commit b0c596352f76e501680fc2fbe4419e701e488ece
parent 1a068169cb70e2ebb2d5e1fcefa4309fc4f7643e
Author: wilsu <wilsu@outlook.de>
Date: Thu, 27 Nov 2025 13:56:23 +0000
Bug 998485 - Removed analyzeEdgeCasesForward from MIR.h/.cpp - r=nbp
Differential Revision: https://phabricator.services.mozilla.com/D257010
Diffstat:
10 files changed, 0 insertions(+), 387 deletions(-)
diff --git a/js/src/jit/EdgeCaseAnalysis.cpp b/js/src/jit/EdgeCaseAnalysis.cpp
@@ -1,51 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim: set ts=8 sts=2 et sw=2 tw=80:
- * 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/EdgeCaseAnalysis.h"
-
-#include "jit/MIR-wasm.h"
-#include "jit/MIR.h"
-#include "jit/MIRGenerator.h"
-#include "jit/MIRGraph.h"
-
-using namespace js;
-using namespace js::jit;
-
-EdgeCaseAnalysis::EdgeCaseAnalysis(const MIRGenerator* mir, MIRGraph& graph)
- : mir(mir), graph(graph) {}
-
-bool EdgeCaseAnalysis::analyzeLate() {
- // Renumber definitions for NeedNegativeZeroCheck under
- // analyzeEdgeCasesBackward.
- uint32_t nextId = 0;
-
- for (ReversePostorderIterator block(graph.rpoBegin());
- block != graph.rpoEnd(); block++) {
- for (MDefinitionIterator iter(*block); iter; iter++) {
- if (mir->shouldCancel("Analyze Late (first loop)")) {
- return false;
- }
-
- iter->setId(nextId++);
- iter->analyzeEdgeCasesForward();
- }
- block->lastIns()->setId(nextId++);
- }
-
- for (PostorderIterator block(graph.poBegin()); block != graph.poEnd();
- block++) {
- for (MInstructionReverseIterator riter(block->rbegin());
- riter != block->rend(); riter++) {
- if (mir->shouldCancel("Analyze Late (second loop)")) {
- return false;
- }
-
- riter->analyzeEdgeCasesBackward();
- }
- }
-
- return true;
-}
diff --git a/js/src/jit/EdgeCaseAnalysis.h b/js/src/jit/EdgeCaseAnalysis.h
@@ -1,28 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim: set ts=8 sts=2 et sw=2 tw=80:
- * 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_EdgeCaseAnalysis_h
-#define jit_EdgeCaseAnalysis_h
-
-namespace js {
-namespace jit {
-
-class MIRGenerator;
-class MIRGraph;
-
-class EdgeCaseAnalysis {
- const MIRGenerator* mir;
- MIRGraph& graph;
-
- public:
- EdgeCaseAnalysis(const MIRGenerator* mir, MIRGraph& graph);
- [[nodiscard]] bool analyzeLate();
-};
-
-} // namespace jit
-} // namespace js
-
-#endif /* jit_EdgeCaseAnalysis_h */
diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp
@@ -23,7 +23,6 @@
#include "jit/CodeGenerator.h"
#include "jit/CompileInfo.h"
#include "jit/DominatorTree.h"
-#include "jit/EdgeCaseAnalysis.h"
#include "jit/EffectiveAddressAnalysis.h"
#include "jit/ExecutableAllocator.h"
#include "jit/FoldLinearArithConstants.h"
@@ -1492,22 +1491,6 @@ bool OptimizeMIR(MIRGenerator* mir) {
}
}
- // Passes after this point must not move instructions; these analyses
- // depend on knowing the final order in which instructions will execute.
-
- if (mir->optimizationInfo().edgeCaseAnalysisEnabled()) {
- EdgeCaseAnalysis edgeCaseAnalysis(mir, graph);
- if (!edgeCaseAnalysis.analyzeLate()) {
- return false;
- }
- mir->spewPass("Edge Case Analysis (Late)");
- AssertGraphCoherency(graph);
-
- if (mir->shouldCancel("Edge Case Analysis (Late)")) {
- return false;
- }
- }
-
if (mir->optimizationInfo().eliminateRedundantChecksEnabled()) {
// Note: check elimination has to run after all other passes that move
// instructions. Since check uses are replaced with the actual index,
diff --git a/js/src/jit/IonOptimizationLevels.h b/js/src/jit/IonOptimizationLevels.h
@@ -44,9 +44,6 @@ class OptimizationInfo {
// Toggles whether Alignment Mask Analysis is performed.
bool ama_;
- // Toggles whether Edge Case Analysis is used.
- bool edgeCaseAnalysis_;
-
// Toggles whether redundant checks get removed.
bool eliminateRedundantChecks_;
@@ -91,7 +88,6 @@ class OptimizationInfo {
: level_(OptimizationLevel::Normal),
eaa_(false),
ama_(false),
- edgeCaseAnalysis_(false),
eliminateRedundantChecks_(false),
eliminateRedundantShapeGuards_(false),
eliminateRedundantGCBarriers_(false),
@@ -111,7 +107,6 @@ class OptimizationInfo {
autoTruncate_ = true;
eaa_ = true;
- edgeCaseAnalysis_ = true;
eliminateRedundantChecks_ = true;
eliminateRedundantShapeGuards_ = true;
eliminateRedundantGCBarriers_ = true;
@@ -137,7 +132,6 @@ class OptimizationInfo {
ama_ = true;
autoTruncate_ = false;
- edgeCaseAnalysis_ = false;
eliminateRedundantChecks_ = false;
eliminateRedundantShapeGuards_ = false;
eliminateRedundantGCBarriers_ = false;
@@ -181,10 +175,6 @@ class OptimizationInfo {
bool amaEnabled() const { return ama_ && !JitOptions.disableAma; }
- bool edgeCaseAnalysisEnabled() const {
- return edgeCaseAnalysis_ && !JitOptions.disableEdgeCaseAnalysis;
- }
-
bool eliminateRedundantChecksEnabled() const {
return eliminateRedundantChecks_;
}
diff --git a/js/src/jit/JitOptions.cpp b/js/src/jit/JitOptions.cpp
@@ -81,9 +81,6 @@ DefaultJitOptions::DefaultJitOptions() {
// Toggles whether Effective Address Analysis is globally disabled.
SET_DEFAULT(disableEaa, false);
- // Toggles whether Edge Case Analysis is gobally disabled.
- SET_DEFAULT(disableEdgeCaseAnalysis, false);
-
// Toggle whether global value numbering is globally disabled.
SET_DEFAULT(disableGvn, false);
diff --git a/js/src/jit/JitOptions.h b/js/src/jit/JitOptions.h
@@ -54,7 +54,6 @@ struct DefaultJitOptions {
bool disableJitHints;
bool disableAma;
bool disableEaa;
- bool disableEdgeCaseAnalysis;
bool disableGvn;
bool disableInlining;
bool disableLicm;
diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp
@@ -662,10 +662,6 @@ MDefinition* MInstruction::foldsToStore(TempAllocator& alloc) {
return value;
}
-void MDefinition::analyzeEdgeCasesForward() {}
-
-void MDefinition::analyzeEdgeCasesBackward() {}
-
void MInstruction::setResumePoint(MResumePoint* resumePoint) {
MOZ_ASSERT(!resumePoint_);
resumePoint_ = resumePoint;
@@ -2854,159 +2850,6 @@ MDefinition* MBinaryBitwiseInstruction::foldUnnecessaryBitop() {
return this;
}
-static inline bool CanProduceNegativeZero(MDefinition* def) {
- // Test if this instruction can produce negative zero even when bailing out
- // and changing types.
- switch (def->op()) {
- case MDefinition::Opcode::Constant:
- if (def->type() == MIRType::Double &&
- def->toConstant()->toDouble() == -0.0) {
- return true;
- }
- [[fallthrough]];
- case MDefinition::Opcode::BitAnd:
- case MDefinition::Opcode::BitOr:
- case MDefinition::Opcode::BitXor:
- case MDefinition::Opcode::BitNot:
- case MDefinition::Opcode::Lsh:
- case MDefinition::Opcode::Rsh:
- return false;
- default:
- return true;
- }
-}
-
-static inline bool NeedNegativeZeroCheck(MDefinition* def) {
- if (def->isGuard() || def->isGuardRangeBailouts()) {
- return true;
- }
-
- // Test if all uses have the same semantics for -0 and 0
- for (MUseIterator use = def->usesBegin(); use != def->usesEnd(); use++) {
- if (use->consumer()->isResumePoint()) {
- return true;
- }
-
- MDefinition* use_def = use->consumer()->toDefinition();
- switch (use_def->op()) {
- case MDefinition::Opcode::Add: {
- // If add is truncating -0 and 0 are observed as the same.
- if (use_def->toAdd()->isTruncated()) {
- break;
- }
-
- // x + y gives -0, when both x and y are -0
-
- // Figure out the order in which the addition's operands will
- // execute. EdgeCaseAnalysis::analyzeLate has renumbered the MIR
- // definitions for us so that this just requires comparing ids.
- MDefinition* first = use_def->toAdd()->lhs();
- MDefinition* second = use_def->toAdd()->rhs();
- if (first->id() > second->id()) {
- std::swap(first, second);
- }
- // Negative zero checks can be removed on the first executed
- // operand only if it is guaranteed the second executed operand
- // will produce a value other than -0. While the second is
- // typed as an int32, a bailout taken between execution of the
- // operands may change that type and cause a -0 to flow to the
- // second.
- //
- // There is no way to test whether there are any bailouts
- // between execution of the operands, so remove negative
- // zero checks from the first only if the second's type is
- // independent from type changes that may occur after bailing.
- if (def == first && CanProduceNegativeZero(second)) {
- return true;
- }
-
- // The negative zero check can always be removed on the second
- // executed operand; by the time this executes the first will have
- // been evaluated as int32 and the addition's result cannot be -0.
- break;
- }
- case MDefinition::Opcode::Sub: {
- // If sub is truncating -0 and 0 are observed as the same
- if (use_def->toSub()->isTruncated()) {
- break;
- }
-
- // x + y gives -0, when x is -0 and y is 0
-
- // We can remove the negative zero check on the rhs, only if we
- // are sure the lhs isn't negative zero.
-
- // The lhs is typed as integer (i.e. not -0.0), but it can bailout
- // and change type. This should be fine if the lhs is executed
- // first. However if the rhs is executed first, the lhs can bail,
- // change type and become -0.0 while the rhs has already been
- // optimized to not make a difference between zero and negative zero.
- MDefinition* lhs = use_def->toSub()->lhs();
- MDefinition* rhs = use_def->toSub()->rhs();
- if (rhs->id() < lhs->id() && CanProduceNegativeZero(lhs)) {
- return true;
- }
-
- [[fallthrough]];
- }
- case MDefinition::Opcode::StoreElement:
- case MDefinition::Opcode::StoreHoleValueElement:
- case MDefinition::Opcode::LoadElement:
- case MDefinition::Opcode::LoadElementHole:
- case MDefinition::Opcode::LoadUnboxedScalar:
- case MDefinition::Opcode::LoadDataViewElement:
- case MDefinition::Opcode::LoadTypedArrayElementHole:
- case MDefinition::Opcode::CharCodeAt:
- case MDefinition::Opcode::Mod:
- case MDefinition::Opcode::InArray:
- // Only allowed to remove check when definition is the second operand
- if (use_def->getOperand(0) == def) {
- return true;
- }
- for (size_t i = 2, e = use_def->numOperands(); i < e; i++) {
- if (use_def->getOperand(i) == def) {
- return true;
- }
- }
- break;
- case MDefinition::Opcode::BoundsCheck:
- // Only allowed to remove check when definition is the first operand
- if (use_def->toBoundsCheck()->getOperand(1) == def) {
- return true;
- }
- break;
- case MDefinition::Opcode::ToString:
- case MDefinition::Opcode::FromCharCode:
- case MDefinition::Opcode::FromCodePoint:
- case MDefinition::Opcode::TableSwitch:
- case MDefinition::Opcode::Compare:
- case MDefinition::Opcode::BitAnd:
- case MDefinition::Opcode::BitOr:
- case MDefinition::Opcode::BitXor:
- case MDefinition::Opcode::Abs:
- case MDefinition::Opcode::TruncateToInt32:
- // Always allowed to remove check. No matter which operand.
- break;
- case MDefinition::Opcode::StoreElementHole:
- case MDefinition::Opcode::StoreTypedArrayElementHole:
- case MDefinition::Opcode::PostWriteElementBarrier:
- // Only allowed to remove check when definition is the third operand.
- for (size_t i = 0, e = use_def->numOperands(); i < e; i++) {
- if (i == 2) {
- continue;
- }
- if (use_def->getOperand(i) == def) {
- return true;
- }
- }
- break;
- default:
- return true;
- }
- }
- return false;
-}
-
#ifdef JS_JITSPEW
void MBinaryArithInstruction::printOpcode(GenericPrinter& out) const {
MDefinition::printOpcode(out);
@@ -3937,54 +3780,6 @@ MDefinition* MDiv::foldsTo(TempAllocator& alloc) {
return this;
}
-void MDiv::analyzeEdgeCasesForward() {
- // This is only meaningful when doing integer division.
- if (type() != MIRType::Int32) {
- return;
- }
-
- MOZ_ASSERT(lhs()->type() == MIRType::Int32);
- MOZ_ASSERT(rhs()->type() == MIRType::Int32);
-
- // Try removing divide by zero check
- if (rhs()->isConstant() && !rhs()->toConstant()->isInt32(0)) {
- canBeDivideByZero_ = false;
- }
-
- // If lhs is a constant int != INT32_MIN, then
- // negative overflow check can be skipped.
- if (lhs()->isConstant() && !lhs()->toConstant()->isInt32(INT32_MIN)) {
- canBeNegativeOverflow_ = false;
- }
-
- // If rhs is a constant int != -1, likewise.
- if (rhs()->isConstant() && !rhs()->toConstant()->isInt32(-1)) {
- canBeNegativeOverflow_ = false;
- }
-
- // If lhs is != 0, then negative zero check can be skipped.
- if (lhs()->isConstant() && !lhs()->toConstant()->isInt32(0)) {
- setCanBeNegativeZero(false);
- }
-
- // If rhs is >= 0, likewise.
- if (rhs()->isConstant() && rhs()->type() == MIRType::Int32) {
- if (rhs()->toConstant()->toInt32() >= 0) {
- setCanBeNegativeZero(false);
- }
- }
-}
-
-void MDiv::analyzeEdgeCasesBackward() {
- // In general, canBeNegativeZero_ is only valid for integer divides.
- // It's fine to access here because we're only using it to avoid
- // wasting effort to decide whether we can clear an already cleared
- // flag.
- if (canBeNegativeZero_ && !NeedNegativeZeroCheck(this)) {
- setCanBeNegativeZero(false);
- }
-}
-
bool MDiv::fallible() const { return !isTruncated(); }
MDefinition* MMod::foldsTo(TempAllocator& alloc) {
@@ -4003,24 +3798,6 @@ MDefinition* MMod::foldsTo(TempAllocator& alloc) {
return this;
}
-void MMod::analyzeEdgeCasesForward() {
- // These optimizations make sense only for integer division
- if (type() != MIRType::Int32) {
- return;
- }
-
- if (rhs()->isConstant() && !rhs()->toConstant()->isInt32(0)) {
- canBeDivideByZero_ = false;
- }
-
- if (rhs()->isConstant()) {
- int32_t n = rhs()->toConstant()->toInt32();
- if (n > 0 && !IsPowerOfTwo(uint32_t(n))) {
- canBePowerOfTwoDivisor_ = false;
- }
- }
-}
-
bool MMod::fallible() const {
return !isTruncated() &&
(isUnsigned() || canBeDivideByZero() || canBeNegativeDividend());
@@ -4126,34 +3903,6 @@ MDefinition* MMul::foldsTo(TempAllocator& alloc) {
return this;
}
-void MMul::analyzeEdgeCasesForward() {
- // Try to remove the check for negative zero
- // This only makes sense when using the integer multiplication
- if (type() != MIRType::Int32) {
- return;
- }
-
- // If lhs is > 0, no need for negative zero check.
- if (lhs()->isConstant() && lhs()->type() == MIRType::Int32) {
- if (lhs()->toConstant()->toInt32() > 0) {
- setCanBeNegativeZero(false);
- }
- }
-
- // If rhs is > 0, likewise.
- if (rhs()->isConstant() && rhs()->type() == MIRType::Int32) {
- if (rhs()->toConstant()->toInt32() > 0) {
- setCanBeNegativeZero(false);
- }
- }
-}
-
-void MMul::analyzeEdgeCasesBackward() {
- if (canBeNegativeZero() && !NeedNegativeZeroCheck(this)) {
- setCanBeNegativeZero(false);
- }
-}
-
bool MMul::canOverflow() const {
if (isTruncated()) {
return false;
@@ -4699,12 +4448,6 @@ MDefinition* MBooleanToInt32::foldsTo(TempAllocator& alloc) {
return this;
}
-void MToNumberInt32::analyzeEdgeCasesBackward() {
- if (!NeedNegativeZeroCheck(this)) {
- setNeedsNegativeZeroCheck(false);
- }
-}
-
MDefinition* MTruncateToInt32::foldsTo(TempAllocator& alloc) {
MDefinition* input = getOperand(0);
if (input->isBox()) {
diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h
@@ -678,8 +678,6 @@ class MDefinition : public MNode {
bool congruentIfOperandsEqual(const MDefinition* ins) const;
virtual MDefinition* foldsTo(TempAllocator& alloc);
- virtual void analyzeEdgeCasesForward();
- virtual void analyzeEdgeCasesBackward();
// |canTruncate| reports if this instruction supports truncation. If
// |canTruncate| function returns true, then the |truncate| function is
@@ -3826,7 +3824,6 @@ class MToNumberInt32 : public MUnaryInstruction, public ToInt32Policy::Data {
MDefinition* foldsTo(TempAllocator& alloc) override;
// this only has backwards information flow.
- void analyzeEdgeCasesBackward() override;
bool needsNegativeZeroCheck() const { return needsNegativeZeroCheck_; }
void setNeedsNegativeZeroCheck(bool needsCheck) {
@@ -5215,8 +5212,6 @@ class MMul : public MBinaryArithInstruction {
}
MDefinition* foldsTo(TempAllocator& alloc) override;
- void analyzeEdgeCasesForward() override;
- void analyzeEdgeCasesBackward() override;
void collectRangeInfoPreTrunc() override;
double getIdentity() const override { return 1; }
@@ -5314,8 +5309,6 @@ class MDiv : public MBinaryArithInstruction {
}
MDefinition* foldsTo(TempAllocator& alloc) override;
- void analyzeEdgeCasesForward() override;
- void analyzeEdgeCasesBackward() override;
double getIdentity() const override { MOZ_CRASH("not used"); }
@@ -5452,8 +5445,6 @@ class MMod : public MBinaryArithInstruction {
return canBePowerOfTwoDivisor_;
}
- void analyzeEdgeCasesForward() override;
-
bool isUnsigned() const { return unsigned_; }
bool trapOnError() const { return trapOnError_; }
diff --git a/js/src/jit/moz.build b/js/src/jit/moz.build
@@ -38,7 +38,6 @@ UNIFIED_SOURCES += [
"CompileWrappers.cpp",
"Disassemble.cpp",
"DominatorTree.cpp",
- "EdgeCaseAnalysis.cpp",
"EffectiveAddressAnalysis.cpp",
"ExecutableAllocator.cpp",
"FlushICache.cpp",
diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp
@@ -13855,16 +13855,6 @@ bool SetContextJITOptions(JSContext* cx, const OptionParser& op) {
}
}
- if (const char* str = op.getStringOption("ion-edgecase-analysis")) {
- if (strcmp(str, "on") == 0) {
- jit::JitOptions.disableEdgeCaseAnalysis = false;
- } else if (strcmp(str, "off") == 0) {
- jit::JitOptions.disableEdgeCaseAnalysis = true;
- } else {
- return OptionFailure("ion-edgecase-analysis", str);
- }
- }
-
if (const char* str = op.getStringOption("ion-pruning")) {
if (strcmp(str, "on") == 0) {
jit::JitOptions.disablePruning = false;