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 #ifndef ES2PANDA_COMPILER_CORE_REG_ALLOCATOR_H
17 #define ES2PANDA_COMPILER_CORE_REG_ALLOCATOR_H
18 
19 #include <gen/isa.h>
20 #include <lexer/token/sourceLocation.h>
21 #include <macros.h>
22 
23 namespace panda::es2panda::ir {
24 class AstNode;
25 }  // namespace panda::es2panda::ir
26 
27 namespace panda::es2panda::compiler {
28 
29 class PandaGen;
30 
31 class RegAllocator {
32 public:
RegAllocator(PandaGen *pg)33     explicit RegAllocator(PandaGen *pg)
34         : pg_(pg), sourceLocationFlag_(lexer::SourceLocationFlag::VALID_SOURCE_LOCATION)
35     {
36     }
37     NO_COPY_SEMANTIC(RegAllocator);
38     NO_MOVE_SEMANTIC(RegAllocator);
39     ~RegAllocator() = default;
40 
SetSourceLocationFlag(lexer::SourceLocationFlag flag)41     void SetSourceLocationFlag(lexer::SourceLocationFlag flag)
42     {
43         sourceLocationFlag_ = flag;
44     }
45 
GetSourceLocationFlag() const46     lexer::SourceLocationFlag GetSourceLocationFlag() const
47     {
48         return sourceLocationFlag_;
49     }
50 
51     ArenaAllocator *Allocator() const;
52     bool HasSpill() const;
53     uint16_t GetSpillRegsCount() const;
54 
55     void AdjustInsRegWhenHasSpill();
56 
57     Label *AllocLabel(std::string &&id);
AddLabel(Label *label)58     void AddLabel(Label *label)
59     {
60         PushBack(label);
61     }
62 
63     template <typename T, typename... Args>
Emit(const ir::AstNode *node, Args &&... args)64     void Emit(const ir::AstNode *node, Args &&... args)
65     {
66         auto *ins = Alloc<T>(node, std::forward<Args>(args)...);
67         Run(ins);
68     }
69 
70     template <typename T, typename... Args>
EmitRange(const ir::AstNode *node, size_t argCount, Args &&... args)71     void EmitRange(const ir::AstNode *node, size_t argCount, Args &&... args)
72     {
73         auto *ins = Alloc<T>(node, std::forward<Args>(args)...);
74         Run(ins, argCount);
75     }
76 
77 private:
CheckRegIndices(IRNode *ins, const Span<VReg *> &registers, std::vector<OperandKind> *regsKind = nullptr)78     bool CheckRegIndices(IRNode *ins, const Span<VReg *> &registers,
79                          std::vector<OperandKind> *regsKind = nullptr)
80     {
81         CHECK_NOT_NULL(ins);
82         Formats formats = ins->GetFormats();
83 
84         for (const auto &format : formats) {
85             limit_ = 0;
86             for (const auto &formatItem : format.GetFormatItem()) {
87                 if (regsKind && formatItem.IsVReg()) {
88                     regsKind->push_back(formatItem.Kind());
89                 }
90 
91                 if (formatItem.IsVReg() && limit_ == 0) {
92                     limit_ = 1 << formatItem.Bitwidth();
93                 }
94             }
95 
96             if (std::all_of(registers.begin(), registers.end(),
97                             [this](const VReg *reg) { return IsRegisterCorrect(reg); })) {
98                 return true;
99             }
100         }
101         return false;
102     }
103 
IsRegisterCorrect(const VReg *reg) const104     inline bool IsRegisterCorrect(const VReg *reg) const
105     {
106         return *reg < limit_;
107     }
108 
FreeSpill()109     inline void FreeSpill()
110     {
111         spillIndex_ = 0;
112     }
113 
114     void PushBack(IRNode *ins);
115     void UpdateIcSlot(IRNode *node);
116     void Run(IRNode *ins);
117     void Run(IRNode *ins, size_t argCount);
118     void AdjustInsSpill(const Span<VReg *> &registers, IRNode *ins, ArenaList<IRNode *> &newInsns,
119                         const std::vector<OperandKind> &regsKind);
120     void AdjustRangeInsSpill(Span<VReg *> &registers, IRNode *ins, ArenaList<IRNode *> &newInsns);
121 
122     template <typename T, typename... Args>
Alloc(const ir::AstNode *node, Args &&... args)123     T *Alloc(const ir::AstNode *node, Args &&... args)
124     {
125         ir::AstNode *invalidNode = nullptr;
126         bool isInvalid = GetSourceLocationFlag() == lexer::SourceLocationFlag::INVALID_SOURCE_LOCATION;
127         auto *ret = Allocator()->New<T>(isInvalid ? invalidNode : node, std::forward<Args>(args)...);
128         UpdateIcSlot(ret);
129         return ret;
130     }
131 
132     template <typename T, typename... Args>
Add(ArenaList<IRNode *> &insns, const ir::AstNode *node, Args &&... args)133     void Add(ArenaList<IRNode *> &insns, const ir::AstNode *node, Args &&... args)
134     {
135         insns.push_back(Alloc<T>(node, std::forward<Args>(args)...));
136     }
137 
138     PandaGen *pg_;
139     lexer::SourceLocationFlag sourceLocationFlag_; // for instructions that need to be set with invalid debuginfo
140     size_t limit_ {0};
141     uint16_t spillRegs_ {0};
142     VReg spillIndex_ {0};
143     bool hasSpill_ {false};
144     std::vector<std::pair<VReg, VReg>> dstRegSpills_ {};
145 };
146 
147 class FrontAllocator {
148 public:
149     explicit FrontAllocator(PandaGen *pg);
150     NO_COPY_SEMANTIC(FrontAllocator);
151     NO_MOVE_SEMANTIC(FrontAllocator);
152     ~FrontAllocator();
153 
154 private:
155     PandaGen *pg_;
156     ArenaList<IRNode *> insn_;
157 };
158 }  // namespace panda::es2panda::compiler
159 
160 #endif
161