1 /*
2 * Copyright (c) 2023-2024 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/analysis.h"
24 #include "optimizer/ir/basicblock.h"
25 #include "optimizer/ir/inst.h"
26 #include "optimizer/optimizations/phi_type_resolving.h"
27
28 namespace ark::compiler {
PhiTypeResolving(Graph * graph)29 PhiTypeResolving::PhiTypeResolving(Graph *graph) : Optimization(graph), phis_ {graph->GetLocalAllocator()->Adapter()} {}
30
InvalidateAnalyses()31 void PhiTypeResolving::InvalidateAnalyses()
32 {
33 GetGraph()->InvalidateAnalysis<BoundsAnalysis>();
34 GetGraph()->InvalidateAnalysis<AliasAnalysis>();
35 }
36
RunImpl()37 bool PhiTypeResolving::RunImpl()
38 {
39 bool isApplied = false;
40 GetGraph()->RunPass<DominatorsTree>();
41 for (auto bb : GetGraph()->GetBlocksRPO()) {
42 // We use reverse iter because new instrucion is inserted after last phi and forward iteratoris broken.
43 for (auto inst : bb->PhiInstsSafeReverse()) {
44 if (inst->GetType() != DataType::ANY) {
45 continue;
46 }
47 phis_.clear();
48 anyType_ = AnyBaseType::UNDEFINED_TYPE;
49 if (!CheckInputsAnyTypesRec(inst)) {
50 continue;
51 }
52 PropagateTypeToPhi();
53 ASSERT(inst->GetType() != DataType::ANY);
54 isApplied = true;
55 }
56 }
57 return isApplied;
58 }
59
CheckInputsAnyTypesRec(Inst * phi)60 bool PhiTypeResolving::CheckInputsAnyTypesRec(Inst *phi)
61 {
62 ASSERT(phi->IsPhi());
63 if (std::find(phis_.begin(), phis_.end(), phi) != phis_.end()) {
64 return true;
65 }
66
67 if (GetGraph()->IsOsrMode()) {
68 for (auto &user : phi->GetUsers()) {
69 if (user.GetInst()->GetOpcode() == Opcode::SaveStateOsr) {
70 // Find way to enable it in OSR mode.
71 return false;
72 }
73 }
74 }
75
76 phis_.push_back(phi);
77 int32_t inputNum = -1;
78 for (auto &input : phi->GetInputs()) {
79 ++inputNum;
80 auto inputInst = phi->GetDataFlowInput(input.GetInst());
81 if (GetGraph()->IsOsrMode()) {
82 if (HasOsrEntryBetween<BasicBlock>(inputInst->GetBasicBlock(), phi->CastToPhi()->GetPhiInputBb(inputNum))) {
83 return false;
84 }
85 }
86 if (inputInst->GetOpcode() == Opcode::Phi) {
87 if (!CheckInputsAnyTypesRec(inputInst)) {
88 return false;
89 }
90 continue;
91 }
92 if (inputInst->GetOpcode() != Opcode::CastValueToAnyType) {
93 return false;
94 }
95 auto type = inputInst->CastToCastValueToAnyType()->GetAnyType();
96 ASSERT(type != AnyBaseType::UNDEFINED_TYPE);
97 if (anyType_ == AnyBaseType::UNDEFINED_TYPE) {
98 // We can't propogate opject, because GC can move it
99 if (AnyBaseTypeToDataType(type) == DataType::REFERENCE) {
100 return false;
101 }
102 anyType_ = type;
103 continue;
104 }
105 if (anyType_ != type) {
106 return false;
107 }
108 }
109 return AnyBaseTypeToDataType(anyType_) != DataType::ANY;
110 }
111
PropagateTypeToPhi()112 void PhiTypeResolving::PropagateTypeToPhi()
113 {
114 auto newType = AnyBaseTypeToDataType(anyType_);
115 for (auto phi : phis_) {
116 phi->SetType(newType);
117 size_t inputsCount = phi->GetInputsCount();
118 for (size_t idx = 0; idx < inputsCount; ++idx) {
119 auto inputInst = phi->GetDataFlowInput(idx);
120 if (inputInst->GetOpcode() == Opcode::CastValueToAnyType) {
121 phi->SetInput(idx, inputInst->GetInput(0).GetInst());
122 } else if (phi->GetInput(idx).GetInst() != inputInst) {
123 ASSERT(std::find(phis_.begin(), phis_.end(), phi) != phis_.end());
124 // case:
125 // 2.any Phi v1(bb1), v3(bb3) -> v3
126 // 3.any AnyTypeCheck v2 - > v2
127 ASSERT(phi->GetInput(idx).GetInst()->GetOpcode() == Opcode::AnyTypeCheck);
128 phi->SetInput(idx, inputInst);
129 } else {
130 ASSERT(std::find(phis_.begin(), phis_.end(), phi) != phis_.end());
131 }
132 }
133 auto *castToAnyInst = GetGraph()->CreateInstCastValueToAnyType(phi->GetPc(), anyType_, nullptr);
134 auto *bb = phi->GetBasicBlock();
135 auto *first = bb->GetFirstInst();
136 if (first == nullptr) {
137 bb->AppendInst(castToAnyInst);
138 } else if (first->IsSaveState()) {
139 bb->InsertAfter(castToAnyInst, first);
140 } else {
141 bb->InsertBefore(castToAnyInst, first);
142 }
143
144 for (auto it = phi->GetUsers().begin(); it != phi->GetUsers().end();) {
145 auto userInst = it->GetInst();
146 if ((userInst->IsPhi() && userInst->GetType() != DataType::ANY) ||
147 (userInst == first && userInst->IsSaveState())) {
148 ++it;
149 continue;
150 }
151 userInst->SetInput(it->GetIndex(), castToAnyInst);
152 it = phi->GetUsers().begin();
153 }
154 castToAnyInst->SetInput(0, phi);
155 }
156 }
157 } // namespace ark::compiler
158