Don't undef rewrite if var unused in the preceding ctrl flow
MODIFY
ir/state.cpp
ir/state.cpp
@@ -43,6 +43,7 @@ static T intersect_set(const T &a, const T &b) {
void State::ValueAnalysis::intersect(const State::ValueAnalysis &other) {
non_poison_vals = intersect_set(non_poison_vals, other.non_poison_vals);
non_undef_vals = intersect_set(non_undef_vals, other.non_undef_vals);
+ unused_vars = intersect_set(unused_vars, other.unused_vars);
for (auto &[fn, interval] : other.ranges_fn_calls) {
auto [I, inserted] = ranges_fn_calls.try_emplace(fn, 0, interval.second);
@@ -96,7 +97,8 @@ const StateValue& State::exec(const Value &v) {
assert(undef_vars.empty());
auto val = v.toSMT(*this);
ENSURE(values_map.try_emplace(&v, (unsigned)values.size()).second);
- values.emplace_back(&v, ValTy(move(val), move(undef_vars)), false);
+ values.emplace_back(&v, ValTy(move(val), move(undef_vars)));
+ analysis.unused_vars.insert(&v);
// cleanup potentially used temporary values due to undef rewriting
while (i_tmp_values > 0) {
@@ -263,7 +265,7 @@ expr State::strip_undef_and_add_ub(const Value &val, const expr &e) {
}
const StateValue& State::operator[](const Value &val) {
- auto &[var, val_uvars, used] = values[values_map.at(&val)];
+ auto &[var, val_uvars] = values[values_map.at(&val)];
auto &[sval, uvars] = val_uvars;
(void)var;
@@ -304,8 +306,11 @@ const StateValue& State::operator[](const Value &val) {
return simplify(sval, true);
}
- if (uvars.empty() || !used || disable_undef_rewrite) {
- used = true;
+ auto unused_itr = analysis.unused_vars.find(&val);
+ bool unused = unused_itr != analysis.unused_vars.end();
+ if (uvars.empty() || unused || disable_undef_rewrite) {
+ if (unused)
+ analysis.unused_vars.erase(unused_itr);
undef_vars.insert(uvars.begin(), uvars.end());
return simplify(sval, true);
}

MODIFY
ir/state.h
ir/state.h
@@ -51,6 +51,8 @@ private:
std::set<const Value *> non_poison_vals; // vars that are not poison
// vars that are not undef (partially undefs are not allowed too)
std::map<const Value *, smt::expr> non_undef_vals;
+ // vars that have never been used
+ std::set<const Value *> unused_vars;
struct FnCallRanges
: public std::map<std::string, std::pair<unsigned, unsigned>> {
@@ -80,9 +82,9 @@ private:
const BasicBlock *current_bb = nullptr;
std::set<smt::expr> quantified_vars;
- // var -> ((value, not_poison), undef_vars, already_used?)
+ // var -> ((value, not_poison), undef_vars)
std::unordered_map<const Value*, unsigned> values_map;
- std::vector<std::tuple<const Value*, ValTy, bool>> values;
+ std::vector<std::pair<const Value*, ValTy>> values;
// dst BB -> src BB -> BasicBlockInfo
std::unordered_map<const BasicBlock*,

MODIFY
tools/transform.cpp
tools/transform.cpp
@@ -149,8 +149,7 @@ static void error(Errors &errs, State &src_state, State &tgt_state,
s << " for " << *var;
s << "\n\nExample:\n";
- for (auto &[var, val, used] : src_state.getValues()) {
- (void)used;
+ for (auto &[var, val] : src_state.getValues()) {
if (!dynamic_cast<const Input*>(var) &&
!dynamic_cast<const ConstantInput*>(var))
continue;
@@ -169,8 +168,7 @@ static void error(Errors &errs, State &src_state, State &tgt_state,
}
}
- for (auto &[var, val, used] : st->getValues()) {
- (void)used;
+ for (auto &[var, val] : st->getValues()) {
auto &name = var->getName();
if (name == var_name)
break;
@@ -945,7 +943,7 @@ Errors TransformVerify::verify() const {
auto [src_state, tgt_state] = exec();
if (check_each_var) {
- for (auto &[var, val, used] : src_state->getValues()) {
+ for (auto &[var, val] : src_state->getValues()) {
auto &name = var->getName();
if (name[0] != '%' || !dynamic_cast<const Instr*>(var))
continue;

Don't undef rewrite if var unused in the preceding ctrl flow (#521)