From 832a7498bf7aff89a70800c5f02517866f93dc1f Mon Sep 17 00:00:00 2001 From: Peter Kukol Date: Thu, 15 Sep 2016 23:59:05 -0600 Subject: [PATCH] Option for reporting GenTree operator bashing stats (#7152) * Add option (off by default) to report GenTree operator bashing stats. --- src/jit/compiler.cpp | 16 +-- src/jit/compiler.hpp | 28 +++- src/jit/decomposelongs.cpp | 4 +- src/jit/gentree.cpp | 252 ++++++++++++++++++++++++----------- src/jit/gentree.h | 28 +++- src/jit/gtlist.h | 320 ++++++++++++++++++++++----------------------- src/jit/jit.h | 1 + src/jit/liveness.cpp | 4 +- src/jit/lower.cpp | 2 +- src/jit/lowerxarch.cpp | 2 +- src/jit/rationalize.cpp | 2 +- 11 files changed, 391 insertions(+), 268 deletions(-) diff --git a/src/jit/compiler.cpp b/src/jit/compiler.cpp index c47707c..f3699bd 100644 --- a/src/jit/compiler.cpp +++ b/src/jit/compiler.cpp @@ -1186,6 +1186,10 @@ void Compiler::compShutdown() } #endif +#if NODEBASH_STATS + GenTree::ReportOperBashing(jitstdout); +#endif + // Where should we write our statistics output? FILE* fout = jitstdout; @@ -1519,6 +1523,7 @@ void Compiler::compDisplayStaticSizes(FILE* fout) fprintf(fout, "Size of GenTreeLclFld = %3u\n", sizeof(GenTreeLclFld)); fprintf(fout, "Size of GenTreeRegVar = %3u\n", sizeof(GenTreeRegVar)); fprintf(fout, "Size of GenTreeCast = %3u\n", sizeof(GenTreeCast)); + fprintf(fout, "Size of GenTreeJumpCC = %3u\n", sizeof(GenTreeJumpCC)); fprintf(fout, "Size of GenTreeBox = %3u\n", sizeof(GenTreeBox)); fprintf(fout, "Size of GenTreeField = %3u\n", sizeof(GenTreeField)); fprintf(fout, "Size of GenTreeArgList = %3u\n", sizeof(GenTreeArgList)); @@ -1545,12 +1550,10 @@ void Compiler::compDisplayStaticSizes(FILE* fout) fprintf(fout, "Size of GenTreePutArgStk = %3u\n", sizeof(GenTreePutArgStk)); fprintf(fout, "Size of GenTreeCopyOrReload = %3u\n", sizeof(GenTreeCopyOrReload)); fprintf(fout, "Size of GenTreeAllocObj = %3u\n", sizeof(GenTreeAllocObj)); - fprintf(fout, "Size of GenTreeBlkOp = %3u\n", sizeof(GenTreeBlkOp)); - fprintf(fout, "Size of GenTreeCpBlk = %3u\n", sizeof(GenTreeCpBlk)); - fprintf(fout, "Size of GenTreeCpObj = %3u\n", sizeof(GenTreeCpObj)); + fprintf(fout, "Size of GenTreeBlk = %3u\n", sizeof(GenTreeBlk)); + fprintf(fout, "Size of GenTreeDynBlk = %3u\n", sizeof(GenTreeDynBlk)); fprintf(fout, "Size of GenTreeArrIndex = %3u\n", sizeof(GenTreeArrIndex)); fprintf(fout, "Size of GenTreeArrOffs = %3u\n", sizeof(GenTreeArrOffs)); - fprintf(fout, "Size of GenTreeInitBlk = %3u\n", sizeof(GenTreeInitBlk)); #ifdef FEATURE_SIMD fprintf(fout, "Size of GenTreeSIMD = %3u\n", sizeof(GenTreeSIMD)); #endif @@ -10151,11 +10154,6 @@ void cNodeIR(Compiler* comp, GenTree* tree) } break; - case GT_STORE_CLS_VAR: - - chars += printf(" ???"); - break; - case GT_LEA: GenTreeAddrMode* lea = tree->AsAddrMode(); diff --git a/src/jit/compiler.hpp b/src/jit/compiler.hpp index eb8eb19..cc428e9 100644 --- a/src/jit/compiler.hpp +++ b/src/jit/compiler.hpp @@ -804,7 +804,7 @@ void* GenTree::operator new(size_t sz, Compiler* comp, genTreeOps oper) #if SMALL_TREE_NODES size_t size = GenTree::s_gtNodeSizes[oper]; #else - size_t size = TREE_NODE_SZ_LARGE; + size_t size = TREE_NODE_SZ_LARGE; #endif #if MEASURE_NODE_SIZE @@ -1285,11 +1285,11 @@ inline void GenTree::SetOper(genTreeOps oper, ValueNumberUpdate vnUpdate) assert(GenTree::s_gtNodeSizes[gtOper] == TREE_NODE_SZ_SMALL || GenTree::s_gtNodeSizes[gtOper] == TREE_NODE_SZ_LARGE); - assert(GenTree::s_gtNodeSizes[oper] == TREE_NODE_SZ_SMALL || GenTree::s_gtNodeSizes[oper] == TREE_NODE_SZ_LARGE); + assert(GenTree::s_gtNodeSizes[oper] == TREE_NODE_SZ_SMALL || GenTree::s_gtNodeSizes[oper] == TREE_NODE_SZ_LARGE); assert(GenTree::s_gtNodeSizes[oper] == TREE_NODE_SZ_SMALL || (gtDebugFlags & GTF_DEBUG_NODE_LARGE)); - gtOper = oper; + SetOperRaw(oper); #ifdef DEBUG // Maintain the invariant that unary operators always have NULL gtOp2. @@ -1327,6 +1327,9 @@ inline void GenTree::CopyFrom(const GenTree* src, Compiler* comp) assert((gtDebugFlags & GTF_DEBUG_NODE_LARGE) || GenTree::s_gtNodeSizes[src->gtOper] == TREE_NODE_SZ_SMALL); GenTreePtr prev = gtPrev; GenTreePtr next = gtNext; + + RecordOperBashing(OperGet(), src->OperGet()); // nop unless NODEBASH_STATS is enabled + // The VTable pointer is copied intentionally here memcpy((void*)this, (void*)src, src->GetNodeSize()); this->gtPrev = prev; @@ -1373,7 +1376,7 @@ inline void GenTree::InitNodeSize() inline void GenTree::SetOper(genTreeOps oper, ValueNumberUpdate vnUpdate) { - gtOper = oper; + SetOperRaw(oper); if (vnUpdate == CLEAR_VN) { @@ -1384,6 +1387,7 @@ inline void GenTree::SetOper(genTreeOps oper, ValueNumberUpdate vnUpdate) inline void GenTree::CopyFrom(GenTreePtr src) { + RecordOperBashing(OperGet(), src->OperGet()); // nop unless NODEBASH_STATS is enabled *this = *src; #ifdef DEBUG gtSeqNum = 0; @@ -1405,6 +1409,16 @@ inline GenTreePtr Compiler::gtNewCastNodeL(var_types typ, GenTreePtr op1, var_ty #endif // SMALL_TREE_NODES /*****************************************************************************/ +/*****************************************************************************/ + +inline void GenTree::SetOperRaw(genTreeOps oper) +{ + // Please do not do anything here other than assign to gtOper (debug-only + // code is OK, but should be kept to a minimum). + RecordOperBashing(OperGet(), oper); // nop unless NODEBASH_STATS is enabled + gtOper = oper; +} + inline void GenTree::SetOperResetFlags(genTreeOps oper) { SetOper(oper); @@ -1446,7 +1460,7 @@ inline void GenTree::ChangeOper(genTreeOps oper, ValueNumberUpdate vnUpdate) inline void GenTree::ChangeOperUnchecked(genTreeOps oper) { - gtOper = oper; // Trust the caller and don't use SetOper() + SetOperRaw(oper); // Trust the caller and don't use SetOper() gtFlags &= GTF_COMMON_MASK; } @@ -1579,7 +1593,7 @@ inline unsigned Compiler::lvaGrabTemp(bool shortLifetime DEBUGARG(const char* re #if 0 // TODO-Cleanup: Enable this and test. -#ifdef DEBUG +#ifdef DEBUG // Fill the old table with junks. So to detect the un-intended use. memset(lvaTable, fDefaultFill2.val_DontUse_(CLRConfig::INTERNAL_JitDefaultFill, 0xFF), lvaCount * sizeof(*lvaTable)); #endif @@ -1655,7 +1669,7 @@ inline unsigned Compiler::lvaGrabTemps(unsigned cnt DEBUGARG(const char* reason) } #if 0 -#ifdef DEBUG +#ifdef DEBUG // TODO-Cleanup: Enable this and test. // Fill the old table with junks. So to detect the un-intended use. memset(lvaTable, fDefaultFill2.val_DontUse_(CLRConfig::INTERNAL_JitDefaultFill, 0xFF), lvaCount * sizeof(*lvaTable)); diff --git a/src/jit/decomposelongs.cpp b/src/jit/decomposelongs.cpp index 4b5f367..00745c0 100644 --- a/src/jit/decomposelongs.cpp +++ b/src/jit/decomposelongs.cpp @@ -953,7 +953,7 @@ GenTree* DecomposeLongs::DecomposeShift(LIR::Use& use) call = m_compiler->fgMorphArgs(callNode); Range().InsertAfter(tree, LIR::SeqTree(m_compiler, call)); - + Range().Remove(tree); use.ReplaceWith(m_compiler, call); return call; @@ -1003,7 +1003,7 @@ GenTree* DecomposeLongs::DecomposeMul(LIR::Use& use) // Get rid of the hi ops. We don't need them. tree->gtOp.gtOp1 = loOp1; tree->gtOp.gtOp2 = loOp2; - tree->gtOper = GT_MUL_LONG; + tree->SetOperRaw(GT_MUL_LONG); return StoreNodeToVar(use); } diff --git a/src/jit/gentree.cpp b/src/jit/gentree.cpp index 3bea668..9dbcdcc 100644 --- a/src/jit/gentree.cpp +++ b/src/jit/gentree.cpp @@ -21,7 +21,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX /*****************************************************************************/ const unsigned short GenTree::gtOperKindTable[] = { -#define GTNODE(en, sn, cm, ok) ok + GTK_COMMUTE *cm, +#define GTNODE(en, sn, st, cm, ok) ok + GTK_COMMUTE *cm, #include "gtlist.h" }; @@ -209,7 +209,7 @@ static void printIndent(IndentStack* indentStack) } static const char* nodeNames[] = { -#define GTNODE(en, sn, cm, ok) sn, +#define GTNODE(en, sn, st, cm, ok) sn, #include "gtlist.h" }; @@ -220,8 +220,12 @@ const char* GenTree::NodeName(genTreeOps op) return nodeNames[op]; } +#endif + +#if defined(DEBUG) || NODEBASH_STATS + static const char* opNames[] = { -#define GTNODE(en, sn, cm, ok) #en, +#define GTNODE(en, sn, st, cm, ok) #en, #include "gtlist.h" }; @@ -247,6 +251,16 @@ const char* GenTree::OpName(genTreeOps op) /* static */ unsigned char GenTree::s_gtNodeSizes[GT_COUNT + 1]; +#if NODEBASH_STATS + +unsigned char GenTree::s_gtTrueSizes[GT_COUNT+1] +{ + #define GTNODE(en, sn, st, cm, ok) sizeof(st), + #include "gtlist.h" +}; + +#endif//NODEBASH_STATS + /* static */ void GenTree::InitNodeSize() { @@ -264,12 +278,13 @@ void GenTree::InitNodeSize() // Now set all of the appropriate entries to 'large' CLANG_FORMAT_COMMENT_ANCHOR; + // clang-format off #if defined(FEATURE_HFA) || defined(FEATURE_UNIX_AMD64_STRUCT_PASSING) // On ARM32, ARM64 and System V for struct returning // there is code that does GT_ASG-tree.CopyObj call. // CopyObj is a large node and the GT_ASG is small, which triggers an exception. - GenTree::s_gtNodeSizes[GT_ASG] = TREE_NODE_SZ_LARGE; - GenTree::s_gtNodeSizes[GT_RETURN] = TREE_NODE_SZ_LARGE; + GenTree::s_gtNodeSizes[GT_ASG] = TREE_NODE_SZ_LARGE; + GenTree::s_gtNodeSizes[GT_RETURN] = TREE_NODE_SZ_LARGE; #endif // defined(FEATURE_HFA) || defined(FEATURE_UNIX_AMD64_STRUCT_PASSING) GenTree::s_gtNodeSizes[GT_CALL] = TREE_NODE_SZ_LARGE; @@ -281,29 +296,29 @@ void GenTree::InitNodeSize() #ifdef FEATURE_SIMD GenTree::s_gtNodeSizes[GT_SIMD_CHK] = TREE_NODE_SZ_LARGE; #endif // FEATURE_SIMD - GenTree::s_gtNodeSizes[GT_ARR_ELEM] = TREE_NODE_SZ_LARGE; - GenTree::s_gtNodeSizes[GT_ARR_INDEX] = TREE_NODE_SZ_LARGE; - GenTree::s_gtNodeSizes[GT_ARR_OFFSET] = TREE_NODE_SZ_LARGE; - GenTree::s_gtNodeSizes[GT_RET_EXPR] = TREE_NODE_SZ_LARGE; - GenTree::s_gtNodeSizes[GT_OBJ] = TREE_NODE_SZ_LARGE; - GenTree::s_gtNodeSizes[GT_FIELD] = TREE_NODE_SZ_LARGE; - GenTree::s_gtNodeSizes[GT_STMT] = TREE_NODE_SZ_LARGE; - GenTree::s_gtNodeSizes[GT_CMPXCHG] = TREE_NODE_SZ_LARGE; - GenTree::s_gtNodeSizes[GT_QMARK] = TREE_NODE_SZ_LARGE; - GenTree::s_gtNodeSizes[GT_LEA] = TREE_NODE_SZ_LARGE; - GenTree::s_gtNodeSizes[GT_STORE_OBJ] = TREE_NODE_SZ_LARGE; - GenTree::s_gtNodeSizes[GT_DYN_BLK] = TREE_NODE_SZ_LARGE; - GenTree::s_gtNodeSizes[GT_STORE_DYN_BLK] = TREE_NODE_SZ_LARGE; - GenTree::s_gtNodeSizes[GT_INTRINSIC] = TREE_NODE_SZ_LARGE; - GenTree::s_gtNodeSizes[GT_ALLOCOBJ] = TREE_NODE_SZ_LARGE; + GenTree::s_gtNodeSizes[GT_ARR_ELEM] = TREE_NODE_SZ_LARGE; + GenTree::s_gtNodeSizes[GT_ARR_INDEX] = TREE_NODE_SZ_LARGE; + GenTree::s_gtNodeSizes[GT_ARR_OFFSET] = TREE_NODE_SZ_LARGE; + GenTree::s_gtNodeSizes[GT_RET_EXPR] = TREE_NODE_SZ_LARGE; + GenTree::s_gtNodeSizes[GT_OBJ] = TREE_NODE_SZ_LARGE; + GenTree::s_gtNodeSizes[GT_FIELD] = TREE_NODE_SZ_LARGE; + GenTree::s_gtNodeSizes[GT_STMT] = TREE_NODE_SZ_LARGE; + GenTree::s_gtNodeSizes[GT_CMPXCHG] = TREE_NODE_SZ_LARGE; + GenTree::s_gtNodeSizes[GT_QMARK] = TREE_NODE_SZ_LARGE; + GenTree::s_gtNodeSizes[GT_LEA] = TREE_NODE_SZ_LARGE; + GenTree::s_gtNodeSizes[GT_STORE_OBJ] = TREE_NODE_SZ_LARGE; + GenTree::s_gtNodeSizes[GT_DYN_BLK] = TREE_NODE_SZ_LARGE; + GenTree::s_gtNodeSizes[GT_STORE_DYN_BLK] = TREE_NODE_SZ_LARGE; + GenTree::s_gtNodeSizes[GT_INTRINSIC] = TREE_NODE_SZ_LARGE; + GenTree::s_gtNodeSizes[GT_ALLOCOBJ] = TREE_NODE_SZ_LARGE; #if USE_HELPERS_FOR_INT_DIV - GenTree::s_gtNodeSizes[GT_DIV] = TREE_NODE_SZ_LARGE; - GenTree::s_gtNodeSizes[GT_UDIV] = TREE_NODE_SZ_LARGE; - GenTree::s_gtNodeSizes[GT_MOD] = TREE_NODE_SZ_LARGE; - GenTree::s_gtNodeSizes[GT_UMOD] = TREE_NODE_SZ_LARGE; + GenTree::s_gtNodeSizes[GT_DIV] = TREE_NODE_SZ_LARGE; + GenTree::s_gtNodeSizes[GT_UDIV] = TREE_NODE_SZ_LARGE; + GenTree::s_gtNodeSizes[GT_MOD] = TREE_NODE_SZ_LARGE; + GenTree::s_gtNodeSizes[GT_UMOD] = TREE_NODE_SZ_LARGE; #endif #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING - GenTree::s_gtNodeSizes[GT_PUTARG_STK] = TREE_NODE_SZ_LARGE; + GenTree::s_gtNodeSizes[GT_PUTARG_STK] = TREE_NODE_SZ_LARGE; #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING assert(GenTree::s_gtNodeSizes[GT_RETURN] == GenTree::s_gtNodeSizes[GT_ASG]); @@ -313,60 +328,62 @@ void GenTree::InitNodeSize() assert(sizeof(GenTreeLclFld) <= GenTree::s_gtNodeSizes[GT_LCL_FLD]); assert(sizeof(GenTreeLclVar) <= GenTree::s_gtNodeSizes[GT_LCL_VAR]); - static_assert_no_msg(sizeof(GenTree) <= TREE_NODE_SZ_SMALL); - static_assert_no_msg(sizeof(GenTreeUnOp) <= TREE_NODE_SZ_SMALL); - static_assert_no_msg(sizeof(GenTreeOp) <= TREE_NODE_SZ_SMALL); - static_assert_no_msg(sizeof(GenTreeVal) <= TREE_NODE_SZ_SMALL); + static_assert_no_msg(sizeof(GenTree) <= TREE_NODE_SZ_SMALL); + static_assert_no_msg(sizeof(GenTreeUnOp) <= TREE_NODE_SZ_SMALL); + static_assert_no_msg(sizeof(GenTreeOp) <= TREE_NODE_SZ_SMALL); + static_assert_no_msg(sizeof(GenTreeVal) <= TREE_NODE_SZ_SMALL); static_assert_no_msg(sizeof(GenTreeIntConCommon) <= TREE_NODE_SZ_SMALL); - static_assert_no_msg(sizeof(GenTreePhysReg) <= TREE_NODE_SZ_SMALL); + static_assert_no_msg(sizeof(GenTreePhysReg) <= TREE_NODE_SZ_SMALL); #ifndef LEGACY_BACKEND - static_assert_no_msg(sizeof(GenTreeJumpTable) <= TREE_NODE_SZ_SMALL); + static_assert_no_msg(sizeof(GenTreeJumpTable) <= TREE_NODE_SZ_SMALL); #endif // !LEGACY_BACKEND - static_assert_no_msg(sizeof(GenTreeIntCon) <= TREE_NODE_SZ_SMALL); - static_assert_no_msg(sizeof(GenTreeLngCon) <= TREE_NODE_SZ_SMALL); - static_assert_no_msg(sizeof(GenTreeDblCon) <= TREE_NODE_SZ_SMALL); - static_assert_no_msg(sizeof(GenTreeStrCon) <= TREE_NODE_SZ_SMALL); + static_assert_no_msg(sizeof(GenTreeIntCon) <= TREE_NODE_SZ_SMALL); + static_assert_no_msg(sizeof(GenTreeLngCon) <= TREE_NODE_SZ_SMALL); + static_assert_no_msg(sizeof(GenTreeDblCon) <= TREE_NODE_SZ_SMALL); + static_assert_no_msg(sizeof(GenTreeStrCon) <= TREE_NODE_SZ_SMALL); static_assert_no_msg(sizeof(GenTreeLclVarCommon) <= TREE_NODE_SZ_SMALL); - static_assert_no_msg(sizeof(GenTreeLclVar) <= TREE_NODE_SZ_SMALL); - static_assert_no_msg(sizeof(GenTreeLclFld) <= TREE_NODE_SZ_SMALL); - static_assert_no_msg(sizeof(GenTreeRegVar) <= TREE_NODE_SZ_SMALL); - static_assert_no_msg(sizeof(GenTreeCast) <= TREE_NODE_SZ_LARGE); // *** large node - static_assert_no_msg(sizeof(GenTreeBox) <= TREE_NODE_SZ_LARGE); // *** large node - static_assert_no_msg(sizeof(GenTreeField) <= TREE_NODE_SZ_LARGE); // *** large node - static_assert_no_msg(sizeof(GenTreeArgList) <= TREE_NODE_SZ_SMALL); - static_assert_no_msg(sizeof(GenTreeColon) <= TREE_NODE_SZ_SMALL); - static_assert_no_msg(sizeof(GenTreeCall) <= TREE_NODE_SZ_LARGE); // *** large node - static_assert_no_msg(sizeof(GenTreeCmpXchg) <= TREE_NODE_SZ_LARGE); // *** large node - static_assert_no_msg(sizeof(GenTreeFptrVal) <= TREE_NODE_SZ_LARGE); // *** large node - static_assert_no_msg(sizeof(GenTreeQmark) <= TREE_NODE_SZ_LARGE); // *** large node - static_assert_no_msg(sizeof(GenTreeIntrinsic) <= TREE_NODE_SZ_LARGE); // *** large node - static_assert_no_msg(sizeof(GenTreeIndex) <= TREE_NODE_SZ_LARGE); // *** large node - static_assert_no_msg(sizeof(GenTreeArrLen) <= TREE_NODE_SZ_LARGE); // *** large node - static_assert_no_msg(sizeof(GenTreeBoundsChk) <= TREE_NODE_SZ_LARGE); // *** large node - static_assert_no_msg(sizeof(GenTreeArrElem) <= TREE_NODE_SZ_LARGE); // *** large node - static_assert_no_msg(sizeof(GenTreeArrIndex) <= TREE_NODE_SZ_LARGE); // *** large node - static_assert_no_msg(sizeof(GenTreeArrOffs) <= TREE_NODE_SZ_LARGE); // *** large node - static_assert_no_msg(sizeof(GenTreeIndir) <= TREE_NODE_SZ_SMALL); - static_assert_no_msg(sizeof(GenTreeStoreInd) <= TREE_NODE_SZ_SMALL); - static_assert_no_msg(sizeof(GenTreeAddrMode) <= TREE_NODE_SZ_SMALL); - static_assert_no_msg(sizeof(GenTreeObj) <= TREE_NODE_SZ_LARGE); // *** large node - static_assert_no_msg(sizeof(GenTreeBlk) <= TREE_NODE_SZ_SMALL); - static_assert_no_msg(sizeof(GenTreeRetExpr) <= TREE_NODE_SZ_LARGE); // *** large node - static_assert_no_msg(sizeof(GenTreeStmt) <= TREE_NODE_SZ_LARGE); // *** large node - static_assert_no_msg(sizeof(GenTreeClsVar) <= TREE_NODE_SZ_SMALL); - static_assert_no_msg(sizeof(GenTreeArgPlace) <= TREE_NODE_SZ_SMALL); - static_assert_no_msg(sizeof(GenTreeLabel) <= TREE_NODE_SZ_SMALL); - static_assert_no_msg(sizeof(GenTreePhiArg) <= TREE_NODE_SZ_SMALL); - static_assert_no_msg(sizeof(GenTreeAllocObj) <= TREE_NODE_SZ_LARGE); // *** large node + static_assert_no_msg(sizeof(GenTreeLclVar) <= TREE_NODE_SZ_SMALL); + static_assert_no_msg(sizeof(GenTreeLclFld) <= TREE_NODE_SZ_SMALL); + static_assert_no_msg(sizeof(GenTreeRegVar) <= TREE_NODE_SZ_SMALL); + static_assert_no_msg(sizeof(GenTreeJumpCC) <= TREE_NODE_SZ_SMALL); + static_assert_no_msg(sizeof(GenTreeCast) <= TREE_NODE_SZ_LARGE); // *** large node + static_assert_no_msg(sizeof(GenTreeBox) <= TREE_NODE_SZ_LARGE); // *** large node + static_assert_no_msg(sizeof(GenTreeField) <= TREE_NODE_SZ_LARGE); // *** large node + static_assert_no_msg(sizeof(GenTreeArgList) <= TREE_NODE_SZ_SMALL); + static_assert_no_msg(sizeof(GenTreeColon) <= TREE_NODE_SZ_SMALL); + static_assert_no_msg(sizeof(GenTreeCall) <= TREE_NODE_SZ_LARGE); // *** large node + static_assert_no_msg(sizeof(GenTreeCmpXchg) <= TREE_NODE_SZ_LARGE); // *** large node + static_assert_no_msg(sizeof(GenTreeFptrVal) <= TREE_NODE_SZ_LARGE); // *** large node + static_assert_no_msg(sizeof(GenTreeQmark) <= TREE_NODE_SZ_LARGE); // *** large node + static_assert_no_msg(sizeof(GenTreeIntrinsic) <= TREE_NODE_SZ_LARGE); // *** large node + static_assert_no_msg(sizeof(GenTreeIndex) <= TREE_NODE_SZ_LARGE); // *** large node + static_assert_no_msg(sizeof(GenTreeArrLen) <= TREE_NODE_SZ_LARGE); // *** large node + static_assert_no_msg(sizeof(GenTreeBoundsChk) <= TREE_NODE_SZ_LARGE); // *** large node + static_assert_no_msg(sizeof(GenTreeArrElem) <= TREE_NODE_SZ_LARGE); // *** large node + static_assert_no_msg(sizeof(GenTreeArrIndex) <= TREE_NODE_SZ_LARGE); // *** large node + static_assert_no_msg(sizeof(GenTreeArrOffs) <= TREE_NODE_SZ_LARGE); // *** large node + static_assert_no_msg(sizeof(GenTreeIndir) <= TREE_NODE_SZ_SMALL); + static_assert_no_msg(sizeof(GenTreeStoreInd) <= TREE_NODE_SZ_SMALL); + static_assert_no_msg(sizeof(GenTreeAddrMode) <= TREE_NODE_SZ_SMALL); + static_assert_no_msg(sizeof(GenTreeObj) <= TREE_NODE_SZ_LARGE); // *** large node + static_assert_no_msg(sizeof(GenTreeBlk) <= TREE_NODE_SZ_SMALL); + static_assert_no_msg(sizeof(GenTreeRetExpr) <= TREE_NODE_SZ_LARGE); // *** large node + static_assert_no_msg(sizeof(GenTreeStmt) <= TREE_NODE_SZ_LARGE); // *** large node + static_assert_no_msg(sizeof(GenTreeClsVar) <= TREE_NODE_SZ_SMALL); + static_assert_no_msg(sizeof(GenTreeArgPlace) <= TREE_NODE_SZ_SMALL); + static_assert_no_msg(sizeof(GenTreeLabel) <= TREE_NODE_SZ_SMALL); + static_assert_no_msg(sizeof(GenTreePhiArg) <= TREE_NODE_SZ_SMALL); + static_assert_no_msg(sizeof(GenTreeAllocObj) <= TREE_NODE_SZ_LARGE); // *** large node #ifndef FEATURE_UNIX_AMD64_STRUCT_PASSING - static_assert_no_msg(sizeof(GenTreePutArgStk) <= TREE_NODE_SZ_SMALL); + static_assert_no_msg(sizeof(GenTreePutArgStk) <= TREE_NODE_SZ_SMALL); #else // FEATURE_UNIX_AMD64_STRUCT_PASSING - static_assert_no_msg(sizeof(GenTreePutArgStk) <= TREE_NODE_SZ_LARGE); + static_assert_no_msg(sizeof(GenTreePutArgStk) <= TREE_NODE_SZ_LARGE); #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING #ifdef FEATURE_SIMD - static_assert_no_msg(sizeof(GenTreeSIMD) <= TREE_NODE_SZ_SMALL); + static_assert_no_msg(sizeof(GenTreeSIMD) <= TREE_NODE_SZ_SMALL); #endif // FEATURE_SIMD + // clang-format on } size_t GenTree::GetNodeSize() const @@ -393,6 +410,88 @@ bool GenTree::IsNodeProperlySized() const } #endif +/***************************************************************************** + * + * When 'NODEBASH_STATS' is enabled in "jit.h" we record all instances of + * an existing GenTree node having its operator changed. This can be useful + * for two (related) things - to see what is being bashed (and what isn't), + * and to verify that the existing choices for what nodes are marked 'large' + * are reasonable (to minimize "wasted" space). + * + * And yes, the hash function / logic is simplistic, but it is conflict-free + * and transparent for what we need. + */ + +#if NODEBASH_STATS + +#define BASH_HASH_SIZE 211 + +inline hashme(genTreeOps op1, genTreeOps op2) { return ((op1 * 104729) ^ (op2 * 56569)) % BASH_HASH_SIZE; } + +struct BashHashDsc +{ + unsigned __int32 bhFullHash; // the hash value (unique for all old->new pairs) + unsigned __int32 bhCount; // the same old->new bashings seen so far + unsigned __int8 bhOperOld; // original gtOper + unsigned __int8 bhOperNew; // new gtOper +}; + +static BashHashDsc BashHash[BASH_HASH_SIZE]; + +void GenTree::RecordOperBashing(genTreeOps operOld, genTreeOps operNew) +{ + unsigned hash = hashme(operOld, operNew); + BashHashDsc *desc = BashHash + hash; + + if (desc->bhFullHash != hash) + { + noway_assert(desc->bhCount == 0); // if this ever fires, need fix the hash fn + desc->bhFullHash = hash; + } + + desc->bhCount += 1; + desc->bhOperOld = operOld; + desc->bhOperNew = operNew; +} + +void GenTree::ReportOperBashing(FILE *f) +{ + unsigned total = 0; + + fflush(f); + + fprintf(f, "\n"); + fprintf(f, "Bashed gtOper stats:\n"); + fprintf(f, "\n"); + fprintf(f, " Old operator New operator #bytes old->new Count\n"); + fprintf(f, " ---------------------------------------------------------------\n"); + + for (unsigned h = 0; h < BASH_HASH_SIZE; h++) + { + unsigned count = BashHash[h].bhCount; + if (count == 0) + continue; + + unsigned opOld = BashHash[h].bhOperOld; + unsigned opNew = BashHash[h].bhOperNew; + + fprintf(f, " GT_%-13s -> GT_%-13s [size: %3u->%3u] %c %7u\n", OpName((genTreeOps)opOld), + OpName((genTreeOps)opNew), + s_gtTrueSizes[opOld], + s_gtTrueSizes[opNew], + (s_gtTrueSizes[opOld] < s_gtTrueSizes[opNew]) ? 'X' : ' ', + count); + total += count; + } + fprintf(f, "\n"); + fprintf(f, "Total bashings: %u\n", total); + fprintf(f, "\n"); + + fflush(f); +} + +#endif// NODEBASH_STATS + #else // SMALL_TREE_NODES #ifdef DEBUG @@ -7175,7 +7274,7 @@ void GenTreeIntCon::FixupInitBlkValue(var_types asgType) } } -// +// //------------------------------------------------------------------------ // gtBlockOpInit: Initializes a BlkOp GenTree // @@ -7184,7 +7283,7 @@ void GenTreeIntCon::FixupInitBlkValue(var_types asgType) // dst - the target (destination) we want to either initialize or copy to. // src - the init value for InitBlk or the source struct for CpBlk/CpObj. // isVolatile - specifies whether this node is a volatile memory operation. -// +// // Assumptions: // 'result' is an assignment that is newly constructed. // If 'dst' is TYP_STRUCT, then it must be a block node or lclVar. @@ -8494,7 +8593,8 @@ bool GenTree::gtRequestSetFlags() /*****************************************************************************/ void GenTree::CopyTo(class Compiler* comp, const GenTree& gt) { - gtOper = gt.gtOper; + SetOperRaw(gt.OperGet()); + gtType = gt.gtType; gtAssertionNum = gt.gtAssertionNum; @@ -12620,18 +12720,18 @@ GenTreePtr Compiler::gtFoldExprConst(GenTreePtr tree) // Don't fold conversions of +inf/-inf to integral value on all platforms // as the value returned by JIT helper doesn't match with the C compiler's cast result. - // We want the behavior to be same with or without folding. + // We want the behavior to be same with or without folding. return tree; } - if (d1 <= -1.0 && varTypeIsUnsigned(tree->CastToType())) + if (d1 <= -1.0 && varTypeIsUnsigned(tree->CastToType())) { // Don't fold conversions of these cases becasue the result is unspecified per ECMA spec // and the native math doing the fold doesn't match the run-time computation on all platforms. // We want the behavior to be same with or without folding. return tree; } - + switch (tree->CastToType()) { case TYP_BYTE: @@ -14181,7 +14281,7 @@ void Compiler::gtExtractSideEffList(GenTreePtr expr, // effect of this instruction, change it into a GT_LOCKADD node (the add only) if (oper == GT_XADD) { - expr->gtOper = GT_LOCKADD; + expr->SetOperRaw(GT_LOCKADD); expr->gtType = TYP_VOID; } diff --git a/src/jit/gentree.h b/src/jit/gentree.h index 5716cae..e0e6a1a 100644 --- a/src/jit/gentree.h +++ b/src/jit/gentree.h @@ -68,7 +68,7 @@ enum SpecialCodeKind DECLARE_TYPED_ENUM(genTreeOps, BYTE) { -#define GTNODE(en, sn, cm, ok) GT_##en, +#define GTNODE(en, sn, st, cm, ok) GT_##en, #include "gtlist.h" GT_COUNT, @@ -1394,8 +1394,7 @@ public: static bool OperIsStore(genTreeOps gtOper) { return (gtOper == GT_STOREIND || gtOper == GT_STORE_LCL_VAR || gtOper == GT_STORE_LCL_FLD || - gtOper == GT_STORE_CLS_VAR || gtOper == GT_STORE_BLK || gtOper == GT_STORE_OBJ || - gtOper == GT_STORE_DYN_BLK); + gtOper == GT_STORE_BLK || gtOper == GT_STORE_OBJ || gtOper == GT_STORE_DYN_BLK); } static bool OperIsAtomicOp(genTreeOps gtOper) @@ -1541,6 +1540,10 @@ public: public: #if SMALL_TREE_NODES static unsigned char s_gtNodeSizes[]; +#if NODEBASH_STATS + static unsigned char s_gtTrueSizes[]; + static const char* s_gtNodeRawNames[]; +#endif #endif static void InitNodeSize(); @@ -1559,16 +1562,16 @@ public: static bool Compare(GenTreePtr op1, GenTreePtr op2, bool swapOK = false); -//--------------------------------------------------------------------- -#ifdef DEBUG //--------------------------------------------------------------------- +#if defined(DEBUG) static const char* NodeName(genTreeOps op); +#endif +#if defined(DEBUG) || NODEBASH_STATS static const char* OpName(genTreeOps op); - -//--------------------------------------------------------------------- #endif + //--------------------------------------------------------------------- bool IsNothingNode() const; @@ -1588,6 +1591,7 @@ public: // set gtOper and only keep GTF_COMMON_MASK flags void ChangeOper(genTreeOps oper, ValueNumberUpdate vnUpdate = CLEAR_VN); void ChangeOperUnchecked(genTreeOps oper); + void SetOperRaw(genTreeOps oper); void ChangeType(var_types newType) { @@ -1602,6 +1606,16 @@ public: } } +#if SMALL_TREE_NODES +#if NODEBASH_STATS + static void RecordOperBashing(genTreeOps operOld, genTreeOps operNew); + static void ReportOperBashing(FILE *fp); +#else + static void RecordOperBashing(genTreeOps operOld, genTreeOps operNew) { /* do nothing */ } + static void ReportOperBashing(FILE *fp) { /* do nothing */ } +#endif +#endif + bool IsLocal() const { return OperIsLocal(OperGet()); diff --git a/src/jit/gtlist.h b/src/jit/gtlist.h index da8246d..bc2f8f2 100644 --- a/src/jit/gtlist.h +++ b/src/jit/gtlist.h @@ -9,259 +9,255 @@ #endif /*****************************************************************************/ // -// Node enum -// , "Node name" -// ,commutative -// ,operKind +// Node enum +// ,"Node name" +// ,GenTree struct flavor +// ,commutative +// ,operKind -GTNODE(NONE , "" ,0,GTK_SPECIAL) +GTNODE(NONE , "" ,char ,0,GTK_SPECIAL) //----------------------------------------------------------------------------- // Leaf nodes (i.e. these nodes have no sub-operands): //----------------------------------------------------------------------------- -GTNODE(LCL_VAR , "lclVar" ,0,GTK_LEAF|GTK_LOCAL) // local variable -GTNODE(LCL_FLD , "lclFld" ,0,GTK_LEAF|GTK_LOCAL) // field in a non-primitive variable -GTNODE(LCL_VAR_ADDR , "&lclVar" ,0,GTK_LEAF) // address of local variable -GTNODE(LCL_FLD_ADDR , "&lclFld" ,0,GTK_LEAF) // address of field in a non-primitive variable -GTNODE(STORE_LCL_VAR , "st.lclVar" ,0,GTK_UNOP|GTK_LOCAL|GTK_NOVALUE) // store to local variable -GTNODE(STORE_LCL_FLD , "st.lclFld" ,0,GTK_UNOP|GTK_LOCAL|GTK_NOVALUE) // store to field in a non-primitive variable -GTNODE(CATCH_ARG , "catchArg" ,0,GTK_LEAF) // Exception object in a catch block -GTNODE(LABEL , "codeLabel" ,0,GTK_LEAF) // Jump-target -GTNODE(FTN_ADDR , "ftnAddr" ,0,GTK_LEAF) // Address of a function -GTNODE(RET_EXPR , "retExpr" ,0,GTK_LEAF) // Place holder for the return expression from an inline candidate +GTNODE(LCL_VAR , "lclVar" ,GenTreeLclVar ,0,GTK_LEAF|GTK_LOCAL) // local variable +GTNODE(LCL_FLD , "lclFld" ,GenTreeLclFld ,0,GTK_LEAF|GTK_LOCAL) // field in a non-primitive variable +GTNODE(LCL_VAR_ADDR , "&lclVar" ,GenTreeLclVar ,0,GTK_LEAF) // address of local variable +GTNODE(LCL_FLD_ADDR , "&lclFld" ,GenTreeLclFld ,0,GTK_LEAF) // address of field in a non-primitive variable +GTNODE(STORE_LCL_VAR , "st.lclVar" ,GenTreeLclVar ,0,GTK_UNOP|GTK_LOCAL|GTK_NOVALUE) // store to local variable +GTNODE(STORE_LCL_FLD , "st.lclFld" ,GenTreeLclFld ,0,GTK_UNOP|GTK_LOCAL|GTK_NOVALUE) // store to field in a non-primitive variable +GTNODE(CATCH_ARG , "catchArg" ,GenTree ,0,GTK_LEAF) // Exception object in a catch block +GTNODE(LABEL , "codeLabel" ,GenTreeLabel ,0,GTK_LEAF) // Jump-target +GTNODE(FTN_ADDR , "ftnAddr" ,GenTreeFptrVal ,0,GTK_LEAF) // Address of a function +GTNODE(RET_EXPR , "retExpr" ,GenTreeRetExpr ,0,GTK_LEAF) // Place holder for the return expression from an inline candidate //----------------------------------------------------------------------------- // Constant nodes: //----------------------------------------------------------------------------- -GTNODE(CNS_INT , "const" ,0,GTK_LEAF|GTK_CONST) -GTNODE(CNS_LNG , "lconst" ,0,GTK_LEAF|GTK_CONST) -GTNODE(CNS_DBL , "dconst" ,0,GTK_LEAF|GTK_CONST) -GTNODE(CNS_STR , "sconst" ,0,GTK_LEAF|GTK_CONST) +GTNODE(CNS_INT , "const" ,GenTreeIntCon ,0,GTK_LEAF|GTK_CONST) +GTNODE(CNS_LNG , "lconst" ,GenTreeLngCon ,0,GTK_LEAF|GTK_CONST) +GTNODE(CNS_DBL , "dconst" ,GenTreeDblCon ,0,GTK_LEAF|GTK_CONST) +GTNODE(CNS_STR , "sconst" ,GenTreeStrCon ,0,GTK_LEAF|GTK_CONST) //----------------------------------------------------------------------------- // Unary operators (1 operand): //----------------------------------------------------------------------------- -GTNODE(NOT , "~" ,0,GTK_UNOP) -GTNODE(NOP , "nop" ,0,GTK_UNOP) -GTNODE(NEG , "unary -" ,0,GTK_UNOP) -GTNODE(COPY , "copy" ,0,GTK_UNOP) // Copies a variable from its current location to a register that satisfies - // code generation constraints. The child is the actual lclVar node. -GTNODE(RELOAD , "reload" ,0,GTK_UNOP) -GTNODE(CHS , "flipsign" ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR) // GT_CHS is actually unary -- op2 is ignored. - // Changing to unary presently causes problems, though -- take a little work to fix. - -GTNODE(ARR_LENGTH , "arrLen" ,0,GTK_UNOP|GTK_EXOP) // array-length - -GTNODE(INTRINSIC , "intrinsic" ,0,GTK_BINOP|GTK_EXOP) // intrinsics - -GTNODE(LOCKADD , "lockAdd" ,0,GTK_BINOP|GTK_NOVALUE) -GTNODE(XADD , "XAdd" ,0,GTK_BINOP) -GTNODE(XCHG , "Xchg" ,0,GTK_BINOP) -GTNODE(CMPXCHG , "cmpxchg" ,0,GTK_SPECIAL) -GTNODE(MEMORYBARRIER , "memoryBarrier" ,0,GTK_LEAF|GTK_NOVALUE) - -GTNODE(CAST , "cast" ,0,GTK_UNOP|GTK_EXOP) // conversion to another type -GTNODE(CKFINITE , "ckfinite" ,0,GTK_UNOP) // Check for NaN -GTNODE(LCLHEAP , "lclHeap" ,0,GTK_UNOP) // alloca() -GTNODE(JMP , "jump" ,0,GTK_LEAF|GTK_NOVALUE) // Jump to another function - - -GTNODE(ADDR , "addr" ,0,GTK_UNOP) // address of -GTNODE(IND , "indir" ,0,GTK_UNOP) // load indirection -GTNODE(STOREIND , "storeIndir" ,0,GTK_BINOP|GTK_NOVALUE) // store indirection - - // TODO-Cleanup: GT_ARR_BOUNDS_CHECK should be made a GTK_BINOP now that it has only two child nodes -GTNODE(ARR_BOUNDS_CHECK , "arrBndsChk" ,0,GTK_SPECIAL|GTK_NOVALUE) // array bounds check -GTNODE(OBJ , "obj" ,0,GTK_UNOP|GTK_EXOP) // Object that MAY have gc pointers, and thus includes the relevant gc layout info. -GTNODE(STORE_OBJ , "storeObj" ,0,GTK_BINOP|GTK_EXOP|GTK_NOVALUE) // Object that MAY have gc pointers, and thus includes the relevant gc layout info. -GTNODE(BLK , "blk" ,0,GTK_UNOP) // Block/object with no gc pointers, and with a known size (e.g. a struct with no gc fields) -GTNODE(STORE_BLK , "storeBlk" ,0,GTK_BINOP|GTK_NOVALUE) // Block/object with no gc pointers, and with a known size (e.g. a struct with no gc fields) -GTNODE(DYN_BLK , "DynBlk" ,0,GTK_SPECIAL) // Dynamically sized block object -GTNODE(STORE_DYN_BLK , "storeDynBlk" ,0,GTK_SPECIAL|GTK_NOVALUE) // Dynamically sized block object -GTNODE(BOX , "box" ,0,GTK_UNOP|GTK_EXOP|GTK_NOTLIR) +GTNODE(NOT , "~" ,GenTreeOp ,0,GTK_UNOP) +GTNODE(NOP , "nop" ,GenTree ,0,GTK_UNOP) +GTNODE(NEG , "unary -" ,GenTreeOp ,0,GTK_UNOP) +GTNODE(COPY , "copy" ,GenTreeCopyOrReload,0,GTK_UNOP) // Copies a variable from its current location to a register that satisfies + // code generation constraints. The child is the actual lclVar node. +GTNODE(RELOAD , "reload" ,GenTreeCopyOrReload,0,GTK_UNOP) +GTNODE(CHS , "flipsign" ,GenTreeOp ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR) // GT_CHS is actually unary -- op2 is ignored. + // Changing to unary presently causes problems, though -- take a little work to fix. + +GTNODE(ARR_LENGTH , "arrLen" ,GenTreeArrLen ,0,GTK_UNOP|GTK_EXOP) // array-length + +GTNODE(INTRINSIC , "intrinsic" ,GenTreeIntrinsic ,0,GTK_BINOP|GTK_EXOP) // intrinsics + +GTNODE(LOCKADD , "lockAdd" ,GenTreeOp ,0,GTK_BINOP|GTK_NOVALUE) +GTNODE(XADD , "XAdd" ,GenTreeOp ,0,GTK_BINOP) +GTNODE(XCHG , "Xchg" ,GenTreeOp ,0,GTK_BINOP) +GTNODE(CMPXCHG , "cmpxchg" ,GenTreeCmpXchg ,0,GTK_SPECIAL) +GTNODE(MEMORYBARRIER , "memoryBarrier",GenTree ,0,GTK_LEAF|GTK_NOVALUE) + +GTNODE(CAST , "cast" ,GenTreeCast ,0,GTK_UNOP|GTK_EXOP) // conversion to another type +GTNODE(CKFINITE , "ckfinite" ,GenTreeOp ,0,GTK_UNOP) // Check for NaN +GTNODE(LCLHEAP , "lclHeap" ,GenTreeOp ,0,GTK_UNOP) // alloca() +GTNODE(JMP , "jump" ,GenTreeVal ,0,GTK_LEAF|GTK_NOVALUE) // Jump to another function + +GTNODE(ADDR , "addr" ,GenTreeOp ,0,GTK_UNOP) // address of +GTNODE(IND , "indir" ,GenTreeOp ,0,GTK_UNOP) // load indirection +GTNODE(STOREIND , "storeIndir" ,GenTreeStoreInd ,0,GTK_BINOP|GTK_NOVALUE) // store indirection + + // TODO-Cleanup: GT_ARR_BOUNDS_CHECK should be made a GTK_BINOP now that it has only two child nodes +GTNODE(ARR_BOUNDS_CHECK , "arrBndsChk" ,GenTreeBoundsChk ,0,GTK_SPECIAL|GTK_NOVALUE)// array bounds check +GTNODE(OBJ , "obj" ,GenTreeObj ,0,GTK_UNOP|GTK_EXOP) // Object that MAY have gc pointers, and thus includes the relevant gc layout info. +GTNODE(STORE_OBJ , "storeObj" ,GenTreeBlk ,0,GTK_BINOP|GTK_EXOP|GTK_NOVALUE) // Object that MAY have gc pointers, and thus includes the relevant gc layout info. +GTNODE(BLK , "blk" ,GenTreeBlk ,0,GTK_UNOP) // Block/object with no gc pointers, and with a known size (e.g. a struct with no gc fields) +GTNODE(STORE_BLK , "storeBlk" ,GenTreeBlk ,0,GTK_BINOP|GTK_NOVALUE) // Block/object with no gc pointers, and with a known size (e.g. a struct with no gc fields) +GTNODE(DYN_BLK , "DynBlk" ,GenTreeBlk ,0,GTK_SPECIAL) // Dynamically sized block object +GTNODE(STORE_DYN_BLK , "storeDynBlk" ,GenTreeBlk ,0,GTK_SPECIAL|GTK_NOVALUE)// Dynamically sized block object +GTNODE(BOX , "box" ,GenTreeBox ,0,GTK_UNOP|GTK_EXOP|GTK_NOTLIR) #ifdef FEATURE_SIMD -GTNODE(SIMD_CHK , "simdChk" ,0,GTK_SPECIAL|GTK_NOVALUE) // Compare whether an index is less than the given SIMD vector length, and call CORINFO_HELP_RNGCHKFAIL if not. - // TODO-CQ: In future may want to add a field that specifies different exceptions but we'll - // need VM assistance for that. - // TODO-CQ: It would actually be very nice to make this an unconditional throw, and expose the control flow that - // does the compare, so that it can be more easily optimized. But that involves generating qmarks at import time... +GTNODE(SIMD_CHK , "simdChk" ,GenTreeBoundsChk ,0,GTK_SPECIAL|GTK_NOVALUE)// Compare whether an index is less than the given SIMD vector length, and call CORINFO_HELP_RNGCHKFAIL if not. + // TODO-CQ: In future may want to add a field that specifies different exceptions but we'll + // need VM assistance for that. + // TODO-CQ: It would actually be very nice to make this an unconditional throw, and expose the control flow that + // does the compare, so that it can be more easily optimized. But that involves generating qmarks at import time... #endif // FEATURE_SIMD -GTNODE(ALLOCOBJ , "allocObj" ,0,GTK_UNOP|GTK_EXOP) // object allocator +GTNODE(ALLOCOBJ , "allocObj" ,GenTreeAllocObj ,0,GTK_UNOP|GTK_EXOP) // object allocator //----------------------------------------------------------------------------- // Binary operators (2 operands): //----------------------------------------------------------------------------- -GTNODE(ADD , "+" ,1,GTK_BINOP) -GTNODE(SUB , "-" ,0,GTK_BINOP) -GTNODE(MUL , "*" ,1,GTK_BINOP) -GTNODE(DIV , "/" ,0,GTK_BINOP) -GTNODE(MOD , "%" ,0,GTK_BINOP) +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(UDIV , "un-/" ,0,GTK_BINOP) -GTNODE(UMOD , "un-%" ,0,GTK_BINOP) +GTNODE(UDIV , "un-/" ,GenTreeOp ,0,GTK_BINOP) +GTNODE(UMOD , "un-%" ,GenTreeOp ,0,GTK_BINOP) -GTNODE(OR , "|" ,1,GTK_BINOP|GTK_LOGOP) -GTNODE(XOR , "^" ,1,GTK_BINOP|GTK_LOGOP) -GTNODE(AND , "&" ,1,GTK_BINOP|GTK_LOGOP) +GTNODE(OR , "|" ,GenTreeOp ,1,GTK_BINOP|GTK_LOGOP) +GTNODE(XOR , "^" ,GenTreeOp ,1,GTK_BINOP|GTK_LOGOP) +GTNODE(AND , "&" ,GenTreeOp ,1,GTK_BINOP|GTK_LOGOP) -GTNODE(LSH , "<<" ,0,GTK_BINOP) -GTNODE(RSH , ">>" ,0,GTK_BINOP) -GTNODE(RSZ , ">>>" ,0,GTK_BINOP) -GTNODE(ROL , "rol" ,0,GTK_BINOP) -GTNODE(ROR , "ror" ,0,GTK_BINOP) -GTNODE(MULHI , "mulhi" ,1,GTK_BINOP) // returns high bits (top N bits of the 2N bit result of an NxN multiply) - // GT_MULHI is used in division by a constant (fgMorphDivByConst). 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(LSH , "<<" ,GenTreeOp ,0,GTK_BINOP) +GTNODE(RSH , ">>" ,GenTreeOp ,0,GTK_BINOP) +GTNODE(RSZ , ">>>" ,GenTreeOp ,0,GTK_BINOP) +GTNODE(ROL , "rol" ,GenTreeOp ,0,GTK_BINOP) +GTNODE(ROR , "ror" ,GenTreeOp ,0,GTK_BINOP) +GTNODE(MULHI , "mulhi" ,GenTreeOp ,1,GTK_BINOP) // returns high bits (top N bits of the 2N bit result of an NxN multiply) + // GT_MULHI is used in division by a constant (fgMorphDivByConst). 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(ASG , "=" ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR) -GTNODE(ASG_ADD , "+=" ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR) -GTNODE(ASG_SUB , "-=" ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR) -GTNODE(ASG_MUL , "*=" ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR) -GTNODE(ASG_DIV , "/=" ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR) -GTNODE(ASG_MOD , "%=" ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR) +GTNODE(ASG , "=" ,GenTreeOp ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR) +GTNODE(ASG_ADD , "+=" ,GenTreeOp ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR) +GTNODE(ASG_SUB , "-=" ,GenTreeOp ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR) +GTNODE(ASG_MUL , "*=" ,GenTreeOp ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR) +GTNODE(ASG_DIV , "/=" ,GenTreeOp ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR) +GTNODE(ASG_MOD , "%=" ,GenTreeOp ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR) -GTNODE(ASG_UDIV , "/=" ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR) -GTNODE(ASG_UMOD , "%=" ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR) +GTNODE(ASG_UDIV , "/=" ,GenTreeOp ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR) +GTNODE(ASG_UMOD , "%=" ,GenTreeOp ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR) -GTNODE(ASG_OR , "|=" ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR) -GTNODE(ASG_XOR , "^=" ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR) -GTNODE(ASG_AND , "&=" ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR) -GTNODE(ASG_LSH , "<<=" ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR) -GTNODE(ASG_RSH , ">>=" ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR) -GTNODE(ASG_RSZ , ">>>=" ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR) +GTNODE(ASG_OR , "|=" ,GenTreeOp ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR) +GTNODE(ASG_XOR , "^=" ,GenTreeOp ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR) +GTNODE(ASG_AND , "&=" ,GenTreeOp ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR) +GTNODE(ASG_LSH , "<<=" ,GenTreeOp ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR) +GTNODE(ASG_RSH , ">>=" ,GenTreeOp ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR) +GTNODE(ASG_RSZ , ">>>=" ,GenTreeOp ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR) -GTNODE(EQ , "==" ,0,GTK_BINOP|GTK_RELOP) -GTNODE(NE , "!=" ,0,GTK_BINOP|GTK_RELOP) -GTNODE(LT , "<" ,0,GTK_BINOP|GTK_RELOP) -GTNODE(LE , "<=" ,0,GTK_BINOP|GTK_RELOP) -GTNODE(GE , ">=" ,0,GTK_BINOP|GTK_RELOP) -GTNODE(GT , ">" ,0,GTK_BINOP|GTK_RELOP) +GTNODE(EQ , "==" ,GenTreeOp ,0,GTK_BINOP|GTK_RELOP) +GTNODE(NE , "!=" ,GenTreeOp ,0,GTK_BINOP|GTK_RELOP) +GTNODE(LT , "<" ,GenTreeOp ,0,GTK_BINOP|GTK_RELOP) +GTNODE(LE , "<=" ,GenTreeOp ,0,GTK_BINOP|GTK_RELOP) +GTNODE(GE , ">=" ,GenTreeOp ,0,GTK_BINOP|GTK_RELOP) +GTNODE(GT , ">" ,GenTreeOp ,0,GTK_BINOP|GTK_RELOP) -GTNODE(COMMA , "comma" ,0,GTK_BINOP|GTK_NOTLIR) +GTNODE(COMMA , "comma" ,GenTreeOp ,0,GTK_BINOP|GTK_NOTLIR) -GTNODE(QMARK , "qmark" ,0,GTK_BINOP|GTK_EXOP|GTK_NOTLIR) -GTNODE(COLON , "colon" ,0,GTK_BINOP|GTK_NOTLIR) +GTNODE(QMARK , "qmark" ,GenTreeQmark ,0,GTK_BINOP|GTK_EXOP|GTK_NOTLIR) +GTNODE(COLON , "colon" ,GenTreeColon ,0,GTK_BINOP|GTK_NOTLIR) -GTNODE(INDEX , "[]" ,0,GTK_BINOP|GTK_EXOP|GTK_NOTLIR) // SZ-array-element +GTNODE(INDEX , "[]" ,GenTreeIndex ,0,GTK_BINOP|GTK_EXOP|GTK_NOTLIR) // SZ-array-element -GTNODE(MKREFANY , "mkrefany" ,0,GTK_BINOP) +GTNODE(MKREFANY , "mkrefany" ,GenTreeOp ,0,GTK_BINOP) -GTNODE(LEA , "lea" ,0,GTK_BINOP|GTK_EXOP) +GTNODE(LEA , "lea" ,GenTreeAddrMode ,0,GTK_BINOP|GTK_EXOP) #if !defined(LEGACY_BACKEND) && !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 , "gt_long" ,0,GTK_BINOP) +GTNODE(LONG , "gt_long" ,GenTreeOp ,0,GTK_BINOP) // The following are nodes representing x86 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 , "+Lo" ,1,GTK_BINOP) -GTNODE(ADD_HI , "+Hi" ,1,GTK_BINOP) -GTNODE(SUB_LO , "-Lo" ,0,GTK_BINOP) -GTNODE(SUB_HI , "-Hi" ,0,GTK_BINOP) -GTNODE(DIV_HI , "/Hi" ,0,GTK_BINOP) -GTNODE(MOD_HI , "%Hi" ,0,GTK_BINOP) -GTNODE(MUL_LONG , "*long" ,1,GTK_BINOP) // A mul that returns the 2N bit result of an NxN multiply. This op - // is used for x86 multiplies that take two ints and return a long - // result. All other multiplies with long results are morphed into - // helper calls. It is similar to GT_MULHI, the difference being that - // GT_MULHI drops the lo part of the result, whereas GT_MUL_LONG keeps - // both parts of the result. +GTNODE(ADD_LO , "+Lo" ,GenTreeOp ,1,GTK_BINOP) +GTNODE(ADD_HI , "+Hi" ,GenTreeOp ,1,GTK_BINOP) +GTNODE(SUB_LO , "-Lo" ,GenTreeOp ,0,GTK_BINOP) +GTNODE(SUB_HI , "-Hi" ,GenTreeOp ,0,GTK_BINOP) +GTNODE(DIV_HI , "/Hi" ,GenTreeOp ,0,GTK_BINOP) +GTNODE(MOD_HI , "%Hi" ,GenTreeOp ,0,GTK_BINOP) +GTNODE(MUL_LONG , "*long" ,GenTreeOp ,1,GTK_BINOP) // A mul that returns the 2N bit result of an NxN multiply. This op + // is used for x86 multiplies that take two ints and return a long + // result. All other multiplies with long results are morphed into + // helper calls. It is similar to GT_MULHI, the difference being that + // GT_MULHI drops the lo part of the result, whereas GT_MUL_LONG keeps + // both parts of the result. #endif // !defined(LEGACY_BACKEND) && !defined(_TARGET_64BIT_) #ifdef FEATURE_SIMD -GTNODE(SIMD , "simd" ,0,GTK_BINOP|GTK_EXOP) // SIMD functions/operators/intrinsics +GTNODE(SIMD , "simd" ,GenTreeSIMD ,0,GTK_BINOP|GTK_EXOP) // SIMD functions/operators/intrinsics #endif // FEATURE_SIMD //----------------------------------------------------------------------------- // Other nodes that look like unary/binary operators: //----------------------------------------------------------------------------- -// The following are both conditional branches. GT_JTRUE has a single operand that computes a condition. GT_JCC -// implicitly reads the condition bits from a previous operation. The latter is allowed only in the LIR form -// used in the RyuJIT backend. -GTNODE(JTRUE , "jmpTrue" ,0,GTK_UNOP|GTK_NOVALUE) -GTNODE(JCC , "jcc" ,0,GTK_LEAF|GTK_NOVALUE) +GTNODE(JTRUE , "jmpTrue" ,GenTreeOp ,0,GTK_UNOP|GTK_NOVALUE) +GTNODE(JCC , "jcc" ,GenTreeJumpCC ,0,GTK_LEAF|GTK_NOVALUE) -GTNODE(LIST , "" ,0,GTK_BINOP) +GTNODE(LIST , "" ,GenTreeOp ,0,GTK_BINOP) //----------------------------------------------------------------------------- // Other nodes that have special structure: //----------------------------------------------------------------------------- -GTNODE(FIELD , "field" ,0,GTK_SPECIAL) // Member-field -GTNODE(ARR_ELEM , "arrMD&" ,0,GTK_SPECIAL) // Multi-dimensional array-element address -GTNODE(ARR_INDEX , "arrMDIdx" ,0,GTK_BINOP|GTK_EXOP) // Effective, bounds-checked index for one dimension of a multi-dimensional array element -GTNODE(ARR_OFFSET , "arrMDOffs" ,0,GTK_SPECIAL) // Flattened offset of multi-dimensional array element -GTNODE(CALL , "call()" ,0,GTK_SPECIAL) +GTNODE(FIELD , "field" ,GenTreeField ,0,GTK_SPECIAL) // Member-field +GTNODE(ARR_ELEM , "arrMD&" ,GenTreeArrElem ,0,GTK_SPECIAL) // Multi-dimensional array-element address +GTNODE(ARR_INDEX , "arrMDIdx" ,GenTreeArrIndex ,0,GTK_BINOP|GTK_EXOP) // Effective, bounds-checked index for one dimension of a multi-dimensional array element +GTNODE(ARR_OFFSET , "arrMDOffs" ,GenTreeArrOffs ,0,GTK_SPECIAL) // Flattened offset of multi-dimensional array element +GTNODE(CALL , "call()" ,GenTreeCall ,0,GTK_SPECIAL) //----------------------------------------------------------------------------- // Statement operator nodes: //----------------------------------------------------------------------------- -GTNODE(BEG_STMTS , "begStmts" ,0,GTK_SPECIAL|GTK_NOVALUE) // used only temporarily in importer by impBegin/EndTreeList() -GTNODE(STMT , "stmtExpr" ,0,GTK_SPECIAL|GTK_NOVALUE) // top-level list nodes in bbTreeList +GTNODE(BEG_STMTS , "begStmts" ,GenTree ,0,GTK_SPECIAL|GTK_NOVALUE)// used only temporarily in importer by impBegin/EndTreeList() +GTNODE(STMT , "stmtExpr" ,GenTreeStmt ,0,GTK_SPECIAL|GTK_NOVALUE)// top-level list nodes in bbTreeList -GTNODE(RETURN , "return" ,0,GTK_UNOP|GTK_NOVALUE) // return from current function -GTNODE(SWITCH , "switch" ,0,GTK_UNOP|GTK_NOVALUE) // switch +GTNODE(RETURN , "return" ,GenTreeOp ,0,GTK_UNOP|GTK_NOVALUE) // return from current function +GTNODE(SWITCH , "switch" ,GenTreeOp ,0,GTK_UNOP|GTK_NOVALUE) // switch -GTNODE(NO_OP , "no_op" ,0,GTK_LEAF|GTK_NOVALUE) // nop! +GTNODE(NO_OP , "no_op" ,GenTree ,0,GTK_LEAF|GTK_NOVALUE) // nop! -GTNODE(START_NONGC, "start_nongc",0,GTK_LEAF|GTK_NOVALUE) // starts a new instruction group that will be non-gc interruptible +GTNODE(START_NONGC , "start_nongc" ,GenTree ,0,GTK_LEAF|GTK_NOVALUE) // starts a new instruction group that will be non-gc interruptible -GTNODE(PROF_HOOK , "prof_hook" ,0,GTK_LEAF|GTK_NOVALUE) // profiler Enter/Leave/TailCall hook +GTNODE(PROF_HOOK , "prof_hook" ,GenTree ,0,GTK_LEAF|GTK_NOVALUE) // profiler Enter/Leave/TailCall hook -GTNODE(RETFILT , "retfilt", 0,GTK_UNOP|GTK_NOVALUE) // end filter with TYP_I_IMPL return value +GTNODE(RETFILT , "retfilt" ,GenTreeOp ,0,GTK_UNOP|GTK_NOVALUE) // end filter with TYP_I_IMPL return value #if !FEATURE_EH_FUNCLETS -GTNODE(END_LFIN , "endLFin" ,0,GTK_LEAF|GTK_NOVALUE) // end locally-invoked finally +GTNODE(END_LFIN , "endLFin" ,GenTreeVal ,0,GTK_LEAF|GTK_NOVALUE) // end locally-invoked finally #endif // !FEATURE_EH_FUNCLETS //----------------------------------------------------------------------------- // Nodes used for optimizations. //----------------------------------------------------------------------------- -GTNODE(PHI , "phi" ,0,GTK_UNOP) // phi node for ssa. -GTNODE(PHI_ARG , "phiArg" ,0,GTK_LEAF|GTK_LOCAL) // phi(phiarg, phiarg, phiarg) +GTNODE(PHI , "phi" ,GenTreeOp ,0,GTK_UNOP) // phi node for ssa. +GTNODE(PHI_ARG , "phiArg" ,GenTreePhiArg ,0,GTK_LEAF|GTK_LOCAL) // phi(phiarg, phiarg, phiarg) //----------------------------------------------------------------------------- // Nodes used by Lower to generate a closer CPU representation of other nodes //----------------------------------------------------------------------------- -GTNODE(JMPTABLE , "jumpTable" , 0, GTK_LEAF) // Generates the jump table for switches -GTNODE(SWITCH_TABLE, "tableSwitch", 0, GTK_BINOP|GTK_NOVALUE) // Jump Table based switch construct +GTNODE(JMPTABLE , "jumpTable" ,GenTreeJumpTable ,0, GTK_LEAF) // Generates the jump table for switches +GTNODE(SWITCH_TABLE , "tableSwitch" ,GenTreeOp ,0, GTK_BINOP|GTK_NOVALUE) // Jump Table based switch construct //----------------------------------------------------------------------------- // Nodes used only within the code generator: //----------------------------------------------------------------------------- -GTNODE(REG_VAR , "regVar" ,0,GTK_LEAF|GTK_LOCAL) // register variable -GTNODE(CLS_VAR , "clsVar" ,0,GTK_LEAF) // static data member -GTNODE(CLS_VAR_ADDR , "&clsVar" ,0,GTK_LEAF) // static data member address -GTNODE(STORE_CLS_VAR, "st.clsVar" ,0,GTK_LEAF|GTK_NOVALUE) // store to static data member -GTNODE(ARGPLACE , "argPlace" ,0,GTK_LEAF) // placeholder for a register arg -GTNODE(NULLCHECK , "nullcheck" ,0,GTK_UNOP|GTK_NOVALUE) // null checks the source -GTNODE(PHYSREG , "physregSrc" ,0,GTK_LEAF) // read from a physical register -GTNODE(PHYSREGDST , "physregDst" ,0,GTK_UNOP|GTK_NOVALUE) // write to a physical register -GTNODE(EMITNOP , "emitnop" ,0,GTK_LEAF|GTK_NOVALUE) // emitter-placed nop -GTNODE(PINVOKE_PROLOG,"pinvoke_prolog",0,GTK_LEAF|GTK_NOVALUE) // pinvoke prolog seq -GTNODE(PINVOKE_EPILOG,"pinvoke_epilog",0,GTK_LEAF|GTK_NOVALUE) // pinvoke epilog seq -GTNODE(PUTARG_REG , "putarg_reg" ,0,GTK_UNOP) // operator that places outgoing arg in register -GTNODE(PUTARG_STK , "putarg_stk" ,0,GTK_UNOP) // operator that places outgoing arg in stack -GTNODE(RETURNTRAP , "returnTrap" ,0,GTK_UNOP|GTK_NOVALUE) // a conditional call to wait on gc -GTNODE(SWAP , "swap" ,0,GTK_BINOP|GTK_NOVALUE) // op1 and op2 swap (registers) -GTNODE(IL_OFFSET , "il_offset" ,0,GTK_LEAF|GTK_NOVALUE) // marks an IL offset for debugging purposes +GTNODE(REG_VAR , "regVar" ,GenTreeLclVar ,0,GTK_LEAF|GTK_LOCAL) // register variable +GTNODE(CLS_VAR , "clsVar" ,GenTreeClsVar ,0,GTK_LEAF) // static data member +GTNODE(CLS_VAR_ADDR , "&clsVar" ,GenTreeClsVar ,0,GTK_LEAF) // static data member address +GTNODE(ARGPLACE , "argPlace" ,GenTreeArgPlace ,0,GTK_LEAF) // placeholder for a register arg +GTNODE(NULLCHECK , "nullcheck" ,GenTreeOp ,0,GTK_UNOP|GTK_NOVALUE) // null checks the source +GTNODE(PHYSREG , "physregSrc" ,GenTreePhysReg ,0,GTK_LEAF) // read from a physical register +GTNODE(PHYSREGDST , "physregDst" ,GenTreeOp ,0,GTK_UNOP|GTK_NOVALUE) // write to a physical register +GTNODE(EMITNOP , "emitnop" ,GenTree ,0,GTK_LEAF|GTK_NOVALUE) // emitter-placed nop +GTNODE(PINVOKE_PROLOG ,"pinvoke_prolog",GenTree ,0,GTK_LEAF|GTK_NOVALUE) // pinvoke prolog seq +GTNODE(PINVOKE_EPILOG ,"pinvoke_epilog",GenTree ,0,GTK_LEAF|GTK_NOVALUE) // pinvoke epilog seq +GTNODE(PUTARG_REG , "putarg_reg" ,GenTreeOp ,0,GTK_UNOP) // operator that places outgoing arg in register +GTNODE(PUTARG_STK , "putarg_stk" ,GenTreePutArgStk ,0,GTK_UNOP) // operator that places outgoing arg in stack +GTNODE(RETURNTRAP , "returnTrap" ,GenTreeOp ,0,GTK_UNOP|GTK_NOVALUE) // a conditional call to wait on gc +GTNODE(SWAP , "swap" ,GenTreeOp ,0,GTK_BINOP|GTK_NOVALUE) // op1 and op2 swap (registers) +GTNODE(IL_OFFSET , "il_offset" ,GenTreeStmt ,0,GTK_LEAF|GTK_NOVALUE) // marks an IL offset for debugging purposes /*****************************************************************************/ #undef GTNODE diff --git a/src/jit/jit.h b/src/jit/jit.h index f917acd..8b79f88 100644 --- a/src/jit/jit.h +++ b/src/jit/jit.h @@ -465,6 +465,7 @@ typedef ptrdiff_t ssize_t; #define MEASURE_NODE_SIZE 0 // Collect stats about GenTree node allocations. #define MEASURE_PTRTAB_SIZE 0 // Collect stats about GC pointer table allocations. #define EMITTER_STATS 0 // Collect stats on the emitter. +#define NODEBASH_STATS 0 // Collect stats on changed gtOper values in GenTree's. #define VERBOSE_SIZES 0 // Always display GC info sizes. If set, DISPLAY_SIZES must also be set. #define VERBOSE_VERIFY 0 // Dump additional information when verifying code. Useful to debug verification bugs. diff --git a/src/jit/liveness.cpp b/src/jit/liveness.cpp index 19d3263..a8c674f 100644 --- a/src/jit/liveness.cpp +++ b/src/jit/liveness.cpp @@ -2548,10 +2548,10 @@ bool Compiler::fgRemoveDeadStore( switch (asgNode->gtOper) { case GT_ASG_ADD: - asgNode->gtOper = GT_ADD; + asgNode->SetOperRaw(GT_ADD); break; case GT_ASG_SUB: - asgNode->gtOper = GT_SUB; + asgNode->SetOperRaw(GT_SUB); break; default: // Only add and sub allowed, we don't have ASG_MUL and ASG_DIV for ints, and diff --git a/src/jit/lower.cpp b/src/jit/lower.cpp index 61bc6c9..cb9c3e9 100644 --- a/src/jit/lower.cpp +++ b/src/jit/lower.cpp @@ -2857,7 +2857,7 @@ void Lowering::InsertPInvokeCallEpilog(GenTreeCall* call) // First argument is the address of the frame variable. GenTree* frameAddr = new (comp, GT_LCL_VAR) GenTreeLclVar(GT_LCL_VAR, TYP_BYREF, comp->lvaInlinedPInvokeFrameVar, BAD_IL_OFFSET); - frameAddr->gtOper = GT_LCL_VAR_ADDR; + frameAddr->SetOperRaw(GT_LCL_VAR_ADDR); // Insert call to CORINFO_HELP_JIT_PINVOKE_END GenTree* helperCall = diff --git a/src/jit/lowerxarch.cpp b/src/jit/lowerxarch.cpp index c82603b..f818809 100644 --- a/src/jit/lowerxarch.cpp +++ b/src/jit/lowerxarch.cpp @@ -3102,7 +3102,7 @@ void Lowering::TreeNodeInfoInitCmp(GenTreePtr tree) // so that we can generate a test instruction. // Reverse the equality comparison - tree->gtOper = (tree->gtOper == GT_EQ) ? GT_NE : GT_EQ; + tree->SetOperRaw((tree->gtOper == GT_EQ) ? GT_NE : GT_EQ); // Change the relOp2CnsVal to zero relOp2CnsVal = 0; diff --git a/src/jit/rationalize.cpp b/src/jit/rationalize.cpp index 081d642..11cba06 100644 --- a/src/jit/rationalize.cpp +++ b/src/jit/rationalize.cpp @@ -526,7 +526,7 @@ void Rationalizer::RewriteAssignment(LIR::Use& use) } JITDUMP("Rewriting GT_ASG(%s(X), Y) to %s(X,Y):\n", GenTree::NodeName(location->gtOper), GenTree::NodeName(storeOper)); - storeBlk->gtOper = storeOper; + storeBlk->SetOperRaw(storeOper); storeBlk->gtFlags &= ~GTF_DONT_CSE; storeBlk->gtFlags |= (assignment->gtFlags & (GTF_ALL_EFFECT | GTF_REVERSE_OPS | GTF_BLK_VOLATILE | GTF_BLK_UNALIGNED | GTF_BLK_INIT | GTF_DONT_CSE)); -- 2.7.4