bool FixpointIterator::is_required()

in opt/object-sensitive-dce/UsedVarsAnalysis.cpp [114:222]


bool FixpointIterator::is_required(const IRInstruction* insn,
                                   const UsedVarsSet& used_vars) const {
  auto op = insn->opcode();
  switch (op) {
  case IOPCODE_LOAD_PARAM:
  case IOPCODE_LOAD_PARAM_OBJECT:
  case IOPCODE_LOAD_PARAM_WIDE:
  // Control-flow opcodes are always required.
  case OPCODE_RETURN_VOID:
  case OPCODE_RETURN:
  case OPCODE_RETURN_WIDE:
  case OPCODE_RETURN_OBJECT:
  case OPCODE_MONITOR_ENTER:
  case OPCODE_MONITOR_EXIT:
  case OPCODE_CHECK_CAST:
  case OPCODE_THROW:
  case OPCODE_GOTO:
  case OPCODE_SWITCH:
  case OPCODE_IF_EQ:
  case OPCODE_IF_NE:
  case OPCODE_IF_LT:
  case OPCODE_IF_GE:
  case OPCODE_IF_GT:
  case OPCODE_IF_LE:
  case OPCODE_IF_EQZ:
  case OPCODE_IF_NEZ:
  case OPCODE_IF_LTZ:
  case OPCODE_IF_GEZ:
  case OPCODE_IF_GTZ:
  case OPCODE_IF_LEZ: {
    return true;
  }
  case OPCODE_APUT:
  case OPCODE_APUT_WIDE:
  case OPCODE_APUT_OBJECT:
  case OPCODE_APUT_BOOLEAN:
  case OPCODE_APUT_BYTE:
  case OPCODE_APUT_CHAR:
  case OPCODE_APUT_SHORT:
  case OPCODE_IPUT:
  case OPCODE_IPUT_WIDE:
  case OPCODE_IPUT_OBJECT:
  case OPCODE_IPUT_BOOLEAN:
  case OPCODE_IPUT_BYTE:
  case OPCODE_IPUT_CHAR:
  case OPCODE_IPUT_SHORT: {
    const auto& env = m_insn_env_map.at(insn);
    return is_used_or_escaping_write(env, used_vars, insn->src(1));
  }
  case OPCODE_FILL_ARRAY_DATA: {
    const auto& env = m_insn_env_map.at(insn);
    return is_used_or_escaping_write(env, used_vars, insn->src(0));
  }
  case OPCODE_SPUT:
  case OPCODE_SPUT_WIDE:
  case OPCODE_SPUT_OBJECT:
  case OPCODE_SPUT_BOOLEAN:
  case OPCODE_SPUT_BYTE:
  case OPCODE_SPUT_CHAR:
  case OPCODE_SPUT_SHORT: {
    return true;
  }
  case OPCODE_INVOKE_DIRECT:
  case OPCODE_INVOKE_STATIC:
  case OPCODE_INVOKE_VIRTUAL: {
    auto method = resolve_method(insn->get_method(), opcode_to_search(insn));
    if (method == nullptr) {
      return true;
    }
    if (assumenosideeffects(method)) {
      return used_vars.contains(RESULT_REGISTER);
    }
    const auto& env = m_insn_env_map.at(insn);
    if (method::is_init(method) &&
        (used_vars.contains(insn->src(0)) ||
         is_used_or_escaping_write(env, used_vars, insn->src(0)))) {
      return true;
    }
    if (!m_invoke_to_summary_map.count(insn)) {
      return true;
    }
    // A call is required if it has a side-effect, if its return value is used,
    // or if it mutates an argument that may later be read somewhere up the
    // callstack.
    auto& summary = m_invoke_to_summary_map.at(insn);
    if (summary.effects != side_effects::EFF_NONE ||
        used_vars.contains(RESULT_REGISTER)) {
      return true;
    }
    const auto& mod_params = summary.modified_params;
    return std::any_of(
        mod_params.begin(), mod_params.end(), [&](param_idx_t idx) {
          return is_used_or_escaping_write(env, used_vars, insn->src(idx));
        });
  }
  case OPCODE_INVOKE_SUPER:
  case OPCODE_INVOKE_INTERFACE: {
    return true;
  }
  default: {
    if (insn->has_dest()) {
      return used_vars.contains(insn->dest());
    } else if (insn->has_move_result_any()) {
      return used_vars.contains(RESULT_REGISTER);
    }
    return true;
  }
  }
}