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
11 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
12 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
15 #ifndef _COMPILER_HPP_
16 #define _COMPILER_HPP_
18 #include "emit.h" // for emitter::emitAddLabel
22 #include "compilerbitsettraits.hpp"
25 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
26 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
28 XX Miscellaneous utility functions. Some of these are defined in Utils.cpp XX
30 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
31 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
34 /*****************************************************************************/
35 /*****************************************************************************/
37 inline bool getInlinePInvokeEnabled()
40 return JitConfig.JitPInvokeEnabled() && !JitConfig.StressCOMCall();
46 inline bool getInlinePInvokeCheckEnabled()
49 return JitConfig.JitPInvokeCheckEnabled() != 0;
55 // Enforce float narrowing for buggy compilers (notably preWhidbey VC)
56 inline float forceCastToFloat(double d)
58 Volatile<float> f = (float)d;
62 // Enforce UInt32 narrowing for buggy compilers (notably Whidbey Beta 2 LKG)
63 inline UINT32 forceCastToUInt32(double d)
65 Volatile<UINT32> u = (UINT32)d;
71 ROUND_NEVER = 0, // Never round
72 ROUND_CMP_CONST = 1, // Round values compared against constants
73 ROUND_CMP = 2, // Round comparands and return values
74 ROUND_ALWAYS = 3, // Round always
77 DEFAULT_ROUND_LEVEL = ROUND_NEVER
80 inline RoundLevel getRoundFloatLevel()
83 return (RoundLevel)JitConfig.JitRoundFloat();
85 return DEFAULT_ROUND_LEVEL;
89 /*****************************************************************************/
90 /*****************************************************************************
92 * Return the lowest bit that is set
96 inline T genFindLowestBit(T value)
98 return (value & (0 - value));
101 /*****************************************************************************/
102 /*****************************************************************************
104 * Return the highest bit that is set (that is, a mask that includes just the highest bit).
105 * TODO-ARM64-Throughput: we should convert these to use the _BitScanReverse() / _BitScanReverse64()
106 * compiler intrinsics, but our CRT header file intrin.h doesn't define these for ARM64 yet.
109 inline unsigned int genFindHighestBit(unsigned int mask)
112 unsigned int bit = 1U << ((sizeof(unsigned int) * 8) - 1); // start looking at the top
113 while ((bit & mask) == 0)
120 inline unsigned __int64 genFindHighestBit(unsigned __int64 mask)
123 unsigned __int64 bit = 1ULL << ((sizeof(unsigned __int64) * 8) - 1); // start looking at the top
124 while ((bit & mask) == 0)
132 // TODO-ARM64-Cleanup: These should probably be the implementation, when intrin.h is updated for ARM64
134 unsigned int genFindHighestBit(unsigned int mask)
138 _BitScanReverse(&index, mask);
143 unsigned __int64 genFindHighestBit(unsigned __int64 mask)
147 _BitScanReverse64(&index, mask);
152 /*****************************************************************************
154 * Return true if the given 64-bit value has exactly zero or one bits set.
157 template <typename T>
158 inline BOOL genMaxOneBit(T value)
160 return (value & (value - 1)) == 0;
163 /*****************************************************************************
165 * Return true if the given 32-bit value has exactly zero or one bits set.
168 inline BOOL genMaxOneBit(unsigned value)
170 return (value & (value - 1)) == 0;
173 /*****************************************************************************
175 * Return true if the given 64-bit value has exactly one bit set.
178 template <typename T>
179 inline bool genExactlyOneBit(T value)
181 return ((value != 0) && genMaxOneBit(value));
184 /*****************************************************************************
186 * Return true if the given 32-bit value has exactly zero or one bits set.
189 inline bool genExactlyOneBit(unsigned value)
191 return ((value != 0) && genMaxOneBit(value));
194 /*****************************************************************************
196 * Given a value that has exactly one bit set, return the position of that
197 * bit, in other words return the logarithm in base 2 of the given value.
199 inline unsigned genLog2(unsigned value)
201 return BitPosition(value);
204 // Given an unsigned 64-bit value, returns the lower 32-bits in unsigned format
206 inline unsigned ulo32(unsigned __int64 value)
208 return static_cast<unsigned>(value);
211 // Given an unsigned 64-bit value, returns the upper 32-bits in unsigned format
213 inline unsigned uhi32(unsigned __int64 value)
215 return static_cast<unsigned>(value >> 32);
218 /*****************************************************************************
220 * Given a value that has exactly one bit set, return the position of that
221 * bit, in other words return the logarithm in base 2 of the given value.
224 inline unsigned genLog2(unsigned __int64 value)
226 unsigned lo32 = ulo32(value);
227 unsigned hi32 = uhi32(value);
232 return genLog2(lo32);
236 return genLog2(hi32) + 32;
240 /*****************************************************************************
242 * Return the lowest bit that is set in the given register mask.
245 inline regMaskTP genFindLowestReg(regMaskTP value)
247 return (regMaskTP)genFindLowestBit(value);
250 /*****************************************************************************
252 * A rather simple routine that counts the number of bits in a given number.
255 template <typename T>
256 inline unsigned genCountBits(T bits)
263 bits -= genFindLowestBit(bits);
269 /*****************************************************************************
271 * Given 3 masks value, end, start, returns the bits of value between start
272 * and end (exclusive).
274 * value[bitNum(end) - 1, bitNum(start) + 1]
277 inline unsigned __int64 BitsBetween(unsigned __int64 value, unsigned __int64 end, unsigned __int64 start)
281 assert((start & (start - 1)) == 0);
282 assert((end & (end - 1)) == 0);
284 return value & ~((start - 1) | start) & // Ones to the left of set bit in the start mask.
285 (end - 1); // Ones to the right of set bit in the end mask.
288 /*****************************************************************************/
290 inline bool jitIsScaleIndexMul(size_t val)
305 // Returns "tree" iff "val" is a valid addressing mode scale shift amount on
306 // the target architecture.
307 inline bool jitIsScaleIndexShift(ssize_t val)
309 // It happens that this is the right test for all our current targets: x86, x64 and ARM.
310 // This test would become target-dependent if we added a new target with a different constraint.
311 return 0 < val && val < 4;
314 /*****************************************************************************
315 * Returns true if value is between [start..end).
316 * The comparison is inclusive of start, exclusive of end.
320 inline bool Compiler::jitIsBetween(unsigned value, unsigned start, unsigned end)
322 return start <= value && value < end;
325 /*****************************************************************************
326 * Returns true if value is between [start..end].
327 * The comparison is inclusive of both start and end.
331 inline bool Compiler::jitIsBetweenInclusive(unsigned value, unsigned start, unsigned end)
333 return start <= value && value <= end;
336 /******************************************************************************************
337 * Return the EH descriptor for the given region index.
339 inline EHblkDsc* Compiler::ehGetDsc(unsigned regionIndex)
341 assert(regionIndex < compHndBBtabCount);
342 return &compHndBBtab[regionIndex];
345 /******************************************************************************************
346 * Return the EH descriptor index of the enclosing try, for the given region index.
348 inline unsigned Compiler::ehGetEnclosingTryIndex(unsigned regionIndex)
350 return ehGetDsc(regionIndex)->ebdEnclosingTryIndex;
353 /******************************************************************************************
354 * Return the EH descriptor index of the enclosing handler, for the given region index.
356 inline unsigned Compiler::ehGetEnclosingHndIndex(unsigned regionIndex)
358 return ehGetDsc(regionIndex)->ebdEnclosingHndIndex;
361 /******************************************************************************************
362 * Return the EH index given a region descriptor.
364 inline unsigned Compiler::ehGetIndex(EHblkDsc* ehDsc)
366 assert(compHndBBtab <= ehDsc && ehDsc < compHndBBtab + compHndBBtabCount);
367 return (unsigned)(ehDsc - compHndBBtab);
370 /******************************************************************************************
371 * Return the EH descriptor for the most nested 'try' region this BasicBlock is a member of
372 * (or nullptr if this block is not in a 'try' region).
374 inline EHblkDsc* Compiler::ehGetBlockTryDsc(BasicBlock* block)
376 if (!block->hasTryIndex())
381 return ehGetDsc(block->getTryIndex());
384 /******************************************************************************************
385 * Return the EH descriptor for the most nested filter or handler region this BasicBlock is a member of
386 * (or nullptr if this block is not in a filter or handler region).
388 inline EHblkDsc* Compiler::ehGetBlockHndDsc(BasicBlock* block)
390 if (!block->hasHndIndex())
395 return ehGetDsc(block->getHndIndex());
398 #if FEATURE_EH_FUNCLETS
400 /*****************************************************************************
401 * Get the FuncInfoDsc for the funclet we are currently generating code for.
402 * This is only valid during codegen.
405 inline FuncInfoDsc* Compiler::funCurrentFunc()
407 return funGetFunc(compCurrFuncIdx);
410 /*****************************************************************************
411 * Change which funclet we are currently generating code for.
412 * This is only valid after funclets are created.
415 inline void Compiler::funSetCurrentFunc(unsigned funcIdx)
417 assert(fgFuncletsCreated);
418 assert(FitsIn<unsigned short>(funcIdx));
419 noway_assert(funcIdx < compFuncInfoCount);
420 compCurrFuncIdx = (unsigned short)funcIdx;
423 /*****************************************************************************
424 * Get the FuncInfoDsc for the given funclet.
425 * This is only valid after funclets are created.
428 inline FuncInfoDsc* Compiler::funGetFunc(unsigned funcIdx)
430 assert(fgFuncletsCreated);
431 assert(funcIdx < compFuncInfoCount);
432 return &compFuncInfos[funcIdx];
435 /*****************************************************************************
436 * Get the funcIdx for the EH funclet that begins with block.
437 * This is only valid after funclets are created.
438 * It is only valid for blocks marked with BBF_FUNCLET_BEG because
439 * otherwise we would have to do a more expensive check to determine
440 * if this should return the filter funclet or the filter handler funclet.
443 inline unsigned Compiler::funGetFuncIdx(BasicBlock* block)
445 assert(fgFuncletsCreated);
446 assert(block->bbFlags & BBF_FUNCLET_BEG);
448 EHblkDsc* eh = ehGetDsc(block->getHndIndex());
449 unsigned int funcIdx = eh->ebdFuncIndex;
450 if (eh->ebdHndBeg != block)
452 // If this is a filter EH clause, but we want the funclet
453 // for the filter (not the filter handler), it is the previous one
454 noway_assert(eh->HasFilter());
455 noway_assert(eh->ebdFilter == block);
456 assert(funGetFunc(funcIdx)->funKind == FUNC_HANDLER);
457 assert(funGetFunc(funcIdx)->funEHIndex == funGetFunc(funcIdx - 1)->funEHIndex);
458 assert(funGetFunc(funcIdx - 1)->funKind == FUNC_FILTER);
465 #else // !FEATURE_EH_FUNCLETS
467 /*****************************************************************************
468 * Get the FuncInfoDsc for the funclet we are currently generating code for.
469 * This is only valid during codegen. For non-funclet platforms, this is
470 * always the root function.
473 inline FuncInfoDsc* Compiler::funCurrentFunc()
475 return &compFuncInfoRoot;
478 /*****************************************************************************
479 * Change which funclet we are currently generating code for.
480 * This is only valid after funclets are created.
483 inline void Compiler::funSetCurrentFunc(unsigned funcIdx)
485 assert(funcIdx == 0);
488 /*****************************************************************************
489 * Get the FuncInfoDsc for the givven funclet.
490 * This is only valid after funclets are created.
493 inline FuncInfoDsc* Compiler::funGetFunc(unsigned funcIdx)
495 assert(funcIdx == 0);
496 return &compFuncInfoRoot;
499 /*****************************************************************************
500 * No funclets, so always 0.
503 inline unsigned Compiler::funGetFuncIdx(BasicBlock* block)
508 #endif // !FEATURE_EH_FUNCLETS
510 //------------------------------------------------------------------------------
511 // genRegNumFromMask : Maps a single register mask to a register number.
514 // mask - the register mask
517 // The number of the register contained in the mask.
520 // The mask contains one and only one register.
522 inline regNumber genRegNumFromMask(regMaskTP mask)
524 assert(mask != 0); // Must have one bit set, so can't have a mask of zero
526 /* Convert the mask to a register number */
528 regNumber regNum = (regNumber)genLog2(mask);
530 /* Make sure we got it right */
532 assert(genRegMask(regNum) == mask);
537 //------------------------------------------------------------------------------
538 // genSmallTypeCanRepresentValue: Checks if a value can be represented by a given small type.
541 // value - the value to check
545 // True if the value is representable, false otherwise.
547 inline bool genSmallTypeCanRepresentValue(var_types type, ssize_t value)
553 return FitsIn<UINT8>(value);
555 return FitsIn<INT8>(value);
557 return FitsIn<UINT16>(value);
559 return FitsIn<INT16>(value);
565 /*****************************************************************************
567 * Return the size in bytes of the given type.
570 extern const BYTE genTypeSizes[TYP_COUNT];
573 inline unsigned genTypeSize(T type)
575 assert((unsigned)TypeGet(type) < _countof(genTypeSizes));
577 return genTypeSizes[TypeGet(type)];
580 /*****************************************************************************
582 * Return the "stack slot count" of the given type.
583 * returns 1 for 32-bit types and 2 for 64-bit types.
586 extern const BYTE genTypeStSzs[TYP_COUNT];
588 inline unsigned genTypeStSz(var_types type)
590 assert((unsigned)type < _countof(genTypeStSzs));
592 return genTypeStSzs[type];
595 /*****************************************************************************
597 * Return the number of registers required to hold a value of the given type.
600 /*****************************************************************************
602 * The following function maps a 'precise' type to an actual type as seen
603 * by the VM (for example, 'byte' maps to 'int').
606 extern const BYTE genActualTypes[TYP_COUNT];
608 inline var_types genActualType(var_types type)
610 /* Spot check to make certain the table is in synch with the enum */
612 assert(genActualTypes[TYP_DOUBLE] == TYP_DOUBLE);
613 assert(genActualTypes[TYP_REF] == TYP_REF);
615 assert((unsigned)type < sizeof(genActualTypes));
616 return (var_types)genActualTypes[type];
619 /*****************************************************************************/
621 inline var_types genUnsignedType(var_types type)
623 /* Force signed types into corresponding unsigned type */
646 /*****************************************************************************/
648 inline var_types genSignedType(var_types type)
650 /* Force non-small unsigned type into corresponding signed type */
651 /* Note that we leave the small types alone */
668 /*****************************************************************************
669 * Can this type be passed as a parameter in a register?
672 inline bool isRegParamType(var_types type)
674 #if defined(_TARGET_X86_)
675 return (type <= TYP_INT || type == TYP_REF || type == TYP_BYREF);
676 #else // !_TARGET_X86_
678 #endif // !_TARGET_X86_
681 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
682 /*****************************************************************************/
683 // Returns true if 'type' is a struct that can be enregistered for call args
684 // or can be returned by value in multiple registers.
685 // if 'type' is not a struct the return value will be false.
688 // type - the basic jit var_type for the item being queried
689 // typeClass - the handle for the struct when 'type' is TYP_STRUCT
690 // typeSize - Out param (if non-null) is updated with the size of 'type'.
691 // forReturn - this is true when we asking about a GT_RETURN context;
692 // this is false when we are asking about an argument context
694 inline bool Compiler::VarTypeIsMultiByteAndCanEnreg(var_types type,
695 CORINFO_CLASS_HANDLE typeClass,
702 if (varTypeIsStruct(type))
704 size = info.compCompHnd->getClassSize(typeClass);
707 structPassingKind howToReturnStruct;
708 type = getReturnTypeForStruct(typeClass, &howToReturnStruct, size);
712 structPassingKind howToPassStruct;
713 type = getArgTypeForStruct(typeClass, &howToPassStruct, size);
715 if (type != TYP_UNKNOWN)
722 size = genTypeSize(type);
725 if (typeSize != nullptr)
732 #endif //_TARGET_AMD64_ || _TARGET_ARM64_
734 /*****************************************************************************/
738 inline const char* varTypeGCstring(var_types type)
753 /*****************************************************************************/
755 const char* varTypeName(var_types);
757 /*****************************************************************************
759 * Helpers to pull big-endian values out of a byte stream.
762 inline unsigned genGetU1(const BYTE* addr)
767 inline signed genGetI1(const BYTE* addr)
769 return (signed char)addr[0];
772 inline unsigned genGetU2(const BYTE* addr)
774 return (addr[0] << 8) | addr[1];
777 inline signed genGetI2(const BYTE* addr)
779 return (signed short)((addr[0] << 8) | addr[1]);
782 inline unsigned genGetU4(const BYTE* addr)
784 return (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3];
787 /*****************************************************************************/
788 // Helpers to pull little-endian values out of a byte stream.
790 inline unsigned __int8 getU1LittleEndian(const BYTE* ptr)
792 return *(UNALIGNED unsigned __int8*)ptr;
795 inline unsigned __int16 getU2LittleEndian(const BYTE* ptr)
797 return GET_UNALIGNED_VAL16(ptr);
800 inline unsigned __int32 getU4LittleEndian(const BYTE* ptr)
802 return GET_UNALIGNED_VAL32(ptr);
805 inline signed __int8 getI1LittleEndian(const BYTE* ptr)
807 return *(UNALIGNED signed __int8*)ptr;
810 inline signed __int16 getI2LittleEndian(const BYTE* ptr)
812 return GET_UNALIGNED_VAL16(ptr);
815 inline signed __int32 getI4LittleEndian(const BYTE* ptr)
817 return GET_UNALIGNED_VAL32(ptr);
820 inline signed __int64 getI8LittleEndian(const BYTE* ptr)
822 return GET_UNALIGNED_VAL64(ptr);
825 inline float getR4LittleEndian(const BYTE* ptr)
827 __int32 val = getI4LittleEndian(ptr);
828 return *(float*)&val;
831 inline double getR8LittleEndian(const BYTE* ptr)
833 __int64 val = getI8LittleEndian(ptr);
834 return *(double*)&val;
837 /*****************************************************************************
839 * Return the normalized index to use in the EXPSET_TP for the CSE with
840 * the given CSE index.
841 * Each GenTree has the following field:
842 * signed char gtCSEnum; // 0 or the CSE index (negated if def)
843 * So zero is reserved to mean this node is not a CSE
844 * and postive values indicate CSE uses and negative values indicate CSE defs.
845 * The caller of this method must pass a non-zero postive value.
846 * This precondition is checked by the assert on the first line of this method.
849 inline unsigned int genCSEnum2bit(unsigned index)
851 assert((index > 0) && (index <= EXPSET_SZ));
857 const char* genES2str(BitVecTraits* traits, EXPSET_TP set);
858 const char* refCntWtd2str(unsigned refCntWtd);
862 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
863 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
865 XX Inline functions XX
867 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
868 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
871 void* GenTree::operator new(size_t sz, Compiler* comp, genTreeOps oper)
874 size_t size = GenTree::s_gtNodeSizes[oper];
876 size_t size = TREE_NODE_SZ_LARGE;
879 #if MEASURE_NODE_SIZE
880 genNodeSizeStats.genTreeNodeCnt += 1;
881 genNodeSizeStats.genTreeNodeSize += size;
882 genNodeSizeStats.genTreeNodeActualSize += sz;
884 genNodeSizeStatsPerFunc.genTreeNodeCnt += 1;
885 genNodeSizeStatsPerFunc.genTreeNodeSize += size;
886 genNodeSizeStatsPerFunc.genTreeNodeActualSize += sz;
887 #endif // MEASURE_NODE_SIZE
890 return comp->compGetMem(size, CMK_ASTNode);
893 // GenTree constructor
894 inline GenTree::GenTree(genTreeOps oper, var_types type DEBUGARG(bool largeNode))
903 #ifdef LEGACY_BACKEND
905 #endif // LEGACY_BACKEND
908 #endif // FEATURE_ANYCSE
913 #if FEATURE_STACK_FP_X87
920 INDEBUG(gtRegTag = GT_REGTAG_NONE;)
922 INDEBUG(gtCostsInitialized = false;)
926 size_t size = GenTree::s_gtNodeSizes[oper];
927 if (size == TREE_NODE_SZ_SMALL && !largeNode)
929 gtDebugFlags |= GTF_DEBUG_NODE_SMALL;
931 else if (size == TREE_NODE_SZ_LARGE || largeNode)
933 gtDebugFlags |= GTF_DEBUG_NODE_LARGE;
937 assert(!"bogus node size");
943 InterlockedIncrement(&s_gtNodeCounts[oper]);
948 gtTreeID = JitTls::GetCompiler()->compGenTreeID++;
949 gtVNPair.SetBoth(ValueNumStore::NoVN);
950 gtRegTag = GT_REGTAG_NONE;
951 gtOperSave = GT_NONE;
955 /*****************************************************************************/
957 inline GenTreeStmt* Compiler::gtNewStmt(GenTree* expr, IL_OFFSETX offset)
959 /* NOTE - GT_STMT is now a small node in retail */
961 GenTreeStmt* stmt = new (this, GT_STMT) GenTreeStmt(expr, offset);
966 /*****************************************************************************/
968 inline GenTree* Compiler::gtNewOperNode(genTreeOps oper, var_types type, GenTree* op1, bool doSimplifications)
970 assert((GenTree::OperKind(oper) & (GTK_UNOP | GTK_BINOP)) != 0);
971 assert((GenTree::OperKind(oper) & GTK_EXOP) ==
972 0); // Can't use this to construct any types that extend unary/binary operator.
973 assert(op1 != nullptr || oper == GT_PHI || oper == GT_RETFILT || oper == GT_NOP ||
974 (oper == GT_RETURN && type == TYP_VOID));
976 if (doSimplifications)
978 // We do some simplifications here.
979 // If this gets to be too many, try a switch...
980 // TODO-Cleanup: With the factoring out of array bounds checks, it should not be the
981 // case that we need to check for the array index case here, but without this check
982 // we get failures (see for example jit\Directed\Languages\Python\test_methods_d.exe)
985 // IND(ADDR(IND(x)) == IND(x)
986 if (op1->gtOper == GT_ADDR)
988 if (op1->gtOp.gtOp1->gtOper == GT_IND && (op1->gtOp.gtOp1->gtFlags & GTF_IND_ARR_INDEX) == 0)
990 op1 = op1->gtOp.gtOp1->gtOp.gtOp1;
994 else if (oper == GT_ADDR)
996 // if "x" is not an array index, ADDR(IND(x)) == x
997 if (op1->gtOper == GT_IND && (op1->gtFlags & GTF_IND_ARR_INDEX) == 0)
999 return op1->gtOp.gtOp1;
1004 GenTree* node = new (this, oper) GenTreeOp(oper, type, op1, nullptr);
1007 // the GT_ADDR of a Local Variable implies GTF_ADDR_ONSTACK
1009 if ((oper == GT_ADDR) && (op1->OperGet() == GT_LCL_VAR))
1011 node->gtFlags |= GTF_ADDR_ONSTACK;
1017 // Returns an opcode that is of the largest node size in use.
1018 inline genTreeOps LargeOpOpcode()
1020 #if SMALL_TREE_NODES
1021 // Allocate a large node
1022 assert(GenTree::s_gtNodeSizes[GT_CALL] == TREE_NODE_SZ_LARGE);
1027 /******************************************************************************
1029 * Use to create nodes which may later be morphed to another (big) operator
1032 inline GenTree* Compiler::gtNewLargeOperNode(genTreeOps oper, var_types type, GenTree* op1, GenTree* op2)
1034 assert((GenTree::OperKind(oper) & (GTK_UNOP | GTK_BINOP)) != 0);
1035 assert((GenTree::OperKind(oper) & GTK_EXOP) ==
1036 0); // Can't use this to construct any types that extend unary/binary operator.
1037 #if SMALL_TREE_NODES
1038 // Allocate a large node
1040 assert(GenTree::s_gtNodeSizes[oper] == TREE_NODE_SZ_SMALL);
1042 GenTree* node = new (this, LargeOpOpcode()) GenTreeOp(oper, type, op1, op2 DEBUGARG(/*largeNode*/ true));
1044 GenTree* node = new (this, oper) GenTreeOp(oper, type, op1, op2);
1050 /*****************************************************************************
1052 * allocates a integer constant entry that represents a handle (something
1053 * that may need to be fixed up).
1056 inline GenTree* Compiler::gtNewIconHandleNode(size_t value, unsigned flags, FieldSeqNode* fields)
1059 assert((flags & (GTF_ICON_HDL_MASK | GTF_ICON_FIELD_OFF)) != 0);
1061 // Interpret "fields == NULL" as "not a field."
1062 if (fields == nullptr)
1064 fields = FieldSeqStore::NotAField();
1067 #if defined(LATE_DISASM)
1068 node = new (this, LargeOpOpcode()) GenTreeIntCon(TYP_I_IMPL, value, fields DEBUGARG(/*largeNode*/ true));
1070 node = new (this, GT_CNS_INT) GenTreeIntCon(TYP_I_IMPL, value, fields);
1072 node->gtFlags |= flags;
1076 /*****************************************************************************
1078 * It may not be allowed to embed HANDLEs directly into the JITed code (for eg,
1079 * as arguments to JIT helpers). Get a corresponding value that can be embedded.
1080 * These are versions for each specific type of HANDLE
1083 inline GenTree* Compiler::gtNewIconEmbScpHndNode(CORINFO_MODULE_HANDLE scpHnd)
1085 void *embedScpHnd, *pEmbedScpHnd;
1087 embedScpHnd = (void*)info.compCompHnd->embedModuleHandle(scpHnd, &pEmbedScpHnd);
1089 assert((!embedScpHnd) != (!pEmbedScpHnd));
1091 return gtNewIconEmbHndNode(embedScpHnd, pEmbedScpHnd, GTF_ICON_SCOPE_HDL, scpHnd);
1094 //-----------------------------------------------------------------------------
1096 inline GenTree* Compiler::gtNewIconEmbClsHndNode(CORINFO_CLASS_HANDLE clsHnd)
1098 void *embedClsHnd, *pEmbedClsHnd;
1100 embedClsHnd = (void*)info.compCompHnd->embedClassHandle(clsHnd, &pEmbedClsHnd);
1102 assert((!embedClsHnd) != (!pEmbedClsHnd));
1104 return gtNewIconEmbHndNode(embedClsHnd, pEmbedClsHnd, GTF_ICON_CLASS_HDL, clsHnd);
1107 //-----------------------------------------------------------------------------
1109 inline GenTree* Compiler::gtNewIconEmbMethHndNode(CORINFO_METHOD_HANDLE methHnd)
1111 void *embedMethHnd, *pEmbedMethHnd;
1113 embedMethHnd = (void*)info.compCompHnd->embedMethodHandle(methHnd, &pEmbedMethHnd);
1115 assert((!embedMethHnd) != (!pEmbedMethHnd));
1117 return gtNewIconEmbHndNode(embedMethHnd, pEmbedMethHnd, GTF_ICON_METHOD_HDL, methHnd);
1120 //-----------------------------------------------------------------------------
1122 inline GenTree* Compiler::gtNewIconEmbFldHndNode(CORINFO_FIELD_HANDLE fldHnd)
1124 void *embedFldHnd, *pEmbedFldHnd;
1126 embedFldHnd = (void*)info.compCompHnd->embedFieldHandle(fldHnd, &pEmbedFldHnd);
1128 assert((!embedFldHnd) != (!pEmbedFldHnd));
1130 return gtNewIconEmbHndNode(embedFldHnd, pEmbedFldHnd, GTF_ICON_FIELD_HDL, fldHnd);
1133 /*****************************************************************************/
1135 //------------------------------------------------------------------------------
1136 // gtNewHelperCallNode : Helper to create a call helper node.
1140 // helper - Call helper
1141 // type - Type of the node
1145 // New CT_HELPER node
1147 inline GenTreeCall* Compiler::gtNewHelperCallNode(unsigned helper, var_types type, GenTreeArgList* args)
1149 unsigned flags = s_helperCallProperties.NoThrow((CorInfoHelpFunc)helper) ? 0 : GTF_EXCEPT;
1150 GenTreeCall* result = gtNewCallNode(CT_HELPER, eeFindHelper(helper), type, args);
1151 result->gtFlags |= flags;
1154 // Helper calls are never candidates.
1156 result->gtInlineObservation = InlineObservation::CALLSITE_IS_CALL_TO_HELPER;
1162 //------------------------------------------------------------------------
1163 // gtNewAllocObjNode: A little helper to create an object allocation node.
1166 // helper - Value returned by ICorJitInfo::getNewHelper
1167 // clsHnd - Corresponding class handle
1168 // type - Tree return type (e.g. TYP_REF)
1169 // op1 - Node containing an address of VtablePtr
1172 // Returns GT_ALLOCOBJ node that will be later morphed into an
1173 // allocation helper call or local variable allocation on the stack.
1174 inline GenTree* Compiler::gtNewAllocObjNode(unsigned int helper,
1175 CORINFO_CLASS_HANDLE clsHnd,
1179 GenTree* node = new (this, GT_ALLOCOBJ) GenTreeAllocObj(type, helper, clsHnd, op1);
1183 //------------------------------------------------------------------------
1184 // gtNewRuntimeLookup: Helper to create a runtime lookup node
1187 // hnd - generic handle being looked up
1188 // hndTyp - type of the generic handle
1189 // tree - tree for the lookup
1192 // New GenTreeRuntimeLookup node.
1193 inline GenTree* Compiler::gtNewRuntimeLookup(CORINFO_GENERIC_HANDLE hnd, CorInfoGenericHandleType hndTyp, GenTree* tree)
1195 assert(tree != nullptr);
1196 GenTree* node = new (this, GT_RUNTIMELOOKUP) GenTreeRuntimeLookup(hnd, hndTyp, tree);
1200 /*****************************************************************************/
1202 inline GenTree* Compiler::gtNewCodeRef(BasicBlock* block)
1204 GenTree* node = new (this, GT_LABEL) GenTreeLabel(block);
1208 /*****************************************************************************
1210 * A little helper to create a data member reference node.
1213 inline GenTree* Compiler::gtNewFieldRef(
1214 var_types typ, CORINFO_FIELD_HANDLE fldHnd, GenTree* obj, DWORD offset, bool nullcheck)
1216 #if SMALL_TREE_NODES
1217 /* 'GT_FIELD' nodes may later get transformed into 'GT_IND' */
1219 assert(GenTree::s_gtNodeSizes[GT_IND] <= GenTree::s_gtNodeSizes[GT_FIELD]);
1220 GenTree* tree = new (this, GT_FIELD) GenTreeField(typ);
1222 GenTree* tree = new (this, GT_FIELD) GenTreeField(typ);
1224 tree->gtField.gtFldObj = obj;
1225 tree->gtField.gtFldHnd = fldHnd;
1226 tree->gtField.gtFldOffset = offset;
1228 #ifdef FEATURE_READYTORUN_COMPILER
1229 tree->gtField.gtFieldLookup.addr = nullptr;
1234 tree->gtFlags |= GTF_FLD_NULLCHECK;
1237 // If "obj" is the address of a local, note that a field of that struct local has been accessed.
1238 if (obj != nullptr && obj->OperGet() == GT_ADDR && varTypeIsStruct(obj->gtOp.gtOp1) &&
1239 obj->gtOp.gtOp1->OperGet() == GT_LCL_VAR)
1241 unsigned lclNum = obj->gtOp.gtOp1->gtLclVarCommon.gtLclNum;
1242 lvaTable[lclNum].lvFieldAccessed = 1;
1243 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
1244 // These structs are passed by reference; we should probably be able to treat these
1245 // as non-global refs, but downstream logic expects these to be marked this way.
1246 if (lvaTable[lclNum].lvIsParam)
1248 tree->gtFlags |= GTF_GLOB_REF;
1250 #endif // defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
1254 tree->gtFlags |= GTF_GLOB_REF;
1260 /*****************************************************************************
1262 * A little helper to create an array index node.
1265 inline GenTree* Compiler::gtNewIndexRef(var_types typ, GenTree* arrayOp, GenTree* indexOp)
1267 GenTreeIndex* gtIndx = new (this, GT_INDEX) GenTreeIndex(typ, arrayOp, indexOp, genTypeSize(typ));
1272 //------------------------------------------------------------------------------
1273 // gtNewArrLen : Helper to create an array length node.
1277 // typ - Type of the node
1278 // arrayOp - Array node
1279 // lenOffset - Offset of the length field
1282 // New GT_ARR_LENGTH node
1284 inline GenTreeArrLen* Compiler::gtNewArrLen(var_types typ, GenTree* arrayOp, int lenOffset)
1286 GenTreeArrLen* arrLen = new (this, GT_ARR_LENGTH) GenTreeArrLen(typ, arrayOp, lenOffset);
1287 static_assert_no_msg(GTF_ARRLEN_NONFAULTING == GTF_IND_NONFAULTING);
1288 arrLen->SetIndirExceptionFlags(this);
1292 //------------------------------------------------------------------------------
1293 // gtNewIndir : Helper to create an indirection node.
1296 // typ - Type of the node
1297 // addr - Address of the indirection
1302 inline GenTree* Compiler::gtNewIndir(var_types typ, GenTree* addr)
1304 GenTree* indir = gtNewOperNode(GT_IND, typ, addr);
1305 indir->SetIndirExceptionFlags(this);
1309 /*****************************************************************************
1311 * Create (and check for) a "nothing" node, i.e. a node that doesn't produce
1312 * any code. We currently use a "nop" node of type void for this purpose.
1315 inline GenTree* Compiler::gtNewNothingNode()
1317 return new (this, GT_NOP) GenTreeOp(GT_NOP, TYP_VOID);
1319 /*****************************************************************************/
1321 inline bool GenTree::IsNothingNode() const
1323 return (gtOper == GT_NOP && gtType == TYP_VOID);
1326 /*****************************************************************************
1328 * Change the given node to a NOP - May be later changed to a GT_COMMA
1330 *****************************************************************************/
1332 inline void GenTree::gtBashToNOP()
1337 gtOp.gtOp1 = gtOp.gtOp2 = nullptr;
1339 gtFlags &= ~(GTF_ALL_EFFECT | GTF_REVERSE_OPS);
1342 // return new arg placeholder node. Does not do anything but has a type associated
1343 // with it so we can keep track of register arguments in lists associated w/ call nodes
1345 inline GenTree* Compiler::gtNewArgPlaceHolderNode(var_types type, CORINFO_CLASS_HANDLE clsHnd)
1347 GenTree* node = new (this, GT_ARGPLACE) GenTreeArgPlace(type, clsHnd);
1351 /*****************************************************************************/
1353 inline GenTree* Compiler::gtUnusedValNode(GenTree* expr)
1355 return gtNewOperNode(GT_COMMA, TYP_VOID, expr, gtNewNothingNode());
1358 /*****************************************************************************
1360 * A wrapper for gtSetEvalOrder and gtComputeFPlvls
1361 * Necessary because the FP levels may need to be re-computed if we reverse
1365 inline void Compiler::gtSetStmtInfo(GenTree* stmt)
1367 assert(stmt->gtOper == GT_STMT);
1368 GenTree* expr = stmt->gtStmt.gtStmtExpr;
1370 #if FEATURE_STACK_FP_X87
1371 /* We will try to compute the FP stack level at each node */
1372 codeGen->genResetFPstkLevel();
1374 /* Sometimes we need to redo the FP level computation */
1375 gtFPstLvlRedo = false;
1376 #endif // FEATURE_STACK_FP_X87
1385 /* Recursively process the expression */
1387 gtSetEvalOrder(expr);
1389 // Set the statement to have the same costs as the top node of the tree.
1390 stmt->CopyCosts(expr);
1392 #if FEATURE_STACK_FP_X87
1393 /* Unused float values leave one operand on the stack */
1394 assert(codeGen->genGetFPstkLevel() == 0 || codeGen->genGetFPstkLevel() == 1);
1396 /* Do we need to recompute FP stack levels? */
1400 codeGen->genResetFPstkLevel();
1401 gtComputeFPlvls(expr);
1402 assert(codeGen->genGetFPstkLevel() == 0 || codeGen->genGetFPstkLevel() == 1);
1404 #endif // FEATURE_STACK_FP_X87
1407 #if FEATURE_STACK_FP_X87
1408 inline unsigned Compiler::gtSetEvalOrderAndRestoreFPstkLevel(GenTree* tree)
1410 unsigned FPlvlSave = codeGen->genFPstkLevel;
1411 unsigned result = gtSetEvalOrder(tree);
1412 codeGen->genFPstkLevel = FPlvlSave;
1416 #else // !FEATURE_STACK_FP_X87
1417 inline unsigned Compiler::gtSetEvalOrderAndRestoreFPstkLevel(GenTree* tree)
1419 return gtSetEvalOrder(tree);
1421 #endif // FEATURE_STACK_FP_X87
1423 /*****************************************************************************/
1424 #if SMALL_TREE_NODES
1425 /*****************************************************************************/
1427 inline void GenTree::SetOper(genTreeOps oper, ValueNumberUpdate vnUpdate)
1429 assert(((gtDebugFlags & GTF_DEBUG_NODE_SMALL) != 0) != ((gtDebugFlags & GTF_DEBUG_NODE_LARGE) != 0));
1431 /* Make sure the node isn't too small for the new operator */
1433 assert(GenTree::s_gtNodeSizes[gtOper] == TREE_NODE_SZ_SMALL ||
1434 GenTree::s_gtNodeSizes[gtOper] == TREE_NODE_SZ_LARGE);
1436 assert(GenTree::s_gtNodeSizes[oper] == TREE_NODE_SZ_SMALL || GenTree::s_gtNodeSizes[oper] == TREE_NODE_SZ_LARGE);
1437 assert(GenTree::s_gtNodeSizes[oper] == TREE_NODE_SZ_SMALL || (gtDebugFlags & GTF_DEBUG_NODE_LARGE));
1439 #if defined(_HOST_64BIT_) && !defined(_TARGET_64BIT_)
1440 if (gtOper == GT_CNS_LNG && oper == GT_CNS_INT)
1442 // When casting from LONG to INT, we need to force cast of the value,
1443 // if the host architecture represents INT and LONG with the same data size.
1444 gtLngCon.gtLconVal = (INT64)(INT32)gtLngCon.gtLconVal;
1446 #endif // defined(_HOST_64BIT_) && !defined(_TARGET_64BIT_)
1451 // Maintain the invariant that unary operators always have NULL gtOp2.
1452 // If we ever start explicitly allocating GenTreeUnOp nodes, we wouldn't be
1453 // able to do that (but if we did, we'd have to have a check in gtOp -- perhaps
1455 if (OperKind(oper) == GTK_UNOP)
1457 gtOp.gtOp2 = nullptr;
1461 #if DEBUGGABLE_GENTREE
1462 // Until we eliminate SetOper/ChangeOper, we also change the vtable of the node, so that
1463 // it shows up correctly in the debugger.
1464 SetVtableForOper(oper);
1465 #endif // DEBUGGABLE_GENTREE
1467 if (oper == GT_CNS_INT)
1469 gtIntCon.gtFieldSeq = nullptr;
1472 #if !defined(LEGACY_BACKEND) && defined(_TARGET_ARM_)
1473 if (oper == GT_MUL_LONG)
1475 // We sometimes bash GT_MUL to GT_MUL_LONG, which converts it from GenTreeOp to GenTreeMultiRegOp.
1476 gtMultiRegOp.gtOtherReg = REG_NA;
1477 gtMultiRegOp.ClearOtherRegFlags();
1481 if (vnUpdate == CLEAR_VN)
1483 // Clear the ValueNum field as well.
1484 gtVNPair.SetBoth(ValueNumStore::NoVN);
1488 inline GenTreeCast* Compiler::gtNewCastNode(var_types typ, GenTree* op1, bool fromUnsigned, var_types castType)
1490 GenTreeCast* res = new (this, GT_CAST) GenTreeCast(typ, op1, fromUnsigned, castType);
1494 inline GenTreeCast* Compiler::gtNewCastNodeL(var_types typ, GenTree* op1, bool fromUnsigned, var_types castType)
1496 /* Some casts get transformed into 'GT_CALL' or 'GT_IND' nodes */
1498 assert(GenTree::s_gtNodeSizes[GT_CALL] >= GenTree::s_gtNodeSizes[GT_CAST]);
1499 assert(GenTree::s_gtNodeSizes[GT_CALL] >= GenTree::s_gtNodeSizes[GT_IND]);
1501 /* Make a big node first and then change it to be GT_CAST */
1504 new (this, LargeOpOpcode()) GenTreeCast(typ, op1, fromUnsigned, castType DEBUGARG(/*largeNode*/ true));
1508 /*****************************************************************************/
1509 #else // SMALL_TREE_NODES
1510 /*****************************************************************************/
1512 inline void GenTree::InitNodeSize()
1516 inline void GenTree::SetOper(genTreeOps oper, ValueNumberUpdate vnUpdate)
1520 if (vnUpdate == CLEAR_VN)
1522 // Clear the ValueNum field.
1523 gtVNPair.SetBoth(ValueNumStore::NoVN);
1527 inline void GenTree::ReplaceWith(GenTree* src)
1529 RecordOperBashing(OperGet(), src->OperGet()); // nop unless NODEBASH_STATS is enabled
1536 inline GenTree* Compiler::gtNewCastNode(var_types typ, GenTree* op1, var_types castType)
1538 GenTree* tree = gtNewOperNode(GT_CAST, typ, op1);
1539 tree->gtCast.gtCastType = castType;
1542 inline GenTree* Compiler::gtNewCastNodeL(var_types typ, GenTree* op1, var_types castType)
1544 return gtNewCastNode(typ, op1, castType);
1547 /*****************************************************************************/
1548 #endif // SMALL_TREE_NODES
1549 /*****************************************************************************/
1551 /*****************************************************************************/
1553 inline void GenTree::SetOperRaw(genTreeOps oper)
1555 // Please do not do anything here other than assign to gtOper (debug-only
1556 // code is OK, but should be kept to a minimum).
1557 RecordOperBashing(OperGet(), oper); // nop unless NODEBASH_STATS is enabled
1561 inline void GenTree::SetOperResetFlags(genTreeOps oper)
1564 gtFlags &= GTF_NODE_MASK;
1567 inline void GenTree::ChangeOperConst(genTreeOps oper)
1569 #ifdef _TARGET_64BIT_
1570 assert(oper != GT_CNS_LNG); // We should never see a GT_CNS_LNG for a 64-bit target!
1572 assert(OperIsConst(oper)); // use ChangeOper() instead
1573 SetOperResetFlags(oper);
1574 // Some constant subtypes have additional fields that must be initialized.
1575 if (oper == GT_CNS_INT)
1577 gtIntCon.gtFieldSeq = FieldSeqStore::NotAField();
1581 inline void GenTree::ChangeOper(genTreeOps oper, ValueNumberUpdate vnUpdate)
1583 assert(!OperIsConst(oper)); // use ChangeOperLeaf() instead
1585 unsigned mask = GTF_COMMON_MASK;
1586 if (this->OperIsIndirOrArrLength() && OperIsIndirOrArrLength(oper))
1588 mask |= GTF_IND_NONFAULTING;
1590 SetOper(oper, vnUpdate);
1593 // Do "oper"-specific initializations...
1597 gtLclFld.gtLclOffs = 0;
1598 gtLclFld.gtFieldSeq = FieldSeqStore::NotAField();
1605 inline void GenTree::ChangeOperUnchecked(genTreeOps oper)
1607 unsigned mask = GTF_COMMON_MASK;
1608 if (this->OperIsIndirOrArrLength() && OperIsIndirOrArrLength(oper))
1610 mask |= GTF_IND_NONFAULTING;
1612 SetOperRaw(oper); // Trust the caller and don't use SetOper()
1616 /*****************************************************************************
1617 * Returns true if the node is &var (created by ldarga and ldloca)
1620 inline bool GenTree::IsVarAddr() const
1622 if (gtOper == GT_ADDR)
1624 if (gtFlags & GTF_ADDR_ONSTACK)
1626 assert((gtType == TYP_BYREF) || (gtType == TYP_I_IMPL));
1633 /*****************************************************************************
1635 * Returns true if the node is of the "ovf" variety, for example, add.ovf.i1.
1636 * + gtOverflow() can only be called for valid operators (that is, we know it is one
1637 * of the operators which may have GTF_OVERFLOW set).
1638 * + gtOverflowEx() is more expensive, and should be called only if gtOper may be
1639 * an operator for which GTF_OVERFLOW is invalid.
1642 inline bool GenTree::gtOverflow() const
1644 assert(OperMayOverflow());
1646 if ((gtFlags & GTF_OVERFLOW) != 0)
1648 assert(varTypeIsIntegral(TypeGet()));
1658 inline bool GenTree::gtOverflowEx() const
1660 return OperMayOverflow() && gtOverflow();
1664 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1665 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1667 XX Inline functions XX
1669 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1670 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1673 inline bool Compiler::lvaHaveManyLocals() const
1675 return (lvaCount >= lclMAX_TRACKED);
1678 /*****************************************************************************
1680 * Allocate a temporary variable or a set of temp variables.
1683 inline unsigned Compiler::lvaGrabTemp(bool shortLifetime DEBUGARG(const char* reason))
1685 if (compIsForInlining())
1687 // Grab the temp using Inliner's Compiler instance.
1688 Compiler* pComp = impInlineInfo->InlinerCompiler; // The Compiler instance for the caller (i.e. the inliner)
1690 if (pComp->lvaHaveManyLocals())
1692 // Don't create more LclVar with inlining
1693 compInlineResult->NoteFatal(InlineObservation::CALLSITE_TOO_MANY_LOCALS);
1696 unsigned tmpNum = pComp->lvaGrabTemp(shortLifetime DEBUGARG(reason));
1697 lvaTable = pComp->lvaTable;
1698 lvaCount = pComp->lvaCount;
1699 lvaTableCnt = pComp->lvaTableCnt;
1703 // You cannot allocate more space after frame layout!
1704 noway_assert(lvaDoneFrameLayout < Compiler::TENTATIVE_FRAME_LAYOUT);
1706 /* Check if the lvaTable has to be grown */
1707 if (lvaCount + 1 > lvaTableCnt)
1709 unsigned newLvaTableCnt = lvaCount + (lvaCount / 2) + 1;
1711 // Check for overflow
1712 if (newLvaTableCnt <= lvaCount)
1714 IMPL_LIMITATION("too many locals");
1717 // Note: compGetMemArray might throw.
1718 LclVarDsc* newLvaTable = (LclVarDsc*)compGetMemArray(newLvaTableCnt, sizeof(*lvaTable), CMK_LvaTable);
1720 memcpy(newLvaTable, lvaTable, lvaCount * sizeof(*lvaTable));
1721 memset(newLvaTable + lvaCount, 0, (newLvaTableCnt - lvaCount) * sizeof(*lvaTable));
1723 for (unsigned i = lvaCount; i < newLvaTableCnt; i++)
1725 new (&newLvaTable[i], jitstd::placement_t()) LclVarDsc(this); // call the constructor.
1729 // Fill the old table with junks. So to detect the un-intended use.
1730 memset(lvaTable, JitConfig.JitDefaultFill(), lvaCount * sizeof(*lvaTable));
1733 lvaTableCnt = newLvaTableCnt;
1734 lvaTable = newLvaTable;
1737 lvaTable[lvaCount].lvType = TYP_UNDEF; // Initialize lvType, lvIsTemp and lvOnFrame
1738 lvaTable[lvaCount].lvIsTemp = shortLifetime;
1739 lvaTable[lvaCount].lvOnFrame = true;
1741 unsigned tempNum = lvaCount;
1748 printf("\nlvaGrabTemp returning %d (", tempNum);
1749 gtDispLclVar(tempNum, false);
1750 printf(")%s called for %s.\n", shortLifetime ? "" : " (a long lifetime temp)", reason);
1757 inline unsigned Compiler::lvaGrabTemps(unsigned cnt DEBUGARG(const char* reason))
1759 if (compIsForInlining())
1761 // Grab the temps using Inliner's Compiler instance.
1762 unsigned tmpNum = impInlineInfo->InlinerCompiler->lvaGrabTemps(cnt DEBUGARG(reason));
1764 lvaTable = impInlineInfo->InlinerCompiler->lvaTable;
1765 lvaCount = impInlineInfo->InlinerCompiler->lvaCount;
1766 lvaTableCnt = impInlineInfo->InlinerCompiler->lvaTableCnt;
1773 printf("\nlvaGrabTemps(%d) returning %d..%d (long lifetime temps) called for %s", cnt, lvaCount,
1774 lvaCount + cnt - 1, reason);
1778 // You cannot allocate more space after frame layout!
1779 noway_assert(lvaDoneFrameLayout < Compiler::TENTATIVE_FRAME_LAYOUT);
1781 /* Check if the lvaTable has to be grown */
1782 if (lvaCount + cnt > lvaTableCnt)
1784 unsigned newLvaTableCnt = lvaCount + max(lvaCount / 2 + 1, cnt);
1786 // Check for overflow
1787 if (newLvaTableCnt <= lvaCount)
1789 IMPL_LIMITATION("too many locals");
1792 // Note: compGetMemArray might throw.
1793 LclVarDsc* newLvaTable = (LclVarDsc*)compGetMemArray(newLvaTableCnt, sizeof(*lvaTable), CMK_LvaTable);
1795 memcpy(newLvaTable, lvaTable, lvaCount * sizeof(*lvaTable));
1796 memset(newLvaTable + lvaCount, 0, (newLvaTableCnt - lvaCount) * sizeof(*lvaTable));
1797 for (unsigned i = lvaCount; i < newLvaTableCnt; i++)
1799 new (&newLvaTable[i], jitstd::placement_t()) LclVarDsc(this); // call the constructor.
1803 // Fill the old table with junks. So to detect the un-intended use.
1804 memset(lvaTable, JitConfig.JitDefaultFill(), lvaCount * sizeof(*lvaTable));
1807 lvaTableCnt = newLvaTableCnt;
1808 lvaTable = newLvaTable;
1811 unsigned tempNum = lvaCount;
1815 lvaTable[lvaCount].lvType = TYP_UNDEF; // Initialize lvType, lvIsTemp and lvOnFrame
1816 lvaTable[lvaCount].lvIsTemp = false;
1817 lvaTable[lvaCount].lvOnFrame = true;
1824 /*****************************************************************************
1826 * Allocate a temporary variable which is implicitly used by code-gen
1827 * There will be no explicit references to the temp, and so it needs to
1828 * be forced to be kept alive, and not be optimized away.
1831 inline unsigned Compiler::lvaGrabTempWithImplicitUse(bool shortLifetime DEBUGARG(const char* reason))
1833 if (compIsForInlining())
1835 // Grab the temp using Inliner's Compiler instance.
1836 unsigned tmpNum = impInlineInfo->InlinerCompiler->lvaGrabTempWithImplicitUse(shortLifetime DEBUGARG(reason));
1838 lvaTable = impInlineInfo->InlinerCompiler->lvaTable;
1839 lvaCount = impInlineInfo->InlinerCompiler->lvaCount;
1840 lvaTableCnt = impInlineInfo->InlinerCompiler->lvaTableCnt;
1844 unsigned lclNum = lvaGrabTemp(shortLifetime DEBUGARG(reason));
1846 LclVarDsc* varDsc = &lvaTable[lclNum];
1848 // This will prevent it from being optimized away
1849 // TODO-CQ: We shouldn't have to go as far as to declare these
1850 // address-exposed -- DoNotEnregister should suffice?
1851 lvaSetVarAddrExposed(lclNum);
1853 // We need lvRefCnt to be non-zero to prevent various asserts from firing.
1854 varDsc->lvRefCnt = 1;
1855 varDsc->lvRefCntWtd = BB_UNITY_WEIGHT;
1860 /*****************************************************************************
1862 * If lvaTrackedFixed is false then set the lvaSortAgain flag
1863 * (this allows us to grow the number of tracked variables)
1864 * and zero lvRefCntWtd when lvRefCnt is zero
1867 inline void LclVarDsc::lvaResetSortAgainFlag(Compiler* comp)
1869 if (!comp->lvaTrackedFixed)
1871 /* Flag this change, set lvaSortAgain to true */
1872 comp->lvaSortAgain = true;
1874 /* Set weighted ref count to zero if ref count is zero */
1881 /*****************************************************************************
1883 * Decrement the ref counts for a local variable
1886 inline void LclVarDsc::decRefCnts(BasicBlock::weight_t weight, Compiler* comp, bool propagate)
1888 /* Decrement lvRefCnt and lvRefCntWtd */
1889 Compiler::lvaPromotionType promotionType = DUMMY_INIT(Compiler::PROMOTION_TYPE_NONE);
1890 if (varTypeIsStruct(lvType))
1892 promotionType = comp->lvaGetPromotionType(this);
1896 // Decrement counts on the local itself.
1898 if (lvType != TYP_STRUCT || promotionType != Compiler::PROMOTION_TYPE_INDEPENDENT)
1900 assert(lvRefCnt); // Can't decrement below zero
1902 // TODO: Well, the assert above could be bogus.
1903 // If lvRefCnt has overflowed before, then might drop to 0.
1904 // Therefore we do need the following check to keep lvRefCnt from underflow:
1908 // Decrement lvRefCnt
1913 // Decrement lvRefCntWtd
1917 if (lvIsTemp && (weight * 2 > weight))
1922 if (lvRefCntWtd <= weight)
1923 { // Can't go below zero
1928 lvRefCntWtd -= weight;
1934 if (varTypeIsStruct(lvType) && propagate)
1936 // For promoted struct locals, decrement lvRefCnt on its field locals as well.
1937 if (promotionType == Compiler::PROMOTION_TYPE_INDEPENDENT ||
1938 promotionType == Compiler::PROMOTION_TYPE_DEPENDENT)
1940 for (unsigned i = lvFieldLclStart; i < lvFieldLclStart + lvFieldCnt; ++i)
1942 comp->lvaTable[i].decRefCnts(comp->lvaMarkRefsWeight, comp, false); // Don't propagate
1947 if (lvIsStructField && propagate)
1949 // Depending on the promotion type, decrement the ref count for the parent struct as well.
1950 promotionType = comp->lvaGetParentPromotionType(this);
1951 LclVarDsc* parentvarDsc = &comp->lvaTable[lvParentLcl];
1952 assert(!parentvarDsc->lvRegStruct);
1953 if (promotionType == Compiler::PROMOTION_TYPE_DEPENDENT)
1955 parentvarDsc->decRefCnts(comp->lvaMarkRefsWeight, comp, false); // Don't propagate
1959 lvaResetSortAgainFlag(comp);
1964 unsigned varNum = (unsigned)(this - comp->lvaTable);
1965 assert(&comp->lvaTable[varNum] == this);
1966 printf("New refCnts for V%02u: refCnt = %2u, refCntWtd = %s\n", varNum, lvRefCnt, refCntWtd2str(lvRefCntWtd));
1971 /*****************************************************************************
1973 * Increment the ref counts for a local variable
1976 inline void LclVarDsc::incRefCnts(BasicBlock::weight_t weight, Compiler* comp, bool propagate)
1978 Compiler::lvaPromotionType promotionType = DUMMY_INIT(Compiler::PROMOTION_TYPE_NONE);
1979 if (varTypeIsStruct(lvType))
1981 promotionType = comp->lvaGetPromotionType(this);
1985 // Increment counts on the local itself.
1987 if (lvType != TYP_STRUCT || promotionType != Compiler::PROMOTION_TYPE_INDEPENDENT)
1990 // Increment lvRefCnt
1992 int newRefCnt = lvRefCnt + 1;
1993 if (newRefCnt == (unsigned short)newRefCnt) // lvRefCnt is an "unsigned short". Don't overflow it.
1995 lvRefCnt = (unsigned short)newRefCnt;
1998 // This fires when an uninitialize value for 'weight' is used (see lvaMarkRefsWeight)
1999 assert(weight != 0xdddddddd);
2001 // Increment lvRefCntWtd
2005 // We double the weight of internal temps
2007 if (lvIsTemp && (weight * 2 > weight))
2012 unsigned newWeight = lvRefCntWtd + weight;
2013 if (newWeight >= lvRefCntWtd)
2014 { // lvRefCntWtd is an "unsigned". Don't overflow it
2015 lvRefCntWtd = newWeight;
2018 { // On overflow we assign ULONG_MAX
2019 lvRefCntWtd = ULONG_MAX;
2024 if (varTypeIsStruct(lvType) && propagate)
2026 // For promoted struct locals, increment lvRefCnt on its field locals as well.
2027 if (promotionType == Compiler::PROMOTION_TYPE_INDEPENDENT ||
2028 promotionType == Compiler::PROMOTION_TYPE_DEPENDENT)
2030 for (unsigned i = lvFieldLclStart; i < lvFieldLclStart + lvFieldCnt; ++i)
2032 comp->lvaTable[i].incRefCnts(comp->lvaMarkRefsWeight, comp, false); // Don't propagate
2037 if (lvIsStructField && propagate)
2039 // Depending on the promotion type, increment the ref count for the parent struct as well.
2040 promotionType = comp->lvaGetParentPromotionType(this);
2041 LclVarDsc* parentvarDsc = &comp->lvaTable[lvParentLcl];
2042 assert(!parentvarDsc->lvRegStruct);
2043 if (promotionType == Compiler::PROMOTION_TYPE_DEPENDENT)
2045 parentvarDsc->incRefCnts(comp->lvaMarkRefsWeight, comp, false); // Don't propagate
2049 lvaResetSortAgainFlag(comp);
2054 unsigned varNum = (unsigned)(this - comp->lvaTable);
2055 assert(&comp->lvaTable[varNum] == this);
2056 printf("New refCnts for V%02u: refCnt = %2u, refCntWtd = %s\n", varNum, lvRefCnt, refCntWtd2str(lvRefCntWtd));
2061 /*****************************************************************************
2063 * Set the lvPrefReg field to reg
2066 inline void LclVarDsc::setPrefReg(regNumber regNum, Compiler* comp)
2069 if (isFloatRegType(TypeGet()))
2071 // Check for FP struct-promoted field being passed in integer register
2073 if (!genIsValidFloatReg(regNum))
2077 regMask = genRegMaskFloat(regNum, TypeGet());
2081 regMask = genRegMask(regNum);
2085 // Don't set a preferred register for a TYP_STRUCT that takes more than one register slot
2086 if ((TypeGet() == TYP_STRUCT) && (lvSize() > REGSIZE_BYTES))
2090 /* Only interested if we have a new register bit set */
2091 if (lvPrefReg & regMask)
2101 printf("Change preferred register for V%02u from ", this - comp->lvaTable);
2102 dspRegMask(lvPrefReg);
2106 printf("Set preferred register for V%02u", this - comp->lvaTable);
2109 dspRegMask(regMask);
2114 /* Overwrite the lvPrefReg field */
2116 lvPrefReg = (regMaskSmall)regMask;
2118 #ifdef LEGACY_BACKEND
2119 // This is specific to the classic register allocator.
2120 // While walking the trees during reg predict we set the lvPrefReg mask
2121 // and then re-sort the 'tracked' variable when the lvPrefReg mask changes.
2124 /* Flag this change, set lvaSortAgain to true */
2125 comp->lvaSortAgain = true;
2127 #endif // LEGACY_BACKEND
2130 /*****************************************************************************
2132 * Add regMask to the lvPrefReg field
2135 inline void LclVarDsc::addPrefReg(regMaskTP regMask, Compiler* comp)
2137 assert(regMask != RBM_NONE);
2140 // Don't set a preferred register for a TYP_STRUCT that takes more than one register slot
2141 if ((lvType == TYP_STRUCT) && (lvSize() > REGSIZE_BYTES))
2145 /* Only interested if we have a new register bit set */
2146 if (lvPrefReg & regMask)
2156 printf("Additional preferred register for V%02u from ", this - comp->lvaTable);
2157 dspRegMask(lvPrefReg);
2161 printf("Set preferred register for V%02u", this - comp->lvaTable);
2164 dspRegMask(lvPrefReg | regMask);
2169 /* Update the lvPrefReg field */
2171 lvPrefReg |= regMask;
2173 #ifdef LEGACY_BACKEND
2174 // This is specific to the classic register allocator
2175 // While walking the trees during reg predict we set the lvPrefReg mask
2176 // and then resort the 'tracked' variable when the lvPrefReg mask changes
2179 /* Flag this change, set lvaSortAgain to true */
2180 comp->lvaSortAgain = true;
2182 #endif // LEGACY_BACKEND
2185 /*****************************************************************************
2187 * The following returns the mask of all tracked locals
2188 * referenced in a statement.
2191 inline VARSET_VALRET_TP Compiler::lvaStmtLclMask(GenTree* stmt)
2196 VARSET_TP lclMask(VarSetOps::MakeEmpty(this));
2198 assert(stmt->gtOper == GT_STMT);
2199 assert(fgStmtListThreaded);
2201 for (tree = stmt->gtStmt.gtStmtList; tree; tree = tree->gtNext)
2203 if (tree->gtOper != GT_LCL_VAR)
2208 varNum = tree->gtLclVarCommon.gtLclNum;
2209 assert(varNum < lvaCount);
2210 varDsc = lvaTable + varNum;
2212 if (!varDsc->lvTracked)
2217 VarSetOps::UnionD(this, lclMask, VarSetOps::MakeSingleton(this, varDsc->lvVarIndex));
2223 /*****************************************************************************
2224 * Returns true if the lvType is a TYP_REF or a TYP_BYREF.
2225 * When the lvType is a TYP_STRUCT it searches the GC layout
2226 * of the struct and returns true iff it contains a GC ref.
2229 inline bool Compiler::lvaTypeIsGC(unsigned varNum)
2231 if (lvaTable[varNum].TypeGet() == TYP_STRUCT)
2233 assert(lvaTable[varNum].lvGcLayout != nullptr); // bits are intialized
2234 return (lvaTable[varNum].lvStructGcCount != 0);
2236 return (varTypeIsGC(lvaTable[varNum].TypeGet()));
2239 /*****************************************************************************
2240 Is this a synchronized instance method? If so, we will need to report "this"
2241 in the GC information, so that the EE can release the object lock
2242 in case of an exception
2244 We also need to report "this" and keep it alive for all shared generic
2245 code that gets the actual generic context from the "this" pointer and
2246 has exception handlers.
2248 For example, if List<T>::m() is shared between T = object and T = string,
2249 then inside m() an exception handler "catch E<T>" needs to be able to fetch
2250 the 'this' pointer to find out what 'T' is in order to tell if we
2251 should catch the exception or not.
2254 inline bool Compiler::lvaKeepAliveAndReportThis()
2256 if (info.compIsStatic || lvaTable[0].TypeGet() != TYP_REF)
2261 const bool genericsContextIsThis = (info.compMethodInfo->options & CORINFO_GENERICS_CTXT_FROM_THIS) != 0;
2263 #ifdef JIT32_GCENCODER
2265 if (info.compFlags & CORINFO_FLG_SYNCH)
2268 if (genericsContextIsThis)
2270 // TODO: Check if any of the exception clauses are
2271 // typed using a generic type. Else, we do not need to report this.
2272 if (info.compXcptnsCount > 0)
2275 if (opts.compDbgCode)
2278 if (lvaGenericsContextUseCount > 0)
2280 JITDUMP("Reporting this as generic context: %u refs\n", lvaGenericsContextUseCount);
2284 #else // !JIT32_GCENCODER
2285 // If the generics context is the this pointer we need to report it if either
2286 // the VM requires us to keep the generics context alive or it is used in a look-up.
2287 // We keep it alive in the lookup scenario, even when the VM didn't ask us to,
2288 // because collectible types need the generics context when gc-ing.
2289 if (genericsContextIsThis)
2291 const bool isUsed = lvaGenericsContextUseCount > 0;
2292 const bool mustKeep = (info.compMethodInfo->options & CORINFO_GENERICS_CTXT_KEEP_ALIVE) != 0;
2294 if (isUsed || mustKeep)
2296 JITDUMP("Reporting this as generic context: %u refs%s\n", lvaGenericsContextUseCount,
2297 mustKeep ? ", must keep" : "");
2307 /*****************************************************************************
2308 Similar to lvaKeepAliveAndReportThis
2311 inline bool Compiler::lvaReportParamTypeArg()
2313 if (info.compMethodInfo->options & (CORINFO_GENERICS_CTXT_FROM_METHODDESC | CORINFO_GENERICS_CTXT_FROM_METHODTABLE))
2315 assert(info.compTypeCtxtArg != -1);
2317 // If the VM requires us to keep the generics context alive and report it (for example, if any catch
2318 // clause catches a type that uses a generic parameter of this method) this flag will be set.
2319 if (info.compMethodInfo->options & CORINFO_GENERICS_CTXT_KEEP_ALIVE)
2324 // Otherwise, if an exact type parameter is needed in the body, report the generics context.
2325 // We do this because collectible types needs the generics context when gc-ing.
2326 if (lvaGenericsContextUseCount > 0)
2332 // Otherwise, we don't need to report it -- the generics context parameter is unused.
2336 //*****************************************************************************
2338 inline int Compiler::lvaCachedGenericContextArgOffset()
2340 assert(lvaDoneFrameLayout == FINAL_FRAME_LAYOUT);
2342 return lvaCachedGenericContextArgOffs;
2345 /*****************************************************************************
2347 * Return the stack framed offset of the given variable; set *FPbased to
2348 * true if the variable is addressed off of FP, false if it's addressed
2349 * off of SP. Note that 'varNum' can be a negated spill-temporary var index.
2351 * mustBeFPBased - strong about whether the base reg is FP. But it is also
2352 * strong about not being FPBased after FINAL_FRAME_LAYOUT. i.e.,
2353 * it enforces SP based.
2355 * addrModeOffset - is the addressing mode offset, for example: v02 + 0x10
2356 * So, V02 itself is at offset sp + 0x10 and then addrModeOffset is what gets
2357 * added beyond that.
2363 Compiler::lvaFrameAddress(int varNum, bool mustBeFPBased, regNumber* pBaseReg, int addrModeOffset)
2366 Compiler::lvaFrameAddress(int varNum, bool* pFPbased)
2369 assert(lvaDoneFrameLayout != NO_FRAME_LAYOUT);
2373 bool fConservative = false;
2374 var_types type = TYP_UNDEF;
2379 assert((unsigned)varNum < lvaCount);
2380 varDsc = lvaTable + varNum;
2381 type = varDsc->TypeGet();
2382 bool isPrespilledArg = false;
2383 #if defined(_TARGET_ARM_) && defined(PROFILING_SUPPORTED)
2384 isPrespilledArg = varDsc->lvIsParam && compIsProfilerHookNeeded() &&
2385 lvaIsPreSpilled(varNum, codeGen->regSet.rsMaskPreSpillRegs(false));
2388 // If we have finished with register allocation, and this isn't a stack-based local,
2389 // check that this has a valid stack location.
2390 if (lvaDoneFrameLayout > REGALLOC_FRAME_LAYOUT && !varDsc->lvOnFrame)
2392 #ifdef _TARGET_AMD64_
2393 #ifndef FEATURE_UNIX_AMD64_STRUCT_PASSING
2394 // On amd64, every param has a stack location, except on Unix-like systems.
2395 assert(varDsc->lvIsParam);
2396 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
2397 #elif !defined(LEGACY_BACKEND)
2398 // For !LEGACY_BACKEND on other targets, a stack parameter that is enregistered or prespilled
2399 // for profiling on ARM will have a stack location.
2400 assert((varDsc->lvIsParam && !varDsc->lvIsRegArg) || isPrespilledArg);
2401 #else // !(_TARGET_AMD64 || defined(LEGACY_BACKEND))
2402 // Otherwise, we only have a valid stack location for:
2403 // A parameter that was passed on the stack, being homed into its register home,
2404 // or a prespilled argument on arm under profiler.
2405 assert((varDsc->lvIsParam && !varDsc->lvIsRegArg && varDsc->lvRegister) || isPrespilledArg);
2406 #endif // !(_TARGET_AMD64 || defined(LEGACY_BACKEND))
2409 FPbased = varDsc->lvFramePointerBased;
2412 #if FEATURE_FIXED_OUT_ARGS
2413 if ((unsigned)varNum == lvaOutgoingArgSpaceVar)
2415 assert(FPbased == false);
2421 assert(FPbased == (isFramePointerUsed() || (genDoubleAlign() && varDsc->lvIsParam && !varDsc->lvIsRegArg)));
2424 assert(FPbased == isFramePointerUsed());
2430 offset = varDsc->lvStkOffs;
2432 else // Its a spill-temp
2434 FPbased = isFramePointerUsed();
2435 if (lvaDoneFrameLayout == Compiler::FINAL_FRAME_LAYOUT)
2437 TempDsc* tmpDsc = tmpFindNum(varNum);
2438 #ifndef LEGACY_BACKEND
2439 // The temp might be in use, since this might be during code generation.
2440 if (tmpDsc == nullptr)
2442 tmpDsc = tmpFindNum(varNum, Compiler::TEMP_USAGE_USED);
2444 #endif // !LEGACY_BACKEND
2445 assert(tmpDsc != nullptr);
2446 offset = tmpDsc->tdTempOffs();
2447 type = tmpDsc->tdTempType();
2451 // This value is an estimate until we calculate the
2452 // offset after the final frame layout
2453 // ---------------------------------------------------
2455 // +-------------------------+ base --+
2456 // | LR, ++N for ARM | | frameBaseOffset (= N)
2457 // +-------------------------+ |
2458 // | R11, ++N for ARM | <---FP |
2459 // +-------------------------+ --+
2460 // | compCalleeRegsPushed - N| | lclFrameOffset
2461 // +-------------------------+ --+
2463 // +-------------------------+ |
2464 // | tmp[MAX_SPILL_TEMP] | |
2466 // | tmp[0] | | compLclFrameSize
2467 // +-------------------------+ |
2468 // | outgoingArgSpaceSize | |
2469 // +-------------------------+ --+
2472 // ---------------------------------------------------
2474 type = compFloatingPointUsed ? TYP_FLOAT : TYP_INT;
2475 fConservative = true;
2478 // Worst case stack based offset.
2479 CLANG_FORMAT_COMMENT_ANCHOR;
2480 #if FEATURE_FIXED_OUT_ARGS
2481 int outGoingArgSpaceSize = lvaOutgoingArgSpaceSize;
2483 int outGoingArgSpaceSize = 0;
2485 offset = outGoingArgSpaceSize + max(-varNum * TARGET_POINTER_SIZE, (int)lvaGetMaxSpillTempSize());
2489 // Worst case FP based offset.
2490 CLANG_FORMAT_COMMENT_ANCHOR;
2493 offset = codeGen->genCallerSPtoInitialSPdelta() - codeGen->genCallerSPtoFPdelta();
2495 offset = -(codeGen->genTotalFrameSize());
2506 *pBaseReg = REG_FPBASE;
2508 // Change the FP-based addressing to the SP-based addressing when possible because
2509 // it generates smaller code on ARM. See frame picture above for the math.
2512 // If it is the final frame layout phase, we don't have a choice, we should stick
2513 // to either FP based or SP based that we decided in the earlier phase. Because
2514 // we have already selected the instruction. Min-opts will have R10 enabled, so just
2517 int spOffset = fConservative ? compLclFrameSize : offset + codeGen->genSPtoFPdelta();
2518 int actualOffset = (spOffset + addrModeOffset);
2519 int ldrEncodeLimit = (varTypeIsFloating(type) ? 0x3FC : 0xFFC);
2520 // Use ldr sp imm encoding.
2521 if (lvaDoneFrameLayout == FINAL_FRAME_LAYOUT || opts.MinOpts() || (actualOffset <= ldrEncodeLimit))
2524 *pBaseReg = compLocallocUsed ? REG_SAVED_LOCALLOC_SP : REG_SPBASE;
2526 // Use ldr +/-imm8 encoding.
2527 else if (offset >= -0x7C && offset <= ldrEncodeLimit)
2529 *pBaseReg = REG_FPBASE;
2531 // Use a single movw. prefer locals.
2532 else if (actualOffset <= 0xFFFC) // Fix 383910 ARM ILGEN
2535 *pBaseReg = compLocallocUsed ? REG_SAVED_LOCALLOC_SP : REG_SPBASE;
2540 *pBaseReg = REG_FPBASE;
2546 *pBaseReg = REG_SPBASE;
2549 *pFPbased = FPbased;
2555 inline bool Compiler::lvaIsParameter(unsigned varNum)
2559 assert(varNum < lvaCount);
2560 varDsc = lvaTable + varNum;
2562 return varDsc->lvIsParam;
2565 inline bool Compiler::lvaIsRegArgument(unsigned varNum)
2569 assert(varNum < lvaCount);
2570 varDsc = lvaTable + varNum;
2572 return varDsc->lvIsRegArg;
2575 inline BOOL Compiler::lvaIsOriginalThisArg(unsigned varNum)
2577 assert(varNum < lvaCount);
2579 BOOL isOriginalThisArg = (varNum == info.compThisArg) && (info.compIsStatic == false);
2582 if (isOriginalThisArg)
2584 LclVarDsc* varDsc = lvaTable + varNum;
2585 // Should never write to or take the address of the original 'this' arg
2586 CLANG_FORMAT_COMMENT_ANCHOR;
2588 #ifndef JIT32_GCENCODER
2589 // With the general encoder/decoder, when the original 'this' arg is needed as a generics context param, we
2590 // copy to a new local, and mark the original as DoNotEnregister, to
2591 // ensure that it is stack-allocated. It should not be the case that the original one can be modified -- it
2592 // should not be written to, or address-exposed.
2593 assert(!varDsc->lvHasILStoreOp &&
2594 (!varDsc->lvAddrExposed || ((info.compMethodInfo->options & CORINFO_GENERICS_CTXT_FROM_THIS) != 0)));
2596 assert(!varDsc->lvHasILStoreOp && !varDsc->lvAddrExposed);
2601 return isOriginalThisArg;
2604 inline BOOL Compiler::lvaIsOriginalThisReadOnly()
2606 return lvaArg0Var == info.compThisArg;
2609 /*****************************************************************************
2611 * The following is used to detect the cases where the same local variable#
2612 * is used both as a long/double value and a 32-bit value and/or both as an
2613 * integer/address and a float value.
2616 /* static */ inline unsigned Compiler::lvaTypeRefMask(var_types type)
2618 const static BYTE lvaTypeRefMasks[] = {
2619 #define DEF_TP(tn, nm, jitType, verType, sz, sze, asze, st, al, tf, howUsed) howUsed,
2620 #include "typelist.h"
2624 assert((unsigned)type < sizeof(lvaTypeRefMasks));
2625 assert(lvaTypeRefMasks[type] != 0);
2627 return lvaTypeRefMasks[type];
2630 /*****************************************************************************
2632 * The following is used to detect the cases where the same local variable#
2633 * is used both as a long/double value and a 32-bit value and/or both as an
2634 * integer/address and a float value.
2637 inline var_types Compiler::lvaGetActualType(unsigned lclNum)
2639 return genActualType(lvaGetRealType(lclNum));
2642 inline var_types Compiler::lvaGetRealType(unsigned lclNum)
2644 return lvaTable[lclNum].TypeGet();
2648 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2649 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2651 XX Inline functions XX
2653 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2654 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2657 inline unsigned Compiler::compMapILargNum(unsigned ILargNum)
2659 assert(ILargNum < info.compILargsCount || tiVerificationNeeded);
2661 // Note that this works because if compRetBuffArg/compTypeCtxtArg/lvVarargsHandleArg are not present
2662 // they will be BAD_VAR_NUM (MAX_UINT), which is larger than any variable number.
2663 if (ILargNum >= info.compRetBuffArg)
2666 assert(ILargNum < info.compLocalsCount || tiVerificationNeeded); // compLocals count already adjusted.
2669 if (ILargNum >= (unsigned)info.compTypeCtxtArg)
2672 assert(ILargNum < info.compLocalsCount || tiVerificationNeeded); // compLocals count already adjusted.
2675 if (ILargNum >= (unsigned)lvaVarargsHandleArg)
2678 assert(ILargNum < info.compLocalsCount || tiVerificationNeeded); // compLocals count already adjusted.
2681 assert(ILargNum < info.compArgsCount || tiVerificationNeeded);
2685 // For ARM varargs, all arguments go in integer registers, so swizzle the type
2686 inline var_types Compiler::mangleVarArgsType(var_types type)
2688 #ifdef _TARGET_ARMARCH_
2689 if (info.compIsVarArgs || opts.compUseSoftFP)
2701 #endif // _TARGET_ARMARCH_
2705 // For CORECLR there is no vararg on System V systems.
2707 inline regNumber Compiler::getCallArgIntRegister(regNumber floatReg)
2709 #ifdef _TARGET_AMD64_
2723 #else // !_TARGET_AMD64_
2724 // How will float args be passed for RyuJIT/x86?
2725 NYI("getCallArgIntRegister for RyuJIT/x86");
2727 #endif // !_TARGET_AMD64_
2730 inline regNumber Compiler::getCallArgFloatRegister(regNumber intReg)
2732 #ifdef _TARGET_AMD64_
2746 #else // !_TARGET_AMD64_
2747 // How will float args be passed for RyuJIT/x86?
2748 NYI("getCallArgFloatRegister for RyuJIT/x86");
2750 #endif // !_TARGET_AMD64_
2752 #endif // FEATURE_VARARG
2755 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2756 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2757 XX Register Allocator XX
2758 XX Inline functions XX
2760 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2761 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2764 /*****************************************************************************/
2766 inline bool rpCanAsgOperWithoutReg(GenTree* op, bool lclvar)
2770 switch (op->OperGet())
2776 type = genActualType(op->TypeGet());
2777 if (lclvar && ((type == TYP_INT) || (type == TYP_REF) || (type == TYP_BYREF)))
2790 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2791 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2794 XX Inline functions XX
2796 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2797 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2800 inline bool Compiler::compCanEncodePtrArgCntMax()
2802 #ifdef JIT32_GCENCODER
2804 // The GC encoding for fully interruptible methods does not
2805 // support more than 1023 pushed arguments, so we have to
2806 // use a partially interruptible GC info/encoding.
2808 return (fgPtrArgCntMax < MAX_PTRARG_OFS);
2809 #else // JIT32_GCENCODER
2814 /*****************************************************************************
2816 * Call the given function pointer for all nodes in the tree. The 'visitor'
2817 * fn should return one of the following values:
2819 * WALK_ABORT stop walking and return immediately
2820 * WALK_CONTINUE continue walking
2821 * WALK_SKIP_SUBTREES don't walk any subtrees of the node just visited
2823 * computeStack - true if we want to make stack visible to callback function
2826 inline Compiler::fgWalkResult Compiler::fgWalkTreePre(
2827 GenTree** pTree, fgWalkPreFn* visitor, void* callBackData, bool lclVarsOnly, bool computeStack)
2830 fgWalkData walkData;
2832 walkData.compiler = this;
2833 walkData.wtprVisitorFn = visitor;
2834 walkData.pCallbackData = callBackData;
2835 walkData.parent = nullptr;
2836 walkData.wtprLclsOnly = lclVarsOnly;
2838 walkData.printModified = false;
2841 fgWalkResult result;
2842 if (lclVarsOnly && computeStack)
2844 GenericTreeWalker<true, true, false, true, true> walker(&walkData);
2845 result = walker.WalkTree(pTree, nullptr);
2847 else if (lclVarsOnly)
2849 GenericTreeWalker<false, true, false, true, true> walker(&walkData);
2850 result = walker.WalkTree(pTree, nullptr);
2852 else if (computeStack)
2854 GenericTreeWalker<true, true, false, false, true> walker(&walkData);
2855 result = walker.WalkTree(pTree, nullptr);
2859 GenericTreeWalker<false, true, false, false, true> walker(&walkData);
2860 result = walker.WalkTree(pTree, nullptr);
2864 if (verbose && walkData.printModified)
2873 /*****************************************************************************
2875 * Same as above, except the tree walk is performed in a depth-first fashion,
2876 * The 'visitor' fn should return one of the following values:
2878 * WALK_ABORT stop walking and return immediately
2879 * WALK_CONTINUE continue walking
2881 * computeStack - true if we want to make stack visible to callback function
2884 inline Compiler::fgWalkResult Compiler::fgWalkTreePost(GenTree** pTree,
2885 fgWalkPostFn* visitor,
2889 fgWalkData walkData;
2891 walkData.compiler = this;
2892 walkData.wtpoVisitorFn = visitor;
2893 walkData.pCallbackData = callBackData;
2894 walkData.parent = nullptr;
2896 fgWalkResult result;
2899 GenericTreeWalker<true, false, true, false, true> walker(&walkData);
2900 result = walker.WalkTree(pTree, nullptr);
2904 GenericTreeWalker<false, false, true, false, true> walker(&walkData);
2905 result = walker.WalkTree(pTree, nullptr);
2908 assert(result == WALK_CONTINUE || result == WALK_ABORT);
2913 /*****************************************************************************
2915 * Call the given function pointer for all nodes in the tree. The 'visitor'
2916 * fn should return one of the following values:
2918 * WALK_ABORT stop walking and return immediately
2919 * WALK_CONTINUE continue walking
2920 * WALK_SKIP_SUBTREES don't walk any subtrees of the node just visited
2923 inline Compiler::fgWalkResult Compiler::fgWalkTree(GenTree** pTree,
2924 fgWalkPreFn* preVisitor,
2925 fgWalkPreFn* postVisitor,
2929 fgWalkData walkData;
2931 walkData.compiler = this;
2932 walkData.wtprVisitorFn = preVisitor;
2933 walkData.wtpoVisitorFn = postVisitor;
2934 walkData.pCallbackData = callBackData;
2935 walkData.parent = nullptr;
2936 walkData.wtprLclsOnly = false;
2938 walkData.printModified = false;
2941 fgWalkResult result;
2943 assert(preVisitor || postVisitor);
2945 if (preVisitor && postVisitor)
2947 GenericTreeWalker<true, true, true, false, true> walker(&walkData);
2948 result = walker.WalkTree(pTree, nullptr);
2950 else if (preVisitor)
2952 GenericTreeWalker<true, true, false, false, true> walker(&walkData);
2953 result = walker.WalkTree(pTree, nullptr);
2957 GenericTreeWalker<true, false, true, false, true> walker(&walkData);
2958 result = walker.WalkTree(pTree, nullptr);
2962 if (verbose && walkData.printModified)
2971 /*****************************************************************************
2973 * Has this block been added to throw an inlined exception
2974 * Returns true if the block was added to throw one of:
2975 * range-check exception
2976 * argument exception (used by feature SIMD)
2977 * argument range-check exception (used by feature SIMD)
2978 * divide by zero exception (Not used on X86/X64)
2979 * null reference exception (Not currently used)
2980 * overflow exception
2983 inline bool Compiler::fgIsThrowHlpBlk(BasicBlock* block)
2985 if (!fgIsCodeAdded())
2990 if (!(block->bbFlags & BBF_INTERNAL) || block->bbJumpKind != BBJ_THROW)
2995 GenTree* call = block->lastNode();
3000 LIR::Range& blockRange = LIR::AsRange(block);
3001 for (LIR::Range::ReverseIterator node = blockRange.rbegin(), end = blockRange.rend(); node != end; ++node)
3003 if (node->OperGet() == GT_CALL)
3005 assert(*node == call);
3006 assert(node == blockRange.rbegin());
3013 if (!call || (call->gtOper != GT_CALL))
3018 if (!((call->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_RNGCHKFAIL)) ||
3019 (call->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_THROWDIVZERO)) ||
3020 (call->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_THROWNULLREF)) ||
3021 (call->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_OVERFLOW))))
3026 // We can get to this point for blocks that we didn't create as throw helper blocks
3027 // under stress, with crazy flow graph optimizations. So, walk the fgAddCodeList
3028 // for the final determination.
3030 for (AddCodeDsc* add = fgAddCodeList; add; add = add->acdNext)
3032 if (block == add->acdDstBlk)
3034 return add->acdKind == SCK_RNGCHK_FAIL || add->acdKind == SCK_DIV_BY_ZERO || add->acdKind == SCK_OVERFLOW ||
3035 add->acdKind == SCK_ARG_EXCPN || add->acdKind == SCK_ARG_RNG_EXCPN;
3039 // We couldn't find it in the fgAddCodeList
3043 #if !FEATURE_FIXED_OUT_ARGS
3045 /*****************************************************************************
3047 * Return the stackLevel of the inserted block that throws exception
3048 * (by calling the EE helper).
3051 inline unsigned Compiler::fgThrowHlpBlkStkLevel(BasicBlock* block)
3053 for (AddCodeDsc* add = fgAddCodeList; add; add = add->acdNext)
3055 if (block == add->acdDstBlk)
3057 // Compute assert cond separately as assert macro cannot have conditional compilation directives.
3059 (add->acdKind == SCK_RNGCHK_FAIL || add->acdKind == SCK_DIV_BY_ZERO || add->acdKind == SCK_OVERFLOW ||
3060 add->acdKind == SCK_ARG_EXCPN || add->acdKind == SCK_ARG_RNG_EXCPN);
3063 // TODO: bbTgtStkDepth is DEBUG-only.
3064 // Should we use it regularly and avoid this search.
3065 assert(block->bbTgtStkDepth == add->acdStkLvl);
3066 return add->acdStkLvl;
3070 noway_assert(!"fgThrowHlpBlkStkLevel should only be called if fgIsThrowHlpBlk() is true, but we can't find the "
3071 "block in the fgAddCodeList list");
3073 /* We couldn't find the basic block: it must not have been a throw helper block */
3078 #endif // !FEATURE_FIXED_OUT_ARGS
3081 Small inline function to change a given block to a throw block.
3084 inline void Compiler::fgConvertBBToThrowBB(BasicBlock* block)
3086 // If we're converting a BBJ_CALLFINALLY block to a BBJ_THROW block,
3087 // then mark the subsequent BBJ_ALWAYS block as unreferenced.
3088 if (block->isBBCallAlwaysPair())
3090 BasicBlock* leaveBlk = block->bbNext;
3091 noway_assert(leaveBlk->bbJumpKind == BBJ_ALWAYS);
3093 leaveBlk->bbFlags &= ~BBF_DONT_REMOVE;
3094 leaveBlk->bbRefs = 0;
3095 leaveBlk->bbPreds = nullptr;
3097 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
3098 // This function (fgConvertBBToThrowBB) can be called before the predecessor lists are created (e.g., in
3099 // fgMorph). The fgClearFinallyTargetBit() function to update the BBF_FINALLY_TARGET bit depends on these
3100 // predecessor lists. If there are no predecessor lists, we immediately clear all BBF_FINALLY_TARGET bits
3101 // (to allow subsequent dead code elimination to delete such blocks without asserts), and set a flag to
3102 // recompute them later, before they are required.
3103 if (fgComputePredsDone)
3105 fgClearFinallyTargetBit(leaveBlk->bbJumpDest);
3109 fgClearAllFinallyTargetBits();
3110 fgNeedToAddFinallyTargetBits = true;
3112 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
3115 block->bbJumpKind = BBJ_THROW;
3116 block->bbSetRunRarely(); // any block with a throw is rare
3119 /*****************************************************************************
3121 * Return true if we've added any new basic blocks.
3124 inline bool Compiler::fgIsCodeAdded()
3126 return fgAddCodeModf;
3129 /*****************************************************************************
3130 Is the offset too big?
3132 inline bool Compiler::fgIsBigOffset(size_t offset)
3134 return (offset > compMaxUncheckedOffsetForNullObject);
3137 #if defined(LEGACY_BACKEND)
3139 /***********************************************************************************
3141 * Returns true if back-end will do other than integer division which currently occurs only
3142 * if "divisor" is a positive integer constant and a power of 2 other than 1 and INT_MIN
3145 inline bool Compiler::fgIsSignedDivOptimizable(GenTree* divisor)
3147 if (!opts.MinOpts() && divisor->IsCnsIntOrI())
3149 ssize_t ival = divisor->gtIntConCommon.IconValue();
3151 /* Is the divisor a power of 2 (excluding INT_MIN) ?.
3152 The intent of the third condition below is to exclude INT_MIN on a 64-bit platform
3153 and during codegen we need to encode ival-1 within 32 bits. If ival were INT_MIN
3154 then ival-1 would cause underflow.
3156 Note that we could put #ifdef around the third check so that it is applied only on
3157 64-bit platforms but the below is a more generic way to express it as it is a no-op
3158 on 32-bit platforms.
3160 return (ival > 0 && genMaxOneBit(ival) && ((ssize_t)(int)ival == ival));
3166 /************************************************************************************
3168 * Returns true if back-end will do other than integer division which currently occurs
3169 * if "divisor" is an unsigned integer constant and a power of 2 other than 1 and zero.
3172 inline bool Compiler::fgIsUnsignedDivOptimizable(GenTree* divisor)
3174 if (!opts.MinOpts() && divisor->IsCnsIntOrI())
3176 size_t ival = divisor->gtIntCon.gtIconVal;
3178 /* Is the divisor a power of 2 ? */
3179 return ival && genMaxOneBit(ival);
3185 /*****************************************************************************
3187 * Returns true if back-end will do other than integer division which currently occurs
3188 * if "divisor" is a positive integer constant and a power of 2 other than zero
3191 inline bool Compiler::fgIsSignedModOptimizable(GenTree* divisor)
3193 if (!opts.MinOpts() && divisor->IsCnsIntOrI())
3195 size_t ival = divisor->gtIntCon.gtIconVal;
3197 /* Is the divisor a power of 2 ? */
3198 return ssize_t(ival) > 0 && genMaxOneBit(ival);
3204 /*****************************************************************************
3206 * Returns true if back-end will do other than integer division which currently occurs
3207 * if "divisor" is a positive integer constant and a power of 2 other than zero
3210 inline bool Compiler::fgIsUnsignedModOptimizable(GenTree* divisor)
3212 if (!opts.MinOpts() && divisor->IsCnsIntOrI())
3214 size_t ival = divisor->gtIntCon.gtIconVal;
3216 /* Is the divisor a power of 2 ? */
3217 return ival != 0 && ival == (unsigned)genFindLowestBit(ival);
3223 #endif // LEGACY_BACKEND
3226 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3227 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3229 XX Inline functions XX
3231 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3232 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3235 /*****************************************************************************/
3237 /* static */ inline unsigned Compiler::tmpSlot(unsigned size)
3239 noway_assert(size >= sizeof(int));
3240 noway_assert(size <= TEMP_MAX_SIZE);
3241 assert((size % sizeof(int)) == 0);
3243 assert(size < UINT32_MAX);
3244 return size / sizeof(int) - 1;
3247 /*****************************************************************************
3249 * Finish allocating temps - should be called each time after a pass is made
3250 * over a function body.
3253 inline void Compiler::tmpEnd()
3256 if (verbose && (tmpCount > 0))
3258 printf("%d tmps used\n", tmpCount);
3263 /*****************************************************************************
3265 * Shuts down the temp-tracking code. Should be called once per function
3269 inline void Compiler::tmpDone()
3275 assert(tmpAllFree());
3276 for (temp = tmpListBeg(), count = temp ? 1 : 0; temp; temp = tmpListNxt(temp), count += temp ? 1 : 0)
3278 assert(temp->tdLegalOffset());
3281 // Make sure that all the temps were released
3282 assert(count == tmpCount);
3283 assert(tmpGetCount == 0);
3288 inline bool Compiler::shouldUseVerboseTrees()
3290 return (JitConfig.JitDumpVerboseTrees() == 1);
3293 inline bool Compiler::shouldUseVerboseSsa()
3295 return (JitConfig.JitDumpVerboseSsa() == 1);
3298 //------------------------------------------------------------------------
3299 // shouldDumpASCIITrees: Should we use only ASCII characters for tree dumps?
3302 // This is set to default to 1 in clrConfigValues.h
3304 inline bool Compiler::shouldDumpASCIITrees()
3306 return (JitConfig.JitDumpASCII() == 1);
3309 /*****************************************************************************
3310 * Should we enable JitStress mode?
3312 * !=2: Vary stress. Performance will be slightly/moderately degraded
3313 * 2: Check-all stress. Performance will be REALLY horrible
3316 inline DWORD getJitStressLevel()
3318 return JitConfig.JitStress();
3321 /*****************************************************************************
3322 * Should we do the strict check for non-virtual call to the virtual method?
3325 inline DWORD StrictCheckForNonVirtualCallToVirtualMethod()
3327 return JitConfig.JitStrictCheckForNonVirtualCallToVirtualMethod() == 1;
3332 /*****************************************************************************/
3333 /* Map a register argument number ("RegArgNum") to a register number ("RegNum").
3334 * A RegArgNum is in this range:
3335 * [0, MAX_REG_ARG) -- for integer registers
3336 * [0, MAX_FLOAT_REG_ARG) -- for floating point registers
3337 * Note that RegArgNum's are overlapping for integer and floating-point registers,
3338 * while RegNum's are not (for ARM anyway, though for x86, it might be different).
3339 * If we have a fixed return buffer register and are given it's index
3340 * we return the fixed return buffer register
3343 inline regNumber genMapIntRegArgNumToRegNum(unsigned argNum)
3345 if (hasFixedRetBuffReg() && (argNum == theFixedRetBuffArgNum()))
3347 return theFixedRetBuffReg();
3350 assert(argNum < ArrLen(intArgRegs));
3352 return intArgRegs[argNum];
3355 inline regNumber genMapFloatRegArgNumToRegNum(unsigned argNum)
3357 #ifndef _TARGET_X86_
3358 assert(argNum < ArrLen(fltArgRegs));
3360 return fltArgRegs[argNum];
3362 assert(!"no x86 float arg regs\n");
3367 __forceinline regNumber genMapRegArgNumToRegNum(unsigned argNum, var_types type)
3369 if (varTypeIsFloating(type))
3371 return genMapFloatRegArgNumToRegNum(argNum);
3375 return genMapIntRegArgNumToRegNum(argNum);
3379 /*****************************************************************************/
3380 /* Map a register argument number ("RegArgNum") to a register mask of the associated register.
3381 * Note that for floating-pointer registers, only the low register for a register pair
3382 * (for a double on ARM) is returned.
3385 inline regMaskTP genMapIntRegArgNumToRegMask(unsigned argNum)
3387 assert(argNum < ArrLen(intArgMasks));
3389 return intArgMasks[argNum];
3392 inline regMaskTP genMapFloatRegArgNumToRegMask(unsigned argNum)
3394 #ifndef _TARGET_X86_
3395 assert(argNum < ArrLen(fltArgMasks));
3397 return fltArgMasks[argNum];
3399 assert(!"no x86 float arg regs\n");
3404 __forceinline regMaskTP genMapArgNumToRegMask(unsigned argNum, var_types type)
3407 if (varTypeIsFloating(type))
3409 result = genMapFloatRegArgNumToRegMask(argNum);
3411 if (type == TYP_DOUBLE)
3413 assert((result & RBM_DBL_REGS) != 0);
3414 result |= (result << 1);
3420 result = genMapIntRegArgNumToRegMask(argNum);
3425 /*****************************************************************************/
3426 /* Map a register number ("RegNum") to a register argument number ("RegArgNum")
3427 * If we have a fixed return buffer register we return theFixedRetBuffArgNum
3430 inline unsigned genMapIntRegNumToRegArgNum(regNumber regNum)
3432 assert(genRegMask(regNum) & fullIntArgRegMask());
3438 #if MAX_REG_ARG >= 2
3441 #if MAX_REG_ARG >= 3
3444 #if MAX_REG_ARG >= 4
3447 #if MAX_REG_ARG >= 5
3450 #if MAX_REG_ARG >= 6
3453 #if MAX_REG_ARG >= 7
3456 #if MAX_REG_ARG >= 8
3467 // Check for the Arm64 fixed return buffer argument register
3468 if (hasFixedRetBuffReg() && (regNum == theFixedRetBuffReg()))
3470 return theFixedRetBuffArgNum();
3474 assert(!"invalid register arg register");
3480 inline unsigned genMapFloatRegNumToRegArgNum(regNumber regNum)
3482 assert(genRegMask(regNum) & RBM_FLTARG_REGS);
3485 return regNum - REG_F0;
3486 #elif defined(_TARGET_ARM64_)
3487 return regNum - REG_V0;
3488 #elif defined(UNIX_AMD64_ABI)
3489 return regNum - REG_FLTARG_0;
3492 #if MAX_FLOAT_REG_ARG >= 1
3497 #if MAX_REG_ARG >= 2
3500 #if MAX_REG_ARG >= 3
3503 #if MAX_REG_ARG >= 4
3506 #if MAX_REG_ARG >= 5
3514 assert(!"invalid register arg register");
3518 assert(!"flt reg args not allowed");
3524 inline unsigned genMapRegNumToRegArgNum(regNumber regNum, var_types type)
3526 if (varTypeIsFloating(type))
3528 return genMapFloatRegNumToRegArgNum(regNum);
3532 return genMapIntRegNumToRegArgNum(regNum);
3536 /*****************************************************************************/
3537 /* Return a register mask with the first 'numRegs' argument registers set.
3540 inline regMaskTP genIntAllRegArgMask(unsigned numRegs)
3542 assert(numRegs <= MAX_REG_ARG);
3544 regMaskTP result = RBM_NONE;
3545 for (unsigned i = 0; i < numRegs; i++)
3547 result |= intArgMasks[i];
3552 #if !FEATURE_STACK_FP_X87
3554 inline regMaskTP genFltAllRegArgMask(unsigned numRegs)
3556 assert(numRegs <= MAX_FLOAT_REG_ARG);
3558 regMaskTP result = RBM_NONE;
3559 for (unsigned i = 0; i < numRegs; i++)
3561 result |= fltArgMasks[i];
3566 #endif // !FEATURE_STACK_FP_X87
3569 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3570 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3572 XX Inline functions XX
3574 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3575 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3578 /*****************************************************************************
3580 * Update the current set of live variables based on the life set recorded
3581 * in the given expression tree node.
3584 template <bool ForCodeGen>
3585 inline void Compiler::compUpdateLife(GenTree* tree)
3587 // TODO-Cleanup: We shouldn't really be calling this more than once
3588 if (tree == compCurLifeTree)
3593 if (!tree->OperIsNonPhiLocal() && fgIsIndirOfAddrOfLocal(tree) == nullptr)
3598 compUpdateLifeVar<ForCodeGen>(tree);
3601 template <bool ForCodeGen>
3602 inline void Compiler::compUpdateLife(VARSET_VALARG_TP newLife)
3604 if (!VarSetOps::Equal(this, compCurLife, newLife))
3606 compChangeLife<ForCodeGen>(newLife);
3613 printf("Liveness not changing: %s ", VarSetOps::ToString(this, compCurLife));
3614 dumpConvertedVarSet(this, compCurLife);
3621 /*****************************************************************************
3623 * We stash cookies in basic blocks for the code emitter; this call retrieves
3624 * the cookie associated with the given basic block.
3627 inline void* emitCodeGetCookie(BasicBlock* block)
3630 return block->bbEmitCookie;
3634 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3635 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3637 XX Inline functions XX
3639 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3640 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3643 #if LOCAL_ASSERTION_PROP
3645 /*****************************************************************************
3647 * The following resets the value assignment table
3648 * used only during local assertion prop
3651 inline void Compiler::optAssertionReset(AssertionIndex limit)
3653 PREFAST_ASSUME(optAssertionCount <= optMaxAssertionCount);
3655 while (optAssertionCount > limit)
3657 AssertionIndex index = optAssertionCount;
3658 AssertionDsc* curAssertion = optGetAssertion(index);
3659 optAssertionCount--;
3660 unsigned lclNum = curAssertion->op1.lcl.lclNum;
3661 assert(lclNum < lvaTableCnt);
3662 BitVecOps::RemoveElemD(apTraits, GetAssertionDep(lclNum), index - 1);
3665 // Find the Copy assertions
3667 if ((curAssertion->assertionKind == OAK_EQUAL) && (curAssertion->op1.kind == O1K_LCLVAR) &&
3668 (curAssertion->op2.kind == O2K_LCLVAR_COPY))
3671 // op2.lcl.lclNum no longer depends upon this assertion
3673 lclNum = curAssertion->op2.lcl.lclNum;
3674 BitVecOps::RemoveElemD(apTraits, GetAssertionDep(lclNum), index - 1);
3677 while (optAssertionCount < limit)
3679 AssertionIndex index = ++optAssertionCount;
3680 AssertionDsc* curAssertion = optGetAssertion(index);
3681 unsigned lclNum = curAssertion->op1.lcl.lclNum;
3682 BitVecOps::AddElemD(apTraits, GetAssertionDep(lclNum), index - 1);
3685 // Check for Copy assertions
3687 if ((curAssertion->assertionKind == OAK_EQUAL) && (curAssertion->op1.kind == O1K_LCLVAR) &&
3688 (curAssertion->op2.kind == O2K_LCLVAR_COPY))
3691 // op2.lcl.lclNum now depends upon this assertion
3693 lclNum = curAssertion->op2.lcl.lclNum;
3694 BitVecOps::AddElemD(apTraits, GetAssertionDep(lclNum), index - 1);
3699 /*****************************************************************************
3701 * The following removes the i-th entry in the value assignment table
3702 * used only during local assertion prop
3705 inline void Compiler::optAssertionRemove(AssertionIndex index)
3708 assert(index <= optAssertionCount);
3709 PREFAST_ASSUME(optAssertionCount <= optMaxAssertionCount);
3711 AssertionDsc* curAssertion = optGetAssertion(index);
3713 // Two cases to consider if (index == optAssertionCount) then the last
3714 // entry in the table is to be removed and that happens automatically when
3715 // optAssertionCount is decremented and we can just clear the optAssertionDep bits
3716 // The other case is when index < optAssertionCount and here we overwrite the
3717 // index-th entry in the table with the data found at the end of the table
3718 // Since we are reordering the rable the optAssertionDep bits need to be recreated
3719 // using optAssertionReset(0) and optAssertionReset(newAssertionCount) will
3720 // correctly update the optAssertionDep bits
3722 if (index == optAssertionCount)
3724 unsigned lclNum = curAssertion->op1.lcl.lclNum;
3725 BitVecOps::RemoveElemD(apTraits, GetAssertionDep(lclNum), index - 1);
3728 // Check for Copy assertions
3730 if ((curAssertion->assertionKind == OAK_EQUAL) && (curAssertion->op1.kind == O1K_LCLVAR) &&
3731 (curAssertion->op2.kind == O2K_LCLVAR_COPY))
3734 // op2.lcl.lclNum no longer depends upon this assertion
3736 lclNum = curAssertion->op2.lcl.lclNum;
3737 BitVecOps::RemoveElemD(apTraits, GetAssertionDep(lclNum), index - 1);
3740 optAssertionCount--;
3744 AssertionDsc* lastAssertion = optGetAssertion(optAssertionCount);
3745 AssertionIndex newAssertionCount = optAssertionCount - 1;
3747 optAssertionReset(0); // This make optAssertionCount equal 0
3749 memcpy(curAssertion, // the entry to be removed
3750 lastAssertion, // last entry in the table
3751 sizeof(AssertionDsc));
3753 optAssertionReset(newAssertionCount);
3756 #endif // LOCAL_ASSERTION_PROP
3758 inline void Compiler::LoopDsc::AddModifiedField(Compiler* comp, CORINFO_FIELD_HANDLE fldHnd)
3760 if (lpFieldsModified == nullptr)
3763 new (comp->getAllocatorLoopHoist()) Compiler::LoopDsc::FieldHandleSet(comp->getAllocatorLoopHoist());
3765 lpFieldsModified->Set(fldHnd, true);
3768 inline void Compiler::LoopDsc::AddModifiedElemType(Compiler* comp, CORINFO_CLASS_HANDLE structHnd)
3770 if (lpArrayElemTypesModified == nullptr)
3772 lpArrayElemTypesModified =
3773 new (comp->getAllocatorLoopHoist()) Compiler::LoopDsc::ClassHandleSet(comp->getAllocatorLoopHoist());
3775 lpArrayElemTypesModified->Set(structHnd, true);
3778 inline void Compiler::LoopDsc::VERIFY_lpIterTree()
3781 assert(lpFlags & LPFLG_ITER);
3783 // iterTree should be "lcl <op>= const"
3787 assert(lpIterTree->OperIsAssignment());
3789 if (lpIterTree->OperGet() == GT_ASG)
3791 GenTree* lhs = lpIterTree->gtOp.gtOp1;
3792 GenTree* rhs = lpIterTree->gtOp.gtOp2;
3793 assert(lhs->OperGet() == GT_LCL_VAR);
3795 switch (rhs->gtOper)
3804 assert(!"Unknown operator for loop increment");
3806 assert(rhs->gtOp.gtOp1->OperGet() == GT_LCL_VAR);
3807 assert(rhs->gtOp.gtOp1->AsLclVarCommon()->GetLclNum() == lhs->AsLclVarCommon()->GetLclNum());
3808 assert(rhs->gtOp.gtOp2->OperGet() == GT_CNS_INT);
3812 assert(lpIterTree->gtOp.gtOp1->OperGet() == GT_LCL_VAR);
3813 assert(lpIterTree->gtOp.gtOp2->OperGet() == GT_CNS_INT);
3818 //-----------------------------------------------------------------------------
3820 inline unsigned Compiler::LoopDsc::lpIterVar()
3822 VERIFY_lpIterTree();
3823 return lpIterTree->gtOp.gtOp1->gtLclVarCommon.gtLclNum;
3826 //-----------------------------------------------------------------------------
3828 inline int Compiler::LoopDsc::lpIterConst()
3830 VERIFY_lpIterTree();
3831 if (lpIterTree->OperGet() == GT_ASG)
3833 GenTree* rhs = lpIterTree->gtOp.gtOp2;
3834 return (int)rhs->gtOp.gtOp2->gtIntCon.gtIconVal;
3838 return (int)lpIterTree->gtOp.gtOp2->gtIntCon.gtIconVal;
3842 //-----------------------------------------------------------------------------
3844 inline genTreeOps Compiler::LoopDsc::lpIterOper()
3846 VERIFY_lpIterTree();
3847 if (lpIterTree->OperGet() == GT_ASG)
3849 GenTree* rhs = lpIterTree->gtOp.gtOp2;
3850 return rhs->OperGet();
3854 return lpIterTree->OperGet();
3858 inline var_types Compiler::LoopDsc::lpIterOperType()
3860 VERIFY_lpIterTree();
3862 var_types type = lpIterTree->TypeGet();
3863 assert(genActualType(type) == TYP_INT);
3865 if ((lpIterTree->gtFlags & GTF_UNSIGNED) && type == TYP_INT)
3873 inline void Compiler::LoopDsc::VERIFY_lpTestTree()
3876 assert(lpFlags & LPFLG_ITER);
3879 genTreeOps oper = lpTestTree->OperGet();
3880 assert(GenTree::OperIsCompare(oper));
3882 GenTree* iterator = nullptr;
3883 GenTree* limit = nullptr;
3884 if ((lpTestTree->gtOp.gtOp2->gtOper == GT_LCL_VAR) && (lpTestTree->gtOp.gtOp2->gtFlags & GTF_VAR_ITERATOR) != 0)
3886 iterator = lpTestTree->gtOp.gtOp2;
3887 limit = lpTestTree->gtOp.gtOp1;
3889 else if ((lpTestTree->gtOp.gtOp1->gtOper == GT_LCL_VAR) &&
3890 (lpTestTree->gtOp.gtOp1->gtFlags & GTF_VAR_ITERATOR) != 0)
3892 iterator = lpTestTree->gtOp.gtOp1;
3893 limit = lpTestTree->gtOp.gtOp2;
3897 // one of the nodes has to be the iterator
3901 if (lpFlags & LPFLG_CONST_LIMIT)
3903 assert(limit->OperIsConst());
3905 if (lpFlags & LPFLG_VAR_LIMIT)
3907 assert(limit->OperGet() == GT_LCL_VAR);
3909 if (lpFlags & LPFLG_ARRLEN_LIMIT)
3911 assert(limit->OperGet() == GT_ARR_LENGTH);
3916 //-----------------------------------------------------------------------------
3918 inline bool Compiler::LoopDsc::lpIsReversed()
3920 VERIFY_lpTestTree();
3921 return ((lpTestTree->gtOp.gtOp2->gtOper == GT_LCL_VAR) &&
3922 (lpTestTree->gtOp.gtOp2->gtFlags & GTF_VAR_ITERATOR) != 0);
3925 //-----------------------------------------------------------------------------
3927 inline genTreeOps Compiler::LoopDsc::lpTestOper()
3929 VERIFY_lpTestTree();
3930 genTreeOps op = lpTestTree->OperGet();
3931 return lpIsReversed() ? GenTree::SwapRelop(op) : op;
3934 //-----------------------------------------------------------------------------
3936 inline GenTree* Compiler::LoopDsc::lpIterator()
3938 VERIFY_lpTestTree();
3940 return lpIsReversed() ? lpTestTree->gtOp.gtOp2 : lpTestTree->gtOp.gtOp1;
3943 //-----------------------------------------------------------------------------
3945 inline GenTree* Compiler::LoopDsc::lpLimit()
3947 VERIFY_lpTestTree();
3949 return lpIsReversed() ? lpTestTree->gtOp.gtOp1 : lpTestTree->gtOp.gtOp2;
3952 //-----------------------------------------------------------------------------
3954 inline int Compiler::LoopDsc::lpConstLimit()
3956 VERIFY_lpTestTree();
3957 assert(lpFlags & LPFLG_CONST_LIMIT);
3959 GenTree* limit = lpLimit();
3960 assert(limit->OperIsConst());
3961 return (int)limit->gtIntCon.gtIconVal;
3964 //-----------------------------------------------------------------------------
3966 inline unsigned Compiler::LoopDsc::lpVarLimit()
3968 VERIFY_lpTestTree();
3969 assert(lpFlags & LPFLG_VAR_LIMIT);
3971 GenTree* limit = lpLimit();
3972 assert(limit->OperGet() == GT_LCL_VAR);
3973 return limit->gtLclVarCommon.gtLclNum;
3976 //-----------------------------------------------------------------------------
3978 inline bool Compiler::LoopDsc::lpArrLenLimit(Compiler* comp, ArrIndex* index)
3980 VERIFY_lpTestTree();
3981 assert(lpFlags & LPFLG_ARRLEN_LIMIT);
3983 GenTree* limit = lpLimit();
3984 assert(limit->OperGet() == GT_ARR_LENGTH);
3986 // Check if we have a.length or a[i][j].length
3987 if (limit->gtArrLen.ArrRef()->gtOper == GT_LCL_VAR)
3989 index->arrLcl = limit->gtArrLen.ArrRef()->gtLclVarCommon.gtLclNum;
3993 // We have a[i].length, extract a[i] pattern.
3994 else if (limit->gtArrLen.ArrRef()->gtOper == GT_COMMA)
3996 return comp->optReconstructArrIndex(limit->gtArrLen.ArrRef(), index, BAD_VAR_NUM);
4001 /*****************************************************************************
4002 * Is "var" assigned in the loop "lnum" ?
4005 inline bool Compiler::optIsVarAssgLoop(unsigned lnum, unsigned var)
4007 assert(lnum < optLoopCount);
4008 if (var < lclMAX_ALLSET_TRACKED)
4010 ALLVARSET_TP vs(AllVarSetOps::MakeSingleton(this, var));
4011 return optIsSetAssgLoop(lnum, vs) != 0;
4015 return optIsVarAssigned(optLoopTable[lnum].lpHead->bbNext, optLoopTable[lnum].lpBottom, nullptr, var);
4019 /*****************************************************************************
4020 * If the tree is a tracked local variable, return its LclVarDsc ptr.
4023 inline LclVarDsc* Compiler::optIsTrackedLocal(GenTree* tree)
4028 if (tree->gtOper != GT_LCL_VAR)
4033 lclNum = tree->gtLclVarCommon.gtLclNum;
4035 assert(lclNum < lvaCount);
4036 varDsc = lvaTable + lclNum;
4038 /* if variable not tracked, return NULL */
4039 if (!varDsc->lvTracked)
4048 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4049 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4051 XX Optimization activation rules XX
4053 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4054 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4057 // are we compiling for fast code, or are we compiling for blended code and
4059 // We return true for BLENDED_CODE if the Block executes more than BB_LOOP_WEIGHT/2
4060 inline bool Compiler::optFastCodeOrBlendedLoop(BasicBlock::weight_t bbWeight)
4062 return (compCodeOpt() == FAST_CODE) ||
4063 ((compCodeOpt() == BLENDED_CODE) && (bbWeight > (BB_LOOP_WEIGHT / 2 * BB_UNITY_WEIGHT)));
4066 // are we running on a Intel Pentium 4?
4067 inline bool Compiler::optPentium4(void)
4069 return (info.genCPU == CPU_X86_PENTIUM_4);
4072 // should we use add/sub instead of inc/dec? (faster on P4, but increases size)
4073 inline bool Compiler::optAvoidIncDec(BasicBlock::weight_t bbWeight)
4075 return optPentium4() && optFastCodeOrBlendedLoop(bbWeight);
4078 // should we try to replace integer multiplication with lea/add/shift sequences?
4079 inline bool Compiler::optAvoidIntMult(void)
4081 return (compCodeOpt() != SMALL_CODE);
4085 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4086 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4088 XX Inline functions XX
4090 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4091 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4094 extern var_types JITtype2varType(CorInfoType type);
4096 #include "ee_il_dll.hpp"
4098 inline CORINFO_METHOD_HANDLE Compiler::eeFindHelper(unsigned helper)
4100 assert(helper < CORINFO_HELP_COUNT);
4102 /* Helpers are marked by the fact that they are odd numbers
4103 * force this to be an odd number (will shift it back to extract) */
4105 return ((CORINFO_METHOD_HANDLE)(size_t)((helper << 2) + 1));
4108 inline CorInfoHelpFunc Compiler::eeGetHelperNum(CORINFO_METHOD_HANDLE method)
4110 // Helpers are marked by the fact that they are odd numbers
4111 if (!(((size_t)method) & 1))
4113 return (CORINFO_HELP_UNDEF);
4115 return ((CorInfoHelpFunc)(((size_t)method) >> 2));
4118 inline Compiler::fgWalkResult Compiler::CountSharedStaticHelper(GenTree** pTree, fgWalkData* data)
4120 if (Compiler::IsSharedStaticHelper(*pTree))
4122 int* pCount = (int*)data->pCallbackData;
4126 return WALK_CONTINUE;
4129 // TODO-Cleanup: Replace calls to IsSharedStaticHelper with new HelperCallProperties
4132 inline bool Compiler::IsSharedStaticHelper(GenTree* tree)
4134 if (tree->gtOper != GT_CALL || tree->gtCall.gtCallType != CT_HELPER)
4139 CorInfoHelpFunc helper = eeGetHelperNum(tree->gtCall.gtCallMethHnd);
4142 // More helpers being added to IsSharedStaticHelper (that have similar behaviors but are not true
4143 // ShareStaticHelperts)
4144 helper == CORINFO_HELP_STRCNS || helper == CORINFO_HELP_BOX ||
4146 // helpers being added to IsSharedStaticHelper
4147 helper == CORINFO_HELP_GETSTATICFIELDADDR_CONTEXT || helper == CORINFO_HELP_GETSTATICFIELDADDR_TLS ||
4148 helper == CORINFO_HELP_GETGENERICS_GCSTATIC_BASE || helper == CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE ||
4149 helper == CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE ||
4150 helper == CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE ||
4152 helper == CORINFO_HELP_GETSHARED_GCSTATIC_BASE || helper == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE ||
4153 helper == CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR ||
4154 helper == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR ||
4155 helper == CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS ||
4156 helper == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS ||
4157 helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE ||
4158 helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE ||
4159 helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR ||
4160 helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR ||
4161 helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS ||
4162 helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS ||
4163 #ifdef FEATURE_READYTORUN_COMPILER
4164 helper == CORINFO_HELP_READYTORUN_STATIC_BASE || helper == CORINFO_HELP_READYTORUN_GENERIC_STATIC_BASE ||
4166 helper == CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS;
4168 // See above TODO-Cleanup
4169 bool result2 = s_helperCallProperties.IsPure(helper) && s_helperCallProperties.NonNullReturn(helper);
4170 assert (result1 == result2);
4175 inline bool Compiler::IsTreeAlwaysHoistable(GenTree* tree)
4177 if (IsSharedStaticHelper(tree))
4179 return (GTF_CALL_HOISTABLE & tree->gtFlags) ? true : false;
4187 inline bool Compiler::IsGcSafePoint(GenTree* tree)
4191 GenTreeCall* call = tree->AsCall();
4192 if (!call->IsFastTailCall())
4194 if (call->gtCallType == CT_INDIRECT)
4198 else if (call->gtCallType == CT_USER_FUNC)
4200 if ((call->gtCallMoreFlags & GTF_CALL_M_NOGCCHECK) == 0)
4205 // otherwise we have a CT_HELPER
4213 // Note that we want to have two special FIELD_HANDLES that will both
4214 // be considered non-Data Offset handles
4216 // The special values that we use are FLD_GLOBAL_DS and FLD_GLOBAL_FS
4219 inline bool jitStaticFldIsGlobAddr(CORINFO_FIELD_HANDLE fldHnd)
4221 return (fldHnd == FLD_GLOBAL_DS || fldHnd == FLD_GLOBAL_FS);
4224 #if defined(DEBUG) || defined(FEATURE_JIT_METHOD_PERF) || defined(FEATURE_SIMD) || defined(FEATURE_TRACELOGGING)
4226 inline bool Compiler::eeIsNativeMethod(CORINFO_METHOD_HANDLE method)
4228 return ((((size_t)method) & 0x2) == 0x2);
4231 inline CORINFO_METHOD_HANDLE Compiler::eeGetMethodHandleForNative(CORINFO_METHOD_HANDLE method)
4233 assert((((size_t)method) & 0x3) == 0x2);
4234 return (CORINFO_METHOD_HANDLE)(((size_t)method) & ~0x3);
4238 inline CORINFO_METHOD_HANDLE Compiler::eeMarkNativeTarget(CORINFO_METHOD_HANDLE method)
4240 assert((((size_t)method) & 0x3) == 0);
4241 if (method == nullptr)
4247 return (CORINFO_METHOD_HANDLE)(((size_t)method) | 0x2);
4252 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4253 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4255 XX Inline functions XX
4257 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4258 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4262 inline bool Compiler::compStressCompile(compStressArea stressArea, unsigned weightPercentage)
4268 inline ArenaAllocator* Compiler::compGetAllocator()
4270 return compAllocator;
4273 /*****************************************************************************
4275 * Allocate memory from the no-release allocator. All such memory will be
4276 * freed up simulataneously at the end of the procedure
4281 inline void* Compiler::compGetMem(size_t sz, CompMemKind cmk)
4285 #if MEASURE_MEM_ALLOC
4286 genMemStats.AddAlloc(sz, cmk);
4289 return compAllocator->allocateMemory(sz);
4294 // Wrapper for Compiler::compGetMem that can be forward-declared for use in template
4295 // types which Compiler depends on but which need to allocate heap memory.
4296 inline void* compGetMem(Compiler* comp, size_t sz)
4298 return comp->compGetMem(sz);
4301 /*****************************************************************************
4303 * A common memory allocation for arrays of structures involves the
4304 * multiplication of the number of elements with the size of each element.
4305 * If this computation overflows, then the memory allocation might succeed,
4306 * but not allocate sufficient memory for all the elements. This can cause
4307 * us to overwrite the allocation, and AV or worse, corrupt memory.
4309 * This method checks for overflow, and succeeds only when it detects
4310 * that there's no overflow. It should be cheap, because when inlined with
4311 * a constant elemSize, the division should be done in compile time, and so
4312 * at run time we simply have a check of numElem against some number (this
4313 * is why we __forceinline).
4316 #define MAX_MEMORY_PER_ALLOCATION (512 * 1024 * 1024)
4318 __forceinline void* Compiler::compGetMemArray(size_t numElem, size_t elemSize, CompMemKind cmk)
4320 if (numElem > (MAX_MEMORY_PER_ALLOCATION / elemSize))
4325 return compGetMem(numElem * elemSize, cmk);
4328 /******************************************************************************
4330 * Roundup the allocated size so that if this memory block is aligned,
4331 * then the next block allocated too will be aligned.
4332 * The JIT will always try to keep all the blocks aligned.
4335 inline void Compiler::compFreeMem(void* ptr)
4339 inline bool Compiler::compIsProfilerHookNeeded()
4341 #ifdef PROFILING_SUPPORTED
4342 return compProfilerHookNeeded
4343 // IL stubs are excluded by VM and we need to do the same even running
4344 // under a complus env hook to generate profiler hooks
4345 || (opts.compJitELTHookEnabled && !opts.jitFlags->IsSet(JitFlags::JIT_FLAG_IL_STUB));
4346 #else // !PROFILING_SUPPORTED
4348 #endif // !PROFILING_SUPPORTED
4351 /*****************************************************************************
4353 * Check for the special case where the object is the constant 0.
4354 * As we can't even fold the tree (null+fldOffs), we are left with
4355 * op1 and op2 both being a constant. This causes lots of problems.
4356 * We simply grab a temp and assign 0 to it and use it in place of the NULL.
4359 inline GenTree* Compiler::impCheckForNullPointer(GenTree* obj)
4361 /* If it is not a GC type, we will be able to fold it.
4362 So don't need to do anything */
4364 if (!varTypeIsGC(obj->TypeGet()))
4369 if (obj->gtOper == GT_CNS_INT)
4371 assert(obj->gtType == TYP_REF || obj->gtType == TYP_BYREF);
4373 // We can see non-zero byrefs for RVA statics.
4374 if (obj->gtIntCon.gtIconVal != 0)
4376 assert(obj->gtType == TYP_BYREF);
4380 unsigned tmp = lvaGrabTemp(true DEBUGARG("CheckForNullPointer"));
4382 // We don't need to spill while appending as we are only assigning
4383 // NULL to a freshly-grabbed temp.
4385 impAssignTempGen(tmp, obj, (unsigned)CHECK_SPILL_NONE);
4387 obj = gtNewLclvNode(tmp, obj->gtType);
4393 /*****************************************************************************
4395 * Check for the special case where the object is the methods original 'this' pointer.
4396 * Note that, the original 'this' pointer is always local var 0 for non-static method,
4397 * even if we might have created the copy of 'this' pointer in lvaArg0Var.
4400 inline bool Compiler::impIsThis(GenTree* obj)
4402 if (compIsForInlining())
4404 return impInlineInfo->InlinerCompiler->impIsThis(obj);
4408 return ((obj != nullptr) && (obj->gtOper == GT_LCL_VAR) && lvaIsOriginalThisArg(obj->gtLclVarCommon.gtLclNum));
4412 /*****************************************************************************
4414 * Check to see if the delegate is created using "LDFTN <TOK>" or not.
4417 inline bool Compiler::impIsLDFTN_TOKEN(const BYTE* delegateCreateStart, const BYTE* newobjCodeAddr)
4419 assert(newobjCodeAddr[0] == CEE_NEWOBJ);
4420 return (newobjCodeAddr - delegateCreateStart == 6 && // LDFTN <TOK> takes 6 bytes
4421 delegateCreateStart[0] == CEE_PREFIX1 && delegateCreateStart[1] == (CEE_LDFTN & 0xFF));
4424 /*****************************************************************************
4426 * Check to see if the delegate is created using "DUP LDVIRTFTN <TOK>" or not.
4429 inline bool Compiler::impIsDUP_LDVIRTFTN_TOKEN(const BYTE* delegateCreateStart, const BYTE* newobjCodeAddr)
4431 assert(newobjCodeAddr[0] == CEE_NEWOBJ);
4432 return (newobjCodeAddr - delegateCreateStart == 7 && // DUP LDVIRTFTN <TOK> takes 6 bytes
4433 delegateCreateStart[0] == CEE_DUP && delegateCreateStart[1] == CEE_PREFIX1 &&
4434 delegateCreateStart[2] == (CEE_LDVIRTFTN & 0xFF));
4436 /*****************************************************************************
4438 * Returns true if the compiler instance is created for import only (verification).
4441 inline bool Compiler::compIsForImportOnly()
4443 return opts.jitFlags->IsSet(JitFlags::JIT_FLAG_IMPORT_ONLY);
4446 /*****************************************************************************
4448 * Returns true if the compiler instance is created for inlining.
4451 inline bool Compiler::compIsForInlining()
4453 return (impInlineInfo != nullptr);
4456 /*****************************************************************************
4458 * Check the inline result field in the compiler to see if inlining failed or not.
4461 inline bool Compiler::compDonotInline()
4463 if (compIsForInlining())
4465 assert(compInlineResult != nullptr);
4466 return compInlineResult->IsFailure();
4474 inline bool Compiler::impIsPrimitive(CorInfoType jitType)
4476 return ((CORINFO_TYPE_BOOL <= jitType && jitType <= CORINFO_TYPE_DOUBLE) || jitType == CORINFO_TYPE_PTR);
4479 /*****************************************************************************
4481 * Get the promotion type of a struct local.
4484 inline Compiler::lvaPromotionType Compiler::lvaGetPromotionType(const LclVarDsc* varDsc)
4486 assert(!varDsc->lvPromoted || varTypeIsPromotable(varDsc) || varDsc->lvUnusedStruct);
4488 if (!varDsc->lvPromoted)
4490 // no struct promotion for this LclVar
4491 return PROMOTION_TYPE_NONE;
4493 if (varDsc->lvDoNotEnregister)
4495 // The struct is not enregistered
4496 return PROMOTION_TYPE_DEPENDENT;
4498 if (!varDsc->lvIsParam)
4500 // The struct is a register candidate
4501 return PROMOTION_TYPE_INDEPENDENT;
4504 // Has struct promotion for arguments been disabled using COMPlus_JitNoStructPromotion=2
4505 if (fgNoStructParamPromotion)
4507 // The struct parameter is not enregistered
4508 return PROMOTION_TYPE_DEPENDENT;
4511 // We have a parameter that could be enregistered
4512 CLANG_FORMAT_COMMENT_ANCHOR;
4514 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
4516 // The struct parameter is a register candidate
4517 return PROMOTION_TYPE_INDEPENDENT;
4519 // The struct parameter is not enregistered
4520 return PROMOTION_TYPE_DEPENDENT;
4524 /*****************************************************************************
4526 * Get the promotion type of a struct local.
4529 inline Compiler::lvaPromotionType Compiler::lvaGetPromotionType(unsigned varNum)
4531 assert(varNum < lvaCount);
4532 return lvaGetPromotionType(&lvaTable[varNum]);
4535 /*****************************************************************************
4537 * Given a field local, get the promotion type of its parent struct local.
4540 inline Compiler::lvaPromotionType Compiler::lvaGetParentPromotionType(const LclVarDsc* varDsc)
4542 assert(varDsc->lvIsStructField);
4543 assert(varDsc->lvParentLcl < lvaCount);
4545 lvaPromotionType promotionType = lvaGetPromotionType(varDsc->lvParentLcl);
4546 assert(promotionType != PROMOTION_TYPE_NONE);
4547 return promotionType;
4550 /*****************************************************************************
4552 * Given a field local, get the promotion type of its parent struct local.
4555 inline Compiler::lvaPromotionType Compiler::lvaGetParentPromotionType(unsigned varNum)
4557 assert(varNum < lvaCount);
4558 return lvaGetParentPromotionType(&lvaTable[varNum]);
4561 /*****************************************************************************
4563 * Return true if the local is a field local of a promoted struct of type PROMOTION_TYPE_DEPENDENT.
4564 * Return false otherwise.
4567 inline bool Compiler::lvaIsFieldOfDependentlyPromotedStruct(const LclVarDsc* varDsc)
4569 if (!varDsc->lvIsStructField)
4574 lvaPromotionType promotionType = lvaGetParentPromotionType(varDsc);
4575 if (promotionType == PROMOTION_TYPE_DEPENDENT)
4580 assert(promotionType == PROMOTION_TYPE_INDEPENDENT);
4584 //------------------------------------------------------------------------
4585 // lvaIsGCTracked: Determine whether this var should be reported
4586 // as tracked for GC purposes.
4589 // varDsc - the LclVarDsc for the var in question.
4592 // Returns true if the variable should be reported as tracked in the GC info.
4595 // This never returns true for struct variables, even if they are tracked.
4596 // This is because struct variables are never tracked as a whole for GC purposes.
4597 // It is up to the caller to ensure that the fields of struct variables are
4598 // correctly tracked.
4599 // On Amd64, we never GC-track fields of dependently promoted structs, even
4600 // though they may be tracked for optimization purposes.
4601 // It seems that on x86 and arm, we simply don't track these
4602 // fields, though I have not verified that. I attempted to make these GC-tracked,
4603 // but there was too much logic that depends on these being untracked, so changing
4604 // this would require non-trivial effort.
4606 inline bool Compiler::lvaIsGCTracked(const LclVarDsc* varDsc)
4608 if (varDsc->lvTracked && (varDsc->lvType == TYP_REF || varDsc->lvType == TYP_BYREF))
4610 // Stack parameters are always untracked w.r.t. GC reportings
4611 const bool isStackParam = varDsc->lvIsParam && !varDsc->lvIsRegArg;
4612 #ifdef _TARGET_AMD64_
4613 return !isStackParam && !lvaIsFieldOfDependentlyPromotedStruct(varDsc);
4614 #else // !_TARGET_AMD64_
4615 return !isStackParam;
4616 #endif // !_TARGET_AMD64_
4624 inline void Compiler::EndPhase(Phases phase)
4626 #if defined(FEATURE_JIT_METHOD_PERF)
4627 if (pCompJitTimer != nullptr)
4629 pCompJitTimer->EndPhase(this, phase);
4633 fgDumpFlowGraph(phase);
4634 #endif // DUMP_FLOWGRAPHS
4635 previousCompletedPhase = phase;
4639 if ((*dumpIRPhase == L'*') || (wcscmp(dumpIRPhase, PhaseShortNames[phase]) == 0))
4642 printf("IR after %s (switch: %ls)\n", PhaseEnums[phase], PhaseShortNames[phase]);
4649 else if (dumpIRTrees)
4654 // If we are just dumping a single method and we have a request to exit
4655 // after dumping, do so now.
4657 if (dumpIRExit && ((*dumpIRPhase != L'*') || (phase == PHASE_EMIT_GCEH)))
4666 /*****************************************************************************/
4667 #if MEASURE_CLRAPI_CALLS
4669 inline void Compiler::CLRApiCallEnter(unsigned apix)
4671 if (pCompJitTimer != nullptr)
4673 pCompJitTimer->CLRApiCallEnter(apix);
4676 inline void Compiler::CLRApiCallLeave(unsigned apix)
4678 if (pCompJitTimer != nullptr)
4680 pCompJitTimer->CLRApiCallLeave(apix);
4684 inline void Compiler::CLR_API_Enter(API_ICorJitInfo_Names ename)
4686 CLRApiCallEnter(ename);
4689 inline void Compiler::CLR_API_Leave(API_ICorJitInfo_Names ename)
4691 CLRApiCallLeave(ename);
4694 #endif // MEASURE_CLRAPI_CALLS
4696 //------------------------------------------------------------------------------
4697 // fgStructTempNeedsExplicitZeroInit : Check whether temp struct needs
4698 // explicit zero initialization in this basic block.
4701 // varDsc - struct local var description
4702 // block - basic block to check
4705 // true if the struct temp needs explicit zero-initialization in this basic block;
4709 // Structs with GC pointer fields are fully zero-initialized in the prolog if compInitMem is true.
4710 // Therefore, we don't need to insert zero-initialization if this block is not in a loop.
4712 bool Compiler::fgStructTempNeedsExplicitZeroInit(LclVarDsc* varDsc, BasicBlock* block)
4714 bool containsGCPtr = (varDsc->lvStructGcCount > 0);
4715 return (!containsGCPtr || !info.compInitMem || ((block->bbFlags & BBF_BACKWARD_JUMP) != 0));
4718 /*****************************************************************************/
4719 bool Compiler::fgExcludeFromSsa(unsigned lclNum)
4723 return true; // If we're doing MinOpts, no SSA vars.
4726 LclVarDsc* varDsc = &lvaTable[lclNum];
4728 if (varDsc->lvAddrExposed)
4730 return true; // We exclude address-exposed variables.
4732 if (!varDsc->lvTracked)
4734 return true; // SSA is only done for tracked variables
4736 // lvPromoted structs are never tracked...
4737 assert(!varDsc->lvPromoted);
4739 if (varDsc->lvOverlappingFields)
4741 return true; // Don't use SSA on structs that have overlapping fields
4744 if (varDsc->lvIsStructField && (lvaGetParentPromotionType(lclNum) != PROMOTION_TYPE_INDEPENDENT))
4746 // SSA must exclude struct fields that are not independent
4747 // - because we don't model the struct assignment properly when multiple fields can be assigned by one struct
4749 // - SSA doesn't allow a single node to contain multiple SSA definitions.
4750 // - and PROMOTION_TYPE_DEPENDEDNT fields are never candidates for a register.
4752 // Example mscorlib method: CompatibilitySwitches:IsCompatibilitySwitchSet
4756 // otherwise this variable is *not* excluded for SSA
4760 /*****************************************************************************/
4761 ValueNum Compiler::GetUseAsgDefVNOrTreeVN(GenTree* op)
4763 if (op->gtFlags & GTF_VAR_USEASG)
4765 unsigned lclNum = op->AsLclVarCommon()->GetLclNum();
4766 unsigned ssaNum = GetSsaNumForLocalVarDef(op);
4767 return lvaTable[lclNum].GetPerSsaData(ssaNum)->m_vnPair.GetConservative();
4771 return op->gtVNPair.GetConservative();
4775 /*****************************************************************************/
4776 unsigned Compiler::GetSsaNumForLocalVarDef(GenTree* lcl)
4778 // Address-taken variables don't have SSA numbers.
4779 if (fgExcludeFromSsa(lcl->AsLclVarCommon()->gtLclNum))
4781 return SsaConfig::RESERVED_SSA_NUM;
4784 if (lcl->gtFlags & GTF_VAR_USEASG)
4786 // It's an "lcl op= rhs" assignment. "lcl" is both used and defined here;
4787 // we've chosen in this case to annotate "lcl" with the SSA number (and VN) of the use,
4788 // and to store the SSA number of the def in a side table.
4790 // In case of a remorph (fgMorph) in CSE/AssertionProp after SSA phase, there
4791 // wouldn't be an entry for the USEASG portion of the indir addr, return
4793 if (!GetOpAsgnVarDefSsaNums()->Lookup(lcl, &ssaNum))
4795 return SsaConfig::RESERVED_SSA_NUM;
4801 return lcl->AsLclVarCommon()->gtSsaNum;
4805 template <typename TVisitor>
4806 void GenTree::VisitOperands(TVisitor visitor)
4813 case GT_LCL_VAR_ADDR:
4814 case GT_LCL_FLD_ADDR:
4823 case GT_MEMORYBARRIER:
4828 case GT_START_NONGC:
4830 #if !FEATURE_EH_FUNCLETS
4832 #endif // !FEATURE_EH_FUNCLETS
4834 #ifndef LEGACY_BACKEND
4836 #endif // LEGACY_BACKEND
4839 case GT_CLS_VAR_ADDR:
4843 case GT_PINVOKE_PROLOG:
4844 case GT_PINVOKE_EPILOG:
4848 // Unary operators with an optional operand
4852 if (this->AsUnOp()->gtOp1 == nullptr)
4858 // Standard unary operators
4859 case GT_STORE_LCL_VAR:
4860 case GT_STORE_LCL_FLD:
4882 #if defined(_TARGET_ARM_) && !defined(LEGACY_BACKEND)
4883 case GT_PUTARG_SPLIT:
4886 visitor(this->AsUnOp()->gtOp1);
4891 assert(this->AsUnOp()->gtOp1 != nullptr);
4892 this->AsUnOp()->gtOp1->VisitListOperands(visitor);
4896 VisitListOperands(visitor);
4901 if (this->AsSIMD()->gtSIMDIntrinsicID == SIMDIntrinsicInitN)
4903 assert(this->AsSIMD()->gtOp1 != nullptr);
4904 this->AsSIMD()->gtOp1->VisitListOperands(visitor);
4908 VisitBinOpOperands<TVisitor>(visitor);
4911 #endif // FEATURE_SIMD
4913 #ifdef FEATURE_HW_INTRINSICS
4914 case GT_HWIntrinsic:
4915 if ((this->AsHWIntrinsic()->gtOp1 != nullptr) && this->AsHWIntrinsic()->gtOp1->OperIsList())
4917 this->AsHWIntrinsic()->gtOp1->VisitListOperands(visitor);
4921 VisitBinOpOperands<TVisitor>(visitor);
4924 #endif // FEATURE_HW_INTRINSICS
4929 GenTreeCmpXchg* const cmpXchg = this->AsCmpXchg();
4930 if (visitor(cmpXchg->gtOpLocation) == VisitResult::Abort)
4934 if (visitor(cmpXchg->gtOpValue) == VisitResult::Abort)
4938 visitor(cmpXchg->gtOpComparand);
4942 case GT_ARR_BOUNDS_CHECK:
4945 #endif // FEATURE_SIMD
4946 #ifdef FEATURE_HW_INTRINSICS
4947 case GT_HW_INTRINSIC_CHK:
4948 #endif // FEATURE_HW_INTRINSICS
4950 GenTreeBoundsChk* const boundsChk = this->AsBoundsChk();
4951 if (visitor(boundsChk->gtIndex) == VisitResult::Abort)
4955 visitor(boundsChk->gtArrLen);
4960 if (this->AsField()->gtFldObj != nullptr)
4962 visitor(this->AsField()->gtFldObj);
4967 if (this->AsStmt()->gtStmtExpr != nullptr)
4969 visitor(this->AsStmt()->gtStmtExpr);
4975 GenTreeArrElem* const arrElem = this->AsArrElem();
4976 if (visitor(arrElem->gtArrObj) == VisitResult::Abort)
4980 for (unsigned i = 0; i < arrElem->gtArrRank; i++)
4982 if (visitor(arrElem->gtArrInds[i]) == VisitResult::Abort)
4992 GenTreeArrOffs* const arrOffs = this->AsArrOffs();
4993 if (visitor(arrOffs->gtOffset) == VisitResult::Abort)
4997 if (visitor(arrOffs->gtIndex) == VisitResult::Abort)
5001 visitor(arrOffs->gtArrObj);
5007 GenTreeDynBlk* const dynBlock = this->AsDynBlk();
5008 if (visitor(dynBlock->gtOp1) == VisitResult::Abort)
5012 visitor(dynBlock->gtDynamicSize);
5016 case GT_STORE_DYN_BLK:
5018 GenTreeDynBlk* const dynBlock = this->AsDynBlk();
5019 if (visitor(dynBlock->gtOp1) == VisitResult::Abort)
5023 if (visitor(dynBlock->gtOp2) == VisitResult::Abort)
5027 visitor(dynBlock->gtDynamicSize);
5033 GenTreeCall* const call = this->AsCall();
5034 if ((call->gtCallObjp != nullptr) && (visitor(call->gtCallObjp) == VisitResult::Abort))
5038 if ((call->gtCallArgs != nullptr) && (call->gtCallArgs->VisitListOperands(visitor) == VisitResult::Abort))
5042 if ((call->gtCallLateArgs != nullptr) &&
5043 (call->gtCallLateArgs->VisitListOperands(visitor)) == VisitResult::Abort)
5047 if (call->gtCallType == CT_INDIRECT)
5049 if ((call->gtCallCookie != nullptr) && (visitor(call->gtCallCookie) == VisitResult::Abort))
5053 if ((call->gtCallAddr != nullptr) && (visitor(call->gtCallAddr) == VisitResult::Abort))
5058 if ((call->gtControlExpr != nullptr))
5060 visitor(call->gtControlExpr);
5067 assert(this->OperIsBinary());
5068 VisitBinOpOperands<TVisitor>(visitor);
5073 template <typename TVisitor>
5074 GenTree::VisitResult GenTree::VisitListOperands(TVisitor visitor)
5076 for (GenTreeArgList* node = this->AsArgList(); node != nullptr; node = node->Rest())
5078 if (visitor(node->gtOp1) == VisitResult::Abort)
5080 return VisitResult::Abort;
5084 return VisitResult::Continue;
5087 template <typename TVisitor>
5088 void GenTree::VisitBinOpOperands(TVisitor visitor)
5090 assert(this->OperIsBinary());
5092 GenTreeOp* const op = this->AsOp();
5094 GenTree* const op1 = op->gtOp1;
5095 if ((op1 != nullptr) && (visitor(op1) == VisitResult::Abort))
5100 GenTree* const op2 = op->gtOp2;
5107 /*****************************************************************************
5110 * Note that compGetMem is an arena allocator that returns memory that is
5111 * not zero-initialized and can contain data from a prior allocation lifetime.
5114 inline void* __cdecl operator new(size_t sz, Compiler* context, CompMemKind cmk)
5116 return context->compGetMem(sz, cmk);
5119 inline void* __cdecl operator new[](size_t sz, Compiler* context, CompMemKind cmk)
5121 return context->compGetMem(sz, cmk);
5124 inline void* __cdecl operator new(size_t sz, void* p, const jitstd::placement_t& /* syntax_difference */)
5129 /*****************************************************************************/
5133 inline void printRegMask(regMaskTP mask)
5135 printf(REG_MASK_ALL_FMT, mask);
5138 inline char* regMaskToString(regMaskTP mask, Compiler* context)
5140 const size_t cchRegMask = 24;
5141 char* regmask = new (context, CMK_Unknown) char[cchRegMask];
5143 sprintf_s(regmask, cchRegMask, REG_MASK_ALL_FMT, mask);
5148 inline void printRegMaskInt(regMaskTP mask)
5150 printf(REG_MASK_INT_FMT, (mask & RBM_ALLINT));
5153 inline char* regMaskIntToString(regMaskTP mask, Compiler* context)
5155 const size_t cchRegMask = 24;
5156 char* regmask = new (context, CMK_Unknown) char[cchRegMask];
5158 sprintf_s(regmask, cchRegMask, REG_MASK_INT_FMT, (mask & RBM_ALLINT));
5165 inline static bool StructHasOverlappingFields(DWORD attribs)
5167 return ((attribs & CORINFO_FLG_OVERLAPPING_FIELDS) != 0);
5170 inline static bool StructHasCustomLayout(DWORD attribs)
5172 return ((attribs & CORINFO_FLG_CUSTOMLAYOUT) != 0);
5175 /*****************************************************************************
5176 * This node should not be referenced by anyone now. Set its values to garbage
5177 * to catch extra references
5180 inline void DEBUG_DESTROY_NODE(GenTree* tree)
5183 // printf("DEBUG_DESTROY_NODE for [0x%08x]\n", tree);
5185 // Save gtOper in case we want to find out what this node was
5186 tree->gtOperSave = tree->gtOper;
5188 tree->gtType = TYP_UNDEF;
5189 tree->gtFlags |= 0xFFFFFFFF & ~GTF_NODE_MASK;
5190 if (tree->OperIsSimple())
5192 tree->gtOp.gtOp1 = tree->gtOp.gtOp2 = nullptr;
5194 // Must do this last, because the "gtOp" check above will fail otherwise.
5195 // Don't call SetOper, because GT_COUNT is not a valid value
5196 tree->gtOper = GT_COUNT;
5200 /*****************************************************************************/
5201 #endif //_COMPILER_HPP_
5202 /*****************************************************************************/