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