• 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 "if_conversion.h"
18 
19 #include "optimizer/ir/basicblock.h"
20 #include "optimizer/analysis/alias_analysis.h"
21 #include "optimizer/analysis/bounds_analysis.h"
22 
23 namespace panda::compiler {
RunImpl()24 bool IfConversion::RunImpl()
25 {
26     COMPILER_LOG(DEBUG, IFCONVERSION) << "Run " << GetPassName();
27     bool result = false;
28     // Post order (without reverse)
29     for (auto it = GetGraph()->GetBlocksRPO().rbegin(); it != GetGraph()->GetBlocksRPO().rend(); it++) {
30         auto block = *it;
31         if (block->GetSuccsBlocks().size() == MAX_SUCCS_NUM) {
32             result |= TryTriangle(block) || TryDiamond(block);
33         }
34     }
35     COMPILER_LOG(DEBUG, IFCONVERSION) << GetPassName() << " complete";
36     return result;
37 }
38 
39 /*
40    The methods handles the recognition of the following pattern that have two variations:
41    BB -- basic block the recognition starts from
42    TBB -- TrueSuccessor of BB
43    FBB -- FalseSuccessor of BB
44 
45        P0          P1
46       [BB]        [BB]
47        |  \        |  \
48        |  [TBB]    |  [FBB]
49        |  /        |  /
50       [FBB]       [TBB]
51 */
TryTriangle(BasicBlock * bb)52 bool IfConversion::TryTriangle(BasicBlock *bb)
53 {
54     ASSERT(bb->GetSuccsBlocks().size() == MAX_SUCCS_NUM);
55     BasicBlock *tbb;
56     BasicBlock *fbb;
57     bool swapped = false;
58     // interpret P1 variation as P0
59     if (bb->GetTrueSuccessor()->GetPredsBlocks().size() == 1) {
60         tbb = bb->GetTrueSuccessor();
61         fbb = bb->GetFalseSuccessor();
62     } else if (bb->GetFalseSuccessor()->GetPredsBlocks().size() == 1) {
63         tbb = bb->GetFalseSuccessor();
64         fbb = bb->GetTrueSuccessor();
65         swapped = true;
66     } else {
67         return false;
68     }
69 
70     if (tbb->GetSuccsBlocks().size() > 1 || fbb->GetPredsBlocks().size() <= 1 || tbb->GetSuccessor(0) != fbb) {
71         return false;
72     }
73 
74     uint32_t inst_count = 0;
75     uint32_t phi_count = 0;
76     if (IsConvertable(tbb, &inst_count) && IsPhisAllowed(fbb, tbb, bb, &phi_count)) {
77         COMPILER_LOG(DEBUG, IFCONVERSION)
78             << "Triangle pattern was found in Block #" << bb->GetId() << " with " << inst_count
79             << " convertible instruction(s) and " << phi_count << " Phi(s) to process";
80         if (inst_count <= limit_ && phi_count <= limit_) {
81             // Joining tbb into bb
82             bb->JoinBlocksUsingSelect(tbb, nullptr, swapped);
83 
84             if (fbb->GetPredsBlocks().size() == 1 && bb->IsTry() == fbb->IsTry()) {
85                 bb->JoinSuccessorBlock();  // join fbb
86                 COMPILER_LOG(DEBUG, IFCONVERSION) << "Merged blocks " << tbb->GetId() << " and " << fbb->GetId()
87                                                   << " into " << bb->GetId() << " using Select";
88                 GetGraph()->GetEventWriter().EventIfConversion(bb->GetId(), bb->GetGuestPc(), "Triangle", tbb->GetId(),
89                                                                fbb->GetId(), -1);
90             } else {
91                 COMPILER_LOG(DEBUG, IFCONVERSION)
92                     << "Merged block " << tbb->GetId() << " into " << bb->GetId() << " using Select";
93                 GetGraph()->GetEventWriter().EventIfConversion(bb->GetId(), bb->GetGuestPc(), "Triangle_Phi",
94                                                                tbb->GetId(), -1, -1);
95             }
96             return true;
97         }
98     }
99 
100     return false;
101 }
102 
103 /*
104    The methods handles the recognition of the following pattern:
105    BB -- basic block the recognition starts from
106    TBB -- TrueSuccessor of BB
107    FBB -- FalseSuccessor of BB
108    JBB -- Joint basic block of branches
109 
110       [BB]
111      /    \
112    [TBB] [FBB]
113      \    /
114       [JBB]
115 */
TryDiamond(BasicBlock * bb)116 bool IfConversion::TryDiamond(BasicBlock *bb)
117 {
118     ASSERT(bb->GetSuccsBlocks().size() == MAX_SUCCS_NUM);
119     BasicBlock *tbb = bb->GetTrueSuccessor();
120     if (tbb->GetPredsBlocks().size() != 1 || tbb->GetSuccsBlocks().size() != 1) {
121         return false;
122     }
123 
124     BasicBlock *fbb = bb->GetFalseSuccessor();
125     if (fbb->GetPredsBlocks().size() != 1 || fbb->GetSuccsBlocks().size() != 1) {
126         return false;
127     }
128 
129     BasicBlock *jbb = tbb->GetSuccessor(0);
130     if (jbb->GetPredsBlocks().size() <= 1 || fbb->GetSuccessor(0) != jbb) {
131         return false;
132     }
133 
134     uint32_t tbb_inst = 0;
135     uint32_t fbb_inst = 0;
136     uint32_t phi_count = 0;
137     if (IsConvertable(tbb, &tbb_inst) && IsConvertable(fbb, &fbb_inst) && IsPhisAllowed(jbb, tbb, fbb, &phi_count)) {
138         COMPILER_LOG(DEBUG, IFCONVERSION)
139             << "Diamond pattern was found in Block #" << bb->GetId() << " with " << (tbb_inst + fbb_inst)
140             << " convertible instruction(s) and " << phi_count << " Phi(s) to process";
141         if (tbb_inst + fbb_inst <= limit_ && phi_count <= limit_) {
142             // Joining tbb into bb
143             bb->JoinBlocksUsingSelect(tbb, fbb, false);
144 
145             bb->JoinSuccessorBlock();  // joining fbb
146 
147             if (jbb->GetPredsBlocks().size() == 1 && bb->IsTry() == jbb->IsTry()) {
148                 bb->JoinSuccessorBlock();  // joining jbb
149                 COMPILER_LOG(DEBUG, IFCONVERSION) << "Merged blocks " << tbb->GetId() << ", " << fbb->GetId() << " and "
150                                                   << jbb->GetId() << " into " << bb->GetId() << " using Select";
151                 GetGraph()->GetEventWriter().EventIfConversion(bb->GetId(), bb->GetGuestPc(), "Diamond", tbb->GetId(),
152                                                                fbb->GetId(), jbb->GetId());
153             } else {
154                 COMPILER_LOG(DEBUG, IFCONVERSION) << "Merged blocks " << tbb->GetId() << " and " << fbb->GetId()
155                                                   << " into " << bb->GetId() << " using Select";
156                 GetGraph()->GetEventWriter().EventIfConversion(bb->GetId(), bb->GetGuestPc(), "Diamond_Phi",
157                                                                tbb->GetId(), fbb->GetId(), -1);
158             }
159             return true;
160         }
161     }
162     return false;
163 }
164 
IsConvertable(BasicBlock * bb,uint32_t * inst_count)165 bool IfConversion::IsConvertable(BasicBlock *bb, uint32_t *inst_count)
166 {
167     uint32_t total = 0;
168     for (auto inst : bb->AllInsts()) {
169         ASSERT(inst->GetOpcode() != Opcode::Phi);
170         if (!inst->IsIfConvertable()) {
171             return false;
172         }
173         total += static_cast<uint32_t>(inst->HasUsers());
174     }
175     *inst_count = total;
176     return true;
177 }
178 
IsPhisAllowed(BasicBlock * bb,BasicBlock * pred1,BasicBlock * pred2,uint32_t * phi_count)179 bool IfConversion::IsPhisAllowed(BasicBlock *bb, BasicBlock *pred1, BasicBlock *pred2, uint32_t *phi_count)
180 {
181     uint32_t total = 0;
182 
183     for (auto phi : bb->PhiInsts()) {
184         size_t index1 = phi->CastToPhi()->GetPredBlockIndex(pred1);
185         size_t index2 = phi->CastToPhi()->GetPredBlockIndex(pred2);
186         ASSERT(index1 != index2);
187 
188         auto inst1 = phi->GetInput(index1).GetInst();
189         auto inst2 = phi->GetInput(index2).GetInst();
190 
191         if (inst1 == inst2) {
192             // Otherwise DCE should remove Phi
193             [[maybe_unused]] constexpr auto IMM_2 = 2;
194             ASSERT(bb->GetPredsBlocks().size() > IMM_2);
195             // No select needed
196             continue;
197         }
198 
199         // Select can't support float operands
200         if (DataType::IsFloatType(phi->GetType())) {
201             return false;
202         }
203 
204         // One more Select
205         total++;
206     }
207     *phi_count = total;
208     return true;
209 }
210 
InvalidateAnalyses()211 void IfConversion::InvalidateAnalyses()
212 {
213     GetGraph()->InvalidateAnalysis<AliasAnalysis>();
214     GetGraph()->InvalidateAnalysis<BoundsAnalysis>();
215 }
216 }  // namespace panda::compiler
217