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