@@ -230,7 +230,7 @@ class WebAssemblyFixIrreducibleControlFlow final : public MachineFunctionPass {
230
230
MachineFunction &MF);
231
231
232
232
void makeSingleEntryLoop (BlockSet &Entries, BlockSet &Blocks,
233
- MachineFunction &MF);
233
+ MachineFunction &MF, const ReachabilityGraph &Graph );
234
234
235
235
public:
236
236
static char ID; // Pass identification, replacement for typeid
@@ -279,7 +279,7 @@ bool WebAssemblyFixIrreducibleControlFlow::processRegion(
279
279
}
280
280
281
281
if (MutualLoopEntries.size () > 1 ) {
282
- makeSingleEntryLoop (MutualLoopEntries, Blocks, MF);
282
+ makeSingleEntryLoop (MutualLoopEntries, Blocks, MF, Graph );
283
283
FoundIrreducibility = true ;
284
284
Changed = true ;
285
285
break ;
@@ -315,9 +315,12 @@ bool WebAssemblyFixIrreducibleControlFlow::processRegion(
315
315
// Given a set of entries to a single loop, create a single entry for that
316
316
// loop by creating a dispatch block for them, routing control flow using
317
317
// a helper variable. Also updates Blocks with any new blocks created, so
318
- // that we properly track all the blocks in the region.
318
+ // that we properly track all the blocks in the region. But this does not update
319
+ // ReachabilityGraph; this will be updated in the caller of this function as
320
+ // needed.
319
321
void WebAssemblyFixIrreducibleControlFlow::makeSingleEntryLoop (
320
- BlockSet &Entries, BlockSet &Blocks, MachineFunction &MF) {
322
+ BlockSet &Entries, BlockSet &Blocks, MachineFunction &MF,
323
+ const ReachabilityGraph &Graph) {
321
324
assert (Entries.size () >= 2 );
322
325
323
326
// Sort the entries to ensure a deterministic build.
@@ -385,36 +388,78 @@ void WebAssemblyFixIrreducibleControlFlow::makeSingleEntryLoop(
385
388
}
386
389
}
387
390
388
- for (MachineBasicBlock *Pred : AllPreds) {
389
- DenseMap<MachineBasicBlock *, MachineBasicBlock *> Map;
391
+ // This set stores predecessors within this loop.
392
+ DenseSet<MachineBasicBlock *> InLoop;
393
+ for (auto *Pred : AllPreds) {
390
394
for (auto *Entry : Pred->successors ()) {
391
- if (!Entries.count (Entry)) {
395
+ if (!Entries.count (Entry))
392
396
continue ;
397
+ if (Graph.canReach (Entry, Pred)) {
398
+ InLoop.insert (Pred);
399
+ break ;
393
400
}
401
+ }
402
+ }
403
+
404
+ // Record if each entry has a layout predecessor. This map stores
405
+ // <<Predecessor is within the loop?, loop entry>, layout predecessor>
406
+ std::map<std::pair<bool , MachineBasicBlock *>, MachineBasicBlock *>
407
+ EntryToLayoutPred;
408
+ for (auto *Pred : AllPreds)
409
+ for (auto *Entry : Pred->successors ())
410
+ if (Entries.count (Entry) && Pred->isLayoutSuccessor (Entry))
411
+ EntryToLayoutPred[std::make_pair (InLoop.count (Pred), Entry)] = Pred;
412
+
413
+ // We need to create at most two routing blocks per entry: one for
414
+ // predecessors outside the loop and one for predecessors inside the loop.
415
+ // This map stores
416
+ // <<Predecessor is within the loop?, loop entry>, routing block>
417
+ std::map<std::pair<bool , MachineBasicBlock *>, MachineBasicBlock *> Map;
418
+ for (auto *Pred : AllPreds) {
419
+ bool PredInLoop = InLoop.count (Pred);
420
+ for (auto *Entry : Pred->successors ()) {
421
+ if (!Entries.count (Entry) ||
422
+ Map.count (std::make_pair (InLoop.count (Pred), Entry)))
423
+ continue ;
424
+ // If there exists a layout predecessor of this entry and this predecessor
425
+ // is not that, we rather create a routing block after that layout
426
+ // predecessor to save a branch.
427
+ if (EntryToLayoutPred.count (std::make_pair (PredInLoop, Entry)) &&
428
+ EntryToLayoutPred[std::make_pair (PredInLoop, Entry)] != Pred)
429
+ continue ;
394
430
395
431
// This is a successor we need to rewrite.
396
- MachineBasicBlock *Split = MF.CreateMachineBasicBlock ();
432
+ MachineBasicBlock *Routing = MF.CreateMachineBasicBlock ();
397
433
MF.insert (Pred->isLayoutSuccessor (Entry)
398
434
? MachineFunction::iterator (Entry)
399
435
: MF.end (),
400
- Split );
401
- Blocks.insert (Split );
436
+ Routing );
437
+ Blocks.insert (Routing );
402
438
403
439
// Set the jump table's register of the index of the block we wish to
404
440
// jump to, and jump to the jump table.
405
- BuildMI (Split , DebugLoc (), TII.get (WebAssembly::CONST_I32), Reg)
441
+ BuildMI (Routing , DebugLoc (), TII.get (WebAssembly::CONST_I32), Reg)
406
442
.addImm (Indices[Entry]);
407
- BuildMI (Split , DebugLoc (), TII.get (WebAssembly::BR)).addMBB (Dispatch);
408
- Split ->addSuccessor (Dispatch);
409
- Map[Entry] = Split ;
443
+ BuildMI (Routing , DebugLoc (), TII.get (WebAssembly::BR)).addMBB (Dispatch);
444
+ Routing ->addSuccessor (Dispatch);
445
+ Map[std::make_pair (PredInLoop, Entry) ] = Routing ;
410
446
}
447
+ }
448
+
449
+ for (auto *Pred : AllPreds) {
450
+ bool PredInLoop = InLoop.count (Pred);
411
451
// Remap the terminator operands and the successor list.
412
452
for (MachineInstr &Term : Pred->terminators ())
413
453
for (auto &Op : Term.explicit_uses ())
414
454
if (Op.isMBB () && Indices.count (Op.getMBB ()))
415
- Op.setMBB (Map[Op.getMBB ()]);
416
- for (auto Rewrite : Map)
417
- Pred->replaceSuccessor (Rewrite.first , Rewrite.second );
455
+ Op.setMBB (Map[std::make_pair (PredInLoop, Op.getMBB ())]);
456
+
457
+ for (auto *Succ : Pred->successors ()) {
458
+ if (!Entries.count (Succ))
459
+ continue ;
460
+ auto *Routing = Map[std::make_pair (PredInLoop, Succ)];
461
+ Pred->replaceSuccessor (Succ, Routing);
462
+ }
418
463
}
419
464
420
465
// Create a fake default label, because br_table requires one.
0 commit comments