blob: 99128d013d40507927fe267945f905a3923f1342 [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.DebugPosition;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.Position;
/**
* {@link RemoveDebugPositionPeephole} looks for the following two patterns:
*
* <pre>
* p: DebugPosition
* [q: Const]*
* q: Instr // TODO(b/166074600): This must currently be a Const.
* </pre>
*
* if p = q:
*
* <pre>
* [q: Const]*
* q: Instr
* </pre>
*
* if p != q and size([q: Const]*) > 0:
*
* <pre>
* [p: Const]*
* q: Instr
* </pre>
*
* This rewrite will eliminate debug positions that can be placed on a constant, retaining the line
* but avoiding the nop resulting in a remaining position instruction.
*/
public class RemoveDebugPositionPeephole implements BasicBlockPeephole {
private final Point debugPositionExp = new Point(Instruction::isDebugPosition);
private final Point secondInstructionExp =
new Point(
// TODO(b/166074600): It should be possible to match on any materializing instruction
// here. The phi-optimization seems to invalidate that by changing stack operations.
Instruction::isConstInstruction);
private final PeepholeLayout layout =
PeepholeLayout.lookForward(debugPositionExp, secondInstructionExp);
@Override
public boolean match(InstructionListIterator it) {
Match match = layout.test(it);
if (match == null) {
return false;
}
DebugPosition debugPosition = debugPositionExp.get(match).asDebugPosition();
Instruction secondInstruction = secondInstructionExp.get(match);
// If the position is the same on the following instruction it can simply be removed.
Position position = debugPosition.getPosition();
if (position.equals(secondInstruction.getPosition())) {
it.removeOrReplaceByDebugLocalRead();
return true;
}
boolean movedPosition = false;
it.next(); // skip debug position.
Instruction current = it.next(); // start loop at second instruction.
assert current == secondInstruction;
while (current.isConstInstruction() && it.hasNext()) {
Instruction next = it.next();
if (!next.getPosition().equals(current.getPosition())) {
break;
}
// The constant shares position with the next instruction so it subsumes the position of
// the debug position.
movedPosition = true;
current.forceOverwritePosition(position);
current = next;
}
it.previousUntil(i -> i == debugPosition);
if (movedPosition) {
it.next();
it.removeOrReplaceByDebugLocalRead();
return true;
}
return false;
}
@Override
public boolean resetAfterMatch() {
return false;
}
}