• 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 "inst_builder.h"
17 #include "phi_resolver.h"
18 #include "compiler_logger.h"
19 
20 namespace panda::compiler {
Prepare()21 void InstBuilder::Prepare()
22 {
23     SetCurrentBlock(GetGraph()->GetStartBlock());
24 #ifndef PANDA_TARGET_WINDOWS
25     GetGraph()->ResetParameterInfo();
26 #endif
27     auto num_args = GetRuntime()->GetMethodTotalArgumentsCount(GetMethod());
28     // Create Parameter instructions for all arguments
29     for (size_t i = 0; i < num_args; i++) {
30         auto param_inst = GetGraph()->AddNewParameter(i);
31         auto type = DataType::Type::ANY;
32         auto reg_num = GetRuntime()->GetMethodRegistersCount(GetMethod()) + i;
33         ASSERT(!GetGraph()->IsBytecodeOptimizer() || reg_num != INVALID_REG);
34 
35         param_inst->SetType(type);
36         SetParamSpillFill(GetGraph(), param_inst, num_args, i, type);
37 
38         UpdateDefinition(reg_num, param_inst);
39     }
40 }
41 
UpdateDefsForCatch()42 void InstBuilder::UpdateDefsForCatch()
43 {
44     Inst *catch_phi = current_bb_->GetFirstInst();
45     ASSERT(catch_phi != nullptr);
46     for (size_t vreg = 0; vreg < GetVRegsCount(); vreg++) {
47         ASSERT(catch_phi->IsCatchPhi());
48         defs_[current_bb_->GetId()][vreg] = catch_phi;
49         catch_phi = catch_phi->GetNext();
50     }
51 }
52 
UpdateDefsForLoopHead()53 void InstBuilder::UpdateDefsForLoopHead()
54 {
55     // If current block is a loop header, then propagate all definitions from preheader's predecessors to
56     // current block.
57     ASSERT(current_bb_->GetLoop()->GetPreHeader());
58     auto pred_defs = defs_[current_bb_->GetLoop()->GetPreHeader()->GetId()];
59     COMPILER_LOG(DEBUG, IR_BUILDER) << "basic block is loop header";
60     for (size_t vreg = 0; vreg < GetVRegsCount(); vreg++) {
61         auto def_inst = pred_defs[vreg];
62         if (def_inst != nullptr) {
63             auto phi = GetGraph()->CreateInstPhi();
64             phi->SetMarker(GetNoTypeMarker());
65             phi->SetLinearNumber(vreg);
66             current_bb_->AppendPhi(phi);
67             (*current_defs_)[vreg] = phi;
68             COMPILER_LOG(DEBUG, IR_BUILDER) << "create Phi(id=" << phi->GetId() << ") for r" << vreg
69                                             << "(def id=" << pred_defs[vreg]->GetId() << ")";
70         }
71     }
72 }
73 
UpdateDefs()74 void InstBuilder::UpdateDefs()
75 {
76     current_bb_->SetMarker(visited_block_marker_);
77     if (current_bb_->IsCatchBegin()) {
78         UpdateDefsForCatch();
79     } else if (current_bb_->IsLoopHeader() && !current_bb_->GetLoop()->IsIrreducible()) {
80         UpdateDefsForLoopHead();
81     } else if (current_bb_->GetPredsBlocks().size() == 1) {
82         // Only one predecessor - simply copy all its definitions
83         auto &pred_defs = defs_[current_bb_->GetPredsBlocks()[0]->GetId()];
84         std::copy(pred_defs.begin(), pred_defs.end(), current_defs_->begin());
85     } else if (current_bb_->GetPredsBlocks().size() > 1) {
86         // If there are multiple predecessors, then add phi for each register that has different definitions
87         for (size_t vreg = 0; vreg < GetVRegsCount(); vreg++) {
88             Inst *value = nullptr;
89             bool different = false;
90             for (auto pred_bb : current_bb_->GetPredsBlocks()) {
91                 // When irreducible loop header is visited before it's back-edge, phi should be created,
92                 // since we do not know if definitions are different at this point
93                 if (!pred_bb->IsMarked(visited_block_marker_)) {
94                     ASSERT(current_bb_->GetLoop()->IsIrreducible());
95                     different = true;
96                     break;
97                 }
98                 if (value == nullptr) {
99                     value = defs_[pred_bb->GetId()][vreg];
100                 } else if (value != defs_[pred_bb->GetId()][vreg]) {
101                     different = true;
102                     break;
103                 }
104             }
105             if (different) {
106                 auto phi = GetGraph()->CreateInstPhi();
107                 phi->SetMarker(GetNoTypeMarker());
108                 phi->SetLinearNumber(vreg);
109                 current_bb_->AppendPhi(phi);
110                 (*current_defs_)[vreg] = phi;
111                 COMPILER_LOG(DEBUG, IR_BUILDER) << "create Phi(id=" << phi->GetId() << ") for r" << vreg;
112             } else {
113                 (*current_defs_)[vreg] = value;
114             }
115         }
116     }
117 }
118 
AddCatchPhiInputs(const ArenaUnorderedSet<BasicBlock * > & catch_handlers,const InstVector & defs,Inst * throwable_inst)119 void InstBuilder::AddCatchPhiInputs(const ArenaUnorderedSet<BasicBlock *> &catch_handlers, const InstVector &defs,
120                                     Inst *throwable_inst)
121 {
122     ASSERT(!catch_handlers.empty());
123     for (auto catch_bb : catch_handlers) {
124         auto inst = catch_bb->GetFirstInst();
125         while (!inst->IsCatchPhi()) {
126             inst = inst->GetNext();
127         }
128         ASSERT(inst != nullptr);
129         GetGraph()->AppendThrowableInst(throwable_inst, catch_bb);
130         for (size_t vreg = 0; vreg < GetVRegsCount(); vreg++, inst = inst->GetNext()) {
131             ASSERT(inst->GetOpcode() == Opcode::CatchPhi);
132             auto catch_phi = inst->CastToCatchPhi();
133             if (catch_phi->IsAcc()) {
134                 ASSERT(vreg == VREGS_AND_ARGS_COUNT);
135                 continue;
136             }
137             auto input_inst = defs[vreg];
138             if (input_inst != nullptr && input_inst != catch_phi) {
139                 catch_phi->AppendInput(input_inst);
140                 catch_phi->AppendThrowableInst(throwable_inst);
141             }
142         }
143     }
144 }
145 
SetParamSpillFill(Graph * graph,ParameterInst * param_inst,size_t num_args,size_t i,DataType::Type type)146 void InstBuilder::SetParamSpillFill(Graph *graph, ParameterInst *param_inst, size_t num_args, size_t i,
147                                     DataType::Type type)
148 {
149     if (graph->IsBytecodeOptimizer()) {
150         auto reg_src = static_cast<Register>(VIRTUAL_FRAME_SIZE - num_args + i);
151         DataType::Type reg_type;
152         if (DataType::IsReference(type)) {
153             reg_type = DataType::REFERENCE;
154         } else if (DataType::Is64Bits(type, graph->GetArch())) {
155             reg_type = DataType::UINT64;
156         } else {
157             reg_type = DataType::UINT32;
158         }
159 
160         param_inst->SetLocationData({LocationType::REGISTER, LocationType::REGISTER, reg_src, reg_src, reg_type});
161     }
162 }
163 
164 /**
165  * Set type of instruction, then recursively set type to its inputs.
166  */
SetTypeRec(Inst * inst,DataType::Type type)167 void InstBuilder::SetTypeRec(Inst *inst, DataType::Type type)
168 {
169     inst->SetType(type);
170     inst->ResetMarker(GetNoTypeMarker());
171     for (auto input : inst->GetInputs()) {
172         if (input.GetInst()->IsMarked(GetNoTypeMarker())) {
173             SetTypeRec(input.GetInst(), type);
174         }
175     }
176 }
177 
178 /**
179  * Remove vreg from SaveState for the case
180  * BB 1
181  *   ....
182  * succs: [bb 2, bb 3]
183  *
184  * BB 2: preds: [bb 1]
185  *   89.i64  Sub                        v85, v88 -> (v119, v90)
186  *   90.f64  Cast                       v89 -> (v96, v92)
187  * succs: [bb 3]
188  *
189  * BB 3: preds: [bb 1, bb 2]
190  *   .....
191  *   119.     SaveState                  v105(vr0), v106(vr1), v94(vr4), v89(vr8), v0(vr10), v1(vr11) -> (v120)
192  *
193  * v89(vr8) used only in BB 2, so we need to remove its from "119.     SaveState"
194  */
195 /* static */
RemoveNotDominateInputs(SaveStateInst * save_state)196 void InstBuilder::RemoveNotDominateInputs(SaveStateInst *save_state)
197 {
198     size_t idx = 0;
199     size_t inputs_count = save_state->GetInputsCount();
200     while (idx < inputs_count) {
201         auto input_inst = save_state->GetInput(idx).GetInst();
202         // We can don't call IsDominate, if save_state and input_inst in one basic block.
203         // It's reduce number of IsDominate calls.
204         if (!input_inst->InSameBlockOrDominate(save_state)) {
205             save_state->RemoveInput(idx);
206             inputs_count--;
207         } else {
208             ASSERT(input_inst->GetBasicBlock() != save_state->GetBasicBlock() || input_inst->IsDominate(save_state));
209             idx++;
210         }
211     }
212 }
213 
214 /**
215  * Fix instructions that can't be fully completed in building process.
216  */
FixInstructions()217 void InstBuilder::FixInstructions()
218 {
219     // Remove dead Phi and set types to phi which have not type.
220     // Phi may not have type if all it users are pseudo instructions, like SaveState
221     for (auto bb : GetGraph()->GetBlocksRPO()) {
222         for (auto inst : bb->PhiInstsSafe()) {
223             inst->ReserveInputs(bb->GetPredsBlocks().size());
224             for (auto &pred_bb : bb->GetPredsBlocks()) {
225                 if (inst->GetLinearNumber() == INVALID_LINEAR_NUM) {
226                     continue;
227                 }
228                 auto pred = defs_[pred_bb->GetId()][inst->GetLinearNumber()];
229                 if (pred == nullptr) {
230                     // If any input of phi instruction is not defined then we assume that phi is dead. DCE should
231                     // remove it.
232                     continue;
233                 }
234                 inst->AppendInput(pred);
235             }
236         }
237     }
238 
239     // Check all instructions that have no type and fix it. Type is got from instructions with known input types.
240     for (auto bb : GetGraph()->GetBlocksRPO()) {
241         for (auto inst : bb->AllInsts()) {
242             if (inst->IsSaveState()) {
243                 RemoveNotDominateInputs(static_cast<SaveStateInst *>(inst));
244                 continue;
245             }
246             auto input_idx = 0;
247             for (auto input : inst->GetInputs()) {
248                 if (input.GetInst()->IsMarked(GetNoTypeMarker())) {
249                     auto input_type = inst->GetInputType(input_idx);
250                     if (input_type != DataType::NO_TYPE) {
251                         SetTypeRec(input.GetInst(), input_type);
252                     }
253                 }
254                 input_idx++;
255             }
256         }
257     }
258     // Resolve dead and inconsistent phi instructions
259     PhiResolver phi_resolver(GetGraph());
260     phi_resolver.Run();
261     ResolveConstants();
262     CleanupCatchPhis();
263 }
264 
CreateSaveState(Opcode opc,size_t pc)265 SaveStateInst *InstBuilder::CreateSaveState(Opcode opc, size_t pc)
266 {
267     ASSERT(opc == Opcode::SaveState);
268     SaveStateInst *inst = GetGraph()->CreateInstSaveState();
269     inst->SetPc(pc);
270     inst->SetMethod(GetMethod());
271     inst->ReserveInputs(0);
272     return inst;
273 }
274 
GetMethodArgumentsCount(uintptr_t id) const275 size_t InstBuilder::GetMethodArgumentsCount(uintptr_t id) const
276 {
277     return GetRuntime()->GetMethodArgumentsCount(GetMethod(), id);
278 }
279 
GetPc(const uint8_t * inst_ptr) const280 size_t InstBuilder::GetPc(const uint8_t *inst_ptr) const
281 {
282     return inst_ptr - instructions_buf_;
283 }
284 
ResolveConstants()285 void InstBuilder::ResolveConstants()
286 {
287     ConstantInst *curr_const = GetGraph()->GetFirstConstInst();
288     while (curr_const != nullptr) {
289         SplitConstant(curr_const);
290         curr_const = curr_const->GetNextConst();
291     }
292 }
293 
SplitConstant(ConstantInst * const_inst)294 void InstBuilder::SplitConstant(ConstantInst *const_inst)
295 {
296     if (const_inst->GetType() != DataType::INT64 || !const_inst->HasUsers()) {
297         return;
298     }
299     auto users = const_inst->GetUsers();
300     auto curr_it = users.begin();
301     while (curr_it != users.end()) {
302         auto user = (*curr_it).GetInst();
303         DataType::Type type = user->GetInputType(curr_it->GetIndex());
304         ++curr_it;
305         if (type != DataType::FLOAT32 && type != DataType::FLOAT64) {
306             continue;
307         }
308         ConstantInst *new_const = nullptr;
309         if (type == DataType::FLOAT32) {
310             auto val = bit_cast<float>(static_cast<uint32_t>(const_inst->GetIntValue()));
311             new_const = GetGraph()->FindOrCreateConstant(val);
312         } else {
313             auto val = bit_cast<double, uint64_t>(const_inst->GetIntValue());
314             new_const = GetGraph()->FindOrCreateConstant(val);
315         }
316         user->ReplaceInput(const_inst, new_const);
317     }
318 }
319 
CleanupCatchPhis()320 void InstBuilder::CleanupCatchPhis()
321 {
322     for (auto block : GetGraph()->GetBlocksRPO()) {
323         for (auto inst : block->AllInstsSafe()) {
324             if (!inst->IsCatchPhi() || inst->GetInputs().Empty()) {
325                 continue;
326             }
327             // Remove catch-phis without real users
328             bool has_ss_users_only = true;
329             for (const auto &user : inst->GetUsers()) {
330                 if (!user.GetInst()->IsSaveState()) {
331                     has_ss_users_only = false;
332                     break;
333                 }
334             }
335             if (has_ss_users_only) {
336                 auto users = inst->GetUsers();
337                 while (!users.Empty()) {
338                     auto &user = users.Front();
339                     user.GetInst()->RemoveInput(user.GetIndex());
340                 }
341                 block->RemoveInst(inst);
342             }
343         }
344     }
345 }
346 }  // namespace panda::compiler
347