From ebb2d05ec16a9a30cc58c7e5ef3586cce531e539 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Thu, 26 Feb 2015 22:17:51 -0800 Subject: [PATCH] Bug 1137573 - OdinMonkey: Alignment Mask Analysis r=luke --- js/src/jit/AlignmentMaskAnalysis.cpp | 89 +++++++++++++++++++++++++ js/src/jit/AlignmentMaskAnalysis.h | 30 +++++++++ js/src/jit/EffectiveAddressAnalysis.cpp | 32 +-------- js/src/jit/Ion.cpp | 13 ++++ js/src/jit/IonOptimizationLevels.cpp | 1 + js/src/jit/IonOptimizationLevels.h | 7 ++ js/src/jit/JitOptions.cpp | 3 + js/src/jit/JitOptions.h | 1 + js/src/moz.build | 1 + js/src/vm/TraceLogging.cpp | 1 + js/src/vm/TraceLoggingTypes.h | 1 + 11 files changed, 149 insertions(+), 30 deletions(-) create mode 100644 js/src/jit/AlignmentMaskAnalysis.cpp create mode 100644 js/src/jit/AlignmentMaskAnalysis.h diff --git a/js/src/jit/AlignmentMaskAnalysis.cpp b/js/src/jit/AlignmentMaskAnalysis.cpp new file mode 100644 index 00000000000..e2f0764c640 --- /dev/null +++ b/js/src/jit/AlignmentMaskAnalysis.cpp @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "jit/AlignmentMaskAnalysis.h" +#include "jit/MIR.h" +#include "jit/MIRGraph.h" + +using namespace js; +using namespace jit; + +static bool +IsAlignmentMask(uint32_t m) +{ + // Test whether m is just leading ones and trailing zeros. + return (-m & ~m) == 0; +} + +static void +AnalyzeAsmHeapAddress(MDefinition *ptr, MIRGraph &graph) +{ + // Fold (a+i)&m to (a&m)+i, since the users of the BitAnd include heap + // accesses. This will expose the redundancy for GVN when expressions + // like this: + // a&m + // (a+1)&m, + // (a+2)&m, + // are transformed into this: + // a&m + // (a&m)+1 + // (a&m)+2 + // and it will allow the constants to be folded by the + // EffectiveAddressAnalysis pass. + + if (!ptr->isBitAnd()) + return; + + MDefinition *lhs = ptr->toBitAnd()->getOperand(0); + MDefinition *rhs = ptr->toBitAnd()->getOperand(1); + int lhsIndex = 0; + if (lhs->isConstantValue()) { + mozilla::Swap(lhs, rhs); + lhsIndex = 1; + } + if (!lhs->isAdd() || !lhs->hasOneUse() || !rhs->isConstantValue()) + return; + + MDefinition *op0 = lhs->toAdd()->getOperand(0); + MDefinition *op1 = lhs->toAdd()->getOperand(1); + int op0Index = 0; + if (op0->isConstantValue()) { + mozilla::Swap(op0, op1); + op0Index = 1; + } + if (!op1->isConstantValue()) + return; + + uint32_t i = op1->constantValue().toInt32(); + uint32_t m = rhs->constantValue().toInt32(); + if (!IsAlignmentMask(m) || ((i & m) != i)) + return; + + ptr->replaceAllUsesWith(lhs); + ptr->toBitAnd()->replaceOperand(lhsIndex, op0); + lhs->toAdd()->replaceOperand(op0Index, ptr); + + MInstructionIterator iter = ptr->block()->begin(ptr->toBitAnd()); + ++iter; + lhs->block()->moveBefore(*iter, lhs->toAdd()); +} + +bool +AlignmentMaskAnalysis::analyze() +{ + for (ReversePostorderIterator block(graph_.rpoBegin()); block != graph_.rpoEnd(); block++) { + for (MInstructionIterator i = block->begin(); i != block->end(); i++) { + // Note that we don't check for MAsmJSCompareExchangeHeap + // or MAsmJSAtomicBinopHeap, because the backend and the OOB + // mechanism don't support non-zero offsets for them yet. + if (i->isAsmJSLoadHeap()) + AnalyzeAsmHeapAddress(i->toAsmJSLoadHeap()->ptr(), graph_); + else if (i->isAsmJSStoreHeap()) + AnalyzeAsmHeapAddress(i->toAsmJSStoreHeap()->ptr(), graph_); + } + } + return true; +} diff --git a/js/src/jit/AlignmentMaskAnalysis.h b/js/src/jit/AlignmentMaskAnalysis.h new file mode 100644 index 00000000000..3a6f17e9839 --- /dev/null +++ b/js/src/jit/AlignmentMaskAnalysis.h @@ -0,0 +1,30 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef jit_AlignmentMaskAnalysis_h +#define jit_AlignmentMaskAnalysis_h + +namespace js { +namespace jit { + +class MIRGraph; + +class AlignmentMaskAnalysis +{ + MIRGraph &graph_; + + public: + explicit AlignmentMaskAnalysis(MIRGraph &graph) + : graph_(graph) + {} + + bool analyze(); +}; + +} /* namespace jit */ +} /* namespace js */ + +#endif /* jit_AlignmentMaskAnalysis_h */ diff --git a/js/src/jit/EffectiveAddressAnalysis.cpp b/js/src/jit/EffectiveAddressAnalysis.cpp index 5d41fcd0b3e..b8364949472 100644 --- a/js/src/jit/EffectiveAddressAnalysis.cpp +++ b/js/src/jit/EffectiveAddressAnalysis.cpp @@ -89,13 +89,6 @@ AnalyzeLsh(TempAllocator &alloc, MLsh *lsh) last->block()->insertAfter(last, eaddr); } -static bool -IsAlignmentMask(uint32_t m) -{ - // Test whether m is just leading ones and trailing zeros. - return (-m & ~m) == 0; -} - template static void AnalyzeAsmHeapAccess(MAsmJSHeapAccessType *ins, MIRGraph &graph) @@ -116,6 +109,8 @@ AnalyzeAsmHeapAccess(MAsmJSHeapAccessType *ins, MIRGraph &graph) } } else if (ptr->isAdd()) { // Look for heap[a+i] where i is a constant offset, and fold the offset. + // Alignment masks have already been moved out of the way by the + // Alignment Mask Analysis pass. MDefinition *op0 = ptr->toAdd()->getOperand(0); MDefinition *op1 = ptr->toAdd()->getOperand(1); if (op0->isConstantValue()) @@ -125,29 +120,6 @@ AnalyzeAsmHeapAccess(MAsmJSHeapAccessType *ins, MIRGraph &graph) if (ins->tryAddDisplacement(imm)) ins->replacePtr(op0); } - } else if (ptr->isBitAnd() && ptr->hasOneUse()) { - // Transform heap[(a+i)&m] to heap[(a&m)+i] so that we can fold i into - // the access. Since we currently just mutate the BitAnd in place, this - // requires that we are its only user. - MDefinition *lhs = ptr->toBitAnd()->getOperand(0); - MDefinition *rhs = ptr->toBitAnd()->getOperand(1); - int lhsIndex = 0; - if (lhs->isConstantValue()) { - mozilla::Swap(lhs, rhs); - lhsIndex = 1; - } - if (lhs->isAdd() && rhs->isConstantValue()) { - MDefinition *op0 = lhs->toAdd()->getOperand(0); - MDefinition *op1 = lhs->toAdd()->getOperand(1); - if (op0->isConstantValue()) - mozilla::Swap(op0, op1); - if (op1->isConstantValue()) { - uint32_t i = op1->constantValue().toInt32(); - uint32_t m = rhs->constantValue().toInt32(); - if (IsAlignmentMask(m) && ((i & m) == i) && ins->tryAddDisplacement(i)) - ptr->toBitAnd()->replaceOperand(lhsIndex, op0); - } - } } } diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index 0defb354ee6..b89f8097c9e 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -14,6 +14,7 @@ #include "gc/Marking.h" #include "jit/AliasAnalysis.h" +#include "jit/AlignmentMaskAnalysis.h" #include "jit/BacktrackingAllocator.h" #include "jit/BaselineFrame.h" #include "jit/BaselineInspector.h" @@ -1248,6 +1249,18 @@ OptimizeMIR(MIRGenerator *mir) return false; } + if (mir->optimizationInfo().amaEnabled()) { + AutoTraceLog log(logger, TraceLogger_AlignmentMaskAnalysis); + AlignmentMaskAnalysis ama(graph); + if (!ama.analyze()) + return false; + IonSpewPass("Alignment Mask Analysis"); + AssertExtendedGraphCoherency(graph); + + if (mir->shouldCancel("Alignment Mask Analysis")) + return false; + } + ValueNumberer gvn(mir, graph); if (!gvn.init()) return false; diff --git a/js/src/jit/IonOptimizationLevels.cpp b/js/src/jit/IonOptimizationLevels.cpp index 5c3a23ae26f..d1becbedeb0 100644 --- a/js/src/jit/IonOptimizationLevels.cpp +++ b/js/src/jit/IonOptimizationLevels.cpp @@ -55,6 +55,7 @@ OptimizationInfo::initAsmjsOptimizationInfo() // Take normal option values for not specified values. initNormalOptimizationInfo(); + ama_ = true; level_ = Optimization_AsmJS; edgeCaseAnalysis_ = false; eliminateRedundantChecks_ = false; diff --git a/js/src/jit/IonOptimizationLevels.h b/js/src/jit/IonOptimizationLevels.h index 3ebeccd365a..4d6beae47d7 100644 --- a/js/src/jit/IonOptimizationLevels.h +++ b/js/src/jit/IonOptimizationLevels.h @@ -49,6 +49,9 @@ class OptimizationInfo // Toggles whether Effective Address Analysis is performed. bool eaa_; + // Toggles whether Alignment Mask Analysis is performed. + bool ama_; + // Toggles whether Edge Case Analysis is used. bool edgeCaseAnalysis_; @@ -167,6 +170,10 @@ class OptimizationInfo return eaa_ && !js_JitOptions.disableEaa; } + bool amaEnabled() const { + return ama_ && !js_JitOptions.disableAma; + } + bool edgeCaseAnalysisEnabled() const { return edgeCaseAnalysis_ && !js_JitOptions.disableEdgeCaseAnalysis; } diff --git a/js/src/jit/JitOptions.cpp b/js/src/jit/JitOptions.cpp index 9d59d4b1e9c..08a28d06c28 100644 --- a/js/src/jit/JitOptions.cpp +++ b/js/src/jit/JitOptions.cpp @@ -105,6 +105,9 @@ JitOptions::JitOptions() // Toggles whether Effective Address Analysis is globally disabled. SET_DEFAULT(disableEaa, false); + // Toggles whether Alignment Mask Analysis is globally disabled. + SET_DEFAULT(disableAma, false); + // Whether functions are compiled immediately. SET_DEFAULT(eagerCompilation, false); diff --git a/js/src/jit/JitOptions.h b/js/src/jit/JitOptions.h index 0da55fdc3fb..06d4bd7c659 100644 --- a/js/src/jit/JitOptions.h +++ b/js/src/jit/JitOptions.h @@ -55,6 +55,7 @@ struct JitOptions bool disableSink; bool disableLoopUnrolling; bool disableEaa; + bool disableAma; bool eagerCompilation; mozilla::Maybe forcedDefaultIonWarmUpThreshold; mozilla::Maybe forcedRegisterAllocator; diff --git a/js/src/moz.build b/js/src/moz.build index c3223ec9173..6620dc423dc 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -140,6 +140,7 @@ UNIFIED_SOURCES += [ 'irregexp/RegExpParser.cpp', 'irregexp/RegExpStack.cpp', 'jit/AliasAnalysis.cpp', + 'jit/AlignmentMaskAnalysis.cpp', 'jit/BacktrackingAllocator.cpp', 'jit/Bailouts.cpp', 'jit/BaselineBailouts.cpp', diff --git a/js/src/vm/TraceLogging.cpp b/js/src/vm/TraceLogging.cpp index 76700e17cf7..92943945dcc 100644 --- a/js/src/vm/TraceLogging.cpp +++ b/js/src/vm/TraceLogging.cpp @@ -683,6 +683,7 @@ TraceLoggerThreadState::init() enabledTextIds[TraceLogger_RangeAnalysis] = true; enabledTextIds[TraceLogger_LoopUnrolling] = true; enabledTextIds[TraceLogger_EffectiveAddressAnalysis] = true; + enabledTextIds[TraceLogger_AlignmentMaskAnalysis] = true; enabledTextIds[TraceLogger_EliminateDeadCode] = true; enabledTextIds[TraceLogger_EdgeCaseAnalysis] = true; enabledTextIds[TraceLogger_EliminateRedundantChecks] = true; diff --git a/js/src/vm/TraceLoggingTypes.h b/js/src/vm/TraceLoggingTypes.h index e6d0b1ddfe1..380ff1712eb 100644 --- a/js/src/vm/TraceLoggingTypes.h +++ b/js/src/vm/TraceLoggingTypes.h @@ -50,6 +50,7 @@ _(RangeAnalysis) \ _(LoopUnrolling) \ _(EffectiveAddressAnalysis) \ + _(AlignmentMaskAnalysis) \ _(EliminateDeadCode) \ _(EdgeCaseAnalysis) \ _(EliminateRedundantChecks) \