Skip to content

Commit 562f7f3

Browse files
committed
Handle OSR entry blocks in layout
1 parent af44f33 commit 562f7f3

1 file changed

Lines changed: 62 additions & 6 deletions

File tree

src/Graph.ts

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,15 +61,15 @@ function asTrueLH(block: Block | undefined): LoopHeader {
6161
if (isTrueLH(block)) {
6262
return block;
6363
}
64-
throw new Error("Block is not a LoopHeader");
64+
throw new Error(`Block ${block.id} is not a LoopHeader`);
6565
}
6666

6767
function asLH(block: Block | undefined): LoopHeader {
6868
assert(block);
6969
if (isLH(block)) {
7070
return block as LoopHeader;
7171
}
72-
throw new Error("Block is not a pseudo LoopHeader");
72+
throw new Error(`Block ${block.id} is not a pseudo LoopHeader`);
7373
}
7474

7575
type LayoutNode = BlockNode | DummyNode;
@@ -344,11 +344,12 @@ export class Graph {
344344
}
345345

346346
private layout(): [LayoutNode[][], number[], number[]] {
347-
const roots = this.blocks.filter(b => b.predecessors.length === 0);
347+
const [roots, osrBlocks] = this.findLayoutRoots();
348+
log.log("Layout roots:", roots.map(r => r.id));
348349

349-
// Make the roots into pseudo loop headers.
350-
for (const r of roots) {
351-
const root = r as LoopHeader;
350+
// Make the roots and OSR blocks into pseudo loop headers.
351+
for (const b of [...roots, ...osrBlocks]) {
352+
const root = b as LoopHeader;
352353
root.loopHeight = 0;
353354
root.parentLoop = null;
354355
root.outgoingEdges = [];
@@ -366,8 +367,15 @@ export class Graph {
366367
log.groupEnd();
367368
}
368369
for (const r of roots) {
370+
log.group("layer");
369371
this.layer(r);
372+
log.groupEnd();
370373
}
374+
for (const b of osrBlocks) {
375+
b.layer = 0;
376+
b.loopID = b.id;
377+
}
378+
371379
const layoutNodesByLayer = this.makeLayoutNodes();
372380
this.straightenEdges(layoutNodesByLayer);
373381
const trackHeights = this.finagleJoints(layoutNodesByLayer);
@@ -376,6 +384,44 @@ export class Graph {
376384
return [layoutNodesByLayer, layerHeights, trackHeights];
377385
}
378386

387+
// Finds the "layout roots" of the graph, which are the blocks we should
388+
// start the layout process from. This may not always equal the true roots
389+
// (blocks without predecessors), because OSR blocks can cause us to begin
390+
// layout at arbitrary points in the graph.
391+
private findLayoutRoots(): [Block[], Block[]] {
392+
const newRoots: Block[] = [];
393+
const osrBlocks: Block[] = [];
394+
const roots = this.blocks.filter(b => b.predecessors.length === 0);
395+
for (const root of roots) {
396+
let newRoot = root;
397+
if (root.attributes.includes("osr")) {
398+
assert(root.succs.length > 0);
399+
osrBlocks.push(root);
400+
newRoot = root.succs[0];
401+
402+
// Walk up the graph by repeatedly choosing the first non-OSR, non-
403+
// backedge predecessor.
404+
for (let j = 0; ; j++) {
405+
if (j >= 10_000_000) {
406+
throw new Error("likely infinite loop");
407+
}
408+
409+
const validPredecessors = newRoot.preds.filter(p => !p.attributes.includes("osr") && !p.attributes.includes("backedge"));
410+
if (validPredecessors.length === 0) {
411+
break;
412+
}
413+
newRoot = validPredecessors[0];
414+
}
415+
}
416+
417+
// Track and deduplicate
418+
if (!newRoots.includes(newRoot)) {
419+
newRoots.push(newRoot);
420+
}
421+
}
422+
return [newRoots, osrBlocks];
423+
}
424+
379425
// Walks through the graph tracking which loop each block belongs to. As
380426
// each block is visited, it is assigned the current loop ID. If the
381427
// block has lesser loopDepth than its parent, that means it is outside
@@ -392,6 +438,7 @@ export class Graph {
392438
}
393439

394440
log.log("block:", block.id, block.loopDepth, "loopIDsByDepth:", loopIDsByDepth);
441+
log.log(block.attributes);
395442

396443
if (isTrueLH(block)) {
397444
const parentID = loopIDsByDepth[loopIDsByDepth.length - 1];
@@ -427,6 +474,8 @@ export class Graph {
427474
}
428475

429476
private layer(block: Block, layer = 0) {
477+
log.log("block", block.id, "layer", layer);
478+
430479
if (block.attributes.includes("backedge")) {
431480
block.layer = block.succs[0].layer;
432481
return;
@@ -464,6 +513,8 @@ export class Graph {
464513
}
465514

466515
private makeLayoutNodes(): LayoutNode[][] {
516+
log.group("makeLayoutNodes");
517+
467518
function connectNodes(from: LayoutNode, fromPort: number, to: LayoutNode) {
468519
from.dstNodes[fromPort] = to;
469520
if (!to.srcNodes.includes(from)) {
@@ -498,6 +549,8 @@ export class Graph {
498549
const activeEdges: IncompleteEdge[] = [];
499550
const latestDummiesForBackedges = new Map<Block, DummyNode>();
500551
for (const [layer, blocks] of blocksByLayer.entries()) {
552+
log.group("layer", layer, "blocks", blocks.map(b => b.id));
553+
501554
// Delete any active edges that terminate at this layer, since we do
502555
// not want to make any dummy nodes for them.
503556
const terminatingEdges: IncompleteEdge[] = [];
@@ -639,6 +692,8 @@ export class Graph {
639692
const backedgeDummy = must(latestDummiesForBackedges.get(edge.dstBlock));
640693
connectNodes(edge.src, edge.srcPort, backedgeDummy);
641694
}
695+
696+
log.groupEnd();
642697
}
643698

644699
// Prune backedge dummies that don't have a source. This can happen because
@@ -704,6 +759,7 @@ export class Graph {
704759
}
705760
}
706761

762+
log.groupEnd();
707763
return layoutNodesByLayer;
708764
}
709765

0 commit comments

Comments
 (0)