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