From: sivarv Date: Thu, 23 Feb 2017 18:59:28 +0000 (-0800) Subject: Enable promotion of structs containing fields of structs with a single pointer-sized... X-Git-Tag: submit/tizen/20210909.063632~11030^2~7981^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8db4be59f18d384b1f2cdc49b3a5e953d7ec6aec;p=platform%2Fupstream%2Fdotnet%2Fruntime.git Enable promotion of structs containing fields of structs with a single pointer-sized scalar type field. Commit migrated from https://github.com/dotnet/coreclr/commit/cc35e361b1c1ddeb9e36dbb293f1456a211f5216 --- diff --git a/src/coreclr/src/jit/lclvars.cpp b/src/coreclr/src/jit/lclvars.cpp index fa1ba82..56fbe07 100644 --- a/src/coreclr/src/jit/lclvars.cpp +++ b/src/coreclr/src/jit/lclvars.cpp @@ -1543,8 +1543,60 @@ void Compiler::lvaCanPromoteStructType(CORINFO_CLASS_HANDLE typeHnd, if (pFieldInfo->fldSize == 0) { + // Size of TYP_BLK, TYP_FUNC, TYP_VOID and TYP_STRUCT is zero. + // Early out if field type is other than TYP_STRUCT. + // This is a defensive check as we don't expect a struct to have + // fields of TYP_BLK, TYP_FUNC or TYP_VOID. + if (pFieldInfo->fldType != TYP_STRUCT) + { + return; + } + // Non-primitive struct field. - return; + // Try to promote structs of single field of scalar types aligned at their + // natural boundary. + + // Do Not promote if the struct field in turn has more than one field. + if (info.compCompHnd->getClassNumInstanceFields(pFieldInfo->fldTypeHnd) != 1) + { + return; + } + + // Do not promote if the single field is not aligned at its natural boundary within + // the struct field. + CORINFO_FIELD_HANDLE fHnd = info.compCompHnd->getFieldInClass(pFieldInfo->fldTypeHnd, 0); + unsigned fOffset = info.compCompHnd->getFieldOffset(fHnd); + if (fOffset != 0) + { + return; + } + + CORINFO_CLASS_HANDLE cHnd; + CorInfoType fieldCorType = info.compCompHnd->getFieldType(fHnd, &cHnd); + var_types fieldVarType = JITtype2varType(fieldCorType); + unsigned fieldSize = genTypeSize(fieldVarType); + + // Do not promote if either not a primitive type or size equal to ptr size on + // target or a struct containing a single floating-point field. + // + // TODO-PERF: Structs containing a single floating-point field on Amd64 + // needs to be passed in integer registers. Right now LSRA doesn't support + // passing of floating-point LCL_VARS in integer registers. Enabling promotion + // of such structs results in an assert in lsra right now. + // + // TODO-PERF: Right now promotion is confined to struct containing a ptr sized + // field (int/uint/ref/byref on 32-bits and long/ulong/ref/byref on 64-bits). + // Though this would serve the purpose of promoting Span containing ByReference, + // this can be extended to other primitive types as long as they are aligned at their + // natural boundary. + if (fieldSize == 0 || fieldSize != TARGET_POINTER_SIZE || varTypeIsFloating(fieldVarType)) + { + return; + } + + // Retype the field as the type of the single field of the struct + pFieldInfo->fldType = fieldVarType; + pFieldInfo->fldSize = fieldSize; } if ((pFieldInfo->fldOffset % pFieldInfo->fldSize) != 0) diff --git a/src/coreclr/src/jit/lower.cpp b/src/coreclr/src/jit/lower.cpp index b3a674e..7d672d4 100644 --- a/src/coreclr/src/jit/lower.cpp +++ b/src/coreclr/src/jit/lower.cpp @@ -971,6 +971,43 @@ GenTreePtr Lowering::NewPutArg(GenTreeCall* call, GenTreePtr arg, fgArgTabEntryP assert(!varTypeIsSIMD(arg)); numRefs = comp->info.compCompHnd->getClassGClayout(arg->gtObj.gtClass, gcLayout); putArg->AsPutArgStk()->setGcPointers(numRefs, gcLayout); + +#ifdef _TARGET_X86_ + // On x86 VM lies about the type of a struct containing a pointer sized + // integer field by returning the type of its field as the type of struct. + // Such struct can be passed in a register depending its position in + // parameter list. VM does this unwrapping only one level and therefore + // a type like Struct Foo { Struct Bar { int f}} awlays needs to be + // passed on stack. Also, VM doesn't lie about type of such a struct + // when it is a field of another struct. That is VM doesn't lie about + // the type of Foo.Bar + // + // We now support the promotion of fields that are of type struct. + // However we only support a limited case where the struct field has a + // single field and that single field must be a scalar type. Say Foo.Bar + // field is getting passed as a parameter to a call, Since it is a TYP_STRUCT, + // as per x86 ABI it should always be passed on stack. Therefore GenTree + // node under a PUTARG_STK could be GT_OBJ(GT_LCL_VAR_ADDR(v1)), where + // local v1 could be a promoted field standing for Foo.Bar. Note that + // the type of v1 will be the type of field of Foo.Bar.f when Foo is + // promoted. That is v1 will be a scalar type. In this case we need to + // pass v1 on stack instead of in a register. + // + // TODO-PERF: replace GT_OBJ(GT_LCL_VAR_ADDR(v1)) with v1 if v1 is + // a scalar type and the width of GT_OBJ matches the type size of v1. + // Note that this cannot be done till call node arguments are morphed + // because we should not lose the fact that the type of argument is + // a struct so that the arg gets correctly marked to be passed on stack. + GenTree* objOp1 = arg->gtGetOp1(); + if (objOp1->OperGet() == GT_LCL_VAR_ADDR) + { + unsigned lclNum = objOp1->AsLclVarCommon()->GetLclNum(); + if (comp->lvaTable[lclNum].lvType != TYP_STRUCT) + { + comp->lvaSetVarDoNotEnregister(lclNum DEBUGARG(Compiler::DNER_VMNeedsStackAddr)); + } + } +#endif // _TARGET_X86_ } } #endif // FEATURE_PUT_STRUCT_ARG_STK diff --git a/src/coreclr/src/jit/rationalize.cpp b/src/coreclr/src/jit/rationalize.cpp index 00e0bec..1bc3a61 100644 --- a/src/coreclr/src/jit/rationalize.cpp +++ b/src/coreclr/src/jit/rationalize.cpp @@ -732,6 +732,35 @@ Compiler::fgWalkResult Rationalizer::RewriteNode(GenTree** useEdge, ArrayStackAsIndir()->Addr(); + if (addr->OperGet() == GT_ADD && addr->gtGetOp1()->OperGet() == GT_LCL_VAR_ADDR && + addr->gtGetOp2()->IsIntegralConst(0)) + { + GenTreeLclVarCommon* lclVarNode = addr->gtGetOp1()->AsLclVarCommon(); + unsigned lclNum = lclVarNode->GetLclNum(); + LclVarDsc* varDsc = comp->lvaTable + lclNum; + if (node->TypeGet() == varDsc->TypeGet()) + { + JITDUMP("Rewriting GT_IND(GT_ADD(LCL_VAR_ADDR,0)) to LCL_VAR\n"); + lclVarNode->SetOper(GT_LCL_VAR); + lclVarNode->gtType = node->TypeGet(); + use.ReplaceWith(comp, lclVarNode); + BlockRange().Remove(addr); + BlockRange().Remove(addr->gtGetOp2()); + BlockRange().Remove(node); + } + } + } break; case GT_NOP: