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
16 //--------------------------------------------------------------------------------------------------
17 // ToGenTree - Convert an arrLen operation into a gentree node.
20 // comp Compiler instance to allocate trees
23 // Returns the gen tree representation for arrLen or MD Array node as defined by
27 // This tree produces GT_INDEX node, the caller is supposed to morph it appropriately
28 // so it can be codegen'ed.
30 GenTree* LC_Array::ToGenTree(Compiler* comp)
35 // Create a a[i][j][k].length type node.
36 GenTree* arr = comp->gtNewLclvNode(arrIndex->arrLcl, comp->lvaTable[arrIndex->arrLcl].lvType);
37 int rank = GetDimRank();
38 for (int i = 0; i < rank; ++i)
40 arr = comp->gtNewIndexRef(TYP_REF, arr, comp->gtNewLclvNode(arrIndex->indLcls[i],
41 comp->lvaTable[arrIndex->indLcls[i]].lvType));
43 // If asked for arrlen invoke arr length operator.
46 GenTree* arrLen = comp->gtNewArrLen(TYP_INT, arr, offsetof(CORINFO_Array, length));
57 // TODO-CQ: Optimize for MD Array.
58 assert(!"Optimize for MD Array");
63 //--------------------------------------------------------------------------------------------------
64 // ToGenTree - Convert an "identifier" into a gentree node.
67 // comp Compiler instance to allocate trees
70 // Returns the gen tree representation for either a constant or a variable or an arrLen operation
71 // defined by the "type" member
73 GenTree* LC_Ident::ToGenTree(Compiler* comp)
75 // Convert to GenTree nodes.
79 assert(constant <= INT32_MAX);
80 return comp->gtNewIconNode(constant);
82 return comp->gtNewLclvNode(constant, comp->lvaTable[constant].lvType);
84 return arrLen.ToGenTree(comp);
86 return comp->gtNewIconNode(0, TYP_REF);
88 assert(!"Could not convert LC_Ident to GenTree");
94 //--------------------------------------------------------------------------------------------------
95 // ToGenTree - Convert an "expression" into a gentree node.
98 // comp Compiler instance to allocate trees
101 // Returns the gen tree representation for either a constant or a variable or an arrLen operation
102 // defined by the "type" member
104 GenTree* LC_Expr::ToGenTree(Compiler* comp)
106 // Convert to GenTree nodes.
110 return ident.ToGenTree(comp);
112 assert(!"Could not convert LC_Expr to GenTree");
118 //--------------------------------------------------------------------------------------------------
119 // ToGenTree - Convert a "condition" into a gentree node.
122 // comp Compiler instance to allocate trees
125 // Returns the gen tree representation for the conditional operator on lhs and rhs trees
127 GenTree* LC_Condition::ToGenTree(Compiler* comp)
129 GenTree* op1Tree = op1.ToGenTree(comp);
130 GenTree* op2Tree = op2.ToGenTree(comp);
131 assert(genTypeSize(genActualType(op1Tree->TypeGet())) == genTypeSize(genActualType(op2Tree->TypeGet())));
132 return comp->gtNewOperNode(oper, TYP_INT, op1Tree, op2Tree);
135 //--------------------------------------------------------------------------------------------------
136 // Evaluates - Evaluate a given loop cloning condition if it can be statically evaluated.
139 // pResult The evaluation result
142 // Returns true if the condition can be statically evaluated. If the condition's result
143 // is statically unknown then return false. In other words, true if "pResult" is valid.
145 bool LC_Condition::Evaluates(bool* pResult)
152 // If op1 == op2 then equality should result in true.
163 // If op1 == op2 then inequality should result in false.
172 // for all other 'oper' kinds, we will return false
178 //--------------------------------------------------------------------------------------------------
179 // Combines - Check whether two conditions would combine to yield a single new condition.
182 // cond The condition that is checked if it would combine with "*this" condition.
183 // newCond The resulting combined condition.
186 // Returns true if "cond" combines with the "this" condition.
187 // "newCond" contains the combines condition.
190 // Check if both conditions are equal. If so, return just 1 of them.
191 // Reverse their operators and check if their reversed operands match. If so, return either of them.
194 // This is not a full-fledged expression optimizer, it is supposed
195 // to remove redundant conditions that are generated for optimization
196 // opportunities. Anything further should be implemented as needed.
197 // For example, for (i = beg; i < end; i += inc) a[i]. Then, the conditions
198 // would be: "beg >= 0, end <= a.len, inc > 0"
199 bool LC_Condition::Combines(const LC_Condition& cond, LC_Condition* newCond)
201 if (oper == cond.oper && op1 == cond.op1 && op2 == cond.op2)
206 else if ((oper == GT_LT || oper == GT_LE || oper == GT_GT || oper == GT_GE) &&
207 GenTree::ReverseRelop(oper) == cond.oper && op1 == cond.op2 && op2 == cond.op1)
215 //--------------------------------------------------------------------------------------------------
216 // GetLoopOptInfo - Retrieve the loop opt info candidate array.
219 // loopNum the loop index.
222 // Return the optInfo array member. The method doesn't allocate memory.
224 JitExpandArrayStack<LcOptInfo*>* LoopCloneContext::GetLoopOptInfo(unsigned loopNum)
226 return optInfo[loopNum];
229 //--------------------------------------------------------------------------------------------------
230 // CancelLoopOptInfo - Cancel loop cloning optimization for this loop.
233 // loopNum the loop index.
238 void LoopCloneContext::CancelLoopOptInfo(unsigned loopNum)
240 JITDUMP("Cancelling loop cloning for loop L_%02u\n", loopNum);
241 optInfo[loopNum] = nullptr;
242 if (conditions[loopNum] != nullptr)
244 conditions[loopNum]->Reset();
245 conditions[loopNum] = nullptr;
249 //--------------------------------------------------------------------------------------------------
250 // EnsureLoopOptInfo - Retrieve the loop opt info candidate array, if it is not present, allocate
254 // loopNum the loop index.
257 // The array of optimization candidates for the loop.
259 JitExpandArrayStack<LcOptInfo*>* LoopCloneContext::EnsureLoopOptInfo(unsigned loopNum)
261 if (optInfo[loopNum] == nullptr)
263 optInfo[loopNum] = new (alloc) JitExpandArrayStack<LcOptInfo*>(alloc, 4);
265 return optInfo[loopNum];
268 //--------------------------------------------------------------------------------------------------
269 // EnsureLoopOptInfo - Retrieve the loop cloning conditions candidate array,
270 // if it is not present, allocate memory.
273 // loopNum the loop index.
276 // The array of cloning conditions for the loop.
278 JitExpandArrayStack<LC_Condition>* LoopCloneContext::EnsureConditions(unsigned loopNum)
280 if (conditions[loopNum] == nullptr)
282 conditions[loopNum] = new (alloc) JitExpandArrayStack<LC_Condition>(alloc, 4);
284 return conditions[loopNum];
287 //--------------------------------------------------------------------------------------------------
288 // GetConditions - Get the cloning conditions array for the loop, no allocation.
291 // loopNum the loop index.
294 // The array of cloning conditions for the loop.
296 JitExpandArrayStack<LC_Condition>* LoopCloneContext::GetConditions(unsigned loopNum)
298 return conditions[loopNum];
301 //--------------------------------------------------------------------------------------------------
302 // EnsureDerefs - Ensure an array of dereferences is created if it doesn't exist.
305 // loopNum the loop index.
308 // The array of dereferences for the loop.
310 JitExpandArrayStack<LC_Array>* LoopCloneContext::EnsureDerefs(unsigned loopNum)
312 if (derefs[loopNum] == nullptr)
314 derefs[loopNum] = new (alloc) JitExpandArrayStack<LC_Array>(alloc, 4);
316 return derefs[loopNum];
319 //--------------------------------------------------------------------------------------------------
320 // HasBlockConditions - Check if there are block level conditions for the loop.
323 // loopNum the loop index.
326 // Return true if there are any block level conditions.
328 bool LoopCloneContext::HasBlockConditions(unsigned loopNum)
330 JitExpandArrayStack<JitExpandArrayStack<LC_Condition>*>* levelCond = blockConditions[loopNum];
331 if (levelCond == nullptr)
336 // Walk through each block to check if any of them has conditions.
337 for (unsigned i = 0; i < levelCond->Size(); ++i)
339 if ((*levelCond)[i]->Size() > 0)
347 //--------------------------------------------------------------------------------------------------
348 // GetBlockConditions - Return block level conditions for the loop.
351 // loopNum the loop index.
354 // Return block conditions.
356 JitExpandArrayStack<JitExpandArrayStack<LC_Condition>*>* LoopCloneContext::GetBlockConditions(unsigned loopNum)
358 assert(HasBlockConditions(loopNum));
359 return blockConditions[loopNum];
362 //--------------------------------------------------------------------------------------------------
363 // EnsureBlockConditions - Allocate block level conditions for the loop if not exists.
366 // loopNum the loop index.
367 // condBlocks the number of block-level conditions for each loop, corresponding to the blocks
371 // Return block conditions.
373 JitExpandArrayStack<JitExpandArrayStack<LC_Condition>*>* LoopCloneContext::EnsureBlockConditions(unsigned loopNum,
376 if (blockConditions[loopNum] == nullptr)
378 blockConditions[loopNum] =
379 new (alloc) JitExpandArrayStack<JitExpandArrayStack<LC_Condition>*>(alloc, condBlocks);
381 JitExpandArrayStack<JitExpandArrayStack<LC_Condition>*>* levelCond = blockConditions[loopNum];
382 for (unsigned i = 0; i < condBlocks; ++i)
384 levelCond->Set(i, new (alloc) JitExpandArrayStack<LC_Condition>(alloc));
390 void LoopCloneContext::PrintBlockConditions(unsigned loopNum)
392 JitExpandArrayStack<JitExpandArrayStack<LC_Condition>*>* levelCond = blockConditions[loopNum];
393 if (levelCond == nullptr || levelCond->Size() == 0)
395 JITDUMP("No block conditions\n");
399 for (unsigned i = 0; i < levelCond->Size(); ++i)
401 JITDUMP("%d = {", i);
402 for (unsigned j = 0; j < ((*levelCond)[i])->Size(); ++j)
408 (*((*levelCond)[i]))[j].Print();
415 //--------------------------------------------------------------------------------------------------
416 // EvaluateConditions - Evaluate the loop cloning conditions statically, if it can be evaluated.
419 // loopNum the loop index.
420 // pAllTrue all the cloning conditions evaluated to "true" statically.
421 // pAnyFalse some cloning condition evaluated to "false" statically.
422 // verbose verbose logging required.
428 // For example, a condition like "V02 >= V02" statically evaluates to true. Caller should detect such
429 // conditions and remove them from the "conditions" array.
431 // Similarly, conditions like "V02 > V02" will evaluate to "false". In this case caller has to abort
432 // loop cloning optimization for the loop. Note that the assumption for conditions is that they will
433 // all be "AND"ed, so statically we know we will never take the fast path.
435 // Sometimes we simply can't say statically whether "V02 > V01.length" is true or false.
436 // In that case, the "pAllTrue" will be false because this condition doesn't evaluate to "true" and
437 // "pAnyFalse" could be false if no other condition statically evaluates to "false".
438 void LoopCloneContext::EvaluateConditions(unsigned loopNum, bool* pAllTrue, bool* pAnyFalse DEBUGARG(bool verbose))
441 bool anyFalse = false;
443 JitExpandArrayStack<LC_Condition>& conds = *conditions[loopNum];
445 JITDUMP("Evaluating %d loop cloning conditions for loop %d\n", conds.Size(), loopNum);
447 assert(conds.Size() > 0);
448 for (unsigned i = 0; i < conds.Size(); ++i)
453 printf("Considering condition %d: (", i);
459 // Check if this condition evaluates to true or false.
460 if (conds[i].Evaluates(&res))
462 JITDUMP(") evaluates to %d\n", res);
471 JITDUMP("), could not be evaluated\n");
476 JITDUMP("Evaluation result allTrue = %d, anyFalse = %d\n", allTrue, anyFalse);
478 *pAnyFalse = anyFalse;
481 //--------------------------------------------------------------------------------------------------
482 // OptimizeConditions - Evaluate the loop cloning conditions statically, if they can be evaluated
483 // then optimize the "conditions" array accordingly.
486 // conds The conditions array to optimize.
492 // For example, a condition like "V02 >= V02" statically evaluates to true. Remove such conditions
493 // from the "conditions" array.
495 // Similarly, conditions like "V02 > V02" will evaluate to "false". In this case abort loop cloning
496 // optimization for the loop.
498 // Sometimes, two conditions will combine together to yield a single condition, then remove a
499 // duplicate condition.
500 void LoopCloneContext::OptimizeConditions(JitExpandArrayStack<LC_Condition>& conds)
502 for (unsigned i = 0; i < conds.Size(); ++i)
504 // Check if the conditions evaluate.
506 if (conds[i].Evaluates(&result))
508 // If statically known to be true, then remove this condition.
517 // Some condition is statically false, then simply indicate
518 // not to clone this loop.
519 CancelLoopOptInfo(i);
524 // Check for all other conditions[j], if it would combine with
526 for (unsigned j = i + 1; j < conds.Size(); ++j)
528 LC_Condition newCond;
529 if (conds[i].Combines(conds[j], &newCond))
539 // Make sure we didn't miss some combining.
540 for (unsigned i = 0; i < conds.Size(); ++i)
542 for (unsigned j = 0; j < conds.Size(); ++j)
544 LC_Condition newCond;
545 if ((i != j) && conds[i].Combines(conds[j], &newCond))
547 assert(!"Loop cloning conditions can still be optimized further.");
554 //--------------------------------------------------------------------------------------------------
555 // OptimizeBlockConditions - Optimize block level conditions.
558 // loopNum the loop index.
561 // Calls OptimizeConditions helper on block level conditions.
566 void LoopCloneContext::OptimizeBlockConditions(unsigned loopNum DEBUGARG(bool verbose))
568 if (!HasBlockConditions(loopNum))
572 JitExpandArrayStack<JitExpandArrayStack<LC_Condition>*>* levelCond = blockConditions[loopNum];
573 for (unsigned i = 0; i < levelCond->Size(); ++i)
575 OptimizeConditions(*((*levelCond)[i]));
580 printf("After optimizing block-level cloning conditions\n\t");
581 PrintConditions(loopNum);
587 //--------------------------------------------------------------------------------------------------
588 // OptimizeConditions - Optimize cloning conditions.
591 // loopNum the loop index.
592 // verbose verbose logging required.
595 // Calls OptimizeConditions helper on cloning conditions.
600 void LoopCloneContext::OptimizeConditions(unsigned loopNum DEBUGARG(bool verbose))
605 printf("Before optimizing cloning conditions\n\t");
606 PrintConditions(loopNum);
610 JitExpandArrayStack<LC_Condition>& conds = *conditions[loopNum];
611 OptimizeConditions(conds);
616 printf("After optimizing cloning conditions\n\t");
617 PrintConditions(loopNum);
624 //--------------------------------------------------------------------------------------------------
625 // PrintConditions - Print loop cloning conditions necessary to clone the loop.
628 // loopNum the loop index.
633 void LoopCloneContext::PrintConditions(unsigned loopNum)
635 if (conditions[loopNum] == nullptr)
637 JITDUMP("NO conditions");
640 if (conditions[loopNum]->Size() == 0)
642 JITDUMP("Conditions were optimized away! Will always take cloned path.");
644 for (unsigned i = 0; i < conditions[loopNum]->Size(); ++i)
650 (*conditions[loopNum])[i].Print();
655 //--------------------------------------------------------------------------------------------------
656 // CondToStmtInBlock - Convert an array of conditions. Evaluate them into a JTRUE stmt and add it to
660 // comp Compiler instance
661 // conds Array of conditions to evaluate into a JTRUE stmt
662 // block Block to insert the stmt into
663 // reverse Reverse conditions if true.
666 // The condition that will be generated: jmpTrue(cond1 & cond2 ... == 0)
671 void LoopCloneContext::CondToStmtInBlock(Compiler* comp,
672 JitExpandArrayStack<LC_Condition>& conds,
676 noway_assert(conds.Size() > 0);
678 // Get the first condition.
679 GenTree* cond = conds[0].ToGenTree(comp);
680 for (unsigned i = 1; i < conds.Size(); ++i)
682 // Append all conditions using AND operator.
683 cond = comp->gtNewOperNode(GT_AND, TYP_INT, cond, conds[i].ToGenTree(comp));
686 // Add "cond == 0" node
687 cond = comp->gtNewOperNode(reverse ? GT_NE : GT_EQ, TYP_INT, cond, comp->gtNewIconNode(0));
689 // Add jmpTrue "cond == 0" to slow path.
690 GenTree* stmt = comp->fgNewStmtFromTree(comp->gtNewOperNode(GT_JTRUE, TYP_VOID, cond));
692 // Add stmt to the block.
693 comp->fgInsertStmtAtEnd(block, stmt);
696 comp->fgMorphBlockStmt(block, stmt->AsStmt() DEBUGARG("Loop cloning condition"));
699 //--------------------------------------------------------------------------------------------------
700 // Lcl - the current node's local variable.
706 // If level is 0, then just return the array base. Else return the index variable on dim 'level'
709 // The local variable in the node's level.
711 unsigned LC_Deref::Lcl()
713 unsigned lvl = level;
716 return array.arrIndex->arrLcl;
719 return array.arrIndex->indLcls[lvl];
722 //--------------------------------------------------------------------------------------------------
723 // HasChildren - Check if there are children to 'this' node.
729 // Return true if children are present.
731 bool LC_Deref::HasChildren()
733 return children != nullptr && children->Size() > 0;
736 //--------------------------------------------------------------------------------------------------
737 // DeriveLevelConditions - Generate conditions for each level of the tree.
740 // conds An array of conditions for each level i.e., (level x conditions). This array will
741 // contain the conditions for the tree at the end of the method.
744 // level0 yields only (a != null) condition. All other levels yield two conditions:
745 // (level < a[...].length && a[...][level] != null)
750 void LC_Deref::DeriveLevelConditions(JitExpandArrayStack<JitExpandArrayStack<LC_Condition>*>* conds)
754 // For level 0, just push (a != null).
755 (*conds)[level]->Push(
756 LC_Condition(GT_NE, LC_Expr(LC_Ident(Lcl(), LC_Ident::Var)), LC_Expr(LC_Ident(LC_Ident::Null))));
760 // Adjust for level0 having just 1 condition and push condition (i < a.len).
761 LC_Array arrLen = array;
762 arrLen.oper = LC_Array::ArrLen;
763 arrLen.dim = level - 1;
764 (*conds)[level * 2 - 1]->Push(
765 LC_Condition(GT_LT, LC_Expr(LC_Ident(Lcl(), LC_Ident::Var)), LC_Expr(LC_Ident(arrLen))));
767 // Push condition (a[i] != null)
768 LC_Array arrTmp = array;
770 (*conds)[level * 2]->Push(LC_Condition(GT_NE, LC_Expr(LC_Ident(arrTmp)), LC_Expr(LC_Ident(LC_Ident::Null))));
773 // Invoke on the children recursively.
776 for (unsigned i = 0; i < children->Size(); ++i)
778 (*children)[i]->DeriveLevelConditions(conds);
783 //--------------------------------------------------------------------------------------------------
784 // EnsureChildren - Create an array of child nodes if nullptr.
787 // alloc CompAllocator instance
792 void LC_Deref::EnsureChildren(CompAllocator* alloc)
794 if (children == nullptr)
796 children = new (alloc) JitExpandArrayStack<LC_Deref*>(alloc);
800 //--------------------------------------------------------------------------------------------------
801 // Find - Find the node representing the local variable in child nodes of the 'this' node.
804 // lcl the local to find in the children array
807 // The child node if found or nullptr.
809 LC_Deref* LC_Deref::Find(unsigned lcl)
811 return Find(children, lcl);
814 //--------------------------------------------------------------------------------------------------
815 // Find - Find the node representing the local variable in a list of nodes.
818 // lcl the local to find.
819 // children the list of nodes to find the node representing the lcl.
822 // The node if found or nullptr.
826 LC_Deref* LC_Deref::Find(JitExpandArrayStack<LC_Deref*>* children, unsigned lcl)
828 if (children == nullptr)
832 for (unsigned i = 0; i < children->Size(); ++i)
834 if ((*children)[i]->Lcl() == lcl)
836 return (*children)[i];