1/*
2 * Copyright (c) 2021 - 2023 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 "regSpiller.h"
17#include "compiler/core/codeGen.h"
18#include "checker/types/type.h"
19
20namespace ark::es2panda::compiler {
21
22CodeGen *RegSpiller::GetCodeGen() const noexcept
23{
24    return cg_;
25}
26
27std::pair<RegSpiller::SpillInfo, const checker::Type *> RegSpiller::New() noexcept
28{
29    const VReg origin {VReg::REG_START - spillIndex_++};
30    const auto *const originType = cg_->GetVRegType(origin);
31    const SpillInfo spillInfo {origin, cg_->AllocRegWithType(originType)};
32    return std::make_pair(spillInfo, originType);
33}
34
35void RegSpiller::Adjust(const std::unordered_set<VReg> &regs) noexcept
36{
37    while (true) {
38        const VReg origin {VReg::REG_START - spillIndex_};
39
40        if (regs.count(origin) == 0) {
41            break;
42        }
43
44        ++spillIndex_;
45    }
46}
47
48void RegSpiller::SetCodeGen(CodeGen &cg) noexcept
49{
50    cg_ = &cg;
51}
52
53std::uint32_t RegSpiller::SpillIndex() const noexcept
54{
55    return spillIndex_;
56}
57
58std::uint32_t &RegSpiller::SpillIndex() noexcept
59{
60    return spillIndex_;
61}
62
63RegScope DynamicRegSpiller::Start(CodeGen &cg)
64{
65    SetCodeGen(cg);
66    regEnd_ = GetCodeGen()->NextReg().GetIndex();
67    return RegScope {&cg};
68}
69
70RegSpiller::SpillInfo DynamicRegSpiller::Restore()
71{
72    const auto newSpillIndex = --SpillIndex();
73    return RegSpiller::SpillInfo(VReg {VReg::REG_START - newSpillIndex}, VReg {regEnd_ - SpillIndex()});
74}
75
76bool DynamicRegSpiller::Restored() const
77{
78    return SpillIndex() == 0;
79}
80
81IRNode *DynamicRegSpiller::MoveReg(const ir::AstNode *const node, const VReg vd, const VReg vs,
82                                   [[maybe_unused]] const bool spillMov)
83{
84    return GetCodeGen()->AllocMov(node, vd, vs);
85}
86
87void DynamicRegSpiller::Finalize() noexcept
88{
89    ASSERT(SpillIndex() == 0);
90}
91
92RegScope StaticRegSpiller::Start(CodeGen &cg)
93{
94    SetCodeGen(cg);
95    return RegScope {&cg};
96}
97
98RegSpiller::SpillInfo StaticRegSpiller::Restore()
99{
100    ASSERT(spills_.size() <= VReg::REG_START);
101    ASSERT(!spills_.empty());
102    const auto last = spills_.back().Reversed();
103    spills_.pop_back();
104    return last;
105}
106
107bool StaticRegSpiller::Restored() const
108{
109    return spills_.empty();
110}
111
112IRNode *StaticRegSpiller::MoveReg(const ir::AstNode *const node, const VReg vd, const VReg vs, const bool spillMov)
113{
114    if (vd == vs) {
115        return nullptr;
116    }
117
118    const auto *const sourceType = GetCodeGen()->GetVRegType(vs);
119    if (sourceType == nullptr) {
120        return nullptr;
121    }
122
123    GetCodeGen()->SetVRegType(vd, sourceType);
124    if (spillMov) {
125        spills_.emplace_back(vd, vs);
126    }
127
128    return GetCodeGen()->AllocMov(node, vd, vs);
129}
130
131void StaticRegSpiller::Finalize() noexcept
132{
133    SpillIndex() = 0;
134}
135
136}  // namespace ark::es2panda::compiler
137