From 2b90ce6b79b4c83965a778b68363ea4997a2b7fd Mon Sep 17 00:00:00 2001 From: Igor Kirillov Date: Mon, 3 Nov 2025 15:13:56 +0000 Subject: [PATCH] Aarch64: fold movsbq+shlqi into sbfizq - add the sbfizq VASM opcode with ARM lowering - teach the ARM simplifier to replace movsbq+shlqi with sbfizq - mark the new instruction as pure for effects analysis --- hphp/runtime/vm/jit/vasm-arm.cpp | 1 + hphp/runtime/vm/jit/vasm-info.cpp | 1 + hphp/runtime/vm/jit/vasm-instr.cpp | 1 + hphp/runtime/vm/jit/vasm-instr.h | 2 ++ hphp/runtime/vm/jit/vasm-simplify-arm.cpp | 21 +++++++++++++++++++++ 5 files changed, 26 insertions(+) diff --git a/hphp/runtime/vm/jit/vasm-arm.cpp b/hphp/runtime/vm/jit/vasm-arm.cpp index e972222e9abfcb..a665a4866e9e9d 100644 --- a/hphp/runtime/vm/jit/vasm-arm.cpp +++ b/hphp/runtime/vm/jit/vasm-arm.cpp @@ -450,6 +450,7 @@ struct Vgen { void emit(const mrs& i) { a->Mrs(X(i.r), vixl::SystemRegister(i.s.l())); } void emit(const msr& i) { a->Msr(vixl::SystemRegister(i.s.l()), X(i.r)); } void emit(const ubfmli& i) { a->ubfm(W(i.d), W(i.s), i.mr.w(), i.ms.w()); } + void emit(const sbfizq& i) { a->Sbfiz(X(i.d), X(i.s), i.shift.l(), i.width.l()); } void emit(const storepair& i) { a->Stp(X(i.s0), X(i.s1), M(i.d)); } void emit(const storepairl& i) { a->Stp(W(i.s0), W(i.s1), M(i.d)); } void emit(const loadpair& i) { a->Ldp(X(i.d0), X(i.d1), M(i.s)); } diff --git a/hphp/runtime/vm/jit/vasm-info.cpp b/hphp/runtime/vm/jit/vasm-info.cpp index 33d2dc0b856441..313259370a105c 100644 --- a/hphp/runtime/vm/jit/vasm-info.cpp +++ b/hphp/runtime/vm/jit/vasm-info.cpp @@ -247,6 +247,7 @@ bool effectsImpl(const Vinstr& inst, bool pure) { case Vinstr::sar: case Vinstr::sarq: case Vinstr::sarqi: + case Vinstr::sbfizq: case Vinstr::setcc: case Vinstr::shl: case Vinstr::shr: diff --git a/hphp/runtime/vm/jit/vasm-instr.cpp b/hphp/runtime/vm/jit/vasm-instr.cpp index 4d0acd4fff29ba..3ddce8794c2825 100644 --- a/hphp/runtime/vm/jit/vasm-instr.cpp +++ b/hphp/runtime/vm/jit/vasm-instr.cpp @@ -356,6 +356,7 @@ Width width(Vinstr::Opcode op) { case Vinstr::sarqi: case Vinstr::shlqi: case Vinstr::shrqi: + case Vinstr::sbfizq: case Vinstr::subq: case Vinstr::subqi: case Vinstr::subqim: diff --git a/hphp/runtime/vm/jit/vasm-instr.h b/hphp/runtime/vm/jit/vasm-instr.h index 2fa51dc98fa962..6f1e70e11622cf 100644 --- a/hphp/runtime/vm/jit/vasm-instr.h +++ b/hphp/runtime/vm/jit/vasm-instr.h @@ -362,6 +362,7 @@ struct Vunit; O(mrs, I(s), Un, D(r))\ O(msr, I(s), U(r), Dn)\ O(ubfmli, I(mr) I(ms), U(s), D(d))\ + O(sbfizq, I(shift) I(width), U(s), D(d))\ O(loadpair, Inone, U(s), D(d0) D(d1))\ O(loadpairl, Inone, U(s), D(d0) D(d1))\ O(storepair, Inone, U(s0) U(s1) UW(d), Dn)\ @@ -1280,6 +1281,7 @@ struct fcvtzs { VregDbl s; Vreg64 d;}; struct mrs { Immed s; Vreg64 r; }; struct msr { Vreg64 r; Immed s; }; struct ubfmli { Immed mr, ms; Vreg32 s, d; }; +struct sbfizq { Immed shift, width; Vreg64 s, d; }; struct loadpair { Vptr128 s; Vreg64 d0, d1; }; struct loadpairl { Vptr64 s; Vreg32 d0, d1; }; struct storepair { Vreg64 s0, s1; Vptr128 d; }; diff --git a/hphp/runtime/vm/jit/vasm-simplify-arm.cpp b/hphp/runtime/vm/jit/vasm-simplify-arm.cpp index cc7c363dba01eb..93cc25e08a59e6 100644 --- a/hphp/runtime/vm/jit/vasm-simplify-arm.cpp +++ b/hphp/runtime/vm/jit/vasm-simplify-arm.cpp @@ -152,6 +152,27 @@ bool simplify(Env& env, const movzbl& inst, Vlabel b, size_t i) { /////////////////////////////////////////////////////////////////////////////// +bool simplify(Env& env, const movsbq& inst, Vlabel b, size_t i) { + // movsbq{s, tmp}; shlqi{imm, tmp, d} -> sbfizq{imm, 8, s, d} + return if_inst(env, b, i + 1, [&] (const shlqi& sh) { + if (inst.d != sh.s1) return false; + if (env.use_counts[inst.d] != 1) return false; + if (sh.fl) return false; + if (sh.sf.isValid() && env.use_counts[sh.sf]) return false; + + auto const shift = sh.s0.l(); + if (shift < 0 || shift > 56) return false; + + return simplify_impl(env, b, i, [&] (Vout& v) { + auto const src = Vreg64(Vreg(inst.s)); + v << sbfizq{sh.s0, Immed{8}, src, sh.d}; + return 2; + }); + }); +} + +/////////////////////////////////////////////////////////////////////////////// + int is_adjacent_vptr64(const Vptr64& a, const Vptr64& b, int32_t step, int32_t min_disp, int32_t max_disp) { const int32_t min_disp_val = a.disp < b.disp ? a.disp : b.disp; if (a.base.isValid() && b.base.isValid() &&