<!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>[192540] trunk</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/192540">192540</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2015-11-17 14:31:40 -0800 (Tue, 17 Nov 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>CheckAdd/Mul should have commutativity optimizations in B3-&gt;Air lowering
https://bugs.webkit.org/show_bug.cgi?id=151214

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

This is an overhaul of CheckAdd/CheckSub/CheckMul that fixes bugs, improves codegen, and
simplifies the contract between B3 and its client.

Previously, the idea was that the operands to the Air BranchAdd/Sub/Mul matched the children of
the B3 CheckAdd/Sub/Mul, or at least, that's what the B3::CheckSpecial would make you believe.
This meant that B3/Air had to avoid optimizations that would break this protocol. This prevented
commutativity optimizations on CheckAdd/Mul and it also prevented strength reduction from
CheckMul(x, 2) to CheckAdd(x, x), for example. Those optimizations would break things because the
client's Stackmap generation callback was allowed to assume that the first entry in params.reps
was the first child. Also, there was a contract between B3 and its client that for CheckAdd/Sub,
the client would undo the operation by doing the opposite operation with the params.reps[0] as the
source and params.reps[1] as the destination.

This not only prevented commutativity optimizations, it also led to bugs. Here are two bugs that
we had:

- Add(x, x) would not work. The client would be told to undo the add using %x as both the source
  and destination. The client would use a sub() instruction. The result would not be x - it would
  be zero.

- Mul where the result got coalesced with one of the sources. You can't undo a multiplication, so
  you need to keep the inputs alive until after the result is computed - i.e. the inputs are late
  uses. I initially thought I worked around this by using a three-operand form of Mul, but of
  course that doesn't actually fix the issue.

This patch fixes these issues comprehensively by introducing the following changes:

The params.reps corresponding to the first two children of CheckAdd/Sub/Mul and the first child of
Check are always garbage: if you want to know the values of those children in the slow path, pass
them as additional stackmap children. This makes it clear to the compiler whose values you
actually care about, and frees the compiler to reorder and commute the non-stackmap children.

The &quot;undo&quot; of an Add or Sub is handled internally by B3: the client doesn't have to know anything
about undoing. B3 does it. The contract is simply that if a B3::Value* is a stackmap child of a
CheckXYZ, then the corresponding entry in params.reps inside the stackmap generator callback will
contain the value of that Value*. For Add and Sub, B3 undoes the operation. For Add(x, x), the
undo uses the carry flag and some shift magic. For Mul, B3 uses LateUse:

A new kind of Arg::Role called Arg::LateUse is introduced: This kind of use means that the use
happens at the start of the execution of the next instruction. None of the built-in Air opcodes
use LateUse, but it is used by B3::CheckSpecial. We use it to implement CheckMul.

Finally, this change fixes testComplex to actually create many live variables. This revealed a
really dumb pathology in allocateStack(), and this patch fixes it. Basically, it's a bad idea to
build interference graphs by repeatedly recreating the same cliques.

* assembler/MacroAssemblerX86Common.h:
(JSC::MacroAssemblerX86Common::test32):
(JSC::MacroAssemblerX86Common::setCarry):
(JSC::MacroAssemblerX86Common::invert):
* b3/B3CheckSpecial.cpp:
(JSC::B3::Air::numB3Args):
(JSC::B3::CheckSpecial::Key::Key):
(JSC::B3::CheckSpecial::Key::dump):
(JSC::B3::CheckSpecial::CheckSpecial):
(JSC::B3::CheckSpecial::forEachArg):
(JSC::B3::CheckSpecial::isValid):
(JSC::B3::CheckSpecial::generate):
(JSC::B3::CheckSpecial::dumpImpl):
(JSC::B3::CheckSpecial::deepDumpImpl):
* b3/B3CheckSpecial.h:
(JSC::B3::CheckSpecial::Key::Key):
(JSC::B3::CheckSpecial::Key::operator==):
(JSC::B3::CheckSpecial::Key::operator!=):
(JSC::B3::CheckSpecial::Key::opcode):
(JSC::B3::CheckSpecial::Key::numArgs):
(JSC::B3::CheckSpecial::Key::stackmapRole):
(JSC::B3::CheckSpecial::Key::hash):
* b3/B3CheckValue.cpp:
(JSC::B3::CheckValue::~CheckValue):
(JSC::B3::CheckValue::convertToAdd):
(JSC::B3::CheckValue::CheckValue):
* b3/B3CheckValue.h:
* b3/B3Const32Value.cpp:
(JSC::B3::Const32Value::checkMulConstant):
(JSC::B3::Const32Value::checkNegConstant):
(JSC::B3::Const32Value::divConstant):
* b3/B3Const32Value.h:
* b3/B3Const64Value.cpp:
(JSC::B3::Const64Value::checkMulConstant):
(JSC::B3::Const64Value::checkNegConstant):
(JSC::B3::Const64Value::divConstant):
* b3/B3Const64Value.h:
* b3/B3LowerToAir.cpp:
(JSC::B3::Air::LowerToAir::appendBinOp):
(JSC::B3::Air::LowerToAir::lower):
* b3/B3Opcode.h:
* b3/B3PatchpointSpecial.cpp:
(JSC::B3::PatchpointSpecial::~PatchpointSpecial):
(JSC::B3::PatchpointSpecial::forEachArg):
(JSC::B3::PatchpointSpecial::isValid):
* b3/B3ReduceStrength.cpp:
* b3/B3StackmapSpecial.cpp:
(JSC::B3::StackmapSpecial::forEachArgImpl):
* b3/B3StackmapSpecial.h:
* b3/B3StackmapValue.cpp:
(JSC::B3::StackmapValue::append):
(JSC::B3::StackmapValue::appendSomeRegister):
(JSC::B3::StackmapValue::setConstrainedChild):
* b3/B3StackmapValue.h:
* b3/B3Validate.cpp:
* b3/B3Value.cpp:
(JSC::B3::Value::checkMulConstant):
(JSC::B3::Value::checkNegConstant):
(JSC::B3::Value::divConstant):
* b3/B3Value.h:
* b3/air/AirAllocateStack.cpp:
(JSC::B3::Air::allocateStack):
* b3/air/AirArg.cpp:
(WTF::printInternal):
* b3/air/AirArg.h:
(JSC::B3::Air::Arg::isAnyUse):
(JSC::B3::Air::Arg::isEarlyUse):
(JSC::B3::Air::Arg::isLateUse):
(JSC::B3::Air::Arg::isDef):
(JSC::B3::Air::Arg::forEachTmp):
(JSC::B3::Air::Arg::isUse): Deleted.
* b3/air/AirGenerate.cpp:
(JSC::B3::Air::generate):
* b3/air/AirIteratedRegisterCoalescing.cpp:
(JSC::B3::Air::IteratedRegisterCoalescingAllocator::build):
(JSC::B3::Air::IteratedRegisterCoalescingAllocator::allocate):
(JSC::B3::Air::IteratedRegisterCoalescingAllocator::InterferenceEdge::hash):
(JSC::B3::Air::IteratedRegisterCoalescingAllocator::InterferenceEdge::dump):
(JSC::B3::Air::addSpillAndFillToProgram):
(JSC::B3::Air::iteratedRegisterCoalescingOnType):
(JSC::B3::Air::iteratedRegisterCoalescing):
* b3/air/AirLiveness.h:
(JSC::B3::Air::Liveness::Liveness):
(JSC::B3::Air::Liveness::LocalCalc::LocalCalc):
(JSC::B3::Air::Liveness::LocalCalc::live):
(JSC::B3::Air::Liveness::LocalCalc::takeLive):
(JSC::B3::Air::Liveness::LocalCalc::execute):
* b3/air/AirOpcode.opcodes:
* b3/air/AirReportUsedRegisters.cpp:
(JSC::B3::Air::reportUsedRegisters):
* b3/air/AirSpillEverything.cpp:
(JSC::B3::Air::spillEverything):
* b3/testb3.cpp:
(JSC::B3::testMulArg):
(JSC::B3::testMulArgStore):
(JSC::B3::testMulAddArg):
(JSC::B3::testMulArgs):
(JSC::B3::testComplex):
(JSC::B3::testSimpleCheck):
(JSC::B3::testCheckLessThan):
(JSC::B3::testCheckMegaCombo):
(JSC::B3::testCheckAddImm):
(JSC::B3::testCheckAddImmCommute):
(JSC::B3::testCheckAddImmSomeRegister):
(JSC::B3::testCheckAdd):
(JSC::B3::testCheckAdd64):
(JSC::B3::testCheckSubImm):
(JSC::B3::testCheckSubBadImm):
(JSC::B3::testCheckSub):
(JSC::B3::testCheckSub64):
(JSC::B3::testCheckNeg):
(JSC::B3::testCheckNeg64):
(JSC::B3::testCheckMul):
(JSC::B3::testCheckMulMemory):
(JSC::B3::testCheckMul2):
(JSC::B3::testCheckMul64):
(JSC::B3::run):

Source/WTF:

Disable my failed attempts at perfect forwarding, since they were incorrect, and caused compile
errors if you tried to pass an argument that bound to lvalue. This shouldn't affect performance of
anything we care about, and performance tests seem to confirm that it's all good.

* wtf/ScopedLambda.h:</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="#trunkSourceJavaScriptCoreb3B3CheckSpecialcpp">trunk/Source/JavaScriptCore/b3/B3CheckSpecial.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3CheckSpecialh">trunk/Source/JavaScriptCore/b3/B3CheckSpecial.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3CheckValuecpp">trunk/Source/JavaScriptCore/b3/B3CheckValue.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3CheckValueh">trunk/Source/JavaScriptCore/b3/B3CheckValue.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Const32Valuecpp">trunk/Source/JavaScriptCore/b3/B3Const32Value.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Const32Valueh">trunk/Source/JavaScriptCore/b3/B3Const32Value.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Const64Valuecpp">trunk/Source/JavaScriptCore/b3/B3Const64Value.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Const64Valueh">trunk/Source/JavaScriptCore/b3/B3Const64Value.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3LowerToAircpp">trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Opcodeh">trunk/Source/JavaScriptCore/b3/B3Opcode.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3PatchpointSpecialcpp">trunk/Source/JavaScriptCore/b3/B3PatchpointSpecial.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3ReduceStrengthcpp">trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3StackmapSpecialcpp">trunk/Source/JavaScriptCore/b3/B3StackmapSpecial.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3StackmapSpecialh">trunk/Source/JavaScriptCore/b3/B3StackmapSpecial.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3StackmapValuecpp">trunk/Source/JavaScriptCore/b3/B3StackmapValue.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3StackmapValueh">trunk/Source/JavaScriptCore/b3/B3StackmapValue.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Validatecpp">trunk/Source/JavaScriptCore/b3/B3Validate.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Valuecpp">trunk/Source/JavaScriptCore/b3/B3Value.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3Valueh">trunk/Source/JavaScriptCore/b3/B3Value.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirAllocateStackcpp">trunk/Source/JavaScriptCore/b3/air/AirAllocateStack.cpp</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="#trunkSourceJavaScriptCoreb3airAirGeneratecpp">trunk/Source/JavaScriptCore/b3/air/AirGenerate.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirIteratedRegisterCoalescingcpp">trunk/Source/JavaScriptCore/b3/air/AirIteratedRegisterCoalescing.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirLivenessh">trunk/Source/JavaScriptCore/b3/air/AirLiveness.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirOpcodeopcodes">trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirReportUsedRegisterscpp">trunk/Source/JavaScriptCore/b3/air/AirReportUsedRegisters.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirSpillEverythingcpp">trunk/Source/JavaScriptCore/b3/air/AirSpillEverything.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3testb3cpp">trunk/Source/JavaScriptCore/b3/testb3.cpp</a></li>
<li><a href="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFwtfScopedLambdah">trunk/Source/WTF/wtf/ScopedLambda.h</a></li>
<li><a href="#trunkToolsReducedFTLComplexTestcpp">trunk/Tools/ReducedFTL/ComplexTest.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -1,5 +1,176 @@
</span><span class="cx"> 2015-11-17  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        CheckAdd/Mul should have commutativity optimizations in B3-&gt;Air lowering
+        https://bugs.webkit.org/show_bug.cgi?id=151214
+
+        Reviewed by Geoffrey Garen.
+
+        This is an overhaul of CheckAdd/CheckSub/CheckMul that fixes bugs, improves codegen, and
+        simplifies the contract between B3 and its client.
+
+        Previously, the idea was that the operands to the Air BranchAdd/Sub/Mul matched the children of
+        the B3 CheckAdd/Sub/Mul, or at least, that's what the B3::CheckSpecial would make you believe.
+        This meant that B3/Air had to avoid optimizations that would break this protocol. This prevented
+        commutativity optimizations on CheckAdd/Mul and it also prevented strength reduction from
+        CheckMul(x, 2) to CheckAdd(x, x), for example. Those optimizations would break things because the
+        client's Stackmap generation callback was allowed to assume that the first entry in params.reps
+        was the first child. Also, there was a contract between B3 and its client that for CheckAdd/Sub,
+        the client would undo the operation by doing the opposite operation with the params.reps[0] as the
+        source and params.reps[1] as the destination.
+
+        This not only prevented commutativity optimizations, it also led to bugs. Here are two bugs that
+        we had:
+
+        - Add(x, x) would not work. The client would be told to undo the add using %x as both the source
+          and destination. The client would use a sub() instruction. The result would not be x - it would
+          be zero.
+
+        - Mul where the result got coalesced with one of the sources. You can't undo a multiplication, so
+          you need to keep the inputs alive until after the result is computed - i.e. the inputs are late
+          uses. I initially thought I worked around this by using a three-operand form of Mul, but of
+          course that doesn't actually fix the issue.
+
+        This patch fixes these issues comprehensively by introducing the following changes:
+
+        The params.reps corresponding to the first two children of CheckAdd/Sub/Mul and the first child of
+        Check are always garbage: if you want to know the values of those children in the slow path, pass
+        them as additional stackmap children. This makes it clear to the compiler whose values you
+        actually care about, and frees the compiler to reorder and commute the non-stackmap children.
+
+        The &quot;undo&quot; of an Add or Sub is handled internally by B3: the client doesn't have to know anything
+        about undoing. B3 does it. The contract is simply that if a B3::Value* is a stackmap child of a
+        CheckXYZ, then the corresponding entry in params.reps inside the stackmap generator callback will
+        contain the value of that Value*. For Add and Sub, B3 undoes the operation. For Add(x, x), the
+        undo uses the carry flag and some shift magic. For Mul, B3 uses LateUse:
+
+        A new kind of Arg::Role called Arg::LateUse is introduced: This kind of use means that the use
+        happens at the start of the execution of the next instruction. None of the built-in Air opcodes
+        use LateUse, but it is used by B3::CheckSpecial. We use it to implement CheckMul.
+
+        Finally, this change fixes testComplex to actually create many live variables. This revealed a
+        really dumb pathology in allocateStack(), and this patch fixes it. Basically, it's a bad idea to
+        build interference graphs by repeatedly recreating the same cliques.
+
+        * assembler/MacroAssemblerX86Common.h:
+        (JSC::MacroAssemblerX86Common::test32):
+        (JSC::MacroAssemblerX86Common::setCarry):
+        (JSC::MacroAssemblerX86Common::invert):
+        * b3/B3CheckSpecial.cpp:
+        (JSC::B3::Air::numB3Args):
+        (JSC::B3::CheckSpecial::Key::Key):
+        (JSC::B3::CheckSpecial::Key::dump):
+        (JSC::B3::CheckSpecial::CheckSpecial):
+        (JSC::B3::CheckSpecial::forEachArg):
+        (JSC::B3::CheckSpecial::isValid):
+        (JSC::B3::CheckSpecial::generate):
+        (JSC::B3::CheckSpecial::dumpImpl):
+        (JSC::B3::CheckSpecial::deepDumpImpl):
+        * b3/B3CheckSpecial.h:
+        (JSC::B3::CheckSpecial::Key::Key):
+        (JSC::B3::CheckSpecial::Key::operator==):
+        (JSC::B3::CheckSpecial::Key::operator!=):
+        (JSC::B3::CheckSpecial::Key::opcode):
+        (JSC::B3::CheckSpecial::Key::numArgs):
+        (JSC::B3::CheckSpecial::Key::stackmapRole):
+        (JSC::B3::CheckSpecial::Key::hash):
+        * b3/B3CheckValue.cpp:
+        (JSC::B3::CheckValue::~CheckValue):
+        (JSC::B3::CheckValue::convertToAdd):
+        (JSC::B3::CheckValue::CheckValue):
+        * b3/B3CheckValue.h:
+        * b3/B3Const32Value.cpp:
+        (JSC::B3::Const32Value::checkMulConstant):
+        (JSC::B3::Const32Value::checkNegConstant):
+        (JSC::B3::Const32Value::divConstant):
+        * b3/B3Const32Value.h:
+        * b3/B3Const64Value.cpp:
+        (JSC::B3::Const64Value::checkMulConstant):
+        (JSC::B3::Const64Value::checkNegConstant):
+        (JSC::B3::Const64Value::divConstant):
+        * b3/B3Const64Value.h:
+        * b3/B3LowerToAir.cpp:
+        (JSC::B3::Air::LowerToAir::appendBinOp):
+        (JSC::B3::Air::LowerToAir::lower):
+        * b3/B3Opcode.h:
+        * b3/B3PatchpointSpecial.cpp:
+        (JSC::B3::PatchpointSpecial::~PatchpointSpecial):
+        (JSC::B3::PatchpointSpecial::forEachArg):
+        (JSC::B3::PatchpointSpecial::isValid):
+        * b3/B3ReduceStrength.cpp:
+        * b3/B3StackmapSpecial.cpp:
+        (JSC::B3::StackmapSpecial::forEachArgImpl):
+        * b3/B3StackmapSpecial.h:
+        * b3/B3StackmapValue.cpp:
+        (JSC::B3::StackmapValue::append):
+        (JSC::B3::StackmapValue::appendSomeRegister):
+        (JSC::B3::StackmapValue::setConstrainedChild):
+        * b3/B3StackmapValue.h:
+        * b3/B3Validate.cpp:
+        * b3/B3Value.cpp:
+        (JSC::B3::Value::checkMulConstant):
+        (JSC::B3::Value::checkNegConstant):
+        (JSC::B3::Value::divConstant):
+        * b3/B3Value.h:
+        * b3/air/AirAllocateStack.cpp:
+        (JSC::B3::Air::allocateStack):
+        * b3/air/AirArg.cpp:
+        (WTF::printInternal):
+        * b3/air/AirArg.h:
+        (JSC::B3::Air::Arg::isAnyUse):
+        (JSC::B3::Air::Arg::isEarlyUse):
+        (JSC::B3::Air::Arg::isLateUse):
+        (JSC::B3::Air::Arg::isDef):
+        (JSC::B3::Air::Arg::forEachTmp):
+        (JSC::B3::Air::Arg::isUse): Deleted.
+        * b3/air/AirGenerate.cpp:
+        (JSC::B3::Air::generate):
+        * b3/air/AirIteratedRegisterCoalescing.cpp:
+        (JSC::B3::Air::IteratedRegisterCoalescingAllocator::build):
+        (JSC::B3::Air::IteratedRegisterCoalescingAllocator::allocate):
+        (JSC::B3::Air::IteratedRegisterCoalescingAllocator::InterferenceEdge::hash):
+        (JSC::B3::Air::IteratedRegisterCoalescingAllocator::InterferenceEdge::dump):
+        (JSC::B3::Air::addSpillAndFillToProgram):
+        (JSC::B3::Air::iteratedRegisterCoalescingOnType):
+        (JSC::B3::Air::iteratedRegisterCoalescing):
+        * b3/air/AirLiveness.h:
+        (JSC::B3::Air::Liveness::Liveness):
+        (JSC::B3::Air::Liveness::LocalCalc::LocalCalc):
+        (JSC::B3::Air::Liveness::LocalCalc::live):
+        (JSC::B3::Air::Liveness::LocalCalc::takeLive):
+        (JSC::B3::Air::Liveness::LocalCalc::execute):
+        * b3/air/AirOpcode.opcodes:
+        * b3/air/AirReportUsedRegisters.cpp:
+        (JSC::B3::Air::reportUsedRegisters):
+        * b3/air/AirSpillEverything.cpp:
+        (JSC::B3::Air::spillEverything):
+        * b3/testb3.cpp:
+        (JSC::B3::testMulArg):
+        (JSC::B3::testMulArgStore):
+        (JSC::B3::testMulAddArg):
+        (JSC::B3::testMulArgs):
+        (JSC::B3::testComplex):
+        (JSC::B3::testSimpleCheck):
+        (JSC::B3::testCheckLessThan):
+        (JSC::B3::testCheckMegaCombo):
+        (JSC::B3::testCheckAddImm):
+        (JSC::B3::testCheckAddImmCommute):
+        (JSC::B3::testCheckAddImmSomeRegister):
+        (JSC::B3::testCheckAdd):
+        (JSC::B3::testCheckAdd64):
+        (JSC::B3::testCheckSubImm):
+        (JSC::B3::testCheckSubBadImm):
+        (JSC::B3::testCheckSub):
+        (JSC::B3::testCheckSub64):
+        (JSC::B3::testCheckNeg):
+        (JSC::B3::testCheckNeg64):
+        (JSC::B3::testCheckMul):
+        (JSC::B3::testCheckMulMemory):
+        (JSC::B3::testCheckMul2):
+        (JSC::B3::testCheckMul64):
+        (JSC::B3::run):
+
+2015-11-17  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
</ins><span class="cx">         Air should lay out code optimally
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=150478
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerX86Commonh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -1611,6 +1611,11 @@
</span><span class="cx">         set32(x86Condition(cond), dest);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void setCarry(RegisterID dest)
+    {
+        set32(X86Assembler::ConditionC, dest);
+    }
+
</ins><span class="cx">     // Invert a relational condition, e.g. == becomes !=, &lt; becomes &gt;=, etc.
</span><span class="cx">     static RelationalCondition invert(RelationalCondition cond)
</span><span class="cx">     {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3CheckSpecialcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3CheckSpecial.cpp (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3CheckSpecial.cpp        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/JavaScriptCore/b3/B3CheckSpecial.cpp        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -39,9 +39,9 @@
</span><span class="cx"> 
</span><span class="cx"> namespace {
</span><span class="cx"> 
</span><del>-unsigned numB3Args(Inst&amp; inst)
</del><ins>+unsigned numB3Args(B3::Opcode opcode)
</ins><span class="cx"> {
</span><del>-    switch (inst.origin-&gt;opcode()) {
</del><ins>+    switch (opcode) {
</ins><span class="cx">     case CheckAdd:
</span><span class="cx">     case CheckSub:
</span><span class="cx">     case CheckMul:
</span><span class="lines">@@ -54,28 +54,40 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+unsigned numB3Args(Value* value)
+{
+    return numB3Args(value-&gt;opcode());
+}
+
+unsigned numB3Args(Inst&amp; inst)
+{
+    return numB3Args(inst.origin);
+}
+
</ins><span class="cx"> } // anonymous namespace
</span><span class="cx"> 
</span><span class="cx"> CheckSpecial::Key::Key(const Inst&amp; inst)
</span><span class="cx"> {
</span><span class="cx">     m_opcode = inst.opcode;
</span><span class="cx">     m_numArgs = inst.args.size();
</span><ins>+    m_stackmapRole = Arg::Use;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void CheckSpecial::Key::dump(PrintStream&amp; out) const
</span><span class="cx"> {
</span><del>-    out.print(m_opcode, &quot;(&quot;, m_numArgs, &quot;)&quot;);
</del><ins>+    out.print(m_opcode, &quot;(&quot;, m_numArgs, &quot;,&quot;, m_stackmapRole, &quot;)&quot;);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-CheckSpecial::CheckSpecial(Air::Opcode opcode, unsigned numArgs)
</del><ins>+CheckSpecial::CheckSpecial(Air::Opcode opcode, unsigned numArgs, Arg::Role stackmapRole)
</ins><span class="cx">     : m_checkOpcode(opcode)
</span><ins>+    , m_stackmapRole(stackmapRole)
</ins><span class="cx">     , m_numCheckArgs(numArgs)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(isTerminal(opcode));
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> CheckSpecial::CheckSpecial(const CheckSpecial::Key&amp; key)
</span><del>-    : CheckSpecial(key.opcode(), key.numArgs())
</del><ins>+    : CheckSpecial(key.opcode(), key.numArgs(), key.stackmapRole())
</ins><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -105,7 +117,7 @@
</span><span class="cx">     Inst hidden = hiddenBranch(inst);
</span><span class="cx">     hidden.forEachArg(callback);
</span><span class="cx">     commitHiddenBranch(inst, hidden);
</span><del>-    forEachArgImpl(numB3Args(inst), m_numCheckArgs + 1, inst, callback);
</del><ins>+    forEachArgImpl(numB3Args(inst), m_numCheckArgs + 1, inst, m_stackmapRole, callback);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool CheckSpecial::isValid(Inst&amp; inst)
</span><span class="lines">@@ -130,28 +142,71 @@
</span><span class="cx">     ASSERT(value);
</span><span class="cx"> 
</span><span class="cx">     Vector&lt;ValueRep&gt; reps;
</span><del>-    if (isCheckMath(value-&gt;opcode())) {
-        if (value-&gt;opcode() == CheckMul) {
-            reps.append(repForArg(*context.code, inst.args[2]));
-            reps.append(repForArg(*context.code, inst.args[3]));
-        } else {
-            if (value-&gt;opcode() == CheckSub &amp;&amp; value-&gt;child(0)-&gt;isInt(0))
-                reps.append(ValueRep::constant(0));
-            else
-                reps.append(repForArg(*context.code, inst.args[3]));
-            reps.append(repForArg(*context.code, inst.args[2]));
-        }
-    } else {
-        ASSERT(value-&gt;opcode() == Check);
-        reps.append(ValueRep::constant(1));
-    }
</del><ins>+    for (unsigned i = numB3Args(value); i--;)
+        reps.append(ValueRep());
</ins><span class="cx"> 
</span><span class="cx">     appendRepsImpl(context, m_numCheckArgs + 1, inst, reps);
</span><del>-    
</del><ins>+
+    // Set aside the args that are relevant to undoing the operation. This is because we don't want to
+    // capture all of inst in the closure below.
+    Vector&lt;Arg, 3&gt; args;
+    for (unsigned i = 0; i &lt; m_numCheckArgs; ++i)
+        args.append(inst.args[1 + i]);
+
</ins><span class="cx">     context.latePaths.append(
</span><span class="cx">         createSharedTask&lt;GenerationContext::LatePathFunction&gt;(
</span><del>-            [=] (CCallHelpers&amp; jit, GenerationContext&amp;) {
</del><ins>+            [=] (CCallHelpers&amp; jit, GenerationContext&amp; context) {
</ins><span class="cx">                 fail.link(&amp;jit);
</span><ins>+
+                // If necessary, undo the operation.
+                switch (m_checkOpcode) {
+                case BranchAdd32:
+                    if (args[1] == args[2]) {
+                        // This is ugly, but that's fine - we won't have to do this very often.
+                        ASSERT(args[1].isGPR());
+                        GPRReg valueGPR = args[1].gpr();
+                        GPRReg scratchGPR = CCallHelpers::selectScratchGPR(valueGPR);
+                        jit.pushToSave(scratchGPR);
+                        jit.setCarry(scratchGPR);
+                        jit.lshift32(CCallHelpers::TrustedImm32(31), scratchGPR);
+                        jit.urshift32(CCallHelpers::TrustedImm32(1), valueGPR);
+                        jit.or32(scratchGPR, valueGPR);
+                        jit.popToRestore(scratchGPR);
+                        break;
+                    }
+                    Inst(Sub32, nullptr, args[1], args[2]).generate(jit, context);
+                    break;
+                case BranchAdd64:
+                    if (args[1] == args[2]) {
+                        // This is ugly, but that's fine - we won't have to do this very often.
+                        ASSERT(args[1].isGPR());
+                        GPRReg valueGPR = args[1].gpr();
+                        GPRReg scratchGPR = CCallHelpers::selectScratchGPR(valueGPR);
+                        jit.pushToSave(scratchGPR);
+                        jit.setCarry(scratchGPR);
+                        jit.lshift64(CCallHelpers::TrustedImm32(63), scratchGPR);
+                        jit.urshift64(CCallHelpers::TrustedImm32(1), valueGPR);
+                        jit.or64(scratchGPR, valueGPR);
+                        jit.popToRestore(scratchGPR);
+                        break;
+                    }
+                    Inst(Sub64, nullptr, args[1], args[2]).generate(jit, context);
+                    break;
+                case BranchSub32:
+                    Inst(Add32, nullptr, args[1], args[2]).generate(jit, context);
+                    break;
+                case BranchSub64:
+                    Inst(Add64, nullptr, args[1], args[2]).generate(jit, context);
+                    break;
+                case BranchNeg32:
+                    Inst(Neg32, nullptr, args[1]).generate(jit, context);
+                    break;
+                case BranchNeg64:
+                    Inst(Neg64, nullptr, args[1]).generate(jit, context);
+                    break;
+                default:
+                    break;
+                }
</ins><span class="cx">                 
</span><span class="cx">                 StackmapGenerationParams params;
</span><span class="cx">                 params.value = value;
</span><span class="lines">@@ -166,7 +221,7 @@
</span><span class="cx"> 
</span><span class="cx"> void CheckSpecial::dumpImpl(PrintStream&amp; out) const
</span><span class="cx"> {
</span><del>-    out.print(m_checkOpcode, &quot;(&quot;, m_numCheckArgs, &quot;)&quot;);
</del><ins>+    out.print(m_checkOpcode, &quot;(&quot;, m_numCheckArgs, &quot;,&quot;, m_stackmapRole, &quot;)&quot;);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void CheckSpecial::deepDumpImpl(PrintStream&amp; out) const
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3CheckSpecialh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3CheckSpecial.h (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3CheckSpecial.h        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/JavaScriptCore/b3/B3CheckSpecial.h        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -28,6 +28,7 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(B3_JIT)
</span><span class="cx"> 
</span><ins>+#include &quot;AirArg.h&quot;
</ins><span class="cx"> #include &quot;AirOpcode.h&quot;
</span><span class="cx"> #include &quot;B3StackmapSpecial.h&quot;
</span><span class="cx"> #include &lt;wtf/HashMap.h&gt;
</span><span class="lines">@@ -56,12 +57,14 @@
</span><span class="cx">     public:
</span><span class="cx">         Key()
</span><span class="cx">             : m_opcode(Air::Nop)
</span><ins>+            , m_stackmapRole(Air::Arg::Use)
</ins><span class="cx">             , m_numArgs(0)
</span><span class="cx">         {
</span><span class="cx">         }
</span><span class="cx">         
</span><del>-        Key(Air::Opcode opcode, unsigned numArgs)
</del><ins>+        Key(Air::Opcode opcode, unsigned numArgs, Air::Arg::Role stackmapRole = Air::Arg::Use)
</ins><span class="cx">             : m_opcode(opcode)
</span><ins>+            , m_stackmapRole(stackmapRole)
</ins><span class="cx">             , m_numArgs(numArgs)
</span><span class="cx">         {
</span><span class="cx">         }
</span><span class="lines">@@ -71,7 +74,8 @@
</span><span class="cx">         bool operator==(const Key&amp; other) const
</span><span class="cx">         {
</span><span class="cx">             return m_opcode == other.m_opcode
</span><del>-                &amp;&amp; m_numArgs == other.m_numArgs;
</del><ins>+                &amp;&amp; m_numArgs == other.m_numArgs
+                &amp;&amp; m_stackmapRole == other.m_stackmapRole;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         bool operator!=(const Key&amp; other) const
</span><span class="lines">@@ -83,11 +87,13 @@
</span><span class="cx"> 
</span><span class="cx">         Air::Opcode opcode() const { return m_opcode; }
</span><span class="cx">         unsigned numArgs() const { return m_numArgs; }
</span><ins>+        Air::Arg::Role stackmapRole() const { return m_stackmapRole; }
</ins><span class="cx"> 
</span><span class="cx">         void dump(PrintStream&amp; out) const;
</span><span class="cx"> 
</span><span class="cx">         Key(WTF::HashTableDeletedValueType)
</span><span class="cx">             : m_opcode(Air::Nop)
</span><ins>+            , m_stackmapRole(Air::Arg::Use)
</ins><span class="cx">             , m_numArgs(1)
</span><span class="cx">         {
</span><span class="cx">         }
</span><span class="lines">@@ -100,15 +106,16 @@
</span><span class="cx">         unsigned hash() const
</span><span class="cx">         {
</span><span class="cx">             // Seriously, we don't need to be smart here. It just doesn't matter.
</span><del>-            return m_opcode + m_numArgs;
</del><ins>+            return m_opcode + m_numArgs + m_stackmapRole;
</ins><span class="cx">         }
</span><span class="cx">         
</span><span class="cx">     private:
</span><span class="cx">         Air::Opcode m_opcode;
</span><ins>+        Air::Arg::Role m_stackmapRole;
</ins><span class="cx">         unsigned m_numArgs;
</span><span class="cx">     };
</span><span class="cx">     
</span><del>-    CheckSpecial(Air::Opcode, unsigned numArgs);
</del><ins>+    CheckSpecial(Air::Opcode, unsigned numArgs, Air::Arg::Role stackmapRole = Air::Arg::Use);
</ins><span class="cx">     CheckSpecial(const Key&amp;);
</span><span class="cx">     ~CheckSpecial();
</span><span class="cx"> 
</span><span class="lines">@@ -133,6 +140,7 @@
</span><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     Air::Opcode m_checkOpcode;
</span><ins>+    Air::Arg::Role m_stackmapRole;
</ins><span class="cx">     unsigned m_numCheckArgs;
</span><span class="cx"> };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3CheckValuecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3CheckValue.cpp (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3CheckValue.cpp        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/JavaScriptCore/b3/B3CheckValue.cpp        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -34,6 +34,12 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void CheckValue::convertToAdd()
+{
+    RELEASE_ASSERT(opcode() == CheckAdd || opcode() == CheckSub || opcode() == CheckMul);
+    m_opcode = CheckAdd;
+}
+
</ins><span class="cx"> // Use this form for CheckAdd, CheckSub, and CheckMul.
</span><span class="cx"> CheckValue::CheckValue(unsigned index, Opcode opcode, Origin origin, Value* left, Value* right)
</span><span class="cx">     : StackmapValue(index, CheckedOpcode, opcode, left-&gt;type(), origin)
</span><span class="lines">@@ -41,8 +47,8 @@
</span><span class="cx">     ASSERT(B3::isInt(type()));
</span><span class="cx">     ASSERT(left-&gt;type() == right-&gt;type());
</span><span class="cx">     ASSERT(opcode == CheckAdd || opcode == CheckSub || opcode == CheckMul);
</span><del>-    append(ConstrainedValue(left, ValueRep::SomeRegister));
-    append(ConstrainedValue(right, ValueRep::SomeRegister));
</del><ins>+    append(ConstrainedValue(left, ValueRep::Any));
+    append(ConstrainedValue(right, ValueRep::Any));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> // Use this form for Check.
</span><span class="lines">@@ -50,7 +56,7 @@
</span><span class="cx">     : StackmapValue(index, CheckedOpcode, opcode, Void, origin)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(opcode == Check);
</span><del>-    append(predicate);
</del><ins>+    append(ConstrainedValue(predicate, ValueRep::Any));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } } // namespace JSC::B3
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3CheckValueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3CheckValue.h (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3CheckValue.h        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/JavaScriptCore/b3/B3CheckValue.h        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -49,6 +49,8 @@
</span><span class="cx"> 
</span><span class="cx">     ~CheckValue();
</span><span class="cx"> 
</span><ins>+    void convertToAdd();
+
</ins><span class="cx"> private:
</span><span class="cx">     friend class Procedure;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Const32Valuecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Const32Value.cpp (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Const32Value.cpp        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/JavaScriptCore/b3/B3Const32Value.cpp        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -98,6 +98,13 @@
</span><span class="cx">     return proc.add&lt;Const32Value&gt;(origin(), result.unsafeGet());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+Value* Const32Value::checkNegConstant(Procedure&amp; proc) const
+{
+    if (m_value == -m_value)
+        return nullptr;
+    return negConstant(proc);
+}
+
</ins><span class="cx"> Value* Const32Value::divConstant(Procedure&amp; proc, const Value* other) const
</span><span class="cx"> {
</span><span class="cx">     if (!other-&gt;hasInt32())
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Const32Valueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Const32Value.h (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Const32Value.h        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/JavaScriptCore/b3/B3Const32Value.h        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -48,6 +48,7 @@
</span><span class="cx">     Value* checkAddConstant(Procedure&amp;, const Value* other) const override;
</span><span class="cx">     Value* checkSubConstant(Procedure&amp;, const Value* other) const override;
</span><span class="cx">     Value* checkMulConstant(Procedure&amp;, const Value* other) const override;
</span><ins>+    Value* checkNegConstant(Procedure&amp;) const override;
</ins><span class="cx">     Value* divConstant(Procedure&amp;, const Value* other) const override;
</span><span class="cx">     Value* bitAndConstant(Procedure&amp;, const Value* other) const override;
</span><span class="cx">     Value* bitOrConstant(Procedure&amp;, const Value* other) const override;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Const64Valuecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Const64Value.cpp (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Const64Value.cpp        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/JavaScriptCore/b3/B3Const64Value.cpp        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -98,6 +98,13 @@
</span><span class="cx">     return proc.add&lt;Const64Value&gt;(origin(), result.unsafeGet());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+Value* Const64Value::checkNegConstant(Procedure&amp; proc) const
+{
+    if (m_value == -m_value)
+        return nullptr;
+    return negConstant(proc);
+}
+
</ins><span class="cx"> Value* Const64Value::divConstant(Procedure&amp; proc, const Value* other) const
</span><span class="cx"> {
</span><span class="cx">     if (!other-&gt;hasInt64())
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Const64Valueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Const64Value.h (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Const64Value.h        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/JavaScriptCore/b3/B3Const64Value.h        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -48,6 +48,7 @@
</span><span class="cx">     Value* checkAddConstant(Procedure&amp;, const Value* other) const override;
</span><span class="cx">     Value* checkSubConstant(Procedure&amp;, const Value* other) const override;
</span><span class="cx">     Value* checkMulConstant(Procedure&amp;, const Value* other) const override;
</span><ins>+    Value* checkNegConstant(Procedure&amp;) const override;
</ins><span class="cx">     Value* divConstant(Procedure&amp;, const Value* other) const override;
</span><span class="cx">     Value* bitAndConstant(Procedure&amp;, const Value* other) const override;
</span><span class="cx">     Value* bitOrConstant(Procedure&amp;, const Value* other) const override;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3LowerToAircpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -598,6 +598,10 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        // FIXME: If we're going to use a two-operand instruction, and the operand is commutative, we
+        // should coalesce the result with the operand that is killed.
+        // https://bugs.webkit.org/show_bug.cgi?id=151321
+        
</ins><span class="cx">         append(relaxedMoveForType(m_value-&gt;type()), tmp(left), result);
</span><span class="cx">         append(opcode, tmp(right), result);
</span><span class="cx">     }
</span><span class="lines">@@ -1530,10 +1534,6 @@
</span><span class="cx"> 
</span><span class="cx">         case CheckAdd:
</span><span class="cx">         case CheckSub: {
</span><del>-            // FIXME: Make this support commutativity. That will let us leverage more instruction forms
-            // and it let us commute to maximize coalescing.
-            // https://bugs.webkit.org/show_bug.cgi?id=151214
-
</del><span class="cx">             CheckValue* checkValue = m_value-&gt;as&lt;CheckValue&gt;();
</span><span class="cx"> 
</span><span class="cx">             Value* left = checkValue-&gt;child(0);
</span><span class="lines">@@ -1543,7 +1543,7 @@
</span><span class="cx"> 
</span><span class="cx">             // Handle checked negation.
</span><span class="cx">             if (checkValue-&gt;opcode() == CheckSub &amp;&amp; left-&gt;isInt(0)) {
</span><del>-                append(relaxedMoveForType(checkValue-&gt;type()), tmp(right), result);
</del><ins>+                append(Move, tmp(right), result);
</ins><span class="cx"> 
</span><span class="cx">                 Air::Opcode opcode =
</span><span class="cx">                     opcodeForType(BranchNeg32, BranchNeg64, Air::Oops, checkValue-&gt;type());
</span><span class="lines">@@ -1559,39 +1559,67 @@
</span><span class="cx">                 return;
</span><span class="cx">             }
</span><span class="cx"> 
</span><del>-            append(relaxedMoveForType(m_value-&gt;type()), tmp(left), result);
</del><ins>+            // FIXME: Use commutativity of CheckAdd to increase the likelihood of coalescing.
+            // https://bugs.webkit.org/show_bug.cgi?id=151321
+
+            append(Move, tmp(left), result);
</ins><span class="cx">             
</span><span class="cx">             Air::Opcode opcode = Air::Oops;
</span><del>-            CheckSpecial* special = nullptr;
</del><span class="cx">             switch (m_value-&gt;opcode()) {
</span><span class="cx">             case CheckAdd:
</span><span class="cx">                 opcode = opcodeForType(BranchAdd32, BranchAdd64, Air::Oops, m_value-&gt;type());
</span><del>-                special = ensureCheckSpecial(opcode, 3);
</del><span class="cx">                 break;
</span><span class="cx">             case CheckSub:
</span><span class="cx">                 opcode = opcodeForType(BranchSub32, BranchSub64, Air::Oops, m_value-&gt;type());
</span><del>-                special = ensureCheckSpecial(opcode, 3);
</del><span class="cx">                 break;
</span><span class="cx">             default:
</span><span class="cx">                 RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="cx"> 
</span><del>-            Inst inst(Patch, checkValue, Arg::special(special));
-
-            inst.args.append(Arg::resCond(MacroAssembler::Overflow));
-
</del><span class="cx">             // FIXME: It would be great to fuse Loads into these. We currently don't do it because the
</span><span class="cx">             // rule for stackmaps is that all addresses are just stack addresses. Maybe we could relax
</span><span class="cx">             // this rule here.
</span><span class="cx">             // https://bugs.webkit.org/show_bug.cgi?id=151228
</span><del>-            
</del><ins>+
+            Arg source;
</ins><span class="cx">             if (imm(right) &amp;&amp; isValidForm(opcode, Arg::ResCond, Arg::Imm, Arg::Tmp))
</span><del>-                inst.args.append(imm(right));
</del><ins>+                source = imm(right);
</ins><span class="cx">             else
</span><del>-                inst.args.append(tmp(right));
</del><ins>+                source = tmp(right);
+
+            // There is a really hilarious case that arises when we do BranchAdd32(%x, %x). We won't emit
+            // such code, but the coalescing in our register allocator also does copy propagation, so
+            // although we emit:
+            //
+            //     Move %tmp1, %tmp2
+            //     BranchAdd32 %tmp1, %tmp2
+            //
+            // The register allocator may turn this into:
+            //
+            //     BranchAdd32 %rax, %rax
+            //
+            // Currently we handle this by ensuring that even this kind of addition can be undone. We can
+            // undo it by using the carry flag. It's tempting to get rid of that code and just &quot;fix&quot; this
+            // here by forcing LateUse on the stackmap. If we did that unconditionally, we'd lose a lot of
+            // performance. So it's tempting to do it only if left == right. But that creates an awkward
+            // constraint on Air: it means that Air would not be allowed to do any copy propagation.
+            // Notice that the %rax,%rax situation happened after Air copy-propagated the Move we are
+            // emitting. We know that copy-propagating over that Move causes add-to-self. But what if we
+            // emit something like a Move - or even do other kinds of copy-propagation on tmp's -
+            // somewhere else in this code. The add-to-self situation may only emerge after some other Air
+            // optimizations remove other Move's or identity-like operations. That's why we don't use
+            // LateUse here to take care of add-to-self.
+            
+            CheckSpecial* special = ensureCheckSpecial(opcode, 3);
+            
+            Inst inst(Patch, checkValue, Arg::special(special));
+
+            inst.args.append(Arg::resCond(MacroAssembler::Overflow));
+
+            inst.args.append(source);
</ins><span class="cx">             inst.args.append(result);
</span><del>-            
</del><ins>+
</ins><span class="cx">             fillStackmap(inst, checkValue, 2);
</span><span class="cx"> 
</span><span class="cx">             m_insts.last().append(WTF::move(inst));
</span><span class="lines">@@ -1599,10 +1627,6 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         case CheckMul: {
</span><del>-            // Handle multiplication separately. Multiplication is hard because we have to preserve
-            // both inputs. This requires using three-operand multiplication, even on platforms where
-            // this requires an additional Move.
-
</del><span class="cx">             CheckValue* checkValue = m_value-&gt;as&lt;CheckValue&gt;();
</span><span class="cx"> 
</span><span class="cx">             Value* left = checkValue-&gt;child(0);
</span><span class="lines">@@ -1612,14 +1636,15 @@
</span><span class="cx"> 
</span><span class="cx">             Air::Opcode opcode =
</span><span class="cx">                 opcodeForType(BranchMul32, BranchMul64, Air::Oops, checkValue-&gt;type());
</span><del>-            CheckSpecial* special = ensureCheckSpecial(opcode, 4);
</del><ins>+            CheckSpecial* special = ensureCheckSpecial(opcode, 3, Arg::LateUse);
</ins><span class="cx"> 
</span><span class="cx">             // FIXME: Handle immediates.
</span><span class="cx">             // https://bugs.webkit.org/show_bug.cgi?id=151230
</span><span class="cx"> 
</span><ins>+            append(Move, tmp(left), result);
+
</ins><span class="cx">             Inst inst(Patch, checkValue, Arg::special(special));
</span><span class="cx">             inst.args.append(Arg::resCond(MacroAssembler::Overflow));
</span><del>-            inst.args.append(tmp(left));
</del><span class="cx">             inst.args.append(tmp(right));
</span><span class="cx">             inst.args.append(result);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Opcodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Opcode.h (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Opcode.h        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/JavaScriptCore/b3/B3Opcode.h        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -163,6 +163,10 @@
</span><span class="cx">     // callbacks. Yet, this transformation is valid even if they are different because we know that
</span><span class="cx">     // after the first CheckAdd executes, the second CheckAdd could not have possibly taken slow
</span><span class="cx">     // path. Therefore, the second CheckAdd's callback is irrelevant.
</span><ins>+    //
+    // Note that the first two children of these operations have ValueRep's, both as input constraints and
+    // in the reps provided to the generator. The output constraints could be anything, and should not be
+    // inspected for meaning. If you want to capture the values of the inputs, use stackmap arguments.
</ins><span class="cx">     CheckAdd,
</span><span class="cx">     CheckSub,
</span><span class="cx">     CheckMul,
</span><span class="lines">@@ -170,7 +174,8 @@
</span><span class="cx">     // Check that side-exits. Use the CheckValue class. Like CheckAdd and friends, this has a
</span><span class="cx">     // stackmap with a generation callback. This takes an int argument that this branches on, with
</span><span class="cx">     // full branch fusion in the instruction selector. A true value jumps to the generator's slow
</span><del>-    // path.
</del><ins>+    // path. Note that the predicate child is has both an input and output ValueRep. The input constraint
+    // must be Any, and the output could be anything.
</ins><span class="cx">     Check,
</span><span class="cx"> 
</span><span class="cx">     // SSA support, in the style of DFG SSA.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3PatchpointSpecialcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3PatchpointSpecial.cpp (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3PatchpointSpecial.cpp        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/JavaScriptCore/b3/B3PatchpointSpecial.cpp        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -43,16 +43,18 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void PatchpointSpecial::forEachArg(
-    Inst&amp; inst, const ScopedLambda&lt;Inst::EachArgCallback&gt;&amp; callback)
</del><ins>+void PatchpointSpecial::forEachArg(Inst&amp; inst, const ScopedLambda&lt;Inst::EachArgCallback&gt;&amp; callback)
</ins><span class="cx"> {
</span><ins>+    // FIXME: Allow B3 Patchpoints to specify LateUse.
+    // https://bugs.webkit.org/show_bug.cgi?id=151335
+    
</ins><span class="cx">     if (inst.origin-&gt;type() == Void) {
</span><del>-        forEachArgImpl(0, 1, inst, callback);
</del><ins>+        forEachArgImpl(0, 1, inst, Arg::Use, callback);
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     callback(inst.args[1], Arg::Def, inst.origin-&gt;airType());
</span><del>-    forEachArgImpl(0, 2, inst, callback);
</del><ins>+    forEachArgImpl(0, 2, inst, Arg::Use, callback);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool PatchpointSpecial::isValid(Inst&amp; inst)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3ReduceStrengthcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/JavaScriptCore/b3/B3ReduceStrength.cpp        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -633,18 +633,11 @@
</span><span class="cx">             break;
</span><span class="cx"> 
</span><span class="cx">         case CheckAdd:
</span><del>-            // FIXME: Handle commutativity.
-            // https://bugs.webkit.org/show_bug.cgi?id=151214
-            
</del><span class="cx">             if (replaceWithNewValue(m_value-&gt;child(0)-&gt;checkAddConstant(m_proc, m_value-&gt;child(1))))
</span><span class="cx">                 break;
</span><ins>+
+            handleCommutativity();
</ins><span class="cx">             
</span><del>-            if (m_value-&gt;child(0)-&gt;isInt(0)) {
-                m_value-&gt;replaceWithIdentity(m_value-&gt;child(1));
-                m_changed = true;
-                break;
-            }
-            
</del><span class="cx">             if (m_value-&gt;child(1)-&gt;isInt(0)) {
</span><span class="cx">                 m_value-&gt;replaceWithIdentity(m_value-&gt;child(0));
</span><span class="cx">                 m_changed = true;
</span><span class="lines">@@ -661,30 +654,43 @@
</span><span class="cx">                 m_changed = true;
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><ins>+
+            if (Value* negatedConstant = m_value-&gt;child(1)-&gt;checkNegConstant(m_proc)) {
+                m_insertionSet.insertValue(m_index, negatedConstant);
+                m_value-&gt;as&lt;CheckValue&gt;()-&gt;convertToAdd();
+                m_value-&gt;child(1) = negatedConstant;
+                m_changed = true;
+                break;
+            }
</ins><span class="cx">             break;
</span><span class="cx"> 
</span><span class="cx">         case CheckMul:
</span><del>-            // FIXME: Handle commutativity.
-            // https://bugs.webkit.org/show_bug.cgi?id=151214
-            
</del><span class="cx">             if (replaceWithNewValue(m_value-&gt;child(0)-&gt;checkMulConstant(m_proc, m_value-&gt;child(1))))
</span><span class="cx">                 break;
</span><span class="cx"> 
</span><del>-            if (m_value-&gt;child(0)-&gt;isInt(1)) {
-                m_value-&gt;replaceWithIdentity(m_value-&gt;child(1));
-                m_changed = true;
-                break;
-            }
-            
-            if (m_value-&gt;child(1)-&gt;isInt(1)) {
-                m_value-&gt;replaceWithIdentity(m_value-&gt;child(0));
-                m_changed = true;
-                break;
-            }
</del><ins>+            handleCommutativity();
</ins><span class="cx"> 
</span><del>-            if (m_value-&gt;child(0)-&gt;isInt(0) || m_value-&gt;child(1)-&gt;isInt(0)) {
-                replaceWithNewValue(m_proc.addIntConstant(m_value, 0));
-                break;
</del><ins>+            if (m_value-&gt;child(1)-&gt;hasInt()) {
+                bool modified = true;
+                switch (m_value-&gt;child(1)-&gt;asInt()) {
+                case 0:
+                    replaceWithNewValue(m_proc.addIntConstant(m_value, 0));
+                    break;
+                case 1:
+                    m_value-&gt;replaceWithIdentity(m_value-&gt;child(0));
+                    m_changed = true;
+                    break;
+                case 2:
+                    m_value-&gt;as&lt;CheckValue&gt;()-&gt;convertToAdd();
+                    m_value-&gt;child(1) = m_value-&gt;child(0);
+                    m_changed = true;
+                    break;
+                default:
+                    modified = false;
+                    break;
+                }
+                if (modified)
+                    break;
</ins><span class="cx">             }
</span><span class="cx">             break;
</span><span class="cx"> 
</span><span class="lines">@@ -761,6 +767,10 @@
</span><span class="cx">     // If we decide that value2 coming first is the canonical ordering.
</span><span class="cx">     void handleCommutativity()
</span><span class="cx">     {
</span><ins>+        // Note that we have commutative operations that take more than two children. Those operations may
+        // commute their first two children while leaving the rest unaffected.
+        ASSERT(m_value-&gt;numChildren() &gt;= 2);
+        
</ins><span class="cx">         // Leave it alone if the right child is a constant.
</span><span class="cx">         if (m_value-&gt;child(1)-&gt;isConstant())
</span><span class="cx">             return;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3StackmapSpecialcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3StackmapSpecial.cpp (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3StackmapSpecial.cpp        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/JavaScriptCore/b3/B3StackmapSpecial.cpp        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -65,7 +65,7 @@
</span><span class="cx"> 
</span><span class="cx"> void StackmapSpecial::forEachArgImpl(
</span><span class="cx">     unsigned numIgnoredB3Args, unsigned numIgnoredAirArgs,
</span><del>-    Inst&amp; inst, const ScopedLambda&lt;Inst::EachArgCallback&gt;&amp; callback)
</del><ins>+    Inst&amp; inst, Arg::Role role, const ScopedLambda&lt;Inst::EachArgCallback&gt;&amp; callback)
</ins><span class="cx"> {
</span><span class="cx">     Value* value = inst.origin;
</span><span class="cx"> 
</span><span class="lines">@@ -78,7 +78,7 @@
</span><span class="cx">         Arg&amp; arg = inst.args[i + numIgnoredAirArgs];
</span><span class="cx">         Value* child = value-&gt;child(i + numIgnoredB3Args);
</span><span class="cx"> 
</span><del>-        callback(arg, Arg::Use, Arg::typeForB3Type(child-&gt;type()));
</del><ins>+        callback(arg, role, Arg::typeForB3Type(child-&gt;type()));
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3StackmapSpecialh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3StackmapSpecial.h (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3StackmapSpecial.h        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/JavaScriptCore/b3/B3StackmapSpecial.h        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -28,6 +28,7 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(B3_JIT)
</span><span class="cx"> 
</span><ins>+#include &quot;AirArg.h&quot;
</ins><span class="cx"> #include &quot;AirSpecial.h&quot;
</span><span class="cx"> #include &quot;B3ValueRep.h&quot;
</span><span class="cx"> 
</span><span class="lines">@@ -53,7 +54,7 @@
</span><span class="cx"> 
</span><span class="cx">     void forEachArgImpl(
</span><span class="cx">         unsigned numIgnoredB3Args, unsigned numIgnoredAirArgs,
</span><del>-        Air::Inst&amp;, const ScopedLambda&lt;Air::Inst::EachArgCallback&gt;&amp;);
</del><ins>+        Air::Inst&amp;, Air::Arg::Role role, const ScopedLambda&lt;Air::Inst::EachArgCallback&gt;&amp;);
</ins><span class="cx">     bool isValidImpl(
</span><span class="cx">         unsigned numIgnoredB3Args, unsigned numIgnoredAirArgs,
</span><span class="cx">         Air::Inst&amp;);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3StackmapValuecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3StackmapValue.cpp (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3StackmapValue.cpp        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/JavaScriptCore/b3/B3StackmapValue.cpp        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -48,6 +48,11 @@
</span><span class="cx">     m_reps.append(constrainedValue.rep());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void StackmapValue::appendSomeRegister(Value* value)
+{
+    append(ConstrainedValue(value, ValueRep::SomeRegister));
+}
+
</ins><span class="cx"> void StackmapValue::setConstrainedChild(unsigned index, const ConstrainedValue&amp; constrainedValue)
</span><span class="cx"> {
</span><span class="cx">     child(index) = constrainedValue.value();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3StackmapValueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3StackmapValue.h (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3StackmapValue.h        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/JavaScriptCore/b3/B3StackmapValue.h        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -77,6 +77,10 @@
</span><span class="cx">     // children().append(). That will work fine, but it's not recommended.
</span><span class="cx">     void append(const ConstrainedValue&amp;);
</span><span class="cx"> 
</span><ins>+    // This is a helper for something you might do a lot of: append a value that should be constrained
+    // to SomeRegister.
+    void appendSomeRegister(Value*);
+
</ins><span class="cx">     const Vector&lt;ValueRep&gt;&amp; reps() const { return m_reps; }
</span><span class="cx"> 
</span><span class="cx">     void clobber(const RegisterSet&amp; set)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Validatecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Validate.cpp (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Validate.cpp        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/JavaScriptCore/b3/B3Validate.cpp        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -278,6 +278,8 @@
</span><span class="cx">                 VALIDATE(value-&gt;numChildren() &gt;= 2, (&quot;At &quot;, *value));
</span><span class="cx">                 VALIDATE(isInt(value-&gt;child(0)-&gt;type()), (&quot;At &quot;, *value));
</span><span class="cx">                 VALIDATE(isInt(value-&gt;child(1)-&gt;type()), (&quot;At &quot;, *value));
</span><ins>+                VALIDATE(value-&gt;as&lt;StackmapValue&gt;()-&gt;constrainedChild(0).rep() == ValueRep::Any, (&quot;At &quot;, *value));
+                VALIDATE(value-&gt;as&lt;StackmapValue&gt;()-&gt;constrainedChild(1).rep() == ValueRep::Any, (&quot;At &quot;, *value));
</ins><span class="cx">                 validateStackmap(value);
</span><span class="cx">                 break;
</span><span class="cx">             case Check:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Valuecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Value.cpp (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Value.cpp        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/JavaScriptCore/b3/B3Value.cpp        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -154,6 +154,11 @@
</span><span class="cx">     return nullptr;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+Value* Value::checkNegConstant(Procedure&amp;) const
+{
+    return nullptr;
+}
+
</ins><span class="cx"> Value* Value::divConstant(Procedure&amp;, const Value*) const
</span><span class="cx"> {
</span><span class="cx">     return nullptr;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Valueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Value.h (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Value.h        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/JavaScriptCore/b3/B3Value.h        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -41,6 +41,7 @@
</span><span class="cx"> namespace JSC { namespace B3 {
</span><span class="cx"> 
</span><span class="cx"> class BasicBlock;
</span><ins>+class CheckValue;
</ins><span class="cx"> class Procedure;
</span><span class="cx"> 
</span><span class="cx"> class JS_EXPORT_PRIVATE Value {
</span><span class="lines">@@ -118,6 +119,7 @@
</span><span class="cx">     virtual Value* checkAddConstant(Procedure&amp;, const Value* other) const;
</span><span class="cx">     virtual Value* checkSubConstant(Procedure&amp;, const Value* other) const;
</span><span class="cx">     virtual Value* checkMulConstant(Procedure&amp;, const Value* other) const;
</span><ins>+    virtual Value* checkNegConstant(Procedure&amp;) const;
</ins><span class="cx">     virtual Value* divConstant(Procedure&amp;, const Value* other) const; // This chooses ChillDiv semantics for integers.
</span><span class="cx">     virtual Value* bitAndConstant(Procedure&amp;, const Value* other) const;
</span><span class="cx">     virtual Value* bitOrConstant(Procedure&amp;, const Value* other) const;
</span><span class="lines">@@ -272,6 +274,8 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> private:
</span><ins>+    friend class CheckValue; // CheckValue::convertToAdd() modifies m_opcode.
+    
</ins><span class="cx">     static Type typeFor(Opcode, Value* firstChild);
</span><span class="cx"> 
</span><span class="cx">     // This group of fields is arranged to fit in 64 bits.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirAllocateStackcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirAllocateStack.cpp (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirAllocateStack.cpp        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/JavaScriptCore/b3/air/AirAllocateStack.cpp        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -146,38 +146,22 @@
</span><span class="cx">         auto interfere = [&amp;] (Inst&amp; inst) {
</span><span class="cx">             if (verbose)
</span><span class="cx">                 dataLog(&quot;Interfering: &quot;, pointerListDump(localCalc.live()), &quot;\n&quot;);
</span><del>-            
-            // Form a clique of stack slots that interfere. First find the list of stack slots
-            // that are live right now.
-            slots.resize(0);
-            for (StackSlot* slot : localCalc.live()) {
-                if (slot-&gt;kind() == StackSlotKind::Anonymous)
-                    slots.append(slot);
-            }
</del><span class="cx"> 
</span><del>-            // We mustn't mandate that the input code is optimal. Therefore, it may have dead stores
-            // to the stack. We need to treat these as interfering.
</del><span class="cx">             inst.forEachArg(
</span><span class="cx">                 [&amp;] (Arg&amp; arg, Arg::Role role, Arg::Type) {
</span><del>-                    if (Arg::isDef(role) &amp;&amp; arg.isStack()) {
-                        StackSlot* slot = arg.stackSlot();
-                        if (slot-&gt;kind() == StackSlotKind::Anonymous
-                            &amp;&amp; !localCalc.live().contains(slot))
-                            slots.append(slot);
</del><ins>+                    if (!Arg::isDef(role))
+                        return;
+                    if (!arg.isStack())
+                        return;
+                    StackSlot* slot = arg.stackSlot();
+                    if (slot-&gt;kind() != StackSlotKind::Anonymous)
+                        return;
+
+                    for (StackSlot* otherSlot : localCalc.live()) {
+                        interference[slot].add(otherSlot);
+                        interference[otherSlot].add(slot);
</ins><span class="cx">                     }
</span><span class="cx">                 });
</span><del>-            
-            if (verbose)
-                dataLog(&quot;    Slots: &quot;, pointerListDump(slots), &quot;\n&quot;);
-            for (unsigned i = 0; i &lt; slots.size(); ++i) {
-                StackSlot* outer = slots[i];
-                for (unsigned j = i + 1; j &lt; slots.size(); ++j) {
-                    StackSlot* inner = slots[j];
-
-                    interference[inner].add(outer);
-                    interference[outer].add(inner);
-                }
-            }
</del><span class="cx">         };
</span><span class="cx"> 
</span><span class="cx">         for (unsigned instIndex = block-&gt;size(); instIndex--;) {
</span><span class="lines">@@ -185,7 +169,7 @@
</span><span class="cx">                 dataLog(&quot;Analyzing: &quot;, block-&gt;at(instIndex), &quot;\n&quot;);
</span><span class="cx">             Inst&amp; inst = block-&gt;at(instIndex);
</span><span class="cx">             interfere(inst);
</span><del>-            localCalc.execute(inst);
</del><ins>+            localCalc.execute(instIndex);
</ins><span class="cx">         }
</span><span class="cx">         Inst nop;
</span><span class="cx">         interfere(nop);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirArgcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirArg.cpp (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirArg.cpp        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/JavaScriptCore/b3/air/AirArg.cpp        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -181,6 +181,9 @@
</span><span class="cx">     case Arg::UseAddr:
</span><span class="cx">         out.print(&quot;UseAddr&quot;);
</span><span class="cx">         return;
</span><ins>+    case Arg::LateUse:
+        out.print(&quot;LateUse&quot;);
+        return;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     RELEASE_ASSERT_NOT_REACHED();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirArgh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirArg.h (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirArg.h        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/JavaScriptCore/b3/air/AirArg.h        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -83,6 +83,10 @@
</span><span class="cx">         // always escaping, and Stack is presumed to be always escaping if it's Locked.
</span><span class="cx">         Use,
</span><span class="cx"> 
</span><ins>+        // LateUse means that the Inst will read from this value after doing its Def's. Note that LateUse
+        // on an Addr or Index still means Use on the internal temporaries.
+        LateUse,
+
</ins><span class="cx">         // Def means that the Inst will write to this value after doing everything else.
</span><span class="cx">         //
</span><span class="cx">         // For Tmp: The Inst will write to this Tmp.
</span><span class="lines">@@ -123,12 +127,13 @@
</span><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     // Returns true if the Role implies that the Inst will Use the Arg. It's deliberately false for
</span><del>-    // UseAddr, since isUse() for an Arg::addr means that we are loading from the address.
-    static bool isUse(Role role)
</del><ins>+    // UseAddr, since isAnyUse() for an Arg::addr means that we are loading from the address.
+    static bool isAnyUse(Role role)
</ins><span class="cx">     {
</span><span class="cx">         switch (role) {
</span><span class="cx">         case Use:
</span><span class="cx">         case UseDef:
</span><ins>+        case LateUse:
</ins><span class="cx">             return true;
</span><span class="cx">         case Def:
</span><span class="cx">         case UseAddr:
</span><span class="lines">@@ -136,12 +141,33 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    // Returns true if the Role implies that the Inst will Use the Arg before doing anything else.
+    static bool isEarlyUse(Role role)
+    {
+        switch (role) {
+        case Use:
+        case UseDef:
+            return true;
+        case Def:
+        case UseAddr:
+        case LateUse:
+            return false;
+        }
+    }
+
+    // Returns true if the Role implies that the Inst will Use the Arg after doing everything else.
+    static bool isLateUse(Role role)
+    {
+        return role == LateUse;
+    }
+
</ins><span class="cx">     // Returns true if the Role implies that the Inst will Def the Arg.
</span><span class="cx">     static bool isDef(Role role)
</span><span class="cx">     {
</span><span class="cx">         switch (role) {
</span><span class="cx">         case Use:
</span><span class="cx">         case UseAddr:
</span><ins>+        case LateUse:
</ins><span class="cx">             return false;
</span><span class="cx">         case Def:
</span><span class="cx">         case UseDef:
</span><span class="lines">@@ -666,7 +692,7 @@
</span><span class="cx">     {
</span><span class="cx">         switch (m_kind) {
</span><span class="cx">         case Tmp:
</span><del>-            ASSERT(isUse(argRole) || isDef(argRole));
</del><ins>+            ASSERT(isAnyUse(argRole) || isDef(argRole));
</ins><span class="cx">             functor(m_base, argRole, argType);
</span><span class="cx">             break;
</span><span class="cx">         case Addr:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirGeneratecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirGenerate.cpp (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirGenerate.cpp        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/JavaScriptCore/b3/air/AirGenerate.cpp        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -72,7 +72,10 @@
</span><span class="cx">     // After this phase, every Tmp has a reg.
</span><span class="cx">     //
</span><span class="cx">     // For debugging, you can use spillEverything() to put everything to the stack between each Inst.
</span><del>-    iteratedRegisterCoalescing(code);
</del><ins>+    if (false)
+        spillEverything(code);
+    else
+        iteratedRegisterCoalescing(code);
</ins><span class="cx"> 
</span><span class="cx">     // Prior to this point the prologue and epilogue is implicit. This makes it explicit. It also
</span><span class="cx">     // does things like identify which callee-saves we're using and saves them.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirIteratedRegisterCoalescingcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirIteratedRegisterCoalescing.cpp (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirIteratedRegisterCoalescing.cpp        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/JavaScriptCore/b3/air/AirIteratedRegisterCoalescing.cpp        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -34,12 +34,14 @@
</span><span class="cx"> #include &quot;AirLiveness.h&quot;
</span><span class="cx"> #include &quot;AirPhaseScope.h&quot;
</span><span class="cx"> #include &quot;AirRegisterPriority.h&quot;
</span><ins>+#include &lt;wtf/ListDump.h&gt;
</ins><span class="cx"> #include &lt;wtf/ListHashSet.h&gt;
</span><span class="cx"> 
</span><span class="cx"> namespace JSC { namespace B3 { namespace Air {
</span><span class="cx"> 
</span><span class="cx"> static bool debug = false;
</span><span class="cx"> static bool traceDebug = false;
</span><ins>+static bool reportStats = false;
</ins><span class="cx"> 
</span><span class="cx"> template&lt;Arg::Type type&gt;
</span><span class="cx"> struct MoveInstHelper;
</span><span class="lines">@@ -168,7 +170,7 @@
</span><span class="cx">                 if (Arg::isDef(role))
</span><span class="cx">                     defTmp = argTmp;
</span><span class="cx">                 else {
</span><del>-                    ASSERT(Arg::isUse(role));
</del><ins>+                    ASSERT(Arg::isEarlyUse(role));
</ins><span class="cx">                     useTmp = argTmp;
</span><span class="cx">                 }
</span><span class="cx">             });
</span><span class="lines">@@ -204,6 +206,7 @@
</span><span class="cx">         makeWorkList();
</span><span class="cx"> 
</span><span class="cx">         if (debug) {
</span><ins>+            dataLog(&quot;Interference: &quot;, listDump(m_interferenceEdges), &quot;\n&quot;);
</ins><span class="cx">             dumpInterferenceGraphInDot(WTF::dataFile());
</span><span class="cx">             dataLog(&quot;Initial work list\n&quot;);
</span><span class="cx">             dumpWorkLists(WTF::dataFile());
</span><span class="lines">@@ -742,6 +745,11 @@
</span><span class="cx">             return WTF::IntHash&lt;uint64_t&gt;::hash(m_value);
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        void dump(PrintStream&amp; out) const
+        {
+            out.print(first(), &quot;&lt;=&gt;&quot;, second());
+        }
+
</ins><span class="cx">     private:
</span><span class="cx">         uint64_t m_value { 0 };
</span><span class="cx">     };
</span><span class="lines">@@ -951,7 +959,7 @@
</span><span class="cx">                 Arg arg = Arg::stack(stackSlotEntry-&gt;value);
</span><span class="cx">                 Opcode move = type == Arg::GP ? Move : MoveDouble;
</span><span class="cx"> 
</span><del>-                if (Arg::isUse(role)) {
</del><ins>+                if (Arg::isAnyUse(role)) {
</ins><span class="cx">                     Tmp newTmp = code.newTmp(type);
</span><span class="cx">                     insertionSet.insert(instIndex, move, inst.origin, arg, newTmp);
</span><span class="cx">                     tmp = newTmp;
</span><span class="lines">@@ -968,9 +976,10 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;Arg::Type type&gt;
</span><del>-static void iteratedRegisterCoalescingOnType(Code&amp; code, HashSet&lt;Tmp&gt;&amp; unspillableTmps)
</del><ins>+static void iteratedRegisterCoalescingOnType(Code&amp; code, HashSet&lt;Tmp&gt;&amp; unspillableTmps, unsigned&amp; numIterations)
</ins><span class="cx"> {
</span><span class="cx">     while (true) {
</span><ins>+        numIterations++;
</ins><span class="cx">         IteratedRegisterCoalescingAllocator&lt;type&gt; allocator(code, unspillableTmps);
</span><span class="cx">         Liveness&lt;Tmp&gt; liveness(code);
</span><span class="cx">         for (BasicBlock* block : code) {
</span><span class="lines">@@ -978,7 +987,7 @@
</span><span class="cx">             for (unsigned instIndex = block-&gt;size(); instIndex--;) {
</span><span class="cx">                 Inst&amp; inst = block-&gt;at(instIndex);
</span><span class="cx">                 allocator.build(inst, localCalc);
</span><del>-                localCalc.execute(inst);
</del><ins>+                localCalc.execute(instIndex);
</ins><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -997,12 +1006,14 @@
</span><span class="cx"> 
</span><span class="cx">     bool gpIsColored = false;
</span><span class="cx">     bool fpIsColored = false;
</span><ins>+    unsigned numIterations = 0;
</ins><span class="cx"> 
</span><span class="cx">     HashSet&lt;Tmp&gt; unspillableGPs;
</span><span class="cx">     HashSet&lt;Tmp&gt; unspillableFPs;
</span><span class="cx"> 
</span><span class="cx">     // First we run both allocator together as long as they both spill.
</span><span class="cx">     while (!gpIsColored &amp;&amp; !fpIsColored) {
</span><ins>+        numIterations++;
</ins><span class="cx">         IteratedRegisterCoalescingAllocator&lt;Arg::GP&gt; gpAllocator(code, unspillableGPs);
</span><span class="cx">         IteratedRegisterCoalescingAllocator&lt;Arg::FP&gt; fpAllocator(code, unspillableFPs);
</span><span class="cx"> 
</span><span class="lines">@@ -1017,7 +1028,7 @@
</span><span class="cx">                 gpAllocator.build(inst, localCalc);
</span><span class="cx">                 fpAllocator.build(inst, localCalc);
</span><span class="cx"> 
</span><del>-                localCalc.execute(inst);
</del><ins>+                localCalc.execute(instIndex);
</ins><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -1038,9 +1049,12 @@
</span><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     if (!gpIsColored)
</span><del>-        iteratedRegisterCoalescingOnType&lt;Arg::GP&gt;(code, unspillableGPs);
</del><ins>+        iteratedRegisterCoalescingOnType&lt;Arg::GP&gt;(code, unspillableGPs, numIterations);
</ins><span class="cx">     if (!fpIsColored)
</span><del>-        iteratedRegisterCoalescingOnType&lt;Arg::FP&gt;(code, unspillableFPs);
</del><ins>+        iteratedRegisterCoalescingOnType&lt;Arg::FP&gt;(code, unspillableFPs, numIterations);
+
+    if (reportStats)
+        dataLog(&quot;Num iterations = &quot;, numIterations, &quot;\n&quot;);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } } } // namespace JSC::B3::Air
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirLivenessh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirLiveness.h (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirLiveness.h        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/JavaScriptCore/b3/air/AirLiveness.h        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -49,6 +49,16 @@
</span><span class="cx">         m_liveAtHead.resize(code.size());
</span><span class="cx">         m_liveAtTail.resize(code.size());
</span><span class="cx"> 
</span><ins>+        // The liveAtTail of each block automatically contains the LateUse's of the terminal.
+        for (BasicBlock* block : code) {
+            HashSet&lt;Thing&gt;&amp; live = m_liveAtTail[block];
+            block-&gt;last().forEach&lt;Thing&gt;(
+                [&amp;] (Thing&amp; thing, Arg::Role role, Arg::Type) {
+                    if (Arg::isLateUse(role))
+                        live.add(thing);
+                });
+        }
+
</ins><span class="cx">         IndexSet&lt;BasicBlock&gt; seen;
</span><span class="cx"> 
</span><span class="cx">         bool changed = true;
</span><span class="lines">@@ -61,7 +71,7 @@
</span><span class="cx">                     continue;
</span><span class="cx">                 LocalCalc localCalc(*this, block);
</span><span class="cx">                 for (size_t instIndex = block-&gt;size(); instIndex--;)
</span><del>-                    localCalc.execute(block-&gt;at(instIndex));
</del><ins>+                    localCalc.execute(instIndex);
</ins><span class="cx">                 bool firstTime = seen.add(block);
</span><span class="cx">                 if (!firstTime &amp;&amp; localCalc.live() == m_liveAtHead[block])
</span><span class="cx">                     continue;
</span><span class="lines">@@ -90,14 +100,17 @@
</span><span class="cx">     public:
</span><span class="cx">         LocalCalc(Liveness&amp; liveness, BasicBlock* block)
</span><span class="cx">             : m_live(liveness.liveAtTail(block))
</span><ins>+            , m_block(block)
</ins><span class="cx">         {
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         const HashSet&lt;Thing&gt;&amp; live() const { return m_live; }
</span><span class="cx">         HashSet&lt;Thing&gt;&amp;&amp; takeLive() { return WTF::move(m_live); }
</span><span class="cx"> 
</span><del>-        void execute(Inst&amp; inst)
</del><ins>+        void execute(unsigned instIndex)
</ins><span class="cx">         {
</span><ins>+            Inst&amp; inst = m_block-&gt;at(instIndex);
+            
</ins><span class="cx">             // First handle def's.
</span><span class="cx">             inst.forEach&lt;Thing&gt;(
</span><span class="cx">                 [this] (Thing&amp; arg, Arg::Role role, Arg::Type) {
</span><span class="lines">@@ -107,20 +120,34 @@
</span><span class="cx">                         m_live.remove(arg);
</span><span class="cx">                 });
</span><span class="cx"> 
</span><del>-            // Finally handle use's.
</del><ins>+            // Then handle use's.
</ins><span class="cx">             inst.forEach&lt;Thing&gt;(
</span><span class="cx">                 [this] (Thing&amp; arg, Arg::Role role, Arg::Type) {
</span><span class="cx">                     if (!isAlive(arg))
</span><span class="cx">                         return;
</span><del>-                    if (Arg::isUse(role))
</del><ins>+                    if (Arg::isEarlyUse(role))
</ins><span class="cx">                         m_live.add(arg);
</span><span class="cx">                 });
</span><ins>+
+            // And finally, handle the late use's of the previous instruction.
+            if (instIndex) {
+                Inst&amp; prevInst = m_block-&gt;at(instIndex - 1);
+
+                prevInst.forEach&lt;Thing&gt;(
+                    [this] (Thing&amp; arg, Arg::Role role, Arg::Type) {
+                        if (!Arg::isLateUse(role))
+                            return;
+                        if (isAlive(arg))
+                            m_live.add(arg);
+                    });
+            }
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">     private:
</span><span class="cx">         HashSet&lt;Thing&gt; m_live;
</span><ins>+        BasicBlock* m_block;
</ins><span class="cx">     };
</span><del>-    
</del><ins>+
</ins><span class="cx"> private:
</span><span class="cx">     IndexMap&lt;BasicBlock, HashSet&lt;Thing&gt;&gt; m_liveAtHead;
</span><span class="cx">     IndexMap&lt;BasicBlock, HashSet&lt;Thing&gt;&gt; m_liveAtTail;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirOpcodeopcodes"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -331,15 +331,9 @@
</span><span class="cx">     ResCond, Tmp, Tmp
</span><span class="cx">     ResCond, Addr, Tmp
</span><span class="cx"> 
</span><del>-BranchMul32 U:G, U:G, U:G, D:G /branch
-    ResCond, Tmp, Tmp, Tmp
-
</del><span class="cx"> BranchMul64 U:G, U:G, UD:G /branch
</span><span class="cx">     ResCond, Tmp, Tmp
</span><span class="cx"> 
</span><del>-BranchMul64 U:G, U:G, U:G, D:G /branch
-    ResCond, Tmp, Tmp, Tmp
-
</del><span class="cx"> BranchSub32 U:G, U:G, UD:G /branch
</span><span class="cx">     ResCond, Tmp, Tmp
</span><span class="cx">     ResCond, Imm, Tmp
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirReportUsedRegisterscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirReportUsedRegisters.cpp (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirReportUsedRegisters.cpp        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/JavaScriptCore/b3/air/AirReportUsedRegisters.cpp        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -56,7 +56,7 @@
</span><span class="cx">                 }
</span><span class="cx">                 inst.reportUsedRegisters(registerSet);
</span><span class="cx">             }
</span><del>-            localCalc.execute(inst);
</del><ins>+            localCalc.execute(instIndex);
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirSpillEverythingcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirSpillEverything.cpp (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirSpillEverything.cpp        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/JavaScriptCore/b3/air/AirSpillEverything.cpp        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -69,7 +69,7 @@
</span><span class="cx">         for (unsigned instIndex = block-&gt;size(); instIndex--;) {
</span><span class="cx">             Inst&amp; inst = block-&gt;at(instIndex);
</span><span class="cx">             setUsedRegisters(instIndex + 1, inst);
</span><del>-            localCalc.execute(inst);
</del><ins>+            localCalc.execute(instIndex);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         Inst nop;
</span><span class="lines">@@ -140,6 +140,7 @@
</span><span class="cx">                         }
</span><span class="cx">                         break;
</span><span class="cx">                     case Arg::UseDef:
</span><ins>+                    case Arg::LateUse:
</ins><span class="cx">                         for (Reg reg : regsInPriorityOrder(type)) {
</span><span class="cx">                             if (!setBefore.get(reg) &amp;&amp; !setAfter.get(reg)) {
</span><span class="cx">                                 setAfter.set(reg);
</span><span class="lines">@@ -160,7 +161,7 @@
</span><span class="cx"> 
</span><span class="cx">                     Opcode move = type == Arg::GP ? Move : MoveDouble;
</span><span class="cx"> 
</span><del>-                    if (Arg::isUse(role)) {
</del><ins>+                    if (Arg::isAnyUse(role)) {
</ins><span class="cx">                         insertionSet.insert(
</span><span class="cx">                             instIndex, move, inst.origin, arg, tmp);
</span><span class="cx">                     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3testb3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/testb3.cpp (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/testb3.cpp        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/JavaScriptCore/b3/testb3.cpp        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -297,7 +297,8 @@
</span><span class="cx"> {
</span><span class="cx">     Procedure proc;
</span><span class="cx">     BasicBlock* root = proc.addBlock();
</span><del>-    Value* value = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0);
</del><ins>+    Value* value = root-&gt;appendNew&lt;Value&gt;(
+        proc, Trunc, Origin(), root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0));
</ins><span class="cx">     root-&gt;appendNew&lt;ControlValue&gt;(
</span><span class="cx">         proc, Return, Origin(),
</span><span class="cx">         root-&gt;appendNew&lt;Value&gt;(proc, Mul, Origin(), value, value));
</span><span class="lines">@@ -305,6 +306,51 @@
</span><span class="cx">     CHECK(compileAndRun&lt;int&gt;(proc, a) == a * a);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void testMulArgStore(int a)
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    int mulSlot;
+    int valueSlot;
+    
+    Value* value = root-&gt;appendNew&lt;Value&gt;(
+        proc, Trunc, Origin(),
+        root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* mul = root-&gt;appendNew&lt;Value&gt;(proc, Mul, Origin(), value, value);
+
+    root-&gt;appendNew&lt;MemoryValue&gt;(
+        proc, Store, Origin(), value,
+        root-&gt;appendNew&lt;ConstPtrValue&gt;(proc, Origin(), &amp;valueSlot));
+    root-&gt;appendNew&lt;MemoryValue&gt;(
+        proc, Store, Origin(), mul,
+        root-&gt;appendNew&lt;ConstPtrValue&gt;(proc, Origin(), &amp;mulSlot));
+
+    root-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(), root-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), 0));
+
+    CHECK(!compileAndRun&lt;int&gt;(proc, a));
+    CHECK(mulSlot == a * a);
+    CHECK(valueSlot == a);
+}
+
+void testMulAddArg(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(),
+            root-&gt;appendNew&lt;Value&gt;(proc, Mul, Origin(), value, value),
+            value));
+
+    CHECK(compileAndRun&lt;int&gt;(proc, a) == a * a + a);
+}
+
</ins><span class="cx"> void testMulArgs(int a, int b)
</span><span class="cx"> {
</span><span class="cx">     Procedure proc;
</span><span class="lines">@@ -2754,9 +2800,9 @@
</span><span class="cx">     for (unsigned i = 0; i &lt; numConstructs; ++i) {
</span><span class="cx">         if (i &amp; 1) {
</span><span class="cx">             // Control flow diamond.
</span><del>-            unsigned predicateVarIndex = (i &gt;&gt; 1) % numVars;
-            unsigned thenIncVarIndex = ((i &gt;&gt; 1) + 1) % numVars;
-            unsigned elseIncVarIndex = ((i &gt;&gt; 1) + 2) % numVars;
</del><ins>+            unsigned predicateVarIndex = ((i &gt;&gt; 1) + 2) % numVars;
+            unsigned thenIncVarIndex = ((i &gt;&gt; 1) + 0) % numVars;
+            unsigned elseIncVarIndex = ((i &gt;&gt; 1) + 1) % numVars;
</ins><span class="cx"> 
</span><span class="cx">             BasicBlock* thenBlock = proc.addBlock();
</span><span class="cx">             BasicBlock* elseBlock = proc.addBlock();
</span><span class="lines">@@ -2801,7 +2847,7 @@
</span><span class="cx">             BasicBlock* loopSkip = proc.addBlock();
</span><span class="cx">             BasicBlock* continuation = proc.addBlock();
</span><span class="cx">             
</span><del>-            Value* startIndex = vars[(i &gt;&gt; 1) % numVars];
</del><ins>+            Value* startIndex = vars[((i &gt;&gt; 1) + 1) % numVars];
</ins><span class="cx">             Value* startSum = current-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), 0);
</span><span class="cx">             current-&gt;appendNew&lt;ControlValue&gt;(
</span><span class="cx">                 proc, Branch, Origin(), startIndex,
</span><span class="lines">@@ -2855,7 +2901,7 @@
</span><span class="cx">             skipSum-&gt;setPhi(finalSum);
</span><span class="cx"> 
</span><span class="cx">             current = continuation;
</span><del>-            vars[((i &gt;&gt; 1) + 1) % numVars] = finalSum;
</del><ins>+            vars[((i &gt;&gt; 1) + 0) % numVars] = finalSum;
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -3183,8 +3229,6 @@
</span><span class="cx">     check-&gt;setGenerator(
</span><span class="cx">         [&amp;] (CCallHelpers&amp; jit, const StackmapGenerationParams&amp; params) {
</span><span class="cx">             CHECK(params.reps.size() == 1);
</span><del>-            CHECK(params.reps[0].isConstant());
-            CHECK(params.reps[0].value() == 1);
</del><span class="cx"> 
</span><span class="cx">             // This should always work because a function this simple should never have callee
</span><span class="cx">             // saves.
</span><span class="lines">@@ -3216,8 +3260,6 @@
</span><span class="cx">     check-&gt;setGenerator(
</span><span class="cx">         [&amp;] (CCallHelpers&amp; jit, const StackmapGenerationParams&amp; params) {
</span><span class="cx">             CHECK(params.reps.size() == 1);
</span><del>-            CHECK(params.reps[0].isConstant());
-            CHECK(params.reps[0].value() == 1);
</del><span class="cx"> 
</span><span class="cx">             // This should always work because a function this simple should never have callee
</span><span class="cx">             // saves.
</span><span class="lines">@@ -3263,8 +3305,6 @@
</span><span class="cx">     check-&gt;setGenerator(
</span><span class="cx">         [&amp;] (CCallHelpers&amp; jit, const StackmapGenerationParams&amp; params) {
</span><span class="cx">             CHECK(params.reps.size() == 1);
</span><del>-            CHECK(params.reps[0].isConstant());
-            CHECK(params.reps[0].value() == 1);
</del><span class="cx"> 
</span><span class="cx">             // This should always work because a function this simple should never have callee
</span><span class="cx">             // saves.
</span><span class="lines">@@ -3299,14 +3339,15 @@
</span><span class="cx">         root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0));
</span><span class="cx">     Value* arg2 = root-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), 42);
</span><span class="cx">     CheckValue* checkAdd = root-&gt;appendNew&lt;CheckValue&gt;(proc, CheckAdd, Origin(), arg1, arg2);
</span><ins>+    checkAdd-&gt;append(arg1);
+    checkAdd-&gt;append(arg2);
</ins><span class="cx">     checkAdd-&gt;setGenerator(
</span><span class="cx">         [&amp;] (CCallHelpers&amp; jit, const StackmapGenerationParams&amp; params) {
</span><del>-            CHECK(params.reps.size() == 2);
-            CHECK(params.reps[0].isGPR());
-            CHECK(params.reps[1].isConstant());
-            CHECK(params.reps[1].value() == 42);
-            jit.sub32(CCallHelpers::TrustedImm32(42), params.reps[0].gpr());
-            jit.convertInt32ToDouble(params.reps[0].gpr(), FPRInfo::fpRegT0);
</del><ins>+            CHECK(params.reps.size() == 4);
+            CHECK(params.reps[2].isGPR());
+            CHECK(params.reps[3].isConstant());
+            CHECK(params.reps[3].value() == 42);
+            jit.convertInt32ToDouble(params.reps[2].gpr(), FPRInfo::fpRegT0);
</ins><span class="cx">             jit.convertInt32ToDouble(CCallHelpers::TrustedImm32(42), FPRInfo::fpRegT1);
</span><span class="cx">             jit.addDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
</span><span class="cx">             jit.emitFunctionEpilogue();
</span><span class="lines">@@ -3324,6 +3365,75 @@
</span><span class="cx">     CHECK(invoke&lt;double&gt;(*code, 2147483647) == 2147483689.0);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void testCheckAddImmCommute()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* arg1 = root-&gt;appendNew&lt;Value&gt;(
+        proc, Trunc, Origin(),
+        root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* arg2 = root-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), 42);
+    CheckValue* checkAdd = root-&gt;appendNew&lt;CheckValue&gt;(proc, CheckAdd, Origin(), arg2, arg1);
+    checkAdd-&gt;append(arg1);
+    checkAdd-&gt;append(arg2);
+    checkAdd-&gt;setGenerator(
+        [&amp;] (CCallHelpers&amp; jit, const StackmapGenerationParams&amp; params) {
+            CHECK(params.reps.size() == 4);
+            CHECK(params.reps[2].isGPR());
+            CHECK(params.reps[3].isConstant());
+            CHECK(params.reps[3].value() == 42);
+            jit.convertInt32ToDouble(params.reps[2].gpr(), FPRInfo::fpRegT0);
+            jit.convertInt32ToDouble(CCallHelpers::TrustedImm32(42), FPRInfo::fpRegT1);
+            jit.addDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+            jit.emitFunctionEpilogue();
+            jit.ret();
+        });
+    root-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(proc, IToD, Origin(), checkAdd));
+
+    auto code = compile(proc);
+
+    CHECK(invoke&lt;double&gt;(*code, 0) == 42.0);
+    CHECK(invoke&lt;double&gt;(*code, 1) == 43.0);
+    CHECK(invoke&lt;double&gt;(*code, 42) == 84.0);
+    CHECK(invoke&lt;double&gt;(*code, 2147483647) == 2147483689.0);
+}
+
+void testCheckAddImmSomeRegister()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* arg1 = root-&gt;appendNew&lt;Value&gt;(
+        proc, Trunc, Origin(),
+        root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* arg2 = root-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), 42);
+    CheckValue* checkAdd = root-&gt;appendNew&lt;CheckValue&gt;(proc, CheckAdd, Origin(), arg1, arg2);
+    checkAdd-&gt;appendSomeRegister(arg1);
+    checkAdd-&gt;appendSomeRegister(arg2);
+    checkAdd-&gt;setGenerator(
+        [&amp;] (CCallHelpers&amp; jit, const StackmapGenerationParams&amp; params) {
+            CHECK(params.reps.size() == 4);
+            CHECK(params.reps[2].isGPR());
+            CHECK(params.reps[3].isGPR());
+            jit.convertInt32ToDouble(params.reps[2].gpr(), FPRInfo::fpRegT0);
+            jit.convertInt32ToDouble(params.reps[3].gpr(), FPRInfo::fpRegT1);
+            jit.addDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+            jit.emitFunctionEpilogue();
+            jit.ret();
+        });
+    root-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(proc, IToD, Origin(), checkAdd));
+
+    auto code = compile(proc);
+
+    CHECK(invoke&lt;double&gt;(*code, 0) == 42.0);
+    CHECK(invoke&lt;double&gt;(*code, 1) == 43.0);
+    CHECK(invoke&lt;double&gt;(*code, 42) == 84.0);
+    CHECK(invoke&lt;double&gt;(*code, 2147483647) == 2147483689.0);
+}
+
</ins><span class="cx"> void testCheckAdd()
</span><span class="cx"> {
</span><span class="cx">     Procedure proc;
</span><span class="lines">@@ -3335,14 +3445,15 @@
</span><span class="cx">         proc, Trunc, Origin(),
</span><span class="cx">         root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1));
</span><span class="cx">     CheckValue* checkAdd = root-&gt;appendNew&lt;CheckValue&gt;(proc, CheckAdd, Origin(), arg1, arg2);
</span><ins>+    checkAdd-&gt;appendSomeRegister(arg1);
+    checkAdd-&gt;appendSomeRegister(arg2);
</ins><span class="cx">     checkAdd-&gt;setGenerator(
</span><span class="cx">         [&amp;] (CCallHelpers&amp; jit, const StackmapGenerationParams&amp; params) {
</span><del>-            CHECK(params.reps.size() == 2);
-            CHECK(params.reps[0].isGPR());
-            CHECK(params.reps[1].isGPR());
-            jit.sub32(params.reps[1].gpr(), params.reps[0].gpr());
-            jit.convertInt32ToDouble(params.reps[0].gpr(), FPRInfo::fpRegT0);
-            jit.convertInt32ToDouble(params.reps[1].gpr(), FPRInfo::fpRegT1);
</del><ins>+            CHECK(params.reps.size() == 4);
+            CHECK(params.reps[2].isGPR());
+            CHECK(params.reps[3].isGPR());
+            jit.convertInt32ToDouble(params.reps[2].gpr(), FPRInfo::fpRegT0);
+            jit.convertInt32ToDouble(params.reps[3].gpr(), FPRInfo::fpRegT1);
</ins><span class="cx">             jit.addDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
</span><span class="cx">             jit.emitFunctionEpilogue();
</span><span class="cx">             jit.ret();
</span><span class="lines">@@ -3366,14 +3477,15 @@
</span><span class="cx">     Value* arg1 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0);
</span><span class="cx">     Value* arg2 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1);
</span><span class="cx">     CheckValue* checkAdd = root-&gt;appendNew&lt;CheckValue&gt;(proc, CheckAdd, Origin(), arg1, arg2);
</span><ins>+    checkAdd-&gt;appendSomeRegister(arg1);
+    checkAdd-&gt;appendSomeRegister(arg2);
</ins><span class="cx">     checkAdd-&gt;setGenerator(
</span><span class="cx">         [&amp;] (CCallHelpers&amp; jit, const StackmapGenerationParams&amp; params) {
</span><del>-            CHECK(params.reps.size() == 2);
-            CHECK(params.reps[0].isGPR());
-            CHECK(params.reps[1].isGPR());
-            jit.sub64(params.reps[1].gpr(), params.reps[0].gpr());
-            jit.convertInt64ToDouble(params.reps[0].gpr(), FPRInfo::fpRegT0);
-            jit.convertInt64ToDouble(params.reps[1].gpr(), FPRInfo::fpRegT1);
</del><ins>+            CHECK(params.reps.size() == 4);
+            CHECK(params.reps[2].isGPR());
+            CHECK(params.reps[3].isGPR());
+            jit.convertInt64ToDouble(params.reps[2].gpr(), FPRInfo::fpRegT0);
+            jit.convertInt64ToDouble(params.reps[3].gpr(), FPRInfo::fpRegT1);
</ins><span class="cx">             jit.addDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
</span><span class="cx">             jit.emitFunctionEpilogue();
</span><span class="cx">             jit.ret();
</span><span class="lines">@@ -3437,14 +3549,15 @@
</span><span class="cx">         root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0));
</span><span class="cx">     Value* arg2 = root-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), 42);
</span><span class="cx">     CheckValue* checkSub = root-&gt;appendNew&lt;CheckValue&gt;(proc, CheckSub, Origin(), arg1, arg2);
</span><ins>+    checkSub-&gt;append(arg1);
+    checkSub-&gt;append(arg2);
</ins><span class="cx">     checkSub-&gt;setGenerator(
</span><span class="cx">         [&amp;] (CCallHelpers&amp; jit, const StackmapGenerationParams&amp; params) {
</span><del>-            CHECK(params.reps.size() == 2);
-            CHECK(params.reps[0].isGPR());
-            CHECK(params.reps[1].isConstant());
-            CHECK(params.reps[1].value() == 42);
-            jit.add32(CCallHelpers::TrustedImm32(42), params.reps[0].gpr());
-            jit.convertInt32ToDouble(params.reps[0].gpr(), FPRInfo::fpRegT0);
</del><ins>+            CHECK(params.reps.size() == 4);
+            CHECK(params.reps[2].isGPR());
+            CHECK(params.reps[3].isConstant());
+            CHECK(params.reps[3].value() == 42);
+            jit.convertInt32ToDouble(params.reps[2].gpr(), FPRInfo::fpRegT0);
</ins><span class="cx">             jit.convertInt32ToDouble(CCallHelpers::TrustedImm32(42), FPRInfo::fpRegT1);
</span><span class="cx">             jit.subDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
</span><span class="cx">             jit.emitFunctionEpilogue();
</span><span class="lines">@@ -3462,6 +3575,42 @@
</span><span class="cx">     CHECK(invoke&lt;double&gt;(*code, -2147483647) == -2147483689.0);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void testCheckSubBadImm()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* arg1 = root-&gt;appendNew&lt;Value&gt;(
+        proc, Trunc, Origin(),
+        root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0));
+    int32_t badImm = std::numeric_limits&lt;int&gt;::min();
+    Value* arg2 = root-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), badImm);
+    CheckValue* checkSub = root-&gt;appendNew&lt;CheckValue&gt;(proc, CheckSub, Origin(), arg1, arg2);
+    checkSub-&gt;append(arg1);
+    checkSub-&gt;append(arg2);
+    checkSub-&gt;setGenerator(
+        [&amp;] (CCallHelpers&amp; jit, const StackmapGenerationParams&amp; params) {
+            CHECK(params.reps.size() == 4);
+            CHECK(params.reps[2].isGPR());
+            CHECK(params.reps[3].isConstant());
+            CHECK(params.reps[3].value() == badImm);
+            jit.convertInt32ToDouble(params.reps[2].gpr(), FPRInfo::fpRegT0);
+            jit.convertInt32ToDouble(CCallHelpers::TrustedImm32(badImm), FPRInfo::fpRegT1);
+            jit.subDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+            jit.emitFunctionEpilogue();
+            jit.ret();
+        });
+    root-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(proc, IToD, Origin(), checkSub));
+
+    auto code = compile(proc);
+
+    CHECK(invoke&lt;double&gt;(*code, 0) == -static_cast&lt;double&gt;(badImm));
+    CHECK(invoke&lt;double&gt;(*code, -1) == -static_cast&lt;double&gt;(badImm) - 1);
+    CHECK(invoke&lt;double&gt;(*code, 1) == -static_cast&lt;double&gt;(badImm) + 1);
+    CHECK(invoke&lt;double&gt;(*code, 42) == -static_cast&lt;double&gt;(badImm) + 42);
+}
+
</ins><span class="cx"> void testCheckSub()
</span><span class="cx"> {
</span><span class="cx">     Procedure proc;
</span><span class="lines">@@ -3473,14 +3622,15 @@
</span><span class="cx">         proc, Trunc, Origin(),
</span><span class="cx">         root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1));
</span><span class="cx">     CheckValue* checkSub = root-&gt;appendNew&lt;CheckValue&gt;(proc, CheckSub, Origin(), arg1, arg2);
</span><ins>+    checkSub-&gt;append(arg1);
+    checkSub-&gt;append(arg2);
</ins><span class="cx">     checkSub-&gt;setGenerator(
</span><span class="cx">         [&amp;] (CCallHelpers&amp; jit, const StackmapGenerationParams&amp; params) {
</span><del>-            CHECK(params.reps.size() == 2);
-            CHECK(params.reps[0].isGPR());
-            CHECK(params.reps[1].isGPR());
-            jit.add32(params.reps[1].gpr(), params.reps[0].gpr());
-            jit.convertInt32ToDouble(params.reps[0].gpr(), FPRInfo::fpRegT0);
-            jit.convertInt32ToDouble(params.reps[1].gpr(), FPRInfo::fpRegT1);
</del><ins>+            CHECK(params.reps.size() == 4);
+            CHECK(params.reps[2].isGPR());
+            CHECK(params.reps[3].isGPR());
+            jit.convertInt32ToDouble(params.reps[2].gpr(), FPRInfo::fpRegT0);
+            jit.convertInt32ToDouble(params.reps[3].gpr(), FPRInfo::fpRegT1);
</ins><span class="cx">             jit.subDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
</span><span class="cx">             jit.emitFunctionEpilogue();
</span><span class="cx">             jit.ret();
</span><span class="lines">@@ -3509,14 +3659,15 @@
</span><span class="cx">     Value* arg1 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0);
</span><span class="cx">     Value* arg2 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1);
</span><span class="cx">     CheckValue* checkSub = root-&gt;appendNew&lt;CheckValue&gt;(proc, CheckSub, Origin(), arg1, arg2);
</span><ins>+    checkSub-&gt;append(arg1);
+    checkSub-&gt;append(arg2);
</ins><span class="cx">     checkSub-&gt;setGenerator(
</span><span class="cx">         [&amp;] (CCallHelpers&amp; jit, const StackmapGenerationParams&amp; params) {
</span><del>-            CHECK(params.reps.size() == 2);
-            CHECK(params.reps[0].isGPR());
-            CHECK(params.reps[1].isGPR());
-            jit.add64(params.reps[1].gpr(), params.reps[0].gpr());
-            jit.convertInt64ToDouble(params.reps[0].gpr(), FPRInfo::fpRegT0);
-            jit.convertInt64ToDouble(params.reps[1].gpr(), FPRInfo::fpRegT1);
</del><ins>+            CHECK(params.reps.size() == 4);
+            CHECK(params.reps[2].isGPR());
+            CHECK(params.reps[3].isGPR());
+            jit.convertInt64ToDouble(params.reps[2].gpr(), FPRInfo::fpRegT0);
+            jit.convertInt64ToDouble(params.reps[3].gpr(), FPRInfo::fpRegT1);
</ins><span class="cx">             jit.subDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
</span><span class="cx">             jit.emitFunctionEpilogue();
</span><span class="cx">             jit.ret();
</span><span class="lines">@@ -3580,13 +3731,12 @@
</span><span class="cx">         proc, Trunc, Origin(),
</span><span class="cx">         root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0));
</span><span class="cx">     CheckValue* checkNeg = root-&gt;appendNew&lt;CheckValue&gt;(proc, CheckSub, Origin(), arg1, arg2);
</span><ins>+    checkNeg-&gt;append(arg2);
</ins><span class="cx">     checkNeg-&gt;setGenerator(
</span><span class="cx">         [&amp;] (CCallHelpers&amp; jit, const StackmapGenerationParams&amp; params) {
</span><del>-            CHECK(params.reps.size() == 2);
-            CHECK(params.reps[0] == ValueRep::constant(0));
-            CHECK(params.reps[1].isGPR());
-            jit.neg32(params.reps[1].gpr());
-            jit.convertInt32ToDouble(params.reps[1].gpr(), FPRInfo::fpRegT1);
</del><ins>+            CHECK(params.reps.size() == 3);
+            CHECK(params.reps[2].isGPR());
+            jit.convertInt32ToDouble(params.reps[2].gpr(), FPRInfo::fpRegT1);
</ins><span class="cx">             jit.negateDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
</span><span class="cx">             jit.emitFunctionEpilogue();
</span><span class="cx">             jit.ret();
</span><span class="lines">@@ -3610,13 +3760,12 @@
</span><span class="cx">     Value* arg1 = root-&gt;appendNew&lt;Const64Value&gt;(proc, Origin(), 0);
</span><span class="cx">     Value* arg2 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0);
</span><span class="cx">     CheckValue* checkNeg = root-&gt;appendNew&lt;CheckValue&gt;(proc, CheckSub, Origin(), arg1, arg2);
</span><ins>+    checkNeg-&gt;append(arg2);
</ins><span class="cx">     checkNeg-&gt;setGenerator(
</span><span class="cx">         [&amp;] (CCallHelpers&amp; jit, const StackmapGenerationParams&amp; params) {
</span><del>-            CHECK(params.reps.size() == 2);
-            CHECK(params.reps[0] == ValueRep::constant(0));
-            CHECK(params.reps[1].isGPR());
-            jit.neg64(params.reps[1].gpr());
-            jit.convertInt64ToDouble(params.reps[1].gpr(), FPRInfo::fpRegT1);
</del><ins>+            CHECK(params.reps.size() == 3);
+            CHECK(params.reps[2].isGPR());
+            jit.convertInt64ToDouble(params.reps[2].gpr(), FPRInfo::fpRegT1);
</ins><span class="cx">             jit.negateDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
</span><span class="cx">             jit.emitFunctionEpilogue();
</span><span class="cx">             jit.ret();
</span><span class="lines">@@ -3644,13 +3793,15 @@
</span><span class="cx">         proc, Trunc, Origin(),
</span><span class="cx">         root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1));
</span><span class="cx">     CheckValue* checkMul = root-&gt;appendNew&lt;CheckValue&gt;(proc, CheckMul, Origin(), arg1, arg2);
</span><ins>+    checkMul-&gt;append(arg1);
+    checkMul-&gt;append(arg2);
</ins><span class="cx">     checkMul-&gt;setGenerator(
</span><span class="cx">         [&amp;] (CCallHelpers&amp; jit, const StackmapGenerationParams&amp; params) {
</span><del>-            CHECK(params.reps.size() == 2);
-            CHECK(params.reps[0].isGPR());
-            CHECK(params.reps[1].isGPR());
-            jit.convertInt32ToDouble(params.reps[0].gpr(), FPRInfo::fpRegT0);
-            jit.convertInt32ToDouble(params.reps[1].gpr(), FPRInfo::fpRegT1);
</del><ins>+            CHECK(params.reps.size() == 4);
+            CHECK(params.reps[2].isGPR());
+            CHECK(params.reps[3].isGPR());
+            jit.convertInt32ToDouble(params.reps[2].gpr(), FPRInfo::fpRegT0);
+            jit.convertInt32ToDouble(params.reps[3].gpr(), FPRInfo::fpRegT1);
</ins><span class="cx">             jit.mulDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
</span><span class="cx">             jit.emitFunctionEpilogue();
</span><span class="cx">             jit.ret();
</span><span class="lines">@@ -3667,6 +3818,92 @@
</span><span class="cx">     CHECK(invoke&lt;double&gt;(*code, 2147483647, 42) == 2147483647.0 * 42.0);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void testCheckMulMemory()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+
+    int left;
+    int right;
+    
+    Value* arg1 = root-&gt;appendNew&lt;MemoryValue&gt;(
+        proc, Load, Int32, Origin(),
+        root-&gt;appendNew&lt;ConstPtrValue&gt;(proc, Origin(), &amp;left));
+    Value* arg2 = root-&gt;appendNew&lt;MemoryValue&gt;(
+        proc, Load, Int32, Origin(),
+        root-&gt;appendNew&lt;ConstPtrValue&gt;(proc, Origin(), &amp;right));
+    CheckValue* checkMul = root-&gt;appendNew&lt;CheckValue&gt;(proc, CheckMul, Origin(), arg1, arg2);
+    checkMul-&gt;append(arg1);
+    checkMul-&gt;append(arg2);
+    checkMul-&gt;setGenerator(
+        [&amp;] (CCallHelpers&amp; jit, const StackmapGenerationParams&amp; params) {
+            CHECK(params.reps.size() == 4);
+            CHECK(params.reps[2].isGPR());
+            CHECK(params.reps[3].isGPR());
+            jit.convertInt32ToDouble(params.reps[2].gpr(), FPRInfo::fpRegT0);
+            jit.convertInt32ToDouble(params.reps[3].gpr(), FPRInfo::fpRegT1);
+            jit.mulDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+            jit.emitFunctionEpilogue();
+            jit.ret();
+        });
+    root-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(proc, IToD, Origin(), checkMul));
+
+    auto code = compile(proc);
+
+    left = 0;
+    right = 42;
+    CHECK(invoke&lt;double&gt;(*code) == 0.0);
+    
+    left = 1;
+    right = 42;
+    CHECK(invoke&lt;double&gt;(*code) == 42.0);
+
+    left = 42;
+    right = 42;
+    CHECK(invoke&lt;double&gt;(*code) == 42.0 * 42.0);
+
+    left = 2147483647;
+    right = 42;
+    CHECK(invoke&lt;double&gt;(*code) == 2147483647.0 * 42.0);
+}
+
+void testCheckMul2()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* arg1 = root-&gt;appendNew&lt;Value&gt;(
+        proc, Trunc, Origin(),
+        root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0));
+    Value* arg2 = root-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), 2);
+    CheckValue* checkMul = root-&gt;appendNew&lt;CheckValue&gt;(proc, CheckMul, Origin(), arg1, arg2);
+    checkMul-&gt;append(arg1);
+    checkMul-&gt;append(arg2);
+    checkMul-&gt;setGenerator(
+        [&amp;] (CCallHelpers&amp; jit, const StackmapGenerationParams&amp; params) {
+            CHECK(params.reps.size() == 4);
+            CHECK(params.reps[2].isGPR());
+            CHECK(params.reps[3].isConstant());
+            CHECK(params.reps[3].value() == 2);
+            jit.convertInt32ToDouble(params.reps[2].gpr(), FPRInfo::fpRegT0);
+            jit.convertInt32ToDouble(CCallHelpers::TrustedImm32(2), FPRInfo::fpRegT1);
+            jit.mulDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
+            jit.emitFunctionEpilogue();
+            jit.ret();
+        });
+    root-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(proc, IToD, Origin(), checkMul));
+
+    auto code = compile(proc);
+
+    CHECK(invoke&lt;double&gt;(*code, 0) == 0.0);
+    CHECK(invoke&lt;double&gt;(*code, 1) == 2.0);
+    CHECK(invoke&lt;double&gt;(*code, 42) == 42.0 * 2.0);
+    CHECK(invoke&lt;double&gt;(*code, 2147483647) == 2147483647.0 * 2.0);
+}
+
</ins><span class="cx"> void testCheckMul64()
</span><span class="cx"> {
</span><span class="cx">     Procedure proc;
</span><span class="lines">@@ -3674,13 +3911,15 @@
</span><span class="cx">     Value* arg1 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0);
</span><span class="cx">     Value* arg2 = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1);
</span><span class="cx">     CheckValue* checkMul = root-&gt;appendNew&lt;CheckValue&gt;(proc, CheckMul, Origin(), arg1, arg2);
</span><ins>+    checkMul-&gt;append(arg1);
+    checkMul-&gt;append(arg2);
</ins><span class="cx">     checkMul-&gt;setGenerator(
</span><span class="cx">         [&amp;] (CCallHelpers&amp; jit, const StackmapGenerationParams&amp; params) {
</span><del>-            CHECK(params.reps.size() == 2);
-            CHECK(params.reps[0].isGPR());
-            CHECK(params.reps[1].isGPR());
-            jit.convertInt64ToDouble(params.reps[0].gpr(), FPRInfo::fpRegT0);
-            jit.convertInt64ToDouble(params.reps[1].gpr(), FPRInfo::fpRegT1);
</del><ins>+            CHECK(params.reps.size() == 4);
+            CHECK(params.reps[2].isGPR());
+            CHECK(params.reps[3].isGPR());
+            jit.convertInt64ToDouble(params.reps[2].gpr(), FPRInfo::fpRegT0);
+            jit.convertInt64ToDouble(params.reps[3].gpr(), FPRInfo::fpRegT1);
</ins><span class="cx">             jit.mulDouble(FPRInfo::fpRegT1, FPRInfo::fpRegT0);
</span><span class="cx">             jit.emitFunctionEpilogue();
</span><span class="cx">             jit.ret();
</span><span class="lines">@@ -4425,6 +4664,10 @@
</span><span class="cx">     RUN(testAddImmsDouble(negativeZero(), negativeZero()));
</span><span class="cx"> 
</span><span class="cx">     RUN(testMulArg(5));
</span><ins>+    RUN(testMulAddArg(5));
+    RUN(testMulAddArg(85));
+    RUN(testMulArgStore(5));
+    RUN(testMulArgStore(85));
</ins><span class="cx">     RUN(testMulArgs(1, 1));
</span><span class="cx">     RUN(testMulArgs(1, 2));
</span><span class="cx">     RUN(testMulArgs(3, 3));
</span><span class="lines">@@ -4880,11 +5123,14 @@
</span><span class="cx">     RUN(testCheckLessThan());
</span><span class="cx">     RUN(testCheckMegaCombo());
</span><span class="cx">     RUN(testCheckAddImm());
</span><ins>+    RUN(testCheckAddImmCommute());
+    RUN(testCheckAddImmSomeRegister());
</ins><span class="cx">     RUN(testCheckAdd());
</span><span class="cx">     RUN(testCheckAdd64());
</span><span class="cx">     RUN(testCheckAddFold(100, 200));
</span><span class="cx">     RUN(testCheckAddFoldFail(2147483647, 100));
</span><span class="cx">     RUN(testCheckSubImm());
</span><ins>+    RUN(testCheckSubBadImm());
</ins><span class="cx">     RUN(testCheckSub());
</span><span class="cx">     RUN(testCheckSub64());
</span><span class="cx">     RUN(testCheckSubFold(100, 200));
</span><span class="lines">@@ -4892,6 +5138,8 @@
</span><span class="cx">     RUN(testCheckNeg());
</span><span class="cx">     RUN(testCheckNeg64());
</span><span class="cx">     RUN(testCheckMul());
</span><ins>+    RUN(testCheckMulMemory());
+    RUN(testCheckMul2());
</ins><span class="cx">     RUN(testCheckMul64());
</span><span class="cx">     RUN(testCheckMulFold(100, 200));
</span><span class="cx">     RUN(testCheckMulFoldFail(2147483647, 100));
</span></span></pre></div>
<a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/WTF/ChangeLog        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -1,5 +1,18 @@
</span><span class="cx"> 2015-11-17  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        CheckAdd/Mul should have commutativity optimizations in B3-&gt;Air lowering
+        https://bugs.webkit.org/show_bug.cgi?id=151214
+
+        Reviewed by Geoffrey Garen.
+
+        Disable my failed attempts at perfect forwarding, since they were incorrect, and caused compile
+        errors if you tried to pass an argument that bound to lvalue. This shouldn't affect performance of
+        anything we care about, and performance tests seem to confirm that it's all good.
+
+        * wtf/ScopedLambda.h:
+
+2015-11-17  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
</ins><span class="cx">         Air should lay out code optimally
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=150478
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWTFwtfScopedLambdah"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/ScopedLambda.h (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/ScopedLambda.h        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Source/WTF/wtf/ScopedLambda.h        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -44,19 +44,20 @@
</span><span class="cx"> template&lt;typename ResultType, typename... ArgumentTypes&gt;
</span><span class="cx"> class ScopedLambda&lt;ResultType (ArgumentTypes...)&gt; {
</span><span class="cx"> public:
</span><del>-    ScopedLambda(ResultType (*impl)(void* arg, ArgumentTypes&amp;&amp;...) = nullptr, void* arg = nullptr)
</del><ins>+    ScopedLambda(ResultType (*impl)(void* arg, ArgumentTypes...) = nullptr, void* arg = nullptr)
</ins><span class="cx">         : m_impl(impl)
</span><span class="cx">         , m_arg(arg)
</span><span class="cx">     {
</span><span class="cx">     }
</span><del>-    
-    ResultType operator()(ArgumentTypes&amp;&amp;... arguments) const
</del><ins>+
+    template&lt;typename... PassedArgumentTypes&gt;
+    ResultType operator()(PassedArgumentTypes&amp;&amp;... arguments) const
</ins><span class="cx">     {
</span><del>-        return m_impl(m_arg, std::forward&lt;ArgumentTypes&gt;(arguments)...);
</del><ins>+        return m_impl(m_arg, std::forward&lt;PassedArgumentTypes&gt;(arguments)...);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    ResultType (*m_impl)(void* arg, ArgumentTypes&amp;&amp;...);
</del><ins>+    ResultType (*m_impl)(void* arg, ArgumentTypes...);
</ins><span class="cx">     void *m_arg;
</span><span class="cx"> };
</span><span class="cx"> 
</span><span class="lines">@@ -72,10 +73,9 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    static ResultType implFunction(void* argument, ArgumentTypes&amp;&amp;... arguments)
</del><ins>+    static ResultType implFunction(void* argument, ArgumentTypes... arguments)
</ins><span class="cx">     {
</span><del>-        return static_cast&lt;ScopedLambdaFunctor*&gt;(argument)-&gt;m_functor(
-            std::forward&lt;ArgumentTypes&gt;(arguments)...);
</del><ins>+        return static_cast&lt;ScopedLambdaFunctor*&gt;(argument)-&gt;m_functor(arguments...);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     Functor m_functor;
</span></span></pre></div>
<a id="trunkToolsReducedFTLComplexTestcpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ReducedFTL/ComplexTest.cpp (192539 => 192540)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ReducedFTL/ComplexTest.cpp        2015-11-17 22:29:54 UTC (rev 192539)
+++ trunk/Tools/ReducedFTL/ComplexTest.cpp        2015-11-17 22:31:40 UTC (rev 192540)
</span><span class="lines">@@ -102,9 +102,9 @@
</span><span class="cx">     for (unsigned i = 0; i &lt; numConstructs; ++i) {
</span><span class="cx">         if (i &amp; 1) {
</span><span class="cx">             // Control flow diamond.
</span><del>-            unsigned predicateVarIndex = (i &gt;&gt; 1) % numVars;
-            unsigned thenIncVarIndex = ((i &gt;&gt; 1) + 1) % numVars;
-            unsigned elseIncVarIndex = ((i &gt;&gt; 1) + 2) % numVars;
</del><ins>+            unsigned predicateVarIndex = ((i &gt;&gt; 1) + 2) % numVars;
+            unsigned thenIncVarIndex = ((i &gt;&gt; 1) + 0) % numVars;
+            unsigned elseIncVarIndex = ((i &gt;&gt; 1) + 1) % numVars;
</ins><span class="cx"> 
</span><span class="cx">             BasicBlock* thenBlock = BasicBlock::Create(context, &quot;&quot;, function);
</span><span class="cx">             BasicBlock* elseBlock = BasicBlock::Create(context, &quot;&quot;, function);
</span><span class="lines">@@ -138,7 +138,7 @@
</span><span class="cx">             BasicBlock* loopBody = BasicBlock::Create(context, &quot;&quot;, function);
</span><span class="cx">             BasicBlock* continuation = BasicBlock::Create(context, &quot;&quot;, function);
</span><span class="cx"> 
</span><del>-            Value* startIndex = vars[(i &gt;&gt; 1) % numVars];
</del><ins>+            Value* startIndex = vars[((i &gt;&gt; 1) + 1) % numVars];
</ins><span class="cx">             Value* startSum = builder-&gt;getInt32(0);
</span><span class="cx">             builder-&gt;CreateCondBr(
</span><span class="cx">                 builder-&gt;CreateICmpNE(startIndex, builder-&gt;getInt32(0)),
</span><span class="lines">@@ -176,6 +176,7 @@
</span><span class="cx">             finalSum-&gt;addIncoming(startSum, current);
</span><span class="cx">             finalSum-&gt;addIncoming(newBodySum, loopBody);
</span><span class="cx">             current = continuation;
</span><ins>+            vars[((i &gt;&gt; 1) + 0) % numVars] = finalSum;
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>