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