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}("