@@ -617,9 +617,12 @@ bool Compiler::fgDumpFlowGraph(Phases phase)
617
617
618
618
#ifdef DEBUG
619
619
const bool createDotFile = JitConfig.JitDumpFgDot () != 0 ;
620
- const bool includeEH = JitConfig.JitDumpFgEH () != 0 ;
621
- const bool includeLoops = JitConfig.JitDumpFgLoops () != 0 ;
622
- const bool constrained = JitConfig.JitDumpFgConstrained () != 0 ;
620
+ const bool includeEH = (JitConfig.JitDumpFgEH () != 0 ) && !compIsForInlining ();
621
+ // The loop table is not well maintained after the optimization phases, but there is no single point at which
622
+ // it is declared invalid. For now, refuse to add loop information starting at the rationalize phase, to
623
+ // avoid asserts.
624
+ const bool includeLoops = (JitConfig.JitDumpFgLoops () != 0 ) && !compIsForInlining () && (phase < PHASE_RATIONALIZE);
625
+ const bool constrained = JitConfig.JitDumpFgConstrained () != 0 ;
623
626
#else // !DEBUG
624
627
const bool createDotFile = true ;
625
628
const bool includeEH = false ;
@@ -633,6 +636,8 @@ bool Compiler::fgDumpFlowGraph(Phases phase)
633
636
return false ;
634
637
}
635
638
639
+ JITDUMP (" Dumping flow graph after phase %s\n " , PhaseNames[phase]);
640
+
636
641
bool validWeights = fgHaveValidEdgeWeights;
637
642
double weightDivisor = (double )BasicBlock::getCalledCount (this );
638
643
const char * escapedString;
@@ -654,7 +659,8 @@ bool Compiler::fgDumpFlowGraph(Phases phase)
654
659
if (createDotFile)
655
660
{
656
661
fprintf (fgxFile, " digraph FlowGraph {\n " );
657
- fprintf (fgxFile, " graph [label = \" %s\\ nafter\\ n%s\" ];\n " , info.compMethodName , PhaseNames[phase]);
662
+ fprintf (fgxFile, " graph [label = \" %s%s\\ nafter\\ n%s\" ];\n " , info.compMethodName ,
663
+ compIsForInlining () ? " \\ n(inlinee)" : " " , PhaseNames[phase]);
658
664
fprintf (fgxFile, " node [shape = \" Box\" ];\n " );
659
665
}
660
666
else
@@ -712,12 +718,18 @@ bool Compiler::fgDumpFlowGraph(Phases phase)
712
718
// to insert in the tree, to determine nesting. We'd like to use the bbNum to do this. However, we don't
713
719
// want to renumber the blocks. So, create a mapping of bbNum to ordinal, and compare block order by
714
720
// comparing the mapped ordinals instead.
715
-
716
- unsigned blockOrdinal = 0 ;
717
- unsigned * blkMap = new (this , CMK_DebugOnly) unsigned [fgBBNumMax + 1 ];
718
- memset (blkMap, 0 , sizeof (unsigned ) * (fgBBNumMax + 1 ));
721
+ //
722
+ // For inlinees, the max block number of the inliner is used, so we need to allocate the block map based on
723
+ // that size, even though it means allocating a block map possibly much bigger than what's required for just
724
+ // the inlinee blocks.
725
+
726
+ unsigned blkMapSize = 1 + (compIsForInlining () ? impInlineInfo->InlinerCompiler ->fgBBNumMax : fgBBNumMax);
727
+ unsigned blockOrdinal = 1 ;
728
+ unsigned * blkMap = new (this , CMK_DebugOnly) unsigned [blkMapSize];
729
+ memset (blkMap, 0 , sizeof (unsigned ) * blkMapSize);
719
730
for (BasicBlock* block = fgFirstBB; block != nullptr ; block = block->bbNext )
720
731
{
732
+ assert (block->bbNum < blkMapSize);
721
733
blkMap[block->bbNum ] = blockOrdinal++;
722
734
}
723
735
@@ -1040,7 +1052,8 @@ bool Compiler::fgDumpFlowGraph(Phases phase)
1040
1052
};
1041
1053
1042
1054
public:
1043
- RegionGraph (Compiler* comp, unsigned * blkMap) : m_comp(comp), m_rgnRoot(nullptr ), m_blkMap(blkMap)
1055
+ RegionGraph (Compiler* comp, unsigned * blkMap, unsigned blkMapSize)
1056
+ : m_comp(comp), m_rgnRoot(nullptr ), m_blkMap(blkMap), m_blkMapSize(blkMapSize)
1044
1057
{
1045
1058
// Create a root region that encompasses the whole function.
1046
1059
m_rgnRoot =
@@ -1087,6 +1100,24 @@ bool Compiler::fgDumpFlowGraph(Phases phase)
1087
1100
unsigned childStartOrdinal = m_blkMap[child->m_bbStart ->bbNum ];
1088
1101
unsigned childEndOrdinal = m_blkMap[child->m_bbEnd ->bbNum ];
1089
1102
1103
+ // Consider the following cases, where each "x" is a block in the range:
1104
+ // xxxxxxx // current 'child' range; we're comparing against this
1105
+ // xxxxxxx // (1) same range; could be considered child or parent
1106
+ // xxxxxxxxx // (2) parent range, shares last block
1107
+ // xxxxxxxxx // (3) parent range, shares first block
1108
+ // xxxxxxxxxxx // (4) fully overlapping parent range
1109
+ // xx // (5) non-overlapping preceding sibling range
1110
+ // xx // (6) non-overlapping following sibling range
1111
+ // xxx // (7) child range
1112
+ // xxx // (8) child range, shares same start block
1113
+ // x // (9) single-block child range, shares same start block
1114
+ // xxx // (10) child range, shares same end block
1115
+ // x // (11) single-block child range, shares same end block
1116
+ // xxxxxxx // illegal: overlapping ranges
1117
+ // xxx // illegal: overlapping ranges (shared child start block and new end block)
1118
+ // xxxxxxx // illegal: overlapping ranges
1119
+ // xxx // illegal: overlapping ranges (shared child end block and new start block)
1120
+
1090
1121
// Assert the child is properly nested within the parent.
1091
1122
// Note that if regions have the same start and end, you can't tell which is nested within the
1092
1123
// other, though it shouldn't matter.
@@ -1095,21 +1126,19 @@ bool Compiler::fgDumpFlowGraph(Phases phase)
1095
1126
assert (childEndOrdinal <= curEndOrdinal);
1096
1127
1097
1128
// Should the new region be before this child?
1129
+ // Case (5).
1098
1130
if (newEndOrdinal < childStartOrdinal)
1099
1131
{
1100
1132
// Insert before this child.
1101
1133
newRgn->m_rgnNext = child;
1102
1134
*lastChildPtr = newRgn;
1103
1135
break ;
1104
1136
}
1105
- else if (newEndOrdinal <= childEndOrdinal)
1137
+ else if ((newStartOrdinal >= childStartOrdinal) && ( newEndOrdinal <= childEndOrdinal) )
1106
1138
{
1107
1139
// Insert as a child of this child.
1108
- // Need to recurse to walk the child's children list to see where
1109
- // it belongs.
1110
-
1111
- // It better be properly nested.
1112
- assert (newStartOrdinal >= childStartOrdinal);
1140
+ // Need to recurse to walk the child's children list to see where it belongs.
1141
+ // Case (1), (7), (8), (9), (10), (11).
1113
1142
1114
1143
curStartOrdinal = m_blkMap[child->m_bbStart ->bbNum ];
1115
1144
curEndOrdinal = m_blkMap[child->m_bbEnd ->bbNum ];
@@ -1122,6 +1151,8 @@ bool Compiler::fgDumpFlowGraph(Phases phase)
1122
1151
else if (newStartOrdinal <= childStartOrdinal)
1123
1152
{
1124
1153
// The new region is a parent of one or more of the existing children.
1154
+ // Case (2), (3), (4).
1155
+
1125
1156
// Find all the children it encompasses.
1126
1157
Region** lastEndChildPtr = &child->m_rgnNext ;
1127
1158
Region* endChild = child->m_rgnNext ;
@@ -1154,6 +1185,7 @@ bool Compiler::fgDumpFlowGraph(Phases phase)
1154
1185
}
1155
1186
1156
1187
// Else, look for next child.
1188
+ // Case (6).
1157
1189
1158
1190
lastChildPtr = &child->m_rgnNext ;
1159
1191
child = child->m_rgnNext ;
@@ -1216,17 +1248,82 @@ bool Compiler::fgDumpFlowGraph(Phases phase)
1216
1248
// ------------------------------------------------------------------------
1217
1249
// Dump: dump the entire region graph
1218
1250
//
1219
- // Arguments:
1220
- // stmt - the statement to dump;
1221
- // bbNum - the basic block number to dump.
1222
- //
1223
1251
void Dump ()
1224
1252
{
1225
1253
printf (" Region graph:\n " );
1226
1254
DumpRegionNode (m_rgnRoot, 0 );
1227
1255
printf (" \n " );
1228
1256
}
1229
1257
1258
+ // ------------------------------------------------------------------------
1259
+ // VerifyNode: verify the region graph rooted at `rgn`.
1260
+ //
1261
+ // Arguments:
1262
+ // rgn - the node (and its children) to check.
1263
+ //
1264
+ void Verify (Region* rgn)
1265
+ {
1266
+ // The region needs to be a non-overlapping parent to all its children.
1267
+ // The children need to be non-overlapping, and in increasing order.
1268
+
1269
+ unsigned rgnStartOrdinal = m_blkMap[rgn->m_bbStart ->bbNum ];
1270
+ unsigned rgnEndOrdinal = m_blkMap[rgn->m_bbEnd ->bbNum ];
1271
+ assert (rgnStartOrdinal <= rgnEndOrdinal);
1272
+
1273
+ Region* child = rgn->m_rgnChild ;
1274
+ Region* lastChild = nullptr ;
1275
+ if (child != nullptr )
1276
+ {
1277
+ unsigned childStartOrdinal = m_blkMap[child->m_bbStart ->bbNum ];
1278
+ unsigned childEndOrdinal = m_blkMap[child->m_bbEnd ->bbNum ];
1279
+ assert (childStartOrdinal <= childEndOrdinal);
1280
+ assert (rgnStartOrdinal <= childStartOrdinal);
1281
+
1282
+ while (true )
1283
+ {
1284
+ Verify (child);
1285
+
1286
+ lastChild = child;
1287
+ unsigned lastChildStartOrdinal = childStartOrdinal;
1288
+ unsigned lastChildEndOrdinal = childEndOrdinal;
1289
+
1290
+ child = child->m_rgnNext ;
1291
+ if (child == nullptr )
1292
+ {
1293
+ break ;
1294
+ }
1295
+
1296
+ childStartOrdinal = m_blkMap[child->m_bbStart ->bbNum ];
1297
+ childEndOrdinal = m_blkMap[child->m_bbEnd ->bbNum ];
1298
+ assert (childStartOrdinal <= childEndOrdinal);
1299
+
1300
+ // The children can't overlap; they can't share any blocks.
1301
+ assert (lastChildEndOrdinal < childStartOrdinal);
1302
+ }
1303
+
1304
+ // The parent region must fully include the last child.
1305
+ assert (childEndOrdinal <= rgnEndOrdinal);
1306
+ }
1307
+ }
1308
+
1309
+ // ------------------------------------------------------------------------
1310
+ // Verify: verify the region graph satisfies proper nesting, and other legality rules.
1311
+ //
1312
+ void Verify ()
1313
+ {
1314
+ assert (m_comp != nullptr );
1315
+ assert (m_blkMap != nullptr );
1316
+ for (unsigned i = 0 ; i < m_blkMapSize; i++)
1317
+ {
1318
+ assert (m_blkMap[i] < m_blkMapSize);
1319
+ }
1320
+
1321
+ // The root region has no siblings.
1322
+ assert (m_rgnRoot != nullptr );
1323
+ assert (m_rgnRoot->m_rgnNext == nullptr );
1324
+ Verify (m_rgnRoot);
1325
+ }
1326
+
1230
1327
#endif // DEBUG
1231
1328
1232
1329
// ------------------------------------------------------------------------
@@ -1349,11 +1446,12 @@ bool Compiler::fgDumpFlowGraph(Phases phase)
1349
1446
Compiler* m_comp;
1350
1447
Region* m_rgnRoot;
1351
1448
unsigned * m_blkMap;
1449
+ unsigned m_blkMapSize;
1352
1450
};
1353
1451
1354
1452
// Define the region graph object. We'll add regions to this, then output the graph.
1355
1453
1356
- RegionGraph rgnGraph (this , blkMap);
1454
+ RegionGraph rgnGraph (this , blkMap, blkMapSize );
1357
1455
1358
1456
// Add the EH regions to the region graph. An EH region consists of a region for the
1359
1457
// `try`, a region for the handler, and, for filter/filter-handlers, a region for the
@@ -1405,13 +1503,18 @@ bool Compiler::fgDumpFlowGraph(Phases phase)
1405
1503
for (unsigned loopNum = 0 ; loopNum < optLoopCount; loopNum++)
1406
1504
{
1407
1505
const LoopDsc& loop = optLoopTable[loopNum];
1506
+ if (loop.lpFlags & LPFLG_REMOVED)
1507
+ {
1508
+ continue ;
1509
+ }
1408
1510
sprintf_s (name, sizeof (name), FMT_LP, loopNum);
1409
1511
rgnGraph.Insert (name, RegionGraph::RegionType::Loop, loop.lpFirst , loop.lpBottom );
1410
1512
}
1411
1513
}
1412
1514
1413
1515
// All the regions have been added. Now, output them.
1414
1516
DBEXEC (verbose, rgnGraph.Dump ());
1517
+ INDEBUG (rgnGraph.Verify ());
1415
1518
rgnGraph.Output (fgxFile);
1416
1519
}
1417
1520
}
0 commit comments