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 * Given a value that has exactly one bit set, return the position of that
176 * bit, in other words return the logarithm in base 2 of the given value.
178 inline unsigned genLog2(unsigned value)
180 return BitPosition(value);
183 // Given an unsigned 64-bit value, returns the lower 32-bits in unsigned format
185 inline unsigned ulo32(unsigned __int64 value)
187 return static_cast<unsigned>(value);
190 // Given an unsigned 64-bit value, returns the upper 32-bits in unsigned format
192 inline unsigned uhi32(unsigned __int64 value)
194 return static_cast<unsigned>(value >> 32);
197 /*****************************************************************************
199 * Given a value that has exactly one bit set, return the position of that
200 * bit, in other words return the logarithm in base 2 of the given value.
203 inline unsigned genLog2(unsigned __int64 value)
205 unsigned lo32 = ulo32(value);
206 unsigned hi32 = uhi32(value);
211 return genLog2(lo32);
215 return genLog2(hi32) + 32;
219 /*****************************************************************************
221 * Return the lowest bit that is set in the given register mask.
224 inline regMaskTP genFindLowestReg(regMaskTP value)
226 return (regMaskTP)genFindLowestBit(value);
229 /*****************************************************************************
231 * A rather simple routine that counts the number of bits in a given number.
234 template <typename T>
235 inline unsigned genCountBits(T bits)
242 bits -= genFindLowestBit(bits);
248 /*****************************************************************************
250 * Given 3 masks value, end, start, returns the bits of value between start
251 * and end (exclusive).
253 * value[bitNum(end) - 1, bitNum(start) + 1]
256 inline unsigned __int64 BitsBetween(unsigned __int64 value, unsigned __int64 end, unsigned __int64 start)
260 assert((start & (start - 1)) == 0);
261 assert((end & (end - 1)) == 0);
263 return value & ~((start - 1) | start) & // Ones to the left of set bit in the start mask.
264 (end - 1); // Ones to the right of set bit in the end mask.
267 /*****************************************************************************/
269 inline bool jitIsScaleIndexMul(size_t val)
284 // Returns "tree" iff "val" is a valid addressing mode scale shift amount on
285 // the target architecture.
286 inline bool jitIsScaleIndexShift(ssize_t val)
288 // It happens that this is the right test for all our current targets: x86, x64 and ARM.
289 // This test would become target-dependent if we added a new target with a different constraint.
290 return 0 < val && val < 4;
293 /*****************************************************************************
294 * Returns true if value is between [start..end).
295 * The comparison is inclusive of start, exclusive of end.
299 inline bool Compiler::jitIsBetween(unsigned value, unsigned start, unsigned end)
301 return start <= value && value < end;
304 /*****************************************************************************
305 * Returns true if value is between [start..end].
306 * The comparison is inclusive of both start and end.
310 inline bool Compiler::jitIsBetweenInclusive(unsigned value, unsigned start, unsigned end)
312 return start <= value && value <= end;
315 /******************************************************************************************
316 * Return the EH descriptor for the given region index.
318 inline EHblkDsc* Compiler::ehGetDsc(unsigned regionIndex)
320 assert(regionIndex < compHndBBtabCount);
321 return &compHndBBtab[regionIndex];
324 /******************************************************************************************
325 * Return the EH descriptor index of the enclosing try, for the given region index.
327 inline unsigned Compiler::ehGetEnclosingTryIndex(unsigned regionIndex)
329 return ehGetDsc(regionIndex)->ebdEnclosingTryIndex;
332 /******************************************************************************************
333 * Return the EH descriptor index of the enclosing handler, for the given region index.
335 inline unsigned Compiler::ehGetEnclosingHndIndex(unsigned regionIndex)
337 return ehGetDsc(regionIndex)->ebdEnclosingHndIndex;
340 /******************************************************************************************
341 * Return the EH index given a region descriptor.
343 inline unsigned Compiler::ehGetIndex(EHblkDsc* ehDsc)
345 assert(compHndBBtab <= ehDsc && ehDsc < compHndBBtab + compHndBBtabCount);
346 return (unsigned)(ehDsc - compHndBBtab);
349 /******************************************************************************************
350 * Return the EH descriptor for the most nested 'try' region this BasicBlock is a member of
351 * (or nullptr if this block is not in a 'try' region).
353 inline EHblkDsc* Compiler::ehGetBlockTryDsc(BasicBlock* block)
355 if (!block->hasTryIndex())
360 return ehGetDsc(block->getTryIndex());
363 /******************************************************************************************
364 * Return the EH descriptor for the most nested filter or handler region this BasicBlock is a member of
365 * (or nullptr if this block is not in a filter or handler region).
367 inline EHblkDsc* Compiler::ehGetBlockHndDsc(BasicBlock* block)
369 if (!block->hasHndIndex())
374 return ehGetDsc(block->getHndIndex());
377 #if FEATURE_EH_FUNCLETS
379 /*****************************************************************************
380 * Get the FuncInfoDsc for the funclet we are currently generating code for.
381 * This is only valid during codegen.
384 inline FuncInfoDsc* Compiler::funCurrentFunc()
386 return funGetFunc(compCurrFuncIdx);
389 /*****************************************************************************
390 * Change which funclet we are currently generating code for.
391 * This is only valid after funclets are created.
394 inline void Compiler::funSetCurrentFunc(unsigned funcIdx)
396 assert(fgFuncletsCreated);
397 assert(FitsIn<unsigned short>(funcIdx));
398 noway_assert(funcIdx < compFuncInfoCount);
399 compCurrFuncIdx = (unsigned short)funcIdx;
402 /*****************************************************************************
403 * Get the FuncInfoDsc for the given funclet.
404 * This is only valid after funclets are created.
407 inline FuncInfoDsc* Compiler::funGetFunc(unsigned funcIdx)
409 assert(fgFuncletsCreated);
410 assert(funcIdx < compFuncInfoCount);
411 return &compFuncInfos[funcIdx];
414 /*****************************************************************************
415 * Get the funcIdx for the EH funclet that begins with block.
416 * This is only valid after funclets are created.
417 * It is only valid for blocks marked with BBF_FUNCLET_BEG because
418 * otherwise we would have to do a more expensive check to determine
419 * if this should return the filter funclet or the filter handler funclet.
422 inline unsigned Compiler::funGetFuncIdx(BasicBlock* block)
424 assert(fgFuncletsCreated);
425 assert(block->bbFlags & BBF_FUNCLET_BEG);
427 EHblkDsc* eh = ehGetDsc(block->getHndIndex());
428 unsigned int funcIdx = eh->ebdFuncIndex;
429 if (eh->ebdHndBeg != block)
431 // If this is a filter EH clause, but we want the funclet
432 // for the filter (not the filter handler), it is the previous one
433 noway_assert(eh->HasFilter());
434 noway_assert(eh->ebdFilter == block);
435 assert(funGetFunc(funcIdx)->funKind == FUNC_HANDLER);
436 assert(funGetFunc(funcIdx)->funEHIndex == funGetFunc(funcIdx - 1)->funEHIndex);
437 assert(funGetFunc(funcIdx - 1)->funKind == FUNC_FILTER);
444 #else // !FEATURE_EH_FUNCLETS
446 /*****************************************************************************
447 * Get the FuncInfoDsc for the funclet we are currently generating code for.
448 * This is only valid during codegen. For non-funclet platforms, this is
449 * always the root function.
452 inline FuncInfoDsc* Compiler::funCurrentFunc()
454 return &compFuncInfoRoot;
457 /*****************************************************************************
458 * Change which funclet we are currently generating code for.
459 * This is only valid after funclets are created.
462 inline void Compiler::funSetCurrentFunc(unsigned funcIdx)
464 assert(funcIdx == 0);
467 /*****************************************************************************
468 * Get the FuncInfoDsc for the givven funclet.
469 * This is only valid after funclets are created.
472 inline FuncInfoDsc* Compiler::funGetFunc(unsigned funcIdx)
474 assert(funcIdx == 0);
475 return &compFuncInfoRoot;
478 /*****************************************************************************
479 * No funclets, so always 0.
482 inline unsigned Compiler::funGetFuncIdx(BasicBlock* block)
487 #endif // !FEATURE_EH_FUNCLETS
489 //------------------------------------------------------------------------------
490 // genRegNumFromMask : Maps a single register mask to a register number.
493 // mask - the register mask
496 // The number of the register contained in the mask.
499 // The mask contains one and only one register.
501 inline regNumber genRegNumFromMask(regMaskTP mask)
503 assert(mask != 0); // Must have one bit set, so can't have a mask of zero
505 /* Convert the mask to a register number */
507 regNumber regNum = (regNumber)genLog2(mask);
509 /* Make sure we got it right */
511 assert(genRegMask(regNum) == mask);
516 //------------------------------------------------------------------------------
517 // genSmallTypeCanRepresentValue: Checks if a value can be represented by a given small type.
520 // value - the value to check
524 // True if the value is representable, false otherwise.
526 inline bool genSmallTypeCanRepresentValue(var_types type, ssize_t value)
532 return FitsIn<UINT8>(value);
534 return FitsIn<INT8>(value);
536 return FitsIn<UINT16>(value);
538 return FitsIn<INT16>(value);
544 /*****************************************************************************
546 * Return the size in bytes of the given type.
549 extern const BYTE genTypeSizes[TYP_COUNT];
552 inline unsigned genTypeSize(T type)
554 assert((unsigned)TypeGet(type) < _countof(genTypeSizes));
556 return genTypeSizes[TypeGet(type)];
559 /*****************************************************************************
561 * Return the "stack slot count" of the given type.
562 * returns 1 for 32-bit types and 2 for 64-bit types.
565 extern const BYTE genTypeStSzs[TYP_COUNT];
567 inline unsigned genTypeStSz(var_types type)
569 assert((unsigned)type < _countof(genTypeStSzs));
571 return genTypeStSzs[type];
574 /*****************************************************************************
576 * Return the number of registers required to hold a value of the given type.
579 /*****************************************************************************
581 * The following function maps a 'precise' type to an actual type as seen
582 * by the VM (for example, 'byte' maps to 'int').
585 extern const BYTE genActualTypes[TYP_COUNT];
587 inline var_types genActualType(var_types type)
589 /* Spot check to make certain the table is in synch with the enum */
591 assert(genActualTypes[TYP_DOUBLE] == TYP_DOUBLE);
592 assert(genActualTypes[TYP_REF] == TYP_REF);
594 assert((unsigned)type < sizeof(genActualTypes));
595 return (var_types)genActualTypes[type];
598 /*****************************************************************************/
600 inline var_types genUnsignedType(var_types type)
602 /* Force signed types into corresponding unsigned type */
625 /*****************************************************************************/
627 inline var_types genSignedType(var_types type)
629 /* Force non-small unsigned type into corresponding signed type */
630 /* Note that we leave the small types alone */
647 /*****************************************************************************
648 * Can this type be passed as a parameter in a register?
651 inline bool isRegParamType(var_types type)
653 #if defined(_TARGET_X86_)
654 return (type <= TYP_INT || type == TYP_REF || type == TYP_BYREF);
655 #else // !_TARGET_X86_
657 #endif // !_TARGET_X86_
660 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
661 /*****************************************************************************/
662 // Returns true if 'type' is a struct that can be enregistered for call args
663 // or can be returned by value in multiple registers.
664 // if 'type' is not a struct the return value will be false.
667 // type - the basic jit var_type for the item being queried
668 // typeClass - the handle for the struct when 'type' is TYP_STRUCT
669 // typeSize - Out param (if non-null) is updated with the size of 'type'.
670 // forReturn - this is true when we asking about a GT_RETURN context;
671 // this is false when we are asking about an argument context
673 inline bool Compiler::VarTypeIsMultiByteAndCanEnreg(var_types type,
674 CORINFO_CLASS_HANDLE typeClass,
681 if (varTypeIsStruct(type))
683 size = info.compCompHnd->getClassSize(typeClass);
686 structPassingKind howToReturnStruct;
687 type = getReturnTypeForStruct(typeClass, &howToReturnStruct, size);
691 structPassingKind howToPassStruct;
692 type = getArgTypeForStruct(typeClass, &howToPassStruct, size);
694 if (type != TYP_UNKNOWN)
701 size = genTypeSize(type);
704 if (typeSize != nullptr)
711 #endif //_TARGET_AMD64_ || _TARGET_ARM64_
713 /*****************************************************************************/
717 inline const char* varTypeGCstring(var_types type)
732 /*****************************************************************************/
734 const char* varTypeName(var_types);
736 /*****************************************************************************
738 * Helpers to pull big-endian values out of a byte stream.
741 inline unsigned genGetU1(const BYTE* addr)
746 inline signed genGetI1(const BYTE* addr)
748 return (signed char)addr[0];
751 inline unsigned genGetU2(const BYTE* addr)
753 return (addr[0] << 8) | addr[1];
756 inline signed genGetI2(const BYTE* addr)
758 return (signed short)((addr[0] << 8) | addr[1]);
761 inline unsigned genGetU4(const BYTE* addr)
763 return (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3];
766 /*****************************************************************************/
767 // Helpers to pull little-endian values out of a byte stream.
769 inline unsigned __int8 getU1LittleEndian(const BYTE* ptr)
771 return *(UNALIGNED unsigned __int8*)ptr;
774 inline unsigned __int16 getU2LittleEndian(const BYTE* ptr)
776 return GET_UNALIGNED_VAL16(ptr);
779 inline unsigned __int32 getU4LittleEndian(const BYTE* ptr)
781 return GET_UNALIGNED_VAL32(ptr);
784 inline signed __int8 getI1LittleEndian(const BYTE* ptr)
786 return *(UNALIGNED signed __int8*)ptr;
789 inline signed __int16 getI2LittleEndian(const BYTE* ptr)
791 return GET_UNALIGNED_VAL16(ptr);
794 inline signed __int32 getI4LittleEndian(const BYTE* ptr)
796 return GET_UNALIGNED_VAL32(ptr);
799 inline signed __int64 getI8LittleEndian(const BYTE* ptr)
801 return GET_UNALIGNED_VAL64(ptr);
804 inline float getR4LittleEndian(const BYTE* ptr)
806 __int32 val = getI4LittleEndian(ptr);
807 return *(float*)&val;
810 inline double getR8LittleEndian(const BYTE* ptr)
812 __int64 val = getI8LittleEndian(ptr);
813 return *(double*)&val;
816 /*****************************************************************************
818 * Return the normalized index to use in the EXPSET_TP for the CSE with
819 * the given CSE index.
820 * Each GenTree has the following field:
821 * signed char gtCSEnum; // 0 or the CSE index (negated if def)
822 * So zero is reserved to mean this node is not a CSE
823 * and postive values indicate CSE uses and negative values indicate CSE defs.
824 * The caller of this method must pass a non-zero postive value.
825 * This precondition is checked by the assert on the first line of this method.
828 inline unsigned int genCSEnum2bit(unsigned index)
830 assert((index > 0) && (index <= EXPSET_SZ));
836 const char* genES2str(BitVecTraits* traits, EXPSET_TP set);
837 const char* refCntWtd2str(unsigned refCntWtd);
841 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
842 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
844 XX Inline functions XX
846 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
847 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
850 void* GenTree::operator new(size_t sz, Compiler* comp, genTreeOps oper)
853 size_t size = GenTree::s_gtNodeSizes[oper];
855 size_t size = TREE_NODE_SZ_LARGE;
858 #if MEASURE_NODE_SIZE
859 genNodeSizeStats.genTreeNodeCnt += 1;
860 genNodeSizeStats.genTreeNodeSize += size;
861 genNodeSizeStats.genTreeNodeActualSize += sz;
863 genNodeSizeStatsPerFunc.genTreeNodeCnt += 1;
864 genNodeSizeStatsPerFunc.genTreeNodeSize += size;
865 genNodeSizeStatsPerFunc.genTreeNodeActualSize += sz;
866 #endif // MEASURE_NODE_SIZE
869 return comp->compGetMem(size, CMK_ASTNode);
872 // GenTree constructor
873 inline GenTree::GenTree(genTreeOps oper, var_types type DEBUGARG(bool largeNode))
882 #ifdef LEGACY_BACKEND
884 #endif // LEGACY_BACKEND
887 #endif // FEATURE_ANYCSE
892 #if FEATURE_STACK_FP_X87
899 INDEBUG(gtRegTag = GT_REGTAG_NONE;)
901 INDEBUG(gtCostsInitialized = false;)
905 size_t size = GenTree::s_gtNodeSizes[oper];
906 if (size == TREE_NODE_SZ_SMALL && !largeNode)
908 gtDebugFlags |= GTF_DEBUG_NODE_SMALL;
910 else if (size == TREE_NODE_SZ_LARGE || largeNode)
912 gtDebugFlags |= GTF_DEBUG_NODE_LARGE;
916 assert(!"bogus node size");
922 InterlockedIncrement(&s_gtNodeCounts[oper]);
927 gtTreeID = JitTls::GetCompiler()->compGenTreeID++;
928 gtVNPair.SetBoth(ValueNumStore::NoVN);
929 gtRegTag = GT_REGTAG_NONE;
930 gtOperSave = GT_NONE;
934 /*****************************************************************************/
936 inline GenTreeStmt* Compiler::gtNewStmt(GenTreePtr expr, IL_OFFSETX offset)
938 /* NOTE - GT_STMT is now a small node in retail */
940 GenTreeStmt* stmt = new (this, GT_STMT) GenTreeStmt(expr, offset);
945 /*****************************************************************************/
947 inline GenTreePtr Compiler::gtNewOperNode(genTreeOps oper, var_types type, GenTreePtr op1, bool doSimplifications)
949 assert((GenTree::OperKind(oper) & (GTK_UNOP | GTK_BINOP)) != 0);
950 assert((GenTree::OperKind(oper) & GTK_EXOP) ==
951 0); // Can't use this to construct any types that extend unary/binary operator.
952 assert(op1 != nullptr || oper == GT_PHI || oper == GT_RETFILT || oper == GT_NOP ||
953 (oper == GT_RETURN && type == TYP_VOID));
955 if (doSimplifications)
957 // We do some simplifications here.
958 // If this gets to be too many, try a switch...
959 // TODO-Cleanup: With the factoring out of array bounds checks, it should not be the
960 // case that we need to check for the array index case here, but without this check
961 // we get failures (see for example jit\Directed\Languages\Python\test_methods_d.exe)
964 // IND(ADDR(IND(x)) == IND(x)
965 if (op1->gtOper == GT_ADDR)
967 if (op1->gtOp.gtOp1->gtOper == GT_IND && (op1->gtOp.gtOp1->gtFlags & GTF_IND_ARR_INDEX) == 0)
969 op1 = op1->gtOp.gtOp1->gtOp.gtOp1;
973 else if (oper == GT_ADDR)
975 // if "x" is not an array index, ADDR(IND(x)) == x
976 if (op1->gtOper == GT_IND && (op1->gtFlags & GTF_IND_ARR_INDEX) == 0)
978 return op1->gtOp.gtOp1;
983 GenTreePtr node = new (this, oper) GenTreeOp(oper, type, op1, nullptr);
986 // the GT_ADDR of a Local Variable implies GTF_ADDR_ONSTACK
988 if ((oper == GT_ADDR) && (op1->OperGet() == GT_LCL_VAR))
990 node->gtFlags |= GTF_ADDR_ONSTACK;
996 // Returns an opcode that is of the largest node size in use.
997 inline genTreeOps LargeOpOpcode()
1000 // Allocate a large node
1001 assert(GenTree::s_gtNodeSizes[GT_CALL] == TREE_NODE_SZ_LARGE);
1006 /******************************************************************************
1008 * Use to create nodes which may later be morphed to another (big) operator
1011 inline GenTreePtr Compiler::gtNewLargeOperNode(genTreeOps oper, var_types type, GenTreePtr op1, GenTreePtr op2)
1013 assert((GenTree::OperKind(oper) & (GTK_UNOP | GTK_BINOP)) != 0);
1014 assert((GenTree::OperKind(oper) & GTK_EXOP) ==
1015 0); // Can't use this to construct any types that extend unary/binary operator.
1016 #if SMALL_TREE_NODES
1017 // Allocate a large node
1019 assert(GenTree::s_gtNodeSizes[oper] == TREE_NODE_SZ_SMALL);
1021 GenTreePtr node = new (this, LargeOpOpcode()) GenTreeOp(oper, type, op1, op2 DEBUGARG(/*largeNode*/ true));
1023 GenTreePtr node = new (this, oper) GenTreeOp(oper, type, op1, op2);
1029 /*****************************************************************************
1031 * allocates a integer constant entry that represents a handle (something
1032 * that may need to be fixed up).
1035 inline GenTreePtr Compiler::gtNewIconHandleNode(size_t value, unsigned flags, FieldSeqNode* fields)
1038 assert((flags & (GTF_ICON_HDL_MASK | GTF_ICON_FIELD_OFF)) != 0);
1040 // Interpret "fields == NULL" as "not a field."
1041 if (fields == nullptr)
1043 fields = FieldSeqStore::NotAField();
1046 #if defined(LATE_DISASM)
1047 node = new (this, LargeOpOpcode()) GenTreeIntCon(TYP_I_IMPL, value, fields DEBUGARG(/*largeNode*/ true));
1049 node = new (this, GT_CNS_INT) GenTreeIntCon(TYP_I_IMPL, value, fields);
1051 node->gtFlags |= flags;
1055 /*****************************************************************************
1057 * It may not be allowed to embed HANDLEs directly into the JITed code (for eg,
1058 * as arguments to JIT helpers). Get a corresponding value that can be embedded.
1059 * These are versions for each specific type of HANDLE
1062 inline GenTreePtr Compiler::gtNewIconEmbScpHndNode(CORINFO_MODULE_HANDLE scpHnd)
1064 void *embedScpHnd, *pEmbedScpHnd;
1066 embedScpHnd = (void*)info.compCompHnd->embedModuleHandle(scpHnd, &pEmbedScpHnd);
1068 assert((!embedScpHnd) != (!pEmbedScpHnd));
1070 return gtNewIconEmbHndNode(embedScpHnd, pEmbedScpHnd, GTF_ICON_SCOPE_HDL, scpHnd);
1073 //-----------------------------------------------------------------------------
1075 inline GenTreePtr Compiler::gtNewIconEmbClsHndNode(CORINFO_CLASS_HANDLE clsHnd)
1077 void *embedClsHnd, *pEmbedClsHnd;
1079 embedClsHnd = (void*)info.compCompHnd->embedClassHandle(clsHnd, &pEmbedClsHnd);
1081 assert((!embedClsHnd) != (!pEmbedClsHnd));
1083 return gtNewIconEmbHndNode(embedClsHnd, pEmbedClsHnd, GTF_ICON_CLASS_HDL, clsHnd);
1086 //-----------------------------------------------------------------------------
1088 inline GenTreePtr Compiler::gtNewIconEmbMethHndNode(CORINFO_METHOD_HANDLE methHnd)
1090 void *embedMethHnd, *pEmbedMethHnd;
1092 embedMethHnd = (void*)info.compCompHnd->embedMethodHandle(methHnd, &pEmbedMethHnd);
1094 assert((!embedMethHnd) != (!pEmbedMethHnd));
1096 return gtNewIconEmbHndNode(embedMethHnd, pEmbedMethHnd, GTF_ICON_METHOD_HDL, methHnd);
1099 //-----------------------------------------------------------------------------
1101 inline GenTreePtr Compiler::gtNewIconEmbFldHndNode(CORINFO_FIELD_HANDLE fldHnd)
1103 void *embedFldHnd, *pEmbedFldHnd;
1105 embedFldHnd = (void*)info.compCompHnd->embedFieldHandle(fldHnd, &pEmbedFldHnd);
1107 assert((!embedFldHnd) != (!pEmbedFldHnd));
1109 return gtNewIconEmbHndNode(embedFldHnd, pEmbedFldHnd, GTF_ICON_FIELD_HDL, fldHnd);
1112 /*****************************************************************************/
1114 //------------------------------------------------------------------------------
1115 // gtNewHelperCallNode : Helper to create a call helper node.
1119 // helper - Call helper
1120 // type - Type of the node
1124 // New CT_HELPER node
1126 inline GenTreeCall* Compiler::gtNewHelperCallNode(unsigned helper, var_types type, GenTreeArgList* args)
1128 unsigned flags = s_helperCallProperties.NoThrow((CorInfoHelpFunc)helper) ? 0 : GTF_EXCEPT;
1129 GenTreeCall* result = gtNewCallNode(CT_HELPER, eeFindHelper(helper), type, args);
1130 result->gtFlags |= flags;
1133 // Helper calls are never candidates.
1135 result->gtInlineObservation = InlineObservation::CALLSITE_IS_CALL_TO_HELPER;
1141 //------------------------------------------------------------------------
1142 // gtNewAllocObjNode: A little helper to create an object allocation node.
1145 // helper - Value returned by ICorJitInfo::getNewHelper
1146 // clsHnd - Corresponding class handle
1147 // type - Tree return type (e.g. TYP_REF)
1148 // op1 - Node containing an address of VtablePtr
1151 // Returns GT_ALLOCOBJ node that will be later morphed into an
1152 // allocation helper call or local variable allocation on the stack.
1153 inline GenTreePtr Compiler::gtNewAllocObjNode(unsigned int helper,
1154 CORINFO_CLASS_HANDLE clsHnd,
1158 GenTreePtr node = new (this, GT_ALLOCOBJ) GenTreeAllocObj(type, helper, clsHnd, op1);
1162 //------------------------------------------------------------------------
1163 // gtNewRuntimeLookup: Helper to create a runtime lookup node
1166 // hnd - generic handle being looked up
1167 // hndTyp - type of the generic handle
1168 // tree - tree for the lookup
1171 // New GenTreeRuntimeLookup node.
1172 inline GenTree* Compiler::gtNewRuntimeLookup(CORINFO_GENERIC_HANDLE hnd, CorInfoGenericHandleType hndTyp, GenTree* tree)
1174 assert(tree != nullptr);
1175 GenTree* node = new (this, GT_RUNTIMELOOKUP) GenTreeRuntimeLookup(hnd, hndTyp, tree);
1179 /*****************************************************************************/
1181 inline GenTreePtr Compiler::gtNewCodeRef(BasicBlock* block)
1183 GenTreePtr node = new (this, GT_LABEL) GenTreeLabel(block);
1187 /*****************************************************************************
1189 * A little helper to create a data member reference node.
1192 inline GenTreePtr Compiler::gtNewFieldRef(
1193 var_types typ, CORINFO_FIELD_HANDLE fldHnd, GenTreePtr obj, DWORD offset, bool nullcheck)
1195 #if SMALL_TREE_NODES
1196 /* 'GT_FIELD' nodes may later get transformed into 'GT_IND' */
1198 assert(GenTree::s_gtNodeSizes[GT_IND] <= GenTree::s_gtNodeSizes[GT_FIELD]);
1199 GenTreePtr tree = new (this, GT_FIELD) GenTreeField(typ);
1201 GenTreePtr tree = new (this, GT_FIELD) GenTreeField(typ);
1203 tree->gtField.gtFldObj = obj;
1204 tree->gtField.gtFldHnd = fldHnd;
1205 tree->gtField.gtFldOffset = offset;
1207 #ifdef FEATURE_READYTORUN_COMPILER
1208 tree->gtField.gtFieldLookup.addr = nullptr;
1213 tree->gtFlags |= GTF_FLD_NULLCHECK;
1216 // If "obj" is the address of a local, note that a field of that struct local has been accessed.
1217 if (obj != nullptr && obj->OperGet() == GT_ADDR && varTypeIsStruct(obj->gtOp.gtOp1) &&
1218 obj->gtOp.gtOp1->OperGet() == GT_LCL_VAR)
1220 unsigned lclNum = obj->gtOp.gtOp1->gtLclVarCommon.gtLclNum;
1221 lvaTable[lclNum].lvFieldAccessed = 1;
1222 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
1223 // These structs are passed by reference; we should probably be able to treat these
1224 // as non-global refs, but downstream logic expects these to be marked this way.
1225 if (lvaTable[lclNum].lvIsParam)
1227 tree->gtFlags |= GTF_GLOB_REF;
1229 #endif // defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
1233 tree->gtFlags |= GTF_GLOB_REF;
1239 /*****************************************************************************
1241 * A little helper to create an array index node.
1244 inline GenTreePtr Compiler::gtNewIndexRef(var_types typ, GenTreePtr arrayOp, GenTreePtr indexOp)
1246 GenTreeIndex* gtIndx = new (this, GT_INDEX) GenTreeIndex(typ, arrayOp, indexOp, genTypeSize(typ));
1251 //------------------------------------------------------------------------------
1252 // gtNewArrLen : Helper to create an array length node.
1256 // typ - Type of the node
1257 // arrayOp - Array node
1258 // lenOffset - Offset of the length field
1261 // New GT_ARR_LENGTH node
1263 inline GenTreeArrLen* Compiler::gtNewArrLen(var_types typ, GenTree* arrayOp, int lenOffset)
1265 GenTreeArrLen* arrLen = new (this, GT_ARR_LENGTH) GenTreeArrLen(typ, arrayOp, lenOffset);
1266 static_assert_no_msg(GTF_ARRLEN_NONFAULTING == GTF_IND_NONFAULTING);
1267 arrLen->SetIndirExceptionFlags(this);
1271 //------------------------------------------------------------------------------
1272 // gtNewIndir : Helper to create an indirection node.
1275 // typ - Type of the node
1276 // addr - Address of the indirection
1281 inline GenTree* Compiler::gtNewIndir(var_types typ, GenTree* addr)
1283 GenTree* indir = gtNewOperNode(GT_IND, typ, addr);
1284 indir->SetIndirExceptionFlags(this);
1288 /*****************************************************************************
1290 * Create (and check for) a "nothing" node, i.e. a node that doesn't produce
1291 * any code. We currently use a "nop" node of type void for this purpose.
1294 inline GenTreePtr Compiler::gtNewNothingNode()
1296 return new (this, GT_NOP) GenTreeOp(GT_NOP, TYP_VOID);
1298 /*****************************************************************************/
1300 inline bool GenTree::IsNothingNode() const
1302 return (gtOper == GT_NOP && gtType == TYP_VOID);
1305 /*****************************************************************************
1307 * Change the given node to a NOP - May be later changed to a GT_COMMA
1309 *****************************************************************************/
1311 inline void GenTree::gtBashToNOP()
1316 gtOp.gtOp1 = gtOp.gtOp2 = nullptr;
1318 gtFlags &= ~(GTF_ALL_EFFECT | GTF_REVERSE_OPS);
1321 // return new arg placeholder node. Does not do anything but has a type associated
1322 // with it so we can keep track of register arguments in lists associated w/ call nodes
1324 inline GenTreePtr Compiler::gtNewArgPlaceHolderNode(var_types type, CORINFO_CLASS_HANDLE clsHnd)
1326 GenTreePtr node = new (this, GT_ARGPLACE) GenTreeArgPlace(type, clsHnd);
1330 /*****************************************************************************/
1332 inline GenTreePtr Compiler::gtUnusedValNode(GenTreePtr expr)
1334 return gtNewOperNode(GT_COMMA, TYP_VOID, expr, gtNewNothingNode());
1337 /*****************************************************************************
1339 * A wrapper for gtSetEvalOrder and gtComputeFPlvls
1340 * Necessary because the FP levels may need to be re-computed if we reverse
1344 inline void Compiler::gtSetStmtInfo(GenTree* stmt)
1346 assert(stmt->gtOper == GT_STMT);
1347 GenTreePtr expr = stmt->gtStmt.gtStmtExpr;
1349 #if FEATURE_STACK_FP_X87
1350 /* We will try to compute the FP stack level at each node */
1351 codeGen->genResetFPstkLevel();
1353 /* Sometimes we need to redo the FP level computation */
1354 gtFPstLvlRedo = false;
1355 #endif // FEATURE_STACK_FP_X87
1364 /* Recursively process the expression */
1366 gtSetEvalOrder(expr);
1368 // Set the statement to have the same costs as the top node of the tree.
1369 stmt->CopyCosts(expr);
1371 #if FEATURE_STACK_FP_X87
1372 /* Unused float values leave one operand on the stack */
1373 assert(codeGen->genGetFPstkLevel() == 0 || codeGen->genGetFPstkLevel() == 1);
1375 /* Do we need to recompute FP stack levels? */
1379 codeGen->genResetFPstkLevel();
1380 gtComputeFPlvls(expr);
1381 assert(codeGen->genGetFPstkLevel() == 0 || codeGen->genGetFPstkLevel() == 1);
1383 #endif // FEATURE_STACK_FP_X87
1386 #if FEATURE_STACK_FP_X87
1387 inline unsigned Compiler::gtSetEvalOrderAndRestoreFPstkLevel(GenTree* tree)
1389 unsigned FPlvlSave = codeGen->genFPstkLevel;
1390 unsigned result = gtSetEvalOrder(tree);
1391 codeGen->genFPstkLevel = FPlvlSave;
1395 #else // !FEATURE_STACK_FP_X87
1396 inline unsigned Compiler::gtSetEvalOrderAndRestoreFPstkLevel(GenTree* tree)
1398 return gtSetEvalOrder(tree);
1400 #endif // FEATURE_STACK_FP_X87
1402 /*****************************************************************************/
1403 #if SMALL_TREE_NODES
1404 /*****************************************************************************/
1406 inline void GenTree::SetOper(genTreeOps oper, ValueNumberUpdate vnUpdate)
1408 assert(((gtDebugFlags & GTF_DEBUG_NODE_SMALL) != 0) != ((gtDebugFlags & GTF_DEBUG_NODE_LARGE) != 0));
1410 /* Make sure the node isn't too small for the new operator */
1412 assert(GenTree::s_gtNodeSizes[gtOper] == TREE_NODE_SZ_SMALL ||
1413 GenTree::s_gtNodeSizes[gtOper] == TREE_NODE_SZ_LARGE);
1415 assert(GenTree::s_gtNodeSizes[oper] == TREE_NODE_SZ_SMALL || GenTree::s_gtNodeSizes[oper] == TREE_NODE_SZ_LARGE);
1416 assert(GenTree::s_gtNodeSizes[oper] == TREE_NODE_SZ_SMALL || (gtDebugFlags & GTF_DEBUG_NODE_LARGE));
1421 // Maintain the invariant that unary operators always have NULL gtOp2.
1422 // If we ever start explicitly allocating GenTreeUnOp nodes, we wouldn't be
1423 // able to do that (but if we did, we'd have to have a check in gtOp -- perhaps
1425 if (OperKind(oper) == GTK_UNOP)
1427 gtOp.gtOp2 = nullptr;
1431 #if DEBUGGABLE_GENTREE
1432 // Until we eliminate SetOper/ChangeOper, we also change the vtable of the node, so that
1433 // it shows up correctly in the debugger.
1434 SetVtableForOper(oper);
1435 #endif // DEBUGGABLE_GENTREE
1437 if (oper == GT_CNS_INT)
1439 gtIntCon.gtFieldSeq = nullptr;
1442 #if !defined(LEGACY_BACKEND) && defined(_TARGET_ARM_)
1443 if (oper == GT_MUL_LONG)
1445 // We sometimes bash GT_MUL to GT_MUL_LONG, which converts it from GenTreeOp to GenTreeMultiRegOp.
1446 gtMultiRegOp.gtOtherReg = REG_NA;
1447 gtMultiRegOp.ClearOtherRegFlags();
1451 if (vnUpdate == CLEAR_VN)
1453 // Clear the ValueNum field as well.
1454 gtVNPair.SetBoth(ValueNumStore::NoVN);
1458 inline GenTreePtr Compiler::gtNewCastNode(var_types typ, GenTreePtr op1, var_types castType)
1460 GenTreePtr res = new (this, GT_CAST) GenTreeCast(typ, op1, castType);
1464 inline GenTreePtr Compiler::gtNewCastNodeL(var_types typ, GenTreePtr op1, var_types castType)
1466 /* Some casts get transformed into 'GT_CALL' or 'GT_IND' nodes */
1468 assert(GenTree::s_gtNodeSizes[GT_CALL] >= GenTree::s_gtNodeSizes[GT_CAST]);
1469 assert(GenTree::s_gtNodeSizes[GT_CALL] >= GenTree::s_gtNodeSizes[GT_IND]);
1471 /* Make a big node first and then change it to be GT_CAST */
1473 GenTreePtr res = new (this, LargeOpOpcode()) GenTreeCast(typ, op1, castType DEBUGARG(/*largeNode*/ true));
1477 /*****************************************************************************/
1478 #else // SMALL_TREE_NODES
1479 /*****************************************************************************/
1481 inline void GenTree::InitNodeSize()
1485 inline void GenTree::SetOper(genTreeOps oper, ValueNumberUpdate vnUpdate)
1489 if (vnUpdate == CLEAR_VN)
1491 // Clear the ValueNum field.
1492 gtVNPair.SetBoth(ValueNumStore::NoVN);
1496 inline void GenTree::ReplaceWith(GenTreePtr src)
1498 RecordOperBashing(OperGet(), src->OperGet()); // nop unless NODEBASH_STATS is enabled
1505 inline GenTreePtr Compiler::gtNewCastNode(var_types typ, GenTreePtr op1, var_types castType)
1507 GenTreePtr tree = gtNewOperNode(GT_CAST, typ, op1);
1508 tree->gtCast.gtCastType = castType;
1511 inline GenTreePtr Compiler::gtNewCastNodeL(var_types typ, GenTreePtr op1, var_types castType)
1513 return gtNewCastNode(typ, op1, castType);
1516 /*****************************************************************************/
1517 #endif // SMALL_TREE_NODES
1518 /*****************************************************************************/
1520 /*****************************************************************************/
1522 inline void GenTree::SetOperRaw(genTreeOps oper)
1524 // Please do not do anything here other than assign to gtOper (debug-only
1525 // code is OK, but should be kept to a minimum).
1526 RecordOperBashing(OperGet(), oper); // nop unless NODEBASH_STATS is enabled
1530 inline void GenTree::SetOperResetFlags(genTreeOps oper)
1533 gtFlags &= GTF_NODE_MASK;
1536 inline void GenTree::ChangeOperConst(genTreeOps oper)
1538 #ifdef _TARGET_64BIT_
1539 assert(oper != GT_CNS_LNG); // We should never see a GT_CNS_LNG for a 64-bit target!
1541 assert(OperIsConst(oper)); // use ChangeOper() instead
1542 SetOperResetFlags(oper);
1543 // Some constant subtypes have additional fields that must be initialized.
1544 if (oper == GT_CNS_INT)
1546 gtIntCon.gtFieldSeq = FieldSeqStore::NotAField();
1550 inline void GenTree::ChangeOper(genTreeOps oper, ValueNumberUpdate vnUpdate)
1552 assert(!OperIsConst(oper)); // use ChangeOperLeaf() instead
1554 unsigned mask = GTF_COMMON_MASK;
1555 if (this->OperIsIndirOrArrLength() && OperIsIndirOrArrLength(oper))
1557 mask |= GTF_IND_NONFAULTING;
1559 SetOper(oper, vnUpdate);
1562 // Do "oper"-specific initializations...
1566 gtLclFld.gtLclOffs = 0;
1567 gtLclFld.gtFieldSeq = FieldSeqStore::NotAField();
1574 inline void GenTree::ChangeOperUnchecked(genTreeOps oper)
1576 unsigned mask = GTF_COMMON_MASK;
1577 if (this->OperIsIndirOrArrLength() && OperIsIndirOrArrLength(oper))
1579 mask |= GTF_IND_NONFAULTING;
1581 SetOperRaw(oper); // Trust the caller and don't use SetOper()
1585 /*****************************************************************************
1586 * Returns true if the node is &var (created by ldarga and ldloca)
1589 inline bool GenTree::IsVarAddr() const
1591 if (gtOper == GT_ADDR)
1593 if (gtFlags & GTF_ADDR_ONSTACK)
1595 assert((gtType == TYP_BYREF) || (gtType == TYP_I_IMPL));
1602 /*****************************************************************************
1604 * Returns true if the node is of the "ovf" variety, for example, add.ovf.i1.
1605 * + gtOverflow() can only be called for valid operators (that is, we know it is one
1606 * of the operators which may have GTF_OVERFLOW set).
1607 * + gtOverflowEx() is more expensive, and should be called only if gtOper may be
1608 * an operator for which GTF_OVERFLOW is invalid.
1611 inline bool GenTree::gtOverflow() const
1613 assert(OperMayOverflow());
1615 if ((gtFlags & GTF_OVERFLOW) != 0)
1617 assert(varTypeIsIntegral(TypeGet()));
1627 inline bool GenTree::gtOverflowEx() const
1629 return OperMayOverflow() && gtOverflow();
1633 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1634 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1636 XX Inline functions XX
1638 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1639 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1642 inline bool Compiler::lvaHaveManyLocals() const
1644 return (lvaCount >= lclMAX_TRACKED);
1647 /*****************************************************************************
1649 * Allocate a temporary variable or a set of temp variables.
1652 inline unsigned Compiler::lvaGrabTemp(bool shortLifetime DEBUGARG(const char* reason))
1654 if (compIsForInlining())
1656 // Grab the temp using Inliner's Compiler instance.
1657 Compiler* pComp = impInlineInfo->InlinerCompiler; // The Compiler instance for the caller (i.e. the inliner)
1659 if (pComp->lvaHaveManyLocals())
1661 // Don't create more LclVar with inlining
1662 compInlineResult->NoteFatal(InlineObservation::CALLSITE_TOO_MANY_LOCALS);
1665 unsigned tmpNum = pComp->lvaGrabTemp(shortLifetime DEBUGARG(reason));
1666 lvaTable = pComp->lvaTable;
1667 lvaCount = pComp->lvaCount;
1668 lvaTableCnt = pComp->lvaTableCnt;
1672 // You cannot allocate more space after frame layout!
1673 noway_assert(lvaDoneFrameLayout < Compiler::TENTATIVE_FRAME_LAYOUT);
1675 /* Check if the lvaTable has to be grown */
1676 if (lvaCount + 1 > lvaTableCnt)
1678 unsigned newLvaTableCnt = lvaCount + (lvaCount / 2) + 1;
1680 // Check for overflow
1681 if (newLvaTableCnt <= lvaCount)
1683 IMPL_LIMITATION("too many locals");
1686 // Note: compGetMemArray might throw.
1687 LclVarDsc* newLvaTable = (LclVarDsc*)compGetMemArray(newLvaTableCnt, sizeof(*lvaTable), CMK_LvaTable);
1689 memcpy(newLvaTable, lvaTable, lvaCount * sizeof(*lvaTable));
1690 memset(newLvaTable + lvaCount, 0, (newLvaTableCnt - lvaCount) * sizeof(*lvaTable));
1692 for (unsigned i = lvaCount; i < newLvaTableCnt; i++)
1694 new (&newLvaTable[i], jitstd::placement_t()) LclVarDsc(this); // call the constructor.
1698 // TODO-Cleanup: Enable this and test.
1700 // Fill the old table with junks. So to detect the un-intended use.
1701 memset(lvaTable, fDefaultFill2.val_DontUse_(CLRConfig::INTERNAL_JitDefaultFill, 0xFF), lvaCount * sizeof(*lvaTable));
1705 lvaTableCnt = newLvaTableCnt;
1706 lvaTable = newLvaTable;
1709 lvaTable[lvaCount].lvType = TYP_UNDEF; // Initialize lvType, lvIsTemp and lvOnFrame
1710 lvaTable[lvaCount].lvIsTemp = shortLifetime;
1711 lvaTable[lvaCount].lvOnFrame = true;
1713 unsigned tempNum = lvaCount;
1720 printf("\nlvaGrabTemp returning %d (", tempNum);
1721 gtDispLclVar(tempNum, false);
1722 printf(")%s called for %s.\n", shortLifetime ? "" : " (a long lifetime temp)", reason);
1729 inline unsigned Compiler::lvaGrabTemps(unsigned cnt DEBUGARG(const char* reason))
1731 if (compIsForInlining())
1733 // Grab the temps using Inliner's Compiler instance.
1734 unsigned tmpNum = impInlineInfo->InlinerCompiler->lvaGrabTemps(cnt DEBUGARG(reason));
1736 lvaTable = impInlineInfo->InlinerCompiler->lvaTable;
1737 lvaCount = impInlineInfo->InlinerCompiler->lvaCount;
1738 lvaTableCnt = impInlineInfo->InlinerCompiler->lvaTableCnt;
1745 printf("\nlvaGrabTemps(%d) returning %d..%d (long lifetime temps) called for %s", cnt, lvaCount,
1746 lvaCount + cnt - 1, reason);
1750 // You cannot allocate more space after frame layout!
1751 noway_assert(lvaDoneFrameLayout < Compiler::TENTATIVE_FRAME_LAYOUT);
1753 /* Check if the lvaTable has to be grown */
1754 if (lvaCount + cnt > lvaTableCnt)
1756 unsigned newLvaTableCnt = lvaCount + max(lvaCount / 2 + 1, cnt);
1758 // Check for overflow
1759 if (newLvaTableCnt <= lvaCount)
1761 IMPL_LIMITATION("too many locals");
1764 // Note: compGetMemArray might throw.
1765 LclVarDsc* newLvaTable = (LclVarDsc*)compGetMemArray(newLvaTableCnt, sizeof(*lvaTable), CMK_LvaTable);
1767 memcpy(newLvaTable, lvaTable, lvaCount * sizeof(*lvaTable));
1768 memset(newLvaTable + lvaCount, 0, (newLvaTableCnt - lvaCount) * sizeof(*lvaTable));
1769 for (unsigned i = lvaCount; i < newLvaTableCnt; i++)
1771 new (&newLvaTable[i], jitstd::placement_t()) LclVarDsc(this); // call the constructor.
1776 // TODO-Cleanup: Enable this and test.
1777 // Fill the old table with junks. So to detect the un-intended use.
1778 memset(lvaTable, fDefaultFill2.val_DontUse_(CLRConfig::INTERNAL_JitDefaultFill, 0xFF), lvaCount * sizeof(*lvaTable));
1782 lvaTableCnt = newLvaTableCnt;
1783 lvaTable = newLvaTable;
1786 unsigned tempNum = lvaCount;
1790 lvaTable[lvaCount].lvType = TYP_UNDEF; // Initialize lvType, lvIsTemp and lvOnFrame
1791 lvaTable[lvaCount].lvIsTemp = false;
1792 lvaTable[lvaCount].lvOnFrame = true;
1799 /*****************************************************************************
1801 * Allocate a temporary variable which is implicitly used by code-gen
1802 * There will be no explicit references to the temp, and so it needs to
1803 * be forced to be kept alive, and not be optimized away.
1806 inline unsigned Compiler::lvaGrabTempWithImplicitUse(bool shortLifetime DEBUGARG(const char* reason))
1808 if (compIsForInlining())
1810 // Grab the temp using Inliner's Compiler instance.
1811 unsigned tmpNum = impInlineInfo->InlinerCompiler->lvaGrabTempWithImplicitUse(shortLifetime DEBUGARG(reason));
1813 lvaTable = impInlineInfo->InlinerCompiler->lvaTable;
1814 lvaCount = impInlineInfo->InlinerCompiler->lvaCount;
1815 lvaTableCnt = impInlineInfo->InlinerCompiler->lvaTableCnt;
1819 unsigned lclNum = lvaGrabTemp(shortLifetime DEBUGARG(reason));
1821 LclVarDsc* varDsc = &lvaTable[lclNum];
1823 // This will prevent it from being optimized away
1824 // TODO-CQ: We shouldn't have to go as far as to declare these
1825 // address-exposed -- DoNotEnregister should suffice?
1826 lvaSetVarAddrExposed(lclNum);
1828 // We need lvRefCnt to be non-zero to prevent various asserts from firing.
1829 varDsc->lvRefCnt = 1;
1830 varDsc->lvRefCntWtd = BB_UNITY_WEIGHT;
1835 /*****************************************************************************
1837 * If lvaTrackedFixed is false then set the lvaSortAgain flag
1838 * (this allows us to grow the number of tracked variables)
1839 * and zero lvRefCntWtd when lvRefCnt is zero
1842 inline void LclVarDsc::lvaResetSortAgainFlag(Compiler* comp)
1844 if (!comp->lvaTrackedFixed)
1846 /* Flag this change, set lvaSortAgain to true */
1847 comp->lvaSortAgain = true;
1849 /* Set weighted ref count to zero if ref count is zero */
1856 /*****************************************************************************
1858 * Decrement the ref counts for a local variable
1861 inline void LclVarDsc::decRefCnts(BasicBlock::weight_t weight, Compiler* comp, bool propagate)
1863 /* Decrement lvRefCnt and lvRefCntWtd */
1864 Compiler::lvaPromotionType promotionType = DUMMY_INIT(Compiler::PROMOTION_TYPE_NONE);
1865 if (varTypeIsStruct(lvType))
1867 promotionType = comp->lvaGetPromotionType(this);
1871 // Decrement counts on the local itself.
1873 if (lvType != TYP_STRUCT || promotionType != Compiler::PROMOTION_TYPE_INDEPENDENT)
1875 assert(lvRefCnt); // Can't decrement below zero
1877 // TODO: Well, the assert above could be bogus.
1878 // If lvRefCnt has overflowed before, then might drop to 0.
1879 // Therefore we do need the following check to keep lvRefCnt from underflow:
1883 // Decrement lvRefCnt
1888 // Decrement lvRefCntWtd
1892 if (lvIsTemp && (weight * 2 > weight))
1897 if (lvRefCntWtd <= weight)
1898 { // Can't go below zero
1903 lvRefCntWtd -= weight;
1909 if (varTypeIsStruct(lvType) && propagate)
1911 // For promoted struct locals, decrement lvRefCnt on its field locals as well.
1912 if (promotionType == Compiler::PROMOTION_TYPE_INDEPENDENT ||
1913 promotionType == Compiler::PROMOTION_TYPE_DEPENDENT)
1915 for (unsigned i = lvFieldLclStart; i < lvFieldLclStart + lvFieldCnt; ++i)
1917 comp->lvaTable[i].decRefCnts(comp->lvaMarkRefsWeight, comp, false); // Don't propagate
1922 if (lvIsStructField && propagate)
1924 // Depending on the promotion type, decrement the ref count for the parent struct as well.
1925 promotionType = comp->lvaGetParentPromotionType(this);
1926 LclVarDsc* parentvarDsc = &comp->lvaTable[lvParentLcl];
1927 assert(!parentvarDsc->lvRegStruct);
1928 if (promotionType == Compiler::PROMOTION_TYPE_DEPENDENT)
1930 parentvarDsc->decRefCnts(comp->lvaMarkRefsWeight, comp, false); // Don't propagate
1934 lvaResetSortAgainFlag(comp);
1939 unsigned varNum = (unsigned)(this - comp->lvaTable);
1940 assert(&comp->lvaTable[varNum] == this);
1941 printf("New refCnts for V%02u: refCnt = %2u, refCntWtd = %s\n", varNum, lvRefCnt, refCntWtd2str(lvRefCntWtd));
1946 /*****************************************************************************
1948 * Increment the ref counts for a local variable
1951 inline void LclVarDsc::incRefCnts(BasicBlock::weight_t weight, Compiler* comp, bool propagate)
1953 Compiler::lvaPromotionType promotionType = DUMMY_INIT(Compiler::PROMOTION_TYPE_NONE);
1954 if (varTypeIsStruct(lvType))
1956 promotionType = comp->lvaGetPromotionType(this);
1960 // Increment counts on the local itself.
1962 if (lvType != TYP_STRUCT || promotionType != Compiler::PROMOTION_TYPE_INDEPENDENT)
1965 // Increment lvRefCnt
1967 int newRefCnt = lvRefCnt + 1;
1968 if (newRefCnt == (unsigned short)newRefCnt) // lvRefCnt is an "unsigned short". Don't overflow it.
1970 lvRefCnt = (unsigned short)newRefCnt;
1973 // This fires when an uninitialize value for 'weight' is used (see lvaMarkRefsWeight)
1974 assert(weight != 0xdddddddd);
1976 // Increment lvRefCntWtd
1980 // We double the weight of internal temps
1982 if (lvIsTemp && (weight * 2 > weight))
1987 unsigned newWeight = lvRefCntWtd + weight;
1988 if (newWeight >= lvRefCntWtd)
1989 { // lvRefCntWtd is an "unsigned". Don't overflow it
1990 lvRefCntWtd = newWeight;
1993 { // On overflow we assign ULONG_MAX
1994 lvRefCntWtd = ULONG_MAX;
1999 if (varTypeIsStruct(lvType) && propagate)
2001 // For promoted struct locals, increment lvRefCnt on its field locals as well.
2002 if (promotionType == Compiler::PROMOTION_TYPE_INDEPENDENT ||
2003 promotionType == Compiler::PROMOTION_TYPE_DEPENDENT)
2005 for (unsigned i = lvFieldLclStart; i < lvFieldLclStart + lvFieldCnt; ++i)
2007 comp->lvaTable[i].incRefCnts(comp->lvaMarkRefsWeight, comp, false); // Don't propagate
2012 if (lvIsStructField && propagate)
2014 // Depending on the promotion type, increment the ref count for the parent struct as well.
2015 promotionType = comp->lvaGetParentPromotionType(this);
2016 LclVarDsc* parentvarDsc = &comp->lvaTable[lvParentLcl];
2017 assert(!parentvarDsc->lvRegStruct);
2018 if (promotionType == Compiler::PROMOTION_TYPE_DEPENDENT)
2020 parentvarDsc->incRefCnts(comp->lvaMarkRefsWeight, comp, false); // Don't propagate
2024 lvaResetSortAgainFlag(comp);
2029 unsigned varNum = (unsigned)(this - comp->lvaTable);
2030 assert(&comp->lvaTable[varNum] == this);
2031 printf("New refCnts for V%02u: refCnt = %2u, refCntWtd = %s\n", varNum, lvRefCnt, refCntWtd2str(lvRefCntWtd));
2036 /*****************************************************************************
2038 * Set the lvPrefReg field to reg
2041 inline void LclVarDsc::setPrefReg(regNumber regNum, Compiler* comp)
2044 if (isFloatRegType(TypeGet()))
2046 // Check for FP struct-promoted field being passed in integer register
2048 if (!genIsValidFloatReg(regNum))
2052 regMask = genRegMaskFloat(regNum, TypeGet());
2056 regMask = genRegMask(regNum);
2060 // Don't set a preferred register for a TYP_STRUCT that takes more than one register slot
2061 if ((TypeGet() == TYP_STRUCT) && (lvSize() > REGSIZE_BYTES))
2065 /* Only interested if we have a new register bit set */
2066 if (lvPrefReg & regMask)
2076 printf("Change preferred register for V%02u from ", this - comp->lvaTable);
2077 dspRegMask(lvPrefReg);
2081 printf("Set preferred register for V%02u", this - comp->lvaTable);
2084 dspRegMask(regMask);
2089 /* Overwrite the lvPrefReg field */
2091 lvPrefReg = (regMaskSmall)regMask;
2093 #ifdef LEGACY_BACKEND
2094 // This is specific to the classic register allocator.
2095 // While walking the trees during reg predict we set the lvPrefReg mask
2096 // and then re-sort the 'tracked' variable when the lvPrefReg mask changes.
2099 /* Flag this change, set lvaSortAgain to true */
2100 comp->lvaSortAgain = true;
2102 #endif // LEGACY_BACKEND
2105 /*****************************************************************************
2107 * Add regMask to the lvPrefReg field
2110 inline void LclVarDsc::addPrefReg(regMaskTP regMask, Compiler* comp)
2112 assert(regMask != RBM_NONE);
2115 // Don't set a preferred register for a TYP_STRUCT that takes more than one register slot
2116 if ((lvType == TYP_STRUCT) && (lvSize() > REGSIZE_BYTES))
2120 /* Only interested if we have a new register bit set */
2121 if (lvPrefReg & regMask)
2131 printf("Additional preferred register for V%02u from ", this - comp->lvaTable);
2132 dspRegMask(lvPrefReg);
2136 printf("Set preferred register for V%02u", this - comp->lvaTable);
2139 dspRegMask(lvPrefReg | regMask);
2144 /* Update the lvPrefReg field */
2146 lvPrefReg |= regMask;
2148 #ifdef LEGACY_BACKEND
2149 // This is specific to the classic register allocator
2150 // While walking the trees during reg predict we set the lvPrefReg mask
2151 // and then resort the 'tracked' variable when the lvPrefReg mask changes
2154 /* Flag this change, set lvaSortAgain to true */
2155 comp->lvaSortAgain = true;
2157 #endif // LEGACY_BACKEND
2160 /*****************************************************************************
2162 * The following returns the mask of all tracked locals
2163 * referenced in a statement.
2166 inline VARSET_VALRET_TP Compiler::lvaStmtLclMask(GenTreePtr stmt)
2171 VARSET_TP lclMask(VarSetOps::MakeEmpty(this));
2173 assert(stmt->gtOper == GT_STMT);
2174 assert(fgStmtListThreaded);
2176 for (tree = stmt->gtStmt.gtStmtList; tree; tree = tree->gtNext)
2178 if (tree->gtOper != GT_LCL_VAR)
2183 varNum = tree->gtLclVarCommon.gtLclNum;
2184 assert(varNum < lvaCount);
2185 varDsc = lvaTable + varNum;
2187 if (!varDsc->lvTracked)
2192 VarSetOps::UnionD(this, lclMask, VarSetOps::MakeSingleton(this, varDsc->lvVarIndex));
2198 /*****************************************************************************
2199 * Returns true if the lvType is a TYP_REF or a TYP_BYREF.
2200 * When the lvType is a TYP_STRUCT it searches the GC layout
2201 * of the struct and returns true iff it contains a GC ref.
2204 inline bool Compiler::lvaTypeIsGC(unsigned varNum)
2206 if (lvaTable[varNum].TypeGet() == TYP_STRUCT)
2208 assert(lvaTable[varNum].lvGcLayout != nullptr); // bits are intialized
2209 return (lvaTable[varNum].lvStructGcCount != 0);
2211 return (varTypeIsGC(lvaTable[varNum].TypeGet()));
2214 /*****************************************************************************
2215 Is this a synchronized instance method? If so, we will need to report "this"
2216 in the GC information, so that the EE can release the object lock
2217 in case of an exception
2219 We also need to report "this" and keep it alive for all shared generic
2220 code that gets the actual generic context from the "this" pointer and
2221 has exception handlers.
2223 For example, if List<T>::m() is shared between T = object and T = string,
2224 then inside m() an exception handler "catch E<T>" needs to be able to fetch
2225 the 'this' pointer to find out what 'T' is in order to tell if we
2226 should catch the exception or not.
2229 inline bool Compiler::lvaKeepAliveAndReportThis()
2231 if (info.compIsStatic || lvaTable[0].TypeGet() != TYP_REF)
2236 const bool genericsContextIsThis = (info.compMethodInfo->options & CORINFO_GENERICS_CTXT_FROM_THIS) != 0;
2238 #ifdef JIT32_GCENCODER
2240 if (info.compFlags & CORINFO_FLG_SYNCH)
2243 if (genericsContextIsThis)
2245 // TODO: Check if any of the exception clauses are
2246 // typed using a generic type. Else, we do not need to report this.
2247 if (info.compXcptnsCount > 0)
2250 if (opts.compDbgCode)
2253 if (lvaGenericsContextUseCount > 0)
2255 JITDUMP("Reporting this as generic context: %u refs\n", lvaGenericsContextUseCount);
2259 #else // !JIT32_GCENCODER
2260 // If the generics context is the this pointer we need to report it if either
2261 // the VM requires us to keep the generics context alive or it is used in a look-up.
2262 // We keep it alive in the lookup scenario, even when the VM didn't ask us to,
2263 // because collectible types need the generics context when gc-ing.
2264 if (genericsContextIsThis)
2266 const bool isUsed = lvaGenericsContextUseCount > 0;
2267 const bool mustKeep = (info.compMethodInfo->options & CORINFO_GENERICS_CTXT_KEEP_ALIVE) != 0;
2269 if (isUsed || mustKeep)
2271 JITDUMP("Reporting this as generic context: %u refs%s\n", lvaGenericsContextUseCount,
2272 mustKeep ? ", must keep" : "");
2282 /*****************************************************************************
2283 Similar to lvaKeepAliveAndReportThis
2286 inline bool Compiler::lvaReportParamTypeArg()
2288 if (info.compMethodInfo->options & (CORINFO_GENERICS_CTXT_FROM_METHODDESC | CORINFO_GENERICS_CTXT_FROM_METHODTABLE))
2290 assert(info.compTypeCtxtArg != -1);
2292 // If the VM requires us to keep the generics context alive and report it (for example, if any catch
2293 // clause catches a type that uses a generic parameter of this method) this flag will be set.
2294 if (info.compMethodInfo->options & CORINFO_GENERICS_CTXT_KEEP_ALIVE)
2299 // Otherwise, if an exact type parameter is needed in the body, report the generics context.
2300 // We do this because collectible types needs the generics context when gc-ing.
2301 if (lvaGenericsContextUseCount > 0)
2307 // Otherwise, we don't need to report it -- the generics context parameter is unused.
2311 //*****************************************************************************
2313 inline unsigned Compiler::lvaCachedGenericContextArgOffset()
2315 assert(lvaDoneFrameLayout == FINAL_FRAME_LAYOUT);
2317 return lvaCachedGenericContextArgOffs;
2320 /*****************************************************************************
2322 * Return the stack framed offset of the given variable; set *FPbased to
2323 * true if the variable is addressed off of FP, false if it's addressed
2324 * off of SP. Note that 'varNum' can be a negated spill-temporary var index.
2326 * mustBeFPBased - strong about whether the base reg is FP. But it is also
2327 * strong about not being FPBased after FINAL_FRAME_LAYOUT. i.e.,
2328 * it enforces SP based.
2330 * addrModeOffset - is the addressing mode offset, for example: v02 + 0x10
2331 * So, V02 itself is at offset sp + 0x10 and then addrModeOffset is what gets
2332 * added beyond that.
2338 Compiler::lvaFrameAddress(int varNum, bool mustBeFPBased, regNumber* pBaseReg, int addrModeOffset)
2341 Compiler::lvaFrameAddress(int varNum, bool* pFPbased)
2344 assert(lvaDoneFrameLayout != NO_FRAME_LAYOUT);
2348 bool fConservative = false;
2349 var_types type = TYP_UNDEF;
2354 assert((unsigned)varNum < lvaCount);
2355 varDsc = lvaTable + varNum;
2356 type = varDsc->TypeGet();
2357 bool isPrespilledArg = false;
2358 #if defined(_TARGET_ARM_) && defined(PROFILING_SUPPORTED)
2359 isPrespilledArg = varDsc->lvIsParam && compIsProfilerHookNeeded() &&
2360 lvaIsPreSpilled(varNum, codeGen->regSet.rsMaskPreSpillRegs(false));
2363 // If we have finished with register allocation, and this isn't a stack-based local,
2364 // check that this has a valid stack location.
2365 if (lvaDoneFrameLayout > REGALLOC_FRAME_LAYOUT && !varDsc->lvOnFrame)
2367 #ifdef _TARGET_AMD64_
2368 #ifndef FEATURE_UNIX_AMD64_STRUCT_PASSING
2369 // On amd64, every param has a stack location, except on Unix-like systems.
2370 assert(varDsc->lvIsParam);
2371 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
2372 #elif !defined(LEGACY_BACKEND)
2373 // For !LEGACY_BACKEND on other targets, a stack parameter that is enregistered or prespilled
2374 // for profiling on ARM will have a stack location.
2375 assert((varDsc->lvIsParam && !varDsc->lvIsRegArg) || isPrespilledArg);
2376 #else // !(_TARGET_AMD64 || defined(LEGACY_BACKEND))
2377 // Otherwise, we only have a valid stack location for:
2378 // A parameter that was passed on the stack, being homed into its register home,
2379 // or a prespilled argument on arm under profiler.
2380 assert((varDsc->lvIsParam && !varDsc->lvIsRegArg && varDsc->lvRegister) || isPrespilledArg);
2381 #endif // !(_TARGET_AMD64 || defined(LEGACY_BACKEND))
2384 FPbased = varDsc->lvFramePointerBased;
2387 #if FEATURE_FIXED_OUT_ARGS
2388 if ((unsigned)varNum == lvaOutgoingArgSpaceVar)
2390 assert(FPbased == false);
2396 assert(FPbased == (isFramePointerUsed() || (genDoubleAlign() && varDsc->lvIsParam && !varDsc->lvIsRegArg)));
2399 assert(FPbased == isFramePointerUsed());
2405 offset = varDsc->lvStkOffs;
2407 else // Its a spill-temp
2409 FPbased = isFramePointerUsed();
2410 if (lvaDoneFrameLayout == Compiler::FINAL_FRAME_LAYOUT)
2412 TempDsc* tmpDsc = tmpFindNum(varNum);
2413 #ifndef LEGACY_BACKEND
2414 // The temp might be in use, since this might be during code generation.
2415 if (tmpDsc == nullptr)
2417 tmpDsc = tmpFindNum(varNum, Compiler::TEMP_USAGE_USED);
2419 #endif // !LEGACY_BACKEND
2420 assert(tmpDsc != nullptr);
2421 offset = tmpDsc->tdTempOffs();
2422 type = tmpDsc->tdTempType();
2426 // This value is an estimate until we calculate the
2427 // offset after the final frame layout
2428 // ---------------------------------------------------
2430 // +-------------------------+ base --+
2431 // | LR, ++N for ARM | | frameBaseOffset (= N)
2432 // +-------------------------+ |
2433 // | R11, ++N for ARM | <---FP |
2434 // +-------------------------+ --+
2435 // | compCalleeRegsPushed - N| | lclFrameOffset
2436 // +-------------------------+ --+
2438 // +-------------------------+ |
2439 // | tmp[MAX_SPILL_TEMP] | |
2441 // | tmp[0] | | compLclFrameSize
2442 // +-------------------------+ |
2443 // | outgoingArgSpaceSize | |
2444 // +-------------------------+ --+
2447 // ---------------------------------------------------
2449 type = compFloatingPointUsed ? TYP_FLOAT : TYP_INT;
2450 fConservative = true;
2453 // Worst case stack based offset.
2454 CLANG_FORMAT_COMMENT_ANCHOR;
2455 #if FEATURE_FIXED_OUT_ARGS
2456 int outGoingArgSpaceSize = lvaOutgoingArgSpaceSize;
2458 int outGoingArgSpaceSize = 0;
2460 offset = outGoingArgSpaceSize + max(-varNum * TARGET_POINTER_SIZE, (int)lvaGetMaxSpillTempSize());
2464 // Worst case FP based offset.
2465 CLANG_FORMAT_COMMENT_ANCHOR;
2468 offset = codeGen->genCallerSPtoInitialSPdelta() - codeGen->genCallerSPtoFPdelta();
2470 offset = -(codeGen->genTotalFrameSize());
2481 *pBaseReg = REG_FPBASE;
2483 // Change the FP-based addressing to the SP-based addressing when possible because
2484 // it generates smaller code on ARM. See frame picture above for the math.
2487 // If it is the final frame layout phase, we don't have a choice, we should stick
2488 // to either FP based or SP based that we decided in the earlier phase. Because
2489 // we have already selected the instruction. Min-opts will have R10 enabled, so just
2492 int spOffset = fConservative ? compLclFrameSize : offset + codeGen->genSPtoFPdelta();
2493 int actualOffset = (spOffset + addrModeOffset);
2494 int ldrEncodeLimit = (varTypeIsFloating(type) ? 0x3FC : 0xFFC);
2495 // Use ldr sp imm encoding.
2496 if (lvaDoneFrameLayout == FINAL_FRAME_LAYOUT || opts.MinOpts() || (actualOffset <= ldrEncodeLimit))
2499 *pBaseReg = compLocallocUsed ? REG_SAVED_LOCALLOC_SP : REG_SPBASE;
2501 // Use ldr +/-imm8 encoding.
2502 else if (offset >= -0x7C && offset <= ldrEncodeLimit)
2504 *pBaseReg = REG_FPBASE;
2506 // Use a single movw. prefer locals.
2507 else if (actualOffset <= 0xFFFC) // Fix 383910 ARM ILGEN
2510 *pBaseReg = compLocallocUsed ? REG_SAVED_LOCALLOC_SP : REG_SPBASE;
2515 *pBaseReg = REG_FPBASE;
2521 *pBaseReg = REG_SPBASE;
2524 *pFPbased = FPbased;
2530 inline bool Compiler::lvaIsParameter(unsigned varNum)
2534 assert(varNum < lvaCount);
2535 varDsc = lvaTable + varNum;
2537 return varDsc->lvIsParam;
2540 inline bool Compiler::lvaIsRegArgument(unsigned varNum)
2544 assert(varNum < lvaCount);
2545 varDsc = lvaTable + varNum;
2547 return varDsc->lvIsRegArg;
2550 inline BOOL Compiler::lvaIsOriginalThisArg(unsigned varNum)
2552 assert(varNum < lvaCount);
2554 BOOL isOriginalThisArg = (varNum == info.compThisArg) && (info.compIsStatic == false);
2557 if (isOriginalThisArg)
2559 LclVarDsc* varDsc = lvaTable + varNum;
2560 // Should never write to or take the address of the original 'this' arg
2561 CLANG_FORMAT_COMMENT_ANCHOR;
2563 #ifndef JIT32_GCENCODER
2564 // With the general encoder/decoder, when the original 'this' arg is needed as a generics context param, we
2565 // copy to a new local, and mark the original as DoNotEnregister, to
2566 // ensure that it is stack-allocated. It should not be the case that the original one can be modified -- it
2567 // should not be written to, or address-exposed.
2568 assert(!varDsc->lvHasILStoreOp &&
2569 (!varDsc->lvAddrExposed || ((info.compMethodInfo->options & CORINFO_GENERICS_CTXT_FROM_THIS) != 0)));
2571 assert(!varDsc->lvHasILStoreOp && !varDsc->lvAddrExposed);
2576 return isOriginalThisArg;
2579 inline BOOL Compiler::lvaIsOriginalThisReadOnly()
2581 return lvaArg0Var == info.compThisArg;
2584 /*****************************************************************************
2586 * The following is used to detect the cases where the same local variable#
2587 * is used both as a long/double value and a 32-bit value and/or both as an
2588 * integer/address and a float value.
2591 /* static */ inline unsigned Compiler::lvaTypeRefMask(var_types type)
2593 const static BYTE lvaTypeRefMasks[] = {
2594 #define DEF_TP(tn, nm, jitType, verType, sz, sze, asze, st, al, tf, howUsed) howUsed,
2595 #include "typelist.h"
2599 assert((unsigned)type < sizeof(lvaTypeRefMasks));
2600 assert(lvaTypeRefMasks[type] != 0);
2602 return lvaTypeRefMasks[type];
2605 /*****************************************************************************
2607 * The following is used to detect the cases where the same local variable#
2608 * is used both as a long/double value and a 32-bit value and/or both as an
2609 * integer/address and a float value.
2612 inline var_types Compiler::lvaGetActualType(unsigned lclNum)
2614 return genActualType(lvaGetRealType(lclNum));
2617 inline var_types Compiler::lvaGetRealType(unsigned lclNum)
2619 return lvaTable[lclNum].TypeGet();
2623 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2624 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2626 XX Inline functions XX
2628 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2629 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2632 inline unsigned Compiler::compMapILargNum(unsigned ILargNum)
2634 assert(ILargNum < info.compILargsCount || tiVerificationNeeded);
2636 // Note that this works because if compRetBuffArg/compTypeCtxtArg/lvVarargsHandleArg are not present
2637 // they will be BAD_VAR_NUM (MAX_UINT), which is larger than any variable number.
2638 if (ILargNum >= info.compRetBuffArg)
2641 assert(ILargNum < info.compLocalsCount || tiVerificationNeeded); // compLocals count already adjusted.
2644 if (ILargNum >= (unsigned)info.compTypeCtxtArg)
2647 assert(ILargNum < info.compLocalsCount || tiVerificationNeeded); // compLocals count already adjusted.
2650 if (ILargNum >= (unsigned)lvaVarargsHandleArg)
2653 assert(ILargNum < info.compLocalsCount || tiVerificationNeeded); // compLocals count already adjusted.
2656 assert(ILargNum < info.compArgsCount || tiVerificationNeeded);
2660 // For ARM varargs, all arguments go in integer registers, so swizzle the type
2661 inline var_types Compiler::mangleVarArgsType(var_types type)
2663 #ifdef _TARGET_ARMARCH_
2664 if (info.compIsVarArgs || opts.compUseSoftFP)
2676 #endif // _TARGET_ARMARCH_
2680 // For CORECLR there is no vararg on System V systems.
2682 inline regNumber Compiler::getCallArgIntRegister(regNumber floatReg)
2684 #ifdef _TARGET_AMD64_
2698 #else // !_TARGET_AMD64_
2699 // How will float args be passed for RyuJIT/x86?
2700 NYI("getCallArgIntRegister for RyuJIT/x86");
2702 #endif // !_TARGET_AMD64_
2705 inline regNumber Compiler::getCallArgFloatRegister(regNumber intReg)
2707 #ifdef _TARGET_AMD64_
2721 #else // !_TARGET_AMD64_
2722 // How will float args be passed for RyuJIT/x86?
2723 NYI("getCallArgFloatRegister for RyuJIT/x86");
2725 #endif // !_TARGET_AMD64_
2727 #endif // FEATURE_VARARG
2730 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2731 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2732 XX Register Allocator XX
2733 XX Inline functions XX
2735 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2736 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2739 /*****************************************************************************/
2741 inline bool rpCanAsgOperWithoutReg(GenTreePtr op, bool lclvar)
2745 switch (op->OperGet())
2751 type = genActualType(op->TypeGet());
2752 if (lclvar && ((type == TYP_INT) || (type == TYP_REF) || (type == TYP_BYREF)))
2765 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2766 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2769 XX Inline functions XX
2771 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2772 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2775 inline bool Compiler::compCanEncodePtrArgCntMax()
2777 #ifdef JIT32_GCENCODER
2779 // The GC encoding for fully interruptible methods does not
2780 // support more than 1023 pushed arguments, so we have to
2781 // use a partially interruptible GC info/encoding.
2783 return (fgPtrArgCntMax < MAX_PTRARG_OFS);
2784 #else // JIT32_GCENCODER
2789 /*****************************************************************************
2791 * Call the given function pointer for all nodes in the tree. The 'visitor'
2792 * fn should return one of the following values:
2794 * WALK_ABORT stop walking and return immediately
2795 * WALK_CONTINUE continue walking
2796 * WALK_SKIP_SUBTREES don't walk any subtrees of the node just visited
2798 * computeStack - true if we want to make stack visible to callback function
2801 inline Compiler::fgWalkResult Compiler::fgWalkTreePre(
2802 GenTreePtr* pTree, fgWalkPreFn* visitor, void* callBackData, bool lclVarsOnly, bool computeStack)
2805 fgWalkData walkData;
2807 walkData.compiler = this;
2808 walkData.wtprVisitorFn = visitor;
2809 walkData.pCallbackData = callBackData;
2810 walkData.parent = nullptr;
2811 walkData.wtprLclsOnly = lclVarsOnly;
2813 walkData.printModified = false;
2816 fgWalkResult result;
2817 if (lclVarsOnly && computeStack)
2819 GenericTreeWalker<true, true, false, true, true> walker(&walkData);
2820 result = walker.WalkTree(pTree, nullptr);
2822 else if (lclVarsOnly)
2824 GenericTreeWalker<false, true, false, true, true> walker(&walkData);
2825 result = walker.WalkTree(pTree, nullptr);
2827 else if (computeStack)
2829 GenericTreeWalker<true, true, false, false, true> walker(&walkData);
2830 result = walker.WalkTree(pTree, nullptr);
2834 GenericTreeWalker<false, true, false, false, true> walker(&walkData);
2835 result = walker.WalkTree(pTree, nullptr);
2839 if (verbose && walkData.printModified)
2848 /*****************************************************************************
2850 * Same as above, except the tree walk is performed in a depth-first fashion,
2851 * The 'visitor' fn should return one of the following values:
2853 * WALK_ABORT stop walking and return immediately
2854 * WALK_CONTINUE continue walking
2856 * computeStack - true if we want to make stack visible to callback function
2859 inline Compiler::fgWalkResult Compiler::fgWalkTreePost(GenTreePtr* pTree,
2860 fgWalkPostFn* visitor,
2864 fgWalkData walkData;
2866 walkData.compiler = this;
2867 walkData.wtpoVisitorFn = visitor;
2868 walkData.pCallbackData = callBackData;
2869 walkData.parent = nullptr;
2871 fgWalkResult result;
2874 GenericTreeWalker<true, false, true, false, true> walker(&walkData);
2875 result = walker.WalkTree(pTree, nullptr);
2879 GenericTreeWalker<false, false, true, false, true> walker(&walkData);
2880 result = walker.WalkTree(pTree, nullptr);
2883 assert(result == WALK_CONTINUE || result == WALK_ABORT);
2888 /*****************************************************************************
2890 * Call the given function pointer for all nodes in the tree. The 'visitor'
2891 * fn should return one of the following values:
2893 * WALK_ABORT stop walking and return immediately
2894 * WALK_CONTINUE continue walking
2895 * WALK_SKIP_SUBTREES don't walk any subtrees of the node just visited
2898 inline Compiler::fgWalkResult Compiler::fgWalkTree(GenTreePtr* pTree,
2899 fgWalkPreFn* preVisitor,
2900 fgWalkPreFn* postVisitor,
2904 fgWalkData walkData;
2906 walkData.compiler = this;
2907 walkData.wtprVisitorFn = preVisitor;
2908 walkData.wtpoVisitorFn = postVisitor;
2909 walkData.pCallbackData = callBackData;
2910 walkData.parent = nullptr;
2911 walkData.wtprLclsOnly = false;
2913 walkData.printModified = false;
2916 fgWalkResult result;
2918 assert(preVisitor || postVisitor);
2920 if (preVisitor && postVisitor)
2922 GenericTreeWalker<true, true, true, false, true> walker(&walkData);
2923 result = walker.WalkTree(pTree, nullptr);
2925 else if (preVisitor)
2927 GenericTreeWalker<true, true, false, false, true> walker(&walkData);
2928 result = walker.WalkTree(pTree, nullptr);
2932 GenericTreeWalker<true, false, true, false, true> walker(&walkData);
2933 result = walker.WalkTree(pTree, nullptr);
2937 if (verbose && walkData.printModified)
2946 /*****************************************************************************
2948 * Has this block been added to throw an inlined exception
2949 * Returns true if the block was added to throw one of:
2950 * range-check exception
2951 * argument exception (used by feature SIMD)
2952 * argument range-check exception (used by feature SIMD)
2953 * divide by zero exception (Not used on X86/X64)
2954 * null reference exception (Not currently used)
2955 * overflow exception
2958 inline bool Compiler::fgIsThrowHlpBlk(BasicBlock* block)
2960 if (!fgIsCodeAdded())
2965 if (!(block->bbFlags & BBF_INTERNAL) || block->bbJumpKind != BBJ_THROW)
2970 GenTree* call = block->lastNode();
2975 LIR::Range& blockRange = LIR::AsRange(block);
2976 for (LIR::Range::ReverseIterator node = blockRange.rbegin(), end = blockRange.rend(); node != end; ++node)
2978 if (node->OperGet() == GT_CALL)
2980 assert(*node == call);
2981 assert(node == blockRange.rbegin());
2988 if (!call || (call->gtOper != GT_CALL))
2993 if (!((call->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_RNGCHKFAIL)) ||
2994 (call->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_THROWDIVZERO)) ||
2995 (call->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_THROWNULLREF)) ||
2996 (call->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_OVERFLOW))))
3001 // We can get to this point for blocks that we didn't create as throw helper blocks
3002 // under stress, with crazy flow graph optimizations. So, walk the fgAddCodeList
3003 // for the final determination.
3005 for (AddCodeDsc* add = fgAddCodeList; add; add = add->acdNext)
3007 if (block == add->acdDstBlk)
3009 return add->acdKind == SCK_RNGCHK_FAIL || add->acdKind == SCK_DIV_BY_ZERO || add->acdKind == SCK_OVERFLOW ||
3010 add->acdKind == SCK_ARG_EXCPN || add->acdKind == SCK_ARG_RNG_EXCPN;
3014 // We couldn't find it in the fgAddCodeList
3018 #if !FEATURE_FIXED_OUT_ARGS
3020 /*****************************************************************************
3022 * Return the stackLevel of the inserted block that throws exception
3023 * (by calling the EE helper).
3026 inline unsigned Compiler::fgThrowHlpBlkStkLevel(BasicBlock* block)
3028 for (AddCodeDsc* add = fgAddCodeList; add; add = add->acdNext)
3030 if (block == add->acdDstBlk)
3032 // Compute assert cond separately as assert macro cannot have conditional compilation directives.
3034 (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);
3038 // TODO: bbTgtStkDepth is DEBUG-only.
3039 // Should we use it regularly and avoid this search.
3040 assert(block->bbTgtStkDepth == add->acdStkLvl);
3041 return add->acdStkLvl;
3045 noway_assert(!"fgThrowHlpBlkStkLevel should only be called if fgIsThrowHlpBlk() is true, but we can't find the "
3046 "block in the fgAddCodeList list");
3048 /* We couldn't find the basic block: it must not have been a throw helper block */
3053 #endif // !FEATURE_FIXED_OUT_ARGS
3056 Small inline function to change a given block to a throw block.
3059 inline void Compiler::fgConvertBBToThrowBB(BasicBlock* block)
3061 // If we're converting a BBJ_CALLFINALLY block to a BBJ_THROW block,
3062 // then mark the subsequent BBJ_ALWAYS block as unreferenced.
3063 if (block->isBBCallAlwaysPair())
3065 BasicBlock* leaveBlk = block->bbNext;
3066 noway_assert(leaveBlk->bbJumpKind == BBJ_ALWAYS);
3068 leaveBlk->bbFlags &= ~BBF_DONT_REMOVE;
3069 leaveBlk->bbRefs = 0;
3070 leaveBlk->bbPreds = nullptr;
3072 #if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
3073 // This function (fgConvertBBToThrowBB) can be called before the predecessor lists are created (e.g., in
3074 // fgMorph). The fgClearFinallyTargetBit() function to update the BBF_FINALLY_TARGET bit depends on these
3075 // predecessor lists. If there are no predecessor lists, we immediately clear all BBF_FINALLY_TARGET bits
3076 // (to allow subsequent dead code elimination to delete such blocks without asserts), and set a flag to
3077 // recompute them later, before they are required.
3078 if (fgComputePredsDone)
3080 fgClearFinallyTargetBit(leaveBlk->bbJumpDest);
3084 fgClearAllFinallyTargetBits();
3085 fgNeedToAddFinallyTargetBits = true;
3087 #endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
3090 block->bbJumpKind = BBJ_THROW;
3091 block->bbSetRunRarely(); // any block with a throw is rare
3094 /*****************************************************************************
3096 * Return true if we've added any new basic blocks.
3099 inline bool Compiler::fgIsCodeAdded()
3101 return fgAddCodeModf;
3104 /*****************************************************************************
3105 Is the offset too big?
3107 inline bool Compiler::fgIsBigOffset(size_t offset)
3109 return (offset > compMaxUncheckedOffsetForNullObject);
3112 /***********************************************************************************
3114 * Returns true if back-end will do other than integer division which currently occurs only
3115 * if "divisor" is a positive integer constant and a power of 2 other than 1 and INT_MIN
3118 inline bool Compiler::fgIsSignedDivOptimizable(GenTreePtr divisor)
3120 if (!opts.MinOpts() && divisor->IsCnsIntOrI())
3122 ssize_t ival = divisor->gtIntConCommon.IconValue();
3124 /* Is the divisor a power of 2 (excluding INT_MIN) ?.
3125 The intent of the third condition below is to exclude INT_MIN on a 64-bit platform
3126 and during codegen we need to encode ival-1 within 32 bits. If ival were INT_MIN
3127 then ival-1 would cause underflow.
3129 Note that we could put #ifdef around the third check so that it is applied only on
3130 64-bit platforms but the below is a more generic way to express it as it is a no-op
3131 on 32-bit platforms.
3133 return (ival > 0 && genMaxOneBit(ival) && ((ssize_t)(int)ival == ival));
3139 /************************************************************************************
3141 * Returns true if back-end will do other than integer division which currently occurs
3142 * if "divisor" is an unsigned integer constant and a power of 2 other than 1 and zero.
3145 inline bool Compiler::fgIsUnsignedDivOptimizable(GenTreePtr divisor)
3147 if (!opts.MinOpts() && divisor->IsCnsIntOrI())
3149 size_t ival = divisor->gtIntCon.gtIconVal;
3151 /* Is the divisor a power of 2 ? */
3152 return ival && genMaxOneBit(ival);
3158 /*****************************************************************************
3160 * Returns true if back-end will do other than integer division which currently occurs
3161 * if "divisor" is a positive integer constant and a power of 2 other than zero
3164 inline bool Compiler::fgIsSignedModOptimizable(GenTreePtr divisor)
3166 if (!opts.MinOpts() && divisor->IsCnsIntOrI())
3168 size_t ival = divisor->gtIntCon.gtIconVal;
3170 /* Is the divisor a power of 2 ? */
3171 return ssize_t(ival) > 0 && genMaxOneBit(ival);
3177 /*****************************************************************************
3179 * Returns true if back-end will do other than integer division which currently occurs
3180 * if "divisor" is a positive integer constant and a power of 2 other than zero
3183 inline bool Compiler::fgIsUnsignedModOptimizable(GenTreePtr divisor)
3185 if (!opts.MinOpts() && divisor->IsCnsIntOrI())
3187 size_t ival = divisor->gtIntCon.gtIconVal;
3189 /* Is the divisor a power of 2 ? */
3190 return ival != 0 && ival == (unsigned)genFindLowestBit(ival);
3197 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3198 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3200 XX Inline functions XX
3202 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3203 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3206 /*****************************************************************************/
3208 /* static */ inline unsigned Compiler::tmpSlot(unsigned size)
3210 noway_assert(size >= sizeof(int));
3211 noway_assert(size <= TEMP_MAX_SIZE);
3212 assert((size % sizeof(int)) == 0);
3214 assert(size < UINT32_MAX);
3215 return size / sizeof(int) - 1;
3218 /*****************************************************************************
3220 * Finish allocating temps - should be called each time after a pass is made
3221 * over a function body.
3224 inline void Compiler::tmpEnd()
3227 if (verbose && (tmpCount > 0))
3229 printf("%d tmps used\n", tmpCount);
3234 /*****************************************************************************
3236 * Shuts down the temp-tracking code. Should be called once per function
3240 inline void Compiler::tmpDone()
3246 assert(tmpAllFree());
3247 for (temp = tmpListBeg(), count = temp ? 1 : 0; temp; temp = tmpListNxt(temp), count += temp ? 1 : 0)
3249 assert(temp->tdLegalOffset());
3252 // Make sure that all the temps were released
3253 assert(count == tmpCount);
3254 assert(tmpGetCount == 0);
3259 inline bool Compiler::shouldUseVerboseTrees()
3261 return (JitConfig.JitDumpVerboseTrees() == 1);
3264 inline bool Compiler::shouldUseVerboseSsa()
3266 return (JitConfig.JitDumpVerboseSsa() == 1);
3269 //------------------------------------------------------------------------
3270 // shouldDumpASCIITrees: Should we use only ASCII characters for tree dumps?
3273 // This is set to default to 1 in clrConfigValues.h
3275 inline bool Compiler::shouldDumpASCIITrees()
3277 return (JitConfig.JitDumpASCII() == 1);
3280 /*****************************************************************************
3281 * Should we enable JitStress mode?
3283 * !=2: Vary stress. Performance will be slightly/moderately degraded
3284 * 2: Check-all stress. Performance will be REALLY horrible
3287 inline DWORD getJitStressLevel()
3289 return JitConfig.JitStress();
3292 /*****************************************************************************
3293 * Should we do the strict check for non-virtual call to the virtual method?
3296 inline DWORD StrictCheckForNonVirtualCallToVirtualMethod()
3298 return JitConfig.JitStrictCheckForNonVirtualCallToVirtualMethod() == 1;
3303 /*****************************************************************************/
3304 /* Map a register argument number ("RegArgNum") to a register number ("RegNum").
3305 * A RegArgNum is in this range:
3306 * [0, MAX_REG_ARG) -- for integer registers
3307 * [0, MAX_FLOAT_REG_ARG) -- for floating point registers
3308 * Note that RegArgNum's are overlapping for integer and floating-point registers,
3309 * while RegNum's are not (for ARM anyway, though for x86, it might be different).
3310 * If we have a fixed return buffer register and are given it's index
3311 * we return the fixed return buffer register
3314 inline regNumber genMapIntRegArgNumToRegNum(unsigned argNum)
3316 if (hasFixedRetBuffReg() && (argNum == theFixedRetBuffArgNum()))
3318 return theFixedRetBuffReg();
3321 assert(argNum < ArrLen(intArgRegs));
3323 return intArgRegs[argNum];
3326 inline regNumber genMapFloatRegArgNumToRegNum(unsigned argNum)
3328 #ifndef _TARGET_X86_
3329 assert(argNum < ArrLen(fltArgRegs));
3331 return fltArgRegs[argNum];
3333 assert(!"no x86 float arg regs\n");
3338 __forceinline regNumber genMapRegArgNumToRegNum(unsigned argNum, var_types type)
3340 if (varTypeIsFloating(type))
3342 return genMapFloatRegArgNumToRegNum(argNum);
3346 return genMapIntRegArgNumToRegNum(argNum);
3350 /*****************************************************************************/
3351 /* Map a register argument number ("RegArgNum") to a register mask of the associated register.
3352 * Note that for floating-pointer registers, only the low register for a register pair
3353 * (for a double on ARM) is returned.
3356 inline regMaskTP genMapIntRegArgNumToRegMask(unsigned argNum)
3358 assert(argNum < ArrLen(intArgMasks));
3360 return intArgMasks[argNum];
3363 inline regMaskTP genMapFloatRegArgNumToRegMask(unsigned argNum)
3365 #ifndef _TARGET_X86_
3366 assert(argNum < ArrLen(fltArgMasks));
3368 return fltArgMasks[argNum];
3370 assert(!"no x86 float arg regs\n");
3375 __forceinline regMaskTP genMapArgNumToRegMask(unsigned argNum, var_types type)
3378 if (varTypeIsFloating(type))
3380 result = genMapFloatRegArgNumToRegMask(argNum);
3382 if (type == TYP_DOUBLE)
3384 assert((result & RBM_DBL_REGS) != 0);
3385 result |= (result << 1);
3391 result = genMapIntRegArgNumToRegMask(argNum);
3396 /*****************************************************************************/
3397 /* Map a register number ("RegNum") to a register argument number ("RegArgNum")
3398 * If we have a fixed return buffer register we return theFixedRetBuffArgNum
3401 inline unsigned genMapIntRegNumToRegArgNum(regNumber regNum)
3403 assert(genRegMask(regNum) & fullIntArgRegMask());
3409 #if MAX_REG_ARG >= 2
3412 #if MAX_REG_ARG >= 3
3415 #if MAX_REG_ARG >= 4
3418 #if MAX_REG_ARG >= 5
3421 #if MAX_REG_ARG >= 6
3424 #if MAX_REG_ARG >= 7
3427 #if MAX_REG_ARG >= 8
3438 // Check for the Arm64 fixed return buffer argument register
3439 if (hasFixedRetBuffReg() && (regNum == theFixedRetBuffReg()))
3441 return theFixedRetBuffArgNum();
3445 assert(!"invalid register arg register");
3451 inline unsigned genMapFloatRegNumToRegArgNum(regNumber regNum)
3453 assert(genRegMask(regNum) & RBM_FLTARG_REGS);
3456 return regNum - REG_F0;
3457 #elif defined(_TARGET_ARM64_)
3458 return regNum - REG_V0;
3459 #elif defined(UNIX_AMD64_ABI)
3460 return regNum - REG_FLTARG_0;
3463 #if MAX_FLOAT_REG_ARG >= 1
3468 #if MAX_REG_ARG >= 2
3471 #if MAX_REG_ARG >= 3
3474 #if MAX_REG_ARG >= 4
3477 #if MAX_REG_ARG >= 5
3485 assert(!"invalid register arg register");
3489 assert(!"flt reg args not allowed");
3495 inline unsigned genMapRegNumToRegArgNum(regNumber regNum, var_types type)
3497 if (varTypeIsFloating(type))
3499 return genMapFloatRegNumToRegArgNum(regNum);
3503 return genMapIntRegNumToRegArgNum(regNum);
3507 /*****************************************************************************/
3508 /* Return a register mask with the first 'numRegs' argument registers set.
3511 inline regMaskTP genIntAllRegArgMask(unsigned numRegs)
3513 assert(numRegs <= MAX_REG_ARG);
3515 regMaskTP result = RBM_NONE;
3516 for (unsigned i = 0; i < numRegs; i++)
3518 result |= intArgMasks[i];
3523 #if !FEATURE_STACK_FP_X87
3525 inline regMaskTP genFltAllRegArgMask(unsigned numRegs)
3527 assert(numRegs <= MAX_FLOAT_REG_ARG);
3529 regMaskTP result = RBM_NONE;
3530 for (unsigned i = 0; i < numRegs; i++)
3532 result |= fltArgMasks[i];
3537 #endif // !FEATURE_STACK_FP_X87
3540 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3541 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3543 XX Inline functions XX
3545 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3546 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3549 /*****************************************************************************
3551 * Update the current set of live variables based on the life set recorded
3552 * in the given expression tree node.
3555 template <bool ForCodeGen>
3556 inline void Compiler::compUpdateLife(GenTreePtr tree)
3558 // TODO-Cleanup: We shouldn't really be calling this more than once
3559 if (tree == compCurLifeTree)
3564 if (!tree->OperIsNonPhiLocal() && fgIsIndirOfAddrOfLocal(tree) == nullptr)
3569 compUpdateLifeVar<ForCodeGen>(tree);
3572 template <bool ForCodeGen>
3573 inline void Compiler::compUpdateLife(VARSET_VALARG_TP newLife)
3575 if (!VarSetOps::Equal(this, compCurLife, newLife))
3577 compChangeLife<ForCodeGen>(newLife DEBUGARG(nullptr));
3584 printf("Liveness not changing: %s ", VarSetOps::ToString(this, compCurLife));
3585 dumpConvertedVarSet(this, compCurLife);
3592 /*****************************************************************************
3594 * We stash cookies in basic blocks for the code emitter; this call retrieves
3595 * the cookie associated with the given basic block.
3598 inline void* emitCodeGetCookie(BasicBlock* block)
3601 return block->bbEmitCookie;
3605 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3606 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3608 XX Inline functions XX
3610 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3611 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3614 #if LOCAL_ASSERTION_PROP
3616 /*****************************************************************************
3618 * The following resets the value assignment table
3619 * used only during local assertion prop
3622 inline void Compiler::optAssertionReset(AssertionIndex limit)
3624 PREFAST_ASSUME(optAssertionCount <= optMaxAssertionCount);
3626 while (optAssertionCount > limit)
3628 AssertionIndex index = optAssertionCount;
3629 AssertionDsc* curAssertion = optGetAssertion(index);
3630 optAssertionCount--;
3631 unsigned lclNum = curAssertion->op1.lcl.lclNum;
3632 assert(lclNum < lvaTableCnt);
3633 BitVecOps::RemoveElemD(apTraits, GetAssertionDep(lclNum), index - 1);
3636 // Find the Copy assertions
3638 if ((curAssertion->assertionKind == OAK_EQUAL) && (curAssertion->op1.kind == O1K_LCLVAR) &&
3639 (curAssertion->op2.kind == O2K_LCLVAR_COPY))
3642 // op2.lcl.lclNum no longer depends upon this assertion
3644 lclNum = curAssertion->op2.lcl.lclNum;
3645 BitVecOps::RemoveElemD(apTraits, GetAssertionDep(lclNum), index - 1);
3648 while (optAssertionCount < limit)
3650 AssertionIndex index = ++optAssertionCount;
3651 AssertionDsc* curAssertion = optGetAssertion(index);
3652 unsigned lclNum = curAssertion->op1.lcl.lclNum;
3653 BitVecOps::AddElemD(apTraits, GetAssertionDep(lclNum), index - 1);
3656 // Check for Copy assertions
3658 if ((curAssertion->assertionKind == OAK_EQUAL) && (curAssertion->op1.kind == O1K_LCLVAR) &&
3659 (curAssertion->op2.kind == O2K_LCLVAR_COPY))
3662 // op2.lcl.lclNum now depends upon this assertion
3664 lclNum = curAssertion->op2.lcl.lclNum;
3665 BitVecOps::AddElemD(apTraits, GetAssertionDep(lclNum), index - 1);
3670 /*****************************************************************************
3672 * The following removes the i-th entry in the value assignment table
3673 * used only during local assertion prop
3676 inline void Compiler::optAssertionRemove(AssertionIndex index)
3679 assert(index <= optAssertionCount);
3680 PREFAST_ASSUME(optAssertionCount <= optMaxAssertionCount);
3682 AssertionDsc* curAssertion = optGetAssertion(index);
3684 // Two cases to consider if (index == optAssertionCount) then the last
3685 // entry in the table is to be removed and that happens automatically when
3686 // optAssertionCount is decremented and we can just clear the optAssertionDep bits
3687 // The other case is when index < optAssertionCount and here we overwrite the
3688 // index-th entry in the table with the data found at the end of the table
3689 // Since we are reordering the rable the optAssertionDep bits need to be recreated
3690 // using optAssertionReset(0) and optAssertionReset(newAssertionCount) will
3691 // correctly update the optAssertionDep bits
3693 if (index == optAssertionCount)
3695 unsigned lclNum = curAssertion->op1.lcl.lclNum;
3696 BitVecOps::RemoveElemD(apTraits, GetAssertionDep(lclNum), index - 1);
3699 // Check for Copy assertions
3701 if ((curAssertion->assertionKind == OAK_EQUAL) && (curAssertion->op1.kind == O1K_LCLVAR) &&
3702 (curAssertion->op2.kind == O2K_LCLVAR_COPY))
3705 // op2.lcl.lclNum no longer depends upon this assertion
3707 lclNum = curAssertion->op2.lcl.lclNum;
3708 BitVecOps::RemoveElemD(apTraits, GetAssertionDep(lclNum), index - 1);
3711 optAssertionCount--;
3715 AssertionDsc* lastAssertion = optGetAssertion(optAssertionCount);
3716 AssertionIndex newAssertionCount = optAssertionCount - 1;
3718 optAssertionReset(0); // This make optAssertionCount equal 0
3720 memcpy(curAssertion, // the entry to be removed
3721 lastAssertion, // last entry in the table
3722 sizeof(AssertionDsc));
3724 optAssertionReset(newAssertionCount);
3727 #endif // LOCAL_ASSERTION_PROP
3729 inline void Compiler::LoopDsc::AddModifiedField(Compiler* comp, CORINFO_FIELD_HANDLE fldHnd)
3731 if (lpFieldsModified == nullptr)
3734 new (comp->getAllocatorLoopHoist()) Compiler::LoopDsc::FieldHandleSet(comp->getAllocatorLoopHoist());
3736 lpFieldsModified->Set(fldHnd, true);
3739 inline void Compiler::LoopDsc::AddModifiedElemType(Compiler* comp, CORINFO_CLASS_HANDLE structHnd)
3741 if (lpArrayElemTypesModified == nullptr)
3743 lpArrayElemTypesModified =
3744 new (comp->getAllocatorLoopHoist()) Compiler::LoopDsc::ClassHandleSet(comp->getAllocatorLoopHoist());
3746 lpArrayElemTypesModified->Set(structHnd, true);
3749 inline void Compiler::LoopDsc::VERIFY_lpIterTree()
3752 assert(lpFlags & LPFLG_ITER);
3754 // iterTree should be "lcl <op>= const"
3758 assert(lpIterTree->OperIsAssignment());
3760 if (lpIterTree->OperGet() == GT_ASG)
3762 GenTreePtr lhs = lpIterTree->gtOp.gtOp1;
3763 GenTreePtr rhs = lpIterTree->gtOp.gtOp2;
3764 assert(lhs->OperGet() == GT_LCL_VAR);
3766 switch (rhs->gtOper)
3775 assert(!"Unknown operator for loop increment");
3777 assert(rhs->gtOp.gtOp1->OperGet() == GT_LCL_VAR);
3778 assert(rhs->gtOp.gtOp1->AsLclVarCommon()->GetLclNum() == lhs->AsLclVarCommon()->GetLclNum());
3779 assert(rhs->gtOp.gtOp2->OperGet() == GT_CNS_INT);
3783 assert(lpIterTree->gtOp.gtOp1->OperGet() == GT_LCL_VAR);
3784 assert(lpIterTree->gtOp.gtOp2->OperGet() == GT_CNS_INT);
3789 //-----------------------------------------------------------------------------
3791 inline unsigned Compiler::LoopDsc::lpIterVar()
3793 VERIFY_lpIterTree();
3794 return lpIterTree->gtOp.gtOp1->gtLclVarCommon.gtLclNum;
3797 //-----------------------------------------------------------------------------
3799 inline int Compiler::LoopDsc::lpIterConst()
3801 VERIFY_lpIterTree();
3802 if (lpIterTree->OperGet() == GT_ASG)
3804 GenTreePtr rhs = lpIterTree->gtOp.gtOp2;
3805 return (int)rhs->gtOp.gtOp2->gtIntCon.gtIconVal;
3809 return (int)lpIterTree->gtOp.gtOp2->gtIntCon.gtIconVal;
3813 //-----------------------------------------------------------------------------
3815 inline genTreeOps Compiler::LoopDsc::lpIterOper()
3817 VERIFY_lpIterTree();
3818 if (lpIterTree->OperGet() == GT_ASG)
3820 GenTreePtr rhs = lpIterTree->gtOp.gtOp2;
3821 return rhs->OperGet();
3825 return lpIterTree->OperGet();
3829 inline var_types Compiler::LoopDsc::lpIterOperType()
3831 VERIFY_lpIterTree();
3833 var_types type = lpIterTree->TypeGet();
3834 assert(genActualType(type) == TYP_INT);
3836 if ((lpIterTree->gtFlags & GTF_UNSIGNED) && type == TYP_INT)
3844 inline void Compiler::LoopDsc::VERIFY_lpTestTree()
3847 assert(lpFlags & LPFLG_ITER);
3850 genTreeOps oper = lpTestTree->OperGet();
3851 assert(GenTree::OperIsCompare(oper));
3853 GenTreePtr iterator = nullptr;
3854 GenTreePtr limit = nullptr;
3855 if ((lpTestTree->gtOp.gtOp2->gtOper == GT_LCL_VAR) && (lpTestTree->gtOp.gtOp2->gtFlags & GTF_VAR_ITERATOR) != 0)
3857 iterator = lpTestTree->gtOp.gtOp2;
3858 limit = lpTestTree->gtOp.gtOp1;
3860 else if ((lpTestTree->gtOp.gtOp1->gtOper == GT_LCL_VAR) &&
3861 (lpTestTree->gtOp.gtOp1->gtFlags & GTF_VAR_ITERATOR) != 0)
3863 iterator = lpTestTree->gtOp.gtOp1;
3864 limit = lpTestTree->gtOp.gtOp2;
3868 // one of the nodes has to be the iterator
3872 if (lpFlags & LPFLG_CONST_LIMIT)
3874 assert(limit->OperIsConst());
3876 if (lpFlags & LPFLG_VAR_LIMIT)
3878 assert(limit->OperGet() == GT_LCL_VAR);
3880 if (lpFlags & LPFLG_ARRLEN_LIMIT)
3882 assert(limit->OperGet() == GT_ARR_LENGTH);
3887 //-----------------------------------------------------------------------------
3889 inline bool Compiler::LoopDsc::lpIsReversed()
3891 VERIFY_lpTestTree();
3892 return ((lpTestTree->gtOp.gtOp2->gtOper == GT_LCL_VAR) &&
3893 (lpTestTree->gtOp.gtOp2->gtFlags & GTF_VAR_ITERATOR) != 0);
3896 //-----------------------------------------------------------------------------
3898 inline genTreeOps Compiler::LoopDsc::lpTestOper()
3900 VERIFY_lpTestTree();
3901 genTreeOps op = lpTestTree->OperGet();
3902 return lpIsReversed() ? GenTree::SwapRelop(op) : op;
3905 //-----------------------------------------------------------------------------
3907 inline GenTreePtr Compiler::LoopDsc::lpIterator()
3909 VERIFY_lpTestTree();
3911 return lpIsReversed() ? lpTestTree->gtOp.gtOp2 : lpTestTree->gtOp.gtOp1;
3914 //-----------------------------------------------------------------------------
3916 inline GenTreePtr Compiler::LoopDsc::lpLimit()
3918 VERIFY_lpTestTree();
3920 return lpIsReversed() ? lpTestTree->gtOp.gtOp1 : lpTestTree->gtOp.gtOp2;
3923 //-----------------------------------------------------------------------------
3925 inline int Compiler::LoopDsc::lpConstLimit()
3927 VERIFY_lpTestTree();
3928 assert(lpFlags & LPFLG_CONST_LIMIT);
3930 GenTreePtr limit = lpLimit();
3931 assert(limit->OperIsConst());
3932 return (int)limit->gtIntCon.gtIconVal;
3935 //-----------------------------------------------------------------------------
3937 inline unsigned Compiler::LoopDsc::lpVarLimit()
3939 VERIFY_lpTestTree();
3940 assert(lpFlags & LPFLG_VAR_LIMIT);
3942 GenTreePtr limit = lpLimit();
3943 assert(limit->OperGet() == GT_LCL_VAR);
3944 return limit->gtLclVarCommon.gtLclNum;
3947 //-----------------------------------------------------------------------------
3949 inline bool Compiler::LoopDsc::lpArrLenLimit(Compiler* comp, ArrIndex* index)
3951 VERIFY_lpTestTree();
3952 assert(lpFlags & LPFLG_ARRLEN_LIMIT);
3954 GenTreePtr limit = lpLimit();
3955 assert(limit->OperGet() == GT_ARR_LENGTH);
3957 // Check if we have a.length or a[i][j].length
3958 if (limit->gtArrLen.ArrRef()->gtOper == GT_LCL_VAR)
3960 index->arrLcl = limit->gtArrLen.ArrRef()->gtLclVarCommon.gtLclNum;
3964 // We have a[i].length, extract a[i] pattern.
3965 else if (limit->gtArrLen.ArrRef()->gtOper == GT_COMMA)
3967 return comp->optReconstructArrIndex(limit->gtArrLen.ArrRef(), index, BAD_VAR_NUM);
3972 /*****************************************************************************
3973 * Is "var" assigned in the loop "lnum" ?
3976 inline bool Compiler::optIsVarAssgLoop(unsigned lnum, unsigned var)
3978 assert(lnum < optLoopCount);
3979 if (var < lclMAX_ALLSET_TRACKED)
3981 ALLVARSET_TP vs(AllVarSetOps::MakeSingleton(this, var));
3982 return optIsSetAssgLoop(lnum, vs) != 0;
3986 return optIsVarAssigned(optLoopTable[lnum].lpHead->bbNext, optLoopTable[lnum].lpBottom, nullptr, var);
3990 /*****************************************************************************
3991 * If the tree is a tracked local variable, return its LclVarDsc ptr.
3994 inline LclVarDsc* Compiler::optIsTrackedLocal(GenTreePtr tree)
3999 if (tree->gtOper != GT_LCL_VAR)
4004 lclNum = tree->gtLclVarCommon.gtLclNum;
4006 assert(lclNum < lvaCount);
4007 varDsc = lvaTable + lclNum;
4009 /* if variable not tracked, return NULL */
4010 if (!varDsc->lvTracked)
4019 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4020 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4022 XX Optimization activation rules XX
4024 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4025 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4028 // are we compiling for fast code, or are we compiling for blended code and
4030 // We return true for BLENDED_CODE if the Block executes more than BB_LOOP_WEIGHT/2
4031 inline bool Compiler::optFastCodeOrBlendedLoop(BasicBlock::weight_t bbWeight)
4033 return (compCodeOpt() == FAST_CODE) ||
4034 ((compCodeOpt() == BLENDED_CODE) && (bbWeight > (BB_LOOP_WEIGHT / 2 * BB_UNITY_WEIGHT)));
4037 // are we running on a Intel Pentium 4?
4038 inline bool Compiler::optPentium4(void)
4040 return (info.genCPU == CPU_X86_PENTIUM_4);
4043 // should we use add/sub instead of inc/dec? (faster on P4, but increases size)
4044 inline bool Compiler::optAvoidIncDec(BasicBlock::weight_t bbWeight)
4046 return optPentium4() && optFastCodeOrBlendedLoop(bbWeight);
4049 // should we try to replace integer multiplication with lea/add/shift sequences?
4050 inline bool Compiler::optAvoidIntMult(void)
4052 return (compCodeOpt() != SMALL_CODE);
4056 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4057 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4059 XX Inline functions XX
4061 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4062 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4065 extern var_types JITtype2varType(CorInfoType type);
4067 #include "ee_il_dll.hpp"
4069 inline CORINFO_METHOD_HANDLE Compiler::eeFindHelper(unsigned helper)
4071 assert(helper < CORINFO_HELP_COUNT);
4073 /* Helpers are marked by the fact that they are odd numbers
4074 * force this to be an odd number (will shift it back to extract) */
4076 return ((CORINFO_METHOD_HANDLE)(size_t)((helper << 2) + 1));
4079 inline CorInfoHelpFunc Compiler::eeGetHelperNum(CORINFO_METHOD_HANDLE method)
4081 // Helpers are marked by the fact that they are odd numbers
4082 if (!(((size_t)method) & 1))
4084 return (CORINFO_HELP_UNDEF);
4086 return ((CorInfoHelpFunc)(((size_t)method) >> 2));
4089 inline Compiler::fgWalkResult Compiler::CountSharedStaticHelper(GenTreePtr* pTree, fgWalkData* data)
4091 if (Compiler::IsSharedStaticHelper(*pTree))
4093 int* pCount = (int*)data->pCallbackData;
4097 return WALK_CONTINUE;
4100 // TODO-Cleanup: Replace calls to IsSharedStaticHelper with new HelperCallProperties
4103 inline bool Compiler::IsSharedStaticHelper(GenTreePtr tree)
4105 if (tree->gtOper != GT_CALL || tree->gtCall.gtCallType != CT_HELPER)
4110 CorInfoHelpFunc helper = eeGetHelperNum(tree->gtCall.gtCallMethHnd);
4113 // More helpers being added to IsSharedStaticHelper (that have similar behaviors but are not true
4114 // ShareStaticHelperts)
4115 helper == CORINFO_HELP_STRCNS || helper == CORINFO_HELP_BOX ||
4117 // helpers being added to IsSharedStaticHelper
4118 helper == CORINFO_HELP_GETSTATICFIELDADDR_CONTEXT || helper == CORINFO_HELP_GETSTATICFIELDADDR_TLS ||
4119 helper == CORINFO_HELP_GETGENERICS_GCSTATIC_BASE || helper == CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE ||
4120 helper == CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE ||
4121 helper == CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE ||
4123 helper == CORINFO_HELP_GETSHARED_GCSTATIC_BASE || helper == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE ||
4124 helper == CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR ||
4125 helper == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR ||
4126 helper == CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS ||
4127 helper == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS ||
4128 helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE ||
4129 helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE ||
4130 helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR ||
4131 helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR ||
4132 helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS ||
4133 helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS ||
4134 #ifdef FEATURE_READYTORUN_COMPILER
4135 helper == CORINFO_HELP_READYTORUN_STATIC_BASE || helper == CORINFO_HELP_READYTORUN_GENERIC_STATIC_BASE ||
4137 helper == CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS;
4139 // See above TODO-Cleanup
4140 bool result2 = s_helperCallProperties.IsPure(helper) && s_helperCallProperties.NonNullReturn(helper);
4141 assert (result1 == result2);
4146 inline bool Compiler::IsTreeAlwaysHoistable(GenTreePtr tree)
4148 if (IsSharedStaticHelper(tree))
4150 return (GTF_CALL_HOISTABLE & tree->gtFlags) ? true : false;
4158 inline bool Compiler::IsGcSafePoint(GenTreePtr tree)
4162 GenTreeCall* call = tree->AsCall();
4163 if (!call->IsFastTailCall())
4165 if (call->gtCallType == CT_INDIRECT)
4169 else if (call->gtCallType == CT_USER_FUNC)
4171 if ((call->gtCallMoreFlags & GTF_CALL_M_NOGCCHECK) == 0)
4176 // otherwise we have a CT_HELPER
4184 // Note that we want to have two special FIELD_HANDLES that will both
4185 // be considered non-Data Offset handles
4187 // The special values that we use are FLD_GLOBAL_DS and FLD_GLOBAL_FS
4190 inline bool jitStaticFldIsGlobAddr(CORINFO_FIELD_HANDLE fldHnd)
4192 return (fldHnd == FLD_GLOBAL_DS || fldHnd == FLD_GLOBAL_FS);
4195 #if defined(DEBUG) || defined(FEATURE_JIT_METHOD_PERF) || defined(FEATURE_SIMD) || defined(FEATURE_TRACELOGGING)
4197 inline bool Compiler::eeIsNativeMethod(CORINFO_METHOD_HANDLE method)
4199 return ((((size_t)method) & 0x2) == 0x2);
4202 inline CORINFO_METHOD_HANDLE Compiler::eeGetMethodHandleForNative(CORINFO_METHOD_HANDLE method)
4204 assert((((size_t)method) & 0x3) == 0x2);
4205 return (CORINFO_METHOD_HANDLE)(((size_t)method) & ~0x3);
4209 inline CORINFO_METHOD_HANDLE Compiler::eeMarkNativeTarget(CORINFO_METHOD_HANDLE method)
4211 assert((((size_t)method) & 0x3) == 0);
4212 if (method == nullptr)
4218 return (CORINFO_METHOD_HANDLE)(((size_t)method) | 0x2);
4223 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4224 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4226 XX Inline functions XX
4228 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4229 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
4233 inline bool Compiler::compStressCompile(compStressArea stressArea, unsigned weightPercentage)
4239 inline ArenaAllocator* Compiler::compGetAllocator()
4241 return compAllocator;
4244 /*****************************************************************************
4246 * Allocate memory from the no-release allocator. All such memory will be
4247 * freed up simulataneously at the end of the procedure
4252 inline void* Compiler::compGetMem(size_t sz, CompMemKind cmk)
4256 #if MEASURE_MEM_ALLOC
4257 genMemStats.AddAlloc(sz, cmk);
4260 return compAllocator->allocateMemory(sz);
4265 // Wrapper for Compiler::compGetMem that can be forward-declared for use in template
4266 // types which Compiler depends on but which need to allocate heap memory.
4267 inline void* compGetMem(Compiler* comp, size_t sz)
4269 return comp->compGetMem(sz);
4272 /*****************************************************************************
4274 * A common memory allocation for arrays of structures involves the
4275 * multiplication of the number of elements with the size of each element.
4276 * If this computation overflows, then the memory allocation might succeed,
4277 * but not allocate sufficient memory for all the elements. This can cause
4278 * us to overwrite the allocation, and AV or worse, corrupt memory.
4280 * This method checks for overflow, and succeeds only when it detects
4281 * that there's no overflow. It should be cheap, because when inlined with
4282 * a constant elemSize, the division should be done in compile time, and so
4283 * at run time we simply have a check of numElem against some number (this
4284 * is why we __forceinline).
4287 #define MAX_MEMORY_PER_ALLOCATION (512 * 1024 * 1024)
4289 __forceinline void* Compiler::compGetMemArray(size_t numElem, size_t elemSize, CompMemKind cmk)
4291 if (numElem > (MAX_MEMORY_PER_ALLOCATION / elemSize))
4296 return compGetMem(numElem * elemSize, cmk);
4299 /******************************************************************************
4301 * Roundup the allocated size so that if this memory block is aligned,
4302 * then the next block allocated too will be aligned.
4303 * The JIT will always try to keep all the blocks aligned.
4306 inline void Compiler::compFreeMem(void* ptr)
4310 inline bool Compiler::compIsProfilerHookNeeded()
4312 #ifdef PROFILING_SUPPORTED
4313 return compProfilerHookNeeded
4314 // IL stubs are excluded by VM and we need to do the same even running
4315 // under a complus env hook to generate profiler hooks
4316 || (opts.compJitELTHookEnabled && !opts.jitFlags->IsSet(JitFlags::JIT_FLAG_IL_STUB));
4317 #else // !PROFILING_SUPPORTED
4319 #endif // !PROFILING_SUPPORTED
4322 /*****************************************************************************
4324 * Check for the special case where the object is the constant 0.
4325 * As we can't even fold the tree (null+fldOffs), we are left with
4326 * op1 and op2 both being a constant. This causes lots of problems.
4327 * We simply grab a temp and assign 0 to it and use it in place of the NULL.
4330 inline GenTreePtr Compiler::impCheckForNullPointer(GenTreePtr obj)
4332 /* If it is not a GC type, we will be able to fold it.
4333 So don't need to do anything */
4335 if (!varTypeIsGC(obj->TypeGet()))
4340 if (obj->gtOper == GT_CNS_INT)
4342 assert(obj->gtType == TYP_REF || obj->gtType == TYP_BYREF);
4343 assert(obj->gtIntCon.gtIconVal == 0);
4345 unsigned tmp = lvaGrabTemp(true DEBUGARG("CheckForNullPointer"));
4347 // We don't need to spill while appending as we are only assigning
4348 // NULL to a freshly-grabbed temp.
4350 impAssignTempGen(tmp, obj, (unsigned)CHECK_SPILL_NONE);
4352 obj = gtNewLclvNode(tmp, obj->gtType);
4358 /*****************************************************************************
4360 * Check for the special case where the object is the methods original 'this' pointer.
4361 * Note that, the original 'this' pointer is always local var 0 for non-static method,
4362 * even if we might have created the copy of 'this' pointer in lvaArg0Var.
4365 inline bool Compiler::impIsThis(GenTreePtr obj)
4367 if (compIsForInlining())
4369 return impInlineInfo->InlinerCompiler->impIsThis(obj);
4373 return ((obj != nullptr) && (obj->gtOper == GT_LCL_VAR) && lvaIsOriginalThisArg(obj->gtLclVarCommon.gtLclNum));
4377 /*****************************************************************************
4379 * Check to see if the delegate is created using "LDFTN <TOK>" or not.
4382 inline bool Compiler::impIsLDFTN_TOKEN(const BYTE* delegateCreateStart, const BYTE* newobjCodeAddr)
4384 assert(newobjCodeAddr[0] == CEE_NEWOBJ);
4385 return (newobjCodeAddr - delegateCreateStart == 6 && // LDFTN <TOK> takes 6 bytes
4386 delegateCreateStart[0] == CEE_PREFIX1 && delegateCreateStart[1] == (CEE_LDFTN & 0xFF));
4389 /*****************************************************************************
4391 * Check to see if the delegate is created using "DUP LDVIRTFTN <TOK>" or not.
4394 inline bool Compiler::impIsDUP_LDVIRTFTN_TOKEN(const BYTE* delegateCreateStart, const BYTE* newobjCodeAddr)
4396 assert(newobjCodeAddr[0] == CEE_NEWOBJ);
4397 return (newobjCodeAddr - delegateCreateStart == 7 && // DUP LDVIRTFTN <TOK> takes 6 bytes
4398 delegateCreateStart[0] == CEE_DUP && delegateCreateStart[1] == CEE_PREFIX1 &&
4399 delegateCreateStart[2] == (CEE_LDVIRTFTN & 0xFF));
4401 /*****************************************************************************
4403 * Returns true if the compiler instance is created for import only (verification).
4406 inline bool Compiler::compIsForImportOnly()
4408 return opts.jitFlags->IsSet(JitFlags::JIT_FLAG_IMPORT_ONLY);
4411 /*****************************************************************************
4413 * Returns true if the compiler instance is created for inlining.
4416 inline bool Compiler::compIsForInlining()
4418 return (impInlineInfo != nullptr);
4421 /*****************************************************************************
4423 * Check the inline result field in the compiler to see if inlining failed or not.
4426 inline bool Compiler::compDonotInline()
4428 if (compIsForInlining())
4430 assert(compInlineResult != nullptr);
4431 return compInlineResult->IsFailure();
4439 inline bool Compiler::impIsPrimitive(CorInfoType jitType)
4441 return ((CORINFO_TYPE_BOOL <= jitType && jitType <= CORINFO_TYPE_DOUBLE) || jitType == CORINFO_TYPE_PTR);
4444 /*****************************************************************************
4446 * Get the promotion type of a struct local.
4449 inline Compiler::lvaPromotionType Compiler::lvaGetPromotionType(const LclVarDsc* varDsc)
4451 assert(!varDsc->lvPromoted || varTypeIsPromotable(varDsc) || varDsc->lvUnusedStruct);
4453 if (!varDsc->lvPromoted)
4455 // no struct promotion for this LclVar
4456 return PROMOTION_TYPE_NONE;
4458 if (varDsc->lvDoNotEnregister)
4460 // The struct is not enregistered
4461 return PROMOTION_TYPE_DEPENDENT;
4463 if (!varDsc->lvIsParam)
4465 // The struct is a register candidate
4466 return PROMOTION_TYPE_INDEPENDENT;
4469 // Has struct promotion for arguments been disabled using COMPlus_JitNoStructPromotion=2
4470 if (fgNoStructParamPromotion)
4472 // The struct parameter is not enregistered
4473 return PROMOTION_TYPE_DEPENDENT;
4476 // We have a parameter that could be enregistered
4477 CLANG_FORMAT_COMMENT_ANCHOR;
4479 #if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
4481 // The struct parameter is a register candidate
4482 return PROMOTION_TYPE_INDEPENDENT;
4484 // The struct parameter is not enregistered
4485 return PROMOTION_TYPE_DEPENDENT;
4489 /*****************************************************************************
4491 * Get the promotion type of a struct local.
4494 inline Compiler::lvaPromotionType Compiler::lvaGetPromotionType(unsigned varNum)
4496 assert(varNum < lvaCount);
4497 return lvaGetPromotionType(&lvaTable[varNum]);
4500 /*****************************************************************************
4502 * Given a field local, get the promotion type of its parent struct local.
4505 inline Compiler::lvaPromotionType Compiler::lvaGetParentPromotionType(const LclVarDsc* varDsc)
4507 assert(varDsc->lvIsStructField);
4508 assert(varDsc->lvParentLcl < lvaCount);
4510 lvaPromotionType promotionType = lvaGetPromotionType(varDsc->lvParentLcl);
4511 assert(promotionType != PROMOTION_TYPE_NONE);
4512 return promotionType;
4515 /*****************************************************************************
4517 * Given a field local, get the promotion type of its parent struct local.
4520 inline Compiler::lvaPromotionType Compiler::lvaGetParentPromotionType(unsigned varNum)
4522 assert(varNum < lvaCount);
4523 return lvaGetParentPromotionType(&lvaTable[varNum]);
4526 /*****************************************************************************
4528 * Return true if the local is a field local of a promoted struct of type PROMOTION_TYPE_DEPENDENT.
4529 * Return false otherwise.
4532 inline bool Compiler::lvaIsFieldOfDependentlyPromotedStruct(const LclVarDsc* varDsc)
4534 if (!varDsc->lvIsStructField)
4539 lvaPromotionType promotionType = lvaGetParentPromotionType(varDsc);
4540 if (promotionType == PROMOTION_TYPE_DEPENDENT)
4545 assert(promotionType == PROMOTION_TYPE_INDEPENDENT);
4549 //------------------------------------------------------------------------
4550 // lvaIsGCTracked: Determine whether this var should be reported
4551 // as tracked for GC purposes.
4554 // varDsc - the LclVarDsc for the var in question.
4557 // Returns true if the variable should be reported as tracked in the GC info.
4560 // This never returns true for struct variables, even if they are tracked.
4561 // This is because struct variables are never tracked as a whole for GC purposes.
4562 // It is up to the caller to ensure that the fields of struct variables are
4563 // correctly tracked.
4564 // On Amd64, we never GC-track fields of dependently promoted structs, even
4565 // though they may be tracked for optimization purposes.
4566 // It seems that on x86 and arm, we simply don't track these
4567 // fields, though I have not verified that. I attempted to make these GC-tracked,
4568 // but there was too much logic that depends on these being untracked, so changing
4569 // this would require non-trivial effort.
4571 inline bool Compiler::lvaIsGCTracked(const LclVarDsc* varDsc)
4573 if (varDsc->lvTracked && (varDsc->lvType == TYP_REF || varDsc->lvType == TYP_BYREF))
4575 // Stack parameters are always untracked w.r.t. GC reportings
4576 const bool isStackParam = varDsc->lvIsParam && !varDsc->lvIsRegArg;
4577 #ifdef _TARGET_AMD64_
4578 return !isStackParam && !lvaIsFieldOfDependentlyPromotedStruct(varDsc);
4579 #else // !_TARGET_AMD64_
4580 return !isStackParam;
4581 #endif // !_TARGET_AMD64_
4589 inline void Compiler::EndPhase(Phases phase)
4591 #if defined(FEATURE_JIT_METHOD_PERF)
4592 if (pCompJitTimer != nullptr)
4594 pCompJitTimer->EndPhase(this, phase);
4598 fgDumpFlowGraph(phase);
4599 #endif // DUMP_FLOWGRAPHS
4600 previousCompletedPhase = phase;
4604 if ((*dumpIRPhase == L'*') || (wcscmp(dumpIRPhase, PhaseShortNames[phase]) == 0))
4607 printf("IR after %s (switch: %ls)\n", PhaseEnums[phase], PhaseShortNames[phase]);
4614 else if (dumpIRTrees)
4619 // If we are just dumping a single method and we have a request to exit
4620 // after dumping, do so now.
4622 if (dumpIRExit && ((*dumpIRPhase != L'*') || (phase == PHASE_EMIT_GCEH)))
4631 /*****************************************************************************/
4632 #if MEASURE_CLRAPI_CALLS
4634 inline void Compiler::CLRApiCallEnter(unsigned apix)
4636 if (pCompJitTimer != nullptr)
4638 pCompJitTimer->CLRApiCallEnter(apix);
4641 inline void Compiler::CLRApiCallLeave(unsigned apix)
4643 if (pCompJitTimer != nullptr)
4645 pCompJitTimer->CLRApiCallLeave(apix);
4649 inline void Compiler::CLR_API_Enter(API_ICorJitInfo_Names ename)
4651 CLRApiCallEnter(ename);
4654 inline void Compiler::CLR_API_Leave(API_ICorJitInfo_Names ename)
4656 CLRApiCallLeave(ename);
4659 #endif // MEASURE_CLRAPI_CALLS
4661 //------------------------------------------------------------------------------
4662 // fgStructTempNeedsExplicitZeroInit : Check whether temp struct needs
4663 // explicit zero initialization in this basic block.
4666 // varDsc - struct local var description
4667 // block - basic block to check
4670 // true if the struct temp needs explicit zero-initialization in this basic block;
4674 // Structs with GC pointer fields are fully zero-initialized in the prolog if compInitMem is true.
4675 // Therefore, we don't need to insert zero-initialization if this block is not in a loop.
4677 bool Compiler::fgStructTempNeedsExplicitZeroInit(LclVarDsc* varDsc, BasicBlock* block)
4679 bool containsGCPtr = (varDsc->lvStructGcCount > 0);
4680 return (!containsGCPtr || !info.compInitMem || ((block->bbFlags & BBF_BACKWARD_JUMP) != 0));
4683 /*****************************************************************************/
4684 bool Compiler::fgExcludeFromSsa(unsigned lclNum)
4688 return true; // If we're doing MinOpts, no SSA vars.
4691 LclVarDsc* varDsc = &lvaTable[lclNum];
4693 if (varDsc->lvAddrExposed)
4695 return true; // We exclude address-exposed variables.
4697 if (!varDsc->lvTracked)
4699 return true; // SSA is only done for tracked variables
4701 // lvPromoted structs are never tracked...
4702 assert(!varDsc->lvPromoted);
4704 if (varDsc->lvOverlappingFields)
4706 return true; // Don't use SSA on structs that have overlapping fields
4709 if (varDsc->lvIsStructField && (lvaGetParentPromotionType(lclNum) != PROMOTION_TYPE_INDEPENDENT))
4711 // SSA must exclude struct fields that are not independent
4712 // - because we don't model the struct assignment properly when multiple fields can be assigned by one struct
4714 // - SSA doesn't allow a single node to contain multiple SSA definitions.
4715 // - and PROMOTION_TYPE_DEPENDEDNT fields are never candidates for a register.
4717 // Example mscorlib method: CompatibilitySwitches:IsCompatibilitySwitchSet
4721 // otherwise this variable is *not* excluded for SSA
4725 /*****************************************************************************/
4726 ValueNum Compiler::GetUseAsgDefVNOrTreeVN(GenTreePtr op)
4728 if (op->gtFlags & GTF_VAR_USEASG)
4730 unsigned lclNum = op->AsLclVarCommon()->GetLclNum();
4731 unsigned ssaNum = GetSsaNumForLocalVarDef(op);
4732 return lvaTable[lclNum].GetPerSsaData(ssaNum)->m_vnPair.GetConservative();
4736 return op->gtVNPair.GetConservative();
4740 /*****************************************************************************/
4741 unsigned Compiler::GetSsaNumForLocalVarDef(GenTreePtr lcl)
4743 // Address-taken variables don't have SSA numbers.
4744 if (fgExcludeFromSsa(lcl->AsLclVarCommon()->gtLclNum))
4746 return SsaConfig::RESERVED_SSA_NUM;
4749 if (lcl->gtFlags & GTF_VAR_USEASG)
4751 // It's an "lcl op= rhs" assignment. "lcl" is both used and defined here;
4752 // we've chosen in this case to annotate "lcl" with the SSA number (and VN) of the use,
4753 // and to store the SSA number of the def in a side table.
4755 // In case of a remorph (fgMorph) in CSE/AssertionProp after SSA phase, there
4756 // wouldn't be an entry for the USEASG portion of the indir addr, return
4758 if (!GetOpAsgnVarDefSsaNums()->Lookup(lcl, &ssaNum))
4760 return SsaConfig::RESERVED_SSA_NUM;
4766 return lcl->AsLclVarCommon()->gtSsaNum;
4770 template <typename TVisitor>
4771 void GenTree::VisitOperands(TVisitor visitor)
4778 case GT_LCL_VAR_ADDR:
4779 case GT_LCL_FLD_ADDR:
4788 case GT_MEMORYBARRIER:
4793 case GT_START_NONGC:
4795 #if !FEATURE_EH_FUNCLETS
4797 #endif // !FEATURE_EH_FUNCLETS
4799 #ifndef LEGACY_BACKEND
4801 #endif // LEGACY_BACKEND
4804 case GT_CLS_VAR_ADDR:
4808 case GT_PINVOKE_PROLOG:
4809 case GT_PINVOKE_EPILOG:
4813 // Unary operators with an optional operand
4817 if (this->AsUnOp()->gtOp1 == nullptr)
4823 // Standard unary operators
4824 case GT_STORE_LCL_VAR:
4825 case GT_STORE_LCL_FLD:
4847 #if defined(_TARGET_ARM_) && !defined(LEGACY_BACKEND)
4848 case GT_PUTARG_SPLIT:
4851 visitor(this->AsUnOp()->gtOp1);
4856 assert(this->AsUnOp()->gtOp1 != nullptr);
4857 this->AsUnOp()->gtOp1->VisitListOperands(visitor);
4861 VisitListOperands(visitor);
4866 if (this->AsSIMD()->gtSIMDIntrinsicID == SIMDIntrinsicInitN)
4868 assert(this->AsSIMD()->gtOp1 != nullptr);
4869 this->AsSIMD()->gtOp1->VisitListOperands(visitor);
4873 VisitBinOpOperands<TVisitor>(visitor);
4876 #endif // FEATURE_SIMD
4878 #ifdef FEATURE_HW_INTRINSICS
4879 case GT_HWIntrinsic:
4880 if ((this->AsHWIntrinsic()->gtOp1 != nullptr) && this->AsHWIntrinsic()->gtOp1->OperIsList())
4882 this->AsHWIntrinsic()->gtOp1->VisitListOperands(visitor);
4886 VisitBinOpOperands<TVisitor>(visitor);
4889 #endif // FEATURE_HW_INTRINSICS
4894 GenTreeCmpXchg* const cmpXchg = this->AsCmpXchg();
4895 if (visitor(cmpXchg->gtOpLocation) == VisitResult::Abort)
4899 if (visitor(cmpXchg->gtOpValue) == VisitResult::Abort)
4903 visitor(cmpXchg->gtOpComparand);
4907 case GT_ARR_BOUNDS_CHECK:
4910 #endif // FEATURE_SIMD
4912 GenTreeBoundsChk* const boundsChk = this->AsBoundsChk();
4913 if (visitor(boundsChk->gtIndex) == VisitResult::Abort)
4917 visitor(boundsChk->gtArrLen);
4922 if (this->AsField()->gtFldObj != nullptr)
4924 visitor(this->AsField()->gtFldObj);
4929 if (this->AsStmt()->gtStmtExpr != nullptr)
4931 visitor(this->AsStmt()->gtStmtExpr);
4937 GenTreeArrElem* const arrElem = this->AsArrElem();
4938 if (visitor(arrElem->gtArrObj) == VisitResult::Abort)
4942 for (unsigned i = 0; i < arrElem->gtArrRank; i++)
4944 if (visitor(arrElem->gtArrInds[i]) == VisitResult::Abort)
4954 GenTreeArrOffs* const arrOffs = this->AsArrOffs();
4955 if (visitor(arrOffs->gtOffset) == VisitResult::Abort)
4959 if (visitor(arrOffs->gtIndex) == VisitResult::Abort)
4963 visitor(arrOffs->gtArrObj);
4969 GenTreeDynBlk* const dynBlock = this->AsDynBlk();
4970 if (visitor(dynBlock->gtOp1) == VisitResult::Abort)
4974 visitor(dynBlock->gtDynamicSize);
4978 case GT_STORE_DYN_BLK:
4980 GenTreeDynBlk* const dynBlock = this->AsDynBlk();
4981 if (visitor(dynBlock->gtOp1) == VisitResult::Abort)
4985 if (visitor(dynBlock->gtOp2) == VisitResult::Abort)
4989 visitor(dynBlock->gtDynamicSize);
4995 GenTreeCall* const call = this->AsCall();
4996 if ((call->gtCallObjp != nullptr) && (visitor(call->gtCallObjp) == VisitResult::Abort))
5000 if ((call->gtCallArgs != nullptr) && (call->gtCallArgs->VisitListOperands(visitor) == VisitResult::Abort))
5004 if ((call->gtCallLateArgs != nullptr) &&
5005 (call->gtCallLateArgs->VisitListOperands(visitor)) == VisitResult::Abort)
5009 if (call->gtCallType == CT_INDIRECT)
5011 if ((call->gtCallCookie != nullptr) && (visitor(call->gtCallCookie) == VisitResult::Abort))
5015 if ((call->gtCallAddr != nullptr) && (visitor(call->gtCallAddr) == VisitResult::Abort))
5020 if ((call->gtControlExpr != nullptr))
5022 visitor(call->gtControlExpr);
5029 assert(this->OperIsBinary());
5030 VisitBinOpOperands<TVisitor>(visitor);
5035 template <typename TVisitor>
5036 GenTree::VisitResult GenTree::VisitListOperands(TVisitor visitor)
5038 for (GenTreeArgList* node = this->AsArgList(); node != nullptr; node = node->Rest())
5040 if (visitor(node->gtOp1) == VisitResult::Abort)
5042 return VisitResult::Abort;
5046 return VisitResult::Continue;
5049 template <typename TVisitor>
5050 void GenTree::VisitBinOpOperands(TVisitor visitor)
5052 assert(this->OperIsBinary());
5054 GenTreeOp* const op = this->AsOp();
5056 GenTree* const op1 = op->gtOp1;
5057 if ((op1 != nullptr) && (visitor(op1) == VisitResult::Abort))
5062 GenTree* const op2 = op->gtOp2;
5069 /*****************************************************************************
5072 * Note that compGetMem is an arena allocator that returns memory that is
5073 * not zero-initialized and can contain data from a prior allocation lifetime.
5076 inline void* __cdecl operator new(size_t sz, Compiler* context, CompMemKind cmk)
5078 return context->compGetMem(sz, cmk);
5081 inline void* __cdecl operator new[](size_t sz, Compiler* context, CompMemKind cmk)
5083 return context->compGetMem(sz, cmk);
5086 inline void* __cdecl operator new(size_t sz, void* p, const jitstd::placement_t& /* syntax_difference */)
5091 /*****************************************************************************/
5095 inline void printRegMask(regMaskTP mask)
5097 printf(REG_MASK_ALL_FMT, mask);
5100 inline char* regMaskToString(regMaskTP mask, Compiler* context)
5102 const size_t cchRegMask = 24;
5103 char* regmask = new (context, CMK_Unknown) char[cchRegMask];
5105 sprintf_s(regmask, cchRegMask, REG_MASK_ALL_FMT, mask);
5110 inline void printRegMaskInt(regMaskTP mask)
5112 printf(REG_MASK_INT_FMT, (mask & RBM_ALLINT));
5115 inline char* regMaskIntToString(regMaskTP mask, Compiler* context)
5117 const size_t cchRegMask = 24;
5118 char* regmask = new (context, CMK_Unknown) char[cchRegMask];
5120 sprintf_s(regmask, cchRegMask, REG_MASK_INT_FMT, (mask & RBM_ALLINT));
5127 inline static bool StructHasOverlappingFields(DWORD attribs)
5129 return ((attribs & CORINFO_FLG_OVERLAPPING_FIELDS) != 0);
5132 inline static bool StructHasCustomLayout(DWORD attribs)
5134 return ((attribs & CORINFO_FLG_CUSTOMLAYOUT) != 0);
5137 /*****************************************************************************
5138 * This node should not be referenced by anyone now. Set its values to garbage
5139 * to catch extra references
5142 inline void DEBUG_DESTROY_NODE(GenTreePtr tree)
5145 // printf("DEBUG_DESTROY_NODE for [0x%08x]\n", tree);
5147 // Save gtOper in case we want to find out what this node was
5148 tree->gtOperSave = tree->gtOper;
5150 tree->gtType = TYP_UNDEF;
5151 tree->gtFlags |= 0xFFFFFFFF & ~GTF_NODE_MASK;
5152 if (tree->OperIsSimple())
5154 tree->gtOp.gtOp1 = tree->gtOp.gtOp2 = nullptr;
5156 // Must do this last, because the "gtOp" check above will fail otherwise.
5157 // Don't call SetOper, because GT_COUNT is not a valid value
5158 tree->gtOper = GT_COUNT;
5162 /*****************************************************************************/
5163 #endif //_COMPILER_HPP_
5164 /*****************************************************************************/