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#ifndef ECMASCRIPT_COMPILER_CIRCUIT_BUILDER_HELPER_H
17#define ECMASCRIPT_COMPILER_CIRCUIT_BUILDER_HELPER_H
18
19#include "ecmascript/compiler/circuit_builder.h"
20
21namespace panda::ecmascript {
22    class JSRuntimeOptions;
23} // namespace panda::ecmascript
24
25namespace panda::ecmascript::kungfu {
26
27class CompilationConfig {
28public:
29    explicit CompilationConfig(const std::string &triple, const JSRuntimeOptions *options = nullptr);
30    ~CompilationConfig() = default;
31
32    inline bool Is32Bit() const
33    {
34        return triple_ == Triple::TRIPLE_ARM32;
35    }
36
37    inline bool IsAArch64() const
38    {
39        return triple_ == Triple::TRIPLE_AARCH64;
40    }
41
42    inline bool IsAmd64() const
43    {
44        return triple_ == Triple::TRIPLE_AMD64;
45    }
46
47    inline bool Is64Bit() const
48    {
49        return IsAArch64() || IsAmd64();
50    }
51
52    Triple GetTriple() const
53    {
54        return triple_;
55    }
56
57    std::string GetTripleStr() const
58    {
59        return tripleStr_;
60    }
61
62    bool IsTraceBC() const
63    {
64        return isTraceBc_;
65    }
66
67    bool IsProfiling() const
68    {
69        return profiling_;
70    }
71
72    bool IsStressDeopt() const
73    {
74        return stressDeopt_;
75    }
76
77    bool IsVerifyVTbale() const
78    {
79        return verifyVTable_;
80    }
81
82    bool IsTypedOpProfiling() const
83    {
84        return typedOpProfiling_;
85    }
86
87private:
88    inline Triple GetTripleFromString(const std::string &triple)
89    {
90        if (triple.compare(TARGET_X64) == 0) {
91            return Triple::TRIPLE_AMD64;
92        }
93
94        if (triple.compare(TARGET_AARCH64) == 0) {
95            return Triple::TRIPLE_AARCH64;
96        }
97
98        if (triple.compare(TARGET_ARM32) == 0) {
99            return Triple::TRIPLE_ARM32;
100        }
101        LOG_ECMA(FATAL) << "this branch is unreachable";
102        UNREACHABLE();
103    }
104    std::string tripleStr_;
105    Triple triple_;
106    bool isTraceBc_ {false};
107    bool profiling_ {false};
108    bool stressDeopt_ {false};
109    bool verifyVTable_ {false};
110    bool typedOpProfiling_ {false};
111};
112
113class Label {
114public:
115    Label() = default;
116    explicit Label(Environment *env);
117    explicit Label(CircuitBuilder *cirBuilder);
118    ~Label() = default;
119    Label(Label const &label) = default;
120    Label &operator=(Label const &label) = default;
121    Label(Label &&label) = default;
122    Label &operator=(Label &&label) = default;
123    inline void Seal()
124    {
125        return impl_->Seal();
126    }
127    inline void WriteVariable(Variable *var, GateRef value)
128    {
129        impl_->WriteVariable(var, value);
130    }
131    inline GateRef ReadVariable(Variable *var)
132    {
133        return impl_->ReadVariable(var);
134    }
135    inline void Bind()
136    {
137        impl_->Bind();
138    }
139    inline void MergeAllControl()
140    {
141        impl_->MergeAllControl();
142    }
143    inline void MergeAllDepend()
144    {
145        impl_->MergeAllDepend();
146    }
147    inline void AppendPredecessor(const Label *predecessor)
148    {
149        impl_->AppendPredecessor(predecessor->GetRawLabel());
150    }
151    inline std::vector<Label> GetPredecessors() const
152    {
153        std::vector<Label> labels;
154        for (auto rawlabel : impl_->GetPredecessors()) {
155            labels.emplace_back(Label(rawlabel));
156        }
157        return labels;
158    }
159    inline void SetControl(GateRef control)
160    {
161        impl_->SetControl(control);
162    }
163    inline void SetPreControl(GateRef control)
164    {
165        impl_->SetPreControl(control);
166    }
167    inline void MergeControl(GateRef control)
168    {
169        impl_->MergeControl(control);
170    }
171    inline GateRef GetControl() const
172    {
173        return impl_->GetControl();
174    }
175    inline GateRef GetDepend() const
176    {
177        return impl_->GetDepend();
178    }
179    inline void SetDepend(GateRef depend)
180    {
181        return impl_->SetDepend(depend);
182    }
183
184private:
185    class LabelImpl {
186    public:
187        LabelImpl(Environment *env, GateRef control)
188            : env_(env), control_(control), predeControl_(-1), isSealed_(false)
189        {
190        }
191        ~LabelImpl() = default;
192        NO_MOVE_SEMANTIC(LabelImpl);
193        NO_COPY_SEMANTIC(LabelImpl);
194        void Seal();
195        void WriteVariable(Variable *var, GateRef value);
196        GateRef ReadVariable(Variable *var);
197        void Bind();
198        void MergeAllControl();
199        void MergeAllDepend();
200        void AppendPredecessor(LabelImpl *predecessor);
201        std::vector<LabelImpl *> GetPredecessors() const
202        {
203            return predecessors_;
204        }
205        void SetControl(GateRef control)
206        {
207            control_ = control;
208        }
209        void SetPreControl(GateRef control)
210        {
211            predeControl_ = control;
212        }
213        void MergeControl(GateRef control)
214        {
215            if (predeControl_ == Circuit::NullGate()) {
216                predeControl_ = control;
217                control_ = predeControl_;
218            } else {
219                otherPredeControls_.push_back(control);
220            }
221        }
222        GateRef GetControl() const
223        {
224            return control_;
225        }
226        void SetDepend(GateRef depend)
227        {
228            depend_ = depend;
229        }
230        GateRef GetDepend() const
231        {
232            return depend_;
233        }
234
235    private:
236        bool IsNeedSeal() const;
237        bool IsSealed() const
238        {
239            return isSealed_;
240        }
241        bool IsLoopHead() const;
242        bool IsControlCase() const;
243        GateRef ReadVariableRecursive(Variable *var);
244        Environment *env_;
245        GateRef control_;
246        GateRef predeControl_ {Circuit::NullGate()};
247        GateRef depend_ {Circuit::NullGate()};
248        GateRef loopDepend_ {Circuit::NullGate()};
249        std::vector<GateRef> otherPredeControls_;
250        bool isSealed_ {false};
251        std::map<Variable *, GateRef> valueMap_;
252        std::vector<GateRef> phi;
253        std::vector<LabelImpl *> predecessors_;
254        std::map<Variable *, GateRef> incompletePhis_;
255    };
256
257    explicit Label(LabelImpl *impl) : impl_(impl) {}
258    friend class Environment;
259    LabelImpl *GetRawLabel() const
260    {
261        return impl_;
262    }
263    LabelImpl *impl_ {nullptr};
264};
265
266class Environment {
267public:
268    using LabelImpl = Label::LabelImpl;
269    Environment(GateRef hir, Circuit *circuit, CircuitBuilder *builder);
270    Environment(GateRef stateEntry, GateRef dependEntry, const std::initializer_list<GateRef>& args,
271                Circuit *circuit, CircuitBuilder *builder);
272    Environment(size_t arguments, CircuitBuilder *builder);
273    ~Environment();
274    Label *GetCurrentLabel() const
275    {
276        return currentLabel_;
277    }
278    void SetCurrentLabel(Label *label)
279    {
280        currentLabel_ = label;
281    }
282    CircuitBuilder *GetBuilder() const
283    {
284        return circuitBuilder_;
285    }
286    Circuit *GetCircuit() const
287    {
288        return circuit_;
289    }
290    int NextVariableId()
291    {
292        return nextVariableId_++;
293    }
294    void SetCompilationConfig(const CompilationConfig *cfg)
295    {
296        ccfg_ = cfg;
297    }
298    const CompilationConfig *GetCompilationConfig() const
299    {
300        return ccfg_;
301    }
302    inline bool Is32Bit() const
303    {
304        return ccfg_->Is32Bit();
305    }
306    inline bool IsAArch64() const
307    {
308        return ccfg_->IsAArch64();
309    }
310    inline bool IsAmd64() const
311    {
312        return ccfg_->IsAmd64();
313    }
314    inline bool IsArch64Bit() const
315    {
316        return ccfg_->IsAmd64() ||  ccfg_->IsAArch64();
317    }
318    inline bool IsAsmInterp() const
319    {
320        return circuit_->GetFrameType() == FrameType::ASM_INTERPRETER_FRAME;
321    }
322    inline bool IsBaselineBuiltin() const
323    {
324        return circuit_->GetFrameType() == FrameType::BASELINE_BUILTIN_FRAME;
325    }
326    inline bool IsArch32Bit() const
327    {
328        return ccfg_->Is32Bit();
329    }
330    inline GateRef GetArgument(size_t index) const
331    {
332        return arguments_.at(index);
333    }
334    inline Label GetLabelFromSelector(GateRef sel)
335    {
336        Label::LabelImpl *rawlabel = phiToLabels_[sel];
337        return Label(rawlabel);
338    }
339    inline void AddSelectorToLabel(GateRef sel, Label label)
340    {
341        phiToLabels_[sel] = label.GetRawLabel();
342    }
343    inline LabelImpl *NewLabel(Environment *env, GateRef control = -1)
344    {
345        auto impl = new Label::LabelImpl(env, control);
346        rawLabels_.emplace_back(impl);
347        return impl;
348    }
349    void SubCfgEntry(Label *entry)
350    {
351        if (currentLabel_ != nullptr) {
352            GateRef control = currentLabel_->GetControl();
353            GateRef depend = currentLabel_->GetDepend();
354            stack_.push(currentLabel_);
355            currentLabel_ = entry;
356            currentLabel_->SetControl(control);
357            currentLabel_->SetDepend(depend);
358        }
359    }
360    void SubCfgExit()
361    {
362        if (currentLabel_ != nullptr) {
363            GateRef control = currentLabel_->GetControl();
364            GateRef depend = currentLabel_->GetDepend();
365            if (!stack_.empty()) {
366                currentLabel_ = stack_.top();
367                currentLabel_->SetControl(control);
368                currentLabel_->SetDepend(depend);
369                stack_.pop();
370            }
371        }
372    }
373    inline GateRef GetInput(size_t index) const
374    {
375        return inputList_.at(index);
376    }
377
378private:
379    Label *currentLabel_ {nullptr};
380    Circuit *circuit_ {nullptr};
381    CircuitBuilder *circuitBuilder_ {nullptr};
382    std::unordered_map<GateRef, LabelImpl *> phiToLabels_;
383    std::vector<GateRef> inputList_;
384    Label entry_;
385    std::vector<LabelImpl *> rawLabels_;
386    std::stack<Label *> stack_;
387    int nextVariableId_ {0};
388    std::vector<GateRef> arguments_;
389    const CompilationConfig *ccfg_ {nullptr};
390};
391
392class Variable {
393public:
394    Variable(Environment *env, VariableType type, uint32_t id, GateRef value) : id_(id), type_(type), env_(env)
395    {
396        Bind(value);
397        env_->GetCurrentLabel()->WriteVariable(this, value);
398    }
399    Variable(CircuitBuilder *cirbuilder, VariableType type, uint32_t id, GateRef value)
400        : id_(id), type_(type), env_(cirbuilder->GetCurrentEnvironment())
401    {
402        Bind(value);
403        env_->GetCurrentLabel()->WriteVariable(this, value);
404    }
405    ~Variable() = default;
406    NO_MOVE_SEMANTIC(Variable);
407    NO_COPY_SEMANTIC(Variable);
408    void Bind(GateRef value)
409    {
410        currentValue_ = value;
411    }
412    GateRef Value() const
413    {
414        return currentValue_;
415    }
416    VariableType Type() const
417    {
418        return type_;
419    }
420    bool IsBound() const
421    {
422        return currentValue_ != 0;
423    }
424    Variable &operator=(const GateRef value)
425    {
426        env_->GetCurrentLabel()->WriteVariable(this, value);
427        Bind(value);
428        return *this;
429    }
430    GateRef operator*()
431    {
432        return env_->GetCurrentLabel()->ReadVariable(this);
433    }
434    GateRef ReadVariable()
435    {
436        return env_->GetCurrentLabel()->ReadVariable(this);
437    }
438    void WriteVariable(GateRef value)
439    {
440        env_->GetCurrentLabel()->WriteVariable(this, value);
441        Bind(value);
442    }
443    GateRef AddPhiOperand(GateRef val);
444    GateRef AddOperandToSelector(GateRef val, size_t idx, GateRef in);
445    GateRef TryRemoveTrivialPhi(GateRef phi);
446    uint32_t GetId() const
447    {
448        return id_;
449    }
450
451private:
452    Circuit* GetCircuit() const
453    {
454        return env_->GetCircuit();
455    }
456
457    uint32_t id_;
458    VariableType type_;
459    GateRef currentValue_ {0};
460    Environment *env_;
461};
462
463}
464
465#endif  // ECMASCRIPT_COMPILER_CIRCUIT_BUILDER_H
466