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 #include "stacklevelsetter.h"
26 #endif // !LEGACY_BACKEND
28 #include "jittelemetry.h"
31 // Column settings for COMPlus_JitDumpIR. We could(should) make these programmable.
32 #define COLUMN_OPCODE 30
33 #define COLUMN_OPERANDS (COLUMN_OPCODE + 25)
34 #define COLUMN_KINDS 110
35 #define COLUMN_FLAGS (COLUMN_KINDS + 32)
39 unsigned Compiler::jitTotalMethodCompiled = 0;
40 #endif // defined(DEBUG)
43 LONG Compiler::jitNestingLevel = 0;
44 #endif // defined(DEBUG)
48 bool Compiler::s_pAltJitExcludeAssembliesListInitialized = false;
49 AssemblyNamesList2* Compiler::s_pAltJitExcludeAssembliesList = nullptr;
52 /*****************************************************************************
54 * Little helpers to grab the current cycle counter value; this is done
55 * differently based on target architecture, host toolchain, etc. The
56 * main thing is to keep the overhead absolutely minimal; in fact, on
57 * x86/x64 we use RDTSC even though it's not thread-safe; GetThreadCycles
58 * (which is monotonous) is just too expensive.
60 #ifdef FEATURE_JIT_METHOD_PERF
62 #if defined(_HOST_X86_) || defined(_HOST_AMD64_)
67 inline bool _our_GetThreadCycles(unsigned __int64* cycleOut)
69 *cycleOut = __rdtsc();
73 #elif defined(__clang__)
75 inline bool _our_GetThreadCycles(unsigned __int64* cycleOut)
78 __asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi));
79 *cycleOut = (static_cast<unsigned __int64>(hi) << 32) | static_cast<unsigned __int64>(lo);
83 #else // neither _MSC_VER nor __clang__
85 // The following *might* work - might as well try.
86 #define _our_GetThreadCycles(cp) GetThreadCycles(cp)
90 #elif defined(_HOST_ARM_) || defined(_HOST_ARM64_)
92 // If this doesn't work please see ../gc/gc.cpp for additional ARM
93 // info (and possible solutions).
94 #define _our_GetThreadCycles(cp) GetThreadCycles(cp)
96 #else // not x86/x64 and not ARM
98 // Don't know what this target is, but let's give it a try; if
99 // someone really wants to make this work, please add the right
101 #define _our_GetThreadCycles(cp) GetThreadCycles(cp)
103 #endif // which host OS
105 #endif // FEATURE_JIT_METHOD_PERF
106 /*****************************************************************************/
107 inline unsigned getCurTime()
113 return (((tim.wHour * 60) + tim.wMinute) * 60 + tim.wSecond) * 1000 + tim.wMilliseconds;
116 /*****************************************************************************/
118 /*****************************************************************************/
120 static FILE* jitSrcFilePtr;
122 static unsigned jitCurSrcLine;
124 void Compiler::JitLogEE(unsigned level, const char* fmt, ...)
131 vflogf(jitstdout, fmt, args);
136 vlogf(level, fmt, args);
140 void Compiler::compDspSrcLinesByLineNum(unsigned line, bool seek)
147 if (jitCurSrcLine == line)
152 if (jitCurSrcLine > line)
159 if (fseek(jitSrcFilePtr, 0, SEEK_SET) != 0)
161 printf("Compiler::compDspSrcLinesByLineNum: fseek returned an error.\n");
176 if (!fgets(temp, sizeof(temp), jitSrcFilePtr))
187 if (llen && temp[llen - 1] == '\n')
192 printf("; %s\n", temp);
193 } while (++jitCurSrcLine < line);
201 /*****************************************************************************/
203 void Compiler::compDspSrcLinesByNativeIP(UNATIVE_OFFSET curIP)
205 static IPmappingDsc* nextMappingDsc;
206 static unsigned lastLine;
215 if (genIPmappingList)
217 nextMappingDsc = genIPmappingList;
218 lastLine = jitGetILoffs(nextMappingDsc->ipmdILoffsx);
220 unsigned firstLine = jitGetILoffs(nextMappingDsc->ipmdILoffsx);
222 unsigned earlierLine = (firstLine < 5) ? 0 : firstLine - 5;
224 compDspSrcLinesByLineNum(earlierLine, true); // display previous 5 lines
225 compDspSrcLinesByLineNum(firstLine, false);
229 nextMappingDsc = nullptr;
237 UNATIVE_OFFSET offset = nextMappingDsc->ipmdNativeLoc.CodeOffset(genEmitter);
241 IL_OFFSET nextOffs = jitGetILoffs(nextMappingDsc->ipmdILoffsx);
243 if (lastLine < nextOffs)
245 compDspSrcLinesByLineNum(nextOffs);
249 // This offset corresponds to a previous line. Rewind to that line
251 compDspSrcLinesByLineNum(nextOffs - 2, true);
252 compDspSrcLinesByLineNum(nextOffs);
256 nextMappingDsc = nextMappingDsc->ipmdNext;
261 /*****************************************************************************/
264 /*****************************************************************************/
265 #if defined(DEBUG) || MEASURE_NODE_SIZE || MEASURE_BLOCK_SIZE || DISPLAY_SIZES || CALL_ARG_STATS
267 static unsigned genMethodCnt; // total number of methods JIT'ted
268 unsigned genMethodICnt; // number of interruptible methods
269 unsigned genMethodNCnt; // number of non-interruptible methods
270 static unsigned genSmallMethodsNeedingExtraMemoryCnt = 0;
274 /*****************************************************************************/
275 #if MEASURE_NODE_SIZE
276 NodeSizeStats genNodeSizeStats;
277 NodeSizeStats genNodeSizeStatsPerFunc;
279 unsigned genTreeNcntHistBuckets[] = {10, 20, 30, 40, 50, 100, 200, 300, 400, 500, 1000, 5000, 10000, 0};
280 Histogram genTreeNcntHist(genTreeNcntHistBuckets);
282 unsigned genTreeNsizHistBuckets[] = {1000, 5000, 10000, 50000, 100000, 500000, 1000000, 0};
283 Histogram genTreeNsizHist(genTreeNsizHistBuckets);
284 #endif // MEASURE_NODE_SIZE
286 /*****************************************************************************/
287 #if MEASURE_MEM_ALLOC
289 unsigned memAllocHistBuckets[] = {64, 128, 192, 256, 512, 1024, 4096, 8192, 0};
290 Histogram memAllocHist(memAllocHistBuckets);
291 unsigned memUsedHistBuckets[] = {16, 32, 64, 128, 192, 256, 512, 1024, 4096, 8192, 0};
292 Histogram memUsedHist(memUsedHistBuckets);
294 #endif // MEASURE_MEM_ALLOC
296 /*****************************************************************************
298 * Variables to keep track of total code amounts.
303 size_t grossVMsize; // Total IL code size
304 size_t grossNCsize; // Native code + data size
305 size_t totalNCsize; // Native code + data + GC info size (TODO-Cleanup: GC info size only accurate for JIT32_GCENCODER)
306 size_t gcHeaderISize; // GC header size: interruptible methods
307 size_t gcPtrMapISize; // GC pointer map size: interruptible methods
308 size_t gcHeaderNSize; // GC header size: non-interruptible methods
309 size_t gcPtrMapNSize; // GC pointer map size: non-interruptible methods
311 #endif // DISPLAY_SIZES
313 /*****************************************************************************
315 * Variables to keep track of argument counts.
320 unsigned argTotalCalls;
321 unsigned argHelperCalls;
322 unsigned argStaticCalls;
323 unsigned argNonVirtualCalls;
324 unsigned argVirtualCalls;
326 unsigned argTotalArgs; // total number of args for all calls (including objectPtr)
327 unsigned argTotalDWordArgs;
328 unsigned argTotalLongArgs;
329 unsigned argTotalFloatArgs;
330 unsigned argTotalDoubleArgs;
332 unsigned argTotalRegArgs;
333 unsigned argTotalTemps;
334 unsigned argTotalLclVar;
335 unsigned argTotalDeferred;
336 unsigned argTotalConst;
338 unsigned argTotalObjPtr;
339 unsigned argTotalGTF_ASGinArgs;
341 unsigned argMaxTempsPerMethod;
343 unsigned argCntBuckets[] = {0, 1, 2, 3, 4, 5, 6, 10, 0};
344 Histogram argCntTable(argCntBuckets);
346 unsigned argDWordCntBuckets[] = {0, 1, 2, 3, 4, 5, 6, 10, 0};
347 Histogram argDWordCntTable(argDWordCntBuckets);
349 unsigned argDWordLngCntBuckets[] = {0, 1, 2, 3, 4, 5, 6, 10, 0};
350 Histogram argDWordLngCntTable(argDWordLngCntBuckets);
352 unsigned argTempsCntBuckets[] = {0, 1, 2, 3, 4, 5, 6, 10, 0};
353 Histogram argTempsCntTable(argTempsCntBuckets);
355 #endif // CALL_ARG_STATS
357 /*****************************************************************************
359 * Variables to keep track of basic block counts.
362 #if COUNT_BASIC_BLOCKS
364 // --------------------------------------------------
365 // Basic block count frequency table:
366 // --------------------------------------------------
367 // <= 1 ===> 26872 count ( 56% of total)
368 // 2 .. 2 ===> 669 count ( 58% of total)
369 // 3 .. 3 ===> 4687 count ( 68% of total)
370 // 4 .. 5 ===> 5101 count ( 78% of total)
371 // 6 .. 10 ===> 5575 count ( 90% of total)
372 // 11 .. 20 ===> 3028 count ( 97% of total)
373 // 21 .. 50 ===> 1108 count ( 99% of total)
374 // 51 .. 100 ===> 182 count ( 99% of total)
375 // 101 .. 1000 ===> 34 count (100% of total)
376 // 1001 .. 10000 ===> 0 count (100% of total)
377 // --------------------------------------------------
379 unsigned bbCntBuckets[] = {1, 2, 3, 5, 10, 20, 50, 100, 1000, 10000, 0};
380 Histogram bbCntTable(bbCntBuckets);
382 /* Histogram for the IL opcode size of methods with a single basic block */
384 unsigned bbSizeBuckets[] = {1, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 0};
385 Histogram bbOneBBSizeTable(bbSizeBuckets);
387 #endif // COUNT_BASIC_BLOCKS
389 /*****************************************************************************
391 * Used by optFindNaturalLoops to gather statistical information such as
392 * - total number of natural loops
393 * - number of loops with 1, 2, ... exit conditions
394 * - number of loops that have an iterator (for like)
395 * - number of loops that have a constant iterator
400 unsigned totalLoopMethods; // counts the total number of methods that have natural loops
401 unsigned maxLoopsPerMethod; // counts the maximum number of loops a method has
402 unsigned totalLoopOverflows; // # of methods that identified more loops than we can represent
403 unsigned totalLoopCount; // counts the total number of natural loops
404 unsigned totalUnnatLoopCount; // counts the total number of (not-necessarily natural) loops
405 unsigned totalUnnatLoopOverflows; // # of methods that identified more unnatural loops than we can represent
406 unsigned iterLoopCount; // counts the # of loops with an iterator (for like)
407 unsigned simpleTestLoopCount; // counts the # of loops with an iterator and a simple loop condition (iter < const)
408 unsigned constIterLoopCount; // counts the # of loops with a constant iterator (for like)
409 bool hasMethodLoops; // flag to keep track if we already counted a method as having loops
410 unsigned loopsThisMethod; // counts the number of loops in the current method
411 bool loopOverflowThisMethod; // True if we exceeded the max # of loops in the method.
413 /* Histogram for number of loops in a method */
415 unsigned loopCountBuckets[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0};
416 Histogram loopCountTable(loopCountBuckets);
418 /* Histogram for number of loop exits */
420 unsigned loopExitCountBuckets[] = {0, 1, 2, 3, 4, 5, 6, 0};
421 Histogram loopExitCountTable(loopExitCountBuckets);
423 #endif // COUNT_LOOPS
425 //------------------------------------------------------------------------
426 // getJitGCType: Given the VM's CorInfoGCType convert it to the JIT's var_types
429 // gcType - an enum value that originally came from an element
430 // of the BYTE[] returned from getClassGClayout()
433 // The corresponsing enum value from the JIT's var_types
436 // The gcLayout of each field of a struct is returned from getClassGClayout()
437 // as a BYTE[] but each BYTE element is actually a CorInfoGCType value
438 // Note when we 'know' that there is only one element in theis array
439 // the JIT will often pass the address of a single BYTE, instead of a BYTE[]
442 var_types Compiler::getJitGCType(BYTE gcType)
444 var_types result = TYP_UNKNOWN;
445 CorInfoGCType corInfoType = (CorInfoGCType)gcType;
447 if (corInfoType == TYPE_GC_NONE)
451 else if (corInfoType == TYPE_GC_REF)
455 else if (corInfoType == TYPE_GC_BYREF)
461 noway_assert(!"Bad value of 'gcType'");
466 #if FEATURE_MULTIREG_ARGS
467 //---------------------------------------------------------------------------
468 // getStructGcPtrsFromOp: Given a GenTree node of TYP_STRUCT that represents
469 // a pass by value argument, return the gcPtr layout
470 // for the pointers sized fields
472 // op - the operand of TYP_STRUCT that is passed by value
473 // gcPtrsOut - an array of BYTES that are written by this method
474 // they will contain the VM's CorInfoGCType values
475 // for each pointer sized field
477 // Two [or more] values are written into the gcPtrs array
479 // Note that for ARM64 there will alwys be exactly two pointer sized fields
481 void Compiler::getStructGcPtrsFromOp(GenTree* op, BYTE* gcPtrsOut)
483 assert(op->TypeGet() == TYP_STRUCT);
485 #ifdef _TARGET_ARM64_
486 if (op->OperGet() == GT_OBJ)
488 CORINFO_CLASS_HANDLE objClass = op->gtObj.gtClass;
490 int structSize = info.compCompHnd->getClassSize(objClass);
491 assert(structSize <= 2 * TARGET_POINTER_SIZE);
493 BYTE gcPtrsTmp[2] = {TYPE_GC_NONE, TYPE_GC_NONE};
495 info.compCompHnd->getClassGClayout(objClass, &gcPtrsTmp[0]);
497 gcPtrsOut[0] = gcPtrsTmp[0];
498 gcPtrsOut[1] = gcPtrsTmp[1];
500 else if (op->OperGet() == GT_LCL_VAR)
502 GenTreeLclVarCommon* varNode = op->AsLclVarCommon();
503 unsigned varNum = varNode->gtLclNum;
504 assert(varNum < lvaCount);
505 LclVarDsc* varDsc = &lvaTable[varNum];
507 // At this point any TYP_STRUCT LclVar must be a 16-byte pass by value argument
508 assert(varDsc->lvSize() == 2 * TARGET_POINTER_SIZE);
510 gcPtrsOut[0] = varDsc->lvGcLayout[0];
511 gcPtrsOut[1] = varDsc->lvGcLayout[1];
516 noway_assert(!"Unsupported Oper for getStructGcPtrsFromOp");
519 #endif // FEATURE_MULTIREG_ARGS
522 //---------------------------------------------------------------------------
523 // IsSingleFloat32Struct:
524 // Check if the given struct type contains only one float32 value type
527 // clsHnd - the handle for the struct type
530 // true if the given struct type contains only one float32 value type,
534 bool Compiler::isSingleFloat32Struct(CORINFO_CLASS_HANDLE clsHnd)
538 // all of class chain must be of value type and must have only one field
539 if (!info.compCompHnd->isValueClass(clsHnd) || info.compCompHnd->getClassNumInstanceFields(clsHnd) != 1)
544 CORINFO_CLASS_HANDLE* pClsHnd = &clsHnd;
545 CORINFO_FIELD_HANDLE fldHnd = info.compCompHnd->getFieldInClass(clsHnd, 0);
546 CorInfoType fieldType = info.compCompHnd->getFieldType(fldHnd, pClsHnd);
550 case CORINFO_TYPE_VALUECLASS:
554 case CORINFO_TYPE_FLOAT:
564 //-----------------------------------------------------------------------------
565 // getPrimitiveTypeForStruct:
566 // Get the "primitive" type that is is used for a struct
567 // of size 'structSize'.
568 // We examine 'clsHnd' to check the GC layout of the struct and
569 // return TYP_REF for structs that simply wrap an object.
570 // If the struct is a one element HFA, we will return the
571 // proper floating point type.
574 // structSize - the size of the struct type, cannot be zero
575 // clsHnd - the handle for the struct type, used when may have
576 // an HFA or if we need the GC layout for an object ref.
579 // The primitive type (i.e. byte, short, int, long, ref, float, double)
580 // used to pass or return structs of this size.
581 // If we shouldn't use a "primitive" type then TYP_UNKNOWN is returned.
583 // For 32-bit targets (X86/ARM32) the 64-bit TYP_LONG type is not
584 // considered a primitive type by this method.
585 // So a struct that wraps a 'long' is passed and returned in the
586 // same way as any other 8-byte struct
587 // For ARM32 if we have an HFA struct that wraps a 64-bit double
588 // we will return TYP_DOUBLE.
590 var_types Compiler::getPrimitiveTypeForStruct(unsigned structSize, CORINFO_CLASS_HANDLE clsHnd)
592 assert(structSize != 0);
606 #ifndef _TARGET_XARCH_
611 #endif // _TARGET_XARCH_
613 #ifdef _TARGET_64BIT_
617 // A structSize of 4 with IsHfa, it must be an HFA of one float
626 #ifndef _TARGET_XARCH_
630 useType = TYP_I_IMPL;
633 #endif // _TARGET_XARCH_
634 #endif // _TARGET_64BIT_
636 case TARGET_POINTER_SIZE:
638 // For ARM_SOFTFP, HFA is unsupported so we need to check in another way
639 // This matters only for size-4 struct cause bigger structs would be processed with RetBuf
640 if (isSingleFloat32Struct(clsHnd))
645 #ifdef _TARGET_64BIT_
646 var_types hfaType = GetHfaType(clsHnd);
648 // A structSize of 8 with IsHfa, we have two possiblities:
649 // An HFA of one double or an HFA of two floats
651 // Check and exclude the case of an HFA of two floats
652 if (hfaType == TYP_DOUBLE)
654 // We have an HFA of one double
655 useType = TYP_DOUBLE;
659 assert(hfaType == TYP_FLOAT);
661 // We have an HFA of two floats
662 // This should be passed or returned in two FP registers
663 useType = TYP_UNKNOWN;
665 #else // a 32BIT target
666 // A structSize of 4 with IsHfa, it must be an HFA of one float
668 #endif // _TARGET_64BIT_
673 // Check if this pointer-sized struct is wrapping a GC object
674 info.compCompHnd->getClassGClayout(clsHnd, &gcPtr);
675 useType = getJitGCType(gcPtr);
683 var_types hfaType = GetHfaType(clsHnd);
685 // A structSize of 8 with IsHfa, we have two possiblities:
686 // An HFA of one double or an HFA of two floats
688 // Check and exclude the case of an HFA of two floats
689 if (hfaType == TYP_DOUBLE)
691 // We have an HFA of one double
692 useType = TYP_DOUBLE;
696 assert(hfaType == TYP_FLOAT);
698 // We have an HFA of two floats
699 // This should be passed or returned in two FP registers
700 useType = TYP_UNKNOWN;
705 // We don't have an HFA
706 useType = TYP_UNKNOWN;
709 #endif // _TARGET_ARM_
712 useType = TYP_UNKNOWN;
719 //-----------------------------------------------------------------------------
720 // getArgTypeForStruct:
721 // Get the type that is used to pass values of the given struct type.
722 // If you have already retrieved the struct size then it should be
723 // passed as the optional third argument, as this allows us to avoid
724 // an extra call to getClassSize(clsHnd)
727 // clsHnd - the handle for the struct type
728 // wbPassStruct - An "out" argument with information about how
729 // the struct is to be passed
730 // structSize - the size of the struct type,
731 // or zero if we should call getClassSize(clsHnd)
734 // For wbPassStruct you can pass a 'nullptr' and nothing will be written
735 // or returned for that out parameter.
736 // When *wbPassStruct is SPK_PrimitiveType this method's return value
737 // is the primitive type used to pass the struct.
738 // When *wbPassStruct is SPK_ByReference this method's return value
739 // is always TYP_UNKNOWN and the struct type is passed by reference to a copy
740 // When *wbPassStruct is SPK_ByValue or SPK_ByValueAsHfa this method's return value
741 // is always TYP_STRUCT and the struct type is passed by value either
742 // using multiple registers or on the stack.
745 // The size must be the size of the given type.
746 // The given class handle must be for a value type (struct).
750 // When the clsHnd is a one element HFA type we return the appropriate
751 // floating point primitive type and *wbPassStruct is SPK_PrimitiveType
752 // If there are two or more elements in the HFA type then the this method's
753 // return value is TYP_STRUCT and *wbPassStruct is SPK_ByValueAsHfa
755 var_types Compiler::getArgTypeForStruct(CORINFO_CLASS_HANDLE clsHnd,
756 structPassingKind* wbPassStruct,
757 unsigned structSize /* = 0 */)
759 var_types useType = TYP_UNKNOWN;
760 structPassingKind howToPassStruct = SPK_Unknown; // We must change this before we return
764 structSize = info.compCompHnd->getClassSize(clsHnd);
766 assert(structSize > 0);
768 #ifdef UNIX_AMD64_ABI
770 // An 8-byte struct may need to be passed in a floating point register
771 // So we always consult the struct "Classifier" routine
773 SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
774 eeGetSystemVAmd64PassStructInRegisterDescriptor(clsHnd, &structDesc);
776 // If we have one eightByteCount then we can set 'useType' based on that
777 if (structDesc.eightByteCount == 1)
779 // Set 'useType' to the type of the first eightbyte item
780 useType = GetEightByteType(structDesc, 0);
783 #elif defined(_TARGET_X86_)
785 // On x86 we never pass structs as primitive types (unless the VM unwraps them for us)
786 useType = TYP_UNKNOWN;
788 #else // all other targets
790 // The largest primitive type is 8 bytes (TYP_DOUBLE)
791 // so we can skip calling getPrimitiveTypeForStruct when we
792 // have a struct that is larger than that.
794 if (structSize <= sizeof(double))
796 // We set the "primitive" useType based upon the structSize
797 // and also examine the clsHnd to see if it is an HFA of count one
798 useType = getPrimitiveTypeForStruct(structSize, clsHnd);
801 #endif // all other targets
803 // Did we change this struct type into a simple "primitive" type?
805 if (useType != TYP_UNKNOWN)
807 // Yes, we should use the "primitive" type in 'useType'
808 howToPassStruct = SPK_PrimitiveType;
810 else // We can't replace the struct with a "primitive" type
812 // See if we can pass this struct by value, possibly in multiple registers
813 // or if we should pass it by reference to a copy
815 if (structSize <= MAX_PASS_MULTIREG_BYTES)
817 // Structs that are HFA's are passed by value in multiple registers
820 // HFA's of count one should have been handled by getPrimitiveTypeForStruct
821 assert(GetHfaCount(clsHnd) >= 2);
823 // setup wbPassType and useType indicate that this is passed by value as an HFA
824 // using multiple registers
825 // (when all of the parameters registers are used, then the stack will be used)
826 howToPassStruct = SPK_ByValueAsHfa;
827 useType = TYP_STRUCT;
829 else // Not an HFA struct type
832 #ifdef UNIX_AMD64_ABI
834 // The case of (structDesc.eightByteCount == 1) should have already been handled
835 if (structDesc.eightByteCount > 1)
837 // setup wbPassType and useType indicate that this is passed by value in multiple registers
838 // (when all of the parameters registers are used, then the stack will be used)
839 howToPassStruct = SPK_ByValue;
840 useType = TYP_STRUCT;
844 assert(structDesc.eightByteCount == 0);
845 // Otherwise we pass this struct by reference to a copy
846 // setup wbPassType and useType indicate that this is passed using one register
847 // (by reference to a copy)
848 howToPassStruct = SPK_ByReference;
849 useType = TYP_UNKNOWN;
852 #elif defined(_TARGET_ARM64_)
854 // Structs that are pointer sized or smaller should have been handled by getPrimitiveTypeForStruct
855 assert(structSize > TARGET_POINTER_SIZE);
857 // On ARM64 structs that are 9-16 bytes are passed by value in multiple registers
859 if (structSize <= (TARGET_POINTER_SIZE * 2))
861 // setup wbPassType and useType indicate that this is passed by value in multiple registers
862 // (when all of the parameters registers are used, then the stack will be used)
863 howToPassStruct = SPK_ByValue;
864 useType = TYP_STRUCT;
866 else // a structSize that is 17-32 bytes in size
868 // Otherwise we pass this struct by reference to a copy
869 // setup wbPassType and useType indicate that this is passed using one register
870 // (by reference to a copy)
871 howToPassStruct = SPK_ByReference;
872 useType = TYP_UNKNOWN;
875 #elif defined(_TARGET_X86_) || defined(_TARGET_ARM_)
877 // Otherwise we pass this struct by value on the stack
878 // setup wbPassType and useType indicate that this is passed by value according to the X86/ARM32 ABI
879 howToPassStruct = SPK_ByValue;
880 useType = TYP_STRUCT;
882 #else // _TARGET_XXX_
884 noway_assert(!"Unhandled TARGET in getArgTypeForStruct (with FEATURE_MULTIREG_ARGS=1)");
886 #endif // _TARGET_XXX_
889 else // (structSize > MAX_PASS_MULTIREG_BYTES)
891 // We have a (large) struct that can't be replaced with a "primitive" type
892 // and can't be passed in multiple registers
893 CLANG_FORMAT_COMMENT_ANCHOR;
895 #if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
897 // Otherwise we pass this struct by value on the stack
898 // setup wbPassType and useType indicate that this is passed by value according to the X86/ARM32 ABI
899 howToPassStruct = SPK_ByValue;
900 useType = TYP_STRUCT;
902 #elif defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
904 // Otherwise we pass this struct by reference to a copy
905 // setup wbPassType and useType indicate that this is passed using one register (by reference to a copy)
906 howToPassStruct = SPK_ByReference;
907 useType = TYP_UNKNOWN;
909 #else // _TARGET_XXX_
911 noway_assert(!"Unhandled TARGET in getArgTypeForStruct");
913 #endif // _TARGET_XXX_
917 // 'howToPassStruct' must be set to one of the valid values before we return
918 assert(howToPassStruct != SPK_Unknown);
919 if (wbPassStruct != nullptr)
921 *wbPassStruct = howToPassStruct;
927 //-----------------------------------------------------------------------------
928 // getReturnTypeForStruct:
929 // Get the type that is used to return values of the given struct type.
930 // If you have already retrieved the struct size then it should be
931 // passed as the optional third argument, as this allows us to avoid
932 // an extra call to getClassSize(clsHnd)
935 // clsHnd - the handle for the struct type
936 // wbReturnStruct - An "out" argument with information about how
937 // the struct is to be returned
938 // structSize - the size of the struct type,
939 // or zero if we should call getClassSize(clsHnd)
942 // For wbReturnStruct you can pass a 'nullptr' and nothing will be written
943 // or returned for that out parameter.
944 // When *wbReturnStruct is SPK_PrimitiveType this method's return value
945 // is the primitive type used to return the struct.
946 // When *wbReturnStruct is SPK_ByReference this method's return value
947 // is always TYP_UNKNOWN and the struct type is returned using a return buffer
948 // When *wbReturnStruct is SPK_ByValue or SPK_ByValueAsHfa this method's return value
949 // is always TYP_STRUCT and the struct type is returned using multiple registers.
952 // The size must be the size of the given type.
953 // The given class handle must be for a value type (struct).
957 // When the clsHnd is a one element HFA type then this method's return
958 // value is the appropriate floating point primitive type and
959 // *wbReturnStruct is SPK_PrimitiveType.
960 // If there are two or more elements in the HFA type and the target supports
961 // multireg return types then the return value is TYP_STRUCT and
962 // *wbReturnStruct is SPK_ByValueAsHfa.
963 // Additionally if there are two or more elements in the HFA type and
964 // the target doesn't support multreg return types then it is treated
965 // as if it wasn't an HFA type.
966 // About returning TYP_STRUCT:
967 // Whenever this method's return value is TYP_STRUCT it always means
968 // that multiple registers are used to return this struct.
970 var_types Compiler::getReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd,
971 structPassingKind* wbReturnStruct /* = nullptr */,
972 unsigned structSize /* = 0 */)
974 var_types useType = TYP_UNKNOWN;
975 structPassingKind howToReturnStruct = SPK_Unknown; // We must change this before we return
977 assert(clsHnd != NO_CLASS_HANDLE);
981 structSize = info.compCompHnd->getClassSize(clsHnd);
983 assert(structSize > 0);
985 #ifdef UNIX_AMD64_ABI
987 // An 8-byte struct may need to be returned in a floating point register
988 // So we always consult the struct "Classifier" routine
990 SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
991 eeGetSystemVAmd64PassStructInRegisterDescriptor(clsHnd, &structDesc);
993 // If we have one eightByteCount then we can set 'useType' based on that
994 if (structDesc.eightByteCount == 1)
996 // Set 'useType' to the type of the first eightbyte item
997 useType = GetEightByteType(structDesc, 0);
998 assert(structDesc.passedInRegisters == true);
1001 #else // not UNIX_AMD64
1003 // The largest primitive type is 8 bytes (TYP_DOUBLE)
1004 // so we can skip calling getPrimitiveTypeForStruct when we
1005 // have a struct that is larger than that.
1007 if (structSize <= sizeof(double))
1009 #if defined LEGACY_BACKEND
1013 // We set the "primitive" useType based upon the structSize
1014 // and also examine the clsHnd to see if it is an HFA of count one
1015 useType = getPrimitiveTypeForStruct(structSize, clsHnd);
1019 #endif // UNIX_AMD64_ABI
1021 #ifdef _TARGET_64BIT_
1022 // Note this handles an odd case when FEATURE_MULTIREG_RET is disabled and HFAs are enabled
1024 // getPrimitiveTypeForStruct will return TYP_UNKNOWN for a struct that is an HFA of two floats
1025 // because when HFA are enabled, normally we would use two FP registers to pass or return it
1027 // But if we don't have support for multiple register return types, we have to change this.
1028 // Since we what we have an 8-byte struct (float + float) we change useType to TYP_I_IMPL
1029 // so that the struct is returned instead using an 8-byte integer register.
1031 if ((FEATURE_MULTIREG_RET == 0) && (useType == TYP_UNKNOWN) && (structSize == (2 * sizeof(float))) && IsHfa(clsHnd))
1033 useType = TYP_I_IMPL;
1037 // Did we change this struct type into a simple "primitive" type?
1039 if (useType != TYP_UNKNOWN)
1041 // Yes, we should use the "primitive" type in 'useType'
1042 howToReturnStruct = SPK_PrimitiveType;
1044 else // We can't replace the struct with a "primitive" type
1046 // See if we can return this struct by value, possibly in multiple registers
1047 // or if we should return it using a return buffer register
1049 if ((FEATURE_MULTIREG_RET == 1) && (structSize <= MAX_RET_MULTIREG_BYTES))
1051 // Structs that are HFA's are returned in multiple registers
1054 #if !defined(LEGACY_BACKEND)
1055 // HFA's of count one should have been handled by getPrimitiveTypeForStruct
1056 assert(GetHfaCount(clsHnd) >= 2);
1057 #endif // !defined(LEGACY_BACKEND)
1059 // setup wbPassType and useType indicate that this is returned by value as an HFA
1060 // using multiple registers
1061 howToReturnStruct = SPK_ByValueAsHfa;
1062 useType = TYP_STRUCT;
1064 else // Not an HFA struct type
1067 #ifdef UNIX_AMD64_ABI
1069 // The case of (structDesc.eightByteCount == 1) should have already been handled
1070 if (structDesc.eightByteCount > 1)
1072 // setup wbPassType and useType indicate that this is returned by value in multiple registers
1073 howToReturnStruct = SPK_ByValue;
1074 useType = TYP_STRUCT;
1075 assert(structDesc.passedInRegisters == true);
1079 assert(structDesc.eightByteCount == 0);
1080 // Otherwise we return this struct using a return buffer
1081 // setup wbPassType and useType indicate that this is return using a return buffer register
1082 // (reference to a return buffer)
1083 howToReturnStruct = SPK_ByReference;
1084 useType = TYP_UNKNOWN;
1085 assert(structDesc.passedInRegisters == false);
1088 #elif defined(_TARGET_ARM64_)
1090 // Structs that are pointer sized or smaller should have been handled by getPrimitiveTypeForStruct
1091 assert(structSize > TARGET_POINTER_SIZE);
1093 // On ARM64 structs that are 9-16 bytes are returned by value in multiple registers
1095 if (structSize <= (TARGET_POINTER_SIZE * 2))
1097 // setup wbPassType and useType indicate that this is return by value in multiple registers
1098 howToReturnStruct = SPK_ByValue;
1099 useType = TYP_STRUCT;
1101 else // a structSize that is 17-32 bytes in size
1103 // Otherwise we return this struct using a return buffer
1104 // setup wbPassType and useType indicate that this is returned using a return buffer register
1105 // (reference to a return buffer)
1106 howToReturnStruct = SPK_ByReference;
1107 useType = TYP_UNKNOWN;
1110 #elif defined(_TARGET_ARM_) || defined(_TARGET_X86_)
1112 // Otherwise we return this struct using a return buffer
1113 // setup wbPassType and useType indicate that this is returned using a return buffer register
1114 // (reference to a return buffer)
1115 howToReturnStruct = SPK_ByReference;
1116 useType = TYP_UNKNOWN;
1118 #else // _TARGET_XXX_
1120 noway_assert(!"Unhandled TARGET in getReturnTypeForStruct (with FEATURE_MULTIREG_ARGS=1)");
1122 #endif // _TARGET_XXX_
1125 else // (structSize > MAX_RET_MULTIREG_BYTES) || (FEATURE_MULTIREG_RET == 0)
1127 // We have a (large) struct that can't be replaced with a "primitive" type
1128 // and can't be returned in multiple registers
1130 // We return this struct using a return buffer register
1131 // setup wbPassType and useType indicate that this is returned using a return buffer register
1132 // (reference to a return buffer)
1133 howToReturnStruct = SPK_ByReference;
1134 useType = TYP_UNKNOWN;
1138 // 'howToReturnStruct' must be set to one of the valid values before we return
1139 assert(howToReturnStruct != SPK_Unknown);
1140 if (wbReturnStruct != nullptr)
1142 *wbReturnStruct = howToReturnStruct;
1148 ///////////////////////////////////////////////////////////////////////////////
1150 // MEASURE_NOWAY: code to measure and rank dynamic occurences of noway_assert.
1151 // (Just the appearances of noway_assert, whether the assert is true or false.)
1152 // This might help characterize the cost of noway_assert in non-DEBUG builds,
1153 // or determine which noway_assert should be simple DEBUG-only asserts.
1155 ///////////////////////////////////////////////////////////////////////////////
1165 FileLine() : m_file(nullptr), m_line(0), m_condStr(nullptr)
1169 FileLine(const char* file, unsigned line, const char* condStr) : m_line(line)
1171 size_t newSize = (strlen(file) + 1) * sizeof(char);
1172 m_file = (char*)HostAllocator::getHostAllocator()->Alloc(newSize);
1173 strcpy_s(m_file, newSize, file);
1175 newSize = (strlen(condStr) + 1) * sizeof(char);
1176 m_condStr = (char*)HostAllocator::getHostAllocator()->Alloc(newSize);
1177 strcpy_s(m_condStr, newSize, condStr);
1180 FileLine(const FileLine& other)
1182 m_file = other.m_file;
1183 m_line = other.m_line;
1184 m_condStr = other.m_condStr;
1187 // GetHashCode() and Equals() are needed by JitHashTable
1189 static unsigned GetHashCode(FileLine fl)
1191 assert(fl.m_file != nullptr);
1192 unsigned code = fl.m_line;
1193 for (const char* p = fl.m_file; *p != '\0'; p++)
1197 // Could also add condStr.
1201 static bool Equals(FileLine fl1, FileLine fl2)
1203 return (fl1.m_line == fl2.m_line) && (0 == strcmp(fl1.m_file, fl2.m_file));
1207 typedef JitHashTable<FileLine, FileLine, size_t, HostAllocator> FileLineToCountMap;
1208 FileLineToCountMap* NowayAssertMap;
1210 void Compiler::RecordNowayAssert(const char* filename, unsigned line, const char* condStr)
1212 if (NowayAssertMap == nullptr)
1214 NowayAssertMap = new (HostAllocator::getHostAllocator()) FileLineToCountMap(HostAllocator::getHostAllocator());
1216 FileLine fl(filename, line, condStr);
1217 size_t* pCount = NowayAssertMap->LookupPointer(fl);
1218 if (pCount == nullptr)
1220 NowayAssertMap->Set(fl, 1);
1228 void RecordNowayAssertGlobal(const char* filename, unsigned line, const char* condStr)
1230 if ((JitConfig.JitMeasureNowayAssert() == 1) && (JitTls::GetCompiler() != nullptr))
1232 JitTls::GetCompiler()->RecordNowayAssert(filename, line, condStr);
1236 struct NowayAssertCountMap
1241 NowayAssertCountMap() : count(0)
1245 static int __cdecl compare(const void* elem1, const void* elem2)
1247 NowayAssertCountMap* e1 = (NowayAssertCountMap*)elem1;
1248 NowayAssertCountMap* e2 = (NowayAssertCountMap*)elem2;
1249 return (int)((ssize_t)e2->count - (ssize_t)e1->count); // sort in descending order
1253 void DisplayNowayAssertMap()
1255 if (NowayAssertMap != nullptr)
1259 LPCWSTR strJitMeasureNowayAssertFile = JitConfig.JitMeasureNowayAssertFile();
1260 if (strJitMeasureNowayAssertFile != nullptr)
1262 fout = _wfopen(strJitMeasureNowayAssertFile, W("a"));
1263 if (fout == nullptr)
1265 fprintf(jitstdout, "Failed to open JitMeasureNowayAssertFile \"%ws\"\n", strJitMeasureNowayAssertFile);
1274 // Iterate noway assert map, create sorted table by occurrence, dump it.
1275 unsigned count = NowayAssertMap->GetCount();
1276 NowayAssertCountMap* nacp = new NowayAssertCountMap[count];
1279 for (FileLineToCountMap::KeyIterator iter = NowayAssertMap->Begin(), end = NowayAssertMap->End();
1280 !iter.Equal(end); ++iter)
1282 nacp[i].count = iter.GetValue();
1283 nacp[i].fl = iter.Get();
1287 qsort(nacp, count, sizeof(nacp[0]), NowayAssertCountMap::compare);
1289 if (fout == jitstdout)
1291 // Don't output the header if writing to a file, since we'll be appending to existing dumps in that case.
1292 fprintf(fout, "\nnoway_assert counts:\n");
1293 fprintf(fout, "count, file, line, text\n");
1296 for (i = 0; i < count; i++)
1298 fprintf(fout, "%u, %s, %u, \"%s\"\n", nacp[i].count, nacp[i].fl.m_file, nacp[i].fl.m_line,
1299 nacp[i].fl.m_condStr);
1302 if (fout != jitstdout)
1310 #endif // MEASURE_NOWAY
1312 /*****************************************************************************
1313 * variables to keep track of how many iterations we go in a dataflow pass
1318 unsigned CSEiterCount; // counts the # of iteration for the CSE dataflow
1319 unsigned CFiterCount; // counts the # of iteration for the Const Folding dataflow
1321 #endif // DATAFLOW_ITER
1323 #if MEASURE_BLOCK_SIZE
1324 size_t genFlowNodeSize;
1325 size_t genFlowNodeCnt;
1326 #endif // MEASURE_BLOCK_SIZE
1328 /*****************************************************************************/
1329 // We keep track of methods we've already compiled.
1331 /*****************************************************************************
1332 * Declare the statics
1337 unsigned Compiler::s_compMethodsCount = 0; // to produce unique label names
1340 #if MEASURE_MEM_ALLOC
1342 bool Compiler::s_dspMemStats = false;
1345 #ifndef PROFILING_SUPPORTED
1346 const bool Compiler::Options::compNoPInvokeInlineCB = false;
1349 /*****************************************************************************
1351 * One time initialization code
1355 void Compiler::compStartup()
1358 grossVMsize = grossNCsize = totalNCsize = 0;
1359 #endif // DISPLAY_SIZES
1361 // Initialize the JIT's allocator.
1362 ArenaAllocator::startup();
1364 /* Initialize the table of tree node sizes */
1366 GenTree::InitNodeSize();
1368 #ifdef JIT32_GCENCODER
1369 // Initialize the GC encoder lookup table
1371 GCInfo::gcInitEncoderLookupTable();
1374 /* Initialize the emitter */
1376 emitter::emitInit();
1378 // Static vars of ValueNumStore
1379 ValueNumStore::InitValueNumStoreStatics();
1381 compDisplayStaticSizes(jitstdout);
1384 /*****************************************************************************
1386 * One time finalization code
1390 void Compiler::compShutdown()
1393 if (s_pAltJitExcludeAssembliesList != nullptr)
1395 s_pAltJitExcludeAssembliesList->~AssemblyNamesList2(); // call the destructor
1396 s_pAltJitExcludeAssembliesList = nullptr;
1401 DisplayNowayAssertMap();
1402 #endif // MEASURE_NOWAY
1404 ArenaAllocator::shutdown();
1406 /* Shut down the emitter */
1408 emitter::emitDone();
1410 #if defined(DEBUG) || defined(INLINE_DATA)
1411 // Finish reading and/or writing inline xml
1412 InlineStrategy::FinalizeXml();
1413 #endif // defined(DEBUG) || defined(INLINE_DATA)
1415 #if defined(DEBUG) || MEASURE_NODE_SIZE || MEASURE_BLOCK_SIZE || DISPLAY_SIZES || CALL_ARG_STATS
1416 if (genMethodCnt == 0)
1423 GenTree::ReportOperBashing(jitstdout);
1426 // Where should we write our statistics output?
1427 FILE* fout = jitstdout;
1429 #ifdef FEATURE_JIT_METHOD_PERF
1430 if (compJitTimeLogFilename != nullptr)
1432 FILE* jitTimeLogFile = _wfopen(compJitTimeLogFilename, W("a"));
1433 if (jitTimeLogFile != nullptr)
1435 CompTimeSummaryInfo::s_compTimeSummary.Print(jitTimeLogFile);
1436 fclose(jitTimeLogFile);
1439 #endif // FEATURE_JIT_METHOD_PERF
1441 #if FUNC_INFO_LOGGING
1442 if (compJitFuncInfoFile != nullptr)
1444 fclose(compJitFuncInfoFile);
1445 compJitFuncInfoFile = nullptr;
1447 #endif // FUNC_INFO_LOGGING
1449 #if COUNT_RANGECHECKS
1450 if (optRangeChkAll > 0)
1452 fprintf(fout, "Removed %u of %u range checks\n", optRangeChkRmv, optRangeChkAll);
1454 #endif // COUNT_RANGECHECKS
1458 // Add up all the counts so that we can show percentages of total
1460 for (unsigned op = 0; op < GT_COUNT; op++)
1461 gtc += GenTree::s_gtNodeCounts[op];
1465 unsigned rem_total = gtc;
1466 unsigned rem_large = 0;
1467 unsigned rem_small = 0;
1469 unsigned tot_large = 0;
1470 unsigned tot_small = 0;
1472 fprintf(fout, "\nGenTree operator counts (approximate):\n\n");
1474 for (unsigned op = 0; op < GT_COUNT; op++)
1476 unsigned siz = GenTree::s_gtTrueSizes[op];
1477 unsigned cnt = GenTree::s_gtNodeCounts[op];
1478 double pct = 100.0 * cnt / gtc;
1480 if (siz > TREE_NODE_SZ_SMALL)
1485 // Let's not show anything below a threshold
1488 fprintf(fout, " GT_%-17s %7u (%4.1lf%%) %3u bytes each\n", GenTree::OpName((genTreeOps)op), cnt,
1494 if (siz > TREE_NODE_SZ_SMALL)
1502 fprintf(fout, " All other GT_xxx ... %7u (%4.1lf%%) ... %4.1lf%% small + %4.1lf%% large\n", rem_total,
1503 100.0 * rem_total / gtc, 100.0 * rem_small / gtc, 100.0 * rem_large / gtc);
1505 fprintf(fout, " -----------------------------------------------------\n");
1506 fprintf(fout, " Total ....... %11u --ALL-- ... %4.1lf%% small + %4.1lf%% large\n", gtc,
1507 100.0 * tot_small / gtc, 100.0 * tot_large / gtc);
1508 fprintf(fout, "\n");
1511 #endif // COUNT_AST_OPERS
1515 if (grossVMsize && grossNCsize)
1517 fprintf(fout, "\n");
1518 fprintf(fout, "--------------------------------------\n");
1519 fprintf(fout, "Function and GC info size stats\n");
1520 fprintf(fout, "--------------------------------------\n");
1522 fprintf(fout, "[%7u VM, %8u %6s %4u%%] %s\n", grossVMsize, grossNCsize, Target::g_tgtCPUName,
1523 100 * grossNCsize / grossVMsize, "Total (excluding GC info)");
1525 fprintf(fout, "[%7u VM, %8u %6s %4u%%] %s\n", grossVMsize, totalNCsize, Target::g_tgtCPUName,
1526 100 * totalNCsize / grossVMsize, "Total (including GC info)");
1528 if (gcHeaderISize || gcHeaderNSize)
1530 fprintf(fout, "\n");
1532 fprintf(fout, "GC tables : [%7uI,%7uN] %7u byt (%u%% of IL, %u%% of %s).\n",
1533 gcHeaderISize + gcPtrMapISize, gcHeaderNSize + gcPtrMapNSize, totalNCsize - grossNCsize,
1534 100 * (totalNCsize - grossNCsize) / grossVMsize, 100 * (totalNCsize - grossNCsize) / grossNCsize,
1535 Target::g_tgtCPUName);
1537 fprintf(fout, "GC headers : [%7uI,%7uN] %7u byt, [%4.1fI,%4.1fN] %4.1f byt/meth\n", gcHeaderISize,
1538 gcHeaderNSize, gcHeaderISize + gcHeaderNSize, (float)gcHeaderISize / (genMethodICnt + 0.001),
1539 (float)gcHeaderNSize / (genMethodNCnt + 0.001),
1540 (float)(gcHeaderISize + gcHeaderNSize) / genMethodCnt);
1542 fprintf(fout, "GC ptr maps : [%7uI,%7uN] %7u byt, [%4.1fI,%4.1fN] %4.1f byt/meth\n", gcPtrMapISize,
1543 gcPtrMapNSize, gcPtrMapISize + gcPtrMapNSize, (float)gcPtrMapISize / (genMethodICnt + 0.001),
1544 (float)gcPtrMapNSize / (genMethodNCnt + 0.001),
1545 (float)(gcPtrMapISize + gcPtrMapNSize) / genMethodCnt);
1549 fprintf(fout, "\n");
1551 fprintf(fout, "GC tables take up %u bytes (%u%% of instr, %u%% of %6s code).\n",
1552 totalNCsize - grossNCsize, 100 * (totalNCsize - grossNCsize) / grossVMsize,
1553 100 * (totalNCsize - grossNCsize) / grossNCsize, Target::g_tgtCPUName);
1558 fprintf(fout, "%u out of %u methods generated with double-aligned stack\n",
1559 Compiler::s_lvaDoubleAlignedProcsCount, genMethodCnt);
1564 #endif // DISPLAY_SIZES
1567 compDispCallArgStats(fout);
1570 #if COUNT_BASIC_BLOCKS
1571 fprintf(fout, "--------------------------------------------------\n");
1572 fprintf(fout, "Basic block count frequency table:\n");
1573 fprintf(fout, "--------------------------------------------------\n");
1574 bbCntTable.dump(fout);
1575 fprintf(fout, "--------------------------------------------------\n");
1577 fprintf(fout, "\n");
1579 fprintf(fout, "--------------------------------------------------\n");
1580 fprintf(fout, "IL method size frequency table for methods with a single basic block:\n");
1581 fprintf(fout, "--------------------------------------------------\n");
1582 bbOneBBSizeTable.dump(fout);
1583 fprintf(fout, "--------------------------------------------------\n");
1584 #endif // COUNT_BASIC_BLOCKS
1588 fprintf(fout, "\n");
1589 fprintf(fout, "---------------------------------------------------\n");
1590 fprintf(fout, "Loop stats\n");
1591 fprintf(fout, "---------------------------------------------------\n");
1592 fprintf(fout, "Total number of methods with loops is %5u\n", totalLoopMethods);
1593 fprintf(fout, "Total number of loops is %5u\n", totalLoopCount);
1594 fprintf(fout, "Maximum number of loops per method is %5u\n", maxLoopsPerMethod);
1595 fprintf(fout, "# of methods overflowing nat loop table is %5u\n", totalLoopOverflows);
1596 fprintf(fout, "Total number of 'unnatural' loops is %5u\n", totalUnnatLoopCount);
1597 fprintf(fout, "# of methods overflowing unnat loop limit is %5u\n", totalUnnatLoopOverflows);
1598 fprintf(fout, "Total number of loops with an iterator is %5u\n", iterLoopCount);
1599 fprintf(fout, "Total number of loops with a simple iterator is %5u\n", simpleTestLoopCount);
1600 fprintf(fout, "Total number of loops with a constant iterator is %5u\n", constIterLoopCount);
1602 fprintf(fout, "--------------------------------------------------\n");
1603 fprintf(fout, "Loop count frequency table:\n");
1604 fprintf(fout, "--------------------------------------------------\n");
1605 loopCountTable.dump(fout);
1606 fprintf(fout, "--------------------------------------------------\n");
1607 fprintf(fout, "Loop exit count frequency table:\n");
1608 fprintf(fout, "--------------------------------------------------\n");
1609 loopExitCountTable.dump(fout);
1610 fprintf(fout, "--------------------------------------------------\n");
1612 #endif // COUNT_LOOPS
1616 fprintf(fout, "---------------------------------------------------\n");
1617 fprintf(fout, "Total number of iterations in the CSE dataflow loop is %5u\n", CSEiterCount);
1618 fprintf(fout, "Total number of iterations in the CF dataflow loop is %5u\n", CFiterCount);
1620 #endif // DATAFLOW_ITER
1622 #if MEASURE_NODE_SIZE
1624 fprintf(fout, "\n");
1625 fprintf(fout, "---------------------------------------------------\n");
1626 fprintf(fout, "GenTree node allocation stats\n");
1627 fprintf(fout, "---------------------------------------------------\n");
1629 fprintf(fout, "Allocated %6I64u tree nodes (%7I64u bytes total, avg %4I64u bytes per method)\n",
1630 genNodeSizeStats.genTreeNodeCnt, genNodeSizeStats.genTreeNodeSize,
1631 genNodeSizeStats.genTreeNodeSize / genMethodCnt);
1633 fprintf(fout, "Allocated %7I64u bytes of unused tree node space (%3.2f%%)\n",
1634 genNodeSizeStats.genTreeNodeSize - genNodeSizeStats.genTreeNodeActualSize,
1635 (float)(100 * (genNodeSizeStats.genTreeNodeSize - genNodeSizeStats.genTreeNodeActualSize)) /
1636 genNodeSizeStats.genTreeNodeSize);
1638 fprintf(fout, "\n");
1639 fprintf(fout, "---------------------------------------------------\n");
1640 fprintf(fout, "Distribution of per-method GenTree node counts:\n");
1641 genTreeNcntHist.dump(fout);
1643 fprintf(fout, "\n");
1644 fprintf(fout, "---------------------------------------------------\n");
1645 fprintf(fout, "Distribution of per-method GenTree node allocations (in bytes):\n");
1646 genTreeNsizHist.dump(fout);
1648 #endif // MEASURE_NODE_SIZE
1650 #if MEASURE_BLOCK_SIZE
1652 fprintf(fout, "\n");
1653 fprintf(fout, "---------------------------------------------------\n");
1654 fprintf(fout, "BasicBlock and flowList/BasicBlockList allocation stats\n");
1655 fprintf(fout, "---------------------------------------------------\n");
1657 fprintf(fout, "Allocated %6u basic blocks (%7u bytes total, avg %4u bytes per method)\n", BasicBlock::s_Count,
1658 BasicBlock::s_Size, BasicBlock::s_Size / genMethodCnt);
1659 fprintf(fout, "Allocated %6u flow nodes (%7u bytes total, avg %4u bytes per method)\n", genFlowNodeCnt,
1660 genFlowNodeSize, genFlowNodeSize / genMethodCnt);
1662 #endif // MEASURE_BLOCK_SIZE
1664 #if MEASURE_MEM_ALLOC
1668 fprintf(fout, "\nAll allocations:\n");
1669 s_aggMemStats.Print(jitstdout);
1671 fprintf(fout, "\nLargest method:\n");
1672 s_maxCompMemStats.Print(jitstdout);
1674 fprintf(fout, "\n");
1675 fprintf(fout, "---------------------------------------------------\n");
1676 fprintf(fout, "Distribution of total memory allocated per method (in KB):\n");
1677 memAllocHist.dump(fout);
1679 fprintf(fout, "\n");
1680 fprintf(fout, "---------------------------------------------------\n");
1681 fprintf(fout, "Distribution of total memory used per method (in KB):\n");
1682 memUsedHist.dump(fout);
1685 #endif // MEASURE_MEM_ALLOC
1687 #if LOOP_HOIST_STATS
1688 #ifdef DEBUG // Always display loop stats in retail
1689 if (JitConfig.DisplayLoopHoistStats() != 0)
1692 PrintAggregateLoopHoistStats(jitstdout);
1694 #endif // LOOP_HOIST_STATS
1696 #if MEASURE_PTRTAB_SIZE
1698 fprintf(fout, "\n");
1699 fprintf(fout, "---------------------------------------------------\n");
1700 fprintf(fout, "GC pointer table stats\n");
1701 fprintf(fout, "---------------------------------------------------\n");
1703 fprintf(fout, "Reg pointer descriptor size (internal): %8u (avg %4u per method)\n", GCInfo::s_gcRegPtrDscSize,
1704 GCInfo::s_gcRegPtrDscSize / genMethodCnt);
1706 fprintf(fout, "Total pointer table size: %8u (avg %4u per method)\n", GCInfo::s_gcTotalPtrTabSize,
1707 GCInfo::s_gcTotalPtrTabSize / genMethodCnt);
1709 #endif // MEASURE_PTRTAB_SIZE
1711 #if MEASURE_NODE_SIZE || MEASURE_BLOCK_SIZE || MEASURE_PTRTAB_SIZE || DISPLAY_SIZES
1713 if (genMethodCnt != 0)
1715 fprintf(fout, "\n");
1716 fprintf(fout, "A total of %6u methods compiled", genMethodCnt);
1718 if (genMethodICnt || genMethodNCnt)
1720 fprintf(fout, " (%u interruptible, %u non-interruptible)", genMethodICnt, genMethodNCnt);
1722 #endif // DISPLAY_SIZES
1723 fprintf(fout, ".\n");
1726 #endif // MEASURE_NODE_SIZE || MEASURE_BLOCK_SIZE || MEASURE_PTRTAB_SIZE || DISPLAY_SIZES
1733 fprintf(fout, "\n");
1734 fprintf(fout, "---------------------------------------------------\n");
1735 fprintf(fout, "Fatal errors stats\n");
1736 fprintf(fout, "---------------------------------------------------\n");
1737 fprintf(fout, " badCode: %u\n", fatal_badCode);
1738 fprintf(fout, " noWay: %u\n", fatal_noWay);
1739 fprintf(fout, " NOMEM: %u\n", fatal_NOMEM);
1740 fprintf(fout, " noWayAssertBody: %u\n", fatal_noWayAssertBody);
1742 fprintf(fout, " noWayAssertBodyArgs: %u\n", fatal_noWayAssertBodyArgs);
1744 fprintf(fout, " NYI: %u\n", fatal_NYI);
1745 #endif // MEASURE_FATAL
1748 /*****************************************************************************
1749 * Display static data structure sizes.
1753 void Compiler::compDisplayStaticSizes(FILE* fout)
1756 #if MEASURE_NODE_SIZE
1757 GenTree::DumpNodeSizes(fout);
1760 #if MEASURE_BLOCK_SIZE
1762 BasicBlock* bbDummy = nullptr;
1764 fprintf(fout, "\n");
1765 fprintf(fout, "Offset / size of bbNext = %3u / %3u\n", offsetof(BasicBlock, bbNext),
1766 sizeof(bbDummy->bbNext));
1767 fprintf(fout, "Offset / size of bbNum = %3u / %3u\n", offsetof(BasicBlock, bbNum),
1768 sizeof(bbDummy->bbNum));
1769 fprintf(fout, "Offset / size of bbPostOrderNum = %3u / %3u\n", offsetof(BasicBlock, bbPostOrderNum),
1770 sizeof(bbDummy->bbPostOrderNum));
1771 fprintf(fout, "Offset / size of bbRefs = %3u / %3u\n", offsetof(BasicBlock, bbRefs),
1772 sizeof(bbDummy->bbRefs));
1773 fprintf(fout, "Offset / size of bbFlags = %3u / %3u\n", offsetof(BasicBlock, bbFlags),
1774 sizeof(bbDummy->bbFlags));
1775 fprintf(fout, "Offset / size of bbWeight = %3u / %3u\n", offsetof(BasicBlock, bbWeight),
1776 sizeof(bbDummy->bbWeight));
1777 fprintf(fout, "Offset / size of bbJumpKind = %3u / %3u\n", offsetof(BasicBlock, bbJumpKind),
1778 sizeof(bbDummy->bbJumpKind));
1779 fprintf(fout, "Offset / size of bbJumpOffs = %3u / %3u\n", offsetof(BasicBlock, bbJumpOffs),
1780 sizeof(bbDummy->bbJumpOffs));
1781 fprintf(fout, "Offset / size of bbJumpDest = %3u / %3u\n", offsetof(BasicBlock, bbJumpDest),
1782 sizeof(bbDummy->bbJumpDest));
1783 fprintf(fout, "Offset / size of bbJumpSwt = %3u / %3u\n", offsetof(BasicBlock, bbJumpSwt),
1784 sizeof(bbDummy->bbJumpSwt));
1785 fprintf(fout, "Offset / size of bbEntryState = %3u / %3u\n", offsetof(BasicBlock, bbEntryState),
1786 sizeof(bbDummy->bbEntryState));
1787 fprintf(fout, "Offset / size of bbStkTempsIn = %3u / %3u\n", offsetof(BasicBlock, bbStkTempsIn),
1788 sizeof(bbDummy->bbStkTempsIn));
1789 fprintf(fout, "Offset / size of bbStkTempsOut = %3u / %3u\n", offsetof(BasicBlock, bbStkTempsOut),
1790 sizeof(bbDummy->bbStkTempsOut));
1791 fprintf(fout, "Offset / size of bbTryIndex = %3u / %3u\n", offsetof(BasicBlock, bbTryIndex),
1792 sizeof(bbDummy->bbTryIndex));
1793 fprintf(fout, "Offset / size of bbHndIndex = %3u / %3u\n", offsetof(BasicBlock, bbHndIndex),
1794 sizeof(bbDummy->bbHndIndex));
1795 fprintf(fout, "Offset / size of bbCatchTyp = %3u / %3u\n", offsetof(BasicBlock, bbCatchTyp),
1796 sizeof(bbDummy->bbCatchTyp));
1797 fprintf(fout, "Offset / size of bbStkDepth = %3u / %3u\n", offsetof(BasicBlock, bbStkDepth),
1798 sizeof(bbDummy->bbStkDepth));
1799 fprintf(fout, "Offset / size of bbFPinVars = %3u / %3u\n", offsetof(BasicBlock, bbFPinVars),
1800 sizeof(bbDummy->bbFPinVars));
1801 fprintf(fout, "Offset / size of bbPreds = %3u / %3u\n", offsetof(BasicBlock, bbPreds),
1802 sizeof(bbDummy->bbPreds));
1803 fprintf(fout, "Offset / size of bbReach = %3u / %3u\n", offsetof(BasicBlock, bbReach),
1804 sizeof(bbDummy->bbReach));
1805 fprintf(fout, "Offset / size of bbIDom = %3u / %3u\n", offsetof(BasicBlock, bbIDom),
1806 sizeof(bbDummy->bbIDom));
1807 fprintf(fout, "Offset / size of bbDfsNum = %3u / %3u\n", offsetof(BasicBlock, bbDfsNum),
1808 sizeof(bbDummy->bbDfsNum));
1809 fprintf(fout, "Offset / size of bbCodeOffs = %3u / %3u\n", offsetof(BasicBlock, bbCodeOffs),
1810 sizeof(bbDummy->bbCodeOffs));
1811 fprintf(fout, "Offset / size of bbCodeOffsEnd = %3u / %3u\n", offsetof(BasicBlock, bbCodeOffsEnd),
1812 sizeof(bbDummy->bbCodeOffsEnd));
1813 fprintf(fout, "Offset / size of bbVarUse = %3u / %3u\n", offsetof(BasicBlock, bbVarUse),
1814 sizeof(bbDummy->bbVarUse));
1815 fprintf(fout, "Offset / size of bbVarDef = %3u / %3u\n", offsetof(BasicBlock, bbVarDef),
1816 sizeof(bbDummy->bbVarDef));
1817 fprintf(fout, "Offset / size of bbLiveIn = %3u / %3u\n", offsetof(BasicBlock, bbLiveIn),
1818 sizeof(bbDummy->bbLiveIn));
1819 fprintf(fout, "Offset / size of bbLiveOut = %3u / %3u\n", offsetof(BasicBlock, bbLiveOut),
1820 sizeof(bbDummy->bbLiveOut));
1821 fprintf(fout, "Offset / size of bbMemorySsaPhiFunc = %3u / %3u\n", offsetof(BasicBlock, bbMemorySsaPhiFunc),
1822 sizeof(bbDummy->bbMemorySsaPhiFunc));
1823 fprintf(fout, "Offset / size of bbMemorySsaNumIn = %3u / %3u\n", offsetof(BasicBlock, bbMemorySsaNumIn),
1824 sizeof(bbDummy->bbMemorySsaNumIn));
1825 fprintf(fout, "Offset / size of bbMemorySsaNumOut = %3u / %3u\n", offsetof(BasicBlock, bbMemorySsaNumOut),
1826 sizeof(bbDummy->bbMemorySsaNumOut));
1827 fprintf(fout, "Offset / size of bbScope = %3u / %3u\n", offsetof(BasicBlock, bbScope),
1828 sizeof(bbDummy->bbScope));
1829 fprintf(fout, "Offset / size of bbCseGen = %3u / %3u\n", offsetof(BasicBlock, bbCseGen),
1830 sizeof(bbDummy->bbCseGen));
1831 fprintf(fout, "Offset / size of bbCseIn = %3u / %3u\n", offsetof(BasicBlock, bbCseIn),
1832 sizeof(bbDummy->bbCseIn));
1833 fprintf(fout, "Offset / size of bbCseOut = %3u / %3u\n", offsetof(BasicBlock, bbCseOut),
1834 sizeof(bbDummy->bbCseOut));
1836 fprintf(fout, "Offset / size of bbEmitCookie = %3u / %3u\n", offsetof(BasicBlock, bbEmitCookie),
1837 sizeof(bbDummy->bbEmitCookie));
1839 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
1840 fprintf(fout, "Offset / size of bbUnwindNopEmitCookie = %3u / %3u\n", offsetof(BasicBlock, bbUnwindNopEmitCookie),
1841 sizeof(bbDummy->bbUnwindNopEmitCookie));
1842 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
1845 fprintf(fout, "Offset / size of bbStackIn = %3u / %3u\n", offsetof(BasicBlock, bbStackIn),
1846 sizeof(bbDummy->bbStackIn));
1847 fprintf(fout, "Offset / size of bbStackOut = %3u / %3u\n", offsetof(BasicBlock, bbStackOut),
1848 sizeof(bbDummy->bbStackOut));
1849 fprintf(fout, "Offset / size of bbTypesIn = %3u / %3u\n", offsetof(BasicBlock, bbTypesIn),
1850 sizeof(bbDummy->bbTypesIn));
1851 fprintf(fout, "Offset / size of bbTypesOut = %3u / %3u\n", offsetof(BasicBlock, bbTypesOut),
1852 sizeof(bbDummy->bbTypesOut));
1855 #if FEATURE_STACK_FP_X87
1856 fprintf(fout, "Offset / size of bbFPStateX87 = %3u / %3u\n", offsetof(BasicBlock, bbFPStateX87),
1857 sizeof(bbDummy->bbFPStateX87));
1858 #endif // FEATURE_STACK_FP_X87
1861 fprintf(fout, "Offset / size of bbLoopNum = %3u / %3u\n", offsetof(BasicBlock, bbLoopNum),
1862 sizeof(bbDummy->bbLoopNum));
1865 fprintf(fout, "\n");
1866 fprintf(fout, "Size of BasicBlock = %3u\n", sizeof(BasicBlock));
1868 #endif // MEASURE_BLOCK_SIZE
1871 emitterStaticStats(fout);
1875 /*****************************************************************************
1880 void Compiler::compInit(ArenaAllocator* pAlloc, InlineInfo* inlineInfo)
1883 compAllocator = pAlloc;
1885 // Inlinee Compile object will only be allocated when needed for the 1st time.
1886 InlineeCompiler = nullptr;
1888 // Set the inline info.
1889 impInlineInfo = inlineInfo;
1891 eeInfoInitialized = false;
1893 compDoAggressiveInlining = false;
1895 if (compIsForInlining())
1897 m_inlineStrategy = nullptr;
1898 compInlineResult = inlineInfo->inlineResult;
1900 // We shouldn't be using the compAllocatorGeneric for other than the root compiler.
1901 compAllocatorGeneric = nullptr;
1902 #if MEASURE_MEM_ALLOC
1903 compAllocatorBitset = nullptr;
1904 compAllocatorGC = nullptr;
1905 compAllocatorLoopHoist = nullptr;
1907 compAllocatorDebugOnly = nullptr;
1909 #endif // MEASURE_MEM_ALLOC
1911 #ifdef LEGACY_BACKEND
1912 compQMarks = nullptr;
1917 m_inlineStrategy = new (this, CMK_Inlining) InlineStrategy(this);
1918 compInlineResult = nullptr;
1920 compAllocatorGeneric = new (this, CMK_Unknown) CompAllocator(this, CMK_Generic);
1921 #if MEASURE_MEM_ALLOC
1922 compAllocatorBitset = new (this, CMK_Unknown) CompAllocator(this, CMK_bitset);
1923 compAllocatorGC = new (this, CMK_Unknown) CompAllocator(this, CMK_GC);
1924 compAllocatorLoopHoist = new (this, CMK_Unknown) CompAllocator(this, CMK_LoopHoist);
1926 compAllocatorDebugOnly = new (this, CMK_Unknown) CompAllocator(this, CMK_DebugOnly);
1928 #endif // MEASURE_MEM_ALLOC
1930 #ifdef LEGACY_BACKEND
1931 compQMarks = new (this, CMK_Unknown) JitExpandArrayStack<GenTree*>(getAllocator());
1935 #ifdef FEATURE_TRACELOGGING
1936 // Make sure JIT telemetry is initialized as soon as allocations can be made
1937 // but no later than a point where noway_asserts can be thrown.
1938 // 1. JIT telemetry could allocate some objects internally.
1939 // 2. NowayAsserts are tracked through telemetry.
1940 // Note: JIT telemetry could gather data when compiler is not fully initialized.
1941 // So you have to initialize the compiler variables you use for telemetry.
1942 assert((unsigned)PHASE_PRE_IMPORT == 0);
1943 previousCompletedPhase = PHASE_PRE_IMPORT;
1944 info.compILCodeSize = 0;
1945 info.compMethodHnd = nullptr;
1946 compJitTelemetry.Initialize(this);
1950 bRangeAllowStress = false;
1956 if (!compIsForInlining())
1958 codeGen = getCodeGenerator(this);
1959 #ifdef LEGACY_BACKEND
1961 #endif // LEGACY_BACKEND
1963 #ifndef LEGACY_BACKEND
1965 #endif // !LEGACY_BACKEND
1967 compVarScopeMap = nullptr;
1969 // If this method were a real constructor for Compiler, these would
1970 // become method initializations.
1971 impPendingBlockMembers = JitExpandArray<BYTE>(getAllocator());
1972 impSpillCliquePredMembers = JitExpandArray<BYTE>(getAllocator());
1973 impSpillCliqueSuccMembers = JitExpandArray<BYTE>(getAllocator());
1975 memset(&lvMemoryPerSsaData, 0, sizeof(PerSsaArray));
1976 lvMemoryPerSsaData.Init(getAllocator());
1977 lvMemoryNumSsaNames = 0;
1980 // Initialize all the per-method statistics gathering data structures.
1985 #if MEASURE_MEM_ALLOC
1987 #endif // MEASURE_MEM_ALLOC
1988 #if LOOP_HOIST_STATS
1989 m_loopsConsidered = 0;
1990 m_curLoopHasHoistedExpression = false;
1991 m_loopsWithHoistedExpressions = 0;
1992 m_totalHoistedExpressions = 0;
1993 #endif // LOOP_HOIST_STATS
1994 #if MEASURE_NODE_SIZE
1995 genNodeSizeStatsPerFunc.Init();
1996 #endif // MEASURE_NODE_SIZE
2003 compJmpOpUsed = false;
2004 compLongUsed = false;
2005 compTailCallUsed = false;
2006 compLocallocUsed = false;
2007 compLocallocOptimized = false;
2008 compQmarkRationalized = false;
2009 compQmarkUsed = false;
2010 compFloatingPointUsed = false;
2011 compUnsafeCastUsed = false;
2012 #if CPU_USES_BLOCK_MOVE
2013 compBlkOpUsed = false;
2015 #if FEATURE_STACK_FP_X87
2016 compMayHaveTransitionBlocks = false;
2018 compNeedsGSSecurityCookie = false;
2019 compGSReorderStackLayout = false;
2021 compStackProbePrologDone = false;
2024 compGeneratingProlog = false;
2025 compGeneratingEpilog = false;
2027 #ifndef LEGACY_BACKEND
2028 compLSRADone = false;
2029 #endif // !LEGACY_BACKEND
2030 compRationalIRForm = false;
2033 compCodeGenDone = false;
2034 compRegSetCheckLevel = 0;
2035 opts.compMinOptsIsUsed = false;
2037 opts.compMinOptsIsSet = false;
2039 // Used by fgFindJumpTargets for inlining heuristics.
2040 opts.instrCount = 0;
2042 // Used to track when we should consider running EarlyProp
2045 for (unsigned i = 0; i < MAX_LOOP_NUM; i++)
2047 AllVarSetOps::AssignNoCopy(this, optLoopTable[i].lpAsgVars, AllVarSetOps::UninitVal());
2051 m_nodeTestData = nullptr;
2052 m_loopHoistCSEClass = FIRST_LOOP_HOIST_CSE_CLASS;
2054 m_switchDescMap = nullptr;
2055 m_blockToEHPreds = nullptr;
2056 m_fieldSeqStore = nullptr;
2057 m_zeroOffsetFieldMap = nullptr;
2058 m_arrayInfoMap = nullptr;
2059 m_refAnyClass = nullptr;
2060 for (MemoryKind memoryKind : allMemoryKinds())
2062 m_memorySsaMap[memoryKind] = nullptr;
2066 if (!compIsForInlining())
2068 compDoComponentUnitTestsOnce();
2073 m_opAsgnVarDefSsaNums = nullptr;
2074 m_indirAssignMap = nullptr;
2075 fgSsaPassesCompleted = 0;
2076 fgVNPassesCompleted = 0;
2078 // check that HelperCallProperties are initialized
2080 assert(s_helperCallProperties.IsPure(CORINFO_HELP_GETSHARED_GCSTATIC_BASE));
2081 assert(!s_helperCallProperties.IsPure(CORINFO_HELP_GETFIELDOBJ)); // quick sanity check
2083 // We start with the flow graph in tree-order
2084 fgOrder = FGOrderTree;
2088 SIMDFloatHandle = nullptr;
2089 SIMDDoubleHandle = nullptr;
2090 SIMDIntHandle = nullptr;
2091 SIMDUShortHandle = nullptr;
2092 SIMDUByteHandle = nullptr;
2093 SIMDShortHandle = nullptr;
2094 SIMDByteHandle = nullptr;
2095 SIMDLongHandle = nullptr;
2096 SIMDUIntHandle = nullptr;
2097 SIMDULongHandle = nullptr;
2098 SIMDVector2Handle = nullptr;
2099 SIMDVector3Handle = nullptr;
2100 SIMDVector4Handle = nullptr;
2101 SIMDVectorHandle = nullptr;
2102 #ifdef FEATURE_HW_INTRINSICS
2103 #if defined(_TARGET_ARM64_)
2104 Vector64FloatHandle = nullptr;
2105 Vector64UIntHandle = nullptr;
2106 Vector64UShortHandle = nullptr;
2107 Vector64UByteHandle = nullptr;
2108 Vector64IntHandle = nullptr;
2109 Vector64ShortHandle = nullptr;
2110 Vector64ByteHandle = nullptr;
2111 #endif // defined(_TARGET_ARM64_)
2112 Vector128FloatHandle = nullptr;
2113 Vector128DoubleHandle = nullptr;
2114 Vector128IntHandle = nullptr;
2115 Vector128UShortHandle = nullptr;
2116 Vector128UByteHandle = nullptr;
2117 Vector128ShortHandle = nullptr;
2118 Vector128ByteHandle = nullptr;
2119 Vector128LongHandle = nullptr;
2120 Vector128UIntHandle = nullptr;
2121 Vector128ULongHandle = nullptr;
2122 #if defined(_TARGET_XARCH_)
2123 Vector256FloatHandle = nullptr;
2124 Vector256DoubleHandle = nullptr;
2125 Vector256IntHandle = nullptr;
2126 Vector256UShortHandle = nullptr;
2127 Vector256UByteHandle = nullptr;
2128 Vector256ShortHandle = nullptr;
2129 Vector256ByteHandle = nullptr;
2130 Vector256LongHandle = nullptr;
2131 Vector256UIntHandle = nullptr;
2132 Vector256ULongHandle = nullptr;
2133 #endif // defined(_TARGET_XARCH_)
2134 #endif // FEATURE_HW_INTRINSICS
2135 #endif // FEATURE_SIMD
2137 compUsesThrowHelper = false;
2140 /*****************************************************************************
2145 void Compiler::compDone()
2149 void* Compiler::compGetHelperFtn(CorInfoHelpFunc ftnNum, /* IN */
2150 void** ppIndirection) /* OUT */
2154 if (info.compMatchedVM)
2156 addr = info.compCompHnd->getHelperFtn(ftnNum, ppIndirection);
2160 // If we don't have a matched VM, we won't get valid results when asking for a helper function.
2161 addr = (void*)0xCA11CA11; // "callcall"
2167 unsigned Compiler::compGetTypeSize(CorInfoType cit, CORINFO_CLASS_HANDLE clsHnd)
2169 var_types sigType = genActualType(JITtype2varType(cit));
2171 sigSize = genTypeSize(sigType);
2172 if (cit == CORINFO_TYPE_VALUECLASS)
2174 sigSize = info.compCompHnd->getClassSize(clsHnd);
2176 else if (cit == CORINFO_TYPE_REFANY)
2178 sigSize = 2 * TARGET_POINTER_SIZE;
2184 static bool DidComponentUnitTests = false;
2186 void Compiler::compDoComponentUnitTestsOnce()
2188 if (!JitConfig.RunComponentUnitTests())
2193 if (!DidComponentUnitTests)
2195 DidComponentUnitTests = true;
2196 ValueNumStore::RunTests(this);
2197 BitSetSupport::TestSuite(getAllocatorDebugOnly());
2201 //------------------------------------------------------------------------
2202 // compGetJitDefaultFill:
2205 // An unsigned char value used to initizalize memory allocated by the JIT.
2206 // The default value is taken from COMPLUS_JitDefaultFill, if is not set
2207 // the value will be 0xdd. When JitStress is active a random value based
2208 // on the method hash is used.
2211 // Note that we can't use small values like zero, because we have some
2212 // asserts that can fire for such values.
2214 unsigned char Compiler::compGetJitDefaultFill()
2216 unsigned char defaultFill = (unsigned char)JitConfig.JitDefaultFill();
2218 if ((this != nullptr) && (compStressCompile(STRESS_GENERIC_VARN, 50)))
2221 temp = info.compMethodHash();
2222 temp = (temp >> 16) ^ temp;
2223 temp = (temp >> 8) ^ temp;
2225 // asserts like this: assert(!IsUninitialized(stkLvl));
2226 // mean that small values for defaultFill are problematic
2227 // so we make the value larger in that case.
2232 defaultFill = (unsigned char)temp;
2240 /*****************************************************************************
2242 * The central memory allocation routine used by the compiler. Normally this
2243 * is a simple inline method defined in compiler.hpp, but for debugging it's
2244 * often convenient to keep it non-inline.
2249 void* Compiler::compGetMem(size_t sz, CompMemKind cmk)
2252 #if SMALL_TREE_NODES
2253 if (sz != TREE_NODE_SZ_SMALL &&
2254 sz != TREE_NODE_SZ_LARGE && sz > 32)
2256 printf("Alloc %3u bytes\n", sz);
2259 if (sz != sizeof(GenTree) && sz > 32)
2261 printf("Alloc %3u bytes\n", sz);
2266 #if MEASURE_MEM_ALLOC
2267 genMemStats.AddAlloc(sz, cmk);
2270 void* ptr = compAllocator->allocateMemory(sz);
2272 // Verify that the current block is aligned. Only then will the next
2273 // block allocated be on an aligned boundary.
2274 assert((size_t(ptr) & (sizeof(size_t) - 1)) == 0);
2281 /*****************************************************************************/
2283 /*****************************************************************************/
2285 VarName Compiler::compVarName(regNumber reg, bool isFloatReg)
2289 #if FEATURE_STACK_FP_X87
2290 assert(reg < FP_STK_SIZE); // would like to have same assert as below but sometimes you get -1?
2292 assert(genIsValidFloatReg(reg));
2297 assert(genIsValidReg(reg));
2300 if ((info.compVarScopesCount > 0) && compCurBB && opts.varNames)
2305 /* Look for the matching register */
2306 for (lclNum = 0, varDsc = lvaTable; lclNum < lvaCount; lclNum++, varDsc++)
2308 /* If the variable is not in a register, or not in the register we're looking for, quit. */
2309 /* Also, if it is a compiler generated variable (i.e. slot# > info.compVarScopesCount), don't bother. */
2310 if ((varDsc->lvRegister != 0) && (varDsc->lvRegNum == reg) && (varDsc->IsFloatRegType() || !isFloatReg) &&
2311 (varDsc->lvSlotNum < info.compVarScopesCount))
2313 /* check if variable in that register is live */
2314 if (VarSetOps::IsMember(this, compCurLife, varDsc->lvVarIndex))
2316 /* variable is live - find the corresponding slot */
2317 VarScopeDsc* varScope =
2318 compFindLocalVar(varDsc->lvSlotNum, compCurBB->bbCodeOffs, compCurBB->bbCodeOffsEnd);
2321 return varScope->vsdName;
2327 #ifdef LEGACY_BACKEND
2328 // maybe var is marked dead, but still used (last use)
2329 if (!isFloatReg && codeGen->regSet.rsUsedTree[reg] != NULL)
2333 if (GenTree::OperIsUnary(codeGen->regSet.rsUsedTree[reg]->OperGet()))
2335 assert(codeGen->regSet.rsUsedTree[reg]->gtOp.gtOp1 != NULL);
2336 nodePtr = codeGen->regSet.rsUsedTree[reg]->gtOp.gtOp1;
2340 nodePtr = codeGen->regSet.rsUsedTree[reg];
2343 if ((nodePtr->gtOper == GT_REG_VAR) && (nodePtr->gtRegVar.gtRegNum == reg) &&
2344 (nodePtr->gtRegVar.gtLclNum < info.compVarScopesCount))
2346 VarScopeDsc* varScope =
2347 compFindLocalVar(nodePtr->gtRegVar.gtLclNum, compCurBB->bbCodeOffs, compCurBB->bbCodeOffsEnd);
2349 return varScope->vsdName;
2352 #endif // LEGACY_BACKEND
2357 const char* Compiler::compRegVarName(regNumber reg, bool displayVar, bool isFloatReg)
2361 isFloatReg = genIsValidFloatReg(reg);
2364 if (displayVar && (reg != REG_NA))
2366 VarName varName = compVarName(reg, isFloatReg);
2370 const int NAME_VAR_REG_BUFFER_LEN = 4 + 256 + 1;
2371 static char nameVarReg[2][NAME_VAR_REG_BUFFER_LEN]; // to avoid overwriting the buffer when have 2
2372 // consecutive calls before printing
2373 static int index = 0; // for circular index into the name array
2375 index = (index + 1) % 2; // circular reuse of index
2376 sprintf_s(nameVarReg[index], NAME_VAR_REG_BUFFER_LEN, "%s'%s'", getRegName(reg, isFloatReg),
2377 VarNameToStr(varName));
2379 return nameVarReg[index];
2383 /* no debug info required or no variable in that register
2384 -> return standard name */
2386 return getRegName(reg, isFloatReg);
2389 #define MAX_REG_PAIR_NAME_LENGTH 10
2391 const char* Compiler::compRegPairName(regPairNo regPair)
2393 static char regNameLong[MAX_REG_PAIR_NAME_LENGTH];
2395 if (regPair == REG_PAIR_NONE)
2400 assert(regPair >= REG_PAIR_FIRST && regPair <= REG_PAIR_LAST);
2402 strcpy_s(regNameLong, sizeof(regNameLong), compRegVarName(genRegPairLo(regPair)));
2403 strcat_s(regNameLong, sizeof(regNameLong), "|");
2404 strcat_s(regNameLong, sizeof(regNameLong), compRegVarName(genRegPairHi(regPair)));
2408 const char* Compiler::compRegNameForSize(regNumber reg, size_t size)
2410 if (size == 0 || size >= 4)
2412 return compRegVarName(reg, true);
2417 const char * sizeNames[][2] =
2423 #ifdef _TARGET_AMD64_
2424 { "spl", "sp" }, // ESP
2425 { "bpl", "bp" }, // EBP
2426 { "sil", "si" }, // ESI
2427 { "dil", "di" }, // EDI
2436 #endif // _TARGET_AMD64_
2440 assert(isByteReg(reg));
2441 assert(genRegMask(reg) & RBM_BYTE_REGS);
2442 assert(size == 1 || size == 2);
2444 return sizeNames[reg][size - 1];
2447 const char* Compiler::compFPregVarName(unsigned fpReg, bool displayVar)
2449 const int NAME_VAR_REG_BUFFER_LEN = 4 + 256 + 1;
2450 static char nameVarReg[2][NAME_VAR_REG_BUFFER_LEN]; // to avoid overwriting the buffer when have 2 consecutive calls
2452 static int index = 0; // for circular index into the name array
2454 index = (index + 1) % 2; // circular reuse of index
2456 #if FEATURE_STACK_FP_X87
2457 /* 'fpReg' is the distance from the bottom of the stack, ie.
2458 * it is independant of the current FP stack level
2461 if (displayVar && codeGen->genFPregCnt)
2463 assert(fpReg < FP_STK_SIZE);
2464 assert(compCodeGenDone || (fpReg <= codeGen->compCurFPState.m_uStackSize));
2466 int pos = codeGen->genFPregCnt - (fpReg + 1 - codeGen->genGetFPstkLevel());
2469 VarName varName = compVarName((regNumber)pos, true);
2473 sprintf_s(nameVarReg[index], NAME_VAR_REG_BUFFER_LEN, "ST(%d)'%s'", fpReg, VarNameToStr(varName));
2474 return nameVarReg[index];
2478 #endif // FEATURE_STACK_FP_X87
2480 /* no debug info required or no variable in that register
2481 -> return standard name */
2483 sprintf_s(nameVarReg[index], NAME_VAR_REG_BUFFER_LEN, "ST(%d)", fpReg);
2484 return nameVarReg[index];
2487 const char* Compiler::compLocalVarName(unsigned varNum, unsigned offs)
2492 for (i = 0, t = info.compVarScopes; i < info.compVarScopesCount; i++, t++)
2494 if (t->vsdVarNum != varNum)
2499 if (offs >= t->vsdLifeBeg && offs < t->vsdLifeEnd)
2501 return VarNameToStr(t->vsdName);
2508 /*****************************************************************************/
2510 /*****************************************************************************/
2512 #ifdef _TARGET_XARCH_
2513 static bool configEnableISA(InstructionSet isa)
2518 case InstructionSet_SSE:
2519 return JitConfig.EnableSSE() != 0;
2520 case InstructionSet_SSE2:
2521 return JitConfig.EnableSSE2() != 0;
2522 case InstructionSet_SSE3:
2523 return JitConfig.EnableSSE3() != 0;
2524 case InstructionSet_SSSE3:
2525 return JitConfig.EnableSSSE3() != 0;
2526 case InstructionSet_SSE41:
2527 return JitConfig.EnableSSE41() != 0;
2528 case InstructionSet_SSE42:
2529 return JitConfig.EnableSSE42() != 0;
2530 case InstructionSet_AVX:
2531 return JitConfig.EnableAVX() != 0;
2532 case InstructionSet_AVX2:
2533 // Don't enable AVX2 when AVX is disabled
2534 return (JitConfig.EnableAVX() != 0) && (JitConfig.EnableAVX2() != 0);
2536 case InstructionSet_AES:
2537 return JitConfig.EnableAES() != 0;
2538 case InstructionSet_BMI1:
2539 return JitConfig.EnableBMI1() != 0;
2540 case InstructionSet_BMI2:
2541 return JitConfig.EnableBMI2() != 0;
2542 case InstructionSet_FMA:
2543 return JitConfig.EnableFMA() != 0;
2544 case InstructionSet_LZCNT:
2545 return JitConfig.EnableLZCNT() != 0;
2546 case InstructionSet_PCLMULQDQ:
2547 return JitConfig.EnablePCLMULQDQ() != 0;
2548 case InstructionSet_POPCNT:
2549 return JitConfig.EnablePOPCNT() != 0;
2554 // We have a retail config switch that can disable AVX/AVX2 instructions
2555 if ((isa == InstructionSet_AVX) || (isa == InstructionSet_AVX2))
2557 return JitConfig.EnableAVX() != 0;
2565 #endif // _TARGET_XARCH_
2567 void Compiler::compSetProcessor()
2569 const JitFlags& jitFlags = *opts.jitFlags;
2571 #if defined(_TARGET_ARM_)
2572 info.genCPU = CPU_ARM;
2573 #elif defined(_TARGET_AMD64_)
2574 info.genCPU = CPU_X64;
2575 #elif defined(_TARGET_X86_)
2576 if (jitFlags.IsSet(JitFlags::JIT_FLAG_TARGET_P4))
2577 info.genCPU = CPU_X86_PENTIUM_4;
2579 info.genCPU = CPU_X86;
2583 // Processor specific optimizations
2585 CLANG_FORMAT_COMMENT_ANCHOR;
2587 #ifdef _TARGET_AMD64_
2588 opts.compUseFCOMI = false;
2589 opts.compUseCMOV = true;
2590 opts.compCanUseSSE2 = true;
2591 #elif defined(_TARGET_X86_)
2592 opts.compUseFCOMI = jitFlags.IsSet(JitFlags::JIT_FLAG_USE_FCOMI);
2593 opts.compUseCMOV = jitFlags.IsSet(JitFlags::JIT_FLAG_USE_CMOV);
2595 #ifdef LEGACY_BACKEND
2596 opts.compCanUseSSE2 = jitFlags.IsSet(JitFlags::JIT_FLAG_USE_SSE2);
2598 // RyuJIT/x86 requires SSE2 to be available: there is no support for generating floating-point
2599 // code with x87 instructions.
2600 opts.compCanUseSSE2 = true;
2604 if (opts.compUseFCOMI)
2605 opts.compUseFCOMI = !compStressCompile(STRESS_USE_FCOMI, 50);
2606 if (opts.compUseCMOV)
2607 opts.compUseCMOV = !compStressCompile(STRESS_USE_CMOV, 50);
2609 #ifdef LEGACY_BACKEND
2611 // Should we override the SSE2 setting?
2614 SSE2_FORCE_DISABLE = 0,
2616 SSE2_FORCE_INVALID = -1
2619 if (JitConfig.JitCanUseSSE2() == SSE2_FORCE_DISABLE)
2620 opts.compCanUseSSE2 = false;
2621 else if (JitConfig.JitCanUseSSE2() == SSE2_FORCE_USE)
2622 opts.compCanUseSSE2 = true;
2623 else if (opts.compCanUseSSE2)
2624 opts.compCanUseSSE2 = !compStressCompile(STRESS_GENERIC_VARN, 50);
2626 #else // !LEGACY_BACKEND
2628 // RyuJIT/x86 requires SSE2 to be available and hence
2629 // don't turn off compCanUseSSE2 under stress.
2630 assert(opts.compCanUseSSE2);
2632 #endif // !LEGACY_BACKEND
2636 #endif // _TARGET_X86_
2638 // Instruction set flags for Intel hardware intrinsics
2639 #ifdef _TARGET_XARCH_
2640 opts.compSupportsISA = 0;
2642 if (!jitFlags.IsSet(JitFlags::JIT_FLAG_PREJIT))
2644 if (opts.compCanUseSSE2)
2646 if (configEnableISA(InstructionSet_SSE))
2648 opts.setSupportedISA(InstructionSet_SSE);
2650 if (configEnableISA(InstructionSet_SSE2))
2652 opts.setSupportedISA(InstructionSet_SSE2);
2654 if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_AES))
2656 if (configEnableISA(InstructionSet_AES))
2658 opts.setSupportedISA(InstructionSet_AES);
2661 if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_AVX))
2663 if (configEnableISA(InstructionSet_AVX))
2665 opts.setSupportedISA(InstructionSet_AVX);
2668 if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_AVX2))
2670 // COMPlus_EnableAVX is also used to control the code generation of
2671 // System.Numerics.Vectors and floating-point arithmetics
2672 if (configEnableISA(InstructionSet_AVX) && configEnableISA(InstructionSet_AVX2))
2674 opts.setSupportedISA(InstructionSet_AVX2);
2677 if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_BMI1))
2679 if (configEnableISA(InstructionSet_BMI1))
2681 opts.setSupportedISA(InstructionSet_BMI1);
2684 if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_BMI2))
2686 if (configEnableISA(InstructionSet_BMI2))
2688 opts.setSupportedISA(InstructionSet_BMI2);
2691 if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_FMA))
2693 if (configEnableISA(InstructionSet_FMA))
2695 opts.setSupportedISA(InstructionSet_FMA);
2698 if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_LZCNT))
2700 if (configEnableISA(InstructionSet_LZCNT))
2702 opts.setSupportedISA(InstructionSet_LZCNT);
2705 if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_PCLMULQDQ))
2707 if (configEnableISA(InstructionSet_PCLMULQDQ))
2709 opts.setSupportedISA(InstructionSet_PCLMULQDQ);
2712 if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_POPCNT))
2714 if (configEnableISA(InstructionSet_POPCNT))
2716 opts.setSupportedISA(InstructionSet_POPCNT);
2720 // There are currently two sets of flags that control SSE3 through SSE4.2 support
2721 // This is the general EnableSSE3_4 flag and the individual ISA flags. We need to
2722 // check both for any given ISA.
2723 if (JitConfig.EnableSSE3_4())
2725 if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_SSE3))
2727 if (configEnableISA(InstructionSet_SSE3))
2729 opts.setSupportedISA(InstructionSet_SSE3);
2732 if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_SSE41))
2734 if (configEnableISA(InstructionSet_SSE41))
2736 opts.setSupportedISA(InstructionSet_SSE41);
2739 if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_SSE42))
2741 if (configEnableISA(InstructionSet_SSE42))
2743 opts.setSupportedISA(InstructionSet_SSE42);
2746 if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_SSSE3))
2748 if (configEnableISA(InstructionSet_SSSE3))
2750 opts.setSupportedISA(InstructionSet_SSSE3);
2757 if (!compIsForInlining())
2759 if (canUseVexEncoding())
2761 codeGen->getEmitter()->SetUseVEXEncoding(true);
2762 // Assume each JITted method does not contain AVX instruction at first
2763 codeGen->getEmitter()->SetContainsAVX(false);
2764 codeGen->getEmitter()->SetContains256bitAVX(false);
2766 else if (compSupports(InstructionSet_SSSE3) || compSupports(InstructionSet_SSE41) ||
2767 compSupports(InstructionSet_SSE42))
2769 // Emitter::UseSSE4 controls whether we support the 4-byte encoding for certain
2770 // instructions. We need to check if either is supported independently, since
2771 // it is currently possible to enable/disable them separately.
2772 codeGen->getEmitter()->SetUseSSE4(true);
2776 #if defined(_TARGET_ARM64_)
2777 // There is no JitFlag for Base instructions handle manually
2778 opts.setSupportedISA(InstructionSet_Base);
2779 #define HARDWARE_INTRINSIC_CLASS(flag, isa) \
2780 if (jitFlags.IsSet(JitFlags::flag)) \
2781 opts.setSupportedISA(InstructionSet_##isa);
2782 #include "hwintrinsiclistArm64.h"
2787 #ifdef PROFILING_SUPPORTED
2788 // A Dummy routine to receive Enter/Leave/Tailcall profiler callbacks.
2789 // These are used when complus_JitEltHookEnabled=1
2790 #ifdef _TARGET_AMD64_
2791 void DummyProfilerELTStub(UINT_PTR ProfilerHandle, UINT_PTR callerSP)
2795 #else //! _TARGET_AMD64_
2796 void DummyProfilerELTStub(UINT_PTR ProfilerHandle)
2800 #endif //!_TARGET_AMD64_
2802 #endif // PROFILING_SUPPORTED
2804 bool Compiler::compIsFullTrust()
2806 return (info.compCompHnd->canSkipMethodVerification(info.compMethodHnd) == CORINFO_VERIFICATION_CAN_SKIP);
2809 bool Compiler::compShouldThrowOnNoway(
2810 #ifdef FEATURE_TRACELOGGING
2811 const char* filename, unsigned line
2815 #ifdef FEATURE_TRACELOGGING
2816 compJitTelemetry.NotifyNowayAssert(filename, line);
2819 // In min opts, we don't want the noway assert to go through the exception
2820 // path. Instead we want it to just silently go through codegen for
2822 // If we are not in full trust, we should always fire for security.
2823 return !opts.MinOpts() || !compIsFullTrust();
2826 // ConfigInteger does not offer an option for decimal flags. Any numbers are interpreted as hex.
2827 // I could add the decimal option to ConfigInteger or I could write a function to reinterpret this
2828 // value as the user intended.
2829 unsigned ReinterpretHexAsDecimal(unsigned in)
2831 // ex: in: 0x100 returns: 100
2832 unsigned result = 0;
2843 unsigned digit = in % 16;
2846 result += digit * index;
2852 void Compiler::compInitOptions(JitFlags* jitFlags)
2854 #ifdef UNIX_AMD64_ABI
2855 opts.compNeedToAlignFrame = false;
2856 #endif // UNIX_AMD64_ABI
2857 memset(&opts, 0, sizeof(opts));
2859 if (compIsForInlining())
2861 // The following flags are lost when inlining. (They are removed in
2862 // Compiler::fgInvokeInlineeCompiler().)
2863 assert(!jitFlags->IsSet(JitFlags::JIT_FLAG_BBOPT));
2864 assert(!jitFlags->IsSet(JitFlags::JIT_FLAG_BBINSTR));
2865 assert(!jitFlags->IsSet(JitFlags::JIT_FLAG_PROF_ENTERLEAVE));
2866 assert(!jitFlags->IsSet(JitFlags::JIT_FLAG_DEBUG_EnC));
2867 assert(!jitFlags->IsSet(JitFlags::JIT_FLAG_DEBUG_INFO));
2869 assert(jitFlags->IsSet(JitFlags::JIT_FLAG_SKIP_VERIFICATION));
2872 opts.jitFlags = jitFlags;
2873 opts.compFlags = CLFLG_MAXOPT; // Default value is for full optimization
2875 if (jitFlags->IsSet(JitFlags::JIT_FLAG_DEBUG_CODE) || jitFlags->IsSet(JitFlags::JIT_FLAG_MIN_OPT) ||
2876 jitFlags->IsSet(JitFlags::JIT_FLAG_TIER0))
2878 opts.compFlags = CLFLG_MINOPT;
2880 // Don't optimize .cctors (except prejit) or if we're an inlinee
2881 else if (!jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT) && ((info.compFlags & FLG_CCTOR) == FLG_CCTOR) &&
2882 !compIsForInlining())
2884 opts.compFlags = CLFLG_MINOPT;
2887 // Default value is to generate a blend of size and speed optimizations
2889 opts.compCodeOpt = BLENDED_CODE;
2891 // If the EE sets SIZE_OPT or if we are compiling a Class constructor
2892 // we will optimize for code size at the expense of speed
2894 if (jitFlags->IsSet(JitFlags::JIT_FLAG_SIZE_OPT) || ((info.compFlags & FLG_CCTOR) == FLG_CCTOR))
2896 opts.compCodeOpt = SMALL_CODE;
2899 // If the EE sets SPEED_OPT we will optimize for speed at the expense of code size
2901 else if (jitFlags->IsSet(JitFlags::JIT_FLAG_SPEED_OPT) ||
2902 (jitFlags->IsSet(JitFlags::JIT_FLAG_TIER1) && !jitFlags->IsSet(JitFlags::JIT_FLAG_MIN_OPT)))
2904 opts.compCodeOpt = FAST_CODE;
2905 assert(!jitFlags->IsSet(JitFlags::JIT_FLAG_SIZE_OPT));
2908 //-------------------------------------------------------------------------
2910 opts.compDbgCode = jitFlags->IsSet(JitFlags::JIT_FLAG_DEBUG_CODE);
2911 opts.compDbgInfo = jitFlags->IsSet(JitFlags::JIT_FLAG_DEBUG_INFO);
2912 opts.compDbgEnC = jitFlags->IsSet(JitFlags::JIT_FLAG_DEBUG_EnC);
2914 #if REGEN_SHORTCUTS || REGEN_CALLPAT
2915 // We never want to have debugging enabled when regenerating GC encoding patterns
2916 opts.compDbgCode = false;
2917 opts.compDbgInfo = false;
2918 opts.compDbgEnC = false;
2924 opts.dspOrder = false;
2925 if (compIsForInlining())
2927 verbose = impInlineInfo->InlinerCompiler->verbose;
2932 codeGen->setVerbose(false);
2934 verboseTrees = verbose && shouldUseVerboseTrees();
2935 verboseSsa = verbose && shouldUseVerboseSsa();
2936 asciiTrees = shouldDumpASCIITrees();
2937 opts.dspDiffable = compIsForInlining() ? impInlineInfo->InlinerCompiler->opts.dspDiffable : false;
2940 opts.compNeedSecurityCheck = false;
2941 opts.altJit = false;
2943 #if defined(LATE_DISASM) && !defined(DEBUG)
2944 // For non-debug builds with the late disassembler built in, we currently always do late disassembly
2945 // (we have no way to determine when not to, since we don't have class/method names).
2946 // In the DEBUG case, this is initialized to false, below.
2947 opts.doLateDisasm = true;
2952 const JitConfigValues::MethodSet* pfAltJit;
2953 if (jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
2955 pfAltJit = &JitConfig.AltJitNgen();
2959 pfAltJit = &JitConfig.AltJit();
2963 if (pfAltJit->contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
2968 unsigned altJitLimit = ReinterpretHexAsDecimal(JitConfig.AltJitLimit());
2969 if (altJitLimit > 0 && Compiler::jitTotalMethodCompiled >= altJitLimit)
2971 opts.altJit = false;
2977 const char* altJitVal;
2978 if (jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
2980 altJitVal = JitConfig.AltJitNgen().list();
2984 altJitVal = JitConfig.AltJit().list();
2988 // In release mode, you either get all methods or no methods. You must use "*" as the parameter, or we ignore it.
2989 // You don't get to give a regular expression of methods to match.
2990 // (Partially, this is because we haven't computed and stored the method and class name except in debug, and it
2991 // might be expensive to do so.)
2992 if ((altJitVal != nullptr) && (strcmp(altJitVal, "*") == 0))
3001 // Take care of COMPlus_AltJitExcludeAssemblies.
3004 // First, initialize the AltJitExcludeAssemblies list, but only do it once.
3005 if (!s_pAltJitExcludeAssembliesListInitialized)
3007 const wchar_t* wszAltJitExcludeAssemblyList = JitConfig.AltJitExcludeAssemblies();
3008 if (wszAltJitExcludeAssemblyList != nullptr)
3010 // NOTE: The Assembly name list is allocated in the process heap, not in the no-release heap, which is
3012 // for every compilation. This is ok because we only allocate once, due to the static.
3013 s_pAltJitExcludeAssembliesList = new (HostAllocator::getHostAllocator())
3014 AssemblyNamesList2(wszAltJitExcludeAssemblyList, HostAllocator::getHostAllocator());
3016 s_pAltJitExcludeAssembliesListInitialized = true;
3019 if (s_pAltJitExcludeAssembliesList != nullptr)
3021 // We have an exclusion list. See if this method is in an assembly that is on the list.
3022 // Note that we check this for every method, since we might inline across modules, and
3023 // if the inlinee module is on the list, we don't want to use the altjit for it.
3024 const char* methodAssemblyName = info.compCompHnd->getAssemblyName(
3025 info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd)));
3026 if (s_pAltJitExcludeAssembliesList->IsInList(methodAssemblyName))
3028 opts.altJit = false;
3036 bool altJitConfig = !pfAltJit->isEmpty();
3038 // If we have a non-empty AltJit config then we change all of these other
3039 // config values to refer only to the AltJit. Otherwise, a lot of COMPlus_* variables
3040 // would apply to both the altjit and the normal JIT, but we only care about
3041 // debugging the altjit if the COMPlus_AltJit configuration is set.
3043 if (compIsForImportOnly() && (!altJitConfig || opts.altJit))
3045 if (JitConfig.JitImportBreak().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3047 assert(!"JitImportBreak reached");
3051 bool verboseDump = false;
3052 bool dumpIR = false;
3053 bool dumpIRTypes = false;
3054 bool dumpIRLocals = false;
3055 bool dumpIRRegs = false;
3056 bool dumpIRSsa = false;
3057 bool dumpIRValnums = false;
3058 bool dumpIRCosts = false;
3059 bool dumpIRFlags = false;
3060 bool dumpIRKinds = false;
3061 bool dumpIRNodes = false;
3062 bool dumpIRNoLists = false;
3063 bool dumpIRNoLeafs = false;
3064 bool dumpIRNoStmts = false;
3065 bool dumpIRTrees = false;
3066 bool dumpIRLinear = false;
3067 bool dumpIRDataflow = false;
3068 bool dumpIRBlockHeaders = false;
3069 bool dumpIRExit = false;
3070 LPCWSTR dumpIRPhase = nullptr;
3071 LPCWSTR dumpIRFormat = nullptr;
3073 if (!altJitConfig || opts.altJit)
3075 LPCWSTR dumpIRFormat = nullptr;
3077 // We should only enable 'verboseDump' when we are actually compiling a matching method
3078 // and not enable it when we are just considering inlining a matching method.
3080 if (!compIsForInlining())
3082 if (jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
3084 if (JitConfig.NgenDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3088 unsigned ngenHashDumpVal = (unsigned)JitConfig.NgenHashDump();
3089 if ((ngenHashDumpVal != (DWORD)-1) && (ngenHashDumpVal == info.compMethodHash()))
3093 if (JitConfig.NgenDumpIR().contains(info.compMethodName, info.compClassName,
3094 &info.compMethodInfo->args))
3098 unsigned ngenHashDumpIRVal = (unsigned)JitConfig.NgenHashDumpIR();
3099 if ((ngenHashDumpIRVal != (DWORD)-1) && (ngenHashDumpIRVal == info.compMethodHash()))
3103 dumpIRFormat = JitConfig.NgenDumpIRFormat();
3104 dumpIRPhase = JitConfig.NgenDumpIRPhase();
3108 if (JitConfig.JitDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3112 unsigned jitHashDumpVal = (unsigned)JitConfig.JitHashDump();
3113 if ((jitHashDumpVal != (DWORD)-1) && (jitHashDumpVal == info.compMethodHash()))
3117 if (JitConfig.JitDumpIR().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3121 unsigned jitHashDumpIRVal = (unsigned)JitConfig.JitHashDumpIR();
3122 if ((jitHashDumpIRVal != (DWORD)-1) && (jitHashDumpIRVal == info.compMethodHash()))
3126 dumpIRFormat = JitConfig.JitDumpIRFormat();
3127 dumpIRPhase = JitConfig.JitDumpIRPhase();
3131 if (dumpIRPhase == nullptr)
3133 dumpIRPhase = W("*");
3136 this->dumpIRPhase = dumpIRPhase;
3138 if (dumpIRFormat != nullptr)
3140 this->dumpIRFormat = dumpIRFormat;
3143 dumpIRTrees = false;
3144 dumpIRLinear = true;
3145 if (dumpIRFormat != nullptr)
3147 for (LPCWSTR p = dumpIRFormat; (*p != 0);)
3149 for (; (*p != 0); p++)
3162 static bool dumpedHelp = false;
3164 if ((*p == L'?') && (!dumpedHelp))
3166 printf("*******************************************************************************\n");
3171 printf("Available specifiers (comma separated):\n");
3173 printf("? dump out value of COMPlus_JitDumpIRFormat and this list of values\n");
3175 printf("linear linear IR dump (default)\n");
3176 printf("tree tree IR dump (traditional)\n");
3177 printf("mixed intermingle tree dump with linear IR dump\n");
3179 printf("dataflow use data flow form of linear IR dump\n");
3180 printf("structural use structural form of linear IR dump\n");
3181 printf("all implies structural, include everything\n");
3183 printf("kinds include tree node kinds in dump, example: \"kinds=[LEAF][LOCAL]\"\n");
3184 printf("flags include tree node flags in dump, example: \"flags=[CALL][GLOB_REF]\" \n");
3185 printf("types includes tree node types in dump, example: \".int\"\n");
3186 printf("locals include local numbers and tracking numbers in dump, example: \"(V3,T1)\"\n");
3187 printf("regs include register assignments in dump, example: \"(rdx)\"\n");
3188 printf("ssa include SSA numbers in dump, example: \"<d:3>\" or \"<u:3>\"\n");
3189 printf("valnums include Value numbers in dump, example: \"<v:$c4>\" or \"<v:$c4,$c5>\"\n");
3191 printf("nolist exclude GT_LIST nodes from dump\n");
3192 printf("noleafs exclude LEAF nodes from dump (fold into operations)\n");
3193 printf("nostmts exclude GT_STMTS from dump (unless required by dependencies)\n");
3195 printf("blkhdrs include block headers\n");
3196 printf("exit exit program after last phase dump (used with single method)\n");
3198 printf("*******************************************************************************\n");
3202 if (wcsncmp(p, W("types"), 5) == 0)
3207 if (wcsncmp(p, W("locals"), 6) == 0)
3209 dumpIRLocals = true;
3212 if (wcsncmp(p, W("regs"), 4) == 0)
3217 if (wcsncmp(p, W("ssa"), 3) == 0)
3222 if (wcsncmp(p, W("valnums"), 7) == 0)
3224 dumpIRValnums = true;
3227 if (wcsncmp(p, W("costs"), 5) == 0)
3232 if (wcsncmp(p, W("flags"), 5) == 0)
3237 if (wcsncmp(p, W("kinds"), 5) == 0)
3242 if (wcsncmp(p, W("nodes"), 5) == 0)
3247 if (wcsncmp(p, W("exit"), 4) == 0)
3252 if (wcsncmp(p, W("nolists"), 7) == 0)
3254 dumpIRNoLists = true;
3257 if (wcsncmp(p, W("noleafs"), 7) == 0)
3259 dumpIRNoLeafs = true;
3262 if (wcsncmp(p, W("nostmts"), 7) == 0)
3264 dumpIRNoStmts = true;
3267 if (wcsncmp(p, W("trees"), 5) == 0)
3270 dumpIRLinear = false;
3273 if (wcsncmp(p, W("structural"), 10) == 0)
3275 dumpIRLinear = true;
3276 dumpIRNoStmts = false;
3277 dumpIRNoLeafs = false;
3278 dumpIRNoLists = false;
3281 if (wcsncmp(p, W("all"), 3) == 0)
3283 dumpIRLinear = true;
3287 dumpIRLocals = true;
3290 dumpIRValnums = true;
3292 dumpIRNoStmts = false;
3293 dumpIRNoLeafs = false;
3294 dumpIRNoLists = false;
3297 if (wcsncmp(p, W("linear"), 6) == 0)
3299 dumpIRTrees = false;
3300 dumpIRLinear = true;
3303 if (wcsncmp(p, W("mixed"), 5) == 0)
3306 dumpIRLinear = true;
3309 if (wcsncmp(p, W("dataflow"), 8) == 0)
3311 dumpIRDataflow = true;
3312 dumpIRNoLeafs = true;
3313 dumpIRNoLists = true;
3314 dumpIRNoStmts = true;
3317 if (wcsncmp(p, W("blkhdrs"), 7) == 0)
3319 dumpIRBlockHeaders = true;
3322 for (; (*p != 0); p++)
3341 this->dumpIR = true;
3346 this->dumpIRTypes = true;
3351 this->dumpIRLocals = true;
3356 this->dumpIRRegs = true;
3361 this->dumpIRSsa = true;
3366 this->dumpIRValnums = true;
3371 this->dumpIRCosts = true;
3376 this->dumpIRFlags = true;
3381 this->dumpIRKinds = true;
3386 this->dumpIRNodes = true;
3391 this->dumpIRNoLists = true;
3396 this->dumpIRNoLeafs = true;
3399 if (dumpIRNoLeafs && dumpIRDataflow)
3401 this->dumpIRDataflow = true;
3406 this->dumpIRNoStmts = true;
3411 this->dumpIRTrees = true;
3416 this->dumpIRLinear = true;
3419 if (dumpIRBlockHeaders)
3421 this->dumpIRBlockHeaders = true;
3426 this->dumpIRExit = true;
3432 // Minimum bar for availing SIMD benefits is SSE2 on AMD64/x86.
3433 featureSIMD = jitFlags->IsSet(JitFlags::JIT_FLAG_FEATURE_SIMD);
3434 setUsesSIMDTypes(false);
3435 #endif // FEATURE_SIMD
3437 if (compIsForImportOnly())
3442 #if FEATURE_TAILCALL_OPT
3443 // By default opportunistic tail call optimization is enabled.
3444 // Recognition is done in the importer so this must be set for
3445 // inlinees as well.
3446 opts.compTailCallOpt = true;
3447 #endif // FEATURE_TAILCALL_OPT
3449 if (compIsForInlining())
3454 // The rest of the opts fields that we initialize here
3455 // should only be used when we generate code for the method
3456 // They should not be used when importing or inlining
3457 CLANG_FORMAT_COMMENT_ANCHOR;
3459 #if FEATURE_TAILCALL_OPT
3460 opts.compTailCallLoopOpt = true;
3461 #endif // FEATURE_TAILCALL_OPT
3463 opts.genFPorder = true;
3464 opts.genFPopt = true;
3466 opts.instrCount = 0;
3467 opts.lvRefCount = 0;
3469 #ifdef PROFILING_SUPPORTED
3470 opts.compJitELTHookEnabled = false;
3471 #endif // PROFILING_SUPPORTED
3474 opts.dspInstrs = false;
3475 opts.dspEmit = false;
3476 opts.dspLines = false;
3477 opts.varNames = false;
3478 opts.dmpHex = false;
3479 opts.disAsm = false;
3480 opts.disAsmSpilled = false;
3481 opts.disDiffable = false;
3482 opts.dspCode = false;
3483 opts.dspEHTable = false;
3484 opts.dspGCtbls = false;
3485 opts.disAsm2 = false;
3486 opts.dspUnwind = false;
3487 opts.compLongAddress = false;
3488 opts.optRepeat = false;
3491 opts.doLateDisasm = false;
3492 #endif // LATE_DISASM
3494 compDebugBreak = false;
3496 // If we have a non-empty AltJit config then we change all of these other
3497 // config values to refer only to the AltJit.
3499 if (!altJitConfig || opts.altJit)
3501 if (jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
3503 if ((JitConfig.NgenOrder() & 1) == 1)
3505 opts.dspOrder = true;
3508 if (JitConfig.NgenGCDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3510 opts.dspGCtbls = true;
3513 if (JitConfig.NgenDisasm().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3517 if (JitConfig.NgenDisasm().contains("SPILLED", nullptr, nullptr))
3519 opts.disAsmSpilled = true;
3522 if (JitConfig.NgenUnwindDump().contains(info.compMethodName, info.compClassName,
3523 &info.compMethodInfo->args))
3525 opts.dspUnwind = true;
3528 if (JitConfig.NgenEHDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3530 opts.dspEHTable = true;
3535 if ((JitConfig.JitOrder() & 1) == 1)
3537 opts.dspOrder = true;
3540 if (JitConfig.JitGCDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3542 opts.dspGCtbls = true;
3545 if (JitConfig.JitDisasm().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3550 if (JitConfig.JitDisasm().contains("SPILLED", nullptr, nullptr))
3552 opts.disAsmSpilled = true;
3555 if (JitConfig.JitUnwindDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3557 opts.dspUnwind = true;
3560 if (JitConfig.JitEHDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3562 opts.dspEHTable = true;
3567 if (JitConfig.JitLateDisasm().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3568 opts.doLateDisasm = true;
3569 #endif // LATE_DISASM
3571 // This one applies to both Ngen/Jit Disasm output: COMPlus_JitDiffableDasm=1
3572 if (JitConfig.DiffableDasm() != 0)
3574 opts.disDiffable = true;
3575 opts.dspDiffable = true;
3578 if (JitConfig.JitLongAddress() != 0)
3580 opts.compLongAddress = true;
3583 if (JitConfig.JitOptRepeat().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3585 opts.optRepeat = true;
3591 opts.dspCode = true;
3592 opts.dspEHTable = true;
3593 opts.dspGCtbls = true;
3594 opts.disAsm2 = true;
3595 opts.dspUnwind = true;
3597 verboseTrees = shouldUseVerboseTrees();
3598 verboseSsa = shouldUseVerboseSsa();
3599 codeGen->setVerbose(true);
3602 treesBeforeAfterMorph = (JitConfig.TreesBeforeAfterMorph() == 1);
3603 morphNum = 0; // Initialize the morphed-trees counting.
3605 expensiveDebugCheckLevel = JitConfig.JitExpensiveDebugCheckLevel();
3606 if (expensiveDebugCheckLevel == 0)
3608 // If we're in a stress mode that modifies the flowgraph, make 1 the default.
3609 if (fgStressBBProf() || compStressCompile(STRESS_DO_WHILE_LOOPS, 30))
3611 expensiveDebugCheckLevel = 1;
3617 printf("****** START compiling %s (MethodHash=%08x)\n", info.compFullName, info.compMethodHash());
3618 printf("Generating code for %s %s\n", Target::g_tgtPlatformName, Target::g_tgtCPUName);
3619 printf(""); // in our logic this causes a flush
3622 if (JitConfig.JitBreak().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3624 assert(!"JitBreak reached");
3627 unsigned jitHashBreakVal = (unsigned)JitConfig.JitHashBreak();
3628 if ((jitHashBreakVal != (DWORD)-1) && (jitHashBreakVal == info.compMethodHash()))
3630 assert(!"JitHashBreak reached");
3634 JitConfig.JitDebugBreak().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args) ||
3635 JitConfig.JitBreak().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3637 compDebugBreak = true;
3640 memset(compActiveStressModes, 0, sizeof(compActiveStressModes));
3644 //-------------------------------------------------------------------------
3647 assert(!codeGen->isGCTypeFixed());
3648 opts.compGcChecks = (JitConfig.JitGCChecks() != 0) || compStressCompile(STRESS_GENERIC_VARN, 5);
3652 STACK_CHECK_ON_RETURN = 0x1,
3653 STACK_CHECK_ON_CALL = 0x2,
3654 STACK_CHECK_ALL = 0x3,
3657 DWORD dwJitStackChecks = JitConfig.JitStackChecks();
3658 if (compStressCompile(STRESS_GENERIC_VARN, 5))
3660 dwJitStackChecks = STACK_CHECK_ALL;
3662 opts.compStackCheckOnRet = (dwJitStackChecks & DWORD(STACK_CHECK_ON_RETURN)) != 0;
3663 opts.compStackCheckOnCall = (dwJitStackChecks & DWORD(STACK_CHECK_ON_CALL)) != 0;
3666 #if MEASURE_MEM_ALLOC
3667 s_dspMemStats = (JitConfig.DisplayMemStats() != 0);
3670 #ifdef PROFILING_SUPPORTED
3671 opts.compNoPInvokeInlineCB = jitFlags->IsSet(JitFlags::JIT_FLAG_PROF_NO_PINVOKE_INLINE);
3673 // Cache the profiler handle
3674 if (jitFlags->IsSet(JitFlags::JIT_FLAG_PROF_ENTERLEAVE))
3678 info.compCompHnd->GetProfilingHandle(&hookNeeded, &compProfilerMethHnd, &indirected);
3679 compProfilerHookNeeded = !!hookNeeded;
3680 compProfilerMethHndIndirected = !!indirected;
3684 compProfilerHookNeeded = false;
3685 compProfilerMethHnd = nullptr;
3686 compProfilerMethHndIndirected = false;
3689 // Honour COMPlus_JitELTHookEnabled only if VM has not asked us to generate profiler
3690 // hooks in the first place. That is, override VM only if it hasn't asked for a
3691 // profiler callback for this method.
3692 if (!compProfilerHookNeeded && (JitConfig.JitELTHookEnabled() != 0))
3694 opts.compJitELTHookEnabled = true;
3697 // TBD: Exclude PInvoke stubs
3698 if (opts.compJitELTHookEnabled)
3700 compProfilerMethHnd = (void*)DummyProfilerELTStub;
3701 compProfilerMethHndIndirected = false;
3704 #endif // PROFILING_SUPPORTED
3706 #if FEATURE_TAILCALL_OPT
3707 const wchar_t* strTailCallOpt = JitConfig.TailCallOpt();
3708 if (strTailCallOpt != nullptr)
3710 opts.compTailCallOpt = (UINT)_wtoi(strTailCallOpt) != 0;
3713 if (JitConfig.TailCallLoopOpt() == 0)
3715 opts.compTailCallLoopOpt = false;
3719 opts.compScopeInfo = opts.compDbgInfo;
3722 codeGen->getDisAssembler().disOpenForLateDisAsm(info.compMethodName, info.compClassName,
3723 info.compMethodInfo->args.pSig);
3726 //-------------------------------------------------------------------------
3728 opts.compReloc = jitFlags->IsSet(JitFlags::JIT_FLAG_RELOC);
3731 #if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
3732 // Whether encoding of absolute addr as PC-rel offset is enabled in RyuJIT
3733 opts.compEnablePCRelAddr = (JitConfig.EnablePCRelAddr() != 0);
3737 opts.compProcedureSplitting = jitFlags->IsSet(JitFlags::JIT_FLAG_PROCSPLIT);
3739 #ifdef _TARGET_ARM64_
3740 // TODO-ARM64-NYI: enable hot/cold splitting
3741 opts.compProcedureSplitting = false;
3742 #endif // _TARGET_ARM64_
3745 opts.compProcedureSplittingEH = opts.compProcedureSplitting;
3748 if (opts.compProcedureSplitting)
3750 // Note that opts.compdbgCode is true under ngen for checked assemblies!
3751 opts.compProcedureSplitting = !opts.compDbgCode;
3754 // JitForceProcedureSplitting is used to force procedure splitting on checked assemblies.
3755 // This is useful for debugging on a checked build. Note that we still only do procedure
3756 // splitting in the zapper.
3757 if (JitConfig.JitForceProcedureSplitting().contains(info.compMethodName, info.compClassName,
3758 &info.compMethodInfo->args))
3760 opts.compProcedureSplitting = true;
3763 // JitNoProcedureSplitting will always disable procedure splitting.
3764 if (JitConfig.JitNoProcedureSplitting().contains(info.compMethodName, info.compClassName,
3765 &info.compMethodInfo->args))
3767 opts.compProcedureSplitting = false;
3770 // JitNoProcedureSplittingEH will disable procedure splitting in functions with EH.
3771 if (JitConfig.JitNoProcedureSplittingEH().contains(info.compMethodName, info.compClassName,
3772 &info.compMethodInfo->args))
3774 opts.compProcedureSplittingEH = false;
3779 fgProfileBuffer = nullptr;
3780 fgProfileData_ILSizeMismatch = false;
3781 fgNumProfileRuns = 0;
3782 if (jitFlags->IsSet(JitFlags::JIT_FLAG_BBOPT))
3784 assert(!compIsForInlining());
3786 hr = info.compCompHnd->getBBProfileData(info.compMethodHnd, &fgProfileBufferCount, &fgProfileBuffer,
3789 // a failed result that also has a non-NULL fgProfileBuffer
3790 // indicates that the ILSize for the method no longer matches
3791 // the ILSize for the method when profile data was collected.
3793 // We will discard the IBC data in this case
3795 if (FAILED(hr) && (fgProfileBuffer != nullptr))
3797 fgProfileData_ILSizeMismatch = true;
3798 fgProfileBuffer = nullptr;
3801 // A successful result implies a non-NULL fgProfileBuffer
3805 assert(fgProfileBuffer != nullptr);
3808 // A failed result implies a NULL fgProfileBuffer
3809 // see implementation of Compiler::fgHaveProfileData()
3813 assert(fgProfileBuffer == nullptr);
3818 opts.compNeedStackProbes = false;
3821 if (JitConfig.StackProbesOverride() != 0 || compStressCompile(STRESS_GENERIC_VARN, 5))
3823 opts.compNeedStackProbes = true;
3828 // Now, set compMaxUncheckedOffsetForNullObject for STRESS_NULL_OBJECT_CHECK
3829 if (compStressCompile(STRESS_NULL_OBJECT_CHECK, 30))
3831 compMaxUncheckedOffsetForNullObject = (size_t)JitConfig.JitMaxUncheckedOffset();
3834 printf("STRESS_NULL_OBJECT_CHECK: compMaxUncheckedOffsetForNullObject=0x%X\n",
3835 compMaxUncheckedOffsetForNullObject);
3841 printf("OPTIONS: compCodeOpt = %s\n",
3842 (opts.compCodeOpt == BLENDED_CODE)
3844 : (opts.compCodeOpt == SMALL_CODE) ? "SMALL_CODE"
3845 : (opts.compCodeOpt == FAST_CODE) ? "FAST_CODE" : "UNKNOWN_CODE");
3847 printf("OPTIONS: compDbgCode = %s\n", dspBool(opts.compDbgCode));
3848 printf("OPTIONS: compDbgInfo = %s\n", dspBool(opts.compDbgInfo));
3849 printf("OPTIONS: compDbgEnC = %s\n", dspBool(opts.compDbgEnC));
3850 printf("OPTIONS: compProcedureSplitting = %s\n", dspBool(opts.compProcedureSplitting));
3851 printf("OPTIONS: compProcedureSplittingEH = %s\n", dspBool(opts.compProcedureSplittingEH));
3853 if (jitFlags->IsSet(JitFlags::JIT_FLAG_BBOPT) && fgHaveProfileData())
3855 printf("OPTIONS: using real profile data\n");
3858 if (fgProfileData_ILSizeMismatch)
3860 printf("OPTIONS: discarded IBC profile data due to mismatch in ILSize\n");
3863 if (jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
3865 printf("OPTIONS: Jit invoked for ngen\n");
3867 printf("OPTIONS: Stack probing is %s\n", opts.compNeedStackProbes ? "ENABLED" : "DISABLED");
3871 opts.compGCPollType = GCPOLL_NONE;
3872 if (jitFlags->IsSet(JitFlags::JIT_FLAG_GCPOLL_CALLS))
3874 opts.compGCPollType = GCPOLL_CALL;
3876 else if (jitFlags->IsSet(JitFlags::JIT_FLAG_GCPOLL_INLINE))
3878 // make sure that the EE didn't set both flags.
3879 assert(opts.compGCPollType == GCPOLL_NONE);
3880 opts.compGCPollType = GCPOLL_INLINE;
3883 #ifdef PROFILING_SUPPORTED
3884 #ifdef UNIX_AMD64_ABI
3885 if (compIsProfilerHookNeeded())
3887 opts.compNeedToAlignFrame = true;
3889 #endif // UNIX_AMD64_ABI
3895 bool Compiler::compJitHaltMethod()
3897 /* This method returns true when we use an INS_BREAKPOINT to allow us to step into the generated native code */
3898 /* Note that this these two "Jit" environment variables also work for ngen images */
3900 if (JitConfig.JitHalt().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3905 /* Use this Hash variant when there are a lot of method with the same name and different signatures */
3907 unsigned fJitHashHaltVal = (unsigned)JitConfig.JitHashHalt();
3908 if ((fJitHashHaltVal != (unsigned)-1) && (fJitHashHaltVal == info.compMethodHash()))
3916 /*****************************************************************************
3917 * Should we use a "stress-mode" for the given stressArea. We have different
3918 * areas to allow the areas to be mixed in different combinations in
3919 * different methods.
3920 * 'weight' indicates how often (as a percentage) the area should be stressed.
3921 * It should reflect the usefulness:overhead ratio.
3924 const LPCWSTR Compiler::s_compStressModeNames[STRESS_COUNT + 1] = {
3925 #define STRESS_MODE(mode) W("STRESS_") W(#mode),
3931 bool Compiler::compStressCompile(compStressArea stressArea, unsigned weight)
3936 if (!bRangeAllowStress)
3941 if (!JitConfig.JitStressOnly().isEmpty() &&
3942 !JitConfig.JitStressOnly().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
3947 bool doStress = false;
3948 const wchar_t* strStressModeNames;
3950 // Does user explicitly prevent using this STRESS_MODE through the command line?
3951 const wchar_t* strStressModeNamesNot = JitConfig.JitStressModeNamesNot();
3952 if ((strStressModeNamesNot != nullptr) &&
3953 (wcsstr(strStressModeNamesNot, s_compStressModeNames[stressArea]) != nullptr))
3959 // Does user explicitly set this STRESS_MODE through the command line?
3960 strStressModeNames = JitConfig.JitStressModeNames();
3961 if (strStressModeNames != nullptr)
3963 if (wcsstr(strStressModeNames, s_compStressModeNames[stressArea]) != nullptr)
3969 // This stress mode name did not match anything in the stress
3970 // mode whitelist. If user has requested only enable mode,
3971 // don't allow this stress mode to turn on.
3972 const bool onlyEnableMode = JitConfig.JitStressModeNamesOnly() != 0;
3981 // 0: No stress (Except when explicitly set in complus_JitStressModeNames)
3982 // !=2: Vary stress. Performance will be slightly/moderately degraded
3983 // 2: Check-all stress. Performance will be REALLY horrible
3984 stressLevel = getJitStressLevel();
3986 assert(weight <= MAX_STRESS_WEIGHT);
3988 /* Check for boundary conditions */
3990 if (stressLevel == 0 || weight == 0)
3995 // Should we allow unlimited stress ?
3996 if (stressArea > STRESS_COUNT_VARN && stressLevel == 2)
4001 if (weight == MAX_STRESS_WEIGHT)
4007 // Get a hash which can be compared with 'weight'
4009 assert(stressArea != 0);
4010 hash = (info.compMethodHash() ^ stressArea ^ stressLevel) % MAX_STRESS_WEIGHT;
4012 assert(hash < MAX_STRESS_WEIGHT && weight <= MAX_STRESS_WEIGHT);
4013 doStress = (hash < weight);
4017 if (doStress && !compActiveStressModes[stressArea])
4021 printf("\n\n*** JitStress: %ws ***\n\n", s_compStressModeNames[stressArea]);
4023 compActiveStressModes[stressArea] = 1;
4031 void Compiler::compInitDebuggingInfo()
4033 assert(!compIsForInlining());
4038 printf("*************** In compInitDebuggingInfo() for %s\n", info.compFullName);
4042 /*-------------------------------------------------------------------------
4044 * Get hold of the local variable records, if there are any
4047 info.compVarScopesCount = 0;
4049 if (opts.compScopeInfo)
4054 compInitVarScopeMap();
4056 if (opts.compScopeInfo || opts.compDbgCode)
4058 compInitScopeLists();
4061 if (opts.compDbgCode && (info.compVarScopesCount > 0))
4063 /* Create a new empty basic block. fgExtendDbgLifetimes() may add
4064 initialization of variables which are in scope right from the
4065 start of the (real) first BB (and therefore artificially marked
4066 as alive) into this block.
4069 fgEnsureFirstBBisScratch();
4071 fgInsertStmtAtEnd(fgFirstBB, gtNewNothingNode());
4073 JITDUMP("Debuggable code - Add new %s to perform initialization of variables\n", fgFirstBB->dspToString());
4076 /*-------------------------------------------------------------------------
4078 * Read the stmt-offsets table and the line-number table
4081 info.compStmtOffsetsImplicit = ICorDebugInfo::NO_BOUNDARIES;
4083 // We can only report debug info for EnC at places where the stack is empty.
4084 // Actually, at places where there are not live temps. Else, we won't be able
4085 // to map between the old and the new versions correctly as we won't have
4086 // any info for the live temps.
4088 assert(!opts.compDbgEnC || !opts.compDbgInfo ||
4089 0 == (info.compStmtOffsetsImplicit & ~ICorDebugInfo::STACK_EMPTY_BOUNDARIES));
4091 info.compStmtOffsetsCount = 0;
4093 if (opts.compDbgInfo)
4095 /* Get hold of the line# records, if there are any */
4102 printf("info.compStmtOffsetsCount = %d\n", info.compStmtOffsetsCount);
4103 printf("info.compStmtOffsetsImplicit = %04Xh", info.compStmtOffsetsImplicit);
4105 if (info.compStmtOffsetsImplicit)
4108 if (info.compStmtOffsetsImplicit & ICorDebugInfo::STACK_EMPTY_BOUNDARIES)
4110 printf("STACK_EMPTY ");
4112 if (info.compStmtOffsetsImplicit & ICorDebugInfo::NOP_BOUNDARIES)
4116 if (info.compStmtOffsetsImplicit & ICorDebugInfo::CALL_SITE_BOUNDARIES)
4118 printf("CALL_SITE ");
4123 IL_OFFSET* pOffs = info.compStmtOffsets;
4124 for (unsigned i = 0; i < info.compStmtOffsetsCount; i++, pOffs++)
4126 printf("%02d) IL_%04Xh\n", i, *pOffs);
4133 void Compiler::compSetOptimizationLevel()
4135 bool theMinOptsValue;
4136 unsigned jitMinOpts;
4138 if (compIsForInlining())
4140 theMinOptsValue = impInlineInfo->InlinerCompiler->opts.MinOpts();
4144 theMinOptsValue = false;
4146 if (opts.compFlags == CLFLG_MINOPT)
4148 JITLOG((LL_INFO100, "CLFLG_MINOPT set for method %s\n", info.compFullName));
4149 theMinOptsValue = true;
4153 jitMinOpts = JitConfig.JitMinOpts();
4155 if (!theMinOptsValue && (jitMinOpts > 0))
4157 unsigned methodCount = Compiler::jitTotalMethodCompiled;
4158 unsigned methodCountMask = methodCount & 0xFFF;
4159 unsigned kind = (jitMinOpts & 0xF000000) >> 24;
4163 if (jitMinOpts <= methodCount)
4167 printf(" Optimizations disabled by JitMinOpts and methodCount\n");
4169 theMinOptsValue = true;
4174 unsigned firstMinopts = (jitMinOpts >> 12) & 0xFFF;
4175 unsigned secondMinopts = (jitMinOpts >> 0) & 0xFFF;
4177 if ((firstMinopts == methodCountMask) || (secondMinopts == methodCountMask))
4181 printf("0xD: Optimizations disabled by JitMinOpts and methodCountMask\n");
4183 theMinOptsValue = true;
4189 unsigned startMinopts = (jitMinOpts >> 12) & 0xFFF;
4190 unsigned endMinopts = (jitMinOpts >> 0) & 0xFFF;
4192 if ((startMinopts <= methodCountMask) && (endMinopts >= methodCountMask))
4196 printf("0xE: Optimizations disabled by JitMinOpts and methodCountMask\n");
4198 theMinOptsValue = true;
4204 unsigned bitsZero = (jitMinOpts >> 12) & 0xFFF;
4205 unsigned bitsOne = (jitMinOpts >> 0) & 0xFFF;
4207 if (((methodCountMask & bitsOne) == bitsOne) && ((~methodCountMask & bitsZero) == bitsZero))
4211 printf("0xF: Optimizations disabled by JitMinOpts and methodCountMask\n");
4213 theMinOptsValue = true;
4220 if (!theMinOptsValue)
4222 if (JitConfig.JitMinOptsName().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
4224 theMinOptsValue = true;
4229 // The code in this #if can be used to debug optimization issues according to method hash.
4230 // To use, uncomment, rebuild and set environment variables minoptshashlo and minoptshashhi.
4232 unsigned methHash = info.compMethodHash();
4233 char* lostr = getenv("minoptshashlo");
4234 unsigned methHashLo = 0;
4235 if (lostr != nullptr)
4237 sscanf_s(lostr, "%x", &methHashLo);
4238 char* histr = getenv("minoptshashhi");
4239 unsigned methHashHi = UINT32_MAX;
4240 if (histr != nullptr)
4242 sscanf_s(histr, "%x", &methHashHi);
4243 if (methHash >= methHashLo && methHash <= methHashHi)
4245 printf("MinOpts for method %s, hash = 0x%x.\n",
4246 info.compFullName, info.compMethodHash());
4247 printf(""); // in our logic this causes a flush
4248 theMinOptsValue = true;
4255 if (compStressCompile(STRESS_MIN_OPTS, 5))
4257 theMinOptsValue = true;
4259 // For PREJIT we never drop down to MinOpts
4260 // unless unless CLFLG_MINOPT is set
4261 else if (!opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
4263 if ((unsigned)JitConfig.JitMinOptsCodeSize() < info.compILCodeSize)
4265 JITLOG((LL_INFO10, "IL Code Size exceeded, using MinOpts for method %s\n", info.compFullName));
4266 theMinOptsValue = true;
4268 else if ((unsigned)JitConfig.JitMinOptsInstrCount() < opts.instrCount)
4270 JITLOG((LL_INFO10, "IL instruction count exceeded, using MinOpts for method %s\n", info.compFullName));
4271 theMinOptsValue = true;
4273 else if ((unsigned)JitConfig.JitMinOptsBbCount() < fgBBcount)
4275 JITLOG((LL_INFO10, "Basic Block count exceeded, using MinOpts for method %s\n", info.compFullName));
4276 theMinOptsValue = true;
4278 else if ((unsigned)JitConfig.JitMinOptsLvNumCount() < lvaCount)
4280 JITLOG((LL_INFO10, "Local Variable Num count exceeded, using MinOpts for method %s\n", info.compFullName));
4281 theMinOptsValue = true;
4283 else if ((unsigned)JitConfig.JitMinOptsLvRefCount() < opts.lvRefCount)
4285 JITLOG((LL_INFO10, "Local Variable Ref count exceeded, using MinOpts for method %s\n", info.compFullName));
4286 theMinOptsValue = true;
4288 if (theMinOptsValue == true)
4290 JITLOG((LL_INFO10000, "IL Code Size,Instr %4d,%4d, Basic Block count %3d, Local Variable Num,Ref count "
4291 "%3d,%3d for method %s\n",
4292 info.compILCodeSize, opts.instrCount, fgBBcount, lvaCount, opts.lvRefCount, info.compFullName));
4293 if (JitConfig.JitBreakOnMinOpts() != 0)
4295 assert(!"MinOpts enabled");
4300 // Retail check if we should force Minopts due to the complexity of the method
4301 // For PREJIT we never drop down to MinOpts
4302 // unless unless CLFLG_MINOPT is set
4303 if (!theMinOptsValue && !opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT) &&
4304 ((DEFAULT_MIN_OPTS_CODE_SIZE < info.compILCodeSize) || (DEFAULT_MIN_OPTS_INSTR_COUNT < opts.instrCount) ||
4305 (DEFAULT_MIN_OPTS_BB_COUNT < fgBBcount) || (DEFAULT_MIN_OPTS_LV_NUM_COUNT < lvaCount) ||
4306 (DEFAULT_MIN_OPTS_LV_REF_COUNT < opts.lvRefCount)))
4308 theMinOptsValue = true;
4312 JITLOG((LL_INFO10000,
4313 "IL Code Size,Instr %4d,%4d, Basic Block count %3d, Local Variable Num,Ref count %3d,%3d for method %s\n",
4314 info.compILCodeSize, opts.instrCount, fgBBcount, lvaCount, opts.lvRefCount, info.compFullName));
4317 // The code in this #if has been useful in debugging loop cloning issues, by
4318 // enabling selective enablement of the loop cloning optimization according to
4321 if (!theMinOptsValue)
4323 unsigned methHash = info.compMethodHash();
4324 char* lostr = getenv("opthashlo");
4325 unsigned methHashLo = 0;
4328 sscanf_s(lostr, "%x", &methHashLo);
4329 // methHashLo = (unsigned(atoi(lostr)) << 2); // So we don't have to use negative numbers.
4331 char* histr = getenv("opthashhi");
4332 unsigned methHashHi = UINT32_MAX;
4335 sscanf_s(histr, "%x", &methHashHi);
4336 // methHashHi = (unsigned(atoi(histr)) << 2); // So we don't have to use negative numbers.
4338 if (methHash < methHashLo || methHash > methHashHi)
4340 theMinOptsValue = true;
4344 printf("Doing optimization in in %s (0x%x).\n", info.compFullName, methHash);
4352 // Set the MinOpts value
4353 opts.SetMinOpts(theMinOptsValue);
4356 if (verbose && !compIsForInlining())
4358 printf("OPTIONS: opts.MinOpts() == %s\n", opts.MinOpts() ? "true" : "false");
4362 /* Control the optimizations */
4364 if (opts.MinOpts() || opts.compDbgCode)
4366 opts.compFlags &= ~CLFLG_MAXOPT;
4367 opts.compFlags |= CLFLG_MINOPT;
4370 if (!compIsForInlining())
4372 codeGen->setFramePointerRequired(false);
4373 codeGen->setFrameRequired(false);
4375 if (opts.MinOpts() || opts.compDbgCode)
4377 codeGen->setFrameRequired(true);
4380 #if !defined(_TARGET_AMD64_)
4381 // The VM sets JitFlags::JIT_FLAG_FRAMED for two reasons: (1) the COMPlus_JitFramed variable is set, or
4382 // (2) the function is marked "noinline". The reason for #2 is that people mark functions
4383 // noinline to ensure the show up on in a stack walk. But for AMD64, we don't need a frame
4384 // pointer for the frame to show up in stack walk.
4385 if (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_FRAMED))
4386 codeGen->setFrameRequired(true);
4389 if (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_RELOC))
4391 codeGen->genAlignLoops = false; // loop alignment not supported for prejitted code
4393 // The zapper doesn't set JitFlags::JIT_FLAG_ALIGN_LOOPS, and there is
4394 // no reason for it to set it as the JIT doesn't currently support loop alignment
4395 // for prejitted images. (The JIT doesn't know the final address of the code, hence
4396 // it can't align code based on unknown addresses.)
4397 assert(!opts.jitFlags->IsSet(JitFlags::JIT_FLAG_ALIGN_LOOPS));
4401 codeGen->genAlignLoops = opts.jitFlags->IsSet(JitFlags::JIT_FLAG_ALIGN_LOOPS);
4405 info.compUnwrapContextful = !opts.MinOpts() && !opts.compDbgCode;
4407 fgCanRelocateEHRegions = true;
4410 #ifdef _TARGET_ARMARCH_
4411 // Function compRsvdRegCheck:
4412 // given a curState to use for calculating the total frame size
4413 // it will return true if the REG_OPT_RSVD should be reserved so
4414 // that it can be use to form large offsets when accessing stack
4415 // based LclVar including both incoming and out going argument areas.
4417 // The method advances the frame layout state to curState by calling
4418 // lvaFrameSize(curState).
4420 bool Compiler::compRsvdRegCheck(FrameLayoutState curState)
4422 // Always do the layout even if returning early. Callers might
4423 // depend on us to do the layout.
4424 unsigned frameSize = lvaFrameSize(curState);
4425 JITDUMP("\ncompRsvdRegCheck\n frame size = %6d\n compArgSize = %6d\n", frameSize, compArgSize);
4429 // Have a recovery path in case we fail to reserve REG_OPT_RSVD and go
4430 // over the limit of SP and FP offset ranges due to large
4432 JITDUMP(" Returning true (MinOpts)\n\n");
4436 unsigned calleeSavedRegMaxSz = CALLEE_SAVED_REG_MAXSZ;
4437 if (compFloatingPointUsed)
4439 calleeSavedRegMaxSz += CALLEE_SAVED_FLOAT_MAXSZ;
4442 noway_assert(frameSize > calleeSavedRegMaxSz);
4444 #if defined(_TARGET_ARM64_)
4446 // TODO-ARM64-CQ: update this!
4447 JITDUMP(" Returning true (ARM64)\n\n");
4448 return true; // just always assume we'll need it, for now
4450 #else // _TARGET_ARM_
4455 // inArgs compArgSize
4459 // + callee saved regs CALLEE_SAVED_REG_MAXSZ (32 bytes)
4460 // optional saved fp regs 16 * sizeof(float) (64 bytes)
4462 // incl. TEMPS MAX_SPILL_TEMP_SIZE
4468 // With codeGen->isFramePointerRequired we use R11 to access incoming args with positive offsets
4469 // and use R11 to access LclVars with negative offsets in the non funclet or
4470 // main region we use SP with positive offsets. The limiting factor in the
4471 // codeGen->isFramePointerRequired case is that we need the offset to be less than or equal to 0x7C
4472 // for negative offsets, but positive offsets can be imm12 limited by vldr/vstr
4475 // Subtract 4 bytes for alignment of a local var because number of temps could
4476 // trigger a misaligned double or long.
4478 unsigned maxR11ArgLimit = (compFloatingPointUsed ? 0x03FC : 0x0FFC);
4479 unsigned maxR11LclLimit = 0x0078;
4480 JITDUMP(" maxR11ArgLimit = %6d\n maxR11LclLimit = %6d\n", maxR11ArgLimit, maxR11LclLimit);
4482 if (codeGen->isFramePointerRequired())
4484 unsigned maxR11LclOffs = frameSize;
4485 unsigned maxR11ArgOffs = compArgSize + (2 * REGSIZE_BYTES);
4486 JITDUMP(" maxR11LclOffs = %6d\n maxR11ArgOffs = %6d\n", maxR11LclOffs, maxR11ArgOffs)
4487 if (maxR11LclOffs > maxR11LclLimit)
4489 JITDUMP(" Returning true (frame reqd and maxR11LclOffs)\n\n");
4492 if (maxR11ArgOffs > maxR11ArgLimit)
4494 JITDUMP(" Returning true (frame reqd and maxR11ArgOffs)\n\n");
4499 // So this case is the SP based frame case, but note that we also will use SP based
4500 // offsets for R11 based frames in the non-funclet main code area. However if we have
4501 // passed the above max_R11_offset check these SP checks won't fire.
4503 // Check local coverage first. If vldr/vstr will be used the limit can be +/-imm8.
4504 unsigned maxSPLclLimit = (compFloatingPointUsed ? 0x03F8 : 0x0FF8);
4505 JITDUMP(" maxSPLclLimit = %6d\n", maxSPLclLimit);
4506 if (frameSize > (codeGen->isFramePointerUsed() ? (maxR11LclLimit + maxSPLclLimit) : maxSPLclLimit))
4508 JITDUMP(" Returning true (frame reqd; local coverage)\n\n");
4512 // Check arguments coverage.
4513 if ((!codeGen->isFramePointerUsed() || (compArgSize > maxR11ArgLimit)) && (compArgSize + frameSize) > maxSPLclLimit)
4515 JITDUMP(" Returning true (no frame; arg coverage)\n\n");
4519 // We won't need to reserve REG_OPT_RSVD.
4521 JITDUMP(" Returning false\n\n");
4523 #endif // _TARGET_ARM_
4525 #endif // _TARGET_ARMARCH_
4527 void Compiler::compFunctionTraceStart()
4530 if (compIsForInlining())
4535 if ((JitConfig.JitFunctionTrace() != 0) && !opts.disDiffable)
4537 LONG newJitNestingLevel = InterlockedIncrement(&Compiler::jitNestingLevel);
4538 if (newJitNestingLevel <= 0)
4540 printf("{ Illegal nesting level %d }\n", newJitNestingLevel);
4543 for (LONG i = 0; i < newJitNestingLevel - 1; i++)
4547 printf("{ Start Jitting %s (MethodHash=%08x)\n", info.compFullName,
4548 info.compMethodHash()); /* } editor brace matching workaround for this printf */
4553 void Compiler::compFunctionTraceEnd(void* methodCodePtr, ULONG methodCodeSize, bool isNYI)
4556 assert(!compIsForInlining());
4558 if ((JitConfig.JitFunctionTrace() != 0) && !opts.disDiffable)
4560 LONG newJitNestingLevel = InterlockedDecrement(&Compiler::jitNestingLevel);
4561 if (newJitNestingLevel < 0)
4563 printf("{ Illegal nesting level %d }\n", newJitNestingLevel);
4566 for (LONG i = 0; i < newJitNestingLevel; i++)
4570 /* { editor brace-matching workaround for following printf */
4571 printf("} Jitted Entry %03x at" FMT_ADDR "method %s size %08x%s\n", Compiler::jitTotalMethodCompiled,
4572 DBG_ADDR(methodCodePtr), info.compFullName, methodCodeSize,
4573 isNYI ? " NYI" : (compIsForImportOnly() ? " import only" : ""));
4578 //*********************************************************************************************
4581 // This is the most interesting 'toplevel' function in the JIT. It goes through the operations of
4582 // importing, morphing, optimizations and code generation. This is called from the EE through the
4583 // code:CILJit::compileMethod function.
4585 // For an overview of the structure of the JIT, see:
4586 // https://github.com/dotnet/coreclr/blob/master/Documentation/botr/ryujit-overview.md
4588 void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags* compileFlags)
4590 if (compIsForInlining())
4592 // Notify root instance that an inline attempt is about to import IL
4593 impInlineRoot()->m_inlineStrategy->NoteImport();
4598 VarSetOps::AssignAllowUninitRhs(this, compCurLife, VarSetOps::UninitVal());
4600 /* The temp holding the secret stub argument is used by fgImport() when importing the intrinsic. */
4602 if (info.compPublishStubParam)
4604 assert(lvaStubArgumentVar == BAD_VAR_NUM);
4605 lvaStubArgumentVar = lvaGrabTempWithImplicitUse(false DEBUGARG("stub argument"));
4606 lvaTable[lvaStubArgumentVar].lvType = TYP_I_IMPL;
4609 EndPhase(PHASE_PRE_IMPORT);
4611 compFunctionTraceStart();
4613 /* Convert the instrs in each basic block to a tree based intermediate representation */
4617 assert(!fgComputePredsDone);
4618 if (fgCheapPredsValid)
4620 // Remove cheap predecessors before inlining and fat call transformation;
4621 // allowing the cheap predecessor lists to be inserted causes problems
4622 // with splitting existing blocks.
4626 if (IsTargetAbi(CORINFO_CORERT_ABI) && doesMethodHaveFatPointer())
4628 fgTransformFatCalli();
4631 EndPhase(PHASE_IMPORTATION);
4633 if (compIsForInlining())
4635 /* Quit inlining if fgImport() failed for any reason. */
4637 if (!compDonotInline())
4639 /* Filter out unimported BBs */
4641 fgRemoveEmptyBlocks();
4643 // Update type of return spill temp if we have gathered better info
4644 // when importing the inlinee.
4645 if (fgNeedReturnSpillTemp())
4647 CORINFO_CLASS_HANDLE retExprClassHnd = impInlineInfo->retExprClassHnd;
4648 if (retExprClassHnd != nullptr)
4650 lvaUpdateClass(lvaInlineeReturnSpillTemp, retExprClassHnd, impInlineInfo->retExprClassHndIsExact);
4655 EndPhase(PHASE_POST_IMPORT);
4657 #ifdef FEATURE_JIT_METHOD_PERF
4658 if (pCompJitTimer != nullptr)
4660 #if MEASURE_CLRAPI_CALLS
4661 EndPhase(PHASE_CLR_API);
4663 pCompJitTimer->Terminate(this, CompTimeSummaryInfo::s_compTimeSummary, false);
4670 assert(!compDonotInline());
4672 // Maybe the caller was not interested in generating code
4673 if (compIsForImportOnly())
4675 compFunctionTraceEnd(nullptr, 0, false);
4680 // If we aren't yet supporting EH in a compiler bring-up, remove as many EH handlers as possible, so
4681 // we can pass tests that contain try/catch EH, but don't actually throw any exceptions.
4683 #endif // !FEATURE_EH
4685 if (compileFlags->IsSet(JitFlags::JIT_FLAG_BBINSTR))
4687 fgInstrumentMethod();
4690 // We could allow ESP frames. Just need to reserve space for
4691 // pushing EBP if the method becomes an EBP-frame after an edit.
4692 // Note that requiring a EBP Frame disallows double alignment. Thus if we change this
4693 // we either have to disallow double alignment for E&C some other way or handle it in EETwain.
4695 if (opts.compDbgEnC)
4697 codeGen->setFramePointerRequired(true);
4699 // Since we need a slots for security near ebp, its not possible
4700 // to do this after an Edit without shifting all the locals.
4701 // So we just always reserve space for these slots in case an Edit adds them
4702 opts.compNeedSecurityCheck = true;
4704 // We don't care about localloc right now. If we do support it,
4705 // EECodeManager::FixContextForEnC() needs to handle it smartly
4706 // in case the localloc was actually executed.
4708 // compLocallocUsed = true;
4711 EndPhase(PHASE_POST_IMPORT);
4713 /* Initialize the BlockSet epoch */
4715 NewBasicBlockEpoch();
4717 /* Massage the trees so that we can generate code out of them */
4720 EndPhase(PHASE_MORPH_END);
4722 /* GS security checks for unsafe buffers */
4723 if (getNeedsGSSecurityCookie())
4728 printf("\n*************** -GS checks for unsafe buffers \n");
4732 gsGSChecksInitCookie();
4734 if (compGSReorderStackLayout)
4736 gsCopyShadowParams();
4742 fgDispBasicBlocks(true);
4747 EndPhase(PHASE_GS_COOKIE);
4749 /* Compute bbNum, bbRefs and bbPreds */
4751 JITDUMP("\nRenumbering the basic blocks for fgComputePred\n");
4754 noway_assert(!fgComputePredsDone); // This is the first time full (not cheap) preds will be computed.
4756 EndPhase(PHASE_COMPUTE_PREDS);
4758 /* If we need to emit GC Poll calls, mark the blocks that need them now. This is conservative and can
4759 * be optimized later. */
4760 fgMarkGCPollBlocks();
4761 EndPhase(PHASE_MARK_GC_POLL_BLOCKS);
4763 /* From this point on the flowgraph information such as bbNum,
4764 * bbRefs or bbPreds has to be kept updated */
4766 // Compute the edge weights (if we have profile data)
4767 fgComputeEdgeWeights();
4768 EndPhase(PHASE_COMPUTE_EDGE_WEIGHTS);
4770 #if FEATURE_EH_FUNCLETS
4772 /* Create funclets from the EH handlers. */
4775 EndPhase(PHASE_CREATE_FUNCLETS);
4777 #endif // FEATURE_EH_FUNCLETS
4779 if (!opts.MinOpts() && !opts.compDbgCode)
4781 optOptimizeLayout();
4782 EndPhase(PHASE_OPTIMIZE_LAYOUT);
4784 // Compute reachability sets and dominators.
4785 fgComputeReachability();
4786 EndPhase(PHASE_COMPUTE_REACHABILITY);
4789 // Transform each GT_ALLOCOBJ node into either an allocation helper call or
4790 // local variable allocation on the stack.
4791 ObjectAllocator objectAllocator(this);
4792 objectAllocator.Run();
4794 if (!opts.MinOpts() && !opts.compDbgCode)
4796 /* Perform loop inversion (i.e. transform "while" loops into
4797 "repeat" loops) and discover and classify natural loops
4798 (e.g. mark iterative loops as such). Also marks loop blocks
4799 and sets bbWeight to the loop nesting levels
4803 EndPhase(PHASE_OPTIMIZE_LOOPS);
4805 // Clone loops with optimization opportunities, and
4806 // choose the one based on dynamic condition evaluation.
4808 EndPhase(PHASE_CLONE_LOOPS);
4812 EndPhase(PHASE_UNROLL_LOOPS);
4816 fgDebugCheckLinks();
4819 /* Create the variable table (and compute variable ref counts) */
4822 EndPhase(PHASE_MARK_LOCAL_VARS);
4824 // IMPORTANT, after this point, every place where trees are modified or cloned
4825 // the local variable reference counts must be updated
4826 // You can test the value of the following variable to see if
4827 // the local variable ref counts must be updated
4829 assert(lvaLocalVarRefCounted == true);
4831 if (!opts.MinOpts() && !opts.compDbgCode)
4833 /* Optimize boolean conditions */
4836 EndPhase(PHASE_OPTIMIZE_BOOLS);
4838 // optOptimizeBools() might have changed the number of blocks; the dominators/reachability might be bad.
4841 /* Figure out the order in which operators are to be evaluated */
4843 EndPhase(PHASE_FIND_OPER_ORDER);
4845 // Weave the tree lists. Anyone who modifies the tree shapes after
4846 // this point is responsible for calling fgSetStmtSeq() to keep the
4847 // nodes properly linked.
4848 // This can create GC poll calls, and create new BasicBlocks (without updating dominators/reachability).
4850 EndPhase(PHASE_SET_BLOCK_ORDER);
4852 // IMPORTANT, after this point, every place where tree topology changes must redo evaluation
4853 // order (gtSetStmtInfo) and relink nodes (fgSetStmtSeq) if required.
4854 CLANG_FORMAT_COMMENT_ANCHOR;
4857 // Now we have determined the order of evaluation and the gtCosts for every node.
4858 // If verbose, dump the full set of trees here before the optimization phases mutate them
4862 fgDispBasicBlocks(true); // 'true' will call fgDumpTrees() after dumping the BasicBlocks
4867 // At this point we know if we are fully interruptible or not
4868 if (!opts.MinOpts() && !opts.compDbgCode)
4871 bool doEarlyProp = true;
4872 bool doValueNum = true;
4873 bool doLoopHoisting = true;
4874 bool doCopyProp = true;
4875 bool doAssertionProp = true;
4876 bool doRangeAnalysis = true;
4879 #if defined(OPT_CONFIG)
4880 doSsa = (JitConfig.JitDoSsa() != 0);
4881 doEarlyProp = doSsa && (JitConfig.JitDoEarlyProp() != 0);
4882 doValueNum = doSsa && (JitConfig.JitDoValueNumber() != 0);
4883 doLoopHoisting = doValueNum && (JitConfig.JitDoLoopHoisting() != 0);
4884 doCopyProp = doValueNum && (JitConfig.JitDoCopyProp() != 0);
4885 doAssertionProp = doValueNum && (JitConfig.JitDoAssertionProp() != 0);
4886 doRangeAnalysis = doAssertionProp && (JitConfig.JitDoRangeAnalysis() != 0);
4890 iterations = JitConfig.JitOptRepeatCount();
4892 #endif // defined(OPT_CONFIG)
4894 while (iterations > 0)
4899 EndPhase(PHASE_BUILD_SSA);
4904 /* Propagate array length and rewrite getType() method call */
4906 EndPhase(PHASE_EARLY_PROP);
4912 EndPhase(PHASE_VALUE_NUMBER);
4917 /* Hoist invariant code out of loops */
4919 EndPhase(PHASE_HOIST_LOOP_CODE);
4924 /* Perform VN based copy propagation */
4926 EndPhase(PHASE_VN_COPY_PROP);
4930 /* Remove common sub-expressions */
4932 #endif // FEATURE_ANYCSE
4935 if (doAssertionProp)
4937 /* Assertion propagation */
4938 optAssertionPropMain();
4939 EndPhase(PHASE_ASSERTION_PROP_MAIN);
4942 if (doRangeAnalysis)
4944 /* Optimize array index range checks */
4945 RangeCheck rc(this);
4946 rc.OptimizeRangeChecks();
4947 EndPhase(PHASE_OPTIMIZE_INDEX_CHECKS);
4949 #endif // ASSERTION_PROP
4951 /* update the flowgraph if we modified it during the optimization phase*/
4954 fgUpdateFlowGraph();
4955 EndPhase(PHASE_UPDATE_FLOW_GRAPH);
4957 // Recompute the edge weight if we have modified the flow graph
4958 fgComputeEdgeWeights();
4959 EndPhase(PHASE_COMPUTE_EDGE_WEIGHTS2);
4962 // Iterate if requested, resetting annotations first.
4963 if (--iterations == 0)
4967 ResetOptAnnotations();
4968 RecomputeLoopInfo();
4972 #ifdef _TARGET_AMD64_
4973 // Check if we need to add the Quirk for the PPP backward compat issue
4974 compQuirkForPPPflag = compQuirkForPPP();
4977 fgDetermineFirstColdBlock();
4978 EndPhase(PHASE_DETERMINE_FIRST_COLD_BLOCK);
4981 fgDebugCheckLinks(compStressCompile(STRESS_REMORPH_TREES, 50));
4983 // Stash the current estimate of the function's size if necessary.
4986 compSizeEstimate = 0;
4987 compCycleEstimate = 0;
4988 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
4990 for (GenTreeStmt* stmt = block->firstStmt(); stmt != nullptr; stmt = stmt->getNextStmt())
4992 compSizeEstimate += stmt->GetCostSz();
4993 compCycleEstimate += stmt->GetCostEx();
4999 #ifndef LEGACY_BACKEND
5000 // rationalize trees
5001 Rationalizer rat(this); // PHASE_RATIONALIZE
5003 #endif // !LEGACY_BACKEND
5005 // Here we do "simple lowering". When the RyuJIT backend works for all
5006 // platforms, this will be part of the more general lowering phase. For now, though, we do a separate
5007 // pass of "final lowering." We must do this before (final) liveness analysis, because this creates
5008 // range check throw blocks, in which the liveness must be correct.
5010 EndPhase(PHASE_SIMPLE_LOWERING);
5012 #ifdef LEGACY_BACKEND
5013 /* Local variable liveness */
5014 fgLocalVarLiveness();
5015 EndPhase(PHASE_LCLVARLIVENESS);
5016 #endif // !LEGACY_BACKEND
5019 fgDebugCheckBBlist();
5020 fgDebugCheckLinks();
5023 /* Enable this to gather statistical data such as
5024 * call and register argument info, flowgraph and loop info, etc. */
5029 if (compLocallocUsed)
5031 // We reserve REG_SAVED_LOCALLOC_SP to store SP on entry for stack unwinding
5032 codeGen->regSet.rsMaskResvd |= RBM_SAVED_LOCALLOC_SP;
5034 #endif // _TARGET_ARM_
5035 #if defined(_TARGET_ARMARCH_) && defined(LEGACY_BACKEND)
5036 // Determine whether we need to reserve a register for large lclVar offsets.
5037 // The determination depends heavily on the number of locals, which changes for RyuJIT backend
5038 // due to the introduction of new temps during Rationalizer and Lowering.
5039 // In LEGACY_BACKEND we do that here even though the decision to have a frame pointer or not may
5040 // change during register allocation, changing the computation somewhat.
5041 // In RyuJIT backend we do this after determining the frame type, and before beginning
5042 // register allocation.
5043 if (compRsvdRegCheck(PRE_REGALLOC_FRAME_LAYOUT))
5045 // We reserve R10/IP1 in this case to hold the offsets in load/store instructions
5046 codeGen->regSet.rsMaskResvd |= RBM_OPT_RSVD;
5047 assert(REG_OPT_RSVD != REG_FP);
5048 JITDUMP(" Reserved REG_OPT_RSVD (%s) due to large frame\n", getRegName(REG_OPT_RSVD));
5050 // compRsvdRegCheck() has read out the FramePointerUsed property, but doLinearScan()
5051 // tries to overwrite it later. This violates the PhasedVar rule and triggers an assertion.
5052 // TODO-ARM-Bug?: What is the proper way to handle this situation?
5053 codeGen->resetFramePointerUsedWritePhase();
5057 // Display the pre-regalloc frame offsets that we have tentatively decided upon
5062 #endif // _TARGET_ARMARCH_
5064 /* Assign registers to variables, etc. */
5065 CLANG_FORMAT_COMMENT_ANCHOR;
5067 #ifndef LEGACY_BACKEND
5068 ///////////////////////////////////////////////////////////////////////////////
5069 // Dominator and reachability sets are no longer valid. They haven't been
5070 // maintained up to here, and shouldn't be used (unless recomputed).
5071 ///////////////////////////////////////////////////////////////////////////////
5072 fgDomsComputed = false;
5074 /* Create LSRA before Lowering, this way Lowering can initialize the TreeNode Map */
5075 m_pLinearScan = getLinearScanAllocator(this);
5078 m_pLowering = new (this, CMK_LSRA) Lowering(this, m_pLinearScan); // PHASE_LOWERING
5081 StackLevelSetter stackLevelSetter(this); // PHASE_STACK_LEVEL_SETTER
5082 stackLevelSetter.Run();
5084 assert(lvaSortAgain == false); // We should have re-run fgLocalVarLiveness() in lower.Run()
5085 lvaTrackedFixed = true; // We can not add any new tracked variables after this point.
5087 /* Now that lowering is completed we can proceed to perform register allocation */
5088 m_pLinearScan->doLinearScan();
5089 EndPhase(PHASE_LINEAR_SCAN);
5091 // Copied from rpPredictRegUse()
5092 genFullPtrRegMap = (codeGen->genInterruptible || !codeGen->isFramePointerUsed());
5093 #else // LEGACY_BACKEND
5095 lvaTrackedFixed = true; // We cannot add any new tracked variables after this point.
5096 // For the classic JIT32 at this point lvaSortAgain can be set and raAssignVars() will call lvaSortOnly()
5098 // Now do "classic" register allocation.
5100 EndPhase(PHASE_RA_ASSIGN_VARS);
5101 #endif // LEGACY_BACKEND
5104 fgDebugCheckLinks();
5109 codeGen->genGenerateCode(methodCodePtr, methodCodeSize);
5111 #ifdef FEATURE_JIT_METHOD_PERF
5114 #if MEASURE_CLRAPI_CALLS
5115 EndPhase(PHASE_CLR_API);
5117 pCompJitTimer->Terminate(this, CompTimeSummaryInfo::s_compTimeSummary, true);
5121 RecordStateAtEndOfCompilation();
5123 #ifdef FEATURE_TRACELOGGING
5124 compJitTelemetry.NotifyEndOfCompilation();
5128 ++Compiler::jitTotalMethodCompiled;
5129 #endif // defined(DEBUG)
5131 compFunctionTraceEnd(*methodCodePtr, *methodCodeSize, false);
5132 JITDUMP("Method code size: %d\n", (unsigned)(*methodCodeSize));
5134 #if FUNC_INFO_LOGGING
5135 if (compJitFuncInfoFile != nullptr)
5137 assert(!compIsForInlining());
5138 #ifdef DEBUG // We only have access to info.compFullName in DEBUG builds.
5139 fprintf(compJitFuncInfoFile, "%s\n", info.compFullName);
5141 fprintf(compJitFuncInfoFile, " %s\n", eeGetMethodFullName(info.compMethodHnd));
5143 fprintf(compJitFuncInfoFile, ""); // in our logic this causes a flush
5145 #endif // FUNC_INFO_LOGGING
5148 //------------------------------------------------------------------------
5149 // ResetOptAnnotations: Clear annotations produced during global optimizations.
5152 // The intent of this method is to clear any information typically assumed
5153 // to be set only once; it is used between iterations when JitOptRepeat is
5156 void Compiler::ResetOptAnnotations()
5158 assert(opts.optRepeat);
5159 assert(JitConfig.JitOptRepeatCount() > 0);
5162 m_opAsgnVarDefSsaNums = nullptr;
5163 m_blockToEHPreds = nullptr;
5164 fgSsaPassesCompleted = 0;
5165 fgVNPassesCompleted = 0;
5167 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
5169 for (GenTreeStmt* stmt = block->firstStmt(); stmt != nullptr; stmt = stmt->getNextStmt())
5171 stmt->gtFlags &= ~GTF_STMT_HAS_CSE;
5173 for (GenTree* tree = stmt->gtStmt.gtStmtList; tree != nullptr; tree = tree->gtNext)
5176 tree->ClearAssertion();
5177 tree->gtCSEnum = NO_CSE;
5183 //------------------------------------------------------------------------
5184 // RecomputeLoopInfo: Recompute loop annotations between opt-repeat iterations.
5187 // The intent of this method is to update loop structure annotations, and those
5188 // they depend on; these annotations may have become stale during optimization,
5189 // and need to be up-to-date before running another iteration of optimizations.
5191 void Compiler::RecomputeLoopInfo()
5193 assert(opts.optRepeat);
5194 assert(JitConfig.JitOptRepeatCount() > 0);
5195 // Recompute reachability sets, dominators, and loops.
5197 fgDomsComputed = false;
5198 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
5200 block->bbFlags &= ~BBF_LOOP_FLAGS;
5202 fgComputeReachability();
5203 // Rebuild the loop tree annotations themselves. Since this is performed as
5204 // part of 'optOptimizeLoops', this will also re-perform loop rotation, but
5205 // not other optimizations, as the others are not part of 'optOptimizeLoops'.
5209 /*****************************************************************************/
5210 void Compiler::ProcessShutdownWork(ICorStaticInfo* statInfo)
5214 #ifdef _TARGET_AMD64_
5215 // Check if we need to add the Quirk for the PPP backward compat issue.
5216 // This Quirk addresses a compatibility issue between the new RyuJit and the previous JIT64.
5217 // A backward compatibity issue called 'PPP' exists where a PInvoke call passes a 32-byte struct
5218 // into a native API which basically writes 48 bytes of data into the struct.
5219 // With the stack frame layout used by the RyuJIT the extra 16 bytes written corrupts a
5220 // caller saved register and this leads to an A/V in the calling method.
5221 // The older JIT64 jit compiler just happened to have a different stack layout and/or
5222 // caller saved register set so that it didn't hit the A/V in the caller.
5223 // By increasing the amount of stack allocted for the struct by 32 bytes we can fix this.
5225 // Return true if we actually perform the Quirk, otherwise return false
5227 bool Compiler::compQuirkForPPP()
5230 { // We require that there are exactly two locals
5234 if (compTailCallUsed)
5235 { // Don't try this quirk if a tail call was used
5239 bool hasOutArgs = false;
5240 LclVarDsc* varDscExposedStruct = nullptr;
5245 /* Look for struct locals that are address taken */
5246 for (lclNum = 0, varDsc = lvaTable; lclNum < lvaCount; lclNum++, varDsc++)
5248 if (varDsc->lvIsParam) // It can't be a parameter
5253 // We require that the OutgoingArg space lclVar exists
5254 if (lclNum == lvaOutgoingArgSpaceVar)
5256 hasOutArgs = true; // Record that we saw it
5260 // Look for a 32-byte address exposed Struct and record its varDsc
5261 if ((varDsc->TypeGet() == TYP_STRUCT) && varDsc->lvAddrExposed && (varDsc->lvExactSize == 32))
5263 varDscExposedStruct = varDsc;
5267 // We only perform the Quirk when there are two locals
5268 // one of them is a address exposed struct of size 32
5269 // and the other is the outgoing arg space local
5271 if (hasOutArgs && (varDscExposedStruct != nullptr))
5276 printf("\nAdding a backwards compatibility quirk for the 'PPP' issue\n");
5280 // Increase the exact size of this struct by 32 bytes
5281 // This fixes the PPP backward compat issue
5282 varDscExposedStruct->lvExactSize += 32;
5284 // Update the GC info to indicate that the padding area does
5285 // not contain any GC pointers.
5287 // The struct is now 64 bytes.
5289 // We're on x64 so this should be 8 pointer slots.
5290 assert((varDscExposedStruct->lvExactSize / TARGET_POINTER_SIZE) == 8);
5292 BYTE* oldGCPtrs = varDscExposedStruct->lvGcLayout;
5293 BYTE* newGCPtrs = (BYTE*)compGetMem(8, CMK_LvaTable);
5295 for (int i = 0; i < 4; i++)
5297 newGCPtrs[i] = oldGCPtrs[i];
5300 for (int i = 4; i < 8; i++)
5302 newGCPtrs[i] = TYPE_GC_NONE;
5305 varDscExposedStruct->lvGcLayout = newGCPtrs;
5311 #endif // _TARGET_AMD64_
5313 /*****************************************************************************/
5316 void* forceFrameJIT; // used to force to frame &useful for fastchecked debugging
5318 bool Compiler::skipMethod()
5320 static ConfigMethodRange fJitRange;
5321 fJitRange.EnsureInit(JitConfig.JitRange());
5322 assert(!fJitRange.Error());
5324 // Normally JitConfig.JitRange() is null, we don't want to skip
5325 // jitting any methods.
5327 // So, the logic below relies on the fact that a null range string
5328 // passed to ConfigMethodRange represents the set of all methods.
5330 if (!fJitRange.Contains(info.compCompHnd, info.compMethodHnd))
5335 if (JitConfig.JitExclude().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
5340 if (!JitConfig.JitInclude().isEmpty() &&
5341 !JitConfig.JitInclude().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
5351 /*****************************************************************************/
5353 int Compiler::compCompile(CORINFO_METHOD_HANDLE methodHnd,
5354 CORINFO_MODULE_HANDLE classPtr,
5355 COMP_HANDLE compHnd,
5356 CORINFO_METHOD_INFO* methodInfo,
5357 void** methodCodePtr,
5358 ULONG* methodCodeSize,
5359 JitFlags* compileFlags)
5361 #ifdef FEATURE_JIT_METHOD_PERF
5362 static bool checkedForJitTimeLog = false;
5364 pCompJitTimer = nullptr;
5366 if (!checkedForJitTimeLog)
5368 // Call into VM to get the config strings. FEATURE_JIT_METHOD_PERF is enabled for
5369 // retail builds. Do not call the regular Config helper here as it would pull
5370 // in a copy of the config parser into the clrjit.dll.
5371 InterlockedCompareExchangeT(&Compiler::compJitTimeLogFilename, compHnd->getJitTimeLogFilename(), NULL);
5373 // At a process or module boundary clear the file and start afresh.
5374 JitTimer::PrintCsvHeader();
5376 checkedForJitTimeLog = true;
5378 if ((Compiler::compJitTimeLogFilename != nullptr) || (JitTimeLogCsv() != nullptr))
5380 pCompJitTimer = JitTimer::Create(this, methodInfo->ILCodeSize);
5382 #endif // FEATURE_JIT_METHOD_PERF
5385 Compiler* me = this;
5386 forceFrameJIT = (void*)&me; // let us see the this pointer in fastchecked build
5387 // set this early so we can use it without relying on random memory values
5388 verbose = compIsForInlining() ? impInlineInfo->InlinerCompiler->verbose : false;
5390 this->dumpIR = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIR : false;
5391 this->dumpIRPhase = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRPhase : nullptr;
5392 this->dumpIRFormat = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRFormat : nullptr;
5393 this->dumpIRTypes = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRTypes : false;
5394 this->dumpIRLocals = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRLocals : false;
5395 this->dumpIRRegs = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRRegs : false;
5396 this->dumpIRSsa = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRSsa : false;
5397 this->dumpIRValnums = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRValnums : false;
5398 this->dumpIRCosts = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRCosts : false;
5399 this->dumpIRFlags = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRFlags : false;
5400 this->dumpIRKinds = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRKinds : false;
5401 this->dumpIRNodes = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRNodes : false;
5402 this->dumpIRNoLists = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRNoLists : false;
5403 this->dumpIRNoLeafs = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRNoLeafs : false;
5404 this->dumpIRNoStmts = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRNoStmts : false;
5405 this->dumpIRTrees = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRTrees : false;
5406 this->dumpIRLinear = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRLinear : false;
5407 this->dumpIRDataflow = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRDataflow : false;
5408 this->dumpIRBlockHeaders = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRBlockHeaders : NULL;
5409 this->dumpIRExit = compIsForInlining() ? impInlineInfo->InlinerCompiler->dumpIRExit : NULL;
5413 #if defined(DEBUG) || defined(INLINE_DATA)
5414 info.compMethodHashPrivate = 0;
5415 #endif // defined(DEBUG) || defined(INLINE_DATA)
5417 #if FUNC_INFO_LOGGING
5418 LPCWSTR tmpJitFuncInfoFilename = JitConfig.JitFuncInfoFile();
5420 if (tmpJitFuncInfoFilename != nullptr)
5422 LPCWSTR oldFuncInfoFileName =
5423 InterlockedCompareExchangeT(&compJitFuncInfoFilename, tmpJitFuncInfoFilename, NULL);
5424 if (oldFuncInfoFileName == nullptr)
5426 assert(compJitFuncInfoFile == nullptr);
5427 compJitFuncInfoFile = _wfopen(compJitFuncInfoFilename, W("a"));
5428 if (compJitFuncInfoFile == nullptr)
5430 #if defined(DEBUG) && !defined(FEATURE_PAL) // no 'perror' in the PAL
5431 perror("Failed to open JitFuncInfoLogFile");
5432 #endif // defined(DEBUG) && !defined(FEATURE_PAL)
5436 #endif // FUNC_INFO_LOGGING
5438 // if (s_compMethodsCount==0) setvbuf(jitstdout, NULL, _IONBF, 0);
5440 info.compCompHnd = compHnd;
5441 info.compMethodHnd = methodHnd;
5442 info.compMethodInfo = methodInfo;
5444 virtualStubParamInfo = new (this, CMK_Unknown) VirtualStubParamInfo(IsTargetAbi(CORINFO_CORERT_ABI));
5446 // Do we have a matched VM? Or are we "abusing" the VM to help us do JIT work (such as using an x86 native VM
5447 // with an ARM-targeting "altjit").
5448 info.compMatchedVM = IMAGE_FILE_MACHINE_TARGET == info.compCompHnd->getExpectedTargetArchitecture();
5450 #if (defined(_TARGET_UNIX_) && !defined(_HOST_UNIX_)) || (!defined(_TARGET_UNIX_) && defined(_HOST_UNIX_))
5451 // The host and target platforms don't match. This info isn't handled by the existing
5452 // getExpectedTargetArchitecture() JIT-EE interface method.
5453 info.compMatchedVM = false;
5456 compMaxUncheckedOffsetForNullObject = eeGetEEInfo()->maxUncheckedOffsetForNullObject;
5458 // Set the context for token lookup.
5459 if (compIsForInlining())
5461 impTokenLookupContextHandle = impInlineInfo->tokenLookupContextHandle;
5463 assert(impInlineInfo->inlineCandidateInfo->clsHandle == compHnd->getMethodClass(methodHnd));
5464 info.compClassHnd = impInlineInfo->inlineCandidateInfo->clsHandle;
5466 assert(impInlineInfo->inlineCandidateInfo->clsAttr == info.compCompHnd->getClassAttribs(info.compClassHnd));
5467 // printf("%x != %x\n", impInlineInfo->inlineCandidateInfo->clsAttr,
5468 // info.compCompHnd->getClassAttribs(info.compClassHnd));
5469 info.compClassAttr = impInlineInfo->inlineCandidateInfo->clsAttr;
5473 impTokenLookupContextHandle = MAKE_METHODCONTEXT(info.compMethodHnd);
5475 info.compClassHnd = compHnd->getMethodClass(methodHnd);
5476 info.compClassAttr = info.compCompHnd->getClassAttribs(info.compClassHnd);
5479 info.compProfilerCallback = false; // Assume false until we are told to hook this method.
5481 #if defined(DEBUG) || defined(LATE_DISASM)
5482 const char* classNamePtr;
5484 info.compMethodName = eeGetMethodName(methodHnd, &classNamePtr);
5485 unsigned len = (unsigned)roundUp(strlen(classNamePtr) + 1);
5486 info.compClassName = (char*)compGetMem(len, CMK_DebugOnly);
5487 strcpy_s((char*)info.compClassName, len, classNamePtr);
5489 info.compFullName = eeGetMethodFullName(methodHnd);
5490 #endif // defined(DEBUG) || defined(LATE_DISASM)
5493 if (!compIsForInlining())
5495 JitTls::GetLogEnv()->setCompiler(this);
5498 // Have we been told to be more selective in our Jitting?
5501 if (compIsForInlining())
5503 compInlineResult->NoteFatal(InlineObservation::CALLEE_MARKED_AS_SKIPPED);
5505 return CORJIT_SKIPPED;
5508 // Opt-in to jit stress based on method hash ranges.
5510 // Note the default (with JitStressRange not set) is that all
5511 // methods will be subject to stress.
5512 static ConfigMethodRange fJitStressRange;
5513 fJitStressRange.EnsureInit(JitConfig.JitStressRange());
5514 assert(!fJitStressRange.Error());
5515 bRangeAllowStress = fJitStressRange.Contains(info.compCompHnd, info.compMethodHnd);
5519 // Set this before the first 'BADCODE'
5520 // Skip verification where possible
5521 tiVerificationNeeded = !compileFlags->IsSet(JitFlags::JIT_FLAG_SKIP_VERIFICATION);
5523 assert(!compIsForInlining() || !tiVerificationNeeded); // Inlinees must have been verified.
5525 // assume the code is verifiable unless proven otherwise
5526 tiIsVerifiableCode = TRUE;
5528 tiRuntimeCalloutNeeded = false;
5530 CorInfoInstantiationVerification instVerInfo = INSTVER_GENERIC_PASSED_VERIFICATION;
5532 if (!compIsForInlining() && tiVerificationNeeded)
5534 instVerInfo = compHnd->isInstantiationOfVerifiedGeneric(methodHnd);
5536 if (tiVerificationNeeded && (instVerInfo == INSTVER_GENERIC_FAILED_VERIFICATION))
5538 CorInfoCanSkipVerificationResult canSkipVerificationResult =
5539 info.compCompHnd->canSkipMethodVerification(info.compMethodHnd);
5541 switch (canSkipVerificationResult)
5543 case CORINFO_VERIFICATION_CANNOT_SKIP:
5544 // We cannot verify concrete instantiation.
5545 // We can only verify the typical/open instantiation
5546 // The VM should throw a VerificationException instead of allowing this.
5547 NO_WAY("Verification of closed instantiations is not supported");
5550 case CORINFO_VERIFICATION_CAN_SKIP:
5551 // The VM should first verify the open instantiation. If unverifiable code
5552 // is detected, it should pass in JitFlags::JIT_FLAG_SKIP_VERIFICATION.
5553 assert(!"The VM should have used JitFlags::JIT_FLAG_SKIP_VERIFICATION");
5554 tiVerificationNeeded = false;
5557 case CORINFO_VERIFICATION_RUNTIME_CHECK:
5558 // This is a concrete generic instantiation with unverifiable code, that also
5559 // needs a runtime callout.
5560 tiVerificationNeeded = false;
5561 tiRuntimeCalloutNeeded = true;
5564 case CORINFO_VERIFICATION_DONT_JIT:
5565 // We cannot verify concrete instantiation.
5566 // We can only verify the typical/open instantiation
5567 // The VM should throw a VerificationException instead of allowing this.
5568 BADCODE("NGEN of unverifiable transparent code is not supported");
5573 // load any constraints for verification, noting any cycles to be rejected by the verifying importer
5574 if (tiVerificationNeeded)
5576 compHnd->initConstraintsForVerification(methodHnd, &info.hasCircularClassConstraints,
5577 &info.hasCircularMethodConstraints);
5581 /* Setup an error trap */
5587 CORINFO_MODULE_HANDLE classPtr;
5588 COMP_HANDLE compHnd;
5589 CORINFO_METHOD_INFO* methodInfo;
5590 void** methodCodePtr;
5591 ULONG* methodCodeSize;
5592 JitFlags* compileFlags;
5594 CorInfoInstantiationVerification instVerInfo;
5598 param.classPtr = classPtr;
5599 param.compHnd = compHnd;
5600 param.methodInfo = methodInfo;
5601 param.methodCodePtr = methodCodePtr;
5602 param.methodCodeSize = methodCodeSize;
5603 param.compileFlags = compileFlags;
5604 param.instVerInfo = instVerInfo;
5605 param.result = CORJIT_INTERNALERROR;
5607 setErrorTrap(compHnd, Param*, pParam, ¶m) // ERROR TRAP: Start normal block
5609 pParam->result = pParam->pThis->compCompileHelper(pParam->classPtr, pParam->compHnd, pParam->methodInfo,
5610 pParam->methodCodePtr, pParam->methodCodeSize,
5611 pParam->compileFlags, pParam->instVerInfo);
5613 finallyErrorTrap() // ERROR TRAP: The following block handles errors
5617 if (compIsForInlining())
5622 /* Tell the emitter that we're done with this function */
5624 genEmitter->emitEndCG();
5629 endErrorTrap() // ERROR TRAP: End
5631 return param.result;
5634 #if defined(DEBUG) || defined(INLINE_DATA)
5635 unsigned Compiler::Info::compMethodHash() const
5637 if (compMethodHashPrivate == 0)
5639 compMethodHashPrivate = compCompHnd->getMethodHash(compMethodHnd);
5641 return compMethodHashPrivate;
5643 #endif // defined(DEBUG) || defined(INLINE_DATA)
5645 void Compiler::compCompileFinish()
5647 #if defined(DEBUG) || MEASURE_NODE_SIZE || MEASURE_BLOCK_SIZE || DISPLAY_SIZES || CALL_ARG_STATS
5651 #if MEASURE_MEM_ALLOC
5653 // Grab the relevant lock.
5654 CritSecHolder statsLock(s_memStatsLock);
5656 // Make the updates.
5657 genMemStats.nraTotalSizeAlloc = compGetAllocator()->getTotalBytesAllocated();
5658 genMemStats.nraTotalSizeUsed = compGetAllocator()->getTotalBytesUsed();
5659 memAllocHist.record((unsigned)((genMemStats.nraTotalSizeAlloc + 1023) / 1024));
5660 memUsedHist.record((unsigned)((genMemStats.nraTotalSizeUsed + 1023) / 1024));
5661 s_aggMemStats.Add(genMemStats);
5662 if (genMemStats.allocSz > s_maxCompMemStats.allocSz)
5664 s_maxCompMemStats = genMemStats;
5669 if (s_dspMemStats || verbose)
5671 printf("\nAllocations for %s (MethodHash=%08x)\n", info.compFullName, info.compMethodHash());
5672 genMemStats.Print(jitstdout);
5675 #endif // MEASURE_MEM_ALLOC
5677 #if LOOP_HOIST_STATS
5678 AddLoopHoistStats();
5679 #endif // LOOP_HOIST_STATS
5681 #if MEASURE_NODE_SIZE
5682 genTreeNcntHist.record(static_cast<unsigned>(genNodeSizeStatsPerFunc.genTreeNodeCnt));
5683 genTreeNsizHist.record(static_cast<unsigned>(genNodeSizeStatsPerFunc.genTreeNodeSize));
5687 // Small methods should fit in ArenaAllocator::getDefaultPageSize(), or else
5688 // we should bump up ArenaAllocator::getDefaultPageSize()
5690 if ((info.compILCodeSize <= 32) && // Is it a reasonably small method?
5691 (info.compNativeCodeSize < 512) && // Some trivial methods generate huge native code. eg. pushing a single huge
5693 (impInlinedCodeSize <= 128) && // Is the the inlining reasonably bounded?
5694 // Small methods cannot meaningfully have a big number of locals
5695 // or arguments. We always track arguments at the start of
5696 // the prolog which requires memory
5697 (info.compLocalsCount <= 32) && (!opts.MinOpts()) && // We may have too many local variables, etc
5698 (getJitStressLevel() == 0) && // We need extra memory for stress
5699 !opts.optRepeat && // We need extra memory to repeat opts
5700 !compAllocator->bypassHostAllocator() && // ArenaAllocator::getDefaultPageSize() is artificially low for
5702 (compAllocator->getTotalBytesAllocated() > (2 * ArenaAllocator::getDefaultPageSize())) &&
5703 // Factor of 2x is because data-structures are bigger under DEBUG
5704 #ifndef LEGACY_BACKEND
5705 // RyuJIT backend needs memory tuning! TODO-Cleanup: remove this case when memory tuning is complete.
5706 (compAllocator->getTotalBytesAllocated() > (10 * ArenaAllocator::getDefaultPageSize())) &&
5708 !verbose) // We allocate lots of memory to convert sets to strings for JitDump
5710 genSmallMethodsNeedingExtraMemoryCnt++;
5712 // Less than 1% of all methods should run into this.
5713 // We cannot be more strict as there are always degenerate cases where we
5714 // would need extra memory (like huge structs as locals - see lvaSetStruct()).
5715 assert((genMethodCnt < 500) || (genSmallMethodsNeedingExtraMemoryCnt < (genMethodCnt / 100)));
5719 #if defined(DEBUG) || defined(INLINE_DATA)
5721 m_inlineStrategy->DumpData();
5722 m_inlineStrategy->DumpXml();
5729 // mdMethodDef __stdcall CEEInfo::getMethodDefFromMethod(CORINFO_METHOD_HANDLE hMethod)
5730 mdMethodDef currentMethodToken = info.compCompHnd->getMethodDefFromMethod(info.compMethodHnd);
5732 unsigned profCallCount = 0;
5733 if (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_BBOPT) && fgHaveProfileData())
5735 assert(fgProfileBuffer[0].ILOffset == 0);
5736 profCallCount = fgProfileBuffer[0].ExecutionCount;
5739 static bool headerPrinted = false;
5743 headerPrinted = true;
5744 printf(" | Profiled | Exec- | Method has | calls | Num |LclV |AProp| CSE | Reg |bytes | %3s code size | \n", Target::g_tgtCPUName);
5745 printf(" mdToken | | RGN | Count | EH | FRM | LOOP | NRM | IND | BBs | Cnt | Cnt | Cnt | Alloc | IL | HOT | COLD | method name \n");
5746 printf("---------+-----+------+----------+----+-----+------+-----+-----+-----+-----+-----+-----+---------+------+-------+-------+-----------\n");
5747 // 06001234 | PRF | HOT | 219 | EH | ebp | LOOP | 15 | 6 | 12 | 17 | 12 | 8 | 28 p2 | 145 | 211 | 123 | System.Example(int)
5751 printf("%08X | ", currentMethodToken);
5753 CorInfoRegionKind regionKind = info.compMethodInfo->regionKind;
5759 else if (fgHaveProfileData())
5768 if (regionKind == CORINFO_REGION_NONE)
5772 else if (regionKind == CORINFO_REGION_HOT)
5776 else if (regionKind == CORINFO_REGION_COLD)
5780 else if (regionKind == CORINFO_REGION_JIT)
5789 printf("%8d | ", profCallCount);
5791 if (compHndBBtabCount > 0)
5800 if (rpFrameType == FT_EBP_FRAME)
5802 printf("%3s | ", STR_FPBASE);
5804 else if (rpFrameType == FT_ESP_FRAME)
5806 printf("%3s | ", STR_SPBASE);
5809 else if (rpFrameType == FT_DOUBLE_ALIGN_FRAME)
5814 else // (rpFrameType == FT_NOT_SET)
5828 printf(" %3d |", optCallCount);
5829 printf(" %3d |", optIndirectCallCount);
5830 printf(" %3d |", fgBBcountAtCodegen);
5831 printf(" %3d |", lvaCount);
5835 printf(" MinOpts |");
5839 printf(" %3d |", optAssertionCount);
5841 printf(" %3d |", optCSEcount);
5843 printf(" %3d |", 0);
5844 #endif // FEATURE_ANYCSE
5847 #ifndef LEGACY_BACKEND
5848 printf(" LSRA |"); // TODO-Cleanup: dump some interesting LSRA stat into the order file?
5849 #else // LEGACY_BACKEND
5850 printf("%s%4d p%1d |", (tmpCount > 0) ? "T" : " ", rpStkPredict / BB_UNITY_WEIGHT, rpPasses);
5851 #endif // LEGACY_BACKEND
5852 printf(" %4d |", info.compMethodInfo->ILCodeSize);
5853 printf(" %5d |", info.compTotalHotCodeSize);
5854 printf(" %5d |", info.compTotalColdCodeSize);
5856 printf(" %s\n", eeGetMethodFullName(info.compMethodHnd));
5857 printf(""); // in our logic this causes a flush
5862 printf("****** DONE compiling %s\n", info.compFullName);
5863 printf(""); // in our logic this causes a flush
5866 // Only call _DbgBreakCheck when we are jitting, not when we are ngen-ing
5867 // For ngen the int3 or breakpoint instruction will be right at the
5868 // start of the ngen method and we will stop when we execute it.
5870 if (!opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
5872 if (compJitHaltMethod())
5874 #if !defined(_HOST_UNIX_)
5875 // TODO-UNIX: re-enable this when we have an OS that supports a pop-up dialog
5877 // Don't do an assert, but just put up the dialog box so we get just-in-time debugger
5878 // launching. When you hit 'retry' it will continue and naturally stop at the INT 3
5879 // that the JIT put in the code
5880 _DbgBreakCheck(__FILE__, __LINE__, "JitHalt");
5887 #ifdef PSEUDORANDOM_NOP_INSERTION
5888 // this is zlib adler32 checksum. source came from windows base
5890 #define BASE 65521L // largest prime smaller than 65536
5892 // NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1
5894 #define DO1(buf, i) \
5899 #define DO2(buf, i) \
5902 #define DO4(buf, i) \
5905 #define DO8(buf, i) \
5912 unsigned adler32(unsigned adler, char* buf, unsigned int len)
5914 unsigned int s1 = adler & 0xffff;
5915 unsigned int s2 = (adler >> 16) & 0xffff;
5923 k = len < NMAX ? len : NMAX;
5940 return (s2 << 16) | s1;
5944 unsigned getMethodBodyChecksum(__in_z char* code, int size)
5946 #ifdef PSEUDORANDOM_NOP_INSERTION
5947 return adler32(0, code, size);
5953 int Compiler::compCompileHelper(CORINFO_MODULE_HANDLE classPtr,
5954 COMP_HANDLE compHnd,
5955 CORINFO_METHOD_INFO* methodInfo,
5956 void** methodCodePtr,
5957 ULONG* methodCodeSize,
5958 JitFlags* compileFlags,
5959 CorInfoInstantiationVerification instVerInfo)
5961 CORINFO_METHOD_HANDLE methodHnd = info.compMethodHnd;
5963 info.compCode = methodInfo->ILCode;
5964 info.compILCodeSize = methodInfo->ILCodeSize;
5966 if (info.compILCodeSize == 0)
5968 BADCODE("code size is zero");
5971 if (compIsForInlining())
5974 unsigned methAttr_Old = impInlineInfo->inlineCandidateInfo->methAttr;
5975 unsigned methAttr_New = info.compCompHnd->getMethodAttribs(info.compMethodHnd);
5976 unsigned flagsToIgnore = CORINFO_FLG_DONT_INLINE | CORINFO_FLG_FORCEINLINE;
5977 assert((methAttr_Old & (~flagsToIgnore)) == (methAttr_New & (~flagsToIgnore)));
5980 info.compFlags = impInlineInfo->inlineCandidateInfo->methAttr;
5984 info.compFlags = info.compCompHnd->getMethodAttribs(info.compMethodHnd);
5985 #ifdef PSEUDORANDOM_NOP_INSERTION
5986 info.compChecksum = getMethodBodyChecksum((char*)methodInfo->ILCode, methodInfo->ILCodeSize);
5990 // compInitOptions will set the correct verbose flag.
5992 compInitOptions(compileFlags);
5995 if (!compIsForInlining() && !opts.altJit)
5997 // We're an altjit, but the COMPlus_AltJit configuration did not say to compile this method,
5999 return CORJIT_SKIPPED;
6007 printf("IL to import:\n");
6008 dumpILRange(info.compCode, info.compILCodeSize);
6013 // Check for COMPlus_AgressiveInlining
6014 if (JitConfig.JitAggressiveInlining())
6016 compDoAggressiveInlining = true;
6019 if (compDoAggressiveInlining)
6021 info.compFlags |= CORINFO_FLG_FORCEINLINE;
6026 // Check for ForceInline stress.
6027 if (compStressCompile(STRESS_FORCE_INLINE, 0))
6029 info.compFlags |= CORINFO_FLG_FORCEINLINE;
6032 if (compIsForInlining())
6034 JITLOG((LL_INFO100000, "\nINLINER impTokenLookupContextHandle for %s is 0x%p.\n",
6035 eeGetMethodFullName(info.compMethodHnd), dspPtr(impTokenLookupContextHandle)));
6038 // Force verification if asked to do so
6039 if (JitConfig.JitForceVer())
6041 tiVerificationNeeded = (instVerInfo == INSTVER_NOT_INSTANTIATION);
6044 if (tiVerificationNeeded)
6046 JITLOG((LL_INFO10000, "tiVerificationNeeded initially set to true for %s\n", info.compFullName));
6050 /* Since tiVerificationNeeded can be turned off in the middle of
6051 compiling a method, and it might have caused blocks to be queued up
6052 for reimporting, impCanReimport can be used to check for reimporting. */
6054 impCanReimport = (tiVerificationNeeded || compStressCompile(STRESS_CHK_REIMPORT, 15));
6056 // Need security prolog/epilog callouts when there is a declarative security in the method.
6057 tiSecurityCalloutNeeded = ((info.compFlags & CORINFO_FLG_NOSECURITYWRAP) == 0);
6059 if (tiSecurityCalloutNeeded || (info.compFlags & CORINFO_FLG_SECURITYCHECK))
6061 // We need to allocate the security object on the stack
6062 // when the method being compiled has a declarative security
6063 // (i.e. when CORINFO_FLG_NOSECURITYWRAP is reset for the current method).
6064 // This is also the case when we inject a prolog and epilog in the method.
6065 opts.compNeedSecurityCheck = true;
6068 /* Initialize set a bunch of global values */
6070 info.compScopeHnd = classPtr;
6071 info.compXcptnsCount = methodInfo->EHcount;
6072 info.compMaxStack = methodInfo->maxStack;
6073 compHndBBtab = nullptr;
6074 compHndBBtabCount = 0;
6075 compHndBBtabAllocCount = 0;
6077 info.compNativeCodeSize = 0;
6078 info.compTotalHotCodeSize = 0;
6079 info.compTotalColdCodeSize = 0;
6082 compCurBB = nullptr;
6085 // Reset node and block ID counter
6087 compBasicBlockID = 0;
6090 /* Initialize emitter */
6092 if (!compIsForInlining())
6094 codeGen->getEmitter()->emitBegCG(this, compHnd);
6097 info.compIsStatic = (info.compFlags & CORINFO_FLG_STATIC) != 0;
6099 info.compIsContextful = (info.compClassAttr & CORINFO_FLG_CONTEXTFUL) != 0;
6101 info.compPublishStubParam = opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PUBLISH_SECRET_PARAM);
6103 switch (methodInfo->args.getCallConv())
6105 case CORINFO_CALLCONV_VARARG:
6106 case CORINFO_CALLCONV_NATIVEVARARG:
6107 info.compIsVarArgs = true;
6109 case CORINFO_CALLCONV_DEFAULT:
6110 info.compIsVarArgs = false;
6113 BADCODE("bad calling convention");
6115 info.compRetNativeType = info.compRetType = JITtype2varType(methodInfo->args.retType);
6117 info.compCallUnmanaged = 0;
6118 info.compLvFrameListRoot = BAD_VAR_NUM;
6120 info.compInitMem = ((methodInfo->options & CORINFO_OPT_INIT_LOCALS) != 0);
6122 /* Allocate the local variable table */
6126 if (!compIsForInlining())
6128 compInitDebuggingInfo();
6132 if (compIsForInlining())
6134 compBasicBlockID = impInlineInfo->InlinerCompiler->compBasicBlockID;
6138 const bool forceInline = !!(info.compFlags & CORINFO_FLG_FORCEINLINE);
6140 if (!compIsForInlining() && opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
6142 // We're prejitting the root method. We also will analyze it as
6143 // a potential inline candidate.
6144 InlineResult prejitResult(this, methodHnd, "prejit");
6146 // Do the initial inline screen.
6147 impCanInlineIL(methodHnd, methodInfo, forceInline, &prejitResult);
6149 // Temporarily install the prejitResult as the
6150 // compInlineResult so it's available to fgFindJumpTargets
6151 // and can accumulate more observations as the IL is
6154 // We don't pass prejitResult in as a parameter to avoid
6155 // potential aliasing confusion -- the other call to
6156 // fgFindBasicBlocks may have set up compInlineResult and
6157 // the code in fgFindJumpTargets references that data
6158 // member extensively.
6159 assert(compInlineResult == nullptr);
6160 assert(impInlineInfo == nullptr);
6161 compInlineResult = &prejitResult;
6163 // Find the basic blocks. We must do this regardless of
6164 // inlineability, since we are prejitting this method.
6166 // This will also update the status of this method as
6167 // an inline candidate.
6168 fgFindBasicBlocks();
6170 // Undo the temporary setup.
6171 assert(compInlineResult == &prejitResult);
6172 compInlineResult = nullptr;
6174 // If still a viable, discretionary inline, assess
6176 if (prejitResult.IsDiscretionaryCandidate())
6178 prejitResult.DetermineProfitability(methodInfo);
6181 m_inlineStrategy->NotePrejitDecision(prejitResult);
6183 // Handle the results of the inline analysis.
6184 if (prejitResult.IsFailure())
6186 // This method is a bad inlinee according to our
6187 // analysis. We will let the InlineResult destructor
6188 // mark it as noinline in the prejit image to save the
6191 // This decision better not be context-dependent.
6192 assert(prejitResult.IsNever());
6196 // This looks like a viable inline candidate. Since
6197 // we're not actually inlining, don't report anything.
6198 prejitResult.SetReported();
6203 // We are jitting the root method, or inlining.
6204 fgFindBasicBlocks();
6207 // If we're inlining and the candidate is bad, bail out.
6208 if (compDonotInline())
6213 compSetOptimizationLevel();
6215 #if COUNT_BASIC_BLOCKS
6216 bbCntTable.record(fgBBcount);
6220 bbOneBBSizeTable.record(methodInfo->ILCodeSize);
6222 #endif // COUNT_BASIC_BLOCKS
6227 printf("Basic block list for '%s'\n", info.compFullName);
6228 fgDispBasicBlocks();
6233 /* Give the function a unique number */
6235 if (opts.disAsm || opts.dspEmit || verbose)
6237 s_compMethodsCount = ~info.compMethodHash() & 0xffff;
6241 s_compMethodsCount++;
6245 if (compIsForInlining())
6247 compInlineResult->NoteInt(InlineObservation::CALLEE_NUMBER_OF_BASIC_BLOCKS, fgBBcount);
6249 if (compInlineResult->IsFailure())
6256 if (JitConfig.DumpJittedMethods() == 1 && !compIsForInlining())
6258 printf("Compiling %4d %s::%s, IL size = %u, hsh=0x%x\n", Compiler::jitTotalMethodCompiled, info.compClassName,
6259 info.compMethodName, info.compILCodeSize, info.compMethodHash());
6261 if (compIsForInlining())
6263 compGenTreeID = impInlineInfo->InlinerCompiler->compGenTreeID;
6267 compCompile(methodCodePtr, methodCodeSize, compileFlags);
6270 if (compIsForInlining())
6272 impInlineInfo->InlinerCompiler->compGenTreeID = compGenTreeID;
6273 impInlineInfo->InlinerCompiler->compBasicBlockID = compBasicBlockID;
6279 if (compDonotInline())
6281 // Verify we have only one inline result in play.
6282 assert(impInlineInfo->inlineResult == compInlineResult);
6285 if (!compIsForInlining())
6287 compCompileFinish();
6289 // Did we just compile for a target architecture that the VM isn't expecting? If so, the VM
6290 // can't used the generated code (and we better be an AltJit!).
6292 if (!info.compMatchedVM)
6294 return CORJIT_SKIPPED;
6299 if (JitConfig.RunAltJitCode() == 0)
6301 return CORJIT_SKIPPED;
6311 //------------------------------------------------------------------------
6312 // compFindLocalVarLinear: Linear search for variable's scope containing offset.
6315 // varNum The variable number to search for in the array of scopes.
6316 // offs The offset value which should occur within the life of the variable.
6319 // VarScopeDsc* of a matching variable that contains the offset within its life
6320 // begin and life end or nullptr when there is no match found.
6323 // Linear search for matching variables with their life begin and end containing
6325 // or NULL if one couldn't be found.
6328 // Usually called for scope count = 4. Could be called for values upto 8.
6330 VarScopeDsc* Compiler::compFindLocalVarLinear(unsigned varNum, unsigned offs)
6332 for (unsigned i = 0; i < info.compVarScopesCount; i++)
6334 VarScopeDsc* dsc = &info.compVarScopes[i];
6335 if ((dsc->vsdVarNum == varNum) && (dsc->vsdLifeBeg <= offs) && (dsc->vsdLifeEnd > offs))
6343 //------------------------------------------------------------------------
6344 // compFindLocalVar: Search for variable's scope containing offset.
6347 // varNum The variable number to search for in the array of scopes.
6348 // offs The offset value which should occur within the life of the variable.
6351 // VarScopeDsc* of a matching variable that contains the offset within its life
6352 // begin and life end.
6353 // or NULL if one couldn't be found.
6356 // Linear search for matching variables with their life begin and end containing
6357 // the offset only when the scope count is < MAX_LINEAR_FIND_LCL_SCOPELIST,
6358 // else use the hashtable lookup.
6360 VarScopeDsc* Compiler::compFindLocalVar(unsigned varNum, unsigned offs)
6362 if (info.compVarScopesCount < MAX_LINEAR_FIND_LCL_SCOPELIST)
6364 return compFindLocalVarLinear(varNum, offs);
6368 VarScopeDsc* ret = compFindLocalVar(varNum, offs, offs);
6369 assert(ret == compFindLocalVarLinear(varNum, offs));
6374 //------------------------------------------------------------------------
6375 // compFindLocalVar: Search for variable's scope containing offset.
6378 // varNum The variable number to search for in the array of scopes.
6379 // lifeBeg The life begin of the variable's scope
6380 // lifeEnd The life end of the variable's scope
6383 // VarScopeDsc* of a matching variable that contains the offset within its life
6384 // begin and life end, or NULL if one couldn't be found.
6387 // Following are the steps used:
6388 // 1. Index into the hashtable using varNum.
6389 // 2. Iterate through the linked list at index varNum to find a matching
6392 VarScopeDsc* Compiler::compFindLocalVar(unsigned varNum, unsigned lifeBeg, unsigned lifeEnd)
6394 assert(compVarScopeMap != nullptr);
6396 VarScopeMapInfo* info;
6397 if (compVarScopeMap->Lookup(varNum, &info))
6399 VarScopeListNode* list = info->head;
6400 while (list != nullptr)
6402 if ((list->data->vsdLifeBeg <= lifeBeg) && (list->data->vsdLifeEnd > lifeEnd))
6412 //-------------------------------------------------------------------------
6413 // compInitVarScopeMap: Create a scope map so it can be looked up by varNum
6416 // Map.K => Map.V :: varNum => List(ScopeDsc)
6418 // Create a scope map that can be indexed by varNum and can be iterated
6419 // on it's values to look for matching scope when given an offs or
6420 // lifeBeg and lifeEnd.
6423 // 1. Build the map only when we think linear search is slow, i.e.,
6424 // MAX_LINEAR_FIND_LCL_SCOPELIST is large.
6425 // 2. Linked list preserves original array order.
6427 void Compiler::compInitVarScopeMap()
6429 if (info.compVarScopesCount < MAX_LINEAR_FIND_LCL_SCOPELIST)
6434 assert(compVarScopeMap == nullptr);
6436 compVarScopeMap = new (getAllocator()) VarNumToScopeDscMap(getAllocator());
6438 // 599 prime to limit huge allocations; for ex: duplicated scopes on single var.
6439 compVarScopeMap->Reallocate(min(info.compVarScopesCount, 599));
6441 for (unsigned i = 0; i < info.compVarScopesCount; ++i)
6443 unsigned varNum = info.compVarScopes[i].vsdVarNum;
6445 VarScopeListNode* node = VarScopeListNode::Create(&info.compVarScopes[i], getAllocator());
6447 // Index by varNum and if the list exists append "node" to the "list".
6448 VarScopeMapInfo* info;
6449 if (compVarScopeMap->Lookup(varNum, &info))
6451 info->tail->next = node;
6454 // Create a new list.
6457 info = VarScopeMapInfo::Create(node, getAllocator());
6458 compVarScopeMap->Set(varNum, info);
6463 int __cdecl genCmpLocalVarLifeBeg(const void* elem1, const void* elem2)
6465 return (*((VarScopeDsc**)elem1))->vsdLifeBeg - (*((VarScopeDsc**)elem2))->vsdLifeBeg;
6468 int __cdecl genCmpLocalVarLifeEnd(const void* elem1, const void* elem2)
6470 return (*((VarScopeDsc**)elem1))->vsdLifeEnd - (*((VarScopeDsc**)elem2))->vsdLifeEnd;
6473 inline void Compiler::compInitScopeLists()
6475 if (info.compVarScopesCount == 0)
6477 compEnterScopeList = compExitScopeList = nullptr;
6481 // Populate the 'compEnterScopeList' and 'compExitScopeList' lists
6483 compEnterScopeList = new (this, CMK_DebugInfo) VarScopeDsc*[info.compVarScopesCount];
6484 compExitScopeList = new (this, CMK_DebugInfo) VarScopeDsc*[info.compVarScopesCount];
6486 for (unsigned i = 0; i < info.compVarScopesCount; i++)
6488 compEnterScopeList[i] = compExitScopeList[i] = &info.compVarScopes[i];
6491 qsort(compEnterScopeList, info.compVarScopesCount, sizeof(*compEnterScopeList), genCmpLocalVarLifeBeg);
6492 qsort(compExitScopeList, info.compVarScopesCount, sizeof(*compExitScopeList), genCmpLocalVarLifeEnd);
6495 void Compiler::compResetScopeLists()
6497 if (info.compVarScopesCount == 0)
6502 assert(compEnterScopeList && compExitScopeList);
6504 compNextEnterScope = compNextExitScope = 0;
6507 VarScopeDsc* Compiler::compGetNextEnterScope(unsigned offs, bool scan)
6509 assert(info.compVarScopesCount);
6510 assert(compEnterScopeList && compExitScopeList);
6512 if (compNextEnterScope < info.compVarScopesCount)
6514 assert(compEnterScopeList[compNextEnterScope]);
6515 unsigned nextEnterOff = compEnterScopeList[compNextEnterScope]->vsdLifeBeg;
6516 assert(scan || (offs <= nextEnterOff));
6520 if (offs == nextEnterOff)
6522 return compEnterScopeList[compNextEnterScope++];
6527 if (nextEnterOff <= offs)
6529 return compEnterScopeList[compNextEnterScope++];
6537 VarScopeDsc* Compiler::compGetNextExitScope(unsigned offs, bool scan)
6539 assert(info.compVarScopesCount);
6540 assert(compEnterScopeList && compExitScopeList);
6542 if (compNextExitScope < info.compVarScopesCount)
6544 assert(compExitScopeList[compNextExitScope]);
6545 unsigned nextExitOffs = compExitScopeList[compNextExitScope]->vsdLifeEnd;
6546 assert(scan || (offs <= nextExitOffs));
6550 if (offs == nextExitOffs)
6552 return compExitScopeList[compNextExitScope++];
6557 if (nextExitOffs <= offs)
6559 return compExitScopeList[compNextExitScope++];
6567 // The function will call the callback functions for scopes with boundaries
6568 // at instrs from the current status of the scope lists to 'offset',
6569 // ordered by instrs.
6571 void Compiler::compProcessScopesUntil(unsigned offset,
6573 void (Compiler::*enterScopeFn)(VARSET_TP* inScope, VarScopeDsc*),
6574 void (Compiler::*exitScopeFn)(VARSET_TP* inScope, VarScopeDsc*))
6576 assert(offset != BAD_IL_OFFSET);
6577 assert(inScope != nullptr);
6579 bool foundExit = false, foundEnter = true;
6581 VarScopeDsc* nextExitScope = nullptr;
6582 VarScopeDsc* nextEnterScope = nullptr;
6583 unsigned offs = offset, curEnterOffs = 0;
6585 goto START_FINDING_SCOPES;
6587 // We need to determine the scopes which are open for the current block.
6588 // This loop walks over the missing blocks between the current and the
6589 // previous block, keeping the enter and exit offsets in lockstep.
6593 foundExit = foundEnter = false;
6597 (this->*exitScopeFn)(inScope, nextExitScope);
6598 nextExitScope = nullptr;
6602 offs = nextEnterScope ? nextEnterScope->vsdLifeBeg : offset;
6604 while ((scope = compGetNextExitScope(offs, true)) != nullptr)
6608 if (!nextEnterScope || scope->vsdLifeEnd > nextEnterScope->vsdLifeBeg)
6610 // We overshot the last found Enter scope. Save the scope for later
6611 // and find an entering scope
6613 nextExitScope = scope;
6617 (this->*exitScopeFn)(inScope, scope);
6622 (this->*enterScopeFn)(inScope, nextEnterScope);
6623 curEnterOffs = nextEnterScope->vsdLifeBeg;
6624 nextEnterScope = nullptr;
6628 offs = nextExitScope ? nextExitScope->vsdLifeEnd : offset;
6630 START_FINDING_SCOPES:
6632 while ((scope = compGetNextEnterScope(offs, true)) != nullptr)
6636 if ((nextExitScope && scope->vsdLifeBeg >= nextExitScope->vsdLifeEnd) || (scope->vsdLifeBeg > curEnterOffs))
6638 // We overshot the last found exit scope. Save the scope for later
6639 // and find an exiting scope
6641 nextEnterScope = scope;
6645 (this->*enterScopeFn)(inScope, scope);
6649 curEnterOffs = scope->vsdLifeBeg;
6652 } while (foundExit || foundEnter);
6657 void Compiler::compDispScopeLists()
6661 printf("Local variable scopes = %d\n", info.compVarScopesCount);
6663 if (info.compVarScopesCount)
6665 printf(" \tVarNum \tLVNum \t Name \tBeg \tEnd\n");
6668 printf("Sorted by enter scope:\n");
6669 for (i = 0; i < info.compVarScopesCount; i++)
6671 VarScopeDsc* varScope = compEnterScopeList[i];
6673 printf("%2d: \t%02Xh \t%02Xh \t%10s \t%03Xh \t%03Xh", i, varScope->vsdVarNum, varScope->vsdLVnum,
6674 VarNameToStr(varScope->vsdName) == nullptr ? "UNKNOWN" : VarNameToStr(varScope->vsdName),
6675 varScope->vsdLifeBeg, varScope->vsdLifeEnd);
6677 if (compNextEnterScope == i)
6679 printf(" <-- next enter scope");
6685 printf("Sorted by exit scope:\n");
6686 for (i = 0; i < info.compVarScopesCount; i++)
6688 VarScopeDsc* varScope = compExitScopeList[i];
6690 printf("%2d: \t%02Xh \t%02Xh \t%10s \t%03Xh \t%03Xh", i, varScope->vsdVarNum, varScope->vsdLVnum,
6691 VarNameToStr(varScope->vsdName) == nullptr ? "UNKNOWN" : VarNameToStr(varScope->vsdName),
6692 varScope->vsdLifeBeg, varScope->vsdLifeEnd);
6694 if (compNextExitScope == i)
6696 printf(" <-- next exit scope");
6703 void Compiler::compDispLocalVars()
6705 printf("info.compVarScopesCount = %d\n", info.compVarScopesCount);
6707 if (info.compVarScopesCount > 0)
6709 printf(" \tVarNum \tLVNum \t Name \tBeg \tEnd\n");
6712 for (unsigned i = 0; i < info.compVarScopesCount; i++)
6714 VarScopeDsc* varScope = &info.compVarScopes[i];
6715 printf("%2d: \t%02Xh \t%02Xh \t%10s \t%03Xh \t%03Xh\n", i, varScope->vsdVarNum, varScope->vsdLVnum,
6716 VarNameToStr(varScope->vsdName) == nullptr ? "UNKNOWN" : VarNameToStr(varScope->vsdName),
6717 varScope->vsdLifeBeg, varScope->vsdLifeEnd);
6723 /*****************************************************************************/
6725 #if MEASURE_CLRAPI_CALLS
6727 struct WrapICorJitInfo : public ICorJitInfo
6729 //------------------------------------------------------------------------
6730 // WrapICorJitInfo::makeOne: allocate an instance of WrapICorJitInfo
6733 // alloc - the allocator to get memory from for the instance
6734 // compile - the compiler instance
6735 // compHndRef - the ICorJitInfo handle from the EE; the caller's
6736 // copy may be replaced with a "wrapper" instance
6739 // If the config flags indicate that ICorJitInfo should be wrapped,
6740 // we return the "wrapper" instance; otherwise we return "nullptr".
6742 static WrapICorJitInfo* makeOne(ArenaAllocator* alloc, Compiler* compiler, COMP_HANDLE& compHndRef /* INOUT */)
6744 WrapICorJitInfo* wrap = nullptr;
6746 if (JitConfig.JitEECallTimingInfo() != 0)
6748 // It's too early to use the default allocator, so we do this
6749 // in two steps to be safe (the constructor doesn't need to do
6750 // anything except fill in the vtable pointer, so we let the
6752 void* inst = alloc->allocateMemory(roundUp(sizeof(WrapICorJitInfo)));
6753 if (inst != nullptr)
6755 // If you get a build error here due to 'WrapICorJitInfo' being
6756 // an abstract class, it's very likely that the wrapper bodies
6757 // in ICorJitInfo_API_wrapper.hpp are no longer in sync with
6758 // the EE interface; please be kind and update the header file.
6759 wrap = new (inst, jitstd::placement_t()) WrapICorJitInfo();
6761 wrap->wrapComp = compiler;
6763 // Save the real handle and replace it with our wrapped version.
6764 wrap->wrapHnd = compHndRef;
6774 COMP_HANDLE wrapHnd; // the "real thing"
6777 #include "ICorJitInfo_API_wrapper.hpp"
6780 #endif // MEASURE_CLRAPI_CALLS
6782 /*****************************************************************************/
6784 // Compile a single method
6786 int jitNativeCode(CORINFO_METHOD_HANDLE methodHnd,
6787 CORINFO_MODULE_HANDLE classPtr,
6788 COMP_HANDLE compHnd,
6789 CORINFO_METHOD_INFO* methodInfo,
6790 void** methodCodePtr,
6791 ULONG* methodCodeSize,
6792 JitFlags* compileFlags,
6793 void* inlineInfoPtr)
6796 // A non-NULL inlineInfo means we are compiling the inlinee method.
6798 InlineInfo* inlineInfo = (InlineInfo*)inlineInfoPtr;
6800 bool jitFallbackCompile = false;
6802 int result = CORJIT_INTERNALERROR;
6804 ArenaAllocator* pAlloc = nullptr;
6805 ArenaAllocator alloc;
6807 #if MEASURE_CLRAPI_CALLS
6808 WrapICorJitInfo* wrapCLR = nullptr;
6813 // Use inliner's memory allocator when compiling the inlinee.
6814 pAlloc = inlineInfo->InlinerCompiler->compGetAllocator();
6818 IEEMemoryManager* pMemoryManager = compHnd->getMemoryManager();
6820 // Try to reuse the pre-inited allocator
6821 pAlloc = ArenaAllocator::getPooledAllocator(pMemoryManager);
6823 if (pAlloc == nullptr)
6825 alloc = ArenaAllocator(pMemoryManager);
6836 ArenaAllocator* pAlloc;
6837 ArenaAllocator* alloc;
6838 bool jitFallbackCompile;
6840 CORINFO_METHOD_HANDLE methodHnd;
6841 CORINFO_MODULE_HANDLE classPtr;
6842 COMP_HANDLE compHnd;
6843 CORINFO_METHOD_INFO* methodInfo;
6844 void** methodCodePtr;
6845 ULONG* methodCodeSize;
6846 JitFlags* compileFlags;
6847 InlineInfo* inlineInfo;
6848 #if MEASURE_CLRAPI_CALLS
6849 WrapICorJitInfo* wrapCLR;
6854 param.pComp = nullptr;
6855 param.pAlloc = pAlloc;
6856 param.alloc = &alloc;
6857 param.jitFallbackCompile = jitFallbackCompile;
6858 param.methodHnd = methodHnd;
6859 param.classPtr = classPtr;
6860 param.compHnd = compHnd;
6861 param.methodInfo = methodInfo;
6862 param.methodCodePtr = methodCodePtr;
6863 param.methodCodeSize = methodCodeSize;
6864 param.compileFlags = compileFlags;
6865 param.inlineInfo = inlineInfo;
6866 #if MEASURE_CLRAPI_CALLS
6867 param.wrapCLR = nullptr;
6869 param.result = result;
6871 setErrorTrap(compHnd, Param*, pParamOuter, ¶m)
6873 setErrorTrap(nullptr, Param*, pParam, pParamOuter)
6875 if (pParam->inlineInfo)
6877 // Lazily create the inlinee compiler object
6878 if (pParam->inlineInfo->InlinerCompiler->InlineeCompiler == nullptr)
6880 pParam->inlineInfo->InlinerCompiler->InlineeCompiler =
6881 (Compiler*)pParam->pAlloc->allocateMemory(roundUp(sizeof(*pParam->pComp)));
6884 // Use the inlinee compiler object
6885 pParam->pComp = pParam->inlineInfo->InlinerCompiler->InlineeCompiler;
6887 // memset(pParam->pComp, 0xEE, sizeof(Compiler));
6892 // Allocate create the inliner compiler object
6893 pParam->pComp = (Compiler*)pParam->pAlloc->allocateMemory(roundUp(sizeof(*pParam->pComp)));
6896 #if MEASURE_CLRAPI_CALLS
6897 pParam->wrapCLR = WrapICorJitInfo::makeOne(pParam->pAlloc, pParam->pComp, pParam->compHnd);
6900 // push this compiler on the stack (TLS)
6901 pParam->pComp->prevCompiler = JitTls::GetCompiler();
6902 JitTls::SetCompiler(pParam->pComp);
6904 // PREFIX_ASSUME gets turned into ASSERT_CHECK and we cannot have it here
6905 #if defined(_PREFAST_) || defined(_PREFIX_)
6906 PREFIX_ASSUME(pParam->pComp != NULL);
6908 assert(pParam->pComp != nullptr);
6911 pParam->pComp->compInit(pParam->pAlloc, pParam->inlineInfo);
6914 pParam->pComp->jitFallbackCompile = pParam->jitFallbackCompile;
6917 // Now generate the code
6919 pParam->pComp->compCompile(pParam->methodHnd, pParam->classPtr, pParam->compHnd, pParam->methodInfo,
6920 pParam->methodCodePtr, pParam->methodCodeSize, pParam->compileFlags);
6924 // Add a dummy touch to pComp so that it is kept alive, and is easy to get to
6925 // during debugging since all other data can be obtained through it.
6927 if (pParamOuter->pComp) // If OOM is thrown when allocating memory for pComp, we will end up here.
6928 // In that case, pComp is still NULL.
6930 pParamOuter->pComp->info.compCode = nullptr;
6932 // pop the compiler off the TLS stack only if it was linked above
6933 assert(JitTls::GetCompiler() == pParamOuter->pComp);
6934 JitTls::SetCompiler(JitTls::GetCompiler()->prevCompiler);
6937 if (pParamOuter->inlineInfo == nullptr)
6939 // Free up the allocator we were using
6940 pParamOuter->pAlloc->destroy();
6947 // If we were looking at an inlinee....
6948 if (inlineInfo != nullptr)
6950 // Note that we failed to compile the inlinee, and that
6951 // there's no point trying to inline it again anywhere else.
6952 inlineInfo->inlineResult->NoteFatal(InlineObservation::CALLEE_COMPILATION_ERROR);
6954 param.result = __errc;
6958 result = param.result;
6960 if (!inlineInfo && (result == CORJIT_INTERNALERROR || result == CORJIT_RECOVERABLEERROR) && !jitFallbackCompile)
6962 // If we failed the JIT, reattempt with debuggable code.
6963 jitFallbackCompile = true;
6965 // Update the flags for 'safer' code generation.
6966 compileFlags->Set(JitFlags::JIT_FLAG_MIN_OPT);
6967 compileFlags->Clear(JitFlags::JIT_FLAG_SIZE_OPT);
6968 compileFlags->Clear(JitFlags::JIT_FLAG_SPEED_OPT);
6976 #if defined(UNIX_AMD64_ABI)
6978 // GetTypeFromClassificationAndSizes:
6979 // Returns the type of the eightbyte accounting for the classification and size of the eightbyte.
6982 // classType: classification type
6983 // size: size of the eightbyte.
6986 var_types Compiler::GetTypeFromClassificationAndSizes(SystemVClassificationType classType, int size)
6988 var_types type = TYP_UNKNOWN;
6991 case SystemVClassificationTypeInteger:
7010 assert(false && "GetTypeFromClassificationAndSizes Invalid Integer classification type.");
7013 case SystemVClassificationTypeIntegerReference:
7016 case SystemVClassificationTypeIntegerByRef:
7019 case SystemVClassificationTypeSSE:
7030 assert(false && "GetTypeFromClassificationAndSizes Invalid SSE classification type.");
7035 assert(false && "GetTypeFromClassificationAndSizes Invalid classification type.");
7042 //-------------------------------------------------------------------
7043 // GetEightByteType: Returns the type of eightbyte slot of a struct
7046 // structDesc - struct classification description.
7047 // slotNum - eightbyte slot number for the struct.
7050 // type of the eightbyte slot of the struct
7053 var_types Compiler::GetEightByteType(const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR& structDesc,
7056 var_types eightByteType = TYP_UNDEF;
7057 unsigned len = structDesc.eightByteSizes[slotNum];
7059 switch (structDesc.eightByteClassifications[slotNum])
7061 case SystemVClassificationTypeInteger:
7062 // See typelist.h for jit type definition.
7063 // All the types of size < 4 bytes are of jit type TYP_INT.
7064 if (structDesc.eightByteSizes[slotNum] <= 4)
7066 eightByteType = TYP_INT;
7068 else if (structDesc.eightByteSizes[slotNum] <= 8)
7070 eightByteType = TYP_LONG;
7074 assert(false && "GetEightByteType Invalid Integer classification type.");
7077 case SystemVClassificationTypeIntegerReference:
7078 assert(len == REGSIZE_BYTES);
7079 eightByteType = TYP_REF;
7081 case SystemVClassificationTypeIntegerByRef:
7082 assert(len == REGSIZE_BYTES);
7083 eightByteType = TYP_BYREF;
7085 case SystemVClassificationTypeSSE:
7086 if (structDesc.eightByteSizes[slotNum] <= 4)
7088 eightByteType = TYP_FLOAT;
7090 else if (structDesc.eightByteSizes[slotNum] <= 8)
7092 eightByteType = TYP_DOUBLE;
7096 assert(false && "GetEightByteType Invalid SSE classification type.");
7100 assert(false && "GetEightByteType Invalid classification type.");
7104 return eightByteType;
7107 //------------------------------------------------------------------------------------------------------
7108 // GetStructTypeOffset: Gets the type, size and offset of the eightbytes of a struct for System V systems.
7111 // 'structDesc' - struct description
7112 // 'type0' - out param; returns the type of the first eightbyte.
7113 // 'type1' - out param; returns the type of the second eightbyte.
7114 // 'offset0' - out param; returns the offset of the first eightbyte.
7115 // 'offset1' - out param; returns the offset of the second eightbyte.
7118 void Compiler::GetStructTypeOffset(const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR& structDesc,
7121 unsigned __int8* offset0,
7122 unsigned __int8* offset1)
7124 *offset0 = structDesc.eightByteOffsets[0];
7125 *offset1 = structDesc.eightByteOffsets[1];
7127 *type0 = TYP_UNKNOWN;
7128 *type1 = TYP_UNKNOWN;
7130 // Set the first eightbyte data
7131 if (structDesc.eightByteCount >= 1)
7133 *type0 = GetEightByteType(structDesc, 0);
7136 // Set the second eight byte data
7137 if (structDesc.eightByteCount == 2)
7139 *type1 = GetEightByteType(structDesc, 1);
7143 //------------------------------------------------------------------------------------------------------
7144 // GetStructTypeOffset: Gets the type, size and offset of the eightbytes of a struct for System V systems.
7147 // 'typeHnd' - type handle
7148 // 'type0' - out param; returns the type of the first eightbyte.
7149 // 'type1' - out param; returns the type of the second eightbyte.
7150 // 'offset0' - out param; returns the offset of the first eightbyte.
7151 // 'offset1' - out param; returns the offset of the second eightbyte.
7153 void Compiler::GetStructTypeOffset(CORINFO_CLASS_HANDLE typeHnd,
7156 unsigned __int8* offset0,
7157 unsigned __int8* offset1)
7159 SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
7160 eeGetSystemVAmd64PassStructInRegisterDescriptor(typeHnd, &structDesc);
7161 assert(structDesc.passedInRegisters);
7162 GetStructTypeOffset(structDesc, type0, type1, offset0, offset1);
7165 #endif // defined(UNIX_AMD64_ABI)
7167 /*****************************************************************************/
7168 /*****************************************************************************/
7171 Compiler::NodeToIntMap* Compiler::FindReachableNodesInNodeTestData()
7173 NodeToIntMap* reachable = new (getAllocatorDebugOnly()) NodeToIntMap(getAllocatorDebugOnly());
7175 if (m_nodeTestData == nullptr)
7180 // Otherwise, iterate.
7182 for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
7184 for (GenTree* stmt = block->FirstNonPhiDef(); stmt != nullptr; stmt = stmt->gtNext)
7186 for (GenTree* tree = stmt->gtStmt.gtStmtList; tree; tree = tree->gtNext)
7188 TestLabelAndNum tlAndN;
7190 // For call nodes, translate late args to what they stand for.
7191 if (tree->OperGet() == GT_CALL)
7193 GenTreeCall* call = tree->AsCall();
7194 GenTreeArgList* args = call->gtCallArgs;
7196 while (args != nullptr)
7198 GenTree* arg = args->Current();
7199 if (arg->gtFlags & GTF_LATE_ARG)
7201 // Find the corresponding late arg.
7202 GenTree* lateArg = call->fgArgInfo->GetLateArg(i);
7203 if (GetNodeTestData()->Lookup(lateArg, &tlAndN))
7205 reachable->Set(lateArg, 0);
7209 args = args->Rest();
7213 if (GetNodeTestData()->Lookup(tree, &tlAndN))
7215 reachable->Set(tree, 0);
7223 void Compiler::TransferTestDataToNode(GenTree* from, GenTree* to)
7225 TestLabelAndNum tlAndN;
7226 // We can't currently associate multiple annotations with a single node.
7227 // If we need to, we can fix this...
7229 // If the table is null, don't create it just to do the lookup, which would fail...
7230 if (m_nodeTestData != nullptr && GetNodeTestData()->Lookup(from, &tlAndN))
7232 assert(!GetNodeTestData()->Lookup(to, &tlAndN));
7233 // We can't currently associate multiple annotations with a single node.
7234 // If we need to, we can fix this...
7235 TestLabelAndNum tlAndNTo;
7236 assert(!GetNodeTestData()->Lookup(to, &tlAndNTo));
7238 GetNodeTestData()->Remove(from);
7239 GetNodeTestData()->Set(to, tlAndN);
7243 void Compiler::CopyTestDataToCloneTree(GenTree* from, GenTree* to)
7245 if (m_nodeTestData == nullptr)
7249 if (from == nullptr)
7251 assert(to == nullptr);
7255 TestLabelAndNum tlAndN;
7256 if (GetNodeTestData()->Lookup(from, &tlAndN))
7258 // We can't currently associate multiple annotations with a single node.
7259 // If we need to, we can fix this...
7260 TestLabelAndNum tlAndNTo;
7261 assert(!GetNodeTestData()->Lookup(to, &tlAndNTo));
7262 GetNodeTestData()->Set(to, tlAndN);
7264 // Now recurse, in parallel on both trees.
7266 genTreeOps oper = from->OperGet();
7267 unsigned kind = from->OperKind();
7268 assert(oper == to->OperGet());
7270 // Cconstant or leaf nodes have no children.
7271 if (kind & (GTK_CONST | GTK_LEAF))
7276 // Otherwise, is it a 'simple' unary/binary operator?
7278 if (kind & GTK_SMPOP)
7280 if (from->gtOp.gtOp1 != nullptr)
7282 assert(to->gtOp.gtOp1 != nullptr);
7283 CopyTestDataToCloneTree(from->gtOp.gtOp1, to->gtOp.gtOp1);
7287 assert(to->gtOp.gtOp1 == nullptr);
7290 if (from->gtGetOp2IfPresent() != nullptr)
7292 assert(to->gtGetOp2IfPresent() != nullptr);
7293 CopyTestDataToCloneTree(from->gtGetOp2(), to->gtGetOp2());
7297 assert(to->gtGetOp2IfPresent() == nullptr);
7303 // Otherwise, see what kind of a special operator we have here.
7308 CopyTestDataToCloneTree(from->gtStmt.gtStmtExpr, to->gtStmt.gtStmtExpr);
7312 CopyTestDataToCloneTree(from->gtCall.gtCallObjp, to->gtCall.gtCallObjp);
7313 CopyTestDataToCloneTree(from->gtCall.gtCallArgs, to->gtCall.gtCallArgs);
7314 CopyTestDataToCloneTree(from->gtCall.gtCallLateArgs, to->gtCall.gtCallLateArgs);
7316 if (from->gtCall.gtCallType == CT_INDIRECT)
7318 CopyTestDataToCloneTree(from->gtCall.gtCallCookie, to->gtCall.gtCallCookie);
7319 CopyTestDataToCloneTree(from->gtCall.gtCallAddr, to->gtCall.gtCallAddr);
7321 // The other call types do not have additional GenTree arguments.
7326 CopyTestDataToCloneTree(from->gtField.gtFldObj, to->gtField.gtFldObj);
7330 assert(from->gtArrElem.gtArrRank == to->gtArrElem.gtArrRank);
7331 for (unsigned dim = 0; dim < from->gtArrElem.gtArrRank; dim++)
7333 CopyTestDataToCloneTree(from->gtArrElem.gtArrInds[dim], to->gtArrElem.gtArrInds[dim]);
7335 CopyTestDataToCloneTree(from->gtArrElem.gtArrObj, to->gtArrElem.gtArrObj);
7339 CopyTestDataToCloneTree(from->gtCmpXchg.gtOpLocation, to->gtCmpXchg.gtOpLocation);
7340 CopyTestDataToCloneTree(from->gtCmpXchg.gtOpValue, to->gtCmpXchg.gtOpValue);
7341 CopyTestDataToCloneTree(from->gtCmpXchg.gtOpComparand, to->gtCmpXchg.gtOpComparand);
7344 case GT_ARR_BOUNDS_CHECK:
7347 #endif // FEATURE_SIMD
7348 #ifdef FEATURE_HW_INTRINSICS
7349 case GT_HW_INTRINSIC_CHK:
7350 #endif // FEATURE_HW_INTRINSICS
7351 CopyTestDataToCloneTree(from->gtBoundsChk.gtIndex, to->gtBoundsChk.gtIndex);
7352 CopyTestDataToCloneTree(from->gtBoundsChk.gtArrLen, to->gtBoundsChk.gtArrLen);
7363 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7364 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7368 XX Functions for the stand-alone version of the JIT . XX
7370 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7371 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7374 /*****************************************************************************/
7375 void codeGeneratorCodeSizeBeg()
7378 /*****************************************************************************/
7380 /*****************************************************************************
7382 * If any temporary tables are smaller than 'genMinSize2free' we won't bother
7386 const size_t genMinSize2free = 64;
7388 /*****************************************************************************/
7390 /*****************************************************************************
7392 * Used for counting pointer assignments.
7395 /*****************************************************************************/
7396 void codeGeneratorCodeSizeEnd()
7399 /*****************************************************************************
7401 * Gather statistics - mainly used for the standalone
7402 * Enable various #ifdef's to get the information you need
7405 void Compiler::compJitStats()
7409 /* Method types and argument statistics */
7411 #endif // CALL_ARG_STATS
7416 /*****************************************************************************
7418 * Gather statistics about method calls and arguments
7421 void Compiler::compCallArgStats()
7432 unsigned argDWordNum;
7438 unsigned regArgDeferred;
7439 unsigned regArgTemp;
7441 unsigned regArgLclVar;
7442 unsigned regArgConst;
7444 unsigned argTempsThisMethod = 0;
7446 assert(fgStmtListThreaded);
7448 for (block = fgFirstBB; block; block = block->bbNext)
7450 for (stmt = block->bbTreeList; stmt; stmt = stmt->gtNext)
7452 assert(stmt->gtOper == GT_STMT);
7454 for (call = stmt->gtStmt.gtStmtList; call; call = call->gtNext)
7456 if (call->gtOper != GT_CALL)
7461 regArgNum = regArgDeferred = regArgTemp =
7463 regArgConst = regArgLclVar =
7465 argDWordNum = argLngNum = argFltNum = argDblNum = 0;
7469 if (!call->gtCall.gtCallObjp)
7471 if (call->gtCall.gtCallType == CT_HELPER)
7482 /* We have a 'this' pointer */
7490 if (call->IsVirtual())
7492 /* virtual function */
7497 argNonVirtualCalls++;
7501 #ifdef LEGACY_BACKEND
7502 // TODO-Cleaenup: We need to add support below for additional node types that RyuJIT backend has in the
7504 // Gather arguments information.
7506 for (args = call->gtCall.gtCallArgs; args; args = args->gtOp.gtOp2)
7508 argx = args->gtOp.gtOp1;
7512 switch (genActualType(argx->TypeGet()))
7533 /* This is a deferred register argument */
7534 assert(argx->gtOper == GT_NOP);
7535 assert(argx->gtFlags & GTF_LATE_ARG);
7540 /* Is this argument a register argument? */
7542 if (argx->gtFlags & GTF_LATE_ARG)
7546 /* We either have a deferred argument or a temp */
7548 if (argx->gtOper == GT_NOP)
7554 assert(argx->gtOper == GT_ASG);
7560 /* Look at the register arguments and count how many constants, local vars */
7562 for (args = call->gtCall.gtCallLateArgs; args; args = args->gtOp.gtOp2)
7564 argx = args->gtOp.gtOp1;
7566 switch (argx->gtOper)
7578 assert(argNum == argDWordNum + argLngNum + argFltNum + argDblNum);
7579 assert(regArgNum == regArgDeferred + regArgTemp);
7581 argTotalArgs += argNum;
7582 argTotalRegArgs += regArgNum;
7584 argTotalDWordArgs += argDWordNum;
7585 argTotalLongArgs += argLngNum;
7586 argTotalFloatArgs += argFltNum;
7587 argTotalDoubleArgs += argDblNum;
7589 argTotalDeferred += regArgDeferred;
7590 argTotalTemps += regArgTemp;
7591 argTotalConst += regArgConst;
7592 argTotalLclVar += regArgLclVar;
7594 argTempsThisMethod += regArgTemp;
7596 argCntTable.record(argNum);
7597 argDWordCntTable.record(argDWordNum);
7598 argDWordLngCntTable.record(argDWordNum + (2 * argLngNum));
7599 #endif // LEGACY_BACKEND
7604 argTempsCntTable.record(argTempsThisMethod);
7606 if (argMaxTempsPerMethod < argTempsThisMethod)
7608 argMaxTempsPerMethod = argTempsThisMethod;
7613 void Compiler::compDispCallArgStats(FILE* fout)
7615 if (argTotalCalls == 0)
7618 fprintf(fout, "\n");
7619 fprintf(fout, "--------------------------------------------------\n");
7620 fprintf(fout, "Call stats\n");
7621 fprintf(fout, "--------------------------------------------------\n");
7622 fprintf(fout, "Total # of calls = %d, calls / method = %.3f\n\n", argTotalCalls,
7623 (float)argTotalCalls / genMethodCnt);
7625 fprintf(fout, "Percentage of helper calls = %4.2f %%\n", (float)(100 * argHelperCalls) / argTotalCalls);
7626 fprintf(fout, "Percentage of static calls = %4.2f %%\n", (float)(100 * argStaticCalls) / argTotalCalls);
7627 fprintf(fout, "Percentage of virtual calls = %4.2f %%\n", (float)(100 * argVirtualCalls) / argTotalCalls);
7628 fprintf(fout, "Percentage of non-virtual calls = %4.2f %%\n\n", (float)(100 * argNonVirtualCalls) / argTotalCalls);
7630 fprintf(fout, "Average # of arguments per call = %.2f%%\n\n", (float)argTotalArgs / argTotalCalls);
7632 fprintf(fout, "Percentage of DWORD arguments = %.2f %%\n", (float)(100 * argTotalDWordArgs) / argTotalArgs);
7633 fprintf(fout, "Percentage of LONG arguments = %.2f %%\n", (float)(100 * argTotalLongArgs) / argTotalArgs);
7634 fprintf(fout, "Percentage of FLOAT arguments = %.2f %%\n", (float)(100 * argTotalFloatArgs) / argTotalArgs);
7635 fprintf(fout, "Percentage of DOUBLE arguments = %.2f %%\n\n", (float)(100 * argTotalDoubleArgs) / argTotalArgs);
7637 if (argTotalRegArgs == 0)
7641 fprintf(fout, "Total deferred arguments = %d \n", argTotalDeferred);
7643 fprintf(fout, "Total temp arguments = %d \n\n", argTotalTemps);
7645 fprintf(fout, "Total 'this' arguments = %d \n", argTotalObjPtr);
7646 fprintf(fout, "Total local var arguments = %d \n", argTotalLclVar);
7647 fprintf(fout, "Total constant arguments = %d \n\n", argTotalConst);
7650 fprintf(fout, "\nRegister Arguments:\n\n");
7652 fprintf(fout, "Percentage of deferred arguments = %.2f %%\n", (float)(100 * argTotalDeferred) / argTotalRegArgs);
7653 fprintf(fout, "Percentage of temp arguments = %.2f %%\n\n", (float)(100 * argTotalTemps) / argTotalRegArgs);
7655 fprintf(fout, "Maximum # of temps per method = %d\n\n", argMaxTempsPerMethod);
7657 fprintf(fout, "Percentage of ObjPtr arguments = %.2f %%\n", (float)(100 * argTotalObjPtr) / argTotalRegArgs);
7658 // fprintf(fout, "Percentage of global arguments = %.2f %%\n", (float)(100 * argTotalDWordGlobEf) /
7659 // argTotalRegArgs);
7660 fprintf(fout, "Percentage of constant arguments = %.2f %%\n", (float)(100 * argTotalConst) / argTotalRegArgs);
7661 fprintf(fout, "Percentage of lcl var arguments = %.2f %%\n\n", (float)(100 * argTotalLclVar) / argTotalRegArgs);
7663 fprintf(fout, "--------------------------------------------------\n");
7664 fprintf(fout, "Argument count frequency table (includes ObjPtr):\n");
7665 fprintf(fout, "--------------------------------------------------\n");
7666 argCntTable.dump(fout);
7667 fprintf(fout, "--------------------------------------------------\n");
7669 fprintf(fout, "--------------------------------------------------\n");
7670 fprintf(fout, "DWORD argument count frequency table (w/o LONG):\n");
7671 fprintf(fout, "--------------------------------------------------\n");
7672 argDWordCntTable.dump(fout);
7673 fprintf(fout, "--------------------------------------------------\n");
7675 fprintf(fout, "--------------------------------------------------\n");
7676 fprintf(fout, "Temps count frequency table (per method):\n");
7677 fprintf(fout, "--------------------------------------------------\n");
7678 argTempsCntTable.dump(fout);
7679 fprintf(fout, "--------------------------------------------------\n");
7682 fprintf(fout, "--------------------------------------------------\n");
7683 fprintf(fout, "DWORD argument count frequency table (w/ LONG):\n");
7684 fprintf(fout, "--------------------------------------------------\n");
7685 argDWordLngCntTable.dump(fout);
7686 fprintf(fout, "--------------------------------------------------\n");
7690 #endif // CALL_ARG_STATS
7692 // JIT time end to end, and by phases.
7694 #ifdef FEATURE_JIT_METHOD_PERF
7696 CritSecObject CompTimeSummaryInfo::s_compTimeSummaryLock;
7697 CompTimeSummaryInfo CompTimeSummaryInfo::s_compTimeSummary;
7698 #if MEASURE_CLRAPI_CALLS
7699 double JitTimer::s_cyclesPerSec = CycleTimer::CyclesPerSecond();
7701 #endif // FEATURE_JIT_METHOD_PERF
7703 #if defined(FEATURE_JIT_METHOD_PERF) || DUMP_FLOWGRAPHS || defined(FEATURE_TRACELOGGING)
7704 const char* PhaseNames[] = {
7705 #define CompPhaseNameMacro(enum_nm, string_nm, short_nm, hasChildren, parent, measureIR) string_nm,
7706 #include "compphases.h"
7709 const char* PhaseEnums[] = {
7710 #define CompPhaseNameMacro(enum_nm, string_nm, short_nm, hasChildren, parent, measureIR) #enum_nm,
7711 #include "compphases.h"
7714 const LPCWSTR PhaseShortNames[] = {
7715 #define CompPhaseNameMacro(enum_nm, string_nm, short_nm, hasChildren, parent, measureIR) W(short_nm),
7716 #include "compphases.h"
7718 #endif // defined(FEATURE_JIT_METHOD_PERF) || DUMP_FLOWGRAPHS
7720 #ifdef FEATURE_JIT_METHOD_PERF
7721 bool PhaseHasChildren[] = {
7722 #define CompPhaseNameMacro(enum_nm, string_nm, short_nm, hasChildren, parent, measureIR) hasChildren,
7723 #include "compphases.h"
7726 int PhaseParent[] = {
7727 #define CompPhaseNameMacro(enum_nm, string_nm, short_nm, hasChildren, parent, measureIR) parent,
7728 #include "compphases.h"
7731 bool PhaseReportsIRSize[] = {
7732 #define CompPhaseNameMacro(enum_nm, string_nm, short_nm, hasChildren, parent, measureIR) measureIR,
7733 #include "compphases.h"
7736 CompTimeInfo::CompTimeInfo(unsigned byteCodeBytes)
7737 : m_byteCodeBytes(byteCodeBytes)
7739 , m_parentPhaseEndSlop(0)
7740 , m_timerFailure(false)
7741 #if MEASURE_CLRAPI_CALLS
7742 , m_allClrAPIcalls(0)
7743 , m_allClrAPIcycles(0)
7746 for (int i = 0; i < PHASE_NUMBER_OF; i++)
7748 m_invokesByPhase[i] = 0;
7749 m_cyclesByPhase[i] = 0;
7750 #if MEASURE_CLRAPI_CALLS
7751 m_CLRinvokesByPhase[i] = 0;
7752 m_CLRcyclesByPhase[i] = 0;
7756 #if MEASURE_CLRAPI_CALLS
7757 assert(ARRAYSIZE(m_perClrAPIcalls) == API_ICorJitInfo_Names::API_COUNT);
7758 assert(ARRAYSIZE(m_perClrAPIcycles) == API_ICorJitInfo_Names::API_COUNT);
7759 assert(ARRAYSIZE(m_maxClrAPIcycles) == API_ICorJitInfo_Names::API_COUNT);
7760 for (int i = 0; i < API_ICorJitInfo_Names::API_COUNT; i++)
7762 m_perClrAPIcalls[i] = 0;
7763 m_perClrAPIcycles[i] = 0;
7764 m_maxClrAPIcycles[i] = 0;
7769 bool CompTimeSummaryInfo::IncludedInFilteredData(CompTimeInfo& info)
7771 return false; // info.m_byteCodeBytes < 10;
7774 //------------------------------------------------------------------------
7775 // CompTimeSummaryInfo::AddInfo: Record timing info from one compile.
7778 // info - The timing information to record.
7779 // includePhases - If "true", the per-phase info in "info" is valid,
7780 // which means that a "normal" compile has ended; if
7781 // the value is "false" we are recording the results
7782 // of a partial compile (typically an import-only run
7783 // on behalf of the inliner) in which case the phase
7784 // info is not valid and so we only record EE call
7786 void CompTimeSummaryInfo::AddInfo(CompTimeInfo& info, bool includePhases)
7788 if (info.m_timerFailure)
7790 return; // Don't update if there was a failure.
7793 CritSecHolder timeLock(s_compTimeSummaryLock);
7797 bool includeInFiltered = IncludedInFilteredData(info);
7801 // Update the totals and maxima.
7802 m_total.m_byteCodeBytes += info.m_byteCodeBytes;
7803 m_maximum.m_byteCodeBytes = max(m_maximum.m_byteCodeBytes, info.m_byteCodeBytes);
7804 m_total.m_totalCycles += info.m_totalCycles;
7805 m_maximum.m_totalCycles = max(m_maximum.m_totalCycles, info.m_totalCycles);
7807 #if MEASURE_CLRAPI_CALLS
7808 // Update the CLR-API values.
7809 m_total.m_allClrAPIcalls += info.m_allClrAPIcalls;
7810 m_maximum.m_allClrAPIcalls = max(m_maximum.m_allClrAPIcalls, info.m_allClrAPIcalls);
7811 m_total.m_allClrAPIcycles += info.m_allClrAPIcycles;
7812 m_maximum.m_allClrAPIcycles = max(m_maximum.m_allClrAPIcycles, info.m_allClrAPIcycles);
7815 if (includeInFiltered)
7817 m_numFilteredMethods++;
7818 m_filtered.m_byteCodeBytes += info.m_byteCodeBytes;
7819 m_filtered.m_totalCycles += info.m_totalCycles;
7820 m_filtered.m_parentPhaseEndSlop += info.m_parentPhaseEndSlop;
7823 for (int i = 0; i < PHASE_NUMBER_OF; i++)
7825 m_total.m_invokesByPhase[i] += info.m_invokesByPhase[i];
7826 m_total.m_cyclesByPhase[i] += info.m_cyclesByPhase[i];
7828 #if MEASURE_CLRAPI_CALLS
7829 m_total.m_CLRinvokesByPhase[i] += info.m_CLRinvokesByPhase[i];
7830 m_total.m_CLRcyclesByPhase[i] += info.m_CLRcyclesByPhase[i];
7833 if (includeInFiltered)
7835 m_filtered.m_invokesByPhase[i] += info.m_invokesByPhase[i];
7836 m_filtered.m_cyclesByPhase[i] += info.m_cyclesByPhase[i];
7837 #if MEASURE_CLRAPI_CALLS
7838 m_filtered.m_CLRinvokesByPhase[i] += info.m_CLRinvokesByPhase[i];
7839 m_filtered.m_CLRcyclesByPhase[i] += info.m_CLRcyclesByPhase[i];
7842 m_maximum.m_cyclesByPhase[i] = max(m_maximum.m_cyclesByPhase[i], info.m_cyclesByPhase[i]);
7844 #if MEASURE_CLRAPI_CALLS
7845 m_maximum.m_CLRcyclesByPhase[i] = max(m_maximum.m_CLRcyclesByPhase[i], info.m_CLRcyclesByPhase[i]);
7848 m_total.m_parentPhaseEndSlop += info.m_parentPhaseEndSlop;
7849 m_maximum.m_parentPhaseEndSlop = max(m_maximum.m_parentPhaseEndSlop, info.m_parentPhaseEndSlop);
7851 #if MEASURE_CLRAPI_CALLS
7856 // Update the "global" CLR-API values.
7857 m_total.m_allClrAPIcalls += info.m_allClrAPIcalls;
7858 m_maximum.m_allClrAPIcalls = max(m_maximum.m_allClrAPIcalls, info.m_allClrAPIcalls);
7859 m_total.m_allClrAPIcycles += info.m_allClrAPIcycles;
7860 m_maximum.m_allClrAPIcycles = max(m_maximum.m_allClrAPIcycles, info.m_allClrAPIcycles);
7862 // Update the per-phase CLR-API values.
7863 m_total.m_invokesByPhase[PHASE_CLR_API] += info.m_allClrAPIcalls;
7864 m_maximum.m_invokesByPhase[PHASE_CLR_API] =
7865 max(m_maximum.m_perClrAPIcalls[PHASE_CLR_API], info.m_allClrAPIcalls);
7866 m_total.m_cyclesByPhase[PHASE_CLR_API] += info.m_allClrAPIcycles;
7867 m_maximum.m_cyclesByPhase[PHASE_CLR_API] =
7868 max(m_maximum.m_cyclesByPhase[PHASE_CLR_API], info.m_allClrAPIcycles);
7871 for (int i = 0; i < API_ICorJitInfo_Names::API_COUNT; i++)
7873 m_total.m_perClrAPIcalls[i] += info.m_perClrAPIcalls[i];
7874 m_maximum.m_perClrAPIcalls[i] = max(m_maximum.m_perClrAPIcalls[i], info.m_perClrAPIcalls[i]);
7876 m_total.m_perClrAPIcycles[i] += info.m_perClrAPIcycles[i];
7877 m_maximum.m_perClrAPIcycles[i] = max(m_maximum.m_perClrAPIcycles[i], info.m_perClrAPIcycles[i]);
7879 m_maximum.m_maxClrAPIcycles[i] = max(m_maximum.m_maxClrAPIcycles[i], info.m_maxClrAPIcycles[i]);
7885 LPCWSTR Compiler::compJitTimeLogFilename = nullptr;
7887 void CompTimeSummaryInfo::Print(FILE* f)
7894 double countsPerSec = CycleTimer::CyclesPerSecond();
7895 if (countsPerSec == 0.0)
7897 fprintf(f, "Processor does not have a high-frequency timer.\n");
7901 bool extraInfo = (JitConfig.JitEECallTimingInfo() != 0);
7902 double totTime_ms = 0.0;
7904 fprintf(f, "JIT Compilation time report:\n");
7905 fprintf(f, " Compiled %d methods.\n", m_numMethods);
7906 if (m_numMethods != 0)
7908 fprintf(f, " Compiled %d bytecodes total (%d max, %8.2f avg).\n", m_total.m_byteCodeBytes,
7909 m_maximum.m_byteCodeBytes, (double)m_total.m_byteCodeBytes / (double)m_numMethods);
7910 totTime_ms = ((double)m_total.m_totalCycles / countsPerSec) * 1000.0;
7911 fprintf(f, " Time: total: %10.3f Mcycles/%10.3f ms\n", ((double)m_total.m_totalCycles / 1000000.0),
7913 fprintf(f, " max: %10.3f Mcycles/%10.3f ms\n", ((double)m_maximum.m_totalCycles) / 1000000.0,
7914 ((double)m_maximum.m_totalCycles / countsPerSec) * 1000.0);
7915 fprintf(f, " avg: %10.3f Mcycles/%10.3f ms\n",
7916 ((double)m_total.m_totalCycles) / 1000000.0 / (double)m_numMethods, totTime_ms / (double)m_numMethods);
7918 const char* extraHdr1 = "";
7919 const char* extraHdr2 = "";
7920 #if MEASURE_CLRAPI_CALLS
7923 extraHdr1 = " CLRs/meth % in CLR";
7924 extraHdr2 = "-----------------------";
7928 fprintf(f, "\n Total time by phases:\n");
7929 fprintf(f, " PHASE inv/meth Mcycles time (ms) %% of total max (ms)%s\n",
7931 fprintf(f, " ---------------------------------------------------------------------------------------%s\n",
7934 // Ensure that at least the names array and the Phases enum have the same number of entries:
7935 assert(_countof(PhaseNames) == PHASE_NUMBER_OF);
7936 for (int i = 0; i < PHASE_NUMBER_OF; i++)
7938 double phase_tot_ms = (((double)m_total.m_cyclesByPhase[i]) / countsPerSec) * 1000.0;
7939 double phase_max_ms = (((double)m_maximum.m_cyclesByPhase[i]) / countsPerSec) * 1000.0;
7940 double phase_tot_pct = 100.0 * phase_tot_ms / totTime_ms;
7942 #if MEASURE_CLRAPI_CALLS
7943 // Skip showing CLR API call info if we didn't collect any
7944 if (i == PHASE_CLR_API && !extraInfo)
7948 // Indent nested phases, according to depth.
7949 int ancPhase = PhaseParent[i];
7950 while (ancPhase != -1)
7953 ancPhase = PhaseParent[ancPhase];
7955 fprintf(f, " %-30s %6.2f %10.2f %9.3f %8.2f%% %8.3f", PhaseNames[i],
7956 ((double)m_total.m_invokesByPhase[i]) / ((double)m_numMethods),
7957 ((double)m_total.m_cyclesByPhase[i]) / 1000000.0, phase_tot_ms, (phase_tot_ms * 100.0 / totTime_ms),
7960 #if MEASURE_CLRAPI_CALLS
7961 if (extraInfo && i != PHASE_CLR_API)
7963 double nest_tot_ms = (((double)m_total.m_CLRcyclesByPhase[i]) / countsPerSec) * 1000.0;
7964 double nest_percent = nest_tot_ms * 100.0 / totTime_ms;
7965 double calls_per_fn = ((double)m_total.m_CLRinvokesByPhase[i]) / ((double)m_numMethods);
7967 if (nest_percent > 0.1 || calls_per_fn > 10)
7968 fprintf(f, " %5.1f %8.2f%%", calls_per_fn, nest_percent);
7974 // Show slop if it's over a certain percentage of the total
7975 double pslop_pct = 100.0 * m_total.m_parentPhaseEndSlop * 1000.0 / countsPerSec / totTime_ms;
7976 if (pslop_pct >= 1.0)
7978 fprintf(f, "\n 'End phase slop' should be very small (if not, there's unattributed time): %9.3f Mcycles = "
7979 "%3.1f%% of total.\n\n",
7980 m_total.m_parentPhaseEndSlop / 1000000.0, pslop_pct);
7983 if (m_numFilteredMethods > 0)
7985 fprintf(f, " Compiled %d methods that meet the filter requirement.\n", m_numFilteredMethods);
7986 fprintf(f, " Compiled %d bytecodes total (%8.2f avg).\n", m_filtered.m_byteCodeBytes,
7987 (double)m_filtered.m_byteCodeBytes / (double)m_numFilteredMethods);
7988 double totTime_ms = ((double)m_filtered.m_totalCycles / countsPerSec) * 1000.0;
7989 fprintf(f, " Time: total: %10.3f Mcycles/%10.3f ms\n", ((double)m_filtered.m_totalCycles / 1000000.0),
7991 fprintf(f, " avg: %10.3f Mcycles/%10.3f ms\n",
7992 ((double)m_filtered.m_totalCycles) / 1000000.0 / (double)m_numFilteredMethods,
7993 totTime_ms / (double)m_numFilteredMethods);
7995 fprintf(f, " Total time by phases:\n");
7996 fprintf(f, " PHASE inv/meth Mcycles time (ms) %% of total\n");
7997 fprintf(f, " --------------------------------------------------------------------------------------\n");
7998 // Ensure that at least the names array and the Phases enum have the same number of entries:
7999 assert(_countof(PhaseNames) == PHASE_NUMBER_OF);
8000 for (int i = 0; i < PHASE_NUMBER_OF; i++)
8002 double phase_tot_ms = (((double)m_filtered.m_cyclesByPhase[i]) / countsPerSec) * 1000.0;
8003 // Indent nested phases, according to depth.
8004 int ancPhase = PhaseParent[i];
8005 while (ancPhase != -1)
8008 ancPhase = PhaseParent[ancPhase];
8010 fprintf(f, " %-30s %5.2f %10.2f %9.3f %8.2f%%\n", PhaseNames[i],
8011 ((double)m_filtered.m_invokesByPhase[i]) / ((double)m_numFilteredMethods),
8012 ((double)m_filtered.m_cyclesByPhase[i]) / 1000000.0, phase_tot_ms,
8013 (phase_tot_ms * 100.0 / totTime_ms));
8016 double fslop_ms = m_filtered.m_parentPhaseEndSlop * 1000.0 / countsPerSec;
8020 "\n 'End phase slop' should be very small (if not, there's unattributed time): %9.3f Mcycles.\n",
8021 m_filtered.m_parentPhaseEndSlop);
8025 #if MEASURE_CLRAPI_CALLS
8026 if (m_total.m_allClrAPIcalls > 0 && m_total.m_allClrAPIcycles > 0)
8029 if (m_totMethods > 0)
8030 fprintf(f, " Imported %u methods.\n\n", m_numMethods + m_totMethods);
8032 fprintf(f, " CLR API # calls total time max time avg time %% "
8034 fprintf(f, " -------------------------------------------------------------------------------");
8035 fprintf(f, "---------------------\n");
8037 static const char* APInames[] = {
8038 #define DEF_CLR_API(name) #name,
8039 #include "ICorJitInfo_API_names.h"
8042 unsigned shownCalls = 0;
8043 double shownMillis = 0.0;
8045 unsigned checkedCalls = 0;
8046 double checkedMillis = 0.0;
8049 for (unsigned pass = 0; pass < 2; pass++)
8051 for (unsigned i = 0; i < API_ICorJitInfo_Names::API_COUNT; i++)
8053 unsigned calls = m_total.m_perClrAPIcalls[i];
8057 unsigned __int64 cycles = m_total.m_perClrAPIcycles[i];
8058 double millis = 1000.0 * cycles / countsPerSec;
8060 // Don't show the small fry to keep the results manageable
8063 // We always show the following API because it is always called
8064 // exactly once for each method and its body is the simplest one
8065 // possible (it just returns an integer constant), and therefore
8066 // it can be used to measure the overhead of adding the CLR API
8067 // timing code. Roughly speaking, on a 3GHz x64 box the overhead
8068 // per call should be around 40 ns when using RDTSC, compared to
8069 // about 140 ns when using GetThreadCycles() under Windows.
8070 if (i != API_ICorJitInfo_Names::API_getExpectedTargetArchitecture)
8074 // In the first pass we just compute the totals.
8077 shownCalls += m_total.m_perClrAPIcalls[i];
8078 shownMillis += millis;
8082 unsigned __int32 maxcyc = m_maximum.m_maxClrAPIcycles[i];
8083 double max_ms = 1000.0 * maxcyc / countsPerSec;
8085 fprintf(f, " %-40s", APInames[i]); // API name
8086 fprintf(f, " %8u %9.1f ms", calls, millis); // #calls, total time
8087 fprintf(f, " %8.1f ms %8.1f ns", max_ms, 1000000.0 * millis / calls); // max, avg time
8088 fprintf(f, " %5.1f%%\n", 100.0 * millis / shownMillis); // % of total
8091 checkedCalls += m_total.m_perClrAPIcalls[i];
8092 checkedMillis += millis;
8098 assert(checkedCalls == shownCalls);
8099 assert(checkedMillis == shownMillis);
8102 if (shownCalls > 0 || shownMillis > 0)
8104 fprintf(f, " -------------------------");
8105 fprintf(f, "---------------------------------------------------------------------------\n");
8106 fprintf(f, " Total for calls shown above %8u %10.1f ms", shownCalls, shownMillis);
8107 if (totTime_ms > 0.0)
8108 fprintf(f, " (%4.1lf%% of overall JIT time)", shownMillis * 100.0 / totTime_ms);
8118 JitTimer::JitTimer(unsigned byteCodeSize) : m_info(byteCodeSize)
8120 #if MEASURE_CLRAPI_CALLS
8121 m_CLRcallInvokes = 0;
8122 m_CLRcallCycles = 0;
8126 m_lastPhase = (Phases)-1;
8127 #if MEASURE_CLRAPI_CALLS
8128 m_CLRcallAPInum = -1;
8132 unsigned __int64 threadCurCycles;
8133 if (_our_GetThreadCycles(&threadCurCycles))
8135 m_start = threadCurCycles;
8136 m_curPhaseStart = threadCurCycles;
8140 void JitTimer::EndPhase(Compiler* compiler, Phases phase)
8143 // We re-run some phases currently, so this following assert doesn't work.
8144 // assert((int)phase > (int)m_lastPhase); // We should end phases in increasing order.
8146 unsigned __int64 threadCurCycles;
8147 if (_our_GetThreadCycles(&threadCurCycles))
8149 unsigned __int64 phaseCycles = (threadCurCycles - m_curPhaseStart);
8151 // If this is not a leaf phase, the assumption is that the last subphase must have just recently ended.
8152 // Credit the duration to "slop", the total of which should be very small.
8153 if (PhaseHasChildren[phase])
8155 m_info.m_parentPhaseEndSlop += phaseCycles;
8159 // It is a leaf phase. Credit duration to it.
8160 m_info.m_invokesByPhase[phase]++;
8161 m_info.m_cyclesByPhase[phase] += phaseCycles;
8163 #if MEASURE_CLRAPI_CALLS
8164 // Record the CLR API timing info as well.
8165 m_info.m_CLRinvokesByPhase[phase] += m_CLRcallInvokes;
8166 m_info.m_CLRcyclesByPhase[phase] += m_CLRcallCycles;
8169 // Credit the phase's ancestors, if any.
8170 int ancPhase = PhaseParent[phase];
8171 while (ancPhase != -1)
8173 m_info.m_cyclesByPhase[ancPhase] += phaseCycles;
8174 ancPhase = PhaseParent[ancPhase];
8177 #if MEASURE_CLRAPI_CALLS
8178 const Phases lastPhase = PHASE_CLR_API;
8180 const Phases lastPhase = PHASE_NUMBER_OF;
8182 if (phase + 1 == lastPhase)
8184 m_info.m_totalCycles = (threadCurCycles - m_start);
8188 m_curPhaseStart = threadCurCycles;
8192 if ((JitConfig.JitMeasureIR() != 0) && PhaseReportsIRSize[phase])
8194 m_info.m_nodeCountAfterPhase[phase] = compiler->fgMeasureIR();
8198 m_info.m_nodeCountAfterPhase[phase] = 0;
8203 m_lastPhase = phase;
8205 #if MEASURE_CLRAPI_CALLS
8206 m_CLRcallInvokes = 0;
8207 m_CLRcallCycles = 0;
8211 #if MEASURE_CLRAPI_CALLS
8213 //------------------------------------------------------------------------
8214 // JitTimer::CLRApiCallEnter: Start the stopwatch for an EE call.
8217 // apix - The API index - an "enum API_ICorJitInfo_Names" value.
8220 void JitTimer::CLRApiCallEnter(unsigned apix)
8222 assert(m_CLRcallAPInum == -1); // Nested calls not allowed
8223 m_CLRcallAPInum = apix;
8225 // If we can't get the cycles, we'll just ignore this call
8226 if (!_our_GetThreadCycles(&m_CLRcallStart))
8230 //------------------------------------------------------------------------
8231 // JitTimer::CLRApiCallLeave: compute / record time spent in an EE call.
8234 // apix - The API's "enum API_ICorJitInfo_Names" value; this value
8235 // should match the value passed to the most recent call to
8236 // "CLRApiCallEnter" (i.e. these must come as matched pairs),
8237 // and they also may not nest.
8240 void JitTimer::CLRApiCallLeave(unsigned apix)
8242 // Make sure we're actually inside a measured CLR call.
8243 assert(m_CLRcallAPInum != -1);
8244 m_CLRcallAPInum = -1;
8246 // Ignore this one if we don't have a valid starting counter.
8247 if (m_CLRcallStart != 0)
8249 if (JitConfig.JitEECallTimingInfo() != 0)
8251 unsigned __int64 threadCurCycles;
8252 if (_our_GetThreadCycles(&threadCurCycles))
8254 // Compute the cycles spent in the call.
8255 threadCurCycles -= m_CLRcallStart;
8257 // Add the cycles to the 'phase' and bump its use count.
8258 m_info.m_cyclesByPhase[PHASE_CLR_API] += threadCurCycles;
8259 m_info.m_invokesByPhase[PHASE_CLR_API] += 1;
8261 // Add the values to the "per API" info.
8262 m_info.m_allClrAPIcycles += threadCurCycles;
8263 m_info.m_allClrAPIcalls += 1;
8265 m_info.m_perClrAPIcalls[apix] += 1;
8266 m_info.m_perClrAPIcycles[apix] += threadCurCycles;
8267 m_info.m_maxClrAPIcycles[apix] = max(m_info.m_maxClrAPIcycles[apix], (unsigned __int32)threadCurCycles);
8269 // Subtract the cycles from the enclosing phase by bumping its start time
8270 m_curPhaseStart += threadCurCycles;
8272 // Update the running totals.
8273 m_CLRcallInvokes += 1;
8274 m_CLRcallCycles += threadCurCycles;
8281 assert(m_CLRcallAPInum != -1); // No longer in this API call.
8282 m_CLRcallAPInum = -1;
8285 #endif // MEASURE_CLRAPI_CALLS
8287 CritSecObject JitTimer::s_csvLock;
8289 LPCWSTR Compiler::JitTimeLogCsv()
8291 LPCWSTR jitTimeLogCsv = JitConfig.JitTimeLogCsv();
8292 return jitTimeLogCsv;
8295 void JitTimer::PrintCsvHeader()
8297 LPCWSTR jitTimeLogCsv = Compiler::JitTimeLogCsv();
8298 if (jitTimeLogCsv == nullptr)
8303 CritSecHolder csvLock(s_csvLock);
8305 FILE* fp = _wfopen(jitTimeLogCsv, W("a"));
8308 // Seek to the end of the file s.t. `ftell` doesn't lie to us on Windows
8309 fseek(fp, 0, SEEK_END);
8311 // Write the header if the file is empty
8314 fprintf(fp, "\"Method Name\",");
8315 fprintf(fp, "\"Assembly or SPMI Index\",");
8316 fprintf(fp, "\"IL Bytes\",");
8317 fprintf(fp, "\"Basic Blocks\",");
8318 fprintf(fp, "\"Min Opts\",");
8319 fprintf(fp, "\"Loops Cloned\",");
8321 for (int i = 0; i < PHASE_NUMBER_OF; i++)
8323 fprintf(fp, "\"%s\",", PhaseNames[i]);
8324 if ((JitConfig.JitMeasureIR() != 0) && PhaseReportsIRSize[i])
8326 fprintf(fp, "\"Node Count After %s\",", PhaseNames[i]);
8330 InlineStrategy::DumpCsvHeader(fp);
8332 fprintf(fp, "\"Executable Code Bytes\",");
8333 fprintf(fp, "\"GC Info Bytes\",");
8334 fprintf(fp, "\"Total Bytes Allocated\",");
8335 fprintf(fp, "\"Total Cycles\",");
8336 fprintf(fp, "\"CPS\"\n");
8342 extern ICorJitHost* g_jitHost;
8344 void JitTimer::PrintCsvMethodStats(Compiler* comp)
8346 LPCWSTR jitTimeLogCsv = Compiler::JitTimeLogCsv();
8347 if (jitTimeLogCsv == nullptr)
8352 // eeGetMethodFullName uses locks, so don't enter crit sec before this call.
8353 const char* methName = comp->eeGetMethodFullName(comp->info.compMethodHnd);
8355 // Try and access the SPMI index to report in the data set.
8357 // If the jit is not hosted under SPMI this will return the
8358 // default value of zero.
8360 // Query the jit host directly here instead of going via the
8361 // config cache, since value will change for each method.
8362 int index = g_jitHost->getIntConfigValue(W("SuperPMIMethodContextNumber"), 0);
8364 CritSecHolder csvLock(s_csvLock);
8366 FILE* fp = _wfopen(jitTimeLogCsv, W("a"));
8367 fprintf(fp, "\"%s\",", methName);
8370 fprintf(fp, "%d,", index);
8374 const char* methodAssemblyName = comp->info.compCompHnd->getAssemblyName(
8375 comp->info.compCompHnd->getModuleAssembly(comp->info.compCompHnd->getClassModule(comp->info.compClassHnd)));
8376 fprintf(fp, "\"%s\",", methodAssemblyName);
8378 fprintf(fp, "%u,", comp->info.compILCodeSize);
8379 fprintf(fp, "%u,", comp->fgBBcount);
8380 fprintf(fp, "%u,", comp->opts.MinOpts());
8381 fprintf(fp, "%u,", comp->optLoopsCloned);
8382 unsigned __int64 totCycles = 0;
8383 for (int i = 0; i < PHASE_NUMBER_OF; i++)
8385 if (!PhaseHasChildren[i])
8387 totCycles += m_info.m_cyclesByPhase[i];
8389 fprintf(fp, "%I64u,", m_info.m_cyclesByPhase[i]);
8391 if ((JitConfig.JitMeasureIR() != 0) && PhaseReportsIRSize[i])
8393 fprintf(fp, "%u,", m_info.m_nodeCountAfterPhase[i]);
8397 comp->m_inlineStrategy->DumpCsvData(fp);
8399 fprintf(fp, "%Iu,", comp->info.compNativeCodeSize);
8400 fprintf(fp, "%Iu,", comp->compInfoBlkSize);
8401 fprintf(fp, "%Iu,", comp->compGetAllocator()->getTotalBytesAllocated());
8402 fprintf(fp, "%I64u,", m_info.m_totalCycles);
8403 fprintf(fp, "%f\n", CycleTimer::CyclesPerSecond());
8407 // Completes the timing of the current method, and adds it to "sum".
8408 void JitTimer::Terminate(Compiler* comp, CompTimeSummaryInfo& sum, bool includePhases)
8412 PrintCsvMethodStats(comp);
8415 sum.AddInfo(m_info, includePhases);
8417 #endif // FEATURE_JIT_METHOD_PERF
8419 #if MEASURE_MEM_ALLOC
8421 CritSecObject Compiler::s_memStatsLock; // Default constructor.
8422 Compiler::AggregateMemStats Compiler::s_aggMemStats; // Default constructor.
8423 Compiler::MemStats Compiler::s_maxCompMemStats; // Default constructor.
8425 const char* Compiler::MemStats::s_CompMemKindNames[] = {
8426 #define CompMemKindMacro(kind) #kind,
8427 #include "compmemkind.h"
8430 void Compiler::MemStats::Print(FILE* f)
8432 fprintf(f, "count: %10u, size: %10llu, max = %10llu\n", allocCnt, allocSz, allocSzMax);
8433 fprintf(f, "allocateMemory: %10llu, nraUsed: %10llu\n", nraTotalSizeAlloc, nraTotalSizeUsed);
8437 void Compiler::MemStats::PrintByKind(FILE* f)
8439 fprintf(f, "\nAlloc'd bytes by kind:\n %20s | %10s | %7s\n", "kind", "size", "pct");
8440 fprintf(f, " %20s-+-%10s-+-%7s\n", "--------------------", "----------", "-------");
8441 float allocSzF = static_cast<float>(allocSz);
8442 for (int cmk = 0; cmk < CMK_Count; cmk++)
8444 float pct = 100.0f * static_cast<float>(allocSzByKind[cmk]) / allocSzF;
8445 fprintf(f, " %20s | %10llu | %6.2f%%\n", s_CompMemKindNames[cmk], allocSzByKind[cmk], pct);
8450 void Compiler::AggregateMemStats::Print(FILE* f)
8452 fprintf(f, "For %9u methods:\n", nMethods);
8457 fprintf(f, " count: %12u (avg %7u per method)\n", allocCnt, allocCnt / nMethods);
8458 fprintf(f, " alloc size : %12llu (avg %7llu per method)\n", allocSz, allocSz / nMethods);
8459 fprintf(f, " max alloc : %12llu\n", allocSzMax);
8461 fprintf(f, " allocateMemory : %12llu (avg %7llu per method)\n", nraTotalSizeAlloc, nraTotalSizeAlloc / nMethods);
8462 fprintf(f, " nraUsed : %12llu (avg %7llu per method)\n", nraTotalSizeUsed, nraTotalSizeUsed / nMethods);
8465 #endif // MEASURE_MEM_ALLOC
8467 #if LOOP_HOIST_STATS
8469 CritSecObject Compiler::s_loopHoistStatsLock; // Default constructor.
8470 unsigned Compiler::s_loopsConsidered = 0;
8471 unsigned Compiler::s_loopsWithHoistedExpressions = 0;
8472 unsigned Compiler::s_totalHoistedExpressions = 0;
8475 void Compiler::PrintAggregateLoopHoistStats(FILE* f)
8478 fprintf(f, "---------------------------------------------------\n");
8479 fprintf(f, "Loop hoisting stats\n");
8480 fprintf(f, "---------------------------------------------------\n");
8482 double pctWithHoisted = 0.0;
8483 if (s_loopsConsidered > 0)
8485 pctWithHoisted = 100.0 * (double(s_loopsWithHoistedExpressions) / double(s_loopsConsidered));
8487 double exprsPerLoopWithExpr = 0.0;
8488 if (s_loopsWithHoistedExpressions > 0)
8490 exprsPerLoopWithExpr = double(s_totalHoistedExpressions) / double(s_loopsWithHoistedExpressions);
8492 fprintf(f, "Considered %d loops. Of these, we hoisted expressions out of %d (%6.2f%%).\n", s_loopsConsidered,
8493 s_loopsWithHoistedExpressions, pctWithHoisted);
8494 fprintf(f, " A total of %d expressions were hoisted, an average of %5.2f per loop-with-hoisted-expr.\n",
8495 s_totalHoistedExpressions, exprsPerLoopWithExpr);
8498 void Compiler::AddLoopHoistStats()
8500 CritSecHolder statsLock(s_loopHoistStatsLock);
8502 s_loopsConsidered += m_loopsConsidered;
8503 s_loopsWithHoistedExpressions += m_loopsWithHoistedExpressions;
8504 s_totalHoistedExpressions += m_totalHoistedExpressions;
8507 void Compiler::PrintPerMethodLoopHoistStats()
8509 double pctWithHoisted = 0.0;
8510 if (m_loopsConsidered > 0)
8512 pctWithHoisted = 100.0 * (double(m_loopsWithHoistedExpressions) / double(m_loopsConsidered));
8514 double exprsPerLoopWithExpr = 0.0;
8515 if (m_loopsWithHoistedExpressions > 0)
8517 exprsPerLoopWithExpr = double(m_totalHoistedExpressions) / double(m_loopsWithHoistedExpressions);
8519 printf("Considered %d loops. Of these, we hoisted expressions out of %d (%5.2f%%).\n", m_loopsConsidered,
8520 m_loopsWithHoistedExpressions, pctWithHoisted);
8521 printf(" A total of %d expressions were hoisted, an average of %5.2f per loop-with-hoisted-expr.\n",
8522 m_totalHoistedExpressions, exprsPerLoopWithExpr);
8524 #endif // LOOP_HOIST_STATS
8526 //------------------------------------------------------------------------
8527 // RecordStateAtEndOfInlining: capture timing data (if enabled) after
8528 // inlining as completed.
8531 // Records data needed for SQM and inlining data dumps. Should be
8532 // called after inlining is complete. (We do this after inlining
8533 // because this marks the last point at which the JIT is likely to
8534 // cause type-loading and class initialization).
8536 void Compiler::RecordStateAtEndOfInlining()
8538 #if defined(DEBUG) || defined(INLINE_DATA) || defined(FEATURE_CLRSQM)
8540 m_compCyclesAtEndOfInlining = 0;
8541 m_compTickCountAtEndOfInlining = 0;
8542 bool b = CycleTimer::GetThreadCyclesS(&m_compCyclesAtEndOfInlining);
8545 return; // We don't have a thread cycle counter.
8547 m_compTickCountAtEndOfInlining = GetTickCount();
8549 #endif // defined(DEBUG) || defined(INLINE_DATA) || defined(FEATURE_CLRSQM)
8552 //------------------------------------------------------------------------
8553 // RecordStateAtEndOfCompilation: capture timing data (if enabled) after
8554 // compilation is completed.
8556 void Compiler::RecordStateAtEndOfCompilation()
8558 #if defined(DEBUG) || defined(INLINE_DATA) || defined(FEATURE_CLRSQM)
8562 unsigned __int64 compCyclesAtEnd;
8563 bool b = CycleTimer::GetThreadCyclesS(&compCyclesAtEnd);
8566 return; // We don't have a thread cycle counter.
8568 assert(compCyclesAtEnd >= m_compCyclesAtEndOfInlining);
8570 m_compCycles = compCyclesAtEnd - m_compCyclesAtEndOfInlining;
8572 #endif // defined(DEBUG) || defined(INLINE_DATA) || defined(FEATURE_CLRSQM)
8574 #ifdef FEATURE_CLRSQM
8577 unsigned __int64 mcycles64 = m_compCycles / ((unsigned __int64)1000000);
8579 if (mcycles64 > UINT32_MAX)
8581 mcycles = UINT32_MAX;
8585 mcycles = (unsigned)mcycles64;
8588 DWORD ticksAtEnd = GetTickCount();
8589 assert(ticksAtEnd >= m_compTickCountAtEndOfInlining);
8590 DWORD compTicks = ticksAtEnd - m_compTickCountAtEndOfInlining;
8592 if (mcycles >= 1000)
8594 info.compCompHnd->logSQMLongJitEvent(mcycles, compTicks, info.compILCodeSize, fgBBcount, opts.MinOpts(),
8595 info.compMethodHnd);
8598 #endif // FEATURE_CLRSQM
8601 #if FUNC_INFO_LOGGING
8603 LPCWSTR Compiler::compJitFuncInfoFilename = nullptr;
8606 FILE* Compiler::compJitFuncInfoFile = nullptr;
8607 #endif // FUNC_INFO_LOGGING
8611 // dumpConvertedVarSet() dumps the varset bits that are tracked
8612 // variable indices, and we convert them to variable numbers, sort the variable numbers, and
8613 // print them as variable numbers. To do this, we use a temporary set indexed by
8614 // variable number. We can't use the "all varset" type because it is still size-limited, and might
8615 // not be big enough to handle all possible variable numbers.
8616 void dumpConvertedVarSet(Compiler* comp, VARSET_VALARG_TP vars)
8618 BYTE* pVarNumSet; // trivial set: one byte per varNum, 0 means not in set, 1 means in set.
8620 size_t varNumSetBytes = comp->lvaCount * sizeof(BYTE);
8621 pVarNumSet = (BYTE*)_alloca(varNumSetBytes);
8622 memset(pVarNumSet, 0, varNumSetBytes); // empty the set
8624 VarSetOps::Iter iter(comp, vars);
8625 unsigned varIndex = 0;
8626 while (iter.NextElem(&varIndex))
8628 unsigned varNum = comp->lvaTrackedToVarNum[varIndex];
8629 assert(varNum < comp->lvaCount);
8630 pVarNumSet[varNum] = 1; // This varNum is in the set
8635 for (size_t varNum = 0; varNum < comp->lvaCount; varNum++)
8637 if (pVarNumSet[varNum] == 1)
8643 printf("V%02u", varNum);
8650 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8651 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8653 XX Debugging helpers XX
8655 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8656 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8659 /*****************************************************************************/
8660 /* The following functions are intended to be called from the debugger, to dump
8661 * various data structures.
8663 * The versions that start with 'c' take a Compiler* as the first argument.
8664 * The versions that start with 'd' use the tlsCompiler, so don't require a Compiler*.
8667 * cBlock, dBlock : Display a basic block (call fgTableDispBasicBlock()).
8668 * cBlocks, dBlocks : Display all the basic blocks of a function (call fgDispBasicBlocks()).
8669 * cBlocksV, dBlocksV : Display all the basic blocks of a function (call fgDispBasicBlocks(true)).
8670 * "V" means "verbose", and will dump all the trees.
8671 * cTree, dTree : Display a tree (call gtDispTree()).
8672 * cTreeLIR, dTreeLIR : Display a tree in LIR form (call gtDispLIRNode()).
8673 * cTrees, dTrees : Display all the trees in a function (call fgDumpTrees()).
8674 * cEH, dEH : Display the EH handler table (call fgDispHandlerTab()).
8675 * cVar, dVar : Display a local variable given its number (call lvaDumpEntry()).
8676 * cVarDsc, dVarDsc : Display a local variable given a LclVarDsc* (call lvaDumpEntry()).
8677 * cVars, dVars : Display the local variable table (call lvaTableDump()).
8678 * cVarsFinal, dVarsFinal : Display the local variable table (call lvaTableDump(FINAL_FRAME_LAYOUT)).
8679 * cBlockCheapPreds, dBlockCheapPreds : Display a block's cheap predecessors (call block->dspCheapPreds()).
8680 * cBlockPreds, dBlockPreds : Display a block's predecessors (call block->dspPreds()).
8681 * cBlockSuccs, dBlockSuccs : Display a block's successors (call block->dspSuccs(compiler)).
8682 * cReach, dReach : Display all block reachability (call fgDispReach()).
8683 * cDoms, dDoms : Display all block dominators (call fgDispDoms()).
8684 * cLiveness, dLiveness : Display per-block variable liveness (call fgDispBBLiveness()).
8685 * cCVarSet, dCVarSet : Display a "converted" VARSET_TP: the varset is assumed to be tracked variable
8686 * indices. These are converted to variable numbers and sorted. (Calls
8687 * dumpConvertedVarSet()).
8689 * cFuncIR, dFuncIR : Display all the basic blocks of a function in linear IR form.
8690 * cLoopIR, dLoopIR : Display a loop in linear IR form.
8691 * dLoopNumIR : Display a loop (given number) in linear IR form.
8692 * cBlockIR, dBlockIR : Display a basic block in linear IR form.
8693 * cTreeIR, dTreeIR : Display a tree in linear IR form.
8694 * dTabStopIR : Display spaces to the next tab stop column
8695 * cTreeTypeIR dTreeTypeIR : Display tree type
8696 * cTreeKindsIR dTreeKindsIR : Display tree kinds
8697 * cTreeFlagsIR dTreeFlagsIR : Display tree flags
8698 * cOperandIR dOperandIR : Display tree operand
8699 * cLeafIR dLeafIR : Display tree leaf
8700 * cIndirIR dIndirIR : Display indir tree as [t#] or [leaf]
8701 * cListIR dListIR : Display tree list
8702 * cSsaNumIR dSsaNumIR : Display SSA number as <u|d:#>
8703 * cValNumIR dValNumIR : Display Value number as <v{l|c}:#{,R}>
8704 * cDependsIR : Display dependencies of a tree DEP(t# ...) node
8705 * based on child comma tree nodes
8706 * dFormatIR : Display dump format specified on command line
8709 * The following don't require a Compiler* to work:
8710 * dRegMask : Display a regMaskTP (call dspRegMask(mask)).
8713 void cBlock(Compiler* comp, BasicBlock* block)
8715 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8716 printf("===================================================================== *Block %u\n", sequenceNumber++);
8717 comp->fgTableDispBasicBlock(block);
8720 void cBlocks(Compiler* comp)
8722 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8723 printf("===================================================================== *Blocks %u\n", sequenceNumber++);
8724 comp->fgDispBasicBlocks();
8727 void cBlocksV(Compiler* comp)
8729 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8730 printf("===================================================================== *BlocksV %u\n", sequenceNumber++);
8731 comp->fgDispBasicBlocks(true);
8734 void cTree(Compiler* comp, GenTree* tree)
8736 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8737 printf("===================================================================== *Tree %u\n", sequenceNumber++);
8738 comp->gtDispTree(tree, nullptr, ">>>");
8741 void cTreeLIR(Compiler* comp, GenTree* tree)
8743 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8744 printf("===================================================================== *TreeLIR %u\n", sequenceNumber++);
8745 comp->gtDispLIRNode(tree);
8748 void cTrees(Compiler* comp)
8750 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8751 printf("===================================================================== *Trees %u\n", sequenceNumber++);
8752 comp->fgDumpTrees(comp->fgFirstBB, nullptr);
8755 void cEH(Compiler* comp)
8757 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8758 printf("===================================================================== *EH %u\n", sequenceNumber++);
8759 comp->fgDispHandlerTab();
8762 void cVar(Compiler* comp, unsigned lclNum)
8764 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8765 printf("===================================================================== *Var %u\n", sequenceNumber++);
8766 comp->lvaDumpEntry(lclNum, Compiler::FINAL_FRAME_LAYOUT);
8769 void cVarDsc(Compiler* comp, LclVarDsc* varDsc)
8771 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8772 printf("===================================================================== *VarDsc %u\n", sequenceNumber++);
8773 unsigned lclNum = (unsigned)(varDsc - comp->lvaTable);
8774 comp->lvaDumpEntry(lclNum, Compiler::FINAL_FRAME_LAYOUT);
8777 void cVars(Compiler* comp)
8779 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8780 printf("===================================================================== *Vars %u\n", sequenceNumber++);
8781 comp->lvaTableDump();
8784 void cVarsFinal(Compiler* comp)
8786 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8787 printf("===================================================================== *Vars %u\n", sequenceNumber++);
8788 comp->lvaTableDump(Compiler::FINAL_FRAME_LAYOUT);
8791 void cBlockCheapPreds(Compiler* comp, BasicBlock* block)
8793 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8794 printf("===================================================================== *BlockCheapPreds %u\n",
8796 block->dspCheapPreds();
8799 void cBlockPreds(Compiler* comp, BasicBlock* block)
8801 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8802 printf("===================================================================== *BlockPreds %u\n", sequenceNumber++);
8806 void cBlockSuccs(Compiler* comp, BasicBlock* block)
8808 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8809 printf("===================================================================== *BlockSuccs %u\n", sequenceNumber++);
8810 block->dspSuccs(comp);
8813 void cReach(Compiler* comp)
8815 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8816 printf("===================================================================== *Reach %u\n", sequenceNumber++);
8817 comp->fgDispReach();
8820 void cDoms(Compiler* comp)
8822 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8823 printf("===================================================================== *Doms %u\n", sequenceNumber++);
8827 void cLiveness(Compiler* comp)
8829 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8830 printf("===================================================================== *Liveness %u\n", sequenceNumber++);
8831 comp->fgDispBBLiveness();
8834 void cCVarSet(Compiler* comp, VARSET_VALARG_TP vars)
8836 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8837 printf("===================================================================== dCVarSet %u\n", sequenceNumber++);
8838 dumpConvertedVarSet(comp, vars);
8839 printf("\n"); // dumpConvertedVarSet() doesn't emit a trailing newline
8842 void dBlock(BasicBlock* block)
8844 cBlock(JitTls::GetCompiler(), block);
8849 cBlocks(JitTls::GetCompiler());
8854 cBlocksV(JitTls::GetCompiler());
8857 void dTree(GenTree* tree)
8859 cTree(JitTls::GetCompiler(), tree);
8862 void dTreeLIR(GenTree* tree)
8864 cTreeLIR(JitTls::GetCompiler(), tree);
8869 cTrees(JitTls::GetCompiler());
8874 cEH(JitTls::GetCompiler());
8877 void dVar(unsigned lclNum)
8879 cVar(JitTls::GetCompiler(), lclNum);
8882 void dVarDsc(LclVarDsc* varDsc)
8884 cVarDsc(JitTls::GetCompiler(), varDsc);
8889 cVars(JitTls::GetCompiler());
8894 cVarsFinal(JitTls::GetCompiler());
8897 void dBlockPreds(BasicBlock* block)
8899 cBlockPreds(JitTls::GetCompiler(), block);
8902 void dBlockCheapPreds(BasicBlock* block)
8904 cBlockCheapPreds(JitTls::GetCompiler(), block);
8907 void dBlockSuccs(BasicBlock* block)
8909 cBlockSuccs(JitTls::GetCompiler(), block);
8914 cReach(JitTls::GetCompiler());
8919 cDoms(JitTls::GetCompiler());
8924 cLiveness(JitTls::GetCompiler());
8927 void dCVarSet(VARSET_VALARG_TP vars)
8929 cCVarSet(JitTls::GetCompiler(), vars);
8932 void dRegMask(regMaskTP mask)
8934 static unsigned sequenceNumber = 0; // separate calls with a number to indicate this function has been called
8935 printf("===================================================================== dRegMask %u\n", sequenceNumber++);
8937 printf("\n"); // dspRegMask() doesn't emit a trailing newline
8940 void dBlockList(BasicBlockList* list)
8942 printf("WorkList: ");
8943 while (list != nullptr)
8945 printf("BB%02u ", list->block->bbNum);
8951 // Global variables available in debug mode. That are set by debug APIs for finding
8952 // Trees, Stmts, and/or Blocks using id or bbNum.
8953 // That can be used in watch window or as a way to get address of fields for data break points.
8956 GenTreeStmt* dbStmt;
8957 BasicBlock* dbTreeBlock;
8958 BasicBlock* dbBlock;
8960 // Debug APIs for finding Trees, Stmts, and/or Blocks.
8961 // As a side effect, they set the debug variables above.
8963 GenTree* dFindTree(GenTree* tree, unsigned id)
8967 if (tree == nullptr)
8972 if (tree->gtTreeID == id)
8978 unsigned childCount = tree->NumChildren();
8979 for (unsigned childIndex = 0; childIndex < childCount; childIndex++)
8981 child = tree->GetChild(childIndex);
8982 child = dFindTree(child, id);
8983 if (child != nullptr)
8992 GenTree* dFindTree(unsigned id)
8994 Compiler* comp = JitTls::GetCompiler();
8998 dbTreeBlock = nullptr;
9001 for (block = comp->fgFirstBB; block != nullptr; block = block->bbNext)
9003 for (GenTreeStmt* stmt = block->firstStmt(); stmt; stmt = stmt->gtNextStmt)
9005 tree = dFindTree(stmt, id);
9006 if (tree != nullptr)
9008 dbTreeBlock = block;
9017 GenTreeStmt* dFindStmt(unsigned id)
9019 Compiler* comp = JitTls::GetCompiler();
9024 unsigned stmtId = 0;
9025 for (block = comp->fgFirstBB; block != nullptr; block = block->bbNext)
9027 for (GenTreeStmt* stmt = block->firstStmt(); stmt; stmt = stmt->gtNextStmt)
9041 BasicBlock* dFindBlock(unsigned bbNum)
9043 Compiler* comp = JitTls::GetCompiler();
9044 BasicBlock* block = nullptr;
9047 for (block = comp->fgFirstBB; block != nullptr; block = block->bbNext)
9049 if (block->bbNum == bbNum)
9059 /*****************************************************************************
9061 * COMPlus_JitDumpIR support - dump out function in linear IR form
9064 void cFuncIR(Compiler* comp)
9068 printf("Method %s::%s, hsh=0x%x\n", comp->info.compClassName, comp->info.compMethodName,
9069 comp->info.compMethodHash());
9073 for (block = comp->fgFirstBB; block != nullptr; block = block->bbNext)
9075 cBlockIR(comp, block);
9079 /*****************************************************************************
9081 * COMPlus_JitDumpIR support - dump out the format specifiers from COMPlus_JitDumpIRFormat
9086 Compiler* comp = JitTls::GetCompiler();
9088 if (comp->dumpIRFormat != nullptr)
9090 printf("COMPlus_JitDumpIRFormat=%ls", comp->dumpIRFormat);
9094 /*****************************************************************************
9096 * COMPlus_JitDumpIR support - dump out function in linear IR form
9101 cFuncIR(JitTls::GetCompiler());
9104 /*****************************************************************************
9106 * COMPlus_JitDumpIR support - dump out loop in linear IR form
9109 void cLoopIR(Compiler* comp, Compiler::LoopDsc* loop)
9111 BasicBlock* blockHead = loop->lpHead;
9112 BasicBlock* blockFirst = loop->lpFirst;
9113 BasicBlock* blockTop = loop->lpTop;
9114 BasicBlock* blockEntry = loop->lpEntry;
9115 BasicBlock* blockBottom = loop->lpBottom;
9116 BasicBlock* blockExit = loop->lpExit;
9117 BasicBlock* blockLast = blockBottom->bbNext;
9122 printf("HEAD BB%02u\n", blockHead->bbNum);
9123 printf("FIRST BB%02u\n", blockFirst->bbNum);
9124 printf("TOP BB%02u\n", blockTop->bbNum);
9125 printf("ENTRY BB%02u\n", blockEntry->bbNum);
9126 if (loop->lpExitCnt == 1)
9128 printf("EXIT BB%02u\n", blockExit->bbNum);
9132 printf("EXITS %u", loop->lpExitCnt);
9134 printf("BOTTOM BB%02u\n", blockBottom->bbNum);
9137 cBlockIR(comp, blockHead);
9138 for (block = blockFirst; ((block != nullptr) && (block != blockLast)); block = block->bbNext)
9140 cBlockIR(comp, block);
9144 /*****************************************************************************
9146 * COMPlus_JitDumpIR support - dump out loop in linear IR form
9149 void dLoopIR(Compiler::LoopDsc* loop)
9151 cLoopIR(JitTls::GetCompiler(), loop);
9154 /*****************************************************************************
9156 * COMPlus_JitDumpIR support - dump out loop (given loop number) in linear IR form
9159 void dLoopNumIR(unsigned loopNum)
9161 Compiler* comp = JitTls::GetCompiler();
9163 if (loopNum >= comp->optLoopCount)
9165 printf("loopNum %u out of range\n");
9169 Compiler::LoopDsc* loop = &comp->optLoopTable[loopNum];
9170 cLoopIR(JitTls::GetCompiler(), loop);
9173 /*****************************************************************************
9175 * COMPlus_JitDumpIR support - dump spaces to specified tab stop
9178 int dTabStopIR(int curr, int tabstop)
9182 if (tabstop <= curr)
9184 chars += printf(" ");
9187 for (int i = curr; i < tabstop; i++)
9189 chars += printf(" ");
9195 void cNodeIR(Compiler* comp, GenTree* tree);
9197 /*****************************************************************************
9199 * COMPlus_JitDumpIR support - dump out block in linear IR form
9202 void cBlockIR(Compiler* comp, BasicBlock* block)
9204 bool noStmts = comp->dumpIRNoStmts;
9205 bool trees = comp->dumpIRTrees;
9207 if (comp->dumpIRBlockHeaders)
9209 block->dspBlockHeader(comp);
9213 printf("BB%02u:\n", block->bbNum);
9218 if (!block->IsLIR())
9220 for (GenTreeStmt* stmt = block->firstStmt(); stmt; stmt = stmt->gtNextStmt)
9222 // Print current stmt.
9228 printf("=====================================================================\n");
9231 if (comp->compRationalIRForm)
9235 foreach_treenode_execution_order(tree, stmt)
9237 cNodeIR(comp, tree);
9242 cTreeIR(comp, stmt);
9245 if (!noStmts && !trees)
9253 for (GenTree* node = block->bbTreeList; node != nullptr; node = node->gtNext)
9255 cNodeIR(comp, node);
9261 chars += dTabStopIR(chars, COLUMN_OPCODE);
9263 chars += printf(" ");
9264 switch (block->bbJumpKind)
9266 case BBJ_EHFINALLYRET:
9267 chars += printf("BRANCH(EHFINALLYRET)");
9270 case BBJ_EHFILTERRET:
9271 chars += printf("BRANCH(EHFILTERRET)");
9274 case BBJ_EHCATCHRET:
9275 chars += printf("BRANCH(EHCATCHRETURN)");
9276 chars += dTabStopIR(chars, COLUMN_OPERANDS);
9277 chars += printf(" BB%02u", block->bbJumpDest->bbNum);
9281 chars += printf("BRANCH(THROW)");
9285 chars += printf("BRANCH(RETURN)");
9289 // For fall-through blocks
9290 chars += printf("BRANCH(NONE)");
9294 chars += printf("BRANCH(ALWAYS)");
9295 chars += dTabStopIR(chars, COLUMN_OPERANDS);
9296 chars += printf(" BB%02u", block->bbJumpDest->bbNum);
9297 if (block->bbFlags & BBF_KEEP_BBJ_ALWAYS)
9299 chars += dTabStopIR(chars, COLUMN_KINDS);
9300 chars += printf("; [KEEP_BBJ_ALWAYS]");
9305 chars += printf("BRANCH(LEAVE)");
9306 chars += dTabStopIR(chars, COLUMN_OPERANDS);
9307 chars += printf(" BB%02u", block->bbJumpDest->bbNum);
9310 case BBJ_CALLFINALLY:
9311 chars += printf("BRANCH(CALLFINALLY)");
9312 chars += dTabStopIR(chars, COLUMN_OPERANDS);
9313 chars += printf(" BB%02u", block->bbJumpDest->bbNum);
9317 chars += printf("BRANCH(COND)");
9318 chars += dTabStopIR(chars, COLUMN_OPERANDS);
9319 chars += printf(" BB%02u", block->bbJumpDest->bbNum);
9323 chars += printf("BRANCH(SWITCH)");
9324 chars += dTabStopIR(chars, COLUMN_OPERANDS);
9327 jumpCnt = block->bbJumpSwt->bbsCount;
9328 BasicBlock** jumpTab;
9329 jumpTab = block->bbJumpSwt->bbsDstTab;
9332 chars += printf("%c BB%02u", (jumpTab == block->bbJumpSwt->bbsDstTab) ? ' ' : ',', (*jumpTab)->bbNum);
9333 } while (++jumpTab, --jumpCnt);
9342 if (block->bbNext != nullptr)
9348 /*****************************************************************************
9350 * COMPlus_JitDumpIR support - dump out block in linear IR form
9353 void dBlockIR(BasicBlock* block)
9355 cBlockIR(JitTls::GetCompiler(), block);
9358 /*****************************************************************************
9360 * COMPlus_JitDumpIR support - dump out tree node type for linear IR form
9363 int cTreeTypeIR(Compiler* comp, GenTree* tree)
9367 var_types type = tree->TypeGet();
9369 const char* typeName = varTypeName(type);
9370 chars += printf(".%s", typeName);
9375 /*****************************************************************************
9377 * COMPlus_JitDumpIR support - dump out tree node type for linear IR form
9380 int dTreeTypeIR(GenTree* tree)
9382 int chars = cTreeTypeIR(JitTls::GetCompiler(), tree);
9387 /*****************************************************************************
9389 * COMPlus_JitDumpIR support - dump out tree node kind for linear IR form
9392 int cTreeKindsIR(Compiler* comp, GenTree* tree)
9396 unsigned kind = tree->OperKind();
9398 chars += printf("kinds=");
9399 if (kind == GTK_SPECIAL)
9401 chars += printf("[SPECIAL]");
9403 if (kind & GTK_CONST)
9405 chars += printf("[CONST]");
9407 if (kind & GTK_LEAF)
9409 chars += printf("[LEAF]");
9411 if (kind & GTK_UNOP)
9413 chars += printf("[UNOP]");
9415 if (kind & GTK_BINOP)
9417 chars += printf("[BINOP]");
9419 if (kind & GTK_LOGOP)
9421 chars += printf("[LOGOP]");
9423 #ifdef LEGACY_BACKEND
9424 if (kind & GTK_ASGOP)
9426 chars += printf("[ASGOP]");
9429 if (kind & GTK_COMMUTE)
9431 chars += printf("[COMMUTE]");
9433 if (kind & GTK_EXOP)
9435 chars += printf("[EXOP]");
9437 if (kind & GTK_LOCAL)
9439 chars += printf("[LOCAL]");
9441 if (kind & GTK_SMPOP)
9443 chars += printf("[SMPOP]");
9449 /*****************************************************************************
9451 * COMPlus_JitDumpIR support - dump out tree node kind for linear IR form
9454 int dTreeKindsIR(GenTree* tree)
9456 int chars = cTreeKindsIR(JitTls::GetCompiler(), tree);
9461 /*****************************************************************************
9463 * COMPlus_JitDumpIR support - dump out tree node flags for linear IR form
9466 int cTreeFlagsIR(Compiler* comp, GenTree* tree)
9470 if (tree->gtFlags != 0)
9472 chars += printf("flags=");
9475 CLANG_FORMAT_COMMENT_ANCHOR;
9478 #if SMALL_TREE_NODES
9479 if (comp->dumpIRNodes)
9481 if (tree->gtDebugFlags & GTF_DEBUG_NODE_LARGE)
9483 chars += printf("[NODE_LARGE]");
9485 if (tree->gtDebugFlags & GTF_DEBUG_NODE_SMALL)
9487 chars += printf("[NODE_SMALL]");
9490 #endif // SMALL_TREE_NODES
9491 if (tree->gtDebugFlags & GTF_DEBUG_NODE_MORPHED)
9493 chars += printf("[MORPHED]");
9495 #endif // defined(DEBUG)
9497 if (tree->gtFlags & GTF_COLON_COND)
9499 chars += printf("[COLON_COND]");
9504 genTreeOps op = tree->OperGet();
9509 case GT_LCL_VAR_ADDR:
9511 case GT_LCL_FLD_ADDR:
9512 case GT_STORE_LCL_FLD:
9513 case GT_STORE_LCL_VAR:
9516 if (tree->gtFlags & GTF_VAR_DEF)
9518 chars += printf("[VAR_DEF]");
9520 if (tree->gtFlags & GTF_VAR_USEASG)
9522 chars += printf("[VAR_USEASG]");
9524 if (tree->gtFlags & GTF_VAR_CAST)
9526 chars += printf("[VAR_CAST]");
9528 if (tree->gtFlags & GTF_VAR_ITERATOR)
9530 chars += printf("[VAR_ITERATOR]");
9532 if (tree->gtFlags & GTF_VAR_CLONED)
9534 chars += printf("[VAR_CLONED]");
9536 if (tree->gtFlags & GTF_VAR_DEATH)
9538 chars += printf("[VAR_DEATH]");
9540 if (tree->gtFlags & GTF_VAR_ARR_INDEX)
9542 chars += printf("[VAR_ARR_INDEX]");
9545 if (tree->gtDebugFlags & GTF_DEBUG_VAR_CSE_REF)
9547 chars += printf("[VAR_CSE_REF]");
9550 if (op == GT_REG_VAR)
9552 if (tree->gtFlags & GTF_REG_BIRTH)
9554 chars += printf("[REG_BIRTH]");
9561 if (tree->gtFlags & GTF_NOP_DEATH)
9563 chars += printf("[NOP_DEATH]");
9572 if (tree->gtFlags & GTF_FLD_NULLCHECK)
9574 chars += printf("[FLD_NULLCHECK]");
9576 if (tree->gtFlags & GTF_FLD_VOLATILE)
9578 chars += printf("[FLD_VOLATILE]");
9584 if (tree->gtFlags & GTF_INX_REFARR_LAYOUT)
9586 chars += printf("[INX_REFARR_LAYOUT]");
9588 if (tree->gtFlags & GTF_INX_STRING_LAYOUT)
9590 chars += printf("[INX_STRING_LAYOUT]");
9594 if (tree->gtFlags & GTF_INX_RNGCHK)
9596 chars += printf("[INX_RNGCHK]");
9603 if (tree->gtFlags & GTF_IND_VOLATILE)
9605 chars += printf("[IND_VOLATILE]");
9607 if (tree->gtFlags & GTF_IND_TGTANYWHERE)
9609 chars += printf("[IND_TGTANYWHERE]");
9611 if (tree->gtFlags & GTF_IND_TLS_REF)
9613 chars += printf("[IND_TLS_REF]");
9615 if (tree->gtFlags & GTF_IND_ASG_LHS)
9617 chars += printf("[IND_ASG_LHS]");
9619 if (tree->gtFlags & GTF_IND_UNALIGNED)
9621 chars += printf("[IND_UNALIGNED]");
9623 if (tree->gtFlags & GTF_IND_INVARIANT)
9625 chars += printf("[IND_INVARIANT]");
9627 if (tree->gtFlags & GTF_IND_ARR_LEN)
9629 chars += printf("[IND_ARR_INDEX]");
9635 if (tree->gtFlags & GTF_CLS_VAR_ASG_LHS)
9637 chars += printf("[CLS_VAR_ASG_LHS]");
9643 if (tree->gtFlags & GTF_ADDR_ONSTACK)
9645 chars += printf("[ADDR_ONSTACK]");
9650 #if !defined(_TARGET_64BIT_) && !defined(LEGACY_BACKEND)
9654 if (tree->gtFlags & GTF_MUL_64RSLT)
9656 chars += printf("[64RSLT]");
9658 if (tree->gtFlags & GTF_ADDRMODE_NO_CSE)
9660 chars += printf("[ADDRMODE_NO_CSE]");
9666 if (tree->gtFlags & GTF_ADDRMODE_NO_CSE)
9668 chars += printf("[ADDRMODE_NO_CSE]");
9674 if (tree->gtFlags & GTF_ADDRMODE_NO_CSE)
9676 chars += printf("[ADDRMODE_NO_CSE]");
9683 #ifdef LEGACY_BACKEND
9684 if (tree->gtFlags & GTF_MOD_INT_RESULT)
9686 chars += printf("[MOD_INT_RESULT]");
9688 #endif // LEGACY_BACKEND
9699 if (tree->gtFlags & GTF_RELOP_NAN_UN)
9701 chars += printf("[RELOP_NAN_UN]");
9703 if (tree->gtFlags & GTF_RELOP_JMP_USED)
9705 chars += printf("[RELOP_JMP_USED]");
9707 if (tree->gtFlags & GTF_RELOP_QMARK)
9709 chars += printf("[RELOP_QMARK]");
9715 if (tree->gtFlags & GTF_QMARK_CAST_INSTOF)
9717 chars += printf("[QMARK_CAST_INSTOF]");
9723 if (tree->gtFlags & GTF_BOX_VALUE)
9725 chars += printf("[BOX_VALUE]");
9732 unsigned handleKind = (tree->gtFlags & GTF_ICON_HDL_MASK);
9737 case GTF_ICON_SCOPE_HDL:
9739 chars += printf("[ICON_SCOPE_HDL]");
9742 case GTF_ICON_CLASS_HDL:
9744 chars += printf("[ICON_CLASS_HDL]");
9747 case GTF_ICON_METHOD_HDL:
9749 chars += printf("[ICON_METHOD_HDL]");
9752 case GTF_ICON_FIELD_HDL:
9754 chars += printf("[ICON_FIELD_HDL]");
9757 case GTF_ICON_STATIC_HDL:
9759 chars += printf("[ICON_STATIC_HDL]");
9762 case GTF_ICON_STR_HDL:
9764 chars += printf("[ICON_STR_HDL]");
9767 case GTF_ICON_PSTR_HDL:
9769 chars += printf("[ICON_PSTR_HDL]");
9772 case GTF_ICON_PTR_HDL:
9774 chars += printf("[ICON_PTR_HDL]");
9777 case GTF_ICON_VARG_HDL:
9779 chars += printf("[ICON_VARG_HDL]");
9782 case GTF_ICON_PINVKI_HDL:
9784 chars += printf("[ICON_PINVKI_HDL]");
9787 case GTF_ICON_TOKEN_HDL:
9789 chars += printf("[ICON_TOKEN_HDL]");
9792 case GTF_ICON_TLS_HDL:
9794 chars += printf("[ICON_TLD_HDL]");
9797 case GTF_ICON_FTN_ADDR:
9799 chars += printf("[ICON_FTN_ADDR]");
9802 case GTF_ICON_CIDMID_HDL:
9804 chars += printf("[ICON_CIDMID_HDL]");
9807 case GTF_ICON_BBC_PTR:
9809 chars += printf("[ICON_BBC_PTR]");
9812 case GTF_ICON_FIELD_OFF:
9814 chars += printf("[ICON_FIELD_OFF]");
9822 if (tree->AsObj()->HasGCPtr())
9824 chars += printf("[BLK_HASGCPTR]");
9831 case GT_STORE_DYN_BLK:
9833 if (tree->gtFlags & GTF_BLK_VOLATILE)
9835 chars += printf("[BLK_VOLATILE]");
9837 if (tree->AsBlk()->IsUnaligned())
9839 chars += printf("[BLK_UNALIGNED]");
9845 if (tree->gtFlags & GTF_CALL_UNMANAGED)
9847 chars += printf("[CALL_UNMANAGED]");
9849 if (tree->gtFlags & GTF_CALL_INLINE_CANDIDATE)
9851 chars += printf("[CALL_INLINE_CANDIDATE]");
9853 if (!tree->AsCall()->IsVirtual())
9855 chars += printf("[CALL_NONVIRT]");
9857 if (tree->AsCall()->IsVirtualVtable())
9859 chars += printf("[CALL_VIRT_VTABLE]");
9861 if (tree->AsCall()->IsVirtualStub())
9863 chars += printf("[CALL_VIRT_STUB]");
9865 if (tree->gtFlags & GTF_CALL_NULLCHECK)
9867 chars += printf("[CALL_NULLCHECK]");
9869 if (tree->gtFlags & GTF_CALL_POP_ARGS)
9871 chars += printf("[CALL_POP_ARGS]");
9873 if (tree->gtFlags & GTF_CALL_HOISTABLE)
9875 chars += printf("[CALL_HOISTABLE]");
9877 #ifdef LEGACY_BACKEND
9878 if (tree->gtFlags & GTF_CALL_REG_SAVE)
9880 chars += printf("[CALL_REG_SAVE]");
9882 #endif // LEGACY_BACKEND
9884 // More flags associated with calls.
9887 GenTreeCall* call = tree->AsCall();
9889 if (call->gtCallMoreFlags & GTF_CALL_M_EXPLICIT_TAILCALL)
9891 chars += printf("[CALL_M_EXPLICIT_TAILCALL]");
9893 if (call->gtCallMoreFlags & GTF_CALL_M_TAILCALL)
9895 chars += printf("[CALL_M_TAILCALL]");
9897 if (call->gtCallMoreFlags & GTF_CALL_M_VARARGS)
9899 chars += printf("[CALL_M_VARARGS]");
9901 if (call->gtCallMoreFlags & GTF_CALL_M_RETBUFFARG)
9903 chars += printf("[CALL_M_RETBUFFARG]");
9905 if (call->gtCallMoreFlags & GTF_CALL_M_DELEGATE_INV)
9907 chars += printf("[CALL_M_DELEGATE_INV]");
9909 if (call->gtCallMoreFlags & GTF_CALL_M_NOGCCHECK)
9911 chars += printf("[CALL_M_NOGCCHECK]");
9913 if (call->gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC)
9915 chars += printf("[CALL_M_SPECIAL_INTRINSIC]");
9918 if (call->IsUnmanaged())
9920 if (call->gtCallMoreFlags & GTF_CALL_M_UNMGD_THISCALL)
9922 chars += printf("[CALL_M_UNMGD_THISCALL]");
9925 else if (call->IsVirtualStub())
9927 if (call->gtCallMoreFlags & GTF_CALL_M_VIRTSTUB_REL_INDIRECT)
9929 chars += printf("[CALL_M_VIRTSTUB_REL_INDIRECT]");
9932 else if (!call->IsVirtual())
9934 if (call->gtCallMoreFlags & GTF_CALL_M_NONVIRT_SAME_THIS)
9936 chars += printf("[CALL_M_NONVIRT_SAME_THIS]");
9940 if (call->gtCallMoreFlags & GTF_CALL_M_FRAME_VAR_DEATH)
9942 chars += printf("[CALL_M_FRAME_VAR_DEATH]");
9944 #ifndef LEGACY_BACKEND
9945 if (call->gtCallMoreFlags & GTF_CALL_M_TAILCALL_VIA_HELPER)
9947 chars += printf("[CALL_M_TAILCALL_VIA_HELPER]");
9950 #if FEATURE_TAILCALL_OPT
9951 if (call->gtCallMoreFlags & GTF_CALL_M_IMPLICIT_TAILCALL)
9953 chars += printf("[CALL_M_IMPLICIT_TAILCALL]");
9956 if (call->gtCallMoreFlags & GTF_CALL_M_PINVOKE)
9958 chars += printf("[CALL_M_PINVOKE]");
9965 if (tree->gtFlags & GTF_STMT_CMPADD)
9967 chars += printf("[STMT_CMPADD]");
9969 if (tree->gtFlags & GTF_STMT_HAS_CSE)
9971 chars += printf("[STMT_HAS_CSE]");
9978 unsigned flags = (tree->gtFlags & (~(unsigned)(GTF_COMMON_MASK | GTF_OVERFLOW)));
9981 chars += printf("[%08X]", flags);
9989 if (tree->gtFlags & GTF_ASG)
9991 chars += printf("[ASG]");
9993 if (tree->gtFlags & GTF_CALL)
9995 chars += printf("[CALL]");
10003 #ifdef LEGACY_BACKEND
10007 if (tree->gtFlags & GTF_OVERFLOW)
10009 chars += printf("[OVERFLOW]");
10015 if (tree->gtFlags & GTF_EXCEPT)
10017 chars += printf("[EXCEPT]");
10019 if (tree->gtFlags & GTF_GLOB_REF)
10021 chars += printf("[GLOB_REF]");
10023 if (tree->gtFlags & GTF_ORDER_SIDEEFF)
10025 chars += printf("[ORDER_SIDEEFF]");
10027 if (tree->gtFlags & GTF_REVERSE_OPS)
10029 if (op != GT_LCL_VAR)
10031 chars += printf("[REVERSE_OPS]");
10034 if (tree->gtFlags & GTF_SPILLED)
10036 chars += printf("[SPILLED_OPER]");
10038 #if defined(LEGACY_BACKEND)
10041 chars += printf("[REG_VAL]");
10043 if (tree->gtFlags & GTF_SPILLED_OP2)
10045 chars += printf("[SPILLED_OP2]");
10047 if (tree->gtFlags & GTF_ZSF_SET)
10049 chars += printf("[ZSF_SET]");
10052 #if FEATURE_SET_FLAGS
10053 if (tree->gtFlags & GTF_SET_FLAGS)
10055 if ((op != GT_IND) && (op != GT_STOREIND))
10057 chars += printf("[ZSF_SET_FLAGS]");
10061 if (tree->gtFlags & GTF_IND_NONFAULTING)
10063 if (tree->OperIsIndirOrArrLength())
10065 chars += printf("[IND_NONFAULTING]");
10068 if (tree->gtFlags & GTF_MAKE_CSE)
10070 chars += printf("[MAKE_CSE]");
10072 if (tree->gtFlags & GTF_DONT_CSE)
10074 chars += printf("[DONT_CSE]");
10076 if (tree->gtFlags & GTF_BOOLEAN)
10078 chars += printf("[BOOLEAN]");
10080 #if CPU_HAS_BYTE_REGS && defined(LEGACY_BACKEND)
10081 if (tree->gtFlags & GTF_SMALL_OK)
10083 chars += printf("[SMALL_OK]");
10086 if (tree->gtFlags & GTF_UNSIGNED)
10088 chars += printf("[SMALL_UNSIGNED]");
10090 if (tree->gtFlags & GTF_LATE_ARG)
10092 chars += printf("[SMALL_LATE_ARG]");
10094 if (tree->gtFlags & GTF_SPILL)
10096 chars += printf("[SPILL]");
10098 if (tree->gtFlags & GTF_REUSE_REG_VAL)
10100 if (op == GT_CNS_INT)
10102 chars += printf("[REUSE_REG_VAL]");
10110 /*****************************************************************************
10112 * COMPlus_JitDumpIR support - dump out tree node flags for linear IR form
10115 int dTreeFlagsIR(GenTree* tree)
10117 int chars = cTreeFlagsIR(JitTls::GetCompiler(), tree);
10122 /*****************************************************************************
10124 * COMPlus_JitDumpIR support - dump out SSA number on tree node for linear IR form
10127 int cSsaNumIR(Compiler* comp, GenTree* tree)
10131 if (tree->gtLclVarCommon.HasSsaName())
10133 if (tree->gtFlags & GTF_VAR_USEASG)
10135 assert(tree->gtFlags & GTF_VAR_DEF);
10136 chars += printf("<u:%d><d:%d>", tree->gtLclVarCommon.gtSsaNum, comp->GetSsaNumForLocalVarDef(tree));
10140 chars += printf("<%s:%d>", (tree->gtFlags & GTF_VAR_DEF) ? "d" : "u", tree->gtLclVarCommon.gtSsaNum);
10147 /*****************************************************************************
10149 * COMPlus_JitDumpIR support - dump out SSA number on tree node for linear IR form
10152 int dSsaNumIR(GenTree* tree)
10154 int chars = cSsaNumIR(JitTls::GetCompiler(), tree);
10159 /*****************************************************************************
10161 * COMPlus_JitDumpIR support - dump out Value Number on tree node for linear IR form
10164 int cValNumIR(Compiler* comp, GenTree* tree)
10168 if (tree->gtVNPair.GetLiberal() != ValueNumStore::NoVN)
10170 assert(tree->gtVNPair.GetConservative() != ValueNumStore::NoVN);
10171 ValueNumPair vnp = tree->gtVNPair;
10173 if (vnp.BothEqual())
10175 chars += printf("<v:");
10176 vn = vnp.GetLiberal();
10177 chars += printf(STR_VN "%x", vn);
10178 if (ValueNumStore::isReservedVN(vn))
10180 chars += printf("R");
10182 chars += printf(">");
10186 vn = vnp.GetLiberal();
10187 chars += printf("<v:");
10188 chars += printf(STR_VN "%x", vn);
10189 if (ValueNumStore::isReservedVN(vn))
10191 chars += printf("R");
10193 chars += printf(",");
10194 vn = vnp.GetConservative();
10195 chars += printf(STR_VN "%x", vn);
10196 if (ValueNumStore::isReservedVN(vn))
10198 chars += printf("R");
10200 chars += printf(">");
10207 /*****************************************************************************
10209 * COMPlus_JitDumpIR support - dump out Value Number on tree node for linear IR form
10212 int dValNumIR(GenTree* tree)
10214 int chars = cValNumIR(JitTls::GetCompiler(), tree);
10219 /*****************************************************************************
10221 * COMPlus_JitDumpIR support - dump out tree leaf node for linear IR form
10224 int cLeafIR(Compiler* comp, GenTree* tree)
10227 genTreeOps op = tree->OperGet();
10228 const char* ilKind = nullptr;
10229 const char* ilName = nullptr;
10230 unsigned ilNum = 0;
10231 unsigned lclNum = 0;
10232 bool hasSsa = false;
10239 case GT_LCL_VAR_ADDR:
10240 case GT_STORE_LCL_VAR:
10243 lclNum = tree->gtLclVarCommon.gtLclNum;
10244 comp->gtGetLclVarNameInfo(lclNum, &ilKind, &ilName, &ilNum);
10245 if (ilName != nullptr)
10247 chars += printf("%s", ilName);
10251 LclVarDsc* varDsc = comp->lvaTable + lclNum;
10252 chars += printf("%s%d", ilKind, ilNum);
10253 if (comp->dumpIRLocals)
10255 chars += printf("(V%02u", lclNum);
10256 if (varDsc->lvTracked)
10258 chars += printf(":T%02u", varDsc->lvVarIndex);
10260 if (comp->dumpIRRegs)
10262 if (varDsc->lvRegister)
10264 if (isRegPairType(varDsc->TypeGet()))
10266 chars += printf(":%s:%s",
10267 getRegName(varDsc->lvOtherReg), // hi32
10268 getRegName(varDsc->lvRegNum)); // lo32
10272 chars += printf(":%s", getRegName(varDsc->lvRegNum));
10277 switch (tree->GetRegTag())
10279 case GenTree::GT_REGTAG_REG:
10280 chars += printf(":%s", comp->compRegVarName(tree->gtRegNum));
10282 #if CPU_LONG_USES_REGPAIR
10283 case GenTree::GT_REGTAG_REGPAIR:
10284 chars += printf(":%s", comp->compRegPairName(tree->gtRegPair));
10292 chars += printf(")");
10294 else if (comp->dumpIRRegs)
10296 if (varDsc->lvRegister)
10298 chars += printf("(");
10299 if (isRegPairType(varDsc->TypeGet()))
10301 chars += printf("%s:%s",
10302 getRegName(varDsc->lvOtherReg), // hi32
10303 getRegName(varDsc->lvRegNum)); // lo32
10307 chars += printf("%s", getRegName(varDsc->lvRegNum));
10309 chars += printf(")");
10313 switch (tree->GetRegTag())
10315 case GenTree::GT_REGTAG_REG:
10316 chars += printf("(%s)", comp->compRegVarName(tree->gtRegNum));
10318 #if CPU_LONG_USES_REGPAIR
10319 case GenTree::GT_REGTAG_REGPAIR:
10320 chars += printf("(%s)", comp->compRegPairName(tree->gtRegPair));
10330 if (op == GT_REG_VAR)
10332 if (isFloatRegType(tree->gtType))
10334 assert(tree->gtRegVar.gtRegNum == tree->gtRegNum);
10335 chars += printf("(FPV%u)", tree->gtRegNum);
10339 chars += printf("(%s)", comp->compRegVarName(tree->gtRegVar.gtRegNum));
10347 case GT_LCL_FLD_ADDR:
10348 case GT_STORE_LCL_FLD:
10350 lclNum = tree->gtLclVarCommon.gtLclNum;
10351 comp->gtGetLclVarNameInfo(lclNum, &ilKind, &ilName, &ilNum);
10352 if (ilName != nullptr)
10354 chars += printf("%s+%u", ilName, tree->gtLclFld.gtLclOffs);
10358 chars += printf("%s%d+%u", ilKind, ilNum, tree->gtLclFld.gtLclOffs);
10359 LclVarDsc* varDsc = comp->lvaTable + lclNum;
10360 if (comp->dumpIRLocals)
10362 chars += printf("(V%02u", lclNum);
10363 if (varDsc->lvTracked)
10365 chars += printf(":T%02u", varDsc->lvVarIndex);
10367 if (comp->dumpIRRegs)
10369 if (varDsc->lvRegister)
10371 if (isRegPairType(varDsc->TypeGet()))
10373 chars += printf(":%s:%s",
10374 getRegName(varDsc->lvOtherReg), // hi32
10375 getRegName(varDsc->lvRegNum)); // lo32
10379 chars += printf(":%s", getRegName(varDsc->lvRegNum));
10384 switch (tree->GetRegTag())
10386 case GenTree::GT_REGTAG_REG:
10387 chars += printf(":%s", comp->compRegVarName(tree->gtRegNum));
10389 #if CPU_LONG_USES_REGPAIR
10390 case GenTree::GT_REGTAG_REGPAIR:
10391 chars += printf(":%s", comp->compRegPairName(tree->gtRegPair));
10399 chars += printf(")");
10401 else if (comp->dumpIRRegs)
10403 if (varDsc->lvRegister)
10405 chars += printf("(");
10406 if (isRegPairType(varDsc->TypeGet()))
10408 chars += printf("%s:%s",
10409 getRegName(varDsc->lvOtherReg), // hi32
10410 getRegName(varDsc->lvRegNum)); // lo32
10414 chars += printf("%s", getRegName(varDsc->lvRegNum));
10416 chars += printf(")");
10420 switch (tree->GetRegTag())
10422 case GenTree::GT_REGTAG_REG:
10423 chars += printf("(%s)", comp->compRegVarName(tree->gtRegNum));
10425 #if CPU_LONG_USES_REGPAIR
10426 case GenTree::GT_REGTAG_REGPAIR:
10427 chars += printf("(%s)", comp->compRegPairName(tree->gtRegPair));
10437 // TODO: We probably want to expand field sequence.
10438 // gtDispFieldSeq(tree->gtLclFld.gtFieldSeq);
10445 if (tree->IsIconHandle())
10448 // TODO: Commented out because sometimes the CLR throws
10449 // and exception when asking the names of some handles.
10450 // Need to investigate.
10452 const char* className;
10453 const char* fieldName;
10454 const char* methodName;
10455 const wchar_t* str;
10457 switch (tree->GetIconHandleFlag())
10460 case GTF_ICON_SCOPE_HDL:
10462 chars += printf("SCOPE(?)");
10465 case GTF_ICON_CLASS_HDL:
10467 className = comp->eeGetClassName((CORINFO_CLASS_HANDLE)tree->gtIntCon.gtIconVal);
10468 chars += printf("CLASS(%s)", className);
10471 case GTF_ICON_METHOD_HDL:
10473 methodName = comp->eeGetMethodName((CORINFO_METHOD_HANDLE)tree->gtIntCon.gtIconVal,
10475 chars += printf("METHOD(%s.%s)", className, methodName);
10478 case GTF_ICON_FIELD_HDL:
10480 fieldName = comp->eeGetFieldName((CORINFO_FIELD_HANDLE)tree->gtIntCon.gtIconVal,
10482 chars += printf("FIELD(%s.%s) ", className, fieldName);
10485 case GTF_ICON_STATIC_HDL:
10487 fieldName = comp->eeGetFieldName((CORINFO_FIELD_HANDLE)tree->gtIntCon.gtIconVal,
10489 chars += printf("STATIC_FIELD(%s.%s)", className, fieldName);
10492 case GTF_ICON_STR_HDL:
10494 str = comp->eeGetCPString(tree->gtIntCon.gtIconVal);
10495 chars += printf("\"%S\"", str);
10498 case GTF_ICON_PSTR_HDL:
10500 chars += printf("PSTR(?)");
10503 case GTF_ICON_PTR_HDL:
10505 chars += printf("PTR(?)");
10508 case GTF_ICON_VARG_HDL:
10510 chars += printf("VARARG(?)");
10513 case GTF_ICON_PINVKI_HDL:
10515 chars += printf("PINVOKE(?)");
10518 case GTF_ICON_TOKEN_HDL:
10520 chars += printf("TOKEN(%08X)", tree->gtIntCon.gtIconVal);
10523 case GTF_ICON_TLS_HDL:
10525 chars += printf("TLS(?)");
10528 case GTF_ICON_FTN_ADDR:
10530 chars += printf("FTN(?)");
10533 case GTF_ICON_CIDMID_HDL:
10535 chars += printf("CIDMID(?)");
10538 case GTF_ICON_BBC_PTR:
10540 chars += printf("BBC(?)");
10545 chars += printf("HANDLE(?)");
10549 #ifdef _TARGET_64BIT_
10550 if ((tree->gtIntCon.gtIconVal & 0xFFFFFFFF00000000LL) != 0)
10552 chars += printf("HANDLE(0x%llx)", dspPtr(tree->gtIntCon.gtIconVal));
10557 chars += printf("HANDLE(0x%0x)", dspPtr(tree->gtIntCon.gtIconVal));
10563 if (tree->TypeGet() == TYP_REF)
10565 assert(tree->gtIntCon.gtIconVal == 0);
10566 chars += printf("null");
10568 #ifdef _TARGET_64BIT_
10569 else if ((tree->gtIntCon.gtIconVal & 0xFFFFFFFF00000000LL) != 0)
10571 chars += printf("0x%llx", tree->gtIntCon.gtIconVal);
10576 chars += printf("%ld(0x%x)", tree->gtIntCon.gtIconVal, tree->gtIntCon.gtIconVal);
10583 chars += printf("CONST(LONG)");
10588 chars += printf("CONST(DOUBLE)");
10593 chars += printf("CONST(STR)");
10599 const char* methodName;
10600 const char* className;
10602 methodName = comp->eeGetMethodName((CORINFO_METHOD_HANDLE)tree->gtVal.gtVal1, &className);
10603 chars += printf(" %s.%s", className, methodName);
10608 case GT_START_NONGC:
10611 case GT_MEMORYBARRIER:
10613 case GT_PINVOKE_PROLOG:
10614 #ifndef LEGACY_BACKEND
10622 chars += printf("t%d", tree->gtRetExpr.gtInlineCandidate->gtTreeID);
10627 chars += printf("%s", getRegName(tree->gtPhysReg.gtSrcReg, varTypeIsFloating(tree)));
10632 if (tree->gtLabel.gtLabBB)
10634 chars += printf("BB%02u", tree->gtLabel.gtLabBB->bbNum);
10638 chars += printf("BB?");
10644 if (tree->gtStmt.gtStmtILoffsx == BAD_IL_OFFSET)
10646 chars += printf("?");
10650 chars += printf("0x%x", jitGetILoffs(tree->gtStmt.gtStmtILoffsx));
10655 case GT_CLS_VAR_ADDR:
10658 if (tree->OperIsLeaf())
10660 chars += printf("<leaf nyi: %s>", tree->OpName(tree->OperGet()));
10663 chars += printf("t%d", tree->gtTreeID);
10667 if (comp->dumpIRTypes)
10669 chars += cTreeTypeIR(comp, tree);
10671 if (comp->dumpIRValnums)
10673 chars += cValNumIR(comp, tree);
10675 if (hasSsa && comp->dumpIRSsa)
10677 chars += cSsaNumIR(comp, tree);
10683 /*****************************************************************************
10685 * COMPlus_JitDumpIR support - dump out tree leaf node for linear IR form
10688 int dLeafIR(GenTree* tree)
10690 int chars = cLeafIR(JitTls::GetCompiler(), tree);
10695 /*****************************************************************************
10697 * COMPlus_JitDumpIR support - dump out tree indir node for linear IR form
10700 int cIndirIR(Compiler* comp, GenTree* tree)
10702 assert(tree->gtOper == GT_IND);
10707 chars += printf("[");
10708 child = tree->GetChild(0);
10709 chars += cLeafIR(comp, child);
10710 chars += printf("]");
10715 /*****************************************************************************
10717 * COMPlus_JitDumpIR support - dump out tree indir node for linear IR form
10720 int dIndirIR(GenTree* tree)
10722 int chars = cIndirIR(JitTls::GetCompiler(), tree);
10727 /*****************************************************************************
10729 * COMPlus_JitDumpIR support - dump out tree operand node for linear IR form
10732 int cOperandIR(Compiler* comp, GenTree* operand)
10736 if (operand == nullptr)
10738 chars += printf("t?");
10742 bool dumpTypes = comp->dumpIRTypes;
10743 bool dumpValnums = comp->dumpIRValnums;
10744 bool foldIndirs = comp->dumpIRDataflow;
10745 bool foldLeafs = comp->dumpIRNoLeafs;
10746 bool foldCommas = comp->dumpIRDataflow;
10747 bool dumpDataflow = comp->dumpIRDataflow;
10748 bool foldLists = comp->dumpIRNoLists;
10749 bool dumpRegs = comp->dumpIRRegs;
10751 genTreeOps op = operand->OperGet();
10753 if (foldLeafs && operand->OperIsLeaf())
10755 if ((op == GT_ARGPLACE) && foldLists)
10759 chars += cLeafIR(comp, operand);
10761 else if (dumpDataflow && (operand->OperIsAssignment() || (op == GT_STORE_LCL_VAR) || (op == GT_STORE_LCL_FLD)))
10763 operand = operand->GetChild(0);
10764 chars += cOperandIR(comp, operand);
10766 else if ((op == GT_INDEX) && foldIndirs)
10768 chars += printf("[t%d]", operand->gtTreeID);
10771 chars += cTreeTypeIR(comp, operand);
10775 chars += cValNumIR(comp, operand);
10778 else if ((op == GT_IND) && foldIndirs)
10780 chars += cIndirIR(comp, operand);
10783 chars += cTreeTypeIR(comp, operand);
10787 chars += cValNumIR(comp, operand);
10790 else if ((op == GT_COMMA) && foldCommas)
10792 operand = operand->GetChild(1);
10793 chars += cOperandIR(comp, operand);
10795 else if ((op == GT_LIST) && foldLists)
10797 GenTree* list = operand;
10798 unsigned childCount = list->NumChildren();
10800 operand = list->GetChild(0);
10801 int operandChars = cOperandIR(comp, operand);
10802 chars += operandChars;
10803 if (childCount > 1)
10805 if (operandChars > 0)
10807 chars += printf(", ");
10809 operand = list->GetChild(1);
10810 if (operand->gtOper == GT_LIST)
10812 chars += cListIR(comp, operand);
10816 chars += cOperandIR(comp, operand);
10822 chars += printf("t%d", operand->gtTreeID);
10825 regNumber regNum = operand->GetReg();
10826 if (regNum != REG_NA)
10828 chars += printf("(%s)", getRegName(regNum));
10833 chars += cTreeTypeIR(comp, operand);
10837 chars += cValNumIR(comp, operand);
10844 /*****************************************************************************
10846 * COMPlus_JitDumpIR support - dump out tree operand node for linear IR form
10849 int dOperandIR(GenTree* operand)
10851 int chars = cOperandIR(JitTls::GetCompiler(), operand);
10856 /*****************************************************************************
10858 * COMPlus_JitDumpIR support - dump out tree list of nodes for linear IR form
10861 int cListIR(Compiler* comp, GenTree* list)
10866 assert(list->gtOper == GT_LIST);
10869 unsigned childCount;
10871 childCount = list->NumChildren();
10872 assert(childCount == 1 || childCount == 2);
10875 for (unsigned childIndex = 0; childIndex < childCount; childIndex++)
10877 if ((childIndex > 0) && (operandChars > 0))
10879 chars += printf(", ");
10882 child = list->GetChild(childIndex);
10883 operandChars = cOperandIR(comp, child);
10884 chars += operandChars;
10890 /*****************************************************************************
10892 * COMPlus_JitDumpIR support - dump out tree list of nodes for linear IR form
10895 int dListIR(GenTree* list)
10897 int chars = cListIR(JitTls::GetCompiler(), list);
10902 /*****************************************************************************
10904 * COMPlus_JitDumpIR support - dump out tree dependencies based on comma nodes for linear IR form
10907 int cDependsIR(Compiler* comp, GenTree* comma, bool* first)
10911 assert(comma->gtOper == GT_COMMA);
10915 child = comma->GetChild(0);
10916 if (child->gtOper == GT_COMMA)
10918 chars += cDependsIR(comp, child, first);
10924 chars += printf(", ");
10926 chars += printf("t%d", child->gtTreeID);
10930 child = comma->GetChild(1);
10931 if (child->gtOper == GT_COMMA)
10933 chars += cDependsIR(comp, child, first);
10939 /*****************************************************************************
10941 * COMPlus_JitDumpIR support - dump out tree dependencies based on comma nodes for linear IR form
10944 int dDependsIR(GenTree* comma)
10949 chars = cDependsIR(JitTls::GetCompiler(), comma, &first);
10954 /*****************************************************************************
10956 * COMPlus_JitDumpIR support - dump out tree node in linear IR form
10959 void cNodeIR(Compiler* comp, GenTree* tree)
10961 bool foldLeafs = comp->dumpIRNoLeafs;
10962 bool foldIndirs = comp->dumpIRDataflow;
10963 bool foldLists = comp->dumpIRNoLists;
10964 bool dataflowView = comp->dumpIRDataflow;
10965 bool dumpTypes = comp->dumpIRTypes;
10966 bool dumpValnums = comp->dumpIRValnums;
10967 bool noStmts = comp->dumpIRNoStmts;
10968 genTreeOps op = tree->OperGet();
10969 unsigned childCount = tree->NumChildren();
10972 // What are we skipping?
10974 if (tree->OperIsLeaf())
10981 else if (op == GT_IND)
10988 else if (op == GT_LIST)
10995 else if (op == GT_STMT)
11001 child = tree->GetChild(0);
11002 if (child->gtOper != GT_COMMA)
11013 else if (op == GT_COMMA)
11021 bool nodeIsValue = tree->IsValue();
11023 // Dump tree id or dataflow destination.
11027 // if (comp->compRationalIRForm)
11029 // chars += printf("R");
11032 chars += printf(" ");
11033 if (dataflowView && tree->OperIsAssignment())
11035 child = tree->GetChild(0);
11036 chars += cOperandIR(comp, child);
11038 else if (dataflowView && ((op == GT_STORE_LCL_VAR) || (op == GT_STORE_LCL_FLD)))
11040 chars += cLeafIR(comp, tree);
11042 else if (dataflowView && (op == GT_STOREIND))
11044 child = tree->GetChild(0);
11045 chars += printf("[");
11046 chars += cOperandIR(comp, child);
11047 chars += printf("]");
11050 chars += cTreeTypeIR(comp, tree);
11054 chars += cValNumIR(comp, tree);
11057 else if (nodeIsValue)
11059 chars += printf("t%d", tree->gtTreeID);
11060 if (comp->dumpIRRegs)
11062 regNumber regNum = tree->GetReg();
11063 if (regNum != REG_NA)
11065 chars += printf("(%s)", getRegName(regNum));
11070 chars += cTreeTypeIR(comp, tree);
11074 chars += cValNumIR(comp, tree);
11078 // Dump opcode and tree ID if need in dataflow view.
11080 chars += dTabStopIR(chars, COLUMN_OPCODE);
11081 const char* opName = tree->OpName(op);
11082 chars += printf(" %c %s", nodeIsValue ? '=' : ' ', opName);
11086 if (tree->OperIsAssignment() || (op == GT_STORE_LCL_VAR) || (op == GT_STORE_LCL_FLD) || (op == GT_STOREIND))
11088 chars += printf("(t%d)", tree->gtTreeID);
11092 // Dump modifiers for opcodes to help with readability
11096 GenTreeCall* call = tree->AsCall();
11098 if (call->gtCallType == CT_USER_FUNC)
11100 if (call->IsVirtualStub())
11102 chars += printf(":VS");
11104 else if (call->IsVirtualVtable())
11106 chars += printf(":VT");
11108 else if (call->IsVirtual())
11110 chars += printf(":V");
11113 else if (call->gtCallType == CT_HELPER)
11115 chars += printf(":H");
11117 else if (call->gtCallType == CT_INDIRECT)
11119 chars += printf(":I");
11121 else if (call->IsUnmanaged())
11123 chars += printf(":U");
11127 if (call->IsVirtualStub())
11129 chars += printf(":XVS");
11131 else if (call->IsVirtualVtable())
11133 chars += printf(":XVT");
11137 chars += printf(":?");
11141 if (call->IsUnmanaged())
11143 if (call->gtCallMoreFlags & GTF_CALL_M_UNMGD_THISCALL)
11145 chars += printf(":T");
11149 if (tree->gtFlags & GTF_CALL_NULLCHECK)
11151 chars += printf(":N");
11154 else if (op == GT_INTRINSIC)
11156 CorInfoIntrinsics intrin = tree->gtIntrinsic.gtIntrinsicId;
11158 chars += printf(":");
11161 case CORINFO_INTRINSIC_Sin:
11162 chars += printf("Sin");
11164 case CORINFO_INTRINSIC_Cos:
11165 chars += printf("Cos");
11167 case CORINFO_INTRINSIC_Cbrt:
11168 chars += printf("Cbrt");
11170 case CORINFO_INTRINSIC_Sqrt:
11171 chars += printf("Sqrt");
11173 case CORINFO_INTRINSIC_Cosh:
11174 chars += printf("Cosh");
11176 case CORINFO_INTRINSIC_Sinh:
11177 chars += printf("Sinh");
11179 case CORINFO_INTRINSIC_Tan:
11180 chars += printf("Tan");
11182 case CORINFO_INTRINSIC_Tanh:
11183 chars += printf("Tanh");
11185 case CORINFO_INTRINSIC_Asin:
11186 chars += printf("Asin");
11188 case CORINFO_INTRINSIC_Asinh:
11189 chars += printf("Asinh");
11191 case CORINFO_INTRINSIC_Acos:
11192 chars += printf("Acos");
11194 case CORINFO_INTRINSIC_Acosh:
11195 chars += printf("Acosh");
11197 case CORINFO_INTRINSIC_Atan:
11198 chars += printf("Atan");
11200 case CORINFO_INTRINSIC_Atan2:
11201 chars += printf("Atan2");
11203 case CORINFO_INTRINSIC_Atanh:
11204 chars += printf("Atanh");
11206 case CORINFO_INTRINSIC_Log10:
11207 chars += printf("Log10");
11209 case CORINFO_INTRINSIC_Pow:
11210 chars += printf("Pow");
11212 case CORINFO_INTRINSIC_Exp:
11213 chars += printf("Exp");
11215 case CORINFO_INTRINSIC_Ceiling:
11216 chars += printf("Ceiling");
11218 case CORINFO_INTRINSIC_Floor:
11219 chars += printf("Floor");
11222 chars += printf("unknown(%d)", intrin);
11229 chars += dTabStopIR(chars, COLUMN_OPERANDS);
11231 // Dump operator specific fields as operands
11240 const char* className = nullptr;
11241 const char* fieldName = comp->eeGetFieldName(tree->gtField.gtFldHnd, &className);
11243 chars += printf(" %s.%s", className, fieldName);
11249 if (tree->gtCall.gtCallType != CT_INDIRECT)
11251 const char* methodName;
11252 const char* className;
11254 methodName = comp->eeGetMethodName(tree->gtCall.gtCallMethHnd, &className);
11256 chars += printf(" %s.%s", className, methodName);
11260 case GT_STORE_LCL_VAR:
11261 case GT_STORE_LCL_FLD:
11265 chars += printf(" ");
11266 chars += cLeafIR(comp, tree);
11272 GenTreeAddrMode* lea = tree->AsAddrMode();
11273 GenTree* base = lea->Base();
11274 GenTree* index = lea->Index();
11275 unsigned scale = lea->gtScale;
11276 int offset = lea->Offset();
11278 chars += printf(" [");
11279 if (base != nullptr)
11281 chars += cOperandIR(comp, base);
11283 if (index != nullptr)
11285 if (base != nullptr)
11287 chars += printf("+");
11289 chars += cOperandIR(comp, index);
11292 chars += printf("*%u", scale);
11295 if ((offset != 0) || ((base == nullptr) && (index == nullptr)))
11297 if ((base != nullptr) || (index != nullptr))
11299 chars += printf("+");
11301 chars += printf("%d", offset);
11303 chars += printf("]");
11309 if (tree->OperIsLeaf())
11311 chars += printf(" ");
11312 chars += cLeafIR(comp, tree);
11314 else if (op == GT_LEA)
11316 // Already dumped it above.
11318 else if (op == GT_PHI)
11320 if (tree->gtOp.gtOp1 != nullptr)
11323 for (GenTreeArgList* args = tree->gtOp.gtOp1->AsArgList(); args != nullptr; args = args->Rest())
11325 child = args->Current();
11328 chars += printf(",");
11331 chars += printf(" ");
11332 chars += cOperandIR(comp, child);
11338 bool hasComma = false;
11340 int operandChars = 0;
11341 for (unsigned childIndex = 0; childIndex < childCount; childIndex++)
11343 child = tree->GetChild(childIndex);
11344 if (child == nullptr)
11349 if (child->gtOper == GT_COMMA)
11354 if (dataflowView && (childIndex == 0))
11356 if ((op == GT_ASG) || (op == GT_STOREIND))
11364 chars += printf(",");
11367 bool isList = (child->gtOper == GT_LIST);
11368 if (!isList || !foldLists)
11370 if (foldLeafs && (child->gtOper == GT_ARGPLACE))
11374 chars += printf(" ");
11375 operandChars = cOperandIR(comp, child);
11376 chars += operandChars;
11377 if (operandChars > 0)
11385 chars += printf(" ");
11386 operandChars = cOperandIR(comp, child);
11387 chars += operandChars;
11388 if (operandChars > 0)
11395 if (dataflowView && hasComma)
11397 chars += printf(", DEPS(");
11399 for (unsigned childIndex = 0; childIndex < childCount; childIndex++)
11401 child = tree->GetChild(childIndex);
11402 if (child->gtOper == GT_COMMA)
11404 chars += cDependsIR(comp, child, &first);
11407 chars += printf(")");
11411 // Dump kinds, flags, costs
11413 if (comp->dumpIRKinds || comp->dumpIRFlags || comp->dumpIRCosts)
11415 chars += dTabStopIR(chars, COLUMN_KINDS);
11416 chars += printf(";");
11417 if (comp->dumpIRKinds)
11419 chars += printf(" ");
11420 chars += cTreeKindsIR(comp, tree);
11422 if (comp->dumpIRFlags && (tree->gtFlags != 0))
11424 if (comp->dumpIRKinds)
11426 chars += dTabStopIR(chars, COLUMN_FLAGS);
11430 chars += printf(" ");
11432 chars += cTreeFlagsIR(comp, tree);
11434 if (comp->dumpIRCosts && (tree->gtCostsInitialized))
11436 chars += printf(" CostEx=%d, CostSz=%d", tree->GetCostEx(), tree->GetCostSz());
11443 /*****************************************************************************
11445 * COMPlus_JitDumpIR support - dump out tree in linear IR form
11448 void cTreeIR(Compiler* comp, GenTree* tree)
11450 bool foldLeafs = comp->dumpIRNoLeafs;
11451 bool foldIndirs = comp->dumpIRDataflow;
11452 bool foldLists = comp->dumpIRNoLists;
11453 bool dataflowView = comp->dumpIRDataflow;
11454 bool dumpTypes = comp->dumpIRTypes;
11455 bool dumpValnums = comp->dumpIRValnums;
11456 bool noStmts = comp->dumpIRNoStmts;
11457 genTreeOps op = tree->OperGet();
11458 unsigned childCount = tree->NumChildren();
11461 // Recurse and dump trees that this node depends on.
11463 if (tree->OperIsLeaf())
11466 else if (tree->OperIsBinary() && tree->IsReverseOp())
11468 child = tree->GetChild(1);
11469 cTreeIR(comp, child);
11470 child = tree->GetChild(0);
11471 cTreeIR(comp, child);
11473 else if (op == GT_PHI)
11479 assert(!tree->IsReverseOp());
11480 for (unsigned childIndex = 0; childIndex < childCount; childIndex++)
11482 child = tree->GetChild(childIndex);
11483 if (child != nullptr)
11485 cTreeIR(comp, child);
11490 cNodeIR(comp, tree);
11493 /*****************************************************************************
11495 * COMPlus_JitDumpIR support - dump out tree in linear IR form
11498 void dTreeIR(GenTree* tree)
11500 cTreeIR(JitTls::GetCompiler(), tree);
11505 #if VARSET_COUNTOPS
11507 BitSetSupport::BitSetOpCounter Compiler::m_varsetOpCounter("VarSetOpCounts.log");
11509 #if ALLVARSET_COUNTOPS
11511 BitSetSupport::BitSetOpCounter Compiler::m_allvarsetOpCounter("AllVarSetOpCounts.log");
11515 HelperCallProperties Compiler::s_helperCallProperties;
11517 /*****************************************************************************/
11518 /*****************************************************************************/
11520 //------------------------------------------------------------------------
11522 // Given some tree node return does it need all GC refs to be spilled from
11523 // callee save registers.
11526 // tree - the tree for which we ask about gc refs.
11529 // true - tree kills GC refs on callee save registers
11530 // false - tree doesn't affect GC refs on callee save registers
11531 bool Compiler::killGCRefs(GenTree* tree)
11533 if (tree->IsCall())
11535 GenTreeCall* call = tree->AsCall();
11536 if (call->IsUnmanaged())
11541 if (call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_JIT_PINVOKE_BEGIN))
11543 assert(opts.ShouldUsePInvokeHelpers());