• 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 "common.h"
17 #include "compiler/optimizer/ir/basicblock.h"
18 #include "compiler/optimizer/ir/graph.h"
19 
20 namespace panda::bytecodeopt {
21 
AccReadIndex(const compiler::Inst * inst)22 uint8_t AccReadIndex(const compiler::Inst *inst)
23 {
24     // For calls we cannot tell static index for acc position, thus
25     // ensure that we don't invoke this for calls
26     ASSERT(!inst->IsCall());
27 
28     switch (inst->GetOpcode()) {
29         case compiler::Opcode::LoadArray:
30         case compiler::Opcode::StoreObject:
31         case compiler::Opcode::StoreStatic:
32         case compiler::Opcode::NewArray:
33             return 1U;
34         case compiler::Opcode::StoreArray:
35             return 2U;
36         default: {
37             if (inst->IsIntrinsic() && inst->IsAccRead()) {
38                 ASSERT(inst->GetBasicBlock()->GetGraph()->IsDynamicMethod());
39                 ASSERT(inst->GetInputsCount() >= 2U);
40                 return inst->GetInputsCount() - 2U;
41             }
42             return 0;
43         }
44     }
45 }
46 
47 // This method is used by bytecode optimizer's codegen.
CanConvertToIncI(const compiler::BinaryImmOperation * binop)48 bool CanConvertToIncI(const compiler::BinaryImmOperation *binop)
49 {
50     ASSERT(binop->GetBasicBlock()->GetGraph()->IsRegAllocApplied());
51     ASSERT(binop->GetOpcode() == compiler::Opcode::AddI || binop->GetOpcode() == compiler::Opcode::SubI);
52 
53     // IncI works on the same register.
54     if (binop->GetSrcReg(0) != binop->GetDstReg()) {
55         return false;
56     }
57 
58     // IncI cannot write accumulator.
59     if (binop->GetSrcReg(0) == compiler::ACC_REG_ID) {
60         return false;
61     }
62 
63     // IncI users cannot read from accumulator.
64     // While Addi/SubI stores the output in accumulator, IncI works directly on registers.
65     for (const auto &user : binop->GetUsers()) {
66         const auto *uinst = user.GetInst();
67 
68         if (uinst->IsCall()) {
69             continue;
70         }
71 
72         const uint8_t index = AccReadIndex(uinst);
73         if (uinst->GetInput(index).GetInst() == binop && uinst->GetSrcReg(index) == compiler::ACC_REG_ID) {
74             return false;
75         }
76     }
77 
78     constexpr uint64_t bitmask = 0xffffffff;
79     // Define min and max values of i4 type.
80     constexpr int32_t min = -8;
81     constexpr int32_t max = 7;
82 
83     int32_t imm = binop->GetImm() & bitmask;
84     // Note: subi 3 is the same as inci v2, -3.
85     if (binop->GetOpcode() == compiler::Opcode::SubI) {
86         imm = -imm;
87     }
88 
89     // IncI works only with 4 bits immediates.
90     return imm >= min && imm <= max;
91 }
92 
93 }  // namespace panda::bytecodeopt
94