summaryrefslogtreecommitdiff
path: root/src/jit/gentree.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/jit/gentree.cpp')
-rw-r--r--src/jit/gentree.cpp117
1 files changed, 108 insertions, 9 deletions
diff --git a/src/jit/gentree.cpp b/src/jit/gentree.cpp
index 284000e55b..3c06925fe4 100644
--- a/src/jit/gentree.cpp
+++ b/src/jit/gentree.cpp
@@ -224,7 +224,15 @@ void GenTree::InitNodeSize()
GenTree::s_gtNodeSizes[op] = TREE_NODE_SZ_SMALL;
}
- /* Now set all of the appropriate entries to 'large' */
+ // Now set all of the appropriate entries to 'large'
+
+ // On ARM and System V struct returning there
+ // is code that does GT_ASG-tree.CopyObj call.
+ // CopyObj is a large node and the GT_ASG is small, which triggers an exception.
+#if defined(_TARGET_ARM_) || defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
+ GenTree::s_gtNodeSizes[GT_ASG ] = TREE_NODE_SZ_LARGE;
+ GenTree::s_gtNodeSizes[GT_RETURN ] = TREE_NODE_SZ_LARGE;
+#endif // defined(_TARGET_ARM_) || defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
GenTree::s_gtNodeSizes[GT_CALL ] = TREE_NODE_SZ_LARGE;
GenTree::s_gtNodeSizes[GT_CAST ] = TREE_NODE_SZ_LARGE;
@@ -256,6 +264,15 @@ void GenTree::InitNodeSize()
GenTree::s_gtNodeSizes[GT_MOD ] = TREE_NODE_SZ_LARGE;
GenTree::s_gtNodeSizes[GT_UMOD ] = TREE_NODE_SZ_LARGE;
#endif
+#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
+ GenTree::s_gtNodeSizes[GT_PUTARG_STK ] = TREE_NODE_SZ_LARGE;
+#endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
+#if defined(_TARGET_ARM_) || defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
+ // In importer for Hfa and register returned structs we rewrite GT_ASG to GT_COPYOBJ/GT_CPYBLK
+ // Make sure the sizes agree.
+ assert(GenTree::s_gtNodeSizes[GT_COPYOBJ] <= GenTree::s_gtNodeSizes[GT_ASG]);
+ assert(GenTree::s_gtNodeSizes[GT_COPYBLK] <= GenTree::s_gtNodeSizes[GT_ASG]);
+#endif // !(defined(_TARGET_ARM_) || defined(FEATURE_UNIX_AMD64_STRUCT_PASSING))
assert(GenTree::s_gtNodeSizes[GT_RETURN] == GenTree::s_gtNodeSizes[GT_ASG]);
@@ -312,7 +329,12 @@ void GenTree::InitNodeSize()
static_assert_no_msg(sizeof(GenTreeArgPlace) <= TREE_NODE_SZ_SMALL);
static_assert_no_msg(sizeof(GenTreeLabel) <= TREE_NODE_SZ_SMALL);
static_assert_no_msg(sizeof(GenTreePhiArg) <= TREE_NODE_SZ_SMALL);
+#ifndef FEATURE_UNIX_AMD64_STRUCT_PASSING
static_assert_no_msg(sizeof(GenTreePutArgStk) <= TREE_NODE_SZ_SMALL);
+#else // FEATURE_UNIX_AMD64_STRUCT_PASSING
+ static_assert_no_msg(sizeof(GenTreePutArgStk) <= TREE_NODE_SZ_LARGE);
+#endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
+
#ifdef FEATURE_SIMD
static_assert_no_msg(sizeof(GenTreeSIMD) <= TREE_NODE_SZ_SMALL);
#endif // FEATURE_SIMD
@@ -4366,13 +4388,21 @@ void GenTree::InsertAfterSelf(GenTree* node, GenTreeStmt* stmt /* = n
// 'parent' must be non-null
//
// Notes:
-// Must not be called for GT_LDOBJ (which isn't used for RyuJIT, which is the only context
-// in which this method is used)
+// For non System V systems with native struct passing (i.e. FEATURE_UNIX_AMD64_STRUCT_PASSING not defined)
+// this method must not be called for GT_LDOBJ (which isn't used for RyuJIT, which is the only context
+// in which this method is used).
+// If FEATURE_UNIX_AMD64_STRUCT_PASSING is defined we can get here with GT_LDOBJ tree. This happens when
+// a struct is passed in two registers. The GT_LDOBJ is converted to a GT_LIST with two GT_LCL_FLDs later
+// in Lower/LowerXArch.
+//
GenTreePtr* GenTree::gtGetChildPointer(GenTreePtr parent)
{
+#ifndef FEATURE_UNIX_AMD64_STRUCT_PASSING
noway_assert(parent->OperGet() != GT_LDOBJ);
+#endif // !FEATURE_UNIX_AMD64_STRUCT_PASSING
+
switch (parent->OperGet())
{
default:
@@ -4380,6 +4410,14 @@ GenTreePtr* GenTree::gtGetChildPointer(GenTreePtr parent)
if (this == parent->gtOp.gtOp1) return &(parent->gtOp.gtOp1);
if (this == parent->gtOp.gtOp2) return &(parent->gtOp.gtOp2);
break;
+
+#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
+ case GT_LDOBJ:
+ // Any GT_LDOBJ with a field must be lowered before this point.
+ noway_assert(parent->AsLdObj()->gtFldTreeList == nullptr);
+ break;
+#endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
+
case GT_CMPXCHG:
if (this == parent->gtCmpXchg.gtOpLocation) return &(parent->gtCmpXchg.gtOpLocation);
if (this == parent->gtCmpXchg.gtOpValue) return &(parent->gtCmpXchg.gtOpValue);
@@ -5027,7 +5065,7 @@ GenTreePtr Compiler::gtNewInlineCandidateReturnExpr(GenTreePtr inline
GenTreePtr node = new(this, GT_RET_EXPR) GenTreeRetExpr(type);
node->gtRetExpr.gtInlineCandidate = inlineCandidate;
-#ifdef _TARGET_ARM_
+#if defined(_TARGET_ARM_) || defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
if (inlineCandidate->gtType == TYP_STRUCT)
{
if (inlineCandidate->gtOper == GT_CALL)
@@ -5067,7 +5105,13 @@ GenTreeArgList* Compiler::gtNewListNode(GenTreePtr op1, GenTreeArgList* op2)
GenTreeArgList* Compiler::gtNewArgList(GenTreePtr op)
{
- assert((op != NULL) && (op->OperGet() != GT_LIST) && (op->OperGet() != GT_LIST));
+#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
+ // With structs passed in multiple args we could have the arg
+ // GT_LIST containing a list of LCL_FLDs
+ assert((op != NULL) && ((!op->IsList()) || (op->IsListOfLclFlds())));
+#else // !FEATURE_UNIX_AMD64_STRUCT_PASSING
+ assert((op != NULL) && (op->OperGet() != GT_LIST));
+#endif // !FEATURE_UNIX_AMD64_STRUCT_PASSING
return new (this, GT_LIST) GenTreeArgList(op);
}
@@ -5079,8 +5123,15 @@ GenTreeArgList* Compiler::gtNewArgList(GenTreePtr op)
GenTreeArgList* Compiler::gtNewArgList(GenTreePtr op1, GenTreePtr op2)
{
- assert((op1 != NULL) && (op1->OperGet() != GT_LIST) && (op1->OperGet() != GT_LIST));
- assert((op2 != NULL) && (op2->OperGet() != GT_LIST) && (op2->OperGet() != GT_LIST));
+#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
+ // With structs passed in multiple args we could have the arg
+ // GT_LIST containing a list of LCL_FLDs
+ assert((op1 != NULL) && ((!op1->IsList()) || (op1->IsListOfLclFlds())));
+ assert((op2 != NULL) && ((!op2->IsList()) || (op2->IsListOfLclFlds())));
+#else // !FEATURE_UNIX_AMD64_STRUCT_PASSING
+ assert((op1 != NULL) && (!op1->IsList()));
+ assert((op2 != NULL) && (!op2->IsList()));
+#endif // !FEATURE_UNIX_AMD64_STRUCT_PASSING
GenTreePtr tree;
@@ -5207,9 +5258,11 @@ GenTreePtr Compiler::gtNewAssignNode(GenTreePtr dst, GenTreePtr src DEB
// using struct assignment.
#ifdef _TARGET_ARM_
assert(isPhiDefn || type != TYP_STRUCT || IsHfa(dst) || IsHfa(src));
-#else
+#elif defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
// You need to use GT_COPYBLK for assigning structs
// See impAssignStruct()
+ assert(isPhiDefn || type != TYP_STRUCT || IsRegisterPassable(dst) || IsRegisterPassable(src));
+#else // !FEATURE_UNIX_AMD64_STRUCT_PASSING
assert(isPhiDefn || type != TYP_STRUCT);
#endif
@@ -5553,7 +5606,6 @@ GenTreePtr Compiler::gtClone(GenTree * tree, bool complexOK)
tree->gtField.gtFldHnd,
objp,
tree->gtField.gtFldOffset);
-
}
else if (tree->gtOper == GT_ADD)
{
@@ -8629,6 +8681,51 @@ GenTreePtr Compiler::gtDispLinearTree(GenTreeStmt* curStmt,
// get child msg
if (tree->IsCall())
{
+ // If this is a call and the arg (listElem) is a GT_LIST (Unix LCL_FLD for passing a var in multiple registers)
+ // print the nodes of the nested list and continue to the next argument.
+ if (listElem->gtOper == GT_LIST)
+ {
+ GenTreePtr nextListNested = nullptr;
+ for (GenTreePtr listNested = listElem; listNested != nullptr; listNested = nextListNested)
+ {
+ GenTreePtr listElemNested;
+ if (listNested->gtOper == GT_LIST)
+ {
+ nextListNested = listNested->MoveNext();
+ listElemNested = listNested->Current();
+ }
+ else
+ {
+ // GT_LIST nodes (under initBlk, others?) can have a non-null op2 that's not a GT_LIST
+ nextListNested = nullptr;
+ listElemNested = listNested;
+ }
+
+ indentStack->Push(indentInfo);
+ if (child == tree->gtCall.gtCallArgs)
+ {
+ gtGetArgMsg(tree, listNested, listElemNum, bufp, BufLength);
+ }
+ else
+ {
+ assert(child == tree->gtCall.gtCallLateArgs);
+ gtGetLateArgMsg(tree, listNested, listElemNum, bufp, BufLength);
+ }
+ nextLinearNode = gtDispLinearTree(curStmt, nextLinearNode, listElemNested, indentStack, bufp);
+ indentStack->Pop();
+ }
+
+ // Skip the GT_LIST nodes, as we do not print them, and the next node to print will occur
+ // after the list.
+ while (nextLinearNode->OperGet() == GT_LIST)
+ {
+ nextLinearNode = nextLinearNode->gtNext;
+ }
+
+ listElemNum++;
+ continue;
+ }
+
if (child == tree->gtCall.gtCallArgs)
{
gtGetArgMsg(tree, listElem, listElemNum, bufp, BufLength);
@@ -8643,6 +8740,7 @@ GenTreePtr Compiler::gtDispLinearTree(GenTreeStmt* curStmt,
{
sprintf_s(bufp, sizeof(buf), "List Item %d", listElemNum);
}
+
indentStack->Push(indentInfo);
nextLinearNode = gtDispLinearTree(curStmt, nextLinearNode, listElem, indentStack, bufp);
indentStack->Pop();
@@ -10179,6 +10277,7 @@ LNG_ADD_CHKOVF:
}
}
}
+
lval1 = ltemp; break;
case GT_OR : lval1 |= lval2; break;