@@ -2678,6 +2678,9 @@ void Compiler::optFindNaturalLoops()
2678
2678
2679
2679
// Make sure that loops are canonical: that every loop has a unique "top", by creating an empty "nop"
2680
2680
// one, if necessary, for loops containing others that share a "top."
2681
+ //
2682
+ // Also make sure that no loop's "bottom" is another loop's "head".
2683
+ //
2681
2684
for (unsigned char loopInd = 0 ; loopInd < optLoopCount; loopInd++)
2682
2685
{
2683
2686
// Traverse the outermost loops as entries into the loop nest; so skip non-outermost.
@@ -2923,7 +2926,7 @@ bool Compiler::optCanonicalizeLoopNest(unsigned char loopInd)
2923
2926
2924
2927
// -----------------------------------------------------------------------------
2925
2928
// optCanonicalizeLoop: ensure that each loop top's back edges come only from
2926
- // blocks in the same loop.
2929
+ // blocks in the same loop, and that no loop head/bottom blocks coincide .
2927
2930
//
2928
2931
// Arguments:
2929
2932
// loopInd - index of the loop to consider
@@ -3006,6 +3009,84 @@ bool Compiler::optCanonicalizeLoop(unsigned char loopInd)
3006
3009
modified |= didCanon;
3007
3010
}
3008
3011
3012
+ // Check if this loopInd head is also the bottom of some sibling.
3013
+ // If so, add a block in between to serve as the new head.
3014
+ //
3015
+ auto repairLoop = [this ](unsigned char loopInd, unsigned char sibling) {
3016
+
3017
+ BasicBlock* const h = optLoopTable[loopInd].lpHead ;
3018
+ BasicBlock* const siblingB = optLoopTable[sibling].lpBottom ;
3019
+
3020
+ if (h == siblingB)
3021
+ {
3022
+ // We have
3023
+ //
3024
+ // sibling.B (== loopInd.H) -e-> loopInd.T
3025
+ //
3026
+ // where e is a "critical edge", that is
3027
+ // * sibling.B has other successors (notably sibling.T),
3028
+ // * loopInd.T has other predecessors (notably loopInd.B)
3029
+ //
3030
+ // turn this into
3031
+ //
3032
+ // sibling.B -> newH (== loopInd.H) -> loopInd.T
3033
+ //
3034
+ // Ideally we'd just call fgSplitEdge, but we are
3035
+ // not keeping pred lists in good shape.
3036
+ //
3037
+ BasicBlock* const t = optLoopTable[loopInd].lpTop ;
3038
+ assert (siblingB->bbJumpKind == BBJ_COND);
3039
+ assert (siblingB->bbNext == t);
3040
+
3041
+ JITDUMP (FMT_LP " head " FMT_BB " is also " FMT_LP " bottom\n " , loopInd, h->bbNum , sibling);
3042
+
3043
+ BasicBlock* const newH = fgNewBBbefore (BBJ_NONE, t, /* extendRegion*/ true );
3044
+
3045
+ // Anything that flows into sibling will flow here.
3046
+ // So we use sibling.H as our best guess for weight.
3047
+ //
3048
+ newH->inheritWeight (optLoopTable[sibling].lpHead );
3049
+ newH->bbNatLoopNum = optLoopTable[loopInd].lpParent ;
3050
+ optUpdateLoopHead (loopInd, h, newH);
3051
+
3052
+ return true ;
3053
+ }
3054
+ return false ;
3055
+ };
3056
+
3057
+ if (optLoopTable[loopInd].lpParent == BasicBlock::NOT_IN_LOOP)
3058
+ {
3059
+ // check against all other top-level loops
3060
+ //
3061
+ for (unsigned char sibling = 0 ; sibling < optLoopCount; sibling++)
3062
+ {
3063
+ if (optLoopTable[sibling].lpParent != BasicBlock::NOT_IN_LOOP)
3064
+ {
3065
+ continue ;
3066
+ }
3067
+
3068
+ modified |= repairLoop (loopInd, sibling);
3069
+ }
3070
+ }
3071
+ else
3072
+ {
3073
+ // check against all other sibling loops
3074
+ //
3075
+ const unsigned char parentLoop = optLoopTable[loopInd].lpParent ;
3076
+
3077
+ for (unsigned char sibling = optLoopTable[parentLoop].lpChild ; //
3078
+ sibling != BasicBlock::NOT_IN_LOOP; //
3079
+ sibling = optLoopTable[sibling].lpSibling )
3080
+ {
3081
+ if (sibling == loopInd)
3082
+ {
3083
+ continue ;
3084
+ }
3085
+
3086
+ modified |= repairLoop (loopInd, sibling);
3087
+ }
3088
+ }
3089
+
3009
3090
if (modified)
3010
3091
{
3011
3092
JITDUMP (" Done canonicalizing " FMT_LP " \n\n " , loopInd);
0 commit comments