FoldLinearArithConstants.cpp (3697B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "jit/FoldLinearArithConstants.h" 8 9 #include "jit/IonAnalysis.h" 10 #include "jit/MIR-wasm.h" 11 #include "jit/MIR.h" 12 #include "jit/MIRGenerator.h" 13 #include "jit/MIRGraph.h" 14 15 using namespace js; 16 using namespace jit; 17 18 namespace js { 19 namespace jit { 20 21 // Mark this node and its children as RecoveredOnBailout when they are not used. 22 // The marked nodes will be removed during DCE. Marking as RecoveredOnBailout is 23 // necessary because the Sink pass is ran before this pass. 24 static void markNodesAsRecoveredOnBailout(MDefinition* def) { 25 if (def->hasLiveDefUses() || !DeadIfUnused(def) || 26 !def->canRecoverOnBailout()) { 27 return; 28 } 29 30 JitSpew(JitSpew_FLAC, "mark as recovered on bailout: %s%u", def->opName(), 31 def->id()); 32 def->setRecoveredOnBailoutUnchecked(); 33 34 // Recursively mark nodes that do not have multiple uses. This loop is 35 // necessary because a node could be an unused right shift zero or an 36 // unused add, and both need to be marked as RecoveredOnBailout. 37 for (size_t i = 0; i < def->numOperands(); i++) { 38 markNodesAsRecoveredOnBailout(def->getOperand(i)); 39 } 40 } 41 42 // Fold AddIs with one variable and two or more constants into one AddI. 43 static void AnalyzeAdd(TempAllocator& alloc, MAdd* add) { 44 if (add->type() != MIRType::Int32 || add->isRecoveredOnBailout()) { 45 return; 46 } 47 48 if (!add->hasUses()) { 49 return; 50 } 51 52 JitSpew(JitSpew_FLAC, "analyze add: %s%u", add->opName(), add->id()); 53 54 SimpleLinearSum sum = ExtractLinearSum(add); 55 if (sum.constant == 0 || !sum.term) { 56 return; 57 } 58 59 // Determine which operand is the constant. 60 int idx = add->getOperand(0)->isConstant() ? 0 : 1; 61 if (add->getOperand(idx)->isConstant()) { 62 // Do not replace an add where the outcome is the same add instruction. 63 MOZ_ASSERT(add->getOperand(idx)->toConstant()->type() == MIRType::Int32); 64 if (sum.term == add->getOperand(1 - idx) || 65 sum.constant == add->getOperand(idx)->toConstant()->toInt32()) { 66 return; 67 } 68 } 69 70 MInstruction* rhs = MConstant::NewInt32(alloc, sum.constant); 71 add->block()->insertBefore(add, rhs); 72 73 MAdd* addNew = MAdd::New(alloc, sum.term, rhs, add->truncateKind()); 74 addNew->setBailoutKind(add->bailoutKind()); 75 76 add->replaceAllLiveUsesWith(addNew); 77 add->block()->insertBefore(add, addNew); 78 JitSpew(JitSpew_FLAC, "replaced with: %s%u", addNew->opName(), addNew->id()); 79 JitSpew(JitSpew_FLAC, "and constant: %s%u (%d)", rhs->opName(), rhs->id(), 80 sum.constant); 81 82 // Mark the stale nodes as RecoveredOnBailout since the Sink pass has 83 // been run before this pass. DCE will then remove the unused nodes. 84 markNodesAsRecoveredOnBailout(add); 85 } 86 87 bool FoldLinearArithConstants(const MIRGenerator* mir, MIRGraph& graph) { 88 JitSpew(JitSpew_FLAC, "Begin"); 89 for (PostorderIterator block(graph.poBegin()); block != graph.poEnd(); 90 block++) { 91 if (mir->shouldCancel("Fold Linear Arithmetic Constants (main loop)")) { 92 return false; 93 } 94 95 for (MInstructionIterator i = block->begin(); i != block->end(); i++) { 96 if (!graph.alloc().ensureBallast()) { 97 return false; 98 } 99 100 if (mir->shouldCancel("Fold Linear Arithmetic Constants (inner loop)")) { 101 return false; 102 } 103 104 if (i->isAdd()) { 105 AnalyzeAdd(graph.alloc(), i->toAdd()); 106 } 107 } 108 } 109 return true; 110 } 111 112 } /* namespace jit */ 113 } /* namespace js */