/* ** Copyright (C) 2018 Martin Brain ** ** This program is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program. If not, see . */ #include "symfpu/baseTypes/cprover_exprt.h" #include #include #include #include #include #define THERE_BE_DRAGONS #ifdef THERE_BE_DRAGONS // GCC needs LINKFLAGS="-rdynamic" to give function names in the backtrace #include #include #endif namespace symfpu { namespace cprover_exprt { #define BITS 32 roundingMode traits::RNE (void) { return roundingMode(from_integer(0/*ieee_floatt::ROUND_TO_EVEN*/, signedbv_typet(BITS))); } roundingMode traits::RNA (void) { return roundingMode(from_integer(4, signedbv_typet(BITS))); } roundingMode traits::RTP (void) { return roundingMode(from_integer(2/*ieee_floatt::ROUND_TO_PLUS_INF*/, signedbv_typet(BITS))); } roundingMode traits::RTN (void) { return roundingMode(from_integer(1/*ieee_floatt::ROUND_TO_MINUS_INF*/, signedbv_typet(BITS))); } roundingMode traits::RTZ (void) { return roundingMode(from_integer(3/*ieee_floatt::ROUND_TO_ZERO*/, signedbv_typet(BITS))); } #ifdef THERE_BE_DRAGONS // The following code is evil and insane // It exists to add labels in code generated by boolbvt_graph.h struct demangledName { std::string path; std::string mangledName; std::string demangledName; std::string remainder; }; /// Attempts to demangle the function name assuming the glibc /// format of stack entry: /// /// path '(' mangledName '+' offset ') [' address ']\0' /// /// \param out: The output stream /// \param stack_entry: Description of the stack_entry /// /// \return True <=> the entry has been successfully demangled and printed. static demangledName demangle(const std::string &stack_entry) { demangledName return_value = {"Not found", "Not found", "Not found", stack_entry}; std::string working(stack_entry); std::string::size_type start=working.rfind('('); // Path may contain '(' ! std::string::size_type end=working.find('+', start); return_value.path = working.substr(0, start - 1); if(start!=std::string::npos && end!=std::string::npos && start+1<=end-1) { std::string::size_type length=end-(start+1); std::string mangled(working.substr(start+1, length)); return_value.mangledName = mangled; int demangle_success=1; char * demangled = abi::__cxa_demangle(mangled.c_str(), nullptr, nullptr, &demangle_success); if(demangle_success==0) { return_value.demangledName = demangled; } else { return_value.demangledName = "Demangle failed"; } } else { return_value.mangledName = "Mangled name not found"; return_value.demangledName = "Nothing to demangle"; } return_value.remainder = working.substr(end + 1); return return_value; } typedef std::pair creation_context; static creation_context find_creation_context (void) { void * stack[50] = {}; std::size_t entries = backtrace(stack, sizeof(stack) / sizeof(void *)); char **description = backtrace_symbols(stack, entries); std::string locationPrefix; std::string locationPostfix; // Start at the right place to avoid the C shim which doesn't decode #define MAGIC_START 4 // Avoid the introspection of this code #define MAGIC_END 3 for(std::size_t i=entries - MAGIC_START; i>MAGIC_END; i--) { demangledName d = demangle(description[i]); if (d.demangledName.find("symfpu::") == 0 && // !(d.demangledName.find("symfpu::cprover_exprt") == 0) && d.demangledName.find("symfpu::ite") == std::string::npos && d.demangledName.find("symfpu::ITE") == std::string::npos && d.demangledName.find("symfpu::unpackedFloat") != std::string::npos ) { locationPrefix += "subgraph \"cluster_" + d.demangledName + "\" {\n"; locationPrefix += "label = \"" + d.demangledName + "\"\n"; locationPostfix += "}\n"; } } free(description); return creation_context(locationPrefix, locationPostfix); } static void apply_creation_context_rec (const creation_context &ct, exprt &e) { e.set("#creation_open", ct.first); e.set("#creation_close", ct.second); // In some cases multiple exprts have been created between tags. // Naive recursion is bad! Forall_operands(e_it, e) { if (e_it->get_comments().find("#creation_open") == e_it->get_comments().end()) apply_creation_context_rec(ct, *e_it); } return; } static exprt apply_creation_context (const exprt &e) { creation_context ct = find_creation_context(); exprt ei(e); if (ct.first.empty()) return ei; apply_creation_context_rec(ct, ei); return ei; } #endif exprt proposition::tag (const exprt &e) const { #ifdef THERE_BE_DRAGONS if (boolbv_grapht::graph_enable) return apply_creation_context(e); #endif return e; } template exprt bitVector::tag (const exprt &e) const { #ifdef THERE_BE_DRAGONS if (boolbv_grapht::graph_enable) return apply_creation_context(e); #endif return e; } // Instantiate template exprt bitVector::tag (const exprt &e) const; template exprt bitVector::tag (const exprt &e) const; #define INLINESIMP // Inline simplification as simplify_expr does not scale // Just to reduce the visual clutter exprt simplify_local_constant_fold (const exprt e) { if (e.id() == ID_constant) { return e; } else { /* exprt check_target(e); while (check_target.id() == ID_typecast || check_target.id() == ID_extractbits) { check_target = check_target.op0(); } forall_operands(it, check_target) */ forall_operands(it, e) { if ((*it).id() != ID_constant) return e; } symbol_tablet s; namespacet n(s); return simplify_expr(e, n); } } exprt simplify_if (const if_exprt i) { const exprt cond(i.cond()); const exprt true_case(i.true_case()); const exprt false_case(i.false_case()); // Start with the simple ones if (cond.is_true() || (true_case == false_case)) { return true_case; } else if (cond.is_false()) { return false_case; } else { // Compact if's if (true_case.id() == ID_if) { if_exprt l(to_if_expr(true_case)); if (l.true_case() == false_case) { return simplify_if(if_exprt(and_exprt(cond, not_exprt(l.cond())), l.false_case(), false_case)); } else if (l.false_case() == false_case) { return simplify_if(if_exprt(and_exprt(cond, l.cond()), l.true_case(), false_case)); } } else if (false_case.id() == ID_if) { if_exprt l(to_if_expr(false_case)); if (l.true_case() == true_case) { return simplify_if(if_exprt(and_exprt(not_exprt(cond), not_exprt(l.cond())), l.false_case(), true_case)); } else if (l.false_case() == true_case) { return simplify_if(if_exprt(and_exprt(not_exprt(cond), l.cond()), l.true_case(), true_case)); } } } return i; } exprt proposition::simplify (const exprt &e) const { #ifndef INLINESIMP return e; #endif exprt r(simplify_local_constant_fold(e)); if (r.id() == ID_constant) return r; if (e.id() == ID_if) { exprt s(simplify_if(to_if_expr(e))); // Additional simplifications for Boolean things if (s.id() == ID_if) { if_exprt i(to_if_expr(s)); if (i.true_case().is_true()) { return simplify(or_exprt(i.cond(), i.false_case())); } else if (i.true_case().is_false()) { return simplify(and_exprt(not_exprt(i.cond()), i.false_case())); } else if (i.false_case().is_true()) { return simplify(or_exprt(not_exprt(i.cond()), i.true_case())); } else if (i.false_case().is_false()) { return simplify(and_exprt(i.cond(), i.true_case())); } assert(!i.cond().is_constant()); assert(!i.true_case().is_constant()); assert(!i.false_case().is_constant()); } return s; } else if (e.id() == ID_not) { if (e.op0().id() == ID_not) { return simplify(e.op0().op0()); } } else if (e.id() == ID_and) { exprt::operandst operands(e.operands()); size_t i = 0; while (i < operands.size()) { if (operands[i].is_true()) { operands.erase(operands.begin() + i); } else if (operands[i].is_false()) { return operands[i]; } else if (operands[i].id() == ID_and) { exprt::operandst appendMe(operands[i].operands()); for (size_t j = 0; j < appendMe.size(); ++j) { operands.push_back(appendMe[j]); } operands.erase(operands.begin() + i); } else if (operands[i].id() == ID_not && operands[i].op0().id() == ID_or) { exprt::operandst negateMe(operands[i].op0().operands()); for (size_t j = 0; j < negateMe.size(); ++j) { operands.push_back(not_exprt(negateMe[j])); } operands.erase(operands.begin() + i); } else { bool duplicate = false; for (size_t j = 0; j < i; ++j) { if (operands[j] == operands[i]) { duplicate = true; break; } } if (duplicate) { operands.erase(operands.begin() + i); } else { ++i; } } } if (operands.size() == 0) { return true_exprt(); } else if (operands.size() == 1) { return operands[0]; } else { return conjunction(operands); } } else if (e.id() == ID_or) { exprt::operandst operands(e.operands()); size_t i = 0; while (i < operands.size()) { if (operands[i].is_false()) { operands.erase(operands.begin() + i); } else if (operands[i].is_true()) { return operands[i]; } else if (operands[i].id() == ID_or) { exprt::operandst appendMe(operands[i].operands()); for (size_t j = 0; j < appendMe.size(); ++j) { operands.push_back(appendMe[j]); } operands.erase(operands.begin() + i); } else if (operands[i].id() == ID_not && operands[i].op0().id() == ID_and) { exprt::operandst negateMe(operands[i].op0().operands()); for (size_t j = 0; j < negateMe.size(); ++j) { operands.push_back(not_exprt(negateMe[j])); } operands.erase(operands.begin() + i); } else { bool duplicate = false; for (size_t j = 0; j < i; ++j) { if (operands[j] == operands[i]) { duplicate = true; break; } } if (duplicate) { operands.erase(operands.begin() + i); } else { ++i; } } } if (operands.size() == 0) { return false_exprt(); } else if (operands.size() == 1) { return operands[0]; } else { return disjunction(operands); } } else if (e.id() == ID_equal) { if (e.op0() == e.op1()) return true_exprt(); } return e; } template exprt bitVector::simplify (const exprt &e) const { #ifndef INLINESIMP return e; #endif exprt r(simplify_local_constant_fold(e)); if (r.id() == ID_constant) return r; if (e.id() == ID_if) { return simplify_if(to_if_expr(e)); } return e; } // Instantiate template exprt bitVector::simplify (const exprt &e) const; template exprt bitVector::simplify (const exprt &e) const; } // Use improved version of some of the operations #ifndef SYMFPU_WORDLEVEL_ENCODINGS template <> cprover_exprt::traits::ubv orderEncode (const cprover_exprt::traits::ubv &b) { return orderEncodeBitwise(b); } template <> stickyRightShiftResult stickyRightShift (const cprover_exprt::traits::ubv &input, const cprover_exprt::traits::ubv &shiftAmount) { return stickyRightShiftBitwise(input, shiftAmount); } #endif template <> void probabilityAnnotation (const cprover_exprt::traits::prop &p, const probability &pr) { boolbv_symfput::probablity_annotations.insert(std::make_pair(p, pr)); return; } }