blob: 0b0d537286a2156f14415bb1d58bb3dadf413da8 [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;
import java.util.function.Function;
import java.util.function.IntFunction;
/** Strategy encoding phi values as instructions in the LIR instruction stream. */
public 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> referenceStrategy = LirSsaValueStrategy.get();
private final Reference2IntMap<Value> values = new Reference2IntOpenHashMap<>();
private final Reference2IntMap<BasicBlock> blocks = new Reference2IntOpenHashMap<>();
@Override
public boolean isPhiInlineInstruction() {
return true;
}
@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 LirStrategyInfo<Integer> getStrategyInfo() {
return new LirStrategyInfo<Integer>() {
@Override
public LirSsaValueStrategy<Integer> getReferenceStrategy() {
return referenceStrategy;
}
};
}
}
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, LirStrategyInfo<Integer> strategyInfo) {
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, Function<Integer, DebugLocalInfo> getLocalInfo) {
DebugLocalInfo localInfo = getLocalInfo.apply(index);
Value value = values[index];
if (value == null) {
value = new Value(index, type, localInfo);
values[index] = value;
} else {
value.setType(type);
if (localInfo != null) {
if (!value.hasLocalInfo()) {
value.setLocalInfo(localInfo);
}
assert localInfo == value.getLocalInfo();
}
}
return value;
}
@Override
public Phi getPhiDefinitionForInstructionIndex(
int valueIndex,
IntFunction<BasicBlock> getBlock,
TypeElement type,
Function<Integer, DebugLocalInfo> getLocalInfo,
LirStrategyInfo<Integer> strategyInfo) {
BasicBlock block = getBlock.apply(valueIndex);
DebugLocalInfo localInfo = getLocalInfo.apply(valueIndex);
Phi phi = new Phi(valueIndex, block, 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;
}
}
}