<!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>[194331] trunk/Source/JavaScriptCore</title>
</head>
<body>

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

<h3>Log Message</h3>
<pre>B3-&gt;Air lowering incorrectly copy-propagates over ZExt32's
https://bugs.webkit.org/show_bug.cgi?id=152365

Reviewed by Benjamin Poulain.

The instruction selector thinks that Value's that return Int32's are going to always be lowered
to instructions that zero-extend the destination. But this isn't actually true. If you have an
Add32 with a destination on the stack (i.e. spilled) then it only writes 4 bytes. Then, the
filler will load 8 bytes from the stack at the point of use. So, the use of the Add32 will see
garbage in the high bits.

The fact that the spiller chose to use 8 bytes for a Tmp that gets defined by an Add32 is a
pretty sad bug, but:

- It's entirely up to the spiller to decide how many bytes to use for a Tmp, since we do not
  ascribe a type to Tmps. We could ascribe types to Tmps, but then coalescing would become
  harder. Our goal is to fix the bug while still enabling coalescing in cases like &quot;a[i]&quot; where
  &quot;i&quot; is a 32-bit integer that is computed using operations that already do zero-extension.

- More broadly, it's strange that the instruction selector decides whether a Value will be
  lowered to something that zero-extends. That's too constraining, since the most optimal
  instruction selection might involve something that doesn't zero-extend in cases of spilling, so
  the zero-extension should only happen if it's actually needed. This means that we need to
  understand which Air instructions cause zero-extensions.

- If we know which Air instructions cause zero-extensions, then we don't need the instruction
  selector to copy-propagate ZExt32's. We have copy-propagation in Air thanks to the register
  allocator.

In fact, the register allocator is exactly where all of the pieces come together. It's there that
we want to know which operations zero-extend and which don't. It also wants to know how many bits
of a Tmp each instruction reads. Armed with that information, the register allocator can emit
more optimal spill code, use less stack space for spill slots, and coalesce Move32's. As a bonus,
on X86, it replaces Move's with Move32's whenever it can. On X86, Move32 is cheaper.

This fixes a crash bug in V8/encrypt. After fixing this, I only needed two minor fixes to get
V8/encrypt to run. We're about 10% behind LLVM on steady state throughput on this test. It
appears to be mostly due to excessive spilling caused by CCall slow paths. That's fixable: we
could make CCalls on slow paths use a variant of CCallSpecial that promises not to clobber any
registers, and then have it emit spill code around the call itself. LLVM probably gets this
optimization from its live range splitting.

I tried writing a regression test. The problem is that you need garbage on the stack for this to
work, and I didn't feel like writing a flaky test. It appears that running V8/encrypt will cover
this, so we do have coverage.

* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* assembler/AbstractMacroAssembler.h:
(JSC::isX86):
(JSC::isX86_64):
(JSC::optimizeForARMv7IDIVSupported):
(JSC::optimizeForX86):
(JSC::optimizeForX86_64):
* b3/B3LowerToAir.cpp:
(JSC::B3::Air::LowerToAir::highBitsAreZero):
(JSC::B3::Air::LowerToAir::shouldCopyPropagate):
(JSC::B3::Air::LowerToAir::lower):
* b3/B3PatchpointSpecial.cpp:
(JSC::B3::PatchpointSpecial::forEachArg):
* b3/B3StackmapSpecial.cpp:
(JSC::B3::StackmapSpecial::forEachArgImpl):
* 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::pointerWidth):
(JSC::B3::Air::Arg::isAnyUse):
(JSC::B3::Air::Arg::isColdUse):
(JSC::B3::Air::Arg::isEarlyUse):
(JSC::B3::Air::Arg::isDef):
(JSC::B3::Air::Arg::isZDef):
(JSC::B3::Air::Arg::widthForB3Type):
(JSC::B3::Air::Arg::conservativeWidth):
(JSC::B3::Air::Arg::minimumWidth):
(JSC::B3::Air::Arg::bytes):
(JSC::B3::Air::Arg::widthForBytes):
(JSC::B3::Air::Arg::Arg):
(JSC::B3::Air::Arg::forEachTmp):
* b3/air/AirCCallSpecial.cpp:
(JSC::B3::Air::CCallSpecial::forEachArg):
* b3/air/AirEliminateDeadCode.cpp:
(JSC::B3::Air::eliminateDeadCode):
* b3/air/AirFixPartialRegisterStalls.cpp:
(JSC::B3::Air::fixPartialRegisterStalls):
* b3/air/AirInst.cpp:
(JSC::B3::Air::Inst::hasArgEffects):
* b3/air/AirInst.h:
(JSC::B3::Air::Inst::forEachTmpFast):
(JSC::B3::Air::Inst::forEachTmp):
* b3/air/AirInstInlines.h:
(JSC::B3::Air::Inst::forEachTmpWithExtraClobberedRegs):
* b3/air/AirIteratedRegisterCoalescing.cpp:
* b3/air/AirLiveness.h:
(JSC::B3::Air::AbstractLiveness::AbstractLiveness):
(JSC::B3::Air::AbstractLiveness::LocalCalc::execute):
* b3/air/AirOpcode.opcodes:
* b3/air/AirSpillEverything.cpp:
(JSC::B3::Air::spillEverything):
* b3/air/AirTmpWidth.cpp: Added.
(JSC::B3::Air::TmpWidth::TmpWidth):
(JSC::B3::Air::TmpWidth::~TmpWidth):
* b3/air/AirTmpWidth.h: Added.
(JSC::B3::Air::TmpWidth::width):
(JSC::B3::Air::TmpWidth::defWidth):
(JSC::B3::Air::TmpWidth::useWidth):
(JSC::B3::Air::TmpWidth::Widths::Widths):
* b3/air/AirUseCounts.h:
(JSC::B3::Air::UseCounts::UseCounts):
* b3/air/opcode_generator.rb:
* b3/testb3.cpp:
(JSC::B3::testCheckMegaCombo):
(JSC::B3::testCheckTrickyMegaCombo):
(JSC::B3::testCheckTwoMegaCombos):
(JSC::B3::run):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreCMakeListstxt">trunk/Source/JavaScriptCore/CMakeLists.txt</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj">trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerAbstractMacroAssemblerh">trunk/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3LowerToAircpp">trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3PatchpointSpecialcpp">trunk/Source/JavaScriptCore/b3/B3PatchpointSpecial.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3StackmapSpecialcpp">trunk/Source/JavaScriptCore/b3/B3StackmapSpecial.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="#trunkSourceJavaScriptCoreb3airAirCCallSpecialcpp">trunk/Source/JavaScriptCore/b3/air/AirCCallSpecial.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirEliminateDeadCodecpp">trunk/Source/JavaScriptCore/b3/air/AirEliminateDeadCode.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirFixPartialRegisterStallscpp">trunk/Source/JavaScriptCore/b3/air/AirFixPartialRegisterStalls.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirInstcpp">trunk/Source/JavaScriptCore/b3/air/AirInst.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirInsth">trunk/Source/JavaScriptCore/b3/air/AirInst.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirInstInlinesh">trunk/Source/JavaScriptCore/b3/air/AirInstInlines.h</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="#trunkSourceJavaScriptCoreb3airAirOptimizeBlockOrdercpp">trunk/Source/JavaScriptCore/b3/air/AirOptimizeBlockOrder.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirSpillEverythingcpp">trunk/Source/JavaScriptCore/b3/air/AirSpillEverything.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirUseCountsh">trunk/Source/JavaScriptCore/b3/air/AirUseCounts.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airopcode_generatorrb">trunk/Source/JavaScriptCore/b3/air/opcode_generator.rb</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3testb3cpp">trunk/Source/JavaScriptCore/b3/testb3.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp">trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLOSRExitHandlecpp">trunk/Source/JavaScriptCore/ftl/FTLOSRExitHandle.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreb3airAirTmpWidthcpp">trunk/Source/JavaScriptCore/b3/air/AirTmpWidth.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirTmpWidthh">trunk/Source/JavaScriptCore/b3/air/AirTmpWidth.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreCMakeListstxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/CMakeLists.txt (194330 => 194331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/CMakeLists.txt        2015-12-21 15:16:58 UTC (rev 194330)
+++ trunk/Source/JavaScriptCore/CMakeLists.txt        2015-12-21 16:16:01 UTC (rev 194331)
</span><span class="lines">@@ -90,6 +90,7 @@
</span><span class="cx">     b3/air/AirSpillEverything.cpp
</span><span class="cx">     b3/air/AirStackSlot.cpp
</span><span class="cx">     b3/air/AirTmp.cpp
</span><ins>+    b3/air/AirTmpWidth.cpp
</ins><span class="cx">     b3/air/AirValidate.cpp
</span><span class="cx"> 
</span><span class="cx">     b3/B3ArgumentRegValue.cpp
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (194330 => 194331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-12-21 15:16:58 UTC (rev 194330)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-12-21 16:16:01 UTC (rev 194331)
</span><span class="lines">@@ -1,3 +1,123 @@
</span><ins>+2015-12-21  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        B3-&gt;Air lowering incorrectly copy-propagates over ZExt32's
+        https://bugs.webkit.org/show_bug.cgi?id=152365
+
+        Reviewed by Benjamin Poulain.
+
+        The instruction selector thinks that Value's that return Int32's are going to always be lowered
+        to instructions that zero-extend the destination. But this isn't actually true. If you have an
+        Add32 with a destination on the stack (i.e. spilled) then it only writes 4 bytes. Then, the
+        filler will load 8 bytes from the stack at the point of use. So, the use of the Add32 will see
+        garbage in the high bits.
+
+        The fact that the spiller chose to use 8 bytes for a Tmp that gets defined by an Add32 is a
+        pretty sad bug, but:
+
+        - It's entirely up to the spiller to decide how many bytes to use for a Tmp, since we do not
+          ascribe a type to Tmps. We could ascribe types to Tmps, but then coalescing would become
+          harder. Our goal is to fix the bug while still enabling coalescing in cases like &quot;a[i]&quot; where
+          &quot;i&quot; is a 32-bit integer that is computed using operations that already do zero-extension.
+
+        - More broadly, it's strange that the instruction selector decides whether a Value will be
+          lowered to something that zero-extends. That's too constraining, since the most optimal
+          instruction selection might involve something that doesn't zero-extend in cases of spilling, so
+          the zero-extension should only happen if it's actually needed. This means that we need to
+          understand which Air instructions cause zero-extensions.
+
+        - If we know which Air instructions cause zero-extensions, then we don't need the instruction
+          selector to copy-propagate ZExt32's. We have copy-propagation in Air thanks to the register
+          allocator.
+
+        In fact, the register allocator is exactly where all of the pieces come together. It's there that
+        we want to know which operations zero-extend and which don't. It also wants to know how many bits
+        of a Tmp each instruction reads. Armed with that information, the register allocator can emit
+        more optimal spill code, use less stack space for spill slots, and coalesce Move32's. As a bonus,
+        on X86, it replaces Move's with Move32's whenever it can. On X86, Move32 is cheaper.
+
+        This fixes a crash bug in V8/encrypt. After fixing this, I only needed two minor fixes to get
+        V8/encrypt to run. We're about 10% behind LLVM on steady state throughput on this test. It
+        appears to be mostly due to excessive spilling caused by CCall slow paths. That's fixable: we
+        could make CCalls on slow paths use a variant of CCallSpecial that promises not to clobber any
+        registers, and then have it emit spill code around the call itself. LLVM probably gets this
+        optimization from its live range splitting.
+
+        I tried writing a regression test. The problem is that you need garbage on the stack for this to
+        work, and I didn't feel like writing a flaky test. It appears that running V8/encrypt will cover
+        this, so we do have coverage.
+
+        * CMakeLists.txt:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * assembler/AbstractMacroAssembler.h:
+        (JSC::isX86):
+        (JSC::isX86_64):
+        (JSC::optimizeForARMv7IDIVSupported):
+        (JSC::optimizeForX86):
+        (JSC::optimizeForX86_64):
+        * b3/B3LowerToAir.cpp:
+        (JSC::B3::Air::LowerToAir::highBitsAreZero):
+        (JSC::B3::Air::LowerToAir::shouldCopyPropagate):
+        (JSC::B3::Air::LowerToAir::lower):
+        * b3/B3PatchpointSpecial.cpp:
+        (JSC::B3::PatchpointSpecial::forEachArg):
+        * b3/B3StackmapSpecial.cpp:
+        (JSC::B3::StackmapSpecial::forEachArgImpl):
+        * 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::pointerWidth):
+        (JSC::B3::Air::Arg::isAnyUse):
+        (JSC::B3::Air::Arg::isColdUse):
+        (JSC::B3::Air::Arg::isEarlyUse):
+        (JSC::B3::Air::Arg::isDef):
+        (JSC::B3::Air::Arg::isZDef):
+        (JSC::B3::Air::Arg::widthForB3Type):
+        (JSC::B3::Air::Arg::conservativeWidth):
+        (JSC::B3::Air::Arg::minimumWidth):
+        (JSC::B3::Air::Arg::bytes):
+        (JSC::B3::Air::Arg::widthForBytes):
+        (JSC::B3::Air::Arg::Arg):
+        (JSC::B3::Air::Arg::forEachTmp):
+        * b3/air/AirCCallSpecial.cpp:
+        (JSC::B3::Air::CCallSpecial::forEachArg):
+        * b3/air/AirEliminateDeadCode.cpp:
+        (JSC::B3::Air::eliminateDeadCode):
+        * b3/air/AirFixPartialRegisterStalls.cpp:
+        (JSC::B3::Air::fixPartialRegisterStalls):
+        * b3/air/AirInst.cpp:
+        (JSC::B3::Air::Inst::hasArgEffects):
+        * b3/air/AirInst.h:
+        (JSC::B3::Air::Inst::forEachTmpFast):
+        (JSC::B3::Air::Inst::forEachTmp):
+        * b3/air/AirInstInlines.h:
+        (JSC::B3::Air::Inst::forEachTmpWithExtraClobberedRegs):
+        * b3/air/AirIteratedRegisterCoalescing.cpp:
+        * b3/air/AirLiveness.h:
+        (JSC::B3::Air::AbstractLiveness::AbstractLiveness):
+        (JSC::B3::Air::AbstractLiveness::LocalCalc::execute):
+        * b3/air/AirOpcode.opcodes:
+        * b3/air/AirSpillEverything.cpp:
+        (JSC::B3::Air::spillEverything):
+        * b3/air/AirTmpWidth.cpp: Added.
+        (JSC::B3::Air::TmpWidth::TmpWidth):
+        (JSC::B3::Air::TmpWidth::~TmpWidth):
+        * b3/air/AirTmpWidth.h: Added.
+        (JSC::B3::Air::TmpWidth::width):
+        (JSC::B3::Air::TmpWidth::defWidth):
+        (JSC::B3::Air::TmpWidth::useWidth):
+        (JSC::B3::Air::TmpWidth::Widths::Widths):
+        * b3/air/AirUseCounts.h:
+        (JSC::B3::Air::UseCounts::UseCounts):
+        * b3/air/opcode_generator.rb:
+        * b3/testb3.cpp:
+        (JSC::B3::testCheckMegaCombo):
+        (JSC::B3::testCheckTrickyMegaCombo):
+        (JSC::B3::testCheckTwoMegaCombos):
+        (JSC::B3::run):
+
</ins><span class="cx"> 2015-12-21  Andy VanWagoner  &lt;thetalecrafter@gmail.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [INTL] Implement String.prototype.localeCompare in ECMA-402
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (194330 => 194331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2015-12-21 15:16:58 UTC (rev 194330)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2015-12-21 16:16:01 UTC (rev 194331)
</span><span class="lines">@@ -695,6 +695,8 @@
</span><span class="cx">                 0FE0502C1AA9095600D33B33 /* VarOffset.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE050231AA9095600D33B33 /* VarOffset.cpp */; };
</span><span class="cx">                 0FE0502D1AA9095600D33B33 /* VarOffset.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE050241AA9095600D33B33 /* VarOffset.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0FE0502F1AAA806900D33B33 /* ScopedArgumentsTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE0502E1AAA806900D33B33 /* ScopedArgumentsTable.cpp */; };
</span><ins>+                0FE0E4AD1C24C94A002E17B6 /* AirTmpWidth.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE0E4AB1C24C94A002E17B6 /* AirTmpWidth.cpp */; };
+                0FE0E4AE1C24C94A002E17B6 /* AirTmpWidth.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE0E4AC1C24C94A002E17B6 /* AirTmpWidth.h */; };
</ins><span class="cx">                 0FE228ED1436AB2700196C48 /* Options.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE228EB1436AB2300196C48 /* Options.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0FE228EE1436AB2C00196C48 /* Options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE228EA1436AB2300196C48 /* Options.cpp */; };
</span><span class="cx">                 0FE254F61ABDDD2200A7C6D2 /* DFGVarargsForwardingPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE254F41ABDDD2200A7C6D2 /* DFGVarargsForwardingPhase.cpp */; };
</span><span class="lines">@@ -2835,6 +2837,8 @@
</span><span class="cx">                 0FE050231AA9095600D33B33 /* VarOffset.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VarOffset.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FE050241AA9095600D33B33 /* VarOffset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VarOffset.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FE0502E1AAA806900D33B33 /* ScopedArgumentsTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScopedArgumentsTable.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                0FE0E4AB1C24C94A002E17B6 /* AirTmpWidth.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AirTmpWidth.cpp; path = b3/air/AirTmpWidth.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                0FE0E4AC1C24C94A002E17B6 /* AirTmpWidth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AirTmpWidth.h; path = b3/air/AirTmpWidth.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 0FE228EA1436AB2300196C48 /* Options.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Options.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FE228EB1436AB2300196C48 /* Options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Options.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FE254F41ABDDD2200A7C6D2 /* DFGVarargsForwardingPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGVarargsForwardingPhase.cpp; path = dfg/DFGVarargsForwardingPhase.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -4800,6 +4804,8 @@
</span><span class="cx">                                 0FEC85681BDACDC70080FF74 /* AirTmp.cpp */,
</span><span class="cx">                                 0FEC85691BDACDC70080FF74 /* AirTmp.h */,
</span><span class="cx">                                 0FEC856A1BDACDC70080FF74 /* AirTmpInlines.h */,
</span><ins>+                                0FE0E4AB1C24C94A002E17B6 /* AirTmpWidth.cpp */,
+                                0FE0E4AC1C24C94A002E17B6 /* AirTmpWidth.h */,
</ins><span class="cx">                                 0F3730921C0D67EE00052BFA /* AirUseCounts.h */,
</span><span class="cx">                                 0FEC856B1BDACDC70080FF74 /* AirValidate.cpp */,
</span><span class="cx">                                 0FEC856C1BDACDC70080FF74 /* AirValidate.h */,
</span><span class="lines">@@ -7296,6 +7302,7 @@
</span><span class="cx">                                 0F235BD917178E1C00690C7F /* FTLExitThunkGenerator.h in Headers */,
</span><span class="cx">                                 0F2B9CF719D0BAC100B1D1B5 /* FTLExitTimeObjectMaterialization.h in Headers */,
</span><span class="cx">                                 0F235BDB17178E1C00690C7F /* FTLExitValue.h in Headers */,
</span><ins>+                                0FE0E4AE1C24C94A002E17B6 /* AirTmpWidth.h in Headers */,
</ins><span class="cx">                                 A7F2996C17A0BB670010417A /* FTLFail.h in Headers */,
</span><span class="cx">                                 0FEA0A2C170B661900BB722C /* FTLFormattedValue.h in Headers */,
</span><span class="cx">                                 0FD8A31A17D51F2200CA2C40 /* FTLForOSREntryJITCode.h in Headers */,
</span><span class="lines">@@ -9229,6 +9236,7 @@
</span><span class="cx">                                 0F766D3815AE4A1C008F363E /* StructureStubClearingWatchpoint.cpp in Sources */,
</span><span class="cx">                                 BCCF0D0C0EF0B8A500413C8F /* StructureStubInfo.cpp in Sources */,
</span><span class="cx">                                 705B41AB1A6E501E00716757 /* Symbol.cpp in Sources */,
</span><ins>+                                0FE0E4AD1C24C94A002E17B6 /* AirTmpWidth.cpp in Sources */,
</ins><span class="cx">                                 705B41AD1A6E501E00716757 /* SymbolConstructor.cpp in Sources */,
</span><span class="cx">                                 705B41AF1A6E501E00716757 /* SymbolObject.cpp in Sources */,
</span><span class="cx">                                 705B41B11A6E501E00716757 /* SymbolPrototype.cpp in Sources */,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerAbstractMacroAssemblerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h (194330 => 194331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h        2015-12-21 15:16:58 UTC (rev 194330)
+++ trunk/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h        2015-12-21 16:16:01 UTC (rev 194331)
</span><span class="lines">@@ -67,6 +67,15 @@
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline bool isX86_64()
+{
+#if CPU(X86_64)
+    return true;
+#else
+    return false;
+#endif
+}
+
</ins><span class="cx"> inline bool optimizeForARMv7IDIVSupported()
</span><span class="cx"> {
</span><span class="cx">     return isARMv7IDIVSupported() &amp;&amp; Options::useArchitectureSpecificOptimizations();
</span><span class="lines">@@ -82,6 +91,11 @@
</span><span class="cx">     return isX86() &amp;&amp; Options::useArchitectureSpecificOptimizations();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline bool optimizeForX86_64()
+{
+    return isX86_64() &amp;&amp; Options::useArchitectureSpecificOptimizations();
+}
+
</ins><span class="cx"> class AllowMacroScratchRegisterUsage;
</span><span class="cx"> class DisallowMacroScratchRegisterUsage;
</span><span class="cx"> class LinkBuffer;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3LowerToAircpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp (194330 => 194331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2015-12-21 15:16:58 UTC (rev 194330)
+++ trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2015-12-21 16:16:01 UTC (rev 194331)
</span><span class="lines">@@ -158,16 +158,12 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    // NOTE: This entire mechanism could be done over Air, if we felt that this would be fast enough.
-    // For now we're assuming that it's faster to do this here, since analyzing B3 is so cheap.
</del><span class="cx">     bool shouldCopyPropagate(Value* value)
</span><span class="cx">     {
</span><span class="cx">         switch (value-&gt;opcode()) {
</span><span class="cx">         case Trunc:
</span><span class="cx">         case Identity:
</span><span class="cx">             return true;
</span><del>-        case ZExt32:
-            return highBitsAreZero(value-&gt;child(0));
</del><span class="cx">         default:
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="lines">@@ -1775,11 +1771,6 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         case ZExt32: {
</span><del>-            if (highBitsAreZero(m_value-&gt;child(0))) {
-                ASSERT(tmp(m_value-&gt;child(0)) == tmp(m_value));
-                return;
-            }
-
</del><span class="cx">             appendUnOp&lt;Move32, Air::Oops&gt;(m_value-&gt;child(0));
</span><span class="cx">             return;
</span><span class="cx">         }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3PatchpointSpecialcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3PatchpointSpecial.cpp (194330 => 194331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3PatchpointSpecial.cpp        2015-12-21 15:16:58 UTC (rev 194330)
+++ trunk/Source/JavaScriptCore/b3/B3PatchpointSpecial.cpp        2015-12-21 16:16:01 UTC (rev 194331)
</span><span class="lines">@@ -54,7 +54,7 @@
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    callback(inst.args[1], Arg::Def, inst.origin-&gt;airType());
</del><ins>+    callback(inst.args[1], Arg::Def, inst.origin-&gt;airType(), inst.origin-&gt;airWidth());
</ins><span class="cx">     forEachArgImpl(0, 2, inst, SameAsRep, callback);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3StackmapSpecialcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3StackmapSpecial.cpp (194330 => 194331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3StackmapSpecial.cpp        2015-12-21 15:16:58 UTC (rev 194330)
+++ trunk/Source/JavaScriptCore/b3/B3StackmapSpecial.cpp        2015-12-21 16:16:01 UTC (rev 194331)
</span><span class="lines">@@ -111,8 +111,9 @@
</span><span class="cx">             role = Arg::LateUse;
</span><span class="cx">             break;
</span><span class="cx">         }
</span><del>-        
-        callback(arg, role, Arg::typeForB3Type(child.value()-&gt;type()));
</del><ins>+
+        Type type = child.value()-&gt;type();
+        callback(arg, role, Arg::typeForB3Type(type), Arg::widthForB3Type(type));
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3Valueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3Value.h (194330 => 194331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3Value.h        2015-12-21 15:16:58 UTC (rev 194330)
+++ trunk/Source/JavaScriptCore/b3/B3Value.h        2015-12-21 16:16:01 UTC (rev 194331)
</span><span class="lines">@@ -76,6 +76,7 @@
</span><span class="cx"> 
</span><span class="cx">     // This is useful when lowering. Note that this is only valid for non-void values.
</span><span class="cx">     Air::Arg::Type airType() const { return Air::Arg::typeForB3Type(type()); }
</span><ins>+    Air::Arg::Width airWidth() const { return Air::Arg::widthForB3Type(type()); }
</ins><span class="cx"> 
</span><span class="cx">     AdjacencyList&amp; children() { return m_children; } 
</span><span class="cx">     const AdjacencyList&amp; children() const { return m_children; }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirAllocateStackcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirAllocateStack.cpp (194330 => 194331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirAllocateStack.cpp        2015-12-21 15:16:58 UTC (rev 194330)
+++ trunk/Source/JavaScriptCore/b3/air/AirAllocateStack.cpp        2015-12-21 16:16:01 UTC (rev 194331)
</span><span class="lines">@@ -104,7 +104,7 @@
</span><span class="cx">     for (BasicBlock* block : code) {
</span><span class="cx">         for (Inst&amp; inst : *block) {
</span><span class="cx">             inst.forEachArg(
</span><del>-                [&amp;] (Arg&amp; arg, Arg::Role role, Arg::Type) {
</del><ins>+                [&amp;] (Arg&amp; arg, Arg::Role role, Arg::Type, Arg::Width) {
</ins><span class="cx">                     if (role == Arg::UseAddr &amp;&amp; arg.isStack())
</span><span class="cx">                         escapingStackSlots.add(arg.stackSlot());
</span><span class="cx">                 });
</span><span class="lines">@@ -148,7 +148,7 @@
</span><span class="cx">                 dataLog(&quot;Interfering: &quot;, WTF::pointerListDump(localCalc.live()), &quot;\n&quot;);
</span><span class="cx"> 
</span><span class="cx">             inst.forEachArg(
</span><del>-                [&amp;] (Arg&amp; arg, Arg::Role role, Arg::Type) {
</del><ins>+                [&amp;] (Arg&amp; arg, Arg::Role role, Arg::Type, Arg::Width) {
</ins><span class="cx">                     if (!Arg::isDef(role))
</span><span class="cx">                         return;
</span><span class="cx">                     if (!arg.isStack())
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirArgcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirArg.cpp (194330 => 194331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirArg.cpp        2015-12-21 15:16:58 UTC (rev 194330)
+++ trunk/Source/JavaScriptCore/b3/air/AirArg.cpp        2015-12-21 16:16:01 UTC (rev 194331)
</span><span class="lines">@@ -178,6 +178,12 @@
</span><span class="cx">     case Arg::UseDef:
</span><span class="cx">         out.print(&quot;UseDef&quot;);
</span><span class="cx">         return;
</span><ins>+    case Arg::ZDef:
+        out.print(&quot;ZDef&quot;);
+        return;
+    case Arg::UseZDef:
+        out.print(&quot;UseZDef&quot;);
+        return;
</ins><span class="cx">     case Arg::UseAddr:
</span><span class="cx">         out.print(&quot;UseAddr&quot;);
</span><span class="cx">         return;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirArgh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirArg.h (194330 => 194331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirArg.h        2015-12-21 15:16:58 UTC (rev 194330)
+++ trunk/Source/JavaScriptCore/b3/air/AirArg.h        2015-12-21 16:16:01 UTC (rev 194331)
</span><span class="lines">@@ -101,9 +101,28 @@
</span><span class="cx">         // Like Use of address, Def of address does not mean escape.
</span><span class="cx">         Def,
</span><span class="cx"> 
</span><ins>+        // This is a special variant of Def that implies that the upper bits of the target register are
+        // zero-filled. Specifically, if the Width of a ZDef is less than the largest possible width of
+        // the argument (for example, we're on a 64-bit machine and we have a Width32 ZDef of a GPR) then
+        // this has different implications for the upper bits (i.e. the top 32 bits in our example)
+        // depending on the kind of the argument:
+        //
+        // For register: the upper bits are zero-filled.
+        // For address: the upper bits are not touched (i.e. we do a 32-bit store in our example).
+        // For tmp: either the upper bits are not touched or they are zero-filled, and we won't know
+        // which until we lower the tmp to either a StackSlot or a Reg.
+        //
+        // The behavior of ZDef is consistent with what happens when you perform 32-bit operations on a
+        // 64-bit GPR. It's not consistent with what happens with 8-bit or 16-bit Defs on x86 GPRs, or
+        // what happens with float Defs in ARM NEON or X86 SSE. Hence why we have both Def and ZDef.
+        ZDef,
+
</ins><span class="cx">         // This is a combined Use and Def. It means that both things happen.
</span><span class="cx">         UseDef,
</span><span class="cx"> 
</span><ins>+        // This is a combined Use and ZDef. It means that both things happen.
+        UseZDef,
+
</ins><span class="cx">         // This is a special kind of use that is only valid for addresses. It means that the
</span><span class="cx">         // instruction will evaluate the address expression and consume the effective address, but it
</span><span class="cx">         // will neither load nor store. This is an escaping use, because now the address may be
</span><span class="lines">@@ -126,6 +145,13 @@
</span><span class="cx">         Width64
</span><span class="cx">     };
</span><span class="cx"> 
</span><ins>+    static Width pointerWidth()
+    {
+        if (sizeof(void*) == 8)
+            return Width64;
+        return Width32;
+    }
+
</ins><span class="cx">     enum Signedness : int8_t {
</span><span class="cx">         Signed,
</span><span class="cx">         Unsigned
</span><span class="lines">@@ -139,9 +165,11 @@
</span><span class="cx">         case Use:
</span><span class="cx">         case ColdUse:
</span><span class="cx">         case UseDef:
</span><ins>+        case UseZDef:
</ins><span class="cx">         case LateUse:
</span><span class="cx">             return true;
</span><span class="cx">         case Def:
</span><ins>+        case ZDef:
</ins><span class="cx">         case UseAddr:
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="lines">@@ -155,7 +183,9 @@
</span><span class="cx">             return true;
</span><span class="cx">         case Use:
</span><span class="cx">         case UseDef:
</span><ins>+        case UseZDef:
</ins><span class="cx">         case Def:
</span><ins>+        case ZDef:
</ins><span class="cx">         case UseAddr:
</span><span class="cx">             return false;
</span><span class="cx">         }
</span><span class="lines">@@ -173,8 +203,10 @@
</span><span class="cx">         case Use:
</span><span class="cx">         case ColdUse:
</span><span class="cx">         case UseDef:
</span><ins>+        case UseZDef:
</ins><span class="cx">             return true;
</span><span class="cx">         case Def:
</span><ins>+        case ZDef:
</ins><span class="cx">         case UseAddr:
</span><span class="cx">         case LateUse:
</span><span class="cx">             return false;
</span><span class="lines">@@ -198,10 +230,29 @@
</span><span class="cx">             return false;
</span><span class="cx">         case Def:
</span><span class="cx">         case UseDef:
</span><ins>+        case ZDef:
+        case UseZDef:
</ins><span class="cx">             return true;
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    // Returns true if the Role implies that the Inst will ZDef the Arg.
+    static bool isZDef(Role role)
+    {
+        switch (role) {
+        case Use:
+        case ColdUse:
+        case UseAddr:
+        case LateUse:
+        case Def:
+        case UseDef:
+            return false;
+        case ZDef:
+        case UseZDef:
+            return true;
+        }
+    }
+
</ins><span class="cx">     static Type typeForB3Type(B3::Type type)
</span><span class="cx">     {
</span><span class="cx">         switch (type) {
</span><span class="lines">@@ -234,6 +285,37 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    static Width conservativeWidth(Type type)
+    {
+        return type == GP ? pointerWidth() : Width64;
+    }
+
+    static Width minimumWidth(Type type)
+    {
+        return type == GP ? Width8 : Width32;
+    }
+
+    static unsigned bytes(Width width)
+    {
+        return 1 &lt;&lt; width;
+    }
+
+    static Width widthForBytes(unsigned bytes)
+    {
+        switch (bytes) {
+        case 0:
+        case 1:
+            return Width8;
+        case 2:
+            return Width16;
+        case 3:
+        case 4:
+            return Width32;
+        default:
+            return Width64;
+        }
+    }
+
</ins><span class="cx">     Arg()
</span><span class="cx">         : m_kind(Invalid)
</span><span class="cx">     {
</span><span class="lines">@@ -717,19 +799,19 @@
</span><span class="cx">     //
</span><span class="cx">     // This defs (%rcx) but uses %rcx.
</span><span class="cx">     template&lt;typename Functor&gt;
</span><del>-    void forEachTmp(Role argRole, Type argType, const Functor&amp; functor)
</del><ins>+    void forEachTmp(Role argRole, Type argType, Width argWidth, const Functor&amp; functor)
</ins><span class="cx">     {
</span><span class="cx">         switch (m_kind) {
</span><span class="cx">         case Tmp:
</span><span class="cx">             ASSERT(isAnyUse(argRole) || isDef(argRole));
</span><del>-            functor(m_base, argRole, argType);
</del><ins>+            functor(m_base, argRole, argType, argWidth);
</ins><span class="cx">             break;
</span><span class="cx">         case Addr:
</span><del>-            functor(m_base, Use, GP);
</del><ins>+            functor(m_base, Use, GP, argRole == UseAddr ? argWidth : pointerWidth());
</ins><span class="cx">             break;
</span><span class="cx">         case Index:
</span><del>-            functor(m_base, Use, GP);
-            functor(m_index, Use, GP);
</del><ins>+            functor(m_base, Use, GP, argRole == UseAddr ? argWidth : pointerWidth());
+            functor(m_index, Use, GP, argRole == UseAddr ? argWidth : pointerWidth());
</ins><span class="cx">             break;
</span><span class="cx">         default:
</span><span class="cx">             break;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirCCallSpecialcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirCCallSpecial.cpp (194330 => 194331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirCCallSpecial.cpp        2015-12-21 15:16:58 UTC (rev 194330)
+++ trunk/Source/JavaScriptCore/b3/air/AirCCallSpecial.cpp        2015-12-21 16:16:01 UTC (rev 194331)
</span><span class="lines">@@ -45,16 +45,17 @@
</span><span class="cx"> void CCallSpecial::forEachArg(Inst&amp; inst, const ScopedLambda&lt;Inst::EachArgCallback&gt;&amp; callback)
</span><span class="cx"> {
</span><span class="cx">     for (unsigned i = 0; i &lt; numCalleeArgs; ++i)
</span><del>-        callback(inst.args[calleeArgOffset + i], Arg::Use, Arg::GP);
</del><ins>+        callback(inst.args[calleeArgOffset + i], Arg::Use, Arg::GP, Arg::pointerWidth());
</ins><span class="cx">     for (unsigned i = 0; i &lt; numReturnGPArgs; ++i)
</span><del>-        callback(inst.args[returnGPArgOffset + i], Arg::Def, Arg::GP);
</del><ins>+        callback(inst.args[returnGPArgOffset + i], Arg::Def, Arg::GP, Arg::pointerWidth());
</ins><span class="cx">     for (unsigned i = 0; i &lt; numReturnFPArgs; ++i)
</span><del>-        callback(inst.args[returnFPArgOffset + i], Arg::Def, Arg::FP);
</del><ins>+        callback(inst.args[returnFPArgOffset + i], Arg::Def, Arg::FP, Arg::Width64);
</ins><span class="cx">     
</span><span class="cx">     for (unsigned i = argArgOffset; i &lt; inst.args.size(); ++i) {
</span><span class="cx">         // For the type, we can just query the arg's type. The arg will have a type, because we
</span><span class="cx">         // require these args to be argument registers.
</span><del>-        callback(inst.args[i], Arg::Use, inst.args[i].type());
</del><ins>+        Arg::Type type = inst.args[i].type();
+        callback(inst.args[i], Arg::Use, type, Arg::conservativeWidth(type));
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirEliminateDeadCodecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirEliminateDeadCode.cpp (194330 => 194331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirEliminateDeadCode.cpp        2015-12-21 15:16:58 UTC (rev 194330)
+++ trunk/Source/JavaScriptCore/b3/air/AirEliminateDeadCode.cpp        2015-12-21 16:16:01 UTC (rev 194331)
</span><span class="lines">@@ -80,7 +80,7 @@
</span><span class="cx">         // This instruction should be presumed dead, if its Args are all dead.
</span><span class="cx">         bool storesToLive = false;
</span><span class="cx">         inst.forEachArg(
</span><del>-            [&amp;] (Arg&amp; arg, Arg::Role role, Arg::Type) {
</del><ins>+            [&amp;] (Arg&amp; arg, Arg::Role role, Arg::Type, Arg::Width) {
</ins><span class="cx">                 if (!Arg::isDef(role))
</span><span class="cx">                     return;
</span><span class="cx">                 storesToLive |= isArgLive(arg);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirFixPartialRegisterStallscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirFixPartialRegisterStalls.cpp (194330 => 194331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirFixPartialRegisterStalls.cpp        2015-12-21 15:16:58 UTC (rev 194330)
+++ trunk/Source/JavaScriptCore/b3/air/AirFixPartialRegisterStalls.cpp        2015-12-21 16:16:01 UTC (rev 194331)
</span><span class="lines">@@ -113,7 +113,7 @@
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    inst.forEachTmp([&amp;] (Tmp&amp; tmp, Arg::Role role, Arg::Type) {
</del><ins>+    inst.forEachTmp([&amp;] (Tmp&amp; tmp, Arg::Role role, Arg::Type, Arg::Width) {
</ins><span class="cx">         ASSERT_WITH_MESSAGE(tmp.isReg(), &quot;This phase must be run after register allocation.&quot;);
</span><span class="cx"> 
</span><span class="cx">         if (tmp.isFPR() &amp;&amp; Arg::isDef(role))
</span><span class="lines">@@ -203,7 +203,7 @@
</span><span class="cx">             if (hasPartialXmmRegUpdate(inst)) {
</span><span class="cx">                 RegisterSet defs;
</span><span class="cx">                 RegisterSet uses;
</span><del>-                inst.forEachTmp([&amp;] (Tmp&amp; tmp, Arg::Role role, Arg::Type) {
</del><ins>+                inst.forEachTmp([&amp;] (Tmp&amp; tmp, Arg::Role role, Arg::Type, Arg::Width) {
</ins><span class="cx">                     if (tmp.isFPR()) {
</span><span class="cx">                         if (Arg::isDef(role))
</span><span class="cx">                             defs.set(tmp.fpr());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirInstcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirInst.cpp (194330 => 194331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirInst.cpp        2015-12-21 15:16:58 UTC (rev 194330)
+++ trunk/Source/JavaScriptCore/b3/air/AirInst.cpp        2015-12-21 16:16:01 UTC (rev 194331)
</span><span class="lines">@@ -38,7 +38,7 @@
</span><span class="cx"> {
</span><span class="cx">     bool result = false;
</span><span class="cx">     forEachArg(
</span><del>-        [&amp;] (Arg&amp;, Arg::Role role, Arg::Type) {
</del><ins>+        [&amp;] (Arg&amp;, Arg::Role role, Arg::Type, Arg::Width) {
</ins><span class="cx">             if (Arg::isDef(role))
</span><span class="cx">                 result = true;
</span><span class="cx">         });
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirInsth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirInst.h (194330 => 194331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirInst.h        2015-12-21 15:16:58 UTC (rev 194330)
+++ trunk/Source/JavaScriptCore/b3/air/AirInst.h        2015-12-21 16:16:01 UTC (rev 194331)
</span><span class="lines">@@ -98,20 +98,20 @@
</span><span class="cx">             arg.forEachTmpFast(functor);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    typedef void EachArgCallback(Arg&amp;, Arg::Role, Arg::Type);
</del><ins>+    typedef void EachArgCallback(Arg&amp;, Arg::Role, Arg::Type, Arg::Width);
</ins><span class="cx">     
</span><del>-    // Calls the functor with (arg, role, type). This function is auto-generated by
</del><ins>+    // Calls the functor with (arg, role, type, width). This function is auto-generated by
</ins><span class="cx">     // opcode_generator.rb.
</span><span class="cx">     template&lt;typename Functor&gt;
</span><span class="cx">     void forEachArg(const Functor&amp;);
</span><span class="cx"> 
</span><del>-    // Calls the functor with (tmp, role, type).
</del><ins>+    // Calls the functor with (tmp, role, type, width).
</ins><span class="cx">     template&lt;typename Functor&gt;
</span><span class="cx">     void forEachTmp(const Functor&amp; functor)
</span><span class="cx">     {
</span><span class="cx">         forEachArg(
</span><del>-            [&amp;] (Arg&amp; arg, Arg::Role role, Arg::Type type) {
-                arg.forEachTmp(role, type, functor);
</del><ins>+            [&amp;] (Arg&amp; arg, Arg::Role role, Arg::Type type, Arg::Width width) {
+                arg.forEachTmp(role, type, width, functor);
</ins><span class="cx">             });
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirInstInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirInstInlines.h (194330 => 194331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirInstInlines.h        2015-12-21 15:16:58 UTC (rev 194330)
+++ trunk/Source/JavaScriptCore/b3/air/AirInstInlines.h        2015-12-21 16:16:01 UTC (rev 194331)
</span><span class="lines">@@ -55,7 +55,7 @@
</span><span class="cx">     static void forEach(Inst&amp; inst, const Functor&amp; functor)
</span><span class="cx">     {
</span><span class="cx">         inst.forEachArg(
</span><del>-            [&amp;] (Arg&amp; arg, Arg::Role role, Arg::Type type) {
</del><ins>+            [&amp;] (Arg&amp; arg, Arg::Role role, Arg::Type type, Arg::Width width) {
</ins><span class="cx">                 if (!arg.isStack())
</span><span class="cx">                     return;
</span><span class="cx">                 StackSlot* stackSlot = arg.stackSlot();
</span><span class="lines">@@ -66,7 +66,7 @@
</span><span class="cx">                 // semantics of &quot;Anonymous&quot;.
</span><span class="cx">                 // https://bugs.webkit.org/show_bug.cgi?id=151128
</span><span class="cx">                 
</span><del>-                functor(stackSlot, role, type);
</del><ins>+                functor(stackSlot, role, type, width);
</ins><span class="cx">                 arg = Arg::stack(stackSlot, arg.offset());
</span><span class="cx">             });
</span><span class="cx">     }
</span><span class="lines">@@ -99,12 +99,13 @@
</span><span class="cx"> inline void Inst::forEachTmpWithExtraClobberedRegs(Inst* nextInst, const Functor&amp; functor)
</span><span class="cx"> {
</span><span class="cx">     forEachTmp(
</span><del>-        [&amp;] (Tmp&amp; tmpArg, Arg::Role role, Arg::Type argType) {
-            functor(tmpArg, role, argType);
</del><ins>+        [&amp;] (Tmp&amp; tmpArg, Arg::Role role, Arg::Type argType, Arg::Width argWidth) {
+            functor(tmpArg, role, argType, argWidth);
</ins><span class="cx">         });
</span><span class="cx"> 
</span><span class="cx">     auto reportReg = [&amp;] (Reg reg) {
</span><del>-        functor(Tmp(reg), Arg::Def, reg.isGPR() ? Arg::GP : Arg::FP);
</del><ins>+        Arg::Type type = reg.isGPR() ? Arg::GP : Arg::FP;
+        functor(Tmp(reg), Arg::Def, type, Arg::conservativeWidth(type));
</ins><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     if (hasSpecial())
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirIteratedRegisterCoalescingcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirIteratedRegisterCoalescing.cpp (194330 => 194331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirIteratedRegisterCoalescing.cpp        2015-12-21 15:16:58 UTC (rev 194330)
+++ trunk/Source/JavaScriptCore/b3/air/AirIteratedRegisterCoalescing.cpp        2015-12-21 16:16:01 UTC (rev 194331)
</span><span class="lines">@@ -35,6 +35,7 @@
</span><span class="cx"> #include &quot;AirPhaseScope.h&quot;
</span><span class="cx"> #include &quot;AirRegisterPriority.h&quot;
</span><span class="cx"> #include &quot;AirTmpInlines.h&quot;
</span><ins>+#include &quot;AirTmpWidth.h&quot;
</ins><span class="cx"> #include &quot;AirUseCounts.h&quot;
</span><span class="cx"> #include &lt;wtf/ListDump.h&gt;
</span><span class="cx"> #include &lt;wtf/ListHashSet.h&gt;
</span><span class="lines">@@ -630,9 +631,10 @@
</span><span class="cx"> template&lt;Arg::Type type&gt;
</span><span class="cx"> class ColoringAllocator : public AbstractColoringAllocator&lt;unsigned&gt; {
</span><span class="cx"> public:
</span><del>-    ColoringAllocator(Code&amp; code, const UseCounts&lt;Tmp&gt;&amp; useCounts, const HashSet&lt;unsigned&gt;&amp; unspillableTmp)
</del><ins>+    ColoringAllocator(Code&amp; code, TmpWidth&amp; tmpWidth, const UseCounts&lt;Tmp&gt;&amp; useCounts, const HashSet&lt;unsigned&gt;&amp; unspillableTmp)
</ins><span class="cx">         : AbstractColoringAllocator&lt;unsigned&gt;(regsInPriorityOrder(type), AbsoluteTmpMapper&lt;type&gt;::lastMachineRegisterIndex(), tmpArraySize(code))
</span><span class="cx">         , m_code(code)
</span><ins>+        , m_tmpWidth(tmpWidth)
</ins><span class="cx">         , m_useCounts(useCounts)
</span><span class="cx">         , m_unspillableTmps(unspillableTmp)
</span><span class="cx">     {
</span><span class="lines">@@ -646,9 +648,17 @@
</span><span class="cx">         return AbsoluteTmpMapper&lt;type&gt;::tmpFromAbsoluteIndex(getAlias(AbsoluteTmpMapper&lt;type&gt;::absoluteIndex(tmp)));
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    // This tells you if a Move will be coalescable if the src and dst end up matching. This method
+    // relies on an analysis that is invalidated by register allocation, so you it's only meaningful to
+    // call this *before* replacing the Tmp's in this Inst with registers or spill slots.
+    bool mayBeCoalescable(const Inst&amp; inst) const
+    {
+        return mayBeCoalescableImpl(inst, &amp;m_tmpWidth);
+    }
+
</ins><span class="cx">     bool isUselessMove(const Inst&amp; inst) const
</span><span class="cx">     {
</span><del>-        return mayBeCoalescable(inst) &amp;&amp; inst.args[0].tmp() == inst.args[1].tmp();
</del><ins>+        return mayBeCoalescableImpl(inst, nullptr) &amp;&amp; inst.args[0].tmp() == inst.args[1].tmp();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     Tmp getAliasWhenSpilling(Tmp tmp) const
</span><span class="lines">@@ -770,14 +780,14 @@
</span><span class="cx">     {
</span><span class="cx">         inst.forEachTmpWithExtraClobberedRegs(
</span><span class="cx">             nextInst,
</span><del>-            [&amp;] (const Tmp&amp; arg, Arg::Role role, Arg::Type argType) {
</del><ins>+            [&amp;] (const Tmp&amp; arg, Arg::Role role, Arg::Type argType, Arg::Width) {
</ins><span class="cx">                 if (!Arg::isDef(role) || argType != type)
</span><span class="cx">                     return;
</span><span class="cx">                 
</span><span class="cx">                 // All the Def()s interfere with each other and with all the extra clobbered Tmps.
</span><span class="cx">                 // We should not use forEachDefAndExtraClobberedTmp() here since colored Tmps
</span><span class="cx">                 // do not need interference edges in our implementation.
</span><del>-                inst.forEachTmp([&amp;] (Tmp&amp; otherArg, Arg::Role role, Arg::Type argType) {
</del><ins>+                inst.forEachTmp([&amp;] (Tmp&amp; otherArg, Arg::Role role, Arg::Type argType, Arg::Width) {
</ins><span class="cx">                     if (!Arg::isDef(role) || argType != type)
</span><span class="cx">                         return;
</span><span class="cx"> 
</span><span class="lines">@@ -791,7 +801,7 @@
</span><span class="cx">             // coalesce the Move even if the two Tmp never interfere anywhere.
</span><span class="cx">             Tmp defTmp;
</span><span class="cx">             Tmp useTmp;
</span><del>-            inst.forEachTmp([&amp;defTmp, &amp;useTmp] (Tmp&amp; argTmp, Arg::Role role, Arg::Type) {
</del><ins>+            inst.forEachTmp([&amp;defTmp, &amp;useTmp] (Tmp&amp; argTmp, Arg::Role role, Arg::Type, Arg::Width) {
</ins><span class="cx">                 if (Arg::isDef(role))
</span><span class="cx">                     defTmp = argTmp;
</span><span class="cx">                 else {
</span><span class="lines">@@ -839,7 +849,7 @@
</span><span class="cx">         // All the Def()s interfere with everthing live.
</span><span class="cx">         inst.forEachTmpWithExtraClobberedRegs(
</span><span class="cx">             nextInst,
</span><del>-            [&amp;] (const Tmp&amp; arg, Arg::Role role, Arg::Type argType) {
</del><ins>+            [&amp;] (const Tmp&amp; arg, Arg::Role role, Arg::Type argType, Arg::Width) {
</ins><span class="cx">                 if (!Arg::isDef(role) || argType != type)
</span><span class="cx">                     return;
</span><span class="cx">                 
</span><span class="lines">@@ -857,12 +867,15 @@
</span><span class="cx">         addEdge(AbsoluteTmpMapper&lt;type&gt;::absoluteIndex(a), AbsoluteTmpMapper&lt;type&gt;::absoluteIndex(b));
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    bool mayBeCoalescable(const Inst&amp; inst) const
</del><ins>+    // Calling this without a tmpWidth will perform a more conservative coalescing analysis that assumes
+    // that Move32's are not coalescable.
+    static bool mayBeCoalescableImpl(const Inst&amp; inst, TmpWidth* tmpWidth)
</ins><span class="cx">     {
</span><span class="cx">         switch (type) {
</span><span class="cx">         case Arg::GP:
</span><span class="cx">             switch (inst.opcode) {
</span><span class="cx">             case Move:
</span><ins>+            case Move32:
</ins><span class="cx">                 break;
</span><span class="cx">             default:
</span><span class="cx">                 return false;
</span><span class="lines">@@ -887,6 +900,22 @@
</span><span class="cx">         ASSERT(inst.args[0].type() == type);
</span><span class="cx">         ASSERT(inst.args[1].type() == type);
</span><span class="cx"> 
</span><ins>+        // We can coalesce a Move32 so long as either of the following holds:
+        // - The input is already zero-filled.
+        // - The output only cares about the low 32 bits.
+        //
+        // Note that the input property requires an analysis over ZDef's, so it's only valid so long
+        // as the input gets a register. We don't know if the input gets a register, but we do know
+        // that if it doesn't get a register then we will still emit this Move32.
+        if (inst.opcode == Move32) {
+            if (!tmpWidth)
+                return false;
+
+            if (tmpWidth-&gt;defWidth(inst.args[0].tmp()) &gt; Arg::Width32
+                &amp;&amp; tmpWidth-&gt;useWidth(inst.args[1].tmp()) &gt; Arg::Width32)
+                return false;
+        }
+        
</ins><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -1024,6 +1053,7 @@
</span><span class="cx">     using AbstractColoringAllocator&lt;unsigned&gt;::getAlias;
</span><span class="cx"> 
</span><span class="cx">     Code&amp; m_code;
</span><ins>+    TmpWidth&amp; m_tmpWidth;
</ins><span class="cx">     // FIXME: spilling should not type specific. It is only a side effect of using UseCounts.
</span><span class="cx">     const UseCounts&lt;Tmp&gt;&amp; m_useCounts;
</span><span class="cx">     const HashSet&lt;unsigned&gt;&amp; m_unspillableTmps;
</span><span class="lines">@@ -1053,7 +1083,23 @@
</span><span class="cx">         HashSet&lt;unsigned&gt; unspillableTmps;
</span><span class="cx">         while (true) {
</span><span class="cx">             ++m_numIterations;
</span><del>-            ColoringAllocator&lt;type&gt; allocator(m_code, m_useCounts, unspillableTmps);
</del><ins>+
+            // FIXME: One way to optimize this code is to remove the recomputation inside the fixpoint.
+            // We need to recompute because spilling adds tmps, but we could just update tmpWidth when we
+            // add those tmps. Note that one easy way to remove the recomputation is to make any newly
+            // added Tmps get the same use/def widths that the original Tmp got. But, this may hurt the
+            // spill code we emit. Since we currently recompute TmpWidth after spilling, the newly
+            // created Tmps may get narrower use/def widths. On the other hand, the spiller already
+            // selects which move instruction to use based on the original Tmp's widths, so it may not
+            // matter than a subsequent iteration sees a coservative width for the new Tmps. Also, the
+            // recomputation may not actually be a performance problem; it's likely that a better way to
+            // improve performance of TmpWidth is to replace its HashMap with something else. It's
+            // possible that most of the TmpWidth overhead is from queries of TmpWidth rather than the
+            // recomputation, in which case speeding up the lookup would be a bigger win.
+            // https://bugs.webkit.org/show_bug.cgi?id=152478
+            m_tmpWidth.recompute(m_code);
+            
+            ColoringAllocator&lt;type&gt; allocator(m_code, m_tmpWidth, m_useCounts, unspillableTmps);
</ins><span class="cx">             if (!allocator.requiresSpilling()) {
</span><span class="cx">                 assignRegistersToTmp(allocator);
</span><span class="cx">                 return;
</span><span class="lines">@@ -1069,6 +1115,22 @@
</span><span class="cx">             // Give Tmp a valid register.
</span><span class="cx">             for (unsigned instIndex = 0; instIndex &lt; block-&gt;size(); ++instIndex) {
</span><span class="cx">                 Inst&amp; inst = block-&gt;at(instIndex);
</span><ins>+
+                // The mayBeCoalescable() method will change its mind for some operations after we
+                // complete register allocation. So, we record this before starting.
+                bool mayBeCoalescable = allocator.mayBeCoalescable(inst);
+
+                // On X86_64, Move32 is cheaper if we know that it's equivalent to a Move. It's
+                // equivalent if the destination's high bits are not observable or if the source's high
+                // bits are all zero. Note that we don't have the opposite optimization for other
+                // architectures, which may prefer Move over Move32, because Move is canonical already.
+                if (type == Arg::GP &amp;&amp; optimizeForX86_64() &amp;&amp; inst.opcode == Move
+                    &amp;&amp; inst.args[0].isTmp() &amp;&amp; inst.args[1].isTmp()) {
+                    if (m_tmpWidth.useWidth(inst.args[1].tmp()) &lt;= Arg::Width32
+                        || m_tmpWidth.defWidth(inst.args[0].tmp()) &lt;= Arg::Width32)
+                        inst.opcode = Move32;
+                }
+
</ins><span class="cx">                 inst.forEachTmpFast([&amp;] (Tmp&amp; tmp) {
</span><span class="cx">                     if (tmp.isReg() || tmp.isGP() == (type != Arg::GP))
</span><span class="cx">                         return;
</span><span class="lines">@@ -1085,11 +1147,15 @@
</span><span class="cx">                     ASSERT(assignedTmp.isReg());
</span><span class="cx">                     tmp = assignedTmp;
</span><span class="cx">                 });
</span><ins>+
+                if (mayBeCoalescable &amp;&amp; inst.args[0].isTmp() &amp;&amp; inst.args[1].isTmp()
+                    &amp;&amp; inst.args[0].tmp() == inst.args[1].tmp())
+                    inst = Inst();
</ins><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             // Remove all the useless moves we created in this block.
</span><span class="cx">             block-&gt;insts().removeAllMatching([&amp;] (const Inst&amp; inst) {
</span><del>-                return allocator.isUselessMove(inst);
</del><ins>+                return !inst;
</ins><span class="cx">             });
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -1103,7 +1169,9 @@
</span><span class="cx">             unspillableTmps.add(AbsoluteTmpMapper&lt;type&gt;::absoluteIndex(tmp));
</span><span class="cx"> 
</span><span class="cx">             // Allocate stack slot for each spilled value.
</span><del>-            bool isNewTmp = stackSlots.add(tmp, m_code.addStackSlot(8, StackSlotKind::Anonymous)).isNewEntry;
</del><ins>+            StackSlot* stackSlot = m_code.addStackSlot(
+                m_tmpWidth.width(tmp) &lt;= Arg::Width32 ? 4 : 8, StackSlotKind::Anonymous);
+            bool isNewTmp = stackSlots.add(tmp, stackSlot).isNewEntry;
</ins><span class="cx">             ASSERT_UNUSED(isNewTmp, isNewTmp);
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -1115,18 +1183,36 @@
</span><span class="cx">             for (unsigned instIndex = 0; instIndex &lt; block-&gt;size(); ++instIndex) {
</span><span class="cx">                 Inst&amp; inst = block-&gt;at(instIndex);
</span><span class="cx"> 
</span><ins>+                // The TmpWidth analysis will say that a Move only stores 32 bits into the destination,
+                // if the source only had 32 bits worth of non-zero bits. Same for the source: it will
+                // only claim to read 32 bits from the source if only 32 bits of the destination are
+                // read. Note that we only apply this logic if this turns into a load or store, since
+                // Move is the canonical way to move data between GPRs.
+                bool forceMove32IfDidSpill = false;
+                bool didSpill = false;
+                if (type == Arg::GP &amp;&amp; inst.opcode == Move) {
+                    if (m_tmpWidth.defWidth(inst.args[0].tmp()) &lt;= Arg::Width32
+                        || m_tmpWidth.useWidth(inst.args[1].tmp()) &lt;= Arg::Width32)
+                        forceMove32IfDidSpill = true;
+                }
+
</ins><span class="cx">                 // Try to replace the register use by memory use when possible.
</span><span class="cx">                 for (unsigned i = 0; i &lt; inst.args.size(); ++i) {
</span><span class="cx">                     Arg&amp; arg = inst.args[i];
</span><span class="cx">                     if (arg.isTmp() &amp;&amp; arg.type() == type &amp;&amp; !arg.isReg()) {
</span><span class="cx">                         auto stackSlotEntry = stackSlots.find(arg.tmp());
</span><del>-                        if (stackSlotEntry != stackSlots.end() &amp;&amp; inst.admitsStack(i))
</del><ins>+                        if (stackSlotEntry != stackSlots.end() &amp;&amp; inst.admitsStack(i)) {
</ins><span class="cx">                             arg = Arg::stack(stackSlotEntry-&gt;value);
</span><ins>+                            didSpill = true;
+                        }
</ins><span class="cx">                     }
</span><span class="cx">                 }
</span><span class="cx"> 
</span><ins>+                if (didSpill &amp;&amp; forceMove32IfDidSpill)
+                    inst.opcode = Move32;
+
</ins><span class="cx">                 // For every other case, add Load/Store as needed.
</span><del>-                inst.forEachTmp([&amp;] (Tmp&amp; tmp, Arg::Role role, Arg::Type argType) {
</del><ins>+                inst.forEachTmp([&amp;] (Tmp&amp; tmp, Arg::Role role, Arg::Type argType, Arg::Width) {
</ins><span class="cx">                     if (tmp.isReg() || argType != type)
</span><span class="cx">                         return;
</span><span class="cx"> 
</span><span class="lines">@@ -1141,7 +1227,18 @@
</span><span class="cx">                     }
</span><span class="cx"> 
</span><span class="cx">                     Arg arg = Arg::stack(stackSlotEntry-&gt;value);
</span><del>-                    Opcode move = type == Arg::GP ? Move : MoveDouble;
</del><ins>+                    Opcode move = Oops;
+                    switch (stackSlotEntry-&gt;value-&gt;byteSize()) {
+                    case 4:
+                        move = type == Arg::GP ? Move32 : MoveFloat;
+                        break;
+                    case 8:
+                        move = type == Arg::GP ? Move : MoveDouble;
+                        break;
+                    default:
+                        RELEASE_ASSERT_NOT_REACHED();
+                        break;
+                    }
</ins><span class="cx"> 
</span><span class="cx">                     if (Arg::isAnyUse(role)) {
</span><span class="cx">                         Tmp newTmp = m_code.newTmp(type);
</span><span class="lines">@@ -1166,6 +1263,7 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     Code&amp; m_code;
</span><ins>+    TmpWidth m_tmpWidth;
</ins><span class="cx">     UseCounts&lt;Tmp&gt; m_useCounts;
</span><span class="cx">     unsigned m_numIterations { 0 };
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirLivenessh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirLiveness.h (194330 => 194331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirLiveness.h        2015-12-21 15:16:58 UTC (rev 194330)
+++ trunk/Source/JavaScriptCore/b3/air/AirLiveness.h        2015-12-21 16:16:01 UTC (rev 194331)
</span><span class="lines">@@ -90,7 +90,7 @@
</span><span class="cx">             typename Adapter::IndexSet&amp; liveAtTail = m_liveAtTail[block];
</span><span class="cx"> 
</span><span class="cx">             block-&gt;last().forEach&lt;typename Adapter::Thing&gt;(
</span><del>-                [&amp;] (typename Adapter::Thing&amp; thing, Arg::Role role, Arg::Type type) {
</del><ins>+                [&amp;] (typename Adapter::Thing&amp; thing, Arg::Role role, Arg::Type type, Arg::Width) {
</ins><span class="cx">                     if (Arg::isLateUse(role) &amp;&amp; Adapter::acceptsType(type))
</span><span class="cx">                         liveAtTail.add(Adapter::valueToIndex(thing));
</span><span class="cx">                 });
</span><span class="lines">@@ -216,14 +216,14 @@
</span><span class="cx">             auto&amp; workset = m_liveness.m_workset;
</span><span class="cx">             // First handle def's.
</span><span class="cx">             inst.forEach&lt;typename Adapter::Thing&gt;(
</span><del>-                [&amp;] (typename Adapter::Thing&amp; thing, Arg::Role role, Arg::Type type) {
</del><ins>+                [&amp;] (typename Adapter::Thing&amp; thing, Arg::Role role, Arg::Type type, Arg::Width) {
</ins><span class="cx">                     if (Arg::isDef(role) &amp;&amp; Adapter::acceptsType(type))
</span><span class="cx">                         workset.remove(Adapter::valueToIndex(thing));
</span><span class="cx">                 });
</span><span class="cx"> 
</span><span class="cx">             // Then handle use's.
</span><span class="cx">             inst.forEach&lt;typename Adapter::Thing&gt;(
</span><del>-                [&amp;] (typename Adapter::Thing&amp; thing, Arg::Role role, Arg::Type type) {
</del><ins>+                [&amp;] (typename Adapter::Thing&amp; thing, Arg::Role role, Arg::Type type, Arg::Width) {
</ins><span class="cx">                     if (Arg::isEarlyUse(role) &amp;&amp; Adapter::acceptsType(type))
</span><span class="cx">                         workset.add(Adapter::valueToIndex(thing));
</span><span class="cx">                 });
</span><span class="lines">@@ -232,7 +232,7 @@
</span><span class="cx">             if (instIndex) {
</span><span class="cx">                 Inst&amp; prevInst = m_block-&gt;at(instIndex - 1);
</span><span class="cx">                 prevInst.forEach&lt;typename Adapter::Thing&gt;(
</span><del>-                    [&amp;] (typename Adapter::Thing&amp; thing, Arg::Role role, Arg::Type type) {
</del><ins>+                    [&amp;] (typename Adapter::Thing&amp; thing, Arg::Role role, Arg::Type type, Arg::Width) {
</ins><span class="cx">                         if (Arg::isLateUse(role) &amp;&amp; Adapter::acceptsType(type))
</span><span class="cx">                             workset.add(Adapter::valueToIndex(thing));
</span><span class="cx">                     });
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirOpcodeopcodes"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes (194330 => 194331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes        2015-12-21 15:16:58 UTC (rev 194330)
+++ trunk/Source/JavaScriptCore/b3/air/AirOpcode.opcodes        2015-12-21 16:16:01 UTC (rev 194331)
</span><span class="lines">@@ -23,14 +23,17 @@
</span><span class="cx"> 
</span><span class="cx"> # Syllabus:
</span><span class="cx"> #
</span><del>-# Roles and types:
-# U:G =&gt; use of a general-purpose register or value
-# D:G =&gt; def of a general-purpose register or value
-# UD:G =&gt; use and def of a general-purpose register or value
-# UA:G =&gt; UseAddr (see comment in Arg.h)
-# U:F =&gt; use of a float register or value
-# D:F =&gt; def of a float register or value
-# UD:F =&gt; use and def of a float register or value
</del><ins>+# Examples of some roles, types, and widths:
+# U:G:32 =&gt; use of the low 32 bits of a general-purpose register or value
+# D:G:32 =&gt; def of the low 32 bits of a general-purpose register or value
+# UD:G:32 =&gt; use and def of the low 32 bits of a general-purpose register or value
+# U:G:64 =&gt; use of the low 64 bits of a general-purpose register or value
+# ZD:G:32 =&gt; def of all bits of a general-purpose register, where all but the low 32 bits are guaranteed to be zeroed.
+# UA:G:Ptr =&gt; UseAddr (see comment in Arg.h)
+# U:F:32 =&gt; use of a float register or value
+# U:F:64 =&gt; use of a double register or value
+# D:F:32 =&gt; def of a float register or value
+# UD:F:32 =&gt; use and def of a float register or value
</ins><span class="cx"> #
</span><span class="cx"> # Argument kinds:
</span><span class="cx"> # Tmp =&gt; temporary or register
</span><span class="lines">@@ -44,11 +47,11 @@
</span><span class="cx"> # of things. So, although this file uses a particular indentation style, none of the whitespace or
</span><span class="cx"> # even newlines are meaningful to the parser. For example, you could write:
</span><span class="cx"> #
</span><del>-# Foo42 U:G, UD:F Imm, Tmp Addr, Tmp
</del><ins>+# Foo42 U:G:32, UD:F:32 Imm, Tmp Addr, Tmp
</ins><span class="cx"> #
</span><span class="cx"> # And the parser would know that this is the same as:
</span><span class="cx"> #
</span><del>-# Foo42 U:G, UD:F
</del><ins>+# Foo42 U:G:32, UD:F:32
</ins><span class="cx"> #     Imm, Tmp
</span><span class="cx"> #     Addr, Tmp
</span><span class="cx"> #
</span><span class="lines">@@ -58,22 +61,22 @@
</span><span class="cx"> # union of those architectures. For example, if this is the only overload of the opcode, then it makes the
</span><span class="cx"> # opcode only available on x86_64:
</span><span class="cx"> #
</span><del>-# x86_64: Fuzz UD:G, D:G
</del><ins>+# x86_64: Fuzz UD:G:64, D:G:64
</ins><span class="cx"> #     Tmp, Tmp
</span><span class="cx"> #     Tmp, Addr
</span><span class="cx"> #
</span><span class="cx"> # But this only restricts the two-operand form, the other form is allowed on all architectures:
</span><span class="cx"> #
</span><del>-# x86_64: Fuzz UD:G, D:G
</del><ins>+# x86_64: Fuzz UD:G:64, D:G:64
</ins><span class="cx"> #     Tmp, Tmp
</span><span class="cx"> #     Tmp, Addr
</span><del>-# Fuzz UD:G, D:G, U:F
</del><ins>+# Fuzz UD:G:Ptr, D:G:Ptr, U:F:Ptr
</ins><span class="cx"> #     Tmp, Tmp, Tmp
</span><span class="cx"> #     Tmp, Addr, Tmp
</span><span class="cx"> #
</span><span class="cx"> # And you can also restrict individual forms:
</span><span class="cx"> #
</span><del>-# Thingy UD:G, D:G
</del><ins>+# Thingy UD:G:32, D:G:32
</ins><span class="cx"> #     Tmp, Tmp
</span><span class="cx"> #     arm64: Tmp, Addr
</span><span class="cx"> #
</span><span class="lines">@@ -81,7 +84,7 @@
</span><span class="cx"> # form. In this example, the version that takes an address is only available on armv7 while the other
</span><span class="cx"> # versions are available on armv7 or x86_64:
</span><span class="cx"> #
</span><del>-# x86_64 armv7: Buzz U:G, UD:F
</del><ins>+# x86_64 armv7: Buzz U:G:32, UD:F:32
</ins><span class="cx"> #     Tmp, Tmp
</span><span class="cx"> #     Imm, Tmp
</span><span class="cx"> #     armv7: Addr, Tmp
</span><span class="lines">@@ -103,214 +106,214 @@
</span><span class="cx"> 
</span><span class="cx"> Nop
</span><span class="cx"> 
</span><del>-Add32 U:G, UD:G
</del><ins>+Add32 U:G:32, UZD:G:32
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     x86: Imm, Addr
</span><span class="cx">     Imm, Tmp
</span><span class="cx">     x86: Addr, Tmp
</span><span class="cx">     x86: Tmp, Addr
</span><span class="cx"> 
</span><del>-Add32 U:G, U:G, D:G
</del><ins>+Add32 U:G:32, U:G:32, ZD:G:32
</ins><span class="cx">     Imm, Tmp, Tmp
</span><span class="cx">     Tmp, Tmp, Tmp
</span><span class="cx"> 
</span><del>-64: Add64 U:G, UD:G
</del><ins>+64: Add64 U:G:64, UD:G:64
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     x86: Imm, Addr
</span><span class="cx">     Imm, Tmp
</span><span class="cx">     x86: Addr, Tmp
</span><span class="cx">     x86: Tmp, Addr
</span><span class="cx"> 
</span><del>-64: Add64 U:G, U:G, D:G
</del><ins>+64: Add64 U:G:64, U:G:64, D:G:64
</ins><span class="cx">     Imm, Tmp, Tmp
</span><span class="cx">     Tmp, Tmp, Tmp
</span><span class="cx"> 
</span><del>-AddDouble U:F, UD:F
</del><ins>+AddDouble U:F:64, UD:F:64
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     x86: Addr, Tmp
</span><span class="cx"> 
</span><del>-AddFloat U:F, UD:F
</del><ins>+AddFloat U:F:32, UD:F:32
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     x86: Addr, Tmp
</span><span class="cx"> 
</span><del>-Sub32 U:G, UD:G
</del><ins>+Sub32 U:G:32, UZD:G:32
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     x86: Imm, Addr
</span><span class="cx">     Imm, Tmp
</span><span class="cx">     x86: Addr, Tmp
</span><span class="cx">     x86: Tmp, Addr
</span><span class="cx"> 
</span><del>-64: Sub64 U:G, UD:G
</del><ins>+64: Sub64 U:G:64, UD:G:64
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     x86: Imm, Addr
</span><span class="cx">     Imm, Tmp
</span><span class="cx">     x86: Addr, Tmp
</span><span class="cx">     x86: Tmp, Addr
</span><span class="cx"> 
</span><del>-SubDouble U:F, UD:F
</del><ins>+SubDouble U:F:64, UD:F:64
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     x86: Addr, Tmp
</span><span class="cx"> 
</span><del>-SubFloat U:F, UD:F
</del><ins>+SubFloat U:F:32, UD:F:32
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     x86: Addr, Tmp
</span><span class="cx"> 
</span><del>-Neg32 UD:G
</del><ins>+Neg32 UZD:G:32
</ins><span class="cx">     Tmp
</span><span class="cx">     Addr
</span><span class="cx"> 
</span><del>-64: Neg64 UD:G
</del><ins>+64: Neg64 UD:G:64
</ins><span class="cx">     Tmp
</span><span class="cx"> 
</span><del>-Mul32 U:G, UD:G
</del><ins>+Mul32 U:G:32, UZD:G:32
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     x86: Addr, Tmp
</span><span class="cx"> 
</span><del>-Mul32 U:G, U:G, D:G
</del><ins>+Mul32 U:G:32, U:G:32, ZD:G:32
</ins><span class="cx">     Imm, Tmp, Tmp
</span><span class="cx"> 
</span><del>-64: Mul64 U:G, UD:G
</del><ins>+64: Mul64 U:G:64, UD:G:64
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx"> 
</span><del>-MulDouble U:F, UD:F
</del><ins>+MulDouble U:F:64, UD:F:64
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     x86: Addr, Tmp
</span><span class="cx"> 
</span><del>-MulFloat U:F, UD:F
</del><ins>+MulFloat U:F:32, UD:F:32
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     x86: Addr, Tmp
</span><span class="cx"> 
</span><del>-DivDouble U:F, UD:F
</del><ins>+DivDouble U:F:32, UD:F:32
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     x86: Addr, Tmp
</span><span class="cx"> 
</span><del>-DivFloat U:F, UD:F
</del><ins>+DivFloat U:F:32, UD:F:32
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     x86: Addr, Tmp
</span><span class="cx"> 
</span><del>-x86: X86ConvertToDoubleWord32 U:G, D:G
</del><ins>+x86: X86ConvertToDoubleWord32 U:G:32, ZD:G:32
</ins><span class="cx">     Tmp*, Tmp*
</span><span class="cx"> 
</span><del>-x86_64: X86ConvertToQuadWord64 U:G, D:G
</del><ins>+x86_64: X86ConvertToQuadWord64 U:G:64, D:G:64
</ins><span class="cx">     Tmp*, Tmp*
</span><span class="cx"> 
</span><del>-x86: X86Div32 UD:G, UD:G, U:G
</del><ins>+x86: X86Div32 UZD:G:32, UZD:G:32, U:G:32
</ins><span class="cx">     Tmp*, Tmp*, Tmp
</span><span class="cx"> 
</span><del>-x86_64: X86Div64 UD:G, UD:G, U:G
</del><ins>+x86_64: X86Div64 UZD:G:64, UZD:G:64, U:G:64
</ins><span class="cx">     Tmp*, Tmp*, Tmp
</span><span class="cx"> 
</span><del>-Lea UA:G, D:G
</del><ins>+Lea UA:G:Ptr, D:G:Ptr
</ins><span class="cx">     Addr, Tmp
</span><span class="cx"> 
</span><del>-And32 U:G, UD:G
</del><ins>+And32 U:G:32, UZD:G:32
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     Imm, Tmp
</span><span class="cx">     x86: Tmp, Addr
</span><span class="cx">     x86: Addr, Tmp
</span><span class="cx">     x86: Imm, Addr
</span><span class="cx"> 
</span><del>-64: And64 U:G, UD:G
</del><ins>+64: And64 U:G:64, UD:G:64
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     Imm, Tmp
</span><span class="cx"> 
</span><del>-AndDouble U:F, UD:F
</del><ins>+AndDouble U:F:64, UD:F:64
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx"> 
</span><del>-AndFloat U:F, UD:F
</del><ins>+AndFloat U:F:32, UD:F:32
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx"> 
</span><del>-Lshift32 U:G, UD:G
</del><ins>+Lshift32 U:G:32, UZD:G:32
</ins><span class="cx">     Tmp*, Tmp
</span><span class="cx">     Imm, Tmp
</span><span class="cx"> 
</span><del>-64: Lshift64 U:G, UD:G
</del><ins>+64: Lshift64 U:G:64, UD:G:64
</ins><span class="cx">     Tmp*, Tmp
</span><span class="cx">     Imm, Tmp
</span><span class="cx"> 
</span><del>-Rshift32 U:G, UD:G
</del><ins>+Rshift32 U:G:32, UZD:G:32
</ins><span class="cx">     Tmp*, Tmp
</span><span class="cx">     Imm, Tmp
</span><span class="cx"> 
</span><del>-64: Rshift64 U:G, UD:G
</del><ins>+64: Rshift64 U:G:64, UD:G:64
</ins><span class="cx">     Tmp*, Tmp
</span><span class="cx">     Imm, Tmp
</span><span class="cx"> 
</span><del>-Urshift32 U:G, UD:G
</del><ins>+Urshift32 U:G:32, UZD:G:32
</ins><span class="cx">     Tmp*, Tmp
</span><span class="cx">     Imm, Tmp
</span><span class="cx"> 
</span><del>-64: Urshift64 U:G, UD:G
</del><ins>+64: Urshift64 U:G:64, UD:G:64
</ins><span class="cx">     Tmp*, Tmp
</span><span class="cx">     Imm, Tmp
</span><span class="cx"> 
</span><del>-Or32 U:G, UD:G
</del><ins>+Or32 U:G:32, UZD:G:32
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     Imm, Tmp
</span><span class="cx">     x86: Tmp, Addr
</span><span class="cx">     x86: Addr, Tmp
</span><span class="cx">     x86: Imm, Addr
</span><span class="cx"> 
</span><del>-64: Or64 U:G, UD:G
</del><ins>+64: Or64 U:G:64, UD:G:64
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     Imm, Tmp
</span><span class="cx"> 
</span><del>-Xor32 U:G, UD:G
</del><ins>+Xor32 U:G:32, UZD:G:32
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     Imm, Tmp
</span><span class="cx">     x86: Tmp, Addr
</span><span class="cx">     x86: Addr, Tmp
</span><span class="cx">     x86: Imm, Addr
</span><span class="cx"> 
</span><del>-64: Xor64 U:G, UD:G
</del><ins>+64: Xor64 U:G:64, UD:G:64
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     x86: Tmp, Addr
</span><span class="cx">     Imm, Tmp
</span><span class="cx"> 
</span><del>-Not32 UD:G
</del><ins>+Not32 UZD:G:32
</ins><span class="cx">     Tmp
</span><span class="cx">     x86: Addr
</span><span class="cx"> 
</span><del>-64: Not64 UD:G
</del><ins>+64: Not64 UD:G:64
</ins><span class="cx">     Tmp
</span><span class="cx">     x86: Addr
</span><span class="cx"> 
</span><del>-CeilDouble U:F, UD:F
</del><ins>+CeilDouble U:F:64, UD:F:64
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     Addr, Tmp
</span><span class="cx"> 
</span><del>-CeilFloat U:F, UD:F
</del><ins>+CeilFloat U:F:32, UD:F:32
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     Addr, Tmp
</span><span class="cx"> 
</span><del>-SqrtDouble U:F, UD:F
</del><ins>+SqrtDouble U:F:64, UD:F:64
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     x86: Addr, Tmp
</span><span class="cx"> 
</span><del>-SqrtFloat U:F, UD:F
</del><ins>+SqrtFloat U:F:32, UD:F:32
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     x86: Addr, Tmp
</span><span class="cx"> 
</span><del>-ConvertInt32ToDouble U:G, D:F
</del><ins>+ConvertInt32ToDouble U:G:32, D:F:64
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     x86: Addr, Tmp
</span><span class="cx"> 
</span><del>-64: ConvertInt64ToDouble U:G, D:F
</del><ins>+64: ConvertInt64ToDouble U:G:64, D:F:64
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx"> 
</span><del>-CountLeadingZeros32 U:G, D:G
</del><ins>+CountLeadingZeros32 U:G:32, ZD:G:32
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     x86: Addr, Tmp
</span><span class="cx"> 
</span><del>-64: CountLeadingZeros64 U:G, D:G
</del><ins>+64: CountLeadingZeros64 U:G:64, D:G:64
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     x86: Addr, Tmp
</span><span class="cx"> 
</span><del>-ConvertDoubleToFloat U:F, D:F
</del><ins>+ConvertDoubleToFloat U:F:64, D:F:32
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     x86: Addr, Tmp
</span><span class="cx"> 
</span><del>-ConvertFloatToDouble U:F, D:F
</del><ins>+ConvertFloatToDouble U:F:32, D:F:64
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     x86: Addr, Tmp
</span><span class="cx"> 
</span><span class="lines">@@ -318,7 +321,7 @@
</span><span class="cx"> # the platform. I'm not entirely sure that this is a good thing; it might be better to just have a
</span><span class="cx"> # Move64 instruction. OTOH, our MacroAssemblers already have this notion of &quot;move()&quot; that basically
</span><span class="cx"> # means movePtr.
</span><del>-Move U:G, D:G
</del><ins>+Move U:G:Ptr, D:G:Ptr
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     Imm, Tmp as signExtend32ToPtr
</span><span class="cx">     Imm64, Tmp
</span><span class="lines">@@ -328,7 +331,7 @@
</span><span class="cx">     Tmp, Index as storePtr
</span><span class="cx">     Imm, Addr as storePtr
</span><span class="cx"> 
</span><del>-Move32 U:G, D:G
</del><ins>+Move32 U:G:32, ZD:G:32
</ins><span class="cx">     Tmp, Tmp as zeroExtend32ToPtr
</span><span class="cx">     Addr, Tmp as load32
</span><span class="cx">     Index, Tmp as load32
</span><span class="lines">@@ -337,118 +340,118 @@
</span><span class="cx">     Imm, Addr as store32
</span><span class="cx">     Imm, Index as store32
</span><span class="cx"> 
</span><del>-SignExtend32ToPtr U:G, D:G
</del><ins>+SignExtend32ToPtr U:G:32, D:G:Ptr
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx"> 
</span><del>-ZeroExtend8To32 U:G, D:G
</del><ins>+ZeroExtend8To32 U:G:8, ZD:G:32
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     Addr, Tmp as load8
</span><span class="cx">     Index, Tmp as load8
</span><span class="cx"> 
</span><del>-SignExtend8To32 U:G, D:G
</del><ins>+SignExtend8To32 U:G:8, ZD:G:32
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     x86: Addr, Tmp as load8SignedExtendTo32
</span><span class="cx">     Index, Tmp as load8SignedExtendTo32
</span><span class="cx"> 
</span><del>-ZeroExtend16To32 U:G, D:G
</del><ins>+ZeroExtend16To32 U:G:16, ZD:G:32
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     Addr, Tmp as load16
</span><span class="cx">     Index, Tmp as load16
</span><span class="cx"> 
</span><del>-SignExtend16To32 U:G, D:G
</del><ins>+SignExtend16To32 U:G:16, ZD:G:32
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     Addr, Tmp as load16SignedExtendTo32
</span><span class="cx">     Index, Tmp as load16SignedExtendTo32
</span><span class="cx"> 
</span><del>-MoveFloat U:F, D:F
</del><ins>+MoveFloat U:F:32, D:F:32
</ins><span class="cx">     Tmp, Tmp as moveDouble
</span><span class="cx">     Addr, Tmp as loadFloat
</span><span class="cx">     Index, Tmp as loadFloat
</span><span class="cx">     Tmp, Addr as storeFloat
</span><span class="cx">     Tmp, Index as storeFloat
</span><span class="cx"> 
</span><del>-MoveDouble U:F, D:F
</del><ins>+MoveDouble U:F:64, D:F:64
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     Addr, Tmp as loadDouble
</span><span class="cx">     Index, Tmp as loadDouble
</span><span class="cx">     Tmp, Addr as storeDouble
</span><span class="cx">     Tmp, Index as storeDouble
</span><span class="cx"> 
</span><del>-MoveZeroToDouble D:F
</del><ins>+MoveZeroToDouble D:F:64
</ins><span class="cx">     Tmp
</span><span class="cx"> 
</span><del>-64: Move64ToDouble U:G, D:F
</del><ins>+64: Move64ToDouble U:G:64, D:F:64
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     Addr, Tmp as loadDouble
</span><span class="cx">     Index, Tmp as loadDouble
</span><span class="cx"> 
</span><del>-MoveInt32ToPacked U:G, D:F
</del><ins>+MoveInt32ToPacked U:G:32, D:F:32
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     Addr, Tmp as loadFloat
</span><span class="cx">     Index, Tmp as loadFloat
</span><span class="cx"> 
</span><del>-64: MoveDoubleTo64 U:F, D:G
</del><ins>+64: MoveDoubleTo64 U:F:64, D:G:64
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     Addr, Tmp as load64
</span><span class="cx">     Index, Tmp as load64
</span><span class="cx"> 
</span><del>-MovePackedToInt32 U:F, D:G
</del><ins>+MovePackedToInt32 U:F:32, D:G:32
</ins><span class="cx">     Tmp, Tmp
</span><span class="cx">     Addr, Tmp as load32
</span><span class="cx">     Index, Tmp as load32
</span><span class="cx"> 
</span><del>-Load8 U:G, D:G
</del><ins>+Load8 U:G:8, ZD:G:32
</ins><span class="cx">     Addr, Tmp
</span><span class="cx">     Index, Tmp
</span><span class="cx"> 
</span><del>-Store8 U:G, D:G
</del><ins>+Store8 U:G:8, D:G:8
</ins><span class="cx">     Tmp, Index
</span><span class="cx">     Tmp, Addr
</span><span class="cx">     Imm, Index
</span><span class="cx">     Imm, Addr
</span><span class="cx"> 
</span><del>-Load8SignedExtendTo32 U:G, D:G
</del><ins>+Load8SignedExtendTo32 U:G:8, ZD:G:32
</ins><span class="cx">     Addr, Tmp
</span><span class="cx">     Index, Tmp
</span><span class="cx"> 
</span><del>-Load16 U:G, D:G
</del><ins>+Load16 U:G:16, ZD:G:32
</ins><span class="cx">     Addr, Tmp
</span><span class="cx">     Index, Tmp
</span><span class="cx"> 
</span><del>-Load16SignedExtendTo32 U:G, D:G
</del><ins>+Load16SignedExtendTo32 U:G:16, ZD:G:32
</ins><span class="cx">     Addr, Tmp
</span><span class="cx">     Index, Tmp
</span><span class="cx"> 
</span><del>-Compare32 U:G, U:G, U:G, D:G
</del><ins>+Compare32 U:G:32, U:G:32, U:G:32, ZD:G:32
</ins><span class="cx">     RelCond, Tmp, Tmp, Tmp
</span><span class="cx">     RelCond, Tmp, Imm, Tmp
</span><span class="cx"> 
</span><del>-64: Compare64 U:G, U:G, U:G, D:G
</del><ins>+64: Compare64 U:G:32, U:G:64, U:G:64, ZD:G:32
</ins><span class="cx">     RelCond, Tmp, Imm, Tmp
</span><span class="cx">     RelCond, Tmp, Tmp, Tmp
</span><span class="cx"> 
</span><del>-Test32 U:G, U:G, U:G, D:G
</del><ins>+Test32 U:G:32, U:G:32, U:G:32, ZD:G:32
</ins><span class="cx">     x86: ResCond, Addr, Imm, Tmp
</span><span class="cx">     ResCond, Tmp, Tmp, Tmp
</span><span class="cx"> 
</span><del>-64: Test64 U:G, U:G, U:G, D:G
</del><ins>+64: Test64 U:G:32, U:G:64, U:G:64, ZD:G:32
</ins><span class="cx">     ResCond, Tmp, Imm, Tmp
</span><span class="cx">     ResCond, Tmp, Tmp, Tmp
</span><span class="cx"> 
</span><del>-CompareDouble U:G, U:F, U:F, D:G
</del><ins>+CompareDouble U:G:32, U:F:64, U:F:64, ZD:G:32
</ins><span class="cx">     DoubleCond, Tmp, Tmp, Tmp
</span><span class="cx"> 
</span><del>-CompareFloat U:G, U:F, U:F, D:G
</del><ins>+CompareFloat U:G:32, U:F:32, U:F:32, ZD:G:32
</ins><span class="cx">     DoubleCond, Tmp, Tmp, Tmp
</span><span class="cx"> 
</span><span class="cx"> # Note that branches have some logic in AirOptimizeBlockOrder.cpp. If you add new branches, please make sure
</span><span class="cx"> # you opt them into the block order optimizations.
</span><span class="cx"> 
</span><del>-Branch8 U:G, U:G, U:G /branch
</del><ins>+Branch8 U:G:32, U:G:8, U:G:8 /branch
</ins><span class="cx">     x86: RelCond, Addr, Imm
</span><span class="cx">     x86: RelCond, Index, Imm
</span><span class="cx"> 
</span><del>-Branch32 U:G, U:G, U:G /branch
</del><ins>+Branch32 U:G:32, U:G:32, U:G:32 /branch
</ins><span class="cx">     x86: RelCond, Addr, Imm
</span><span class="cx">     RelCond, Tmp, Tmp
</span><span class="cx">     RelCond, Tmp, Imm
</span><span class="lines">@@ -456,17 +459,17 @@
</span><span class="cx">     x86: RelCond, Addr, Tmp
</span><span class="cx">     x86: RelCond, Index, Imm
</span><span class="cx"> 
</span><del>-64: Branch64 U:G, U:G, U:G /branch
</del><ins>+64: Branch64 U:G:32, U:G:64, U:G:64 /branch
</ins><span class="cx">     RelCond, Tmp, Tmp
</span><span class="cx">     x86: RelCond, Tmp, Addr
</span><span class="cx">     x86: RelCond, Addr, Tmp
</span><span class="cx">     x86: RelCond, Index, Tmp
</span><span class="cx"> 
</span><del>-BranchTest8 U:G, U:G, U:G /branch
</del><ins>+BranchTest8 U:G:32, U:G:8, U:G:8 /branch
</ins><span class="cx">     x86: ResCond, Addr, Imm
</span><span class="cx">     x86: ResCond, Index, Imm
</span><span class="cx"> 
</span><del>-BranchTest32 U:G, U:G, U:G /branch
</del><ins>+BranchTest32 U:G:32, U:G:32, U:G:32 /branch
</ins><span class="cx">     ResCond, Tmp, Tmp
</span><span class="cx">     ResCond, Tmp, Imm
</span><span class="cx">     x86: ResCond, Addr, Imm
</span><span class="lines">@@ -474,95 +477,95 @@
</span><span class="cx"> 
</span><span class="cx"> # Warning: forms that take an immediate will sign-extend their immediate. You probably want
</span><span class="cx"> # BranchTest32 in most cases where you use an immediate.
</span><del>-64: BranchTest64 U:G, U:G, U:G /branch
</del><ins>+64: BranchTest64 U:G:32, U:G:64, U:G:64 /branch
</ins><span class="cx">     ResCond, Tmp, Tmp
</span><span class="cx">     ResCond, Tmp, Imm
</span><span class="cx">     x86: ResCond, Addr, Imm
</span><span class="cx">     x86: ResCond, Addr, Tmp
</span><span class="cx">     x86: ResCond, Index, Imm
</span><span class="cx"> 
</span><del>-BranchDouble U:G, U:F, U:F /branch
</del><ins>+BranchDouble U:G:32, U:F:64, U:F:64 /branch
</ins><span class="cx">     DoubleCond, Tmp, Tmp
</span><span class="cx"> 
</span><del>-BranchFloat U:G, U:F, U:F /branch
</del><ins>+BranchFloat U:G:32, U:F:32, U:F:32 /branch
</ins><span class="cx">     DoubleCond, Tmp, Tmp
</span><span class="cx"> 
</span><del>-BranchAdd32 U:G, U:G, UD:G /branch
</del><ins>+BranchAdd32 U:G:32, U:G:32, UZD:G:32 /branch
</ins><span class="cx">     ResCond, Tmp, Tmp
</span><span class="cx">     ResCond, Imm, Tmp
</span><span class="cx">     x86: ResCond, Imm, Addr
</span><span class="cx">     x86: ResCond, Tmp, Addr
</span><span class="cx">     x86: ResCond, Addr, Tmp
</span><span class="cx"> 
</span><del>-64: BranchAdd64 U:G, U:G, UD:G /branch
</del><ins>+64: BranchAdd64 U:G:32, U:G:64, UD:G:64 /branch
</ins><span class="cx">     ResCond, Imm, Tmp
</span><span class="cx">     ResCond, Tmp, Tmp
</span><span class="cx"> 
</span><del>-BranchMul32 U:G, U:G, UD:G /branch
</del><ins>+BranchMul32 U:G:32, U:G:32, UZD:G:32 /branch
</ins><span class="cx">     ResCond, Tmp, Tmp
</span><span class="cx">     x86: ResCond, Addr, Tmp
</span><span class="cx"> 
</span><del>-BranchMul32 U:G, U:G, U:G, D:G /branch
</del><ins>+BranchMul32 U:G:32, U:G:32, U:G:32, ZD:G:32 /branch
</ins><span class="cx">     ResCond, Tmp, Imm, Tmp
</span><span class="cx"> 
</span><del>-64: BranchMul64 U:G, U:G, UD:G /branch
</del><ins>+64: BranchMul64 U:G:32, U:G:64, UZD:G:64 /branch
</ins><span class="cx">     ResCond, Tmp, Tmp
</span><span class="cx"> 
</span><del>-BranchSub32 U:G, U:G, UD:G /branch
</del><ins>+BranchSub32 U:G:32, U:G:32, UZD:G:32 /branch
</ins><span class="cx">     ResCond, Tmp, Tmp
</span><span class="cx">     ResCond, Imm, Tmp
</span><span class="cx">     x86: ResCond, Imm, Addr
</span><span class="cx">     x86: ResCond, Tmp, Addr
</span><span class="cx">     x86: ResCond, Addr, Tmp
</span><span class="cx"> 
</span><del>-64: BranchSub64 U:G, U:G, UD:G /branch
</del><ins>+64: BranchSub64 U:G:32, U:G:64, UD:G:64 /branch
</ins><span class="cx">     ResCond, Imm, Tmp
</span><span class="cx">     ResCond, Tmp, Tmp
</span><span class="cx"> 
</span><del>-BranchNeg32 U:G, UD:G /branch
</del><ins>+BranchNeg32 U:G:32, UZD:G:32 /branch
</ins><span class="cx">     ResCond, Tmp
</span><span class="cx"> 
</span><del>-64: BranchNeg64 U:G, UD:G /branch
</del><ins>+64: BranchNeg64 U:G:32, UZD:G:64 /branch
</ins><span class="cx">     ResCond, Tmp
</span><span class="cx"> 
</span><del>-MoveConditionally32 U:G, U:G, U:G, U:G, UD:G
</del><ins>+MoveConditionally32 U:G:32, U:G:32, U:G:32, U:G:Ptr, UD:G:Ptr
</ins><span class="cx">     RelCond, Tmp, Tmp, Tmp, Tmp
</span><span class="cx"> 
</span><del>-64: MoveConditionally64 U:G, U:G, U:G, U:G, UD:G
</del><ins>+64: MoveConditionally64 U:G:32, U:G:64, U:G:64, U:G:Ptr, UD:G:Ptr
</ins><span class="cx">     RelCond, Tmp, Tmp, Tmp, Tmp
</span><span class="cx"> 
</span><del>-MoveConditionallyTest32 U:G, U:G, U:G, U:G, UD:G
</del><ins>+MoveConditionallyTest32 U:G:32, U:G:32, U:G:32, U:G:Ptr, UD:G:Ptr
</ins><span class="cx">     ResCond, Tmp, Tmp, Tmp, Tmp
</span><span class="cx">     ResCond, Tmp, Imm, Tmp, Tmp
</span><span class="cx"> 
</span><del>-64: MoveConditionallyTest64 U:G, U:G, U:G, U:G, UD:G
</del><ins>+64: MoveConditionallyTest64 U:G:32, U:G:64, U:G:64, U:G:Ptr, UD:G:Ptr
</ins><span class="cx">     ResCond, Tmp, Tmp, Tmp, Tmp
</span><span class="cx">     ResCond, Tmp, Imm, Tmp, Tmp
</span><span class="cx"> 
</span><del>-MoveConditionallyDouble U:G, U:F, U:F, U:G, UD:G
</del><ins>+MoveConditionallyDouble U:G:32, U:F:64, U:F:64, U:G:Ptr, UD:G:Ptr
</ins><span class="cx">     DoubleCond, Tmp, Tmp, Tmp, Tmp
</span><span class="cx"> 
</span><del>-MoveConditionallyFloat U:G, U:F, U:F, U:G, UD:G
</del><ins>+MoveConditionallyFloat U:G:32, U:F:32, U:F:32, U:G:Ptr, UD:G:Ptr
</ins><span class="cx">     DoubleCond, Tmp, Tmp, Tmp, Tmp
</span><span class="cx"> 
</span><del>-MoveDoubleConditionally32 U:G, U:G, U:G, U:F, UD:F
</del><ins>+MoveDoubleConditionally32 U:G:32, U:G:32, U:G:32, U:F:64, UD:F:64
</ins><span class="cx">     RelCond, Tmp, Tmp, Tmp, Tmp
</span><span class="cx"> 
</span><del>-64: MoveDoubleConditionally64 U:G, U:G, U:G, U:F, UD:F
</del><ins>+64: MoveDoubleConditionally64 U:G:32, U:G:64, U:G:64, U:F:64, UD:F:64
</ins><span class="cx">     RelCond, Tmp, Tmp, Tmp, Tmp
</span><span class="cx"> 
</span><del>-MoveDoubleConditionallyTest32 U:G, U:G, U:G, U:F, UD:F
</del><ins>+MoveDoubleConditionallyTest32 U:G:32, U:G:32, U:G:32, U:F:64, UD:F:64
</ins><span class="cx">     ResCond, Tmp, Tmp, Tmp, Tmp
</span><span class="cx">     ResCond, Tmp, Imm, Tmp, Tmp
</span><span class="cx"> 
</span><del>-64: MoveDoubleConditionallyTest64 U:G, U:G, U:G, U:F, UD:F
</del><ins>+64: MoveDoubleConditionallyTest64 U:G:32, U:G:64, U:G:64, U:F:64, UD:F:64
</ins><span class="cx">     ResCond, Tmp, Tmp, Tmp, Tmp
</span><span class="cx">     ResCond, Tmp, Imm, Tmp, Tmp
</span><span class="cx"> 
</span><del>-MoveDoubleConditionallyDouble U:G, U:F, U:F, U:F, UD:F
</del><ins>+MoveDoubleConditionallyDouble U:G:32, U:F:64, U:F:64, U:F:64, UD:F:64
</ins><span class="cx">     DoubleCond, Tmp, Tmp, Tmp, Tmp
</span><span class="cx"> 
</span><del>-MoveDoubleConditionallyFloat U:G, U:F, U:F, U:F, UD:F
</del><ins>+MoveDoubleConditionallyFloat U:G:32, U:F:32, U:F:32, U:F:64, UD:F:64
</ins><span class="cx">     DoubleCond, Tmp, Tmp, Tmp, Tmp
</span><span class="cx"> 
</span><span class="cx"> Jump /branch
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirOptimizeBlockOrdercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirOptimizeBlockOrder.cpp (194330 => 194331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirOptimizeBlockOrder.cpp        2015-12-21 15:16:58 UTC (rev 194330)
+++ trunk/Source/JavaScriptCore/b3/air/AirOptimizeBlockOrder.cpp        2015-12-21 16:16:01 UTC (rev 194331)
</span><span class="lines">@@ -148,6 +148,7 @@
</span><span class="cx">         case BranchTest8:
</span><span class="cx">         case BranchTest32:
</span><span class="cx">         case BranchTest64:
</span><ins>+        case BranchFloat:
</ins><span class="cx">         case BranchDouble:
</span><span class="cx">         case BranchAdd32:
</span><span class="cx">         case BranchAdd64:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirSpillEverythingcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirSpillEverything.cpp (194330 => 194331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirSpillEverything.cpp        2015-12-21 15:16:58 UTC (rev 194330)
+++ trunk/Source/JavaScriptCore/b3/air/AirSpillEverything.cpp        2015-12-21 16:16:01 UTC (rev 194331)
</span><span class="lines">@@ -67,7 +67,7 @@
</span><span class="cx">             // code is suboptimal.
</span><span class="cx">             inst.forEachTmpWithExtraClobberedRegs(
</span><span class="cx">                 index &lt; block-&gt;size() ? &amp;block-&gt;at(index) : nullptr,
</span><del>-                [&amp;registerSet] (const Tmp&amp; tmp, Arg::Role role, Arg::Type) {
</del><ins>+                [&amp;registerSet] (const Tmp&amp; tmp, Arg::Role role, Arg::Type, Arg::Width) {
</ins><span class="cx">                     if (tmp.isReg() &amp;&amp; Arg::isDef(role))
</span><span class="cx">                         registerSet.set(tmp.reg());
</span><span class="cx">                 });
</span><span class="lines">@@ -119,7 +119,7 @@
</span><span class="cx"> 
</span><span class="cx">             // Now fall back on spilling using separate Move's to load/store the tmp.
</span><span class="cx">             inst.forEachTmp(
</span><del>-                [&amp;] (Tmp&amp; tmp, Arg::Role role, Arg::Type type) {
</del><ins>+                [&amp;] (Tmp&amp; tmp, Arg::Role role, Arg::Type type, Arg::Width) {
</ins><span class="cx">                     if (tmp.isReg())
</span><span class="cx">                         return;
</span><span class="cx">                     
</span><span class="lines">@@ -140,6 +140,7 @@
</span><span class="cx">                         }
</span><span class="cx">                         break;
</span><span class="cx">                     case Arg::Def:
</span><ins>+                    case Arg::ZDef:
</ins><span class="cx">                         for (Reg reg : regsInPriorityOrder(type)) {
</span><span class="cx">                             if (!setAfter.get(reg)) {
</span><span class="cx">                                 setAfter.set(reg);
</span><span class="lines">@@ -149,6 +150,7 @@
</span><span class="cx">                         }
</span><span class="cx">                         break;
</span><span class="cx">                     case Arg::UseDef:
</span><ins>+                    case Arg::UseZDef:
</ins><span class="cx">                     case Arg::LateUse:
</span><span class="cx">                         for (Reg reg : regsInPriorityOrder(type)) {
</span><span class="cx">                             if (!setBefore.get(reg) &amp;&amp; !setAfter.get(reg)) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirTmpWidthcpp"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/b3/air/AirTmpWidth.cpp (0 => 194331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirTmpWidth.cpp                                (rev 0)
+++ trunk/Source/JavaScriptCore/b3/air/AirTmpWidth.cpp        2015-12-21 16:16:01 UTC (rev 194331)
</span><span class="lines">@@ -0,0 +1,144 @@
</span><ins>+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include &quot;config.h&quot;
+#include &quot;AirTmpWidth.h&quot;
+
+#if ENABLE(B3_JIT)
+
+#include &quot;AirCode.h&quot;
+#include &quot;AirInstInlines.h&quot;
+
+namespace JSC { namespace B3 { namespace Air {
+
+TmpWidth::TmpWidth()
+{
+}
+
+TmpWidth::TmpWidth(Code&amp; code)
+{
+    recompute(code);
+}
+
+TmpWidth::~TmpWidth()
+{
+}
+
+void TmpWidth::recompute(Code&amp; code)
+{
+    m_width.clear();
+    
+    // Assume the worst for registers.
+    RegisterSet::allRegisters().forEach(
+        [&amp;] (Reg reg) {
+            Widths&amp; widths = m_width.add(Tmp(reg), Widths()).iterator-&gt;value;
+            Arg::Type type = Arg(Tmp(reg)).type();
+            widths.use = Arg::conservativeWidth(type);
+            widths.def = Arg::conservativeWidth(type);
+        });
+    
+    // Now really analyze everything but Move's over Tmp's, but set aside those Move's so we can find
+    // them quickly during the fixpoint below. Note that we can make this analysis stronger by
+    // recognizing more kinds of Move's or anything that has Move-like behavior, though it's probably not
+    // worth it.
+    Vector&lt;Inst*&gt; moves;
+    for (BasicBlock* block : code) {
+        for (Inst&amp; inst : *block) {
+            if (inst.opcode == Move &amp;&amp; inst.args[1].isTmp()) {
+                if (inst.args[0].isTmp()) {
+                    moves.append(&amp;inst);
+                    continue;
+                }
+                if (inst.args[0].isImm()
+                    &amp;&amp; inst.args[0].value() &gt;= 0) {
+                    Tmp tmp = inst.args[1].tmp();
+                    Widths&amp; widths = m_width.add(tmp, Widths(Arg::GP)).iterator-&gt;value;
+                    
+                    if (inst.args[0].value() &lt;= std::numeric_limits&lt;int8_t&gt;::max())
+                        widths.def = std::max(widths.def, Arg::Width8);
+                    else if (inst.args[0].value() &lt;= std::numeric_limits&lt;int16_t&gt;::max())
+                        widths.def = std::max(widths.def, Arg::Width16);
+                    else if (inst.args[0].value() &lt;= std::numeric_limits&lt;int32_t&gt;::max())
+                        widths.def = std::max(widths.def, Arg::Width32);
+                    else
+                        widths.def = std::max(widths.def, Arg::Width64);
+
+                    continue;
+                }
+            }
+            inst.forEachTmp(
+                [&amp;] (Tmp&amp; tmp, Arg::Role role, Arg::Type type, Arg::Width width) {
+                    Widths&amp; widths = m_width.add(tmp, Widths(type)).iterator-&gt;value;
+                    
+                    if (Arg::isAnyUse(role))
+                        widths.use = std::max(widths.use, width);
+
+                    if (Arg::isZDef(role))
+                        widths.def = std::max(widths.def, width);
+                    else if (Arg::isDef(role))
+                        widths.def = Arg::conservativeWidth(type);
+                });
+        }
+    }
+
+    // Finally, fixpoint over the Move's.
+    bool changed = true;
+    while (changed) {
+        changed = false;
+        for (Inst* move : moves) {
+            ASSERT(move-&gt;opcode == Move);
+            ASSERT(move-&gt;args[0].isTmp());
+            ASSERT(move-&gt;args[1].isTmp());
+            
+            Widths&amp; srcWidths = m_width.add(move-&gt;args[0].tmp(), Widths(Arg::GP)).iterator-&gt;value;
+            Widths&amp; dstWidths = m_width.add(move-&gt;args[1].tmp(), Widths(Arg::GP)).iterator-&gt;value;
+
+            // Legend:
+            //
+            //     Move %src, %dst
+
+            // defWidth(%dst) is a promise about how many high bits are zero. The smaller the width, the
+            // stronger the promise. This Move may weaken that promise if we know that %src is making a
+            // weaker promise. Such forward flow is the only thing that determines defWidth().
+            if (dstWidths.def &lt; srcWidths.def) {
+                dstWidths.def = srcWidths.def;
+                changed = true;
+            }
+
+            // srcWidth(%src) is a promise about how many high bits are ignored. The smaller the width,
+            // the stronger the promise. This Move may weaken that promise if we know that %dst is making
+            // a weaker promise. Such backward flow is the only thing that determines srcWidth().
+            if (srcWidths.use &lt; dstWidths.use) {
+                srcWidths.use = dstWidths.use;
+                changed = true;
+            }
+        }
+    }
+}
+
+} } } // namespace JSC::B3::Air
+
+#endif // ENABLE(B3_JIT)
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirTmpWidthh"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/b3/air/AirTmpWidth.h (0 => 194331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirTmpWidth.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/b3/air/AirTmpWidth.h        2015-12-21 16:16:01 UTC (rev 194331)
</span><span class="lines">@@ -0,0 +1,108 @@
</span><ins>+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef AirTmpWidth_h
+#define AirTmpWidth_h
+
+#if ENABLE(B3_JIT)
+
+#include &quot;AirArg.h&quot;
+#include &lt;wtf/HashSet.h&gt;
+
+namespace JSC { namespace B3 { namespace Air {
+
+class Code;
+
+class TmpWidth {
+public:
+    TmpWidth();
+    TmpWidth(Code&amp;);
+    ~TmpWidth();
+
+    void recompute(Code&amp;);
+
+    // The width of a Tmp is the number of bits that you need to be able to track without some trivial
+    // recovery. A Tmp may have a &quot;subwidth&quot; (say, Width32 on a 64-bit system) if either of the following
+    // is true:
+    //
+    // - The high bits are never read.
+    // - The high bits are always zero.
+    //
+    // This doesn't tell you which of those properties holds, but you can query that using the other
+    // methods.
+    Arg::Width width(Tmp tmp) const
+    {
+        auto iter = m_width.find(tmp);
+        if (iter == m_width.end())
+            return Arg::minimumWidth(Arg(tmp).type());
+        return std::min(iter-&gt;value.use, iter-&gt;value.def);
+    }
+
+    // This indirectly tells you how much of the tmp's high bits are guaranteed to be zero. The number of
+    // high bits that are zero are:
+    //
+    //     TotalBits - defWidth(tmp)
+    //
+    // Where TotalBits are the total number of bits in the register, so 64 on a 64-bit system.
+    Arg::Width defWidth(Tmp tmp) const
+    {
+        auto iter = m_width.find(tmp);
+        if (iter == m_width.end())
+            return Arg::minimumWidth(Arg(tmp).type());
+        return iter-&gt;value.def;
+    }
+
+    // This tells you how much of Tmp is going to be read.
+    Arg::Width useWidth(Tmp tmp) const
+    {
+        auto iter = m_width.find(tmp);
+        if (iter == m_width.end())
+            return Arg::minimumWidth(Arg(tmp).type());
+        return iter-&gt;value.use;
+    }
+    
+private:
+    struct Widths {
+        Widths() { }
+
+        Widths(Arg::Type type)
+        {
+            use = Arg::minimumWidth(type);
+            def = Arg::minimumWidth(type);
+        }
+        
+        Arg::Width use;
+        Arg::Width def;
+    };
+    
+    HashMap&lt;Tmp, Widths&gt; m_width;
+};
+
+} } } // namespace JSC::B3::Air
+
+#endif // ENABLE(B3_JIT)
+
+#endif // AirTmpWidth_h
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirUseCountsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirUseCounts.h (194330 => 194331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirUseCounts.h        2015-12-21 15:16:58 UTC (rev 194330)
+++ trunk/Source/JavaScriptCore/b3/air/AirUseCounts.h        2015-12-21 16:16:01 UTC (rev 194331)
</span><span class="lines">@@ -77,7 +77,7 @@
</span><span class="cx">                 frequency *= Options::rareBlockPenalty();
</span><span class="cx">             for (Inst&amp; inst : *block) {
</span><span class="cx">                 inst.forEach&lt;Thing&gt;(
</span><del>-                    [&amp;] (Thing&amp; arg, Arg::Role role, Arg::Type) {
</del><ins>+                    [&amp;] (Thing&amp; arg, Arg::Role role, Arg::Type, Arg::Width) {
</ins><span class="cx">                         Counts&amp; counts = m_counts.add(arg, Counts()).iterator-&gt;value;
</span><span class="cx"> 
</span><span class="cx">                         if (Arg::isWarmUse(role))
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airopcode_generatorrb"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/opcode_generator.rb (194330 => 194331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/opcode_generator.rb        2015-12-21 15:16:58 UTC (rev 194330)
+++ trunk/Source/JavaScriptCore/b3/air/opcode_generator.rb        2015-12-21 16:16:01 UTC (rev 194331)
</span><span class="lines">@@ -44,11 +44,12 @@
</span><span class="cx"> end
</span><span class="cx"> 
</span><span class="cx"> class Arg
</span><del>-    attr_reader :role, :type
</del><ins>+    attr_reader :role, :type, :width
</ins><span class="cx"> 
</span><del>-    def initialize(role, type)
</del><ins>+    def initialize(role, type, width)
</ins><span class="cx">         @role = role
</span><span class="cx">         @type = type
</span><ins>+        @width = width
</ins><span class="cx">     end
</span><span class="cx"> end
</span><span class="cx"> 
</span><span class="lines">@@ -173,7 +174,7 @@
</span><span class="cx"> end
</span><span class="cx"> 
</span><span class="cx"> def isUD(token)
</span><del>-    token =~ /\A((U)|(D)|(UD)|(UA))\Z/
</del><ins>+    token =~ /\A((U)|(D)|(UD)|(ZD)|(UZD)|(UA))\Z/
</ins><span class="cx"> end
</span><span class="cx"> 
</span><span class="cx"> def isGF(token)
</span><span class="lines">@@ -188,8 +189,12 @@
</span><span class="cx">     token =~ /\A((x86)|(x86_32)|(x86_64)|(arm)|(armv7)|(arm64)|(32)|(64))\Z/
</span><span class="cx"> end
</span><span class="cx"> 
</span><ins>+def isWidth(token)
+    token =~ /\A((8)|(16)|(32)|(64)|(Ptr))\Z/
+end
+
</ins><span class="cx"> def isKeyword(token)
</span><del>-    isUD(token) or isGF(token) or isKind(token) or isArch(token) or
</del><ins>+    isUD(token) or isGF(token) or isKind(token) or isArch(token) or isWidth(token) or
</ins><span class="cx">         token == &quot;special&quot; or token == &quot;as&quot;
</span><span class="cx"> end
</span><span class="cx"> 
</span><span class="lines">@@ -256,6 +261,13 @@
</span><span class="cx">         result
</span><span class="cx">     end
</span><span class="cx"> 
</span><ins>+    def consumeWidth
+        result = token.string
+        parseError(&quot;Expected width (8, 16, 32, or 64)&quot;) unless isWidth(result)
+        advance
+        result
+    end
+
</ins><span class="cx">     def parseArchs
</span><span class="cx">         return nil unless isArch(token)
</span><span class="cx"> 
</span><span class="lines">@@ -350,8 +362,10 @@
</span><span class="cx">                         role = consumeRole
</span><span class="cx">                         consume(&quot;:&quot;)
</span><span class="cx">                         type = consumeType
</span><ins>+                        consume(&quot;:&quot;)
+                        width = consumeWidth
</ins><span class="cx">                         
</span><del>-                        signature &lt;&lt; Arg.new(role, type)
</del><ins>+                        signature &lt;&lt; Arg.new(role, type, width)
</ins><span class="cx">                         
</span><span class="cx">                         break unless token == &quot;,&quot;
</span><span class="cx">                         consume(&quot;,&quot;)
</span><span class="lines">@@ -606,26 +620,37 @@
</span><span class="cx">     matchInstOverload(outp, :fast, &quot;this&quot;) {
</span><span class="cx">         | opcode, overload |
</span><span class="cx">         if opcode.special
</span><del>-            outp.puts &quot;functor(args[0], Arg::Use, Arg::GP); // This is basically bogus, but it works f analyses model Special as an immediate.&quot;
</del><ins>+            outp.puts &quot;functor(args[0], Arg::Use, Arg::GP, Arg::pointerWidth()); // This is basically bogus, but it works for analyses that model Special as an immediate.&quot;
</ins><span class="cx">             outp.puts &quot;args[0].special()-&gt;forEachArg(*this, scopedLambda&lt;EachArgCallback&gt;(functor));&quot;
</span><span class="cx">         else
</span><span class="cx">             overload.signature.each_with_index {
</span><span class="cx">                 | arg, index |
</span><ins>+                
</ins><span class="cx">                 role = nil
</span><span class="cx">                 case arg.role
</span><span class="cx">                 when &quot;U&quot;
</span><span class="cx">                     role = &quot;Use&quot;
</span><span class="cx">                 when &quot;D&quot;
</span><span class="cx">                     role = &quot;Def&quot;
</span><ins>+                when &quot;ZD&quot;
+                    role = &quot;ZDef&quot;
</ins><span class="cx">                 when &quot;UD&quot;
</span><span class="cx">                     role = &quot;UseDef&quot;
</span><ins>+                when &quot;UZD&quot;
+                    role = &quot;UseZDef&quot;
</ins><span class="cx">                 when &quot;UA&quot;
</span><span class="cx">                     role = &quot;UseAddr&quot;
</span><span class="cx">                 else
</span><span class="cx">                     raise
</span><span class="cx">                 end
</span><ins>+
+                if arg.width == &quot;Ptr&quot;
+                    width = &quot;Arg::pointerWidth()&quot;
+                else
+                    width = &quot;Arg::Width#{arg.width}&quot;
+                end
</ins><span class="cx">                 
</span><del>-                outp.puts &quot;functor(args[#{index}], Arg::#{role}, Arg::#{arg.type}P);&quot;
</del><ins>+                outp.puts &quot;functor(args[#{index}], Arg::#{role}, Arg::#{arg.type}P, #{width});&quot;
</ins><span class="cx">             }
</span><span class="cx">         end
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3testb3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/testb3.cpp (194330 => 194331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/testb3.cpp        2015-12-21 15:16:58 UTC (rev 194330)
+++ trunk/Source/JavaScriptCore/b3/testb3.cpp        2015-12-21 16:16:01 UTC (rev 194331)
</span><span class="lines">@@ -6368,6 +6368,61 @@
</span><span class="cx">     CHECK(invoke&lt;int&gt;(*code, &amp;value - 2, 1) == 42);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void testCheckTrickyMegaCombo()
+{
+    Procedure proc;
+    BasicBlock* root = proc.addBlock();
+    Value* base = root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR0);
+    Value* index = root-&gt;appendNew&lt;Value&gt;(
+        proc, ZExt32, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(
+            proc, Add, Origin(),
+            root-&gt;appendNew&lt;Value&gt;(
+                proc, Trunc, Origin(),
+                root-&gt;appendNew&lt;ArgumentRegValue&gt;(proc, Origin(), GPRInfo::argumentGPR1)),
+            root-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), 1)));
+
+    Value* ptr = root-&gt;appendNew&lt;Value&gt;(
+        proc, Add, Origin(), base,
+        root-&gt;appendNew&lt;Value&gt;(
+            proc, Shl, Origin(), index,
+            root-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), 1)));
+    
+    CheckValue* check = root-&gt;appendNew&lt;CheckValue&gt;(
+        proc, Check, Origin(),
+        root-&gt;appendNew&lt;Value&gt;(
+            proc, LessThan, Origin(),
+            root-&gt;appendNew&lt;MemoryValue&gt;(proc, Load8S, Origin(), ptr),
+            root-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), 42)));
+    check-&gt;setGenerator(
+        [&amp;] (CCallHelpers&amp; jit, const StackmapGenerationParams&amp; params) {
+            AllowMacroScratchRegisterUsage allowScratch(jit);
+            CHECK(!params.size());
+
+            // This should always work because a function this simple should never have callee
+            // saves.
+            jit.move(CCallHelpers::TrustedImm32(42), GPRInfo::returnValueGPR);
+            jit.emitFunctionEpilogue();
+            jit.ret();
+        });
+    root-&gt;appendNew&lt;ControlValue&gt;(
+        proc, Return, Origin(), root-&gt;appendNew&lt;Const32Value&gt;(proc, Origin(), 0));
+
+    auto code = compile(proc);
+
+    int8_t value;
+    value = 42;
+    CHECK(invoke&lt;int&gt;(*code, &amp;value - 2, 0) == 0);
+    value = 127;
+    CHECK(invoke&lt;int&gt;(*code, &amp;value - 2, 0) == 0);
+    value = 41;
+    CHECK(invoke&lt;int&gt;(*code, &amp;value - 2, 0) == 42);
+    value = 0;
+    CHECK(invoke&lt;int&gt;(*code, &amp;value - 2, 0) == 42);
+    value = -1;
+    CHECK(invoke&lt;int&gt;(*code, &amp;value - 2, 0) == 42);
+}
+
</ins><span class="cx"> void testCheckTwoMegaCombos()
</span><span class="cx"> {
</span><span class="cx">     Procedure proc;
</span><span class="lines">@@ -9474,6 +9529,7 @@
</span><span class="cx">     RUN(testSimpleCheck());
</span><span class="cx">     RUN(testCheckLessThan());
</span><span class="cx">     RUN(testCheckMegaCombo());
</span><ins>+    RUN(testCheckTrickyMegaCombo());
</ins><span class="cx">     RUN(testCheckTwoMegaCombos());
</span><span class="cx">     RUN(testCheckTwoNonRedundantMegaCombos());
</span><span class="cx">     RUN(testCheckAddImm());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (194330 => 194331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2015-12-21 15:16:58 UTC (rev 194330)
+++ trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2015-12-21 16:16:01 UTC (rev 194331)
</span><span class="lines">@@ -4218,10 +4218,17 @@
</span><span class="cx">         LValue length = m_out.load32(kids[0], m_heaps.JSString_length);
</span><span class="cx">         for (unsigned i = 1; i &lt; numKids; ++i) {
</span><span class="cx">             flags = m_out.bitAnd(flags, m_out.load32(kids[i], m_heaps.JSString_flags));
</span><ins>+#if FTL_USES_B3
+            B3::CheckValue* lengthCheck = m_out.speculateAdd(
+                length, m_out.load32(kids[i], m_heaps.JSString_length));
+            blessSpeculation(lengthCheck, Uncountable, noValue(), nullptr, m_origin);
+            length = lengthCheck;
+#else // FTL_USES_B3            
</ins><span class="cx">             LValue lengthAndOverflow = m_out.addWithOverflow32(
</span><span class="cx">                 length, m_out.load32(kids[i], m_heaps.JSString_length));
</span><span class="cx">             speculate(Uncountable, noValue(), 0, m_out.extractValue(lengthAndOverflow, 1));
</span><span class="cx">             length = m_out.extractValue(lengthAndOverflow, 0);
</span><ins>+#endif // FTL_USES_B3
</ins><span class="cx">         }
</span><span class="cx">         m_out.store32(
</span><span class="cx">             m_out.bitAnd(m_out.constInt32(JSString::Is8Bit), flags),
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLOSRExitHandlecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLOSRExitHandle.cpp (194330 => 194331)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLOSRExitHandle.cpp        2015-12-21 15:16:58 UTC (rev 194330)
+++ trunk/Source/JavaScriptCore/ftl/FTLOSRExitHandle.cpp        2015-12-21 16:16:01 UTC (rev 194331)
</span><span class="lines">@@ -39,9 +39,10 @@
</span><span class="cx">     label = jit.label();
</span><span class="cx">     jit.pushToSaveImmediateWithoutTouchingRegisters(CCallHelpers::TrustedImm32(index));
</span><span class="cx">     CCallHelpers::PatchableJump jump = jit.patchableJump();
</span><ins>+    RefPtr&lt;OSRExitHandle&gt; self = this;
</ins><span class="cx">     jit.addLinkTask(
</span><del>-        [this, jump] (LinkBuffer&amp; linkBuffer) {
-            exit.m_patchableJump = CodeLocationJump(linkBuffer.locationOf(jump));
</del><ins>+        [self, jump] (LinkBuffer&amp; linkBuffer) {
+            self-&gt;exit.m_patchableJump = CodeLocationJump(linkBuffer.locationOf(jump));
</ins><span class="cx"> 
</span><span class="cx">             linkBuffer.link(
</span><span class="cx">                 jump.m_jump,
</span></span></pre>
</div>
</div>

</body>
</html>