• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-2024 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 ark::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->IsCallOrIntrinsic() || (inst->GetBasicBlock()->GetGraph()->IsAbcKit() && !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                 if (inst->GetBasicBlock()->GetGraph()->IsAbcKit()) {
39                     ASSERT(inst->GetInputsCount() >= 1U);
40                     return 0U;
41                 }
42                 ASSERT(inst->GetBasicBlock()->GetGraph()->IsDynamicMethod());
43                 ASSERT(inst->GetInputsCount() >= 2U);
44                 return inst->GetInputsCount() - 2L;
45             }
46             return 0U;
47         }
48     }
49 }
50 
51 #ifdef ENABLE_LIBABCKIT
52 #include "generated/abckit_intrinsics.inl"
53 #else
IsAbcKitIntrinsicRange(compiler::RuntimeInterface::IntrinsicId intrinsicId)54 bool IsAbcKitIntrinsicRange([[maybe_unused]] compiler::RuntimeInterface::IntrinsicId intrinsicId)
55 {
56     UNREACHABLE();
57 }
IsAbcKitIntrinsic(compiler::RuntimeInterface::IntrinsicId intrinsicId)58 bool IsAbcKitIntrinsic([[maybe_unused]] compiler::RuntimeInterface::IntrinsicId intrinsicId)
59 {
60     UNREACHABLE();
61 }
62 #endif
63 
64 // This method is used by bytecode optimizer's codegen.
CanConvertToIncI(const compiler::BinaryImmOperation * binop)65 bool CanConvertToIncI(const compiler::BinaryImmOperation *binop)
66 {
67     ASSERT(binop->GetBasicBlock()->GetGraph()->IsRegAllocApplied());
68     ASSERT(binop->GetOpcode() == compiler::Opcode::AddI || binop->GetOpcode() == compiler::Opcode::SubI);
69 
70     // IncI works on the same register.
71     if (binop->GetSrcReg(0U) != binop->GetDstReg()) {
72         return false;
73     }
74 
75     // IncI cannot write accumulator.
76     if (binop->GetSrcReg(0U) == compiler::GetAccReg()) {
77         return false;
78     }
79 
80     // IncI users cannot read from accumulator.
81     // While Addi/SubI stores the output in accumulator, IncI works directly on registers.
82     for (const auto &user : binop->GetUsers()) {
83         const auto *uinst = user.GetInst();
84 
85         if (uinst->IsCallOrIntrinsic()) {
86             continue;
87         }
88 
89         const uint8_t index = AccReadIndex(uinst);
90         if (uinst->GetInput(index).GetInst() == binop && uinst->GetSrcReg(index) == compiler::GetAccReg()) {
91             return false;
92         }
93     }
94 
95     constexpr uint64_t BITMASK = 0xffffffff;
96     // Define min and max values of i4 type.
97     // NOLINTNEXTLINE(readability-identifier-naming)
98     constexpr int32_t min = -8;
99     // NOLINTNEXTLINE(readability-identifier-naming)
100     constexpr int32_t max = 7;
101 
102     int32_t imm = binop->GetImm() & BITMASK;
103     // Note: subi 3 is the same as inci v2, -3.
104     if (binop->GetOpcode() == compiler::Opcode::SubI) {
105         imm = -imm;
106     }
107 
108     // IncI works only with 4 bits immediates.
109     return imm >= min && imm <= max;
110 }
111 
IsCall(compiler::Inst * inst)112 bool IsCall(compiler::Inst *inst)
113 {
114     if (inst->GetBasicBlock()->GetGraph()->IsAbcKit()) {
115         if (inst->IsCall()) {
116             return true;
117         }
118     } else {
119         if (inst->IsCallOrIntrinsic()) {
120             return true;
121         }
122     }
123     return false;
124 }
125 
126 }  // namespace ark::bytecodeopt
127