diff options
Diffstat (limited to 'src/jit/gentree.cpp')
-rw-r--r-- | src/jit/gentree.cpp | 117 |
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; |