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