blob: 70cda395569fefab647e4575be2881d49455927f [file] [log] [blame]
// 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;
}
}
}