Skip to content

Commit

Permalink
Enregister structs on win x64. (#55045)
Browse files Browse the repository at this point in the history
* Enreg structs x64 windows.

* try to get zero diffs on other platforms.

* fix comment
  • Loading branch information
Sergey Andreenko committed Jul 9, 2021
1 parent 03cb946 commit ede3733
Show file tree
Hide file tree
Showing 8 changed files with 45 additions and 37 deletions.
14 changes: 4 additions & 10 deletions src/coreclr/jit/codegencommon.cpp
Expand Up @@ -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);

Expand Down
16 changes: 5 additions & 11 deletions src/coreclr/jit/codegenlinear.cpp
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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);
}
}

Expand Down
11 changes: 10 additions & 1 deletion src/coreclr/jit/compiler.h
Expand Up @@ -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
Expand Down
8 changes: 6 additions & 2 deletions src/coreclr/jit/jitconfigvalues.h
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/lclvars.cpp
Expand Up @@ -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));
}
Expand Down
23 changes: 12 additions & 11 deletions src/coreclr/jit/lower.cpp
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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));
}

Expand All @@ -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))
{
Expand Down Expand Up @@ -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;

Expand All @@ -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);
Expand Down Expand Up @@ -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())
{
Expand Down
6 changes: 6 additions & 0 deletions src/coreclr/jit/lowerxarch.cpp
Expand Up @@ -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))
{
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/lsra.cpp
Expand Up @@ -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
Expand Down

0 comments on commit ede3733

Please sign in to comment.