Use ValueNumberGenerator for generating block numbers

Computing the next id from the max over a linear list has bad
performance.

Bug: 163089034
Change-Id: Idf25f7845984a2f915771df7f16f725cad3b8979
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/constant/SparseConditionalConstantPropagation.java b/src/main/java/com/android/tools/r8/ir/analysis/constant/SparseConditionalConstantPropagation.java
index 54d5160..cf531ff 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/constant/SparseConditionalConstantPropagation.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/constant/SparseConditionalConstantPropagation.java
@@ -38,16 +38,16 @@
   private final Map<Value, LatticeElement> mapping = new HashMap<>();
   private final Deque<Value> ssaEdges = new LinkedList<>();
   private final Deque<BasicBlock> flowEdges = new LinkedList<>();
-  private final int nextBlockNumber;
+  private final int maxBlockNumber;
   private final BitSet[] executableFlowEdges;
   private final BitSet visitedBlocks;
 
   public SparseConditionalConstantPropagation(AppView<?> appView, IRCode code) {
     this.appView = appView;
     this.code = code;
-    nextBlockNumber = code.getHighestBlockNumber() + 1;
-    executableFlowEdges = new BitSet[nextBlockNumber];
-    visitedBlocks = new BitSet(nextBlockNumber);
+    maxBlockNumber = code.getCurrentBlockNumber() + 1;
+    executableFlowEdges = new BitSet[maxBlockNumber];
+    visitedBlocks = new BitSet(maxBlockNumber);
   }
 
   public void run() {
@@ -252,7 +252,7 @@
   private void setExecutableEdge(int from, int to) {
     BitSet previousExecutable = executableFlowEdges[to];
     if (previousExecutable == null) {
-      previousExecutable = new BitSet(nextBlockNumber);
+      previousExecutable = new BitSet(maxBlockNumber);
       executableFlowEdges[to] = previousExecutable;
     }
     previousExecutable.set(from);
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
index 0064ccb..fa3c34c 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
@@ -1483,7 +1483,7 @@
     block.add(moveException, code);
     block.add(throwInstruction, code);
     block.close(null);
-    block.setNumber(code.getHighestBlockNumber() + 1);
+    block.setNumber(code.getNextBlockNumber());
     return block;
   }
 
@@ -1762,9 +1762,8 @@
    * method does not affect incoming edges in any way, and just adds new blocks with MoveException
    * and Goto.
    */
-  public int splitCriticalExceptionEdges(
+  public void splitCriticalExceptionEdges(
       IRCode code, Consumer<BasicBlock> onNewBlock, InternalOptions options) {
-    int nextBlockNumber = code.getHighestBlockNumber() + 1;
     List<BasicBlock> predecessors = getMutablePredecessors();
     boolean hasMoveException = entry().isMoveException();
     TypeElement exceptionTypeLattice = null;
@@ -1788,7 +1787,7 @@
             "Invalid block structure: catch block reachable via non-exceptional flow.");
       }
       BasicBlock newBlock = new BasicBlock();
-      newBlock.setNumber(nextBlockNumber++);
+      newBlock.setNumber(code.getNextBlockNumber());
       newPredecessors.add(newBlock);
       if (hasMoveException) {
         Value value =
@@ -1823,7 +1822,6 @@
       phi.addOperands(values);
       move.outValue().replaceUsers(phi);
     }
-    return nextBlockNumber;
   }
 
   /**
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionListIterator.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionListIterator.java
index 57d52df..68447db 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionListIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionListIterator.java
@@ -383,9 +383,6 @@
     List<BasicBlock> blocks = code.blocks;
     assert blocksIterator == null || IteratorUtils.peekPrevious(blocksIterator) == block;
 
-    int blockNumber = code.getHighestBlockNumber() + 1;
-    BasicBlock newBlock;
-
     // Don't allow splitting after the last instruction.
     assert hasNext();
 
@@ -394,7 +391,7 @@
 
     // Prepare the new block, placing the exception handlers on the block with the throwing
     // instruction.
-    newBlock = block.createSplitBlock(blockNumber, keepCatchHandlers);
+    BasicBlock newBlock = block.createSplitBlock(code.getNextBlockNumber(), keepCatchHandlers);
 
     // Add a goto instruction.
     Goto newGoto = new Goto(block);
@@ -699,9 +696,8 @@
     assert IteratorUtils.peekNext(blocksIterator) == invokeBlock;
 
     // Insert inlinee blocks into the IR code of the callee, before the invoke block.
-    int blockNumber = code.getHighestBlockNumber() + 1;
     for (BasicBlock bb : inlinee.blocks) {
-      bb.setNumber(blockNumber++);
+      bb.setNumber(code.getNextBlockNumber());
       blocksIterator.add(bb);
     }
 
@@ -745,7 +741,7 @@
       return it;
     }
     BasicBlock newExitBlock = new BasicBlock();
-    newExitBlock.setNumber(code.getHighestBlockNumber() + 1);
+    newExitBlock.setNumber(code.getNextBlockNumber());
     Return newReturn;
     if (normalExits.get(0).exit().asReturn().isReturnVoid()) {
       newReturn = new Return();
diff --git a/src/main/java/com/android/tools/r8/ir/code/IRCode.java b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
index f177619..77988b8 100644
--- a/src/main/java/com/android/tools/r8/ir/code/IRCode.java
+++ b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
@@ -38,7 +38,6 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.Comparator;
 import java.util.Deque;
 import java.util.HashSet;
 import java.util.IdentityHashMap;
@@ -109,6 +108,7 @@
 
   public LinkedList<BasicBlock> blocks;
   public final ValueNumberGenerator valueNumberGenerator;
+  public final ValueNumberGenerator basicBlockNumberGenerator;
   private int usedMarkingColors = 0;
 
   private boolean numbered = false;
@@ -128,14 +128,17 @@
       ProgramMethod method,
       LinkedList<BasicBlock> blocks,
       ValueNumberGenerator valueNumberGenerator,
+      ValueNumberGenerator basicBlockNumberGenerator,
       IRMetadata metadata,
       Origin origin) {
     assert metadata != null;
     assert options != null;
+    assert blocks.size() == basicBlockNumberGenerator.peek();
     this.options = options;
     this.method = method;
     this.blocks = blocks;
     this.valueNumberGenerator = valueNumberGenerator;
+    this.basicBlockNumberGenerator = basicBlockNumberGenerator;
     this.metadata = metadata;
     this.origin = origin;
     // TODO(zerny): Remove or update this property now that all instructions have positions.
@@ -348,7 +351,7 @@
       if (hasSeenThrowingInstruction) {
         List<BasicBlock> successors = block.getSuccessors();
         if (successors.size() == 1 && ListUtils.first(successors).getPredecessors().size() > 1) {
-          BasicBlock splitBlock = block.createSplitBlock(getHighestBlockNumber() + 1, true);
+          BasicBlock splitBlock = block.createSplitBlock(getNextBlockNumber(), true);
           Goto newGoto = new Goto(block);
           newGoto.setPosition(Position.none());
           splitBlock.listIterator(this).add(newGoto);
@@ -361,7 +364,6 @@
 
   public void splitCriticalEdges() {
     List<BasicBlock> newBlocks = new ArrayList<>();
-    int nextBlockNumber = getHighestBlockNumber() + 1;
     for (BasicBlock block : blocks) {
       // We are using a spilling register allocator that might need to insert moves at
       // all critical edges, so we always split them all.
@@ -383,7 +385,7 @@
           // structure.
           BasicBlock newBlock =
               BasicBlock.createGotoBlock(
-                  nextBlockNumber++, pred.exit().getPosition(), metadata, block);
+                  getNextBlockNumber(), pred.exit().getPosition(), metadata, block);
           newBlocks.add(newBlock);
           pred.replaceSuccessor(block, newBlock);
           newBlock.getMutablePredecessors().add(pred);
@@ -424,7 +426,6 @@
     // Get the blocks first, as calling topologicallySortedBlocks also sets marks.
     ImmutableList<BasicBlock> sorted = topologicallySortedBlocks();
     int color = reserveMarkingColor();
-    int nextBlockNumber = blocks.size();
     LinkedList<BasicBlock> tracedBlocks = new LinkedList<>();
     for (BasicBlock block : sorted) {
       if (!block.isMarked(color)) {
@@ -441,7 +442,7 @@
         if (fallthrough != null) {
           BasicBlock newFallthrough =
               BasicBlock.createGotoBlock(
-                  nextBlockNumber++, current.exit().getPosition(), metadata, fallthrough);
+                  getNextBlockNumber(), current.exit().getPosition(), metadata, fallthrough);
           current.exit().setFallthroughBlock(newFallthrough);
           newFallthrough.getMutablePredecessors().add(current);
           fallthrough.replacePredecessor(current, newFallthrough);
@@ -786,12 +787,12 @@
   }
 
   public boolean consistentBlockNumbering() {
-    blocks
-        .stream()
+    blocks.stream()
         .collect(Collectors.groupingBy(BasicBlock::getNumber, Collectors.counting()))
         .forEach(
             (key, value) -> {
               assert value == 1;
+              assert value <= basicBlockNumberGenerator.peek();
             });
     return true;
   }
@@ -1144,8 +1145,12 @@
     return new Phi(valueNumberGenerator.next(), block, type, null, RegisterReadType.NORMAL);
   }
 
-  public final int getHighestBlockNumber() {
-    return blocks.stream().max(Comparator.comparingInt(BasicBlock::getNumber)).get().getNumber();
+  public final int getNextBlockNumber() {
+    return basicBlockNumberGenerator.next();
+  }
+
+  public final int getCurrentBlockNumber() {
+    return basicBlockNumberGenerator.peek();
   }
 
   public ConstClass createConstClass(AppView<?> appView, DexType type) {
diff --git a/src/main/java/com/android/tools/r8/ir/code/ValueNumberGenerator.java b/src/main/java/com/android/tools/r8/ir/code/ValueNumberGenerator.java
index ac07f11..722f30e 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ValueNumberGenerator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ValueNumberGenerator.java
@@ -9,4 +9,8 @@
   public int next() {
     return nextValueNumber++;
   }
+
+  public int peek() {
+    return nextValueNumber;
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index 292f069..c36eb8e 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -392,6 +392,7 @@
   private int currentInstructionOffset = -1;
 
   final private ValueNumberGenerator valueNumberGenerator;
+  private final ValueNumberGenerator basicBlockNumberGenerator;
   private final ProgramMethod method;
   private ProgramMethod context;
   public final AppView<?> appView;
@@ -483,6 +484,7 @@
     this.origin = origin;
     this.prototypeChanges = prototypeChanges;
     this.valueNumberGenerator = valueNumberGenerator;
+    this.basicBlockNumberGenerator = new ValueNumberGenerator();
   }
 
   public DexEncodedMethod getMethod() {
@@ -679,7 +681,14 @@
 
     // Package up the IR code.
     IRCode ir =
-        new IRCode(appView.options(), method, blocks, valueNumberGenerator, metadata, origin);
+        new IRCode(
+            appView.options(),
+            method,
+            blocks,
+            valueNumberGenerator,
+            basicBlockNumberGenerator,
+            metadata,
+            origin);
 
     // Verify critical edges are split so we have a place to insert phi moves if necessary.
     assert ir.verifySplitCriticalEdges();
@@ -834,7 +843,7 @@
       assert debugLocalEnds.isEmpty();
       setCurrentBlock(item.block);
       blocks.add(currentBlock);
-      currentBlock.setNumber(nextBlockNumber++);
+      currentBlock.setNumber(basicBlockNumberGenerator.next());
       // Process synthesized move-exception block specially.
       if (item instanceof MoveExceptionWorklistItem) {
         processMoveExceptionItem((MoveExceptionWorklistItem) item);
@@ -2286,7 +2295,7 @@
 
     BlockInfo info = new BlockInfo();
     BasicBlock block = info.block;
-    block.setNumber(nextBlockNumber++);
+    block.setNumber(basicBlockNumberGenerator.next());
     blocks.add(block);
 
     // Compute some unused offset for the new block and link it in the CFG.
@@ -2631,7 +2640,7 @@
             if (joinBlock == null) {
               joinBlock =
                   BasicBlock.createGotoBlock(
-                      blocks.size() + blocksToAdd.size(), block.getPosition(), metadata, block);
+                      basicBlockNumberGenerator.next(), block.getPosition(), metadata, block);
               joinBlocks.put(otherPredecessorIndex, joinBlock);
               blocksToAdd.add(joinBlock);
               BasicBlock otherPredecessor = block.getPredecessors().get(otherPredecessorIndex);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/StringSwitchRemover.java b/src/main/java/com/android/tools/r8/ir/conversion/StringSwitchRemover.java
index 52a7d0a..fec0919 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/StringSwitchRemover.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/StringSwitchRemover.java
@@ -204,7 +204,6 @@
 
     @Override
     void removeStringSwitch() {
-      int nextBlockNumber = code.getHighestBlockNumber() + 1;
       // Remove outgoing control flow edges from the block containing the string switch.
       for (BasicBlock successor : block.getNormalSuccessors()) {
         successor.removePredecessor(block, null);
@@ -237,7 +236,8 @@
         if (blocksTargetedByMultipleSwitchCases.contains(targetBlock)) {
           // Need an intermediate block to avoid critical edges.
           BasicBlock intermediateBlock =
-              BasicBlock.createGotoBlock(nextBlockNumber++, Position.none(), code.metadata());
+              BasicBlock.createGotoBlock(
+                  code.getNextBlockNumber(), Position.none(), code.metadata());
           intermediateBlock.link(targetBlock);
           blockIterator.add(intermediateBlock);
           newBlocksWithStrings.add(intermediateBlock);
@@ -245,7 +245,7 @@
         }
         BasicBlock newBlock =
             BasicBlock.createIfBlock(
-                nextBlockNumber++,
+                code.getNextBlockNumber(),
                 ifInstruction,
                 code.metadata(),
                 constStringInstruction,
@@ -278,7 +278,6 @@
 
     Int2ReferenceMap<Map<DexString, BasicBlock>> structure;
 
-    private int nextBlockNumber;
     private int nextStringId;
 
     private SingleHashBasedStringSwitchRemover(
@@ -294,11 +293,10 @@
       this.idSwitchBlock = theSwitch.fallthroughBlock().getUniqueNormalSuccessor();
       this.idSwitchFallthroughBlock = idSwitchBlock.getUniqueNormalSuccessor();
       this.structure = createStructure(theSwitch);
-      this.nextBlockNumber = code.getHighestBlockNumber() + 1;
     }
 
     private int getAndIncrementNextBlockNumber() {
-      return nextBlockNumber++;
+      return code.getNextBlockNumber();
     }
 
     private Int2ReferenceMap<Map<DexString, BasicBlock>> createStructure(StringSwitch theSwitch)
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/BasicBlockInstructionsEquivalence.java b/src/main/java/com/android/tools/r8/ir/optimize/BasicBlockInstructionsEquivalence.java
index 17c8d1a..b7909df 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/BasicBlockInstructionsEquivalence.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/BasicBlockInstructionsEquivalence.java
@@ -21,7 +21,7 @@
 
   BasicBlockInstructionsEquivalence(IRCode code, RegisterAllocator allocator) {
     this.allocator = allocator;
-    hashes = new int[code.getHighestBlockNumber() + 1];
+    hashes = new int[code.getCurrentBlockNumber() + 1];
     Arrays.fill(hashes, UNKNOW_HASH);
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index 4cb2fab..996b8d8 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -710,7 +710,6 @@
     assert block == originalBlock;
 
     // Collect the new blocks for adding to the block list.
-    int nextBlockNumber = code.getHighestBlockNumber() + 1;
     LinkedList<BasicBlock> newBlocks = new LinkedList<>();
 
     // Build the switch-blocks backwards, to always have the fallthrough block in hand.
@@ -722,9 +721,7 @@
         int key = keys.getInt(j);
         switchBuilder.addKeyAndTarget(key, keyToTarget.get(key));
       }
-      switchBuilder
-          .setFallthrough(fallthroughBlock)
-          .setBlockNumber(nextBlockNumber++);
+      switchBuilder.setFallthrough(fallthroughBlock).setBlockNumber(code.getNextBlockNumber());
       BasicBlock newSwitchBlock = switchBuilder.build(code.metadata());
       newBlocks.addFirst(newSwitchBlock);
       fallthroughBlock = newSwitchBlock;
@@ -740,7 +737,7 @@
           .setRight(key)
           .setTarget(peeledOffTarget)
           .setFallthrough(fallthroughBlock)
-          .setBlockNumber(nextBlockNumber++);
+          .setBlockNumber(code.getNextBlockNumber());
       BasicBlock ifBlock = ifBuilder.build();
       newBlocks.addFirst(ifBlock);
       fallthroughBlock = ifBlock;
@@ -3478,7 +3475,8 @@
       iterator.add(new InvokeVirtual(print, null, ImmutableList.of(out, indent)));
 
       // Add a block for end-of-line printing.
-      BasicBlock eol = BasicBlock.createGotoBlock(code.blocks.size(), position, code.metadata());
+      BasicBlock eol =
+          BasicBlock.createGotoBlock(code.getNextBlockNumber(), position, code.metadata());
       code.blocks.add(eol);
 
       BasicBlock successor = block.unlinkSingleSuccessor();
@@ -3493,14 +3491,15 @@
         successor = block.unlinkSingleSuccessor();
         If theIf = new If(Type.NE, argument);
         theIf.setPosition(position);
-        BasicBlock ifBlock = BasicBlock.createIfBlock(code.blocks.size(), theIf, code.metadata());
+        BasicBlock ifBlock =
+            BasicBlock.createIfBlock(code.getNextBlockNumber(), theIf, code.metadata());
         code.blocks.add(ifBlock);
         // Fallthrough block must be added right after the if.
         BasicBlock isNullBlock =
-            BasicBlock.createGotoBlock(code.blocks.size(), position, code.metadata());
+            BasicBlock.createGotoBlock(code.getNextBlockNumber(), position, code.metadata());
         code.blocks.add(isNullBlock);
         BasicBlock isNotNullBlock =
-            BasicBlock.createGotoBlock(code.blocks.size(), position, code.metadata());
+            BasicBlock.createGotoBlock(code.getNextBlockNumber(), position, code.metadata());
         code.blocks.add(isNotNullBlock);
 
         // Link the added blocks together.
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index c1130e4..67b6310 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -635,11 +635,9 @@
 
         code.prepareBlocksForCatchHandlers();
 
-        int nextBlockNumber = code.getHighestBlockNumber() + 1;
-
         // Create a block for holding the monitor-exit instruction.
         BasicBlock monitorExitBlock = new BasicBlock();
-        monitorExitBlock.setNumber(nextBlockNumber++);
+        monitorExitBlock.setNumber(code.getNextBlockNumber());
 
         // For each block in the code that may throw, add a catch-all handler targeting the
         // monitor-exit block.
@@ -654,7 +652,7 @@
           }
           BasicBlock moveExceptionBlock =
               BasicBlock.createGotoBlock(
-                  nextBlockNumber++, Position.none(), code.metadata(), monitorExitBlock);
+                  code.getNextBlockNumber(), Position.none(), code.metadata(), monitorExitBlock);
           InstructionListIterator moveExceptionBlockIterator =
               moveExceptionBlock.listIterator(code);
           moveExceptionBlockIterator.setInsertionPosition(Position.syntheticNone());
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/PeepholeOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/PeepholeOptimizer.java
index 958749e..a8cd620 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/PeepholeOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/PeepholeOptimizer.java
@@ -242,7 +242,6 @@
       blocks.add(normalExit);
     }
     do {
-      int startNumberOfNewBlock = code.getHighestBlockNumber() + 1;
       Map<BasicBlock, BasicBlock> newBlocks = new IdentityHashMap<>();
       for (BasicBlock block : blocks) {
         InstructionEquivalence equivalence = new InstructionEquivalence(allocator);
@@ -294,10 +293,9 @@
           if (commonSuffixSize <= 1 || sizeDelta >= 0) {
             continue;
           }
-          int blockNumber = startNumberOfNewBlock + newBlocks.size();
           BasicBlock newBlock =
               createAndInsertBlockForSuffix(
-                  blockNumber,
+                  code.getNextBlockNumber(),
                   commonSuffixSize,
                   predsWithSameLastInstruction,
                   block == normalExit ? null : block,
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/ConstantRemovalTest.java b/src/test/java/com/android/tools/r8/ir/optimize/ConstantRemovalTest.java
index dc6bc19..c139dcf 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/ConstantRemovalTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/ConstantRemovalTest.java
@@ -70,8 +70,9 @@
     //
     // Then test that peephole optimization realizes that the last const number
     // is needed and the value 10 is *not* still in register 0 at that point.
+    final ValueNumberGenerator basicBlockNumberGenerator = new ValueNumberGenerator();
     BasicBlock block = new BasicBlock();
-    block.setNumber(0);
+    block.setNumber(basicBlockNumberGenerator.next());
 
     IRMetadata metadata = IRMetadata.unknown();
     Position position = Position.testingPosition();
@@ -141,6 +142,7 @@
             null,
             blocks,
             new ValueNumberGenerator(),
+            basicBlockNumberGenerator,
             IRMetadata.unknown(),
             Origin.unknown());
     PeepholeOptimizer.optimize(code, new MockLinearScanRegisterAllocator(appView, code));
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/TrivialGotoEliminationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/TrivialGotoEliminationTest.java
index 7d7785f..69394e0 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/TrivialGotoEliminationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/TrivialGotoEliminationTest.java
@@ -62,18 +62,20 @@
     //   throw v0
     // block2:
     //   return
+    final ValueNumberGenerator basicBlockNumberGenerator = new ValueNumberGenerator();
     Position position = Position.testingPosition();
     BasicBlock block2 = new BasicBlock();
-    block2.setNumber(2);
-    BasicBlock block0 = BasicBlock.createGotoBlock(0, position, metadata, block2);
+    BasicBlock block0 =
+        BasicBlock.createGotoBlock(basicBlockNumberGenerator.next(), position, metadata, block2);
+    BasicBlock block1 = new BasicBlock();
+    block1.setNumber(basicBlockNumberGenerator.next());
+    block2.setNumber(basicBlockNumberGenerator.next());
     block0.setFilledForTesting();
     block2.getMutablePredecessors().add(block0);
     Instruction ret = new Return();
     ret.setPosition(position);
     block2.add(ret, metadata);
     block2.setFilledForTesting();
-    BasicBlock block1 = new BasicBlock();
-    block1.setNumber(1);
     Value value = new Value(0, TypeElement.getInt(), null);
     Instruction number = new ConstNumber(value, 0);
     number.setPosition(position);
@@ -97,6 +99,7 @@
             null,
             blocks,
             new ValueNumberGenerator(),
+            basicBlockNumberGenerator,
             IRMetadata.unknown(),
             Origin.unknown());
     CodeRewriter.collapseTrivialGotos(code);
@@ -123,28 +126,30 @@
     //
     // block3:
     //   goto block3
+    final ValueNumberGenerator basicBlockNumberGenerator = new ValueNumberGenerator();
     Position position = Position.testingPosition();
+    BasicBlock block0 = new BasicBlock();
+    block0.setNumber(basicBlockNumberGenerator.next());
     BasicBlock block2 = new BasicBlock();
-    block2.setNumber(2);
+    BasicBlock block1 =
+        BasicBlock.createGotoBlock(basicBlockNumberGenerator.next(), position, metadata);
+    block2.setNumber(basicBlockNumberGenerator.next());
     Instruction ret = new Return();
     ret.setPosition(position);
     block2.add(ret, metadata);
     block2.setFilledForTesting();
 
     BasicBlock block3 = new BasicBlock();
-    block3.setNumber(3);
+    block3.setNumber(basicBlockNumberGenerator.next());
     Instruction instruction = new Goto();
     instruction.setPosition(position);
     block3.add(instruction, metadata);
     block3.setFilledForTesting();
     block3.getMutableSuccessors().add(block3);
 
-    BasicBlock block1 = BasicBlock.createGotoBlock(1, position, metadata);
     block1.getMutableSuccessors().add(block3);
     block1.setFilledForTesting();
 
-    BasicBlock block0 = new BasicBlock();
-    block0.setNumber(0);
     Value value =
         new Value(
             0,
@@ -181,6 +186,7 @@
             null,
             blocks,
             new ValueNumberGenerator(),
+            basicBlockNumberGenerator,
             IRMetadata.unknown(),
             Origin.unknown());
     CodeRewriter.collapseTrivialGotos(code);