• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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