Esempio n. 1
0
void optimizeJmps(Vunit& unit) {
  auto isEmpty = [&](Vlabel b, Vinstr::Opcode op) {
    auto& code = unit.blocks[b].code;
    return code.size() == 1 && op == code[0].op;
  };
  bool changed = false;
  bool ever_changed = false;
  jit::vector<int> npreds(unit.blocks.size(), 0);
  do {
    if (changed) {
      fill(npreds.begin(), npreds.end(), 0);
    }
    changed = false;
    PostorderWalker{unit}.dfs([&](Vlabel b) {
      for (auto s : succs(unit.blocks[b])) {
        npreds[s]++;
      }
    });
    // give roots an extra predecessor to prevent cloning them.
    for (auto b : unit.roots) {
      npreds[b]++;
    }
    PostorderWalker{unit}.dfs([&](Vlabel b) {
      auto& block = unit.blocks[b];
      auto& code = block.code;
      assert(!code.empty());
      if (code.back().op == Vinstr::jcc) {
        auto ss = succs(block);
        if (ss[0] == ss[1]) {
          // both edges have same target, change to jmp
          code.back() = jmp{ss[0]};
          changed = true;
        }
      }
      if (code.back().op == Vinstr::jmp) {
        auto& s = code.back().jmp_.target;
        if (isEmpty(s, Vinstr::jmp)) {
          // skip over s
          s = unit.blocks[s].code.back().jmp_.target;
          changed = true;
        } else if (npreds[s] == 1 || isEmpty(s, Vinstr::jcc)) {
          // overwrite jmp with copy of s
          auto& code2 = unit.blocks[s].code;
          code.pop_back();
          code.insert(code.end(), code2.begin(), code2.end());
          changed = true;
        }
      } else {
        for (auto& s : succs(block)) {
          if (isEmpty(s, Vinstr::jmp)) {
            // skip over s
            s = unit.blocks[s].code.back().jmp_.target;
            changed = true;
          }
        }
      }
    });
    ever_changed |= changed;
  } while (changed);
  if (ever_changed) {
    printUnit(kVasmJumpsLevel, "after vasm-jumps", unit);
  }
}
Esempio n. 2
0
void optimizeJmps(Vunit& unit) {
    auto isEmpty = [&](Vlabel b, Vinstr::Opcode op) {
        auto& code = unit.blocks[b].code;
        return code.size() == 1 && op == code[0].op;
    };
    bool changed = false;
    bool ever_changed = false;
    // The number of incoming edges from (reachable) predecessors for each block.
    // It is maintained as an upper bound of the actual value during the
    // transformation.
    jit::vector<int> npreds(unit.blocks.size(), 0);
    do {
        if (changed) {
            std::fill(begin(npreds), end(npreds), 0);
        }
        changed = false;
        PostorderWalker{unit} .dfs([&](Vlabel b) {
            for (auto s : succs(unit.blocks[b])) {
                npreds[s]++;
            }
        });
        // give entry an extra predecessor to prevent cloning it.
        npreds[unit.entry]++;

        PostorderWalker{unit} .dfs([&](Vlabel b) {
            auto& block = unit.blocks[b];
            auto& code = block.code;
            assertx(!code.empty());
            if (code.back().op == Vinstr::jcc) {
                auto ss = succs(block);
                if (ss[0] == ss[1]) {
                    // both edges have same target, change to jmp
                    code.back() = jmp{ss[0]};
                    --npreds[ss[0]];
                    changed = true;
                } else {
                    auto jcc_i = code.back().jcc_;
                    if (isEmpty(jcc_i.targets[0], Vinstr::fallback)) {
                        jcc_i = jcc{ccNegate(jcc_i.cc), jcc_i.sf,
                            {jcc_i.targets[1], jcc_i.targets[0]}};
                    }
                    if (isEmpty(jcc_i.targets[1], Vinstr::fallback)) {
                        // replace jcc with fallbackcc and jmp
                        const auto& fb_i = unit.blocks[jcc_i.targets[1]].code[0].fallback_;
                        const auto t0 = jcc_i.targets[0];
                        const auto jcc_origin = code.back().origin;
                        code.pop_back();
                        code.emplace_back(
                            fallbackcc{jcc_i.cc, jcc_i.sf, fb_i.dest, fb_i.trflags});
                        code.back().origin = jcc_origin;
                        code.emplace_back(jmp{t0});
                        code.back().origin = jcc_origin;
                        changed = true;
                    }
                }
            }

            for (auto& s : succs(block)) {
                if (isEmpty(s, Vinstr::jmp)) {
                    // skip over s
                    --npreds[s];
                    s = unit.blocks[s].code.back().jmp_.target;
                    ++npreds[s];
                    changed = true;
                }
            }

            if (code.back().op == Vinstr::jmp) {
                auto s = code.back().jmp_.target;
                if (npreds[s] == 1 || isEmpty(s, Vinstr::jcc)) {
                    // overwrite jmp with copy of s
                    auto& code2 = unit.blocks[s].code;
                    code.pop_back();
                    code.insert(code.end(), code2.begin(), code2.end());
                    if (--npreds[s]) {
                        for (auto ss : succs(block)) {
                            ++npreds[ss];
                        }
                    }
                    changed = true;
                }
            }
        });
        ever_changed |= changed;
    } while (changed);
    if (ever_changed) {
        printUnit(kVasmJumpsLevel, "after vasm-jumps", unit);
    }
}