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