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