mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 03:32:28 +00:00 
			
		
		
		
	* Introduce X-macro-based trace tag definition - Created trace_tags.def to centralize TRACE tag definitions - Each tag includes a symbolic name and description - Set up enum class TraceTag for type-safe usage in TRACE macros * Add script to generate Markdown documentation from trace_tags.def - Python script parses trace_tags.def and outputs trace_tags.md * Refactor TRACE_NEW to prepend TraceTag and pass enum to is_trace_enabled * trace: improve trace tag handling system with hierarchical tagging - Introduce hierarchical tag-class structure: enabling a tag class activates all child tags - Unify TRACE, STRACE, SCTRACE, and CTRACE under enum TraceTag - Implement initial version of trace_tag.def using X(tag, tag_class, description) (class names and descriptions to be refined in a future update) * trace: replace all string-based TRACE tags with enum TraceTag - Migrated all TRACE, STRACE, SCTRACE, and CTRACE macros to use enum TraceTag values instead of raw string literals * trace : add cstring header * trace : Add Markdown documentation generation from trace_tags.def via mk_api_doc.py * trace : rename macro parameter 'class' to 'tag_class' and remove Unicode comment in trace_tags.h. * trace : Add TODO comment for future implementation of tag_class activation * trace : Disable code related to tag_class until implementation is ready (#7663).
		
			
				
	
	
		
			289 lines
		
	
	
	
		
			9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			289 lines
		
	
	
	
		
			9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*++
 | |
|   Copyright (c) 2020 Microsoft Corporation
 | |
| 
 | |
|   Module Name:
 | |
| 
 | |
|    sat_lut_finder.cpp
 | |
| 
 | |
|   Abstract:
 | |
|    
 | |
|     lut finder
 | |
| 
 | |
|   Author:
 | |
| 
 | |
|     Nikolaj Bjorner 2020-01-02
 | |
| 
 | |
|   Notes:
 | |
|   
 | |
| 
 | |
|   --*/
 | |
| 
 | |
| #include "sat/sat_lut_finder.h"
 | |
| #include "sat/sat_solver.h"
 | |
| 
 | |
| namespace sat {
 | |
| 
 | |
|     void lut_finder::operator()(clause_vector& clauses) {
 | |
|         m_removed_clauses.reset();
 | |
|         unsigned max_size = m_max_lut_size;
 | |
|         // we better have enough bits in the combination mask to 
 | |
|         // handle clauses up to max_size.
 | |
|         // max_size = 5 -> 32 bits
 | |
|         // max_size = 6 -> 64 bits
 | |
|         SASSERT(sizeof(m_combination)*8 >= (1ull << static_cast<uint64_t>(max_size)));
 | |
|         init_clause_filter();
 | |
|         for (unsigned i = 0; i <= 6; ++i) {
 | |
|             m_masks[i] = cut::effect_mask(i);
 | |
|         }
 | |
|         m_var_position.resize(s.num_vars());
 | |
|         for (clause* cp : clauses) {
 | |
|             cp->unmark_used();
 | |
|         }
 | |
|         for (; max_size > 2; --max_size) {
 | |
|             for (clause* cp : clauses) {
 | |
|                 clause& c = *cp;
 | |
|                 if (c.size() == max_size && !c.was_removed() && !c.is_learned() && !c.was_used()) {
 | |
|                     check_lut(c);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         m_clause_filters.clear();
 | |
|         
 | |
|         for (clause* cp : clauses) cp->unmark_used();
 | |
|         for (clause* cp : m_removed_clauses) cp->mark_used();
 | |
|         std::function<bool(clause*)> not_used = [](clause* cp) { return !cp->was_used(); };
 | |
|         clauses.filter_update(not_used);
 | |
|     }
 | |
| 
 | |
|     void lut_finder::check_lut(clause& c) {
 | |
|         SASSERT(c.size() > 2);
 | |
|         unsigned filter = get_clause_filter(c);
 | |
|         s.init_visited();
 | |
|         unsigned mask = 0, i = 0;        
 | |
|         m_vars.reset();
 | |
|         m_clause.reset();
 | |
|         for (literal l : c) {
 | |
|             m_clause.push_back(l);
 | |
|         }
 | |
|         // ensure that variables in returned LUT are sorted
 | |
|         std::sort(m_clause.begin(), m_clause.end());
 | |
|         for (literal l : m_clause) {
 | |
|             m_vars.push_back(l.var());
 | |
|             m_var_position[l.var()] = i;
 | |
|             s.mark_visited(l.var());
 | |
|             mask |= (l.sign() << (i++)); 
 | |
|         }
 | |
|         m_clauses_to_remove.reset();
 | |
|         m_clauses_to_remove.push_back(&c);
 | |
|         m_combination = 0;
 | |
|         m_num_combinations = 0;
 | |
|         set_combination(mask);
 | |
|         c.mark_used();
 | |
|         for (literal l : c) {
 | |
|             for (auto const& cf : m_clause_filters[l.var()]) {                
 | |
|                 if ((filter == (filter | cf.m_filter)) && 
 | |
|                     !cf.m_clause->was_used() &&
 | |
|                     extract_lut(*cf.m_clause)) {
 | |
|                     add_lut();
 | |
|                     return;
 | |
|                 }
 | |
|             }
 | |
|             // TBD: replace by BIG
 | |
|             // loop over binary clauses in watch list
 | |
|             for (watched const & w : s.get_wlist(l)) {
 | |
|                 if (w.is_binary_clause() && s.is_visited(w.get_literal().var()) && w.get_literal().index() < l.index()) {
 | |
|                     if (extract_lut(~l, w.get_literal())) {
 | |
|                         add_lut();
 | |
|                         return;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             l.neg();
 | |
|             for (watched const & w : s.get_wlist(l)) {
 | |
|                 if (w.is_binary_clause() && s.is_visited(w.get_literal().var()) && w.get_literal().index() < l.index()) {
 | |
|                     if (extract_lut(~l, w.get_literal())) {
 | |
|                         add_lut();
 | |
|                         return;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     void lut_finder::add_lut() {
 | |
|         DEBUG_CODE(for (clause* cp : m_clauses_to_remove) VERIFY(cp->was_used()););
 | |
|         m_removed_clauses.append(m_clauses_to_remove);
 | |
|         bool_var v;
 | |
|         uint64_t lut = convert_combination(m_vars, v);
 | |
|         TRACE(aig_simplifier,
 | |
|               for (clause* cp : m_clauses_to_remove) {
 | |
|                   tout << *cp << "\n" << v << ": " << m_vars << "\n";
 | |
|               }
 | |
|               display_mask(tout, lut, 1u << m_vars.size()) << "\n";);
 | |
|         m_on_lut(lut, m_vars, v);
 | |
|     }
 | |
| 
 | |
|     bool lut_finder::extract_lut(literal l1, literal l2) {
 | |
|         SASSERT(s.m_visited.is_visited(l1.var()));
 | |
|         SASSERT(s.m_visited.is_visited(l2.var()));
 | |
|         m_missing.reset();
 | |
|         unsigned mask = 0;
 | |
|         for (unsigned i = 0; i < m_vars.size(); ++i) {
 | |
|             if (m_vars[i] == l1.var()) {
 | |
|                 mask |= (l1.sign() << i);
 | |
|             }
 | |
|             else if (m_vars[i] == l2.var()) {
 | |
|                 mask |= (l2.sign() << i);
 | |
|             }
 | |
|             else {
 | |
|                 m_missing.push_back(i);
 | |
|             }
 | |
|         }
 | |
|         return update_combinations(mask);
 | |
|     }
 | |
| 
 | |
|     bool lut_finder::extract_lut(clause& c2) {
 | |
|         for (literal l : c2) {            
 | |
|             if (!s.is_visited(l.var())) 
 | |
|                 return false;
 | |
|         }
 | |
|         if (c2.size() == m_vars.size()) {
 | |
|             m_clauses_to_remove.push_back(&c2);
 | |
|             c2.mark_used();
 | |
|         }
 | |
|         // insert missing
 | |
|         unsigned mask = 0;
 | |
|         m_missing.reset();
 | |
|         SASSERT(c2.size() <= m_vars.size());
 | |
|         for (unsigned i = 0; i < m_vars.size(); ++i) {
 | |
|             m_clause[i] = null_literal;
 | |
|         }
 | |
|         for (literal l : c2) {
 | |
|             unsigned pos = m_var_position[l.var()];
 | |
|             m_clause[pos] = l;
 | |
|         }
 | |
|         for (unsigned j = 0; j < m_vars.size(); ++j) {
 | |
|             literal lit = m_clause[j];
 | |
|             if (lit == null_literal) {
 | |
|                 m_missing.push_back(j);
 | |
|             }
 | |
|             else {
 | |
|                 mask |= (m_clause[j].sign() << j);
 | |
|             }
 | |
|         }                    
 | |
|         return update_combinations(mask);
 | |
|     }
 | |
| 
 | |
|     void lut_finder::set_combination(unsigned mask) {
 | |
|         if (!get_combination(mask)) { 
 | |
|             m_combination |= (1ull << mask); 
 | |
|             m_num_combinations++;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     bool lut_finder::update_combinations(unsigned mask) {
 | |
|         unsigned num_missing = m_missing.size();
 | |
|         for (unsigned k = 0; k < (1ul << num_missing); ++k) {
 | |
|             unsigned mask2 = mask;
 | |
|             for (unsigned i = 0; i < num_missing; ++i) {
 | |
|                 if ((k & (1 << i)) != 0) {
 | |
|                     mask2 |= 1ul << m_missing[i];
 | |
|                 }
 | |
|             }
 | |
|             set_combination(mask2);
 | |
|         }
 | |
|         return lut_is_defined(m_vars.size());
 | |
|     }
 | |
| 
 | |
|     bool lut_finder::lut_is_defined(unsigned sz) {
 | |
|         if (m_num_combinations < (1ull << (sz/2))) 
 | |
|             return false;
 | |
|         for (unsigned i = sz; i-- > 0; ) {
 | |
|             if (lut_is_defined(i, sz)) 
 | |
|                 return true;
 | |
|         }
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * \brief check if all output combinations for variable i are defined.
 | |
|      */
 | |
|     bool lut_finder::lut_is_defined(unsigned i, unsigned sz) {
 | |
|         uint64_t c = m_combination | (m_combination >> (1ull << (uint64_t)i));
 | |
|         uint64_t m = m_masks[i];
 | |
|         if (sz < 6) m &= ((1ull << (1ull << sz)) - 1);
 | |
|         return (c & m) == m;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * find variable where it is defined
 | |
|      * convert bit-mask to truth table for that variable.
 | |
|      * remove variable from vars, 
 | |
|      * return truth table.
 | |
|      */
 | |
| 
 | |
|     uint64_t lut_finder::convert_combination(bool_var_vector& vars, bool_var& v) {
 | |
|         SASSERT(lut_is_defined(vars.size()));
 | |
|         unsigned i = 0;
 | |
|         for (i = vars.size(); i-- > 0; ) {
 | |
|             if (lut_is_defined(i, vars.size())) {
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
|         SASSERT(i < vars.size());
 | |
|         v = vars[i];
 | |
|         vars.erase(v);
 | |
|         uint64_t r = 0;
 | |
|         uint64_t m = m_masks[i];
 | |
|         unsigned offset = 0;
 | |
|         // example, if i = 2, then we are examining 
 | |
|         // how m_combination evaluates at position xy0uv
 | |
|         // If it evaluates to 0, then it has to evaluate to 1 on position xy1uv
 | |
|         // Offset keeps track of the value of xyuv
 | |
|         // 
 | |
|         for (unsigned j = 0; j < 64; ++j) {
 | |
|             if (0 != (m & (1ull << j))) {
 | |
|                 if (0 != (m_combination & (1ull << j))) {
 | |
|                     r |= 1ull << offset;
 | |
|                 }
 | |
|                 ++offset;
 | |
|             }
 | |
|         }
 | |
|         return r;
 | |
|     }
 | |
| 
 | |
|     void lut_finder::init_clause_filter() {
 | |
|         m_clause_filters.reset();
 | |
|         m_clause_filters.resize(s.num_vars());
 | |
|         init_clause_filter(s.m_clauses);
 | |
|         init_clause_filter(s.m_learned);
 | |
|     }
 | |
| 
 | |
|     void lut_finder::init_clause_filter(clause_vector& clauses) {
 | |
|         for (clause* cp : clauses) {
 | |
|             clause& c = *cp;
 | |
|             if (c.size() <= m_max_lut_size && s.all_distinct(c)) {
 | |
|                 clause_filter cf(get_clause_filter(c), cp);
 | |
|                 for (literal l : c) {
 | |
|                     m_clause_filters[l.var()].push_back(cf);
 | |
|                 }            
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     unsigned lut_finder::get_clause_filter(clause const& c) {
 | |
|         unsigned filter = 0;
 | |
|         for (literal l : c) {
 | |
|             filter |= 1 << ((l.var() % 32));
 | |
|         }
 | |
|         return filter;
 | |
|     }
 | |
| 
 | |
|     std::ostream& lut_finder::display_mask(std::ostream& out, uint64_t mask, unsigned sz) const {
 | |
|         for (unsigned i = 0; i < sz; ++i) {
 | |
|             out << ((0 != (((mask >> i)) & 0x1)) ? "1" : "0");
 | |
|         }
 | |
|         return out;
 | |
|     }
 | |
| 
 | |
| }
 |