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.
5 // Defines the class "ValueNumStore", which maintains value numbers for a compilation.
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.
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.
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.
23 /*****************************************************************************/
26 /*****************************************************************************/
31 // Defines the type ValueNum.
32 #include "valuenumtype.h"
33 // Defines the type SmallHashTable.
34 #include "smallhash.h"
36 // A "ValueNumStore" represents the "universe" of value numbers used in a single
39 // All members of the enumeration genTreeOps are also members of VNFunc.
40 // (Though some of these may be labeled "illegal").
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"
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);
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."
63 bool Equals(const VNFuncApp& funcApp)
65 if (m_func != funcApp.m_func)
69 if (m_arity != funcApp.m_arity)
73 for (unsigned i = 0; i < m_arity; i++)
75 if (m_args[i] != funcApp.m_args[i])
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 = "$";
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;
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>
106 VNMap(CompAllocator* alloc) : JitHashTable<fromType, keyfuncs, ValueNum>(alloc)
111 ~VNMap<fromType, keyfuncs>::JitHashTable();
114 bool Set(fromType k, ValueNum val)
116 assert(val != RecursiveVN);
117 return JitHashTable<fromType, keyfuncs, ValueNum>::Set(k, val);
119 bool Lookup(fromType k, ValueNum* pVal = nullptr) const
121 bool result = JitHashTable<fromType, keyfuncs, ValueNum>::Lookup(k, pVal);
122 assert(!result || *pVal != RecursiveVN);
130 // For allocations. (Other things?)
131 CompAllocator* m_alloc;
133 // TODO-Cleanup: should transform "attribs" into a struct with bit fields. That would be simpler...
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
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;
150 // These enum constants are used to encode the cast operation in the lowest bits by VNForCastOper
153 VCA_UnsignedSrc = 0x01,
155 VCA_BitCount = 1, // the number of reserved bits
156 VCA_ReservedBits = 0x01, // i.e. (VCA_UnsignedSrc)
159 // An array of length GT_COUNT, mapping genTreeOp values to their VNFOpAttrib.
160 static UINT8* s_vnfOpAttribs;
162 // Returns "true" iff gtOper is a legal value number function.
163 // (Requires InitValueNumStoreStatics to have been run.)
164 static bool GenTreeOpIsLegalVNFunc(genTreeOps gtOper);
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);
170 // Returns "true" iff "vnf" is a comparison (and thus binary) operator.
171 static bool VNFuncIsComparison(VNFunc vnf);
173 // Returns "true" iff "vnf" can be evaluated for constant arguments.
174 static bool CanEvalForConstantArgs(VNFunc vnf);
177 template <typename T>
178 static T EvalOp(VNFunc vnf, T v0);
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);
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);
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);
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);
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);
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);
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;
228 // This is the constant value used for the default value of m_mapSelectBudget
229 #define DEFAULT_MAP_SELECT_BUDGET 100 // used by JitVNMapSelBudget
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;
236 // Initializes any static variables of ValueNumStore.
237 static void InitValueNumStoreStatics();
239 // Initialize an empty ValueNumStore.
240 ValueNumStore(Compiler* comp, CompAllocator* allocator);
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)
247 return unsigned(vnf) > VNF_Boundary || GenTreeOpIsLegalVNFunc(static_cast<genTreeOps>(vnf));
250 // Returns the arity of "vnf".
251 static unsigned VNFuncArity(VNFunc vnf);
253 // Requires "gtOper" to be a genTreeOps legally representing a VNFunc, and returns that
255 // (Requires InitValueNumStoreStatics to have been run.)
256 static VNFunc GenTreeOpToVNFunc(genTreeOps gtOper)
258 assert(GenTreeOpIsLegalVNFunc(gtOper));
259 return static_cast<VNFunc>(gtOper);
263 static void RunTests(Compiler* comp);
266 // This block of methods gets value numbers for constants of primitive types.
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);
274 #ifdef _TARGET_64BIT_
275 ValueNum VNForPtrSizeIntCon(INT64 cnsVal)
277 return VNForLongCon(cnsVal);
280 ValueNum VNForPtrSizeIntCon(INT32 cnsVal)
282 return VNForIntCon(cnsVal);
286 ValueNum VNForCastOper(var_types castToType, bool srcIsUnsigned = false);
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);
292 // And the single constant for an object reference type.
293 static ValueNum VNForNull()
295 // We reserve Chunk 0 for "special" VNs. SRC_Null (== 0) is the VN of "null".
296 return ValueNum(SRC_Null);
299 // The zero map is the map that returns a zero "for the appropriate type" when indexed at any index.
300 static ValueNum VNForZeroMap()
302 // We reserve Chunk 0 for "special" VNs. Let SRC_ZeroMap (== 1) be the zero map.
303 return ValueNum(SRC_ZeroMap);
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()
310 // We reserve Chunk 0 for "special" VNs. Let SRC_ReadOnlyHeap (== 3) be the read-only heap.
311 return ValueNum(SRC_ReadOnlyHeap);
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()
318 // We reserve Chunk 0 for "special" VNs. Let SRC_Void (== 4) be the value for "void".
319 return ValueNum(SRC_Void);
321 static ValueNumPair VNPForVoid()
323 return ValueNumPair(VNForVoid(), VNForVoid());
326 // A special value number for the empty set of exceptions.
327 static ValueNum VNForEmptyExcSet()
329 // We reserve Chunk 0 for "special" VNs. Let SRC_EmptyExcSet (== 5) be the value for the empty set of
331 return ValueNum(SRC_EmptyExcSet);
333 static ValueNumPair VNPForEmptyExcSet()
335 return ValueNumPair(VNForEmptyExcSet(), VNForEmptyExcSet());
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);
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);
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);
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));
355 ValueNumPair VNPExcSetUnion(ValueNumPair xs0vnp, ValueNumPair xs1vnp);
357 // Returns "true" iff "vn" is an application of "VNF_ValWithExc".
358 bool VNHasExc(ValueNum vn)
361 return GetVNFunc(vn, &funcApp) && funcApp.m_func == VNF_ValWithExc;
364 // Requires that "vn" is *not* a "VNF_ValWithExc" appliation.
365 // If vn "excSet" is not "VNForEmptyExcSet()", return "VNF_ValWithExc(vn, excSet)". Otherwise,
367 ValueNum VNWithExc(ValueNum vn, ValueNum excSet);
369 ValueNumPair VNPWithExc(ValueNumPair vnp, ValueNumPair excSetVNP);
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);
375 void VNPUnpackExc(ValueNumPair vnWx, ValueNumPair* pvn, ValueNumPair* pvnx);
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);
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);
387 // True "iff" vn is a value known to be non-null. (For example, the result of an allocation...)
388 bool IsKnownNonNull(ValueNum vn);
390 // True "iff" vn is a value returned by a call to a shared static helper.
391 bool IsSharedStatic(ValueNum vn);
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);
401 // The following four op VNForFunc is only used for VNF_PtrToArrElem, elemTypeEqVN, arrVN, inxVN, fldSeqVN
403 var_types typ, VNFunc func, ValueNum op1VNwx, ValueNum op2VNwx, ValueNum op3VNwx, ValueNum op4VNwx);
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);
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);
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);
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)
423 res.SetBoth(VNForFunc(typ, func));
426 ValueNumPair VNPairForFunc(var_types typ, VNFunc func, ValueNumPair opVN)
428 return ValueNumPair(VNForFunc(typ, func, opVN.GetLiberal()), VNForFunc(typ, func, opVN.GetConservative()));
430 ValueNumPair VNPairForFunc(var_types typ, VNFunc func, ValueNumPair op1VN, ValueNumPair op2VN)
432 return ValueNumPair(VNForFunc(typ, func, op1VN.GetLiberal(), op2VN.GetLiberal()),
433 VNForFunc(typ, func, op1VN.GetConservative(), op2VN.GetConservative()));
435 ValueNumPair VNPairForFunc(var_types typ, VNFunc func, ValueNumPair op1VN, ValueNumPair op2VN, ValueNumPair op3VN)
437 return ValueNumPair(VNForFunc(typ, func, op1VN.GetLiberal(), op2VN.GetLiberal(), op3VN.GetLiberal()),
438 VNForFunc(typ, func, op1VN.GetConservative(), op2VN.GetConservative(),
439 op3VN.GetConservative()));
441 ValueNumPair VNPairForFunc(
442 var_types typ, VNFunc func, ValueNumPair op1VN, ValueNumPair op2VN, ValueNumPair op3VN, ValueNumPair op4VN)
444 return ValueNumPair(VNForFunc(typ, func, op1VN.GetLiberal(), op2VN.GetLiberal(), op3VN.GetLiberal(),
446 VNForFunc(typ, func, op1VN.GetConservative(), op2VN.GetConservative(),
447 op3VN.GetConservative(), op4VN.GetConservative()));
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);
454 // This controls extra tracing of the "evaluation" of "VNF_MapSelect" functions.
455 #define FEATURE_VN_TRACE_APPLY_SELECTORS 1
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,
464 FieldSeqNode* fieldSeq,
465 size_t* wbFinalStructSize = nullptr);
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);
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);
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);
485 ValueNumPair VNPairApplySelectors(ValueNumPair map, FieldSeqNode* fieldSeq, var_types indType);
487 ValueNumPair VNPairApplySelectorsAssign(
488 ValueNumPair map, FieldSeqNode* fieldSeq, ValueNumPair rhs, var_types indType, BasicBlock* block)
490 return ValueNumPair(VNApplySelectorsAssign(VNK_Liberal, map.GetLiberal(), fieldSeq, rhs.GetLiberal(), indType,
492 VNApplySelectorsAssign(VNK_Conservative, map.GetConservative(), fieldSeq,
493 rhs.GetConservative(), indType, block));
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);
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);
506 // Returns true iff the VN represents an application of VNF_NotAField.
507 bool IsVNNotAField(ValueNum vn);
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);
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);
517 // Both argument must represent field sequences; returns the value number representing the
518 // concatenation "fsVN1 || fsVN2".
519 ValueNum FieldSeqVNAppend(ValueNum fsVN1, ValueNum fsVN2);
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);
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
533 // Returns TYP_UNKNOWN if the given value number has not been given a type.
534 var_types TypeOfVN(ValueNum vn);
536 // Returns MAX_LOOP_NUM if the given value number's loop nest is unknown or ill-defined.
537 BasicBlock::loopNumber LoopOfVN(ValueNum vn);
539 // Returns true iff the VN represents a (non-handle) constant.
540 bool IsVNConstant(ValueNum vn);
542 // Returns true iff the VN represents an integeral constant.
543 bool IsVNInt32Constant(ValueNum vn);
545 typedef SmallHashTable<ValueNum, bool, 8U> CheckedBoundVNSet;
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);
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);
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
563 UnsignedCompareCheckedBoundInfo() : cmpOper(GT_NONE), vnIdx(NoVN), vnBound(NoVN)
568 struct CompareCheckedBoundArithInfo
570 // (vnBound - 1) > vnOp
571 // (vnBound arrOper arrOp) cmpOper cmpOp
577 CompareCheckedBoundArithInfo() : vnBound(NoVN), arrOper(GT_NONE), arrOp(NoVN), cmpOper(GT_NONE), cmpOp(NoVN)
581 void dump(ValueNumStore* vnStore)
583 vnStore->vnDump(vnStore->m_pComp, cmpOp);
585 printf(vnStore->VNFuncName((VNFunc)cmpOper));
587 vnStore->vnDump(vnStore->m_pComp, vnBound);
588 if (arrOper != GT_NONE)
590 printf(vnStore->VNFuncName((VNFunc)arrOper));
591 vnStore->vnDump(vnStore->m_pComp, arrOp);
597 struct ConstantBoundInfo
604 ConstantBoundInfo() : constVal(0), cmpOper(GT_NONE), cmpOpVN(NoVN)
609 void dump(ValueNumStore* vnStore)
611 vnStore->vnDump(vnStore->m_pComp, cmpOpVN);
613 printf(vnStore->VNFuncName((VNFunc)cmpOper));
615 printf("%d", constVal);
620 // Check if "vn" is "new [] (type handle, size)"
621 bool IsVNNewArr(ValueNum vn, VNFuncApp* funcApp);
623 // Check if "vn" IsVNNewArr and return <= 0 if arr size cannot be determined, else array size.
624 int GetNewArrSize(ValueNum vn);
626 // Check if "vn" is "a.len"
627 bool IsVNArrLen(ValueNum vn);
629 // If "vn" is VN(a.len) then return VN(a); NoVN if VN(a) can't be determined.
630 ValueNum GetArrForLenVn(ValueNum vn);
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);
635 // If "vn" is constant bound, then populate the "info" fields for constVal, cmpOp, cmpOper.
636 void GetConstantBoundInfo(ValueNum vn, ConstantBoundInfo* info);
638 // If "vn" is of the form "(uint)var < (uint)len" (or equivalent) return true.
639 bool IsVNUnsignedCompareCheckedBound(ValueNum vn, UnsignedCompareCheckedBoundInfo* info);
641 // If "vn" is of the form "var < len" or "len <= var" return true.
642 bool IsVNCompareCheckedBound(ValueNum vn);
644 // If "vn" is checked bound, then populate the "info" fields for the boundVn, cmpOp, cmpOper.
645 void GetCompareCheckedBound(ValueNum vn, CompareCheckedBoundArithInfo* info);
647 // If "vn" is of the form "len +/- var" return true.
648 bool IsVNCheckedBoundArith(ValueNum vn);
650 // If "vn" is checked bound arith, then populate the "info" fields for arrOper, arrVn, arrOp.
651 void GetCheckedBoundArithInfo(ValueNum vn, CompareCheckedBoundArithInfo* info);
653 // If "vn" is of the form "var < len +/- k" return true.
654 bool IsVNCompareCheckedBoundArith(ValueNum vn);
656 // If "vn" is checked bound arith, then populate the "info" fields for cmpOp, cmpOper.
657 void GetCompareCheckedBoundArithInfo(ValueNum vn, CompareCheckedBoundArithInfo* info);
659 // Returns the flags on the current handle. GTF_ICON_SCOPE_HDL for example.
660 unsigned GetHandleFlags(ValueNum vn);
662 // Returns true iff the VN represents a handle constant.
663 bool IsVNHandle(ValueNum vn);
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.
676 template <typename T>
677 static T CoerceTypRefToT(Chunk* c, unsigned offset);
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);
683 template <typename T>
684 T ConstantValueInternal(ValueNum vn DEBUGARG(bool coerce))
686 Chunk* c = m_chunks.GetNoExpand(GetChunkNum(vn));
687 assert(c->m_attribs == CEA_Const || c->m_attribs == CEA_Handle);
689 unsigned offset = ChunkOffset(vn);
694 assert(0 <= offset && offset <= 1); // Null or exception.
701 assert(&typeid(T) == &typeid(size_t)); // We represent ref/byref constants as size_t's.
711 if (c->m_attribs == CEA_Handle)
713 C_ASSERT(offsetof(VNHandle, m_cnsVal) == 0);
714 return (T) reinterpret_cast<VNHandle*>(c->m_defs)[offset].m_cnsVal;
719 T val1 = reinterpret_cast<T*>(c->m_defs)[offset];
720 T val2 = SafeGetConstantValue<T>(c, offset);
722 // Detect if there is a mismatch between the VN storage type and explicitly
724 bool mismatch = false;
725 if (varTypeIsFloating(c->m_typ))
727 mismatch = (memcmp(&val1, &val2, sizeof(val1)) != 0);
731 mismatch = (val1 != val2);
737 !"Called ConstantValue<T>(vn), but type(T) != type(vn); Use CoercedConstantValue instead.");
741 return SafeGetConstantValue<T>(c, offset);
744 assert(false); // We do not record constants of this typ.
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)
755 return ConstantValueInternal<T>(vn DEBUGARG(false));
758 // Requires that "vn" is a constant, and that its type can be coerced to the explicitly passed
760 template <typename T>
761 T CoercedConstantValue(ValueNum vn)
763 return ConstantValueInternal<T>(vn DEBUGARG(true));
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);
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
775 ValueNum EvalMathFuncUnary(var_types typ, CorInfoIntrinsics mthFunc, ValueNum arg0VN);
777 ValueNum EvalMathFuncBinary(var_types typ, CorInfoIntrinsics mthFunc, ValueNum arg0VN, ValueNum arg1VN);
779 ValueNumPair EvalMathFuncUnary(var_types typ, CorInfoIntrinsics mthFunc, ValueNumPair arg0VNP)
781 return ValueNumPair(EvalMathFuncUnary(typ, mthFunc, arg0VNP.GetLiberal()),
782 EvalMathFuncUnary(typ, mthFunc, arg0VNP.GetConservative()));
785 ValueNumPair EvalMathFuncBinary(var_types typ,
786 CorInfoIntrinsics mthFunc,
787 ValueNumPair arg0VNP,
788 ValueNumPair arg1VNP)
790 return ValueNumPair(EvalMathFuncBinary(typ, mthFunc, arg0VNP.GetLiberal(), arg1VNP.GetLiberal()),
791 EvalMathFuncBinary(typ, mthFunc, arg0VNP.GetConservative(), arg1VNP.GetConservative()));
794 // Returns "true" iff "vn" represents a function application.
795 bool IsVNFunc(ValueNum vn);
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);
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);
805 // Returns "true" iff "vn" is a valid value number -- one that has been previously returned.
806 bool VNIsValid(ValueNum vn);
809 // This controls whether we recursively call vnDump on function arguments.
810 #define FEATURE_VN_DUMP_FUNC_ARGS 0
812 // Prints, to standard out, a representation of "vn".
813 void vnDump(Compiler* comp, ValueNum vn, bool isPtr = false);
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);
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);
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);
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[];
832 // Returns the string name of "vn" when it is a reserved value number, nullptr otherwise
833 static const char* reservedName(ValueNum vn);
837 // Returns true if "vn" is a reserved value number
838 static bool isReservedVN(ValueNum);
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.
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);
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;
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;
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)
866 return vn >> LogChunkSize;
869 // Returns the offset of the given "vn" within its chunk.
870 static unsigned ChunkOffset(ValueNum vn)
872 return vn & ChunkOffsetMask;
875 // The base VN of the next chunk to be allocated. Should always be a multiple of ChunkSize.
876 ValueNum m_nextChunkBase;
878 enum ChunkExtraAttribs : BYTE
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.
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.
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).
902 // The value number of the first VN in the chunk.
905 // The common attributes of this chunk.
907 ChunkExtraAttribs m_attribs;
908 BasicBlock::loopNumber m_loopNum;
910 // Initialize a chunk, starting at "*baseVN", for the given "typ", "attribs", and "loopNum" (using "alloc" for
912 // (Increments "*baseVN" by ChunkSize.)
913 Chunk(CompAllocator* alloc,
916 ChunkExtraAttribs attribs,
917 BasicBlock::loopNumber loopNum);
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.
923 assert(m_numUsed < ChunkSize);
930 typedef typename ValueNumStore::VarTypConv<N>::Type Type;
934 struct VNHandle : public JitKeyFuncsDefEquals<VNHandle>
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)
941 handle->m_cnsVal = m_cnsVal;
942 handle->m_flags = m_flags;
944 bool operator==(const VNHandle& y) const
946 return m_cnsVal == y.m_cnsVal && m_flags == y.m_flags;
948 static unsigned GetHashCode(const VNHandle& val)
950 return static_cast<unsigned>(val.m_cnsVal);
957 VNDefFunc0Arg(VNFunc func) : m_func(func)
961 VNDefFunc0Arg() : m_func(VNF_COUNT)
965 bool operator==(const VNDefFunc0Arg& y) const
967 return m_func == y.m_func;
971 struct VNDefFunc1Arg : public VNDefFunc0Arg
974 VNDefFunc1Arg(VNFunc func, ValueNum arg0) : VNDefFunc0Arg(func), m_arg0(arg0)
978 VNDefFunc1Arg() : VNDefFunc0Arg(), m_arg0(ValueNumStore::NoVN)
982 bool operator==(const VNDefFunc1Arg& y) const
984 return VNDefFunc0Arg::operator==(y) && m_arg0 == y.m_arg0;
988 struct VNDefFunc2Arg : public VNDefFunc1Arg
991 VNDefFunc2Arg(VNFunc func, ValueNum arg0, ValueNum arg1) : VNDefFunc1Arg(func, arg0), m_arg1(arg1)
995 VNDefFunc2Arg() : m_arg1(ValueNumStore::NoVN)
999 bool operator==(const VNDefFunc2Arg& y) const
1001 return VNDefFunc1Arg::operator==(y) && m_arg1 == y.m_arg1;
1005 struct VNDefFunc3Arg : public VNDefFunc2Arg
1008 VNDefFunc3Arg(VNFunc func, ValueNum arg0, ValueNum arg1, ValueNum arg2)
1009 : VNDefFunc2Arg(func, arg0, arg1), m_arg2(arg2)
1012 VNDefFunc3Arg() : m_arg2(ValueNumStore::NoVN)
1016 bool operator==(const VNDefFunc3Arg& y) const
1018 return VNDefFunc2Arg::operator==(y) && m_arg2 == y.m_arg2;
1022 struct VNDefFunc4Arg : public VNDefFunc3Arg
1025 VNDefFunc4Arg(VNFunc func, ValueNum arg0, ValueNum arg1, ValueNum arg2, ValueNum arg3)
1026 : VNDefFunc3Arg(func, arg0, arg1, arg2), m_arg3(arg3)
1029 VNDefFunc4Arg() : m_arg3(ValueNumStore::NoVN)
1033 bool operator==(const VNDefFunc4Arg& y) const
1035 return VNDefFunc3Arg::operator==(y) && m_arg3 == y.m_arg3;
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;
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);
1056 // Returns true if "sel(map, ind)" is a member of "m_fixedPointMapSels".
1057 bool SelectIsBeingEvaluatedRecursively(ValueNum map, ValueNum ind);
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;
1062 // This is a map from "chunk number" to the attributes of the chunk.
1063 JitExpandArrayStack<Chunk*> m_chunks;
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
1070 ChunkNum m_curAllocChunk[TYP_COUNT][CEA_Count + MAX_LOOP_NUM + 1];
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);
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)
1082 return SmallIntConstMin <= i && i <= SmallIntConstMax;
1084 ValueNum m_VNsForSmallIntConsts[SmallIntConstNum];
1090 ValueNumList(const ValueNum& v, ValueNumList* n = nullptr) : vn(v), next(n)
1095 // Keeps track of value numbers that are integer constants and also handles (GTG_ICON_HDL_MASK.)
1096 ValueNumList* m_intConHandles;
1098 typedef VNMap<INT32> IntToValueNumMap;
1099 IntToValueNumMap* m_intCnsMap;
1100 IntToValueNumMap* GetIntCnsMap()
1102 if (m_intCnsMap == nullptr)
1104 m_intCnsMap = new (m_alloc) IntToValueNumMap(m_alloc);
1109 ValueNum GetVNForIntCon(INT32 cnsVal)
1112 if (GetIntCnsMap()->Lookup(cnsVal, &res))
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);
1127 typedef VNMap<INT64> LongToValueNumMap;
1128 LongToValueNumMap* m_longCnsMap;
1129 LongToValueNumMap* GetLongCnsMap()
1131 if (m_longCnsMap == nullptr)
1133 m_longCnsMap = new (m_alloc) LongToValueNumMap(m_alloc);
1135 return m_longCnsMap;
1138 typedef VNMap<VNHandle, VNHandle> HandleToValueNumMap;
1139 HandleToValueNumMap* m_handleMap;
1140 HandleToValueNumMap* GetHandleMap()
1142 if (m_handleMap == nullptr)
1144 m_handleMap = new (m_alloc) HandleToValueNumMap(m_alloc);
1149 struct LargePrimitiveKeyFuncsFloat : public JitLargePrimitiveKeyFuncs<float>
1151 static bool Equals(float x, float y)
1153 return *(unsigned*)&x == *(unsigned*)&y;
1157 typedef VNMap<float, LargePrimitiveKeyFuncsFloat> FloatToValueNumMap;
1158 FloatToValueNumMap* m_floatCnsMap;
1159 FloatToValueNumMap* GetFloatCnsMap()
1161 if (m_floatCnsMap == nullptr)
1163 m_floatCnsMap = new (m_alloc) FloatToValueNumMap(m_alloc);
1165 return m_floatCnsMap;
1168 // In the JIT we need to distinguish -0.0 and 0.0 for optimizations.
1169 struct LargePrimitiveKeyFuncsDouble : public JitLargePrimitiveKeyFuncs<double>
1171 static bool Equals(double x, double y)
1173 return *(__int64*)&x == *(__int64*)&y;
1177 typedef VNMap<double, LargePrimitiveKeyFuncsDouble> DoubleToValueNumMap;
1178 DoubleToValueNumMap* m_doubleCnsMap;
1179 DoubleToValueNumMap* GetDoubleCnsMap()
1181 if (m_doubleCnsMap == nullptr)
1183 m_doubleCnsMap = new (m_alloc) DoubleToValueNumMap(m_alloc);
1185 return m_doubleCnsMap;
1188 LongToValueNumMap* m_byrefCnsMap;
1189 LongToValueNumMap* GetByrefCnsMap()
1191 if (m_byrefCnsMap == nullptr)
1193 m_byrefCnsMap = new (m_alloc) LongToValueNumMap(m_alloc);
1195 return m_byrefCnsMap;
1198 struct VNDefFunc0ArgKeyFuncs : public JitKeyFuncsDefEquals<VNDefFunc1Arg>
1200 static unsigned GetHashCode(VNDefFunc1Arg val)
1202 return (val.m_func << 24) + val.m_arg0;
1205 typedef VNMap<VNFunc> VNFunc0ToValueNumMap;
1206 VNFunc0ToValueNumMap* m_VNFunc0Map;
1207 VNFunc0ToValueNumMap* GetVNFunc0Map()
1209 if (m_VNFunc0Map == nullptr)
1211 m_VNFunc0Map = new (m_alloc) VNFunc0ToValueNumMap(m_alloc);
1213 return m_VNFunc0Map;
1216 struct VNDefFunc1ArgKeyFuncs : public JitKeyFuncsDefEquals<VNDefFunc1Arg>
1218 static unsigned GetHashCode(VNDefFunc1Arg val)
1220 return (val.m_func << 24) + val.m_arg0;
1223 typedef VNMap<VNDefFunc1Arg, VNDefFunc1ArgKeyFuncs> VNFunc1ToValueNumMap;
1224 VNFunc1ToValueNumMap* m_VNFunc1Map;
1225 VNFunc1ToValueNumMap* GetVNFunc1Map()
1227 if (m_VNFunc1Map == nullptr)
1229 m_VNFunc1Map = new (m_alloc) VNFunc1ToValueNumMap(m_alloc);
1231 return m_VNFunc1Map;
1234 struct VNDefFunc2ArgKeyFuncs : public JitKeyFuncsDefEquals<VNDefFunc2Arg>
1236 static unsigned GetHashCode(VNDefFunc2Arg val)
1238 return (val.m_func << 24) + (val.m_arg0 << 8) + val.m_arg1;
1241 typedef VNMap<VNDefFunc2Arg, VNDefFunc2ArgKeyFuncs> VNFunc2ToValueNumMap;
1242 VNFunc2ToValueNumMap* m_VNFunc2Map;
1243 VNFunc2ToValueNumMap* GetVNFunc2Map()
1245 if (m_VNFunc2Map == nullptr)
1247 m_VNFunc2Map = new (m_alloc) VNFunc2ToValueNumMap(m_alloc);
1249 return m_VNFunc2Map;
1252 struct VNDefFunc3ArgKeyFuncs : public JitKeyFuncsDefEquals<VNDefFunc3Arg>
1254 static unsigned GetHashCode(VNDefFunc3Arg val)
1256 return (val.m_func << 24) + (val.m_arg0 << 16) + (val.m_arg1 << 8) + val.m_arg2;
1259 typedef VNMap<VNDefFunc3Arg, VNDefFunc3ArgKeyFuncs> VNFunc3ToValueNumMap;
1260 VNFunc3ToValueNumMap* m_VNFunc3Map;
1261 VNFunc3ToValueNumMap* GetVNFunc3Map()
1263 if (m_VNFunc3Map == nullptr)
1265 m_VNFunc3Map = new (m_alloc) VNFunc3ToValueNumMap(m_alloc);
1267 return m_VNFunc3Map;
1270 struct VNDefFunc4ArgKeyFuncs : public JitKeyFuncsDefEquals<VNDefFunc4Arg>
1272 static unsigned GetHashCode(VNDefFunc4Arg val)
1274 return (val.m_func << 24) + (val.m_arg0 << 16) + (val.m_arg1 << 8) + val.m_arg2 + (val.m_arg3 << 12);
1277 typedef VNMap<VNDefFunc4Arg, VNDefFunc4ArgKeyFuncs> VNFunc4ToValueNumMap;
1278 VNFunc4ToValueNumMap* m_VNFunc4Map;
1279 VNFunc4ToValueNumMap* GetVNFunc4Map()
1281 if (m_VNFunc4Map == nullptr)
1283 m_VNFunc4Map = new (m_alloc) VNFunc4ToValueNumMap(m_alloc);
1285 return m_VNFunc4Map;
1288 enum SpecialRefConsts
1296 SRC_NumSpecialRefConsts
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;
1306 struct ValueNumStore::VarTypConv<TYP_INT>
1312 struct ValueNumStore::VarTypConv<TYP_FLOAT>
1318 struct ValueNumStore::VarTypConv<TYP_LONG>
1324 struct ValueNumStore::VarTypConv<TYP_DOUBLE>
1327 typedef double Lang;
1330 struct ValueNumStore::VarTypConv<TYP_BYREF>
1336 struct ValueNumStore::VarTypConv<TYP_REF>
1338 typedef class Object* Type;
1339 typedef class Object* Lang;
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)
1349 return CoerceTypRefToT<T>(c, offset);
1351 return static_cast<T>(reinterpret_cast<VarTypConv<TYP_BYREF>::Type*>(c->m_defs)[offset]);
1353 return static_cast<T>(reinterpret_cast<VarTypConv<TYP_INT>::Type*>(c->m_defs)[offset]);
1355 return static_cast<T>(reinterpret_cast<VarTypConv<TYP_LONG>::Type*>(c->m_defs)[offset]);
1357 return static_cast<T>(reinterpret_cast<VarTypConv<TYP_FLOAT>::Lang*>(c->m_defs)[offset]);
1359 return static_cast<T>(reinterpret_cast<VarTypConv<TYP_DOUBLE>::Lang*>(c->m_defs)[offset]);
1366 // Inline functions.
1369 inline bool ValueNumStore::GenTreeOpIsLegalVNFunc(genTreeOps gtOper)
1371 return (s_vnfOpAttribs[gtOper] & VNFOA_IllegalGenTreeOp) == 0;
1375 inline bool ValueNumStore::VNFuncIsCommutative(VNFunc vnf)
1377 return (s_vnfOpAttribs[vnf] & VNFOA_Commutative) != 0;
1380 inline bool ValueNumStore::VNFuncIsComparison(VNFunc vnf)
1382 if (vnf >= VNF_Boundary)
1386 genTreeOps gtOp = genTreeOps(vnf);
1387 return GenTree::OperIsCompare(gtOp) != 0;
1391 inline size_t ValueNumStore::CoerceTypRefToT(Chunk* c, unsigned offset)
1393 return reinterpret_cast<size_t>(reinterpret_cast<VarTypConv<TYP_REF>::Type*>(c->m_defs)[offset]);
1396 template <typename T>
1397 inline T ValueNumStore::CoerceTypRefToT(Chunk* c, unsigned offset)
1399 noway_assert(sizeof(T) >= sizeof(VarTypConv<TYP_REF>::Type));
1403 /*****************************************************************************/
1404 #endif // _VALUENUM_H_
1405 /*****************************************************************************/