<!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>[203996] 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/203996">203996</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2016-08-01 16:22:15 -0700 (Mon, 01 Aug 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>[B3] Fusing immediates into test instructions should work again
https://bugs.webkit.org/show_bug.cgi?id=160073

Reviewed by Sam Weinig.

When we introduced BitImm, we forgot to change the Branch(BitAnd(value, constant))
fusion.  This emits test instructions, so it should use BitImm for the constant.  But it
was still using Imm!  This meant that isValidForm() always returned false.
        
This fixes the code path to use BitImm, and turns off our use of BitImm64 on x86 since
it provides no benefit on x86 and has some risk (the code appears to play fast and loose
with the scratch register).
        
This is not an obvious progression on anything, so I added comprehensive tests to
testb3, which check that we selected the optimal instruction in a variety of situations.
We should add more tests like this!

Rolling this back in after fixing ARM64. The bug was that branchTest32|64 on ARM64 doesn't
actually support BitImm or BitImm64, at least not yet. Disabling that in AirOpcodes makes
this patch not a regression on ARM64. That change was reviewed by Benjamin Poulain.

* b3/B3BasicBlock.h:
(JSC::B3::BasicBlock::successorBlock):
* b3/B3LowerToAir.cpp:
(JSC::B3::Air::LowerToAir::createGenericCompare):
* b3/B3LowerToAir.h:
* b3/air/AirArg.cpp:
(JSC::B3::Air::Arg::isRepresentableAs):
(JSC::B3::Air::Arg::usesTmp):
* b3/air/AirArg.h:
(JSC::B3::Air::Arg::isRepresentableAs):
(JSC::B3::Air::Arg::castToType):
(JSC::B3::Air::Arg::asNumber):
* b3/air/AirCode.h:
(JSC::B3::Air::Code::size):
(JSC::B3::Air::Code::at):
* b3/air/AirOpcode.opcodes:
* b3/air/AirValidate.h:
* b3/air/opcode_generator.rb:
* b3/testb3.cpp:
(JSC::B3::compile):
(JSC::B3::compileAndRun):
(JSC::B3::lowerToAirForTesting):
(JSC::B3::testSomeEarlyRegister):
(JSC::B3::testBranchBitAndImmFusion):
(JSC::B3::zero):
(JSC::B3::run):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3LowerToAircpp">trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3LowerToAirh">trunk/Source/JavaScriptCore/b3/B3LowerToAir.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirArgcpp">trunk/Source/JavaScriptCore/b3/air/AirArg.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirArgh">trunk/Source/JavaScriptCore/b3/air/AirArg.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirCodeh">trunk/Source/JavaScriptCore/b3/air/AirCode.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirOpcodeopcodes">trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirValidateh">trunk/Source/JavaScriptCore/b3/air/AirValidate.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airopcode_generatorrb">trunk/Source/JavaScriptCore/b3/air/opcode_generator.rb</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 (203995 => 203996)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-08-01 23:21:48 UTC (rev 203995)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-08-01 23:22:15 UTC (rev 203996)
</span><span class="lines">@@ -1,3 +1,53 @@
</span><ins>+2016-07-22  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        [B3] Fusing immediates into test instructions should work again
+        https://bugs.webkit.org/show_bug.cgi?id=160073
+
+        Reviewed by Sam Weinig.
+
+        When we introduced BitImm, we forgot to change the Branch(BitAnd(value, constant))
+        fusion.  This emits test instructions, so it should use BitImm for the constant.  But it
+        was still using Imm!  This meant that isValidForm() always returned false.
+        
+        This fixes the code path to use BitImm, and turns off our use of BitImm64 on x86 since
+        it provides no benefit on x86 and has some risk (the code appears to play fast and loose
+        with the scratch register).
+        
+        This is not an obvious progression on anything, so I added comprehensive tests to
+        testb3, which check that we selected the optimal instruction in a variety of situations.
+        We should add more tests like this!
+
+        Rolling this back in after fixing ARM64. The bug was that branchTest32|64 on ARM64 doesn't
+        actually support BitImm or BitImm64, at least not yet. Disabling that in AirOpcodes makes
+        this patch not a regression on ARM64. That change was reviewed by Benjamin Poulain.
+
+        * b3/B3BasicBlock.h:
+        (JSC::B3::BasicBlock::successorBlock):
+        * b3/B3LowerToAir.cpp:
+        (JSC::B3::Air::LowerToAir::createGenericCompare):
+        * b3/B3LowerToAir.h:
+        * b3/air/AirArg.cpp:
+        (JSC::B3::Air::Arg::isRepresentableAs):
+        (JSC::B3::Air::Arg::usesTmp):
+        * b3/air/AirArg.h:
+        (JSC::B3::Air::Arg::isRepresentableAs):
+        (JSC::B3::Air::Arg::castToType):
+        (JSC::B3::Air::Arg::asNumber):
+        * b3/air/AirCode.h:
+        (JSC::B3::Air::Code::size):
+        (JSC::B3::Air::Code::at):
+        * b3/air/AirOpcode.opcodes:
+        * b3/air/AirValidate.h:
+        * b3/air/opcode_generator.rb:
+        * b3/testb3.cpp:
+        (JSC::B3::compile):
+        (JSC::B3::compileAndRun):
+        (JSC::B3::lowerToAirForTesting):
+        (JSC::B3::testSomeEarlyRegister):
+        (JSC::B3::testBranchBitAndImmFusion):
+        (JSC::B3::zero):
+        (JSC::B3::run):
+
</ins><span class="cx"> 2016-08-01  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Rationalize varargs stack overflow checks
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3LowerToAircpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp (203995 => 203996)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2016-08-01 23:21:48 UTC (rev 203995)
+++ trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2016-08-01 23:22:15 UTC (rev 203996)
</span><span class="lines">@@ -1330,22 +1330,43 @@
</span><span class="cx">                 Value* left = value-&gt;child(0);
</span><span class="cx">                 Value* right = value-&gt;child(1);
</span><span class="cx"> 
</span><del>-                // FIXME: We don't actually have to worry about leftImm.
-                // https://bugs.webkit.org/show_bug.cgi?id=150954
</del><ins>+                bool hasRightConst;
+                int64_t rightConst;
+                Arg rightImm;
+                Arg rightImm64;
</ins><span class="cx"> 
</span><del>-                Arg leftImm = imm(left);
-                Arg rightImm = imm(right);
</del><ins>+                hasRightConst = right-&gt;hasInt();
+                if (hasRightConst) {
+                    rightConst = right-&gt;asInt();
+                    rightImm = bitImm(right);
+                    rightImm64 = bitImm64(right);
+                }
</ins><span class="cx">                 
</span><del>-                auto tryTestLoadImm = [&amp;] (Arg::Width width, B3::Opcode loadOpcode) -&gt; Inst {
-                    if (rightImm &amp;&amp; rightImm.isRepresentableAs(width, Arg::Unsigned)) {
</del><ins>+                auto tryTestLoadImm = [&amp;] (Arg::Width width, Arg::Signedness signedness, B3::Opcode loadOpcode) -&gt; Inst {
+                    if (!hasRightConst)
+                        return Inst();
+                    // Signed loads will create high bits, so if the immediate has high bits
+                    // then we cannot proceed. Consider BitAnd(Load8S(ptr), 0x101). This cannot
+                    // be turned into testb (ptr), $1, since if the high bit within that byte
+                    // was set then it would be extended to include 0x100. The handling below
+                    // won't anticipate this, so we need to catch it here.
+                    if (signedness == Arg::Signed
+                        &amp;&amp; !Arg::isRepresentableAs(width, Arg::Unsigned, rightConst))
+                        return Inst();
+                    
+                    // FIXME: If this is unsigned then we can chop things off of the immediate.
+                    // This might make the immediate more legal. Perhaps that's a job for
+                    // strength reduction?
+                    
+                    if (rightImm) {
</ins><span class="cx">                         if (Inst result = tryTest(width, loadPromise(left, loadOpcode), rightImm)) {
</span><span class="cx">                             commitInternal(left);
</span><span class="cx">                             return result;
</span><span class="cx">                         }
</span><span class="cx">                     }
</span><del>-                    if (leftImm &amp;&amp; leftImm.isRepresentableAs(width, Arg::Unsigned)) {
-                        if (Inst result = tryTest(width, leftImm, loadPromise(right, loadOpcode))) {
-                            commitInternal(right);
</del><ins>+                    if (rightImm64) {
+                        if (Inst result = tryTest(width, loadPromise(left, loadOpcode), rightImm64)) {
+                            commitInternal(left);
</ins><span class="cx">                             return result;
</span><span class="cx">                         }
</span><span class="cx">                     }
</span><span class="lines">@@ -1355,24 +1376,28 @@
</span><span class="cx">                 if (canCommitInternal) {
</span><span class="cx">                     // First handle test's that involve fewer bits than B3's type system supports.
</span><span class="cx"> 
</span><del>-                    if (Inst result = tryTestLoadImm(Arg::Width8, Load8Z))
</del><ins>+                    if (Inst result = tryTestLoadImm(Arg::Width8, Arg::Unsigned, Load8Z))
</ins><span class="cx">                         return result;
</span><span class="cx">                     
</span><del>-                    if (Inst result = tryTestLoadImm(Arg::Width8, Load8S))
</del><ins>+                    if (Inst result = tryTestLoadImm(Arg::Width8, Arg::Signed, Load8S))
</ins><span class="cx">                         return result;
</span><span class="cx">                     
</span><del>-                    if (Inst result = tryTestLoadImm(Arg::Width16, Load16Z))
</del><ins>+                    if (Inst result = tryTestLoadImm(Arg::Width16, Arg::Unsigned, Load16Z))
</ins><span class="cx">                         return result;
</span><span class="cx">                     
</span><del>-                    if (Inst result = tryTestLoadImm(Arg::Width16, Load16S))
</del><ins>+                    if (Inst result = tryTestLoadImm(Arg::Width16, Arg::Signed, Load16S))
</ins><span class="cx">                         return result;
</span><span class="cx"> 
</span><del>-                    // Now handle test's that involve a load and an immediate. Note that immediates
-                    // are 32-bit, and we want zero-extension. Hence, the immediate form is compiled
-                    // as a 32-bit test. Note that this spits on the grave of inferior endians, such
-                    // as the big one.
</del><ins>+                    // This allows us to use a 32-bit test for 64-bit BitAnd if the immediate is
+                    // representable as an unsigned 32-bit value. The logic involved is the same
+                    // as if we were pondering using a 32-bit test for
+                    // BitAnd(SExt(Load(ptr)), const), in the sense that in both cases we have
+                    // to worry about high bits. So, we use the &quot;Signed&quot; version of this helper.
+                    if (Inst result = tryTestLoadImm(Arg::Width32, Arg::Signed, Load))
+                        return result;
</ins><span class="cx">                     
</span><del>-                    if (Inst result = tryTestLoadImm(Arg::Width32, Load))
</del><ins>+                    // This is needed to handle 32-bit test for arbitrary 32-bit immediates.
+                    if (Inst result = tryTestLoadImm(width, Arg::Unsigned, Load))
</ins><span class="cx">                         return result;
</span><span class="cx">                     
</span><span class="cx">                     // Now handle test's that involve a load.
</span><span class="lines">@@ -1391,30 +1416,23 @@
</span><span class="cx"> 
</span><span class="cx">                 // Now handle test's that involve an immediate and a tmp.
</span><span class="cx"> 
</span><del>-                if (leftImm) {
-                    if ((width == Arg::Width32 &amp;&amp; leftImm.value() == 0xffffffff)
-                        || (width == Arg::Width64 &amp;&amp; leftImm.value() == -1)) {
-                        ArgPromise argPromise = tmpPromise(right);
-                        if (Inst result = tryTest(width, argPromise, argPromise))
-                            return result;
-                    }
-                    if (leftImm.isRepresentableAs&lt;uint32_t&gt;()) {
-                        if (Inst result = tryTest(Arg::Width32, leftImm, tmpPromise(right)))
-                            return result;
-                    }
-                }
-
-                if (rightImm) {
-                    if ((width == Arg::Width32 &amp;&amp; rightImm.value() == 0xffffffff)
-                        || (width == Arg::Width64 &amp;&amp; rightImm.value() == -1)) {
</del><ins>+                if (hasRightConst) {
+                    if ((width == Arg::Width32 &amp;&amp; rightConst == 0xffffffff)
+                        || (width == Arg::Width64 &amp;&amp; rightConst == -1)) {
</ins><span class="cx">                         ArgPromise argPromise = tmpPromise(left);
</span><span class="cx">                         if (Inst result = tryTest(width, argPromise, argPromise))
</span><span class="cx">                             return result;
</span><span class="cx">                     }
</span><del>-                    if (rightImm.isRepresentableAs&lt;uint32_t&gt;()) {
</del><ins>+                    if (isRepresentableAs&lt;uint32_t&gt;(rightConst)) {
</ins><span class="cx">                         if (Inst result = tryTest(Arg::Width32, tmpPromise(left), rightImm))
</span><span class="cx">                             return result;
</span><ins>+                        if (Inst result = tryTest(Arg::Width32, tmpPromise(left), rightImm64))
+                            return result;
</ins><span class="cx">                     }
</span><ins>+                    if (Inst result = tryTest(width, tmpPromise(left), rightImm))
+                        return result;
+                    if (Inst result = tryTest(width, tmpPromise(left), rightImm64))
+                        return result;
</ins><span class="cx">                 }
</span><span class="cx"> 
</span><span class="cx">                 // Finally, just do tmp's.
</span><span class="lines">@@ -1432,37 +1450,37 @@
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (Arg::isValidImmForm(-1)) {
</del><ins>+        if (Arg::isValidBitImmForm(-1)) {
</ins><span class="cx">             if (canCommitInternal &amp;&amp; value-&gt;as&lt;MemoryValue&gt;()) {
</span><span class="cx">                 // Handle things like Branch(Load8Z(value))
</span><span class="cx"> 
</span><del>-                if (Inst result = tryTest(Arg::Width8, loadPromise(value, Load8Z), Arg::imm(-1))) {
</del><ins>+                if (Inst result = tryTest(Arg::Width8, loadPromise(value, Load8Z), Arg::bitImm(-1))) {
</ins><span class="cx">                     commitInternal(value);
</span><span class="cx">                     return result;
</span><span class="cx">                 }
</span><span class="cx"> 
</span><del>-                if (Inst result = tryTest(Arg::Width8, loadPromise(value, Load8S), Arg::imm(-1))) {
</del><ins>+                if (Inst result = tryTest(Arg::Width8, loadPromise(value, Load8S), Arg::bitImm(-1))) {
</ins><span class="cx">                     commitInternal(value);
</span><span class="cx">                     return result;
</span><span class="cx">                 }
</span><span class="cx"> 
</span><del>-                if (Inst result = tryTest(Arg::Width16, loadPromise(value, Load16Z), Arg::imm(-1))) {
</del><ins>+                if (Inst result = tryTest(Arg::Width16, loadPromise(value, Load16Z), Arg::bitImm(-1))) {
</ins><span class="cx">                     commitInternal(value);
</span><span class="cx">                     return result;
</span><span class="cx">                 }
</span><span class="cx"> 
</span><del>-                if (Inst result = tryTest(Arg::Width16, loadPromise(value, Load16S), Arg::imm(-1))) {
</del><ins>+                if (Inst result = tryTest(Arg::Width16, loadPromise(value, Load16S), Arg::bitImm(-1))) {
</ins><span class="cx">                     commitInternal(value);
</span><span class="cx">                     return result;
</span><span class="cx">                 }
</span><span class="cx"> 
</span><del>-                if (Inst result = tryTest(width, loadPromise(value), Arg::imm(-1))) {
</del><ins>+                if (Inst result = tryTest(width, loadPromise(value), Arg::bitImm(-1))) {
</ins><span class="cx">                     commitInternal(value);
</span><span class="cx">                     return result;
</span><span class="cx">                 }
</span><span class="cx">             }
</span><span class="cx"> 
</span><del>-            if (Inst result = test(width, resCond, tmpPromise(value), Arg::imm(-1)))
</del><ins>+            if (Inst result = test(width, resCond, tmpPromise(value), Arg::bitImm(-1)))
</ins><span class="cx">                 return result;
</span><span class="cx">         }
</span><span class="cx">         
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3LowerToAirh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3LowerToAir.h (203995 => 203996)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3LowerToAir.h        2016-08-01 23:21:48 UTC (rev 203995)
+++ trunk/Source/JavaScriptCore/b3/B3LowerToAir.h        2016-08-01 23:22:15 UTC (rev 203996)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2015 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -35,7 +35,7 @@
</span><span class="cx"> 
</span><span class="cx"> // This lowers the current B3 procedure to an Air code.
</span><span class="cx"> 
</span><del>-void lowerToAir(Procedure&amp;);
</del><ins>+JS_EXPORT_PRIVATE void lowerToAir(Procedure&amp;);
</ins><span class="cx"> 
</span><span class="cx"> } } // namespace JSC::B3
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirArgcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirArg.cpp (203995 => 203996)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirArg.cpp        2016-08-01 23:21:48 UTC (rev 203995)
+++ trunk/Source/JavaScriptCore/b3/air/AirArg.cpp        2016-08-01 23:22:15 UTC (rev 203996)
</span><span class="lines">@@ -57,31 +57,7 @@
</span><span class="cx"> 
</span><span class="cx"> bool Arg::isRepresentableAs(Width width, Signedness signedness) const
</span><span class="cx"> {
</span><del>-    switch (signedness) {
-    case Signed:
-        switch (width) {
-        case Width8:
-            return isRepresentableAs&lt;int8_t&gt;();
-        case Width16:
-            return isRepresentableAs&lt;int16_t&gt;();
-        case Width32:
-            return isRepresentableAs&lt;int32_t&gt;();
-        case Width64:
-            return isRepresentableAs&lt;int64_t&gt;();
-        }
-    case Unsigned:
-        switch (width) {
-        case Width8:
-            return isRepresentableAs&lt;uint8_t&gt;();
-        case Width16:
-            return isRepresentableAs&lt;uint16_t&gt;();
-        case Width32:
-            return isRepresentableAs&lt;uint32_t&gt;();
-        case Width64:
-            return isRepresentableAs&lt;uint64_t&gt;();
-        }
-    }
-    ASSERT_NOT_REACHED();
</del><ins>+    return isRepresentableAs(width, signedness, value());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool Arg::usesTmp(Air::Tmp tmp) const
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirArgh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirArg.h (203995 => 203996)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirArg.h        2016-08-01 23:21:48 UTC (rev 203995)
+++ trunk/Source/JavaScriptCore/b3/air/AirArg.h        2016-08-01 23:22:15 UTC (rev 203996)
</span><span class="lines">@@ -793,8 +793,66 @@
</span><span class="cx">     {
</span><span class="cx">         return B3::isRepresentableAs&lt;T&gt;(value());
</span><span class="cx">     }
</span><ins>+    
+    static bool isRepresentableAs(Width width, Signedness signedness, int64_t value)
+    {
+        switch (signedness) {
+        case Signed:
+            switch (width) {
+            case Width8:
+                return B3::isRepresentableAs&lt;int8_t&gt;(value);
+            case Width16:
+                return B3::isRepresentableAs&lt;int16_t&gt;(value);
+            case Width32:
+                return B3::isRepresentableAs&lt;int32_t&gt;(value);
+            case Width64:
+                return B3::isRepresentableAs&lt;int64_t&gt;(value);
+            }
+        case Unsigned:
+            switch (width) {
+            case Width8:
+                return B3::isRepresentableAs&lt;uint8_t&gt;(value);
+            case Width16:
+                return B3::isRepresentableAs&lt;uint16_t&gt;(value);
+            case Width32:
+                return B3::isRepresentableAs&lt;uint32_t&gt;(value);
+            case Width64:
+                return B3::isRepresentableAs&lt;uint64_t&gt;(value);
+            }
+        }
+        ASSERT_NOT_REACHED();
+    }
</ins><span class="cx"> 
</span><span class="cx">     bool isRepresentableAs(Width, Signedness) const;
</span><ins>+    
+    static int64_t castToType(Width width, Signedness signedness, int64_t value)
+    {
+        switch (signedness) {
+        case Signed:
+            switch (width) {
+            case Width8:
+                return static_cast&lt;int8_t&gt;(value);
+            case Width16:
+                return static_cast&lt;int16_t&gt;(value);
+            case Width32:
+                return static_cast&lt;int32_t&gt;(value);
+            case Width64:
+                return static_cast&lt;int64_t&gt;(value);
+            }
+        case Unsigned:
+            switch (width) {
+            case Width8:
+                return static_cast&lt;uint8_t&gt;(value);
+            case Width16:
+                return static_cast&lt;uint16_t&gt;(value);
+            case Width32:
+                return static_cast&lt;uint32_t&gt;(value);
+            case Width64:
+                return static_cast&lt;uint64_t&gt;(value);
+            }
+        }
+        ASSERT_NOT_REACHED();
+    }
</ins><span class="cx"> 
</span><span class="cx">     template&lt;typename T&gt;
</span><span class="cx">     T asNumber() const
</span><span class="lines">@@ -1300,11 +1358,11 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WTF {
</span><span class="cx"> 
</span><del>-void printInternal(PrintStream&amp;, JSC::B3::Air::Arg::Kind);
-void printInternal(PrintStream&amp;, JSC::B3::Air::Arg::Role);
-void printInternal(PrintStream&amp;, JSC::B3::Air::Arg::Type);
-void printInternal(PrintStream&amp;, JSC::B3::Air::Arg::Width);
-void printInternal(PrintStream&amp;, JSC::B3::Air::Arg::Signedness);
</del><ins>+JS_EXPORT_PRIVATE void printInternal(PrintStream&amp;, JSC::B3::Air::Arg::Kind);
+JS_EXPORT_PRIVATE void printInternal(PrintStream&amp;, JSC::B3::Air::Arg::Role);
+JS_EXPORT_PRIVATE void printInternal(PrintStream&amp;, JSC::B3::Air::Arg::Type);
+JS_EXPORT_PRIVATE void printInternal(PrintStream&amp;, JSC::B3::Air::Arg::Width);
+JS_EXPORT_PRIVATE void printInternal(PrintStream&amp;, JSC::B3::Air::Arg::Signedness);
</ins><span class="cx"> 
</span><span class="cx"> template&lt;typename T&gt; struct DefaultHash;
</span><span class="cx"> template&lt;&gt; struct DefaultHash&lt;JSC::B3::Air::Arg&gt; {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirCodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirCode.h (203995 => 203996)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirCode.h        2016-08-01 23:21:48 UTC (rev 203995)
+++ trunk/Source/JavaScriptCore/b3/air/AirCode.h        2016-08-01 23:22:15 UTC (rev 203996)
</span><span class="lines">@@ -152,7 +152,7 @@
</span><span class="cx">     // Recomputes predecessors and deletes unreachable blocks.
</span><span class="cx">     void resetReachability();
</span><span class="cx"> 
</span><del>-    void dump(PrintStream&amp;) const;
</del><ins>+    JS_EXPORT_PRIVATE void dump(PrintStream&amp;) const;
</ins><span class="cx"> 
</span><span class="cx">     unsigned size() const { return m_blocks.size(); }
</span><span class="cx">     BasicBlock* at(unsigned index) const { return m_blocks[index].get(); }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirOpcodeopcodes"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes (203995 => 203996)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes        2016-08-01 23:21:48 UTC (rev 203995)
+++ trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes        2016-08-01 23:22:15 UTC (rev 203996)
</span><span class="lines">@@ -675,23 +675,23 @@
</span><span class="cx">     x86: RelCond, Index, Tmp
</span><span class="cx"> 
</span><span class="cx"> BranchTest8 U:G:32, U:G:8, U:G:8 /branch
</span><del>-    x86: ResCond, Addr, Imm
-    x86: ResCond, Index, Imm
</del><ins>+    x86: ResCond, Addr, BitImm
+    x86: ResCond, Index, BitImm
</ins><span class="cx"> 
</span><span class="cx"> BranchTest32 U:G:32, U:G:32, U:G:32 /branch
</span><span class="cx">     ResCond, Tmp, Tmp
</span><del>-    ResCond, Tmp, BitImm
-    x86: ResCond, Addr, Imm
-    x86: ResCond, Index, Imm
</del><ins>+    x86: ResCond, Tmp, BitImm
+    x86: ResCond, Addr, BitImm
+    x86: ResCond, Index, BitImm
</ins><span class="cx"> 
</span><span class="cx"> # Warning: forms that take an immediate will sign-extend their immediate. You probably want
</span><span class="cx"> # BranchTest32 in most cases where you use an immediate.
</span><span class="cx"> 64: BranchTest64 U:G:32, U:G:64, U:G:64 /branch
</span><span class="cx">     ResCond, Tmp, Tmp
</span><del>-    ResCond, Tmp, BitImm64
-    x86: ResCond, Addr, Imm
</del><ins>+    x86: ResCond, Tmp, BitImm
+    x86: ResCond, Addr, BitImm
</ins><span class="cx">     x86: ResCond, Addr, Tmp
</span><del>-    x86: ResCond, Index, Imm
</del><ins>+    x86: ResCond, Index, BitImm
</ins><span class="cx"> 
</span><span class="cx"> BranchDouble U:G:32, U:F:64, U:F:64 /branch
</span><span class="cx">     DoubleCond, Tmp, Tmp
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirValidateh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirValidate.h (203995 => 203996)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirValidate.h        2016-08-01 23:21:48 UTC (rev 203995)
+++ trunk/Source/JavaScriptCore/b3/air/AirValidate.h        2016-08-01 23:22:15 UTC (rev 203996)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2015 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -32,7 +32,7 @@
</span><span class="cx"> 
</span><span class="cx"> class Code;
</span><span class="cx"> 
</span><del>-void validate(Code&amp;, const char* dumpBefore = nullptr);
</del><ins>+JS_EXPORT_PRIVATE void validate(Code&amp;, const char* dumpBefore = nullptr);
</ins><span class="cx"> 
</span><span class="cx"> } } } // namespace JSC::B3::Air
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airopcode_generatorrb"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/opcode_generator.rb (203995 => 203996)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/opcode_generator.rb        2016-08-01 23:21:48 UTC (rev 203995)
+++ trunk/Source/JavaScriptCore/b3/air/opcode_generator.rb        2016-08-01 23:22:15 UTC (rev 203996)
</span><span class="lines">@@ -490,7 +490,7 @@
</span><span class="cx">     
</span><span class="cx">     outp.puts &quot;namespace WTF {&quot;
</span><span class="cx">     outp.puts &quot;class PrintStream;&quot;
</span><del>-    outp.puts &quot;void printInternal(PrintStream&amp;, JSC::B3::Air::Opcode);&quot;
</del><ins>+    outp.puts &quot;JS_EXPORT_PRIVATE void printInternal(PrintStream&amp;, JSC::B3::Air::Opcode);&quot;
</ins><span class="cx">     outp.puts &quot;} // namespace WTF&quot;
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3testb3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/testb3.cpp (203995 => 203996)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/testb3.cpp        2016-08-01 23:21:48 UTC (rev 203995)
+++ trunk/Source/JavaScriptCore/b3/testb3.cpp        2016-08-01 23:22:15 UTC (rev 203996)
</span><span class="lines">@@ -135,6 +135,22 @@
</span><span class="cx">     return invoke&lt;T&gt;(*compile(procedure), arguments...);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void lowerToAirForTesting(Procedure&amp; proc)
+{
+    proc.resetReachability();
+    
+    if (shouldBeVerbose())
+        dataLog(&quot;B3 before lowering:\n&quot;, proc);
+    
+    validate(proc);
+    lowerToAir(proc);
+    
+    if (shouldBeVerbose())
+        dataLog(&quot;Air after lowering:\n&quot;, proc.code());
+    
+    Air::validate(proc.code());
+}
+
</ins><span class="cx"> template&lt;typename Type&gt;
</span><span class="cx"> struct Operand {
</span><span class="cx">     const char* name;
</span><span class="lines">@@ -12179,6 +12195,7 @@
</span><span class="cx">     
</span><span class="cx">     polyJump-&gt;setGenerator(
</span><span class="cx">         [&amp;] (CCallHelpers&amp; jit, const StackmapGenerationParams&amp; params) {
</span><ins>+            AllowMacroScratchRegisterUsage allowScratch(jit);
</ins><span class="cx">             Vector&lt;Box&lt;CCallHelpers::Label&gt;&gt; labels = params.successorLabels();
</span><span class="cx"> 
</span><span class="cx">             MacroAssemblerCodePtr* jumpTable = bitwise_cast&lt;MacroAssemblerCodePtr*&gt;(
</span><span class="lines">@@ -12811,6 +12828,48 @@
</span><span class="cx">     run(false);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void testBranchBitAndImmFusion(
+    B3::Opcode valueModifier, Type valueType, int64_t constant,
+    Air::Opcode expectedOpcode, Air::Arg::Kind firstKind)
+{
+    // Currently this test should pass on all CPUs. But some CPUs may not support this fused
+    // instruction. It's OK to skip this test on those CPUs.
+    
+    Procedure proc;
+    
+    BasicBlock* root = proc.addBlock();
+    BasicBlock* one = proc.addBlock();
+    BasicBlock* two = proc.addBlock();
+    
+    Value* left = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0);
+    
+    if (valueModifier != Identity) {
+        if (MemoryValue::accepts(valueModifier))
+            left = root-&gt;appendNew&lt;MemoryValue&gt;(proc, valueModifier, valueType, Origin(), left);
+        else
+            left = root-&gt;appendNew&lt;Value&gt;(proc, valueModifier, valueType, Origin(), left);
+    }
+    
+    root-&gt;appendNew&lt;Value&gt;(
+        proc, Branch, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(
+            proc, BitAnd, Origin(), left,
+            root-&gt;appendIntConstant(proc, Origin(), valueType, constant)));
+    root-&gt;setSuccessors(FrequentedBlock(one), FrequentedBlock(two));
+    
+    one-&gt;appendNew&lt;Value&gt;(proc, Oops, Origin());
+    two-&gt;appendNew&lt;Value&gt;(proc, Oops, Origin());
+
+    lowerToAirForTesting(proc);
+
+    // The first basic block must end in a BranchTest64(resCond, tmp, bitImm).
+    Air::Inst terminal = proc.code()[0]-&gt;last();
+    CHECK_EQ(terminal.opcode, expectedOpcode);
+    CHECK_EQ(terminal.args[0].kind(), Air::Arg::ResCond);
+    CHECK_EQ(terminal.args[1].kind(), firstKind);
+    CHECK(terminal.args[2].kind() == Air::Arg::BitImm || terminal.args[2].kind() == Air::Arg::BitImm64);
+}
+
</ins><span class="cx"> // Make sure the compiler does not try to optimize anything out.
</span><span class="cx"> NEVER_INLINE double zero()
</span><span class="cx"> {
</span><span class="lines">@@ -14224,6 +14283,17 @@
</span><span class="cx"> 
</span><span class="cx">     RUN(testSomeEarlyRegister());
</span><span class="cx">     
</span><ins>+    if (isX86()) {
+        RUN(testBranchBitAndImmFusion(Identity, Int64, 1, Air::BranchTest32, Air::Arg::Tmp));
+        RUN(testBranchBitAndImmFusion(Identity, Int64, 0xff, Air::BranchTest32, Air::Arg::Tmp));
+        RUN(testBranchBitAndImmFusion(Trunc, Int32, 1, Air::BranchTest32, Air::Arg::Tmp));
+        RUN(testBranchBitAndImmFusion(Trunc, Int32, 0xff, Air::BranchTest32, Air::Arg::Tmp));
+        RUN(testBranchBitAndImmFusion(Load8S, Int32, 1, Air::BranchTest8, Air::Arg::Addr));
+        RUN(testBranchBitAndImmFusion(Load8Z, Int32, 1, Air::BranchTest8, Air::Arg::Addr));
+        RUN(testBranchBitAndImmFusion(Load, Int32, 1, Air::BranchTest32, Air::Arg::Addr));
+        RUN(testBranchBitAndImmFusion(Load, Int64, 1, Air::BranchTest32, Air::Arg::Addr));
+    }
+
</ins><span class="cx">     if (tasks.isEmpty())
</span><span class="cx">         usage();
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>