Stop using LIST nodes for CALL arg lists (dotnet/coreclr#26392)
authormikedn <onemihaid@hotmail.com>
Mon, 9 Sep 2019 17:09:17 +0000 (20:09 +0300)
committerCarol Eidt <carol.eidt@microsoft.com>
Mon, 9 Sep 2019 17:09:17 +0000 (10:09 -0700)
* Stop using GT_LIST in GenTreeCall

* Clarify optAssertionGenJtrue code

* Cleanup optCreateAssertion

* Cleanup AddHiddenArgument

* Cleanup impInlineIsGuaranteedThisDerefBeforeAnySideEffects

Commit migrated from https://github.com/dotnet/coreclr/commit/667222e7cee75c0473e2e6b3a9c89dd5043ff176

22 files changed:
src/coreclr/src/jit/assertionprop.cpp
src/coreclr/src/jit/codegenarmarch.cpp
src/coreclr/src/jit/codegenxarch.cpp
src/coreclr/src/jit/compiler.cpp
src/coreclr/src/jit/compiler.h
src/coreclr/src/jit/compiler.hpp
src/coreclr/src/jit/decomposelongs.cpp
src/coreclr/src/jit/flowgraph.cpp
src/coreclr/src/jit/gentree.cpp
src/coreclr/src/jit/gentree.h
src/coreclr/src/jit/gschecks.cpp
src/coreclr/src/jit/importer.cpp
src/coreclr/src/jit/indirectcalltransformer.cpp
src/coreclr/src/jit/lower.cpp
src/coreclr/src/jit/lowerxarch.cpp
src/coreclr/src/jit/lsraarmarch.cpp
src/coreclr/src/jit/lsraxarch.cpp
src/coreclr/src/jit/morph.cpp
src/coreclr/src/jit/objectalloc.cpp
src/coreclr/src/jit/rationalize.cpp
src/coreclr/src/jit/rationalize.h
src/coreclr/src/jit/valuenum.cpp

index e354248..d9759e4 100644 (file)
@@ -802,47 +802,37 @@ Compiler::AssertionDsc* Compiler::optGetAssertion(AssertionIndex assertIndex)
     return assertion;
 }
 
-/*****************************************************************************
- *
- * A simple helper routine so not all callers need to supply a AssertionDsc*
- * if they don't care about it. Refer overloaded method optCreateAssertion.
- *
- */
-AssertionIndex Compiler::optCreateAssertion(GenTree* op1, GenTree* op2, optAssertionKind assertionKind)
-{
-    AssertionDsc assertionDsc;
-    return optCreateAssertion(op1, op2, assertionKind, &assertionDsc);
-}
-
-/*****************************************************************************
- *
- *  We attempt to create the following assertion:
- *
- *     op1 assertionKind op2
- *
- *  If we can create the assertion then update 'assertion' if we are
- *  unsuccessful assertion->assertionKind will be OAK_INVALID. If we are
- *  successful in creating the assertion we call optAddAssertion which adds
- *  the assertion to our assertion table.
- *
- *  If we are able to create the assertion the return value is the
- *  assertionIndex for this assertion otherwise the return value is
- *  NO_ASSERTION_INDEX and we could not create the assertion.
- *
- */
+//------------------------------------------------------------------------
+// optCreateAssertion: Create an (op1 assertionKind op2) assertion.
+//
+// Arguments:
+//    op1 - the first assertion operand
+//    op2 - the second assertion operand
+//    assertionKind - the assertion kind
+//    helperCallArgs - when true this indicates that the assertion operands
+//                     are the arguments of a type cast helper call such as
+//                     CORINFO_HELP_ISINSTANCEOFCLASS
+// Return Value:
+//    The new assertion index or NO_ASSERTION_INDEX if a new assertion
+//    was not created.
+//
+// Notes:
+//    Assertion creation may fail either because the provided assertion
+//    operands aren't supported or because the assertion table is full.
+//
 AssertionIndex Compiler::optCreateAssertion(GenTree*         op1,
                                             GenTree*         op2,
                                             optAssertionKind assertionKind,
-                                            AssertionDsc*    assertion)
+                                            bool             helperCallArgs)
 {
-    memset(assertion, 0, sizeof(AssertionDsc));
-    //
-    // If we cannot create an assertion using op1 and op2 then the assertionKind
-    // must be OAK_INVALID, so we initialize it to OAK_INVALID and only change it
-    // to a valid assertion when everything is good.
-    //
-    assertion->assertionKind = OAK_INVALID;
-    bool      haveArgs       = false;
+    assert((op1 != nullptr) && !op1->OperIs(GT_LIST));
+    assert((op2 == nullptr) || !op2->OperIs(GT_LIST));
+    assert(!helperCallArgs || (op2 != nullptr));
+
+    AssertionDsc assertion;
+    memset(&assertion, 0, sizeof(AssertionDsc));
+    assert(assertion.assertionKind == OAK_INVALID);
+
     var_types toType;
 
     if (op1->gtOper == GT_ARR_BOUNDS_CHECK)
@@ -850,34 +840,19 @@ AssertionIndex Compiler::optCreateAssertion(GenTree*         op1,
         if (assertionKind == OAK_NO_THROW)
         {
             GenTreeBoundsChk* arrBndsChk = op1->AsBoundsChk();
-            assertion->assertionKind     = assertionKind;
-            assertion->op1.kind          = O1K_ARR_BND;
-            assertion->op1.bnd.vnIdx     = vnStore->VNConservativeNormalValue(arrBndsChk->gtIndex->gtVNPair);
-            assertion->op1.bnd.vnLen     = vnStore->VNConservativeNormalValue(arrBndsChk->gtArrLen->gtVNPair);
+            assertion.assertionKind      = assertionKind;
+            assertion.op1.kind           = O1K_ARR_BND;
+            assertion.op1.bnd.vnIdx      = vnStore->VNConservativeNormalValue(arrBndsChk->gtIndex->gtVNPair);
+            assertion.op1.bnd.vnLen      = vnStore->VNConservativeNormalValue(arrBndsChk->gtArrLen->gtVNPair);
             goto DONE_ASSERTION;
         }
     }
 
     //
-    // Did we receive Helper call args?
-    //
-    if (op1->gtOper == GT_LIST)
-    {
-        if (op2->gtOper != GT_LIST)
-        {
-            goto DONE_ASSERTION; // Don't make an assertion
-        }
-        op1      = op1->gtOp.gtOp1;
-        op2      = op2->gtOp.gtOp1;
-        haveArgs = true;
-    }
-
-    //
     // Are we trying to make a non-null assertion?
     //
     if (op2 == nullptr)
     {
-        assert(haveArgs == false);
         //
         // Must an OAK_NOT_EQUAL assertion
         //
@@ -959,7 +934,7 @@ AssertionIndex Compiler::optCreateAssertion(GenTree*         op1,
                 goto DONE_ASSERTION; // Don't make an assertion
             }
 
-            assertion->op1.kind = O1K_VALUE_NUMBER;
+            assertion.op1.kind = O1K_VALUE_NUMBER;
         }
         else
         {
@@ -969,21 +944,21 @@ AssertionIndex Compiler::optCreateAssertion(GenTree*         op1,
                 goto DONE_ASSERTION; // Don't make an assertion
             }
 
-            assertion->op1.kind       = O1K_LCLVAR;
-            assertion->op1.lcl.lclNum = lclNum;
-            assertion->op1.lcl.ssaNum = op1->AsLclVarCommon()->GetSsaNum();
-            vn                        = vnStore->VNConservativeNormalValue(op1->gtVNPair);
+            assertion.op1.kind       = O1K_LCLVAR;
+            assertion.op1.lcl.lclNum = lclNum;
+            assertion.op1.lcl.ssaNum = op1->AsLclVarCommon()->GetSsaNum();
+            vn                       = vnStore->VNConservativeNormalValue(op1->gtVNPair);
         }
 
-        assertion->op1.vn           = vn;
-        assertion->assertionKind    = assertionKind;
-        assertion->op2.kind         = O2K_CONST_INT;
-        assertion->op2.vn           = ValueNumStore::VNForNull();
-        assertion->op2.u1.iconVal   = 0;
-        assertion->op2.u1.iconFlags = 0;
+        assertion.op1.vn           = vn;
+        assertion.assertionKind    = assertionKind;
+        assertion.op2.kind         = O2K_CONST_INT;
+        assertion.op2.vn           = ValueNumStore::VNForNull();
+        assertion.op2.u1.iconVal   = 0;
+        assertion.op2.u1.iconFlags = 0;
 #ifdef _TARGET_64BIT_
-        assertion->op2.u1.iconFlags |= 1; // Signify that this is really TYP_LONG
-#endif                                    // _TARGET_64BIT_
+        assertion.op2.u1.iconFlags |= 1; // Signify that this is really TYP_LONG
+#endif                                   // _TARGET_64BIT_
     }
     //
     // Are we making an assertion about a local variable?
@@ -1000,7 +975,7 @@ AssertionIndex Compiler::optCreateAssertion(GenTree*         op1,
             goto DONE_ASSERTION; // Don't make an assertion
         }
 
-        if (haveArgs)
+        if (helperCallArgs)
         {
             //
             // Must either be an OAK_EQUAL or an OAK_NOT_EQUAL assertion
@@ -1012,12 +987,12 @@ AssertionIndex Compiler::optCreateAssertion(GenTree*         op1,
 
             if (op2->gtOper == GT_IND)
             {
-                op2                 = op2->gtOp.gtOp1;
-                assertion->op2.kind = O2K_IND_CNS_INT;
+                op2                = op2->gtOp.gtOp1;
+                assertion.op2.kind = O2K_IND_CNS_INT;
             }
             else
             {
-                assertion->op2.kind = O2K_CONST_INT;
+                assertion.op2.kind = O2K_CONST_INT;
             }
 
             if (op2->gtOper != GT_CNS_INT)
@@ -1031,20 +1006,20 @@ AssertionIndex Compiler::optCreateAssertion(GenTree*         op1,
             //          where a class can be sealed, but they don't behave as exact types because casts to
             //          non-base types sometimes still succeed.
             //
-            assertion->op1.kind         = O1K_SUBTYPE;
-            assertion->op1.lcl.lclNum   = lclNum;
-            assertion->op1.vn           = vnStore->VNConservativeNormalValue(op1->gtVNPair);
-            assertion->op1.lcl.ssaNum   = op1->AsLclVarCommon()->GetSsaNum();
-            assertion->op2.u1.iconVal   = op2->gtIntCon.gtIconVal;
-            assertion->op2.vn           = vnStore->VNConservativeNormalValue(op2->gtVNPair);
-            assertion->op2.u1.iconFlags = op2->GetIconHandleFlag();
+            assertion.op1.kind         = O1K_SUBTYPE;
+            assertion.op1.lcl.lclNum   = lclNum;
+            assertion.op1.vn           = vnStore->VNConservativeNormalValue(op1->gtVNPair);
+            assertion.op1.lcl.ssaNum   = op1->AsLclVarCommon()->GetSsaNum();
+            assertion.op2.u1.iconVal   = op2->gtIntCon.gtIconVal;
+            assertion.op2.vn           = vnStore->VNConservativeNormalValue(op2->gtVNPair);
+            assertion.op2.u1.iconFlags = op2->GetIconHandleFlag();
 
             //
             // Ok everything has been set and the assertion looks good
             //
-            assertion->assertionKind = assertionKind;
+            assertion.assertionKind = assertionKind;
         }
-        else // !haveArgs
+        else // !helperCallArgs
         {
             /* Skip over a GT_COMMA node(s), if necessary */
             while (op2->gtOper == GT_COMMA)
@@ -1052,10 +1027,10 @@ AssertionIndex Compiler::optCreateAssertion(GenTree*         op1,
                 op2 = op2->gtOp.gtOp2;
             }
 
-            assertion->op1.kind       = O1K_LCLVAR;
-            assertion->op1.lcl.lclNum = lclNum;
-            assertion->op1.vn         = vnStore->VNConservativeNormalValue(op1->gtVNPair);
-            assertion->op1.lcl.ssaNum = op1->AsLclVarCommon()->GetSsaNum();
+            assertion.op1.kind       = O1K_LCLVAR;
+            assertion.op1.lcl.lclNum = lclNum;
+            assertion.op1.vn         = vnStore->VNConservativeNormalValue(op1->gtVNPair);
+            assertion.op1.lcl.ssaNum = op1->AsLclVarCommon()->GetSsaNum();
 
             switch (op2->gtOper)
             {
@@ -1099,9 +1074,9 @@ AssertionIndex Compiler::optCreateAssertion(GenTree*         op1,
                         goto DONE_ASSERTION; // Don't make an assertion
                     }
 
-                    assertion->op2.kind    = op2Kind;
-                    assertion->op2.lconVal = 0;
-                    assertion->op2.vn      = vnStore->VNConservativeNormalValue(op2->gtVNPair);
+                    assertion.op2.kind    = op2Kind;
+                    assertion.op2.lconVal = 0;
+                    assertion.op2.vn      = vnStore->VNConservativeNormalValue(op2->gtVNPair);
 
                     if (op2->gtOper == GT_CNS_INT)
                     {
@@ -1119,18 +1094,18 @@ AssertionIndex Compiler::optCreateAssertion(GenTree*         op1,
                             goto DONE_ASSERTION; // Don't make an assertion
                         }
 #endif // _TARGET_ARM_
-                        assertion->op2.u1.iconVal   = op2->gtIntCon.gtIconVal;
-                        assertion->op2.u1.iconFlags = op2->GetIconHandleFlag();
+                        assertion.op2.u1.iconVal   = op2->gtIntCon.gtIconVal;
+                        assertion.op2.u1.iconFlags = op2->GetIconHandleFlag();
 #ifdef _TARGET_64BIT_
                         if (op2->TypeGet() == TYP_LONG || op2->TypeGet() == TYP_BYREF)
                         {
-                            assertion->op2.u1.iconFlags |= 1; // Signify that this is really TYP_LONG
+                            assertion.op2.u1.iconFlags |= 1; // Signify that this is really TYP_LONG
                         }
 #endif // _TARGET_64BIT_
                     }
                     else if (op2->gtOper == GT_CNS_LNG)
                     {
-                        assertion->op2.lconVal = op2->gtLngCon.gtLconVal;
+                        assertion.op2.lconVal = op2->gtLngCon.gtLconVal;
                     }
                     else
                     {
@@ -1140,13 +1115,13 @@ AssertionIndex Compiler::optCreateAssertion(GenTree*         op1,
                         {
                             goto DONE_ASSERTION; // Don't make an assertion
                         }
-                        assertion->op2.dconVal = op2->gtDblCon.gtDconVal;
+                        assertion.op2.dconVal = op2->gtDblCon.gtDconVal;
                     }
 
                     //
                     // Ok everything has been set and the assertion looks good
                     //
-                    assertion->assertionKind = assertionKind;
+                    assertion.assertionKind = assertionKind;
                 }
                 break;
 
@@ -1192,15 +1167,15 @@ AssertionIndex Compiler::optCreateAssertion(GenTree*         op1,
                         goto DONE_ASSERTION; // Don't make an assertion
                     }
 
-                    assertion->op2.kind       = O2K_LCLVAR_COPY;
-                    assertion->op2.lcl.lclNum = lclNum2;
-                    assertion->op2.vn         = vnStore->VNConservativeNormalValue(op2->gtVNPair);
-                    assertion->op2.lcl.ssaNum = op2->AsLclVarCommon()->GetSsaNum();
+                    assertion.op2.kind       = O2K_LCLVAR_COPY;
+                    assertion.op2.lcl.lclNum = lclNum2;
+                    assertion.op2.vn         = vnStore->VNConservativeNormalValue(op2->gtVNPair);
+                    assertion.op2.lcl.ssaNum = op2->AsLclVarCommon()->GetSsaNum();
 
                     //
                     // Ok everything has been set and the assertion looks good
                     //
-                    assertion->assertionKind = assertionKind;
+                    assertion.assertionKind = assertionKind;
                 }
                 break;
 
@@ -1277,19 +1252,19 @@ AssertionIndex Compiler::optCreateAssertion(GenTree*         op1,
                         case TYP_UINT:
                         case TYP_INT:
 #endif // _TARGET_64BIT_
-                            assertion->op2.u2.loBound = AssertionDsc::GetLowerBoundForIntegralType(toType);
-                            assertion->op2.u2.hiBound = AssertionDsc::GetUpperBoundForIntegralType(toType);
+                            assertion.op2.u2.loBound = AssertionDsc::GetLowerBoundForIntegralType(toType);
+                            assertion.op2.u2.hiBound = AssertionDsc::GetUpperBoundForIntegralType(toType);
                             break;
 
                         default:
                             goto DONE_ASSERTION; // Don't make an assertion
                     }
-                    assertion->op2.kind      = O2K_SUBRANGE;
-                    assertion->assertionKind = OAK_SUBRANGE;
+                    assertion.op2.kind      = O2K_SUBRANGE;
+                    assertion.assertionKind = OAK_SUBRANGE;
                 }
                 break;
             }
-        } // else // !haveArgs
+        } // else // !helperCallArgs
     }     // if (op1->gtOper == GT_LCL_VAR)
 
     //
@@ -1320,15 +1295,15 @@ AssertionIndex Compiler::optCreateAssertion(GenTree*         op1,
                 goto DONE_ASSERTION; // Don't make an assertion
             }
 
-            assertion->op1.kind       = O1K_EXACT_TYPE;
-            assertion->op1.lcl.lclNum = lclNum;
-            assertion->op1.vn         = vnStore->VNConservativeNormalValue(op1->gtVNPair);
-            assertion->op1.lcl.ssaNum = op1->AsLclVarCommon()->GetSsaNum();
+            assertion.op1.kind       = O1K_EXACT_TYPE;
+            assertion.op1.lcl.lclNum = lclNum;
+            assertion.op1.vn         = vnStore->VNConservativeNormalValue(op1->gtVNPair);
+            assertion.op1.lcl.ssaNum = op1->AsLclVarCommon()->GetSsaNum();
 
-            assert(assertion->op1.lcl.ssaNum == SsaConfig::RESERVED_SSA_NUM ||
-                   assertion->op1.vn ==
-                       vnStore->VNConservativeNormalValue(
-                           lvaTable[lclNum].GetPerSsaData(assertion->op1.lcl.ssaNum)->m_vnPair));
+            assert((assertion.op1.lcl.ssaNum == SsaConfig::RESERVED_SSA_NUM) ||
+                   (assertion.op1.vn ==
+                    vnStore->VNConservativeNormalValue(
+                        lvaTable[lclNum].GetPerSsaData(assertion.op1.lcl.ssaNum)->m_vnPair)));
 
             ssize_t  cnsValue  = 0;
             unsigned iconFlags = 0;
@@ -1340,36 +1315,36 @@ AssertionIndex Compiler::optCreateAssertion(GenTree*         op1,
                     goto DONE_ASSERTION; // Don't make an assertion
                 }
 
-                assertion->assertionKind  = assertionKind;
-                assertion->op2.kind       = O2K_IND_CNS_INT;
-                assertion->op2.u1.iconVal = cnsValue;
-                assertion->op2.vn         = vnStore->VNConservativeNormalValue(op2->gtOp.gtOp1->gtVNPair);
+                assertion.assertionKind  = assertionKind;
+                assertion.op2.kind       = O2K_IND_CNS_INT;
+                assertion.op2.u1.iconVal = cnsValue;
+                assertion.op2.vn         = vnStore->VNConservativeNormalValue(op2->gtOp.gtOp1->gtVNPair);
 
                 /* iconFlags should only contain bits in GTF_ICON_HDL_MASK */
                 assert((iconFlags & ~GTF_ICON_HDL_MASK) == 0);
-                assertion->op2.u1.iconFlags = iconFlags;
+                assertion.op2.u1.iconFlags = iconFlags;
 #ifdef _TARGET_64BIT_
                 if (op2->gtOp.gtOp1->TypeGet() == TYP_LONG)
                 {
-                    assertion->op2.u1.iconFlags |= 1; // Signify that this is really TYP_LONG
+                    assertion.op2.u1.iconFlags |= 1; // Signify that this is really TYP_LONG
                 }
 #endif // _TARGET_64BIT_
             }
             // JIT case
             else if (optIsTreeKnownIntValue(!optLocalAssertionProp, op2, &cnsValue, &iconFlags))
             {
-                assertion->assertionKind  = assertionKind;
-                assertion->op2.kind       = O2K_IND_CNS_INT;
-                assertion->op2.u1.iconVal = cnsValue;
-                assertion->op2.vn         = vnStore->VNConservativeNormalValue(op2->gtVNPair);
+                assertion.assertionKind  = assertionKind;
+                assertion.op2.kind       = O2K_IND_CNS_INT;
+                assertion.op2.u1.iconVal = cnsValue;
+                assertion.op2.vn         = vnStore->VNConservativeNormalValue(op2->gtVNPair);
 
                 /* iconFlags should only contain bits in GTF_ICON_HDL_MASK */
                 assert((iconFlags & ~GTF_ICON_HDL_MASK) == 0);
-                assertion->op2.u1.iconFlags = iconFlags;
+                assertion.op2.u1.iconFlags = iconFlags;
 #ifdef _TARGET_64BIT_
                 if (op2->TypeGet() == TYP_LONG)
                 {
-                    assertion->op2.u1.iconFlags |= 1; // Signify that this is really TYP_LONG
+                    assertion.op2.u1.iconFlags |= 1; // Signify that this is really TYP_LONG
                 }
 #endif // _TARGET_64BIT_
             }
@@ -1381,30 +1356,30 @@ AssertionIndex Compiler::optCreateAssertion(GenTree*         op1,
     }
 
 DONE_ASSERTION:
-    if (assertion->assertionKind == OAK_INVALID)
+    if (assertion.assertionKind == OAK_INVALID)
     {
         return NO_ASSERTION_INDEX;
     }
 
     if (!optLocalAssertionProp)
     {
-        if ((assertion->op1.vn == ValueNumStore::NoVN) || (assertion->op2.vn == ValueNumStore::NoVN) ||
-            (assertion->op1.vn == ValueNumStore::VNForVoid()) || (assertion->op2.vn == ValueNumStore::VNForVoid()))
+        if ((assertion.op1.vn == ValueNumStore::NoVN) || (assertion.op2.vn == ValueNumStore::NoVN) ||
+            (assertion.op1.vn == ValueNumStore::VNForVoid()) || (assertion.op2.vn == ValueNumStore::VNForVoid()))
         {
             return NO_ASSERTION_INDEX;
         }
 
         // TODO: only copy assertions rely on valid SSA number so we could generate more assertions here
-        if ((assertion->op1.kind != O1K_VALUE_NUMBER) && (assertion->op1.lcl.ssaNum == SsaConfig::RESERVED_SSA_NUM))
+        if ((assertion.op1.kind != O1K_VALUE_NUMBER) && (assertion.op1.lcl.ssaNum == SsaConfig::RESERVED_SSA_NUM))
         {
             return NO_ASSERTION_INDEX;
         }
     }
 
     // Now add the assertion to our assertion table
-    noway_assert(assertion->op1.kind != O1K_INVALID);
-    noway_assert(assertion->op1.kind == O1K_ARR_BND || assertion->op2.kind != O2K_INVALID);
-    return optAddAssertion(assertion);
+    noway_assert(assertion.op1.kind != O1K_INVALID);
+    noway_assert((assertion.op1.kind == O1K_ARR_BND) || (assertion.op2.kind != O2K_INVALID));
+    return optAddAssertion(&assertion);
 }
 
 /*****************************************************************************
@@ -1693,15 +1668,26 @@ void Compiler::optDebugCheckAssertions(AssertionIndex index)
 }
 #endif
 
-/*****************************************************************************
- *
- * Given a "candidateAssertion", and the assertion operands op1 and op2,
- * create a complementary assertion and add it to the assertion table,
- * which can be retrieved using optFindComplementary(index)
- *
- */
-
-void Compiler::optCreateComplementaryAssertion(AssertionIndex assertionIndex, GenTree* op1, GenTree* op2)
+//------------------------------------------------------------------------
+// optCreateComplementaryAssertion: Create an assertion that is the complementary
+//     of the specified assertion.
+//
+// Arguments:
+//    assertionIndex - the index of the assertion
+//    op1 - the first assertion operand
+//    op2 - the second assertion operand
+//    helperCallArgs - when true this indicates that the assertion operands
+//                     are the arguments of a type cast helper call such as
+//                     CORINFO_HELP_ISINSTANCEOFCLASS
+//
+// Notes:
+//    The created complementary assertion is associated with the original
+//    assertion such that it can be found by optFindComplementary.
+//
+void Compiler::optCreateComplementaryAssertion(AssertionIndex assertionIndex,
+                                               GenTree*       op1,
+                                               GenTree*       op2,
+                                               bool           helperCallArgs)
 {
     if (assertionIndex == NO_ASSERTION_INDEX)
     {
@@ -1720,43 +1706,54 @@ void Compiler::optCreateComplementaryAssertion(AssertionIndex assertionIndex, Ge
 
     if (candidateAssertion.assertionKind == OAK_EQUAL)
     {
-        AssertionIndex index = optCreateAssertion(op1, op2, OAK_NOT_EQUAL);
+        AssertionIndex index = optCreateAssertion(op1, op2, OAK_NOT_EQUAL, helperCallArgs);
         optMapComplementary(index, assertionIndex);
     }
     else if (candidateAssertion.assertionKind == OAK_NOT_EQUAL)
     {
-        AssertionIndex index = optCreateAssertion(op1, op2, OAK_EQUAL);
+        AssertionIndex index = optCreateAssertion(op1, op2, OAK_EQUAL, helperCallArgs);
         optMapComplementary(index, assertionIndex);
     }
 
     // Are we making a subtype or exact type assertion?
     if ((candidateAssertion.op1.kind == O1K_SUBTYPE) || (candidateAssertion.op1.kind == O1K_EXACT_TYPE))
     {
-        // Did we recieve helper call args?
-        if (op1->gtOper == GT_LIST)
-        {
-            op1 = op1->gtOp.gtOp1;
-        }
         optCreateAssertion(op1, nullptr, OAK_NOT_EQUAL);
     }
 }
 
-/*****************************************************************************
- *
- * Create assertions for jtrue operands. Given operands "op1" and "op2" that
- * are used in a conditional evaluation of a jtrue stmt, create assertions
- * for the operands.
- */
-
-AssertionIndex Compiler::optCreateJtrueAssertions(GenTree* op1, GenTree* op2, Compiler::optAssertionKind assertionKind)
+//------------------------------------------------------------------------
+// optCreateJtrueAssertions: Create assertions about a JTRUE's relop operands.
+//
+// Arguments:
+//    op1 - the first assertion operand
+//    op2 - the second assertion operand
+//    assertionKind - the assertion kind
+//    helperCallArgs - when true this indicates that the assertion operands
+//                     are the arguments of a type cast helper call such as
+//                     CORINFO_HELP_ISINSTANCEOFCLASS
+// Return Value:
+//    The new assertion index or NO_ASSERTION_INDEX if a new assertion
+//    was not created.
+//
+// Notes:
+//    Assertion creation may fail either because the provided assertion
+//    operands aren't supported or because the assertion table is full.
+//    If an assertion is created succesfully then an attempt is made to also
+//    create a second, complementary assertion. This may too fail, for the
+//    same reasons as the first one.
+//
+AssertionIndex Compiler::optCreateJtrueAssertions(GenTree*                   op1,
+                                                  GenTree*                   op2,
+                                                  Compiler::optAssertionKind assertionKind,
+                                                  bool                       helperCallArgs)
 {
-    AssertionDsc   candidateAssertion;
-    AssertionIndex assertionIndex = optCreateAssertion(op1, op2, assertionKind, &candidateAssertion);
+    AssertionIndex assertionIndex = optCreateAssertion(op1, op2, assertionKind, helperCallArgs);
     // Don't bother if we don't have an assertion on the JTrue False path. Current implementation
     // allows for a complementary only if there is an assertion on the False path (tree->HasAssertion()).
     if (assertionIndex != NO_ASSERTION_INDEX)
     {
-        optCreateComplementaryAssertion(assertionIndex, op1, op2);
+        optCreateComplementaryAssertion(assertionIndex, op1, op2, helperCallArgs);
     }
     return assertionIndex;
 }
@@ -1973,36 +1970,37 @@ AssertionInfo Compiler::optAssertionGenJtrue(GenTree* tree)
     {
         return NO_ASSERTION_INDEX;
     }
-    if (op1->gtCall.gtCallMethHnd != eeFindHelper(CORINFO_HELP_ISINSTANCEOFINTERFACE) &&
-        op1->gtCall.gtCallMethHnd != eeFindHelper(CORINFO_HELP_ISINSTANCEOFARRAY) &&
-        op1->gtCall.gtCallMethHnd != eeFindHelper(CORINFO_HELP_ISINSTANCEOFCLASS) &&
-        op1->gtCall.gtCallMethHnd != eeFindHelper(CORINFO_HELP_ISINSTANCEOFANY))
-    {
-        return NO_ASSERTION_INDEX;
-    }
 
-    op2 = op1->gtCall.gtCallLateArgs->gtOp.gtOp2;
-    op1 = op1->gtCall.gtCallLateArgs;
+    GenTreeCall* call = op1->AsCall();
 
-    // For the assertion, ensure op1 is the object being tested.
-    // Morph may have swizzled the operand order.
-    GenTree* op1op = op1->gtOp.gtOp1;
-
-    if (op1op->TypeGet() == TYP_I_IMPL)
+    if ((call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_ISINSTANCEOFINTERFACE)) ||
+        (call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_ISINSTANCEOFARRAY)) ||
+        (call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_ISINSTANCEOFCLASS)) ||
+        (call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_ISINSTANCEOFANY)))
     {
-        jitstd::swap(op1, op2);
-        op1op = op1->gtOp.gtOp1;
-    }
+        // TODO-Cleanup: Arg nodes should be retrieved by other means (e.g. GetArgNode)
+        // that do not involve gtCallLateArgs directly. The helper parameter order is
+        // actually (methodTable, object) but the method table tends to end up last in
+        // gtCallLateArgs because it is usually a constant.
+        GenTree* objectNode      = call->gtCallLateArgs->GetNode();
+        GenTree* methodTableNode = call->gtCallLateArgs->GetNext()->GetNode();
 
-    assert(op1op->TypeGet() == TYP_REF);
+        // Swap the nodes if they're not ordered as expected.
+        if (objectNode->TypeGet() == TYP_I_IMPL)
+        {
+            jitstd::swap(objectNode, methodTableNode);
+        }
 
-    // Reverse the assertion
-    assert(assertionKind == OAK_EQUAL || assertionKind == OAK_NOT_EQUAL);
-    assertionKind = (assertionKind == OAK_EQUAL) ? OAK_NOT_EQUAL : OAK_EQUAL;
+        assert(objectNode->TypeGet() == TYP_REF);
 
-    if (op1op->OperIs(GT_LCL_VAR))
-    {
-        return optCreateJtrueAssertions(op1, op2, assertionKind);
+        // Reverse the assertion
+        assert((assertionKind == OAK_EQUAL) || (assertionKind == OAK_NOT_EQUAL));
+        assertionKind = (assertionKind == OAK_EQUAL) ? OAK_NOT_EQUAL : OAK_EQUAL;
+
+        if (objectNode->OperIs(GT_LCL_VAR))
+        {
+            return optCreateJtrueAssertions(objectNode, methodTableNode, assertionKind, /* helperCallArgs */ true);
+        }
     }
 
     return NO_ASSERTION_INDEX;
index cff8966..1b83bd3 100644 (file)
@@ -2271,11 +2271,9 @@ void CodeGen::genCallInstruction(GenTreeCall* call)
     assert(!call->IsVirtual() || call->gtControlExpr || call->gtCallAddr);
 
     // Consume all the arg regs
-    for (GenTree* list = call->gtCallLateArgs; list; list = list->MoveNext())
+    for (GenTreeCall::Use& use : call->LateArgs())
     {
-        assert(list->OperIsList());
-
-        GenTree* argNode = list->Current();
+        GenTree* argNode = use.GetNode();
 
         fgArgTabEntry* curArgTabEntry = compiler->gtArgEntryByNode(call, argNode);
         assert(curArgTabEntry);
index 1b5e11a..3cced1a 100644 (file)
@@ -5344,11 +5344,9 @@ void CodeGen::genCallInstruction(GenTreeCall* call)
     }
 
     // Consume all the arg regs
-    for (GenTree* list = call->gtCallLateArgs; list; list = list->MoveNext())
+    for (GenTreeCall::Use& use : call->LateArgs())
     {
-        assert(list->OperIsList());
-
-        GenTree* argNode = list->Current();
+        GenTree* argNode = use.GetNode();
 
         fgArgTabEntry* curArgTabEntry = compiler->gtArgEntryByNode(call, argNode->gtSkipReloadOrCopy());
         assert(curArgTabEntry);
@@ -5418,40 +5416,35 @@ void CodeGen::genCallInstruction(GenTreeCall* call)
 #if defined(_TARGET_X86_) || defined(UNIX_AMD64_ABI)
     // The call will pop its arguments.
     // for each putarg_stk:
-    ssize_t  stackArgBytes = 0;
-    GenTree* args          = call->gtCallArgs;
-    while (args)
+    ssize_t stackArgBytes = 0;
+    for (GenTreeCall::Use& use : call->Args())
     {
-        GenTree* arg = args->gtOp.gtOp1;
-        if (arg->OperGet() != GT_ARGPLACE && !(arg->gtFlags & GTF_LATE_ARG))
+        GenTree* arg = use.GetNode();
+        if (arg->OperIs(GT_PUTARG_STK) && ((arg->gtFlags & GTF_LATE_ARG) == 0))
         {
-            if (arg->OperGet() == GT_PUTARG_STK)
-            {
-                GenTree* source = arg->gtOp.gtOp1;
-                unsigned size   = arg->AsPutArgStk()->getArgSize();
-                stackArgBytes += size;
+            GenTree* source = arg->AsPutArgStk()->gtGetOp1();
+            unsigned size   = arg->AsPutArgStk()->getArgSize();
+            stackArgBytes += size;
 #ifdef DEBUG
-                fgArgTabEntry* curArgTabEntry = compiler->gtArgEntryByNode(call, arg);
-                assert(curArgTabEntry);
-                assert(size == (curArgTabEntry->numSlots * TARGET_POINTER_SIZE));
+            fgArgTabEntry* curArgTabEntry = compiler->gtArgEntryByNode(call, arg);
+            assert(curArgTabEntry != nullptr);
+            assert(size == (curArgTabEntry->numSlots * TARGET_POINTER_SIZE));
 #ifdef FEATURE_PUT_STRUCT_ARG_STK
-                if (source->TypeGet() == TYP_STRUCT)
-                {
-                    GenTreeObj* obj      = source->AsObj();
-                    unsigned    argBytes = roundUp(obj->GetLayout()->GetSize(), TARGET_POINTER_SIZE);
+            if (source->TypeGet() == TYP_STRUCT)
+            {
+                GenTreeObj* obj      = source->AsObj();
+                unsigned    argBytes = roundUp(obj->GetLayout()->GetSize(), TARGET_POINTER_SIZE);
 #ifdef _TARGET_X86_
-                    // If we have an OBJ, we must have created a copy if the original arg was not a
-                    // local and was not a multiple of TARGET_POINTER_SIZE.
-                    // Note that on x64/ux this will be handled by unrolling in genStructPutArgUnroll.
-                    assert((argBytes == obj->GetLayout()->GetSize()) || obj->Addr()->IsLocalAddrExpr());
+                // If we have an OBJ, we must have created a copy if the original arg was not a
+                // local and was not a multiple of TARGET_POINTER_SIZE.
+                // Note that on x64/ux this will be handled by unrolling in genStructPutArgUnroll.
+                assert((argBytes == obj->GetLayout()->GetSize()) || obj->Addr()->IsLocalAddrExpr());
 #endif // _TARGET_X86_
-                    assert((curArgTabEntry->numSlots * TARGET_POINTER_SIZE) == argBytes);
-                }
+                assert((curArgTabEntry->numSlots * TARGET_POINTER_SIZE) == argBytes);
+            }
 #endif // FEATURE_PUT_STRUCT_ARG_STK
 #endif // DEBUG
-            }
         }
-        args = args->gtOp.gtOp2;
     }
 #endif // defined(_TARGET_X86_) || defined(UNIX_AMD64_ABI)
 
index aa446a9..b83e0f9 100644 (file)
@@ -6865,13 +6865,11 @@ Compiler::NodeToIntMap* Compiler::FindReachableNodesInNodeTestData()
                 // For call nodes, translate late args to what they stand for.
                 if (tree->OperGet() == GT_CALL)
                 {
-                    GenTreeCall*    call = tree->AsCall();
-                    GenTreeArgList* args = call->gtCallArgs;
-                    unsigned        i    = 0;
-                    while (args != nullptr)
+                    GenTreeCall* call = tree->AsCall();
+                    unsigned     i    = 0;
+                    for (GenTreeCall::Use& use : call->Args())
                     {
-                        GenTree* arg = args->Current();
-                        if (arg->gtFlags & GTF_LATE_ARG)
+                        if ((use.GetNode()->gtFlags & GTF_LATE_ARG) != 0)
                         {
                             // Find the corresponding late arg.
                             GenTree* lateArg = call->fgArgInfo->GetArgNode(i);
@@ -6881,7 +6879,6 @@ Compiler::NodeToIntMap* Compiler::FindReachableNodesInNodeTestData()
                             }
                         }
                         i++;
-                        args = args->Rest();
                     }
                 }
 
index f057acf..175bda4 100644 (file)
@@ -1333,9 +1333,10 @@ struct FuncInfoDsc
 
 struct fgArgTabEntry
 {
-    GenTree* node;   // Initially points at the Op1 field of 'parent', but if the argument is replaced with an GT_ASG or
-                     // placeholder it will point at the actual argument in the gtCallLateArgs list.
-    GenTree* parent; // Points at the GT_LIST node in the gtCallArgs for this argument
+    GenTree* node;         // Initially points to `use`'s node, but if the argument is replaced with an GT_ASG or
+                           // placeholder it will point at the actual argument node in the gtCallLateArgs list.
+    GenTreeCall::Use* use; // Points at the GenTreeCall::Use in the gtCallArgs for this argument
+                           // or nullptr for the `this` argument which does not have a corresponding GenTreeCall::Use.
 
     unsigned argNum; // The original argument number, also specifies the required argument evaluation order from the IL
 
@@ -1776,19 +1777,19 @@ public:
     fgArgInfo(Compiler* comp, GenTreeCall* call, unsigned argCount);
     fgArgInfo(GenTreeCall* newCall, GenTreeCall* oldCall);
 
-    fgArgTabEntry* AddRegArg(unsigned  argNum,
-                             GenTree*  node,
-                             GenTree*  parent,
-                             regNumber regNum,
-                             unsigned  numRegs,
-                             unsigned  alignment,
-                             bool      isStruct,
-                             bool      isVararg = false);
+    fgArgTabEntry* AddRegArg(unsigned          argNum,
+                             GenTree*          node,
+                             GenTreeCall::Use* use,
+                             regNumber         regNum,
+                             unsigned          numRegs,
+                             unsigned          alignment,
+                             bool              isStruct,
+                             bool              isVararg = false);
 
 #ifdef UNIX_AMD64_ABI
     fgArgTabEntry* AddRegArg(unsigned                                                         argNum,
                              GenTree*                                                         node,
-                             GenTree*                                                         parent,
+                             GenTreeCall::Use*                                                use,
                              regNumber                                                        regNum,
                              unsigned                                                         numRegs,
                              unsigned                                                         alignment,
@@ -1800,13 +1801,13 @@ public:
                              const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* const structDescPtr = nullptr);
 #endif // UNIX_AMD64_ABI
 
-    fgArgTabEntry* AddStkArg(unsigned argNum,
-                             GenTree* node,
-                             GenTree* parent,
-                             unsigned numSlots,
-                             unsigned alignment,
-                             bool     isStruct,
-                             bool     isVararg = false);
+    fgArgTabEntry* AddStkArg(unsigned          argNum,
+                             GenTree*          node,
+                             GenTreeCall::Use* use,
+                             unsigned          numSlots,
+                             unsigned          alignment,
+                             bool              isStruct,
+                             bool              isVararg = false);
 
     void RemorphReset();
     void UpdateRegArg(fgArgTabEntry* argEntry, GenTree* node, bool reMorphing);
@@ -2513,18 +2514,25 @@ public:
 
     GenTreeArgList* gtNewListNode(GenTree* op1, GenTreeArgList* op2);
 
+    GenTreeCall::Use* gtNewCallArgs(GenTree* node);
+    GenTreeCall::Use* gtNewCallArgs(GenTree* node1, GenTree* node2);
+    GenTreeCall::Use* gtNewCallArgs(GenTree* node1, GenTree* node2, GenTree* node3);
+    GenTreeCall::Use* gtNewCallArgs(GenTree* node1, GenTree* node2, GenTree* node3, GenTree* node4);
+    GenTreeCall::Use* gtPrependNewCallArg(GenTree* node, GenTreeCall::Use* args);
+    GenTreeCall::Use* gtInsertNewCallArgAfter(GenTree* node, GenTreeCall::Use* after);
+
     GenTreeCall* gtNewCallNode(gtCallTypes           callType,
                                CORINFO_METHOD_HANDLE handle,
                                var_types             type,
-                               GenTreeArgList*       args,
+                               GenTreeCall::Use*     args,
                                IL_OFFSETX            ilOffset = BAD_IL_OFFSET);
 
-    GenTreeCall* gtNewIndCallNode(GenTree*        addr,
-                                  var_types       type,
-                                  GenTreeArgList* args,
-                                  IL_OFFSETX      ilOffset = BAD_IL_OFFSET);
+    GenTreeCall* gtNewIndCallNode(GenTree*          addr,
+                                  var_types         type,
+                                  GenTreeCall::Use* args,
+                                  IL_OFFSETX        ilOffset = BAD_IL_OFFSET);
 
-    GenTreeCall* gtNewHelperCallNode(unsigned helper, var_types type, GenTreeArgList* args = nullptr);
+    GenTreeCall* gtNewHelperCallNode(unsigned helper, var_types type, GenTreeCall::Use* args = nullptr);
 
     GenTree* gtNewLclvNode(unsigned lnum, var_types type DEBUGARG(IL_OFFSETX ILoffs = BAD_IL_OFFSET));
     GenTree* gtNewLclLNode(unsigned lnum, var_types type DEBUGARG(IL_OFFSETX ILoffs = BAD_IL_OFFSET));
@@ -2687,6 +2695,7 @@ public:
     bool gtHasLocalsWithAddrOp(GenTree* tree);
 
     unsigned gtSetListOrder(GenTree* list, bool regs, bool isListCallArgs);
+    unsigned gtSetCallArgsOrder(const GenTreeCall::UseList& args, bool lateArgs, int* callCostEx, int* callCostSz);
 
     void gtWalkOp(GenTree** op1, GenTree** op2, GenTree* base, bool constOnly);
 
@@ -3776,7 +3785,7 @@ public:
     GenTreeCall* impReadyToRunHelperToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
                                            CorInfoHelpFunc         helper,
                                            var_types               type,
-                                           GenTreeArgList*         arg                = nullptr,
+                                           GenTreeCall::Use*       args               = nullptr,
                                            CORINFO_LOOKUP_KIND*    pGenericLookupKind = nullptr);
 
     GenTree* impCastClassOrIsInstToTree(GenTree*                op1,
@@ -3833,9 +3842,9 @@ private:
                 ((opcode >= CEE_STLOC_0) && (opcode <= CEE_STLOC_3)));
     }
 
-    GenTreeArgList* impPopList(unsigned count, CORINFO_SIG_INFO* sig, GenTreeArgList* prefixTree = nullptr);
+    GenTreeCall::Use* impPopCallArgs(unsigned count, CORINFO_SIG_INFO* sig, GenTreeCall::Use* prefixArgs = nullptr);
 
-    GenTreeArgList* impPopRevList(unsigned count, CORINFO_SIG_INFO* sig, unsigned skipReverseCount = 0);
+    GenTreeCall::Use* impPopReverseCallArgs(unsigned count, CORINFO_SIG_INFO* sig, unsigned skipReverseCount = 0);
 
     /*
      * Get current IL offset with stack-empty info incoporated
@@ -4075,9 +4084,10 @@ private:
 
     BOOL impInlineIsThis(GenTree* tree, InlArgInfo* inlArgInfo);
 
-    BOOL impInlineIsGuaranteedThisDerefBeforeAnySideEffects(GenTree*    additionalTreesToBeEvaluatedBefore,
-                                                            GenTree*    variableBeingDereferenced,
-                                                            InlArgInfo* inlArgInfo);
+    BOOL impInlineIsGuaranteedThisDerefBeforeAnySideEffects(GenTree*          additionalTree,
+                                                            GenTreeCall::Use* additionalCallArgs,
+                                                            GenTree*          dereferencedAddress,
+                                                            InlArgInfo*       inlArgInfo);
 
     void impMarkInlineCandidate(GenTree*               call,
                                 CORINFO_CONTEXT_HANDLE exactContextHnd,
@@ -4632,9 +4642,6 @@ public:
     // Does value-numbering for a call.  We interpret some helper calls.
     void fgValueNumberCall(GenTreeCall* call);
 
-    // The VN of some nodes in "args" may have changed -- reassign VNs to the arg list nodes.
-    void fgUpdateArgListVNs(GenTreeArgList* args);
-
     // Does value-numbering for a helper "call" that has a VN function symbol "vnf".
     void fgValueNumberHelperCallFunc(GenTreeCall* call, VNFunc vnf, ValueNumPair vnpExc);
 
@@ -5342,7 +5349,7 @@ private:
 
     GenTree* fgMorphCastIntoHelper(GenTree* tree, int helper, GenTree* oper);
 
-    GenTree* fgMorphIntoHelperCall(GenTree* tree, int helper, GenTreeArgList* args, bool morphArgs = true);
+    GenTree* fgMorphIntoHelperCall(GenTree* tree, int helper, GenTreeCall::Use* args, bool morphArgs = true);
 
     GenTree* fgMorphStackArgForVarArgs(unsigned lclNum, var_types varType, unsigned lclOffs);
 
@@ -5399,7 +5406,7 @@ private:
     GenTreeArgList* fgMorphArgList(GenTreeArgList* args, MorphAddrContext* mac);
 
     void fgMakeOutgoingStructArgCopy(GenTreeCall*         call,
-                                     GenTree*             args,
+                                     GenTreeCall::Use*    args,
                                      unsigned             argIndex,
                                      CORINFO_CLASS_HANDLE copyBlkClass);
 
@@ -6700,17 +6707,22 @@ public:
     AssertionIndex optAssertionGenPhiDefn(GenTree* tree);
     AssertionInfo optCreateJTrueBoundsAssertion(GenTree* tree);
     AssertionInfo optAssertionGenJtrue(GenTree* tree);
-    AssertionIndex optCreateJtrueAssertions(GenTree* op1, GenTree* op2, Compiler::optAssertionKind assertionKind);
+    AssertionIndex optCreateJtrueAssertions(GenTree*                   op1,
+                                            GenTree*                   op2,
+                                            Compiler::optAssertionKind assertionKind,
+                                            bool                       helperCallArgs = false);
     AssertionIndex optFindComplementary(AssertionIndex assertionIndex);
     void optMapComplementary(AssertionIndex assertionIndex, AssertionIndex index);
 
     // Assertion creation functions.
-    AssertionIndex optCreateAssertion(GenTree* op1, GenTree* op2, optAssertionKind assertionKind);
     AssertionIndex optCreateAssertion(GenTree*         op1,
                                       GenTree*         op2,
                                       optAssertionKind assertionKind,
-                                      AssertionDsc*    assertion);
-    void optCreateComplementaryAssertion(AssertionIndex assertionIndex, GenTree* op1, GenTree* op2);
+                                      bool             helperCallArgs = false);
+    void optCreateComplementaryAssertion(AssertionIndex assertionIndex,
+                                         GenTree*       op1,
+                                         GenTree*       op2,
+                                         bool           helperCallArgs = false);
 
     bool optAssertionVnInvolvesNan(AssertionDsc* assertion);
     AssertionIndex optAddAssertion(AssertionDsc* assertion);
@@ -10138,18 +10150,18 @@ public:
                     }
                 }
 
-                for (GenTreeArgList* args = call->gtCallArgs; args != nullptr; args = args->Rest())
+                for (GenTreeCall::Use& use : call->Args())
                 {
-                    result = WalkTree(args->pCurrent(), call);
+                    result = WalkTree(&use.NodeRef(), call);
                     if (result == fgWalkResult::WALK_ABORT)
                     {
                         return result;
                     }
                 }
 
-                for (GenTreeArgList* args = call->gtCallLateArgs; args != nullptr; args = args->Rest())
+                for (GenTreeCall::Use& use : call->LateArgs())
                 {
-                    result = WalkTree(args->pCurrent(), call);
+                    result = WalkTree(&use.NodeRef(), call);
                     if (result == fgWalkResult::WALK_ABORT)
                     {
                         return result;
index 0ea0a25..f10b4d6 100644 (file)
@@ -1110,7 +1110,7 @@ inline GenTree* Compiler::gtNewIconEmbFldHndNode(CORINFO_FIELD_HANDLE fldHnd)
 // Return Value:
 //    New CT_HELPER node
 
-inline GenTreeCall* Compiler::gtNewHelperCallNode(unsigned helper, var_types type, GenTreeArgList* args)
+inline GenTreeCall* Compiler::gtNewHelperCallNode(unsigned helper, var_types type, GenTreeCall::Use* args)
 {
     unsigned     flags  = s_helperCallProperties.NoThrow((CorInfoHelpFunc)helper) ? 0 : GTF_EXCEPT;
     GenTreeCall* result = gtNewCallNode(CT_HELPER, eeFindHelper(helper), type, args);
@@ -4405,15 +4405,23 @@ void GenTree::VisitOperands(TVisitor visitor)
             {
                 return;
             }
-            if ((call->gtCallArgs != nullptr) && (call->gtCallArgs->VisitListOperands(visitor) == VisitResult::Abort))
+
+            for (GenTreeCall::Use& use : call->Args())
             {
-                return;
+                if (visitor(use.GetNode()) == VisitResult::Abort)
+                {
+                    return;
+                }
             }
-            if ((call->gtCallLateArgs != nullptr) &&
-                (call->gtCallLateArgs->VisitListOperands(visitor)) == VisitResult::Abort)
+
+            for (GenTreeCall::Use& use : call->LateArgs())
             {
-                return;
+                if (visitor(use.GetNode()) == VisitResult::Abort)
+                {
+                    return;
+                }
             }
+
             if (call->gtCallType == CT_INDIRECT)
             {
                 if ((call->gtCallCookie != nullptr) && (visitor(call->gtCallCookie) == VisitResult::Abort))
index 4a0f27b..1bb540c 100644 (file)
@@ -1365,7 +1365,7 @@ GenTree* DecomposeLongs::DecomposeShift(LIR::Use& use)
                 unreached();
         }
 
-        GenTreeArgList* argList = m_compiler->gtNewArgList(loOp1, hiOp1, shiftByOp);
+        GenTreeCall::Use* argList = m_compiler->gtNewCallArgs(loOp1, hiOp1, shiftByOp);
 
         GenTree* call = m_compiler->gtNewHelperCallNode(helper, TYP_LONG, argList);
         call->gtFlags |= shift->gtFlags & GTF_ALL_EFFECT;
index 84d4373..553f286 100644 (file)
@@ -279,8 +279,8 @@ void Compiler::fgInstrumentMethod()
         {
             // In such cases we still want to add the method entry callback node
 
-            GenTreeArgList* args = gtNewArgList(gtNewIconEmbMethHndNode(info.compMethodHnd));
-            GenTree*        call = gtNewHelperCallNode(CORINFO_HELP_BBT_FCN_ENTER, TYP_VOID, args);
+            GenTreeCall::Use* args = gtNewCallArgs(gtNewIconEmbMethHndNode(info.compMethodHnd));
+            GenTree*          call = gtNewHelperCallNode(CORINFO_HELP_BBT_FCN_ENTER, TYP_VOID, args);
 
             stmt = gtNewStmt(call);
         }
@@ -361,8 +361,8 @@ void Compiler::fgInstrumentMethod()
             arg = gtNewIconEmbMethHndNode(info.compMethodHnd);
         }
 
-        GenTreeArgList* args = gtNewArgList(arg);
-        GenTree*        call = gtNewHelperCallNode(CORINFO_HELP_BBT_FCN_ENTER, TYP_VOID, args);
+        GenTreeCall::Use* args = gtNewCallArgs(arg);
+        GenTree*          call = gtNewHelperCallNode(CORINFO_HELP_BBT_FCN_ENTER, TYP_VOID, args);
 
         // Get the address of the first blocks ExecutionCount
         size_t addrOfFirstExecutionCount = (size_t)&profileBlockCountsStart->ExecutionCount;
@@ -7127,7 +7127,7 @@ GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfo
             break;
     }
 
-    GenTreeArgList* argList = nullptr;
+    GenTreeCall::Use* argList = nullptr;
 
     GenTree* opModuleIDArg;
     GenTree* opClassIDArg;
@@ -7171,11 +7171,11 @@ GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfo
         }
 
         // call the helper to get the base
-        argList = gtNewArgList(opModuleIDArg, opClassIDArg);
+        argList = gtNewCallArgs(opModuleIDArg, opClassIDArg);
     }
     else
     {
-        argList = gtNewArgList(opModuleIDArg);
+        argList = gtNewCallArgs(opModuleIDArg);
     }
 
     GenTreeCall* result = gtNewHelperCallNode(helper, type, argList);
@@ -7337,7 +7337,7 @@ GenTree* Compiler::fgOptimizeDelegateConstructor(GenTreeCall*            call,
     CORINFO_METHOD_HANDLE methHnd = call->gtCallMethHnd;
     CORINFO_CLASS_HANDLE  clsHnd  = info.compCompHnd->getMethodClass(methHnd);
 
-    GenTree* targetMethod = call->gtCallArgs->Rest()->Current();
+    GenTree* targetMethod = call->gtCallArgs->GetNext()->GetNode();
     noway_assert(targetMethod->TypeGet() == TYP_I_IMPL);
     genTreeOps            oper            = targetMethod->OperGet();
     CORINFO_METHOD_HANDLE targetMethodHnd = nullptr;
@@ -7348,7 +7348,7 @@ GenTree* Compiler::fgOptimizeDelegateConstructor(GenTreeCall*            call,
     }
     else if (oper == GT_CALL && targetMethod->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_VIRTUAL_FUNC_PTR))
     {
-        GenTree* handleNode = targetMethod->gtCall.gtCallArgs->Rest()->Rest()->Current();
+        GenTree* handleNode = targetMethod->AsCall()->gtCallArgs->GetNext()->GetNext()->GetNode();
 
         if (handleNode->OperGet() == GT_CNS_INT)
         {
@@ -7387,7 +7387,7 @@ GenTree* Compiler::fgOptimizeDelegateConstructor(GenTreeCall*            call,
         GenTreeCall* runtimeLookupCall = qmarkNode->gtOp.gtOp2->gtOp.gtOp1->AsCall();
 
         // This could be any of CORINFO_HELP_RUNTIMEHANDLE_(METHOD|CLASS)(_LOG?)
-        GenTree* tokenNode = runtimeLookupCall->gtCallArgs->gtOp.gtOp2->gtOp.gtOp1;
+        GenTree* tokenNode = runtimeLookupCall->gtCallArgs->GetNext()->GetNode();
         noway_assert(tokenNode->OperGet() == GT_CNS_INT);
         targetMethodHnd = CORINFO_METHOD_HANDLE(tokenNode->gtIntCon.gtCompileTimeHandle);
     }
@@ -7420,14 +7420,14 @@ GenTree* Compiler::fgOptimizeDelegateConstructor(GenTreeCall*            call,
                 JITDUMP("optimized\n");
 
                 GenTree*             thisPointer       = call->gtCallObjp;
-                GenTree*             targetObjPointers = call->gtCallArgs->Current();
-                GenTreeArgList*      helperArgs        = nullptr;
+                GenTree*             targetObjPointers = call->gtCallArgs->GetNode();
+                GenTreeCall::Use*    helperArgs        = nullptr;
                 CORINFO_LOOKUP       pLookup;
                 CORINFO_CONST_LOOKUP entryPoint;
                 info.compCompHnd->getReadyToRunDelegateCtorHelper(ldftnToken, clsHnd, &pLookup);
                 if (!pLookup.lookupKind.needsRuntimeLookup)
                 {
-                    helperArgs = gtNewArgList(thisPointer, targetObjPointers);
+                    helperArgs = gtNewCallArgs(thisPointer, targetObjPointers);
                     entryPoint = pLookup.constLookup;
                 }
                 else
@@ -7437,7 +7437,7 @@ GenTree* Compiler::fgOptimizeDelegateConstructor(GenTreeCall*            call,
                     info.compCompHnd->getReadyToRunHelper(ldftnToken, &pLookup.lookupKind,
                                                           CORINFO_HELP_READYTORUN_GENERIC_HANDLE, &genericLookup);
                     GenTree* ctxTree = getRuntimeContextTree(pLookup.lookupKind.runtimeLookupKind);
-                    helperArgs       = gtNewArgList(thisPointer, targetObjPointers, ctxTree);
+                    helperArgs       = gtNewCallArgs(thisPointer, targetObjPointers, ctxTree);
                     entryPoint       = genericLookup;
                 }
                 call = gtNewHelperCallNode(CORINFO_HELP_READYTORUN_DELEGATE_CTOR, TYP_VOID, helperArgs);
@@ -7453,9 +7453,9 @@ GenTree* Compiler::fgOptimizeDelegateConstructor(GenTreeCall*            call,
         {
             JITDUMP("optimized\n");
 
-            GenTree*        thisPointer       = call->gtCallObjp;
-            GenTree*        targetObjPointers = call->gtCallArgs->Current();
-            GenTreeArgList* helperArgs        = gtNewArgList(thisPointer, targetObjPointers);
+            GenTree*          thisPointer       = call->gtCallObjp;
+            GenTree*          targetObjPointers = call->gtCallArgs->GetNode();
+            GenTreeCall::Use* helperArgs        = gtNewCallArgs(thisPointer, targetObjPointers);
 
             call = gtNewHelperCallNode(CORINFO_HELP_READYTORUN_DELEGATE_CTOR, TYP_VOID, helperArgs);
 
@@ -7490,24 +7490,24 @@ GenTree* Compiler::fgOptimizeDelegateConstructor(GenTreeCall*            call,
 
             call->gtCallMethHnd = alternateCtor;
 
-            noway_assert(call->gtCallArgs->Rest()->Rest() == nullptr);
-            GenTreeArgList* addArgs = nullptr;
+            noway_assert(call->gtCallArgs->GetNext()->GetNext() == nullptr);
+            GenTreeCall::Use* addArgs = nullptr;
             if (ctorData.pArg5)
             {
                 GenTree* arg5 = gtNewIconHandleNode(size_t(ctorData.pArg5), GTF_ICON_FTN_ADDR);
-                addArgs       = gtNewListNode(arg5, addArgs);
+                addArgs       = gtPrependNewCallArg(arg5, addArgs);
             }
             if (ctorData.pArg4)
             {
                 GenTree* arg4 = gtNewIconHandleNode(size_t(ctorData.pArg4), GTF_ICON_FTN_ADDR);
-                addArgs       = gtNewListNode(arg4, addArgs);
+                addArgs       = gtPrependNewCallArg(arg4, addArgs);
             }
             if (ctorData.pArg3)
             {
                 GenTree* arg3 = gtNewIconHandleNode(size_t(ctorData.pArg3), GTF_ICON_FTN_ADDR);
-                addArgs       = gtNewListNode(arg3, addArgs);
+                addArgs       = gtPrependNewCallArg(arg3, addArgs);
             }
-            call->gtCallArgs->Rest()->Rest() = addArgs;
+            call->gtCallArgs->GetNext()->SetNext(addArgs);
         }
         else
         {
@@ -7856,7 +7856,7 @@ GenTree* Compiler::fgGetCritSectOfStaticMethod()
                 tree = gtNewLclvNode(info.compTypeCtxtArg, TYP_I_IMPL);
                 // Call helper CORINFO_HELP_GETCLASSFROMMETHODPARAM to get the class handle
                 // from the method handle.
-                tree = gtNewHelperCallNode(CORINFO_HELP_GETCLASSFROMMETHODPARAM, TYP_I_IMPL, gtNewArgList(tree));
+                tree = gtNewHelperCallNode(CORINFO_HELP_GETCLASSFROMMETHODPARAM, TYP_I_IMPL, gtNewCallArgs(tree));
                 break;
             }
 
@@ -7870,7 +7870,7 @@ GenTree* Compiler::fgGetCritSectOfStaticMethod()
         noway_assert(tree); // tree should now contain the CORINFO_CLASS_HANDLE for the exact class.
 
         // Given the class handle, get the pointer to the Monitor.
-        tree = gtNewHelperCallNode(CORINFO_HELP_GETSYNCFROMCLASSHANDLE, TYP_I_IMPL, gtNewArgList(tree));
+        tree = gtNewHelperCallNode(CORINFO_HELP_GETSYNCFROMCLASSHANDLE, TYP_I_IMPL, gtNewCallArgs(tree));
     }
 
     noway_assert(tree);
@@ -8153,13 +8153,13 @@ GenTree* Compiler::fgCreateMonitorTree(unsigned lvaMonAcquired, unsigned lvaThis
     {
         tree = fgGetCritSectOfStaticMethod();
         tree = gtNewHelperCallNode(enter ? CORINFO_HELP_MON_ENTER_STATIC : CORINFO_HELP_MON_EXIT_STATIC, TYP_VOID,
-                                   gtNewArgList(tree, varAddrNode));
+                                   gtNewCallArgs(tree, varAddrNode));
     }
     else
     {
         tree = gtNewLclvNode(lvaThisVar, TYP_REF);
         tree = gtNewHelperCallNode(enter ? CORINFO_HELP_MON_ENTER : CORINFO_HELP_MON_EXIT, TYP_VOID,
-                                   gtNewArgList(tree, varAddrNode));
+                                   gtNewCallArgs(tree, varAddrNode));
     }
 
 #ifdef DEBUG
@@ -8286,7 +8286,7 @@ void Compiler::fgAddReversePInvokeEnterExit()
 
     tree = gtNewOperNode(GT_ADDR, TYP_I_IMPL, gtNewLclvNode(lvaReversePInvokeFrameVar, TYP_BLK));
 
-    tree = gtNewHelperCallNode(CORINFO_HELP_JIT_REVERSE_PINVOKE_ENTER, TYP_VOID, gtNewArgList(tree));
+    tree = gtNewHelperCallNode(CORINFO_HELP_JIT_REVERSE_PINVOKE_ENTER, TYP_VOID, gtNewCallArgs(tree));
 
     fgEnsureFirstBBisScratch();
 
@@ -8306,7 +8306,7 @@ void Compiler::fgAddReversePInvokeEnterExit()
 
     tree = gtNewOperNode(GT_ADDR, TYP_I_IMPL, gtNewLclvNode(lvaReversePInvokeFrameVar, TYP_BLK));
 
-    tree = gtNewHelperCallNode(CORINFO_HELP_JIT_REVERSE_PINVOKE_EXIT, TYP_VOID, gtNewArgList(tree));
+    tree = gtNewHelperCallNode(CORINFO_HELP_JIT_REVERSE_PINVOKE_EXIT, TYP_VOID, gtNewCallArgs(tree));
 
     assert(genReturnBB != nullptr);
 
@@ -9084,8 +9084,8 @@ void Compiler::fgAddInternal()
         tree = gtNewIconEmbMethHndNode(info.compMethodHnd);
 
         tree = gtNewHelperCallNode(info.compCompHnd->getSecurityPrologHelper(info.compMethodHnd), TYP_VOID,
-                                   gtNewArgList(tree, gtNewOperNode(GT_ADDR, TYP_BYREF,
-                                                                    gtNewLclvNode(lvaSecurityObject, TYP_REF))));
+                                   gtNewCallArgs(tree, gtNewOperNode(GT_ADDR, TYP_BYREF,
+                                                                     gtNewLclvNode(lvaSecurityObject, TYP_REF))));
 
         /* Create a new basic block and stick the call in it */
 
@@ -9120,7 +9120,7 @@ void Compiler::fgAddInternal()
         {
             tree = fgGetCritSectOfStaticMethod();
 
-            tree = gtNewHelperCallNode(CORINFO_HELP_MON_ENTER_STATIC, TYP_VOID, gtNewArgList(tree));
+            tree = gtNewHelperCallNode(CORINFO_HELP_MON_ENTER_STATIC, TYP_VOID, gtNewCallArgs(tree));
         }
         else
         {
@@ -9128,7 +9128,7 @@ void Compiler::fgAddInternal()
 
             tree = gtNewLclvNode(info.compThisArg, TYP_REF);
 
-            tree = gtNewHelperCallNode(CORINFO_HELP_MON_ENTER, TYP_VOID, gtNewArgList(tree));
+            tree = gtNewHelperCallNode(CORINFO_HELP_MON_ENTER, TYP_VOID, gtNewCallArgs(tree));
         }
 
         /* Create a new basic block and stick the call in it */
@@ -9157,13 +9157,13 @@ void Compiler::fgAddInternal()
         {
             tree = fgGetCritSectOfStaticMethod();
 
-            tree = gtNewHelperCallNode(CORINFO_HELP_MON_EXIT_STATIC, TYP_VOID, gtNewArgList(tree));
+            tree = gtNewHelperCallNode(CORINFO_HELP_MON_EXIT_STATIC, TYP_VOID, gtNewCallArgs(tree));
         }
         else
         {
             tree = gtNewLclvNode(info.compThisArg, TYP_REF);
 
-            tree = gtNewHelperCallNode(CORINFO_HELP_MON_EXIT, TYP_VOID, gtNewArgList(tree));
+            tree = gtNewHelperCallNode(CORINFO_HELP_MON_EXIT, TYP_VOID, gtNewCallArgs(tree));
         }
 
         fgNewStmtNearEnd(genReturnBB, tree);
@@ -9194,7 +9194,7 @@ void Compiler::fgAddInternal()
 
         tree = gtNewIconEmbMethHndNode(info.compMethodHnd);
 
-        tree = gtNewHelperCallNode(CORINFO_HELP_VERIFICATION_RUNTIME_CHECK, TYP_VOID, gtNewArgList(tree));
+        tree = gtNewHelperCallNode(CORINFO_HELP_VERIFICATION_RUNTIME_CHECK, TYP_VOID, gtNewCallArgs(tree));
 
         /* Create a new basic block and stick the call in it */
 
@@ -18747,21 +18747,14 @@ void Compiler::fgSetTreeSeqHelper(GenTree* tree, bool isLIR)
                 fgSetTreeSeqHelper(tree->gtCall.gtCallObjp, isLIR);
             }
 
-            /* We'll evaluate the arguments next, left to right
-             * NOTE: setListOrder needs cleanup - eliminate the #ifdef afterwards */
-
-            if (tree->gtCall.gtCallArgs)
+            for (GenTreeCall::Use& use : tree->AsCall()->Args())
             {
-                fgSetTreeSeqHelper(tree->gtCall.gtCallArgs, isLIR);
+                fgSetTreeSeqHelper(use.GetNode(), isLIR);
             }
 
-            /* Evaluate the temp register arguments list
-             * This is a "hidden" list and its only purpose is to
-             * extend the life of temps until we make the call */
-
-            if (tree->gtCall.gtCallLateArgs)
+            for (GenTreeCall::Use& use : tree->AsCall()->LateArgs())
             {
-                fgSetTreeSeqHelper(tree->gtCall.gtCallLateArgs, isLIR);
+                fgSetTreeSeqHelper(use.GetNode(), isLIR);
             }
 
             if ((tree->gtCall.gtCallType == CT_INDIRECT) && (tree->gtCall.gtCallCookie != nullptr))
@@ -21298,8 +21291,6 @@ void Compiler::fgDebugCheckFlags(GenTree* tree)
         {
             case GT_CALL:
 
-                GenTree*     args;
-                GenTree*     argx;
                 GenTreeCall* call;
 
                 call = tree->AsCall();
@@ -21315,27 +21306,25 @@ void Compiler::fgDebugCheckFlags(GenTree* tree)
                     }
                 }
 
-                for (args = call->gtCallArgs; args; args = args->gtOp.gtOp2)
+                for (GenTreeCall::Use& use : call->Args())
                 {
-                    argx = args->gtOp.gtOp1;
-                    fgDebugCheckFlags(argx);
+                    fgDebugCheckFlags(use.GetNode());
 
-                    chkFlags |= (argx->gtFlags & GTF_SIDE_EFFECT);
+                    chkFlags |= (use.GetNode()->gtFlags & GTF_SIDE_EFFECT);
 
-                    if (argx->gtFlags & GTF_ASG)
+                    if ((use.GetNode()->gtFlags & GTF_ASG) != 0)
                     {
                         treeFlags |= GTF_ASG;
                     }
                 }
 
-                for (args = call->gtCallLateArgs; args; args = args->gtOp.gtOp2)
+                for (GenTreeCall::Use& use : call->LateArgs())
                 {
-                    argx = args->gtOp.gtOp1;
-                    fgDebugCheckFlags(argx);
+                    fgDebugCheckFlags(use.GetNode());
 
-                    chkFlags |= (argx->gtFlags & GTF_SIDE_EFFECT);
+                    chkFlags |= (use.GetNode()->gtFlags & GTF_SIDE_EFFECT);
 
-                    if (argx->gtFlags & GTF_ASG)
+                    if ((use.GetNode()->gtFlags & GTF_ASG) != 0)
                     {
                         treeFlags |= GTF_ASG;
                     }
@@ -21355,15 +21344,15 @@ void Compiler::fgDebugCheckFlags(GenTree* tree)
 
                 if (call->IsUnmanaged() && (call->gtCallMoreFlags & GTF_CALL_M_UNMGD_THISCALL))
                 {
-                    if (call->gtCallArgs->gtOp.gtOp1->OperGet() == GT_NOP)
+                    if (call->gtCallArgs->GetNode()->OperGet() == GT_NOP)
                     {
-                        noway_assert(call->gtCallLateArgs->gtOp.gtOp1->TypeGet() == TYP_I_IMPL ||
-                                     call->gtCallLateArgs->gtOp.gtOp1->TypeGet() == TYP_BYREF);
+                        noway_assert(call->gtCallLateArgs->GetNode()->TypeGet() == TYP_I_IMPL ||
+                                     call->gtCallLateArgs->GetNode()->TypeGet() == TYP_BYREF);
                     }
                     else
                     {
-                        noway_assert(call->gtCallArgs->gtOp.gtOp1->TypeGet() == TYP_I_IMPL ||
-                                     call->gtCallArgs->gtOp.gtOp1->TypeGet() == TYP_BYREF);
+                        noway_assert(call->gtCallArgs->GetNode()->TypeGet() == TYP_I_IMPL ||
+                                     call->gtCallArgs->GetNode()->TypeGet() == TYP_BYREF);
                     }
                 }
                 break;
index c925e96..9267068 100644 (file)
@@ -1441,14 +1441,55 @@ AGAIN:
                 }
             }
 
-            if (Compare(op1->gtCall.gtCallLateArgs, op2->gtCall.gtCallLateArgs) &&
-                Compare(op1->gtCall.gtCallArgs, op2->gtCall.gtCallArgs) &&
-                Compare(op1->gtCall.gtControlExpr, op2->gtCall.gtControlExpr) &&
-                Compare(op1->gtCall.gtCallObjp, op2->gtCall.gtCallObjp))
+            if (!Compare(op1->AsCall()->gtCallObjp, op2->AsCall()->gtCallObjp))
             {
-                return true;
+                return false;
             }
-            break;
+
+            {
+                GenTreeCall::UseIterator i1   = op1->AsCall()->Args().begin();
+                GenTreeCall::UseIterator end1 = op1->AsCall()->Args().end();
+                GenTreeCall::UseIterator i2   = op2->AsCall()->Args().begin();
+                GenTreeCall::UseIterator end2 = op2->AsCall()->Args().end();
+
+                for (; (i1 != end1) && (i2 != end2); ++i1, ++i2)
+                {
+                    if (!Compare(i1->GetNode(), i2->GetNode()))
+                    {
+                        return false;
+                    }
+                }
+
+                if ((i1 != end1) || (i2 != end2))
+                {
+                    return false;
+                }
+
+                i1   = op1->AsCall()->LateArgs().begin();
+                end1 = op1->AsCall()->LateArgs().end();
+                i2   = op2->AsCall()->LateArgs().begin();
+                end2 = op2->AsCall()->LateArgs().end();
+
+                for (; (i1 != end1) && (i2 != end2); ++i1, ++i2)
+                {
+                    if (!Compare(i1->GetNode(), i2->GetNode()))
+                    {
+                        return false;
+                    }
+                }
+
+                if ((i1 != end1) || (i2 != end2))
+                {
+                    return false;
+                }
+            }
+
+            if (!Compare(op1->AsCall()->gtControlExpr, op2->AsCall()->gtControlExpr))
+            {
+                return false;
+            }
+
+            return true;
 
         case GT_ARR_ELEM:
 
@@ -1632,17 +1673,17 @@ AGAIN:
                 }
             }
 
-            if (tree->gtCall.gtCallArgs)
+            for (GenTreeCall::Use& use : tree->AsCall()->Args())
             {
-                if (gtHasRef(tree->gtCall.gtCallArgs, lclNum, defOnly))
+                if (gtHasRef(use.GetNode(), lclNum, defOnly))
                 {
                     return true;
                 }
             }
 
-            if (tree->gtCall.gtCallLateArgs)
+            for (GenTreeCall::Use& use : tree->AsCall()->LateArgs())
             {
-                if (gtHasRef(tree->gtCall.gtCallLateArgs, lclNum, defOnly))
+                if (gtHasRef(use.GetNode(), lclNum, defOnly))
                 {
                     return true;
                 }
@@ -2113,11 +2154,9 @@ AGAIN:
                 hash = genTreeHashAdd(hash, gtHashValue(temp));
             }
 
-            if (tree->gtCall.gtCallArgs)
+            for (GenTreeCall::Use& use : tree->AsCall()->Args())
             {
-                temp = tree->gtCall.gtCallArgs;
-                assert(temp);
-                hash = genTreeHashAdd(hash, gtHashValue(temp));
+                hash = genTreeHashAdd(hash, gtHashValue(use.GetNode()));
             }
 
             if (tree->gtCall.gtCallType == CT_INDIRECT)
@@ -2131,11 +2170,9 @@ AGAIN:
                 hash = genTreeHashAdd(hash, tree->gtCall.gtCallMethHnd);
             }
 
-            if (tree->gtCall.gtCallLateArgs)
+            for (GenTreeCall::Use& use : tree->AsCall()->LateArgs())
             {
-                temp = tree->gtCall.gtCallLateArgs;
-                assert(temp);
-                hash = genTreeHashAdd(hash, gtHashValue(temp));
+                hash = genTreeHashAdd(hash, gtHashValue(use.GetNode()));
             }
             break;
 
@@ -2471,6 +2508,46 @@ unsigned Compiler::gtSetListOrder(GenTree* list, bool isListCallArgs, bool callA
     return nxtlvl;
 }
 
+unsigned Compiler::gtSetCallArgsOrder(const GenTreeCall::UseList& args, bool lateArgs, int* callCostEx, int* callCostSz)
+{
+    unsigned level  = 0;
+    unsigned costEx = 0;
+    unsigned costSz = 0;
+
+    for (GenTreeCall::Use& use : args)
+    {
+        GenTree* argNode  = use.GetNode();
+        unsigned argLevel = gtSetEvalOrder(argNode);
+
+        if (argLevel > level)
+        {
+            level = argLevel;
+        }
+
+        if (argNode->gtCostEx != 0)
+        {
+            costEx += argNode->gtCostEx;
+            costEx += lateArgs ? 0 : IND_COST_EX;
+        }
+
+        if (argNode->gtCostSz != 0)
+        {
+            costSz += argNode->gtCostSz;
+#ifdef _TARGET_XARCH_
+            if (lateArgs) // push is smaller than mov to reg
+#endif
+            {
+                costSz += 1;
+            }
+        }
+    }
+
+    *callCostEx += costEx;
+    *callCostSz += costSz;
+
+    return level;
+}
+
 //-----------------------------------------------------------------------------
 // gtWalkOp: Traverse and mark an address expression
 //
@@ -4149,34 +4226,28 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree)
 
             /* Evaluate the arguments, right to left */
 
-            if (tree->gtCall.gtCallArgs)
+            if (tree->AsCall()->gtCallArgs != nullptr)
             {
-                const bool isListCallArgs = true;
-                const bool callArgsInRegs = false;
-                lvl2                      = gtSetListOrder(tree->gtCall.gtCallArgs, isListCallArgs, callArgsInRegs);
+                const bool lateArgs = false;
+                lvl2                = gtSetCallArgsOrder(tree->AsCall()->Args(), lateArgs, &costEx, &costSz);
                 if (level < lvl2)
                 {
                     level = lvl2;
                 }
-                costEx += tree->gtCall.gtCallArgs->gtCostEx;
-                costSz += tree->gtCall.gtCallArgs->gtCostSz;
             }
 
             /* Evaluate the temp register arguments list
              * This is a "hidden" list and its only purpose is to
              * extend the life of temps until we make the call */
 
-            if (tree->gtCall.gtCallLateArgs)
+            if (tree->AsCall()->gtCallLateArgs != nullptr)
             {
-                const bool isListCallArgs = true;
-                const bool callArgsInRegs = true;
-                lvl2                      = gtSetListOrder(tree->gtCall.gtCallLateArgs, isListCallArgs, callArgsInRegs);
+                const bool lateArgs = true;
+                lvl2                = gtSetCallArgsOrder(tree->AsCall()->LateArgs(), lateArgs, &costEx, &costSz);
                 if (level < lvl2)
                 {
                     level = lvl2;
                 }
-                costEx += tree->gtCall.gtCallLateArgs->gtCostEx;
-                costSz += tree->gtCall.gtCallLateArgs->gtCostSz;
             }
 
             if (tree->gtCall.gtCallType == CT_INDIRECT)
@@ -4693,13 +4764,19 @@ GenTree** GenTree::gtGetChildPointer(GenTree* parent) const
             {
                 return &(call->gtCallObjp);
             }
-            if (this == call->gtCallArgs)
+            for (GenTreeCall::Use& use : call->Args())
             {
-                return reinterpret_cast<GenTree**>(&(call->gtCallArgs));
+                if (this == use.GetNode())
+                {
+                    return &use.NodeRef();
+                }
             }
-            if (this == call->gtCallLateArgs)
+            for (GenTreeCall::Use& use : call->LateArgs())
             {
-                return reinterpret_cast<GenTree**>(&(call->gtCallLateArgs));
+                if (this == use.GetNode())
+                {
+                    return &use.NodeRef();
+                }
             }
             if (this == call->gtControlExpr)
             {
@@ -5009,12 +5086,23 @@ bool GenTree::TryGetUse(GenTree* def, GenTree*** use)
                     return true;
                 }
             }
-            if ((call->gtCallArgs != nullptr) && call->gtCallArgs->TryGetUseList(def, use))
+            for (GenTreeCall::Use& argUse : call->Args())
             {
-                return true;
+                if (argUse.GetNode() == def)
+                {
+                    *use = &argUse.NodeRef();
+                    return true;
+                }
             }
-
-            return (call->gtCallLateArgs != nullptr) && call->gtCallLateArgs->TryGetUseList(def, use);
+            for (GenTreeCall::Use& argUse : call->LateArgs())
+            {
+                if (argUse.GetNode() == def)
+                {
+                    *use = &argUse.NodeRef();
+                    return true;
+                }
+            }
+            return false;
         }
 
         // Binary nodes
@@ -5841,20 +5929,20 @@ GenTree* Compiler::gtNewSIMDVectorOne(var_types simdType, var_types baseType, un
 }
 #endif // FEATURE_SIMD
 
-GenTreeCall* Compiler::gtNewIndCallNode(GenTree* addr, var_types type, GenTreeArgList* args, IL_OFFSETX ilOffset)
+GenTreeCall* Compiler::gtNewIndCallNode(GenTree* addr, var_types type, GenTreeCall::Use* args, IL_OFFSETX ilOffset)
 {
     return gtNewCallNode(CT_INDIRECT, (CORINFO_METHOD_HANDLE)addr, type, args, ilOffset);
 }
 
 GenTreeCall* Compiler::gtNewCallNode(
-    gtCallTypes callType, CORINFO_METHOD_HANDLE callHnd, var_types type, GenTreeArgList* args, IL_OFFSETX ilOffset)
+    gtCallTypes callType, CORINFO_METHOD_HANDLE callHnd, var_types type, GenTreeCall::Use* args, IL_OFFSETX ilOffset)
 {
     GenTreeCall* node = new (this, GT_CALL) GenTreeCall(genActualType(type));
 
     node->gtFlags |= (GTF_CALL | GTF_GLOB_REF);
-    if (args)
+    for (GenTreeCall::Use& use : GenTreeCall::UseList(args))
     {
-        node->gtFlags |= (args->gtFlags & GTF_ALL_EFFECT);
+        node->gtFlags |= (use.GetNode()->gtFlags & GTF_ALL_EFFECT);
     }
     node->gtCallType      = callType;
     node->gtCallMethHnd   = callHnd;
@@ -6015,6 +6103,37 @@ GenTree* Compiler::gtNewInlineCandidateReturnExpr(GenTree* inlineCandidate, var_
     return node;
 }
 
+GenTreeCall::Use* Compiler::gtPrependNewCallArg(GenTree* node, GenTreeCall::Use* args)
+{
+    return new (this, CMK_ASTNode) GenTreeCall::Use(node, args);
+}
+
+GenTreeCall::Use* Compiler::gtInsertNewCallArgAfter(GenTree* node, GenTreeCall::Use* after)
+{
+    after->SetNext(new (this, CMK_ASTNode) GenTreeCall::Use(node, after->GetNext()));
+    return after->GetNext();
+}
+
+GenTreeCall::Use* Compiler::gtNewCallArgs(GenTree* node)
+{
+    return new (this, CMK_ASTNode) GenTreeCall::Use(node);
+}
+
+GenTreeCall::Use* Compiler::gtNewCallArgs(GenTree* node1, GenTree* node2)
+{
+    return new (this, CMK_ASTNode) GenTreeCall::Use(node1, gtNewCallArgs(node2));
+}
+
+GenTreeCall::Use* Compiler::gtNewCallArgs(GenTree* node1, GenTree* node2, GenTree* node3)
+{
+    return new (this, CMK_ASTNode) GenTreeCall::Use(node1, gtNewCallArgs(node2, node3));
+}
+
+GenTreeCall::Use* Compiler::gtNewCallArgs(GenTree* node1, GenTree* node2, GenTree* node3, GenTree* node4)
+{
+    return new (this, CMK_ASTNode) GenTreeCall::Use(node1, gtNewCallArgs(node2, node3, node4));
+}
+
 GenTreeArgList* Compiler::gtNewListNode(GenTree* op1, GenTreeArgList* op2)
 {
     assert((op1 != nullptr) && (op1->OperGet() != GT_LIST));
@@ -6098,10 +6217,9 @@ fgArgTabEntry* Compiler::gtArgEntryByNode(GenTreeCall* call, GenTree* node)
         {
             return curArgTabEntry;
         }
-        else if (curArgTabEntry->parent != nullptr)
+        else if (curArgTabEntry->use != nullptr)
         {
-            assert(curArgTabEntry->parent->OperIsList());
-            if (curArgTabEntry->parent->Current() == node)
+            if (curArgTabEntry->use->GetNode() == node)
             {
                 return curArgTabEntry;
             }
@@ -6160,14 +6278,15 @@ GenTree* Compiler::gtArgNodeByLateArgInx(GenTreeCall* call, unsigned lateArgInx)
     GenTree* argx     = nullptr;
     unsigned regIndex = 0;
 
-    for (GenTreeArgList *list = call->gtCall.gtCallLateArgs; list != nullptr; regIndex++, list = list->Rest())
+    for (GenTreeCall::Use& use : call->LateArgs())
     {
-        argx = list->Current();
+        argx = use.GetNode();
         assert(!argx->IsArgPlaceHolderNode()); // No placeholder nodes are in gtCallLateArgs;
         if (regIndex == lateArgInx)
         {
             break;
         }
+        regIndex++;
     }
     noway_assert(argx != nullptr);
     return argx;
@@ -6179,7 +6298,7 @@ GenTree* Compiler::gtArgNodeByLateArgInx(GenTreeCall* call, unsigned lateArgInx)
  */
 bool Compiler::gtArgIsThisPtr(fgArgTabEntry* argEntry)
 {
-    return (argEntry->parent == nullptr);
+    return (argEntry->use == nullptr);
 }
 
 /*****************************************************************************
@@ -7473,12 +7592,23 @@ GenTreeCall* Compiler::gtCloneExprCallHelper(GenTreeCall* tree, unsigned addFlag
     GenTreeCall* copy = new (this, GT_CALL) GenTreeCall(tree->TypeGet());
 
     copy->gtCallObjp = tree->gtCallObjp ? gtCloneExpr(tree->gtCallObjp, addFlags, deepVarNum, deepVarVal) : nullptr;
-    copy->gtCallArgs =
-        tree->gtCallArgs ? gtCloneExpr(tree->gtCallArgs, addFlags, deepVarNum, deepVarVal)->AsArgList() : nullptr;
     copy->gtCallMoreFlags = tree->gtCallMoreFlags;
-    copy->gtCallLateArgs  = tree->gtCallLateArgs
-                               ? gtCloneExpr(tree->gtCallLateArgs, addFlags, deepVarNum, deepVarVal)->AsArgList()
-                               : nullptr;
+    copy->gtCallArgs      = nullptr;
+    copy->gtCallLateArgs  = nullptr;
+
+    GenTreeCall::Use** argsTail = &copy->gtCallArgs;
+    for (GenTreeCall::Use& use : tree->Args())
+    {
+        *argsTail = gtNewCallArgs(gtCloneExpr(use.GetNode(), addFlags, deepVarNum, deepVarVal));
+        argsTail  = &((*argsTail)->NextRef());
+    }
+
+    argsTail = &copy->gtCallLateArgs;
+    for (GenTreeCall::Use& use : tree->LateArgs())
+    {
+        *argsTail = gtNewCallArgs(gtCloneExpr(use.GetNode(), addFlags, deepVarNum, deepVarVal));
+        argsTail  = &((*argsTail)->NextRef());
+    }
 
 #if !FEATURE_FIXED_OUT_ARGS
     copy->regArgList      = tree->regArgList;
@@ -7942,21 +8072,18 @@ GenTree* Compiler::gtGetThisArg(GenTreeCall* call)
             // There is no information about registers of late args for platforms
             // with FEATURE_FIXED_OUT_ARGS that is why this debug check is under
             // !FEATURE_FIXED_OUT_ARGS.
-            regNumber thisReg  = REG_ARG_0;
-            GenTree*  lateArgs = call->gtCallLateArgs;
-            regList   list     = call->regArgList;
-            int       index    = 0;
-            while (lateArgs != NULL)
+            regNumber thisReg = REG_ARG_0;
+            regList   list    = call->regArgList;
+            int       index   = 0;
+            for (GenTreeCall::Use& use : call->LateArgs())
             {
-                assert(lateArgs->gtOper == GT_LIST);
                 assert(index < call->regArgListCount);
                 regNumber curArgReg = list[index];
                 if (curArgReg == thisReg)
                 {
-                    assert(result == lateArgs->gtOp.gtOp1);
+                    assert(result == use.GetNode());
                 }
 
-                lateArgs = lateArgs->gtOp.gtOp2;
                 index++;
             }
 #endif // !FEATURE_FIXED_OUT_ARGS && defined(DEBUG)
@@ -8147,18 +8274,18 @@ unsigned GenTree::NumChildren()
             case GT_CALL:
             {
                 GenTreeCall* call = AsCall();
-                unsigned     res  = 0; // arg list(s) (including late args).
+                unsigned     res  = 0;
                 if (call->gtCallObjp != nullptr)
                 {
-                    res++; // Add objp?
+                    res++;
                 }
-                if (call->gtCallArgs != nullptr)
+                for (GenTreeCall::Use& use : call->Args())
                 {
-                    res++; // Add args?
+                    res++;
                 }
-                if (call->gtCallLateArgs != nullptr)
+                for (GenTreeCall::Use& use : call->LateArgs())
                 {
-                    res++; // Add late args?
+                    res++;
                 }
                 if (call->gtControlExpr != nullptr)
                 {
@@ -8323,64 +8450,67 @@ GenTree* GenTree::GetChild(unsigned childNum)
 
             case GT_CALL:
             {
-                // The if chain below assumes that all possible children are non-null.
-                // If some are null, "virtually skip them."
-                // If there isn't "virtually skip it."
                 GenTreeCall* call = AsCall();
 
-                if (call->gtCallObjp == nullptr)
-                {
-                    childNum++;
-                }
-                if (childNum >= 1 && call->gtCallArgs == nullptr)
-                {
-                    childNum++;
-                }
-                if (childNum >= 2 && call->gtCallLateArgs == nullptr)
-                {
-                    childNum++;
-                }
-                if (childNum >= 3 && call->gtControlExpr == nullptr)
-                {
-                    childNum++;
-                }
-                if (call->gtCallType == CT_INDIRECT)
+                if (call->gtCallObjp != nullptr)
                 {
-                    if (childNum >= 4 && call->gtCallCookie == nullptr)
+                    if (childNum == 0)
                     {
-                        childNum++;
+                        return call->gtCallObjp;
                     }
-                }
 
-                if (childNum == 0)
-                {
-                    return call->gtCallObjp;
+                    childNum--;
                 }
-                else if (childNum == 1)
+
+                for (GenTreeCall::Use& use : call->Args())
                 {
-                    return call->gtCallArgs;
+                    if (childNum == 0)
+                    {
+                        return use.GetNode();
+                    }
+
+                    childNum--;
                 }
-                else if (childNum == 2)
+
+                for (GenTreeCall::Use& use : call->LateArgs())
                 {
-                    return call->gtCallLateArgs;
+                    if (childNum == 0)
+                    {
+                        return use.GetNode();
+                    }
+
+                    childNum--;
                 }
-                else if (childNum == 3)
+
+                if (call->gtControlExpr != nullptr)
                 {
-                    return call->gtControlExpr;
+                    if (childNum == 0)
+                    {
+                        return call->gtControlExpr;
+                    }
+
+                    childNum--;
                 }
-                else
+
+                if ((call->gtCallType == CT_INDIRECT) && (call->gtCallCookie != nullptr))
                 {
-                    assert(call->gtCallType == CT_INDIRECT);
-                    if (childNum == 4)
+                    if (childNum == 0)
                     {
                         return call->gtCallCookie;
                     }
-                    else
+
+                    childNum--;
+                }
+
+                if (call->gtCallAddr != nullptr)
+                {
+                    if (childNum == 0)
                     {
-                        assert(childNum == 5);
                         return call->gtCallAddr;
                     }
                 }
+
+                unreached();
             }
             case GT_NONE:
                 unreached();
@@ -8888,9 +9018,9 @@ void          GenTreeUseEdgeIterator::AdvanceCall()
         case CALL_ARGS:
             if (m_statePtr != nullptr)
             {
-                GenTreeArgList* argNode = static_cast<GenTreeArgList*>(m_statePtr);
-                m_edge                  = &argNode->gtOp1;
-                m_statePtr              = argNode->Rest();
+                GenTreeCall::Use* use = static_cast<GenTreeCall::Use*>(m_statePtr);
+                m_edge                = &use->NodeRef();
+                m_statePtr            = use->GetNext();
                 return;
             }
             m_statePtr = call->gtCallLateArgs;
@@ -8900,9 +9030,9 @@ void          GenTreeUseEdgeIterator::AdvanceCall()
         case CALL_LATE_ARGS:
             if (m_statePtr != nullptr)
             {
-                GenTreeArgList* argNode = static_cast<GenTreeArgList*>(m_statePtr);
-                m_edge                  = &argNode->gtOp1;
-                m_statePtr              = argNode->Rest();
+                GenTreeCall::Use* use = static_cast<GenTreeCall::Use*>(m_statePtr);
+                m_edge                = &use->NodeRef();
+                m_statePtr            = use->GetNext();
                 return;
             }
             m_advance = &GenTreeUseEdgeIterator::AdvanceCall<CALL_CONTROL_EXPR>;
@@ -10961,18 +11091,13 @@ void Compiler::gtDispTree(GenTree*     tree,
 #if !FEATURE_FIXED_OUT_ARGS
                 regList list = call->regArgList;
 #endif
-                /* process the late argument list */
                 int lateArgIndex = 0;
-                for (GenTreeArgList* lateArgs = call->gtCallLateArgs; lateArgs;
-                     (lateArgIndex++, lateArgs = lateArgs->Rest()))
+                for (GenTreeCall::Use& use : call->LateArgs())
                 {
-                    GenTree* argx;
-
-                    argx = lateArgs->Current();
-
-                    IndentInfo arcType = (lateArgs->Rest() == nullptr) ? IIArcBottom : IIArc;
-                    gtGetLateArgMsg(call, argx, lateArgIndex, -1, bufp, sizeof(buf));
-                    gtDispChild(argx, indentStack, arcType, bufp, topOnly);
+                    IndentInfo arcType = (use.GetNext() == nullptr) ? IIArcBottom : IIArc;
+                    gtGetLateArgMsg(call, use.GetNode(), lateArgIndex, -1, bufp, sizeof(buf));
+                    gtDispChild(use.GetNode(), indentStack, arcType, bufp, topOnly);
+                    lateArgIndex++;
                 }
             }
         }
@@ -11320,35 +11445,25 @@ void Compiler::gtGetLateArgMsg(
 //
 void Compiler::gtDispArgList(GenTreeCall* call, IndentStack* indentStack)
 {
-    GenTree*  args      = call->gtCallArgs;
-    unsigned  argnum    = 0;
-    const int BufLength = 256;
-    char      buf[BufLength];
-    char*     bufp        = &buf[0];
-    unsigned  numChildren = call->NumChildren();
-    assert(numChildren != 0);
-    bool argListIsLastChild = (args == call->GetChild(numChildren - 1));
+    unsigned numChildren = call->NumChildren();
+    GenTree* lastArgNode = call->GetChild(numChildren - 1);
+
+    unsigned argnum = 0;
 
-    IndentInfo arcType = IIArc;
     if (call->gtCallObjp != nullptr)
     {
         argnum++;
     }
 
-    while (args != nullptr)
+    for (GenTreeCall::Use& use : call->Args())
     {
-        assert(args->gtOper == GT_LIST);
-        GenTree* arg = args->gtOp.gtOp1;
-        if (!arg->IsNothingNode() && !arg->IsArgPlaceHolderNode())
+        GenTree* argNode = use.GetNode();
+        if (!argNode->IsNothingNode() && !argNode->IsArgPlaceHolderNode())
         {
-            gtGetArgMsg(call, arg, argnum, -1, bufp, BufLength);
-            if (argListIsLastChild && (args->gtOp.gtOp2 == nullptr))
-            {
-                arcType = IIArcBottom;
-            }
-            gtDispChild(arg, indentStack, arcType, bufp, false);
+            char buf[256];
+            gtGetArgMsg(call, argNode, argnum, -1, buf, sizeof(buf));
+            gtDispChild(argNode, indentStack, (argNode == lastArgNode) ? IIArcBottom : IIArc, buf, false);
         }
-        args = args->gtOp.gtOp2;
         argnum++;
     }
 }
@@ -11746,8 +11861,8 @@ GenTree* Compiler::gtFoldExprCall(GenTreeCall* call)
         case CORINFO_INTRINSIC_TypeNEQ:
         {
             noway_assert(call->TypeGet() == TYP_INT);
-            GenTree* op1 = call->gtCallArgs->gtOp.gtOp1;
-            GenTree* op2 = call->gtCallArgs->gtOp.gtOp2->gtOp.gtOp1;
+            GenTree* op1 = call->gtCallArgs->GetNode();
+            GenTree* op2 = call->gtCallArgs->GetNext()->GetNode();
 
             // If either operand is known to be a RuntimeType, this can be folded
             GenTree* result = gtFoldTypeEqualityCall(methodID, op1, op2);
@@ -11768,7 +11883,7 @@ GenTree* Compiler::gtFoldExprCall(GenTreeCall* call)
     if (ni == NI_System_Enum_HasFlag)
     {
         GenTree* thisOp = call->gtCallObjp;
-        GenTree* flagOp = call->gtCallArgs->gtOp.gtOp1;
+        GenTree* flagOp = call->gtCallArgs->GetNode();
         GenTree* result = gtOptimizeEnumHasFlag(thisOp, flagOp);
 
         if (result != nullptr)
@@ -11913,8 +12028,8 @@ GenTree* Compiler::gtCreateHandleCompare(genTreeOps             oper,
     assert(typeCheckInliningResult == CORINFO_INLINE_TYPECHECK_USE_HELPER);
 
     // Emit a call to a runtime helper
-    GenTreeArgList* helperArgs = gtNewArgList(op1, op2);
-    GenTree*        ret        = gtNewHelperCallNode(CORINFO_HELP_ARE_TYPES_EQUIVALENT, TYP_INT, helperArgs);
+    GenTreeCall::Use* helperArgs = gtNewCallArgs(op1, op2);
+    GenTree*          ret        = gtNewHelperCallNode(CORINFO_HELP_ARE_TYPES_EQUIVALENT, TYP_INT, helperArgs);
     if (oper == GT_EQ)
     {
         ret = gtNewOperNode(GT_NE, TYP_INT, ret, gtNewIconNode(0, TYP_INT));
@@ -11987,8 +12102,8 @@ GenTree* Compiler::gtFoldTypeCompare(GenTree* tree)
     if (op1IsFromHandle && op2IsFromHandle)
     {
         JITDUMP("Optimizing compare of types-from-handles to instead compare handles\n");
-        GenTree*             op1ClassFromHandle = tree->gtOp.gtOp1->gtCall.gtCallArgs->gtOp.gtOp1;
-        GenTree*             op2ClassFromHandle = tree->gtOp.gtOp2->gtCall.gtCallArgs->gtOp.gtOp1;
+        GenTree*             op1ClassFromHandle = tree->AsOp()->gtOp1->AsCall()->gtCallArgs->GetNode();
+        GenTree*             op2ClassFromHandle = tree->AsOp()->gtOp2->AsCall()->gtCallArgs->GetNode();
         GenTree*             op1TunneledHandle  = nullptr;
         GenTree*             op2TunneledHandle  = nullptr;
         CORINFO_CLASS_HANDLE cls1Hnd            = NO_CLASS_HANDLE;
@@ -12089,7 +12204,7 @@ GenTree* Compiler::gtFoldTypeCompare(GenTree* tree)
     GenTree* const opOther  = op1IsFromHandle ? op2 : op1;
 
     // Tunnel through the handle operand to get at the class handle involved.
-    GenTree* const       opHandleArgument = opHandle->gtCall.gtCallArgs->gtOp.gtOp1;
+    GenTree* const       opHandleArgument = opHandle->AsCall()->gtCallArgs->GetNode();
     CORINFO_CLASS_HANDLE clsHnd           = gtGetHelperArgClassHandle(opHandleArgument);
 
     // If we couldn't find the class handle, give up.
@@ -12617,8 +12732,8 @@ GenTree* Compiler::gtTryRemoveBoxUpstreamEffects(GenTree* op, BoxRemovalOptions
         }
         else if (asgSrcOper == GT_CALL)
         {
-            GenTreeCall* newobjCall = asgSrc->AsCall();
-            GenTree*     newobjArgs = newobjCall->gtCallArgs;
+            GenTreeCall*      newobjCall = asgSrc->AsCall();
+            GenTreeCall::Use* newobjArgs = newobjCall->gtCallArgs;
 
             // In R2R expansions the handle may not be an explicit operand to the helper,
             // so we can't remove the box.
@@ -12629,7 +12744,7 @@ GenTree* Compiler::gtTryRemoveBoxUpstreamEffects(GenTree* op, BoxRemovalOptions
                 return nullptr;
             }
 
-            boxTypeHandle = newobjArgs->AsArgList()->Current();
+            boxTypeHandle = newobjArgs->GetNode();
         }
         else
         {
@@ -13908,7 +14023,7 @@ GenTree* Compiler::gtFoldExprConst(GenTree* tree)
 
             op2 = op1;
             op1 = gtNewHelperCallNode(CORINFO_HELP_OVERFLOW, TYP_VOID,
-                                      gtNewArgList(gtNewIconNode(compCurBB->bbTryIndex)));
+                                      gtNewCallArgs(gtNewIconNode(compCurBB->bbTryIndex)));
 
             // op1 is a call to the JIT helper that throws an Overflow exception
             // attach the ExcSet for VNF_OverflowExc(Void) to this call
@@ -14583,8 +14698,8 @@ GenTree* Compiler::gtNewRefCOMfield(GenTree*                objPtr,
            pFieldInfo->fieldAccessor == CORINFO_FIELD_STATIC_ADDR_HELPER);
 
     /* If we can't access it directly, we need to call a helper function */
-    GenTreeArgList* args       = nullptr;
-    var_types       helperType = TYP_BYREF;
+    GenTreeCall::Use* args       = nullptr;
+    var_types         helperType = TYP_BYREF;
 
     if (pFieldInfo->fieldAccessor == CORINFO_FIELD_INSTANCE_HELPER)
     {
@@ -14606,7 +14721,7 @@ GenTree* Compiler::gtNewRefCOMfield(GenTree*                objPtr,
                 assg = gtNewCastNode(TYP_FLOAT, assg, false, TYP_FLOAT);
             }
 
-            args       = gtNewArgList(assg);
+            args       = gtNewCallArgs(assg);
             helperType = TYP_VOID;
         }
         else if (access & CORINFO_ACCESS_GET)
@@ -14625,7 +14740,7 @@ GenTree* Compiler::gtNewRefCOMfield(GenTree*                objPtr,
     if (pFieldInfo->helper == CORINFO_HELP_GETFIELDSTRUCT || pFieldInfo->helper == CORINFO_HELP_SETFIELDSTRUCT)
     {
         assert(pFieldInfo->structType != nullptr);
-        args = gtNewListNode(gtNewIconEmbClsHndNode(pFieldInfo->structType), args);
+        args = gtPrependNewCallArg(gtNewIconEmbClsHndNode(pFieldInfo->structType), args);
     }
 
     GenTree* fieldHnd = impTokenToHandle(pResolvedToken);
@@ -14634,7 +14749,7 @@ GenTree* Compiler::gtNewRefCOMfield(GenTree*                objPtr,
         return nullptr;
     }
 
-    args = gtNewListNode(fieldHnd, args);
+    args = gtPrependNewCallArg(fieldHnd, args);
 
     // If it's a static field, we shouldn't have an object node
     // If it's an instance field, we have an object node
@@ -14642,7 +14757,7 @@ GenTree* Compiler::gtNewRefCOMfield(GenTree*                objPtr,
 
     if (objPtr != nullptr)
     {
-        args = gtNewListNode(objPtr, args);
+        args = gtPrependNewCallArg(objPtr, args);
     }
 
     GenTreeCall* call = gtNewHelperCallNode(pFieldInfo->helper, genActualType(helperType), args);
@@ -14749,18 +14864,18 @@ bool Compiler::gtNodeHasSideEffects(GenTree* tree, unsigned flags)
             if (!call->HasSideEffects(this, ignoreExceptions, ignoreCctors))
             {
                 // If this call is otherwise side effect free, check its arguments.
-                for (GenTreeArgList* args = call->gtCallArgs; args != nullptr; args = args->Rest())
+                for (GenTreeCall::Use& use : call->Args())
                 {
-                    if (gtTreeHasSideEffects(args->Current(), flags))
+                    if (gtTreeHasSideEffects(use.GetNode(), flags))
                     {
                         return true;
                     }
                 }
                 // I'm a little worried that args that assign to temps that are late args will look like
                 // side effects...but better to be conservative for now.
-                for (GenTreeArgList* args = call->gtCallLateArgs; args != nullptr; args = args->Rest())
+                for (GenTreeCall::Use& use : call->LateArgs())
                 {
-                    if (gtTreeHasSideEffects(args->Current(), flags))
+                    if (gtTreeHasSideEffects(use.GetNode(), flags))
                     {
                         return true;
                     }
@@ -16946,8 +17061,8 @@ CORINFO_CLASS_HANDLE Compiler::gtGetHelperCallClassHandle(GenTreeCall* call, boo
         case CORINFO_HELP_ISINSTANCEOFANY:
         {
             // Fetch the class handle from the helper call arglist
-            GenTreeArgList*      args    = call->gtCallArgs;
-            GenTree*             typeArg = args->Current();
+            GenTreeCall::Use*    args    = call->gtCallArgs;
+            GenTree*             typeArg = args->GetNode();
             CORINFO_CLASS_HANDLE castHnd = gtGetHelperArgClassHandle(typeArg);
 
             // We generally assume the type being cast to is the best type
@@ -16973,7 +17088,7 @@ CORINFO_CLASS_HANDLE Compiler::gtGetHelperCallClassHandle(GenTreeCall* call, boo
             // type from the value being cast instead.
             if (castHnd == nullptr)
             {
-                GenTree* valueArg = args->Rest()->Current();
+                GenTree* valueArg = args->GetNext()->GetNode();
                 castHnd           = gtGetClassHandle(valueArg, pIsExact, pIsNonNull);
             }
 
index ed8b8cd..290fc8c 100644 (file)
@@ -2385,7 +2385,7 @@ class GenTreeUseEdgeIterator final
     AdvanceFn m_advance;
     GenTree*  m_node;
     GenTree** m_edge;
-    // Pointer sized state storage, GenTreeArgList* or GenTreePhi::Use* currently.
+    // Pointer sized state storage, GenTreeArgList* or GenTreePhi::Use* or GenTreeCall::Use* currently.
     void* m_statePtr;
     // Integer sized state storage, usually the operand index for non-list based nodes.
     int m_state;
@@ -3315,13 +3315,121 @@ class fgArgInfo;
 
 struct GenTreeCall final : public GenTree
 {
-    GenTree*        gtCallObjp;     // The instance argument ('this' pointer)
-    GenTreeArgList* gtCallArgs;     // The list of arguments in original evaluation order
-    GenTreeArgList* gtCallLateArgs; // On x86:     The register arguments in an optimal order
-                                    // On ARM/x64: - also includes any outgoing arg space arguments
-                                    //             - that were evaluated into a temp LclVar
+    class Use
+    {
+        GenTree* m_node;
+        Use*     m_next;
+
+    public:
+        Use(GenTree* node, Use* next = nullptr) : m_node(node), m_next(next)
+        {
+        }
+
+        GenTree*& NodeRef()
+        {
+            return m_node;
+        }
+
+        GenTree* GetNode() const
+        {
+            return m_node;
+        }
+
+        void SetNode(GenTree* node)
+        {
+            assert(node != nullptr);
+            m_node = node;
+        }
+
+        Use*& NextRef()
+        {
+            return m_next;
+        }
+
+        Use* GetNext() const
+        {
+            return m_next;
+        }
+
+        void SetNext(Use* next)
+        {
+            m_next = next;
+        }
+    };
+
+    class UseIterator
+    {
+        Use* m_use;
+
+    public:
+        UseIterator(Use* use) : m_use(use)
+        {
+        }
+
+        Use& operator*() const
+        {
+            return *m_use;
+        }
+
+        Use* operator->() const
+        {
+            return m_use;
+        }
+
+        UseIterator& operator++()
+        {
+            m_use = m_use->GetNext();
+            return *this;
+        }
+
+        bool operator==(const UseIterator& i) const
+        {
+            return m_use == i.m_use;
+        }
+
+        bool operator!=(const UseIterator& i) const
+        {
+            return m_use != i.m_use;
+        }
+    };
+
+    class UseList
+    {
+        Use* m_uses;
+
+    public:
+        UseList(Use* uses) : m_uses(uses)
+        {
+        }
+
+        UseIterator begin() const
+        {
+            return UseIterator(m_uses);
+        }
+
+        UseIterator end() const
+        {
+            return UseIterator(nullptr);
+        }
+    };
+
+    GenTree* gtCallObjp;     // The instance argument ('this' pointer)
+    Use*     gtCallArgs;     // The list of arguments in original evaluation order
+    Use*     gtCallLateArgs; // On x86:     The register arguments in an optimal order
+                             // On ARM/x64: - also includes any outgoing arg space arguments
+                             //             - that were evaluated into a temp LclVar
     fgArgInfo* fgArgInfo;
 
+    UseList Args()
+    {
+        return UseList(gtCallArgs);
+    }
+
+    UseList LateArgs()
+    {
+        return UseList(gtCallLateArgs);
+    }
+
 #if !FEATURE_FIXED_OUT_ARGS
     int     regArgListCount;
     regList regArgList;
index 4a2483a..cdac19d 100644 (file)
@@ -196,13 +196,13 @@ Compiler::fgWalkResult Compiler::gsMarkPtrsAndAssignGroups(GenTree** pTree, fgWa
                     comp->fgWalkTreePre(&tree->gtCall.gtCallObjp, gsMarkPtrsAndAssignGroups, (void*)&newState);
                 }
 
-                for (GenTreeArgList* args = tree->gtCall.gtCallArgs; args; args = args->Rest())
+                for (GenTreeCall::Use& use : tree->AsCall()->Args())
                 {
-                    comp->fgWalkTreePre(&args->Current(), gsMarkPtrsAndAssignGroups, (void*)&newState);
+                    comp->fgWalkTreePre(&use.NodeRef(), gsMarkPtrsAndAssignGroups, (void*)&newState);
                 }
-                for (GenTreeArgList* args = tree->gtCall.gtCallLateArgs; args; args = args->Rest())
+                for (GenTreeCall::Use& use : tree->AsCall()->LateArgs())
                 {
-                    comp->fgWalkTreePre(&args->Current(), gsMarkPtrsAndAssignGroups, (void*)&newState);
+                    comp->fgWalkTreePre(&use.NodeRef(), gsMarkPtrsAndAssignGroups, (void*)&newState);
                 }
 
                 if (tree->gtCall.gtCallType == CT_INDIRECT)
index 7fff80e..8a9f646 100644 (file)
@@ -858,20 +858,20 @@ void Compiler::impAssignTempGen(unsigned             tmpNum,
  *  prefixTree at the head of the list.
  */
 
-GenTreeArgList* Compiler::impPopList(unsigned count, CORINFO_SIG_INFO* sig, GenTreeArgList* prefixTree)
+GenTreeCall::Use* Compiler::impPopCallArgs(unsigned count, CORINFO_SIG_INFO* sig, GenTreeCall::Use* prefixArgs)
 {
     assert(sig == nullptr || count == sig->numArgs);
 
     CORINFO_CLASS_HANDLE structType;
-    GenTreeArgList*      treeList;
+    GenTreeCall::Use*    argList;
 
     if (Target::g_tgtArgOrder == Target::ARG_ORDER_R2L)
     {
-        treeList = nullptr;
+        argList = nullptr;
     }
     else
     { // ARG_ORDER_L2R
-        treeList = prefixTree;
+        argList = prefixArgs;
     }
 
     while (count--)
@@ -917,7 +917,7 @@ GenTreeArgList* Compiler::impPopList(unsigned count, CORINFO_SIG_INFO* sig, GenT
         }
 
         /* NOTE: we defer bashing the type for I_IMPL to fgMorphArgs */
-        treeList = gtNewListNode(temp, treeList);
+        argList = gtPrependNewCallArg(temp, argList);
     }
 
     if (sig != nullptr)
@@ -936,28 +936,28 @@ GenTreeArgList* Compiler::impPopList(unsigned count, CORINFO_SIG_INFO* sig, GenT
         CORINFO_ARG_LIST_HANDLE argLst = sig->args;
         CORINFO_CLASS_HANDLE    argClass;
         CORINFO_CLASS_HANDLE    argRealClass;
-        GenTreeArgList*         args;
+        GenTreeCall::Use*       arg;
 
-        for (args = treeList, count = sig->numArgs; count > 0; args = args->Rest(), count--)
+        for (arg = argList, count = sig->numArgs; count > 0; arg = arg->GetNext(), count--)
         {
-            PREFIX_ASSUME(args != nullptr);
+            PREFIX_ASSUME(arg != nullptr);
 
             CorInfoType corType = strip(info.compCompHnd->getArgType(sig, argLst, &argClass));
 
             // insert implied casts (from float to double or double to float)
 
-            if (corType == CORINFO_TYPE_DOUBLE && args->Current()->TypeGet() == TYP_FLOAT)
+            if ((corType == CORINFO_TYPE_DOUBLE) && (arg->GetNode()->TypeGet() == TYP_FLOAT))
             {
-                args->Current() = gtNewCastNode(TYP_DOUBLE, args->Current(), false, TYP_DOUBLE);
+                arg->SetNode(gtNewCastNode(TYP_DOUBLE, arg->GetNode(), false, TYP_DOUBLE));
             }
-            else if (corType == CORINFO_TYPE_FLOAT && args->Current()->TypeGet() == TYP_DOUBLE)
+            else if ((corType == CORINFO_TYPE_FLOAT) && (arg->GetNode()->TypeGet() == TYP_DOUBLE))
             {
-                args->Current() = gtNewCastNode(TYP_FLOAT, args->Current(), false, TYP_FLOAT);
+                arg->SetNode(gtNewCastNode(TYP_FLOAT, arg->GetNode(), false, TYP_FLOAT));
             }
 
             // insert any widening or narrowing casts for backwards compatibility
 
-            args->Current() = impImplicitIorI4Cast(args->Current(), JITtype2varType(corType));
+            arg->SetNode(impImplicitIorI4Cast(arg->GetNode(), JITtype2varType(corType)));
 
             if (corType != CORINFO_TYPE_CLASS && corType != CORINFO_TYPE_BYREF && corType != CORINFO_TYPE_PTR &&
                 corType != CORINFO_TYPE_VAR && (argRealClass = info.compCompHnd->getArgClass(sig, argLst)) != nullptr)
@@ -967,9 +967,9 @@ GenTreeArgList* Compiler::impPopList(unsigned count, CORINFO_SIG_INFO* sig, GenT
                 // primitive types.
                 // We will try to adjust for this case here to avoid breaking customers code (see VSW 485789 for
                 // details).
-                if (corType == CORINFO_TYPE_VALUECLASS && !varTypeIsStruct(args->Current()))
+                if (corType == CORINFO_TYPE_VALUECLASS && !varTypeIsStruct(arg->GetNode()->TypeGet()))
                 {
-                    args->Current() = impNormStructVal(args->Current(), argRealClass, (unsigned)CHECK_SPILL_ALL, true);
+                    arg->SetNode(impNormStructVal(arg->GetNode(), argRealClass, (unsigned)CHECK_SPILL_ALL, true));
                 }
 
                 // Make sure that all valuetypes (including enums) that we push are loaded.
@@ -990,15 +990,15 @@ GenTreeArgList* Compiler::impPopList(unsigned count, CORINFO_SIG_INFO* sig, GenT
 
         // Simple in-place reversal to place treeList
         // at the end of a reversed prefixTree
-        while (prefixTree != nullptr)
+        while (prefixArgs != nullptr)
         {
-            GenTreeArgList* next = prefixTree->Rest();
-            prefixTree->Rest()   = treeList;
-            treeList             = prefixTree;
-            prefixTree           = next;
+            GenTreeCall::Use* next = prefixArgs->GetNext();
+            prefixArgs->SetNext(argList);
+            argList    = prefixArgs;
+            prefixArgs = next;
         }
     }
-    return treeList;
+    return argList;
 }
 
 /*****************************************************************************
@@ -1007,12 +1007,11 @@ GenTreeArgList* Compiler::impPopList(unsigned count, CORINFO_SIG_INFO* sig, GenT
  *  The first "skipReverseCount" items are not reversed.
  */
 
-GenTreeArgList* Compiler::impPopRevList(unsigned count, CORINFO_SIG_INFO* sig, unsigned skipReverseCount)
-
+GenTreeCall::Use* Compiler::impPopReverseCallArgs(unsigned count, CORINFO_SIG_INFO* sig, unsigned skipReverseCount)
 {
     assert(skipReverseCount <= count);
 
-    GenTreeArgList* list = impPopList(count, sig);
+    GenTreeCall::Use* list = impPopCallArgs(count, sig);
 
     // reverse the list
     if (list == nullptr || skipReverseCount == count)
@@ -1020,8 +1019,8 @@ GenTreeArgList* Compiler::impPopRevList(unsigned count, CORINFO_SIG_INFO* sig, u
         return list;
     }
 
-    GenTreeArgList* ptr          = nullptr; // Initialized to the first node that needs to be reversed
-    GenTreeArgList* lastSkipNode = nullptr; // Will be set to the last node that does not need to be reversed
+    GenTreeCall::Use* ptr          = nullptr; // Initialized to the first node that needs to be reversed
+    GenTreeCall::Use* lastSkipNode = nullptr; // Will be set to the last node that does not need to be reversed
 
     if (skipReverseCount == 0)
     {
@@ -1033,26 +1032,26 @@ GenTreeArgList* Compiler::impPopRevList(unsigned count, CORINFO_SIG_INFO* sig, u
         // Get to the first node that needs to be reversed
         for (unsigned i = 0; i < skipReverseCount - 1; i++)
         {
-            lastSkipNode = lastSkipNode->Rest();
+            lastSkipNode = lastSkipNode->GetNext();
         }
 
         PREFIX_ASSUME(lastSkipNode != nullptr);
-        ptr = lastSkipNode->Rest();
+        ptr = lastSkipNode->GetNext();
     }
 
-    GenTreeArgList* reversedList = nullptr;
+    GenTreeCall::Use* reversedList = nullptr;
 
     do
     {
-        GenTreeArgList* tmp = ptr->Rest();
-        ptr->Rest()         = reversedList;
-        reversedList        = ptr;
-        ptr                 = tmp;
+        GenTreeCall::Use* tmp = ptr->GetNext();
+        ptr->SetNext(reversedList);
+        reversedList = ptr;
+        ptr          = tmp;
     } while (ptr != nullptr);
 
     if (skipReverseCount)
     {
-        lastSkipNode->Rest() = reversedList;
+        lastSkipNode->SetNext(reversedList);
         return list;
     }
     else
@@ -1205,7 +1204,7 @@ GenTree* Compiler::impAssignStructPtr(GenTree*             destAddr,
             // Case of call returning a struct via hidden retbuf arg
 
             // insert the return value buffer into the argument list as first byref parameter
-            src->gtCall.gtCallArgs = gtNewListNode(destAddr, src->gtCall.gtCallArgs);
+            src->AsCall()->gtCallArgs = gtPrependNewCallArg(destAddr, src->AsCall()->gtCallArgs);
 
             // now returns void, not a struct
             src->gtType = TYP_VOID;
@@ -1285,7 +1284,7 @@ GenTree* Compiler::impAssignStructPtr(GenTree*             destAddr,
         if (call->HasRetBufArg())
         {
             // insert the return value buffer into the argument list as first byref parameter
-            call->gtCallArgs = gtNewListNode(destAddr, call->gtCallArgs);
+            call->gtCallArgs = gtPrependNewCallArg(destAddr, call->gtCallArgs);
 
             // now returns void, not a struct
             src->gtType  = TYP_VOID;
@@ -1895,7 +1894,7 @@ GenTreeCall* Compiler::impReadyToRunHelperToTree(
     CORINFO_RESOLVED_TOKEN* pResolvedToken,
     CorInfoHelpFunc         helper,
     var_types               type,
-    GenTreeArgList*         args /* =NULL*/,
+    GenTreeCall::Use*       args /* = nullptr */,
     CORINFO_LOOKUP_KIND*    pGenericLookupKind /* =NULL. Only used with generics */)
 {
     CORINFO_CONST_LOOKUP lookup;
@@ -2031,12 +2030,12 @@ GenTree* Compiler::impRuntimeLookupToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken
         if (opts.IsReadyToRun())
         {
             return impReadyToRunHelperToTree(pResolvedToken, CORINFO_HELP_READYTORUN_GENERIC_HANDLE, TYP_I_IMPL,
-                                             gtNewArgList(ctxTree), &pLookup->lookupKind);
+                                             gtNewCallArgs(ctxTree), &pLookup->lookupKind);
         }
 #endif
         GenTree* argNode =
             gtNewIconEmbHndNode(pRuntimeLookup->signature, nullptr, GTF_ICON_TOKEN_HDL, compileTimeHandle);
-        GenTreeArgList* helperArgs = gtNewArgList(ctxTree, argNode);
+        GenTreeCall::Use* helperArgs = gtNewCallArgs(ctxTree, argNode);
 
         return gtNewHelperCallNode(pRuntimeLookup->helper, TYP_I_IMPL, helperArgs);
     }
@@ -2138,8 +2137,8 @@ GenTree* Compiler::impRuntimeLookupToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken
     // Call to helper
     GenTree* argNode = gtNewIconEmbHndNode(pRuntimeLookup->signature, nullptr, GTF_ICON_TOKEN_HDL, compileTimeHandle);
 
-    GenTreeArgList* helperArgs = gtNewArgList(ctxTree, argNode);
-    GenTree*        helperCall = gtNewHelperCallNode(pRuntimeLookup->helper, TYP_I_IMPL, helperArgs);
+    GenTreeCall::Use* helperArgs = gtNewCallArgs(ctxTree, argNode);
+    GenTree*          helperCall = gtNewHelperCallNode(pRuntimeLookup->helper, TYP_I_IMPL, helperArgs);
 
     // Check for null and possibly call helper
     GenTree* relop = gtNewOperNode(GT_NE, TYP_INT, handle, gtNewIconNode(0, TYP_I_IMPL));
@@ -3031,7 +3030,7 @@ GenTree* Compiler::impInitializeArrayIntrinsic(CORINFO_SIG_INFO* sig)
     }
 
     // Strip helper call away
-    fieldTokenNode = fieldTokenNode->gtCall.gtCallArgs->Current();
+    fieldTokenNode = fieldTokenNode->AsCall()->gtCallArgs->GetNode();
 
     if (fieldTokenNode->gtOper == GT_IND)
     {
@@ -3131,11 +3130,11 @@ GenTree* Compiler::impInitializeArrayIntrinsic(CORINFO_SIG_INFO* sig)
             return nullptr;
         }
 
-        GenTreeArgList* tokenArg = newArrayCall->gtCall.gtCallArgs;
+        GenTreeCall::Use* tokenArg = newArrayCall->gtCall.gtCallArgs;
         assert(tokenArg != nullptr);
-        GenTreeArgList* numArgsArg = tokenArg->Rest();
+        GenTreeCall::Use* numArgsArg = tokenArg->GetNext();
         assert(numArgsArg != nullptr);
-        GenTreeArgList* argsArg = numArgsArg->Rest();
+        GenTreeCall::Use* argsArg = numArgsArg->GetNext();
         assert(argsArg != nullptr);
 
         //
@@ -3144,13 +3143,13 @@ GenTree* Compiler::impInitializeArrayIntrinsic(CORINFO_SIG_INFO* sig)
         // be at most 64 arguments - 32 lengths and 32 lower bounds.
         //
 
-        if ((!numArgsArg->Current()->IsCnsIntOrI()) || (numArgsArg->Current()->AsIntCon()->IconValue() < 1) ||
-            (numArgsArg->Current()->AsIntCon()->IconValue() > 64))
+        if ((!numArgsArg->GetNode()->IsCnsIntOrI()) || (numArgsArg->GetNode()->AsIntCon()->IconValue() < 1) ||
+            (numArgsArg->GetNode()->AsIntCon()->IconValue() > 64))
         {
             return nullptr;
         }
 
-        unsigned numArgs = static_cast<unsigned>(numArgsArg->Current()->AsIntCon()->IconValue());
+        unsigned numArgs = static_cast<unsigned>(numArgsArg->GetNode()->AsIntCon()->IconValue());
         bool     lowerBoundsSpecified;
 
         if (numArgs == rank * 2)
@@ -3214,7 +3213,7 @@ GenTree* Compiler::impInitializeArrayIntrinsic(CORINFO_SIG_INFO* sig)
         unsigned argIndex = 0;
         GenTree* comma;
 
-        for (comma = argsArg->Current(); Match::IsComma(comma); comma = comma->gtGetOp2())
+        for (comma = argsArg->GetNode(); Match::IsComma(comma); comma = comma->gtGetOp2())
         {
             if (lowerBoundsSpecified)
             {
@@ -3270,18 +3269,18 @@ GenTree* Compiler::impInitializeArrayIntrinsic(CORINFO_SIG_INFO* sig)
 
         GenTree* arrayLengthNode;
 
-        GenTreeArgList* args = newArrayCall->gtCall.gtCallArgs;
+        GenTreeCall::Use* args = newArrayCall->AsCall()->gtCallArgs;
 #ifdef FEATURE_READYTORUN_COMPILER
         if (newArrayCall->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_READYTORUN_NEWARR_1))
         {
             // Array length is 1st argument for readytorun helper
-            arrayLengthNode = args->Current();
+            arrayLengthNode = args->GetNode();
         }
         else
 #endif
         {
             // Array length is 2nd argument for regular helper
-            arrayLengthNode = args->Rest()->Current();
+            arrayLengthNode = args->GetNext()->GetNode();
         }
 
         //
@@ -3676,7 +3675,7 @@ GenTree* Compiler::impIntrinsic(GenTree*                newobjThis,
                     assert(typeHandleHelper == CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_MAYBENULL);
                     typeHandleHelper = CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE_MAYBENULL;
                 }
-                assert(op1->gtCall.gtCallArgs->gtOp.gtOp2 == nullptr);
+                assert(op1->AsCall()->gtCallArgs->GetNext() == nullptr);
                 op1         = gtNewHelperCallNode(typeHandleHelper, TYP_REF, op1->gtCall.gtCallArgs);
                 op1->gtType = TYP_REF;
                 retNode     = op1;
@@ -3701,10 +3700,9 @@ GenTree* Compiler::impIntrinsic(GenTree*                newobjThis,
                 op1 = impPopStack().val;
 
                 // Get native TypeHandle argument to old helper
-                op1 = op1->gtCall.gtCallArgs;
-                assert(op1->OperIsList());
-                assert(op1->gtOp.gtOp2 == nullptr);
-                op1     = op1->gtOp.gtOp1;
+                GenTreeCall::Use* arg = op1->AsCall()->gtCallArgs;
+                assert(arg->GetNext() == nullptr);
+                op1     = arg->GetNode();
                 retNode = op1;
             }
             // Call the regular function.
@@ -3730,8 +3728,8 @@ GenTree* Compiler::impIntrinsic(GenTree*                newobjThis,
                     // do for LDTOKEN since the return value of this operator is Type,
                     // not RuntimeTypeHandle.
                     impPopStack();
-                    GenTreeArgList* helperArgs = gtNewArgList(boxTypeHandle);
-                    GenTree*        runtimeType =
+                    GenTreeCall::Use* helperArgs = gtNewCallArgs(boxTypeHandle);
+                    GenTree*          runtimeType =
                         gtNewHelperCallNode(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE, TYP_REF, helperArgs);
                     retNode = runtimeType;
                 }
@@ -3760,8 +3758,8 @@ GenTree* Compiler::impIntrinsic(GenTree*                newobjThis,
                         assert(compDonotInline());
                         return nullptr;
                     }
-                    GenTreeArgList* helperArgs = gtNewArgList(typeHandleOp);
-                    GenTree*        runtimeType =
+                    GenTreeCall::Use* helperArgs = gtNewCallArgs(typeHandleOp);
+                    GenTree*          runtimeType =
                         gtNewHelperCallNode(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE, TYP_REF, helperArgs);
                     retNode = runtimeType;
                 }
@@ -4596,7 +4594,7 @@ void Compiler::verConvertBBToThrowVerificationException(BasicBlock* block DEBUGA
     assert(verCurrentState.esStackDepth == 0);
 
     GenTree* op1 =
-        gtNewHelperCallNode(CORINFO_HELP_VERIFICATION, TYP_VOID, gtNewArgList(gtNewIconNode(block->bbCodeOffs)));
+        gtNewHelperCallNode(CORINFO_HELP_VERIFICATION, TYP_VOID, gtNewCallArgs(gtNewIconNode(block->bbCodeOffs)));
     // verCurrentState.esStackDepth = 0;
     impAppendTree(op1, (unsigned)CHECK_SPILL_NONE, impCurStmtOffs);
 
@@ -5687,7 +5685,7 @@ GenTree* Compiler::impImportLdvirtftn(GenTree*                thisPtr,
             runtimeMethodHandle = gtNewIconEmbMethHndNode(pResolvedToken->hMethod);
         }
         return gtNewHelperCallNode(CORINFO_HELP_GVMLOOKUP_FOR_SLOT, TYP_I_IMPL,
-                                   gtNewArgList(thisPtr, runtimeMethodHandle));
+                                   gtNewCallArgs(thisPtr, runtimeMethodHandle));
     }
 
 #ifdef FEATURE_READYTORUN_COMPILER
@@ -5696,7 +5694,7 @@ GenTree* Compiler::impImportLdvirtftn(GenTree*                thisPtr,
         if (!pCallInfo->exactContextNeedsRuntimeLookup)
         {
             GenTreeCall* call =
-                gtNewHelperCallNode(CORINFO_HELP_READYTORUN_VIRTUAL_FUNC_PTR, TYP_I_IMPL, gtNewArgList(thisPtr));
+                gtNewHelperCallNode(CORINFO_HELP_READYTORUN_VIRTUAL_FUNC_PTR, TYP_I_IMPL, gtNewCallArgs(thisPtr));
 
             call->setEntryPoint(pCallInfo->codePointerLookup.constLookup);
 
@@ -5709,7 +5707,7 @@ GenTree* Compiler::impImportLdvirtftn(GenTree*                thisPtr,
             GenTree* ctxTree = getRuntimeContextTree(pCallInfo->codePointerLookup.lookupKind.runtimeLookupKind);
 
             return impReadyToRunHelperToTree(pResolvedToken, CORINFO_HELP_READYTORUN_GENERIC_HANDLE, TYP_I_IMPL,
-                                             gtNewArgList(ctxTree), &pCallInfo->codePointerLookup.lookupKind);
+                                             gtNewCallArgs(ctxTree), &pCallInfo->codePointerLookup.lookupKind);
         }
     }
 #endif
@@ -5727,11 +5725,11 @@ GenTree* Compiler::impImportLdvirtftn(GenTree*                thisPtr,
         return nullptr;
     }
 
-    GenTreeArgList* helpArgs = gtNewArgList(exactMethodDesc);
+    GenTreeCall::Use* helpArgs = gtNewCallArgs(exactMethodDesc);
 
-    helpArgs = gtNewListNode(exactTypeDesc, helpArgs);
+    helpArgs = gtPrependNewCallArg(exactTypeDesc, helpArgs);
 
-    helpArgs = gtNewListNode(thisPtr, helpArgs);
+    helpArgs = gtPrependNewCallArg(thisPtr, helpArgs);
 
     // Call helper function.  This gets the target address of the final destination callsite.
 
@@ -6049,8 +6047,9 @@ void Compiler::impImportAndPushBox(CORINFO_RESOLVED_TOKEN* pResolvedToken)
             return;
         }
 
-        GenTreeArgList* args = gtNewArgList(op2, impGetStructAddr(exprToBox, operCls, (unsigned)CHECK_SPILL_ALL, true));
-        op1                  = gtNewHelperCallNode(boxHelper, TYP_REF, args);
+        GenTreeCall::Use* args =
+            gtNewCallArgs(op2, impGetStructAddr(exprToBox, operCls, (unsigned)CHECK_SPILL_ALL, true));
+        op1 = gtNewHelperCallNode(boxHelper, TYP_REF, args);
     }
 
     /* Push the result back on the stack, */
@@ -6086,8 +6085,7 @@ void Compiler::impImportNewObjArray(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORI
 
     assert(pCallInfo->sig.numArgs);
 
-    GenTree*        node;
-    GenTreeArgList* args;
+    GenTree* node;
 
     //
     // There are two different JIT helpers that can be used to allocate
@@ -6152,12 +6150,12 @@ void Compiler::impImportNewObjArray(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORI
             node = gtNewOperNode(GT_COMMA, node->TypeGet(), gtNewAssignNode(dest, arg), node);
         }
 
-        args = gtNewArgList(node);
+        GenTreeCall::Use* args = gtNewCallArgs(node);
 
         // pass number of arguments to the helper
-        args = gtNewListNode(gtNewIconNode(pCallInfo->sig.numArgs), args);
+        args = gtPrependNewCallArg(gtNewIconNode(pCallInfo->sig.numArgs), args);
 
-        args = gtNewListNode(classHandle, args);
+        args = gtPrependNewCallArg(classHandle, args);
 
         node = gtNewHelperCallNode(CORINFO_HELP_NEW_MDARR_NONVARARG, TYP_REF, args);
     }
@@ -6169,13 +6167,13 @@ void Compiler::impImportNewObjArray(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORI
         // pushed in reverse order on the CPU stack)
         //
 
-        args = gtNewArgList(classHandle);
+        GenTreeCall::Use* args = gtNewCallArgs(classHandle);
 
         // pass number of arguments to the helper
-        args = gtNewListNode(gtNewIconNode(pCallInfo->sig.numArgs), args);
+        args = gtPrependNewCallArg(gtNewIconNode(pCallInfo->sig.numArgs), args);
 
         unsigned argFlags = 0;
-        args              = impPopList(pCallInfo->sig.numArgs, &pCallInfo->sig, args);
+        args              = impPopCallArgs(pCallInfo->sig.numArgs, &pCallInfo->sig, args);
 
         node = gtNewHelperCallNode(CORINFO_HELP_NEW_MDARR, TYP_REF, args);
 
@@ -6185,14 +6183,18 @@ void Compiler::impImportNewObjArray(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORI
 #ifdef DEBUG
         // At the present time we don't track Caller pop arguments
         // that have GC references in them
-        for (GenTreeArgList* temp = args; temp; temp = temp->Rest())
+        for (GenTreeCall::Use& use : GenTreeCall::UseList(args))
         {
-            assert(temp->Current()->gtType != TYP_REF);
+            assert(use.GetNode()->TypeGet() != TYP_REF);
         }
 #endif
     }
 
-    node->gtFlags |= args->gtFlags & GTF_GLOB_EFFECT;
+    for (GenTreeCall::Use& use : node->AsCall()->Args())
+    {
+        node->gtFlags |= use.GetNode()->gtFlags & GTF_GLOB_EFFECT;
+    }
+
     node->gtCall.compileTimeHelperArgumentHandle = (CORINFO_GENERIC_HANDLE)pResolvedToken->hClass;
 
     // Remember that this basic block contains 'new' of a md array
@@ -6594,18 +6596,19 @@ void Compiler::impPopArgsForUnmanagedCall(GenTree* call, CORINFO_SIG_INFO* sig)
     /* The argument list is now "clean" - no out-of-order side effects
      * Pop the argument list in reverse order */
 
-    GenTree* args = call->gtCall.gtCallArgs = impPopRevList(sig->numArgs, sig, sig->numArgs - argsToReverse);
+    GenTreeCall::Use* args     = impPopReverseCallArgs(sig->numArgs, sig, sig->numArgs - argsToReverse);
+    call->AsCall()->gtCallArgs = args;
 
     if (call->gtCall.gtCallMoreFlags & GTF_CALL_M_UNMGD_THISCALL)
     {
-        GenTree* thisPtr = args->Current();
+        GenTree* thisPtr = args->GetNode();
         impBashVarAddrsToI(thisPtr);
         assert(thisPtr->TypeGet() == TYP_I_IMPL || thisPtr->TypeGet() == TYP_BYREF);
     }
 
-    if (args)
+    for (GenTreeCall::Use& use : GenTreeCall::UseList(args))
     {
-        call->gtFlags |= args->gtFlags & GTF_GLOB_EFFECT;
+        call->gtFlags |= use.GetNode()->gtFlags & GTF_GLOB_EFFECT;
     }
 }
 
@@ -6642,7 +6645,7 @@ GenTree* Compiler::impInitClass(CORINFO_RESOLVED_TOKEN* pResolvedToken)
 
     if (runtimeLookup)
     {
-        node = gtNewHelperCallNode(CORINFO_HELP_INITCLASS, TYP_VOID, gtNewArgList(node));
+        node = gtNewHelperCallNode(CORINFO_HELP_INITCLASS, TYP_VOID, gtNewCallArgs(node));
     }
     else
     {
@@ -6750,7 +6753,7 @@ GenTree* Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedT
                     break;
             }
 
-            op1 = gtNewHelperCallNode(pFieldInfo->helper, type, gtNewArgList(op1));
+            op1 = gtNewHelperCallNode(pFieldInfo->helper, type, gtNewCallArgs(op1));
 
             FieldSeqNode* fs = GetFieldSeqStore()->CreateSingleton(pResolvedToken->hField);
             op1              = gtNewOperNode(GT_ADD, type, op1,
@@ -6796,8 +6799,8 @@ GenTree* Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedT
             CORINFO_LOOKUP_KIND kind = info.compCompHnd->getLocationOfThisType(info.compMethodHnd);
             assert(kind.needsRuntimeLookup);
 
-            GenTree*        ctxTree = getRuntimeContextTree(kind.runtimeLookupKind);
-            GenTreeArgList* args    = gtNewArgList(ctxTree);
+            GenTree*          ctxTree = getRuntimeContextTree(kind.runtimeLookupKind);
+            GenTreeCall::Use* args    = gtNewCallArgs(ctxTree);
 
             unsigned callFlags = 0;
 
@@ -6952,7 +6955,7 @@ void Compiler::impHandleAccessAllowedInternal(CorInfoIsAccessAllowedResult resul
 void Compiler::impInsertHelperCall(CORINFO_HELPER_DESC* helperInfo)
 {
     // Construct the argument list
-    GenTreeArgList* args = nullptr;
+    GenTreeCall::Use* args = nullptr;
     assert(helperInfo->helperNum != CORINFO_HELP_UNDEF);
     for (unsigned i = helperInfo->numArgs; i > 0; --i)
     {
@@ -6982,7 +6985,7 @@ void Compiler::impInsertHelperCall(CORINFO_HELPER_DESC* helperInfo)
             default:
                 NO_WAY("Illegal helper arg type");
         }
-        args = (currentArg == nullptr) ? gtNewArgList(currentArg) : gtNewListNode(currentArg, args);
+        args = gtPrependNewCallArg(currentArg, args);
     }
 
     /* TODO-Review:
@@ -7245,7 +7248,7 @@ var_types Compiler::impImportCall(OPCODE                  opcode,
     unsigned               mflags                         = 0;
     unsigned               argFlags                       = 0;
     GenTree*               call                           = nullptr;
-    GenTreeArgList*        args                           = nullptr;
+    GenTreeCall::Use*      args                           = nullptr;
     CORINFO_THIS_TRANSFORM constraintCallThisTransform    = CORINFO_NO_THIS_TRANSFORM;
     CORINFO_CONTEXT_HANDLE exactContextHnd                = nullptr;
     bool                   exactContextNeedsRuntimeLookup = false;
@@ -7293,8 +7296,8 @@ var_types Compiler::impImportCall(OPCODE                  opcode,
     bool checkForSmallType  = opts.IsJit64Compat() || opts.IsReadyToRun();
     bool bIntrinsicImported = false;
 
-    CORINFO_SIG_INFO calliSig;
-    GenTreeArgList*  extraArg = nullptr;
+    CORINFO_SIG_INFO  calliSig;
+    GenTreeCall::Use* extraArg = nullptr;
 
     /*-------------------------------------------------------------------------
      * First create the call node
@@ -7653,7 +7656,7 @@ var_types Compiler::impImportCall(OPCODE                  opcode,
                 // OK, We've been told to call via LDVIRTFTN, so just
                 // take the call now....
 
-                args = impPopList(sig->numArgs, sig);
+                GenTreeCall::Use* args = impPopCallArgs(sig->numArgs, sig);
 
                 GenTree* thisPtr = impPopStack().val;
                 thisPtr          = impTransformThis(thisPtr, pConstrainedResolvedToken, callInfo->thisTransform);
@@ -8035,7 +8038,7 @@ var_types Compiler::impImportCall(OPCODE                  opcode,
         GenTree* cookie = gtNewIconEmbHndNode(varCookie, pVarCookie, GTF_ICON_VARG_HDL, sig);
 
         assert(extraArg == nullptr);
-        extraArg = gtNewArgList(cookie);
+        extraArg = gtNewCallArgs(cookie);
     }
 
     //-------------------------------------------------------------------------
@@ -8169,7 +8172,7 @@ var_types Compiler::impImportCall(OPCODE                  opcode,
         }
 
         assert(extraArg == nullptr);
-        extraArg = gtNewArgList(instParam);
+        extraArg = gtNewCallArgs(instParam);
     }
 
     // Inlining may need the exact type context (exactContextHnd) if we're inlining shared generic code, in particular
@@ -8201,11 +8204,12 @@ var_types Compiler::impImportCall(OPCODE                  opcode,
     //-------------------------------------------------------------------------
     // The main group of arguments
 
-    args = call->gtCall.gtCallArgs = impPopList(sig->numArgs, sig, extraArg);
+    args                       = impPopCallArgs(sig->numArgs, sig, extraArg);
+    call->AsCall()->gtCallArgs = args;
 
-    if (args)
+    for (GenTreeCall::Use& use : call->AsCall()->Args())
     {
-        call->gtFlags |= args->gtFlags & GTF_GLOB_EFFECT;
+        call->gtFlags |= use.GetNode()->gtFlags & GTF_GLOB_EFFECT;
     }
 
     //-------------------------------------------------------------------------
@@ -8496,7 +8500,7 @@ DONE:
             assert(callObj != nullptr);
 
             if ((call->gtCall.IsVirtual() || (call->gtFlags & GTF_CALL_NULLCHECK)) &&
-                impInlineIsGuaranteedThisDerefBeforeAnySideEffects(call->gtCall.gtCallArgs, callObj,
+                impInlineIsGuaranteedThisDerefBeforeAnySideEffects(nullptr, call->AsCall()->gtCallArgs, callObj,
                                                                    impInlineInfo->inlArgInfo))
             {
                 impInlineInfo->thisDereferencedFirst = true;
@@ -10342,7 +10346,7 @@ GenTree* Compiler::impCastClassOrIsInstToTree(GenTree*                op1,
         //
         op2->gtFlags |= GTF_DONT_CSE;
 
-        return gtNewHelperCallNode(helper, TYP_REF, gtNewArgList(op2, op1));
+        return gtNewHelperCallNode(helper, TYP_REF, gtNewCallArgs(op2, op1));
     }
 
     JITDUMP("\nExpanding %s inline\n", isCastClass ? "castclass" : "isinst");
@@ -10402,7 +10406,7 @@ GenTree* Compiler::impCastClassOrIsInstToTree(GenTree*                op1,
         //
         const CorInfoHelpFunc specialHelper = CORINFO_HELP_CHKCASTCLASS_SPECIAL;
 
-        condTrue = gtNewHelperCallNode(specialHelper, TYP_REF, gtNewArgList(op2Var, gtClone(op1)));
+        condTrue = gtNewHelperCallNode(specialHelper, TYP_REF, gtNewCallArgs(op2Var, gtClone(op1)));
     }
     else
     {
@@ -10704,13 +10708,12 @@ void Compiler::impImportBlockCode(BasicBlock* block)
         CORINFO_CLASS_HANDLE ldelemClsHnd = DUMMY_INIT(NULL);
         CORINFO_CLASS_HANDLE stelemClsHnd = DUMMY_INIT(NULL);
 
-        var_types       lclTyp, ovflType = TYP_UNKNOWN;
-        GenTree*        op1           = DUMMY_INIT(NULL);
-        GenTree*        op2           = DUMMY_INIT(NULL);
-        GenTreeArgList* args          = nullptr; // What good do these "DUMMY_INIT"s do?
-        GenTree*        newObjThisPtr = DUMMY_INIT(NULL);
-        bool            uns           = DUMMY_INIT(false);
-        bool            isLocal       = false;
+        var_types lclTyp, ovflType = TYP_UNKNOWN;
+        GenTree*  op1           = DUMMY_INIT(NULL);
+        GenTree*  op2           = DUMMY_INIT(NULL);
+        GenTree*  newObjThisPtr = DUMMY_INIT(NULL);
+        bool      uns           = DUMMY_INIT(false);
+        bool      isLocal       = false;
 
         /* Get the next opcode and the size of its parameters */
 
@@ -11523,10 +11526,12 @@ void Compiler::impImportBlockCode(BasicBlock* block)
                     return;
                 }
 
-                args = gtNewArgList(op1);                      // Type
-                args = gtNewListNode(impPopStack().val, args); // index
-                args = gtNewListNode(impPopStack().val, args); // array
-                op1  = gtNewHelperCallNode(CORINFO_HELP_LDELEMA_REF, TYP_BYREF, args);
+                {
+                    GenTreeCall::Use* args = gtNewCallArgs(op1);                           // Type
+                    args                   = gtPrependNewCallArg(impPopStack().val, args); // index
+                    args                   = gtPrependNewCallArg(impPopStack().val, args); // array
+                    op1                    = gtNewHelperCallNode(CORINFO_HELP_LDELEMA_REF, TYP_BYREF, args);
+                }
 
                 impPushOnStack(op1, tiRetVal);
                 break;
@@ -11825,7 +11830,7 @@ void Compiler::impImportBlockCode(BasicBlock* block)
                 }
 
                 /* Call a helper function to do the assignment */
-                op1 = gtNewHelperCallNode(CORINFO_HELP_ARRADDR_ST, TYP_VOID, impPopList(3, nullptr));
+                op1 = gtNewHelperCallNode(CORINFO_HELP_ARRADDR_ST, TYP_VOID, impPopCallArgs(3, nullptr));
 
                 goto SPILL_APPEND;
 
@@ -14126,7 +14131,7 @@ void Compiler::impImportBlockCode(BasicBlock* block)
                         else
                         {
                             if (compIsForInlining() &&
-                                impInlineIsGuaranteedThisDerefBeforeAnySideEffects(nullptr, obj,
+                                impInlineIsGuaranteedThisDerefBeforeAnySideEffects(nullptr, nullptr, obj,
                                                                                    impInlineInfo->inlArgInfo))
                             {
                                 impInlineInfo->thisDereferencedFirst = true;
@@ -14435,7 +14440,8 @@ void Compiler::impImportBlockCode(BasicBlock* block)
                         }
 
                         if (compIsForInlining() &&
-                            impInlineIsGuaranteedThisDerefBeforeAnySideEffects(op2, obj, impInlineInfo->inlArgInfo))
+                            impInlineIsGuaranteedThisDerefBeforeAnySideEffects(op2, nullptr, obj,
+                                                                               impInlineInfo->inlArgInfo))
                         {
                             impInlineInfo->thisDereferencedFirst = true;
                         }
@@ -14676,7 +14682,7 @@ void Compiler::impImportBlockCode(BasicBlock* block)
                 if (opts.IsReadyToRun())
                 {
                     op1 = impReadyToRunHelperToTree(&resolvedToken, CORINFO_HELP_READYTORUN_NEWARR_1, TYP_REF,
-                                                    gtNewArgList(op2));
+                                                    gtNewCallArgs(op2));
                     usingReadyToRunHelper = (op1 != nullptr);
 
                     if (!usingReadyToRunHelper)
@@ -14700,7 +14706,7 @@ void Compiler::impImportBlockCode(BasicBlock* block)
                 if (!usingReadyToRunHelper)
 #endif
                 {
-                    args = gtNewArgList(op1, op2);
+                    GenTreeCall::Use* args = gtNewCallArgs(op1, op2);
 
                     /* Create a call to 'new' */
 
@@ -14879,7 +14885,7 @@ void Compiler::impImportBlockCode(BasicBlock* block)
                     {
                         GenTreeCall* opLookup =
                             impReadyToRunHelperToTree(&resolvedToken, CORINFO_HELP_READYTORUN_ISINSTANCEOF, TYP_REF,
-                                                      gtNewArgList(op1));
+                                                      gtNewCallArgs(op1));
                         usingReadyToRunHelper = (opLookup != nullptr);
                         op1                   = (usingReadyToRunHelper ? opLookup : op1);
 
@@ -14942,8 +14948,7 @@ void Compiler::impImportBlockCode(BasicBlock* block)
                 op1 = impNormStructVal(op1, impGetRefAnyClass(), (unsigned)CHECK_SPILL_ALL);
 
                 // Call helper GETREFANY(classHandle, op1);
-                args = gtNewArgList(op2, op1);
-                op1  = gtNewHelperCallNode(CORINFO_HELP_GETREFANY, TYP_BYREF, args);
+                op1 = gtNewHelperCallNode(CORINFO_HELP_GETREFANY, TYP_BYREF, gtNewCallArgs(op2, op1));
 
                 impPushOnStack(op1, tiRetVal);
                 break;
@@ -14990,7 +14995,7 @@ void Compiler::impImportBlockCode(BasicBlock* block)
 
                 // convert native TypeHandle to RuntimeTypeHandle
                 {
-                    GenTreeArgList* helperArgs = gtNewArgList(op1);
+                    GenTreeCall::Use* helperArgs = gtNewCallArgs(op1);
 
                     op1 = gtNewHelperCallNode(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPEHANDLE_MAYBENULL, TYP_STRUCT,
                                               helperArgs);
@@ -15031,7 +15036,7 @@ void Compiler::impImportBlockCode(BasicBlock* block)
                     helper = CORINFO_HELP_FIELDDESC_TO_STUBRUNTIMEFIELD;
                 }
 
-                GenTreeArgList* helperArgs = gtNewArgList(op1);
+                GenTreeCall::Use* helperArgs = gtNewCallArgs(op1);
 
                 op1 = gtNewHelperCallNode(helper, TYP_STRUCT, helperArgs);
 
@@ -15186,8 +15191,7 @@ void Compiler::impImportBlockCode(BasicBlock* block)
                     { // compDonotInline()
                         return;
                     }
-                    args = gtNewArgList(op2, op1);
-                    op1  = gtNewHelperCallNode(helper, TYP_VOID, args);
+                    op1 = gtNewHelperCallNode(helper, TYP_VOID, gtNewCallArgs(op2, op1));
 
                     op1 = new (this, GT_COLON) GenTreeColon(TYP_VOID, gtNewNothingNode(), op1);
                     op1 = gtNewQmarkNode(TYP_VOID, condBox, op1);
@@ -15211,10 +15215,9 @@ void Compiler::impImportBlockCode(BasicBlock* block)
                             canExpandInline ? "want smaller code or faster jitting" : "inline expansion not legal");
 
                     // Don't optimize, just call the helper and be done with it
-                    args = gtNewArgList(op2, op1);
-                    op1 =
-                        gtNewHelperCallNode(helper,
-                                            (var_types)((helper == CORINFO_HELP_UNBOX) ? TYP_BYREF : TYP_STRUCT), args);
+                    op1 = gtNewHelperCallNode(helper,
+                                              (var_types)((helper == CORINFO_HELP_UNBOX) ? TYP_BYREF : TYP_STRUCT),
+                                              gtNewCallArgs(op2, op1));
                 }
 
                 assert(helper == CORINFO_HELP_UNBOX && op1->gtType == TYP_BYREF || // Unbox helper returns a byref.
@@ -15461,7 +15464,7 @@ void Compiler::impImportBlockCode(BasicBlock* block)
                     {
                         GenTreeCall* opLookup =
                             impReadyToRunHelperToTree(&resolvedToken, CORINFO_HELP_READYTORUN_CHKCAST, TYP_REF,
-                                                      gtNewArgList(op1));
+                                                      gtNewCallArgs(op1));
                         usingReadyToRunHelper = (opLookup != nullptr);
                         op1                   = (usingReadyToRunHelper ? opLookup : op1);
 
@@ -15531,7 +15534,7 @@ void Compiler::impImportBlockCode(BasicBlock* block)
                 block->bbSetRunRarely(); // any block with a throw is rare
                 /* Pop the exception object and create the 'throw' helper call */
 
-                op1 = gtNewHelperCallNode(CORINFO_HELP_THROW, TYP_VOID, gtNewArgList(impPopStack().val));
+                op1 = gtNewHelperCallNode(CORINFO_HELP_THROW, TYP_VOID, gtNewCallArgs(impPopStack().val));
 
             EVAL_APPEND:
                 if (verCurrentState.esStackDepth > 0)
@@ -16255,8 +16258,8 @@ bool Compiler::impReturnInstruction(BasicBlock* block, int prefixFlags, OPCODE&
                 assert(op2->gtType == TYP_REF);
 
                 // confirm that the argument is a GC pointer (for debugging (GC stress))
-                GenTreeArgList* args = gtNewArgList(op2);
-                op2                  = gtNewHelperCallNode(CORINFO_HELP_CHECK_OBJ, TYP_REF, args);
+                GenTreeCall::Use* args = gtNewCallArgs(op2);
+                op2                    = gtNewHelperCallNode(CORINFO_HELP_CHECK_OBJ, TYP_REF, args);
 
                 if (verbose)
                 {
@@ -16571,7 +16574,7 @@ bool Compiler::impReturnInstruction(BasicBlock* block, int prefixFlags, OPCODE&
 #endif // defined(_TARGET_ARM64_)
                 {
                     assert(iciCall->HasRetBufArg());
-                    GenTree* dest = gtCloneExpr(iciCall->gtCallArgs->gtOp.gtOp1);
+                    GenTree* dest = gtCloneExpr(iciCall->gtCallArgs->GetNode());
                     // spill temp only exists if there are multiple return points
                     if (fgNeedReturnSpillTemp())
                     {
@@ -18694,7 +18697,7 @@ void Compiler::impInlineInitVars(InlineInfo* pInlineInfo)
 {
     assert(!compIsForInlining());
 
-    GenTree*             call         = pInlineInfo->iciCall;
+    GenTreeCall*         call         = pInlineInfo->iciCall;
     CORINFO_METHOD_INFO* methInfo     = &pInlineInfo->inlineCandidateInfo->methInfo;
     unsigned             clsAttr      = pInlineInfo->inlineCandidateInfo->clsAttr;
     InlArgInfo*          inlArgInfo   = pInlineInfo->inlArgInfo;
@@ -18707,10 +18710,7 @@ void Compiler::impInlineInitVars(InlineInfo* pInlineInfo)
 
     memset(inlArgInfo, 0, (MAX_INL_ARGS + 1) * sizeof(inlArgInfo[0]));
 
-    /* Get hold of the 'this' pointer and the argument list proper */
-
-    GenTree* thisArg = call->gtCall.gtCallObjp;
-    GenTree* argList = call->gtCall.gtCallArgs;
+    GenTree* thisArg = call->gtCallObjp;
     unsigned argCnt  = 0; // Count of the arguments
 
     assert((methInfo->args.hasThis()) == (thisArg != nullptr));
@@ -18739,9 +18739,9 @@ void Compiler::impInlineInitVars(InlineInfo* pInlineInfo)
     unsigned typeCtxtArg = methInfo->args.totalILArgs();
 #endif // USER_ARGS_COME_LAST
 
-    for (GenTree* argTmp = argList; argTmp; argTmp = argTmp->gtOp.gtOp2)
+    for (GenTreeCall::Use& use : call->Args())
     {
-        if (argTmp == argList && hasRetBuffArg)
+        if (hasRetBuffArg && (&use == call->gtCallArgs))
         {
             continue;
         }
@@ -18754,9 +18754,7 @@ void Compiler::impInlineInitVars(InlineInfo* pInlineInfo)
             continue;
         }
 
-        assert(argTmp->gtOper == GT_LIST);
-        GenTree* arg       = argTmp->gtOp.gtOp1;
-        GenTree* actualArg = arg->gtRetExprVal();
+        GenTree* actualArg = use.GetNode()->gtRetExprVal();
         impInlineRecordArgInfo(pInlineInfo, actualArg, argCnt, inlineResult);
 
         if (inlineResult->IsFailure())
@@ -19402,19 +19400,29 @@ BOOL Compiler::impInlineIsThis(GenTree* tree, InlArgInfo* inlArgInfo)
 }
 
 //-----------------------------------------------------------------------------
-// This function checks if a dereference in the inlinee can guarantee that
-// the "this" is non-NULL.
-// If we haven't hit a branch or a side effect, and we are dereferencing
-// from 'this' to access a field or make GTF_CALL_NULLCHECK call,
-// then we can avoid a separate null pointer check.
+// impInlineIsGuaranteedThisDerefBeforeAnySideEffects: Check if a dereference in
+// the inlinee can guarantee that the "this" pointer is non-NULL.
 //
-// "additionalTreesToBeEvaluatedBefore"
-// is the set of pending trees that have not yet been added to the statement list,
-// and which have been removed from verCurrentState.esStack[]
-
-BOOL Compiler::impInlineIsGuaranteedThisDerefBeforeAnySideEffects(GenTree*    additionalTreesToBeEvaluatedBefore,
-                                                                  GenTree*    variableBeingDereferenced,
-                                                                  InlArgInfo* inlArgInfo)
+// Arguments:
+//    additionalTree - a tree to check for side effects
+//    additionalCallArgs - a list of call args to check for side effects
+//    dereferencedAddress - address expression being dereferenced
+//    inlArgInfo - inlinee argument information
+//
+// Notes:
+//    If we haven't hit a branch or a side effect, and we are dereferencing
+//    from 'this' to access a field or make GTF_CALL_NULLCHECK call,
+//    then we can avoid a separate null pointer check.
+//
+//    The importer stack and current statement list are searched for side effects.
+//    Trees that have been popped of the stack but haven't been appended to the
+//    statement list and have to be checked for side effects may be provided via
+//    additionalTree and additionalCallArgs.
+//
+BOOL Compiler::impInlineIsGuaranteedThisDerefBeforeAnySideEffects(GenTree*          additionalTree,
+                                                                  GenTreeCall::Use* additionalCallArgs,
+                                                                  GenTree*          dereferencedAddress,
+                                                                  InlArgInfo*       inlArgInfo)
 {
     assert(compIsForInlining());
     assert(opts.OptEnabled(CLFLG_INLINING));
@@ -19426,17 +19434,24 @@ BOOL Compiler::impInlineIsGuaranteedThisDerefBeforeAnySideEffects(GenTree*    ad
         return FALSE;
     }
 
-    if (!impInlineIsThis(variableBeingDereferenced, inlArgInfo))
+    if (!impInlineIsThis(dereferencedAddress, inlArgInfo))
     {
         return FALSE;
     }
 
-    if (additionalTreesToBeEvaluatedBefore &&
-        GTF_GLOBALLY_VISIBLE_SIDE_EFFECTS(additionalTreesToBeEvaluatedBefore->gtFlags))
+    if ((additionalTree != nullptr) && GTF_GLOBALLY_VISIBLE_SIDE_EFFECTS(additionalTree->gtFlags))
     {
         return FALSE;
     }
 
+    for (GenTreeCall::Use& use : GenTreeCall::UseList(additionalCallArgs))
+    {
+        if (GTF_GLOBALLY_VISIBLE_SIDE_EFFECTS(use.GetNode()->gtFlags))
+        {
+            return false;
+        }
+    }
+
     for (GenTreeStmt* stmt = impStmtList; stmt != nullptr; stmt = stmt->gtNextStmt)
     {
         GenTree* expr = stmt->gtStmtExpr;
@@ -20315,18 +20330,18 @@ void Compiler::impDevirtualizeCall(GenTreeCall*            call,
                         // Prepend for R2L arg passing or empty L2R passing
                         if ((Target::g_tgtArgOrder == Target::ARG_ORDER_R2L) || (call->gtCallArgs == nullptr))
                         {
-                            call->gtCallArgs = gtNewListNode(methodTableArg, call->gtCallArgs);
+                            call->gtCallArgs = gtPrependNewCallArg(methodTableArg, call->gtCallArgs);
                         }
                         // Append for non-empty L2R
                         else
                         {
-                            GenTreeArgList* beforeArg = call->gtCallArgs;
-                            while (beforeArg->Rest() != nullptr)
+                            GenTreeCall::Use* beforeArg = call->gtCallArgs;
+                            while (beforeArg->GetNext() != nullptr)
                             {
-                                beforeArg = beforeArg->Rest();
+                                beforeArg = beforeArg->GetNext();
                             }
 
-                            beforeArg->Rest() = gtNewListNode(methodTableArg, nullptr);
+                            beforeArg->SetNext(gtNewCallArgs(methodTableArg));
                         }
 
                         call->gtCallMethHnd = unboxedEntryMethod;
@@ -20528,16 +20543,14 @@ public:
 
     void StoreRetExprResultsInArgs(GenTreeCall* call)
     {
-        GenTreeArgList** pArgs = &call->gtCallArgs;
-        if (*pArgs != nullptr)
+        for (GenTreeCall::Use& use : call->Args())
         {
-            comp->fgWalkTreePre((GenTree**)pArgs, SpillRetExprVisitor, this);
+            comp->fgWalkTreePre(&use.NodeRef(), SpillRetExprVisitor, this);
         }
 
-        GenTree** pThisArg = &call->gtCallObjp;
-        if (*pThisArg != nullptr)
+        if (call->gtCallObjp != nullptr)
         {
-            comp->fgWalkTreePre(pThisArg, SpillRetExprVisitor, this);
+            comp->fgWalkTreePre(&call->gtCallObjp, SpillRetExprVisitor, this);
         }
     }
 
index 8f82dd2..5cd10a0 100644 (file)
@@ -428,25 +428,19 @@ private:
         //
         void AddHiddenArgument(GenTreeCall* fatCall, GenTree* hiddenArgument)
         {
-            GenTreeArgList* oldArgs = fatCall->gtCallArgs;
-            GenTreeArgList* newArgs;
 #if USER_ARGS_COME_LAST
             if (fatCall->HasRetBufArg())
             {
-                GenTree*        retBuffer = oldArgs->Current();
-                GenTreeArgList* rest      = oldArgs->Rest();
-                newArgs                   = compiler->gtNewListNode(hiddenArgument, rest);
-                newArgs                   = compiler->gtNewListNode(retBuffer, newArgs);
+                GenTreeCall::Use* retBufArg = fatCall->gtCallArgs;
+                compiler->gtInsertNewCallArgAfter(hiddenArgument, retBufArg);
             }
             else
             {
-                newArgs = compiler->gtNewListNode(hiddenArgument, oldArgs);
+                fatCall->gtCallArgs = compiler->gtPrependNewCallArg(hiddenArgument, fatCall->gtCallArgs);
             }
 #else
-            newArgs = oldArgs;
-            AddArgumentToTail(newArgs, hiddenArgument);
+            AddArgumentToTail(fatCall->gtCallArgs, hiddenArgument);
 #endif
-            fatCall->gtCallArgs = newArgs;
         }
 
         //------------------------------------------------------------------------
@@ -456,14 +450,14 @@ private:
         //    argList - fat call node
         //    hiddenArgument - generic context hidden argument
         //
-        void AddArgumentToTail(GenTreeArgList* argList, GenTree* hiddenArgument)
+        void AddArgumentToTail(GenTreeCall::Use* argList, GenTree* hiddenArgument)
         {
-            GenTreeArgList* iterator = argList;
-            while (iterator->Rest() != nullptr)
+            GenTreeCall::Use* iterator = argList;
+            while (iterator->GetNext() != nullptr)
             {
-                iterator = iterator->Rest();
+                iterator = iterator->GetNext();
             }
-            iterator->Rest() = compiler->gtNewArgList(hiddenArgument);
+            iterator->SetNext(compiler->gtNewCallArgs(hiddenArgument));
         }
 
     private:
index 19b4ebc..1b6511c 100644 (file)
@@ -1496,18 +1496,16 @@ void Lowering::LowerArgsForCall(GenTreeCall* call)
         LowerArg(call, &call->gtCallObjp);
     }
 
-    GenTreeArgList* args = call->gtCallArgs;
-
     JITDUMP("\nargs:\n======\n");
-    for (; args; args = args->Rest())
+    for (GenTreeCall::Use& use : call->Args())
     {
-        LowerArg(call, &args->Current());
+        LowerArg(call, &use.NodeRef());
     }
 
     JITDUMP("\nlate:\n======\n");
-    for (args = call->gtCallLateArgs; args; args = args->Rest())
+    for (GenTreeCall::Use& use : call->LateArgs())
     {
-        LowerArg(call, &args->Current());
+        LowerArg(call, &use.NodeRef());
     }
 }
 
@@ -1724,14 +1722,13 @@ void Lowering::CheckVSQuirkStackPaddingNeeded(GenTreeCall* call)
     {
         bool     paddingNeeded  = false;
         GenTree* firstPutArgReg = nullptr;
-        for (GenTreeArgList* args = call->gtCallLateArgs; args; args = args->Rest())
+        for (GenTreeCall::Use& use : call->LateArgs())
         {
-            GenTree* tmp = args->Current();
-            if (tmp->OperGet() == GT_PUTARG_REG)
+            if (use.GetNode()->OperIs(GT_PUTARG_REG))
             {
                 if (firstPutArgReg == nullptr)
                 {
-                    firstPutArgReg = tmp;
+                    firstPutArgReg = use.GetNode();
                     GenTree* op1   = firstPutArgReg->gtOp.gtOp1;
 
                     if (op1->OperGet() == GT_LCL_VAR_ADDR)
@@ -1826,28 +1823,26 @@ void Lowering::InsertProfTailCallHook(GenTreeCall* call, GenTree* insertionPoint
 
     if (insertionPoint == nullptr)
     {
-        GenTree* tmp = nullptr;
-        for (GenTreeArgList* args = call->gtCallArgs; args; args = args->Rest())
+        for (GenTreeCall::Use& use : call->Args())
         {
-            tmp = args->Current();
-            assert(tmp->OperGet() != GT_PUTARG_REG); // We don't expect to see these in gtCallArgs
-            if (tmp->OperGet() == GT_PUTARG_STK)
+            assert(!use.GetNode()->OperIs(GT_PUTARG_REG)); // We don't expect to see these in gtCallArgs
+
+            if (use.GetNode()->OperIs(GT_PUTARG_STK))
             {
                 // found it
-                insertionPoint = tmp;
+                insertionPoint = use.GetNode();
                 break;
             }
         }
 
         if (insertionPoint == nullptr)
         {
-            for (GenTreeArgList* args = call->gtCallLateArgs; args; args = args->Rest())
+            for (GenTreeCall::Use& use : call->LateArgs())
             {
-                tmp = args->Current();
-                if ((tmp->OperGet() == GT_PUTARG_REG) || (tmp->OperGet() == GT_PUTARG_STK))
+                if (use.GetNode()->OperIs(GT_PUTARG_REG, GT_PUTARG_STK))
                 {
                     // found it
-                    insertionPoint = tmp;
+                    insertionPoint = use.GetNode();
                     break;
                 }
             }
@@ -1916,24 +1911,21 @@ void Lowering::LowerFastTailCall(GenTreeCall* call)
     // calls subsequently in execution order to setup other args, because the nested
     // call could over-write the stack arg that is setup earlier.
     GenTree*             firstPutArgStk = nullptr;
-    GenTreeArgList*      args;
     ArrayStack<GenTree*> putargs(comp->getAllocator(CMK_ArrayStack));
 
-    for (args = call->gtCallArgs; args; args = args->Rest())
+    for (GenTreeCall::Use& use : call->Args())
     {
-        GenTree* tmp = args->Current();
-        if (tmp->OperGet() == GT_PUTARG_STK)
+        if (use.GetNode()->OperIs(GT_PUTARG_STK))
         {
-            putargs.Push(tmp);
+            putargs.Push(use.GetNode());
         }
     }
 
-    for (args = call->gtCallLateArgs; args; args = args->Rest())
+    for (GenTreeCall::Use& use : call->LateArgs())
     {
-        GenTree* tmp = args->Current();
-        if (tmp->OperGet() == GT_PUTARG_STK)
+        if (use.GetNode()->OperIs(GT_PUTARG_STK))
         {
-            putargs.Push(tmp);
+            putargs.Push(use.GetNode());
         }
     }
 
@@ -3355,9 +3347,9 @@ void Lowering::InsertPInvokeMethodProlog()
     CLANG_FORMAT_COMMENT_ANCHOR;
 
 #if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
-    GenTreeArgList* argList = comp->gtNewArgList(frameAddr);
+    GenTreeCall::Use* argList = comp->gtNewCallArgs(frameAddr);
 #else
-    GenTreeArgList*    argList = comp->gtNewArgList(frameAddr, PhysReg(REG_SECRET_STUB_PARAM));
+    GenTreeCall::Use*  argList = comp->gtNewCallArgs(frameAddr, PhysReg(REG_SECRET_STUB_PARAM));
 #endif
 
     GenTree* call = comp->gtNewHelperCallNode(CORINFO_HELP_INIT_PINVOKE_FRAME, TYP_I_IMPL, argList);
@@ -3540,7 +3532,7 @@ void Lowering::InsertPInvokeCallProlog(GenTreeCall* call)
 
         // Insert call to CORINFO_HELP_JIT_PINVOKE_BEGIN
         GenTree* helperCall =
-            comp->gtNewHelperCallNode(CORINFO_HELP_JIT_PINVOKE_BEGIN, TYP_VOID, comp->gtNewArgList(frameAddr));
+            comp->gtNewHelperCallNode(CORINFO_HELP_JIT_PINVOKE_BEGIN, TYP_VOID, comp->gtNewCallArgs(frameAddr));
 
         comp->fgMorphTree(helperCall);
         BlockRange().InsertBefore(insertBefore, LIR::SeqTree(comp, helperCall));
@@ -3697,7 +3689,7 @@ void Lowering::InsertPInvokeCallEpilog(GenTreeCall* call)
 
         // Insert call to CORINFO_HELP_JIT_PINVOKE_END
         GenTreeCall* helperCall =
-            comp->gtNewHelperCallNode(CORINFO_HELP_JIT_PINVOKE_END, TYP_VOID, comp->gtNewArgList(frameAddr));
+            comp->gtNewHelperCallNode(CORINFO_HELP_JIT_PINVOKE_END, TYP_VOID, comp->gtNewCallArgs(frameAddr));
 
         comp->fgMorphTree(helperCall);
         BlockRange().InsertAfter(call, LIR::SeqTree(comp, helperCall));
@@ -5264,14 +5256,14 @@ void Lowering::CheckCall(GenTreeCall* call)
         CheckCallArg(call->gtCallObjp);
     }
 
-    for (GenTreeArgList* args = call->gtCallArgs; args != nullptr; args = args->Rest())
+    for (GenTreeCall::Use& use : call->Args())
     {
-        CheckCallArg(args->Current());
+        CheckCallArg(use.GetNode());
     }
 
-    for (GenTreeArgList* args = call->gtCallLateArgs; args != nullptr; args = args->Rest())
+    for (GenTreeCall::Use& use : call->LateArgs())
     {
-        CheckCallArg(args->Current());
+        CheckCallArg(use.GetNode());
     }
 }
 
index df5f583..63451eb 100644 (file)
@@ -1455,25 +1455,20 @@ void Lowering::ContainCheckCallOperands(GenTreeCall* call)
         }
     }
 
-    GenTree* args = call->gtCallArgs;
-    while (args)
+    for (GenTreeCall::Use& use : call->Args())
     {
-        GenTree* arg = args->gtOp.gtOp1;
-        if (arg->gtOper == GT_PUTARG_STK)
+        if (use.GetNode()->OperIs(GT_PUTARG_STK))
         {
-            LowerPutArgStk(arg->AsPutArgStk());
+            LowerPutArgStk(use.GetNode()->AsPutArgStk());
         }
-        args = args->gtOp.gtOp2;
     }
-    args = call->gtCallLateArgs;
-    while (args)
+
+    for (GenTreeCall::Use& use : call->LateArgs())
     {
-        GenTree* arg = args->gtOp.gtOp1;
-        if (arg->gtOper == GT_PUTARG_STK)
+        if (use.GetNode()->OperIs(GT_PUTARG_STK))
         {
-            LowerPutArgStk(arg->AsPutArgStk());
+            LowerPutArgStk(use.GetNode()->AsPutArgStk());
         }
-        args = args->gtOp.gtOp2;
     }
 }
 
index eec4e26..9f93979 100644 (file)
@@ -225,18 +225,16 @@ int LinearScan::BuildCall(GenTreeCall* call)
     // Each register argument corresponds to one source.
     bool callHasFloatRegArgs = false;
 
-    for (GenTree* list = call->gtCallLateArgs; list; list = list->MoveNext())
+    for (GenTreeCall::Use& arg : call->LateArgs())
     {
-        assert(list->OperIsList());
-
-        GenTree* argNode = list->Current();
+        GenTree* argNode = arg.GetNode();
 
 #ifdef DEBUG
         // During Build, we only use the ArgTabEntry for validation,
         // as getting it is rather expensive.
         fgArgTabEntry* curArgTabEntry = compiler->gtArgEntryByNode(call, argNode);
         regNumber      argReg         = curArgTabEntry->regNum;
-        assert(curArgTabEntry);
+        assert(curArgTabEntry != nullptr);
 #endif
 
         if (argNode->gtOper == GT_PUTARG_STK)
@@ -311,6 +309,7 @@ int LinearScan::BuildCall(GenTreeCall* call)
         }
     }
 
+#ifdef DEBUG
     // Now, count stack args
     // Note that these need to be computed into a register, but then
     // they're just stored to the stack - so the reg doesn't
@@ -318,18 +317,15 @@ int LinearScan::BuildCall(GenTreeCall* call)
     // because the code generator doesn't actually consider it live,
     // so it can't be spilled.
 
-    GenTree* args = call->gtCallArgs;
-    while (args)
+    for (GenTreeCall::Use& use : call->Args())
     {
-        GenTree* arg = args->gtGetOp1();
+        GenTree* arg = use.GetNode();
 
         // Skip arguments that have been moved to the Late Arg list
-        if (!(args->gtFlags & GTF_LATE_ARG))
+        if ((arg->gtFlags & GTF_LATE_ARG) == 0)
         {
-#ifdef DEBUG
             fgArgTabEntry* curArgTabEntry = compiler->gtArgEntryByNode(call, arg);
-            assert(curArgTabEntry);
-#endif
+            assert(curArgTabEntry != nullptr);
 #if FEATURE_ARG_SPLIT
             // PUTARG_SPLIT nodes must be in the gtCallLateArgs list, since they
             // define registers used by the call.
@@ -344,8 +340,8 @@ int LinearScan::BuildCall(GenTreeCall* call)
                 assert(!arg->IsValue() || arg->IsUnusedValue());
             }
         }
-        args = args->gtGetOp2();
     }
+#endif // DEBUG
 
     // If it is a fast tail call, it is already preferenced to use IP0.
     // Therefore, no need set src candidates on call tgt again.
index a81c29f..a5a5944 100644 (file)
@@ -1087,9 +1087,9 @@ int LinearScan::BuildCall(GenTreeCall* call)
 
     // First, determine internal registers.
     // We will need one for any float arguments to a varArgs call.
-    for (GenTree* list = call->gtCallLateArgs; list; list = list->MoveNext())
+    for (GenTreeCall::Use& use : call->LateArgs())
     {
-        GenTree* argNode = list->Current();
+        GenTree* argNode = use.GetNode();
         if (argNode->OperIsPutArgReg())
         {
             HandleFloatVarArgs(call, argNode, &callHasFloatRegArgs);
@@ -1105,7 +1105,7 @@ int LinearScan::BuildCall(GenTreeCall* call)
     }
 
     // Now, count reg args
-    for (GenTree* list = call->gtCallLateArgs; list; list = list->MoveNext())
+    for (GenTreeCall::Use& use : call->LateArgs())
     {
         // By this point, lowering has ensured that all call arguments are one of the following:
         // - an arg setup store
@@ -1116,7 +1116,7 @@ int LinearScan::BuildCall(GenTreeCall* call)
         // - a put arg
         //
         // Note that this property is statically checked by LinearScan::CheckBlock.
-        GenTree* argNode = list->Current();
+        GenTree* argNode = use.GetNode();
 
         // Each register argument corresponds to one source.
         if (argNode->OperIsPutArgReg())
@@ -1185,6 +1185,7 @@ int LinearScan::BuildCall(GenTreeCall* call)
 #endif // DEBUG
     }
 
+#ifdef DEBUG
     // Now, count stack args
     // Note that these need to be computed into a register, but then
     // they're just stored to the stack - so the reg doesn't
@@ -1192,10 +1193,9 @@ int LinearScan::BuildCall(GenTreeCall* call)
     // because the code generator doesn't actually consider it live,
     // so it can't be spilled.
 
-    GenTree* args = call->gtCallArgs;
-    while (args)
+    for (GenTreeCall::Use& use : call->Args())
     {
-        GenTree* arg = args->gtGetOp1();
+        GenTree* arg = use.GetNode();
         if (!(arg->gtFlags & GTF_LATE_ARG) && !arg)
         {
             if (arg->IsValue() && !arg->isContained())
@@ -1203,8 +1203,8 @@ int LinearScan::BuildCall(GenTreeCall* call)
                 assert(arg->IsUnusedValue());
             }
         }
-        args = args->gtGetOp2();
     }
+#endif // DEBUG
 
     // set reg requirements on call target represented as control sequence.
     if (ctrlExpr != nullptr)
index 64ab823..541bbef 100644 (file)
@@ -47,7 +47,7 @@ GenTree* Compiler::fgMorphCastIntoHelper(GenTree* tree, int helper, GenTree* ope
         noway_assert(tree->gtCast.CastOp() == oper);
         noway_assert(tree->gtOper == GT_CAST);
     }
-    result = fgMorphIntoHelperCall(tree, helper, gtNewArgList(oper));
+    result = fgMorphIntoHelperCall(tree, helper, gtNewCallArgs(oper));
     assert(result == tree);
     return result;
 }
@@ -58,7 +58,7 @@ GenTree* Compiler::fgMorphCastIntoHelper(GenTree* tree, int helper, GenTree* ope
  *  the given argument list.
  */
 
-GenTree* Compiler::fgMorphIntoHelperCall(GenTree* tree, int helper, GenTreeArgList* args, bool morphArgs)
+GenTree* Compiler::fgMorphIntoHelperCall(GenTree* tree, int helper, GenTreeCall::Use* args, bool morphArgs)
 {
     // The helper call ought to be semantically equivalent to the original node, so preserve its VN.
     tree->ChangeOper(GT_CALL, GenTree::PRESERVE_VN);
@@ -105,9 +105,10 @@ GenTree* Compiler::fgMorphIntoHelperCall(GenTree* tree, int helper, GenTreeArgLi
         tree->gtFlags &= ~GTF_EXCEPT;
     }
     tree->gtFlags |= GTF_CALL;
-    if (args)
+
+    for (GenTreeCall::Use& use : GenTreeCall::UseList(args))
     {
-        tree->gtFlags |= (args->gtFlags & GTF_ALL_EFFECT);
+        tree->gtFlags |= (use.GetNode()->gtFlags & GTF_ALL_EFFECT);
     }
 
     /* Perform the morphing */
@@ -797,32 +798,6 @@ GenTree* Compiler::fgUnwrapProxy(GenTree* objRef)
     return objRef;
 }
 
-/*****************************************************************************
- *
- *  Morph an argument list; compute the pointer argument count in the process.
- *
- *  NOTE: This function can be called from any place in the JIT to perform re-morphing
- *  due to graph altering modifications such as copy / constant propagation
- */
-
-unsigned UpdateGT_LISTFlags(GenTree* tree)
-{
-    assert(tree->gtOper == GT_LIST);
-
-    unsigned flags = 0;
-    if (tree->gtOp.gtOp2)
-    {
-        flags |= UpdateGT_LISTFlags(tree->gtOp.gtOp2);
-    }
-
-    flags |= (tree->gtOp.gtOp1->gtFlags & GTF_ALL_EFFECT);
-
-    tree->gtFlags &= ~GTF_ALL_EFFECT;
-    tree->gtFlags |= flags;
-
-    return tree->gtFlags;
-}
-
 #ifdef DEBUG
 void fgArgTabEntry::Dump()
 {
@@ -965,10 +940,10 @@ fgArgInfo::fgArgInfo(GenTreeCall* newCall, GenTreeCall* oldCall)
     // We create local, artificial GenTreeArgLists that includes the gtCallObjp, if that exists, as first argument,
     // so we can iterate over these argument lists more uniformly.
     // Need to provide a temporary non-null first arguments to these constructors: if we use them, we'll replace them
-    GenTreeArgList* newArgs;
-    GenTreeArgList  newArgObjp(newCall, newCall->gtCallArgs);
-    GenTreeArgList* oldArgs;
-    GenTreeArgList  oldArgObjp(oldCall, oldCall->gtCallArgs);
+    GenTreeCall::Use* newArgs;
+    GenTreeCall::Use  newArgObjp(newCall, newCall->gtCallArgs);
+    GenTreeCall::Use* oldArgs;
+    GenTreeCall::Use  oldArgObjp(oldCall, oldCall->gtCallArgs);
 
     if (newCall->gtCallObjp == nullptr)
     {
@@ -979,25 +954,25 @@ fgArgInfo::fgArgInfo(GenTreeCall* newCall, GenTreeCall* oldCall)
     else
     {
         assert(oldCall->gtCallObjp != nullptr);
-        newArgObjp.Current() = newCall->gtCallArgs;
-        newArgs              = &newArgObjp;
-        oldArgObjp.Current() = oldCall->gtCallObjp;
-        oldArgs              = &oldArgObjp;
+        newArgObjp.SetNode(newCall->gtCallObjp);
+        newArgs = &newArgObjp;
+        oldArgObjp.SetNode(oldCall->gtCallObjp);
+        oldArgs = &oldArgObjp;
     }
 
-    GenTree*        newCurr;
-    GenTree*        oldCurr;
-    GenTreeArgList* newParent   = nullptr;
-    GenTreeArgList* oldParent   = nullptr;
-    fgArgTabEntry** oldArgTable = oldArgInfo->argTable;
-    bool            scanRegArgs = false;
+    GenTree*          newCurr;
+    GenTree*          oldCurr;
+    GenTreeCall::Use* newParent   = nullptr;
+    GenTreeCall::Use* oldParent   = nullptr;
+    fgArgTabEntry**   oldArgTable = oldArgInfo->argTable;
+    bool              scanRegArgs = false;
 
-    while (newArgs)
+    while (newArgs != nullptr)
     {
         /* Get hold of the next argument values for the oldCall and newCall */
 
-        newCurr = newArgs->Current();
-        oldCurr = oldArgs->Current();
+        newCurr = newArgs->GetNode();
+        oldCurr = oldArgs->GetNode();
         if (newArgs != &newArgObjp)
         {
             newParent = newArgs;
@@ -1007,8 +982,8 @@ fgArgInfo::fgArgInfo(GenTreeCall* newCall, GenTreeCall* oldCall)
         {
             assert(newParent == nullptr && oldParent == nullptr);
         }
-        newArgs = newArgs->Rest();
-        oldArgs = oldArgs->Rest();
+        newArgs = newArgs->GetNext();
+        oldArgs = oldArgs->GetNext();
 
         fgArgTabEntry* oldArgTabEntry = nullptr;
         fgArgTabEntry* newArgTabEntry = nullptr;
@@ -1017,7 +992,7 @@ fgArgInfo::fgArgInfo(GenTreeCall* newCall, GenTreeCall* oldCall)
         {
             oldArgTabEntry = oldArgTable[inx];
 
-            if (oldArgTabEntry->parent == oldParent)
+            if (oldArgTabEntry->use == oldParent)
             {
                 assert((oldParent == nullptr) == (newParent == nullptr));
 
@@ -1031,7 +1006,7 @@ fgArgInfo::fgArgInfo(GenTreeCall* newCall, GenTreeCall* oldCall)
 
                 // Then update all GenTree* fields in the newArgTabEntry
                 //
-                newArgTabEntry->parent = newParent;
+                newArgTabEntry->use = newParent;
 
                 // The node field is likely to have been updated
                 //  to point at a node in the gtCallLateArgs list
@@ -1068,19 +1043,15 @@ fgArgInfo::fgArgInfo(GenTreeCall* newCall, GenTreeCall* oldCall)
         newArgs = newCall->gtCallLateArgs;
         oldArgs = oldCall->gtCallLateArgs;
 
-        while (newArgs)
+        while (newArgs != nullptr)
         {
             /* Get hold of the next argument values for the oldCall and newCall */
 
-            assert(newArgs->OperIsList());
-
-            newCurr = newArgs->Current();
-            newArgs = newArgs->Rest();
+            newCurr = newArgs->GetNode();
+            newArgs = newArgs->GetNext();
 
-            assert(oldArgs->OperIsList());
-
-            oldCurr = oldArgs->Current();
-            oldArgs = oldArgs->Rest();
+            oldCurr = oldArgs->GetNode();
+            oldArgs = oldArgs->GetNext();
 
             fgArgTabEntry* oldArgTabEntry = nullptr;
             fgArgTabEntry* newArgTabEntry = nullptr;
@@ -1122,14 +1093,14 @@ void fgArgInfo::AddArg(fgArgTabEntry* curArgTabEntry)
     argCount++;
 }
 
-fgArgTabEntry* fgArgInfo::AddRegArg(unsigned  argNum,
-                                    GenTree*  node,
-                                    GenTree*  parent,
-                                    regNumber regNum,
-                                    unsigned  numRegs,
-                                    unsigned  alignment,
-                                    bool      isStruct,
-                                    bool      isVararg /*=false*/)
+fgArgTabEntry* fgArgInfo::AddRegArg(unsigned          argNum,
+                                    GenTree*          node,
+                                    GenTreeCall::Use* use,
+                                    regNumber         regNum,
+                                    unsigned          numRegs,
+                                    unsigned          alignment,
+                                    bool              isStruct,
+                                    bool              isVararg /*=false*/)
 {
     fgArgTabEntry* curArgTabEntry = new (compiler, CMK_fgArgInfo) fgArgTabEntry;
 
@@ -1142,7 +1113,7 @@ fgArgTabEntry* fgArgInfo::AddRegArg(unsigned  argNum,
     curArgTabEntry->argNum     = argNum;
     curArgTabEntry->node       = node;
     curArgTabEntry->argType    = node->TypeGet();
-    curArgTabEntry->parent     = parent;
+    curArgTabEntry->use        = use;
     curArgTabEntry->slotNum    = 0;
     curArgTabEntry->numRegs    = numRegs;
     curArgTabEntry->numSlots   = 0;
@@ -1170,7 +1141,7 @@ fgArgTabEntry* fgArgInfo::AddRegArg(unsigned  argNum,
 #if defined(UNIX_AMD64_ABI)
 fgArgTabEntry* fgArgInfo::AddRegArg(unsigned                                                         argNum,
                                     GenTree*                                                         node,
-                                    GenTree*                                                         parent,
+                                    GenTreeCall::Use*                                                use,
                                     regNumber                                                        regNum,
                                     unsigned                                                         numRegs,
                                     unsigned                                                         alignment,
@@ -1181,7 +1152,7 @@ fgArgTabEntry* fgArgInfo::AddRegArg(unsigned
                                     const unsigned                                                   structFloatRegs,
                                     const SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* const structDescPtr)
 {
-    fgArgTabEntry* curArgTabEntry = AddRegArg(argNum, node, parent, regNum, numRegs, alignment, isStruct, isVararg);
+    fgArgTabEntry* curArgTabEntry = AddRegArg(argNum, node, use, regNum, numRegs, alignment, isStruct, isVararg);
     assert(curArgTabEntry != nullptr);
 
     curArgTabEntry->isStruct        = isStruct; // is this a struct arg
@@ -1204,13 +1175,13 @@ fgArgTabEntry* fgArgInfo::AddRegArg(unsigned
 }
 #endif // defined(UNIX_AMD64_ABI)
 
-fgArgTabEntry* fgArgInfo::AddStkArg(unsigned argNum,
-                                    GenTree* node,
-                                    GenTree* parent,
-                                    unsigned numSlots,
-                                    unsigned alignment,
-                                    bool     isStruct,
-                                    bool     isVararg /*=false*/)
+fgArgTabEntry* fgArgInfo::AddStkArg(unsigned          argNum,
+                                    GenTree*          node,
+                                    GenTreeCall::Use* use,
+                                    unsigned          numSlots,
+                                    unsigned          alignment,
+                                    bool              isStruct,
+                                    bool              isVararg /*=false*/)
 {
     fgArgTabEntry* curArgTabEntry = new (compiler, CMK_fgArgInfo) fgArgTabEntry;
 
@@ -1220,7 +1191,7 @@ fgArgTabEntry* fgArgInfo::AddStkArg(unsigned argNum,
     curArgTabEntry->argNum  = argNum;
     curArgTabEntry->node    = node;
     curArgTabEntry->argType = node->TypeGet();
-    curArgTabEntry->parent  = parent;
+    curArgTabEntry->use     = use;
     curArgTabEntry->slotNum = nextSlotNum;
     curArgTabEntry->numRegs = 0;
 #if defined(UNIX_AMD64_ABI)
@@ -1276,10 +1247,9 @@ void fgArgInfo::UpdateRegArg(fgArgTabEntry* curArgTabEntry, GenTree* node, bool
 
     assert(curArgTabEntry->numRegs != 0);
 
-    if (curArgTabEntry->parent != nullptr)
+    if (curArgTabEntry->use != nullptr)
     {
-        assert(curArgTabEntry->parent->OperIsList());
-        assert(curArgTabEntry->parent->Current() == node);
+        assert(curArgTabEntry->use->GetNode() == node);
     }
 
     if (curArgTabEntry->node != node)
@@ -1319,10 +1289,9 @@ void fgArgInfo::UpdateStkArg(fgArgTabEntry* curArgTabEntry, GenTree* node, bool
     assert((isLateArg && ((node->gtFlags & GTF_LATE_ARG) != 0)) ||
            (!isLateArg && ((node->gtFlags & GTF_LATE_ARG) == 0)));
 
-    noway_assert(curArgTabEntry->parent != nullptr);
+    noway_assert(curArgTabEntry->use != nullptr);
     assert((curArgTabEntry->regNum == REG_STK) || curArgTabEntry->isSplit);
-    assert(curArgTabEntry->parent->OperIsList());
-    assert(curArgTabEntry->parent->Current() == node);
+    assert(curArgTabEntry->use->GetNode() == node);
     nextSlotNum = (unsigned)roundUp(nextSlotNum, curArgTabEntry->alignment);
     assert(curArgTabEntry->slotNum == nextSlotNum);
 
@@ -1336,14 +1305,15 @@ void fgArgInfo::UpdateStkArg(fgArgTabEntry* curArgTabEntry, GenTree* node, bool
 
             // Traverse the late argument list to find this argument so that we can update it.
             unsigned listInx = 0;
-            for (GenTreeArgList *list = callTree->gtCall.gtCallLateArgs; list; list = list->Rest(), listInx++)
+            for (GenTreeCall::Use& use : callTree->AsCall()->LateArgs())
             {
-                argx = list->Current();
+                argx = use.GetNode();
                 assert(!argx->IsArgPlaceHolderNode()); // No place holders nodes are in gtCallLateArgs;
                 if (listInx == lateArgInx)
                 {
                     break;
                 }
+                listInx++;
             }
             assert(listInx == lateArgInx);
             assert(lateArgInx == curArgTabEntry->lateArgInx);
@@ -1409,7 +1379,7 @@ void fgArgInfo::SplitArg(unsigned argNum, unsigned numRegs, unsigned numSlots)
 //
 void fgArgInfo::EvalToTmp(fgArgTabEntry* curArgTabEntry, unsigned tmpNum, GenTree* newNode)
 {
-    assert(curArgTabEntry->parent->Current() == newNode);
+    assert(curArgTabEntry->use->GetNode() == newNode);
 
     curArgTabEntry->node   = newNode;
     curArgTabEntry->tmpNum = tmpNum;
@@ -2209,7 +2179,7 @@ void fgArgInfo::EvalArgsToTemps()
 
     unsigned regArgInx = 0;
     // Now go through the argument table and perform the necessary evaluation into temps
-    GenTreeArgList* tmpRegArgNext = nullptr;
+    GenTreeCall::Use* tmpRegArgNext = nullptr;
     for (unsigned curInx = 0; curInx < argCount; curInx++)
     {
         fgArgTabEntry* curArgTabEntry = argTable[curInx];
@@ -2439,16 +2409,13 @@ void fgArgInfo::EvalArgsToTemps()
 
         if (setupArg != nullptr)
         {
-            if (curArgTabEntry->parent)
+            if (curArgTabEntry->use != nullptr)
             {
-                GenTree* parent = curArgTabEntry->parent;
+                GenTreeCall::Use* use = curArgTabEntry->use;
                 /* a normal argument from the list */
-                noway_assert(parent->OperIsList());
-                noway_assert(parent->gtOp.gtOp1 == argx);
-
-                parent->gtFlags |= (setupArg->gtFlags & GTF_ALL_EFFECT);
+                noway_assert(use->GetNode() == argx);
 
-                parent->gtOp.gtOp1 = setupArg;
+                use->SetNode(setupArg);
             }
             else
             {
@@ -2463,21 +2430,17 @@ void fgArgInfo::EvalArgsToTemps()
 
         if (tmpRegArgNext == nullptr)
         {
-            tmpRegArgNext                   = compiler->gtNewArgList(defArg);
+            tmpRegArgNext                   = compiler->gtNewCallArgs(defArg);
             callTree->gtCall.gtCallLateArgs = tmpRegArgNext;
         }
         else
         {
-            noway_assert(tmpRegArgNext->OperIsList());
-            noway_assert(tmpRegArgNext->Current());
-            tmpRegArgNext->gtOp.gtOp2 = compiler->gtNewArgList(defArg);
+            noway_assert(tmpRegArgNext->GetNode() != nullptr);
+            tmpRegArgNext->SetNext(compiler->gtNewCallArgs(defArg));
 
-            tmpRegArgNext->gtFlags |= (defArg->gtFlags & GTF_ALL_EFFECT);
-            tmpRegArgNext = tmpRegArgNext->Rest();
+            tmpRegArgNext = tmpRegArgNext->GetNext();
         }
 
-        tmpRegArgNext->gtFlags |= (defArg->gtFlags & GTF_ALL_EFFECT);
-
         curArgTabEntry->node       = defArg;
         curArgTabEntry->lateArgInx = regArgInx++;
     }
@@ -2504,9 +2467,8 @@ void fgArgInfo::EvalArgsToTemps()
 // It will be used only on the intercepted-for-host code path to copy the arguments.
 int Compiler::fgEstimateCallStackSize(GenTreeCall* call)
 {
-
     int numArgs = 0;
-    for (GenTreeArgList* args = call->gtCallArgs; args; args = args->Rest())
+    for (GenTreeCall::Use& use : call->Args())
     {
         numArgs++;
     }
@@ -2604,8 +2566,8 @@ GenTree* Compiler::fgInsertCommaFormTemp(GenTree** ppTree, CORINFO_CLASS_HANDLE
 //
 void Compiler::fgInitArgInfo(GenTreeCall* call)
 {
-    GenTree* args;
-    GenTree* argx;
+    GenTreeCall::Use* args;
+    GenTree*          argx;
 
     unsigned argIndex     = 0;
     unsigned intArgRegNum = 0;
@@ -2762,7 +2724,7 @@ void Compiler::fgInitArgInfo(GenTreeCall* call)
     {
         numArgs++;
     }
-    for (GenTree* args = call->gtCallArgs; (args != nullptr); args = args->gtOp.gtOp2)
+    for (GenTreeCall::Use& use : call->Args())
     {
         numArgs++;
     }
@@ -2782,8 +2744,8 @@ void Compiler::fgInitArgInfo(GenTreeCall* call)
     // Set the argument registers correctly here.
     if (call->IsHelperCall(this, CORINFO_HELP_INIT_PINVOKE_FRAME))
     {
-        GenTreeArgList* args = call->gtCallArgs;
-        GenTree*        arg1 = args->Current();
+        GenTreeCall::Use* args = call->gtCallArgs;
+        GenTree*          arg1 = args->GetNode();
         assert(arg1 != nullptr);
         nonStandardArgs.Add(arg1, REG_PINVOKE_FRAME);
     }
@@ -2815,11 +2777,11 @@ void Compiler::fgInitArgInfo(GenTreeCall* call)
             GenTreeAddrMode(TYP_BYREF, arg, nullptr, 0, eeGetEEInfo()->offsetOfSecureDelegateIndirectCell);
 
         // Append newArg as the last arg
-        GenTreeArgList** insertionPoint = &call->gtCallArgs;
-        for (; *insertionPoint != nullptr; insertionPoint = &(*insertionPoint)->Rest())
+        GenTreeCall::Use** insertionPoint = &call->gtCallArgs;
+        for (; *insertionPoint != nullptr; insertionPoint = &((*insertionPoint)->NextRef()))
         {
         }
-        *insertionPoint = gtNewListNode(newArg, nullptr);
+        *insertionPoint = gtNewCallArgs(newArg);
 
         numArgs++;
         nonStandardArgs.Add(newArg, virtualStubParamInfo->GetReg());
@@ -2831,13 +2793,13 @@ void Compiler::fgInitArgInfo(GenTreeCall* call)
     else if (call->IsHelperCall(this, CORINFO_HELP_LLSH) || call->IsHelperCall(this, CORINFO_HELP_LRSH) ||
              call->IsHelperCall(this, CORINFO_HELP_LRSZ))
     {
-        GenTreeArgList* args = call->gtCallArgs;
-        GenTree*        arg1 = args->Current();
+        GenTreeCall::Use* args = call->gtCallArgs;
+        GenTree*          arg1 = args->GetNode();
         assert(arg1 != nullptr);
         nonStandardArgs.Add(arg1, REG_LNGARG_LO);
 
-        args          = args->Rest();
-        GenTree* arg2 = args->Current();
+        args          = args->GetNext();
+        GenTree* arg2 = args->GetNode();
         assert(arg2 != nullptr);
         nonStandardArgs.Add(arg2, REG_LNGARG_HI);
     }
@@ -2852,9 +2814,8 @@ void Compiler::fgInitArgInfo(GenTreeCall* call)
     {
         args = call->gtCallArgs;
         assert(args != nullptr);
-        assert(args->OperIsList());
 
-        argx = call->gtCallArgs->Current();
+        argx = call->gtCallArgs->GetNode();
 
         // We don't increment numArgs here, since we already counted this argument above.
 
@@ -2871,7 +2832,7 @@ void Compiler::fgInitArgInfo(GenTreeCall* call)
         // It will be used only on the intercepted-for-host code path to copy the arguments.
 
         GenTree* cns     = new (this, GT_CNS_INT) GenTreeIntCon(TYP_I_IMPL, fgEstimateCallStackSize(call));
-        call->gtCallArgs = gtNewListNode(cns, call->gtCallArgs);
+        call->gtCallArgs = gtPrependNewCallArg(cns, call->gtCallArgs);
         numArgs++;
 
         nonStandardArgs.Add(cns, REG_PINVOKE_COOKIE_PARAM);
@@ -2882,7 +2843,7 @@ void Compiler::fgInitArgInfo(GenTreeCall* call)
         {
             GenTree* stubAddrArg = fgGetStubAddrArg(call);
             // And push the stub address onto the list of arguments
-            call->gtCallArgs = gtNewListNode(stubAddrArg, call->gtCallArgs);
+            call->gtCallArgs = gtPrependNewCallArg(stubAddrArg, call->gtCallArgs);
 
             numArgs++;
             nonStandardArgs.Add(stubAddrArg, stubAddrArg->gtRegNum);
@@ -2907,14 +2868,14 @@ void Compiler::fgInitArgInfo(GenTreeCall* call)
 
 #if defined(_TARGET_X86_)
         // x86 passes the cookie on the stack as the final argument to the call.
-        GenTreeArgList** insertionPoint = &call->gtCallArgs;
-        for (; *insertionPoint != nullptr; insertionPoint = &(*insertionPoint)->Rest())
+        GenTreeCall::Use** insertionPoint = &call->gtCallArgs;
+        for (; *insertionPoint != nullptr; insertionPoint = &((*insertionPoint)->NextRef()))
         {
         }
-        *insertionPoint = gtNewListNode(arg, nullptr);
+        *insertionPoint = gtNewCallArgs(arg);
 #else  // !defined(_TARGET_X86_)
         // All other architectures pass the cookie in a register.
-        call->gtCallArgs = gtNewListNode(arg, call->gtCallArgs);
+        call->gtCallArgs = gtPrependNewCallArg(arg, call->gtCallArgs);
 #endif // defined(_TARGET_X86_)
 
         nonStandardArgs.Add(arg, REG_PINVOKE_COOKIE_PARAM);
@@ -2922,7 +2883,7 @@ void Compiler::fgInitArgInfo(GenTreeCall* call)
 
         // put destination into R10/EAX
         arg              = gtClone(call->gtCallAddr, true);
-        call->gtCallArgs = gtNewListNode(arg, call->gtCallArgs);
+        call->gtCallArgs = gtPrependNewCallArg(arg, call->gtCallArgs);
         numArgs++;
 
         nonStandardArgs.Add(arg, REG_PINVOKE_TARGET_PARAM);
@@ -2943,7 +2904,7 @@ void Compiler::fgInitArgInfo(GenTreeCall* call)
         indirectCellAddress->gtRegNum = REG_R2R_INDIRECT_PARAM;
 
         // Push the stub address onto the list of arguments.
-        call->gtCallArgs = gtNewListNode(indirectCellAddress, call->gtCallArgs);
+        call->gtCallArgs = gtPrependNewCallArg(indirectCellAddress, call->gtCallArgs);
 
         numArgs++;
         nonStandardArgs.Add(indirectCellAddress, indirectCellAddress->gtRegNum);
@@ -2999,9 +2960,9 @@ void Compiler::fgInitArgInfo(GenTreeCall* call)
 
         if (call->gtCallMoreFlags & GTF_CALL_M_UNMGD_THISCALL)
         {
-            noway_assert(call->gtCallArgs->gtOp.gtOp1->TypeGet() == TYP_I_IMPL ||
-                         call->gtCallArgs->gtOp.gtOp1->TypeGet() == TYP_BYREF ||
-                         call->gtCallArgs->gtOp.gtOp1->gtOper ==
+            noway_assert(call->gtCallArgs->GetNode()->TypeGet() == TYP_I_IMPL ||
+                         call->gtCallArgs->GetNode()->TypeGet() == TYP_BYREF ||
+                         call->gtCallArgs->GetNode()->gtOper ==
                              GT_NOP); // the arg was already morphed to a register (fgMorph called twice)
             maxRegArgs = 1;
         }
@@ -3062,10 +3023,9 @@ void Compiler::fgInitArgInfo(GenTreeCall* call)
     SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc;
 #endif // UNIX_AMD64_ABI
 
-    for (args = call->gtCallArgs; args; args = args->gtOp.gtOp2, argIndex++)
+    for (args = call->gtCallArgs; args != nullptr; args = args->GetNext(), argIndex++)
     {
-        assert(args->OperIsList());
-        argx                    = args->Current();
+        argx                    = args->GetNode();
         fgArgTabEntry* argEntry = nullptr;
 
         // Change the node to TYP_I_IMPL so we don't report GC info
@@ -3275,8 +3235,7 @@ void Compiler::fgInitArgInfo(GenTreeCall* call)
             // We have an argument with a struct type, but it may be be a child of a GT_COMMA
             GenTree* argObj = argx->gtEffectiveVal(true /*commaOnly*/);
 
-            assert(args->OperIsList());
-            assert(argx == args->Current());
+            assert(argx == args->GetNode());
 
             unsigned originalSize = structSize;
             originalSize          = (originalSize == 0 ? TARGET_POINTER_SIZE : originalSize);
@@ -3596,7 +3555,7 @@ void Compiler::fgInitArgInfo(GenTreeCall* call)
                         {
                             // This indicates a partial enregistration of a struct type
                             assert((isStructArg) || argx->OperIsFieldList() || argx->OperIsCopyBlkOp() ||
-                                   (argx->gtOper == GT_COMMA && (args->gtFlags & GTF_ASG)));
+                                   (argx->gtOper == GT_COMMA && (argx->gtFlags & GTF_ASG)));
                             unsigned numRegsPartial = MAX_REG_ARG - intArgRegNum;
                             assert((unsigned char)numRegsPartial == numRegsPartial);
                             call->fgArgInfo->SplitArg(argIndex, numRegsPartial, size - numRegsPartial);
@@ -3716,8 +3675,8 @@ void Compiler::fgInitArgInfo(GenTreeCall* call)
 #endif
 GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call)
 {
-    GenTree* args;
-    GenTree* argx;
+    GenTreeCall::Use* args;
+    GenTree*          argx;
 
     unsigned flagsSummary = 0;
 
@@ -3739,12 +3698,12 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call)
         // available when we call UpdateRegArg so that we correctly update the fgArgInfo
         // with the folded tree that represents the final optimized argument nodes.
         //
-        if (call->gtCallLateArgs != nullptr)
+        for (GenTreeCall::Use& use : call->LateArgs())
         {
-
-            call->gtCallLateArgs = fgMorphTree(call->gtCallLateArgs)->AsArgList();
-            flagsSummary |= call->gtCallLateArgs->gtFlags;
+            use.SetNode(fgMorphTree(use.GetNode()));
+            flagsSummary |= use.GetNode()->gtFlags;
         }
+
         assert(call->fgArgInfo != nullptr);
     }
     call->fgArgInfo->RemorphReset();
@@ -3772,17 +3731,16 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call)
     // Note that this name is a bit of a misnomer - it indicates that there are struct args
     // that occupy more than a single slot that are passed by value (not necessarily in regs).
     bool hasMultiregStructArgs = false;
-    for (args = call->gtCallArgs; args; args = args->gtOp.gtOp2, argIndex++)
+    for (args = call->gtCallArgs; args != nullptr; args = args->GetNext(), argIndex++)
     {
-        GenTree**      parentArgx = &args->gtOp.gtOp1;
+        GenTree**      parentArgx = &args->NodeRef();
         fgArgTabEntry* argEntry   = call->fgArgInfo->GetArgEntry(argIndex, reMorphing);
 
         // Morph the arg node, and update the parent and argEntry pointers.
         argx        = *parentArgx;
         argx        = fgMorphTree(argx);
         *parentArgx = argx;
-        assert(args->OperIsList());
-        assert(argx == args->Current());
+        assert(argx == args->GetNode());
 
         unsigned             argAlign     = argEntry->alignment;
         unsigned             size         = argEntry->getSize();
@@ -4139,7 +4097,7 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call)
                 GenTreeFieldList(argx->gtOp.gtOp2, OFFSETOF__CORINFO_TypedReference__type, TYP_I_IMPL, fieldList);
             fgArgTabEntry* fp = Compiler::gtArgEntryByNode(call, argx);
             fp->node          = fieldList;
-            args->gtOp.gtOp1  = fieldList;
+            args->SetNode(fieldList);
 
 #else  // !_TARGET_X86_
 
@@ -4162,7 +4120,7 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call)
             GenTree* asg         = gtNewOperNode(GT_COMMA, TYP_VOID, asgPtrSlot, asgTypeSlot);
 
             // Change the expression to "(tmp=val)"
-            args->gtOp.gtOp1 = asg;
+            args->SetNode(asg);
 
             // EvalArgsToTemps will cause tmp to actually get loaded as the argument
             call->fgArgInfo->EvalToTmp(argEntry, tmp, asg);
@@ -4216,7 +4174,7 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call)
                             GenTreeFieldList(lcl, fieldVarDsc->lvFldOffset, fieldVarDsc->lvType, nullptr);
                         fgArgTabEntry* fp = Compiler::gtArgEntryByNode(call, argx);
                         fp->node          = fieldList;
-                        args->gtOp.gtOp1  = fieldList;
+                        args->SetNode(fieldList);
                     }
                     else
                     {
@@ -4229,7 +4187,7 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call)
         }
 #endif // _TARGET_X86_
 
-        flagsSummary |= args->Current()->gtFlags;
+        flagsSummary |= args->GetNode()->gtFlags;
 
     } // end foreach argument loop
 
@@ -4238,11 +4196,6 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call)
         call->fgArgInfo->ArgsComplete();
     }
 
-    if (call->gtCallArgs)
-    {
-        UpdateGT_LISTFlags(call->gtCallArgs);
-    }
-
     /* Process the function address, if indirect call */
 
     if (call->gtCallType == CT_INDIRECT)
@@ -4298,12 +4251,6 @@ GenTreeCall* Compiler::fgMorphArgs(GenTreeCall* call)
         call->fgArgInfo->SortArgs();
 
         call->fgArgInfo->EvalArgsToTemps();
-
-        // We may have updated the arguments
-        if (call->gtCallArgs)
-        {
-            UpdateGT_LISTFlags(call->gtCallArgs);
-        }
     }
 
     if (hasMultiregStructArgs)
@@ -4351,39 +4298,35 @@ void Compiler::fgMorphMultiregStructArgs(GenTreeCall* call)
     assert(!"Logic error: no MultiregStructArgs for Windows X64 ABI");
 #endif
 
-    for (GenTree* args = call->gtCallArgs; args != nullptr; args = args->gtOp.gtOp2)
+    for (GenTreeCall::Use& use : call->Args())
     {
         // For late arguments the arg tree that is overridden is in the gtCallLateArgs list.
         // For such late args the gtCallArgList contains the setup arg node (evaluating the arg.)
         // The tree from the gtCallLateArgs list is passed to the callee. The fgArgEntry node contains the mapping
         // between the nodes in both lists. If the arg is not a late arg, the fgArgEntry->node points to itself,
         // otherwise points to the list in the late args list.
-        bool           isLateArg  = (args->gtOp.gtOp1->gtFlags & GTF_LATE_ARG) != 0;
-        fgArgTabEntry* fgEntryPtr = gtArgEntryByNode(call, args->gtOp.gtOp1);
+        bool           isLateArg  = (use.GetNode()->gtFlags & GTF_LATE_ARG) != 0;
+        fgArgTabEntry* fgEntryPtr = gtArgEntryByNode(call, use.GetNode());
         assert(fgEntryPtr != nullptr);
-        GenTree* argx     = fgEntryPtr->node;
-        GenTree* lateList = nullptr;
-        GenTree* lateNode = nullptr;
+        GenTree*          argx     = fgEntryPtr->node;
+        GenTreeCall::Use* lateUse  = nullptr;
+        GenTree*          lateNode = nullptr;
 
         if (isLateArg)
         {
-            for (GenTree* list = call->gtCallLateArgs; list; list = list->MoveNext())
+            for (GenTreeCall::Use& lateArgUse : call->LateArgs())
             {
-                assert(list->OperIsList());
-
-                GenTree* argNode = list->Current();
+                GenTree* argNode = lateArgUse.GetNode();
                 if (argx == argNode)
                 {
-                    lateList = list;
+                    lateUse  = &lateArgUse;
                     lateNode = argNode;
                     break;
                 }
             }
-            assert(lateList != nullptr && lateNode != nullptr);
+            assert((lateUse != nullptr) && (lateNode != nullptr));
         }
 
-        GenTree* arg = argx;
-
         if (!fgEntryPtr->isStruct)
         {
             continue;
@@ -4421,21 +4364,22 @@ void Compiler::fgMorphMultiregStructArgs(GenTreeCall* call)
                         }
                     }
                 }
-                arg = fgMorphMultiregStructArg(arg, fgEntryPtr);
+
+                GenTree* newArgx = fgMorphMultiregStructArg(argx, fgEntryPtr);
 
                 // Did we replace 'argx' with a new tree?
-                if (arg != argx)
+                if (newArgx != argx)
                 {
-                    fgEntryPtr->node = arg; // Record the new value for the arg in the fgEntryPtr->node
+                    fgEntryPtr->node = newArgx; // Record the new value for the arg in the fgEntryPtr->node
 
                     // link the new arg node into either the late arg list or the gtCallArgs list
                     if (isLateArg)
                     {
-                        lateList->gtOp.gtOp1 = arg;
+                        lateUse->SetNode(newArgx);
                     }
                     else
                     {
-                        args->gtOp.gtOp1 = arg;
+                        use.SetNode(newArgx);
                     }
                 }
             }
@@ -5093,11 +5037,11 @@ GenTreeFieldList* Compiler::fgMorphLclArgToFieldlist(GenTreeLclVarCommon* lcl)
 //    tree that computes address of the outgoing arg
 //
 void Compiler::fgMakeOutgoingStructArgCopy(GenTreeCall*         call,
-                                           GenTree*             args,
+                                           GenTreeCall::Use*    args,
                                            unsigned             argIndex,
                                            CORINFO_CLASS_HANDLE copyBlkClass)
 {
-    GenTree* argx = args->Current();
+    GenTree* argx = args->GetNode();
     noway_assert(argx->gtOper != GT_MKREFANY);
     fgArgTabEntry* argEntry = Compiler::gtArgEntryByNode(call, argx);
 
@@ -5135,8 +5079,8 @@ void Compiler::fgMakeOutgoingStructArgCopy(GenTreeCall*         call,
                     assert(!call->IsTailCall());
 
                     varDsc->setLvRefCnt(0, RCS_EARLY);
-                    args->gtOp.gtOp1 = lcl;
-                    argEntry->node   = lcl;
+                    args->SetNode(lcl);
+                    argEntry->node = lcl;
 
                     JITDUMP("did not have to make outgoing copy for V%2d", varNum);
                     return;
@@ -5234,7 +5178,7 @@ void Compiler::fgMakeOutgoingStructArgCopy(GenTreeCall*         call,
 
 #endif // FEATURE_FIXED_OUT_ARGS
 
-    args->gtOp.gtOp1 = arg;
+    args->SetNode(arg);
     call->fgArgInfo->EvalToTmp(argEntry, tmp, arg);
 
     return;
@@ -7333,7 +7277,7 @@ GenTree* Compiler::fgMorphPotentialTailCall(GenTreeCall* call)
     if (info.compRetBuffArg != BAD_VAR_NUM)
     {
         noway_assert(call->TypeGet() == TYP_VOID);
-        GenTree* retValBuf = call->gtCallArgs->gtOp.gtOp1;
+        GenTree* retValBuf = call->gtCallArgs->GetNode();
         if (retValBuf->gtOper != GT_LCL_VAR || retValBuf->gtLclVarCommon.gtLclNum != info.compRetBuffArg)
         {
             failTailCall("Need to copy return buffer");
@@ -7800,7 +7744,7 @@ void Compiler::fgMorphTailCallViaHelper(GenTreeCall* call, void* pfnCopyArgs)
             call->gtFlags &= ~GTF_CALL_NULLCHECK;
         }
 
-        call->gtCallArgs = gtNewListNode(objp, call->gtCallArgs);
+        call->gtCallArgs = gtPrependNewCallArg(objp, call->gtCallArgs);
     }
 
     // Add the extra VSD parameter if needed
@@ -7814,7 +7758,7 @@ void Compiler::fgMorphTailCallViaHelper(GenTreeCall* call, void* pfnCopyArgs)
         stubAddrArg->gtRegNum = REG_NA;
 
         // And push the stub address onto the list of arguments
-        call->gtCallArgs = gtNewListNode(stubAddrArg, call->gtCallArgs);
+        call->gtCallArgs = gtPrependNewCallArg(stubAddrArg, call->gtCallArgs);
     }
     else if (call->IsVirtualVtable())
     {
@@ -7883,12 +7827,12 @@ void Compiler::fgMorphTailCallViaHelper(GenTreeCall* call, void* pfnCopyArgs)
 
     // Now inject a placeholder for the real call target that codegen will generate
     GenTree* arg     = gtNewIconNode(0, TYP_I_IMPL);
-    call->gtCallArgs = gtNewListNode(arg, call->gtCallArgs);
+    call->gtCallArgs = gtPrependNewCallArg(arg, call->gtCallArgs);
 
     // Lastly inject the pointer for the copy routine
     noway_assert(pfnCopyArgs != nullptr);
     arg              = gtNewIconHandleNode(ssize_t(pfnCopyArgs), GTF_ICON_FTN_ADDR);
-    call->gtCallArgs = gtNewListNode(arg, call->gtCallArgs);
+    call->gtCallArgs = gtPrependNewCallArg(arg, call->gtCallArgs);
 
     // It is now a varargs tail call
     call->gtCallMoreFlags |= GTF_CALL_M_VARARGS | GTF_CALL_M_TAILCALL | GTF_CALL_M_TAILCALL_VIA_HELPER;
@@ -8035,7 +7979,7 @@ void Compiler::fgMorphTailCallViaHelper(GenTreeCall* call, void* pfnCopyArgs)
         // During rationalization tmp="this" and null check will
         // materialize as embedded stmts in right execution order.
         assert(thisPtr != nullptr);
-        call->gtCallArgs = gtNewListNode(thisPtr, call->gtCallArgs);
+        call->gtCallArgs = gtPrependNewCallArg(thisPtr, call->gtCallArgs);
     }
 
 #if defined(_TARGET_AMD64_)
@@ -8054,26 +7998,26 @@ void Compiler::fgMorphTailCallViaHelper(GenTreeCall* call, void* pfnCopyArgs)
         stubAddrArg->gtRegNum = REG_NA;
 
         // And push the stub address onto the list of arguments
-        call->gtCallArgs = gtNewListNode(stubAddrArg, call->gtCallArgs);
+        call->gtCallArgs = gtPrependNewCallArg(stubAddrArg, call->gtCallArgs);
     }
 
     // Now inject a placeholder for the real call target that Lower phase will generate.
     GenTree* arg     = gtNewIconNode(0, TYP_I_IMPL);
-    call->gtCallArgs = gtNewListNode(arg, call->gtCallArgs);
+    call->gtCallArgs = gtPrependNewCallArg(arg, call->gtCallArgs);
 
     // Inject the pointer for the copy routine to be used for struct copying
     noway_assert(pfnCopyArgs != nullptr);
     arg              = gtNewIconHandleNode(ssize_t(pfnCopyArgs), GTF_ICON_FTN_ADDR);
-    call->gtCallArgs = gtNewListNode(arg, call->gtCallArgs);
+    call->gtCallArgs = gtPrependNewCallArg(arg, call->gtCallArgs);
 
 #else // !_TARGET_AMD64_
 
     // Find the end of the argument list. ppArg will point at the last pointer; setting *ppArg will
     // append to the list.
-    GenTreeArgList** ppArg = &call->gtCallArgs;
-    for (GenTreeArgList* args = call->gtCallArgs; args != nullptr; args = args->Rest())
+    GenTreeCall::Use** ppArg = &call->gtCallArgs;
+    for (GenTreeCall::Use& use : call->Args())
     {
-        ppArg = (GenTreeArgList**)&args->gtOp2;
+        ppArg = &use.NextRef();
     }
     assert(ppArg != nullptr);
     assert(*ppArg == nullptr);
@@ -8081,25 +8025,25 @@ void Compiler::fgMorphTailCallViaHelper(GenTreeCall* call, void* pfnCopyArgs)
     unsigned nOldStkArgsWords =
         (compArgSize - (codeGen->intRegState.rsCalleeRegArgCount * REGSIZE_BYTES)) / REGSIZE_BYTES;
     GenTree* arg3 = gtNewIconNode((ssize_t)nOldStkArgsWords, TYP_I_IMPL);
-    *ppArg        = gtNewListNode(arg3, nullptr); // numberOfOldStackArgs
-    ppArg         = (GenTreeArgList**)&((*ppArg)->gtOp2);
+    *ppArg        = gtNewCallArgs(arg3); // numberOfOldStackArgs
+    ppArg         = &((*ppArg)->NextRef());
 
     // Inject a placeholder for the count of outgoing stack arguments that the Lowering phase will generate.
     // The constant will be replaced.
     GenTree* arg2 = gtNewIconNode(9, TYP_I_IMPL);
-    *ppArg        = gtNewListNode(arg2, nullptr); // numberOfNewStackArgs
-    ppArg         = (GenTreeArgList**)&((*ppArg)->gtOp2);
+    *ppArg        = gtNewCallArgs(arg2); // numberOfNewStackArgs
+    ppArg         = &((*ppArg)->NextRef());
 
     // Inject a placeholder for the flags.
     // The constant will be replaced.
     GenTree* arg1 = gtNewIconNode(8, TYP_I_IMPL);
-    *ppArg        = gtNewListNode(arg1, nullptr);
-    ppArg         = (GenTreeArgList**)&((*ppArg)->gtOp2);
+    *ppArg        = gtNewCallArgs(arg1);
+    ppArg         = &((*ppArg)->NextRef());
 
     // Inject a placeholder for the real call target that the Lowering phase will generate.
     // The constant will be replaced.
     GenTree* arg0 = gtNewIconNode(7, TYP_I_IMPL);
-    *ppArg        = gtNewListNode(arg0, nullptr);
+    *ppArg        = gtNewCallArgs(arg0);
 
 #endif // !_TARGET_AMD64_
 
@@ -8226,10 +8170,9 @@ void Compiler::fgMorphRecursiveFastTailCallIntoLoop(BasicBlock* block, GenTreeCa
     // Early args don't include 'this' arg. We need to account for that so that the call to gtArgEntryByArgNum
     // below has the correct second argument.
     int earlyArgIndex = (thisArg == nullptr) ? 0 : 1;
-    for (GenTreeArgList* earlyArgs = recursiveTailCall->gtCallArgs; earlyArgs != nullptr;
-         (earlyArgIndex++, earlyArgs = earlyArgs->Rest()))
+    for (GenTreeCall::Use& use : recursiveTailCall->Args())
     {
-        GenTree* earlyArg = earlyArgs->Current();
+        GenTree* earlyArg = use.GetNode();
         if (!earlyArg->IsNothingNode() && !earlyArg->IsArgPlaceHolderNode())
         {
             if ((earlyArg->gtFlags & GTF_LATE_ARG) != 0)
@@ -8252,15 +8195,15 @@ void Compiler::fgMorphRecursiveFastTailCallIntoLoop(BasicBlock* block, GenTreeCa
                 }
             }
         }
+        earlyArgIndex++;
     }
 
     // Process late args.
     int lateArgIndex = 0;
-    for (GenTreeArgList* lateArgs = recursiveTailCall->gtCallLateArgs; lateArgs != nullptr;
-         (lateArgIndex++, lateArgs = lateArgs->Rest()))
+    for (GenTreeCall::Use& use : recursiveTailCall->LateArgs())
     {
         // A late argument is an actual argument that needs to be assigned to the corresponding caller's parameter.
-        GenTree*       lateArg        = lateArgs->Current();
+        GenTree*       lateArg        = use.GetNode();
         fgArgTabEntry* curArgTabEntry = gtArgEntryByLateArgIndex(recursiveTailCall, lateArgIndex);
         GenTreeStmt*   paramAssignStmt =
             fgAssignRecursiveCallArgToCallerParam(lateArg, curArgTabEntry, block, callILOffset,
@@ -8271,6 +8214,7 @@ void Compiler::fgMorphRecursiveFastTailCallIntoLoop(BasicBlock* block, GenTreeCa
             // All temp assignments will happen before the first param assignment.
             tmpAssignmentInsertionPoint = paramAssignStmt;
         }
+        lateArgIndex++;
     }
 
     // If the method has starg.s 0 or ldarga.s 0 a special local (lvaArg0Var) is created so that
@@ -8521,7 +8465,7 @@ GenTree* Compiler::fgMorphCall(GenTreeCall* call)
         // This is call to CORINFO_HELP_VIRTUAL_FUNC_PTR with ignored result.
         // Transform it into a null check.
 
-        GenTree* thisPtr = call->gtCallArgs->gtOp.gtOp1;
+        GenTree* thisPtr = call->gtCallArgs->GetNode();
 
         GenTree* nullCheck = gtNewOperNode(GT_IND, TYP_I_IMPL, thisPtr);
         nullCheck->gtFlags |= GTF_EXCEPT;
@@ -8593,7 +8537,7 @@ GenTree* Compiler::fgMorphCall(GenTreeCall* call)
         // if we're passing the caller's ret buff arg to the callee, since the caller's caller
         // will maintain the same invariant.)
 
-        GenTree* dest = call->gtCallArgs->gtOp.gtOp1;
+        GenTree* dest = call->gtCallArgs->GetNode();
         assert(dest->OperGet() != GT_ARGPLACE); // If it was, we'd be in a remorph, which we've already excluded above.
         if (dest->gtType == TYP_BYREF && !(dest->OperGet() == GT_ADDR && dest->gtOp.gtOp1->OperGet() == GT_LCL_VAR))
         {
@@ -8616,7 +8560,7 @@ GenTree* Compiler::fgMorphCall(GenTreeCall* call)
             }
         }
 
-        call->gtCallArgs->gtOp.gtOp1 = dest;
+        call->gtCallArgs->SetNode(dest);
     }
 
     /* Process the "normal" argument list */
@@ -8638,9 +8582,9 @@ GenTree* Compiler::fgMorphCall(GenTreeCall* call)
             // Either or both of the array and index arguments may have been spilled to temps by `fgMorphArgs`. Copy
             // the spill trees as well if necessary.
             GenTreeOp* argSetup = nullptr;
-            for (GenTreeArgList* earlyArgs = call->gtCallArgs; earlyArgs != nullptr; earlyArgs = earlyArgs->Rest())
+            for (GenTreeCall::Use& use : call->Args())
             {
-                GenTree* const arg = earlyArgs->Current();
+                GenTree* const arg = use.GetNode();
                 if (arg->OperGet() != GT_ASG)
                 {
                     continue;
@@ -8701,9 +8645,9 @@ GenTree* Compiler::fgMorphCall(GenTreeCall* call)
         info.compCompHnd->getIntrinsicID(call->gtCallMethHnd) == CORINFO_INTRINSIC_GetManagedThreadId)
     {
         noway_assert(origDest == nullptr);
-        noway_assert(call->gtCallLateArgs->gtOp.gtOp1 != nullptr);
+        noway_assert(call->gtCallLateArgs->GetNode() != nullptr);
 
-        GenTree* innerCall = call->gtCallLateArgs->gtOp.gtOp1;
+        GenTree* innerCall = call->gtCallLateArgs->GetNode();
 
         if (innerCall->gtOper == GT_CALL && (innerCall->gtCall.gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC) &&
             info.compCompHnd->getIntrinsicID(innerCall->gtCall.gtCallMethHnd) ==
@@ -8800,15 +8744,15 @@ GenTree* Compiler::fgMorphConst(GenTree* tree)
         {
             // For un-important blocks, we want to construct the string lazily
 
-            GenTreeArgList* args;
+            GenTreeCall::Use* args;
             if (helper == CORINFO_HELP_STRCNS_CURRENT_MODULE)
             {
-                args = gtNewArgList(gtNewIconNode(RidFromToken(tree->gtStrCon.gtSconCPX), TYP_INT));
+                args = gtNewCallArgs(gtNewIconNode(RidFromToken(tree->gtStrCon.gtSconCPX), TYP_INT));
             }
             else
             {
-                args = gtNewArgList(gtNewIconNode(RidFromToken(tree->gtStrCon.gtSconCPX), TYP_INT),
-                                    gtNewIconEmbScpHndNode(tree->gtStrCon.gtScpHnd));
+                args = gtNewCallArgs(gtNewIconNode(RidFromToken(tree->gtStrCon.gtSconCPX), TYP_INT),
+                                     gtNewIconEmbScpHndNode(tree->gtStrCon.gtScpHnd));
             }
 
             tree = gtNewHelperCallNode(helper, TYP_REF, args);
@@ -10974,7 +10918,7 @@ GenTree* Compiler::fgMorphRecognizeBoxNullable(GenTree* compare)
     }
 
     // Get the nullable struct argument
-    GenTree* arg = opCall->gtCall.gtCallArgs->gtOp.gtOp2->gtOp.gtOp1;
+    GenTree* arg = opCall->AsCall()->gtCallArgs->GetNext()->GetNode();
 
     // Check for cases that are unsafe to optimize and return the unchanged tree
     if (arg->IsArgPlaceHolderNode() || arg->IsNothingNode() || ((arg->gtFlags & GTF_LATE_ARG) != 0))
@@ -11705,7 +11649,7 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac)
                 return fgMorphTree(tree);
             }
         }
-            return fgMorphIntoHelperCall(tree, helper, gtNewArgList(op1, op2));
+            return fgMorphIntoHelperCall(tree, helper, gtNewCallArgs(op1, op2));
 
         case GT_RETURN:
             // normalize small integer return values
@@ -11764,9 +11708,9 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac)
                 switch (tree->TypeGet())
                 {
                     case TYP_DOUBLE:
-                        return fgMorphIntoHelperCall(tree, CORINFO_HELP_DBLROUND, gtNewArgList(op1));
+                        return fgMorphIntoHelperCall(tree, CORINFO_HELP_DBLROUND, gtNewCallArgs(op1));
                     case TYP_FLOAT:
-                        return fgMorphIntoHelperCall(tree, CORINFO_HELP_FLTROUND, gtNewArgList(op1));
+                        return fgMorphIntoHelperCall(tree, CORINFO_HELP_FLTROUND, gtNewCallArgs(op1));
                     default:
                         unreached();
                 }
@@ -16276,7 +16220,7 @@ GenTree* Compiler::fgInitThisClass()
             // base of the class that owns the method being compiled". If we're in this method, it means we're not
             // inlining and there's no ambiguity.
             return impReadyToRunHelperToTree(&resolvedToken, CORINFO_HELP_READYTORUN_GENERIC_STATIC_BASE, TYP_BYREF,
-                                             gtNewArgList(ctxTree), &kind);
+                                             gtNewCallArgs(ctxTree), &kind);
         }
 #endif
 
@@ -16297,20 +16241,20 @@ GenTree* Compiler::fgInitThisClass()
                     vtTree->gtFlags |= GTF_EXCEPT; // Null-pointer exception
                     GenTree* methodHnd = gtNewIconEmbMethHndNode(info.compMethodHnd);
 
-                    return gtNewHelperCallNode(CORINFO_HELP_INITINSTCLASS, TYP_VOID, gtNewArgList(vtTree, methodHnd));
+                    return gtNewHelperCallNode(CORINFO_HELP_INITINSTCLASS, TYP_VOID, gtNewCallArgs(vtTree, methodHnd));
                 }
 
             case CORINFO_LOOKUP_CLASSPARAM:
             {
                 GenTree* vtTree = gtNewLclvNode(info.compTypeCtxtArg, TYP_I_IMPL);
-                return gtNewHelperCallNode(CORINFO_HELP_INITCLASS, TYP_VOID, gtNewArgList(vtTree));
+                return gtNewHelperCallNode(CORINFO_HELP_INITCLASS, TYP_VOID, gtNewCallArgs(vtTree));
             }
 
             case CORINFO_LOOKUP_METHODPARAM:
             {
                 GenTree* methHndTree = gtNewLclvNode(info.compTypeCtxtArg, TYP_I_IMPL);
                 return gtNewHelperCallNode(CORINFO_HELP_INITINSTCLASS, TYP_VOID,
-                                           gtNewArgList(gtNewIconNode(0), methHndTree));
+                                           gtNewCallArgs(gtNewIconNode(0), methHndTree));
             }
         }
     }
@@ -16898,9 +16842,9 @@ void Compiler::fgMorph()
             if (lvaTable[i].TypeGet() == TYP_REF)
             {
                 // confirm that the argument is a GC pointer (for debugging (GC stress))
-                GenTree*        op   = gtNewLclvNode(i, TYP_REF);
-                GenTreeArgList* args = gtNewArgList(op);
-                op                   = gtNewHelperCallNode(CORINFO_HELP_CHECK_OBJ, TYP_VOID, args);
+                GenTree*          op   = gtNewLclvNode(i, TYP_REF);
+                GenTreeCall::Use* args = gtNewCallArgs(op);
+                op                     = gtNewHelperCallNode(CORINFO_HELP_CHECK_OBJ, TYP_VOID, args);
 
                 fgEnsureFirstBBisScratch();
                 fgNewStmtAtEnd(fgFirstBB, op);
index 40d46e4..2dcc4c2 100644 (file)
@@ -453,7 +453,7 @@ GenTree* ObjectAllocator::MorphAllocObjNodeIntoHelperCall(GenTreeAllocObj* alloc
     unsigned int helper               = allocObj->gtNewHelper;
     bool         helperHasSideEffects = allocObj->gtHelperHasSideEffects;
 
-    GenTreeArgList* args;
+    GenTreeCall::Use* args;
 #ifdef FEATURE_READYTORUN_COMPILER
     CORINFO_CONST_LOOKUP entryPoint = allocObj->gtEntryPoint;
     if (helper == CORINFO_HELP_READYTORUN_NEW)
@@ -463,7 +463,7 @@ GenTree* ObjectAllocator::MorphAllocObjNodeIntoHelperCall(GenTreeAllocObj* alloc
     else
 #endif
     {
-        args = comp->gtNewArgList(op1);
+        args = comp->gtNewCallArgs(op1);
     }
 
     const bool morphArgs  = false;
index 288cdda..4240f52 100644 (file)
@@ -139,7 +139,7 @@ void Rationalizer::RewriteNodeAsCall(GenTree**             use,
 #ifdef FEATURE_READYTORUN_COMPILER
                                      CORINFO_CONST_LOOKUP entryPoint,
 #endif
-                                     GenTreeArgList* args)
+                                     GenTreeCall::Use* args)
 {
     GenTree* const tree           = *use;
     GenTree* const treeFirstNode  = comp->fgGetFirstNode(tree);
@@ -209,14 +209,14 @@ void Rationalizer::RewriteIntrinsicAsUserCall(GenTree** use, ArrayStack<GenTree*
 {
     GenTreeIntrinsic* intrinsic = (*use)->AsIntrinsic();
 
-    GenTreeArgList* args;
+    GenTreeCall::Use* args;
     if (intrinsic->gtOp.gtOp2 == nullptr)
     {
-        args = comp->gtNewArgList(intrinsic->gtGetOp1());
+        args = comp->gtNewCallArgs(intrinsic->gtGetOp1());
     }
     else
     {
-        args = comp->gtNewArgList(intrinsic->gtGetOp1(), intrinsic->gtGetOp2());
+        args = comp->gtNewCallArgs(intrinsic->gtGetOp1(), intrinsic->gtGetOp2());
     }
 
     RewriteNodeAsCall(use, parents, intrinsic->gtMethodHandle,
index 83ec879..1eedc5d 100644 (file)
@@ -45,7 +45,7 @@ private:
 #ifdef FEATURE_READYTORUN_COMPILER
                            CORINFO_CONST_LOOKUP entryPoint,
 #endif
-                           GenTreeArgList* args);
+                           GenTreeCall::Use* args);
 
     void RewriteIntrinsicAsUserCall(GenTree** use, Compiler::GenTreeStack& parents);
 
index 04726e0..5f66ea8 100644 (file)
@@ -8393,9 +8393,9 @@ void Compiler::fgValueNumberHelperCallFunc(GenTreeCall* call, VNFunc vnf, ValueN
 {
     unsigned nArgs = ValueNumStore::VNFuncArity(vnf);
     assert(vnf != VNF_Boundary);
-    GenTreeArgList* args                    = call->gtCallArgs;
-    bool            generateUniqueVN        = false;
-    bool            useEntryPointAddrAsArg0 = false;
+    GenTreeCall::Use* args                    = call->gtCallArgs;
+    bool              generateUniqueVN        = false;
+    bool              useEntryPointAddrAsArg0 = false;
 
     switch (vnf)
     {
@@ -8409,7 +8409,7 @@ void Compiler::fgValueNumberHelperCallFunc(GenTreeCall* call, VNFunc vnf, ValueN
         case VNF_JitNewArr:
         {
             generateUniqueVN  = true;
-            ValueNumPair vnp1 = vnStore->VNPNormalPair(args->Rest()->Current()->gtVNPair);
+            ValueNumPair vnp1 = vnStore->VNPNormalPair(args->GetNext()->GetNode()->gtVNPair);
 
             // The New Array helper may throw an overflow exception
             vnpExc = vnStore->VNPExcSetSingleton(vnStore->VNPairForFunc(TYP_REF, VNF_NewArrOverflowExc, vnp1));
@@ -8440,7 +8440,7 @@ void Compiler::fgValueNumberHelperCallFunc(GenTreeCall* call, VNFunc vnf, ValueN
         case VNF_JitReadyToRunNewArr:
         {
             generateUniqueVN  = true;
-            ValueNumPair vnp1 = vnStore->VNPNormalPair(args->Current()->gtVNPair);
+            ValueNumPair vnp1 = vnStore->VNPNormalPair(args->GetNode()->gtVNPair);
 
             // The New Array helper may throw an overflow exception
             vnpExc = vnStore->VNPExcSetSingleton(vnStore->VNPairForFunc(TYP_REF, VNF_NewArrOverflowExc, vnp1));
@@ -8480,7 +8480,7 @@ void Compiler::fgValueNumberHelperCallFunc(GenTreeCall* call, VNFunc vnf, ValueN
     if (call->IsR2RRelativeIndir())
     {
 #ifdef DEBUG
-        assert(args->Current()->OperGet() == GT_ARGPLACE);
+        assert(args->GetNode()->OperGet() == GT_ARGPLACE);
 
         // Find the corresponding late arg.
         GenTree* indirectCellAddress = call->fgArgInfo->GetArgNode(0);
@@ -8507,7 +8507,7 @@ void Compiler::fgValueNumberHelperCallFunc(GenTreeCall* call, VNFunc vnf, ValueN
     else
     {
         auto getCurrentArg = [call, &args, useEntryPointAddrAsArg0](int currentIndex) {
-            GenTree* arg = args->Current();
+            GenTree* arg = args->GetNode();
             if ((arg->gtFlags & GTF_LATE_ARG) != 0)
             {
                 // This arg is a setup node that moves the arg into position.
@@ -8544,7 +8544,7 @@ void Compiler::fgValueNumberHelperCallFunc(GenTreeCall* call, VNFunc vnf, ValueN
             // Also include in the argument exception sets
             vnpExc = vnStore->VNPExcSetUnion(vnpExc, vnp0x);
 
-            args = args->Rest();
+            args = args->GetNext();
         }
         if (nArgs == 1)
         {
@@ -8566,7 +8566,7 @@ void Compiler::fgValueNumberHelperCallFunc(GenTreeCall* call, VNFunc vnf, ValueN
             vnStore->VNPUnpackExc(vnp1wx, &vnp1, &vnp1x);
             vnpExc = vnStore->VNPExcSetUnion(vnpExc, vnp1x);
 
-            args = args->Rest();
+            args = args->GetNext();
             if (nArgs == 2)
             {
                 if (generateUniqueVN)
@@ -8586,7 +8586,7 @@ void Compiler::fgValueNumberHelperCallFunc(GenTreeCall* call, VNFunc vnf, ValueN
                 vnStore->VNPUnpackExc(vnp2wx, &vnp2, &vnp2x);
                 vnpExc = vnStore->VNPExcSetUnion(vnpExc, vnp2x);
 
-                args = args->Rest();
+                args = args->GetNext();
                 assert(nArgs == 3); // Our current maximum.
                 assert(args == nullptr);
                 if (generateUniqueVN)
@@ -8610,19 +8610,16 @@ void Compiler::fgValueNumberCall(GenTreeCall* call)
 {
     // First: do value numbering of any argument placeholder nodes in the argument list
     // (by transferring from the VN of the late arg that they are standing in for...)
-    unsigned        i               = 0;
-    GenTreeArgList* args            = call->gtCallArgs;
-    bool            updatedArgPlace = false;
-    while (args != nullptr)
+    unsigned i = 0;
+    for (GenTreeCall::Use& use : call->Args())
     {
-        GenTree* arg = args->Current();
+        GenTree* arg = use.GetNode();
         if (arg->OperGet() == GT_ARGPLACE)
         {
             // Find the corresponding late arg.
             GenTree* lateArg = call->fgArgInfo->GetArgNode(i);
             assert(lateArg->gtVNPair.BothDefined());
-            arg->gtVNPair   = lateArg->gtVNPair;
-            updatedArgPlace = true;
+            arg->gtVNPair = lateArg->gtVNPair;
 #ifdef DEBUG
             if (verbose)
             {
@@ -8635,13 +8632,6 @@ void Compiler::fgValueNumberCall(GenTreeCall* call)
 #endif
         }
         i++;
-        args = args->Rest();
-    }
-    if (updatedArgPlace)
-    {
-        // Now we have to update the VN's of the argument list nodes, since that will be used in determining
-        // loop-invariance.
-        fgUpdateArgListVNs(call->gtCallArgs);
     }
 
     if (call->gtCallType == CT_HELPER)
@@ -8670,17 +8660,6 @@ void Compiler::fgValueNumberCall(GenTreeCall* call)
     }
 }
 
-void Compiler::fgUpdateArgListVNs(GenTreeArgList* args)
-{
-    if (args == nullptr)
-    {
-        return;
-    }
-    // Otherwise...
-    fgUpdateArgListVNs(args->Rest());
-    fgValueNumberTree(args);
-}
-
 VNFunc Compiler::fgValueNumberJitHelperMethodVNFunc(CorInfoHelpFunc helpFunc)
 {
     assert(s_helperCallProperties.IsPure(helpFunc) || s_helperCallProperties.IsAllocator(helpFunc));