Title: [191846] trunk/Source/_javascript_Core
Revision
191846
Author
[email protected]
Date
2015-10-31 16:12:53 -0700 (Sat, 31 Oct 2015)

Log Message

Air should eliminate dead code
https://bugs.webkit.org/show_bug.cgi?id=150746

Reviewed by Geoffrey Garen.

This adds a very simple dead code elimination to Air. It simply looks at whether a Tmp or
StackSlot has ever been used by a live instruction. An instruction is live if it has non-arg
effects (branching, returning, calling, etc) or if it stores to a live Arg. An Arg is live if
it references a live Tmp or StackSlot, or if it is neither a Tmp nor a StackSlot. The phase
runs these rules to fixpoint, and then removes the dead instructions.

This also changes the AirOpcodes parser to handle multiple attributes per opcode, so that we
could conceivably say things like "FooBar /branch /effects". It also adds the /effects
attribute, which we currently use for Breakpoint and nothing else. C calls, patchpoints, and
checks are all Specials, and the Special base class by default always claims that the
instruction has effects. In the future, we could have B3 use a Patch in Air to implement
exotic math constructs; then the Special associated with that thing would claim that there
are no effects.

* _javascript_Core.xcodeproj/project.pbxproj:
* b3/air/AirBasicBlock.h:
(JSC::B3::Air::BasicBlock::begin):
(JSC::B3::Air::BasicBlock::end):
(JSC::B3::Air::BasicBlock::at):
(JSC::B3::Air::BasicBlock::last):
(JSC::B3::Air::BasicBlock::resize):
(JSC::B3::Air::BasicBlock::appendInst):
* b3/air/AirEliminateDeadCode.cpp: Added.
(JSC::B3::Air::eliminateDeadCode):
* b3/air/AirEliminateDeadCode.h: Added.
* b3/air/AirGenerate.cpp:
(JSC::B3::Air::generate):
* b3/air/AirInst.h:
* b3/air/AirOpcode.opcodes:
* b3/air/AirSpecial.cpp:
(JSC::B3::Air::Special::name):
(JSC::B3::Air::Special::hasNonArgNonControlEffects):
(JSC::B3::Air::Special::dump):
* b3/air/AirSpecial.h:
* b3/air/opcode_generator.rb:

Modified Paths

Added Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (191845 => 191846)


--- trunk/Source/_javascript_Core/ChangeLog	2015-10-31 23:01:30 UTC (rev 191845)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-10-31 23:12:53 UTC (rev 191846)
@@ -1,3 +1,46 @@
+2015-10-30  Filip Pizlo  <[email protected]>
+
+        Air should eliminate dead code
+        https://bugs.webkit.org/show_bug.cgi?id=150746
+
+        Reviewed by Geoffrey Garen.
+
+        This adds a very simple dead code elimination to Air. It simply looks at whether a Tmp or
+        StackSlot has ever been used by a live instruction. An instruction is live if it has non-arg
+        effects (branching, returning, calling, etc) or if it stores to a live Arg. An Arg is live if
+        it references a live Tmp or StackSlot, or if it is neither a Tmp nor a StackSlot. The phase
+        runs these rules to fixpoint, and then removes the dead instructions.
+
+        This also changes the AirOpcodes parser to handle multiple attributes per opcode, so that we
+        could conceivably say things like "FooBar /branch /effects". It also adds the /effects
+        attribute, which we currently use for Breakpoint and nothing else. C calls, patchpoints, and
+        checks are all Specials, and the Special base class by default always claims that the
+        instruction has effects. In the future, we could have B3 use a Patch in Air to implement
+        exotic math constructs; then the Special associated with that thing would claim that there
+        are no effects.
+
+        * _javascript_Core.xcodeproj/project.pbxproj:
+        * b3/air/AirBasicBlock.h:
+        (JSC::B3::Air::BasicBlock::begin):
+        (JSC::B3::Air::BasicBlock::end):
+        (JSC::B3::Air::BasicBlock::at):
+        (JSC::B3::Air::BasicBlock::last):
+        (JSC::B3::Air::BasicBlock::resize):
+        (JSC::B3::Air::BasicBlock::appendInst):
+        * b3/air/AirEliminateDeadCode.cpp: Added.
+        (JSC::B3::Air::eliminateDeadCode):
+        * b3/air/AirEliminateDeadCode.h: Added.
+        * b3/air/AirGenerate.cpp:
+        (JSC::B3::Air::generate):
+        * b3/air/AirInst.h:
+        * b3/air/AirOpcode.opcodes:
+        * b3/air/AirSpecial.cpp:
+        (JSC::B3::Air::Special::name):
+        (JSC::B3::Air::Special::hasNonArgNonControlEffects):
+        (JSC::B3::Air::Special::dump):
+        * b3/air/AirSpecial.h:
+        * b3/air/opcode_generator.rb:
+
 2015-10-31  Filip Pizlo  <[email protected]>
 
         Air needs a late register liveness phase that calls Special::reportUsedRegisters()

Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (191845 => 191846)


--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2015-10-31 23:01:30 UTC (rev 191845)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2015-10-31 23:12:53 UTC (rev 191846)
@@ -311,6 +311,8 @@
 		0F426A491460CBB700131F8F /* VirtualRegister.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F426A461460CBAB00131F8F /* VirtualRegister.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0F426A4B1460CD6E00131F8F /* DataFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F426A4A1460CD6B00131F8F /* DataFormat.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0F431738146BAC69007E3890 /* ListableHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F431736146BAC65007E3890 /* ListableHandler.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		0F4570381BE44C910062A629 /* AirEliminateDeadCode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F4570361BE44C910062A629 /* AirEliminateDeadCode.cpp */; };
+		0F4570391BE44C910062A629 /* AirEliminateDeadCode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F4570371BE44C910062A629 /* AirEliminateDeadCode.h */; };
 		0F45703C1BE45F0A0062A629 /* AirReportUsedRegisters.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F45703A1BE45F0A0062A629 /* AirReportUsedRegisters.cpp */; };
 		0F45703D1BE45F0A0062A629 /* AirReportUsedRegisters.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F45703B1BE45F0A0062A629 /* AirReportUsedRegisters.h */; };
 		0F46808214BA572D00BFE272 /* JITExceptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F46808014BA572700BFE272 /* JITExceptions.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -2327,6 +2329,8 @@
 		0F426A461460CBAB00131F8F /* VirtualRegister.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VirtualRegister.h; sourceTree = "<group>"; };
 		0F426A4A1460CD6B00131F8F /* DataFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataFormat.h; sourceTree = "<group>"; };
 		0F431736146BAC65007E3890 /* ListableHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ListableHandler.h; sourceTree = "<group>"; };
+		0F4570361BE44C910062A629 /* AirEliminateDeadCode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AirEliminateDeadCode.cpp; path = b3/air/AirEliminateDeadCode.cpp; sourceTree = "<group>"; };
+		0F4570371BE44C910062A629 /* AirEliminateDeadCode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AirEliminateDeadCode.h; path = b3/air/AirEliminateDeadCode.h; sourceTree = "<group>"; };
 		0F45703A1BE45F0A0062A629 /* AirReportUsedRegisters.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AirReportUsedRegisters.cpp; path = b3/air/AirReportUsedRegisters.cpp; sourceTree = "<group>"; };
 		0F45703B1BE45F0A0062A629 /* AirReportUsedRegisters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AirReportUsedRegisters.h; path = b3/air/AirReportUsedRegisters.h; sourceTree = "<group>"; };
 		0F46807F14BA572700BFE272 /* JITExceptions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITExceptions.cpp; sourceTree = "<group>"; };
@@ -4482,6 +4486,8 @@
 				0FEC854F1BDACDC70080FF74 /* AirCCallSpecial.h */,
 				0FEC85501BDACDC70080FF74 /* AirCode.cpp */,
 				0FEC85511BDACDC70080FF74 /* AirCode.h */,
+				0F4570361BE44C910062A629 /* AirEliminateDeadCode.cpp */,
+				0F4570371BE44C910062A629 /* AirEliminateDeadCode.h */,
 				0FEC85521BDACDC70080FF74 /* AirFrequentedBlock.h */,
 				0FEC85531BDACDC70080FF74 /* AirGenerate.cpp */,
 				0FEC85541BDACDC70080FF74 /* AirGenerate.h */,
@@ -7540,6 +7546,7 @@
 				A7B601821639FD2A00372BA3 /* UnlinkedCodeBlock.h in Headers */,
 				996B73261BDA08EF00331B84 /* StringIteratorPrototype.lut.h in Headers */,
 				14142E511B796ECE00F4BF4B /* UnlinkedFunctionExecutable.h in Headers */,
+				0F4570391BE44C910062A629 /* AirEliminateDeadCode.h in Headers */,
 				0F2E892C16D028AD009E4FD2 /* UnusedPointer.h in Headers */,
 				99DA00B11BD5994E00F4575C /* UpdateContents.py in Headers */,
 				0F963B3813FC6FE90002D9B2 /* ValueProfile.h in Headers */,
@@ -8279,6 +8286,7 @@
 				0FD8A32517D51F5700CA2C40 /* DFGOSREntrypointCreationPhase.cpp in Sources */,
 				0FC09791146A6F7100CF2442 /* DFGOSRExit.cpp in Sources */,
 				0F235BEB17178E7300690C7F /* DFGOSRExitBase.cpp in Sources */,
+				0F4570381BE44C910062A629 /* AirEliminateDeadCode.cpp in Sources */,
 				0FC09792146A6F7300CF2442 /* DFGOSRExitCompiler.cpp in Sources */,
 				0FC09776146943B000CF2442 /* DFGOSRExitCompiler32_64.cpp in Sources */,
 				0FC0977214693AF900CF2442 /* DFGOSRExitCompiler64.cpp in Sources */,

Modified: trunk/Source/_javascript_Core/b3/air/AirBasicBlock.h (191845 => 191846)


--- trunk/Source/_javascript_Core/b3/air/AirBasicBlock.h	2015-10-31 23:01:30 UTC (rev 191845)
+++ trunk/Source/_javascript_Core/b3/air/AirBasicBlock.h	2015-10-31 23:12:53 UTC (rev 191846)
@@ -57,12 +57,14 @@
     InstList::const_iterator begin() const { return m_insts.begin(); }
     InstList::const_iterator end() const { return m_insts.end(); }
 
-    const Inst& at(size_t index) const { return m_insts[index]; }
-    Inst& at(size_t index) { return m_insts[index]; }
+    const Inst& at(unsigned index) const { return m_insts[index]; }
+    Inst& at(unsigned index) { return m_insts[index]; }
 
     const Inst& last() const { return m_insts.last(); }
     Inst& last() { return m_insts.last(); }
 
+    void resize(unsigned size) { m_insts.resize(size); }
+
     template<typename Inst>
     void appendInst(Inst&& inst)
     {

Added: trunk/Source/_javascript_Core/b3/air/AirEliminateDeadCode.cpp (0 => 191846)


--- trunk/Source/_javascript_Core/b3/air/AirEliminateDeadCode.cpp	                        (rev 0)
+++ trunk/Source/_javascript_Core/b3/air/AirEliminateDeadCode.cpp	2015-10-31 23:12:53 UTC (rev 191846)
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+#include "AirEliminateDeadCode.h"
+
+#if ENABLE(B3_JIT)
+
+#include "AirCode.h"
+#include "AirInstInlines.h"
+#include "AirPhaseScope.h"
+#include "B3IndexSet.h"
+
+namespace JSC { namespace B3 { namespace Air {
+
+bool eliminateDeadCode(Code& code)
+{
+    PhaseScope phaseScope(code, "eliminateDeadCode");
+
+    HashSet<Tmp> liveTmps;
+    IndexSet<StackSlot> liveStackSlots;
+    bool changed;
+
+    auto isArgLive = [&] (const Arg& arg) -> bool {
+        switch (arg.kind()) {
+        case Arg::Tmp:
+            if (arg.isReg())
+                return true;
+            return liveTmps.contains(arg.tmp());
+        case Arg::Stack:
+            if (arg.stackSlot()->isLocked())
+                return true;
+            return liveStackSlots.contains(arg.stackSlot());
+        default:
+            return true;
+        }
+    };
+
+    auto addLiveArg = [&] (const Arg& arg) -> bool {
+        switch (arg.kind()) {
+        case Arg::Tmp:
+            if (arg.isReg())
+                return false;
+            return liveTmps.add(arg.tmp()).isNewEntry;
+        case Arg::Stack:
+            if (arg.stackSlot()->isLocked())
+                return false;
+            return liveStackSlots.add(arg.stackSlot());
+        default:
+            return false;
+        }
+    };
+
+    auto isInstLive = [&] (Inst& inst) -> bool {
+        if (inst.hasNonArgEffects())
+            return true;
+
+        // This instruction should be presumed dead, if its Args are all dead.
+        bool storesToLive = false;
+        inst.forEachArg(
+            [&] (Arg& arg, Arg::Role role, Arg::Type) {
+                if (!Arg::isDef(role))
+                    return;
+                storesToLive |= isArgLive(arg);
+            });
+        return storesToLive;
+    };
+
+    auto handleInst = [&] (Inst& inst) {
+        if (!isInstLive(inst))
+            return;
+
+        // We get here if the Inst is live. For simplicity we say that a live instruction forces
+        // liveness upon everything it mentions.
+        for (Arg& arg : inst.args) {
+            changed |= addLiveArg(arg);
+            arg.forEachTmpFast(
+                [&] (Tmp& tmp) {
+                    changed |= addLiveArg(tmp);
+                });
+        }
+    };
+
+    auto runForward = [&] () -> bool {
+        changed = false;
+        for (BasicBlock* block : code) {
+            for (Inst& inst : *block)
+                handleInst(inst);
+        }
+        return changed;
+    };
+
+    auto runBackward = [&] () -> bool {
+        changed = false;
+        for (unsigned blockIndex = code.size(); blockIndex--;) {
+            BasicBlock* block = code[blockIndex];
+            for (unsigned instIndex = block->size(); instIndex--;)
+                handleInst(block->at(instIndex));
+        }
+        return changed;
+    };
+
+    for (;;) {
+        // Propagating backward is most likely to be profitable.
+        if (!runBackward())
+            break;
+        if (!runBackward())
+            break;
+
+        // Occasionally propagating forward greatly reduces the likelihood of pathologies.
+        if (!runForward())
+            break;
+    }
+
+    changed = false;
+    for (BasicBlock* block : code) {
+        unsigned sourceIndex = 0;
+        unsigned targetIndex = 0;
+        while (sourceIndex < block->size()) {
+            Inst inst = WTF::move(block->at(sourceIndex++));
+            if (isInstLive(inst))
+                block->at(targetIndex++) = WTF::move(inst);
+            else
+                changed = true;
+        }
+        block->resize(targetIndex);
+    }
+
+    return changed;
+}
+
+} } } // namespace JSC::B3::Air
+
+#endif // ENABLE(B3_JIT)
+

Added: trunk/Source/_javascript_Core/b3/air/AirEliminateDeadCode.h (0 => 191846)


--- trunk/Source/_javascript_Core/b3/air/AirEliminateDeadCode.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/b3/air/AirEliminateDeadCode.h	2015-10-31 23:12:53 UTC (rev 191846)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef AirEliminateDeadCode_h
+#define AirEliminateDeadCode_h
+
+#if ENABLE(B3_JIT)
+
+namespace JSC { namespace B3 { namespace Air {
+
+class Code;
+
+// This eliminates instructions that have no observable effect. These are instructions whose only
+// effect would be storing to some Arg, except that we proved that the location specified by the Arg
+// is never loaded from. The only Args for which we can do such analysis are non-Reg Tmps and
+// anonymous StackSlots.
+
+bool eliminateDeadCode(Code&);
+
+} } } // namespace JSC::B3::Air
+
+#endif // ENABLE(B3_JIT)
+
+#endif // AirEliminateDeadCode_h
+

Modified: trunk/Source/_javascript_Core/b3/air/AirGenerate.cpp (191845 => 191846)


--- trunk/Source/_javascript_Core/b3/air/AirGenerate.cpp	2015-10-31 23:01:30 UTC (rev 191845)
+++ trunk/Source/_javascript_Core/b3/air/AirGenerate.cpp	2015-10-31 23:12:53 UTC (rev 191846)
@@ -30,6 +30,7 @@
 
 #include "AirAllocateStack.h"
 #include "AirCode.h"
+#include "AirEliminateDeadCode.h"
 #include "AirGenerationContext.h"
 #include "AirHandleCalleeSaves.h"
 #include "AirReportUsedRegisters.h"
@@ -58,6 +59,8 @@
     // This is where we run our optimizations and transformations.
     // FIXME: Add Air optimizations.
     // https://bugs.webkit.org/show_bug.cgi?id=150456
+    
+    eliminateDeadCode(code);
 
     // This is where we would have a real register allocator. Then, we could use spillEverything()
     // in place of the register allocator only for testing.

Modified: trunk/Source/_javascript_Core/b3/air/AirInst.h (191845 => 191846)


--- trunk/Source/_javascript_Core/b3/air/AirInst.h	2015-10-31 23:01:30 UTC (rev 191845)
+++ trunk/Source/_javascript_Core/b3/air/AirInst.h	2015-10-31 23:12:53 UTC (rev 191846)
@@ -141,6 +141,14 @@
     // This function is auto-generated by opcode_generator.rb.
     bool admitsStack(unsigned argIndex);
 
+    // Returns true if this instruction can have any effects other than control flow or arguments.
+    bool hasNonArgNonControlEffects();
+
+    // Returns true if this instruction can have any effects other than what is implied by arguments.
+    // For example, "Move $42, (%rax)" will return false because the effect of storing to (%rax) is
+    // implied by the second argument.
+    bool hasNonArgEffects();
+
     // Generate some code for this instruction. This is, like, literally our backend. If this is the
     // terminal, it returns the jump that needs to be linked for the "then" case, with the "else"
     // case being fall-through. This function is auto-generated by opcode_generator.rb.

Modified: trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes (191845 => 191846)


--- trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes	2015-10-31 23:01:30 UTC (rev 191845)
+++ trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes	2015-10-31 23:12:53 UTC (rev 191846)
@@ -131,6 +131,8 @@
     Index, Tmp as load32
     Tmp, Addr as store32
     Tmp, Index as store32
+    Imm, Addr as store32
+    Imm, Index as store32
 
 MoveDouble U:F, D:F
     Tmp, Tmp
@@ -186,7 +188,7 @@
 
 Ret /terminal
 
-Breakpoint /terminal
+Breakpoint /effects
 
 # Air allows for exotic behavior. A Patch's behavior is determined entirely by the Special operand,
 # which must be the first operand.

Modified: trunk/Source/_javascript_Core/b3/air/AirSpecial.cpp (191845 => 191846)


--- trunk/Source/_javascript_Core/b3/air/AirSpecial.cpp	2015-10-31 23:01:30 UTC (rev 191845)
+++ trunk/Source/_javascript_Core/b3/air/AirSpecial.cpp	2015-10-31 23:12:53 UTC (rev 191846)
@@ -50,6 +50,11 @@
     return out.toCString();
 }
 
+bool Special::hasNonArgNonControlEffects()
+{
+    return true;
+}
+
 void Special::dump(PrintStream& out) const
 {
     out.print(dumpPrefix);

Modified: trunk/Source/_javascript_Core/b3/air/AirSpecial.h (191845 => 191846)


--- trunk/Source/_javascript_Core/b3/air/AirSpecial.h	2015-10-31 23:01:30 UTC (rev 191845)
+++ trunk/Source/_javascript_Core/b3/air/AirSpecial.h	2015-10-31 23:12:53 UTC (rev 191846)
@@ -82,6 +82,9 @@
 
     virtual const RegisterSet& extraClobberedRegs(Inst&) = 0;
 
+    // By default, this returns true.
+    virtual bool hasNonArgNonControlEffects();
+
     void dump(PrintStream&) const;
     void deepDump(PrintStream&) const;
 

Modified: trunk/Source/_javascript_Core/b3/air/opcode_generator.rb (191845 => 191846)


--- trunk/Source/_javascript_Core/b3/air/opcode_generator.rb	2015-10-31 23:01:30 UTC (rev 191845)
+++ trunk/Source/_javascript_Core/b3/air/opcode_generator.rb	2015-10-31 23:12:53 UTC (rev 191846)
@@ -27,12 +27,12 @@
 
 class Opcode
     attr_reader :name, :special, :overloads
-    attr_accessor :kind
+    attr_reader :attributes
 
     def initialize(name, special)
         @name = name
         @special = special
-        @kind = :inst
+        @attributes = {}
         unless special
             @overloads = []
         end
@@ -291,13 +291,15 @@
                     }
                 end
 
-                if token == "/"
+                while token == "/"
                     consume("/")
                     case token.string
                     when "branch"
-                        opcode.kind = :branch
+                        opcode.attributes[:branch] = true
                     when "terminal"
-                        opcode.kind = :terminal
+                        opcode.attributes[:terminal] = true
+                    when "effects"
+                        opcode.attributes[:effects] = true
                     else
                         parseError("Bad / directive")
                     end
@@ -580,7 +582,7 @@
     outp.puts "switch (opcode) {"
     $opcodes.values.each {
         | opcode |
-        if opcode.kind == :terminal or opcode.kind == :branch
+        if opcode.attributes[:terminal] or opcode.attributes[:branch]
             outp.puts "case #{opcode.name}:"
         end
     }
@@ -786,6 +788,50 @@
     outp.puts "return false;"
     outp.puts "}"
 
+    outp.puts "bool Inst::hasNonArgNonControlEffects()"
+    outp.puts "{"
+    outp.puts "switch (opcode) {"
+    $opcodes.values.each {
+        | opcode |
+        if opcode.attributes[:effects]
+            outp.puts "case #{opcode.name}:"
+        end
+    }
+    outp.puts "return true;"
+    $opcodes.values.each {
+        | opcode |
+        if opcode.special
+            outp.puts "case #{opcode.name}:"
+        end
+    }
+    outp.puts "return args[0].special()->hasNonArgNonControlEffects();"
+    outp.puts "default:"
+    outp.puts "return false;"
+    outp.puts "}"
+    outp.puts "}"
+    
+    outp.puts "bool Inst::hasNonArgEffects()"
+    outp.puts "{"
+    outp.puts "switch (opcode) {"
+    $opcodes.values.each {
+        | opcode |
+        if opcode.attributes[:branch] or opcode.attributes[:terminal] or opcode.attributes[:effects]
+            outp.puts "case #{opcode.name}:"
+        end
+    }
+    outp.puts "return true;"
+    $opcodes.values.each {
+        | opcode |
+        if opcode.special
+            outp.puts "case #{opcode.name}:"
+        end
+    }
+    outp.puts "return args[0].special()->hasNonArgNonControlEffects();"
+    outp.puts "default:"
+    outp.puts "return false;"
+    outp.puts "}"
+    outp.puts "}"
+    
     outp.puts "CCallHelpers::Jump Inst::generate(CCallHelpers& jit, GenerationContext& context)"
     outp.puts "{"
     outp.puts "UNUSED_PARAM(jit);"
@@ -801,7 +847,7 @@
             else
                 methodName = opcode.masmName
             end
-            if opcode.kind == :branch
+            if opcode.attributes[:branch]
                 outp.print "result = "
             end
             outp.print "jit.#{methodName}("
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to