diff options
Diffstat (limited to 'Source/JavaScriptCore/b3/B3FoldPathConstants.cpp')
-rw-r--r-- | Source/JavaScriptCore/b3/B3FoldPathConstants.cpp | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/b3/B3FoldPathConstants.cpp b/Source/JavaScriptCore/b3/B3FoldPathConstants.cpp new file mode 100644 index 000000000..919f2da1f --- /dev/null +++ b/Source/JavaScriptCore/b3/B3FoldPathConstants.cpp @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2016 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 "B3FoldPathConstants.h" + +#if ENABLE(B3_JIT) + +#include "B3BasicBlockInlines.h" +#include "B3ControlValue.h" +#include "B3Dominators.h" +#include "B3InsertionSetInlines.h" +#include "B3PhaseScope.h" +#include "B3ProcedureInlines.h" +#include "B3SwitchValue.h" +#include "B3ValueInlines.h" + +namespace JSC { namespace B3 { + +namespace { + +const bool verbose = false; + +class FoldPathConstants { +public: + FoldPathConstants(Procedure& proc) + : m_proc(proc) + , m_insertionSet(proc) + { + } + + void run() + { + bool changed = false; + + if (verbose) + dataLog("B3 before folding path constants: \n", m_proc, "\n"); + + // Find all of the values that are the subject of a branch or switch. For any successor + // that we dominate, install a value override at that block. + + HashMap<Value*, Vector<Override>> overrides; + + Dominators& dominators = m_proc.dominators(); + + auto addOverride = [&] ( + BasicBlock* from, Value* value, const Override& override) { + + if (override.block->numPredecessors() != 1) + return; + ASSERT(override.block->predecessor(0) == from); + + Vector<Override>& forValue = + overrides.add(value, Vector<Override>()).iterator->value; + + if (!ASSERT_DISABLED) { + for (const Override& otherOverride : forValue) + ASSERT_UNUSED(otherOverride, otherOverride.block != override.block); + } + + if (verbose) + dataLog("Overriding ", *value, " from ", *from, ": ", override, "\n"); + + forValue.append(override); + }; + + for (BasicBlock* block : m_proc) { + ControlValue* branch = block->last()->as<ControlValue>(); + switch (branch->opcode()) { + case Branch: + if (branch->successorBlock(0) == branch->successorBlock(1)) + continue; + addOverride( + block, branch->child(0), + Override::nonZero(branch->successorBlock(0))); + addOverride( + block, branch->child(0), + Override::constant(branch->successorBlock(1), 0)); + break; + case Switch: { + HashMap<BasicBlock*, unsigned> targetUses; + for (const SwitchCase& switchCase : *branch->as<SwitchValue>()) + targetUses.add(switchCase.targetBlock(), 0).iterator->value++; + + for (const SwitchCase& switchCase : *branch->as<SwitchValue>()) { + if (targetUses.find(switchCase.targetBlock())->value != 1) + continue; + + addOverride( + block, branch->child(0), + Override::constant(switchCase.targetBlock(), switchCase.caseValue())); + } + break; + } + default: + break; + } + } + + // Install the constants in the override blocks. We use one-shot insertion sets because + // each block will get at most one thing inserted into it anyway. + for (auto& entry : overrides) { + for (Override& override : entry.value) { + if (!override.hasValue) + continue; + override.valueNode = + m_insertionSet.insertIntConstant(0, entry.key, override.value); + m_insertionSet.execute(override.block); + } + } + + // Replace all uses of a value that has an override with that override, if appropriate. + // Certain instructions get special treatment. + auto getOverride = [&] (BasicBlock* block, Value* value) -> Override { + auto iter = overrides.find(value); + if (iter == overrides.end()) + return Override(); + + Vector<Override>& forValue = iter->value; + Override result; + for (Override& override : forValue) { + if (dominators.dominates(override.block, block) + && override.isBetterThan(result)) + result = override; + } + + if (verbose) + dataLog("In block ", *block, " getting override for ", *value, ": ", result, "\n"); + + return result; + }; + + for (BasicBlock* block : m_proc) { + for (unsigned valueIndex = 0; valueIndex < block->size(); ++valueIndex) { + Value* value = block->at(valueIndex); + + switch (value->opcode()) { + case Branch: { + ControlValue* branch = value->as<ControlValue>(); + if (getOverride(block, branch->child(0)).isNonZero) { + branch->convertToJump(branch->taken().block()); + changed = true; + } + break; + } + + case Equal: { + if (value->child(1)->isInt(0) + && getOverride(block, value->child(0)).isNonZero) { + value->replaceWithIdentity( + m_insertionSet.insertIntConstant(valueIndex, value, 0)); + } + break; + } + + case NotEqual: { + if (value->child(1)->isInt(0) + && getOverride(block, value->child(0)).isNonZero) { + value->replaceWithIdentity( + m_insertionSet.insertIntConstant(valueIndex, value, 1)); + } + break; + } + + default: + break; + } + + for (Value*& child : value->children()) { + Override override = getOverride(block, child); + if (override.valueNode) + child = override.valueNode; + } + } + m_insertionSet.execute(block); + } + + if (changed) { + m_proc.resetReachability(); + m_proc.invalidateCFG(); + } + } + +private: + struct Override { + Override() + { + } + + static Override constant(BasicBlock* block, int64_t value) + { + Override result; + result.block = block; + result.hasValue = true; + result.value = value; + if (value) + result.isNonZero = true; + return result; + } + + static Override nonZero(BasicBlock* block) + { + Override result; + result.block = block; + result.isNonZero = true; + return result; + } + + bool isBetterThan(const Override& override) + { + if (hasValue && !override.hasValue) + return true; + if (isNonZero && !override.isNonZero) + return true; + return false; + } + + void dump(PrintStream& out) const + { + out.print("{block = ", pointerDump(block), ", value = "); + if (hasValue) + out.print(value); + else + out.print("<none>"); + out.print(", isNonZero = ", isNonZero); + if (valueNode) + out.print(", valueNode = ", *valueNode); + out.print("}"); + } + + BasicBlock* block { nullptr }; + bool hasValue { false }; + bool isNonZero { false }; + int64_t value { 0 }; + Value* valueNode { nullptr }; + }; + + Procedure& m_proc; + InsertionSet m_insertionSet; +}; + +} // anonymous namespace + +void foldPathConstants(Procedure& proc) +{ + PhaseScope phaseScope(proc, "foldPathConstants"); + FoldPathConstants foldPathConstants(proc); + foldPathConstants.run(); +} + +} } // namespace JSC::B3 + +#endif // ENABLE(B3_JIT) + |