1/*
2 * Copyright (c) 2021-2024 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 "ecmascript/compiler/circuit_builder_helper.h"
17#include "ecmascript/js_runtime_options.h"
18
19namespace panda::ecmascript::kungfu {
20
21CompilationConfig::CompilationConfig(const std::string &triple, const JSRuntimeOptions *options)
22    : tripleStr_(triple), triple_(GetTripleFromString(triple))
23{
24    if (options != nullptr) {
25        isTraceBc_ = options->IsTraceBC();
26        profiling_ = options->GetOptCodeProfiler();
27        stressDeopt_ = options->GetStressDeopt();
28        verifyVTable_ = options->GetVerifyVTable();
29        typedOpProfiling_ = options->GetTypedOpProfiler();
30    }
31}
32
33Environment::Environment(size_t arguments, CircuitBuilder *builder)
34    : circuit_(builder->GetCircuit()), circuitBuilder_(builder), arguments_(arguments)
35{
36    circuitBuilder_->SetEnvironment(this);
37    SetCompilationConfig(circuitBuilder_->GetCompilationConfig());
38    for (size_t i = 0; i < arguments; i++) {
39        arguments_[i] = circuitBuilder_->Arguments(i);
40    }
41    entry_ = Label(NewLabel(this, circuit_->GetStateRoot()));
42    currentLabel_ = &entry_;
43    currentLabel_->Seal();
44    auto depend_entry = circuit_->GetDependRoot();
45    currentLabel_->SetDepend(depend_entry);
46}
47
48Environment::Environment(GateRef hir, Circuit *circuit, CircuitBuilder *builder)
49    : circuit_(circuit), circuitBuilder_(builder)
50{
51    circuitBuilder_->SetEnvironment(this);
52    SetCompilationConfig(circuitBuilder_->GetCompilationConfig());
53    GateAccessor acc(circuit);
54    entry_ = Label(NewLabel(this, acc.GetIn(hir, 0)));
55    currentLabel_ = &entry_;
56    currentLabel_->Seal();
57    auto dependEntry = acc.GetDep(hir);
58    currentLabel_->SetDepend(dependEntry);
59    for (size_t i = 2; i < acc.GetNumIns(hir); i++) {
60        inputList_.emplace_back(acc.GetIn(hir, i));
61    }
62}
63
64Environment::Environment(GateRef stateEntry, GateRef dependEntry,
65    const std::initializer_list<GateRef>& args, Circuit *circuit, CircuitBuilder *builder)
66    : circuit_(circuit), circuitBuilder_(builder)
67{
68    circuitBuilder_->SetEnvironment(this);
69    SetCompilationConfig(circuitBuilder_->GetCompilationConfig());
70    entry_ = Label(NewLabel(this, stateEntry));
71    currentLabel_ = &entry_;
72    currentLabel_->Seal();
73    currentLabel_->SetDepend(dependEntry);
74    for (auto in : args) {
75        inputList_.emplace_back(in);
76    }
77}
78
79Environment::~Environment()
80{
81    circuitBuilder_->SetEnvironment(nullptr);
82    for (auto label : rawLabels_) {
83        delete label;
84    }
85}
86
87Label::Label(Environment *env)
88{
89    ASSERT(env != nullptr);
90    impl_ = env->NewLabel(env);
91}
92
93Label::Label(CircuitBuilder *cirBuilder)
94{
95    ASSERT(cirBuilder != nullptr);
96    auto env = cirBuilder->GetCurrentEnvironment();
97    ASSERT(env != nullptr);
98    impl_ = env->NewLabel(env);
99}
100
101void Label::LabelImpl::Seal()
102{
103    for (auto &[variable, gate] : incompletePhis_) {
104        variable->AddPhiOperand(gate);
105    }
106    isSealed_ = true;
107}
108
109void Label::LabelImpl::WriteVariable(Variable *var, GateRef value)
110{
111    valueMap_[var] = value;
112}
113
114GateRef Label::LabelImpl::ReadVariable(Variable *var)
115{
116    if (valueMap_.find(var) != valueMap_.end()) {
117        auto result = valueMap_.at(var);
118        GateAccessor acc(env_->GetCircuit());
119        if (!acc.IsNop(result)) {
120            return result;
121        }
122    }
123    return ReadVariableRecursive(var);
124}
125
126GateRef Label::LabelImpl::ReadVariableRecursive(Variable *var)
127{
128    GateRef val;
129    MachineType machineType = CircuitBuilder::GetMachineTypeFromVariableType(var->Type());
130    if (!IsSealed()) {
131        // only loopheader gate will be not sealed
132        int valueCounts = static_cast<int>(this->predecessors_.size()) + 1;
133        if (machineType == MachineType::NOVALUE) {
134            val = env_->GetBuilder()->Selector(OpCode::DEPEND_SELECTOR,
135                predeControl_, {}, valueCounts, var->Type());
136        } else {
137            val = env_->GetBuilder()->Selector(OpCode::VALUE_SELECTOR,
138                machineType, predeControl_, {}, valueCounts, var->Type());
139        }
140        env_->AddSelectorToLabel(val, Label(this));
141        incompletePhis_[var] = val;
142    } else if (predecessors_.size() == 1) {
143        val = predecessors_[0]->ReadVariable(var);
144    } else {
145        if (machineType == MachineType::NOVALUE) {
146            val = env_->GetBuilder()->Selector(OpCode::DEPEND_SELECTOR,
147                predeControl_, {}, this->predecessors_.size(), var->Type());
148        } else {
149            val = env_->GetBuilder()->Selector(OpCode::VALUE_SELECTOR, machineType,
150                predeControl_, {}, this->predecessors_.size(), var->Type());
151        }
152        env_->AddSelectorToLabel(val, Label(this));
153        WriteVariable(var, val);
154        val = var->AddPhiOperand(val);
155    }
156    WriteVariable(var, val);
157    return val;
158}
159
160void Label::LabelImpl::Bind()
161{
162    ASSERT(!predecessors_.empty());
163    if (IsLoopHead()) {
164        // 2 means input number of depend selector gate
165        loopDepend_ = env_->GetBuilder()->Selector(OpCode::DEPEND_SELECTOR, predeControl_, {}, 2);
166        GateAccessor(env_->GetCircuit()).NewIn(loopDepend_, 1, predecessors_[0]->GetDepend());
167        depend_ = loopDepend_;
168    }
169    if (IsNeedSeal()) {
170        Seal();
171        MergeAllControl();
172        MergeAllDepend();
173    }
174}
175
176void Label::LabelImpl::MergeAllControl()
177{
178    if (predecessors_.size() < 2) {  // 2 : Loop Head only support two predecessors_
179        return;
180    }
181
182    if (IsLoopHead()) {
183        ASSERT(predecessors_.size() == 2);  // 2 : Loop Head only support two predecessors_
184        ASSERT(otherPredeControls_.size() == 1);
185        GateAccessor(env_->GetCircuit()).NewIn(predeControl_, 1, otherPredeControls_[0]);
186        return;
187    }
188
189    // merge all control of predecessors_
190    std::vector<GateRef> inGates(predecessors_.size());
191    size_t i = 0;
192    ASSERT(predeControl_ != -1);
193    ASSERT((otherPredeControls_.size() + 1) == predecessors_.size());
194    inGates[i++] = predeControl_;
195    for (auto in : otherPredeControls_) {
196        inGates[i++] = in;
197    }
198
199    GateRef merge = env_->GetBuilder()->Merge(inGates);
200    predeControl_ = merge;
201    control_ = merge;
202}
203
204void Label::LabelImpl::MergeAllDepend()
205{
206    if (predecessors_.size() < 2) {  // 2 : Loop Head only support two predecessors_
207        depend_ = predecessors_[0]->GetDepend();
208        if (IsControlCase()) {
209            // Add depend_relay to current label
210            depend_ = env_->GetBuilder()->DependRelay(predeControl_, depend_);
211        }
212        return;
213    }
214    if (IsLoopHead()) {
215        ASSERT(predecessors_.size() == 2);  // 2 : Loop Head only support two predecessors_
216        // Add loop depend to in of depend_seclector
217        ASSERT(loopDepend_ != -1);
218        // 2 mean 3rd input gate for loopDepend_(depend_selector)
219        GateAccessor(env_->GetCircuit()).NewIn(loopDepend_, 2, predecessors_[1]->GetDepend());
220        return;
221    }
222
223    //  Merge all depends to depend_seclector
224    std::vector<GateRef> dependsList;
225    for (auto prede : this->GetPredecessors()) {
226        dependsList.push_back(prede->GetDepend());
227    }
228    depend_ = env_->GetBuilder()->Selector(OpCode::DEPEND_SELECTOR,
229        predeControl_, dependsList, dependsList.size());
230}
231
232void Label::LabelImpl::AppendPredecessor(Label::LabelImpl *predecessor)
233{
234    if (predecessor != nullptr) {
235        predecessors_.push_back(predecessor);
236    }
237}
238
239bool Label::LabelImpl::IsNeedSeal() const
240{
241    auto stateCount = GateAccessor(env_->GetCircuit()).GetStateCount(predeControl_);
242    return predecessors_.size() >= stateCount;
243}
244
245bool Label::LabelImpl::IsLoopHead() const
246{
247    return GateAccessor(env_->GetCircuit()).IsLoopHead(predeControl_);
248}
249
250bool Label::LabelImpl::IsControlCase() const
251{
252    return GateAccessor(env_->GetCircuit()).IsControlCase(predeControl_);
253}
254}