<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[193804] trunk/Source/JavaScriptCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/193804">193804</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2015-12-08 18:30:39 -0800 (Tue, 08 Dec 2015)</dd>
</dl>

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

Patch by Benjamin Poulain &lt;bpoulain@apple.com&gt; 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-&gt;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):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerMacroAssemblerX86Commonh">trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerMacroAssemblerX86_64h">trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerX86Assemblerh">trunk/Source/JavaScriptCore/assembler/X86Assembler.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3LowerToAircpp">trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirOpcodeopcodes">trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3testb3cpp">trunk/Source/JavaScriptCore/b3/testb3.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (193803 => 193804)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-12-09 02:01:25 UTC (rev 193803)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-12-09 02:30:39 UTC (rev 193804)
</span><span class="lines">@@ -1,3 +1,76 @@
</span><ins>+2015-12-08  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
+
+        [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-&gt;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):
+
</ins><span class="cx"> 2015-12-08  Mark Lam  &lt;mark.lam@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Factoring out common DFG code for bitwise and shift operators.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerX86Commonh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h (193803 => 193804)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h        2015-12-09 02:01:25 UTC (rev 193803)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h        2015-12-09 02:30:39 UTC (rev 193804)
</span><span class="lines">@@ -160,6 +160,26 @@
</span><span class="cx"> 
</span><span class="cx">         m_assembler.leal_mr(imm.m_value, src, dest);
</span><span class="cx">     }
</span><ins>+
+    void add32(RegisterID a, RegisterID b, RegisterID dest)
+    {
+        x86Lea32(BaseIndex(a, b, TimesOne), dest);
+    }
+
+    void x86Lea32(BaseIndex index, RegisterID dest)
+    {
+        if (!index.scale &amp;&amp; !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);
+    }
</ins><span class="cx">     
</span><span class="cx">     void and32(RegisterID src, RegisterID dest)
</span><span class="cx">     {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerX86_64h"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h (193803 => 193804)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h        2015-12-09 02:01:25 UTC (rev 193803)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h        2015-12-09 02:30:39 UTC (rev 193804)
</span><span class="lines">@@ -263,6 +263,11 @@
</span><span class="cx">         m_assembler.addq_mr(src.offset, src.base, dest);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void add64(RegisterID src, Address dest)
+    {
+        m_assembler.addq_rm(src, dest.offset, dest.base);
+    }
+
</ins><span class="cx">     void add64(AbsoluteAddress src, RegisterID dest)
</span><span class="cx">     {
</span><span class="cx">         move(TrustedImmPtr(src.m_ptr), scratchRegister());
</span><span class="lines">@@ -313,6 +318,26 @@
</span><span class="cx">         add64(imm, Address(scratchRegister()));
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void add64(RegisterID a, RegisterID b, RegisterID dest)
+    {
+        x86Lea64(BaseIndex(a, b, TimesOne), dest);
+    }
+
+    void x86Lea64(BaseIndex index, RegisterID dest)
+    {
+        if (!index.scale &amp;&amp; !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);
+    }
+
</ins><span class="cx">     void addPtrNoFlags(TrustedImm32 imm, RegisterID srcDest)
</span><span class="cx">     {
</span><span class="cx">         m_assembler.leaq_mr(imm.m_value, srcDest, srcDest);
</span><span class="lines">@@ -507,6 +532,21 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    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);
+    }
+
</ins><span class="cx">     void xor64(RegisterID src, RegisterID dest)
</span><span class="cx">     {
</span><span class="cx">         m_assembler.xorq_rr(src, dest);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerX86Assemblerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/X86Assembler.h (193803 => 193804)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/X86Assembler.h        2015-12-09 02:01:25 UTC (rev 193803)
+++ trunk/Source/JavaScriptCore/assembler/X86Assembler.h        2015-12-09 02:30:39 UTC (rev 193804)
</span><span class="lines">@@ -464,6 +464,11 @@
</span><span class="cx">         m_formatter.oneByteOp64(OP_ADD_GvEv, dst, base, offset);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void addq_rm(RegisterID src, int offset, RegisterID base)
+    {
+        m_formatter.oneByteOp64(OP_ADD_EvGv, src, base, offset);
+    }
+
</ins><span class="cx">     void addq_ir(int imm, RegisterID dst)
</span><span class="cx">     {
</span><span class="cx">         if (CAN_SIGN_EXTEND_8_32(imm)) {
</span><span class="lines">@@ -758,6 +763,16 @@
</span><span class="cx">         m_formatter.oneByteOp64(OP_SUB_EvGv, src, dst);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    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);
+    }
+
</ins><span class="cx">     void subq_ir(int imm, RegisterID dst)
</span><span class="cx">     {
</span><span class="cx">         if (CAN_SIGN_EXTEND_8_32(imm)) {
</span><span class="lines">@@ -771,6 +786,17 @@
</span><span class="cx">             m_formatter.immediate32(imm);
</span><span class="cx">         }
</span><span class="cx">     }
</span><ins>+
+    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);
+        }
+    }
</ins><span class="cx"> #else
</span><span class="cx">     void subl_im(int imm, const void* addr)
</span><span class="cx">     {
</span><span class="lines">@@ -1773,11 +1799,22 @@
</span><span class="cx">     {
</span><span class="cx">         m_formatter.oneByteOp(OP_LEA, dst, base, offset);
</span><span class="cx">     }
</span><ins>+
+    void leal_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst)
+    {
+        m_formatter.oneByteOp(OP_LEA, dst, base, index, scale, offset);
+    }
+
</ins><span class="cx"> #if CPU(X86_64)
</span><span class="cx">     void leaq_mr(int offset, RegisterID base, RegisterID dst)
</span><span class="cx">     {
</span><span class="cx">         m_formatter.oneByteOp64(OP_LEA, dst, base, offset);
</span><span class="cx">     }
</span><ins>+
+    void leaq_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst)
+    {
+        m_formatter.oneByteOp64(OP_LEA, dst, base, index, scale, offset);
+    }
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx">     // Flow control:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3LowerToAircpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp (193803 => 193804)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2015-12-09 02:01:25 UTC (rev 193803)
+++ trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2015-12-09 02:30:39 UTC (rev 193804)
</span><span class="lines">@@ -621,23 +621,25 @@
</span><span class="cx"> 
</span><span class="cx">         // At this point, we prefer versions of the operation that have a fused load or an immediate
</span><span class="cx">         // over three operand forms.
</span><del>-        
-        if (commutativity == Commutative) {
-            ArgPromise leftAddr = loadPromise(left);
-            if (isValidForm(opcode, leftAddr.kind(), Arg::Tmp)) {
-                append(relaxedMoveForType(m_value-&gt;type()), tmp(right), result);
-                append(opcode, leftAddr.consume(*this), result);
</del><ins>+
+        if (left != right) {
+            if (commutativity == Commutative) {
+                ArgPromise leftAddr = loadPromise(left);
+                if (isValidForm(opcode, leftAddr.kind(), Arg::Tmp)) {
+                    append(relaxedMoveForType(m_value-&gt;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-&gt;type()), tmp(left), result);
+                append(opcode, rightAddr.consume(*this), result);
</ins><span class="cx">                 return;
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        ArgPromise rightAddr = loadPromise(right);
-        if (isValidForm(opcode, rightAddr.kind(), Arg::Tmp)) {
-            append(relaxedMoveForType(m_value-&gt;type()), tmp(left), result);
-            append(opcode, rightAddr.consume(*this), result);
-            return;
-        }
-
</del><span class="cx">         if (imm(right) &amp;&amp; isValidForm(opcode, Arg::Imm, Arg::Tmp)) {
</span><span class="cx">             append(relaxedMoveForType(m_value-&gt;type()), tmp(left), result);
</span><span class="cx">             append(opcode, imm(right), result);
</span><span class="lines">@@ -1494,11 +1496,7 @@
</span><span class="cx"> 
</span><span class="cx">         case Shl: {
</span><span class="cx">             if (m_value-&gt;child(1)-&gt;isInt32(1)) {
</span><del>-                // This optimization makes sense on X86. I don't know if it makes sense anywhere else.
-                append(Move, tmp(m_value-&gt;child(0)), tmp(m_value));
-                append(
-                    opcodeForType(Add32, Add64, m_value-&gt;child(0)-&gt;type()),
-                    tmp(m_value), tmp(m_value));
</del><ins>+                appendBinOp&lt;Add32, Add64, AddDouble, AddFloat, Commutative&gt;(m_value-&gt;child(0), m_value-&gt;child(0));
</ins><span class="cx">                 return;
</span><span class="cx">             }
</span><span class="cx">             
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirOpcodeopcodes"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes (193803 => 193804)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes        2015-12-09 02:01:25 UTC (rev 193803)
+++ trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes        2015-12-09 02:30:39 UTC (rev 193804)
</span><span class="lines">@@ -68,15 +68,18 @@
</span><span class="cx"> 
</span><span class="cx"> Add32 U:G, U:G, D:G
</span><span class="cx">     Imm, Tmp, Tmp
</span><ins>+    Tmp, Tmp, Tmp
</ins><span class="cx"> 
</span><span class="cx"> Add64 U:G, UD:G
</span><span class="cx">     Tmp, Tmp
</span><span class="cx">     Imm, Addr
</span><span class="cx">     Imm, Tmp
</span><span class="cx">     Addr, Tmp
</span><ins>+    Tmp, Addr
</ins><span class="cx"> 
</span><span class="cx"> Add64 U:G, U:G, D:G
</span><span class="cx">     Imm, Tmp, Tmp
</span><ins>+    Tmp, Tmp, Tmp
</ins><span class="cx"> 
</span><span class="cx"> AddDouble U:F, UD:F
</span><span class="cx">     Tmp, Tmp
</span><span class="lines">@@ -95,7 +98,10 @@
</span><span class="cx"> 
</span><span class="cx"> Sub64 U:G, UD:G
</span><span class="cx">     Tmp, Tmp
</span><ins>+    Imm, Addr
</ins><span class="cx">     Imm, Tmp
</span><ins>+    Addr, Tmp
+    Tmp, Addr
</ins><span class="cx"> 
</span><span class="cx"> SubDouble U:F, UD:F
</span><span class="cx">     Tmp, Tmp
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3testb3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/testb3.cpp (193803 => 193804)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/testb3.cpp        2015-12-09 02:01:25 UTC (rev 193803)
+++ trunk/Source/JavaScriptCore/b3/testb3.cpp        2015-12-09 02:30:39 UTC (rev 193804)
</span><span class="lines">@@ -203,6 +203,67 @@
</span><span class="cx">     CHECK(compileAndRun&lt;int&gt;(proc, b) == a + b);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void testAddArgMem(int64_t a, int64_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1);
+    MemoryValue* load = root-&gt;appendNew&lt;MemoryValue&gt;(proc, Load, Int64, Origin(), address);
+    Value* result = root-&gt;appendNew&lt;Value&gt;(proc, Add, Origin(),
+        root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0),
+        load);
+    root-&gt;appendNew&lt;MemoryValue&gt;(proc, Store, Origin(), result, address);
+    root-&gt;appendNew&lt;ControlValue&gt;(proc, Return, Origin(), root-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), 0));
+
+    int64_t inputOutput = b;
+    CHECK(!compileAndRun&lt;int64_t&gt;(proc, a, &amp;inputOutput));
+    CHECK(inputOutput == a + b);
+}
+
+void testAddMemArg(int64_t a, int64_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root-&gt;appendNew&lt;MemoryValue&gt;(proc, Load, Int64, Origin(), address);
+    Value* result = root-&gt;appendNew&lt;Value&gt;(proc, Add, Origin(),
+        load,
+        root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1));
+    root-&gt;appendNew&lt;ControlValue&gt;(proc, Return, Origin(), result);
+
+    CHECK(compileAndRun&lt;int64_t&gt;(proc, &amp;a, b) == a + b);
+}
+
+void testAddImmMem(int64_t a, int64_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root-&gt;appendNew&lt;MemoryValue&gt;(proc, Load, Int64, Origin(), address);
+    Value* result = root-&gt;appendNew&lt;Value&gt;(proc, Add, Origin(),
+        root-&gt;appendNew&lt;Const64Value&gt;(proc, Origin(), a),
+        load);
+    root-&gt;appendNew&lt;MemoryValue&gt;(proc, Store, Origin(), result, address);
+    root-&gt;appendNew&lt;ControlValue&gt;(proc, Return, Origin(), root-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), 0));
+
+    int64_t inputOutput = b;
+    CHECK(!compileAndRun&lt;int&gt;(proc, &amp;inputOutput));
+    CHECK(inputOutput == a + b);
+}
+
+void testAddArg32(int a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* value = root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(),
+        root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0));
+    root-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(proc, Add, Origin(), value, value));
+
+    CHECK(compileAndRun&lt;int&gt;(proc, a) == a + a);
+}
+
</ins><span class="cx"> void testAddArgs32(int a, int b)
</span><span class="cx"> {
</span><span class="cx">     Procedure proc;
</span><span class="lines">@@ -221,6 +282,54 @@
</span><span class="cx">     CHECK(compileAndRun&lt;int&gt;(proc, a, b) == a + b);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void testAddArgMem32(int32_t a, int32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1);
+    MemoryValue* load = root-&gt;appendNew&lt;MemoryValue&gt;(proc, Load, Int32, Origin(), address);
+    Value* argument = root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(),
+        root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* result = root-&gt;appendNew&lt;Value&gt;(proc, Add, Origin(), argument, load);
+    root-&gt;appendNew&lt;MemoryValue&gt;(proc, Store, Origin(), result, address);
+    root-&gt;appendNew&lt;ControlValue&gt;(proc, Return, Origin(), root-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), 0));
+
+    int32_t inputOutput = b;
+    CHECK(!compileAndRun&lt;int32_t&gt;(proc, a, &amp;inputOutput));
+    CHECK(inputOutput == a + b);
+}
+
+void testAddMemArg32(int32_t a, int32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root-&gt;appendNew&lt;MemoryValue&gt;(proc, Load, Int32, Origin(), address);
+    Value* argument = root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(),
+        root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1));
+    Value* result = root-&gt;appendNew&lt;Value&gt;(proc, Add, Origin(), load, argument);
+    root-&gt;appendNew&lt;ControlValue&gt;(proc, Return, Origin(), result);
+
+    CHECK(compileAndRun&lt;int32_t&gt;(proc, &amp;a, b) == a + b);
+}
+
+void testAddImmMem32(int32_t a, int32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root-&gt;appendNew&lt;MemoryValue&gt;(proc, Load, Int32, Origin(), address);
+    Value* result = root-&gt;appendNew&lt;Value&gt;(proc, Add, Origin(),
+        root-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), a),
+        load);
+    root-&gt;appendNew&lt;MemoryValue&gt;(proc, Store, Origin(), result, address);
+    root-&gt;appendNew&lt;ControlValue&gt;(proc, Return, Origin(), root-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), 0));
+
+    int32_t inputOutput = b;
+    CHECK(!compileAndRun&lt;int&gt;(proc, &amp;inputOutput));
+    CHECK(inputOutput == a + b);
+}
+
</ins><span class="cx"> void testAddLoadTwice()
</span><span class="cx"> {
</span><span class="cx">     auto test = [&amp;] (unsigned optLevel) {
</span><span class="lines">@@ -1047,6 +1156,72 @@
</span><span class="cx">     CHECK(compileAndRun&lt;int&gt;(proc, b) == a - b);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void testSubArgMem(int64_t a, int64_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1);
+    MemoryValue* load = root-&gt;appendNew&lt;MemoryValue&gt;(proc, Load, Int64, Origin(), address);
+    Value* result = root-&gt;appendNew&lt;Value&gt;(proc, Sub, Origin(),
+        root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0),
+        load);
+    root-&gt;appendNew&lt;ControlValue&gt;(proc, Return, Origin(), result);
+
+    CHECK(compileAndRun&lt;int64_t&gt;(proc, a, &amp;b) == a - b);
+}
+
+void testSubMemArg(int64_t a, int64_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root-&gt;appendNew&lt;MemoryValue&gt;(proc, Load, Int64, Origin(), address);
+    Value* result = root-&gt;appendNew&lt;Value&gt;(proc, Sub, Origin(),
+        load,
+        root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1));
+    root-&gt;appendNew&lt;MemoryValue&gt;(proc, Store, Origin(), result, address);
+    root-&gt;appendNew&lt;ControlValue&gt;(proc, Return, Origin(), root-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), 0));
+
+    int64_t inputOutput = a;
+    CHECK(!compileAndRun&lt;int64_t&gt;(proc, &amp;inputOutput, b));
+    CHECK(inputOutput == a - b);
+}
+
+void testSubImmMem(int64_t a, int64_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root-&gt;appendNew&lt;MemoryValue&gt;(proc, Load, Int64, Origin(), address);
+    Value* result = root-&gt;appendNew&lt;Value&gt;(proc, Sub, Origin(),
+        root-&gt;appendNew&lt;Const64Value&gt;(proc, Origin(), a),
+        load);
+    root-&gt;appendNew&lt;MemoryValue&gt;(proc, Store, Origin(), result, address);
+    root-&gt;appendNew&lt;ControlValue&gt;(proc, Return, Origin(), root-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), 0));
+
+    int64_t inputOutput = b;
+    CHECK(!compileAndRun&lt;int&gt;(proc, &amp;inputOutput));
+    CHECK(inputOutput == a - b);
+}
+
+void testSubMemImm(int64_t a, int64_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root-&gt;appendNew&lt;MemoryValue&gt;(proc, Load, Int64, Origin(), address);
+    Value* result = root-&gt;appendNew&lt;Value&gt;(proc, Sub, Origin(),
+        load,
+        root-&gt;appendNew&lt;Const64Value&gt;(proc, Origin(), b));
+    root-&gt;appendNew&lt;MemoryValue&gt;(proc, Store, Origin(), result, address);
+    root-&gt;appendNew&lt;ControlValue&gt;(proc, Return, Origin(), root-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), 0));
+
+    int64_t inputOutput = a;
+    CHECK(!compileAndRun&lt;int&gt;(proc, &amp;inputOutput));
+    CHECK(inputOutput == a - b);
+}
+
+
</ins><span class="cx"> void testSubArgs32(int a, int b)
</span><span class="cx"> {
</span><span class="cx">     Procedure proc;
</span><span class="lines">@@ -1097,6 +1272,71 @@
</span><span class="cx">     CHECK(compileAndRun&lt;int&gt;(proc, b) == a - b);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void testSubMemArg32(int32_t a, int32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root-&gt;appendNew&lt;MemoryValue&gt;(proc, Load, Int32, Origin(), address);
+    Value* argument = root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(),
+        root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1));
+    Value* result = root-&gt;appendNew&lt;Value&gt;(proc, Sub, Origin(), load, argument);
+    root-&gt;appendNew&lt;MemoryValue&gt;(proc, Store, Origin(), result, address);
+    root-&gt;appendNew&lt;ControlValue&gt;(proc, Return, Origin(), root-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), 0));
+
+    int32_t inputOutput = a;
+    CHECK(!compileAndRun&lt;int32_t&gt;(proc, &amp;inputOutput, b));
+    CHECK(inputOutput == a - b);
+}
+
+void testSubArgMem32(int32_t a, int32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1);
+    MemoryValue* load = root-&gt;appendNew&lt;MemoryValue&gt;(proc, Load, Int32, Origin(), address);
+    Value* argument = root-&gt;appendNew&lt;Value&gt;(proc, Trunc, Origin(),
+        root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* result = root-&gt;appendNew&lt;Value&gt;(proc, Sub, Origin(), argument, load);
+    root-&gt;appendNew&lt;ControlValue&gt;(proc, Return, Origin(), result);
+
+    CHECK(compileAndRun&lt;int32_t&gt;(proc, a, &amp;b) == a - b);
+}
+
+void testSubImmMem32(int32_t a, int32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root-&gt;appendNew&lt;MemoryValue&gt;(proc, Load, Int32, Origin(), address);
+    Value* result = root-&gt;appendNew&lt;Value&gt;(proc, Sub, Origin(),
+        root-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), a),
+        load);
+    root-&gt;appendNew&lt;MemoryValue&gt;(proc, Store, Origin(), result, address);
+    root-&gt;appendNew&lt;ControlValue&gt;(proc, Return, Origin(), root-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), 0));
+
+    int32_t inputOutput = b;
+    CHECK(!compileAndRun&lt;int&gt;(proc, &amp;inputOutput));
+    CHECK(inputOutput == a - b);
+}
+
+void testSubMemImm32(int32_t a, int32_t b)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* address = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0);
+    MemoryValue* load = root-&gt;appendNew&lt;MemoryValue&gt;(proc, Load, Int32, Origin(), address);
+    Value* result = root-&gt;appendNew&lt;Value&gt;(proc, Sub, Origin(),
+        load,
+        root-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), b));
+    root-&gt;appendNew&lt;MemoryValue&gt;(proc, Store, Origin(), result, address);
+    root-&gt;appendNew&lt;ControlValue&gt;(proc, Return, Origin(), root-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), 0));
+
+    int32_t inputOutput = a;
+    CHECK(!compileAndRun&lt;int&gt;(proc, &amp;inputOutput));
+    CHECK(inputOutput == a - b);
+}
+
</ins><span class="cx"> void testNegValueSubOne32(int a)
</span><span class="cx"> {
</span><span class="cx">     Procedure proc;
</span><span class="lines">@@ -6690,8 +6930,15 @@
</span><span class="cx">     RUN(testAddImmArg(1, 2));
</span><span class="cx">     RUN(testAddImmArg(0, 2));
</span><span class="cx">     RUN(testAddImmArg(1, 0));
</span><ins>+    RUN_BINARY(testAddArgMem, int64Operands(), int64Operands());
+    RUN_BINARY(testAddMemArg, int64Operands(), int64Operands());
+    RUN_BINARY(testAddImmMem, int64Operands(), int64Operands());
+    RUN_UNARY(testAddArg32, int32Operands());
</ins><span class="cx">     RUN(testAddArgs32(1, 1));
</span><span class="cx">     RUN(testAddArgs32(1, 2));
</span><ins>+    RUN_BINARY(testAddArgMem32, int32Operands(), int32Operands());
+    RUN_BINARY(testAddMemArg32, int32Operands(), int32Operands());
+    RUN_BINARY(testAddImmMem32, int32Operands(), int32Operands());
</ins><span class="cx">     RUN(testAddLoadTwice());
</span><span class="cx"> 
</span><span class="cx">     RUN(testAddArgDouble(M_PI));
</span><span class="lines">@@ -6826,6 +7073,10 @@
</span><span class="cx">     RUN(testSubImmArg(1, 2));
</span><span class="cx">     RUN(testSubImmArg(13, -42));
</span><span class="cx">     RUN(testSubImmArg(-13, 42));
</span><ins>+    RUN_BINARY(testSubArgMem, int64Operands(), int64Operands());
+    RUN_BINARY(testSubMemArg, int64Operands(), int64Operands());
+    RUN_BINARY(testSubImmMem, int32Operands(), int32Operands());
+    RUN_BINARY(testSubMemImm, int32Operands(), int32Operands());
</ins><span class="cx">     RUN_UNARY(testNegValueSubOne, int32Operands());
</span><span class="cx"> 
</span><span class="cx">     RUN(testSubArgs32(1, 1));
</span><span class="lines">@@ -6840,6 +7091,10 @@
</span><span class="cx">     RUN(testSubImmArg32(1, 2));
</span><span class="cx">     RUN(testSubImmArg32(13, -42));
</span><span class="cx">     RUN(testSubImmArg32(-13, 42));
</span><ins>+    RUN_BINARY(testSubArgMem32, int32Operands(), int32Operands());
+    RUN_BINARY(testSubMemArg32, int32Operands(), int32Operands());
+    RUN_BINARY(testSubImmMem32, int32Operands(), int32Operands());
+    RUN_BINARY(testSubMemImm32, int32Operands(), int32Operands());
</ins><span class="cx">     RUN_UNARY(testNegValueSubOne32, int64Operands());
</span><span class="cx"> 
</span><span class="cx">     RUN_UNARY(testSubArgDouble, floatingPointOperands&lt;double&gt;());
</span></span></pre>
</div>
</div>

</body>
</html>