From 326d6bd071aeffd5a5e5a8a33c95aef3f00c34fa Mon Sep 17 00:00:00 2001 From: Rick Lavoie Date: Fri, 7 Dec 2018 14:33:36 -0800 Subject: [PATCH] Add more vasm visitors Summary: Add a few more vasm visitors. These let you visit "across" Vregs and mutate Vregs while you visit. Reviewed By: mofarrell Differential Revision: D13287210 fbshipit-source-id: abb0cb1c195939c162dc1a9eef9c8cd0bd55cdd1 --- hphp/runtime/vm/jit/vasm-visit.h | 177 ++++++++++++++++++++++++++++++++++++++- hphp/runtime/vm/jit/vasm-xls.cpp | 1 + 2 files changed, 176 insertions(+), 2 deletions(-) diff --git a/hphp/runtime/vm/jit/vasm-visit.h b/hphp/runtime/vm/jit/vasm-visit.h index b5bc6160dc9..63804ef26d1 100644 --- a/hphp/runtime/vm/jit/vasm-visit.h +++ b/hphp/runtime/vm/jit/vasm-visit.h @@ -135,6 +135,32 @@ void visitDefs(const Vunit& unit, const Vinstr& inst, Def def) { } } +template +void visitAcrosses(const Vunit& unit, const Vinstr& inst, Across across) { + switch (inst.op) { +#define O(name, imms, uses, defs) \ + case Vinstr::name: { \ + auto& i = inst.name##_; (void)i; \ + uses \ + break; \ + } +#define U(s) +#define UA(s) visit(unit, i.s, across); +#define UH(s,h) +#define UM(s) +#define UW(s) +#define Un + VASM_OPCODES +#undef Un +#undef UW +#undef UM +#undef UH +#undef UA +#undef U +#undef O + } +} + /* * visitOperands visits all operands of the given instruction, calling * visitor.imm(), visitor.use(), visitor.across(), and visitor.def() as defined @@ -185,6 +211,153 @@ visitOperands(Tinstr& inst, Visitor& visitor) { /////////////////////////////////////////////////////////////////////////////// +/* Build VregSets from uses/acrosses/defs of a given Vinstr */ + +inline VregSet usesSet(const Vunit& unit, const Vinstr& inst) { + VregSet uses; + visitUses(unit, inst, [&] (Vreg r) { uses.add(r); }); + return uses; +} + +inline VregSet acrossesSet(const Vunit& unit, const Vinstr& inst) { + VregSet acrosses; + visitAcrosses(unit, inst, [&] (Vreg r) { acrosses.add(r); }); + return acrosses; +} + +inline VregSet defsSet(const Vunit& unit, const Vinstr& inst) { + VregSet defs; + visitDefs(unit, inst, [&] (Vreg r) { defs.add(r); }); + return defs; +} + +/////////////////////////////////////////////////////////////////////////////// + +namespace detail { + +template +struct MutableRegVisitor { + Vunit& unit; + + U u; + D d; + RU ru; + RD rd; + + template void imm(const T&) const {} + template void across(T& r) { use(r); } + template void useHint(T1& r, const T2&) { use(r); } + template void defHint(T1& r, const T2&) { def(r); } + + void use(RegSet r) { r = ru(r); } + void use(Vtuple uses) { for (auto& r : unit.tuples[uses]) use(r); } + void use(Vptr& m) { + if (m.base.isValid()) use(m.base); + if (m.index.isValid()) use(m.index); + } + void use(VcallArgsId a) { + auto& args = unit.vcallArgs[a]; + for (auto& r : args.args) use(r); + for (auto& r : args.simdArgs) use(r); + for (auto& r : args.stkArgs) use(r); + for (auto& r : args.indRetArgs) use(r); + } + template void use(Vr& m) { Vreg r = m; use(r); m = r; } + void use(Vreg& r) { r = u((Vreg)r); } + + void def(RegSet r) const { r = rd(r); } + void def(Vtuple defs) { for (auto& r : unit.tuples[defs]) def(r); } + template void def(Vr& m) { Vreg r = m; def(r); m = r; } + void def(Vreg& r) { r = d((Vreg)r); } +}; + +} + +/* + * Visit all the register operands of a Vinstr, calling 'u' for uses, 'd' for + * defs, 'ru' for use RegSets, 'rd' for def RegSets. The callables return a new + * Vreg/RegSet, causing the Vinstr to be rewritten with that Vreg/RegSet. + */ +template +void visitRegsMutable(Vunit& unit, + Vinstr& instr, + U&& u, + D&& d, + RU&& ru, + RD&& rd) { + detail::MutableRegVisitor visitor{ + unit, + std::forward(u), + std::forward(d), + std::forward(ru), + std::forward(rd) + }; + visitOperands(instr, visitor); +} + +/* + * Overload for when you don't care about RegSets (they'll be left unchanged). + */ +template +void visitRegsMutable(Vunit& unit, + Vinstr& instr, + U&& u, + D&& d) { + visitRegsMutable( + unit, + instr, + std::forward(u), + std::forward(d), + [](RegSet r) { return r; }, + [](RegSet r) { return r; } + ); +} + +/////////////////////////////////////////////////////////////////////////////// + +namespace detail { + +template struct DefsWithHintsVisitor { + const Vunit& unit; + D d; + + template void imm(const T&) const {} + template void use(const T&) {} + template void across(const T&) {} + template void useHint(const T1&, const T2&) {} + + void defHint(Vreg r1, Vreg r2) { d(r1, r2); } + void defHint(Vtuple v1, Vtuple v2) { + auto const& t1 = unit.tuples[v1]; + auto const& t2 = unit.tuples[v2]; + assertx(t1.size() == t2.size()); + for (size_t i = 0; i < t1.size(); ++i) d(t1[i], t2[i]); + } + + void def(const RegSet& s) { s.forEach([&] (Vreg r) { d(r, Vreg{}); }); } + void def(Vtuple defs) { + for (auto const& r : unit.tuples[defs]) d(r, Vreg{}); + } + void def(Vreg r) { d(r, Vreg{}); } +}; + +} + +/* + * Visit a Vinstr's defs, calling 'd' with the Vreg and its matching hint (if + * any). If there's no hint, an invalid Vreg will be passed as the second + * parameter. + */ +template +void visitDefsWithHints(const Vunit& unit, const Vinstr& instr, D&& d) { + detail::DefsWithHintsVisitor visitor{unit, std::forward(d)}; + visitOperands(instr, visitor); +} + +/////////////////////////////////////////////////////////////////////////////// + /* * Visit reachable blocks, calling `pre' and `post' on each one. */ @@ -234,11 +407,11 @@ private: DfsWalker m_dfs; }; +/////////////////////////////////////////////////////////////////////////////// + using PredVector = jit::vector>; PredVector computePreds(const Vunit& unit); -/////////////////////////////////////////////////////////////////////////////// - }} #endif diff --git a/hphp/runtime/vm/jit/vasm-xls.cpp b/hphp/runtime/vm/jit/vasm-xls.cpp index 9968a65cac7..f2baa5098d6 100644 --- a/hphp/runtime/vm/jit/vasm-xls.cpp +++ b/hphp/runtime/vm/jit/vasm-xls.cpp @@ -933,6 +933,7 @@ struct UseVisitor { * register, but is still correct. */ template void across(R r) { use(r, constraint(r), m_range.end + 1); } + void across(Vtuple uses) { for (auto r : m_unit.tuples[uses]) across(r); } void across(RegSet regs) { regs.forEach([&](Vreg r) { across(r); }); } void across(Vptr m) { if (m.base.isValid()) across(m.base); -- 2.11.4.GIT