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)22uint8_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)48bool 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