| // 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; |
| } |
| } |
| } |