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 "regAllocator.h"
17
18 #include <compiler/core/pandagen.h>
19
20 #include <algorithm>
21
22 namespace panda::es2panda::compiler {
23
24 // FrontAllocator
25
FrontAllocator(PandaGen * pg)26 FrontAllocator::FrontAllocator(PandaGen *pg)
27 : pg_(pg), insn_(std::move(pg_->Insns()), pg_->Allocator()->Adapter())
28 {
29 }
30
~FrontAllocator()31 FrontAllocator::~FrontAllocator()
32 {
33 pg_->Insns().splice(pg_->Insns().end(), std::move(insn_));
34 }
35
36 // RegAllocator
37
PushBack(IRNode * ins)38 void RegAllocator::PushBack(IRNode *ins)
39 {
40 pg_->Insns().push_back(ins);
41 }
42
Allocator() const43 ArenaAllocator *RegAllocator::Allocator() const
44 {
45 return pg_->Allocator();
46 }
47
HasSpill() const48 bool RegAllocator::HasSpill() const
49 {
50 return hasSpill_;
51 }
52
GetSpillRegsCount() const53 uint16_t RegAllocator::GetSpillRegsCount() const
54 {
55 return spillRegs_;
56 }
57
UpdateIcSlot(IRNode * node)58 void RegAllocator::UpdateIcSlot(IRNode *node)
59 {
60 auto inc = node->SetIcSlot(pg_->GetCurrentSlot());
61 if (node->InlineCacheEnabled() && (inc == 0) && !pg_->IsIcOverFlow()) {
62 pg_->SetIcOverFlow();
63 }
64 pg_->IncreaseCurrentSlot(inc);
65 }
66
AllocLabel(std::string && id)67 Label *RegAllocator::AllocLabel(std::string &&id)
68 {
69 const auto *lastInsNode = pg_->Insns().empty() ? FIRST_NODE_OF_FUNCTION : pg_->Insns().back()->Node();
70 return Alloc<Label>(lastInsNode, std::move(id));
71 }
72
Run(IRNode * ins,int64_t typeIndex)73 void RegAllocator::Run(IRNode *ins, int64_t typeIndex)
74 {
75 Run(ins);
76 pg_->TypedInsns()[ins] = typeIndex;
77 }
78
Run(IRNode * ins)79 void RegAllocator::Run(IRNode *ins)
80 {
81 std::array<VReg *, IRNode::MAX_REG_OPERAND> regs {};
82 auto regCnt = ins->Registers(®s);
83 if (regCnt == 0) {
84 return PushBack(ins);
85 }
86
87 auto registers = Span<VReg *>(regs.data(), regs.data() + regCnt);
88 spillRegs_ = std::max(spillRegs_, static_cast<uint16_t>(regCnt));
89
90 if (!CheckRegIndices(ins, registers)) {
91 hasSpill_ = true;
92 }
93
94 PushBack(ins);
95 }
96
Run(IRNode * ins,size_t argCount)97 void RegAllocator::Run(IRNode *ins, size_t argCount)
98 {
99 std::array<VReg *, IRNode::MAX_REG_OPERAND> regs {};
100 auto regCnt = ins->Registers(®s);
101 ASSERT(regCnt != 0);
102 auto registers = Span<VReg *>(regs.data(), regs.data() + regCnt);
103 spillRegs_ = std::max(spillRegs_, static_cast<uint16_t>(argCount + regCnt - 1));
104
105 if (!CheckRegIndices(ins, registers)) {
106 hasSpill_ = true;
107 }
108
109 PushBack(ins);
110 }
111
AdjustInsRegWhenHasSpill()112 void RegAllocator::AdjustInsRegWhenHasSpill()
113 {
114 if (!hasSpill_) {
115 spillRegs_ = 0;
116 return;
117 }
118
119 if ((spillRegs_ + pg_->TotalRegsNum()) > UINT16_MAX) {
120 throw Error(ErrorType::GENERIC, "Can't adjust spill insns when regs run out");
121 }
122
123 ArenaList<IRNode *> newInsns(Allocator()->Adapter());
124 auto &insns = pg_->Insns();
125 for (auto it = insns.begin(); it != insns.end(); ++it) {
126 IRNode *ins = *it;
127 std::vector<OperandKind> regsKind;
128 std::array<VReg *, IRNode::MAX_REG_OPERAND> regs {};
129 auto regCnt = ins->Registers(®s);
130 if (regCnt == 0) {
131 newInsns.push_back(ins);
132 continue;
133 }
134
135 auto registers = Span<VReg *>(regs.data(), regs.data() + regCnt);
136 for (auto *reg : registers) {
137 *reg = *reg + spillRegs_;
138 }
139
140 if (CheckRegIndices(ins, registers, ®sKind)) {
141 // current ins has no spill, continue iterating
142 newInsns.push_back(ins);
143 continue;
144 }
145
146 // current ins has spill
147 if (ins->IsRangeInst()) {
148 AdjustRangeInsSpill(registers, ins, newInsns);
149 continue;
150 }
151
152 AdjustInsSpill(registers, ins, newInsns, regsKind);
153 }
154 pg_->SetInsns(newInsns);
155 }
156
AdjustInsSpill(const Span<VReg * > & registers,IRNode * ins,ArenaList<IRNode * > & newInsns,const std::vector<OperandKind> & regsKind)157 void RegAllocator::AdjustInsSpill(const Span<VReg *> ®isters, IRNode *ins, ArenaList<IRNode *> &newInsns,
158 const std::vector<OperandKind> ®sKind)
159 {
160 ASSERT(spillIndex_ == 0);
161 ASSERT(!regsKind.empty());
162 int idx = 0;
163 for (auto *reg : registers) {
164 if (IsRegisterCorrect(reg)) {
165 idx++;
166 continue;
167 }
168
169 const auto originReg = *reg;
170 VReg spillReg = spillIndex_;
171 if (regsKind[idx] == OperandKind::SRC_VREG || regsKind[idx] == OperandKind::SRC_DST_VREG) {
172 Add<Mov>(newInsns, ins->Node(), spillReg, originReg);
173 }
174 if (regsKind[idx] == OperandKind::DST_VREG || regsKind[idx] == OperandKind::SRC_DST_VREG) {
175 dstRegSpills_.push_back(std::make_pair(originReg, spillReg));
176 }
177 *reg = spillIndex_++;
178 idx++;
179 }
180
181 newInsns.push_back(ins);
182
183 for (auto spillPair : dstRegSpills_) {
184 Add<Mov>(newInsns, ins->Node(), spillPair.first, spillPair.second);
185 }
186
187 FreeSpill();
188 dstRegSpills_.clear();
189 }
190
AdjustRangeInsSpill(Span<VReg * > & registers,IRNode * ins,ArenaList<IRNode * > & newInsns)191 void RegAllocator::AdjustRangeInsSpill(Span<VReg *> ®isters, IRNode *ins, ArenaList<IRNode *> &newInsns)
192 {
193 ASSERT(spillIndex_ == 0);
194 ASSERT(ins->IsRangeInst());
195 auto rangeRegCount = ins->RangeRegsCount();
196 auto *iter = registers.begin();
197 auto *rangeStartIter = iter + registers.size() - 1;
198
199 while (iter != rangeStartIter) {
200 VReg *reg = *iter;
201 Add<Mov>(newInsns, ins->Node(), spillIndex_, *reg);
202 *reg = spillIndex_++;
203 iter++;
204 }
205
206 VReg *rangeStartReg = *rangeStartIter;
207 auto originReg = *rangeStartReg;
208 *rangeStartReg = spillIndex_;
209
210 while (rangeRegCount--) {
211 Add<Mov>(newInsns, ins->Node(), spillIndex_++, originReg++);
212 }
213
214 newInsns.push_back(ins);
215 FreeSpill();
216 }
217
218 } // namespace panda::es2panda::compiler
219