[LIR] Abstract encoding and decoding of values to distinguish phis.
This CL does not change the actual encoding or change the identification
of phis. It introduces most of the infrastructure to make the
identification possible independent of the base writer and
parser/iterator. Follow-up CLs will create a new strategy and amend the
builders to allow a separate value-table for phis.
Bug: b/225838009
Change-Id: I22fdb736a3e6c8d3bc4a249ec21d982b3ea2aea8
diff --git a/src/main/java/com/android/tools/r8/ir/code/Argument.java b/src/main/java/com/android/tools/r8/ir/code/Argument.java
index 587ef11..36dc37b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Argument.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Argument.java
@@ -177,7 +177,7 @@
}
@Override
- public void buildLir(LirBuilder<Value, BasicBlock> builder) {
+ public void buildLir(LirBuilder<Value, ?> builder) {
builder.addArgument(index, knownToBeBoolean);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java b/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java
index b3c3bbc..bd3b20a 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ArrayLength.java
@@ -154,7 +154,7 @@
}
@Override
- public void buildLir(LirBuilder<Value, BasicBlock> builder) {
+ public void buildLir(LirBuilder<Value, ?> builder) {
builder.addArrayLength(array());
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java b/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
index 04857de..cae2002 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
@@ -346,7 +346,7 @@
}
@Override
- public void buildLir(LirBuilder<Value, BasicBlock> builder) {
+ public void buildLir(LirBuilder<Value, ?> builder) {
builder.addConstNumber(outType(), value);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstString.java b/src/main/java/com/android/tools/r8/ir/code/ConstString.java
index b0b2bd2..e2ce753 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstString.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstString.java
@@ -182,7 +182,7 @@
}
@Override
- public void buildLir(LirBuilder<Value, BasicBlock> builder) {
+ public void buildLir(LirBuilder<Value, ?> builder) {
builder.addConstString(value);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/DebugLocalWrite.java b/src/main/java/com/android/tools/r8/ir/code/DebugLocalWrite.java
index 8c0eba5..9bb5f9a 100644
--- a/src/main/java/com/android/tools/r8/ir/code/DebugLocalWrite.java
+++ b/src/main/java/com/android/tools/r8/ir/code/DebugLocalWrite.java
@@ -90,7 +90,7 @@
}
@Override
- public void buildLir(LirBuilder<Value, BasicBlock> builder) {
+ public void buildLir(LirBuilder<Value, ?> builder) {
builder.addDebugLocalWrite(src());
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/DebugPosition.java b/src/main/java/com/android/tools/r8/ir/code/DebugPosition.java
index 361dd22..090040a 100644
--- a/src/main/java/com/android/tools/r8/ir/code/DebugPosition.java
+++ b/src/main/java/com/android/tools/r8/ir/code/DebugPosition.java
@@ -101,7 +101,7 @@
}
@Override
- public void buildLir(LirBuilder<Value, BasicBlock> builder) {
+ public void buildLir(LirBuilder<Value, ?> builder) {
builder.addDebugPosition(getPosition());
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Div.java b/src/main/java/com/android/tools/r8/ir/code/Div.java
index eac1fbf..a7e9822 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Div.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Div.java
@@ -151,7 +151,7 @@
}
@Override
- public void buildLir(LirBuilder<Value, BasicBlock> builder) {
+ public void buildLir(LirBuilder<Value, ?> builder) {
builder.addDiv(type, leftValue(), rightValue());
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Goto.java b/src/main/java/com/android/tools/r8/ir/code/Goto.java
index 886ca9a..96aeca3 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Goto.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Goto.java
@@ -128,7 +128,7 @@
}
@Override
- public void buildLir(LirBuilder<Value, BasicBlock> builder) {
+ public void buildLir(LirBuilder<Value, ?> builder) {
builder.addGoto(getTarget());
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/If.java b/src/main/java/com/android/tools/r8/ir/code/If.java
index a6a436e..08fc6a3 100644
--- a/src/main/java/com/android/tools/r8/ir/code/If.java
+++ b/src/main/java/com/android/tools/r8/ir/code/If.java
@@ -250,7 +250,7 @@
}
@Override
- public void buildLir(LirBuilder<Value, BasicBlock> builder) {
+ public void buildLir(LirBuilder<Value, ?> builder) {
ValueType ifType = inValues.get(0).outType();
if (inValues.size() == 1) {
builder.addIf(type, ifType, inValues.get(0), getTrueTarget());
diff --git a/src/main/java/com/android/tools/r8/ir/code/Instruction.java b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
index 8d7088f..7435bc7 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
@@ -1563,7 +1563,7 @@
return false;
}
- public void buildLir(LirBuilder<Value, BasicBlock> builder) {
+ public void buildLir(LirBuilder<Value, ?> builder) {
throw new Unimplemented("Missing impl for " + getClass().getSimpleName());
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java b/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
index e200a72..146f61a 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeDirect.java
@@ -218,7 +218,7 @@
}
@Override
- public void buildLir(LirBuilder<Value, BasicBlock> builder) {
+ public void buildLir(LirBuilder<Value, ?> builder) {
builder.addInvokeDirect(getInvokedMethod(), arguments());
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java b/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
index 8d77e02..cf04e98 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
@@ -204,7 +204,7 @@
}
@Override
- public void buildLir(LirBuilder<Value, BasicBlock> builder) {
+ public void buildLir(LirBuilder<Value, ?> builder) {
builder.addInvokeVirtual(getInvokedMethod(), arguments());
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/MoveException.java b/src/main/java/com/android/tools/r8/ir/code/MoveException.java
index 9cf1d30..ae9434b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/MoveException.java
+++ b/src/main/java/com/android/tools/r8/ir/code/MoveException.java
@@ -134,7 +134,7 @@
}
@Override
- public void buildLir(LirBuilder<Value, BasicBlock> builder) {
+ public void buildLir(LirBuilder<Value, ?> builder) {
builder.addMoveException(exceptionType);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Return.java b/src/main/java/com/android/tools/r8/ir/code/Return.java
index 1eb399b..7cd7505 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Return.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Return.java
@@ -153,7 +153,7 @@
}
@Override
- public void buildLir(LirBuilder<Value, BasicBlock> builder) {
+ public void buildLir(LirBuilder<Value, ?> builder) {
if (hasReturnValue()) {
builder.addReturn(returnValue());
} else {
diff --git a/src/main/java/com/android/tools/r8/ir/code/StaticGet.java b/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
index 4d767b0..6595fb2 100644
--- a/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
+++ b/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
@@ -300,7 +300,7 @@
}
@Override
- public void buildLir(LirBuilder<Value, BasicBlock> builder) {
+ public void buildLir(LirBuilder<Value, ?> builder) {
builder.addStaticGet(getField());
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index a15209c8..d13d3a4 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -23,6 +23,7 @@
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.StaticFieldValues;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringCollection;
import com.android.tools.r8.ir.desugar.CovariantReturnTypeAnnotationTransformer;
import com.android.tools.r8.ir.optimize.AssertionErrorTwoArgsConstructorRewriter;
@@ -63,6 +64,8 @@
import com.android.tools.r8.lightir.IR2LirConverter;
import com.android.tools.r8.lightir.Lir2IRConverter;
import com.android.tools.r8.lightir.LirCode;
+import com.android.tools.r8.lightir.LirStrategy;
+import com.android.tools.r8.lightir.LirStrategy.PhiInInstructionsStrategy;
import com.android.tools.r8.logging.Log;
import com.android.tools.r8.naming.IdentifierNameStringMarker;
import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagatorIROptimizer;
@@ -1102,11 +1105,15 @@
OptimizationFeedback feedback,
BytecodeMetadataProvider bytecodeMetadataProvider,
Timing timing) {
+ LirStrategy<Value, Integer> strategy = new PhiInInstructionsStrategy();
timing.begin("IR->LIR");
- LirCode lirCode = IR2LirConverter.translate(code, appView.dexItemFactory());
+ LirCode<Integer> lirCode =
+ IR2LirConverter.translate(code, strategy.getEncodingStrategy(), appView.dexItemFactory());
timing.end();
timing.begin("LIR->IR");
- IRCode irCode = Lir2IRConverter.translate(code.context(), lirCode, appView);
+ IRCode irCode =
+ Lir2IRConverter.translate(
+ code.context(), lirCode, strategy.getDecodingStrategy(lirCode), appView);
timing.end();
return irCode;
}
diff --git a/src/main/java/com/android/tools/r8/lightir/IR2LirConverter.java b/src/main/java/com/android/tools/r8/lightir/IR2LirConverter.java
index fbd5571..21af715 100644
--- a/src/main/java/com/android/tools/r8/lightir/IR2LirConverter.java
+++ b/src/main/java/com/android/tools/r8/lightir/IR2LirConverter.java
@@ -12,12 +12,9 @@
import com.android.tools.r8.ir.code.InstructionIterator;
import com.android.tools.r8.ir.code.Phi;
import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.lightir.LirBuilder.BlockIndexGetter;
import com.android.tools.r8.utils.ListUtils;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
-import it.unimi.dsi.fastutil.objects.Reference2IntMap;
-import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap;
import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap;
import java.util.ArrayList;
@@ -25,39 +22,40 @@
import java.util.Comparator;
import java.util.List;
-public class IR2LirConverter {
+public class IR2LirConverter<EV> {
private final DexItemFactory factory;
private final IRCode irCode;
- private final Reference2IntMap<BasicBlock> blocks = new Reference2IntOpenHashMap<>();
- private final Reference2IntMap<Value> values = new Reference2IntOpenHashMap<>();
- private final LirBuilder<Value, BasicBlock> builder;
+ private final LirEncodingStrategy<Value, EV> strategy;
+ private final LirBuilder<Value, EV> builder;
- private IR2LirConverter(DexItemFactory factory, IRCode irCode) {
+ private IR2LirConverter(
+ DexItemFactory factory, IRCode irCode, LirEncodingStrategy<Value, EV> strategy) {
this.factory = factory;
this.irCode = irCode;
+ this.strategy = strategy;
this.builder =
- new LirBuilder<Value, BasicBlock>(
- irCode.context().getReference(), values::getInt, blocks::getInt, factory)
+ new LirBuilder<>(irCode.context().getReference(), strategy, factory)
.setMetadata(irCode.metadata());
}
- public static LirCode translate(IRCode irCode, DexItemFactory factory) {
- return new IR2LirConverter(factory, irCode).internalTranslate();
+ public static <EV> LirCode<EV> translate(
+ IRCode irCode, LirEncodingStrategy<Value, EV> strategy, DexItemFactory factory) {
+ return new IR2LirConverter<>(factory, irCode, strategy).internalTranslate();
}
private void recordBlock(BasicBlock block, int blockIndex) {
- blocks.put(block, blockIndex);
+ strategy.defineBlock(block, blockIndex);
}
private void recordValue(Value value, int valueIndex) {
- values.put(value, valueIndex);
+ EV encodedValue = strategy.defineValue(value, valueIndex);
if (value.hasLocalInfo()) {
- builder.setDebugValue(value.getLocalInfo(), valueIndex);
+ builder.setDebugValue(value.getLocalInfo(), encodedValue);
}
}
- private LirCode internalTranslate() {
+ private LirCode<EV> internalTranslate() {
irCode.traceBlocks();
computeBlockAndValueTables();
computeInstructions();
@@ -74,7 +72,7 @@
if (block.hasPhis()) {
// The block order of the predecessors may change, since the LIR does not encode the
// direct links, the block order is used to determine predecessor order.
- int[] permutation = computePermutation(block.getPredecessors(), blocks::getInt);
+ int[] permutation = computePermutation(block.getPredecessors(), strategy::getBlockIndex);
Value[] operands = new Value[block.getPredecessors().size()];
for (Phi phi : block.getPhis()) {
permuteOperands(phi.getOperands(), permutation, operands);
@@ -85,16 +83,17 @@
if (block.hasCatchHandlers()) {
CatchHandlers<BasicBlock> handlers = block.getCatchHandlers();
builder.addTryCatchHanders(
- blocks.getInt(block),
+ strategy.getBlockIndex(block),
new CatchHandlers<>(
- handlers.getGuards(), ListUtils.map(handlers.getAllTargets(), blocks::getInt)));
+ handlers.getGuards(),
+ ListUtils.map(handlers.getAllTargets(), strategy::getBlockIndex)));
}
InstructionIterator it = block.iterator();
while (it.hasNext()) {
assert builder.verifyCurrentValueIndex(currentValueIndex);
Instruction instruction = it.next();
assert !instruction.hasOutValue()
- || currentValueIndex == values.getInt(instruction.outValue());
+ || strategy.verifyValueIndex(instruction.outValue(), currentValueIndex);
builder.setCurrentPosition(instruction.getPosition());
if (!instruction.getDebugValues().isEmpty()) {
builder.setDebugLocalEnds(currentValueIndex, instruction.getDebugValues());
@@ -144,8 +143,12 @@
}
}
+ private interface BlockIndexGetter {
+ int getBlockIndex(BasicBlock block);
+ }
+
private static int[] computePermutation(
- List<BasicBlock> originalPredecessors, BlockIndexGetter<BasicBlock> blockIndexGetter) {
+ List<BasicBlock> originalPredecessors, BlockIndexGetter blockIndexGetter) {
int predecessorCount = originalPredecessors.size();
// The final predecessor list is sorted by block order.
List<BasicBlock> sortedPredecessors = new ArrayList<>(originalPredecessors);
diff --git a/src/main/java/com/android/tools/r8/lightir/Lir2IRConverter.java b/src/main/java/com/android/tools/r8/lightir/Lir2IRConverter.java
index e7891b0..cc64c4e 100644
--- a/src/main/java/com/android/tools/r8/lightir/Lir2IRConverter.java
+++ b/src/main/java/com/android/tools/r8/lightir/Lir2IRConverter.java
@@ -31,7 +31,6 @@
import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.NumericType;
import com.android.tools.r8.ir.code.Phi;
-import com.android.tools.r8.ir.code.Phi.RegisterReadType;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.Position.SyntheticPosition;
import com.android.tools.r8.ir.code.Return;
@@ -52,8 +51,12 @@
private Lir2IRConverter() {}
- public static IRCode translate(ProgramMethod method, LirCode lirCode, AppView<?> appView) {
- Parser parser = new Parser(lirCode, method.getReference(), appView);
+ public static <EV> IRCode translate(
+ ProgramMethod method,
+ LirCode<EV> lirCode,
+ LirDecodingStrategy<Value, EV> strategy,
+ AppView<?> appView) {
+ Parser<EV> parser = new Parser<>(lirCode, method.getReference(), appView, strategy);
parser.parseArguments(method);
lirCode.forEach(view -> view.accept(parser));
return parser.getIRCode(method);
@@ -63,16 +66,16 @@
* When building IR the structured LIR parser is used to obtain the decoded operand indexes. The
* below parser subclass handles translation of indexes to SSA values.
*/
- private static class Parser extends LirParsedInstructionCallback {
+ private static class Parser<EV> extends LirParsedInstructionCallback<EV> {
private static final int ENTRY_BLOCK_INDEX = -1;
private final AppView<?> appView;
- private final LirCode code;
+ private final LirCode<EV> code;
+ private final LirDecodingStrategy<Value, EV> strategy;
private final NumberGenerator valueNumberGenerator = new NumberGenerator();
private final NumberGenerator basicBlockNumberGenerator = new NumberGenerator();
- private final Value[] values;
private final Int2ReferenceMap<BasicBlock> blocks = new Int2ReferenceOpenHashMap<>();
private BasicBlock currentBlock = null;
@@ -82,13 +85,17 @@
private PositionEntry nextPositionEntry = null;
private int nextIndexInPositionsTable = 0;
- public Parser(LirCode code, DexMethod method, AppView<?> appView) {
+ public Parser(
+ LirCode<EV> code,
+ DexMethod method,
+ AppView<?> appView,
+ LirDecodingStrategy<Value, EV> strategy) {
super(code);
assert code.getPositionTable().length > 0;
assert code.getPositionTable()[0].fromInstructionIndex == 0;
this.appView = appView;
this.code = code;
- values = new Value[code.getArgumentCount() + code.getInstructionCount()];
+ this.strategy = strategy;
// Recreate the preamble position. This is active for arguments and code with no positions.
currentPosition = SyntheticPosition.builder().setLine(0).setMethod(method).build();
}
@@ -184,19 +191,14 @@
});
}
- public Value getValue(int index) {
- Value value = values[index];
- if (value == null) {
- value = new Value(index, TypeElement.getBottom(), null);
- values[index] = value;
- }
- return value;
+ public Value getValue(EV encodedValue) {
+ return strategy.getValue(encodedValue);
}
- public List<Value> getValues(IntList indices) {
+ public List<Value> getValues(List<EV> indices) {
List<Value> arguments = new ArrayList<>(indices.size());
for (int i = 0; i < indices.size(); i++) {
- arguments.add(getValue(indices.getInt(i)));
+ arguments.add(getValue(indices.get(i)));
}
return arguments;
}
@@ -212,17 +214,7 @@
public Value getOutValueForNextInstruction(TypeElement type) {
int valueIndex = toInstructionIndexInIR(peekNextInstructionIndex());
DebugLocalInfo localInfo = code.getDebugLocalInfo(valueIndex);
- Value value = values[valueIndex];
- if (value == null) {
- value = new Value(valueIndex, type, localInfo);
- values[valueIndex] = value;
- } else {
- value.setType(type);
- if (localInfo != null) {
- value.setLocalInfo(localInfo);
- }
- }
- return value;
+ return strategy.getValueDefinitionForInstructionIndex(valueIndex, type, localInfo);
}
public Phi getPhiForNextInstructionAndAdvanceState(TypeElement type) {
@@ -233,17 +225,8 @@
// uniform with instructions.
advanceInstructionState();
// Creating the phi implicitly adds it to currentBlock.
- Phi phi = new Phi(valueIndex, currentBlock, type, localInfo, RegisterReadType.NORMAL);
- Value value = values[valueIndex];
- if (value != null) {
- // A fake ssa value has already been created, replace the users by the actual phi.
- // TODO(b/225838009): We could consider encoding the value type as a bit in the value index
- // and avoid the overhead of replacing users at phi-definition time.
- assert !value.isPhi();
- value.replaceUsers(phi);
- }
- values[valueIndex] = phi;
- return phi;
+ return strategy.getPhiDefinitionForInstructionIndex(
+ valueIndex, currentBlock, type, localInfo);
}
private void advanceInstructionState() {
@@ -261,7 +244,7 @@
int[] debugEndIndices = code.getDebugLocalEnds(index);
if (debugEndIndices != null) {
for (int encodedDebugEndIndex : debugEndIndices) {
- int debugEndIndex = code.decodeValueIndex(encodedDebugEndIndex, index);
+ EV debugEndIndex = code.decodeValueIndex(encodedDebugEndIndex, index);
Value debugValue = getValue(debugEndIndex);
debugValue.addDebugLocalEnd(instruction);
}
@@ -278,9 +261,7 @@
// which would otherwise advance the state.
TypeElement typeElement = type.toTypeElement(appView);
DebugLocalInfo localInfo = code.getDebugLocalInfo(index);
- Value dest = new Value(index, typeElement, localInfo);
- assert values[index] == null;
- values[index] = dest;
+ Value dest = strategy.getValueDefinitionForInstructionIndex(index, typeElement, localInfo);
Argument argument = new Argument(dest, index, type.isBooleanType());
assert currentBlock != null;
assert currentPosition.isSyntheticPosition();
@@ -303,7 +284,7 @@
}
@Override
- public void onDivInt(int leftValueIndex, int rightValueIndex) {
+ public void onDivInt(EV leftValueIndex, EV rightValueIndex) {
Value dest = getOutValueForNextInstruction(TypeElement.getInt());
addInstruction(
new Div(NumericType.INT, dest, getValue(leftValueIndex), getValue(rightValueIndex)));
@@ -316,7 +297,7 @@
}
@Override
- public void onIf(IfType ifKind, int blockIndex, int valueIndex) {
+ public void onIf(IfType ifKind, int blockIndex, EV valueIndex) {
BasicBlock targetBlock = getBasicBlock(blockIndex);
Value value = getValue(valueIndex);
addInstruction(new If(ifKind, value));
@@ -340,7 +321,7 @@
}
@Override
- public void onInvokeDirect(DexMethod target, IntList arguments) {
+ public void onInvokeDirect(DexMethod target, List<EV> arguments) {
// TODO(b/225838009): Maintain is-interface bit.
Value dest = getInvokeInstructionOutputValue(target);
List<Value> ssaArgumentValues = getValues(arguments);
@@ -349,7 +330,7 @@
}
@Override
- public void onInvokeVirtual(DexMethod target, IntList arguments) {
+ public void onInvokeVirtual(DexMethod target, List<EV> arguments) {
// TODO(b/225838009): Maintain is-interface bit.
Value dest = getInvokeInstructionOutputValue(target);
List<Value> ssaArgumentValues = getValues(arguments);
@@ -376,7 +357,7 @@
}
@Override
- public void onArrayLength(int arrayValueIndex) {
+ public void onArrayLength(EV arrayValueIndex) {
Value dest = getOutValueForNextInstruction(TypeElement.getInt());
Value arrayValue = getValue(arrayValueIndex);
addInstruction(new ArrayLength(dest, arrayValue));
@@ -388,11 +369,11 @@
}
@Override
- public void onPhi(DexType type, IntList operands) {
+ public void onPhi(DexType type, List<EV> operands) {
Phi phi = getPhiForNextInstructionAndAdvanceState(type.toTypeElement(appView));
List<Value> values = new ArrayList<>(operands.size());
for (int i = 0; i < operands.size(); i++) {
- values.add(getValue(operands.getInt(i)));
+ values.add(getValue(operands.get(i)));
}
phi.addOperands(values);
}
@@ -404,7 +385,7 @@
}
@Override
- public void onDebugLocalWrite(int srcIndex) {
+ public void onDebugLocalWrite(EV srcIndex) {
Value src = getValue(srcIndex);
// The type is in the local table, so initialize it with bottom and reset with the local info.
Value dest = getOutValueForNextInstruction(TypeElement.getBottom());
diff --git a/src/main/java/com/android/tools/r8/lightir/LirBuilder.java b/src/main/java/com/android/tools/r8/lightir/LirBuilder.java
index 992e754..0f78a4e 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirBuilder.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirBuilder.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.CatchHandlers;
import com.android.tools.r8.ir.code.IRMetadata;
import com.android.tools.r8.ir.code.IfType;
@@ -31,41 +32,25 @@
import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Set;
-/**
- * Builder for constructing LIR code from IR.
- *
- * @param <V> Type of SSA values. This is abstract to ensure that value internals are not used in
- * building.
- * @param <B> Type of basic blocks. This is abstract to ensure that basic block internals are not
- * used in building.
- */
-public class LirBuilder<V, B> {
-
- // Abstraction for the only accessible properties of an SSA value.
- public interface ValueIndexGetter<V> {
- int getValueIndex(V value);
- }
-
- // Abstraction for the only accessible properties of a basic block.
- public interface BlockIndexGetter<B> {
- int getBlockIndex(B block);
- }
+/** Builder for constructing LIR code from IR. */
+public class LirBuilder<V, EV> {
private final DexItemFactory factory;
private final ByteArrayWriter byteWriter = new ByteArrayWriter();
private final LirWriter writer = new LirWriter(byteWriter);
private final Reference2IntMap<DexItem> constants;
- private final ValueIndexGetter<V> valueIndexGetter;
- private final BlockIndexGetter<B> blockIndexGetter;
private final List<PositionEntry> positionTable;
private int argumentCount = 0;
private int instructionCount = 0;
private IRMetadata metadata = null;
- private final LirSsaValueStrategy ssaValueStrategy = LirSsaValueStrategy.get();
+
+ private final LirEncodingStrategy<V, EV> strategy;
private Position currentPosition;
private Position flushedPosition;
@@ -74,7 +59,7 @@
new Int2ReferenceOpenHashMap<>();
// Mapping from SSA value definition to the local name index in the constant pool.
- private final Int2ReferenceMap<DebugLocalInfo> debugLocals = new Int2ReferenceOpenHashMap<>();
+ private final Map<EV, DebugLocalInfo> debugLocals = new HashMap<>();
// Mapping from instruction to the end usage of SSA values with debug local info.
private final Int2ReferenceMap<int[]> debugLocalEnds = new Int2ReferenceOpenHashMap<>();
@@ -83,16 +68,11 @@
private static final int MAX_VALUE_COUNT = 10;
private int[] valueIndexBuffer = new int[MAX_VALUE_COUNT];
- public LirBuilder(
- DexMethod method,
- ValueIndexGetter<V> valueIndexGetter,
- BlockIndexGetter<B> blockIndexGetter,
- DexItemFactory factory) {
+ public LirBuilder(DexMethod method, LirEncodingStrategy<V, EV> strategy, DexItemFactory factory) {
this.factory = factory;
constants = new Reference2IntOpenHashMap<>();
positionTable = new ArrayList<>();
- this.valueIndexGetter = valueIndexGetter;
- this.blockIndexGetter = blockIndexGetter;
+ this.strategy = strategy;
currentPosition = SyntheticPosition.builder().setLine(0).setMethod(method).build();
flushedPosition = currentPosition;
}
@@ -116,7 +96,7 @@
tryCatchRanges.put(blockIndex, handlers);
}
- public LirBuilder<V, B> setCurrentPosition(Position position) {
+ public LirBuilder<V, EV> setCurrentPosition(Position position) {
assert position != null;
assert position != Position.none();
currentPosition = position;
@@ -145,24 +125,33 @@
ByteUtils.writeEncodedInt(index, writer::writeOperand);
}
- private int getValueIndex(V value) {
- return valueIndexGetter.getValueIndex(value);
+ private EV getEncodedValue(V value) {
+ return strategy.getEncodedValue(value);
}
- private int valueIndexSize(int valueIndex, int referencingInstructionIndex) {
+ private int getEncodedValueIndex(EV value, int referencingInstructionIndex) {
int referencingValueIndex = referencingInstructionIndex + argumentCount;
- int encodedValueIndex = ssaValueStrategy.encodeValueIndex(valueIndex, referencingValueIndex);
+ return strategy.getEncodedValueIndexForReference(value, referencingValueIndex);
+ }
+
+ private int valueIndexSize(EV value, int referencingInstructionIndex) {
+ return encodedValueIndexSize(getEncodedValueIndex(value, referencingInstructionIndex));
+ }
+
+ private int encodedValueIndexSize(int encodedValueIndex) {
return ByteUtils.intEncodingSize(encodedValueIndex);
}
- private void writeValueIndex(int valueIndex, int referencingInstructionIndex) {
- int referencingValueIndex = referencingInstructionIndex + argumentCount;
- int encodedValueIndex = ssaValueStrategy.encodeValueIndex(valueIndex, referencingValueIndex);
+ private void writeValueIndex(EV value, int referencingInstructionIndex) {
+ writeEncodedValueIndex(getEncodedValueIndex(value, referencingInstructionIndex));
+ }
+
+ private void writeEncodedValueIndex(int encodedValueIndex) {
ByteUtils.writeEncodedInt(encodedValueIndex, writer::writeOperand);
}
- private int getBlockIndex(B block) {
- return blockIndexGetter.getBlockIndex(block);
+ private int getBlockIndex(BasicBlock block) {
+ return strategy.getBlockIndex(block);
}
private int blockIndexSize(int index) {
@@ -173,31 +162,31 @@
ByteUtils.writeEncodedInt(index, writer::writeOperand);
}
- public LirBuilder<V, B> setMetadata(IRMetadata metadata) {
+ public LirBuilder<V, EV> setMetadata(IRMetadata metadata) {
this.metadata = metadata;
return this;
}
- public LirBuilder<V, B> setDebugValue(DebugLocalInfo debugInfo, int valueIndex) {
+ public LirBuilder<V, EV> setDebugValue(DebugLocalInfo debugInfo, EV valueIndex) {
DebugLocalInfo old = debugLocals.put(valueIndex, debugInfo);
assert old == null;
return this;
}
- public LirBuilder<V, B> setDebugLocalEnds(int instructionValueIndex, Set<V> endValues) {
+ public LirBuilder<V, EV> setDebugLocalEnds(int instructionValueIndex, Set<V> endValues) {
int size = endValues.size();
int[] indices = new int[size];
Iterator<V> iterator = endValues.iterator();
for (int i = 0; i < size; i++) {
- int valueIndex = getValueIndex(iterator.next());
- int encodedValueIndex = ssaValueStrategy.encodeValueIndex(valueIndex, instructionValueIndex);
- indices[i] = encodedValueIndex;
+ EV value = getEncodedValue(iterator.next());
+ // The index is already the value index (it has been offset by argument count).
+ indices[i] = strategy.getEncodedValueIndexForReference(value, instructionValueIndex);
}
debugLocalEnds.put(instructionValueIndex, indices);
return this;
}
- public LirBuilder<V, B> addArgument(int index, boolean knownToBeBoolean) {
+ public LirBuilder<V, EV> addArgument(int index, boolean knownToBeBoolean) {
// Arguments are implicitly given by method descriptor and not an actual instruction.
assert argumentCount == index;
argumentCount++;
@@ -212,22 +201,23 @@
return instructionCount++;
}
- private LirBuilder<V, B> addNoOperandInstruction(int opcode) {
+ private LirBuilder<V, EV> addNoOperandInstruction(int opcode) {
advanceInstructionState();
writer.writeOneByteInstruction(opcode);
return this;
}
- private LirBuilder<V, B> addOneItemInstruction(int opcode, DexItem item) {
+ private LirBuilder<V, EV> addOneItemInstruction(int opcode, DexItem item) {
return addInstructionTemplate(opcode, Collections.singletonList(item), Collections.emptyList());
}
- private LirBuilder<V, B> addOneValueInstruction(int opcode, V value) {
+ private LirBuilder<V, EV> addOneValueInstruction(int opcode, V value) {
return addInstructionTemplate(
opcode, Collections.emptyList(), Collections.singletonList(value));
}
- private LirBuilder<V, B> addInstructionTemplate(int opcode, List<DexItem> items, List<V> values) {
+ private LirBuilder<V, EV> addInstructionTemplate(
+ int opcode, List<DexItem> items, List<V> values) {
assert values.size() < MAX_VALUE_COUNT;
int instructionIndex = advanceInstructionState();
int operandSize = 0;
@@ -235,26 +225,26 @@
operandSize += constantIndexSize(item);
}
for (int i = 0; i < values.size(); i++) {
- V value = values.get(i);
- int valueIndex = getValueIndex(value);
- operandSize += valueIndexSize(valueIndex, instructionIndex);
- valueIndexBuffer[i] = valueIndex;
+ EV value = getEncodedValue(values.get(i));
+ int encodedValueIndex = getEncodedValueIndex(value, instructionIndex);
+ operandSize += encodedValueIndexSize(encodedValueIndex);
+ valueIndexBuffer[i] = encodedValueIndex;
}
writer.writeInstruction(opcode, operandSize);
for (DexItem item : items) {
writeConstantIndex(item);
}
for (int i = 0; i < values.size(); i++) {
- writeValueIndex(valueIndexBuffer[i], instructionIndex);
+ writeEncodedValueIndex(valueIndexBuffer[i]);
}
return this;
}
- public LirBuilder<V, B> addConstNull() {
+ public LirBuilder<V, EV> addConstNull() {
return addNoOperandInstruction(LirOpcodes.ACONST_NULL);
}
- public LirBuilder<V, B> addConstInt(int value) {
+ public LirBuilder<V, EV> addConstInt(int value) {
if (-1 <= value && value <= 5) {
addNoOperandInstruction(LirOpcodes.ICONST_0 + value);
} else {
@@ -265,7 +255,7 @@
return this;
}
- public LirBuilder<V, B> addConstNumber(ValueType type, long value) {
+ public LirBuilder<V, EV> addConstNumber(ValueType type, long value) {
switch (type) {
case OBJECT:
return addConstNull();
@@ -279,11 +269,11 @@
}
}
- public LirBuilder<V, B> addConstString(DexString string) {
+ public LirBuilder<V, EV> addConstString(DexString string) {
return addOneItemInstruction(LirOpcodes.LDC, string);
}
- public LirBuilder<V, B> addDiv(NumericType type, V leftValue, V rightValue) {
+ public LirBuilder<V, EV> addDiv(NumericType type, V leftValue, V rightValue) {
switch (type) {
case BYTE:
case CHAR:
@@ -301,35 +291,35 @@
}
}
- public LirBuilder<V, B> addArrayLength(V array) {
+ public LirBuilder<V, EV> addArrayLength(V array) {
return addOneValueInstruction(LirOpcodes.ARRAYLENGTH, array);
}
- public LirBuilder<V, B> addStaticGet(DexField field) {
+ public LirBuilder<V, EV> addStaticGet(DexField field) {
return addOneItemInstruction(LirOpcodes.GETSTATIC, field);
}
- public LirBuilder<V, B> addInvokeInstruction(int opcode, DexMethod method, List<V> arguments) {
+ public LirBuilder<V, EV> addInvokeInstruction(int opcode, DexMethod method, List<V> arguments) {
return addInstructionTemplate(opcode, Collections.singletonList(method), arguments);
}
- public LirBuilder<V, B> addInvokeDirect(DexMethod method, List<V> arguments) {
+ public LirBuilder<V, EV> addInvokeDirect(DexMethod method, List<V> arguments) {
return addInvokeInstruction(LirOpcodes.INVOKEDIRECT, method, arguments);
}
- public LirBuilder<V, B> addInvokeVirtual(DexMethod method, List<V> arguments) {
+ public LirBuilder<V, EV> addInvokeVirtual(DexMethod method, List<V> arguments) {
return addInvokeInstruction(LirOpcodes.INVOKEVIRTUAL, method, arguments);
}
- public LirBuilder<V, B> addReturn(V value) {
+ public LirBuilder<V, EV> addReturn(V value) {
throw new Unimplemented();
}
- public LirBuilder<V, B> addReturnVoid() {
+ public LirBuilder<V, EV> addReturnVoid() {
return addNoOperandInstruction(LirOpcodes.RETURN);
}
- public LirBuilder<V, B> addDebugPosition(Position position) {
+ public LirBuilder<V, EV> addDebugPosition(Position position) {
assert currentPosition == position;
return addNoOperandInstruction(LirOpcodes.DEBUGPOS);
}
@@ -338,7 +328,7 @@
addNoOperandInstruction(LirOpcodes.FALLTHROUGH);
}
- public LirBuilder<V, B> addGoto(B target) {
+ public LirBuilder<V, EV> addGoto(BasicBlock target) {
int targetIndex = getBlockIndex(target);
int operandSize = blockIndexSize(targetIndex);
advanceInstructionState();
@@ -347,7 +337,8 @@
return this;
}
- public LirBuilder<V, B> addIf(IfType ifKind, ValueType valueType, V value, B trueTarget) {
+ public LirBuilder<V, EV> addIf(
+ IfType ifKind, ValueType valueType, V value, BasicBlock trueTarget) {
int opcode;
switch (ifKind) {
case EQ:
@@ -371,18 +362,18 @@
default:
throw new Unreachable("Unexpected if kind: " + ifKind);
}
- int targetIndex = getBlockIndex(trueTarget);
- int valueIndex = getValueIndex(value);
- int operandSize = blockIndexSize(targetIndex) + valueIndexSize(valueIndex, instructionCount);
int instructionIndex = advanceInstructionState();
+ int targetIndex = getBlockIndex(trueTarget);
+ int valueIndex = getEncodedValueIndex(getEncodedValue(value), instructionIndex);
+ int operandSize = blockIndexSize(targetIndex) + encodedValueIndexSize(valueIndex);
writer.writeInstruction(opcode, operandSize);
writeBlockIndex(targetIndex);
- writeValueIndex(valueIndex, instructionIndex);
+ writeEncodedValueIndex(valueIndex);
return this;
}
- public LirBuilder<V, B> addIfCmp(
- IfType ifKind, ValueType valueType, List<V> inValues, B trueTarget) {
+ public LirBuilder<V, EV> addIfCmp(
+ IfType ifKind, ValueType valueType, List<V> inValues, BasicBlock trueTarget) {
int opcode;
switch (ifKind) {
case EQ:
@@ -408,40 +399,40 @@
}
int instructionIndex = advanceInstructionState();
int targetIndex = getBlockIndex(trueTarget);
- int valueOneIndex = getValueIndex(inValues.get(0));
- int valueTwoIndex = getValueIndex(inValues.get(1));
+ int valueOneIndex = getEncodedValueIndex(getEncodedValue(inValues.get(0)), instructionIndex);
+ int valueTwoIndex = getEncodedValueIndex(getEncodedValue(inValues.get(1)), instructionIndex);
int operandSize =
blockIndexSize(targetIndex)
- + valueIndexSize(valueOneIndex, instructionIndex)
- + valueIndexSize(valueTwoIndex, instructionIndex);
+ + encodedValueIndexSize(valueOneIndex)
+ + encodedValueIndexSize(valueTwoIndex);
writer.writeInstruction(opcode, operandSize);
writeBlockIndex(targetIndex);
- writeValueIndex(valueOneIndex, instructionIndex);
- writeValueIndex(valueTwoIndex, instructionIndex);
+ writeEncodedValueIndex(valueOneIndex);
+ writeEncodedValueIndex(valueTwoIndex);
return this;
}
- public LirBuilder<V, B> addMoveException(DexType exceptionType) {
+ public LirBuilder<V, EV> addMoveException(DexType exceptionType) {
return addOneItemInstruction(LirOpcodes.MOVEEXCEPTION, exceptionType);
}
- public LirBuilder<V, B> addPhi(TypeElement type, List<V> operands) {
+ public LirBuilder<V, EV> addPhi(TypeElement type, List<V> operands) {
DexType dexType = toDexType(type);
return addInstructionTemplate(LirOpcodes.PHI, Collections.singletonList(dexType), operands);
}
- public LirBuilder<V, B> addDebugLocalWrite(V src) {
+ public LirBuilder<V, EV> addDebugLocalWrite(V src) {
return addOneValueInstruction(LirOpcodes.DEBUGLOCALWRITE, src);
}
- public LirCode build() {
+ public LirCode<EV> build() {
assert metadata != null;
int constantsCount = constants.size();
DexItem[] constantTable = new DexItem[constantsCount];
constants.forEach((item, index) -> constantTable[index] = item);
- DebugLocalInfoTable debugTable =
- debugLocals.isEmpty() ? null : new DebugLocalInfoTable(debugLocals, debugLocalEnds);
- return new LirCode(
+ DebugLocalInfoTable<EV> debugTable =
+ debugLocals.isEmpty() ? null : new DebugLocalInfoTable<>(debugLocals, debugLocalEnds);
+ return new LirCode<>(
metadata,
constantTable,
positionTable.toArray(new PositionEntry[positionTable.size()]),
@@ -450,6 +441,6 @@
instructionCount,
new TryCatchTable(tryCatchRanges),
debugTable,
- ssaValueStrategy);
+ strategy.getSsaValueStrategy());
}
}
diff --git a/src/main/java/com/android/tools/r8/lightir/LirCode.java b/src/main/java/com/android/tools/r8/lightir/LirCode.java
index 3851ba5..f62d9f6 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirCode.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirCode.java
@@ -10,11 +10,10 @@
import com.android.tools.r8.ir.code.CatchHandlers;
import com.android.tools.r8.ir.code.IRMetadata;
import com.android.tools.r8.ir.code.Position;
-import com.android.tools.r8.lightir.LirBuilder.BlockIndexGetter;
-import com.android.tools.r8.lightir.LirBuilder.ValueIndexGetter;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
+import java.util.Map;
-public class LirCode implements Iterable<LirInstructionView> {
+public class LirCode<EV> implements Iterable<LirInstructionView> {
public static class PositionEntry {
final int fromInstructionIndex;
@@ -38,13 +37,12 @@
}
}
- public static class DebugLocalInfoTable {
- private final Int2ReferenceMap<DebugLocalInfo> valueToLocalMap;
+ public static class DebugLocalInfoTable<EV> {
+ private final Map<EV, DebugLocalInfo> valueToLocalMap;
private final Int2ReferenceMap<int[]> instructionToEndUseMap;
public DebugLocalInfoTable(
- Int2ReferenceMap<DebugLocalInfo> valueToLocalMap,
- Int2ReferenceMap<int[]> instructionToEndUseMap) {
+ Map<EV, DebugLocalInfo> valueToLocalMap, Int2ReferenceMap<int[]> instructionToEndUseMap) {
assert !valueToLocalMap.isEmpty();
assert !instructionToEndUseMap.isEmpty();
this.valueToLocalMap = valueToLocalMap;
@@ -52,7 +50,7 @@
}
}
- private final LirSsaValueStrategy ssaValueStrategy;
+ private final LirSsaValueStrategy<EV> ssaValueStrategy;
private final IRMetadata metadata;
@@ -74,14 +72,11 @@
private final TryCatchTable tryCatchTable;
/** Table of debug local information for each SSA value (if present). */
- private final DebugLocalInfoTable debugLocalInfoTable;
+ private final DebugLocalInfoTable<EV> debugLocalInfoTable;
- public static <V, B> LirBuilder<V, B> builder(
- DexMethod method,
- ValueIndexGetter<V> valueIndexGetter,
- BlockIndexGetter<B> blockIndexGetter,
- DexItemFactory factory) {
- return new LirBuilder<V, B>(method, valueIndexGetter, blockIndexGetter, factory);
+ public static <V, EV> LirBuilder<V, EV> builder(
+ DexMethod method, LirEncodingStrategy<V, EV> strategy, DexItemFactory factory) {
+ return new LirBuilder<>(method, strategy, factory);
}
/** Should be constructed using {@link LirBuilder}. */
@@ -93,8 +88,8 @@
byte[] instructions,
int instructionCount,
TryCatchTable tryCatchTable,
- DebugLocalInfoTable debugLocalInfoTable,
- LirSsaValueStrategy ssaValueStrategy) {
+ DebugLocalInfoTable<EV> debugLocalInfoTable,
+ LirSsaValueStrategy<EV> ssaValueStrategy) {
this.metadata = metadata;
this.constants = constants;
this.positionTable = positions;
@@ -106,7 +101,7 @@
this.ssaValueStrategy = ssaValueStrategy;
}
- public int decodeValueIndex(int encodedValueIndex, int currentValueIndex) {
+ public EV decodeValueIndex(int encodedValueIndex, int currentValueIndex) {
return ssaValueStrategy.decodeValueIndex(encodedValueIndex, currentValueIndex);
}
@@ -138,7 +133,7 @@
return tryCatchTable;
}
- public DebugLocalInfoTable getDebugLocalInfoTable() {
+ public DebugLocalInfoTable<EV> getDebugLocalInfoTable() {
return debugLocalInfoTable;
}
@@ -159,6 +154,6 @@
@Override
public String toString() {
- return new LirPrinter(this).prettyPrint();
+ return new LirPrinter<>(this).prettyPrint();
}
}
diff --git a/src/main/java/com/android/tools/r8/lightir/LirDecodingStrategy.java b/src/main/java/com/android/tools/r8/lightir/LirDecodingStrategy.java
new file mode 100644
index 0000000..1e25e3c
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/lightir/LirDecodingStrategy.java
@@ -0,0 +1,21 @@
+// Copyright (c) 2023, 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.lightir;
+
+import com.android.tools.r8.graph.DebugLocalInfo;
+import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.Phi;
+
+/** Abstraction for how to decode SSA values (and basic blocks) when reading LIR. */
+public abstract class LirDecodingStrategy<V, EV> {
+
+ public abstract V getValue(EV encodedValue);
+
+ public abstract V getValueDefinitionForInstructionIndex(
+ int instructionIndex, TypeElement type, DebugLocalInfo localInfo);
+
+ public abstract Phi getPhiDefinitionForInstructionIndex(
+ int instructionIndex, BasicBlock block, TypeElement type, DebugLocalInfo localInfo);
+}
diff --git a/src/main/java/com/android/tools/r8/lightir/LirEncodingStrategy.java b/src/main/java/com/android/tools/r8/lightir/LirEncodingStrategy.java
new file mode 100644
index 0000000..8bbba90
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/lightir/LirEncodingStrategy.java
@@ -0,0 +1,26 @@
+// Copyright (c) 2023, 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.lightir;
+
+import com.android.tools.r8.ir.code.BasicBlock;
+
+/** Abstraction for how to encode SSA values (and basic blocks) when building LIR. */
+public abstract class LirEncodingStrategy<V, EV> {
+
+ public abstract void defineBlock(BasicBlock block, int index);
+
+ public abstract int getBlockIndex(BasicBlock block);
+
+ public abstract EV defineValue(V value, int index);
+
+ public abstract boolean verifyValueIndex(V value, int expectedIndex);
+
+ public abstract EV getEncodedValue(V value);
+
+ public int getEncodedValueIndexForReference(EV encodedValue, int referencingValueIndex) {
+ return getSsaValueStrategy().encodeValueIndex(encodedValue, referencingValueIndex);
+ }
+
+ public abstract LirSsaValueStrategy<EV> getSsaValueStrategy();
+}
diff --git a/src/main/java/com/android/tools/r8/lightir/LirParsedInstructionCallback.java b/src/main/java/com/android/tools/r8/lightir/LirParsedInstructionCallback.java
index 5b72543..ed94301 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirParsedInstructionCallback.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirParsedInstructionCallback.java
@@ -11,8 +11,8 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.code.IfType;
import com.android.tools.r8.ir.code.NumericType;
-import it.unimi.dsi.fastutil.ints.IntArrayList;
-import it.unimi.dsi.fastutil.ints.IntList;
+import java.util.ArrayList;
+import java.util.List;
/**
* Structured callbacks for interpreting LIR.
@@ -25,11 +25,11 @@
* <p>Due to the parsing of the individual instructions, this parser has a higher overhead than
* using the basic {@link LirInstructionView}.
*/
-public abstract class LirParsedInstructionCallback implements LirInstructionCallback {
+public abstract class LirParsedInstructionCallback<EV> implements LirInstructionCallback {
- private final LirCode code;
+ private final LirCode<EV> code;
- public LirParsedInstructionCallback(LirCode code) {
+ public LirParsedInstructionCallback(LirCode<EV> code) {
this.code = code;
}
@@ -40,11 +40,11 @@
return getCurrentValueIndex() - code.getArgumentCount();
}
- private int getActualValueIndex(int relativeValueIndex) {
+ private EV getActualValueIndex(int relativeValueIndex) {
return code.decodeValueIndex(relativeValueIndex, getCurrentValueIndex());
}
- private int getNextValueOperand(LirInstructionView view) {
+ private EV getNextValueOperand(LirInstructionView view) {
return getActualValueIndex(view.getNextValueOperand());
}
@@ -66,15 +66,15 @@
onInstruction();
}
- public void onDiv(NumericType type, int leftValueIndex, int rightValueIndex) {
+ public void onDiv(NumericType type, EV leftValueIndex, EV rightValueIndex) {
onInstruction();
}
- public void onDivInt(int leftValueIndex, int rightValueIndex) {
+ public void onDivInt(EV leftValueIndex, EV rightValueIndex) {
onDiv(NumericType.INT, leftValueIndex, rightValueIndex);
}
- public void onIf(IfType ifKind, int blockIndex, int valueIndex) {
+ public void onIf(IfType ifKind, int blockIndex, EV valueIndex) {
onInstruction();
}
@@ -90,19 +90,19 @@
onInstruction();
}
- public void onDebugLocalWrite(int srcIndex) {
+ public void onDebugLocalWrite(EV srcIndex) {
onInstruction();
}
- public void onInvokeMethodInstruction(DexMethod method, IntList arguments) {
+ public void onInvokeMethodInstruction(DexMethod method, List<EV> arguments) {
onInstruction();
}
- public void onInvokeDirect(DexMethod method, IntList arguments) {
+ public void onInvokeDirect(DexMethod method, List<EV> arguments) {
onInvokeMethodInstruction(method, arguments);
}
- public void onInvokeVirtual(DexMethod method, IntList arguments) {
+ public void onInvokeVirtual(DexMethod method, List<EV> arguments) {
onInvokeMethodInstruction(method, arguments);
}
@@ -118,7 +118,7 @@
onInstruction();
}
- public void onArrayLength(int arrayValueIndex) {
+ public void onArrayLength(EV arrayValueIndex) {
onInstruction();
}
@@ -126,7 +126,7 @@
onInstruction();
}
- public void onPhi(DexType type, IntList operands) {
+ public void onPhi(DexType type, List<EV> operands) {
onInstruction();
}
@@ -172,15 +172,15 @@
}
case LirOpcodes.IDIV:
{
- int leftValueIndex = getNextValueOperand(view);
- int rightValueIndex = getNextValueOperand(view);
+ EV leftValueIndex = getNextValueOperand(view);
+ EV rightValueIndex = getNextValueOperand(view);
onDivInt(leftValueIndex, rightValueIndex);
return;
}
case LirOpcodes.IFNE:
{
int blockIndex = view.getNextBlockOperand();
- int valueIndex = getNextValueOperand(view);
+ EV valueIndex = getNextValueOperand(view);
onIf(IfType.NE, blockIndex, valueIndex);
return;
}
@@ -193,14 +193,14 @@
case LirOpcodes.INVOKEDIRECT:
{
DexMethod target = getInvokeInstructionTarget(view);
- IntList arguments = getInvokeInstructionArguments(view);
+ List<EV> arguments = getInvokeInstructionArguments(view);
onInvokeDirect(target, arguments);
return;
}
case LirOpcodes.INVOKEVIRTUAL:
{
DexMethod target = getInvokeInstructionTarget(view);
- IntList arguments = getInvokeInstructionArguments(view);
+ List<EV> arguments = getInvokeInstructionArguments(view);
onInvokeVirtual(target, arguments);
return;
}
@@ -228,7 +228,7 @@
case LirOpcodes.PHI:
{
DexType type = (DexType) getConstantItem(view.getNextConstantOperand());
- IntList operands = new IntArrayList();
+ List<EV> operands = new ArrayList<>();
while (view.hasMoreOperands()) {
operands.add(getNextValueOperand(view));
}
@@ -248,7 +248,7 @@
}
case LirOpcodes.DEBUGLOCALWRITE:
{
- int srcIndex = getNextValueOperand(view);
+ EV srcIndex = getNextValueOperand(view);
onDebugLocalWrite(srcIndex);
return;
}
@@ -261,8 +261,8 @@
return (DexMethod) getConstantItem(view.getNextConstantOperand());
}
- private IntList getInvokeInstructionArguments(LirInstructionView view) {
- IntList arguments = new IntArrayList();
+ private List<EV> getInvokeInstructionArguments(LirInstructionView view) {
+ List<EV> arguments = new ArrayList<>();
while (view.hasMoreOperands()) {
arguments.add(getNextValueOperand(view));
}
diff --git a/src/main/java/com/android/tools/r8/lightir/LirPrinter.java b/src/main/java/com/android/tools/r8/lightir/LirPrinter.java
index 4e6e2d6..20dfc30 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirPrinter.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirPrinter.java
@@ -11,12 +11,12 @@
import com.android.tools.r8.ir.code.IfType;
import com.android.tools.r8.ir.code.NumericType;
import com.android.tools.r8.utils.StringUtils;
-import it.unimi.dsi.fastutil.ints.IntList;
+import java.util.List;
-public class LirPrinter extends LirParsedInstructionCallback {
+public class LirPrinter<EV> extends LirParsedInstructionCallback<EV> {
private static final String SEPERATOR = "\n";
- private final LirCode code;
+ private final LirCode<EV> code;
private final StringBuilder builder = new StringBuilder();
private final int instructionIndexPadding;
@@ -25,7 +25,7 @@
private int valueIndex = 0;
private LirInstructionView view;
- public LirPrinter(LirCode code) {
+ public LirPrinter(LirCode<EV> code) {
super(code);
this.code = code;
instructionIndexPadding =
@@ -52,13 +52,17 @@
return "v" + valueIndex;
}
+ private String fmtValueIndex(EV valueIndex) {
+ return "v" + valueIndex;
+ }
+
private String fmtInsnIndex(int instructionIndex) {
return instructionIndex < 0 ? "--" : ("" + instructionIndex);
}
- private void appendValueArguments(IntList arguments) {
+ private void appendValueArguments(List<EV> arguments) {
for (int i = 0; i < arguments.size(); i++) {
- builder.append(fmtValueIndex(arguments.getInt(i))).append(' ');
+ builder.append(fmtValueIndex(arguments.get(i))).append(' ');
}
}
@@ -124,7 +128,7 @@
}
@Override
- public void onDiv(NumericType type, int leftValueIndex, int rightValueIndex) {
+ public void onDiv(NumericType type, EV leftValueIndex, EV rightValueIndex) {
appendOutValue()
.append(fmtValueIndex(leftValueIndex))
.append(' ')
@@ -134,7 +138,7 @@
}
@Override
- public void onIf(IfType ifKind, int blockIndex, int valueIndex) {
+ public void onIf(IfType ifKind, int blockIndex, EV valueIndex) {
builder.append(fmtValueIndex(valueIndex)).append(' ').append(fmtInsnIndex(blockIndex));
}
@@ -154,12 +158,12 @@
}
@Override
- public void onDebugLocalWrite(int srcIndex) {
+ public void onDebugLocalWrite(EV srcIndex) {
appendOutValue().append(fmtValueIndex(srcIndex));
}
@Override
- public void onInvokeMethodInstruction(DexMethod method, IntList arguments) {
+ public void onInvokeMethodInstruction(DexMethod method, List<EV> arguments) {
if (!method.getReturnType().isVoidType()) {
appendOutValue();
}
@@ -184,7 +188,7 @@
}
@Override
- public void onArrayLength(int arrayValueIndex) {
+ public void onArrayLength(EV arrayValueIndex) {
appendOutValue().append(fmtValueIndex(arrayValueIndex));
}
@@ -194,7 +198,7 @@
}
@Override
- public void onPhi(DexType type, IntList operands) {
+ public void onPhi(DexType type, List<EV> operands) {
appendOutValue();
appendValueArguments(operands);
builder.append(type);
diff --git a/src/main/java/com/android/tools/r8/lightir/LirSsaValueStrategy.java b/src/main/java/com/android/tools/r8/lightir/LirSsaValueStrategy.java
index b89dca8..78642e8 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirSsaValueStrategy.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirSsaValueStrategy.java
@@ -10,40 +10,42 @@
* the SSA out value. This strategy provides a way to opaquely encode any references of an SSA value
* as the relative offset from the referencing instruction.
*/
-public abstract class LirSsaValueStrategy {
+public abstract class LirSsaValueStrategy<EV> {
- private static final LirSsaValueStrategy INSTANCE = new RelativeStrategy();
+ private static final LirSsaValueStrategy<Integer> INSTANCE = new RelativeStrategy();
- public static LirSsaValueStrategy get() {
+ public static LirSsaValueStrategy<Integer> get() {
return INSTANCE;
}
- public abstract int encodeValueIndex(int absoluteValueIndex, int currentValueIndex);
+ public abstract int encodeValueIndex(EV value, int currentValueIndex);
- public abstract int decodeValueIndex(int encodedValueIndex, int currentValueIndex);
+ public abstract EV decodeValueIndex(int encodedValueIndex, int currentValueIndex);
- private static class AbsoluteStrategy extends LirSsaValueStrategy {
+ private static class AbsoluteStrategy extends LirSsaValueStrategy<Integer> {
@Override
- public int encodeValueIndex(int absoluteValueIndex, int currentValueIndex) {
- return absoluteValueIndex;
+ public int encodeValueIndex(Integer value, int currentValueIndex) {
+ assert value != null;
+ return value;
}
@Override
- public int decodeValueIndex(int encodedValueIndex, int currentValueIndex) {
+ public Integer decodeValueIndex(int encodedValueIndex, int currentValueIndex) {
return encodedValueIndex;
}
}
- private static class RelativeStrategy extends LirSsaValueStrategy {
+ private static class RelativeStrategy extends LirSsaValueStrategy<Integer> {
@Override
- public int encodeValueIndex(int absoluteValueIndex, int currentValueIndex) {
+ public int encodeValueIndex(Integer absoluteValueIndex, int currentValueIndex) {
+ assert absoluteValueIndex != null;
return currentValueIndex - absoluteValueIndex;
}
@Override
- public int decodeValueIndex(int encodedValueIndex, int currentValueIndex) {
+ public Integer decodeValueIndex(int encodedValueIndex, int currentValueIndex) {
return currentValueIndex - encodedValueIndex;
}
}
diff --git a/src/main/java/com/android/tools/r8/lightir/LirStrategy.java b/src/main/java/com/android/tools/r8/lightir/LirStrategy.java
new file mode 100644
index 0000000..70cda39
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/lightir/LirStrategy.java
@@ -0,0 +1,139 @@
+// Copyright (c) 2023, 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.lightir;
+
+import com.android.tools.r8.graph.DebugLocalInfo;
+import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.Phi;
+import com.android.tools.r8.ir.code.Phi.RegisterReadType;
+import com.android.tools.r8.ir.code.Value;
+import it.unimi.dsi.fastutil.objects.Reference2IntMap;
+import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
+
+/**
+ * Abstraction for encoding and decoding LIR values.
+ *
+ * @param <V> Abstract type of high-level values. This is always 'Value' but templating it avoids
+ * any use of the actual high-level IR Value type.
+ * @param <EV> Abstract type of encoded values. This is an intermediate encoding prior to
+ * serializing the value to an int or sequence of bytes. This encoding allows abstracting out
+ * the possible encoding for phi and non-phi values.
+ */
+public abstract class LirStrategy<V, EV> {
+ public abstract LirEncodingStrategy<V, EV> getEncodingStrategy();
+
+ public abstract LirDecodingStrategy<V, EV> getDecodingStrategy(LirCode<EV> code);
+
+ // Strategy that implements the encoding of phi values as instructions in the LIR instruction
+ // stream.
+ public static class PhiInInstructionsStrategy extends LirStrategy<Value, Integer> {
+
+ @Override
+ public LirEncodingStrategy<Value, Integer> getEncodingStrategy() {
+ return new EncodingStrategy();
+ }
+
+ @Override
+ public LirDecodingStrategy<Value, Integer> getDecodingStrategy(LirCode<Integer> code) {
+ return new DecodingStrategy(code);
+ }
+ }
+
+ private static class EncodingStrategy extends LirEncodingStrategy<Value, Integer> {
+
+ // EV == Integer and its definition is equal to its shifted instruction index.
+ // The conversion for EV to its int-valued reference is determined by the 'valueStrategy'.
+
+ private final LirSsaValueStrategy<Integer> valueStrategy = LirSsaValueStrategy.get();
+ private final Reference2IntMap<Value> values = new Reference2IntOpenHashMap<>();
+ private final Reference2IntMap<BasicBlock> blocks = new Reference2IntOpenHashMap<>();
+
+ @Override
+ public void defineBlock(BasicBlock block, int index) {
+ assert !blocks.containsKey(block);
+ blocks.put(block, index);
+ }
+
+ @Override
+ public Integer defineValue(Value value, int index) {
+ values.put(value, index);
+ return index;
+ }
+
+ @Override
+ public boolean verifyValueIndex(Value value, int expectedIndex) {
+ assert expectedIndex == values.getInt(value);
+ return true;
+ }
+
+ @Override
+ public Integer getEncodedValue(Value value) {
+ return values.getInt(value);
+ }
+
+ @Override
+ public int getBlockIndex(BasicBlock block) {
+ assert blocks.containsKey(block);
+ return blocks.getInt(block);
+ }
+
+ @Override
+ public LirSsaValueStrategy<Integer> getSsaValueStrategy() {
+ return valueStrategy;
+ }
+ }
+
+ private static class DecodingStrategy extends LirDecodingStrategy<Value, Integer> {
+
+ private final Value[] values;
+
+ DecodingStrategy(LirCode<Integer> code) {
+ values = new Value[code.getArgumentCount() + code.getInstructionCount()];
+ }
+
+ @Override
+ public Value getValue(Integer encodedValue) {
+ int index = encodedValue;
+ Value value = values[index];
+ if (value == null) {
+ value = new Value(index, TypeElement.getBottom(), null);
+ values[index] = value;
+ }
+ return value;
+ }
+
+ @Override
+ public Value getValueDefinitionForInstructionIndex(
+ int index, TypeElement type, DebugLocalInfo localInfo) {
+ Value value = values[index];
+ if (value == null) {
+ value = new Value(index, type, localInfo);
+ values[index] = value;
+ } else {
+ value.setType(type);
+ if (localInfo != null) {
+ value.setLocalInfo(localInfo);
+ }
+ }
+ return value;
+ }
+
+ @Override
+ public Phi getPhiDefinitionForInstructionIndex(
+ int index, BasicBlock block, TypeElement type, DebugLocalInfo localInfo) {
+ Phi phi = new Phi(index, block, type, localInfo, RegisterReadType.NORMAL);
+ Value value = values[index];
+ if (value != null) {
+ // A fake ssa value has already been created, replace the users by the actual phi.
+ // TODO(b/225838009): We could consider encoding the value type as a bit in the value index
+ // and avoid the overhead of replacing users at phi-definition time.
+ assert !value.isPhi();
+ value.replaceUsers(phi);
+ }
+ values[index] = phi;
+ return phi;
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/lightir/LirBasicCallbackTest.java b/src/test/java/com/android/tools/r8/lightir/LirBasicCallbackTest.java
index a3b9a1b..062470c 100644
--- a/src/test/java/com/android/tools/r8/lightir/LirBasicCallbackTest.java
+++ b/src/test/java/com/android/tools/r8/lightir/LirBasicCallbackTest.java
@@ -14,7 +14,9 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.IRMetadata;
+import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.references.Reference;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -32,20 +34,45 @@
parameters.assertNoneRuntime();
}
+ private static class ThrowingStrategy extends LirEncodingStrategy<Value, Integer> {
+
+ @Override
+ public void defineBlock(BasicBlock block, int index) {
+ throw new Unreachable();
+ }
+
+ @Override
+ public int getBlockIndex(BasicBlock block) {
+ throw new Unreachable();
+ }
+
+ @Override
+ public Integer defineValue(Value value, int index) {
+ throw new Unreachable();
+ }
+
+ @Override
+ public boolean verifyValueIndex(Value value, int expectedIndex) {
+ throw new Unreachable();
+ }
+
+ @Override
+ public Integer getEncodedValue(Value value) {
+ throw new Unreachable();
+ }
+
+ @Override
+ public LirSsaValueStrategy<Integer> getSsaValueStrategy() {
+ return null;
+ }
+ }
+
@Test
public void test() {
DexItemFactory factory = new DexItemFactory();
DexMethod method = factory.createMethod(Reference.methodFromDescriptor("LFoo;", "bar", "()V"));
- LirCode code =
- LirCode.builder(
- method,
- v -> {
- throw new Unreachable();
- },
- b -> {
- throw new Unreachable();
- },
- factory)
+ LirCode<?> code =
+ LirCode.builder(method, new ThrowingStrategy(), factory)
.setMetadata(IRMetadata.unknown())
.addConstNull()
.addConstInt(42)