blob: 86958a50b711c68aa9ed292bead3dfcac2385fdd [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 com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionListIterator;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
public class PeepholeLayout {
private List<List<Instruction>> instructions;
private final PeepholeExpression[] expressions;
private final boolean backwards;
private PeepholeLayout(boolean backwards, PeepholeExpression... expressions) {
this.instructions = new ArrayList<>(expressions.length);
for (int i = 0; i < expressions.length; i++) {
this.instructions.add(new ArrayList<>());
expressions[i].setIndex(i);
}
this.backwards = backwards;
this.expressions = expressions;
}
public static PeepholeLayout lookForward(PeepholeExpression... expressions) {
return new PeepholeLayout(false, expressions);
}
public static PeepholeLayout lookBackward(PeepholeExpression... expressions) {
return new PeepholeLayout(true, expressions);
}
public Match test(InstructionListIterator it) {
if (backwards) {
return testDirection(it::hasPrevious, it::previous, it::next);
} else {
return testDirection(it::hasNext, it::next, it::previous);
}
}
private Match testDirection(
Supplier<Boolean> hasNextInstruction,
Supplier<Instruction> nextInstruction,
Runnable resetOne) {
if (!hasNextInstruction.get()) {
return null;
}
boolean success = true;
Instruction current = nextInstruction.get();
int index;
for (index = 0; index < expressions.length; index++) {
PeepholeExpression e = expressions[index];
List<Instruction> expInstructions = instructions.get(index);
expInstructions.clear();
if (current != null) {
for (int i = 0; i < e.getMax(); i++) {
if (!e.getPredicate().test(current)) {
break;
}
expInstructions.add(current);
if (!hasNextInstruction.get()) {
current = null;
break;
}
current = nextInstruction.get();
}
}
success &= expInstructions.size() >= e.getMin() && expInstructions.size() <= e.getMax();
if (!success) {
break;
}
}
for (int i = 0; i < index; i++) {
for (int j = 0; j < instructions.get(i).size(); j++) {
resetOne.run();
}
}
if (current != null) {
resetOne.run();
}
return success ? new Match(expressions, instructions) : null;
}
}