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