blob: b533452a4047286156711c72448d359e5000acde [file] [log] [blame]
// Copyright (c) 2016, 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.code;
import static com.android.tools.r8.dex.Constants.U4BIT_MAX;
import static com.android.tools.r8.dex.Constants.U8BIT_MAX;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.utils.CfgPrinter;
import java.util.List;
public class If extends JumpInstruction {
public enum Type {
EQ, GE, GT, LE, LT, NE;
// Returns the comparison type if the operands are swapped.
public Type forSwappedOperands() {
switch (this) {
case EQ:
case NE:
return this;
case GE:
return Type.LE;
case GT:
return Type.LT;
case LE:
return Type.GE;
case LT:
return Type.GT;
default:
throw new Unreachable("Unknown if condition type.");
}
}
public Type inverted() {
switch (this) {
case EQ:
return Type.NE;
case GE:
return Type.LT;
case GT:
return Type.LE;
case LE:
return Type.GT;
case LT:
return Type.GE;
case NE:
return Type.EQ;
default:
throw new Unreachable("Unknown if condition type.");
}
}
}
private Type type;
public If(Type type, Value value) {
super(null, value);
this.type = type;
}
public If(Type type, List<Value> values) {
super(null, values);
this.type = type;
}
public boolean isZeroTest() {
return inValues.size() == 1;
}
public Type getType() {
return type;
}
public void invert() {
BasicBlock tmp = getTrueTarget();
setTrueTarget(fallthroughBlock());
setFallthroughBlock(tmp);
type = type.inverted();
}
public BasicBlock getTrueTarget() {
assert getBlock().exit() == this;
List<BasicBlock> successors = getBlock().getSuccessors();
assert successors.size() >= 2;
return successors.get(successors.size() - 2);
}
public void setTrueTarget(BasicBlock block) {
assert getBlock().exit() == this;
List<BasicBlock> successors = getBlock().getSuccessors();
assert successors.size() >= 2;
successors.set(successors.size() - 2, block);
}
@Override
public BasicBlock fallthroughBlock() {
assert getBlock().exit() == this;
List<BasicBlock> successors = getBlock().getSuccessors();
assert successors.size() >= 2;
return successors.get(successors.size() - 1);
}
@Override
public void setFallthroughBlock(BasicBlock block) {
List<BasicBlock> successors = getBlock().getSuccessors();
successors.set(successors.size() - 1, block);
}
@Override
public void buildDex(DexBuilder builder) {
builder.addIf(this);
}
@Override
public String toString() {
return super.toString() + " " + type + " block " + getTrueTarget().getNumber()
+ " (fallthrough " + fallthroughBlock().getNumber() + ")";
}
@Override
public int maxInValueRegister() {
return isZeroTest() ? U8BIT_MAX : U4BIT_MAX;
}
@Override
public int maxOutValueRegister() {
assert false : "If instructions define no values.";
return 0;
}
@Override
public void print(CfgPrinter printer) {
super.print(printer);
printer.append(" B").append(getTrueTarget().getNumber());
}
@Override
public boolean identicalNonValueParts(Instruction other) {
If o = other.asIf();
return o.getTrueTarget() == getTrueTarget()
&& o.fallthroughBlock() == fallthroughBlock()
&& o.type == type;
}
@Override
public int compareNonValueParts(Instruction other) {
assert other.isIf();
assert false : "Not supported";
return 0;
}
public BasicBlock targetFromCondition(int cond) {
switch (type) {
case EQ:
return cond == 0 ? getTrueTarget() : fallthroughBlock();
case NE:
return cond != 0 ? getTrueTarget() : fallthroughBlock();
case GE:
return cond >= 0 ? getTrueTarget() : fallthroughBlock();
case GT:
return cond > 0 ? getTrueTarget() : fallthroughBlock();
case LE:
return cond <= 0 ? getTrueTarget() : fallthroughBlock();
case LT:
return cond < 0 ? getTrueTarget() : fallthroughBlock();
}
throw new Unreachable("Unexpected condition type " + type);
}
@Override
public boolean isIf() {
return true;
}
@Override
public If asIf() {
return this;
}
}