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