// Copyright (c) 2022, 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.cf.code.CfArithmeticBinop;
import com.android.tools.r8.cf.code.CfArithmeticBinop.Opcode;
import com.android.tools.r8.cf.code.CfLogicalBinop;
import com.android.tools.r8.cf.code.CfNumberConversion;
import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DebugLocalInfo;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItem;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
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.Cmp;
import com.android.tools.r8.ir.code.Cmp.Bias;
import com.android.tools.r8.ir.code.IRMetadata;
import com.android.tools.r8.ir.code.IfType;
import com.android.tools.r8.ir.code.MemberType;
import com.android.tools.r8.ir.code.MonitorType;
import com.android.tools.r8.ir.code.NumericType;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.Position.SyntheticPosition;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.lightir.LirCode.DebugLocalInfoTable;
import com.android.tools.r8.lightir.LirCode.PositionEntry;
import com.android.tools.r8.lightir.LirCode.TryCatchTable;
import com.android.tools.r8.utils.ListUtils;
import com.google.common.collect.ImmutableList;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
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. */
public class LirBuilder<V, EV> {
  private static final int FLOAT_0 = Float.floatToRawIntBits(0);
  private static final int FLOAT_1 = Float.floatToRawIntBits(1);
  private static final int FLOAT_2 = Float.floatToRawIntBits(2);
  private static final long DOUBLE_0 = Double.doubleToRawLongBits(0);
  private static final long DOUBLE_1 = Double.doubleToRawLongBits(1);

  private final DexItemFactory factory;
  private final ByteArrayWriter byteWriter = new ByteArrayWriter();
  private final LirWriter writer = new LirWriter(byteWriter);
  private final Reference2IntMap<DexItem> constants;
  private final List<PositionEntry> positionTable;
  private int argumentCount = 0;
  private int instructionCount = 0;
  private IRMetadata metadata = null;

  private final LirEncodingStrategy<V, EV> strategy;

  private Position currentPosition;
  private Position flushedPosition;

  private final Int2ReferenceMap<CatchHandlers<Integer>> tryCatchRanges =
      new Int2ReferenceOpenHashMap<>();

  // Mapping from SSA value definition to the local name index in the constant pool.
  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<>();

  // TODO(b/225838009): Reconsider this fixed space as the operand count for phis is much larger.
  // Pre-allocated space for caching value indexes when writing instructions.
  private static final int MAX_VALUE_COUNT = 256;
  private int[] valueIndexBuffer = new int[MAX_VALUE_COUNT];

  /**
   * Internal "DexItem" for the instruction payloads such that they can be put in the pool.
   *
   * <p>The instruction encoding assumes the instruction operand payload size is u1, so this allows
   * the data payload to be stored in the constant pool instead.
   */
  public abstract static class InstructionPayload extends DexItem {
    @Override
    protected final void collectMixedSectionItems(MixedSectionCollection collection) {
      throw new Unreachable();
    }
  }

  /**
   * Internal "DexItem" for the fill-array payloads such that they can be put in the pool.
   *
   * <p>The instruction encoding assumes the instruction operand payload size is u1, so the data
   * payload is stored in the constant pool instead.
   */
  public static class FillArrayPayload extends InstructionPayload {
    public final int element_width;
    public final long size;
    public final short[] data;

    public FillArrayPayload(int element_width, long size, short[] data) {
      this.element_width = element_width;
      this.size = size;
      this.data = data;
    }
  }

  public static class IntSwitchPayload extends InstructionPayload {
    public final int[] keys;
    public final int[] targets;

    public IntSwitchPayload(int[] keys, int[] targets) {
      assert keys.length == targets.length;
      this.keys = keys;
      this.targets = targets;
    }
  }

  public LirBuilder(DexMethod method, LirEncodingStrategy<V, EV> strategy, DexItemFactory factory) {
    this.factory = factory;
    constants = new Reference2IntOpenHashMap<>();
    positionTable = new ArrayList<>();
    this.strategy = strategy;
    currentPosition = SyntheticPosition.builder().setLine(0).setMethod(method).build();
    flushedPosition = currentPosition;
  }

  public DexItemFactory factory() {
    return factory;
  }

  public boolean verifyCurrentValueIndex(int valueIndex) {
    assert instructionCount + argumentCount == valueIndex;
    return true;
  }

  public DexType toDexType(TypeElement typeElement) {
    if (typeElement.isPrimitiveType()) {
      return typeElement.asPrimitiveType().toDexType(factory);
    }
    if (typeElement.isReferenceType()) {
      return typeElement.asReferenceType().toDexType(factory);
    }
    throw new Unreachable("Unexpected type element: " + typeElement);
  }

  public void addTryCatchHanders(int blockIndex, CatchHandlers<Integer> handlers) {
    tryCatchRanges.put(blockIndex, handlers);
  }

  public LirBuilder<V, EV> setCurrentPosition(Position position) {
    assert position != null;
    currentPosition = position;
    return this;
  }

  private void setPositionIndex(int instructionIndex, Position position) {
    assert positionTable.isEmpty()
        || ListUtils.last(positionTable).fromInstructionIndex < instructionIndex;
    positionTable.add(new PositionEntry(instructionIndex, position));
  }

  private int getConstantIndex(DexItem item) {
    int nextIndex = constants.size();
    Integer oldIndex = constants.putIfAbsent(item, nextIndex);
    return oldIndex != null ? oldIndex : nextIndex;
  }

  private int constantIndexSize(DexItem item) {
    return 4;
  }

  private void writeConstantIndex(DexItem item) {
    int index = getConstantIndex(item);
    assert constantIndexSize(item) == ByteUtils.intEncodingSize(index);
    ByteUtils.writeEncodedInt(index, writer::writeOperand);
  }

  private EV getEncodedValue(V value) {
    return strategy.getEncodedValue(value);
  }

  private int getEncodedValueIndex(EV value, int referencingInstructionIndex) {
    int referencingValueIndex = referencingInstructionIndex + argumentCount;
    return strategy.getEncodedValueIndexForReference(value, referencingValueIndex);
  }

  private int encodedValueIndexSize(int encodedValueIndex) {
    return ByteUtils.intEncodingSize(encodedValueIndex);
  }

  private void writeEncodedValueIndex(int encodedValueIndex) {
    ByteUtils.writeEncodedInt(encodedValueIndex, writer::writeOperand);
  }

  private int getBlockIndex(BasicBlock block) {
    return strategy.getBlockIndex(block);
  }

  private int blockIndexSize(int index) {
    return ByteUtils.intEncodingSize(index);
  }

  private void writeBlockIndex(int index) {
    ByteUtils.writeEncodedInt(index, writer::writeOperand);
  }

  public LirBuilder<V, EV> setMetadata(IRMetadata metadata) {
    this.metadata = metadata;
    return this;
  }

  public LirBuilder<V, EV> setDebugValue(DebugLocalInfo debugInfo, EV valueIndex) {
    DebugLocalInfo old = debugLocals.put(valueIndex, debugInfo);
    assert old == null;
    return this;
  }

  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++) {
      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, EV> addArgument(int index, boolean knownToBeBoolean) {
    // Arguments are implicitly given by method descriptor and not an actual instruction.
    assert argumentCount == index;
    argumentCount++;
    return this;
  }

  private int advanceInstructionState() {
    if (!currentPosition.equals(flushedPosition)) {
      setPositionIndex(instructionCount, currentPosition);
      flushedPosition = currentPosition;
    }
    return instructionCount++;
  }

  private LirBuilder<V, EV> addNoOperandInstruction(int opcode) {
    advanceInstructionState();
    writer.writeOneByteInstruction(opcode);
    return this;
  }

  private LirBuilder<V, EV> addOneItemInstruction(int opcode, DexItem item) {
    return addInstructionTemplate(opcode, Collections.singletonList(item), Collections.emptyList());
  }

  private LirBuilder<V, EV> addOneValueInstruction(int opcode, V value) {
    return addInstructionTemplate(
        opcode, Collections.emptyList(), Collections.singletonList(value));
  }

  private LirBuilder<V, EV> addTwoValueInstruction(int opcode, V leftValue, V rightValue) {
    return addInstructionTemplate(
        opcode, Collections.emptyList(), ImmutableList.of(leftValue, rightValue));
  }

  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;
    for (DexItem item : items) {
      operandSize += constantIndexSize(item);
    }
    for (int i = 0; i < values.size(); i++) {
      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++) {
      writeEncodedValueIndex(valueIndexBuffer[i]);
    }
    return this;
  }

  public LirBuilder<V, EV> addConstNull() {
    return addNoOperandInstruction(LirOpcodes.ACONST_NULL);
  }

  public LirBuilder<V, EV> addConstInt(int value) {
    if (-1 <= value && value <= 5) {
      addNoOperandInstruction(LirOpcodes.ICONST_0 + value);
    } else {
      advanceInstructionState();
      writer.writeInstruction(LirOpcodes.ICONST, ByteUtils.intEncodingSize(value));
      ByteUtils.writeEncodedInt(value, writer::writeOperand);
    }
    return this;
  }

  public LirBuilder<V, EV> addConstFloat(int value) {
    if (value == FLOAT_0) {
      return addNoOperandInstruction(LirOpcodes.FCONST_0);
    }
    if (value == FLOAT_1) {
      return addNoOperandInstruction(LirOpcodes.FCONST_1);
    }
    if (value == FLOAT_2) {
      return addNoOperandInstruction(LirOpcodes.FCONST_2);
    }
    advanceInstructionState();
    writer.writeInstruction(LirOpcodes.FCONST, ByteUtils.intEncodingSize(value));
    ByteUtils.writeEncodedInt(value, writer::writeOperand);
    return this;
  }

  public LirBuilder<V, EV> addConstLong(long value) {
    if (value == 0) {
      return addNoOperandInstruction(LirOpcodes.LCONST_0);
    }
    if (value == 1) {
      return addNoOperandInstruction(LirOpcodes.LCONST_1);
    }
    advanceInstructionState();
    writer.writeInstruction(LirOpcodes.LCONST, ByteUtils.longEncodingSize(value));
    ByteUtils.writeEncodedLong(value, writer::writeOperand);
    return this;
  }

  public LirBuilder<V, EV> addConstDouble(long value) {
    if (value == DOUBLE_0) {
      return addNoOperandInstruction(LirOpcodes.DCONST_0);
    }
    if (value == DOUBLE_1) {
      return addNoOperandInstruction(LirOpcodes.DCONST_1);
    }
    advanceInstructionState();
    writer.writeInstruction(LirOpcodes.DCONST, ByteUtils.longEncodingSize(value));
    ByteUtils.writeEncodedLong(value, writer::writeOperand);
    return this;
  }

  public LirBuilder<V, EV> addConstNumber(ValueType type, long value) {
    switch (type) {
      case OBJECT:
        return addConstNull();
      case INT:
        return addConstInt((int) value);
      case FLOAT:
        return addConstFloat((int) value);
      case LONG:
        return addConstLong(value);
      case DOUBLE:
        return addConstDouble(value);
      default:
        throw new Unimplemented();
    }
  }

  public LirBuilder<V, EV> addConstString(DexString string) {
    return addOneItemInstruction(LirOpcodes.LDC, string);
  }

  public LirBuilder<V, EV> addConstClass(DexType type) {
    return addOneItemInstruction(LirOpcodes.LDC, type);
  }

  public LirBuilder<V, EV> addDiv(NumericType type, V leftValue, V rightValue) {
    int opcode;
    switch (type) {
      case BYTE:
      case CHAR:
      case SHORT:
      case INT:
        {
          opcode = LirOpcodes.IDIV;
          break;
        }
      case LONG:
        {
          opcode = LirOpcodes.LDIV;
          break;
        }
      case FLOAT:
        {
          opcode = LirOpcodes.FDIV;
          break;
        }
      case DOUBLE:
        {
          opcode = LirOpcodes.DDIV;
          break;
        }
      default:
        throw new Unreachable("Unexpected type: " + type);
    }
    return addInstructionTemplate(
        opcode, Collections.emptyList(), ImmutableList.of(leftValue, rightValue));
  }

  public LirBuilder<V, EV> addArrayLength(V array) {
    return addOneValueInstruction(LirOpcodes.ARRAYLENGTH, array);
  }

  public LirBuilder<V, EV> addCheckCast(DexType type, V value) {
    return addInstructionTemplate(
        LirOpcodes.CHECKCAST, Collections.singletonList(type), Collections.singletonList(value));
  }

  public LirBuilder<V, EV> addInstanceOf(DexType type, V value) {
    return addInstructionTemplate(
        LirOpcodes.INSTANCEOF, Collections.singletonList(type), Collections.singletonList(value));
  }

  public LirBuilder<V, EV> addStaticGet(DexField field) {
    return addOneItemInstruction(LirOpcodes.GETSTATIC, field);
  }

  public LirBuilder<V, EV> addStaticPut(DexField field, V value) {
    return addInstructionTemplate(
        LirOpcodes.PUTSTATIC, Collections.singletonList(field), ImmutableList.of(value));
  }

  public LirBuilder<V, EV> addInstanceGet(DexField field, V object) {
    return addInstructionTemplate(
        LirOpcodes.GETFIELD, Collections.singletonList(field), Collections.singletonList(object));
  }

  public LirBuilder<V, EV> addInstancePut(DexField field, V object, V value) {
    return addInstructionTemplate(
        LirOpcodes.PUTFIELD, Collections.singletonList(field), ImmutableList.of(object, value));
  }

  public LirBuilder<V, EV> addInvokeInstruction(int opcode, DexMethod method, List<V> arguments) {
    return addInstructionTemplate(opcode, Collections.singletonList(method), arguments);
  }

  public LirBuilder<V, EV> addInvokeDirect(
      DexMethod method, List<V> arguments, boolean isInterface) {
    int opcode = isInterface ? LirOpcodes.INVOKEDIRECT_ITF : LirOpcodes.INVOKEDIRECT;
    return addInvokeInstruction(opcode, method, arguments);
  }

  public LirBuilder<V, EV> addInvokeSuper(
      DexMethod method, List<V> arguments, boolean isInterface) {
    int opcode = isInterface ? LirOpcodes.INVOKESUPER_ITF : LirOpcodes.INVOKESUPER;
    return addInvokeInstruction(opcode, method, arguments);
  }

  public LirBuilder<V, EV> addInvokeVirtual(DexMethod method, List<V> arguments) {
    return addInvokeInstruction(LirOpcodes.INVOKEVIRTUAL, method, arguments);
  }

  public LirBuilder<V, EV> addInvokeStatic(
      DexMethod method, List<V> arguments, boolean isInterface) {
    int opcode = isInterface ? LirOpcodes.INVOKESTATIC_ITF : LirOpcodes.INVOKESTATIC;
    return addInvokeInstruction(opcode, method, arguments);
  }

  public LirBuilder<V, EV> addInvokeInterface(DexMethod method, List<V> arguments) {
    return addInvokeInstruction(LirOpcodes.INVOKEINTERFACE, method, arguments);
  }

  public LirBuilder<V, EV> addNewInstance(DexType clazz) {
    return addOneItemInstruction(LirOpcodes.NEW, clazz);
  }

  public LirBuilder<V, EV> addThrow(V exception) {
    return addOneValueInstruction(LirOpcodes.ATHROW, exception);
  }

  public LirBuilder<V, EV> addReturn(V value) {
    return addOneValueInstruction(LirOpcodes.ARETURN, value);
  }

  public LirBuilder<V, EV> addReturnVoid() {
    return addNoOperandInstruction(LirOpcodes.RETURN);
  }

  public LirBuilder<V, EV> addDebugPosition(Position position) {
    assert currentPosition == position;
    return addNoOperandInstruction(LirOpcodes.DEBUGPOS);
  }

  public void addFallthrough() {
    addNoOperandInstruction(LirOpcodes.FALLTHROUGH);
  }

  public LirBuilder<V, EV> addGoto(BasicBlock target) {
    int targetIndex = getBlockIndex(target);
    int operandSize = blockIndexSize(targetIndex);
    advanceInstructionState();
    writer.writeInstruction(LirOpcodes.GOTO, operandSize);
    writeBlockIndex(targetIndex);
    return this;
  }

  public LirBuilder<V, EV> addIntSwitch(
      V value,
      int[] keys,
      Int2ReferenceSortedMap<BasicBlock> keyToTargetMap,
      BasicBlock fallthroughBlock) {
    int[] targets = new int[keys.length];
    for (int i = 0; i < keys.length; i++) {
      targets[i] = getBlockIndex(keyToTargetMap.get(keys[i]));
    }
    IntSwitchPayload payload = new IntSwitchPayload(keys, targets);
    return addInstructionTemplate(
        LirOpcodes.TABLESWITCH,
        Collections.singletonList(payload),
        Collections.singletonList(value));
  }

  public LirBuilder<V, EV> addIf(
      IfType ifKind, ValueType valueType, V value, BasicBlock trueTarget) {
    int opcode;
    switch (ifKind) {
      case EQ:
        opcode = valueType.isObject() ? LirOpcodes.IFNULL : LirOpcodes.IFEQ;
        break;
      case GE:
        opcode = LirOpcodes.IFGE;
        break;
      case GT:
        opcode = LirOpcodes.IFGT;
        break;
      case LE:
        opcode = LirOpcodes.IFLE;
        break;
      case LT:
        opcode = LirOpcodes.IFLT;
        break;
      case NE:
        opcode = valueType.isObject() ? LirOpcodes.IFNONNULL : LirOpcodes.IFNE;
        break;
      default:
        throw new Unreachable("Unexpected if kind: " + ifKind);
    }
    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);
    writeEncodedValueIndex(valueIndex);
    return this;
  }

  public LirBuilder<V, EV> addIfCmp(
      IfType ifKind, ValueType valueType, List<V> inValues, BasicBlock trueTarget) {
    int opcode;
    switch (ifKind) {
      case EQ:
        opcode = valueType.isObject() ? LirOpcodes.IF_ACMPEQ : LirOpcodes.IF_ICMPEQ;
        break;
      case GE:
        opcode = LirOpcodes.IF_ICMPGE;
        break;
      case GT:
        opcode = LirOpcodes.IF_ICMPGT;
        break;
      case LE:
        opcode = LirOpcodes.IF_ICMPLE;
        break;
      case LT:
        opcode = LirOpcodes.IF_ICMPLT;
        break;
      case NE:
        opcode = valueType.isObject() ? LirOpcodes.IF_ACMPNE : LirOpcodes.IF_ICMPNE;
        break;
      default:
        throw new Unreachable("Unexpected if kind " + ifKind);
    }
    int instructionIndex = advanceInstructionState();
    int targetIndex = getBlockIndex(trueTarget);
    int valueOneIndex = getEncodedValueIndex(getEncodedValue(inValues.get(0)), instructionIndex);
    int valueTwoIndex = getEncodedValueIndex(getEncodedValue(inValues.get(1)), instructionIndex);
    int operandSize =
        blockIndexSize(targetIndex)
            + encodedValueIndexSize(valueOneIndex)
            + encodedValueIndexSize(valueTwoIndex);
    writer.writeInstruction(opcode, operandSize);
    writeBlockIndex(targetIndex);
    writeEncodedValueIndex(valueOneIndex);
    writeEncodedValueIndex(valueTwoIndex);
    return this;
  }

  public LirBuilder<V, EV> addMoveException(DexType exceptionType) {
    return addOneItemInstruction(LirOpcodes.MOVEEXCEPTION, exceptionType);
  }

  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, EV> addDebugLocalWrite(V src) {
    return addOneValueInstruction(LirOpcodes.DEBUGLOCALWRITE, src);
  }

  public LirCode<EV> build() {
    assert metadata != null;
    int constantsCount = constants.size();
    DexItem[] constantTable = new DexItem[constantsCount];
    constants.forEach((item, index) -> constantTable[index] = item);
    DebugLocalInfoTable<EV> debugTable =
        debugLocals.isEmpty() ? null : new DebugLocalInfoTable<>(debugLocals, debugLocalEnds);
    return new LirCode<>(
        metadata,
        constantTable,
        positionTable.toArray(new PositionEntry[positionTable.size()]),
        argumentCount,
        byteWriter.toByteArray(),
        instructionCount,
        new TryCatchTable(tryCatchRanges),
        debugTable,
        strategy.getStrategyInfo());
  }

  private int getCmpOpcode(NumericType type, Cmp.Bias bias) {
    switch (type) {
      case LONG:
        return LirOpcodes.LCMP;
      case FLOAT:
        return bias == Cmp.Bias.LT ? LirOpcodes.FCMPL : LirOpcodes.FCMPG;
      case DOUBLE:
        return bias == Cmp.Bias.LT ? LirOpcodes.DCMPL : LirOpcodes.DCMPG;
      default:
        throw new Unreachable("Cmp has unknown type " + type);
    }
  }

  public LirBuilder<V, EV> addCmp(NumericType type, Bias bias, V leftValue, V rightValue) {
    return addTwoValueInstruction(getCmpOpcode(type, bias), leftValue, rightValue);
  }

  public LirBuilder<V, EV> addArithmeticBinop(
      CfArithmeticBinop.Opcode binop, NumericType type, V leftValue, V rightValue) {
    // The LIR and CF opcodes are the same values, check that the two endpoints match.
    assert LirOpcodes.IADD == CfArithmeticBinop.getAsmOpcode(Opcode.Add, NumericType.INT);
    assert LirOpcodes.DREM == CfArithmeticBinop.getAsmOpcode(Opcode.Rem, NumericType.DOUBLE);
    int opcode = CfArithmeticBinop.getAsmOpcode(binop, type);
    return addTwoValueInstruction(opcode, leftValue, rightValue);
  }

  public LirBuilder<V, EV> addLogicalBinop(
      CfLogicalBinop.Opcode binop, NumericType type, V leftValue, V rightValue) {
    // The LIR and CF opcodes are the same values, check that the two endpoints match.
    assert LirOpcodes.ISHL
        == CfLogicalBinop.getAsmOpcode(CfLogicalBinop.Opcode.Shl, NumericType.INT);
    assert LirOpcodes.LXOR
        == CfLogicalBinop.getAsmOpcode(CfLogicalBinop.Opcode.Xor, NumericType.LONG);
    int opcode = CfLogicalBinop.getAsmOpcode(binop, type);
    return addTwoValueInstruction(opcode, leftValue, rightValue);
  }

  public LirBuilder<V, EV> addMonitor(MonitorType type, V value) {
    return addOneValueInstruction(
        type == MonitorType.ENTER ? LirOpcodes.MONITORENTER : LirOpcodes.MONITOREXIT, value);
  }

  public LirBuilder<V, EV> addNewArrayEmpty(V size, DexType type) {
    return addInstructionTemplate(
        LirOpcodes.NEWARRAY, Collections.singletonList(type), Collections.singletonList(size));
  }

  public LirBuilder<V, EV> addInvokeNewArray(DexType type, List<V> arguments) {
    return addInstructionTemplate(
        LirOpcodes.INVOKENEWARRAY, Collections.singletonList(type), arguments);
  }

  public LirBuilder<V, EV> addNewArrayFilledData(int elementWidth, long size, short[] data, V src) {
    FillArrayPayload payloadConstant = new FillArrayPayload(elementWidth, size, data);
    return addInstructionTemplate(
        LirOpcodes.NEWARRAYFILLEDDATA,
        Collections.singletonList(payloadConstant),
        Collections.singletonList(src));
  }

  public LirBuilder<V, EV> addNumberConversion(NumericType from, NumericType to, V value) {
    int opcode = new CfNumberConversion(from, to).getAsmOpcode();
    assert LirOpcodes.I2L <= opcode;
    assert opcode <= LirOpcodes.I2S;
    return addOneValueInstruction(opcode, value);
  }

  public LirBuilder<V, EV> addArrayGetObject(DexType destType, V array, V index) {
    return addInstructionTemplate(
        LirOpcodes.AALOAD, Collections.singletonList(destType), ImmutableList.of(array, index));
  }

  public LirBuilder<V, EV> addArrayGetPrimitive(MemberType memberType, V array, V index) {
    int opcode;
    switch (memberType) {
      case BOOLEAN_OR_BYTE:
        opcode = LirOpcodes.BALOAD;
        break;
      case CHAR:
        opcode = LirOpcodes.CALOAD;
        break;
      case SHORT:
        opcode = LirOpcodes.SALOAD;
        break;
      case INT:
        opcode = LirOpcodes.IALOAD;
        break;
      case FLOAT:
        opcode = LirOpcodes.FALOAD;
        break;
      case LONG:
        opcode = LirOpcodes.LALOAD;
        break;
      case DOUBLE:
        opcode = LirOpcodes.DALOAD;
        break;
      default:
        throw new Unreachable("Unexpected object or imprecise member type: " + memberType);
    }
    return addInstructionTemplate(opcode, Collections.emptyList(), ImmutableList.of(array, index));
  }

  public LirBuilder<V, EV> addArrayPut(MemberType memberType, V array, V index, V value) {
    int opcode;
    switch (memberType) {
      case BOOLEAN_OR_BYTE:
        opcode = LirOpcodes.BASTORE;
        break;
      case CHAR:
        opcode = LirOpcodes.CASTORE;
        break;
      case SHORT:
        opcode = LirOpcodes.SASTORE;
        break;
      case INT:
        opcode = LirOpcodes.IASTORE;
        break;
      case FLOAT:
        opcode = LirOpcodes.FASTORE;
        break;
      case LONG:
        opcode = LirOpcodes.LASTORE;
        break;
      case DOUBLE:
        opcode = LirOpcodes.DASTORE;
        break;
      case OBJECT:
        opcode = LirOpcodes.AASTORE;
        break;
      default:
        throw new Unreachable("Unexpected imprecise member type: " + memberType);
    }
    return addInstructionTemplate(
        opcode, Collections.emptyList(), ImmutableList.of(array, index, value));
  }
}
