• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-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 "compiler_logger.h"
17 #include "optimizer/analysis/alias_analysis.h"
18 #include "optimizer/analysis/bounds_analysis.h"
19 #include "optimizer/analysis/dominators_tree.h"
20 #include "optimizer/analysis/rpo.h"
21 #include "optimizer/analysis/loop_analyzer.h"
22 #include "optimizer/analysis/types_analysis.h"
23 #include "optimizer/ir/basicblock.h"
24 #include "optimizer/ir/inst.h"
25 #include "optimizer/optimizations/types_resolving.h"
26 #ifndef __clang_analyzer__
27 #include "irtoc_ir_inline.h"
28 #endif
29 
30 namespace panda::compiler {
TypesResolving(Graph * graph)31 TypesResolving::TypesResolving(Graph *graph)
32     : Optimization(graph), types_ {graph->GetLocalAllocator()->Adapter()}, phis_ {graph->GetLocalAllocator()->Adapter()}
33 {
34 }
35 
InvalidateAnalyses()36 void TypesResolving::InvalidateAnalyses()
37 {
38     GetGraph()->InvalidateAnalysis<BoundsAnalysis>();
39     GetGraph()->InvalidateAnalysis<AliasAnalysis>();
40     GetGraph()->InvalidateAnalysis<LoopAnalyzer>();
41     InvalidateBlocksOrderAnalyzes(GetGraph());
42 }
43 
RunImpl()44 bool TypesResolving::RunImpl()
45 {
46     bool is_applied = false;
47     GetGraph()->RunPass<TypesAnalysis>();
48     for (auto bb : GetGraph()->GetVectorBlocks()) {
49         if (bb == nullptr || bb->IsEmpty()) {
50             continue;
51         }
52         for (auto inst : bb->InstsSafe()) {
53             if (GetGraph()->GetVectorBlocks()[inst->GetBasicBlock()->GetId()] == nullptr) {
54                 break;
55             }
56             if (inst->GetOpcode() != Opcode::Intrinsic) {
57                 continue;
58             }
59             auto intrinsics_inst = inst->CastToIntrinsic();
60             if (!intrinsics_inst->CanBeInlined()) {
61                 continue;
62             }
63             is_applied |= TryInline(intrinsics_inst);
64         }
65     }
66     is_applied |= TryResolvePhi();
67     return is_applied;
68 }
69 
GetAssumedAnyType(Inst * inst)70 AnyBaseType TypesResolving::GetAssumedAnyType(Inst *inst)
71 {
72     switch (inst->GetOpcode()) {
73         case Opcode::Phi:
74             return inst->CastToPhi()->GetAssumedAnyType();
75         case Opcode::CastValueToAnyType:
76             return inst->CastToCastValueToAnyType()->GetAnyType();
77         case Opcode::AnyTypeCheck: {
78             auto type = inst->CastToAnyTypeCheck()->GetAnyType();
79             if (type == AnyBaseType::UNDEFINED_TYPE) {
80                 return GetAssumedAnyType(inst->GetInput(0).GetInst());
81             }
82             return type;
83         }
84         default:
85             return AnyBaseType::UNDEFINED_TYPE;
86     }
87 }
88 
DoInline(IntrinsicInst * intrinsic)89 bool TypesResolving::DoInline(IntrinsicInst *intrinsic)
90 {
91     switch (intrinsic->GetIntrinsicId()) {
92 #ifndef __clang_analyzer__
93 #include "intrinsics_inline.inl"
94 #endif
95         default: {
96             return false;
97         }
98     }
99 }
100 
CheckInputsAnyTypesRec(Inst * phi)101 bool TypesResolving::CheckInputsAnyTypesRec(Inst *phi)
102 {
103     ASSERT(phi->IsPhi());
104     if (std::find(phis_.begin(), phis_.end(), phi) != phis_.end()) {
105         return true;
106     }
107     phis_.push_back(phi);
108     for (auto &input : phi->GetInputs()) {
109         auto input_inst = phi->GetDataFlowInput(input.GetInst());
110         if (input_inst->GetOpcode() == Opcode::Phi) {
111             if (!CheckInputsAnyTypesRec(input_inst)) {
112                 return false;
113             }
114             continue;
115         }
116         if (input_inst->GetOpcode() != Opcode::CastValueToAnyType) {
117             return false;
118         }
119         auto type = input_inst->CastToCastValueToAnyType()->GetAnyType();
120         ASSERT(type != AnyBaseType::UNDEFINED_TYPE);
121         if (any_type_ == AnyBaseType::UNDEFINED_TYPE) {
122             // We can't propogate opject, because GC can move it
123             if (AnyBaseTypeToDataType(type) == DataType::REFERENCE) {
124                 return false;
125             }
126             any_type_ = type;
127             continue;
128         }
129         if (any_type_ != type) {
130             return false;
131         }
132     }
133     return true;
134 }
135 
PropagateTypeToPhi()136 void TypesResolving::PropagateTypeToPhi()
137 {
138     auto new_type = AnyBaseTypeToDataType(any_type_);
139     for (auto phi : phis_) {
140         phi->SetType(new_type);
141         size_t inputs_count = phi->GetInputsCount();
142         for (size_t idx = 0; idx < inputs_count; ++idx) {
143             auto input_inst = phi->GetDataFlowInput(idx);
144             if (input_inst->GetOpcode() == Opcode::CastValueToAnyType) {
145                 phi->SetInput(idx, input_inst->GetInput(0).GetInst());
146             } else {
147                 ASSERT(std::find(phis_.begin(), phis_.end(), phi) != phis_.end());
148                 // case:
149                 // 2.any Phi v1(bb1), v3(bb3) -> v3
150                 // 3.any AnyTypeCheck v2 - > v2
151                 if (phi->GetInput(idx).GetInst() != input_inst) {
152                     ASSERT(phi->GetInput(idx).GetInst()->GetOpcode() == Opcode::AnyTypeCheck);
153                     phi->SetInput(idx, input_inst);
154                 }
155             }
156         }
157         auto *cast_to_any_inst = GetGraph()->CreateInstCastValueToAnyType(DataType::ANY, phi->GetPc());
158         cast_to_any_inst->SetAnyType(any_type_);
159         phi->GetBasicBlock()->PrependInst(cast_to_any_inst);
160         for (auto it = phi->GetUsers().begin(); it != phi->GetUsers().end();) {
161             auto user_inst = it->GetInst();
162             if (user_inst->IsPhi() && user_inst->GetType() != DataType::ANY) {
163                 ++it;
164                 continue;
165             }
166             user_inst->SetInput(it->GetIndex(), cast_to_any_inst);
167             it = phi->GetUsers().begin();
168         }
169         cast_to_any_inst->SetInput(0, phi);
170     }
171 }
172 
TryResolvePhi()173 bool TypesResolving::TryResolvePhi()
174 {
175     bool is_applied = false;
176     for (auto bb : GetGraph()->GetBlocksRPO()) {
177         // We use reverse iter because new instrucion is inserted after last phi and forward iteratoris brokken.
178         for (auto inst : bb->PhiInstsSafeReverse()) {
179             if (inst->GetType() != DataType::ANY) {
180                 continue;
181             }
182             phis_.clear();
183             any_type_ = AnyBaseType::UNDEFINED_TYPE;
184             if (!CheckInputsAnyTypesRec(inst)) {
185                 continue;
186             }
187             PropagateTypeToPhi();
188             ASSERT(inst->GetType() != DataType::ANY);
189             is_applied = true;
190         }
191     }
192     return is_applied;
193 }
194 
TryInline(IntrinsicInst * intrinsic)195 bool TypesResolving::TryInline(IntrinsicInst *intrinsic)
196 {
197     types_.clear();
198     AnyBaseType type = AnyBaseType::UNDEFINED_TYPE;
199     for (auto &input : intrinsic->GetInputs()) {
200         auto input_inst = input.GetInst();
201         if (input_inst->IsSaveState()) {
202             continue;
203         }
204         auto input_type = GetAssumedAnyType(input_inst);
205         if (input_type != AnyBaseType::UNDEFINED_TYPE) {
206             type = input_type;
207         }
208         types_.emplace_back(input_type);
209     }
210     // last input is SaveSatte
211     ASSERT(types_.size() + 1 == intrinsic->GetInputsCount());
212     // All intrinsics inputs don't have type information.
213     if (type == AnyBaseType::UNDEFINED_TYPE) {
214         return false;
215     }
216     // Set known type to undefined input types.
217     for (auto &curr_type : types_) {
218         if (curr_type == AnyBaseType::UNDEFINED_TYPE) {
219             curr_type = type;
220         }
221     }
222     if (DoInline(intrinsic)) {
223         size_t i = 0;
224         for (auto &input : intrinsic->GetInputs()) {
225             auto input_inst = input.GetInst();
226             if (input_inst->IsSaveState()) {
227                 continue;
228             }
229             if (input_inst->GetOpcode() == Opcode::AnyTypeCheck) {
230                 input_inst->CastToAnyTypeCheck()->SetAnyType(types_[i]);
231             }
232             ++i;
233         }
234         return true;
235     }
236     return false;
237 }
238 }  // namespace panda::compiler
239