1
0
Fork 0
mirror of https://github.com/VSadov/Satori.git synced 2025-06-11 18:20:26 +09:00

Save 260k in InitValueNumStoreStatics (#85945)

It appears that the big #define for the intrinsics is causing InitValueNumStoreStatics to get big enough that C++ optimization ends up being disabled, which means a lot of constant operations aren't folded. This rewrites it as a const table. It adds some redundant information to the tables that we #include/#define in several places but currently includes many assertions that the old and new values match.

Local size change of release clrjit_win_x64_x64.dll: 2,001,920 -> 1,735,680.  InitValueNumStoreStatics (261k) is replaced by 1.2k of static data.

Resolves #85953
This commit is contained in:
Mark Plesko 2023-06-05 03:43:22 -07:00 committed by GitHub
parent 2bf8f1aa83
commit 9f8f6531b7
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 2184 additions and 2106 deletions

View file

@ -1329,7 +1329,7 @@ void Compiler::compStartup()
emitter::emitInit();
// Static vars of ValueNumStore
ValueNumStore::InitValueNumStoreStatics();
ValueNumStore::ValidateValueNumStoreStatics();
compDisplayStaticSizes(jitstdout);
}

View file

@ -21,13 +21,13 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
/*****************************************************************************/
const unsigned char GenTree::gtOperKindTable[] = {
#define GTNODE(en, st, cm, ok) ((ok)&GTK_MASK) + GTK_COMMUTE *cm,
#define GTNODE(en, st, cm, ivn, ok) ((ok)&GTK_MASK) + GTK_COMMUTE *cm,
#include "gtlist.h"
};
#ifdef DEBUG
const GenTreeDebugOperKind GenTree::gtDebugOperKindTable[] = {
#define GTNODE(en, st, cm, ok) static_cast<GenTreeDebugOperKind>((ok)&DBK_MASK),
#define GTNODE(en, st, cm, ivn, ok) static_cast<GenTreeDebugOperKind>((ok)&DBK_MASK),
#include "gtlist.h"
};
#endif // DEBUG
@ -171,7 +171,7 @@ static void printIndent(IndentStack* indentStack)
#if defined(DEBUG) || NODEBASH_STATS || MEASURE_NODE_SIZE || COUNT_AST_OPERS || DUMP_FLOWGRAPHS
static const char* opNames[] = {
#define GTNODE(en, st, cm, ok) #en,
#define GTNODE(en, st, cm, ivn, ok) #en,
#include "gtlist.h"
};
@ -187,7 +187,7 @@ const char* GenTree::OpName(genTreeOps op)
#if MEASURE_NODE_SIZE
static const char* opStructNames[] = {
#define GTNODE(en, st, cm, ok) #st,
#define GTNODE(en, st, cm, ivn, ok) #st,
#include "gtlist.h"
};
@ -214,7 +214,7 @@ unsigned char GenTree::s_gtNodeSizes[GT_COUNT + 1];
#if NODEBASH_STATS || MEASURE_NODE_SIZE || COUNT_AST_OPERS
unsigned char GenTree::s_gtTrueSizes[GT_COUNT + 1]{
#define GTNODE(en, st, cm, ok) sizeof(st),
#define GTNODE(en, st, cm, ivn, ok) sizeof(st),
#include "gtlist.h"
};

View file

@ -1087,7 +1087,7 @@ public:
return TypeIs(type) || TypeIs(rest...);
}
static bool StaticOperIs(genTreeOps operCompare, genTreeOps oper)
static constexpr bool StaticOperIs(genTreeOps operCompare, genTreeOps oper)
{
return operCompare == oper;
}

View file

@ -8,7 +8,7 @@
enum genTreeOps : BYTE
{
#define GTNODE(en, st, cm, ok) GT_##en,
#define GTNODE(en, st, cm, ivn, ok) GT_##en,
#include "gtlist.h"
GT_COUNT,

View file

@ -11,164 +11,165 @@
// Node enum
// , GenTree struct flavor
// ,commutative
// ,oper kind | DEBUG oper kind
// ,illegal as VN func
// ,oper kind | DEBUG oper kind
GTNODE(NONE , char ,0,GTK_SPECIAL)
GTNODE(NONE , char ,0,0,GTK_SPECIAL)
//-----------------------------------------------------------------------------
// Nodes related to locals:
//-----------------------------------------------------------------------------
GTNODE(PHI , GenTreePhi ,0,GTK_SPECIAL) // phi node for ssa.
GTNODE(PHI_ARG , GenTreePhiArg ,0,GTK_LEAF) // phi(phiarg, phiarg, phiarg)
GTNODE(LCL_VAR , GenTreeLclVar ,0,GTK_LEAF) // local variable
GTNODE(LCL_FLD , GenTreeLclFld ,0,GTK_LEAF) // field in a non-primitive variable
GTNODE(STORE_LCL_VAR , GenTreeLclVar ,0,GTK_UNOP|GTK_EXOP|GTK_NOVALUE|GTK_STORE) // store to local variable
GTNODE(STORE_LCL_FLD , GenTreeLclFld ,0,GTK_UNOP|GTK_EXOP|GTK_NOVALUE|GTK_STORE) // store to a part of the variable
GTNODE(LCL_ADDR , GenTreeLclFld ,0,GTK_LEAF) // local address
GTNODE(PHI , GenTreePhi ,0,0,GTK_SPECIAL) // phi node for ssa.
GTNODE(PHI_ARG , GenTreePhiArg ,0,0,GTK_LEAF) // phi(phiarg, phiarg, phiarg)
GTNODE(LCL_VAR , GenTreeLclVar ,0,0,GTK_LEAF) // local variable
GTNODE(LCL_FLD , GenTreeLclFld ,0,0,GTK_LEAF) // field in a non-primitive variable
GTNODE(STORE_LCL_VAR , GenTreeLclVar ,0,1,GTK_UNOP|GTK_EXOP|GTK_NOVALUE|GTK_STORE) // store to local variable
GTNODE(STORE_LCL_FLD , GenTreeLclFld ,0,1,GTK_UNOP|GTK_EXOP|GTK_NOVALUE|GTK_STORE) // store to a part of the variable
GTNODE(LCL_ADDR , GenTreeLclFld ,0,0,GTK_LEAF) // local address
//-----------------------------------------------------------------------------
// Leaf nodes (i.e. these nodes have no sub-operands):
//-----------------------------------------------------------------------------
GTNODE(CATCH_ARG , GenTree ,0,GTK_LEAF) // Exception object in a catch block
GTNODE(LABEL , GenTree ,0,GTK_LEAF) // Jump-target
GTNODE(JMP , GenTreeVal ,0,GTK_LEAF|GTK_NOVALUE) // Jump to another function
GTNODE(FTN_ADDR , GenTreeFptrVal ,0,GTK_LEAF) // Address of a function
GTNODE(RET_EXPR , GenTreeRetExpr ,0,GTK_LEAF|DBK_NOTLIR) // Place holder for the return expression from an inline candidate
GTNODE(CATCH_ARG , GenTree ,0,0,GTK_LEAF) // Exception object in a catch block
GTNODE(LABEL , GenTree ,0,0,GTK_LEAF) // Jump-target
GTNODE(JMP , GenTreeVal ,0,0,GTK_LEAF|GTK_NOVALUE) // Jump to another function
GTNODE(FTN_ADDR , GenTreeFptrVal ,0,0,GTK_LEAF) // Address of a function
GTNODE(RET_EXPR , GenTreeRetExpr ,0,0,GTK_LEAF|DBK_NOTLIR) // Place holder for the return expression from an inline candidate
//-----------------------------------------------------------------------------
// Constant nodes:
//-----------------------------------------------------------------------------
GTNODE(CNS_INT , GenTreeIntCon ,0,GTK_LEAF)
GTNODE(CNS_LNG , GenTreeLngCon ,0,GTK_LEAF)
GTNODE(CNS_DBL , GenTreeDblCon ,0,GTK_LEAF)
GTNODE(CNS_STR , GenTreeStrCon ,0,GTK_LEAF)
GTNODE(CNS_VEC , GenTreeVecCon ,0,GTK_LEAF)
GTNODE(CNS_INT , GenTreeIntCon ,0,0,GTK_LEAF)
GTNODE(CNS_LNG , GenTreeLngCon ,0,0,GTK_LEAF)
GTNODE(CNS_DBL , GenTreeDblCon ,0,0,GTK_LEAF)
GTNODE(CNS_STR , GenTreeStrCon ,0,0,GTK_LEAF)
GTNODE(CNS_VEC , GenTreeVecCon ,0,0,GTK_LEAF)
//-----------------------------------------------------------------------------
// Unary operators (1 operand):
//-----------------------------------------------------------------------------
GTNODE(NOT , GenTreeOp ,0,GTK_UNOP)
GTNODE(NOP , GenTree ,0,GTK_UNOP|DBK_NOCONTAIN)
GTNODE(NEG , GenTreeOp ,0,GTK_UNOP)
GTNODE(NOT , GenTreeOp ,0,0,GTK_UNOP)
GTNODE(NOP , GenTree ,0,0,GTK_UNOP|DBK_NOCONTAIN)
GTNODE(NEG , GenTreeOp ,0,0,GTK_UNOP)
GTNODE(INTRINSIC , GenTreeIntrinsic ,0,GTK_BINOP|GTK_EXOP)
GTNODE(INTRINSIC , GenTreeIntrinsic ,0,0,GTK_BINOP|GTK_EXOP)
GTNODE(LOCKADD , GenTreeOp ,0,GTK_BINOP|GTK_NOVALUE|DBK_NOTHIR)
GTNODE(XAND , GenTreeOp ,0,GTK_BINOP)
GTNODE(XORR , GenTreeOp ,0,GTK_BINOP)
GTNODE(XADD , GenTreeOp ,0,GTK_BINOP)
GTNODE(XCHG , GenTreeOp ,0,GTK_BINOP)
GTNODE(CMPXCHG , GenTreeCmpXchg ,0,GTK_SPECIAL)
GTNODE(MEMORYBARRIER , GenTree ,0,GTK_LEAF|GTK_NOVALUE)
GTNODE(LOCKADD , GenTreeOp ,0,1,GTK_BINOP|GTK_NOVALUE|DBK_NOTHIR)
GTNODE(XAND , GenTreeOp ,0,1,GTK_BINOP)
GTNODE(XORR , GenTreeOp ,0,1,GTK_BINOP)
GTNODE(XADD , GenTreeOp ,0,1,GTK_BINOP)
GTNODE(XCHG , GenTreeOp ,0,1,GTK_BINOP)
GTNODE(CMPXCHG , GenTreeCmpXchg ,0,1,GTK_SPECIAL)
GTNODE(MEMORYBARRIER , GenTree ,0,0,GTK_LEAF|GTK_NOVALUE)
GTNODE(KEEPALIVE , GenTree ,0,GTK_UNOP|GTK_NOVALUE) // keep operand alive, generate no code, produce no result
GTNODE(KEEPALIVE , GenTree ,0,0,GTK_UNOP|GTK_NOVALUE) // keep operand alive, generate no code, produce no result
GTNODE(CAST , GenTreeCast ,0,GTK_UNOP|GTK_EXOP) // conversion to another type
GTNODE(CAST , GenTreeCast ,0,0,GTK_UNOP|GTK_EXOP) // conversion to another type
#if defined(TARGET_ARM)
GTNODE(BITCAST , GenTreeMultiRegOp ,0,GTK_UNOP) // reinterpretation of bits as another type
GTNODE(BITCAST , GenTreeMultiRegOp ,0,1,GTK_UNOP) // reinterpretation of bits as another type
#else
GTNODE(BITCAST , GenTreeOp ,0,GTK_UNOP) // reinterpretation of bits as another type
GTNODE(BITCAST , GenTreeOp ,0,1,GTK_UNOP) // reinterpretation of bits as another type
#endif
GTNODE(CKFINITE , GenTreeOp ,0,GTK_UNOP|DBK_NOCONTAIN) // Check for NaN
GTNODE(LCLHEAP , GenTreeOp ,0,GTK_UNOP|DBK_NOCONTAIN) // alloca()
GTNODE(CKFINITE , GenTreeOp ,0,1,GTK_UNOP|DBK_NOCONTAIN) // Check for NaN
GTNODE(LCLHEAP , GenTreeOp ,0,1,GTK_UNOP|DBK_NOCONTAIN) // alloca()
GTNODE(BOUNDS_CHECK , GenTreeBoundsChk ,0,GTK_BINOP|GTK_EXOP|GTK_NOVALUE) // a bounds check - for arrays/spans/SIMDs/HWINTRINSICs
GTNODE(BOUNDS_CHECK , GenTreeBoundsChk ,0,1,GTK_BINOP|GTK_EXOP|GTK_NOVALUE) // a bounds check - for arrays/spans/SIMDs/HWINTRINSICs
GTNODE(IND , GenTreeIndir ,0,GTK_UNOP) // Load indirection
GTNODE(STOREIND , GenTreeStoreInd ,0,GTK_BINOP|GTK_EXOP|GTK_NOVALUE|GTK_STORE) // Store indirection
GTNODE(BLK , GenTreeBlk ,0,GTK_UNOP|GTK_EXOP) // Struct load
GTNODE(STORE_BLK , GenTreeBlk ,0,GTK_BINOP|GTK_EXOP|GTK_NOVALUE|GTK_STORE) // Struct store
GTNODE(STORE_DYN_BLK , GenTreeStoreDynBlk ,0,GTK_SPECIAL|GTK_NOVALUE) // Dynamically sized block store, with native uint size
GTNODE(NULLCHECK , GenTreeIndir ,0,GTK_UNOP|GTK_NOVALUE) // Null checks the source
GTNODE(IND , GenTreeIndir ,0,1,GTK_UNOP) // Load indirection
GTNODE(STOREIND , GenTreeStoreInd ,0,1,GTK_BINOP|GTK_EXOP|GTK_NOVALUE|GTK_STORE) // Store indirection
GTNODE(BLK , GenTreeBlk ,0,1,GTK_UNOP|GTK_EXOP) // Struct load
GTNODE(STORE_BLK , GenTreeBlk ,0,1,GTK_BINOP|GTK_EXOP|GTK_NOVALUE|GTK_STORE) // Struct store
GTNODE(STORE_DYN_BLK , GenTreeStoreDynBlk ,0,1,GTK_SPECIAL|GTK_NOVALUE) // Dynamically sized block store, with native uint size
GTNODE(NULLCHECK , GenTreeIndir ,0,1,GTK_UNOP|GTK_NOVALUE) // Null checks the source
GTNODE(ARR_LENGTH , GenTreeArrLen ,0,GTK_UNOP|GTK_EXOP) // single-dimension (SZ) array length
GTNODE(MDARR_LENGTH , GenTreeMDArr ,0,GTK_UNOP|GTK_EXOP) // multi-dimension (MD) array length of a specific dimension
GTNODE(MDARR_LOWER_BOUND, GenTreeMDArr ,0,GTK_UNOP|GTK_EXOP) // multi-dimension (MD) array lower bound of a specific dimension
GTNODE(FIELD_ADDR , GenTreeFieldAddr ,0,GTK_UNOP|GTK_EXOP|DBK_NOTLIR) // Field address
GTNODE(ALLOCOBJ , GenTreeAllocObj ,0,GTK_UNOP|GTK_EXOP|DBK_NOTLIR) // object allocator
GTNODE(ARR_LENGTH , GenTreeArrLen ,0,0,GTK_UNOP|GTK_EXOP) // single-dimension (SZ) array length
GTNODE(MDARR_LENGTH , GenTreeMDArr ,0,1,GTK_UNOP|GTK_EXOP) // multi-dimension (MD) array length of a specific dimension
GTNODE(MDARR_LOWER_BOUND, GenTreeMDArr ,0,1,GTK_UNOP|GTK_EXOP) // multi-dimension (MD) array lower bound of a specific dimension
GTNODE(FIELD_ADDR , GenTreeFieldAddr ,0,0,GTK_UNOP|GTK_EXOP|DBK_NOTLIR) // Field address
GTNODE(ALLOCOBJ , GenTreeAllocObj ,0,0,GTK_UNOP|GTK_EXOP|DBK_NOTLIR) // object allocator
GTNODE(INIT_VAL , GenTreeOp ,0,GTK_UNOP) // Initialization value for an initBlk
GTNODE(INIT_VAL , GenTreeOp ,0,1,GTK_UNOP) // Initialization value for an initBlk
GTNODE(BOX , GenTreeBox ,0,GTK_UNOP|GTK_EXOP|DBK_NOTLIR) // Marks its first operands (a local) as being a box
GTNODE(RUNTIMELOOKUP , GenTreeRuntimeLookup, 0,GTK_UNOP|GTK_EXOP|DBK_NOTLIR) // Runtime handle lookup
GTNODE(ARR_ADDR , GenTreeArrAddr ,0,GTK_UNOP|GTK_EXOP|DBK_NOTLIR) // Wraps an array address expression
GTNODE(BOX , GenTreeBox ,0,1,GTK_UNOP|GTK_EXOP|DBK_NOTLIR) // Marks its first operands (a local) as being a box
GTNODE(RUNTIMELOOKUP , GenTreeRuntimeLookup, 0,0,GTK_UNOP|GTK_EXOP|DBK_NOTLIR) // Runtime handle lookup
GTNODE(ARR_ADDR , GenTreeArrAddr ,0,1,GTK_UNOP|GTK_EXOP|DBK_NOTLIR) // Wraps an array address expression
GTNODE(BSWAP , GenTreeOp ,0,GTK_UNOP) // Byte swap (32-bit or 64-bit)
GTNODE(BSWAP16 , GenTreeOp ,0,GTK_UNOP) // Byte swap lower 16-bits and zero upper 16 bits
GTNODE(BSWAP , GenTreeOp ,0,0,GTK_UNOP) // Byte swap (32-bit or 64-bit)
GTNODE(BSWAP16 , GenTreeOp ,0,0,GTK_UNOP) // Byte swap lower 16-bits and zero upper 16 bits
GTNODE(LZCNT , GenTreeOp ,0,GTK_UNOP) // Leading Zero Count - Only used for SIMD VN evaluation today
GTNODE(LZCNT , GenTreeOp ,0,0,GTK_UNOP) // Leading Zero Count - Only used for SIMD VN evaluation today
//-----------------------------------------------------------------------------
// Binary operators (2 operands):
//-----------------------------------------------------------------------------
GTNODE(ADD , GenTreeOp ,1,GTK_BINOP)
GTNODE(SUB , GenTreeOp ,0,GTK_BINOP)
GTNODE(MUL , GenTreeOp ,1,GTK_BINOP)
GTNODE(DIV , GenTreeOp ,0,GTK_BINOP)
GTNODE(MOD , GenTreeOp ,0,GTK_BINOP)
GTNODE(ADD , GenTreeOp ,1,0,GTK_BINOP)
GTNODE(SUB , GenTreeOp ,0,0,GTK_BINOP)
GTNODE(MUL , GenTreeOp ,1,0,GTK_BINOP)
GTNODE(DIV , GenTreeOp ,0,0,GTK_BINOP)
GTNODE(MOD , GenTreeOp ,0,0,GTK_BINOP)
GTNODE(UDIV , GenTreeOp ,0,GTK_BINOP)
GTNODE(UMOD , GenTreeOp ,0,GTK_BINOP)
GTNODE(UDIV , GenTreeOp ,0,0,GTK_BINOP)
GTNODE(UMOD , GenTreeOp ,0,0,GTK_BINOP)
GTNODE(OR , GenTreeOp ,1,GTK_BINOP)
GTNODE(XOR , GenTreeOp ,1,GTK_BINOP)
GTNODE(AND , GenTreeOp ,1,GTK_BINOP)
GTNODE(OR , GenTreeOp ,1,0,GTK_BINOP)
GTNODE(XOR , GenTreeOp ,1,0,GTK_BINOP)
GTNODE(AND , GenTreeOp ,1,0,GTK_BINOP)
GTNODE(LSH , GenTreeOp ,0,GTK_BINOP)
GTNODE(RSH , GenTreeOp ,0,GTK_BINOP)
GTNODE(RSZ , GenTreeOp ,0,GTK_BINOP)
GTNODE(ROL , GenTreeOp ,0,GTK_BINOP)
GTNODE(ROR , GenTreeOp ,0,GTK_BINOP)
GTNODE(LSH , GenTreeOp ,0,0,GTK_BINOP)
GTNODE(RSH , GenTreeOp ,0,0,GTK_BINOP)
GTNODE(RSZ , GenTreeOp ,0,0,GTK_BINOP)
GTNODE(ROL , GenTreeOp ,0,0,GTK_BINOP)
GTNODE(ROR , GenTreeOp ,0,0,GTK_BINOP)
GTNODE(EQ , GenTreeOp ,0,GTK_BINOP)
GTNODE(NE , GenTreeOp ,0,GTK_BINOP)
GTNODE(LT , GenTreeOp ,0,GTK_BINOP)
GTNODE(LE , GenTreeOp ,0,GTK_BINOP)
GTNODE(GE , GenTreeOp ,0,GTK_BINOP)
GTNODE(GT , GenTreeOp ,0,GTK_BINOP)
GTNODE(EQ , GenTreeOp ,0,0,GTK_BINOP)
GTNODE(NE , GenTreeOp ,0,0,GTK_BINOP)
GTNODE(LT , GenTreeOp ,0,0,GTK_BINOP)
GTNODE(LE , GenTreeOp ,0,0,GTK_BINOP)
GTNODE(GE , GenTreeOp ,0,0,GTK_BINOP)
GTNODE(GT , GenTreeOp ,0,0,GTK_BINOP)
// These implement EQ/NE(AND(x, y), 0). They always produce a value (GT_TEST is the version that does not).
GTNODE(TEST_EQ , GenTreeOp ,0,GTK_BINOP|DBK_NOTHIR)
GTNODE(TEST_NE , GenTreeOp ,0,GTK_BINOP|DBK_NOTHIR)
GTNODE(TEST_EQ , GenTreeOp ,0,0,GTK_BINOP|DBK_NOTHIR)
GTNODE(TEST_NE , GenTreeOp ,0,0,GTK_BINOP|DBK_NOTHIR)
#ifdef TARGET_XARCH
// BITTEST_EQ/NE(a, n) == EQ/NE(AND(a, LSH(1, n)), 0), but only used in xarch that has the BT instruction
GTNODE(BITTEST_EQ , GenTreeOp ,0,(GTK_BINOP|DBK_NOTHIR))
GTNODE(BITTEST_NE , GenTreeOp ,0,(GTK_BINOP|DBK_NOTHIR))
GTNODE(BITTEST_EQ , GenTreeOp ,0,0,(GTK_BINOP|DBK_NOTHIR))
GTNODE(BITTEST_NE , GenTreeOp ,0,0,(GTK_BINOP|DBK_NOTHIR))
#endif
// Conditional select with 3 operands: condition, true value, false value
GTNODE(SELECT , GenTreeConditional ,0,GTK_SPECIAL)
GTNODE(SELECT , GenTreeConditional ,0,0,GTK_SPECIAL)
GTNODE(COMMA , GenTreeOp ,0,GTK_BINOP|DBK_NOTLIR)
GTNODE(QMARK , GenTreeQmark ,0,GTK_BINOP|GTK_EXOP|DBK_NOTLIR)
GTNODE(COLON , GenTreeColon ,0,GTK_BINOP|DBK_NOTLIR)
GTNODE(COMMA , GenTreeOp ,0,1,GTK_BINOP|DBK_NOTLIR)
GTNODE(QMARK , GenTreeQmark ,0,1,GTK_BINOP|GTK_EXOP|DBK_NOTLIR)
GTNODE(COLON , GenTreeColon ,0,1,GTK_BINOP|DBK_NOTLIR)
GTNODE(INDEX_ADDR , GenTreeIndexAddr ,0,GTK_BINOP|GTK_EXOP) // Address of SZ-array-element.
GTNODE(MKREFANY , GenTreeOp ,0,GTK_BINOP|DBK_NOTLIR)
GTNODE(LEA , GenTreeAddrMode ,0,GTK_BINOP|GTK_EXOP|DBK_NOTHIR)
GTNODE(INDEX_ADDR , GenTreeIndexAddr ,0,0,GTK_BINOP|GTK_EXOP) // Address of SZ-array-element.
GTNODE(MKREFANY , GenTreeOp ,0,0,GTK_BINOP|DBK_NOTLIR)
GTNODE(LEA , GenTreeAddrMode ,0,0,GTK_BINOP|GTK_EXOP|DBK_NOTHIR)
#if !defined(TARGET_64BIT)
// A GT_LONG node simply represents the long value produced by the concatenation
// of its two (lower and upper half) operands. Some GT_LONG nodes are transient,
// during the decomposing of longs; others are handled by codegen as operands of
// nodes such as calls, returns and stores of long lclVars.
GTNODE(LONG , GenTreeOp ,0,GTK_BINOP|DBK_NOTHIR)
GTNODE(LONG , GenTreeOp ,0,0,GTK_BINOP|DBK_NOTHIR)
// The following are nodes representing x86/arm32 specific long operators, including
// high operators of a 64-bit operations that requires a carry/borrow, which are
// named GT_XXX_HI for consistency, low operators of 64-bit operations that need
// to not be modified in phases post-decompose, and operators that return 64-bit
// results in one instruction.
GTNODE(ADD_LO , GenTreeOp ,1,GTK_BINOP|DBK_NOTHIR)
GTNODE(ADD_HI , GenTreeOp ,1,GTK_BINOP|DBK_NOTHIR)
GTNODE(SUB_LO , GenTreeOp ,0,GTK_BINOP|DBK_NOTHIR)
GTNODE(SUB_HI , GenTreeOp ,0,GTK_BINOP|DBK_NOTHIR)
GTNODE(ADD_LO , GenTreeOp ,1,0,GTK_BINOP|DBK_NOTHIR)
GTNODE(ADD_HI , GenTreeOp ,1,0,GTK_BINOP|DBK_NOTHIR)
GTNODE(SUB_LO , GenTreeOp ,0,0,GTK_BINOP|DBK_NOTHIR)
GTNODE(SUB_HI , GenTreeOp ,0,0,GTK_BINOP|DBK_NOTHIR)
// The following are nodes that specify shifts that take a GT_LONG op1. The GT_LONG
// contains the hi and lo parts of three operand shift form where one op will be
@ -177,13 +178,13 @@ GTNODE(SUB_HI , GenTreeOp ,0,GTK_BINOP|DBK_NOTHIR)
// will shift the lo bits of the high operand into the lo operand). LSH_HI
// represents the high operation of a 64-bit left shift by a constant int, and
// RSH_LO represents the lo operation of a 64-bit right shift by a constant int.
GTNODE(LSH_HI , GenTreeOp ,0,GTK_BINOP|DBK_NOTHIR)
GTNODE(RSH_LO , GenTreeOp ,0,GTK_BINOP|DBK_NOTHIR)
GTNODE(LSH_HI , GenTreeOp ,0,0,GTK_BINOP|DBK_NOTHIR)
GTNODE(RSH_LO , GenTreeOp ,0,0,GTK_BINOP|DBK_NOTHIR)
#endif // !defined(TARGET_64BIT)
#ifdef FEATURE_HW_INTRINSICS
GTNODE(HWINTRINSIC , GenTreeHWIntrinsic ,0,GTK_SPECIAL) // hardware intrinsics
GTNODE(HWINTRINSIC , GenTreeHWIntrinsic ,0,0,GTK_SPECIAL) // hardware intrinsics
#endif // FEATURE_HW_INTRINSICS
//-----------------------------------------------------------------------------
@ -191,13 +192,13 @@ GTNODE(HWINTRINSIC , GenTreeHWIntrinsic ,0,GTK_SPECIAL) // ha
//-----------------------------------------------------------------------------
// Saturating increment, used in division by a constant (LowerUnsignedDivOrMod).
GTNODE(INC_SATURATE , GenTreeOp ,0,GTK_UNOP|DBK_NOTHIR)
GTNODE(INC_SATURATE , GenTreeOp ,0,0,GTK_UNOP|DBK_NOTHIR)
// Returns high bits (top N bits of the 2N bit result of an NxN multiply)
// GT_MULHI is used in division by a constant (LowerUnsignedDivOrMod). We turn
// the div into a MULHI + some adjustments. In codegen, we only use the
// results of the high register, and we drop the low results.
GTNODE(MULHI , GenTreeOp ,1,GTK_BINOP|DBK_NOTHIR)
GTNODE(MULHI , GenTreeOp ,1,0,GTK_BINOP|DBK_NOTHIR)
// A mul that returns the 2N bit result of an NxN multiply. This op is used for
// multiplies that take two ints and return a long result. For 32 bit targets,
@ -206,15 +207,15 @@ GTNODE(MULHI , GenTreeOp ,1,GTK_BINOP|DBK_NOTHIR)
// part of the result, whereas GT_MUL_LONG keeps both parts of the result.
// MUL_LONG is also used on ARM64, where 64 bit multiplication is more expensive.
#if !defined(TARGET_64BIT)
GTNODE(MUL_LONG , GenTreeMultiRegOp ,1,GTK_BINOP|DBK_NOTHIR)
GTNODE(MUL_LONG , GenTreeMultiRegOp ,1,0,GTK_BINOP|DBK_NOTHIR)
#elif defined(TARGET_ARM64)
GTNODE(MUL_LONG , GenTreeOp ,1,GTK_BINOP|DBK_NOTHIR)
GTNODE(MUL_LONG , GenTreeOp ,1,0,GTK_BINOP|DBK_NOTHIR)
#endif
// AndNot - emitted on ARM/ARM64 as the BIC instruction. Also used for creating AndNot HWINTRINSIC vector nodes in a cross-ISA manner.
GTNODE(AND_NOT , GenTreeOp ,0,GTK_BINOP|DBK_NOTHIR)
GTNODE(AND_NOT , GenTreeOp ,0,0,GTK_BINOP|DBK_NOTHIR)
#ifdef TARGET_ARM64
GTNODE(BFIZ , GenTreeOp ,0,GTK_BINOP|DBK_NOTHIR) // Bitfield Insert in Zero.
GTNODE(BFIZ , GenTreeOp ,0,0,GTK_BINOP|DBK_NOTHIR) // Bitfield Insert in Zero.
#endif
//-----------------------------------------------------------------------------
@ -222,102 +223,102 @@ GTNODE(BFIZ , GenTreeOp ,0,GTK_BINOP|DBK_NOTHIR) // Bitfiel
//-----------------------------------------------------------------------------
// Sets the condition flags according to the compare result. N.B. Not a relop, it does not produce a value and it cannot be reversed.
GTNODE(CMP , GenTreeOp ,0,GTK_BINOP|GTK_NOVALUE|DBK_NOTHIR)
GTNODE(CMP , GenTreeOp ,0,0,GTK_BINOP|GTK_NOVALUE|DBK_NOTHIR)
// Generate a test instruction; sets the CPU flags according to (a & b) and does not produce a value.
GTNODE(TEST , GenTreeOp ,0,GTK_BINOP|GTK_NOVALUE|DBK_NOTHIR)
GTNODE(TEST , GenTreeOp ,0,0,GTK_BINOP|GTK_NOVALUE|DBK_NOTHIR)
#ifdef TARGET_XARCH
// The XARCH BT instruction. Like CMP, this sets the condition flags (CF to be precise) and does not produce a value.
GTNODE(BT , GenTreeOp ,0,(GTK_BINOP|GTK_NOVALUE|DBK_NOTHIR))
GTNODE(BT , GenTreeOp ,0,0,(GTK_BINOP|GTK_NOVALUE|DBK_NOTHIR))
#endif
// Makes a comparison and jumps if the condition specified by gtCondition is true. Does not set flags.
GTNODE(JCMP , GenTreeOpCC ,0,GTK_BINOP|GTK_NOVALUE|DBK_NOTHIR)
GTNODE(JCMP , GenTreeOpCC ,0,0,GTK_BINOP|GTK_NOVALUE|DBK_NOTHIR)
// Do a bit test and jump if set/not set.
GTNODE(JTEST , GenTreeOpCC ,0,GTK_BINOP|GTK_NOVALUE|DBK_NOTHIR)
GTNODE(JTEST , GenTreeOpCC ,0,0,GTK_BINOP|GTK_NOVALUE|DBK_NOTHIR)
// Checks the condition flags and branch if the condition specified by GenTreeCC::gtCondition is true.
GTNODE(JCC , GenTreeCC ,0,GTK_LEAF|GTK_NOVALUE|DBK_NOTHIR)
GTNODE(JCC , GenTreeCC ,0,0,GTK_LEAF|GTK_NOVALUE|DBK_NOTHIR)
// Checks the condition flags and produces 1 if the condition specified by GenTreeCC::gtCondition is true and 0 otherwise.
GTNODE(SETCC , GenTreeCC ,0,GTK_LEAF|DBK_NOTHIR)
GTNODE(SETCC , GenTreeCC ,0,0,GTK_LEAF|DBK_NOTHIR)
// Variant of SELECT that reuses flags computed by a previous node with the specified condition.
GTNODE(SELECTCC , GenTreeOpCC ,0,GTK_BINOP|DBK_NOTHIR)
GTNODE(SELECTCC , GenTreeOpCC ,0,0,GTK_BINOP|DBK_NOTHIR)
#ifdef TARGET_ARM64
// The arm64 ccmp instruction. If the specified condition is true, compares two
// operands and sets the condition flags according to the result. Otherwise
// sets the condition flags to the specified immediate value.
GTNODE(CCMP , GenTreeCCMP ,0,GTK_BINOP|GTK_NOVALUE|DBK_NOTHIR)
GTNODE(CCMP , GenTreeCCMP ,0,0,GTK_BINOP|GTK_NOVALUE|DBK_NOTHIR)
// Maps to arm64 csinc/cinc instruction. Computes result = condition ? op1 : op2 + 1.
// If op2 is null, computes result = condition ? op1 + 1 : op1.
GTNODE(SELECT_INC , GenTreeOp ,0,GTK_BINOP|DBK_NOTHIR)
GTNODE(SELECT_INC , GenTreeOp ,0,0,GTK_BINOP|DBK_NOTHIR)
// Variant of SELECT_INC that reuses flags computed by a previous node with the specified condition.
GTNODE(SELECT_INCCC , GenTreeOpCC ,0,GTK_BINOP|DBK_NOTHIR)
GTNODE(SELECT_INCCC , GenTreeOpCC ,0,0,GTK_BINOP|DBK_NOTHIR)
// Maps to arm64 csinv/cinv instruction. Computes result = condition ? op1 : ~op2.
// If op2 is null, computes result = condition ? ~op1 : op1.
GTNODE(SELECT_INV , GenTreeOp ,0,GTK_BINOP|DBK_NOTHIR)
GTNODE(SELECT_INV , GenTreeOp ,0,0,GTK_BINOP|DBK_NOTHIR)
// Variant of SELECT_INV that reuses flags computed by a previous node with the specified condition.
GTNODE(SELECT_INVCC , GenTreeOpCC ,0,GTK_BINOP|DBK_NOTHIR)
GTNODE(SELECT_INVCC , GenTreeOpCC ,0,0,GTK_BINOP|DBK_NOTHIR)
// Maps to arm64 csneg/cneg instruction.. Computes result = condition ? op1 : -op2.
// If op2 is null, computes result = condition ? -op1 : op1.
GTNODE(SELECT_NEG , GenTreeOp ,0,GTK_BINOP|DBK_NOTHIR)
GTNODE(SELECT_NEG , GenTreeOp ,0,0,GTK_BINOP|DBK_NOTHIR)
// Variant of SELECT_NEG that reuses flags computed by a previous node with the specified condition.
GTNODE(SELECT_NEGCC , GenTreeOpCC ,0,GTK_BINOP|DBK_NOTHIR)
GTNODE(SELECT_NEGCC , GenTreeOpCC ,0,0,GTK_BINOP|DBK_NOTHIR)
#endif
//-----------------------------------------------------------------------------
// Other nodes that look like unary/binary operators:
//-----------------------------------------------------------------------------
GTNODE(JTRUE , GenTreeOp ,0,GTK_UNOP|GTK_NOVALUE)
GTNODE(JTRUE , GenTreeOp ,0,1,GTK_UNOP|GTK_NOVALUE)
//-----------------------------------------------------------------------------
// Other nodes that have special structure:
//-----------------------------------------------------------------------------
GTNODE(ARR_ELEM , GenTreeArrElem ,0,GTK_SPECIAL) // Multi-dimensional array-element address
GTNODE(CALL , GenTreeCall ,0,GTK_SPECIAL|DBK_NOCONTAIN)
GTNODE(FIELD_LIST , GenTreeFieldList ,0,GTK_SPECIAL) // List of fields of a struct, when passed as an argument
GTNODE(ARR_ELEM , GenTreeArrElem ,0,0,GTK_SPECIAL) // Multi-dimensional array-element address
GTNODE(CALL , GenTreeCall ,0,0,GTK_SPECIAL|DBK_NOCONTAIN)
GTNODE(FIELD_LIST , GenTreeFieldList ,0,0,GTK_SPECIAL) // List of fields of a struct, when passed as an argument
GTNODE(RETURN , GenTreeOp ,0,GTK_UNOP|GTK_NOVALUE)
GTNODE(SWITCH , GenTreeOp ,0,GTK_UNOP|GTK_NOVALUE)
GTNODE(NO_OP , GenTree ,0,GTK_LEAF|GTK_NOVALUE) // A NOP that cannot be deleted.
GTNODE(RETURN , GenTreeOp ,0,1,GTK_UNOP|GTK_NOVALUE)
GTNODE(SWITCH , GenTreeOp ,0,1,GTK_UNOP|GTK_NOVALUE)
GTNODE(NO_OP , GenTree ,0,0,GTK_LEAF|GTK_NOVALUE) // A NOP that cannot be deleted.
GTNODE(START_NONGC , GenTree ,0,GTK_LEAF|GTK_NOVALUE|DBK_NOTHIR) // Starts a new instruction group that will be non-gc interruptible.
GTNODE(START_PREEMPTGC , GenTree ,0,GTK_LEAF|GTK_NOVALUE|DBK_NOTHIR) // Starts a new instruction group where preemptive GC is enabled.
GTNODE(PROF_HOOK , GenTree ,0,GTK_LEAF|GTK_NOVALUE|DBK_NOTHIR) // Profiler Enter/Leave/TailCall hook.
GTNODE(START_NONGC , GenTree ,0,0,GTK_LEAF|GTK_NOVALUE|DBK_NOTHIR) // Starts a new instruction group that will be non-gc interruptible.
GTNODE(START_PREEMPTGC , GenTree ,0,0,GTK_LEAF|GTK_NOVALUE|DBK_NOTHIR) // Starts a new instruction group where preemptive GC is enabled.
GTNODE(PROF_HOOK , GenTree ,0,0,GTK_LEAF|GTK_NOVALUE|DBK_NOTHIR) // Profiler Enter/Leave/TailCall hook.
GTNODE(RETFILT , GenTreeOp ,0,GTK_UNOP|GTK_NOVALUE) // End filter with TYP_I_IMPL return value.
GTNODE(RETFILT , GenTreeOp ,0,1,GTK_UNOP|GTK_NOVALUE) // End filter with TYP_I_IMPL return value.
#if !defined(FEATURE_EH_FUNCLETS)
GTNODE(END_LFIN , GenTreeVal ,0,GTK_LEAF|GTK_NOVALUE) // End locally-invoked finally.
GTNODE(END_LFIN , GenTreeVal ,0,0,GTK_LEAF|GTK_NOVALUE) // End locally-invoked finally.
#endif // !FEATURE_EH_FUNCLETS
//-----------------------------------------------------------------------------
// Nodes used by Lower to generate a closer CPU representation of other nodes
//-----------------------------------------------------------------------------
GTNODE(JMPTABLE , GenTree ,0,GTK_LEAF|DBK_NOCONTAIN|DBK_NOTHIR) // Generates the jump table for switches
GTNODE(SWITCH_TABLE , GenTreeOp ,0,GTK_BINOP|GTK_NOVALUE|DBK_NOTHIR) // Jump Table based switch construct
GTNODE(JMPTABLE , GenTree ,0,0,GTK_LEAF|DBK_NOCONTAIN|DBK_NOTHIR) // Generates the jump table for switches
GTNODE(SWITCH_TABLE , GenTreeOp ,0,0,GTK_BINOP|GTK_NOVALUE|DBK_NOTHIR) // Jump Table based switch construct
//-----------------------------------------------------------------------------
// Nodes used only within the code generator:
//-----------------------------------------------------------------------------
GTNODE(CLS_VAR_ADDR , GenTreeClsVar ,0,GTK_LEAF|DBK_NOTHIR) // static data member address
GTNODE(PHYSREG , GenTreePhysReg ,0,GTK_LEAF|DBK_NOTHIR) // read from a physical register
GTNODE(EMITNOP , GenTree ,0,GTK_LEAF|GTK_NOVALUE|DBK_NOTHIR) // emitter-placed nop
GTNODE(PINVOKE_PROLOG , GenTree ,0,GTK_LEAF|GTK_NOVALUE|DBK_NOTHIR) // pinvoke prolog seq
GTNODE(PINVOKE_EPILOG , GenTree ,0,GTK_LEAF|GTK_NOVALUE|DBK_NOTHIR) // pinvoke epilog seq
GTNODE(RETURNTRAP , GenTreeOp ,0,GTK_UNOP|GTK_NOVALUE|DBK_NOTHIR) // a conditional call to wait on gc
GTNODE(CLS_VAR_ADDR , GenTreeClsVar ,0,0,GTK_LEAF|DBK_NOTHIR) // static data member address
GTNODE(PHYSREG , GenTreePhysReg ,0,0,GTK_LEAF|DBK_NOTHIR) // read from a physical register
GTNODE(EMITNOP , GenTree ,0,0,GTK_LEAF|GTK_NOVALUE|DBK_NOTHIR) // emitter-placed nop
GTNODE(PINVOKE_PROLOG , GenTree ,0,0,GTK_LEAF|GTK_NOVALUE|DBK_NOTHIR) // pinvoke prolog seq
GTNODE(PINVOKE_EPILOG , GenTree ,0,0,GTK_LEAF|GTK_NOVALUE|DBK_NOTHIR) // pinvoke epilog seq
GTNODE(RETURNTRAP , GenTreeOp ,0,0,GTK_UNOP|GTK_NOVALUE|DBK_NOTHIR) // a conditional call to wait on gc
#if defined(TARGET_ARM)
GTNODE(PUTARG_REG , GenTreeMultiRegOp ,0,GTK_UNOP|DBK_NOTHIR) // operator that places outgoing arg in register
GTNODE(PUTARG_REG , GenTreeMultiRegOp ,0,0,GTK_UNOP|DBK_NOTHIR) // operator that places outgoing arg in register
#else
GTNODE(PUTARG_REG , GenTreeOp ,0,GTK_UNOP|DBK_NOTHIR) // operator that places outgoing arg in register
GTNODE(PUTARG_REG , GenTreeOp ,0,0,GTK_UNOP|DBK_NOTHIR) // operator that places outgoing arg in register
#endif
GTNODE(PUTARG_STK , GenTreePutArgStk ,0,GTK_UNOP|GTK_NOVALUE|DBK_NOTHIR) // operator that places outgoing arg in stack
GTNODE(PUTARG_STK , GenTreePutArgStk ,0,0,GTK_UNOP|GTK_NOVALUE|DBK_NOTHIR) // operator that places outgoing arg in stack
#if FEATURE_ARG_SPLIT
GTNODE(PUTARG_SPLIT , GenTreePutArgSplit ,0,GTK_UNOP|DBK_NOTHIR) // operator that places outgoing arg in registers with stack (split struct in ARM32)
GTNODE(PUTARG_SPLIT , GenTreePutArgSplit ,0,0,GTK_UNOP|DBK_NOTHIR) // operator that places outgoing arg in registers with stack (split struct in ARM32)
#endif // FEATURE_ARG_SPLIT
GTNODE(SWAP , GenTreeOp ,0,GTK_BINOP|GTK_NOVALUE|DBK_NOTHIR) // op1 and op2 swap (registers)
GTNODE(COPY , GenTreeCopyOrReload,0,GTK_UNOP|DBK_NOTHIR) // Copies a variable from its current location to a register that satisfies
GTNODE(RELOAD , GenTreeCopyOrReload,0,GTK_UNOP|DBK_NOTHIR) // code generation constraints. The operand is the actual lclVar node.
GTNODE(IL_OFFSET , GenTreeILOffset ,0,GTK_LEAF|GTK_NOVALUE|DBK_NOTHIR) // marks an IL offset for debugging purposes
GTNODE(SWAP , GenTreeOp ,0,0,GTK_BINOP|GTK_NOVALUE|DBK_NOTHIR) // op1 and op2 swap (registers)
GTNODE(COPY , GenTreeCopyOrReload,0,0,GTK_UNOP|DBK_NOTHIR) // Copies a variable from its current location to a register that satisfies
GTNODE(RELOAD , GenTreeCopyOrReload,0,0,GTK_UNOP|DBK_NOTHIR) // code generation constraints. The operand is the actual lclVar node.
GTNODE(IL_OFFSET , GenTreeILOffset ,0,0,GTK_LEAF|GTK_NOVALUE|DBK_NOTHIR) // marks an IL offset for debugging purposes
/*****************************************************************************/
#undef GTNODE

View file

@ -9,7 +9,7 @@
static const HWIntrinsicInfo hwIntrinsicInfoArray[] = {
// clang-format off
#if defined(TARGET_XARCH)
#define HARDWARE_INTRINSIC(isa, name, size, numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, flag) \
#define HARDWARE_INTRINSIC(isa, name, size, numarg, extra, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, flag) \
{ \
/* name */ #name, \
/* flags */ static_cast<HWIntrinsicFlag>(flag), \
@ -22,7 +22,7 @@ static const HWIntrinsicInfo hwIntrinsicInfoArray[] = {
},
#include "hwintrinsiclistxarch.h"
#elif defined (TARGET_ARM64)
#define HARDWARE_INTRINSIC(isa, name, size, numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, flag) \
#define HARDWARE_INTRINSIC(isa, name, size, numarg, extra, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, flag) \
{ \
/* name */ #name, \
/* flags */ static_cast<HWIntrinsicFlag>(flag), \

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -126,11 +126,11 @@ enum NamedIntrinsic : unsigned short
#ifdef FEATURE_HW_INTRINSICS
NI_HW_INTRINSIC_START,
#if defined(TARGET_XARCH)
#define HARDWARE_INTRINSIC(isa, name, size, numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, flag) \
#define HARDWARE_INTRINSIC(isa, name, size, numarg, extra, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, flag) \
NI_##isa##_##name,
#include "hwintrinsiclistxarch.h"
#elif defined(TARGET_ARM64)
#define HARDWARE_INTRINSIC(isa, name, size, numarg, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, flag) \
#define HARDWARE_INTRINSIC(isa, name, size, numarg, extra, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, flag) \
NI_##isa##_##name,
#include "hwintrinsiclistarm64.h"
#endif // !defined(TARGET_XARCH) && !defined(TARGET_ARM64)

View file

@ -8852,7 +8852,65 @@ void ValueNumStore::vnDumpZeroObj(Compiler* comp, VNFuncApp* zeroObj)
#endif // DEBUG
// Static fields, methods.
static UINT8 vnfOpAttribs[VNF_COUNT];
#define ValueNumFuncDef(vnf, arity, commute, knownNonNull, sharedStatic, extra) \
static_assert((arity) >= 0 || !(extra), "valuenumfuncs.h has EncodesExtraTypeArg==true and arity<0 for " #vnf);
#include "valuenumfuncs.h"
#ifdef FEATURE_HW_INTRINSICS
#define HARDWARE_INTRINSIC(isa, name, size, argCount, extra, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, flag) \
static_assert((size) != 0 || !(extra), \
"hwintrinsicslist<arch>.h has EncodesExtraTypeArg==true and size==0 for " #isa " " #name);
#if defined(TARGET_XARCH)
#include "hwintrinsiclistxarch.h"
#elif defined(TARGET_ARM64)
#include "hwintrinsiclistarm64.h"
#else
#error Unsupported platform
#endif
#endif // FEATURE_HW_INTRINSICS
/* static */ constexpr uint8_t ValueNumStore::GetOpAttribsForArity(genTreeOps oper, GenTreeOperKind kind)
{
return ((GenTree::StaticOperIs(oper, GT_SELECT) ? 3 : (((kind & GTK_UNOP) >> 1) | ((kind & GTK_BINOP) >> 1)))
<< VNFOA_ArityShift) &
VNFOA_ArityMask;
}
/* static */ constexpr uint8_t ValueNumStore::GetOpAttribsForGenTree(genTreeOps oper,
bool commute,
bool illegalAsVNFunc,
GenTreeOperKind kind)
{
return GetOpAttribsForArity(oper, kind) | (static_cast<uint8_t>(commute) << VNFOA_CommutativeShift) |
(static_cast<uint8_t>(illegalAsVNFunc) << VNFOA_IllegalGenTreeOpShift);
}
/* static */ constexpr uint8_t ValueNumStore::GetOpAttribsForFunc(int arity,
bool commute,
bool knownNonNull,
bool sharedStatic)
{
return (static_cast<uint8_t>(commute) << VNFOA_CommutativeShift) |
(static_cast<uint8_t>(knownNonNull) << VNFOA_KnownNonNullShift) |
(static_cast<uint8_t>(sharedStatic) << VNFOA_SharedStaticShift) |
((static_cast<uint8_t>(arity & ~(arity >> 31)) << VNFOA_ArityShift) & VNFOA_ArityMask);
}
const uint8_t ValueNumStore::s_vnfOpAttribs[VNF_COUNT] = {
#define GTNODE(en, st, cm, ivn, ok) \
GetOpAttribsForGenTree(static_cast<genTreeOps>(GT_##en), cm, ivn, static_cast<GenTreeOperKind>(ok)),
#include "gtlist.h"
0, // VNF_Boundary
#define ValueNumFuncDef(vnf, arity, commute, knownNonNull, sharedStatic, extra) \
GetOpAttribsForFunc((arity) + static_cast<int>(extra), commute, knownNonNull, sharedStatic),
#include "valuenumfuncs.h"
};
static genTreeOps genTreeOpsIllegalAsVNFunc[] = {GT_IND, // When we do heap memory.
GT_NULLCHECK, GT_QMARK, GT_COLON, GT_LOCKADD, GT_XADD, GT_XCHG,
GT_CMPXCHG, GT_LCLHEAP, GT_BOX, GT_XORR, GT_XAND, GT_STORE_DYN_BLK,
@ -8869,15 +8927,10 @@ static genTreeOps genTreeOpsIllegalAsVNFunc[] = {GT_IND, // When we do heap memo
// These control-flow operations need no values.
GT_JTRUE, GT_RETURN, GT_SWITCH, GT_RETFILT, GT_CKFINITE};
UINT8* ValueNumStore::s_vnfOpAttribs = nullptr;
void ValueNumStore::InitValueNumStoreStatics()
void ValueNumStore::ValidateValueNumStoreStatics()
{
// Make sure we have the constants right...
assert(unsigned(VNFOA_Arity1) == (1 << VNFOA_ArityShift));
assert(VNFOA_ArityMask == (VNFOA_MaxArity << VNFOA_ArityShift));
s_vnfOpAttribs = &vnfOpAttribs[0];
#if DEBUG
uint8_t arr[VNF_COUNT] = {};
for (unsigned i = 0; i < GT_COUNT; i++)
{
genTreeOps gtOper = static_cast<genTreeOps>(i);
@ -8895,11 +8948,11 @@ void ValueNumStore::InitValueNumStoreStatics()
arity = 3;
}
vnfOpAttribs[i] |= ((arity << VNFOA_ArityShift) & VNFOA_ArityMask);
arr[i] |= ((arity << VNFOA_ArityShift) & VNFOA_ArityMask);
if (GenTree::OperIsCommutative(gtOper))
{
vnfOpAttribs[i] |= VNFOA_Commutative;
arr[i] |= VNFOA_Commutative;
}
}
@ -8907,25 +8960,24 @@ void ValueNumStore::InitValueNumStoreStatics()
int vnfNum = VNF_Boundary + 1; // The macro definition below will update this after using it.
#define ValueNumFuncDef(vnf, arity, commute, knownNonNull, sharedStatic) \
#define ValueNumFuncDef(vnf, arity, commute, knownNonNull, sharedStatic, extra) \
if (commute) \
vnfOpAttribs[vnfNum] |= VNFOA_Commutative; \
arr[vnfNum] |= VNFOA_Commutative; \
if (knownNonNull) \
vnfOpAttribs[vnfNum] |= VNFOA_KnownNonNull; \
arr[vnfNum] |= VNFOA_KnownNonNull; \
if (sharedStatic) \
vnfOpAttribs[vnfNum] |= VNFOA_SharedStatic; \
arr[vnfNum] |= VNFOA_SharedStatic; \
if (arity > 0) \
vnfOpAttribs[vnfNum] |= ((arity << VNFOA_ArityShift) & VNFOA_ArityMask); \
arr[vnfNum] |= ((arity << VNFOA_ArityShift) & VNFOA_ArityMask); \
vnfNum++;
#include "valuenumfuncs.h"
#undef ValueNumFuncDef
assert(vnfNum == VNF_COUNT);
#define ValueNumFuncSetArity(vnfNum, arity) \
vnfOpAttribs[vnfNum] &= ~VNFOA_ArityMask; /* clear old arity value */ \
vnfOpAttribs[vnfNum] |= ((arity << VNFOA_ArityShift) & VNFOA_ArityMask) /* set the new arity value */
arr[vnfNum] &= ~VNFOA_ArityMask; /* clear old arity value */ \
arr[vnfNum] |= ((arity << VNFOA_ArityShift) & VNFOA_ArityMask) /* set the new arity value */
#ifdef FEATURE_HW_INTRINSICS
@ -8939,7 +8991,7 @@ void ValueNumStore::InitValueNumStoreStatics()
// These HW_Intrinsic's have an extra VNF_SimdType arg.
//
VNFunc func = VNFunc(VNF_HWI_FIRST + (id - NI_HW_INTRINSIC_START - 1));
unsigned oldArity = VNFuncArity(func);
unsigned oldArity = (arr[func] & VNFOA_ArityMask) >> VNFOA_ArityShift;
unsigned newArity = oldArity + 1;
ValueNumFuncSetArity(func, newArity);
@ -8948,7 +9000,7 @@ void ValueNumStore::InitValueNumStoreStatics()
if (HWIntrinsicInfo::IsCommutative(id))
{
VNFunc func = VNFunc(VNF_HWI_FIRST + (id - NI_HW_INTRINSIC_START - 1));
vnfOpAttribs[func] |= VNFOA_Commutative;
arr[func] |= VNFOA_Commutative;
}
}
@ -8958,17 +9010,23 @@ void ValueNumStore::InitValueNumStoreStatics()
for (unsigned i = 0; i < ArrLen(genTreeOpsIllegalAsVNFunc); i++)
{
vnfOpAttribs[genTreeOpsIllegalAsVNFunc[i]] |= VNFOA_IllegalGenTreeOp;
arr[genTreeOpsIllegalAsVNFunc[i]] |= VNFOA_IllegalGenTreeOp;
}
assert(ArrLen(arr) == ArrLen(s_vnfOpAttribs));
for (unsigned i = 0; i < ArrLen(arr); i++)
{
assert(arr[i] == s_vnfOpAttribs[i]);
}
#endif // DEBUG
}
#ifdef DEBUG
// Define the name array.
#define ValueNumFuncDef(vnf, arity, commute, knownNonNull, sharedStatic) #vnf,
#define ValueNumFuncDef(vnf, arity, commute, knownNonNull, sharedStatic, extra) #vnf,
const char* ValueNumStore::VNFuncNameArr[] = {
#include "valuenumfuncs.h"
#undef ValueNumFuncDef
};
/* static */ const char* ValueNumStore::VNFuncName(VNFunc vnf)

View file

@ -167,7 +167,7 @@ enum VNFunc
{
// Implicitly, elements of genTreeOps here.
VNF_Boundary = GT_COUNT,
#define ValueNumFuncDef(nm, arity, commute, knownNonNull, sharedStatic) VNF_##nm,
#define ValueNumFuncDef(nm, arity, commute, knownNonNull, sharedStatic, extra) VNF_##nm,
#include "valuenumfuncs.h"
VNF_COUNT
};
@ -275,10 +275,21 @@ private:
VNFOA_SharedStatic = 0x40, // 1 iff this VNF is represent one of the shared static jit helpers
};
static const unsigned VNFOA_ArityShift = 2;
static const unsigned VNFOA_ArityBits = 3;
static const unsigned VNFOA_MaxArity = (1 << VNFOA_ArityBits) - 1; // Max arity we can represent.
static const unsigned VNFOA_ArityMask = (VNFOA_Arity4 | VNFOA_Arity2 | VNFOA_Arity1);
static const unsigned VNFOA_IllegalGenTreeOpShift = 0;
static const unsigned VNFOA_CommutativeShift = 1;
static const unsigned VNFOA_ArityShift = 2;
static const unsigned VNFOA_ArityBits = 3;
static const unsigned VNFOA_MaxArity = (1 << VNFOA_ArityBits) - 1; // Max arity we can represent.
static const unsigned VNFOA_ArityMask = (VNFOA_Arity4 | VNFOA_Arity2 | VNFOA_Arity1);
static const unsigned VNFOA_KnownNonNullShift = 5;
static const unsigned VNFOA_SharedStaticShift = 6;
static_assert(unsigned(VNFOA_IllegalGenTreeOp) == (1 << VNFOA_IllegalGenTreeOpShift));
static_assert(unsigned(VNFOA_Commutative) == (1 << VNFOA_CommutativeShift));
static_assert(unsigned(VNFOA_Arity1) == (1 << VNFOA_ArityShift));
static_assert(VNFOA_ArityMask == (VNFOA_MaxArity << VNFOA_ArityShift));
static_assert(unsigned(VNFOA_KnownNonNull) == (1 << VNFOA_KnownNonNullShift));
static_assert(unsigned(VNFOA_SharedStatic) == (1 << VNFOA_SharedStaticShift));
// These enum constants are used to encode the cast operation in the lowest bits by VNForCastOper
enum VNFCastAttrib
@ -289,8 +300,14 @@ private:
VCA_ReservedBits = 0x01, // i.e. (VCA_UnsignedSrc)
};
// An array of length GT_COUNT, mapping genTreeOp values to their VNFOpAttrib.
static UINT8* s_vnfOpAttribs;
// Helpers and an array of length GT_COUNT, mapping genTreeOp values to their VNFOpAttrib.
static constexpr uint8_t GetOpAttribsForArity(genTreeOps oper, GenTreeOperKind kind);
static constexpr uint8_t GetOpAttribsForGenTree(genTreeOps oper,
bool commute,
bool illegalAsVNFunc,
GenTreeOperKind kind);
static constexpr uint8_t GetOpAttribsForFunc(int arity, bool commute, bool knownNonNull, bool sharedStatic);
static const uint8_t s_vnfOpAttribs[];
// Returns "true" iff gtOper is a legal value number function.
// (Requires InitValueNumStoreStatics to have been run.)
@ -383,8 +400,8 @@ private:
GenTreeFlags GetFoldedArithOpResultHandleFlags(ValueNum vn);
public:
// Initializes any static variables of ValueNumStore.
static void InitValueNumStoreStatics();
// Validate that the new initializer for s_vnfOpAttribs matches the old code.
static void ValidateValueNumStoreStatics();
// Initialize an empty ValueNumStore.
ValueNumStore(Compiler* comp, CompAllocator allocator);

View file

@ -3,180 +3,180 @@
// Defines the functions understood by the value-numbering system.
// ValueNumFuncDef(<name of function>, <arity (1-4)>, <is-commutative (for arity = 2)>, <non-null (for gc functions)>,
// <is-shared-static>)
// <is-shared-static>, <encodes-extra-type-arg>)
// clang-format off
ValueNumFuncDef(MemOpaque, 1, false, false, false) // Args: 0: loop num
ValueNumFuncDef(MapSelect, 2, false, false, false) // Args: 0: map, 1: key.
ValueNumFuncDef(MapStore, 4, false, false, false) // Args: 0: map, 1: index (e. g. field handle), 2: value being stored, 3: loop num.
ValueNumFuncDef(MapPhysicalStore, 3, false, false, false) // Args: 0: map, 1: "physical selector": offset and size, 2: value being stored
ValueNumFuncDef(BitCast, 2, false, false, false) // Args: 0: VN of the arg, 1: VN of the target type
ValueNumFuncDef(ZeroObj, 1, false, false, false) // Args: 0: VN of the class handle.
ValueNumFuncDef(PhiDef, 3, false, false, false) // Args: 0: local var # (or -1 for memory), 1: SSA #, 2: VN of definition.
ValueNumFuncDef(PhiMemoryDef, 2, false, false, false) // Args: 0: VN for basic block pointer, 1: VN of definition
ValueNumFuncDef(Phi, 2, false, false, false) // A phi function. Only occurs as arg of PhiDef or PhiMemoryDef. Arguments are SSA numbers of var being defined.
ValueNumFuncDef(MemOpaque, 1, false, false, false, false) // Args: 0: loop num
ValueNumFuncDef(MapSelect, 2, false, false, false, false) // Args: 0: map, 1: key.
ValueNumFuncDef(MapStore, 4, false, false, false, false) // Args: 0: map, 1: index (e. g. field handle), 2: value being stored, 3: loop num.
ValueNumFuncDef(MapPhysicalStore, 3, false, false, false, false) // Args: 0: map, 1: "physical selector": offset and size, 2: value being stored
ValueNumFuncDef(BitCast, 2, false, false, false, false) // Args: 0: VN of the arg, 1: VN of the target type
ValueNumFuncDef(ZeroObj, 1, false, false, false, false) // Args: 0: VN of the class handle.
ValueNumFuncDef(PhiDef, 3, false, false, false, false) // Args: 0: local var # (or -1 for memory), 1: SSA #, 2: VN of definition.
ValueNumFuncDef(PhiMemoryDef, 2, false, false, false, false) // Args: 0: VN for basic block pointer, 1: VN of definition
ValueNumFuncDef(Phi, 2, false, false, false, false) // A phi function. Only occurs as arg of PhiDef or PhiMemoryDef. Arguments are SSA numbers of var being defined.
ValueNumFuncDef(PtrToLoc, 2, false, true, false) // Pointer (byref) to a local variable. Args: VN's of: 0: local's number, 1: offset.
ValueNumFuncDef(PtrToArrElem, 4, false, false, false) // Pointer (byref) to an array element. Args: 0: array elem type eq class var_types value, VN's of: 1: array, 2: index, 3: offset.
ValueNumFuncDef(PtrToStatic, 3, false, true, false) // Pointer (byref) to a static variable (or possibly a field thereof, if the static variable is a struct).
// Args: 0: (VN of) the box's address if the static is "boxed",
// 1: (VN of) the field sequence,
// 2: (VN of) offset for the constituent struct fields
ValueNumFuncDef(PtrToLoc, 2, false, true, false, false) // Pointer (byref) to a local variable. Args: VN's of: 0: local's number, 1: offset.
ValueNumFuncDef(PtrToArrElem, 4, false, false, false, false) // Pointer (byref) to an array element. Args: 0: array elem type eq class var_types value, VN's of: 1: array, 2: index, 3: offset.
ValueNumFuncDef(PtrToStatic, 3, false, true, false, false) // Pointer (byref) to a static variable (or possibly a field thereof, if the static variable is a struct).
// Args: 0: (VN of) the box's address if the static is "boxed",
// 1: (VN of) the field sequence,
// 2: (VN of) offset for the constituent struct fields
ValueNumFuncDef(MDArrLength, 2, false, false, false) // MD array len, Args: 0: array, 1: dimension
ValueNumFuncDef(MDArrLowerBound, 2, false, false, false) // MD array lower bound, Args: 0: array, 1: dimension
ValueNumFuncDef(MDArrLength, 2, false, false, false, false) // MD array len, Args: 0: array, 1: dimension
ValueNumFuncDef(MDArrLowerBound, 2, false, false, false, false) // MD array lower bound, Args: 0: array, 1: dimension
ValueNumFuncDef(InitVal, 1, false, false, false) // An input arg, or init val of a local Args: 0: a constant VN.
ValueNumFuncDef(InitVal, 1, false, false, false, false) // An input arg, or init val of a local Args: 0: a constant VN.
ValueNumFuncDef(Cast, 2, false, false, false) // VNF_Cast: Cast Operation changes the representations size and unsigned-ness.
// Args: 0: Source for the cast operation.
// 1: Constant integer representing the operation .
// Use VNForCastOper() to construct.
ValueNumFuncDef(CastOvf, 2, false, false, false) // Same as a VNF_Cast but also can throw an overflow exception.
ValueNumFuncDef(Cast, 2, false, false, false, false) // VNF_Cast: Cast Operation changes the representations size and unsigned-ness.
// Args: 0: Source for the cast operation.
// 1: Constant integer representing the operation .
// Use VNForCastOper() to construct.
ValueNumFuncDef(CastOvf, 2, false, false, false, false) // Same as a VNF_Cast but also can throw an overflow exception.
ValueNumFuncDef(CastClass, 2, false, false, false) // Args: 0: Handle of class being cast to, 1: object being cast.
ValueNumFuncDef(IsInstanceOf, 2, false, false, false) // Args: 0: Handle of class being queried, 1: object being queried.
ValueNumFuncDef(ReadyToRunCastClass, 2, false, false, false) // Args: 0: Helper stub address, 1: object being cast.
ValueNumFuncDef(ReadyToRunIsInstanceOf, 2, false, false, false) // Args: 0: Helper stub address, 1: object being queried.
ValueNumFuncDef(TypeHandleToRuntimeType, 1, false, false, false) // Args: 0: TypeHandle to translate
ValueNumFuncDef(TypeHandleToRuntimeTypeHandle, 1, false, false, false) // Args: 0: TypeHandle to translate
ValueNumFuncDef(CastClass, 2, false, false, false, false) // Args: 0: Handle of class being cast to, 1: object being cast.
ValueNumFuncDef(IsInstanceOf, 2, false, false, false, false) // Args: 0: Handle of class being queried, 1: object being queried.
ValueNumFuncDef(ReadyToRunCastClass, 2, false, false, false, false) // Args: 0: Helper stub address, 1: object being cast.
ValueNumFuncDef(ReadyToRunIsInstanceOf, 2, false, false, false, false) // Args: 0: Helper stub address, 1: object being queried.
ValueNumFuncDef(TypeHandleToRuntimeType, 1, false, false, false, false) // Args: 0: TypeHandle to translate
ValueNumFuncDef(TypeHandleToRuntimeTypeHandle, 1, false, false, false, false) // Args: 0: TypeHandle to translate
ValueNumFuncDef(LdElemA, 3, false, false, false) // Args: 0: array value; 1: index value; 2: type handle of element.
ValueNumFuncDef(LdElemA, 3, false, false, false, false) // Args: 0: array value; 1: index value; 2: type handle of element.
ValueNumFuncDef(ByrefExposedLoad, 3, false, false, false) // Args: 0: type handle/id, 1: pointer value; 2: ByrefExposed heap value
ValueNumFuncDef(ByrefExposedLoad, 3, false, false, false, false) // Args: 0: type handle/id, 1: pointer value; 2: ByrefExposed heap value
ValueNumFuncDef(GetRefanyVal, 2, false, false, false) // Args: 0: type handle; 1: typedref value. Returns the value (asserting that the type is right).
ValueNumFuncDef(GetRefanyVal, 2, false, false, false, false) // Args: 0: type handle; 1: typedref value. Returns the value (asserting that the type is right).
ValueNumFuncDef(GetClassFromMethodParam, 1, false, true, false) // Args: 0: method generic argument.
ValueNumFuncDef(GetSyncFromClassHandle, 1, false, true, false) // Args: 0: class handle.
ValueNumFuncDef(LoopCloneChoiceAddr, 0, false, true, false)
ValueNumFuncDef(GetClassFromMethodParam, 1, false, true, false, false) // Args: 0: method generic argument.
ValueNumFuncDef(GetSyncFromClassHandle, 1, false, true, false, false) // Args: 0: class handle.
ValueNumFuncDef(LoopCloneChoiceAddr, 0, false, true, false, false)
// How we represent values of expressions with exceptional side effects:
ValueNumFuncDef(ValWithExc, 2, false, false, false) // Args: 0: value number from normal execution; 1: VN for set of possible exceptions.
ValueNumFuncDef(ExcSetCons, 2, false, false, false) // Args: 0: exception; 1: exception set (including EmptyExcSet). Invariant: "car"s are always in ascending order.
ValueNumFuncDef(ValWithExc, 2, false, false, false, false) // Args: 0: value number from normal execution; 1: VN for set of possible exceptions.
ValueNumFuncDef(ExcSetCons, 2, false, false, false, false) // Args: 0: exception; 1: exception set (including EmptyExcSet). Invariant: "car"s are always in ascending order.
// Various functions that are used to indicate that an exceptions may occur
// Curremtly when the execution is always thrown, the value VNForVoid() is used as Arg0 by OverflowExc and DivideByZeroExc
//
ValueNumFuncDef(NullPtrExc, 1, false, false, false) // Null pointer exception check. Args: 0: address value, throws when it is null
ValueNumFuncDef(ArithmeticExc, 2, false, false, false) // Arithmetic exception check, ckfinite and integer division overflow, Args: 0: expression value,
ValueNumFuncDef(OverflowExc, 1, false, false, false) // Integer overflow check. used for checked add,sub and mul Args: 0: expression value, throws when it overflows
ValueNumFuncDef(ConvOverflowExc, 2, false, false, false) // Cast conversion overflow check. Args: 0: input value; 1: var_types of the target type
ValueNumFuncDef(NullPtrExc, 1, false, false, false, false) // Null pointer exception check. Args: 0: address value, throws when it is null
ValueNumFuncDef(ArithmeticExc, 2, false, false, false, false) // Arithmetic exception check, ckfinite and integer division overflow, Args: 0: expression value,
ValueNumFuncDef(OverflowExc, 1, false, false, false, false) // Integer overflow check. used for checked add,sub and mul Args: 0: expression value, throws when it overflows
ValueNumFuncDef(ConvOverflowExc, 2, false, false, false, false) // Cast conversion overflow check. Args: 0: input value; 1: var_types of the target type
// - (shifted left one bit; low bit encode whether source is unsigned.)
ValueNumFuncDef(DivideByZeroExc, 1, false, false, false) // Division by zero check. Args: 0: divisor value, throws when it is zero
ValueNumFuncDef(IndexOutOfRangeExc, 2, false, false, false) // Array bounds check, Args: 0: array length; 1: index value, throws when the bounds check fails.
ValueNumFuncDef(InvalidCastExc, 2, false, false, false) // CastClass check, Args: 0: ref value being cast; 1: handle of type being cast to, throws when the cast fails.
ValueNumFuncDef(NewArrOverflowExc, 1, false, false, false) // Raises Integer overflow when Arg 0 is negative
ValueNumFuncDef(HelperMultipleExc, 0, false, false, false) // Represents one or more different exceptions that could be thrown by a Jit Helper method
ValueNumFuncDef(DivideByZeroExc, 1, false, false, false, false) // Division by zero check. Args: 0: divisor value, throws when it is zero
ValueNumFuncDef(IndexOutOfRangeExc, 2, false, false, false, false) // Array bounds check, Args: 0: array length; 1: index value, throws when the bounds check fails.
ValueNumFuncDef(InvalidCastExc, 2, false, false, false, false) // CastClass check, Args: 0: ref value being cast; 1: handle of type being cast to, throws when the cast fails.
ValueNumFuncDef(NewArrOverflowExc, 1, false, false, false, false) // Raises Integer overflow when Arg 0 is negative
ValueNumFuncDef(HelperMultipleExc, 0, false, false, false, false) // Represents one or more different exceptions that could be thrown by a Jit Helper method
ValueNumFuncDef(FltRound, 1, false, false, false)
ValueNumFuncDef(DblRound, 1, false, false, false)
ValueNumFuncDef(FltRound, 1, false, false, false, false)
ValueNumFuncDef(DblRound, 1, false, false, false, false)
ValueNumFuncDef(Abs, 1, false, false, false)
ValueNumFuncDef(Acos, 1, false, false, false)
ValueNumFuncDef(Acosh, 1, false, false, false)
ValueNumFuncDef(Asin, 1, false, false, false)
ValueNumFuncDef(Asinh, 1, false, false, false)
ValueNumFuncDef(Atan, 1, false, false, false)
ValueNumFuncDef(Atanh, 1, false, false, false)
ValueNumFuncDef(Atan2, 2, false, false, false)
ValueNumFuncDef(Cbrt, 1, false, false, false)
ValueNumFuncDef(Ceiling, 1, false, false, false)
ValueNumFuncDef(Cos, 1, false, false, false)
ValueNumFuncDef(Cosh, 1, false, false, false)
ValueNumFuncDef(Exp, 1, false, false, false)
ValueNumFuncDef(Floor, 1, false, false, false)
ValueNumFuncDef(FMod, 2, false, false, false)
ValueNumFuncDef(ILogB, 1, false, false, false)
ValueNumFuncDef(Log, 1, false, false, false)
ValueNumFuncDef(Log2, 1, false, false, false)
ValueNumFuncDef(Log10, 1, false, false, false)
ValueNumFuncDef(Max, 2, false, false, false)
ValueNumFuncDef(Min, 2, false, false, false)
ValueNumFuncDef(Pow, 2, false, false, false)
ValueNumFuncDef(RoundDouble, 1, false, false, false)
ValueNumFuncDef(RoundInt32, 1, false, false, false)
ValueNumFuncDef(RoundSingle, 1, false, false, false)
ValueNumFuncDef(Sin, 1, false, false, false)
ValueNumFuncDef(Sinh, 1, false, false, false)
ValueNumFuncDef(Sqrt, 1, false, false, false)
ValueNumFuncDef(Tan, 1, false, false, false)
ValueNumFuncDef(Tanh, 1, false, false, false)
ValueNumFuncDef(Truncate, 1, false, false, false)
ValueNumFuncDef(Abs, 1, false, false, false, false)
ValueNumFuncDef(Acos, 1, false, false, false, false)
ValueNumFuncDef(Acosh, 1, false, false, false, false)
ValueNumFuncDef(Asin, 1, false, false, false, false)
ValueNumFuncDef(Asinh, 1, false, false, false, false)
ValueNumFuncDef(Atan, 1, false, false, false, false)
ValueNumFuncDef(Atanh, 1, false, false, false, false)
ValueNumFuncDef(Atan2, 2, false, false, false, false)
ValueNumFuncDef(Cbrt, 1, false, false, false, false)
ValueNumFuncDef(Ceiling, 1, false, false, false, false)
ValueNumFuncDef(Cos, 1, false, false, false, false)
ValueNumFuncDef(Cosh, 1, false, false, false, false)
ValueNumFuncDef(Exp, 1, false, false, false, false)
ValueNumFuncDef(Floor, 1, false, false, false, false)
ValueNumFuncDef(FMod, 2, false, false, false, false)
ValueNumFuncDef(ILogB, 1, false, false, false, false)
ValueNumFuncDef(Log, 1, false, false, false, false)
ValueNumFuncDef(Log2, 1, false, false, false, false)
ValueNumFuncDef(Log10, 1, false, false, false, false)
ValueNumFuncDef(Max, 2, false, false, false, false)
ValueNumFuncDef(Min, 2, false, false, false, false)
ValueNumFuncDef(Pow, 2, false, false, false, false)
ValueNumFuncDef(RoundDouble, 1, false, false, false, false)
ValueNumFuncDef(RoundInt32, 1, false, false, false, false)
ValueNumFuncDef(RoundSingle, 1, false, false, false, false)
ValueNumFuncDef(Sin, 1, false, false, false, false)
ValueNumFuncDef(Sinh, 1, false, false, false, false)
ValueNumFuncDef(Sqrt, 1, false, false, false, false)
ValueNumFuncDef(Tan, 1, false, false, false, false)
ValueNumFuncDef(Tanh, 1, false, false, false, false)
ValueNumFuncDef(Truncate, 1, false, false, false, false)
ValueNumFuncDef(ManagedThreadId, 0, false, false, false)
ValueNumFuncDef(ManagedThreadId, 0, false, false, false, false)
ValueNumFuncDef(ObjGetType, 1, false, true, false)
ValueNumFuncDef(GetgenericsGcstaticBase, 1, false, true, true)
ValueNumFuncDef(GetgenericsNongcstaticBase, 1, false, true, true)
ValueNumFuncDef(GetsharedGcstaticBase, 2, false, true, true)
ValueNumFuncDef(GetsharedNongcstaticBase, 2, false, true, true)
ValueNumFuncDef(GetsharedGcstaticBaseNoctor, 1, false, true, true)
ValueNumFuncDef(GetsharedNongcstaticBaseNoctor, 1, false, true, true)
ValueNumFuncDef(ReadyToRunStaticBaseGC, 1, false, true, true)
ValueNumFuncDef(ReadyToRunStaticBaseNonGC, 1, false, true, true)
ValueNumFuncDef(ReadyToRunStaticBaseThread, 1, false, true, true)
ValueNumFuncDef(ReadyToRunStaticBaseThreadNonGC, 1, false, true, true)
ValueNumFuncDef(ReadyToRunGenericStaticBase, 2, false, true, true)
ValueNumFuncDef(GetsharedGcstaticBaseDynamicclass, 2, false, true, true)
ValueNumFuncDef(GetsharedNongcstaticBaseDynamicclass, 2, false, true, true)
ValueNumFuncDef(GetgenericsGcthreadstaticBase, 1, false, true, true)
ValueNumFuncDef(GetgenericsNongcthreadstaticBase, 1, false, true, true)
ValueNumFuncDef(GetsharedGcthreadstaticBase, 2, false, true, true)
ValueNumFuncDef(GetsharedNongcthreadstaticBase, 2, false, true, true)
ValueNumFuncDef(GetsharedGcthreadstaticBaseNoctor, 2, false, true, true)
ValueNumFuncDef(GetsharedGcthreadstaticBaseNoctorOptimized, 1, false, true, true)
ValueNumFuncDef(GetsharedNongcthreadstaticBaseNoctor, 2, false, true, true)
ValueNumFuncDef(GetsharedNongcthreadstaticBaseNoctorOptimized, 1, false, true, true)
ValueNumFuncDef(GetsharedGcthreadstaticBaseDynamicclass, 2, false, true, true)
ValueNumFuncDef(GetsharedNongcthreadstaticBaseDynamicclass, 2, false, true, true)
ValueNumFuncDef(ObjGetType, 1, false, true, false, false)
ValueNumFuncDef(GetgenericsGcstaticBase, 1, false, true, true, false)
ValueNumFuncDef(GetgenericsNongcstaticBase, 1, false, true, true, false)
ValueNumFuncDef(GetsharedGcstaticBase, 2, false, true, true, false)
ValueNumFuncDef(GetsharedNongcstaticBase, 2, false, true, true, false)
ValueNumFuncDef(GetsharedGcstaticBaseNoctor, 1, false, true, true, false)
ValueNumFuncDef(GetsharedNongcstaticBaseNoctor, 1, false, true, true, false)
ValueNumFuncDef(ReadyToRunStaticBaseGC, 1, false, true, true, false)
ValueNumFuncDef(ReadyToRunStaticBaseNonGC, 1, false, true, true, false)
ValueNumFuncDef(ReadyToRunStaticBaseThread, 1, false, true, true, false)
ValueNumFuncDef(ReadyToRunStaticBaseThreadNonGC, 1, false, true, true, false)
ValueNumFuncDef(ReadyToRunGenericStaticBase, 2, false, true, true, false)
ValueNumFuncDef(GetsharedGcstaticBaseDynamicclass, 2, false, true, true, false)
ValueNumFuncDef(GetsharedNongcstaticBaseDynamicclass, 2, false, true, true, false)
ValueNumFuncDef(GetgenericsGcthreadstaticBase, 1, false, true, true, false)
ValueNumFuncDef(GetgenericsNongcthreadstaticBase, 1, false, true, true, false)
ValueNumFuncDef(GetsharedGcthreadstaticBase, 2, false, true, true, false)
ValueNumFuncDef(GetsharedNongcthreadstaticBase, 2, false, true, true, false)
ValueNumFuncDef(GetsharedGcthreadstaticBaseNoctor, 2, false, true, true, false)
ValueNumFuncDef(GetsharedGcthreadstaticBaseNoctorOptimized, 1, false, true, true, false)
ValueNumFuncDef(GetsharedNongcthreadstaticBaseNoctor, 2, false, true, true, false)
ValueNumFuncDef(GetsharedNongcthreadstaticBaseNoctorOptimized, 1, false, true, true, false)
ValueNumFuncDef(GetsharedGcthreadstaticBaseDynamicclass, 2, false, true, true, false)
ValueNumFuncDef(GetsharedNongcthreadstaticBaseDynamicclass, 2, false, true, true, false)
ValueNumFuncDef(ClassinitSharedDynamicclass, 2, false, false, false)
ValueNumFuncDef(RuntimeHandleMethod, 2, false, true, false)
ValueNumFuncDef(RuntimeHandleClass, 2, false, true, false)
ValueNumFuncDef(ReadyToRunGenericHandle, 2, false, true, false)
ValueNumFuncDef(ClassinitSharedDynamicclass, 2, false, false, false, false)
ValueNumFuncDef(RuntimeHandleMethod, 2, false, true, false, false)
ValueNumFuncDef(RuntimeHandleClass, 2, false, true, false, false)
ValueNumFuncDef(ReadyToRunGenericHandle, 2, false, true, false, false)
ValueNumFuncDef(GetStaticAddrTLS, 1, false, true, false)
ValueNumFuncDef(GetStaticAddrTLS, 1, false, true, false, false)
ValueNumFuncDef(JitNew, 2, false, true, false)
ValueNumFuncDef(JitNewArr, 3, false, true, false)
ValueNumFuncDef(JitNewMdArr, 4, false, true, false)
ValueNumFuncDef(JitReadyToRunNew, 2, false, true, false)
ValueNumFuncDef(JitReadyToRunNewArr, 3, false, true, false)
ValueNumFuncDef(Box, 3, false, false, false)
ValueNumFuncDef(BoxNullable, 3, false, false, false)
ValueNumFuncDef(JitNew, 2, false, true, false, false)
ValueNumFuncDef(JitNewArr, 3, false, true, false, false)
ValueNumFuncDef(JitNewMdArr, 4, false, true, false, false)
ValueNumFuncDef(JitReadyToRunNew, 2, false, true, false, false)
ValueNumFuncDef(JitReadyToRunNewArr, 3, false, true, false, false)
ValueNumFuncDef(Box, 3, false, false, false, false)
ValueNumFuncDef(BoxNullable, 3, false, false, false, false)
ValueNumFuncDef(LazyStrCns, 2, false, true, false) // Lazy-initialized string literal (helper)
ValueNumFuncDef(InvariantLoad, 1, false, false, false) // Args: 0: (VN of) the address.
ValueNumFuncDef(InvariantNonNullLoad, 1, false, true, false) // Args: 0: (VN of) the address.
ValueNumFuncDef(Unbox, 2, false, true, false)
ValueNumFuncDef(LazyStrCns, 2, false, true, false, false) // Lazy-initialized string literal (helper)
ValueNumFuncDef(InvariantLoad, 1, false, false, false, false) // Args: 0: (VN of) the address.
ValueNumFuncDef(InvariantNonNullLoad, 1, false, true, false, false) // Args: 0: (VN of) the address.
ValueNumFuncDef(Unbox, 2, false, true, false, false)
ValueNumFuncDef(LT_UN, 2, false, false, false) // unsigned or unordered comparisons
ValueNumFuncDef(LE_UN, 2, false, false, false)
ValueNumFuncDef(GE_UN, 2, false, false, false)
ValueNumFuncDef(GT_UN, 2, false, false, false)
ValueNumFuncDef(LT_UN, 2, false, false, false, false) // unsigned or unordered comparisons
ValueNumFuncDef(LE_UN, 2, false, false, false, false)
ValueNumFuncDef(GE_UN, 2, false, false, false, false)
ValueNumFuncDef(GT_UN, 2, false, false, false, false)
ValueNumFuncDef(ADD_OVF, 2, true, false, false) // overflow checking operations
ValueNumFuncDef(SUB_OVF, 2, false, false, false)
ValueNumFuncDef(MUL_OVF, 2, true, false, false)
ValueNumFuncDef(ADD_OVF, 2, true, false, false, false) // overflow checking operations
ValueNumFuncDef(SUB_OVF, 2, false, false, false, false)
ValueNumFuncDef(MUL_OVF, 2, true, false, false, false)
ValueNumFuncDef(ADD_UN_OVF, 2, true, false, false) // unsigned overflow checking operations
ValueNumFuncDef(SUB_UN_OVF, 2, false, false, false)
ValueNumFuncDef(MUL_UN_OVF, 2, true, false, false)
ValueNumFuncDef(ADD_UN_OVF, 2, true, false, false, false) // unsigned overflow checking operations
ValueNumFuncDef(SUB_UN_OVF, 2, false, false, false, false)
ValueNumFuncDef(MUL_UN_OVF, 2, true, false, false, false)
#ifdef FEATURE_SIMD
ValueNumFuncDef(SimdType, 2, false, false, false) // A value number function to compose a SIMD type
ValueNumFuncDef(SimdType, 2, false, false, false, false) // A value number function to compose a SIMD type
#endif
#if defined(TARGET_XARCH)
#define HARDWARE_INTRINSIC(isa, name, size, argCount, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, flag) \
ValueNumFuncDef(HWI_##isa##_##name, argCount, false, false, false) // All of the HARDWARE_INTRINSICS for x86/x64
#define HARDWARE_INTRINSIC(isa, name, size, argCount, extra, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, flag) \
ValueNumFuncDef(HWI_##isa##_##name, argCount, ((flag) & HW_Flag_Commutative) >> 0, false, false, extra) // All of the HARDWARE_INTRINSICS for x86/x64
#include "hwintrinsiclistxarch.h"
#define VNF_HWI_FIRST VNF_HWI_Vector128_Abs
#elif defined (TARGET_ARM64)
#define HARDWARE_INTRINSIC(isa, name, size, argCount, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, flag) \
ValueNumFuncDef(HWI_##isa##_##name, argCount, false, false, false) // All of the HARDWARE_INTRINSICS for arm64
#define HARDWARE_INTRINSIC(isa, name, size, argCount, extra, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, category, flag) \
ValueNumFuncDef(HWI_##isa##_##name, argCount, ((flag) & HW_Flag_Commutative) >> 0, false, false, extra) // All of the HARDWARE_INTRINSICS for arm64
#include "hwintrinsiclistarm64.h"
#define VNF_HWI_FIRST VNF_HWI_Vector64_Abs