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