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