Bug 1251392 - Baldr: Implement PopcntI. r=sunfish
authorMichael Bebenita <mbebenita@gmail.com>
Tue, 01 Mar 2016 11:37:43 -0800
changeset 322688 3a2df80faeb64cac5c11dbc81cf184dbf3c9acf0
parent 322687 5c0bc38a3b8839e358dc627aa3c7a357a35b3154
child 322689 7251e33ee977c169ae0228472047acb275ecfb49
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssunfish
bugs1251392
milestone47.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1251392 - Baldr: Implement PopcntI. r=sunfish
js/src/asmjs/Wasm.cpp
js/src/asmjs/WasmIonCompile.cpp
js/src/jit-test/tests/wasm/basic-integer.js
js/src/jit/Lowering.cpp
js/src/jit/Lowering.h
js/src/jit/MIR.cpp
js/src/jit/MIR.h
js/src/jit/MOpcodes.h
js/src/jit/RangeAnalysis.cpp
js/src/jit/arm/CodeGenerator-arm.cpp
js/src/jit/arm/CodeGenerator-arm.h
js/src/jit/shared/LIR-shared.h
js/src/jit/shared/LOpcodes-shared.h
js/src/jit/x86-shared/Assembler-x86-shared.cpp
js/src/jit/x86-shared/Assembler-x86-shared.h
js/src/jit/x86-shared/BaseAssembler-x86-shared.h
js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp
js/src/jit/x86-shared/CodeGenerator-x86-shared.h
js/src/jit/x86-shared/Encoding-x86-shared.h
--- a/js/src/asmjs/Wasm.cpp
+++ b/js/src/asmjs/Wasm.cpp
@@ -422,21 +422,20 @@ DecodeExpr(FunctionDecoder& f, ExprType 
         return DecodeSetLocal(f, expected);
       case Expr::Block:
         return DecodeBlock(f, expected);
       case Expr::If:
         return DecodeIfElse(f, /* hasElse */ false, expected);
       case Expr::IfElse:
         return DecodeIfElse(f, /* hasElse */ true, expected);
       case Expr::I32Clz:
+      case Expr::I32Popcnt:
         return DecodeUnaryOperator(f, expected, ExprType::I32);
       case Expr::I32Ctz:
         return f.fail("NYI: ctz");
-      case Expr::I32Popcnt:
-        return f.fail("NYI: popcnt");
       case Expr::I64Clz:
       case Expr::I64Ctz:
       case Expr::I64Popcnt:
         return f.fail("NYI: i64") &&
                DecodeUnaryOperator(f, expected, ExprType::I64);
       case Expr::F32Abs:
       case Expr::F32Neg:
       case Expr::F32Ceil:
--- a/js/src/asmjs/WasmIonCompile.cpp
+++ b/js/src/asmjs/WasmIonCompile.cpp
@@ -2816,16 +2816,18 @@ EmitExpr(FunctionCompiler& f, ExprType t
       case Expr::I32TruncSF32:
       case Expr::I32TruncUF32:
         return EmitUnary<MTruncateToInt32>(f, ExprType::F32, def);
       case Expr::I32TruncSF64:
       case Expr::I32TruncUF64:
         return EmitUnary<MTruncateToInt32>(f, ExprType::F64, def);
       case Expr::I32Clz:
         return EmitUnary<MClz>(f, ExprType::I32, def);
+      case Expr::I32Popcnt:
+        return EmitUnary<MPopcnt>(f, ExprType::I32, def);
       case Expr::I32Abs:
         return EmitUnaryMir<MAbs>(f, ExprType::I32, def);
       case Expr::I32Neg:
         return EmitUnaryMir<MAsmJSNeg>(f, ExprType::I32, def);
       case Expr::I32Or:
         return EmitBitwise<MBitOr>(f, ExprType::I32, def);
       case Expr::I32And:
         return EmitBitwise<MBitAnd>(f, ExprType::I32, def);
@@ -3053,17 +3055,16 @@ EmitExpr(FunctionCompiler& f, ExprType t
                           SimdSign::Unsigned, def);
 
       // Future opcodes
       case Expr::Loop:
       case Expr::Select:
       case Expr::Br:
       case Expr::BrIf:
       case Expr::I32Ctz:
-      case Expr::I32Popcnt:
       case Expr::F32CopySign:
       case Expr::F32Trunc:
       case Expr::F32Nearest:
       case Expr::F64CopySign:
       case Expr::F64Nearest:
       case Expr::F64Trunc:
       case Expr::I32WrapI64:
       case Expr::I64ExtendSI32:
--- a/js/src/jit-test/tests/wasm/basic-integer.js
+++ b/js/src/jit-test/tests/wasm/basic-integer.js
@@ -47,17 +47,19 @@ function testComparison(type, opcode, lh
                             (export "" 1))`)(), expect);
   } else {
     assertEq(wasmEvalText('(module (func (param ' + type + ') (param ' + type + ') (result i32) (' + type + '.' + opcode + ' (get_local 0) (get_local 1))) (export "" 0))')(lhs, rhs), expect);
   }
 }
 
 testUnary('i32', 'clz', 40, 26);
 //testUnary('i32', 'ctz', 40, 0); // TODO: NYI
-//testUnary('i32', 'popcnt', 40, 0); // TODO: NYI
+testUnary('i32', 'popcnt', 40, 2);
+testUnary('i32', 'popcnt', 0, 0);
+testUnary('i32', 'popcnt', 0xFFFFFFFF, 32);
 
 testBinary('i32', 'add', 40, 2, 42);
 testBinary('i32', 'sub', 40, 2, 38);
 testBinary('i32', 'mul', 40, 2, 80);
 testBinary('i32', 'div_s', -40, 2, -20);
 testBinary('i32', 'div_u', -40, 2, 2147483628);
 testBinary('i32', 'rem_s', 40, -3, 1);
 testBinary('i32', 'rem_u', 40, -3, 40);
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -1389,16 +1389,25 @@ LIRGenerator::visitClz(MClz* ins)
 {
     MDefinition* num = ins->num();
 
     LClzI* lir = new(alloc()) LClzI(useRegisterAtStart(num));
     define(lir, ins);
 }
 
 void
+LIRGenerator::visitPopcnt(MPopcnt* ins)
+{
+    MDefinition* num = ins->num();
+
+    LPopcntI* lir = new(alloc()) LPopcntI(useRegisterAtStart(num), temp());
+    define(lir, ins);
+}
+
+void
 LIRGenerator::visitSqrt(MSqrt* ins)
 {
     MDefinition* num = ins->input();
     MOZ_ASSERT(IsFloatingPointType(num->type()));
 
     LInstructionHelper<1, 1, 0>* lir;
     if (num->type() == MIRType_Double)
         lir = new(alloc()) LSqrtD(useRegisterAtStart(num));
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -125,16 +125,17 @@ class LIRGenerator : public LIRGenerator
     void visitUrsh(MUrsh* ins);
     void visitFloor(MFloor* ins);
     void visitCeil(MCeil* ins);
     void visitRound(MRound* ins);
     void visitMinMax(MMinMax* ins);
     void visitAbs(MAbs* ins);
     void visitClz(MClz* ins);
     void visitSqrt(MSqrt* ins);
+    void visitPopcnt(MPopcnt* ins);
     void visitAtan2(MAtan2* ins);
     void visitHypot(MHypot* ins);
     void visitPow(MPow* ins);
     void visitMathFunction(MMathFunction* ins);
     void visitAdd(MAdd* ins);
     void visitSub(MSub* ins);
     void visitMul(MMul* ins);
     void visitDiv(MDiv* ins);
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -5098,16 +5098,27 @@ MClz::foldsTo(TempAllocator& alloc)
             return MConstant::New(alloc, Int32Value(32));
         return MConstant::New(alloc, Int32Value(mozilla::CountLeadingZeroes32(n)));
     }
 
     return this;
 }
 
 MDefinition*
+MPopcnt::foldsTo(TempAllocator& alloc)
+{
+    if (num()->isConstant()) {
+        int32_t n = num()->toConstant()->toInt32();
+        return MConstant::New(alloc, Int32Value(mozilla::CountPopulation32(n)));
+    }
+
+    return this;
+}
+
+MDefinition*
 MBoundsCheck::foldsTo(TempAllocator& alloc)
 {
     if (index()->isConstant() && length()->isConstant()) {
         uint32_t len = length()->toConstant()->toInt32();
         uint32_t idx = index()->toConstant()->toInt32();
         if (idx + uint32_t(minimum()) < len && idx + uint32_t(maximum()) < len)
             return index();
     }
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -6018,16 +6018,52 @@ class MClz
         return operandIsNeverZero_;
     }
 
     MDefinition* foldsTo(TempAllocator& alloc) override;
     void computeRange(TempAllocator& alloc) override;
     void collectRangeInfoPreTrunc() override;
 };
 
+class MPopcnt
+    : public MUnaryInstruction
+    , public BitwisePolicy::Data
+{
+    explicit MPopcnt(MDefinition* num)
+      : MUnaryInstruction(num)
+    {
+        MOZ_ASSERT(IsNumberType(num->type()));
+        specialization_ = MIRType_Int32;
+        setResultType(MIRType_Int32);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(Popcnt)
+    static MPopcnt* New(TempAllocator& alloc, MDefinition* num) {
+        return new(alloc) MPopcnt(num);
+    }
+    static MPopcnt* NewAsmJS(TempAllocator& alloc, MDefinition* num) {
+        return new(alloc) MPopcnt(num);
+    }
+    MDefinition* num() const {
+        return getOperand(0);
+    }
+    bool congruentTo(const MDefinition* ins) const override {
+        return congruentIfOperandsEqual(ins);
+    }
+
+    AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+
+    MDefinition* foldsTo(TempAllocator& alloc) override;
+    void computeRange(TempAllocator& alloc) override;
+};
+
 // Inline implementation of Math.sqrt().
 class MSqrt
   : public MUnaryInstruction,
     public FloatingPointPolicy<0>::Data
 {
     MSqrt(MDefinition* num, MIRType type)
       : MUnaryInstruction(num)
     {
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -81,16 +81,17 @@ namespace jit {
     _(BitOr)                                                                \
     _(BitXor)                                                               \
     _(Lsh)                                                                  \
     _(Rsh)                                                                  \
     _(Ursh)                                                                 \
     _(MinMax)                                                               \
     _(Abs)                                                                  \
     _(Clz)                                                                  \
+    _(Popcnt)                                                               \
     _(Sqrt)                                                                 \
     _(Atan2)                                                                \
     _(Hypot)                                                                \
     _(Pow)                                                                  \
     _(PowHalf)                                                              \
     _(Random)                                                               \
     _(MathFunction)                                                         \
     _(Add)                                                                  \
--- a/js/src/jit/RangeAnalysis.cpp
+++ b/js/src/jit/RangeAnalysis.cpp
@@ -1468,16 +1468,22 @@ MCeil::computeRange(TempAllocator& alloc
 
 void
 MClz::computeRange(TempAllocator& alloc)
 {
     setRange(Range::NewUInt32Range(alloc, 0, 32));
 }
 
 void
+MPopcnt::computeRange(TempAllocator& alloc)
+{
+    setRange(Range::NewUInt32Range(alloc, 0, 32));
+}
+
+void
 MMinMax::computeRange(TempAllocator& alloc)
 {
     if (specialization_ != MIRType_Int32 && specialization_ != MIRType_Double)
         return;
 
     Range left(getOperand(0));
     Range right(getOperand(1));
     setRange(isMax() ? Range::max(alloc, &left, &right) : Range::min(alloc, &left, &right));
--- a/js/src/jit/arm/CodeGenerator-arm.cpp
+++ b/js/src/jit/arm/CodeGenerator-arm.cpp
@@ -950,16 +950,40 @@ CodeGeneratorARM::visitClzI(LClzI* ins)
 {
     Register input = ToRegister(ins->input());
     Register output = ToRegister(ins->output());
 
     masm.ma_clz(input, output);
 }
 
 void
+CodeGeneratorARM::visitPopcntI(LPopcntI* ins)
+{
+    Register input = ToRegister(ins->input());
+    Register output = ToRegister(ins->output());
+
+    // Equivalent to GCC output of mozilla::CountPopulation32()
+    Register tmp = ToRegister(ins->temp());
+
+    masm.ma_mov(input, output);
+    masm.as_mov(tmp, asr(output, 1));
+    masm.ma_and(Imm32(0x55555555), tmp);
+    masm.ma_sub(output, tmp, output);
+    masm.as_mov(tmp, asr(output, 2));
+    masm.ma_and(Imm32(0x33333333), output);
+    masm.ma_and(Imm32(0x33333333), tmp);
+    masm.ma_add(output, tmp, output);
+    masm.as_add(output, output, lsr(output, 4));
+    masm.ma_and(Imm32(0xF0F0F0F), output);
+    masm.as_add(output, output, lsl(output, 8));
+    masm.as_add(output, output, lsl(output, 16));
+    masm.as_mov(output, asr(output, 24));
+}
+
+void
 CodeGeneratorARM::visitPowHalfD(LPowHalfD* ins)
 {
     FloatRegister input = ToFloatRegister(ins->input());
     FloatRegister output = ToFloatRegister(ins->output());
     ScratchDoubleScope scratch(masm);
 
     Label done;
 
--- a/js/src/jit/arm/CodeGenerator-arm.h
+++ b/js/src/jit/arm/CodeGenerator-arm.h
@@ -118,16 +118,17 @@ class CodeGeneratorARM : public CodeGene
     virtual void visitSoftModI(LSoftModI* ins);
     virtual void visitModPowTwoI(LModPowTwoI* ins);
     virtual void visitModMaskI(LModMaskI* ins);
     virtual void visitPowHalfD(LPowHalfD* ins);
     virtual void visitShiftI(LShiftI* ins);
     virtual void visitUrshD(LUrshD* ins);
 
     virtual void visitClzI(LClzI* ins);
+    virtual void visitPopcntI(LPopcntI* ins);
 
     virtual void visitTestIAndBranch(LTestIAndBranch* test);
     virtual void visitCompare(LCompare* comp);
     virtual void visitCompareAndBranch(LCompareAndBranch* comp);
     virtual void visitTestDAndBranch(LTestDAndBranch* test);
     virtual void visitTestFAndBranch(LTestFAndBranch* test);
     virtual void visitCompareD(LCompareD* comp);
     virtual void visitCompareF(LCompareF* comp);
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -3203,16 +3203,35 @@ class LClzI : public LInstructionHelper<
         setOperand(0, num);
     }
 
     MClz* mir() const {
         return mir_->toClz();
     }
 };
 
+// Count population
+class LPopcntI : public LInstructionHelper<1, 1, 1>
+{
+  public:
+    LIR_HEADER(PopcntI)
+    explicit LPopcntI(const LAllocation& num, const LDefinition& temp) {
+        setOperand(0, num);
+        setTemp(0, temp);
+    }
+
+    MPopcnt* mir() const {
+        return mir_->toPopcnt();
+    }
+
+    const LDefinition* temp() {
+        return getTemp(0);
+    }
+};
+
 // Square root of a double.
 class LSqrtD : public LInstructionHelper<1, 1, 0>
 {
   public:
     LIR_HEADER(SqrtD)
     explicit LSqrtD(const LAllocation& num) {
         setOperand(0, num);
     }
--- a/js/src/jit/shared/LOpcodes-shared.h
+++ b/js/src/jit/shared/LOpcodes-shared.h
@@ -137,16 +137,17 @@
     _(MinMaxF)                      \
     _(NegI)                         \
     _(NegD)                         \
     _(NegF)                         \
     _(AbsI)                         \
     _(AbsD)                         \
     _(AbsF)                         \
     _(ClzI)                         \
+    _(PopcntI)                      \
     _(SqrtD)                        \
     _(SqrtF)                        \
     _(Atan2D)                       \
     _(Hypot)                        \
     _(PowI)                         \
     _(PowD)                         \
     _(PowHalfD)                     \
     _(Random)                       \
--- a/js/src/jit/x86-shared/Assembler-x86-shared.cpp
+++ b/js/src/jit/x86-shared/Assembler-x86-shared.cpp
@@ -153,16 +153,17 @@ AssemblerX86Shared::verifyHeapAccessDisa
     Disassembler::VerifyHeapAccess(masm.data() + begin, masm.data() + end, heapAccess);
 #endif
 }
 
 CPUInfo::SSEVersion CPUInfo::maxSSEVersion = UnknownSSE;
 CPUInfo::SSEVersion CPUInfo::maxEnabledSSEVersion = UnknownSSE;
 bool CPUInfo::avxPresent = false;
 bool CPUInfo::avxEnabled = false;
+bool CPUInfo::popcntPresent = false;
 
 static uintptr_t
 ReadXGETBV()
 {
     // We use a variety of low-level mechanisms to get at the xgetbv
     // instruction, including spelling out the xgetbv instruction as bytes,
     // because older compilers and assemblers may not recognize the instruction
     // by name.
@@ -247,9 +248,13 @@ CPUInfo::SetSSEVersion()
 
     // If the hardware supports AVX, check whether the OS supports it too.
     if (avxPresent) {
         size_t xcr0EAX = ReadXGETBV();
         static const int xcr0SSEBit = 1 << 1;
         static const int xcr0AVXBit = 1 << 2;
         avxPresent = (xcr0EAX & xcr0SSEBit) && (xcr0EAX & xcr0AVXBit);
     }
+
+    static const int POPCNTBit = 1 << 23;
+
+    popcntPresent = (flagsECX & POPCNTBit);
 }
--- a/js/src/jit/x86-shared/Assembler-x86-shared.h
+++ b/js/src/jit/x86-shared/Assembler-x86-shared.h
@@ -206,31 +206,33 @@ class CPUInfo
         return avxPresent;
     }
 
   private:
     static SSEVersion maxSSEVersion;
     static SSEVersion maxEnabledSSEVersion;
     static bool avxPresent;
     static bool avxEnabled;
+    static bool popcntPresent;
 
     static void SetSSEVersion();
 
   public:
     static bool IsSSE2Present() {
 #ifdef JS_CODEGEN_X64
         return true;
 #else
         return GetSSEVersion() >= SSE2;
 #endif
     }
     static bool IsSSE3Present()  { return GetSSEVersion() >= SSE3; }
     static bool IsSSSE3Present() { return GetSSEVersion() >= SSSE3; }
     static bool IsSSE41Present() { return GetSSEVersion() >= SSE4_1; }
     static bool IsSSE42Present() { return GetSSEVersion() >= SSE4_2; }
+    static bool IsPOPCNTPresent() { return popcntPresent; }
 
 #ifdef JS_CODEGEN_X86
     static void SetFloatingPointDisabled() { maxEnabledSSEVersion = NoSSE; avxEnabled = false; }
 #endif
     static void SetSSE3Disabled() { maxEnabledSSEVersion = SSE2; avxEnabled = false; }
     static void SetSSE4Disabled() { maxEnabledSSEVersion = SSSE3; avxEnabled = false; }
     static void SetAVXEnabled() { avxEnabled = true; }
 };
@@ -1038,16 +1040,17 @@ class AssemblerX86Shared : public Assemb
 
     void breakpoint() {
         masm.int3();
     }
 
     static bool HasSSE2() { return CPUInfo::IsSSE2Present(); }
     static bool HasSSE3() { return CPUInfo::IsSSE3Present(); }
     static bool HasSSE41() { return CPUInfo::IsSSE41Present(); }
+    static bool HasPOPCNT() { return CPUInfo::IsPOPCNTPresent(); }
     static bool SupportsFloatingPoint() { return CPUInfo::IsSSE2Present(); }
     static bool SupportsSimd() { return CPUInfo::IsSSE2Present(); }
     static bool HasAVX() { return CPUInfo::IsAVXPresent(); }
 
     void cmpl(Register rhs, Register lhs) {
         masm.cmpl_rr(rhs.encoding(), lhs.encoding());
     }
     void cmpl(const Operand& rhs, Register lhs) {
@@ -1540,16 +1543,19 @@ class AssemblerX86Shared : public Assemb
             break;
           default:
             MOZ_CRASH("unexpected operand kind");
         }
     }
     void bsr(const Register& src, const Register& dest) {
         masm.bsr_rr(src.encoding(), dest.encoding());
     }
+    void popcnt(const Register& src, const Register& dest) {
+        masm.popcnt_rr(src.encoding(), dest.encoding());
+    }
     void imull(Register multiplier) {
         masm.imull_r(multiplier.encoding());
     }
     void umull(Register multiplier) {
         masm.mull_r(multiplier.encoding());
     }
     void imull(Imm32 imm, Register dest) {
         masm.imull_ir(imm.value, dest.encoding(), dest.encoding());
--- a/js/src/jit/x86-shared/BaseAssembler-x86-shared.h
+++ b/js/src/jit/x86-shared/BaseAssembler-x86-shared.h
@@ -1280,16 +1280,23 @@ public:
     }
 
     void bsr_rr(RegisterID src, RegisterID dst)
     {
         spew("bsr        %s, %s", GPReg32Name(src), GPReg32Name(dst));
         m_formatter.twoByteOp(OP2_BSR_GvEv, src, dst);
     }
 
+    void popcnt_rr(RegisterID src, RegisterID dst)
+    {
+        spew("popcnt     %s, %s", GPReg32Name(src), GPReg32Name(dst));
+        m_formatter.legacySSEPrefix(VEX_SS);
+        m_formatter.twoByteOp(OP2_POPCNT_GvEv, src, dst);
+    }
+
     void imull_rr(RegisterID src, RegisterID dst)
     {
         spew("imull      %s, %s", GPReg32Name(src), GPReg32Name(dst));
         m_formatter.twoByteOp(OP2_IMUL_GvEv, src, dst);
     }
 
     void imull_r(RegisterID multiplier)
     {
--- a/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp
@@ -720,16 +720,48 @@ CodeGeneratorX86Shared::visitClzI(LClzI*
 
     masm.bind(&nonzero);
     masm.bsr(input, output);
     masm.xor32(Imm32(0x1F), output);
     masm.bind(&done);
 }
 
 void
+CodeGeneratorX86Shared::visitPopcntI(LPopcntI* ins)
+{
+    Register input = ToRegister(ins->input());
+    Register output = ToRegister(ins->output());
+
+    if (AssemblerX86Shared::HasPOPCNT()) {
+        masm.popcnt(input, output);
+        return;
+    }
+
+    // Equivalent to mozilla::CountPopulation32()
+    Register tmp = ToRegister(ins->temp());
+
+    masm.movl(input, output);
+    masm.movl(input, tmp);
+    masm.shrl(Imm32(1), output);
+    masm.andl(Imm32(0x55555555), output);
+    masm.subl(output, tmp);
+    masm.movl(tmp, output);
+    masm.andl(Imm32(0x33333333), output);
+    masm.shrl(Imm32(2), tmp);
+    masm.andl(Imm32(0x33333333), tmp);
+    masm.addl(output, tmp);
+    masm.movl(tmp, output);
+    masm.shrl(Imm32(4), output);
+    masm.addl(tmp, output);
+    masm.andl(Imm32(0xF0F0F0F), output);
+    masm.imull(Imm32(0x1010101), output, output);
+    masm.shrl(Imm32(24), output);
+}
+
+void
 CodeGeneratorX86Shared::visitSqrtD(LSqrtD* ins)
 {
     FloatRegister input = ToFloatRegister(ins->input());
     FloatRegister output = ToFloatRegister(ins->output());
     masm.vsqrtsd(input, output, output);
 }
 
 void
--- a/js/src/jit/x86-shared/CodeGenerator-x86-shared.h
+++ b/js/src/jit/x86-shared/CodeGenerator-x86-shared.h
@@ -211,16 +211,17 @@ class CodeGeneratorX86Shared : public Co
     // Instruction visitors.
     virtual void visitDouble(LDouble* ins);
     virtual void visitFloat32(LFloat32* ins);
     virtual void visitMinMaxD(LMinMaxD* ins);
     virtual void visitMinMaxF(LMinMaxF* ins);
     virtual void visitAbsD(LAbsD* ins);
     virtual void visitAbsF(LAbsF* ins);
     virtual void visitClzI(LClzI* ins);
+    virtual void visitPopcntI(LPopcntI* ins);
     virtual void visitSqrtD(LSqrtD* ins);
     virtual void visitSqrtF(LSqrtF* ins);
     virtual void visitPowHalfD(LPowHalfD* ins);
     virtual void visitAddI(LAddI* ins);
     virtual void visitSubI(LSubI* ins);
     virtual void visitMulI(LMulI* ins);
     virtual void visitDivI(LDivI* ins);
     virtual void visitDivPowTwoI(LDivPowTwoI* ins);
--- a/js/src/jit/x86-shared/Encoding-x86-shared.h
+++ b/js/src/jit/x86-shared/Encoding-x86-shared.h
@@ -196,16 +196,17 @@ enum TwoByteOpcodeID {
     OP2_JCC_rel32       = 0x80,
     OP_SETCC            = 0x90,
     OP2_SHLD            = 0xA4,
     OP2_SHRD            = 0xAC,
     OP_FENCE            = 0xAE,
     OP2_IMUL_GvEv       = 0xAF,
     OP2_CMPXCHG_GvEb    = 0xB0,
     OP2_CMPXCHG_GvEw    = 0xB1,
+    OP2_POPCNT_GvEv     = 0xB8,
     OP2_BSR_GvEv        = 0xBD,
     OP2_MOVSX_GvEb      = 0xBE,
     OP2_MOVSX_GvEw      = 0xBF,
     OP2_MOVZX_GvEb      = 0xB6,
     OP2_MOVZX_GvEw      = 0xB7,
     OP2_XADD_EbGb       = 0xC0,
     OP2_XADD_EvGv       = 0xC1,
     OP2_CMPPS_VpsWps    = 0xC2,