1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
17 #include "hostallocator.h"
19 #include "ssabuilder.h"
21 #include "rangecheck.h"
23 #ifndef LEGACY_BACKEND
25 #endif // !LEGACY_BACKEND
27 #include "jittelemetry.h"
30 // Column settings for COMPlus_JitDumpIR. We could(should) make these programmable.
31 #define COLUMN_OPCODE 30
32 #define COLUMN_OPERANDS (COLUMN_OPCODE + 25)
33 #define COLUMN_KINDS 110
34 #define COLUMN_FLAGS (COLUMN_KINDS + 32)
38 unsigned Compiler::jitTotalMethodCompiled = 0;
39 #endif // defined(DEBUG)
42 LONG Compiler::jitNestingLevel = 0;
43 #endif // defined(DEBUG)
47 bool Compiler::s_pAltJitExcludeAssembliesListInitialized = false;
48 AssemblyNamesList2* Compiler::s_pAltJitExcludeAssembliesList = nullptr;
51 /*****************************************************************************
53 * Little helpers to grab the current cycle counter value; this is done
54 * differently based on target architecture, host toolchain, etc. The
55 * main thing is to keep the overhead absolutely minimal; in fact, on
56 * x86/x64 we use RDTSC even though it's not thread-safe; GetThreadCycles
57 * (which is monotonous) is just too expensive.
59 #ifdef FEATURE_JIT_METHOD_PERF
61 #if defined(_HOST_X86_) || defined(_HOST_AMD64_)
66 inline bool _our_GetThreadCycles(unsigned __int64* cycleOut)
68 *cycleOut = __rdtsc();
72 #elif defined(__clang__)
74 inline bool _our_GetThreadCycles(unsigned __int64* cycleOut)
77 asm volatile("rdtsc" : "=A"(cycles));
82 #else // neither _MSC_VER nor __clang__
84 // The following *might* work - might as well try.
85 #define _our_GetThreadCycles(cp) GetThreadCycles(cp)
89 #elif defined(_HOST_ARM_) || defined(_HOST_ARM64_)
91 // If this doesn't work please see ../gc/gc.cpp for additional ARM
92 // info (and possible solutions).
93 #define _our_GetThreadCycles(cp) GetThreadCycles(cp)
95 #else // not x86/x64 and not ARM
97 // Don't know what this target is, but let's give it a try; if
98 // someone really wants to make this work, please add the right
100 #define _our_GetThreadCycles(cp) GetThreadCycles(cp)
102 #endif // which host OS
104 #endif // FEATURE_JIT_METHOD_PERF
105 /*****************************************************************************/
106 inline unsigned getCurTime()
112 return (((tim.wHour * 60) + tim.wMinute) * 60 + tim.wSecond) * 1000 + tim.wMilliseconds;
115 /*****************************************************************************/
117 /*****************************************************************************/
119 static FILE* jitSrcFilePtr;
121 static unsigned jitCurSrcLine;
123 void Compiler::JitLogEE(unsigned level, const char* fmt, ...)
130 vflogf(jitstdout, fmt, args);
135 vlogf(level, fmt, args);
139 void Compiler::compDspSrcLinesByLineNum(unsigned line, bool seek)
146 if (jitCurSrcLine == line)
151 if (jitCurSrcLine > line)
158 if (fseek(jitSrcFilePtr, 0, SEEK_SET) != 0)
160 printf("Compiler::compDspSrcLinesByLineNum: fseek returned an error.\n");
175 if (!fgets(temp, sizeof(temp), jitSrcFilePtr))
186 if (llen && temp[llen - 1] == '\n')
191 printf("; %s\n", temp);
192 } while (++jitCurSrcLine < line);
200 /*****************************************************************************/
202 void Compiler::compDspSrcLinesByNativeIP(UNATIVE_OFFSET curIP)
204 static IPmappingDsc* nextMappingDsc;
205 static unsigned lastLine;
214 if (genIPmappingList)
216 nextMappingDsc = genIPmappingList;
217 lastLine = jitGetILoffs(nextMappingDsc->ipmdILoffsx);
219 unsigned firstLine = jitGetILoffs(nextMappingDsc->ipmdILoffsx);
221 unsigned earlierLine = (firstLine < 5) ? 0 : firstLine - 5;
223 compDspSrcLinesByLineNum(earlierLine, true); // display previous 5 lines
224 compDspSrcLinesByLineNum(firstLine, false);
228 nextMappingDsc = nullptr;
236 UNATIVE_OFFSET offset = nextMappingDsc->ipmdNativeLoc.CodeOffset(genEmitter);
240 IL_OFFSET nextOffs = jitGetILoffs(nextMappingDsc->ipmdILoffsx);
242 if (lastLine < nextOffs)
244 compDspSrcLinesByLineNum(nextOffs);
248 // This offset corresponds to a previous line. Rewind to that line
250 compDspSrcLinesByLineNum(nextOffs - 2, true);
251 compDspSrcLinesByLineNum(nextOffs);
255 nextMappingDsc = nextMappingDsc->ipmdNext;
260 /*****************************************************************************/
263 /*****************************************************************************/
264 #if defined(DEBUG) || MEASURE_NODE_SIZE || MEASURE_BLOCK_SIZE || DISPLAY_SIZES || CALL_ARG_STATS
266 static unsigned genMethodCnt; // total number of methods JIT'ted
267 unsigned genMethodICnt; // number of interruptible methods
268 unsigned genMethodNCnt; // number of non-interruptible methods
269 static unsigned genSmallMethodsNeedingExtraMemoryCnt = 0;
273 /*****************************************************************************/
274 #if MEASURE_NODE_SIZE
275 NodeSizeStats genNodeSizeStats;
276 NodeSizeStats genNodeSizeStatsPerFunc;
278 unsigned genTreeNcntHistBuckets[] = {10, 20, 30, 40, 50, 100, 200, 300, 400, 500, 1000, 5000, 10000, 0};
279 Histogram genTreeNcntHist(HostAllocator::getHostAllocator(), genTreeNcntHistBuckets);
281 unsigned genTreeNsizHistBuckets[] = {1000, 5000, 10000, 50000, 100000, 500000, 1000000, 0};
282 Histogram genTreeNsizHist(HostAllocator::getHostAllocator(), genTreeNsizHistBuckets);
283 #endif // MEASURE_NODE_SIZE
285 /*****************************************************************************/
286 #if MEASURE_MEM_ALLOC
288 unsigned memSizeHistBuckets[] = {20, 50, 75, 100, 150, 250, 500, 1000, 5000, 0};
289 Histogram memAllocHist(HostAllocator::getHostAllocator(), memSizeHistBuckets);
290 Histogram memUsedHist(HostAllocator::getHostAllocator(), memSizeHistBuckets);
292 #endif // MEASURE_MEM_ALLOC
294 /*****************************************************************************
296 * Variables to keep track of total code amounts.
301 size_t grossVMsize; // Total IL code size
302 size_t grossNCsize; // Native code + data size
303 size_t totalNCsize; // Native code + data + GC info size (TODO-Cleanup: GC info size only accurate for JIT32_GCENCODER)
304 size_t gcHeaderISize; // GC header size: interruptible methods
305 size_t gcPtrMapISize; // GC pointer map size: interruptible methods
306 size_t gcHeaderNSize; // GC header size: non-interruptible methods
307 size_t gcPtrMapNSize; // GC pointer map size: non-interruptible methods
309 #endif // DISPLAY_SIZES
311 /*****************************************************************************
313 * Variables to keep track of argument counts.
318 unsigned argTotalCalls;
319 unsigned argHelperCalls;
320 unsigned argStaticCalls;
321 unsigned argNonVirtualCalls;
322 unsigned argVirtualCalls;
324 unsigned argTotalArgs; // total number of args for all calls (including objectPtr)
325 unsigned argTotalDWordArgs;
326 unsigned argTotalLongArgs;
327 unsigned argTotalFloatArgs;
328 unsigned argTotalDoubleArgs;
330 unsigned argTotalRegArgs;
331 unsigned argTotalTemps;
332 unsigned argTotalLclVar;
333 unsigned argTotalDeferred;
334 unsigned argTotalConst;
336 unsigned argTotalObjPtr;
337 unsigned argTotalGTF_ASGinArgs;
339 unsigned argMaxTempsPerMethod;
341 unsigned argCntBuckets[] = {0, 1, 2, 3, 4, 5, 6, 10, 0};
342 Histogram argCntTable(HostAllocator::getHostAllocator(), argCntBuckets);
344 unsigned argDWordCntBuckets[] = {0, 1, 2, 3, 4, 5, 6, 10, 0};
345 Histogram argDWordCntTable(HostAllocator::getHostAllocator(), argDWordCntBuckets);
347 unsigned argDWordLngCntBuckets[] = {0, 1, 2, 3, 4, 5, 6, 10, 0};
348 Histogram argDWordLngCntTable(HostAllocator::getHostAllocator(), argDWordLngCntBuckets);
350 unsigned argTempsCntBuckets[] = {0, 1, 2, 3, 4, 5, 6, 10, 0};
351 Histogram argTempsCntTable(HostAllocator::getHostAllocator(), argTempsCntBuckets);
353 #endif // CALL_ARG_STATS
355 /*****************************************************************************
357 * Variables to keep track of basic block counts.
360 #if COUNT_BASIC_BLOCKS
362 // --------------------------------------------------
363 // Basic block count frequency table:
364 // --------------------------------------------------
365 // <= 1 ===> 26872 count ( 56% of total)
366 // 2 .. 2 ===> 669 count ( 58% of total)
367 // 3 .. 3 ===> 4687 count ( 68% of total)
368 // 4 .. 5 ===> 5101 count ( 78% of total)
369 // 6 .. 10 ===> 5575 count ( 90% of total)
370 // 11 .. 20 ===> 3028 count ( 97% of total)
371 // 21 .. 50 ===> 1108 count ( 99% of total)
372 // 51 .. 100 ===> 182 count ( 99% of total)
373 // 101 .. 1000 ===> 34 count (100% of total)
374 // 1001 .. 10000 ===> 0 count (100% of total)
375 // --------------------------------------------------
377 unsigned bbCntBuckets[] = {1, 2, 3, 5, 10, 20, 50, 100, 1000, 10000, 0};
378 Histogram bbCntTable(HostAllocator::getHostAllocator(), bbCntBuckets);
380 /* Histogram for the IL opcode size of methods with a single basic block */
382 unsigned bbSizeBuckets[] = {1, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 0};
383 Histogram bbOneBBSizeTable(HostAllocator::getHostAllocator(), bbSizeBuckets);
385 #endif // COUNT_BASIC_BLOCKS
387 /*****************************************************************************
389 * Used by optFindNaturalLoops to gather statistical information such as
390 * - total number of natural loops
391 * - number of loops with 1, 2, ... exit conditions
392 * - number of loops that have an iterator (for like)
393 * - number of loops that have a constant iterator
398 unsigned totalLoopMethods; // counts the total number of methods that have natural loops
399 unsigned maxLoopsPerMethod; // counts the maximum number of loops a method has
400 unsigned totalLoopOverflows; // # of methods that identified more loops than we can represent
401 unsigned totalLoopCount; // counts the total number of natural loops
402 unsigned totalUnnatLoopCount; // counts the total number of (not-necessarily natural) loops
403 unsigned totalUnnatLoopOverflows; // # of methods that identified more unnatural loops than we can represent
404 unsigned iterLoopCount; // counts the # of loops with an iterator (for like)
405 unsigned simpleTestLoopCount; // counts the # of loops with an iterator and a simple loop condition (iter < const)
406 unsigned constIterLoopCount; // counts the # of loops with a constant iterator (for like)
407 bool hasMethodLoops; // flag to keep track if we already counted a method as having loops
408 unsigned loopsThisMethod; // counts the number of loops in the current method
409 bool loopOverflowThisMethod; // True if we exceeded the max # of loops in the method.
411 /* Histogram for number of loops in a method */
413 unsigned loopCountBuckets[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0};
414 Histogram loopCountTable(HostAllocator::getHostAllocator(), loopCountBuckets);
416 /* Histogram for number of loop exits */
418 unsigned loopExitCountBuckets[] = {0, 1, 2, 3, 4, 5, 6, 0};
419 Histogram loopExitCountTable(HostAllocator::getHostAllocator(), loopExitCountBuckets);
421 #endif // COUNT_LOOPS
423 //------------------------------------------------------------------------
424 // getJitGCType: Given the VM's CorInfoGCType convert it to the JIT's var_types
427 // gcType - an enum value that originally came from an element
428 // of the BYTE[] returned from getClassGClayout()
431 // The corresponsing enum value from the JIT's var_types
434 // The gcLayout of each field of a struct is returned from getClassGClayout()
435 // as a BYTE[] but each BYTE element is actually a CorInfoGCType value
436 // Note when we 'know' that there is only one element in theis array
437 // the JIT will often pass the address of a single BYTE, instead of a BYTE[]
440 var_types Compiler::getJitGCType(BYTE gcType)
442 var_types result = TYP_UNKNOWN;
443 CorInfoGCType corInfoType = (CorInfoGCType)gcType;
445 if (corInfoType == TYPE_GC_NONE)
449 else if (corInfoType == TYPE_GC_REF)
453 else if (corInfoType == TYPE_GC_BYREF)
459 noway_assert(!"Bad value of 'gcType'");
464 #if FEATURE_MULTIREG_ARGS
465 //---------------------------------------------------------------------------
466 // getStructGcPtrsFromOp: Given a GenTree node of TYP_STRUCT that represents
467 // a pass by value argument, return the gcPtr layout
468 // for the pointers sized fields
470 // op - the operand of TYP_STRUCT that is passed by value
471 // gcPtrsOut - an array of BYTES that are written by this method
472 // they will contain the VM's CorInfoGCType values
473 // for each pointer sized field
475 // Two [or more] values are written into the gcPtrs array
477 // Note that for ARM64 there will alwys be exactly two pointer sized fields
479 void Compiler::getStructGcPtrsFromOp(GenTreePtr op, BYTE* gcPtrsOut)
481 assert(op->TypeGet() == TYP_STRUCT);
483 #ifdef _TARGET_ARM64_
484 if (op->OperGet() == GT_OBJ)
486 CORINFO_CLASS_HANDLE objClass = op->gtObj.gtClass;
488 int structSize = info.compCompHnd->getClassSize(objClass);
489 assert(structSize <= 2 * TARGET_POINTER_SIZE);
491 BYTE gcPtrsTmp[2] = {TYPE_GC_NONE, TYPE_GC_NONE};
493 info.compCompHnd->getClassGClayout(objClass, &gcPtrsTmp[0]);
495 gcPtrsOut[0] = gcPtrsTmp[0];
496 gcPtrsOut[1] = gcPtrsTmp[1];
498 else if (op->OperGet() == GT_LCL_VAR)
500 GenTreeLclVarCommon* varNode = op->AsLclVarCommon();
501 unsigned varNum = varNode->gtLclNum;
502 assert(varNum < lvaCount);
503 LclVarDsc* varDsc = &lvaTable[varNum];
505 // At this point any TYP_STRUCT LclVar must be a 16-byte pass by value argument
506 assert(varDsc->lvSize() == 2 * TARGET_POINTER_SIZE);
508 gcPtrsOut[0] = varDsc->lvGcLayout[0];
509 gcPtrsOut[1] = varDsc->lvGcLayout[1];
514 noway_assert(!"Unsupported Oper for getStructGcPtrsFromOp");
517 #endif // FEATURE_MULTIREG_ARGS
520 //---------------------------------------------------------------------------
521 // IsSingleFloat32Struct:
522 // Check if the given struct type contains only one float32 value type
525 // clsHnd - the handle for the struct type
528 // true if the given struct type contains only one float32 value type,
532 bool Compiler::isSingleFloat32Struct(CORINFO_CLASS_HANDLE clsHnd)
536 // all of class chain must be of value type and must have only one field
537 if (!info.compCompHnd->isValueClass(clsHnd) || info.compCompHnd->getClassNumInstanceFields(clsHnd) != 1)
542 CORINFO_CLASS_HANDLE* pClsHnd = &clsHnd;
543 CORINFO_FIELD_HANDLE fldHnd = info.compCompHnd->getFieldInClass(clsHnd, 0);
544 CorInfoType fieldType = info.compCompHnd->getFieldType(fldHnd, pClsHnd);
548 case CORINFO_TYPE_VALUECLASS:
552 case CORINFO_TYPE_FLOAT:
562 //-----------------------------------------------------------------------------
563 // getPrimitiveTypeForStruct:
564 // Get the "primitive" type that is is used for a struct
565 // of size 'structSize'.
566 // We examine 'clsHnd' to check the GC layout of the struct and
567 // return TYP_REF for structs that simply wrap an object.
568 // If the struct is a one element HFA, we will return the
569 // proper floating point type.
572 // structSize - the size of the struct type, cannot be zero
573 // clsHnd - the handle for the struct type, used when may have
574 // an HFA or if we need the GC layout for an object ref.
577 // The primitive type (i.e. byte, short, int, long, ref, float, double)
578 // used to pass or return structs of this size.
579 // If we shouldn't use a "primitive" type then TYP_UNKNOWN is returned.
581 // For 32-bit targets (X86/ARM32) the 64-bit TYP_LONG type is not
582 // considered a primitive type by this method.
583 // So a struct that wraps a 'long' is passed and returned in the
584 // same way as any other 8-byte struct
585 // For ARM32 if we have an HFA struct that wraps a 64-bit double
586 // we will return TYP_DOUBLE.
588 var_types Compiler::getPrimitiveTypeForStruct(unsigned structSize, CORINFO_CLASS_HANDLE clsHnd)
590 assert(structSize != 0);
604 #ifndef _TARGET_XARCH_
609 #endif // _TARGET_XARCH_
611 #ifdef _TARGET_64BIT_
615 // A structSize of 4 with IsHfa, it must be an HFA of one float
624 #ifndef _TARGET_XARCH_
628 useType = TYP_I_IMPL;
631 #endif // _TARGET_XARCH_
632 #endif // _TARGET_64BIT_
634 case TARGET_POINTER_SIZE:
636 // For ARM_SOFTFP, HFA is unsupported so we need to check in another way
637 // This matters only for size-4 struct cause bigger structs would be processed with RetBuf
638 if (isSingleFloat32Struct(clsHnd))
643 #ifdef _TARGET_64BIT_
644 var_types hfaType = GetHfaType(clsHnd);
646 // A structSize of 8 with IsHfa, we have two possiblities:
647 // An HFA of one double or an HFA of two floats
649 // Check and exclude the case of an HFA of two floats
650 if (hfaType == TYP_DOUBLE)
652 // We have an HFA of one double
653 useType = TYP_DOUBLE;
657 assert(hfaType == TYP_FLOAT);
659 // We have an HFA of two floats
660 // This should be passed or returned in two FP registers
661 useType = TYP_UNKNOWN;
663 #else // a 32BIT target
664 // A structSize of 4 with IsHfa, it must be an HFA of one float
666 #endif // _TARGET_64BIT_
671 // Check if this pointer-sized struct is wrapping a GC object
672 info.compCompHnd->getClassGClayout(clsHnd, &gcPtr);
673 useType = getJitGCType(gcPtr);
681 var_types hfaType = GetHfaType(clsHnd);
683 // A structSize of 8 with IsHfa, we have two possiblities:
684 // An HFA of one double or an HFA of two floats
686 // Check and exclude the case of an HFA of two floats
687 if (hfaType == TYP_DOUBLE)
689 // We have an HFA of one double
690 useType = TYP_DOUBLE;
694 assert(hfaType == TYP_FLOAT);
696 // We have an HFA of two floats
697 // This should be passed or returned in two FP registers
698 useType = TYP_UNKNOWN;
703 // We don't have an HFA
704 useType = TYP_UNKNOWN;
707 #endif // _TARGET_ARM_
710 useType = TYP_UNKNOWN;
717 //-----------------------------------------------------------------------------
718 // getArgTypeForStruct:
719 // Get the type that is used to pass values of the given struct type.
720 // If you have already retrieved the struct size then it should be
721 // passed as the optional third argument, as this allows us to avoid
722 // an extra call to getClassSize(clsHnd)
725 // clsHnd - the handle for the struct type
726 // wbPassStruct - An "out" argument with information about how
727 // the struct is to be passed
728 // structSize - the size of the struct type,
729 // or zero if we should call getClassSize(clsHnd)
732 // For wbPassStruct you can pass a 'nullptr' and nothing will be written
733 // or returned for that out parameter.
734 // When *wbPassStruct is SPK_PrimitiveType this method's return value
735 // is the primitive type used to pass the struct.
736 // When *wbPassStruct is SPK_ByReference this method's return value
737 // is always TYP_UNKNOWN and the struct type is passed by reference to a copy
738 // When *wbPassStruct is SPK_ByValue or SPK_ByValueAsHfa this method's return value
739 // is always TYP_STRUCT and the struct type is passed by value either
740 // using multiple registers or on the stack.
743 // The size must be the size of the given type.
744 // The given class handle must be for a value type (struct).
748 // When the clsHnd is a one element HFA type we return the appropriate
749 // floating point primitive type and *wbPassStruct is SPK_PrimitiveType
750 // If there are two or more elements in the HFA type then the this method's
751 // return value is TYP_STRUCT and *wbPassStruct is SPK_ByValueAsHfa
753 var_types Compiler::getArgTypeForStruct(CORINFO_CLASS_HANDLE clsHnd,
754 structPassingKind* wbPassStruct,
755 unsigned structSize /* = 0 */)
757 var_types useType = TYP_UNKNOWN;
758 structPassingKind howToPassStruct = SPK_Unknown; // We must change this before we return
762 structSize = info.compCompHnd->getClassSize(clsHnd);
764 assert(structSize > 0);
766 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
768 // An 8-byte struct may need to be passed in a floating point register
769 // So we always consult the struct "Classifier" routine
771 SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
772 eeGetSystemVAmd64PassStructInRegisterDescriptor(clsHnd, &structDesc);
774 // If we have one eightByteCount then we can set 'useType' based on that
775 if (structDesc.eightByteCount == 1)
777 // Set 'useType' to the type of the first eightbyte item
778 useType = GetEightByteType(structDesc, 0);
781 #elif defined(_TARGET_X86_)
783 // On x86 we never pass structs as primitive types (unless the VM unwraps them for us)
784 useType = TYP_UNKNOWN;
786 #else // all other targets
788 // The largest primitive type is 8 bytes (TYP_DOUBLE)
789 // so we can skip calling getPrimitiveTypeForStruct when we
790 // have a struct that is larger than that.
792 if (structSize <= sizeof(double))
794 // We set the "primitive" useType based upon the structSize
795 // and also examine the clsHnd to see if it is an HFA of count one
796 useType = getPrimitiveTypeForStruct(structSize, clsHnd);
799 #endif // all other targets
801 // Did we change this struct type into a simple "primitive" type?
803 if (useType != TYP_UNKNOWN)
805 // Yes, we should use the "primitive" type in 'useType'
806 howToPassStruct = SPK_PrimitiveType;
808 else // We can't replace the struct with a "primitive" type
810 // See if we can pass this struct by value, possibly in multiple registers
811 // or if we should pass it by reference to a copy
813 if (structSize <= MAX_PASS_MULTIREG_BYTES)
815 // Structs that are HFA's are passed by value in multiple registers
818 // HFA's of count one should have been handled by getPrimitiveTypeForStruct
819 assert(GetHfaCount(clsHnd) >= 2);
821 // setup wbPassType and useType indicate that this is passed by value as an HFA
822 // using multiple registers
823 // (when all of the parameters registers are used, then the stack will be used)
824 howToPassStruct = SPK_ByValueAsHfa;
825 useType = TYP_STRUCT;
827 else // Not an HFA struct type
830 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
832 // The case of (structDesc.eightByteCount == 1) should have already been handled
833 if (structDesc.eightByteCount > 1)
835 // setup wbPassType and useType indicate that this is passed by value in multiple registers
836 // (when all of the parameters registers are used, then the stack will be used)
837 howToPassStruct = SPK_ByValue;
838 useType = TYP_STRUCT;
842 assert(structDesc.eightByteCount == 0);
843 // Otherwise we pass this struct by reference to a copy
844 // setup wbPassType and useType indicate that this is passed using one register
845 // (by reference to a copy)
846 howToPassStruct = SPK_ByReference;
847 useType = TYP_UNKNOWN;
850 #elif defined(_TARGET_ARM64_)
852 // Structs that are pointer sized or smaller should have been handled by getPrimitiveTypeForStruct
853 assert(structSize > TARGET_POINTER_SIZE);
855 // On ARM64 structs that are 9-16 bytes are passed by value in multiple registers
857 if (structSize <= (TARGET_POINTER_SIZE * 2))
859 // setup wbPassType and useType indicate that this is passed by value in multiple registers
860 // (when all of the parameters registers are used, then the stack will be used)
861 howToPassStruct = SPK_ByValue;
862 useType = TYP_STRUCT;
864 else // a structSize that is 17-32 bytes in size
866 // Otherwise we pass this struct by reference to a copy
867 // setup wbPassType and useType indicate that this is passed using one register
868 // (by reference to a copy)
869 howToPassStruct = SPK_ByReference;
870 useType = TYP_UNKNOWN;
873 #elif defined(_TARGET_X86_) || defined(_TARGET_ARM_)
875 // Otherwise we pass this struct by value on the stack
876 // setup wbPassType and useType indicate that this is passed by value according to the X86/ARM32 ABI
877 howToPassStruct = SPK_ByValue;
878 useType = TYP_STRUCT;
880 #else // _TARGET_XXX_
882 noway_assert(!"Unhandled TARGET in getArgTypeForStruct (with FEATURE_MULTIREG_ARGS=1)");
884 #endif // _TARGET_XXX_
887 else // (structSize > MAX_PASS_MULTIREG_BYTES)
889 // We have a (large) struct that can't be replaced with a "primitive" type
890 // and can't be passed in multiple registers
891 CLANG_FORMAT_COMMENT_ANCHOR;
893 #if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
895 // Otherwise we pass this struct by value on the stack
896 // setup wbPassType and useType indicate that this is passed by value according to the X86/ARM32 ABI
897 howToPassStruct = SPK_ByValue;
898 useType = TYP_STRUCT;
900 #elif defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
902 // Otherwise we pass this struct by reference to a copy
903 // setup wbPassType and useType indicate that this is passed using one register (by reference to a copy)
904 howToPassStruct = SPK_ByReference;
905 useType = TYP_UNKNOWN;
907 #else // _TARGET_XXX_
909 noway_assert(!"Unhandled TARGET in getArgTypeForStruct");
911 #endif // _TARGET_XXX_
915 // 'howToPassStruct' must be set to one of the valid values before we return
916 assert(howToPassStruct != SPK_Unknown);
917 if (wbPassStruct != nullptr)
919 *wbPassStruct = howToPassStruct;
924 //-----------------------------------------------------------------------------
925 // getReturnTypeForStruct:
926 // Get the type that is used to return values of the given struct type.
927 // If you have already retrieved the struct size then it should be
928 // passed as the optional third argument, as this allows us to avoid
929 // an extra call to getClassSize(clsHnd)
932 // clsHnd - the handle for the struct type
933 // wbReturnStruct - An "out" argument with information about how
934 // the struct is to be returned
935 // structSize - the size of the struct type,
936 // or zero if we should call getClassSize(clsHnd)
939 // For wbReturnStruct you can pass a 'nullptr' and nothing will be written
940 // or returned for that out parameter.
941 // When *wbReturnStruct is SPK_PrimitiveType this method's return value
942 // is the primitive type used to return the struct.
943 // When *wbReturnStruct is SPK_ByReference this method's return value
944 // is always TYP_UNKNOWN and the struct type is returned using a return buffer
945 // When *wbReturnStruct is SPK_ByValue or SPK_ByValueAsHfa this method's return value
946 // is always TYP_STRUCT and the struct type is returned using multiple registers.
949 // The size must be the size of the given type.
950 // The given class handle must be for a value type (struct).
954 // When the clsHnd is a one element HFA type then this method's return
955 // value is the appropriate floating point primitive type and
956 // *wbReturnStruct is SPK_PrimitiveType.
957 // If there are two or more elements in the HFA type and the target supports
958 // multireg return types then the return value is TYP_STRUCT and
959 // *wbReturnStruct is SPK_ByValueAsHfa.
960 // Additionally if there are two or more elements in the HFA type and
961 // the target doesn't support multreg return types then it is treated
962 // as if it wasn't an HFA type.
963 // About returning TYP_STRUCT:
964 // Whenever this method's return value is TYP_STRUCT it always means
965 // that multiple registers are used to return this struct.
967 var_types Compiler::getReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd,
968 structPassingKind* wbReturnStruct /* = nullptr */,
969 unsigned structSize /* = 0 */)
971 var_types useType = TYP_UNKNOWN;
972 structPassingKind howToReturnStruct = SPK_Unknown; // We must change this before we return
974 assert(clsHnd != NO_CLASS_HANDLE);
978 structSize = info.compCompHnd->getClassSize(clsHnd);
980 assert(structSize > 0);
982 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
984 // An 8-byte struct may need to be returned in a floating point register
985 // So we always consult the struct "Classifier" routine
987 SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
988 eeGetSystemVAmd64PassStructInRegisterDescriptor(clsHnd, &structDesc);
990 // If we have one eightByteCount then we can set 'useType' based on that
991 if (structDesc.eightByteCount == 1)
993 // Set 'useType' to the type of the first eightbyte item
994 useType = GetEightByteType(structDesc, 0);
995 assert(structDesc.passedInRegisters == true);
998 #else // not UNIX_AMD64
1000 // The largest primitive type is 8 bytes (TYP_DOUBLE)
1001 // so we can skip calling getPrimitiveTypeForStruct when we
1002 // have a struct that is larger than that.
1004 if (structSize <= sizeof(double))
1006 // We set the "primitive" useType based upon the structSize
1007 // and also examine the clsHnd to see if it is an HFA of count one
1008 useType = getPrimitiveTypeForStruct(structSize, clsHnd);
1011 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
1013 #ifdef _TARGET_64BIT_
1014 // Note this handles an odd case when FEATURE_MULTIREG_RET is disabled and HFAs are enabled
1016 // getPrimitiveTypeForStruct will return TYP_UNKNOWN for a struct that is an HFA of two floats
1017 // because when HFA are enabled, normally we would use two FP registers to pass or return it
1019 // But if we don't have support for multiple register return types, we have to change this.
1020 // Since we what we have an 8-byte struct (float + float) we change useType to TYP_I_IMPL
1021 // so that the struct is returned instead using an 8-byte integer register.
1023 if ((FEATURE_MULTIREG_RET == 0) && (useType == TYP_UNKNOWN) && (structSize == (2 * sizeof(float))) && IsHfa(clsHnd))
1025 useType = TYP_I_IMPL;
1029 // Did we change this struct type into a simple "primitive" type?
1031 if (useType != TYP_UNKNOWN)
1033 // Yes, we should use the "primitive" type in 'useType'
1034 howToReturnStruct = SPK_PrimitiveType;
1036 else // We can't replace the struct with a "primitive" type
1038 // See if we can return this struct by value, possibly in multiple registers
1039 // or if we should return it using a return buffer register
1041 if ((FEATURE_MULTIREG_RET == 1) && (structSize <= MAX_RET_MULTIREG_BYTES))
1043 // Structs that are HFA's are returned in multiple registers
1046 // HFA's of count one should have been handled by getPrimitiveTypeForStruct
1047 assert(GetHfaCount(clsHnd) >= 2);
1049 // setup wbPassType and useType indicate that this is returned by value as an HFA
1050 // using multiple registers
1051 howToReturnStruct = SPK_ByValueAsHfa;
1052 useType = TYP_STRUCT;
1054 else // Not an HFA struct type
1057 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
1059 // The case of (structDesc.eightByteCount == 1) should have already been handled
1060 if (structDesc.eightByteCount > 1)
1062 // setup wbPassType and useType indicate that this is returned by value in multiple registers
1063 howToReturnStruct = SPK_ByValue;
1064 useType = TYP_STRUCT;
1065 assert(structDesc.passedInRegisters == true);
1069 assert(structDesc.eightByteCount == 0);
1070 // Otherwise we return this struct using a return buffer
1071 // setup wbPassType and useType indicate that this is return using a return buffer register
1072 // (reference to a return buffer)
1073 howToReturnStruct = SPK_ByReference;
1074 useType = TYP_UNKNOWN;
1075 assert(structDesc.passedInRegisters == false);
1078 #elif defined(_TARGET_ARM64_)
1080 // Structs that are pointer sized or smaller should have been handled by getPrimitiveTypeForStruct
1081 assert(structSize > TARGET_POINTER_SIZE);
1083 // On ARM64 structs that are 9-16 bytes are returned by value in multiple registers
1085 if (structSize <= (TARGET_POINTER_SIZE * 2))
1087 // setup wbPassType and useType indicate that this is return by value in multiple registers
1088 howToReturnStruct = SPK_ByValue;
1089 useType = TYP_STRUCT;
1091 else // a structSize that is 17-32 bytes in size
1093 // Otherwise we return this struct using a return buffer
1094 // setup wbPassType and useType indicate that this is returned using a return buffer register
1095 // (reference to a return buffer)
1096 howToReturnStruct = SPK_ByReference;
1097 useType = TYP_UNKNOWN;
1100 #elif defined(_TARGET_ARM_) || defined(_TARGET_X86_)
1102 // Otherwise we return this struct using a return buffer
1103 // setup wbPassType and useType indicate that this is returned using a return buffer register
1104 // (reference to a return buffer)
1105 howToReturnStruct = SPK_ByReference;
1106 useType = TYP_UNKNOWN;
1108 #else // _TARGET_XXX_
1110 noway_assert(!"Unhandled TARGET in getReturnTypeForStruct (with FEATURE_MULTIREG_ARGS=1)");
1112 #endif // _TARGET_XXX_
1115 else // (structSize > MAX_RET_MULTIREG_BYTES) || (FEATURE_MULTIREG_RET == 0)
1117 // We have a (large) struct that can't be replaced with a "primitive" type
1118 // and can't be returned in multiple registers
1120 // We return this struct using a return buffer register
1121 // setup wbPassType and useType indicate that this is returned using a return buffer register
1122 // (reference to a return buffer)
1123 howToReturnStruct = SPK_ByReference;
1124 useType = TYP_UNKNOWN;
1128 // 'howToReturnStruct' must be set to one of the valid values before we return
1129 assert(howToReturnStruct != SPK_Unknown);
1130 if (wbReturnStruct != nullptr)
1132 *wbReturnStruct = howToReturnStruct;
1137 /*****************************************************************************
1138 * variables to keep track of how many iterations we go in a dataflow pass
1143 unsigned CSEiterCount; // counts the # of iteration for the CSE dataflow
1144 unsigned CFiterCount; // counts the # of iteration for the Const Folding dataflow
1146 #endif // DATAFLOW_ITER
1148 #if MEASURE_BLOCK_SIZE
1149 size_t genFlowNodeSize;
1150 size_t genFlowNodeCnt;
1151 #endif // MEASURE_BLOCK_SIZE
1153 /*****************************************************************************/
1154 // We keep track of methods we've already compiled.
1156 /*****************************************************************************
1157 * Declare the statics
1162 unsigned Compiler::s_compMethodsCount = 0; // to produce unique label names
1165 #if MEASURE_MEM_ALLOC
1167 bool Compiler::s_dspMemStats = false;
1170 #ifndef PROFILING_SUPPORTED
1171 const bool Compiler::Options::compNoPInvokeInlineCB = false;
1174 /*****************************************************************************
1176 * One time initialization code
1180 void Compiler::compStartup()
1183 grossVMsize = grossNCsize = totalNCsize = 0;
1184 #endif // DISPLAY_SIZES
1186 // Initialize the JIT's allocator.
1187 ArenaAllocator::startup();
1189 /* Initialize the table of tree node sizes */
1191 GenTree::InitNodeSize();
1193 #ifdef JIT32_GCENCODER
1194 // Initialize the GC encoder lookup table
1196 GCInfo::gcInitEncoderLookupTable();
1199 /* Initialize the emitter */
1201 emitter::emitInit();
1203 // Static vars of ValueNumStore
1204 ValueNumStore::InitValueNumStoreStatics();
1206 compDisplayStaticSizes(jitstdout);
1209 /*****************************************************************************
1211 * One time finalization code
1215 void Compiler::compShutdown()
1218 if (s_pAltJitExcludeAssembliesList != nullptr)
1220 s_pAltJitExcludeAssembliesList->~AssemblyNamesList2(); // call the destructor
1221 s_pAltJitExcludeAssembliesList = nullptr;
1225 ArenaAllocator::shutdown();
1227 /* Shut down the emitter */
1229 emitter::emitDone();
1231 #if defined(DEBUG) || defined(INLINE_DATA)
1232 // Finish reading and/or writing inline xml
1233 InlineStrategy::FinalizeXml();
1234 #endif // defined(DEBUG) || defined(INLINE_DATA)
1236 #if defined(DEBUG) || MEASURE_NODE_SIZE || MEASURE_BLOCK_SIZE || DISPLAY_SIZES || CALL_ARG_STATS
1237 if (genMethodCnt == 0)
1244 GenTree::ReportOperBashing(jitstdout);
1247 // Where should we write our statistics output?
1248 FILE* fout = jitstdout;
1250 #ifdef FEATURE_JIT_METHOD_PERF
1251 if (compJitTimeLogFilename != nullptr)
1253 FILE* jitTimeLogFile = _wfopen(compJitTimeLogFilename, W("a"));
1254 if (jitTimeLogFile != nullptr)
1256 CompTimeSummaryInfo::s_compTimeSummary.Print(jitTimeLogFile);
1257 fclose(jitTimeLogFile);
1260 #endif // FEATURE_JIT_METHOD_PERF
1262 #if FUNC_INFO_LOGGING
1263 if (compJitFuncInfoFile != nullptr)
1265 fclose(compJitFuncInfoFile);
1266 compJitFuncInfoFile = nullptr;
1268 #endif // FUNC_INFO_LOGGING
1270 #if COUNT_RANGECHECKS
1271 if (optRangeChkAll > 0)
1273 fprintf(fout, "Removed %u of %u range checks\n", optRangeChkRmv, optRangeChkAll);
1275 #endif // COUNT_RANGECHECKS
1279 // Add up all the counts so that we can show percentages of total
1281 for (unsigned op = 0; op < GT_COUNT; op++)
1282 gtc += GenTree::s_gtNodeCounts[op];
1286 unsigned rem_total = gtc;
1287 unsigned rem_large = 0;
1288 unsigned rem_small = 0;
1290 unsigned tot_large = 0;
1291 unsigned tot_small = 0;
1293 fprintf(fout, "\nGenTree operator counts (approximate):\n\n");
1295 for (unsigned op = 0; op < GT_COUNT; op++)
1297 unsigned siz = GenTree::s_gtTrueSizes[op];
1298 unsigned cnt = GenTree::s_gtNodeCounts[op];
1299 double pct = 100.0 * cnt / gtc;
1301 if (siz > TREE_NODE_SZ_SMALL)
1306 // Let's not show anything below a threshold
1309 fprintf(fout, " GT_%-17s %7u (%4.1lf%%) %3u bytes each\n", GenTree::OpName((genTreeOps)op), cnt,
1315 if (siz > TREE_NODE_SZ_SMALL)
1323 fprintf(fout, " All other GT_xxx ... %7u (%4.1lf%%) ... %4.1lf%% small + %4.1lf%% large\n", rem_total,
1324 100.0 * rem_total / gtc, 100.0 * rem_small / gtc, 100.0 * rem_large / gtc);
1326 fprintf(fout, " -----------------------------------------------------\n");
1327 fprintf(fout, " Total ....... %11u --ALL-- ... %4.1lf%% small + %4.1lf%% large\n", gtc,
1328 100.0 * tot_small / gtc, 100.0 * tot_large / gtc);
1329 fprintf(fout, "\n");
1332 #endif // COUNT_AST_OPERS
1336 if (grossVMsize && grossNCsize)
1338 fprintf(fout, "\n");
1339 fprintf(fout, "--------------------------------------\n");
1340 fprintf(fout, "Function and GC info size stats\n");
1341 fprintf(fout, "--------------------------------------\n");
1343 fprintf(fout, "[%7u VM, %8u %6s %4u%%] %s\n", grossVMsize, grossNCsize, Target::g_tgtCPUName,
1344 100 * grossNCsize / grossVMsize, "Total (excluding GC info)");
1346 fprintf(fout, "[%7u VM, %8u %6s %4u%%] %s\n", grossVMsize, totalNCsize, Target::g_tgtCPUName,
1347 100 * totalNCsize / grossVMsize, "Total (including GC info)");
1349 if (gcHeaderISize || gcHeaderNSize)
1351 fprintf(fout, "\n");
1353 fprintf(fout, "GC tables : [%7uI,%7uN] %7u byt (%u%% of IL, %u%% of %s).\n",
1354 gcHeaderISize + gcPtrMapISize, gcHeaderNSize + gcPtrMapNSize, totalNCsize - grossNCsize,
1355 100 * (totalNCsize - grossNCsize) / grossVMsize, 100 * (totalNCsize - grossNCsize) / grossNCsize,
1356 Target::g_tgtCPUName);
1358 fprintf(fout, "GC headers : [%7uI,%7uN] %7u byt, [%4.1fI,%4.1fN] %4.1f byt/meth\n", gcHeaderISize,
1359 gcHeaderNSize, gcHeaderISize + gcHeaderNSize, (float)gcHeaderISize / (genMethodICnt + 0.001),
1360 (float)gcHeaderNSize / (genMethodNCnt + 0.001),
1361 (float)(gcHeaderISize + gcHeaderNSize) / genMethodCnt);
1363 fprintf(fout, "GC ptr maps : [%7uI,%7uN] %7u byt, [%4.1fI,%4.1fN] %4.1f byt/meth\n", gcPtrMapISize,
1364 gcPtrMapNSize, gcPtrMapISize + gcPtrMapNSize, (float)gcPtrMapISize / (genMethodICnt + 0.001),
1365 (float)gcPtrMapNSize / (genMethodNCnt + 0.001),
1366 (float)(gcPtrMapISize + gcPtrMapNSize) / genMethodCnt);
1370 fprintf(fout, "\n");
1372 fprintf(fout, "GC tables take up %u bytes (%u%% of instr, %u%% of %6s code).\n",
1373 totalNCsize - grossNCsize, 100 * (totalNCsize - grossNCsize) / grossVMsize,
1374 100 * (totalNCsize - grossNCsize) / grossNCsize, Target::g_tgtCPUName);
1379 fprintf(fout, "%u out of %u methods generated with double-aligned stack\n",
1380 Compiler::s_lvaDoubleAlignedProcsCount, genMethodCnt);
1385 #endif // DISPLAY_SIZES
1388 compDispCallArgStats(fout);
1391 #if COUNT_BASIC_BLOCKS
1392 fprintf(fout, "--------------------------------------------------\n");
1393 fprintf(fout, "Basic block count frequency table:\n");
1394 fprintf(fout, "--------------------------------------------------\n");
1395 bbCntTable.dump(fout);
1396 fprintf(fout, "--------------------------------------------------\n");
1398 fprintf(fout, "\n");
1400 fprintf(fout, "--------------------------------------------------\n");
1401 fprintf(fout, "IL method size frequency table for methods with a single basic block:\n");
1402 fprintf(fout, "--------------------------------------------------\n");
1403 bbOneBBSizeTable.dump(fout);
1404 fprintf(fout, "--------------------------------------------------\n");
1405 #endif // COUNT_BASIC_BLOCKS
1409 fprintf(fout, "\n");
1410 fprintf(fout, "---------------------------------------------------\n");
1411 fprintf(fout, "Loop stats\n");
1412 fprintf(fout, "---------------------------------------------------\n");
1413 fprintf(fout, "Total number of methods with loops is %5u\n", totalLoopMethods);
1414 fprintf(fout, "Total number of loops is %5u\n", totalLoopCount);
1415 fprintf(fout, "Maximum number of loops per method is %5u\n", maxLoopsPerMethod);
1416 fprintf(fout, "# of methods overflowing nat loop table is %5u\n", totalLoopOverflows);
1417 fprintf(fout, "Total number of 'unnatural' loops is %5u\n", totalUnnatLoopCount);
1418 fprintf(fout, "# of methods overflowing unnat loop limit is %5u\n", totalUnnatLoopOverflows);
1419 fprintf(fout, "Total number of loops with an iterator is %5u\n", iterLoopCount);
1420 fprintf(fout, "Total number of loops with a simple iterator is %5u\n", simpleTestLoopCount);
1421 fprintf(fout, "Total number of loops with a constant iterator is %5u\n", constIterLoopCount);
1423 fprintf(fout, "--------------------------------------------------\n");
1424 fprintf(fout, "Loop count frequency table:\n");
1425 fprintf(fout, "--------------------------------------------------\n");
1426 loopCountTable.dump(fout);
1427 fprintf(fout, "--------------------------------------------------\n");
1428 fprintf(fout, "Loop exit count frequency table:\n");
1429 fprintf(fout, "--------------------------------------------------\n");
1430 loopExitCountTable.dump(fout);
1431 fprintf(fout, "--------------------------------------------------\n");
1433 #endif // COUNT_LOOPS
1437 fprintf(fout, "---------------------------------------------------\n");
1438 fprintf(fout, "Total number of iterations in the CSE dataflow loop is %5u\n", CSEiterCount);
1439 fprintf(fout, "Total number of iterations in the CF dataflow loop is %5u\n", CFiterCount);
1441 #endif // DATAFLOW_ITER
1443 #if MEASURE_NODE_SIZE
1445 fprintf(fout, "\n");
1446 fprintf(fout, "---------------------------------------------------\n");
1447 fprintf(fout, "GenTree node allocation stats\n");
1448 fprintf(fout, "---------------------------------------------------\n");
1450 fprintf(fout, "Allocated %6u tree nodes (%7u bytes total, avg %4u bytes per method)\n",
1451 genNodeSizeStats.genTreeNodeCnt, genNodeSizeStats.genTreeNodeSize,
1452 genNodeSizeStats.genTreeNodeSize / genMethodCnt);
1454 fprintf(fout, "Allocated %7u bytes of unused tree node space (%3.2f%%)\n",
1455 genNodeSizeStats.genTreeNodeSize - genNodeSizeStats.genTreeNodeActualSize,
1456 (float)(100 * (genNodeSizeStats.genTreeNodeSize - genNodeSizeStats.genTreeNodeActualSize)) /
1457 genNodeSizeStats.genTreeNodeSize);
1459 fprintf(fout, "\n");
1460 fprintf(fout, "---------------------------------------------------\n");
1461 fprintf(fout, "Distribution of per-method GenTree node counts:\n");
1462 genTreeNcntHist.dump(fout);
1464 fprintf(fout, "\n");
1465 fprintf(fout, "---------------------------------------------------\n");
1466 fprintf(fout, "Distribution of per-method GenTree node allocations (in bytes):\n");
1467 genTreeNsizHist.dump(fout);
1469 #endif // MEASURE_NODE_SIZE
1471 #if MEASURE_BLOCK_SIZE
1473 fprintf(fout, "\n");
1474 fprintf(fout, "---------------------------------------------------\n");
1475 fprintf(fout, "BasicBlock and flowList/BasicBlockList allocation stats\n");
1476 fprintf(fout, "---------------------------------------------------\n");
1478 fprintf(fout, "Allocated %6u basic blocks (%7u bytes total, avg %4u bytes per method)\n", BasicBlock::s_Count,
1479 BasicBlock::s_Size, BasicBlock::s_Size / genMethodCnt);
1480 fprintf(fout, "Allocated %6u flow nodes (%7u bytes total, avg %4u bytes per method)\n", genFlowNodeCnt,
1481 genFlowNodeSize, genFlowNodeSize / genMethodCnt);
1483 #endif // MEASURE_BLOCK_SIZE
1485 #if MEASURE_MEM_ALLOC
1489 fprintf(fout, "\nAll allocations:\n");
1490 s_aggMemStats.Print(jitstdout);
1492 fprintf(fout, "\nLargest method:\n");
1493 s_maxCompMemStats.Print(jitstdout);
1495 fprintf(fout, "\n");
1496 fprintf(fout, "---------------------------------------------------\n");
1497 fprintf(fout, "Distribution of total memory allocated per method (in KB):\n");
1498 memAllocHist.dump(fout);
1500 fprintf(fout, "\n");
1501 fprintf(fout, "---------------------------------------------------\n");
1502 fprintf(fout, "Distribution of total memory used per method (in KB):\n");
1503 memUsedHist.dump(fout);
1506 #endif // MEASURE_MEM_ALLOC
1508 #if LOOP_HOIST_STATS
1509 #ifdef DEBUG // Always display loop stats in retail
1510 if (JitConfig.DisplayLoopHoistStats() != 0)
1513 PrintAggregateLoopHoistStats(jitstdout);
1515 #endif // LOOP_HOIST_STATS
1517 #if MEASURE_PTRTAB_SIZE
1519 fprintf(fout, "\n");
1520 fprintf(fout, "---------------------------------------------------\n");
1521 fprintf(fout, "GC pointer table stats\n");
1522 fprintf(fout, "---------------------------------------------------\n");
1524 fprintf(fout, "Reg pointer descriptor size (internal): %8u (avg %4u per method)\n", GCInfo::s_gcRegPtrDscSize,
1525 GCInfo::s_gcRegPtrDscSize / genMethodCnt);
1527 fprintf(fout, "Total pointer table size: %8u (avg %4u per method)\n", GCInfo::s_gcTotalPtrTabSize,
1528 GCInfo::s_gcTotalPtrTabSize / genMethodCnt);
1530 #endif // MEASURE_PTRTAB_SIZE
1532 #if MEASURE_NODE_SIZE || MEASURE_BLOCK_SIZE || MEASURE_PTRTAB_SIZE || DISPLAY_SIZES
1534 if (genMethodCnt != 0)
1536 fprintf(fout, "\n");
1537 fprintf(fout, "A total of %6u methods compiled", genMethodCnt);
1539 if (genMethodICnt || genMethodNCnt)
1541 fprintf(fout, " (%u interruptible, %u non-interruptible)", genMethodICnt, genMethodNCnt);
1543 #endif // DISPLAY_SIZES
1544 fprintf(fout, ".\n");
1547 #endif // MEASURE_NODE_SIZE || MEASURE_BLOCK_SIZE || MEASURE_PTRTAB_SIZE || DISPLAY_SIZES
1554 fprintf(fout, "\n");
1555 fprintf(fout, "---------------------------------------------------\n");
1556 fprintf(fout, "Fatal errors stats\n");
1557 fprintf(fout, "---------------------------------------------------\n");
1558 fprintf(fout, " badCode: %u\n", fatal_badCode);
1559 fprintf(fout, " noWay: %u\n", fatal_noWay);
1560 fprintf(fout, " NOMEM: %u\n", fatal_NOMEM);
1561 fprintf(fout, " noWayAssertBody: %u\n", fatal_noWayAssertBody);
1563 fprintf(fout, " noWayAssertBodyArgs: %u\n", fatal_noWayAssertBodyArgs);
1565 fprintf(fout, " NYI: %u\n", fatal_NYI);
1566 #endif // MEASURE_FATAL
1569 /*****************************************************************************
1570 * Display static data structure sizes.
1574 void Compiler::compDisplayStaticSizes(FILE* fout)
1577 #if MEASURE_NODE_SIZE
1578 GenTree::DumpNodeSizes(fout);
1581 #if MEASURE_BLOCK_SIZE
1583 BasicBlock* bbDummy = nullptr;
1585 fprintf(fout, "\n");
1586 fprintf(fout, "Offset / size of bbNext = %3u / %3u\n", offsetof(BasicBlock, bbNext),
1587 sizeof(bbDummy->bbNext));
1588 fprintf(fout, "Offset / size of bbNum = %3u / %3u\n", offsetof(BasicBlock, bbNum),
1589 sizeof(bbDummy->bbNum));
1590 fprintf(fout, "Offset / size of bbPostOrderNum = %3u / %3u\n", offsetof(BasicBlock, bbPostOrderNum),
1591 sizeof(bbDummy->bbPostOrderNum));
1592 fprintf(fout, "Offset / size of bbRefs = %3u / %3u\n", offsetof(BasicBlock, bbRefs),
1593 sizeof(bbDummy->bbRefs));
1594 fprintf(fout, "Offset / size of bbFlags = %3u / %3u\n", offsetof(BasicBlock, bbFlags),
1595 sizeof(bbDummy->bbFlags));
1596 fprintf(fout, "Offset / size of bbWeight = %3u / %3u\n", offsetof(BasicBlock, bbWeight),
1597 sizeof(bbDummy->bbWeight));
1598 fprintf(fout, "Offset / size of bbJumpKind = %3u / %3u\n", offsetof(BasicBlock, bbJumpKind),
1599 sizeof(bbDummy->bbJumpKind));
1600 fprintf(fout, "Offset / size of bbJumpOffs = %3u / %3u\n", offsetof(BasicBlock, bbJumpOffs),
1601 sizeof(bbDummy->bbJumpOffs));
1602 fprintf(fout, "Offset / size of bbJumpDest = %3u / %3u\n", offsetof(BasicBlock, bbJumpDest),
1603 sizeof(bbDummy->bbJumpDest));
1604 fprintf(fout, "Offset / size of bbJumpSwt = %3u / %3u\n", offsetof(BasicBlock, bbJumpSwt),
1605 sizeof(bbDummy->bbJumpSwt));
1606 fprintf(fout, "Offset / size of bbEntryState = %3u / %3u\n", offsetof(BasicBlock, bbEntryState),
1607 sizeof(bbDummy->bbEntryState));
1608 fprintf(fout, "Offset / size of bbStkTempsIn = %3u / %3u\n", offsetof(BasicBlock, bbStkTempsIn),
1609 sizeof(bbDummy->bbStkTempsIn));
1610 fprintf(fout, "Offset / size of bbStkTempsOut = %3u / %3u\n", offsetof(BasicBlock, bbStkTempsOut),
1611 sizeof(bbDummy->bbStkTempsOut));
1612 fprintf(fout, "Offset / size of bbTryIndex = %3u / %3u\n", offsetof(BasicBlock, bbTryIndex),
1613 sizeof(bbDummy->bbTryIndex));
1614 fprintf(fout, "Offset / size of bbHndIndex = %3u / %3u\n", offsetof(BasicBlock, bbHndIndex),
1615 sizeof(bbDummy->bbHndIndex));
1616 fprintf(fout, "Offset / size of bbCatchTyp = %3u / %3u\n", offsetof(BasicBlock, bbCatchTyp),
1617 sizeof(bbDummy->bbCatchTyp));
1618 fprintf(fout, "Offset / size of bbStkDepth = %3u / %3u\n", offsetof(BasicBlock, bbStkDepth),
1619 sizeof(bbDummy->bbStkDepth));
1620 fprintf(fout, "Offset / size of bbFPinVars = %3u / %3u\n", offsetof(BasicBlock, bbFPinVars),
1621 sizeof(bbDummy->bbFPinVars));
1622 fprintf(fout, "Offset / size of bbPreds = %3u / %3u\n", offsetof(BasicBlock, bbPreds),
1623 sizeof(bbDummy->bbPreds));
1624 fprintf(fout, "Offset / size of bbReach = %3u / %3u\n", offsetof(BasicBlock, bbReach),
1625 sizeof(bbDummy->bbReach));
1626 fprintf(fout, "Offset / size of bbIDom = %3u / %3u\n", offsetof(BasicBlock, bbIDom),
1627 sizeof(bbDummy->bbIDom));
1628 fprintf(fout, "Offset / size of bbDfsNum = %3u / %3u\n", offsetof(BasicBlock, bbDfsNum),
1629 sizeof(bbDummy->bbDfsNum));
1630 fprintf(fout, "Offset / size of bbCodeOffs = %3u / %3u\n", offsetof(BasicBlock, bbCodeOffs),
1631 sizeof(bbDummy->bbCodeOffs));
1632 fprintf(fout, "Offset / size of bbCodeOffsEnd = %3u / %3u\n", offsetof(BasicBlock, bbCodeOffsEnd),
1633 sizeof(bbDummy->bbCodeOffsEnd));
1634 fprintf(fout, "Offset / size of bbVarUse = %3u / %3u\n", offsetof(BasicBlock, bbVarUse),
1635 sizeof(bbDummy->bbVarUse));
1636 fprintf(fout, "Offset / size of bbVarDef = %3u / %3u\n", offsetof(BasicBlock, bbVarDef),
1637 sizeof(bbDummy->bbVarDef));
1638 fprintf(fout, "Offset / size of bbLiveIn = %3u / %3u\n", offsetof(BasicBlock, bbLiveIn),
1639 sizeof(bbDummy->bbLiveIn));
1640 fprintf(fout, "Offset / size of bbLiveOut = %3u / %3u\n", offsetof(BasicBlock, bbLiveOut),
1641 sizeof(bbDummy->bbLiveOut));
1642 fprintf(fout, "Offset / size of bbHeapSsaPhiFunc = %3u / %3u\n", offsetof(BasicBlock, bbHeapSsaPhiFunc),
1643 sizeof(bbDummy->bbHeapSsaPhiFunc));
1644 fprintf(fout, "Offset / size of bbHeapSsaNumIn = %3u / %3u\n", offsetof(BasicBlock, bbHeapSsaNumIn),
1645 sizeof(bbDummy->bbHeapSsaNumIn));
1646 fprintf(fout, "Offset / size of bbHeapSsaNumOut = %3u / %3u\n", offsetof(BasicBlock, bbHeapSsaNumOut),
1647 sizeof(bbDummy->bbHeapSsaNumOut));
1648 fprintf(fout, "Offset / size of bbScope = %3u / %3u\n", offsetof(BasicBlock, bbScope),
1649 sizeof(bbDummy->bbScope));
1650 fprintf(fout, "Offset / size of bbCseGen = %3u / %3u\n", offsetof(BasicBlock, bbCseGen),
1651 sizeof(bbDummy->bbCseGen));
1652 fprintf(fout, "Offset / size of bbCseIn = %3u / %3u\n", offsetof(BasicBlock, bbCseIn),
1653 sizeof(bbDummy->bbCseIn));
1654 fprintf(fout, "Offset / size of bbCseOut = %3u / %3u\n", offsetof(BasicBlock, bbCseOut),
1655 sizeof(bbDummy->bbCseOut));
1657 fprintf(fout, "Offset / size of bbEmitCookie = %3u / %3u\n", offsetof(BasicBlock, bbEmitCookie),
1658 sizeof(bbDummy->bbEmitCookie));
1660 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
1661 fprintf(fout, "Offset / size of bbUnwindNopEmitCookie = %3u / %3u\n", offsetof(BasicBlock, bbUnwindNopEmitCookie),
1662 sizeof(bbDummy->bbUnwindNopEmitCookie));
1663 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
1666 fprintf(fout, "Offset / size of bbStackIn = %3u / %3u\n", offsetof(BasicBlock, bbStackIn),
1667 sizeof(bbDummy->bbStackIn));
1668 fprintf(fout, "Offset / size of bbStackOut = %3u / %3u\n", offsetof(BasicBlock, bbStackOut),
1669 sizeof(bbDummy->bbStackOut));
1670 fprintf(fout, "Offset / size of bbTypesIn = %3u / %3u\n", offsetof(BasicBlock, bbTypesIn),
1671 sizeof(bbDummy->bbTypesIn));
1672 fprintf(fout, "Offset / size of bbTypesOut = %3u / %3u\n", offsetof(BasicBlock, bbTypesOut),
1673 sizeof(bbDummy->bbTypesOut));
1676 #if FEATURE_STACK_FP_X87
1677 fprintf(fout, "Offset / size of bbFPStateX87 = %3u / %3u\n", offsetof(BasicBlock, bbFPStateX87),
1678 sizeof(bbDummy->bbFPStateX87));
1679 #endif // FEATURE_STACK_FP_X87
1682 fprintf(fout, "Offset / size of bbLoopNum = %3u / %3u\n", offsetof(BasicBlock, bbLoopNum),
1683 sizeof(bbDummy->bbLoopNum));
1686 fprintf(fout, "\n");
1687 fprintf(fout, "Size of BasicBlock = %3u\n", sizeof(BasicBlock));
1689 #endif // MEASURE_BLOCK_SIZE
1692 emitterStaticStats(fout);
1696 /*****************************************************************************
1701 void Compiler::compInit(ArenaAllocator* pAlloc, InlineInfo* inlineInfo)
1704 compAllocator = pAlloc;
1706 // Inlinee Compile object will only be allocated when needed for the 1st time.
1707 InlineeCompiler = nullptr;
1709 // Set the inline info.
1710 impInlineInfo = inlineInfo;
1712 eeInfoInitialized = false;
1714 compDoAggressiveInlining = false;
1716 if (compIsForInlining())
1718 m_inlineStrategy = nullptr;
1719 compInlineResult = inlineInfo->inlineResult;
1720 compAsIAllocator = nullptr; // We shouldn't be using the compAsIAllocator for other than the root compiler.
1721 #if MEASURE_MEM_ALLOC
1722 compAsIAllocatorBitset = nullptr;
1723 compAsIAllocatorGC = nullptr;
1724 compAsIAllocatorLoopHoist = nullptr;
1726 compAsIAllocatorDebugOnly = nullptr;
1728 #endif // MEASURE_MEM_ALLOC
1730 compQMarks = nullptr;
1734 m_inlineStrategy = new (this, CMK_Inlining) InlineStrategy(this);
1735 compInlineResult = nullptr;
1736 compAsIAllocator = new (this, CMK_Unknown) CompAllocator(this, CMK_AsIAllocator);
1737 #if MEASURE_MEM_ALLOC
1738 compAsIAllocatorBitset = new (this, CMK_Unknown) CompAllocator(this, CMK_bitset);
1739 compAsIAllocatorGC = new (this, CMK_Unknown) CompAllocator(this, CMK_GC);
1740 compAsIAllocatorLoopHoist = new (this, CMK_Unknown) CompAllocator(this, CMK_LoopHoist);
1742 compAsIAllocatorDebugOnly = new (this, CMK_Unknown) CompAllocator(this, CMK_DebugOnly);
1744 #endif // MEASURE_MEM_ALLOC
1746 compQMarks = new (this, CMK_Unknown) ExpandArrayStack<GenTreePtr>(getAllocator());
1749 #ifdef FEATURE_TRACELOGGING
1750 // Make sure JIT telemetry is initialized as soon as allocations can be made
1751 // but no later than a point where noway_asserts can be thrown.
1752 // 1. JIT telemetry could allocate some objects internally.
1753 // 2. NowayAsserts are tracked through telemetry.
1754 // Note: JIT telemetry could gather data when compiler is not fully initialized.
1755 // So you have to initialize the compiler variables you use for telemetry.
1756 assert((unsigned)PHASE_PRE_IMPORT == 0);
1757 previousCompletedPhase = PHASE_PRE_IMPORT;
1758 info.compILCodeSize = 0;
1759 info.compMethodHnd = nullptr;
1760 compJitTelemetry.Initialize(this);
1764 bRangeAllowStress = false;
1770 if (!compIsForInlining())
1772 codeGen = getCodeGenerator(this);
1773 #ifdef LEGACY_BACKEND
1775 #endif // LEGACY_BACKEND
1777 #ifndef LEGACY_BACKEND
1779 #endif // !LEGACY_BACKEND
1781 compVarScopeMap = nullptr;
1783 // If this method were a real constructor for Compiler, these would
1784 // become method initializations.
1785 impPendingBlockMembers = ExpandArray<BYTE>(getAllocator());
1786 impSpillCliquePredMembers = ExpandArray<BYTE>(getAllocator());
1787 impSpillCliqueSuccMembers = ExpandArray<BYTE>(getAllocator());
1789 memset(&lvHeapPerSsaData, 0, sizeof(PerSsaArray));
1790 lvHeapPerSsaData.Init(getAllocator());
1791 lvHeapNumSsaNames = 0;
1794 // Initialize all the per-method statistics gathering data structures.
1799 #if MEASURE_MEM_ALLOC
1801 #endif // MEASURE_MEM_ALLOC
1802 #if LOOP_HOIST_STATS
1803 m_loopsConsidered = 0;
1804 m_curLoopHasHoistedExpression = false;
1805 m_loopsWithHoistedExpressions = 0;
1806 m_totalHoistedExpressions = 0;
1807 #endif // LOOP_HOIST_STATS
1808 #if MEASURE_NODE_SIZE
1809 genNodeSizeStatsPerFunc.Init();
1810 #endif // MEASURE_NODE_SIZE
1817 compJmpOpUsed = false;
1818 compLongUsed = false;
1819 compTailCallUsed = false;
1820 compLocallocUsed = false;
1821 compQmarkRationalized = false;
1822 compQmarkUsed = false;
1823 compFloatingPointUsed = false;
1824 compUnsafeCastUsed = false;
1825 #if CPU_USES_BLOCK_MOVE
1826 compBlkOpUsed = false;
1828 #if FEATURE_STACK_FP_X87
1829 compMayHaveTransitionBlocks = false;
1831 compNeedsGSSecurityCookie = false;
1832 compGSReorderStackLayout = false;
1834 compStackProbePrologDone = false;
1837 compGeneratingProlog = false;
1838 compGeneratingEpilog = false;
1840 #ifndef LEGACY_BACKEND
1841 compLSRADone = false;
1842 #endif // !LEGACY_BACKEND
1843 compRationalIRForm = false;
1846 compCodeGenDone = false;
1847 compRegSetCheckLevel = 0;
1848 opts.compMinOptsIsUsed = false;
1850 opts.compMinOptsIsSet = false;
1852 // Used by fgFindJumpTargets for inlining heuristics.
1853 opts.instrCount = 0;
1855 // Used to track when we should consider running EarlyProp
1858 for (unsigned i = 0; i < MAX_LOOP_NUM; i++)
1860 AllVarSetOps::AssignNoCopy(this, optLoopTable[i].lpAsgVars, AllVarSetOps::UninitVal());
1864 m_nodeTestData = nullptr;
1865 m_loopHoistCSEClass = FIRST_LOOP_HOIST_CSE_CLASS;
1867 m_switchDescMap = nullptr;
1868 m_blockToEHPreds = nullptr;
1869 m_fieldSeqStore = nullptr;
1870 m_zeroOffsetFieldMap = nullptr;
1871 m_arrayInfoMap = nullptr;
1872 m_heapSsaMap = nullptr;
1873 m_refAnyClass = nullptr;
1876 if (!compIsForInlining())
1878 compDoComponentUnitTestsOnce();
1883 m_opAsgnVarDefSsaNums = nullptr;
1884 m_indirAssignMap = nullptr;
1885 fgSsaPassesCompleted = 0;
1886 fgVNPassesCompleted = 0;
1888 // check that HelperCallProperties are initialized
1890 assert(s_helperCallProperties.IsPure(CORINFO_HELP_GETSHARED_GCSTATIC_BASE));
1891 assert(!s_helperCallProperties.IsPure(CORINFO_HELP_GETFIELDOBJ)); // quick sanity check
1893 // We start with the flow graph in tree-order
1894 fgOrder = FGOrderTree;
1898 SIMDFloatHandle = nullptr;
1899 SIMDDoubleHandle = nullptr;
1900 SIMDIntHandle = nullptr;
1901 SIMDUShortHandle = nullptr;
1902 SIMDUByteHandle = nullptr;
1903 SIMDShortHandle = nullptr;
1904 SIMDByteHandle = nullptr;
1905 SIMDLongHandle = nullptr;
1906 SIMDUIntHandle = nullptr;
1907 SIMDULongHandle = nullptr;
1908 SIMDVector2Handle = nullptr;
1909 SIMDVector3Handle = nullptr;
1910 SIMDVector4Handle = nullptr;
1911 SIMDVectorHandle = nullptr;
1914 compUsesThrowHelper = false;
1917 /*****************************************************************************
1922 void Compiler::compDone()
1926 void* Compiler::compGetHelperFtn(CorInfoHelpFunc ftnNum, /* IN */
1927 void** ppIndirection) /* OUT */
1931 if (info.compMatchedVM)
1933 addr = info.compCompHnd->getHelperFtn(ftnNum, ppIndirection);
1937 // If we don't have a matched VM, we won't get valid results when asking for a helper function.
1938 addr = (void*)0xCA11CA11; // "callcall"
1944 unsigned Compiler::compGetTypeSize(CorInfoType cit, CORINFO_CLASS_HANDLE clsHnd)
1946 var_types sigType = genActualType(JITtype2varType(cit));
1948 sigSize = genTypeSize(sigType);
1949 if (cit == CORINFO_TYPE_VALUECLASS)
1951 sigSize = info.compCompHnd->getClassSize(clsHnd);
1953 else if (cit == CORINFO_TYPE_REFANY)
1955 sigSize = 2 * sizeof(void*);
1961 static bool DidComponentUnitTests = false;
1963 void Compiler::compDoComponentUnitTestsOnce()
1965 if (!JitConfig.RunComponentUnitTests())
1970 if (!DidComponentUnitTests)
1972 DidComponentUnitTests = true;
1973 ValueNumStore::RunTests(this);
1974 BitSetSupport::TestSuite(getAllocatorDebugOnly());
1979 /******************************************************************************
1981 * The Emitter uses this callback function to allocate its memory
1985 void* Compiler::compGetMemCallback(void* p, size_t size, CompMemKind cmk)
1989 return ((Compiler*)p)->compGetMem(size, cmk);
1992 /*****************************************************************************
1994 * The central memory allocation routine used by the compiler. Normally this
1995 * is a simple inline method defined in compiler.hpp, but for debugging it's
1996 * often convenient to keep it non-inline.
2001 void* Compiler::compGetMem(size_t sz, CompMemKind cmk)
2004 #if SMALL_TREE_NODES
2005 if (sz != TREE_NODE_SZ_SMALL &&
2006 sz != TREE_NODE_SZ_LARGE && sz > 32)
2008 printf("Alloc %3u bytes\n", sz);
2011 if (sz != sizeof(GenTree) && sz > 32)
2013 printf("Alloc %3u bytes\n", sz);
2018 #if MEASURE_MEM_ALLOC
2019 genMemStats.AddAlloc(sz, cmk);
2022 void* ptr = compAllocator->allocateMemory(sz);
2024 // Verify that the current block is aligned. Only then will the next
2025 // block allocated be on an aligned boundary.
2026 assert((size_t(ptr) & (sizeof(size_t) - 1)) == 0);
2033 /*****************************************************************************/
2035 /*****************************************************************************/
2037 VarName Compiler::compVarName(regNumber reg, bool isFloatReg)
2041 #if FEATURE_STACK_FP_X87
2042 assert(reg < FP_STK_SIZE); // would like to have same assert as below but sometimes you get -1?
2044 assert(genIsValidFloatReg(reg));
2049 assert(genIsValidReg(reg));
2052 if ((info.compVarScopesCount > 0) && compCurBB && opts.varNames)
2057 /* Look for the matching register */
2058 for (lclNum = 0, varDsc = lvaTable; lclNum < lvaCount; lclNum++, varDsc++)
2060 /* If the variable is not in a register, or not in the register we're looking for, quit. */
2061 /* Also, if it is a compiler generated variable (i.e. slot# > info.compVarScopesCount), don't bother. */
2062 if ((varDsc->lvRegister != 0) && (varDsc->lvRegNum == reg) && (varDsc->IsFloatRegType() || !isFloatReg) &&
2063 (varDsc->lvSlotNum < info.compVarScopesCount))
2065 /* check if variable in that register is live */
2066 if (VarSetOps::IsMember(this, compCurLife, varDsc->lvVarIndex))
2068 /* variable is live - find the corresponding slot */
2069 VarScopeDsc* varScope =
2070 compFindLocalVar(varDsc->lvSlotNum, compCurBB->bbCodeOffs, compCurBB->bbCodeOffsEnd);
2073 return varScope->vsdName;
2079 #ifdef LEGACY_BACKEND
2080 // maybe var is marked dead, but still used (last use)
2081 if (!isFloatReg && codeGen->regSet.rsUsedTree[reg] != NULL)
2085 if (GenTree::OperIsUnary(codeGen->regSet.rsUsedTree[reg]->OperGet()))
2087 assert(codeGen->regSet.rsUsedTree[reg]->gtOp.gtOp1 != NULL);
2088 nodePtr = codeGen->regSet.rsUsedTree[reg]->gtOp.gtOp1;
2092 nodePtr = codeGen->regSet.rsUsedTree[reg];
2095 if ((nodePtr->gtOper == GT_REG_VAR) && (nodePtr->gtRegVar.gtRegNum == reg) &&
2096 (nodePtr->gtRegVar.gtLclNum < info.compVarScopesCount))
2098 VarScopeDsc* varScope =
2099 compFindLocalVar(nodePtr->gtRegVar.gtLclNum, compCurBB->bbCodeOffs, compCurBB->bbCodeOffsEnd);
2101 return varScope->vsdName;
2104 #endif // LEGACY_BACKEND
2109 const char* Compiler::compRegVarName(regNumber reg, bool displayVar, bool isFloatReg)
2113 isFloatReg = genIsValidFloatReg(reg);
2116 if (displayVar && (reg != REG_NA))
2118 VarName varName = compVarName(reg, isFloatReg);
2122 const int NAME_VAR_REG_BUFFER_LEN = 4 + 256 + 1;
2123 static char nameVarReg[2][NAME_VAR_REG_BUFFER_LEN]; // to avoid overwriting the buffer when have 2
2124 // consecutive calls before printing
2125 static int index = 0; // for circular index into the name array
2127 index = (index + 1) % 2; // circular reuse of index
2128 sprintf_s(nameVarReg[index], NAME_VAR_REG_BUFFER_LEN, "%s'%s'", getRegName(reg, isFloatReg),
2129 VarNameToStr(varName));
2131 return nameVarReg[index];
2135 /* no debug info required or no variable in that register
2136 -> return standard name */
2138 return getRegName(reg, isFloatReg);
2141 #define MAX_REG_PAIR_NAME_LENGTH 10
2143 const char* Compiler::compRegPairName(regPairNo regPair)
2145 static char regNameLong[MAX_REG_PAIR_NAME_LENGTH];
2147 if (regPair == REG_PAIR_NONE)
2152 assert(regPair >= REG_PAIR_FIRST && regPair <= REG_PAIR_LAST);
2154 strcpy_s(regNameLong, sizeof(regNameLong), compRegVarName(genRegPairLo(regPair)));
2155 strcat_s(regNameLong, sizeof(regNameLong), "|");
2156 strcat_s(regNameLong, sizeof(regNameLong), compRegVarName(genRegPairHi(regPair)));
2160 const char* Compiler::compRegNameForSize(regNumber reg, size_t size)
2162 if (size == 0 || size >= 4)
2164 return compRegVarName(reg, true);
2169 const char * sizeNames[][2] =
2175 #ifdef _TARGET_AMD64_
2176 { "spl", "sp" }, // ESP
2177 { "bpl", "bp" }, // EBP
2178 { "sil", "si" }, // ESI
2179 { "dil", "di" }, // EDI
2188 #endif // _TARGET_AMD64_
2192 assert(isByteReg(reg));
2193 assert(genRegMask(reg) & RBM_BYTE_REGS);
2194 assert(size == 1 || size == 2);
2196 return sizeNames[reg][size - 1];
2199 const char* Compiler::compFPregVarName(unsigned fpReg, bool displayVar)
2201 const int NAME_VAR_REG_BUFFER_LEN = 4 + 256 + 1;
2202 static char nameVarReg[2][NAME_VAR_REG_BUFFER_LEN]; // to avoid overwriting the buffer when have 2 consecutive calls
2204 static int index = 0; // for circular index into the name array
2206 index = (index + 1) % 2; // circular reuse of index
2208 #if FEATURE_STACK_FP_X87
2209 /* 'fpReg' is the distance from the bottom of the stack, ie.
2210 * it is independant of the current FP stack level
2213 if (displayVar && codeGen->genFPregCnt)
2215 assert(fpReg < FP_STK_SIZE);
2216 assert(compCodeGenDone || (fpReg <= codeGen->compCurFPState.m_uStackSize));
2218 int pos = codeGen->genFPregCnt - (fpReg + 1 - codeGen->genGetFPstkLevel());
2221 VarName varName = compVarName((regNumber)pos, true);
2225 sprintf_s(nameVarReg[index], NAME_VAR_REG_BUFFER_LEN, "ST(%d)'%s'", fpReg, VarNameToStr(varName));
2226 return nameVarReg[index];
2230 #endif // FEATURE_STACK_FP_X87
2232 /* no debug info required or no variable in that register
2233 -> return standard name */
2235 sprintf_s(nameVarReg[index], NAME_VAR_REG_BUFFER_LEN, "ST(%d)", fpReg);
2236 return nameVarReg[index];
2239 const char* Compiler::compLocalVarName(unsigned varNum, unsigned offs)
2244 for (i = 0, t = info.compVarScopes; i < info.compVarScopesCount; i++, t++)
2246 if (t->vsdVarNum != varNum)
2251 if (offs >= t->vsdLifeBeg && offs < t->vsdLifeEnd)
2253 return VarNameToStr(t->vsdName);
2260 /*****************************************************************************/
2262 /*****************************************************************************/
2264 void Compiler::compSetProcessor()
2266 const JitFlags& jitFlags = *opts.jitFlags;
2268 #if defined(_TARGET_ARM_)
2269 info.genCPU = CPU_ARM;
2270 #elif defined(_TARGET_AMD64_)
2271 info.genCPU = CPU_X64;
2272 #elif defined(_TARGET_X86_)
2273 if (jitFlags.IsSet(JitFlags::JIT_FLAG_TARGET_P4))
2274 info.genCPU = CPU_X86_PENTIUM_4;
2276 info.genCPU = CPU_X86;
2280 // Processor specific optimizations
2282 CLANG_FORMAT_COMMENT_ANCHOR;
2284 #ifdef _TARGET_XARCH_
2285 opts.compCanUseSSE3_4 = false;
2286 if (!jitFlags.IsSet(JitFlags::JIT_FLAG_PREJIT) && jitFlags.IsSet(JitFlags::JIT_FLAG_USE_SSE3_4))
2288 if (JitConfig.EnableSSE3_4() != 0)
2290 opts.compCanUseSSE3_4 = true;
2294 #ifdef FEATURE_AVX_SUPPORT
2295 // COMPlus_EnableAVX can be used to disable using AVX if available on a target machine.
2296 // Note that FEATURE_AVX_SUPPORT is not enabled for ctpjit
2297 opts.compCanUseAVX = false;
2298 if (!jitFlags.IsSet(JitFlags::JIT_FLAG_PREJIT) && jitFlags.IsSet(JitFlags::JIT_FLAG_USE_AVX2))
2300 if (JitConfig.EnableAVX() != 0)
2302 opts.compCanUseAVX = true;
2305 #endif // FEATURE_AVX_SUPPORT
2307 if (!compIsForInlining())
2309 #ifdef FEATURE_AVX_SUPPORT
2310 if (opts.compCanUseAVX)
2312 codeGen->getEmitter()->SetUseAVX(true);
2313 // Assume each JITted method does not contain AVX instruction at first
2314 codeGen->getEmitter()->SetContainsAVX(false);
2315 codeGen->getEmitter()->SetContains256bitAVX(false);
2318 #endif // FEATURE_AVX_SUPPORT
2319 if (opts.compCanUseSSE3_4)
2321 codeGen->getEmitter()->SetUseSSE3_4(true);
2324 #endif // _TARGET_XARCH_
2326 #ifdef _TARGET_AMD64_
2327 opts.compUseFCOMI = false;
2328 opts.compUseCMOV = true;
2329 opts.compCanUseSSE2 = true;
2330 #elif defined(_TARGET_X86_)
2331 opts.compUseFCOMI = jitFlags.IsSet(JitFlags::JIT_FLAG_USE_FCOMI);
2332 opts.compUseCMOV = jitFlags.IsSet(JitFlags::JIT_FLAG_USE_CMOV);
2333 opts.compCanUseSSE2 = jitFlags.IsSet(JitFlags::JIT_FLAG_USE_SSE2);
2335 #if !defined(LEGACY_BACKEND) && !defined(FEATURE_CORECLR)
2336 // RyuJIT/x86 requires SSE2 to be available: there is no support for generating floating-point
2337 // code with x87 instructions. On .NET Core, the VM always tells us that SSE2 is available.
2338 // However, on desktop, under ngen, (and presumably in the unlikely case you're actually
2339 // running on a machine without SSE2), the VM does not set the SSE2 flag. We ignore this and
2340 // go ahead and generate SSE2 code anyway.
2341 if (!opts.compCanUseSSE2)
2343 JITDUMP("VM didn't set CORJIT_FLG_USE_SSE2! Ignoring, and generating SSE2 code anyway.\n");
2344 opts.compCanUseSSE2 = true;
2346 #endif // !defined(LEGACY_BACKEND) && !defined(FEATURE_CORECLR)
2349 if (opts.compUseFCOMI)
2350 opts.compUseFCOMI = !compStressCompile(STRESS_USE_FCOMI, 50);
2351 if (opts.compUseCMOV)
2352 opts.compUseCMOV = !compStressCompile(STRESS_USE_CMOV, 50);
2354 #ifdef LEGACY_BACKEND
2356 // Should we override the SSE2 setting?
2359 SSE2_FORCE_DISABLE = 0,
2361 SSE2_FORCE_INVALID = -1
2364 if (JitConfig.JitCanUseSSE2() == SSE2_FORCE_DISABLE)
2365 opts.compCanUseSSE2 = false;
2366 else if (JitConfig.JitCanUseSSE2() == SSE2_FORCE_USE)
2367 opts.compCanUseSSE2 = true;
2368 else if (opts.compCanUseSSE2)
2369 opts.compCanUseSSE2 = !compStressCompile(STRESS_GENERIC_VARN, 50);
2371 #else // !LEGACY_BACKEND
2373 // RyuJIT/x86 requires SSE2 to be available and hence
2374 // don't turn off compCanUseSSE2 under stress.
2375 assert(opts.compCanUseSSE2);
2377 #endif // !LEGACY_BACKEND
2381 #endif // _TARGET_X86_
2384 #ifdef PROFILING_SUPPORTED
2385 // A Dummy routine to receive Enter/Leave/Tailcall profiler callbacks.
2386 // These are used when complus_JitEltHookEnabled=1
2387 #ifdef _TARGET_AMD64_
2388 void DummyProfilerELTStub(UINT_PTR ProfilerHandle, UINT_PTR callerSP)
2392 #else //! _TARGET_AMD64_
2393 void DummyProfilerELTStub(UINT_PTR ProfilerHandle)
2397 #endif //!_TARGET_AMD64_
2399 #endif // PROFILING_SUPPORTED
2401 bool Compiler::compIsFullTrust()
2403 return (info.compCompHnd->canSkipMethodVerification(info.compMethodHnd) == CORINFO_VERIFICATION_CAN_SKIP);
2406 bool Compiler::compShouldThrowOnNoway(
2407 #ifdef FEATURE_TRACELOGGING
2408 const char* filename, unsigned line
2412 #ifdef FEATURE_TRACELOGGING
2413 compJitTelemetry.NotifyNowayAssert(filename, line);
2415 // In min opts, we don't want the noway assert to go through the exception
2416 // path. Instead we want it to just silently go through codegen for
2418 // If we are not in full trust, we should always fire for security.
2419 return !opts.MinOpts() || !compIsFullTrust();
2422 // ConfigInteger does not offer an option for decimal flags. Any numbers are interpreted as hex.
2423 // I could add the decimal option to ConfigInteger or I could write a function to reinterpret this
2424 // value as the user intended.
2425 unsigned ReinterpretHexAsDecimal(unsigned in)
2427 // ex: in: 0x100 returns: 100
2428 unsigned result = 0;
2439 unsigned digit = in % 16;
2442 result += digit * index;
2448 void Compiler::compInitOptions(JitFlags* jitFlags)
2450 #ifdef UNIX_AMD64_ABI
2451 opts.compNeedToAlignFrame = false;
2452 #endif // UNIX_AMD64_ABI
2453 memset(&opts, 0, sizeof(opts));
2455 if (compIsForInlining())
2457 // The following flags are lost when inlining. (They are removed in
2458 // Compiler::fgInvokeInlineeCompiler().)
2459 assert(!jitFlags->IsSet(JitFlags::JIT_FLAG_BBOPT));
2460 assert(!jitFlags->IsSet(JitFlags::JIT_FLAG_BBINSTR));
2461 assert(!jitFlags->IsSet(JitFlags::JIT_FLAG_PROF_ENTERLEAVE));
2462 assert(!jitFlags->IsSet(JitFlags::JIT_FLAG_DEBUG_EnC));
2463 assert(!jitFlags->IsSet(JitFlags::JIT_FLAG_DEBUG_INFO));
2465 assert(jitFlags->IsSet(JitFlags::JIT_FLAG_SKIP_VERIFICATION));
2468 opts.jitFlags = jitFlags;
2469 opts.compFlags = CLFLG_MAXOPT; // Default value is for full optimization
2471 if (jitFlags->IsSet(JitFlags::JIT_FLAG_DEBUG_CODE) || jitFlags->IsSet(JitFlags::JIT_FLAG_MIN_OPT))
2473 opts.compFlags = CLFLG_MINOPT;
2475 // Don't optimize .cctors (except prejit) or if we're an inlinee
2476 else if (!jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT) && ((info.compFlags & FLG_CCTOR) == FLG_CCTOR) &&
2477 !compIsForInlining())
2479 opts.compFlags = CLFLG_MINOPT;
2482 // Default value is to generate a blend of size and speed optimizations
2484 opts.compCodeOpt = BLENDED_CODE;
2486 // If the EE sets SIZE_OPT or if we are compiling a Class constructor
2487 // we will optimize for code size at the expense of speed
2489 if (jitFlags->IsSet(JitFlags::JIT_FLAG_SIZE_OPT) || ((info.compFlags & FLG_CCTOR) == FLG_CCTOR))
2491 opts.compCodeOpt = SMALL_CODE;
2494 // If the EE sets SPEED_OPT we will optimize for speed at the expense of code size
2496 else if (jitFlags->IsSet(JitFlags::JIT_FLAG_SPEED_OPT))
2498 opts.compCodeOpt = FAST_CODE;
2499 assert(!jitFlags->IsSet(JitFlags::JIT_FLAG_SIZE_OPT));
2502 //-------------------------------------------------------------------------
2504 opts.compDbgCode = jitFlags->IsSet(JitFlags::JIT_FLAG_DEBUG_CODE);
2505 opts.compDbgInfo = jitFlags->IsSet(JitFlags::JIT_FLAG_DEBUG_INFO);
2506 opts.compDbgEnC = jitFlags->IsSet(JitFlags::JIT_FLAG_DEBUG_EnC);
2508 #if REGEN_SHORTCUTS || REGEN_CALLPAT
2509 // We never want to have debugging enabled when regenerating GC encoding patterns
2510 opts.compDbgCode = false;
2511 opts.compDbgInfo = false;
2512 opts.compDbgEnC = false;
2518 opts.dspOrder = false;
2519 if (compIsForInlining())
2521 verbose = impInlineInfo->InlinerCompiler->verbose;
2526 codeGen->setVerbose(false);
2528 verboseTrees = verbose && shouldUseVerboseTrees();
2529 verboseSsa = verbose && shouldUseVerboseSsa();
2530 asciiTrees = shouldDumpASCIITrees();
2531 opts.dspDiffable = compIsForInlining() ? impInlineInfo->InlinerCompiler->opts.dspDiffable : false;
2534 opts.compNeedSecurityCheck = false;
2535 opts.altJit = false;
2537 #if defined(LATE_DISASM) && !defined(DEBUG)
2538 // For non-debug builds with the late disassembler built in, we currently always do late disassembly
2539 // (we have no way to determine when not to, since we don't have class/method names).
2540 // In the DEBUG case, this is initialized to false, below.
2541 opts.doLateDisasm = true;
2546 const JitConfigValues::MethodSet* pfAltJit;
2547 if (jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
2549 pfAltJit = &JitConfig.AltJitNgen();
2553 pfAltJit = &JitConfig.AltJit();
2557 if (pfAltJit->contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
2562 unsigned altJitLimit = ReinterpretHexAsDecimal(JitConfig.AltJitLimit());
2563 if (altJitLimit > 0 && Compiler::jitTotalMethodCompiled >= altJitLimit)
2565 opts.altJit = false;
2571 const char* altJitVal;
2572 if (jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
2574 altJitVal = JitConfig.AltJitNgen().list();
2578 altJitVal = JitConfig.AltJit().list();
2582 // In release mode, you either get all methods or no methods. You must use "*" as the parameter, or we ignore it.
2583 // You don't get to give a regular expression of methods to match.
2584 // (Partially, this is because we haven't computed and stored the method and class name except in debug, and it
2585 // might be expensive to do so.)
2586 if ((altJitVal != nullptr) && (strcmp(altJitVal, "*") == 0))
2595 // Take care of COMPlus_AltJitExcludeAssemblies.
2598 // First, initialize the AltJitExcludeAssemblies list, but only do it once.
2599 if (!s_pAltJitExcludeAssembliesListInitialized)
2601 const wchar_t* wszAltJitExcludeAssemblyList = JitConfig.AltJitExcludeAssemblies();
2602 if (wszAltJitExcludeAssemblyList != nullptr)
2604 // NOTE: The Assembly name list is allocated in the process heap, not in the no-release heap, which is
2606 // for every compilation. This is ok because we only allocate once, due to the static.
2607 s_pAltJitExcludeAssembliesList = new (HostAllocator::getHostAllocator())
2608 AssemblyNamesList2(wszAltJitExcludeAssemblyList, HostAllocator::getHostAllocator());
2610 s_pAltJitExcludeAssembliesListInitialized = true;
2613 if (s_pAltJitExcludeAssembliesList != nullptr)
2615 // We have an exclusion list. See if this method is in an assembly that is on the list.
2616 // Note that we check this for every method, since we might inline across modules, and
2617 // if the inlinee module is on the list, we don't want to use the altjit for it.
2618 const char* methodAssemblyName = info.compCompHnd->getAssemblyName(
2619 info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd)));
2620 if (s_pAltJitExcludeAssembliesList->IsInList(methodAssemblyName))
2622 opts.altJit = false;
2630 bool altJitConfig = !pfAltJit->isEmpty();
2632 // If we have a non-empty AltJit config then we change all of these other
2633 // config values to refer only to the AltJit. Otherwise, a lot of COMPlus_* variables
2634 // would apply to both the altjit and the normal JIT, but we only care about
2635 // debugging the altjit if the COMPlus_AltJit configuration is set.
2637 if (compIsForImportOnly() && (!altJitConfig || opts.altJit))
2639 if (JitConfig.JitImportBreak().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
2641 assert(!"JitImportBreak reached");
2645 bool verboseDump = false;
2646 bool dumpIR = false;
2647 bool dumpIRTypes = false;
2648 bool dumpIRLocals = false;
2649 bool dumpIRRegs = false;
2650 bool dumpIRSsa = false;
2651 bool dumpIRValnums = false;
2652 bool dumpIRCosts = false;
2653 bool dumpIRFlags = false;
2654 bool dumpIRKinds = false;
2655 bool dumpIRNodes = false;
2656 bool dumpIRNoLists = false;
2657 bool dumpIRNoLeafs = false;
2658 bool dumpIRNoStmts = false;
2659 bool dumpIRTrees = false;
2660 bool dumpIRLinear = false;
2661 bool dumpIRDataflow = false;
2662 bool dumpIRBlockHeaders = false;
2663 bool dumpIRExit = false;
2664 LPCWSTR dumpIRPhase = nullptr;
2665 LPCWSTR dumpIRFormat = nullptr;
2667 if (!altJitConfig || opts.altJit)
2669 LPCWSTR dumpIRFormat = nullptr;
2671 // We should only enable 'verboseDump' when we are actually compiling a matching method
2672 // and not enable it when we are just considering inlining a matching method.
2674 if (!compIsForInlining())
2676 if (jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
2678 if (JitConfig.NgenDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
2682 unsigned ngenHashDumpVal = (unsigned)JitConfig.NgenHashDump();
2683 if ((ngenHashDumpVal != (DWORD)-1) && (ngenHashDumpVal == info.compMethodHash()))
2687 if (JitConfig.NgenDumpIR().contains(info.compMethodName, info.compClassName,
2688 &info.compMethodInfo->args))
2692 unsigned ngenHashDumpIRVal = (unsigned)JitConfig.NgenHashDumpIR();
2693 if ((ngenHashDumpIRVal != (DWORD)-1) && (ngenHashDumpIRVal == info.compMethodHash()))
2697 dumpIRFormat = JitConfig.NgenDumpIRFormat();
2698 dumpIRPhase = JitConfig.NgenDumpIRPhase();
2702 if (JitConfig.JitDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
2706 unsigned jitHashDumpVal = (unsigned)JitConfig.JitHashDump();
2707 if ((jitHashDumpVal != (DWORD)-1) && (jitHashDumpVal == info.compMethodHash()))
2711 if (JitConfig.JitDumpIR().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
2715 unsigned jitHashDumpIRVal = (unsigned)JitConfig.JitHashDumpIR();
2716 if ((jitHashDumpIRVal != (DWORD)-1) && (jitHashDumpIRVal == info.compMethodHash()))
2720 dumpIRFormat = JitConfig.JitDumpIRFormat();
2721 dumpIRPhase = JitConfig.JitDumpIRPhase();
2725 if (dumpIRPhase == nullptr)
2727 dumpIRPhase = W("*");
2730 this->dumpIRPhase = dumpIRPhase;
2732 if (dumpIRFormat != nullptr)
2734 this->dumpIRFormat = dumpIRFormat;
2737 dumpIRTrees = false;
2738 dumpIRLinear = true;
2739 if (dumpIRFormat != nullptr)
2741 for (LPCWSTR p = dumpIRFormat; (*p != 0);)
2743 for (; (*p != 0); p++)
2756 static bool dumpedHelp = false;
2758 if ((*p == L'?') && (!dumpedHelp))
2760 printf("*******************************************************************************\n");
2765 printf("Available specifiers (comma separated):\n");
2767 printf("? dump out value of COMPlus_JitDumpIRFormat and this list of values\n");
2769 printf("linear linear IR dump (default)\n");
2770 printf("tree tree IR dump (traditional)\n");
2771 printf("mixed intermingle tree dump with linear IR dump\n");
2773 printf("dataflow use data flow form of linear IR dump\n");
2774 printf("structural use structural form of linear IR dump\n");
2775 printf("all implies structural, include everything\n");
2777 printf("kinds include tree node kinds in dump, example: \"kinds=[LEAF][LOCAL]\"\n");
2778 printf("flags include tree node flags in dump, example: \"flags=[CALL][GLOB_REF]\" \n");
2779 printf("types includes tree node types in dump, example: \".int\"\n");
2780 printf("locals include local numbers and tracking numbers in dump, example: \"(V3,T1)\"\n");
2781 printf("regs include register assignments in dump, example: \"(rdx)\"\n");
2782 printf("ssa include SSA numbers in dump, example: \"<d:3>\" or \"<u:3>\"\n");
2783 printf("valnums include Value numbers in dump, example: \"<v:$c4>\" or \"<v:$c4,$c5>\"\n");
2785 printf("nolist exclude GT_LIST nodes from dump\n");
2786 printf("noleafs exclude LEAF nodes from dump (fold into operations)\n");
2787 printf("nostmts exclude GT_STMTS from dump (unless required by dependencies)\n");
2789 printf("blkhdrs include block headers\n");
2790 printf("exit exit program after last phase dump (used with single method)\n");
2792 printf("*******************************************************************************\n");
2796 if (wcsncmp(p, W("types"), 5) == 0)
2801 if (wcsncmp(p, W("locals"), 6) == 0)
2803 dumpIRLocals = true;
2806 if (wcsncmp(p, W("regs"), 4) == 0)
2811 if (wcsncmp(p, W("ssa"), 3) == 0)
2816 if (wcsncmp(p, W("valnums"), 7) == 0)
2818 dumpIRValnums = true;
2821 if (wcsncmp(p, W("costs"), 5) == 0)
2826 if (wcsncmp(p, W("flags"), 5) == 0)
2831 if (wcsncmp(p, W("kinds"), 5) == 0)
2836 if (wcsncmp(p, W("nodes"), 5) == 0)
2841 if (wcsncmp(p, W("exit"), 4) == 0)
2846 if (wcsncmp(p, W("nolists"), 7) == 0)
2848 dumpIRNoLists = true;
2851 if (wcsncmp(p, W("noleafs"), 7) == 0)
2853 dumpIRNoLeafs = true;
2856 if (wcsncmp(p, W("nostmts"), 7) == 0)
2858 dumpIRNoStmts = true;
2861 if (wcsncmp(p, W("trees"), 5) == 0)
2864 dumpIRLinear = false;
2867 if (wcsncmp(p, W("structural"), 10) == 0)
2869 dumpIRLinear = true;
2870 dumpIRNoStmts = false;
2871 dumpIRNoLeafs = false;
2872 dumpIRNoLists = false;
2875 if (wcsncmp(p, W("all"), 3) == 0)
2877 dumpIRLinear = true;
2881 dumpIRLocals = true;
2884 dumpIRValnums = true;
2886 dumpIRNoStmts = false;
2887 dumpIRNoLeafs = false;
2888 dumpIRNoLists = false;
2891 if (wcsncmp(p, W("linear"), 6) == 0)
2893 dumpIRTrees = false;
2894 dumpIRLinear = true;
2897 if (wcsncmp(p, W("mixed"), 5) == 0)
2900 dumpIRLinear = true;
2903 if (wcsncmp(p, W("dataflow"), 8) == 0)
2905 dumpIRDataflow = true;
2906 dumpIRNoLeafs = true;
2907 dumpIRNoLists = true;
2908 dumpIRNoStmts = true;
2911 if (wcsncmp(p, W("blkhdrs"), 7) == 0)
2913 dumpIRBlockHeaders = true;
2916 for (; (*p != 0); p++)
2935 this->dumpIR = true;
2940 this->dumpIRTypes = true;
2945 this->dumpIRLocals = true;
2950 this->dumpIRRegs = true;
2955 this->dumpIRSsa = true;
2960 this->dumpIRValnums = true;
2965 this->dumpIRCosts = true;
2970 this->dumpIRFlags = true;
2975 this->dumpIRKinds = true;
2980 this->dumpIRNodes = true;
2985 this->dumpIRNoLists = true;
2990 this->dumpIRNoLeafs = true;
2993 if (dumpIRNoLeafs && dumpIRDataflow)
2995 this->dumpIRDataflow = true;
3000 this->dumpIRNoStmts = true;
3005 this->dumpIRTrees = true;
3010 this->dumpIRLinear = true;
3013 if (dumpIRBlockHeaders)
3015 this->dumpIRBlockHeaders = true;
3020 this->dumpIRExit = true;
3026 // Minimum bar for availing SIMD benefits is SSE2 on AMD64/x86.
3027 featureSIMD = jitFlags->IsSet(JitFlags::JIT_FLAG_FEATURE_SIMD);
3028 #endif // FEATURE_SIMD
3030 if (compIsForInlining() || compIsForImportOnly())
3034 // The rest of the opts fields that we initialize here
3035 // should only be used when we generate code for the method
3036 // They should not be used when importing or inlining
3038 opts.genFPorder = true;
3039 opts.genFPopt = true;
3041 opts.instrCount = 0;
3042 opts.lvRefCount = 0;
3044 #if FEATURE_TAILCALL_OPT
3045 // By default opportunistic tail call optimization is enabled
3046 opts.compTailCallOpt = true;
3047 opts.compTailCallLoopOpt = true;
3050 #ifdef PROFILING_SUPPORTED
3051 opts.compJitELTHookEnabled = false;
3052 #endif // PROFILING_SUPPORTED
3055 opts.dspInstrs = false;
3056 opts.dspEmit = false;
3057 opts.dspLines = false;
3058 opts.varNames = false;
3059 opts.dmpHex = false;
3060 opts.disAsm = false;
3061 opts.disAsmSpilled = false;
3062 opts.disDiffable = false;
3063 opts.dspCode = false;
3064 opts.dspEHTable = false;
3065 opts.dspGCtbls = false;
3066 opts.disAsm2 = false;
3067 opts.dspUnwind = false;
3068 opts.compLongAddress = false;
3069 opts.optRepeat = false;
3072 opts.doLateDisasm = false;
3073 #endif // LATE_DISASM
3075 compDebugBreak = false;
3077 // If we have a non-empty AltJit config then we change all of these other
3078 // config values to refer only to the AltJit.
3080 if (!altJitConfig || opts.altJit)
3082 if (jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
3084 if ((JitConfig.NgenOrder() & 1) == 1)
3086 opts.dspOrder = true;
3089 if (JitConfig.NgenGCDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3091 opts.dspGCtbls = true;
3094 if (JitConfig.NgenDisasm().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3098 if (JitConfig.NgenDisasm().contains("SPILLED", nullptr, nullptr))
3100 opts.disAsmSpilled = true;
3103 if (JitConfig.NgenUnwindDump().contains(info.compMethodName, info.compClassName,
3104 &info.compMethodInfo->args))
3106 opts.dspUnwind = true;
3109 if (JitConfig.NgenEHDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3111 opts.dspEHTable = true;
3116 if ((JitConfig.JitOrder() & 1) == 1)
3118 opts.dspOrder = true;
3121 if (JitConfig.JitGCDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3123 opts.dspGCtbls = true;
3126 if (JitConfig.JitDisasm().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3131 if (JitConfig.JitDisasm().contains("SPILLED", nullptr, nullptr))
3133 opts.disAsmSpilled = true;
3136 if (JitConfig.JitUnwindDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3138 opts.dspUnwind = true;
3141 if (JitConfig.JitEHDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3143 opts.dspEHTable = true;
3148 if (JitConfig.JitLateDisasm().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3149 opts.doLateDisasm = true;
3150 #endif // LATE_DISASM
3152 // This one applies to both Ngen/Jit Disasm output: COMPlus_JitDiffableDasm=1
3153 if (JitConfig.DiffableDasm() != 0)
3155 opts.disDiffable = true;
3156 opts.dspDiffable = true;
3159 if (JitConfig.JitLongAddress() != 0)
3161 opts.compLongAddress = true;
3164 if (JitConfig.JitOptRepeat().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3166 opts.optRepeat = true;
3172 opts.dspCode = true;
3173 opts.dspEHTable = true;
3174 opts.dspGCtbls = true;
3175 opts.disAsm2 = true;
3176 opts.dspUnwind = true;
3178 verboseTrees = shouldUseVerboseTrees();
3179 verboseSsa = shouldUseVerboseSsa();
3180 codeGen->setVerbose(true);
3183 treesBeforeAfterMorph = (JitConfig.TreesBeforeAfterMorph() == 1);
3184 morphNum = 0; // Initialize the morphed-trees counting.
3186 expensiveDebugCheckLevel = JitConfig.JitExpensiveDebugCheckLevel();
3187 if (expensiveDebugCheckLevel == 0)
3189 // If we're in a stress mode that modifies the flowgraph, make 1 the default.
3190 if (fgStressBBProf() || compStressCompile(STRESS_DO_WHILE_LOOPS, 30))
3192 expensiveDebugCheckLevel = 1;
3198 printf("****** START compiling %s (MethodHash=%08x)\n", info.compFullName, info.compMethodHash());
3199 printf("Generating code for %s %s\n", Target::g_tgtPlatformName, Target::g_tgtCPUName);
3200 printf(""); // in our logic this causes a flush
3203 if (JitConfig.JitBreak().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3205 assert(!"JitBreak reached");
3208 unsigned jitHashBreakVal = (unsigned)JitConfig.JitHashBreak();
3209 if ((jitHashBreakVal != (DWORD)-1) && (jitHashBreakVal == info.compMethodHash()))
3211 assert(!"JitHashBreak reached");
3215 JitConfig.JitDebugBreak().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args) ||
3216 JitConfig.JitBreak().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3218 compDebugBreak = true;
3221 memset(compActiveStressModes, 0, sizeof(compActiveStressModes));
3225 //-------------------------------------------------------------------------
3228 assert(!codeGen->isGCTypeFixed());
3229 opts.compGcChecks = (JitConfig.JitGCChecks() != 0) || compStressCompile(STRESS_GENERIC_VARN, 5);
3233 STACK_CHECK_ON_RETURN = 0x1,
3234 STACK_CHECK_ON_CALL = 0x2,
3235 STACK_CHECK_ALL = 0x3,
3238 DWORD dwJitStackChecks = JitConfig.JitStackChecks();
3239 if (compStressCompile(STRESS_GENERIC_VARN, 5))
3241 dwJitStackChecks = STACK_CHECK_ALL;
3243 opts.compStackCheckOnRet = (dwJitStackChecks & DWORD(STACK_CHECK_ON_RETURN)) != 0;
3244 opts.compStackCheckOnCall = (dwJitStackChecks & DWORD(STACK_CHECK_ON_CALL)) != 0;
3247 #if MEASURE_MEM_ALLOC
3248 s_dspMemStats = (JitConfig.DisplayMemStats() != 0);
3251 #ifdef PROFILING_SUPPORTED
3252 opts.compNoPInvokeInlineCB = jitFlags->IsSet(JitFlags::JIT_FLAG_PROF_NO_PINVOKE_INLINE);
3254 // Cache the profiler handle
3255 if (jitFlags->IsSet(JitFlags::JIT_FLAG_PROF_ENTERLEAVE))
3259 info.compCompHnd->GetProfilingHandle(&hookNeeded, &compProfilerMethHnd, &indirected);
3260 compProfilerHookNeeded = !!hookNeeded;
3261 compProfilerMethHndIndirected = !!indirected;
3265 compProfilerHookNeeded = false;
3266 compProfilerMethHnd = nullptr;
3267 compProfilerMethHndIndirected = false;
3270 // Honour COMPlus_JitELTHookEnabled only if VM has not asked us to generate profiler
3271 // hooks in the first place. That is, override VM only if it hasn't asked for a
3272 // profiler callback for this method.
3273 if (!compProfilerHookNeeded && (JitConfig.JitELTHookEnabled() != 0))
3275 opts.compJitELTHookEnabled = true;
3278 // TBD: Exclude PInvoke stubs
3279 if (opts.compJitELTHookEnabled)
3281 compProfilerMethHnd = (void*)DummyProfilerELTStub;
3282 compProfilerMethHndIndirected = false;
3285 #endif // PROFILING_SUPPORTED
3287 #if FEATURE_TAILCALL_OPT
3288 const wchar_t* strTailCallOpt = JitConfig.TailCallOpt();
3289 if (strTailCallOpt != nullptr)
3291 opts.compTailCallOpt = (UINT)_wtoi(strTailCallOpt) != 0;
3294 if (JitConfig.TailCallLoopOpt() == 0)
3296 opts.compTailCallLoopOpt = false;
3300 opts.compScopeInfo = opts.compDbgInfo;
3303 codeGen->getDisAssembler().disOpenForLateDisAsm(info.compMethodName, info.compClassName,
3304 info.compMethodInfo->args.pSig);
3307 //-------------------------------------------------------------------------
3310 opts.compReloc = jitFlags->IsSet(JitFlags::JIT_FLAG_RELOC);
3314 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
3315 // Whether encoding of absolute addr as PC-rel offset is enabled in RyuJIT
3316 opts.compEnablePCRelAddr = (JitConfig.EnablePCRelAddr() != 0);
3320 opts.compProcedureSplitting = jitFlags->IsSet(JitFlags::JIT_FLAG_PROCSPLIT);
3322 #ifdef _TARGET_ARM64_
3323 // TODO-ARM64-NYI: enable hot/cold splitting
3324 opts.compProcedureSplitting = false;
3325 #endif // _TARGET_ARM64_
3328 opts.compProcedureSplittingEH = opts.compProcedureSplitting;
3331 if (opts.compProcedureSplitting)
3333 // Note that opts.compdbgCode is true under ngen for checked assemblies!
3334 opts.compProcedureSplitting = !opts.compDbgCode;
3337 // JitForceProcedureSplitting is used to force procedure splitting on checked assemblies.
3338 // This is useful for debugging on a checked build. Note that we still only do procedure
3339 // splitting in the zapper.
3340 if (JitConfig.JitForceProcedureSplitting().contains(info.compMethodName, info.compClassName,
3341 &info.compMethodInfo->args))
3343 opts.compProcedureSplitting = true;
3346 // JitNoProcedureSplitting will always disable procedure splitting.
3347 if (JitConfig.JitNoProcedureSplitting().contains(info.compMethodName, info.compClassName,
3348 &info.compMethodInfo->args))
3350 opts.compProcedureSplitting = false;
3353 // JitNoProcedureSplittingEH will disable procedure splitting in functions with EH.
3354 if (JitConfig.JitNoProcedureSplittingEH().contains(info.compMethodName, info.compClassName,
3355 &info.compMethodInfo->args))
3357 opts.compProcedureSplittingEH = false;
3362 fgProfileBuffer = nullptr;
3363 fgProfileData_ILSizeMismatch = false;
3364 fgNumProfileRuns = 0;
3365 if (jitFlags->IsSet(JitFlags::JIT_FLAG_BBOPT))
3367 assert(!compIsForInlining());
3369 hr = info.compCompHnd->getBBProfileData(info.compMethodHnd, &fgProfileBufferCount, &fgProfileBuffer,
3372 // a failed result that also has a non-NULL fgProfileBuffer
3373 // indicates that the ILSize for the method no longer matches
3374 // the ILSize for the method when profile data was collected.
3376 // We will discard the IBC data in this case
3378 if (FAILED(hr) && (fgProfileBuffer != nullptr))
3380 fgProfileData_ILSizeMismatch = true;
3381 fgProfileBuffer = nullptr;
3384 // A successful result implies a non-NULL fgProfileBuffer
3388 assert(fgProfileBuffer != nullptr);
3391 // A failed result implies a NULL fgProfileBuffer
3392 // see implementation of Compiler::fgHaveProfileData()
3396 assert(fgProfileBuffer == nullptr);
3401 opts.compNeedStackProbes = false;
3404 if (JitConfig.StackProbesOverride() != 0 || compStressCompile(STRESS_GENERIC_VARN, 5))
3406 opts.compNeedStackProbes = true;
3411 // Now, set compMaxUncheckedOffsetForNullObject for STRESS_NULL_OBJECT_CHECK
3412 if (compStressCompile(STRESS_NULL_OBJECT_CHECK, 30))
3414 compMaxUncheckedOffsetForNullObject = (size_t)JitConfig.JitMaxUncheckedOffset();
3417 printf("STRESS_NULL_OBJECT_CHECK: compMaxUncheckedOffsetForNullObject=0x%X\n",
3418 compMaxUncheckedOffsetForNullObject);
3424 printf("OPTIONS: compCodeOpt = %s\n",
3425 (opts.compCodeOpt == BLENDED_CODE)
3427 : (opts.compCodeOpt == SMALL_CODE) ? "SMALL_CODE"
3428 : (opts.compCodeOpt == FAST_CODE) ? "FAST_CODE" : "UNKNOWN_CODE");
3430 printf("OPTIONS: compDbgCode = %s\n", dspBool(opts.compDbgCode));
3431 printf("OPTIONS: compDbgInfo = %s\n", dspBool(opts.compDbgInfo));
3432 printf("OPTIONS: compDbgEnC = %s\n", dspBool(opts.compDbgEnC));
3433 printf("OPTIONS: compProcedureSplitting = %s\n", dspBool(opts.compProcedureSplitting));
3434 printf("OPTIONS: compProcedureSplittingEH = %s\n", dspBool(opts.compProcedureSplittingEH));
3436 if (jitFlags->IsSet(JitFlags::JIT_FLAG_BBOPT) && fgHaveProfileData())
3438 printf("OPTIONS: using real profile data\n");
3441 if (fgProfileData_ILSizeMismatch)
3443 printf("OPTIONS: discarded IBC profile data due to mismatch in ILSize\n");
3446 if (jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
3448 printf("OPTIONS: Jit invoked for ngen\n");
3450 printf("OPTIONS: Stack probing is %s\n", opts.compNeedStackProbes ? "ENABLED" : "DISABLED");
3454 opts.compGCPollType = GCPOLL_NONE;
3455 if (jitFlags->IsSet(JitFlags::JIT_FLAG_GCPOLL_CALLS))
3457 opts.compGCPollType = GCPOLL_CALL;
3459 else if (jitFlags->IsSet(JitFlags::JIT_FLAG_GCPOLL_INLINE))
3461 // make sure that the EE didn't set both flags.
3462 assert(opts.compGCPollType == GCPOLL_NONE);
3463 opts.compGCPollType = GCPOLL_INLINE;
3469 void JitDump(const char* pcFormat, ...)
3472 va_start(lst, pcFormat);
3473 vflogf(jitstdout, pcFormat, lst);
3477 bool Compiler::compJitHaltMethod()
3479 /* This method returns true when we use an INS_BREAKPOINT to allow us to step into the generated native code */
3480 /* Note that this these two "Jit" environment variables also work for ngen images */
3482 if (JitConfig.JitHalt().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3487 /* Use this Hash variant when there are a lot of method with the same name and different signatures */
3489 unsigned fJitHashHaltVal = (unsigned)JitConfig.JitHashHalt();
3490 if ((fJitHashHaltVal != (unsigned)-1) && (fJitHashHaltVal == info.compMethodHash()))
3498 /*****************************************************************************
3499 * Should we use a "stress-mode" for the given stressArea. We have different
3500 * areas to allow the areas to be mixed in different combinations in
3501 * different methods.
3502 * 'weight' indicates how often (as a percentage) the area should be stressed.
3503 * It should reflect the usefulness:overhead ratio.
3506 const LPCWSTR Compiler::s_compStressModeNames[STRESS_COUNT + 1] = {
3507 #define STRESS_MODE(mode) W("STRESS_") W(#mode),
3513 bool Compiler::compStressCompile(compStressArea stressArea, unsigned weight)
3518 if (!bRangeAllowStress)
3523 if (!JitConfig.JitStressOnly().isEmpty() &&
3524 !JitConfig.JitStressOnly().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3529 bool doStress = false;
3530 const wchar_t* strStressModeNames;
3532 // Does user explicitly prevent using this STRESS_MODE through the command line?
3533 const wchar_t* strStressModeNamesNot = JitConfig.JitStressModeNamesNot();
3534 if ((strStressModeNamesNot != nullptr) &&
3535 (wcsstr(strStressModeNamesNot, s_compStressModeNames[stressArea]) != nullptr))
3539 printf("JitStressModeNamesNot contains %ws\n", s_compStressModeNames[stressArea]);
3545 // Does user explicitly set this STRESS_MODE through the command line?
3546 strStressModeNames = JitConfig.JitStressModeNames();
3547 if (strStressModeNames != nullptr)
3549 if (wcsstr(strStressModeNames, s_compStressModeNames[stressArea]) != nullptr)
3553 printf("JitStressModeNames contains %ws\n", s_compStressModeNames[stressArea]);
3559 // This stress mode name did not match anything in the stress
3560 // mode whitelist. If user has requested only enable mode,
3561 // don't allow this stress mode to turn on.
3562 const bool onlyEnableMode = JitConfig.JitStressModeNamesOnly() != 0;
3571 // 0: No stress (Except when explicitly set in complus_JitStressModeNames)
3572 // !=2: Vary stress. Performance will be slightly/moderately degraded
3573 // 2: Check-all stress. Performance will be REALLY horrible
3574 stressLevel = getJitStressLevel();
3576 assert(weight <= MAX_STRESS_WEIGHT);
3578 /* Check for boundary conditions */
3580 if (stressLevel == 0 || weight == 0)
3585 // Should we allow unlimited stress ?
3586 if (stressArea > STRESS_COUNT_VARN && stressLevel == 2)
3591 if (weight == MAX_STRESS_WEIGHT)
3597 // Get a hash which can be compared with 'weight'
3599 assert(stressArea != 0);
3600 hash = (info.compMethodHash() ^ stressArea ^ stressLevel) % MAX_STRESS_WEIGHT;
3602 assert(hash < MAX_STRESS_WEIGHT && weight <= MAX_STRESS_WEIGHT);
3603 doStress = (hash < weight);
3607 if (doStress && !compActiveStressModes[stressArea])
3611 printf("\n\n*** JitStress: %ws ***\n\n", s_compStressModeNames[stressArea]);
3613 compActiveStressModes[stressArea] = 1;
3621 void Compiler::compInitDebuggingInfo()
3623 assert(!compIsForInlining());
3628 printf("*************** In compInitDebuggingInfo() for %s\n", info.compFullName);
3632 /*-------------------------------------------------------------------------
3634 * Get hold of the local variable records, if there are any
3637 info.compVarScopesCount = 0;
3639 if (opts.compScopeInfo)
3644 compInitVarScopeMap();
3646 if (opts.compScopeInfo || opts.compDbgCode)
3648 compInitScopeLists();
3651 if (opts.compDbgCode && (info.compVarScopesCount > 0))
3653 /* Create a new empty basic block. fgExtendDbgLifetimes() may add
3654 initialization of variables which are in scope right from the
3655 start of the (real) first BB (and therefore artificially marked
3656 as alive) into this block.
3659 fgEnsureFirstBBisScratch();
3661 fgInsertStmtAtEnd(fgFirstBB, gtNewNothingNode());
3663 JITDUMP("Debuggable code - Add new BB%02u to perform initialization of variables [%08X]\n", fgFirstBB->bbNum,
3667 /*-------------------------------------------------------------------------
3669 * Read the stmt-offsets table and the line-number table
3672 info.compStmtOffsetsImplicit = ICorDebugInfo::NO_BOUNDARIES;
3674 // We can only report debug info for EnC at places where the stack is empty.
3675 // Actually, at places where there are not live temps. Else, we won't be able
3676 // to map between the old and the new versions correctly as we won't have
3677 // any info for the live temps.
3679 assert(!opts.compDbgEnC || !opts.compDbgInfo ||
3680 0 == (info.compStmtOffsetsImplicit & ~ICorDebugInfo::STACK_EMPTY_BOUNDARIES));
3682 info.compStmtOffsetsCount = 0;
3684 if (opts.compDbgInfo)
3686 /* Get hold of the line# records, if there are any */
3693 printf("info.compStmtOffsetsCount = %d\n", info.compStmtOffsetsCount);
3694 printf("info.compStmtOffsetsImplicit = %04Xh", info.compStmtOffsetsImplicit);
3696 if (info.compStmtOffsetsImplicit)
3699 if (info.compStmtOffsetsImplicit & ICorDebugInfo::STACK_EMPTY_BOUNDARIES)
3701 printf("STACK_EMPTY ");
3703 if (info.compStmtOffsetsImplicit & ICorDebugInfo::NOP_BOUNDARIES)
3707 if (info.compStmtOffsetsImplicit & ICorDebugInfo::CALL_SITE_BOUNDARIES)
3709 printf("CALL_SITE ");
3714 IL_OFFSET* pOffs = info.compStmtOffsets;
3715 for (unsigned i = 0; i < info.compStmtOffsetsCount; i++, pOffs++)
3717 printf("%02d) IL_%04Xh\n", i, *pOffs);
3724 void Compiler::compSetOptimizationLevel()
3726 bool theMinOptsValue;
3727 unsigned jitMinOpts;
3729 if (compIsForInlining())
3731 theMinOptsValue = impInlineInfo->InlinerCompiler->opts.MinOpts();
3735 theMinOptsValue = false;
3737 if (opts.compFlags == CLFLG_MINOPT)
3739 JITLOG((LL_INFO100, "CLFLG_MINOPT set for method %s\n", info.compFullName));
3740 theMinOptsValue = true;
3744 jitMinOpts = JitConfig.JitMinOpts();
3746 if (!theMinOptsValue && (jitMinOpts > 0))
3748 unsigned methodCount = Compiler::jitTotalMethodCompiled;
3749 unsigned methodCountMask = methodCount & 0xFFF;
3750 unsigned kind = (jitMinOpts & 0xF000000) >> 24;
3754 if (jitMinOpts <= methodCount)
3758 printf(" Optimizations disabled by JitMinOpts and methodCount\n");
3760 theMinOptsValue = true;
3765 unsigned firstMinopts = (jitMinOpts >> 12) & 0xFFF;
3766 unsigned secondMinopts = (jitMinOpts >> 0) & 0xFFF;
3768 if ((firstMinopts == methodCountMask) || (secondMinopts == methodCountMask))
3772 printf("0xD: Optimizations disabled by JitMinOpts and methodCountMask\n");
3774 theMinOptsValue = true;
3780 unsigned startMinopts = (jitMinOpts >> 12) & 0xFFF;
3781 unsigned endMinopts = (jitMinOpts >> 0) & 0xFFF;
3783 if ((startMinopts <= methodCountMask) && (endMinopts >= methodCountMask))
3787 printf("0xE: Optimizations disabled by JitMinOpts and methodCountMask\n");
3789 theMinOptsValue = true;
3795 unsigned bitsZero = (jitMinOpts >> 12) & 0xFFF;
3796 unsigned bitsOne = (jitMinOpts >> 0) & 0xFFF;
3798 if (((methodCountMask & bitsOne) == bitsOne) && ((~methodCountMask & bitsZero) == bitsZero))
3802 printf("0xF: Optimizations disabled by JitMinOpts and methodCountMask\n");
3804 theMinOptsValue = true;
3811 if (!theMinOptsValue)
3813 if (JitConfig.JitMinOptsName().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3815 theMinOptsValue = true;
3820 // The code in this #if can be used to debug optimization issues according to method hash.
3821 // To use, uncomment, rebuild and set environment variables minoptshashlo and minoptshashhi.
3823 unsigned methHash = info.compMethodHash();
3824 char* lostr = getenv("minoptshashlo");
3825 unsigned methHashLo = 0;
3826 if (lostr != nullptr)
3828 sscanf_s(lostr, "%x", &methHashLo);
3829 char* histr = getenv("minoptshashhi");
3830 unsigned methHashHi = UINT32_MAX;
3831 if (histr != nullptr)
3833 sscanf_s(histr, "%x", &methHashHi);
3834 if (methHash >= methHashLo && methHash <= methHashHi)
3836 printf("MinOpts for method %s, hash = 0x%x.\n",
3837 info.compFullName, info.compMethodHash());
3838 printf(""); // in our logic this causes a flush
3839 theMinOptsValue = true;
3846 if (compStressCompile(STRESS_MIN_OPTS, 5))
3848 theMinOptsValue = true;
3850 // For PREJIT we never drop down to MinOpts
3851 // unless unless CLFLG_MINOPT is set
3852 else if (!opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
3854 if ((unsigned)JitConfig.JitMinOptsCodeSize() < info.compILCodeSize)
3856 JITLOG((LL_INFO10, "IL Code Size exceeded, using MinOpts for method %s\n", info.compFullName));
3857 theMinOptsValue = true;
3859 else if ((unsigned)JitConfig.JitMinOptsInstrCount() < opts.instrCount)
3861 JITLOG((LL_INFO10, "IL instruction count exceeded, using MinOpts for method %s\n", info.compFullName));
3862 theMinOptsValue = true;
3864 else if ((unsigned)JitConfig.JitMinOptsBbCount() < fgBBcount)
3866 JITLOG((LL_INFO10, "Basic Block count exceeded, using MinOpts for method %s\n", info.compFullName));
3867 theMinOptsValue = true;
3869 else if ((unsigned)JitConfig.JitMinOptsLvNumCount() < lvaCount)
3871 JITLOG((LL_INFO10, "Local Variable Num count exceeded, using MinOpts for method %s\n", info.compFullName));
3872 theMinOptsValue = true;
3874 else if ((unsigned)JitConfig.JitMinOptsLvRefCount() < opts.lvRefCount)
3876 JITLOG((LL_INFO10, "Local Variable Ref count exceeded, using MinOpts for method %s\n", info.compFullName));
3877 theMinOptsValue = true;
3879 if (theMinOptsValue == true)
3881 JITLOG((LL_INFO10000, "IL Code Size,Instr %4d,%4d, Basic Block count %3d, Local Variable Num,Ref count "
3882 "%3d,%3d for method %s\n",
3883 info.compILCodeSize, opts.instrCount, fgBBcount, lvaCount, opts.lvRefCount, info.compFullName));
3884 if (JitConfig.JitBreakOnMinOpts() != 0)
3886 assert(!"MinOpts enabled");
3891 // Retail check if we should force Minopts due to the complexity of the method
3892 // For PREJIT we never drop down to MinOpts
3893 // unless unless CLFLG_MINOPT is set
3894 if (!theMinOptsValue && !opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT) &&
3895 ((DEFAULT_MIN_OPTS_CODE_SIZE < info.compILCodeSize) || (DEFAULT_MIN_OPTS_INSTR_COUNT < opts.instrCount) ||
3896 (DEFAULT_MIN_OPTS_BB_COUNT < fgBBcount) || (DEFAULT_MIN_OPTS_LV_NUM_COUNT < lvaCount) ||
3897 (DEFAULT_MIN_OPTS_LV_REF_COUNT < opts.lvRefCount)))
3899 theMinOptsValue = true;
3903 JITLOG((LL_INFO10000,
3904 "IL Code Size,Instr %4d,%4d, Basic Block count %3d, Local Variable Num,Ref count %3d,%3d for method %s\n",
3905 info.compILCodeSize, opts.instrCount, fgBBcount, lvaCount, opts.lvRefCount, info.compFullName));
3908 // The code in this #if has been useful in debugging loop cloning issues, by
3909 // enabling selective enablement of the loop cloning optimization according to
3912 if (!theMinOptsValue)
3914 unsigned methHash = info.compMethodHash();
3915 char* lostr = getenv("opthashlo");
3916 unsigned methHashLo = 0;
3919 sscanf_s(lostr, "%x", &methHashLo);
3920 // methHashLo = (unsigned(atoi(lostr)) << 2); // So we don't have to use negative numbers.
3922 char* histr = getenv("opthashhi");
3923 unsigned methHashHi = UINT32_MAX;
3926 sscanf_s(histr, "%x", &methHashHi);
3927 // methHashHi = (unsigned(atoi(histr)) << 2); // So we don't have to use negative numbers.
3929 if (methHash < methHashLo || methHash > methHashHi)
3931 theMinOptsValue = true;
3935 printf("Doing optimization in in %s (0x%x).\n", info.compFullName, methHash);
3943 // Set the MinOpts value
3944 opts.SetMinOpts(theMinOptsValue);
3947 if (verbose && !compIsForInlining())
3949 printf("OPTIONS: opts.MinOpts() == %s\n", opts.MinOpts() ? "true" : "false");
3953 /* Control the optimizations */
3955 if (opts.MinOpts() || opts.compDbgCode)
3957 opts.compFlags &= ~CLFLG_MAXOPT;
3958 opts.compFlags |= CLFLG_MINOPT;
3961 if (!compIsForInlining())
3963 codeGen->setFramePointerRequired(false);
3964 codeGen->setFrameRequired(false);
3966 if (opts.MinOpts() || opts.compDbgCode)
3968 codeGen->setFrameRequired(true);
3971 #if !defined(_TARGET_AMD64_)
3972 // The VM sets JitFlags::JIT_FLAG_FRAMED for two reasons: (1) the COMPlus_JitFramed variable is set, or
3973 // (2) the function is marked "noinline". The reason for #2 is that people mark functions
3974 // noinline to ensure the show up on in a stack walk. But for AMD64, we don't need a frame
3975 // pointer for the frame to show up in stack walk.
3976 if (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_FRAMED))
3977 codeGen->setFrameRequired(true);
3980 if (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_RELOC))
3982 codeGen->genAlignLoops = false; // loop alignment not supported for prejitted code
3984 // The zapper doesn't set JitFlags::JIT_FLAG_ALIGN_LOOPS, and there is
3985 // no reason for it to set it as the JIT doesn't currently support loop alignment
3986 // for prejitted images. (The JIT doesn't know the final address of the code, hence
3987 // it can't align code based on unknown addresses.)
3988 assert(!opts.jitFlags->IsSet(JitFlags::JIT_FLAG_ALIGN_LOOPS));
3992 codeGen->genAlignLoops = opts.jitFlags->IsSet(JitFlags::JIT_FLAG_ALIGN_LOOPS);
3996 info.compUnwrapContextful = !opts.MinOpts() && !opts.compDbgCode;
3998 fgCanRelocateEHRegions = true;
4001 #ifdef _TARGET_ARMARCH_
4002 // Function compRsvdRegCheck:
4003 // given a curState to use for calculating the total frame size
4004 // it will return true if the REG_OPT_RSVD should be reserved so
4005 // that it can be use to form large offsets when accessing stack
4006 // based LclVar including both incoming and out going argument areas.
4008 // The method advances the frame layout state to curState by calling
4009 // lvaFrameSize(curState).
4011 bool Compiler::compRsvdRegCheck(FrameLayoutState curState)
4013 // Always do the layout even if returning early. Callers might
4014 // depend on us to do the layout.
4015 unsigned frameSize = lvaFrameSize(curState);
4019 // Have a recovery path in case we fail to reserve REG_OPT_RSVD and go
4020 // over the limit of SP and FP offset ranges due to large
4025 unsigned calleeSavedRegMaxSz = CALLEE_SAVED_REG_MAXSZ;
4026 if (compFloatingPointUsed)
4028 calleeSavedRegMaxSz += CALLEE_SAVED_FLOAT_MAXSZ;
4031 noway_assert(frameSize > calleeSavedRegMaxSz);
4033 #if defined(_TARGET_ARM64_)
4035 // TODO-ARM64-CQ: update this!
4036 return true; // just always assume we'll need it, for now
4038 #else // _TARGET_ARM_
4043 // inArgs compArgSize
4047 // + callee saved regs CALLEE_SAVED_REG_MAXSZ (32 bytes)
4048 // optional saved fp regs 16 * sizeof(float) (64 bytes)
4050 // incl. TEMPS MAX_SPILL_TEMP_SIZE
4056 // With codeGen->isFramePointerRequired we use R11 to access incoming args with positive offsets
4057 // and use R11 to access LclVars with negative offsets in the non funclet or
4058 // main region we use SP with positive offsets. The limiting factor in the
4059 // codeGen->isFramePointerRequired case is that we need the offset to be less than or equal to 0x7C
4060 // for negative offsets, but positive offsets can be imm12 limited by vldr/vstr
4063 // Subtract 4 bytes for alignment of a local var because number of temps could
4064 // trigger a misaligned double or long.
4066 unsigned maxR11ArgLimit = (compFloatingPointUsed ? 0x03FC : 0x0FFC);
4067 unsigned maxR11LclLimit = 0x0078;
4069 if (codeGen->isFramePointerRequired())
4071 unsigned maxR11LclOffs = frameSize;
4072 unsigned maxR11ArgOffs = compArgSize + (2 * REGSIZE_BYTES);
4073 if (maxR11LclOffs > maxR11LclLimit || maxR11ArgOffs > maxR11ArgLimit)
4079 // So this case is the SP based frame case, but note that we also will use SP based
4080 // offsets for R11 based frames in the non-funclet main code area. However if we have
4081 // passed the above max_R11_offset check these SP checks won't fire.
4083 // Check local coverage first. If vldr/vstr will be used the limit can be +/-imm8.
4084 unsigned maxSPLclLimit = (compFloatingPointUsed ? 0x03F8 : 0x0FF8);
4085 if (frameSize > (codeGen->isFramePointerUsed() ? (maxR11LclLimit + maxSPLclLimit) : maxSPLclLimit))
4090 // Check arguments coverage.
4091 if ((!codeGen->isFramePointerUsed() || (compArgSize > maxR11ArgLimit)) && (compArgSize + frameSize) > maxSPLclLimit)
4096 // We won't need to reserve REG_OPT_RSVD.
4099 #endif // _TARGET_ARM_
4101 #endif // _TARGET_ARMARCH_
4103 void Compiler::compFunctionTraceStart()
4106 if (compIsForInlining())
4111 if ((JitConfig.JitFunctionTrace() != 0) && !opts.disDiffable)
4113 LONG newJitNestingLevel = InterlockedIncrement(&Compiler::jitNestingLevel);
4114 if (newJitNestingLevel <= 0)
4116 printf("{ Illegal nesting level %d }\n", newJitNestingLevel);
4119 for (LONG i = 0; i < newJitNestingLevel - 1; i++)
4123 printf("{ Start Jitting %s (MethodHash=%08x)\n", info.compFullName,
4124 info.compMethodHash()); /* } editor brace matching workaround for this printf */
4129 void Compiler::compFunctionTraceEnd(void* methodCodePtr, ULONG methodCodeSize, bool isNYI)
4132 assert(!compIsForInlining());
4134 if ((JitConfig.JitFunctionTrace() != 0) && !opts.disDiffable)
4136 LONG newJitNestingLevel = InterlockedDecrement(&Compiler::jitNestingLevel);
4137 if (newJitNestingLevel < 0)
4139 printf("{ Illegal nesting level %d }\n", newJitNestingLevel);
4142 for (LONG i = 0; i < newJitNestingLevel; i++)
4146 /* { editor brace-matching workaround for following printf */
4147 printf("} Jitted Entry %03x at" FMT_ADDR "method %s size %08x%s\n", Compiler::jitTotalMethodCompiled,
4148 DBG_ADDR(methodCodePtr), info.compFullName, methodCodeSize,
4149 isNYI ? " NYI" : (compIsForImportOnly() ? " import only" : ""));
4154 //*********************************************************************************************
4157 // This is the most interesting 'toplevel' function in the JIT. It goes through the operations of
4158 // importing, morphing, optimizations and code generation. This is called from the EE through the
4159 // code:CILJit::compileMethod function.
4161 // For an overview of the structure of the JIT, see:
4162 // https://github.com/dotnet/coreclr/blob/master/Documentation/botr/ryujit-overview.md
4164 void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags* compileFlags)
4166 if (compIsForInlining())
4168 // Notify root instance that an inline attempt is about to import IL
4169 impInlineRoot()->m_inlineStrategy->NoteImport();
4174 VarSetOps::AssignAllowUninitRhs(this, compCurLife, VarSetOps::UninitVal());
4176 /* The temp holding the secret stub argument is used by fgImport() when importing the intrinsic. */
4178 if (info.compPublishStubParam)
4180 assert(lvaStubArgumentVar == BAD_VAR_NUM);
4181 lvaStubArgumentVar = lvaGrabTempWithImplicitUse(false DEBUGARG("stub argument"));
4182 lvaTable[lvaStubArgumentVar].lvType = TYP_I_IMPL;
4185 EndPhase(PHASE_PRE_IMPORT);
4187 compFunctionTraceStart();
4189 /* Convert the instrs in each basic block to a tree based intermediate representation */
4193 assert(!fgComputePredsDone);
4194 if (fgCheapPredsValid)
4196 // Remove cheap predecessors before inlining; allowing the cheap predecessor lists to be inserted
4197 // with inlined blocks causes problems.
4201 EndPhase(PHASE_IMPORTATION);
4203 if (compIsForInlining())
4205 /* Quit inlining if fgImport() failed for any reason. */
4207 if (!compDonotInline())
4209 /* Filter out unimported BBs */
4211 fgRemoveEmptyBlocks();
4214 EndPhase(PHASE_POST_IMPORT);
4216 #ifdef FEATURE_JIT_METHOD_PERF
4217 if (pCompJitTimer != nullptr)
4219 #if MEASURE_CLRAPI_CALLS
4220 EndPhase(PHASE_CLR_API);
4222 pCompJitTimer->Terminate(this, CompTimeSummaryInfo::s_compTimeSummary, false);
4229 assert(!compDonotInline());
4231 // Maybe the caller was not interested in generating code
4232 if (compIsForImportOnly())
4234 compFunctionTraceEnd(nullptr, 0, false);
4239 // If we aren't yet supporting EH in a compiler bring-up, remove as many EH handlers as possible, so
4240 // we can pass tests that contain try/catch EH, but don't actually throw any exceptions.
4242 #endif // !FEATURE_EH
4244 if (compileFlags->IsSet(JitFlags::JIT_FLAG_BBINSTR))
4246 fgInstrumentMethod();
4249 // We could allow ESP frames. Just need to reserve space for
4250 // pushing EBP if the method becomes an EBP-frame after an edit.
4251 // Note that requiring a EBP Frame disallows double alignment. Thus if we change this
4252 // we either have to disallow double alignment for E&C some other way or handle it in EETwain.
4254 if (opts.compDbgEnC)
4256 codeGen->setFramePointerRequired(true);
4258 // Since we need a slots for security near ebp, its not possible
4259 // to do this after an Edit without shifting all the locals.
4260 // So we just always reserve space for these slots in case an Edit adds them
4261 opts.compNeedSecurityCheck = true;
4263 // We don't care about localloc right now. If we do support it,
4264 // EECodeManager::FixContextForEnC() needs to handle it smartly
4265 // in case the localloc was actually executed.
4267 // compLocallocUsed = true;
4270 EndPhase(PHASE_POST_IMPORT);
4272 /* Initialize the BlockSet epoch */
4274 NewBasicBlockEpoch();
4276 /* Massage the trees so that we can generate code out of them */
4279 EndPhase(PHASE_MORPH_END);
4281 /* GS security checks for unsafe buffers */
4282 if (getNeedsGSSecurityCookie())
4287 printf("\n*************** -GS checks for unsafe buffers \n");
4291 gsGSChecksInitCookie();
4293 if (compGSReorderStackLayout)
4295 gsCopyShadowParams();
4301 fgDispBasicBlocks(true);
4306 EndPhase(PHASE_GS_COOKIE);
4308 /* Compute bbNum, bbRefs and bbPreds */
4310 JITDUMP("\nRenumbering the basic blocks for fgComputePred\n");
4313 noway_assert(!fgComputePredsDone); // This is the first time full (not cheap) preds will be computed.
4315 EndPhase(PHASE_COMPUTE_PREDS);
4317 /* If we need to emit GC Poll calls, mark the blocks that need them now. This is conservative and can
4318 * be optimized later. */
4319 fgMarkGCPollBlocks();
4320 EndPhase(PHASE_MARK_GC_POLL_BLOCKS);
4322 /* From this point on the flowgraph information such as bbNum,
4323 * bbRefs or bbPreds has to be kept updated */
4325 // Compute the edge weights (if we have profile data)
4326 fgComputeEdgeWeights();
4327 EndPhase(PHASE_COMPUTE_EDGE_WEIGHTS);
4329 #if FEATURE_EH_FUNCLETS
4331 /* Create funclets from the EH handlers. */
4334 EndPhase(PHASE_CREATE_FUNCLETS);
4336 #endif // FEATURE_EH_FUNCLETS
4338 if (!opts.MinOpts() && !opts.compDbgCode)
4340 optOptimizeLayout();
4341 EndPhase(PHASE_OPTIMIZE_LAYOUT);
4343 // Compute reachability sets and dominators.
4344 fgComputeReachability();
4347 // Transform each GT_ALLOCOBJ node into either an allocation helper call or
4348 // local variable allocation on the stack.
4349 ObjectAllocator objectAllocator(this);
4350 objectAllocator.Run();
4352 if (!opts.MinOpts() && !opts.compDbgCode)
4354 /* Perform loop inversion (i.e. transform "while" loops into
4355 "repeat" loops) and discover and classify natural loops
4356 (e.g. mark iterative loops as such). Also marks loop blocks
4357 and sets bbWeight to the loop nesting levels
4361 EndPhase(PHASE_OPTIMIZE_LOOPS);
4363 // Clone loops with optimization opportunities, and
4364 // choose the one based on dynamic condition evaluation.
4366 EndPhase(PHASE_CLONE_LOOPS);
4370 EndPhase(PHASE_UNROLL_LOOPS);
4374 fgDebugCheckLinks();
4377 /* Create the variable table (and compute variable ref counts) */
4380 EndPhase(PHASE_MARK_LOCAL_VARS);
4382 // IMPORTANT, after this point, every place where trees are modified or cloned
4383 // the local variable reference counts must be updated
4384 // You can test the value of the following variable to see if
4385 // the local variable ref counts must be updated
4387 assert(lvaLocalVarRefCounted == true);
4389 if (!opts.MinOpts() && !opts.compDbgCode)
4391 /* Optimize boolean conditions */
4394 EndPhase(PHASE_OPTIMIZE_BOOLS);
4396 // optOptimizeBools() might have changed the number of blocks; the dominators/reachability might be bad.
4399 /* Figure out the order in which operators are to be evaluated */
4401 EndPhase(PHASE_FIND_OPER_ORDER);
4403 // Weave the tree lists. Anyone who modifies the tree shapes after
4404 // this point is responsible for calling fgSetStmtSeq() to keep the
4405 // nodes properly linked.
4406 // This can create GC poll calls, and create new BasicBlocks (without updating dominators/reachability).
4408 EndPhase(PHASE_SET_BLOCK_ORDER);
4410 // IMPORTANT, after this point, every place where tree topology changes must redo evaluation
4411 // order (gtSetStmtInfo) and relink nodes (fgSetStmtSeq) if required.
4412 CLANG_FORMAT_COMMENT_ANCHOR;
4415 // Now we have determined the order of evaluation and the gtCosts for every node.
4416 // If verbose, dump the full set of trees here before the optimization phases mutate them
4420 fgDispBasicBlocks(true); // 'true' will call fgDumpTrees() after dumping the BasicBlocks
4425 // At this point we know if we are fully interruptible or not
4426 if (!opts.MinOpts() && !opts.compDbgCode)
4429 bool doEarlyProp = true;
4430 bool doValueNum = true;
4431 bool doLoopHoisting = true;
4432 bool doCopyProp = true;
4433 bool doAssertionProp = true;
4434 bool doRangeAnalysis = true;
4438 doSsa = (JitConfig.JitDoSsa() != 0);
4439 doEarlyProp = doSsa && (JitConfig.JitDoEarlyProp() != 0);
4440 doValueNum = doSsa && (JitConfig.JitDoValueNumber() != 0);
4441 doLoopHoisting = doValueNum && (JitConfig.JitDoLoopHoisting() != 0);
4442 doCopyProp = doValueNum && (JitConfig.JitDoCopyProp() != 0);
4443 doAssertionProp = doValueNum && (JitConfig.JitDoAssertionProp() != 0);
4444 doRangeAnalysis = doAssertionProp && (JitConfig.JitDoRangeAnalysis() != 0);
4448 iterations = JitConfig.JitOptRepeatCount();
4452 while (iterations > 0)
4457 EndPhase(PHASE_BUILD_SSA);
4462 /* Propagate array length and rewrite getType() method call */
4464 EndPhase(PHASE_EARLY_PROP);
4470 EndPhase(PHASE_VALUE_NUMBER);
4475 /* Hoist invariant code out of loops */
4477 EndPhase(PHASE_HOIST_LOOP_CODE);
4482 /* Perform VN based copy propagation */
4484 EndPhase(PHASE_VN_COPY_PROP);
4488 /* Remove common sub-expressions */
4490 #endif // FEATURE_ANYCSE
4493 if (doAssertionProp)
4495 /* Assertion propagation */
4496 optAssertionPropMain();
4497 EndPhase(PHASE_ASSERTION_PROP_MAIN);
4500 if (doRangeAnalysis)
4502 /* Optimize array index range checks */
4503 RangeCheck rc(this);
4504 rc.OptimizeRangeChecks();
4505 EndPhase(PHASE_OPTIMIZE_INDEX_CHECKS);
4507 #endif // ASSERTION_PROP
4509 /* update the flowgraph if we modified it during the optimization phase*/
4512 fgUpdateFlowGraph();
4513 EndPhase(PHASE_UPDATE_FLOW_GRAPH);
4515 // Recompute the edge weight if we have modified the flow graph
4516 fgComputeEdgeWeights();
4517 EndPhase(PHASE_COMPUTE_EDGE_WEIGHTS2);
4520 // Iterate if requested, resetting annotations first.
4521 if (--iterations == 0)
4525 ResetOptAnnotations();
4526 RecomputeLoopInfo();
4530 #ifdef _TARGET_AMD64_
4531 // Check if we need to add the Quirk for the PPP backward compat issue
4532 compQuirkForPPPflag = compQuirkForPPP();
4535 fgDetermineFirstColdBlock();
4536 EndPhase(PHASE_DETERMINE_FIRST_COLD_BLOCK);
4539 fgDebugCheckLinks(compStressCompile(STRESS_REMORPH_TREES, 50));
4541 // Stash the current estimate of the function's size if necessary.
4544 compSizeEstimate = 0;
4545 compCycleEstimate = 0;
4546 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
4548 for (GenTreeStmt* stmt = block->firstStmt(); stmt != nullptr; stmt = stmt->getNextStmt())
4550 compSizeEstimate += stmt->GetCostSz();
4551 compCycleEstimate += stmt->GetCostEx();
4557 #ifndef LEGACY_BACKEND
4558 // rationalize trees
4559 Rationalizer rat(this); // PHASE_RATIONALIZE
4561 #endif // !LEGACY_BACKEND
4563 // Here we do "simple lowering". When the RyuJIT backend works for all
4564 // platforms, this will be part of the more general lowering phase. For now, though, we do a separate
4565 // pass of "final lowering." We must do this before (final) liveness analysis, because this creates
4566 // range check throw blocks, in which the liveness must be correct.
4568 EndPhase(PHASE_SIMPLE_LOWERING);
4570 #ifdef LEGACY_BACKEND
4571 /* Local variable liveness */
4572 fgLocalVarLiveness();
4573 EndPhase(PHASE_LCLVARLIVENESS);
4574 #endif // !LEGACY_BACKEND
4577 fgDebugCheckBBlist();
4578 fgDebugCheckLinks();
4581 /* Enable this to gather statistical data such as
4582 * call and register argument info, flowgraph and loop info, etc. */
4587 if (compLocallocUsed)
4589 // We reserve REG_SAVED_LOCALLOC_SP to store SP on entry for stack unwinding
4590 codeGen->regSet.rsMaskResvd |= RBM_SAVED_LOCALLOC_SP;
4592 #endif // _TARGET_ARM_
4593 #ifdef _TARGET_ARMARCH_
4594 if (compRsvdRegCheck(PRE_REGALLOC_FRAME_LAYOUT))
4596 // We reserve R10/IP1 in this case to hold the offsets in load/store instructions
4597 codeGen->regSet.rsMaskResvd |= RBM_OPT_RSVD;
4598 assert(REG_OPT_RSVD != REG_FP);
4600 // compRsvdRegCheck() has read out the FramePointerUsed property, but doLinearScan()
4601 // tries to overwrite it later. This violates the PhasedVar rule and triggers an assertion.
4602 // TODO-ARM-Bug?: What is the proper way to handle this situation?
4603 codeGen->resetFramePointerUsedWritePhase();
4607 // Display the pre-regalloc frame offsets that we have tentatively decided upon
4612 #endif // _TARGET_ARMARCH_
4614 /* Assign registers to variables, etc. */
4615 CLANG_FORMAT_COMMENT_ANCHOR;
4617 #ifndef LEGACY_BACKEND
4618 ///////////////////////////////////////////////////////////////////////////////
4619 // Dominator and reachability sets are no longer valid. They haven't been
4620 // maintained up to here, and shouldn't be used (unless recomputed).
4621 ///////////////////////////////////////////////////////////////////////////////
4622 fgDomsComputed = false;
4624 /* Create LSRA before Lowering, this way Lowering can initialize the TreeNode Map */
4625 m_pLinearScan = getLinearScanAllocator(this);
4628 Lowering lower(this, m_pLinearScan); // PHASE_LOWERING
4631 assert(lvaSortAgain == false); // We should have re-run fgLocalVarLiveness() in lower.Run()
4632 lvaTrackedFixed = true; // We can not add any new tracked variables after this point.
4634 /* Now that lowering is completed we can proceed to perform register allocation */
4635 m_pLinearScan->doLinearScan();
4636 EndPhase(PHASE_LINEAR_SCAN);
4638 // Copied from rpPredictRegUse()
4639 genFullPtrRegMap = (codeGen->genInterruptible || !codeGen->isFramePointerUsed());
4640 #else // LEGACY_BACKEND
4642 lvaTrackedFixed = true; // We cannot add any new tracked variables after this point.
4643 // For the classic JIT32 at this point lvaSortAgain can be set and raAssignVars() will call lvaSortOnly()
4645 // Now do "classic" register allocation.
4647 EndPhase(PHASE_RA_ASSIGN_VARS);
4648 #endif // LEGACY_BACKEND
4651 fgDebugCheckLinks();
4656 codeGen->genGenerateCode(methodCodePtr, methodCodeSize);
4658 #ifdef FEATURE_JIT_METHOD_PERF
4661 #if MEASURE_CLRAPI_CALLS
4662 EndPhase(PHASE_CLR_API);
4664 pCompJitTimer->Terminate(this, CompTimeSummaryInfo::s_compTimeSummary, true);
4668 RecordStateAtEndOfCompilation();
4670 #ifdef FEATURE_TRACELOGGING
4671 compJitTelemetry.NotifyEndOfCompilation();
4675 ++Compiler::jitTotalMethodCompiled;
4676 #endif // defined(DEBUG)
4678 compFunctionTraceEnd(*methodCodePtr, *methodCodeSize, false);
4680 #if FUNC_INFO_LOGGING
4681 if (compJitFuncInfoFile != nullptr)
4683 assert(!compIsForInlining());
4684 #ifdef DEBUG // We only have access to info.compFullName in DEBUG builds.
4685 fprintf(compJitFuncInfoFile, "%s\n", info.compFullName);
4687 fprintf(compJitFuncInfoFile, " %s\n", eeGetMethodFullName(info.compMethodHnd));
4689 fprintf(compJitFuncInfoFile, ""); // in our logic this causes a flush
4691 #endif // FUNC_INFO_LOGGING
4694 //------------------------------------------------------------------------
4695 // ResetOptAnnotations: Clear annotations produced during global optimizations.
4698 // The intent of this method is to clear any information typically assumed
4699 // to be set only once; it is used between iterations when JitOptRepeat is
4702 void Compiler::ResetOptAnnotations()
4704 assert(opts.optRepeat);
4705 assert(JitConfig.JitOptRepeatCount() > 0);
4708 m_opAsgnVarDefSsaNums = nullptr;
4709 m_blockToEHPreds = nullptr;
4710 fgSsaPassesCompleted = 0;
4711 fgVNPassesCompleted = 0;
4713 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
4715 for (GenTreeStmt* stmt = block->firstStmt(); stmt != nullptr; stmt = stmt->getNextStmt())
4717 stmt->gtFlags &= ~GTF_STMT_HAS_CSE;
4719 for (GenTreePtr tree = stmt->gtStmt.gtStmtList; tree != nullptr; tree = tree->gtNext)
4722 tree->ClearAssertion();
4723 tree->gtCSEnum = NO_CSE;
4729 //------------------------------------------------------------------------
4730 // RecomputeLoopInfo: Recompute loop annotations between opt-repeat iterations.
4733 // The intent of this method is to update loop structure annotations, and those
4734 // they depend on; these annotations may have become stale during optimization,
4735 // and need to be up-to-date before running another iteration of optimizations.
4737 void Compiler::RecomputeLoopInfo()
4739 assert(opts.optRepeat);
4740 assert(JitConfig.JitOptRepeatCount() > 0);
4741 // Recompute reachability sets, dominators, and loops.
4743 fgDomsComputed = false;
4744 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
4746 block->bbFlags &= ~BBF_LOOP_FLAGS;
4748 fgComputeReachability();
4749 // Rebuild the loop tree annotations themselves. Since this is performed as
4750 // part of 'optOptimizeLoops', this will also re-perform loop rotation, but
4751 // not other optimizations, as the others are not part of 'optOptimizeLoops'.
4755 /*****************************************************************************/
4756 void Compiler::ProcessShutdownWork(ICorStaticInfo* statInfo)
4760 #ifdef _TARGET_AMD64_
4761 // Check if we need to add the Quirk for the PPP backward compat issue.
4762 // This Quirk addresses a compatibility issue between the new RyuJit and the previous JIT64.
4763 // A backward compatibity issue called 'PPP' exists where a PInvoke call passes a 32-byte struct
4764 // into a native API which basically writes 48 bytes of data into the struct.
4765 // With the stack frame layout used by the RyuJIT the extra 16 bytes written corrupts a
4766 // caller saved register and this leads to an A/V in the calling method.
4767 // The older JIT64 jit compiler just happened to have a different stack layout and/or
4768 // caller saved register set so that it didn't hit the A/V in the caller.
4769 // By increasing the amount of stack allocted for the struct by 32 bytes we can fix this.
4771 // Return true if we actually perform the Quirk, otherwise return false
4773 bool Compiler::compQuirkForPPP()
4776 { // We require that there are exactly two locals
4780 if (compTailCallUsed)
4781 { // Don't try this quirk if a tail call was used
4785 bool hasOutArgs = false;
4786 LclVarDsc* varDscExposedStruct = nullptr;
4791 /* Look for struct locals that are address taken */
4792 for (lclNum = 0, varDsc = lvaTable; lclNum < lvaCount; lclNum++, varDsc++)
4794 if (varDsc->lvIsParam) // It can't be a parameter
4799 // We require that the OutgoingArg space lclVar exists
4800 if (lclNum == lvaOutgoingArgSpaceVar)
4802 hasOutArgs = true; // Record that we saw it
4806 // Look for a 32-byte address exposed Struct and record its varDsc
4807 if ((varDsc->TypeGet() == TYP_STRUCT) && varDsc->lvAddrExposed && (varDsc->lvExactSize == 32))
4809 varDscExposedStruct = varDsc;
4813 // We only perform the Quirk when there are two locals
4814 // one of them is a address exposed struct of size 32
4815 // and the other is the outgoing arg space local
4817 if (hasOutArgs && (varDscExposedStruct != nullptr))
4822 printf("\nAdding a backwards compatibility quirk for the 'PPP' issue\n");
4826 // Increase the exact size of this struct by 32 bytes
4827 // This fixes the PPP backward compat issue
4828 varDscExposedStruct->lvExactSize += 32;
4834 #endif // _TARGET_AMD64_
4836 /*****************************************************************************/
4839 void* forceFrameJIT; // used to force to frame &useful for fastchecked debugging
4841 bool Compiler::skipMethod()
4843 static ConfigMethodRange fJitRange;
4844 fJitRange.EnsureInit(JitConfig.JitRange());
4845 assert(!fJitRange.Error());
4847 // Normally JitConfig.JitRange() is null, we don't want to skip
4848 // jitting any methods.
4850 // So, the logic below relies on the fact that a null range string
4851 // passed to ConfigMethodRange represents the set of all methods.
4853 if (!fJitRange.Contains(info.compCompHnd, info.compMethodHnd))
4858 if (JitConfig.JitExclude().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
4863 if (!JitConfig.JitInclude().isEmpty() &&
4864 !JitConfig.JitInclude().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
4874 /*****************************************************************************/
4876 int Compiler::compCompile(CORINFO_METHOD_HANDLE methodHnd,
4877 CORINFO_MODULE_HANDLE classPtr,
4878 COMP_HANDLE compHnd,
4879 CORINFO_METHOD_INFO* methodInfo,
4880 void** methodCodePtr,
4881 ULONG* methodCodeSize,
4882 JitFlags* compileFlags)
4884 #ifdef FEATURE_JIT_METHOD_PERF
4885 static bool checkedForJitTimeLog = false;
4887 pCompJitTimer = nullptr;
4889 if (!checkedForJitTimeLog)
4891 // Call into VM to get the config strings. FEATURE_JIT_METHOD_PERF is enabled for
4892 // retail builds. Do not call the regular Config helper here as it would pull
4893 // in a copy of the config parser into the clrjit.dll.
4894 InterlockedCompareExchangeT(&Compiler::compJitTimeLogFilename, compHnd->getJitTimeLogFilename(), NULL);
4896 // At a process or module boundary clear the file and start afresh.
4897 JitTimer::PrintCsvHeader();
4899 checkedForJitTimeLog = true;
4901 if ((Compiler::compJitTimeLogFilename != nullptr) || (JitTimeLogCsv() != nullptr))
4903 pCompJitTimer = JitTimer::Create(this, methodInfo->ILCodeSize);
4905 #endif // FEATURE_JIT_METHOD_PERF
4908 Compiler* me = this;
4909 forceFrameJIT = (void*)&me; // let us see the this pointer in fastchecked build
4910 // set this early so we can use it without relying on random memory values
4911 verbose = compIsForInlining() ? impInlineInfo->InlinerCompiler->verbose : false;
4913 this->dumpIR = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIR : false;
4914 this->dumpIRPhase = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRPhase : nullptr;
4915 this->dumpIRFormat = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRFormat : nullptr;
4916 this->dumpIRTypes = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRTypes : false;
4917 this->dumpIRLocals = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRLocals : false;
4918 this->dumpIRRegs = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRRegs : false;
4919 this->dumpIRSsa = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRSsa : false;
4920 this->dumpIRValnums = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRValnums : false;
4921 this->dumpIRCosts = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRCosts : false;
4922 this->dumpIRFlags = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRFlags : false;
4923 this->dumpIRKinds = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRKinds : false;
4924 this->dumpIRNodes = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRNodes : false;
4925 this->dumpIRNoLists = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRNoLists : false;
4926 this->dumpIRNoLeafs = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRNoLeafs : false;
4927 this->dumpIRNoStmts = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRNoStmts : false;
4928 this->dumpIRTrees = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRTrees : false;
4929 this->dumpIRLinear = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRLinear : false;
4930 this->dumpIRDataflow = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRDataflow : false;
4931 this->dumpIRBlockHeaders = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRBlockHeaders : NULL;
4932 this->dumpIRExit = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRExit : NULL;
4936 #if defined(DEBUG) || defined(INLINE_DATA)
4937 info.compMethodHashPrivate = 0;
4938 #endif // defined(DEBUG) || defined(INLINE_DATA)
4940 #if FUNC_INFO_LOGGING
4941 LPCWSTR tmpJitFuncInfoFilename = JitConfig.JitFuncInfoFile();
4943 if (tmpJitFuncInfoFilename != nullptr)
4945 LPCWSTR oldFuncInfoFileName =
4946 InterlockedCompareExchangeT(&compJitFuncInfoFilename, tmpJitFuncInfoFilename, NULL);
4947 if (oldFuncInfoFileName == nullptr)
4949 assert(compJitFuncInfoFile == nullptr);
4950 compJitFuncInfoFile = _wfopen(compJitFuncInfoFilename, W("a"));
4951 if (compJitFuncInfoFile == nullptr)
4953 #if defined(DEBUG) && !defined(FEATURE_PAL) // no 'perror' in the PAL
4954 perror("Failed to open JitFuncInfoLogFile");
4955 #endif // defined(DEBUG) && !defined(FEATURE_PAL)
4959 #endif // FUNC_INFO_LOGGING
4961 // if (s_compMethodsCount==0) setvbuf(jitstdout, NULL, _IONBF, 0);
4963 info.compCompHnd = compHnd;
4964 info.compMethodHnd = methodHnd;
4965 info.compMethodInfo = methodInfo;
4967 // Do we have a matched VM? Or are we "abusing" the VM to help us do JIT work (such as using an x86 native VM
4968 // with an ARM-targeting "altjit").
4969 info.compMatchedVM = IMAGE_FILE_MACHINE_TARGET == info.compCompHnd->getExpectedTargetArchitecture();
4971 #if defined(ALT_JIT) && defined(UNIX_AMD64_ABI)
4972 // ToDo: This code is to allow us to run UNIX codegen on Windows for now. Remove when appropriate.
4973 // Make sure that the generated UNIX altjit code is skipped on Windows. The static jit codegen is used to run.
4974 info.compMatchedVM = false;
4975 #endif // UNIX_AMD64_ABI
4977 #if COR_JIT_EE_VERSION > 460
4978 compMaxUncheckedOffsetForNullObject = eeGetEEInfo()->maxUncheckedOffsetForNullObject;
4979 #else // COR_JIT_EE_VERSION <= 460
4980 compMaxUncheckedOffsetForNullObject = MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT;
4981 #endif // COR_JIT_EE_VERSION > 460
4983 // Set the context for token lookup.
4984 if (compIsForInlining())
4986 impTokenLookupContextHandle = impInlineInfo->tokenLookupContextHandle;
4988 assert(impInlineInfo->inlineCandidateInfo->clsHandle == compHnd->getMethodClass(methodHnd));
4989 info.compClassHnd = impInlineInfo->inlineCandidateInfo->clsHandle;
4991 assert(impInlineInfo->inlineCandidateInfo->clsAttr == info.compCompHnd->getClassAttribs(info.compClassHnd));
4992 // printf("%x != %x\n", impInlineInfo->inlineCandidateInfo->clsAttr,
4993 // info.compCompHnd->getClassAttribs(info.compClassHnd));
4994 info.compClassAttr = impInlineInfo->inlineCandidateInfo->clsAttr;
4998 impTokenLookupContextHandle = MAKE_METHODCONTEXT(info.compMethodHnd);
5000 info.compClassHnd = compHnd->getMethodClass(methodHnd);
5001 info.compClassAttr = info.compCompHnd->getClassAttribs(info.compClassHnd);
5004 info.compProfilerCallback = false; // Assume false until we are told to hook this method.
5006 #if defined(DEBUG) || defined(LATE_DISASM)
5007 const char* classNamePtr;
5009 info.compMethodName = eeGetMethodName(methodHnd, &classNamePtr);
5010 unsigned len = (unsigned)roundUp(strlen(classNamePtr) + 1);
5011 info.compClassName = (char*)compGetMem(len, CMK_DebugOnly);
5012 strcpy_s((char*)info.compClassName, len, classNamePtr);
5014 info.compFullName = eeGetMethodFullName(methodHnd);
5015 #endif // defined(DEBUG) || defined(LATE_DISASM)
5018 if (!compIsForInlining())
5020 JitTls::GetLogEnv()->setCompiler(this);
5023 // Have we been told to be more selective in our Jitting?
5026 if (compIsForInlining())
5028 compInlineResult->NoteFatal(InlineObservation::CALLEE_MARKED_AS_SKIPPED);
5030 return CORJIT_SKIPPED;
5033 // Opt-in to jit stress based on method hash ranges.
5035 // Note the default (with JitStressRange not set) is that all
5036 // methods will be subject to stress.
5037 static ConfigMethodRange fJitStressRange;
5038 fJitStressRange.EnsureInit(JitConfig.JitStressRange());
5039 assert(!fJitStressRange.Error());
5040 bRangeAllowStress = fJitStressRange.Contains(info.compCompHnd, info.compMethodHnd);
5044 // Set this before the first 'BADCODE'
5045 // Skip verification where possible
5046 tiVerificationNeeded = !compileFlags->IsSet(JitFlags::JIT_FLAG_SKIP_VERIFICATION);
5048 assert(!compIsForInlining() || !tiVerificationNeeded); // Inlinees must have been verified.
5050 // assume the code is verifiable unless proven otherwise
5051 tiIsVerifiableCode = TRUE;
5053 tiRuntimeCalloutNeeded = false;
5055 CorInfoInstantiationVerification instVerInfo = INSTVER_GENERIC_PASSED_VERIFICATION;
5057 if (!compIsForInlining() && tiVerificationNeeded)
5059 instVerInfo = compHnd->isInstantiationOfVerifiedGeneric(methodHnd);
5061 if (tiVerificationNeeded && (instVerInfo == INSTVER_GENERIC_FAILED_VERIFICATION))
5063 CorInfoCanSkipVerificationResult canSkipVerificationResult =
5064 info.compCompHnd->canSkipMethodVerification(info.compMethodHnd);
5066 switch (canSkipVerificationResult)
5068 case CORINFO_VERIFICATION_CANNOT_SKIP:
5069 // We cannot verify concrete instantiation.
5070 // We can only verify the typical/open instantiation
5071 // The VM should throw a VerificationException instead of allowing this.
5072 NO_WAY("Verification of closed instantiations is not supported");
5075 case CORINFO_VERIFICATION_CAN_SKIP:
5076 // The VM should first verify the open instantiation. If unverifiable code
5077 // is detected, it should pass in JitFlags::JIT_FLAG_SKIP_VERIFICATION.
5078 assert(!"The VM should have used JitFlags::JIT_FLAG_SKIP_VERIFICATION");
5079 tiVerificationNeeded = false;
5082 case CORINFO_VERIFICATION_RUNTIME_CHECK:
5083 // This is a concrete generic instantiation with unverifiable code, that also
5084 // needs a runtime callout.
5085 tiVerificationNeeded = false;
5086 tiRuntimeCalloutNeeded = true;
5089 case CORINFO_VERIFICATION_DONT_JIT:
5090 // We cannot verify concrete instantiation.
5091 // We can only verify the typical/open instantiation
5092 // The VM should throw a VerificationException instead of allowing this.
5093 BADCODE("NGEN of unverifiable transparent code is not supported");
5098 // load any constraints for verification, noting any cycles to be rejected by the verifying importer
5099 if (tiVerificationNeeded)
5101 compHnd->initConstraintsForVerification(methodHnd, &info.hasCircularClassConstraints,
5102 &info.hasCircularMethodConstraints);
5106 /* Setup an error trap */
5112 CORINFO_MODULE_HANDLE classPtr;
5113 COMP_HANDLE compHnd;
5114 CORINFO_METHOD_INFO* methodInfo;
5115 void** methodCodePtr;
5116 ULONG* methodCodeSize;
5117 JitFlags* compileFlags;
5119 CorInfoInstantiationVerification instVerInfo;
5123 param.classPtr = classPtr;
5124 param.compHnd = compHnd;
5125 param.methodInfo = methodInfo;
5126 param.methodCodePtr = methodCodePtr;
5127 param.methodCodeSize = methodCodeSize;
5128 param.compileFlags = compileFlags;
5129 param.instVerInfo = instVerInfo;
5130 param.result = CORJIT_INTERNALERROR;
5132 setErrorTrap(compHnd, Param*, pParam, ¶m) // ERROR TRAP: Start normal block
5134 pParam->result = pParam->pThis->compCompileHelper(pParam->classPtr, pParam->compHnd, pParam->methodInfo,
5135 pParam->methodCodePtr, pParam->methodCodeSize,
5136 pParam->compileFlags, pParam->instVerInfo);
5138 finallyErrorTrap() // ERROR TRAP: The following block handles errors
5142 if (compIsForInlining())
5147 /* Tell the emitter that we're done with this function */
5149 genEmitter->emitEndCG();
5154 endErrorTrap() // ERROR TRAP: End
5156 return param.result;
5159 #if defined(DEBUG) || defined(INLINE_DATA)
5160 unsigned Compiler::Info::compMethodHash() const
5162 if (compMethodHashPrivate == 0)
5164 compMethodHashPrivate = compCompHnd->getMethodHash(compMethodHnd);
5166 return compMethodHashPrivate;
5168 #endif // defined(DEBUG) || defined(INLINE_DATA)
5170 void Compiler::compCompileFinish()
5172 #if defined(DEBUG) || MEASURE_NODE_SIZE || MEASURE_BLOCK_SIZE || DISPLAY_SIZES || CALL_ARG_STATS
5176 #if MEASURE_MEM_ALLOC
5178 // Grab the relevant lock.
5179 CritSecHolder statsLock(s_memStatsLock);
5181 // Make the updates.
5182 genMemStats.nraTotalSizeAlloc = compGetAllocator()->getTotalBytesAllocated();
5183 genMemStats.nraTotalSizeUsed = compGetAllocator()->getTotalBytesUsed();
5184 memAllocHist.record((unsigned)((genMemStats.nraTotalSizeAlloc + 1023) / 1024));
5185 memUsedHist.record((unsigned)((genMemStats.nraTotalSizeUsed + 1023) / 1024));
5186 s_aggMemStats.Add(genMemStats);
5187 if (genMemStats.allocSz > s_maxCompMemStats.allocSz)
5189 s_maxCompMemStats = genMemStats;
5194 if (s_dspMemStats || verbose)
5196 printf("\nAllocations for %s (MethodHash=%08x)\n", info.compFullName, info.compMethodHash());
5197 genMemStats.Print(jitstdout);
5200 #endif // MEASURE_MEM_ALLOC
5202 #if LOOP_HOIST_STATS
5203 AddLoopHoistStats();
5204 #endif // LOOP_HOIST_STATS
5206 #if MEASURE_NODE_SIZE
5207 genTreeNcntHist.record(static_cast<unsigned>(genNodeSizeStatsPerFunc.genTreeNodeCnt));
5208 genTreeNsizHist.record(static_cast<unsigned>(genNodeSizeStatsPerFunc.genTreeNodeSize));
5212 // Small methods should fit in ArenaAllocator::getDefaultPageSize(), or else
5213 // we should bump up ArenaAllocator::getDefaultPageSize()
5215 if ((info.compILCodeSize <= 32) && // Is it a reasonably small method?
5216 (info.compNativeCodeSize < 512) && // Some trivial methods generate huge native code. eg. pushing a single huge
5218 (impInlinedCodeSize <= 128) && // Is the the inlining reasonably bounded?
5219 // Small methods cannot meaningfully have a big number of locals
5220 // or arguments. We always track arguments at the start of
5221 // the prolog which requires memory
5222 (info.compLocalsCount <= 32) && (!opts.MinOpts()) && // We may have too many local variables, etc
5223 (getJitStressLevel() == 0) && // We need extra memory for stress
5224 !opts.optRepeat && // We need extra memory to repeat opts
5225 !compAllocator->bypassHostAllocator() && // ArenaAllocator::getDefaultPageSize() is artificially low for
5227 (compAllocator->getTotalBytesAllocated() > (2 * ArenaAllocator::getDefaultPageSize())) &&
5228 // Factor of 2x is because data-structures are bigger under DEBUG
5229 #ifndef LEGACY_BACKEND
5230 // RyuJIT backend needs memory tuning! TODO-Cleanup: remove this case when memory tuning is complete.
5231 (compAllocator->getTotalBytesAllocated() > (10 * ArenaAllocator::getDefaultPageSize())) &&
5233 !verbose) // We allocate lots of memory to convert sets to strings for JitDump
5235 genSmallMethodsNeedingExtraMemoryCnt++;
5237 // Less than 1% of all methods should run into this.
5238 // We cannot be more strict as there are always degenerate cases where we
5239 // would need extra memory (like huge structs as locals - see lvaSetStruct()).
5240 assert((genMethodCnt < 500) || (genSmallMethodsNeedingExtraMemoryCnt < (genMethodCnt / 100)));
5244 #if defined(DEBUG) || defined(INLINE_DATA)
5246 m_inlineStrategy->DumpData();
5247 m_inlineStrategy->DumpXml();
5254 // mdMethodDef __stdcall CEEInfo::getMethodDefFromMethod(CORINFO_METHOD_HANDLE hMethod)
5255 mdMethodDef currentMethodToken = info.compCompHnd->getMethodDefFromMethod(info.compMethodHnd);
5257 unsigned profCallCount = 0;
5258 if (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_BBOPT) && fgHaveProfileData())
5260 assert(fgProfileBuffer[0].ILOffset == 0);
5261 profCallCount = fgProfileBuffer[0].ExecutionCount;
5264 static bool headerPrinted = false;
5268 headerPrinted = true;
5269 printf(" | Profiled | Exec- | Method has | calls | Num |LclV |AProp| CSE | Reg |bytes | %3s code size | \n", Target::g_tgtCPUName);
5270 printf(" mdToken | | RGN | Count | EH | FRM | LOOP | NRM | IND | BBs | Cnt | Cnt | Cnt | Alloc | IL | HOT | COLD | method name \n");
5271 printf("---------+-----+------+----------+----+-----+------+-----+-----+-----+-----+-----+-----+---------+------+-------+-------+-----------\n");
5272 // 06001234 | PRF | HOT | 219 | EH | ebp | LOOP | 15 | 6 | 12 | 17 | 12 | 8 | 28 p2 | 145 | 211 | 123 | System.Example(int)
5276 printf("%08X | ", currentMethodToken);
5278 CorInfoRegionKind regionKind = info.compMethodInfo->regionKind;
5284 else if (fgHaveProfileData())
5293 if (regionKind == CORINFO_REGION_NONE)
5297 else if (regionKind == CORINFO_REGION_HOT)
5301 else if (regionKind == CORINFO_REGION_COLD)
5305 else if (regionKind == CORINFO_REGION_JIT)
5314 printf("%8d | ", profCallCount);
5316 if (compHndBBtabCount > 0)
5325 if (rpFrameType == FT_EBP_FRAME)
5327 printf("%3s | ", STR_FPBASE);
5329 else if (rpFrameType == FT_ESP_FRAME)
5331 printf("%3s | ", STR_SPBASE);
5334 else if (rpFrameType == FT_DOUBLE_ALIGN_FRAME)
5339 else // (rpFrameType == FT_NOT_SET)
5353 printf(" %3d |", optCallCount);
5354 printf(" %3d |", optIndirectCallCount);
5355 printf(" %3d |", fgBBcountAtCodegen);
5356 printf(" %3d |", lvaCount);
5360 printf(" MinOpts |");
5364 printf(" %3d |", optAssertionCount);
5366 printf(" %3d |", optCSEcount);
5368 printf(" %3d |", 0);
5369 #endif // FEATURE_ANYCSE
5372 #ifndef LEGACY_BACKEND
5373 printf(" LSRA |"); // TODO-Cleanup: dump some interesting LSRA stat into the order file?
5374 #else // LEGACY_BACKEND
5375 printf("%s%4d p%1d |", (tmpCount > 0) ? "T" : " ", rpStkPredict / BB_UNITY_WEIGHT, rpPasses);
5376 #endif // LEGACY_BACKEND
5377 printf(" %4d |", info.compMethodInfo->ILCodeSize);
5378 printf(" %5d |", info.compTotalHotCodeSize);
5379 printf(" %5d |", info.compTotalColdCodeSize);
5381 printf(" %s\n", eeGetMethodFullName(info.compMethodHnd));
5382 printf(""); // in our logic this causes a flush
5387 printf("****** DONE compiling %s\n", info.compFullName);
5388 printf(""); // in our logic this causes a flush
5391 // Only call _DbgBreakCheck when we are jitting, not when we are ngen-ing
5392 // For ngen the int3 or breakpoint instruction will be right at the
5393 // start of the ngen method and we will stop when we execute it.
5395 if (!opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
5397 if (compJitHaltMethod())
5399 #if !defined(_TARGET_ARM64_) && !defined(PLATFORM_UNIX)
5400 // TODO-ARM64-NYI: re-enable this when we have an OS that supports a pop-up dialog
5402 // Don't do an assert, but just put up the dialog box so we get just-in-time debugger
5403 // launching. When you hit 'retry' it will continue and naturally stop at the INT 3
5404 // that the JIT put in the code
5405 _DbgBreakCheck(__FILE__, __LINE__, "JitHalt");
5412 #ifdef PSEUDORANDOM_NOP_INSERTION
5413 // this is zlib adler32 checksum. source came from windows base
5415 #define BASE 65521L // largest prime smaller than 65536
5417 // NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
5419 #define DO1(buf, i) \
5424 #define DO2(buf, i) \
5427 #define DO4(buf, i) \
5430 #define DO8(buf, i) \
5437 unsigned adler32(unsigned adler, char* buf, unsigned int len)
5439 unsigned int s1 = adler & 0xffff;
5440 unsigned int s2 = (adler >> 16) & 0xffff;
5448 k = len < NMAX ? len : NMAX;
5465 return (s2 << 16) | s1;
5469 unsigned getMethodBodyChecksum(__in_z char* code, int size)
5471 #ifdef PSEUDORANDOM_NOP_INSERTION
5472 return adler32(0, code, size);
5478 int Compiler::compCompileHelper(CORINFO_MODULE_HANDLE classPtr,
5479 COMP_HANDLE compHnd,
5480 CORINFO_METHOD_INFO* methodInfo,
5481 void** methodCodePtr,
5482 ULONG* methodCodeSize,
5483 JitFlags* compileFlags,
5484 CorInfoInstantiationVerification instVerInfo)
5486 CORINFO_METHOD_HANDLE methodHnd = info.compMethodHnd;
5488 info.compCode = methodInfo->ILCode;
5489 info.compILCodeSize = methodInfo->ILCodeSize;
5491 if (info.compILCodeSize == 0)
5493 BADCODE("code size is zero");
5496 if (compIsForInlining())
5499 unsigned methAttr_Old = impInlineInfo->inlineCandidateInfo->methAttr;
5500 unsigned methAttr_New = info.compCompHnd->getMethodAttribs(info.compMethodHnd);
5501 unsigned flagsToIgnore = CORINFO_FLG_DONT_INLINE | CORINFO_FLG_FORCEINLINE;
5502 assert((methAttr_Old & (~flagsToIgnore)) == (methAttr_New & (~flagsToIgnore)));
5505 info.compFlags = impInlineInfo->inlineCandidateInfo->methAttr;
5509 info.compFlags = info.compCompHnd->getMethodAttribs(info.compMethodHnd);
5510 #ifdef PSEUDORANDOM_NOP_INSERTION
5511 info.compChecksum = getMethodBodyChecksum((char*)methodInfo->ILCode, methodInfo->ILCodeSize);
5515 // compInitOptions will set the correct verbose flag.
5517 compInitOptions(compileFlags);
5520 if (!compIsForInlining() && !opts.altJit)
5522 // We're an altjit, but the COMPlus_AltJit configuration did not say to compile this method,
5524 return CORJIT_SKIPPED;
5532 printf("IL to import:\n");
5533 dumpILRange(info.compCode, info.compILCodeSize);
5538 // Check for COMPlus_AgressiveInlining
5539 if (JitConfig.JitAggressiveInlining())
5541 compDoAggressiveInlining = true;
5544 if (compDoAggressiveInlining)
5546 info.compFlags |= CORINFO_FLG_FORCEINLINE;
5551 // Check for ForceInline stress.
5552 if (compStressCompile(STRESS_FORCE_INLINE, 0))
5554 info.compFlags |= CORINFO_FLG_FORCEINLINE;
5557 if (compIsForInlining())
5559 JITLOG((LL_INFO100000, "\nINLINER impTokenLookupContextHandle for %s is 0x%p.\n",
5560 eeGetMethodFullName(info.compMethodHnd), dspPtr(impTokenLookupContextHandle)));
5563 // Force verification if asked to do so
5564 if (JitConfig.JitForceVer())
5566 tiVerificationNeeded = (instVerInfo == INSTVER_NOT_INSTANTIATION);
5569 if (tiVerificationNeeded)
5571 JITLOG((LL_INFO10000, "tiVerificationNeeded initially set to true for %s\n", info.compFullName));
5575 /* Since tiVerificationNeeded can be turned off in the middle of
5576 compiling a method, and it might have caused blocks to be queued up
5577 for reimporting, impCanReimport can be used to check for reimporting. */
5579 impCanReimport = (tiVerificationNeeded || compStressCompile(STRESS_CHK_REIMPORT, 15));
5581 // Need security prolog/epilog callouts when there is a declarative security in the method.
5582 tiSecurityCalloutNeeded = ((info.compFlags & CORINFO_FLG_NOSECURITYWRAP) == 0);
5584 if (tiSecurityCalloutNeeded || (info.compFlags & CORINFO_FLG_SECURITYCHECK))
5586 // We need to allocate the security object on the stack
5587 // when the method being compiled has a declarative security
5588 // (i.e. when CORINFO_FLG_NOSECURITYWRAP is reset for the current method).
5589 // This is also the case when we inject a prolog and epilog in the method.
5590 opts.compNeedSecurityCheck = true;
5593 /* Initialize set a bunch of global values */
5595 info.compScopeHnd = classPtr;
5596 info.compXcptnsCount = methodInfo->EHcount;
5597 info.compMaxStack = methodInfo->maxStack;
5598 compHndBBtab = nullptr;
5599 compHndBBtabCount = 0;
5600 compHndBBtabAllocCount = 0;
5602 info.compNativeCodeSize = 0;
5603 info.compTotalHotCodeSize = 0;
5604 info.compTotalColdCodeSize = 0;
5607 compCurBB = nullptr;
5610 // Reset node ID counter
5614 /* Initialize emitter */
5616 if (!compIsForInlining())
5618 codeGen->getEmitter()->emitBegCG(this, compHnd);
5621 info.compIsStatic = (info.compFlags & CORINFO_FLG_STATIC) != 0;
5623 info.compIsContextful = (info.compClassAttr & CORINFO_FLG_CONTEXTFUL) != 0;
5625 info.compPublishStubParam = opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PUBLISH_SECRET_PARAM);
5627 switch (methodInfo->args.getCallConv())
5629 case CORINFO_CALLCONV_VARARG:
5630 case CORINFO_CALLCONV_NATIVEVARARG:
5631 info.compIsVarArgs = true;
5633 case CORINFO_CALLCONV_DEFAULT:
5634 info.compIsVarArgs = false;
5637 BADCODE("bad calling convention");
5639 info.compRetNativeType = info.compRetType = JITtype2varType(methodInfo->args.retType);
5641 info.compCallUnmanaged = 0;
5642 info.compLvFrameListRoot = BAD_VAR_NUM;
5644 #if FEATURE_FIXED_OUT_ARGS
5645 lvaOutgoingArgSpaceSize = 0;
5648 lvaGenericsContextUsed = false;
5650 info.compInitMem = ((methodInfo->options & CORINFO_OPT_INIT_LOCALS) != 0);
5652 /* Allocate the local variable table */
5656 if (!compIsForInlining())
5658 compInitDebuggingInfo();
5661 const bool forceInline = !!(info.compFlags & CORINFO_FLG_FORCEINLINE);
5663 if (!compIsForInlining() && opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
5665 // We're prejitting the root method. We also will analyze it as
5666 // a potential inline candidate.
5667 InlineResult prejitResult(this, methodHnd, "prejit");
5669 // Do the initial inline screen.
5670 impCanInlineIL(methodHnd, methodInfo, forceInline, &prejitResult);
5672 // Temporarily install the prejitResult as the
5673 // compInlineResult so it's available to fgFindJumpTargets
5674 // and can accumulate more observations as the IL is
5677 // We don't pass prejitResult in as a parameter to avoid
5678 // potential aliasing confusion -- the other call to
5679 // fgFindBasicBlocks may have set up compInlineResult and
5680 // the code in fgFindJumpTargets references that data
5681 // member extensively.
5682 assert(compInlineResult == nullptr);
5683 assert(impInlineInfo == nullptr);
5684 compInlineResult = &prejitResult;
5686 // Find the basic blocks. We must do this regardless of
5687 // inlineability, since we are prejitting this method.
5689 // This will also update the status of this method as
5690 // an inline candidate.
5691 fgFindBasicBlocks();
5693 // Undo the temporary setup.
5694 assert(compInlineResult == &prejitResult);
5695 compInlineResult = nullptr;
5697 // If still a viable, discretionary inline, assess
5699 if (prejitResult.IsDiscretionaryCandidate())
5701 prejitResult.DetermineProfitability(methodInfo);
5704 // Handle the results of the inline analysis.
5705 if (prejitResult.IsFailure())
5707 // This method is a bad inlinee according to our
5708 // analysis. We will let the InlineResult destructor
5709 // mark it as noinline in the prejit image to save the
5712 // This decision better not be context-dependent.
5713 assert(prejitResult.IsNever());
5717 // This looks like a viable inline candidate. Since
5718 // we're not actually inlining, don't report anything.
5719 prejitResult.SetReported();
5724 // We are jitting the root method, or inlining.
5725 fgFindBasicBlocks();
5728 // If we're inlining and the candidate is bad, bail out.
5729 if (compDonotInline())
5734 compSetOptimizationLevel();
5736 #if COUNT_BASIC_BLOCKS
5737 bbCntTable.record(fgBBcount);
5741 bbOneBBSizeTable.record(methodInfo->ILCodeSize);
5743 #endif // COUNT_BASIC_BLOCKS
5748 printf("Basic block list for '%s'\n", info.compFullName);
5749 fgDispBasicBlocks();
5754 /* Give the function a unique number */
5756 if (opts.disAsm || opts.dspEmit || verbose)
5758 s_compMethodsCount = ~info.compMethodHash() & 0xffff;
5762 s_compMethodsCount++;
5766 if (compIsForInlining())
5768 compInlineResult->NoteInt(InlineObservation::CALLEE_NUMBER_OF_BASIC_BLOCKS, fgBBcount);
5770 if (compInlineResult->IsFailure())
5777 if (JitConfig.DumpJittedMethods() == 1 && !compIsForInlining())
5779 printf("Compiling %4d %s::%s, IL size = %u, hsh=0x%x\n", Compiler::jitTotalMethodCompiled, info.compClassName,
5780 info.compMethodName, info.compILCodeSize, info.compMethodHash());
5782 if (compIsForInlining())
5784 compGenTreeID = impInlineInfo->InlinerCompiler->compGenTreeID;
5788 compCompile(methodCodePtr, methodCodeSize, compileFlags);
5791 if (compIsForInlining())
5793 impInlineInfo->InlinerCompiler->compGenTreeID = compGenTreeID;
5799 if (compDonotInline())
5801 // Verify we have only one inline result in play.
5802 assert(impInlineInfo->inlineResult == compInlineResult);
5805 if (!compIsForInlining())
5807 compCompileFinish();
5809 // Did we just compile for a target architecture that the VM isn't expecting? If so, the VM
5810 // can't used the generated code (and we better be an AltJit!).
5812 if (!info.compMatchedVM)
5814 return CORJIT_SKIPPED;
5819 if (JitConfig.RunAltJitCode() == 0)
5821 return CORJIT_SKIPPED;
5831 //------------------------------------------------------------------------
5832 // compFindLocalVarLinear: Linear search for variable's scope containing offset.
5835 // varNum The variable number to search for in the array of scopes.
5836 // offs The offset value which should occur within the life of the variable.
5839 // VarScopeDsc* of a matching variable that contains the offset within its life
5840 // begin and life end or nullptr when there is no match found.
5843 // Linear search for matching variables with their life begin and end containing
5845 // or NULL if one couldn't be found.
5848 // Usually called for scope count = 4. Could be called for values upto 8.
5850 VarScopeDsc* Compiler::compFindLocalVarLinear(unsigned varNum, unsigned offs)
5852 for (unsigned i = 0; i < info.compVarScopesCount; i++)
5854 VarScopeDsc* dsc = &info.compVarScopes[i];
5855 if ((dsc->vsdVarNum == varNum) && (dsc->vsdLifeBeg <= offs) && (dsc->vsdLifeEnd > offs))
5863 //------------------------------------------------------------------------
5864 // compFindLocalVar: Search for variable's scope containing offset.
5867 // varNum The variable number to search for in the array of scopes.
5868 // offs The offset value which should occur within the life of the variable.
5871 // VarScopeDsc* of a matching variable that contains the offset within its life
5872 // begin and life end.
5873 // or NULL if one couldn't be found.
5876 // Linear search for matching variables with their life begin and end containing
5877 // the offset only when the scope count is < MAX_LINEAR_FIND_LCL_SCOPELIST,
5878 // else use the hashtable lookup.
5880 VarScopeDsc* Compiler::compFindLocalVar(unsigned varNum, unsigned offs)
5882 if (info.compVarScopesCount < MAX_LINEAR_FIND_LCL_SCOPELIST)
5884 return compFindLocalVarLinear(varNum, offs);
5888 VarScopeDsc* ret = compFindLocalVar(varNum, offs, offs);
5889 assert(ret == compFindLocalVarLinear(varNum, offs));
5894 //------------------------------------------------------------------------
5895 // compFindLocalVar: Search for variable's scope containing offset.
5898 // varNum The variable number to search for in the array of scopes.
5899 // lifeBeg The life begin of the variable's scope
5900 // lifeEnd The life end of the variable's scope
5903 // VarScopeDsc* of a matching variable that contains the offset within its life
5904 // begin and life end, or NULL if one couldn't be found.
5907 // Following are the steps used:
5908 // 1. Index into the hashtable using varNum.
5909 // 2. Iterate through the linked list at index varNum to find a matching
5912 VarScopeDsc* Compiler::compFindLocalVar(unsigned varNum, unsigned lifeBeg, unsigned lifeEnd)
5914 assert(compVarScopeMap != nullptr);
5916 VarScopeMapInfo* info;
5917 if (compVarScopeMap->Lookup(varNum, &info))
5919 VarScopeListNode* list = info->head;
5920 while (list != nullptr)
5922 if ((list->data->vsdLifeBeg <= lifeBeg) && (list->data->vsdLifeEnd > lifeEnd))
5932 //-------------------------------------------------------------------------
5933 // compInitVarScopeMap: Create a scope map so it can be looked up by varNum
5936 // Map.K => Map.V :: varNum => List(ScopeDsc)
5938 // Create a scope map that can be indexed by varNum and can be iterated
5939 // on it's values to look for matching scope when given an offs or
5940 // lifeBeg and lifeEnd.
5943 // 1. Build the map only when we think linear search is slow, i.e.,
5944 // MAX_LINEAR_FIND_LCL_SCOPELIST is large.
5945 // 2. Linked list preserves original array order.
5947 void Compiler::compInitVarScopeMap()
5949 if (info.compVarScopesCount < MAX_LINEAR_FIND_LCL_SCOPELIST)
5954 assert(compVarScopeMap == nullptr);
5956 compVarScopeMap = new (getAllocator()) VarNumToScopeDscMap(getAllocator());
5958 // 599 prime to limit huge allocations; for ex: duplicated scopes on single var.
5959 compVarScopeMap->Reallocate(min(info.compVarScopesCount, 599));
5961 for (unsigned i = 0; i < info.compVarScopesCount; ++i)
5963 unsigned varNum = info.compVarScopes[i].vsdVarNum;
5965 VarScopeListNode* node = VarScopeListNode::Create(&info.compVarScopes[i], getAllocator());
5967 // Index by varNum and if the list exists append "node" to the "list".
5968 VarScopeMapInfo* info;
5969 if (compVarScopeMap->Lookup(varNum, &info))
5971 info->tail->next = node;
5974 // Create a new list.
5977 info = VarScopeMapInfo::Create(node, getAllocator());
5978 compVarScopeMap->Set(varNum, info);
5983 static int __cdecl genCmpLocalVarLifeBeg(const void* elem1, const void* elem2)
5985 return (*((VarScopeDsc**)elem1))->vsdLifeBeg - (*((VarScopeDsc**)elem2))->vsdLifeBeg;
5988 static int __cdecl genCmpLocalVarLifeEnd(const void* elem1, const void* elem2)
5990 return (*((VarScopeDsc**)elem1))->vsdLifeEnd - (*((VarScopeDsc**)elem2))->vsdLifeEnd;
5993 inline void Compiler::compInitScopeLists()
5995 if (info.compVarScopesCount == 0)
5997 compEnterScopeList = compExitScopeList = nullptr;
6001 // Populate the 'compEnterScopeList' and 'compExitScopeList' lists
6003 compEnterScopeList = new (this, CMK_DebugInfo) VarScopeDsc*[info.compVarScopesCount];
6004 compExitScopeList = new (this, CMK_DebugInfo) VarScopeDsc*[info.compVarScopesCount];
6006 for (unsigned i = 0; i < info.compVarScopesCount; i++)
6008 compEnterScopeList[i] = compExitScopeList[i] = &info.compVarScopes[i];
6011 qsort(compEnterScopeList, info.compVarScopesCount, sizeof(*compEnterScopeList), genCmpLocalVarLifeBeg);
6012 qsort(compExitScopeList, info.compVarScopesCount, sizeof(*compExitScopeList), genCmpLocalVarLifeEnd);
6015 void Compiler::compResetScopeLists()
6017 if (info.compVarScopesCount == 0)
6022 assert(compEnterScopeList && compExitScopeList);
6024 compNextEnterScope = compNextExitScope = 0;
6027 VarScopeDsc* Compiler::compGetNextEnterScope(unsigned offs, bool scan)
6029 assert(info.compVarScopesCount);
6030 assert(compEnterScopeList && compExitScopeList);
6032 if (compNextEnterScope < info.compVarScopesCount)
6034 assert(compEnterScopeList[compNextEnterScope]);
6035 unsigned nextEnterOff = compEnterScopeList[compNextEnterScope]->vsdLifeBeg;
6036 assert(scan || (offs <= nextEnterOff));
6040 if (offs == nextEnterOff)
6042 return compEnterScopeList[compNextEnterScope++];
6047 if (nextEnterOff <= offs)
6049 return compEnterScopeList[compNextEnterScope++];
6057 VarScopeDsc* Compiler::compGetNextExitScope(unsigned offs, bool scan)
6059 assert(info.compVarScopesCount);
6060 assert(compEnterScopeList && compExitScopeList);
6062 if (compNextExitScope < info.compVarScopesCount)
6064 assert(compExitScopeList[compNextExitScope]);
6065 unsigned nextExitOffs = compExitScopeList[compNextExitScope]->vsdLifeEnd;
6066 assert(scan || (offs <= nextExitOffs));
6070 if (offs == nextExitOffs)
6072 return compExitScopeList[compNextExitScope++];
6077 if (nextExitOffs <= offs)
6079 return compExitScopeList[compNextExitScope++];
6087 // The function will call the callback functions for scopes with boundaries
6088 // at instrs from the current status of the scope lists to 'offset',
6089 // ordered by instrs.
6091 void Compiler::compProcessScopesUntil(unsigned offset,
6093 void (Compiler::*enterScopeFn)(VARSET_TP* inScope, VarScopeDsc*),
6094 void (Compiler::*exitScopeFn)(VARSET_TP* inScope, VarScopeDsc*))
6096 assert(offset != BAD_IL_OFFSET);
6097 assert(inScope != nullptr);
6099 bool foundExit = false, foundEnter = true;
6101 VarScopeDsc* nextExitScope = nullptr;
6102 VarScopeDsc* nextEnterScope = nullptr;
6103 unsigned offs = offset, curEnterOffs = 0;
6105 goto START_FINDING_SCOPES;
6107 // We need to determine the scopes which are open for the current block.
6108 // This loop walks over the missing blocks between the current and the
6109 // previous block, keeping the enter and exit offsets in lockstep.
6113 foundExit = foundEnter = false;
6117 (this->*exitScopeFn)(inScope, nextExitScope);
6118 nextExitScope = nullptr;
6122 offs = nextEnterScope ? nextEnterScope->vsdLifeBeg : offset;
6124 while ((scope = compGetNextExitScope(offs, true)) != nullptr)
6128 if (!nextEnterScope || scope->vsdLifeEnd > nextEnterScope->vsdLifeBeg)
6130 // We overshot the last found Enter scope. Save the scope for later
6131 // and find an entering scope
6133 nextExitScope = scope;
6137 (this->*exitScopeFn)(inScope, scope);
6142 (this->*enterScopeFn)(inScope, nextEnterScope);
6143 curEnterOffs = nextEnterScope->vsdLifeBeg;
6144 nextEnterScope = nullptr;
6148 offs = nextExitScope ? nextExitScope->vsdLifeEnd : offset;
6150 START_FINDING_SCOPES:
6152 while ((scope = compGetNextEnterScope(offs, true)) != nullptr)
6156 if ((nextExitScope && scope->vsdLifeBeg >= nextExitScope->vsdLifeEnd) || (scope->vsdLifeBeg > curEnterOffs))
6158 // We overshot the last found exit scope. Save the scope for later
6159 // and find an exiting scope
6161 nextEnterScope = scope;
6165 (this->*enterScopeFn)(inScope, scope);
6169 curEnterOffs = scope->vsdLifeBeg;
6172 } while (foundExit || foundEnter);
6177 void Compiler::compDispScopeLists()
6181 printf("Local variable scopes = %d\n", info.compVarScopesCount);
6183 if (info.compVarScopesCount)
6185 printf(" \tVarNum \tLVNum \t Name \tBeg \tEnd\n");
6188 printf("Sorted by enter scope:\n");
6189 for (i = 0; i < info.compVarScopesCount; i++)
6191 VarScopeDsc* varScope = compEnterScopeList[i];
6193 printf("%2d: \t%02Xh \t%02Xh \t%10s \t%03Xh \t%03Xh", i, varScope->vsdVarNum, varScope->vsdLVnum,
6194 VarNameToStr(varScope->vsdName) == nullptr ? "UNKNOWN" : VarNameToStr(varScope->vsdName),
6195 varScope->vsdLifeBeg, varScope->vsdLifeEnd);
6197 if (compNextEnterScope == i)
6199 printf(" <-- next enter scope");
6205 printf("Sorted by exit scope:\n");
6206 for (i = 0; i < info.compVarScopesCount; i++)
6208 VarScopeDsc* varScope = compExitScopeList[i];
6210 printf("%2d: \t%02Xh \t%02Xh \t%10s \t%03Xh \t%03Xh", i, varScope->vsdVarNum, varScope->vsdLVnum,
6211 VarNameToStr(varScope->vsdName) == nullptr ? "UNKNOWN" : VarNameToStr(varScope->vsdName),
6212 varScope->vsdLifeBeg, varScope->vsdLifeEnd);
6214 if (compNextExitScope == i)
6216 printf(" <-- next exit scope");
6223 void Compiler::compDispLocalVars()
6225 printf("info.compVarScopesCount = %d\n", info.compVarScopesCount);
6227 if (info.compVarScopesCount > 0)
6229 printf(" \tVarNum \tLVNum \t Name \tBeg \tEnd\n");
6232 for (unsigned i = 0; i < info.compVarScopesCount; i++)
6234 VarScopeDsc* varScope = &info.compVarScopes[i];
6235 printf("%2d: \t%02Xh \t%02Xh \t%10s \t%03Xh \t%03Xh\n", i, varScope->vsdVarNum, varScope->vsdLVnum,
6236 VarNameToStr(varScope->vsdName) == nullptr ? "UNKNOWN" : VarNameToStr(varScope->vsdName),
6237 varScope->vsdLifeBeg, varScope->vsdLifeEnd);
6243 /*****************************************************************************/
6245 #if MEASURE_CLRAPI_CALLS
6247 struct WrapICorJitInfo : public ICorJitInfo
6249 //------------------------------------------------------------------------
6250 // WrapICorJitInfo::makeOne: allocate an instance of WrapICorJitInfo
6253 // alloc - the allocator to get memory from for the instance
6254 // compile - the compiler instance
6255 // compHndRef - the ICorJitInfo handle from the EE; the caller's
6256 // copy may be replaced with a "wrapper" instance
6259 // If the config flags indicate that ICorJitInfo should be wrapped,
6260 // we return the "wrapper" instance; otherwise we return "nullptr".
6262 static WrapICorJitInfo* makeOne(ArenaAllocator* alloc, Compiler* compiler, COMP_HANDLE& compHndRef /* INOUT */)
6264 WrapICorJitInfo* wrap = nullptr;
6266 if (JitConfig.JitEECallTimingInfo() != 0)
6268 // It's too early to use the default allocator, so we do this
6269 // in two steps to be safe (the constructor doesn't need to do
6270 // anything except fill in the vtable pointer, so we let the
6272 void* inst = alloc->allocateMemory(roundUp(sizeof(WrapICorJitInfo)));
6273 if (inst != nullptr)
6275 // If you get a build error here due to 'WrapICorJitInfo' being
6276 // an abstract class, it's very likely that the wrapper bodies
6277 // in ICorJitInfo_API_wrapper.hpp are no longer in sync with
6278 // the EE interface; please be kind and update the header file.
6279 wrap = new (inst, jitstd::placement_t()) WrapICorJitInfo();
6281 wrap->wrapComp = compiler;
6283 // Save the real handle and replace it with our wrapped version.
6284 wrap->wrapHnd = compHndRef;
6294 COMP_HANDLE wrapHnd; // the "real thing"
6297 #include "ICorJitInfo_API_wrapper.hpp"
6300 #endif // MEASURE_CLRAPI_CALLS
6302 /*****************************************************************************/
6304 // Compile a single method
6306 int jitNativeCode(CORINFO_METHOD_HANDLE methodHnd,
6307 CORINFO_MODULE_HANDLE classPtr,
6308 COMP_HANDLE compHnd,
6309 CORINFO_METHOD_INFO* methodInfo,
6310 void** methodCodePtr,
6311 ULONG* methodCodeSize,
6312 JitFlags* compileFlags,
6313 void* inlineInfoPtr)
6316 // A non-NULL inlineInfo means we are compiling the inlinee method.
6318 InlineInfo* inlineInfo = (InlineInfo*)inlineInfoPtr;
6320 bool jitFallbackCompile = false;
6322 int result = CORJIT_INTERNALERROR;
6324 ArenaAllocator* pAlloc = nullptr;
6325 ArenaAllocator alloc;
6327 #if MEASURE_CLRAPI_CALLS
6328 WrapICorJitInfo* wrapCLR = nullptr;
6333 // Use inliner's memory allocator when compiling the inlinee.
6334 pAlloc = inlineInfo->InlinerCompiler->compGetAllocator();
6338 IEEMemoryManager* pMemoryManager = compHnd->getMemoryManager();
6340 // Try to reuse the pre-inited allocator
6341 pAlloc = ArenaAllocator::getPooledAllocator(pMemoryManager);
6343 if (pAlloc == nullptr)
6345 alloc = ArenaAllocator(pMemoryManager);
6356 ArenaAllocator* pAlloc;
6357 ArenaAllocator* alloc;
6358 bool jitFallbackCompile;
6360 CORINFO_METHOD_HANDLE methodHnd;
6361 CORINFO_MODULE_HANDLE classPtr;
6362 COMP_HANDLE compHnd;
6363 CORINFO_METHOD_INFO* methodInfo;
6364 void** methodCodePtr;
6365 ULONG* methodCodeSize;
6366 JitFlags* compileFlags;
6367 InlineInfo* inlineInfo;
6368 #if MEASURE_CLRAPI_CALLS
6369 WrapICorJitInfo* wrapCLR;
6374 param.pComp = nullptr;
6375 param.pAlloc = pAlloc;
6376 param.alloc = &alloc;
6377 param.jitFallbackCompile = jitFallbackCompile;
6378 param.methodHnd = methodHnd;
6379 param.classPtr = classPtr;
6380 param.compHnd = compHnd;
6381 param.methodInfo = methodInfo;
6382 param.methodCodePtr = methodCodePtr;
6383 param.methodCodeSize = methodCodeSize;
6384 param.compileFlags = compileFlags;
6385 param.inlineInfo = inlineInfo;
6386 #if MEASURE_CLRAPI_CALLS
6387 param.wrapCLR = nullptr;
6389 param.result = result;
6391 setErrorTrap(compHnd, Param*, pParamOuter, ¶m)
6393 setErrorTrap(nullptr, Param*, pParam, pParamOuter)
6395 if (pParam->inlineInfo)
6397 // Lazily create the inlinee compiler object
6398 if (pParam->inlineInfo->InlinerCompiler->InlineeCompiler == nullptr)
6400 pParam->inlineInfo->InlinerCompiler->InlineeCompiler =
6401 (Compiler*)pParam->pAlloc->allocateMemory(roundUp(sizeof(*pParam->pComp)));
6404 // Use the inlinee compiler object
6405 pParam->pComp = pParam->inlineInfo->InlinerCompiler->InlineeCompiler;
6407 // memset(pParam->pComp, 0xEE, sizeof(Compiler));
6412 // Allocate create the inliner compiler object
6413 pParam->pComp = (Compiler*)pParam->pAlloc->allocateMemory(roundUp(sizeof(*pParam->pComp)));
6416 #if MEASURE_CLRAPI_CALLS
6417 pParam->wrapCLR = WrapICorJitInfo::makeOne(pParam->pAlloc, pParam->pComp, pParam->compHnd);
6420 // push this compiler on the stack (TLS)
6421 pParam->pComp->prevCompiler = JitTls::GetCompiler();
6422 JitTls::SetCompiler(pParam->pComp);
6424 // PREFIX_ASSUME gets turned into ASSERT_CHECK and we cannot have it here
6425 #if defined(_PREFAST_) || defined(_PREFIX_)
6426 PREFIX_ASSUME(pParam->pComp != NULL);
6428 assert(pParam->pComp != nullptr);
6431 pParam->pComp->compInit(pParam->pAlloc, pParam->inlineInfo);
6434 pParam->pComp->jitFallbackCompile = pParam->jitFallbackCompile;
6437 // Now generate the code
6439 pParam->pComp->compCompile(pParam->methodHnd, pParam->classPtr, pParam->compHnd, pParam->methodInfo,
6440 pParam->methodCodePtr, pParam->methodCodeSize, pParam->compileFlags);
6444 // Add a dummy touch to pComp so that it is kept alive, and is easy to get to
6445 // during debugging since all other data can be obtained through it.
6447 if (pParamOuter->pComp) // If OOM is thrown when allocating memory for pComp, we will end up here.
6448 // In that case, pComp is still NULL.
6450 pParamOuter->pComp->info.compCode = nullptr;
6452 // pop the compiler off the TLS stack only if it was linked above
6453 assert(JitTls::GetCompiler() == pParamOuter->pComp);
6454 JitTls::SetCompiler(JitTls::GetCompiler()->prevCompiler);
6457 if (pParamOuter->inlineInfo == nullptr)
6459 // Free up the allocator we were using
6460 pParamOuter->pAlloc->destroy();
6467 // If we were looking at an inlinee....
6468 if (inlineInfo != nullptr)
6470 // Note that we failed to compile the inlinee, and that
6471 // there's no point trying to inline it again anywhere else.
6472 inlineInfo->inlineResult->NoteFatal(InlineObservation::CALLEE_COMPILATION_ERROR);
6474 param.result = __errc;
6478 result = param.result;
6480 if (!inlineInfo && (result == CORJIT_INTERNALERROR || result == CORJIT_RECOVERABLEERROR) && !jitFallbackCompile)
6482 // If we failed the JIT, reattempt with debuggable code.
6483 jitFallbackCompile = true;
6485 // Update the flags for 'safer' code generation.
6486 compileFlags->Set(JitFlags::JIT_FLAG_MIN_OPT);
6487 compileFlags->Clear(JitFlags::JIT_FLAG_SIZE_OPT);
6488 compileFlags->Clear(JitFlags::JIT_FLAG_SPEED_OPT);
6496 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
6498 // GetTypeFromClassificationAndSizes:
6499 // Returns the type of the eightbyte accounting for the classification and size of the eightbyte.
6502 // classType: classification type
6503 // size: size of the eightbyte.
6506 var_types Compiler::GetTypeFromClassificationAndSizes(SystemVClassificationType classType, int size)
6508 var_types type = TYP_UNKNOWN;
6511 case SystemVClassificationTypeInteger:
6530 assert(false && "GetTypeFromClassificationAndSizes Invalid Integer classification type.");
6533 case SystemVClassificationTypeIntegerReference:
6536 case SystemVClassificationTypeIntegerByRef:
6539 case SystemVClassificationTypeSSE:
6550 assert(false && "GetTypeFromClassificationAndSizes Invalid SSE classification type.");
6555 assert(false && "GetTypeFromClassificationAndSizes Invalid classification type.");
6562 //-------------------------------------------------------------------
6563 // GetEightByteType: Returns the type of eightbyte slot of a struct
6566 // structDesc - struct classification description.
6567 // slotNum - eightbyte slot number for the struct.
6570 // type of the eightbyte slot of the struct
6573 var_types Compiler::GetEightByteType(const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR& structDesc,
6576 var_types eightByteType = TYP_UNDEF;
6577 unsigned len = structDesc.eightByteSizes[slotNum];
6579 switch (structDesc.eightByteClassifications[slotNum])
6581 case SystemVClassificationTypeInteger:
6582 // See typelist.h for jit type definition.
6583 // All the types of size < 4 bytes are of jit type TYP_INT.
6584 if (structDesc.eightByteSizes[slotNum] <= 4)
6586 eightByteType = TYP_INT;
6588 else if (structDesc.eightByteSizes[slotNum] <= 8)
6590 eightByteType = TYP_LONG;
6594 assert(false && "GetEightByteType Invalid Integer classification type.");
6597 case SystemVClassificationTypeIntegerReference:
6598 assert(len == REGSIZE_BYTES);
6599 eightByteType = TYP_REF;
6601 case SystemVClassificationTypeIntegerByRef:
6602 assert(len == REGSIZE_BYTES);
6603 eightByteType = TYP_BYREF;
6605 case SystemVClassificationTypeSSE:
6606 if (structDesc.eightByteSizes[slotNum] <= 4)
6608 eightByteType = TYP_FLOAT;
6610 else if (structDesc.eightByteSizes[slotNum] <= 8)
6612 eightByteType = TYP_DOUBLE;
6616 assert(false && "GetEightByteType Invalid SSE classification type.");
6620 assert(false && "GetEightByteType Invalid classification type.");
6624 return eightByteType;
6627 //------------------------------------------------------------------------------------------------------
6628 // GetStructTypeOffset: Gets the type, size and offset of the eightbytes of a struct for System V systems.
6631 // 'structDesc' - struct description
6632 // 'type0' - out param; returns the type of the first eightbyte.
6633 // 'type1' - out param; returns the type of the second eightbyte.
6634 // 'offset0' - out param; returns the offset of the first eightbyte.
6635 // 'offset1' - out param; returns the offset of the second eightbyte.
6638 void Compiler::GetStructTypeOffset(const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR& structDesc,
6641 unsigned __int8* offset0,
6642 unsigned __int8* offset1)
6644 *offset0 = structDesc.eightByteOffsets[0];
6645 *offset1 = structDesc.eightByteOffsets[1];
6647 *type0 = TYP_UNKNOWN;
6648 *type1 = TYP_UNKNOWN;
6650 // Set the first eightbyte data
6651 if (structDesc.eightByteCount >= 1)
6653 *type0 = GetEightByteType(structDesc, 0);
6656 // Set the second eight byte data
6657 if (structDesc.eightByteCount == 2)
6659 *type1 = GetEightByteType(structDesc, 1);
6662 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
6664 /*****************************************************************************/
6665 /*****************************************************************************/
6668 Compiler::NodeToIntMap* Compiler::FindReachableNodesInNodeTestData()
6670 NodeToIntMap* reachable = new (getAllocatorDebugOnly()) NodeToIntMap(getAllocatorDebugOnly());
6672 if (m_nodeTestData == nullptr)
6677 // Otherwise, iterate.
6679 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
6681 for (GenTreePtr stmt = block->FirstNonPhiDef(); stmt != nullptr; stmt = stmt->gtNext)
6683 for (GenTreePtr tree = stmt->gtStmt.gtStmtList; tree; tree = tree->gtNext)
6685 TestLabelAndNum tlAndN;
6687 // For call nodes, translate late args to what they stand for.
6688 if (tree->OperGet() == GT_CALL)
6690 GenTreeCall* call = tree->AsCall();
6691 GenTreeArgList* args = call->gtCallArgs;
6693 while (args != nullptr)
6695 GenTreePtr arg = args->Current();
6696 if (arg->gtFlags & GTF_LATE_ARG)
6698 // Find the corresponding late arg.
6699 GenTreePtr lateArg = nullptr;
6700 for (unsigned j = 0; j < call->fgArgInfo->ArgCount(); j++)
6702 if (call->fgArgInfo->ArgTable()[j]->argNum == i)
6704 lateArg = call->fgArgInfo->ArgTable()[j]->node;
6708 assert(lateArg != nullptr);
6709 if (GetNodeTestData()->Lookup(lateArg, &tlAndN))
6711 reachable->Set(lateArg, 0);
6715 args = args->Rest();
6719 if (GetNodeTestData()->Lookup(tree, &tlAndN))
6721 reachable->Set(tree, 0);
6729 void Compiler::TransferTestDataToNode(GenTreePtr from, GenTreePtr to)
6731 TestLabelAndNum tlAndN;
6732 // We can't currently associate multiple annotations with a single node.
6733 // If we need to, we can fix this...
6735 // If the table is null, don't create it just to do the lookup, which would fail...
6736 if (m_nodeTestData != nullptr && GetNodeTestData()->Lookup(from, &tlAndN))
6738 assert(!GetNodeTestData()->Lookup(to, &tlAndN));
6739 // We can't currently associate multiple annotations with a single node.
6740 // If we need to, we can fix this...
6741 TestLabelAndNum tlAndNTo;
6742 assert(!GetNodeTestData()->Lookup(to, &tlAndNTo));
6744 GetNodeTestData()->Remove(from);
6745 GetNodeTestData()->Set(to, tlAndN);
6749 void Compiler::CopyTestDataToCloneTree(GenTreePtr from, GenTreePtr to)
6751 if (m_nodeTestData == nullptr)
6755 if (from == nullptr)
6757 assert(to == nullptr);
6761 TestLabelAndNum tlAndN;
6762 if (GetNodeTestData()->Lookup(from, &tlAndN))
6764 // We can't currently associate multiple annotations with a single node.
6765 // If we need to, we can fix this...
6766 TestLabelAndNum tlAndNTo;
6767 assert(!GetNodeTestData()->Lookup(to, &tlAndNTo));
6768 GetNodeTestData()->Set(to, tlAndN);
6770 // Now recurse, in parallel on both trees.
6772 genTreeOps oper = from->OperGet();
6773 unsigned kind = from->OperKind();
6774 assert(oper == to->OperGet());
6776 // Cconstant or leaf nodes have no children.
6777 if (kind & (GTK_CONST | GTK_LEAF))
6782 // Otherwise, is it a 'simple' unary/binary operator?
6784 if (kind & GTK_SMPOP)
6786 if (from->gtOp.gtOp1 != nullptr)
6788 assert(to->gtOp.gtOp1 != nullptr);
6789 CopyTestDataToCloneTree(from->gtOp.gtOp1, to->gtOp.gtOp1);
6793 assert(to->gtOp.gtOp1 == nullptr);
6796 if (from->gtGetOp2() != nullptr)
6798 assert(to->gtGetOp2() != nullptr);
6799 CopyTestDataToCloneTree(from->gtGetOp2(), to->gtGetOp2());
6803 assert(to->gtGetOp2() == nullptr);
6809 // Otherwise, see what kind of a special operator we have here.
6814 CopyTestDataToCloneTree(from->gtStmt.gtStmtExpr, to->gtStmt.gtStmtExpr);
6818 CopyTestDataToCloneTree(from->gtCall.gtCallObjp, to->gtCall.gtCallObjp);
6819 CopyTestDataToCloneTree(from->gtCall.gtCallArgs, to->gtCall.gtCallArgs);
6820 CopyTestDataToCloneTree(from->gtCall.gtCallLateArgs, to->gtCall.gtCallLateArgs);
6822 if (from->gtCall.gtCallType == CT_INDIRECT)
6824 CopyTestDataToCloneTree(from->gtCall.gtCallCookie, to->gtCall.gtCallCookie);
6825 CopyTestDataToCloneTree(from->gtCall.gtCallAddr, to->gtCall.gtCallAddr);
6827 // The other call types do not have additional GenTree arguments.
6832 CopyTestDataToCloneTree(from->gtField.gtFldObj, to->gtField.gtFldObj);
6836 assert(from->gtArrElem.gtArrRank == to->gtArrElem.gtArrRank);
6837 for (unsigned dim = 0; dim < from->gtArrElem.gtArrRank; dim++)
6839 CopyTestDataToCloneTree(from->gtArrElem.gtArrInds[dim], to->gtArrElem.gtArrInds[dim]);
6841 CopyTestDataToCloneTree(from->gtArrElem.gtArrObj, to->gtArrElem.gtArrObj);
6845 CopyTestDataToCloneTree(from->gtCmpXchg.gtOpLocation, to->gtCmpXchg.gtOpLocation);
6846 CopyTestDataToCloneTree(from->gtCmpXchg.gtOpValue, to->gtCmpXchg.gtOpValue);
6847 CopyTestDataToCloneTree(from->gtCmpXchg.gtOpComparand, to->gtCmpXchg.gtOpComparand);
6850 case GT_ARR_BOUNDS_CHECK:
6853 #endif // FEATURE_SIMD
6854 CopyTestDataToCloneTree(from->gtBoundsChk.gtArrLen, to->gtBoundsChk.gtArrLen);
6855 CopyTestDataToCloneTree(from->gtBoundsChk.gtIndex, to->gtBoundsChk.gtIndex);
6866 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6867 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6871 XX Functions for the stand-alone version of the JIT . XX
6873 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6874 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6877 /*****************************************************************************/
6878 void codeGeneratorCodeSizeBeg()
6881 /*****************************************************************************/
6883 /*****************************************************************************
6885 * If any temporary tables are smaller than 'genMinSize2free' we won't bother
6889 const size_t genMinSize2free = 64;
6891 /*****************************************************************************/
6893 /*****************************************************************************
6895 * Used for counting pointer assignments.
6898 /*****************************************************************************/
6899 void codeGeneratorCodeSizeEnd()
6902 /*****************************************************************************
6904 * Gather statistics - mainly used for the standalone
6905 * Enable various #ifdef's to get the information you need
6908 void Compiler::compJitStats()
6912 /* Method types and argument statistics */
6914 #endif // CALL_ARG_STATS
6919 /*****************************************************************************
6921 * Gather statistics about method calls and arguments
6924 void Compiler::compCallArgStats()
6935 unsigned argDWordNum;
6941 unsigned regArgDeferred;
6942 unsigned regArgTemp;
6944 unsigned regArgLclVar;
6945 unsigned regArgConst;
6947 unsigned argTempsThisMethod = 0;
6949 assert(fgStmtListThreaded);
6951 for (block = fgFirstBB; block; block = block->bbNext)
6953 for (stmt = block->bbTreeList; stmt; stmt = stmt->gtNext)
6955 assert(stmt->gtOper == GT_STMT);
6957 for (call = stmt->gtStmt.gtStmtList; call; call = call->gtNext)
6959 if (call->gtOper != GT_CALL)
6964 regArgNum = regArgDeferred = regArgTemp =
6966 regArgConst = regArgLclVar =
6968 argDWordNum = argLngNum = argFltNum = argDblNum = 0;
6972 if (!call->gtCall.gtCallObjp)
6974 if (call->gtCall.gtCallType == CT_HELPER)
6985 /* We have a 'this' pointer */
6993 if (call->gtFlags & (GTF_CALL_VIRT_VTABLE | GTF_CALL_VIRT_STUB))
6995 /* virtual function */
7000 argNonVirtualCalls++;
7004 #ifdef LEGACY_BACKEND
7005 // TODO-Cleaenup: We need to add support below for additional node types that RyuJIT backend has in the
7007 // Gather arguments information.
7009 for (args = call->gtCall.gtCallArgs; args; args = args->gtOp.gtOp2)
7011 argx = args->gtOp.gtOp1;
7015 switch (genActualType(argx->TypeGet()))
7036 /* This is a deferred register argument */
7037 assert(argx->gtOper == GT_NOP);
7038 assert(argx->gtFlags & GTF_LATE_ARG);
7043 /* Is this argument a register argument? */
7045 if (argx->gtFlags & GTF_LATE_ARG)
7049 /* We either have a deferred argument or a temp */
7051 if (argx->gtOper == GT_NOP)
7057 assert(argx->gtOper == GT_ASG);
7063 /* Look at the register arguments and count how many constants, local vars */
7065 for (args = call->gtCall.gtCallLateArgs; args; args = args->gtOp.gtOp2)
7067 argx = args->gtOp.gtOp1;
7069 switch (argx->gtOper)
7081 assert(argNum == argDWordNum + argLngNum + argFltNum + argDblNum);
7082 assert(regArgNum == regArgDeferred + regArgTemp);
7084 argTotalArgs += argNum;
7085 argTotalRegArgs += regArgNum;
7087 argTotalDWordArgs += argDWordNum;
7088 argTotalLongArgs += argLngNum;
7089 argTotalFloatArgs += argFltNum;
7090 argTotalDoubleArgs += argDblNum;
7092 argTotalDeferred += regArgDeferred;
7093 argTotalTemps += regArgTemp;
7094 argTotalConst += regArgConst;
7095 argTotalLclVar += regArgLclVar;
7097 argTempsThisMethod += regArgTemp;
7099 argCntTable.record(argNum);
7100 argDWordCntTable.record(argDWordNum);
7101 argDWordLngCntTable.record(argDWordNum + (2 * argLngNum));
7102 #endif // LEGACY_BACKEND
7107 argTempsCntTable.record(argTempsThisMethod);
7109 if (argMaxTempsPerMethod < argTempsThisMethod)
7111 argMaxTempsPerMethod = argTempsThisMethod;
7116 void Compiler::compDispCallArgStats(FILE* fout)
7118 if (argTotalCalls == 0)
7121 fprintf(fout, "\n");
7122 fprintf(fout, "--------------------------------------------------\n");
7123 fprintf(fout, "Call stats\n");
7124 fprintf(fout, "--------------------------------------------------\n");
7125 fprintf(fout, "Total # of calls = %d, calls / method = %.3f\n\n", argTotalCalls,
7126 (float)argTotalCalls / genMethodCnt);
7128 fprintf(fout, "Percentage of helper calls = %4.2f %%\n", (float)(100 * argHelperCalls) / argTotalCalls);
7129 fprintf(fout, "Percentage of static calls = %4.2f %%\n", (float)(100 * argStaticCalls) / argTotalCalls);
7130 fprintf(fout, "Percentage of virtual calls = %4.2f %%\n", (float)(100 * argVirtualCalls) / argTotalCalls);
7131 fprintf(fout, "Percentage of non-virtual calls = %4.2f %%\n\n", (float)(100 * argNonVirtualCalls) / argTotalCalls);
7133 fprintf(fout, "Average # of arguments per call = %.2f%%\n\n", (float)argTotalArgs / argTotalCalls);
7135 fprintf(fout, "Percentage of DWORD arguments = %.2f %%\n", (float)(100 * argTotalDWordArgs) / argTotalArgs);
7136 fprintf(fout, "Percentage of LONG arguments = %.2f %%\n", (float)(100 * argTotalLongArgs) / argTotalArgs);
7137 fprintf(fout, "Percentage of FLOAT arguments = %.2f %%\n", (float)(100 * argTotalFloatArgs) / argTotalArgs);
7138 fprintf(fout, "Percentage of DOUBLE arguments = %.2f %%\n\n", (float)(100 * argTotalDoubleArgs) / argTotalArgs);
7140 if (argTotalRegArgs == 0)
7144 fprintf(fout, "Total deferred arguments = %d \n", argTotalDeferred);
7146 fprintf(fout, "Total temp arguments = %d \n\n", argTotalTemps);
7148 fprintf(fout, "Total 'this' arguments = %d \n", argTotalObjPtr);
7149 fprintf(fout, "Total local var arguments = %d \n", argTotalLclVar);
7150 fprintf(fout, "Total constant arguments = %d \n\n", argTotalConst);
7153 fprintf(fout, "\nRegister Arguments:\n\n");
7155 fprintf(fout, "Percentage of deferred arguments = %.2f %%\n", (float)(100 * argTotalDeferred) / argTotalRegArgs);
7156 fprintf(fout, "Percentage of temp arguments = %.2f %%\n\n", (float)(100 * argTotalTemps) / argTotalRegArgs);
7158 fprintf(fout, "Maximum # of temps per method = %d\n\n", argMaxTempsPerMethod);
7160 fprintf(fout, "Percentage of ObjPtr arguments = %.2f %%\n", (float)(100 * argTotalObjPtr) / argTotalRegArgs);
7161 // fprintf(fout, "Percentage of global arguments = %.2f %%\n", (float)(100 * argTotalDWordGlobEf) /
7162 // argTotalRegArgs);
7163 fprintf(fout, "Percentage of constant arguments = %.2f %%\n", (float)(100 * argTotalConst) / argTotalRegArgs);
7164 fprintf(fout, "Percentage of lcl var arguments = %.2f %%\n\n", (float)(100 * argTotalLclVar) / argTotalRegArgs);
7166 fprintf(fout, "--------------------------------------------------\n");
7167 fprintf(fout, "Argument count frequency table (includes ObjPtr):\n");
7168 fprintf(fout, "--------------------------------------------------\n");
7169 argCntTable.dump(fout);
7170 fprintf(fout, "--------------------------------------------------\n");
7172 fprintf(fout, "--------------------------------------------------\n");
7173 fprintf(fout, "DWORD argument count frequency table (w/o LONG):\n");
7174 fprintf(fout, "--------------------------------------------------\n");
7175 argDWordCntTable.dump(fout);
7176 fprintf(fout, "--------------------------------------------------\n");
7178 fprintf(fout, "--------------------------------------------------\n");
7179 fprintf(fout, "Temps count frequency table (per method):\n");
7180 fprintf(fout, "--------------------------------------------------\n");
7181 argTempsCntTable.dump(fout);
7182 fprintf(fout, "--------------------------------------------------\n");
7185 fprintf(fout, "--------------------------------------------------\n");
7186 fprintf(fout, "DWORD argument count frequency table (w/ LONG):\n");
7187 fprintf(fout, "--------------------------------------------------\n");
7188 argDWordLngCntTable.dump(fout);
7189 fprintf(fout, "--------------------------------------------------\n");
7193 #endif // CALL_ARG_STATS
7195 // JIT time end to end, and by phases.
7197 #ifdef FEATURE_JIT_METHOD_PERF
7199 CritSecObject CompTimeSummaryInfo::s_compTimeSummaryLock;
7200 CompTimeSummaryInfo CompTimeSummaryInfo::s_compTimeSummary;
7201 #if MEASURE_CLRAPI_CALLS
7202 double JitTimer::s_cyclesPerSec = CycleTimer::CyclesPerSecond();
7204 #endif // FEATURE_JIT_METHOD_PERF
7206 #if defined(FEATURE_JIT_METHOD_PERF) || DUMP_FLOWGRAPHS || defined(FEATURE_TRACELOGGING)
7207 const char* PhaseNames[] = {
7208 #define CompPhaseNameMacro(enum_nm, string_nm, short_nm, hasChildren, parent) string_nm,
7209 #include "compphases.h"
7212 const char* PhaseEnums[] = {
7213 #define CompPhaseNameMacro(enum_nm, string_nm, short_nm, hasChildren, parent) #enum_nm,
7214 #include "compphases.h"
7217 const LPCWSTR PhaseShortNames[] = {
7218 #define CompPhaseNameMacro(enum_nm, string_nm, short_nm, hasChildren, parent) W(short_nm),
7219 #include "compphases.h"
7221 #endif // defined(FEATURE_JIT_METHOD_PERF) || DUMP_FLOWGRAPHS
7223 #ifdef FEATURE_JIT_METHOD_PERF
7224 bool PhaseHasChildren[] = {
7225 #define CompPhaseNameMacro(enum_nm, string_nm, short_nm, hasChildren, parent) hasChildren,
7226 #include "compphases.h"
7229 int PhaseParent[] = {
7230 #define CompPhaseNameMacro(enum_nm, string_nm, short_nm, hasChildren, parent) parent,
7231 #include "compphases.h"
7234 CompTimeInfo::CompTimeInfo(unsigned byteCodeBytes)
7235 : m_byteCodeBytes(byteCodeBytes)
7237 , m_parentPhaseEndSlop(0)
7238 , m_timerFailure(false)
7239 #if MEASURE_CLRAPI_CALLS
7240 , m_allClrAPIcalls(0)
7241 , m_allClrAPIcycles(0)
7244 for (int i = 0; i < PHASE_NUMBER_OF; i++)
7246 m_invokesByPhase[i] = 0;
7247 m_cyclesByPhase[i] = 0;
7248 #if MEASURE_CLRAPI_CALLS
7249 m_CLRinvokesByPhase[i] = 0;
7250 m_CLRcyclesByPhase[i] = 0;
7254 #if MEASURE_CLRAPI_CALLS
7255 assert(ARRAYSIZE(m_perClrAPIcalls) == API_ICorJitInfo_Names::API_COUNT);
7256 assert(ARRAYSIZE(m_perClrAPIcycles) == API_ICorJitInfo_Names::API_COUNT);
7257 assert(ARRAYSIZE(m_maxClrAPIcycles) == API_ICorJitInfo_Names::API_COUNT);
7258 for (int i = 0; i < API_ICorJitInfo_Names::API_COUNT; i++)
7260 m_perClrAPIcalls[i] = 0;
7261 m_perClrAPIcycles[i] = 0;
7262 m_maxClrAPIcycles[i] = 0;
7267 bool CompTimeSummaryInfo::IncludedInFilteredData(CompTimeInfo& info)
7269 return false; // info.m_byteCodeBytes < 10;
7272 //------------------------------------------------------------------------
7273 // CompTimeSummaryInfo::AddInfo: Record timing info from one compile.
7276 // info - The timing information to record.
7277 // includePhases - If "true", the per-phase info in "info" is valid,
7278 // which means that a "normal" compile has ended; if
7279 // the value is "false" we are recording the results
7280 // of a partial compile (typically an import-only run
7281 // on behalf of the inliner) in which case the phase
7282 // info is not valid and so we only record EE call
7284 void CompTimeSummaryInfo::AddInfo(CompTimeInfo& info, bool includePhases)
7286 if (info.m_timerFailure)
7288 return; // Don't update if there was a failure.
7291 CritSecHolder timeLock(s_compTimeSummaryLock);
7295 bool includeInFiltered = IncludedInFilteredData(info);
7299 // Update the totals and maxima.
7300 m_total.m_byteCodeBytes += info.m_byteCodeBytes;
7301 m_maximum.m_byteCodeBytes = max(m_maximum.m_byteCodeBytes, info.m_byteCodeBytes);
7302 m_total.m_totalCycles += info.m_totalCycles;
7303 m_maximum.m_totalCycles = max(m_maximum.m_totalCycles, info.m_totalCycles);
7305 #if MEASURE_CLRAPI_CALLS
7306 // Update the CLR-API values.
7307 m_total.m_allClrAPIcalls += info.m_allClrAPIcalls;
7308 m_maximum.m_allClrAPIcalls = max(m_maximum.m_allClrAPIcalls, info.m_allClrAPIcalls);
7309 m_total.m_allClrAPIcycles += info.m_allClrAPIcycles;
7310 m_maximum.m_allClrAPIcycles = max(m_maximum.m_allClrAPIcycles, info.m_allClrAPIcycles);
7313 if (includeInFiltered)
7315 m_numFilteredMethods++;
7316 m_filtered.m_byteCodeBytes += info.m_byteCodeBytes;
7317 m_filtered.m_totalCycles += info.m_totalCycles;
7318 m_filtered.m_parentPhaseEndSlop += info.m_parentPhaseEndSlop;
7321 for (int i = 0; i < PHASE_NUMBER_OF; i++)
7323 m_total.m_invokesByPhase[i] += info.m_invokesByPhase[i];
7324 m_total.m_cyclesByPhase[i] += info.m_cyclesByPhase[i];
7326 #if MEASURE_CLRAPI_CALLS
7327 m_total.m_CLRinvokesByPhase[i] += info.m_CLRinvokesByPhase[i];
7328 m_total.m_CLRcyclesByPhase[i] += info.m_CLRcyclesByPhase[i];
7331 if (includeInFiltered)
7333 m_filtered.m_invokesByPhase[i] += info.m_invokesByPhase[i];
7334 m_filtered.m_cyclesByPhase[i] += info.m_cyclesByPhase[i];
7335 #if MEASURE_CLRAPI_CALLS
7336 m_filtered.m_CLRinvokesByPhase[i] += info.m_CLRinvokesByPhase[i];
7337 m_filtered.m_CLRcyclesByPhase[i] += info.m_CLRcyclesByPhase[i];
7340 m_maximum.m_cyclesByPhase[i] = max(m_maximum.m_cyclesByPhase[i], info.m_cyclesByPhase[i]);
7342 #if MEASURE_CLRAPI_CALLS
7343 m_maximum.m_CLRcyclesByPhase[i] = max(m_maximum.m_CLRcyclesByPhase[i], info.m_CLRcyclesByPhase[i]);
7346 m_total.m_parentPhaseEndSlop += info.m_parentPhaseEndSlop;
7347 m_maximum.m_parentPhaseEndSlop = max(m_maximum.m_parentPhaseEndSlop, info.m_parentPhaseEndSlop);
7349 #if MEASURE_CLRAPI_CALLS
7354 // Update the "global" CLR-API values.
7355 m_total.m_allClrAPIcalls += info.m_allClrAPIcalls;
7356 m_maximum.m_allClrAPIcalls = max(m_maximum.m_allClrAPIcalls, info.m_allClrAPIcalls);
7357 m_total.m_allClrAPIcycles += info.m_allClrAPIcycles;
7358 m_maximum.m_allClrAPIcycles = max(m_maximum.m_allClrAPIcycles, info.m_allClrAPIcycles);
7360 // Update the per-phase CLR-API values.
7361 m_total.m_invokesByPhase[PHASE_CLR_API] += info.m_allClrAPIcalls;
7362 m_maximum.m_invokesByPhase[PHASE_CLR_API] =
7363 max(m_maximum.m_perClrAPIcalls[PHASE_CLR_API], info.m_allClrAPIcalls);
7364 m_total.m_cyclesByPhase[PHASE_CLR_API] += info.m_allClrAPIcycles;
7365 m_maximum.m_cyclesByPhase[PHASE_CLR_API] =
7366 max(m_maximum.m_cyclesByPhase[PHASE_CLR_API], info.m_allClrAPIcycles);
7369 for (int i = 0; i < API_ICorJitInfo_Names::API_COUNT; i++)
7371 m_total.m_perClrAPIcalls[i] += info.m_perClrAPIcalls[i];
7372 m_maximum.m_perClrAPIcalls[i] = max(m_maximum.m_perClrAPIcalls[i], info.m_perClrAPIcalls[i]);
7374 m_total.m_perClrAPIcycles[i] += info.m_perClrAPIcycles[i];
7375 m_maximum.m_perClrAPIcycles[i] = max(m_maximum.m_perClrAPIcycles[i], info.m_perClrAPIcycles[i]);
7377 m_maximum.m_maxClrAPIcycles[i] = max(m_maximum.m_maxClrAPIcycles[i], info.m_maxClrAPIcycles[i]);
7383 LPCWSTR Compiler::compJitTimeLogFilename = nullptr;
7385 void CompTimeSummaryInfo::Print(FILE* f)
7392 double countsPerSec = CycleTimer::CyclesPerSecond();
7393 if (countsPerSec == 0.0)
7395 fprintf(f, "Processor does not have a high-frequency timer.\n");
7399 bool extraInfo = (JitConfig.JitEECallTimingInfo() != 0);
7400 double totTime_ms = 0.0;
7402 fprintf(f, "JIT Compilation time report:\n");
7403 fprintf(f, " Compiled %d methods.\n", m_numMethods);
7404 if (m_numMethods != 0)
7406 fprintf(f, " Compiled %d bytecodes total (%d max, %8.2f avg).\n", m_total.m_byteCodeBytes,
7407 m_maximum.m_byteCodeBytes, (double)m_total.m_byteCodeBytes / (double)m_numMethods);
7408 totTime_ms = ((double)m_total.m_totalCycles / countsPerSec) * 1000.0;
7409 fprintf(f, " Time: total: %10.3f Mcycles/%10.3f ms\n", ((double)m_total.m_totalCycles / 1000000.0),
7411 fprintf(f, " max: %10.3f Mcycles/%10.3f ms\n", ((double)m_maximum.m_totalCycles) / 1000000.0,
7412 ((double)m_maximum.m_totalCycles / countsPerSec) * 1000.0);
7413 fprintf(f, " avg: %10.3f Mcycles/%10.3f ms\n",
7414 ((double)m_total.m_totalCycles) / 1000000.0 / (double)m_numMethods, totTime_ms / (double)m_numMethods);
7416 const char* extraHdr1 = "";
7417 const char* extraHdr2 = "";
7418 #if MEASURE_CLRAPI_CALLS
7421 extraHdr1 = " CLRs/meth % in CLR";
7422 extraHdr2 = "-----------------------";
7426 fprintf(f, "\n Total time by phases:\n");
7427 fprintf(f, " PHASE inv/meth Mcycles time (ms) %% of total max (ms)%s\n",
7429 fprintf(f, " ---------------------------------------------------------------------------------------%s\n",
7432 // Ensure that at least the names array and the Phases enum have the same number of entries:
7433 assert(sizeof(PhaseNames) / sizeof(const char*) == PHASE_NUMBER_OF);
7434 for (int i = 0; i < PHASE_NUMBER_OF; i++)
7436 double phase_tot_ms = (((double)m_total.m_cyclesByPhase[i]) / countsPerSec) * 1000.0;
7437 double phase_max_ms = (((double)m_maximum.m_cyclesByPhase[i]) / countsPerSec) * 1000.0;
7438 double phase_tot_pct = 100.0 * phase_tot_ms / totTime_ms;
7440 #if MEASURE_CLRAPI_CALLS
7441 // Skip showing CLR API call info if we didn't collect any
7442 if (i == PHASE_CLR_API && !extraInfo)
7446 // Indent nested phases, according to depth.
7447 int ancPhase = PhaseParent[i];
7448 while (ancPhase != -1)
7451 ancPhase = PhaseParent[ancPhase];
7453 fprintf(f, " %-30s %6.2f %10.2f %9.3f %8.2f%% %8.3f", PhaseNames[i],
7454 ((double)m_total.m_invokesByPhase[i]) / ((double)m_numMethods),
7455 ((double)m_total.m_cyclesByPhase[i]) / 1000000.0, phase_tot_ms, (phase_tot_ms * 100.0 / totTime_ms),
7458 #if MEASURE_CLRAPI_CALLS
7459 if (extraInfo && i != PHASE_CLR_API)
7461 double nest_tot_ms = (((double)m_total.m_CLRcyclesByPhase[i]) / countsPerSec) * 1000.0;
7462 double nest_percent = nest_tot_ms * 100.0 / totTime_ms;
7463 double calls_per_fn = ((double)m_total.m_CLRinvokesByPhase[i]) / ((double)m_numMethods);
7465 if (nest_percent > 0.1 || calls_per_fn > 10)
7466 fprintf(f, " %5.1f %8.2f%%", calls_per_fn, nest_percent);
7472 // Show slop if it's over a certain percentage of the total
7473 double pslop_pct = 100.0 * m_total.m_parentPhaseEndSlop * 1000.0 / countsPerSec / totTime_ms;
7474 if (pslop_pct >= 1.0)
7476 fprintf(f, "\n 'End phase slop' should be very small (if not, there's unattributed time): %9.3f Mcycles = "
7477 "%3.1f%% of total.\n\n",
7478 m_total.m_parentPhaseEndSlop / 1000000.0, pslop_pct);
7481 if (m_numFilteredMethods > 0)
7483 fprintf(f, " Compiled %d methods that meet the filter requirement.\n", m_numFilteredMethods);
7484 fprintf(f, " Compiled %d bytecodes total (%8.2f avg).\n", m_filtered.m_byteCodeBytes,
7485 (double)m_filtered.m_byteCodeBytes / (double)m_numFilteredMethods);
7486 double totTime_ms = ((double)m_filtered.m_totalCycles / countsPerSec) * 1000.0;
7487 fprintf(f, " Time: total: %10.3f Mcycles/%10.3f ms\n", ((double)m_filtered.m_totalCycles / 1000000.0),
7489 fprintf(f, " avg: %10.3f Mcycles/%10.3f ms\n",
7490 ((double)m_filtered.m_totalCycles) / 1000000.0 / (double)m_numFilteredMethods,
7491 totTime_ms / (double)m_numFilteredMethods);
7493 fprintf(f, " Total time by phases:\n");
7494 fprintf(f, " PHASE inv/meth Mcycles time (ms) %% of total\n");
7495 fprintf(f, " --------------------------------------------------------------------------------------\n");
7496 // Ensure that at least the names array and the Phases enum have the same number of entries:
7497 assert(sizeof(PhaseNames) / sizeof(const char*) == PHASE_NUMBER_OF);
7498 for (int i = 0; i < PHASE_NUMBER_OF; i++)
7500 double phase_tot_ms = (((double)m_filtered.m_cyclesByPhase[i]) / countsPerSec) * 1000.0;
7501 // Indent nested phases, according to depth.
7502 int ancPhase = PhaseParent[i];
7503 while (ancPhase != -1)
7506 ancPhase = PhaseParent[ancPhase];
7508 fprintf(f, " %-30s %5.2f %10.2f %9.3f %8.2f%%\n", PhaseNames[i],
7509 ((double)m_filtered.m_invokesByPhase[i]) / ((double)m_numFilteredMethods),
7510 ((double)m_filtered.m_cyclesByPhase[i]) / 1000000.0, phase_tot_ms,
7511 (phase_tot_ms * 100.0 / totTime_ms));
7514 double fslop_ms = m_filtered.m_parentPhaseEndSlop * 1000.0 / countsPerSec;
7518 "\n 'End phase slop' should be very small (if not, there's unattributed time): %9.3f Mcycles.\n",
7519 m_filtered.m_parentPhaseEndSlop);
7523 #if MEASURE_CLRAPI_CALLS
7524 if (m_total.m_allClrAPIcalls > 0 && m_total.m_allClrAPIcycles > 0)
7527 if (m_totMethods > 0)
7528 fprintf(f, " Imported %u methods.\n\n", m_numMethods + m_totMethods);
7530 fprintf(f, " CLR API # calls total time max time avg time %% "
7532 fprintf(f, " -------------------------------------------------------------------------------");
7533 fprintf(f, "---------------------\n");
7535 static const char* APInames[] = {
7536 #define DEF_CLR_API(name) #name,
7537 #include "ICorJitInfo_API_names.h"
7540 unsigned shownCalls = 0;
7541 double shownMillis = 0.0;
7543 unsigned checkedCalls = 0;
7544 double checkedMillis = 0.0;
7547 for (unsigned pass = 0; pass < 2; pass++)
7549 for (unsigned i = 0; i < API_ICorJitInfo_Names::API_COUNT; i++)
7551 unsigned calls = m_total.m_perClrAPIcalls[i];
7555 unsigned __int64 cycles = m_total.m_perClrAPIcycles[i];
7556 double millis = 1000.0 * cycles / countsPerSec;
7558 // Don't show the small fry to keep the results manageable
7561 // We always show the following API because it is always called
7562 // exactly once for each method and its body is the simplest one
7563 // possible (it just returns an integer constant), and therefore
7564 // it can be used to measure the overhead of adding the CLR API
7565 // timing code. Roughly speaking, on a 3GHz x64 box the overhead
7566 // per call should be around 40 ns when using RDTSC, compared to
7567 // about 140 ns when using GetThreadCycles() under Windows.
7568 if (i != API_ICorJitInfo_Names::API_getExpectedTargetArchitecture)
7572 // In the first pass we just compute the totals.
7575 shownCalls += m_total.m_perClrAPIcalls[i];
7576 shownMillis += millis;
7580 unsigned __int32 maxcyc = m_maximum.m_maxClrAPIcycles[i];
7581 double max_ms = 1000.0 * maxcyc / countsPerSec;
7583 fprintf(f, " %-40s", APInames[i]); // API name
7584 fprintf(f, " %8u %9.1f ms", calls, millis); // #calls, total time
7585 fprintf(f, " %8.1f ms %8.1f ns", max_ms, 1000000.0 * millis / calls); // max, avg time
7586 fprintf(f, " %5.1f%%\n", 100.0 * millis / shownMillis); // % of total
7589 checkedCalls += m_total.m_perClrAPIcalls[i];
7590 checkedMillis += millis;
7596 assert(checkedCalls == shownCalls);
7597 assert(checkedMillis == shownMillis);
7600 if (shownCalls > 0 || shownMillis > 0)
7602 fprintf(f, " -------------------------");
7603 fprintf(f, "---------------------------------------------------------------------------\n");
7604 fprintf(f, " Total for calls shown above %8u %10.1f ms", shownCalls, shownMillis);
7605 if (totTime_ms > 0.0)
7606 fprintf(f, " (%4.1lf%% of overall JIT time)", shownMillis * 100.0 / totTime_ms);
7616 JitTimer::JitTimer(unsigned byteCodeSize) : m_info(byteCodeSize)
7618 #if MEASURE_CLRAPI_CALLS
7619 m_CLRcallInvokes = 0;
7620 m_CLRcallCycles = 0;
7624 m_lastPhase = (Phases)-1;
7625 #if MEASURE_CLRAPI_CALLS
7626 m_CLRcallAPInum = -1;
7630 unsigned __int64 threadCurCycles;
7631 if (_our_GetThreadCycles(&threadCurCycles))
7633 m_start = threadCurCycles;
7634 m_curPhaseStart = threadCurCycles;
7638 void JitTimer::EndPhase(Phases phase)
7641 // We re-run some phases currently, so this following assert doesn't work.
7642 // assert((int)phase > (int)m_lastPhase); // We should end phases in increasing order.
7644 unsigned __int64 threadCurCycles;
7645 if (_our_GetThreadCycles(&threadCurCycles))
7647 unsigned __int64 phaseCycles = (threadCurCycles - m_curPhaseStart);
7649 // If this is not a leaf phase, the assumption is that the last subphase must have just recently ended.
7650 // Credit the duration to "slop", the total of which should be very small.
7651 if (PhaseHasChildren[phase])
7653 m_info.m_parentPhaseEndSlop += phaseCycles;
7657 // It is a leaf phase. Credit duration to it.
7658 m_info.m_invokesByPhase[phase]++;
7659 m_info.m_cyclesByPhase[phase] += phaseCycles;
7661 #if MEASURE_CLRAPI_CALLS
7662 // Record the CLR API timing info as well.
7663 m_info.m_CLRinvokesByPhase[phase] += m_CLRcallInvokes;
7664 m_info.m_CLRcyclesByPhase[phase] += m_CLRcallCycles;
7667 // Credit the phase's ancestors, if any.
7668 int ancPhase = PhaseParent[phase];
7669 while (ancPhase != -1)
7671 m_info.m_cyclesByPhase[ancPhase] += phaseCycles;
7672 ancPhase = PhaseParent[ancPhase];
7675 #if MEASURE_CLRAPI_CALLS
7676 const Phases lastPhase = PHASE_CLR_API;
7678 const Phases lastPhase = PHASE_NUMBER_OF;
7680 if (phase + 1 == lastPhase)
7682 m_info.m_totalCycles = (threadCurCycles - m_start);
7686 m_curPhaseStart = threadCurCycles;
7692 m_lastPhase = phase;
7694 #if MEASURE_CLRAPI_CALLS
7695 m_CLRcallInvokes = 0;
7696 m_CLRcallCycles = 0;
7700 #if MEASURE_CLRAPI_CALLS
7702 //------------------------------------------------------------------------
7703 // JitTimer::CLRApiCallEnter: Start the stopwatch for an EE call.
7706 // apix - The API index - an "enum API_ICorJitInfo_Names" value.
7709 void JitTimer::CLRApiCallEnter(unsigned apix)
7711 assert(m_CLRcallAPInum == -1); // Nested calls not allowed
7712 m_CLRcallAPInum = apix;
7714 // If we can't get the cycles, we'll just ignore this call
7715 if (!_our_GetThreadCycles(&m_CLRcallStart))
7719 //------------------------------------------------------------------------
7720 // JitTimer::CLRApiCallLeave: compute / record time spent in an EE call.
7723 // apix - The API's "enum API_ICorJitInfo_Names" value; this value
7724 // should match the value passed to the most recent call to
7725 // "CLRApiCallEnter" (i.e. these must come as matched pairs),
7726 // and they also may not nest.
7729 void JitTimer::CLRApiCallLeave(unsigned apix)
7731 // Make sure we're actually inside a measured CLR call.
7732 assert(m_CLRcallAPInum != -1);
7733 m_CLRcallAPInum = -1;
7735 // Ignore this one if we don't have a valid starting counter.
7736 if (m_CLRcallStart != 0)
7738 if (JitConfig.JitEECallTimingInfo() != 0)
7740 unsigned __int64 threadCurCycles;
7741 if (_our_GetThreadCycles(&threadCurCycles))
7743 // Compute the cycles spent in the call.
7744 threadCurCycles -= m_CLRcallStart;
7746 // Add the cycles to the 'phase' and bump its use count.
7747 m_info.m_cyclesByPhase[PHASE_CLR_API] += threadCurCycles;
7748 m_info.m_invokesByPhase[PHASE_CLR_API] += 1;
7750 // Add the values to the "per API" info.
7751 m_info.m_allClrAPIcycles += threadCurCycles;
7752 m_info.m_allClrAPIcalls += 1;
7754 m_info.m_perClrAPIcalls[apix] += 1;
7755 m_info.m_perClrAPIcycles[apix] += threadCurCycles;
7756 m_info.m_maxClrAPIcycles[apix] = max(m_info.m_maxClrAPIcycles[apix], (unsigned __int32)threadCurCycles);
7758 // Subtract the cycles from the enclosing phase by bumping its start time
7759 m_curPhaseStart += threadCurCycles;
7761 // Update the running totals.
7762 m_CLRcallInvokes += 1;
7763 m_CLRcallCycles += threadCurCycles;
7770 assert(m_CLRcallAPInum != -1); // No longer in this API call.
7771 m_CLRcallAPInum = -1;
7774 #endif // MEASURE_CLRAPI_CALLS
7776 CritSecObject JitTimer::s_csvLock;
7778 LPCWSTR Compiler::JitTimeLogCsv()
7780 LPCWSTR jitTimeLogCsv = JitConfig.JitTimeLogCsv();
7781 return jitTimeLogCsv;
7784 void JitTimer::PrintCsvHeader()
7786 LPCWSTR jitTimeLogCsv = Compiler::JitTimeLogCsv();
7787 if (jitTimeLogCsv == nullptr)
7792 CritSecHolder csvLock(s_csvLock);
7794 FILE* fp = _wfopen(jitTimeLogCsv, W("a"));
7797 // Write the header if the file is empty
7800 fprintf(fp, "\"Method Name\",");
7801 fprintf(fp, "\"Method Index\",");
7802 fprintf(fp, "\"IL Bytes\",");
7803 fprintf(fp, "\"Basic Blocks\",");
7804 fprintf(fp, "\"Opt Level\",");
7805 fprintf(fp, "\"Loops Cloned\",");
7807 for (int i = 0; i < PHASE_NUMBER_OF; i++)
7809 fprintf(fp, "\"%s\",", PhaseNames[i]);
7812 InlineStrategy::DumpCsvHeader(fp);
7814 fprintf(fp, "\"Total Cycles\",");
7815 fprintf(fp, "\"CPS\"\n");
7821 extern ICorJitHost* g_jitHost;
7823 void JitTimer::PrintCsvMethodStats(Compiler* comp)
7825 LPCWSTR jitTimeLogCsv = Compiler::JitTimeLogCsv();
7826 if (jitTimeLogCsv == nullptr)
7831 // eeGetMethodFullName uses locks, so don't enter crit sec before this call.
7832 const char* methName = comp->eeGetMethodFullName(comp->info.compMethodHnd);
7834 // Try and access the SPMI index to report in the data set.
7836 // If the jit is not hosted under SPMI this will return the
7837 // default value of zero.
7839 // Query the jit host directly here instead of going via the
7840 // config cache, since value will change for each method.
7841 int index = g_jitHost->getIntConfigValue(W("SuperPMIMethodContextNumber"), 0);
7843 CritSecHolder csvLock(s_csvLock);
7845 FILE* fp = _wfopen(jitTimeLogCsv, W("a"));
7846 fprintf(fp, "\"%s\",", methName);
7847 fprintf(fp, "%d,", index);
7848 fprintf(fp, "%u,", comp->info.compILCodeSize);
7849 fprintf(fp, "%u,", comp->fgBBcount);
7850 fprintf(fp, "%u,", comp->opts.MinOpts());
7851 fprintf(fp, "%u,", comp->optLoopsCloned);
7852 unsigned __int64 totCycles = 0;
7853 for (int i = 0; i < PHASE_NUMBER_OF; i++)
7855 if (!PhaseHasChildren[i])
7857 totCycles += m_info.m_cyclesByPhase[i];
7859 fprintf(fp, "%I64u,", m_info.m_cyclesByPhase[i]);
7862 comp->m_inlineStrategy->DumpCsvData(fp);
7864 fprintf(fp, "%I64u,", m_info.m_totalCycles);
7865 fprintf(fp, "%f\n", CycleTimer::CyclesPerSecond());
7869 // Completes the timing of the current method, and adds it to "sum".
7870 void JitTimer::Terminate(Compiler* comp, CompTimeSummaryInfo& sum, bool includePhases)
7874 PrintCsvMethodStats(comp);
7877 sum.AddInfo(m_info, includePhases);
7879 #endif // FEATURE_JIT_METHOD_PERF
7881 #if MEASURE_MEM_ALLOC
7883 CritSecObject Compiler::s_memStatsLock; // Default constructor.
7884 Compiler::AggregateMemStats Compiler::s_aggMemStats; // Default constructor.
7885 Compiler::MemStats Compiler::s_maxCompMemStats; // Default constructor.
7887 const char* Compiler::MemStats::s_CompMemKindNames[] = {
7888 #define CompMemKindMacro(kind) #kind,
7889 #include "compmemkind.h"
7892 void Compiler::MemStats::Print(FILE* f)
7894 fprintf(f, "count: %10u, size: %10llu, max = %10llu\n", allocCnt, allocSz, allocSzMax);
7895 fprintf(f, "allocateMemory: %10llu, nraUsed: %10llu\n", nraTotalSizeAlloc, nraTotalSizeUsed);
7899 void Compiler::MemStats::PrintByKind(FILE* f)
7901 fprintf(f, "\nAlloc'd bytes by kind:\n %20s | %10s | %7s\n", "kind", "size", "pct");
7902 fprintf(f, " %20s-+-%10s-+-%7s\n", "--------------------", "----------", "-------");
7903 float allocSzF = static_cast<float>(allocSz);
7904 for (int cmk = 0; cmk < CMK_Count; cmk++)
7906 float pct = 100.0f * static_cast<float>(allocSzByKind[cmk]) / allocSzF;
7907 fprintf(f, " %20s | %10llu | %6.2f%%\n", s_CompMemKindNames[cmk], allocSzByKind[cmk], pct);
7912 void Compiler::AggregateMemStats::Print(FILE* f)
7914 fprintf(f, "For %9u methods:\n", nMethods);
7919 fprintf(f, " count: %12u (avg %7u per method)\n", allocCnt, allocCnt / nMethods);
7920 fprintf(f, " alloc size : %12llu (avg %7llu per method)\n", allocSz, allocSz / nMethods);
7921 fprintf(f, " max alloc : %12llu\n", allocSzMax);
7923 fprintf(f, " allocateMemory : %12llu (avg %7llu per method)\n", nraTotalSizeAlloc, nraTotalSizeAlloc / nMethods);
7924 fprintf(f, " nraUsed : %12llu (avg %7llu per method)\n", nraTotalSizeUsed, nraTotalSizeUsed / nMethods);
7927 #endif // MEASURE_MEM_ALLOC
7929 #if LOOP_HOIST_STATS
7931 CritSecObject Compiler::s_loopHoistStatsLock; // Default constructor.
7932 unsigned Compiler::s_loopsConsidered = 0;
7933 unsigned Compiler::s_loopsWithHoistedExpressions = 0;
7934 unsigned Compiler::s_totalHoistedExpressions = 0;
7937 void Compiler::PrintAggregateLoopHoistStats(FILE* f)
7940 fprintf(f, "---------------------------------------------------\n");
7941 fprintf(f, "Loop hoisting stats\n");
7942 fprintf(f, "---------------------------------------------------\n");
7944 double pctWithHoisted = 0.0;
7945 if (s_loopsConsidered > 0)
7947 pctWithHoisted = 100.0 * (double(s_loopsWithHoistedExpressions) / double(s_loopsConsidered));
7949 double exprsPerLoopWithExpr = 0.0;
7950 if (s_loopsWithHoistedExpressions > 0)
7952 exprsPerLoopWithExpr = double(s_totalHoistedExpressions) / double(s_loopsWithHoistedExpressions);
7954 fprintf(f, "Considered %d loops. Of these, we hoisted expressions out of %d (%6.2f%%).\n", s_loopsConsidered,
7955 s_loopsWithHoistedExpressions, pctWithHoisted);
7956 fprintf(f, " A total of %d expressions were hoisted, an average of %5.2f per loop-with-hoisted-expr.\n",
7957 s_totalHoistedExpressions, exprsPerLoopWithExpr);
7960 void Compiler::AddLoopHoistStats()
7962 CritSecHolder statsLock(s_loopHoistStatsLock);
7964 s_loopsConsidered += m_loopsConsidered;
7965 s_loopsWithHoistedExpressions += m_loopsWithHoistedExpressions;
7966 s_totalHoistedExpressions += m_totalHoistedExpressions;
7969 void Compiler::PrintPerMethodLoopHoistStats()
7971 double pctWithHoisted = 0.0;
7972 if (m_loopsConsidered > 0)
7974 pctWithHoisted = 100.0 * (double(m_loopsWithHoistedExpressions) / double(m_loopsConsidered));
7976 double exprsPerLoopWithExpr = 0.0;
7977 if (m_loopsWithHoistedExpressions > 0)
7979 exprsPerLoopWithExpr = double(m_totalHoistedExpressions) / double(m_loopsWithHoistedExpressions);
7981 printf("Considered %d loops. Of these, we hoisted expressions out of %d (%5.2f%%).\n", m_loopsConsidered,
7982 m_loopsWithHoistedExpressions, pctWithHoisted);
7983 printf(" A total of %d expressions were hoisted, an average of %5.2f per loop-with-hoisted-expr.\n",
7984 m_totalHoistedExpressions, exprsPerLoopWithExpr);
7986 #endif // LOOP_HOIST_STATS
7988 //------------------------------------------------------------------------
7989 // RecordStateAtEndOfInlining: capture timing data (if enabled) after
7990 // inlining as completed.
7993 // Records data needed for SQM and inlining data dumps. Should be
7994 // called after inlining is complete. (We do this after inlining
7995 // because this marks the last point at which the JIT is likely to
7996 // cause type-loading and class initialization).
7998 void Compiler::RecordStateAtEndOfInlining()
8000 #if defined(DEBUG) || defined(INLINE_DATA) || defined(FEATURE_CLRSQM)
8002 m_compCyclesAtEndOfInlining = 0;
8003 m_compTickCountAtEndOfInlining = 0;
8004 bool b = CycleTimer::GetThreadCyclesS(&m_compCyclesAtEndOfInlining);
8007 return; // We don't have a thread cycle counter.
8009 m_compTickCountAtEndOfInlining = GetTickCount();
8011 #endif // defined(DEBUG) || defined(INLINE_DATA) || defined(FEATURE_CLRSQM)
8014 //------------------------------------------------------------------------
8015 // RecordStateAtEndOfCompilation: capture timing data (if enabled) after
8016 // compilation is completed.
8018 void Compiler::RecordStateAtEndOfCompilation()
8020 #if defined(DEBUG) || defined(INLINE_DATA) || defined(FEATURE_CLRSQM)
8024 unsigned __int64 compCyclesAtEnd;
8025 bool b = CycleTimer::GetThreadCyclesS(&compCyclesAtEnd);
8028 return; // We don't have a thread cycle counter.
8030 assert(compCyclesAtEnd >= m_compCyclesAtEndOfInlining);
8032 m_compCycles = compCyclesAtEnd - m_compCyclesAtEndOfInlining;
8034 #endif // defined(DEBUG) || defined(INLINE_DATA) || defined(FEATURE_CLRSQM)
8036 #ifdef FEATURE_CLRSQM
8039 unsigned __int64 mcycles64 = m_compCycles / ((unsigned __int64)1000000);
8041 if (mcycles64 > UINT32_MAX)
8043 mcycles = UINT32_MAX;
8047 mcycles = (unsigned)mcycles64;
8050 DWORD ticksAtEnd = GetTickCount();
8051 assert(ticksAtEnd >= m_compTickCountAtEndOfInlining);
8052 DWORD compTicks = ticksAtEnd - m_compTickCountAtEndOfInlining;
8054 if (mcycles >= 1000)
8056 info.compCompHnd->logSQMLongJitEvent(mcycles, compTicks, info.compILCodeSize, fgBBcount, opts.MinOpts(),
8057 info.compMethodHnd);
8060 #endif // FEATURE_CLRSQM
8063 #if FUNC_INFO_LOGGING
8065 LPCWSTR Compiler::compJitFuncInfoFilename = nullptr;
8068 FILE* Compiler::compJitFuncInfoFile = nullptr;
8069 #endif // FUNC_INFO_LOGGING
8073 // dumpConvertedVarSet() is just like dumpVarSet(), except we assume the varset bits are tracked
8074 // variable indices, and we convert them to variable numbers, sort the variable numbers, and
8075 // print them as variable numbers. To do this, we use a temporary set indexed by
8076 // variable number. We can't use the "all varset" type because it is still size-limited, and might
8077 // not be big enough to handle all possible variable numbers.
8078 void dumpConvertedVarSet(Compiler* comp, VARSET_VALARG_TP vars)
8080 BYTE* pVarNumSet; // trivial set: one byte per varNum, 0 means not in set, 1 means in set.
8082 size_t varNumSetBytes = comp->lvaCount * sizeof(BYTE);
8083 pVarNumSet = (BYTE*)_alloca(varNumSetBytes);
8084 memset(pVarNumSet, 0, varNumSetBytes); // empty the set
8086 VARSET_ITER_INIT(comp, iter, vars, varIndex);
8087 while (iter.NextElem(comp, &varIndex))
8089 unsigned varNum = comp->lvaTrackedToVarNum[varIndex];
8090 assert(varNum < comp->lvaCount);
8091 pVarNumSet[varNum] = 1; // This varNum is in the set
8096 for (size_t varNum = 0; varNum < comp->lvaCount; varNum++)
8098 if (pVarNumSet[varNum] == 1)
8104 printf("V%02u", varNum);
8111 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8112 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8114 XX Debugging helpers XX
8116 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8117 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8120 /*****************************************************************************/
8121 /* The following functions are intended to be called from the debugger, to dump
8122 * various data structures.
8124 * The versions that start with 'c' take a Compiler* as the first argument.
8125 * The versions that start with 'd' use the tlsCompiler, so don't require a Compiler*.
8128 * cBlock, dBlock : Display a basic block (call fgDispBasicBlock()).
8129 * cBlocks, dBlocks : Display all the basic blocks of a function (call fgDispBasicBlocks()).
8130 * cBlocksV, dBlocksV : Display all the basic blocks of a function (call fgDispBasicBlocks(true)).
8131 * "V" means "verbose", and will dump all the trees.
8132 * cTree, dTree : Display a tree (call gtDispTree()).
8133 * cTrees, dTrees : Display all the trees in a function (call fgDumpTrees()).
8134 * cEH, dEH : Display the EH handler table (call fgDispHandlerTab()).
8135 * cVar, dVar : Display a local variable given its number (call lvaDumpEntry()).
8136 * cVarDsc, dVarDsc : Display a local variable given a LclVarDsc* (call lvaDumpEntry()).
8137 * cVars, dVars : Display the local variable table (call lvaTableDump()).
8138 * cVarsFinal, dVarsFinal : Display the local variable table (call lvaTableDump(FINAL_FRAME_LAYOUT)).
8139 * cBlockCheapPreds, dBlockCheapPreds : Display a block's cheap predecessors (call block->dspCheapPreds()).
8140 * cBlockPreds, dBlockPreds : Display a block's predecessors (call block->dspPreds()).
8141 * cBlockSuccs, dBlockSuccs : Display a block's successors (call block->dspSuccs(compiler)).
8142 * cReach, dReach : Display all block reachability (call fgDispReach()).
8143 * cDoms, dDoms : Display all block dominators (call fgDispDoms()).
8144 * cLiveness, dLiveness : Display per-block variable liveness (call fgDispBBLiveness()).
8145 * cCVarSet, dCVarSet : Display a "converted" VARSET_TP: the varset is assumed to be tracked variable
8146 * indices. These are converted to variable numbers and sorted. (Calls
8147 * dumpConvertedVarSet()).
8149 * cFuncIR, dFuncIR : Display all the basic blocks of a function in linear IR form.
8150 * cLoopIR, dLoopIR : Display a loop in linear IR form.
8151 * dLoopNumIR : Display a loop (given number) in linear IR form.
8152 * cBlockIR, dBlockIR : Display a basic block in linear IR form.
8153 * cTreeIR, dTreeIR : Display a tree in linear IR form.
8154 * dTabStopIR : Display spaces to the next tab stop column
8155 * cTreeTypeIR dTreeTypeIR : Display tree type
8156 * cTreeKindsIR dTreeKindsIR : Display tree kinds
8157 * cTreeFlagsIR dTreeFlagsIR : Display tree flags
8158 * cOperandIR dOperandIR : Display tree operand
8159 * cLeafIR dLeafIR : Display tree leaf
8160 * cIndirIR dIndirIR : Display indir tree as [t#] or [leaf]
8161 * cListIR dListIR : Display tree list
8162 * cSsaNumIR dSsaNumIR : Display SSA number as <u|d:#>
8163 * cValNumIR dValNumIR : Display Value number as <v{l|c}:#{,R}>
8164 * cDependsIR : Display dependencies of a tree DEP(t# ...) node
8165 * based on child comma tree nodes
8166 * dFormatIR : Display dump format specified on command line
8169 * The following don't require a Compiler* to work:
8170 * dVarSet : Display a VARSET_TP (call dumpVarSet()).
8171 * dRegMask : Display a regMaskTP (call dspRegMask(mask)).
8174 void cBlock(Compiler* comp, BasicBlock* block)
8176 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8177 printf("===================================================================== *Block %u\n", sequenceNumber++);
8178 comp->fgTableDispBasicBlock(block);
8181 void cBlocks(Compiler* comp)
8183 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8184 printf("===================================================================== *Blocks %u\n", sequenceNumber++);
8185 comp->fgDispBasicBlocks();
8188 void cBlocksV(Compiler* comp)
8190 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8191 printf("===================================================================== *BlocksV %u\n", sequenceNumber++);
8192 comp->fgDispBasicBlocks(true);
8195 void cTree(Compiler* comp, GenTree* tree)
8197 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8198 printf("===================================================================== *Tree %u\n", sequenceNumber++);
8199 comp->gtDispTree(tree, nullptr, ">>>");
8202 void cTrees(Compiler* comp)
8204 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8205 printf("===================================================================== *Trees %u\n", sequenceNumber++);
8206 comp->fgDumpTrees(comp->fgFirstBB, nullptr);
8209 void cEH(Compiler* comp)
8211 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8212 printf("===================================================================== *EH %u\n", sequenceNumber++);
8213 comp->fgDispHandlerTab();
8216 void cVar(Compiler* comp, unsigned lclNum)
8218 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8219 printf("===================================================================== *Var %u\n", sequenceNumber++);
8220 comp->lvaDumpEntry(lclNum, Compiler::FINAL_FRAME_LAYOUT);
8223 void cVarDsc(Compiler* comp, LclVarDsc* varDsc)
8225 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8226 printf("===================================================================== *VarDsc %u\n", sequenceNumber++);
8227 unsigned lclNum = (unsigned)(varDsc - comp->lvaTable);
8228 comp->lvaDumpEntry(lclNum, Compiler::FINAL_FRAME_LAYOUT);
8231 void cVars(Compiler* comp)
8233 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8234 printf("===================================================================== *Vars %u\n", sequenceNumber++);
8235 comp->lvaTableDump();
8238 void cVarsFinal(Compiler* comp)
8240 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8241 printf("===================================================================== *Vars %u\n", sequenceNumber++);
8242 comp->lvaTableDump(Compiler::FINAL_FRAME_LAYOUT);
8245 void cBlockCheapPreds(Compiler* comp, BasicBlock* block)
8247 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8248 printf("===================================================================== *BlockCheapPreds %u\n",
8250 block->dspCheapPreds();
8253 void cBlockPreds(Compiler* comp, BasicBlock* block)
8255 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8256 printf("===================================================================== *BlockPreds %u\n", sequenceNumber++);
8260 void cBlockSuccs(Compiler* comp, BasicBlock* block)
8262 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8263 printf("===================================================================== *BlockSuccs %u\n", sequenceNumber++);
8264 block->dspSuccs(comp);
8267 void cReach(Compiler* comp)
8269 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8270 printf("===================================================================== *Reach %u\n", sequenceNumber++);
8271 comp->fgDispReach();
8274 void cDoms(Compiler* comp)
8276 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8277 printf("===================================================================== *Doms %u\n", sequenceNumber++);
8281 void cLiveness(Compiler* comp)
8283 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8284 printf("===================================================================== *Liveness %u\n", sequenceNumber++);
8285 comp->fgDispBBLiveness();
8288 void cCVarSet(Compiler* comp, VARSET_VALARG_TP vars)
8290 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8291 printf("===================================================================== dCVarSet %u\n", sequenceNumber++);
8292 dumpConvertedVarSet(comp, vars);
8293 printf("\n"); // dumpConvertedVarSet() doesn't emit a trailing newline
8296 void dBlock(BasicBlock* block)
8298 cBlock(JitTls::GetCompiler(), block);
8303 cBlocks(JitTls::GetCompiler());
8308 cBlocksV(JitTls::GetCompiler());
8311 void dTree(GenTree* tree)
8313 cTree(JitTls::GetCompiler(), tree);
8318 cTrees(JitTls::GetCompiler());
8323 cEH(JitTls::GetCompiler());
8326 void dVar(unsigned lclNum)
8328 cVar(JitTls::GetCompiler(), lclNum);
8331 void dVarDsc(LclVarDsc* varDsc)
8333 cVarDsc(JitTls::GetCompiler(), varDsc);
8338 cVars(JitTls::GetCompiler());
8343 cVarsFinal(JitTls::GetCompiler());
8346 void dBlockPreds(BasicBlock* block)
8348 cBlockPreds(JitTls::GetCompiler(), block);
8351 void dBlockCheapPreds(BasicBlock* block)
8353 cBlockCheapPreds(JitTls::GetCompiler(), block);
8356 void dBlockSuccs(BasicBlock* block)
8358 cBlockSuccs(JitTls::GetCompiler(), block);
8363 cReach(JitTls::GetCompiler());
8368 cDoms(JitTls::GetCompiler());
8373 cLiveness(JitTls::GetCompiler());
8376 void dCVarSet(VARSET_VALARG_TP vars)
8378 cCVarSet(JitTls::GetCompiler(), vars);
8381 void dRegMask(regMaskTP mask)
8383 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8384 printf("===================================================================== dRegMask %u\n", sequenceNumber++);
8386 printf("\n"); // dspRegMask() doesn't emit a trailing newline
8389 void dBlockList(BasicBlockList* list)
8391 printf("WorkList: ");
8392 while (list != nullptr)
8394 printf("BB%02u ", list->block->bbNum);
8400 // Global variables available in debug mode. That are set by debug APIs for finding
8401 // Trees, Stmts, and/or Blocks using id or bbNum.
8402 // That can be used in watch window or as a way to get address of fields for data break points.
8405 GenTreeStmt* dbStmt;
8406 BasicBlock* dbTreeBlock;
8407 BasicBlock* dbBlock;
8409 // Debug APIs for finding Trees, Stmts, and/or Blocks.
8410 // As a side effect, they set the debug variables above.
8412 GenTree* dFindTree(GenTree* tree, unsigned id)
8416 if (tree == nullptr)
8421 if (tree->gtTreeID == id)
8427 unsigned childCount = tree->NumChildren();
8428 for (unsigned childIndex = 0; childIndex < childCount; childIndex++)
8430 child = tree->GetChild(childIndex);
8431 child = dFindTree(child, id);
8432 if (child != nullptr)
8441 GenTree* dFindTree(unsigned id)
8443 Compiler* comp = JitTls::GetCompiler();
8447 dbTreeBlock = nullptr;
8450 for (block = comp->fgFirstBB; block != nullptr; block = block->bbNext)
8452 for (GenTreeStmt* stmt = block->firstStmt(); stmt; stmt = stmt->gtNextStmt)
8454 tree = dFindTree(stmt, id);
8455 if (tree != nullptr)
8457 dbTreeBlock = block;
8466 GenTreeStmt* dFindStmt(unsigned id)
8468 Compiler* comp = JitTls::GetCompiler();
8473 unsigned stmtId = 0;
8474 for (block = comp->fgFirstBB; block != nullptr; block = block->bbNext)
8476 for (GenTreeStmt* stmt = block->firstStmt(); stmt; stmt = stmt->gtNextStmt)
8490 BasicBlock* dFindBlock(unsigned bbNum)
8492 Compiler* comp = JitTls::GetCompiler();
8493 BasicBlock* block = nullptr;
8496 for (block = comp->fgFirstBB; block != nullptr; block = block->bbNext)
8498 if (block->bbNum == bbNum)
8508 /*****************************************************************************
8510 * COMPlus_JitDumpIR support - dump out function in linear IR form
8513 void cFuncIR(Compiler* comp)
8517 printf("Method %s::%s, hsh=0x%x\n", comp->info.compClassName, comp->info.compMethodName,
8518 comp->info.compMethodHash());
8522 for (block = comp->fgFirstBB; block != nullptr; block = block->bbNext)
8524 cBlockIR(comp, block);
8528 /*****************************************************************************
8530 * COMPlus_JitDumpIR support - dump out the format specifiers from COMPlus_JitDumpIRFormat
8535 Compiler* comp = JitTls::GetCompiler();
8537 if (comp->dumpIRFormat != nullptr)
8539 printf("COMPlus_JitDumpIRFormat=%ls", comp->dumpIRFormat);
8543 /*****************************************************************************
8545 * COMPlus_JitDumpIR support - dump out function in linear IR form
8550 cFuncIR(JitTls::GetCompiler());
8553 /*****************************************************************************
8555 * COMPlus_JitDumpIR support - dump out loop in linear IR form
8558 void cLoopIR(Compiler* comp, Compiler::LoopDsc* loop)
8560 BasicBlock* blockHead = loop->lpHead;
8561 BasicBlock* blockFirst = loop->lpFirst;
8562 BasicBlock* blockTop = loop->lpTop;
8563 BasicBlock* blockEntry = loop->lpEntry;
8564 BasicBlock* blockBottom = loop->lpBottom;
8565 BasicBlock* blockExit = loop->lpExit;
8566 BasicBlock* blockLast = blockBottom->bbNext;
8571 printf("HEAD BB%02u\n", blockHead->bbNum);
8572 printf("FIRST BB%02u\n", blockFirst->bbNum);
8573 printf("TOP BB%02u\n", blockTop->bbNum);
8574 printf("ENTRY BB%02u\n", blockEntry->bbNum);
8575 if (loop->lpExitCnt == 1)
8577 printf("EXIT BB%02u\n", blockExit->bbNum);
8581 printf("EXITS %u", loop->lpExitCnt);
8583 printf("BOTTOM BB%02u\n", blockBottom->bbNum);
8586 cBlockIR(comp, blockHead);
8587 for (block = blockFirst; ((block != nullptr) && (block != blockLast)); block = block->bbNext)
8589 cBlockIR(comp, block);
8593 /*****************************************************************************
8595 * COMPlus_JitDumpIR support - dump out loop in linear IR form
8598 void dLoopIR(Compiler::LoopDsc* loop)
8600 cLoopIR(JitTls::GetCompiler(), loop);
8603 /*****************************************************************************
8605 * COMPlus_JitDumpIR support - dump out loop (given loop number) in linear IR form
8608 void dLoopNumIR(unsigned loopNum)
8610 Compiler* comp = JitTls::GetCompiler();
8612 if (loopNum >= comp->optLoopCount)
8614 printf("loopNum %u out of range\n");
8618 Compiler::LoopDsc* loop = &comp->optLoopTable[loopNum];
8619 cLoopIR(JitTls::GetCompiler(), loop);
8622 /*****************************************************************************
8624 * COMPlus_JitDumpIR support - dump spaces to specified tab stop
8627 int dTabStopIR(int curr, int tabstop)
8631 if (tabstop <= curr)
8633 chars += printf(" ");
8636 for (int i = curr; i < tabstop; i++)
8638 chars += printf(" ");
8644 void cNodeIR(Compiler* comp, GenTree* tree);
8646 /*****************************************************************************
8648 * COMPlus_JitDumpIR support - dump out block in linear IR form
8651 void cBlockIR(Compiler* comp, BasicBlock* block)
8653 bool noStmts = comp->dumpIRNoStmts;
8654 bool trees = comp->dumpIRTrees;
8656 if (comp->dumpIRBlockHeaders)
8658 block->dspBlockHeader(comp);
8662 printf("BB%02u:\n", block->bbNum);
8667 if (!block->IsLIR())
8669 for (GenTreeStmt* stmt = block->firstStmt(); stmt; stmt = stmt->gtNextStmt)
8671 // Print current stmt.
8677 printf("=====================================================================\n");
8680 if (comp->compRationalIRForm)
8684 foreach_treenode_execution_order(tree, stmt)
8686 cNodeIR(comp, tree);
8691 cTreeIR(comp, stmt);
8694 if (!noStmts && !trees)
8702 for (GenTree* node = block->bbTreeList; node != nullptr; node = node->gtNext)
8704 cNodeIR(comp, node);
8710 chars += dTabStopIR(chars, COLUMN_OPCODE);
8712 chars += printf(" ");
8713 switch (block->bbJumpKind)
8715 case BBJ_EHFINALLYRET:
8716 chars += printf("BRANCH(EHFINALLYRET)");
8719 case BBJ_EHFILTERRET:
8720 chars += printf("BRANCH(EHFILTERRET)");
8723 case BBJ_EHCATCHRET:
8724 chars += printf("BRANCH(EHCATCHRETURN)");
8725 chars += dTabStopIR(chars, COLUMN_OPERANDS);
8726 chars += printf(" BB%02u", block->bbJumpDest->bbNum);
8730 chars += printf("BRANCH(THROW)");
8734 chars += printf("BRANCH(RETURN)");
8738 // For fall-through blocks
8739 chars += printf("BRANCH(NONE)");
8743 chars += printf("BRANCH(ALWAYS)");
8744 chars += dTabStopIR(chars, COLUMN_OPERANDS);
8745 chars += printf(" BB%02u", block->bbJumpDest->bbNum);
8746 if (block->bbFlags & BBF_KEEP_BBJ_ALWAYS)
8748 chars += dTabStopIR(chars, COLUMN_KINDS);
8749 chars += printf("; [KEEP_BBJ_ALWAYS]");
8754 chars += printf("BRANCH(LEAVE)");
8755 chars += dTabStopIR(chars, COLUMN_OPERANDS);
8756 chars += printf(" BB%02u", block->bbJumpDest->bbNum);
8759 case BBJ_CALLFINALLY:
8760 chars += printf("BRANCH(CALLFINALLY)");
8761 chars += dTabStopIR(chars, COLUMN_OPERANDS);
8762 chars += printf(" BB%02u", block->bbJumpDest->bbNum);
8766 chars += printf("BRANCH(COND)");
8767 chars += dTabStopIR(chars, COLUMN_OPERANDS);
8768 chars += printf(" BB%02u", block->bbJumpDest->bbNum);
8772 chars += printf("BRANCH(SWITCH)");
8773 chars += dTabStopIR(chars, COLUMN_OPERANDS);
8776 jumpCnt = block->bbJumpSwt->bbsCount;
8777 BasicBlock** jumpTab;
8778 jumpTab = block->bbJumpSwt->bbsDstTab;
8781 chars += printf("%c BB%02u", (jumpTab == block->bbJumpSwt->bbsDstTab) ? ' ' : ',', (*jumpTab)->bbNum);
8782 } while (++jumpTab, --jumpCnt);
8791 if (block->bbNext != nullptr)
8797 /*****************************************************************************
8799 * COMPlus_JitDumpIR support - dump out block in linear IR form
8802 void dBlockIR(BasicBlock* block)
8804 cBlockIR(JitTls::GetCompiler(), block);
8807 /*****************************************************************************
8809 * COMPlus_JitDumpIR support - dump out tree node type for linear IR form
8812 int cTreeTypeIR(Compiler* comp, GenTree* tree)
8816 var_types type = tree->TypeGet();
8818 const char* typeName = varTypeName(type);
8819 chars += printf(".%s", typeName);
8824 /*****************************************************************************
8826 * COMPlus_JitDumpIR support - dump out tree node type for linear IR form
8829 int dTreeTypeIR(GenTree* tree)
8831 int chars = cTreeTypeIR(JitTls::GetCompiler(), tree);
8836 /*****************************************************************************
8838 * COMPlus_JitDumpIR support - dump out tree node kind for linear IR form
8841 int cTreeKindsIR(Compiler* comp, GenTree* tree)
8845 unsigned kind = tree->OperKind();
8847 chars += printf("kinds=");
8848 if (kind == GTK_SPECIAL)
8850 chars += printf("[SPECIAL]");
8852 if (kind & GTK_CONST)
8854 chars += printf("[CONST]");
8856 if (kind & GTK_LEAF)
8858 chars += printf("[LEAF]");
8860 if (kind & GTK_UNOP)
8862 chars += printf("[UNOP]");
8864 if (kind & GTK_BINOP)
8866 chars += printf("[BINOP]");
8868 if (kind & GTK_LOGOP)
8870 chars += printf("[LOGOP]");
8872 if (kind & GTK_ASGOP)
8874 chars += printf("[ASGOP]");
8876 if (kind & GTK_COMMUTE)
8878 chars += printf("[COMMUTE]");
8880 if (kind & GTK_EXOP)
8882 chars += printf("[EXOP]");
8884 if (kind & GTK_LOCAL)
8886 chars += printf("[LOCAL]");
8888 if (kind & GTK_SMPOP)
8890 chars += printf("[SMPOP]");
8896 /*****************************************************************************
8898 * COMPlus_JitDumpIR support - dump out tree node kind for linear IR form
8901 int dTreeKindsIR(GenTree* tree)
8903 int chars = cTreeKindsIR(JitTls::GetCompiler(), tree);
8908 /*****************************************************************************
8910 * COMPlus_JitDumpIR support - dump out tree node flags for linear IR form
8913 int cTreeFlagsIR(Compiler* comp, GenTree* tree)
8917 if (tree->gtFlags != 0)
8919 chars += printf("flags=");
8922 CLANG_FORMAT_COMMENT_ANCHOR;
8925 #if SMALL_TREE_NODES
8926 if (comp->dumpIRNodes)
8928 if (tree->gtDebugFlags & GTF_DEBUG_NODE_LARGE)
8930 chars += printf("[NODE_LARGE]");
8932 if (tree->gtDebugFlags & GTF_DEBUG_NODE_SMALL)
8934 chars += printf("[NODE_SMALL]");
8937 #endif // SMALL_TREE_NODES
8938 if (tree->gtDebugFlags & GTF_DEBUG_NODE_MORPHED)
8940 chars += printf("[MORPHED]");
8942 #endif // defined(DEBUG)
8944 if (tree->gtFlags & GTF_COLON_COND)
8946 chars += printf("[COLON_COND]");
8951 genTreeOps op = tree->OperGet();
8956 case GT_LCL_VAR_ADDR:
8958 case GT_LCL_FLD_ADDR:
8959 case GT_STORE_LCL_FLD:
8960 case GT_STORE_LCL_VAR:
8963 if (tree->gtFlags & GTF_VAR_DEF)
8965 chars += printf("[VAR_DEF]");
8967 if (tree->gtFlags & GTF_VAR_USEASG)
8969 chars += printf("[VAR_USEASG]");
8971 if (tree->gtFlags & GTF_VAR_USEDEF)
8973 chars += printf("[VAR_USEDEF]");
8975 if (tree->gtFlags & GTF_VAR_CAST)
8977 chars += printf("[VAR_CAST]");
8979 if (tree->gtFlags & GTF_VAR_ITERATOR)
8981 chars += printf("[VAR_ITERATOR]");
8983 if (tree->gtFlags & GTF_VAR_CLONED)
8985 chars += printf("[VAR_CLONED]");
8987 if (tree->gtFlags & GTF_VAR_DEATH)
8989 chars += printf("[VAR_DEATH]");
8991 if (tree->gtFlags & GTF_VAR_ARR_INDEX)
8993 chars += printf("[VAR_ARR_INDEX]");
8996 if (tree->gtDebugFlags & GTF_DEBUG_VAR_CSE_REF)
8998 chars += printf("[VAR_CSE_REF]");
9001 if (op == GT_REG_VAR)
9003 if (tree->gtFlags & GTF_REG_BIRTH)
9005 chars += printf("[REG_BIRTH]");
9012 if (tree->gtFlags & GTF_NOP_DEATH)
9014 chars += printf("[NOP_DEATH]");
9020 if (tree->gtFlags & GTF_NO_OP_NO)
9022 chars += printf("[NO_OP_NO]");
9028 if (tree->gtFlags & GTF_FLD_NULLCHECK)
9030 chars += printf("[FLD_NULLCHECK]");
9032 if (tree->gtFlags & GTF_FLD_VOLATILE)
9034 chars += printf("[FLD_VOLATILE]");
9040 if (tree->gtFlags & GTF_INX_RNGCHK)
9042 chars += printf("[INX_RNGCHK]");
9044 if (tree->gtFlags & GTF_INX_REFARR_LAYOUT)
9046 chars += printf("[INX_REFARR_LAYOUT]");
9048 if (tree->gtFlags & GTF_INX_STRING_LAYOUT)
9050 chars += printf("[INX_STRING_LAYOUT]");
9057 if (tree->gtFlags & GTF_IND_VOLATILE)
9059 chars += printf("[IND_VOLATILE]");
9061 if (tree->gtFlags & GTF_IND_REFARR_LAYOUT)
9063 chars += printf("[IND_REFARR_LAYOUT]");
9065 if (tree->gtFlags & GTF_IND_TGTANYWHERE)
9067 chars += printf("[IND_TGTANYWHERE]");
9069 if (tree->gtFlags & GTF_IND_TLS_REF)
9071 chars += printf("[IND_TLS_REF]");
9073 if (tree->gtFlags & GTF_IND_ASG_LHS)
9075 chars += printf("[IND_ASG_LHS]");
9077 if (tree->gtFlags & GTF_IND_UNALIGNED)
9079 chars += printf("[IND_UNALIGNED]");
9081 if (tree->gtFlags & GTF_IND_INVARIANT)
9083 chars += printf("[IND_INVARIANT]");
9085 if (tree->gtFlags & GTF_IND_ARR_LEN)
9087 chars += printf("[IND_ARR_INDEX]");
9093 if (tree->gtFlags & GTF_CLS_VAR_ASG_LHS)
9095 chars += printf("[CLS_VAR_ASG_LHS]");
9101 if (tree->gtFlags & GTF_ADDR_ONSTACK)
9103 chars += printf("[ADDR_ONSTACK]");
9108 #if defined(_TARGET_X86_) && !defined(LEGACY_BACKEND)
9112 if (tree->gtFlags & GTF_MUL_64RSLT)
9114 chars += printf("[64RSLT]");
9116 if (tree->gtFlags & GTF_ADDRMODE_NO_CSE)
9118 chars += printf("[ADDRMODE_NO_CSE]");
9124 if (tree->gtFlags & GTF_ADDRMODE_NO_CSE)
9126 chars += printf("[ADDRMODE_NO_CSE]");
9132 if (tree->gtFlags & GTF_ADDRMODE_NO_CSE)
9134 chars += printf("[ADDRMODE_NO_CSE]");
9141 if (tree->gtFlags & GTF_MOD_INT_RESULT)
9143 chars += printf("[MOD_INT_RESULT]");
9154 if (tree->gtFlags & GTF_RELOP_NAN_UN)
9156 chars += printf("[RELOP_NAN_UN]");
9158 if (tree->gtFlags & GTF_RELOP_JMP_USED)
9160 chars += printf("[RELOP_JMP_USED]");
9162 if (tree->gtFlags & GTF_RELOP_QMARK)
9164 chars += printf("[RELOP_QMARK]");
9166 if (tree->gtFlags & GTF_RELOP_SMALL)
9168 chars += printf("[RELOP_SMALL]");
9174 if (tree->gtFlags & GTF_QMARK_CAST_INSTOF)
9176 chars += printf("[QMARK_CAST_INSTOF]");
9182 if (tree->gtFlags & GTF_BOX_VALUE)
9184 chars += printf("[BOX_VALUE]");
9191 unsigned handleKind = (tree->gtFlags & GTF_ICON_HDL_MASK);
9196 case GTF_ICON_SCOPE_HDL:
9198 chars += printf("[ICON_SCOPE_HDL]");
9201 case GTF_ICON_CLASS_HDL:
9203 chars += printf("[ICON_CLASS_HDL]");
9206 case GTF_ICON_METHOD_HDL:
9208 chars += printf("[ICON_METHOD_HDL]");
9211 case GTF_ICON_FIELD_HDL:
9213 chars += printf("[ICON_FIELD_HDL]");
9216 case GTF_ICON_STATIC_HDL:
9218 chars += printf("[ICON_STATIC_HDL]");
9221 case GTF_ICON_STR_HDL:
9223 chars += printf("[ICON_STR_HDL]");
9226 case GTF_ICON_PSTR_HDL:
9228 chars += printf("[ICON_PSTR_HDL]");
9231 case GTF_ICON_PTR_HDL:
9233 chars += printf("[ICON_PTR_HDL]");
9236 case GTF_ICON_VARG_HDL:
9238 chars += printf("[ICON_VARG_HDL]");
9241 case GTF_ICON_PINVKI_HDL:
9243 chars += printf("[ICON_PINVKI_HDL]");
9246 case GTF_ICON_TOKEN_HDL:
9248 chars += printf("[ICON_TOKEN_HDL]");
9251 case GTF_ICON_TLS_HDL:
9253 chars += printf("[ICON_TLD_HDL]");
9256 case GTF_ICON_FTN_ADDR:
9258 chars += printf("[ICON_FTN_ADDR]");
9261 case GTF_ICON_CIDMID_HDL:
9263 chars += printf("[ICON_CIDMID_HDL]");
9266 case GTF_ICON_BBC_PTR:
9268 chars += printf("[ICON_BBC_PTR]");
9271 case GTF_ICON_FIELD_OFF:
9273 chars += printf("[ICON_FIELD_OFF]");
9281 if (tree->AsObj()->HasGCPtr())
9283 chars += printf("[BLK_HASGCPTR]");
9290 case GT_STORE_DYN_BLK:
9292 if (tree->gtFlags & GTF_BLK_VOLATILE)
9294 chars += printf("[BLK_VOLATILE]");
9296 if (tree->AsBlk()->IsUnaligned())
9298 chars += printf("[BLK_UNALIGNED]");
9304 if (tree->gtFlags & GTF_CALL_UNMANAGED)
9306 chars += printf("[CALL_UNMANAGED]");
9308 if (tree->gtFlags & GTF_CALL_INLINE_CANDIDATE)
9310 chars += printf("[CALL_INLINE_CANDIDATE]");
9312 if (tree->gtFlags & GTF_CALL_NONVIRT)
9314 chars += printf("[CALL_NONVIRT]");
9316 if (tree->gtFlags & GTF_CALL_VIRT_VTABLE)
9318 chars += printf("[CALL_VIRT_VTABLE]");
9320 if (tree->gtFlags & GTF_CALL_VIRT_STUB)
9322 chars += printf("[CALL_VIRT_STUB]");
9324 if (tree->gtFlags & GTF_CALL_NULLCHECK)
9326 chars += printf("[CALL_NULLCHECK]");
9328 if (tree->gtFlags & GTF_CALL_POP_ARGS)
9330 chars += printf("[CALL_POP_ARGS]");
9332 if (tree->gtFlags & GTF_CALL_HOISTABLE)
9334 chars += printf("[CALL_HOISTABLE]");
9336 if (tree->gtFlags & GTF_CALL_REG_SAVE)
9338 chars += printf("[CALL_REG_SAVE]");
9341 // More flags associated with calls.
9344 GenTreeCall* call = tree->AsCall();
9346 if (call->gtCallMoreFlags & GTF_CALL_M_EXPLICIT_TAILCALL)
9348 chars += printf("[CALL_M_EXPLICIT_TAILCALL]");
9350 if (call->gtCallMoreFlags & GTF_CALL_M_TAILCALL)
9352 chars += printf("[CALL_M_TAILCALL]");
9354 if (call->gtCallMoreFlags & GTF_CALL_M_VARARGS)
9356 chars += printf("[CALL_M_VARARGS]");
9358 if (call->gtCallMoreFlags & GTF_CALL_M_RETBUFFARG)
9360 chars += printf("[CALL_M_RETBUFFARG]");
9362 if (call->gtCallMoreFlags & GTF_CALL_M_DELEGATE_INV)
9364 chars += printf("[CALL_M_DELEGATE_INV]");
9366 if (call->gtCallMoreFlags & GTF_CALL_M_NOGCCHECK)
9368 chars += printf("[CALL_M_NOGCCHECK]");
9370 if (call->gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC)
9372 chars += printf("[CALL_M_SPECIAL_INTRINSIC]");
9375 if (call->IsUnmanaged())
9377 if (call->gtCallMoreFlags & GTF_CALL_M_UNMGD_THISCALL)
9379 chars += printf("[CALL_M_UNMGD_THISCALL]");
9382 else if (call->IsVirtualStub())
9384 if (call->gtCallMoreFlags & GTF_CALL_M_VIRTSTUB_REL_INDIRECT)
9386 chars += printf("[CALL_M_VIRTSTUB_REL_INDIRECT]");
9389 else if (!call->IsVirtual())
9391 if (call->gtCallMoreFlags & GTF_CALL_M_NONVIRT_SAME_THIS)
9393 chars += printf("[CALL_M_NONVIRT_SAME_THIS]");
9397 if (call->gtCallMoreFlags & GTF_CALL_M_FRAME_VAR_DEATH)
9399 chars += printf("[CALL_M_FRAME_VAR_DEATH]");
9401 #ifndef LEGACY_BACKEND
9402 if (call->gtCallMoreFlags & GTF_CALL_M_TAILCALL_VIA_HELPER)
9404 chars += printf("[CALL_M_TAILCALL_VIA_HELPER]");
9407 #if FEATURE_TAILCALL_OPT
9408 if (call->gtCallMoreFlags & GTF_CALL_M_IMPLICIT_TAILCALL)
9410 chars += printf("[CALL_M_IMPLICIT_TAILCALL]");
9413 if (call->gtCallMoreFlags & GTF_CALL_M_PINVOKE)
9415 chars += printf("[CALL_M_PINVOKE]");
9422 if (tree->gtFlags & GTF_STMT_CMPADD)
9424 chars += printf("[STMT_CMPADD]");
9426 if (tree->gtFlags & GTF_STMT_HAS_CSE)
9428 chars += printf("[STMT_HAS_CSE]");
9435 unsigned flags = (tree->gtFlags & (~(unsigned)(GTF_COMMON_MASK | GTF_OVERFLOW)));
9438 chars += printf("[%08X]", flags);
9446 if (tree->gtFlags & GTF_ASG)
9448 chars += printf("[ASG]");
9450 if (tree->gtFlags & GTF_CALL)
9452 chars += printf("[CALL]");
9462 if (tree->gtFlags & GTF_OVERFLOW)
9464 chars += printf("[OVERFLOW]");
9470 if (tree->gtFlags & GTF_EXCEPT)
9472 chars += printf("[EXCEPT]");
9474 if (tree->gtFlags & GTF_GLOB_REF)
9476 chars += printf("[GLOB_REF]");
9478 if (tree->gtFlags & GTF_ORDER_SIDEEFF)
9480 chars += printf("[ORDER_SIDEEFF]");
9482 if (tree->gtFlags & GTF_REVERSE_OPS)
9484 if (op != GT_LCL_VAR)
9486 chars += printf("[REVERSE_OPS]");
9489 if (tree->gtFlags & GTF_REG_VAL)
9491 chars += printf("[REG_VAL]");
9493 if (tree->gtFlags & GTF_SPILLED)
9495 chars += printf("[SPILLED_OPER]");
9497 #if defined(LEGACY_BACKEND)
9498 if (tree->gtFlags & GTF_SPILLED_OP2)
9500 chars += printf("[SPILLED_OP2]");
9503 if (tree->gtFlags & GTF_ZSF_SET)
9505 chars += printf("[ZSF_SET]");
9507 #if FEATURE_SET_FLAGS
9508 if (tree->gtFlags & GTF_SET_FLAGS)
9510 if ((op != GT_IND) && (op != GT_STOREIND))
9512 chars += printf("[ZSF_SET_FLAGS]");
9516 if (tree->gtFlags & GTF_IND_NONFAULTING)
9518 if ((op == GT_IND) || (op == GT_STOREIND))
9520 chars += printf("[IND_NONFAULTING]");
9523 if (tree->gtFlags & GTF_MAKE_CSE)
9525 chars += printf("[MAKE_CSE]");
9527 if (tree->gtFlags & GTF_DONT_CSE)
9529 chars += printf("[DONT_CSE]");
9531 if (tree->gtFlags & GTF_BOOLEAN)
9533 chars += printf("[BOOLEAN]");
9535 if (tree->gtFlags & GTF_SMALL_OK)
9537 chars += printf("[SMALL_OK]");
9539 if (tree->gtFlags & GTF_UNSIGNED)
9541 chars += printf("[SMALL_UNSIGNED]");
9543 if (tree->gtFlags & GTF_LATE_ARG)
9545 chars += printf("[SMALL_LATE_ARG]");
9547 if (tree->gtFlags & GTF_SPILL)
9549 chars += printf("[SPILL]");
9551 if (tree->gtFlags & GTF_SPILL_HIGH)
9553 chars += printf("[SPILL_HIGH]");
9555 if (tree->gtFlags & GTF_REUSE_REG_VAL)
9557 if (op == GT_CNS_INT)
9559 chars += printf("[REUSE_REG_VAL]");
9567 /*****************************************************************************
9569 * COMPlus_JitDumpIR support - dump out tree node flags for linear IR form
9572 int dTreeFlagsIR(GenTree* tree)
9574 int chars = cTreeFlagsIR(JitTls::GetCompiler(), tree);
9579 /*****************************************************************************
9581 * COMPlus_JitDumpIR support - dump out SSA number on tree node for linear IR form
9584 int cSsaNumIR(Compiler* comp, GenTree* tree)
9588 if (tree->gtLclVarCommon.HasSsaName())
9590 if (tree->gtFlags & GTF_VAR_USEASG)
9592 assert(tree->gtFlags & GTF_VAR_DEF);
9593 chars += printf("<u:%d><d:%d>", tree->gtLclVarCommon.gtSsaNum, comp->GetSsaNumForLocalVarDef(tree));
9597 chars += printf("<%s:%d>", (tree->gtFlags & GTF_VAR_DEF) ? "d" : "u", tree->gtLclVarCommon.gtSsaNum);
9604 /*****************************************************************************
9606 * COMPlus_JitDumpIR support - dump out SSA number on tree node for linear IR form
9609 int dSsaNumIR(GenTree* tree)
9611 int chars = cSsaNumIR(JitTls::GetCompiler(), tree);
9616 /*****************************************************************************
9618 * COMPlus_JitDumpIR support - dump out Value Number on tree node for linear IR form
9621 int cValNumIR(Compiler* comp, GenTree* tree)
9625 if (tree->gtVNPair.GetLiberal() != ValueNumStore::NoVN)
9627 assert(tree->gtVNPair.GetConservative() != ValueNumStore::NoVN);
9628 ValueNumPair vnp = tree->gtVNPair;
9630 if (vnp.BothEqual())
9632 chars += printf("<v:");
9633 vn = vnp.GetLiberal();
9634 chars += printf(STR_VN "%x", vn);
9635 if (ValueNumStore::isReservedVN(vn))
9637 chars += printf("R");
9639 chars += printf(">");
9643 vn = vnp.GetLiberal();
9644 chars += printf("<v:");
9645 chars += printf(STR_VN "%x", vn);
9646 if (ValueNumStore::isReservedVN(vn))
9648 chars += printf("R");
9650 chars += printf(",");
9651 vn = vnp.GetConservative();
9652 chars += printf(STR_VN "%x", vn);
9653 if (ValueNumStore::isReservedVN(vn))
9655 chars += printf("R");
9657 chars += printf(">");
9664 /*****************************************************************************
9666 * COMPlus_JitDumpIR support - dump out Value Number on tree node for linear IR form
9669 int dValNumIR(GenTree* tree)
9671 int chars = cValNumIR(JitTls::GetCompiler(), tree);
9676 /*****************************************************************************
9678 * COMPlus_JitDumpIR support - dump out tree leaf node for linear IR form
9681 int cLeafIR(Compiler* comp, GenTree* tree)
9684 genTreeOps op = tree->OperGet();
9685 const char* ilKind = nullptr;
9686 const char* ilName = nullptr;
9688 unsigned lclNum = 0;
9689 bool hasSsa = false;
9696 case GT_LCL_VAR_ADDR:
9697 case GT_STORE_LCL_VAR:
9700 lclNum = tree->gtLclVarCommon.gtLclNum;
9701 comp->gtGetLclVarNameInfo(lclNum, &ilKind, &ilName, &ilNum);
9702 if (ilName != nullptr)
9704 chars += printf("%s", ilName);
9708 LclVarDsc* varDsc = comp->lvaTable + lclNum;
9709 chars += printf("%s%d", ilKind, ilNum);
9710 if (comp->dumpIRLocals)
9712 chars += printf("(V%02u", lclNum);
9713 if (varDsc->lvTracked)
9715 chars += printf(":T%02u", varDsc->lvVarIndex);
9717 if (comp->dumpIRRegs)
9719 if (varDsc->lvRegister)
9721 if (isRegPairType(varDsc->TypeGet()))
9723 chars += printf(":%s:%s",
9724 getRegName(varDsc->lvOtherReg), // hi32
9725 getRegName(varDsc->lvRegNum)); // lo32
9729 chars += printf(":%s", getRegName(varDsc->lvRegNum));
9734 switch (tree->GetRegTag())
9736 case GenTree::GT_REGTAG_REG:
9737 chars += printf(":%s", comp->compRegVarName(tree->gtRegNum));
9739 #if CPU_LONG_USES_REGPAIR
9740 case GenTree::GT_REGTAG_REGPAIR:
9741 chars += printf(":%s", comp->compRegPairName(tree->gtRegPair));
9749 chars += printf(")");
9751 else if (comp->dumpIRRegs)
9753 if (varDsc->lvRegister)
9755 chars += printf("(");
9756 if (isRegPairType(varDsc->TypeGet()))
9758 chars += printf("%s:%s",
9759 getRegName(varDsc->lvOtherReg), // hi32
9760 getRegName(varDsc->lvRegNum)); // lo32
9764 chars += printf("%s", getRegName(varDsc->lvRegNum));
9766 chars += printf(")");
9770 switch (tree->GetRegTag())
9772 case GenTree::GT_REGTAG_REG:
9773 chars += printf("(%s)", comp->compRegVarName(tree->gtRegNum));
9775 #if CPU_LONG_USES_REGPAIR
9776 case GenTree::GT_REGTAG_REGPAIR:
9777 chars += printf("(%s)", comp->compRegPairName(tree->gtRegPair));
9787 if (op == GT_REG_VAR)
9789 if (isFloatRegType(tree->gtType))
9791 assert(tree->gtRegVar.gtRegNum == tree->gtRegNum);
9792 chars += printf("(FPV%u)", tree->gtRegNum);
9796 chars += printf("(%s)", comp->compRegVarName(tree->gtRegVar.gtRegNum));
9804 case GT_LCL_FLD_ADDR:
9805 case GT_STORE_LCL_FLD:
9807 lclNum = tree->gtLclVarCommon.gtLclNum;
9808 comp->gtGetLclVarNameInfo(lclNum, &ilKind, &ilName, &ilNum);
9809 if (ilName != nullptr)
9811 chars += printf("%s+%u", ilName, tree->gtLclFld.gtLclOffs);
9815 chars += printf("%s%d+%u", ilKind, ilNum, tree->gtLclFld.gtLclOffs);
9816 LclVarDsc* varDsc = comp->lvaTable + lclNum;
9817 if (comp->dumpIRLocals)
9819 chars += printf("(V%02u", lclNum);
9820 if (varDsc->lvTracked)
9822 chars += printf(":T%02u", varDsc->lvVarIndex);
9824 if (comp->dumpIRRegs)
9826 if (varDsc->lvRegister)
9828 if (isRegPairType(varDsc->TypeGet()))
9830 chars += printf(":%s:%s",
9831 getRegName(varDsc->lvOtherReg), // hi32
9832 getRegName(varDsc->lvRegNum)); // lo32
9836 chars += printf(":%s", getRegName(varDsc->lvRegNum));
9841 switch (tree->GetRegTag())
9843 case GenTree::GT_REGTAG_REG:
9844 chars += printf(":%s", comp->compRegVarName(tree->gtRegNum));
9846 #if CPU_LONG_USES_REGPAIR
9847 case GenTree::GT_REGTAG_REGPAIR:
9848 chars += printf(":%s", comp->compRegPairName(tree->gtRegPair));
9856 chars += printf(")");
9858 else if (comp->dumpIRRegs)
9860 if (varDsc->lvRegister)
9862 chars += printf("(");
9863 if (isRegPairType(varDsc->TypeGet()))
9865 chars += printf("%s:%s",
9866 getRegName(varDsc->lvOtherReg), // hi32
9867 getRegName(varDsc->lvRegNum)); // lo32
9871 chars += printf("%s", getRegName(varDsc->lvRegNum));
9873 chars += printf(")");
9877 switch (tree->GetRegTag())
9879 case GenTree::GT_REGTAG_REG:
9880 chars += printf("(%s)", comp->compRegVarName(tree->gtRegNum));
9882 #if CPU_LONG_USES_REGPAIR
9883 case GenTree::GT_REGTAG_REGPAIR:
9884 chars += printf("(%s)", comp->compRegPairName(tree->gtRegPair));
9894 // TODO: We probably want to expand field sequence.
9895 // gtDispFieldSeq(tree->gtLclFld.gtFieldSeq);
9902 if (tree->IsIconHandle())
9905 // TODO: Commented out because sometimes the CLR throws
9906 // and exception when asking the names of some handles.
9907 // Need to investigate.
9909 const char* className;
9910 const char* fieldName;
9911 const char* methodName;
9914 switch (tree->GetIconHandleFlag())
9917 case GTF_ICON_SCOPE_HDL:
9919 chars += printf("SCOPE(?)");
9922 case GTF_ICON_CLASS_HDL:
9924 className = comp->eeGetClassName((CORINFO_CLASS_HANDLE)tree->gtIntCon.gtIconVal);
9925 chars += printf("CLASS(%s)", className);
9928 case GTF_ICON_METHOD_HDL:
9930 methodName = comp->eeGetMethodName((CORINFO_METHOD_HANDLE)tree->gtIntCon.gtIconVal,
9932 chars += printf("METHOD(%s.%s)", className, methodName);
9935 case GTF_ICON_FIELD_HDL:
9937 fieldName = comp->eeGetFieldName((CORINFO_FIELD_HANDLE)tree->gtIntCon.gtIconVal,
9939 chars += printf("FIELD(%s.%s) ", className, fieldName);
9942 case GTF_ICON_STATIC_HDL:
9944 fieldName = comp->eeGetFieldName((CORINFO_FIELD_HANDLE)tree->gtIntCon.gtIconVal,
9946 chars += printf("STATIC_FIELD(%s.%s)", className, fieldName);
9949 case GTF_ICON_STR_HDL:
9951 str = comp->eeGetCPString(tree->gtIntCon.gtIconVal);
9952 chars += printf("\"%S\"", str);
9955 case GTF_ICON_PSTR_HDL:
9957 chars += printf("PSTR(?)");
9960 case GTF_ICON_PTR_HDL:
9962 chars += printf("PTR(?)");
9965 case GTF_ICON_VARG_HDL:
9967 chars += printf("VARARG(?)");
9970 case GTF_ICON_PINVKI_HDL:
9972 chars += printf("PINVOKE(?)");
9975 case GTF_ICON_TOKEN_HDL:
9977 chars += printf("TOKEN(%08X)", tree->gtIntCon.gtIconVal);
9980 case GTF_ICON_TLS_HDL:
9982 chars += printf("TLS(?)");
9985 case GTF_ICON_FTN_ADDR:
9987 chars += printf("FTN(?)");
9990 case GTF_ICON_CIDMID_HDL:
9992 chars += printf("CIDMID(?)");
9995 case GTF_ICON_BBC_PTR:
9997 chars += printf("BBC(?)");
10002 chars += printf("HANDLE(?)");
10006 #ifdef _TARGET_64BIT_
10007 if ((tree->gtIntCon.gtIconVal & 0xFFFFFFFF00000000LL) != 0)
10009 chars += printf("HANDLE(0x%llx)", dspPtr(tree->gtIntCon.gtIconVal));
10014 chars += printf("HANDLE(0x%0x)", dspPtr(tree->gtIntCon.gtIconVal));
10020 if (tree->TypeGet() == TYP_REF)
10022 assert(tree->gtIntCon.gtIconVal == 0);
10023 chars += printf("null");
10025 #ifdef _TARGET_64BIT_
10026 else if ((tree->gtIntCon.gtIconVal & 0xFFFFFFFF00000000LL) != 0)
10028 chars += printf("0x%llx", tree->gtIntCon.gtIconVal);
10033 chars += printf("%ld(0x%x)", tree->gtIntCon.gtIconVal, tree->gtIntCon.gtIconVal);
10040 chars += printf("CONST(LONG)");
10045 chars += printf("CONST(DOUBLE)");
10050 chars += printf("CONST(STR)");
10056 const char* methodName;
10057 const char* className;
10059 methodName = comp->eeGetMethodName((CORINFO_METHOD_HANDLE)tree->gtVal.gtVal1, &className);
10060 chars += printf(" %s.%s", className, methodName);
10065 case GT_START_NONGC:
10068 case GT_MEMORYBARRIER:
10070 case GT_PINVOKE_PROLOG:
10071 #ifndef LEGACY_BACKEND
10079 chars += printf("t%d", tree->gtRetExpr.gtInlineCandidate->gtTreeID);
10084 chars += printf("%s", getRegName(tree->gtPhysReg.gtSrcReg, varTypeIsFloating(tree)));
10089 if (tree->gtLabel.gtLabBB)
10091 chars += printf("BB%02u", tree->gtLabel.gtLabBB->bbNum);
10095 chars += printf("BB?");
10101 if (tree->gtStmt.gtStmtILoffsx == BAD_IL_OFFSET)
10103 chars += printf("?");
10107 chars += printf("0x%x", jitGetILoffs(tree->gtStmt.gtStmtILoffsx));
10112 case GT_CLS_VAR_ADDR:
10115 if (tree->OperIsLeaf())
10117 chars += printf("<leaf nyi: %s>", tree->OpName(tree->OperGet()));
10120 chars += printf("t%d", tree->gtTreeID);
10124 if (comp->dumpIRTypes)
10126 chars += cTreeTypeIR(comp, tree);
10128 if (comp->dumpIRValnums)
10130 chars += cValNumIR(comp, tree);
10132 if (hasSsa && comp->dumpIRSsa)
10134 chars += cSsaNumIR(comp, tree);
10140 /*****************************************************************************
10142 * COMPlus_JitDumpIR support - dump out tree leaf node for linear IR form
10145 int dLeafIR(GenTree* tree)
10147 int chars = cLeafIR(JitTls::GetCompiler(), tree);
10152 /*****************************************************************************
10154 * COMPlus_JitDumpIR support - dump out tree indir node for linear IR form
10157 int cIndirIR(Compiler* comp, GenTree* tree)
10159 assert(tree->gtOper == GT_IND);
10164 chars += printf("[");
10165 child = tree->GetChild(0);
10166 chars += cLeafIR(comp, child);
10167 chars += printf("]");
10172 /*****************************************************************************
10174 * COMPlus_JitDumpIR support - dump out tree indir node for linear IR form
10177 int dIndirIR(GenTree* tree)
10179 int chars = cIndirIR(JitTls::GetCompiler(), tree);
10184 /*****************************************************************************
10186 * COMPlus_JitDumpIR support - dump out tree operand node for linear IR form
10189 int cOperandIR(Compiler* comp, GenTree* operand)
10193 if (operand == nullptr)
10195 chars += printf("t?");
10199 bool dumpTypes = comp->dumpIRTypes;
10200 bool dumpValnums = comp->dumpIRValnums;
10201 bool foldIndirs = comp->dumpIRDataflow;
10202 bool foldLeafs = comp->dumpIRNoLeafs;
10203 bool foldCommas = comp->dumpIRDataflow;
10204 bool dumpDataflow = comp->dumpIRDataflow;
10205 bool foldLists = comp->dumpIRNoLists;
10206 bool dumpRegs = comp->dumpIRRegs;
10208 genTreeOps op = operand->OperGet();
10210 if (foldLeafs && operand->OperIsLeaf())
10212 if ((op == GT_ARGPLACE) && foldLists)
10216 chars += cLeafIR(comp, operand);
10218 else if (dumpDataflow && (operand->OperIsAssignment() || (op == GT_STORE_LCL_VAR) || (op == GT_STORE_LCL_FLD)))
10220 operand = operand->GetChild(0);
10221 chars += cOperandIR(comp, operand);
10223 else if ((op == GT_INDEX) && foldIndirs)
10225 chars += printf("[t%d]", operand->gtTreeID);
10228 chars += cTreeTypeIR(comp, operand);
10232 chars += cValNumIR(comp, operand);
10235 else if ((op == GT_IND) && foldIndirs)
10237 chars += cIndirIR(comp, operand);
10240 chars += cTreeTypeIR(comp, operand);
10244 chars += cValNumIR(comp, operand);
10247 else if ((op == GT_COMMA) && foldCommas)
10249 operand = operand->GetChild(1);
10250 chars += cOperandIR(comp, operand);
10252 else if ((op == GT_LIST) && foldLists)
10254 GenTree* list = operand;
10255 unsigned childCount = list->NumChildren();
10257 operand = list->GetChild(0);
10258 int operandChars = cOperandIR(comp, operand);
10259 chars += operandChars;
10260 if (childCount > 1)
10262 if (operandChars > 0)
10264 chars += printf(", ");
10266 operand = list->GetChild(1);
10267 if (operand->gtOper == GT_LIST)
10269 chars += cListIR(comp, operand);
10273 chars += cOperandIR(comp, operand);
10279 chars += printf("t%d", operand->gtTreeID);
10282 regNumber regNum = operand->GetReg();
10283 if (regNum != REG_NA)
10285 chars += printf("(%s)", getRegName(regNum));
10290 chars += cTreeTypeIR(comp, operand);
10294 chars += cValNumIR(comp, operand);
10301 /*****************************************************************************
10303 * COMPlus_JitDumpIR support - dump out tree operand node for linear IR form
10306 int dOperandIR(GenTree* operand)
10308 int chars = cOperandIR(JitTls::GetCompiler(), operand);
10313 /*****************************************************************************
10315 * COMPlus_JitDumpIR support - dump out tree list of nodes for linear IR form
10318 int cListIR(Compiler* comp, GenTree* list)
10323 assert(list->gtOper == GT_LIST);
10326 unsigned childCount;
10328 childCount = list->NumChildren();
10329 assert(childCount == 1 || childCount == 2);
10332 for (unsigned childIndex = 0; childIndex < childCount; childIndex++)
10334 if ((childIndex > 0) && (operandChars > 0))
10336 chars += printf(", ");
10339 child = list->GetChild(childIndex);
10340 operandChars = cOperandIR(comp, child);
10341 chars += operandChars;
10347 /*****************************************************************************
10349 * COMPlus_JitDumpIR support - dump out tree list of nodes for linear IR form
10352 int dListIR(GenTree* list)
10354 int chars = cListIR(JitTls::GetCompiler(), list);
10359 /*****************************************************************************
10361 * COMPlus_JitDumpIR support - dump out tree dependencies based on comma nodes for linear IR form
10364 int cDependsIR(Compiler* comp, GenTree* comma, bool* first)
10368 assert(comma->gtOper == GT_COMMA);
10372 child = comma->GetChild(0);
10373 if (child->gtOper == GT_COMMA)
10375 chars += cDependsIR(comp, child, first);
10381 chars += printf(", ");
10383 chars += printf("t%d", child->gtTreeID);
10387 child = comma->GetChild(1);
10388 if (child->gtOper == GT_COMMA)
10390 chars += cDependsIR(comp, child, first);
10396 /*****************************************************************************
10398 * COMPlus_JitDumpIR support - dump out tree dependencies based on comma nodes for linear IR form
10401 int dDependsIR(GenTree* comma)
10406 chars = cDependsIR(JitTls::GetCompiler(), comma, &first);
10411 /*****************************************************************************
10413 * COMPlus_JitDumpIR support - dump out tree node in linear IR form
10416 void cNodeIR(Compiler* comp, GenTree* tree)
10418 bool foldLeafs = comp->dumpIRNoLeafs;
10419 bool foldIndirs = comp->dumpIRDataflow;
10420 bool foldLists = comp->dumpIRNoLists;
10421 bool dataflowView = comp->dumpIRDataflow;
10422 bool dumpTypes = comp->dumpIRTypes;
10423 bool dumpValnums = comp->dumpIRValnums;
10424 bool noStmts = comp->dumpIRNoStmts;
10425 genTreeOps op = tree->OperGet();
10426 unsigned childCount = tree->NumChildren();
10429 // What are we skipping?
10431 if (tree->OperIsLeaf())
10438 else if (op == GT_IND)
10445 else if (op == GT_LIST)
10452 else if (op == GT_STMT)
10458 child = tree->GetChild(0);
10459 if (child->gtOper != GT_COMMA)
10470 else if (op == GT_COMMA)
10478 bool nodeIsValue = tree->IsValue();
10480 // Dump tree id or dataflow destination.
10484 // if (comp->compRationalIRForm)
10486 // chars += printf("R");
10489 chars += printf(" ");
10490 if (dataflowView && tree->OperIsAssignment())
10492 child = tree->GetChild(0);
10493 chars += cOperandIR(comp, child);
10495 else if (dataflowView && ((op == GT_STORE_LCL_VAR) || (op == GT_STORE_LCL_FLD)))
10497 chars += cLeafIR(comp, tree);
10499 else if (dataflowView && (op == GT_STOREIND))
10501 child = tree->GetChild(0);
10502 chars += printf("[");
10503 chars += cOperandIR(comp, child);
10504 chars += printf("]");
10507 chars += cTreeTypeIR(comp, tree);
10511 chars += cValNumIR(comp, tree);
10514 else if (nodeIsValue)
10516 chars += printf("t%d", tree->gtTreeID);
10517 if (comp->dumpIRRegs)
10519 regNumber regNum = tree->GetReg();
10520 if (regNum != REG_NA)
10522 chars += printf("(%s)", getRegName(regNum));
10527 chars += cTreeTypeIR(comp, tree);
10531 chars += cValNumIR(comp, tree);
10535 // Dump opcode and tree ID if need in dataflow view.
10537 chars += dTabStopIR(chars, COLUMN_OPCODE);
10538 const char* opName = tree->OpName(op);
10539 chars += printf(" %c %s", nodeIsValue ? '=' : ' ', opName);
10543 if (tree->OperIsAssignment() || (op == GT_STORE_LCL_VAR) || (op == GT_STORE_LCL_FLD) || (op == GT_STOREIND))
10545 chars += printf("(t%d)", tree->gtTreeID);
10549 // Dump modifiers for opcodes to help with readability
10553 GenTreeCall* call = tree->AsCall();
10555 if (call->gtCallType == CT_USER_FUNC)
10557 if (call->IsVirtualStub())
10559 chars += printf(":VS");
10561 else if (call->IsVirtualVtable())
10563 chars += printf(":VT");
10565 else if (call->IsVirtual())
10567 chars += printf(":V");
10570 else if (call->gtCallType == CT_HELPER)
10572 chars += printf(":H");
10574 else if (call->gtCallType == CT_INDIRECT)
10576 chars += printf(":I");
10578 else if (call->IsUnmanaged())
10580 chars += printf(":U");
10584 if (call->IsVirtualStub())
10586 chars += printf(":XVS");
10588 else if (call->IsVirtualVtable())
10590 chars += printf(":XVT");
10594 chars += printf(":?");
10598 if (call->IsUnmanaged())
10600 if (call->gtCallMoreFlags & GTF_CALL_M_UNMGD_THISCALL)
10602 chars += printf(":T");
10606 if (tree->gtFlags & GTF_CALL_NULLCHECK)
10608 chars += printf(":N");
10611 else if (op == GT_INTRINSIC)
10613 CorInfoIntrinsics intrin = tree->gtIntrinsic.gtIntrinsicId;
10615 chars += printf(":");
10618 case CORINFO_INTRINSIC_Sin:
10619 chars += printf("Sin");
10621 case CORINFO_INTRINSIC_Cos:
10622 chars += printf("Cos");
10624 case CORINFO_INTRINSIC_Sqrt:
10625 chars += printf("Sqrt");
10627 case CORINFO_INTRINSIC_Cosh:
10628 chars += printf("Cosh");
10630 case CORINFO_INTRINSIC_Sinh:
10631 chars += printf("Sinh");
10633 case CORINFO_INTRINSIC_Tan:
10634 chars += printf("Tan");
10636 case CORINFO_INTRINSIC_Tanh:
10637 chars += printf("Tanh");
10639 case CORINFO_INTRINSIC_Asin:
10640 chars += printf("Asin");
10642 case CORINFO_INTRINSIC_Acos:
10643 chars += printf("Acos");
10645 case CORINFO_INTRINSIC_Atan:
10646 chars += printf("Atan");
10648 case CORINFO_INTRINSIC_Atan2:
10649 chars += printf("Atan2");
10651 case CORINFO_INTRINSIC_Log10:
10652 chars += printf("Log10");
10654 case CORINFO_INTRINSIC_Pow:
10655 chars += printf("Pow");
10657 case CORINFO_INTRINSIC_Exp:
10658 chars += printf("Exp");
10660 case CORINFO_INTRINSIC_Ceiling:
10661 chars += printf("Ceiling");
10663 case CORINFO_INTRINSIC_Floor:
10664 chars += printf("Floor");
10667 chars += printf("unknown(%d)", intrin);
10674 chars += dTabStopIR(chars, COLUMN_OPERANDS);
10676 // Dump operator specific fields as operands
10685 const char* className = nullptr;
10686 const char* fieldName = comp->eeGetFieldName(tree->gtField.gtFldHnd, &className);
10688 chars += printf(" %s.%s", className, fieldName);
10694 if (tree->gtCall.gtCallType != CT_INDIRECT)
10696 const char* methodName;
10697 const char* className;
10699 methodName = comp->eeGetMethodName(tree->gtCall.gtCallMethHnd, &className);
10701 chars += printf(" %s.%s", className, methodName);
10705 case GT_STORE_LCL_VAR:
10706 case GT_STORE_LCL_FLD:
10710 chars += printf(" ");
10711 chars += cLeafIR(comp, tree);
10717 GenTreeAddrMode* lea = tree->AsAddrMode();
10718 GenTree* base = lea->Base();
10719 GenTree* index = lea->Index();
10720 unsigned scale = lea->gtScale;
10721 unsigned offset = lea->gtOffset;
10723 chars += printf(" [");
10724 if (base != nullptr)
10726 chars += cOperandIR(comp, base);
10728 if (index != nullptr)
10730 if (base != nullptr)
10732 chars += printf("+");
10734 chars += cOperandIR(comp, index);
10737 chars += printf("*%u", scale);
10740 if ((offset != 0) || ((base == nullptr) && (index == nullptr)))
10742 if ((base != nullptr) || (index != nullptr))
10744 chars += printf("+");
10746 chars += printf("%u", offset);
10748 chars += printf("]");
10754 if (tree->OperIsLeaf())
10756 chars += printf(" ");
10757 chars += cLeafIR(comp, tree);
10759 else if (op == GT_LEA)
10761 // Already dumped it above.
10763 else if (op == GT_PHI)
10765 if (tree->gtOp.gtOp1 != nullptr)
10768 for (GenTreeArgList* args = tree->gtOp.gtOp1->AsArgList(); args != nullptr; args = args->Rest())
10770 child = args->Current();
10773 chars += printf(",");
10776 chars += printf(" ");
10777 chars += cOperandIR(comp, child);
10783 bool hasComma = false;
10785 int operandChars = 0;
10786 for (unsigned childIndex = 0; childIndex < childCount; childIndex++)
10788 child = tree->GetChild(childIndex);
10789 if (child == nullptr)
10794 if (child->gtOper == GT_COMMA)
10799 if (dataflowView && (childIndex == 0))
10801 if ((op == GT_ASG) || (op == GT_STOREIND))
10809 chars += printf(",");
10812 bool isList = (child->gtOper == GT_LIST);
10813 if (!isList || !foldLists)
10815 if (foldLeafs && (child->gtOper == GT_ARGPLACE))
10819 chars += printf(" ");
10820 operandChars = cOperandIR(comp, child);
10821 chars += operandChars;
10822 if (operandChars > 0)
10830 chars += printf(" ");
10831 operandChars = cOperandIR(comp, child);
10832 chars += operandChars;
10833 if (operandChars > 0)
10840 if (dataflowView && hasComma)
10842 chars += printf(", DEPS(");
10844 for (unsigned childIndex = 0; childIndex < childCount; childIndex++)
10846 child = tree->GetChild(childIndex);
10847 if (child->gtOper == GT_COMMA)
10849 chars += cDependsIR(comp, child, &first);
10852 chars += printf(")");
10856 // Dump kinds, flags, costs
10858 if (comp->dumpIRKinds || comp->dumpIRFlags || comp->dumpIRCosts)
10860 chars += dTabStopIR(chars, COLUMN_KINDS);
10861 chars += printf(";");
10862 if (comp->dumpIRKinds)
10864 chars += printf(" ");
10865 chars += cTreeKindsIR(comp, tree);
10867 if (comp->dumpIRFlags && (tree->gtFlags != 0))
10869 if (comp->dumpIRKinds)
10871 chars += dTabStopIR(chars, COLUMN_FLAGS);
10875 chars += printf(" ");
10877 chars += cTreeFlagsIR(comp, tree);
10879 if (comp->dumpIRCosts && (tree->gtCostsInitialized))
10881 chars += printf(" CostEx=%d, CostSz=%d", tree->GetCostEx(), tree->GetCostSz());
10888 /*****************************************************************************
10890 * COMPlus_JitDumpIR support - dump out tree in linear IR form
10893 void cTreeIR(Compiler* comp, GenTree* tree)
10895 bool foldLeafs = comp->dumpIRNoLeafs;
10896 bool foldIndirs = comp->dumpIRDataflow;
10897 bool foldLists = comp->dumpIRNoLists;
10898 bool dataflowView = comp->dumpIRDataflow;
10899 bool dumpTypes = comp->dumpIRTypes;
10900 bool dumpValnums = comp->dumpIRValnums;
10901 bool noStmts = comp->dumpIRNoStmts;
10902 genTreeOps op = tree->OperGet();
10903 unsigned childCount = tree->NumChildren();
10906 // Recurse and dump trees that this node depends on.
10908 if (tree->OperIsLeaf())
10911 else if (tree->OperIsBinary() && tree->IsReverseOp())
10913 child = tree->GetChild(1);
10914 cTreeIR(comp, child);
10915 child = tree->GetChild(0);
10916 cTreeIR(comp, child);
10918 else if (op == GT_PHI)
10924 assert(!tree->IsReverseOp());
10925 for (unsigned childIndex = 0; childIndex < childCount; childIndex++)
10927 child = tree->GetChild(childIndex);
10928 if (child != nullptr)
10930 cTreeIR(comp, child);
10935 cNodeIR(comp, tree);
10938 /*****************************************************************************
10940 * COMPlus_JitDumpIR support - dump out tree in linear IR form
10943 void dTreeIR(GenTree* tree)
10945 cTreeIR(JitTls::GetCompiler(), tree);
10950 #if VARSET_COUNTOPS
10952 BitSetSupport::BitSetOpCounter Compiler::m_varsetOpCounter("VarSetOpCounts.log");
10954 #if ALLVARSET_COUNTOPS
10956 BitSetSupport::BitSetOpCounter Compiler::m_allvarsetOpCounter("AllVarSetOpCounts.log");
10960 HelperCallProperties Compiler::s_helperCallProperties;
10962 /*****************************************************************************/
10963 /*****************************************************************************/