Title: [193804] trunk/Source/_javascript_Core
Revision
193804
Author
[email protected]
Date
2015-12-08 18:30:39 -0800 (Tue, 08 Dec 2015)

Log Message

[JSC] Improve how B3 lowers Add() and Sub() on x86
https://bugs.webkit.org/show_bug.cgi?id=152026

Patch by Benjamin Poulain <[email protected]> on 2015-12-08
Reviewed by Geoffrey Garen.

The assembler was missing some important x86 forms of
ADD and SUB that were making our lowering
unfriendly with register allocation.

First, we were missing a 3 operand version of Add
implement with LEA. As a result, an Add would
be lowered as:
    Move op1->srcDest
    Add op2, srcDest
The problem with such code is that op2 and srcDest
interferes. It is impossible to assign them the same
machine register.

With the new Add form, we have:
    Add op1, op2, dest
without interferences between any of those values.
The add is implement by a LEA without scaling or displacement.

This patch also adds missing forms of Add and Sub with
direct addressing for arguments. This avoids dealing with Tmps
that only exist for those operations.

Finally, the lowering of adding something to itself was updated accordingly.
Such operation is transformed in Shl by 2. The lowering of Shl
was adding an explicit Move, preventing the use of LEA when it
is useful.
Instead of having an explicit move, I changed the direct addressing
forms to only be selected if the two operands are different.
A Move is then added by appendBinOp() if needed.

* assembler/MacroAssemblerX86Common.h:
(JSC::MacroAssemblerX86Common::add32):
(JSC::MacroAssemblerX86Common::x86Lea32):
* assembler/MacroAssemblerX86_64.h:
(JSC::MacroAssemblerX86_64::add64):
(JSC::MacroAssemblerX86_64::x86Lea64):
(JSC::MacroAssemblerX86_64::sub64):
* assembler/X86Assembler.h:
(JSC::X86Assembler::addq_rm):
(JSC::X86Assembler::subq_mr):
(JSC::X86Assembler::subq_rm):
(JSC::X86Assembler::subq_im):
(JSC::X86Assembler::leal_mr):
(JSC::X86Assembler::leaq_mr):
* b3/B3LowerToAir.cpp:
(JSC::B3::Air::LowerToAir::appendBinOp):
(JSC::B3::Air::LowerToAir::lower):
* b3/air/AirOpcode.opcodes:
* b3/testb3.cpp:
(JSC::B3::testAddArgMem):
(JSC::B3::testAddMemArg):
(JSC::B3::testAddImmMem):
(JSC::B3::testAddArg32):
(JSC::B3::testAddArgMem32):
(JSC::B3::testAddMemArg32):
(JSC::B3::testAddImmMem32):
(JSC::B3::testSubArgMem):
(JSC::B3::testSubMemArg):
(JSC::B3::testSubImmMem):
(JSC::B3::testSubMemImm):
(JSC::B3::testSubMemArg32):
(JSC::B3::testSubArgMem32):
(JSC::B3::testSubImmMem32):
(JSC::B3::testSubMemImm32):
(JSC::B3::run):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (193803 => 193804)


--- trunk/Source/_javascript_Core/ChangeLog	2015-12-09 02:01:25 UTC (rev 193803)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-12-09 02:30:39 UTC (rev 193804)
@@ -1,3 +1,76 @@
+2015-12-08  Benjamin Poulain  <[email protected]>
+
+        [JSC] Improve how B3 lowers Add() and Sub() on x86
+        https://bugs.webkit.org/show_bug.cgi?id=152026
+
+        Reviewed by Geoffrey Garen.
+
+        The assembler was missing some important x86 forms of
+        ADD and SUB that were making our lowering
+        unfriendly with register allocation.
+
+        First, we were missing a 3 operand version of Add
+        implement with LEA. As a result, an Add would
+        be lowered as:
+            Move op1->srcDest
+            Add op2, srcDest
+        The problem with such code is that op2 and srcDest
+        interferes. It is impossible to assign them the same
+        machine register.
+
+        With the new Add form, we have:
+            Add op1, op2, dest
+        without interferences between any of those values.
+        The add is implement by a LEA without scaling or displacement.
+
+        This patch also adds missing forms of Add and Sub with
+        direct addressing for arguments. This avoids dealing with Tmps
+        that only exist for those operations.
+
+        Finally, the lowering of adding something to itself was updated accordingly.
+        Such operation is transformed in Shl by 2. The lowering of Shl
+        was adding an explicit Move, preventing the use of LEA when it
+        is useful.
+        Instead of having an explicit move, I changed the direct addressing
+        forms to only be selected if the two operands are different.
+        A Move is then added by appendBinOp() if needed.
+
+        * assembler/MacroAssemblerX86Common.h:
+        (JSC::MacroAssemblerX86Common::add32):
+        (JSC::MacroAssemblerX86Common::x86Lea32):
+        * assembler/MacroAssemblerX86_64.h:
+        (JSC::MacroAssemblerX86_64::add64):
+        (JSC::MacroAssemblerX86_64::x86Lea64):
+        (JSC::MacroAssemblerX86_64::sub64):
+        * assembler/X86Assembler.h:
+        (JSC::X86Assembler::addq_rm):
+        (JSC::X86Assembler::subq_mr):
+        (JSC::X86Assembler::subq_rm):
+        (JSC::X86Assembler::subq_im):
+        (JSC::X86Assembler::leal_mr):
+        (JSC::X86Assembler::leaq_mr):
+        * b3/B3LowerToAir.cpp:
+        (JSC::B3::Air::LowerToAir::appendBinOp):
+        (JSC::B3::Air::LowerToAir::lower):
+        * b3/air/AirOpcode.opcodes:
+        * b3/testb3.cpp:
+        (JSC::B3::testAddArgMem):
+        (JSC::B3::testAddMemArg):
+        (JSC::B3::testAddImmMem):
+        (JSC::B3::testAddArg32):
+        (JSC::B3::testAddArgMem32):
+        (JSC::B3::testAddMemArg32):
+        (JSC::B3::testAddImmMem32):
+        (JSC::B3::testSubArgMem):
+        (JSC::B3::testSubMemArg):
+        (JSC::B3::testSubImmMem):
+        (JSC::B3::testSubMemImm):
+        (JSC::B3::testSubMemArg32):
+        (JSC::B3::testSubArgMem32):
+        (JSC::B3::testSubImmMem32):
+        (JSC::B3::testSubMemImm32):
+        (JSC::B3::run):
+
 2015-12-08  Mark Lam  <[email protected]>
 
         Factoring out common DFG code for bitwise and shift operators.

Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h (193803 => 193804)


--- trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h	2015-12-09 02:01:25 UTC (rev 193803)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h	2015-12-09 02:30:39 UTC (rev 193804)
@@ -160,6 +160,26 @@
 
         m_assembler.leal_mr(imm.m_value, src, dest);
     }
+
+    void add32(RegisterID a, RegisterID b, RegisterID dest)
+    {
+        x86Lea32(BaseIndex(a, b, TimesOne), dest);
+    }
+
+    void x86Lea32(BaseIndex index, RegisterID dest)
+    {
+        if (!index.scale && !index.offset) {
+            if (index.base == dest) {
+                add32(index.index, dest);
+                return;
+            }
+            if (index.index == dest) {
+                add32(index.base, dest);
+                return;
+            }
+        }
+        m_assembler.leal_mr(index.offset, index.base, index.index, index.scale, dest);
+    }
     
     void and32(RegisterID src, RegisterID dest)
     {

Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerX86_64.h (193803 => 193804)


--- trunk/Source/_javascript_Core/assembler/MacroAssemblerX86_64.h	2015-12-09 02:01:25 UTC (rev 193803)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerX86_64.h	2015-12-09 02:30:39 UTC (rev 193804)
@@ -263,6 +263,11 @@
         m_assembler.addq_mr(src.offset, src.base, dest);
     }
 
+    void add64(RegisterID src, Address dest)
+    {
+        m_assembler.addq_rm(src, dest.offset, dest.base);
+    }
+
     void add64(AbsoluteAddress src, RegisterID dest)
     {
         move(TrustedImmPtr(src.m_ptr), scratchRegister());
@@ -313,6 +318,26 @@
         add64(imm, Address(scratchRegister()));
     }
 
+    void add64(RegisterID a, RegisterID b, RegisterID dest)
+    {
+        x86Lea64(BaseIndex(a, b, TimesOne), dest);
+    }
+
+    void x86Lea64(BaseIndex index, RegisterID dest)
+    {
+        if (!index.scale && !index.offset) {
+            if (index.base == dest) {
+                add64(index.index, dest);
+                return;
+            }
+            if (index.index == dest) {
+                add64(index.base, dest);
+                return;
+            }
+        }
+        m_assembler.leaq_mr(index.offset, index.base, index.index, index.scale, dest);
+    }
+
     void addPtrNoFlags(TrustedImm32 imm, RegisterID srcDest)
     {
         m_assembler.leaq_mr(imm.m_value, srcDest, srcDest);
@@ -507,6 +532,21 @@
         }
     }
 
+    void sub64(TrustedImm32 imm, Address address)
+    {
+        m_assembler.subq_im(imm.m_value, address.offset, address.base);
+    }
+
+    void sub64(Address src, RegisterID dest)
+    {
+        m_assembler.subq_mr(src.offset, src.base, dest);
+    }
+
+    void sub64(RegisterID src, Address dest)
+    {
+        m_assembler.subq_rm(src, dest.offset, dest.base);
+    }
+
     void xor64(RegisterID src, RegisterID dest)
     {
         m_assembler.xorq_rr(src, dest);

Modified: trunk/Source/_javascript_Core/assembler/X86Assembler.h (193803 => 193804)


--- trunk/Source/_javascript_Core/assembler/X86Assembler.h	2015-12-09 02:01:25 UTC (rev 193803)
+++ trunk/Source/_javascript_Core/assembler/X86Assembler.h	2015-12-09 02:30:39 UTC (rev 193804)
@@ -464,6 +464,11 @@
         m_formatter.oneByteOp64(OP_ADD_GvEv, dst, base, offset);
     }
 
+    void addq_rm(RegisterID src, int offset, RegisterID base)
+    {
+        m_formatter.oneByteOp64(OP_ADD_EvGv, src, base, offset);
+    }
+
     void addq_ir(int imm, RegisterID dst)
     {
         if (CAN_SIGN_EXTEND_8_32(imm)) {
@@ -758,6 +763,16 @@
         m_formatter.oneByteOp64(OP_SUB_EvGv, src, dst);
     }
 
+    void subq_mr(int offset, RegisterID base, RegisterID dst)
+    {
+        m_formatter.oneByteOp64(OP_SUB_GvEv, dst, base, offset);
+    }
+
+    void subq_rm(RegisterID src, int offset, RegisterID base)
+    {
+        m_formatter.oneByteOp64(OP_SUB_EvGv, src, base, offset);
+    }
+
     void subq_ir(int imm, RegisterID dst)
     {
         if (CAN_SIGN_EXTEND_8_32(imm)) {
@@ -771,6 +786,17 @@
             m_formatter.immediate32(imm);
         }
     }
+
+    void subq_im(int imm, int offset, RegisterID base)
+    {
+        if (CAN_SIGN_EXTEND_8_32(imm)) {
+            m_formatter.oneByteOp64(OP_GROUP1_EvIb, GROUP1_OP_SUB, base, offset);
+            m_formatter.immediate8(imm);
+        } else {
+            m_formatter.oneByteOp64(OP_GROUP1_EvIz, GROUP1_OP_SUB, base, offset);
+            m_formatter.immediate32(imm);
+        }
+    }
 #else
     void subl_im(int imm, const void* addr)
     {
@@ -1773,11 +1799,22 @@
     {
         m_formatter.oneByteOp(OP_LEA, dst, base, offset);
     }
+
+    void leal_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst)
+    {
+        m_formatter.oneByteOp(OP_LEA, dst, base, index, scale, offset);
+    }
+
 #if CPU(X86_64)
     void leaq_mr(int offset, RegisterID base, RegisterID dst)
     {
         m_formatter.oneByteOp64(OP_LEA, dst, base, offset);
     }
+
+    void leaq_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst)
+    {
+        m_formatter.oneByteOp64(OP_LEA, dst, base, index, scale, offset);
+    }
 #endif
 
     // Flow control:

Modified: trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp (193803 => 193804)


--- trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp	2015-12-09 02:01:25 UTC (rev 193803)
+++ trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp	2015-12-09 02:30:39 UTC (rev 193804)
@@ -621,23 +621,25 @@
 
         // At this point, we prefer versions of the operation that have a fused load or an immediate
         // over three operand forms.
-        
-        if (commutativity == Commutative) {
-            ArgPromise leftAddr = loadPromise(left);
-            if (isValidForm(opcode, leftAddr.kind(), Arg::Tmp)) {
-                append(relaxedMoveForType(m_value->type()), tmp(right), result);
-                append(opcode, leftAddr.consume(*this), result);
+
+        if (left != right) {
+            if (commutativity == Commutative) {
+                ArgPromise leftAddr = loadPromise(left);
+                if (isValidForm(opcode, leftAddr.kind(), Arg::Tmp)) {
+                    append(relaxedMoveForType(m_value->type()), tmp(right), result);
+                    append(opcode, leftAddr.consume(*this), result);
+                    return;
+                }
+            }
+
+            ArgPromise rightAddr = loadPromise(right);
+            if (isValidForm(opcode, rightAddr.kind(), Arg::Tmp)) {
+                append(relaxedMoveForType(m_value->type()), tmp(left), result);
+                append(opcode, rightAddr.consume(*this), result);
                 return;
             }
         }
 
-        ArgPromise rightAddr = loadPromise(right);
-        if (isValidForm(opcode, rightAddr.kind(), Arg::Tmp)) {
-            append(relaxedMoveForType(m_value->type()), tmp(left), result);
-            append(opcode, rightAddr.consume(*this), result);
-            return;
-        }
-
         if (imm(right) && isValidForm(opcode, Arg::Imm, Arg::Tmp)) {
             append(relaxedMoveForType(m_value->type()), tmp(left), result);
             append(opcode, imm(right), result);
@@ -1494,11 +1496,7 @@
 
         case Shl: {
             if (m_value->child(1)->isInt32(1)) {
-                // This optimization makes sense on X86. I don't know if it makes sense anywhere else.
-                append(Move, tmp(m_value->child(0)), tmp(m_value));
-                append(
-                    opcodeForType(Add32, Add64, m_value->child(0)->type()),
-                    tmp(m_value), tmp(m_value));
+                appendBinOp<Add32, Add64, AddDouble, AddFloat, Commutative>(m_value->child(0), m_value->child(0));
                 return;
             }
             

Modified: trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes (193803 => 193804)


--- trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes	2015-12-09 02:01:25 UTC (rev 193803)
+++ trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes	2015-12-09 02:30:39 UTC (rev 193804)
@@ -68,15 +68,18 @@
 
 Add32 U:G, U:G, D:G
     Imm, Tmp, Tmp
+    Tmp, Tmp, Tmp
 
 Add64 U:G, UD:G
     Tmp, Tmp
     Imm, Addr
     Imm, Tmp
     Addr, Tmp
+    Tmp, Addr
 
 Add64 U:G, U:G, D:G
     Imm, Tmp, Tmp
+    Tmp, Tmp, Tmp
 
 AddDouble U:F, UD:F
     Tmp, Tmp
@@ -95,7 +98,10 @@
 
 Sub64 U:G, UD:G
     Tmp, Tmp
+    Imm, Addr
     Imm, Tmp
+    Addr, Tmp
+    Tmp, Addr
 
 SubDouble U:F, UD:F
     Tmp, Tmp

Modified: trunk/Source/_javascript_Core/b3/testb3.cpp (193803 => 193804)


--- trunk/Source/_javascript_Core/b3/testb3.cpp	2015-12-09 02:01:25 UTC (rev 193803)
+++ trunk/Source/_javascript_Core/b3/testb3.cpp	2015-12-09 02:30:39 UTC (rev 193804)
@@ -203,6 +203,67 @@
     CHECK(compileAndRun<int>(proc, b) == a + b);
 }
 
+void testAddArgMem(int64_t a, int64_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), address);
+    Value* result = root->appendNew<Value>(proc, Add, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+        load);
+    root->appendNew<MemoryValue>(proc, Store, Origin(), result, address);
+    root->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
+
+    int64_t inputOutput = b;
+    CHECK(!compileAndRun<int64_t>(proc, a, &inputOutput));
+    CHECK(inputOutput == a + b);
+}
+
+void testAddMemArg(int64_t a, int64_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), address);
+    Value* result = root->appendNew<Value>(proc, Add, Origin(),
+        load,
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+
+    CHECK(compileAndRun<int64_t>(proc, &a, b) == a + b);
+}
+
+void testAddImmMem(int64_t a, int64_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), address);
+    Value* result = root->appendNew<Value>(proc, Add, Origin(),
+        root->appendNew<Const64Value>(proc, Origin(), a),
+        load);
+    root->appendNew<MemoryValue>(proc, Store, Origin(), result, address);
+    root->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
+
+    int64_t inputOutput = b;
+    CHECK(!compileAndRun<int>(proc, &inputOutput));
+    CHECK(inputOutput == a + b);
+}
+
+void testAddArg32(int a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* value = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    root->appendNew<ControlValue>(
+        proc, Return, Origin(),
+        root->appendNew<Value>(proc, Add, Origin(), value, value));
+
+    CHECK(compileAndRun<int>(proc, a) == a + a);
+}
+
 void testAddArgs32(int a, int b)
 {
     Procedure proc;
@@ -221,6 +282,54 @@
     CHECK(compileAndRun<int>(proc, a, b) == a + b);
 }
 
+void testAddArgMem32(int32_t a, int32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), address);
+    Value* argument = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* result = root->appendNew<Value>(proc, Add, Origin(), argument, load);
+    root->appendNew<MemoryValue>(proc, Store, Origin(), result, address);
+    root->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
+
+    int32_t inputOutput = b;
+    CHECK(!compileAndRun<int32_t>(proc, a, &inputOutput));
+    CHECK(inputOutput == a + b);
+}
+
+void testAddMemArg32(int32_t a, int32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), address);
+    Value* argument = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+    Value* result = root->appendNew<Value>(proc, Add, Origin(), load, argument);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+
+    CHECK(compileAndRun<int32_t>(proc, &a, b) == a + b);
+}
+
+void testAddImmMem32(int32_t a, int32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), address);
+    Value* result = root->appendNew<Value>(proc, Add, Origin(),
+        root->appendNew<Const32Value>(proc, Origin(), a),
+        load);
+    root->appendNew<MemoryValue>(proc, Store, Origin(), result, address);
+    root->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
+
+    int32_t inputOutput = b;
+    CHECK(!compileAndRun<int>(proc, &inputOutput));
+    CHECK(inputOutput == a + b);
+}
+
 void testAddLoadTwice()
 {
     auto test = [&] (unsigned optLevel) {
@@ -1047,6 +1156,72 @@
     CHECK(compileAndRun<int>(proc, b) == a - b);
 }
 
+void testSubArgMem(int64_t a, int64_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), address);
+    Value* result = root->appendNew<Value>(proc, Sub, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0),
+        load);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+
+    CHECK(compileAndRun<int64_t>(proc, a, &b) == a - b);
+}
+
+void testSubMemArg(int64_t a, int64_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), address);
+    Value* result = root->appendNew<Value>(proc, Sub, Origin(),
+        load,
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+    root->appendNew<MemoryValue>(proc, Store, Origin(), result, address);
+    root->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
+
+    int64_t inputOutput = a;
+    CHECK(!compileAndRun<int64_t>(proc, &inputOutput, b));
+    CHECK(inputOutput == a - b);
+}
+
+void testSubImmMem(int64_t a, int64_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), address);
+    Value* result = root->appendNew<Value>(proc, Sub, Origin(),
+        root->appendNew<Const64Value>(proc, Origin(), a),
+        load);
+    root->appendNew<MemoryValue>(proc, Store, Origin(), result, address);
+    root->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
+
+    int64_t inputOutput = b;
+    CHECK(!compileAndRun<int>(proc, &inputOutput));
+    CHECK(inputOutput == a - b);
+}
+
+void testSubMemImm(int64_t a, int64_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int64, Origin(), address);
+    Value* result = root->appendNew<Value>(proc, Sub, Origin(),
+        load,
+        root->appendNew<Const64Value>(proc, Origin(), b));
+    root->appendNew<MemoryValue>(proc, Store, Origin(), result, address);
+    root->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
+
+    int64_t inputOutput = a;
+    CHECK(!compileAndRun<int>(proc, &inputOutput));
+    CHECK(inputOutput == a - b);
+}
+
+
 void testSubArgs32(int a, int b)
 {
     Procedure proc;
@@ -1097,6 +1272,71 @@
     CHECK(compileAndRun<int>(proc, b) == a - b);
 }
 
+void testSubMemArg32(int32_t a, int32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), address);
+    Value* argument = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+    Value* result = root->appendNew<Value>(proc, Sub, Origin(), load, argument);
+    root->appendNew<MemoryValue>(proc, Store, Origin(), result, address);
+    root->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
+
+    int32_t inputOutput = a;
+    CHECK(!compileAndRun<int32_t>(proc, &inputOutput, b));
+    CHECK(inputOutput == a - b);
+}
+
+void testSubArgMem32(int32_t a, int32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), address);
+    Value* argument = root->appendNew<Value>(proc, Trunc, Origin(),
+        root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* result = root->appendNew<Value>(proc, Sub, Origin(), argument, load);
+    root->appendNew<ControlValue>(proc, Return, Origin(), result);
+
+    CHECK(compileAndRun<int32_t>(proc, a, &b) == a - b);
+}
+
+void testSubImmMem32(int32_t a, int32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), address);
+    Value* result = root->appendNew<Value>(proc, Sub, Origin(),
+        root->appendNew<Const32Value>(proc, Origin(), a),
+        load);
+    root->appendNew<MemoryValue>(proc, Store, Origin(), result, address);
+    root->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
+
+    int32_t inputOutput = b;
+    CHECK(!compileAndRun<int>(proc, &inputOutput));
+    CHECK(inputOutput == a - b);
+}
+
+void testSubMemImm32(int32_t a, int32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root->appendNew<MemoryValue>(proc, Load, Int32, Origin(), address);
+    Value* result = root->appendNew<Value>(proc, Sub, Origin(),
+        load,
+        root->appendNew<Const32Value>(proc, Origin(), b));
+    root->appendNew<MemoryValue>(proc, Store, Origin(), result, address);
+    root->appendNew<ControlValue>(proc, Return, Origin(), root->appendNew<Const32Value>(proc, Origin(), 0));
+
+    int32_t inputOutput = a;
+    CHECK(!compileAndRun<int>(proc, &inputOutput));
+    CHECK(inputOutput == a - b);
+}
+
 void testNegValueSubOne32(int a)
 {
     Procedure proc;
@@ -6690,8 +6930,15 @@
     RUN(testAddImmArg(1, 2));
     RUN(testAddImmArg(0, 2));
     RUN(testAddImmArg(1, 0));
+    RUN_BINARY(testAddArgMem, int64Operands(), int64Operands());
+    RUN_BINARY(testAddMemArg, int64Operands(), int64Operands());
+    RUN_BINARY(testAddImmMem, int64Operands(), int64Operands());
+    RUN_UNARY(testAddArg32, int32Operands());
     RUN(testAddArgs32(1, 1));
     RUN(testAddArgs32(1, 2));
+    RUN_BINARY(testAddArgMem32, int32Operands(), int32Operands());
+    RUN_BINARY(testAddMemArg32, int32Operands(), int32Operands());
+    RUN_BINARY(testAddImmMem32, int32Operands(), int32Operands());
     RUN(testAddLoadTwice());
 
     RUN(testAddArgDouble(M_PI));
@@ -6826,6 +7073,10 @@
     RUN(testSubImmArg(1, 2));
     RUN(testSubImmArg(13, -42));
     RUN(testSubImmArg(-13, 42));
+    RUN_BINARY(testSubArgMem, int64Operands(), int64Operands());
+    RUN_BINARY(testSubMemArg, int64Operands(), int64Operands());
+    RUN_BINARY(testSubImmMem, int32Operands(), int32Operands());
+    RUN_BINARY(testSubMemImm, int32Operands(), int32Operands());
     RUN_UNARY(testNegValueSubOne, int32Operands());
 
     RUN(testSubArgs32(1, 1));
@@ -6840,6 +7091,10 @@
     RUN(testSubImmArg32(1, 2));
     RUN(testSubImmArg32(13, -42));
     RUN(testSubImmArg32(-13, 42));
+    RUN_BINARY(testSubArgMem32, int32Operands(), int32Operands());
+    RUN_BINARY(testSubMemArg32, int32Operands(), int32Operands());
+    RUN_BINARY(testSubImmMem32, int32Operands(), int32Operands());
+    RUN_BINARY(testSubMemImm32, int32Operands(), int32Operands());
     RUN_UNARY(testNegValueSubOne32, int64Operands());
 
     RUN_UNARY(testSubArgDouble, floatingPointOperands<double>());
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to