Skip to content

Commit

Permalink
Fix no struct promotion condition for long vars on 32bit platforms. (#…
Browse files Browse the repository at this point in the history
…53067)

* fix a condition.

* Move `PromoteLongVars` to `DecomposeLongs`.

* response review
  • Loading branch information
Sergey Andreenko authored May 26, 2021
1 parent 84b7c67 commit d2072e2
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 96 deletions.
3 changes: 0 additions & 3 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -3816,9 +3816,6 @@ class Compiler

StructPromotionHelper* structPromotionHelper;

#if !defined(TARGET_64BIT)
void lvaPromoteLongVars();
#endif // !defined(TARGET_64BIT)
unsigned lvaGetFieldLocal(const LclVarDsc* varDsc, unsigned int fldOffset);
lvaPromotionType lvaGetPromotionType(const LclVarDsc* varDsc);
lvaPromotionType lvaGetPromotionType(unsigned varNum);
Expand Down
104 changes: 102 additions & 2 deletions src/coreclr/jit/decomposelongs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX*/
//
void DecomposeLongs::PrepareForDecomposition()
{
m_compiler->lvaPromoteLongVars();
PromoteLongVars();
}

//------------------------------------------------------------------------
Expand Down Expand Up @@ -1954,4 +1954,104 @@ genTreeOps DecomposeLongs::GetLoOper(genTreeOps oper)
}
}

#endif // !TARGET_64BIT
//------------------------------------------------------------------------
// PromoteLongVars: "Struct promote" all register candidate longs as if they are structs of two ints.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
void DecomposeLongs::PromoteLongVars()
{
if ((m_compiler->opts.compFlags & CLFLG_REGVAR) == 0)
{
return;
}

// The lvaTable might grow as we grab temps. Make a local copy here.
unsigned startLvaCount = m_compiler->lvaCount;
for (unsigned lclNum = 0; lclNum < startLvaCount; lclNum++)
{
LclVarDsc* varDsc = m_compiler->lvaGetDesc(lclNum);
if (!varTypeIsLong(varDsc))
{
continue;
}
if (varDsc->lvDoNotEnregister)
{
continue;
}
if (varDsc->lvRefCnt() == 0)
{
continue;
}
if (varDsc->lvIsStructField)
{
continue;
}
if (m_compiler->fgNoStructPromotion)
{
continue;
}
if (m_compiler->fgNoStructParamPromotion && varDsc->lvIsParam)
{
continue;
}

assert(!varDsc->lvIsMultiRegArgOrRet());
varDsc->lvFieldCnt = 2;
varDsc->lvFieldLclStart = m_compiler->lvaCount;
varDsc->lvPromoted = true;
varDsc->lvContainsHoles = false;

JITDUMP("\nPromoting long local V%02u:", lclNum);

bool isParam = varDsc->lvIsParam;

for (unsigned index = 0; index < 2; ++index)
{
// Grab the temp for the field local.
CLANG_FORMAT_COMMENT_ANCHOR;

#ifdef DEBUG
char buf[200];
sprintf_s(buf, sizeof(buf), "%s V%02u.%s (fldOffset=0x%x)", "field", lclNum, index == 0 ? "lo" : "hi",
index * 4);

// We need to copy 'buf' as lvaGrabTemp() below caches a copy to its argument.
size_t len = strlen(buf) + 1;
char* bufp = m_compiler->getAllocator(CMK_DebugOnly).allocate<char>(len);
strcpy_s(bufp, len, buf);
#endif

unsigned varNum =
m_compiler->lvaGrabTemp(false DEBUGARG(bufp)); // Lifetime of field locals might span multiple BBs, so
// they are long lifetime temps.

LclVarDsc* fieldVarDsc = m_compiler->lvaGetDesc(varNum);
fieldVarDsc->lvType = TYP_INT;
fieldVarDsc->lvExactSize = genTypeSize(TYP_INT);
fieldVarDsc->lvIsStructField = true;
fieldVarDsc->lvFldOffset = (unsigned char)(index * genTypeSize(TYP_INT));
fieldVarDsc->lvFldOrdinal = (unsigned char)index;
fieldVarDsc->lvParentLcl = lclNum;
// Currently we do not support enregistering incoming promoted aggregates with more than one field.
if (isParam)
{
fieldVarDsc->lvIsParam = true;
m_compiler->lvaSetVarDoNotEnregister(varNum DEBUGARG(Compiler::DNER_LongParamField));
}
}
}

#ifdef DEBUG
if (m_compiler->verbose)
{
printf("\nlvaTable after PromoteLongVars\n");
m_compiler->lvaTableDump();
}
#endif // DEBUG
}
#endif // !defined(TARGET_64BIT)
2 changes: 2 additions & 0 deletions src/coreclr/jit/decomposelongs.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ class DecomposeLongs
return *m_range;
}

void PromoteLongVars();

// Driver functions
void DecomposeRangeHelper();
GenTree* DecomposeNode(GenTree* tree);
Expand Down
6 changes: 4 additions & 2 deletions src/coreclr/jit/fgbasic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,13 @@ void Compiler::fgInit()
#ifdef DEBUG
if (!compIsForInlining())
{
if ((JitConfig.JitNoStructPromotion() & 1) == 1)
const int noStructPromotionValue = JitConfig.JitNoStructPromotion();
assert(0 <= noStructPromotionValue && noStructPromotionValue <= 2);
if (noStructPromotionValue == 1)
{
fgNoStructPromotion = true;
}
if ((JitConfig.JitNoStructPromotion() & 2) == 2)
if (noStructPromotionValue == 2)
{
fgNoStructParamPromotion = true;
}
Expand Down
3 changes: 2 additions & 1 deletion src/coreclr/jit/jitconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ CONFIG_INTEGER(JitNoHoist, W("JitNoHoist"), 0)
CONFIG_INTEGER(JitNoInline, W("JitNoInline"), 0) // Disables inlining of all methods
CONFIG_INTEGER(JitNoMemoryBarriers, W("JitNoMemoryBarriers"), 0) // If 1, don't generate memory barriers
CONFIG_INTEGER(JitNoRegLoc, W("JitNoRegLoc"), 0)
CONFIG_INTEGER(JitNoStructPromotion, W("JitNoStructPromotion"), 0) // Disables struct promotion in Jit32
CONFIG_INTEGER(JitNoStructPromotion, W("JitNoStructPromotion"), 0) // Disables struct promotion 1 - for all, 2 - for
// params.
CONFIG_INTEGER(JitNoUnroll, W("JitNoUnroll"), 0)
CONFIG_INTEGER(JitOrder, W("JitOrder"), 0)
CONFIG_INTEGER(JitQueryCurrentStaticFieldClass, W("JitQueryCurrentStaticFieldClass"), 1)
Expand Down
88 changes: 0 additions & 88 deletions src/coreclr/jit/lclvars.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2459,94 +2459,6 @@ void Compiler::StructPromotionHelper::PromoteStructVar(unsigned lclNum)
}
}

#if !defined(TARGET_64BIT)
//------------------------------------------------------------------------
// lvaPromoteLongVars: "Struct promote" all register candidate longs as if they are structs of two ints.
//
// Arguments:
// None.
//
// Return Value:
// None.
//
void Compiler::lvaPromoteLongVars()
{
if ((opts.compFlags & CLFLG_REGVAR) == 0)
{
return;
}

// The lvaTable might grow as we grab temps. Make a local copy here.
unsigned startLvaCount = lvaCount;
for (unsigned lclNum = 0; lclNum < startLvaCount; lclNum++)
{
LclVarDsc* varDsc = &lvaTable[lclNum];
if (!varTypeIsLong(varDsc) || varDsc->lvDoNotEnregister || (varDsc->lvRefCnt() == 0) ||
varDsc->lvIsStructField || (fgNoStructPromotion && varDsc->lvIsParam))
{
continue;
}

assert(!varDsc->lvIsMultiRegArgOrRet());
varDsc->lvFieldCnt = 2;
varDsc->lvFieldLclStart = lvaCount;
varDsc->lvPromoted = true;
varDsc->lvContainsHoles = false;

#ifdef DEBUG
if (verbose)
{
printf("\nPromoting long local V%02u:", lclNum);
}
#endif

bool isParam = varDsc->lvIsParam;

for (unsigned index = 0; index < 2; ++index)
{
// Grab the temp for the field local.
CLANG_FORMAT_COMMENT_ANCHOR;

#ifdef DEBUG
char buf[200];
sprintf_s(buf, sizeof(buf), "%s V%02u.%s (fldOffset=0x%x)", "field", lclNum, index == 0 ? "lo" : "hi",
index * 4);

// We need to copy 'buf' as lvaGrabTemp() below caches a copy to its argument.
size_t len = strlen(buf) + 1;
char* bufp = getAllocator(CMK_DebugOnly).allocate<char>(len);
strcpy_s(bufp, len, buf);
#endif

unsigned varNum = lvaGrabTemp(false DEBUGARG(bufp)); // Lifetime of field locals might span multiple BBs, so
// they are long lifetime temps.

LclVarDsc* fieldVarDsc = &lvaTable[varNum];
fieldVarDsc->lvType = TYP_INT;
fieldVarDsc->lvExactSize = genTypeSize(TYP_INT);
fieldVarDsc->lvIsStructField = true;
fieldVarDsc->lvFldOffset = (unsigned char)(index * genTypeSize(TYP_INT));
fieldVarDsc->lvFldOrdinal = (unsigned char)index;
fieldVarDsc->lvParentLcl = lclNum;
// Currently we do not support enregistering incoming promoted aggregates with more than one field.
if (isParam)
{
fieldVarDsc->lvIsParam = true;
lvaSetVarDoNotEnregister(varNum DEBUGARG(DNER_LongParamField));
}
}
}

#ifdef DEBUG
if (verbose)
{
printf("\nlvaTable after lvaPromoteLongVars\n");
lvaTableDump();
}
#endif // DEBUG
}
#endif // !defined(TARGET_64BIT)

//--------------------------------------------------------------------------------------------
// lvaGetFieldLocal - returns the local var index for a promoted field in a promoted struct var.
//
Expand Down

0 comments on commit d2072e2

Please sign in to comment.