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