@@ -1829,13 +1829,6 @@ bool Compiler::StructPromotionHelper::CanPromoteStructVar(unsigned lclNum)
1829
1829
return false ;
1830
1830
}
1831
1831
1832
- // TODO-CQ: enable promotion for OSR locals
1833
- if (compiler->lvaIsOSRLocal (lclNum))
1834
- {
1835
- JITDUMP (" struct promotion of V%02u is disabled because it is an OSR local\n " , lclNum);
1836
- return false ;
1837
- }
1838
-
1839
1832
CORINFO_CLASS_HANDLE typeHnd = varDsc->GetStructHnd ();
1840
1833
assert (typeHnd != NO_CLASS_HANDLE);
1841
1834
@@ -5934,6 +5927,11 @@ int Compiler::lvaAssignVirtualFrameOffsetToArg(unsigned lclNum,
5934
5927
for (unsigned i = 0 ; i < varDsc->lvFieldCnt ; i++)
5935
5928
{
5936
5929
LclVarDsc* fieldVarDsc = lvaGetDesc (firstFieldNum + i);
5930
+
5931
+ JITDUMP (" Adjusting offset of dependent V%02u of arg V%02u: parent %u field %u net %u\n " , lclNum,
5932
+ firstFieldNum + i, varDsc->GetStackOffset (), fieldVarDsc->lvFldOffset ,
5933
+ varDsc->GetStackOffset () + fieldVarDsc->lvFldOffset );
5934
+
5937
5935
fieldVarDsc->SetStackOffset (varDsc->GetStackOffset () + fieldVarDsc->lvFldOffset );
5938
5936
}
5939
5937
}
@@ -6409,7 +6407,7 @@ void Compiler::lvaAssignVirtualFrameOffsetsToLocals()
6409
6407
In other words, we will not calculate the "base" address of the struct local if
6410
6408
the promotion type is PROMOTION_TYPE_FIELD_DEPENDENT.
6411
6409
*/
6412
- if (!opts. IsOSR () && lvaIsFieldOfDependentlyPromotedStruct (varDsc))
6410
+ if (lvaIsFieldOfDependentlyPromotedStruct (varDsc))
6413
6411
{
6414
6412
continue ;
6415
6413
}
@@ -6436,21 +6434,34 @@ void Compiler::lvaAssignVirtualFrameOffsetsToLocals()
6436
6434
// will refer to their memory homes.
6437
6435
if (lvaIsOSRLocal (lclNum))
6438
6436
{
6439
- // TODO-CQ: enable struct promotion for OSR locals; when that
6440
- // happens, figure out how to properly refer to the original
6441
- // frame slots for the promoted fields.
6442
- assert (!varDsc->lvIsStructField );
6437
+ if (varDsc->lvIsStructField )
6438
+ {
6439
+ const unsigned parentLclNum = varDsc->lvParentLcl ;
6440
+ const int parentOriginalOffset = info.compPatchpointInfo ->Offset (parentLclNum);
6441
+ const int offset = originalFrameStkOffs + parentOriginalOffset + varDsc->lvFldOffset ;
6442
+
6443
+ JITDUMP (" ---OSR--- V%02u (promoted field of V%02u; on tier0 frame) tier0 FP-rel offset %d tier0 "
6444
+ " frame offset %d field offset %d new virt offset "
6445
+ " %d\n " ,
6446
+ lclNum, parentLclNum, parentOriginalOffset, originalFrameStkOffs, varDsc->lvFldOffset ,
6447
+ offset);
6443
6448
6444
- // Add frampointer-relative offset of this OSR live local in the original frame
6445
- // to the offset of original frame in our new frame.
6446
- int originalOffset = info.compPatchpointInfo ->Offset (lclNum);
6447
- int offset = originalFrameStkOffs + originalOffset;
6449
+ lvaTable[lclNum].SetStackOffset (offset);
6450
+ }
6451
+ else
6452
+ {
6453
+ // Add frampointer-relative offset of this OSR live local in the original frame
6454
+ // to the offset of original frame in our new frame.
6455
+ const int originalOffset = info.compPatchpointInfo ->Offset (lclNum);
6456
+ const int offset = originalFrameStkOffs + originalOffset;
6448
6457
6449
- JITDUMP (" ---OSR--- V%02u (on tier0 frame) tier0 FP-rel offset %d tier0 frame offset %d new virt offset "
6458
+ JITDUMP (
6459
+ " ---OSR--- V%02u (on tier0 frame) tier0 FP-rel offset %d tier0 frame offset %d new virt offset "
6450
6460
" %d\n " ,
6451
6461
lclNum, originalOffset, originalFrameStkOffs, offset);
6452
6462
6453
- lvaTable[lclNum].SetStackOffset (offset);
6463
+ lvaTable[lclNum].SetStackOffset (offset);
6464
+ }
6454
6465
continue ;
6455
6466
}
6456
6467
@@ -7091,18 +7102,25 @@ void Compiler::lvaAssignFrameOffsetsToPromotedStructs()
7091
7102
// This is not true for the System V systems since there is no
7092
7103
// outgoing args space. Assign the dependently promoted fields properly.
7093
7104
//
7094
- if (varDsc->lvIsStructField
7095
- #if !defined(UNIX_AMD64_ABI) && !defined(TARGET_ARM) && !defined(TARGET_X86)
7096
- // ARM: lo/hi parts of a promoted long arg need to be updated.
7105
+ CLANG_FORMAT_COMMENT_ANCHOR;
7097
7106
7098
- // For System V platforms there is no outgoing args space.
7107
+ #if defined(UNIX_AMD64_ABI) || defined(TARGET_ARM) || defined(TARGET_X86)
7108
+ // ARM: lo/hi parts of a promoted long arg need to be updated.
7109
+ //
7110
+ // For System V platforms there is no outgoing args space.
7111
+ //
7112
+ // For System V and x86, a register passed struct arg is homed on the stack in a separate local var.
7113
+ // The offset of these structs is already calculated in lvaAssignVirtualFrameOffsetToArg methos.
7114
+ // Make sure the code below is not executed for these structs and the offset is not changed.
7115
+ //
7116
+ const bool mustProcessParams = true ;
7117
+ #else
7118
+ // OSR must also assign offsets here.
7119
+ //
7120
+ const bool mustProcessParams = opts.IsOSR ();
7121
+ #endif // defined(UNIX_AMD64_ABI) || defined(TARGET_ARM) || defined(TARGET_X86)
7099
7122
7100
- // For System V and x86, a register passed struct arg is homed on the stack in a separate local var.
7101
- // The offset of these structs is already calculated in lvaAssignVirtualFrameOffsetToArg methos.
7102
- // Make sure the code below is not executed for these structs and the offset is not changed.
7103
- && !varDsc->lvIsParam
7104
- #endif // !defined(UNIX_AMD64_ABI) && !defined(TARGET_ARM) && !defined(TARGET_X86)
7105
- )
7123
+ if (varDsc->lvIsStructField && (!varDsc->lvIsParam || mustProcessParams))
7106
7124
{
7107
7125
LclVarDsc* parentvarDsc = lvaGetDesc (varDsc->lvParentLcl );
7108
7126
lvaPromotionType promotionType = lvaGetPromotionType (parentvarDsc);
@@ -7119,6 +7137,9 @@ void Compiler::lvaAssignFrameOffsetsToPromotedStructs()
7119
7137
noway_assert (varDsc->lvOnFrame );
7120
7138
if (parentvarDsc->lvOnFrame )
7121
7139
{
7140
+ JITDUMP (" Adjusting offset of dependent V%02u of V%02u: parent %u field %u net %u\n " , lclNum,
7141
+ varDsc->lvParentLcl , parentvarDsc->GetStackOffset (), varDsc->lvFldOffset ,
7142
+ parentvarDsc->GetStackOffset () + varDsc->lvFldOffset );
7122
7143
varDsc->SetStackOffset (parentvarDsc->GetStackOffset () + varDsc->lvFldOffset );
7123
7144
}
7124
7145
else
@@ -7922,6 +7943,24 @@ Compiler::fgWalkResult Compiler::lvaStressLclFldCB(GenTree** pTree, fgWalkData*
7922
7943
return WALK_SKIP_SUBTREES;
7923
7944
}
7924
7945
7946
+ // Ignore OSR locals; if in memory, they will live on the
7947
+ // Tier0 frame and so can't have their storage adjusted.
7948
+ //
7949
+ if (pComp->lvaIsOSRLocal (lclNum))
7950
+ {
7951
+ varDsc->lvNoLclFldStress = true ;
7952
+ return WALK_SKIP_SUBTREES;
7953
+ }
7954
+
7955
+ // Likewise for Tier0 methods with patchpoints --
7956
+ // if we modify them we'll misreport their locations in the patchpoint info.
7957
+ //
7958
+ if (pComp->doesMethodHavePatchpoints () || pComp->doesMethodHavePartialCompilationPatchpoints ())
7959
+ {
7960
+ varDsc->lvNoLclFldStress = true ;
7961
+ return WALK_SKIP_SUBTREES;
7962
+ }
7963
+
7925
7964
// Fix for lcl_fld stress mode
7926
7965
if (varDsc->lvKeepType )
7927
7966
{
0 commit comments