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