Skip to content

Commit 5a30553

Browse files
Introduce ASG rationalization phase
1 parent 9658056 commit 5a30553

File tree

7 files changed

+189
-182
lines changed

7 files changed

+189
-182
lines changed

src/coreclr/jit/compiler.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1919,6 +1919,7 @@ void Compiler::compInit(ArenaAllocator* pAlloc,
19191919
compLocallocUsed = false;
19201920
compLocallocOptimized = false;
19211921
compQmarkRationalized = false;
1922+
compAssignmentRationalized = false;
19221923
compQmarkUsed = false;
19231924
compFloatingPointUsed = false;
19241925

@@ -5064,6 +5065,8 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
50645065
//
50655066
DoPhase(this, PHASE_DETERMINE_FIRST_COLD_BLOCK, &Compiler::fgDetermineFirstColdBlock);
50665067

5068+
DoPhase(this, PHASE_RATIONALIZE_ASSIGNMENTS, &Compiler::fgRationalizeAssignments);
5069+
50675070
#ifdef DEBUG
50685071
// Stash the current estimate of the function's size if necessary.
50695072
if (verbose)

src/coreclr/jit/compiler.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4830,6 +4830,9 @@ class Compiler
48304830
void fgExpandQmarkStmt(BasicBlock* block, Statement* stmt);
48314831
void fgExpandQmarkNodes();
48324832

4833+
PhaseStatus fgRationalizeAssignments();
4834+
GenTree* fgRationalizeAssignment(GenTreeOp* assignment);
4835+
48334836
// Do "simple lowering." This functionality is (conceptually) part of "general"
48344837
// lowering that is distributed between fgMorph and the lowering phase of LSRA.
48354838
PhaseStatus fgSimpleLowering();
@@ -9232,6 +9235,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
92329235
bool compLocallocOptimized; // Does the method have an optimized localloc
92339236
bool compQmarkUsed; // Does the method use GT_QMARK/GT_COLON
92349237
bool compQmarkRationalized; // Is it allowed to use a GT_QMARK/GT_COLON node.
9238+
bool compAssignmentRationalized; // Have the ASG nodes been turned into their store equivalents?
92359239
bool compHasBackwardJump; // Does the method (or some inlinee) have a lexically backwards jump?
92369240
bool compHasBackwardJumpInHandler; // Does the method have a lexically backwards jump in a handler?
92379241
bool compSwitchedToOptimized; // Codegen initially was Tier0 but jit switched to FullOpts

src/coreclr/jit/compphases.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ CompPhaseNameMacro(PHASE_IF_CONVERSION, "If conversion",
9191
CompPhaseNameMacro(PHASE_VN_BASED_DEAD_STORE_REMOVAL,"VN-based dead store removal", false, -1, false)
9292
CompPhaseNameMacro(PHASE_OPT_UPDATE_FLOW_GRAPH, "Update flow graph opt pass", false, -1, false)
9393
CompPhaseNameMacro(PHASE_COMPUTE_EDGE_WEIGHTS2, "Compute edge weights (2, false)",false, -1, false)
94+
CompPhaseNameMacro(PHASE_RATIONALIZE_ASSIGNMENTS, "Rationalize assignments", false, -1, false)
9495
CompPhaseNameMacro(PHASE_STRESS_SPLIT_TREE, "Stress gtSplitTree", false, -1, false)
9596
CompPhaseNameMacro(PHASE_EXPAND_RTLOOKUPS, "Expand runtime lookups", false, -1, true)
9697
CompPhaseNameMacro(PHASE_EXPAND_STATIC_INIT, "Expand static init", false, -1, true)

src/coreclr/jit/flowgraph.cpp

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2841,6 +2841,175 @@ PhaseStatus Compiler::fgFindOperOrder()
28412841
return PhaseStatus::MODIFIED_EVERYTHING;
28422842
}
28432843

2844+
//------------------------------------------------------------------------
2845+
// fgRationalizeAssignments: Rewrite assignment nodes into stores.
2846+
//
2847+
// TODO-ASG: delete.
2848+
//
2849+
PhaseStatus Compiler::fgRationalizeAssignments()
2850+
{
2851+
class AssignmentRationalizationVisitor : public GenTreeVisitor<AssignmentRationalizationVisitor>
2852+
{
2853+
public:
2854+
enum
2855+
{
2856+
DoPreOrder = true
2857+
};
2858+
2859+
AssignmentRationalizationVisitor(Compiler* compiler) : GenTreeVisitor(compiler)
2860+
{
2861+
}
2862+
2863+
fgWalkResult PreOrderVisit(GenTree** use, GenTree* user)
2864+
{
2865+
GenTree* node = *use;
2866+
2867+
// GTF_ASG is sometimes not propagated from setup arg assignments so we have to check for GTF_CALL too.
2868+
if ((node->gtFlags & (GTF_ASG | GTF_CALL)) == 0)
2869+
{
2870+
return fgWalkResult::WALK_SKIP_SUBTREES;
2871+
}
2872+
2873+
if (node->OperIs(GT_ASG))
2874+
{
2875+
GenTreeFlags lhsRhsFlags = node->gtGetOp1()->gtFlags | node->gtGetOp2()->gtFlags;
2876+
*use = m_compiler->fgRationalizeAssignment(node->AsOp());
2877+
2878+
// TP: return early quickly for simple assignments.
2879+
if ((lhsRhsFlags & (GTF_ASG | GTF_CALL)) == 0)
2880+
{
2881+
return fgWalkResult::WALK_SKIP_SUBTREES;
2882+
}
2883+
}
2884+
2885+
return fgWalkResult::WALK_CONTINUE;
2886+
}
2887+
};
2888+
2889+
AssignmentRationalizationVisitor visitor(this);
2890+
for (BasicBlock* block : Blocks())
2891+
{
2892+
for (Statement* stmt : block->Statements())
2893+
{
2894+
GenTree** use = stmt->GetRootNodePointer();
2895+
if (visitor.PreOrderVisit(use, nullptr) == fgWalkResult::WALK_CONTINUE)
2896+
{
2897+
visitor.WalkTree(use, nullptr);
2898+
}
2899+
}
2900+
}
2901+
2902+
compAssignmentRationalized = true;
2903+
2904+
return PhaseStatus::MODIFIED_EVERYTHING;
2905+
}
2906+
2907+
//------------------------------------------------------------------------
2908+
// fgRationalizeAssignment: Rewrite GT_ASG into a store node.
2909+
//
2910+
// Arguments:
2911+
// assignment - The assignment node to rewrite
2912+
//
2913+
// Return Value:
2914+
// Assignment's location, turned into the appropriate store node.
2915+
//
2916+
GenTree* Compiler::fgRationalizeAssignment(GenTreeOp* assignment)
2917+
{
2918+
assert(assignment->OperGet() == GT_ASG);
2919+
2920+
bool isReverseOp = assignment->IsReverseOp();
2921+
GenTree* location = assignment->gtGetOp1();
2922+
GenTree* value = assignment->gtGetOp2();
2923+
if (location->OperIsLocal())
2924+
{
2925+
assert((location->gtFlags & GTF_VAR_DEF) != 0);
2926+
}
2927+
else if (value->OperIs(GT_LCL_VAR))
2928+
{
2929+
assert((value->gtFlags & GTF_VAR_DEF) == 0);
2930+
}
2931+
2932+
if (assignment->OperIsInitBlkOp())
2933+
{
2934+
// No SIMD types are allowed for InitBlks (including zero-inits).
2935+
assert(assignment->TypeIs(TYP_STRUCT) && location->TypeIs(TYP_STRUCT));
2936+
}
2937+
2938+
genTreeOps storeOp;
2939+
switch (location->OperGet())
2940+
{
2941+
case GT_LCL_VAR:
2942+
storeOp = GT_STORE_LCL_VAR;
2943+
break;
2944+
case GT_LCL_FLD:
2945+
storeOp = GT_STORE_LCL_FLD;
2946+
break;
2947+
case GT_BLK:
2948+
storeOp = GT_STORE_BLK;
2949+
break;
2950+
case GT_IND:
2951+
storeOp = GT_STOREIND;
2952+
break;
2953+
default:
2954+
unreached();
2955+
}
2956+
2957+
JITDUMP("Rewriting GT_ASG(%s, X) to %s(X)\n", GenTree::OpName(location->OperGet()), GenTree::OpName(storeOp));
2958+
2959+
GenTree* store = location;
2960+
store->SetOperRaw(storeOp);
2961+
store->Data() = value;
2962+
store->gtFlags |= GTF_ASG;
2963+
store->AddAllEffectsFlags(value);
2964+
store->AddAllEffectsFlags(assignment->gtFlags & GTF_GLOB_REF); // TODO-ASG: zero-diff quirk, delete.
2965+
if (isReverseOp && !store->OperIsLocalStore())
2966+
{
2967+
store->SetReverseOp();
2968+
}
2969+
2970+
if (storeOp == GT_STOREIND)
2971+
{
2972+
store->AsStoreInd()->SetRMWStatusDefault();
2973+
}
2974+
2975+
// [..., LHS, ..., RHS, ASG] -> [..., ..., RHS, LHS<STORE>] (normal)
2976+
// [..., RHS, ..., LHS, ASG] -> [..., RHS, ..., LHS<STORE>] (reversed)
2977+
if (assignment->gtPrev != nullptr)
2978+
{
2979+
assert(fgNodeThreading == NodeThreading::AllTrees);
2980+
if (isReverseOp)
2981+
{
2982+
GenTree* nextNode = assignment->gtNext;
2983+
store->gtNext = nextNode;
2984+
if (nextNode != nullptr)
2985+
{
2986+
nextNode->gtPrev = store;
2987+
}
2988+
}
2989+
else
2990+
{
2991+
if (store->gtPrev != nullptr)
2992+
{
2993+
store->gtPrev->gtNext = store->gtNext;
2994+
}
2995+
store->gtNext->gtPrev = store->gtPrev;
2996+
2997+
store->gtPrev = assignment->gtPrev;
2998+
store->gtNext = assignment->gtNext;
2999+
store->gtPrev->gtNext = store;
3000+
if (store->gtNext != nullptr)
3001+
{
3002+
store->gtNext->gtPrev = store;
3003+
}
3004+
}
3005+
}
3006+
3007+
DISPNODE(store);
3008+
JITDUMP("\n");
3009+
3010+
return store;
3011+
}
3012+
28443013
//------------------------------------------------------------------------
28453014
// fgSimpleLowering: do full walk of all IR, lowering selected operations
28463015
// and computing lvaOutgoingArgSpaceSize.

src/coreclr/jit/gentree.cpp

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15972,23 +15972,18 @@ GenTree* Compiler::gtNewTempAssign(
1597215972
GenTree* asg;
1597315973
GenTree* dest = gtNewLclvNode(tmp, dstTyp);
1597415974

15975-
if (val->IsInitVal())
15976-
{
15977-
asg = gtNewAssignNode(dest, val);
15978-
}
15979-
else if (varTypeIsStruct(varDsc))
15975+
if (varTypeIsStruct(varDsc) && !val->IsInitVal())
1598015976
{
1598115977
asg = impAssignStruct(dest, val, CHECK_SPILL_NONE, pAfterStmt, di, block);
1598215978
}
1598315979
else
1598415980
{
15985-
assert(!varTypeIsStruct(valTyp));
1598615981
asg = gtNewAssignNode(dest, val);
1598715982
}
1598815983

15989-
if (compRationalIRForm)
15984+
if (compAssignmentRationalized)
1599015985
{
15991-
Rationalizer::RewriteAssignmentIntoStoreLcl(asg->AsOp());
15986+
asg = fgRationalizeAssignment(asg->AsOp());
1599215987
}
1599315988

1599415989
return asg;
@@ -17242,9 +17237,15 @@ bool GenTree::IsPhiNode()
1724217237

1724317238
bool GenTree::IsPhiDefn()
1724417239
{
17245-
bool res = OperIs(GT_ASG) && AsOp()->gtOp2->OperIs(GT_PHI);
17246-
assert(!res || AsOp()->gtOp1->OperIs(GT_LCL_VAR));
17247-
return res;
17240+
if (OperIs(GT_ASG))
17241+
{
17242+
return AsOp()->gtOp2->OperIs(GT_PHI);
17243+
}
17244+
if (OperIs(GT_STORE_LCL_VAR))
17245+
{
17246+
return AsLclVar()->Data()->OperIs(GT_PHI);
17247+
}
17248+
return false;
1724817249
}
1724917250

1725017251
bool GenTree::IsLclVarAddr() const

0 commit comments

Comments
 (0)