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