blob: b196de9a8f3105495d4bd216b411e02fb495d6a0 [file] [log] [blame]
// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.optimize.peepholes;
import static com.android.tools.r8.utils.InternalOptions.TestingOptions.NO_LIMIT;
import static com.android.tools.r8.utils.PredicateUtils.not;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.LinearFlowInstructionListIterator;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.IteratorUtils;
import com.google.common.collect.ImmutableList;
import java.util.List;
import java.util.ListIterator;
public class BasicBlockMuncher {
private static List<BasicBlockPeephole> nonDestructivePeepholes() {
return ImmutableList.of(
new RemoveDebugPositionPeephole(), new MoveLoadUpPeephole(), new StoreLoadPeephole());
}
// The StoreLoadPeephole and StoreSequenceLoadPeephole are non-destructive but we would like it
// to run in a fix-point with the other peepholes to allow for more matches.
private static List<BasicBlockPeephole> destructivePeepholes() {
return ImmutableList.of(
new StoreSequenceLoadPeephole(),
new StoreLoadPeephole(),
new LoadLoadDupPeephole(),
new DupDupDupPeephole(),
new StoreLoadToDupStorePeephole());
}
public static void optimize(IRCode code, InternalOptions options) {
runPeepholes(code, nonDestructivePeepholes(), options);
runPeepholes(code, destructivePeepholes(), options);
}
private static void runPeepholes(
IRCode code, List<BasicBlockPeephole> peepholes, InternalOptions options) {
ListIterator<BasicBlock> blocksIterator = code.listIterator(code.blocks.size());
int iterations = 0;
while (blocksIterator.hasPrevious()) {
BasicBlock currentBlock = blocksIterator.previous();
LinearFlowInstructionListIterator it =
new LinearFlowInstructionListIterator(
code, currentBlock, currentBlock.getInstructions().size());
boolean matched = false;
while (true) {
for (BasicBlockPeephole peepHole : peepholes) {
boolean localMatch = peepHole.match(it);
if (localMatch && peepHole.resetAfterMatch()) {
it =
new LinearFlowInstructionListIterator(
code, currentBlock, currentBlock.getInstructions().size());
} else {
matched |= localMatch;
}
}
if (it.hasPrevious()) {
if (options.testing.basicBlockMuncherIterationLimit != NO_LIMIT) {
if (iterations > options.testing.basicBlockMuncherIterationLimit) {
throw new CompilationError("Too many iterations in BasicBlockMuncher");
}
iterations++;
}
it.previous();
} else if (matched) {
matched = false;
it =
new LinearFlowInstructionListIterator(
code, currentBlock, currentBlock.getInstructions().size());
} else {
// Move the iterator to the first block we have not seen.
if (IteratorUtils.previousUntilUnsafe(blocksIterator, not(it::hasVisitedBlock)) != null) {
// Ensure that we visit the first not visited block.
blocksIterator.next();
}
break;
}
}
}
}
}