Bug 1183060 - wrong code generated for x86 word operations. r=sunfish
authorLars T Hansen <lhansen@mozilla.com>
Wed, 05 Aug 2015 09:20:28 +0200
changeset 287940 3ed3258d336a3a949311b63bf2879372aa81ba5e
parent 287939 0a6cee238cada7e179fc6f68478289bc20580878
child 287941 08cdf088f429a49314e3e2ad871e477688323979
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssunfish
bugs1183060
milestone42.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 1183060 - wrong code generated for x86 word operations. r=sunfish
js/src/jit-test/tests/asm.js/testBug1183060.js
js/src/jit/x86-shared/Assembler-x86-shared.h
js/src/jit/x86-shared/BaseAssembler-x86-shared.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/asm.js/testBug1183060.js
@@ -0,0 +1,55 @@
+if (!this.SharedArrayBuffer)
+    quit(0);
+
+function loadModule_uint16(stdlib, foreign, heap) {
+    "use asm";
+    var atomic_add = stdlib.Atomics.add;
+    var atomic_sub = stdlib.Atomics.sub;
+    var atomic_and = stdlib.Atomics.and;
+    var atomic_or = stdlib.Atomics.or;
+    var atomic_xor = stdlib.Atomics.xor;
+    var i16a = new stdlib.SharedUint16Array(heap);
+    function do_add_i(i) {
+	i = i|0;
+	var v = 0;
+	v = atomic_add(i16a, i>>1, 0x3333)|0;
+    }
+    function do_sub_i(i) {
+	i = i|0;
+	var v = 0;
+	v = atomic_sub(i16a, i>>1, 0x3333)|0;
+    }
+    function do_and_i(i) {
+	i = i|0;
+	var v = 0;
+	v = atomic_and(i16a, i>>1, 0x3333)|0;
+    }
+    function do_or_i(i) {
+	i = i|0;
+	var v = 0;
+	v = atomic_or(i16a, i>>1, 0x3333)|0;
+    }
+    function do_xor_i(i) {
+	i = i|0;
+	var v = 0;
+	v = atomic_xor(i16a, i>>1, 0x3333)|0;
+    }
+    return { add_i: do_add_i,
+	     sub_i: do_sub_i,
+	     and_i: do_and_i,
+	     or_i: do_or_i,
+	     xor_i: do_xor_i };
+}
+
+function test_uint16(heap) {
+    var i16m = loadModule_uint16(this, {}, heap);
+    var size = SharedUint16Array.BYTES_PER_ELEMENT;
+    i16m.add_i(size*40)
+    i16m.sub_i(size*40)
+    i16m.and_i(size*40)
+    i16m.or_i(size*40)
+    i16m.xor_i(size*40)
+}
+
+var heap = new SharedArrayBuffer(65536);
+test_uint16(heap);
--- a/js/src/jit/x86-shared/Assembler-x86-shared.h
+++ b/js/src/jit/x86-shared/Assembler-x86-shared.h
@@ -1124,16 +1124,34 @@ class AssemblerX86Shared : public Assemb
             break;
           case Operand::MEM_SCALE:
             masm.addl_im(imm.value, op.disp(), op.base(), op.index(), op.scale());
             break;
           default:
             MOZ_CRASH("unexpected operand kind");
         }
     }
+    void addw(Imm32 imm, const Operand& op) {
+        switch (op.kind()) {
+          case Operand::REG:
+            masm.addw_ir(imm.value, op.reg());
+            break;
+          case Operand::MEM_REG_DISP:
+            masm.addw_im(imm.value, op.disp(), op.base());
+            break;
+          case Operand::MEM_ADDRESS32:
+            masm.addw_im(imm.value, op.address());
+            break;
+          case Operand::MEM_SCALE:
+            masm.addw_im(imm.value, op.disp(), op.base(), op.index(), op.scale());
+            break;
+          default:
+            MOZ_CRASH("unexpected operand kind");
+        }
+    }
     void subl(Imm32 imm, Register dest) {
         masm.subl_ir(imm.value, dest.encoding());
     }
     void subl(Imm32 imm, const Operand& op) {
         switch (op.kind()) {
           case Operand::REG:
             masm.subl_ir(imm.value, op.reg());
             break;
@@ -1142,16 +1160,31 @@ class AssemblerX86Shared : public Assemb
             break;
           case Operand::MEM_SCALE:
             masm.subl_im(imm.value, op.disp(), op.base(), op.index(), op.scale());
             break;
           default:
             MOZ_CRASH("unexpected operand kind");
         }
     }
+    void subw(Imm32 imm, const Operand& op) {
+        switch (op.kind()) {
+          case Operand::REG:
+            masm.subw_ir(imm.value, op.reg());
+            break;
+          case Operand::MEM_REG_DISP:
+            masm.subw_im(imm.value, op.disp(), op.base());
+            break;
+          case Operand::MEM_SCALE:
+            masm.subw_im(imm.value, op.disp(), op.base(), op.index(), op.scale());
+            break;
+          default:
+            MOZ_CRASH("unexpected operand kind");
+        }
+    }
     void addl(Register src, Register dest) {
         masm.addl_rr(src.encoding(), dest.encoding());
     }
     void addl(Register src, const Operand& dest) {
         switch (dest.kind()) {
           case Operand::REG:
             masm.addl_rr(src.encoding(), dest.reg());
             break;
@@ -1160,16 +1193,31 @@ class AssemblerX86Shared : public Assemb
             break;
           case Operand::MEM_SCALE:
             masm.addl_rm(src.encoding(), dest.disp(), dest.base(), dest.index(), dest.scale());
             break;
           default:
             MOZ_CRASH("unexpected operand kind");
         }
     }
+    void addw(Register src, const Operand& dest) {
+        switch (dest.kind()) {
+          case Operand::REG:
+            masm.addw_rr(src.encoding(), dest.reg());
+            break;
+          case Operand::MEM_REG_DISP:
+            masm.addw_rm(src.encoding(), dest.disp(), dest.base());
+            break;
+          case Operand::MEM_SCALE:
+            masm.addw_rm(src.encoding(), dest.disp(), dest.base(), dest.index(), dest.scale());
+            break;
+          default:
+            MOZ_CRASH("unexpected operand kind");
+        }
+    }
     void subl(Register src, Register dest) {
         masm.subl_rr(src.encoding(), dest.encoding());
     }
     void subl(const Operand& src, Register dest) {
         switch (src.kind()) {
           case Operand::REG:
             masm.subl_rr(src.reg(), dest.encoding());
             break;
@@ -1190,16 +1238,31 @@ class AssemblerX86Shared : public Assemb
             break;
           case Operand::MEM_SCALE:
             masm.subl_rm(src.encoding(), dest.disp(), dest.base(), dest.index(), dest.scale());
             break;
           default:
             MOZ_CRASH("unexpected operand kind");
         }
     }
+    void subw(Register src, const Operand& dest) {
+        switch (dest.kind()) {
+          case Operand::REG:
+            masm.subw_rr(src.encoding(), dest.reg());
+            break;
+          case Operand::MEM_REG_DISP:
+            masm.subw_rm(src.encoding(), dest.disp(), dest.base());
+            break;
+          case Operand::MEM_SCALE:
+            masm.subw_rm(src.encoding(), dest.disp(), dest.base(), dest.index(), dest.scale());
+            break;
+          default:
+            MOZ_CRASH("unexpected operand kind");
+        }
+    }
     void orl(Register reg, Register dest) {
         masm.orl_rr(reg.encoding(), dest.encoding());
     }
     void orl(Register src, const Operand& dest) {
         switch (dest.kind()) {
           case Operand::REG:
             masm.orl_rr(src.encoding(), dest.reg());
             break;
@@ -1208,16 +1271,31 @@ class AssemblerX86Shared : public Assemb
             break;
           case Operand::MEM_SCALE:
             masm.orl_rm(src.encoding(), dest.disp(), dest.base(), dest.index(), dest.scale());
             break;
           default:
             MOZ_CRASH("unexpected operand kind");
         }
     }
+    void orw(Register src, const Operand& dest) {
+        switch (dest.kind()) {
+          case Operand::REG:
+            masm.orw_rr(src.encoding(), dest.reg());
+            break;
+          case Operand::MEM_REG_DISP:
+            masm.orw_rm(src.encoding(), dest.disp(), dest.base());
+            break;
+          case Operand::MEM_SCALE:
+            masm.orw_rm(src.encoding(), dest.disp(), dest.base(), dest.index(), dest.scale());
+            break;
+          default:
+            MOZ_CRASH("unexpected operand kind");
+        }
+    }
     void orl(Imm32 imm, Register reg) {
         masm.orl_ir(imm.value, reg.encoding());
     }
     void orl(Imm32 imm, const Operand& op) {
         switch (op.kind()) {
           case Operand::REG:
             masm.orl_ir(imm.value, op.reg());
             break;
@@ -1226,16 +1304,31 @@ class AssemblerX86Shared : public Assemb
             break;
           case Operand::MEM_SCALE:
             masm.orl_im(imm.value, op.disp(), op.base(), op.index(), op.scale());
             break;
           default:
             MOZ_CRASH("unexpected operand kind");
         }
     }
+    void orw(Imm32 imm, const Operand& op) {
+        switch (op.kind()) {
+          case Operand::REG:
+            masm.orw_ir(imm.value, op.reg());
+            break;
+          case Operand::MEM_REG_DISP:
+            masm.orw_im(imm.value, op.disp(), op.base());
+            break;
+          case Operand::MEM_SCALE:
+            masm.orw_im(imm.value, op.disp(), op.base(), op.index(), op.scale());
+            break;
+          default:
+            MOZ_CRASH("unexpected operand kind");
+        }
+    }
     void xorl(Register src, Register dest) {
         masm.xorl_rr(src.encoding(), dest.encoding());
     }
     void xorl(Register src, const Operand& dest) {
         switch (dest.kind()) {
           case Operand::REG:
             masm.xorl_rr(src.encoding(), dest.reg());
             break;
@@ -1244,16 +1337,31 @@ class AssemblerX86Shared : public Assemb
             break;
           case Operand::MEM_SCALE:
             masm.xorl_rm(src.encoding(), dest.disp(), dest.base(), dest.index(), dest.scale());
             break;
           default:
             MOZ_CRASH("unexpected operand kind");
         }
     }
+    void xorw(Register src, const Operand& dest) {
+        switch (dest.kind()) {
+          case Operand::REG:
+            masm.xorw_rr(src.encoding(), dest.reg());
+            break;
+          case Operand::MEM_REG_DISP:
+            masm.xorw_rm(src.encoding(), dest.disp(), dest.base());
+            break;
+          case Operand::MEM_SCALE:
+            masm.xorw_rm(src.encoding(), dest.disp(), dest.base(), dest.index(), dest.scale());
+            break;
+          default:
+            MOZ_CRASH("unexpected operand kind");
+        }
+    }
     void xorl(Imm32 imm, Register reg) {
         masm.xorl_ir(imm.value, reg.encoding());
     }
     void xorl(Imm32 imm, const Operand& op) {
         switch (op.kind()) {
           case Operand::REG:
             masm.xorl_ir(imm.value, op.reg());
             break;
@@ -1262,16 +1370,31 @@ class AssemblerX86Shared : public Assemb
             break;
           case Operand::MEM_SCALE:
             masm.xorl_im(imm.value, op.disp(), op.base(), op.index(), op.scale());
             break;
           default:
             MOZ_CRASH("unexpected operand kind");
         }
     }
+    void xorw(Imm32 imm, const Operand& op) {
+        switch (op.kind()) {
+          case Operand::REG:
+            masm.xorw_ir(imm.value, op.reg());
+            break;
+          case Operand::MEM_REG_DISP:
+            masm.xorw_im(imm.value, op.disp(), op.base());
+            break;
+          case Operand::MEM_SCALE:
+            masm.xorw_im(imm.value, op.disp(), op.base(), op.index(), op.scale());
+            break;
+          default:
+            MOZ_CRASH("unexpected operand kind");
+        }
+    }
     void andl(Register src, Register dest) {
         masm.andl_rr(src.encoding(), dest.encoding());
     }
     void andl(Register src, const Operand& dest) {
         switch (dest.kind()) {
           case Operand::REG:
             masm.andl_rr(src.encoding(), dest.reg());
             break;
@@ -1280,16 +1403,31 @@ class AssemblerX86Shared : public Assemb
             break;
           case Operand::MEM_SCALE:
             masm.andl_rm(src.encoding(), dest.disp(), dest.base(), dest.index(), dest.scale());
             break;
           default:
             MOZ_CRASH("unexpected operand kind");
         }
     }
+    void andw(Register src, const Operand& dest) {
+        switch (dest.kind()) {
+          case Operand::REG:
+            masm.andw_rr(src.encoding(), dest.reg());
+            break;
+          case Operand::MEM_REG_DISP:
+            masm.andw_rm(src.encoding(), dest.disp(), dest.base());
+            break;
+          case Operand::MEM_SCALE:
+            masm.andw_rm(src.encoding(), dest.disp(), dest.base(), dest.index(), dest.scale());
+            break;
+          default:
+            MOZ_CRASH("unexpected operand kind");
+        }
+    }
     void andl(Imm32 imm, Register dest) {
         masm.andl_ir(imm.value, dest.encoding());
     }
     void andl(Imm32 imm, const Operand& op) {
         switch (op.kind()) {
           case Operand::REG:
             masm.andl_ir(imm.value, op.reg());
             break;
@@ -1298,16 +1436,31 @@ class AssemblerX86Shared : public Assemb
             break;
           case Operand::MEM_SCALE:
             masm.andl_im(imm.value, op.disp(), op.base(), op.index(), op.scale());
             break;
           default:
             MOZ_CRASH("unexpected operand kind");
         }
     }
+    void andw(Imm32 imm, const Operand& op) {
+        switch (op.kind()) {
+          case Operand::REG:
+            masm.andw_ir(imm.value, op.reg());
+            break;
+          case Operand::MEM_REG_DISP:
+            masm.andw_im(imm.value, op.disp(), op.base());
+            break;
+          case Operand::MEM_SCALE:
+            masm.andw_im(imm.value, op.disp(), op.base(), op.index(), op.scale());
+            break;
+          default:
+            MOZ_CRASH("unexpected operand kind");
+        }
+    }
     void addl(const Operand& src, Register dest) {
         switch (src.kind()) {
           case Operand::REG:
             masm.addl_rr(src.reg(), dest.encoding());
             break;
           case Operand::MEM_REG_DISP:
             masm.addl_mr(src.disp(), src.base(), dest.encoding());
             break;
@@ -1617,42 +1770,37 @@ class AssemblerX86Shared : public Assemb
     void lock_xorb(T src, const Operand& op) {
         masm.prefix_lock();
         xorb(src, op);
     }
 
     template<typename T>
     void lock_addw(T src, const Operand& op) {
         masm.prefix_lock();
-        masm.prefix_16_for_32();
-        addl(src, op);
+        addw(src, op);
     }
     template<typename T>
     void lock_subw(T src, const Operand& op) {
         masm.prefix_lock();
-        masm.prefix_16_for_32();
-        subl(src, op);
+        subw(src, op);
     }
     template<typename T>
     void lock_andw(T src, const Operand& op) {
         masm.prefix_lock();
-        masm.prefix_16_for_32();
-        andl(src, op);
+        andw(src, op);
     }
     template<typename T>
     void lock_orw(T src, const Operand& op) {
         masm.prefix_lock();
-        masm.prefix_16_for_32();
-        orl(src, op);
+        orw(src, op);
     }
     template<typename T>
     void lock_xorw(T src, const Operand& op) {
         masm.prefix_lock();
-        masm.prefix_16_for_32();
-        xorl(src, op);
+        xorw(src, op);
     }
 
     // Note, lock_addl(imm, op) is used for a memory barrier on non-SSE2 systems,
     // among other things.  Do not optimize, replace by XADDL, or similar.
     template<typename T>
     void lock_addl(T src, const Operand& op) {
         masm.prefix_lock();
         addl(src, op);
--- a/js/src/jit/x86-shared/BaseAssembler-x86-shared.h
+++ b/js/src/jit/x86-shared/BaseAssembler-x86-shared.h
@@ -271,16 +271,23 @@ public:
 #endif
 
     void addl_rr(RegisterID src, RegisterID dst)
     {
         spew("addl       %s, %s", GPReg32Name(src), GPReg32Name(dst));
         m_formatter.oneByteOp(OP_ADD_GvEv, src, dst);
     }
 
+    void addw_rr(RegisterID src, RegisterID dst)
+    {
+        spew("addw       %s, %s", GPReg16Name(src), GPReg16Name(dst));
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        m_formatter.oneByteOp(OP_ADD_GvEv, src, dst);
+    }
+
     void addl_mr(int32_t offset, RegisterID base, RegisterID dst)
     {
         spew("addl       " MEM_ob ", %s", ADDR_ob(offset, base), GPReg32Name(dst));
         m_formatter.oneByteOp(OP_ADD_GvEv, offset, base, dst);
     }
 
     void addl_rm(RegisterID src, int32_t offset, RegisterID base)
     {
@@ -303,16 +310,25 @@ public:
         } else {
             if (dst == rax)
                 m_formatter.oneByteOp(OP_ADD_EAXIv);
             else
                 m_formatter.oneByteOp(OP_GROUP1_EvIz, dst, GROUP1_OP_ADD);
             m_formatter.immediate32(imm);
         }
     }
+
+    void addw_ir(int32_t imm, RegisterID dst)
+    {
+        spew("addw       $%d, %s", int16_t(imm), GPReg16Name(dst));
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        m_formatter.oneByteOp(OP_GROUP1_EvIz, dst, GROUP1_OP_ADD);
+        m_formatter.immediate16(imm);
+    }
+
     void addl_i32r(int32_t imm, RegisterID dst)
     {
         // 32-bit immediate always, for patching.
         spew("addl       $0x%04x, %s", imm, GPReg32Name(dst));
         if (dst == rax)
             m_formatter.oneByteOp(OP_ADD_EAXIv);
         else
             m_formatter.oneByteOp(OP_GROUP1_EvIz, dst, GROUP1_OP_ADD);
@@ -407,16 +423,56 @@ public:
         if (CAN_SIGN_EXTEND_8_32(imm)) {
             m_formatter.oneByteOp(OP_GROUP1_EvIb, addr, GROUP1_OP_ADD);
             m_formatter.immediate8s(imm);
         } else {
             m_formatter.oneByteOp(OP_GROUP1_EvIz, addr, GROUP1_OP_ADD);
             m_formatter.immediate32(imm);
         }
     }
+    void addw_im(int32_t imm, const void* addr)
+    {
+        spew("addw       $%d, %p", int16_t(imm), addr);
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        if (CAN_SIGN_EXTEND_8_32(imm)) {
+            m_formatter.oneByteOp(OP_GROUP1_EvIb, addr, GROUP1_OP_ADD);
+            m_formatter.immediate8s(imm);
+        } else {
+            m_formatter.oneByteOp(OP_GROUP1_EvIz, addr, GROUP1_OP_ADD);
+            m_formatter.immediate16(imm);
+        }
+    }
+
+    void addw_im(int32_t imm, int32_t offset, RegisterID base) {
+        spew("addw       $%d, " MEM_ob, int16_t(imm), ADDR_ob(offset, base));
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        m_formatter.oneByteOp(OP_GROUP1_EvIz, offset, base, GROUP1_OP_ADD);
+        m_formatter.immediate16(imm);
+    }
+
+    void addw_im(int32_t imm, int32_t offset, RegisterID base, RegisterID index, int scale)
+    {
+        spew("addw       $%d, " MEM_obs, int16_t(imm), ADDR_obs(offset, base, index, scale));
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        m_formatter.oneByteOp(OP_GROUP1_EvIz, offset, base, index, scale, GROUP1_OP_ADD);
+        m_formatter.immediate16(imm);
+    }
+
+    void addw_rm(RegisterID src, int32_t offset, RegisterID base) {
+        spew("addw       %s, " MEM_ob, GPReg16Name(src), ADDR_ob(offset, base));
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        m_formatter.oneByteOp(OP_ADD_EvGv, offset, base, src);
+    }
+
+    void addw_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale)
+    {
+        spew("addw       %s, " MEM_obs, GPReg16Name(src), ADDR_obs(offset, base, index, scale));
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        m_formatter.oneByteOp(OP_ADD_EvGv, offset, base, index, scale, src);
+    }
 
     void addb_im(int32_t imm, int32_t offset, RegisterID base) {
         spew("addb       $%d, " MEM_ob, int8_t(imm), ADDR_ob(offset, base));
         m_formatter.oneByteOp(OP_GROUP1_EbIb, offset, base, GROUP1_OP_ADD);
         m_formatter.immediate8(imm);
     }
 
     void addb_im(int32_t imm, int32_t offset, RegisterID base, RegisterID index, int scale)
@@ -688,73 +744,136 @@ public:
     }
 
     void andl_rr(RegisterID src, RegisterID dst)
     {
         spew("andl       %s, %s", GPReg32Name(src), GPReg32Name(dst));
         m_formatter.oneByteOp(OP_AND_GvEv, src, dst);
     }
 
+    void andw_rr(RegisterID src, RegisterID dst)
+    {
+        spew("andw       %s, %s", GPReg16Name(src), GPReg16Name(dst));
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        m_formatter.oneByteOp(OP_AND_GvEv, src, dst);
+    }
+
     void andl_mr(int32_t offset, RegisterID base, RegisterID dst)
     {
         spew("andl       " MEM_ob ", %s", ADDR_ob(offset, base), GPReg32Name(dst));
         m_formatter.oneByteOp(OP_AND_GvEv, offset, base, dst);
     }
 
     void andl_rm(RegisterID src, int32_t offset, RegisterID base)
     {
         spew("andl       %s, " MEM_ob, GPReg32Name(src), ADDR_ob(offset, base));
         m_formatter.oneByteOp(OP_AND_EvGv, offset, base, src);
     }
 
+    void andw_rm(RegisterID src, int32_t offset, RegisterID base)
+    {
+        spew("andw       %s, " MEM_ob, GPReg16Name(src), ADDR_ob(offset, base));
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        m_formatter.oneByteOp(OP_AND_EvGv, offset, base, src);
+    }
+
     void andl_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale)
     {
         spew("andl       %s, " MEM_obs, GPReg32Name(src), ADDR_obs(offset, base, index, scale));
         m_formatter.oneByteOp(OP_AND_EvGv, offset, base, index, scale, src);
     }
 
+    void andw_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale)
+    {
+        spew("andw       %s, " MEM_obs, GPReg16Name(src), ADDR_obs(offset, base, index, scale));
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        m_formatter.oneByteOp(OP_AND_EvGv, offset, base, index, scale, src);
+    }
+
     void andl_ir(int32_t imm, RegisterID dst)
     {
         spew("andl       $0x%x, %s", imm, GPReg32Name(dst));
         if (CAN_SIGN_EXTEND_8_32(imm)) {
             m_formatter.oneByteOp(OP_GROUP1_EvIb, dst, GROUP1_OP_AND);
             m_formatter.immediate8s(imm);
         } else {
             if (dst == rax)
                 m_formatter.oneByteOp(OP_AND_EAXIv);
             else
                 m_formatter.oneByteOp(OP_GROUP1_EvIz, dst, GROUP1_OP_AND);
             m_formatter.immediate32(imm);
         }
     }
 
+    void andw_ir(int32_t imm, RegisterID dst)
+    {
+        spew("andw       $0x%x, %s", int16_t(imm), GPReg16Name(dst));
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        if (CAN_SIGN_EXTEND_8_32(imm)) {
+            m_formatter.oneByteOp(OP_GROUP1_EvIb, dst, GROUP1_OP_AND);
+            m_formatter.immediate8s(imm);
+        } else {
+            if (dst == rax)
+                m_formatter.oneByteOp(OP_AND_EAXIv);
+            else
+                m_formatter.oneByteOp(OP_GROUP1_EvIz, dst, GROUP1_OP_AND);
+            m_formatter.immediate16(imm);
+        }
+    }
+
     void andl_im(int32_t imm, int32_t offset, RegisterID base)
     {
         spew("andl       $0x%x, " MEM_ob, imm, ADDR_ob(offset, base));
         if (CAN_SIGN_EXTEND_8_32(imm)) {
             m_formatter.oneByteOp(OP_GROUP1_EvIb, offset, base, GROUP1_OP_AND);
             m_formatter.immediate8s(imm);
         } else {
             m_formatter.oneByteOp(OP_GROUP1_EvIz, offset, base, GROUP1_OP_AND);
             m_formatter.immediate32(imm);
         }
     }
 
+    void andw_im(int32_t imm, int32_t offset, RegisterID base)
+    {
+        spew("andw       $0x%x, " MEM_ob, int16_t(imm), ADDR_ob(offset, base));
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        if (CAN_SIGN_EXTEND_8_32(imm)) {
+            m_formatter.oneByteOp(OP_GROUP1_EvIb, offset, base, GROUP1_OP_AND);
+            m_formatter.immediate8s(imm);
+        } else {
+            m_formatter.oneByteOp(OP_GROUP1_EvIz, offset, base, GROUP1_OP_AND);
+            m_formatter.immediate16(imm);
+        }
+    }
+
     void andl_im(int32_t imm, int32_t offset, RegisterID base, RegisterID index, int scale)
     {
         spew("andl       $%d, " MEM_obs, imm, ADDR_obs(offset, base, index, scale));
         if (CAN_SIGN_EXTEND_8_32(imm)) {
             m_formatter.oneByteOp(OP_GROUP1_EvIb, offset, base, index, scale, GROUP1_OP_AND);
             m_formatter.immediate8s(imm);
         } else {
             m_formatter.oneByteOp(OP_GROUP1_EvIz, offset, base, index, scale, GROUP1_OP_AND);
             m_formatter.immediate32(imm);
         }
     }
 
+    void andw_im(int32_t imm, int32_t offset, RegisterID base, RegisterID index, int scale)
+    {
+        spew("andw       $%d, " MEM_obs, int16_t(imm), ADDR_obs(offset, base, index, scale));
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        if (CAN_SIGN_EXTEND_8_32(imm)) {
+            m_formatter.oneByteOp(OP_GROUP1_EvIb, offset, base, index, scale, GROUP1_OP_AND);
+            m_formatter.immediate8s(imm);
+        } else {
+            m_formatter.oneByteOp(OP_GROUP1_EvIz, offset, base, index, scale, GROUP1_OP_AND);
+            m_formatter.immediate16(imm);
+        }
+    }
+
 #ifdef JS_CODEGEN_X64
     void andq_rr(RegisterID src, RegisterID dst)
     {
         spew("andq       %s, %s", GPReg64Name(src), GPReg64Name(dst));
         m_formatter.oneByteOp64(OP_AND_GvEv, src, dst);
     }
 
     void andq_mr(int32_t offset, RegisterID base, RegisterID dst)
@@ -866,73 +985,136 @@ public:
     }
 
     void orl_rr(RegisterID src, RegisterID dst)
     {
         spew("orl        %s, %s", GPReg32Name(src), GPReg32Name(dst));
         m_formatter.oneByteOp(OP_OR_GvEv, src, dst);
     }
 
+    void orw_rr(RegisterID src, RegisterID dst)
+    {
+        spew("orw        %s, %s", GPReg16Name(src), GPReg16Name(dst));
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        m_formatter.oneByteOp(OP_OR_GvEv, src, dst);
+    }
+
     void orl_mr(int32_t offset, RegisterID base, RegisterID dst)
     {
         spew("orl        " MEM_ob ", %s", ADDR_ob(offset, base), GPReg32Name(dst));
         m_formatter.oneByteOp(OP_OR_GvEv, offset, base, dst);
     }
 
     void orl_rm(RegisterID src, int32_t offset, RegisterID base)
     {
         spew("orl        %s, " MEM_ob, GPReg32Name(src), ADDR_ob(offset, base));
         m_formatter.oneByteOp(OP_OR_EvGv, offset, base, src);
     }
 
+    void orw_rm(RegisterID src, int32_t offset, RegisterID base)
+    {
+        spew("orw        %s, " MEM_ob, GPReg16Name(src), ADDR_ob(offset, base));
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        m_formatter.oneByteOp(OP_OR_EvGv, offset, base, src);
+    }
+
     void orl_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale)
     {
         spew("orl        %s, " MEM_obs, GPReg32Name(src), ADDR_obs(offset, base, index, scale));
         m_formatter.oneByteOp(OP_OR_EvGv, offset, base, index, scale, src);
     }
 
+    void orw_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale)
+    {
+        spew("orw        %s, " MEM_obs, GPReg16Name(src), ADDR_obs(offset, base, index, scale));
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        m_formatter.oneByteOp(OP_OR_EvGv, offset, base, index, scale, src);
+    }
+
     void orl_ir(int32_t imm, RegisterID dst)
     {
         spew("orl        $0x%x, %s", imm, GPReg32Name(dst));
         if (CAN_SIGN_EXTEND_8_32(imm)) {
             m_formatter.oneByteOp(OP_GROUP1_EvIb, dst, GROUP1_OP_OR);
             m_formatter.immediate8s(imm);
         } else {
             if (dst == rax)
                 m_formatter.oneByteOp(OP_OR_EAXIv);
             else
                 m_formatter.oneByteOp(OP_GROUP1_EvIz, dst, GROUP1_OP_OR);
             m_formatter.immediate32(imm);
         }
     }
 
+    void orw_ir(int32_t imm, RegisterID dst)
+    {
+        spew("orw        $0x%x, %s", int16_t(imm), GPReg16Name(dst));
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        if (CAN_SIGN_EXTEND_8_32(imm)) {
+            m_formatter.oneByteOp(OP_GROUP1_EvIb, dst, GROUP1_OP_OR);
+            m_formatter.immediate8s(imm);
+        } else {
+            if (dst == rax)
+                m_formatter.oneByteOp(OP_OR_EAXIv);
+            else
+                m_formatter.oneByteOp(OP_GROUP1_EvIz, dst, GROUP1_OP_OR);
+            m_formatter.immediate16(imm);
+        }
+    }
+
     void orl_im(int32_t imm, int32_t offset, RegisterID base)
     {
         spew("orl        $0x%x, " MEM_ob, imm, ADDR_ob(offset, base));
         if (CAN_SIGN_EXTEND_8_32(imm)) {
             m_formatter.oneByteOp(OP_GROUP1_EvIb, offset, base, GROUP1_OP_OR);
             m_formatter.immediate8s(imm);
         } else {
             m_formatter.oneByteOp(OP_GROUP1_EvIz, offset, base, GROUP1_OP_OR);
             m_formatter.immediate32(imm);
         }
     }
 
+    void orw_im(int32_t imm, int32_t offset, RegisterID base)
+    {
+        spew("orw        $0x%x, " MEM_ob, int16_t(imm), ADDR_ob(offset, base));
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        if (CAN_SIGN_EXTEND_8_32(imm)) {
+            m_formatter.oneByteOp(OP_GROUP1_EvIb, offset, base, GROUP1_OP_OR);
+            m_formatter.immediate8s(imm);
+        } else {
+            m_formatter.oneByteOp(OP_GROUP1_EvIz, offset, base, GROUP1_OP_OR);
+            m_formatter.immediate16(imm);
+        }
+    }
+
     void orl_im(int32_t imm, int32_t offset, RegisterID base, RegisterID index, int scale)
     {
         spew("orl        $%d, " MEM_obs, imm, ADDR_obs(offset, base, index, scale));
         if (CAN_SIGN_EXTEND_8_32(imm)) {
             m_formatter.oneByteOp(OP_GROUP1_EvIb, offset, base, index, scale, GROUP1_OP_OR);
             m_formatter.immediate8s(imm);
         } else {
             m_formatter.oneByteOp(OP_GROUP1_EvIz, offset, base, index, scale, GROUP1_OP_OR);
             m_formatter.immediate32(imm);
         }
     }
 
+    void orw_im(int32_t imm, int32_t offset, RegisterID base, RegisterID index, int scale)
+    {
+        spew("orw        $%d, " MEM_obs, int16_t(imm), ADDR_obs(offset, base, index, scale));
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        if (CAN_SIGN_EXTEND_8_32(imm)) {
+            m_formatter.oneByteOp(OP_GROUP1_EvIb, offset, base, index, scale, GROUP1_OP_OR);
+            m_formatter.immediate8s(imm);
+        } else {
+            m_formatter.oneByteOp(OP_GROUP1_EvIz, offset, base, index, scale, GROUP1_OP_OR);
+            m_formatter.immediate16(imm);
+        }
+    }
+
 #ifdef JS_CODEGEN_X64
     void negq_r(RegisterID dst)
     {
         spew("negq       %s", GPReg64Name(dst));
         m_formatter.oneByteOp64(OP_GROUP3_Ev, dst, GROUP3_OP_NEG);
     }
 
     void orq_rr(RegisterID src, RegisterID dst)
@@ -976,73 +1158,136 @@ public:
 #endif
 
     void subl_rr(RegisterID src, RegisterID dst)
     {
         spew("subl       %s, %s", GPReg32Name(src), GPReg32Name(dst));
         m_formatter.oneByteOp(OP_SUB_GvEv, src, dst);
     }
 
+    void subw_rr(RegisterID src, RegisterID dst)
+    {
+        spew("subw       %s, %s", GPReg16Name(src), GPReg16Name(dst));
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        m_formatter.oneByteOp(OP_SUB_GvEv, src, dst);
+    }
+
     void subl_mr(int32_t offset, RegisterID base, RegisterID dst)
     {
         spew("subl       " MEM_ob ", %s", ADDR_ob(offset, base), GPReg32Name(dst));
         m_formatter.oneByteOp(OP_SUB_GvEv, offset, base, dst);
     }
 
     void subl_rm(RegisterID src, int32_t offset, RegisterID base)
     {
         spew("subl       %s, " MEM_ob, GPReg32Name(src), ADDR_ob(offset, base));
         m_formatter.oneByteOp(OP_SUB_EvGv, offset, base, src);
     }
 
+    void subw_rm(RegisterID src, int32_t offset, RegisterID base)
+    {
+        spew("subw       %s, " MEM_ob, GPReg16Name(src), ADDR_ob(offset, base));
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        m_formatter.oneByteOp(OP_SUB_EvGv, offset, base, src);
+    }
+
     void subl_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale)
     {
         spew("subl       %s, " MEM_obs, GPReg32Name(src), ADDR_obs(offset, base, index, scale));
         m_formatter.oneByteOp(OP_SUB_EvGv, offset, base, index, scale, src);
     }
 
+    void subw_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale)
+    {
+        spew("subw       %s, " MEM_obs, GPReg16Name(src), ADDR_obs(offset, base, index, scale));
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        m_formatter.oneByteOp(OP_SUB_EvGv, offset, base, index, scale, src);
+    }
+
     void subl_ir(int32_t imm, RegisterID dst)
     {
         spew("subl       $%d, %s", imm, GPReg32Name(dst));
         if (CAN_SIGN_EXTEND_8_32(imm)) {
             m_formatter.oneByteOp(OP_GROUP1_EvIb, dst, GROUP1_OP_SUB);
             m_formatter.immediate8s(imm);
         } else {
             if (dst == rax)
                 m_formatter.oneByteOp(OP_SUB_EAXIv);
             else
                 m_formatter.oneByteOp(OP_GROUP1_EvIz, dst, GROUP1_OP_SUB);
             m_formatter.immediate32(imm);
         }
     }
 
+    void subw_ir(int32_t imm, RegisterID dst)
+    {
+        spew("subw       $%d, %s", int16_t(imm), GPReg16Name(dst));
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        if (CAN_SIGN_EXTEND_8_32(imm)) {
+            m_formatter.oneByteOp(OP_GROUP1_EvIb, dst, GROUP1_OP_SUB);
+            m_formatter.immediate8s(imm);
+        } else {
+            if (dst == rax)
+                m_formatter.oneByteOp(OP_SUB_EAXIv);
+            else
+                m_formatter.oneByteOp(OP_GROUP1_EvIz, dst, GROUP1_OP_SUB);
+            m_formatter.immediate16(imm);
+        }
+    }
+
     void subl_im(int32_t imm, int32_t offset, RegisterID base)
     {
         spew("subl       $%d, " MEM_ob, imm, ADDR_ob(offset, base));
         if (CAN_SIGN_EXTEND_8_32(imm)) {
             m_formatter.oneByteOp(OP_GROUP1_EvIb, offset, base, GROUP1_OP_SUB);
             m_formatter.immediate8s(imm);
         } else {
             m_formatter.oneByteOp(OP_GROUP1_EvIz, offset, base, GROUP1_OP_SUB);
             m_formatter.immediate32(imm);
         }
     }
 
+    void subw_im(int32_t imm, int32_t offset, RegisterID base)
+    {
+        spew("subw       $%d, " MEM_ob, int16_t(imm), ADDR_ob(offset, base));
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        if (CAN_SIGN_EXTEND_8_32(imm)) {
+            m_formatter.oneByteOp(OP_GROUP1_EvIb, offset, base, GROUP1_OP_SUB);
+            m_formatter.immediate8s(imm);
+        } else {
+            m_formatter.oneByteOp(OP_GROUP1_EvIz, offset, base, GROUP1_OP_SUB);
+            m_formatter.immediate16(imm);
+        }
+    }
+
     void subl_im(int32_t imm, int32_t offset, RegisterID base, RegisterID index, int scale)
     {
         spew("subl       $%d, " MEM_obs, imm, ADDR_obs(offset, base, index, scale));
         if (CAN_SIGN_EXTEND_8_32(imm)) {
             m_formatter.oneByteOp(OP_GROUP1_EvIb, offset, base, index, scale, GROUP1_OP_SUB);
             m_formatter.immediate8s(imm);
         } else {
             m_formatter.oneByteOp(OP_GROUP1_EvIz, offset, base, index, scale, GROUP1_OP_SUB);
             m_formatter.immediate32(imm);
         }
     }
 
+    void subw_im(int32_t imm, int32_t offset, RegisterID base, RegisterID index, int scale)
+    {
+        spew("subw       $%d, " MEM_obs, int16_t(imm), ADDR_obs(offset, base, index, scale));
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        if (CAN_SIGN_EXTEND_8_32(imm)) {
+            m_formatter.oneByteOp(OP_GROUP1_EvIb, offset, base, index, scale, GROUP1_OP_SUB);
+            m_formatter.immediate8s(imm);
+        } else {
+            m_formatter.oneByteOp(OP_GROUP1_EvIz, offset, base, index, scale, GROUP1_OP_SUB);
+            m_formatter.immediate16(imm);
+        }
+    }
+
 #ifdef JS_CODEGEN_X64
     void subq_rr(RegisterID src, RegisterID dst)
     {
         spew("subq       %s, %s", GPReg64Name(src), GPReg64Name(dst));
         m_formatter.oneByteOp64(OP_SUB_GvEv, src, dst);
     }
 
     void subq_rm(RegisterID src, int32_t offset, RegisterID base)
@@ -1092,73 +1337,136 @@ public:
 #endif
 
     void xorl_rr(RegisterID src, RegisterID dst)
     {
         spew("xorl       %s, %s", GPReg32Name(src), GPReg32Name(dst));
         m_formatter.oneByteOp(OP_XOR_GvEv, src, dst);
     }
 
+    void xorw_rr(RegisterID src, RegisterID dst)
+    {
+        spew("xorw       %s, %s", GPReg16Name(src), GPReg16Name(dst));
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        m_formatter.oneByteOp(OP_XOR_GvEv, src, dst);
+    }
+
     void xorl_mr(int32_t offset, RegisterID base, RegisterID dst)
     {
         spew("xorl       " MEM_ob ", %s", ADDR_ob(offset, base), GPReg32Name(dst));
         m_formatter.oneByteOp(OP_XOR_GvEv, offset, base, dst);
     }
 
     void xorl_rm(RegisterID src, int32_t offset, RegisterID base)
     {
         spew("xorl       %s, " MEM_ob, GPReg32Name(src), ADDR_ob(offset, base));
         m_formatter.oneByteOp(OP_XOR_EvGv, offset, base, src);
     }
 
+    void xorw_rm(RegisterID src, int32_t offset, RegisterID base)
+    {
+        spew("xorw       %s, " MEM_ob, GPReg16Name(src), ADDR_ob(offset, base));
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        m_formatter.oneByteOp(OP_XOR_EvGv, offset, base, src);
+    }
+
     void xorl_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale)
     {
         spew("xorl       %s, " MEM_obs, GPReg32Name(src), ADDR_obs(offset, base, index, scale));
         m_formatter.oneByteOp(OP_XOR_EvGv, offset, base, index, scale, src);
     }
 
+    void xorw_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale)
+    {
+        spew("xorw       %s, " MEM_obs, GPReg16Name(src), ADDR_obs(offset, base, index, scale));
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        m_formatter.oneByteOp(OP_XOR_EvGv, offset, base, index, scale, src);
+    }
+
     void xorl_im(int32_t imm, int32_t offset, RegisterID base)
     {
         spew("xorl       $0x%x, " MEM_ob, imm, ADDR_ob(offset, base));
         if (CAN_SIGN_EXTEND_8_32(imm)) {
             m_formatter.oneByteOp(OP_GROUP1_EvIb, offset, base, GROUP1_OP_XOR);
             m_formatter.immediate8s(imm);
         } else {
             m_formatter.oneByteOp(OP_GROUP1_EvIz, offset, base, GROUP1_OP_XOR);
             m_formatter.immediate32(imm);
         }
     }
 
+    void xorw_im(int32_t imm, int32_t offset, RegisterID base)
+    {
+        spew("xorw       $0x%x, " MEM_ob, int16_t(imm), ADDR_ob(offset, base));
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        if (CAN_SIGN_EXTEND_8_32(imm)) {
+            m_formatter.oneByteOp(OP_GROUP1_EvIb, offset, base, GROUP1_OP_XOR);
+            m_formatter.immediate8s(imm);
+        } else {
+            m_formatter.oneByteOp(OP_GROUP1_EvIz, offset, base, GROUP1_OP_XOR);
+            m_formatter.immediate16(imm);
+        }
+    }
+
     void xorl_im(int32_t imm, int32_t offset, RegisterID base, RegisterID index, int scale)
     {
         spew("xorl       $%d, " MEM_obs, imm, ADDR_obs(offset, base, index, scale));
         if (CAN_SIGN_EXTEND_8_32(imm)) {
             m_formatter.oneByteOp(OP_GROUP1_EvIb, offset, base, index, scale, GROUP1_OP_XOR);
             m_formatter.immediate8s(imm);
         } else {
             m_formatter.oneByteOp(OP_GROUP1_EvIz, offset, base, index, scale, GROUP1_OP_XOR);
             m_formatter.immediate32(imm);
         }
     }
 
+    void xorw_im(int32_t imm, int32_t offset, RegisterID base, RegisterID index, int scale)
+    {
+        spew("xorw       $%d, " MEM_obs, int16_t(imm), ADDR_obs(offset, base, index, scale));
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        if (CAN_SIGN_EXTEND_8_32(imm)) {
+            m_formatter.oneByteOp(OP_GROUP1_EvIb, offset, base, index, scale, GROUP1_OP_XOR);
+            m_formatter.immediate8s(imm);
+        } else {
+            m_formatter.oneByteOp(OP_GROUP1_EvIz, offset, base, index, scale, GROUP1_OP_XOR);
+            m_formatter.immediate16(imm);
+        }
+    }
+
     void xorl_ir(int32_t imm, RegisterID dst)
     {
         spew("xorl       $%d, %s", imm, GPReg32Name(dst));
         if (CAN_SIGN_EXTEND_8_32(imm)) {
             m_formatter.oneByteOp(OP_GROUP1_EvIb, dst, GROUP1_OP_XOR);
             m_formatter.immediate8s(imm);
         } else {
             if (dst == rax)
                 m_formatter.oneByteOp(OP_XOR_EAXIv);
             else
                 m_formatter.oneByteOp(OP_GROUP1_EvIz, dst, GROUP1_OP_XOR);
             m_formatter.immediate32(imm);
         }
     }
 
+    void xorw_ir(int32_t imm, RegisterID dst)
+    {
+        spew("xorw       $%d, %s", int16_t(imm), GPReg16Name(dst));
+        m_formatter.prefix(PRE_OPERAND_SIZE);
+        if (CAN_SIGN_EXTEND_8_32(imm)) {
+            m_formatter.oneByteOp(OP_GROUP1_EvIb, dst, GROUP1_OP_XOR);
+            m_formatter.immediate8s(imm);
+        } else {
+            if (dst == rax)
+                m_formatter.oneByteOp(OP_XOR_EAXIv);
+            else
+                m_formatter.oneByteOp(OP_GROUP1_EvIz, dst, GROUP1_OP_XOR);
+            m_formatter.immediate16(imm);
+        }
+    }
+
 #ifdef JS_CODEGEN_X64
     void xorq_rr(RegisterID src, RegisterID dst)
     {
         spew("xorq       %s, %s", GPReg64Name(src), GPReg64Name(dst));
         m_formatter.oneByteOp64(OP_XOR_GvEv, src, dst);
     }
 
     void xorq_ir(int32_t imm, RegisterID dst)