1b1994897Sopenharmony_ci/** 2b1994897Sopenharmony_ci * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3b1994897Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4b1994897Sopenharmony_ci * you may not use this file except in compliance with the License. 5b1994897Sopenharmony_ci * You may obtain a copy of the License at 6b1994897Sopenharmony_ci * 7b1994897Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8b1994897Sopenharmony_ci * 9b1994897Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10b1994897Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11b1994897Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12b1994897Sopenharmony_ci * See the License for the specific language governing permissions and 13b1994897Sopenharmony_ci * limitations under the License. 14b1994897Sopenharmony_ci */ 15b1994897Sopenharmony_ci 16b1994897Sopenharmony_ci#ifndef BYTECODE_OPTIMIZER_REG_ENCODER_H 17b1994897Sopenharmony_ci#define BYTECODE_OPTIMIZER_REG_ENCODER_H 18b1994897Sopenharmony_ci 19b1994897Sopenharmony_ci#include "compiler/optimizer/ir/graph.h" 20b1994897Sopenharmony_ci#include "compiler/optimizer/pass.h" 21b1994897Sopenharmony_ci#include "compiler/optimizer/ir/inst.h" 22b1994897Sopenharmony_ci#include "compiler/optimizer/ir/graph_visitor.h" 23b1994897Sopenharmony_ci 24b1994897Sopenharmony_ci/* 25b1994897Sopenharmony_ci * Register Encoder. 26b1994897Sopenharmony_ci * 27b1994897Sopenharmony_ci * After compiler's register allocation layout of the virtual frame looks like: 28b1994897Sopenharmony_ci * 29b1994897Sopenharmony_ci * |<-locals->|<-free registers->|<-RegAlloc temps->|<-arguments->| 30b1994897Sopenharmony_ci * 31b1994897Sopenharmony_ci * where: 32b1994897Sopenharmony_ci * 33b1994897Sopenharmony_ci * * locals (>= 0) are registers allocated for function's local variables; 34b1994897Sopenharmony_ci * * temps (>= 0) are temporary registers that can be allocated by spill-fill 35b1994897Sopenharmony_ci * resolver during breaking mov chain cycles; 36b1994897Sopenharmony_ci * * arguments (>= 0) are registers allocated for function's arguemnts. 37b1994897Sopenharmony_ci * 38b1994897Sopenharmony_ci * The size of the frame is fixed (see register allocator for details). 39b1994897Sopenharmony_ci * 40b1994897Sopenharmony_ci * Locals and temps are allocated densely: if there are more than 0 locals 41b1994897Sopenharmony_ci * (or temps) then all registers go strictly in order without "holes". 42b1994897Sopenharmony_ci * Space for arguments, however, can contain "holes" (each "hole" corresponds 43b1994897Sopenharmony_ci * to an unused argument). 44b1994897Sopenharmony_ci * 45b1994897Sopenharmony_ci * For locals and temps, it is not guaranteed that their number equals to the 46b1994897Sopenharmony_ci * number of registers used in the unoptimized bytecode. Total number of arguments 47b1994897Sopenharmony_ci * is of course constant throughout optimization pipeline. 48b1994897Sopenharmony_ci * 49b1994897Sopenharmony_ci * This pass solves following problems: 50b1994897Sopenharmony_ci * 51b1994897Sopenharmony_ci * 1. Shift temps and arguments to the left adjacently to locals, and reserve the 52b1994897Sopenharmony_ci * range temps from free registers if necessary, consistently changing all register 53b1994897Sopenharmony_ci * numbers for affected instructions. After this is done, the virtual frame looks like: 54b1994897Sopenharmony_ci * 55b1994897Sopenharmony_ci * |<-locals->|<-range temps->|<-RegAlloc temps->|<-arguments->|<-free registers->| 56b1994897Sopenharmony_ci * 57b1994897Sopenharmony_ci * 2. Check if IR contains any instructions that can encode only [r0, r15] with 58b1994897Sopenharmony_ci * actual inputs r16+. If such instructions are found, some lower registers 59b1994897Sopenharmony_ci * (starting with r0, but no more than MAX_NUM_INPUTS registers) are reserved as 60b1994897Sopenharmony_ci * temps and corresponding spills are emitted where needed. After this is done, 61b1994897Sopenharmony_ci * the virtual frame looks like: 62b1994897Sopenharmony_ci * 63b1994897Sopenharmony_ci * |<-Renumber temps->|<-locals->|<-range temps->|<-RegAlloc temps->|<-arguments->|<-free registers->| 64b1994897Sopenharmony_ci * 65b1994897Sopenharmony_ci * After the pass: 66b1994897Sopenharmony_ci * 67b1994897Sopenharmony_ci * * Usage mask is updated accordingly. 68b1994897Sopenharmony_ci * * num_locals + num_temps + num_max_range_input is stored to graph with SetStackSlotsCount 69b1994897Sopenharmony_ci */ 70b1994897Sopenharmony_ci 71b1994897Sopenharmony_cinamespace panda::bytecodeopt { 72b1994897Sopenharmony_cistruct RegContent { 73b1994897Sopenharmony_ci compiler::Register reg; 74b1994897Sopenharmony_ci compiler::DataType::Type type; 75b1994897Sopenharmony_ci 76b1994897Sopenharmony_ci RegContent() : reg(compiler::INVALID_REG), type(compiler::DataType::NO_TYPE) {} 77b1994897Sopenharmony_ci RegContent(compiler::Register r, compiler::DataType::Type t) : reg(r), type(t) {} 78b1994897Sopenharmony_ci 79b1994897Sopenharmony_ci bool operator==(const RegContent &other) const 80b1994897Sopenharmony_ci { 81b1994897Sopenharmony_ci return reg == other.reg && type == other.type; 82b1994897Sopenharmony_ci } 83b1994897Sopenharmony_ci 84b1994897Sopenharmony_ci bool operator!=(const RegContent &other) const 85b1994897Sopenharmony_ci { 86b1994897Sopenharmony_ci return !(*this == other); 87b1994897Sopenharmony_ci } 88b1994897Sopenharmony_ci}; 89b1994897Sopenharmony_ciusing RegContentMap = ArenaUnorderedMap<compiler::Register, RegContent>; 90b1994897Sopenharmony_ciusing RegContentVec = ArenaVector<std::pair<compiler::Register, RegContent>>; 91b1994897Sopenharmony_ci 92b1994897Sopenharmony_cienum class RegEncoderState { IDLE, RENUMBER_ARGS, RESERVE_TEMPS, INSERT_SPILLS }; 93b1994897Sopenharmony_ci 94b1994897Sopenharmony_ciusing panda::compiler::BasicBlock; 95b1994897Sopenharmony_ciusing panda::compiler::Inst; 96b1994897Sopenharmony_ciusing panda::compiler::Opcode; 97b1994897Sopenharmony_ci 98b1994897Sopenharmony_ciclass RegEncoder : public compiler::Optimization, public compiler::GraphVisitor { 99b1994897Sopenharmony_cipublic: 100b1994897Sopenharmony_ci explicit RegEncoder(compiler::Graph *graph) 101b1994897Sopenharmony_ci : compiler::Optimization(graph), num_temps_(0), state_(RegEncoderState::IDLE) 102b1994897Sopenharmony_ci { 103b1994897Sopenharmony_ci } 104b1994897Sopenharmony_ci 105b1994897Sopenharmony_ci ~RegEncoder() override = default; 106b1994897Sopenharmony_ci 107b1994897Sopenharmony_ci // true: Pass applied successfully 108b1994897Sopenharmony_ci // false: Unable to apply pass because of insufficient number of registers 109b1994897Sopenharmony_ci bool RunImpl() override; 110b1994897Sopenharmony_ci 111b1994897Sopenharmony_ci const char *GetPassName() const override 112b1994897Sopenharmony_ci { 113b1994897Sopenharmony_ci return "RegEncoder"; 114b1994897Sopenharmony_ci } 115b1994897Sopenharmony_ci 116b1994897Sopenharmony_ci void Check4Width(compiler::Inst *inst); 117b1994897Sopenharmony_ci void Check8Width(compiler::Inst *inst); 118b1994897Sopenharmony_ci 119b1994897Sopenharmony_ci const ArenaVector<BasicBlock *> &GetBlocksToVisit() const override 120b1994897Sopenharmony_ci { 121b1994897Sopenharmony_ci return GetGraph()->GetBlocksRPO(); 122b1994897Sopenharmony_ci } 123b1994897Sopenharmony_ci 124b1994897Sopenharmony_ci static void VisitIntrinsic(GraphVisitor *visitor, Inst *inst); 125b1994897Sopenharmony_ci 126b1994897Sopenharmony_ci#include "generated/reg_encoder_visitors.inc" 127b1994897Sopenharmony_ci 128b1994897Sopenharmony_ci#include "generated/check_width.h" 129b1994897Sopenharmony_ci 130b1994897Sopenharmony_ci void VisitDefault(Inst *inst) override {} 131b1994897Sopenharmony_ci 132b1994897Sopenharmony_ci#include "compiler/optimizer/ir/visitor.inc" 133b1994897Sopenharmony_ci 134b1994897Sopenharmony_ciprivate: 135b1994897Sopenharmony_ci void CalculateNumNeededTemps(); 136b1994897Sopenharmony_ci void CalculateNumNeededTempsForInst(compiler::Inst *inst); 137b1994897Sopenharmony_ci void RenumberRegs(const compiler::Register min_reg, const compiler::Register delta); 138b1994897Sopenharmony_ci bool RenumberArgRegs(); 139b1994897Sopenharmony_ci void InsertSpills(); 140b1994897Sopenharmony_ci void InsertSpillsForInst(compiler::Inst *inst); 141b1994897Sopenharmony_ci void InsertSpillsForDynInputsInst(compiler::Inst *inst); 142b1994897Sopenharmony_ci 143b1994897Sopenharmony_ci compiler::Register GetNumArgsFromGraph() const 144b1994897Sopenharmony_ci { 145b1994897Sopenharmony_ci auto adapter = GetGraph()->GetRuntime(); 146b1994897Sopenharmony_ci auto method = GetGraph()->GetMethod(); 147b1994897Sopenharmony_ci auto num_args = adapter->GetMethodTotalArgumentsCount(method); 148b1994897Sopenharmony_ci ASSERT(num_args <= compiler::VIRTUAL_FRAME_SIZE); 149b1994897Sopenharmony_ci return num_args; 150b1994897Sopenharmony_ci } 151b1994897Sopenharmony_ci 152b1994897Sopenharmony_ci compiler::Register GetNumLocalsFromGraph() const 153b1994897Sopenharmony_ci { 154b1994897Sopenharmony_ci auto num_locals = GetGraph()->GetStackSlotsCount(); 155b1994897Sopenharmony_ci ASSERT(num_locals <= compiler::VIRTUAL_FRAME_SIZE); 156b1994897Sopenharmony_ci return num_locals; 157b1994897Sopenharmony_ci } 158b1994897Sopenharmony_ci 159b1994897Sopenharmony_ci compiler::Register GetNumRegs() const 160b1994897Sopenharmony_ci { 161b1994897Sopenharmony_ci auto num_regs = GetNumLocalsFromGraph() + GetNumArgsFromGraph(); 162b1994897Sopenharmony_ci ASSERT(num_regs <= compiler::VIRTUAL_FRAME_SIZE); 163b1994897Sopenharmony_ci return num_regs; 164b1994897Sopenharmony_ci } 165b1994897Sopenharmony_ci 166b1994897Sopenharmony_ci void SaveNumLocalsToGraph(uint32_t num_locals) const 167b1994897Sopenharmony_ci { 168b1994897Sopenharmony_ci ASSERT(num_locals <= compiler::VIRTUAL_FRAME_SIZE); 169b1994897Sopenharmony_ci GetGraph()->SetStackSlotsCount(num_locals); 170b1994897Sopenharmony_ci } 171b1994897Sopenharmony_ci 172b1994897Sopenharmony_ci bool GetStatus() const 173b1994897Sopenharmony_ci { 174b1994897Sopenharmony_ci return success_; 175b1994897Sopenharmony_ci } 176b1994897Sopenharmony_ci 177b1994897Sopenharmony_ci static void CallHelper(compiler::GraphVisitor *visitor, Inst *inst) 178b1994897Sopenharmony_ci { 179b1994897Sopenharmony_ci auto *re = static_cast<RegEncoder *>(visitor); 180b1994897Sopenharmony_ci re->Check4Width(inst); 181b1994897Sopenharmony_ci } 182b1994897Sopenharmony_ci 183b1994897Sopenharmony_ciprivate: 184b1994897Sopenharmony_ci compiler::Register num_temps_; 185b1994897Sopenharmony_ci RegEncoderState state_; 186b1994897Sopenharmony_ci compiler::Register num_max_range_input_ {0}; 187b1994897Sopenharmony_ci compiler::Register range_temps_start_ {0}; 188b1994897Sopenharmony_ci 189b1994897Sopenharmony_ci bool success_ {true}; 190b1994897Sopenharmony_ci}; 191b1994897Sopenharmony_ci} // namespace panda::bytecodeopt 192b1994897Sopenharmony_ci 193b1994897Sopenharmony_ci#endif // BYTECODE_OPTIMIZER_REG_ENCODER_H 194