1 /*
2 * Copyright (c) 2022 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 <queue>
17 #include <stack>
18
19 #include "ecmascript/compiler/check_elimination.h"
20
21 namespace panda::ecmascript::kungfu {
Run()22 void CheckElimination::Run()
23 {
24 RemovePassedCheck();
25 RemoveTypeTrustedCheck();
26
27 if (IsLogEnabled()) {
28 LOG_COMPILER(INFO) << "";
29 LOG_COMPILER(INFO) << "\033[34m"
30 << "===================="
31 << " After check eliminating "
32 << "[" << GetMethodName() << "]"
33 << "===================="
34 << "\033[0m";
35 circuit_->PrintAllGatesWithBytecode();
36 LOG_COMPILER(INFO) << "\033[34m" << "========================= End ==========================" << "\033[0m";
37 }
38 }
39
IsPrimitiveTypeCheck(GateRef gate) const40 bool CheckElimination::IsPrimitiveTypeCheck(GateRef gate) const {
41 auto op = acc_.GetOpCode(gate);
42 return op == OpCode::PRIMITIVE_TYPE_CHECK;
43 }
44
IsTrustedType(GateRef gate) const45 bool CheckElimination::IsTrustedType(GateRef gate) const
46 {
47 if (acc_.IsConstant(gate)) {
48 return true;
49 }
50 if (acc_.IsTypedOperator(gate)) {
51 if (acc_.GetOpCode(gate) == OpCode::TYPED_BINARY_OP) {
52 return !acc_.GetGateType(gate).IsIntType();
53 } else {
54 return true;
55 }
56 }
57 return false;
58 }
59
TrustedTypePropagate(std::queue<GateRef> & workList,const std::vector<GateRef> & checkList)60 void CheckElimination::TrustedTypePropagate(std::queue<GateRef>& workList, const std::vector<GateRef>& checkList)
61 {
62 std::unordered_map<GateRef, size_t> trustedInCount;
63 while (!workList.empty()) {
64 auto gate = workList.front();
65 workList.pop();
66 auto uses = acc_.Uses(gate);
67 for (auto i = uses.begin(); i != uses.end(); i++) {
68 GateRef phi = *i;
69 if ((acc_.GetOpCode(phi) != OpCode::VALUE_SELECTOR) ||
70 (acc_.GetGateType(phi) != acc_.GetGateType(gate))) {
71 continue;
72 }
73 trustedInCount[phi]++;
74 if (trustedInCount.at(phi) == acc_.GetNumValueIn(phi)) {
75 workList.push(phi);
76 }
77 }
78 }
79 for (auto check : checkList) {
80 ASSERT(acc_.GetOpCode(check) == OpCode::PRIMITIVE_TYPE_CHECK);
81 auto value = acc_.GetValueIn(check, 0);
82 ASSERT(acc_.GetGateType(value) == acc_.GetParamGateType(check));
83 if (IsTrustedType(value)) {
84 RemoveCheck(check);
85 continue;
86 }
87 if ((trustedInCount.count(value) != 0) &&
88 (trustedInCount.at(value) == acc_.GetNumValueIn(value))) {
89 RemoveCheck(check);
90 continue;
91 }
92 // remove check
93 }
94 }
95
RemoveCheck(GateRef gate)96 void CheckElimination::RemoveCheck(GateRef gate) {
97 auto state = acc_.GetState(gate);
98 auto depend = acc_.GetDep(gate);
99 auto uses = acc_.Uses(gate);
100 for (auto i = uses.begin(); i != uses.end();) {
101 if (acc_.IsStateIn(i)) {
102 i = acc_.ReplaceIn(i, state);
103 } else if (acc_.IsDependIn(i)) {
104 i = acc_.ReplaceIn(i, depend);
105 } else if (acc_.IsValueIn(i)) {
106 i = acc_.ReplaceIn(i, depend);
107 }
108 }
109 acc_.DeleteGate(gate);
110 }
111
RemovePassedCheck()112 void CheckElimination::RemovePassedCheck()
113 {
114 std::queue<GateRef> workList;
115 std::vector<GateRef> passedCheck;
116 std::vector<GateRef> outs;
117 workList.push(acc_.GetStateRoot());
118 std::unordered_set<GateRef> mergeVisit;
119 std::set<std::tuple<OpCode, BitField, GateRef>> CheckSetForOne;
120 std::set<std::tuple<OpCode, BitField, GateRef, GateRef>> CheckSetForTwo;
121 while (!workList.empty()) {
122 auto gate = workList.front();
123 workList.pop();
124 if (acc_.GetOpCode(gate) == OpCode::MERGE) {
125 if (!mergeVisit.count(gate)) {
126 mergeVisit.insert(gate);
127 } else {
128 continue;
129 }
130 }
131 CheckSetForOne.clear();
132 CheckSetForTwo.clear();
133 while (true) {
134 if (!acc_.IsNotWrite(gate)) {
135 CheckSetForOne.clear();
136 CheckSetForTwo.clear();
137 }
138 if (acc_.IsCheckWithOneIn(gate)) {
139 auto op = OpCode(acc_.GetOpCode(gate));
140 auto bit = acc_.TryGetValue(gate);
141 auto v0 = acc_.GetValueIn(gate, 0);
142 auto tp = std::make_tuple(op, bit, v0);
143 if (CheckSetForOne.count(tp)) {
144 passedCheck.emplace_back(gate);
145 } else {
146 CheckSetForOne.insert(tp);
147 }
148 }
149 if (acc_.IsCheckWithTwoIns(gate)) {
150 auto op = OpCode(acc_.GetOpCode(gate));
151 auto bit = acc_.TryGetValue(gate);
152 auto v0 = acc_.GetValueIn(gate, 0);
153 auto v1 = acc_.GetValueIn(gate, 1);
154 auto tp = std::make_tuple(op, bit, v0, v1);
155 if (CheckSetForTwo.count(tp)) {
156 passedCheck.emplace_back(gate);
157 } else {
158 CheckSetForTwo.insert(tp);
159 }
160 }
161
162 outs.clear();
163 acc_.GetStateUses(gate, outs);
164
165 if (outs.size() == 1) {
166 gate = outs[0];
167 auto op = acc_.GetOpCode(gate);
168 if (op == OpCode::LOOP_BACK || op == OpCode::LOOP_BEGIN || op == OpCode::MERGE) {
169 break;
170 }
171 continue;
172 }
173 if ((outs.size() == 2) && (acc_.GetOpCode(gate) == OpCode::JS_BYTECODE)) {
174 if(acc_.GetOpCode(outs[0]) == OpCode::IF_SUCCESS) {
175 gate = outs[0];
176 continue;
177 }
178 if(acc_.GetOpCode(outs[1]) == OpCode::IF_SUCCESS) {
179 gate = outs[1];
180 continue;
181 }
182 }
183 break;
184 }
185 for (auto out : outs) {
186 if (acc_.GetOpCode(out) != OpCode::LOOP_BACK) {
187 workList.push(out);
188 }
189 }
190 }
191 for (auto check : passedCheck) {
192 RemoveCheck(check);
193 }
194 }
195
RemoveTypeTrustedCheck()196 void CheckElimination::RemoveTypeTrustedCheck() {
197 // eliminate type check for type trusted gate (for primitive type check)
198 std::vector<GateRef> allGates;
199 acc_.GetAllGates(allGates);
200 std::queue<GateRef> workList;
201 std::vector<GateRef> checkList;
202 for (auto gate : allGates) {
203 if (IsTrustedType(gate)) {
204 workList.push(gate);
205 }
206 if (IsPrimitiveTypeCheck(gate)) {
207 checkList.emplace_back(gate);
208 }
209 }
210 TrustedTypePropagate(workList, checkList);
211 }
212 } // namespace panda::ecmascript::kungfu