• 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 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(&regs);
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(&regs);
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(&regs);
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, &regsKind)) {
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 *> &registers, IRNode *ins, ArenaList<IRNode *> &newInsns,
154                                   const std::vector<OperandKind> &regsKind)
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 *> &registers, 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