Introduce `GenTreeDebugOperKind` (#64498)
authorSingleAccretion <62474226+SingleAccretion@users.noreply.github.com>
Fri, 11 Feb 2022 16:08:54 +0000 (19:08 +0300)
committerGitHub <noreply@github.com>
Fri, 11 Feb 2022 16:08:54 +0000 (08:08 -0800)
* Introducing GenTreeDebugOperKind

To track invariants related to opers in asserts
without increasing the size of the primary oper
kind table.

Some shuffling of the oper table to make it look better.

* More "gtlist.h" cleanup

Put all OperIsIdir opers together, fix up formatting,
move opers around to more logical places.

* Remove redundant asserts

* GTK_NOTLIR -> DBK_NOTLIR

There is not a lot of point in this being a "release"
oper kind, as it is really only useful for debug checks.

* GTK_NOCONTAIN -> DBK_NOCONTAIN

* Fix formatting...

src/coreclr/jit/assertionprop.cpp
src/coreclr/jit/fgstmt.cpp
src/coreclr/jit/gentree.cpp
src/coreclr/jit/gentree.h
src/coreclr/jit/gtlist.h
src/coreclr/jit/lir.cpp
src/coreclr/jit/lsra.cpp
src/coreclr/jit/lsrabuild.cpp
src/coreclr/jit/rationalize.cpp
src/coreclr/jit/valuenum.cpp

index 87e6733..b5ee60a 100644 (file)
@@ -5636,11 +5636,6 @@ Compiler::fgWalkResult Compiler::optVNConstantPropCurStmt(BasicBlock* block, Sta
         case GT_INTRINSIC:
             break;
 
-        case GT_INC_SATURATE:
-        case GT_MULHI:
-            assert(false && "Unexpected GT_INC_SATURATE/GT_MULHI node encountered before lowering");
-            break;
-
         case GT_JTRUE:
             break;
 
index f5f0739..0730540 100644 (file)
@@ -511,9 +511,9 @@ void Compiler::fgRemoveStmt(BasicBlock* block, Statement* stmt DEBUGARG(bool isU
 }
 
 /******************************************************************************/
-// Returns true if the operator is involved in control-flow
-// TODO-Cleanup: Move this into genTreeKinds in genTree.h
-
+// Returns true if the operator is involved in control-flow.
+// TODO-Cleanup: Make this a GenTreeOperKind.
+//
 inline bool OperIsControlFlow(genTreeOps oper)
 {
     switch (oper)
index 93de256..6797943 100644 (file)
@@ -21,10 +21,17 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 /*****************************************************************************/
 
 const unsigned char GenTree::gtOperKindTable[] = {
-#define GTNODE(en, st, cm, ok) (ok) + GTK_COMMUTE *cm,
+#define GTNODE(en, st, cm, 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),
+#include "gtlist.h"
+};
+#endif // DEBUG
+
 /*****************************************************************************
  *
  *  The types of different GenTree nodes
@@ -15712,29 +15719,32 @@ unsigned GenTree::IsLclVarUpdateTree(GenTree** pOtherTree, genTreeOps* pOper)
     return lclNum;
 }
 
+#ifdef DEBUG
 //------------------------------------------------------------------------
 // canBeContained: check whether this tree node may be a subcomponent of its parent for purposes
 //                 of code generation.
 //
-// Return value: returns true if it is possible to contain this node and false otherwise.
+// Return Value:
+//    True if it is possible to contain this node and false otherwise.
+//
 bool GenTree::canBeContained() const
 {
-    assert(IsLIR());
+    assert(OperIsLIR());
 
     if (gtHasReg())
     {
         return false;
     }
 
-    // It is not possible for nodes that do not produce values or that are not containable values
-    // to be contained.
-    if (((OperKind() & (GTK_NOVALUE | GTK_NOCONTAIN)) != 0) || (OperIsHWIntrinsic() && !isContainableHWIntrinsic()))
+    // It is not possible for nodes that do not produce values or that are not containable values to be contained.
+    if (!IsValue() || ((DebugOperKind() & DBK_NOCONTAIN) != 0) || (OperIsHWIntrinsic() && !isContainableHWIntrinsic()))
     {
         return false;
     }
 
     return true;
 }
+#endif // DEBUG
 
 //------------------------------------------------------------------------
 // isContained: check whether this tree node is a subcomponent of its parent for codegen purposes
@@ -15751,7 +15761,7 @@ bool GenTree::canBeContained() const
 //
 bool GenTree::isContained() const
 {
-    assert(IsLIR());
+    assert(OperIsLIR());
     const bool isMarkedContained = ((gtFlags & GTF_CONTAINED) != 0);
 
 #ifdef DEBUG
index 10ed5ab..5d37fb3 100644 (file)
@@ -85,7 +85,7 @@ enum genTreeOps : BYTE
 // The following enum defines a set of bit flags that can be used
 // to classify expression tree nodes.
 //
-enum genTreeKinds
+enum GenTreeOperKind
 {
     GTK_SPECIAL = 0x00, // special operator
     GTK_LEAF    = 0x01, // leaf    operator
@@ -95,12 +95,28 @@ enum genTreeKinds
     GTK_KINDMASK = (GTK_SPECIAL | GTK_LEAF | GTK_UNOP | GTK_BINOP), // operator kind mask
     GTK_SMPOP    = (GTK_UNOP | GTK_BINOP),
 
-    GTK_COMMUTE = 0x08,   // commutative  operator
-    GTK_EXOP    = 0x10,   // Indicates that an oper for a node type that extends GenTreeOp (or GenTreeUnOp)
-                          // by adding non-node fields to unary or binary operator.
-    GTK_NOVALUE   = 0x20, // node does not produce a value
-    GTK_NOTLIR    = 0x40, // node is not allowed in LIR
-    GTK_NOCONTAIN = 0x80, // this node is a value, but may not be contained
+    GTK_COMMUTE = 0x08, // commutative  operator
+    GTK_EXOP    = 0x10, // Indicates that an oper for a node type that extends GenTreeOp (or GenTreeUnOp)
+                        // by adding non-node fields to unary or binary operator.
+    GTK_NOVALUE = 0x20, // node does not produce a value
+
+    GTK_MASK = 0xFF
+};
+
+// The following enum defines a set of bit flags that describe opers for the purposes
+// of DEBUG-only checks. This is separate from the above "GenTreeOperKind"s to avoid
+// making the table for those larger in Release builds. However, it resides in the same
+// "namespace" and so all values here must be distinct from those in "GenTreeOperKind".
+//
+enum GenTreeDebugOperKind
+{
+    DBK_FIRST_FLAG = GTK_MASK + 1,
+
+    DBK_NOTHIR    = DBK_FIRST_FLAG,      // This oper is not supported in HIR (before rationalization).
+    DBK_NOTLIR    = DBK_FIRST_FLAG << 1, // This oper is not supported in LIR (after rationalization).
+    DBK_NOCONTAIN = DBK_FIRST_FLAG << 2, // This oper produces a value, but may not be contained.
+
+    DBK_MASK = ~GTK_MASK
 };
 
 /*****************************************************************************/
@@ -878,8 +894,11 @@ private:
 public:
     // The register number is stored in a small format (8 bits), but the getters return and the setters take
     // a full-size (unsigned) format, to localize the casts here.
+    CLANG_FORMAT_COMMENT_ANCHOR;
 
+#ifdef DEBUG
     bool canBeContained() const;
+#endif
 
     // for codegen purposes, is this node a subnode of its parent
     bool isContained() const;
@@ -1073,34 +1092,6 @@ public:
         return true;
     }
 
-    bool IsLIR() const
-    {
-        if ((OperKind(gtOper) & GTK_NOTLIR) != 0)
-        {
-            return false;
-        }
-
-        switch (gtOper)
-        {
-            case GT_NOP:
-                // NOPs may only be present in LIR if they do not produce a value.
-                return IsNothingNode();
-
-            case GT_ADDR:
-            {
-                // ADDR ndoes may only be present in LIR if the location they refer to is not a
-                // local, class variable, or IND node.
-                GenTree*   location   = gtGetOp1();
-                genTreeOps locationOp = location->OperGet();
-                return !location->IsLocal() && (locationOp != GT_CLS_VAR) && (locationOp != GT_IND);
-            }
-
-            default:
-                // All other nodes are assumed to be correct.
-                return true;
-        }
-    }
-
     // LIR flags
     //   These helper methods, along with the flag values they manipulate, are defined in lir.h
     //
@@ -1650,6 +1641,20 @@ public:
     }
 
 #ifdef DEBUG
+    static const GenTreeDebugOperKind gtDebugOperKindTable[];
+
+    static GenTreeDebugOperKind DebugOperKind(genTreeOps oper)
+    {
+        assert(oper < GT_COUNT);
+
+        return gtDebugOperKindTable[oper];
+    }
+
+    GenTreeDebugOperKind DebugOperKind() const
+    {
+        return DebugOperKind(OperGet());
+    }
+
     bool NullOp1Legal() const
     {
         assert(OperIsSimple());
@@ -1688,6 +1693,17 @@ public:
         }
     }
 
+    bool OperIsLIR() const
+    {
+        if (OperIs(GT_NOP))
+        {
+            // NOPs may only be present in LIR if they do not produce a value.
+            return IsNothingNode();
+        }
+
+        return (DebugOperKind() & DBK_NOTLIR) == 0;
+    }
+
     bool        OperSupportsReverseOps() const;
     static bool RequiresNonNullOp2(genTreeOps oper);
     bool IsValidCallArgument();
index 9b40861..1d0be8b 100644 (file)
@@ -11,7 +11,7 @@
 //     Node enum
 //                       , GenTree struct flavor
 //                                           ,commutative
-//                                             ,operKind
+//                                             ,oper kind | DEBUG oper kind
 
 GTNODE(NONE             , char               ,0,GTK_SPECIAL)
 
@@ -19,23 +19,27 @@ GTNODE(NONE             , char               ,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_NOVALUE)) // store to local variable
-GTNODE(STORE_LCL_FLD    , GenTreeLclFld      ,0,(GTK_UNOP|GTK_NOVALUE)) // store to a part of the variable
-GTNODE(LCL_VAR_ADDR     , GenTreeLclVar      ,0,GTK_LEAF)               // address of local variable
-GTNODE(LCL_FLD_ADDR     , GenTreeLclFld      ,0,GTK_LEAF)               // address of field in a non-primitive variable
+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_NOVALUE) // store to local variable
+GTNODE(STORE_LCL_FLD    , GenTreeLclFld      ,0,GTK_UNOP|GTK_NOVALUE) // store to a part of the variable
+GTNODE(LCL_VAR_ADDR     , GenTreeLclVar      ,0,GTK_LEAF)             // address of local variable
+GTNODE(LCL_FLD_ADDR     , GenTreeLclFld      ,0,GTK_LEAF)             // address of field in a non-primitive variable
 
 //-----------------------------------------------------------------------------
 //  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(FTN_ADDR         , GenTreeFptrVal     ,0,GTK_LEAF)               // Address of a function
-GTNODE(RET_EXPR         , GenTreeRetExpr     ,0,GTK_LEAF|GTK_NOTLIR)    // Place holder for the return expression from an inline candidate
+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(CLS_VAR          , GenTreeClsVar      ,0,GTK_LEAF)             // Static data member
+
+GTNODE(ARGPLACE         , GenTreeArgPlace    ,0,GTK_LEAF|GTK_NOVALUE|DBK_NOTLIR)  // Placeholder for a "late arg" in the original arg list.
 
 //-----------------------------------------------------------------------------
 //  Constant nodes:
@@ -51,54 +55,52 @@ GTNODE(CNS_STR          , GenTreeStrCon      ,0,GTK_LEAF)
 //-----------------------------------------------------------------------------
 
 GTNODE(NOT              , GenTreeOp          ,0,GTK_UNOP)
-GTNODE(NOP              , GenTree            ,0,(GTK_UNOP|GTK_NOCONTAIN))
+GTNODE(NOP              , GenTree            ,0,GTK_UNOP|DBK_NOCONTAIN)
 GTNODE(NEG              , GenTreeOp          ,0,GTK_UNOP)
-GTNODE(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           , GenTreeCopyOrReload,0,GTK_UNOP)
-GTNODE(ARR_LENGTH       , GenTreeArrLen      ,0,(GTK_UNOP|GTK_EXOP))      // array-length
-GTNODE(INTRINSIC        , GenTreeIntrinsic   ,0,(GTK_BINOP|GTK_EXOP))     // intrinsics
 
-GTNODE(LOCKADD          , GenTreeOp          ,0,(GTK_BINOP|GTK_NOVALUE))
+GTNODE(INTRINSIC        , GenTreeIntrinsic   ,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(MEMORYBARRIER    , GenTree            ,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,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,GTK_UNOP|GTK_EXOP)      // conversion to another type
 #if defined(TARGET_ARM)
 GTNODE(BITCAST          , GenTreeMultiRegOp  ,0,GTK_UNOP)               // reinterpretation of bits as another type
 #else
 GTNODE(BITCAST          , GenTreeOp          ,0,GTK_UNOP)               // reinterpretation of bits as another type
 #endif
-GTNODE(CKFINITE         , GenTreeOp          ,0,(GTK_UNOP|GTK_NOCONTAIN)) // Check for NaN
-GTNODE(LCLHEAP          , GenTreeOp          ,0,(GTK_UNOP|GTK_NOCONTAIN)) // alloca()
-GTNODE(JMP              , GenTreeVal         ,0,(GTK_LEAF|GTK_NOVALUE))   // Jump to another function
-
-GTNODE(ADDR             , GenTreeOp          ,0,GTK_UNOP)               // address of
+GTNODE(CKFINITE         , GenTreeOp          ,0,GTK_UNOP|DBK_NOCONTAIN) // Check for NaN
+GTNODE(LCLHEAP          , GenTreeOp          ,0,GTK_UNOP|DBK_NOCONTAIN) // alloca()
 
-GTNODE(IND              , GenTreeIndir       ,0,GTK_UNOP)                // load indirection
-GTNODE(STOREIND         , GenTreeStoreInd    ,0,(GTK_BINOP|GTK_NOVALUE)) // store indirection
+GTNODE(ADDR             , GenTreeOp          ,0,GTK_UNOP|DBK_NOTLIR)    // address of
 
-GTNODE(BOUNDS_CHECK     , GenTreeBoundsChk   ,0,(GTK_BINOP|GTK_EXOP|GTK_NOVALUE)) // a bounds check - for arrays/spans/SIMDs/HWINTRINSICs
+GTNODE(BOUNDS_CHECK     , GenTreeBoundsChk   ,0,GTK_BINOP|GTK_EXOP|GTK_NOVALUE) // a bounds check - for arrays/spans/SIMDs/HWINTRINSICs
 
-GTNODE(OBJ              , GenTreeObj         ,0,(GTK_UNOP|GTK_EXOP))              // Object that MAY have gc pointers, and thus includes the relevant gc layout info.
-GTNODE(STORE_OBJ        , GenTreeObj         ,0,(GTK_BINOP|GTK_EXOP|GTK_NOVALUE)) // Object that MAY have gc pointers, and thus includes the relevant gc layout info.
-GTNODE(BLK              , GenTreeBlk         ,0,(GTK_UNOP|GTK_EXOP))              // Block/object with no gc pointers, and with a known size (e.g. a struct with no gc fields)
-GTNODE(STORE_BLK        , GenTreeBlk         ,0,(GTK_BINOP|GTK_EXOP|GTK_NOVALUE)) // Block/object with no gc pointers, and with a known size (e.g. a struct with no gc fields)
-GTNODE(STORE_DYN_BLK    , GenTreeStoreDynBlk ,0,(GTK_SPECIAL|GTK_NOVALUE))        // Dynamically sized block store
+GTNODE(IND              , GenTreeIndir       ,0,GTK_UNOP)                       // Load indirection
+GTNODE(STOREIND         , GenTreeStoreInd    ,0,GTK_BINOP|GTK_NOVALUE)          // Store indirection
+GTNODE(OBJ              , GenTreeObj         ,0,GTK_UNOP|GTK_EXOP)              // Object that MAY have gc pointers, and thus includes the relevant gc layout info.
+GTNODE(STORE_OBJ        , GenTreeObj         ,0,GTK_BINOP|GTK_EXOP|GTK_NOVALUE) // Object that MAY have gc pointers, and thus includes the relevant gc layout info.
+GTNODE(BLK              , GenTreeBlk         ,0,GTK_UNOP|GTK_EXOP)              // Block/object with no gc pointers, and with a known size (e.g. a struct with no gc fields)
+GTNODE(STORE_BLK        , GenTreeBlk         ,0,GTK_BINOP|GTK_EXOP|GTK_NOVALUE) // Block/object with no gc pointers, and with a known size (e.g. a struct with no gc fields)
+GTNODE(STORE_DYN_BLK    , GenTreeStoreDynBlk ,0,GTK_SPECIAL|GTK_NOVALUE)        // Dynamically sized block store
+GTNODE(NULLCHECK        , GenTreeIndir       ,0,GTK_UNOP|GTK_NOVALUE)           // Null checks the source
 
-GTNODE(BOX              , GenTreeBox         ,0,(GTK_UNOP|GTK_EXOP|GTK_NOTLIR))
-GTNODE(FIELD            , GenTreeField       ,0,(GTK_UNOP|GTK_EXOP)) // Member-field
-GTNODE(ALLOCOBJ         , GenTreeAllocObj    ,0,(GTK_UNOP|GTK_EXOP)) // object allocator
+GTNODE(ARR_LENGTH       , GenTreeArrLen      ,0,GTK_UNOP|GTK_EXOP)
+GTNODE(FIELD            , GenTreeField       ,0,GTK_UNOP|GTK_EXOP|DBK_NOTLIR) // Member-field
+GTNODE(ALLOCOBJ         , GenTreeAllocObj    ,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,GTK_UNOP) // Initialization value for an initBlk
 
-GTNODE(RUNTIMELOOKUP    , GenTreeRuntimeLookup, 0,(GTK_UNOP|GTK_EXOP))    // Runtime handle lookup
+GTNODE(BOX              , GenTreeBox         ,0,GTK_UNOP|GTK_EXOP|DBK_NOTLIR)   // Marks its first operands (a local) as being a box
+GTNODE(PUTARG_TYPE      , GenTreeOp          ,0,GTK_UNOP|DBK_NOTLIR)            // Saves argument type between importation and morph
+GTNODE(RUNTIMELOOKUP    , GenTreeRuntimeLookup, 0,GTK_UNOP|GTK_EXOP|DBK_NOTLIR) // Runtime handle lookup
 
 GTNODE(BSWAP            , GenTreeOp          ,0,GTK_UNOP)               // Byte swap (32-bit or 64-bit)
 GTNODE(BSWAP16          , GenTreeOp          ,0,GTK_UNOP)               // Byte swap (16-bit)
@@ -126,7 +128,7 @@ GTNODE(RSZ              , GenTreeOp          ,0,GTK_BINOP)
 GTNODE(ROL              , GenTreeOp          ,0,GTK_BINOP)
 GTNODE(ROR              , GenTreeOp          ,0,GTK_BINOP)
 
-GTNODE(ASG              , GenTreeOp          ,0,(GTK_BINOP|GTK_NOTLIR))
+GTNODE(ASG              , GenTreeOp          ,0,GTK_BINOP|DBK_NOTLIR)
 GTNODE(EQ               , GenTreeOp          ,0,GTK_BINOP)
 GTNODE(NE               , GenTreeOp          ,0,GTK_BINOP)
 GTNODE(LT               , GenTreeOp          ,0,GTK_BINOP)
@@ -141,38 +143,35 @@ GTNODE(GT               , GenTreeOp          ,0,GTK_BINOP)
 // codegen which emits a "test reg, reg" instruction, that would be more difficult to do
 // during lowering because the source operand is used twice so it has to be a lclvar.
 // Because of this there is no need to also add GT_TEST_LT/LE/GE/GT opers.
-GTNODE(TEST_EQ          , GenTreeOp          ,0,GTK_BINOP)
-GTNODE(TEST_NE          , GenTreeOp          ,0,GTK_BINOP)
-
-GTNODE(COMMA            , GenTreeOp          ,0,(GTK_BINOP|GTK_NOTLIR))
-
-GTNODE(QMARK            , GenTreeQmark       ,0,(GTK_BINOP|GTK_EXOP|GTK_NOTLIR))
-GTNODE(COLON            , GenTreeColon       ,0,(GTK_BINOP|GTK_NOTLIR))
+GTNODE(TEST_EQ          , GenTreeOp          ,0,GTK_BINOP|DBK_NOTHIR)
+GTNODE(TEST_NE          , GenTreeOp          ,0,GTK_BINOP|DBK_NOTHIR)
 
-GTNODE(INDEX            , GenTreeIndex       ,0,(GTK_BINOP|GTK_EXOP|GTK_NOTLIR))   // SZ-array-element
-GTNODE(INDEX_ADDR       , GenTreeIndexAddr   ,0,(GTK_BINOP|GTK_EXOP)) // addr of SZ-array-element;
-                                                                      // used when aiming to minimize compile times.
+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(MKREFANY         , GenTreeOp          ,0,GTK_BINOP|GTK_NOTLIR)
+GTNODE(INDEX            , GenTreeIndex       ,0,GTK_BINOP|GTK_EXOP|DBK_NOTLIR) // SZ-array-element.
+GTNODE(INDEX_ADDR       , GenTreeIndexAddr   ,0,GTK_BINOP|GTK_EXOP)            // Addr of SZ-array-element; used when aiming to minimize compile times.
 
-GTNODE(LEA              , GenTreeAddrMode    ,0,(GTK_BINOP|GTK_EXOP))
+GTNODE(MKREFANY         , GenTreeOp          ,0,GTK_BINOP|DBK_NOTLIR)
+GTNODE(LEA              , GenTreeAddrMode    ,0,GTK_BINOP|GTK_EXOP)
 
 #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)
+GTNODE(LONG             , GenTreeOp          ,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)
-GTNODE(ADD_HI           , GenTreeOp          ,1,GTK_BINOP)
-GTNODE(SUB_LO           , GenTreeOp          ,0,GTK_BINOP)
-GTNODE(SUB_HI           , GenTreeOp          ,0,GTK_BINOP)
+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)
 
 // 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
@@ -181,8 +180,8 @@ GTNODE(SUB_HI           , GenTreeOp          ,0,GTK_BINOP)
 // 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)
-GTNODE(RSH_LO           , GenTreeOp          ,0,GTK_BINOP)
+GTNODE(LSH_HI           , GenTreeOp          ,0,GTK_BINOP|DBK_NOTHIR)
+GTNODE(RSH_LO           , GenTreeOp          ,0,GTK_BINOP|DBK_NOTHIR)
 #endif // !defined(TARGET_64BIT)
 
 #ifdef FEATURE_SIMD
@@ -197,13 +196,14 @@ GTNODE(HWINTRINSIC      , GenTreeHWIntrinsic ,0,GTK_SPECIAL)               // ha
 //  Backend-specific arithmetic nodes:
 //-----------------------------------------------------------------------------
 
-GTNODE(INC_SATURATE     , GenTreeOp          ,0,GTK_UNOP)  // saturating increment, used in division by a constant (LowerUnsignedDivOrMod)
+// Saturating increment, used in division by a constant (LowerUnsignedDivOrMod).
+GTNODE(INC_SATURATE     , GenTreeOp          ,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)
+GTNODE(MULHI            , GenTreeOp          ,1,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,
@@ -212,100 +212,96 @@ GTNODE(MULHI            , GenTreeOp          ,1,GTK_BINOP)
 // 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)
+GTNODE(MUL_LONG         , GenTreeMultiRegOp  ,1,GTK_BINOP|DBK_NOTHIR)
 #elif defined(TARGET_ARM64)
-GTNODE(MUL_LONG         , GenTreeOp          ,1,GTK_BINOP)
+GTNODE(MUL_LONG         , GenTreeOp          ,1,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)
+GTNODE(AND_NOT          , GenTreeOp          ,0,GTK_BINOP|DBK_NOTHIR)
+
+#ifdef TARGET_ARM64
+GTNODE(MADD             , GenTreeOp          ,0,GTK_BINOP|DBK_NOTHIR) // Generates the Multiply-Add instruction (madd/msub) In the future, we might consider
+                                                                      // enabling it for both armarch and xarch for floating-point MADD "unsafe" math.
+GTNODE(ADDEX,             GenTreeOp          ,0,GTK_BINOP|DBK_NOTHIR) // Add with sign/zero extension.
+GTNODE(BFIZ             , GenTreeOp          ,0,GTK_BINOP|DBK_NOTHIR) // Bitfield Insert in Zero.
+#endif
+
 //-----------------------------------------------------------------------------
 //  LIR specific compare and conditional branch/set nodes:
 //-----------------------------------------------------------------------------
 
-GTNODE(CMP              , GenTreeOp          ,0,(GTK_BINOP|GTK_NOVALUE))  // 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(JCMP             , GenTreeOp          ,0,(GTK_BINOP|GTK_NOVALUE))  // Makes a comparison and jump if the condition specified.  Does not set flags
-GTNODE(JCC              , GenTreeCC          ,0,(GTK_LEAF|GTK_NOVALUE))   // Checks the condition flags and branch if the condition specified
-                                                                        // by GenTreeCC::gtCondition is true.
-GTNODE(SETCC            , GenTreeCC          ,0,GTK_LEAF)               // Checks the condition flags and produces 1 if the condition specified
-                                                                        // by GenTreeCC::gtCondition is true and 0 otherwise.
+// 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)
+// Makes a comparison and jump if the condition specified.  Does not set flags.
+GTNODE(JCMP             , GenTreeOp          ,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)
+// 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)
 #ifdef TARGET_XARCH
-GTNODE(BT               , GenTreeOp          ,0,(GTK_BINOP|GTK_NOVALUE))  // The XARCH BT instruction. Like CMP, this sets the condition flags (CF
-                                                                        // to be precise) and does not produce a value.
+// 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))
 #endif
+
 //-----------------------------------------------------------------------------
 //  Other nodes that look like unary/binary operators:
 //-----------------------------------------------------------------------------
 
-GTNODE(JTRUE            , GenTreeOp          ,0,(GTK_UNOP|GTK_NOVALUE))
+GTNODE(JTRUE            , GenTreeOp          ,0,GTK_UNOP|GTK_NOVALUE)
 
 //-----------------------------------------------------------------------------
 //  Other nodes that have special structure:
 //-----------------------------------------------------------------------------
 
 GTNODE(ARR_ELEM         , GenTreeArrElem     ,0,GTK_SPECIAL)            // Multi-dimensional array-element address
-GTNODE(ARR_INDEX        , GenTreeArrIndex    ,0,(GTK_BINOP|GTK_EXOP))     // Effective, bounds-checked index for one dimension of a multi-dimensional array element
+GTNODE(ARR_INDEX        , GenTreeArrIndex    ,0,GTK_BINOP|GTK_EXOP)     // Effective, bounds-checked index for one dimension of a multi-dimensional array element
 GTNODE(ARR_OFFSET       , GenTreeArrOffs     ,0,GTK_SPECIAL)            // Flattened offset of multi-dimensional array element
-GTNODE(CALL             , GenTreeCall        ,0,(GTK_SPECIAL|GTK_NOCONTAIN))
+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(RETURN           , GenTreeOp          ,0,(GTK_UNOP|GTK_NOVALUE))   // return from current function
-GTNODE(SWITCH           , GenTreeOp          ,0,(GTK_UNOP|GTK_NOVALUE))   // switch
-
-GTNODE(NO_OP            , GenTree            ,0,(GTK_LEAF|GTK_NOVALUE))   // nop!
-
-GTNODE(START_NONGC      , GenTree            ,0,(GTK_LEAF|GTK_NOVALUE))   // starts a new instruction group that will be non-gc interruptible
-
-GTNODE(START_PREEMPTGC  , GenTree            ,0,(GTK_LEAF|GTK_NOVALUE))   // starts a new instruction group where preemptive GC is enabled
+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(PROF_HOOK        , GenTree            ,0,(GTK_LEAF|GTK_NOVALUE))   // profiler Enter/Leave/TailCall hook
+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(RETFILT          , GenTreeOp          ,0,(GTK_UNOP|GTK_NOVALUE))   // end filter with TYP_I_IMPL return value
+GTNODE(RETFILT          , GenTreeOp          ,0,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,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
 //-----------------------------------------------------------------------------
 
-#ifdef TARGET_ARM64
-GTNODE(MADD             , GenTreeOp          ,0, GTK_BINOP)                // Generates the Multiply-Add instruction (madd/msub)
-                                                                           // In future, we might consider enabling it for both armarch and xarch
-                                                                           // for floating-point MADD "unsafe" math
-#endif
-GTNODE(JMPTABLE         , GenTree            ,0, (GTK_LEAF|GTK_NOCONTAIN)) // Generates the jump table for switches
-GTNODE(SWITCH_TABLE     , GenTreeOp          ,0, (GTK_BINOP|GTK_NOVALUE))  // Jump Table based switch construct
-#ifdef TARGET_ARM64
-GTNODE(ADDEX,             GenTreeOp          ,0, GTK_BINOP)                // Add with sign/zero extension
-GTNODE(BFIZ             , GenTreeOp          ,0, GTK_BINOP)                // Bitfield Insert in Zero
-#endif
+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
 
 //-----------------------------------------------------------------------------
 //  Nodes used only within the code generator:
 //-----------------------------------------------------------------------------
 
-GTNODE(CLS_VAR          , GenTreeClsVar      ,0,GTK_LEAF)                        // static data member
-GTNODE(CLS_VAR_ADDR     , GenTreeClsVar      ,0,GTK_LEAF)                        // static data member address
-GTNODE(ARGPLACE         , GenTreeArgPlace    ,0,GTK_LEAF|GTK_NOVALUE|GTK_NOTLIR) // placeholder for a register arg
-GTNODE(NULLCHECK        , GenTreeIndir       ,0,GTK_UNOP|GTK_NOVALUE)            // null checks the source
-GTNODE(PHYSREG          , GenTreePhysReg     ,0,GTK_LEAF)                        // read from a physical register
-GTNODE(EMITNOP          , GenTree            ,0,GTK_LEAF|GTK_NOVALUE)            // emitter-placed nop
-GTNODE(PINVOKE_PROLOG   , GenTree            ,0,GTK_LEAF|GTK_NOVALUE)            // pinvoke prolog seq
-GTNODE(PINVOKE_EPILOG   , GenTree            ,0,GTK_LEAF|GTK_NOVALUE)            // pinvoke epilog seq
+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
 #if defined(TARGET_ARM)
-GTNODE(PUTARG_REG       , GenTreeMultiRegOp  ,0,GTK_UNOP)                        // operator that places outgoing arg in register
+GTNODE(PUTARG_REG       , GenTreeMultiRegOp  ,0,GTK_UNOP|DBK_NOTHIR)              // operator that places outgoing arg in register
 #else
-GTNODE(PUTARG_REG       , GenTreeOp          ,0,GTK_UNOP)                        // operator that places outgoing arg in register
+GTNODE(PUTARG_REG       , GenTreeOp          ,0,GTK_UNOP|DBK_NOTHIR)              // operator that places outgoing arg in register
 #endif
-GTNODE(PUTARG_TYPE      , GenTreeOp          ,0,GTK_UNOP|GTK_NOTLIR)             // operator that places saves argument type between importation and morph
-GTNODE(PUTARG_STK       , GenTreePutArgStk   ,0,GTK_UNOP|GTK_NOVALUE)            // operator that places outgoing arg in stack
+GTNODE(PUTARG_STK       , GenTreePutArgStk   ,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)                        // operator that places outgoing arg in registers with stack (split struct in ARM32)
+GTNODE(PUTARG_SPLIT     , GenTreePutArgSplit ,0,GTK_UNOP|DBK_NOTHIR)              // operator that places outgoing arg in registers with stack (split struct in ARM32)
 #endif // FEATURE_ARG_SPLIT
-GTNODE(RETURNTRAP       , GenTreeOp          ,0,GTK_UNOP|GTK_NOVALUE)            // a conditional call to wait on gc
-GTNODE(SWAP             , GenTreeOp          ,0,GTK_BINOP|GTK_NOVALUE)           // op1 and op2 swap (registers)
-GTNODE(IL_OFFSET        , Statement        ,0,GTK_LEAF|GTK_NOVALUE)            // marks an IL offset for debugging purposes
+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
 
 /*****************************************************************************/
 #undef  GTNODE
index 2f5b762..9334485 100644 (file)
@@ -1415,12 +1415,12 @@ private:
     {
         for (GenTree* operand : node->Operands())
         {
-            if (!operand->IsLIR())
+            // ARGPLACE nodes are not represented in the LIR sequence. Ignore them.
+            if (operand->OperIs(GT_ARGPLACE))
             {
-                // ARGPLACE nodes are not represented in the LIR sequence. Ignore them.
-                assert(operand->OperIs(GT_ARGPLACE));
                 continue;
             }
+
             if (operand->isContained())
             {
                 UseNodeOperands(operand);
@@ -1524,7 +1524,7 @@ bool LIR::Range::CheckLIR(Compiler* compiler, bool checkUnusedValues) const
     for (Iterator node = begin(), end = this->end(); node != end; prev = *node, ++node)
     {
         // Verify that the node is allowed in LIR.
-        assert(node->IsLIR());
+        assert(node->OperIsLIR());
 
         // Some nodes should never be marked unused, as they must be contained in the backend.
         // These may be marked as unused during dead code elimination traversal, but they *must* be subsequently
index d6a247b..0971bef 100644 (file)
@@ -9401,7 +9401,7 @@ void LinearScan::DumpOperandDefs(
 {
     assert(operand != nullptr);
     assert(operandString != nullptr);
-    if (!operand->IsLIR())
+    if (operand->OperIs(GT_ARGPLACE))
     {
         return;
     }
index 46d1316..2c2de88 100644 (file)
@@ -1611,12 +1611,12 @@ void LinearScan::buildUpperVectorRestoreRefPosition(Interval* lclVarInterval, Ls
 int LinearScan::ComputeOperandDstCount(GenTree* operand)
 {
     // GT_ARGPLACE is the only non-LIR node that is currently in the trees at this stage, though
-    // note that it is not in the linear order. It seems best to check for !IsLIR() rather than
-    // GT_ARGPLACE directly, since it's that characteristic that makes it irrelevant for this method.
-    if (!operand->IsLIR())
+    // note that it is not in the linear order.
+    if (operand->OperIs(GT_ARGPLACE))
     {
         return 0;
     }
+
     if (operand->isContained())
     {
         int dstCount = 0;
index 72c1591..5eacf65 100644 (file)
@@ -803,8 +803,8 @@ Compiler::fgWalkResult Rationalizer::RewriteNode(GenTree** useEdge, Compiler::Ge
 #endif // FEATURE_HW_INTRINSICS
 
         default:
-            // These nodes should not be present in HIR.
-            assert(!node->OperIs(GT_CMP, GT_SETCC, GT_JCC, GT_JCMP, GT_LOCKADD));
+            // Check that we don't have nodes not allowed in HIR here.
+            assert((node->DebugOperKind() & DBK_NOTHIR) == 0);
             break;
     }
 
index be8f65e..88966e1 100644 (file)
@@ -9052,10 +9052,6 @@ void Compiler::fgValueNumberTree(GenTree* tree)
                     }
                     break;
 
-                    case GT_LOCKADD: // Binop
-                        noway_assert("LOCKADD should not appear before lowering");
-                        break;
-
                     case GT_XORR: // Binop
                     case GT_XAND: // Binop
                     case GT_XADD: // Binop