From ff7af476b359ce2886f068b55e99900c949651e8 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Mon, 15 May 2023 11:52:03 +0000 Subject: [PATCH] simplify_byte_extract: avoid unnecessary calls to has_subtype This is a performance-improving refactoring: We only need the result of a `has_subtype` call under conditions that are infrequently met. On the benchmark of #7357, this avoids 443214 calls of `has_subtype`, which previously was the most costly part of `simplify_byte_extract`. --- src/util/simplify_expr.cpp | 65 ++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/src/util/simplify_expr.cpp b/src/util/simplify_expr.cpp index 0f61cd9add4..586757e2d5d 100644 --- a/src/util/simplify_expr.cpp +++ b/src/util/simplify_expr.cpp @@ -1831,41 +1831,44 @@ simplify_exprt::simplify_byte_extract(const byte_extract_exprt &expr) const auto bits = expr2bits(expr.op(), expr.id() == ID_byte_extract_little_endian, ns); - // make sure we don't lose bits with structs containing flexible array members - const bool struct_has_flexible_array_member = has_subtype( - expr.type(), - [&](const typet &type) { - if(type.id() != ID_struct && type.id() != ID_struct_tag) - return false; - - const struct_typet &st = to_struct_type(ns.follow(type)); - const auto &comps = st.components(); - if(comps.empty() || comps.back().type().id() != ID_array) - return false; - - if(comps.back().type().get_bool(ID_C_flexible_array_member)) - return true; - - const auto size = - numeric_cast(to_array_type(comps.back().type()).size()); - return !size.has_value() || *size <= 1; - }, - ns); if( bits.has_value() && - mp_integer(bits->size()) >= *el_size + *offset * expr.get_bits_per_byte() && - !struct_has_flexible_array_member) - { - std::string bits_cut = std::string( - bits.value(), - numeric_cast_v(*offset * expr.get_bits_per_byte()), - numeric_cast_v(*el_size)); + mp_integer(bits->size()) >= *el_size + *offset * expr.get_bits_per_byte()) + { + // make sure we don't lose bits with structs containing flexible array + // members + const bool struct_has_flexible_array_member = has_subtype( + expr.type(), + [&](const typet &type) { + if(type.id() != ID_struct && type.id() != ID_struct_tag) + return false; + + const struct_typet &st = to_struct_type(ns.follow(type)); + const auto &comps = st.components(); + if(comps.empty() || comps.back().type().id() != ID_array) + return false; + + if(comps.back().type().get_bool(ID_C_flexible_array_member)) + return true; + + const auto size = + numeric_cast(to_array_type(comps.back().type()).size()); + return !size.has_value() || *size <= 1; + }, + ns); + if(!struct_has_flexible_array_member) + { + std::string bits_cut = std::string( + bits.value(), + numeric_cast_v(*offset * expr.get_bits_per_byte()), + numeric_cast_v(*el_size)); - auto tmp = bits2expr( - bits_cut, expr.type(), expr.id() == ID_byte_extract_little_endian, ns); + auto tmp = bits2expr( + bits_cut, expr.type(), expr.id() == ID_byte_extract_little_endian, ns); - if(tmp.has_value()) - return std::move(*tmp); + if(tmp.has_value()) + return std::move(*tmp); + } } // push byte extracts into struct or union expressions, just like