Fix reading Time zone rules using Julian days (#17672)
[platform/upstream/coreclr.git] / src / jit / valuenum.h
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 // Defines the class "ValueNumStore", which maintains value numbers for a compilation.
6
7 // Recall that "value numbering" assigns an integer value number to each expression.  The "value
8 // number property" is that two expressions with the same value number will evaluate to the same value
9 // at runtime.  Expressions with different value numbers may or may not be equivalent.  This property
10 // of value numbers has obvious applications in redundancy-elimination optimizations.
11 //
12 // Since value numbers give us a way of talking about the (immutable) values to which expressions
13 // evaluate, they provide a good "handle" to use for attributing properties to values.  For example,
14 // we might note that some value number represents some particular integer constant -- which has obvious
15 // application to constant propagation.  Or that we know the exact type of some object reference,
16 // which might be used in devirtualization.
17 //
18 // Finally, we will also use value numbers to express control-flow-dependent assertions.  Some test may
19 // imply that after the test, something new is known about a value: that an object reference is non-null
20 // after a dereference (since control flow continued because no exception was thrown); that an integer value
21 // is restricted to some subrange in after a comparison test; etc.
22
23 /*****************************************************************************/
24 #ifndef _VALUENUM_H_
25 #define _VALUENUM_H_
26 /*****************************************************************************/
27
28 #include "vartype.h"
29 // For "GT_COUNT"
30 #include "gentree.h"
31 // Defines the type ValueNum.
32 #include "valuenumtype.h"
33 // Defines the type SmallHashTable.
34 #include "smallhash.h"
35
36 // A "ValueNumStore" represents the "universe" of value numbers used in a single
37 // compilation.
38
39 // All members of the enumeration genTreeOps are also members of VNFunc.
40 // (Though some of these may be labeled "illegal").
41 enum VNFunc
42 {
43     // Implicitly, elements of genTreeOps here.
44     VNF_Boundary = GT_COUNT,
45 #define ValueNumFuncDef(nm, arity, commute, knownNonNull, sharedStatic) VNF_##nm,
46 #include "valuenumfuncs.h"
47     VNF_COUNT
48 };
49
50 // Given an "oper" and associated flags with it, transform the oper into a
51 // more accurate oper that can be used in evaluation. For example, (GT_ADD, unsigned)
52 // transforms to GT_ADD_UN.
53 VNFunc GetVNFuncForOper(genTreeOps oper, bool isUnsigned);
54
55 // An instance of this struct represents an application of the function symbol
56 // "m_func" to the first "m_arity" (<= 4) argument values in "m_args."
57 struct VNFuncApp
58 {
59     VNFunc   m_func;
60     unsigned m_arity;
61     ValueNum m_args[4];
62
63     bool Equals(const VNFuncApp& funcApp)
64     {
65         if (m_func != funcApp.m_func)
66         {
67             return false;
68         }
69         if (m_arity != funcApp.m_arity)
70         {
71             return false;
72         }
73         for (unsigned i = 0; i < m_arity; i++)
74         {
75             if (m_args[i] != funcApp.m_args[i])
76             {
77                 return false;
78             }
79         }
80         return true;
81     }
82 };
83
84 // A unique prefix character to use when dumping a tree's gtVN in the tree dumps
85 // We use this together with string concatenation to put this in printf format strings
86 // static const char* const VN_DumpPrefix = "$";
87 #define STR_VN "$"
88
89 class ValueNumStore
90 {
91
92 public:
93     // We will reserve "max unsigned" to represent "not a value number", for maps that might start uninitialized.
94     static const ValueNum NoVN = UINT32_MAX;
95     // A second special value, used to indicate that a function evaluation would cause infinite recursion.
96     static const ValueNum RecursiveVN = UINT32_MAX - 1;
97
98     // ==================================================================================================
99     // VNMap - map from something to ValueNum, where something is typically a constant value or a VNFunc
100     //         This class has two purposes - to abstract the implementation and to validate the ValueNums
101     //         being stored or retrieved.
102     template <class fromType, class keyfuncs = JitLargePrimitiveKeyFuncs<fromType>>
103     class VNMap : public JitHashTable<fromType, keyfuncs, ValueNum>
104     {
105     public:
106         VNMap(CompAllocator* alloc) : JitHashTable<fromType, keyfuncs, ValueNum>(alloc)
107         {
108         }
109         ~VNMap()
110         {
111             ~VNMap<fromType, keyfuncs>::JitHashTable();
112         }
113
114         bool Set(fromType k, ValueNum val)
115         {
116             assert(val != RecursiveVN);
117             return JitHashTable<fromType, keyfuncs, ValueNum>::Set(k, val);
118         }
119         bool Lookup(fromType k, ValueNum* pVal = nullptr) const
120         {
121             bool result = JitHashTable<fromType, keyfuncs, ValueNum>::Lookup(k, pVal);
122             assert(!result || *pVal != RecursiveVN);
123             return result;
124         }
125     };
126
127 private:
128     Compiler* m_pComp;
129
130     // For allocations.  (Other things?)
131     CompAllocator* m_alloc;
132
133     // TODO-Cleanup: should transform "attribs" into a struct with bit fields.  That would be simpler...
134
135     enum VNFOpAttrib
136     {
137         VNFOA_IllegalGenTreeOp = 0x1,  // corresponds to a genTreeOps value that is not a legal VN func.
138         VNFOA_Commutative      = 0x2,  // 1 iff the function is commutative.
139         VNFOA_Arity            = 0x4,  // Bits 2..3 encode the arity.
140         VNFOA_AfterArity       = 0x20, // Makes it clear what value the next flag(s) after Arity should have.
141         VNFOA_KnownNonNull     = 0x20, // 1 iff the result is known to be non-null.
142         VNFOA_SharedStatic     = 0x40, // 1 iff this VNF is represent one of the shared static jit helpers
143     };
144
145     static const unsigned VNFOA_ArityShift = 2;
146     static const unsigned VNFOA_ArityBits  = 3;
147     static const unsigned VNFOA_MaxArity   = (1 << VNFOA_ArityBits) - 1; // Max arity we can represent.
148     static const unsigned VNFOA_ArityMask  = VNFOA_AfterArity - VNFOA_Arity;
149
150     // These enum constants are used to encode the cast operation in the lowest bits by VNForCastOper
151     enum VNFCastAttrib
152     {
153         VCA_UnsignedSrc = 0x01,
154
155         VCA_BitCount     = 1,    // the number of reserved bits
156         VCA_ReservedBits = 0x01, // i.e. (VCA_UnsignedSrc)
157     };
158
159     // An array of length GT_COUNT, mapping genTreeOp values to their VNFOpAttrib.
160     static UINT8* s_vnfOpAttribs;
161
162     // Returns "true" iff gtOper is a legal value number function.
163     // (Requires InitValueNumStoreStatics to have been run.)
164     static bool GenTreeOpIsLegalVNFunc(genTreeOps gtOper);
165
166     // Returns "true" iff "vnf" is a commutative (and thus binary) operator.
167     // (Requires InitValueNumStoreStatics to have been run.)
168     static bool VNFuncIsCommutative(VNFunc vnf);
169
170     // Returns "true" iff "vnf" is a comparison (and thus binary) operator.
171     static bool VNFuncIsComparison(VNFunc vnf);
172
173     // Returns "true" iff "vnf" can be evaluated for constant arguments.
174     static bool CanEvalForConstantArgs(VNFunc vnf);
175
176     // return vnf(v0)
177     template <typename T>
178     static T EvalOp(VNFunc vnf, T v0);
179
180     // If vnf(v0, v1) would raise an exception, sets *pExcSet to the singleton set containing the exception, and
181     // returns (T)0. Otherwise, returns vnf(v0, v1).
182     template <typename T>
183     T EvalOp(VNFunc vnf, T v0, T v1, ValueNum* pExcSet);
184
185     template <typename T>
186     static int EvalComparison(VNFunc vnf, T v0, T v1);
187     template <typename T>
188     static int EvalOrderedComparisonFloat(VNFunc vnf, T v0, T v1);
189     // return vnf(v0) or vnf(v0, v1), respectively (must, of course be unary/binary ops, respectively.)
190     // Should only be instantiated for integral types.
191     template <typename T>
192     static T EvalOpIntegral(VNFunc vnf, T v0);
193     template <typename T>
194     T EvalOpIntegral(VNFunc vnf, T v0, T v1, ValueNum* pExcSet);
195
196     // Should only instantiate (in a non-trivial way) for "int" and "INT64".  Returns true iff dividing "v0" by "v1"
197     // would produce integer overflow (an ArithmeticException -- *not* division by zero, which is separate.)
198     template <typename T>
199     static bool IsOverflowIntDiv(T v0, T v1);
200
201     // Should only instantiate (in a non-trivial way) for integral types (signed/unsigned int32/int64).
202     // Returns true iff v is the zero of the appropriate type.
203     template <typename T>
204     static bool IsIntZero(T v);
205
206     // Given an constant value number return its value.
207     int GetConstantInt32(ValueNum argVN);
208     INT64 GetConstantInt64(ValueNum argVN);
209     double GetConstantDouble(ValueNum argVN);
210     float GetConstantSingle(ValueNum argVN);
211
212     // Assumes that all the ValueNum arguments of each of these functions have been shown to represent constants.
213     // Assumes that "vnf" is a operator of the appropriate arity (unary for the first, binary for the second).
214     // Assume that "CanEvalForConstantArgs(vnf)" is true.
215     // Returns the result of evaluating the function with those constant arguments.
216     ValueNum EvalFuncForConstantArgs(var_types typ, VNFunc vnf, ValueNum vn0);
217     ValueNum EvalFuncForConstantArgs(var_types typ, VNFunc vnf, ValueNum vn0, ValueNum vn1);
218     ValueNum EvalFuncForConstantFPArgs(var_types typ, VNFunc vnf, ValueNum vn0, ValueNum vn1);
219     ValueNum EvalCastForConstantArgs(var_types typ, VNFunc vnf, ValueNum vn0, ValueNum vn1);
220
221 #ifdef DEBUG
222     // This helps test some performance pathologies related to "evaluation" of VNF_MapSelect terms,
223     // especially relating to GcHeap/ByrefExposed.  We count the number of applications of such terms we consider,
224     // and if this exceeds a limit, indicated by a COMPlus_ variable, we assert.
225     unsigned m_numMapSels;
226 #endif
227
228 // This is the constant value used for the default value of m_mapSelectBudget
229 #define DEFAULT_MAP_SELECT_BUDGET 100 // used by JitVNMapSelBudget
230
231     // This is the maximum number of MapSelect terms that can be "considered" as part of evaluation of a top-level
232     // MapSelect application.
233     int m_mapSelectBudget;
234
235 public:
236     // Initializes any static variables of ValueNumStore.
237     static void InitValueNumStoreStatics();
238
239     // Initialize an empty ValueNumStore.
240     ValueNumStore(Compiler* comp, CompAllocator* allocator);
241
242     // Returns "true" iff "vnf" (which may have been created by a cast from an integral value) represents
243     // a legal value number function.
244     // (Requires InitValueNumStoreStatics to have been run.)
245     static bool VNFuncIsLegal(VNFunc vnf)
246     {
247         return unsigned(vnf) > VNF_Boundary || GenTreeOpIsLegalVNFunc(static_cast<genTreeOps>(vnf));
248     }
249
250     // Returns the arity of "vnf".
251     static unsigned VNFuncArity(VNFunc vnf);
252
253     // Requires "gtOper" to be a genTreeOps legally representing a VNFunc, and returns that
254     // VNFunc.
255     // (Requires InitValueNumStoreStatics to have been run.)
256     static VNFunc GenTreeOpToVNFunc(genTreeOps gtOper)
257     {
258         assert(GenTreeOpIsLegalVNFunc(gtOper));
259         return static_cast<VNFunc>(gtOper);
260     }
261
262 #ifdef DEBUG
263     static void RunTests(Compiler* comp);
264 #endif // DEBUG
265
266     // This block of methods gets value numbers for constants of primitive types.
267
268     ValueNum VNForIntCon(INT32 cnsVal);
269     ValueNum VNForLongCon(INT64 cnsVal);
270     ValueNum VNForFloatCon(float cnsVal);
271     ValueNum VNForDoubleCon(double cnsVal);
272     ValueNum VNForByrefCon(INT64 byrefVal);
273
274 #ifdef _TARGET_64BIT_
275     ValueNum VNForPtrSizeIntCon(INT64 cnsVal)
276     {
277         return VNForLongCon(cnsVal);
278     }
279 #else
280     ValueNum VNForPtrSizeIntCon(INT32 cnsVal)
281     {
282         return VNForIntCon(cnsVal);
283     }
284 #endif
285
286     ValueNum VNForCastOper(var_types castToType, bool srcIsUnsigned = false);
287
288     // We keep handle values in a separate pool, so we don't confuse a handle with an int constant
289     // that happens to be the same...
290     ValueNum VNForHandle(ssize_t cnsVal, unsigned iconFlags);
291
292     // And the single constant for an object reference type.
293     static ValueNum VNForNull()
294     {
295         // We reserve Chunk 0 for "special" VNs.  SRC_Null (== 0) is the VN of "null".
296         return ValueNum(SRC_Null);
297     }
298
299     // The zero map is the map that returns a zero "for the appropriate type" when indexed at any index.
300     static ValueNum VNForZeroMap()
301     {
302         // We reserve Chunk 0 for "special" VNs.  Let SRC_ZeroMap (== 1) be the zero map.
303         return ValueNum(SRC_ZeroMap);
304     }
305
306     // The ROH map is the map for the "read-only heap".  We assume that this is never mutated, and always
307     // has the same value number.
308     static ValueNum VNForROH()
309     {
310         // We reserve Chunk 0 for "special" VNs.  Let SRC_ReadOnlyHeap (== 3) be the read-only heap.
311         return ValueNum(SRC_ReadOnlyHeap);
312     }
313
314     // A special value number for "void" -- sometimes a type-void thing is an argument to a
315     // GT_LIST, and we want the args to be non-NoVN.
316     static ValueNum VNForVoid()
317     {
318         // We reserve Chunk 0 for "special" VNs.  Let SRC_Void (== 4) be the value for "void".
319         return ValueNum(SRC_Void);
320     }
321     static ValueNumPair VNPForVoid()
322     {
323         return ValueNumPair(VNForVoid(), VNForVoid());
324     }
325
326     // A special value number for the empty set of exceptions.
327     static ValueNum VNForEmptyExcSet()
328     {
329         // We reserve Chunk 0 for "special" VNs.  Let SRC_EmptyExcSet (== 5) be the value for the empty set of
330         // exceptions.
331         return ValueNum(SRC_EmptyExcSet);
332     }
333     static ValueNumPair VNPForEmptyExcSet()
334     {
335         return ValueNumPair(VNForEmptyExcSet(), VNForEmptyExcSet());
336     }
337
338     // Returns the value number for zero of the given "typ".
339     // It has an unreached() for a "typ" that has no zero value, such as TYP_BYREF.
340     ValueNum VNZeroForType(var_types typ);
341
342     // Returns the value number for one of the given "typ".
343     // It returns NoVN for a "typ" that has no one value, such as TYP_REF.
344     ValueNum VNOneForType(var_types typ);
345
346     // Return the value number representing the singleton exception set containing the exception value "x".
347     ValueNum VNExcSetSingleton(ValueNum x);
348     ValueNumPair VNPExcSetSingleton(ValueNumPair x);
349
350     // Returns the VN representing the union of the two exception sets "xs0" and "xs1".
351     // These must be VNForEmtpyExcSet() or applications of VNF_ExcSetCons, obeying
352     // the ascending order invariant (which is preserved in the result.)
353     ValueNum VNExcSetUnion(ValueNum xs0, ValueNum xs1 DEBUGARG(bool topLevel = true));
354
355     ValueNumPair VNPExcSetUnion(ValueNumPair xs0vnp, ValueNumPair xs1vnp);
356
357     // Returns "true" iff "vn" is an application of "VNF_ValWithExc".
358     bool VNHasExc(ValueNum vn)
359     {
360         VNFuncApp funcApp;
361         return GetVNFunc(vn, &funcApp) && funcApp.m_func == VNF_ValWithExc;
362     }
363
364     // Requires that "vn" is *not* a "VNF_ValWithExc" appliation.
365     // If vn "excSet" is not "VNForEmptyExcSet()", return "VNF_ValWithExc(vn, excSet)".  Otherwise,
366     // just return "vn".
367     ValueNum VNWithExc(ValueNum vn, ValueNum excSet);
368
369     ValueNumPair VNPWithExc(ValueNumPair vnp, ValueNumPair excSetVNP);
370
371     // If "vnWx" is a "VNF_ValWithExc(normal, excSet)" application, sets "*pvn" to "normal", and
372     // "*pvnx" to "excSet".  Otherwise, just sets "*pvn" to "normal".
373     void VNUnpackExc(ValueNum vnWx, ValueNum* pvn, ValueNum* pvnx);
374
375     void VNPUnpackExc(ValueNumPair vnWx, ValueNumPair* pvn, ValueNumPair* pvnx);
376
377     // If "vn" is a "VNF_ValWithExc(norm, excSet)" value, returns the "norm" argument; otherwise,
378     // just returns "vn".
379     ValueNum VNNormVal(ValueNum vn);
380     ValueNumPair VNPNormVal(ValueNumPair vn);
381
382     // If "vn" is a "VNF_ValWithExc(norm, excSet)" value, returns the "excSet" argument; otherwise,
383     // just returns "EmptyExcSet()".
384     ValueNum VNExcVal(ValueNum vn);
385     ValueNumPair VNPExcVal(ValueNumPair vn);
386
387     // True "iff" vn is a value known to be non-null.  (For example, the result of an allocation...)
388     bool IsKnownNonNull(ValueNum vn);
389
390     // True "iff" vn is a value returned by a call to a shared static helper.
391     bool IsSharedStatic(ValueNum vn);
392
393     // VN's for functions of other values.
394     // Four overloads, for arities 0, 1, 2, and 3.  If we need other arities, we'll consider it.
395     ValueNum VNForFunc(var_types typ, VNFunc func);
396     ValueNum VNForFunc(var_types typ, VNFunc func, ValueNum opVNwx);
397     // This must not be used for VNF_MapSelect applications; instead use VNForMapSelect, below.
398     ValueNum VNForFunc(var_types typ, VNFunc func, ValueNum op1VNwx, ValueNum op2VNwx);
399     ValueNum VNForFunc(var_types typ, VNFunc func, ValueNum op1VNwx, ValueNum op2VNwx, ValueNum op3VNwx);
400
401     // The following four op VNForFunc is only used for VNF_PtrToArrElem, elemTypeEqVN, arrVN, inxVN, fldSeqVN
402     ValueNum VNForFunc(
403         var_types typ, VNFunc func, ValueNum op1VNwx, ValueNum op2VNwx, ValueNum op3VNwx, ValueNum op4VNwx);
404
405     // This requires a "ValueNumKind" because it will attempt, given "select(phi(m1, ..., mk), ind)", to evaluate
406     // "select(m1, ind)", ..., "select(mk, ind)" to see if they agree.  It needs to know which kind of value number
407     // (liberal/conservative) to read from the SSA def referenced in the phi argument.
408     ValueNum VNForMapSelect(ValueNumKind vnk, var_types typ, ValueNum op1VN, ValueNum op2VN);
409
410     // A method that does the work for VNForMapSelect and may call itself recursively.
411     ValueNum VNForMapSelectWork(
412         ValueNumKind vnk, var_types typ, ValueNum op1VN, ValueNum op2VN, int* pBudget, bool* pUsedRecursiveVN);
413
414     // A specialized version of VNForFunc that is used for VNF_MapStore and provides some logging when verbose is set
415     ValueNum VNForMapStore(var_types typ, ValueNum arg0VN, ValueNum arg1VN, ValueNum arg2VN);
416
417     // These functions parallel the ones above, except that they take liberal/conservative VN pairs
418     // as arguments, and return such a pair (the pair of the function applied to the liberal args, and
419     // the function applied to the conservative args).
420     ValueNumPair VNPairForFunc(var_types typ, VNFunc func)
421     {
422         ValueNumPair res;
423         res.SetBoth(VNForFunc(typ, func));
424         return res;
425     }
426     ValueNumPair VNPairForFunc(var_types typ, VNFunc func, ValueNumPair opVN)
427     {
428         return ValueNumPair(VNForFunc(typ, func, opVN.GetLiberal()), VNForFunc(typ, func, opVN.GetConservative()));
429     }
430     ValueNumPair VNPairForFunc(var_types typ, VNFunc func, ValueNumPair op1VN, ValueNumPair op2VN)
431     {
432         return ValueNumPair(VNForFunc(typ, func, op1VN.GetLiberal(), op2VN.GetLiberal()),
433                             VNForFunc(typ, func, op1VN.GetConservative(), op2VN.GetConservative()));
434     }
435     ValueNumPair VNPairForFunc(var_types typ, VNFunc func, ValueNumPair op1VN, ValueNumPair op2VN, ValueNumPair op3VN)
436     {
437         return ValueNumPair(VNForFunc(typ, func, op1VN.GetLiberal(), op2VN.GetLiberal(), op3VN.GetLiberal()),
438                             VNForFunc(typ, func, op1VN.GetConservative(), op2VN.GetConservative(),
439                                       op3VN.GetConservative()));
440     }
441     ValueNumPair VNPairForFunc(
442         var_types typ, VNFunc func, ValueNumPair op1VN, ValueNumPair op2VN, ValueNumPair op3VN, ValueNumPair op4VN)
443     {
444         return ValueNumPair(VNForFunc(typ, func, op1VN.GetLiberal(), op2VN.GetLiberal(), op3VN.GetLiberal(),
445                                       op4VN.GetLiberal()),
446                             VNForFunc(typ, func, op1VN.GetConservative(), op2VN.GetConservative(),
447                                       op3VN.GetConservative(), op4VN.GetConservative()));
448     }
449
450     // Get a new, unique value number for an expression that we're not equating to some function,
451     // which is the value of a tree in the given block.
452     ValueNum VNForExpr(BasicBlock* block, var_types typ = TYP_UNKNOWN);
453
454 // This controls extra tracing of the "evaluation" of "VNF_MapSelect" functions.
455 #define FEATURE_VN_TRACE_APPLY_SELECTORS 1
456
457     // Return the value number corresponding to constructing "MapSelect(map, f0)", where "f0" is the
458     // (value number of) the first field in "fieldSeq".  (The type of this application will be the type of "f0".)
459     // If there are no remaining fields in "fieldSeq", return that value number; otherwise, return VNApplySelectors
460     // applied to that value number and the remainder of "fieldSeq". When the 'fieldSeq' specifies a TYP_STRUCT
461     // then the size of the struct is returned by 'wbFinalStructSize' (when it is non-null)
462     ValueNum VNApplySelectors(ValueNumKind  vnk,
463                               ValueNum      map,
464                               FieldSeqNode* fieldSeq,
465                               size_t*       wbFinalStructSize = nullptr);
466
467     // Used after VNApplySelectors has determined that "selectedVN" is contained in a Map using VNForMapSelect
468     // It determines whether the 'selectedVN' is of an appropriate type to be read using and indirection of 'indType'
469     // If it is appropriate type then 'selectedVN' is returned, otherwise it may insert a cast to indType
470     // or return a unique value number for an incompatible indType.
471     ValueNum VNApplySelectorsTypeCheck(ValueNum selectedVN, var_types indType, size_t structSize);
472
473     // Assumes that "map" represents a map that is addressable by the fields in "fieldSeq", to get
474     // to a value of the type of "rhs".  Returns an expression for the RHS of an assignment, in the given "block",
475     // to a location containing value "map" that will change the field addressed by "fieldSeq" to "rhs", leaving
476     // all other indices in "map" the same.
477     ValueNum VNApplySelectorsAssign(
478         ValueNumKind vnk, ValueNum map, FieldSeqNode* fieldSeq, ValueNum rhs, var_types indType, BasicBlock* block);
479
480     // Used after VNApplySelectorsAssign has determined that "elem" is to be writen into a Map using VNForMapStore
481     // It determines whether the 'elem' is of an appropriate type to be writen using using an indirection of 'indType'
482     // It may insert a cast to indType or return a unique value number for an incompatible indType.
483     ValueNum VNApplySelectorsAssignTypeCoerce(ValueNum elem, var_types indType, BasicBlock* block);
484
485     ValueNumPair VNPairApplySelectors(ValueNumPair map, FieldSeqNode* fieldSeq, var_types indType);
486
487     ValueNumPair VNPairApplySelectorsAssign(
488         ValueNumPair map, FieldSeqNode* fieldSeq, ValueNumPair rhs, var_types indType, BasicBlock* block)
489     {
490         return ValueNumPair(VNApplySelectorsAssign(VNK_Liberal, map.GetLiberal(), fieldSeq, rhs.GetLiberal(), indType,
491                                                    block),
492                             VNApplySelectorsAssign(VNK_Conservative, map.GetConservative(), fieldSeq,
493                                                    rhs.GetConservative(), indType, block));
494     }
495
496     // Compute the normal ValueNumber for a cast with no exceptions
497     ValueNum VNForCast(ValueNum srcVN, var_types castToType, var_types castFromType, bool srcIsUnsigned = false);
498
499     // Compute the ValueNumberPair for a cast
500     ValueNumPair VNPairForCast(ValueNumPair srcVNPair,
501                                var_types    castToType,
502                                var_types    castFromType,
503                                bool         srcIsUnsigned    = false,
504                                bool         hasOverflowCheck = false);
505
506     // Returns true iff the VN represents an application of VNF_NotAField.
507     bool IsVNNotAField(ValueNum vn);
508
509     // PtrToLoc values need to express a field sequence as one of their arguments.  VN for null represents
510     // empty sequence, otherwise, "FieldSeq(VN(FieldHandle), restOfSeq)".
511     ValueNum VNForFieldSeq(FieldSeqNode* fieldSeq);
512
513     // Requires that "vn" represents a field sequence, that is, is the result of a call to VNForFieldSeq.
514     // Returns the FieldSequence it represents.
515     FieldSeqNode* FieldSeqVNToFieldSeq(ValueNum vn);
516
517     // Both argument must represent field sequences; returns the value number representing the
518     // concatenation "fsVN1 || fsVN2".
519     ValueNum FieldSeqVNAppend(ValueNum fsVN1, ValueNum fsVN2);
520
521     // If "opA" has a PtrToLoc, PtrToArrElem, or PtrToStatic application as its value numbers, and "opB" is an integer
522     // with a "fieldSeq", returns the VN for the pointer form extended with the field sequence; or else NoVN.
523     ValueNum ExtendPtrVN(GenTree* opA, GenTree* opB);
524     // If "opA" has a PtrToLoc, PtrToArrElem, or PtrToStatic application as its value numbers, returns the VN for the
525     // pointer form extended with "fieldSeq"; or else NoVN.
526     ValueNum ExtendPtrVN(GenTree* opA, FieldSeqNode* fieldSeq);
527
528     // Queries on value numbers.
529     // All queries taking value numbers require that those value numbers are valid, that is, that
530     // they have been returned by previous "VNFor..." operations.  They can assert false if this is
531     // not true.
532
533     // Returns TYP_UNKNOWN if the given value number has not been given a type.
534     var_types TypeOfVN(ValueNum vn);
535
536     // Returns MAX_LOOP_NUM if the given value number's loop nest is unknown or ill-defined.
537     BasicBlock::loopNumber LoopOfVN(ValueNum vn);
538
539     // Returns true iff the VN represents a (non-handle) constant.
540     bool IsVNConstant(ValueNum vn);
541
542     // Returns true iff the VN represents an integeral constant.
543     bool IsVNInt32Constant(ValueNum vn);
544
545     typedef SmallHashTable<ValueNum, bool, 8U> CheckedBoundVNSet;
546
547     // Returns true if the VN is known or likely to appear as the conservative value number
548     // of the length argument to a GT_ARR_BOUNDS_CHECK node.
549     bool IsVNCheckedBound(ValueNum vn);
550
551     // Record that a VN is known to appear as the conservative value number of the length
552     // argument to a GT_ARR_BOUNDS_CHECK node.
553     void SetVNIsCheckedBound(ValueNum vn);
554
555     // Information about the individual components of a value number representing an unsigned
556     // comparison of some value against a checked bound VN.
557     struct UnsignedCompareCheckedBoundInfo
558     {
559         unsigned cmpOper;
560         ValueNum vnIdx;
561         ValueNum vnBound;
562
563         UnsignedCompareCheckedBoundInfo() : cmpOper(GT_NONE), vnIdx(NoVN), vnBound(NoVN)
564         {
565         }
566     };
567
568     struct CompareCheckedBoundArithInfo
569     {
570         // (vnBound - 1) > vnOp
571         // (vnBound arrOper arrOp) cmpOper cmpOp
572         ValueNum vnBound;
573         unsigned arrOper;
574         ValueNum arrOp;
575         unsigned cmpOper;
576         ValueNum cmpOp;
577         CompareCheckedBoundArithInfo() : vnBound(NoVN), arrOper(GT_NONE), arrOp(NoVN), cmpOper(GT_NONE), cmpOp(NoVN)
578         {
579         }
580 #ifdef DEBUG
581         void dump(ValueNumStore* vnStore)
582         {
583             vnStore->vnDump(vnStore->m_pComp, cmpOp);
584             printf(" ");
585             printf(vnStore->VNFuncName((VNFunc)cmpOper));
586             printf(" ");
587             vnStore->vnDump(vnStore->m_pComp, vnBound);
588             if (arrOper != GT_NONE)
589             {
590                 printf(vnStore->VNFuncName((VNFunc)arrOper));
591                 vnStore->vnDump(vnStore->m_pComp, arrOp);
592             }
593         }
594 #endif
595     };
596
597     struct ConstantBoundInfo
598     {
599         // 100 > vnOp
600         int      constVal;
601         unsigned cmpOper;
602         ValueNum cmpOpVN;
603
604         ConstantBoundInfo() : constVal(0), cmpOper(GT_NONE), cmpOpVN(NoVN)
605         {
606         }
607
608 #ifdef DEBUG
609         void dump(ValueNumStore* vnStore)
610         {
611             vnStore->vnDump(vnStore->m_pComp, cmpOpVN);
612             printf(" ");
613             printf(vnStore->VNFuncName((VNFunc)cmpOper));
614             printf(" ");
615             printf("%d", constVal);
616         }
617 #endif
618     };
619
620     // Check if "vn" is "new [] (type handle, size)"
621     bool IsVNNewArr(ValueNum vn, VNFuncApp* funcApp);
622
623     // Check if "vn" IsVNNewArr and return <= 0 if arr size cannot be determined, else array size.
624     int GetNewArrSize(ValueNum vn);
625
626     // Check if "vn" is "a.len"
627     bool IsVNArrLen(ValueNum vn);
628
629     // If "vn" is VN(a.len) then return VN(a); NoVN if VN(a) can't be determined.
630     ValueNum GetArrForLenVn(ValueNum vn);
631
632     // Return true with any Relop except for == and !=  and one operand has to be a 32-bit integer constant.
633     bool IsVNConstantBound(ValueNum vn);
634
635     // If "vn" is constant bound, then populate the "info" fields for constVal, cmpOp, cmpOper.
636     void GetConstantBoundInfo(ValueNum vn, ConstantBoundInfo* info);
637
638     // If "vn" is of the form "(uint)var < (uint)len" (or equivalent) return true.
639     bool IsVNUnsignedCompareCheckedBound(ValueNum vn, UnsignedCompareCheckedBoundInfo* info);
640
641     // If "vn" is of the form "var < len" or "len <= var" return true.
642     bool IsVNCompareCheckedBound(ValueNum vn);
643
644     // If "vn" is checked bound, then populate the "info" fields for the boundVn, cmpOp, cmpOper.
645     void GetCompareCheckedBound(ValueNum vn, CompareCheckedBoundArithInfo* info);
646
647     // If "vn" is of the form "len +/- var" return true.
648     bool IsVNCheckedBoundArith(ValueNum vn);
649
650     // If "vn" is checked bound arith, then populate the "info" fields for arrOper, arrVn, arrOp.
651     void GetCheckedBoundArithInfo(ValueNum vn, CompareCheckedBoundArithInfo* info);
652
653     // If "vn" is of the form "var < len +/- k" return true.
654     bool IsVNCompareCheckedBoundArith(ValueNum vn);
655
656     // If "vn" is checked bound arith, then populate the "info" fields for cmpOp, cmpOper.
657     void GetCompareCheckedBoundArithInfo(ValueNum vn, CompareCheckedBoundArithInfo* info);
658
659     // Returns the flags on the current handle. GTF_ICON_SCOPE_HDL for example.
660     unsigned GetHandleFlags(ValueNum vn);
661
662     // Returns true iff the VN represents a handle constant.
663     bool IsVNHandle(ValueNum vn);
664
665     // Convert a vartype_t to the value number's storage type for that vartype_t.
666     // For example, ValueNum of type TYP_LONG are stored in a map of INT64 variables.
667     // Lang is the language (C++) type for the corresponding vartype_t.
668     template <int N>
669     struct VarTypConv
670     {
671     };
672
673 private:
674     struct Chunk;
675
676     template <typename T>
677     static T CoerceTypRefToT(Chunk* c, unsigned offset);
678
679     // Get the actual value and coerce the actual type c->m_typ to the wanted type T.
680     template <typename T>
681     FORCEINLINE T SafeGetConstantValue(Chunk* c, unsigned offset);
682
683     template <typename T>
684     T ConstantValueInternal(ValueNum vn DEBUGARG(bool coerce))
685     {
686         Chunk* c = m_chunks.GetNoExpand(GetChunkNum(vn));
687         assert(c->m_attribs == CEA_Const || c->m_attribs == CEA_Handle);
688
689         unsigned offset = ChunkOffset(vn);
690
691         switch (c->m_typ)
692         {
693             case TYP_REF:
694                 assert(0 <= offset && offset <= 1); // Null or exception.
695                 __fallthrough;
696
697             case TYP_BYREF:
698
699 #ifdef _MSC_VER
700
701                 assert(&typeid(T) == &typeid(size_t)); // We represent ref/byref constants as size_t's.
702
703 #endif // _MSC_VER
704
705                 __fallthrough;
706
707             case TYP_INT:
708             case TYP_LONG:
709             case TYP_FLOAT:
710             case TYP_DOUBLE:
711                 if (c->m_attribs == CEA_Handle)
712                 {
713                     C_ASSERT(offsetof(VNHandle, m_cnsVal) == 0);
714                     return (T) reinterpret_cast<VNHandle*>(c->m_defs)[offset].m_cnsVal;
715                 }
716 #ifdef DEBUG
717                 if (!coerce)
718                 {
719                     T val1 = reinterpret_cast<T*>(c->m_defs)[offset];
720                     T val2 = SafeGetConstantValue<T>(c, offset);
721
722                     // Detect if there is a mismatch between the VN storage type and explicitly
723                     // passed-in type T.
724                     bool mismatch = false;
725                     if (varTypeIsFloating(c->m_typ))
726                     {
727                         mismatch = (memcmp(&val1, &val2, sizeof(val1)) != 0);
728                     }
729                     else
730                     {
731                         mismatch = (val1 != val2);
732                     }
733
734                     if (mismatch)
735                     {
736                         assert(
737                             !"Called ConstantValue<T>(vn), but type(T) != type(vn); Use CoercedConstantValue instead.");
738                     }
739                 }
740 #endif
741                 return SafeGetConstantValue<T>(c, offset);
742
743             default:
744                 assert(false); // We do not record constants of this typ.
745                 return (T)0;
746         }
747     }
748
749 public:
750     // Requires that "vn" is a constant, and that its type is compatible with the explicitly passed
751     // type "T". Also, note that "T" has to have an accurate storage size of the TypeOfVN(vn).
752     template <typename T>
753     T ConstantValue(ValueNum vn)
754     {
755         return ConstantValueInternal<T>(vn DEBUGARG(false));
756     }
757
758     // Requires that "vn" is a constant, and that its type can be coerced to the explicitly passed
759     // type "T".
760     template <typename T>
761     T CoercedConstantValue(ValueNum vn)
762     {
763         return ConstantValueInternal<T>(vn DEBUGARG(true));
764     }
765
766     // Given a value number "vn", go through the list of VNs that are handles
767     // to find if it is present, if so, return "true", else "false."
768     bool IsHandle(ValueNum vn);
769
770     // Requires "mthFunc" to be an intrinsic math function (one of the allowable values for the "gtMath" field
771     // of a GenTreeMath node).  For unary ops, return the value number for the application of this function to
772     // "arg0VN". For binary ops, return the value number for the application of this function to "arg0VN" and
773     // "arg1VN".
774
775     ValueNum EvalMathFuncUnary(var_types typ, CorInfoIntrinsics mthFunc, ValueNum arg0VN);
776
777     ValueNum EvalMathFuncBinary(var_types typ, CorInfoIntrinsics mthFunc, ValueNum arg0VN, ValueNum arg1VN);
778
779     ValueNumPair EvalMathFuncUnary(var_types typ, CorInfoIntrinsics mthFunc, ValueNumPair arg0VNP)
780     {
781         return ValueNumPair(EvalMathFuncUnary(typ, mthFunc, arg0VNP.GetLiberal()),
782                             EvalMathFuncUnary(typ, mthFunc, arg0VNP.GetConservative()));
783     }
784
785     ValueNumPair EvalMathFuncBinary(var_types         typ,
786                                     CorInfoIntrinsics mthFunc,
787                                     ValueNumPair      arg0VNP,
788                                     ValueNumPair      arg1VNP)
789     {
790         return ValueNumPair(EvalMathFuncBinary(typ, mthFunc, arg0VNP.GetLiberal(), arg1VNP.GetLiberal()),
791                             EvalMathFuncBinary(typ, mthFunc, arg0VNP.GetConservative(), arg1VNP.GetConservative()));
792     }
793
794     // Returns "true" iff "vn" represents a function application.
795     bool IsVNFunc(ValueNum vn);
796
797     // If "vn" represents a function application, returns "true" and set "*funcApp" to
798     // the function application it represents; otherwise, return "false."
799     bool GetVNFunc(ValueNum vn, VNFuncApp* funcApp);
800
801     // Requires that "vn" represents a "GC heap address" the sum of a "TYP_REF" value and some integer
802     // value.  Returns the TYP_REF value.
803     ValueNum VNForRefInAddr(ValueNum vn);
804
805     // Returns "true" iff "vn" is a valid value number -- one that has been previously returned.
806     bool VNIsValid(ValueNum vn);
807
808 #ifdef DEBUG
809 // This controls whether we recursively call vnDump on function arguments.
810 #define FEATURE_VN_DUMP_FUNC_ARGS 0
811
812     // Prints, to standard out, a representation of "vn".
813     void vnDump(Compiler* comp, ValueNum vn, bool isPtr = false);
814
815     // Requires "fieldSeq" to be a field sequence VNFuncApp.
816     // Prints a representation (comma-separated list of field names) on standard out.
817     void vnDumpFieldSeq(Compiler* comp, VNFuncApp* fieldSeq, bool isHead);
818
819     // Requires "mapSelect" to be a map select VNFuncApp.
820     // Prints a representation of a MapSelect operation on standard out.
821     void vnDumpMapSelect(Compiler* comp, VNFuncApp* mapSelect);
822
823     // Requires "mapStore" to be a map store VNFuncApp.
824     // Prints a representation of a MapStore operation on standard out.
825     void vnDumpMapStore(Compiler* comp, VNFuncApp* mapStore);
826
827     // Returns the string name of "vnf".
828     static const char* VNFuncName(VNFunc vnf);
829     // Used in the implementation of the above.
830     static const char* VNFuncNameArr[];
831
832     // Returns the string name of "vn" when it is a reserved value number, nullptr otherwise
833     static const char* reservedName(ValueNum vn);
834
835 #endif // DEBUG
836
837     // Returns true if "vn" is a reserved value number
838     static bool isReservedVN(ValueNum);
839
840 #define VALUENUM_SUPPORT_MERGE 0
841 #if VALUENUM_SUPPORT_MERGE
842     // If we're going to support the Merge operation, and do it right, we really need to use an entire
843     // egraph data structure, so that we can do congruence closure, and discover congruences implied
844     // by the eq-class merge.
845
846     // It may be that we provisionally give two expressions distinct value numbers, then later discover
847     // that the values of the expressions are provably equal.  We allow the two value numbers to be
848     // "merged" -- after the merge, they represent the same abstract value.
849     void MergeVNs(ValueNum vn1, ValueNum vn2);
850 #endif
851
852 private:
853     // We will allocate value numbers in "chunks".  Each chunk will have the same type and "constness".
854     static const unsigned LogChunkSize    = 6;
855     static const unsigned ChunkSize       = 1 << LogChunkSize;
856     static const unsigned ChunkOffsetMask = ChunkSize - 1;
857
858     // A "ChunkNum" is a zero-based index naming a chunk in the Store, or else the special "NoChunk" value.
859     typedef UINT32        ChunkNum;
860     static const ChunkNum NoChunk = UINT32_MAX;
861
862     // Returns the ChunkNum of the Chunk that holds "vn" (which is required to be a valid
863     // value number, i.e., one returned by some VN-producing method of this class).
864     static ChunkNum GetChunkNum(ValueNum vn)
865     {
866         return vn >> LogChunkSize;
867     }
868
869     // Returns the offset of the given "vn" within its chunk.
870     static unsigned ChunkOffset(ValueNum vn)
871     {
872         return vn & ChunkOffsetMask;
873     }
874
875     // The base VN of the next chunk to be allocated.  Should always be a multiple of ChunkSize.
876     ValueNum m_nextChunkBase;
877
878     enum ChunkExtraAttribs : BYTE
879     {
880         CEA_None,      // No extra attributes.
881         CEA_Const,     // This chunk contains constant values.
882         CEA_Handle,    // This chunk contains handle constants.
883         CEA_NotAField, // This chunk contains "not a field" values.
884         CEA_Func0,     // Represents functions of arity 0.
885         CEA_Func1,     // ...arity 1.
886         CEA_Func2,     // ...arity 2.
887         CEA_Func3,     // ...arity 3.
888         CEA_Func4,     // ...arity 4.
889         CEA_Count
890     };
891
892     // A "Chunk" holds "ChunkSize" value numbers, starting at "m_baseVN".  All of these share the same
893     // "m_typ" and "m_attribs".  These properties determine the interpretation of "m_defs", as discussed below.
894     struct Chunk
895     {
896         // If "m_defs" is non-null, it is an array of size ChunkSize, whose element type is determined by the other
897         // members. The "m_numUsed" field indicates the number of elements of "m_defs" that are already consumed (the
898         // next one to allocate).
899         void*    m_defs;
900         unsigned m_numUsed;
901
902         // The value number of the first VN in the chunk.
903         ValueNum m_baseVN;
904
905         // The common attributes of this chunk.
906         var_types              m_typ;
907         ChunkExtraAttribs      m_attribs;
908         BasicBlock::loopNumber m_loopNum;
909
910         // Initialize a chunk, starting at "*baseVN", for the given "typ", "attribs", and "loopNum" (using "alloc" for
911         // allocations).
912         // (Increments "*baseVN" by ChunkSize.)
913         Chunk(CompAllocator*         alloc,
914               ValueNum*              baseVN,
915               var_types              typ,
916               ChunkExtraAttribs      attribs,
917               BasicBlock::loopNumber loopNum);
918
919         // Requires that "m_numUsed < ChunkSize."  Returns the offset of the allocated VN within the chunk; the
920         // actual VN is this added to the "m_baseVN" of the chunk.
921         unsigned AllocVN()
922         {
923             assert(m_numUsed < ChunkSize);
924             return m_numUsed++;
925         }
926
927         template <int N>
928         struct Alloc
929         {
930             typedef typename ValueNumStore::VarTypConv<N>::Type Type;
931         };
932     };
933
934     struct VNHandle : public JitKeyFuncsDefEquals<VNHandle>
935     {
936         ssize_t  m_cnsVal;
937         unsigned m_flags;
938         // Don't use a constructor to use the default copy constructor for hashtable rehash.
939         static void Initialize(VNHandle* handle, ssize_t m_cnsVal, unsigned m_flags)
940         {
941             handle->m_cnsVal = m_cnsVal;
942             handle->m_flags  = m_flags;
943         }
944         bool operator==(const VNHandle& y) const
945         {
946             return m_cnsVal == y.m_cnsVal && m_flags == y.m_flags;
947         }
948         static unsigned GetHashCode(const VNHandle& val)
949         {
950             return static_cast<unsigned>(val.m_cnsVal);
951         }
952     };
953
954     struct VNDefFunc0Arg
955     {
956         VNFunc m_func;
957         VNDefFunc0Arg(VNFunc func) : m_func(func)
958         {
959         }
960
961         VNDefFunc0Arg() : m_func(VNF_COUNT)
962         {
963         }
964
965         bool operator==(const VNDefFunc0Arg& y) const
966         {
967             return m_func == y.m_func;
968         }
969     };
970
971     struct VNDefFunc1Arg : public VNDefFunc0Arg
972     {
973         ValueNum m_arg0;
974         VNDefFunc1Arg(VNFunc func, ValueNum arg0) : VNDefFunc0Arg(func), m_arg0(arg0)
975         {
976         }
977
978         VNDefFunc1Arg() : VNDefFunc0Arg(), m_arg0(ValueNumStore::NoVN)
979         {
980         }
981
982         bool operator==(const VNDefFunc1Arg& y) const
983         {
984             return VNDefFunc0Arg::operator==(y) && m_arg0 == y.m_arg0;
985         }
986     };
987
988     struct VNDefFunc2Arg : public VNDefFunc1Arg
989     {
990         ValueNum m_arg1;
991         VNDefFunc2Arg(VNFunc func, ValueNum arg0, ValueNum arg1) : VNDefFunc1Arg(func, arg0), m_arg1(arg1)
992         {
993         }
994
995         VNDefFunc2Arg() : m_arg1(ValueNumStore::NoVN)
996         {
997         }
998
999         bool operator==(const VNDefFunc2Arg& y) const
1000         {
1001             return VNDefFunc1Arg::operator==(y) && m_arg1 == y.m_arg1;
1002         }
1003     };
1004
1005     struct VNDefFunc3Arg : public VNDefFunc2Arg
1006     {
1007         ValueNum m_arg2;
1008         VNDefFunc3Arg(VNFunc func, ValueNum arg0, ValueNum arg1, ValueNum arg2)
1009             : VNDefFunc2Arg(func, arg0, arg1), m_arg2(arg2)
1010         {
1011         }
1012         VNDefFunc3Arg() : m_arg2(ValueNumStore::NoVN)
1013         {
1014         }
1015
1016         bool operator==(const VNDefFunc3Arg& y) const
1017         {
1018             return VNDefFunc2Arg::operator==(y) && m_arg2 == y.m_arg2;
1019         }
1020     };
1021
1022     struct VNDefFunc4Arg : public VNDefFunc3Arg
1023     {
1024         ValueNum m_arg3;
1025         VNDefFunc4Arg(VNFunc func, ValueNum arg0, ValueNum arg1, ValueNum arg2, ValueNum arg3)
1026             : VNDefFunc3Arg(func, arg0, arg1, arg2), m_arg3(arg3)
1027         {
1028         }
1029         VNDefFunc4Arg() : m_arg3(ValueNumStore::NoVN)
1030         {
1031         }
1032
1033         bool operator==(const VNDefFunc4Arg& y) const
1034         {
1035             return VNDefFunc3Arg::operator==(y) && m_arg3 == y.m_arg3;
1036         }
1037     };
1038
1039     // When we evaluate "select(m, i)", if "m" is a the value of a phi definition, we look at
1040     // all the values of the phi args, and see if doing the "select" on each of them yields identical
1041     // results.  If so, that is the result of the entire "select" form.  We have to be careful, however,
1042     // because phis may be recursive in the presence of loop structures -- the VN for the phi may be (or be
1043     // part of the definition of) the VN's of some of the arguments.  But there will be at least one
1044     // argument that does *not* depend on the outer phi VN -- after all, we had to get into the loop somehow.
1045     // So we have to be careful about breaking infinite recursion.  We can ignore "recursive" results -- if all the
1046     // non-recursive results are the same, the recursion indicates that the loop structure didn't alter the result.
1047     // This stack represents the set of outer phis such that select(phi, ind) is being evaluated.
1048     JitExpandArrayStack<VNDefFunc2Arg> m_fixedPointMapSels;
1049
1050 #ifdef DEBUG
1051     // Returns "true" iff "m_fixedPointMapSels" is non-empty, and it's top element is
1052     // "select(map, index)".
1053     bool FixedPointMapSelsTopHasValue(ValueNum map, ValueNum index);
1054 #endif
1055
1056     // Returns true if "sel(map, ind)" is a member of "m_fixedPointMapSels".
1057     bool SelectIsBeingEvaluatedRecursively(ValueNum map, ValueNum ind);
1058
1059     // This is the set of value numbers that have been flagged as arguments to bounds checks, in the length position.
1060     CheckedBoundVNSet m_checkedBoundVNs;
1061
1062     // This is a map from "chunk number" to the attributes of the chunk.
1063     JitExpandArrayStack<Chunk*> m_chunks;
1064
1065     // These entries indicate the current allocation chunk, if any, for each valid combination of <var_types,
1066     // ChunkExtraAttribute, loopNumber>.  Valid combinations require attribs==CEA_None or loopNum==MAX_LOOP_NUM.
1067     // If the value is NoChunk, it indicates that there is no current allocation chunk for that pair, otherwise
1068     // it is the index in "m_chunks" of a chunk with the given attributes, in which the next allocation should
1069     // be attempted.
1070     ChunkNum m_curAllocChunk[TYP_COUNT][CEA_Count + MAX_LOOP_NUM + 1];
1071
1072     // Returns a (pointer to a) chunk in which a new value number may be allocated.
1073     Chunk* GetAllocChunk(var_types typ, ChunkExtraAttribs attribs, BasicBlock::loopNumber loopNum = MAX_LOOP_NUM);
1074
1075     // First, we need mechanisms for mapping from constants to value numbers.
1076     // For small integers, we'll use an array.
1077     static const int      SmallIntConstMin = -1;
1078     static const int      SmallIntConstMax = 10;
1079     static const unsigned SmallIntConstNum = SmallIntConstMax - SmallIntConstMin + 1;
1080     static bool IsSmallIntConst(int i)
1081     {
1082         return SmallIntConstMin <= i && i <= SmallIntConstMax;
1083     }
1084     ValueNum m_VNsForSmallIntConsts[SmallIntConstNum];
1085
1086     struct ValueNumList
1087     {
1088         ValueNum      vn;
1089         ValueNumList* next;
1090         ValueNumList(const ValueNum& v, ValueNumList* n = nullptr) : vn(v), next(n)
1091         {
1092         }
1093     };
1094
1095     // Keeps track of value numbers that are integer constants and also handles (GTG_ICON_HDL_MASK.)
1096     ValueNumList* m_intConHandles;
1097
1098     typedef VNMap<INT32> IntToValueNumMap;
1099     IntToValueNumMap*    m_intCnsMap;
1100     IntToValueNumMap*    GetIntCnsMap()
1101     {
1102         if (m_intCnsMap == nullptr)
1103         {
1104             m_intCnsMap = new (m_alloc) IntToValueNumMap(m_alloc);
1105         }
1106         return m_intCnsMap;
1107     }
1108
1109     ValueNum GetVNForIntCon(INT32 cnsVal)
1110     {
1111         ValueNum res;
1112         if (GetIntCnsMap()->Lookup(cnsVal, &res))
1113         {
1114             return res;
1115         }
1116         else
1117         {
1118             Chunk*   c                                             = GetAllocChunk(TYP_INT, CEA_Const);
1119             unsigned offsetWithinChunk                             = c->AllocVN();
1120             res                                                    = c->m_baseVN + offsetWithinChunk;
1121             reinterpret_cast<INT32*>(c->m_defs)[offsetWithinChunk] = cnsVal;
1122             GetIntCnsMap()->Set(cnsVal, res);
1123             return res;
1124         }
1125     }
1126
1127     typedef VNMap<INT64> LongToValueNumMap;
1128     LongToValueNumMap*   m_longCnsMap;
1129     LongToValueNumMap*   GetLongCnsMap()
1130     {
1131         if (m_longCnsMap == nullptr)
1132         {
1133             m_longCnsMap = new (m_alloc) LongToValueNumMap(m_alloc);
1134         }
1135         return m_longCnsMap;
1136     }
1137
1138     typedef VNMap<VNHandle, VNHandle> HandleToValueNumMap;
1139     HandleToValueNumMap* m_handleMap;
1140     HandleToValueNumMap* GetHandleMap()
1141     {
1142         if (m_handleMap == nullptr)
1143         {
1144             m_handleMap = new (m_alloc) HandleToValueNumMap(m_alloc);
1145         }
1146         return m_handleMap;
1147     }
1148
1149     struct LargePrimitiveKeyFuncsFloat : public JitLargePrimitiveKeyFuncs<float>
1150     {
1151         static bool Equals(float x, float y)
1152         {
1153             return *(unsigned*)&x == *(unsigned*)&y;
1154         }
1155     };
1156
1157     typedef VNMap<float, LargePrimitiveKeyFuncsFloat> FloatToValueNumMap;
1158     FloatToValueNumMap* m_floatCnsMap;
1159     FloatToValueNumMap* GetFloatCnsMap()
1160     {
1161         if (m_floatCnsMap == nullptr)
1162         {
1163             m_floatCnsMap = new (m_alloc) FloatToValueNumMap(m_alloc);
1164         }
1165         return m_floatCnsMap;
1166     }
1167
1168     // In the JIT we need to distinguish -0.0 and 0.0 for optimizations.
1169     struct LargePrimitiveKeyFuncsDouble : public JitLargePrimitiveKeyFuncs<double>
1170     {
1171         static bool Equals(double x, double y)
1172         {
1173             return *(__int64*)&x == *(__int64*)&y;
1174         }
1175     };
1176
1177     typedef VNMap<double, LargePrimitiveKeyFuncsDouble> DoubleToValueNumMap;
1178     DoubleToValueNumMap* m_doubleCnsMap;
1179     DoubleToValueNumMap* GetDoubleCnsMap()
1180     {
1181         if (m_doubleCnsMap == nullptr)
1182         {
1183             m_doubleCnsMap = new (m_alloc) DoubleToValueNumMap(m_alloc);
1184         }
1185         return m_doubleCnsMap;
1186     }
1187
1188     LongToValueNumMap* m_byrefCnsMap;
1189     LongToValueNumMap* GetByrefCnsMap()
1190     {
1191         if (m_byrefCnsMap == nullptr)
1192         {
1193             m_byrefCnsMap = new (m_alloc) LongToValueNumMap(m_alloc);
1194         }
1195         return m_byrefCnsMap;
1196     }
1197
1198     struct VNDefFunc0ArgKeyFuncs : public JitKeyFuncsDefEquals<VNDefFunc1Arg>
1199     {
1200         static unsigned GetHashCode(VNDefFunc1Arg val)
1201         {
1202             return (val.m_func << 24) + val.m_arg0;
1203         }
1204     };
1205     typedef VNMap<VNFunc> VNFunc0ToValueNumMap;
1206     VNFunc0ToValueNumMap* m_VNFunc0Map;
1207     VNFunc0ToValueNumMap* GetVNFunc0Map()
1208     {
1209         if (m_VNFunc0Map == nullptr)
1210         {
1211             m_VNFunc0Map = new (m_alloc) VNFunc0ToValueNumMap(m_alloc);
1212         }
1213         return m_VNFunc0Map;
1214     }
1215
1216     struct VNDefFunc1ArgKeyFuncs : public JitKeyFuncsDefEquals<VNDefFunc1Arg>
1217     {
1218         static unsigned GetHashCode(VNDefFunc1Arg val)
1219         {
1220             return (val.m_func << 24) + val.m_arg0;
1221         }
1222     };
1223     typedef VNMap<VNDefFunc1Arg, VNDefFunc1ArgKeyFuncs> VNFunc1ToValueNumMap;
1224     VNFunc1ToValueNumMap* m_VNFunc1Map;
1225     VNFunc1ToValueNumMap* GetVNFunc1Map()
1226     {
1227         if (m_VNFunc1Map == nullptr)
1228         {
1229             m_VNFunc1Map = new (m_alloc) VNFunc1ToValueNumMap(m_alloc);
1230         }
1231         return m_VNFunc1Map;
1232     }
1233
1234     struct VNDefFunc2ArgKeyFuncs : public JitKeyFuncsDefEquals<VNDefFunc2Arg>
1235     {
1236         static unsigned GetHashCode(VNDefFunc2Arg val)
1237         {
1238             return (val.m_func << 24) + (val.m_arg0 << 8) + val.m_arg1;
1239         }
1240     };
1241     typedef VNMap<VNDefFunc2Arg, VNDefFunc2ArgKeyFuncs> VNFunc2ToValueNumMap;
1242     VNFunc2ToValueNumMap* m_VNFunc2Map;
1243     VNFunc2ToValueNumMap* GetVNFunc2Map()
1244     {
1245         if (m_VNFunc2Map == nullptr)
1246         {
1247             m_VNFunc2Map = new (m_alloc) VNFunc2ToValueNumMap(m_alloc);
1248         }
1249         return m_VNFunc2Map;
1250     }
1251
1252     struct VNDefFunc3ArgKeyFuncs : public JitKeyFuncsDefEquals<VNDefFunc3Arg>
1253     {
1254         static unsigned GetHashCode(VNDefFunc3Arg val)
1255         {
1256             return (val.m_func << 24) + (val.m_arg0 << 16) + (val.m_arg1 << 8) + val.m_arg2;
1257         }
1258     };
1259     typedef VNMap<VNDefFunc3Arg, VNDefFunc3ArgKeyFuncs> VNFunc3ToValueNumMap;
1260     VNFunc3ToValueNumMap* m_VNFunc3Map;
1261     VNFunc3ToValueNumMap* GetVNFunc3Map()
1262     {
1263         if (m_VNFunc3Map == nullptr)
1264         {
1265             m_VNFunc3Map = new (m_alloc) VNFunc3ToValueNumMap(m_alloc);
1266         }
1267         return m_VNFunc3Map;
1268     }
1269
1270     struct VNDefFunc4ArgKeyFuncs : public JitKeyFuncsDefEquals<VNDefFunc4Arg>
1271     {
1272         static unsigned GetHashCode(VNDefFunc4Arg val)
1273         {
1274             return (val.m_func << 24) + (val.m_arg0 << 16) + (val.m_arg1 << 8) + val.m_arg2 + (val.m_arg3 << 12);
1275         }
1276     };
1277     typedef VNMap<VNDefFunc4Arg, VNDefFunc4ArgKeyFuncs> VNFunc4ToValueNumMap;
1278     VNFunc4ToValueNumMap* m_VNFunc4Map;
1279     VNFunc4ToValueNumMap* GetVNFunc4Map()
1280     {
1281         if (m_VNFunc4Map == nullptr)
1282         {
1283             m_VNFunc4Map = new (m_alloc) VNFunc4ToValueNumMap(m_alloc);
1284         }
1285         return m_VNFunc4Map;
1286     }
1287
1288     enum SpecialRefConsts
1289     {
1290         SRC_Null,
1291         SRC_ZeroMap,
1292         SRC_ReadOnlyHeap,
1293         SRC_Void,
1294         SRC_EmptyExcSet,
1295
1296         SRC_NumSpecialRefConsts
1297     };
1298
1299     // The "values" of special ref consts will be all be "null" -- their differing meanings will
1300     // be carried by the distinct value numbers.
1301     static class Object* s_specialRefConsts[SRC_NumSpecialRefConsts];
1302     static class Object* s_nullConst;
1303 };
1304
1305 template <>
1306 struct ValueNumStore::VarTypConv<TYP_INT>
1307 {
1308     typedef INT32 Type;
1309     typedef int   Lang;
1310 };
1311 template <>
1312 struct ValueNumStore::VarTypConv<TYP_FLOAT>
1313 {
1314     typedef INT32 Type;
1315     typedef float Lang;
1316 };
1317 template <>
1318 struct ValueNumStore::VarTypConv<TYP_LONG>
1319 {
1320     typedef INT64 Type;
1321     typedef INT64 Lang;
1322 };
1323 template <>
1324 struct ValueNumStore::VarTypConv<TYP_DOUBLE>
1325 {
1326     typedef INT64  Type;
1327     typedef double Lang;
1328 };
1329 template <>
1330 struct ValueNumStore::VarTypConv<TYP_BYREF>
1331 {
1332     typedef INT64 Type;
1333     typedef void* Lang;
1334 };
1335 template <>
1336 struct ValueNumStore::VarTypConv<TYP_REF>
1337 {
1338     typedef class Object* Type;
1339     typedef class Object* Lang;
1340 };
1341
1342 // Get the actual value and coerce the actual type c->m_typ to the wanted type T.
1343 template <typename T>
1344 FORCEINLINE T ValueNumStore::SafeGetConstantValue(Chunk* c, unsigned offset)
1345 {
1346     switch (c->m_typ)
1347     {
1348         case TYP_REF:
1349             return CoerceTypRefToT<T>(c, offset);
1350         case TYP_BYREF:
1351             return static_cast<T>(reinterpret_cast<VarTypConv<TYP_BYREF>::Type*>(c->m_defs)[offset]);
1352         case TYP_INT:
1353             return static_cast<T>(reinterpret_cast<VarTypConv<TYP_INT>::Type*>(c->m_defs)[offset]);
1354         case TYP_LONG:
1355             return static_cast<T>(reinterpret_cast<VarTypConv<TYP_LONG>::Type*>(c->m_defs)[offset]);
1356         case TYP_FLOAT:
1357             return static_cast<T>(reinterpret_cast<VarTypConv<TYP_FLOAT>::Lang*>(c->m_defs)[offset]);
1358         case TYP_DOUBLE:
1359             return static_cast<T>(reinterpret_cast<VarTypConv<TYP_DOUBLE>::Lang*>(c->m_defs)[offset]);
1360         default:
1361             assert(false);
1362             return (T)0;
1363     }
1364 }
1365
1366 // Inline functions.
1367
1368 // static
1369 inline bool ValueNumStore::GenTreeOpIsLegalVNFunc(genTreeOps gtOper)
1370 {
1371     return (s_vnfOpAttribs[gtOper] & VNFOA_IllegalGenTreeOp) == 0;
1372 }
1373
1374 // static
1375 inline bool ValueNumStore::VNFuncIsCommutative(VNFunc vnf)
1376 {
1377     return (s_vnfOpAttribs[vnf] & VNFOA_Commutative) != 0;
1378 }
1379
1380 inline bool ValueNumStore::VNFuncIsComparison(VNFunc vnf)
1381 {
1382     if (vnf >= VNF_Boundary)
1383     {
1384         return false;
1385     }
1386     genTreeOps gtOp = genTreeOps(vnf);
1387     return GenTree::OperIsCompare(gtOp) != 0;
1388 }
1389
1390 template <>
1391 inline size_t ValueNumStore::CoerceTypRefToT(Chunk* c, unsigned offset)
1392 {
1393     return reinterpret_cast<size_t>(reinterpret_cast<VarTypConv<TYP_REF>::Type*>(c->m_defs)[offset]);
1394 }
1395
1396 template <typename T>
1397 inline T ValueNumStore::CoerceTypRefToT(Chunk* c, unsigned offset)
1398 {
1399     noway_assert(sizeof(T) >= sizeof(VarTypConv<TYP_REF>::Type));
1400     unreached();
1401 }
1402
1403 /*****************************************************************************/
1404 #endif // _VALUENUM_H_
1405 /*****************************************************************************/