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/dead_code_elimination.h"
17 
18 namespace panda::ecmascript::kungfu {
19 
VisitGate(GateRef gate)20 GateRef DeadCodeElimination::VisitGate(GateRef gate)
21 {
22     auto opcode = acc_.GetOpCode(gate);
23     switch (opcode) {
24         case OpCode::SWITCH_BRANCH:
25         case OpCode::IF_BRANCH:
26             return EliminateBranch(gate);
27         case OpCode::MERGE:
28         case OpCode::LOOP_BEGIN:
29             return EliminateMergeAndLoopBegin(gate);
30         case OpCode::DEPEND_SELECTOR:
31             return EliminateDependSelector(gate);
32         case OpCode::IF_EXCEPTION:
33             return EliminateIfException(gate);
34         case OpCode::LOOP_EXIT:
35             return EliminateLoopExit(gate);
36         default :
37             return EliminateGate(gate);
38     }
39     return Circuit::NullGate();
40 }
41 
StateIsDead(GateRef gate)42 GateRef DeadCodeElimination::StateIsDead(GateRef gate)
43 {
44     auto state = acc_.GetState(gate);
45     if (acc_.IsDead(state)) {
46         return state;
47     }
48     return Circuit::NullGate();
49 }
50 
EliminateDependSelector(GateRef gate)51 GateRef DeadCodeElimination::EliminateDependSelector(GateRef gate)
52 {
53     GateRef state = StateIsDead(gate);
54     if (state != Circuit::NullGate() && acc_.IsDead(state)) {
55         return state;
56     }
57     auto stateInput = acc_.GetState(gate);
58     size_t dependCount = acc_.GetDependCount(gate);
59     GateRef result = Circuit::NullGate();
60     for (size_t i = 0; i < dependCount; i++) {
61         auto depend = acc_.GetDep(gate, i);
62         if (acc_.IsDead(depend)) {
63             acc_.ReplaceStateIn(stateInput, deadGate_, i);
64             visitor_->ReVisitGate(stateInput);
65             result = gate;
66         }
67     }
68     return result;
69 }
70 
EliminateIfException(GateRef gate)71 GateRef DeadCodeElimination::EliminateIfException(GateRef gate)
72 {
73     GateRef state = StateIsDead(gate);
74     if (state != Circuit::NullGate() && acc_.IsDead(state)) {
75         return state;
76     }
77     GateRef depend = acc_.GetDep(gate);
78     if (acc_.IsDead(depend)) {
79         return deadGate_;
80     }
81     return Circuit::NullGate();
82 }
83 
EliminateLoopExit(GateRef gate)84 GateRef DeadCodeElimination::EliminateLoopExit(GateRef gate)
85 {
86     GateRef state = StateIsDead(gate);
87     if (state != Circuit::NullGate() && acc_.IsDead(state)) {
88         return DeleteLoopExit(gate);
89     }
90     return Circuit::NullGate();
91 }
92 
EliminateBranch(GateRef gate)93 GateRef DeadCodeElimination::EliminateBranch(GateRef gate)
94 {
95     GateRef state = StateIsDead(gate);
96     if (state != Circuit::NullGate() && acc_.IsDead(state)) {
97         return state;
98     }
99     GateRef value = acc_.GetValueIn(gate, 0);
100     if (acc_.IsDead(value)) {
101         auto uses = acc_.Uses(gate);
102         for (auto it = uses.begin(); it != uses.end(); it++) {
103             if (acc_.IsIfOrSwitchRelated(*it)) {
104                 ReplaceGate(*it, acc_.GetState(gate));
105                 return deadGate_;
106             }
107         }
108         UNREACHABLE();
109     }
110     return gate;
111 }
112 
DecreaseAllSelectors(GateRef gate, size_t count)113 void DeadCodeElimination::DecreaseAllSelectors(GateRef gate, size_t count)
114 {
115     auto uses = acc_.Uses(gate);
116     for (auto it = uses.begin(); it != uses.end(); it++) {
117         if (acc_.IsSelector(*it)) {
118             acc_.DecreaseIn(*it, count + 1);
119         }
120     }
121 }
EliminateMergeAndLoopBegin(GateRef gate)122 GateRef DeadCodeElimination::EliminateMergeAndLoopBegin(GateRef gate)
123 {
124     if (acc_.GetOpCode(gate) == OpCode::LOOP_BEGIN) {
125         auto loopEntry = acc_.GetIn(gate, 0);
126         if (acc_.IsDead(loopEntry)) {
127             return deadGate_;
128         }
129     }
130     size_t count = 0;
131     size_t inputCount = acc_.GetNumIns(gate);
132     for (size_t i = 0; i < inputCount; i++) {
133         auto input = acc_.GetIn(gate, count);
134         if (acc_.IsDead(input)) {
135             acc_.DecreaseIn(gate, count);
136             DecreaseAllSelectors(gate, count);
137         } else {
138             count++;
139         }
140     }
141     if (count == 0) {
142         return deadGate_;
143     } else if (count == 1) {
144         auto uses = acc_.Uses(gate);
145         for (auto it = uses.begin(); it != uses.end(); it++) {
146             if (acc_.IsSelector(*it)) {
147                 TryFindAndDeleteLoopExit(*it);
148                 auto selectorInput = acc_.GetIn(*it, 1);
149                 ReplaceGate(*it, selectorInput);
150             }
151         }
152         return acc_.GetIn(gate, 0);
153     }
154     if (count < inputCount) {
155         auto uses = acc_.Uses(gate);
156         for (auto it = uses.begin(); it != uses.end(); it++) {
157             if (acc_.IsSelector(*it)) {
158                 visitor_->ReVisitGate(*it);
159             }
160         }
161         return gate;
162     }
163     return Circuit::NullGate();
164 }
165 
TryFindAndDeleteLoopExit(GateRef gate)166 void DeadCodeElimination::TryFindAndDeleteLoopExit(GateRef gate)
167 {
168     auto uses = acc_.Uses(gate);
169     for (auto it = uses.begin(); it != uses.end(); it++) {
170         if (acc_.GetOpCode(*it) == OpCode::LOOP_EXIT_VALUE || acc_.GetOpCode(*it) == OpCode::LOOP_EXIT_DEPEND) {
171             GateRef loopExit = acc_.GetState(gate);
172             DeleteLoopExit(loopExit);
173         }
174     }
175 }
DeleteLoopExit(GateRef gate)176 GateRef DeadCodeElimination::DeleteLoopExit(GateRef gate)
177 {
178     auto uses = acc_.Uses(gate);
179     for (auto it = uses.begin(); it != uses.end(); it++) {
180         if (acc_.GetOpCode(*it) == OpCode::LOOP_EXIT_VALUE) {
181             ReplaceGate(*it, acc_.GetValueIn(*it));
182         } else if (acc_.GetOpCode(*it) == OpCode::LOOP_EXIT_DEPEND) {
183             ReplaceGate(*it, acc_.GetDep(*it));
184         }
185     }
186     return acc_.GetState(gate);
187 }
188 
EliminateGate(GateRef gate)189 GateRef DeadCodeElimination::EliminateGate(GateRef gate)
190 {
191     if (acc_.GetStateCount(gate) == 1) {
192         return StateIsDead(gate);
193     }
194     return Circuit::NullGate();
195 }
196 
197 }