@@ -777,7 +777,7 @@ class LocalUses
777
8000
777
else if (lcl->lvIsParam )
778
778
{
779
779
// For parameters, the backend may be able to map it directly from a register.
780
- if (MapsToRegister (comp, access, lclNum ))
780
+ if (Promotion::MapsToParameterRegister (comp, lclNum, access. Offset , access. AccessType ))
781
781
{
782
782
// No promotion will result in a store to stack in the prolog.
783
783
costWithout += COST_STRUCT_ACCESS_CYCLES * comp->fgFirstBB ->getBBWeight (comp);
@@ -1022,46 +1022,6 @@ class LocalUses
1022
1022
1023
1023
return nullptr ;
1024
1024
}
1025
-
1026
- // ------------------------------------------------------------------------
1027
- // MapsToRegister:
1028
- // Check if a specific access in the specified parameter local is
1029
- // expected to map to a register.
1030
- //
1031
- // Parameters:
1032
- // comp - Compiler instance
1033
- // access - Access in the local
1034
- // lclNum - Parameter lcl num
1035
- //
1036
- // Returns:
1037
- // Pointer to a matching access, or nullptr if no match was found.
1038
- //
1039
- bool MapsToRegister (Compiler* comp, const Access& access, unsigned lclNum)
1040
- {
1041
- assert (lclNum < comp->info .compArgsCount );
1042
-
1043
- if (comp->lvaIsImplicitByRefLocal (lclNum))
1044
- {
1045
- return false ;
1046
- }
1047
-
1048
- const ABIPassingInformation& abiInfo = comp->lvaGetParameterABIInfo (lclNum);
1049
- if (abiInfo.HasAnyStackSegment ())
1050
- {
1051
- return false ;
1052
- }
1053
-
1054
- for (const ABIPassingSegment& seg : abiInfo.Segments ())
1055
- {
1056
- if ((access.Offset == seg.Offset ) && (genTypeSize (access.AccessType ) == seg.Size ) &&
1057
- (varTypeUsesIntReg (access.AccessType ) == genIsValidIntReg (seg.GetRegister ())))
1058
- {
1059
- return true ;
1060
- }
1061
- }
1062
-
1063
- return false ;
1064
- }
1065
1025
};
1066
1026
1067
1027
// Struct used to save all struct stores involving physical promotion candidates.
@@ -1674,7 +1634,10 @@ GenTree* Promotion::CreateReadBack(Compiler* compiler, unsigned structLclNum, co
1674
1634
// Parameters:
1675
1635
// block - The block
1676
1636
//
1677
- void ReplaceVisitor::StartBlock (BasicBlock* block)
1637
+ // Returns:
1638
+ // Statement in block to start from.
1639
+ //
1640
+ Statement* ReplaceVisitor::StartBlock (BasicBlock* block)
1678
1641
{
1679
1642
m_currentBlock = block;
1680
1643
@@ -1697,9 +1660,11 @@ void ReplaceVisitor::StartBlock(BasicBlock* block)
1697
1660
// when we start the initial BB.
1698
1661
if (block != m_compiler->fgFirstBB )
1699
1662
{
1700
- return ;
1663
+ return block-> firstStmt () ;
1701
1664
}
1702
1665
1666
+ Statement* lastInsertedStmt = nullptr ;
1667
+
1703
1668
for (AggregateInfo* agg : m_aggregates)
1704
1669
{
1705
1670
LclVarDsc* dsc = m_compiler->lvaGetDesc (agg->LclNum );
@@ -1708,24 +1673,48 @@ void ReplaceVisitor::StartBlock(BasicBlock* block)
1708
1673
continue ;
1709
1674
}
1710
1675
1711
- JITDUMP (" Marking fields of %s V%02u as needing read-back in entry BB " FMT_BB " \n " ,
1712
- dsc-> lvIsParam ? " parameter " : " OSR-local " , agg->LclNum , block->bbNum );
1676
+ JITDUMP (" Processing fields of %s V%02u in entry BB " FMT_BB " \n " , dsc-> lvIsParam ? " parameter " : " OSR-local " ,
1677
+ agg->LclNum , block->bbNum );
1713
1678
1714
1679
for (size_t i = 0 ; i < agg->Replacements .size (); i++)
1715
1680
{
1716
1681
Replacement& rep = agg->Replacements [i];
1717
1682
ClearNeedsWriteBack (rep);
1718
- if (m_liveness->IsReplacementLiveIn (block, agg->LclNum , (unsigned )i))
1683
+ if (!m_liveness->IsReplacementLiveIn (block, agg->LclNum , (unsigned )i))
1684
+ {
1685
+ JITDUMP (" V%02u (%s) ignored because it is not live-in to entry BB\n " , rep.LclNum , rep.Description );
1686
+ continue ;
1687
+ }
1688
+
1689
+ if (!dsc->lvIsParam ||
1690
+ !Promotion::MapsToParameterRegister (m_compiler, agg->LclNum , rep.Offset , rep.AccessType ))
1719
1691
{
1720
1692
SetNeedsReadBack (rep);
1721
- JITDUMP (" V%02u (%s) marked\n " , rep.LclNum , rep.Description );
1693
+ JITDUMP (" V%02u (%s) marked as needing read back\n " , rep.LclNum , rep.Description );
1694
+ continue ;
1695
+ }
1696
+
1697
+ // Insert read backs of parameters mapping to registers eagerly to
1698
+ // set the backend up for recognizing these as register accesses.
1699
+ GenTree* readBack = Promotion::CreateReadBack (m_compiler, agg->LclNum , rep);
1700
+ Statement* stmt = m_compiler->fgNewStmtFromTree (readBack);
1701
+ JITDUMP (" V%02u (%s) is read back eagerly because it is a register parameter\n " , rep.LclNum ,
1702
+ rep.Description );
1703
+ DISPSTMT (stmt);
1704
+ if (lastInsertedStmt == nullptr )
1705
+ {
1706
+ m_compiler->fgInsertStmtAtBeg (block, stmt);
1722
1707
}
1723
1708
else
1724
1709
{
1725
- JITDUMP ( " V%02u (%s) not marked (not live-in to entry BB) \n " , rep. LclNum , rep. Description );
1710
+ m_compiler-> fgInsertStmtAfter (block, lastInsertedStmt, stmt );
1726
1711
}
1712
+ lastInsertedStmt = stmt;
1727
1713
}
1728
1714
}
1715
+
1716
+ // Skip all the eager read-backs if any were inserted.
1717
+ return lastInsertedStmt == nullptr ? block->firstStmt () : lastInsertedStmt->GetNextStmt ();
1729
1718
}
1730
1719
1731
1720
// ------------------------------------------------------------------------
@@ -3031,13 +3020,13 @@ PhaseStatus Promotion::Run()
3031
3020
ReplaceVisitor replacer (this , aggregates, &liveness);
3032
3021
for (BasicBlock* bb : m_compiler->Blocks ())
3033
3022
{
3034
- replacer.StartBlock (bb);
3023
+ Statement* firstStmt = replacer.StartBlock (bb);
3035
3024
3036
3025
JITDUMP (" \n Replacing in " );
3037
3026
DBEXEC (m_compiler->verbose , bb->dspBlockHeader (m_compiler));
3038
3027
JITDUMP (" \n " );
3039
3028
3040
- for (Statement* stmt : bb-> Statements ( ))
3029
+ for (Statement* stmt : StatementList (firstStmt ))
3041
3030
{
3042
3031
replacer.StartStatement (stmt);
3043
3032
@@ -3143,6 +3132,47 @@ GenTree* Promotion::EffectiveUser(Compiler::GenTreeStack& ancestors)
3143
3132
return nullptr ;
3144
3133
}
3145
3134
3135
+ // ------------------------------------------------------------------------
3136
+ // MapsToParameterRegister:
3137
+ // Check if a specific access in the specified parameter local is
3138
+ // expected to map to a register.
3139
+ //
3140
+ // Parameters:
3141
+ // comp - Compiler instance
3142
+ // lclNum - Local being accessed into
3143
+ // offset - Offset being accessed at
3144
+ // accessType - Type of access
3145
+ //
3146
+ // Returns:
3147
+ // True if the access can be efficiently done via a parameter register.
3148
+ //
3149
+ bool Promotion::MapsToParameterRegister (Compiler* comp, unsigned lclNum, unsigned offset, var_types accessType)
3150
+ {
3151
+ assert (lclNum < comp->info .compArgsCount );
3152
+
3153
+ if (comp->opts .IsOSR ())
3154
+ {
3155
+ return false ;
3156
+ }
3157
+
3158
+ const ABIPassingInformation& abiInfo = comp->lvaGetParameterABIInfo (lclNum);
3159
+ if (abiInfo.IsPassedByReference () || abiInfo.HasAnyStackSegment ())
3160
+ {
3161
+ return false ;
3162
+ }
3163
+
3164
+ for (const ABIPassingSegment& seg : abiInfo.Segments ())
3165
+ {
3166
+ if ((offset == seg.Offset ) && (genTypeSize (accessType) == seg.Size ) &&
3167
+ (varTypeUsesIntReg (accessType) == genIsValidIntReg (seg.GetRegister ())))
3168
+ {
3169
+ return true ;
3170
+ }
3171
+ }
3172
+
3173
+ return false ;
3174
+ }
3175
+
3146
3176
// Promotion::ExplicitlyZeroInitReplacementLocals:
3147
3177
// Insert IR to zero out replacement locals if necessary.
3148
3178
//
0 commit comments