• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ecmascript/compiler/graph_editor.h"
17 
18 namespace panda::ecmascript::kungfu {
19 
RemoveDeadState(Circuit * circuit,GateRef gate)20 void GraphEditor::RemoveDeadState(Circuit* circuit, GateRef gate)
21 {
22     GraphEditor editor(circuit);
23     editor.ReplaceGate(gate);
24     editor.RemoveGate();
25 }
26 
EliminateRedundantPhi(Circuit * circuit,bool enableLog,const std::string & methodName)27 void GraphEditor::EliminateRedundantPhi(Circuit* circuit, bool enableLog, const std::string& methodName)
28 {
29     GraphEditor editor(circuit);
30     editor.EliminatePhi();
31     if (enableLog) {
32         LOG_COMPILER(INFO) << " ";
33         LOG_COMPILER(INFO) << "\033[34m" << "================="
34                            << " After Redundant Phi Elimination "
35                            << "[" << methodName << "] "
36                            << "=================" << "\033[0m";
37         circuit->PrintAllGatesWithBytecode();
38         LOG_COMPILER(INFO) << "\033[34m" << "=========================== End ===========================" << "\033[0m";
39     }
40 }
41 
ReplaceGate(GateRef gate)42 void GraphEditor::ReplaceGate(GateRef gate)
43 {
44     auto uses = acc_.Uses(gate);
45     for (auto useIt = uses.begin(); useIt != uses.end();) {
46         if (acc_.IsDependIn(useIt)) {
47             GateRef depend = acc_.GetDep(gate);
48             useIt = acc_.ReplaceIn(useIt, depend);
49         } else {
50             workList_.push_back(useIt.GetEdge());
51             useIt = acc_.ReplaceIn(useIt, circuit_->DeadGate());
52         }
53     }
54     acc_.DeleteGate(gate);
55 }
56 
RemoveGate()57 void GraphEditor::RemoveGate()
58 {
59     while (!workList_.empty()) {
60         Edge& edge = workList_.back();
61         GateRef gate = edge.GetGate();
62         workList_.pop_back();
63         auto opcode = acc_.GetOpCode(gate);
64         switch (opcode) {
65             case OpCode::NOP:
66             case OpCode::DEAD:
67             case OpCode::VALUE_SELECTOR:
68             case OpCode::DEPEND_SELECTOR:
69                 // dead op, just continue
70                 break;
71             case OpCode::LOOP_BEGIN:
72             case OpCode::MERGE:
73                 PropagateMerge(edge);
74                 break;
75             default:
76                 PropagateGate(edge);
77                 break;
78         }
79     }
80 }
81 
PropagateGate(const Edge & edge)82 void GraphEditor::PropagateGate(const Edge& edge)
83 {
84     GateRef gate = edge.GetGate();
85     // isStateIn
86     if (acc_.IsStateIn(gate, edge.GetIndex())) {
87         ASSERT(acc_.GetStateCount(gate) == 1);
88         ReplaceGate(gate);
89         return;
90     }
91 
92     // IsValueIn
93     if (acc_.IsValueIn(gate, edge.GetIndex())) {
94         // value gate
95         ReplaceGate(gate);
96     }
97 }
98 
PropagateMerge(const Edge & edge)99 void GraphEditor::PropagateMerge(const Edge& edge)
100 {
101     GateRef gate = edge.GetGate();
102     auto numIns = acc_.GetNumIns(gate);
103     if (numIns == 1) {
104         ReplaceGate(gate);
105     } else {
106         auto uses = acc_.Uses(gate);
107         for (auto useIt = uses.begin(); useIt != uses.end(); useIt++) {
108             GateRef use = *useIt;
109             //  (Gate1)   (Dead)   (Gate2)       (Gate1)  (Gate2)
110             //     |       |         |              |        |
111             //     ___________________      ==>     __________
112             //             |                             |
113             //           (phi)                         (phi)
114             if (acc_.GetOpCode(use) == OpCode::VALUE_SELECTOR ||
115                 acc_.GetOpCode(use) == OpCode::DEPEND_SELECTOR) {
116                 acc_.DecreaseIn(use, edge.GetIndex() + 1); // +1 skip state input
117             }
118         }
119         acc_.DecreaseIn(gate, edge.GetIndex());
120     }
121 }
122 
FrameValueUsedInCFGTailoring(GateRef gate)123 bool GraphEditor::FrameValueUsedInCFGTailoring(GateRef gate)
124 {
125     std::vector<GateRef> valueOuts;
126     acc_.GetValueUses(gate, valueOuts);
127     for (auto out : valueOuts) {
128         if (acc_.GetOpCode(out) != OpCode::FRAME_STATE) {
129             continue;
130         }
131         std::vector<GateRef> outs;
132         acc_.GetValueUses(out, outs);
133         for (auto use : outs) {
134             if (acc_.GetOpCode(use) != OpCode::DEOPT_CHECK) {
135                 continue;
136             }
137             GateRef deoptType = acc_.GetValueIn(use, 2);  // 2: deopt type
138             uint64_t v = acc_.GetConstantValue(deoptType);
139             if (v == static_cast<uint64_t>(DeoptType::OSRLOOPEXIT) ||
140                 v == static_cast<uint64_t>(DeoptType::INSUFFICIENTPROFILE)) {
141                 return true;
142             }
143         }
144     }
145     return false;
146 }
147 
EliminatePhi()148 void GraphEditor::EliminatePhi()
149 {
150     circuit_->AdvanceTime();
151     std::vector<GateRef> gateList;
152     acc_.GetAllGates(gateList);
153     std::vector<GateRef> phis;
154     std::queue<GateRef> workList;
155     // nomarked phis are unused phis
156     // set previsit for phis in worklist
157     // set visited for used phis
158     // set finished for used gate which is self-use or has same inputs
159 
160     for (auto gate : gateList) {
161         if (acc_.IsValueSelector(gate)) {
162             phis.emplace_back(gate);
163             continue;
164         }
165         // 1. When Deopt occurs, FrameValue assists in restoring the assembly interpreter stack. If all the logic
166         // affected by this FrameValue does not use this phi, then this phi can be deleted.
167         // 2. In the OSR and Insufficient Profile scenarios, we will actively crop CFG and remove some references to
168         // phi, which will result in incomplete recovery of the assembly interpreter stack by Deopt.
169         if (acc_.IsFrameValues(gate) && !FrameValueUsedInCFGTailoring(gate)) {
170             continue;
171         }
172         // get used phi
173         auto valueNum = acc_.GetNumValueIn(gate);
174         for (size_t i = 0; i < valueNum; ++i) {
175             GateRef input = acc_.GetValueIn(gate, i);
176             if (acc_.IsValueSelector(input) && acc_.IsNotMarked(input)) {
177                 acc_.SetPrevisit(input);
178                 workList.push(input);
179             }
180         }
181     }
182 
183     // visit used phi
184     while (!workList.empty()) {
185         auto cur = workList.front();
186         workList.pop();
187         acc_.SetVisited(cur);
188         auto valueNum = acc_.GetNumValueIn(cur);
189         bool sameIns = true;
190         GateRef first = acc_.GetValueIn(cur, 0);
191         for (size_t i = 0; i < valueNum; ++i) {
192             GateRef input = acc_.GetValueIn(cur, i);
193             if (input != first) {
194                 sameIns = false;
195             }
196             if (acc_.IsValueSelector(input) && acc_.IsNotMarked(input)) {
197                 workList.push(input);
198                 acc_.SetPrevisit(input);
199             }
200         }
201 
202         if (!sameIns) {
203             continue;
204         }
205 
206         acc_.SetFinished(cur);
207         auto uses = acc_.Uses(cur);
208         for (auto it = uses.begin(); it != uses.end(); it++) {
209             if (acc_.IsValueSelector(*it) && acc_.IsVisited(*it)) {
210                 // revisit user
211                 acc_.SetPrevisit(*it);
212                 workList.push(*it);
213             }
214         }
215         acc_.UpdateAllUses(cur, first);
216         acc_.DeleteGate(cur);
217     }
218 
219     // delete unused phi
220     for (auto phi : phis) {
221         if (acc_.IsValueSelector(phi) && acc_.IsNotMarked(phi)) {
222             auto optimizedGate = circuit_->GetConstantGate(MachineType::I64,
223                 JSTaggedValue::VALUE_OPTIMIZED_OUT, GateType::TaggedValue());
224             acc_.UpdateAllUses(phi, optimizedGate);
225             acc_.DeleteGate(phi);
226         }
227     }
228 }
229 }  // namespace panda::ecmascript::kungfu
230