• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&regs);
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(&regs);
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(&regs);
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, &regsKind)) {
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 *> &registers, IRNode *ins, ArenaList<IRNode *> &newInsns,
158                                   const std::vector<OperandKind> &regsKind)
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 *> &registers, 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