}
}
+inline GenTree* Compiler::gtNewKeepAliveNode(GenTree* op)
+{
+ GenTree* keepalive = gtNewOperNode(GT_KEEPALIVE, TYP_VOID, op);
+
+ // Prevent both reordering and removal. Invalid optimizations of GC.KeepAlive are
+ // very subtle and hard to observe. Thus we are conservatively marking it with both
+ // GTF_CALL and GTF_GLOB_REF side-effects even though it may be more than strictly
+ // necessary. The conservative side-effects are unlikely to have negative impact
+ // on code quality in this case.
+ keepalive->gtFlags |= (GTF_CALL | GTF_GLOB_REF);
+
+ return keepalive;
+}
+
+inline GenTreeCast* Compiler::gtNewCastNode(var_types typ, GenTree* op1, bool fromUnsigned, var_types castType)
+{
+ GenTreeCast* cast = new (this, GT_CAST) GenTreeCast(typ, op1, fromUnsigned, castType);
+
+ return cast;
+}
+
+inline GenTreeCast* Compiler::gtNewCastNodeL(var_types typ, GenTree* op1, bool fromUnsigned, var_types castType)
+{
+ /* Some casts get transformed into 'GT_CALL' or 'GT_IND' nodes */
+
+ assert(GenTree::s_gtNodeSizes[GT_CALL] >= GenTree::s_gtNodeSizes[GT_CAST]);
+ assert(GenTree::s_gtNodeSizes[GT_CALL] >= GenTree::s_gtNodeSizes[GT_IND]);
+
+ /* Make a big node first and then change it to be GT_CAST */
+
+ GenTreeCast* cast =
+ new (this, LargeOpOpcode()) GenTreeCast(typ, op1, fromUnsigned, castType DEBUGARG(/*largeNode*/ true));
+
+ return cast;
+}
+
+inline GenTreeIndir* Compiler::gtNewMethodTableLookup(GenTree* object)
+{
+ assert(object->TypeIs(TYP_REF));
+ GenTreeIndir* result = gtNewIndir(TYP_I_IMPL, object, GTF_IND_INVARIANT);
+ return result;
+}
+
+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
+
+ // Bashing to MultiOp nodes is currently not supported.
+ assert(!OperIsMultiOp(oper));
+
+ gtOper = oper;
+}
+
+//------------------------------------------------------------------------
+// SetOper: Bash this tree to an oper within its "class".
+//
+// "Bashing" refers to the act of mutating a node in-place to represent
+// a different oper. It is effectively a custom version of the placement
+// new operator. This method encapsulates the common logic for bashing
+// nodes and is intended to be used when the new oper has the same "class"
+// as that being bashed from. "Class" here is used somewhat loosely, but
+// in general is tied to the GenTree subtype the new oper uses and what
+// "namespace" of GenTreeFlags it belongs to - this method does not clear
+// them. For example, GT_LCL_VAR and GT_LCL_FLD share the same "class", as
+// do GT_IND and GT_BLK, etc.
+//
+// This method initializes some fields on a limited number of common tree
+// subtypes, however, in general, it is the caller's responsibility to make
+// sure the new node ends up in a valid state.
+//
+// Arguments:
+// oper - The new oper
+// vnUpdate - Whether to clear or preserve the VN (default: clear)
+//
inline void GenTree::SetOper(genTreeOps oper, ValueNumberUpdate vnUpdate)
{
assert(((gtDebugFlags & GTF_DEBUG_NODE_SMALL) != 0) != ((gtDebugFlags & GTF_DEBUG_NODE_LARGE) != 0));
gtVNPair.SetBoth(ValueNumStore::NoVN);
}
- // Do "oper"-specific initializations. TODO-Cleanup: these are too ad-hoc to be reliable.
- // The bashing code should decide itself what to initialize and what to leave as it was.
+ // Do some "oper"-specific initializations. These are not intended to be exhaustive but
+ // rather simplify calling code for common patterns.
switch (oper)
{
case GT_CNS_INT:
}
}
-inline GenTree* Compiler::gtNewKeepAliveNode(GenTree* op)
-{
- GenTree* keepalive = gtNewOperNode(GT_KEEPALIVE, TYP_VOID, op);
-
- // Prevent both reordering and removal. Invalid optimizations of GC.KeepAlive are
- // very subtle and hard to observe. Thus we are conservatively marking it with both
- // GTF_CALL and GTF_GLOB_REF side-effects even though it may be more than strictly
- // necessary. The conservative side-effects are unlikely to have negative impact
- // on code quality in this case.
- keepalive->gtFlags |= (GTF_CALL | GTF_GLOB_REF);
-
- return keepalive;
-}
-
-inline GenTreeCast* Compiler::gtNewCastNode(var_types typ, GenTree* op1, bool fromUnsigned, var_types castType)
-{
- GenTreeCast* cast = new (this, GT_CAST) GenTreeCast(typ, op1, fromUnsigned, castType);
-
- return cast;
-}
-
-inline GenTreeCast* Compiler::gtNewCastNodeL(var_types typ, GenTree* op1, bool fromUnsigned, var_types castType)
-{
- /* Some casts get transformed into 'GT_CALL' or 'GT_IND' nodes */
-
- assert(GenTree::s_gtNodeSizes[GT_CALL] >= GenTree::s_gtNodeSizes[GT_CAST]);
- assert(GenTree::s_gtNodeSizes[GT_CALL] >= GenTree::s_gtNodeSizes[GT_IND]);
-
- /* Make a big node first and then change it to be GT_CAST */
-
- GenTreeCast* cast =
- new (this, LargeOpOpcode()) GenTreeCast(typ, op1, fromUnsigned, castType DEBUGARG(/*largeNode*/ true));
-
- return cast;
-}
-
-inline GenTreeIndir* Compiler::gtNewMethodTableLookup(GenTree* object)
-{
- assert(object->TypeIs(TYP_REF));
- GenTreeIndir* result = gtNewIndir(TYP_I_IMPL, object, GTF_IND_INVARIANT);
- return result;
-}
-
-/*****************************************************************************/
-
-/*****************************************************************************/
-
-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
-
- // Bashing to MultiOp nodes is not currently supported.
- assert(!OperIsMultiOp(oper));
-
- gtOper = oper;
-}
-
-inline void GenTree::SetOperResetFlags(genTreeOps oper)
-{
- SetOper(oper);
- gtFlags &= GTF_NODE_MASK;
-}
-
+//------------------------------------------------------------------------
+// ChangeOper: Bash this tree to an oper from a foreign "class".
+//
+// This bashing method, unlike "SetOper", clears oper-specific flags and
+// so is more suitable to bashing nodes between different "classes".
+//
+// Arguments:
+// oper - The new oper
+// vnUpdate - Whether to clear or preserve the VN (default: clear)
+//
inline void GenTree::ChangeOper(genTreeOps oper, ValueNumberUpdate vnUpdate)
{
assert(!OperIsConst(oper)); // use BashToConst() instead
gtFlags &= mask;
}
-inline void GenTree::ChangeOperUnchecked(genTreeOps oper)
-{
- GenTreeFlags mask = GTF_COMMON_MASK;
- if (this->OperIsIndirOrArrMetaData() && OperIsIndirOrArrMetaData(oper))
- {
- mask |= GTF_IND_NONFAULTING;
- }
- SetOperRaw(oper); // Trust the caller and don't use SetOper()
- gtFlags &= mask;
-}
-
//------------------------------------------------------------------------
// BashToConst: Bash the node to a constant one.
//
oper = (type == TYP_LONG) ? GT_CNS_NATIVELONG : GT_CNS_INT;
}
- SetOperResetFlags(oper);
+ SetOper(oper);
+ gtFlags &= GTF_NODE_MASK;
gtType = type;
switch (oper)