diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index 78926e64fda65..99852d7f44612 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -4355,16 +4355,10 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere #endif // defined(UNIX_AMD64_ABI) noway_assert(varDsc->lvIsParam && varDsc->lvIsRegArg); -#ifndef TARGET_64BIT -#ifndef TARGET_ARM - // Right now we think that incoming arguments are not pointer sized. When we eventually - // understand the calling convention, this still won't be true. But maybe we'll have a better - // idea of how to ignore it. - - // On Arm, a long can be passed in register - noway_assert(genTypeSize(genActualType(varDsc->TypeGet())) == TARGET_POINTER_SIZE); -#endif -#endif // TARGET_64BIT +#ifdef TARGET_X86 + // On x86 we don't enregister args that are not pointer sized. + noway_assert(genTypeSize(varDsc->GetActualRegisterType()) == TARGET_POINTER_SIZE); +#endif // TARGET_X86 noway_assert(varDsc->lvIsInReg() && !regArgTab[argNum].circular); diff --git a/src/coreclr/jit/codegenlinear.cpp b/src/coreclr/jit/codegenlinear.cpp index 8bf1f852ffd4d..eb942332554f3 100644 --- a/src/coreclr/jit/codegenlinear.cpp +++ b/src/coreclr/jit/codegenlinear.cpp @@ -1191,12 +1191,12 @@ void CodeGen::genUnspillRegIfNeeded(GenTree* tree) assert(spillType != TYP_UNDEF); // TODO-Cleanup: The following code could probably be further merged and cleaned up. -#ifdef TARGET_XARCH +#if defined(TARGET_XARCH) || defined(TARGET_ARM64) // Load local variable from its home location. // In most cases the tree type will indicate the correct type to use for the load. // However, if it is NOT a normalizeOnLoad lclVar (i.e. NOT a small int that always gets - // widened when loaded into a register), and its size is not the same as genActualType of - // the type of the lclVar, then we need to change the type of the tree node when loading. + // widened when loaded into a register), and its size is not the same as the actual register type + // of the lclVar, then we need to change the type of the tree node when loading. // This situation happens due to "optimizations" that avoid a cast and // simply retype the node when using long type lclVar as an int. // While loading the int in that case would work for this use of the lclVar, if it is @@ -1210,13 +1210,6 @@ void CodeGen::genUnspillRegIfNeeded(GenTree* tree) assert(!varTypeIsGC(varDsc)); spillType = lclActualType; } -#elif defined(TARGET_ARM64) - var_types targetType = unspillTree->gtType; - if (spillType != genActualType(varDsc->lvType) && !varTypeIsGC(spillType) && !varDsc->lvNormalizeOnLoad()) - { - assert(!varTypeIsGC(varDsc)); - spillType = genActualType(varDsc->lvType); - } #elif defined(TARGET_ARM) // No normalizing for ARM #else @@ -1465,7 +1458,8 @@ regNumber CodeGen::genConsumeReg(GenTree* tree) LclVarDsc* varDsc = &compiler->lvaTable[lcl->GetLclNum()]; if (varDsc->GetRegNum() != REG_STK) { - inst_Mov(tree->TypeGet(), tree->GetRegNum(), varDsc->GetRegNum(), /* canSkip */ true); + var_types regType = varDsc->GetRegisterType(lcl); + inst_Mov(regType, tree->GetRegNum(), varDsc->GetRegNum(), /* canSkip */ true); } } diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 639b67bb15c94..f816e6917a604 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -1016,11 +1016,20 @@ class LclVarDsc var_types GetActualRegisterType() const; - bool IsEnregisterable() const + bool IsEnregisterableType() const { return GetRegisterType() != TYP_UNDEF; } + bool IsEnregisterableLcl() const + { + if (lvDoNotEnregister) + { + return false; + } + return IsEnregisterableType(); + } + bool CanBeReplacedWithItsField(Compiler* comp) const; #ifdef DEBUG diff --git a/src/coreclr/jit/jitconfigvalues.h b/src/coreclr/jit/jitconfigvalues.h index cc10adc0b8809..7254e205fbc48 100644 --- a/src/coreclr/jit/jitconfigvalues.h +++ b/src/coreclr/jit/jitconfigvalues.h @@ -552,8 +552,12 @@ CONFIG_INTEGER(JitSaveFpLrWithCalleeSavedRegisters, W("JitSaveFpLrWithCalleeSave #endif // defined(TARGET_ARM64) #endif // DEBUG -// Allow to enregister locals with struct type. -CONFIG_INTEGER(JitEnregStructLocals, W("JitEnregStructLocals"), 0) +#if defined(TARGET_AMD64) && defined(TARGET_WINDOWS) +CONFIG_INTEGER(JitEnregStructLocals, W("JitEnregStructLocals"), 1) // Allow to enregister locals with struct type. +#else +CONFIG_INTEGER(JitEnregStructLocals, W("JitEnregStructLocals"), 0) // Don't allow to enregister locals with struct type + // yet. +#endif #undef CONFIG_INTEGER #undef CONFIG_STRING diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp index 603c6747c215c..b2ca56b406ba4 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -3493,7 +3493,7 @@ void Compiler::lvaSortByRefCount() { varDsc->lvTracked = 0; } - else if ((varDsc->lvType == TYP_STRUCT) && !varDsc->lvRegStruct) + else if ((varDsc->lvType == TYP_STRUCT) && !varDsc->lvRegStruct && !compEnregStructLocals()) { lvaSetVarDoNotEnregister(lclNum DEBUGARG(DNER_IsStruct)); } diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index d2a0191648e18..9499ac5d81782 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -3160,7 +3160,7 @@ void Lowering::LowerStoreLocCommon(GenTreeLclVarCommon* lclStore) #endif // !WINDOWS_AMD64_ABI convertToStoreObj = false; } - else if (!varDsc->IsEnregisterable()) + else if (!varDsc->IsEnregisterableType()) { convertToStoreObj = true; } @@ -3418,11 +3418,10 @@ void Lowering::LowerRetSingleRegStructLclVar(GenTreeUnOp* ret) lclNum = fieldLclNum; varDsc = comp->lvaGetDesc(lclNum); } - else if (!varDsc->lvRegStruct && !varTypeIsEnregisterable(varDsc)) - + else if (varDsc->lvPromoted) { - // TODO-1stClassStructs: We can no longer promote or enregister this struct, - // since it is referenced as a whole. + // TODO-1stClassStructs: We can no longer independently promote + // or enregister this struct, since it is referenced as a whole. comp->lvaSetVarDoNotEnregister(lclNum DEBUGARG(Compiler::DNER_BlockOp)); } @@ -3434,9 +3433,10 @@ void Lowering::LowerRetSingleRegStructLclVar(GenTreeUnOp* ret) } else { - var_types lclVarType = varDsc->GetRegisterType(lclVar); + const var_types lclVarType = varDsc->GetRegisterType(lclVar); assert(lclVarType != TYP_UNDEF); - lclVar->ChangeType(lclVarType); + const var_types actualType = genActualType(lclVarType); + lclVar->ChangeType(actualType); if (varTypeUsesFloatReg(ret) != varTypeUsesFloatReg(lclVarType)) { @@ -4039,12 +4039,12 @@ void Lowering::InsertPInvokeMethodProlog() GenTree* call = comp->gtNewHelperCallNode(CORINFO_HELP_INIT_PINVOKE_FRAME, TYP_I_IMPL, argList); // some sanity checks on the frame list root vardsc - LclVarDsc* varDsc = &comp->lvaTable[comp->info.compLvFrameListRoot]; + const unsigned lclNum = comp->info.compLvFrameListRoot; + const LclVarDsc* varDsc = comp->lvaGetDesc(lclNum); noway_assert(!varDsc->lvIsParam); noway_assert(varDsc->lvType == TYP_I_IMPL); - GenTree* store = - new (comp, GT_STORE_LCL_VAR) GenTreeLclVar(GT_STORE_LCL_VAR, TYP_I_IMPL, comp->info.compLvFrameListRoot); + GenTree* store = new (comp, GT_STORE_LCL_VAR) GenTreeLclVar(GT_STORE_LCL_VAR, TYP_I_IMPL, lclNum); store->AsOp()->gtOp1 = call; store->gtFlags |= GTF_VAR_DEF; @@ -4065,6 +4065,7 @@ void Lowering::InsertPInvokeMethodProlog() GenTreeLclFld(GT_STORE_LCL_FLD, TYP_I_IMPL, comp->lvaInlinedPInvokeFrameVar, callFrameInfo.offsetOfCallSiteSP); storeSP->gtOp1 = PhysReg(REG_SPBASE); storeSP->gtFlags |= GTF_VAR_DEF; + comp->lvaSetVarDoNotEnregister(comp->lvaInlinedPInvokeFrameVar DEBUGARG(Compiler::DNER_LocalField)); firstBlockRange.InsertBefore(insertionPoint, LIR::SeqTree(comp, storeSP)); DISPTREERANGE(firstBlockRange, storeSP); @@ -6534,7 +6535,7 @@ void Lowering::ContainCheckRet(GenTreeUnOp* ret) assert(varDsc->lvIsMultiRegRet || (varDsc->lvIsHfa() && varTypeIsValidHfaType(varDsc->lvType))); // Mark var as contained if not enregisterable. - if (!varTypeIsEnregisterable(op1)) + if (!varDsc->IsEnregisterableLcl()) { if (!op1->IsMultiRegLclVar()) { diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp index 55bfab94f6f5f..ed889f7f383bc 100644 --- a/src/coreclr/jit/lowerxarch.cpp +++ b/src/coreclr/jit/lowerxarch.cpp @@ -269,6 +269,12 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode) // address, not knowing that GT_IND is part of a block op that has containment restrictions. src->AsIndir()->Addr()->ClearContained(); } + else if (src->OperIs(GT_LCL_VAR)) + { + // TODO-1stClassStructs: for now we can't work with STORE_BLOCK source in register. + const unsigned srcLclNum = src->AsLclVar()->GetLclNum(); + comp->lvaSetVarDoNotEnregister(srcLclNum DEBUGARG(Compiler::DNER_BlockOp)); + } if (blkNode->OperIs(GT_STORE_OBJ)) { diff --git a/src/coreclr/jit/lsra.cpp b/src/coreclr/jit/lsra.cpp index ddc5442517466..f810ca3d3aa35 100644 --- a/src/coreclr/jit/lsra.cpp +++ b/src/coreclr/jit/lsra.cpp @@ -1490,7 +1490,7 @@ bool LinearScan::isRegCandidate(LclVarDsc* varDsc) // or enregistered, on x86 -- it is believed that we can enregister pinned (more properly, "pinning") // references when using the general GC encoding. unsigned lclNum = (unsigned)(varDsc - compiler->lvaTable); - if (varDsc->lvAddrExposed || !varDsc->IsEnregisterable() || + if (varDsc->lvAddrExposed || !varDsc->IsEnregisterableType() || (!compiler->compEnregStructLocals() && (varDsc->lvType == TYP_STRUCT))) { #ifdef DEBUG