Пример #1
0
bool simplify_impl(Env& env, Vlabel b, size_t i, Simplify simplify) {
  auto& unit = env.unit;

  return vmodify(unit, b, i, [&] (Vout& v) {
    auto& blocks = unit.blocks;
    auto const nremove = simplify(v);

    // Update use counts for to-be-removed instructions.
    for (auto j = i; j < i + nremove; ++j) {
      visitUses(unit, blocks[b].code[j], [&] (Vreg r) {
        --env.use_counts[r];
      });
    }

    // Update use counts and def instructions for to-be-added instructions.
    for (auto const& inst : blocks[Vlabel(v)].code) {
      visitUses(unit, inst, [&] (Vreg r) {
        if (r >= env.use_counts.size()) {
          env.use_counts.resize(size_t{r}+1);
        }
        ++env.use_counts[r];
      });
      visitDefs(unit, inst, [&] (Vreg r) {
        if (r >= env.def_insts.size()) {
          env.def_insts.resize(size_t{r}+1, Vinstr::nop);
        }
        env.def_insts[r] = inst.op;
      });
    }

    return nremove;
  });
}
Пример #2
0
// Return the effect this instruction has on the value of rsp.
// this will assert if an instruction mutates rsp in an untrackable way.
int rspEffect(const Vunit& unit, Vinstr& inst) {
  switch (inst.op) {
    default:
      visitDefs(unit, inst, [&](Vreg r) {
        assert(r != Vreg64(rsp));
      });
      return 0;
    case Vinstr::push:
    case Vinstr::pushl:
    case Vinstr::pushm:
      return -8;
    case Vinstr::pop:
    case Vinstr::popm:
      return 8;
    case Vinstr::addqi: {
      auto& i = inst.addqi_;
      if (i.d == Vreg64(rsp)) {
        assert(i.s1 == Vreg64(rsp));
        return i.s0.l();
      }
      return 0;
    }
    case Vinstr::subqi: {
      auto& i = inst.subqi_;
      if (i.d == Vreg64(rsp)) {
        assert(i.s1 == Vreg64(rsp));
        return -i.s0.l();
      }
      return 0;
    }
  }
}
Пример #3
0
// Remove dead instructions by doing a traditional liveness analysis.
// instructions that mutate memory, physical registers, or status flags
// are considered useful. All branches are considered useful.
//
// Given SSA, there's a faster sparse version of this algorithm that marks
// useful instructions in one pass, then transitively marks pure instructions
// that define inputs to useful instructions. However it requires a mapping
// from vreg numbers to the instruction that defines them, and a way to address
// individual instructions.
//
// We could remove useless branches by computing the post-dominator tree and
// RDF(b) for each block; then a branch is only useful if it controls whether
// or not a useful block executes, and useless branches can be forwarded to
// the nearest useful post-dominator.
void removeDeadCode(Vunit& unit) {
  auto blocks = sortBlocks(unit);
  jit::vector<LiveSet> livein(unit.blocks.size());
  LiveSet live(unit.next_vr);
  auto pass = [&](bool mutate) {
    bool changed = false;
    for (auto blockIt = blocks.end(); blockIt != blocks.begin();) {
      auto b = *--blockIt;
      auto& block = unit.blocks[b];
      live.reset();
      for (auto s : succs(block)) {
        if (!livein[s].empty()) {
          live |= livein[s];
        }
      }
      for (auto i = block.code.end(); i != block.code.begin();) {
        auto& inst = *--i;
        auto useful = effectful(inst);
        visitDefs(unit, inst, [&](Vreg r) {
          if (r.isPhys() || live.test(r)) {
            useful = true;
            live.reset(r);
          }
        });
        if (useful) {
          visitUses(unit, inst, [&](Vreg r) {
            live.set(r);
          });
        } else if (mutate) {
          inst = nop{};
          changed = true;
        }
      }
      if (mutate) {
        assert(live == livein[b]);
      } else {
        if (live != livein[b]) {
          livein[b] = live;
          changed = true;
        }
      }
    }
    return changed;
  };
  // analyze until livein reaches a fixed point
  while (pass(false)) {}
  // nop-out useless instructions
  if (pass(true)) {
    for (auto b : blocks) {
      auto& code = unit.blocks[b].code;
      auto end = std::remove_if(code.begin(), code.end(), [&](Vinstr& inst) {
        return inst.op == Vinstr::nop;
      });
      code.erase(end, code.end());
    }
    printUnit(kVasmDCELevel, "after vasm-dead", unit);
  }
}
Пример #4
0
// Remove dead instructions by doing a traditional liveness analysis.
// instructions that mutate memory, physical registers, or status flags
// are considered useful. All branches are considered useful.
//
// Given SSA, there's a faster sparse version of this algorithm that marks
// useful instructions in one pass, then transitively marks pure instructions
// that define inputs to useful instructions. However it requires a mapping
// from vreg numbers to the instruction that defines them, and a way to address
// individual instructions.
//
// We could remove useless branches by computing the post-dominator tree and
// RDF(b) for each block; then a branch is only useful if it controls whether
// or not a useful block executes, and useless branches can be forwarded to
// the nearest useful post-dominator.
void removeDeadCode(Vunit& unit) {
  Timer timer(Timer::vasm_dce);
  auto blocks = sortBlocks(unit);
  jit::vector<LiveSet> livein(unit.blocks.size());
  LiveSet live(unit.next_vr);

  auto pass = [&](bool mutate) {
    bool changed = false;
    for (auto blockIt = blocks.end(); blockIt != blocks.begin();) {
      auto b = *--blockIt;
      auto& block = unit.blocks[b];
      live.reset();
      for (auto s : succs(block)) {
        if (!livein[s].empty()) {
          live |= livein[s];
        }
      }
      for (auto i = block.code.end(); i != block.code.begin();) {
        auto& inst = *--i;
        auto useful = effectful(inst);
        visitDefs(unit, inst, [&](Vreg r) {
          if (r.isPhys() || live.test(r)) {
            useful = true;
            live.reset(r);
          }
        });
        if (useful) {
          visitUses(unit, inst, [&](Vreg r) {
            live.set(r);
          });
        } else if (mutate) {
          inst = nop{};
          changed = true;
        }
      }
      if (mutate) {
        assertx(live == livein[b]);
      } else {
        if (live != livein[b]) {
          livein[b] = live;
          changed = true;
        }
      }
    }
    return changed;
  };

  // analyze until livein reaches a fixed point
  while (pass(false)) {}
  auto const changed = pass(true);
  removeTrivialNops(unit);
  if (changed) {
    printUnit(kVasmDCELevel, "after vasm-dead", unit);
  }
}