1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
10 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
19 //===============================================================================
21 //------------------------------------------------------------------------
22 // DoPhase: Run analysis (if object stack allocation is enabled) and then
23 // morph each GT_ALLOCOBJ node either into an allocation helper
24 // call or stack allocation.
26 // Runs only if Compiler::optMethodFlags has flag OMF_HAS_NEWOBJ set.
27 void ObjectAllocator::DoPhase()
29 if ((comp->optMethodFlags & OMF_HAS_NEWOBJ) == 0)
34 if (IsObjectStackAllocationEnabled())
42 //------------------------------------------------------------------------
43 // DoAnalysis: Walk over basic blocks of the method and detect all local
44 // variables that can be allocated on the stack.
47 // Must be run after the dominators have been computed (we need this
48 // information to detect loops).
49 void ObjectAllocator::DoAnalysis()
51 assert(m_IsObjectStackAllocationEnabled);
52 assert(comp->fgDomsComputed);
53 // TODO-ObjectStackAllocation
57 //------------------------------------------------------------------------
58 // MorphAllocObjNodes: Morph each GT_ALLOCOBJ node either into an
59 // allocation helper call or stack allocation.
62 // Runs only over the blocks having bbFlags BBF_HAS_NEWOBJ set.
63 void ObjectAllocator::MorphAllocObjNodes()
67 foreach_block(comp, block)
69 const bool basicBlockHasNewObj = (block->bbFlags & BBF_HAS_NEWOBJ) == BBF_HAS_NEWOBJ;
71 if (!basicBlockHasNewObj)
77 for (GenTreeStmt* stmt = block->firstStmt(); stmt; stmt = stmt->gtNextStmt)
79 GenTree* stmtExpr = stmt->gtStmtExpr;
80 GenTree* op2 = nullptr;
82 bool canonicalAllocObjFound = false;
84 if (stmtExpr->OperGet() == GT_ASG && stmtExpr->TypeGet() == TYP_REF)
86 op2 = stmtExpr->gtGetOp2();
88 if (op2->OperGet() == GT_ALLOCOBJ)
90 canonicalAllocObjFound = true;
94 if (canonicalAllocObjFound)
96 assert(basicBlockHasNewObj);
97 //------------------------------------------------------------------------
98 // We expect the following expression tree at this point
99 // * GT_STMT void (top level)
100 // | /--* GT_ALLOCOBJ ref
102 // \--* GT_LCL_VAR ref
103 //------------------------------------------------------------------------
105 GenTree* op1 = stmtExpr->gtGetOp1();
107 assert(op1->OperGet() == GT_LCL_VAR);
108 assert(op1->TypeGet() == TYP_REF);
109 assert(op2 != nullptr);
110 assert(op2->OperGet() == GT_ALLOCOBJ);
112 GenTreeAllocObj* asAllocObj = op2->AsAllocObj();
113 unsigned int lclNum = op1->AsLclVar()->GetLclNum();
115 if (IsObjectStackAllocationEnabled() && CanAllocateLclVarOnStack(lclNum))
117 op2 = MorphAllocObjNodeIntoStackAlloc(asAllocObj, block, stmt);
121 op2 = MorphAllocObjNodeIntoHelperCall(asAllocObj);
124 // Propagate flags of op2 to its parent.
125 stmtExpr->gtOp.gtOp2 = op2;
126 stmtExpr->gtFlags |= op2->gtFlags & GTF_ALL_EFFECT;
131 // We assume that GT_ALLOCOBJ nodes are always present in the
133 comp->fgWalkTreePre(&stmt->gtStmtExpr, AssertWhenAllocObjFoundVisitor);
140 //------------------------------------------------------------------------
141 // MorphAllocObjNodeIntoHelperCall: Morph a GT_ALLOCOBJ node into an
142 // allocation helper call.
145 // allocObj - GT_ALLOCOBJ that will be replaced by helper call.
148 // Address of helper call node (can be the same as allocObj).
151 // Must update parents flags after this.
152 GenTree* ObjectAllocator::MorphAllocObjNodeIntoHelperCall(GenTreeAllocObj* allocObj)
154 assert(allocObj != nullptr);
156 GenTree* op1 = allocObj->gtGetOp1();
158 GenTree* helperCall = comp->fgMorphIntoHelperCall(allocObj, allocObj->gtNewHelper, comp->gtNewArgList(op1));
163 //------------------------------------------------------------------------
164 // MorphAllocObjNodeIntoStackAlloc: Morph a GT_ALLOCOBJ node into stack
167 // allocObj - GT_ALLOCOBJ that will be replaced by helper call.
168 // block - a basic block where allocObj is
169 // stmt - a statement where allocObj is
172 // Address of tree doing stack allocation (can be the same as allocObj).
175 // Must update parents flags after this.
176 // This function can insert additional statements before stmt.
177 GenTree* ObjectAllocator::MorphAllocObjNodeIntoStackAlloc(GenTreeAllocObj* allocObj,
181 assert(allocObj != nullptr);
182 assert(m_AnalysisDone);
184 // TODO-StackAllocation
185 NYI("MorphAllocObjIntoStackAlloc");
192 //------------------------------------------------------------------------
193 // AssertWhenAllocObjFoundVisitor: Look for a GT_ALLOCOBJ node and assert
195 Compiler::fgWalkResult ObjectAllocator::AssertWhenAllocObjFoundVisitor(GenTree** pTree, Compiler::fgWalkData* data)
197 GenTree* tree = *pTree;
199 assert(tree != nullptr);
200 assert(tree->OperGet() != GT_ALLOCOBJ);
202 return Compiler::fgWalkResult::WALK_CONTINUE;
207 //===============================================================================