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