From 4169807870a3cc30e514b6de89500bbcd08dc89f Mon Sep 17 00:00:00 2001 From: Oguz Ulgen Date: Wed, 13 May 2020 16:01:28 -0700 Subject: [PATCH] Add crc32 instruction Reviewed By: ricklavoie Differential Revision: D21531017 fbshipit-source-id: 3a78bd6d4493de9dc090dec4b8faa672435d501b --- hphp/runtime/vm/jit/irlower-internal.cpp | 20 ++++++++++++++++++++ hphp/runtime/vm/jit/irlower-internal.h | 5 +++++ 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-x64.cpp | 7 +++++++ hphp/util/asm-x64-intelxed.h | 2 ++ hphp/util/asm-x64-legacy.h | 10 +++++++--- hphp/util/asm-x64.h | 1 + hphp/util/test/asm.cpp | 18 ++++++++++++++++++ 10 files changed, 64 insertions(+), 3 deletions(-) diff --git a/hphp/runtime/vm/jit/irlower-internal.cpp b/hphp/runtime/vm/jit/irlower-internal.cpp index 9969bf14b29..2e2fe353b0b 100644 --- a/hphp/runtime/vm/jit/irlower-internal.cpp +++ b/hphp/runtime/vm/jit/irlower-internal.cpp @@ -265,6 +265,26 @@ void cgCallNative(Vout& v, IRLS& env, const IRInstruction* inst) { cgCallHelper(v, env, info.func.call, dest, info.sync, args); } +Vreg emitHashInt64(IRLS& env, const IRInstruction* inst, Vreg arr) { + auto& v = vmain(env); + auto const hash = v.makeReg(); + if (arch() == Arch::X64) { +#if defined(USE_HWCRC) && defined(__SSE4_2__) + v << crc32q{arr, v.cns(0), hash}; + return hash; +#endif + } + cgCallHelper( + v, + env, + CallSpec::direct(hash_int64), + callDest(hash), + SyncOptions::Sync, + argGroup(env, inst).reg(arr) + ); + return hash; +} + /////////////////////////////////////////////////////////////////////////////// }}} diff --git a/hphp/runtime/vm/jit/irlower-internal.h b/hphp/runtime/vm/jit/irlower-internal.h index c595a426a12..afb2af84ad5 100644 --- a/hphp/runtime/vm/jit/irlower-internal.h +++ b/hphp/runtime/vm/jit/irlower-internal.h @@ -137,6 +137,11 @@ void emitCheckSurpriseFlags(Vout& v, Vreg fp, Vlabel handleSurprise); void emitCheckSurpriseFlagsEnter(Vout& v, Vout& vcold, Vreg fp, Fixup fixup, Vlabel catchBlock); +/* + * Emits vasm instructions to get crc32 hash of the given arr + */ +Vreg emitHashInt64(IRLS& env, const IRInstruction* inst, Vreg arr); + /////////////////////////////////////////////////////////////////////////////// #define O(name, ...) \ diff --git a/hphp/runtime/vm/jit/vasm-info.cpp b/hphp/runtime/vm/jit/vasm-info.cpp index 7b22e72940e..1345ad9617d 100644 --- a/hphp/runtime/vm/jit/vasm-info.cpp +++ b/hphp/runtime/vm/jit/vasm-info.cpp @@ -187,6 +187,7 @@ bool effectsImpl(const Vinstr& inst, bool pure) { case Vinstr::copy2: case Vinstr::copy: case Vinstr::copyargs: + case Vinstr::crc32q: case Vinstr::csincb: case Vinstr::csincl: case Vinstr::csincq: diff --git a/hphp/runtime/vm/jit/vasm-instr.cpp b/hphp/runtime/vm/jit/vasm-instr.cpp index 591bf6f2728..514812c3cc6 100644 --- a/hphp/runtime/vm/jit/vasm-instr.cpp +++ b/hphp/runtime/vm/jit/vasm-instr.cpp @@ -390,6 +390,7 @@ Width width(Vinstr::Opcode op) { case Vinstr::mulsd: case Vinstr::roundsd: case Vinstr::sqrtsd: + case Vinstr::crc32q: return Width::Quad; case Vinstr::loadups: diff --git a/hphp/runtime/vm/jit/vasm-instr.h b/hphp/runtime/vm/jit/vasm-instr.h index 06c985f5c05..2bc6400525a 100644 --- a/hphp/runtime/vm/jit/vasm-instr.h +++ b/hphp/runtime/vm/jit/vasm-instr.h @@ -340,6 +340,7 @@ struct Vunit; O(sarq, I(fl), UH(s,d), DH(d,s) D(sf))\ O(shlq, I(fl), UH(s,d), DH(d,s) D(sf))\ O(shrq, I(fl), UH(s,d), DH(d,s) D(sf))\ + O(crc32q, Inone, U(s0) UH(s1,d), DH(d,s1))\ /* arm instructions */\ O(csincb, I(cc), U(sf) U(f) U(t), D(d))\ O(csincw, I(cc), U(sf) U(f) U(t), D(d))\ @@ -1230,6 +1231,7 @@ struct idiv { Vreg64 s; VregSF sf; Vflags fl; }; struct sarq { Vreg64 s, d; VregSF sf; Vflags fl; }; // uses rcx struct shlq { Vreg64 s, d; VregSF sf; Vflags fl; }; // uses rcx struct shrq { Vreg64 s, d; VregSF sf; Vflags fl; }; // uses rcx +struct crc32q { Vreg64 s0, s1; Vreg64 d; }; /* * arm intrinsics. diff --git a/hphp/runtime/vm/jit/vasm-x64.cpp b/hphp/runtime/vm/jit/vasm-x64.cpp index 3ad140d5875..234a924360d 100644 --- a/hphp/runtime/vm/jit/vasm-x64.cpp +++ b/hphp/runtime/vm/jit/vasm-x64.cpp @@ -293,6 +293,7 @@ struct Vgen { void emit(xorqi i) { binary(i); a.xorq(i.s0, i.d); } void emit(const conjure& /*i*/) { always_assert(false); } void emit(const conjureuse& /*i*/) { always_assert(false); } + void emit(const crc32q& i); void emit_nop() { emit(lea{rax[8], rax}); @@ -1003,6 +1004,12 @@ void Vgen::emit(xorq i) { a.xorq(i.s0, i.d); } +template +void Vgen::emit(const crc32q& i) { + noncommute(i); + a.crc32q(i.s0, i.d); +} + /////////////////////////////////////////////////////////////////////////////// template diff --git a/hphp/util/asm-x64-intelxed.h b/hphp/util/asm-x64-intelxed.h index 5354b0cb80e..10bfb6576e2 100644 --- a/hphp/util/asm-x64-intelxed.h +++ b/hphp/util/asm-x64-intelxed.h @@ -194,6 +194,8 @@ public: m, r, sz::byte); } void movsbq(Reg8 src, Reg64 dest) { xedInstrRR(XED_ICLASS_MOVSX, src, dest); } + void crc32q(Reg64 src, Reg64 dest) { xedInstrRR(XED_ICLASS_CRC32, + src, dest); } void lea(MemoryRef p, Reg64 reg) { xedInstrMR(XED_ICLASS_LEA, p, reg); } void lea(RIPRelativeRef p, Reg64 reg) { xedInstrMR(XED_ICLASS_LEA, p, reg); } diff --git a/hphp/util/asm-x64-legacy.h b/hphp/util/asm-x64-legacy.h index 4364ae11291..5939cc4af00 100644 --- a/hphp/util/asm-x64-legacy.h +++ b/hphp/util/asm-x64-legacy.h @@ -51,7 +51,7 @@ enum X64InstrFlags { IF_66PREFIXED = 0x4000, // instruction requires a manditory 0x66 prefix IF_F3PREFIXED = 0x8000, // instruction requires a manditory 0xf3 prefix IF_F2PREFIXED = 0x10000, // instruction requires a manditory 0xf2 prefix - IF_THREEBYTEOP = 0x20000, // instruction requires a 0x0F 0x3A prefix + IF_THREEBYTEOP = 0x20000, // instruction requires a 0x0F 0x3[8A] prefix IF_ROUND = 0x40000, // instruction is round(sp)d }; @@ -157,6 +157,8 @@ const X64Instr instr_shrd = { { 0xAD,0xF1,0xAC,0x00,0xF1,0xF1 }, 0x0082 }; const X64Instr instr_int3 = { { 0xF1,0xF1,0xF1,0x00,0xF1,0xCC }, 0x0500 }; const X64Instr instr_roundsd = { { 0xF1,0xF1,0x0b,0x00,0xF1,0xF1 }, 0x64112 }; const X64Instr instr_cmpsd = { { 0xF1,0xF1,0xC2,0xF1,0xF1,0xF1 }, 0x10112 }; +const X64Instr instr_crc32 = { { 0xF1,0xF1,0xF1,0x00,0xF1,0xF1 }, 0x30001 }; + /////////////////////////////////////////////////////////////////////////////// @@ -319,6 +321,7 @@ public: m, r); } void movsbq(Reg8 src, Reg64 dest) { emitRR(instr_movsbx, rn(src), rn(dest)); } + void crc32q(Reg64 src, Reg64 dest) { instrRR(instr_crc32, src, dest); } void lea(MemoryRef p, Reg64 reg) { instrMR(instr_lea, p, reg); } void lea(RIPRelativeRef p, Reg64 reg) { instrMR(instr_lea, p, reg); } @@ -656,8 +659,9 @@ public: byte(0x40 | rex); if (highByteReg) byteRegMisuse(); } - // For two byte opcodes - if ((op.flags & (IF_TWOBYTEOP | IF_IMUL)) != 0) byte(0x0F); + // For two/three byte opcodes + if ((op.flags & (IF_TWOBYTEOP | IF_IMUL | IF_THREEBYTEOP)) != 0) byte(0x0F); + if ((op.flags & IF_THREEBYTEOP) != 0) byte(0x38); byte(op.table[0] | jcond); if (reverse) { emitModrm(3, r2, r1); diff --git a/hphp/util/asm-x64.h b/hphp/util/asm-x64.h index 6e91d2f2556..b1a26a913a0 100644 --- a/hphp/util/asm-x64.h +++ b/hphp/util/asm-x64.h @@ -652,6 +652,7 @@ public: virtual void movzwl(Reg16 src, Reg32 dest) = 0; virtual void loadsbq(MemoryRef m, Reg64 r) = 0; virtual void movsbq(Reg8 src, Reg64 dest) = 0; + virtual void crc32q(Reg64 src, Reg64 dest) = 0; virtual void lea(MemoryRef p, Reg64 reg) = 0; virtual void lea(RIPRelativeRef p, Reg64 reg) = 0; diff --git a/hphp/util/test/asm.cpp b/hphp/util/test/asm.cpp index c292f358013..901867b7f84 100644 --- a/hphp/util/test/asm.cpp +++ b/hphp/util/test/asm.cpp @@ -975,6 +975,24 @@ TEST(Asm, Psllq) { EXPECT_EQ(0x73, current[3]); } +#if defined(USE_HWCRC) && defined(__SSE4_2__) +TEST(Asm, Crc32q) { + TestDataBlock db(10 << 24); + Asm a { db }; + + a. push (rax); + a. push (rbx); + a. movq (0x15, rax); + a. crc32q (rax, rbx); + expect_asm(a, R"( +pushq %rax +pushq %rbx +mov $0x15, %rax +crc32 %rax, %rbx +)"); +} +#endif + }} #endif -- 2.11.4.GIT