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 #include "ecmascript/compiler/later_elimination.h"
16
17 namespace panda::ecmascript::kungfu {
18
Initialize()19 void LaterElimination::Initialize()
20 {
21 dependChains_.resize(circuit_->GetMaxGateId() + 1, nullptr); // 1: +1 for size
22 GateRef entry = acc_.GetDependRoot();
23 VisitDependEntry(entry);
24 }
25
VisitDependEntry(GateRef gate)26 GateRef LaterElimination::VisitDependEntry(GateRef gate)
27 {
28 auto empty = new (chunk_) DependChains(chunk_);
29 return UpdateDependChain(gate, empty);
30 }
31
VisitGate(GateRef gate)32 GateRef LaterElimination::VisitGate(GateRef gate)
33 {
34 auto opcode = acc_.GetOpCode(gate);
35 switch (opcode) {
36 case OpCode::GET_ENV:
37 case OpCode::GET_GLOBAL_ENV:
38 case OpCode::GET_GLOBAL_ENV_OBJ:
39 case OpCode::GET_GLOBAL_ENV_OBJ_HCLASS:
40 case OpCode::GET_GLOBAL_CONSTANT_VALUE:
41 case OpCode::ARRAY_GUARDIAN_CHECK:
42 case OpCode::HCLASS_STABLE_ARRAY_CHECK:
43 case OpCode::HEAP_OBJECT_CHECK:
44 case OpCode::ECMA_OBJECT_CHECK:
45 case OpCode::INT32_UNSIGNED_UPPER_BOUND_CHECK:
46 case OpCode::OVERFLOW_CHECK:
47 case OpCode::VALUE_CHECK_NEG_OVERFLOW:
48 case OpCode::FLOAT64_CHECK_RIGHT_IS_ZERO:
49 case OpCode::INT32_CHECK_RIGHT_IS_ZERO:
50 case OpCode::INT32_DIV_WITH_CHECK:
51 case OpCode::LEX_VAR_IS_HOLE_CHECK:
52 case OpCode::COW_ARRAY_CHECK:
53 case OpCode::FLATTEN_TREE_STRING_CHECK:
54 case OpCode::CHECK_AND_CONVERT:
55 case OpCode::TAGGED_IS_HEAP_OBJECT:
56 case OpCode::IS_MARKER_CELL_VALID:
57 case OpCode::IS_SPECIFIC_OBJECT_TYPE:
58 return TryEliminateGate(gate);
59 case OpCode::DEPEND_SELECTOR:
60 return TryEliminateDependSelector(gate);
61 default:
62 if (acc_.GetDependCount(gate) == 1) { // 1: depend in is 1
63 return TryEliminateOther(gate);
64 }
65 }
66 return Circuit::NullGate();
67 }
68
TryEliminateOther(GateRef gate)69 GateRef LaterElimination::TryEliminateOther(GateRef gate)
70 {
71 ASSERT(acc_.GetDependCount(gate) >= 1);
72 auto depIn = acc_.GetDep(gate);
73 auto dependChain = GetDependChain(depIn);
74 if (dependChain == nullptr) {
75 return Circuit::NullGate();
76 }
77 return UpdateDependChain(gate, dependChain);
78 }
79
TryEliminateGate(GateRef gate)80 GateRef LaterElimination::TryEliminateGate(GateRef gate)
81 {
82 ASSERT(acc_.GetDependCount(gate) == 1);
83 auto depIn = acc_.GetDep(gate);
84 auto dependChain = GetDependChain(depIn);
85 // dependChain is null
86 if (dependChain == nullptr) {
87 return Circuit::NullGate();
88 }
89 // lookup gate, replace
90 auto preGate = LookupNode(dependChain, gate);
91 if (preGate != Circuit::NullGate()) {
92 return preGate;
93 }
94 // update gate, for others elimination
95 dependChain = dependChain->UpdateNode(gate);
96 return UpdateDependChain(gate, dependChain);
97 }
98
TryEliminateDependSelector(GateRef gate)99 GateRef LaterElimination::TryEliminateDependSelector(GateRef gate)
100 {
101 auto state = acc_.GetState(gate);
102 if (acc_.IsLoopHead(state)) {
103 // use loop head as depend chain
104 return TryEliminateOther(gate);
105 }
106
107 auto dependCount = acc_.GetDependCount(gate);
108 for (size_t i = 0; i < dependCount; ++i) {
109 auto depend = acc_.GetDep(gate, i);
110 auto dependChain = GetDependChain(depend);
111 if (dependChain == nullptr) {
112 return Circuit::NullGate();
113 }
114 }
115
116 // all depend done.
117 auto depend = acc_.GetDep(gate);
118 auto dependChain = GetDependChain(depend);
119 DependChains* copy = new (chunk_) DependChains(chunk_);
120 copy->CopyFrom(dependChain);
121 for (size_t i = 1; i < dependCount; ++i) { // 1: second in
122 auto dependIn = acc_.GetDep(gate, i);
123 auto tempChain = GetDependChain(dependIn);
124 copy->Merge(tempChain);
125 }
126 return UpdateDependChain(gate, copy);
127 }
128
UpdateDependChain(GateRef gate, DependChains* dependChain)129 GateRef LaterElimination::UpdateDependChain(GateRef gate, DependChains* dependChain)
130 {
131 ASSERT(dependChain != nullptr);
132 auto oldDependChain = GetDependChain(gate);
133 if (dependChain->Equals(oldDependChain)) {
134 return Circuit::NullGate();
135 }
136 dependChains_[acc_.GetId(gate)] = dependChain;
137 return gate;
138 }
139
CheckReplacement(GateRef lhs, GateRef rhs)140 bool LaterElimination::CheckReplacement(GateRef lhs, GateRef rhs)
141 {
142 if (!acc_.MetaDataEqu(lhs, rhs)) {
143 if (acc_.GetOpCode(lhs) != acc_.GetOpCode(rhs)) {
144 return false;
145 }
146 }
147 size_t valueCount = acc_.GetNumValueIn(lhs);
148 for (size_t i = 0; i < valueCount; i++) {
149 if (acc_.GetValueIn(lhs, i) != acc_.GetValueIn(rhs, i)) {
150 return false;
151 }
152 }
153 auto opcode = acc_.GetOpCode(lhs);
154 switch (opcode) {
155 case OpCode::GET_GLOBAL_ENV_OBJ:
156 case OpCode::GET_GLOBAL_ENV_OBJ_HCLASS:
157 case OpCode::GET_GLOBAL_CONSTANT_VALUE: {
158 if (acc_.GetIndex(lhs) != acc_.GetIndex(rhs)) {
159 return false;
160 }
161 break;
162 }
163 case OpCode::IS_SPECIFIC_OBJECT_TYPE: {
164 if (acc_.GetJSType(lhs) != acc_.GetJSType(rhs)) {
165 return false;
166 }
167 break;
168 }
169 case OpCode::CHECK_AND_CONVERT: {
170 if (acc_.GetSrcType(lhs) != acc_.GetSrcType(rhs)) {
171 return false;
172 }
173 if (acc_.GetDstType(lhs) != acc_.GetDstType(rhs)) {
174 return false;
175 }
176 break;
177 }
178 default:
179 break;
180 }
181 return true;
182 }
183 } // namespace panda::ecmascript::kungfu
184