Merge pull request #19748 from briansull/evalop-specialized
[platform/upstream/coreclr.git] / src / jit / valuenum.cpp
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
6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7 XX                                                                           XX
8 XX                           ValueNum                                        XX
9 XX                                                                           XX
10 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
12 */
13
14 #include "jitpch.h"
15 #ifdef _MSC_VER
16 #pragma hdrstop
17 #endif
18
19 #include "valuenum.h"
20 #include "ssaconfig.h"
21
22 // Windows x86 and Windows ARM/ARM64 may not define _isnanf() but they do define _isnan().
23 // We will redirect the macros to these other functions if the macro is not defined for the
24 // platform. This has the side effect of a possible implicit upcasting for arguments passed.
25 #if (defined(_TARGET_X86_) || defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)) && !defined(FEATURE_PAL)
26
27 #if !defined(_isnanf)
28 #define _isnanf _isnan
29 #endif
30
31 #endif // (defined(_TARGET_X86_) || defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)) && !defined(FEATURE_PAL)
32
33 // We need to use target-specific NaN values when statically compute expressions.
34 // Otherwise, cross crossgen (e.g. x86_arm) would have different binary outputs
35 // from native crossgen (i.e. arm_arm) when the NaN got "embedded" into code.
36 //
37 // For example, when placing NaN value in r3 register
38 // x86_arm crossgen would emit
39 //   movw    r3, 0x00
40 //   movt    r3, 0xfff8
41 // while arm_arm crossgen (and JIT) output is
42 //   movw    r3, 0x00
43 //   movt    r3, 0x7ff8
44
45 struct FloatTraits
46 {
47     //------------------------------------------------------------------------
48     // NaN: Return target-specific float NaN value
49     //
50     // Notes:
51     //    "Default" NaN value returned by expression 0.0f / 0.0f on x86/x64 has
52     //    different binary representation (0xffc00000) than NaN on
53     //    ARM32/ARM64 (0x7fc00000).
54
55     static float NaN()
56     {
57 #if defined(_TARGET_XARCH_)
58         unsigned bits = 0xFFC00000u;
59 #elif defined(_TARGET_ARMARCH_)
60         unsigned           bits = 0x7FC00000u;
61 #else
62 #error Unsupported or unset target architecture
63 #endif
64         float result;
65         static_assert(sizeof(bits) == sizeof(result), "sizeof(unsigned) must equal sizeof(float)");
66         memcpy(&result, &bits, sizeof(result));
67         return result;
68     }
69 };
70
71 struct DoubleTraits
72 {
73     //------------------------------------------------------------------------
74     // NaN: Return target-specific double NaN value
75     //
76     // Notes:
77     //    "Default" NaN value returned by expression 0.0 / 0.0 on x86/x64 has
78     //    different binary representation (0xfff8000000000000) than NaN on
79     //    ARM32/ARM64 (0x7ff8000000000000).
80
81     static double NaN()
82     {
83 #if defined(_TARGET_XARCH_)
84         unsigned long long bits = 0xFFF8000000000000ull;
85 #elif defined(_TARGET_ARMARCH_)
86         unsigned long long bits = 0x7FF8000000000000ull;
87 #else
88 #error Unsupported or unset target architecture
89 #endif
90         double result;
91         static_assert(sizeof(bits) == sizeof(result), "sizeof(unsigned long long) must equal sizeof(double)");
92         memcpy(&result, &bits, sizeof(result));
93         return result;
94     }
95 };
96
97 //------------------------------------------------------------------------
98 // FpAdd: Computes value1 + value2
99 //
100 // Return Value:
101 //    TFpTraits::NaN() - If target ARM32/ARM64 and result value is NaN
102 //    value1 + value2  - Otherwise
103 //
104 // Notes:
105 //    See FloatTraits::NaN() and DoubleTraits::NaN() notes.
106
107 template <typename TFp, typename TFpTraits>
108 TFp FpAdd(TFp value1, TFp value2)
109 {
110 #ifdef _TARGET_ARMARCH_
111     // If [value1] is negative infinity and [value2] is positive infinity
112     //   the result is NaN.
113     // If [value1] is positive infinity and [value2] is negative infinity
114     //   the result is NaN.
115
116     if (!_finite(value1) && !_finite(value2))
117     {
118         if (value1 < 0 && value2 > 0)
119         {
120             return TFpTraits::NaN();
121         }
122
123         if (value1 > 0 && value2 < 0)
124         {
125             return TFpTraits::NaN();
126         }
127     }
128 #endif // _TARGET_ARMARCH_
129
130     return value1 + value2;
131 }
132
133 //------------------------------------------------------------------------
134 // FpSub: Computes value1 - value2
135 //
136 // Return Value:
137 //    TFpTraits::NaN() - If target ARM32/ARM64 and result value is NaN
138 //    value1 - value2  - Otherwise
139 //
140 // Notes:
141 //    See FloatTraits::NaN() and DoubleTraits::NaN() notes.
142
143 template <typename TFp, typename TFpTraits>
144 TFp FpSub(TFp value1, TFp value2)
145 {
146 #ifdef _TARGET_ARMARCH_
147     // If [value1] is positive infinity and [value2] is positive infinity
148     //   the result is NaN.
149     // If [value1] is negative infinity and [value2] is negative infinity
150     //   the result is NaN.
151
152     if (!_finite(value1) && !_finite(value2))
153     {
154         if (value1 > 0 && value2 > 0)
155         {
156             return TFpTraits::NaN();
157         }
158
159         if (value1 < 0 && value2 < 0)
160         {
161             return TFpTraits::NaN();
162         }
163     }
164 #endif // _TARGET_ARMARCH_
165
166     return value1 - value2;
167 }
168
169 //------------------------------------------------------------------------
170 // FpMul: Computes value1 * value2
171 //
172 // Return Value:
173 //    TFpTraits::NaN() - If target ARM32/ARM64 and result value is NaN
174 //    value1 * value2  - Otherwise
175 //
176 // Notes:
177 //    See FloatTraits::NaN() and DoubleTraits::NaN() notes.
178
179 template <typename TFp, typename TFpTraits>
180 TFp FpMul(TFp value1, TFp value2)
181 {
182 #ifdef _TARGET_ARMARCH_
183     // From the ECMA standard:
184     //
185     // If [value1] is zero and [value2] is infinity
186     //   the result is NaN.
187     // If [value1] is infinity and [value2] is zero
188     //   the result is NaN.
189
190     if (value1 == 0 && !_finite(value2) && !_isnan(value2))
191     {
192         return TFpTraits::NaN();
193     }
194     if (!_finite(value1) && !_isnan(value1) && value2 == 0)
195     {
196         return TFpTraits::NaN();
197     }
198 #endif // _TARGET_ARMARCH_
199
200     return value1 * value2;
201 }
202
203 //------------------------------------------------------------------------
204 // FpDiv: Computes value1 / value2
205 //
206 // Return Value:
207 //    TFpTraits::NaN() - If target ARM32/ARM64 and result value is NaN
208 //    value1 / value2  - Otherwise
209 //
210 // Notes:
211 //    See FloatTraits::NaN() and DoubleTraits::NaN() notes.
212
213 template <typename TFp, typename TFpTraits>
214 TFp FpDiv(TFp dividend, TFp divisor)
215 {
216 #ifdef _TARGET_ARMARCH_
217     // From the ECMA standard:
218     //
219     // If [dividend] is zero and [divisor] is zero
220     //   the result is NaN.
221     // If [dividend] is infinity and [divisor] is infinity
222     //   the result is NaN.
223
224     if (dividend == 0 && divisor == 0)
225     {
226         return TFpTraits::NaN();
227     }
228     else if (!_finite(dividend) && !_isnan(dividend) && !_finite(divisor) && !_isnan(divisor))
229     {
230         return TFpTraits::NaN();
231     }
232 #endif // _TARGET_ARMARCH_
233
234     return dividend / divisor;
235 }
236
237 template <typename TFp, typename TFpTraits>
238 TFp FpRem(TFp dividend, TFp divisor)
239 {
240     // From the ECMA standard:
241     //
242     // If [divisor] is zero or [dividend] is infinity
243     //   the result is NaN.
244     // If [divisor] is infinity,
245     //   the result is [dividend]
246
247     if (divisor == 0 || !_finite(dividend))
248     {
249         return TFpTraits::NaN();
250     }
251     else if (!_finite(divisor) && !_isnan(divisor))
252     {
253         return dividend;
254     }
255
256     return (TFp)fmod((double)dividend, (double)divisor);
257 }
258
259 VNFunc GetVNFuncForOper(genTreeOps oper, bool isUnsigned)
260 {
261     if (!isUnsigned || (oper == GT_EQ) || (oper == GT_NE))
262     {
263         return VNFunc(oper);
264     }
265     switch (oper)
266     {
267         case GT_LT:
268             return VNF_LT_UN;
269         case GT_LE:
270             return VNF_LE_UN;
271         case GT_GE:
272             return VNF_GE_UN;
273         case GT_GT:
274             return VNF_GT_UN;
275         case GT_ADD:
276             return VNF_ADD_UN;
277         case GT_SUB:
278             return VNF_SUB_UN;
279         case GT_MUL:
280             return VNF_MUL_UN;
281
282         case GT_NOP:
283         case GT_COMMA:
284             return VNFunc(oper);
285         default:
286             unreached();
287     }
288 }
289
290 ValueNumStore::ValueNumStore(Compiler* comp, CompAllocator alloc)
291     : m_pComp(comp)
292     , m_alloc(alloc)
293     , m_nextChunkBase(0)
294     , m_fixedPointMapSels(alloc, 8)
295     , m_checkedBoundVNs(alloc)
296     , m_chunks(alloc, 8)
297     , m_intCnsMap(nullptr)
298     , m_longCnsMap(nullptr)
299     , m_handleMap(nullptr)
300     , m_floatCnsMap(nullptr)
301     , m_doubleCnsMap(nullptr)
302     , m_byrefCnsMap(nullptr)
303     , m_VNFunc0Map(nullptr)
304     , m_VNFunc1Map(nullptr)
305     , m_VNFunc2Map(nullptr)
306     , m_VNFunc3Map(nullptr)
307     , m_VNFunc4Map(nullptr)
308 #ifdef DEBUG
309     , m_numMapSels(0)
310 #endif
311 {
312     // We have no current allocation chunks.
313     for (unsigned i = 0; i < TYP_COUNT; i++)
314     {
315         for (unsigned j = CEA_None; j <= CEA_Count + MAX_LOOP_NUM; j++)
316         {
317             m_curAllocChunk[i][j] = NoChunk;
318         }
319     }
320
321     for (unsigned i = 0; i < SmallIntConstNum; i++)
322     {
323         m_VNsForSmallIntConsts[i] = NoVN;
324     }
325     // We will reserve chunk 0 to hold some special constants, like the constant NULL, the "exception" value, and the
326     // "zero map."
327     Chunk* specialConstChunk = new (m_alloc) Chunk(m_alloc, &m_nextChunkBase, TYP_REF, CEA_Const, MAX_LOOP_NUM);
328     specialConstChunk->m_numUsed +=
329         SRC_NumSpecialRefConsts; // Implicitly allocate 0 ==> NULL, and 1 ==> Exception, 2 ==> ZeroMap.
330     ChunkNum cn = m_chunks.Push(specialConstChunk);
331     assert(cn == 0);
332
333     m_mapSelectBudget = (int)JitConfig.JitVNMapSelBudget(); // We cast the unsigned DWORD to a signed int.
334
335     // This value must be non-negative and non-zero, reset the value to DEFAULT_MAP_SELECT_BUDGET if it isn't.
336     if (m_mapSelectBudget <= 0)
337     {
338         m_mapSelectBudget = DEFAULT_MAP_SELECT_BUDGET;
339     }
340 }
341
342 unsigned ValueNumStore::VNFuncArity(VNFunc vnf)
343 {
344     // Read the bit field out of the table...
345     return (s_vnfOpAttribs[vnf] & VNFOA_ArityMask) >> VNFOA_ArityShift;
346 }
347
348 template <>
349 bool ValueNumStore::IsOverflowIntDiv(int v0, int v1)
350 {
351     return (v1 == -1) && (v0 == INT32_MIN);
352 }
353 template <>
354 bool ValueNumStore::IsOverflowIntDiv(INT64 v0, INT64 v1)
355 {
356     return (v1 == -1) && (v0 == INT64_MIN);
357 }
358 template <typename T>
359 bool ValueNumStore::IsOverflowIntDiv(T v0, T v1)
360 {
361     return false;
362 }
363
364 template <>
365 bool ValueNumStore::IsIntZero(int v)
366 {
367     return v == 0;
368 }
369 template <>
370 bool ValueNumStore::IsIntZero(unsigned v)
371 {
372     return v == 0;
373 }
374 template <>
375 bool ValueNumStore::IsIntZero(INT64 v)
376 {
377     return v == 0;
378 }
379 template <>
380 bool ValueNumStore::IsIntZero(UINT64 v)
381 {
382     return v == 0;
383 }
384 template <typename T>
385 bool ValueNumStore::IsIntZero(T v)
386 {
387     return false;
388 }
389
390 //
391 // Unary EvalOp
392 //
393
394 template <typename T>
395 T ValueNumStore::EvalOp(VNFunc vnf, T v0)
396 {
397     genTreeOps oper = genTreeOps(vnf);
398
399     // Here we handle unary ops that are the same for all types.
400     switch (oper)
401     {
402         case GT_NEG:
403             // Note that GT_NEG is the only valid unary floating point operation
404             return -v0;
405
406         default:
407             break;
408     }
409
410     // Otherwise must be handled by the type specific method
411     return EvalOpSpecialized(vnf, v0);
412 }
413
414 template <>
415 double ValueNumStore::EvalOpSpecialized<double>(VNFunc vnf, double v0)
416 {
417     // Here we handle specialized double unary ops.
418     noway_assert(!"EvalOpSpecialized<double> - unary");
419     return 0.0;
420 }
421
422 template <>
423 float ValueNumStore::EvalOpSpecialized<float>(VNFunc vnf, float v0)
424 {
425     // Here we handle specialized float unary ops.
426     noway_assert(!"EvalOpSpecialized<float> - unary");
427     return 0.0f;
428 }
429
430 template <typename T>
431 T ValueNumStore::EvalOpSpecialized(VNFunc vnf, T v0)
432 {
433     if (vnf < VNF_Boundary)
434     {
435         genTreeOps oper = genTreeOps(vnf);
436
437         switch (oper)
438         {
439             case GT_NEG:
440                 return -v0;
441
442             case GT_NOT:
443                 return ~v0;
444
445             default:
446                 break;
447         }
448     }
449
450     noway_assert(!"Unhandled operation in EvalOpSpecialized<T> - unary");
451     return v0;
452 }
453
454 //
455 // Binary EvalOp
456 //
457
458 template <typename T>
459 T ValueNumStore::EvalOp(VNFunc vnf, T v0, T v1, ValueNum* pExcSet)
460 {
461     // Here we handle the binary ops that are the same for all types.
462
463     if (vnf < VNF_Boundary)
464     {
465         genTreeOps oper = genTreeOps(vnf);
466
467         // Temporary will be removed
468         switch (oper)
469         {
470             case GT_DIV:
471             case GT_MOD:
472                 if (IsOverflowIntDiv(v0, v1))
473                 {
474                     *pExcSet = VNExcSetSingleton(VNForFunc(TYP_REF, VNF_ArithmeticExc));
475                     return 0;
476                 }
477
478                 __fallthrough;
479
480             case GT_UDIV:
481             case GT_UMOD:
482                 if (IsIntZero(v1))
483                 {
484                     *pExcSet = VNExcSetSingleton(VNForFunc(TYP_REF, VNF_DivideByZeroExc));
485                     return 0;
486                 }
487
488                 __fallthrough;
489
490             default:
491                 break;
492         }
493     }
494
495     // Otherwise must be handled by the type specific method
496     return EvalOpSpecialized(vnf, v0, v1);
497 }
498
499 template <>
500 double ValueNumStore::EvalOpSpecialized<double>(VNFunc vnf, double v0, double v1)
501 {
502     // Here we handle specialized double binary ops.
503     if (vnf < VNF_Boundary)
504     {
505         genTreeOps oper = genTreeOps(vnf);
506
507         // Here we handle
508         switch (oper)
509         {
510             case GT_ADD:
511                 return FpAdd<double, DoubleTraits>(v0, v1);
512             case GT_SUB:
513                 return FpSub<double, DoubleTraits>(v0, v1);
514             case GT_MUL:
515                 return FpMul<double, DoubleTraits>(v0, v1);
516             case GT_DIV:
517                 return FpDiv<double, DoubleTraits>(v0, v1);
518             case GT_MOD:
519                 return FpRem<double, DoubleTraits>(v0, v1);
520
521             default:
522                 // For any other value of 'oper', we will assert below
523                 break;
524         }
525     }
526
527     noway_assert(!"EvalOpSpecialized<double> - binary");
528     return v0;
529 }
530
531 template <>
532 float ValueNumStore::EvalOpSpecialized<float>(VNFunc vnf, float v0, float v1)
533 {
534     // Here we handle specialized float binary ops.
535     if (vnf < VNF_Boundary)
536     {
537         genTreeOps oper = genTreeOps(vnf);
538
539         // Here we handle
540         switch (oper)
541         {
542             case GT_ADD:
543                 return FpAdd<float, FloatTraits>(v0, v1);
544             case GT_SUB:
545                 return FpSub<float, FloatTraits>(v0, v1);
546             case GT_MUL:
547                 return FpMul<float, FloatTraits>(v0, v1);
548             case GT_DIV:
549                 return FpDiv<float, FloatTraits>(v0, v1);
550             case GT_MOD:
551                 return FpRem<float, FloatTraits>(v0, v1);
552
553             default:
554                 // For any other value of 'oper', we will assert below
555                 break;
556         }
557     }
558     assert(!"EvalOpSpecialized<float> - binary");
559     return v0;
560 }
561
562 template <typename T>
563 T ValueNumStore::EvalOpSpecialized(VNFunc vnf, T v0, T v1)
564 {
565     typedef typename jitstd::make_unsigned<T>::type UT;
566
567     assert((sizeof(T) == 4) || (sizeof(T) == 8));
568
569     // Here we handle binary ops that are the same for all integer types
570     if (vnf < VNF_Boundary)
571     {
572         genTreeOps oper = genTreeOps(vnf);
573
574         switch (oper)
575         {
576             case GT_ADD:
577                 return v0 + v1;
578             case GT_SUB:
579                 return v0 - v1;
580             case GT_MUL:
581                 return v0 * v1;
582
583             case GT_DIV:
584                 assert(IsIntZero(v1) == false);
585                 assert(IsOverflowIntDiv(v0, v1) == false);
586                 return v0 / v1;
587
588             case GT_MOD:
589                 assert(IsIntZero(v1) == false);
590                 assert(IsOverflowIntDiv(v0, v1) == false);
591                 return v0 % v1;
592
593             case GT_UDIV:
594                 assert(IsIntZero(v1) == false);
595                 return T(UT(v0) / UT(v1));
596
597             case GT_UMOD:
598                 assert(IsIntZero(v1) == false);
599                 return T(UT(v0) % UT(v1));
600
601             case GT_AND:
602                 return v0 & v1;
603             case GT_OR:
604                 return v0 | v1;
605             case GT_XOR:
606                 return v0 ^ v1;
607
608             case GT_LSH:
609                 if (sizeof(T) == 8)
610                 {
611                     return v0 << (v1 & 0x3F);
612                 }
613                 else
614                 {
615                     return v0 << v1;
616                 }
617             case GT_RSH:
618                 if (sizeof(T) == 8)
619                 {
620                     return v0 >> (v1 & 0x3F);
621                 }
622                 else
623                 {
624                     return v0 >> v1;
625                 }
626             case GT_RSZ:
627                 if (sizeof(T) == 8)
628                 {
629                     return UINT64(v0) >> (v1 & 0x3F);
630                 }
631                 else
632                 {
633                     return UINT32(v0) >> v1;
634                 }
635             case GT_ROL:
636                 if (sizeof(T) == 8)
637                 {
638                     return (v0 << v1) | (UINT64(v0) >> (64 - v1));
639                 }
640                 else
641                 {
642                     return (v0 << v1) | (UINT32(v0) >> (32 - v1));
643                 }
644
645             case GT_ROR:
646                 if (sizeof(T) == 8)
647                 {
648                     return (v0 << (64 - v1)) | (UINT64(v0) >> v1);
649                 }
650                 else
651                 {
652                     return (v0 << (32 - v1)) | (UINT32(v0) >> v1);
653                 }
654
655             default:
656                 // For any other value of 'oper', we will assert below
657                 break;
658         }
659     }
660     else // must be a VNF_ function
661     {
662         switch (vnf)
663         {
664             // Here we handle those that are the same for all integer types.
665
666             case VNF_ADD_UN:
667                 return T(UT(v0) + UT(v1));
668             case VNF_SUB_UN:
669                 return T(UT(v0) - UT(v1));
670             case VNF_MUL_UN:
671                 return T(UT(v0) * UT(v1));
672
673             default:
674                 // For any other value of 'vnf', we will assert below
675                 break;
676         }
677     }
678
679     noway_assert(!"Unhandled operation in EvalOpSpecialized<T> - binary");
680     return v0;
681 }
682
683 template <>
684 int ValueNumStore::EvalComparison<double>(VNFunc vnf, double v0, double v1)
685 {
686     // Here we handle specialized double comparisons.
687
688     // We must check for a NaN argument as they they need special handling
689     bool hasNanArg = (_isnan(v0) || _isnan(v1));
690
691     if (vnf < VNF_Boundary)
692     {
693         genTreeOps oper = genTreeOps(vnf);
694
695         if (hasNanArg)
696         {
697             // return false in all cases except for GT_NE;
698             return (oper == GT_NE);
699         }
700
701         switch (oper)
702         {
703             case GT_EQ:
704                 return v0 == v1;
705             case GT_NE:
706                 return v0 != v1;
707             case GT_GT:
708                 return v0 > v1;
709             case GT_GE:
710                 return v0 >= v1;
711             case GT_LT:
712                 return v0 < v1;
713             case GT_LE:
714                 return v0 <= v1;
715             default:
716                 // For any other value of 'oper', we will assert below
717                 break;
718         }
719     }
720     noway_assert(!"Unhandled operation in EvalComparison<double>");
721     return 0;
722 }
723
724 template <>
725 int ValueNumStore::EvalComparison<float>(VNFunc vnf, float v0, float v1)
726 {
727     // Here we handle specialized float comparisons.
728
729     // We must check for a NaN argument as they they need special handling
730     bool hasNanArg = (_isnanf(v0) || _isnanf(v1));
731
732     if (vnf < VNF_Boundary)
733     {
734         genTreeOps oper = genTreeOps(vnf);
735
736         if (hasNanArg)
737         {
738             // return false in all cases except for GT_NE;
739             return (oper == GT_NE);
740         }
741
742         switch (oper)
743         {
744             case GT_EQ:
745                 return v0 == v1;
746             case GT_NE:
747                 return v0 != v1;
748             case GT_GT:
749                 return v0 > v1;
750             case GT_GE:
751                 return v0 >= v1;
752             case GT_LT:
753                 return v0 < v1;
754             case GT_LE:
755                 return v0 <= v1;
756             default:
757                 // For any other value of 'oper', we will assert below
758                 break;
759         }
760     }
761     else // must be a VNF_ function
762     {
763         if (hasNanArg)
764         {
765             // always returns true
766             return false;
767         }
768
769         switch (vnf)
770         {
771             case VNF_GT_UN:
772                 return v0 > v1;
773             case VNF_GE_UN:
774                 return v0 >= v1;
775             case VNF_LT_UN:
776                 return v0 < v1;
777             case VNF_LE_UN:
778                 return v0 <= v1;
779             default:
780                 // For any other value of 'vnf', we will assert below
781                 break;
782         }
783     }
784     noway_assert(!"Unhandled operation in EvalComparison<float>");
785     return 0;
786 }
787
788 template <typename T>
789 int ValueNumStore::EvalComparison(VNFunc vnf, T v0, T v1)
790 {
791     typedef typename jitstd::make_unsigned<T>::type UT;
792
793     // Here we handle the compare ops that are the same for all integer types.
794     if (vnf < VNF_Boundary)
795     {
796         genTreeOps oper = genTreeOps(vnf);
797         switch (oper)
798         {
799             case GT_EQ:
800                 return v0 == v1;
801             case GT_NE:
802                 return v0 != v1;
803             case GT_GT:
804                 return v0 > v1;
805             case GT_GE:
806                 return v0 >= v1;
807             case GT_LT:
808                 return v0 < v1;
809             case GT_LE:
810                 return v0 <= v1;
811             default:
812                 // For any other value of 'oper', we will assert below
813                 break;
814         }
815     }
816     else // must be a VNF_ function
817     {
818         switch (vnf)
819         {
820             case VNF_GT_UN:
821                 return T(UT(v0) > UT(v1));
822             case VNF_GE_UN:
823                 return T(UT(v0) >= UT(v1));
824             case VNF_LT_UN:
825                 return T(UT(v0) < UT(v1));
826             case VNF_LE_UN:
827                 return T(UT(v0) <= UT(v1));
828             default:
829                 // For any other value of 'vnf', we will assert below
830                 break;
831         }
832     }
833     noway_assert(!"Unhandled operation in EvalComparison<T>");
834     return 0;
835 }
836
837 // Create a ValueNum for an exception set singleton for 'x'
838 //
839 ValueNum ValueNumStore::VNExcSetSingleton(ValueNum x)
840 {
841     return VNForFunc(TYP_REF, VNF_ExcSetCons, x, VNForEmptyExcSet());
842 }
843 // Create a ValueNumPair for an exception set singleton for 'xp'
844 //
845 ValueNumPair ValueNumStore::VNPExcSetSingleton(ValueNumPair xp)
846 {
847     return ValueNumPair(VNExcSetSingleton(xp.GetLiberal()), VNExcSetSingleton(xp.GetConservative()));
848 }
849
850 ValueNum ValueNumStore::VNExcSetUnion(ValueNum xs0, ValueNum xs1 DEBUGARG(bool topLevel))
851 {
852     if (xs0 == VNForEmptyExcSet())
853     {
854         return xs1;
855     }
856     else if (xs1 == VNForEmptyExcSet())
857     {
858         return xs0;
859     }
860     else
861     {
862         VNFuncApp funcXs0;
863         bool      b0 = GetVNFunc(xs0, &funcXs0);
864         assert(b0 && funcXs0.m_func == VNF_ExcSetCons); // Precondition: xs0 is an exception set.
865         VNFuncApp funcXs1;
866         bool      b1 = GetVNFunc(xs1, &funcXs1);
867         assert(b1 && funcXs1.m_func == VNF_ExcSetCons); // Precondition: xs1 is an exception set.
868         ValueNum res = NoVN;
869         if (funcXs0.m_args[0] < funcXs1.m_args[0])
870         {
871             res = VNForFunc(TYP_REF, VNF_ExcSetCons, funcXs0.m_args[0],
872                             VNExcSetUnion(funcXs0.m_args[1], xs1 DEBUGARG(false)));
873         }
874         else if (funcXs0.m_args[0] == funcXs1.m_args[0])
875         {
876             // Equal elements; only add one to the result.
877             res = VNExcSetUnion(funcXs0.m_args[1], xs1);
878         }
879         else
880         {
881             assert(funcXs0.m_args[0] > funcXs1.m_args[0]);
882             res = VNForFunc(TYP_REF, VNF_ExcSetCons, funcXs1.m_args[0],
883                             VNExcSetUnion(xs0, funcXs1.m_args[1] DEBUGARG(false)));
884         }
885
886         return res;
887     }
888 }
889
890 ValueNumPair ValueNumStore::VNPExcSetUnion(ValueNumPair xs0vnp, ValueNumPair xs1vnp)
891 {
892     return ValueNumPair(VNExcSetUnion(xs0vnp.GetLiberal(), xs1vnp.GetLiberal()),
893                         VNExcSetUnion(xs0vnp.GetConservative(), xs1vnp.GetConservative()));
894 }
895
896 void ValueNumStore::VNUnpackExc(ValueNum vnWx, ValueNum* pvn, ValueNum* pvnx)
897 {
898     assert(vnWx != NoVN);
899     VNFuncApp funcApp;
900     if (GetVNFunc(vnWx, &funcApp) && funcApp.m_func == VNF_ValWithExc)
901     {
902         *pvn  = funcApp.m_args[0];
903         *pvnx = funcApp.m_args[1];
904     }
905     else
906     {
907         *pvn = vnWx;
908     }
909 }
910
911 void ValueNumStore::VNPUnpackExc(ValueNumPair vnWx, ValueNumPair* pvn, ValueNumPair* pvnx)
912 {
913     VNUnpackExc(vnWx.GetLiberal(), pvn->GetLiberalAddr(), pvnx->GetLiberalAddr());
914     VNUnpackExc(vnWx.GetConservative(), pvn->GetConservativeAddr(), pvnx->GetConservativeAddr());
915 }
916
917 //--------------------------------------------------------------------------------
918 // VNNormVal:    - Returns a Value Number that represents the result for the
919 //                 normal (non-exceptional) evaluation for the expression.
920 //
921 // Arguments:
922 //    vn         - The Value Number for the expression, including any  excSet.
923 //                 This excSet is an optional item and represents the set of
924 //                 possible exceptions for the expression.
925 //
926 // Return Value:
927 //               - The Value Number for the expression without the exception set.
928 //                 This can be the orginal 'vn', when there are no exceptions.
929 //
930 // Notes:        - Whenever we have an exception set the Value Number will be
931 //                 a VN func with VNF_ValWithExc.
932 //                 This VN func has the normal value as m_args[0]
933 //
934 ValueNum ValueNumStore::VNNormVal(ValueNum vn)
935 {
936     VNFuncApp funcApp;
937     if (GetVNFunc(vn, &funcApp) && funcApp.m_func == VNF_ValWithExc)
938     {
939         return funcApp.m_args[0];
940     }
941     else
942     {
943         return vn;
944     }
945 }
946
947 //--------------------------------------------------------------------------------
948 // VNPNormVal:   - Returns a Value Number Pair that represents the result for the
949 //                 normal (non-exceptional) evaluation for the expression.
950 //                 (see VNNormVal for more details)
951 //
952 // Notes:        = This method is used to form a Value Number Pair when we
953 //                 want both the Liberal and Conservative Value NUmbers
954 //
955 ValueNumPair ValueNumStore::VNPNormVal(ValueNumPair vnp)
956 {
957     return ValueNumPair(VNNormVal(vnp.GetLiberal()), VNNormVal(vnp.GetConservative()));
958 }
959
960 //---------------------------------------------------------------------------
961 // VNExcVal:     - Returns a Value Number that represents the set of possible
962 //                 exceptions that could be encountered for the expression.
963 //
964 // Arguments:
965 //    vn         - The Value Number for the expression, including any excSet.
966 //                 This excSet is an optional item and represents the set of
967 //                 possible exceptions for the expression.
968 //
969 // Return Value:
970 //               - The Value Number for the set of exceptions of the expression.
971 //                 If the 'vn' has no exception set then a special Value Number
972 //                 representing the empty exception set is returned.
973 //
974 // Notes:        - Whenever we have an exception set the Value Number will be
975 //                 a VN func with VNF_ValWithExc.
976 //                 This VN func has the exception set as m_args[1]
977 //
978 ValueNum ValueNumStore::VNExcVal(ValueNum vn)
979 {
980     VNFuncApp funcApp;
981     if (GetVNFunc(vn, &funcApp) && funcApp.m_func == VNF_ValWithExc)
982     {
983         return funcApp.m_args[1];
984     }
985     else
986     {
987         return VNForEmptyExcSet();
988     }
989 }
990
991 //--------------------------------------------------------------------------------
992 // VNPExcVal:    - Returns a Value Number Pair that represents the set of possible
993 //                 exceptions that could be encountered for the expression.
994 //                 (see VNExcVal for more details)
995 //
996 // Notes:        = This method is used to form a Value Number Pair when we
997 //                 want both the Liberal and Conservative Value NUmbers
998 //
999 ValueNumPair ValueNumStore::VNPExcVal(ValueNumPair vnp)
1000 {
1001     return ValueNumPair(VNExcVal(vnp.GetLiberal()), VNExcVal(vnp.GetConservative()));
1002 }
1003
1004 //---------------------------------------------------------------------------
1005 // VNWithExc:    - Returns a Value Number that also can have both a normal value
1006 //                 as well as am exception set.
1007 //
1008 // Arguments:
1009 //    vn         - The current Value Number for the expression, it may include
1010 //                 an exception set.
1011 //    excSet     - The Value Number representing the new exception set that
1012 //                 is to be added to any exceptions already present in 'vn'
1013 //
1014 // Return Value:
1015 //               - The new Value Number for the combination the two inputs.
1016 //                 If the 'excSet' is the special Value Number representing
1017 //                 the empty exception set then 'vn' is returned.
1018 //
1019 // Notes:        - We use a Set Union operation, 'VNExcSetUnion', to add any
1020 //                 new exception items from  'excSet' to the existing set.
1021 //
1022 ValueNum ValueNumStore::VNWithExc(ValueNum vn, ValueNum excSet)
1023 {
1024     if (excSet == VNForEmptyExcSet())
1025     {
1026         return vn;
1027     }
1028     else
1029     {
1030         ValueNum vnNorm;
1031         ValueNum vnX = VNForEmptyExcSet();
1032         VNUnpackExc(vn, &vnNorm, &vnX);
1033         return VNForFunc(TypeOfVN(vnNorm), VNF_ValWithExc, vnNorm, VNExcSetUnion(vnX, excSet));
1034     }
1035 }
1036
1037 //--------------------------------------------------------------------------------
1038 // VNPWithExc:   - Returns a Value Number Pair that also can have both a normal value
1039 //                 as well as am exception set.
1040 //                 (see VNWithExc for more details)
1041 //
1042 // Notes:        = This method is used to form a Value Number Pair when we
1043 //                 want both the Liberal and Conservative Value NUmbers
1044 //
1045 ValueNumPair ValueNumStore::VNPWithExc(ValueNumPair vnp, ValueNumPair excSetVNP)
1046 {
1047     return ValueNumPair(VNWithExc(vnp.GetLiberal(), excSetVNP.GetLiberal()),
1048                         VNWithExc(vnp.GetConservative(), excSetVNP.GetConservative()));
1049 }
1050
1051 bool ValueNumStore::IsKnownNonNull(ValueNum vn)
1052 {
1053     if (vn == NoVN)
1054     {
1055         return false;
1056     }
1057     VNFuncApp funcAttr;
1058     return GetVNFunc(vn, &funcAttr) && (s_vnfOpAttribs[funcAttr.m_func] & VNFOA_KnownNonNull) != 0;
1059 }
1060
1061 bool ValueNumStore::IsSharedStatic(ValueNum vn)
1062 {
1063     if (vn == NoVN)
1064     {
1065         return false;
1066     }
1067     VNFuncApp funcAttr;
1068     return GetVNFunc(vn, &funcAttr) && (s_vnfOpAttribs[funcAttr.m_func] & VNFOA_SharedStatic) != 0;
1069 }
1070
1071 ValueNumStore::Chunk::Chunk(CompAllocator          alloc,
1072                             ValueNum*              pNextBaseVN,
1073                             var_types              typ,
1074                             ChunkExtraAttribs      attribs,
1075                             BasicBlock::loopNumber loopNum)
1076     : m_defs(nullptr), m_numUsed(0), m_baseVN(*pNextBaseVN), m_typ(typ), m_attribs(attribs), m_loopNum(loopNum)
1077 {
1078     // Allocate "m_defs" here, according to the typ/attribs pair.
1079     switch (attribs)
1080     {
1081         case CEA_None:
1082         case CEA_NotAField:
1083             break; // Nothing to do.
1084         case CEA_Const:
1085             switch (typ)
1086             {
1087                 case TYP_INT:
1088                     m_defs = new (alloc) Alloc<TYP_INT>::Type[ChunkSize];
1089                     break;
1090                 case TYP_FLOAT:
1091                     m_defs = new (alloc) Alloc<TYP_FLOAT>::Type[ChunkSize];
1092                     break;
1093                 case TYP_LONG:
1094                     m_defs = new (alloc) Alloc<TYP_LONG>::Type[ChunkSize];
1095                     break;
1096                 case TYP_DOUBLE:
1097                     m_defs = new (alloc) Alloc<TYP_DOUBLE>::Type[ChunkSize];
1098                     break;
1099                 case TYP_BYREF:
1100                     m_defs = new (alloc) Alloc<TYP_BYREF>::Type[ChunkSize];
1101                     break;
1102                 case TYP_REF:
1103                     // We allocate space for a single REF constant, NULL, so we can access these values uniformly.
1104                     // Since this value is always the same, we represent it as a static.
1105                     m_defs = &s_specialRefConsts[0];
1106                     break; // Nothing to do.
1107                 default:
1108                     assert(false); // Should not reach here.
1109             }
1110             break;
1111
1112         case CEA_Handle:
1113             m_defs = new (alloc) VNHandle[ChunkSize];
1114             break;
1115
1116         case CEA_Func0:
1117             m_defs = new (alloc) VNFunc[ChunkSize];
1118             break;
1119
1120         case CEA_Func1:
1121             m_defs = new (alloc) VNDefFunc1Arg[ChunkSize];
1122             break;
1123         case CEA_Func2:
1124             m_defs = new (alloc) VNDefFunc2Arg[ChunkSize];
1125             break;
1126         case CEA_Func3:
1127             m_defs = new (alloc) VNDefFunc3Arg[ChunkSize];
1128             break;
1129         case CEA_Func4:
1130             m_defs = new (alloc) VNDefFunc4Arg[ChunkSize];
1131             break;
1132         default:
1133             unreached();
1134     }
1135     *pNextBaseVN += ChunkSize;
1136 }
1137
1138 ValueNumStore::Chunk* ValueNumStore::GetAllocChunk(var_types              typ,
1139                                                    ChunkExtraAttribs      attribs,
1140                                                    BasicBlock::loopNumber loopNum)
1141 {
1142     Chunk*   res;
1143     unsigned index;
1144     if (loopNum == MAX_LOOP_NUM)
1145     {
1146         // Loop nest is unknown/irrelevant for this VN.
1147         index = attribs;
1148     }
1149     else
1150     {
1151         // Loop nest is interesting.  Since we know this is only true for unique VNs, we know attribs will
1152         // be CEA_None and can just index based on loop number.
1153         noway_assert(attribs == CEA_None);
1154         // Map NOT_IN_LOOP -> MAX_LOOP_NUM to make the index range contiguous [0..MAX_LOOP_NUM]
1155         index = CEA_Count + (loopNum == BasicBlock::NOT_IN_LOOP ? MAX_LOOP_NUM : loopNum);
1156     }
1157     ChunkNum cn = m_curAllocChunk[typ][index];
1158     if (cn != NoChunk)
1159     {
1160         res = m_chunks.Get(cn);
1161         if (res->m_numUsed < ChunkSize)
1162         {
1163             return res;
1164         }
1165     }
1166     // Otherwise, must allocate a new one.
1167     res                         = new (m_alloc) Chunk(m_alloc, &m_nextChunkBase, typ, attribs, loopNum);
1168     cn                          = m_chunks.Push(res);
1169     m_curAllocChunk[typ][index] = cn;
1170     return res;
1171 }
1172
1173 ValueNum ValueNumStore::VNForIntCon(INT32 cnsVal)
1174 {
1175     if (IsSmallIntConst(cnsVal))
1176     {
1177         unsigned ind = cnsVal - SmallIntConstMin;
1178         ValueNum vn  = m_VNsForSmallIntConsts[ind];
1179         if (vn != NoVN)
1180         {
1181             return vn;
1182         }
1183         vn                          = GetVNForIntCon(cnsVal);
1184         m_VNsForSmallIntConsts[ind] = vn;
1185         return vn;
1186     }
1187     else
1188     {
1189         return GetVNForIntCon(cnsVal);
1190     }
1191 }
1192
1193 ValueNum ValueNumStore::VNForLongCon(INT64 cnsVal)
1194 {
1195     ValueNum res;
1196     if (GetLongCnsMap()->Lookup(cnsVal, &res))
1197     {
1198         return res;
1199     }
1200     else
1201     {
1202         Chunk*   c                                             = GetAllocChunk(TYP_LONG, CEA_Const);
1203         unsigned offsetWithinChunk                             = c->AllocVN();
1204         res                                                    = c->m_baseVN + offsetWithinChunk;
1205         reinterpret_cast<INT64*>(c->m_defs)[offsetWithinChunk] = cnsVal;
1206         GetLongCnsMap()->Set(cnsVal, res);
1207         return res;
1208     }
1209 }
1210
1211 ValueNum ValueNumStore::VNForFloatCon(float cnsVal)
1212 {
1213     ValueNum res;
1214     if (GetFloatCnsMap()->Lookup(cnsVal, &res))
1215     {
1216         return res;
1217     }
1218     else
1219     {
1220         Chunk*   c                                             = GetAllocChunk(TYP_FLOAT, CEA_Const);
1221         unsigned offsetWithinChunk                             = c->AllocVN();
1222         res                                                    = c->m_baseVN + offsetWithinChunk;
1223         reinterpret_cast<float*>(c->m_defs)[offsetWithinChunk] = cnsVal;
1224         GetFloatCnsMap()->Set(cnsVal, res);
1225         return res;
1226     }
1227 }
1228
1229 ValueNum ValueNumStore::VNForDoubleCon(double cnsVal)
1230 {
1231     ValueNum res;
1232     if (GetDoubleCnsMap()->Lookup(cnsVal, &res))
1233     {
1234         return res;
1235     }
1236     else
1237     {
1238         Chunk*   c                                              = GetAllocChunk(TYP_DOUBLE, CEA_Const);
1239         unsigned offsetWithinChunk                              = c->AllocVN();
1240         res                                                     = c->m_baseVN + offsetWithinChunk;
1241         reinterpret_cast<double*>(c->m_defs)[offsetWithinChunk] = cnsVal;
1242         GetDoubleCnsMap()->Set(cnsVal, res);
1243         return res;
1244     }
1245 }
1246
1247 ValueNum ValueNumStore::VNForByrefCon(INT64 cnsVal)
1248 {
1249     ValueNum res;
1250     if (GetByrefCnsMap()->Lookup(cnsVal, &res))
1251     {
1252         return res;
1253     }
1254     else
1255     {
1256         Chunk*   c                                             = GetAllocChunk(TYP_BYREF, CEA_Const);
1257         unsigned offsetWithinChunk                             = c->AllocVN();
1258         res                                                    = c->m_baseVN + offsetWithinChunk;
1259         reinterpret_cast<INT64*>(c->m_defs)[offsetWithinChunk] = cnsVal;
1260         GetByrefCnsMap()->Set(cnsVal, res);
1261         return res;
1262     }
1263 }
1264
1265 ValueNum ValueNumStore::VNForCastOper(var_types castToType, bool srcIsUnsigned /*=false*/)
1266 {
1267     assert(castToType != TYP_STRUCT);
1268     INT32 cnsVal = INT32(castToType) << INT32(VCA_BitCount);
1269     assert((cnsVal & INT32(VCA_ReservedBits)) == 0);
1270
1271     if (srcIsUnsigned)
1272     {
1273         // We record the srcIsUnsigned by or-ing a 0x01
1274         cnsVal |= INT32(VCA_UnsignedSrc);
1275     }
1276     ValueNum result = VNForIntCon(cnsVal);
1277
1278 #ifdef DEBUG
1279     if (m_pComp->verbose)
1280     {
1281         printf("    VNForCastOper(%s%s) is " FMT_VN "\n", varTypeName(castToType), srcIsUnsigned ? ", unsignedSrc" : "",
1282                result);
1283     }
1284 #endif
1285
1286     return result;
1287 }
1288
1289 ValueNum ValueNumStore::VNForHandle(ssize_t cnsVal, unsigned handleFlags)
1290 {
1291     assert((handleFlags & ~GTF_ICON_HDL_MASK) == 0);
1292
1293     ValueNum res;
1294     VNHandle handle;
1295     VNHandle::Initialize(&handle, cnsVal, handleFlags);
1296     if (GetHandleMap()->Lookup(handle, &res))
1297     {
1298         return res;
1299     }
1300     else
1301     {
1302         Chunk*   c                                                = GetAllocChunk(TYP_I_IMPL, CEA_Handle);
1303         unsigned offsetWithinChunk                                = c->AllocVN();
1304         res                                                       = c->m_baseVN + offsetWithinChunk;
1305         reinterpret_cast<VNHandle*>(c->m_defs)[offsetWithinChunk] = handle;
1306         GetHandleMap()->Set(handle, res);
1307         return res;
1308     }
1309 }
1310
1311 // Returns the value number for zero of the given "typ".
1312 // It has an unreached() for a "typ" that has no zero value, such as TYP_VOID.
1313 ValueNum ValueNumStore::VNZeroForType(var_types typ)
1314 {
1315     switch (typ)
1316     {
1317         case TYP_BOOL:
1318         case TYP_BYTE:
1319         case TYP_UBYTE:
1320         case TYP_SHORT:
1321         case TYP_USHORT:
1322         case TYP_INT:
1323         case TYP_UINT:
1324             return VNForIntCon(0);
1325         case TYP_LONG:
1326         case TYP_ULONG:
1327             return VNForLongCon(0);
1328         case TYP_FLOAT:
1329             return VNForFloatCon(0.0f);
1330         case TYP_DOUBLE:
1331             return VNForDoubleCon(0.0);
1332         case TYP_REF:
1333             return VNForNull();
1334         case TYP_BYREF:
1335             return VNForByrefCon(0);
1336         case TYP_STRUCT:
1337 #ifdef FEATURE_SIMD
1338         // TODO-CQ: Improve value numbering for SIMD types.
1339         case TYP_SIMD8:
1340         case TYP_SIMD12:
1341         case TYP_SIMD16:
1342         case TYP_SIMD32:
1343 #endif                             // FEATURE_SIMD
1344             return VNForZeroMap(); // Recursion!
1345
1346         // These should be unreached.
1347         default:
1348             unreached(); // Should handle all types.
1349     }
1350 }
1351
1352 // Returns the value number for one of the given "typ".
1353 // It returns NoVN for a "typ" that has no one value, such as TYP_REF.
1354 ValueNum ValueNumStore::VNOneForType(var_types typ)
1355 {
1356     switch (typ)
1357     {
1358         case TYP_BOOL:
1359         case TYP_BYTE:
1360         case TYP_UBYTE:
1361         case TYP_SHORT:
1362         case TYP_USHORT:
1363         case TYP_INT:
1364         case TYP_UINT:
1365             return VNForIntCon(1);
1366         case TYP_LONG:
1367         case TYP_ULONG:
1368             return VNForLongCon(1);
1369         case TYP_FLOAT:
1370             return VNForFloatCon(1.0f);
1371         case TYP_DOUBLE:
1372             return VNForDoubleCon(1.0);
1373
1374         default:
1375             return NoVN;
1376     }
1377 }
1378
1379 class Object* ValueNumStore::s_specialRefConsts[] = {nullptr, nullptr, nullptr};
1380
1381 // Nullary operators (i.e., symbolic constants).
1382 ValueNum ValueNumStore::VNForFunc(var_types typ, VNFunc func)
1383 {
1384     assert(VNFuncArity(func) == 0);
1385     assert(func != VNF_NotAField);
1386
1387     ValueNum res;
1388
1389     if (GetVNFunc0Map()->Lookup(func, &res))
1390     {
1391         return res;
1392     }
1393     else
1394     {
1395         Chunk*   c                                              = GetAllocChunk(typ, CEA_Func0);
1396         unsigned offsetWithinChunk                              = c->AllocVN();
1397         res                                                     = c->m_baseVN + offsetWithinChunk;
1398         reinterpret_cast<VNFunc*>(c->m_defs)[offsetWithinChunk] = func;
1399         GetVNFunc0Map()->Set(func, res);
1400         return res;
1401     }
1402 }
1403
1404 ValueNum ValueNumStore::VNForFunc(var_types typ, VNFunc func, ValueNum arg0VN)
1405 {
1406     assert(arg0VN == VNNormVal(arg0VN)); // Arguments don't carry exceptions.
1407
1408     ValueNum      res;
1409     VNDefFunc1Arg fstruct(func, arg0VN);
1410
1411     // Do constant-folding.
1412     if (CanEvalForConstantArgs(func) && IsVNConstant(arg0VN))
1413     {
1414         return EvalFuncForConstantArgs(typ, func, arg0VN);
1415     }
1416
1417     if (GetVNFunc1Map()->Lookup(fstruct, &res))
1418     {
1419         return res;
1420     }
1421     else
1422     {
1423         // Otherwise, create a new VN for this application.
1424         Chunk*   c                                                     = GetAllocChunk(typ, CEA_Func1);
1425         unsigned offsetWithinChunk                                     = c->AllocVN();
1426         res                                                            = c->m_baseVN + offsetWithinChunk;
1427         reinterpret_cast<VNDefFunc1Arg*>(c->m_defs)[offsetWithinChunk] = fstruct;
1428         GetVNFunc1Map()->Set(fstruct, res);
1429         return res;
1430     }
1431 }
1432
1433 // Windows x86 and Windows ARM/ARM64 may not define _isnanf() but they do define _isnan().
1434 // We will redirect the macros to these other functions if the macro is not defined for the
1435 // platform. This has the side effect of a possible implicit upcasting for arguments passed.
1436 #if (defined(_TARGET_X86_) || defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)) && !defined(FEATURE_PAL)
1437
1438 #if !defined(_isnanf)
1439 #define _isnanf _isnan
1440 #endif
1441
1442 #endif
1443
1444 ValueNum ValueNumStore::VNForFunc(var_types typ, VNFunc func, ValueNum arg0VN, ValueNum arg1VN)
1445 {
1446     assert(arg0VN != NoVN && arg1VN != NoVN);
1447     assert(arg0VN == VNNormVal(arg0VN)); // Arguments carry no exceptions.
1448     assert(arg1VN == VNNormVal(arg1VN)); // Arguments carry no exceptions.
1449     assert(VNFuncArity(func) == 2);
1450     assert(func != VNF_MapSelect); // Precondition: use the special function VNForMapSelect defined for that.
1451
1452     ValueNum res;
1453
1454     // Do constant-folding.
1455     if (CanEvalForConstantArgs(func) && IsVNConstant(arg0VN) && IsVNConstant(arg1VN))
1456     {
1457         bool canFold = true; // Normally we will be able to fold this 'func'
1458
1459         // Special case for VNF_Cast of constant handles
1460         // Don't allow eval/fold of a GT_CAST(non-I_IMPL, Handle)
1461         //
1462         if ((func == VNF_Cast) && (typ != TYP_I_IMPL) && IsVNHandle(arg0VN))
1463         {
1464             canFold = false;
1465         }
1466
1467         // It is possible for us to have mismatched types (see Bug 750863)
1468         // We don't try to fold a binary operation when one of the constant operands
1469         // is a floating-point constant and the other is not.
1470         //
1471         var_types arg0VNtyp      = TypeOfVN(arg0VN);
1472         bool      arg0IsFloating = varTypeIsFloating(arg0VNtyp);
1473
1474         var_types arg1VNtyp      = TypeOfVN(arg1VN);
1475         bool      arg1IsFloating = varTypeIsFloating(arg1VNtyp);
1476
1477         if (arg0IsFloating != arg1IsFloating)
1478         {
1479             canFold = false;
1480         }
1481
1482         // NaNs are unordered wrt to other floats. While an ordered
1483         // comparison would return false, an unordered comparison
1484         // will return true if any operands are a NaN. We only perform
1485         // ordered NaN comparison in EvalComparison.
1486         if ((arg0IsFloating && (((arg0VNtyp == TYP_FLOAT) && _isnanf(GetConstantSingle(arg0VN))) ||
1487                                 ((arg0VNtyp == TYP_DOUBLE) && _isnan(GetConstantDouble(arg0VN))))) ||
1488             (arg1IsFloating && (((arg1VNtyp == TYP_FLOAT) && _isnanf(GetConstantSingle(arg1VN))) ||
1489                                 ((arg1VNtyp == TYP_DOUBLE) && _isnan(GetConstantDouble(arg1VN))))))
1490         {
1491             canFold = false;
1492         }
1493         if (typ == TYP_BYREF)
1494         {
1495             // We don't want to fold expressions that produce TYP_BYREF
1496             canFold = false;
1497         }
1498
1499         if (canFold)
1500         {
1501             return EvalFuncForConstantArgs(typ, func, arg0VN, arg1VN);
1502         }
1503     }
1504     // We canonicalize commutative operations.
1505     // (Perhaps should eventually handle associative/commutative [AC] ops -- but that gets complicated...)
1506     if (VNFuncIsCommutative(func))
1507     {
1508         // Order arg0 arg1 by numerical VN value.
1509         if (arg0VN > arg1VN)
1510         {
1511             jitstd::swap(arg0VN, arg1VN);
1512         }
1513     }
1514     VNDefFunc2Arg fstruct(func, arg0VN, arg1VN);
1515     if (GetVNFunc2Map()->Lookup(fstruct, &res))
1516     {
1517         return res;
1518     }
1519     else
1520     {
1521         // We have ways of evaluating some binary functions.
1522         if (func < VNF_Boundary)
1523         {
1524             if (typ != TYP_BYREF) // We don't want/need to optimize a zero byref
1525             {
1526                 ValueNum resultVN = NoVN;
1527                 ValueNum ZeroVN, OneVN; // We may need to create one of these in the switch below.
1528                 switch (genTreeOps(func))
1529                 {
1530                     case GT_ADD:
1531                         // This identity does not apply for floating point (when x == -0.0)
1532                         // (x + 0) == (0 + x) => x
1533                         ZeroVN = VNZeroForType(typ);
1534                         if (VNIsEqual(arg0VN, ZeroVN))
1535                         {
1536                             resultVN = arg1VN;
1537                         }
1538                         else if (VNIsEqual(arg1VN, ZeroVN))
1539                         {
1540                             resultVN = arg0VN;
1541                         }
1542                         break;
1543
1544                     case GT_SUB:
1545                         // This identity does not apply for floating point (when x == -0.0)
1546                         // (x - 0) => x
1547                         // (x - x) => 0
1548                         ZeroVN = VNZeroForType(typ);
1549                         if (VNIsEqual(arg1VN, ZeroVN))
1550                         {
1551                             resultVN = arg0VN;
1552                         }
1553                         else if (VNIsEqual(arg0VN, arg1VN))
1554                         {
1555                             resultVN = ZeroVN;
1556                         }
1557                         break;
1558
1559                     case GT_MUL:
1560                         // (x * 1) == (1 * x) => x
1561                         OneVN = VNOneForType(typ);
1562                         if (OneVN != NoVN)
1563                         {
1564                             if (arg0VN == OneVN)
1565                             {
1566                                 resultVN = arg1VN;
1567                             }
1568                             else if (arg1VN == OneVN)
1569                             {
1570                                 resultVN = arg0VN;
1571                             }
1572                         }
1573
1574                         if (!varTypeIsFloating(typ))
1575                         {
1576                             // (x * 0) == (0 * x) => 0 (unless x is NaN, which we must assume a fp value may be)
1577                             ZeroVN = VNZeroForType(typ);
1578                             if (arg0VN == ZeroVN)
1579                             {
1580                                 resultVN = ZeroVN;
1581                             }
1582                             else if (arg1VN == ZeroVN)
1583                             {
1584                                 resultVN = ZeroVN;
1585                             }
1586                         }
1587                         break;
1588
1589                     case GT_DIV:
1590                     case GT_UDIV:
1591                         // (x / 1) => x
1592                         OneVN = VNOneForType(typ);
1593                         if (OneVN != NoVN)
1594                         {
1595                             if (arg1VN == OneVN)
1596                             {
1597                                 resultVN = arg0VN;
1598                             }
1599                         }
1600                         break;
1601
1602                     case GT_OR:
1603                     case GT_XOR:
1604                         // (x | 0) == (0 | x) => x
1605                         // (x ^ 0) == (0 ^ x) => x
1606                         ZeroVN = VNZeroForType(typ);
1607                         if (arg0VN == ZeroVN)
1608                         {
1609                             resultVN = arg1VN;
1610                         }
1611                         else if (arg1VN == ZeroVN)
1612                         {
1613                             resultVN = arg0VN;
1614                         }
1615                         break;
1616
1617                     case GT_AND:
1618                         // (x & 0) == (0 & x) => 0
1619                         ZeroVN = VNZeroForType(typ);
1620                         if (arg0VN == ZeroVN)
1621                         {
1622                             resultVN = ZeroVN;
1623                         }
1624                         else if (arg1VN == ZeroVN)
1625                         {
1626                             resultVN = ZeroVN;
1627                         }
1628                         break;
1629
1630                     case GT_LSH:
1631                     case GT_RSH:
1632                     case GT_RSZ:
1633                     case GT_ROL:
1634                     case GT_ROR:
1635                         // (x << 0) => x
1636                         // (x >> 0) => x
1637                         // (x rol 0) => x
1638                         // (x ror 0) => x
1639                         ZeroVN = VNZeroForType(typ);
1640                         if (arg1VN == ZeroVN)
1641                         {
1642                             resultVN = arg0VN;
1643                         }
1644                         break;
1645
1646                     case GT_EQ:
1647                     case GT_GE:
1648                     case GT_LE:
1649                         // (x == x) => true (unless x is NaN)
1650                         // (x <= x) => true (unless x is NaN)
1651                         // (x >= x) => true (unless x is NaN)
1652                         if (VNIsEqual(arg0VN, arg1VN))
1653                         {
1654                             resultVN = VNOneForType(typ);
1655                         }
1656                         if ((arg0VN == VNForNull() && IsKnownNonNull(arg1VN)) ||
1657                             (arg1VN == VNForNull() && IsKnownNonNull(arg0VN)))
1658                         {
1659                             resultVN = VNZeroForType(typ);
1660                         }
1661                         break;
1662
1663                     case GT_NE:
1664                     case GT_GT:
1665                     case GT_LT:
1666                         // (x != x) => false (unless x is NaN)
1667                         // (x > x) => false (unless x is NaN)
1668                         // (x < x) => false (unless x is NaN)
1669                         if (VNIsEqual(arg0VN, arg1VN))
1670                         {
1671                             resultVN = VNZeroForType(typ);
1672                         }
1673                         if ((arg0VN == VNForNull() && IsKnownNonNull(arg1VN)) ||
1674                             (arg1VN == VNForNull() && IsKnownNonNull(arg0VN)))
1675                         {
1676                             resultVN = VNOneForType(typ);
1677                         }
1678                         break;
1679
1680                     default:
1681                         break;
1682                 }
1683
1684                 if ((resultVN != NoVN) && (TypeOfVN(resultVN) == typ))
1685                 {
1686                     return resultVN;
1687                 }
1688             }
1689         }
1690         else // must be a VNF_ function
1691         {
1692             if (VNIsEqual(arg0VN, arg1VN))
1693             {
1694                 // x <= x ==> true
1695                 // x >= x ==> true
1696                 if ((func == VNF_LE_UN) || (func == VNF_GE_UN))
1697                 {
1698                     return VNOneForType(typ);
1699                 }
1700                 // x < x ==> false
1701                 // x > x ==> false
1702                 // x - x ==> 0
1703                 else if ((func == VNF_LT_UN) || (func == VNF_GT_UN) || (func == VNF_SUB_UN))
1704                 {
1705                     return VNZeroForType(typ);
1706                 }
1707             }
1708
1709             if (func == VNF_CastClass)
1710             {
1711                 // In terms of values, a castclass always returns its second argument, the object being cast.
1712                 // The IL operation may also throw an exception
1713                 return VNWithExc(arg1VN, VNExcSetSingleton(VNForFunc(TYP_REF, VNF_InvalidCastExc, arg1VN, arg0VN)));
1714             }
1715         }
1716
1717         // Otherwise, assign a new VN for the function application.
1718         Chunk*   c                                                     = GetAllocChunk(typ, CEA_Func2);
1719         unsigned offsetWithinChunk                                     = c->AllocVN();
1720         res                                                            = c->m_baseVN + offsetWithinChunk;
1721         reinterpret_cast<VNDefFunc2Arg*>(c->m_defs)[offsetWithinChunk] = fstruct;
1722         GetVNFunc2Map()->Set(fstruct, res);
1723         return res;
1724     }
1725 }
1726
1727 //------------------------------------------------------------------------------
1728 // VNForMapStore : Evaluate VNF_MapStore with the given arguments.
1729 //
1730 //
1731 // Arguments:
1732 //    typ  -    Value type
1733 //    arg0VN  - Map value number
1734 //    arg1VN  - Index value number
1735 //    arg2VN  - New value for map[index]
1736 //
1737 // Return Value:
1738 //    Value number for the result of the evaluation.
1739
1740 ValueNum ValueNumStore::VNForMapStore(var_types typ, ValueNum arg0VN, ValueNum arg1VN, ValueNum arg2VN)
1741 {
1742     ValueNum result = VNForFunc(typ, VNF_MapStore, arg0VN, arg1VN, arg2VN);
1743 #ifdef DEBUG
1744     if (m_pComp->verbose)
1745     {
1746         printf("    VNForMapStore(" FMT_VN ", " FMT_VN ", " FMT_VN "):%s returns ", arg0VN, arg1VN, arg2VN,
1747                varTypeName(typ));
1748         m_pComp->vnPrint(result, 1);
1749         printf("\n");
1750     }
1751 #endif
1752     return result;
1753 }
1754
1755 //------------------------------------------------------------------------------
1756 // VNForMapSelect : Evaluate VNF_MapSelect with the given arguments.
1757 //
1758 //
1759 // Arguments:
1760 //    vnk  -    Value number kind
1761 //    typ  -    Value type
1762 //    arg0VN  - Map value number
1763 //    arg1VN  - Index value number
1764 //
1765 // Return Value:
1766 //    Value number for the result of the evaluation.
1767 //
1768 // Notes:
1769 //    This requires a "ValueNumKind" because it will attempt, given "select(phi(m1, ..., mk), ind)", to evaluate
1770 //    "select(m1, ind)", ..., "select(mk, ind)" to see if they agree.  It needs to know which kind of value number
1771 //    (liberal/conservative) to read from the SSA def referenced in the phi argument.
1772
1773 ValueNum ValueNumStore::VNForMapSelect(ValueNumKind vnk, var_types typ, ValueNum arg0VN, ValueNum arg1VN)
1774 {
1775     int      budget          = m_mapSelectBudget;
1776     bool     usedRecursiveVN = false;
1777     ValueNum result          = VNForMapSelectWork(vnk, typ, arg0VN, arg1VN, &budget, &usedRecursiveVN);
1778
1779     // The remaining budget should always be between [0..m_mapSelectBudget]
1780     assert((budget >= 0) && (budget <= m_mapSelectBudget));
1781
1782 #ifdef DEBUG
1783     if (m_pComp->verbose)
1784     {
1785         printf("    VNForMapSelect(" FMT_VN ", " FMT_VN "):%s returns ", arg0VN, arg1VN, varTypeName(typ));
1786         m_pComp->vnPrint(result, 1);
1787         printf("\n");
1788     }
1789 #endif
1790     return result;
1791 }
1792
1793 //------------------------------------------------------------------------------
1794 // VNForMapSelectWork : A method that does the work for VNForMapSelect and may call itself recursively.
1795 //
1796 //
1797 // Arguments:
1798 //    vnk  -             Value number kind
1799 //    typ  -             Value type
1800 //    arg0VN  -          Zeroth argument
1801 //    arg1VN  -          First argument
1802 //    pBudget -          Remaining budget for the outer evaluation
1803 //    pUsedRecursiveVN - Out-parameter that is set to true iff RecursiveVN was returned from this method
1804 //                       or from a method called during one of recursive invocations.
1805 //
1806 // Return Value:
1807 //    Value number for the result of the evaluation.
1808 //
1809 // Notes:
1810 //    This requires a "ValueNumKind" because it will attempt, given "select(phi(m1, ..., mk), ind)", to evaluate
1811 //    "select(m1, ind)", ..., "select(mk, ind)" to see if they agree.  It needs to know which kind of value number
1812 //    (liberal/conservative) to read from the SSA def referenced in the phi argument.
1813
1814 ValueNum ValueNumStore::VNForMapSelectWork(
1815     ValueNumKind vnk, var_types typ, ValueNum arg0VN, ValueNum arg1VN, int* pBudget, bool* pUsedRecursiveVN)
1816 {
1817 TailCall:
1818     // This label allows us to directly implement a tail call by setting up the arguments, and doing a goto to here.
1819     assert(arg0VN != NoVN && arg1VN != NoVN);
1820     assert(arg0VN == VNNormVal(arg0VN)); // Arguments carry no exceptions.
1821     assert(arg1VN == VNNormVal(arg1VN)); // Arguments carry no exceptions.
1822
1823     *pUsedRecursiveVN = false;
1824
1825 #ifdef DEBUG
1826     // Provide a mechanism for writing tests that ensure we don't call this ridiculously often.
1827     m_numMapSels++;
1828 #if 1
1829 // This printing is sometimes useful in debugging.
1830 // if ((m_numMapSels % 1000) == 0) printf("%d VNF_MapSelect applications.\n", m_numMapSels);
1831 #endif
1832     unsigned selLim = JitConfig.JitVNMapSelLimit();
1833     assert(selLim == 0 || m_numMapSels < selLim);
1834 #endif
1835     ValueNum res;
1836
1837     VNDefFunc2Arg fstruct(VNF_MapSelect, arg0VN, arg1VN);
1838     if (GetVNFunc2Map()->Lookup(fstruct, &res))
1839     {
1840         return res;
1841     }
1842     else
1843     {
1844
1845         // Give up if we've run out of budget.
1846         if (--(*pBudget) <= 0)
1847         {
1848             // We have to use 'nullptr' for the basic block here, because subsequent expressions
1849             // in different blocks may find this result in the VNFunc2Map -- other expressions in
1850             // the IR may "evaluate" to this same VNForExpr, so it is not "unique" in the sense
1851             // that permits the BasicBlock attribution.
1852             res = VNForExpr(nullptr, typ);
1853             GetVNFunc2Map()->Set(fstruct, res);
1854             return res;
1855         }
1856
1857         // If it's recursive, stop the recursion.
1858         if (SelectIsBeingEvaluatedRecursively(arg0VN, arg1VN))
1859         {
1860             *pUsedRecursiveVN = true;
1861             return RecursiveVN;
1862         }
1863
1864         if (arg0VN == VNForZeroMap())
1865         {
1866             return VNZeroForType(typ);
1867         }
1868         else if (IsVNFunc(arg0VN))
1869         {
1870             VNFuncApp funcApp;
1871             GetVNFunc(arg0VN, &funcApp);
1872             if (funcApp.m_func == VNF_MapStore)
1873             {
1874                 // select(store(m, i, v), i) == v
1875                 if (funcApp.m_args[1] == arg1VN)
1876                 {
1877 #if FEATURE_VN_TRACE_APPLY_SELECTORS
1878                     JITDUMP("      AX1: select([" FMT_VN "]store(" FMT_VN ", " FMT_VN ", " FMT_VN "), " FMT_VN
1879                             ") ==> " FMT_VN ".\n",
1880                             funcApp.m_args[0], arg0VN, funcApp.m_args[1], funcApp.m_args[2], arg1VN, funcApp.m_args[2]);
1881 #endif
1882                     return funcApp.m_args[2];
1883                 }
1884                 // i # j ==> select(store(m, i, v), j) == select(m, j)
1885                 // Currently the only source of distinctions is when both indices are constants.
1886                 else if (IsVNConstant(arg1VN) && IsVNConstant(funcApp.m_args[1]))
1887                 {
1888                     assert(funcApp.m_args[1] != arg1VN); // we already checked this above.
1889 #if FEATURE_VN_TRACE_APPLY_SELECTORS
1890                     JITDUMP("      AX2: " FMT_VN " != " FMT_VN " ==> select([" FMT_VN "]store(" FMT_VN ", " FMT_VN
1891                             ", " FMT_VN "), " FMT_VN ") ==> select(" FMT_VN ", " FMT_VN ").\n",
1892                             arg1VN, funcApp.m_args[1], arg0VN, funcApp.m_args[0], funcApp.m_args[1], funcApp.m_args[2],
1893                             arg1VN, funcApp.m_args[0], arg1VN);
1894 #endif
1895                     // This is the equivalent of the recursive tail call:
1896                     // return VNForMapSelect(vnk, typ, funcApp.m_args[0], arg1VN);
1897                     // Make sure we capture any exceptions from the "i" and "v" of the store...
1898                     arg0VN = funcApp.m_args[0];
1899                     goto TailCall;
1900                 }
1901             }
1902             else if (funcApp.m_func == VNF_PhiDef || funcApp.m_func == VNF_PhiMemoryDef)
1903             {
1904                 unsigned  lclNum   = BAD_VAR_NUM;
1905                 bool      isMemory = false;
1906                 VNFuncApp phiFuncApp;
1907                 bool      defArgIsFunc = false;
1908                 if (funcApp.m_func == VNF_PhiDef)
1909                 {
1910                     lclNum       = unsigned(funcApp.m_args[0]);
1911                     defArgIsFunc = GetVNFunc(funcApp.m_args[2], &phiFuncApp);
1912                 }
1913                 else
1914                 {
1915                     assert(funcApp.m_func == VNF_PhiMemoryDef);
1916                     isMemory     = true;
1917                     defArgIsFunc = GetVNFunc(funcApp.m_args[1], &phiFuncApp);
1918                 }
1919                 if (defArgIsFunc && phiFuncApp.m_func == VNF_Phi)
1920                 {
1921                     // select(phi(m1, m2), x): if select(m1, x) == select(m2, x), return that, else new fresh.
1922                     // Get the first argument of the phi.
1923
1924                     // We need to be careful about breaking infinite recursion.  Record the outer select.
1925                     m_fixedPointMapSels.Push(VNDefFunc2Arg(VNF_MapSelect, arg0VN, arg1VN));
1926
1927                     assert(IsVNConstant(phiFuncApp.m_args[0]));
1928                     unsigned phiArgSsaNum = ConstantValue<unsigned>(phiFuncApp.m_args[0]);
1929                     ValueNum phiArgVN;
1930                     if (isMemory)
1931                     {
1932                         phiArgVN = m_pComp->GetMemoryPerSsaData(phiArgSsaNum)->m_vnPair.Get(vnk);
1933                     }
1934                     else
1935                     {
1936                         phiArgVN = m_pComp->lvaTable[lclNum].GetPerSsaData(phiArgSsaNum)->m_vnPair.Get(vnk);
1937                     }
1938                     if (phiArgVN != ValueNumStore::NoVN)
1939                     {
1940                         bool     allSame = true;
1941                         ValueNum argRest = phiFuncApp.m_args[1];
1942                         ValueNum sameSelResult =
1943                             VNForMapSelectWork(vnk, typ, phiArgVN, arg1VN, pBudget, pUsedRecursiveVN);
1944
1945                         // It is possible that we just now exceeded our budget, if so we need to force an early exit
1946                         // and stop calling VNForMapSelectWork
1947                         if (*pBudget <= 0)
1948                         {
1949                             // We don't have any budget remaining to verify that all phiArgs are the same
1950                             // so setup the default failure case now.
1951                             allSame = false;
1952                         }
1953
1954                         while (allSame && argRest != ValueNumStore::NoVN)
1955                         {
1956                             ValueNum  cur = argRest;
1957                             VNFuncApp phiArgFuncApp;
1958                             if (GetVNFunc(argRest, &phiArgFuncApp) && phiArgFuncApp.m_func == VNF_Phi)
1959                             {
1960                                 cur     = phiArgFuncApp.m_args[0];
1961                                 argRest = phiArgFuncApp.m_args[1];
1962                             }
1963                             else
1964                             {
1965                                 argRest = ValueNumStore::NoVN; // Cause the loop to terminate.
1966                             }
1967                             assert(IsVNConstant(cur));
1968                             phiArgSsaNum = ConstantValue<unsigned>(cur);
1969                             if (isMemory)
1970                             {
1971                                 phiArgVN = m_pComp->GetMemoryPerSsaData(phiArgSsaNum)->m_vnPair.Get(vnk);
1972                             }
1973                             else
1974                             {
1975                                 phiArgVN = m_pComp->lvaTable[lclNum].GetPerSsaData(phiArgSsaNum)->m_vnPair.Get(vnk);
1976                             }
1977                             if (phiArgVN == ValueNumStore::NoVN)
1978                             {
1979                                 allSame = false;
1980                             }
1981                             else
1982                             {
1983                                 bool     usedRecursiveVN = false;
1984                                 ValueNum curResult =
1985                                     VNForMapSelectWork(vnk, typ, phiArgVN, arg1VN, pBudget, &usedRecursiveVN);
1986                                 *pUsedRecursiveVN |= usedRecursiveVN;
1987                                 if (sameSelResult == ValueNumStore::RecursiveVN)
1988                                 {
1989                                     sameSelResult = curResult;
1990                                 }
1991                                 if (curResult != ValueNumStore::RecursiveVN && curResult != sameSelResult)
1992                                 {
1993                                     allSame = false;
1994                                 }
1995                             }
1996                         }
1997                         if (allSame && sameSelResult != ValueNumStore::RecursiveVN)
1998                         {
1999                             // Make sure we're popping what we pushed.
2000                             assert(FixedPointMapSelsTopHasValue(arg0VN, arg1VN));
2001                             m_fixedPointMapSels.Pop();
2002
2003                             // To avoid exponential searches, we make sure that this result is memo-ized.
2004                             // The result is always valid for memoization if we didn't rely on RecursiveVN to get it.
2005                             // If RecursiveVN was used, we are processing a loop and we can't memo-ize this intermediate
2006                             // result if, e.g., this block is in a multi-entry loop.
2007                             if (!*pUsedRecursiveVN)
2008                             {
2009                                 GetVNFunc2Map()->Set(fstruct, sameSelResult);
2010                             }
2011
2012                             return sameSelResult;
2013                         }
2014                         // Otherwise, fall through to creating the select(phi(m1, m2), x) function application.
2015                     }
2016                     // Make sure we're popping what we pushed.
2017                     assert(FixedPointMapSelsTopHasValue(arg0VN, arg1VN));
2018                     m_fixedPointMapSels.Pop();
2019                 }
2020             }
2021         }
2022
2023         // Otherwise, assign a new VN for the function application.
2024         Chunk*   c                                                     = GetAllocChunk(typ, CEA_Func2);
2025         unsigned offsetWithinChunk                                     = c->AllocVN();
2026         res                                                            = c->m_baseVN + offsetWithinChunk;
2027         reinterpret_cast<VNDefFunc2Arg*>(c->m_defs)[offsetWithinChunk] = fstruct;
2028         GetVNFunc2Map()->Set(fstruct, res);
2029         return res;
2030     }
2031 }
2032
2033 ValueNum ValueNumStore::EvalFuncForConstantArgs(var_types typ, VNFunc func, ValueNum arg0VN)
2034 {
2035     assert(CanEvalForConstantArgs(func));
2036     assert(IsVNConstant(arg0VN));
2037     switch (TypeOfVN(arg0VN))
2038     {
2039         case TYP_INT:
2040         {
2041             int resVal = EvalOp<int>(func, ConstantValue<int>(arg0VN));
2042             // Unary op on a handle results in a handle.
2043             return IsVNHandle(arg0VN) ? VNForHandle(ssize_t(resVal), GetHandleFlags(arg0VN)) : VNForIntCon(resVal);
2044         }
2045         case TYP_LONG:
2046         {
2047             INT64 resVal = EvalOp<INT64>(func, ConstantValue<INT64>(arg0VN));
2048             // Unary op on a handle results in a handle.
2049             return IsVNHandle(arg0VN) ? VNForHandle(ssize_t(resVal), GetHandleFlags(arg0VN)) : VNForLongCon(resVal);
2050         }
2051         case TYP_FLOAT:
2052         {
2053             float resVal = EvalOp<float>(func, ConstantValue<float>(arg0VN));
2054             return VNForFloatCon(resVal);
2055         }
2056         case TYP_DOUBLE:
2057         {
2058             double resVal = EvalOp<double>(func, ConstantValue<double>(arg0VN));
2059             return VNForDoubleCon(resVal);
2060         }
2061         case TYP_REF:
2062         {
2063             // If arg0 has a possible exception, it wouldn't have been constant.
2064             assert(!VNHasExc(arg0VN));
2065             // Otherwise...
2066             assert(arg0VN == VNForNull());         // Only other REF constant.
2067             assert(func == VNFunc(GT_ARR_LENGTH)); // Only function we can apply to a REF constant!
2068             return VNWithExc(VNForVoid(), VNExcSetSingleton(VNForFunc(TYP_REF, VNF_NullPtrExc, VNForNull())));
2069         }
2070         default:
2071             // We will assert below
2072             break;
2073     }
2074     noway_assert(!"Unhandled operation in EvalFuncForConstantArgs");
2075     return NoVN;
2076 }
2077
2078 bool ValueNumStore::SelectIsBeingEvaluatedRecursively(ValueNum map, ValueNum ind)
2079 {
2080     for (unsigned i = 0; i < m_fixedPointMapSels.Size(); i++)
2081     {
2082         VNDefFunc2Arg& elem = m_fixedPointMapSels.GetRef(i);
2083         assert(elem.m_func == VNF_MapSelect);
2084         if (elem.m_arg0 == map && elem.m_arg1 == ind)
2085         {
2086             return true;
2087         }
2088     }
2089     return false;
2090 }
2091
2092 #ifdef DEBUG
2093 bool ValueNumStore::FixedPointMapSelsTopHasValue(ValueNum map, ValueNum index)
2094 {
2095     if (m_fixedPointMapSels.Size() == 0)
2096     {
2097         return false;
2098     }
2099     VNDefFunc2Arg& top = m_fixedPointMapSels.TopRef();
2100     return top.m_func == VNF_MapSelect && top.m_arg0 == map && top.m_arg1 == index;
2101 }
2102 #endif
2103
2104 // Given an integer constant value number return its value as an int.
2105 //
2106 int ValueNumStore::GetConstantInt32(ValueNum argVN)
2107 {
2108     assert(IsVNConstant(argVN));
2109     var_types argVNtyp = TypeOfVN(argVN);
2110
2111     int result = 0;
2112
2113     switch (argVNtyp)
2114     {
2115         case TYP_INT:
2116             result = ConstantValue<int>(argVN);
2117             break;
2118 #ifndef _TARGET_64BIT_
2119         case TYP_REF:
2120         case TYP_BYREF:
2121             result = (int)ConstantValue<size_t>(argVN);
2122             break;
2123 #endif
2124         default:
2125             unreached();
2126     }
2127     return result;
2128 }
2129
2130 // Given an integer constant value number return its value as an INT64.
2131 //
2132 INT64 ValueNumStore::GetConstantInt64(ValueNum argVN)
2133 {
2134     assert(IsVNConstant(argVN));
2135     var_types argVNtyp = TypeOfVN(argVN);
2136
2137     INT64 result = 0;
2138
2139     switch (argVNtyp)
2140     {
2141         case TYP_INT:
2142             result = (INT64)ConstantValue<int>(argVN);
2143             break;
2144         case TYP_LONG:
2145             result = ConstantValue<INT64>(argVN);
2146             break;
2147         case TYP_REF:
2148         case TYP_BYREF:
2149             result = (INT64)ConstantValue<size_t>(argVN);
2150             break;
2151         default:
2152             unreached();
2153     }
2154     return result;
2155 }
2156
2157 // Given a double constant value number return its value as a double.
2158 //
2159 double ValueNumStore::GetConstantDouble(ValueNum argVN)
2160 {
2161     assert(IsVNConstant(argVN));
2162     assert(TypeOfVN(argVN) == TYP_DOUBLE);
2163
2164     return ConstantValue<double>(argVN);
2165 }
2166
2167 // Given a float constant value number return its value as a float.
2168 //
2169 float ValueNumStore::GetConstantSingle(ValueNum argVN)
2170 {
2171     assert(IsVNConstant(argVN));
2172     assert(TypeOfVN(argVN) == TYP_FLOAT);
2173
2174     return ConstantValue<float>(argVN);
2175 }
2176
2177 // Compute the proper value number when the VNFunc has all constant arguments
2178 // This essentially performs constant folding at value numbering time
2179 //
2180 ValueNum ValueNumStore::EvalFuncForConstantArgs(var_types typ, VNFunc func, ValueNum arg0VN, ValueNum arg1VN)
2181 {
2182     assert(CanEvalForConstantArgs(func));
2183     assert(IsVNConstant(arg0VN) && IsVNConstant(arg1VN));
2184     assert(!VNHasExc(arg0VN) && !VNHasExc(arg1VN)); // Otherwise, would not be constant.
2185
2186     // if our func is the VNF_Cast operation we handle it first
2187     if (func == VNF_Cast)
2188     {
2189         return EvalCastForConstantArgs(typ, func, arg0VN, arg1VN);
2190     }
2191
2192     var_types arg0VNtyp = TypeOfVN(arg0VN);
2193     var_types arg1VNtyp = TypeOfVN(arg1VN);
2194
2195     // When both arguments are floating point types
2196     // We defer to the EvalFuncForConstantFPArgs()
2197     if (varTypeIsFloating(arg0VNtyp) && varTypeIsFloating(arg1VNtyp))
2198     {
2199         return EvalFuncForConstantFPArgs(typ, func, arg0VN, arg1VN);
2200     }
2201
2202     // after this we shouldn't have to deal with floating point types for arg0VN or arg1VN
2203     assert(!varTypeIsFloating(arg0VNtyp));
2204     assert(!varTypeIsFloating(arg1VNtyp));
2205
2206     // Stack-normalize the result type.
2207     if (varTypeIsSmall(typ))
2208     {
2209         typ = TYP_INT;
2210     }
2211
2212     ValueNum result; // left uninitialized, we are required to initialize it on all paths below.
2213     ValueNum excSet = VNForEmptyExcSet();
2214
2215     // Are both args of the same type?
2216     if (arg0VNtyp == arg1VNtyp)
2217     {
2218         if (arg0VNtyp == TYP_INT)
2219         {
2220             int arg0Val = ConstantValue<int>(arg0VN);
2221             int arg1Val = ConstantValue<int>(arg1VN);
2222
2223             if (VNFuncIsComparison(func))
2224             {
2225                 assert(typ == TYP_INT);
2226                 result = VNForIntCon(EvalComparison(func, arg0Val, arg1Val));
2227             }
2228             else
2229             {
2230                 assert(typ == TYP_INT);
2231                 int resultVal = EvalOp<int>(func, arg0Val, arg1Val, &excSet);
2232                 // Bin op on a handle results in a handle.
2233                 ValueNum handleVN = IsVNHandle(arg0VN) ? arg0VN : IsVNHandle(arg1VN) ? arg1VN : NoVN;
2234                 if (handleVN != NoVN)
2235                 {
2236                     result = VNForHandle(ssize_t(resultVal), GetHandleFlags(handleVN)); // Use VN for Handle
2237                 }
2238                 else
2239                 {
2240                     result = VNWithExc(VNForIntCon(resultVal), excSet);
2241                 }
2242             }
2243         }
2244         else if (arg0VNtyp == TYP_LONG)
2245         {
2246             INT64 arg0Val = ConstantValue<INT64>(arg0VN);
2247             INT64 arg1Val = ConstantValue<INT64>(arg1VN);
2248
2249             if (VNFuncIsComparison(func))
2250             {
2251                 assert(typ == TYP_INT);
2252                 result = VNForIntCon(EvalComparison(func, arg0Val, arg1Val));
2253             }
2254             else
2255             {
2256                 assert(typ == TYP_LONG);
2257                 INT64    resultVal = EvalOp<INT64>(func, arg0Val, arg1Val, &excSet);
2258                 ValueNum handleVN  = IsVNHandle(arg0VN) ? arg0VN : IsVNHandle(arg1VN) ? arg1VN : NoVN;
2259                 ValueNum resultVN  = (handleVN != NoVN)
2260                                         ? VNForHandle(ssize_t(resultVal), GetHandleFlags(handleVN)) // Use VN for Handle
2261                                         : VNForLongCon(resultVal);
2262                 result = VNWithExc(resultVN, excSet);
2263             }
2264         }
2265         else // both args are TYP_REF or both args are TYP_BYREF
2266         {
2267             INT64 arg0Val = ConstantValue<size_t>(arg0VN); // We represent ref/byref constants as size_t's.
2268             INT64 arg1Val = ConstantValue<size_t>(arg1VN); // Also we consider null to be zero.
2269
2270             if (VNFuncIsComparison(func))
2271             {
2272                 assert(typ == TYP_INT);
2273                 result = VNForIntCon(EvalComparison(func, arg0Val, arg1Val));
2274             }
2275             else if (typ == TYP_INT) // We could see GT_OR of a constant ByRef and Null
2276             {
2277                 int resultVal = (int)EvalOp<INT64>(func, arg0Val, arg1Val, &excSet);
2278                 result        = VNWithExc(VNForIntCon(resultVal), excSet);
2279             }
2280             else // We could see GT_OR of a constant ByRef and Null
2281             {
2282                 assert((typ == TYP_BYREF) || (typ == TYP_LONG));
2283                 INT64 resultVal = EvalOp<INT64>(func, arg0Val, arg1Val, &excSet);
2284                 result          = VNWithExc(VNForByrefCon(resultVal), excSet);
2285             }
2286         }
2287     }
2288     else // We have args of different types
2289     {
2290         // We represent ref/byref constants as size_t's.
2291         // Also we consider null to be zero.
2292         //
2293         INT64 arg0Val = GetConstantInt64(arg0VN);
2294         INT64 arg1Val = GetConstantInt64(arg1VN);
2295
2296         if (VNFuncIsComparison(func))
2297         {
2298             assert(typ == TYP_INT);
2299             result = VNForIntCon(EvalComparison(func, arg0Val, arg1Val));
2300         }
2301         else if (typ == TYP_INT) // We could see GT_OR of an int and constant ByRef or Null
2302         {
2303             int resultVal = (int)EvalOp<INT64>(func, arg0Val, arg1Val, &excSet);
2304             result        = VNWithExc(VNForIntCon(resultVal), excSet);
2305         }
2306         else
2307         {
2308             assert(typ != TYP_INT);
2309             ValueNum resultValx = VNForEmptyExcSet();
2310             INT64    resultVal  = EvalOp<INT64>(func, arg0Val, arg1Val, &resultValx);
2311
2312             // check for the Exception case
2313             if (resultValx != VNForEmptyExcSet())
2314             {
2315                 result = VNWithExc(VNForVoid(), resultValx);
2316             }
2317             else
2318             {
2319                 switch (typ)
2320                 {
2321                     case TYP_BYREF:
2322                         result = VNForByrefCon(resultVal);
2323                         break;
2324                     case TYP_LONG:
2325                         result = VNForLongCon(resultVal);
2326                         break;
2327                     case TYP_REF:
2328                         assert(resultVal == 0); // Only valid REF constant
2329                         result = VNForNull();
2330                         break;
2331                     default:
2332                         unreached();
2333                 }
2334             }
2335         }
2336     }
2337
2338     return result;
2339 }
2340
2341 // Compute the proper value number when the VNFunc has all constant floating-point arguments
2342 // This essentially must perform constant folding at value numbering time
2343 //
2344 ValueNum ValueNumStore::EvalFuncForConstantFPArgs(var_types typ, VNFunc func, ValueNum arg0VN, ValueNum arg1VN)
2345 {
2346     assert(CanEvalForConstantArgs(func));
2347     assert(IsVNConstant(arg0VN) && IsVNConstant(arg1VN));
2348
2349     // We expect both argument types to be floating-point types
2350     var_types arg0VNtyp = TypeOfVN(arg0VN);
2351     var_types arg1VNtyp = TypeOfVN(arg1VN);
2352
2353     assert(varTypeIsFloating(arg0VNtyp));
2354     assert(varTypeIsFloating(arg1VNtyp));
2355
2356     // We also expect both arguments to be of the same floating-point type
2357     assert(arg0VNtyp == arg1VNtyp);
2358
2359     ValueNum result; // left uninitialized, we are required to initialize it on all paths below.
2360
2361     if (VNFuncIsComparison(func))
2362     {
2363         assert(genActualType(typ) == TYP_INT);
2364
2365         if (arg0VNtyp == TYP_FLOAT)
2366         {
2367             result = VNForIntCon(EvalComparison(func, GetConstantSingle(arg0VN), GetConstantSingle(arg1VN)));
2368         }
2369         else
2370         {
2371             assert(arg0VNtyp == TYP_DOUBLE);
2372             result = VNForIntCon(EvalComparison(func, GetConstantDouble(arg0VN), GetConstantDouble(arg1VN)));
2373         }
2374     }
2375     else
2376     {
2377         // We expect the return type to be the same as the argument type
2378         assert(varTypeIsFloating(typ));
2379         assert(arg0VNtyp == typ);
2380
2381         ValueNum exception = VNForEmptyExcSet();
2382
2383         if (typ == TYP_FLOAT)
2384         {
2385             float floatResultVal =
2386                 EvalOp<float>(func, GetConstantSingle(arg0VN), GetConstantSingle(arg1VN), &exception);
2387             assert(exception == VNForEmptyExcSet()); // Floating point ops don't throw.
2388             result = VNForFloatCon(floatResultVal);
2389         }
2390         else
2391         {
2392             assert(typ == TYP_DOUBLE);
2393
2394             double doubleResultVal =
2395                 EvalOp<double>(func, GetConstantDouble(arg0VN), GetConstantDouble(arg1VN), &exception);
2396             assert(exception == VNForEmptyExcSet()); // Floating point ops don't throw.
2397             result = VNForDoubleCon(doubleResultVal);
2398         }
2399     }
2400
2401     return result;
2402 }
2403
2404 // Compute the proper value number for a VNF_Cast with constant arguments
2405 // This essentially must perform constant folding at value numbering time
2406 //
2407 ValueNum ValueNumStore::EvalCastForConstantArgs(var_types typ, VNFunc func, ValueNum arg0VN, ValueNum arg1VN)
2408 {
2409     assert(func == VNF_Cast);
2410     assert(IsVNConstant(arg0VN) && IsVNConstant(arg1VN));
2411
2412     // Stack-normalize the result type.
2413     if (varTypeIsSmall(typ))
2414     {
2415         typ = TYP_INT;
2416     }
2417
2418     var_types arg0VNtyp = TypeOfVN(arg0VN);
2419     var_types arg1VNtyp = TypeOfVN(arg1VN);
2420
2421     // arg1VN is really the gtCastType that we are casting to
2422     assert(arg1VNtyp == TYP_INT);
2423     int arg1Val = ConstantValue<int>(arg1VN);
2424     assert(arg1Val >= 0);
2425
2426     if (IsVNHandle(arg0VN))
2427     {
2428         // We don't allow handles to be cast to random var_types.
2429         assert(typ == TYP_I_IMPL);
2430     }
2431
2432     // We previously encoded the castToType operation using vnForCastOper()
2433     //
2434     bool      srcIsUnsigned = ((arg1Val & INT32(VCA_UnsignedSrc)) != 0);
2435     var_types castToType    = var_types(arg1Val >> INT32(VCA_BitCount));
2436
2437     var_types castFromType = arg0VNtyp;
2438
2439     switch (castFromType) // GT_CAST source type
2440     {
2441 #ifndef _TARGET_64BIT_
2442         case TYP_REF:
2443         case TYP_BYREF:
2444 #endif
2445         case TYP_INT:
2446         {
2447             int arg0Val = GetConstantInt32(arg0VN);
2448
2449             switch (castToType)
2450             {
2451                 case TYP_BYTE:
2452                     assert(typ == TYP_INT);
2453                     return VNForIntCon(INT8(arg0Val));
2454                 case TYP_BOOL:
2455                 case TYP_UBYTE:
2456                     assert(typ == TYP_INT);
2457                     return VNForIntCon(UINT8(arg0Val));
2458                 case TYP_SHORT:
2459                     assert(typ == TYP_INT);
2460                     return VNForIntCon(INT16(arg0Val));
2461                 case TYP_USHORT:
2462                     assert(typ == TYP_INT);
2463                     return VNForIntCon(UINT16(arg0Val));
2464                 case TYP_INT:
2465                 case TYP_UINT:
2466                     assert(typ == TYP_INT);
2467                     return arg0VN;
2468                 case TYP_LONG:
2469                 case TYP_ULONG:
2470                     assert(!IsVNHandle(arg0VN));
2471 #ifdef _TARGET_64BIT_
2472                     if (typ == TYP_LONG)
2473                     {
2474                         if (srcIsUnsigned)
2475                         {
2476                             return VNForLongCon(INT64(unsigned(arg0Val)));
2477                         }
2478                         else
2479                         {
2480                             return VNForLongCon(INT64(arg0Val));
2481                         }
2482                     }
2483                     else
2484                     {
2485                         assert(typ == TYP_BYREF);
2486                         if (srcIsUnsigned)
2487                         {
2488                             return VNForByrefCon(INT64(unsigned(arg0Val)));
2489                         }
2490                         else
2491                         {
2492                             return VNForByrefCon(INT64(arg0Val));
2493                         }
2494                     }
2495 #else // TARGET_32BIT
2496                     if (srcIsUnsigned)
2497                         return VNForLongCon(INT64(unsigned(arg0Val)));
2498                     else
2499                         return VNForLongCon(INT64(arg0Val));
2500 #endif
2501                 case TYP_BYREF:
2502                     assert(typ == TYP_BYREF);
2503                     return VNForByrefCon((INT64)arg0Val);
2504                 case TYP_FLOAT:
2505                     assert(typ == TYP_FLOAT);
2506                     if (srcIsUnsigned)
2507                     {
2508                         return VNForFloatCon(float(unsigned(arg0Val)));
2509                     }
2510                     else
2511                     {
2512                         return VNForFloatCon(float(arg0Val));
2513                     }
2514                 case TYP_DOUBLE:
2515                     assert(typ == TYP_DOUBLE);
2516                     if (srcIsUnsigned)
2517                     {
2518                         return VNForDoubleCon(double(unsigned(arg0Val)));
2519                     }
2520                     else
2521                     {
2522                         return VNForDoubleCon(double(arg0Val));
2523                     }
2524                 default:
2525                     unreached();
2526             }
2527             break;
2528         }
2529             {
2530 #ifdef _TARGET_64BIT_
2531                 case TYP_REF:
2532                 case TYP_BYREF:
2533 #endif
2534                 case TYP_LONG:
2535                     INT64 arg0Val = GetConstantInt64(arg0VN);
2536
2537                     switch (castToType)
2538                     {
2539                         case TYP_BYTE:
2540                             assert(typ == TYP_INT);
2541                             return VNForIntCon(INT8(arg0Val));
2542                         case TYP_BOOL:
2543                         case TYP_UBYTE:
2544                             assert(typ == TYP_INT);
2545                             return VNForIntCon(UINT8(arg0Val));
2546                         case TYP_SHORT:
2547                             assert(typ == TYP_INT);
2548                             return VNForIntCon(INT16(arg0Val));
2549                         case TYP_USHORT:
2550                             assert(typ == TYP_INT);
2551                             return VNForIntCon(UINT16(arg0Val));
2552                         case TYP_INT:
2553                             assert(typ == TYP_INT);
2554                             return VNForIntCon(INT32(arg0Val));
2555                         case TYP_UINT:
2556                             assert(typ == TYP_INT);
2557                             return VNForIntCon(UINT32(arg0Val));
2558                         case TYP_LONG:
2559                         case TYP_ULONG:
2560                             assert(typ == TYP_LONG);
2561                             return arg0VN;
2562                         case TYP_BYREF:
2563                             assert(typ == TYP_BYREF);
2564                             return VNForByrefCon((INT64)arg0Val);
2565                         case TYP_FLOAT:
2566                             assert(typ == TYP_FLOAT);
2567                             if (srcIsUnsigned)
2568                             {
2569                                 return VNForFloatCon(FloatingPointUtils::convertUInt64ToFloat(UINT64(arg0Val)));
2570                             }
2571                             else
2572                             {
2573                                 return VNForFloatCon(float(arg0Val));
2574                             }
2575                         case TYP_DOUBLE:
2576                             assert(typ == TYP_DOUBLE);
2577                             if (srcIsUnsigned)
2578                             {
2579                                 return VNForDoubleCon(FloatingPointUtils::convertUInt64ToDouble(UINT64(arg0Val)));
2580                             }
2581                             else
2582                             {
2583                                 return VNForDoubleCon(double(arg0Val));
2584                             }
2585                         default:
2586                             unreached();
2587                     }
2588             }
2589         case TYP_FLOAT:
2590         {
2591             float arg0Val = GetConstantSingle(arg0VN);
2592
2593             switch (castToType)
2594             {
2595                 case TYP_BYTE:
2596                     assert(typ == TYP_INT);
2597                     return VNForIntCon(INT8(arg0Val));
2598                 case TYP_BOOL:
2599                 case TYP_UBYTE:
2600                     assert(typ == TYP_INT);
2601                     return VNForIntCon(UINT8(arg0Val));
2602                 case TYP_SHORT:
2603                     assert(typ == TYP_INT);
2604                     return VNForIntCon(INT16(arg0Val));
2605                 case TYP_USHORT:
2606                     assert(typ == TYP_INT);
2607                     return VNForIntCon(UINT16(arg0Val));
2608                 case TYP_INT:
2609                     assert(typ == TYP_INT);
2610                     return VNForIntCon(INT32(arg0Val));
2611                 case TYP_UINT:
2612                     assert(typ == TYP_INT);
2613                     return VNForIntCon(UINT32(arg0Val));
2614                 case TYP_LONG:
2615                     assert(typ == TYP_LONG);
2616                     return VNForLongCon(INT64(arg0Val));
2617                 case TYP_ULONG:
2618                     assert(typ == TYP_LONG);
2619                     return VNForLongCon(UINT64(arg0Val));
2620                 case TYP_FLOAT:
2621                     assert(typ == TYP_FLOAT);
2622                     return VNForFloatCon(arg0Val);
2623                 case TYP_DOUBLE:
2624                     assert(typ == TYP_DOUBLE);
2625                     return VNForDoubleCon(double(arg0Val));
2626                 default:
2627                     unreached();
2628             }
2629         }
2630         case TYP_DOUBLE:
2631         {
2632             double arg0Val = GetConstantDouble(arg0VN);
2633
2634             switch (castToType)
2635             {
2636                 case TYP_BYTE:
2637                     assert(typ == TYP_INT);
2638                     return VNForIntCon(INT8(arg0Val));
2639                 case TYP_BOOL:
2640                 case TYP_UBYTE:
2641                     assert(typ == TYP_INT);
2642                     return VNForIntCon(UINT8(arg0Val));
2643                 case TYP_SHORT:
2644                     assert(typ == TYP_INT);
2645                     return VNForIntCon(INT16(arg0Val));
2646                 case TYP_USHORT:
2647                     assert(typ == TYP_INT);
2648                     return VNForIntCon(UINT16(arg0Val));
2649                 case TYP_INT:
2650                     assert(typ == TYP_INT);
2651                     return VNForIntCon(INT32(arg0Val));
2652                 case TYP_UINT:
2653                     assert(typ == TYP_INT);
2654                     return VNForIntCon(UINT32(arg0Val));
2655                 case TYP_LONG:
2656                     assert(typ == TYP_LONG);
2657                     return VNForLongCon(INT64(arg0Val));
2658                 case TYP_ULONG:
2659                     assert(typ == TYP_LONG);
2660                     return VNForLongCon(UINT64(arg0Val));
2661                 case TYP_FLOAT:
2662                     assert(typ == TYP_FLOAT);
2663                     return VNForFloatCon(float(arg0Val));
2664                 case TYP_DOUBLE:
2665                     assert(typ == TYP_DOUBLE);
2666                     return VNForDoubleCon(arg0Val);
2667                 default:
2668                     unreached();
2669             }
2670         }
2671         default:
2672             unreached();
2673     }
2674 }
2675
2676 bool ValueNumStore::CanEvalForConstantArgs(VNFunc vnf)
2677 {
2678     if (vnf < VNF_Boundary)
2679     {
2680         // We'll refine this as we get counterexamples.  But to
2681         // a first approximation, VNFuncs that are genTreeOps should
2682         // be things we can evaluate.
2683         genTreeOps oper = genTreeOps(vnf);
2684         // Some exceptions...
2685         switch (oper)
2686         {
2687             case GT_MKREFANY: // We can't evaluate these.
2688             case GT_RETFILT:
2689             case GT_LIST:
2690             case GT_FIELD_LIST:
2691             case GT_ARR_LENGTH:
2692                 return false;
2693             case GT_MULHI:
2694                 assert(false && "Unexpected GT_MULHI node encountered before lowering");
2695                 return false;
2696             default:
2697                 return true;
2698         }
2699     }
2700     else
2701     {
2702         // some VNF_ that we can evaluate
2703         switch (vnf)
2704         {
2705             case VNF_Cast: // We can evaluate these.
2706                 return true;
2707             case VNF_ObjGetType:
2708                 return false;
2709             default:
2710                 return false;
2711         }
2712     }
2713 }
2714
2715 ValueNum ValueNumStore::VNForFunc(var_types typ, VNFunc func, ValueNum arg0VN, ValueNum arg1VN, ValueNum arg2VN)
2716 {
2717     assert(arg0VN != NoVN);
2718     assert(arg1VN != NoVN);
2719     assert(arg2VN != NoVN);
2720     assert(VNFuncArity(func) == 3);
2721
2722     // Function arguments carry no exceptions.
2723     CLANG_FORMAT_COMMENT_ANCHOR;
2724
2725 #ifdef DEBUG
2726     if (func != VNF_PhiDef)
2727     {
2728         // For a phi definition first and second argument are "plain" local/ssa numbers.
2729         // (I don't know if having such non-VN arguments to a VN function is a good idea -- if we wanted to declare
2730         // ValueNum to be "short" it would be a problem, for example.  But we'll leave it for now, with these explicit
2731         // exceptions.)
2732         assert(arg0VN == VNNormVal(arg0VN));
2733         assert(arg1VN == VNNormVal(arg1VN));
2734     }
2735     assert(arg2VN == VNNormVal(arg2VN));
2736
2737 #endif
2738     assert(VNFuncArity(func) == 3);
2739
2740     ValueNum      res;
2741     VNDefFunc3Arg fstruct(func, arg0VN, arg1VN, arg2VN);
2742     if (GetVNFunc3Map()->Lookup(fstruct, &res))
2743     {
2744         return res;
2745     }
2746     else
2747     {
2748         Chunk*   c                                                     = GetAllocChunk(typ, CEA_Func3);
2749         unsigned offsetWithinChunk                                     = c->AllocVN();
2750         res                                                            = c->m_baseVN + offsetWithinChunk;
2751         reinterpret_cast<VNDefFunc3Arg*>(c->m_defs)[offsetWithinChunk] = fstruct;
2752         GetVNFunc3Map()->Set(fstruct, res);
2753         return res;
2754     }
2755 }
2756
2757 ValueNum ValueNumStore::VNForFunc(
2758     var_types typ, VNFunc func, ValueNum arg0VN, ValueNum arg1VN, ValueNum arg2VN, ValueNum arg3VN)
2759 {
2760     assert(arg0VN != NoVN && arg1VN != NoVN && arg2VN != NoVN && arg3VN != NoVN);
2761     // Function arguments carry no exceptions.
2762     assert(arg0VN == VNNormVal(arg0VN));
2763     assert(arg1VN == VNNormVal(arg1VN));
2764     assert(arg2VN == VNNormVal(arg2VN));
2765     assert(arg3VN == VNNormVal(arg3VN));
2766     assert(VNFuncArity(func) == 4);
2767
2768     ValueNum      res;
2769     VNDefFunc4Arg fstruct(func, arg0VN, arg1VN, arg2VN, arg3VN);
2770     if (GetVNFunc4Map()->Lookup(fstruct, &res))
2771     {
2772         return res;
2773     }
2774     else
2775     {
2776         Chunk*   c                                                     = GetAllocChunk(typ, CEA_Func4);
2777         unsigned offsetWithinChunk                                     = c->AllocVN();
2778         res                                                            = c->m_baseVN + offsetWithinChunk;
2779         reinterpret_cast<VNDefFunc4Arg*>(c->m_defs)[offsetWithinChunk] = fstruct;
2780         GetVNFunc4Map()->Set(fstruct, res);
2781         return res;
2782     }
2783 }
2784
2785 //------------------------------------------------------------------------
2786 // VNForExpr: Opaque value number that is equivalent to itself but unique
2787 //    from all other value numbers.
2788 //
2789 // Arguments:
2790 //    block - BasicBlock where the expression that produces this value occurs.
2791 //            May be nullptr to force conservative "could be anywhere" interpretation.
2792 //     typ - Type of the expression in the IR
2793 //
2794 // Return Value:
2795 //    A new value number distinct from any previously generated, that compares as equal
2796 //    to itself, but not any other value number, and is annotated with the given
2797 //    type and block.
2798
2799 ValueNum ValueNumStore::VNForExpr(BasicBlock* block, var_types typ)
2800 {
2801     BasicBlock::loopNumber loopNum;
2802     if (block == nullptr)
2803     {
2804         loopNum = MAX_LOOP_NUM;
2805     }
2806     else
2807     {
2808         loopNum = block->bbNatLoopNum;
2809     }
2810
2811     // We always allocate a new, unique VN in this call.
2812     // The 'typ' is used to partition the allocation of VNs into different chunks.
2813     Chunk*   c                 = GetAllocChunk(typ, CEA_None, loopNum);
2814     unsigned offsetWithinChunk = c->AllocVN();
2815     ValueNum result            = c->m_baseVN + offsetWithinChunk;
2816     return result;
2817 }
2818
2819 ValueNum ValueNumStore::VNApplySelectors(ValueNumKind  vnk,
2820                                          ValueNum      map,
2821                                          FieldSeqNode* fieldSeq,
2822                                          size_t*       wbFinalStructSize)
2823 {
2824     if (fieldSeq == nullptr)
2825     {
2826         return map;
2827     }
2828     else
2829     {
2830         assert(fieldSeq != FieldSeqStore::NotAField());
2831
2832         // Skip any "FirstElem" pseudo-fields or any "ConstantIndex" pseudo-fields
2833         if (fieldSeq->IsPseudoField())
2834         {
2835             return VNApplySelectors(vnk, map, fieldSeq->m_next, wbFinalStructSize);
2836         }
2837
2838         // Otherwise, is a real field handle.
2839         CORINFO_FIELD_HANDLE fldHnd    = fieldSeq->m_fieldHnd;
2840         CORINFO_CLASS_HANDLE structHnd = NO_CLASS_HANDLE;
2841         ValueNum             fldHndVN  = VNForHandle(ssize_t(fldHnd), GTF_ICON_FIELD_HDL);
2842         noway_assert(fldHnd != nullptr);
2843         CorInfoType fieldCit  = m_pComp->info.compCompHnd->getFieldType(fldHnd, &structHnd);
2844         var_types   fieldType = JITtype2varType(fieldCit);
2845
2846         size_t structSize = 0;
2847         if (varTypeIsStruct(fieldType))
2848         {
2849             structSize = m_pComp->info.compCompHnd->getClassSize(structHnd);
2850             // We do not normalize the type field accesses during importation unless they
2851             // are used in a call, return or assignment.
2852             if ((fieldType == TYP_STRUCT) && (structSize <= m_pComp->largestEnregisterableStructSize()))
2853             {
2854                 fieldType = m_pComp->impNormStructType(structHnd);
2855             }
2856         }
2857         if (wbFinalStructSize != nullptr)
2858         {
2859             *wbFinalStructSize = structSize;
2860         }
2861
2862 #ifdef DEBUG
2863         if (m_pComp->verbose)
2864         {
2865             printf("  VNApplySelectors:\n");
2866             const char* modName;
2867             const char* fldName = m_pComp->eeGetFieldName(fldHnd, &modName);
2868             printf("    VNForHandle(Fseq[%s]) is " FMT_VN ", fieldType is %s", fldName, fldHndVN,
2869                    varTypeName(fieldType));
2870             if (varTypeIsStruct(fieldType))
2871             {
2872                 printf(", size = %d", structSize);
2873             }
2874             printf("\n");
2875         }
2876 #endif
2877
2878         if (fieldSeq->m_next != nullptr)
2879         {
2880             ValueNum newMap = VNForMapSelect(vnk, fieldType, map, fldHndVN);
2881             return VNApplySelectors(vnk, newMap, fieldSeq->m_next, wbFinalStructSize);
2882         }
2883         else // end of fieldSeq
2884         {
2885             return VNForMapSelect(vnk, fieldType, map, fldHndVN);
2886         }
2887     }
2888 }
2889
2890 ValueNum ValueNumStore::VNApplySelectorsTypeCheck(ValueNum elem, var_types indType, size_t elemStructSize)
2891 {
2892     var_types elemTyp = TypeOfVN(elem);
2893
2894     // Check if the elemTyp is matching/compatible
2895
2896     if (indType != elemTyp)
2897     {
2898         // We are trying to read from an 'elem' of type 'elemType' using 'indType' read
2899
2900         size_t elemTypSize = (elemTyp == TYP_STRUCT) ? elemStructSize : genTypeSize(elemTyp);
2901         size_t indTypeSize = genTypeSize(indType);
2902
2903         if ((indType == TYP_REF) && (varTypeIsStruct(elemTyp)))
2904         {
2905             // indType is TYP_REF and elemTyp is TYP_STRUCT
2906             //
2907             // We have a pointer to a static that is a Boxed Struct
2908             //
2909             return elem;
2910         }
2911         else if (indTypeSize > elemTypSize)
2912         {
2913             // Reading beyong the end of 'elem'
2914
2915             // return a new unique value number
2916             elem = VNForExpr(nullptr, indType);
2917             JITDUMP("    *** Mismatched types in VNApplySelectorsTypeCheck (reading beyond the end)\n");
2918         }
2919         else if (varTypeIsStruct(indType))
2920         {
2921             // indType is TYP_STRUCT
2922
2923             // return a new unique value number
2924             elem = VNForExpr(nullptr, indType);
2925             JITDUMP("    *** Mismatched types in VNApplySelectorsTypeCheck (indType is TYP_STRUCT)\n");
2926         }
2927         else
2928         {
2929             // We are trying to read an 'elem' of type 'elemType' using 'indType' read
2930
2931             // insert a cast of elem to 'indType'
2932             elem = VNForCast(elem, indType, elemTyp);
2933         }
2934     }
2935     return elem;
2936 }
2937
2938 ValueNum ValueNumStore::VNApplySelectorsAssignTypeCoerce(ValueNum elem, var_types indType, BasicBlock* block)
2939 {
2940     var_types elemTyp = TypeOfVN(elem);
2941
2942     // Check if the elemTyp is matching/compatible
2943
2944     if (indType != elemTyp)
2945     {
2946         bool isConstant = IsVNConstant(elem);
2947         if (isConstant && (elemTyp == genActualType(indType)))
2948         {
2949             // (i.e. We recorded a constant of TYP_INT for a TYP_BYTE field)
2950         }
2951         else
2952         {
2953             // We are trying to write an 'elem' of type 'elemType' using 'indType' store
2954
2955             if (varTypeIsStruct(indType))
2956             {
2957                 // return a new unique value number
2958                 elem = VNForExpr(block, indType);
2959                 JITDUMP("    *** Mismatched types in VNApplySelectorsAssignTypeCoerce (indType is TYP_STRUCT)\n");
2960             }
2961             else
2962             {
2963                 // We are trying to write an 'elem' of type 'elemType' using 'indType' store
2964
2965                 // insert a cast of elem to 'indType'
2966                 elem = VNForCast(elem, indType, elemTyp);
2967             }
2968         }
2969     }
2970     return elem;
2971 }
2972
2973 //------------------------------------------------------------------------
2974 // VNApplySelectorsAssign: Compute the value number corresponding to "map" but with
2975 //    the element at "fieldSeq" updated to have type "elem"; this is the new memory
2976 //    value for an assignment of value "elem" into the memory at location "fieldSeq"
2977 //    that occurs in block "block" and has type "indType" (so long as the selectors
2978 //    into that memory occupy disjoint locations, which is true for GcHeap).
2979 //
2980 // Arguments:
2981 //    vnk - Identifies whether to recurse to Conservative or Liberal value numbers
2982 //          when recursing through phis
2983 //    map - Value number for the field map before the assignment
2984 //    elem - Value number for the value being stored (to the given field)
2985 //    indType - Type of the indirection storing the value to the field
2986 //    block - Block where the assignment occurs
2987 //
2988 // Return Value:
2989 //    The value number corresponding to memory after the assignment.
2990
2991 ValueNum ValueNumStore::VNApplySelectorsAssign(
2992     ValueNumKind vnk, ValueNum map, FieldSeqNode* fieldSeq, ValueNum elem, var_types indType, BasicBlock* block)
2993 {
2994     if (fieldSeq == nullptr)
2995     {
2996         return VNApplySelectorsAssignTypeCoerce(elem, indType, block);
2997     }
2998     else
2999     {
3000         assert(fieldSeq != FieldSeqStore::NotAField());
3001
3002         // Skip any "FirstElem" pseudo-fields or any "ConstantIndex" pseudo-fields
3003         // These will occur, at least, in struct static expressions, for method table offsets.
3004         if (fieldSeq->IsPseudoField())
3005         {
3006             return VNApplySelectorsAssign(vnk, map, fieldSeq->m_next, elem, indType, block);
3007         }
3008
3009         // Otherwise, fldHnd is a real field handle.
3010         CORINFO_FIELD_HANDLE fldHnd     = fieldSeq->m_fieldHnd;
3011         CORINFO_CLASS_HANDLE structType = nullptr;
3012         noway_assert(fldHnd != nullptr);
3013         CorInfoType fieldCit  = m_pComp->info.compCompHnd->getFieldType(fldHnd, &structType);
3014         var_types   fieldType = JITtype2varType(fieldCit);
3015
3016         ValueNum fieldHndVN = VNForHandle(ssize_t(fldHnd), GTF_ICON_FIELD_HDL);
3017         ValueNum elemAfter;
3018         if (fieldSeq->m_next)
3019         {
3020             ValueNum fseqMap = VNForMapSelect(vnk, fieldType, map, fieldHndVN);
3021             elemAfter        = VNApplySelectorsAssign(vnk, fseqMap, fieldSeq->m_next, elem, indType, block);
3022         }
3023         else
3024         {
3025             elemAfter = VNApplySelectorsAssignTypeCoerce(elem, indType, block);
3026         }
3027
3028         ValueNum newMap = VNForMapStore(fieldType, map, fieldHndVN, elemAfter);
3029         return newMap;
3030     }
3031 }
3032
3033 ValueNumPair ValueNumStore::VNPairApplySelectors(ValueNumPair map, FieldSeqNode* fieldSeq, var_types indType)
3034 {
3035     size_t   structSize = 0;
3036     ValueNum liberalVN  = VNApplySelectors(VNK_Liberal, map.GetLiberal(), fieldSeq, &structSize);
3037     liberalVN           = VNApplySelectorsTypeCheck(liberalVN, indType, structSize);
3038
3039     structSize         = 0;
3040     ValueNum conservVN = VNApplySelectors(VNK_Conservative, map.GetConservative(), fieldSeq, &structSize);
3041     conservVN          = VNApplySelectorsTypeCheck(conservVN, indType, structSize);
3042
3043     return ValueNumPair(liberalVN, conservVN);
3044 }
3045
3046 bool ValueNumStore::IsVNNotAField(ValueNum vn)
3047 {
3048     return m_chunks.GetNoExpand(GetChunkNum(vn))->m_attribs == CEA_NotAField;
3049 }
3050
3051 ValueNum ValueNumStore::VNForFieldSeq(FieldSeqNode* fieldSeq)
3052 {
3053     if (fieldSeq == nullptr)
3054     {
3055         return VNForNull();
3056     }
3057     else if (fieldSeq == FieldSeqStore::NotAField())
3058     {
3059         // We always allocate a new, unique VN in this call.
3060         Chunk*   c                 = GetAllocChunk(TYP_REF, CEA_NotAField);
3061         unsigned offsetWithinChunk = c->AllocVN();
3062         ValueNum result            = c->m_baseVN + offsetWithinChunk;
3063         return result;
3064     }
3065     else
3066     {
3067         ssize_t  fieldHndVal = ssize_t(fieldSeq->m_fieldHnd);
3068         ValueNum fieldHndVN  = VNForHandle(fieldHndVal, GTF_ICON_FIELD_HDL);
3069         ValueNum seqNextVN   = VNForFieldSeq(fieldSeq->m_next);
3070         ValueNum fieldSeqVN  = VNForFunc(TYP_REF, VNF_FieldSeq, fieldHndVN, seqNextVN);
3071
3072 #ifdef DEBUG
3073         if (m_pComp->verbose)
3074         {
3075             printf("  fieldHnd " FMT_VN " is ", fieldHndVN);
3076             vnDump(m_pComp, fieldHndVN);
3077             printf("\n");
3078
3079             printf("  fieldSeq " FMT_VN " is ", fieldSeqVN);
3080             vnDump(m_pComp, fieldSeqVN);
3081             printf("\n");
3082         }
3083 #endif
3084
3085         return fieldSeqVN;
3086     }
3087 }
3088
3089 FieldSeqNode* ValueNumStore::FieldSeqVNToFieldSeq(ValueNum vn)
3090 {
3091     if (vn == VNForNull())
3092     {
3093         return nullptr;
3094     }
3095
3096     assert(IsVNFunc(vn));
3097
3098     VNFuncApp funcApp;
3099     GetVNFunc(vn, &funcApp);
3100     if (funcApp.m_func == VNF_NotAField)
3101     {
3102         return FieldSeqStore::NotAField();
3103     }
3104
3105     assert(funcApp.m_func == VNF_FieldSeq);
3106     const ssize_t fieldHndVal = ConstantValue<ssize_t>(funcApp.m_args[0]);
3107     FieldSeqNode* head =
3108         m_pComp->GetFieldSeqStore()->CreateSingleton(reinterpret_cast<CORINFO_FIELD_HANDLE>(fieldHndVal));
3109     FieldSeqNode* tail = FieldSeqVNToFieldSeq(funcApp.m_args[1]);
3110     return m_pComp->GetFieldSeqStore()->Append(head, tail);
3111 }
3112
3113 ValueNum ValueNumStore::FieldSeqVNAppend(ValueNum fsVN1, ValueNum fsVN2)
3114 {
3115     if (fsVN1 == VNForNull())
3116     {
3117         return fsVN2;
3118     }
3119
3120     assert(IsVNFunc(fsVN1));
3121
3122     VNFuncApp funcApp1;
3123     GetVNFunc(fsVN1, &funcApp1);
3124
3125     if ((funcApp1.m_func == VNF_NotAField) || IsVNNotAField(fsVN2))
3126     {
3127         return VNForFieldSeq(FieldSeqStore::NotAField());
3128     }
3129
3130     assert(funcApp1.m_func == VNF_FieldSeq);
3131     ValueNum tailRes    = FieldSeqVNAppend(funcApp1.m_args[1], fsVN2);
3132     ValueNum fieldSeqVN = VNForFunc(TYP_REF, VNF_FieldSeq, funcApp1.m_args[0], tailRes);
3133
3134 #ifdef DEBUG
3135     if (m_pComp->verbose)
3136     {
3137         printf("  fieldSeq " FMT_VN " is ", fieldSeqVN);
3138         vnDump(m_pComp, fieldSeqVN);
3139         printf("\n");
3140     }
3141 #endif
3142
3143     return fieldSeqVN;
3144 }
3145
3146 ValueNum ValueNumStore::ExtendPtrVN(GenTree* opA, GenTree* opB)
3147 {
3148     if (opB->OperGet() == GT_CNS_INT)
3149     {
3150         FieldSeqNode* fldSeq = opB->gtIntCon.gtFieldSeq;
3151         if (fldSeq != nullptr)
3152         {
3153             return ExtendPtrVN(opA, opB->gtIntCon.gtFieldSeq);
3154         }
3155     }
3156     return NoVN;
3157 }
3158
3159 ValueNum ValueNumStore::ExtendPtrVN(GenTree* opA, FieldSeqNode* fldSeq)
3160 {
3161     assert(fldSeq != nullptr);
3162
3163     ValueNum res = NoVN;
3164
3165     ValueNum opAvnWx = opA->gtVNPair.GetLiberal();
3166     assert(VNIsValid(opAvnWx));
3167     ValueNum opAvn;
3168     ValueNum opAvnx = VNForEmptyExcSet();
3169     VNUnpackExc(opAvnWx, &opAvn, &opAvnx);
3170     assert(VNIsValid(opAvn) && VNIsValid(opAvnx));
3171
3172     VNFuncApp funcApp;
3173     if (!GetVNFunc(opAvn, &funcApp))
3174     {
3175         return res;
3176     }
3177
3178     if (funcApp.m_func == VNF_PtrToLoc)
3179     {
3180 #ifdef DEBUG
3181         // For PtrToLoc, lib == cons.
3182         VNFuncApp consFuncApp;
3183         assert(GetVNFunc(VNNormVal(opA->GetVN(VNK_Conservative)), &consFuncApp) && consFuncApp.Equals(funcApp));
3184 #endif
3185         ValueNum fldSeqVN = VNForFieldSeq(fldSeq);
3186         res = VNForFunc(TYP_BYREF, VNF_PtrToLoc, funcApp.m_args[0], FieldSeqVNAppend(funcApp.m_args[1], fldSeqVN));
3187     }
3188     else if (funcApp.m_func == VNF_PtrToStatic)
3189     {
3190         ValueNum fldSeqVN = VNForFieldSeq(fldSeq);
3191         res               = VNForFunc(TYP_BYREF, VNF_PtrToStatic, FieldSeqVNAppend(funcApp.m_args[0], fldSeqVN));
3192     }
3193     else if (funcApp.m_func == VNF_PtrToArrElem)
3194     {
3195         ValueNum fldSeqVN = VNForFieldSeq(fldSeq);
3196         res = VNForFunc(TYP_BYREF, VNF_PtrToArrElem, funcApp.m_args[0], funcApp.m_args[1], funcApp.m_args[2],
3197                         FieldSeqVNAppend(funcApp.m_args[3], fldSeqVN));
3198     }
3199     if (res != NoVN)
3200     {
3201         res = VNWithExc(res, opAvnx);
3202     }
3203     return res;
3204 }
3205
3206 ValueNum Compiler::fgValueNumberArrIndexAssign(CORINFO_CLASS_HANDLE elemTypeEq,
3207                                                ValueNum             arrVN,
3208                                                ValueNum             inxVN,
3209                                                FieldSeqNode*        fldSeq,
3210                                                ValueNum             rhsVN,
3211                                                var_types            indType)
3212 {
3213     bool      invalidateArray      = false;
3214     ValueNum  elemTypeEqVN         = vnStore->VNForHandle(ssize_t(elemTypeEq), GTF_ICON_CLASS_HDL);
3215     var_types arrElemType          = DecodeElemType(elemTypeEq);
3216     ValueNum  hAtArrType           = vnStore->VNForMapSelect(VNK_Liberal, TYP_REF, fgCurMemoryVN[GcHeap], elemTypeEqVN);
3217     ValueNum  hAtArrTypeAtArr      = vnStore->VNForMapSelect(VNK_Liberal, TYP_REF, hAtArrType, arrVN);
3218     ValueNum  hAtArrTypeAtArrAtInx = vnStore->VNForMapSelect(VNK_Liberal, arrElemType, hAtArrTypeAtArr, inxVN);
3219
3220     ValueNum newValAtInx     = ValueNumStore::NoVN;
3221     ValueNum newValAtArr     = ValueNumStore::NoVN;
3222     ValueNum newValAtArrType = ValueNumStore::NoVN;
3223
3224     if (fldSeq == FieldSeqStore::NotAField())
3225     {
3226         // This doesn't represent a proper array access
3227         JITDUMP("    *** NotAField sequence encountered in fgValueNumberArrIndexAssign\n");
3228
3229         // Store a new unique value for newValAtArrType
3230         newValAtArrType = vnStore->VNForExpr(compCurBB, TYP_REF);
3231         invalidateArray = true;
3232     }
3233     else
3234     {
3235         // Note that this does the right thing if "fldSeq" is null -- returns last "rhs" argument.
3236         // This is the value that should be stored at "arr[inx]".
3237         newValAtInx =
3238             vnStore->VNApplySelectorsAssign(VNK_Liberal, hAtArrTypeAtArrAtInx, fldSeq, rhsVN, indType, compCurBB);
3239
3240         var_types arrElemFldType = arrElemType; // Uses arrElemType unless we has a non-null fldSeq
3241         if (vnStore->IsVNFunc(newValAtInx))
3242         {
3243             VNFuncApp funcApp;
3244             vnStore->GetVNFunc(newValAtInx, &funcApp);
3245             if (funcApp.m_func == VNF_MapStore)
3246             {
3247                 arrElemFldType = vnStore->TypeOfVN(newValAtInx);
3248             }
3249         }
3250
3251         if (indType != arrElemFldType)
3252         {
3253             // Mismatched types: Store between different types (indType into array of arrElemFldType)
3254             //
3255
3256             JITDUMP("    *** Mismatched types in fgValueNumberArrIndexAssign\n");
3257
3258             // Store a new unique value for newValAtArrType
3259             newValAtArrType = vnStore->VNForExpr(compCurBB, TYP_REF);
3260             invalidateArray = true;
3261         }
3262     }
3263
3264     if (!invalidateArray)
3265     {
3266         newValAtArr     = vnStore->VNForMapStore(indType, hAtArrTypeAtArr, inxVN, newValAtInx);
3267         newValAtArrType = vnStore->VNForMapStore(TYP_REF, hAtArrType, arrVN, newValAtArr);
3268     }
3269
3270 #ifdef DEBUG
3271     if (verbose)
3272     {
3273         printf("  hAtArrType " FMT_VN " is MapSelect(curGcHeap(" FMT_VN "), ", hAtArrType, fgCurMemoryVN[GcHeap]);
3274
3275         if (arrElemType == TYP_STRUCT)
3276         {
3277             printf("%s[]).\n", eeGetClassName(elemTypeEq));
3278         }
3279         else
3280         {
3281             printf("%s[]).\n", varTypeName(arrElemType));
3282         }
3283         printf("  hAtArrTypeAtArr " FMT_VN " is MapSelect(hAtArrType(" FMT_VN "), arr=" FMT_VN ")\n", hAtArrTypeAtArr,
3284                hAtArrType, arrVN);
3285         printf("  hAtArrTypeAtArrAtInx " FMT_VN " is MapSelect(hAtArrTypeAtArr(" FMT_VN "), inx=" FMT_VN "):%s\n",
3286                hAtArrTypeAtArrAtInx, hAtArrTypeAtArr, inxVN, varTypeName(arrElemType));
3287
3288         if (!invalidateArray)
3289         {
3290             printf("  newValAtInd " FMT_VN " is ", newValAtInx);
3291             vnStore->vnDump(this, newValAtInx);
3292             printf("\n");
3293
3294             printf("  newValAtArr " FMT_VN " is ", newValAtArr);
3295             vnStore->vnDump(this, newValAtArr);
3296             printf("\n");
3297         }
3298
3299         printf("  newValAtArrType " FMT_VN " is ", newValAtArrType);
3300         vnStore->vnDump(this, newValAtArrType);
3301         printf("\n");
3302     }
3303 #endif // DEBUG
3304
3305     return vnStore->VNForMapStore(TYP_REF, fgCurMemoryVN[GcHeap], elemTypeEqVN, newValAtArrType);
3306 }
3307
3308 ValueNum Compiler::fgValueNumberArrIndexVal(GenTree* tree, VNFuncApp* pFuncApp, ValueNum addrXvn)
3309 {
3310     assert(vnStore->IsVNHandle(pFuncApp->m_args[0]));
3311     CORINFO_CLASS_HANDLE arrElemTypeEQ = CORINFO_CLASS_HANDLE(vnStore->ConstantValue<ssize_t>(pFuncApp->m_args[0]));
3312     ValueNum             arrVN         = pFuncApp->m_args[1];
3313     ValueNum             inxVN         = pFuncApp->m_args[2];
3314     FieldSeqNode*        fldSeq        = vnStore->FieldSeqVNToFieldSeq(pFuncApp->m_args[3]);
3315     return fgValueNumberArrIndexVal(tree, arrElemTypeEQ, arrVN, inxVN, addrXvn, fldSeq);
3316 }
3317
3318 ValueNum Compiler::fgValueNumberArrIndexVal(GenTree*             tree,
3319                                             CORINFO_CLASS_HANDLE elemTypeEq,
3320                                             ValueNum             arrVN,
3321                                             ValueNum             inxVN,
3322                                             ValueNum             excVN,
3323                                             FieldSeqNode*        fldSeq)
3324 {
3325     assert(tree == nullptr || tree->OperIsIndir());
3326
3327     // The VN inputs are required to be non-exceptional values.
3328     assert(arrVN == vnStore->VNNormVal(arrVN));
3329     assert(inxVN == vnStore->VNNormVal(inxVN));
3330
3331     var_types elemTyp = DecodeElemType(elemTypeEq);
3332     var_types indType = (tree == nullptr) ? elemTyp : tree->TypeGet();
3333     ValueNum  selectedElem;
3334
3335     if (fldSeq == FieldSeqStore::NotAField())
3336     {
3337         // This doesn't represent a proper array access
3338         JITDUMP("    *** NotAField sequence encountered in fgValueNumberArrIndexVal\n");
3339
3340         // a new unique value number
3341         selectedElem = vnStore->VNForExpr(compCurBB, elemTyp);
3342
3343 #ifdef DEBUG
3344         if (verbose)
3345         {
3346             printf("  IND of PtrToArrElem is unique VN " FMT_VN ".\n", selectedElem);
3347         }
3348 #endif // DEBUG
3349
3350         if (tree != nullptr)
3351         {
3352             tree->gtVNPair.SetBoth(selectedElem);
3353         }
3354     }
3355     else
3356     {
3357         ValueNum elemTypeEqVN    = vnStore->VNForHandle(ssize_t(elemTypeEq), GTF_ICON_CLASS_HDL);
3358         ValueNum hAtArrType      = vnStore->VNForMapSelect(VNK_Liberal, TYP_REF, fgCurMemoryVN[GcHeap], elemTypeEqVN);
3359         ValueNum hAtArrTypeAtArr = vnStore->VNForMapSelect(VNK_Liberal, TYP_REF, hAtArrType, arrVN);
3360         ValueNum wholeElem       = vnStore->VNForMapSelect(VNK_Liberal, elemTyp, hAtArrTypeAtArr, inxVN);
3361
3362 #ifdef DEBUG
3363         if (verbose)
3364         {
3365             printf("  hAtArrType " FMT_VN " is MapSelect(curGcHeap(" FMT_VN "), ", hAtArrType, fgCurMemoryVN[GcHeap]);
3366             if (elemTyp == TYP_STRUCT)
3367             {
3368                 printf("%s[]).\n", eeGetClassName(elemTypeEq));
3369             }
3370             else
3371             {
3372                 printf("%s[]).\n", varTypeName(elemTyp));
3373             }
3374
3375             printf("  hAtArrTypeAtArr " FMT_VN " is MapSelect(hAtArrType(" FMT_VN "), arr=" FMT_VN ").\n",
3376                    hAtArrTypeAtArr, hAtArrType, arrVN);
3377
3378             printf("  wholeElem " FMT_VN " is MapSelect(hAtArrTypeAtArr(" FMT_VN "), ind=" FMT_VN ").\n", wholeElem,
3379                    hAtArrTypeAtArr, inxVN);
3380         }
3381 #endif // DEBUG
3382
3383         selectedElem          = wholeElem;
3384         size_t elemStructSize = 0;
3385         if (fldSeq)
3386         {
3387             selectedElem = vnStore->VNApplySelectors(VNK_Liberal, wholeElem, fldSeq, &elemStructSize);
3388             elemTyp      = vnStore->TypeOfVN(selectedElem);
3389         }
3390         selectedElem = vnStore->VNApplySelectorsTypeCheck(selectedElem, indType, elemStructSize);
3391         selectedElem = vnStore->VNWithExc(selectedElem, excVN);
3392
3393 #ifdef DEBUG
3394         if (verbose && (selectedElem != wholeElem))
3395         {
3396             printf("  selectedElem is " FMT_VN " after applying selectors.\n", selectedElem);
3397         }
3398 #endif // DEBUG
3399
3400         if (tree != nullptr)
3401         {
3402             tree->gtVNPair.SetLiberal(selectedElem);
3403             // TODO-CQ: what to do here about exceptions?  We don't have the array and ind conservative
3404             // values, so we don't have their exceptions.  Maybe we should.
3405             tree->gtVNPair.SetConservative(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
3406         }
3407     }
3408
3409     return selectedElem;
3410 }
3411
3412 ValueNum Compiler::fgValueNumberByrefExposedLoad(var_types type, ValueNum pointerVN)
3413 {
3414     ValueNum memoryVN = fgCurMemoryVN[ByrefExposed];
3415     // The memoization for VNFunc applications does not factor in the result type, so
3416     // VNF_ByrefExposedLoad takes the loaded type as an explicit parameter.
3417     ValueNum typeVN = vnStore->VNForIntCon(type);
3418     ValueNum loadVN = vnStore->VNForFunc(type, VNF_ByrefExposedLoad, typeVN, vnStore->VNNormVal(pointerVN), memoryVN);
3419
3420     return loadVN;
3421 }
3422
3423 var_types ValueNumStore::TypeOfVN(ValueNum vn)
3424 {
3425     if (vn == NoVN)
3426     {
3427         return TYP_UNDEF;
3428     }
3429
3430     Chunk* c = m_chunks.GetNoExpand(GetChunkNum(vn));
3431     return c->m_typ;
3432 }
3433
3434 //------------------------------------------------------------------------
3435 // LoopOfVN: If the given value number is an opaque one associated with a particular
3436 //    expression in the IR, give the loop number where the expression occurs; otherwise,
3437 //    returns MAX_LOOP_NUM.
3438 //
3439 // Arguments:
3440 //    vn - Value number to query
3441 //
3442 // Return Value:
3443 //    The correspondingblock's bbNatLoopNum, which may be BasicBlock::NOT_IN_LOOP.
3444 //    Returns MAX_LOOP_NUM if this VN is not an opaque value number associated with
3445 //    a particular expression/location in the IR.
3446
3447 BasicBlock::loopNumber ValueNumStore::LoopOfVN(ValueNum vn)
3448 {
3449     if (vn == NoVN)
3450     {
3451         return MAX_LOOP_NUM;
3452     }
3453
3454     Chunk* c = m_chunks.GetNoExpand(GetChunkNum(vn));
3455     return c->m_loopNum;
3456 }
3457
3458 bool ValueNumStore::IsVNConstant(ValueNum vn)
3459 {
3460     if (vn == NoVN)
3461     {
3462         return false;
3463     }
3464     Chunk* c = m_chunks.GetNoExpand(GetChunkNum(vn));
3465     if (c->m_attribs == CEA_Const)
3466     {
3467         return vn != VNForVoid(); // Void is not a "real" constant -- in the sense that it represents no value.
3468     }
3469     else
3470     {
3471         return c->m_attribs == CEA_Handle;
3472     }
3473 }
3474
3475 bool ValueNumStore::IsVNInt32Constant(ValueNum vn)
3476 {
3477     if (!IsVNConstant(vn))
3478     {
3479         return false;
3480     }
3481
3482     return TypeOfVN(vn) == TYP_INT;
3483 }
3484
3485 unsigned ValueNumStore::GetHandleFlags(ValueNum vn)
3486 {
3487     assert(IsVNHandle(vn));
3488     Chunk*    c      = m_chunks.GetNoExpand(GetChunkNum(vn));
3489     unsigned  offset = ChunkOffset(vn);
3490     VNHandle* handle = &reinterpret_cast<VNHandle*>(c->m_defs)[offset];
3491     return handle->m_flags;
3492 }
3493
3494 bool ValueNumStore::IsVNHandle(ValueNum vn)
3495 {
3496     if (vn == NoVN)
3497     {
3498         return false;
3499     }
3500
3501     Chunk* c = m_chunks.GetNoExpand(GetChunkNum(vn));
3502     return c->m_attribs == CEA_Handle;
3503 }
3504
3505 bool ValueNumStore::IsVNConstantBound(ValueNum vn)
3506 {
3507     // Do we have "var < 100"?
3508     if (vn == NoVN)
3509     {
3510         return false;
3511     }
3512
3513     VNFuncApp funcAttr;
3514     if (!GetVNFunc(vn, &funcAttr))
3515     {
3516         return false;
3517     }
3518     if (funcAttr.m_func != (VNFunc)GT_LE && funcAttr.m_func != (VNFunc)GT_GE && funcAttr.m_func != (VNFunc)GT_LT &&
3519         funcAttr.m_func != (VNFunc)GT_GT)
3520     {
3521         return false;
3522     }
3523
3524     return IsVNInt32Constant(funcAttr.m_args[0]) != IsVNInt32Constant(funcAttr.m_args[1]);
3525 }
3526
3527 void ValueNumStore::GetConstantBoundInfo(ValueNum vn, ConstantBoundInfo* info)
3528 {
3529     assert(IsVNConstantBound(vn));
3530     assert(info);
3531
3532     // Do we have var < 100?
3533     VNFuncApp funcAttr;
3534     GetVNFunc(vn, &funcAttr);
3535
3536     bool isOp1Const = IsVNInt32Constant(funcAttr.m_args[1]);
3537
3538     if (isOp1Const)
3539     {
3540         info->cmpOper  = funcAttr.m_func;
3541         info->cmpOpVN  = funcAttr.m_args[0];
3542         info->constVal = GetConstantInt32(funcAttr.m_args[1]);
3543     }
3544     else
3545     {
3546         info->cmpOper  = GenTree::SwapRelop((genTreeOps)funcAttr.m_func);
3547         info->cmpOpVN  = funcAttr.m_args[1];
3548         info->constVal = GetConstantInt32(funcAttr.m_args[0]);
3549     }
3550 }
3551
3552 //------------------------------------------------------------------------
3553 // IsVNArrLenUnsignedBound: Checks if the specified vn represents an expression
3554 //    such as "(uint)i < (uint)len" that implies that the index is valid
3555 //    (0 <= i && i < a.len).
3556 //
3557 // Arguments:
3558 //    vn - Value number to query
3559 //    info - Pointer to an UnsignedCompareCheckedBoundInfo object to return information about
3560 //           the expression. Not populated if the vn expression isn't suitable (e.g. i <= len).
3561 //           This enables optCreateJTrueBoundAssertion to immediatly create an OAK_NO_THROW
3562 //           assertion instead of the OAK_EQUAL/NOT_EQUAL assertions created by signed compares
3563 //           (IsVNCompareCheckedBound, IsVNCompareCheckedBoundArith) that require further processing.
3564
3565 bool ValueNumStore::IsVNUnsignedCompareCheckedBound(ValueNum vn, UnsignedCompareCheckedBoundInfo* info)
3566 {
3567     VNFuncApp funcApp;
3568
3569     if (GetVNFunc(vn, &funcApp))
3570     {
3571         if ((funcApp.m_func == VNF_LT_UN) || (funcApp.m_func == VNF_GE_UN))
3572         {
3573             // We only care about "(uint)i < (uint)len" and its negation "(uint)i >= (uint)len"
3574             if (IsVNCheckedBound(funcApp.m_args[1]))
3575             {
3576                 info->vnIdx   = funcApp.m_args[0];
3577                 info->cmpOper = funcApp.m_func;
3578                 info->vnBound = funcApp.m_args[1];
3579                 return true;
3580             }
3581         }
3582         else if ((funcApp.m_func == VNF_GT_UN) || (funcApp.m_func == VNF_LE_UN))
3583         {
3584             // We only care about "(uint)a.len > (uint)i" and its negation "(uint)a.len <= (uint)i"
3585             if (IsVNCheckedBound(funcApp.m_args[0]))
3586             {
3587                 info->vnIdx = funcApp.m_args[1];
3588                 // Let's keep a consistent operand order - it's always i < len, never len > i
3589                 info->cmpOper = (funcApp.m_func == VNF_GT_UN) ? VNF_LT_UN : VNF_GE_UN;
3590                 info->vnBound = funcApp.m_args[0];
3591                 return true;
3592             }
3593         }
3594     }
3595
3596     return false;
3597 }
3598
3599 bool ValueNumStore::IsVNCompareCheckedBound(ValueNum vn)
3600 {
3601     // Do we have "var < len"?
3602     if (vn == NoVN)
3603     {
3604         return false;
3605     }
3606
3607     VNFuncApp funcAttr;
3608     if (!GetVNFunc(vn, &funcAttr))
3609     {
3610         return false;
3611     }
3612     if (funcAttr.m_func != (VNFunc)GT_LE && funcAttr.m_func != (VNFunc)GT_GE && funcAttr.m_func != (VNFunc)GT_LT &&
3613         funcAttr.m_func != (VNFunc)GT_GT)
3614     {
3615         return false;
3616     }
3617     if (!IsVNCheckedBound(funcAttr.m_args[0]) && !IsVNCheckedBound(funcAttr.m_args[1]))
3618     {
3619         return false;
3620     }
3621
3622     return true;
3623 }
3624
3625 void ValueNumStore::GetCompareCheckedBound(ValueNum vn, CompareCheckedBoundArithInfo* info)
3626 {
3627     assert(IsVNCompareCheckedBound(vn));
3628
3629     // Do we have var < a.len?
3630     VNFuncApp funcAttr;
3631     GetVNFunc(vn, &funcAttr);
3632
3633     bool isOp1CheckedBound = IsVNCheckedBound(funcAttr.m_args[1]);
3634     if (isOp1CheckedBound)
3635     {
3636         info->cmpOper = funcAttr.m_func;
3637         info->cmpOp   = funcAttr.m_args[0];
3638         info->vnBound = funcAttr.m_args[1];
3639     }
3640     else
3641     {
3642         info->cmpOper = GenTree::SwapRelop((genTreeOps)funcAttr.m_func);
3643         info->cmpOp   = funcAttr.m_args[1];
3644         info->vnBound = funcAttr.m_args[0];
3645     }
3646 }
3647
3648 bool ValueNumStore::IsVNCheckedBoundArith(ValueNum vn)
3649 {
3650     // Do we have "a.len +or- var"
3651     if (vn == NoVN)
3652     {
3653         return false;
3654     }
3655
3656     VNFuncApp funcAttr;
3657
3658     return GetVNFunc(vn, &funcAttr) &&                                                     // vn is a func.
3659            (funcAttr.m_func == (VNFunc)GT_ADD || funcAttr.m_func == (VNFunc)GT_SUB) &&     // the func is +/-
3660            (IsVNCheckedBound(funcAttr.m_args[0]) || IsVNCheckedBound(funcAttr.m_args[1])); // either op1 or op2 is a.len
3661 }
3662
3663 void ValueNumStore::GetCheckedBoundArithInfo(ValueNum vn, CompareCheckedBoundArithInfo* info)
3664 {
3665     // Do we have a.len +/- var?
3666     assert(IsVNCheckedBoundArith(vn));
3667     VNFuncApp funcArith;
3668     GetVNFunc(vn, &funcArith);
3669
3670     bool isOp1CheckedBound = IsVNCheckedBound(funcArith.m_args[1]);
3671     if (isOp1CheckedBound)
3672     {
3673         info->arrOper = funcArith.m_func;
3674         info->arrOp   = funcArith.m_args[0];
3675         info->vnBound = funcArith.m_args[1];
3676     }
3677     else
3678     {
3679         info->arrOper = funcArith.m_func;
3680         info->arrOp   = funcArith.m_args[1];
3681         info->vnBound = funcArith.m_args[0];
3682     }
3683 }
3684
3685 bool ValueNumStore::IsVNCompareCheckedBoundArith(ValueNum vn)
3686 {
3687     // Do we have: "var < a.len - var"
3688     if (vn == NoVN)
3689     {
3690         return false;
3691     }
3692
3693     VNFuncApp funcAttr;
3694     if (!GetVNFunc(vn, &funcAttr))
3695     {
3696         return false;
3697     }
3698
3699     // Suitable comparator.
3700     if (funcAttr.m_func != (VNFunc)GT_LE && funcAttr.m_func != (VNFunc)GT_GE && funcAttr.m_func != (VNFunc)GT_LT &&
3701         funcAttr.m_func != (VNFunc)GT_GT)
3702     {
3703         return false;
3704     }
3705
3706     // Either the op0 or op1 is arr len arithmetic.
3707     if (!IsVNCheckedBoundArith(funcAttr.m_args[0]) && !IsVNCheckedBoundArith(funcAttr.m_args[1]))
3708     {
3709         return false;
3710     }
3711
3712     return true;
3713 }
3714
3715 void ValueNumStore::GetCompareCheckedBoundArithInfo(ValueNum vn, CompareCheckedBoundArithInfo* info)
3716 {
3717     assert(IsVNCompareCheckedBoundArith(vn));
3718
3719     VNFuncApp funcAttr;
3720     GetVNFunc(vn, &funcAttr);
3721
3722     // Check whether op0 or op1 is checked bound arithmetic.
3723     bool isOp1CheckedBoundArith = IsVNCheckedBoundArith(funcAttr.m_args[1]);
3724     if (isOp1CheckedBoundArith)
3725     {
3726         info->cmpOper = funcAttr.m_func;
3727         info->cmpOp   = funcAttr.m_args[0];
3728         GetCheckedBoundArithInfo(funcAttr.m_args[1], info);
3729     }
3730     else
3731     {
3732         info->cmpOper = GenTree::SwapRelop((genTreeOps)funcAttr.m_func);
3733         info->cmpOp   = funcAttr.m_args[1];
3734         GetCheckedBoundArithInfo(funcAttr.m_args[0], info);
3735     }
3736 }
3737
3738 ValueNum ValueNumStore::GetArrForLenVn(ValueNum vn)
3739 {
3740     if (vn == NoVN)
3741     {
3742         return NoVN;
3743     }
3744
3745     VNFuncApp funcAttr;
3746     if (GetVNFunc(vn, &funcAttr) && funcAttr.m_func == (VNFunc)GT_ARR_LENGTH)
3747     {
3748         return funcAttr.m_args[0];
3749     }
3750     return NoVN;
3751 }
3752
3753 bool ValueNumStore::IsVNNewArr(ValueNum vn, VNFuncApp* funcApp)
3754 {
3755     if (vn == NoVN)
3756     {
3757         return false;
3758     }
3759     bool result = false;
3760     if (GetVNFunc(vn, funcApp))
3761     {
3762         result = (funcApp->m_func == VNF_JitNewArr) || (funcApp->m_func == VNF_JitReadyToRunNewArr);
3763     }
3764     return result;
3765 }
3766
3767 int ValueNumStore::GetNewArrSize(ValueNum vn)
3768 {
3769     VNFuncApp funcApp;
3770     if (IsVNNewArr(vn, &funcApp))
3771     {
3772         ValueNum arg1VN = funcApp.m_args[1];
3773         if (IsVNConstant(arg1VN) && TypeOfVN(arg1VN) == TYP_INT)
3774         {
3775             return ConstantValue<int>(arg1VN);
3776         }
3777     }
3778     return 0;
3779 }
3780
3781 bool ValueNumStore::IsVNArrLen(ValueNum vn)
3782 {
3783     if (vn == NoVN)
3784     {
3785         return false;
3786     }
3787     VNFuncApp funcAttr;
3788     return (GetVNFunc(vn, &funcAttr) && funcAttr.m_func == (VNFunc)GT_ARR_LENGTH);
3789 }
3790
3791 bool ValueNumStore::IsVNCheckedBound(ValueNum vn)
3792 {
3793     bool dummy;
3794     if (m_checkedBoundVNs.TryGetValue(vn, &dummy))
3795     {
3796         // This VN appeared as the conservative VN of the length argument of some
3797         // GT_ARR_BOUND node.
3798         return true;
3799     }
3800     if (IsVNArrLen(vn))
3801     {
3802         // Even if we haven't seen this VN in a bounds check, if it is an array length
3803         // VN then consider it a checked bound VN.  This facilitates better bounds check
3804         // removal by ensuring that compares against array lengths get put in the
3805         // optCseCheckedBoundMap; such an array length might get CSEd with one that was
3806         // directly used in a bounds check, and having the map entry will let us update
3807         // the compare's VN so that OptimizeRangeChecks can recognize such compares.
3808         return true;
3809     }
3810
3811     return false;
3812 }
3813
3814 void ValueNumStore::SetVNIsCheckedBound(ValueNum vn)
3815 {
3816     // This is meant to flag VNs for lengths that aren't known at compile time, so we can
3817     // form and propagate assertions about them.  Ensure that callers filter out constant
3818     // VNs since they're not what we're looking to flag, and assertion prop can reason
3819     // directly about constants.
3820     assert(!IsVNConstant(vn));
3821     m_checkedBoundVNs.AddOrUpdate(vn, true);
3822 }
3823
3824 ValueNum ValueNumStore::EvalMathFuncUnary(var_types typ, CorInfoIntrinsics gtMathFN, ValueNum arg0VN)
3825 {
3826     assert(arg0VN == VNNormVal(arg0VN));
3827
3828     // If the math intrinsic is not implemented by target-specific instructions, such as implemented
3829     // by user calls, then don't do constant folding on it. This minimizes precision loss.
3830
3831     if (IsVNConstant(arg0VN) && m_pComp->IsTargetIntrinsic(gtMathFN))
3832     {
3833         assert(varTypeIsFloating(TypeOfVN(arg0VN)));
3834
3835         if (typ == TYP_DOUBLE)
3836         {
3837             // Both operand and its result must be of the same floating point type.
3838             assert(typ == TypeOfVN(arg0VN));
3839             double arg0Val = GetConstantDouble(arg0VN);
3840
3841             double res = 0.0;
3842             switch (gtMathFN)
3843             {
3844                 case CORINFO_INTRINSIC_Sin:
3845                     res = sin(arg0Val);
3846                     break;
3847                 case CORINFO_INTRINSIC_Cos:
3848                     res = cos(arg0Val);
3849                     break;
3850                 case CORINFO_INTRINSIC_Sqrt:
3851                     res = sqrt(arg0Val);
3852                     break;
3853                 case CORINFO_INTRINSIC_Abs:
3854                     res = fabs(arg0Val);
3855                     break;
3856                 case CORINFO_INTRINSIC_Ceiling:
3857                     res = ceil(arg0Val);
3858                     break;
3859                 case CORINFO_INTRINSIC_Floor:
3860                     res = floor(arg0Val);
3861                     break;
3862                 case CORINFO_INTRINSIC_Round:
3863                     res = FloatingPointUtils::round(arg0Val);
3864                     break;
3865                 default:
3866                     unreached(); // the above are the only math intrinsics at the time of this writing.
3867             }
3868
3869             return VNForDoubleCon(res);
3870         }
3871         else if (typ == TYP_FLOAT)
3872         {
3873             // Both operand and its result must be of the same floating point type.
3874             assert(typ == TypeOfVN(arg0VN));
3875             float arg0Val = GetConstantSingle(arg0VN);
3876
3877             float res = 0.0f;
3878             switch (gtMathFN)
3879             {
3880                 case CORINFO_INTRINSIC_Sin:
3881                     res = sinf(arg0Val);
3882                     break;
3883                 case CORINFO_INTRINSIC_Cos:
3884                     res = cosf(arg0Val);
3885                     break;
3886                 case CORINFO_INTRINSIC_Sqrt:
3887                     res = sqrtf(arg0Val);
3888                     break;
3889                 case CORINFO_INTRINSIC_Abs:
3890                     res = fabsf(arg0Val);
3891                     break;
3892                 case CORINFO_INTRINSIC_Ceiling:
3893                     res = ceilf(arg0Val);
3894                     break;
3895                 case CORINFO_INTRINSIC_Floor:
3896                     res = floorf(arg0Val);
3897                     break;
3898                 case CORINFO_INTRINSIC_Round:
3899                     res = FloatingPointUtils::round(arg0Val);
3900                     break;
3901                 default:
3902                     unreached(); // the above are the only math intrinsics at the time of this writing.
3903             }
3904
3905             return VNForFloatCon(res);
3906         }
3907         else
3908         {
3909             // CORINFO_INTRINSIC_Round is currently the only intrinsic that takes floating-point arguments
3910             // and that returns a non floating-point result.
3911
3912             assert(typ == TYP_INT);
3913             assert(gtMathFN == CORINFO_INTRINSIC_Round);
3914
3915             int res = 0;
3916
3917             switch (TypeOfVN(arg0VN))
3918             {
3919                 case TYP_DOUBLE:
3920                 {
3921                     double arg0Val = GetConstantDouble(arg0VN);
3922                     res            = int(FloatingPointUtils::round(arg0Val));
3923                     break;
3924                 }
3925                 case TYP_FLOAT:
3926                 {
3927                     float arg0Val = GetConstantSingle(arg0VN);
3928                     res           = int(FloatingPointUtils::round(arg0Val));
3929                     break;
3930                 }
3931                 default:
3932                     unreached();
3933             }
3934
3935             return VNForIntCon(res);
3936         }
3937     }
3938     else
3939     {
3940         assert(typ == TYP_DOUBLE || typ == TYP_FLOAT || (typ == TYP_INT && gtMathFN == CORINFO_INTRINSIC_Round));
3941
3942         VNFunc vnf = VNF_Boundary;
3943         switch (gtMathFN)
3944         {
3945             case CORINFO_INTRINSIC_Sin:
3946                 vnf = VNF_Sin;
3947                 break;
3948             case CORINFO_INTRINSIC_Cos:
3949                 vnf = VNF_Cos;
3950                 break;
3951             case CORINFO_INTRINSIC_Cbrt:
3952                 vnf = VNF_Cbrt;
3953                 break;
3954             case CORINFO_INTRINSIC_Sqrt:
3955                 vnf = VNF_Sqrt;
3956                 break;
3957             case CORINFO_INTRINSIC_Abs:
3958                 vnf = VNF_Abs;
3959                 break;
3960             case CORINFO_INTRINSIC_Round:
3961                 if (typ == TYP_DOUBLE)
3962                 {
3963                     vnf = VNF_RoundDouble;
3964                 }
3965                 else if (typ == TYP_FLOAT)
3966                 {
3967                     vnf = VNF_RoundFloat;
3968                 }
3969                 else if (typ == TYP_INT)
3970                 {
3971                     vnf = VNF_RoundInt;
3972                 }
3973                 else
3974                 {
3975                     noway_assert(!"Invalid INTRINSIC_Round");
3976                 }
3977                 break;
3978             case CORINFO_INTRINSIC_Cosh:
3979                 vnf = VNF_Cosh;
3980                 break;
3981             case CORINFO_INTRINSIC_Sinh:
3982                 vnf = VNF_Sinh;
3983                 break;
3984             case CORINFO_INTRINSIC_Tan:
3985                 vnf = VNF_Tan;
3986                 break;
3987             case CORINFO_INTRINSIC_Tanh:
3988                 vnf = VNF_Tanh;
3989                 break;
3990             case CORINFO_INTRINSIC_Asin:
3991                 vnf = VNF_Asin;
3992                 break;
3993             case CORINFO_INTRINSIC_Asinh:
3994                 vnf = VNF_Asinh;
3995                 break;
3996             case CORINFO_INTRINSIC_Acos:
3997                 vnf = VNF_Acos;
3998                 break;
3999             case CORINFO_INTRINSIC_Acosh:
4000                 vnf = VNF_Acosh;
4001                 break;
4002             case CORINFO_INTRINSIC_Atan:
4003                 vnf = VNF_Atan;
4004                 break;
4005             case CORINFO_INTRINSIC_Atanh:
4006                 vnf = VNF_Atanh;
4007                 break;
4008             case CORINFO_INTRINSIC_Log10:
4009                 vnf = VNF_Log10;
4010                 break;
4011             case CORINFO_INTRINSIC_Exp:
4012                 vnf = VNF_Exp;
4013                 break;
4014             case CORINFO_INTRINSIC_Ceiling:
4015                 vnf = VNF_Ceiling;
4016                 break;
4017             case CORINFO_INTRINSIC_Floor:
4018                 vnf = VNF_Floor;
4019                 break;
4020             default:
4021                 unreached(); // the above are the only math intrinsics at the time of this writing.
4022         }
4023
4024         return VNForFunc(typ, vnf, arg0VN);
4025     }
4026 }
4027
4028 ValueNum ValueNumStore::EvalMathFuncBinary(var_types typ, CorInfoIntrinsics gtMathFN, ValueNum arg0VN, ValueNum arg1VN)
4029 {
4030     assert(varTypeIsFloating(typ));
4031     assert(arg0VN == VNNormVal(arg0VN));
4032     assert(arg1VN == VNNormVal(arg1VN));
4033
4034     VNFunc vnf = VNF_Boundary;
4035
4036     // Currently, none of the binary math intrinsic are implemented by target-specific instructions.
4037     // To minimize precision loss, do not do constant folding on them.
4038
4039     switch (gtMathFN)
4040     {
4041         case CORINFO_INTRINSIC_Atan2:
4042             vnf = VNF_Atan2;
4043             break;
4044
4045         case CORINFO_INTRINSIC_Pow:
4046             vnf = VNF_Pow;
4047             break;
4048
4049         default:
4050             unreached(); // the above are the only binary math intrinsics at the time of this writing.
4051     }
4052
4053     return VNForFunc(typ, vnf, arg0VN, arg1VN);
4054 }
4055
4056 bool ValueNumStore::IsVNFunc(ValueNum vn)
4057 {
4058     if (vn == NoVN)
4059     {
4060         return false;
4061     }
4062     Chunk* c = m_chunks.GetNoExpand(GetChunkNum(vn));
4063     switch (c->m_attribs)
4064     {
4065         case CEA_NotAField:
4066         case CEA_Func0:
4067         case CEA_Func1:
4068         case CEA_Func2:
4069         case CEA_Func3:
4070         case CEA_Func4:
4071             return true;
4072         default:
4073             return false;
4074     }
4075 }
4076
4077 bool ValueNumStore::GetVNFunc(ValueNum vn, VNFuncApp* funcApp)
4078 {
4079     if (vn == NoVN)
4080     {
4081         return false;
4082     }
4083
4084     Chunk*   c      = m_chunks.GetNoExpand(GetChunkNum(vn));
4085     unsigned offset = ChunkOffset(vn);
4086     assert(offset < c->m_numUsed);
4087     switch (c->m_attribs)
4088     {
4089         case CEA_Func4:
4090         {
4091             VNDefFunc4Arg* farg4 = &reinterpret_cast<VNDefFunc4Arg*>(c->m_defs)[offset];
4092             funcApp->m_func      = farg4->m_func;
4093             funcApp->m_arity     = 4;
4094             funcApp->m_args[0]   = farg4->m_arg0;
4095             funcApp->m_args[1]   = farg4->m_arg1;
4096             funcApp->m_args[2]   = farg4->m_arg2;
4097             funcApp->m_args[3]   = farg4->m_arg3;
4098             return true;
4099         }
4100         case CEA_Func3:
4101         {
4102             VNDefFunc3Arg* farg3 = &reinterpret_cast<VNDefFunc3Arg*>(c->m_defs)[offset];
4103             funcApp->m_func      = farg3->m_func;
4104             funcApp->m_arity     = 3;
4105             funcApp->m_args[0]   = farg3->m_arg0;
4106             funcApp->m_args[1]   = farg3->m_arg1;
4107             funcApp->m_args[2]   = farg3->m_arg2;
4108             return true;
4109         }
4110         case CEA_Func2:
4111         {
4112             VNDefFunc2Arg* farg2 = &reinterpret_cast<VNDefFunc2Arg*>(c->m_defs)[offset];
4113             funcApp->m_func      = farg2->m_func;
4114             funcApp->m_arity     = 2;
4115             funcApp->m_args[0]   = farg2->m_arg0;
4116             funcApp->m_args[1]   = farg2->m_arg1;
4117             return true;
4118         }
4119         case CEA_Func1:
4120         {
4121             VNDefFunc1Arg* farg1 = &reinterpret_cast<VNDefFunc1Arg*>(c->m_defs)[offset];
4122             funcApp->m_func      = farg1->m_func;
4123             funcApp->m_arity     = 1;
4124             funcApp->m_args[0]   = farg1->m_arg0;
4125             return true;
4126         }
4127         case CEA_Func0:
4128         {
4129             VNDefFunc0Arg* farg0 = &reinterpret_cast<VNDefFunc0Arg*>(c->m_defs)[offset];
4130             funcApp->m_func      = farg0->m_func;
4131             funcApp->m_arity     = 0;
4132             return true;
4133         }
4134         case CEA_NotAField:
4135         {
4136             funcApp->m_func  = VNF_NotAField;
4137             funcApp->m_arity = 0;
4138             return true;
4139         }
4140         default:
4141             return false;
4142     }
4143 }
4144
4145 ValueNum ValueNumStore::VNForRefInAddr(ValueNum vn)
4146 {
4147     var_types vnType = TypeOfVN(vn);
4148     if (vnType == TYP_REF)
4149     {
4150         return vn;
4151     }
4152     // Otherwise...
4153     assert(vnType == TYP_BYREF);
4154     VNFuncApp funcApp;
4155     if (GetVNFunc(vn, &funcApp))
4156     {
4157         assert(funcApp.m_arity == 2 && (funcApp.m_func == VNFunc(GT_ADD) || funcApp.m_func == VNFunc(GT_SUB)));
4158         var_types vnArg0Type = TypeOfVN(funcApp.m_args[0]);
4159         if (vnArg0Type == TYP_REF || vnArg0Type == TYP_BYREF)
4160         {
4161             return VNForRefInAddr(funcApp.m_args[0]);
4162         }
4163         else
4164         {
4165             assert(funcApp.m_func == VNFunc(GT_ADD) &&
4166                    (TypeOfVN(funcApp.m_args[1]) == TYP_REF || TypeOfVN(funcApp.m_args[1]) == TYP_BYREF));
4167             return VNForRefInAddr(funcApp.m_args[1]);
4168         }
4169     }
4170     else
4171     {
4172         assert(IsVNConstant(vn));
4173         return vn;
4174     }
4175 }
4176
4177 bool ValueNumStore::VNIsValid(ValueNum vn)
4178 {
4179     ChunkNum cn = GetChunkNum(vn);
4180     if (cn >= m_chunks.Size())
4181     {
4182         return false;
4183     }
4184     // Otherwise...
4185     Chunk* c = m_chunks.GetNoExpand(cn);
4186     return ChunkOffset(vn) < c->m_numUsed;
4187 }
4188
4189 #ifdef DEBUG
4190
4191 void ValueNumStore::vnDump(Compiler* comp, ValueNum vn, bool isPtr)
4192 {
4193     printf(" {");
4194     if (vn == NoVN)
4195     {
4196         printf("NoVN");
4197     }
4198     else if (IsVNHandle(vn))
4199     {
4200         ssize_t val = ConstantValue<ssize_t>(vn);
4201         printf("Hnd const: 0x%p", dspPtr(val));
4202     }
4203     else if (IsVNConstant(vn))
4204     {
4205         var_types vnt = TypeOfVN(vn);
4206         switch (vnt)
4207         {
4208             case TYP_BOOL:
4209             case TYP_BYTE:
4210             case TYP_UBYTE:
4211             case TYP_SHORT:
4212             case TYP_USHORT:
4213             case TYP_INT:
4214             case TYP_UINT:
4215             {
4216                 int val = ConstantValue<int>(vn);
4217                 if (isPtr)
4218                 {
4219                     printf("PtrCns[%p]", dspPtr(val));
4220                 }
4221                 else
4222                 {
4223                     printf("IntCns");
4224                     if ((val > -1000) && (val < 1000))
4225                     {
4226                         printf(" %ld", val);
4227                     }
4228                     else
4229                     {
4230                         printf(" 0x%X", val);
4231                     }
4232                 }
4233             }
4234             break;
4235             case TYP_LONG:
4236             case TYP_ULONG:
4237             {
4238                 INT64 val = ConstantValue<INT64>(vn);
4239                 if (isPtr)
4240                 {
4241                     printf("LngPtrCns: 0x%p", dspPtr(val));
4242                 }
4243                 else
4244                 {
4245                     printf("LngCns: ");
4246                     if ((val > -1000) && (val < 1000))
4247                     {
4248                         printf(" %ld", val);
4249                     }
4250                     else if ((val & 0xFFFFFFFF00000000LL) == 0)
4251                     {
4252                         printf(" 0x%X", val);
4253                     }
4254                     else
4255                     {
4256                         printf(" 0x%llx", val);
4257                     }
4258                 }
4259             }
4260             break;
4261             case TYP_FLOAT:
4262                 printf("FltCns[%f]", ConstantValue<float>(vn));
4263                 break;
4264             case TYP_DOUBLE:
4265                 printf("DblCns[%f]", ConstantValue<double>(vn));
4266                 break;
4267             case TYP_REF:
4268                 if (vn == VNForNull())
4269                 {
4270                     printf("null");
4271                 }
4272                 else if (vn == VNForVoid())
4273                 {
4274                     printf("void");
4275                 }
4276                 else
4277                 {
4278                     assert(vn == VNForZeroMap());
4279                     printf("zeroMap");
4280                 }
4281                 break;
4282             case TYP_BYREF:
4283                 printf("byrefVal");
4284                 break;
4285             case TYP_STRUCT:
4286 #ifdef FEATURE_SIMD
4287             case TYP_SIMD8:
4288             case TYP_SIMD12:
4289             case TYP_SIMD16:
4290             case TYP_SIMD32:
4291 #endif // FEATURE_SIMD
4292                 printf("structVal");
4293                 break;
4294
4295             // These should be unreached.
4296             default:
4297                 unreached();
4298         }
4299     }
4300     else if (IsVNCompareCheckedBound(vn))
4301     {
4302         CompareCheckedBoundArithInfo info;
4303         GetCompareCheckedBound(vn, &info);
4304         info.dump(this);
4305     }
4306     else if (IsVNCompareCheckedBoundArith(vn))
4307     {
4308         CompareCheckedBoundArithInfo info;
4309         GetCompareCheckedBoundArithInfo(vn, &info);
4310         info.dump(this);
4311     }
4312     else if (IsVNFunc(vn))
4313     {
4314         VNFuncApp funcApp;
4315         GetVNFunc(vn, &funcApp);
4316         // A few special cases...
4317         switch (funcApp.m_func)
4318         {
4319             case VNF_FieldSeq:
4320                 vnDumpFieldSeq(comp, &funcApp, true);
4321                 break;
4322             case VNF_MapSelect:
4323                 vnDumpMapSelect(comp, &funcApp);
4324                 break;
4325             case VNF_MapStore:
4326                 vnDumpMapStore(comp, &funcApp);
4327                 break;
4328             case VNF_ValWithExc:
4329                 vnDumpValWithExc(comp, &funcApp);
4330                 break;
4331             default:
4332                 printf("%s(", VNFuncName(funcApp.m_func));
4333                 for (unsigned i = 0; i < funcApp.m_arity; i++)
4334                 {
4335                     if (i > 0)
4336                     {
4337                         printf(", ");
4338                     }
4339
4340                     printf(FMT_VN, funcApp.m_args[i]);
4341
4342 #if FEATURE_VN_DUMP_FUNC_ARGS
4343                     printf("=");
4344                     vnDump(comp, funcApp.m_args[i]);
4345 #endif
4346                 }
4347                 printf(")");
4348         }
4349     }
4350     else
4351     {
4352         // Otherwise, just a VN with no structure; print just the VN.
4353         printf("%x", vn);
4354     }
4355     printf("}");
4356 }
4357
4358 // Requires "valWithExc" to be a value with an exeception set VNFuncApp.
4359 // Prints a representation of the exeception set on standard out.
4360 void ValueNumStore::vnDumpValWithExc(Compiler* comp, VNFuncApp* valWithExc)
4361 {
4362     assert(valWithExc->m_func == VNF_ValWithExc); // Precondition.
4363
4364     ValueNum normVN = valWithExc->m_args[0]; // First arg is the VN from normal execution
4365     ValueNum excVN  = valWithExc->m_args[1]; // Second arg is the set of possible exceptions
4366
4367     assert(IsVNFunc(excVN));
4368     VNFuncApp excSeq;
4369     GetVNFunc(excVN, &excSeq);
4370
4371     printf("norm=");
4372     printf(FMT_VN, normVN);
4373     vnDump(comp, normVN);
4374     printf(", exc=");
4375     printf(FMT_VN, excVN);
4376     vnDumpExcSeq(comp, &excSeq, true);
4377 }
4378
4379 // Requires "excSeq" to be a ExcSetCons sequence.
4380 // Prints a representation of the set of exceptions on standard out.
4381 void ValueNumStore::vnDumpExcSeq(Compiler* comp, VNFuncApp* excSeq, bool isHead)
4382 {
4383     assert(excSeq->m_func == VNF_ExcSetCons); // Precondition.
4384
4385     ValueNum curExc  = excSeq->m_args[0];
4386     bool     hasTail = (excSeq->m_args[1] != VNForEmptyExcSet());
4387
4388     if (isHead && hasTail)
4389     {
4390         printf("(");
4391     }
4392
4393     vnDump(comp, curExc);
4394
4395     if (hasTail)
4396     {
4397         printf(", ");
4398         assert(IsVNFunc(excSeq->m_args[1]));
4399         VNFuncApp tail;
4400         GetVNFunc(excSeq->m_args[1], &tail);
4401         vnDumpExcSeq(comp, &tail, false);
4402     }
4403
4404     if (isHead && hasTail)
4405     {
4406         printf(")");
4407     }
4408 }
4409
4410 void ValueNumStore::vnDumpFieldSeq(Compiler* comp, VNFuncApp* fieldSeq, bool isHead)
4411 {
4412     assert(fieldSeq->m_func == VNF_FieldSeq); // Precondition.
4413     // First arg is the field handle VN.
4414     assert(IsVNConstant(fieldSeq->m_args[0]) && TypeOfVN(fieldSeq->m_args[0]) == TYP_I_IMPL);
4415     ssize_t fieldHndVal = ConstantValue<ssize_t>(fieldSeq->m_args[0]);
4416     bool    hasTail     = (fieldSeq->m_args[1] != VNForNull());
4417
4418     if (isHead && hasTail)
4419     {
4420         printf("(");
4421     }
4422
4423     CORINFO_FIELD_HANDLE fldHnd = CORINFO_FIELD_HANDLE(fieldHndVal);
4424     if (fldHnd == FieldSeqStore::FirstElemPseudoField)
4425     {
4426         printf("#FirstElem");
4427     }
4428     else if (fldHnd == FieldSeqStore::ConstantIndexPseudoField)
4429     {
4430         printf("#ConstantIndex");
4431     }
4432     else
4433     {
4434         const char* modName;
4435         const char* fldName = m_pComp->eeGetFieldName(fldHnd, &modName);
4436         printf("%s", fldName);
4437     }
4438
4439     if (hasTail)
4440     {
4441         printf(", ");
4442         assert(IsVNFunc(fieldSeq->m_args[1]));
4443         VNFuncApp tail;
4444         GetVNFunc(fieldSeq->m_args[1], &tail);
4445         vnDumpFieldSeq(comp, &tail, false);
4446     }
4447
4448     if (isHead && hasTail)
4449     {
4450         printf(")");
4451     }
4452 }
4453
4454 void ValueNumStore::vnDumpMapSelect(Compiler* comp, VNFuncApp* mapSelect)
4455 {
4456     assert(mapSelect->m_func == VNF_MapSelect); // Precondition.
4457
4458     ValueNum mapVN   = mapSelect->m_args[0]; // First arg is the map id
4459     ValueNum indexVN = mapSelect->m_args[1]; // Second arg is the index
4460
4461     comp->vnPrint(mapVN, 0);
4462     printf("[");
4463     comp->vnPrint(indexVN, 0);
4464     printf("]");
4465 }
4466
4467 void ValueNumStore::vnDumpMapStore(Compiler* comp, VNFuncApp* mapStore)
4468 {
4469     assert(mapStore->m_func == VNF_MapStore); // Precondition.
4470
4471     ValueNum mapVN    = mapStore->m_args[0]; // First arg is the map id
4472     ValueNum indexVN  = mapStore->m_args[1]; // Second arg is the index
4473     ValueNum newValVN = mapStore->m_args[2]; // Third arg is the new value
4474
4475     comp->vnPrint(mapVN, 0);
4476     printf("[");
4477     comp->vnPrint(indexVN, 0);
4478     printf(" := ");
4479     comp->vnPrint(newValVN, 0);
4480     printf("]");
4481 }
4482 #endif // DEBUG
4483
4484 // Static fields, methods.
4485 static UINT8      vnfOpAttribs[VNF_COUNT];
4486 static genTreeOps genTreeOpsIllegalAsVNFunc[] = {GT_IND, // When we do heap memory.
4487                                                  GT_NULLCHECK, GT_QMARK, GT_COLON, GT_LOCKADD, GT_XADD, GT_XCHG,
4488                                                  GT_CMPXCHG, GT_LCLHEAP, GT_BOX,
4489
4490                                                  // These need special semantics:
4491                                                  GT_COMMA, // == second argument (but with exception(s) from first).
4492                                                  GT_ADDR, GT_ARR_BOUNDS_CHECK,
4493                                                  GT_OBJ,      // May reference heap memory.
4494                                                  GT_BLK,      // May reference heap memory.
4495                                                  GT_INIT_VAL, // Not strictly a pass-through.
4496
4497                                                  // These control-flow operations need no values.
4498                                                  GT_JTRUE, GT_RETURN, GT_SWITCH, GT_RETFILT, GT_CKFINITE};
4499
4500 UINT8* ValueNumStore::s_vnfOpAttribs = nullptr;
4501
4502 void ValueNumStore::InitValueNumStoreStatics()
4503 {
4504     // Make sure we've gotten constants right...
4505     assert(unsigned(VNFOA_Arity) == (1 << VNFOA_ArityShift));
4506     assert(unsigned(VNFOA_AfterArity) == (unsigned(VNFOA_Arity) << VNFOA_ArityBits));
4507
4508     s_vnfOpAttribs = &vnfOpAttribs[0];
4509     for (unsigned i = 0; i < GT_COUNT; i++)
4510     {
4511         genTreeOps gtOper = static_cast<genTreeOps>(i);
4512         unsigned   arity  = 0;
4513         if (GenTree::OperIsUnary(gtOper))
4514         {
4515             arity = 1;
4516         }
4517         else if (GenTree::OperIsBinary(gtOper))
4518         {
4519             arity = 2;
4520         }
4521         // Since GT_ARR_BOUNDS_CHECK is not currently GTK_BINOP
4522         else if (gtOper == GT_ARR_BOUNDS_CHECK)
4523         {
4524             arity = 2;
4525         }
4526         vnfOpAttribs[i] |= (arity << VNFOA_ArityShift);
4527
4528         if (GenTree::OperIsCommutative(gtOper))
4529         {
4530             vnfOpAttribs[i] |= VNFOA_Commutative;
4531         }
4532     }
4533
4534     // I so wish this wasn't the best way to do this...
4535
4536     int vnfNum = VNF_Boundary + 1; // The macro definition below will update this after using it.
4537
4538 #define ValueNumFuncDef(vnf, arity, commute, knownNonNull, sharedStatic)                                               \
4539     if (commute)                                                                                                       \
4540         vnfOpAttribs[vnfNum] |= VNFOA_Commutative;                                                                     \
4541     if (knownNonNull)                                                                                                  \
4542         vnfOpAttribs[vnfNum] |= VNFOA_KnownNonNull;                                                                    \
4543     if (sharedStatic)                                                                                                  \
4544         vnfOpAttribs[vnfNum] |= VNFOA_SharedStatic;                                                                    \
4545     vnfOpAttribs[vnfNum] |= (arity << VNFOA_ArityShift);                                                               \
4546     vnfNum++;
4547
4548 #include "valuenumfuncs.h"
4549 #undef ValueNumFuncDef
4550
4551     for (unsigned i = 0; i < _countof(genTreeOpsIllegalAsVNFunc); i++)
4552     {
4553         vnfOpAttribs[genTreeOpsIllegalAsVNFunc[i]] |= VNFOA_IllegalGenTreeOp;
4554     }
4555 }
4556
4557 #ifdef DEBUG
4558 // Define the name array.
4559 #define ValueNumFuncDef(vnf, arity, commute, knownNonNull, sharedStatic) #vnf,
4560
4561 const char* ValueNumStore::VNFuncNameArr[] = {
4562 #include "valuenumfuncs.h"
4563 #undef ValueNumFuncDef
4564 };
4565
4566 // static
4567 const char* ValueNumStore::VNFuncName(VNFunc vnf)
4568 {
4569     if (vnf < VNF_Boundary)
4570     {
4571         return GenTree::OpName(genTreeOps(vnf));
4572     }
4573     else
4574     {
4575         return VNFuncNameArr[vnf - (VNF_Boundary + 1)];
4576     }
4577 }
4578
4579 static const char* s_reservedNameArr[] = {
4580     "$VN.Recursive",    // -2  RecursiveVN
4581     "$VN.No",           // -1  NoVN
4582     "$VN.Null",         //  0  VNForNull()
4583     "$VN.ZeroMap",      //  1  VNForZeroMap()
4584     "$VN.ReadOnlyHeap", //  2  VNForROH()
4585     "$VN.Void",         //  3  VNForVoid()
4586     "$VN.EmptyExcSet"   //  4  VNForEmptyExcSet()
4587 };
4588
4589 // Returns the string name of "vn" when it is a reserved value number, nullptr otherwise
4590 // static
4591 const char* ValueNumStore::reservedName(ValueNum vn)
4592 {
4593     int val = vn - ValueNumStore::RecursiveVN; // Add two, making 'RecursiveVN' equal to zero
4594     int max = ValueNumStore::SRC_NumSpecialRefConsts - ValueNumStore::RecursiveVN;
4595
4596     if ((val >= 0) && (val < max))
4597     {
4598         return s_reservedNameArr[val];
4599     }
4600     return nullptr;
4601 }
4602
4603 #endif // DEBUG
4604
4605 // Returns true if "vn" is a reserved value number
4606
4607 // static
4608 bool ValueNumStore::isReservedVN(ValueNum vn)
4609 {
4610     int val = vn - ValueNumStore::RecursiveVN; // Adding two, making 'RecursiveVN' equal to zero
4611     int max = ValueNumStore::SRC_NumSpecialRefConsts - ValueNumStore::RecursiveVN;
4612
4613     if ((val >= 0) && (val < max))
4614     {
4615         return true;
4616     }
4617     return false;
4618 }
4619
4620 #ifdef DEBUG
4621 void ValueNumStore::RunTests(Compiler* comp)
4622 {
4623     VNFunc VNF_Add = GenTreeOpToVNFunc(GT_ADD);
4624
4625     ValueNumStore* vns    = new (comp->getAllocatorDebugOnly()) ValueNumStore(comp, comp->getAllocatorDebugOnly());
4626     ValueNum       vnNull = VNForNull();
4627     assert(vnNull == VNForNull());
4628
4629     ValueNum vnFor1 = vns->VNForIntCon(1);
4630     assert(vnFor1 == vns->VNForIntCon(1));
4631     assert(vns->TypeOfVN(vnFor1) == TYP_INT);
4632     assert(vns->IsVNConstant(vnFor1));
4633     assert(vns->ConstantValue<int>(vnFor1) == 1);
4634
4635     ValueNum vnFor100 = vns->VNForIntCon(100);
4636     assert(vnFor100 == vns->VNForIntCon(100));
4637     assert(vnFor100 != vnFor1);
4638     assert(vns->TypeOfVN(vnFor100) == TYP_INT);
4639     assert(vns->IsVNConstant(vnFor100));
4640     assert(vns->ConstantValue<int>(vnFor100) == 100);
4641
4642     ValueNum vnFor1F = vns->VNForFloatCon(1.0f);
4643     assert(vnFor1F == vns->VNForFloatCon(1.0f));
4644     assert(vnFor1F != vnFor1 && vnFor1F != vnFor100);
4645     assert(vns->TypeOfVN(vnFor1F) == TYP_FLOAT);
4646     assert(vns->IsVNConstant(vnFor1F));
4647     assert(vns->ConstantValue<float>(vnFor1F) == 1.0f);
4648
4649     ValueNum vnFor1D = vns->VNForDoubleCon(1.0);
4650     assert(vnFor1D == vns->VNForDoubleCon(1.0));
4651     assert(vnFor1D != vnFor1F && vnFor1D != vnFor1 && vnFor1D != vnFor100);
4652     assert(vns->TypeOfVN(vnFor1D) == TYP_DOUBLE);
4653     assert(vns->IsVNConstant(vnFor1D));
4654     assert(vns->ConstantValue<double>(vnFor1D) == 1.0);
4655
4656     ValueNum vnRandom1   = vns->VNForExpr(nullptr, TYP_INT);
4657     ValueNum vnForFunc2a = vns->VNForFunc(TYP_INT, VNF_Add, vnFor1, vnRandom1);
4658     assert(vnForFunc2a == vns->VNForFunc(TYP_INT, VNF_Add, vnFor1, vnRandom1));
4659     assert(vnForFunc2a != vnFor1D && vnForFunc2a != vnFor1F && vnForFunc2a != vnFor1 && vnForFunc2a != vnRandom1);
4660     assert(vns->TypeOfVN(vnForFunc2a) == TYP_INT);
4661     assert(!vns->IsVNConstant(vnForFunc2a));
4662     assert(vns->IsVNFunc(vnForFunc2a));
4663     VNFuncApp fa2a;
4664     bool      b = vns->GetVNFunc(vnForFunc2a, &fa2a);
4665     assert(b);
4666     assert(fa2a.m_func == VNF_Add && fa2a.m_arity == 2 && fa2a.m_args[0] == vnFor1 && fa2a.m_args[1] == vnRandom1);
4667
4668     ValueNum vnForFunc2b = vns->VNForFunc(TYP_INT, VNF_Add, vnFor1, vnFor100);
4669     assert(vnForFunc2b == vns->VNForFunc(TYP_INT, VNF_Add, vnFor1, vnFor100));
4670     assert(vnForFunc2b != vnFor1D && vnForFunc2b != vnFor1F && vnForFunc2b != vnFor1 && vnForFunc2b != vnFor100);
4671     assert(vns->TypeOfVN(vnForFunc2b) == TYP_INT);
4672     assert(vns->IsVNConstant(vnForFunc2b));
4673     assert(vns->ConstantValue<int>(vnForFunc2b) == 101);
4674
4675     // printf("Did ValueNumStore::RunTests.\n");
4676 }
4677 #endif // DEBUG
4678
4679 typedef JitExpandArrayStack<BasicBlock*> BlockStack;
4680
4681 // This represents the "to do" state of the value number computation.
4682 struct ValueNumberState
4683 {
4684     // These two stacks collectively represent the set of blocks that are candidates for
4685     // processing, because at least one predecessor has been processed.  Blocks on "m_toDoAllPredsDone"
4686     // have had *all* predecessors processed, and thus are candidates for some extra optimizations.
4687     // Blocks on "m_toDoNotAllPredsDone" have at least one predecessor that has not been processed.
4688     // Blocks are initially on "m_toDoNotAllPredsDone" may be moved to "m_toDoAllPredsDone" when their last
4689     // unprocessed predecessor is processed, thus maintaining the invariants.
4690     BlockStack m_toDoAllPredsDone;
4691     BlockStack m_toDoNotAllPredsDone;
4692
4693     Compiler* m_comp;
4694
4695     // TBD: This should really be a bitset...
4696     // For now:
4697     // first bit indicates completed,
4698     // second bit indicates that it's been pushed on all-done stack,
4699     // third bit indicates that it's been pushed on not-all-done stack.
4700     BYTE* m_visited;
4701
4702     enum BlockVisitBits
4703     {
4704         BVB_complete     = 0x1,
4705         BVB_onAllDone    = 0x2,
4706         BVB_onNotAllDone = 0x4,
4707     };
4708
4709     bool GetVisitBit(unsigned bbNum, BlockVisitBits bvb)
4710     {
4711         return (m_visited[bbNum] & bvb) != 0;
4712     }
4713     void SetVisitBit(unsigned bbNum, BlockVisitBits bvb)
4714     {
4715         m_visited[bbNum] |= bvb;
4716     }
4717
4718     ValueNumberState(Compiler* comp)
4719         : m_toDoAllPredsDone(comp->getAllocator(), /*minSize*/ 4)
4720         , m_toDoNotAllPredsDone(comp->getAllocator(), /*minSize*/ 4)
4721         , m_comp(comp)
4722         , m_visited(new (comp, CMK_ValueNumber) BYTE[comp->fgBBNumMax + 1]())
4723     {
4724     }
4725
4726     BasicBlock* ChooseFromNotAllPredsDone()
4727     {
4728         assert(m_toDoAllPredsDone.Size() == 0);
4729         // If we have no blocks with all preds done, then (ideally, if all cycles have been captured by loops)
4730         // we must have at least one block within a loop.  We want to do the loops first.  Doing a loop entry block
4731         // should break the cycle, making the rest of the body of the loop (unless there's a nested loop) doable by the
4732         // all-preds-done rule.  If several loop entry blocks are available, at least one should have all non-loop preds
4733         // done -- we choose that.
4734         for (unsigned i = 0; i < m_toDoNotAllPredsDone.Size(); i++)
4735         {
4736             BasicBlock* cand = m_toDoNotAllPredsDone.Get(i);
4737
4738             // Skip any already-completed blocks (a block may have all its preds finished, get added to the
4739             // all-preds-done todo set, and get processed there).  Do this by moving the last one down, to
4740             // keep the array compact.
4741             while (GetVisitBit(cand->bbNum, BVB_complete))
4742             {
4743                 if (i + 1 < m_toDoNotAllPredsDone.Size())
4744                 {
4745                     cand = m_toDoNotAllPredsDone.Pop();
4746                     m_toDoNotAllPredsDone.Set(i, cand);
4747                 }
4748                 else
4749                 {
4750                     // "cand" is the last element; delete it.
4751                     (void)m_toDoNotAllPredsDone.Pop();
4752                     break;
4753                 }
4754             }
4755             // We may have run out of non-complete candidates above.  If so, we're done.
4756             if (i == m_toDoNotAllPredsDone.Size())
4757             {
4758                 break;
4759             }
4760
4761             // See if "cand" is a loop entry.
4762             unsigned lnum;
4763             if (m_comp->optBlockIsLoopEntry(cand, &lnum))
4764             {
4765                 // "lnum" is the innermost loop of which "cand" is the entry; find the outermost.
4766                 unsigned lnumPar = m_comp->optLoopTable[lnum].lpParent;
4767                 while (lnumPar != BasicBlock::NOT_IN_LOOP)
4768                 {
4769                     if (m_comp->optLoopTable[lnumPar].lpEntry == cand)
4770                     {
4771                         lnum = lnumPar;
4772                     }
4773                     else
4774                     {
4775                         break;
4776                     }
4777                     lnumPar = m_comp->optLoopTable[lnumPar].lpParent;
4778                 }
4779
4780                 bool allNonLoopPredsDone = true;
4781                 for (flowList* pred = m_comp->BlockPredsWithEH(cand); pred != nullptr; pred = pred->flNext)
4782                 {
4783                     BasicBlock* predBlock = pred->flBlock;
4784                     if (!m_comp->optLoopTable[lnum].lpContains(predBlock))
4785                     {
4786                         if (!GetVisitBit(predBlock->bbNum, BVB_complete))
4787                         {
4788                             allNonLoopPredsDone = false;
4789                         }
4790                     }
4791                 }
4792                 if (allNonLoopPredsDone)
4793                 {
4794                     return cand;
4795                 }
4796             }
4797         }
4798
4799         // If we didn't find a loop entry block with all non-loop preds done above, then return a random member (if
4800         // there is one).
4801         if (m_toDoNotAllPredsDone.Size() == 0)
4802         {
4803             return nullptr;
4804         }
4805         else
4806         {
4807             return m_toDoNotAllPredsDone.Pop();
4808         }
4809     }
4810
4811 // Debugging output that is too detailed for a normal JIT dump...
4812 #define DEBUG_VN_VISIT 0
4813
4814     // Record that "blk" has been visited, and add any unvisited successors of "blk" to the appropriate todo set.
4815     void FinishVisit(BasicBlock* blk)
4816     {
4817 #ifdef DEBUG_VN_VISIT
4818         JITDUMP("finish(" FMT_BB ").\n", blk->bbNum);
4819 #endif // DEBUG_VN_VISIT
4820
4821         SetVisitBit(blk->bbNum, BVB_complete);
4822
4823         for (BasicBlock* succ : blk->GetAllSuccs(m_comp))
4824         {
4825 #ifdef DEBUG_VN_VISIT
4826             JITDUMP("   Succ(" FMT_BB ").\n", succ->bbNum);
4827 #endif // DEBUG_VN_VISIT
4828
4829             if (GetVisitBit(succ->bbNum, BVB_complete))
4830             {
4831                 continue;
4832             }
4833 #ifdef DEBUG_VN_VISIT
4834             JITDUMP("     Not yet completed.\n");
4835 #endif // DEBUG_VN_VISIT
4836
4837             bool allPredsVisited = true;
4838             for (flowList* pred = m_comp->BlockPredsWithEH(succ); pred != nullptr; pred = pred->flNext)
4839             {
4840                 BasicBlock* predBlock = pred->flBlock;
4841                 if (!GetVisitBit(predBlock->bbNum, BVB_complete))
4842                 {
4843                     allPredsVisited = false;
4844                     break;
4845                 }
4846             }
4847
4848             if (allPredsVisited)
4849             {
4850 #ifdef DEBUG_VN_VISIT
4851                 JITDUMP("     All preds complete, adding to allDone.\n");
4852 #endif // DEBUG_VN_VISIT
4853
4854                 assert(!GetVisitBit(succ->bbNum, BVB_onAllDone)); // Only last completion of last succ should add to
4855                                                                   // this.
4856                 m_toDoAllPredsDone.Push(succ);
4857                 SetVisitBit(succ->bbNum, BVB_onAllDone);
4858             }
4859             else
4860             {
4861 #ifdef DEBUG_VN_VISIT
4862                 JITDUMP("     Not all preds complete  Adding to notallDone, if necessary...\n");
4863 #endif // DEBUG_VN_VISIT
4864
4865                 if (!GetVisitBit(succ->bbNum, BVB_onNotAllDone))
4866                 {
4867 #ifdef DEBUG_VN_VISIT
4868                     JITDUMP("       Was necessary.\n");
4869 #endif // DEBUG_VN_VISIT
4870                     m_toDoNotAllPredsDone.Push(succ);
4871                     SetVisitBit(succ->bbNum, BVB_onNotAllDone);
4872                 }
4873             }
4874         }
4875     }
4876
4877     bool ToDoExists()
4878     {
4879         return m_toDoAllPredsDone.Size() > 0 || m_toDoNotAllPredsDone.Size() > 0;
4880     }
4881 };
4882
4883 void Compiler::fgValueNumber()
4884 {
4885 #ifdef DEBUG
4886     // This could be a JITDUMP, but some people find it convenient to set a breakpoint on the printf.
4887     if (verbose)
4888     {
4889         printf("\n*************** In fgValueNumber()\n");
4890     }
4891 #endif
4892
4893     // If we skipped SSA, skip VN as well.
4894     if (fgSsaPassesCompleted == 0)
4895     {
4896         return;
4897     }
4898
4899     // Allocate the value number store.
4900     assert(fgVNPassesCompleted > 0 || vnStore == nullptr);
4901     if (fgVNPassesCompleted == 0)
4902     {
4903         CompAllocator allocator(getAllocator(CMK_ValueNumber));
4904         vnStore = new (allocator) ValueNumStore(this, allocator);
4905     }
4906     else
4907     {
4908         ValueNumPair noVnp;
4909         // Make sure the memory SSA names have no value numbers.
4910         for (unsigned i = 0; i < lvMemoryPerSsaData.GetCount(); i++)
4911         {
4912             lvMemoryPerSsaData.GetSsaDefByIndex(i)->m_vnPair = noVnp;
4913         }
4914         for (BasicBlock* blk = fgFirstBB; blk != nullptr; blk = blk->bbNext)
4915         {
4916             // Now iterate over the block's statements, and their trees.
4917             for (GenTree* stmts = blk->FirstNonPhiDef(); stmts != nullptr; stmts = stmts->gtNext)
4918             {
4919                 assert(stmts->IsStatement());
4920                 for (GenTree* tree = stmts->gtStmt.gtStmtList; tree; tree = tree->gtNext)
4921                 {
4922                     tree->gtVNPair.SetBoth(ValueNumStore::NoVN);
4923                 }
4924             }
4925         }
4926     }
4927
4928     // Compute the side effects of loops.
4929     optComputeLoopSideEffects();
4930
4931     // At the block level, we will use a modified worklist algorithm.  We will have two
4932     // "todo" sets of unvisited blocks.  Blocks (other than the entry block) are put in a
4933     // todo set only when some predecessor has been visited, so all blocks have at least one
4934     // predecessor visited.  The distinction between the two sets is whether *all* predecessors have
4935     // already been visited.  We visit such blocks preferentially if they exist, since phi definitions
4936     // in such blocks will have all arguments defined, enabling a simplification in the case that all
4937     // arguments to the phi have the same VN.  If no such blocks exist, we pick a block with at least
4938     // one unvisited predecessor.  In this case, we assign a new VN for phi definitions.
4939
4940     // Start by giving incoming arguments value numbers.
4941     // Also give must-init vars a zero of their type.
4942     for (unsigned lclNum = 0; lclNum < lvaCount; lclNum++)
4943     {
4944         if (!lvaInSsa(lclNum))
4945         {
4946             continue;
4947         }
4948
4949         LclVarDsc* varDsc = &lvaTable[lclNum];
4950         assert(varDsc->lvTracked);
4951
4952         if (varDsc->lvIsParam)
4953         {
4954             // We assume that code equivalent to this variable initialization loop
4955             // has been performed when doing SSA naming, so that all the variables we give
4956             // initial VNs to here have been given initial SSA definitions there.
4957             // SSA numbers always start from FIRST_SSA_NUM, and we give the value number to SSA name FIRST_SSA_NUM.
4958             // We use the VNF_InitVal(i) from here so we know that this value is loop-invariant
4959             // in all loops.
4960             ValueNum      initVal = vnStore->VNForFunc(varDsc->TypeGet(), VNF_InitVal, vnStore->VNForIntCon(lclNum));
4961             LclSsaVarDsc* ssaDef  = varDsc->GetPerSsaData(SsaConfig::FIRST_SSA_NUM);
4962             ssaDef->m_vnPair.SetBoth(initVal);
4963             ssaDef->m_defLoc.m_blk = fgFirstBB;
4964         }
4965         else if (info.compInitMem || varDsc->lvMustInit ||
4966                  VarSetOps::IsMember(this, fgFirstBB->bbLiveIn, varDsc->lvVarIndex))
4967         {
4968             // The last clause covers the use-before-def variables (the ones that are live-in to the the first block),
4969             // these are variables that are read before being initialized (at least on some control flow paths)
4970             // if they are not must-init, then they get VNF_InitVal(i), as with the param case.)
4971
4972             bool      isZeroed = (info.compInitMem || varDsc->lvMustInit);
4973             ValueNum  initVal  = ValueNumStore::NoVN; // We must assign a new value to initVal
4974             var_types typ      = varDsc->TypeGet();
4975
4976             switch (typ)
4977             {
4978                 case TYP_LCLBLK: // The outgoing args area for arm and x64
4979                 case TYP_BLK:    // A blob of memory
4980                     // TYP_BLK is used for the EHSlots LclVar on x86 (aka shadowSPslotsVar)
4981                     // and for the lvaInlinedPInvokeFrameVar on x64, arm and x86
4982                     // The stack associated with these LclVars are not zero initialized
4983                     // thus we set 'initVN' to a new, unique VN.
4984                     //
4985                     initVal = vnStore->VNForExpr(fgFirstBB);
4986                     break;
4987
4988                 case TYP_BYREF:
4989                     if (isZeroed)
4990                     {
4991                         // LclVars of TYP_BYREF can be zero-inited.
4992                         initVal = vnStore->VNForByrefCon(0);
4993                     }
4994                     else
4995                     {
4996                         // Here we have uninitialized TYP_BYREF
4997                         initVal = vnStore->VNForFunc(typ, VNF_InitVal, vnStore->VNForIntCon(lclNum));
4998                     }
4999                     break;
5000
5001                 default:
5002                     if (isZeroed)
5003                     {
5004                         // By default we will zero init these LclVars
5005                         initVal = vnStore->VNZeroForType(typ);
5006                     }
5007                     else
5008                     {
5009                         initVal = vnStore->VNForFunc(typ, VNF_InitVal, vnStore->VNForIntCon(lclNum));
5010                     }
5011                     break;
5012             }
5013 #ifdef _TARGET_X86_
5014             bool isVarargParam = (lclNum == lvaVarargsBaseOfStkArgs || lclNum == lvaVarargsHandleArg);
5015             if (isVarargParam)
5016                 initVal = vnStore->VNForExpr(fgFirstBB); // a new, unique VN.
5017 #endif
5018             assert(initVal != ValueNumStore::NoVN);
5019
5020             LclSsaVarDsc* ssaDef = varDsc->GetPerSsaData(SsaConfig::FIRST_SSA_NUM);
5021             ssaDef->m_vnPair.SetBoth(initVal);
5022             ssaDef->m_defLoc.m_blk = fgFirstBB;
5023         }
5024     }
5025     // Give memory an initial value number (about which we know nothing).
5026     ValueNum memoryInitVal = vnStore->VNForFunc(TYP_REF, VNF_InitVal, vnStore->VNForIntCon(-1)); // Use -1 for memory.
5027     GetMemoryPerSsaData(SsaConfig::FIRST_SSA_NUM)->m_vnPair.SetBoth(memoryInitVal);
5028 #ifdef DEBUG
5029     if (verbose)
5030     {
5031         printf("Memory Initial Value in BB01 is: " FMT_VN "\n", memoryInitVal);
5032     }
5033 #endif // DEBUG
5034
5035     ValueNumberState vs(this);
5036
5037     // Push the first block.  This has no preds.
5038     vs.m_toDoAllPredsDone.Push(fgFirstBB);
5039
5040     while (vs.ToDoExists())
5041     {
5042         while (vs.m_toDoAllPredsDone.Size() > 0)
5043         {
5044             BasicBlock* toDo = vs.m_toDoAllPredsDone.Pop();
5045             fgValueNumberBlock(toDo);
5046             // Record that we've visited "toDo", and add successors to the right sets.
5047             vs.FinishVisit(toDo);
5048         }
5049         // OK, we've run out of blocks whose predecessors are done.  Pick one whose predecessors are not all done,
5050         // process that.  This may make more "all-done" blocks, so we'll go around the outer loop again --
5051         // note that this is an "if", not a "while" loop.
5052         if (vs.m_toDoNotAllPredsDone.Size() > 0)
5053         {
5054             BasicBlock* toDo = vs.ChooseFromNotAllPredsDone();
5055             if (toDo == nullptr)
5056             {
5057                 continue; // We may have run out, because of completed blocks on the not-all-preds done list.
5058             }
5059
5060             fgValueNumberBlock(toDo);
5061             // Record that we've visited "toDo", and add successors to the right sest.
5062             vs.FinishVisit(toDo);
5063         }
5064     }
5065
5066 #ifdef DEBUG
5067     JitTestCheckVN();
5068 #endif // DEBUG
5069
5070     fgVNPassesCompleted++;
5071 }
5072
5073 void Compiler::fgValueNumberBlock(BasicBlock* blk)
5074 {
5075     compCurBB = blk;
5076
5077 #ifdef DEBUG
5078     compCurStmtNum = blk->bbStmtNum - 1; // Set compCurStmtNum
5079 #endif
5080
5081     unsigned outerLoopNum = BasicBlock::NOT_IN_LOOP;
5082
5083     // First: visit phi's.  If "newVNForPhis", give them new VN's.  If not,
5084     // first check to see if all phi args have the same value.
5085     GenTree* firstNonPhi = blk->FirstNonPhiDef();
5086     for (GenTree* phiDefs = blk->bbTreeList; phiDefs != firstNonPhi; phiDefs = phiDefs->gtNext)
5087     {
5088         // TODO-Cleanup: It has been proposed that we should have an IsPhiDef predicate.  We would use it
5089         // in Block::FirstNonPhiDef as well.
5090         GenTree* phiDef = phiDefs->gtStmt.gtStmtExpr;
5091         assert(phiDef->OperGet() == GT_ASG);
5092         GenTreeLclVarCommon* newSsaVar = phiDef->gtOp.gtOp1->AsLclVarCommon();
5093
5094         ValueNumPair phiAppVNP;
5095         ValueNumPair sameVNPair;
5096
5097         GenTree* phiFunc = phiDef->gtOp.gtOp2;
5098
5099         // At this point a GT_PHI node should never have a nullptr for gtOp1
5100         // and the gtOp1 should always be a GT_LIST node.
5101         GenTree* phiOp1 = phiFunc->gtOp.gtOp1;
5102         noway_assert(phiOp1 != nullptr);
5103         noway_assert(phiOp1->OperGet() == GT_LIST);
5104
5105         GenTreeArgList* phiArgs = phiFunc->gtOp.gtOp1->AsArgList();
5106
5107         // A GT_PHI node should have more than one argument.
5108         noway_assert(phiArgs->Rest() != nullptr);
5109
5110         GenTreeLclVarCommon* phiArg = phiArgs->Current()->AsLclVarCommon();
5111         phiArgs                     = phiArgs->Rest();
5112
5113         phiAppVNP.SetBoth(vnStore->VNForIntCon(phiArg->gtSsaNum));
5114         bool allSameLib  = true;
5115         bool allSameCons = true;
5116         sameVNPair       = lvaTable[phiArg->gtLclNum].GetPerSsaData(phiArg->gtSsaNum)->m_vnPair;
5117         if (!sameVNPair.BothDefined())
5118         {
5119             allSameLib  = false;
5120             allSameCons = false;
5121         }
5122         while (phiArgs != nullptr)
5123         {
5124             phiArg = phiArgs->Current()->AsLclVarCommon();
5125             // Set the VN of the phi arg.
5126             phiArg->gtVNPair = lvaTable[phiArg->gtLclNum].GetPerSsaData(phiArg->gtSsaNum)->m_vnPair;
5127             if (phiArg->gtVNPair.BothDefined())
5128             {
5129                 if (phiArg->gtVNPair.GetLiberal() != sameVNPair.GetLiberal())
5130                 {
5131                     allSameLib = false;
5132                 }
5133                 if (phiArg->gtVNPair.GetConservative() != sameVNPair.GetConservative())
5134                 {
5135                     allSameCons = false;
5136                 }
5137             }
5138             else
5139             {
5140                 allSameLib  = false;
5141                 allSameCons = false;
5142             }
5143             ValueNumPair phiArgSsaVNP;
5144             phiArgSsaVNP.SetBoth(vnStore->VNForIntCon(phiArg->gtSsaNum));
5145             phiAppVNP = vnStore->VNPairForFunc(newSsaVar->TypeGet(), VNF_Phi, phiArgSsaVNP, phiAppVNP);
5146             phiArgs   = phiArgs->Rest();
5147         }
5148
5149         ValueNumPair newVNPair;
5150         if (allSameLib)
5151         {
5152             newVNPair.SetLiberal(sameVNPair.GetLiberal());
5153         }
5154         else
5155         {
5156             newVNPair.SetLiberal(phiAppVNP.GetLiberal());
5157         }
5158         if (allSameCons)
5159         {
5160             newVNPair.SetConservative(sameVNPair.GetConservative());
5161         }
5162         else
5163         {
5164             newVNPair.SetConservative(phiAppVNP.GetConservative());
5165         }
5166
5167         LclSsaVarDsc* newSsaVarDsc = lvaTable[newSsaVar->gtLclNum].GetPerSsaData(newSsaVar->GetSsaNum());
5168         // If all the args of the phi had the same value(s, liberal and conservative), then there wasn't really
5169         // a reason to have the phi -- just pass on that value.
5170         if (allSameLib && allSameCons)
5171         {
5172             newSsaVarDsc->m_vnPair = newVNPair;
5173 #ifdef DEBUG
5174             if (verbose)
5175             {
5176                 printf("In SSA definition, incoming phi args all same, set VN of local %d/%d to ",
5177                        newSsaVar->GetLclNum(), newSsaVar->GetSsaNum());
5178                 vnpPrint(newVNPair, 1);
5179                 printf(".\n");
5180             }
5181 #endif // DEBUG
5182         }
5183         else
5184         {
5185             // They were not the same; we need to create a phi definition.
5186             ValueNumPair lclNumVNP;
5187             lclNumVNP.SetBoth(ValueNum(newSsaVar->GetLclNum()));
5188             ValueNumPair ssaNumVNP;
5189             ssaNumVNP.SetBoth(ValueNum(newSsaVar->GetSsaNum()));
5190             ValueNumPair vnPhiDef =
5191                 vnStore->VNPairForFunc(newSsaVar->TypeGet(), VNF_PhiDef, lclNumVNP, ssaNumVNP, phiAppVNP);
5192             newSsaVarDsc->m_vnPair = vnPhiDef;
5193 #ifdef DEBUG
5194             if (verbose)
5195             {
5196                 printf("SSA definition: set VN of local %d/%d to ", newSsaVar->GetLclNum(), newSsaVar->GetSsaNum());
5197                 vnpPrint(vnPhiDef, 1);
5198                 printf(".\n");
5199             }
5200 #endif // DEBUG
5201         }
5202     }
5203
5204     // Now do the same for each MemoryKind.
5205     for (MemoryKind memoryKind : allMemoryKinds())
5206     {
5207         // Is there a phi for this block?
5208         if (blk->bbMemorySsaPhiFunc[memoryKind] == nullptr)
5209         {
5210             fgCurMemoryVN[memoryKind] = GetMemoryPerSsaData(blk->bbMemorySsaNumIn[memoryKind])->m_vnPair.GetLiberal();
5211             assert(fgCurMemoryVN[memoryKind] != ValueNumStore::NoVN);
5212         }
5213         else
5214         {
5215             if ((memoryKind == ByrefExposed) && byrefStatesMatchGcHeapStates)
5216             {
5217                 // The update for GcHeap will copy its result to ByrefExposed.
5218                 assert(memoryKind < GcHeap);
5219                 assert(blk->bbMemorySsaPhiFunc[memoryKind] == blk->bbMemorySsaPhiFunc[GcHeap]);
5220                 continue;
5221             }
5222
5223             unsigned loopNum;
5224             ValueNum newMemoryVN;
5225             if (optBlockIsLoopEntry(blk, &loopNum))
5226             {
5227                 newMemoryVN = fgMemoryVNForLoopSideEffects(memoryKind, blk, loopNum);
5228             }
5229             else
5230             {
5231                 // Are all the VN's the same?
5232                 BasicBlock::MemoryPhiArg* phiArgs = blk->bbMemorySsaPhiFunc[memoryKind];
5233                 assert(phiArgs != BasicBlock::EmptyMemoryPhiDef);
5234                 // There should be > 1 args to a phi.
5235                 assert(phiArgs->m_nextArg != nullptr);
5236                 ValueNum phiAppVN = vnStore->VNForIntCon(phiArgs->GetSsaNum());
5237                 JITDUMP("  Building phi application: $%x = SSA# %d.\n", phiAppVN, phiArgs->GetSsaNum());
5238                 bool     allSame = true;
5239                 ValueNum sameVN  = GetMemoryPerSsaData(phiArgs->GetSsaNum())->m_vnPair.GetLiberal();
5240                 if (sameVN == ValueNumStore::NoVN)
5241                 {
5242                     allSame = false;
5243                 }
5244                 phiArgs = phiArgs->m_nextArg;
5245                 while (phiArgs != nullptr)
5246                 {
5247                     ValueNum phiArgVN = GetMemoryPerSsaData(phiArgs->GetSsaNum())->m_vnPair.GetLiberal();
5248                     if (phiArgVN == ValueNumStore::NoVN || phiArgVN != sameVN)
5249                     {
5250                         allSame = false;
5251                     }
5252 #ifdef DEBUG
5253                     ValueNum oldPhiAppVN = phiAppVN;
5254 #endif
5255                     unsigned phiArgSSANum   = phiArgs->GetSsaNum();
5256                     ValueNum phiArgSSANumVN = vnStore->VNForIntCon(phiArgSSANum);
5257                     JITDUMP("  Building phi application: $%x = SSA# %d.\n", phiArgSSANumVN, phiArgSSANum);
5258                     phiAppVN = vnStore->VNForFunc(TYP_REF, VNF_Phi, phiArgSSANumVN, phiAppVN);
5259                     JITDUMP("  Building phi application: $%x = phi($%x, $%x).\n", phiAppVN, phiArgSSANumVN,
5260                             oldPhiAppVN);
5261                     phiArgs = phiArgs->m_nextArg;
5262                 }
5263                 if (allSame)
5264                 {
5265                     newMemoryVN = sameVN;
5266                 }
5267                 else
5268                 {
5269                     newMemoryVN =
5270                         vnStore->VNForFunc(TYP_REF, VNF_PhiMemoryDef, vnStore->VNForHandle(ssize_t(blk), 0), phiAppVN);
5271                 }
5272             }
5273             GetMemoryPerSsaData(blk->bbMemorySsaNumIn[memoryKind])->m_vnPair.SetLiberal(newMemoryVN);
5274             fgCurMemoryVN[memoryKind] = newMemoryVN;
5275             if ((memoryKind == GcHeap) && byrefStatesMatchGcHeapStates)
5276             {
5277                 // Keep the CurMemoryVNs in sync
5278                 fgCurMemoryVN[ByrefExposed] = newMemoryVN;
5279             }
5280         }
5281 #ifdef DEBUG
5282         if (verbose)
5283         {
5284             printf("The SSA definition for %s (#%d) at start of " FMT_BB " is ", memoryKindNames[memoryKind],
5285                    blk->bbMemorySsaNumIn[memoryKind], blk->bbNum);
5286             vnPrint(fgCurMemoryVN[memoryKind], 1);
5287             printf("\n");
5288         }
5289 #endif // DEBUG
5290     }
5291
5292     // Now iterate over the remaining statements, and their trees.
5293     for (GenTree* stmt = firstNonPhi; stmt != nullptr; stmt = stmt->gtNext)
5294     {
5295         assert(stmt->IsStatement());
5296
5297 #ifdef DEBUG
5298         compCurStmtNum++;
5299         if (verbose)
5300         {
5301             printf("\n***** " FMT_BB ", stmt %d (before)\n", blk->bbNum, compCurStmtNum);
5302             gtDispTree(stmt->gtStmt.gtStmtExpr);
5303             printf("\n");
5304         }
5305 #endif
5306
5307         for (GenTree* tree = stmt->gtStmt.gtStmtList; tree; tree = tree->gtNext)
5308         {
5309             fgValueNumberTree(tree);
5310         }
5311
5312 #ifdef DEBUG
5313         if (verbose)
5314         {
5315             printf("\n***** " FMT_BB ", stmt %d (after)\n", blk->bbNum, compCurStmtNum);
5316             gtDispTree(stmt->gtStmt.gtStmtExpr);
5317             printf("\n");
5318             if (stmt->gtNext)
5319             {
5320                 printf("---------\n");
5321             }
5322         }
5323 #endif
5324     }
5325
5326     for (MemoryKind memoryKind : allMemoryKinds())
5327     {
5328         if ((memoryKind == GcHeap) && byrefStatesMatchGcHeapStates)
5329         {
5330             // The update to the shared SSA data will have already happened for ByrefExposed.
5331             assert(memoryKind > ByrefExposed);
5332             assert(blk->bbMemorySsaNumOut[memoryKind] == blk->bbMemorySsaNumOut[ByrefExposed]);
5333             assert(GetMemoryPerSsaData(blk->bbMemorySsaNumOut[memoryKind])->m_vnPair.GetLiberal() ==
5334                    fgCurMemoryVN[memoryKind]);
5335             continue;
5336         }
5337
5338         if (blk->bbMemorySsaNumOut[memoryKind] != blk->bbMemorySsaNumIn[memoryKind])
5339         {
5340             GetMemoryPerSsaData(blk->bbMemorySsaNumOut[memoryKind])->m_vnPair.SetLiberal(fgCurMemoryVN[memoryKind]);
5341         }
5342     }
5343
5344     compCurBB = nullptr;
5345 }
5346
5347 ValueNum Compiler::fgMemoryVNForLoopSideEffects(MemoryKind  memoryKind,
5348                                                 BasicBlock* entryBlock,
5349                                                 unsigned    innermostLoopNum)
5350 {
5351     // "loopNum" is the innermost loop for which "blk" is the entry; find the outermost one.
5352     assert(innermostLoopNum != BasicBlock::NOT_IN_LOOP);
5353     unsigned loopsInNest = innermostLoopNum;
5354     unsigned loopNum     = innermostLoopNum;
5355     while (loopsInNest != BasicBlock::NOT_IN_LOOP)
5356     {
5357         if (optLoopTable[loopsInNest].lpEntry != entryBlock)
5358         {
5359             break;
5360         }
5361         loopNum     = loopsInNest;
5362         loopsInNest = optLoopTable[loopsInNest].lpParent;
5363     }
5364
5365 #ifdef DEBUG
5366     if (verbose)
5367     {
5368         printf("Computing %s state for block " FMT_BB ", entry block for loops %d to %d:\n",
5369                memoryKindNames[memoryKind], entryBlock->bbNum, innermostLoopNum, loopNum);
5370     }
5371 #endif // DEBUG
5372
5373     // If this loop has memory havoc effects, just use a new, unique VN.
5374     if (optLoopTable[loopNum].lpLoopHasMemoryHavoc[memoryKind])
5375     {
5376         ValueNum res = vnStore->VNForExpr(entryBlock, TYP_REF);
5377 #ifdef DEBUG
5378         if (verbose)
5379         {
5380             printf("  Loop %d has memory havoc effect; heap state is new fresh $%x.\n", loopNum, res);
5381         }
5382 #endif // DEBUG
5383         return res;
5384     }
5385
5386     // Otherwise, find the predecessors of the entry block that are not in the loop.
5387     // If there is only one such, use its memory value as the "base."  If more than one,
5388     // use a new unique VN.
5389     BasicBlock* nonLoopPred          = nullptr;
5390     bool        multipleNonLoopPreds = false;
5391     for (flowList* pred = BlockPredsWithEH(entryBlock); pred != nullptr; pred = pred->flNext)
5392     {
5393         BasicBlock* predBlock = pred->flBlock;
5394         if (!optLoopTable[loopNum].lpContains(predBlock))
5395         {
5396             if (nonLoopPred == nullptr)
5397             {
5398                 nonLoopPred = predBlock;
5399             }
5400             else
5401             {
5402 #ifdef DEBUG
5403                 if (verbose)
5404                 {
5405                     printf("  Entry block has >1 non-loop preds: (at least) " FMT_BB " and " FMT_BB ".\n",
5406                            nonLoopPred->bbNum, predBlock->bbNum);
5407                 }
5408 #endif // DEBUG
5409                 multipleNonLoopPreds = true;
5410                 break;
5411             }
5412         }
5413     }
5414     if (multipleNonLoopPreds)
5415     {
5416         ValueNum res = vnStore->VNForExpr(entryBlock, TYP_REF);
5417 #ifdef DEBUG
5418         if (verbose)
5419         {
5420             printf("  Therefore, memory state is new, fresh $%x.\n", res);
5421         }
5422 #endif // DEBUG
5423         return res;
5424     }
5425     // Otherwise, there is a single non-loop pred.
5426     assert(nonLoopPred != nullptr);
5427     // What is its memory post-state?
5428     ValueNum newMemoryVN = GetMemoryPerSsaData(nonLoopPred->bbMemorySsaNumOut[memoryKind])->m_vnPair.GetLiberal();
5429     assert(newMemoryVN !=
5430            ValueNumStore::NoVN); // We must have processed the single non-loop pred before reaching the loop entry.
5431
5432 #ifdef DEBUG
5433     if (verbose)
5434     {
5435         printf("  Init %s state is $%x, with new, fresh VN at:\n", memoryKindNames[memoryKind], newMemoryVN);
5436     }
5437 #endif // DEBUG
5438     // Modify "base" by setting all the modified fields/field maps/array maps to unknown values.
5439     // These annotations apply specifically to the GcHeap, where we disambiguate across such stores.
5440     if (memoryKind == GcHeap)
5441     {
5442         // First the fields/field maps.
5443         Compiler::LoopDsc::FieldHandleSet* fieldsMod = optLoopTable[loopNum].lpFieldsModified;
5444         if (fieldsMod != nullptr)
5445         {
5446             for (Compiler::LoopDsc::FieldHandleSet::KeyIterator ki = fieldsMod->Begin(); !ki.Equal(fieldsMod->End());
5447                  ++ki)
5448             {
5449                 CORINFO_FIELD_HANDLE fldHnd   = ki.Get();
5450                 ValueNum             fldHndVN = vnStore->VNForHandle(ssize_t(fldHnd), GTF_ICON_FIELD_HDL);
5451
5452 #ifdef DEBUG
5453                 if (verbose)
5454                 {
5455                     const char* modName;
5456                     const char* fldName = eeGetFieldName(fldHnd, &modName);
5457                     printf("     VNForHandle(Fseq[%s]) is " FMT_VN "\n", fldName, fldHndVN);
5458                 }
5459 #endif // DEBUG
5460
5461                 newMemoryVN =
5462                     vnStore->VNForMapStore(TYP_REF, newMemoryVN, fldHndVN, vnStore->VNForExpr(entryBlock, TYP_REF));
5463             }
5464         }
5465         // Now do the array maps.
5466         Compiler::LoopDsc::ClassHandleSet* elemTypesMod = optLoopTable[loopNum].lpArrayElemTypesModified;
5467         if (elemTypesMod != nullptr)
5468         {
5469             for (Compiler::LoopDsc::ClassHandleSet::KeyIterator ki = elemTypesMod->Begin();
5470                  !ki.Equal(elemTypesMod->End()); ++ki)
5471             {
5472                 CORINFO_CLASS_HANDLE elemClsHnd = ki.Get();
5473
5474 #ifdef DEBUG
5475                 if (verbose)
5476                 {
5477                     var_types elemTyp = DecodeElemType(elemClsHnd);
5478                     if (varTypeIsStruct(elemTyp))
5479                     {
5480                         printf("     Array map %s[]\n", eeGetClassName(elemClsHnd));
5481                     }
5482                     else
5483                     {
5484                         printf("     Array map %s[]\n", varTypeName(elemTyp));
5485                     }
5486                 }
5487 #endif // DEBUG
5488
5489                 ValueNum elemTypeVN = vnStore->VNForHandle(ssize_t(elemClsHnd), GTF_ICON_CLASS_HDL);
5490                 ValueNum uniqueVN   = vnStore->VNForExpr(entryBlock, TYP_REF);
5491                 newMemoryVN         = vnStore->VNForMapStore(TYP_REF, newMemoryVN, elemTypeVN, uniqueVN);
5492             }
5493         }
5494     }
5495     else
5496     {
5497         // If there were any fields/elements modified, this should have been recorded as havoc
5498         // for ByrefExposed.
5499         assert(memoryKind == ByrefExposed);
5500         assert((optLoopTable[loopNum].lpFieldsModified == nullptr) ||
5501                optLoopTable[loopNum].lpLoopHasMemoryHavoc[memoryKind]);
5502         assert((optLoopTable[loopNum].lpArrayElemTypesModified == nullptr) ||
5503                optLoopTable[loopNum].lpLoopHasMemoryHavoc[memoryKind]);
5504     }
5505
5506 #ifdef DEBUG
5507     if (verbose)
5508     {
5509         printf("  Final %s state is $%x.\n", memoryKindNames[memoryKind], newMemoryVN);
5510     }
5511 #endif // DEBUG
5512     return newMemoryVN;
5513 }
5514
5515 void Compiler::fgMutateGcHeap(GenTree* tree DEBUGARG(const char* msg))
5516 {
5517     // Update the current memory VN, and if we're tracking the heap SSA # caused by this node, record it.
5518     recordGcHeapStore(tree, vnStore->VNForExpr(compCurBB, TYP_REF) DEBUGARG(msg));
5519 }
5520
5521 void Compiler::fgMutateAddressExposedLocal(GenTree* tree DEBUGARG(const char* msg))
5522 {
5523     // Update the current ByrefExposed VN, and if we're tracking the heap SSA # caused by this node, record it.
5524     recordAddressExposedLocalStore(tree, vnStore->VNForExpr(compCurBB) DEBUGARG(msg));
5525 }
5526
5527 void Compiler::recordGcHeapStore(GenTree* curTree, ValueNum gcHeapVN DEBUGARG(const char* msg))
5528 {
5529     // bbMemoryDef must include GcHeap for any block that mutates the GC Heap
5530     // and GC Heap mutations are also ByrefExposed mutations
5531     assert((compCurBB->bbMemoryDef & memoryKindSet(GcHeap, ByrefExposed)) == memoryKindSet(GcHeap, ByrefExposed));
5532     fgCurMemoryVN[GcHeap] = gcHeapVN;
5533
5534     if (byrefStatesMatchGcHeapStates)
5535     {
5536         // Since GcHeap and ByrefExposed share SSA nodes, they need to share
5537         // value numbers too.
5538         fgCurMemoryVN[ByrefExposed] = gcHeapVN;
5539     }
5540     else
5541     {
5542         // GcHeap and ByrefExposed have different defnums and VNs.  We conservatively
5543         // assume that this GcHeap store may alias any byref load/store, so don't
5544         // bother trying to record the map/select stuff, and instead just an opaque VN
5545         // for ByrefExposed
5546         fgCurMemoryVN[ByrefExposed] = vnStore->VNForExpr(compCurBB);
5547     }
5548
5549 #ifdef DEBUG
5550     if (verbose)
5551     {
5552         printf("  fgCurMemoryVN[GcHeap] assigned for %s at ", msg);
5553         Compiler::printTreeID(curTree);
5554         printf(" to VN: " FMT_VN ".\n", gcHeapVN);
5555     }
5556 #endif // DEBUG
5557
5558     // If byrefStatesMatchGcHeapStates is true, then since GcHeap and ByrefExposed share
5559     // their SSA map entries, the below will effectively update both.
5560     fgValueNumberRecordMemorySsa(GcHeap, curTree);
5561 }
5562
5563 void Compiler::recordAddressExposedLocalStore(GenTree* curTree, ValueNum memoryVN DEBUGARG(const char* msg))
5564 {
5565     // This should only happen if GcHeap and ByrefExposed are being tracked separately;
5566     // otherwise we'd go through recordGcHeapStore.
5567     assert(!byrefStatesMatchGcHeapStates);
5568
5569     // bbMemoryDef must include ByrefExposed for any block that mutates an address-exposed local
5570     assert((compCurBB->bbMemoryDef & memoryKindSet(ByrefExposed)) != 0);
5571     fgCurMemoryVN[ByrefExposed] = memoryVN;
5572
5573 #ifdef DEBUG
5574     if (verbose)
5575     {
5576         printf("  fgCurMemoryVN[ByrefExposed] assigned for %s at ", msg);
5577         Compiler::printTreeID(curTree);
5578         printf(" to VN: " FMT_VN ".\n", memoryVN);
5579     }
5580 #endif // DEBUG
5581
5582     fgValueNumberRecordMemorySsa(ByrefExposed, curTree);
5583 }
5584
5585 void Compiler::fgValueNumberRecordMemorySsa(MemoryKind memoryKind, GenTree* tree)
5586 {
5587     unsigned ssaNum;
5588     if (GetMemorySsaMap(memoryKind)->Lookup(tree, &ssaNum))
5589     {
5590         GetMemoryPerSsaData(ssaNum)->m_vnPair.SetLiberal(fgCurMemoryVN[memoryKind]);
5591 #ifdef DEBUG
5592         if (verbose)
5593         {
5594             printf("Node ");
5595             Compiler::printTreeID(tree);
5596             printf(" sets %s SSA # %d to VN $%x: ", memoryKindNames[memoryKind], ssaNum, fgCurMemoryVN[memoryKind]);
5597             vnStore->vnDump(this, fgCurMemoryVN[memoryKind]);
5598             printf("\n");
5599         }
5600 #endif // DEBUG
5601     }
5602 }
5603
5604 // The input 'tree' is a leaf node that is a constant
5605 // Assign the proper value number to the tree
5606 void Compiler::fgValueNumberTreeConst(GenTree* tree)
5607 {
5608     genTreeOps oper = tree->OperGet();
5609     var_types  typ  = tree->TypeGet();
5610     assert(GenTree::OperIsConst(oper));
5611
5612     switch (typ)
5613     {
5614         case TYP_LONG:
5615         case TYP_ULONG:
5616         case TYP_INT:
5617         case TYP_UINT:
5618         case TYP_USHORT:
5619         case TYP_SHORT:
5620         case TYP_BYTE:
5621         case TYP_UBYTE:
5622         case TYP_BOOL:
5623             if (tree->IsCnsIntOrI() && tree->IsIconHandle())
5624             {
5625                 tree->gtVNPair.SetBoth(
5626                     vnStore->VNForHandle(ssize_t(tree->gtIntConCommon.IconValue()), tree->GetIconHandleFlag()));
5627             }
5628             else if ((typ == TYP_LONG) || (typ == TYP_ULONG))
5629             {
5630                 tree->gtVNPair.SetBoth(vnStore->VNForLongCon(INT64(tree->gtIntConCommon.LngValue())));
5631             }
5632             else
5633             {
5634                 tree->gtVNPair.SetBoth(vnStore->VNForIntCon(int(tree->gtIntConCommon.IconValue())));
5635             }
5636             break;
5637
5638         case TYP_FLOAT:
5639             tree->gtVNPair.SetBoth(vnStore->VNForFloatCon((float)tree->gtDblCon.gtDconVal));
5640             break;
5641         case TYP_DOUBLE:
5642             tree->gtVNPair.SetBoth(vnStore->VNForDoubleCon(tree->gtDblCon.gtDconVal));
5643             break;
5644         case TYP_REF:
5645             if (tree->gtIntConCommon.IconValue() == 0)
5646             {
5647                 tree->gtVNPair.SetBoth(ValueNumStore::VNForNull());
5648             }
5649             else
5650             {
5651                 assert(tree->gtFlags == GTF_ICON_STR_HDL); // Constant object can be only frozen string.
5652                 tree->gtVNPair.SetBoth(
5653                     vnStore->VNForHandle(ssize_t(tree->gtIntConCommon.IconValue()), tree->GetIconHandleFlag()));
5654             }
5655             break;
5656
5657         case TYP_BYREF:
5658             if (tree->gtIntConCommon.IconValue() == 0)
5659             {
5660                 tree->gtVNPair.SetBoth(ValueNumStore::VNForNull());
5661             }
5662             else
5663             {
5664                 assert(tree->IsCnsIntOrI());
5665
5666                 if (tree->IsIconHandle())
5667                 {
5668                     tree->gtVNPair.SetBoth(
5669                         vnStore->VNForHandle(ssize_t(tree->gtIntConCommon.IconValue()), tree->GetIconHandleFlag()));
5670                 }
5671                 else
5672                 {
5673                     tree->gtVNPair.SetBoth(vnStore->VNForByrefCon(tree->gtIntConCommon.IconValue()));
5674                 }
5675             }
5676             break;
5677
5678         default:
5679             unreached();
5680     }
5681 }
5682
5683 //------------------------------------------------------------------------
5684 // fgValueNumberBlockAssignment: Perform value numbering for block assignments.
5685 //
5686 // Arguments:
5687 //    tree          - the block assignment to be value numbered.
5688 //
5689 // Return Value:
5690 //    None.
5691 //
5692 // Assumptions:
5693 //    'tree' must be a block assignment (GT_INITBLK, GT_COPYBLK, GT_COPYOBJ).
5694
5695 void Compiler::fgValueNumberBlockAssignment(GenTree* tree)
5696 {
5697     GenTree* lhs = tree->gtGetOp1();
5698     GenTree* rhs = tree->gtGetOp2();
5699 #ifdef DEBUG
5700     // Sometimes we query the memory ssa map in an assertion, and need a dummy location for the ignored result.
5701     unsigned memorySsaNum;
5702 #endif
5703
5704     if (tree->OperIsInitBlkOp())
5705     {
5706         GenTreeLclVarCommon* lclVarTree;
5707         bool                 isEntire;
5708
5709         if (tree->DefinesLocal(this, &lclVarTree, &isEntire))
5710         {
5711             assert(lclVarTree->gtFlags & GTF_VAR_DEF);
5712             // Should not have been recorded as updating the GC heap.
5713             assert(!GetMemorySsaMap(GcHeap)->Lookup(tree, &memorySsaNum));
5714
5715             unsigned lclNum = lclVarTree->GetLclNum();
5716
5717             // Ignore vars that we excluded from SSA (for example, because they're address-exposed). They don't have
5718             // SSA names in which to store VN's on defs.  We'll yield unique VN's when we read from them.
5719             if (lvaInSsa(lclNum))
5720             {
5721                 // Should not have been recorded as updating ByrefExposed.
5722                 assert(!GetMemorySsaMap(ByrefExposed)->Lookup(tree, &memorySsaNum));
5723
5724                 unsigned lclDefSsaNum = GetSsaNumForLocalVarDef(lclVarTree);
5725
5726                 ValueNum initBlkVN = ValueNumStore::NoVN;
5727                 GenTree* initConst = rhs;
5728                 if (isEntire && initConst->OperGet() == GT_CNS_INT)
5729                 {
5730                     unsigned initVal = 0xFF & (unsigned)initConst->AsIntConCommon()->IconValue();
5731                     if (initVal == 0)
5732                     {
5733                         initBlkVN = vnStore->VNZeroForType(lclVarTree->TypeGet());
5734                     }
5735                 }
5736                 ValueNum lclVarVN = (initBlkVN != ValueNumStore::NoVN)
5737                                         ? initBlkVN
5738                                         : vnStore->VNForExpr(compCurBB, var_types(lvaTable[lclNum].lvType));
5739
5740                 lvaTable[lclNum].GetPerSsaData(lclDefSsaNum)->m_vnPair.SetBoth(lclVarVN);
5741 #ifdef DEBUG
5742                 if (verbose)
5743                 {
5744                     printf("N%03u ", tree->gtSeqNum);
5745                     Compiler::printTreeID(tree);
5746                     printf(" ");
5747                     gtDispNodeName(tree);
5748                     printf(" V%02u/%d => ", lclNum, lclDefSsaNum);
5749                     vnPrint(lclVarVN, 1);
5750                     printf("\n");
5751                 }
5752 #endif // DEBUG
5753             }
5754             else if (lvaVarAddrExposed(lclVarTree->gtLclNum))
5755             {
5756                 fgMutateAddressExposedLocal(tree DEBUGARG("INITBLK - address-exposed local"));
5757             }
5758         }
5759         else
5760         {
5761             // For now, arbitrary side effect on GcHeap/ByrefExposed.
5762             // TODO-CQ: Why not be complete, and get this case right?
5763             fgMutateGcHeap(tree DEBUGARG("INITBLK - non local"));
5764         }
5765         // Initblock's are of type void.  Give them the void "value" -- they may occur in argument lists, which we
5766         // want to be able to give VN's to.
5767         tree->gtVNPair.SetBoth(ValueNumStore::VNForVoid());
5768     }
5769     else
5770     {
5771         assert(tree->OperIsCopyBlkOp());
5772         // TODO-Cleanup: We should factor things so that we uniformly rely on "PtrTo" VN's, and
5773         // the memory cases can be shared with assignments.
5774         GenTreeLclVarCommon* lclVarTree = nullptr;
5775         bool                 isEntire   = false;
5776         // Note that we don't care about exceptions here, since we're only using the values
5777         // to perform an assignment (which happens after any exceptions are raised...)
5778
5779         if (tree->DefinesLocal(this, &lclVarTree, &isEntire))
5780         {
5781             // Should not have been recorded as updating the GC heap.
5782             assert(!GetMemorySsaMap(GcHeap)->Lookup(tree, &memorySsaNum));
5783
5784             unsigned      lhsLclNum = lclVarTree->GetLclNum();
5785             FieldSeqNode* lhsFldSeq = nullptr;
5786             // If it's excluded from SSA, don't need to do anything.
5787             if (lvaInSsa(lhsLclNum))
5788             {
5789                 // Should not have been recorded as updating ByrefExposed.
5790                 assert(!GetMemorySsaMap(ByrefExposed)->Lookup(tree, &memorySsaNum));
5791
5792                 unsigned lclDefSsaNum = GetSsaNumForLocalVarDef(lclVarTree);
5793
5794                 if (lhs->IsLocalExpr(this, &lclVarTree, &lhsFldSeq) ||
5795                     (lhs->OperIsBlk() && (lhs->AsBlk()->gtBlkSize == lvaLclSize(lhsLclNum))))
5796                 {
5797                     noway_assert(lclVarTree->gtLclNum == lhsLclNum);
5798                 }
5799                 else
5800                 {
5801                     GenTree* lhsAddr;
5802                     if (lhs->OperIsBlk())
5803                     {
5804                         lhsAddr = lhs->AsBlk()->Addr();
5805                     }
5806                     else
5807                     {
5808                         assert(lhs->OperGet() == GT_IND);
5809                         lhsAddr = lhs->gtOp.gtOp1;
5810                     }
5811
5812                     // For addr-of-local expressions, lib/cons shouldn't matter.
5813                     assert(lhsAddr->gtVNPair.BothEqual());
5814                     ValueNum lhsAddrVN = lhsAddr->GetVN(VNK_Liberal);
5815
5816                     // Unpack the PtrToLoc value number of the address.
5817                     assert(vnStore->IsVNFunc(lhsAddrVN));
5818
5819                     VNFuncApp lhsAddrFuncApp;
5820                     vnStore->GetVNFunc(lhsAddrVN, &lhsAddrFuncApp);
5821
5822                     assert(lhsAddrFuncApp.m_func == VNF_PtrToLoc);
5823                     assert(vnStore->IsVNConstant(lhsAddrFuncApp.m_args[0]) &&
5824                            vnStore->ConstantValue<unsigned>(lhsAddrFuncApp.m_args[0]) == lhsLclNum);
5825
5826                     lhsFldSeq = vnStore->FieldSeqVNToFieldSeq(lhsAddrFuncApp.m_args[1]);
5827                 }
5828
5829                 // Now we need to get the proper RHS.
5830                 GenTreeLclVarCommon* rhsLclVarTree = nullptr;
5831                 LclVarDsc*           rhsVarDsc     = nullptr;
5832                 FieldSeqNode*        rhsFldSeq     = nullptr;
5833                 ValueNumPair         rhsVNPair;
5834                 bool                 isNewUniq = false;
5835                 if (!rhs->OperIsIndir())
5836                 {
5837                     if (rhs->IsLocalExpr(this, &rhsLclVarTree, &rhsFldSeq))
5838                     {
5839                         unsigned rhsLclNum = rhsLclVarTree->GetLclNum();
5840                         rhsVarDsc          = &lvaTable[rhsLclNum];
5841                         if (!lvaInSsa(rhsLclNum) || rhsFldSeq == FieldSeqStore::NotAField())
5842                         {
5843                             rhsVNPair.SetBoth(vnStore->VNForExpr(compCurBB, rhsLclVarTree->TypeGet()));
5844                             isNewUniq = true;
5845                         }
5846                         else
5847                         {
5848                             rhsVNPair = lvaTable[rhsLclVarTree->GetLclNum()]
5849                                             .GetPerSsaData(rhsLclVarTree->GetSsaNum())
5850                                             ->m_vnPair;
5851                             var_types indType = rhsLclVarTree->TypeGet();
5852
5853                             rhsVNPair = vnStore->VNPairApplySelectors(rhsVNPair, rhsFldSeq, indType);
5854                         }
5855                     }
5856                     else
5857                     {
5858                         rhsVNPair.SetBoth(vnStore->VNForExpr(compCurBB, rhs->TypeGet()));
5859                         isNewUniq = true;
5860                     }
5861                 }
5862                 else
5863                 {
5864                     GenTree*  srcAddr = rhs->AsIndir()->Addr();
5865                     VNFuncApp srcAddrFuncApp;
5866                     if (srcAddr->IsLocalAddrExpr(this, &rhsLclVarTree, &rhsFldSeq))
5867                     {
5868                         unsigned rhsLclNum = rhsLclVarTree->GetLclNum();
5869                         rhsVarDsc          = &lvaTable[rhsLclNum];
5870                         if (!lvaInSsa(rhsLclNum) || rhsFldSeq == FieldSeqStore::NotAField())
5871                         {
5872                             isNewUniq = true;
5873                         }
5874                         else
5875                         {
5876                             rhsVNPair = lvaTable[rhsLclVarTree->GetLclNum()]
5877                                             .GetPerSsaData(rhsLclVarTree->GetSsaNum())
5878                                             ->m_vnPair;
5879                             var_types indType = rhsLclVarTree->TypeGet();
5880
5881                             rhsVNPair = vnStore->VNPairApplySelectors(rhsVNPair, rhsFldSeq, indType);
5882                         }
5883                     }
5884                     else if (vnStore->GetVNFunc(vnStore->VNNormVal(srcAddr->gtVNPair.GetLiberal()), &srcAddrFuncApp))
5885                     {
5886                         if (srcAddrFuncApp.m_func == VNF_PtrToStatic)
5887                         {
5888                             var_types indType    = lclVarTree->TypeGet();
5889                             ValueNum  fieldSeqVN = srcAddrFuncApp.m_args[0];
5890
5891                             FieldSeqNode* zeroOffsetFldSeq = nullptr;
5892                             if (GetZeroOffsetFieldMap()->Lookup(srcAddr, &zeroOffsetFldSeq))
5893                             {
5894                                 fieldSeqVN =
5895                                     vnStore->FieldSeqVNAppend(fieldSeqVN, vnStore->VNForFieldSeq(zeroOffsetFldSeq));
5896                             }
5897
5898                             FieldSeqNode* fldSeqForStaticVar = vnStore->FieldSeqVNToFieldSeq(fieldSeqVN);
5899
5900                             if (fldSeqForStaticVar != FieldSeqStore::NotAField())
5901                             {
5902                                 // We model statics as indices into GcHeap (which is a subset of ByrefExposed).
5903                                 ValueNum selectedStaticVar;
5904                                 size_t   structSize = 0;
5905                                 selectedStaticVar   = vnStore->VNApplySelectors(VNK_Liberal, fgCurMemoryVN[GcHeap],
5906                                                                               fldSeqForStaticVar, &structSize);
5907                                 selectedStaticVar =
5908                                     vnStore->VNApplySelectorsTypeCheck(selectedStaticVar, indType, structSize);
5909
5910                                 rhsVNPair.SetLiberal(selectedStaticVar);
5911                                 rhsVNPair.SetConservative(vnStore->VNForExpr(compCurBB, indType));
5912                             }
5913                             else
5914                             {
5915                                 JITDUMP("    *** Missing field sequence info for Src/RHS of COPYBLK\n");
5916                                 rhsVNPair.SetBoth(vnStore->VNForExpr(compCurBB, indType)); //  a new unique value number
5917                             }
5918                         }
5919                         else if (srcAddrFuncApp.m_func == VNF_PtrToArrElem)
5920                         {
5921                             ValueNum elemLib =
5922                                 fgValueNumberArrIndexVal(nullptr, &srcAddrFuncApp, vnStore->VNForEmptyExcSet());
5923                             rhsVNPair.SetLiberal(elemLib);
5924                             rhsVNPair.SetConservative(vnStore->VNForExpr(compCurBB, lclVarTree->TypeGet()));
5925                         }
5926                         else
5927                         {
5928                             isNewUniq = true;
5929                         }
5930                     }
5931                     else
5932                     {
5933                         isNewUniq = true;
5934                     }
5935                 }
5936
5937                 if (lhsFldSeq == FieldSeqStore::NotAField())
5938                 {
5939                     // We don't have proper field sequence information for the lhs
5940                     //
5941                     JITDUMP("    *** Missing field sequence info for Dst/LHS of COPYBLK\n");
5942                     isNewUniq = true;
5943                 }
5944                 else if (lhsFldSeq != nullptr && isEntire)
5945                 {
5946                     // This can occur in for structs with one field, itself of a struct type.
5947                     // We won't promote these.
5948                     // TODO-Cleanup: decide what exactly to do about this.
5949                     // Always treat them as maps, making them use/def, or reconstitute the
5950                     // map view here?
5951                     isNewUniq = true;
5952                 }
5953                 else if (!isNewUniq)
5954                 {
5955                     ValueNumPair oldLhsVNPair = lvaTable[lhsLclNum].GetPerSsaData(lclVarTree->GetSsaNum())->m_vnPair;
5956                     rhsVNPair                 = vnStore->VNPairApplySelectorsAssign(oldLhsVNPair, lhsFldSeq, rhsVNPair,
5957                                                                     lclVarTree->TypeGet(), compCurBB);
5958                 }
5959
5960                 if (isNewUniq)
5961                 {
5962                     rhsVNPair.SetBoth(vnStore->VNForExpr(compCurBB, lclVarTree->TypeGet()));
5963                 }
5964
5965                 lvaTable[lhsLclNum].GetPerSsaData(lclDefSsaNum)->m_vnPair = vnStore->VNPNormVal(rhsVNPair);
5966
5967 #ifdef DEBUG
5968                 if (verbose)
5969                 {
5970                     printf("Tree ");
5971                     Compiler::printTreeID(tree);
5972                     printf(" assigned VN to local var V%02u/%d: ", lhsLclNum, lclDefSsaNum);
5973                     if (isNewUniq)
5974                     {
5975                         printf("new uniq ");
5976                     }
5977                     vnpPrint(rhsVNPair, 1);
5978                     printf("\n");
5979                 }
5980 #endif // DEBUG
5981             }
5982             else if (lvaVarAddrExposed(lhsLclNum))
5983             {
5984                 fgMutateAddressExposedLocal(tree DEBUGARG("COPYBLK - address-exposed local"));
5985             }
5986         }
5987         else
5988         {
5989             // For now, arbitrary side effect on GcHeap/ByrefExposed.
5990             // TODO-CQ: Why not be complete, and get this case right?
5991             fgMutateGcHeap(tree DEBUGARG("COPYBLK - non local"));
5992         }
5993         // Copyblock's are of type void.  Give them the void "value" -- they may occur in argument lists, which we want
5994         // to be able to give VN's to.
5995         tree->gtVNPair.SetBoth(ValueNumStore::VNForVoid());
5996     }
5997 }
5998
5999 void Compiler::fgValueNumberTree(GenTree* tree)
6000 {
6001     genTreeOps oper = tree->OperGet();
6002
6003 #ifdef FEATURE_SIMD
6004     // TODO-CQ: For now TYP_SIMD values are not handled by value numbering to be amenable for CSE'ing.
6005     if (oper == GT_SIMD)
6006     {
6007         tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, TYP_UNKNOWN));
6008         return;
6009     }
6010 #endif
6011
6012 #ifdef FEATURE_HW_INTRINSICS
6013     if (oper == GT_HWIntrinsic)
6014     {
6015         // TODO-CQ: For now hardware intrinsics are not handled by value numbering to be amenable for CSE'ing.
6016         tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, TYP_UNKNOWN));
6017
6018         GenTreeHWIntrinsic* hwIntrinsicNode = tree->AsHWIntrinsic();
6019         assert(hwIntrinsicNode != nullptr);
6020
6021         // For safety/correctness we must mutate the global heap valuenumber
6022         //  for any HW intrinsic that performs a memory store operation
6023         if (hwIntrinsicNode->OperIsMemoryStore())
6024         {
6025             fgMutateGcHeap(tree DEBUGARG("HWIntrinsic - MemoryStore"));
6026         }
6027
6028         return;
6029     }
6030 #endif // FEATURE_HW_INTRINSICS
6031
6032     var_types typ = tree->TypeGet();
6033     if (GenTree::OperIsConst(oper))
6034     {
6035         // If this is a struct assignment, with a constant rhs, it is an initBlk, and it is not
6036         // really useful to value number the constant.
6037         if (!varTypeIsStruct(tree))
6038         {
6039             fgValueNumberTreeConst(tree);
6040         }
6041     }
6042     else if (GenTree::OperIsLeaf(oper))
6043     {
6044         switch (oper)
6045         {
6046             case GT_LCL_VAR:
6047             case GT_REG_VAR:
6048             {
6049                 GenTreeLclVarCommon* lcl    = tree->AsLclVarCommon();
6050                 unsigned             lclNum = lcl->gtLclNum;
6051
6052                 if ((lcl->gtFlags & GTF_VAR_DEF) == 0 ||
6053                     (lcl->gtFlags & GTF_VAR_USEASG)) // If it is a "pure" def, will handled as part of the assignment.
6054                 {
6055                     LclVarDsc* varDsc = &lvaTable[lcl->gtLclNum];
6056                     if (varDsc->lvPromoted && varDsc->lvFieldCnt == 1)
6057                     {
6058                         // If the promoted var has only one field var, treat like a use of the field var.
6059                         lclNum = varDsc->lvFieldLclStart;
6060                     }
6061
6062                     // Initialize to the undefined value, so we know whether we hit any of the cases here.
6063                     lcl->gtVNPair = ValueNumPair();
6064
6065                     if (lcl->gtSsaNum == SsaConfig::RESERVED_SSA_NUM)
6066                     {
6067                         // Not an SSA variable.
6068
6069                         if (lvaVarAddrExposed(lclNum))
6070                         {
6071                             // Address-exposed locals are part of ByrefExposed.
6072                             ValueNum addrVN = vnStore->VNForFunc(TYP_BYREF, VNF_PtrToLoc, vnStore->VNForIntCon(lclNum),
6073                                                                  vnStore->VNForFieldSeq(nullptr));
6074                             ValueNum loadVN = fgValueNumberByrefExposedLoad(typ, addrVN);
6075
6076                             lcl->gtVNPair.SetBoth(loadVN);
6077                         }
6078                         else
6079                         {
6080                             // Assign odd cases a new, unique, VN.
6081                             lcl->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, lcl->TypeGet()));
6082                         }
6083                     }
6084                     else
6085                     {
6086                         var_types    varType        = varDsc->TypeGet();
6087                         ValueNumPair wholeLclVarVNP = varDsc->GetPerSsaData(lcl->gtSsaNum)->m_vnPair;
6088
6089                         // Check for mismatched LclVar size
6090                         //
6091                         unsigned typSize = genTypeSize(genActualType(typ));
6092                         unsigned varSize = genTypeSize(genActualType(varType));
6093
6094                         if (typSize == varSize)
6095                         {
6096                             lcl->gtVNPair = wholeLclVarVNP;
6097                         }
6098                         else // mismatched LclVar definition and LclVar use size
6099                         {
6100                             if (typSize < varSize)
6101                             {
6102                                 // the indirection is reading less that the whole LclVar
6103                                 // create a new VN that represent the partial value
6104                                 //
6105                                 ValueNumPair partialLclVarVNP = vnStore->VNPairForCast(wholeLclVarVNP, typ, varType);
6106                                 lcl->gtVNPair                 = partialLclVarVNP;
6107                             }
6108                             else
6109                             {
6110                                 assert(typSize > varSize);
6111                                 // the indirection is reading beyond the end of the field
6112                                 //
6113                                 lcl->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, typ)); // return a new unique value
6114                                                                                            // number
6115                             }
6116                         }
6117                     }
6118                     // Temporary, to make progress.
6119                     // TODO-CQ: This should become an assert again...
6120                     if (lcl->gtVNPair.GetLiberal() == ValueNumStore::NoVN)
6121                     {
6122                         assert(lcl->gtVNPair.GetConservative() == ValueNumStore::NoVN);
6123
6124                         // We don't want to fabricate arbitrary value numbers to things we can't reason about.
6125                         // So far, we know about two of these cases:
6126                         // Case 1) We have a local var who has never been defined but it's seen as a use.
6127                         //         This is the case of storeIndir(addr(lclvar)) = expr.  In this case since we only
6128                         //         take the address of the variable, this doesn't mean it's a use nor we have to
6129                         //         initialize it, so in this very rare case, we fabricate a value number.
6130                         // Case 2) Local variables that represent structs which are assigned using CpBlk.
6131                         GenTree* nextNode = lcl->gtNext;
6132                         assert((nextNode->gtOper == GT_ADDR && nextNode->gtOp.gtOp1 == lcl) ||
6133                                varTypeIsStruct(lcl->TypeGet()));
6134                         lcl->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, lcl->TypeGet()));
6135                     }
6136                     assert(lcl->gtVNPair.BothDefined());
6137                 }
6138
6139                 // TODO-Review: For the short term, we have a workaround for copyblk/initblk.  Those that use
6140                 // addrSpillTemp will have a statement like "addrSpillTemp = addr(local)."  If we previously decided
6141                 // that this block operation defines the local, we will have labeled the "local" node as a DEF
6142                 // This flag propagates to the "local" on the RHS.  So we'll assume that this is correct,
6143                 // and treat it as a def (to a new, unique VN).
6144                 else if ((lcl->gtFlags & GTF_VAR_DEF) != 0)
6145                 {
6146                     LclVarDsc* varDsc = &lvaTable[lcl->gtLclNum];
6147                     if (lcl->gtSsaNum != SsaConfig::RESERVED_SSA_NUM)
6148                     {
6149                         lvaTable[lclNum]
6150                             .GetPerSsaData(lcl->gtSsaNum)
6151                             ->m_vnPair.SetBoth(vnStore->VNForExpr(compCurBB, lcl->TypeGet()));
6152                     }
6153                     lcl->gtVNPair = ValueNumPair(); // Avoid confusion -- we don't set the VN of a lcl being defined.
6154                 }
6155             }
6156             break;
6157
6158             case GT_FTN_ADDR:
6159                 // Use the value of the function pointer (actually, a method handle.)
6160                 tree->gtVNPair.SetBoth(
6161                     vnStore->VNForHandle(ssize_t(tree->gtFptrVal.gtFptrMethod), GTF_ICON_METHOD_HDL));
6162                 break;
6163
6164             // This group passes through a value from a child node.
6165             case GT_RET_EXPR:
6166                 tree->SetVNsFromNode(tree->gtRetExpr.gtInlineCandidate);
6167                 break;
6168
6169             case GT_LCL_FLD:
6170             {
6171                 GenTreeLclFld* lclFld = tree->AsLclFld();
6172                 assert(!lvaInSsa(lclFld->GetLclNum()) || lclFld->gtFieldSeq != nullptr);
6173                 // If this is a (full) def, then the variable will be labeled with the new SSA number,
6174                 // which will not have a value.  We skip; it will be handled by one of the assignment-like
6175                 // forms (assignment, or initBlk or copyBlk).
6176                 if (((lclFld->gtFlags & GTF_VAR_DEF) == 0) || (lclFld->gtFlags & GTF_VAR_USEASG))
6177                 {
6178                     unsigned   lclNum = lclFld->GetLclNum();
6179                     unsigned   ssaNum = lclFld->GetSsaNum();
6180                     LclVarDsc* varDsc = &lvaTable[lclNum];
6181
6182                     var_types indType = tree->TypeGet();
6183                     if (lclFld->gtFieldSeq == FieldSeqStore::NotAField() || !lvaInSsa(lclFld->GetLclNum()))
6184                     {
6185                         // This doesn't represent a proper field access or it's a struct
6186                         // with overlapping fields that is hard to reason about; return a new unique VN.
6187                         tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, indType));
6188                     }
6189                     else
6190                     {
6191                         ValueNumPair lclVNPair = varDsc->GetPerSsaData(ssaNum)->m_vnPair;
6192                         tree->gtVNPair         = vnStore->VNPairApplySelectors(lclVNPair, lclFld->gtFieldSeq, indType);
6193                     }
6194                 }
6195             }
6196             break;
6197
6198             // The ones below here all get a new unique VN -- but for various reasons, explained after each.
6199             case GT_CATCH_ARG:
6200                 // We know nothing about the value of a caught expression.
6201                 tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
6202                 break;
6203
6204             case GT_CLS_VAR:
6205                 // Skip GT_CLS_VAR nodes that are the LHS of an assignment.  (We labeled these earlier.)
6206                 // We will "evaluate" this as part of the assignment.
6207                 //
6208                 if ((tree->gtFlags & GTF_CLS_VAR_ASG_LHS) == 0)
6209                 {
6210                     bool isVolatile = (tree->gtFlags & GTF_FLD_VOLATILE) != 0;
6211
6212                     if (isVolatile)
6213                     {
6214                         // For Volatile indirection, first mutate GcHeap/ByrefExposed
6215                         fgMutateGcHeap(tree DEBUGARG("GTF_FLD_VOLATILE - read"));
6216                     }
6217
6218                     // We just mutate GcHeap/ByrefExposed if isVolatile is true, and then do the read as normal.
6219                     //
6220                     // This allows:
6221                     //   1: read s;
6222                     //   2: volatile read s;
6223                     //   3: read s;
6224                     //
6225                     // We should never assume that the values read by 1 and 2 are the same (because the heap was mutated
6226                     // in between them)... but we *should* be able to prove that the values read in 2 and 3 are the
6227                     // same.
6228                     //
6229
6230                     ValueNumPair clsVarVNPair;
6231
6232                     // If the static field handle is for a struct type field, then the value of the static
6233                     // is a "ref" to the boxed struct -- treat it as the address of the static (we assume that a
6234                     // first element offset will be added to get to the actual struct...)
6235                     GenTreeClsVar* clsVar = tree->AsClsVar();
6236                     FieldSeqNode*  fldSeq = clsVar->gtFieldSeq;
6237                     assert(fldSeq != nullptr); // We need to have one.
6238                     ValueNum selectedStaticVar = ValueNumStore::NoVN;
6239                     if (gtIsStaticFieldPtrToBoxedStruct(clsVar->TypeGet(), fldSeq->m_fieldHnd))
6240                     {
6241                         clsVarVNPair.SetBoth(
6242                             vnStore->VNForFunc(TYP_BYREF, VNF_PtrToStatic, vnStore->VNForFieldSeq(fldSeq)));
6243                     }
6244                     else
6245                     {
6246                         // This is a reference to heap memory.
6247                         // We model statics as indices into GcHeap (which is a subset of ByrefExposed).
6248
6249                         FieldSeqNode* fldSeqForStaticVar =
6250                             GetFieldSeqStore()->CreateSingleton(tree->gtClsVar.gtClsVarHnd);
6251                         size_t structSize = 0;
6252                         selectedStaticVar = vnStore->VNApplySelectors(VNK_Liberal, fgCurMemoryVN[GcHeap],
6253                                                                       fldSeqForStaticVar, &structSize);
6254                         selectedStaticVar =
6255                             vnStore->VNApplySelectorsTypeCheck(selectedStaticVar, tree->TypeGet(), structSize);
6256
6257                         clsVarVNPair.SetLiberal(selectedStaticVar);
6258                         // The conservative interpretation always gets a new, unique VN.
6259                         clsVarVNPair.SetConservative(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
6260                     }
6261
6262                     // The ValueNum returned must represent the full-sized IL-Stack value
6263                     // If we need to widen this value then we need to introduce a VNF_Cast here to represent
6264                     // the widened value.    This is necessary since the CSE package can replace all occurances
6265                     // of a given ValueNum with a LclVar that is a full-sized IL-Stack value
6266                     //
6267                     if (varTypeIsSmall(tree->TypeGet()))
6268                     {
6269                         var_types castToType = tree->TypeGet();
6270                         clsVarVNPair         = vnStore->VNPairForCast(clsVarVNPair, castToType, castToType);
6271                     }
6272                     tree->gtVNPair = clsVarVNPair;
6273                 }
6274                 break;
6275
6276             case GT_MEMORYBARRIER: // Leaf
6277                 // For MEMORYBARRIER add an arbitrary side effect on GcHeap/ByrefExposed.
6278                 fgMutateGcHeap(tree DEBUGARG("MEMORYBARRIER"));
6279                 break;
6280
6281             // These do not represent values.
6282             case GT_NO_OP:
6283             case GT_JMP:   // Control flow
6284             case GT_LABEL: // Control flow
6285 #if !FEATURE_EH_FUNCLETS
6286             case GT_END_LFIN: // Control flow
6287 #endif
6288             case GT_ARGPLACE:
6289                 // This node is a standin for an argument whose value will be computed later.  (Perhaps it's
6290                 // a register argument, and we don't want to preclude use of the register in arg evaluation yet.)
6291                 // We give this a "fake" value number now; if the call in which it occurs cares about the
6292                 // value (e.g., it's a helper call whose result is a function of argument values) we'll reset
6293                 // this later, when the later args have been assigned VNs.
6294                 tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
6295                 break;
6296
6297             case GT_PHI_ARG:
6298                 // This one is special because we should never process it in this method: it should
6299                 // always be taken care of, when needed, during pre-processing of a blocks phi definitions.
6300                 assert(false);
6301                 break;
6302
6303             default:
6304                 unreached();
6305         }
6306     }
6307     else if (GenTree::OperIsSimple(oper))
6308     {
6309 #ifdef DEBUG
6310         // Sometimes we query the memory ssa map in an assertion, and need a dummy location for the ignored result.
6311         unsigned memorySsaNum;
6312 #endif
6313
6314         if ((oper == GT_ASG) && !varTypeIsStruct(tree))
6315         {
6316             GenTree* lhs = tree->gtOp.gtOp1;
6317             GenTree* rhs = tree->gtOp.gtOp2;
6318
6319             ValueNumPair rhsVNPair = rhs->gtVNPair;
6320
6321             // Is the type being stored different from the type computed by the rhs?
6322             if (rhs->TypeGet() != lhs->TypeGet())
6323             {
6324                 // This means that there is an implicit cast on the rhs value
6325                 //
6326                 // We will add a cast function to reflect the possible narrowing of the rhs value
6327                 //
6328                 var_types castToType   = lhs->TypeGet();
6329                 var_types castFromType = rhs->TypeGet();
6330                 bool      isUnsigned   = varTypeIsUnsigned(castFromType);
6331
6332                 rhsVNPair = vnStore->VNPairForCast(rhsVNPair, castToType, castFromType, isUnsigned);
6333             }
6334
6335             if (tree->TypeGet() != TYP_VOID)
6336             {
6337                 // Assignment operators, as expressions, return the value of the RHS.
6338                 tree->gtVNPair = rhsVNPair;
6339             }
6340
6341             // Now that we've labeled the assignment as a whole, we don't care about exceptions.
6342             rhsVNPair = vnStore->VNPNormVal(rhsVNPair);
6343
6344             // If the types of the rhs and lhs are different then we
6345             //  may want to change the ValueNumber assigned to the lhs.
6346             //
6347             if (rhs->TypeGet() != lhs->TypeGet())
6348             {
6349                 if (rhs->TypeGet() == TYP_REF)
6350                 {
6351                     // If we have an unsafe IL assignment of a TYP_REF to a non-ref (typically a TYP_BYREF)
6352                     // then don't propagate this ValueNumber to the lhs, instead create a new unique VN
6353                     //
6354                     rhsVNPair.SetBoth(vnStore->VNForExpr(compCurBB, lhs->TypeGet()));
6355                 }
6356             }
6357
6358             // We have to handle the case where the LHS is a comma.  In that case, we don't evaluate the comma,
6359             // so we give it VNForVoid, and we're really interested in the effective value.
6360             GenTree* lhsCommaIter = lhs;
6361             while (lhsCommaIter->OperGet() == GT_COMMA)
6362             {
6363                 lhsCommaIter->gtVNPair.SetBoth(vnStore->VNForVoid());
6364                 lhsCommaIter = lhsCommaIter->gtOp.gtOp2;
6365             }
6366             lhs = lhs->gtEffectiveVal();
6367
6368             // Now, record the new VN for an assignment (performing the indicated "state update").
6369             // It's safe to use gtEffectiveVal here, because the non-last elements of a comma list on the
6370             // LHS will come before the assignment in evaluation order.
6371             switch (lhs->OperGet())
6372             {
6373                 case GT_LCL_VAR:
6374                 case GT_REG_VAR:
6375                 {
6376                     GenTreeLclVarCommon* lcl          = lhs->AsLclVarCommon();
6377                     unsigned             lclDefSsaNum = GetSsaNumForLocalVarDef(lcl);
6378
6379                     // Should not have been recorded as updating the GC heap.
6380                     assert(!GetMemorySsaMap(GcHeap)->Lookup(tree, &memorySsaNum));
6381
6382                     if (lclDefSsaNum != SsaConfig::RESERVED_SSA_NUM)
6383                     {
6384                         // Should not have been recorded as updating ByrefExposed mem.
6385                         assert(!GetMemorySsaMap(ByrefExposed)->Lookup(tree, &memorySsaNum));
6386
6387                         assert(rhsVNPair.GetLiberal() != ValueNumStore::NoVN);
6388
6389                         lhs->gtVNPair                                                 = rhsVNPair;
6390                         lvaTable[lcl->gtLclNum].GetPerSsaData(lclDefSsaNum)->m_vnPair = rhsVNPair;
6391
6392 #ifdef DEBUG
6393                         if (verbose)
6394                         {
6395                             printf("N%03u ", lhs->gtSeqNum);
6396                             Compiler::printTreeID(lhs);
6397                             printf(" ");
6398                             gtDispNodeName(lhs);
6399                             gtDispLeaf(lhs, nullptr);
6400                             printf(" => ");
6401                             vnpPrint(lhs->gtVNPair, 1);
6402                             printf("\n");
6403                         }
6404 #endif // DEBUG
6405                     }
6406                     else if (lvaVarAddrExposed(lcl->gtLclNum))
6407                     {
6408                         // We could use MapStore here and MapSelect on reads of address-exposed locals
6409                         // (using the local nums as selectors) to get e.g. propagation of values
6410                         // through address-taken locals in regions of code with no calls or byref
6411                         // writes.
6412                         // For now, just use a new opaque VN.
6413                         ValueNum heapVN = vnStore->VNForExpr(compCurBB);
6414                         recordAddressExposedLocalStore(tree, heapVN DEBUGARG("local assign"));
6415                     }
6416 #ifdef DEBUG
6417                     else
6418                     {
6419                         if (verbose)
6420                         {
6421                             JITDUMP("Tree ");
6422                             Compiler::printTreeID(tree);
6423                             printf(" assigns to non-address-taken local var V%02u; excluded from SSA, so value not "
6424                                    "tracked.\n",
6425                                    lcl->GetLclNum());
6426                         }
6427                     }
6428 #endif // DEBUG
6429                 }
6430                 break;
6431                 case GT_LCL_FLD:
6432                 {
6433                     GenTreeLclFld* lclFld       = lhs->AsLclFld();
6434                     unsigned       lclDefSsaNum = GetSsaNumForLocalVarDef(lclFld);
6435
6436                     // Should not have been recorded as updating the GC heap.
6437                     assert(!GetMemorySsaMap(GcHeap)->Lookup(tree, &memorySsaNum));
6438
6439                     if (lclDefSsaNum != SsaConfig::RESERVED_SSA_NUM)
6440                     {
6441                         ValueNumPair newLhsVNPair;
6442                         // Is this a full definition?
6443                         if ((lclFld->gtFlags & GTF_VAR_USEASG) == 0)
6444                         {
6445                             assert(!lclFld->IsPartialLclFld(this));
6446                             assert(rhsVNPair.GetLiberal() != ValueNumStore::NoVN);
6447                             newLhsVNPair = rhsVNPair;
6448                         }
6449                         else
6450                         {
6451                             // We should never have a null field sequence here.
6452                             assert(lclFld->gtFieldSeq != nullptr);
6453                             if (lclFld->gtFieldSeq == FieldSeqStore::NotAField())
6454                             {
6455                                 // We don't know what field this represents.  Assign a new VN to the whole variable
6456                                 // (since we may be writing to an unknown portion of it.)
6457                                 newLhsVNPair.SetBoth(vnStore->VNForExpr(compCurBB, lvaGetActualType(lclFld->gtLclNum)));
6458                             }
6459                             else
6460                             {
6461                                 // We do know the field sequence.
6462                                 // The "lclFld" node will be labeled with the SSA number of its "use" identity
6463                                 // (we looked in a side table above for its "def" identity).  Look up that value.
6464                                 ValueNumPair oldLhsVNPair =
6465                                     lvaTable[lclFld->GetLclNum()].GetPerSsaData(lclFld->GetSsaNum())->m_vnPair;
6466                                 newLhsVNPair = vnStore->VNPairApplySelectorsAssign(oldLhsVNPair, lclFld->gtFieldSeq,
6467                                                                                    rhsVNPair, // Pre-value.
6468                                                                                    lclFld->TypeGet(), compCurBB);
6469                             }
6470                         }
6471                         lvaTable[lclFld->GetLclNum()].GetPerSsaData(lclDefSsaNum)->m_vnPair = newLhsVNPair;
6472                         lhs->gtVNPair                                                       = newLhsVNPair;
6473 #ifdef DEBUG
6474                         if (verbose)
6475                         {
6476                             if (lhs->gtVNPair.GetLiberal() != ValueNumStore::NoVN)
6477                             {
6478                                 printf("N%03u ", lhs->gtSeqNum);
6479                                 Compiler::printTreeID(lhs);
6480                                 printf(" ");
6481                                 gtDispNodeName(lhs);
6482                                 gtDispLeaf(lhs, nullptr);
6483                                 printf(" => ");
6484                                 vnpPrint(lhs->gtVNPair, 1);
6485                                 printf("\n");
6486                             }
6487                         }
6488 #endif // DEBUG
6489                     }
6490                     else if (lvaVarAddrExposed(lclFld->gtLclNum))
6491                     {
6492                         // This side-effects ByrefExposed.  Just use a new opaque VN.
6493                         // As with GT_LCL_VAR, we could probably use MapStore here and MapSelect at corresponding
6494                         // loads, but to do so would have to identify the subset of address-exposed locals
6495                         // whose fields can be disambiguated.
6496                         ValueNum heapVN = vnStore->VNForExpr(compCurBB);
6497                         recordAddressExposedLocalStore(tree, heapVN DEBUGARG("local field assign"));
6498                     }
6499                 }
6500                 break;
6501
6502                 case GT_PHI_ARG:
6503                     noway_assert(!"Phi arg cannot be LHS.");
6504                     break;
6505
6506                 case GT_BLK:
6507                 case GT_OBJ:
6508                     noway_assert(!"GT_BLK/GT_OBJ can not be LHS when !varTypeIsStruct(tree) is true!");
6509                     break;
6510
6511                 case GT_IND:
6512                 {
6513                     bool isVolatile = (lhs->gtFlags & GTF_IND_VOLATILE) != 0;
6514
6515                     if (isVolatile)
6516                     {
6517                         // For Volatile store indirection, first mutate GcHeap/ByrefExposed
6518                         fgMutateGcHeap(lhs DEBUGARG("GTF_IND_VOLATILE - store"));
6519                         tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, lhs->TypeGet()));
6520                     }
6521
6522                     GenTree* arg = lhs->gtOp.gtOp1;
6523
6524                     // Indicates whether the argument of the IND is the address of a local.
6525                     bool wasLocal = false;
6526
6527                     lhs->gtVNPair = rhsVNPair;
6528
6529                     VNFuncApp funcApp;
6530                     ValueNum  argVN = arg->gtVNPair.GetLiberal();
6531
6532                     bool argIsVNFunc = vnStore->GetVNFunc(vnStore->VNNormVal(argVN), &funcApp);
6533
6534                     // Is this an assignment to a (field of, perhaps) a local?
6535                     // If it is a PtrToLoc, lib and cons VNs will be the same.
6536                     if (argIsVNFunc)
6537                     {
6538                         if (funcApp.m_func == VNF_PtrToLoc)
6539                         {
6540                             assert(arg->gtVNPair.BothEqual()); // If it's a PtrToLoc, lib/cons shouldn't differ.
6541                             assert(vnStore->IsVNConstant(funcApp.m_args[0]));
6542                             unsigned lclNum = vnStore->ConstantValue<unsigned>(funcApp.m_args[0]);
6543
6544                             wasLocal = true;
6545
6546                             if (lvaInSsa(lclNum))
6547                             {
6548                                 FieldSeqNode* fieldSeq = vnStore->FieldSeqVNToFieldSeq(funcApp.m_args[1]);
6549
6550                                 // Either "arg" is the address of (part of) a local itself, or else we have
6551                                 // a "rogue" PtrToLoc, one that should have made the local in question
6552                                 // address-exposed.  Assert on that.
6553                                 GenTreeLclVarCommon* lclVarTree   = nullptr;
6554                                 bool                 isEntire     = false;
6555                                 unsigned             lclDefSsaNum = SsaConfig::RESERVED_SSA_NUM;
6556                                 ValueNumPair         newLhsVNPair;
6557
6558                                 if (arg->DefinesLocalAddr(this, genTypeSize(lhs->TypeGet()), &lclVarTree, &isEntire))
6559                                 {
6560                                     // The local #'s should agree.
6561                                     assert(lclNum == lclVarTree->GetLclNum());
6562
6563                                     if (fieldSeq == FieldSeqStore::NotAField())
6564                                     {
6565                                         // We don't know where we're storing, so give the local a new, unique VN.
6566                                         // Do this by considering it an "entire" assignment, with an unknown RHS.
6567                                         isEntire = true;
6568                                         rhsVNPair.SetBoth(vnStore->VNForExpr(compCurBB, lclVarTree->TypeGet()));
6569                                     }
6570
6571                                     if (isEntire)
6572                                     {
6573                                         newLhsVNPair = rhsVNPair;
6574                                         lclDefSsaNum = lclVarTree->GetSsaNum();
6575                                     }
6576                                     else
6577                                     {
6578                                         // Don't use the lclVarTree's VN: if it's a local field, it will
6579                                         // already be dereferenced by it's field sequence.
6580                                         ValueNumPair oldLhsVNPair = lvaTable[lclVarTree->GetLclNum()]
6581                                                                         .GetPerSsaData(lclVarTree->GetSsaNum())
6582                                                                         ->m_vnPair;
6583                                         lclDefSsaNum = GetSsaNumForLocalVarDef(lclVarTree);
6584                                         newLhsVNPair =
6585                                             vnStore->VNPairApplySelectorsAssign(oldLhsVNPair, fieldSeq, rhsVNPair,
6586                                                                                 lhs->TypeGet(), compCurBB);
6587                                     }
6588                                     lvaTable[lclNum].GetPerSsaData(lclDefSsaNum)->m_vnPair = newLhsVNPair;
6589                                 }
6590                                 else
6591                                 {
6592                                     unreached(); // "Rogue" PtrToLoc, as discussed above.
6593                                 }
6594 #ifdef DEBUG
6595                                 if (verbose)
6596                                 {
6597                                     printf("Tree ");
6598                                     Compiler::printTreeID(tree);
6599                                     printf(" assigned VN to local var V%02u/%d: VN ", lclNum, lclDefSsaNum);
6600                                     vnpPrint(newLhsVNPair, 1);
6601                                     printf("\n");
6602                                 }
6603 #endif // DEBUG
6604                             }
6605                             else if (lvaVarAddrExposed(lclNum))
6606                             {
6607                                 // Need to record the effect on ByrefExposed.
6608                                 // We could use MapStore here and MapSelect on reads of address-exposed locals
6609                                 // (using the local nums as selectors) to get e.g. propagation of values
6610                                 // through address-taken locals in regions of code with no calls or byref
6611                                 // writes.
6612                                 // For now, just use a new opaque VN.
6613                                 ValueNum heapVN = vnStore->VNForExpr(compCurBB);
6614                                 recordAddressExposedLocalStore(tree, heapVN DEBUGARG("PtrToLoc indir"));
6615                             }
6616                         }
6617                     }
6618
6619                     // Was the argument of the GT_IND the address of a local, handled above?
6620                     if (!wasLocal)
6621                     {
6622                         GenTree*      obj          = nullptr;
6623                         GenTree*      staticOffset = nullptr;
6624                         FieldSeqNode* fldSeq       = nullptr;
6625
6626                         // Is the LHS an array index expression?
6627                         if (argIsVNFunc && funcApp.m_func == VNF_PtrToArrElem)
6628                         {
6629                             CORINFO_CLASS_HANDLE elemTypeEq =
6630                                 CORINFO_CLASS_HANDLE(vnStore->ConstantValue<ssize_t>(funcApp.m_args[0]));
6631                             ValueNum      arrVN  = funcApp.m_args[1];
6632                             ValueNum      inxVN  = funcApp.m_args[2];
6633                             FieldSeqNode* fldSeq = vnStore->FieldSeqVNToFieldSeq(funcApp.m_args[3]);
6634
6635                             // Does the child of the GT_IND 'arg' have an associated zero-offset field sequence?
6636                             FieldSeqNode* addrFieldSeq = nullptr;
6637                             if (GetZeroOffsetFieldMap()->Lookup(arg, &addrFieldSeq))
6638                             {
6639                                 fldSeq = GetFieldSeqStore()->Append(addrFieldSeq, fldSeq);
6640                             }
6641
6642 #ifdef DEBUG
6643                             if (verbose)
6644                             {
6645                                 printf("Tree ");
6646                                 Compiler::printTreeID(tree);
6647                                 printf(" assigns to an array element:\n");
6648                             }
6649 #endif // DEBUG
6650
6651                             ValueNum heapVN = fgValueNumberArrIndexAssign(elemTypeEq, arrVN, inxVN, fldSeq,
6652                                                                           rhsVNPair.GetLiberal(), lhs->TypeGet());
6653                             recordGcHeapStore(tree, heapVN DEBUGARG("ArrIndexAssign (case 1)"));
6654                         }
6655                         // It may be that we haven't parsed it yet.  Try.
6656                         else if (lhs->gtFlags & GTF_IND_ARR_INDEX)
6657                         {
6658                             ArrayInfo arrInfo;
6659                             bool      b = GetArrayInfoMap()->Lookup(lhs, &arrInfo);
6660                             assert(b);
6661                             ValueNum      arrVN  = ValueNumStore::NoVN;
6662                             ValueNum      inxVN  = ValueNumStore::NoVN;
6663                             FieldSeqNode* fldSeq = nullptr;
6664
6665                             // Try to parse it.
6666                             GenTree* arr = nullptr;
6667                             arg->ParseArrayAddress(this, &arrInfo, &arr, &inxVN, &fldSeq);
6668                             if (arr == nullptr)
6669                             {
6670                                 fgMutateGcHeap(tree DEBUGARG("assignment to unparseable array expression"));
6671                                 return;
6672                             }
6673                             // Otherwise, parsing succeeded.
6674
6675                             // Need to form H[arrType][arr][ind][fldSeq] = rhsVNPair.GetLiberal()
6676
6677                             // Get the element type equivalence class representative.
6678                             CORINFO_CLASS_HANDLE elemTypeEq =
6679                                 EncodeElemType(arrInfo.m_elemType, arrInfo.m_elemStructType);
6680                             arrVN = arr->gtVNPair.GetLiberal();
6681
6682                             FieldSeqNode* zeroOffsetFldSeq = nullptr;
6683                             if (GetZeroOffsetFieldMap()->Lookup(arg, &zeroOffsetFldSeq))
6684                             {
6685                                 fldSeq = GetFieldSeqStore()->Append(fldSeq, zeroOffsetFldSeq);
6686                             }
6687
6688                             ValueNum heapVN = fgValueNumberArrIndexAssign(elemTypeEq, arrVN, inxVN, fldSeq,
6689                                                                           rhsVNPair.GetLiberal(), lhs->TypeGet());
6690                             recordGcHeapStore(tree, heapVN DEBUGARG("ArrIndexAssign (case 2)"));
6691                         }
6692                         else if (arg->IsFieldAddr(this, &obj, &staticOffset, &fldSeq))
6693                         {
6694                             if (fldSeq == FieldSeqStore::NotAField())
6695                             {
6696                                 fgMutateGcHeap(tree DEBUGARG("NotAField"));
6697                             }
6698                             else
6699                             {
6700                                 assert(fldSeq != nullptr);
6701 #ifdef DEBUG
6702                                 CORINFO_CLASS_HANDLE fldCls = info.compCompHnd->getFieldClass(fldSeq->m_fieldHnd);
6703                                 if (obj != nullptr)
6704                                 {
6705                                     // Make sure that the class containing it is not a value class (as we are expecting
6706                                     // an instance field)
6707                                     assert((info.compCompHnd->getClassAttribs(fldCls) & CORINFO_FLG_VALUECLASS) == 0);
6708                                     assert(staticOffset == nullptr);
6709                                 }
6710 #endif // DEBUG
6711                                 // Get the first (instance or static) field from field seq.  GcHeap[field] will yield
6712                                 // the "field map".
6713                                 if (fldSeq->IsFirstElemFieldSeq())
6714                                 {
6715                                     fldSeq = fldSeq->m_next;
6716                                     assert(fldSeq != nullptr);
6717                                 }
6718
6719                                 // Get a field sequence for just the first field in the sequence
6720                                 //
6721                                 FieldSeqNode* firstFieldOnly = GetFieldSeqStore()->CreateSingleton(fldSeq->m_fieldHnd);
6722
6723                                 // The final field in the sequence will need to match the 'indType'
6724                                 var_types indType = lhs->TypeGet();
6725                                 ValueNum  fldMapVN =
6726                                     vnStore->VNApplySelectors(VNK_Liberal, fgCurMemoryVN[GcHeap], firstFieldOnly);
6727
6728                                 // The type of the field is "struct" if there are more fields in the sequence,
6729                                 // otherwise it is the type returned from VNApplySelectors above.
6730                                 var_types firstFieldType = vnStore->TypeOfVN(fldMapVN);
6731
6732                                 ValueNum storeVal =
6733                                     rhsVNPair.GetLiberal(); // The value number from the rhs of the assignment
6734                                 ValueNum newFldMapVN = ValueNumStore::NoVN;
6735
6736                                 // when (obj != nullptr) we have an instance field, otherwise a static field
6737                                 // when (staticOffset != nullptr) it represents a offset into a static or the call to
6738                                 // Shared Static Base
6739                                 if ((obj != nullptr) || (staticOffset != nullptr))
6740                                 {
6741                                     ValueNum valAtAddr = fldMapVN;
6742                                     ValueNum normVal   = ValueNumStore::NoVN;
6743
6744                                     if (obj != nullptr)
6745                                     {
6746                                         // construct the ValueNumber for 'fldMap at obj'
6747                                         normVal = vnStore->VNNormVal(obj->GetVN(VNK_Liberal));
6748                                         valAtAddr =
6749                                             vnStore->VNForMapSelect(VNK_Liberal, firstFieldType, fldMapVN, normVal);
6750                                     }
6751                                     else // (staticOffset != nullptr)
6752                                     {
6753                                         // construct the ValueNumber for 'fldMap at staticOffset'
6754                                         normVal = vnStore->VNNormVal(staticOffset->GetVN(VNK_Liberal));
6755                                         valAtAddr =
6756                                             vnStore->VNForMapSelect(VNK_Liberal, firstFieldType, fldMapVN, normVal);
6757                                     }
6758                                     // Now get rid of any remaining struct field dereferences. (if they exist)
6759                                     if (fldSeq->m_next)
6760                                     {
6761                                         storeVal =
6762                                             vnStore->VNApplySelectorsAssign(VNK_Liberal, valAtAddr, fldSeq->m_next,
6763                                                                             storeVal, indType, compCurBB);
6764                                     }
6765
6766                                     // From which we can construct the new ValueNumber for 'fldMap at normVal'
6767                                     newFldMapVN = vnStore->VNForMapStore(vnStore->TypeOfVN(fldMapVN), fldMapVN, normVal,
6768                                                                          storeVal);
6769                                 }
6770                                 else
6771                                 {
6772                                     // plain static field
6773
6774                                     // Now get rid of any remaining struct field dereferences. (if they exist)
6775                                     if (fldSeq->m_next)
6776                                     {
6777                                         storeVal =
6778                                             vnStore->VNApplySelectorsAssign(VNK_Liberal, fldMapVN, fldSeq->m_next,
6779                                                                             storeVal, indType, compCurBB);
6780                                     }
6781
6782                                     newFldMapVN = vnStore->VNApplySelectorsAssign(VNK_Liberal, fgCurMemoryVN[GcHeap],
6783                                                                                   fldSeq, storeVal, indType, compCurBB);
6784                                 }
6785
6786                                 // It is not strictly necessary to set the lhs value number,
6787                                 // but the dumps read better with it set to the 'storeVal' that we just computed
6788                                 lhs->gtVNPair.SetBoth(storeVal);
6789
6790                                 // Update the field map for firstField in GcHeap to this new value.
6791                                 ValueNum heapVN =
6792                                     vnStore->VNApplySelectorsAssign(VNK_Liberal, fgCurMemoryVN[GcHeap], firstFieldOnly,
6793                                                                     newFldMapVN, indType, compCurBB);
6794
6795                                 recordGcHeapStore(tree, heapVN DEBUGARG("StoreField"));
6796                             }
6797                         }
6798                         else
6799                         {
6800                             GenTreeLclVarCommon* lclVarTree = nullptr;
6801                             bool                 isLocal    = tree->DefinesLocal(this, &lclVarTree);
6802
6803                             if (isLocal && lvaVarAddrExposed(lclVarTree->gtLclNum))
6804                             {
6805                                 // Store to address-exposed local; need to record the effect on ByrefExposed.
6806                                 // We could use MapStore here and MapSelect on reads of address-exposed locals
6807                                 // (using the local nums as selectors) to get e.g. propagation of values
6808                                 // through address-taken locals in regions of code with no calls or byref
6809                                 // writes.
6810                                 // For now, just use a new opaque VN.
6811                                 ValueNum memoryVN = vnStore->VNForExpr(compCurBB);
6812                                 recordAddressExposedLocalStore(tree, memoryVN DEBUGARG("PtrToLoc indir"));
6813                             }
6814                             else if (!isLocal)
6815                             {
6816                                 // If it doesn't define a local, then it might update GcHeap/ByrefExposed.
6817                                 // For the new ByrefExposed VN, we could use an operator here like
6818                                 // VNF_ByrefExposedStore that carries the VNs of the pointer and RHS, then
6819                                 // at byref loads if the current ByrefExposed VN happens to be
6820                                 // VNF_ByrefExposedStore with the same pointer VN, we could propagate the
6821                                 // VN from the RHS to the VN for the load.  This would e.g. allow tracking
6822                                 // values through assignments to out params.  For now, just model this
6823                                 // as an opaque GcHeap/ByrefExposed mutation.
6824                                 fgMutateGcHeap(tree DEBUGARG("assign-of-IND"));
6825                             }
6826                         }
6827                     }
6828
6829                     // We don't actually evaluate an IND on the LHS, so give it the Void value.
6830                     tree->gtVNPair.SetBoth(vnStore->VNForVoid());
6831                 }
6832                 break;
6833
6834                 case GT_CLS_VAR:
6835                 {
6836                     bool isVolatile = (lhs->gtFlags & GTF_FLD_VOLATILE) != 0;
6837
6838                     if (isVolatile)
6839                     {
6840                         // For Volatile store indirection, first mutate GcHeap/ByrefExposed
6841                         fgMutateGcHeap(lhs DEBUGARG("GTF_CLS_VAR - store")); // always change fgCurMemoryVN
6842                     }
6843
6844                     // We model statics as indices into GcHeap (which is a subset of ByrefExposed).
6845                     FieldSeqNode* fldSeqForStaticVar = GetFieldSeqStore()->CreateSingleton(lhs->gtClsVar.gtClsVarHnd);
6846                     assert(fldSeqForStaticVar != FieldSeqStore::NotAField());
6847
6848                     ValueNum storeVal = rhsVNPair.GetLiberal(); // The value number from the rhs of the assignment
6849                     storeVal = vnStore->VNApplySelectorsAssign(VNK_Liberal, fgCurMemoryVN[GcHeap], fldSeqForStaticVar,
6850                                                                storeVal, lhs->TypeGet(), compCurBB);
6851
6852                     // It is not strictly necessary to set the lhs value number,
6853                     // but the dumps read better with it set to the 'storeVal' that we just computed
6854                     lhs->gtVNPair.SetBoth(storeVal);
6855
6856                     // bbMemoryDef must include GcHeap for any block that mutates the GC heap
6857                     assert((compCurBB->bbMemoryDef & memoryKindSet(GcHeap)) != 0);
6858
6859                     // Update the field map for the fgCurMemoryVN and SSA for the tree
6860                     recordGcHeapStore(tree, storeVal DEBUGARG("Static Field store"));
6861                 }
6862                 break;
6863
6864                 default:
6865                     assert(!"Unknown node for lhs of assignment!");
6866
6867                     // For Unknown stores, mutate GcHeap/ByrefExposed
6868                     fgMutateGcHeap(lhs DEBUGARG("Unkwown Assignment - store")); // always change fgCurMemoryVN
6869                     break;
6870             }
6871         }
6872         // Other kinds of assignment: initblk and copyblk.
6873         else if (oper == GT_ASG && varTypeIsStruct(tree))
6874         {
6875             fgValueNumberBlockAssignment(tree);
6876         }
6877         else if (oper == GT_ADDR)
6878         {
6879             // We have special representations for byrefs to lvalues.
6880             GenTree* arg = tree->gtOp.gtOp1;
6881             if (arg->OperIsLocal())
6882             {
6883                 FieldSeqNode* fieldSeq = nullptr;
6884                 ValueNum      newVN    = ValueNumStore::NoVN;
6885                 if (!lvaInSsa(arg->gtLclVarCommon.GetLclNum()))
6886                 {
6887                     newVN = vnStore->VNForExpr(compCurBB, TYP_BYREF);
6888                 }
6889                 else if (arg->OperGet() == GT_LCL_FLD)
6890                 {
6891                     fieldSeq = arg->AsLclFld()->gtFieldSeq;
6892                     if (fieldSeq == nullptr)
6893                     {
6894                         // Local field with unknown field seq -- not a precise pointer.
6895                         newVN = vnStore->VNForExpr(compCurBB, TYP_BYREF);
6896                     }
6897                 }
6898                 if (newVN == ValueNumStore::NoVN)
6899                 {
6900                     assert(arg->gtLclVarCommon.GetSsaNum() != ValueNumStore::NoVN);
6901                     newVN = vnStore->VNForFunc(TYP_BYREF, VNF_PtrToLoc,
6902                                                vnStore->VNForIntCon(arg->gtLclVarCommon.GetLclNum()),
6903                                                vnStore->VNForFieldSeq(fieldSeq));
6904                 }
6905                 tree->gtVNPair.SetBoth(newVN);
6906             }
6907             else if ((arg->gtOper == GT_IND) || arg->OperIsBlk())
6908             {
6909                 // Usually the ADDR and IND just cancel out...
6910                 // except when this GT_ADDR has a valid zero-offset field sequence
6911                 //
6912                 FieldSeqNode* zeroOffsetFieldSeq = nullptr;
6913                 if (GetZeroOffsetFieldMap()->Lookup(tree, &zeroOffsetFieldSeq) &&
6914                     (zeroOffsetFieldSeq != FieldSeqStore::NotAField()))
6915                 {
6916                     ValueNum addrExtended = vnStore->ExtendPtrVN(arg->gtOp.gtOp1, zeroOffsetFieldSeq);
6917                     if (addrExtended != ValueNumStore::NoVN)
6918                     {
6919                         tree->gtVNPair.SetBoth(addrExtended); // We don't care about lib/cons differences for addresses.
6920                     }
6921                     else
6922                     {
6923                         // ExtendPtrVN returned a failure result
6924                         // So give this address a new unique value
6925                         tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, TYP_BYREF));
6926                     }
6927                 }
6928                 else
6929                 {
6930                     // They just cancel, so fetch the ValueNumber from the op1 of the GT_IND node.
6931                     //
6932                     GenTree* addr  = arg->AsIndir()->Addr();
6933                     tree->gtVNPair = addr->gtVNPair;
6934
6935                     // For the CSE phase mark the address as GTF_DONT_CSE
6936                     // because it will end up with the same value number as tree (the GT_ADDR).
6937                     addr->gtFlags |= GTF_DONT_CSE;
6938                 }
6939             }
6940             else
6941             {
6942                 // May be more cases to do here!  But we'll punt for now.
6943                 tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, TYP_BYREF));
6944             }
6945         }
6946         else if ((oper == GT_IND) || GenTree::OperIsBlk(oper))
6947         {
6948             // So far, we handle cases in which the address is a ptr-to-local, or if it's
6949             // a pointer to an object field or array element.  Other cases become uses of
6950             // the current ByrefExposed value and the pointer value, so that at least we
6951             // can recognize redundant loads with no stores between them.
6952             GenTree*             addr         = tree->AsIndir()->Addr();
6953             GenTreeLclVarCommon* lclVarTree   = nullptr;
6954             FieldSeqNode*        fldSeq1      = nullptr;
6955             FieldSeqNode*        fldSeq2      = nullptr;
6956             GenTree*             obj          = nullptr;
6957             GenTree*             staticOffset = nullptr;
6958             bool                 isVolatile   = (tree->gtFlags & GTF_IND_VOLATILE) != 0;
6959
6960             // See if the addr has any exceptional part.
6961             ValueNumPair addrNvnp;
6962             ValueNumPair addrXvnp = ValueNumPair(ValueNumStore::VNForEmptyExcSet(), ValueNumStore::VNForEmptyExcSet());
6963             vnStore->VNPUnpackExc(addr->gtVNPair, &addrNvnp, &addrXvnp);
6964
6965             // Is the dereference immutable?  If so, model it as referencing the read-only heap.
6966             if (tree->gtFlags & GTF_IND_INVARIANT)
6967             {
6968                 assert(!isVolatile); // We don't expect both volatile and invariant
6969                 tree->gtVNPair =
6970                     ValueNumPair(vnStore->VNForMapSelect(VNK_Liberal, TYP_REF, ValueNumStore::VNForROH(),
6971                                                          addrNvnp.GetLiberal()),
6972                                  vnStore->VNForMapSelect(VNK_Conservative, TYP_REF, ValueNumStore::VNForROH(),
6973                                                          addrNvnp.GetConservative()));
6974                 tree->gtVNPair = vnStore->VNPWithExc(tree->gtVNPair, addrXvnp);
6975             }
6976             else if (isVolatile)
6977             {
6978                 // For Volatile indirection, mutate GcHeap/ByrefExposed
6979                 fgMutateGcHeap(tree DEBUGARG("GTF_IND_VOLATILE - read"));
6980
6981                 // The value read by the GT_IND can immediately change
6982                 ValueNum newUniq = vnStore->VNForExpr(compCurBB, tree->TypeGet());
6983                 tree->gtVNPair   = vnStore->VNPWithExc(ValueNumPair(newUniq, newUniq), addrXvnp);
6984             }
6985             // We always want to evaluate the LHS when the GT_IND node is marked with GTF_IND_ARR_INDEX
6986             // as this will relabel the GT_IND child correctly using the VNF_PtrToArrElem
6987             else if ((tree->gtFlags & GTF_IND_ARR_INDEX) != 0)
6988             {
6989                 ArrayInfo arrInfo;
6990                 bool      b = GetArrayInfoMap()->Lookup(tree, &arrInfo);
6991                 assert(b);
6992
6993                 ValueNum      inxVN  = ValueNumStore::NoVN;
6994                 FieldSeqNode* fldSeq = nullptr;
6995
6996                 // GenTree* addr = tree->gtOp.gtOp1;
6997                 ValueNum addrVN = addrNvnp.GetLiberal();
6998
6999                 // Try to parse it.
7000                 GenTree* arr = nullptr;
7001                 addr->ParseArrayAddress(this, &arrInfo, &arr, &inxVN, &fldSeq);
7002                 if (arr == nullptr)
7003                 {
7004                     tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
7005                     return;
7006                 }
7007                 assert(fldSeq != FieldSeqStore::NotAField());
7008
7009                 // Otherwise...
7010                 // Need to form H[arrType][arr][ind][fldSeq]
7011                 // Get the array element type equivalence class rep.
7012                 CORINFO_CLASS_HANDLE elemTypeEq   = EncodeElemType(arrInfo.m_elemType, arrInfo.m_elemStructType);
7013                 ValueNum             elemTypeEqVN = vnStore->VNForHandle(ssize_t(elemTypeEq), GTF_ICON_CLASS_HDL);
7014
7015                 // We take the "VNNormVal"s here, because if either has exceptional outcomes, they will be captured
7016                 // as part of the value of the composite "addr" operation...
7017                 ValueNum arrVN = vnStore->VNNormVal(arr->gtVNPair.GetLiberal());
7018                 inxVN          = vnStore->VNNormVal(inxVN);
7019
7020                 // Additionally, relabel the address with a PtrToArrElem value number.
7021                 ValueNum fldSeqVN = vnStore->VNForFieldSeq(fldSeq);
7022                 ValueNum elemAddr =
7023                     vnStore->VNForFunc(TYP_BYREF, VNF_PtrToArrElem, elemTypeEqVN, arrVN, inxVN, fldSeqVN);
7024
7025                 // The aggregate "addr" VN should have had all the exceptions bubble up...
7026                 elemAddr = vnStore->VNWithExc(elemAddr, addrXvnp.GetLiberal());
7027                 addr->gtVNPair.SetBoth(elemAddr);
7028 #ifdef DEBUG
7029                 if (verbose)
7030                 {
7031                     printf("  Relabeled IND_ARR_INDEX address node ");
7032                     Compiler::printTreeID(addr);
7033                     printf(" with l:" FMT_VN ": ", elemAddr);
7034                     vnStore->vnDump(this, elemAddr);
7035                     printf("\n");
7036                     if (vnStore->VNNormVal(elemAddr) != elemAddr)
7037                     {
7038                         printf("      [" FMT_VN " is: ", vnStore->VNNormVal(elemAddr));
7039                         vnStore->vnDump(this, vnStore->VNNormVal(elemAddr));
7040                         printf("]\n");
7041                     }
7042                 }
7043 #endif // DEBUG
7044                 // We now need to retrieve the value number for the array element value
7045                 // and give this value number to the GT_IND node 'tree'
7046                 // We do this whenever we have an rvalue, but we don't do it for a
7047                 // normal LHS assignment into an array element.
7048                 //
7049                 if ((tree->gtFlags & GTF_IND_ASG_LHS) == 0)
7050                 {
7051                     fgValueNumberArrIndexVal(tree, elemTypeEq, arrVN, inxVN, addrXvnp.GetLiberal(), fldSeq);
7052                 }
7053             }
7054             // In general we skip GT_IND nodes on that are the LHS of an assignment.  (We labeled these earlier.)
7055             // We will "evaluate" this as part of the assignment.
7056             else if ((tree->gtFlags & GTF_IND_ASG_LHS) == 0)
7057             {
7058                 FieldSeqNode* localFldSeq = nullptr;
7059                 VNFuncApp     funcApp;
7060
7061                 // Is it a local or a heap address?
7062                 if (addr->IsLocalAddrExpr(this, &lclVarTree, &localFldSeq) && lvaInSsa(lclVarTree->GetLclNum()))
7063                 {
7064                     unsigned   lclNum = lclVarTree->GetLclNum();
7065                     unsigned   ssaNum = lclVarTree->GetSsaNum();
7066                     LclVarDsc* varDsc = &lvaTable[lclNum];
7067
7068                     if ((localFldSeq == FieldSeqStore::NotAField()) || (localFldSeq == nullptr))
7069                     {
7070                         tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
7071                     }
7072                     else
7073                     {
7074                         var_types    indType   = tree->TypeGet();
7075                         ValueNumPair lclVNPair = varDsc->GetPerSsaData(ssaNum)->m_vnPair;
7076                         tree->gtVNPair         = vnStore->VNPairApplySelectors(lclVNPair, localFldSeq, indType);
7077                         ;
7078                     }
7079                     tree->gtVNPair = vnStore->VNPWithExc(tree->gtVNPair, addrXvnp);
7080                 }
7081                 else if (vnStore->GetVNFunc(addrNvnp.GetLiberal(), &funcApp) && funcApp.m_func == VNF_PtrToStatic)
7082                 {
7083                     var_types indType    = tree->TypeGet();
7084                     ValueNum  fieldSeqVN = funcApp.m_args[0];
7085
7086                     FieldSeqNode* fldSeqForStaticVar = vnStore->FieldSeqVNToFieldSeq(fieldSeqVN);
7087
7088                     if (fldSeqForStaticVar != FieldSeqStore::NotAField())
7089                     {
7090                         ValueNum selectedStaticVar;
7091                         // We model statics as indices into the GcHeap (which is a subset of ByrefExposed).
7092                         size_t structSize = 0;
7093                         selectedStaticVar = vnStore->VNApplySelectors(VNK_Liberal, fgCurMemoryVN[GcHeap],
7094                                                                       fldSeqForStaticVar, &structSize);
7095                         selectedStaticVar = vnStore->VNApplySelectorsTypeCheck(selectedStaticVar, indType, structSize);
7096
7097                         tree->gtVNPair.SetLiberal(selectedStaticVar);
7098                         tree->gtVNPair.SetConservative(vnStore->VNForExpr(compCurBB, indType));
7099                     }
7100                     else
7101                     {
7102                         JITDUMP("    *** Missing field sequence info for VNF_PtrToStatic value GT_IND\n");
7103                         tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, indType)); //  a new unique value number
7104                     }
7105                     tree->gtVNPair = vnStore->VNPWithExc(tree->gtVNPair, addrXvnp);
7106                 }
7107                 else if (vnStore->GetVNFunc(addrNvnp.GetLiberal(), &funcApp) && (funcApp.m_func == VNF_PtrToArrElem))
7108                 {
7109                     fgValueNumberArrIndexVal(tree, &funcApp, addrXvnp.GetLiberal());
7110                 }
7111                 else if (addr->IsFieldAddr(this, &obj, &staticOffset, &fldSeq2))
7112                 {
7113                     if (fldSeq2 == FieldSeqStore::NotAField())
7114                     {
7115                         tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
7116                     }
7117                     else if (fldSeq2 != nullptr)
7118                     {
7119                         // Get the first (instance or static) field from field seq.  GcHeap[field] will yield the "field
7120                         // map".
7121                         CLANG_FORMAT_COMMENT_ANCHOR;
7122
7123 #ifdef DEBUG
7124                         CORINFO_CLASS_HANDLE fldCls = info.compCompHnd->getFieldClass(fldSeq2->m_fieldHnd);
7125                         if (obj != nullptr)
7126                         {
7127                             // Make sure that the class containing it is not a value class (as we are expecting an
7128                             // instance field)
7129                             assert((info.compCompHnd->getClassAttribs(fldCls) & CORINFO_FLG_VALUECLASS) == 0);
7130                             assert(staticOffset == nullptr);
7131                         }
7132 #endif // DEBUG
7133                         // Get a field sequence for just the first field in the sequence
7134                         //
7135                         FieldSeqNode* firstFieldOnly = GetFieldSeqStore()->CreateSingleton(fldSeq2->m_fieldHnd);
7136                         size_t        structSize     = 0;
7137                         ValueNum      fldMapVN =
7138                             vnStore->VNApplySelectors(VNK_Liberal, fgCurMemoryVN[GcHeap], firstFieldOnly, &structSize);
7139
7140                         // The final field in the sequence will need to match the 'indType'
7141                         var_types indType = tree->TypeGet();
7142
7143                         // The type of the field is "struct" if there are more fields in the sequence,
7144                         // otherwise it is the type returned from VNApplySelectors above.
7145                         var_types firstFieldType = vnStore->TypeOfVN(fldMapVN);
7146
7147                         ValueNum valAtAddr = fldMapVN;
7148                         if (obj != nullptr)
7149                         {
7150                             // construct the ValueNumber for 'fldMap at obj'
7151                             ValueNum objNormVal = vnStore->VNNormVal(obj->GetVN(VNK_Liberal));
7152                             valAtAddr = vnStore->VNForMapSelect(VNK_Liberal, firstFieldType, fldMapVN, objNormVal);
7153                         }
7154                         else if (staticOffset != nullptr)
7155                         {
7156                             // construct the ValueNumber for 'fldMap at staticOffset'
7157                             ValueNum offsetNormVal = vnStore->VNNormVal(staticOffset->GetVN(VNK_Liberal));
7158                             valAtAddr = vnStore->VNForMapSelect(VNK_Liberal, firstFieldType, fldMapVN, offsetNormVal);
7159                         }
7160
7161                         // Now get rid of any remaining struct field dereferences.
7162                         if (fldSeq2->m_next)
7163                         {
7164                             valAtAddr = vnStore->VNApplySelectors(VNK_Liberal, valAtAddr, fldSeq2->m_next, &structSize);
7165                         }
7166                         valAtAddr = vnStore->VNApplySelectorsTypeCheck(valAtAddr, indType, structSize);
7167
7168                         tree->gtVNPair.SetLiberal(valAtAddr);
7169
7170                         // The conservative value is a new, unique VN.
7171                         tree->gtVNPair.SetConservative(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
7172                         tree->gtVNPair = vnStore->VNPWithExc(tree->gtVNPair, addrXvnp);
7173                     }
7174                     else
7175                     {
7176                         // Occasionally we do an explicit null test on a REF, so we just dereference it with no
7177                         // field sequence.  The result is probably unused.
7178                         tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
7179                         tree->gtVNPair = vnStore->VNPWithExc(tree->gtVNPair, addrXvnp);
7180                     }
7181                 }
7182                 else // We don't know where the address points, so it is an ByrefExposed load.
7183                 {
7184                     ValueNum addrVN = addr->gtVNPair.GetLiberal();
7185                     ValueNum loadVN = fgValueNumberByrefExposedLoad(typ, addrVN);
7186                     tree->gtVNPair.SetLiberal(loadVN);
7187                     tree->gtVNPair.SetConservative(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
7188                     tree->gtVNPair = vnStore->VNPWithExc(tree->gtVNPair, addrXvnp);
7189                 }
7190             }
7191         }
7192         else if (tree->OperGet() == GT_CAST)
7193         {
7194             fgValueNumberCastTree(tree);
7195         }
7196         else if (tree->OperGet() == GT_INTRINSIC)
7197         {
7198             fgValueNumberIntrinsic(tree);
7199         }
7200         else if (ValueNumStore::VNFuncIsLegal(GetVNFuncForOper(oper, (tree->gtFlags & GTF_UNSIGNED) != 0)))
7201         {
7202             if (GenTree::OperIsUnary(oper))
7203             {
7204                 if (tree->gtOp.gtOp1 != nullptr)
7205                 {
7206                     if (tree->OperGet() == GT_NOP)
7207                     {
7208                         // Pass through arg vn.
7209                         tree->gtVNPair = tree->gtOp.gtOp1->gtVNPair;
7210                     }
7211                     else
7212                     {
7213                         ValueNumPair op1VNP;
7214                         ValueNumPair op1VNPx = ValueNumStore::VNPForEmptyExcSet();
7215                         vnStore->VNPUnpackExc(tree->gtOp.gtOp1->gtVNPair, &op1VNP, &op1VNPx);
7216
7217                         // If we are fetching the array length for an array ref that came from global memory
7218                         // then for CSE safety we must use the conservative value number for both
7219                         //
7220                         if ((tree->OperGet() == GT_ARR_LENGTH) && ((tree->gtOp.gtOp1->gtFlags & GTF_GLOB_REF) != 0))
7221                         {
7222                             // use the conservative value number for both when computing the VN for the ARR_LENGTH
7223                             op1VNP.SetBoth(op1VNP.GetConservative());
7224                         }
7225
7226                         tree->gtVNPair =
7227                             vnStore->VNPWithExc(vnStore->VNPairForFunc(tree->TypeGet(),
7228                                                                        GetVNFuncForOper(oper, (tree->gtFlags &
7229                                                                                                GTF_UNSIGNED) != 0),
7230                                                                        op1VNP),
7231                                                 op1VNPx);
7232                     }
7233                 }
7234                 else // Is actually nullary.
7235                 {
7236                     // Mostly we'll leave these without a value number, assuming we'll detect these as VN failures
7237                     // if they actually need to have values.  With the exception of NOPs, which can sometimes have
7238                     // meaning.
7239                     if (tree->OperGet() == GT_NOP)
7240                     {
7241                         tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
7242                     }
7243                 }
7244             }
7245             else
7246             {
7247                 assert(oper != GT_ASG); // We handled assignments earlier.
7248                 assert(GenTree::OperIsBinary(oper));
7249                 // Standard binary operator.
7250                 ValueNumPair op2VNPair;
7251                 if (tree->gtOp.gtOp2 == nullptr)
7252                 {
7253                     op2VNPair.SetBoth(ValueNumStore::VNForNull());
7254                 }
7255                 else
7256                 {
7257                     op2VNPair = tree->gtOp.gtOp2->gtVNPair;
7258                 }
7259                 // A few special case: if we add a field offset constant to a PtrToXXX, we get back a new PtrToXXX.
7260                 ValueNum newVN = ValueNumStore::NoVN;
7261
7262                 ValueNumPair op1vnp;
7263                 ValueNumPair op1Xvnp = ValueNumStore::VNPForEmptyExcSet();
7264                 vnStore->VNPUnpackExc(tree->gtOp.gtOp1->gtVNPair, &op1vnp, &op1Xvnp);
7265                 ValueNumPair op2vnp;
7266                 ValueNumPair op2Xvnp = ValueNumStore::VNPForEmptyExcSet();
7267                 vnStore->VNPUnpackExc(op2VNPair, &op2vnp, &op2Xvnp);
7268                 ValueNumPair excSet = vnStore->VNPExcSetUnion(op1Xvnp, op2Xvnp);
7269
7270                 if (oper == GT_ADD)
7271                 {
7272                     newVN = vnStore->ExtendPtrVN(tree->gtOp.gtOp1, tree->gtOp.gtOp2);
7273                     if (newVN == ValueNumStore::NoVN)
7274                     {
7275                         newVN = vnStore->ExtendPtrVN(tree->gtOp.gtOp2, tree->gtOp.gtOp1);
7276                     }
7277                 }
7278                 if (newVN != ValueNumStore::NoVN)
7279                 {
7280                     newVN = vnStore->VNWithExc(newVN, excSet.GetLiberal());
7281                     // We don't care about differences between liberal and conservative for pointer values.
7282                     tree->gtVNPair.SetBoth(newVN);
7283                 }
7284                 else
7285                 {
7286
7287                     ValueNumPair normalRes =
7288                         vnStore->VNPairForFunc(tree->TypeGet(),
7289                                                GetVNFuncForOper(oper, (tree->gtFlags & GTF_UNSIGNED) != 0), op1vnp,
7290                                                op2vnp);
7291                     // Overflow-checking operations add an overflow exception
7292                     if (tree->gtOverflowEx())
7293                     {
7294                         ValueNum overflowExcSet =
7295                             vnStore->VNExcSetSingleton(vnStore->VNForFunc(TYP_REF, VNF_OverflowExc));
7296                         excSet = vnStore->VNPExcSetUnion(excSet, ValueNumPair(overflowExcSet, overflowExcSet));
7297                     }
7298                     tree->gtVNPair = vnStore->VNPWithExc(normalRes, excSet);
7299                 }
7300             }
7301         }
7302         else // ValueNumStore::VNFuncIsLegal returns false
7303         {
7304             // Some of the genTreeOps that aren't legal VNFuncs so they get special handling.
7305             switch (oper)
7306             {
7307                 case GT_COMMA:
7308                 {
7309                     ValueNumPair op1vnp;
7310                     ValueNumPair op1Xvnp = ValueNumStore::VNPForEmptyExcSet();
7311                     vnStore->VNPUnpackExc(tree->gtOp.gtOp1->gtVNPair, &op1vnp, &op1Xvnp);
7312                     ValueNumPair op2vnp;
7313                     ValueNumPair op2Xvnp = ValueNumStore::VNPForEmptyExcSet();
7314
7315                     GenTree* op2 = tree->gtGetOp2();
7316                     if (op2->OperIsIndir() && ((op2->gtFlags & GTF_IND_ASG_LHS) != 0))
7317                     {
7318                         // If op2 represents the lhs of an assignment then we give a VNForVoid for the lhs
7319                         op2vnp = ValueNumPair(ValueNumStore::VNForVoid(), ValueNumStore::VNForVoid());
7320                     }
7321                     else if ((op2->OperGet() == GT_CLS_VAR) && (op2->gtFlags & GTF_CLS_VAR_ASG_LHS))
7322                     {
7323                         // If op2 represents the lhs of an assignment then we give a VNForVoid for the lhs
7324                         op2vnp = ValueNumPair(ValueNumStore::VNForVoid(), ValueNumStore::VNForVoid());
7325                     }
7326                     else
7327                     {
7328                         vnStore->VNPUnpackExc(op2->gtVNPair, &op2vnp, &op2Xvnp);
7329                     }
7330
7331                     tree->gtVNPair = vnStore->VNPWithExc(op2vnp, vnStore->VNPExcSetUnion(op1Xvnp, op2Xvnp));
7332                 }
7333                 break;
7334
7335                 case GT_NULLCHECK:
7336                 {
7337                     // Explicit null check.
7338                     // Handle case where operand tree also may cause exceptions.
7339                     ValueNumPair excSet = vnStore->VNPExcSetSingleton(
7340                         vnStore->VNPairForFunc(TYP_REF, VNF_NullPtrExc,
7341                                                vnStore->VNPNormVal(tree->gtOp.gtOp1->gtVNPair)));
7342                     ValueNumPair excSetBoth =
7343                         vnStore->VNPExcSetUnion(excSet, vnStore->VNPExcVal(tree->gtOp.gtOp1->gtVNPair));
7344
7345                     tree->gtVNPair = vnStore->VNPWithExc(vnStore->VNPForVoid(), excSetBoth);
7346                 }
7347                 break;
7348
7349                 case GT_LOCKADD: // Binop
7350                 case GT_XADD:    // Binop
7351                 case GT_XCHG:    // Binop
7352                     assert(!tree->OperIs(GT_LOCKADD) && "LOCKADD should not appear before lowering");
7353                     // For CMPXCHG and other intrinsics add an arbitrary side effect on GcHeap/ByrefExposed.
7354                     fgMutateGcHeap(tree DEBUGARG("Interlocked intrinsic"));
7355                     tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
7356                     break;
7357
7358                 case GT_JTRUE:
7359                 case GT_LIST:
7360                     // These nodes never need to have a ValueNumber
7361                     tree->gtVNPair.SetBoth(ValueNumStore::NoVN);
7362                     break;
7363
7364                 case GT_BOX:
7365                     // BOX doesn't do anything at this point, the actual object allocation
7366                     // and initialization happens separately (and not numbering BOX correctly
7367                     // prevents seeing allocation related assertions through it)
7368                     tree->gtVNPair = tree->gtGetOp1()->gtVNPair;
7369                     break;
7370
7371                 default:
7372                     // The default action is to give the node a new, unique VN.
7373                     tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
7374                     break;
7375             }
7376         }
7377     }
7378     else
7379     {
7380         assert(GenTree::OperIsSpecial(oper));
7381
7382         // TBD: We must handle these individually.  For now:
7383         switch (oper)
7384         {
7385             case GT_CALL:
7386                 fgValueNumberCall(tree->AsCall());
7387                 break;
7388
7389             case GT_ARR_BOUNDS_CHECK:
7390 #ifdef FEATURE_SIMD
7391             case GT_SIMD_CHK:
7392 #endif // FEATURE_SIMD
7393 #ifdef FEATURE_HW_INTRINSICS
7394             case GT_HW_INTRINSIC_CHK:
7395 #endif // FEATURE_HW_INTRINSICS
7396             {
7397                 // A bounds check node has no value, but may throw exceptions.
7398                 ValueNumPair excSet = vnStore->VNPExcSetSingleton(
7399                     vnStore->VNPairForFunc(TYP_REF, VNF_IndexOutOfRangeExc,
7400                                            vnStore->VNPNormVal(tree->AsBoundsChk()->gtIndex->gtVNPair),
7401                                            vnStore->VNPNormVal(tree->AsBoundsChk()->gtArrLen->gtVNPair)));
7402                 excSet = vnStore->VNPExcSetUnion(excSet, vnStore->VNPExcVal(tree->AsBoundsChk()->gtIndex->gtVNPair));
7403                 excSet = vnStore->VNPExcSetUnion(excSet, vnStore->VNPExcVal(tree->AsBoundsChk()->gtArrLen->gtVNPair));
7404
7405                 tree->gtVNPair = vnStore->VNPWithExc(vnStore->VNPForVoid(), excSet);
7406
7407                 // Record non-constant value numbers that are used as the length argument to bounds checks, so that
7408                 // assertion prop will know that comparisons against them are worth analyzing.
7409                 ValueNum lengthVN = tree->AsBoundsChk()->gtArrLen->gtVNPair.GetConservative();
7410                 if ((lengthVN != ValueNumStore::NoVN) && !vnStore->IsVNConstant(lengthVN))
7411                 {
7412                     vnStore->SetVNIsCheckedBound(lengthVN);
7413                 }
7414             }
7415             break;
7416
7417             case GT_CMPXCHG: // Specialop
7418                 // For CMPXCHG and other intrinsics add an arbitrary side effect on GcHeap/ByrefExposed.
7419                 fgMutateGcHeap(tree DEBUGARG("Interlocked intrinsic"));
7420                 tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
7421                 break;
7422
7423             default:
7424                 tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
7425         }
7426     }
7427 #ifdef DEBUG
7428     if (verbose)
7429     {
7430         if (tree->gtVNPair.GetLiberal() != ValueNumStore::NoVN)
7431         {
7432             printf("N%03u ", tree->gtSeqNum);
7433             printTreeID(tree);
7434             printf(" ");
7435             gtDispNodeName(tree);
7436             if (tree->OperIsLeaf() || tree->OperIsLocalStore()) // local stores used to be leaves
7437             {
7438                 gtDispLeaf(tree, nullptr);
7439             }
7440             printf(" => ");
7441             vnpPrint(tree->gtVNPair, 1);
7442             printf("\n");
7443         }
7444     }
7445 #endif // DEBUG
7446 }
7447
7448 void Compiler::fgValueNumberIntrinsic(GenTree* tree)
7449 {
7450     assert(tree->OperGet() == GT_INTRINSIC);
7451     GenTreeIntrinsic* intrinsic = tree->AsIntrinsic();
7452     ValueNumPair      arg0VNP, arg1VNP;
7453     ValueNumPair      arg0VNPx = ValueNumStore::VNPForEmptyExcSet();
7454     ValueNumPair      arg1VNPx = ValueNumStore::VNPForEmptyExcSet();
7455
7456     vnStore->VNPUnpackExc(intrinsic->gtOp.gtOp1->gtVNPair, &arg0VNP, &arg0VNPx);
7457
7458     if (intrinsic->gtOp.gtOp2 != nullptr)
7459     {
7460         vnStore->VNPUnpackExc(intrinsic->gtOp.gtOp2->gtVNPair, &arg1VNP, &arg1VNPx);
7461     }
7462
7463     if (IsMathIntrinsic(intrinsic->gtIntrinsicId))
7464     {
7465         // GT_INTRINSIC is a currently a subtype of binary operators. But most of
7466         // the math intrinsics are actually unary operations.
7467
7468         if (intrinsic->gtOp.gtOp2 == nullptr)
7469         {
7470             intrinsic->gtVNPair =
7471                 vnStore->VNPWithExc(vnStore->EvalMathFuncUnary(tree->TypeGet(), intrinsic->gtIntrinsicId, arg0VNP),
7472                                     arg0VNPx);
7473         }
7474         else
7475         {
7476             ValueNumPair newVNP =
7477                 vnStore->EvalMathFuncBinary(tree->TypeGet(), intrinsic->gtIntrinsicId, arg0VNP, arg1VNP);
7478             ValueNumPair excSet = vnStore->VNPExcSetUnion(arg0VNPx, arg1VNPx);
7479             intrinsic->gtVNPair = vnStore->VNPWithExc(newVNP, excSet);
7480         }
7481     }
7482     else
7483     {
7484         switch (intrinsic->gtIntrinsicId)
7485         {
7486             case CORINFO_INTRINSIC_Object_GetType:
7487                 intrinsic->gtVNPair =
7488                     vnStore->VNPWithExc(vnStore->VNPairForFunc(intrinsic->TypeGet(), VNF_ObjGetType, arg0VNP),
7489                                         arg0VNPx);
7490                 break;
7491
7492             default:
7493                 unreached();
7494         }
7495     }
7496 }
7497
7498 void Compiler::fgValueNumberCastTree(GenTree* tree)
7499 {
7500     assert(tree->OperGet() == GT_CAST);
7501
7502     ValueNumPair srcVNPair        = tree->gtOp.gtOp1->gtVNPair;
7503     var_types    castToType       = tree->CastToType();
7504     var_types    castFromType     = tree->CastFromType();
7505     bool         srcIsUnsigned    = ((tree->gtFlags & GTF_UNSIGNED) != 0);
7506     bool         hasOverflowCheck = tree->gtOverflowEx();
7507
7508     assert(genActualType(castToType) == genActualType(tree->TypeGet())); // Insure that the resultType is correct
7509
7510     tree->gtVNPair = vnStore->VNPairForCast(srcVNPair, castToType, castFromType, srcIsUnsigned, hasOverflowCheck);
7511 }
7512
7513 // Compute the normal ValueNumber for a cast operation with no exceptions
7514 ValueNum ValueNumStore::VNForCast(ValueNum  srcVN,
7515                                   var_types castToType,
7516                                   var_types castFromType,
7517                                   bool      srcIsUnsigned /* = false */)
7518 {
7519     // The resulting type after performingthe cast is always widened to a supported IL stack size
7520     var_types resultType = genActualType(castToType);
7521
7522     // When we're considering actual value returned by a non-checking cast whether or not the source is
7523     // unsigned does *not* matter for non-widening casts.  That is, if we cast an int or a uint to short,
7524     // we just extract the first two bytes from the source bit pattern, not worrying about the interpretation.
7525     // The same is true in casting between signed/unsigned types of the same width.  Only when we're doing
7526     // a widening cast do we care about whether the source was unsigned,so we know whether to sign or zero extend it.
7527     //
7528     bool srcIsUnsignedNorm = srcIsUnsigned;
7529     if (genTypeSize(castToType) <= genTypeSize(castFromType))
7530     {
7531         srcIsUnsignedNorm = false;
7532     }
7533
7534     ValueNum castTypeVN = VNForCastOper(castToType, srcIsUnsigned);
7535     ValueNum resultVN   = VNForFunc(resultType, VNF_Cast, srcVN, castTypeVN);
7536
7537 #ifdef DEBUG
7538     if (m_pComp->verbose)
7539     {
7540         printf("    VNForCast(" FMT_VN ", " FMT_VN ") returns ", srcVN, castTypeVN);
7541         m_pComp->vnPrint(resultVN, 1);
7542         printf("\n");
7543     }
7544 #endif
7545
7546     return resultVN;
7547 }
7548
7549 // Compute the ValueNumberPair for a cast operation
7550 ValueNumPair ValueNumStore::VNPairForCast(ValueNumPair srcVNPair,
7551                                           var_types    castToType,
7552                                           var_types    castFromType,
7553                                           bool         srcIsUnsigned,    /* = false */
7554                                           bool         hasOverflowCheck) /* = false */
7555 {
7556     // The resulting type after performingthe cast is always widened to a supported IL stack size
7557     var_types resultType = genActualType(castToType);
7558
7559     ValueNumPair castArgVNP;
7560     ValueNumPair castArgxVNP = ValueNumStore::VNPForEmptyExcSet();
7561     VNPUnpackExc(srcVNPair, &castArgVNP, &castArgxVNP);
7562
7563     // When we're considering actual value returned by a non-checking cast (or a checking cast that succeeds),
7564     // whether or not the source is unsigned does *not* matter for non-widening casts.
7565     // That is, if we cast an int or a uint to short, we just extract the first two bytes from the source
7566     // bit pattern, not worrying about the interpretation.  The same is true in casting between signed/unsigned
7567     // types of the same width.  Only when we're doing a widening cast do we care about whether the source
7568     // was unsigned, so we know whether to sign or zero extend it.
7569     //
7570     // Important: Casts to floating point cannot be optimized in this fashion. (bug 946768)
7571     //
7572     bool srcIsUnsignedNorm = srcIsUnsigned;
7573     if (genTypeSize(castToType) <= genTypeSize(castFromType) && !varTypeIsFloating(castToType))
7574     {
7575         srcIsUnsignedNorm = false;
7576     }
7577
7578     ValueNum     castTypeVN = VNForCastOper(castToType, srcIsUnsignedNorm);
7579     ValueNumPair castTypeVNPair(castTypeVN, castTypeVN);
7580     ValueNumPair castNormRes = VNPairForFunc(resultType, VNF_Cast, castArgVNP, castTypeVNPair);
7581
7582     ValueNumPair resultVNP = VNPWithExc(castNormRes, castArgxVNP);
7583
7584     // If we have a check for overflow, add the exception information.
7585     if (hasOverflowCheck)
7586     {
7587         // For overflow checking, we always need to know whether the source is unsigned.
7588         castTypeVNPair.SetBoth(VNForCastOper(castToType, srcIsUnsigned));
7589         ValueNumPair excSet =
7590             VNPExcSetSingleton(VNPairForFunc(TYP_REF, VNF_ConvOverflowExc, castArgVNP, castTypeVNPair));
7591         excSet    = VNPExcSetUnion(excSet, castArgxVNP);
7592         resultVNP = VNPWithExc(castNormRes, excSet);
7593     }
7594
7595     return resultVNP;
7596 }
7597
7598 void Compiler::fgValueNumberHelperCallFunc(GenTreeCall* call, VNFunc vnf, ValueNumPair vnpExc)
7599 {
7600     unsigned nArgs = ValueNumStore::VNFuncArity(vnf);
7601     assert(vnf != VNF_Boundary);
7602     GenTreeArgList* args                    = call->gtCallArgs;
7603     bool            generateUniqueVN        = false;
7604     bool            useEntryPointAddrAsArg0 = false;
7605
7606     switch (vnf)
7607     {
7608         case VNF_JitNew:
7609         {
7610             generateUniqueVN = true;
7611             vnpExc           = ValueNumStore::VNPForEmptyExcSet();
7612         }
7613         break;
7614
7615         case VNF_JitNewArr:
7616         {
7617             generateUniqueVN  = true;
7618             ValueNumPair vnp1 = vnStore->VNPNormVal(args->Rest()->Current()->gtVNPair);
7619
7620             // The New Array helper may throw an overflow exception
7621             vnpExc = vnStore->VNPExcSetSingleton(vnStore->VNPairForFunc(TYP_REF, VNF_NewArrOverflowExc, vnp1));
7622         }
7623         break;
7624
7625         case VNF_Box:
7626         case VNF_BoxNullable:
7627         {
7628             // Generate unique VN so, VNForFunc generates a uniq value number for box nullable.
7629             // Alternatively instead of using vnpUniq below in VNPairForFunc(...),
7630             // we could use the value number of what the byref arg0 points to.
7631             //
7632             // But retrieving the value number of what the byref arg0 points to is quite a bit more work
7633             // and doing so only very rarely allows for an additional optimization.
7634             generateUniqueVN = true;
7635         }
7636         break;
7637
7638         case VNF_JitReadyToRunNew:
7639         {
7640             generateUniqueVN        = true;
7641             vnpExc                  = ValueNumStore::VNPForEmptyExcSet();
7642             useEntryPointAddrAsArg0 = true;
7643         }
7644         break;
7645
7646         case VNF_JitReadyToRunNewArr:
7647         {
7648             generateUniqueVN  = true;
7649             ValueNumPair vnp1 = vnStore->VNPNormVal(args->Current()->gtVNPair);
7650
7651             // The New Array helper may throw an overflow exception
7652             vnpExc = vnStore->VNPExcSetSingleton(vnStore->VNPairForFunc(TYP_REF, VNF_NewArrOverflowExc, vnp1));
7653             useEntryPointAddrAsArg0 = true;
7654         }
7655         break;
7656
7657         case VNF_ReadyToRunStaticBase:
7658         case VNF_ReadyToRunGenericStaticBase:
7659         case VNF_ReadyToRunIsInstanceOf:
7660         case VNF_ReadyToRunCastClass:
7661         {
7662             useEntryPointAddrAsArg0 = true;
7663         }
7664         break;
7665
7666         default:
7667         {
7668             assert(s_helperCallProperties.IsPure(eeGetHelperNum(call->gtCallMethHnd)));
7669         }
7670         break;
7671     }
7672
7673     if (generateUniqueVN)
7674     {
7675         nArgs--;
7676     }
7677
7678     ValueNumPair vnpUniq;
7679     if (generateUniqueVN)
7680     {
7681         // Generate unique VN so, VNForFunc generates a unique value number.
7682         vnpUniq.SetBoth(vnStore->VNForExpr(compCurBB, call->TypeGet()));
7683     }
7684
7685 #if defined(FEATURE_READYTORUN_COMPILER) && defined(_TARGET_ARMARCH_)
7686     if (call->IsR2RRelativeIndir())
7687     {
7688 #ifdef DEBUG
7689         assert(args->Current()->OperGet() == GT_ARGPLACE);
7690
7691         // Find the corresponding late arg.
7692         GenTree* indirectCellAddress = call->fgArgInfo->GetLateArg(0);
7693         assert(indirectCellAddress->IsCnsIntOrI() && indirectCellAddress->gtRegNum == REG_R2R_INDIRECT_PARAM);
7694 #endif // DEBUG
7695         // For ARM indirectCellAddress is consumed by the call itself, so it should have added as an implicit argument
7696         // in morph. So we do not need to use EntryPointAddrAsArg0, because arg0 is already an entry point addr.
7697         useEntryPointAddrAsArg0 = false;
7698     }
7699 #endif // FEATURE_READYTORUN_COMPILER && _TARGET_ARMARCH_
7700
7701     if (nArgs == 0)
7702     {
7703         if (generateUniqueVN)
7704         {
7705             call->gtVNPair = vnStore->VNPairForFunc(call->TypeGet(), vnf, vnpUniq);
7706         }
7707         else
7708         {
7709             call->gtVNPair.SetBoth(vnStore->VNForFunc(call->TypeGet(), vnf));
7710         }
7711     }
7712     else
7713     {
7714         auto getCurrentArg = [call, &args, useEntryPointAddrAsArg0](int currentIndex) {
7715             GenTree* arg = args->Current();
7716             if ((arg->gtFlags & GTF_LATE_ARG) != 0)
7717             {
7718                 // This arg is a setup node that moves the arg into position.
7719                 // Value-numbering will have visited the separate late arg that
7720                 // holds the actual value, and propagated/computed the value number
7721                 // for this arg there.
7722                 if (useEntryPointAddrAsArg0)
7723                 {
7724                     // The args in the fgArgInfo don't include the entry point, so
7725                     // index into them using one less than the requested index.
7726                     --currentIndex;
7727                 }
7728                 return call->fgArgInfo->GetLateArg(currentIndex);
7729             }
7730             return arg;
7731         };
7732         // Has at least one argument.
7733         ValueNumPair vnp0;
7734         ValueNumPair vnp0x = ValueNumStore::VNPForEmptyExcSet();
7735 #ifdef FEATURE_READYTORUN_COMPILER
7736         if (useEntryPointAddrAsArg0)
7737         {
7738             ssize_t  addrValue  = (ssize_t)call->gtEntryPoint.addr;
7739             ValueNum callAddrVN = vnStore->VNForHandle(addrValue, GTF_ICON_FTN_ADDR);
7740             vnp0                = ValueNumPair(callAddrVN, callAddrVN);
7741         }
7742         else
7743 #endif // FEATURE_READYTORUN_COMPILER
7744         {
7745             assert(!useEntryPointAddrAsArg0);
7746             ValueNumPair vnp0wx = getCurrentArg(0)->gtVNPair;
7747             vnStore->VNPUnpackExc(vnp0wx, &vnp0, &vnp0x);
7748
7749             // Also include in the argument exception sets
7750             vnpExc = vnStore->VNPExcSetUnion(vnpExc, vnp0x);
7751
7752             args = args->Rest();
7753         }
7754         if (nArgs == 1)
7755         {
7756             if (generateUniqueVN)
7757             {
7758                 call->gtVNPair = vnStore->VNPairForFunc(call->TypeGet(), vnf, vnp0, vnpUniq);
7759             }
7760             else
7761             {
7762                 call->gtVNPair = vnStore->VNPairForFunc(call->TypeGet(), vnf, vnp0);
7763             }
7764         }
7765         else
7766         {
7767             // Has at least two arguments.
7768             ValueNumPair vnp1wx = getCurrentArg(1)->gtVNPair;
7769             ValueNumPair vnp1;
7770             ValueNumPair vnp1x = ValueNumStore::VNPForEmptyExcSet();
7771             vnStore->VNPUnpackExc(vnp1wx, &vnp1, &vnp1x);
7772             vnpExc = vnStore->VNPExcSetUnion(vnpExc, vnp1x);
7773
7774             args = args->Rest();
7775             if (nArgs == 2)
7776             {
7777                 if (generateUniqueVN)
7778                 {
7779                     call->gtVNPair = vnStore->VNPairForFunc(call->TypeGet(), vnf, vnp0, vnp1, vnpUniq);
7780                 }
7781                 else
7782                 {
7783                     call->gtVNPair = vnStore->VNPairForFunc(call->TypeGet(), vnf, vnp0, vnp1);
7784                 }
7785             }
7786             else
7787             {
7788                 ValueNumPair vnp2wx = getCurrentArg(2)->gtVNPair;
7789                 ValueNumPair vnp2;
7790                 ValueNumPair vnp2x = ValueNumStore::VNPForEmptyExcSet();
7791                 vnStore->VNPUnpackExc(vnp2wx, &vnp2, &vnp2x);
7792                 vnpExc = vnStore->VNPExcSetUnion(vnpExc, vnp2x);
7793
7794                 args = args->Rest();
7795                 assert(nArgs == 3); // Our current maximum.
7796                 assert(args == nullptr);
7797                 if (generateUniqueVN)
7798                 {
7799                     call->gtVNPair = vnStore->VNPairForFunc(call->TypeGet(), vnf, vnp0, vnp1, vnp2, vnpUniq);
7800                 }
7801                 else
7802                 {
7803                     call->gtVNPair = vnStore->VNPairForFunc(call->TypeGet(), vnf, vnp0, vnp1, vnp2);
7804                 }
7805             }
7806         }
7807         // Add the accumulated exceptions.
7808         call->gtVNPair = vnStore->VNPWithExc(call->gtVNPair, vnpExc);
7809     }
7810     assert(args == nullptr ||
7811            generateUniqueVN); // All arguments should be processed or we generate unique VN and do not care.
7812 }
7813
7814 void Compiler::fgValueNumberCall(GenTreeCall* call)
7815 {
7816     // First: do value numbering of any argument placeholder nodes in the argument list
7817     // (by transferring from the VN of the late arg that they are standing in for...)
7818     unsigned        i               = 0;
7819     GenTreeArgList* args            = call->gtCallArgs;
7820     bool            updatedArgPlace = false;
7821     while (args != nullptr)
7822     {
7823         GenTree* arg = args->Current();
7824         if (arg->OperGet() == GT_ARGPLACE)
7825         {
7826             // Find the corresponding late arg.
7827             GenTree* lateArg = call->fgArgInfo->GetLateArg(i);
7828             assert(lateArg->gtVNPair.BothDefined());
7829             arg->gtVNPair   = lateArg->gtVNPair;
7830             updatedArgPlace = true;
7831 #ifdef DEBUG
7832             if (verbose)
7833             {
7834                 printf("VN of ARGPLACE tree ");
7835                 Compiler::printTreeID(arg);
7836                 printf(" updated to ");
7837                 vnpPrint(arg->gtVNPair, 1);
7838                 printf("\n");
7839             }
7840 #endif
7841         }
7842         i++;
7843         args = args->Rest();
7844     }
7845     if (updatedArgPlace)
7846     {
7847         // Now we have to update the VN's of the argument list nodes, since that will be used in determining
7848         // loop-invariance.
7849         fgUpdateArgListVNs(call->gtCallArgs);
7850     }
7851
7852     if (call->gtCallType == CT_HELPER)
7853     {
7854         bool modHeap = fgValueNumberHelperCall(call);
7855
7856         if (modHeap)
7857         {
7858             // For now, arbitrary side effect on GcHeap/ByrefExposed.
7859             fgMutateGcHeap(call DEBUGARG("HELPER - modifies heap"));
7860         }
7861     }
7862     else
7863     {
7864         if (call->TypeGet() == TYP_VOID)
7865         {
7866             call->gtVNPair.SetBoth(ValueNumStore::VNForVoid());
7867         }
7868         else
7869         {
7870             call->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, call->TypeGet()));
7871         }
7872
7873         // For now, arbitrary side effect on GcHeap/ByrefExposed.
7874         fgMutateGcHeap(call DEBUGARG("CALL"));
7875     }
7876 }
7877
7878 void Compiler::fgUpdateArgListVNs(GenTreeArgList* args)
7879 {
7880     if (args == nullptr)
7881     {
7882         return;
7883     }
7884     // Otherwise...
7885     fgUpdateArgListVNs(args->Rest());
7886     fgValueNumberTree(args);
7887 }
7888
7889 VNFunc Compiler::fgValueNumberHelperMethVNFunc(CorInfoHelpFunc helpFunc)
7890 {
7891     assert(s_helperCallProperties.IsPure(helpFunc) || s_helperCallProperties.IsAllocator(helpFunc));
7892
7893     VNFunc vnf = VNF_Boundary; // An illegal value...
7894     switch (helpFunc)
7895     {
7896         // These translate to other function symbols:
7897         case CORINFO_HELP_DIV:
7898             vnf = VNFunc(GT_DIV);
7899             break;
7900         case CORINFO_HELP_MOD:
7901             vnf = VNFunc(GT_MOD);
7902             break;
7903         case CORINFO_HELP_UDIV:
7904             vnf = VNFunc(GT_UDIV);
7905             break;
7906         case CORINFO_HELP_UMOD:
7907             vnf = VNFunc(GT_UMOD);
7908             break;
7909         case CORINFO_HELP_LLSH:
7910             vnf = VNFunc(GT_LSH);
7911             break;
7912         case CORINFO_HELP_LRSH:
7913             vnf = VNFunc(GT_RSH);
7914             break;
7915         case CORINFO_HELP_LRSZ:
7916             vnf = VNFunc(GT_RSZ);
7917             break;
7918         case CORINFO_HELP_LMUL:
7919         case CORINFO_HELP_LMUL_OVF:
7920             vnf = VNFunc(GT_MUL);
7921             break;
7922         case CORINFO_HELP_ULMUL_OVF:
7923             vnf = VNFunc(GT_MUL);
7924             break; // Is this the right thing?
7925         case CORINFO_HELP_LDIV:
7926             vnf = VNFunc(GT_DIV);
7927             break;
7928         case CORINFO_HELP_LMOD:
7929             vnf = VNFunc(GT_MOD);
7930             break;
7931         case CORINFO_HELP_ULDIV:
7932             vnf = VNFunc(GT_UDIV);
7933             break;
7934         case CORINFO_HELP_ULMOD:
7935             vnf = VNFunc(GT_UMOD);
7936             break;
7937
7938         case CORINFO_HELP_LNG2DBL:
7939             vnf = VNF_Lng2Dbl;
7940             break;
7941         case CORINFO_HELP_ULNG2DBL:
7942             vnf = VNF_ULng2Dbl;
7943             break;
7944         case CORINFO_HELP_DBL2INT:
7945             vnf = VNF_Dbl2Int;
7946             break;
7947         case CORINFO_HELP_DBL2INT_OVF:
7948             vnf = VNF_Dbl2Int;
7949             break;
7950         case CORINFO_HELP_DBL2LNG:
7951             vnf = VNF_Dbl2Lng;
7952             break;
7953         case CORINFO_HELP_DBL2LNG_OVF:
7954             vnf = VNF_Dbl2Lng;
7955             break;
7956         case CORINFO_HELP_DBL2UINT:
7957             vnf = VNF_Dbl2UInt;
7958             break;
7959         case CORINFO_HELP_DBL2UINT_OVF:
7960             vnf = VNF_Dbl2UInt;
7961             break;
7962         case CORINFO_HELP_DBL2ULNG:
7963             vnf = VNF_Dbl2ULng;
7964             break;
7965         case CORINFO_HELP_DBL2ULNG_OVF:
7966             vnf = VNF_Dbl2ULng;
7967             break;
7968         case CORINFO_HELP_FLTREM:
7969             vnf = VNFunc(GT_MOD);
7970             break;
7971         case CORINFO_HELP_DBLREM:
7972             vnf = VNFunc(GT_MOD);
7973             break;
7974         case CORINFO_HELP_FLTROUND:
7975             vnf = VNF_FltRound;
7976             break; // Is this the right thing?
7977         case CORINFO_HELP_DBLROUND:
7978             vnf = VNF_DblRound;
7979             break; // Is this the right thing?
7980
7981         // These allocation operations probably require some augmentation -- perhaps allocSiteId,
7982         // something about array length...
7983         case CORINFO_HELP_NEW_CROSSCONTEXT:
7984         case CORINFO_HELP_NEWFAST:
7985         case CORINFO_HELP_NEWSFAST:
7986         case CORINFO_HELP_NEWSFAST_ALIGN8:
7987             vnf = VNF_JitNew;
7988             break;
7989
7990         case CORINFO_HELP_READYTORUN_NEW:
7991             vnf = VNF_JitReadyToRunNew;
7992             break;
7993
7994         case CORINFO_HELP_NEWARR_1_DIRECT:
7995         case CORINFO_HELP_NEWARR_1_OBJ:
7996         case CORINFO_HELP_NEWARR_1_VC:
7997         case CORINFO_HELP_NEWARR_1_ALIGN8:
7998             vnf = VNF_JitNewArr;
7999             break;
8000
8001         case CORINFO_HELP_NEWARR_1_R2R_DIRECT:
8002         case CORINFO_HELP_READYTORUN_NEWARR_1:
8003             vnf = VNF_JitReadyToRunNewArr;
8004             break;
8005
8006         case CORINFO_HELP_GETGENERICS_GCSTATIC_BASE:
8007             vnf = VNF_GetgenericsGcstaticBase;
8008             break;
8009         case CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE:
8010             vnf = VNF_GetgenericsNongcstaticBase;
8011             break;
8012         case CORINFO_HELP_GETSHARED_GCSTATIC_BASE:
8013             vnf = VNF_GetsharedGcstaticBase;
8014             break;
8015         case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE:
8016             vnf = VNF_GetsharedNongcstaticBase;
8017             break;
8018         case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR:
8019             vnf = VNF_GetsharedGcstaticBaseNoctor;
8020             break;
8021         case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR:
8022             vnf = VNF_GetsharedNongcstaticBaseNoctor;
8023             break;
8024         case CORINFO_HELP_READYTORUN_STATIC_BASE:
8025             vnf = VNF_ReadyToRunStaticBase;
8026             break;
8027         case CORINFO_HELP_READYTORUN_GENERIC_STATIC_BASE:
8028             vnf = VNF_ReadyToRunGenericStaticBase;
8029             break;
8030         case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS:
8031             vnf = VNF_GetsharedGcstaticBaseDynamicclass;
8032             break;
8033         case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS:
8034             vnf = VNF_GetsharedNongcstaticBaseDynamicclass;
8035             break;
8036         case CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS:
8037             vnf = VNF_ClassinitSharedDynamicclass;
8038             break;
8039         case CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE:
8040             vnf = VNF_GetgenericsGcthreadstaticBase;
8041             break;
8042         case CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE:
8043             vnf = VNF_GetgenericsNongcthreadstaticBase;
8044             break;
8045         case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE:
8046             vnf = VNF_GetsharedGcthreadstaticBase;
8047             break;
8048         case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE:
8049             vnf = VNF_GetsharedNongcthreadstaticBase;
8050             break;
8051         case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR:
8052             vnf = VNF_GetsharedGcthreadstaticBaseNoctor;
8053             break;
8054         case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR:
8055             vnf = VNF_GetsharedNongcthreadstaticBaseNoctor;
8056             break;
8057         case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS:
8058             vnf = VNF_GetsharedGcthreadstaticBaseDynamicclass;
8059             break;
8060         case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS:
8061             vnf = VNF_GetsharedNongcthreadstaticBaseDynamicclass;
8062             break;
8063         case CORINFO_HELP_GETSTATICFIELDADDR_CONTEXT:
8064             vnf = VNF_GetStaticAddrContext;
8065             break;
8066         case CORINFO_HELP_GETSTATICFIELDADDR_TLS:
8067             vnf = VNF_GetStaticAddrTLS;
8068             break;
8069
8070         case CORINFO_HELP_RUNTIMEHANDLE_METHOD:
8071         case CORINFO_HELP_RUNTIMEHANDLE_METHOD_LOG:
8072             vnf = VNF_RuntimeHandleMethod;
8073             break;
8074
8075         case CORINFO_HELP_RUNTIMEHANDLE_CLASS:
8076         case CORINFO_HELP_RUNTIMEHANDLE_CLASS_LOG:
8077             vnf = VNF_RuntimeHandleClass;
8078             break;
8079
8080         case CORINFO_HELP_STRCNS:
8081             vnf = VNF_StrCns;
8082             break;
8083
8084         case CORINFO_HELP_CHKCASTCLASS:
8085         case CORINFO_HELP_CHKCASTCLASS_SPECIAL:
8086         case CORINFO_HELP_CHKCASTARRAY:
8087         case CORINFO_HELP_CHKCASTINTERFACE:
8088         case CORINFO_HELP_CHKCASTANY:
8089             vnf = VNF_CastClass;
8090             break;
8091
8092         case CORINFO_HELP_READYTORUN_CHKCAST:
8093             vnf = VNF_ReadyToRunCastClass;
8094             break;
8095
8096         case CORINFO_HELP_ISINSTANCEOFCLASS:
8097         case CORINFO_HELP_ISINSTANCEOFINTERFACE:
8098         case CORINFO_HELP_ISINSTANCEOFARRAY:
8099         case CORINFO_HELP_ISINSTANCEOFANY:
8100             vnf = VNF_IsInstanceOf;
8101             break;
8102
8103         case CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE:
8104             vnf = VNF_TypeHandleToRuntimeType;
8105             break;
8106
8107         case CORINFO_HELP_READYTORUN_ISINSTANCEOF:
8108             vnf = VNF_ReadyToRunIsInstanceOf;
8109             break;
8110
8111         case CORINFO_HELP_LDELEMA_REF:
8112             vnf = VNF_LdElemA;
8113             break;
8114
8115         case CORINFO_HELP_UNBOX:
8116             vnf = VNF_Unbox;
8117             break;
8118
8119         // A constant within any method.
8120         case CORINFO_HELP_GETCURRENTMANAGEDTHREADID:
8121             vnf = VNF_ManagedThreadId;
8122             break;
8123
8124         case CORINFO_HELP_GETREFANY:
8125             // TODO-CQ: This should really be interpreted as just a struct field reference, in terms of values.
8126             vnf = VNF_GetRefanyVal;
8127             break;
8128
8129         case CORINFO_HELP_GETCLASSFROMMETHODPARAM:
8130             vnf = VNF_GetClassFromMethodParam;
8131             break;
8132
8133         case CORINFO_HELP_GETSYNCFROMCLASSHANDLE:
8134             vnf = VNF_GetSyncFromClassHandle;
8135             break;
8136
8137         case CORINFO_HELP_LOOP_CLONE_CHOICE_ADDR:
8138             vnf = VNF_LoopCloneChoiceAddr;
8139             break;
8140
8141         case CORINFO_HELP_BOX:
8142             vnf = VNF_Box;
8143             break;
8144
8145         case CORINFO_HELP_BOX_NULLABLE:
8146             vnf = VNF_BoxNullable;
8147             break;
8148
8149         default:
8150             unreached();
8151     }
8152
8153     assert(vnf != VNF_Boundary);
8154     return vnf;
8155 }
8156
8157 bool Compiler::fgValueNumberHelperCall(GenTreeCall* call)
8158 {
8159     CorInfoHelpFunc helpFunc    = eeGetHelperNum(call->gtCallMethHnd);
8160     bool            pure        = s_helperCallProperties.IsPure(helpFunc);
8161     bool            isAlloc     = s_helperCallProperties.IsAllocator(helpFunc);
8162     bool            modHeap     = s_helperCallProperties.MutatesHeap(helpFunc);
8163     bool            mayRunCctor = s_helperCallProperties.MayRunCctor(helpFunc);
8164     bool            noThrow     = s_helperCallProperties.NoThrow(helpFunc);
8165
8166     ValueNumPair vnpExc = ValueNumStore::VNPForEmptyExcSet();
8167
8168     // If the JIT helper can throw an exception make sure that we fill in
8169     // vnpExc with a Value Number that represents the exception(s) that can be thrown.
8170     if (!noThrow)
8171     {
8172         // If the helper is known to only throw only one particular exception
8173         // we can set vnpExc to that exception, otherwise we conservatively
8174         // model the JIT helper as possibly throwing multiple different exceptions
8175         //
8176         switch (helpFunc)
8177         {
8178             case CORINFO_HELP_OVERFLOW:
8179                 // This helper always throws the VNF_OverflowExc exception
8180                 vnpExc = vnStore->VNPExcSetSingleton(vnStore->VNPairForFunc(TYP_REF, VNF_OverflowExc));
8181                 break;
8182
8183             default:
8184                 // Setup vnpExc with the information that multiple different exceptions
8185                 // could be generated by this helper
8186                 vnpExc = vnStore->VNPExcSetSingleton(vnStore->VNPairForFunc(TYP_REF, VNF_HelperMultipleExc));
8187         }
8188     }
8189
8190     ValueNumPair vnpNorm;
8191
8192     if (call->TypeGet() == TYP_VOID)
8193     {
8194         vnpNorm = ValueNumStore::VNPForVoid();
8195     }
8196     else
8197     {
8198         // TODO-CQ: this is a list of helpers we're going to treat as non-pure,
8199         // because they raise complications.  Eventually, we need to handle those complications...
8200         bool needsFurtherWork = false;
8201         switch (helpFunc)
8202         {
8203             case CORINFO_HELP_NEW_MDARR:
8204                 // This is a varargs helper.  We need to represent the array shape in the VN world somehow.
8205                 needsFurtherWork = true;
8206                 break;
8207             default:
8208                 break;
8209         }
8210
8211         if (!needsFurtherWork && (pure || isAlloc))
8212         {
8213             VNFunc vnf = fgValueNumberHelperMethVNFunc(helpFunc);
8214
8215             if (mayRunCctor)
8216             {
8217                 if ((call->gtFlags & GTF_CALL_HOISTABLE) == 0)
8218                 {
8219                     modHeap = true;
8220                 }
8221             }
8222
8223             fgValueNumberHelperCallFunc(call, vnf, vnpExc);
8224             return modHeap;
8225         }
8226         else
8227         {
8228             vnpNorm.SetBoth(vnStore->VNForExpr(compCurBB, call->TypeGet()));
8229         }
8230     }
8231
8232     call->gtVNPair = vnStore->VNPWithExc(vnpNorm, vnpExc);
8233     return modHeap;
8234 }
8235
8236 #ifdef DEBUG
8237 // This method asserts that SSA name constraints specified are satisfied.
8238 // Until we figure out otherwise, all VN's are assumed to be liberal.
8239 // TODO-Cleanup: new JitTestLabels for lib vs cons vs both VN classes?
8240 void Compiler::JitTestCheckVN()
8241 {
8242     typedef JitHashTable<ssize_t, JitSmallPrimitiveKeyFuncs<ssize_t>, ValueNum>  LabelToVNMap;
8243     typedef JitHashTable<ValueNum, JitSmallPrimitiveKeyFuncs<ValueNum>, ssize_t> VNToLabelMap;
8244
8245     // If we have no test data, early out.
8246     if (m_nodeTestData == nullptr)
8247     {
8248         return;
8249     }
8250
8251     NodeToTestDataMap* testData = GetNodeTestData();
8252
8253     // First we have to know which nodes in the tree are reachable.
8254     typedef JitHashTable<GenTree*, JitPtrKeyFuncs<GenTree>, int> NodeToIntMap;
8255     NodeToIntMap* reachable = FindReachableNodesInNodeTestData();
8256
8257     LabelToVNMap* labelToVN = new (getAllocatorDebugOnly()) LabelToVNMap(getAllocatorDebugOnly());
8258     VNToLabelMap* vnToLabel = new (getAllocatorDebugOnly()) VNToLabelMap(getAllocatorDebugOnly());
8259
8260     if (verbose)
8261     {
8262         printf("\nJit Testing: Value numbering.\n");
8263     }
8264     for (NodeToTestDataMap::KeyIterator ki = testData->Begin(); !ki.Equal(testData->End()); ++ki)
8265     {
8266         TestLabelAndNum tlAndN;
8267         GenTree*        node   = ki.Get();
8268         ValueNum        nodeVN = node->GetVN(VNK_Liberal);
8269
8270         bool b = testData->Lookup(node, &tlAndN);
8271         assert(b);
8272         if (tlAndN.m_tl == TL_VN || tlAndN.m_tl == TL_VNNorm)
8273         {
8274             int dummy;
8275             if (!reachable->Lookup(node, &dummy))
8276             {
8277                 printf("Node ");
8278                 Compiler::printTreeID(node);
8279                 printf(" had a test constraint declared, but has become unreachable at the time the constraint is "
8280                        "tested.\n"
8281                        "(This is probably as a result of some optimization -- \n"
8282                        "you may need to modify the test case to defeat this opt.)\n");
8283                 assert(false);
8284             }
8285
8286             if (verbose)
8287             {
8288                 printf("  Node ");
8289                 Compiler::printTreeID(node);
8290                 printf(" -- VN class %d.\n", tlAndN.m_num);
8291             }
8292
8293             if (tlAndN.m_tl == TL_VNNorm)
8294             {
8295                 nodeVN = vnStore->VNNormVal(nodeVN);
8296             }
8297
8298             ValueNum vn;
8299             if (labelToVN->Lookup(tlAndN.m_num, &vn))
8300             {
8301                 if (verbose)
8302                 {
8303                     printf("      Already in hash tables.\n");
8304                 }
8305                 // The mapping(s) must be one-to-one: if the label has a mapping, then the ssaNm must, as well.
8306                 ssize_t num2;
8307                 bool    b = vnToLabel->Lookup(vn, &num2);
8308                 // And the mappings must be the same.
8309                 if (tlAndN.m_num != num2)
8310                 {
8311                     printf("Node: ");
8312                     Compiler::printTreeID(node);
8313                     printf(", with value number " FMT_VN ", was declared in VN class %d,\n", nodeVN, tlAndN.m_num);
8314                     printf("but this value number " FMT_VN
8315                            " has already been associated with a different SSA name class: %d.\n",
8316                            vn, num2);
8317                     assert(false);
8318                 }
8319                 // And the current node must be of the specified SSA family.
8320                 if (nodeVN != vn)
8321                 {
8322                     printf("Node: ");
8323                     Compiler::printTreeID(node);
8324                     printf(", " FMT_VN " was declared in SSA name class %d,\n", nodeVN, tlAndN.m_num);
8325                     printf("but that name class was previously bound to a different value number: " FMT_VN ".\n", vn);
8326                     assert(false);
8327                 }
8328             }
8329             else
8330             {
8331                 ssize_t num;
8332                 // The mapping(s) must be one-to-one: if the label has no mapping, then the ssaNm may not, either.
8333                 if (vnToLabel->Lookup(nodeVN, &num))
8334                 {
8335                     printf("Node: ");
8336                     Compiler::printTreeID(node);
8337                     printf(", " FMT_VN " was declared in value number class %d,\n", nodeVN, tlAndN.m_num);
8338                     printf(
8339                         "but this value number has already been associated with a different value number class: %d.\n",
8340                         num);
8341                     assert(false);
8342                 }
8343                 // Add to both mappings.
8344                 labelToVN->Set(tlAndN.m_num, nodeVN);
8345                 vnToLabel->Set(nodeVN, tlAndN.m_num);
8346                 if (verbose)
8347                 {
8348                     printf("      added to hash tables.\n");
8349                 }
8350             }
8351         }
8352     }
8353 }
8354
8355 void Compiler::vnpPrint(ValueNumPair vnp, unsigned level)
8356 {
8357     if (vnp.BothEqual())
8358     {
8359         vnPrint(vnp.GetLiberal(), level);
8360     }
8361     else
8362     {
8363         printf("<l:");
8364         vnPrint(vnp.GetLiberal(), level);
8365         printf(", c:");
8366         vnPrint(vnp.GetConservative(), level);
8367         printf(">");
8368     }
8369 }
8370
8371 void Compiler::vnPrint(ValueNum vn, unsigned level)
8372 {
8373
8374     if (ValueNumStore::isReservedVN(vn))
8375     {
8376         printf(ValueNumStore::reservedName(vn));
8377     }
8378     else
8379     {
8380         printf(FMT_VN, vn);
8381         if (level > 0)
8382         {
8383             vnStore->vnDump(this, vn);
8384         }
8385     }
8386 }
8387
8388 #endif // DEBUG
8389
8390 // Methods of ValueNumPair.
8391 ValueNumPair::ValueNumPair() : m_liberal(ValueNumStore::NoVN), m_conservative(ValueNumStore::NoVN)
8392 {
8393 }
8394
8395 bool ValueNumPair::BothDefined() const
8396 {
8397     return (m_liberal != ValueNumStore::NoVN) && (m_conservative != ValueNumStore::NoVN);
8398 }