| 122 | |
| 123 | template<> |
| 124 | DisjointExpr<expr>::DisjointExpr(const expr &e, unsigned depth_limit) { |
| 125 | if (depth_limit-- == 0) { |
| 126 | add(e, expr(true)); |
| 127 | return; |
| 128 | } |
| 129 | |
| 130 | vector<pair<expr, expr>> worklist = { {e, true} }; |
| 131 | expr cond, then, els, a, b; |
| 132 | unsigned high, low; |
| 133 | |
| 134 | do { |
| 135 | // Limit exponential growth |
| 136 | if ((worklist.size() + vals.size()) >= 32 || |
| 137 | hit_half_memory_limit()) { |
| 138 | for (auto &[v, c] : worklist) { |
| 139 | add(std::move(v), std::move(c)); |
| 140 | } |
| 141 | break; |
| 142 | } |
| 143 | |
| 144 | auto [v, c] = worklist.back(); |
| 145 | worklist.pop_back(); |
| 146 | |
| 147 | if (v.isIf(cond, then, els)) { |
| 148 | worklist.emplace_back(std::move(then), c && cond); |
| 149 | worklist.emplace_back(std::move(els), c && !cond); |
| 150 | } |
| 151 | else if (v.isConcat(a, b)) { |
| 152 | DisjointExpr<expr> lhs(a, depth_limit); |
| 153 | DisjointExpr<expr> rhs(b, depth_limit); |
| 154 | if (lhs.size() == 1 && rhs.size() == 1) { |
| 155 | add(std::move(v), std::move(c)); |
| 156 | continue; |
| 157 | } |
| 158 | |
| 159 | for (auto &[lhs_v, lhs_domain] : lhs) { |
| 160 | if (auto rhs_val = rhs.lookup(lhs_domain)) { |
| 161 | add(lhs_v.concat(*rhs_val), c && lhs_domain); |
| 162 | } else { |
| 163 | expr from; |
| 164 | bool negate = true; |
| 165 | if (!lhs_domain.isNot(from)) { |
| 166 | from = lhs_domain; |
| 167 | negate = false; |
| 168 | } |
| 169 | |
| 170 | for (auto &[rhs_v, rhs_domain] : rhs) { |
| 171 | add(lhs_v.concat(simplify(rhs_v, from, negate)), |
| 172 | c && lhs_domain && rhs_domain); |
| 173 | } |
| 174 | } |
| 175 | } |
| 176 | } |
| 177 | else if (v.isExtract(a, high, low)) { |
| 178 | DisjointExpr<expr> vals(a, depth_limit); |
| 179 | if (vals.size() == 1) { |
| 180 | add(std::move(v), std::move(c)); |
| 181 | continue; |
nothing calls this directly
no test coverage detected