• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2025 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 "regAllocator.h"
17 
18 #include "compiler/core/codeGen.h"
19 #include "checker/types/type.h"
20 
21 #include <algorithm>
22 #include <vector>
23 
24 namespace ark::es2panda::compiler {
25 // AllocatorBase
26 
AllocatorBase(CodeGen * const cg)27 AllocatorBase::AllocatorBase(CodeGen *const cg) noexcept : cg_(cg) {}
28 
PushBack(IRNode * const ins) const29 void AllocatorBase::PushBack(IRNode *const ins) const
30 {
31     cg_->Insns().push_back(ins);
32 }
33 
GetCodeGen()34 CodeGen &AllocatorBase::GetCodeGen() noexcept
35 {
36     return *cg_;
37 }
38 
GetCodeGen() const39 const CodeGen &AllocatorBase::GetCodeGen() const noexcept
40 {
41     return *cg_;
42 }
43 
Allocator()44 ArenaAllocator &AllocatorBase::Allocator() noexcept
45 {
46     return *cg_->Allocator();
47 }
48 
Allocator() const49 const ArenaAllocator &AllocatorBase::Allocator() const noexcept
50 {
51     return *cg_->Allocator();
52 }
53 
54 // SimpleAllocator
55 
SimpleAllocator(CodeGen * const cg)56 SimpleAllocator::SimpleAllocator(CodeGen *const cg) noexcept : AllocatorBase(cg) {}
57 
AllocLabel(std::string && id)58 Label *SimpleAllocator::AllocLabel(std::string &&id)
59 {
60     const auto *lastInsNode =
61         GetCodeGen().Insns().empty() ? FIRST_NODE_OF_FUNCTION : GetCodeGen().Insns().back()->Node();
62     return Alloc<Label>(lastInsNode, std::move(id));
63 }
64 
AddLabel(Label * const label) const65 void SimpleAllocator::AddLabel(Label *const label) const
66 {
67     PushBack(label);
68 }
69 
70 // RegAllocatorBase
71 
RegAllocatorBase(CodeGen * const cg,RegSpiller * const spiller)72 RegAllocatorBase::RegAllocatorBase(CodeGen *const cg, RegSpiller *const spiller) noexcept
73     : AllocatorBase(cg), spiller_(spiller)
74 {
75 }
76 
Spiller()77 RegSpiller &RegAllocatorBase::Spiller() noexcept
78 {
79     return *spiller_;
80 }
81 
Spiller() const82 const RegSpiller &RegAllocatorBase::Spiller() const noexcept
83 {
84     return *spiller_;
85 }
86 
RegIndicesValid(const IRNode * const ins,const Span<VReg * > & registers)87 std::pair<bool, std::size_t> RegAllocatorBase::RegIndicesValid(const IRNode *const ins, const Span<VReg *> &registers)
88 {
89     const auto &formats = ins->GetFormats();
90     std::size_t limit = 0;
91 
92     for (const auto &format : formats) {
93         for (const auto &formatItem : format.GetFormatItem()) {
94             if (formatItem.IsVReg()) {
95                 limit = 1U << formatItem.BitWidth();
96                 break;
97             }
98         }
99 
100         if (std::all_of(registers.begin(), registers.end(),
101                         [limit](const VReg *const reg) { return reg->IsValid(limit); })) {
102             return {true, limit};
103         }
104     }
105 
106     return {false, limit};
107 }
108 
Spill(IRNode * const ins,const VReg reg) const109 VReg RegAllocatorBase::Spill(IRNode *const ins, const VReg reg) const
110 {
111     const auto [spill_info, origin_type] = spiller_->New();
112 
113     if (origin_type != nullptr) {
114         if (auto *const mov = spiller_->MoveReg(ins->Node(), spill_info.SpillReg(), spill_info.OriginReg(), true);
115             mov != nullptr) {
116             PushBack(mov);
117         }
118     }
119 
120     if (auto *const mov = spiller_->MoveReg(ins->Node(), spill_info.OriginReg(), reg, false); mov != nullptr) {
121         PushBack(mov);
122         spiller_->GetCodeGen()->SetVRegType(spill_info.OriginReg(), origin_type);
123     }
124 
125     return spill_info.OriginReg();
126 }
127 
Restore(const IRNode * const ins) const128 void RegAllocatorBase::Restore(const IRNode *const ins) const
129 {
130     const auto spillInfo = spiller_->Restore();
131     if (spiller_->GetCodeGen()->GetVRegType(spillInfo.OriginReg()) == nullptr) {
132         return;
133     }
134 
135     if (auto *const mov = spiller_->MoveReg(ins->Node(), spillInfo.OriginReg(), spillInfo.SpillReg(), false);
136         mov != nullptr) {
137         PushBack(mov);
138     }
139 }
140 
141 // RegAllocator
142 
RegAllocator(CodeGen * const cg,RegSpiller * const spiller)143 RegAllocator::RegAllocator(CodeGen *const cg, RegSpiller *const spiller) noexcept : RegAllocatorBase(cg, spiller) {}
144 
Run(IRNode * const ins,const int32_t spillMax)145 void RegAllocator::Run(IRNode *const ins, const int32_t spillMax)
146 {
147     ES2PANDA_ASSERT(Spiller().Restored());
148     std::array<VReg *, IRNode::MAX_REG_OPERAND> regs {};
149     ES2PANDA_ASSERT(ins != nullptr);
150     const auto regCnt = ins->Registers(&regs);
151     const auto registers =
152         Span<VReg *>(regs.data(), regs.data() + (spillMax == std::numeric_limits<int32_t>::max() ? regCnt : spillMax));
153 
154     std::array<OutVReg, IRNode::MAX_REG_OPERAND> dstRegs {};
155     ins->OutRegisters(&dstRegs);
156 
157     const auto [indices_valid, limit] = RegIndicesValid(ins, registers);
158     if (indices_valid) {
159         PushBack(ins);
160         return;
161     }
162 
163     const auto rs = Spiller().Start(GetCodeGen());
164 
165     std::unordered_set<VReg> validRegs;
166     for (auto *const reg : registers) {
167         if (!reg->IsValid(limit)) {
168             continue;
169         }
170 
171         validRegs.insert(*reg);
172     }
173 
174     std::vector<IRNode *> dstMoves;
175     size_t i = 0;
176     for (auto *const reg : registers) {
177         auto dstInfo = dstRegs[i++];
178         if (reg->IsValid(limit)) {
179             continue;
180         }
181 
182         Spiller().Adjust(validRegs);
183 
184         auto r = Spill(ins, *reg);
185 
186         if (dstInfo.reg != nullptr) {
187             dstMoves.push_back(GetCodeGen().AllocMov(ins->Node(), dstInfo, r));
188         }
189 
190         *reg = r;
191     }
192 
193     PushBack(ins);
194 
195     for (auto *mov : dstMoves) {
196         PushBack(mov);
197     }
198 
199     while (!Spiller().Restored()) {
200         Restore(ins);
201     }
202 
203     Spiller().Finalize();
204 }
205 
206 // RangeRegAllocator
207 
RangeRegAllocator(CodeGen * const cg,RegSpiller * const spiller)208 RangeRegAllocator::RangeRegAllocator(CodeGen *const cg, RegSpiller *const spiller) noexcept
209     : RegAllocatorBase(cg, spiller)
210 {
211 }
212 
Run(IRNode * const ins,VReg rangeStart,const std::size_t argCount)213 void RangeRegAllocator::Run(IRNode *const ins, VReg rangeStart, const std::size_t argCount)
214 {
215     ES2PANDA_ASSERT(Spiller().Restored());
216     const auto rangeEnd = rangeStart + argCount;
217 
218     std::array<VReg *, IRNode::MAX_REG_OPERAND> regs {};
219     ES2PANDA_ASSERT(ins != nullptr);
220     const auto regCnt = ins->Registers(&regs);
221     const auto registers = Span<VReg *>(regs.data(), regs.data() + regCnt);
222     if (RegIndicesValid(ins, registers).first) {
223         PushBack(ins);
224         return;
225     }
226 
227     const auto rs = Spiller().Start(GetCodeGen());
228 
229     auto regIter = registers.begin();
230     const auto regIterEnd = regIter + registers.size() - 1;  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
231 
232     while (regIter != regIterEnd) {
233         auto *const reg = *regIter;
234 
235         *reg = Spill(ins, *reg);
236         regIter++;  // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
237     }
238 
239     auto *const regStartReg = *regIter;
240     auto reg = rangeStart++;
241     *regStartReg = Spill(ins, reg);
242 
243     while (rangeStart != rangeEnd) {
244         reg = rangeStart++;
245         Spill(ins, reg);
246     }
247 
248     PushBack(ins);
249 
250     while (!Spiller().Restored()) {
251         Restore(ins);
252     }
253 
254     Spiller().Finalize();
255 }
256 }  // namespace ark::es2panda::compiler
257