1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5/*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7XX XX
8XX Inline functions XX
9XX XX
10XX XX
11XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
12XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
13*/
14
15#ifndef _COMPILER_HPP_
16#define _COMPILER_HPP_
17
18#include "emit.h" // for emitter::emitAddLabel
19
20#include "bitvec.h"
21
22#include "compilerbitsettraits.hpp"
23
24/*
25XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
26XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
27XX XX
28XX Miscellaneous utility functions. Some of these are defined in Utils.cpp XX
29XX XX
30XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
31XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
32*/
33
34/*****************************************************************************/
35/*****************************************************************************/
36
37inline bool getInlinePInvokeEnabled()
38{
39#ifdef DEBUG
40 return JitConfig.JitPInvokeEnabled() && !JitConfig.StressCOMCall();
41#else
42 return true;
43#endif
44}
45
46inline bool getInlinePInvokeCheckEnabled()
47{
48#ifdef DEBUG
49 return JitConfig.JitPInvokeCheckEnabled() != 0;
50#else
51 return false;
52#endif
53}
54
55// Enforce float narrowing for buggy compilers (notably preWhidbey VC)
56inline float forceCastToFloat(double d)
57{
58 Volatile<float> f = (float)d;
59 return f;
60}
61
62// Enforce UInt32 narrowing for buggy compilers (notably Whidbey Beta 2 LKG)
63inline UINT32 forceCastToUInt32(double d)
64{
65 Volatile<UINT32> u = (UINT32)d;
66 return u;
67}
68
69enum RoundLevel
70{
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
75
76 COUNT_ROUND_LEVEL,
77 DEFAULT_ROUND_LEVEL = ROUND_NEVER
78};
79
80inline RoundLevel getRoundFloatLevel()
81{
82#ifdef DEBUG
83 return (RoundLevel)JitConfig.JitRoundFloat();
84#else
85 return DEFAULT_ROUND_LEVEL;
86#endif
87}
88
89/*****************************************************************************/
90/*****************************************************************************
91 *
92 * Return the lowest bit that is set
93 */
94
95template <typename T>
96inline T genFindLowestBit(T value)
97{
98 return (value & (0 - value));
99}
100
101/*****************************************************************************/
102/*****************************************************************************
103 *
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.
107 */
108
109inline unsigned int genFindHighestBit(unsigned int mask)
110{
111 assert(mask != 0);
112 unsigned int bit = 1U << ((sizeof(unsigned int) * 8) - 1); // start looking at the top
113 while ((bit & mask) == 0)
114 {
115 bit >>= 1;
116 }
117 return bit;
118}
119
120inline unsigned __int64 genFindHighestBit(unsigned __int64 mask)
121{
122 assert(mask != 0);
123 unsigned __int64 bit = 1ULL << ((sizeof(unsigned __int64) * 8) - 1); // start looking at the top
124 while ((bit & mask) == 0)
125 {
126 bit >>= 1;
127 }
128 return bit;
129}
130
131#if 0
132// TODO-ARM64-Cleanup: These should probably be the implementation, when intrin.h is updated for ARM64
133inline
134unsigned int genFindHighestBit(unsigned int mask)
135{
136 assert(mask != 0);
137 unsigned int index;
138 _BitScanReverse(&index, mask);
139 return 1L << index;
140}
141
142inline
143unsigned __int64 genFindHighestBit(unsigned __int64 mask)
144{
145 assert(mask != 0);
146 unsigned int index;
147 _BitScanReverse64(&index, mask);
148 return 1LL << index;
149}
150#endif // 0
151
152/*****************************************************************************
153*
154* Return true if the given 64-bit value has exactly zero or one bits set.
155*/
156
157template <typename T>
158inline BOOL genMaxOneBit(T value)
159{
160 return (value & (value - 1)) == 0;
161}
162
163/*****************************************************************************
164*
165* Return true if the given 32-bit value has exactly zero or one bits set.
166*/
167
168inline BOOL genMaxOneBit(unsigned value)
169{
170 return (value & (value - 1)) == 0;
171}
172
173/*****************************************************************************
174*
175* Return true if the given 64-bit value has exactly one bit set.
176*/
177
178template <typename T>
179inline bool genExactlyOneBit(T value)
180{
181 return ((value != 0) && genMaxOneBit(value));
182}
183
184/*****************************************************************************
185*
186* Return true if the given 32-bit value has exactly zero or one bits set.
187*/
188
189inline bool genExactlyOneBit(unsigned value)
190{
191 return ((value != 0) && genMaxOneBit(value));
192}
193
194/*****************************************************************************
195 *
196 * Given a value that has exactly one bit set, return the position of that
197 * bit, in other words return the logarithm in base 2 of the given value.
198 */
199inline unsigned genLog2(unsigned value)
200{
201 return BitPosition(value);
202}
203
204// Given an unsigned 64-bit value, returns the lower 32-bits in unsigned format
205//
206inline unsigned ulo32(unsigned __int64 value)
207{
208 return static_cast<unsigned>(value);
209}
210
211// Given an unsigned 64-bit value, returns the upper 32-bits in unsigned format
212//
213inline unsigned uhi32(unsigned __int64 value)
214{
215 return static_cast<unsigned>(value >> 32);
216}
217
218/*****************************************************************************
219 *
220 * Given a value that has exactly one bit set, return the position of that
221 * bit, in other words return the logarithm in base 2 of the given value.
222 */
223
224inline unsigned genLog2(unsigned __int64 value)
225{
226 unsigned lo32 = ulo32(value);
227 unsigned hi32 = uhi32(value);
228
229 if (lo32 != 0)
230 {
231 assert(hi32 == 0);
232 return genLog2(lo32);
233 }
234 else
235 {
236 return genLog2(hi32) + 32;
237 }
238}
239
240/*****************************************************************************
241 *
242 * Return the lowest bit that is set in the given register mask.
243 */
244
245inline regMaskTP genFindLowestReg(regMaskTP value)
246{
247 return (regMaskTP)genFindLowestBit(value);
248}
249
250/*****************************************************************************
251 *
252 * A rather simple routine that counts the number of bits in a given number.
253 */
254
255template <typename T>
256inline unsigned genCountBits(T bits)
257{
258 unsigned cnt = 0;
259
260 while (bits)
261 {
262 cnt++;
263 bits -= genFindLowestBit(bits);
264 }
265
266 return cnt;
267}
268
269/*****************************************************************************
270 *
271 * Given 3 masks value, end, start, returns the bits of value between start
272 * and end (exclusive).
273 *
274 * value[bitNum(end) - 1, bitNum(start) + 1]
275 */
276
277inline unsigned __int64 BitsBetween(unsigned __int64 value, unsigned __int64 end, unsigned __int64 start)
278{
279 assert(start != 0);
280 assert(start < end);
281 assert((start & (start - 1)) == 0);
282 assert((end & (end - 1)) == 0);
283
284 return value & ~((start - 1) | start) & // Ones to the left of set bit in the start mask.
285 (end - 1); // Ones to the right of set bit in the end mask.
286}
287
288/*****************************************************************************/
289
290inline bool jitIsScaleIndexMul(size_t val)
291{
292 switch (val)
293 {
294 case 1:
295 case 2:
296 case 4:
297 case 8:
298 return true;
299
300 default:
301 return false;
302 }
303}
304
305// Returns "tree" iff "val" is a valid addressing mode scale shift amount on
306// the target architecture.
307inline bool jitIsScaleIndexShift(ssize_t val)
308{
309 // It happens that this is the right test for all our current targets: x86, x64 and ARM.
310 // This test would become target-dependent if we added a new target with a different constraint.
311 return 0 < val && val < 4;
312}
313
314/*****************************************************************************
315 * Returns true if value is between [start..end).
316 * The comparison is inclusive of start, exclusive of end.
317 */
318
319/* static */
320inline bool Compiler::jitIsBetween(unsigned value, unsigned start, unsigned end)
321{
322 return start <= value && value < end;
323}
324
325/*****************************************************************************
326 * Returns true if value is between [start..end].
327 * The comparison is inclusive of both start and end.
328 */
329
330/* static */
331inline bool Compiler::jitIsBetweenInclusive(unsigned value, unsigned start, unsigned end)
332{
333 return start <= value && value <= end;
334}
335
336/******************************************************************************************
337 * Return the EH descriptor for the given region index.
338 */
339inline EHblkDsc* Compiler::ehGetDsc(unsigned regionIndex)
340{
341 assert(regionIndex < compHndBBtabCount);
342 return &compHndBBtab[regionIndex];
343}
344
345/******************************************************************************************
346 * Return the EH descriptor index of the enclosing try, for the given region index.
347 */
348inline unsigned Compiler::ehGetEnclosingTryIndex(unsigned regionIndex)
349{
350 return ehGetDsc(regionIndex)->ebdEnclosingTryIndex;
351}
352
353/******************************************************************************************
354 * Return the EH descriptor index of the enclosing handler, for the given region index.
355 */
356inline unsigned Compiler::ehGetEnclosingHndIndex(unsigned regionIndex)
357{
358 return ehGetDsc(regionIndex)->ebdEnclosingHndIndex;
359}
360
361/******************************************************************************************
362 * Return the EH index given a region descriptor.
363 */
364inline unsigned Compiler::ehGetIndex(EHblkDsc* ehDsc)
365{
366 assert(compHndBBtab <= ehDsc && ehDsc < compHndBBtab + compHndBBtabCount);
367 return (unsigned)(ehDsc - compHndBBtab);
368}
369
370/******************************************************************************************
371 * Return the EH descriptor for the most nested 'try' region this BasicBlock is a member of
372 * (or nullptr if this block is not in a 'try' region).
373 */
374inline EHblkDsc* Compiler::ehGetBlockTryDsc(BasicBlock* block)
375{
376 if (!block->hasTryIndex())
377 {
378 return nullptr;
379 }
380
381 return ehGetDsc(block->getTryIndex());
382}
383
384/******************************************************************************************
385 * Return the EH descriptor for the most nested filter or handler region this BasicBlock is a member of
386 * (or nullptr if this block is not in a filter or handler region).
387 */
388inline EHblkDsc* Compiler::ehGetBlockHndDsc(BasicBlock* block)
389{
390 if (!block->hasHndIndex())
391 {
392 return nullptr;
393 }
394
395 return ehGetDsc(block->getHndIndex());
396}
397
398#if FEATURE_EH_FUNCLETS
399
400/*****************************************************************************
401 * Get the FuncInfoDsc for the funclet we are currently generating code for.
402 * This is only valid during codegen.
403 *
404 */
405inline FuncInfoDsc* Compiler::funCurrentFunc()
406{
407 return funGetFunc(compCurrFuncIdx);
408}
409
410/*****************************************************************************
411 * Change which funclet we are currently generating code for.
412 * This is only valid after funclets are created.
413 *
414 */
415inline void Compiler::funSetCurrentFunc(unsigned funcIdx)
416{
417 assert(fgFuncletsCreated);
418 assert(FitsIn<unsigned short>(funcIdx));
419 noway_assert(funcIdx < compFuncInfoCount);
420 compCurrFuncIdx = (unsigned short)funcIdx;
421}
422
423/*****************************************************************************
424 * Get the FuncInfoDsc for the given funclet.
425 * This is only valid after funclets are created.
426 *
427 */
428inline FuncInfoDsc* Compiler::funGetFunc(unsigned funcIdx)
429{
430 assert(fgFuncletsCreated);
431 assert(funcIdx < compFuncInfoCount);
432 return &compFuncInfos[funcIdx];
433}
434
435/*****************************************************************************
436 * Get the funcIdx for the EH funclet that begins with block.
437 * This is only valid after funclets are created.
438 * It is only valid for blocks marked with BBF_FUNCLET_BEG because
439 * otherwise we would have to do a more expensive check to determine
440 * if this should return the filter funclet or the filter handler funclet.
441 *
442 */
443inline unsigned Compiler::funGetFuncIdx(BasicBlock* block)
444{
445 assert(fgFuncletsCreated);
446 assert(block->bbFlags & BBF_FUNCLET_BEG);
447
448 EHblkDsc* eh = ehGetDsc(block->getHndIndex());
449 unsigned int funcIdx = eh->ebdFuncIndex;
450 if (eh->ebdHndBeg != block)
451 {
452 // If this is a filter EH clause, but we want the funclet
453 // for the filter (not the filter handler), it is the previous one
454 noway_assert(eh->HasFilter());
455 noway_assert(eh->ebdFilter == block);
456 assert(funGetFunc(funcIdx)->funKind == FUNC_HANDLER);
457 assert(funGetFunc(funcIdx)->funEHIndex == funGetFunc(funcIdx - 1)->funEHIndex);
458 assert(funGetFunc(funcIdx - 1)->funKind == FUNC_FILTER);
459 funcIdx--;
460 }
461
462 return funcIdx;
463}
464
465#else // !FEATURE_EH_FUNCLETS
466
467/*****************************************************************************
468 * Get the FuncInfoDsc for the funclet we are currently generating code for.
469 * This is only valid during codegen. For non-funclet platforms, this is
470 * always the root function.
471 *
472 */
473inline FuncInfoDsc* Compiler::funCurrentFunc()
474{
475 return &compFuncInfoRoot;
476}
477
478/*****************************************************************************
479 * Change which funclet we are currently generating code for.
480 * This is only valid after funclets are created.
481 *
482 */
483inline void Compiler::funSetCurrentFunc(unsigned funcIdx)
484{
485 assert(funcIdx == 0);
486}
487
488/*****************************************************************************
489 * Get the FuncInfoDsc for the givven funclet.
490 * This is only valid after funclets are created.
491 *
492 */
493inline FuncInfoDsc* Compiler::funGetFunc(unsigned funcIdx)
494{
495 assert(funcIdx == 0);
496 return &compFuncInfoRoot;
497}
498
499/*****************************************************************************
500 * No funclets, so always 0.
501 *
502 */
503inline unsigned Compiler::funGetFuncIdx(BasicBlock* block)
504{
505 return 0;
506}
507
508#endif // !FEATURE_EH_FUNCLETS
509
510//------------------------------------------------------------------------------
511// genRegNumFromMask : Maps a single register mask to a register number.
512//
513// Arguments:
514// mask - the register mask
515//
516// Return Value:
517// The number of the register contained in the mask.
518//
519// Assumptions:
520// The mask contains one and only one register.
521
522inline regNumber genRegNumFromMask(regMaskTP mask)
523{
524 assert(mask != 0); // Must have one bit set, so can't have a mask of zero
525
526 /* Convert the mask to a register number */
527
528 regNumber regNum = (regNumber)genLog2(mask);
529
530 /* Make sure we got it right */
531
532 assert(genRegMask(regNum) == mask);
533
534 return regNum;
535}
536
537//------------------------------------------------------------------------------
538// genSmallTypeCanRepresentValue: Checks if a value can be represented by a given small type.
539//
540// Arguments:
541// value - the value to check
542// type - the type
543//
544// Return Value:
545// True if the value is representable, false otherwise.
546
547inline bool genSmallTypeCanRepresentValue(var_types type, ssize_t value)
548{
549 switch (type)
550 {
551 case TYP_UBYTE:
552 case TYP_BOOL:
553 return FitsIn<UINT8>(value);
554 case TYP_BYTE:
555 return FitsIn<INT8>(value);
556 case TYP_USHORT:
557 return FitsIn<UINT16>(value);
558 case TYP_SHORT:
559 return FitsIn<INT16>(value);
560 default:
561 unreached();
562 }
563}
564
565/*****************************************************************************
566 *
567 * Return the size in bytes of the given type.
568 */
569
570extern const BYTE genTypeSizes[TYP_COUNT];
571
572template <class T>
573inline unsigned genTypeSize(T type)
574{
575 assert((unsigned)TypeGet(type) < _countof(genTypeSizes));
576
577 return genTypeSizes[TypeGet(type)];
578}
579
580/*****************************************************************************
581 *
582 * Return the "stack slot count" of the given type.
583 * returns 1 for 32-bit types and 2 for 64-bit types.
584 */
585
586extern const BYTE genTypeStSzs[TYP_COUNT];
587
588inline unsigned genTypeStSz(var_types type)
589{
590 assert((unsigned)type < _countof(genTypeStSzs));
591
592 return genTypeStSzs[type];
593}
594
595/*****************************************************************************
596 *
597 * Return the number of registers required to hold a value of the given type.
598 */
599
600/*****************************************************************************
601 *
602 * The following function maps a 'precise' type to an actual type as seen
603 * by the VM (for example, 'byte' maps to 'int').
604 */
605
606extern const BYTE genActualTypes[TYP_COUNT];
607
608inline var_types genActualType(var_types type)
609{
610 /* Spot check to make certain the table is in synch with the enum */
611
612 assert(genActualTypes[TYP_DOUBLE] == TYP_DOUBLE);
613 assert(genActualTypes[TYP_REF] == TYP_REF);
614
615 assert((unsigned)type < sizeof(genActualTypes));
616 return (var_types)genActualTypes[type];
617}
618
619/*****************************************************************************/
620
621inline var_types genUnsignedType(var_types type)
622{
623 /* Force signed types into corresponding unsigned type */
624
625 switch (type)
626 {
627 case TYP_BYTE:
628 type = TYP_UBYTE;
629 break;
630 case TYP_SHORT:
631 type = TYP_USHORT;
632 break;
633 case TYP_INT:
634 type = TYP_UINT;
635 break;
636 case TYP_LONG:
637 type = TYP_ULONG;
638 break;
639 default:
640 break;
641 }
642
643 return type;
644}
645
646/*****************************************************************************/
647
648inline var_types genSignedType(var_types type)
649{
650 /* Force non-small unsigned type into corresponding signed type */
651 /* Note that we leave the small types alone */
652
653 switch (type)
654 {
655 case TYP_UINT:
656 type = TYP_INT;
657 break;
658 case TYP_ULONG:
659 type = TYP_LONG;
660 break;
661 default:
662 break;
663 }
664
665 return type;
666}
667
668/*****************************************************************************
669 * Can this type be passed as a parameter in a register?
670 */
671
672inline bool isRegParamType(var_types type)
673{
674#if defined(_TARGET_X86_)
675 return (type <= TYP_INT || type == TYP_REF || type == TYP_BYREF);
676#else // !_TARGET_X86_
677 return true;
678#endif // !_TARGET_X86_
679}
680
681#if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
682/*****************************************************************************/
683// Returns true if 'type' is a struct that can be enregistered for call args
684// or can be returned by value in multiple registers.
685// if 'type' is not a struct the return value will be false.
686//
687// Arguments:
688// type - the basic jit var_type for the item being queried
689// typeClass - the handle for the struct when 'type' is TYP_STRUCT
690// typeSize - Out param (if non-null) is updated with the size of 'type'.
691// forReturn - this is true when we asking about a GT_RETURN context;
692// this is false when we are asking about an argument context
693// isVarArg - whether or not this is a vararg fixed arg or variable argument
694// - if so on arm64 windows getArgTypeForStruct will ignore HFA
695// - types
696//
697inline bool Compiler::VarTypeIsMultiByteAndCanEnreg(
698 var_types type, CORINFO_CLASS_HANDLE typeClass, unsigned* typeSize, bool forReturn, bool isVarArg)
699{
700 bool result = false;
701 unsigned size = 0;
702
703 if (varTypeIsStruct(type))
704 {
705 size = info.compCompHnd->getClassSize(typeClass);
706 if (forReturn)
707 {
708 structPassingKind howToReturnStruct;
709 type = getReturnTypeForStruct(typeClass, &howToReturnStruct, size);
710 }
711 else
712 {
713 structPassingKind howToPassStruct;
714 type = getArgTypeForStruct(typeClass, &howToPassStruct, isVarArg, size);
715 }
716 if (type != TYP_UNKNOWN)
717 {
718 result = true;
719 }
720 }
721 else
722 {
723 size = genTypeSize(type);
724 }
725
726 if (typeSize != nullptr)
727 {
728 *typeSize = size;
729 }
730
731 return result;
732}
733#endif //_TARGET_AMD64_ || _TARGET_ARM64_
734
735/*****************************************************************************/
736
737#ifdef DEBUG
738
739inline const char* varTypeGCstring(var_types type)
740{
741 switch (type)
742 {
743 case TYP_REF:
744 return "gcr";
745 case TYP_BYREF:
746 return "byr";
747 default:
748 return "non";
749 }
750}
751
752#endif
753
754/*****************************************************************************/
755
756const char* varTypeName(var_types);
757
758/*****************************************************************************
759 *
760 * Helpers to pull big-endian values out of a byte stream.
761 */
762
763inline unsigned genGetU1(const BYTE* addr)
764{
765 return addr[0];
766}
767
768inline signed genGetI1(const BYTE* addr)
769{
770 return (signed char)addr[0];
771}
772
773inline unsigned genGetU2(const BYTE* addr)
774{
775 return (addr[0] << 8) | addr[1];
776}
777
778inline signed genGetI2(const BYTE* addr)
779{
780 return (signed short)((addr[0] << 8) | addr[1]);
781}
782
783inline unsigned genGetU4(const BYTE* addr)
784{
785 return (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3];
786}
787
788/*****************************************************************************/
789// Helpers to pull little-endian values out of a byte stream.
790
791inline unsigned __int8 getU1LittleEndian(const BYTE* ptr)
792{
793 return *(UNALIGNED unsigned __int8*)ptr;
794}
795
796inline unsigned __int16 getU2LittleEndian(const BYTE* ptr)
797{
798 return GET_UNALIGNED_VAL16(ptr);
799}
800
801inline unsigned __int32 getU4LittleEndian(const BYTE* ptr)
802{
803 return GET_UNALIGNED_VAL32(ptr);
804}
805
806inline signed __int8 getI1LittleEndian(const BYTE* ptr)
807{
808 return *(UNALIGNED signed __int8*)ptr;
809}
810
811inline signed __int16 getI2LittleEndian(const BYTE* ptr)
812{
813 return GET_UNALIGNED_VAL16(ptr);
814}
815
816inline signed __int32 getI4LittleEndian(const BYTE* ptr)
817{
818 return GET_UNALIGNED_VAL32(ptr);
819}
820
821inline signed __int64 getI8LittleEndian(const BYTE* ptr)
822{
823 return GET_UNALIGNED_VAL64(ptr);
824}
825
826inline float getR4LittleEndian(const BYTE* ptr)
827{
828 __int32 val = getI4LittleEndian(ptr);
829 return *(float*)&val;
830}
831
832inline double getR8LittleEndian(const BYTE* ptr)
833{
834 __int64 val = getI8LittleEndian(ptr);
835 return *(double*)&val;
836}
837
838/*****************************************************************************
839 *
840 * Return the normalized index to use in the EXPSET_TP for the CSE with
841 * the given CSE index.
842 * Each GenTree has the following field:
843 * signed char gtCSEnum; // 0 or the CSE index (negated if def)
844 * So zero is reserved to mean this node is not a CSE
845 * and postive values indicate CSE uses and negative values indicate CSE defs.
846 * The caller of this method must pass a non-zero postive value.
847 * This precondition is checked by the assert on the first line of this method.
848 */
849
850inline unsigned int genCSEnum2bit(unsigned index)
851{
852 assert((index > 0) && (index <= EXPSET_SZ));
853
854 return (index - 1);
855}
856
857#ifdef DEBUG
858const char* genES2str(BitVecTraits* traits, EXPSET_TP set);
859const char* refCntWtd2str(unsigned refCntWtd);
860#endif
861
862/*
863XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
864XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
865XX GenTree XX
866XX Inline functions XX
867XX XX
868XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
869XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
870*/
871
872void* GenTree::operator new(size_t sz, Compiler* comp, genTreeOps oper)
873{
874#if SMALL_TREE_NODES
875 size_t size = GenTree::s_gtNodeSizes[oper];
876#else
877 size_t size = TREE_NODE_SZ_LARGE;
878#endif
879
880#if MEASURE_NODE_SIZE
881 genNodeSizeStats.genTreeNodeCnt += 1;
882 genNodeSizeStats.genTreeNodeSize += size;
883 genNodeSizeStats.genTreeNodeActualSize += sz;
884
885 genNodeSizeStatsPerFunc.genTreeNodeCnt += 1;
886 genNodeSizeStatsPerFunc.genTreeNodeSize += size;
887 genNodeSizeStatsPerFunc.genTreeNodeActualSize += sz;
888#endif // MEASURE_NODE_SIZE
889
890 assert(size >= sz);
891 return comp->getAllocator(CMK_ASTNode).allocate<char>(size);
892}
893
894// GenTree constructor
895inline GenTree::GenTree(genTreeOps oper, var_types type DEBUGARG(bool largeNode))
896{
897 gtOper = oper;
898 gtType = type;
899 gtFlags = 0;
900 gtLIRFlags = 0;
901#ifdef DEBUG
902 gtDebugFlags = 0;
903#endif // DEBUG
904#if FEATURE_ANYCSE
905 gtCSEnum = NO_CSE;
906#endif // FEATURE_ANYCSE
907#if ASSERTION_PROP
908 ClearAssertion();
909#endif
910
911 gtNext = nullptr;
912 gtPrev = nullptr;
913 gtRegNum = REG_NA;
914 INDEBUG(gtRegTag = GT_REGTAG_NONE;)
915
916 INDEBUG(gtCostsInitialized = false;)
917
918#ifdef DEBUG
919#if SMALL_TREE_NODES
920 size_t size = GenTree::s_gtNodeSizes[oper];
921 if (size == TREE_NODE_SZ_SMALL && !largeNode)
922 {
923 gtDebugFlags |= GTF_DEBUG_NODE_SMALL;
924 }
925 else if (size == TREE_NODE_SZ_LARGE || largeNode)
926 {
927 gtDebugFlags |= GTF_DEBUG_NODE_LARGE;
928 }
929 else
930 {
931 assert(!"bogus node size");
932 }
933#endif
934#endif
935
936#if COUNT_AST_OPERS
937 InterlockedIncrement(&s_gtNodeCounts[oper]);
938#endif
939
940#ifdef DEBUG
941 gtSeqNum = 0;
942 gtTreeID = JitTls::GetCompiler()->compGenTreeID++;
943 gtVNPair.SetBoth(ValueNumStore::NoVN);
944 gtRegTag = GT_REGTAG_NONE;
945 gtOperSave = GT_NONE;
946#endif
947}
948
949/*****************************************************************************/
950
951inline GenTreeStmt* Compiler::gtNewStmt(GenTree* expr, IL_OFFSETX offset)
952{
953 /* NOTE - GT_STMT is now a small node in retail */
954
955 GenTreeStmt* stmt = new (this, GT_STMT) GenTreeStmt(expr, offset);
956
957 return stmt;
958}
959
960/*****************************************************************************/
961
962inline GenTree* Compiler::gtNewOperNode(genTreeOps oper, var_types type, GenTree* op1, bool doSimplifications)
963{
964 assert((GenTree::OperKind(oper) & (GTK_UNOP | GTK_BINOP)) != 0);
965 assert((GenTree::OperKind(oper) & GTK_EXOP) ==
966 0); // Can't use this to construct any types that extend unary/binary operator.
967 assert(op1 != nullptr || oper == GT_PHI || oper == GT_RETFILT || oper == GT_NOP ||
968 (oper == GT_RETURN && type == TYP_VOID));
969
970 if (doSimplifications)
971 {
972 // We do some simplifications here.
973 // If this gets to be too many, try a switch...
974 // TODO-Cleanup: With the factoring out of array bounds checks, it should not be the
975 // case that we need to check for the array index case here, but without this check
976 // we get failures (see for example jit\Directed\Languages\Python\test_methods_d.exe)
977 if (oper == GT_IND)
978 {
979 // IND(ADDR(IND(x)) == IND(x)
980 if (op1->gtOper == GT_ADDR)
981 {
982 if (op1->gtOp.gtOp1->gtOper == GT_IND && (op1->gtOp.gtOp1->gtFlags & GTF_IND_ARR_INDEX) == 0)
983 {
984 op1 = op1->gtOp.gtOp1->gtOp.gtOp1;
985 }
986 }
987 }
988 else if (oper == GT_ADDR)
989 {
990 // if "x" is not an array index, ADDR(IND(x)) == x
991 if (op1->gtOper == GT_IND && (op1->gtFlags & GTF_IND_ARR_INDEX) == 0)
992 {
993 return op1->gtOp.gtOp1;
994 }
995 }
996 }
997
998 GenTree* node = new (this, oper) GenTreeOp(oper, type, op1, nullptr);
999
1000 //
1001 // the GT_ADDR of a Local Variable implies GTF_ADDR_ONSTACK
1002 //
1003 if ((oper == GT_ADDR) && (op1->OperGet() == GT_LCL_VAR))
1004 {
1005 node->gtFlags |= GTF_ADDR_ONSTACK;
1006 }
1007
1008 return node;
1009}
1010
1011// Returns an opcode that is of the largest node size in use.
1012inline genTreeOps LargeOpOpcode()
1013{
1014#if SMALL_TREE_NODES
1015 // Allocate a large node
1016 assert(GenTree::s_gtNodeSizes[GT_CALL] == TREE_NODE_SZ_LARGE);
1017#endif
1018 return GT_CALL;
1019}
1020
1021/******************************************************************************
1022 *
1023 * Use to create nodes which may later be morphed to another (big) operator
1024 */
1025
1026inline GenTree* Compiler::gtNewLargeOperNode(genTreeOps oper, var_types type, GenTree* op1, GenTree* op2)
1027{
1028 assert((GenTree::OperKind(oper) & (GTK_UNOP | GTK_BINOP)) != 0);
1029 assert((GenTree::OperKind(oper) & GTK_EXOP) ==
1030 0); // Can't use this to construct any types that extend unary/binary operator.
1031#if SMALL_TREE_NODES
1032 // Allocate a large node
1033
1034 assert(GenTree::s_gtNodeSizes[oper] == TREE_NODE_SZ_SMALL);
1035
1036 GenTree* node = new (this, LargeOpOpcode()) GenTreeOp(oper, type, op1, op2 DEBUGARG(/*largeNode*/ true));
1037#else
1038 GenTree* node = new (this, oper) GenTreeOp(oper, type, op1, op2);
1039#endif
1040
1041 return node;
1042}
1043
1044/*****************************************************************************
1045 *
1046 * allocates a integer constant entry that represents a handle (something
1047 * that may need to be fixed up).
1048 */
1049
1050inline GenTree* Compiler::gtNewIconHandleNode(size_t value, unsigned flags, FieldSeqNode* fields)
1051{
1052 GenTree* node;
1053 assert((flags & (GTF_ICON_HDL_MASK | GTF_ICON_FIELD_OFF)) != 0);
1054
1055 // Interpret "fields == NULL" as "not a field."
1056 if (fields == nullptr)
1057 {
1058 fields = FieldSeqStore::NotAField();
1059 }
1060
1061#if defined(LATE_DISASM)
1062 node = new (this, LargeOpOpcode()) GenTreeIntCon(TYP_I_IMPL, value, fields DEBUGARG(/*largeNode*/ true));
1063#else
1064 node = new (this, GT_CNS_INT) GenTreeIntCon(TYP_I_IMPL, value, fields);
1065#endif
1066 node->gtFlags |= flags;
1067 return node;
1068}
1069
1070/*****************************************************************************
1071 *
1072 * It may not be allowed to embed HANDLEs directly into the JITed code (for eg,
1073 * as arguments to JIT helpers). Get a corresponding value that can be embedded.
1074 * These are versions for each specific type of HANDLE
1075 */
1076
1077inline GenTree* Compiler::gtNewIconEmbScpHndNode(CORINFO_MODULE_HANDLE scpHnd)
1078{
1079 void *embedScpHnd, *pEmbedScpHnd;
1080
1081 embedScpHnd = (void*)info.compCompHnd->embedModuleHandle(scpHnd, &pEmbedScpHnd);
1082
1083 assert((!embedScpHnd) != (!pEmbedScpHnd));
1084
1085 return gtNewIconEmbHndNode(embedScpHnd, pEmbedScpHnd, GTF_ICON_SCOPE_HDL, scpHnd);
1086}
1087
1088//-----------------------------------------------------------------------------
1089
1090inline GenTree* Compiler::gtNewIconEmbClsHndNode(CORINFO_CLASS_HANDLE clsHnd)
1091{
1092 void *embedClsHnd, *pEmbedClsHnd;
1093
1094 embedClsHnd = (void*)info.compCompHnd->embedClassHandle(clsHnd, &pEmbedClsHnd);
1095
1096 assert((!embedClsHnd) != (!pEmbedClsHnd));
1097
1098 return gtNewIconEmbHndNode(embedClsHnd, pEmbedClsHnd, GTF_ICON_CLASS_HDL, clsHnd);
1099}
1100
1101//-----------------------------------------------------------------------------
1102
1103inline GenTree* Compiler::gtNewIconEmbMethHndNode(CORINFO_METHOD_HANDLE methHnd)
1104{
1105 void *embedMethHnd, *pEmbedMethHnd;
1106
1107 embedMethHnd = (void*)info.compCompHnd->embedMethodHandle(methHnd, &pEmbedMethHnd);
1108
1109 assert((!embedMethHnd) != (!pEmbedMethHnd));
1110
1111 return gtNewIconEmbHndNode(embedMethHnd, pEmbedMethHnd, GTF_ICON_METHOD_HDL, methHnd);
1112}
1113
1114//-----------------------------------------------------------------------------
1115
1116inline GenTree* Compiler::gtNewIconEmbFldHndNode(CORINFO_FIELD_HANDLE fldHnd)
1117{
1118 void *embedFldHnd, *pEmbedFldHnd;
1119
1120 embedFldHnd = (void*)info.compCompHnd->embedFieldHandle(fldHnd, &pEmbedFldHnd);
1121
1122 assert((!embedFldHnd) != (!pEmbedFldHnd));
1123
1124 return gtNewIconEmbHndNode(embedFldHnd, pEmbedFldHnd, GTF_ICON_FIELD_HDL, fldHnd);
1125}
1126
1127/*****************************************************************************/
1128
1129//------------------------------------------------------------------------------
1130// gtNewHelperCallNode : Helper to create a call helper node.
1131//
1132//
1133// Arguments:
1134// helper - Call helper
1135// type - Type of the node
1136// args - Call args
1137//
1138// Return Value:
1139// New CT_HELPER node
1140
1141inline GenTreeCall* Compiler::gtNewHelperCallNode(unsigned helper, var_types type, GenTreeArgList* args)
1142{
1143 unsigned flags = s_helperCallProperties.NoThrow((CorInfoHelpFunc)helper) ? 0 : GTF_EXCEPT;
1144 GenTreeCall* result = gtNewCallNode(CT_HELPER, eeFindHelper(helper), type, args);
1145 result->gtFlags |= flags;
1146
1147#if DEBUG
1148 // Helper calls are never candidates.
1149
1150 result->gtInlineObservation = InlineObservation::CALLSITE_IS_CALL_TO_HELPER;
1151#endif
1152
1153 return result;
1154}
1155
1156//------------------------------------------------------------------------
1157// gtNewAllocObjNode: A little helper to create an object allocation node.
1158//
1159// Arguments:
1160// helper - Value returned by ICorJitInfo::getNewHelper
1161// helperHasSideEffects - True iff allocation helper has side effects
1162// clsHnd - Corresponding class handle
1163// type - Tree return type (e.g. TYP_REF)
1164// op1 - Node containing an address of VtablePtr
1165//
1166// Return Value:
1167// Returns GT_ALLOCOBJ node that will be later morphed into an
1168// allocation helper call or local variable allocation on the stack.
1169
1170inline GenTreeAllocObj* Compiler::gtNewAllocObjNode(
1171 unsigned int helper, bool helperHasSideEffects, CORINFO_CLASS_HANDLE clsHnd, var_types type, GenTree* op1)
1172{
1173 GenTreeAllocObj* node = new (this, GT_ALLOCOBJ) GenTreeAllocObj(type, helper, helperHasSideEffects, clsHnd, op1);
1174 return node;
1175}
1176
1177//------------------------------------------------------------------------
1178// gtNewRuntimeLookup: Helper to create a runtime lookup node
1179//
1180// Arguments:
1181// hnd - generic handle being looked up
1182// hndTyp - type of the generic handle
1183// tree - tree for the lookup
1184//
1185// Return Value:
1186// New GenTreeRuntimeLookup node.
1187
1188inline GenTree* Compiler::gtNewRuntimeLookup(CORINFO_GENERIC_HANDLE hnd, CorInfoGenericHandleType hndTyp, GenTree* tree)
1189{
1190 assert(tree != nullptr);
1191 GenTree* node = new (this, GT_RUNTIMELOOKUP) GenTreeRuntimeLookup(hnd, hndTyp, tree);
1192 return node;
1193}
1194
1195/*****************************************************************************/
1196
1197inline GenTree* Compiler::gtNewCodeRef(BasicBlock* block)
1198{
1199 GenTree* node = new (this, GT_LABEL) GenTreeLabel(block);
1200 return node;
1201}
1202
1203/*****************************************************************************
1204 *
1205 * A little helper to create a data member reference node.
1206 */
1207
1208inline GenTree* Compiler::gtNewFieldRef(var_types typ, CORINFO_FIELD_HANDLE fldHnd, GenTree* obj, DWORD offset)
1209{
1210#if SMALL_TREE_NODES
1211 /* 'GT_FIELD' nodes may later get transformed into 'GT_IND' */
1212 assert(GenTree::s_gtNodeSizes[GT_IND] <= GenTree::s_gtNodeSizes[GT_FIELD]);
1213#endif // SMALL_TREE_NODES
1214
1215 GenTree* tree = new (this, GT_FIELD) GenTreeField(typ, obj, fldHnd, offset);
1216
1217 // If "obj" is the address of a local, note that a field of that struct local has been accessed.
1218 if (obj != nullptr && obj->OperGet() == GT_ADDR && varTypeIsStruct(obj->gtOp.gtOp1) &&
1219 obj->gtOp.gtOp1->OperGet() == GT_LCL_VAR)
1220 {
1221 unsigned lclNum = obj->gtOp.gtOp1->gtLclVarCommon.gtLclNum;
1222 lvaTable[lclNum].lvFieldAccessed = 1;
1223#if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
1224 // These structs are passed by reference; we should probably be able to treat these
1225 // as non-global refs, but downstream logic expects these to be marked this way.
1226 if (lvaTable[lclNum].lvIsParam)
1227 {
1228 tree->gtFlags |= GTF_GLOB_REF;
1229 }
1230#endif // defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
1231 }
1232 else
1233 {
1234 tree->gtFlags |= GTF_GLOB_REF;
1235 }
1236
1237 return tree;
1238}
1239
1240/*****************************************************************************
1241 *
1242 * A little helper to create an array index node.
1243 */
1244
1245inline GenTree* Compiler::gtNewIndexRef(var_types typ, GenTree* arrayOp, GenTree* indexOp)
1246{
1247 GenTreeIndex* gtIndx = new (this, GT_INDEX) GenTreeIndex(typ, arrayOp, indexOp, genTypeSize(typ));
1248
1249 return gtIndx;
1250}
1251
1252//------------------------------------------------------------------------------
1253// gtNewArrLen : Helper to create an array length node.
1254//
1255//
1256// Arguments:
1257// typ - Type of the node
1258// arrayOp - Array node
1259// lenOffset - Offset of the length field
1260//
1261// Return Value:
1262// New GT_ARR_LENGTH node
1263
1264inline GenTreeArrLen* Compiler::gtNewArrLen(var_types typ, GenTree* arrayOp, int lenOffset)
1265{
1266 GenTreeArrLen* arrLen = new (this, GT_ARR_LENGTH) GenTreeArrLen(typ, arrayOp, lenOffset);
1267 static_assert_no_msg(GTF_ARRLEN_NONFAULTING == GTF_IND_NONFAULTING);
1268 arrLen->SetIndirExceptionFlags(this);
1269 return arrLen;
1270}
1271
1272//------------------------------------------------------------------------------
1273// gtNewIndir : Helper to create an indirection node.
1274//
1275// Arguments:
1276// typ - Type of the node
1277// addr - Address of the indirection
1278//
1279// Return Value:
1280// New GT_IND node
1281
1282inline GenTree* Compiler::gtNewIndir(var_types typ, GenTree* addr)
1283{
1284 GenTree* indir = gtNewOperNode(GT_IND, typ, addr);
1285 indir->SetIndirExceptionFlags(this);
1286 return indir;
1287}
1288
1289/*****************************************************************************
1290 *
1291 * Create (and check for) a "nothing" node, i.e. a node that doesn't produce
1292 * any code. We currently use a "nop" node of type void for this purpose.
1293 */
1294
1295inline GenTree* Compiler::gtNewNothingNode()
1296{
1297 return new (this, GT_NOP) GenTreeOp(GT_NOP, TYP_VOID);
1298}
1299/*****************************************************************************/
1300
1301inline bool GenTree::IsNothingNode() const
1302{
1303 return (gtOper == GT_NOP && gtType == TYP_VOID);
1304}
1305
1306/*****************************************************************************
1307 *
1308 * Change the given node to a NOP - May be later changed to a GT_COMMA
1309 *
1310 *****************************************************************************/
1311
1312inline void GenTree::gtBashToNOP()
1313{
1314 ChangeOper(GT_NOP);
1315
1316 gtType = TYP_VOID;
1317 gtOp.gtOp1 = gtOp.gtOp2 = nullptr;
1318
1319 gtFlags &= ~(GTF_ALL_EFFECT | GTF_REVERSE_OPS);
1320}
1321
1322// return new arg placeholder node. Does not do anything but has a type associated
1323// with it so we can keep track of register arguments in lists associated w/ call nodes
1324
1325inline GenTree* Compiler::gtNewArgPlaceHolderNode(var_types type, CORINFO_CLASS_HANDLE clsHnd)
1326{
1327 GenTree* node = new (this, GT_ARGPLACE) GenTreeArgPlace(type, clsHnd);
1328 return node;
1329}
1330
1331/*****************************************************************************/
1332
1333inline GenTree* Compiler::gtUnusedValNode(GenTree* expr)
1334{
1335 return gtNewOperNode(GT_COMMA, TYP_VOID, expr, gtNewNothingNode());
1336}
1337
1338/*****************************************************************************
1339 *
1340 * A wrapper for gtSetEvalOrder and gtComputeFPlvls
1341 * Necessary because the FP levels may need to be re-computed if we reverse
1342 * operands
1343 */
1344
1345inline void Compiler::gtSetStmtInfo(GenTree* stmt)
1346{
1347 assert(stmt->gtOper == GT_STMT);
1348 GenTree* expr = stmt->gtStmt.gtStmtExpr;
1349
1350 /* Recursively process the expression */
1351
1352 gtSetEvalOrder(expr);
1353
1354 // Set the statement to have the same costs as the top node of the tree.
1355 stmt->CopyCosts(expr);
1356}
1357
1358/*****************************************************************************/
1359#if SMALL_TREE_NODES
1360/*****************************************************************************/
1361
1362inline void GenTree::SetOper(genTreeOps oper, ValueNumberUpdate vnUpdate)
1363{
1364 assert(((gtDebugFlags & GTF_DEBUG_NODE_SMALL) != 0) != ((gtDebugFlags & GTF_DEBUG_NODE_LARGE) != 0));
1365
1366 /* Make sure the node isn't too small for the new operator */
1367
1368 assert(GenTree::s_gtNodeSizes[gtOper] == TREE_NODE_SZ_SMALL ||
1369 GenTree::s_gtNodeSizes[gtOper] == TREE_NODE_SZ_LARGE);
1370
1371 assert(GenTree::s_gtNodeSizes[oper] == TREE_NODE_SZ_SMALL || GenTree::s_gtNodeSizes[oper] == TREE_NODE_SZ_LARGE);
1372 assert(GenTree::s_gtNodeSizes[oper] == TREE_NODE_SZ_SMALL || (gtDebugFlags & GTF_DEBUG_NODE_LARGE));
1373
1374#if defined(_HOST_64BIT_) && !defined(_TARGET_64BIT_)
1375 if (gtOper == GT_CNS_LNG && oper == GT_CNS_INT)
1376 {
1377 // When casting from LONG to INT, we need to force cast of the value,
1378 // if the host architecture represents INT and LONG with the same data size.
1379 gtLngCon.gtLconVal = (INT64)(INT32)gtLngCon.gtLconVal;
1380 }
1381#endif // defined(_HOST_64BIT_) && !defined(_TARGET_64BIT_)
1382
1383 SetOperRaw(oper);
1384
1385#ifdef DEBUG
1386 // Maintain the invariant that unary operators always have NULL gtOp2.
1387 // If we ever start explicitly allocating GenTreeUnOp nodes, we wouldn't be
1388 // able to do that (but if we did, we'd have to have a check in gtOp -- perhaps
1389 // a gtUnOp...)
1390 if (OperKind(oper) == GTK_UNOP)
1391 {
1392 gtOp.gtOp2 = nullptr;
1393 }
1394#endif // DEBUG
1395
1396#if DEBUGGABLE_GENTREE
1397 // Until we eliminate SetOper/ChangeOper, we also change the vtable of the node, so that
1398 // it shows up correctly in the debugger.
1399 SetVtableForOper(oper);
1400#endif // DEBUGGABLE_GENTREE
1401
1402 if (oper == GT_CNS_INT)
1403 {
1404 gtIntCon.gtFieldSeq = nullptr;
1405 }
1406
1407#if defined(_TARGET_ARM_)
1408 if (oper == GT_MUL_LONG)
1409 {
1410 // We sometimes bash GT_MUL to GT_MUL_LONG, which converts it from GenTreeOp to GenTreeMultiRegOp.
1411 gtMultiRegOp.gtOtherReg = REG_NA;
1412 gtMultiRegOp.ClearOtherRegFlags();
1413 }
1414#endif
1415
1416 if (vnUpdate == CLEAR_VN)
1417 {
1418 // Clear the ValueNum field as well.
1419 gtVNPair.SetBoth(ValueNumStore::NoVN);
1420 }
1421}
1422
1423inline GenTreeCast* Compiler::gtNewCastNode(var_types typ, GenTree* op1, bool fromUnsigned, var_types castType)
1424{
1425 GenTreeCast* res = new (this, GT_CAST) GenTreeCast(typ, op1, fromUnsigned, castType);
1426 return res;
1427}
1428
1429inline GenTreeCast* Compiler::gtNewCastNodeL(var_types typ, GenTree* op1, bool fromUnsigned, var_types castType)
1430{
1431 /* Some casts get transformed into 'GT_CALL' or 'GT_IND' nodes */
1432
1433 assert(GenTree::s_gtNodeSizes[GT_CALL] >= GenTree::s_gtNodeSizes[GT_CAST]);
1434 assert(GenTree::s_gtNodeSizes[GT_CALL] >= GenTree::s_gtNodeSizes[GT_IND]);
1435
1436 /* Make a big node first and then change it to be GT_CAST */
1437
1438 GenTreeCast* res =
1439 new (this, LargeOpOpcode()) GenTreeCast(typ, op1, fromUnsigned, castType DEBUGARG(/*largeNode*/ true));
1440 return res;
1441}
1442
1443/*****************************************************************************/
1444#else // SMALL_TREE_NODES
1445/*****************************************************************************/
1446
1447inline void GenTree::InitNodeSize()
1448{
1449}
1450
1451inline void GenTree::SetOper(genTreeOps oper, ValueNumberUpdate vnUpdate)
1452{
1453 SetOperRaw(oper);
1454
1455 if (vnUpdate == CLEAR_VN)
1456 {
1457 // Clear the ValueNum field.
1458 gtVNPair.SetBoth(ValueNumStore::NoVN);
1459 }
1460}
1461
1462inline void GenTree::ReplaceWith(GenTree* src)
1463{
1464 RecordOperBashing(OperGet(), src->OperGet()); // nop unless NODEBASH_STATS is enabled
1465 *this = *src;
1466#ifdef DEBUG
1467 gtSeqNum = 0;
1468#endif
1469}
1470
1471inline GenTree* Compiler::gtNewCastNode(var_types typ, GenTree* op1, var_types castType)
1472{
1473 GenTree* tree = gtNewOperNode(GT_CAST, typ, op1);
1474 tree->gtCast.gtCastType = castType;
1475}
1476
1477inline GenTree* Compiler::gtNewCastNodeL(var_types typ, GenTree* op1, var_types castType)
1478{
1479 return gtNewCastNode(typ, op1, castType);
1480}
1481
1482/*****************************************************************************/
1483#endif // SMALL_TREE_NODES
1484/*****************************************************************************/
1485
1486/*****************************************************************************/
1487
1488inline void GenTree::SetOperRaw(genTreeOps oper)
1489{
1490 // Please do not do anything here other than assign to gtOper (debug-only
1491 // code is OK, but should be kept to a minimum).
1492 RecordOperBashing(OperGet(), oper); // nop unless NODEBASH_STATS is enabled
1493 gtOper = oper;
1494}
1495
1496inline void GenTree::SetOperResetFlags(genTreeOps oper)
1497{
1498 SetOper(oper);
1499 gtFlags &= GTF_NODE_MASK;
1500}
1501
1502inline void GenTree::ChangeOperConst(genTreeOps oper)
1503{
1504#ifdef _TARGET_64BIT_
1505 assert(oper != GT_CNS_LNG); // We should never see a GT_CNS_LNG for a 64-bit target!
1506#endif
1507 assert(OperIsConst(oper)); // use ChangeOper() instead
1508 SetOperResetFlags(oper);
1509 // Some constant subtypes have additional fields that must be initialized.
1510 if (oper == GT_CNS_INT)
1511 {
1512 gtIntCon.gtFieldSeq = FieldSeqStore::NotAField();
1513 }
1514}
1515
1516inline void GenTree::ChangeOper(genTreeOps oper, ValueNumberUpdate vnUpdate)
1517{
1518 assert(!OperIsConst(oper)); // use ChangeOperLeaf() instead
1519
1520 unsigned mask = GTF_COMMON_MASK;
1521 if (this->OperIsIndirOrArrLength() && OperIsIndirOrArrLength(oper))
1522 {
1523 mask |= GTF_IND_NONFAULTING;
1524 }
1525 SetOper(oper, vnUpdate);
1526 gtFlags &= mask;
1527
1528 // Do "oper"-specific initializations...
1529 switch (oper)
1530 {
1531 case GT_LCL_FLD:
1532 gtLclFld.gtLclOffs = 0;
1533 gtLclFld.gtFieldSeq = FieldSeqStore::NotAField();
1534 break;
1535 default:
1536 break;
1537 }
1538}
1539
1540inline void GenTree::ChangeOperUnchecked(genTreeOps oper)
1541{
1542 unsigned mask = GTF_COMMON_MASK;
1543 if (this->OperIsIndirOrArrLength() && OperIsIndirOrArrLength(oper))
1544 {
1545 mask |= GTF_IND_NONFAULTING;
1546 }
1547 SetOperRaw(oper); // Trust the caller and don't use SetOper()
1548 gtFlags &= mask;
1549}
1550
1551/*****************************************************************************
1552 * Returns true if the node is &var (created by ldarga and ldloca)
1553 */
1554
1555inline bool GenTree::IsVarAddr() const
1556{
1557 if (gtOper == GT_ADDR)
1558 {
1559 if (gtFlags & GTF_ADDR_ONSTACK)
1560 {
1561 assert((gtType == TYP_BYREF) || (gtType == TYP_I_IMPL));
1562 return true;
1563 }
1564 }
1565 return false;
1566}
1567
1568/*****************************************************************************
1569 *
1570 * Returns true if the node is of the "ovf" variety, for example, add.ovf.i1.
1571 * + gtOverflow() can only be called for valid operators (that is, we know it is one
1572 * of the operators which may have GTF_OVERFLOW set).
1573 * + gtOverflowEx() is more expensive, and should be called only if gtOper may be
1574 * an operator for which GTF_OVERFLOW is invalid.
1575 */
1576
1577inline bool GenTree::gtOverflow() const
1578{
1579 assert(OperMayOverflow());
1580
1581 if ((gtFlags & GTF_OVERFLOW) != 0)
1582 {
1583 assert(varTypeIsIntegral(TypeGet()));
1584
1585 return true;
1586 }
1587 else
1588 {
1589 return false;
1590 }
1591}
1592
1593inline bool GenTree::gtOverflowEx() const
1594{
1595 return OperMayOverflow() && gtOverflow();
1596}
1597
1598/*
1599XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1600XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1601XX LclVarsInfo XX
1602XX Inline functions XX
1603XX XX
1604XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1605XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1606*/
1607
1608inline bool Compiler::lvaHaveManyLocals() const
1609{
1610 return (lvaCount >= lclMAX_TRACKED);
1611}
1612
1613/*****************************************************************************
1614 *
1615 * Allocate a temporary variable or a set of temp variables.
1616 */
1617
1618inline unsigned Compiler::lvaGrabTemp(bool shortLifetime DEBUGARG(const char* reason))
1619{
1620 if (compIsForInlining())
1621 {
1622 // Grab the temp using Inliner's Compiler instance.
1623 Compiler* pComp = impInlineInfo->InlinerCompiler; // The Compiler instance for the caller (i.e. the inliner)
1624
1625 if (pComp->lvaHaveManyLocals())
1626 {
1627 // Don't create more LclVar with inlining
1628 compInlineResult->NoteFatal(InlineObservation::CALLSITE_TOO_MANY_LOCALS);
1629 }
1630
1631 unsigned tmpNum = pComp->lvaGrabTemp(shortLifetime DEBUGARG(reason));
1632 lvaTable = pComp->lvaTable;
1633 lvaCount = pComp->lvaCount;
1634 lvaTableCnt = pComp->lvaTableCnt;
1635 return tmpNum;
1636 }
1637
1638 // You cannot allocate more space after frame layout!
1639 noway_assert(lvaDoneFrameLayout < Compiler::TENTATIVE_FRAME_LAYOUT);
1640
1641 /* Check if the lvaTable has to be grown */
1642 if (lvaCount + 1 > lvaTableCnt)
1643 {
1644 unsigned newLvaTableCnt = lvaCount + (lvaCount / 2) + 1;
1645
1646 // Check for overflow
1647 if (newLvaTableCnt <= lvaCount)
1648 {
1649 IMPL_LIMITATION("too many locals");
1650 }
1651
1652 LclVarDsc* newLvaTable = getAllocator(CMK_LvaTable).allocate<LclVarDsc>(newLvaTableCnt);
1653
1654 memcpy(newLvaTable, lvaTable, lvaCount * sizeof(*lvaTable));
1655 memset(newLvaTable + lvaCount, 0, (newLvaTableCnt - lvaCount) * sizeof(*lvaTable));
1656
1657 for (unsigned i = lvaCount; i < newLvaTableCnt; i++)
1658 {
1659 new (&newLvaTable[i], jitstd::placement_t()) LclVarDsc(); // call the constructor.
1660 }
1661
1662#ifdef DEBUG
1663 // Fill the old table with junks. So to detect the un-intended use.
1664 memset(lvaTable, JitConfig.JitDefaultFill(), lvaCount * sizeof(*lvaTable));
1665#endif
1666
1667 lvaTableCnt = newLvaTableCnt;
1668 lvaTable = newLvaTable;
1669 }
1670
1671 const unsigned tempNum = lvaCount;
1672 lvaCount++;
1673
1674 // Initialize lvType, lvIsTemp and lvOnFrame
1675 lvaTable[tempNum].lvType = TYP_UNDEF;
1676 lvaTable[tempNum].lvIsTemp = shortLifetime;
1677 lvaTable[tempNum].lvOnFrame = true;
1678
1679 // If we've started normal ref counting, bump the ref count of this
1680 // local, as we no longer do any incremental counting, and we presume
1681 // this new local will be referenced.
1682 if (lvaLocalVarRefCounted())
1683 {
1684 if (opts.OptimizationDisabled())
1685 {
1686 lvaTable[tempNum].lvImplicitlyReferenced = 1;
1687 }
1688 else
1689 {
1690 lvaTable[tempNum].setLvRefCnt(1);
1691 lvaTable[tempNum].setLvRefCntWtd(BB_UNITY_WEIGHT);
1692 }
1693 }
1694
1695#ifdef DEBUG
1696 lvaTable[tempNum].lvReason = reason;
1697
1698 if (verbose)
1699 {
1700 printf("\nlvaGrabTemp returning %d (", tempNum);
1701 gtDispLclVar(tempNum, false);
1702 printf(")%s called for %s.\n", shortLifetime ? "" : " (a long lifetime temp)", reason);
1703 }
1704#endif // DEBUG
1705
1706 return tempNum;
1707}
1708
1709inline unsigned Compiler::lvaGrabTemps(unsigned cnt DEBUGARG(const char* reason))
1710{
1711 if (compIsForInlining())
1712 {
1713 // Grab the temps using Inliner's Compiler instance.
1714 unsigned tmpNum = impInlineInfo->InlinerCompiler->lvaGrabTemps(cnt DEBUGARG(reason));
1715
1716 lvaTable = impInlineInfo->InlinerCompiler->lvaTable;
1717 lvaCount = impInlineInfo->InlinerCompiler->lvaCount;
1718 lvaTableCnt = impInlineInfo->InlinerCompiler->lvaTableCnt;
1719 return tmpNum;
1720 }
1721
1722#ifdef DEBUG
1723 if (verbose)
1724 {
1725 printf("\nlvaGrabTemps(%d) returning %d..%d (long lifetime temps) called for %s", cnt, lvaCount,
1726 lvaCount + cnt - 1, reason);
1727 }
1728#endif
1729
1730 // Could handle this...
1731 assert(!lvaLocalVarRefCounted());
1732
1733 // You cannot allocate more space after frame layout!
1734 noway_assert(lvaDoneFrameLayout < Compiler::TENTATIVE_FRAME_LAYOUT);
1735
1736 /* Check if the lvaTable has to be grown */
1737 if (lvaCount + cnt > lvaTableCnt)
1738 {
1739 unsigned newLvaTableCnt = lvaCount + max(lvaCount / 2 + 1, cnt);
1740
1741 // Check for overflow
1742 if (newLvaTableCnt <= lvaCount)
1743 {
1744 IMPL_LIMITATION("too many locals");
1745 }
1746
1747 LclVarDsc* newLvaTable = getAllocator(CMK_LvaTable).allocate<LclVarDsc>(newLvaTableCnt);
1748
1749 memcpy(newLvaTable, lvaTable, lvaCount * sizeof(*lvaTable));
1750 memset(newLvaTable + lvaCount, 0, (newLvaTableCnt - lvaCount) * sizeof(*lvaTable));
1751 for (unsigned i = lvaCount; i < newLvaTableCnt; i++)
1752 {
1753 new (&newLvaTable[i], jitstd::placement_t()) LclVarDsc(); // call the constructor.
1754 }
1755
1756#ifdef DEBUG
1757 // Fill the old table with junks. So to detect the un-intended use.
1758 memset(lvaTable, JitConfig.JitDefaultFill(), lvaCount * sizeof(*lvaTable));
1759#endif
1760
1761 lvaTableCnt = newLvaTableCnt;
1762 lvaTable = newLvaTable;
1763 }
1764
1765 unsigned tempNum = lvaCount;
1766
1767 while (cnt--)
1768 {
1769 lvaTable[lvaCount].lvType = TYP_UNDEF; // Initialize lvType, lvIsTemp and lvOnFrame
1770 lvaTable[lvaCount].lvIsTemp = false;
1771 lvaTable[lvaCount].lvOnFrame = true;
1772 lvaCount++;
1773 }
1774
1775 return tempNum;
1776}
1777
1778/*****************************************************************************
1779 *
1780 * Allocate a temporary variable which is implicitly used by code-gen
1781 * There will be no explicit references to the temp, and so it needs to
1782 * be forced to be kept alive, and not be optimized away.
1783 */
1784
1785inline unsigned Compiler::lvaGrabTempWithImplicitUse(bool shortLifetime DEBUGARG(const char* reason))
1786{
1787 if (compIsForInlining())
1788 {
1789 // Grab the temp using Inliner's Compiler instance.
1790 unsigned tmpNum = impInlineInfo->InlinerCompiler->lvaGrabTempWithImplicitUse(shortLifetime DEBUGARG(reason));
1791
1792 lvaTable = impInlineInfo->InlinerCompiler->lvaTable;
1793 lvaCount = impInlineInfo->InlinerCompiler->lvaCount;
1794 lvaTableCnt = impInlineInfo->InlinerCompiler->lvaTableCnt;
1795 return tmpNum;
1796 }
1797
1798 unsigned lclNum = lvaGrabTemp(shortLifetime DEBUGARG(reason));
1799
1800 LclVarDsc* varDsc = &lvaTable[lclNum];
1801
1802 // This will prevent it from being optimized away
1803 // TODO-CQ: We shouldn't have to go as far as to declare these
1804 // address-exposed -- DoNotEnregister should suffice?
1805 lvaSetVarAddrExposed(lclNum);
1806
1807 // Note the implicit use
1808 varDsc->lvImplicitlyReferenced = 1;
1809
1810 return lclNum;
1811}
1812
1813/*****************************************************************************
1814 *
1815 * Increment the ref counts for a local variable
1816 */
1817
1818inline void LclVarDsc::incRefCnts(BasicBlock::weight_t weight, Compiler* comp, RefCountState state, bool propagate)
1819{
1820 // In minopts and debug codegen, we don't maintain normal ref counts.
1821 if ((state == RCS_NORMAL) && comp->opts.OptimizationDisabled())
1822 {
1823 // Note, at least, that there is at least one reference.
1824 lvImplicitlyReferenced = 1;
1825 return;
1826 }
1827
1828 Compiler::lvaPromotionType promotionType = DUMMY_INIT(Compiler::PROMOTION_TYPE_NONE);
1829 if (varTypeIsStruct(lvType))
1830 {
1831 promotionType = comp->lvaGetPromotionType(this);
1832 }
1833
1834 //
1835 // Increment counts on the local itself.
1836 //
1837 if (lvType != TYP_STRUCT || promotionType != Compiler::PROMOTION_TYPE_INDEPENDENT)
1838 {
1839 //
1840 // Increment lvRefCnt
1841 //
1842 int newRefCnt = lvRefCnt(state) + 1;
1843 if (newRefCnt == (unsigned short)newRefCnt) // lvRefCnt is an "unsigned short". Don't overflow it.
1844 {
1845 setLvRefCnt((unsigned short)newRefCnt, state);
1846 }
1847
1848 //
1849 // Increment lvRefCntWtd
1850 //
1851 if (weight != 0)
1852 {
1853 // We double the weight of internal temps
1854 //
1855 if (lvIsTemp && (weight * 2 > weight))
1856 {
1857 weight *= 2;
1858 }
1859
1860 unsigned newWeight = lvRefCntWtd(state) + weight;
1861 if (newWeight >= lvRefCntWtd(state))
1862 { // lvRefCntWtd is an "unsigned". Don't overflow it
1863 setLvRefCntWtd(newWeight, state);
1864 }
1865 else
1866 { // On overflow we assign ULONG_MAX
1867 setLvRefCntWtd(ULONG_MAX, state);
1868 }
1869 }
1870 }
1871
1872 if (varTypeIsStruct(lvType) && propagate)
1873 {
1874 // For promoted struct locals, increment lvRefCnt on its field locals as well.
1875 if (promotionType == Compiler::PROMOTION_TYPE_INDEPENDENT ||
1876 promotionType == Compiler::PROMOTION_TYPE_DEPENDENT)
1877 {
1878 for (unsigned i = lvFieldLclStart; i < lvFieldLclStart + lvFieldCnt; ++i)
1879 {
1880 comp->lvaTable[i].incRefCnts(weight, comp, state, false); // Don't propagate
1881 }
1882 }
1883 }
1884
1885 if (lvIsStructField && propagate)
1886 {
1887 // Depending on the promotion type, increment the ref count for the parent struct as well.
1888 promotionType = comp->lvaGetParentPromotionType(this);
1889 LclVarDsc* parentvarDsc = &comp->lvaTable[lvParentLcl];
1890 assert(!parentvarDsc->lvRegStruct);
1891 if (promotionType == Compiler::PROMOTION_TYPE_DEPENDENT)
1892 {
1893 parentvarDsc->incRefCnts(weight, comp, state, false); // Don't propagate
1894 }
1895 }
1896
1897#ifdef DEBUG
1898 if (comp->verbose)
1899 {
1900 unsigned varNum = (unsigned)(this - comp->lvaTable);
1901 assert(&comp->lvaTable[varNum] == this);
1902 printf("New refCnts for V%02u: refCnt = %2u, refCntWtd = %s\n", varNum, lvRefCnt(state),
1903 refCntWtd2str(lvRefCntWtd(state)));
1904 }
1905#endif
1906}
1907
1908/*****************************************************************************
1909 *
1910 * The following returns the mask of all tracked locals
1911 * referenced in a statement.
1912 */
1913
1914inline VARSET_VALRET_TP Compiler::lvaStmtLclMask(GenTree* stmt)
1915{
1916 GenTree* tree;
1917 unsigned varNum;
1918 LclVarDsc* varDsc;
1919 VARSET_TP lclMask(VarSetOps::MakeEmpty(this));
1920
1921 assert(stmt->gtOper == GT_STMT);
1922 assert(fgStmtListThreaded);
1923
1924 for (tree = stmt->gtStmt.gtStmtList; tree; tree = tree->gtNext)
1925 {
1926 if (tree->gtOper != GT_LCL_VAR)
1927 {
1928 continue;
1929 }
1930
1931 varNum = tree->gtLclVarCommon.gtLclNum;
1932 assert(varNum < lvaCount);
1933 varDsc = lvaTable + varNum;
1934
1935 if (!varDsc->lvTracked)
1936 {
1937 continue;
1938 }
1939
1940 VarSetOps::UnionD(this, lclMask, VarSetOps::MakeSingleton(this, varDsc->lvVarIndex));
1941 }
1942
1943 return lclMask;
1944}
1945
1946/*****************************************************************************
1947 * Returns true if the lvType is a TYP_REF or a TYP_BYREF.
1948 * When the lvType is a TYP_STRUCT it searches the GC layout
1949 * of the struct and returns true iff it contains a GC ref.
1950 */
1951
1952inline bool Compiler::lvaTypeIsGC(unsigned varNum)
1953{
1954 if (lvaTable[varNum].TypeGet() == TYP_STRUCT)
1955 {
1956 assert(lvaTable[varNum].lvGcLayout != nullptr); // bits are intialized
1957 return (lvaTable[varNum].lvStructGcCount != 0);
1958 }
1959 return (varTypeIsGC(lvaTable[varNum].TypeGet()));
1960}
1961
1962/*****************************************************************************
1963 Is this a synchronized instance method? If so, we will need to report "this"
1964 in the GC information, so that the EE can release the object lock
1965 in case of an exception
1966
1967 We also need to report "this" and keep it alive for all shared generic
1968 code that gets the actual generic context from the "this" pointer and
1969 has exception handlers.
1970
1971 For example, if List<T>::m() is shared between T = object and T = string,
1972 then inside m() an exception handler "catch E<T>" needs to be able to fetch
1973 the 'this' pointer to find out what 'T' is in order to tell if we
1974 should catch the exception or not.
1975 */
1976
1977inline bool Compiler::lvaKeepAliveAndReportThis()
1978{
1979 if (info.compIsStatic || lvaTable[0].TypeGet() != TYP_REF)
1980 {
1981 return false;
1982 }
1983
1984 const bool genericsContextIsThis = (info.compMethodInfo->options & CORINFO_GENERICS_CTXT_FROM_THIS) != 0;
1985
1986#ifdef JIT32_GCENCODER
1987
1988 if (info.compFlags & CORINFO_FLG_SYNCH)
1989 return true;
1990
1991 if (genericsContextIsThis)
1992 {
1993 // TODO: Check if any of the exception clauses are
1994 // typed using a generic type. Else, we do not need to report this.
1995 if (info.compXcptnsCount > 0)
1996 return true;
1997
1998 if (opts.compDbgCode)
1999 return true;
2000
2001 if (lvaGenericsContextUseCount > 0)
2002 {
2003 JITDUMP("Reporting this as generic context: %u refs\n", lvaGenericsContextUseCount);
2004 return true;
2005 }
2006 }
2007#else // !JIT32_GCENCODER
2008 // If the generics context is the this pointer we need to report it if either
2009 // the VM requires us to keep the generics context alive or it is used in a look-up.
2010 // We keep it alive in the lookup scenario, even when the VM didn't ask us to,
2011 // because collectible types need the generics context when gc-ing.
2012 if (genericsContextIsThis)
2013 {
2014 const bool isUsed = lvaGenericsContextUseCount > 0;
2015 const bool mustKeep = (info.compMethodInfo->options & CORINFO_GENERICS_CTXT_KEEP_ALIVE) != 0;
2016
2017 if (isUsed || mustKeep)
2018 {
2019 JITDUMP("Reporting this as generic context: %u refs%s\n", lvaGenericsContextUseCount,
2020 mustKeep ? ", must keep" : "");
2021
2022 return true;
2023 }
2024 }
2025#endif
2026
2027 return false;
2028}
2029
2030/*****************************************************************************
2031 Similar to lvaKeepAliveAndReportThis
2032 */
2033
2034inline bool Compiler::lvaReportParamTypeArg()
2035{
2036 if (info.compMethodInfo->options & (CORINFO_GENERICS_CTXT_FROM_METHODDESC | CORINFO_GENERICS_CTXT_FROM_METHODTABLE))
2037 {
2038 assert(info.compTypeCtxtArg != -1);
2039
2040 // If the VM requires us to keep the generics context alive and report it (for example, if any catch
2041 // clause catches a type that uses a generic parameter of this method) this flag will be set.
2042 if (info.compMethodInfo->options & CORINFO_GENERICS_CTXT_KEEP_ALIVE)
2043 {
2044 return true;
2045 }
2046
2047 // Otherwise, if an exact type parameter is needed in the body, report the generics context.
2048 // We do this because collectible types needs the generics context when gc-ing.
2049 if (lvaGenericsContextUseCount > 0)
2050 {
2051 return true;
2052 }
2053 }
2054
2055 // Otherwise, we don't need to report it -- the generics context parameter is unused.
2056 return false;
2057}
2058
2059//*****************************************************************************
2060
2061inline int Compiler::lvaCachedGenericContextArgOffset()
2062{
2063 assert(lvaDoneFrameLayout == FINAL_FRAME_LAYOUT);
2064
2065 return lvaCachedGenericContextArgOffs;
2066}
2067
2068//------------------------------------------------------------------------
2069// lvaFrameAddress: Determine the stack frame offset of the given variable,
2070// and how to generate an address to that stack frame.
2071//
2072// Arguments:
2073// varNum - The variable to inquire about. Positive for user variables
2074// or arguments, negative for spill-temporaries.
2075// mustBeFPBased - [_TARGET_ARM_ only] True if the base register must be FP.
2076// After FINAL_FRAME_LAYOUT, if false, it also requires SP base register.
2077// pBaseReg - [_TARGET_ARM_ only] Out arg. *pBaseReg is set to the base
2078// register to use.
2079// addrModeOffset - [_TARGET_ARM_ only] The mode offset within the variable that we need to address.
2080// For example, for a large struct local, and a struct field reference, this will be the offset
2081// of the field. Thus, for V02 + 0x28, if V02 itself is at offset SP + 0x10
2082// then addrModeOffset is what gets added beyond that, here 0x28.
2083// isFloatUsage - [_TARGET_ARM_ only] True if the instruction being generated is a floating
2084// point instruction. This requires using floating-point offset restrictions.
2085// Note that a variable can be non-float, e.g., struct, but accessed as a
2086// float local field.
2087// pFPbased - [non-_TARGET_ARM_] Out arg. Set *FPbased to true if the
2088// variable is addressed off of FP, false if it's addressed
2089// off of SP.
2090//
2091// Return Value:
2092// Returns the variable offset from the given base register.
2093//
2094inline
2095#ifdef _TARGET_ARM_
2096 int
2097 Compiler::lvaFrameAddress(
2098 int varNum, bool mustBeFPBased, regNumber* pBaseReg, int addrModeOffset, bool isFloatUsage)
2099#else
2100 int
2101 Compiler::lvaFrameAddress(int varNum, bool* pFPbased)
2102#endif
2103{
2104 assert(lvaDoneFrameLayout != NO_FRAME_LAYOUT);
2105
2106 int varOffset;
2107 bool FPbased;
2108 bool fConservative = false;
2109 if (varNum >= 0)
2110 {
2111 LclVarDsc* varDsc;
2112
2113 assert((unsigned)varNum < lvaCount);
2114 varDsc = lvaTable + varNum;
2115 bool isPrespilledArg = false;
2116#if defined(_TARGET_ARM_) && defined(PROFILING_SUPPORTED)
2117 isPrespilledArg = varDsc->lvIsParam && compIsProfilerHookNeeded() &&
2118 lvaIsPreSpilled(varNum, codeGen->regSet.rsMaskPreSpillRegs(false));
2119#endif
2120
2121 // If we have finished with register allocation, and this isn't a stack-based local,
2122 // check that this has a valid stack location.
2123 if (lvaDoneFrameLayout > REGALLOC_FRAME_LAYOUT && !varDsc->lvOnFrame)
2124 {
2125#ifdef _TARGET_AMD64_
2126#ifndef UNIX_AMD64_ABI
2127 // On amd64, every param has a stack location, except on Unix-like systems.
2128 assert(varDsc->lvIsParam);
2129#endif // UNIX_AMD64_ABI
2130#else // !_TARGET_AMD64_
2131 // For other targets, a stack parameter that is enregistered or prespilled
2132 // for profiling on ARM will have a stack location.
2133 assert((varDsc->lvIsParam && !varDsc->lvIsRegArg) || isPrespilledArg);
2134#endif // !_TARGET_AMD64_
2135 }
2136
2137 FPbased = varDsc->lvFramePointerBased;
2138
2139#ifdef DEBUG
2140#if FEATURE_FIXED_OUT_ARGS
2141 if ((unsigned)varNum == lvaOutgoingArgSpaceVar)
2142 {
2143 assert(FPbased == false);
2144 }
2145 else
2146#endif
2147 {
2148#if DOUBLE_ALIGN
2149 assert(FPbased == (isFramePointerUsed() || (genDoubleAlign() && varDsc->lvIsParam && !varDsc->lvIsRegArg)));
2150#else
2151#ifdef _TARGET_X86_
2152 assert(FPbased == isFramePointerUsed());
2153#endif
2154#endif
2155 }
2156#endif // DEBUG
2157
2158 varOffset = varDsc->lvStkOffs;
2159 }
2160 else // Its a spill-temp
2161 {
2162 FPbased = isFramePointerUsed();
2163 if (lvaDoneFrameLayout == Compiler::FINAL_FRAME_LAYOUT)
2164 {
2165 TempDsc* tmpDsc = codeGen->regSet.tmpFindNum(varNum);
2166 // The temp might be in use, since this might be during code generation.
2167 if (tmpDsc == nullptr)
2168 {
2169 tmpDsc = codeGen->regSet.tmpFindNum(varNum, RegSet::TEMP_USAGE_USED);
2170 }
2171 assert(tmpDsc != nullptr);
2172 varOffset = tmpDsc->tdTempOffs();
2173 }
2174 else
2175 {
2176 // This value is an estimate until we calculate the
2177 // offset after the final frame layout
2178 // ---------------------------------------------------
2179 // : :
2180 // +-------------------------+ base --+
2181 // | LR, ++N for ARM | | frameBaseOffset (= N)
2182 // +-------------------------+ |
2183 // | R11, ++N for ARM | <---FP |
2184 // +-------------------------+ --+
2185 // | compCalleeRegsPushed - N| | lclFrameOffset
2186 // +-------------------------+ --+
2187 // | lclVars | |
2188 // +-------------------------+ |
2189 // | tmp[MAX_SPILL_TEMP] | |
2190 // | tmp[1] | |
2191 // | tmp[0] | | compLclFrameSize
2192 // +-------------------------+ |
2193 // | outgoingArgSpaceSize | |
2194 // +-------------------------+ --+
2195 // | | <---SP
2196 // : :
2197 // ---------------------------------------------------
2198
2199 fConservative = true;
2200 if (!FPbased)
2201 {
2202 // Worst case stack based offset.
2203 CLANG_FORMAT_COMMENT_ANCHOR;
2204#if FEATURE_FIXED_OUT_ARGS
2205 int outGoingArgSpaceSize = lvaOutgoingArgSpaceSize;
2206#else
2207 int outGoingArgSpaceSize = 0;
2208#endif
2209 varOffset = outGoingArgSpaceSize + max(-varNum * TARGET_POINTER_SIZE, (int)lvaGetMaxSpillTempSize());
2210 }
2211 else
2212 {
2213 // Worst case FP based offset.
2214 CLANG_FORMAT_COMMENT_ANCHOR;
2215
2216#ifdef _TARGET_ARM_
2217 varOffset = codeGen->genCallerSPtoInitialSPdelta() - codeGen->genCallerSPtoFPdelta();
2218#else
2219 varOffset = -(codeGen->genTotalFrameSize());
2220#endif
2221 }
2222 }
2223 }
2224
2225#ifdef _TARGET_ARM_
2226 if (FPbased)
2227 {
2228 if (mustBeFPBased)
2229 {
2230 *pBaseReg = REG_FPBASE;
2231 }
2232 // Change the Frame Pointer (R11)-based addressing to the SP-based addressing when possible because
2233 // it generates smaller code on ARM. See frame picture above for the math.
2234 else
2235 {
2236 // If it is the final frame layout phase, we don't have a choice, we should stick
2237 // to either FP based or SP based that we decided in the earlier phase. Because
2238 // we have already selected the instruction. MinOpts will always reserve R10, so
2239 // for MinOpts always use SP-based offsets, using R10 as necessary, for simplicity.
2240
2241 int spVarOffset = fConservative ? compLclFrameSize : varOffset + codeGen->genSPtoFPdelta();
2242 int actualSPOffset = spVarOffset + addrModeOffset;
2243 int actualFPOffset = varOffset + addrModeOffset;
2244 int encodingLimitUpper = isFloatUsage ? 0x3FC : 0xFFF;
2245 int encodingLimitLower = isFloatUsage ? -0x3FC : -0xFF;
2246
2247 // Use SP-based encoding. During encoding, we'll pick the best encoding for the actual offset we have.
2248 if (opts.MinOpts() || (actualSPOffset <= encodingLimitUpper))
2249 {
2250 varOffset = spVarOffset;
2251 *pBaseReg = compLocallocUsed ? REG_SAVED_LOCALLOC_SP : REG_SPBASE;
2252 }
2253 // Use Frame Pointer (R11)-based encoding.
2254 else if ((encodingLimitLower <= actualFPOffset) && (actualFPOffset <= encodingLimitUpper))
2255 {
2256 *pBaseReg = REG_FPBASE;
2257 }
2258 // Otherwise, use SP-based encoding. This is either (1) a small positive offset using a single movw,
2259 // (2) a large offset using movw/movt. In either case, we must have already reserved
2260 // the "reserved register", which will get used during encoding.
2261 else
2262 {
2263 varOffset = spVarOffset;
2264 *pBaseReg = compLocallocUsed ? REG_SAVED_LOCALLOC_SP : REG_SPBASE;
2265 }
2266 }
2267 }
2268 else
2269 {
2270 *pBaseReg = REG_SPBASE;
2271 }
2272#else
2273 *pFPbased = FPbased;
2274#endif
2275
2276 return varOffset;
2277}
2278
2279inline bool Compiler::lvaIsParameter(unsigned varNum)
2280{
2281 LclVarDsc* varDsc;
2282
2283 assert(varNum < lvaCount);
2284 varDsc = lvaTable + varNum;
2285
2286 return varDsc->lvIsParam;
2287}
2288
2289inline bool Compiler::lvaIsRegArgument(unsigned varNum)
2290{
2291 LclVarDsc* varDsc;
2292
2293 assert(varNum < lvaCount);
2294 varDsc = lvaTable + varNum;
2295
2296 return varDsc->lvIsRegArg;
2297}
2298
2299inline BOOL Compiler::lvaIsOriginalThisArg(unsigned varNum)
2300{
2301 assert(varNum < lvaCount);
2302
2303 BOOL isOriginalThisArg = (varNum == info.compThisArg) && (info.compIsStatic == false);
2304
2305#ifdef DEBUG
2306 if (isOriginalThisArg)
2307 {
2308 LclVarDsc* varDsc = lvaTable + varNum;
2309 // Should never write to or take the address of the original 'this' arg
2310 CLANG_FORMAT_COMMENT_ANCHOR;
2311
2312#ifndef JIT32_GCENCODER
2313 // With the general encoder/decoder, when the original 'this' arg is needed as a generics context param, we
2314 // copy to a new local, and mark the original as DoNotEnregister, to
2315 // ensure that it is stack-allocated. It should not be the case that the original one can be modified -- it
2316 // should not be written to, or address-exposed.
2317 assert(!varDsc->lvHasILStoreOp &&
2318 (!varDsc->lvAddrExposed || ((info.compMethodInfo->options & CORINFO_GENERICS_CTXT_FROM_THIS) != 0)));
2319#else
2320 assert(!varDsc->lvHasILStoreOp && !varDsc->lvAddrExposed);
2321#endif
2322 }
2323#endif
2324
2325 return isOriginalThisArg;
2326}
2327
2328inline BOOL Compiler::lvaIsOriginalThisReadOnly()
2329{
2330 return lvaArg0Var == info.compThisArg;
2331}
2332
2333/*****************************************************************************
2334 *
2335 * The following is used to detect the cases where the same local variable#
2336 * is used both as a long/double value and a 32-bit value and/or both as an
2337 * integer/address and a float value.
2338 */
2339
2340/* static */ inline unsigned Compiler::lvaTypeRefMask(var_types type)
2341{
2342 const static BYTE lvaTypeRefMasks[] = {
2343#define DEF_TP(tn, nm, jitType, verType, sz, sze, asze, st, al, tf, howUsed) howUsed,
2344#include "typelist.h"
2345#undef DEF_TP
2346 };
2347
2348 assert((unsigned)type < sizeof(lvaTypeRefMasks));
2349 assert(lvaTypeRefMasks[type] != 0);
2350
2351 return lvaTypeRefMasks[type];
2352}
2353
2354/*****************************************************************************
2355 *
2356 * The following is used to detect the cases where the same local variable#
2357 * is used both as a long/double value and a 32-bit value and/or both as an
2358 * integer/address and a float value.
2359 */
2360
2361inline var_types Compiler::lvaGetActualType(unsigned lclNum)
2362{
2363 return genActualType(lvaGetRealType(lclNum));
2364}
2365
2366inline var_types Compiler::lvaGetRealType(unsigned lclNum)
2367{
2368 return lvaTable[lclNum].TypeGet();
2369}
2370
2371/*
2372XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2373XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2374XX Importer XX
2375XX Inline functions XX
2376XX XX
2377XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2378XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2379*/
2380
2381inline unsigned Compiler::compMapILargNum(unsigned ILargNum)
2382{
2383 assert(ILargNum < info.compILargsCount || tiVerificationNeeded);
2384
2385 // Note that this works because if compRetBuffArg/compTypeCtxtArg/lvVarargsHandleArg are not present
2386 // they will be BAD_VAR_NUM (MAX_UINT), which is larger than any variable number.
2387 if (ILargNum >= info.compRetBuffArg)
2388 {
2389 ILargNum++;
2390 assert(ILargNum < info.compLocalsCount || tiVerificationNeeded); // compLocals count already adjusted.
2391 }
2392
2393 if (ILargNum >= (unsigned)info.compTypeCtxtArg)
2394 {
2395 ILargNum++;
2396 assert(ILargNum < info.compLocalsCount || tiVerificationNeeded); // compLocals count already adjusted.
2397 }
2398
2399 if (ILargNum >= (unsigned)lvaVarargsHandleArg)
2400 {
2401 ILargNum++;
2402 assert(ILargNum < info.compLocalsCount || tiVerificationNeeded); // compLocals count already adjusted.
2403 }
2404
2405 assert(ILargNum < info.compArgsCount || tiVerificationNeeded);
2406 return (ILargNum);
2407}
2408
2409//------------------------------------------------------------------------
2410// Compiler::mangleVarArgsType: Retype float types to their corresponding
2411// : int/long types.
2412//
2413// Notes:
2414//
2415// The mangling of types will only occur for incoming vararg fixed arguments
2416// on windows arm|64 or on armel (softFP).
2417//
2418// NO-OP for all other cases.
2419//
2420inline var_types Compiler::mangleVarArgsType(var_types type)
2421{
2422#if defined(_TARGET_ARMARCH_)
2423 if (opts.compUseSoftFP
2424#if defined(_TARGET_WINDOWS_)
2425 || info.compIsVarArgs
2426#endif // defined(_TARGET_WINDOWS_)
2427 )
2428 {
2429 switch (type)
2430 {
2431 case TYP_FLOAT:
2432 return TYP_INT;
2433 case TYP_DOUBLE:
2434 return TYP_LONG;
2435 default:
2436 break;
2437 }
2438 }
2439#endif // defined(_TARGET_ARMARCH_)
2440 return type;
2441}
2442
2443// For CORECLR there is no vararg on System V systems.
2444#if FEATURE_VARARG
2445inline regNumber Compiler::getCallArgIntRegister(regNumber floatReg)
2446{
2447#ifdef _TARGET_AMD64_
2448 switch (floatReg)
2449 {
2450 case REG_XMM0:
2451 return REG_RCX;
2452 case REG_XMM1:
2453 return REG_RDX;
2454 case REG_XMM2:
2455 return REG_R8;
2456 case REG_XMM3:
2457 return REG_R9;
2458 default:
2459 unreached();
2460 }
2461#else // !_TARGET_AMD64_
2462 // How will float args be passed for RyuJIT/x86?
2463 NYI("getCallArgIntRegister for RyuJIT/x86");
2464 return REG_NA;
2465#endif // !_TARGET_AMD64_
2466}
2467
2468inline regNumber Compiler::getCallArgFloatRegister(regNumber intReg)
2469{
2470#ifdef _TARGET_AMD64_
2471 switch (intReg)
2472 {
2473 case REG_RCX:
2474 return REG_XMM0;
2475 case REG_RDX:
2476 return REG_XMM1;
2477 case REG_R8:
2478 return REG_XMM2;
2479 case REG_R9:
2480 return REG_XMM3;
2481 default:
2482 unreached();
2483 }
2484#else // !_TARGET_AMD64_
2485 // How will float args be passed for RyuJIT/x86?
2486 NYI("getCallArgFloatRegister for RyuJIT/x86");
2487 return REG_NA;
2488#endif // !_TARGET_AMD64_
2489}
2490#endif // FEATURE_VARARG
2491
2492/*
2493XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2494XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2495XX Register Allocator XX
2496XX Inline functions XX
2497XX XX
2498XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2499XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2500*/
2501
2502/*****************************************************************************/
2503
2504inline bool rpCanAsgOperWithoutReg(GenTree* op, bool lclvar)
2505{
2506 var_types type;
2507
2508 switch (op->OperGet())
2509 {
2510 case GT_CNS_LNG:
2511 case GT_CNS_INT:
2512 return true;
2513 case GT_LCL_VAR:
2514 type = genActualType(op->TypeGet());
2515 if (lclvar && ((type == TYP_INT) || (type == TYP_REF) || (type == TYP_BYREF)))
2516 {
2517 return true;
2518 }
2519 break;
2520 default:
2521 break;
2522 }
2523
2524 return false;
2525}
2526
2527/*
2528XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2529XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2530XX XX
2531XX FlowGraph XX
2532XX Inline functions XX
2533XX XX
2534XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2535XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2536*/
2537
2538inline bool Compiler::compCanEncodePtrArgCntMax()
2539{
2540#ifdef JIT32_GCENCODER
2541 // DDB 204533:
2542 // The GC encoding for fully interruptible methods does not
2543 // support more than 1023 pushed arguments, so we have to
2544 // use a partially interruptible GC info/encoding.
2545 //
2546 return (fgPtrArgCntMax < MAX_PTRARG_OFS);
2547#else // JIT32_GCENCODER
2548 return true;
2549#endif
2550}
2551
2552/*****************************************************************************
2553 *
2554 * Call the given function pointer for all nodes in the tree. The 'visitor'
2555 * fn should return one of the following values:
2556 *
2557 * WALK_ABORT stop walking and return immediately
2558 * WALK_CONTINUE continue walking
2559 * WALK_SKIP_SUBTREES don't walk any subtrees of the node just visited
2560 *
2561 * computeStack - true if we want to make stack visible to callback function
2562 */
2563
2564inline Compiler::fgWalkResult Compiler::fgWalkTreePre(
2565 GenTree** pTree, fgWalkPreFn* visitor, void* callBackData, bool lclVarsOnly, bool computeStack)
2566
2567{
2568 fgWalkData walkData;
2569
2570 walkData.compiler = this;
2571 walkData.wtprVisitorFn = visitor;
2572 walkData.pCallbackData = callBackData;
2573 walkData.parent = nullptr;
2574 walkData.wtprLclsOnly = lclVarsOnly;
2575#ifdef DEBUG
2576 walkData.printModified = false;
2577#endif
2578
2579 fgWalkResult result;
2580 if (lclVarsOnly && computeStack)
2581 {
2582 GenericTreeWalker<true, true, false, true, true> walker(&walkData);
2583 result = walker.WalkTree(pTree, nullptr);
2584 }
2585 else if (lclVarsOnly)
2586 {
2587 GenericTreeWalker<false, true, false, true, true> walker(&walkData);
2588 result = walker.WalkTree(pTree, nullptr);
2589 }
2590 else if (computeStack)
2591 {
2592 GenericTreeWalker<true, true, false, false, true> walker(&walkData);
2593 result = walker.WalkTree(pTree, nullptr);
2594 }
2595 else
2596 {
2597 GenericTreeWalker<false, true, false, false, true> walker(&walkData);
2598 result = walker.WalkTree(pTree, nullptr);
2599 }
2600
2601#ifdef DEBUG
2602 if (verbose && walkData.printModified)
2603 {
2604 gtDispTree(*pTree);
2605 }
2606#endif
2607
2608 return result;
2609}
2610
2611/*****************************************************************************
2612 *
2613 * Same as above, except the tree walk is performed in a depth-first fashion,
2614 * The 'visitor' fn should return one of the following values:
2615 *
2616 * WALK_ABORT stop walking and return immediately
2617 * WALK_CONTINUE continue walking
2618 *
2619 * computeStack - true if we want to make stack visible to callback function
2620 */
2621
2622inline Compiler::fgWalkResult Compiler::fgWalkTreePost(GenTree** pTree,
2623 fgWalkPostFn* visitor,
2624 void* callBackData,
2625 bool computeStack)
2626{
2627 fgWalkData walkData;
2628
2629 walkData.compiler = this;
2630 walkData.wtpoVisitorFn = visitor;
2631 walkData.pCallbackData = callBackData;
2632 walkData.parent = nullptr;
2633
2634 fgWalkResult result;
2635 if (computeStack)
2636 {
2637 GenericTreeWalker<true, false, true, false, true> walker(&walkData);
2638 result = walker.WalkTree(pTree, nullptr);
2639 }
2640 else
2641 {
2642 GenericTreeWalker<false, false, true, false, true> walker(&walkData);
2643 result = walker.WalkTree(pTree, nullptr);
2644 }
2645
2646 assert(result == WALK_CONTINUE || result == WALK_ABORT);
2647
2648 return result;
2649}
2650
2651/*****************************************************************************
2652 *
2653 * Call the given function pointer for all nodes in the tree. The 'visitor'
2654 * fn should return one of the following values:
2655 *
2656 * WALK_ABORT stop walking and return immediately
2657 * WALK_CONTINUE continue walking
2658 * WALK_SKIP_SUBTREES don't walk any subtrees of the node just visited
2659 */
2660
2661inline Compiler::fgWalkResult Compiler::fgWalkTree(GenTree** pTree,
2662 fgWalkPreFn* preVisitor,
2663 fgWalkPreFn* postVisitor,
2664 void* callBackData)
2665
2666{
2667 fgWalkData walkData;
2668
2669 walkData.compiler = this;
2670 walkData.wtprVisitorFn = preVisitor;
2671 walkData.wtpoVisitorFn = postVisitor;
2672 walkData.pCallbackData = callBackData;
2673 walkData.parent = nullptr;
2674 walkData.wtprLclsOnly = false;
2675#ifdef DEBUG
2676 walkData.printModified = false;
2677#endif
2678
2679 fgWalkResult result;
2680
2681 assert(preVisitor || postVisitor);
2682
2683 if (preVisitor && postVisitor)
2684 {
2685 GenericTreeWalker<true, true, true, false, true> walker(&walkData);
2686 result = walker.WalkTree(pTree, nullptr);
2687 }
2688 else if (preVisitor)
2689 {
2690 GenericTreeWalker<true, true, false, false, true> walker(&walkData);
2691 result = walker.WalkTree(pTree, nullptr);
2692 }
2693 else
2694 {
2695 GenericTreeWalker<true, false, true, false, true> walker(&walkData);
2696 result = walker.WalkTree(pTree, nullptr);
2697 }
2698
2699#ifdef DEBUG
2700 if (verbose && walkData.printModified)
2701 {
2702 gtDispTree(*pTree);
2703 }
2704#endif
2705
2706 return result;
2707}
2708
2709/*****************************************************************************
2710 *
2711 * Has this block been added to throw an inlined exception
2712 * Returns true if the block was added to throw one of:
2713 * range-check exception
2714 * argument exception (used by feature SIMD)
2715 * argument range-check exception (used by feature SIMD)
2716 * divide by zero exception (Not used on X86/X64)
2717 * null reference exception (Not currently used)
2718 * overflow exception
2719 */
2720
2721inline bool Compiler::fgIsThrowHlpBlk(BasicBlock* block)
2722{
2723 if (!fgIsCodeAdded())
2724 {
2725 return false;
2726 }
2727
2728 if (!(block->bbFlags & BBF_INTERNAL) || block->bbJumpKind != BBJ_THROW)
2729 {
2730 return false;
2731 }
2732
2733 GenTree* call = block->lastNode();
2734
2735#ifdef DEBUG
2736 if (block->IsLIR())
2737 {
2738 LIR::Range& blockRange = LIR::AsRange(block);
2739 for (LIR::Range::ReverseIterator node = blockRange.rbegin(), end = blockRange.rend(); node != end; ++node)
2740 {
2741 if (node->OperGet() == GT_CALL)
2742 {
2743 assert(*node == call);
2744 assert(node == blockRange.rbegin());
2745 break;
2746 }
2747 }
2748 }
2749#endif
2750
2751 if (!call || (call->gtOper != GT_CALL))
2752 {
2753 return false;
2754 }
2755
2756 if (!((call->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_RNGCHKFAIL)) ||
2757 (call->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_THROWDIVZERO)) ||
2758 (call->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_THROWNULLREF)) ||
2759 (call->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_OVERFLOW))))
2760 {
2761 return false;
2762 }
2763
2764 // We can get to this point for blocks that we didn't create as throw helper blocks
2765 // under stress, with crazy flow graph optimizations. So, walk the fgAddCodeList
2766 // for the final determination.
2767
2768 for (AddCodeDsc* add = fgAddCodeList; add; add = add->acdNext)
2769 {
2770 if (block == add->acdDstBlk)
2771 {
2772 return add->acdKind == SCK_RNGCHK_FAIL || add->acdKind == SCK_DIV_BY_ZERO || add->acdKind == SCK_OVERFLOW ||
2773 add->acdKind == SCK_ARG_EXCPN || add->acdKind == SCK_ARG_RNG_EXCPN;
2774 }
2775 }
2776
2777 // We couldn't find it in the fgAddCodeList
2778 return false;
2779}
2780
2781#if !FEATURE_FIXED_OUT_ARGS
2782
2783/*****************************************************************************
2784 *
2785 * Return the stackLevel of the inserted block that throws exception
2786 * (by calling the EE helper).
2787 */
2788
2789inline unsigned Compiler::fgThrowHlpBlkStkLevel(BasicBlock* block)
2790{
2791 for (AddCodeDsc* add = fgAddCodeList; add; add = add->acdNext)
2792 {
2793 if (block == add->acdDstBlk)
2794 {
2795 // Compute assert cond separately as assert macro cannot have conditional compilation directives.
2796 bool cond =
2797 (add->acdKind == SCK_RNGCHK_FAIL || add->acdKind == SCK_DIV_BY_ZERO || add->acdKind == SCK_OVERFLOW ||
2798 add->acdKind == SCK_ARG_EXCPN || add->acdKind == SCK_ARG_RNG_EXCPN);
2799 assert(cond);
2800
2801 // TODO: bbTgtStkDepth is DEBUG-only.
2802 // Should we use it regularly and avoid this search.
2803 assert(block->bbTgtStkDepth == add->acdStkLvl);
2804 return add->acdStkLvl;
2805 }
2806 }
2807
2808 noway_assert(!"fgThrowHlpBlkStkLevel should only be called if fgIsThrowHlpBlk() is true, but we can't find the "
2809 "block in the fgAddCodeList list");
2810
2811 /* We couldn't find the basic block: it must not have been a throw helper block */
2812
2813 return 0;
2814}
2815
2816#endif // !FEATURE_FIXED_OUT_ARGS
2817
2818/*
2819 Small inline function to change a given block to a throw block.
2820
2821*/
2822inline void Compiler::fgConvertBBToThrowBB(BasicBlock* block)
2823{
2824 // If we're converting a BBJ_CALLFINALLY block to a BBJ_THROW block,
2825 // then mark the subsequent BBJ_ALWAYS block as unreferenced.
2826 if (block->isBBCallAlwaysPair())
2827 {
2828 BasicBlock* leaveBlk = block->bbNext;
2829 noway_assert(leaveBlk->bbJumpKind == BBJ_ALWAYS);
2830
2831 leaveBlk->bbFlags &= ~BBF_DONT_REMOVE;
2832 leaveBlk->bbRefs = 0;
2833 leaveBlk->bbPreds = nullptr;
2834
2835#if FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
2836 // This function (fgConvertBBToThrowBB) can be called before the predecessor lists are created (e.g., in
2837 // fgMorph). The fgClearFinallyTargetBit() function to update the BBF_FINALLY_TARGET bit depends on these
2838 // predecessor lists. If there are no predecessor lists, we immediately clear all BBF_FINALLY_TARGET bits
2839 // (to allow subsequent dead code elimination to delete such blocks without asserts), and set a flag to
2840 // recompute them later, before they are required.
2841 if (fgComputePredsDone)
2842 {
2843 fgClearFinallyTargetBit(leaveBlk->bbJumpDest);
2844 }
2845 else
2846 {
2847 fgClearAllFinallyTargetBits();
2848 fgNeedToAddFinallyTargetBits = true;
2849 }
2850#endif // FEATURE_EH_FUNCLETS && defined(_TARGET_ARM_)
2851 }
2852
2853 block->bbJumpKind = BBJ_THROW;
2854 block->bbSetRunRarely(); // any block with a throw is rare
2855}
2856
2857/*****************************************************************************
2858 *
2859 * Return true if we've added any new basic blocks.
2860 */
2861
2862inline bool Compiler::fgIsCodeAdded()
2863{
2864 return fgAddCodeModf;
2865}
2866
2867/*****************************************************************************
2868 Is the offset too big?
2869*/
2870inline bool Compiler::fgIsBigOffset(size_t offset)
2871{
2872 return (offset > compMaxUncheckedOffsetForNullObject);
2873}
2874
2875/*
2876XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2877XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2878XX TempsInfo XX
2879XX Inline functions XX
2880XX XX
2881XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2882XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2883*/
2884
2885/*****************************************************************************/
2886
2887/* static */ inline unsigned RegSet::tmpSlot(unsigned size)
2888{
2889 noway_assert(size >= sizeof(int));
2890 noway_assert(size <= TEMP_MAX_SIZE);
2891 assert((size % sizeof(int)) == 0);
2892
2893 assert(size < UINT32_MAX);
2894 return size / sizeof(int) - 1;
2895}
2896
2897/*****************************************************************************
2898 *
2899 * Finish allocating temps - should be called each time after a pass is made
2900 * over a function body.
2901 */
2902
2903inline void RegSet::tmpEnd()
2904{
2905#ifdef DEBUG
2906 if (m_rsCompiler->verbose && (tmpCount > 0))
2907 {
2908 printf("%d tmps used\n", tmpCount);
2909 }
2910#endif // DEBUG
2911}
2912
2913/*****************************************************************************
2914 *
2915 * Shuts down the temp-tracking code. Should be called once per function
2916 * compiled.
2917 */
2918
2919inline void RegSet::tmpDone()
2920{
2921#ifdef DEBUG
2922 unsigned count;
2923 TempDsc* temp;
2924
2925 assert(tmpAllFree());
2926 for (temp = tmpListBeg(), count = temp ? 1 : 0; temp; temp = tmpListNxt(temp), count += temp ? 1 : 0)
2927 {
2928 assert(temp->tdLegalOffset());
2929 }
2930
2931 // Make sure that all the temps were released
2932 assert(count == tmpCount);
2933 assert(tmpGetCount == 0);
2934#endif // DEBUG
2935}
2936
2937#ifdef DEBUG
2938inline bool Compiler::shouldUseVerboseTrees()
2939{
2940 return (JitConfig.JitDumpVerboseTrees() == 1);
2941}
2942
2943inline bool Compiler::shouldUseVerboseSsa()
2944{
2945 return (JitConfig.JitDumpVerboseSsa() == 1);
2946}
2947
2948//------------------------------------------------------------------------
2949// shouldDumpASCIITrees: Should we use only ASCII characters for tree dumps?
2950//
2951// Notes:
2952// This is set to default to 1 in clrConfigValues.h
2953
2954inline bool Compiler::shouldDumpASCIITrees()
2955{
2956 return (JitConfig.JitDumpASCII() == 1);
2957}
2958
2959/*****************************************************************************
2960 * Should we enable JitStress mode?
2961 * 0: No stress
2962 * !=2: Vary stress. Performance will be slightly/moderately degraded
2963 * 2: Check-all stress. Performance will be REALLY horrible
2964 */
2965
2966inline DWORD getJitStressLevel()
2967{
2968 return JitConfig.JitStress();
2969}
2970
2971/*****************************************************************************
2972 * Should we do the strict check for non-virtual call to the virtual method?
2973 */
2974
2975inline DWORD StrictCheckForNonVirtualCallToVirtualMethod()
2976{
2977 return JitConfig.JitStrictCheckForNonVirtualCallToVirtualMethod() == 1;
2978}
2979
2980#endif // DEBUG
2981
2982/*****************************************************************************/
2983/* Map a register argument number ("RegArgNum") to a register number ("RegNum").
2984 * A RegArgNum is in this range:
2985 * [0, MAX_REG_ARG) -- for integer registers
2986 * [0, MAX_FLOAT_REG_ARG) -- for floating point registers
2987 * Note that RegArgNum's are overlapping for integer and floating-point registers,
2988 * while RegNum's are not (for ARM anyway, though for x86, it might be different).
2989 * If we have a fixed return buffer register and are given it's index
2990 * we return the fixed return buffer register
2991 */
2992
2993inline regNumber genMapIntRegArgNumToRegNum(unsigned argNum)
2994{
2995 if (hasFixedRetBuffReg() && (argNum == theFixedRetBuffArgNum()))
2996 {
2997 return theFixedRetBuffReg();
2998 }
2999
3000 assert(argNum < ArrLen(intArgRegs));
3001
3002 return intArgRegs[argNum];
3003}
3004
3005inline regNumber genMapFloatRegArgNumToRegNum(unsigned argNum)
3006{
3007#ifndef _TARGET_X86_
3008 assert(argNum < ArrLen(fltArgRegs));
3009
3010 return fltArgRegs[argNum];
3011#else
3012 assert(!"no x86 float arg regs\n");
3013 return REG_NA;
3014#endif
3015}
3016
3017__forceinline regNumber genMapRegArgNumToRegNum(unsigned argNum, var_types type)
3018{
3019 if (varTypeIsFloating(type))
3020 {
3021 return genMapFloatRegArgNumToRegNum(argNum);
3022 }
3023 else
3024 {
3025 return genMapIntRegArgNumToRegNum(argNum);
3026 }
3027}
3028
3029/*****************************************************************************/
3030/* Map a register argument number ("RegArgNum") to a register mask of the associated register.
3031 * Note that for floating-pointer registers, only the low register for a register pair
3032 * (for a double on ARM) is returned.
3033 */
3034
3035inline regMaskTP genMapIntRegArgNumToRegMask(unsigned argNum)
3036{
3037 assert(argNum < ArrLen(intArgMasks));
3038
3039 return intArgMasks[argNum];
3040}
3041
3042inline regMaskTP genMapFloatRegArgNumToRegMask(unsigned argNum)
3043{
3044#ifndef _TARGET_X86_
3045 assert(argNum < ArrLen(fltArgMasks));
3046
3047 return fltArgMasks[argNum];
3048#else
3049 assert(!"no x86 float arg regs\n");
3050 return RBM_NONE;
3051#endif
3052}
3053
3054__forceinline regMaskTP genMapArgNumToRegMask(unsigned argNum, var_types type)
3055{
3056 regMaskTP result;
3057 if (varTypeIsFloating(type))
3058 {
3059 result = genMapFloatRegArgNumToRegMask(argNum);
3060#ifdef _TARGET_ARM_
3061 if (type == TYP_DOUBLE)
3062 {
3063 assert((result & RBM_DBL_REGS) != 0);
3064 result |= (result << 1);
3065 }
3066#endif
3067 }
3068 else
3069 {
3070 result = genMapIntRegArgNumToRegMask(argNum);
3071 }
3072 return result;
3073}
3074
3075/*****************************************************************************/
3076/* Map a register number ("RegNum") to a register argument number ("RegArgNum")
3077 * If we have a fixed return buffer register we return theFixedRetBuffArgNum
3078 */
3079
3080inline unsigned genMapIntRegNumToRegArgNum(regNumber regNum)
3081{
3082 assert(genRegMask(regNum) & fullIntArgRegMask());
3083
3084 switch (regNum)
3085 {
3086 case REG_ARG_0:
3087 return 0;
3088#if MAX_REG_ARG >= 2
3089 case REG_ARG_1:
3090 return 1;
3091#if MAX_REG_ARG >= 3
3092 case REG_ARG_2:
3093 return 2;
3094#if MAX_REG_ARG >= 4
3095 case REG_ARG_3:
3096 return 3;
3097#if MAX_REG_ARG >= 5
3098 case REG_ARG_4:
3099 return 4;
3100#if MAX_REG_ARG >= 6
3101 case REG_ARG_5:
3102 return 5;
3103#if MAX_REG_ARG >= 7
3104 case REG_ARG_6:
3105 return 6;
3106#if MAX_REG_ARG >= 8
3107 case REG_ARG_7:
3108 return 7;
3109#endif
3110#endif
3111#endif
3112#endif
3113#endif
3114#endif
3115#endif
3116 default:
3117 // Check for the Arm64 fixed return buffer argument register
3118 if (hasFixedRetBuffReg() && (regNum == theFixedRetBuffReg()))
3119 {
3120 return theFixedRetBuffArgNum();
3121 }
3122 else
3123 {
3124 assert(!"invalid register arg register");
3125 return BAD_VAR_NUM;
3126 }
3127 }
3128}
3129
3130inline unsigned genMapFloatRegNumToRegArgNum(regNumber regNum)
3131{
3132 assert(genRegMask(regNum) & RBM_FLTARG_REGS);
3133
3134#ifdef _TARGET_ARM_
3135 return regNum - REG_F0;
3136#elif defined(_TARGET_ARM64_)
3137 return regNum - REG_V0;
3138#elif defined(UNIX_AMD64_ABI)
3139 return regNum - REG_FLTARG_0;
3140#else
3141
3142#if MAX_FLOAT_REG_ARG >= 1
3143 switch (regNum)
3144 {
3145 case REG_FLTARG_0:
3146 return 0;
3147#if MAX_REG_ARG >= 2
3148 case REG_FLTARG_1:
3149 return 1;
3150#if MAX_REG_ARG >= 3
3151 case REG_FLTARG_2:
3152 return 2;
3153#if MAX_REG_ARG >= 4
3154 case REG_FLTARG_3:
3155 return 3;
3156#if MAX_REG_ARG >= 5
3157 case REG_FLTARG_4:
3158 return 4;
3159#endif
3160#endif
3161#endif
3162#endif
3163 default:
3164 assert(!"invalid register arg register");
3165 return BAD_VAR_NUM;
3166 }
3167#else
3168 assert(!"flt reg args not allowed");
3169 return BAD_VAR_NUM;
3170#endif
3171#endif // !arm
3172}
3173
3174inline unsigned genMapRegNumToRegArgNum(regNumber regNum, var_types type)
3175{
3176 if (varTypeIsFloating(type))
3177 {
3178 return genMapFloatRegNumToRegArgNum(regNum);
3179 }
3180 else
3181 {
3182 return genMapIntRegNumToRegArgNum(regNum);
3183 }
3184}
3185
3186/*****************************************************************************/
3187/* Return a register mask with the first 'numRegs' argument registers set.
3188 */
3189
3190inline regMaskTP genIntAllRegArgMask(unsigned numRegs)
3191{
3192 assert(numRegs <= MAX_REG_ARG);
3193
3194 regMaskTP result = RBM_NONE;
3195 for (unsigned i = 0; i < numRegs; i++)
3196 {
3197 result |= intArgMasks[i];
3198 }
3199 return result;
3200}
3201
3202inline regMaskTP genFltAllRegArgMask(unsigned numRegs)
3203{
3204 assert(numRegs <= MAX_FLOAT_REG_ARG);
3205
3206 regMaskTP result = RBM_NONE;
3207 for (unsigned i = 0; i < numRegs; i++)
3208 {
3209 result |= fltArgMasks[i];
3210 }
3211 return result;
3212}
3213
3214/*
3215XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3216XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3217XX Liveness XX
3218XX Inline functions XX
3219XX XX
3220XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3221XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3222*/
3223
3224template <bool ForCodeGen>
3225inline void Compiler::compUpdateLife(VARSET_VALARG_TP newLife)
3226{
3227 if (!VarSetOps::Equal(this, compCurLife, newLife))
3228 {
3229 compChangeLife<ForCodeGen>(newLife);
3230 }
3231#ifdef DEBUG
3232 else
3233 {
3234 if (verbose)
3235 {
3236 printf("Liveness not changing: %s ", VarSetOps::ToString(this, compCurLife));
3237 dumpConvertedVarSet(this, compCurLife);
3238 printf("\n");
3239 }
3240 }
3241#endif // DEBUG
3242}
3243
3244/*****************************************************************************
3245 *
3246 * We stash cookies in basic blocks for the code emitter; this call retrieves
3247 * the cookie associated with the given basic block.
3248 */
3249
3250inline void* emitCodeGetCookie(BasicBlock* block)
3251{
3252 assert(block);
3253 return block->bbEmitCookie;
3254}
3255
3256/*
3257XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3258XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3259XX Optimizer XX
3260XX Inline functions XX
3261XX XX
3262XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3263XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3264*/
3265
3266#if LOCAL_ASSERTION_PROP
3267
3268/*****************************************************************************
3269 *
3270 * The following resets the value assignment table
3271 * used only during local assertion prop
3272 */
3273
3274inline void Compiler::optAssertionReset(AssertionIndex limit)
3275{
3276 PREFAST_ASSUME(optAssertionCount <= optMaxAssertionCount);
3277
3278 while (optAssertionCount > limit)
3279 {
3280 AssertionIndex index = optAssertionCount;
3281 AssertionDsc* curAssertion = optGetAssertion(index);
3282 optAssertionCount--;
3283 unsigned lclNum = curAssertion->op1.lcl.lclNum;
3284 assert(lclNum < lvaTableCnt);
3285 BitVecOps::RemoveElemD(apTraits, GetAssertionDep(lclNum), index - 1);
3286
3287 //
3288 // Find the Copy assertions
3289 //
3290 if ((curAssertion->assertionKind == OAK_EQUAL) && (curAssertion->op1.kind == O1K_LCLVAR) &&
3291 (curAssertion->op2.kind == O2K_LCLVAR_COPY))
3292 {
3293 //
3294 // op2.lcl.lclNum no longer depends upon this assertion
3295 //
3296 lclNum = curAssertion->op2.lcl.lclNum;
3297 BitVecOps::RemoveElemD(apTraits, GetAssertionDep(lclNum), index - 1);
3298 }
3299 }
3300 while (optAssertionCount < limit)
3301 {
3302 AssertionIndex index = ++optAssertionCount;
3303 AssertionDsc* curAssertion = optGetAssertion(index);
3304 unsigned lclNum = curAssertion->op1.lcl.lclNum;
3305 BitVecOps::AddElemD(apTraits, GetAssertionDep(lclNum), index - 1);
3306
3307 //
3308 // Check for Copy assertions
3309 //
3310 if ((curAssertion->assertionKind == OAK_EQUAL) && (curAssertion->op1.kind == O1K_LCLVAR) &&
3311 (curAssertion->op2.kind == O2K_LCLVAR_COPY))
3312 {
3313 //
3314 // op2.lcl.lclNum now depends upon this assertion
3315 //
3316 lclNum = curAssertion->op2.lcl.lclNum;
3317 BitVecOps::AddElemD(apTraits, GetAssertionDep(lclNum), index - 1);
3318 }
3319 }
3320}
3321
3322/*****************************************************************************
3323 *
3324 * The following removes the i-th entry in the value assignment table
3325 * used only during local assertion prop
3326 */
3327
3328inline void Compiler::optAssertionRemove(AssertionIndex index)
3329{
3330 assert(index > 0);
3331 assert(index <= optAssertionCount);
3332 PREFAST_ASSUME(optAssertionCount <= optMaxAssertionCount);
3333
3334 AssertionDsc* curAssertion = optGetAssertion(index);
3335
3336 // Two cases to consider if (index == optAssertionCount) then the last
3337 // entry in the table is to be removed and that happens automatically when
3338 // optAssertionCount is decremented and we can just clear the optAssertionDep bits
3339 // The other case is when index < optAssertionCount and here we overwrite the
3340 // index-th entry in the table with the data found at the end of the table
3341 // Since we are reordering the rable the optAssertionDep bits need to be recreated
3342 // using optAssertionReset(0) and optAssertionReset(newAssertionCount) will
3343 // correctly update the optAssertionDep bits
3344 //
3345 if (index == optAssertionCount)
3346 {
3347 unsigned lclNum = curAssertion->op1.lcl.lclNum;
3348 BitVecOps::RemoveElemD(apTraits, GetAssertionDep(lclNum), index - 1);
3349
3350 //
3351 // Check for Copy assertions
3352 //
3353 if ((curAssertion->assertionKind == OAK_EQUAL) && (curAssertion->op1.kind == O1K_LCLVAR) &&
3354 (curAssertion->op2.kind == O2K_LCLVAR_COPY))
3355 {
3356 //
3357 // op2.lcl.lclNum no longer depends upon this assertion
3358 //
3359 lclNum = curAssertion->op2.lcl.lclNum;
3360 BitVecOps::RemoveElemD(apTraits, GetAssertionDep(lclNum), index - 1);
3361 }
3362
3363 optAssertionCount--;
3364 }
3365 else
3366 {
3367 AssertionDsc* lastAssertion = optGetAssertion(optAssertionCount);
3368 AssertionIndex newAssertionCount = optAssertionCount - 1;
3369
3370 optAssertionReset(0); // This make optAssertionCount equal 0
3371
3372 memcpy(curAssertion, // the entry to be removed
3373 lastAssertion, // last entry in the table
3374 sizeof(AssertionDsc));
3375
3376 optAssertionReset(newAssertionCount);
3377 }
3378}
3379#endif // LOCAL_ASSERTION_PROP
3380
3381inline void Compiler::LoopDsc::AddModifiedField(Compiler* comp, CORINFO_FIELD_HANDLE fldHnd)
3382{
3383 if (lpFieldsModified == nullptr)
3384 {
3385 lpFieldsModified =
3386 new (comp->getAllocatorLoopHoist()) Compiler::LoopDsc::FieldHandleSet(comp->getAllocatorLoopHoist());
3387 }
3388 lpFieldsModified->Set(fldHnd, true);
3389}
3390
3391inline void Compiler::LoopDsc::AddModifiedElemType(Compiler* comp, CORINFO_CLASS_HANDLE structHnd)
3392{
3393 if (lpArrayElemTypesModified == nullptr)
3394 {
3395 lpArrayElemTypesModified =
3396 new (comp->getAllocatorLoopHoist()) Compiler::LoopDsc::ClassHandleSet(comp->getAllocatorLoopHoist());
3397 }
3398 lpArrayElemTypesModified->Set(structHnd, true);
3399}
3400
3401inline void Compiler::LoopDsc::VERIFY_lpIterTree()
3402{
3403#ifdef DEBUG
3404 assert(lpFlags & LPFLG_ITER);
3405
3406 // iterTree should be "lcl ASG lcl <op> const"
3407
3408 assert(lpIterTree->OperIs(GT_ASG));
3409
3410 GenTree* lhs = lpIterTree->gtOp.gtOp1;
3411 GenTree* rhs = lpIterTree->gtOp.gtOp2;
3412 assert(lhs->OperGet() == GT_LCL_VAR);
3413
3414 switch (rhs->gtOper)
3415 {
3416 case GT_ADD:
3417 case GT_SUB:
3418 case GT_MUL:
3419 case GT_RSH:
3420 case GT_LSH:
3421 break;
3422 default:
3423 assert(!"Unknown operator for loop increment");
3424 }
3425 assert(rhs->gtOp.gtOp1->OperGet() == GT_LCL_VAR);
3426 assert(rhs->gtOp.gtOp1->AsLclVarCommon()->GetLclNum() == lhs->AsLclVarCommon()->GetLclNum());
3427 assert(rhs->gtOp.gtOp2->OperGet() == GT_CNS_INT);
3428#endif
3429}
3430
3431//-----------------------------------------------------------------------------
3432
3433inline unsigned Compiler::LoopDsc::lpIterVar()
3434{
3435 VERIFY_lpIterTree();
3436 return lpIterTree->gtOp.gtOp1->gtLclVarCommon.gtLclNum;
3437}
3438
3439//-----------------------------------------------------------------------------
3440
3441inline int Compiler::LoopDsc::lpIterConst()
3442{
3443 VERIFY_lpIterTree();
3444 GenTree* rhs = lpIterTree->gtOp.gtOp2;
3445 return (int)rhs->gtOp.gtOp2->gtIntCon.gtIconVal;
3446}
3447
3448//-----------------------------------------------------------------------------
3449
3450inline genTreeOps Compiler::LoopDsc::lpIterOper()
3451{
3452 VERIFY_lpIterTree();
3453 GenTree* rhs = lpIterTree->gtOp.gtOp2;
3454 return rhs->OperGet();
3455}
3456
3457inline var_types Compiler::LoopDsc::lpIterOperType()
3458{
3459 VERIFY_lpIterTree();
3460
3461 var_types type = lpIterTree->TypeGet();
3462 assert(genActualType(type) == TYP_INT);
3463
3464 if ((lpIterTree->gtFlags & GTF_UNSIGNED) && type == TYP_INT)
3465 {
3466 type = TYP_UINT;
3467 }
3468
3469 return type;
3470}
3471
3472inline void Compiler::LoopDsc::VERIFY_lpTestTree()
3473{
3474#ifdef DEBUG
3475 assert(lpFlags & LPFLG_ITER);
3476 assert(lpTestTree);
3477
3478 genTreeOps oper = lpTestTree->OperGet();
3479 assert(GenTree::OperIsCompare(oper));
3480
3481 GenTree* iterator = nullptr;
3482 GenTree* limit = nullptr;
3483 if ((lpTestTree->gtOp.gtOp2->gtOper == GT_LCL_VAR) && (lpTestTree->gtOp.gtOp2->gtFlags & GTF_VAR_ITERATOR) != 0)
3484 {
3485 iterator = lpTestTree->gtOp.gtOp2;
3486 limit = lpTestTree->gtOp.gtOp1;
3487 }
3488 else if ((lpTestTree->gtOp.gtOp1->gtOper == GT_LCL_VAR) &&
3489 (lpTestTree->gtOp.gtOp1->gtFlags & GTF_VAR_ITERATOR) != 0)
3490 {
3491 iterator = lpTestTree->gtOp.gtOp1;
3492 limit = lpTestTree->gtOp.gtOp2;
3493 }
3494 else
3495 {
3496 // one of the nodes has to be the iterator
3497 assert(false);
3498 }
3499
3500 if (lpFlags & LPFLG_CONST_LIMIT)
3501 {
3502 assert(limit->OperIsConst());
3503 }
3504 if (lpFlags & LPFLG_VAR_LIMIT)
3505 {
3506 assert(limit->OperGet() == GT_LCL_VAR);
3507 }
3508 if (lpFlags & LPFLG_ARRLEN_LIMIT)
3509 {
3510 assert(limit->OperGet() == GT_ARR_LENGTH);
3511 }
3512#endif
3513}
3514
3515//-----------------------------------------------------------------------------
3516
3517inline bool Compiler::LoopDsc::lpIsReversed()
3518{
3519 VERIFY_lpTestTree();
3520 return ((lpTestTree->gtOp.gtOp2->gtOper == GT_LCL_VAR) &&
3521 (lpTestTree->gtOp.gtOp2->gtFlags & GTF_VAR_ITERATOR) != 0);
3522}
3523
3524//-----------------------------------------------------------------------------
3525
3526inline genTreeOps Compiler::LoopDsc::lpTestOper()
3527{
3528 VERIFY_lpTestTree();
3529 genTreeOps op = lpTestTree->OperGet();
3530 return lpIsReversed() ? GenTree::SwapRelop(op) : op;
3531}
3532
3533//-----------------------------------------------------------------------------
3534
3535inline GenTree* Compiler::LoopDsc::lpIterator()
3536{
3537 VERIFY_lpTestTree();
3538
3539 return lpIsReversed() ? lpTestTree->gtOp.gtOp2 : lpTestTree->gtOp.gtOp1;
3540}
3541
3542//-----------------------------------------------------------------------------
3543
3544inline GenTree* Compiler::LoopDsc::lpLimit()
3545{
3546 VERIFY_lpTestTree();
3547
3548 return lpIsReversed() ? lpTestTree->gtOp.gtOp1 : lpTestTree->gtOp.gtOp2;
3549}
3550
3551//-----------------------------------------------------------------------------
3552
3553inline int Compiler::LoopDsc::lpConstLimit()
3554{
3555 VERIFY_lpTestTree();
3556 assert(lpFlags & LPFLG_CONST_LIMIT);
3557
3558 GenTree* limit = lpLimit();
3559 assert(limit->OperIsConst());
3560 return (int)limit->gtIntCon.gtIconVal;
3561}
3562
3563//-----------------------------------------------------------------------------
3564
3565inline unsigned Compiler::LoopDsc::lpVarLimit()
3566{
3567 VERIFY_lpTestTree();
3568 assert(lpFlags & LPFLG_VAR_LIMIT);
3569
3570 GenTree* limit = lpLimit();
3571 assert(limit->OperGet() == GT_LCL_VAR);
3572 return limit->gtLclVarCommon.gtLclNum;
3573}
3574
3575//-----------------------------------------------------------------------------
3576
3577inline bool Compiler::LoopDsc::lpArrLenLimit(Compiler* comp, ArrIndex* index)
3578{
3579 VERIFY_lpTestTree();
3580 assert(lpFlags & LPFLG_ARRLEN_LIMIT);
3581
3582 GenTree* limit = lpLimit();
3583 assert(limit->OperGet() == GT_ARR_LENGTH);
3584
3585 // Check if we have a.length or a[i][j].length
3586 if (limit->gtArrLen.ArrRef()->gtOper == GT_LCL_VAR)
3587 {
3588 index->arrLcl = limit->gtArrLen.ArrRef()->gtLclVarCommon.gtLclNum;
3589 index->rank = 0;
3590 return true;
3591 }
3592 // We have a[i].length, extract a[i] pattern.
3593 else if (limit->gtArrLen.ArrRef()->gtOper == GT_COMMA)
3594 {
3595 return comp->optReconstructArrIndex(limit->gtArrLen.ArrRef(), index, BAD_VAR_NUM);
3596 }
3597 return false;
3598}
3599
3600/*****************************************************************************
3601 * Is "var" assigned in the loop "lnum" ?
3602 */
3603
3604inline bool Compiler::optIsVarAssgLoop(unsigned lnum, unsigned var)
3605{
3606 assert(lnum < optLoopCount);
3607 if (var < lclMAX_ALLSET_TRACKED)
3608 {
3609 ALLVARSET_TP vs(AllVarSetOps::MakeSingleton(this, var));
3610 return optIsSetAssgLoop(lnum, vs) != 0;
3611 }
3612 else
3613 {
3614 return optIsVarAssigned(optLoopTable[lnum].lpHead->bbNext, optLoopTable[lnum].lpBottom, nullptr, var);
3615 }
3616}
3617
3618/*
3619XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3620XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3621XX XX
3622XX Optimization activation rules XX
3623XX XX
3624XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3625XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3626*/
3627
3628// are we compiling for fast code, or are we compiling for blended code and
3629// inside a loop?
3630// We return true for BLENDED_CODE if the Block executes more than BB_LOOP_WEIGHT/2
3631inline bool Compiler::optFastCodeOrBlendedLoop(BasicBlock::weight_t bbWeight)
3632{
3633 return (compCodeOpt() == FAST_CODE) ||
3634 ((compCodeOpt() == BLENDED_CODE) && (bbWeight > (BB_LOOP_WEIGHT / 2 * BB_UNITY_WEIGHT)));
3635}
3636
3637// are we running on a Intel Pentium 4?
3638inline bool Compiler::optPentium4(void)
3639{
3640 return (info.genCPU == CPU_X86_PENTIUM_4);
3641}
3642
3643// should we use add/sub instead of inc/dec? (faster on P4, but increases size)
3644inline bool Compiler::optAvoidIncDec(BasicBlock::weight_t bbWeight)
3645{
3646 return optPentium4() && optFastCodeOrBlendedLoop(bbWeight);
3647}
3648
3649// should we try to replace integer multiplication with lea/add/shift sequences?
3650inline bool Compiler::optAvoidIntMult(void)
3651{
3652 return (compCodeOpt() != SMALL_CODE);
3653}
3654
3655/*
3656XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3657XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3658XX EEInterface XX
3659XX Inline functions XX
3660XX XX
3661XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3662XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3663*/
3664
3665extern var_types JITtype2varType(CorInfoType type);
3666
3667#include "ee_il_dll.hpp"
3668
3669inline CORINFO_METHOD_HANDLE Compiler::eeFindHelper(unsigned helper)
3670{
3671 assert(helper < CORINFO_HELP_COUNT);
3672
3673 /* Helpers are marked by the fact that they are odd numbers
3674 * force this to be an odd number (will shift it back to extract) */
3675
3676 return ((CORINFO_METHOD_HANDLE)(size_t)((helper << 2) + 1));
3677}
3678
3679inline CorInfoHelpFunc Compiler::eeGetHelperNum(CORINFO_METHOD_HANDLE method)
3680{
3681 // Helpers are marked by the fact that they are odd numbers
3682 if (!(((size_t)method) & 1))
3683 {
3684 return (CORINFO_HELP_UNDEF);
3685 }
3686 return ((CorInfoHelpFunc)(((size_t)method) >> 2));
3687}
3688
3689inline Compiler::fgWalkResult Compiler::CountSharedStaticHelper(GenTree** pTree, fgWalkData* data)
3690{
3691 if (Compiler::IsSharedStaticHelper(*pTree))
3692 {
3693 int* pCount = (int*)data->pCallbackData;
3694 (*pCount)++;
3695 }
3696
3697 return WALK_CONTINUE;
3698}
3699
3700// TODO-Cleanup: Replace calls to IsSharedStaticHelper with new HelperCallProperties
3701//
3702
3703inline bool Compiler::IsSharedStaticHelper(GenTree* tree)
3704{
3705 if (tree->gtOper != GT_CALL || tree->gtCall.gtCallType != CT_HELPER)
3706 {
3707 return false;
3708 }
3709
3710 CorInfoHelpFunc helper = eeGetHelperNum(tree->gtCall.gtCallMethHnd);
3711
3712 bool result1 =
3713 // More helpers being added to IsSharedStaticHelper (that have similar behaviors but are not true
3714 // ShareStaticHelperts)
3715 helper == CORINFO_HELP_STRCNS || helper == CORINFO_HELP_BOX ||
3716
3717 // helpers being added to IsSharedStaticHelper
3718 helper == CORINFO_HELP_GETSTATICFIELDADDR_CONTEXT || helper == CORINFO_HELP_GETSTATICFIELDADDR_TLS ||
3719 helper == CORINFO_HELP_GETGENERICS_GCSTATIC_BASE || helper == CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE ||
3720 helper == CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE ||
3721 helper == CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE ||
3722
3723 helper == CORINFO_HELP_GETSHARED_GCSTATIC_BASE || helper == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE ||
3724 helper == CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR ||
3725 helper == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR ||
3726 helper == CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS ||
3727 helper == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS ||
3728 helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE ||
3729 helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE ||
3730 helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR ||
3731 helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR ||
3732 helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS ||
3733 helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS ||
3734#ifdef FEATURE_READYTORUN_COMPILER
3735 helper == CORINFO_HELP_READYTORUN_STATIC_BASE || helper == CORINFO_HELP_READYTORUN_GENERIC_STATIC_BASE ||
3736#endif
3737 helper == CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS;
3738#if 0
3739 // See above TODO-Cleanup
3740 bool result2 = s_helperCallProperties.IsPure(helper) && s_helperCallProperties.NonNullReturn(helper);
3741 assert (result1 == result2);
3742#endif
3743 return result1;
3744}
3745
3746inline bool Compiler::IsTreeAlwaysHoistable(GenTree* tree)
3747{
3748 if (IsSharedStaticHelper(tree))
3749 {
3750 return (GTF_CALL_HOISTABLE & tree->gtFlags) ? true : false;
3751 }
3752 else
3753 {
3754 return false;
3755 }
3756}
3757
3758inline bool Compiler::IsGcSafePoint(GenTree* tree)
3759{
3760 if (tree->IsCall())
3761 {
3762 GenTreeCall* call = tree->AsCall();
3763 if (!call->IsFastTailCall())
3764 {
3765 if (call->gtCallType == CT_INDIRECT)
3766 {
3767 return true;
3768 }
3769 else if (call->gtCallType == CT_USER_FUNC)
3770 {
3771 if ((call->gtCallMoreFlags & GTF_CALL_M_NOGCCHECK) == 0)
3772 {
3773 return true;
3774 }
3775 }
3776 // otherwise we have a CT_HELPER
3777 }
3778 }
3779
3780 return false;
3781}
3782
3783//
3784// Note that we want to have two special FIELD_HANDLES that will both
3785// be considered non-Data Offset handles
3786//
3787// The special values that we use are FLD_GLOBAL_DS and FLD_GLOBAL_FS
3788//
3789
3790inline bool jitStaticFldIsGlobAddr(CORINFO_FIELD_HANDLE fldHnd)
3791{
3792 return (fldHnd == FLD_GLOBAL_DS || fldHnd == FLD_GLOBAL_FS);
3793}
3794
3795#if defined(DEBUG) || defined(FEATURE_JIT_METHOD_PERF) || defined(FEATURE_SIMD) || defined(FEATURE_TRACELOGGING)
3796
3797inline bool Compiler::eeIsNativeMethod(CORINFO_METHOD_HANDLE method)
3798{
3799 return ((((size_t)method) & 0x2) == 0x2);
3800}
3801
3802inline CORINFO_METHOD_HANDLE Compiler::eeGetMethodHandleForNative(CORINFO_METHOD_HANDLE method)
3803{
3804 assert((((size_t)method) & 0x3) == 0x2);
3805 return (CORINFO_METHOD_HANDLE)(((size_t)method) & ~0x3);
3806}
3807#endif
3808
3809inline CORINFO_METHOD_HANDLE Compiler::eeMarkNativeTarget(CORINFO_METHOD_HANDLE method)
3810{
3811 assert((((size_t)method) & 0x3) == 0);
3812 if (method == nullptr)
3813 {
3814 return method;
3815 }
3816 else
3817 {
3818 return (CORINFO_METHOD_HANDLE)(((size_t)method) | 0x2);
3819 }
3820}
3821
3822/*
3823XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3824XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3825XX Compiler XX
3826XX Inline functions XX
3827XX XX
3828XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3829XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
3830*/
3831
3832#ifndef DEBUG
3833inline bool Compiler::compStressCompile(compStressArea stressArea, unsigned weightPercentage)
3834{
3835 return false;
3836}
3837#endif
3838
3839inline ArenaAllocator* Compiler::compGetArenaAllocator()
3840{
3841 return compArenaAllocator;
3842}
3843
3844inline bool Compiler::compIsProfilerHookNeeded()
3845{
3846#ifdef PROFILING_SUPPORTED
3847 return compProfilerHookNeeded
3848 // IL stubs are excluded by VM and we need to do the same even running
3849 // under a complus env hook to generate profiler hooks
3850 || (opts.compJitELTHookEnabled && !opts.jitFlags->IsSet(JitFlags::JIT_FLAG_IL_STUB));
3851#else // !PROFILING_SUPPORTED
3852 return false;
3853#endif // !PROFILING_SUPPORTED
3854}
3855
3856/*****************************************************************************
3857 *
3858 * Check for the special case where the object is the constant 0.
3859 * As we can't even fold the tree (null+fldOffs), we are left with
3860 * op1 and op2 both being a constant. This causes lots of problems.
3861 * We simply grab a temp and assign 0 to it and use it in place of the NULL.
3862 */
3863
3864inline GenTree* Compiler::impCheckForNullPointer(GenTree* obj)
3865{
3866 /* If it is not a GC type, we will be able to fold it.
3867 So don't need to do anything */
3868
3869 if (!varTypeIsGC(obj->TypeGet()))
3870 {
3871 return obj;
3872 }
3873
3874 if (obj->gtOper == GT_CNS_INT)
3875 {
3876 assert(obj->gtType == TYP_REF || obj->gtType == TYP_BYREF);
3877
3878 // We can see non-zero byrefs for RVA statics.
3879 if (obj->gtIntCon.gtIconVal != 0)
3880 {
3881 assert(obj->gtType == TYP_BYREF);
3882 return obj;
3883 }
3884
3885 unsigned tmp = lvaGrabTemp(true DEBUGARG("CheckForNullPointer"));
3886
3887 // We don't need to spill while appending as we are only assigning
3888 // NULL to a freshly-grabbed temp.
3889
3890 impAssignTempGen(tmp, obj, (unsigned)CHECK_SPILL_NONE);
3891
3892 obj = gtNewLclvNode(tmp, obj->gtType);
3893 }
3894
3895 return obj;
3896}
3897
3898/*****************************************************************************
3899 *
3900 * Check for the special case where the object is the methods original 'this' pointer.
3901 * Note that, the original 'this' pointer is always local var 0 for non-static method,
3902 * even if we might have created the copy of 'this' pointer in lvaArg0Var.
3903 */
3904
3905inline bool Compiler::impIsThis(GenTree* obj)
3906{
3907 if (compIsForInlining())
3908 {
3909 return impInlineInfo->InlinerCompiler->impIsThis(obj);
3910 }
3911 else
3912 {
3913 return ((obj != nullptr) && (obj->gtOper == GT_LCL_VAR) && lvaIsOriginalThisArg(obj->gtLclVarCommon.gtLclNum));
3914 }
3915}
3916
3917/*****************************************************************************
3918 *
3919 * Check to see if the delegate is created using "LDFTN <TOK>" or not.
3920 */
3921
3922inline bool Compiler::impIsLDFTN_TOKEN(const BYTE* delegateCreateStart, const BYTE* newobjCodeAddr)
3923{
3924 assert(newobjCodeAddr[0] == CEE_NEWOBJ);
3925 return (newobjCodeAddr - delegateCreateStart == 6 && // LDFTN <TOK> takes 6 bytes
3926 delegateCreateStart[0] == CEE_PREFIX1 && delegateCreateStart[1] == (CEE_LDFTN & 0xFF));
3927}
3928
3929/*****************************************************************************
3930 *
3931 * Check to see if the delegate is created using "DUP LDVIRTFTN <TOK>" or not.
3932 */
3933
3934inline bool Compiler::impIsDUP_LDVIRTFTN_TOKEN(const BYTE* delegateCreateStart, const BYTE* newobjCodeAddr)
3935{
3936 assert(newobjCodeAddr[0] == CEE_NEWOBJ);
3937 return (newobjCodeAddr - delegateCreateStart == 7 && // DUP LDVIRTFTN <TOK> takes 6 bytes
3938 delegateCreateStart[0] == CEE_DUP && delegateCreateStart[1] == CEE_PREFIX1 &&
3939 delegateCreateStart[2] == (CEE_LDVIRTFTN & 0xFF));
3940}
3941/*****************************************************************************
3942 *
3943 * Returns true if the compiler instance is created for import only (verification).
3944 */
3945
3946inline bool Compiler::compIsForImportOnly()
3947{
3948 return opts.jitFlags->IsSet(JitFlags::JIT_FLAG_IMPORT_ONLY);
3949}
3950
3951/*****************************************************************************
3952 *
3953 * Returns true if the compiler instance is created for inlining.
3954 */
3955
3956inline bool Compiler::compIsForInlining()
3957{
3958 return (impInlineInfo != nullptr);
3959}
3960
3961/*****************************************************************************
3962 *
3963 * Check the inline result field in the compiler to see if inlining failed or not.
3964 */
3965
3966inline bool Compiler::compDonotInline()
3967{
3968 if (compIsForInlining())
3969 {
3970 assert(compInlineResult != nullptr);
3971 return compInlineResult->IsFailure();
3972 }
3973 else
3974 {
3975 return false;
3976 }
3977}
3978
3979inline bool Compiler::impIsPrimitive(CorInfoType jitType)
3980{
3981 return ((CORINFO_TYPE_BOOL <= jitType && jitType <= CORINFO_TYPE_DOUBLE) || jitType == CORINFO_TYPE_PTR);
3982}
3983
3984/*****************************************************************************
3985 *
3986 * Get the promotion type of a struct local.
3987 */
3988
3989inline Compiler::lvaPromotionType Compiler::lvaGetPromotionType(const LclVarDsc* varDsc)
3990{
3991 assert(!varDsc->lvPromoted || varTypeIsPromotable(varDsc) || varDsc->lvUnusedStruct);
3992
3993 if (!varDsc->lvPromoted)
3994 {
3995 // no struct promotion for this LclVar
3996 return PROMOTION_TYPE_NONE;
3997 }
3998 if (varDsc->lvDoNotEnregister)
3999 {
4000 // The struct is not enregistered
4001 return PROMOTION_TYPE_DEPENDENT;
4002 }
4003 if (!varDsc->lvIsParam)
4004 {
4005 // The struct is a register candidate
4006 return PROMOTION_TYPE_INDEPENDENT;
4007 }
4008
4009 // Has struct promotion for arguments been disabled using COMPlus_JitNoStructPromotion=2
4010 if (fgNoStructParamPromotion)
4011 {
4012 // The struct parameter is not enregistered
4013 return PROMOTION_TYPE_DEPENDENT;
4014 }
4015
4016 // We have a parameter that could be enregistered
4017 CLANG_FORMAT_COMMENT_ANCHOR;
4018
4019#if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
4020
4021 // The struct parameter is a register candidate
4022 return PROMOTION_TYPE_INDEPENDENT;
4023#else
4024 // The struct parameter is not enregistered
4025 return PROMOTION_TYPE_DEPENDENT;
4026#endif
4027}
4028
4029/*****************************************************************************
4030 *
4031 * Get the promotion type of a struct local.
4032 */
4033
4034inline Compiler::lvaPromotionType Compiler::lvaGetPromotionType(unsigned varNum)
4035{
4036 assert(varNum < lvaCount);
4037 return lvaGetPromotionType(&lvaTable[varNum]);
4038}
4039
4040/*****************************************************************************
4041 *
4042 * Given a field local, get the promotion type of its parent struct local.
4043 */
4044
4045inline Compiler::lvaPromotionType Compiler::lvaGetParentPromotionType(const LclVarDsc* varDsc)
4046{
4047 assert(varDsc->lvIsStructField);
4048 assert(varDsc->lvParentLcl < lvaCount);
4049
4050 lvaPromotionType promotionType = lvaGetPromotionType(varDsc->lvParentLcl);
4051 assert(promotionType != PROMOTION_TYPE_NONE);
4052 return promotionType;
4053}
4054
4055/*****************************************************************************
4056 *
4057 * Given a field local, get the promotion type of its parent struct local.
4058 */
4059
4060inline Compiler::lvaPromotionType Compiler::lvaGetParentPromotionType(unsigned varNum)
4061{
4062 assert(varNum < lvaCount);
4063 return lvaGetParentPromotionType(&lvaTable[varNum]);
4064}
4065
4066/*****************************************************************************
4067 *
4068 * Return true if the local is a field local of a promoted struct of type PROMOTION_TYPE_DEPENDENT.
4069 * Return false otherwise.
4070 */
4071
4072inline bool Compiler::lvaIsFieldOfDependentlyPromotedStruct(const LclVarDsc* varDsc)
4073{
4074 if (!varDsc->lvIsStructField)
4075 {
4076 return false;
4077 }
4078
4079 lvaPromotionType promotionType = lvaGetParentPromotionType(varDsc);
4080 if (promotionType == PROMOTION_TYPE_DEPENDENT)
4081 {
4082 return true;
4083 }
4084
4085 assert(promotionType == PROMOTION_TYPE_INDEPENDENT);
4086 return false;
4087}
4088
4089//------------------------------------------------------------------------
4090// lvaIsGCTracked: Determine whether this var should be reported
4091// as tracked for GC purposes.
4092//
4093// Arguments:
4094// varDsc - the LclVarDsc for the var in question.
4095//
4096// Return Value:
4097// Returns true if the variable should be reported as tracked in the GC info.
4098//
4099// Notes:
4100// This never returns true for struct variables, even if they are tracked.
4101// This is because struct variables are never tracked as a whole for GC purposes.
4102// It is up to the caller to ensure that the fields of struct variables are
4103// correctly tracked.
4104// On Amd64, we never GC-track fields of dependently promoted structs, even
4105// though they may be tracked for optimization purposes.
4106// It seems that on x86 and arm, we simply don't track these
4107// fields, though I have not verified that. I attempted to make these GC-tracked,
4108// but there was too much logic that depends on these being untracked, so changing
4109// this would require non-trivial effort.
4110
4111inline bool Compiler::lvaIsGCTracked(const LclVarDsc* varDsc)
4112{
4113 if (varDsc->lvTracked && (varDsc->lvType == TYP_REF || varDsc->lvType == TYP_BYREF))
4114 {
4115 // Stack parameters are always untracked w.r.t. GC reportings
4116 const bool isStackParam = varDsc->lvIsParam && !varDsc->lvIsRegArg;
4117#ifdef _TARGET_AMD64_
4118 return !isStackParam && !lvaIsFieldOfDependentlyPromotedStruct(varDsc);
4119#else // !_TARGET_AMD64_
4120 return !isStackParam;
4121#endif // !_TARGET_AMD64_
4122 }
4123 else
4124 {
4125 return false;
4126 }
4127}
4128
4129inline void Compiler::EndPhase(Phases phase)
4130{
4131#if defined(FEATURE_JIT_METHOD_PERF)
4132 if (pCompJitTimer != nullptr)
4133 {
4134 pCompJitTimer->EndPhase(this, phase);
4135 }
4136#endif
4137#if DUMP_FLOWGRAPHS
4138 fgDumpFlowGraph(phase);
4139#endif // DUMP_FLOWGRAPHS
4140 previousCompletedPhase = phase;
4141#ifdef DEBUG
4142 if (dumpIR)
4143 {
4144 if ((*dumpIRPhase == L'*') || (wcscmp(dumpIRPhase, PhaseShortNames[phase]) == 0))
4145 {
4146 printf("\n");
4147 printf("IR after %s (switch: %ls)\n", PhaseEnums[phase], PhaseShortNames[phase]);
4148 printf("\n");
4149
4150 if (dumpIRLinear)
4151 {
4152 dFuncIR();
4153 }
4154 else if (dumpIRTrees)
4155 {
4156 dTrees();
4157 }
4158
4159 // If we are just dumping a single method and we have a request to exit
4160 // after dumping, do so now.
4161
4162 if (dumpIRExit && ((*dumpIRPhase != L'*') || (phase == PHASE_EMIT_GCEH)))
4163 {
4164 exit(0);
4165 }
4166 }
4167 }
4168#endif
4169}
4170
4171/*****************************************************************************/
4172#if MEASURE_CLRAPI_CALLS
4173
4174inline void Compiler::CLRApiCallEnter(unsigned apix)
4175{
4176 if (pCompJitTimer != nullptr)
4177 {
4178 pCompJitTimer->CLRApiCallEnter(apix);
4179 }
4180}
4181inline void Compiler::CLRApiCallLeave(unsigned apix)
4182{
4183 if (pCompJitTimer != nullptr)
4184 {
4185 pCompJitTimer->CLRApiCallLeave(apix);
4186 }
4187}
4188
4189inline void Compiler::CLR_API_Enter(API_ICorJitInfo_Names ename)
4190{
4191 CLRApiCallEnter(ename);
4192}
4193
4194inline void Compiler::CLR_API_Leave(API_ICorJitInfo_Names ename)
4195{
4196 CLRApiCallLeave(ename);
4197}
4198
4199#endif // MEASURE_CLRAPI_CALLS
4200
4201//------------------------------------------------------------------------------
4202// fgStructTempNeedsExplicitZeroInit : Check whether temp struct needs
4203// explicit zero initialization in this basic block.
4204//
4205// Arguments:
4206// varDsc - struct local var description
4207// block - basic block to check
4208//
4209// Returns:
4210// true if the struct temp needs explicit zero-initialization in this basic block;
4211// false otherwise
4212//
4213// Notes:
4214// If compInitMem is true, structs with GC pointer fields and long-lifetime structs
4215// are fully zero-initialized in the prologue. Therefore, we don't need to insert
4216// zero-initialization in this block if it is not in a loop.
4217
4218bool Compiler::fgStructTempNeedsExplicitZeroInit(LclVarDsc* varDsc, BasicBlock* block)
4219{
4220 bool containsGCPtr = (varDsc->lvStructGcCount > 0);
4221 return (!info.compInitMem || ((block->bbFlags & BBF_BACKWARD_JUMP) != 0) || (!containsGCPtr && varDsc->lvIsTemp));
4222}
4223
4224/*****************************************************************************/
4225ValueNum Compiler::GetUseAsgDefVNOrTreeVN(GenTree* op)
4226{
4227 if (op->gtFlags & GTF_VAR_USEASG)
4228 {
4229 unsigned lclNum = op->AsLclVarCommon()->GetLclNum();
4230 unsigned ssaNum = GetSsaNumForLocalVarDef(op);
4231 return lvaTable[lclNum].GetPerSsaData(ssaNum)->m_vnPair.GetConservative();
4232 }
4233 else
4234 {
4235 return op->gtVNPair.GetConservative();
4236 }
4237}
4238
4239/*****************************************************************************/
4240unsigned Compiler::GetSsaNumForLocalVarDef(GenTree* lcl)
4241{
4242 // Address-taken variables don't have SSA numbers.
4243 if (!lvaInSsa(lcl->AsLclVarCommon()->gtLclNum))
4244 {
4245 return SsaConfig::RESERVED_SSA_NUM;
4246 }
4247
4248 if (lcl->gtFlags & GTF_VAR_USEASG)
4249 {
4250 // It's partial definition of a struct. "lcl" is both used and defined here;
4251 // we've chosen in this case to annotate "lcl" with the SSA number (and VN) of the use,
4252 // and to store the SSA number of the def in a side table.
4253 unsigned ssaNum;
4254 // In case of a remorph (fgMorph) in CSE/AssertionProp after SSA phase, there
4255 // wouldn't be an entry for the USEASG portion of the indir addr, return
4256 // reserved.
4257 if (!GetOpAsgnVarDefSsaNums()->Lookup(lcl, &ssaNum))
4258 {
4259 return SsaConfig::RESERVED_SSA_NUM;
4260 }
4261 return ssaNum;
4262 }
4263 else
4264 {
4265 return lcl->AsLclVarCommon()->gtSsaNum;
4266 }
4267}
4268
4269template <typename TVisitor>
4270void GenTree::VisitOperands(TVisitor visitor)
4271{
4272 switch (OperGet())
4273 {
4274 // Leaf nodes
4275 case GT_LCL_VAR:
4276 case GT_LCL_FLD:
4277 case GT_LCL_VAR_ADDR:
4278 case GT_LCL_FLD_ADDR:
4279 case GT_CATCH_ARG:
4280 case GT_LABEL:
4281 case GT_FTN_ADDR:
4282 case GT_RET_EXPR:
4283 case GT_CNS_INT:
4284 case GT_CNS_LNG:
4285 case GT_CNS_DBL:
4286 case GT_CNS_STR:
4287 case GT_MEMORYBARRIER:
4288 case GT_JMP:
4289 case GT_JCC:
4290 case GT_SETCC:
4291 case GT_NO_OP:
4292 case GT_START_NONGC:
4293 case GT_PROF_HOOK:
4294#if !FEATURE_EH_FUNCLETS
4295 case GT_END_LFIN:
4296#endif // !FEATURE_EH_FUNCLETS
4297 case GT_PHI_ARG:
4298 case GT_JMPTABLE:
4299 case GT_CLS_VAR:
4300 case GT_CLS_VAR_ADDR:
4301 case GT_ARGPLACE:
4302 case GT_PHYSREG:
4303 case GT_EMITNOP:
4304 case GT_PINVOKE_PROLOG:
4305 case GT_PINVOKE_EPILOG:
4306 case GT_IL_OFFSET:
4307 return;
4308
4309 // Unary operators with an optional operand
4310 case GT_NOP:
4311 case GT_RETURN:
4312 case GT_RETFILT:
4313 if (this->AsUnOp()->gtOp1 == nullptr)
4314 {
4315 return;
4316 }
4317 __fallthrough;
4318
4319 // Standard unary operators
4320 case GT_STORE_LCL_VAR:
4321 case GT_STORE_LCL_FLD:
4322 case GT_NOT:
4323 case GT_NEG:
4324 case GT_BSWAP:
4325 case GT_BSWAP16:
4326 case GT_COPY:
4327 case GT_RELOAD:
4328 case GT_ARR_LENGTH:
4329 case GT_CAST:
4330 case GT_BITCAST:
4331 case GT_CKFINITE:
4332 case GT_LCLHEAP:
4333 case GT_ADDR:
4334 case GT_IND:
4335 case GT_OBJ:
4336 case GT_BLK:
4337 case GT_BOX:
4338 case GT_ALLOCOBJ:
4339 case GT_INIT_VAL:
4340 case GT_JTRUE:
4341 case GT_SWITCH:
4342 case GT_NULLCHECK:
4343 case GT_PUTARG_REG:
4344 case GT_PUTARG_STK:
4345#if FEATURE_ARG_SPLIT
4346 case GT_PUTARG_SPLIT:
4347#endif // FEATURE_ARG_SPLIT
4348 case GT_RETURNTRAP:
4349 visitor(this->AsUnOp()->gtOp1);
4350 return;
4351
4352 // Variadic nodes
4353 case GT_PHI:
4354 assert(this->AsUnOp()->gtOp1 != nullptr);
4355 this->AsUnOp()->gtOp1->VisitListOperands(visitor);
4356 return;
4357
4358 case GT_FIELD_LIST:
4359 VisitListOperands(visitor);
4360 return;
4361
4362#ifdef FEATURE_SIMD
4363 case GT_SIMD:
4364 if (this->AsSIMD()->gtSIMDIntrinsicID == SIMDIntrinsicInitN)
4365 {
4366 assert(this->AsSIMD()->gtOp1 != nullptr);
4367 this->AsSIMD()->gtOp1->VisitListOperands(visitor);
4368 }
4369 else
4370 {
4371 VisitBinOpOperands<TVisitor>(visitor);
4372 }
4373 return;
4374#endif // FEATURE_SIMD
4375
4376#ifdef FEATURE_HW_INTRINSICS
4377 case GT_HWIntrinsic:
4378 if ((this->AsHWIntrinsic()->gtOp1 != nullptr) && this->AsHWIntrinsic()->gtOp1->OperIsList())
4379 {
4380 this->AsHWIntrinsic()->gtOp1->VisitListOperands(visitor);
4381 }
4382 else
4383 {
4384 VisitBinOpOperands<TVisitor>(visitor);
4385 }
4386 return;
4387#endif // FEATURE_HW_INTRINSICS
4388
4389 // Special nodes
4390 case GT_CMPXCHG:
4391 {
4392 GenTreeCmpXchg* const cmpXchg = this->AsCmpXchg();
4393 if (visitor(cmpXchg->gtOpLocation) == VisitResult::Abort)
4394 {
4395 return;
4396 }
4397 if (visitor(cmpXchg->gtOpValue) == VisitResult::Abort)
4398 {
4399 return;
4400 }
4401 visitor(cmpXchg->gtOpComparand);
4402 return;
4403 }
4404
4405 case GT_ARR_BOUNDS_CHECK:
4406#ifdef FEATURE_SIMD
4407 case GT_SIMD_CHK:
4408#endif // FEATURE_SIMD
4409#ifdef FEATURE_HW_INTRINSICS
4410 case GT_HW_INTRINSIC_CHK:
4411#endif // FEATURE_HW_INTRINSICS
4412 {
4413 GenTreeBoundsChk* const boundsChk = this->AsBoundsChk();
4414 if (visitor(boundsChk->gtIndex) == VisitResult::Abort)
4415 {
4416 return;
4417 }
4418 visitor(boundsChk->gtArrLen);
4419 return;
4420 }
4421
4422 case GT_FIELD:
4423 if (this->AsField()->gtFldObj != nullptr)
4424 {
4425 visitor(this->AsField()->gtFldObj);
4426 }
4427 return;
4428
4429 case GT_STMT:
4430 if (this->AsStmt()->gtStmtExpr != nullptr)
4431 {
4432 visitor(this->AsStmt()->gtStmtExpr);
4433 }
4434 return;
4435
4436 case GT_ARR_ELEM:
4437 {
4438 GenTreeArrElem* const arrElem = this->AsArrElem();
4439 if (visitor(arrElem->gtArrObj) == VisitResult::Abort)
4440 {
4441 return;
4442 }
4443 for (unsigned i = 0; i < arrElem->gtArrRank; i++)
4444 {
4445 if (visitor(arrElem->gtArrInds[i]) == VisitResult::Abort)
4446 {
4447 return;
4448 }
4449 }
4450 return;
4451 }
4452
4453 case GT_ARR_OFFSET:
4454 {
4455 GenTreeArrOffs* const arrOffs = this->AsArrOffs();
4456 if (visitor(arrOffs->gtOffset) == VisitResult::Abort)
4457 {
4458 return;
4459 }
4460 if (visitor(arrOffs->gtIndex) == VisitResult::Abort)
4461 {
4462 return;
4463 }
4464 visitor(arrOffs->gtArrObj);
4465 return;
4466 }
4467
4468 case GT_DYN_BLK:
4469 {
4470 GenTreeDynBlk* const dynBlock = this->AsDynBlk();
4471 if (visitor(dynBlock->gtOp1) == VisitResult::Abort)
4472 {
4473 return;
4474 }
4475 visitor(dynBlock->gtDynamicSize);
4476 return;
4477 }
4478
4479 case GT_STORE_DYN_BLK:
4480 {
4481 GenTreeDynBlk* const dynBlock = this->AsDynBlk();
4482 if (visitor(dynBlock->gtOp1) == VisitResult::Abort)
4483 {
4484 return;
4485 }
4486 if (visitor(dynBlock->gtOp2) == VisitResult::Abort)
4487 {
4488 return;
4489 }
4490 visitor(dynBlock->gtDynamicSize);
4491 return;
4492 }
4493
4494 case GT_CALL:
4495 {
4496 GenTreeCall* const call = this->AsCall();
4497 if ((call->gtCallObjp != nullptr) && (visitor(call->gtCallObjp) == VisitResult::Abort))
4498 {
4499 return;
4500 }
4501 if ((call->gtCallArgs != nullptr) && (call->gtCallArgs->VisitListOperands(visitor) == VisitResult::Abort))
4502 {
4503 return;
4504 }
4505 if ((call->gtCallLateArgs != nullptr) &&
4506 (call->gtCallLateArgs->VisitListOperands(visitor)) == VisitResult::Abort)
4507 {
4508 return;
4509 }
4510 if (call->gtCallType == CT_INDIRECT)
4511 {
4512 if ((call->gtCallCookie != nullptr) && (visitor(call->gtCallCookie) == VisitResult::Abort))
4513 {
4514 return;
4515 }
4516 if ((call->gtCallAddr != nullptr) && (visitor(call->gtCallAddr) == VisitResult::Abort))
4517 {
4518 return;
4519 }
4520 }
4521 if ((call->gtControlExpr != nullptr))
4522 {
4523 visitor(call->gtControlExpr);
4524 }
4525 return;
4526 }
4527
4528 // Binary nodes
4529 default:
4530 assert(this->OperIsBinary());
4531 VisitBinOpOperands<TVisitor>(visitor);
4532 return;
4533 }
4534}
4535
4536template <typename TVisitor>
4537GenTree::VisitResult GenTree::VisitListOperands(TVisitor visitor)
4538{
4539 for (GenTreeArgList* node = this->AsArgList(); node != nullptr; node = node->Rest())
4540 {
4541 if (visitor(node->gtOp1) == VisitResult::Abort)
4542 {
4543 return VisitResult::Abort;
4544 }
4545 }
4546
4547 return VisitResult::Continue;
4548}
4549
4550template <typename TVisitor>
4551void GenTree::VisitBinOpOperands(TVisitor visitor)
4552{
4553 assert(this->OperIsBinary());
4554
4555 GenTreeOp* const op = this->AsOp();
4556
4557 GenTree* const op1 = op->gtOp1;
4558 if ((op1 != nullptr) && (visitor(op1) == VisitResult::Abort))
4559 {
4560 return;
4561 }
4562
4563 GenTree* const op2 = op->gtOp2;
4564 if (op2 != nullptr)
4565 {
4566 visitor(op2);
4567 }
4568}
4569
4570/*****************************************************************************
4571 * operator new
4572 *
4573 * Note that compiler's allocator is an arena allocator that returns memory that is
4574 * not zero-initialized and can contain data from a prior allocation lifetime.
4575 */
4576
4577inline void* __cdecl operator new(size_t sz, Compiler* compiler, CompMemKind cmk)
4578{
4579 return compiler->getAllocator(cmk).allocate<char>(sz);
4580}
4581
4582inline void* __cdecl operator new[](size_t sz, Compiler* compiler, CompMemKind cmk)
4583{
4584 return compiler->getAllocator(cmk).allocate<char>(sz);
4585}
4586
4587inline void* __cdecl operator new(size_t sz, void* p, const jitstd::placement_t& /* syntax_difference */)
4588{
4589 return p;
4590}
4591
4592/*****************************************************************************/
4593
4594#ifdef DEBUG
4595
4596inline void printRegMask(regMaskTP mask)
4597{
4598 printf(REG_MASK_ALL_FMT, mask);
4599}
4600
4601inline char* regMaskToString(regMaskTP mask, Compiler* context)
4602{
4603 const size_t cchRegMask = 24;
4604 char* regmask = new (context, CMK_Unknown) char[cchRegMask];
4605
4606 sprintf_s(regmask, cchRegMask, REG_MASK_ALL_FMT, mask);
4607
4608 return regmask;
4609}
4610
4611inline void printRegMaskInt(regMaskTP mask)
4612{
4613 printf(REG_MASK_INT_FMT, (mask & RBM_ALLINT));
4614}
4615
4616inline char* regMaskIntToString(regMaskTP mask, Compiler* context)
4617{
4618 const size_t cchRegMask = 24;
4619 char* regmask = new (context, CMK_Unknown) char[cchRegMask];
4620
4621 sprintf_s(regmask, cchRegMask, REG_MASK_INT_FMT, (mask & RBM_ALLINT));
4622
4623 return regmask;
4624}
4625
4626#endif // DEBUG
4627
4628inline static bool StructHasOverlappingFields(DWORD attribs)
4629{
4630 return ((attribs & CORINFO_FLG_OVERLAPPING_FIELDS) != 0);
4631}
4632
4633inline static bool StructHasCustomLayout(DWORD attribs)
4634{
4635 return ((attribs & CORINFO_FLG_CUSTOMLAYOUT) != 0);
4636}
4637
4638/*****************************************************************************
4639 * This node should not be referenced by anyone now. Set its values to garbage
4640 * to catch extra references
4641 */
4642
4643inline void DEBUG_DESTROY_NODE(GenTree* tree)
4644{
4645#ifdef DEBUG
4646 // printf("DEBUG_DESTROY_NODE for [0x%08x]\n", tree);
4647
4648 // Save gtOper in case we want to find out what this node was
4649 tree->gtOperSave = tree->gtOper;
4650
4651 tree->gtType = TYP_UNDEF;
4652 tree->gtFlags |= 0xFFFFFFFF & ~GTF_NODE_MASK;
4653 if (tree->OperIsSimple())
4654 {
4655 tree->gtOp.gtOp1 = tree->gtOp.gtOp2 = nullptr;
4656 }
4657 // Must do this last, because the "gtOp" check above will fail otherwise.
4658 // Don't call SetOper, because GT_COUNT is not a valid value
4659 tree->gtOper = GT_COUNT;
4660#endif
4661}
4662
4663//------------------------------------------------------------------------------
4664// lvRefCnt: access reference count for this local var
4665//
4666// Arguments:
4667// state: the requestor's expected ref count state; defaults to RCS_NORMAL
4668//
4669// Return Value:
4670// Ref count for the local.
4671
4672inline unsigned short LclVarDsc::lvRefCnt(RefCountState state) const
4673{
4674
4675#if defined(DEBUG)
4676 assert(state != RCS_INVALID);
4677 Compiler* compiler = JitTls::GetCompiler();
4678 assert(compiler->lvaRefCountState == state);
4679#endif
4680
4681 if (lvImplicitlyReferenced && (m_lvRefCnt == 0))
4682 {
4683 return 1;
4684 }
4685
4686 return m_lvRefCnt;
4687}
4688
4689//------------------------------------------------------------------------------
4690// incLvRefCnt: increment reference count for this local var
4691//
4692// Arguments:
4693// delta: the amount of the increment
4694// state: the requestor's expected ref count state; defaults to RCS_NORMAL
4695//
4696// Notes:
4697// It is currently the caller's responsibilty to ensure this increment
4698// will not cause overflow.
4699
4700inline void LclVarDsc::incLvRefCnt(unsigned short delta, RefCountState state)
4701{
4702
4703#if defined(DEBUG)
4704 assert(state != RCS_INVALID);
4705 Compiler* compiler = JitTls::GetCompiler();
4706 assert(compiler->lvaRefCountState == state);
4707#endif
4708
4709 unsigned short oldRefCnt = m_lvRefCnt;
4710 m_lvRefCnt += delta;
4711 assert(m_lvRefCnt >= oldRefCnt);
4712}
4713
4714//------------------------------------------------------------------------------
4715// setLvRefCnt: set the reference count for this local var
4716//
4717// Arguments:
4718// newValue: the desired new reference count
4719// state: the requestor's expected ref count state; defaults to RCS_NORMAL
4720//
4721// Notes:
4722// Generally after calling v->setLvRefCnt(Y), v->lvRefCnt() == Y.
4723// However this may not be true when v->lvImplicitlyReferenced == 1.
4724
4725inline void LclVarDsc::setLvRefCnt(unsigned short newValue, RefCountState state)
4726{
4727
4728#if defined(DEBUG)
4729 assert(state != RCS_INVALID);
4730 Compiler* compiler = JitTls::GetCompiler();
4731 assert(compiler->lvaRefCountState == state);
4732#endif
4733
4734 m_lvRefCnt = newValue;
4735}
4736
4737//------------------------------------------------------------------------------
4738// lvRefCntWtd: access wighted reference count for this local var
4739//
4740// Arguments:
4741// state: the requestor's expected ref count state; defaults to RCS_NORMAL
4742//
4743// Return Value:
4744// Weighted ref count for the local.
4745
4746inline BasicBlock::weight_t LclVarDsc::lvRefCntWtd(RefCountState state) const
4747{
4748
4749#if defined(DEBUG)
4750 assert(state != RCS_INVALID);
4751 Compiler* compiler = JitTls::GetCompiler();
4752 assert(compiler->lvaRefCountState == state);
4753#endif
4754
4755 if (lvImplicitlyReferenced && (m_lvRefCntWtd == 0))
4756 {
4757 return BB_UNITY_WEIGHT;
4758 }
4759
4760 return m_lvRefCntWtd;
4761}
4762
4763//------------------------------------------------------------------------------
4764// incLvRefCntWtd: increment weighted reference count for this local var
4765//
4766// Arguments:
4767// delta: the amount of the increment
4768// state: the requestor's expected ref count state; defaults to RCS_NORMAL
4769//
4770// Notes:
4771// It is currently the caller's responsibilty to ensure this increment
4772// will not cause overflow.
4773
4774inline void LclVarDsc::incLvRefCntWtd(BasicBlock::weight_t delta, RefCountState state)
4775{
4776
4777#if defined(DEBUG)
4778 assert(state != RCS_INVALID);
4779 Compiler* compiler = JitTls::GetCompiler();
4780 assert(compiler->lvaRefCountState == state);
4781#endif
4782
4783 BasicBlock::weight_t oldRefCntWtd = m_lvRefCntWtd;
4784 m_lvRefCntWtd += delta;
4785 assert(m_lvRefCntWtd >= oldRefCntWtd);
4786}
4787
4788//------------------------------------------------------------------------------
4789// setLvRefCntWtd: set the weighted reference count for this local var
4790//
4791// Arguments:
4792// newValue: the desired new weighted reference count
4793// state: the requestor's expected ref count state; defaults to RCS_NORMAL
4794//
4795// Notes:
4796// Generally after calling v->setLvRefCntWtd(Y), v->lvRefCntWtd() == Y.
4797// However this may not be true when v->lvImplicitlyReferenced == 1.
4798
4799inline void LclVarDsc::setLvRefCntWtd(BasicBlock::weight_t newValue, RefCountState state)
4800{
4801
4802#if defined(DEBUG)
4803 assert(state != RCS_INVALID);
4804 Compiler* compiler = JitTls::GetCompiler();
4805 assert(compiler->lvaRefCountState == state);
4806#endif
4807
4808 m_lvRefCntWtd = newValue;
4809}
4810
4811/*****************************************************************************/
4812#endif //_COMPILER_HPP_
4813/*****************************************************************************/
4814