Fix #6893. (#6932)
authorPat Gavlin <pgavlin@gmail.com>
Wed, 31 Aug 2016 17:56:11 +0000 (10:56 -0700)
committerGitHub <noreply@github.com>
Wed, 31 Aug 2016 17:56:11 +0000 (10:56 -0700)
Aggregate arguments to calls (i.e. arguments that are made up
of multiple, independent values such as those to be passed in
multiple registers) are represented by GT_LIST nodes that are
not distiguishable from normal GT_LIST nodes without the extra
context of the call. GT_LIST nodes, however, are disallowed in
LIR ranges. The intersection of these two design choices causes
problems for code that operates on LIR but wants to observe
aggregate arguments as a whole (rather than piecewise). In the
case of #6893, this caused lowering to attempt to insert a
PUTARG_STK node after the GT_LIST node that represented the
aggregate argument that was being forced to the stack, which
caused an assertion in the LIR utilities to fail (the GT_LIST
node was passed as the insertion point to `LIR::Range::InsertAfter`,
which requires that the insertion point be a part of the given
range).

Conceptually, the fix is simple: the nodes that represent
aggregate arguments must be allowed to be part of LIR ranges.
The implementation, however, is complicated somewhat by the
need to distinguish the nodes used for aggregate arguments from
normal GT_LIST nodes. These changes implement a short-term
fix that distiguished these nodes by adding a node-specific flag,
`GTF_LIST_AGGREGATE`, to indicate that a GT_LIST node is in fact
an aggregate argument. In the long term, a more palatable
implementation would be the introduction of a new node and operator
type to represent aggregate arguments, but this is likely to
require broader changes to the compiler.

src/jit/compiler.h
src/jit/flowgraph.cpp
src/jit/gentree.cpp
src/jit/gentree.h
src/jit/gtlist.h
src/jit/lir.cpp
src/jit/lower.cpp
src/jit/lsra.cpp
src/jit/morph.cpp
src/jit/rationalize.cpp
tests/arm64/Tests.lst

index 2462c58..9235fa2 100644 (file)
@@ -1933,10 +1933,11 @@ public:
     GenTreePtr gtNewIndexRef(var_types typ, GenTreePtr arrayOp, GenTreePtr indexOp);
 
     GenTreeArgList* gtNewArgList(GenTreePtr op);
-
     GenTreeArgList* gtNewArgList(GenTreePtr op1, GenTreePtr op2);
     GenTreeArgList* gtNewArgList(GenTreePtr op1, GenTreePtr op2, GenTreePtr op3);
 
+    GenTreeArgList* gtNewAggregate(GenTree* element);
+
     static fgArgTabEntryPtr gtArgEntryByArgNum(GenTreePtr call, unsigned argNum);
     static fgArgTabEntryPtr gtArgEntryByNode(GenTreePtr call, GenTreePtr node);
     fgArgTabEntryPtr gtArgEntryByLateArgIndex(GenTreePtr call, unsigned lateArgInx);
index ced582b..e894525 100644 (file)
@@ -17979,7 +17979,7 @@ void Compiler::fgSetTreeSeqFinish(GenTreePtr tree, bool isLIR)
 {
     // If we are sequencing a node that does not appear in LIR,
     // do not add it to the list.
-    if (isLIR && ((tree->OperGet() == GT_LIST) || tree->OperGet() == GT_ARGPLACE))
+    if (isLIR && (((tree->OperGet() == GT_LIST) && !tree->AsArgList()->IsAggregate()) || tree->OperGet() == GT_ARGPLACE))
     {
         return;
     }
index 57c9f78..7a76dfa 100644 (file)
@@ -953,6 +953,27 @@ Compiler::fgWalkResult Compiler::fgWalkTreePostRec(GenTreePtr* pTree, fgWalkData
         }
         break;
 
+        case GT_LIST:
+        {
+            GenTreeArgList* list = tree->AsArgList();
+            if (list->IsAggregate())
+            {
+                for (; list != nullptr; list = list->Rest())
+                {
+                    result = fgWalkTreePostRec<computeStack>(&list->gtOp1, fgWalkData);
+                    if (result == WALK_ABORT)
+                    {
+                        return result;
+                    }
+                }
+                break;
+            }
+
+            // GT_LIST nodes that do not represent aggregate arguments intentionally fall through to the
+            // default node processing below.
+            __fallthrough;
+        }
+
         default:
             if (kind & GTK_SMPOP)
             {
@@ -5699,9 +5720,9 @@ GenTreePtr* GenTree::gtGetChildPointer(GenTreePtr parent)
     return nullptr;
 }
 
-bool GenTree::TryGetUse(GenTree* def, GenTree*** use, bool expandMultiRegArgs)
+bool GenTree::TryGetUse(GenTree* def, GenTree*** use)
 {
-    for (GenTree** useEdge : UseEdges(expandMultiRegArgs))
+    for (GenTree** useEdge : UseEdges())
     {
         if (*useEdge == def)
         {
@@ -6386,6 +6407,29 @@ GenTreeArgList* Compiler::gtNewArgList(GenTreePtr arg1, GenTreePtr arg2)
     return new (this, GT_LIST) GenTreeArgList(arg1, gtNewArgList(arg2));
 }
 
+//------------------------------------------------------------------------
+// Compiler::gtNewAggregate:
+//    Creates a new aggregate argument node. These nodes are used to
+//    represent arguments that are composed of multiple values (e.g.
+//    the lclVars that represent the fields of a promoted struct).
+//
+//    Note that aggregate arguments are currently represented by GT_LIST
+//    nodes that are marked with the GTF_LIST_AGGREGATE flag. This
+//    representation may be changed in the future to instead use its own
+//    node type (e.g. GT_AGGREGATE).
+//
+// Arguments:
+//    firstElement - The first element in the aggregate's list of values.
+//
+// Returns:
+//    The newly-created aggregate node.
+GenTreeArgList* Compiler::gtNewAggregate(GenTree* firstElement)
+{
+    GenTreeArgList* agg = gtNewArgList(firstElement);
+    agg->gtFlags |= GTF_LIST_AGGREGATE;
+    return agg;
+}
+
 /*****************************************************************************
  *
  *  Create a list out of the three values.
@@ -8356,18 +8400,14 @@ GenTreeUseEdgeIterator::GenTreeUseEdgeIterator()
     : m_node(nullptr)
     , m_edge(nullptr)
     , m_argList(nullptr)
-    , m_multiRegArg(nullptr)
-    , m_expandMultiRegArgs(false)
     , m_state(-1)
 {
 }
 
-GenTreeUseEdgeIterator::GenTreeUseEdgeIterator(GenTree* node, bool expandMultiRegArgs)
+GenTreeUseEdgeIterator::GenTreeUseEdgeIterator(GenTree* node)
     : m_node(node)
     , m_edge(nullptr)
     , m_argList(nullptr)
-    , m_multiRegArg(nullptr)
-    , m_expandMultiRegArgs(expandMultiRegArgs)
     , m_state(0)
 {
     assert(m_node != nullptr);
@@ -8456,17 +8496,11 @@ GenTree** GenTreeUseEdgeIterator::GetNextUseEdge() const
             }
 
         // Call, phi, and SIMD nodes are handled by MoveNext{Call,Phi,SIMD}UseEdge, repsectively.
-        //
-        // If FEATURE_MULTIREG_ARGS is enabled, so PUTARG_STK nodes also have special handling.
         case GT_CALL:
         case GT_PHI:
 #ifdef FEATURE_SIMD
         case GT_SIMD:
 #endif
-#if FEATURE_MULTIREG_ARGS
-        case GT_PUTARG_STK:
-#endif
-
             break;
 
         case GT_INITBLK:
@@ -8532,6 +8566,14 @@ GenTree** GenTreeUseEdgeIterator::GetNextUseEdge() const
         }
         break;
 
+        case GT_LIST:
+            if (m_node->AsArgList()->IsAggregate())
+            {
+                // List nodes that represent aggregates are handled by MoveNextAggregateUseEdge.
+                break;
+            }
+            __fallthrough;
+
         default:
             if (m_node->OperIsConst() || m_node->OperIsLeaf())
             {
@@ -8568,14 +8610,25 @@ GenTree** GenTreeUseEdgeIterator::GetNextUseEdge() const
 //
 void GenTreeUseEdgeIterator::MoveToNextCallUseEdge()
 {
+    enum
+    {
+        CALL_INSTANCE = 0,
+        CALL_ARGS = 1,
+        CALL_LATE_ARGS = 2,
+        CALL_CONTROL_EXPR = 3,
+        CALL_COOKIE = 4,
+        CALL_ADDRESS = 5,
+        CALL_TERMINAL = 6,
+    };
+
     GenTreeCall* call = m_node->AsCall();
 
     for (;;)
     {
         switch (m_state)
         {
-            case 0:
-                m_state   = 1;
+            case CALL_INSTANCE:
+                m_state   = CALL_ARGS;
                 m_argList = call->gtCallArgs;
 
                 if (call->gtCallObjp != nullptr)
@@ -8585,13 +8638,13 @@ void GenTreeUseEdgeIterator::MoveToNextCallUseEdge()
                 }
                 break;
 
-            case 1:
-            case 3:
+            case CALL_ARGS:
+            case CALL_LATE_ARGS:
                 if (m_argList == nullptr)
                 {
-                    m_state += 2;
+                    m_state++;
 
-                    if (m_state == 3)
+                    if (m_state == CALL_LATE_ARGS)
                     {
                         m_argList = call->gtCallLateArgs;
                     }
@@ -8599,38 +8652,14 @@ void GenTreeUseEdgeIterator::MoveToNextCallUseEdge()
                 else
                 {
                     GenTreeArgList* argNode = m_argList->AsArgList();
-                    if (m_expandMultiRegArgs && argNode->gtOp1->OperGet() == GT_LIST)
-                    {
-                        m_state += 1;
-                        m_multiRegArg = argNode->gtOp1;
-                    }
-                    else
-                    {
-                        m_edge    = &argNode->gtOp1;
-                        m_argList = argNode->Rest();
-                        return;
-                    }
-                }
-                break;
-
-            case 2:
-            case 4:
-                if (m_multiRegArg == nullptr)
-                {
-                    m_state -= 1;
-                    m_argList = m_argList->AsArgList()->Rest();
-                }
-                else
-                {
-                    GenTreeArgList* regNode = m_multiRegArg->AsArgList();
-                    m_edge                  = &regNode->gtOp1;
-                    m_multiRegArg           = regNode->Rest();
+                    m_edge                  = &argNode->gtOp1;
+                    m_argList               = argNode->Rest();
                     return;
                 }
                 break;
 
-            case 5:
-                m_state = call->gtCallType == CT_INDIRECT ? 6 : 8;
+            case CALL_CONTROL_EXPR:
+                m_state = call->gtCallType == CT_INDIRECT ? CALL_COOKIE : CALL_TERMINAL;
 
                 if (call->gtControlExpr != nullptr)
                 {
@@ -8639,10 +8668,10 @@ void GenTreeUseEdgeIterator::MoveToNextCallUseEdge()
                 }
                 break;
 
-            case 6:
+            case 4:
                 assert(call->gtCallType == CT_INDIRECT);
 
-                m_state = 7;
+                m_state = CALL_ADDRESS;
 
                 if (call->gtCallCookie != nullptr)
                 {
@@ -8651,10 +8680,10 @@ void GenTreeUseEdgeIterator::MoveToNextCallUseEdge()
                 }
                 break;
 
-            case 7:
+            case 5:
                 assert(call->gtCallType == CT_INDIRECT);
 
-                m_state = 8;
+                m_state = CALL_TERMINAL;
                 if (call->gtCallAddr != nullptr)
                 {
                     m_edge = &call->gtCallAddr;
@@ -8792,27 +8821,18 @@ void GenTreeUseEdgeIterator::MoveToNextSIMDUseEdge()
 }
 #endif // FEATURE_SIMD
 
-#if FEATURE_MULTIREG_ARGS
-void GenTreeUseEdgeIterator::MoveToNextPutArgStkUseEdge()
+void GenTreeUseEdgeIterator::MoveToNextAggregateUseEdge()
 {
-    assert(m_node->OperGet() == GT_PUTARG_STK);
-
-    GenTreeUnOp* putArg = m_node->AsUnOp();
+    assert(m_node->OperGet() == GT_LIST);
+    assert(m_node->AsArgList()->IsAggregate());
 
     for (;;)
     {
         switch (m_state)
         {
             case 0:
-                if ((putArg->gtOp1->OperGet() != GT_LIST) || !m_expandMultiRegArgs)
-                {
-                    m_state = 2;
-                    m_edge = &putArg->gtOp1;
-                    return;
-                }
-
                 m_state   = 1;
-                m_argList = putArg->gtOp1;
+                m_argList = m_node;
                 break;
 
             case 1:
@@ -8822,9 +8842,9 @@ void GenTreeUseEdgeIterator::MoveToNextPutArgStkUseEdge()
                 }
                 else
                 {
-                    GenTreeArgList* argNode = m_argList->AsArgList();
-                    m_edge                  = &argNode->gtOp1;
-                    m_argList               = argNode->Rest();
+                    GenTreeArgList* aggNode = m_argList->AsArgList();
+                    m_edge                  = &aggNode->gtOp1;
+                    m_argList               = aggNode->Rest();
                     return;
                 }
                 break;
@@ -8838,7 +8858,6 @@ void GenTreeUseEdgeIterator::MoveToNextPutArgStkUseEdge()
         }
     }
 }
-#endif // FEATURE_MULTIREG_ARGS
 
 //------------------------------------------------------------------------
 // GenTreeUseEdgeIterator::operator++:
@@ -8871,12 +8890,10 @@ GenTreeUseEdgeIterator& GenTreeUseEdgeIterator::operator++()
             MoveToNextSIMDUseEdge();
         }
 #endif
-#if FEATURE_MULTIREG_ARGS
-        else if (op == GT_PUTARG_STK)
+        else if ((op == GT_LIST) && (m_node->AsArgList()->IsAggregate()))
         {
-            MoveToNextPutArgStkUseEdge();
+            MoveToNextAggregateUseEdge();
         }
-#endif
         else
         {
             m_edge = GetNextUseEdge();
@@ -8896,9 +8913,9 @@ GenTreeUseEdgeIterator& GenTreeUseEdgeIterator::operator++()
     return *this;
 }
 
-GenTreeUseEdgeIterator GenTree::UseEdgesBegin(bool expandMultiRegArgs)
+GenTreeUseEdgeIterator GenTree::UseEdgesBegin()
 {
-    return GenTreeUseEdgeIterator(this, expandMultiRegArgs);
+    return GenTreeUseEdgeIterator(this);
 }
 
 GenTreeUseEdgeIterator GenTree::UseEdgesEnd()
@@ -8906,14 +8923,14 @@ GenTreeUseEdgeIterator GenTree::UseEdgesEnd()
     return GenTreeUseEdgeIterator();
 }
 
-IteratorPair<GenTreeUseEdgeIterator> GenTree::UseEdges(bool expandMultiRegArgs)
+IteratorPair<GenTreeUseEdgeIterator> GenTree::UseEdges()
 {
-    return MakeIteratorPair(UseEdgesBegin(expandMultiRegArgs), UseEdgesEnd());
+    return MakeIteratorPair(UseEdgesBegin(), UseEdgesEnd());
 }
 
-GenTreeOperandIterator GenTree::OperandsBegin(bool expandMultiRegArgs)
+GenTreeOperandIterator GenTree::OperandsBegin()
 {
-    return GenTreeOperandIterator(this, expandMultiRegArgs);
+    return GenTreeOperandIterator(this);
 }
 
 GenTreeOperandIterator GenTree::OperandsEnd()
@@ -8921,9 +8938,9 @@ GenTreeOperandIterator GenTree::OperandsEnd()
     return GenTreeOperandIterator();
 }
 
-IteratorPair<GenTreeOperandIterator> GenTree::Operands(bool expandMultiRegArgs)
+IteratorPair<GenTreeOperandIterator> GenTree::Operands()
 {
-    return MakeIteratorPair(OperandsBegin(expandMultiRegArgs), OperandsEnd());
+    return MakeIteratorPair(OperandsBegin(), OperandsEnd());
 }
 
 bool GenTree::Precedes(GenTree* other)
@@ -11132,8 +11149,7 @@ void Compiler::gtDispLIRNode(GenTree* node)
     // Visit operands
     IndentInfo operandArc         = IIArcTop;
     int        callArgNumber      = 0;
-    const bool expandMultiRegArgs = false;
-    for (GenTree* operand : node->Operands(expandMultiRegArgs))
+    for (GenTree* operand : node->Operands())
     {
         if (operand->IsArgPlaceHolderNode() || !operand->IsValue())
         {
@@ -15954,6 +15970,24 @@ bool GenTree::isCommutativeSIMDIntrinsic()
 #endif // FEATURE_SIMD
 
 //---------------------------------------------------------------------------------------
+// GenTreeArgList::Prepend:
+//    Prepends an element to a GT_LIST.
+// 
+// Arguments:
+//    compiler - The compiler context.
+//    element  - The element to prepend.
+//
+// Returns:
+//    The new head of the list.
+GenTreeArgList* GenTreeArgList::Prepend(Compiler* compiler, GenTree* element)
+{
+    GenTreeArgList* head = compiler->gtNewListNode(element, this);
+    head->gtFlags |= (gtFlags & GTF_LIST_AGGREGATE);
+    gtFlags &= ~GTF_LIST_AGGREGATE;
+    return head;
+}
+
+//---------------------------------------------------------------------------------------
 // InitializeStructReturnType:
 //    Initialize the Return Type Descriptor for a method that returns a struct type
 //
index d9b0c49..a61eb77 100644 (file)
@@ -940,6 +940,9 @@ public:
 
 #define GTF_ARRLEN_ARR_IDX 0x80000000 // GT_ARR_LENGTH -- Length which feeds into an array index expression
 
+#define GTF_LIST_AGGREGATE 0x80000000 // GT_LIST -- Indicates that this list should be treated as an
+                                      //            anonymous aggregate value (e.g. a multi-value argument).
+
 //----------------------------------------------------------------
 
 #define GTF_STMT_CMPADD 0x80000000  // GT_STMT    -- added by compiler
@@ -1006,6 +1009,11 @@ public:
             return gtType != TYP_VOID;
         }
 
+        if (gtOper == GT_LIST)
+        {
+            return (gtFlags & GTF_LIST_AGGREGATE) != 0;
+        }
+
         return true;
     }
 
@@ -1023,11 +1031,15 @@ public:
                 return IsNothingNode();
 
             case GT_ARGPLACE:
-            case GT_LIST:
-                // ARGPLACE and LIST nodes may not be present in a block's LIR sequence, but they may
+                // ARGPLACE nodes may not be present in a block's LIR sequence, but they may
                 // be present as children of an LIR node.
                 return (gtNext == nullptr) && (gtPrev == nullptr);
 
+            case GT_LIST:
+                // LIST nodes may only be present in an LIR sequence if they represent aggregates.
+                // They are always allowed, however, as children of an LIR node.
+                return ((gtFlags & GTF_LIST_AGGREGATE) != 0) || ((gtNext == nullptr) && (gtPrev == nullptr));
+
             case GT_ADDR:
             {
                 // ADDR ndoes may only be present in LIR if the location they refer to is not a
@@ -1407,6 +1419,11 @@ public:
         return OperIsSIMD(gtOper);
     }
 
+    bool OperIsAggregate()
+    {
+        return (gtOper == GT_LIST) && ((gtFlags & GTF_LIST_AGGREGATE) != 0);
+    }
+
     // Requires that "op" is an op= operator.  Returns
     // the corresponding "op".
     static genTreeOps OpAsgToOper(genTreeOps op);
@@ -1484,7 +1501,7 @@ public:
 
     // Given a tree node, if this node uses that node, return the use as an out parameter and return true.
     // Otherwise, return false.
-    bool TryGetUse(GenTree* def, GenTree*** use, bool expandMultiRegArgs = true);
+    bool TryGetUse(GenTree* def, GenTree*** use);
 
     // Get the parent of this node, and optionally capture the pointer to the child so that it can be modified.
     GenTreePtr gtGetParent(GenTreePtr** parentChildPtrPtr);
@@ -1807,22 +1824,20 @@ public:
 
     // Returns an iterator that will produce the use edge to each operand of this node. Differs
     // from the sequence of nodes produced by a loop over `GetChild` in its handling of call, phi,
-    // and block op nodes. If `expandMultiRegArgs` is true, an multi-reg args passed to a call
-    // will appear be expanded from their GT_LIST node into that node's contents.
-    GenTreeUseEdgeIterator GenTree::UseEdgesBegin(bool expandMultiRegArgs = true);
+    // and block op nodes.
+    GenTreeUseEdgeIterator GenTree::UseEdgesBegin();
     GenTreeUseEdgeIterator GenTree::UseEdgesEnd();
 
-    IteratorPair<GenTreeUseEdgeIterator> GenTree::UseEdges(bool expandMultiRegArgs = true);
+    IteratorPair<GenTreeUseEdgeIterator> GenTree::UseEdges();
 
     // Returns an iterator that will produce each operand of this node. Differs from the sequence
     // of nodes produced by a loop over `GetChild` in its handling of call, phi, and block op
-    // nodes. If `expandMultiRegArgs` is true, an multi-reg args passed to a call will appear
-    // be expanded from their GT_LIST node into that node's contents.
-    GenTreeOperandIterator OperandsBegin(bool expandMultiRegArgs = true);
+    // nodes.
+    GenTreeOperandIterator OperandsBegin();
     GenTreeOperandIterator OperandsEnd();
 
     // Returns a range that will produce the operands of this node in use order.
-    IteratorPair<GenTreeOperandIterator> Operands(bool expandMultiRegArgs = true);
+    IteratorPair<GenTreeOperandIterator> Operands();
 
     bool Precedes(GenTree* other);
 
@@ -1898,17 +1913,15 @@ public:
 class GenTreeUseEdgeIterator final
 {
     friend class GenTreeOperandIterator;
-    friend GenTreeUseEdgeIterator GenTree::UseEdgesBegin(bool expandMultiRegArgs);
+    friend GenTreeUseEdgeIterator GenTree::UseEdgesBegin();
     friend GenTreeUseEdgeIterator GenTree::UseEdgesEnd();
 
     GenTree*  m_node;
     GenTree** m_edge;
     GenTree*  m_argList;
-    GenTree*  m_multiRegArg;
-    bool      m_expandMultiRegArgs;
     int       m_state;
 
-    GenTreeUseEdgeIterator(GenTree* node, bool expandMultiRegArgs);
+    GenTreeUseEdgeIterator(GenTree* node);
 
     GenTree** GetNextUseEdge() const;
     void      MoveToNextCallUseEdge();
@@ -1916,9 +1929,7 @@ class GenTreeUseEdgeIterator final
 #ifdef FEATURE_SIMD
     void MoveToNextSIMDUseEdge();
 #endif
-#if FEATURE_MULTIREG_ARGS
-    void MoveToNextPutArgStkUseEdge();
-#endif
+    void MoveToNextAggregateUseEdge();
 
 public:
     GenTreeUseEdgeIterator();
@@ -1963,12 +1974,12 @@ public:
 // `GenTree::OperandsBegin` and `GenTree::OperandsEnd`.
 class GenTreeOperandIterator final
 {
-    friend GenTreeOperandIterator GenTree::OperandsBegin(bool expandMultiRegArgs);
+    friend GenTreeOperandIterator GenTree::OperandsBegin();
     friend GenTreeOperandIterator GenTree::OperandsEnd();
 
     GenTreeUseEdgeIterator m_useEdges;
 
-    GenTreeOperandIterator(GenTree* node, bool expandMultiRegArgs) : m_useEdges(node, expandMultiRegArgs)
+    GenTreeOperandIterator(GenTree* node) : m_useEdges(node)
     {
     }
 
@@ -2616,6 +2627,11 @@ struct GenTreeField : public GenTree
 // method names for the arguments.
 struct GenTreeArgList : public GenTreeOp
 {
+    bool IsAggregate() const
+    {
+        return (gtFlags & GTF_LIST_AGGREGATE) != 0;
+    }
+
     GenTreePtr& Current()
     {
         return gtOp1;
@@ -2648,6 +2664,8 @@ struct GenTreeArgList : public GenTreeOp
             gtFlags |= rest->gtFlags & GTF_ALL_EFFECT;
         }
     }
+
+    GenTreeArgList* Prepend(Compiler* compiler, GenTree* element);
 };
 
 // There was quite a bit of confusion in the code base about which of gtOp1 and gtOp2 was the
index 59e59b9..6b5f940 100644 (file)
@@ -176,7 +176,7 @@ GTNODE(SIMD       , "simd"       ,0,GTK_BINOP|GTK_EXOP)   // SIMD functions/oper
 
 GTNODE(JTRUE      , "jmpTrue"    ,0,GTK_UNOP|GTK_NOVALUE)
 
-GTNODE(LIST       , "<list>"     ,0,GTK_BINOP|GTK_NOVALUE)
+GTNODE(LIST       , "<list>"     ,0,GTK_BINOP)
 
 //-----------------------------------------------------------------------------
 //  Other nodes that have special structure:
index a6f392a..7fd729d 100644 (file)
@@ -1264,7 +1264,6 @@ LIR::ReadOnlyRange LIR::Range::GetMarkedRange(unsigned  markCount,
             for (GenTree* operand : firstNode->Operands())
             {
                 // Do not mark nodes that do not appear in the execution order
-                assert(operand->OperGet() != GT_LIST);
                 if (operand->OperGet() == GT_ARGPLACE)
                 {
                     continue;
index ae94ac0..83c815b 100644 (file)
@@ -819,7 +819,9 @@ GenTreePtr Lowering::NewPutArg(GenTreeCall* call, GenTreePtr arg, fgArgTabEntryP
                 // clang-format on
 
                 assert(arg->OperGet() == GT_LIST);
+
                 GenTreeArgList* argListPtr = arg->AsArgList();
+                assert(argListPtr->IsAggregate());
 
                 for (unsigned ctr = 0; argListPtr != nullptr; argListPtr = argListPtr->Rest(), ctr++)
                 {
@@ -850,7 +852,9 @@ GenTreePtr Lowering::NewPutArg(GenTreeCall* call, GenTreePtr arg, fgArgTabEntryP
         if ((info->numRegs > 1) && (arg->OperGet() == GT_LIST))
         {
             assert(arg->OperGet() == GT_LIST);
+
             GenTreeArgList* argListPtr = arg->AsArgList();
+            assert(argListPtr->IsAggregate());
 
             for (unsigned ctr = 0; argListPtr != nullptr; argListPtr = argListPtr->Rest(), ctr++)
             {
@@ -1060,7 +1064,6 @@ void Lowering::LowerArg(GenTreeCall* call, GenTreePtr* ppArg)
         // If an extra node is returned, splice it in the right place in the tree.
         if (arg != putArg)
         {
-            // putArg and arg are equals if arg is GT_LIST (a list of multiple LCL_FLDs to be passed in registers.)
             ReplaceArgWithPutArgOrCopy(ppArg, putArg);
         }
     }
@@ -3726,9 +3729,14 @@ void Lowering::CheckCallArg(GenTree* arg)
 #endif
 
         case GT_LIST:
-            for (GenTreeArgList* list = arg->AsArgList(); list != nullptr; list = list->Rest())
             {
-                assert(list->Current()->OperIsPutArg());
+                GenTreeArgList* list = arg->AsArgList();
+                assert(list->IsAggregate());
+
+                for (; list != nullptr; list = list->Rest())
+                {
+                    assert(list->Current()->OperIsPutArg());
+                }
             }
             break;
 
index 1db8524..0f18487 100644 (file)
@@ -3198,7 +3198,7 @@ static int ComputeOperandDstCount(GenTree* operand)
                operand->OperIsCompare());
         return 0;
     }
-    else if (operand->OperIsStore() || operand->TypeGet() == TYP_VOID)
+    else if (!operand->OperIsAggregate() && (operand->OperIsStore() || operand->TypeGet() == TYP_VOID))
     {
         // Stores and void-typed operands may be encountered when processing call nodes, which contain
         // pointers to argument setup stores.
@@ -3206,10 +3206,10 @@ static int ComputeOperandDstCount(GenTree* operand)
     }
     else
     {
-        // If a non-void-types operand is not an unsued value and does not have source registers, that
-        // argument is contained within its parent and produces `sum(operand_dst_count)` registers.
+        // If an aggregate or non-void-typed operand is not an unsued value and does not have source registers,
+        // that argument is contained within its parent and produces `sum(operand_dst_count)` registers.
         int dstCount = 0;
-        for (GenTree* op : operand->Operands(true))
+        for (GenTree* op : operand->Operands())
         {
             dstCount += ComputeOperandDstCount(op);
         }
@@ -3234,7 +3234,7 @@ static int ComputeOperandDstCount(GenTree* operand)
 static int ComputeAvailableSrcCount(GenTree* node)
 {
     int numSources = 0;
-    for (GenTree* operand : node->Operands(true))
+    for (GenTree* operand : node->Operands())
     {
         numSources += ComputeOperandDstCount(operand);
     }
@@ -3253,11 +3253,9 @@ void LinearScan::buildRefPositionsForNode(GenTree*                  tree,
     assert(!isRegPairType(tree->TypeGet()));
 #endif // _TARGET_ARM_
 
-    // The tree traversal doesn't visit GT_LIST or GT_ARGPLACE nodes
-    if (tree->OperGet() == GT_LIST || tree->OperGet() == GT_ARGPLACE)
-    {
-        return;
-    }
+    // The LIR traversal doesn't visit non-aggregate GT_LIST or GT_ARGPLACE nodes
+    assert(tree->OperGet() != GT_ARGPLACE);
+    assert((tree->OperGet() != GT_LIST) || tree->AsArgList()->IsAggregate());
 
     // These nodes are eliminated by the Rationalizer.
     if (tree->OperGet() == GT_CLS_VAR)
@@ -3410,7 +3408,7 @@ void LinearScan::buildRefPositionsForNode(GenTree*                  tree,
             {
                 // Get the location info for the register defined by the first operand.
                 LocationInfoList operandDefs;
-                bool found = operandToLocationInfoMap.TryGetValue(*(tree->OperandsBegin(true)), &operandDefs);
+                bool found = operandToLocationInfoMap.TryGetValue(*(tree->OperandsBegin()), &operandDefs);
                 assert(found);
 
                 // Since we only expect to consume one register, we should only have a single register to
@@ -3514,7 +3512,7 @@ void LinearScan::buildRefPositionsForNode(GenTree*                  tree,
 
         // Get the register information for the first operand of the node.
         LocationInfoList operandDefs;
-        bool             found = operandToLocationInfoMap.TryGetValue(*(tree->OperandsBegin(true)), &operandDefs);
+        bool             found = operandToLocationInfoMap.TryGetValue(*(tree->OperandsBegin()), &operandDefs);
         assert(found);
 
         // Preference the destination to the interval of the first register defined by the first operand.
@@ -3531,7 +3529,7 @@ void LinearScan::buildRefPositionsForNode(GenTree*                  tree,
     int internalCount = buildInternalRegisterDefsForNode(tree, currentLoc, internalRefs);
 
     // pop all ref'd tree temps
-    GenTreeOperandIterator iterator = tree->OperandsBegin(true);
+    GenTreeOperandIterator iterator = tree->OperandsBegin();
 
     // `operandDefs` holds the list of `LocationInfo` values for the registers defined by the current
     // operand. `operandDefsIterator` points to the current `LocationInfo` value in `operandDefs`.
@@ -3796,11 +3794,11 @@ void LinearScan::buildRefPositionsForNode(GenTree*                  tree,
 #endif // FEATURE_PARTIAL_SIMD_CALLEE_SAVE
 
     bool isContainedNode =
-        !noAdd && consume == 0 && produce == 0 && tree->TypeGet() != TYP_VOID && !tree->OperIsStore();
+        !noAdd && consume == 0 && produce == 0 && (tree->OperIsAggregate() || (tree->TypeGet() != TYP_VOID && !tree->OperIsStore()));
     if (isContainedNode)
     {
         // Contained nodes map to the concatenated lists of their operands.
-        for (GenTree* op : tree->Operands(true))
+        for (GenTree* op : tree->Operands())
         {
             if (!op->gtLsraInfo.definesAnyRegisters)
             {
index e8c3463..2e06f1c 100755 (executable)
@@ -4387,9 +4387,9 @@ void Compiler::fgMorphSystemVStructArgs(GenTreeCall* call, bool hasStructArgumen
                                                                                 .eightByteClassifications[1],
                                                                             fgEntryPtr->structDesc.eightByteSizes[1]),
                                           lclCommon->gtLclNum, fgEntryPtr->structDesc.eightByteOffsets[1]);
-                        // Note this should actually be: secondNode = gtNewArgList(newLclField)
-                        GenTreeArgList* secondNode = gtNewListNode(newLclField, nullptr);
-                        secondNode->gtType         = originalType; // Preserve the type. It is a special case.
+
+                        GenTreeArgList* aggregate  = gtNewAggregate(newLclField);
+                        aggregate->gtType          = originalType; // Preserve the type. It is a special case.
                         newLclField->gtFieldSeq    = FieldSeqStore::NotAField();
 
                         // First field
@@ -4397,7 +4397,7 @@ void Compiler::fgMorphSystemVStructArgs(GenTreeCall* call, bool hasStructArgumen
                         arg->gtType =
                             GetTypeFromClassificationAndSizes(fgEntryPtr->structDesc.eightByteClassifications[0],
                                                               fgEntryPtr->structDesc.eightByteSizes[0]);
-                        arg         = gtNewListNode(arg, secondNode);
+                        arg         = aggregate->Prepend(this, arg);
                         arg->gtType = type; // Preserve the type. It is a special case.
                     }
                     else
@@ -4814,7 +4814,7 @@ GenTreePtr Compiler::fgMorphMultiregStructArg(GenTreePtr arg, fgArgTabEntryPtr f
                     //    replace the existing LDOBJ(ADDR(LCLVAR))
                     //    with a LIST(LCLVAR-LO, LIST(LCLVAR-HI, nullptr))
                     //
-                    newArg = gtNewListNode(loLclVar, gtNewArgList(hiLclVar));
+                    newArg = gtNewAggregate(hiLclVar)->Prepend(this, loLclVar);
                 }
             }
         }
@@ -4895,11 +4895,11 @@ GenTreePtr Compiler::fgMorphMultiregStructArg(GenTreePtr arg, fgArgTabEntryPtr f
                 GenTreePtr nextLclFld = gtNewLclFldNode(varNum, type[inx], offset);
                 if (newArg == nullptr)
                 {
-                    newArg = gtNewArgList(nextLclFld);
+                    newArg = gtNewAggregate(nextLclFld);
                 }
                 else
                 {
-                    newArg = gtNewListNode(nextLclFld, newArg);
+                    newArg = newArg->Prepend(this, nextLclFld);
                 }
             }
         }
@@ -4938,26 +4938,24 @@ GenTreePtr Compiler::fgMorphMultiregStructArg(GenTreePtr arg, fgArgTabEntryPtr f
                 GenTreePtr curItem = gtNewOperNode(GT_IND, type[inx], curAddr);
                 if (newArg == nullptr)
                 {
-                    newArg = gtNewArgList(curItem);
+                    newArg = gtNewAggregate(curItem);
                 }
                 else
                 {
-                    newArg = gtNewListNode(curItem, newArg);
+                    newArg = newArg->Prepend(this, curItem);
                 }
             }
         }
     }
 
+#ifdef DEBUG
     // If we reach here we should have set newArg to something
     if (newArg == nullptr)
     {
-#ifdef DEBUG
         gtDispTree(argValue);
-#endif
         assert(!"Missing case in fgMorphMultiregStructArg");
     }
 
-#ifdef DEBUG
     if (verbose)
     {
         printf("fgMorphMultiregStructArg created tree:\n");
index d23d877..f57d8c0 100644 (file)
@@ -865,16 +865,22 @@ Compiler::fgWalkResult Rationalizer::RewriteNode(GenTree** useEdge, ArrayStack<G
 
     // First, remove any preceeding GT_LIST nodes, which are not otherwise visited by the tree walk.
     //
-    // NOTE: GT_LIST nodes that are used by block ops and phi nodes will in fact be visited.
-    for (GenTree* prev = node->gtPrev; prev != nullptr && prev->OperGet() == GT_LIST; prev = node->gtPrev)
+    // NOTE: GT_LIST nodes that are used as aggregates, by block ops, and by phi nodes will in fact be visited.
+    for (GenTree* prev = node->gtPrev;
+        prev != nullptr && prev->OperGet() == GT_LIST && !(prev->AsArgList()->IsAggregate());
+        prev = node->gtPrev)
     {
         BlockRange().Remove(prev);
     }
 
-    // In addition, remove the current node if it is a GT_LIST node.
-    if ((*useEdge)->OperGet() == GT_LIST)
+    // In addition, remove the current node if it is a GT_LIST node that is not an aggregate.
+    if (node->OperGet() == GT_LIST)
     {
-        BlockRange().Remove(*useEdge);
+        GenTreeArgList* list = node->AsArgList();
+        if (!list->IsAggregate())
+        {
+            BlockRange().Remove(list);
+        }
         return Compiler::WALK_CONTINUE;
     }
 
index e0511aa..15c0d17 100644 (file)
@@ -55528,7 +55528,7 @@ RelativePath=JIT\Performance\CodeQuality\Roslyn\CscBench\CscBench.cmd
 WorkingDir=JIT\Performance\CodeQuality\Roslyn\CscBench
 Expected=0
 MaxAllowedDurationSeconds=600
-Categories=Pri0;EXPECTED_FAIL;ISSUE_6893;LONG_RUNNING
+Categories=Pri0;EXPECTED_PASS;LONG_RUNNING
 HostStyle=0
 [SciMark.cmd_8027]
 RelativePath=JIT\Performance\CodeQuality\SciMark\SciMark\SciMark.cmd
@@ -67652,7 +67652,7 @@ RelativePath=managed\Compilation\Compilation\Compilation.cmd
 WorkingDir=managed\Compilation\Compilation
 Expected=0
 MaxAllowedDurationSeconds=800
-Categories=Pri0;RT;EXPECTED_FAIL;ISSUE_6893;NATIVE_INTEROP;LONG_RUNNING
+Categories=Pri0;RT;EXPECTED_PASS;NATIVE_INTEROP;LONG_RUNNING
 HostStyle=0
 [generics.cmd_9787]
 RelativePath=readytorun\generics\generics.cmd