<!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>[192135] 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/192135">192135</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2015-11-07 18:10:57 -0800 (Sat, 07 Nov 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>B3-&gt;Air lowering should do pattern matching the old fashioned way
https://bugs.webkit.org/show_bug.cgi?id=150994

Reviewed by Geoffrey Garen.

When I first wrote the B3-&gt;Air lowering prototype, I was convinced that the patterns would get
so gnarly that we'd want a pattern language to write them in. So I made one, and that's what
the lowering has used. But as we've worked with the IR, we've found that it's very easy to
pattern match in C++ using the B3 API, and we've also found that most of the patterns we wrote
using the pattern language were mostly trivial. So this change removes the pattern match code
generator and the patterns files, and redoes the lowering using good old fashioned switch
statements. This actually reduces the total code of the lowering.

I also took the opportunity to refactoring UnOp and BinOp lowering. We had a lot of repetetive
code for 32-vs-64-bit opcode selection, so I factored that out into a helper. This also saves a
lot of code.

* CMakeLists.txt:
* DerivedSources.make:
* b3/B3AddressMatcher.patterns: Removed.
* b3/B3LowerToAir.cpp:
(JSC::B3::Air::LowerToAir::LowerToAir):
(JSC::B3::Air::LowerToAir::run):
(JSC::B3::Air::LowerToAir::highBitsAreZero):
(JSC::B3::Air::LowerToAir::tmp):
(JSC::B3::Air::LowerToAir::canBeInternal):
(JSC::B3::Air::LowerToAir::commitInternal):
(JSC::B3::Air::LowerToAir::crossesInterference):
(JSC::B3::Air::LowerToAir::effectiveAddr):
(JSC::B3::Air::LowerToAir::addr):
(JSC::B3::Air::LowerToAir::loadPromise):
(JSC::B3::Air::LowerToAir::imm):
(JSC::B3::Air::LowerToAir::immForMove):
(JSC::B3::Air::LowerToAir::immOrTmpForMove):
(JSC::B3::Air::LowerToAir::tryOpcodeForType):
(JSC::B3::Air::LowerToAir::opcodeForType):
(JSC::B3::Air::LowerToAir::appendUnOp):
(JSC::B3::Air::LowerToAir::appendBinOp):
(JSC::B3::Air::LowerToAir::appendShift):
(JSC::B3::Air::LowerToAir::tryAppendStoreUnOp):
(JSC::B3::Air::LowerToAir::tryAppendStoreBinOp):
(JSC::B3::Air::LowerToAir::append):
(JSC::B3::Air::LowerToAir::ensureSpecial):
(JSC::B3::Air::LowerToAir::fillStackmap):
(JSC::B3::Air::LowerToAir::createGenericCompare):
(JSC::B3::Air::LowerToAir::createBranch):
(JSC::B3::Air::LowerToAir::createCompare):
(JSC::B3::Air::LowerToAir::lower):
(JSC::B3::Air::LowerToAir::immOrTmp): Deleted.
(JSC::B3::Air::LowerToAir::AddressSelector::AddressSelector): Deleted.
(JSC::B3::Air::LowerToAir::AddressSelector::acceptRoot): Deleted.
(JSC::B3::Air::LowerToAir::AddressSelector::acceptRootLate): Deleted.
(JSC::B3::Air::LowerToAir::AddressSelector::acceptInternals): Deleted.
(JSC::B3::Air::LowerToAir::AddressSelector::acceptInternalsLate): Deleted.
(JSC::B3::Air::LowerToAir::AddressSelector::acceptOperands): Deleted.
(JSC::B3::Air::LowerToAir::AddressSelector::acceptOperandsLate): Deleted.
(JSC::B3::Air::LowerToAir::AddressSelector::tryAddShift1): Deleted.
(JSC::B3::Air::LowerToAir::AddressSelector::tryAddShift2): Deleted.
(JSC::B3::Air::LowerToAir::AddressSelector::tryAdd): Deleted.
(JSC::B3::Air::LowerToAir::AddressSelector::tryFramePointer): Deleted.
(JSC::B3::Air::LowerToAir::AddressSelector::tryStackSlot): Deleted.
(JSC::B3::Air::LowerToAir::AddressSelector::tryDirect): Deleted.
(JSC::B3::Air::LowerToAir::acceptRoot): Deleted.
(JSC::B3::Air::LowerToAir::acceptRootLate): Deleted.
(JSC::B3::Air::LowerToAir::acceptInternals): Deleted.
(JSC::B3::Air::LowerToAir::acceptInternalsLate): Deleted.
(JSC::B3::Air::LowerToAir::acceptOperands): Deleted.
(JSC::B3::Air::LowerToAir::acceptOperandsLate): Deleted.
(JSC::B3::Air::LowerToAir::tryLoad): Deleted.
(JSC::B3::Air::LowerToAir::tryLoad8S): Deleted.
(JSC::B3::Air::LowerToAir::tryLoad8Z): Deleted.
(JSC::B3::Air::LowerToAir::tryLoad16S): Deleted.
(JSC::B3::Air::LowerToAir::tryLoad16Z): Deleted.
(JSC::B3::Air::LowerToAir::tryAdd): Deleted.
(JSC::B3::Air::LowerToAir::trySub): Deleted.
(JSC::B3::Air::LowerToAir::tryAnd): Deleted.
(JSC::B3::Air::LowerToAir::tryOr): Deleted.
(JSC::B3::Air::LowerToAir::tryXor): Deleted.
(JSC::B3::Air::LowerToAir::tryShl): Deleted.
(JSC::B3::Air::LowerToAir::trySShr): Deleted.
(JSC::B3::Air::LowerToAir::tryZShr): Deleted.
(JSC::B3::Air::LowerToAir::tryStoreAddLoad): Deleted.
(JSC::B3::Air::LowerToAir::tryStoreSubLoad): Deleted.
(JSC::B3::Air::LowerToAir::tryStoreAndLoad): Deleted.
(JSC::B3::Air::LowerToAir::tryStore): Deleted.
(JSC::B3::Air::LowerToAir::tryTrunc): Deleted.
(JSC::B3::Air::LowerToAir::tryZExt32): Deleted.
(JSC::B3::Air::LowerToAir::tryArgumentReg): Deleted.
(JSC::B3::Air::LowerToAir::tryConst32): Deleted.
(JSC::B3::Air::LowerToAir::tryConst64): Deleted.
(JSC::B3::Air::LowerToAir::tryFramePointer): Deleted.
(JSC::B3::Air::LowerToAir::tryStackSlot): Deleted.
(JSC::B3::Air::LowerToAir::tryEqual): Deleted.
(JSC::B3::Air::LowerToAir::tryNotEqual): Deleted.
(JSC::B3::Air::LowerToAir::tryLessThan): Deleted.
(JSC::B3::Air::LowerToAir::tryGreaterThan): Deleted.
(JSC::B3::Air::LowerToAir::tryLessEqual): Deleted.
(JSC::B3::Air::LowerToAir::tryGreaterEqual): Deleted.
(JSC::B3::Air::LowerToAir::tryAbove): Deleted.
(JSC::B3::Air::LowerToAir::tryBelow): Deleted.
(JSC::B3::Air::LowerToAir::tryAboveEqual): Deleted.
(JSC::B3::Air::LowerToAir::tryBelowEqual): Deleted.
(JSC::B3::Air::LowerToAir::tryPatchpoint): Deleted.
(JSC::B3::Air::LowerToAir::tryCheck): Deleted.
(JSC::B3::Air::LowerToAir::tryUpsilon): Deleted.
(JSC::B3::Air::LowerToAir::tryPhi): Deleted.
(JSC::B3::Air::LowerToAir::tryBranch): Deleted.
(JSC::B3::Air::LowerToAir::tryJump): Deleted.
(JSC::B3::Air::LowerToAir::tryIdentity): Deleted.
(JSC::B3::Air::LowerToAir::tryReturn): Deleted.
* b3/B3LoweringMatcher.patterns: Removed.
* b3/generate_pattern_matcher.rb: Removed.</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="#trunkSourceJavaScriptCoreDerivedSourcesmake">trunk/Source/JavaScriptCore/DerivedSources.make</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3LowerToAircpp">trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp</a></li>
</ul>

<h3>Removed Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreb3B3AddressMatcherpatterns">trunk/Source/JavaScriptCore/b3/B3AddressMatcher.patterns</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3LoweringMatcherpatterns">trunk/Source/JavaScriptCore/b3/B3LoweringMatcher.patterns</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3generate_pattern_matcherrb">trunk/Source/JavaScriptCore/b3/generate_pattern_matcher.rb</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreCMakeListstxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/CMakeLists.txt (192134 => 192135)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/CMakeLists.txt        2015-11-08 01:29:22 UTC (rev 192134)
+++ trunk/Source/JavaScriptCore/CMakeLists.txt        2015-11-08 02:10:57 UTC (rev 192135)
</span><span class="lines">@@ -1223,22 +1223,6 @@
</span><span class="cx"> )
</span><span class="cx"> 
</span><span class="cx"> add_custom_command(
</span><del>-    OUTPUT ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/B3AddressMatcher.h
-    MAIN_DEPENDENCY ${JAVASCRIPTCORE_DIR}/b3/B3AddressMatcher.patterns
-    DEPENDS ${JAVASCRIPTCORE_DIR}/b3/generate_pattern_matcher.rb
-    COMMAND ${RUBY_EXECUTABLE} ${JAVASCRIPTCORE_DIR}/b3/generate_pattern_matcher.rb ${JAVASCRIPTCORE_DIR}/b3/B3AddressMatcher.patterns VERBATIM
-    WORKING_DIRECTORY ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}
-)
-
-add_custom_command(
-    OUTPUT ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/B3LoweringMatcher.h
-    MAIN_DEPENDENCY ${JAVASCRIPTCORE_DIR}/b3/B3LoweringMatcher.patterns
-    DEPENDS ${JAVASCRIPTCORE_DIR}/b3/generate_pattern_matcher.rb
-    COMMAND ${RUBY_EXECUTABLE} ${JAVASCRIPTCORE_DIR}/b3/generate_pattern_matcher.rb ${JAVASCRIPTCORE_DIR}/b3/B3LoweringMatcher.patterns VERBATIM
-    WORKING_DIRECTORY ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}
-)
-
-add_custom_command(
</del><span class="cx">     OUTPUT ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/AirOpcode.h ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/AirOpcodeGenerated.h
</span><span class="cx">     MAIN_DEPENDENCY ${JAVASCRIPTCORE_DIR}/b3/air/AirOpcode.opcodes
</span><span class="cx">     DEPENDS ${JAVASCRIPTCORE_DIR}/b3/air/opcode_generator.rb
</span><span class="lines">@@ -1249,8 +1233,6 @@
</span><span class="cx"> list(APPEND JavaScriptCore_SOURCES
</span><span class="cx">     ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/AirOpcode.h
</span><span class="cx">     ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/AirOpcodeGenerated.h
</span><del>-    ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/B3AddressMatcher.h
-    ${DERIVED_SOURCES_JAVASCRIPTCORE_DIR}/B3LoweringMatcher.h
</del><span class="cx"> )
</span><span class="cx"> 
</span><span class="cx"> add_custom_command(
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (192134 => 192135)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-11-08 01:29:22 UTC (rev 192134)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-11-08 02:10:57 UTC (rev 192135)
</span><span class="lines">@@ -1,3 +1,118 @@
</span><ins>+2015-11-06  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        B3-&gt;Air lowering should do pattern matching the old fashioned way
+        https://bugs.webkit.org/show_bug.cgi?id=150994
+
+        Reviewed by Geoffrey Garen.
+
+        When I first wrote the B3-&gt;Air lowering prototype, I was convinced that the patterns would get
+        so gnarly that we'd want a pattern language to write them in. So I made one, and that's what
+        the lowering has used. But as we've worked with the IR, we've found that it's very easy to
+        pattern match in C++ using the B3 API, and we've also found that most of the patterns we wrote
+        using the pattern language were mostly trivial. So this change removes the pattern match code
+        generator and the patterns files, and redoes the lowering using good old fashioned switch
+        statements. This actually reduces the total code of the lowering.
+
+        I also took the opportunity to refactoring UnOp and BinOp lowering. We had a lot of repetetive
+        code for 32-vs-64-bit opcode selection, so I factored that out into a helper. This also saves a
+        lot of code.
+
+        * CMakeLists.txt:
+        * DerivedSources.make:
+        * b3/B3AddressMatcher.patterns: Removed.
+        * b3/B3LowerToAir.cpp:
+        (JSC::B3::Air::LowerToAir::LowerToAir):
+        (JSC::B3::Air::LowerToAir::run):
+        (JSC::B3::Air::LowerToAir::highBitsAreZero):
+        (JSC::B3::Air::LowerToAir::tmp):
+        (JSC::B3::Air::LowerToAir::canBeInternal):
+        (JSC::B3::Air::LowerToAir::commitInternal):
+        (JSC::B3::Air::LowerToAir::crossesInterference):
+        (JSC::B3::Air::LowerToAir::effectiveAddr):
+        (JSC::B3::Air::LowerToAir::addr):
+        (JSC::B3::Air::LowerToAir::loadPromise):
+        (JSC::B3::Air::LowerToAir::imm):
+        (JSC::B3::Air::LowerToAir::immForMove):
+        (JSC::B3::Air::LowerToAir::immOrTmpForMove):
+        (JSC::B3::Air::LowerToAir::tryOpcodeForType):
+        (JSC::B3::Air::LowerToAir::opcodeForType):
+        (JSC::B3::Air::LowerToAir::appendUnOp):
+        (JSC::B3::Air::LowerToAir::appendBinOp):
+        (JSC::B3::Air::LowerToAir::appendShift):
+        (JSC::B3::Air::LowerToAir::tryAppendStoreUnOp):
+        (JSC::B3::Air::LowerToAir::tryAppendStoreBinOp):
+        (JSC::B3::Air::LowerToAir::append):
+        (JSC::B3::Air::LowerToAir::ensureSpecial):
+        (JSC::B3::Air::LowerToAir::fillStackmap):
+        (JSC::B3::Air::LowerToAir::createGenericCompare):
+        (JSC::B3::Air::LowerToAir::createBranch):
+        (JSC::B3::Air::LowerToAir::createCompare):
+        (JSC::B3::Air::LowerToAir::lower):
+        (JSC::B3::Air::LowerToAir::immOrTmp): Deleted.
+        (JSC::B3::Air::LowerToAir::AddressSelector::AddressSelector): Deleted.
+        (JSC::B3::Air::LowerToAir::AddressSelector::acceptRoot): Deleted.
+        (JSC::B3::Air::LowerToAir::AddressSelector::acceptRootLate): Deleted.
+        (JSC::B3::Air::LowerToAir::AddressSelector::acceptInternals): Deleted.
+        (JSC::B3::Air::LowerToAir::AddressSelector::acceptInternalsLate): Deleted.
+        (JSC::B3::Air::LowerToAir::AddressSelector::acceptOperands): Deleted.
+        (JSC::B3::Air::LowerToAir::AddressSelector::acceptOperandsLate): Deleted.
+        (JSC::B3::Air::LowerToAir::AddressSelector::tryAddShift1): Deleted.
+        (JSC::B3::Air::LowerToAir::AddressSelector::tryAddShift2): Deleted.
+        (JSC::B3::Air::LowerToAir::AddressSelector::tryAdd): Deleted.
+        (JSC::B3::Air::LowerToAir::AddressSelector::tryFramePointer): Deleted.
+        (JSC::B3::Air::LowerToAir::AddressSelector::tryStackSlot): Deleted.
+        (JSC::B3::Air::LowerToAir::AddressSelector::tryDirect): Deleted.
+        (JSC::B3::Air::LowerToAir::acceptRoot): Deleted.
+        (JSC::B3::Air::LowerToAir::acceptRootLate): Deleted.
+        (JSC::B3::Air::LowerToAir::acceptInternals): Deleted.
+        (JSC::B3::Air::LowerToAir::acceptInternalsLate): Deleted.
+        (JSC::B3::Air::LowerToAir::acceptOperands): Deleted.
+        (JSC::B3::Air::LowerToAir::acceptOperandsLate): Deleted.
+        (JSC::B3::Air::LowerToAir::tryLoad): Deleted.
+        (JSC::B3::Air::LowerToAir::tryLoad8S): Deleted.
+        (JSC::B3::Air::LowerToAir::tryLoad8Z): Deleted.
+        (JSC::B3::Air::LowerToAir::tryLoad16S): Deleted.
+        (JSC::B3::Air::LowerToAir::tryLoad16Z): Deleted.
+        (JSC::B3::Air::LowerToAir::tryAdd): Deleted.
+        (JSC::B3::Air::LowerToAir::trySub): Deleted.
+        (JSC::B3::Air::LowerToAir::tryAnd): Deleted.
+        (JSC::B3::Air::LowerToAir::tryOr): Deleted.
+        (JSC::B3::Air::LowerToAir::tryXor): Deleted.
+        (JSC::B3::Air::LowerToAir::tryShl): Deleted.
+        (JSC::B3::Air::LowerToAir::trySShr): Deleted.
+        (JSC::B3::Air::LowerToAir::tryZShr): Deleted.
+        (JSC::B3::Air::LowerToAir::tryStoreAddLoad): Deleted.
+        (JSC::B3::Air::LowerToAir::tryStoreSubLoad): Deleted.
+        (JSC::B3::Air::LowerToAir::tryStoreAndLoad): Deleted.
+        (JSC::B3::Air::LowerToAir::tryStore): Deleted.
+        (JSC::B3::Air::LowerToAir::tryTrunc): Deleted.
+        (JSC::B3::Air::LowerToAir::tryZExt32): Deleted.
+        (JSC::B3::Air::LowerToAir::tryArgumentReg): Deleted.
+        (JSC::B3::Air::LowerToAir::tryConst32): Deleted.
+        (JSC::B3::Air::LowerToAir::tryConst64): Deleted.
+        (JSC::B3::Air::LowerToAir::tryFramePointer): Deleted.
+        (JSC::B3::Air::LowerToAir::tryStackSlot): Deleted.
+        (JSC::B3::Air::LowerToAir::tryEqual): Deleted.
+        (JSC::B3::Air::LowerToAir::tryNotEqual): Deleted.
+        (JSC::B3::Air::LowerToAir::tryLessThan): Deleted.
+        (JSC::B3::Air::LowerToAir::tryGreaterThan): Deleted.
+        (JSC::B3::Air::LowerToAir::tryLessEqual): Deleted.
+        (JSC::B3::Air::LowerToAir::tryGreaterEqual): Deleted.
+        (JSC::B3::Air::LowerToAir::tryAbove): Deleted.
+        (JSC::B3::Air::LowerToAir::tryBelow): Deleted.
+        (JSC::B3::Air::LowerToAir::tryAboveEqual): Deleted.
+        (JSC::B3::Air::LowerToAir::tryBelowEqual): Deleted.
+        (JSC::B3::Air::LowerToAir::tryPatchpoint): Deleted.
+        (JSC::B3::Air::LowerToAir::tryCheck): Deleted.
+        (JSC::B3::Air::LowerToAir::tryUpsilon): Deleted.
+        (JSC::B3::Air::LowerToAir::tryPhi): Deleted.
+        (JSC::B3::Air::LowerToAir::tryBranch): Deleted.
+        (JSC::B3::Air::LowerToAir::tryJump): Deleted.
+        (JSC::B3::Air::LowerToAir::tryIdentity): Deleted.
+        (JSC::B3::Air::LowerToAir::tryReturn): Deleted.
+        * b3/B3LoweringMatcher.patterns: Removed.
+        * b3/generate_pattern_matcher.rb: Removed.
+
</ins><span class="cx"> 2015-11-07  Michael Saboff  &lt;msaboff@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Add conditional moves to the MacroAssembler
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreDerivedSourcesmake"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/DerivedSources.make (192134 => 192135)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/DerivedSources.make        2015-11-08 01:29:22 UTC (rev 192134)
+++ trunk/Source/JavaScriptCore/DerivedSources.make        2015-11-08 02:10:57 UTC (rev 192135)
</span><span class="lines">@@ -60,8 +60,6 @@
</span><span class="cx">     Lexer.lut.h \
</span><span class="cx">     KeywordLookup.h \
</span><span class="cx">     RegExpJitTables.h \
</span><del>-    B3LoweringMatcher.h \
-    B3AddressMatcher.h \
</del><span class="cx">     AirOpcode.h \
</span><span class="cx"> #
</span><span class="cx"> 
</span><span class="lines">@@ -265,11 +263,6 @@
</span><span class="cx"> JSReplayInputs.h : $(INPUT_GENERATOR_SPECIFICATIONS) $(INPUT_GENERATOR_SCRIPTS)
</span><span class="cx">         $(PYTHON) $(JavaScriptCore)/replay/scripts/CodeGeneratorReplayInputs.py --outputDir . --framework JavaScriptCore $(INPUT_GENERATOR_SPECIFICATIONS)
</span><span class="cx"> 
</span><del>-B3LoweringMatcher.h: $(JavaScriptCore)/b3/generate_pattern_matcher.rb $(JavaScriptCore)/b3/B3LoweringMatcher.patterns
-        $(RUBY) $^ 
-B3AddressMatcher.h: $(JavaScriptCore)/b3/generate_pattern_matcher.rb $(JavaScriptCore)/b3/B3AddressMatcher.patterns
-        $(RUBY) $^
-
</del><span class="cx"> AirOpcode.h: $(JavaScriptCore)/b3/air/opcode_generator.rb $(JavaScriptCore)/b3/air/AirOpcode.opcodes
</span><span class="cx">         $(RUBY) $^
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3AddressMatcherpatterns"></a>
<div class="delfile"><h4>Deleted: trunk/Source/JavaScriptCore/b3/B3AddressMatcher.patterns (192134 => 192135)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3AddressMatcher.patterns        2015-11-08 01:29:22 UTC (rev 192134)
+++ trunk/Source/JavaScriptCore/b3/B3AddressMatcher.patterns        2015-11-08 02:10:57 UTC (rev 192135)
</span><span class="lines">@@ -1,42 +0,0 @@
</span><del>-# 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. AND ITS CONTRIBUTORS ``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 ITS 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.
-
-matcher AddressMatcher
-
-# Note that this relies on B3 doing aggressive reassociation and canoncalization of integer adds.
-# We'll never see Add(Add(x, const1), const2) because it would have already been reassociated into
-# Add(x, const1 + const2). Also, we will never see Add(const, x), because we would have canonicalized
-# it to Add(x, const). That said, in this code we never make assertions about these optimizations
-# having been performed. Also, since the Load/Store instructions in B3 have a built-in offset, we
-# don't need to match Add(x, const). That would have been folded into the Load/Store instructions
-# already. So, the only fancy mathing this can do is just BaseIndex forms.
-
-AddShift1 = Add(Shl(index, $logScale), base)
-AddShift2 = Add(base, Shl(index, $logScale))
-
-Add = Add(left, right)
-
-FramePointer = FramePointer()
-StackSlot = StackSlot()
-
-Direct
</del></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3LowerToAircpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp (192134 => 192135)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2015-11-08 01:29:22 UTC (rev 192134)
+++ trunk/Source/JavaScriptCore/b3/B3LowerToAir.cpp        2015-11-08 02:10:57 UTC (rev 192135)
</span><span class="lines">@@ -32,14 +32,12 @@
</span><span class="cx"> #include &quot;AirInsertionSet.h&quot;
</span><span class="cx"> #include &quot;AirInstInlines.h&quot;
</span><span class="cx"> #include &quot;AirStackSlot.h&quot;
</span><del>-#include &quot;B3AddressMatcher.h&quot;
</del><span class="cx"> #include &quot;B3ArgumentRegValue.h&quot;
</span><span class="cx"> #include &quot;B3BasicBlockInlines.h&quot;
</span><span class="cx"> #include &quot;B3CheckSpecial.h&quot;
</span><span class="cx"> #include &quot;B3Commutativity.h&quot;
</span><span class="cx"> #include &quot;B3IndexMap.h&quot;
</span><span class="cx"> #include &quot;B3IndexSet.h&quot;
</span><del>-#include &quot;B3LoweringMatcher.h&quot;
</del><span class="cx"> #include &quot;B3MemoryValue.h&quot;
</span><span class="cx"> #include &quot;B3PatchpointSpecial.h&quot;
</span><span class="cx"> #include &quot;B3PatchpointValue.h&quot;
</span><span class="lines">@@ -62,32 +60,31 @@
</span><span class="cx"> class LowerToAir {
</span><span class="cx"> public:
</span><span class="cx">     LowerToAir(Procedure&amp; procedure, Code&amp; code)
</span><del>-        : valueToTmp(procedure.values().size())
-        , blockToBlock(procedure.size())
-        , useCounts(procedure)
-        , addressSelector(*this)
-        , procedure(procedure)
-        , code(code)
</del><ins>+        : m_valueToTmp(procedure.values().size())
+        , m_blockToBlock(procedure.size())
+        , m_useCounts(procedure)
+        , m_procedure(procedure)
+        , m_code(code)
</ins><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void run()
</span><span class="cx">     {
</span><del>-        for (B3::BasicBlock* block : procedure)
-            blockToBlock[block] = code.addBlock(block-&gt;frequency());
-        for (Value* value : procedure.values()) {
</del><ins>+        for (B3::BasicBlock* block : m_procedure)
+            m_blockToBlock[block] = m_code.addBlock(block-&gt;frequency());
+        for (Value* value : m_procedure.values()) {
</ins><span class="cx">             if (StackSlotValue* stackSlotValue = value-&gt;as&lt;StackSlotValue&gt;())
</span><del>-                stackToStack.add(stackSlotValue, code.addStackSlot(stackSlotValue));
</del><ins>+                m_stackToStack.add(stackSlotValue, m_code.addStackSlot(stackSlotValue));
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        procedure.resetValueOwners(); // Used by crossesInterference().
</del><ins>+        m_procedure.resetValueOwners(); // Used by crossesInterference().
</ins><span class="cx"> 
</span><span class="cx">         // Lower defs before uses on a global level. This is a good heuristic to lock down a
</span><span class="cx">         // hoisted address expression before we duplicate it back into the loop.
</span><del>-        for (B3::BasicBlock* block : procedure.blocksInPreOrder()) {
-            currentBlock = block;
</del><ins>+        for (B3::BasicBlock* block : m_procedure.blocksInPreOrder()) {
+            m_block = block;
</ins><span class="cx">             // Reset some state.
</span><del>-            insts.resize(0);
</del><ins>+            m_insts.resize(0);
</ins><span class="cx"> 
</span><span class="cx">             if (verbose)
</span><span class="cx">                 dataLog(&quot;Lowering Block &quot;, *block, &quot;:\n&quot;);
</span><span class="lines">@@ -95,43 +92,40 @@
</span><span class="cx">             // Process blocks in reverse order so we see uses before defs. That's what allows us
</span><span class="cx">             // to match patterns effectively.
</span><span class="cx">             for (unsigned i = block-&gt;size(); i--;) {
</span><del>-                currentIndex = i;
-                currentValue = block-&gt;at(i);
-                if (locked.contains(currentValue))
</del><ins>+                m_index = i;
+                m_value = block-&gt;at(i);
+                if (m_locked.contains(m_value))
</ins><span class="cx">                     continue;
</span><del>-                insts.append(Vector&lt;Inst&gt;());
</del><ins>+                m_insts.append(Vector&lt;Inst&gt;());
</ins><span class="cx">                 if (verbose)
</span><del>-                    dataLog(&quot;Lowering &quot;, deepDump(currentValue), &quot;:\n&quot;);
-                bool result = runLoweringMatcher(currentValue, *this);
-                if (!result) {
-                    dataLog(&quot;FATAL: could not lower &quot;, deepDump(currentValue), &quot;\n&quot;);
-                    RELEASE_ASSERT_NOT_REACHED();
-                }
</del><ins>+                    dataLog(&quot;Lowering &quot;, deepDump(m_value), &quot;:\n&quot;);
+                lower();
</ins><span class="cx">                 if (verbose) {
</span><del>-                    for (Inst&amp; inst : insts.last())
</del><ins>+                    for (Inst&amp; inst : m_insts.last())
</ins><span class="cx">                         dataLog(&quot;    &quot;, inst, &quot;\n&quot;);
</span><span class="cx">                 }
</span><span class="cx">             }
</span><span class="cx"> 
</span><del>-            // Now append the instructions. insts contains them in reverse order, so we process
</del><ins>+            // Now append the instructions. m_insts contains them in reverse order, so we process
</ins><span class="cx">             // it in reverse.
</span><del>-            for (unsigned i = insts.size(); i--;) {
-                for (Inst&amp; inst : insts[i])
-                    blockToBlock[block]-&gt;appendInst(WTF::move(inst));
</del><ins>+            for (unsigned i = m_insts.size(); i--;) {
+                for (Inst&amp; inst : m_insts[i])
+                    m_blockToBlock[block]-&gt;appendInst(WTF::move(inst));
</ins><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             // Make sure that the successors are set up correctly.
</span><span class="cx">             ASSERT(block-&gt;successors().size() &lt;= 2);
</span><span class="cx">             for (B3::BasicBlock* successor : block-&gt;successorBlocks())
</span><del>-                blockToBlock[block]-&gt;successors().append(blockToBlock[successor]);
</del><ins>+                m_blockToBlock[block]-&gt;successors().append(m_blockToBlock[successor]);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        Air::InsertionSet insertionSet(code);
-        for (Inst&amp; inst : prologue)
</del><ins>+        Air::InsertionSet insertionSet(m_code);
+        for (Inst&amp; inst : m_prologue)
</ins><span class="cx">             insertionSet.insertInst(0, WTF::move(inst));
</span><del>-        insertionSet.execute(code[0]);
</del><ins>+        insertionSet.execute(m_code[0]);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><ins>+private:
</ins><span class="cx">     bool highBitsAreZero(Value* value)
</span><span class="cx">     {
</span><span class="cx">         switch (value-&gt;opcode()) {
</span><span class="lines">@@ -265,14 +259,14 @@
</span><span class="cx">     //
</span><span class="cx">     //     auto tryThings = [this] (const Arg&amp; left, const Arg&amp; right) {
</span><span class="cx">     //         if (isValidForm(Foo, left.kind(), right.kind()))
</span><del>-    //             return Inst(Foo, currentValue, left, right);
</del><ins>+    //             return Inst(Foo, m_value, left, right);
</ins><span class="cx">     //         return Inst();
</span><span class="cx">     //     };
</span><span class="cx">     //     if (Inst result = tryThings(loadAddr(left), tmp(right)))
</span><span class="cx">     //         return result;
</span><span class="cx">     //     if (Inst result = tryThings(tmp(left), loadAddr(right))) // this never succeeds.
</span><span class="cx">     //         return result;
</span><del>-    //     return Inst(Foo, currentValue, tmp(left), tmp(right));
</del><ins>+    //     return Inst(Foo, m_value, tmp(left), tmp(right));
</ins><span class="cx">     //
</span><span class="cx">     // If you imagine that loadAddr(value) is just loadPromise(value).consume(*this), then this code
</span><span class="cx">     // will run correctly - it will generate OK code - but the second form is never matched.
</span><span class="lines">@@ -283,27 +277,27 @@
</span><span class="cx">     //
</span><span class="cx">     //     auto tryThings = [this] (const ArgPromise&amp; left, const ArgPromise&amp; right) {
</span><span class="cx">     //         if (isValidForm(Foo, left.kind(), right.kind()))
</span><del>-    //             return Inst(Foo, currentValue, left.consume(*this), right.consume(*this));
</del><ins>+    //             return Inst(Foo, m_value, left.consume(*this), right.consume(*this));
</ins><span class="cx">     //         return Inst();
</span><span class="cx">     //     };
</span><span class="cx">     //     if (Inst result = tryThings(loadPromise(left), tmpPromise(right)))
</span><span class="cx">     //         return result;
</span><span class="cx">     //     if (Inst result = tryThings(tmpPromise(left), loadPromise(right)))
</span><span class="cx">     //         return result;
</span><del>-    //     return Inst(Foo, currentValue, tmp(left), tmp(right));
</del><ins>+    //     return Inst(Foo, m_value, tmp(left), tmp(right));
</ins><span class="cx">     //
</span><span class="cx">     // Notice that we did use tmp in the fall-back case at the end, because by then, we know for sure
</span><span class="cx">     // that we want a tmp. But using tmpPromise in the tryThings() calls ensures that doing so
</span><span class="cx">     // doesn't prevent us from trying loadPromise on the same value.
</span><span class="cx">     Tmp tmp(Value* value)
</span><span class="cx">     {
</span><del>-        Tmp&amp; tmp = valueToTmp[value];
</del><ins>+        Tmp&amp; tmp = m_valueToTmp[value];
</ins><span class="cx">         if (!tmp) {
</span><span class="cx">             while (shouldCopyPropagate(value))
</span><span class="cx">                 value = value-&gt;child(0);
</span><del>-            Tmp&amp; realTmp = valueToTmp[value];
</del><ins>+            Tmp&amp; realTmp = m_valueToTmp[value];
</ins><span class="cx">             if (!realTmp)
</span><del>-                realTmp = code.newTmp(Arg::typeForB3Type(value-&gt;type()));
</del><ins>+                realTmp = m_code.newTmp(Arg::typeForB3Type(value-&gt;type()));
</ins><span class="cx">             tmp = realTmp;
</span><span class="cx">         }
</span><span class="cx">         return tmp;
</span><span class="lines">@@ -318,11 +312,11 @@
</span><span class="cx">     {
</span><span class="cx">         // If one of the internal things has already been computed, then we don't want to cause
</span><span class="cx">         // it to be recomputed again.
</span><del>-        if (valueToTmp[value])
</del><ins>+        if (m_valueToTmp[value])
</ins><span class="cx">             return false;
</span><span class="cx">         
</span><span class="cx">         // We require internals to have only one use - us.
</span><del>-        if (useCounts[value] != 1)
</del><ins>+        if (m_useCounts[value] != 1)
</ins><span class="cx">             return false;
</span><span class="cx"> 
</span><span class="cx">         return true;
</span><span class="lines">@@ -334,7 +328,7 @@
</span><span class="cx">     // short, you should avoid this by using the pattern matcher to match patterns.
</span><span class="cx">     void commitInternal(Value* value)
</span><span class="cx">     {
</span><del>-        locked.add(value);
</del><ins>+        m_locked.add(value);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     bool crossesInterference(Value* value)
</span><span class="lines">@@ -343,13 +337,13 @@
</span><span class="cx">         // willing to do heavier analysis. For example, if we had liveness, then we could label
</span><span class="cx">         // values as &quot;crossing interference&quot; if they interfere with anything that they are live
</span><span class="cx">         // across. But, it's not clear how useful this would be.
</span><del>-        if (value-&gt;owner != currentValue-&gt;owner)
</del><ins>+        if (value-&gt;owner != m_value-&gt;owner)
</ins><span class="cx">             return true;
</span><span class="cx"> 
</span><span class="cx">         Effects effects = value-&gt;effects();
</span><span class="cx"> 
</span><del>-        for (unsigned i = currentIndex; i--;) {
-            Value* otherValue = currentBlock-&gt;at(i);
</del><ins>+        for (unsigned i = m_index; i--;) {
+            Value* otherValue = m_block-&gt;at(i);
</ins><span class="cx">             if (otherValue == value)
</span><span class="cx">                 return false;
</span><span class="cx">             if (effects.interferes(otherValue-&gt;effects()))
</span><span class="lines">@@ -363,23 +357,51 @@
</span><span class="cx">     // This turns the given operand into an address.
</span><span class="cx">     Arg effectiveAddr(Value* address)
</span><span class="cx">     {
</span><del>-        addressSelector.selectedAddress = Arg();
-        if (runAddressMatcher(address, addressSelector))
-            return addressSelector.selectedAddress;
</del><ins>+        // FIXME: Consider matching an address expression even if we've already assigned a
+        // Tmp to it. https://bugs.webkit.org/show_bug.cgi?id=150777
+        if (m_valueToTmp[address])
+            return Arg::addr(tmp(address));
+        
+        switch (address-&gt;opcode()) {
+        case Add: {
+            Value* left = address-&gt;child(0);
+            Value* right = address-&gt;child(1);
</ins><span class="cx"> 
</span><del>-        return Arg::addr(tmp(address));
-    }
</del><ins>+            auto tryIndex = [&amp;] (Value* index, Value* offset) -&gt; Arg {
+                if (index-&gt;opcode() != Shl)
+                    return Arg();
+                if (m_locked.contains(index-&gt;child(0)) || m_locked.contains(offset))
+                    return Arg();
+                if (!index-&gt;child(1)-&gt;hasInt32())
+                    return Arg();
+                
+                unsigned scale = 1 &lt;&lt; (index-&gt;child(1)-&gt;asInt32() &amp; 31);
+                if (!Arg::isValidScale(scale))
+                    return Arg();
</ins><span class="cx"> 
</span><del>-    Arg effectiveAddr(Value* address, Value* memoryValue)
-    {
-        Arg result = effectiveAddr(address);
-        ASSERT(result);
</del><ins>+                return Arg::index(tmp(offset), tmp(index-&gt;child(0)), scale);
+            };
</ins><span class="cx"> 
</span><del>-        int32_t offset = memoryValue-&gt;as&lt;MemoryValue&gt;()-&gt;offset();
-        Arg offsetResult = result.withOffset(offset);
-        if (!offsetResult)
-            return Arg::addr(tmp(address), offset);
-        return offsetResult;
</del><ins>+            if (Arg result = tryIndex(left, right))
+                return result;
+            if (Arg result = tryIndex(right, left))
+                return result;
+
+            if (m_locked.contains(left) || m_locked.contains(right))
+                return Arg::addr(tmp(address));
+            
+            return Arg::index(tmp(left), tmp(right));
+        }
+
+        case FramePointer:
+            return Arg::addr(Tmp(GPRInfo::callFrameRegister));
+
+        case B3::StackSlot:
+            return Arg::stack(m_stackToStack.get(address-&gt;as&lt;StackSlotValue&gt;()));
+
+        default:
+            return Arg::addr(tmp(address));
+        }
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // This gives you the address of the given Load or Store. If it's not a Load or Store, then
</span><span class="lines">@@ -390,7 +412,14 @@
</span><span class="cx">         if (!value)
</span><span class="cx">             return Arg();
</span><span class="cx"> 
</span><del>-        return effectiveAddr(value-&gt;lastChild(), value);
</del><ins>+        Arg result = effectiveAddr(value-&gt;lastChild());
+        ASSERT(result);
+        
+        int32_t offset = memoryValue-&gt;as&lt;MemoryValue&gt;()-&gt;offset();
+        Arg offsetResult = result.withOffset(offset);
+        if (!offsetResult)
+            return Arg::addr(tmp(value-&gt;lastChild()), offset);
+        return offsetResult;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     ArgPromise loadPromise(Value* loadValue, B3::Opcode loadOpcode)
</span><span class="lines">@@ -416,17 +445,58 @@
</span><span class="cx">         return Arg();
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    Arg immOrTmp(Value* value)
-    {
</del><ins>+    Arg immForMove(Value* value) {
</ins><span class="cx">         if (Arg result = imm(value))
</span><span class="cx">             return result;
</span><ins>+        if (value-&gt;hasInt64())
+            return Arg::imm64(value-&gt;asInt64());
+        return Arg();
+    }
+
+    Arg immOrTmpForMove(Value* value)
+    {
+        if (Arg result = immForMove(value))
+            return result;
</ins><span class="cx">         return tmp(value);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    template&lt;Air::Opcode opcode&gt;
</del><ins>+    // By convention, we use Oops to mean &quot;I don't know&quot;.
+    Air::Opcode tryOpcodeForType(
+        Air::Opcode opcode32, Air::Opcode opcode64, Air::Opcode opcodeDouble, Type type)
+    {
+        Air::Opcode opcode;
+        switch (type) {
+        case Int32:
+            opcode = opcode32;
+            break;
+        case Int64:
+            opcode = opcode64;
+            break;
+        case Double:
+            opcode = opcodeDouble;
+            break;
+        default:
+            opcode = Air::Oops;
+            break;
+        }
+
+        return opcode;
+    }
+
+    Air::Opcode opcodeForType(
+        Air::Opcode opcode32, Air::Opcode opcode64, Air::Opcode opcodeDouble, Type type)
+    {
+        Air::Opcode opcode = tryOpcodeForType(opcode32, opcode64, opcodeDouble, type);
+        RELEASE_ASSERT(opcode != Air::Oops);
+        return opcode;
+    }
+
+    template&lt;Air::Opcode opcode32, Air::Opcode opcode64, Air::Opcode opcodeDouble&gt;
</ins><span class="cx">     void appendUnOp(Value* value)
</span><span class="cx">     {
</span><del>-        Tmp result = tmp(currentValue);
</del><ins>+        Air::Opcode opcode = opcodeForType(opcode32, opcode64, opcodeDouble, value-&gt;type());
+        
+        Tmp result = tmp(m_value);
</ins><span class="cx"> 
</span><span class="cx">         // Two operand forms like:
</span><span class="cx">         //     Op a, b
</span><span class="lines">@@ -438,15 +508,19 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        append(relaxedMoveForType(currentValue-&gt;type()), tmp(value), result);
</del><ins>+        append(relaxedMoveForType(m_value-&gt;type()), tmp(value), result);
</ins><span class="cx">         append(opcode, result);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    template&lt;Air::Opcode opcode, Commutativity commutativity = NotCommutative&gt;
</del><ins>+    template&lt;
+        Air::Opcode opcode32, Air::Opcode opcode64, Air::Opcode opcodeDouble,
+        Commutativity commutativity = NotCommutative&gt;
</ins><span class="cx">     void appendBinOp(Value* left, Value* right)
</span><span class="cx">     {
</span><del>-        Tmp result = tmp(currentValue);
</del><ins>+        Air::Opcode opcode = opcodeForType(opcode32, opcode64, opcodeDouble, left-&gt;type());
</ins><span class="cx">         
</span><ins>+        Tmp result = tmp(m_value);
+        
</ins><span class="cx">         // Three-operand forms like:
</span><span class="cx">         //     Op a, b, c
</span><span class="cx">         // mean something like:
</span><span class="lines">@@ -487,7 +561,7 @@
</span><span class="cx">         if (commutativity == Commutative) {
</span><span class="cx">             ArgPromise leftAddr = loadPromise(left);
</span><span class="cx">             if (isValidForm(opcode, leftAddr.kind(), Arg::Tmp)) {
</span><del>-                append(relaxedMoveForType(currentValue-&gt;type()), tmp(right), result);
</del><ins>+                append(relaxedMoveForType(m_value-&gt;type()), tmp(right), result);
</ins><span class="cx">                 append(opcode, leftAddr.consume(*this), result);
</span><span class="cx">                 return;
</span><span class="cx">             }
</span><span class="lines">@@ -495,13 +569,13 @@
</span><span class="cx"> 
</span><span class="cx">         ArgPromise rightAddr = loadPromise(right);
</span><span class="cx">         if (isValidForm(opcode, rightAddr.kind(), Arg::Tmp)) {
</span><del>-            append(relaxedMoveForType(currentValue-&gt;type()), tmp(left), result);
</del><ins>+            append(relaxedMoveForType(m_value-&gt;type()), tmp(left), result);
</ins><span class="cx">             append(opcode, rightAddr.consume(*this), result);
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (imm(right) &amp;&amp; isValidForm(opcode, Arg::Imm, Arg::Tmp)) {
</span><del>-            append(relaxedMoveForType(currentValue-&gt;type()), tmp(left), result);
</del><ins>+            append(relaxedMoveForType(m_value-&gt;type()), tmp(left), result);
</ins><span class="cx">             append(opcode, imm(right), result);
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="lines">@@ -511,29 +585,57 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        append(relaxedMoveForType(currentValue-&gt;type()), tmp(left), result);
</del><ins>+        append(relaxedMoveForType(m_value-&gt;type()), tmp(left), result);
</ins><span class="cx">         append(opcode, tmp(right), result);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    template&lt;Air::Opcode opcode&gt;
</del><ins>+    template&lt;Air::Opcode opcode32, Air::Opcode opcode64&gt;
+    void appendShift(Value* value, Value* amount)
+    {
+        Air::Opcode opcode = opcodeForType(opcode32, opcode64, Air::Oops, value-&gt;type());
+        
+        if (imm(amount)) {
+            append(Move, tmp(value), tmp(m_value));
+            append(opcode, imm(amount), tmp(m_value));
+            return;
+        }
+
+        append(Move, tmp(value), tmp(m_value));
+        append(Move, tmp(amount), Tmp(X86Registers::ecx));
+        append(opcode, Tmp(X86Registers::ecx), tmp(m_value));
+    }
+
+    template&lt;Air::Opcode opcode32, Air::Opcode opcode64&gt;
</ins><span class="cx">     bool tryAppendStoreUnOp(Value* value)
</span><span class="cx">     {
</span><del>-        Arg storeAddr = addr(currentValue);
</del><ins>+        Air::Opcode opcode = tryOpcodeForType(opcode32, opcode64, Air::Oops, value-&gt;type());
+        if (opcode == Air::Oops)
+            return false;
+        
+        Arg storeAddr = addr(m_value);
</ins><span class="cx">         ASSERT(storeAddr);
</span><span class="cx"> 
</span><span class="cx">         ArgPromise loadPromise = this-&gt;loadPromise(value);
</span><span class="cx">         if (loadPromise.peek() != storeAddr)
</span><span class="cx">             return false;
</span><span class="cx"> 
</span><ins>+        if (!isValidForm(opcode, storeAddr.kind()))
+            return false;
+        
</ins><span class="cx">         loadPromise.consume(*this);
</span><span class="cx">         append(opcode, storeAddr);
</span><span class="cx">         return true;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    template&lt;Air::Opcode opcode, Commutativity commutativity = NotCommutative&gt;
</del><ins>+    template&lt;
+        Air::Opcode opcode32, Air::Opcode opcode64, Commutativity commutativity = NotCommutative&gt;
</ins><span class="cx">     bool tryAppendStoreBinOp(Value* left, Value* right)
</span><span class="cx">     {
</span><del>-        Arg storeAddr = addr(currentValue);
</del><ins>+        Air::Opcode opcode = tryOpcodeForType(opcode32, opcode64, Air::Oops, left-&gt;type());
+        if (opcode == Air::Oops)
+            return false;
+        
+        Arg storeAddr = addr(m_value);
</ins><span class="cx">         ASSERT(storeAddr);
</span><span class="cx"> 
</span><span class="cx">         ArgPromise loadPromise;
</span><span class="lines">@@ -608,7 +710,7 @@
</span><span class="cx">     template&lt;typename... Arguments&gt;
</span><span class="cx">     void append(Air::Opcode opcode, Arguments&amp;&amp;... arguments)
</span><span class="cx">     {
</span><del>-        insts.last().append(Inst(opcode, currentValue, std::forward&lt;Arguments&gt;(arguments)...));
</del><ins>+        m_insts.last().append(Inst(opcode, m_value, std::forward&lt;Arguments&gt;(arguments)...));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     template&lt;typename T, typename... Arguments&gt;
</span><span class="lines">@@ -616,7 +718,7 @@
</span><span class="cx">     {
</span><span class="cx">         if (!field) {
</span><span class="cx">             field = static_cast&lt;T*&gt;(
</span><del>-                code.addSpecial(std::make_unique&lt;T&gt;(std::forward&lt;Arguments&gt;(arguments)...)));
</del><ins>+                m_code.addSpecial(std::make_unique&lt;T&gt;(std::forward&lt;Arguments&gt;(arguments)...)));
</ins><span class="cx">         }
</span><span class="cx">         return field;
</span><span class="cx">     }
</span><span class="lines">@@ -629,14 +731,14 @@
</span><span class="cx">             Arg arg;
</span><span class="cx">             switch (value.rep().kind()) {
</span><span class="cx">             case ValueRep::Any:
</span><del>-                arg = immOrTmp(value.value());
</del><ins>+                arg = immOrTmpForMove(value.value());
</ins><span class="cx">                 break;
</span><span class="cx">             case ValueRep::SomeRegister:
</span><span class="cx">                 arg = tmp(value.value());
</span><span class="cx">                 break;
</span><span class="cx">             case ValueRep::Register:
</span><span class="cx">                 arg = Tmp(value.rep().reg());
</span><del>-                append(Move, immOrTmp(value.value()), arg);
</del><ins>+                append(Move, immOrTmpForMove(value.value()), arg);
</ins><span class="cx">                 break;
</span><span class="cx">             case ValueRep::StackArgument:
</span><span class="cx">                 arg = Arg::callArg(value.rep().offsetFromSP());
</span><span class="lines">@@ -650,126 +752,6 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    IndexSet&lt;Value&gt; locked; // These are values that will have no Tmp in Air.
-    IndexMap&lt;Value, Tmp&gt; valueToTmp; // These are values that must have a Tmp in Air. We say that a Value* with a non-null Tmp is &quot;pinned&quot;.
-    IndexMap&lt;B3::BasicBlock, Air::BasicBlock*&gt; blockToBlock;
-    HashMap&lt;StackSlotValue*, Air::StackSlot*&gt; stackToStack;
-
-    UseCounts useCounts;
-
-    Vector&lt;Vector&lt;Inst, 4&gt;&gt; insts;
-    Vector&lt;Inst&gt; prologue;
-
-    B3::BasicBlock* currentBlock;
-    unsigned currentIndex;
-    Value* currentValue;
-
-    // The address selector will match any pattern where the input operands are available as Tmps.
-    // It doesn't care about sharing. It will happily emit the same address expression over and over
-    // again regardless of the expression's complexity. This works out fine, since at the machine
-    // level, address expressions are super cheap. However, this does have a hack to avoid
-    // &quot;unhoisting&quot; address expressions.
-    class AddressSelector {
-    public:
-        AddressSelector(LowerToAir&amp; lower)
-            : lower(lower)
-        {
-        }
-
-        bool acceptRoot(Value* root)
-        {
-            this-&gt;root = root;
-            // We don't want to match an address expression that has already been computed
-            // explicitly. This mostly makes sense. Note that we never hoist basic address
-            // expressions like offset(base), because those are sunk into the MemoryValue. So,
-            // this is mainly just relevant to Index expressions and other more complicated
-            // things. It stands to reason that most of the time, we won't hoist an Index
-            // expression. And if we do, then probably it's a good thing to compute it outside
-            // a loop. That being said, this might turn into a problem. For example, it will
-            // require an extra register to be live. That's unlikely to be profitable.
-            // FIXME: Consider matching an address expression even if we've already assigned a
-            // Tmp to it. https://bugs.webkit.org/show_bug.cgi?id=150777
-            return !lower.valueToTmp[root];
-        }
-
-        void acceptRootLate(Value*) { }
-
-        template&lt;typename... Arguments&gt;
-        bool acceptInternals(Value* value, Arguments... arguments)
-        {
-            if (lower.valueToTmp[value])
-                return false;
-            return acceptInternals(arguments...);
-        }
-        bool acceptInternals() { return true; }
-
-        template&lt;typename... Arguments&gt;
-        void acceptInternalsLate(Arguments...) { }
-
-        template&lt;typename... Arguments&gt;
-        bool acceptOperands(Value* value, Arguments... arguments)
-        {
-            if (lower.locked.contains(value))
-                return false;
-            return acceptOperands(arguments...);
-        }
-        bool acceptOperands() { return true; }
-
-        template&lt;typename... Arguments&gt;
-        void acceptOperandsLate(Arguments...) { }
-
-        bool tryAddShift1(Value* index, Value* logScale, Value* base)
-        {
-            if (logScale-&gt;asInt() &lt; 0 || logScale-&gt;asInt() &gt; 3)
-                return false;
-            selectedAddress = Arg::index(
-                lower.tmp(base), lower.tmp(index), 1 &lt;&lt; logScale-&gt;asInt());
-            return true;
-        }
-
-        bool tryAddShift2(Value* base, Value* index, Value* logScale)
-        {
-            return tryAddShift1(index, logScale, base);
-        }
-
-        bool tryAdd(Value* left, Value* right)
-        {
-            if (right-&gt;hasInt32()) {
-                // This production isn't strictly necessary since we expect
-                // Load(Add(@x, @const1), offset = const2) to have already been strength-reduced
-                // to Load(@x, offset = const1 + const2).
-                selectedAddress = Arg::addr(lower.tmp(left), right-&gt;asInt32());
-                return true;
-            }
-
-            selectedAddress = Arg::index(lower.tmp(left), lower.tmp(right));
-            return true;
-        }
-
-        bool tryFramePointer()
-        {
-            selectedAddress = Arg::addr(Tmp(GPRInfo::callFrameRegister));
-            return true;
-        }
-
-        bool tryStackSlot()
-        {
-            selectedAddress = Arg::stack(lower.stackToStack.get(root-&gt;as&lt;StackSlotValue&gt;()));
-            return true;
-        }
-
-        bool tryDirect()
-        {
-            selectedAddress = Arg::addr(lower.tmp(root));
-            return true;
-        }
-        
-        LowerToAir&amp; lower;
-        Value* root;
-        Arg selectedAddress;
-    };
-    AddressSelector addressSelector;
-
</del><span class="cx">     // Create an Inst to do the comparison specified by the given value.
</span><span class="cx">     template&lt;typename CompareFunctor, typename TestFunctor, typename CompareDoubleFunctor&gt;
</span><span class="cx">     Inst createGenericCompare(
</span><span class="lines">@@ -783,7 +765,7 @@
</span><span class="cx">         // to follow the rule that the instruction selector reduces strength whenever it doesn't
</span><span class="cx">         // require making things more complicated.
</span><span class="cx">         for (;;) {
</span><del>-            if (!canBeInternal(value) &amp;&amp; value != currentValue)
</del><ins>+            if (!canBeInternal(value) &amp;&amp; value != m_value)
</ins><span class="cx">                 break;
</span><span class="cx">             bool shouldInvert =
</span><span class="cx">                 (value-&gt;opcode() == BitXor &amp;&amp; value-&gt;child(1)-&gt;isInt(1) &amp;&amp; value-&gt;child(0)-&gt;returnsBool())
</span><span class="lines">@@ -1021,7 +1003,7 @@
</span><span class="cx">             }
</span><span class="cx">         };
</span><span class="cx"> 
</span><del>-        if (canBeInternal(value) || value == currentValue) {
</del><ins>+        if (canBeInternal(value) || value == m_value) {
</ins><span class="cx">             if (Inst result = attemptFused()) {
</span><span class="cx">                 commitInternal(value);
</span><span class="cx">                 return result;
</span><span class="lines">@@ -1047,7 +1029,7 @@
</span><span class="cx">                 case Arg::Width8:
</span><span class="cx">                     if (isValidForm(Branch8, Arg::RelCond, left.kind(), right.kind())) {
</span><span class="cx">                         return Inst(
</span><del>-                            Branch8, currentValue, relCond,
</del><ins>+                            Branch8, m_value, relCond,
</ins><span class="cx">                             left.consume(*this), right.consume(*this));
</span><span class="cx">                     }
</span><span class="cx">                     return Inst();
</span><span class="lines">@@ -1056,14 +1038,14 @@
</span><span class="cx">                 case Arg::Width32:
</span><span class="cx">                     if (isValidForm(Branch32, Arg::RelCond, left.kind(), right.kind())) {
</span><span class="cx">                         return Inst(
</span><del>-                            Branch32, currentValue, relCond,
</del><ins>+                            Branch32, m_value, relCond,
</ins><span class="cx">                             left.consume(*this), right.consume(*this));
</span><span class="cx">                     }
</span><span class="cx">                     return Inst();
</span><span class="cx">                 case Arg::Width64:
</span><span class="cx">                     if (isValidForm(Branch64, Arg::RelCond, left.kind(), right.kind())) {
</span><span class="cx">                         return Inst(
</span><del>-                            Branch64, currentValue, relCond,
</del><ins>+                            Branch64, m_value, relCond,
</ins><span class="cx">                             left.consume(*this), right.consume(*this));
</span><span class="cx">                     }
</span><span class="cx">                     return Inst();
</span><span class="lines">@@ -1076,7 +1058,7 @@
</span><span class="cx">                 case Arg::Width8:
</span><span class="cx">                     if (isValidForm(BranchTest8, Arg::ResCond, left.kind(), right.kind())) {
</span><span class="cx">                         return Inst(
</span><del>-                            BranchTest8, currentValue, resCond,
</del><ins>+                            BranchTest8, m_value, resCond,
</ins><span class="cx">                             left.consume(*this), right.consume(*this));
</span><span class="cx">                     }
</span><span class="cx">                     return Inst();
</span><span class="lines">@@ -1085,14 +1067,14 @@
</span><span class="cx">                 case Arg::Width32:
</span><span class="cx">                     if (isValidForm(BranchTest32, Arg::ResCond, left.kind(), right.kind())) {
</span><span class="cx">                         return Inst(
</span><del>-                            BranchTest32, currentValue, resCond,
</del><ins>+                            BranchTest32, m_value, resCond,
</ins><span class="cx">                             left.consume(*this), right.consume(*this));
</span><span class="cx">                     }
</span><span class="cx">                     return Inst();
</span><span class="cx">                 case Arg::Width64:
</span><span class="cx">                     if (isValidForm(BranchTest64, Arg::ResCond, left.kind(), right.kind())) {
</span><span class="cx">                         return Inst(
</span><del>-                            BranchTest64, currentValue, resCond,
</del><ins>+                            BranchTest64, m_value, resCond,
</ins><span class="cx">                             left.consume(*this), right.consume(*this));
</span><span class="cx">                     }
</span><span class="cx">                     return Inst();
</span><span class="lines">@@ -1101,7 +1083,7 @@
</span><span class="cx">             [this] (Arg doubleCond, const ArgPromise&amp; left, const ArgPromise&amp; right) -&gt; Inst {
</span><span class="cx">                 if (isValidForm(BranchDouble, Arg::DoubleCond, left.kind(), right.kind())) {
</span><span class="cx">                     return Inst(
</span><del>-                        BranchDouble, currentValue, doubleCond,
</del><ins>+                        BranchDouble, m_value, doubleCond,
</ins><span class="cx">                         left.consume(*this), right.consume(*this));
</span><span class="cx">                 }
</span><span class="cx">                 return Inst();
</span><span class="lines">@@ -1123,15 +1105,15 @@
</span><span class="cx">                 case Arg::Width32:
</span><span class="cx">                     if (isValidForm(Compare32, Arg::RelCond, left.kind(), right.kind(), Arg::Tmp)) {
</span><span class="cx">                         return Inst(
</span><del>-                            Compare32, currentValue, relCond,
-                            left.consume(*this), right.consume(*this), tmp(currentValue));
</del><ins>+                            Compare32, m_value, relCond,
+                            left.consume(*this), right.consume(*this), tmp(m_value));
</ins><span class="cx">                     }
</span><span class="cx">                     return Inst();
</span><span class="cx">                 case Arg::Width64:
</span><span class="cx">                     if (isValidForm(Compare64, Arg::RelCond, left.kind(), right.kind(), Arg::Tmp)) {
</span><span class="cx">                         return Inst(
</span><del>-                            Compare64, currentValue, relCond,
-                            left.consume(*this), right.consume(*this), tmp(currentValue));
</del><ins>+                            Compare64, m_value, relCond,
+                            left.consume(*this), right.consume(*this), tmp(m_value));
</ins><span class="cx">                     }
</span><span class="cx">                     return Inst();
</span><span class="cx">                 }
</span><span class="lines">@@ -1146,15 +1128,15 @@
</span><span class="cx">                 case Arg::Width32:
</span><span class="cx">                     if (isValidForm(Test32, Arg::ResCond, left.kind(), right.kind(), Arg::Tmp)) {
</span><span class="cx">                         return Inst(
</span><del>-                            Test32, currentValue, resCond,
-                            left.consume(*this), right.consume(*this), tmp(currentValue));
</del><ins>+                            Test32, m_value, resCond,
+                            left.consume(*this), right.consume(*this), tmp(m_value));
</ins><span class="cx">                     }
</span><span class="cx">                     return Inst();
</span><span class="cx">                 case Arg::Width64:
</span><span class="cx">                     if (isValidForm(Test64, Arg::ResCond, left.kind(), right.kind(), Arg::Tmp)) {
</span><span class="cx">                         return Inst(
</span><del>-                            Test64, currentValue, resCond,
-                            left.consume(*this), right.consume(*this), tmp(currentValue));
</del><ins>+                            Test64, m_value, resCond,
+                            left.consume(*this), right.consume(*this), tmp(m_value));
</ins><span class="cx">                     }
</span><span class="cx">                     return Inst();
</span><span class="cx">                 }
</span><span class="lines">@@ -1167,433 +1149,272 @@
</span><span class="cx">             inverted);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    // Below is the code for a lowering selector, so that we can pass *this to runLoweringMatcher.
-    // This will match complex multi-value expressions, but only if there is no sharing. For example,
-    // it won't match a Load twice and cause the generated code to do two loads when the original
-    // code just did one.
-    
-    bool acceptRoot(Value* root)
</del><ins>+    void lower()
</ins><span class="cx">     {
</span><del>-        ASSERT_UNUSED(root, !locked.contains(root));
-        return true;
-    }
-    
-    void acceptRootLate(Value*) { }
-    
-    template&lt;typename... Arguments&gt;
-    bool acceptInternals(Value* value, Arguments... arguments)
-    {
-        if (!canBeInternal(value))
-            return false;
-        
-        return acceptInternals(arguments...);
-    }
-    bool acceptInternals() { return true; }
-    
-    template&lt;typename... Arguments&gt;
-    void acceptInternalsLate(Value* value, Arguments... arguments)
-    {
-        commitInternal(value);
-        acceptInternalsLate(arguments...);
-    }
-    void acceptInternalsLate() { }
-    
-    template&lt;typename... Arguments&gt;
-    bool acceptOperands(Value* value, Arguments... arguments)
-    {
-        if (locked.contains(value))
-            return false;
-        return acceptOperands(arguments...);
-    }
-    bool acceptOperands() { return true; }
-    
-    template&lt;typename... Arguments&gt;
-    void acceptOperandsLate(Arguments...) { }
-    
-    bool tryLoad(Value* address)
-    {
-        append(
-            moveForType(currentValue-&gt;type()),
-            effectiveAddr(address, currentValue), tmp(currentValue));
-        return true;
-    }
</del><ins>+        switch (m_value-&gt;opcode()) {
+        case Load:{
+            append(
+                moveForType(m_value-&gt;type()),
+                addr(m_value), tmp(m_value));
+            return;
+        }
+            
+        case Load8S: {
+            append(Load8SignedExtendTo32, addr(m_value), tmp(m_value));
+            return;
+        }
</ins><span class="cx"> 
</span><del>-    bool tryLoad8S(Value* address)
-    {
-        append(Load8SignedExtendTo32, effectiveAddr(address, currentValue), tmp(currentValue));
-        return true;
-    }
-    
-    bool tryLoad8Z(Value* address)
-    {
-        append(Load8, effectiveAddr(address, currentValue), tmp(currentValue));
-        return true;
-    }
-    
-    bool tryLoad16S(Value* address)
-    {
-        append(Load16SignedExtendTo32, effectiveAddr(address, currentValue), tmp(currentValue));
-        return true;
-    }
-    
-    bool tryLoad16Z(Value* address)
-    {
-        append(Load16, effectiveAddr(address, currentValue), tmp(currentValue));
-        return true;
-    }
-    
-    bool tryAdd(Value* left, Value* right)
-    {
-        switch (left-&gt;type()) {
-        case Int32:
-            appendBinOp&lt;Add32, Commutative&gt;(left, right);
-            return true;
-        case Int64:
-            appendBinOp&lt;Add64, Commutative&gt;(left, right);
-            return true;
-        default:
-            // FIXME: Implement more types!
-            return false;
</del><ins>+        case Load8Z: {
+            append(Load8, addr(m_value), tmp(m_value));
+            return;
</ins><span class="cx">         }
</span><del>-    }
</del><span class="cx"> 
</span><del>-    bool trySub(Value* left, Value* right)
-    {
-        switch (left-&gt;type()) {
-        case Int32:
-            if (left-&gt;isInt32(0))
-                appendUnOp&lt;Neg32&gt;(right);
-            else
-                appendBinOp&lt;Sub32&gt;(left, right);
-            return true;
-        case Int64:
-            if (left-&gt;isInt64(0))
-                appendUnOp&lt;Neg64&gt;(right);
-            else
-                appendBinOp&lt;Sub64&gt;(left, right);
-            return true;
-        default:
-            // FIXME: Implement more types!
-            return false;
</del><ins>+        case Load16S: {
+            append(Load16SignedExtendTo32, addr(m_value), tmp(m_value));
+            return;
</ins><span class="cx">         }
</span><del>-    }
-    
-    bool tryAnd(Value* left, Value* right)
-    {
-        switch (left-&gt;type()) {
-        case Int32:
-            appendBinOp&lt;And32, Commutative&gt;(left, right);
-            return true;
-        case Int64:
-            appendBinOp&lt;And64, Commutative&gt;(left, right);
-            return true;
-        default:
-            // FIXME: Implement more types!
-            return false;
</del><ins>+
+        case Load16Z: {
+            append(Load16, addr(m_value), tmp(m_value));
+            return;
</ins><span class="cx">         }
</span><del>-    }
</del><span class="cx"> 
</span><del>-    bool tryOr(Value* left, Value* right)
-    {
-        switch (left-&gt;type()) {
-        case Int32:
-            appendBinOp&lt;Or32, Commutative&gt;(left, right);
-            return true;
-        case Int64:
-            appendBinOp&lt;Or64, Commutative&gt;(left, right);
-            return true;
-        default:
-            // FIXME: Implement more types!
-            return false;
</del><ins>+        case Add: {
+            // FIXME: Need a story for doubles.
+            // https://bugs.webkit.org/show_bug.cgi?id=150991
+            appendBinOp&lt;Add32, Add64, Air::Oops, Commutative&gt;(
+                m_value-&gt;child(0), m_value-&gt;child(1));
+            return;
</ins><span class="cx">         }
</span><del>-    }
</del><span class="cx"> 
</span><del>-    bool tryXor(Value* left, Value* right)
-    {
-        switch (left-&gt;type()) {
-        case Int32:
-            appendBinOp&lt;Xor32, Commutative&gt;(left, right);
-            return true;
-        case Int64:
-            appendBinOp&lt;Xor64, Commutative&gt;(left, right);
-            return true;
-        default:
-            // FIXME: Implement more types!
-            return false;
</del><ins>+        case Sub: {
+            if (m_value-&gt;child(0)-&gt;isInt(0))
+                appendUnOp&lt;Neg32, Neg64, Air::Oops&gt;(m_value-&gt;child(1));
+            else
+                appendBinOp&lt;Sub32, Sub64, Air::Oops&gt;(m_value-&gt;child(0), m_value-&gt;child(1));
+            return;
</ins><span class="cx">         }
</span><del>-    }
</del><span class="cx"> 
</span><del>-    void appendShift(Air::Opcode opcode, Value* value, Value* amount)
-    {
-        if (imm(amount)) {
-            append(Move, tmp(value), tmp(currentValue));
-            append(opcode, imm(amount), tmp(currentValue));
</del><ins>+        case BitAnd: {
+            appendBinOp&lt;And32, And64, Air::Oops, Commutative&gt;(
+                m_value-&gt;child(0), m_value-&gt;child(1));
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        append(Move, tmp(value), tmp(currentValue));
-        append(Move, tmp(amount), Tmp(X86Registers::ecx));
-        append(opcode, Tmp(X86Registers::ecx), tmp(currentValue));
-    }
</del><ins>+        case BitOr: {
+            appendBinOp&lt;Or32, Or64, Air::Oops, Commutative&gt;(
+                m_value-&gt;child(0), m_value-&gt;child(1));
+            return;
+        }
</ins><span class="cx"> 
</span><del>-    bool tryShl(Value* value, Value* amount)
-    {
-        Air::Opcode opcode = value-&gt;type() == Int32 ? Lshift32 : Lshift64;
-        appendShift(opcode, value, amount);
-        return true;
-    }
</del><ins>+        case BitXor: {
+            appendBinOp&lt;Xor32, Xor64, Air::Oops, Commutative&gt;(
+                m_value-&gt;child(0), m_value-&gt;child(1));
+            return;
+        }
</ins><span class="cx"> 
</span><del>-    bool trySShr(Value* value, Value* amount)
-    {
-        Air::Opcode opcode = value-&gt;type() == Int32 ? Rshift32 : Rshift64;
-        appendShift(opcode, value, amount);
-        return true;
-    }
-
-    bool tryZShr(Value* value, Value* amount)
-    {
-        Air::Opcode opcode = value-&gt;type() == Int32 ? Urshift32 : Urshift64;
-        appendShift(opcode, value, amount);
-        return true;
-    }
-    
-    bool tryStoreAddLoad(Value* left, Value* right, Value*)
-    {
-        switch (left-&gt;type()) {
-        case Int32:
-            return tryAppendStoreBinOp&lt;Add32, Commutative&gt;(left, right);
-        default:
-            // FIXME: Implement more types!
-            return false;
</del><ins>+        case Shl: {
+            appendShift&lt;Lshift32, Lshift64&gt;(m_value-&gt;child(0), m_value-&gt;child(1));
+            return;
</ins><span class="cx">         }
</span><del>-    }
</del><span class="cx"> 
</span><del>-    bool tryStoreSubLoad(Value* left, Value* right, Value*)
-    {
-        switch (left-&gt;type()) {
-        case Int32:
-            if (left-&gt;isInt32(0))
-                return tryAppendStoreUnOp&lt;Neg32&gt;(right);
-            return tryAppendStoreBinOp&lt;Sub32, NotCommutative&gt;(left, right);
-        default:
-            // FIXME: Implement more types!
-            return false;
</del><ins>+        case SShr: {
+            appendShift&lt;Rshift32, Rshift64&gt;(m_value-&gt;child(0), m_value-&gt;child(1));
+            return;
</ins><span class="cx">         }
</span><del>-    }
</del><span class="cx"> 
</span><del>-    bool tryStoreAndLoad(Value* left, Value* right, Value*)
-    {
-        switch (left-&gt;type()) {
-        case Int32:
-            return tryAppendStoreBinOp&lt;And32, Commutative&gt;(left, right);
-        default:
-            // FIXME: Implement more types!
-            return false;
</del><ins>+        case ZShr: {
+            appendShift&lt;Urshift32, Urshift64&gt;(m_value-&gt;child(0), m_value-&gt;child(1));
+            return;
</ins><span class="cx">         }
</span><del>-    }
-    
-    bool tryStore(Value* value, Value* address)
-    {
-        appendStore(value, effectiveAddr(address, currentValue));
-        return true;
-    }
</del><span class="cx"> 
</span><del>-    bool tryTrunc(Value* value)
-    {
-        ASSERT_UNUSED(value, tmp(value) == tmp(currentValue));
-        return true;
-    }
</del><ins>+        case Store: {
+            Value* valueToStore = m_value-&gt;child(0);
+            if (canBeInternal(valueToStore)) {
+                bool matched = false;
+                switch (valueToStore-&gt;opcode()) {
+                case Add:
+                    matched = tryAppendStoreBinOp&lt;Add32, Add64, Commutative&gt;(
+                        valueToStore-&gt;child(0), valueToStore-&gt;child(1));
+                    break;
+                case Sub:
+                    if (valueToStore-&gt;child(0)-&gt;isInt(0)) {
+                        matched = tryAppendStoreUnOp&lt;Neg32, Neg64&gt;(valueToStore-&gt;child(1));
+                        break;
+                    }
+                    matched = tryAppendStoreBinOp&lt;Sub32, Sub64&gt;(
+                        valueToStore-&gt;child(0), valueToStore-&gt;child(1));
+                    break;
+                case BitAnd:
+                    matched = tryAppendStoreBinOp&lt;And32, And64, Commutative&gt;(
+                        valueToStore-&gt;child(0), valueToStore-&gt;child(1));
+                    break;
+                default:
+                    break;
+                }
+                if (matched) {
+                    commitInternal(valueToStore);
+                    return;
+                }
+            }
</ins><span class="cx"> 
</span><del>-    bool tryZExt32(Value* value)
-    {
-        if (highBitsAreZero(value)) {
-            ASSERT(tmp(value) == tmp(currentValue));
-            return true;
</del><ins>+            appendStore(valueToStore, addr(m_value));
+            return;
</ins><span class="cx">         }
</span><del>-        
-        append(Move32, tmp(value), tmp(currentValue));
-        return true;
-    }
</del><span class="cx"> 
</span><del>-    bool tryArgumentReg()
-    {
-        prologue.append(Inst(
-            moveForType(currentValue-&gt;type()), currentValue,
-            Tmp(currentValue-&gt;as&lt;ArgumentRegValue&gt;()-&gt;argumentReg()),
-            tmp(currentValue)));
-        return true;
-    }
-    
-    bool tryConst32()
-    {
-        append(Move, imm(currentValue), tmp(currentValue));
-        return true;
-    }
-    
-    bool tryConst64()
-    {
-        if (imm(currentValue)) {
-            append(Move, imm(currentValue), tmp(currentValue));
-            return true;
</del><ins>+        case Trunc: {
+            ASSERT(tmp(m_value-&gt;child(0)) == tmp(m_value));
+            return;
</ins><span class="cx">         }
</span><del>-        append(Move, Arg::imm64(currentValue-&gt;asInt64()), tmp(currentValue));
-        return true;
-    }
</del><span class="cx"> 
</span><del>-    bool tryFramePointer()
-    {
-        append(Move, Tmp(GPRInfo::callFrameRegister), tmp(currentValue));
-        return true;
-    }
</del><ins>+        case ZExt32: {
+            if (highBitsAreZero(m_value-&gt;child(0))) {
+                ASSERT(tmp(m_value-&gt;child(0)) == tmp(m_value));
+                return;
+            }
</ins><span class="cx"> 
</span><del>-    bool tryStackSlot()
-    {
-        append(
-            Lea,
-            Arg::stack(stackToStack.get(currentValue-&gt;as&lt;StackSlotValue&gt;())),
-            tmp(currentValue));
-        return true;
-    }
</del><ins>+            append(Move32, tmp(m_value-&gt;child(0)), tmp(m_value));
+            return;
+        }
</ins><span class="cx"> 
</span><del>-    bool tryEqual()
-    {
-        insts.last().append(createCompare(currentValue));
-        return true;
-    }
</del><ins>+        case ArgumentReg: {
+            m_prologue.append(Inst(
+                moveForType(m_value-&gt;type()), m_value,
+                Tmp(m_value-&gt;as&lt;ArgumentRegValue&gt;()-&gt;argumentReg()),
+                tmp(m_value)));
+            return;
+        }
</ins><span class="cx"> 
</span><del>-    bool tryNotEqual()
-    {
-        insts.last().append(createCompare(currentValue));
-        return true;
-    }
</del><ins>+        case Const32:
+        case Const64: {
+            append(Move, immForMove(m_value), tmp(m_value));
+            return;
+        }
</ins><span class="cx"> 
</span><del>-    bool tryLessThan()
-    {
-        insts.last().append(createCompare(currentValue));
-        return true;
-    }
</del><ins>+        case FramePointer: {
+            append(Move, Tmp(GPRInfo::callFrameRegister), tmp(m_value));
+            return;
+        }
</ins><span class="cx"> 
</span><del>-    bool tryGreaterThan()
-    {
-        insts.last().append(createCompare(currentValue));
-        return true;
-    }
</del><ins>+        case B3::StackSlot: {
+            append(
+                Lea,
+                Arg::stack(m_stackToStack.get(m_value-&gt;as&lt;StackSlotValue&gt;())),
+                tmp(m_value));
+            return;
+        }
</ins><span class="cx"> 
</span><del>-    bool tryLessEqual()
-    {
-        insts.last().append(createCompare(currentValue));
-        return true;
-    }
</del><ins>+        case Equal:
+        case NotEqual:
+        case LessThan:
+        case GreaterThan:
+        case LessEqual:
+        case GreaterEqual:
+        case Above:
+        case Below:
+        case AboveEqual:
+        case BelowEqual: {
+            m_insts.last().append(createCompare(m_value));
+            return;
+        }
</ins><span class="cx"> 
</span><del>-    bool tryGreaterEqual()
-    {
-        insts.last().append(createCompare(currentValue));
-        return true;
-    }
</del><ins>+        case Patchpoint: {
+            PatchpointValue* patchpointValue = m_value-&gt;as&lt;PatchpointValue&gt;();
+            ensureSpecial(m_patchpointSpecial);
+            
+            Inst inst(Patch, patchpointValue, Arg::special(m_patchpointSpecial));
+            
+            if (patchpointValue-&gt;type() != Void)
+                inst.args.append(tmp(patchpointValue));
+            
+            fillStackmap(inst, patchpointValue, 0);
+            
+            m_insts.last().append(WTF::move(inst));
+            return;
+        }
</ins><span class="cx"> 
</span><del>-    bool tryAbove()
-    {
-        insts.last().append(createCompare(currentValue));
-        return true;
-    }
</del><ins>+        case Check: {
+            Inst branch = createBranch(m_value-&gt;child(0));
+            
+            CheckSpecial::Key key(branch);
+            auto result = m_checkSpecials.add(key, nullptr);
+            Special* special = ensureSpecial(result.iterator-&gt;value, key);
+            
+            CheckValue* checkValue = m_value-&gt;as&lt;CheckValue&gt;();
+            
+            Inst inst(Patch, checkValue, Arg::special(special));
+            inst.args.appendVector(branch.args);
+            
+            fillStackmap(inst, checkValue, 1);
+            
+            m_insts.last().append(WTF::move(inst));
+            return;
+        }
</ins><span class="cx"> 
</span><del>-    bool tryBelow()
-    {
-        insts.last().append(createCompare(currentValue));
-        return true;
-    }
</del><ins>+        case Upsilon: {
+            Value* value = m_value-&gt;child(0);
+            append(
+                relaxedMoveForType(value-&gt;type()), immOrTmpForMove(value),
+                tmp(m_value-&gt;as&lt;UpsilonValue&gt;()-&gt;phi()));
+            return;
+        }
</ins><span class="cx"> 
</span><del>-    bool tryAboveEqual()
-    {
-        insts.last().append(createCompare(currentValue));
-        return true;
-    }
</del><ins>+        case Phi: {
+            // Our semantics are determined by Upsilons, so we have nothing to do here.
+            return;
+        }
</ins><span class="cx"> 
</span><del>-    bool tryBelowEqual()
-    {
-        insts.last().append(createCompare(currentValue));
-        return true;
-    }
</del><ins>+        case Branch: {
+            m_insts.last().append(createBranch(m_value-&gt;child(0)));
+            return;
+        }
</ins><span class="cx"> 
</span><del>-    PatchpointSpecial* patchpointSpecial { nullptr };
-    bool tryPatchpoint()
-    {
-        PatchpointValue* patchpointValue = currentValue-&gt;as&lt;PatchpointValue&gt;();
-        ensureSpecial(patchpointSpecial);
</del><ins>+        case B3::Jump: {
+            append(Air::Jump);
+            return;
+        }
+            
+        case Identity: {
+            ASSERT(tmp(m_value-&gt;child(0)) == tmp(m_value));
+            return;
+        }
</ins><span class="cx"> 
</span><del>-        Inst inst(Patch, patchpointValue, Arg::special(patchpointSpecial));
</del><ins>+        case Return: {
+            Value* value = m_value-&gt;child(0);
+            append(
+                relaxedMoveForType(value-&gt;type()), immOrTmpForMove(value),
+                Tmp(GPRInfo::returnValueGPR));
+            append(Ret);
+            return;
+        }
</ins><span class="cx"> 
</span><del>-        if (patchpointValue-&gt;type() != Void)
-            inst.args.append(tmp(patchpointValue));
</del><ins>+        default:
+            break;
+        }
</ins><span class="cx"> 
</span><del>-        fillStackmap(inst, patchpointValue, 0);
-        
-        insts.last().append(WTF::move(inst));
-        return true;
</del><ins>+        dataLog(&quot;FATAL: could not lower &quot;, deepDump(m_value), &quot;\n&quot;);
+        RELEASE_ASSERT_NOT_REACHED();
</ins><span class="cx">     }
</span><ins>+    
+    IndexSet&lt;Value&gt; m_locked; // These are values that will have no Tmp in Air.
+    IndexMap&lt;Value, Tmp&gt; m_valueToTmp; // These are values that must have a Tmp in Air. We say that a Value* with a non-null Tmp is &quot;pinned&quot;.
+    IndexMap&lt;B3::BasicBlock, Air::BasicBlock*&gt; m_blockToBlock;
+    HashMap&lt;StackSlotValue*, Air::StackSlot*&gt; m_stackToStack;
</ins><span class="cx"> 
</span><del>-    HashMap&lt;CheckSpecial::Key, CheckSpecial*&gt; checkSpecials;
-    bool tryCheck(Value* value)
-    {
-        Inst branch = createBranch(value);
</del><ins>+    UseCounts m_useCounts;
</ins><span class="cx"> 
</span><del>-        CheckSpecial::Key key(branch);
-        auto result = checkSpecials.add(key, nullptr);
-        Special* special = ensureSpecial(result.iterator-&gt;value, key);
</del><ins>+    Vector&lt;Vector&lt;Inst, 4&gt;&gt; m_insts;
+    Vector&lt;Inst&gt; m_prologue;
</ins><span class="cx"> 
</span><del>-        CheckValue* checkValue = currentValue-&gt;as&lt;CheckValue&gt;();
</del><ins>+    B3::BasicBlock* m_block;
+    unsigned m_index;
+    Value* m_value;
</ins><span class="cx"> 
</span><del>-        Inst inst(Patch, checkValue, Arg::special(special));
-        inst.args.appendVector(branch.args);
</del><ins>+    PatchpointSpecial* m_patchpointSpecial { nullptr };
+    HashMap&lt;CheckSpecial::Key, CheckSpecial*&gt; m_checkSpecials;
</ins><span class="cx"> 
</span><del>-        fillStackmap(inst, checkValue, 1);
-
-        insts.last().append(WTF::move(inst));
-        return true;
-    }
-
-    bool tryUpsilon(Value* value)
-    {
-        append(
-            relaxedMoveForType(value-&gt;type()),
-            immOrTmp(value),
-            tmp(currentValue-&gt;as&lt;UpsilonValue&gt;()-&gt;phi()));
-        return true;
-    }
-
-    bool tryPhi()
-    {
-        // Our semantics are determined by Upsilons, so we have nothing to do here.
-        return true;
-    }
-
-    bool tryBranch(Value* value)
-    {
-        insts.last().append(createBranch(value));
-        return true;
-    }
-
-    bool tryJump()
-    {
-        append(Air::Jump);
-        return true;
-    }
-
-    bool tryIdentity(Value* value)
-    {
-        ASSERT_UNUSED(value, tmp(value) == tmp(currentValue));
-        return true;
-    }
-    
-    bool tryReturn(Value* value)
-    {
-        append(relaxedMoveForType(value-&gt;type()), immOrTmp(value), Tmp(GPRInfo::returnValueGPR));
-        append(Ret);
-        return true;
-    }
-    
-    Procedure&amp; procedure;
-    Code&amp; code;
</del><ins>+    Procedure&amp; m_procedure;
+    Code&amp; m_code;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // anonymous namespace
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3LoweringMatcherpatterns"></a>
<div class="delfile"><h4>Deleted: trunk/Source/JavaScriptCore/b3/B3LoweringMatcher.patterns (192134 => 192135)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3LoweringMatcher.patterns        2015-11-08 01:29:22 UTC (rev 192134)
+++ trunk/Source/JavaScriptCore/b3/B3LoweringMatcher.patterns        2015-11-08 02:10:57 UTC (rev 192135)
</span><span class="lines">@@ -1,91 +0,0 @@
</span><del>-# 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. AND ITS CONTRIBUTORS ``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 ITS 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.
-
-matcher LoweringMatcher
-
-# These rules are considered in a cascade, starting at the top. It's implenented using switch
-# statements wherever possible.
-
-# Note: adding more rules to this matcher is an excellent way of improving performance!
-
-Load = Load(address)
-
-Load8S = Load8S(address)
-Load8Z = Load8Z(address)
-Load16S = Load16S(address)
-Load16Z = Load16Z(address)
-
-Add = Add(left, right)
-Sub = Sub(left, right)
-And = BitAnd(left, right)
-Or = BitOr(left, right)
-Xor = BitXor(left, right)
-
-Shl = Shl(value, amount)
-SShr = SShr(value, amount)
-ZShr = ZShr(value, amount)
-
-StoreAddLoad = Store(Add(left, right), address)
-StoreSubLoad = Store(Sub(left, right), address)
-StoreAndLoad = Store(BitAnd(left, right), address)
-Store = Store(value, address)
-
-Trunc = Trunc(value)
-
-ZExt32 = ZExt32(value)
-
-ArgumentReg = ArgumentReg()
-
-Const32 = Const32()
-Const64 = Const64()
-
-StackSlot = StackSlot()
-FramePointer = FramePointer()
-
-# These patterns delegate to the comparison matcher.
-Equal = Equal()
-NotEqual = NotEqual()
-LessThan = LessThan()
-GreaterThan = GreaterThan()
-LessEqual = LessEqual()
-GreaterEqual = GreaterEqual()
-Above = Above()
-Below = Below()
-AboveEqual = AboveEqual()
-BelowEqual = BelowEqual()
-
-Patchpoint = Patchpoint()
-Check = Check(value)
-
-Upsilon = Upsilon(value)
-Phi = Phi()
-
-Branch = Branch(value)
-Jump = Jump()
-
-# It would be fantastic to not have to have this here, but the philosophy of our lowering is that
-# it should be sound even if we haven't run optimizations.
-Identity = Identity(value)
-
-Return = Return(value)
-
</del></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3generate_pattern_matcherrb"></a>
<div class="delfile"><h4>Deleted: trunk/Source/JavaScriptCore/b3/generate_pattern_matcher.rb (192134 => 192135)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/generate_pattern_matcher.rb        2015-11-08 01:29:22 UTC (rev 192134)
+++ trunk/Source/JavaScriptCore/b3/generate_pattern_matcher.rb        2015-11-08 02:10:57 UTC (rev 192135)
</span><span class="lines">@@ -1,550 +0,0 @@
</span><del>-#!/usr/bin/env ruby
-
-# 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. AND ITS CONTRIBUTORS ``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 ITS 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.
-
-require &quot;pathname&quot;
-
-$varIndex = 0
-def newVar
-    $varIndex += 1
-    &quot;_tmp#{$varIndex}&quot;
-end
-
-class Production
-    attr_reader :origin, :name, :varName, :anonymous, :opcode, :children
-
-    def initialize(origin, name, opcode, children)
-        @origin = origin
-        @name = name
-        @anonymous = (name == nil or name =~ /\A\$([0-9]+)\Z/)
-        @varName = @anonymous ? newVar : name =~ /\A\$/ ? $' : name
-        @opcode = opcode
-        @children = children ? children : []
-    end
-
-    def hasOpcode
-        opcode != nil
-    end
-
-    def eachVariable(&amp;proc)
-        children.each_with_index {
-            | child, index |
-            yield varName,
-                  child.name,
-                  child.varName,
-                  child.anonymous ? (child.opcode ? :anonInternal : :anonOperand) : (child.opcode ? :internal : :operand),
-                  index
-            child.eachVariable(&amp;proc)
-        }
-    end
-end
-
-class Matcher
-    attr_reader :name, :productions
-
-    def initialize(name, productions)
-        @name = name
-        @productions = productions
-    end
-end
-
-class Origin
-    attr_reader :fileName, :lineNumber
-    
-    def initialize(fileName, lineNumber)
-        @fileName = fileName
-        @lineNumber = lineNumber
-    end
-    
-    def to_s
-        &quot;#{fileName}:#{lineNumber}&quot;
-    end
-end
-
-class Token
-    attr_reader :origin, :string
-    
-    def initialize(origin, string)
-        @origin = origin
-        @string = string
-    end
-    
-    def ==(other)
-        if other.is_a? Token
-            @string == other.string
-        else
-            @string == other
-        end
-    end
-    
-    def =~(other)
-        @string =~ other
-    end
-    
-    def to_s
-        &quot;#{@string.inspect} at #{origin}&quot;
-    end
-    
-    def parseError(*comment)
-        if comment.empty?
-            raise &quot;Parse error: #{to_s}&quot;
-        else
-            raise &quot;Parse error: #{to_s}: #{comment[0]}&quot;
-        end
-    end
-end
-
-def lex(str, fileName)
-    fileName = Pathname.new(fileName)
-    result = []
-    lineNumber = 1
-    while not str.empty?
-        case str
-        when /\A\#([^\n]*)/
-            # comment, ignore
-        when /\A\n/
-            # newline, ignore
-            lineNumber += 1
-        when /\A[a-zA-Z0-9$]([a-zA-Z0-9_]*)/
-            result &lt;&lt; Token.new(Origin.new(fileName, lineNumber), $&amp;)
-        when /\A([ \t\r]+)/
-            # whitespace, ignore
-        when /\A[=(),]/
-            result &lt;&lt; Token.new(Origin.new(fileName, lineNumber), $&amp;)
-        else
-            raise &quot;Lexer error at #{Origin.new(fileName, lineNumber).to_s}, unexpected sequence #{str[0..20].inspect}&quot;
-        end
-        str = $~.post_match
-    end
-    result
-end
-
-def isKeyword(token)
-    # We can extend this as we add more keywords. Like, we might want &quot;include&quot; eventually.
-    token =~ /\A((matcher)|(include))\Z/
-end
-
-def isIdentifier(token)
-    token =~ /\A[a-zA-Z0-9$]([a-zA-Z0-9_]*)\Z/ and not isKeyword(token)
-end
-
-class Parser
-    def initialize(data, fileName)
-        @tokens = lex(data, fileName)
-        @idx = 0
-    end
-
-    def token
-        @tokens[@idx]
-    end
-
-    def advance
-        @idx += 1
-    end
-
-    def parseError(*comment)
-        if token
-            token.parseError(*comment)
-        else
-            if comment.empty?
-                raise &quot;Parse error at end of file&quot;
-            else
-                raise &quot;Parse error at end of file: #{comment[0]}&quot;
-            end
-        end
-    end
-
-    def consume(string)
-        parseError(&quot;Expected #{string}&quot;) unless token == string
-        advance
-    end
-
-    def consumeIdentifier
-        result = token.string
-        parseError(&quot;Expected identifier&quot;) unless isIdentifier(result)
-        advance
-        result
-    end
-
-    def addUnique(name, productions, production)
-        if name == production.varName
-            parseError(&quot;Child production has same name as parent production&quot;)
-        end
-        if productions.detect { | entry | entry.name == production.name }
-            parseError(&quot;Duplicate production&quot;)
-        end
-        productions &lt;&lt; production
-    end
-
-    def parse
-        consume(&quot;matcher&quot;)
-
-        matcherName = consumeIdentifier
-
-        productions = []
-
-        loop {
-            break if @idx &gt;= @tokens.length
-
-            # We might want to support &quot;include&quot;. If we did that, it would go here.
-            production = parseProduction
-            
-            if productions.detect { | entry | entry.name == production.name }
-                parseError(&quot;Duplicate production&quot;)
-            end
-
-            productions &lt;&lt; production
-        }
-
-        Matcher.new(matcherName, productions)
-    end
-
-    def parseProduction
-        origin = token.origin
-        name = consumeIdentifier
-
-        if token == &quot;=&quot;
-            consume(&quot;=&quot;)
-            opcode = consumeIdentifier
-            consume(&quot;(&quot;)
-        elsif token == &quot;(&quot;
-            consume(&quot;(&quot;)
-            opcode = name
-            name = nil
-        else
-            return Production.new(origin, name, nil, nil)
-        end
-        
-        productions = []
-        loop {
-            break if token == &quot;)&quot;
-
-            addUnique(name, productions, parseProduction)
-
-            break if token == &quot;)&quot;
-            consume(&quot;,&quot;)
-        }
-
-        # Advance after the &quot;)&quot;
-        advance
-
-        Production.new(origin, name, opcode, productions)
-    end
-end
-
-fileName = ARGV[0]
-
-parser = Parser.new(IO::read(fileName), fileName)
-matcher = parser.parse
-
-class SubMatch
-    attr_reader :indexMap, :productions
-    
-    def initialize(indexList, productions)
-        @indexMap = []
-        @productions = []
-        indexList.each {
-            | index |
-            @indexMap &lt;&lt; index
-            @productions &lt;&lt; productions[index]
-        }
-    end
-
-    def mapIndexList(indexList)
-        indexList.map {
-            | index |
-            @indexMap[index]
-        }
-    end
-end
-
-$stderr.puts &quot;Generating code for #{fileName}.&quot;
-
-File.open(&quot;B3&quot; + matcher.name + &quot;.h&quot;, &quot;w&quot;) {
-    | outp |
-
-    outp.puts &quot;// Generated by generate_pattern_matcher.rb from #{fileName} -- do not edit!&quot;
-
-    outp.puts &quot;#ifndef B3#{matcher.name}_h&quot;
-    outp.puts &quot;#define B3#{matcher.name}_h&quot;
-    
-    outp.puts &quot;#include \&quot;B3Value.h\&quot;&quot;
-    
-    outp.puts &quot;namespace JSC { namespace B3 {&quot;
-
-    outp.puts &quot;template&lt;typename Adaptor&gt;&quot;
-    outp.puts &quot;bool run#{matcher.name}(Value* _value, Adaptor&amp; adaptor)&quot;
-    outp.puts &quot;{&quot;
-
-    # Note that this does not emit properly indented code, because it's a recursive emitter. If you
-    # want to see the code nicely formatted, open it in a good text editor and ask it to format it
-    # for you.
-
-    # In odd situations, we may not use the input value. Tell the compiler to chill out about it.
-    outp.puts &quot;UNUSED_PARAM(_value);&quot;
-        
-    # This just protects the caller from having to worry about productions having different lengths.
-    def matchLength(outp, valueName, productions)
-        indexLists = []
-        productions.each_with_index {
-            | production, index |
-            if indexLists[-1] and productions[indexLists[-1][0]].children.length == production.children.length
-                indexLists[-1] &lt;&lt; index
-            else
-                indexLists &lt;&lt; [index]
-            end
-        }
-
-        indexLists.each {
-            | indexList |
-            length = productions[indexList[0]].children.length
-            if length &gt; 0
-                outp.puts &quot;if (#{valueName}-&gt;children().size() &gt;= #{length}) {&quot;
-                yield indexList
-                outp.puts &quot;}&quot;
-            else
-                yield indexList
-            end
-        }
-    end
-
-    # This efficiently selects from the given set of productions. It assumes that productions
-    # are not duplicated. It yields the index of the found production, and the coroutine is
-    # responsible for emitting specific code for that production. The coroutine is given lists of
-    # indices of possibly-matching productions.
-    def matchProductions(outp, valueName, productions)
-        # First, split the productions list into runs of productions with an opcode and productions
-        # without one.
-        indexLists = []
-        productions.each_with_index {
-            | production, index |
-            if indexLists[-1] and productions[indexLists[-1][0]].hasOpcode == production.hasOpcode
-                indexLists[-1] &lt;&lt; index
-            else
-                indexLists &lt;&lt; [index]
-            end
-        }
-        
-        # Now, emit pattern matching code. We do it differently for lists with an opcode than for
-        # lists without one.
-        indexLists.each {
-            | indexList |
-            if productions[indexList[0]].hasOpcode
-                # Now, we split this index list into groups for each opcode.
-                groups = {}
-                indexList.each {
-                    | index |
-                    production = productions[index]
-                    if groups[production.opcode]
-                        groups[production.opcode] &lt;&lt; index
-                    else
-                        groups[production.opcode] = [index]
-                    end
-                }
-
-                # Emit a switch statement.
-                outp.puts &quot;switch (#{valueName}-&gt;opcode()) {&quot;
-                groups.each_pair {
-                    | opcode, subIndexList |
-                    outp.puts &quot;case #{opcode}:&quot;
-                    subMatch = SubMatch.new(subIndexList, productions)
-                    matchLength(outp, valueName, subMatch.productions) {
-                        | indexList |
-                        yield subMatch.mapIndexList(indexList)
-                    }
-                    outp.puts &quot;break;&quot;
-                }
-                outp.puts &quot;default:&quot;
-                outp.puts &quot;break;&quot;
-                outp.puts &quot;}&quot;
-            else
-                subMatch = SubMatch.new(indexList, productions)
-                matchLength(outp, valueName, subMatch.productions) {
-                    | indexList |
-                    yield subMatch.mapIndexList(indexList)
-                }
-            end
-        }
-    end
-
-    # Takes productions that have the same opcode and the same length and selects from them based on
-    # the productions at the given column.
-    def matchColumn(outp, valueName, productions, columnIndex)
-        if columnIndex &gt;= productions[0].children.length
-            yield (0...(productions.size)).to_a
-            return
-        end
-
-        subValue = newVar
-        
-        outp.puts &quot;{&quot;
-        outp.puts &quot;Value* #{subValue} = #{valueName}-&gt;child(#{columnIndex});&quot;
-
-        # We may not use this value. Tell the compiler to chill out about it.
-        outp.puts &quot;UNUSED_PARAM(#{subValue});&quot;
-        
-        subProductions = productions.map {
-            | production |
-            production.children[columnIndex]
-        }
-
-        matchRecursively(outp, subValue, subProductions) {
-            | indexList |
-            subMatch = SubMatch.new(indexList, productions)
-            matchColumn(outp, valueName, subMatch.productions, columnIndex + 1) {
-                | indexList |
-                yield subMatch.mapIndexList(indexList)
-            }
-        }
-
-        outp.puts &quot;}&quot;
-    end
-
-    def matchRecursively(outp, valueName, productions)
-        matchProductions(outp, valueName, productions) {
-            | indexList |
-            # We are guaranteed that this index list contains productions with the same opcode and
-            # the same length.
-            subMatch = SubMatch.new(indexList, productions)
-            matchColumn(outp, valueName, subMatch.productions, 0) {
-                | indexList |
-                yield subMatch.mapIndexList(indexList)
-            }
-        }
-    end
-
-    matchRecursively(outp, &quot;_value&quot;, matcher.productions) {
-        | indexList |
-        indexList.each {
-            | index |
-            production = matcher.productions[index]
-            outp.puts &quot;{&quot;
-            outp.puts &quot;Value* #{production.varName} = _value;&quot;
-            outp.puts &quot;UNUSED_PARAM(#{production.varName});&quot;
-            internalArguments = []
-            operandArguments = []
-            tryArguments = []
-            numScopes = 0
-            seen = {}
-
-            # FIXME: We want to be able to combine pattern matchers, like have the pattern match rule
-            # for Branch in the lowering patcher delegate to a matcher that can deduce the kind of
-            # comparison that we're doing. We could then reuse that latter matcher for Check and
-            # unfused compare. The key to making such a delegation work is to have the inner matcher
-            # (the comparison matcher in this case) keep cascading if it encounters a rule that
-            # produces something that the outer matcher cannot handle. It's not obvious that the
-            # comparison matcher would need this, but the address matcher probably will. For example,
-            # we may have a StoreAddLoad rule that delegates to the address matcher, and the address
-            # matcher may produce an address that the lowering matcher cannot use because while the
-            # Add form does accept addresses it may not accept the particular address that the
-            # address matcher produced. In that case, instead of giving up on the StoreAddLoad rule,
-            # we want the address matcher to just try a different address. The comparison matcher
-            # might want this just for better controlling when to pin variables. Currently, if it
-            # constructed some code, it would also pin the variables that it used. If the lowering
-            # matcher then decided to reject the code created by the comparison matcher, it would
-            # have a hard time &quot;unpinning&quot; those variables. But if we had some kind of delegation, we
-            # could have the pinning of the comparison matcher happen only if the lowering matcher
-            # accepted.
-            #
-            # This could all be accomplished by having tryBlah() return something, and have the
-            # matcher also take a functor argument that accepts what tryBlah() returns. So instead of
-            #
-            # if (tryBlah()) ok;
-            #
-            # We would have:
-            #
-            # if (functor(tryBlah()) ok;
-            #
-            # When lowering decided to delegate to the address or comparison matcher, it could supply
-            # a functor that decides whether the thing that the sub-matcher selected is indeed
-            # useful.
-            #
-            # In the near term, we probably won't need this. But we will definitely need it as we
-            # expand to efficiently support more platforms. On X86_64, any branching instruction is
-            # usable in any context, and any address should be usable in any context (and the only
-            # cases where it wouldn't be is if we have holes in the MacroAssembler).
-            #
-            # https://bugs.webkit.org/show_bug.cgi?id=150559
-            
-            production.eachVariable {
-                | parentVarName, childName, childVarName, kind, index |
-                loadExpr = &quot;#{parentVarName}-&gt;child(#{index})&quot;
-                
-                if seen[childVarName]
-                    tmp = newVar
-                    outp.puts &quot;Value* #{tmp} = #{loadExpr};&quot;
-                    outp.puts &quot;if (#{tmp} == #{childVarName}) {&quot;
-                    numScopes += 1
-                else
-                    seen[childVarName] = true
-                    
-                    outp.puts &quot;Value* #{childVarName} = #{loadExpr};&quot;
-
-                    # FIXME: Consider getting rid of the $ prefix.
-                    # https://bugs.webkit.org/show_bug.cgi?id=150527
-                    if childName =~ /\A\$/
-                        if childName =~ /\A\$([0-9]+)\Z/
-                            outp.puts &quot;if (#{childVarName}-&gt;isInt(#{$1})) {&quot;
-                        else
-                            outp.puts &quot;if (#{childVarName}-&gt;hasInt()) {&quot;
-                        end
-                        numScopes += 1
-                    end
-                    
-                    internalArguments &lt;&lt; childVarName if kind == :internal or kind == :anonInternal
-                    operandArguments &lt;&lt; childVarName if kind == :operand or kind == :anonOperand
-                    tryArguments &lt;&lt; childVarName if kind == :internal or kind == :operand
-                end
-            }
-            outp.puts &quot;if (adaptor.acceptRoot(_value)&quot;
-            unless internalArguments.empty?
-                outp.puts(&quot;&amp;&amp; adaptor.acceptInternals(&quot; + internalArguments.join(&quot;, &quot;) + &quot;)&quot;)
-            end
-            unless operandArguments.empty?
-                outp.puts(&quot;&amp;&amp; adaptor.acceptOperands(&quot; + operandArguments.join(&quot;, &quot;) + &quot;)&quot;)
-            end
-            outp.puts(&quot;&amp;&amp; adaptor.try#{production.name}(&quot; + tryArguments.join(&quot;, &quot;) + &quot;)) {&quot;)
-            outp.puts &quot;adaptor.acceptRootLate(_value);&quot;
-            unless internalArguments.empty?
-                outp.puts &quot;adaptor.acceptInternalsLate(&quot; + internalArguments.join(&quot;, &quot;) + &quot;);&quot;
-            end
-            unless operandArguments.empty?
-                outp.puts &quot;adaptor.acceptOperandsLate(&quot; + operandArguments.join(&quot;, &quot;) + &quot;);&quot;
-            end
-            outp.puts &quot;return true;&quot;
-            outp.puts &quot;}&quot;
-            numScopes.times {
-                outp.puts &quot;}&quot;
-            }
-            outp.puts &quot;}&quot;
-        }
-    }
-    
-    outp.puts &quot;    return false;&quot;
-    outp.puts &quot;}&quot;
-    
-    outp.puts &quot;} } // namespace JSC::B3&quot;
-
-    outp.puts &quot;#endif // B3#{matcher.name}_h&quot;
-}
</del></span></pre>
</div>
</div>

</body>
</html>