fb31d426677b20651f6f086e8f2302fe944a15ae
[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     unsigned outerLoopNum = BasicBlock::NOT_IN_LOOP;
5927
5928     // First: visit phi's.  If "newVNForPhis", give them new VN's.  If not,
5929     // first check to see if all phi args have the same value.
5930     GenTree* firstNonPhi = blk->FirstNonPhiDef();
5931     for (GenTree* phiDefs = blk->bbTreeList; phiDefs != firstNonPhi; phiDefs = phiDefs->gtNext)
5932     {
5933         // TODO-Cleanup: It has been proposed that we should have an IsPhiDef predicate.  We would use it
5934         // in Block::FirstNonPhiDef as well.
5935         GenTree* phiDef = phiDefs->gtStmt.gtStmtExpr;
5936         assert(phiDef->OperGet() == GT_ASG);
5937         GenTreeLclVarCommon* newSsaVar = phiDef->gtOp.gtOp1->AsLclVarCommon();
5938
5939         ValueNumPair phiAppVNP;
5940         ValueNumPair sameVNPair;
5941
5942         GenTree* phiFunc = phiDef->gtOp.gtOp2;
5943
5944         // At this point a GT_PHI node should never have a nullptr for gtOp1
5945         // and the gtOp1 should always be a GT_LIST node.
5946         GenTree* phiOp1 = phiFunc->gtOp.gtOp1;
5947         noway_assert(phiOp1 != nullptr);
5948         noway_assert(phiOp1->OperGet() == GT_LIST);
5949
5950         GenTreeArgList* phiArgs = phiFunc->gtOp.gtOp1->AsArgList();
5951
5952         // A GT_PHI node should have more than one argument.
5953         noway_assert(phiArgs->Rest() != nullptr);
5954
5955         GenTreeLclVarCommon* phiArg = phiArgs->Current()->AsLclVarCommon();
5956         phiArgs                     = phiArgs->Rest();
5957
5958         phiAppVNP.SetBoth(vnStore->VNForIntCon(phiArg->gtSsaNum));
5959         bool allSameLib  = true;
5960         bool allSameCons = true;
5961         sameVNPair       = lvaTable[phiArg->gtLclNum].GetPerSsaData(phiArg->gtSsaNum)->m_vnPair;
5962         if (!sameVNPair.BothDefined())
5963         {
5964             allSameLib  = false;
5965             allSameCons = false;
5966         }
5967         while (phiArgs != nullptr)
5968         {
5969             phiArg = phiArgs->Current()->AsLclVarCommon();
5970             // Set the VN of the phi arg.
5971             phiArg->gtVNPair = lvaTable[phiArg->gtLclNum].GetPerSsaData(phiArg->gtSsaNum)->m_vnPair;
5972             if (phiArg->gtVNPair.BothDefined())
5973             {
5974                 if (phiArg->gtVNPair.GetLiberal() != sameVNPair.GetLiberal())
5975                 {
5976                     allSameLib = false;
5977                 }
5978                 if (phiArg->gtVNPair.GetConservative() != sameVNPair.GetConservative())
5979                 {
5980                     allSameCons = false;
5981                 }
5982             }
5983             else
5984             {
5985                 allSameLib  = false;
5986                 allSameCons = false;
5987             }
5988             ValueNumPair phiArgSsaVNP;
5989             phiArgSsaVNP.SetBoth(vnStore->VNForIntCon(phiArg->gtSsaNum));
5990             phiAppVNP = vnStore->VNPairForFunc(newSsaVar->TypeGet(), VNF_Phi, phiArgSsaVNP, phiAppVNP);
5991             phiArgs   = phiArgs->Rest();
5992         }
5993
5994         ValueNumPair newVNPair;
5995         if (allSameLib)
5996         {
5997             newVNPair.SetLiberal(sameVNPair.GetLiberal());
5998         }
5999         else
6000         {
6001             newVNPair.SetLiberal(phiAppVNP.GetLiberal());
6002         }
6003         if (allSameCons)
6004         {
6005             newVNPair.SetConservative(sameVNPair.GetConservative());
6006         }
6007         else
6008         {
6009             newVNPair.SetConservative(phiAppVNP.GetConservative());
6010         }
6011
6012         LclSsaVarDsc* newSsaVarDsc = lvaTable[newSsaVar->gtLclNum].GetPerSsaData(newSsaVar->GetSsaNum());
6013         // If all the args of the phi had the same value(s, liberal and conservative), then there wasn't really
6014         // a reason to have the phi -- just pass on that value.
6015         if (allSameLib && allSameCons)
6016         {
6017             newSsaVarDsc->m_vnPair = newVNPair;
6018 #ifdef DEBUG
6019             if (verbose)
6020             {
6021                 printf("In SSA definition, incoming phi args all same, set VN of local %d/%d to ",
6022                        newSsaVar->GetLclNum(), newSsaVar->GetSsaNum());
6023                 vnpPrint(newVNPair, 1);
6024                 printf(".\n");
6025             }
6026 #endif // DEBUG
6027         }
6028         else
6029         {
6030             // They were not the same; we need to create a phi definition.
6031             ValueNumPair lclNumVNP;
6032             lclNumVNP.SetBoth(ValueNum(newSsaVar->GetLclNum()));
6033             ValueNumPair ssaNumVNP;
6034             ssaNumVNP.SetBoth(ValueNum(newSsaVar->GetSsaNum()));
6035             ValueNumPair vnPhiDef =
6036                 vnStore->VNPairForFunc(newSsaVar->TypeGet(), VNF_PhiDef, lclNumVNP, ssaNumVNP, phiAppVNP);
6037             newSsaVarDsc->m_vnPair = vnPhiDef;
6038 #ifdef DEBUG
6039             if (verbose)
6040             {
6041                 printf("SSA definition: set VN of local %d/%d to ", newSsaVar->GetLclNum(), newSsaVar->GetSsaNum());
6042                 vnpPrint(vnPhiDef, 1);
6043                 printf(".\n");
6044             }
6045 #endif // DEBUG
6046         }
6047     }
6048
6049     // Now do the same for each MemoryKind.
6050     for (MemoryKind memoryKind : allMemoryKinds())
6051     {
6052         // Is there a phi for this block?
6053         if (blk->bbMemorySsaPhiFunc[memoryKind] == nullptr)
6054         {
6055             fgCurMemoryVN[memoryKind] = GetMemoryPerSsaData(blk->bbMemorySsaNumIn[memoryKind])->m_vnPair.GetLiberal();
6056             assert(fgCurMemoryVN[memoryKind] != ValueNumStore::NoVN);
6057         }
6058         else
6059         {
6060             if ((memoryKind == ByrefExposed) && byrefStatesMatchGcHeapStates)
6061             {
6062                 // The update for GcHeap will copy its result to ByrefExposed.
6063                 assert(memoryKind < GcHeap);
6064                 assert(blk->bbMemorySsaPhiFunc[memoryKind] == blk->bbMemorySsaPhiFunc[GcHeap]);
6065                 continue;
6066             }
6067
6068             unsigned loopNum;
6069             ValueNum newMemoryVN;
6070             if (optBlockIsLoopEntry(blk, &loopNum))
6071             {
6072                 newMemoryVN = fgMemoryVNForLoopSideEffects(memoryKind, blk, loopNum);
6073             }
6074             else
6075             {
6076                 // Are all the VN's the same?
6077                 BasicBlock::MemoryPhiArg* phiArgs = blk->bbMemorySsaPhiFunc[memoryKind];
6078                 assert(phiArgs != BasicBlock::EmptyMemoryPhiDef);
6079                 // There should be > 1 args to a phi.
6080                 assert(phiArgs->m_nextArg != nullptr);
6081                 ValueNum phiAppVN = vnStore->VNForIntCon(phiArgs->GetSsaNum());
6082                 JITDUMP("  Building phi application: $%x = SSA# %d.\n", phiAppVN, phiArgs->GetSsaNum());
6083                 bool     allSame = true;
6084                 ValueNum sameVN  = GetMemoryPerSsaData(phiArgs->GetSsaNum())->m_vnPair.GetLiberal();
6085                 if (sameVN == ValueNumStore::NoVN)
6086                 {
6087                     allSame = false;
6088                 }
6089                 phiArgs = phiArgs->m_nextArg;
6090                 while (phiArgs != nullptr)
6091                 {
6092                     ValueNum phiArgVN = GetMemoryPerSsaData(phiArgs->GetSsaNum())->m_vnPair.GetLiberal();
6093                     if (phiArgVN == ValueNumStore::NoVN || phiArgVN != sameVN)
6094                     {
6095                         allSame = false;
6096                     }
6097 #ifdef DEBUG
6098                     ValueNum oldPhiAppVN = phiAppVN;
6099 #endif
6100                     unsigned phiArgSSANum   = phiArgs->GetSsaNum();
6101                     ValueNum phiArgSSANumVN = vnStore->VNForIntCon(phiArgSSANum);
6102                     JITDUMP("  Building phi application: $%x = SSA# %d.\n", phiArgSSANumVN, phiArgSSANum);
6103                     phiAppVN = vnStore->VNForFunc(TYP_REF, VNF_Phi, phiArgSSANumVN, phiAppVN);
6104                     JITDUMP("  Building phi application: $%x = phi($%x, $%x).\n", phiAppVN, phiArgSSANumVN,
6105                             oldPhiAppVN);
6106                     phiArgs = phiArgs->m_nextArg;
6107                 }
6108                 if (allSame)
6109                 {
6110                     newMemoryVN = sameVN;
6111                 }
6112                 else
6113                 {
6114                     newMemoryVN =
6115                         vnStore->VNForFunc(TYP_REF, VNF_PhiMemoryDef, vnStore->VNForHandle(ssize_t(blk), 0), phiAppVN);
6116                 }
6117             }
6118             GetMemoryPerSsaData(blk->bbMemorySsaNumIn[memoryKind])->m_vnPair.SetLiberal(newMemoryVN);
6119             fgCurMemoryVN[memoryKind] = newMemoryVN;
6120             if ((memoryKind == GcHeap) && byrefStatesMatchGcHeapStates)
6121             {
6122                 // Keep the CurMemoryVNs in sync
6123                 fgCurMemoryVN[ByrefExposed] = newMemoryVN;
6124             }
6125         }
6126 #ifdef DEBUG
6127         if (verbose)
6128         {
6129             printf("The SSA definition for %s (#%d) at start of " FMT_BB " is ", memoryKindNames[memoryKind],
6130                    blk->bbMemorySsaNumIn[memoryKind], blk->bbNum);
6131             vnPrint(fgCurMemoryVN[memoryKind], 1);
6132             printf("\n");
6133         }
6134 #endif // DEBUG
6135     }
6136
6137     // Now iterate over the remaining statements, and their trees.
6138     for (GenTree* stmt = firstNonPhi; stmt != nullptr; stmt = stmt->gtNext)
6139     {
6140         assert(stmt->IsStatement());
6141
6142 #ifdef DEBUG
6143         compCurStmtNum++;
6144         if (verbose)
6145         {
6146             printf("\n***** " FMT_BB ", stmt %d (before)\n", blk->bbNum, compCurStmtNum);
6147             gtDispTree(stmt->gtStmt.gtStmtExpr);
6148             printf("\n");
6149         }
6150 #endif
6151
6152         for (GenTree* tree = stmt->gtStmt.gtStmtList; tree; tree = tree->gtNext)
6153         {
6154             fgValueNumberTree(tree);
6155         }
6156
6157 #ifdef DEBUG
6158         if (verbose)
6159         {
6160             printf("\n***** " FMT_BB ", stmt %d (after)\n", blk->bbNum, compCurStmtNum);
6161             gtDispTree(stmt->gtStmt.gtStmtExpr);
6162             printf("\n");
6163             if (stmt->gtNext)
6164             {
6165                 printf("---------\n");
6166             }
6167         }
6168 #endif
6169     }
6170
6171     for (MemoryKind memoryKind : allMemoryKinds())
6172     {
6173         if ((memoryKind == GcHeap) && byrefStatesMatchGcHeapStates)
6174         {
6175             // The update to the shared SSA data will have already happened for ByrefExposed.
6176             assert(memoryKind > ByrefExposed);
6177             assert(blk->bbMemorySsaNumOut[memoryKind] == blk->bbMemorySsaNumOut[ByrefExposed]);
6178             assert(GetMemoryPerSsaData(blk->bbMemorySsaNumOut[memoryKind])->m_vnPair.GetLiberal() ==
6179                    fgCurMemoryVN[memoryKind]);
6180             continue;
6181         }
6182
6183         if (blk->bbMemorySsaNumOut[memoryKind] != blk->bbMemorySsaNumIn[memoryKind])
6184         {
6185             GetMemoryPerSsaData(blk->bbMemorySsaNumOut[memoryKind])->m_vnPair.SetLiberal(fgCurMemoryVN[memoryKind]);
6186         }
6187     }
6188
6189     compCurBB = nullptr;
6190 }
6191
6192 ValueNum Compiler::fgMemoryVNForLoopSideEffects(MemoryKind  memoryKind,
6193                                                 BasicBlock* entryBlock,
6194                                                 unsigned    innermostLoopNum)
6195 {
6196     // "loopNum" is the innermost loop for which "blk" is the entry; find the outermost one.
6197     assert(innermostLoopNum != BasicBlock::NOT_IN_LOOP);
6198     unsigned loopsInNest = innermostLoopNum;
6199     unsigned loopNum     = innermostLoopNum;
6200     while (loopsInNest != BasicBlock::NOT_IN_LOOP)
6201     {
6202         if (optLoopTable[loopsInNest].lpEntry != entryBlock)
6203         {
6204             break;
6205         }
6206         loopNum     = loopsInNest;
6207         loopsInNest = optLoopTable[loopsInNest].lpParent;
6208     }
6209
6210 #ifdef DEBUG
6211     if (verbose)
6212     {
6213         printf("Computing %s state for block " FMT_BB ", entry block for loops %d to %d:\n",
6214                memoryKindNames[memoryKind], entryBlock->bbNum, innermostLoopNum, loopNum);
6215     }
6216 #endif // DEBUG
6217
6218     // If this loop has memory havoc effects, just use a new, unique VN.
6219     if (optLoopTable[loopNum].lpLoopHasMemoryHavoc[memoryKind])
6220     {
6221         ValueNum res = vnStore->VNForExpr(entryBlock, TYP_REF);
6222 #ifdef DEBUG
6223         if (verbose)
6224         {
6225             printf("  Loop %d has memory havoc effect; heap state is new unique $%x.\n", loopNum, res);
6226         }
6227 #endif // DEBUG
6228         return res;
6229     }
6230
6231     // Otherwise, find the predecessors of the entry block that are not in the loop.
6232     // If there is only one such, use its memory value as the "base."  If more than one,
6233     // use a new unique VN.
6234     BasicBlock* nonLoopPred          = nullptr;
6235     bool        multipleNonLoopPreds = false;
6236     for (flowList* pred = BlockPredsWithEH(entryBlock); pred != nullptr; pred = pred->flNext)
6237     {
6238         BasicBlock* predBlock = pred->flBlock;
6239         if (!optLoopTable[loopNum].lpContains(predBlock))
6240         {
6241             if (nonLoopPred == nullptr)
6242             {
6243                 nonLoopPred = predBlock;
6244             }
6245             else
6246             {
6247 #ifdef DEBUG
6248                 if (verbose)
6249                 {
6250                     printf("  Entry block has >1 non-loop preds: (at least) " FMT_BB " and " FMT_BB ".\n",
6251                            nonLoopPred->bbNum, predBlock->bbNum);
6252                 }
6253 #endif // DEBUG
6254                 multipleNonLoopPreds = true;
6255                 break;
6256             }
6257         }
6258     }
6259     if (multipleNonLoopPreds)
6260     {
6261         ValueNum res = vnStore->VNForExpr(entryBlock, TYP_REF);
6262 #ifdef DEBUG
6263         if (verbose)
6264         {
6265             printf("  Therefore, memory state is new, fresh $%x.\n", res);
6266         }
6267 #endif // DEBUG
6268         return res;
6269     }
6270     // Otherwise, there is a single non-loop pred.
6271     assert(nonLoopPred != nullptr);
6272     // What is its memory post-state?
6273     ValueNum newMemoryVN = GetMemoryPerSsaData(nonLoopPred->bbMemorySsaNumOut[memoryKind])->m_vnPair.GetLiberal();
6274     assert(newMemoryVN != ValueNumStore::NoVN); // We must have processed the single non-loop pred before reaching the
6275                                                 // loop entry.
6276
6277 #ifdef DEBUG
6278     if (verbose)
6279     {
6280         printf("  Init %s state is $%x, with new, fresh VN at:\n", memoryKindNames[memoryKind], newMemoryVN);
6281     }
6282 #endif // DEBUG
6283     // Modify "base" by setting all the modified fields/field maps/array maps to unknown values.
6284     // These annotations apply specifically to the GcHeap, where we disambiguate across such stores.
6285     if (memoryKind == GcHeap)
6286     {
6287         // First the fields/field maps.
6288         Compiler::LoopDsc::FieldHandleSet* fieldsMod = optLoopTable[loopNum].lpFieldsModified;
6289         if (fieldsMod != nullptr)
6290         {
6291             for (Compiler::LoopDsc::FieldHandleSet::KeyIterator ki = fieldsMod->Begin(); !ki.Equal(fieldsMod->End());
6292                  ++ki)
6293             {
6294                 CORINFO_FIELD_HANDLE fldHnd   = ki.Get();
6295                 ValueNum             fldHndVN = vnStore->VNForHandle(ssize_t(fldHnd), GTF_ICON_FIELD_HDL);
6296
6297 #ifdef DEBUG
6298                 if (verbose)
6299                 {
6300                     const char* modName;
6301                     const char* fldName = eeGetFieldName(fldHnd, &modName);
6302                     printf("     VNForHandle(%s) is " FMT_VN "\n", fldName, fldHndVN);
6303                 }
6304 #endif // DEBUG
6305
6306                 newMemoryVN =
6307                     vnStore->VNForMapStore(TYP_REF, newMemoryVN, fldHndVN, vnStore->VNForExpr(entryBlock, TYP_REF));
6308             }
6309         }
6310         // Now do the array maps.
6311         Compiler::LoopDsc::ClassHandleSet* elemTypesMod = optLoopTable[loopNum].lpArrayElemTypesModified;
6312         if (elemTypesMod != nullptr)
6313         {
6314             for (Compiler::LoopDsc::ClassHandleSet::KeyIterator ki = elemTypesMod->Begin();
6315                  !ki.Equal(elemTypesMod->End()); ++ki)
6316             {
6317                 CORINFO_CLASS_HANDLE elemClsHnd = ki.Get();
6318
6319 #ifdef DEBUG
6320                 if (verbose)
6321                 {
6322                     var_types elemTyp = DecodeElemType(elemClsHnd);
6323                     // If a valid class handle is given when the ElemType is set, DecodeElemType will
6324                     // return TYP_STRUCT, and elemClsHnd is that handle.
6325                     // Otherwise, elemClsHnd is NOT a valid class handle, and is the encoded var_types value.
6326                     if (elemTyp == TYP_STRUCT)
6327                     {
6328                         printf("     Array map %s[]\n", eeGetClassName(elemClsHnd));
6329                     }
6330                     else
6331                     {
6332                         printf("     Array map %s[]\n", varTypeName(elemTyp));
6333                     }
6334                 }
6335 #endif // DEBUG
6336
6337                 ValueNum elemTypeVN = vnStore->VNForHandle(ssize_t(elemClsHnd), GTF_ICON_CLASS_HDL);
6338                 ValueNum uniqueVN   = vnStore->VNForExpr(entryBlock, TYP_REF);
6339                 newMemoryVN         = vnStore->VNForMapStore(TYP_REF, newMemoryVN, elemTypeVN, uniqueVN);
6340             }
6341         }
6342     }
6343     else
6344     {
6345         // If there were any fields/elements modified, this should have been recorded as havoc
6346         // for ByrefExposed.
6347         assert(memoryKind == ByrefExposed);
6348         assert((optLoopTable[loopNum].lpFieldsModified == nullptr) ||
6349                optLoopTable[loopNum].lpLoopHasMemoryHavoc[memoryKind]);
6350         assert((optLoopTable[loopNum].lpArrayElemTypesModified == nullptr) ||
6351                optLoopTable[loopNum].lpLoopHasMemoryHavoc[memoryKind]);
6352     }
6353
6354 #ifdef DEBUG
6355     if (verbose)
6356     {
6357         printf("  Final %s state is $%x.\n", memoryKindNames[memoryKind], newMemoryVN);
6358     }
6359 #endif // DEBUG
6360     return newMemoryVN;
6361 }
6362
6363 void Compiler::fgMutateGcHeap(GenTree* tree DEBUGARG(const char* msg))
6364 {
6365     // Update the current memory VN, and if we're tracking the heap SSA # caused by this node, record it.
6366     recordGcHeapStore(tree, vnStore->VNForExpr(compCurBB, TYP_REF) DEBUGARG(msg));
6367 }
6368
6369 void Compiler::fgMutateAddressExposedLocal(GenTree* tree DEBUGARG(const char* msg))
6370 {
6371     // Update the current ByrefExposed VN, and if we're tracking the heap SSA # caused by this node, record it.
6372     recordAddressExposedLocalStore(tree, vnStore->VNForExpr(compCurBB) DEBUGARG(msg));
6373 }
6374
6375 void Compiler::recordGcHeapStore(GenTree* curTree, ValueNum gcHeapVN DEBUGARG(const char* msg))
6376 {
6377     // bbMemoryDef must include GcHeap for any block that mutates the GC Heap
6378     // and GC Heap mutations are also ByrefExposed mutations
6379     assert((compCurBB->bbMemoryDef & memoryKindSet(GcHeap, ByrefExposed)) == memoryKindSet(GcHeap, ByrefExposed));
6380     fgCurMemoryVN[GcHeap] = gcHeapVN;
6381
6382     if (byrefStatesMatchGcHeapStates)
6383     {
6384         // Since GcHeap and ByrefExposed share SSA nodes, they need to share
6385         // value numbers too.
6386         fgCurMemoryVN[ByrefExposed] = gcHeapVN;
6387     }
6388     else
6389     {
6390         // GcHeap and ByrefExposed have different defnums and VNs.  We conservatively
6391         // assume that this GcHeap store may alias any byref load/store, so don't
6392         // bother trying to record the map/select stuff, and instead just an opaque VN
6393         // for ByrefExposed
6394         fgCurMemoryVN[ByrefExposed] = vnStore->VNForExpr(compCurBB);
6395     }
6396
6397 #ifdef DEBUG
6398     if (verbose)
6399     {
6400         printf("  fgCurMemoryVN[GcHeap] assigned for %s at ", msg);
6401         Compiler::printTreeID(curTree);
6402         printf(" to VN: " FMT_VN ".\n", gcHeapVN);
6403     }
6404 #endif // DEBUG
6405
6406     // If byrefStatesMatchGcHeapStates is true, then since GcHeap and ByrefExposed share
6407     // their SSA map entries, the below will effectively update both.
6408     fgValueNumberRecordMemorySsa(GcHeap, curTree);
6409 }
6410
6411 void Compiler::recordAddressExposedLocalStore(GenTree* curTree, ValueNum memoryVN DEBUGARG(const char* msg))
6412 {
6413     // This should only happen if GcHeap and ByrefExposed are being tracked separately;
6414     // otherwise we'd go through recordGcHeapStore.
6415     assert(!byrefStatesMatchGcHeapStates);
6416
6417     // bbMemoryDef must include ByrefExposed for any block that mutates an address-exposed local
6418     assert((compCurBB->bbMemoryDef & memoryKindSet(ByrefExposed)) != 0);
6419     fgCurMemoryVN[ByrefExposed] = memoryVN;
6420
6421 #ifdef DEBUG
6422     if (verbose)
6423     {
6424         printf("  fgCurMemoryVN[ByrefExposed] assigned for %s at ", msg);
6425         Compiler::printTreeID(curTree);
6426         printf(" to VN: " FMT_VN ".\n", memoryVN);
6427     }
6428 #endif // DEBUG
6429
6430     fgValueNumberRecordMemorySsa(ByrefExposed, curTree);
6431 }
6432
6433 void Compiler::fgValueNumberRecordMemorySsa(MemoryKind memoryKind, GenTree* tree)
6434 {
6435     unsigned ssaNum;
6436     if (GetMemorySsaMap(memoryKind)->Lookup(tree, &ssaNum))
6437     {
6438         GetMemoryPerSsaData(ssaNum)->m_vnPair.SetLiberal(fgCurMemoryVN[memoryKind]);
6439 #ifdef DEBUG
6440         if (verbose)
6441         {
6442             printf("Node ");
6443             Compiler::printTreeID(tree);
6444             printf(" sets %s SSA # %d to VN $%x: ", memoryKindNames[memoryKind], ssaNum, fgCurMemoryVN[memoryKind]);
6445             vnStore->vnDump(this, fgCurMemoryVN[memoryKind]);
6446             printf("\n");
6447         }
6448 #endif // DEBUG
6449     }
6450 }
6451
6452 // The input 'tree' is a leaf node that is a constant
6453 // Assign the proper value number to the tree
6454 void Compiler::fgValueNumberTreeConst(GenTree* tree)
6455 {
6456     genTreeOps oper = tree->OperGet();
6457     var_types  typ  = tree->TypeGet();
6458     assert(GenTree::OperIsConst(oper));
6459
6460     switch (typ)
6461     {
6462         case TYP_LONG:
6463         case TYP_ULONG:
6464         case TYP_INT:
6465         case TYP_UINT:
6466         case TYP_USHORT:
6467         case TYP_SHORT:
6468         case TYP_BYTE:
6469         case TYP_UBYTE:
6470         case TYP_BOOL:
6471             if (tree->IsCnsIntOrI() && tree->IsIconHandle())
6472             {
6473                 tree->gtVNPair.SetBoth(
6474                     vnStore->VNForHandle(ssize_t(tree->gtIntConCommon.IconValue()), tree->GetIconHandleFlag()));
6475             }
6476             else if ((typ == TYP_LONG) || (typ == TYP_ULONG))
6477             {
6478                 tree->gtVNPair.SetBoth(vnStore->VNForLongCon(INT64(tree->gtIntConCommon.LngValue())));
6479             }
6480             else
6481             {
6482                 tree->gtVNPair.SetBoth(vnStore->VNForIntCon(int(tree->gtIntConCommon.IconValue())));
6483             }
6484             break;
6485
6486         case TYP_FLOAT:
6487             tree->gtVNPair.SetBoth(vnStore->VNForFloatCon((float)tree->gtDblCon.gtDconVal));
6488             break;
6489         case TYP_DOUBLE:
6490             tree->gtVNPair.SetBoth(vnStore->VNForDoubleCon(tree->gtDblCon.gtDconVal));
6491             break;
6492         case TYP_REF:
6493             if (tree->gtIntConCommon.IconValue() == 0)
6494             {
6495                 tree->gtVNPair.SetBoth(ValueNumStore::VNForNull());
6496             }
6497             else
6498             {
6499                 assert(tree->gtFlags == GTF_ICON_STR_HDL); // Constant object can be only frozen string.
6500                 tree->gtVNPair.SetBoth(
6501                     vnStore->VNForHandle(ssize_t(tree->gtIntConCommon.IconValue()), tree->GetIconHandleFlag()));
6502             }
6503             break;
6504
6505         case TYP_BYREF:
6506             if (tree->gtIntConCommon.IconValue() == 0)
6507             {
6508                 tree->gtVNPair.SetBoth(ValueNumStore::VNForNull());
6509             }
6510             else
6511             {
6512                 assert(tree->IsCnsIntOrI());
6513
6514                 if (tree->IsIconHandle())
6515                 {
6516                     tree->gtVNPair.SetBoth(
6517                         vnStore->VNForHandle(ssize_t(tree->gtIntConCommon.IconValue()), tree->GetIconHandleFlag()));
6518                 }
6519                 else
6520                 {
6521                     tree->gtVNPair.SetBoth(vnStore->VNForByrefCon(tree->gtIntConCommon.IconValue()));
6522                 }
6523             }
6524             break;
6525
6526         default:
6527             unreached();
6528     }
6529 }
6530
6531 //------------------------------------------------------------------------
6532 // fgValueNumberBlockAssignment: Perform value numbering for block assignments.
6533 //
6534 // Arguments:
6535 //    tree          - the block assignment to be value numbered.
6536 //
6537 // Return Value:
6538 //    None.
6539 //
6540 // Assumptions:
6541 //    'tree' must be a block assignment (GT_INITBLK, GT_COPYBLK, GT_COPYOBJ).
6542
6543 void Compiler::fgValueNumberBlockAssignment(GenTree* tree)
6544 {
6545     GenTree* lhs = tree->gtGetOp1();
6546     GenTree* rhs = tree->gtGetOp2();
6547
6548     if (tree->OperIsInitBlkOp())
6549     {
6550         GenTreeLclVarCommon* lclVarTree;
6551         bool                 isEntire;
6552
6553         if (tree->DefinesLocal(this, &lclVarTree, &isEntire))
6554         {
6555             assert(lclVarTree->gtFlags & GTF_VAR_DEF);
6556             // Should not have been recorded as updating the GC heap.
6557             assert(!GetMemorySsaMap(GcHeap)->Lookup(tree));
6558
6559             unsigned lclNum = lclVarTree->GetLclNum();
6560
6561             // Ignore vars that we excluded from SSA (for example, because they're address-exposed). They don't have
6562             // SSA names in which to store VN's on defs.  We'll yield unique VN's when we read from them.
6563             if (lvaInSsa(lclNum))
6564             {
6565                 // Should not have been recorded as updating ByrefExposed.
6566                 assert(!GetMemorySsaMap(ByrefExposed)->Lookup(tree));
6567
6568                 unsigned lclDefSsaNum = GetSsaNumForLocalVarDef(lclVarTree);
6569
6570                 ValueNum initBlkVN = ValueNumStore::NoVN;
6571                 GenTree* initConst = rhs;
6572                 if (isEntire && initConst->OperGet() == GT_CNS_INT)
6573                 {
6574                     unsigned initVal = 0xFF & (unsigned)initConst->AsIntConCommon()->IconValue();
6575                     if (initVal == 0)
6576                     {
6577                         initBlkVN = vnStore->VNZeroForType(lclVarTree->TypeGet());
6578                     }
6579                 }
6580                 ValueNum lclVarVN = (initBlkVN != ValueNumStore::NoVN)
6581                                         ? initBlkVN
6582                                         : vnStore->VNForExpr(compCurBB, var_types(lvaTable[lclNum].lvType));
6583
6584                 lvaTable[lclNum].GetPerSsaData(lclDefSsaNum)->m_vnPair.SetBoth(lclVarVN);
6585 #ifdef DEBUG
6586                 if (verbose)
6587                 {
6588                     printf("N%03u ", tree->gtSeqNum);
6589                     Compiler::printTreeID(tree);
6590                     printf(" ");
6591                     gtDispNodeName(tree);
6592                     printf(" V%02u/%d => ", lclNum, lclDefSsaNum);
6593                     vnPrint(lclVarVN, 1);
6594                     printf("\n");
6595                 }
6596 #endif // DEBUG
6597             }
6598             else if (lvaVarAddrExposed(lclVarTree->gtLclNum))
6599             {
6600                 fgMutateAddressExposedLocal(tree DEBUGARG("INITBLK - address-exposed local"));
6601             }
6602         }
6603         else
6604         {
6605             // For now, arbitrary side effect on GcHeap/ByrefExposed.
6606             // TODO-CQ: Why not be complete, and get this case right?
6607             fgMutateGcHeap(tree DEBUGARG("INITBLK - non local"));
6608         }
6609         // Initblock's are of type void.  Give them the void "value" -- they may occur in argument lists, which we
6610         // want to be able to give VN's to.
6611         tree->gtVNPair.SetBoth(ValueNumStore::VNForVoid());
6612     }
6613     else
6614     {
6615         assert(tree->OperIsCopyBlkOp());
6616         // TODO-Cleanup: We should factor things so that we uniformly rely on "PtrTo" VN's, and
6617         // the memory cases can be shared with assignments.
6618         GenTreeLclVarCommon* lclVarTree = nullptr;
6619         bool                 isEntire   = false;
6620         // Note that we don't care about exceptions here, since we're only using the values
6621         // to perform an assignment (which happens after any exceptions are raised...)
6622
6623         if (tree->DefinesLocal(this, &lclVarTree, &isEntire))
6624         {
6625             // Should not have been recorded as updating the GC heap.
6626             assert(!GetMemorySsaMap(GcHeap)->Lookup(tree));
6627
6628             unsigned      lhsLclNum = lclVarTree->GetLclNum();
6629             FieldSeqNode* lhsFldSeq = nullptr;
6630             // If it's excluded from SSA, don't need to do anything.
6631             if (lvaInSsa(lhsLclNum))
6632             {
6633                 // Should not have been recorded as updating ByrefExposed.
6634                 assert(!GetMemorySsaMap(ByrefExposed)->Lookup(tree));
6635
6636                 unsigned lclDefSsaNum = GetSsaNumForLocalVarDef(lclVarTree);
6637
6638                 if (lhs->IsLocalExpr(this, &lclVarTree, &lhsFldSeq))
6639                 {
6640                     noway_assert(lclVarTree->gtLclNum == lhsLclNum);
6641                 }
6642                 else
6643                 {
6644                     GenTree* lhsAddr;
6645                     if (lhs->OperIsBlk())
6646                     {
6647                         lhsAddr = lhs->AsBlk()->Addr();
6648                     }
6649                     else
6650                     {
6651                         assert(lhs->OperGet() == GT_IND);
6652                         lhsAddr = lhs->gtOp.gtOp1;
6653                     }
6654
6655                     // For addr-of-local expressions, lib/cons shouldn't matter.
6656                     assert(lhsAddr->gtVNPair.BothEqual());
6657                     ValueNum lhsAddrVN = lhsAddr->GetVN(VNK_Liberal);
6658
6659                     // Unpack the PtrToLoc value number of the address.
6660                     assert(vnStore->IsVNFunc(lhsAddrVN));
6661
6662                     VNFuncApp lhsAddrFuncApp;
6663                     vnStore->GetVNFunc(lhsAddrVN, &lhsAddrFuncApp);
6664
6665                     assert(lhsAddrFuncApp.m_func == VNF_PtrToLoc);
6666                     assert(vnStore->IsVNConstant(lhsAddrFuncApp.m_args[0]) &&
6667                            vnStore->ConstantValue<unsigned>(lhsAddrFuncApp.m_args[0]) == lhsLclNum);
6668
6669                     lhsFldSeq = vnStore->FieldSeqVNToFieldSeq(lhsAddrFuncApp.m_args[1]);
6670                 }
6671
6672                 // Now we need to get the proper RHS.
6673                 GenTreeLclVarCommon* rhsLclVarTree = nullptr;
6674                 LclVarDsc*           rhsVarDsc     = nullptr;
6675                 FieldSeqNode*        rhsFldSeq     = nullptr;
6676                 ValueNumPair         rhsVNPair;
6677                 bool                 isNewUniq = false;
6678                 if (!rhs->OperIsIndir())
6679                 {
6680                     if (rhs->IsLocalExpr(this, &rhsLclVarTree, &rhsFldSeq))
6681                     {
6682                         unsigned rhsLclNum = rhsLclVarTree->GetLclNum();
6683                         rhsVarDsc          = &lvaTable[rhsLclNum];
6684                         if (!lvaInSsa(rhsLclNum) || rhsFldSeq == FieldSeqStore::NotAField())
6685                         {
6686                             rhsVNPair.SetBoth(vnStore->VNForExpr(compCurBB, rhsLclVarTree->TypeGet()));
6687                             isNewUniq = true;
6688                         }
6689                         else
6690                         {
6691                             rhsVNPair = lvaTable[rhsLclVarTree->GetLclNum()]
6692                                             .GetPerSsaData(rhsLclVarTree->GetSsaNum())
6693                                             ->m_vnPair;
6694                             var_types indType = rhsLclVarTree->TypeGet();
6695
6696                             rhsVNPair = vnStore->VNPairApplySelectors(rhsVNPair, rhsFldSeq, indType);
6697                         }
6698                     }
6699                     else
6700                     {
6701                         rhsVNPair.SetBoth(vnStore->VNForExpr(compCurBB, rhs->TypeGet()));
6702                         isNewUniq = true;
6703                     }
6704                 }
6705                 else
6706                 {
6707                     GenTree*  srcAddr = rhs->AsIndir()->Addr();
6708                     VNFuncApp srcAddrFuncApp;
6709                     if (srcAddr->IsLocalAddrExpr(this, &rhsLclVarTree, &rhsFldSeq))
6710                     {
6711                         unsigned rhsLclNum = rhsLclVarTree->GetLclNum();
6712                         rhsVarDsc          = &lvaTable[rhsLclNum];
6713                         if (!lvaInSsa(rhsLclNum) || rhsFldSeq == FieldSeqStore::NotAField())
6714                         {
6715                             isNewUniq = true;
6716                         }
6717                         else
6718                         {
6719                             rhsVNPair = lvaTable[rhsLclVarTree->GetLclNum()]
6720                                             .GetPerSsaData(rhsLclVarTree->GetSsaNum())
6721                                             ->m_vnPair;
6722                             var_types indType = rhsLclVarTree->TypeGet();
6723
6724                             rhsVNPair = vnStore->VNPairApplySelectors(rhsVNPair, rhsFldSeq, indType);
6725                         }
6726                     }
6727                     else if (vnStore->GetVNFunc(vnStore->VNLiberalNormalValue(srcAddr->gtVNPair), &srcAddrFuncApp))
6728                     {
6729                         if (srcAddrFuncApp.m_func == VNF_PtrToStatic)
6730                         {
6731                             var_types indType    = lclVarTree->TypeGet();
6732                             ValueNum  fieldSeqVN = srcAddrFuncApp.m_args[0];
6733
6734                             FieldSeqNode* zeroOffsetFldSeq = nullptr;
6735                             if (GetZeroOffsetFieldMap()->Lookup(srcAddr, &zeroOffsetFldSeq))
6736                             {
6737                                 fieldSeqVN =
6738                                     vnStore->FieldSeqVNAppend(fieldSeqVN, vnStore->VNForFieldSeq(zeroOffsetFldSeq));
6739                             }
6740
6741                             FieldSeqNode* fldSeqForStaticVar = vnStore->FieldSeqVNToFieldSeq(fieldSeqVN);
6742
6743                             if (fldSeqForStaticVar != FieldSeqStore::NotAField())
6744                             {
6745                                 // We model statics as indices into GcHeap (which is a subset of ByrefExposed).
6746                                 ValueNum selectedStaticVar;
6747                                 size_t   structSize = 0;
6748                                 selectedStaticVar   = vnStore->VNApplySelectors(VNK_Liberal, fgCurMemoryVN[GcHeap],
6749                                                                               fldSeqForStaticVar, &structSize);
6750                                 selectedStaticVar =
6751                                     vnStore->VNApplySelectorsTypeCheck(selectedStaticVar, indType, structSize);
6752
6753                                 rhsVNPair.SetLiberal(selectedStaticVar);
6754                                 rhsVNPair.SetConservative(vnStore->VNForExpr(compCurBB, indType));
6755                             }
6756                             else
6757                             {
6758                                 JITDUMP("    *** Missing field sequence info for Src/RHS of COPYBLK\n");
6759                                 isNewUniq = true;
6760                             }
6761                         }
6762                         else if (srcAddrFuncApp.m_func == VNF_PtrToArrElem)
6763                         {
6764                             ValueNum elemLib =
6765                                 fgValueNumberArrIndexVal(nullptr, &srcAddrFuncApp, vnStore->VNForEmptyExcSet());
6766                             rhsVNPair.SetLiberal(elemLib);
6767                             rhsVNPair.SetConservative(vnStore->VNForExpr(compCurBB, lclVarTree->TypeGet()));
6768                         }
6769                         else
6770                         {
6771                             isNewUniq = true;
6772                         }
6773                     }
6774                     else
6775                     {
6776                         isNewUniq = true;
6777                     }
6778                 }
6779
6780                 if (lhsFldSeq == FieldSeqStore::NotAField())
6781                 {
6782                     // We don't have proper field sequence information for the lhs
6783                     //
6784                     JITDUMP("    *** Missing field sequence info for Dst/LHS of COPYBLK\n");
6785                     isNewUniq = true;
6786                 }
6787
6788                 if (isNewUniq)
6789                 {
6790                     rhsVNPair.SetBoth(vnStore->VNForExpr(compCurBB, lclVarTree->TypeGet()));
6791                 }
6792                 else // We will assign rhsVNPair into a map[lhsFldSeq]
6793                 {
6794                     if (lhsFldSeq != nullptr && isEntire)
6795                     {
6796                         // This can occur for structs with one field, itself of a struct type.
6797                         // We are assigning the one field and it is also the entire enclosing struct.
6798                         //
6799                         // Use an unique value number for the old map, as this is an an entire assignment
6800                         // and we won't have any other values in the map
6801                         ValueNumPair uniqueMap;
6802                         uniqueMap.SetBoth(vnStore->VNForExpr(compCurBB, lclVarTree->TypeGet()));
6803                         rhsVNPair = vnStore->VNPairApplySelectorsAssign(uniqueMap, lhsFldSeq, rhsVNPair,
6804                                                                         lclVarTree->TypeGet(), compCurBB);
6805                     }
6806                     else
6807                     {
6808                         ValueNumPair oldLhsVNPair =
6809                             lvaTable[lhsLclNum].GetPerSsaData(lclVarTree->GetSsaNum())->m_vnPair;
6810                         rhsVNPair = vnStore->VNPairApplySelectorsAssign(oldLhsVNPair, lhsFldSeq, rhsVNPair,
6811                                                                         lclVarTree->TypeGet(), compCurBB);
6812                     }
6813                 }
6814
6815                 lvaTable[lhsLclNum].GetPerSsaData(lclDefSsaNum)->m_vnPair = vnStore->VNPNormalPair(rhsVNPair);
6816
6817 #ifdef DEBUG
6818                 if (verbose)
6819                 {
6820                     printf("Tree ");
6821                     Compiler::printTreeID(tree);
6822                     printf(" assigned VN to local var V%02u/%d: ", lhsLclNum, lclDefSsaNum);
6823                     if (isNewUniq)
6824                     {
6825                         printf("new uniq ");
6826                     }
6827                     vnpPrint(rhsVNPair, 1);
6828                     printf("\n");
6829                 }
6830 #endif // DEBUG
6831             }
6832             else if (lvaVarAddrExposed(lhsLclNum))
6833             {
6834                 fgMutateAddressExposedLocal(tree DEBUGARG("COPYBLK - address-exposed local"));
6835             }
6836         }
6837         else
6838         {
6839             // For now, arbitrary side effect on GcHeap/ByrefExposed.
6840             // TODO-CQ: Why not be complete, and get this case right?
6841             fgMutateGcHeap(tree DEBUGARG("COPYBLK - non local"));
6842         }
6843         // Copyblock's are of type void.  Give them the void "value" -- they may occur in argument lists, which we want
6844         // to be able to give VN's to.
6845         tree->gtVNPair.SetBoth(ValueNumStore::VNForVoid());
6846     }
6847 }
6848
6849 void Compiler::fgValueNumberTree(GenTree* tree)
6850 {
6851     genTreeOps oper = tree->OperGet();
6852
6853 #ifdef FEATURE_SIMD
6854     // TODO-CQ: For now TYP_SIMD values are not handled by value numbering to be amenable for CSE'ing.
6855     if (oper == GT_SIMD)
6856     {
6857         tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, TYP_UNKNOWN));
6858         return;
6859     }
6860 #endif
6861
6862 #ifdef FEATURE_HW_INTRINSICS
6863     if (oper == GT_HWIntrinsic)
6864     {
6865         // TODO-CQ: For now hardware intrinsics are not handled by value numbering to be amenable for CSE'ing.
6866         tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, TYP_UNKNOWN));
6867
6868         GenTreeHWIntrinsic* hwIntrinsicNode = tree->AsHWIntrinsic();
6869         assert(hwIntrinsicNode != nullptr);
6870
6871         // For safety/correctness we must mutate the global heap valuenumber
6872         //  for any HW intrinsic that performs a memory store operation
6873         if (hwIntrinsicNode->OperIsMemoryStore())
6874         {
6875             fgMutateGcHeap(tree DEBUGARG("HWIntrinsic - MemoryStore"));
6876         }
6877
6878         return;
6879     }
6880 #endif // FEATURE_HW_INTRINSICS
6881
6882     var_types typ = tree->TypeGet();
6883     if (GenTree::OperIsConst(oper))
6884     {
6885         // If this is a struct assignment, with a constant rhs, it is an initBlk, and it is not
6886         // really useful to value number the constant.
6887         if (!varTypeIsStruct(tree))
6888         {
6889             fgValueNumberTreeConst(tree);
6890         }
6891     }
6892     else if (GenTree::OperIsLeaf(oper))
6893     {
6894         switch (oper)
6895         {
6896             case GT_LCL_VAR:
6897             {
6898                 GenTreeLclVarCommon* lcl    = tree->AsLclVarCommon();
6899                 unsigned             lclNum = lcl->gtLclNum;
6900                 LclVarDsc*           varDsc = &lvaTable[lclNum];
6901
6902                 // Do we have a Use (read) of the LclVar?
6903                 //
6904                 if ((lcl->gtFlags & GTF_VAR_DEF) == 0 ||
6905                     (lcl->gtFlags & GTF_VAR_USEASG)) // If it is a "pure" def, will handled as part of the assignment.
6906                 {
6907                     bool          generateUniqueVN = false;
6908                     FieldSeqNode* zeroOffsetFldSeq = nullptr;
6909
6910                     // When we have a TYP_BYREF LclVar it can have a zero offset field sequence that needs to be added
6911                     if (typ == TYP_BYREF)
6912                     {
6913                         GetZeroOffsetFieldMap()->Lookup(tree, &zeroOffsetFldSeq);
6914                     }
6915
6916                     if (varDsc->lvPromoted && varDsc->lvFieldCnt == 1)
6917                     {
6918                         // If the promoted var has only one field var, treat like a use of the field var.
6919                         lclNum = varDsc->lvFieldLclStart;
6920                     }
6921
6922                     if (lcl->gtSsaNum == SsaConfig::RESERVED_SSA_NUM)
6923                     {
6924                         // Not an SSA variable.
6925
6926                         if (lvaVarAddrExposed(lclNum))
6927                         {
6928                             // Address-exposed locals are part of ByrefExposed.
6929                             ValueNum addrVN = vnStore->VNForFunc(TYP_BYREF, VNF_PtrToLoc, vnStore->VNForIntCon(lclNum),
6930                                                                  vnStore->VNForFieldSeq(nullptr));
6931                             ValueNum loadVN = fgValueNumberByrefExposedLoad(typ, addrVN);
6932
6933                             lcl->gtVNPair.SetBoth(loadVN);
6934                         }
6935                         else
6936                         {
6937                             // Assign odd cases a new, unique, VN.
6938                             generateUniqueVN = true;
6939                         }
6940                     }
6941                     else
6942                     {
6943                         ValueNumPair wholeLclVarVNP = varDsc->GetPerSsaData(lcl->gtSsaNum)->m_vnPair;
6944
6945                         // Check for mismatched LclVar size
6946                         //
6947                         unsigned typSize = genTypeSize(genActualType(typ));
6948                         unsigned varSize = genTypeSize(genActualType(varDsc->TypeGet()));
6949
6950                         if (typSize == varSize)
6951                         {
6952                             lcl->gtVNPair = wholeLclVarVNP;
6953                         }
6954                         else // mismatched LclVar definition and LclVar use size
6955                         {
6956                             if (typSize < varSize)
6957                             {
6958                                 // the indirection is reading less that the whole LclVar
6959                                 // create a new VN that represent the partial value
6960                                 //
6961                                 ValueNumPair partialLclVarVNP =
6962                                     vnStore->VNPairForCast(wholeLclVarVNP, typ, varDsc->TypeGet());
6963                                 lcl->gtVNPair = partialLclVarVNP;
6964                             }
6965                             else
6966                             {
6967                                 assert(typSize > varSize);
6968                                 // the indirection is reading beyond the end of the field
6969                                 //
6970                                 generateUniqueVN = true;
6971                             }
6972                         }
6973                     }
6974
6975                     if (!generateUniqueVN)
6976                     {
6977                         // There are a couple of cases where we haven't assigned a valid value number to 'lcl'
6978                         //
6979                         if (lcl->gtVNPair.GetLiberal() == ValueNumStore::NoVN)
6980                         {
6981                             // So far, we know about two of these cases:
6982                             // Case 1) We have a local var who has never been defined but it's seen as a use.
6983                             //         This is the case of storeIndir(addr(lclvar)) = expr.  In this case since we only
6984                             //         take the address of the variable, this doesn't mean it's a use nor we have to
6985                             //         initialize it, so in this very rare case, we fabricate a value number.
6986                             // Case 2) Local variables that represent structs which are assigned using CpBlk.
6987                             //
6988                             // Make sure we have either case 1 or case 2
6989                             //
6990                             GenTree* nextNode = lcl->gtNext;
6991                             assert((nextNode->gtOper == GT_ADDR && nextNode->gtOp.gtOp1 == lcl) ||
6992                                    varTypeIsStruct(lcl->TypeGet()));
6993
6994                             // We will assign a unique value number for these
6995                             //
6996                             generateUniqueVN = true;
6997                         }
6998                     }
6999
7000                     if (!generateUniqueVN && (zeroOffsetFldSeq != nullptr))
7001                     {
7002                         ValueNum addrExtended = vnStore->ExtendPtrVN(lcl, zeroOffsetFldSeq);
7003                         if (addrExtended != ValueNumStore::NoVN)
7004                         {
7005                             lcl->gtVNPair.SetBoth(addrExtended);
7006                         }
7007                     }
7008
7009                     if (generateUniqueVN)
7010                     {
7011                         ValueNum uniqVN = vnStore->VNForExpr(compCurBB, lcl->TypeGet());
7012                         lcl->gtVNPair.SetBoth(uniqVN);
7013                     }
7014                 }
7015                 else if ((lcl->gtFlags & GTF_VAR_DEF) != 0)
7016                 {
7017                     // We have a Def (write) of the LclVar
7018
7019                     // TODO-Review: For the short term, we have a workaround for copyblk/initblk.  Those that use
7020                     // addrSpillTemp will have a statement like "addrSpillTemp = addr(local)."  If we previously decided
7021                     // that this block operation defines the local, we will have labeled the "local" node as a DEF
7022                     // This flag propagates to the "local" on the RHS.  So we'll assume that this is correct,
7023                     // and treat it as a def (to a new, unique VN).
7024                     //
7025                     if (lcl->gtSsaNum != SsaConfig::RESERVED_SSA_NUM)
7026                     {
7027                         ValueNum uniqVN = vnStore->VNForExpr(compCurBB, lcl->TypeGet());
7028                         varDsc->GetPerSsaData(lcl->gtSsaNum)->m_vnPair.SetBoth(uniqVN);
7029                     }
7030
7031                     lcl->gtVNPair = ValueNumPair(); // Avoid confusion -- we don't set the VN of a lcl being defined.
7032                 }
7033             }
7034             break;
7035
7036             case GT_FTN_ADDR:
7037                 // Use the value of the function pointer (actually, a method handle.)
7038                 tree->gtVNPair.SetBoth(
7039                     vnStore->VNForHandle(ssize_t(tree->gtFptrVal.gtFptrMethod), GTF_ICON_METHOD_HDL));
7040                 break;
7041
7042             // This group passes through a value from a child node.
7043             case GT_RET_EXPR:
7044                 tree->SetVNsFromNode(tree->gtRetExpr.gtInlineCandidate);
7045                 break;
7046
7047             case GT_LCL_FLD:
7048             {
7049                 GenTreeLclFld* lclFld = tree->AsLclFld();
7050                 assert(!lvaInSsa(lclFld->GetLclNum()) || lclFld->gtFieldSeq != nullptr);
7051                 // If this is a (full) def, then the variable will be labeled with the new SSA number,
7052                 // which will not have a value.  We skip; it will be handled by one of the assignment-like
7053                 // forms (assignment, or initBlk or copyBlk).
7054                 if (((lclFld->gtFlags & GTF_VAR_DEF) == 0) || (lclFld->gtFlags & GTF_VAR_USEASG))
7055                 {
7056                     unsigned   lclNum = lclFld->GetLclNum();
7057                     unsigned   ssaNum = lclFld->GetSsaNum();
7058                     LclVarDsc* varDsc = &lvaTable[lclNum];
7059
7060                     var_types indType = tree->TypeGet();
7061                     if (lclFld->gtFieldSeq == FieldSeqStore::NotAField() || !lvaInSsa(lclFld->GetLclNum()))
7062                     {
7063                         // This doesn't represent a proper field access or it's a struct
7064                         // with overlapping fields that is hard to reason about; return a new unique VN.
7065                         tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, indType));
7066                     }
7067                     else
7068                     {
7069                         ValueNumPair lclVNPair = varDsc->GetPerSsaData(ssaNum)->m_vnPair;
7070                         tree->gtVNPair         = vnStore->VNPairApplySelectors(lclVNPair, lclFld->gtFieldSeq, indType);
7071                     }
7072                 }
7073             }
7074             break;
7075
7076             // The ones below here all get a new unique VN -- but for various reasons, explained after each.
7077             case GT_CATCH_ARG:
7078                 // We know nothing about the value of a caught expression.
7079                 tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
7080                 break;
7081
7082             case GT_CLS_VAR:
7083                 // Skip GT_CLS_VAR nodes that are the LHS of an assignment.  (We labeled these earlier.)
7084                 // We will "evaluate" this as part of the assignment.
7085                 //
7086                 if ((tree->gtFlags & GTF_CLS_VAR_ASG_LHS) == 0)
7087                 {
7088                     bool isVolatile = (tree->gtFlags & GTF_FLD_VOLATILE) != 0;
7089
7090                     if (isVolatile)
7091                     {
7092                         // For Volatile indirection, first mutate GcHeap/ByrefExposed
7093                         fgMutateGcHeap(tree DEBUGARG("GTF_FLD_VOLATILE - read"));
7094                     }
7095
7096                     // We just mutate GcHeap/ByrefExposed if isVolatile is true, and then do the read as normal.
7097                     //
7098                     // This allows:
7099                     //   1: read s;
7100                     //   2: volatile read s;
7101                     //   3: read s;
7102                     //
7103                     // We should never assume that the values read by 1 and 2 are the same (because the heap was mutated
7104                     // in between them)... but we *should* be able to prove that the values read in 2 and 3 are the
7105                     // same.
7106                     //
7107
7108                     ValueNumPair clsVarVNPair;
7109
7110                     // If the static field handle is for a struct type field, then the value of the static
7111                     // is a "ref" to the boxed struct -- treat it as the address of the static (we assume that a
7112                     // first element offset will be added to get to the actual struct...)
7113                     GenTreeClsVar* clsVar = tree->AsClsVar();
7114                     FieldSeqNode*  fldSeq = clsVar->gtFieldSeq;
7115                     assert(fldSeq != nullptr); // We need to have one.
7116                     ValueNum selectedStaticVar = ValueNumStore::NoVN;
7117                     if (gtIsStaticFieldPtrToBoxedStruct(clsVar->TypeGet(), fldSeq->m_fieldHnd))
7118                     {
7119                         clsVarVNPair.SetBoth(
7120                             vnStore->VNForFunc(TYP_BYREF, VNF_PtrToStatic, vnStore->VNForFieldSeq(fldSeq)));
7121                     }
7122                     else
7123                     {
7124                         // This is a reference to heap memory.
7125                         // We model statics as indices into GcHeap (which is a subset of ByrefExposed).
7126
7127                         FieldSeqNode* fldSeqForStaticVar =
7128                             GetFieldSeqStore()->CreateSingleton(tree->gtClsVar.gtClsVarHnd);
7129                         size_t structSize = 0;
7130                         selectedStaticVar = vnStore->VNApplySelectors(VNK_Liberal, fgCurMemoryVN[GcHeap],
7131                                                                       fldSeqForStaticVar, &structSize);
7132                         selectedStaticVar =
7133                             vnStore->VNApplySelectorsTypeCheck(selectedStaticVar, tree->TypeGet(), structSize);
7134
7135                         clsVarVNPair.SetLiberal(selectedStaticVar);
7136                         // The conservative interpretation always gets a new, unique VN.
7137                         clsVarVNPair.SetConservative(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
7138                     }
7139
7140                     // The ValueNum returned must represent the full-sized IL-Stack value
7141                     // If we need to widen this value then we need to introduce a VNF_Cast here to represent
7142                     // the widened value.    This is necessary since the CSE package can replace all occurances
7143                     // of a given ValueNum with a LclVar that is a full-sized IL-Stack value
7144                     //
7145                     if (varTypeIsSmall(tree->TypeGet()))
7146                     {
7147                         var_types castToType = tree->TypeGet();
7148                         clsVarVNPair         = vnStore->VNPairForCast(clsVarVNPair, castToType, castToType);
7149                     }
7150                     tree->gtVNPair = clsVarVNPair;
7151                 }
7152                 break;
7153
7154             case GT_MEMORYBARRIER: // Leaf
7155                 // For MEMORYBARRIER add an arbitrary side effect on GcHeap/ByrefExposed.
7156                 fgMutateGcHeap(tree DEBUGARG("MEMORYBARRIER"));
7157                 break;
7158
7159             // These do not represent values.
7160             case GT_NO_OP:
7161             case GT_JMP:   // Control flow
7162             case GT_LABEL: // Control flow
7163 #if !FEATURE_EH_FUNCLETS
7164             case GT_END_LFIN: // Control flow
7165 #endif
7166             case GT_ARGPLACE:
7167                 // This node is a standin for an argument whose value will be computed later.  (Perhaps it's
7168                 // a register argument, and we don't want to preclude use of the register in arg evaluation yet.)
7169                 // We give this a "fake" value number now; if the call in which it occurs cares about the
7170                 // value (e.g., it's a helper call whose result is a function of argument values) we'll reset
7171                 // this later, when the later args have been assigned VNs.
7172                 tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
7173                 break;
7174
7175             case GT_PHI_ARG:
7176                 // This one is special because we should never process it in this method: it should
7177                 // always be taken care of, when needed, during pre-processing of a blocks phi definitions.
7178                 assert(false);
7179                 break;
7180
7181             default:
7182                 unreached();
7183         }
7184     }
7185     else if (GenTree::OperIsSimple(oper))
7186     {
7187 #ifdef DEBUG
7188         // Sometimes we query the memory ssa map in an assertion, and need a dummy location for the ignored result.
7189         unsigned memorySsaNum;
7190 #endif
7191
7192         if ((oper == GT_ASG) && !varTypeIsStruct(tree))
7193         {
7194             GenTree* lhs = tree->gtOp.gtOp1;
7195             GenTree* rhs = tree->gtOp.gtOp2;
7196
7197             ValueNumPair rhsVNPair = rhs->gtVNPair;
7198
7199             // Is the type being stored different from the type computed by the rhs?
7200             if (rhs->TypeGet() != lhs->TypeGet())
7201             {
7202                 // This means that there is an implicit cast on the rhs value
7203                 //
7204                 // We will add a cast function to reflect the possible narrowing of the rhs value
7205                 //
7206                 var_types castToType   = lhs->TypeGet();
7207                 var_types castFromType = rhs->TypeGet();
7208                 bool      isUnsigned   = varTypeIsUnsigned(castFromType);
7209
7210                 rhsVNPair = vnStore->VNPairForCast(rhsVNPair, castToType, castFromType, isUnsigned);
7211             }
7212
7213             if (tree->TypeGet() != TYP_VOID)
7214             {
7215                 // Assignment operators, as expressions, return the value of the RHS.
7216                 tree->gtVNPair = rhsVNPair;
7217             }
7218
7219             // Now that we've labeled the assignment as a whole, we don't care about exceptions.
7220             rhsVNPair = vnStore->VNPNormalPair(rhsVNPair);
7221
7222             // Record the exeception set for this 'tree' in vnExcSet.
7223             // First we'll record the exeception set for the rhs and
7224             // later we will union in the exeception set for the lhs
7225             //
7226             ValueNum vnExcSet;
7227
7228             // Unpack, Norm,Exc for 'rhsVNPair'
7229             ValueNum vnRhsLibNorm;
7230             vnStore->VNUnpackExc(rhsVNPair.GetLiberal(), &vnRhsLibNorm, &vnExcSet);
7231
7232             // Now that we've saved the rhs exeception set, we we will use the normal values.
7233             rhsVNPair = ValueNumPair(vnRhsLibNorm, vnStore->VNNormalValue(rhsVNPair.GetConservative()));
7234
7235             // If the types of the rhs and lhs are different then we
7236             //  may want to change the ValueNumber assigned to the lhs.
7237             //
7238             if (rhs->TypeGet() != lhs->TypeGet())
7239             {
7240                 if (rhs->TypeGet() == TYP_REF)
7241                 {
7242                     // If we have an unsafe IL assignment of a TYP_REF to a non-ref (typically a TYP_BYREF)
7243                     // then don't propagate this ValueNumber to the lhs, instead create a new unique VN
7244                     //
7245                     rhsVNPair.SetBoth(vnStore->VNForExpr(compCurBB, lhs->TypeGet()));
7246                 }
7247             }
7248
7249             // We have to handle the case where the LHS is a comma.  In that case, we don't evaluate the comma,
7250             // so we give it VNForVoid, and we're really interested in the effective value.
7251             GenTree* lhsCommaIter = lhs;
7252             while (lhsCommaIter->OperGet() == GT_COMMA)
7253             {
7254                 lhsCommaIter->gtVNPair.SetBoth(vnStore->VNForVoid());
7255                 lhsCommaIter = lhsCommaIter->gtOp.gtOp2;
7256             }
7257             lhs = lhs->gtEffectiveVal();
7258
7259             // Now, record the new VN for an assignment (performing the indicated "state update").
7260             // It's safe to use gtEffectiveVal here, because the non-last elements of a comma list on the
7261             // LHS will come before the assignment in evaluation order.
7262             switch (lhs->OperGet())
7263             {
7264                 case GT_LCL_VAR:
7265                 {
7266                     GenTreeLclVarCommon* lcl          = lhs->AsLclVarCommon();
7267                     unsigned             lclDefSsaNum = GetSsaNumForLocalVarDef(lcl);
7268
7269                     // Should not have been recorded as updating the GC heap.
7270                     assert(!GetMemorySsaMap(GcHeap)->Lookup(tree, &memorySsaNum));
7271
7272                     if (lclDefSsaNum != SsaConfig::RESERVED_SSA_NUM)
7273                     {
7274                         // Should not have been recorded as updating ByrefExposed mem.
7275                         assert(!GetMemorySsaMap(ByrefExposed)->Lookup(tree, &memorySsaNum));
7276
7277                         assert(rhsVNPair.GetLiberal() != ValueNumStore::NoVN);
7278
7279                         lhs->gtVNPair                                                 = rhsVNPair;
7280                         lvaTable[lcl->gtLclNum].GetPerSsaData(lclDefSsaNum)->m_vnPair = rhsVNPair;
7281
7282 #ifdef DEBUG
7283                         if (verbose)
7284                         {
7285                             printf("N%03u ", lhs->gtSeqNum);
7286                             Compiler::printTreeID(lhs);
7287                             printf(" ");
7288                             gtDispNodeName(lhs);
7289                             gtDispLeaf(lhs, nullptr);
7290                             printf(" => ");
7291                             vnpPrint(lhs->gtVNPair, 1);
7292                             printf("\n");
7293                         }
7294 #endif // DEBUG
7295                     }
7296                     else if (lvaVarAddrExposed(lcl->gtLclNum))
7297                     {
7298                         // We could use MapStore here and MapSelect on reads of address-exposed locals
7299                         // (using the local nums as selectors) to get e.g. propagation of values
7300                         // through address-taken locals in regions of code with no calls or byref
7301                         // writes.
7302                         // For now, just use a new opaque VN.
7303                         ValueNum heapVN = vnStore->VNForExpr(compCurBB);
7304                         recordAddressExposedLocalStore(tree, heapVN DEBUGARG("local assign"));
7305                     }
7306 #ifdef DEBUG
7307                     else
7308                     {
7309                         if (verbose)
7310                         {
7311                             JITDUMP("Tree ");
7312                             Compiler::printTreeID(tree);
7313                             printf(" assigns to non-address-taken local var V%02u; excluded from SSA, so value not "
7314                                    "tracked.\n",
7315                                    lcl->GetLclNum());
7316                         }
7317                     }
7318 #endif // DEBUG
7319                 }
7320                 break;
7321                 case GT_LCL_FLD:
7322                 {
7323                     GenTreeLclFld* lclFld       = lhs->AsLclFld();
7324                     unsigned       lclDefSsaNum = GetSsaNumForLocalVarDef(lclFld);
7325
7326                     // Should not have been recorded as updating the GC heap.
7327                     assert(!GetMemorySsaMap(GcHeap)->Lookup(tree, &memorySsaNum));
7328
7329                     if (lclDefSsaNum != SsaConfig::RESERVED_SSA_NUM)
7330                     {
7331                         ValueNumPair newLhsVNPair;
7332                         // Is this a full definition?
7333                         if ((lclFld->gtFlags & GTF_VAR_USEASG) == 0)
7334                         {
7335                             assert(!lclFld->IsPartialLclFld(this));
7336                             assert(rhsVNPair.GetLiberal() != ValueNumStore::NoVN);
7337                             newLhsVNPair = rhsVNPair;
7338                         }
7339                         else
7340                         {
7341                             // We should never have a null field sequence here.
7342                             assert(lclFld->gtFieldSeq != nullptr);
7343                             if (lclFld->gtFieldSeq == FieldSeqStore::NotAField())
7344                             {
7345                                 // We don't know what field this represents.  Assign a new VN to the whole variable
7346                                 // (since we may be writing to an unknown portion of it.)
7347                                 newLhsVNPair.SetBoth(vnStore->VNForExpr(compCurBB, lvaGetActualType(lclFld->gtLclNum)));
7348                             }
7349                             else
7350                             {
7351                                 // We do know the field sequence.
7352                                 // The "lclFld" node will be labeled with the SSA number of its "use" identity
7353                                 // (we looked in a side table above for its "def" identity).  Look up that value.
7354                                 ValueNumPair oldLhsVNPair =
7355                                     lvaTable[lclFld->GetLclNum()].GetPerSsaData(lclFld->GetSsaNum())->m_vnPair;
7356                                 newLhsVNPair = vnStore->VNPairApplySelectorsAssign(oldLhsVNPair, lclFld->gtFieldSeq,
7357                                                                                    rhsVNPair, // Pre-value.
7358                                                                                    lclFld->TypeGet(), compCurBB);
7359                             }
7360                         }
7361                         lvaTable[lclFld->GetLclNum()].GetPerSsaData(lclDefSsaNum)->m_vnPair = newLhsVNPair;
7362                         lhs->gtVNPair                                                       = newLhsVNPair;
7363 #ifdef DEBUG
7364                         if (verbose)
7365                         {
7366                             if (lhs->gtVNPair.GetLiberal() != ValueNumStore::NoVN)
7367                             {
7368                                 printf("N%03u ", lhs->gtSeqNum);
7369                                 Compiler::printTreeID(lhs);
7370                                 printf(" ");
7371                                 gtDispNodeName(lhs);
7372                                 gtDispLeaf(lhs, nullptr);
7373                                 printf(" => ");
7374                                 vnpPrint(lhs->gtVNPair, 1);
7375                                 printf("\n");
7376                             }
7377                         }
7378 #endif // DEBUG
7379                     }
7380                     else if (lvaVarAddrExposed(lclFld->gtLclNum))
7381                     {
7382                         // This side-effects ByrefExposed.  Just use a new opaque VN.
7383                         // As with GT_LCL_VAR, we could probably use MapStore here and MapSelect at corresponding
7384                         // loads, but to do so would have to identify the subset of address-exposed locals
7385                         // whose fields can be disambiguated.
7386                         ValueNum heapVN = vnStore->VNForExpr(compCurBB);
7387                         recordAddressExposedLocalStore(tree, heapVN DEBUGARG("local field assign"));
7388                     }
7389                 }
7390                 break;
7391
7392                 case GT_PHI_ARG:
7393                     noway_assert(!"Phi arg cannot be LHS.");
7394                     break;
7395
7396                 case GT_BLK:
7397                 case GT_OBJ:
7398                     noway_assert(!"GT_BLK/GT_OBJ can not be LHS when !varTypeIsStruct(tree) is true!");
7399                     break;
7400
7401                 case GT_IND:
7402                 {
7403                     bool isVolatile = (lhs->gtFlags & GTF_IND_VOLATILE) != 0;
7404
7405                     if (isVolatile)
7406                     {
7407                         // For Volatile store indirection, first mutate GcHeap/ByrefExposed
7408                         fgMutateGcHeap(lhs DEBUGARG("GTF_IND_VOLATILE - store"));
7409                         tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, lhs->TypeGet()));
7410                     }
7411
7412                     GenTree* arg = lhs->gtOp.gtOp1;
7413
7414                     // Indicates whether the argument of the IND is the address of a local.
7415                     bool wasLocal = false;
7416
7417                     lhs->gtVNPair = rhsVNPair;
7418
7419                     VNFuncApp funcApp;
7420                     ValueNum  argVN = arg->gtVNPair.GetLiberal();
7421
7422                     bool argIsVNFunc = vnStore->GetVNFunc(vnStore->VNNormalValue(argVN), &funcApp);
7423
7424                     // Is this an assignment to a (field of, perhaps) a local?
7425                     // If it is a PtrToLoc, lib and cons VNs will be the same.
7426                     if (argIsVNFunc)
7427                     {
7428                         if (funcApp.m_func == VNF_PtrToLoc)
7429                         {
7430                             assert(arg->gtVNPair.BothEqual()); // If it's a PtrToLoc, lib/cons shouldn't differ.
7431                             assert(vnStore->IsVNConstant(funcApp.m_args[0]));
7432                             unsigned lclNum = vnStore->ConstantValue<unsigned>(funcApp.m_args[0]);
7433
7434                             wasLocal = true;
7435
7436                             if (lvaInSsa(lclNum))
7437                             {
7438                                 FieldSeqNode* fieldSeq = vnStore->FieldSeqVNToFieldSeq(funcApp.m_args[1]);
7439
7440                                 // Either "arg" is the address of (part of) a local itself, or else we have
7441                                 // a "rogue" PtrToLoc, one that should have made the local in question
7442                                 // address-exposed.  Assert on that.
7443                                 GenTreeLclVarCommon* lclVarTree   = nullptr;
7444                                 bool                 isEntire     = false;
7445                                 unsigned             lclDefSsaNum = SsaConfig::RESERVED_SSA_NUM;
7446                                 ValueNumPair         newLhsVNPair;
7447
7448                                 if (arg->DefinesLocalAddr(this, genTypeSize(lhs->TypeGet()), &lclVarTree, &isEntire))
7449                                 {
7450                                     // The local #'s should agree.
7451                                     assert(lclNum == lclVarTree->GetLclNum());
7452
7453                                     if (fieldSeq == FieldSeqStore::NotAField())
7454                                     {
7455                                         // We don't know where we're storing, so give the local a new, unique VN.
7456                                         // Do this by considering it an "entire" assignment, with an unknown RHS.
7457                                         isEntire = true;
7458                                         rhsVNPair.SetBoth(vnStore->VNForExpr(compCurBB, lclVarTree->TypeGet()));
7459                                     }
7460
7461                                     if (isEntire)
7462                                     {
7463                                         newLhsVNPair = rhsVNPair;
7464                                         lclDefSsaNum = lclVarTree->GetSsaNum();
7465                                     }
7466                                     else
7467                                     {
7468                                         // Don't use the lclVarTree's VN: if it's a local field, it will
7469                                         // already be dereferenced by it's field sequence.
7470                                         ValueNumPair oldLhsVNPair = lvaTable[lclVarTree->GetLclNum()]
7471                                                                         .GetPerSsaData(lclVarTree->GetSsaNum())
7472                                                                         ->m_vnPair;
7473                                         lclDefSsaNum = GetSsaNumForLocalVarDef(lclVarTree);
7474                                         newLhsVNPair =
7475                                             vnStore->VNPairApplySelectorsAssign(oldLhsVNPair, fieldSeq, rhsVNPair,
7476                                                                                 lhs->TypeGet(), compCurBB);
7477                                     }
7478                                     lvaTable[lclNum].GetPerSsaData(lclDefSsaNum)->m_vnPair = newLhsVNPair;
7479                                 }
7480                                 else
7481                                 {
7482                                     unreached(); // "Rogue" PtrToLoc, as discussed above.
7483                                 }
7484 #ifdef DEBUG
7485                                 if (verbose)
7486                                 {
7487                                     printf("Tree ");
7488                                     Compiler::printTreeID(tree);
7489                                     printf(" assigned VN to local var V%02u/%d: VN ", lclNum, lclDefSsaNum);
7490                                     vnpPrint(newLhsVNPair, 1);
7491                                     printf("\n");
7492                                 }
7493 #endif // DEBUG
7494                             }
7495                             else if (lvaVarAddrExposed(lclNum))
7496                             {
7497                                 // Need to record the effect on ByrefExposed.
7498                                 // We could use MapStore here and MapSelect on reads of address-exposed locals
7499                                 // (using the local nums as selectors) to get e.g. propagation of values
7500                                 // through address-taken locals in regions of code with no calls or byref
7501                                 // writes.
7502                                 // For now, just use a new opaque VN.
7503                                 ValueNum heapVN = vnStore->VNForExpr(compCurBB);
7504                                 recordAddressExposedLocalStore(tree, heapVN DEBUGARG("PtrToLoc indir"));
7505                             }
7506                         }
7507                     }
7508
7509                     // Was the argument of the GT_IND the address of a local, handled above?
7510                     if (!wasLocal)
7511                     {
7512                         GenTree*      obj          = nullptr;
7513                         GenTree*      staticOffset = nullptr;
7514                         FieldSeqNode* fldSeq       = nullptr;
7515
7516                         // Is the LHS an array index expression?
7517                         if (argIsVNFunc && funcApp.m_func == VNF_PtrToArrElem)
7518                         {
7519                             CORINFO_CLASS_HANDLE elemTypeEq =
7520                                 CORINFO_CLASS_HANDLE(vnStore->ConstantValue<ssize_t>(funcApp.m_args[0]));
7521                             ValueNum      arrVN  = funcApp.m_args[1];
7522                             ValueNum      inxVN  = funcApp.m_args[2];
7523                             FieldSeqNode* fldSeq = vnStore->FieldSeqVNToFieldSeq(funcApp.m_args[3]);
7524
7525                             if (arg->gtOper != GT_LCL_VAR)
7526                             {
7527                                 // Does the child of the GT_IND 'arg' have an associated zero-offset field sequence?
7528                                 FieldSeqNode* addrFieldSeq = nullptr;
7529                                 if (GetZeroOffsetFieldMap()->Lookup(arg, &addrFieldSeq))
7530                                 {
7531                                     fldSeq = GetFieldSeqStore()->Append(addrFieldSeq, fldSeq);
7532                                 }
7533                             }
7534
7535 #ifdef DEBUG
7536                             if (verbose)
7537                             {
7538                                 printf("Tree ");
7539                                 Compiler::printTreeID(tree);
7540                                 printf(" assigns to an array element:\n");
7541                             }
7542 #endif // DEBUG
7543
7544                             ValueNum heapVN = fgValueNumberArrIndexAssign(elemTypeEq, arrVN, inxVN, fldSeq,
7545                                                                           rhsVNPair.GetLiberal(), lhs->TypeGet());
7546                             recordGcHeapStore(tree, heapVN DEBUGARG("ArrIndexAssign (case 1)"));
7547                         }
7548                         // It may be that we haven't parsed it yet.  Try.
7549                         else if (lhs->gtFlags & GTF_IND_ARR_INDEX)
7550                         {
7551                             ArrayInfo arrInfo;
7552                             bool      b = GetArrayInfoMap()->Lookup(lhs, &arrInfo);
7553                             assert(b);
7554                             ValueNum      arrVN  = ValueNumStore::NoVN;
7555                             ValueNum      inxVN  = ValueNumStore::NoVN;
7556                             FieldSeqNode* fldSeq = nullptr;
7557
7558                             // Try to parse it.
7559                             GenTree* arr = nullptr;
7560                             arg->ParseArrayAddress(this, &arrInfo, &arr, &inxVN, &fldSeq);
7561                             if (arr == nullptr)
7562                             {
7563                                 fgMutateGcHeap(tree DEBUGARG("assignment to unparseable array expression"));
7564                                 return;
7565                             }
7566                             // Otherwise, parsing succeeded.
7567
7568                             // Need to form H[arrType][arr][ind][fldSeq] = rhsVNPair.GetLiberal()
7569
7570                             // Get the element type equivalence class representative.
7571                             CORINFO_CLASS_HANDLE elemTypeEq =
7572                                 EncodeElemType(arrInfo.m_elemType, arrInfo.m_elemStructType);
7573                             arrVN = arr->gtVNPair.GetLiberal();
7574
7575                             FieldSeqNode* zeroOffsetFldSeq = nullptr;
7576                             if (GetZeroOffsetFieldMap()->Lookup(arg, &zeroOffsetFldSeq))
7577                             {
7578                                 fldSeq = GetFieldSeqStore()->Append(fldSeq, zeroOffsetFldSeq);
7579                             }
7580
7581                             ValueNum heapVN = fgValueNumberArrIndexAssign(elemTypeEq, arrVN, inxVN, fldSeq,
7582                                                                           rhsVNPair.GetLiberal(), lhs->TypeGet());
7583                             recordGcHeapStore(tree, heapVN DEBUGARG("ArrIndexAssign (case 2)"));
7584                         }
7585                         else if (arg->IsFieldAddr(this, &obj, &staticOffset, &fldSeq))
7586                         {
7587                             if (fldSeq == FieldSeqStore::NotAField())
7588                             {
7589                                 fgMutateGcHeap(tree DEBUGARG("NotAField"));
7590                             }
7591                             else
7592                             {
7593                                 assert(fldSeq != nullptr);
7594 #ifdef DEBUG
7595                                 CORINFO_CLASS_HANDLE fldCls = info.compCompHnd->getFieldClass(fldSeq->m_fieldHnd);
7596                                 if (obj != nullptr)
7597                                 {
7598                                     // Make sure that the class containing it is not a value class (as we are expecting
7599                                     // an instance field)
7600                                     assert((info.compCompHnd->getClassAttribs(fldCls) & CORINFO_FLG_VALUECLASS) == 0);
7601                                     assert(staticOffset == nullptr);
7602                                 }
7603 #endif // DEBUG
7604
7605                                 // Get the first (instance or static) field from field seq.  GcHeap[field] will yield
7606                                 // the "field map".
7607                                 if (fldSeq->IsFirstElemFieldSeq())
7608                                 {
7609                                     fldSeq = fldSeq->m_next;
7610                                     assert(fldSeq != nullptr);
7611                                 }
7612
7613                                 // Get a field sequence for just the first field in the sequence
7614                                 //
7615                                 FieldSeqNode* firstFieldOnly = GetFieldSeqStore()->CreateSingleton(fldSeq->m_fieldHnd);
7616
7617                                 // The final field in the sequence will need to match the 'indType'
7618                                 var_types indType = lhs->TypeGet();
7619                                 ValueNum  fldMapVN =
7620                                     vnStore->VNApplySelectors(VNK_Liberal, fgCurMemoryVN[GcHeap], firstFieldOnly);
7621
7622                                 // The type of the field is "struct" if there are more fields in the sequence,
7623                                 // otherwise it is the type returned from VNApplySelectors above.
7624                                 var_types firstFieldType = vnStore->TypeOfVN(fldMapVN);
7625
7626                                 // The value number from the rhs of the assignment
7627                                 ValueNum storeVal    = rhsVNPair.GetLiberal();
7628                                 ValueNum newFldMapVN = ValueNumStore::NoVN;
7629
7630                                 // when (obj != nullptr) we have an instance field, otherwise a static field
7631                                 // when (staticOffset != nullptr) it represents a offset into a static or the call to
7632                                 // Shared Static Base
7633                                 if ((obj != nullptr) || (staticOffset != nullptr))
7634                                 {
7635                                     ValueNum valAtAddr = fldMapVN;
7636                                     ValueNum normVal   = ValueNumStore::NoVN;
7637
7638                                     if (obj != nullptr)
7639                                     {
7640                                         // Unpack, Norm,Exc for 'obj'
7641                                         ValueNum vnObjExcSet;
7642                                         vnStore->VNUnpackExc(obj->gtVNPair.GetLiberal(), &normVal, &vnObjExcSet);
7643                                         vnExcSet = vnStore->VNExcSetUnion(vnExcSet, vnObjExcSet);
7644
7645                                         // construct the ValueNumber for 'fldMap at obj'
7646                                         valAtAddr =
7647                                             vnStore->VNForMapSelect(VNK_Liberal, firstFieldType, fldMapVN, normVal);
7648                                     }
7649                                     else // (staticOffset != nullptr)
7650                                     {
7651                                         // construct the ValueNumber for 'fldMap at staticOffset'
7652                                         normVal = vnStore->VNLiberalNormalValue(staticOffset->gtVNPair);
7653                                         valAtAddr =
7654                                             vnStore->VNForMapSelect(VNK_Liberal, firstFieldType, fldMapVN, normVal);
7655                                     }
7656                                     // Now get rid of any remaining struct field dereferences. (if they exist)
7657                                     if (fldSeq->m_next)
7658                                     {
7659                                         storeVal =
7660                                             vnStore->VNApplySelectorsAssign(VNK_Liberal, valAtAddr, fldSeq->m_next,
7661                                                                             storeVal, indType, compCurBB);
7662                                     }
7663
7664                                     // From which we can construct the new ValueNumber for 'fldMap at normVal'
7665                                     newFldMapVN = vnStore->VNForMapStore(vnStore->TypeOfVN(fldMapVN), fldMapVN, normVal,
7666                                                                          storeVal);
7667                                 }
7668                                 else
7669                                 {
7670                                     // plain static field
7671
7672                                     // Now get rid of any remaining struct field dereferences. (if they exist)
7673                                     if (fldSeq->m_next)
7674                                     {
7675                                         storeVal =
7676                                             vnStore->VNApplySelectorsAssign(VNK_Liberal, fldMapVN, fldSeq->m_next,
7677                                                                             storeVal, indType, compCurBB);
7678                                     }
7679
7680                                     newFldMapVN = vnStore->VNApplySelectorsAssign(VNK_Liberal, fgCurMemoryVN[GcHeap],
7681                                                                                   fldSeq, storeVal, indType, compCurBB);
7682                                 }
7683
7684                                 // It is not strictly necessary to set the lhs value number,
7685                                 // but the dumps read better with it set to the 'storeVal' that we just computed
7686                                 lhs->gtVNPair.SetBoth(storeVal);
7687
7688                                 // Update the field map for firstField in GcHeap to this new value.
7689                                 ValueNum heapVN =
7690                                     vnStore->VNApplySelectorsAssign(VNK_Liberal, fgCurMemoryVN[GcHeap], firstFieldOnly,
7691                                                                     newFldMapVN, indType, compCurBB);
7692
7693                                 recordGcHeapStore(tree, heapVN DEBUGARG("StoreField"));
7694                             }
7695                         }
7696                         else
7697                         {
7698                             GenTreeLclVarCommon* lclVarTree = nullptr;
7699                             bool                 isLocal    = tree->DefinesLocal(this, &lclVarTree);
7700
7701                             if (isLocal && lvaVarAddrExposed(lclVarTree->gtLclNum))
7702                             {
7703                                 // Store to address-exposed local; need to record the effect on ByrefExposed.
7704                                 // We could use MapStore here and MapSelect on reads of address-exposed locals
7705                                 // (using the local nums as selectors) to get e.g. propagation of values
7706                                 // through address-taken locals in regions of code with no calls or byref
7707                                 // writes.
7708                                 // For now, just use a new opaque VN.
7709                                 ValueNum memoryVN = vnStore->VNForExpr(compCurBB);
7710                                 recordAddressExposedLocalStore(tree, memoryVN DEBUGARG("PtrToLoc indir"));
7711                             }
7712                             else if (!isLocal)
7713                             {
7714                                 // If it doesn't define a local, then it might update GcHeap/ByrefExposed.
7715                                 // For the new ByrefExposed VN, we could use an operator here like
7716                                 // VNF_ByrefExposedStore that carries the VNs of the pointer and RHS, then
7717                                 // at byref loads if the current ByrefExposed VN happens to be
7718                                 // VNF_ByrefExposedStore with the same pointer VN, we could propagate the
7719                                 // VN from the RHS to the VN for the load.  This would e.g. allow tracking
7720                                 // values through assignments to out params.  For now, just model this
7721                                 // as an opaque GcHeap/ByrefExposed mutation.
7722                                 fgMutateGcHeap(tree DEBUGARG("assign-of-IND"));
7723                             }
7724                         }
7725                     }
7726
7727                     // We don't actually evaluate an IND on the LHS, so give it the Void value.
7728                     tree->gtVNPair.SetBoth(vnStore->VNForVoid());
7729                 }
7730                 break;
7731
7732                 case GT_CLS_VAR:
7733                 {
7734                     bool isVolatile = (lhs->gtFlags & GTF_FLD_VOLATILE) != 0;
7735
7736                     if (isVolatile)
7737                     {
7738                         // For Volatile store indirection, first mutate GcHeap/ByrefExposed
7739                         fgMutateGcHeap(lhs DEBUGARG("GTF_CLS_VAR - store")); // always change fgCurMemoryVN
7740                     }
7741
7742                     // We model statics as indices into GcHeap (which is a subset of ByrefExposed).
7743                     FieldSeqNode* fldSeqForStaticVar = GetFieldSeqStore()->CreateSingleton(lhs->gtClsVar.gtClsVarHnd);
7744                     assert(fldSeqForStaticVar != FieldSeqStore::NotAField());
7745
7746                     ValueNum storeVal = rhsVNPair.GetLiberal(); // The value number from the rhs of the assignment
7747                     storeVal = vnStore->VNApplySelectorsAssign(VNK_Liberal, fgCurMemoryVN[GcHeap], fldSeqForStaticVar,
7748                                                                storeVal, lhs->TypeGet(), compCurBB);
7749
7750                     // It is not strictly necessary to set the lhs value number,
7751                     // but the dumps read better with it set to the 'storeVal' that we just computed
7752                     lhs->gtVNPair.SetBoth(storeVal);
7753
7754                     // bbMemoryDef must include GcHeap for any block that mutates the GC heap
7755                     assert((compCurBB->bbMemoryDef & memoryKindSet(GcHeap)) != 0);
7756
7757                     // Update the field map for the fgCurMemoryVN and SSA for the tree
7758                     recordGcHeapStore(tree, storeVal DEBUGARG("Static Field store"));
7759                 }
7760                 break;
7761
7762                 default:
7763                     assert(!"Unknown node for lhs of assignment!");
7764
7765                     // For Unknown stores, mutate GcHeap/ByrefExposed
7766                     fgMutateGcHeap(lhs DEBUGARG("Unkwown Assignment - store")); // always change fgCurMemoryVN
7767                     break;
7768             }
7769         }
7770         // Other kinds of assignment: initblk and copyblk.
7771         else if (oper == GT_ASG && varTypeIsStruct(tree))
7772         {
7773             fgValueNumberBlockAssignment(tree);
7774         }
7775         else if (oper == GT_ADDR)
7776         {
7777             // We have special representations for byrefs to lvalues.
7778             GenTree* arg = tree->gtOp.gtOp1;
7779             if (arg->OperIsLocal())
7780             {
7781                 FieldSeqNode* fieldSeq = nullptr;
7782                 ValueNum      newVN    = ValueNumStore::NoVN;
7783                 if (!lvaInSsa(arg->gtLclVarCommon.GetLclNum()))
7784                 {
7785                     newVN = vnStore->VNForExpr(compCurBB, TYP_BYREF);
7786                 }
7787                 else if (arg->OperGet() == GT_LCL_FLD)
7788                 {
7789                     fieldSeq = arg->AsLclFld()->gtFieldSeq;
7790                     if (fieldSeq == nullptr)
7791                     {
7792                         // Local field with unknown field seq -- not a precise pointer.
7793                         newVN = vnStore->VNForExpr(compCurBB, TYP_BYREF);
7794                     }
7795                 }
7796                 if (newVN == ValueNumStore::NoVN)
7797                 {
7798                     assert(arg->gtLclVarCommon.GetSsaNum() != ValueNumStore::NoVN);
7799                     newVN = vnStore->VNForFunc(TYP_BYREF, VNF_PtrToLoc,
7800                                                vnStore->VNForIntCon(arg->gtLclVarCommon.GetLclNum()),
7801                                                vnStore->VNForFieldSeq(fieldSeq));
7802                 }
7803                 tree->gtVNPair.SetBoth(newVN);
7804             }
7805             else if ((arg->gtOper == GT_IND) || arg->OperIsBlk())
7806             {
7807                 // Usually the ADDR and IND just cancel out...
7808                 // except when this GT_ADDR has a valid zero-offset field sequence
7809                 //
7810                 FieldSeqNode* zeroOffsetFieldSeq = nullptr;
7811                 if (GetZeroOffsetFieldMap()->Lookup(tree, &zeroOffsetFieldSeq) &&
7812                     (zeroOffsetFieldSeq != FieldSeqStore::NotAField()))
7813                 {
7814                     ValueNum addrExtended = vnStore->ExtendPtrVN(arg->gtOp.gtOp1, zeroOffsetFieldSeq);
7815                     if (addrExtended != ValueNumStore::NoVN)
7816                     {
7817                         tree->gtVNPair.SetBoth(addrExtended); // We don't care about lib/cons differences for addresses.
7818                     }
7819                     else
7820                     {
7821                         // ExtendPtrVN returned a failure result
7822                         // So give this address a new unique value
7823                         tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, TYP_BYREF));
7824                     }
7825                 }
7826                 else
7827                 {
7828                     // They just cancel, so fetch the ValueNumber from the op1 of the GT_IND node.
7829                     //
7830                     GenTree* addr  = arg->AsIndir()->Addr();
7831                     tree->gtVNPair = addr->gtVNPair;
7832
7833                     // For the CSE phase mark the address as GTF_DONT_CSE
7834                     // because it will end up with the same value number as tree (the GT_ADDR).
7835                     addr->gtFlags |= GTF_DONT_CSE;
7836                 }
7837             }
7838             else
7839             {
7840                 // May be more cases to do here!  But we'll punt for now.
7841                 tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, TYP_BYREF));
7842             }
7843         }
7844         else if ((oper == GT_IND) || GenTree::OperIsBlk(oper))
7845         {
7846             // So far, we handle cases in which the address is a ptr-to-local, or if it's
7847             // a pointer to an object field or array element.  Other cases become uses of
7848             // the current ByrefExposed value and the pointer value, so that at least we
7849             // can recognize redundant loads with no stores between them.
7850             GenTree*             addr         = tree->AsIndir()->Addr();
7851             GenTreeLclVarCommon* lclVarTree   = nullptr;
7852             FieldSeqNode*        fldSeq1      = nullptr;
7853             FieldSeqNode*        fldSeq2      = nullptr;
7854             GenTree*             obj          = nullptr;
7855             GenTree*             staticOffset = nullptr;
7856             bool                 isVolatile   = (tree->gtFlags & GTF_IND_VOLATILE) != 0;
7857
7858             // See if the addr has any exceptional part.
7859             ValueNumPair addrNvnp;
7860             ValueNumPair addrXvnp;
7861             vnStore->VNPUnpackExc(addr->gtVNPair, &addrNvnp, &addrXvnp);
7862
7863             // Is the dereference immutable?  If so, model it as referencing the read-only heap.
7864             if (tree->gtFlags & GTF_IND_INVARIANT)
7865             {
7866                 assert(!isVolatile); // We don't expect both volatile and invariant
7867                 tree->gtVNPair =
7868                     ValueNumPair(vnStore->VNForMapSelect(VNK_Liberal, TYP_REF, ValueNumStore::VNForROH(),
7869                                                          addrNvnp.GetLiberal()),
7870                                  vnStore->VNForMapSelect(VNK_Conservative, TYP_REF, ValueNumStore::VNForROH(),
7871                                                          addrNvnp.GetConservative()));
7872                 tree->gtVNPair = vnStore->VNPWithExc(tree->gtVNPair, addrXvnp);
7873             }
7874             else if (isVolatile)
7875             {
7876                 // For Volatile indirection, mutate GcHeap/ByrefExposed
7877                 fgMutateGcHeap(tree DEBUGARG("GTF_IND_VOLATILE - read"));
7878
7879                 // The value read by the GT_IND can immediately change
7880                 ValueNum newUniq = vnStore->VNForExpr(compCurBB, tree->TypeGet());
7881                 tree->gtVNPair   = vnStore->VNPWithExc(ValueNumPair(newUniq, newUniq), addrXvnp);
7882             }
7883             // We always want to evaluate the LHS when the GT_IND node is marked with GTF_IND_ARR_INDEX
7884             // as this will relabel the GT_IND child correctly using the VNF_PtrToArrElem
7885             else if ((tree->gtFlags & GTF_IND_ARR_INDEX) != 0)
7886             {
7887                 ArrayInfo arrInfo;
7888                 bool      b = GetArrayInfoMap()->Lookup(tree, &arrInfo);
7889                 assert(b);
7890
7891                 ValueNum      inxVN  = ValueNumStore::NoVN;
7892                 FieldSeqNode* fldSeq = nullptr;
7893
7894                 // GenTree* addr = tree->gtOp.gtOp1;
7895                 ValueNum addrVN = addrNvnp.GetLiberal();
7896
7897                 // Try to parse it.
7898                 GenTree* arr = nullptr;
7899                 addr->ParseArrayAddress(this, &arrInfo, &arr, &inxVN, &fldSeq);
7900                 if (arr == nullptr)
7901                 {
7902                     tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
7903                     return;
7904                 }
7905                 assert(fldSeq != FieldSeqStore::NotAField());
7906
7907                 // Otherwise...
7908                 // Need to form H[arrType][arr][ind][fldSeq]
7909                 // Get the array element type equivalence class rep.
7910                 CORINFO_CLASS_HANDLE elemTypeEq   = EncodeElemType(arrInfo.m_elemType, arrInfo.m_elemStructType);
7911                 ValueNum             elemTypeEqVN = vnStore->VNForHandle(ssize_t(elemTypeEq), GTF_ICON_CLASS_HDL);
7912                 JITDUMP("    VNForHandle(arrElemType: %s) is " FMT_VN "\n",
7913                         (arrInfo.m_elemType == TYP_STRUCT) ? eeGetClassName(arrInfo.m_elemStructType)
7914                                                            : varTypeName(arrInfo.m_elemType),
7915                         elemTypeEqVN)
7916
7917                 // We take the "VNNormalValue"s here, because if either has exceptional outcomes, they will be captured
7918                 // as part of the value of the composite "addr" operation...
7919                 ValueNum arrVN = vnStore->VNLiberalNormalValue(arr->gtVNPair);
7920                 inxVN          = vnStore->VNNormalValue(inxVN);
7921
7922                 // Additionally, relabel the address with a PtrToArrElem value number.
7923                 ValueNum fldSeqVN = vnStore->VNForFieldSeq(fldSeq);
7924                 ValueNum elemAddr =
7925                     vnStore->VNForFunc(TYP_BYREF, VNF_PtrToArrElem, elemTypeEqVN, arrVN, inxVN, fldSeqVN);
7926
7927                 // The aggregate "addr" VN should have had all the exceptions bubble up...
7928                 elemAddr = vnStore->VNWithExc(elemAddr, addrXvnp.GetLiberal());
7929                 addr->gtVNPair.SetBoth(elemAddr);
7930 #ifdef DEBUG
7931                 if (verbose)
7932                 {
7933                     printf("  Relabeled IND_ARR_INDEX address node ");
7934                     Compiler::printTreeID(addr);
7935                     printf(" with l:" FMT_VN ": ", elemAddr);
7936                     vnStore->vnDump(this, elemAddr);
7937                     printf("\n");
7938                     if (vnStore->VNNormalValue(elemAddr) != elemAddr)
7939                     {
7940                         printf("      [" FMT_VN " is: ", vnStore->VNNormalValue(elemAddr));
7941                         vnStore->vnDump(this, vnStore->VNNormalValue(elemAddr));
7942                         printf("]\n");
7943                     }
7944                 }
7945 #endif // DEBUG
7946
7947                 // We now need to retrieve the value number for the array element value
7948                 // and give this value number to the GT_IND node 'tree'
7949                 // We do this whenever we have an rvalue, but we don't do it for a
7950                 // normal LHS assignment into an array element.
7951                 //
7952                 if ((tree->gtFlags & GTF_IND_ASG_LHS) == 0)
7953                 {
7954                     fgValueNumberArrIndexVal(tree, elemTypeEq, arrVN, inxVN, addrXvnp.GetLiberal(), fldSeq);
7955                 }
7956             }
7957             // In general we skip GT_IND nodes on that are the LHS of an assignment.  (We labeled these earlier.)
7958             // We will "evaluate" this as part of the assignment.
7959             else if ((tree->gtFlags & GTF_IND_ASG_LHS) == 0)
7960             {
7961                 FieldSeqNode* localFldSeq = nullptr;
7962                 VNFuncApp     funcApp;
7963
7964                 // Is it a local or a heap address?
7965                 if (addr->IsLocalAddrExpr(this, &lclVarTree, &localFldSeq) && lvaInSsa(lclVarTree->GetLclNum()))
7966                 {
7967                     unsigned   lclNum = lclVarTree->GetLclNum();
7968                     unsigned   ssaNum = lclVarTree->GetSsaNum();
7969                     LclVarDsc* varDsc = &lvaTable[lclNum];
7970
7971                     if ((localFldSeq == FieldSeqStore::NotAField()) || (localFldSeq == nullptr))
7972                     {
7973                         tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
7974                     }
7975                     else
7976                     {
7977                         var_types    indType   = tree->TypeGet();
7978                         ValueNumPair lclVNPair = varDsc->GetPerSsaData(ssaNum)->m_vnPair;
7979                         tree->gtVNPair         = vnStore->VNPairApplySelectors(lclVNPair, localFldSeq, indType);
7980                         ;
7981                     }
7982                     tree->gtVNPair = vnStore->VNPWithExc(tree->gtVNPair, addrXvnp);
7983                 }
7984                 else if (vnStore->GetVNFunc(addrNvnp.GetLiberal(), &funcApp) && funcApp.m_func == VNF_PtrToStatic)
7985                 {
7986                     var_types indType    = tree->TypeGet();
7987                     ValueNum  fieldSeqVN = funcApp.m_args[0];
7988
7989                     FieldSeqNode* fldSeqForStaticVar = vnStore->FieldSeqVNToFieldSeq(fieldSeqVN);
7990
7991                     if (fldSeqForStaticVar != FieldSeqStore::NotAField())
7992                     {
7993                         ValueNum selectedStaticVar;
7994                         // We model statics as indices into the GcHeap (which is a subset of ByrefExposed).
7995                         size_t structSize = 0;
7996                         selectedStaticVar = vnStore->VNApplySelectors(VNK_Liberal, fgCurMemoryVN[GcHeap],
7997                                                                       fldSeqForStaticVar, &structSize);
7998                         selectedStaticVar = vnStore->VNApplySelectorsTypeCheck(selectedStaticVar, indType, structSize);
7999
8000                         tree->gtVNPair.SetLiberal(selectedStaticVar);
8001                         tree->gtVNPair.SetConservative(vnStore->VNForExpr(compCurBB, indType));
8002                     }
8003                     else
8004                     {
8005                         JITDUMP("    *** Missing field sequence info for VNF_PtrToStatic value GT_IND\n");
8006                         tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, indType)); //  a new unique value number
8007                     }
8008                     tree->gtVNPair = vnStore->VNPWithExc(tree->gtVNPair, addrXvnp);
8009                 }
8010                 else if (vnStore->GetVNFunc(addrNvnp.GetLiberal(), &funcApp) && (funcApp.m_func == VNF_PtrToArrElem))
8011                 {
8012                     fgValueNumberArrIndexVal(tree, &funcApp, addrXvnp.GetLiberal());
8013                 }
8014                 else if (addr->IsFieldAddr(this, &obj, &staticOffset, &fldSeq2))
8015                 {
8016                     if (fldSeq2 == FieldSeqStore::NotAField())
8017                     {
8018                         tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
8019                     }
8020                     else if (fldSeq2 != nullptr)
8021                     {
8022                         // Get the first (instance or static) field from field seq.  GcHeap[field] will yield the "field
8023                         // map".
8024                         CLANG_FORMAT_COMMENT_ANCHOR;
8025
8026 #ifdef DEBUG
8027                         CORINFO_CLASS_HANDLE fldCls = info.compCompHnd->getFieldClass(fldSeq2->m_fieldHnd);
8028                         if (obj != nullptr)
8029                         {
8030                             // Make sure that the class containing it is not a value class (as we are expecting an
8031                             // instance field)
8032                             assert((info.compCompHnd->getClassAttribs(fldCls) & CORINFO_FLG_VALUECLASS) == 0);
8033                             assert(staticOffset == nullptr);
8034                         }
8035 #endif // DEBUG
8036
8037                         // Get a field sequence for just the first field in the sequence
8038                         //
8039                         FieldSeqNode* firstFieldOnly = GetFieldSeqStore()->CreateSingleton(fldSeq2->m_fieldHnd);
8040                         size_t        structSize     = 0;
8041                         ValueNum      fldMapVN =
8042                             vnStore->VNApplySelectors(VNK_Liberal, fgCurMemoryVN[GcHeap], firstFieldOnly, &structSize);
8043
8044                         // The final field in the sequence will need to match the 'indType'
8045                         var_types indType = tree->TypeGet();
8046
8047                         // The type of the field is "struct" if there are more fields in the sequence,
8048                         // otherwise it is the type returned from VNApplySelectors above.
8049                         var_types firstFieldType = vnStore->TypeOfVN(fldMapVN);
8050
8051                         ValueNum valAtAddr = fldMapVN;
8052                         if (obj != nullptr)
8053                         {
8054                             // construct the ValueNumber for 'fldMap at obj'
8055                             ValueNum objNormVal = vnStore->VNLiberalNormalValue(obj->gtVNPair);
8056                             valAtAddr = vnStore->VNForMapSelect(VNK_Liberal, firstFieldType, fldMapVN, objNormVal);
8057                         }
8058                         else if (staticOffset != nullptr)
8059                         {
8060                             // construct the ValueNumber for 'fldMap at staticOffset'
8061                             ValueNum offsetNormVal = vnStore->VNLiberalNormalValue(staticOffset->gtVNPair);
8062                             valAtAddr = vnStore->VNForMapSelect(VNK_Liberal, firstFieldType, fldMapVN, offsetNormVal);
8063                         }
8064
8065                         // Now get rid of any remaining struct field dereferences.
8066                         if (fldSeq2->m_next)
8067                         {
8068                             valAtAddr = vnStore->VNApplySelectors(VNK_Liberal, valAtAddr, fldSeq2->m_next, &structSize);
8069                         }
8070                         valAtAddr = vnStore->VNApplySelectorsTypeCheck(valAtAddr, indType, structSize);
8071
8072                         tree->gtVNPair.SetLiberal(valAtAddr);
8073
8074                         // The conservative value is a new, unique VN.
8075                         tree->gtVNPair.SetConservative(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
8076                         tree->gtVNPair = vnStore->VNPWithExc(tree->gtVNPair, addrXvnp);
8077                     }
8078                     else
8079                     {
8080                         // Occasionally we do an explicit null test on a REF, so we just dereference it with no
8081                         // field sequence.  The result is probably unused.
8082                         tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
8083                         tree->gtVNPair = vnStore->VNPWithExc(tree->gtVNPair, addrXvnp);
8084                     }
8085                 }
8086                 else // We don't know where the address points, so it is an ByrefExposed load.
8087                 {
8088                     ValueNum addrVN = addr->gtVNPair.GetLiberal();
8089                     ValueNum loadVN = fgValueNumberByrefExposedLoad(typ, addrVN);
8090                     tree->gtVNPair.SetLiberal(loadVN);
8091                     tree->gtVNPair.SetConservative(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
8092                     tree->gtVNPair = vnStore->VNPWithExc(tree->gtVNPair, addrXvnp);
8093                 }
8094             }
8095         }
8096         else if (tree->OperGet() == GT_CAST)
8097         {
8098             fgValueNumberCastTree(tree);
8099         }
8100         else if (tree->OperGet() == GT_INTRINSIC)
8101         {
8102             fgValueNumberIntrinsic(tree);
8103         }
8104         else // Look up the VNFunc for the node
8105         {
8106             VNFunc vnf = GetVNFuncForNode(tree);
8107
8108             if (ValueNumStore::VNFuncIsLegal(vnf))
8109             {
8110                 if (GenTree::OperIsUnary(oper))
8111                 {
8112                     if (tree->gtOp.gtOp1 != nullptr)
8113                     {
8114                         if (tree->OperGet() == GT_NOP)
8115                         {
8116                             // Pass through arg vn.
8117                             tree->gtVNPair = tree->gtOp.gtOp1->gtVNPair;
8118                         }
8119                         else
8120                         {
8121                             ValueNumPair op1VNP;
8122                             ValueNumPair op1VNPx;
8123                             vnStore->VNPUnpackExc(tree->gtOp.gtOp1->gtVNPair, &op1VNP, &op1VNPx);
8124
8125                             // If we are fetching the array length for an array ref that came from global memory
8126                             // then for CSE safety we must use the conservative value number for both
8127                             //
8128                             if ((tree->OperGet() == GT_ARR_LENGTH) && ((tree->gtOp.gtOp1->gtFlags & GTF_GLOB_REF) != 0))
8129                             {
8130                                 // use the conservative value number for both when computing the VN for the ARR_LENGTH
8131                                 op1VNP.SetBoth(op1VNP.GetConservative());
8132                             }
8133
8134                             tree->gtVNPair =
8135                                 vnStore->VNPWithExc(vnStore->VNPairForFunc(tree->TypeGet(), vnf, op1VNP), op1VNPx);
8136                         }
8137                     }
8138                     else // Is actually nullary.
8139                     {
8140                         // Mostly we'll leave these without a value number, assuming we'll detect these as VN failures
8141                         // if they actually need to have values.  With the exception of NOPs, which can sometimes have
8142                         // meaning.
8143                         if (tree->OperGet() == GT_NOP)
8144                         {
8145                             tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
8146                         }
8147                     }
8148                 }
8149                 else // we have a binary oper
8150                 {
8151                     assert(oper != GT_ASG); // We handled assignments earlier.
8152                     assert(GenTree::OperIsBinary(oper));
8153                     // Standard binary operator.
8154                     ValueNumPair op2VNPair;
8155                     if (tree->gtOp.gtOp2 == nullptr)
8156                     {
8157                         // Handle any GT_LIST nodes as they can have a nullptr for op2.
8158                         op2VNPair.SetBoth(ValueNumStore::VNForNull());
8159                     }
8160                     else
8161                     {
8162                         op2VNPair = tree->gtOp.gtOp2->gtVNPair;
8163                     }
8164
8165                     // Handle a few special cases: if we add a field offset constant to a PtrToXXX, we will get back a
8166                     // new
8167                     // PtrToXXX.
8168
8169                     ValueNumPair op1vnp;
8170                     ValueNumPair op1Xvnp;
8171                     vnStore->VNPUnpackExc(tree->gtOp.gtOp1->gtVNPair, &op1vnp, &op1Xvnp);
8172
8173                     ValueNumPair op2vnp;
8174                     ValueNumPair op2Xvnp;
8175                     vnStore->VNPUnpackExc(op2VNPair, &op2vnp, &op2Xvnp);
8176                     ValueNumPair excSet = vnStore->VNPExcSetUnion(op1Xvnp, op2Xvnp);
8177
8178                     ValueNum newVN = ValueNumStore::NoVN;
8179
8180                     // Check for the addition of a field offset constant
8181                     //
8182                     if ((oper == GT_ADD) && (!tree->gtOverflowEx()))
8183                     {
8184                         newVN = vnStore->ExtendPtrVN(tree->gtOp.gtOp1, tree->gtOp.gtOp2);
8185                     }
8186
8187                     if (newVN != ValueNumStore::NoVN)
8188                     {
8189                         // We don't care about differences between liberal and conservative for pointer values.
8190                         newVN = vnStore->VNWithExc(newVN, excSet.GetLiberal());
8191                         tree->gtVNPair.SetBoth(newVN);
8192                     }
8193                     else
8194                     {
8195                         VNFunc       vnf        = GetVNFuncForNode(tree);
8196                         ValueNumPair normalPair = vnStore->VNPairForFunc(tree->TypeGet(), vnf, op1vnp, op2vnp);
8197                         tree->gtVNPair          = vnStore->VNPWithExc(normalPair, excSet);
8198                         // For overflow checking operations the VNF_OverflowExc will be added below
8199                         // by fgValueNumberAddExceptionSet
8200                     }
8201                 }
8202             }
8203             else // ValueNumStore::VNFuncIsLegal returns false
8204             {
8205                 // Some of the genTreeOps that aren't legal VNFuncs so they get special handling.
8206                 switch (oper)
8207                 {
8208                     case GT_COMMA:
8209                     {
8210                         ValueNumPair op1vnp;
8211                         ValueNumPair op1Xvnp;
8212                         vnStore->VNPUnpackExc(tree->gtOp.gtOp1->gtVNPair, &op1vnp, &op1Xvnp);
8213                         ValueNumPair op2vnp;
8214                         ValueNumPair op2Xvnp = ValueNumStore::VNPForEmptyExcSet();
8215                         GenTree*     op2     = tree->gtGetOp2();
8216
8217                         if (op2->OperIsIndir() && ((op2->gtFlags & GTF_IND_ASG_LHS) != 0))
8218                         {
8219                             // If op2 represents the lhs of an assignment then we give a VNForVoid for the lhs
8220                             op2vnp = ValueNumPair(ValueNumStore::VNForVoid(), ValueNumStore::VNForVoid());
8221                         }
8222                         else if ((op2->OperGet() == GT_CLS_VAR) && (op2->gtFlags & GTF_CLS_VAR_ASG_LHS))
8223                         {
8224                             // If op2 represents the lhs of an assignment then we give a VNForVoid for the lhs
8225                             op2vnp = ValueNumPair(ValueNumStore::VNForVoid(), ValueNumStore::VNForVoid());
8226                         }
8227                         else
8228                         {
8229                             vnStore->VNPUnpackExc(op2->gtVNPair, &op2vnp, &op2Xvnp);
8230                         }
8231                         tree->gtVNPair = vnStore->VNPWithExc(op2vnp, vnStore->VNPExcSetUnion(op1Xvnp, op2Xvnp));
8232                     }
8233                     break;
8234
8235                     case GT_NULLCHECK:
8236                     {
8237                         // An Explicit null check, produces no value
8238                         // But we do persist any execeptions produced by op1
8239                         //
8240                         tree->gtVNPair = vnStore->VNPWithExc(vnStore->VNPForVoid(),
8241                                                              vnStore->VNPExceptionSet(tree->gtOp.gtOp1->gtVNPair));
8242                         // The exception set with VNF_NullPtrExc will be added below
8243                         // by fgValueNumberAddExceptionSet
8244                     }
8245                     break;
8246
8247                     case GT_LOCKADD: // Binop
8248                         noway_assert("LOCKADD should not appear before lowering");
8249                         break;
8250
8251                     case GT_XADD: // Binop
8252                     case GT_XCHG: // Binop
8253                     {
8254                         // For XADD and XCHG other intrinsics add an arbitrary side effect on GcHeap/ByrefExposed.
8255                         fgMutateGcHeap(tree DEBUGARG("Interlocked intrinsic"));
8256
8257                         assert(tree->OperIsImplicitIndir()); // special node with an implicit indirections
8258
8259                         GenTree* addr = tree->gtOp.gtOp1; // op1
8260                         GenTree* data = tree->gtOp.gtOp2; // op2
8261
8262                         ValueNumPair vnpExcSet = ValueNumStore::VNPForEmptyExcSet();
8263
8264                         vnpExcSet = vnStore->VNPUnionExcSet(data->gtVNPair, vnpExcSet);
8265                         vnpExcSet = vnStore->VNPUnionExcSet(addr->gtVNPair, vnpExcSet);
8266
8267                         // The normal value is a new unique VN.
8268                         ValueNumPair normalPair;
8269                         normalPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
8270
8271                         // Attach the combined exception set
8272                         tree->gtVNPair = vnStore->VNPWithExc(normalPair, vnpExcSet);
8273
8274                         // add the null check exception for 'addr' to the tree's value number
8275                         fgValueNumberAddExceptionSetForIndirection(tree, addr);
8276                         break;
8277                     }
8278
8279                     case GT_JTRUE:
8280                     case GT_LIST:
8281                         // These nodes never need to have a ValueNumber
8282                         tree->gtVNPair.SetBoth(ValueNumStore::NoVN);
8283                         break;
8284
8285                     case GT_BOX:
8286                         // BOX doesn't do anything at this point, the actual object allocation
8287                         // and initialization happens separately (and not numbering BOX correctly
8288                         // prevents seeing allocation related assertions through it)
8289                         tree->gtVNPair = tree->gtGetOp1()->gtVNPair;
8290                         break;
8291
8292                     default:
8293                         // The default action is to give the node a new, unique VN.
8294                         tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
8295                         break;
8296                 }
8297             }
8298         }
8299
8300         // next we add any exception sets for the current tree node
8301         fgValueNumberAddExceptionSet(tree);
8302     }
8303     else
8304     {
8305         assert(GenTree::OperIsSpecial(oper));
8306
8307         // TBD: We must handle these individually.  For now:
8308         switch (oper)
8309         {
8310             case GT_CALL:
8311                 fgValueNumberCall(tree->AsCall());
8312                 break;
8313
8314             case GT_ARR_BOUNDS_CHECK:
8315 #ifdef FEATURE_SIMD
8316             case GT_SIMD_CHK:
8317 #endif // FEATURE_SIMD
8318 #ifdef FEATURE_HW_INTRINSICS
8319             case GT_HW_INTRINSIC_CHK:
8320 #endif // FEATURE_HW_INTRINSICS
8321             {
8322                 ValueNumPair vnpIndex  = tree->AsBoundsChk()->gtIndex->gtVNPair;
8323                 ValueNumPair vnpArrLen = tree->AsBoundsChk()->gtArrLen->gtVNPair;
8324
8325                 // Construct the exception set for bounds check
8326                 ValueNumPair vnpExcSet = vnStore->VNPExcSetSingleton(
8327                     vnStore->VNPairForFunc(TYP_REF, VNF_IndexOutOfRangeExc, vnStore->VNPNormalPair(vnpIndex),
8328                                            vnStore->VNPNormalPair(vnpArrLen)));
8329
8330                 // And collect the exceptions  from Index and ArrLen
8331                 vnpExcSet = vnStore->VNPUnionExcSet(vnpIndex, vnpExcSet);
8332                 vnpExcSet = vnStore->VNPUnionExcSet(vnpArrLen, vnpExcSet);
8333
8334                 // A bounds check node has no value, but may throw exceptions.
8335                 tree->gtVNPair = vnStore->VNPWithExc(vnStore->VNPForVoid(), vnpExcSet);
8336
8337                 // Record non-constant value numbers that are used as the length argument to bounds checks, so that
8338                 // assertion prop will know that comparisons against them are worth analyzing.
8339                 ValueNum lengthVN = tree->AsBoundsChk()->gtArrLen->gtVNPair.GetConservative();
8340                 if ((lengthVN != ValueNumStore::NoVN) && !vnStore->IsVNConstant(lengthVN))
8341                 {
8342                     vnStore->SetVNIsCheckedBound(lengthVN);
8343                 }
8344             }
8345             break;
8346
8347             case GT_CMPXCHG: // Specialop
8348             {
8349                 // For CMPXCHG and other intrinsics add an arbitrary side effect on GcHeap/ByrefExposed.
8350                 fgMutateGcHeap(tree DEBUGARG("Interlocked intrinsic"));
8351
8352                 GenTreeCmpXchg* const cmpXchg = tree->AsCmpXchg();
8353
8354                 assert(tree->OperIsImplicitIndir()); // special node with an implicit indirections
8355
8356                 GenTree* location  = cmpXchg->gtOpLocation;  // arg1
8357                 GenTree* value     = cmpXchg->gtOpValue;     // arg2
8358                 GenTree* comparand = cmpXchg->gtOpComparand; // arg3
8359
8360                 ValueNumPair vnpExcSet = ValueNumStore::VNPForEmptyExcSet();
8361
8362                 // Collect the exception sets from our operands
8363                 vnpExcSet = vnStore->VNPUnionExcSet(location->gtVNPair, vnpExcSet);
8364                 vnpExcSet = vnStore->VNPUnionExcSet(value->gtVNPair, vnpExcSet);
8365                 vnpExcSet = vnStore->VNPUnionExcSet(comparand->gtVNPair, vnpExcSet);
8366
8367                 // The normal value is a new unique VN.
8368                 ValueNumPair normalPair;
8369                 normalPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
8370
8371                 // Attach the combined exception set
8372                 tree->gtVNPair = vnStore->VNPWithExc(normalPair, vnpExcSet);
8373
8374                 // add the null check exception for 'location' to the tree's value number
8375                 fgValueNumberAddExceptionSetForIndirection(tree, location);
8376                 // add the null check exception for 'comparand' to the tree's value number
8377                 fgValueNumberAddExceptionSetForIndirection(tree, comparand);
8378                 break;
8379             }
8380
8381             default:
8382                 tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, tree->TypeGet()));
8383         }
8384     }
8385 #ifdef DEBUG
8386     if (verbose)
8387     {
8388         if (tree->gtVNPair.GetLiberal() != ValueNumStore::NoVN)
8389         {
8390             printf("N%03u ", tree->gtSeqNum);
8391             printTreeID(tree);
8392             printf(" ");
8393             gtDispNodeName(tree);
8394             if (tree->OperIsLeaf() || tree->OperIsLocalStore()) // local stores used to be leaves
8395             {
8396                 gtDispLeaf(tree, nullptr);
8397             }
8398             printf(" => ");
8399             vnpPrint(tree->gtVNPair, 1);
8400             printf("\n");
8401         }
8402     }
8403 #endif // DEBUG
8404 }
8405
8406 void Compiler::fgValueNumberIntrinsic(GenTree* tree)
8407 {
8408     assert(tree->OperGet() == GT_INTRINSIC);
8409     GenTreeIntrinsic* intrinsic = tree->AsIntrinsic();
8410     ValueNumPair      arg0VNP, arg1VNP;
8411     ValueNumPair      arg0VNPx = ValueNumStore::VNPForEmptyExcSet();
8412     ValueNumPair      arg1VNPx = ValueNumStore::VNPForEmptyExcSet();
8413
8414     vnStore->VNPUnpackExc(intrinsic->gtOp.gtOp1->gtVNPair, &arg0VNP, &arg0VNPx);
8415
8416     if (intrinsic->gtOp.gtOp2 != nullptr)
8417     {
8418         vnStore->VNPUnpackExc(intrinsic->gtOp.gtOp2->gtVNPair, &arg1VNP, &arg1VNPx);
8419     }
8420
8421     if (IsMathIntrinsic(intrinsic->gtIntrinsicId))
8422     {
8423         // GT_INTRINSIC is a currently a subtype of binary operators. But most of
8424         // the math intrinsics are actually unary operations.
8425
8426         if (intrinsic->gtOp.gtOp2 == nullptr)
8427         {
8428             intrinsic->gtVNPair =
8429                 vnStore->VNPWithExc(vnStore->EvalMathFuncUnary(tree->TypeGet(), intrinsic->gtIntrinsicId, arg0VNP),
8430                                     arg0VNPx);
8431         }
8432         else
8433         {
8434             ValueNumPair newVNP =
8435                 vnStore->EvalMathFuncBinary(tree->TypeGet(), intrinsic->gtIntrinsicId, arg0VNP, arg1VNP);
8436             ValueNumPair excSet = vnStore->VNPExcSetUnion(arg0VNPx, arg1VNPx);
8437             intrinsic->gtVNPair = vnStore->VNPWithExc(newVNP, excSet);
8438         }
8439     }
8440     else
8441     {
8442         switch (intrinsic->gtIntrinsicId)
8443         {
8444             case CORINFO_INTRINSIC_Object_GetType:
8445                 intrinsic->gtVNPair =
8446                     vnStore->VNPWithExc(vnStore->VNPairForFunc(intrinsic->TypeGet(), VNF_ObjGetType, arg0VNP),
8447                                         arg0VNPx);
8448                 break;
8449
8450             default:
8451                 unreached();
8452         }
8453     }
8454 }
8455
8456 void Compiler::fgValueNumberCastTree(GenTree* tree)
8457 {
8458     assert(tree->OperGet() == GT_CAST);
8459
8460     ValueNumPair srcVNPair        = tree->gtOp.gtOp1->gtVNPair;
8461     var_types    castToType       = tree->CastToType();
8462     var_types    castFromType     = tree->CastFromType();
8463     bool         srcIsUnsigned    = ((tree->gtFlags & GTF_UNSIGNED) != 0);
8464     bool         hasOverflowCheck = tree->gtOverflowEx();
8465
8466     assert(genActualType(castToType) == genActualType(tree->TypeGet())); // Insure that the resultType is correct
8467
8468     tree->gtVNPair = vnStore->VNPairForCast(srcVNPair, castToType, castFromType, srcIsUnsigned, hasOverflowCheck);
8469 }
8470
8471 // Compute the normal ValueNumber for a cast operation with no exceptions
8472 ValueNum ValueNumStore::VNForCast(ValueNum  srcVN,
8473                                   var_types castToType,
8474                                   var_types castFromType,
8475                                   bool      srcIsUnsigned /* = false */)
8476 {
8477     // The resulting type after performingthe cast is always widened to a supported IL stack size
8478     var_types resultType = genActualType(castToType);
8479
8480     // When we're considering actual value returned by a non-checking cast whether or not the source is
8481     // unsigned does *not* matter for non-widening casts.  That is, if we cast an int or a uint to short,
8482     // we just extract the first two bytes from the source bit pattern, not worrying about the interpretation.
8483     // The same is true in casting between signed/unsigned types of the same width.  Only when we're doing
8484     // a widening cast do we care about whether the source was unsigned,so we know whether to sign or zero extend it.
8485     //
8486     bool srcIsUnsignedNorm = srcIsUnsigned;
8487     if (genTypeSize(castToType) <= genTypeSize(castFromType))
8488     {
8489         srcIsUnsignedNorm = false;
8490     }
8491
8492     ValueNum castTypeVN = VNForCastOper(castToType, srcIsUnsigned);
8493     ValueNum resultVN   = VNForFunc(resultType, VNF_Cast, srcVN, castTypeVN);
8494
8495 #ifdef DEBUG
8496     if (m_pComp->verbose)
8497     {
8498         printf("    VNForCast(" FMT_VN ", " FMT_VN ") returns ", srcVN, castTypeVN);
8499         m_pComp->vnPrint(resultVN, 1);
8500         printf("\n");
8501     }
8502 #endif
8503
8504     return resultVN;
8505 }
8506
8507 // Compute the ValueNumberPair for a cast operation
8508 ValueNumPair ValueNumStore::VNPairForCast(ValueNumPair srcVNPair,
8509                                           var_types    castToType,
8510                                           var_types    castFromType,
8511                                           bool         srcIsUnsigned,    /* = false */
8512                                           bool         hasOverflowCheck) /* = false */
8513 {
8514     // The resulting type after performingthe cast is always widened to a supported IL stack size
8515     var_types resultType = genActualType(castToType);
8516
8517     ValueNumPair castArgVNP;
8518     ValueNumPair castArgxVNP;
8519     VNPUnpackExc(srcVNPair, &castArgVNP, &castArgxVNP);
8520
8521     // When we're considering actual value returned by a non-checking cast, (hasOverflowCheck is false)
8522     // whether or not the source is unsigned does *not* matter for non-widening casts.
8523     // That is, if we cast an int or a uint to short, we just extract the first two bytes from the source
8524     // bit pattern, not worrying about the interpretation.  The same is true in casting between signed/unsigned
8525     // types of the same width.  Only when we're doing a widening cast do we care about whether the source
8526     // was unsigned, so we know whether to sign or zero extend it.
8527     //
8528     // Important: Casts to floating point cannot be optimized in this fashion. (bug 946768)
8529     //
8530     bool srcIsUnsignedNorm = srcIsUnsigned;
8531     if (!hasOverflowCheck && !varTypeIsFloating(castToType) && (genTypeSize(castToType) <= genTypeSize(castFromType)))
8532     {
8533         srcIsUnsignedNorm = false;
8534     }
8535
8536     VNFunc       vnFunc     = hasOverflowCheck ? VNF_CastOvf : VNF_Cast;
8537     ValueNum     castTypeVN = VNForCastOper(castToType, srcIsUnsignedNorm);
8538     ValueNumPair castTypeVNPair(castTypeVN, castTypeVN);
8539     ValueNumPair castNormRes = VNPairForFunc(resultType, vnFunc, castArgVNP, castTypeVNPair);
8540
8541     ValueNumPair resultVNP = VNPWithExc(castNormRes, castArgxVNP);
8542
8543     // If we have a check for overflow, add the exception information.
8544     if (hasOverflowCheck)
8545     {
8546         ValueNumPair ovfChk = VNPairForFunc(TYP_REF, VNF_ConvOverflowExc, castArgVNP, castTypeVNPair);
8547         ValueNumPair excSet = VNPExcSetSingleton(ovfChk);
8548         excSet              = VNPExcSetUnion(excSet, castArgxVNP);
8549         resultVNP           = VNPWithExc(castNormRes, excSet);
8550     }
8551
8552     return resultVNP;
8553 }
8554
8555 void Compiler::fgValueNumberHelperCallFunc(GenTreeCall* call, VNFunc vnf, ValueNumPair vnpExc)
8556 {
8557     unsigned nArgs = ValueNumStore::VNFuncArity(vnf);
8558     assert(vnf != VNF_Boundary);
8559     GenTreeArgList* args                    = call->gtCallArgs;
8560     bool            generateUniqueVN        = false;
8561     bool            useEntryPointAddrAsArg0 = false;
8562
8563     switch (vnf)
8564     {
8565         case VNF_JitNew:
8566         {
8567             generateUniqueVN = true;
8568             vnpExc           = ValueNumStore::VNPForEmptyExcSet();
8569         }
8570         break;
8571
8572         case VNF_JitNewArr:
8573         {
8574             generateUniqueVN  = true;
8575             ValueNumPair vnp1 = vnStore->VNPNormalPair(args->Rest()->Current()->gtVNPair);
8576
8577             // The New Array helper may throw an overflow exception
8578             vnpExc = vnStore->VNPExcSetSingleton(vnStore->VNPairForFunc(TYP_REF, VNF_NewArrOverflowExc, vnp1));
8579         }
8580         break;
8581
8582         case VNF_Box:
8583         case VNF_BoxNullable:
8584         {
8585             // Generate unique VN so, VNForFunc generates a uniq value number for box nullable.
8586             // Alternatively instead of using vnpUniq below in VNPairForFunc(...),
8587             // we could use the value number of what the byref arg0 points to.
8588             //
8589             // But retrieving the value number of what the byref arg0 points to is quite a bit more work
8590             // and doing so only very rarely allows for an additional optimization.
8591             generateUniqueVN = true;
8592         }
8593         break;
8594
8595         case VNF_JitReadyToRunNew:
8596         {
8597             generateUniqueVN        = true;
8598             vnpExc                  = ValueNumStore::VNPForEmptyExcSet();
8599             useEntryPointAddrAsArg0 = true;
8600         }
8601         break;
8602
8603         case VNF_JitReadyToRunNewArr:
8604         {
8605             generateUniqueVN  = true;
8606             ValueNumPair vnp1 = vnStore->VNPNormalPair(args->Current()->gtVNPair);
8607
8608             // The New Array helper may throw an overflow exception
8609             vnpExc = vnStore->VNPExcSetSingleton(vnStore->VNPairForFunc(TYP_REF, VNF_NewArrOverflowExc, vnp1));
8610             useEntryPointAddrAsArg0 = true;
8611         }
8612         break;
8613
8614         case VNF_ReadyToRunStaticBase:
8615         case VNF_ReadyToRunGenericStaticBase:
8616         case VNF_ReadyToRunIsInstanceOf:
8617         case VNF_ReadyToRunCastClass:
8618         {
8619             useEntryPointAddrAsArg0 = true;
8620         }
8621         break;
8622
8623         default:
8624         {
8625             assert(s_helperCallProperties.IsPure(eeGetHelperNum(call->gtCallMethHnd)));
8626         }
8627         break;
8628     }
8629
8630     if (generateUniqueVN)
8631     {
8632         nArgs--;
8633     }
8634
8635     ValueNumPair vnpUniq;
8636     if (generateUniqueVN)
8637     {
8638         // Generate unique VN so, VNForFunc generates a unique value number.
8639         vnpUniq.SetBoth(vnStore->VNForExpr(compCurBB, call->TypeGet()));
8640     }
8641
8642 #if defined(FEATURE_READYTORUN_COMPILER) && defined(_TARGET_ARMARCH_)
8643     if (call->IsR2RRelativeIndir())
8644     {
8645 #ifdef DEBUG
8646         assert(args->Current()->OperGet() == GT_ARGPLACE);
8647
8648         // Find the corresponding late arg.
8649         GenTree* indirectCellAddress = call->fgArgInfo->GetArgNode(0);
8650         assert(indirectCellAddress->IsCnsIntOrI() && indirectCellAddress->gtRegNum == REG_R2R_INDIRECT_PARAM);
8651 #endif // DEBUG
8652
8653         // For ARM indirectCellAddress is consumed by the call itself, so it should have added as an implicit argument
8654         // in morph. So we do not need to use EntryPointAddrAsArg0, because arg0 is already an entry point addr.
8655         useEntryPointAddrAsArg0 = false;
8656     }
8657 #endif // FEATURE_READYTORUN_COMPILER && _TARGET_ARMARCH_
8658
8659     if (nArgs == 0)
8660     {
8661         if (generateUniqueVN)
8662         {
8663             call->gtVNPair = vnStore->VNPairForFunc(call->TypeGet(), vnf, vnpUniq);
8664         }
8665         else
8666         {
8667             call->gtVNPair.SetBoth(vnStore->VNForFunc(call->TypeGet(), vnf));
8668         }
8669     }
8670     else
8671     {
8672         auto getCurrentArg = [call, &args, useEntryPointAddrAsArg0](int currentIndex) {
8673             GenTree* arg = args->Current();
8674             if ((arg->gtFlags & GTF_LATE_ARG) != 0)
8675             {
8676                 // This arg is a setup node that moves the arg into position.
8677                 // Value-numbering will have visited the separate late arg that
8678                 // holds the actual value, and propagated/computed the value number
8679                 // for this arg there.
8680                 if (useEntryPointAddrAsArg0)
8681                 {
8682                     // The args in the fgArgInfo don't include the entry point, so
8683                     // index into them using one less than the requested index.
8684                     --currentIndex;
8685                 }
8686                 return call->fgArgInfo->GetArgNode(currentIndex);
8687             }
8688             return arg;
8689         };
8690         // Has at least one argument.
8691         ValueNumPair vnp0;
8692         ValueNumPair vnp0x = ValueNumStore::VNPForEmptyExcSet();
8693 #ifdef FEATURE_READYTORUN_COMPILER
8694         if (useEntryPointAddrAsArg0)
8695         {
8696             ssize_t  addrValue  = (ssize_t)call->gtEntryPoint.addr;
8697             ValueNum callAddrVN = vnStore->VNForHandle(addrValue, GTF_ICON_FTN_ADDR);
8698             vnp0                = ValueNumPair(callAddrVN, callAddrVN);
8699         }
8700         else
8701 #endif // FEATURE_READYTORUN_COMPILER
8702         {
8703             assert(!useEntryPointAddrAsArg0);
8704             ValueNumPair vnp0wx = getCurrentArg(0)->gtVNPair;
8705             vnStore->VNPUnpackExc(vnp0wx, &vnp0, &vnp0x);
8706
8707             // Also include in the argument exception sets
8708             vnpExc = vnStore->VNPExcSetUnion(vnpExc, vnp0x);
8709
8710             args = args->Rest();
8711         }
8712         if (nArgs == 1)
8713         {
8714             if (generateUniqueVN)
8715             {
8716                 call->gtVNPair = vnStore->VNPairForFunc(call->TypeGet(), vnf, vnp0, vnpUniq);
8717             }
8718             else
8719             {
8720                 call->gtVNPair = vnStore->VNPairForFunc(call->TypeGet(), vnf, vnp0);
8721             }
8722         }
8723         else
8724         {
8725             // Has at least two arguments.
8726             ValueNumPair vnp1wx = getCurrentArg(1)->gtVNPair;
8727             ValueNumPair vnp1;
8728             ValueNumPair vnp1x;
8729             vnStore->VNPUnpackExc(vnp1wx, &vnp1, &vnp1x);
8730             vnpExc = vnStore->VNPExcSetUnion(vnpExc, vnp1x);
8731
8732             args = args->Rest();
8733             if (nArgs == 2)
8734             {
8735                 if (generateUniqueVN)
8736                 {
8737                     call->gtVNPair = vnStore->VNPairForFunc(call->TypeGet(), vnf, vnp0, vnp1, vnpUniq);
8738                 }
8739                 else
8740                 {
8741                     call->gtVNPair = vnStore->VNPairForFunc(call->TypeGet(), vnf, vnp0, vnp1);
8742                 }
8743             }
8744             else
8745             {
8746                 ValueNumPair vnp2wx = getCurrentArg(2)->gtVNPair;
8747                 ValueNumPair vnp2;
8748                 ValueNumPair vnp2x;
8749                 vnStore->VNPUnpackExc(vnp2wx, &vnp2, &vnp2x);
8750                 vnpExc = vnStore->VNPExcSetUnion(vnpExc, vnp2x);
8751
8752                 args = args->Rest();
8753                 assert(nArgs == 3); // Our current maximum.
8754                 assert(args == nullptr);
8755                 if (generateUniqueVN)
8756                 {
8757                     call->gtVNPair = vnStore->VNPairForFunc(call->TypeGet(), vnf, vnp0, vnp1, vnp2, vnpUniq);
8758                 }
8759                 else
8760                 {
8761                     call->gtVNPair = vnStore->VNPairForFunc(call->TypeGet(), vnf, vnp0, vnp1, vnp2);
8762                 }
8763             }
8764         }
8765         // Add the accumulated exceptions.
8766         call->gtVNPair = vnStore->VNPWithExc(call->gtVNPair, vnpExc);
8767     }
8768     assert(args == nullptr || generateUniqueVN); // All arguments should be processed or we generate unique VN and do
8769                                                  // not care.
8770 }
8771
8772 void Compiler::fgValueNumberCall(GenTreeCall* call)
8773 {
8774     // First: do value numbering of any argument placeholder nodes in the argument list
8775     // (by transferring from the VN of the late arg that they are standing in for...)
8776     unsigned        i               = 0;
8777     GenTreeArgList* args            = call->gtCallArgs;
8778     bool            updatedArgPlace = false;
8779     while (args != nullptr)
8780     {
8781         GenTree* arg = args->Current();
8782         if (arg->OperGet() == GT_ARGPLACE)
8783         {
8784             // Find the corresponding late arg.
8785             GenTree* lateArg = call->fgArgInfo->GetArgNode(i);
8786             assert(lateArg->gtVNPair.BothDefined());
8787             arg->gtVNPair   = lateArg->gtVNPair;
8788             updatedArgPlace = true;
8789 #ifdef DEBUG
8790             if (verbose)
8791             {
8792                 printf("VN of ARGPLACE tree ");
8793                 Compiler::printTreeID(arg);
8794                 printf(" updated to ");
8795                 vnpPrint(arg->gtVNPair, 1);
8796                 printf("\n");
8797             }
8798 #endif
8799         }
8800         i++;
8801         args = args->Rest();
8802     }
8803     if (updatedArgPlace)
8804     {
8805         // Now we have to update the VN's of the argument list nodes, since that will be used in determining
8806         // loop-invariance.
8807         fgUpdateArgListVNs(call->gtCallArgs);
8808     }
8809
8810     if (call->gtCallType == CT_HELPER)
8811     {
8812         bool modHeap = fgValueNumberHelperCall(call);
8813
8814         if (modHeap)
8815         {
8816             // For now, arbitrary side effect on GcHeap/ByrefExposed.
8817             fgMutateGcHeap(call DEBUGARG("HELPER - modifies heap"));
8818         }
8819     }
8820     else
8821     {
8822         if (call->TypeGet() == TYP_VOID)
8823         {
8824             call->gtVNPair.SetBoth(ValueNumStore::VNForVoid());
8825         }
8826         else
8827         {
8828             call->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, call->TypeGet()));
8829         }
8830
8831         // For now, arbitrary side effect on GcHeap/ByrefExposed.
8832         fgMutateGcHeap(call DEBUGARG("CALL"));
8833     }
8834 }
8835
8836 void Compiler::fgUpdateArgListVNs(GenTreeArgList* args)
8837 {
8838     if (args == nullptr)
8839     {
8840         return;
8841     }
8842     // Otherwise...
8843     fgUpdateArgListVNs(args->Rest());
8844     fgValueNumberTree(args);
8845 }
8846
8847 VNFunc Compiler::fgValueNumberJitHelperMethodVNFunc(CorInfoHelpFunc helpFunc)
8848 {
8849     assert(s_helperCallProperties.IsPure(helpFunc) || s_helperCallProperties.IsAllocator(helpFunc));
8850
8851     VNFunc vnf = VNF_Boundary; // An illegal value...
8852     switch (helpFunc)
8853     {
8854         // These translate to other function symbols:
8855         case CORINFO_HELP_DIV:
8856             vnf = VNFunc(GT_DIV);
8857             break;
8858         case CORINFO_HELP_MOD:
8859             vnf = VNFunc(GT_MOD);
8860             break;
8861         case CORINFO_HELP_UDIV:
8862             vnf = VNFunc(GT_UDIV);
8863             break;
8864         case CORINFO_HELP_UMOD:
8865             vnf = VNFunc(GT_UMOD);
8866             break;
8867         case CORINFO_HELP_LLSH:
8868             vnf = VNFunc(GT_LSH);
8869             break;
8870         case CORINFO_HELP_LRSH:
8871             vnf = VNFunc(GT_RSH);
8872             break;
8873         case CORINFO_HELP_LRSZ:
8874             vnf = VNFunc(GT_RSZ);
8875             break;
8876         case CORINFO_HELP_LMUL:
8877         case CORINFO_HELP_LMUL_OVF:
8878             vnf = VNFunc(GT_MUL);
8879             break;
8880         case CORINFO_HELP_ULMUL_OVF:
8881             vnf = VNFunc(GT_MUL);
8882             break; // Is this the right thing?
8883         case CORINFO_HELP_LDIV:
8884             vnf = VNFunc(GT_DIV);
8885             break;
8886         case CORINFO_HELP_LMOD:
8887             vnf = VNFunc(GT_MOD);
8888             break;
8889         case CORINFO_HELP_ULDIV:
8890             vnf = VNFunc(GT_UDIV);
8891             break;
8892         case CORINFO_HELP_ULMOD:
8893             vnf = VNFunc(GT_UMOD);
8894             break;
8895
8896         case CORINFO_HELP_LNG2DBL:
8897             vnf = VNF_Lng2Dbl;
8898             break;
8899         case CORINFO_HELP_ULNG2DBL:
8900             vnf = VNF_ULng2Dbl;
8901             break;
8902         case CORINFO_HELP_DBL2INT:
8903             vnf = VNF_Dbl2Int;
8904             break;
8905         case CORINFO_HELP_DBL2INT_OVF:
8906             vnf = VNF_Dbl2Int;
8907             break;
8908         case CORINFO_HELP_DBL2LNG:
8909             vnf = VNF_Dbl2Lng;
8910             break;
8911         case CORINFO_HELP_DBL2LNG_OVF:
8912             vnf = VNF_Dbl2Lng;
8913             break;
8914         case CORINFO_HELP_DBL2UINT:
8915             vnf = VNF_Dbl2UInt;
8916             break;
8917         case CORINFO_HELP_DBL2UINT_OVF:
8918             vnf = VNF_Dbl2UInt;
8919             break;
8920         case CORINFO_HELP_DBL2ULNG:
8921             vnf = VNF_Dbl2ULng;
8922             break;
8923         case CORINFO_HELP_DBL2ULNG_OVF:
8924             vnf = VNF_Dbl2ULng;
8925             break;
8926         case CORINFO_HELP_FLTREM:
8927             vnf = VNFunc(GT_MOD);
8928             break;
8929         case CORINFO_HELP_DBLREM:
8930             vnf = VNFunc(GT_MOD);
8931             break;
8932         case CORINFO_HELP_FLTROUND:
8933             vnf = VNF_FltRound;
8934             break; // Is this the right thing?
8935         case CORINFO_HELP_DBLROUND:
8936             vnf = VNF_DblRound;
8937             break; // Is this the right thing?
8938
8939         // These allocation operations probably require some augmentation -- perhaps allocSiteId,
8940         // something about array length...
8941         case CORINFO_HELP_NEW_CROSSCONTEXT:
8942         case CORINFO_HELP_NEWFAST:
8943         case CORINFO_HELP_NEWSFAST:
8944         case CORINFO_HELP_NEWSFAST_FINALIZE:
8945         case CORINFO_HELP_NEWSFAST_ALIGN8:
8946         case CORINFO_HELP_NEWSFAST_ALIGN8_VC:
8947         case CORINFO_HELP_NEWSFAST_ALIGN8_FINALIZE:
8948             vnf = VNF_JitNew;
8949             break;
8950
8951         case CORINFO_HELP_READYTORUN_NEW:
8952             vnf = VNF_JitReadyToRunNew;
8953             break;
8954
8955         case CORINFO_HELP_NEWARR_1_DIRECT:
8956         case CORINFO_HELP_NEWARR_1_OBJ:
8957         case CORINFO_HELP_NEWARR_1_VC:
8958         case CORINFO_HELP_NEWARR_1_ALIGN8:
8959             vnf = VNF_JitNewArr;
8960             break;
8961
8962         case CORINFO_HELP_NEWARR_1_R2R_DIRECT:
8963         case CORINFO_HELP_READYTORUN_NEWARR_1:
8964             vnf = VNF_JitReadyToRunNewArr;
8965             break;
8966
8967         case CORINFO_HELP_GETGENERICS_GCSTATIC_BASE:
8968             vnf = VNF_GetgenericsGcstaticBase;
8969             break;
8970         case CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE:
8971             vnf = VNF_GetgenericsNongcstaticBase;
8972             break;
8973         case CORINFO_HELP_GETSHARED_GCSTATIC_BASE:
8974             vnf = VNF_GetsharedGcstaticBase;
8975             break;
8976         case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE:
8977             vnf = VNF_GetsharedNongcstaticBase;
8978             break;
8979         case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR:
8980             vnf = VNF_GetsharedGcstaticBaseNoctor;
8981             break;
8982         case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR:
8983             vnf = VNF_GetsharedNongcstaticBaseNoctor;
8984             break;
8985         case CORINFO_HELP_READYTORUN_STATIC_BASE:
8986             vnf = VNF_ReadyToRunStaticBase;
8987             break;
8988         case CORINFO_HELP_READYTORUN_GENERIC_STATIC_BASE:
8989             vnf = VNF_ReadyToRunGenericStaticBase;
8990             break;
8991         case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS:
8992             vnf = VNF_GetsharedGcstaticBaseDynamicclass;
8993             break;
8994         case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS:
8995             vnf = VNF_GetsharedNongcstaticBaseDynamicclass;
8996             break;
8997         case CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS:
8998             vnf = VNF_ClassinitSharedDynamicclass;
8999             break;
9000         case CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE:
9001             vnf = VNF_GetgenericsGcthreadstaticBase;
9002             break;
9003         case CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE:
9004             vnf = VNF_GetgenericsNongcthreadstaticBase;
9005             break;
9006         case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE:
9007             vnf = VNF_GetsharedGcthreadstaticBase;
9008             break;
9009         case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE:
9010             vnf = VNF_GetsharedNongcthreadstaticBase;
9011             break;
9012         case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR:
9013             vnf = VNF_GetsharedGcthreadstaticBaseNoctor;
9014             break;
9015         case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR:
9016             vnf = VNF_GetsharedNongcthreadstaticBaseNoctor;
9017             break;
9018         case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS:
9019             vnf = VNF_GetsharedGcthreadstaticBaseDynamicclass;
9020             break;
9021         case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS:
9022             vnf = VNF_GetsharedNongcthreadstaticBaseDynamicclass;
9023             break;
9024         case CORINFO_HELP_GETSTATICFIELDADDR_CONTEXT:
9025             vnf = VNF_GetStaticAddrContext;
9026             break;
9027         case CORINFO_HELP_GETSTATICFIELDADDR_TLS:
9028             vnf = VNF_GetStaticAddrTLS;
9029             break;
9030
9031         case CORINFO_HELP_RUNTIMEHANDLE_METHOD:
9032         case CORINFO_HELP_RUNTIMEHANDLE_METHOD_LOG:
9033             vnf = VNF_RuntimeHandleMethod;
9034             break;
9035
9036         case CORINFO_HELP_RUNTIMEHANDLE_CLASS:
9037         case CORINFO_HELP_RUNTIMEHANDLE_CLASS_LOG:
9038             vnf = VNF_RuntimeHandleClass;
9039             break;
9040
9041         case CORINFO_HELP_STRCNS:
9042             vnf = VNF_StrCns;
9043             break;
9044
9045         case CORINFO_HELP_CHKCASTCLASS:
9046         case CORINFO_HELP_CHKCASTCLASS_SPECIAL:
9047         case CORINFO_HELP_CHKCASTARRAY:
9048         case CORINFO_HELP_CHKCASTINTERFACE:
9049         case CORINFO_HELP_CHKCASTANY:
9050             vnf = VNF_CastClass;
9051             break;
9052
9053         case CORINFO_HELP_READYTORUN_CHKCAST:
9054             vnf = VNF_ReadyToRunCastClass;
9055             break;
9056
9057         case CORINFO_HELP_ISINSTANCEOFCLASS:
9058         case CORINFO_HELP_ISINSTANCEOFINTERFACE:
9059         case CORINFO_HELP_ISINSTANCEOFARRAY:
9060         case CORINFO_HELP_ISINSTANCEOFANY:
9061             vnf = VNF_IsInstanceOf;
9062             break;
9063
9064         case CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE:
9065             vnf = VNF_TypeHandleToRuntimeType;
9066             break;
9067
9068         case CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE:
9069             vnf = VNF_TypeHandleToRuntimeTypeHandle;
9070             break;
9071
9072         case CORINFO_HELP_ARE_TYPES_EQUIVALENT:
9073             vnf = VNF_AreTypesEquivalent;
9074             break;
9075
9076         case CORINFO_HELP_READYTORUN_ISINSTANCEOF:
9077             vnf = VNF_ReadyToRunIsInstanceOf;
9078             break;
9079
9080         case CORINFO_HELP_LDELEMA_REF:
9081             vnf = VNF_LdElemA;
9082             break;
9083
9084         case CORINFO_HELP_UNBOX:
9085             vnf = VNF_Unbox;
9086             break;
9087
9088         // A constant within any method.
9089         case CORINFO_HELP_GETCURRENTMANAGEDTHREADID:
9090             vnf = VNF_ManagedThreadId;
9091             break;
9092
9093         case CORINFO_HELP_GETREFANY:
9094             // TODO-CQ: This should really be interpreted as just a struct field reference, in terms of values.
9095             vnf = VNF_GetRefanyVal;
9096             break;
9097
9098         case CORINFO_HELP_GETCLASSFROMMETHODPARAM:
9099             vnf = VNF_GetClassFromMethodParam;
9100             break;
9101
9102         case CORINFO_HELP_GETSYNCFROMCLASSHANDLE:
9103             vnf = VNF_GetSyncFromClassHandle;
9104             break;
9105
9106         case CORINFO_HELP_LOOP_CLONE_CHOICE_ADDR:
9107             vnf = VNF_LoopCloneChoiceAddr;
9108             break;
9109
9110         case CORINFO_HELP_BOX:
9111             vnf = VNF_Box;
9112             break;
9113
9114         case CORINFO_HELP_BOX_NULLABLE:
9115             vnf = VNF_BoxNullable;
9116             break;
9117
9118         default:
9119             unreached();
9120     }
9121
9122     assert(vnf != VNF_Boundary);
9123     return vnf;
9124 }
9125
9126 bool Compiler::fgValueNumberHelperCall(GenTreeCall* call)
9127 {
9128     CorInfoHelpFunc helpFunc    = eeGetHelperNum(call->gtCallMethHnd);
9129     bool            pure        = s_helperCallProperties.IsPure(helpFunc);
9130     bool            isAlloc     = s_helperCallProperties.IsAllocator(helpFunc);
9131     bool            modHeap     = s_helperCallProperties.MutatesHeap(helpFunc);
9132     bool            mayRunCctor = s_helperCallProperties.MayRunCctor(helpFunc);
9133     bool            noThrow     = s_helperCallProperties.NoThrow(helpFunc);
9134
9135     ValueNumPair vnpExc = ValueNumStore::VNPForEmptyExcSet();
9136
9137     // If the JIT helper can throw an exception make sure that we fill in
9138     // vnpExc with a Value Number that represents the exception(s) that can be thrown.
9139     if (!noThrow)
9140     {
9141         // If the helper is known to only throw only one particular exception
9142         // we can set vnpExc to that exception, otherwise we conservatively
9143         // model the JIT helper as possibly throwing multiple different exceptions
9144         //
9145         switch (helpFunc)
9146         {
9147             case CORINFO_HELP_OVERFLOW:
9148                 // This helper always throws the VNF_OverflowExc exception
9149                 vnpExc = vnStore->VNPExcSetSingleton(
9150                     vnStore->VNPairForFunc(TYP_REF, VNF_OverflowExc, vnStore->VNPForVoid()));
9151                 break;
9152
9153             default:
9154                 // Setup vnpExc with the information that multiple different exceptions
9155                 // could be generated by this helper
9156                 vnpExc = vnStore->VNPExcSetSingleton(vnStore->VNPairForFunc(TYP_REF, VNF_HelperMultipleExc));
9157         }
9158     }
9159
9160     ValueNumPair vnpNorm;
9161
9162     if (call->TypeGet() == TYP_VOID)
9163     {
9164         vnpNorm = ValueNumStore::VNPForVoid();
9165     }
9166     else
9167     {
9168         // TODO-CQ: this is a list of helpers we're going to treat as non-pure,
9169         // because they raise complications.  Eventually, we need to handle those complications...
9170         bool needsFurtherWork = false;
9171         switch (helpFunc)
9172         {
9173             case CORINFO_HELP_NEW_MDARR:
9174                 // This is a varargs helper.  We need to represent the array shape in the VN world somehow.
9175                 needsFurtherWork = true;
9176                 break;
9177             default:
9178                 break;
9179         }
9180
9181         if (!needsFurtherWork && (pure || isAlloc))
9182         {
9183             VNFunc vnf = fgValueNumberJitHelperMethodVNFunc(helpFunc);
9184
9185             if (mayRunCctor)
9186             {
9187                 if ((call->gtFlags & GTF_CALL_HOISTABLE) == 0)
9188                 {
9189                     modHeap = true;
9190                 }
9191             }
9192
9193             fgValueNumberHelperCallFunc(call, vnf, vnpExc);
9194             return modHeap;
9195         }
9196         else
9197         {
9198             vnpNorm.SetBoth(vnStore->VNForExpr(compCurBB, call->TypeGet()));
9199         }
9200     }
9201
9202     call->gtVNPair = vnStore->VNPWithExc(vnpNorm, vnpExc);
9203     return modHeap;
9204 }
9205
9206 //--------------------------------------------------------------------------------
9207 // fgValueNumberAddExceptionSetForIndirection
9208 //         - Adds the exception sets for the current tree node
9209 //           which is performing a memory indirection operation
9210 //
9211 // Arguments:
9212 //    tree       - The current GenTree node,
9213 //                 It must be some kind of an indirection node
9214 //                 or have an implicit indirection
9215 //    baseAddr   - The address that we are indirecting
9216 //
9217 // Return Value:
9218 //               - The tree's gtVNPair is updated to include the VNF_nullPtrExc
9219 //                 exception set.  We calculate a base address to use as the
9220 //                 argument to the VNF_nullPtrExc function.
9221 //
9222 // Notes:        - The calculation of the base address removes any constant
9223 //                 offsets, so that obj.x and obj.y will both have obj as
9224 //                 their base address.
9225 //                 For arrays the base address currently includes the
9226 //                 index calculations.
9227 //
9228 void Compiler::fgValueNumberAddExceptionSetForIndirection(GenTree* tree, GenTree* baseAddr)
9229 {
9230     // We should have tree that a unary indirection or a tree node with an implicit indirection
9231     assert(tree->OperIsUnary() || tree->OperIsImplicitIndir());
9232
9233     // We evaluate the baseAddr ValueNumber further in order
9234     // to obtain a better value to use for the null check exeception.
9235     //
9236     ValueNumPair baseVNP = baseAddr->gtVNPair;
9237     ValueNum     baseLVN = baseVNP.GetLiberal();
9238     ValueNum     baseCVN = baseVNP.GetConservative();
9239     ssize_t      offsetL = 0;
9240     ssize_t      offsetC = 0;
9241     VNFuncApp    funcAttr;
9242
9243     while (vnStore->GetVNFunc(baseLVN, &funcAttr) && (funcAttr.m_func == (VNFunc)GT_ADD) &&
9244            (vnStore->TypeOfVN(baseLVN) == TYP_BYREF))
9245     {
9246         // The arguments in value numbering functions are sorted in increasing order
9247         // Thus either arg could be the constant.
9248         if (vnStore->IsVNConstant(funcAttr.m_args[0]) && varTypeIsIntegral(vnStore->TypeOfVN(funcAttr.m_args[0])))
9249         {
9250             offsetL += vnStore->CoercedConstantValue<ssize_t>(funcAttr.m_args[0]);
9251             baseLVN = funcAttr.m_args[1];
9252         }
9253         else if (vnStore->IsVNConstant(funcAttr.m_args[1]) && varTypeIsIntegral(vnStore->TypeOfVN(funcAttr.m_args[1])))
9254         {
9255             offsetL += vnStore->CoercedConstantValue<ssize_t>(funcAttr.m_args[1]);
9256             baseLVN = funcAttr.m_args[0];
9257         }
9258         else // neither argument is a constant
9259         {
9260             break;
9261         }
9262
9263         if (fgIsBigOffset(offsetL))
9264         {
9265             // Failure: Exit this loop if we have a "big" offset
9266
9267             // reset baseLVN back to the full address expression
9268             baseLVN = baseVNP.GetLiberal();
9269             break;
9270         }
9271     }
9272
9273     while (vnStore->GetVNFunc(baseCVN, &funcAttr) && (funcAttr.m_func == (VNFunc)GT_ADD) &&
9274            (vnStore->TypeOfVN(baseCVN) == TYP_BYREF))
9275     {
9276         // The arguments in value numbering functions are sorted in increasing order
9277         // Thus either arg could be the constant.
9278         if (vnStore->IsVNConstant(funcAttr.m_args[0]) && varTypeIsIntegral(vnStore->TypeOfVN(funcAttr.m_args[0])))
9279         {
9280             offsetL += vnStore->CoercedConstantValue<ssize_t>(funcAttr.m_args[0]);
9281             baseCVN = funcAttr.m_args[1];
9282         }
9283         else if (vnStore->IsVNConstant(funcAttr.m_args[1]) && varTypeIsIntegral(vnStore->TypeOfVN(funcAttr.m_args[1])))
9284         {
9285             offsetC += vnStore->CoercedConstantValue<ssize_t>(funcAttr.m_args[1]);
9286             baseCVN = funcAttr.m_args[0];
9287         }
9288         else // neither argument is a constant
9289         {
9290             break;
9291         }
9292
9293         if (fgIsBigOffset(offsetC))
9294         {
9295             // Failure: Exit this loop if we have a "big" offset
9296
9297             // reset baseCVN back to the full address expression
9298             baseCVN = baseVNP.GetConservative();
9299             break;
9300         }
9301     }
9302
9303     // Create baseVNP, from the values we just computed,
9304     baseVNP = ValueNumPair(baseLVN, baseCVN);
9305
9306     // Unpack, Norm,Exc for the tree's op1 VN
9307     ValueNumPair vnpBaseNorm;
9308     ValueNumPair vnpBaseExc;
9309     vnStore->VNPUnpackExc(baseVNP, &vnpBaseNorm, &vnpBaseExc);
9310
9311     // The Norm VN for op1 is used to create the NullPtrExc
9312     ValueNumPair excChkSet = vnStore->VNPExcSetSingleton(vnStore->VNPairForFunc(TYP_REF, VNF_NullPtrExc, vnpBaseNorm));
9313
9314     // Combine the excChkSet with exception set of op1
9315     ValueNumPair excSetBoth = vnStore->VNPExcSetUnion(excChkSet, vnpBaseExc);
9316
9317     // Retrieve the Normal VN for tree, note that it may be NoVN, so we handle that case
9318     ValueNumPair vnpNorm = vnStore->VNPNormalPair(tree->gtVNPair);
9319
9320     // For as GT_IND on the lhs of an assignment we will get a NoVN value
9321     if (vnpNorm.GetLiberal() == ValueNumStore::NoVN)
9322     {
9323         // Use the special Void VN value instead.
9324         vnpNorm = vnStore->VNPForVoid();
9325     }
9326     tree->gtVNPair = vnStore->VNPWithExc(vnpNorm, excSetBoth);
9327 }
9328
9329 //--------------------------------------------------------------------------------
9330 // fgValueNumberAddExceptionSetForDivison
9331 //         - Adds the exception sets for the current tree node
9332 //           which is performing an integer division operation
9333 //
9334 // Arguments:
9335 //    tree       - The current GenTree node,
9336 //                 It must be a node that performs an integer division
9337 //
9338 // Return Value:
9339 //               - The tree's gtVNPair is updated to include
9340 //                 VNF_DivideByZeroExc and VNF_ArithmeticExc,
9341 //                 We will omit one or both of them when the operation
9342 //                 has constants arguments that preclude the exception.
9343 //
9344 void Compiler::fgValueNumberAddExceptionSetForDivision(GenTree* tree)
9345 {
9346     genTreeOps oper = tree->OperGet();
9347
9348     // A Divide By Zero exception may be possible.
9349     // The divisor is held in tree->gtOp.gtOp2
9350     //
9351     bool isUnsignedOper         = (oper == GT_UDIV) || (oper == GT_UMOD);
9352     bool needDivideByZeroExcLib = true;
9353     bool needDivideByZeroExcCon = true;
9354     bool needArithmeticExcLib   = !isUnsignedOper; // Overflow isn't possible for unsigned divide
9355     bool needArithmeticExcCon   = !isUnsignedOper;
9356
9357     // Determine if we have a 32-bit or 64-bit divide operation
9358     var_types typ = genActualType(tree->TypeGet());
9359     assert((typ == TYP_INT) || (typ == TYP_LONG));
9360
9361     // Retrieve the Norm VN for op2 to use it for the DivideByZeroExc
9362     ValueNumPair vnpOp2Norm   = vnStore->VNPNormalPair(tree->gtOp.gtOp2->gtVNPair);
9363     ValueNum     vnOp2NormLib = vnpOp2Norm.GetLiberal();
9364     ValueNum     vnOp2NormCon = vnpOp2Norm.GetConservative();
9365
9366     if (typ == TYP_INT)
9367     {
9368         if (vnStore->IsVNConstant(vnOp2NormLib))
9369         {
9370             INT32 kVal = vnStore->ConstantValue<INT32>(vnOp2NormLib);
9371             if (kVal != 0)
9372             {
9373                 needDivideByZeroExcLib = false;
9374             }
9375             if (!isUnsignedOper && (kVal != -1))
9376             {
9377                 needArithmeticExcLib = false;
9378             }
9379         }
9380         if (vnStore->IsVNConstant(vnOp2NormCon))
9381         {
9382             INT32 kVal = vnStore->ConstantValue<INT32>(vnOp2NormCon);
9383             if (kVal != 0)
9384             {
9385                 needDivideByZeroExcCon = false;
9386             }
9387             if (!isUnsignedOper && (kVal != -1))
9388             {
9389                 needArithmeticExcCon = false;
9390             }
9391         }
9392     }
9393     else // (typ == TYP_LONG)
9394     {
9395         if (vnStore->IsVNConstant(vnOp2NormLib))
9396         {
9397             INT64 kVal = vnStore->ConstantValue<INT64>(vnOp2NormLib);
9398             if (kVal != 0)
9399             {
9400                 needDivideByZeroExcLib = false;
9401             }
9402             if (!isUnsignedOper && (kVal != -1))
9403             {
9404                 needArithmeticExcLib = false;
9405             }
9406         }
9407         if (vnStore->IsVNConstant(vnOp2NormCon))
9408         {
9409             INT64 kVal = vnStore->ConstantValue<INT64>(vnOp2NormCon);
9410             if (kVal != 0)
9411             {
9412                 needDivideByZeroExcCon = false;
9413             }
9414             if (!isUnsignedOper && (kVal != -1))
9415             {
9416                 needArithmeticExcCon = false;
9417             }
9418         }
9419     }
9420
9421     // Retrieve the Norm VN for op1 to use it for the ArithmeticExc
9422     ValueNumPair vnpOp1Norm   = vnStore->VNPNormalPair(tree->gtOp.gtOp1->gtVNPair);
9423     ValueNum     vnOp1NormLib = vnpOp1Norm.GetLiberal();
9424     ValueNum     vnOp1NormCon = vnpOp1Norm.GetConservative();
9425
9426     if (needArithmeticExcLib || needArithmeticExcCon)
9427     {
9428         if (typ == TYP_INT)
9429         {
9430             if (vnStore->IsVNConstant(vnOp1NormLib))
9431             {
9432                 INT32 kVal = vnStore->ConstantValue<INT32>(vnOp1NormLib);
9433
9434                 if (!isUnsignedOper && (kVal != INT32_MIN))
9435                 {
9436                     needArithmeticExcLib = false;
9437                 }
9438             }
9439             if (vnStore->IsVNConstant(vnOp1NormCon))
9440             {
9441                 INT32 kVal = vnStore->ConstantValue<INT32>(vnOp1NormCon);
9442
9443                 if (!isUnsignedOper && (kVal != INT32_MIN))
9444                 {
9445                     needArithmeticExcCon = false;
9446                 }
9447             }
9448         }
9449         else // (typ == TYP_LONG)
9450         {
9451             if (vnStore->IsVNConstant(vnOp1NormLib))
9452             {
9453                 INT64 kVal = vnStore->ConstantValue<INT64>(vnOp1NormLib);
9454
9455                 if (!isUnsignedOper && (kVal != INT64_MIN))
9456                 {
9457                     needArithmeticExcLib = false;
9458                 }
9459             }
9460             if (vnStore->IsVNConstant(vnOp1NormCon))
9461             {
9462                 INT64 kVal = vnStore->ConstantValue<INT64>(vnOp1NormCon);
9463
9464                 if (!isUnsignedOper && (kVal != INT64_MIN))
9465                 {
9466                     needArithmeticExcCon = false;
9467                 }
9468             }
9469         }
9470     }
9471
9472     // Unpack, Norm,Exc for the tree's VN
9473     ValueNumPair vnpTreeNorm;
9474     ValueNumPair vnpTreeExc;
9475     ValueNumPair vnpDivZeroExc = ValueNumStore::VNPForEmptyExcSet();
9476     ValueNumPair vnpArithmExc  = ValueNumStore::VNPForEmptyExcSet();
9477
9478     vnStore->VNPUnpackExc(tree->gtVNPair, &vnpTreeNorm, &vnpTreeExc);
9479
9480     if (needDivideByZeroExcLib)
9481     {
9482         vnpDivZeroExc.SetLiberal(
9483             vnStore->VNExcSetSingleton(vnStore->VNForFunc(TYP_REF, VNF_DivideByZeroExc, vnOp2NormLib)));
9484     }
9485     if (needDivideByZeroExcCon)
9486     {
9487         vnpDivZeroExc.SetConservative(
9488             vnStore->VNExcSetSingleton(vnStore->VNForFunc(TYP_REF, VNF_DivideByZeroExc, vnOp2NormCon)));
9489     }
9490     if (needArithmeticExcLib)
9491     {
9492         vnpArithmExc.SetLiberal(
9493             vnStore->VNExcSetSingleton(vnStore->VNForFunc(TYP_REF, VNF_ArithmeticExc, vnOp1NormLib, vnOp2NormLib)));
9494     }
9495     if (needArithmeticExcCon)
9496     {
9497         vnpArithmExc.SetConservative(
9498             vnStore->VNExcSetSingleton(vnStore->VNForFunc(TYP_REF, VNF_ArithmeticExc, vnOp1NormLib, vnOp2NormCon)));
9499     }
9500
9501     // Combine vnpDivZeroExc with the exception set of tree
9502     ValueNumPair newExcSet = vnStore->VNPExcSetUnion(vnpTreeExc, vnpDivZeroExc);
9503     // Combine vnpArithmExc with the newExcSet
9504     newExcSet = vnStore->VNPExcSetUnion(newExcSet, vnpArithmExc);
9505
9506     // Updated VN for tree, it now includes DivideByZeroExc and/or ArithmeticExc
9507     tree->gtVNPair = vnStore->VNPWithExc(vnpTreeNorm, newExcSet);
9508 }
9509
9510 //--------------------------------------------------------------------------------
9511 // fgValueNumberAddExceptionSetForOverflow
9512 //         - Adds the exception set for the current tree node
9513 //           which is performing an overflow checking math operation
9514 //
9515 // Arguments:
9516 //    tree       - The current GenTree node,
9517 //                 It must be a node that performs an overflow
9518 //                 checking math operation
9519 //
9520 // Return Value:
9521 //               - The tree's gtVNPair is updated to include the VNF_OverflowExc
9522 //                 exception set.
9523 //
9524 void Compiler::fgValueNumberAddExceptionSetForOverflow(GenTree* tree)
9525 {
9526     assert(tree->gtOverflowEx());
9527
9528     // We should only be dealing with an Overflow checking ALU operation.
9529     VNFunc vnf = GetVNFuncForNode(tree);
9530     assert((vnf >= VNF_ADD_OVF) && (vnf <= VNF_MUL_UN_OVF));
9531
9532     // Unpack, Norm,Exc for the tree's VN
9533     //
9534     ValueNumPair vnpTreeNorm;
9535     ValueNumPair vnpTreeExc;
9536
9537     vnStore->VNPUnpackExc(tree->gtVNPair, &vnpTreeNorm, &vnpTreeExc);
9538
9539 #ifdef DEBUG
9540     // The normal value number function should be the same overflow checking ALU operation as 'vnf'
9541     VNFuncApp treeNormFuncApp;
9542     assert(vnStore->GetVNFunc(vnpTreeNorm.GetLiberal(), &treeNormFuncApp) && (treeNormFuncApp.m_func == vnf));
9543 #endif // DEBUG
9544
9545     // Overflow-checking operations add an overflow exception
9546     // The normal result is used as the input argument for the OverflowExc
9547     ValueNumPair overflowExcSet =
9548         vnStore->VNPExcSetSingleton(vnStore->VNPairForFunc(TYP_REF, VNF_OverflowExc, vnpTreeNorm));
9549
9550     // Combine the new Overflow exception with the original exception set of tree
9551     ValueNumPair newExcSet = vnStore->VNPExcSetUnion(vnpTreeExc, overflowExcSet);
9552
9553     // Updated VN for tree, it now includes Overflow exception
9554     tree->gtVNPair = vnStore->VNPWithExc(vnpTreeNorm, newExcSet);
9555 }
9556
9557 //--------------------------------------------------------------------------------
9558 // fgValueNumberAddExceptionSetForCkFinite
9559 //         - Adds the exception set for the current tree node
9560 //           which is a CkFinite operation
9561 //
9562 // Arguments:
9563 //    tree       - The current GenTree node,
9564 //                 It must be a CkFinite node
9565 //
9566 // Return Value:
9567 //               - The tree's gtVNPair is updated to include the VNF_ArithmeticExc
9568 //                 exception set.
9569 //
9570 void Compiler::fgValueNumberAddExceptionSetForCkFinite(GenTree* tree)
9571 {
9572     // We should only be dealing with an check finite operation.
9573     assert(tree->OperGet() == GT_CKFINITE);
9574
9575     // Unpack, Norm,Exc for the tree's VN
9576     //
9577     ValueNumPair vnpTreeNorm;
9578     ValueNumPair vnpTreeExc;
9579     ValueNumPair newExcSet;
9580
9581     vnStore->VNPUnpackExc(tree->gtVNPair, &vnpTreeNorm, &vnpTreeExc);
9582
9583     // ckfinite adds an Arithmetic exception
9584     // The normal result is used as the input argument for the ArithmeticExc
9585     ValueNumPair arithmeticExcSet =
9586         vnStore->VNPExcSetSingleton(vnStore->VNPairForFunc(TYP_REF, VNF_ArithmeticExc, vnpTreeNorm));
9587
9588     // Combine the new Arithmetic exception with the original exception set of tree
9589     newExcSet = vnStore->VNPExcSetUnion(vnpTreeExc, arithmeticExcSet);
9590
9591     // Updated VN for tree, it now includes Arithmetic exception
9592     tree->gtVNPair = vnStore->VNPWithExc(vnpTreeNorm, newExcSet);
9593 }
9594
9595 //--------------------------------------------------------------------------------
9596 // fgValueNumberAddExceptionSet
9597 //         - Adds any exception sets needed for the current tree node
9598 //
9599 // Arguments:
9600 //    tree       - The current GenTree node,
9601 //
9602 // Return Value:
9603 //               - The tree's gtVNPair is updated to include the exception sets.
9604 //
9605 // Notes:        - This method relies upon OperMayTHrow to determine if we need
9606 //                 to add an exception set.  If OPerMayThrow returns false no
9607 //                 exception set will be added.
9608 //
9609 void Compiler::fgValueNumberAddExceptionSet(GenTree* tree)
9610 {
9611     if (tree->OperMayThrow(this))
9612     {
9613         switch (tree->OperGet())
9614         {
9615             case GT_CAST: // A cast with an overflow check
9616                 break;    // Already handled by VNPairForCast()
9617
9618             case GT_ADD: // An Overflow checking ALU operation
9619             case GT_SUB:
9620             case GT_MUL:
9621                 fgValueNumberAddExceptionSetForOverflow(tree);
9622                 break;
9623
9624             case GT_LCLHEAP:
9625                 // It is not necessary to model the StackOverflow exception for GT_LCLHEAP
9626                 break;
9627
9628             case GT_INTRINSIC:
9629                 // ToDo: model the exceptions for Intrinsics
9630                 break;
9631
9632             case GT_IND: // Implicit null check.
9633                 if ((tree->gtFlags & GTF_IND_ASG_LHS) != 0)
9634                 {
9635                     // Don't add exception set on LHS of assignment
9636                     break;
9637                 }
9638                 __fallthrough;
9639
9640             case GT_BLK:
9641             case GT_OBJ:
9642             case GT_DYN_BLK:
9643             case GT_NULLCHECK:
9644                 fgValueNumberAddExceptionSetForIndirection(tree, tree->AsIndir()->Addr());
9645                 break;
9646
9647             case GT_ARR_LENGTH:
9648                 fgValueNumberAddExceptionSetForIndirection(tree, tree->AsArrLen()->ArrRef());
9649                 break;
9650
9651             case GT_ARR_ELEM:
9652                 fgValueNumberAddExceptionSetForIndirection(tree, tree->gtArrElem.gtArrObj);
9653                 break;
9654
9655             case GT_ARR_INDEX:
9656                 fgValueNumberAddExceptionSetForIndirection(tree, tree->gtArrIndex.ArrObj());
9657                 break;
9658
9659             case GT_ARR_OFFSET:
9660                 fgValueNumberAddExceptionSetForIndirection(tree, tree->gtArrOffs.gtArrObj);
9661                 break;
9662
9663             case GT_DIV:
9664             case GT_UDIV:
9665             case GT_MOD:
9666             case GT_UMOD:
9667                 fgValueNumberAddExceptionSetForDivision(tree);
9668                 break;
9669
9670             case GT_CKFINITE:
9671                 fgValueNumberAddExceptionSetForCkFinite(tree);
9672                 break;
9673
9674             default:
9675                 assert(!"Handle this oper in fgValueNumberAddExceptionSet");
9676                 break;
9677         }
9678     }
9679 }
9680
9681 #ifdef DEBUG
9682 // This method asserts that SSA name constraints specified are satisfied.
9683 // Until we figure out otherwise, all VN's are assumed to be liberal.
9684 // TODO-Cleanup: new JitTestLabels for lib vs cons vs both VN classes?
9685 void Compiler::JitTestCheckVN()
9686 {
9687     typedef JitHashTable<ssize_t, JitSmallPrimitiveKeyFuncs<ssize_t>, ValueNum>  LabelToVNMap;
9688     typedef JitHashTable<ValueNum, JitSmallPrimitiveKeyFuncs<ValueNum>, ssize_t> VNToLabelMap;
9689
9690     // If we have no test data, early out.
9691     if (m_nodeTestData == nullptr)
9692     {
9693         return;
9694     }
9695
9696     NodeToTestDataMap* testData = GetNodeTestData();
9697
9698     // First we have to know which nodes in the tree are reachable.
9699     typedef JitHashTable<GenTree*, JitPtrKeyFuncs<GenTree>, int> NodeToIntMap;
9700     NodeToIntMap* reachable = FindReachableNodesInNodeTestData();
9701
9702     LabelToVNMap* labelToVN = new (getAllocatorDebugOnly()) LabelToVNMap(getAllocatorDebugOnly());
9703     VNToLabelMap* vnToLabel = new (getAllocatorDebugOnly()) VNToLabelMap(getAllocatorDebugOnly());
9704
9705     if (verbose)
9706     {
9707         printf("\nJit Testing: Value numbering.\n");
9708     }
9709     for (NodeToTestDataMap::KeyIterator ki = testData->Begin(); !ki.Equal(testData->End()); ++ki)
9710     {
9711         TestLabelAndNum tlAndN;
9712         GenTree*        node   = ki.Get();
9713         ValueNum        nodeVN = node->GetVN(VNK_Liberal);
9714
9715         bool b = testData->Lookup(node, &tlAndN);
9716         assert(b);
9717         if (tlAndN.m_tl == TL_VN || tlAndN.m_tl == TL_VNNorm)
9718         {
9719             int dummy;
9720             if (!reachable->Lookup(node, &dummy))
9721             {
9722                 printf("Node ");
9723                 Compiler::printTreeID(node);
9724                 printf(" had a test constraint declared, but has become unreachable at the time the constraint is "
9725                        "tested.\n"
9726                        "(This is probably as a result of some optimization -- \n"
9727                        "you may need to modify the test case to defeat this opt.)\n");
9728                 assert(false);
9729             }
9730
9731             if (verbose)
9732             {
9733                 printf("  Node ");
9734                 Compiler::printTreeID(node);
9735                 printf(" -- VN class %d.\n", tlAndN.m_num);
9736             }
9737
9738             if (tlAndN.m_tl == TL_VNNorm)
9739             {
9740                 nodeVN = vnStore->VNNormalValue(nodeVN);
9741             }
9742
9743             ValueNum vn;
9744             if (labelToVN->Lookup(tlAndN.m_num, &vn))
9745             {
9746                 if (verbose)
9747                 {
9748                     printf("      Already in hash tables.\n");
9749                 }
9750                 // The mapping(s) must be one-to-one: if the label has a mapping, then the ssaNm must, as well.
9751                 ssize_t num2;
9752                 bool    b = vnToLabel->Lookup(vn, &num2);
9753                 // And the mappings must be the same.
9754                 if (tlAndN.m_num != num2)
9755                 {
9756                     printf("Node: ");
9757                     Compiler::printTreeID(node);
9758                     printf(", with value number " FMT_VN ", was declared in VN class %d,\n", nodeVN, tlAndN.m_num);
9759                     printf("but this value number " FMT_VN
9760                            " has already been associated with a different SSA name class: %d.\n",
9761                            vn, num2);
9762                     assert(false);
9763                 }
9764                 // And the current node must be of the specified SSA family.
9765                 if (nodeVN != vn)
9766                 {
9767                     printf("Node: ");
9768                     Compiler::printTreeID(node);
9769                     printf(", " FMT_VN " was declared in SSA name class %d,\n", nodeVN, tlAndN.m_num);
9770                     printf("but that name class was previously bound to a different value number: " FMT_VN ".\n", vn);
9771                     assert(false);
9772                 }
9773             }
9774             else
9775             {
9776                 ssize_t num;
9777                 // The mapping(s) must be one-to-one: if the label has no mapping, then the ssaNm may not, either.
9778                 if (vnToLabel->Lookup(nodeVN, &num))
9779                 {
9780                     printf("Node: ");
9781                     Compiler::printTreeID(node);
9782                     printf(", " FMT_VN " was declared in value number class %d,\n", nodeVN, tlAndN.m_num);
9783                     printf(
9784                         "but this value number has already been associated with a different value number class: %d.\n",
9785                         num);
9786                     assert(false);
9787                 }
9788                 // Add to both mappings.
9789                 labelToVN->Set(tlAndN.m_num, nodeVN);
9790                 vnToLabel->Set(nodeVN, tlAndN.m_num);
9791                 if (verbose)
9792                 {
9793                     printf("      added to hash tables.\n");
9794                 }
9795             }
9796         }
9797     }
9798 }
9799
9800 void Compiler::vnpPrint(ValueNumPair vnp, unsigned level)
9801 {
9802     if (vnp.BothEqual())
9803     {
9804         vnPrint(vnp.GetLiberal(), level);
9805     }
9806     else
9807     {
9808         printf("<l:");
9809         vnPrint(vnp.GetLiberal(), level);
9810         printf(", c:");
9811         vnPrint(vnp.GetConservative(), level);
9812         printf(">");
9813     }
9814 }
9815
9816 void Compiler::vnPrint(ValueNum vn, unsigned level)
9817 {
9818
9819     if (ValueNumStore::isReservedVN(vn))
9820     {
9821         printf(ValueNumStore::reservedName(vn));
9822     }
9823     else
9824     {
9825         printf(FMT_VN, vn);
9826         if (level > 0)
9827         {
9828             vnStore->vnDump(this, vn);
9829         }
9830     }
9831 }
9832
9833 #endif // DEBUG
9834
9835 // Methods of ValueNumPair.
9836 ValueNumPair::ValueNumPair() : m_liberal(ValueNumStore::NoVN), m_conservative(ValueNumStore::NoVN)
9837 {
9838 }
9839
9840 bool ValueNumPair::BothDefined() const
9841 {
9842     return (m_liberal != ValueNumStore::NoVN) && (m_conservative != ValueNumStore::NoVN);
9843 }