From c95e501cec55dc88a223bed5d137462819fca768 Mon Sep 17 00:00:00 2001 From: water111 <48171810+water111@users.noreply.github.com> Date: Fri, 14 May 2021 20:12:59 -0400 Subject: [PATCH] handle zero case in enum comparison (#484) --- decompiler/IR2/FormExpressionAnalysis.cpp | 50 +++++++++++++++++-- decompiler/IR2/bitfields.cpp | 23 +++++---- decompiler/IR2/bitfields.h | 1 + .../reference/engine/dma/dma-disasm_REF.gc | 4 +- .../reference/engine/gfx/hw/gs_REF.gc | 2 +- .../reference/engine/load/file-io_REF.gc | 8 +-- 6 files changed, 67 insertions(+), 21 deletions(-) diff --git a/decompiler/IR2/FormExpressionAnalysis.cpp b/decompiler/IR2/FormExpressionAnalysis.cpp index bd6fa9c053..c9a5a7ff11 100644 --- a/decompiler/IR2/FormExpressionAnalysis.cpp +++ b/decompiler/IR2/FormExpressionAnalysis.cpp @@ -2371,6 +2371,40 @@ Matcher make_int_uint_cast_matcher(const Matcher& thing) { // ConditionElement /////////////////// +namespace { +/*! + * Try to make a pretty looking constant out of value for comparing to something of type. + * If we can't do anything nice, return nullptr. + */ +Form* try_make_constant_for_compare(Form* value, + const TypeSpec& type, + FormPool& pool, + const Env& env) { + if (get_goal_integer_constant(value, env) && env.dts->ts.try_enum_lookup(type)) { + return cast_form(value, type, pool, env); + } + return nullptr; +} + +Form* try_make_constant_from_int_for_compare(s64 value, + const TypeSpec& type, + FormPool& pool, + const Env& env) { + auto enum_type_info = env.dts->ts.try_enum_lookup(type); + if (enum_type_info) { + if (enum_type_info->is_bitfield()) { + if (value != 0) { + // prefer (zero? x) for bitfield enums. + return cast_to_bitfield_enum(enum_type_info, pool, env, value); + } + } else { + return cast_to_int_enum(enum_type_info, pool, env, value); + } + } + return nullptr; +} +} // namespace + FormElement* ConditionElement::make_zero_check_generic(const Env& env, FormPool& pool, const std::vector