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 
21 namespace panda::ecmascript {
22     class JSRuntimeOptions;
23 } // namespace panda::ecmascript
24 
25 namespace panda::ecmascript::kungfu {
26 
27 class CompilationConfig {
28 public:
29     explicit CompilationConfig(const std::string &triple, const JSRuntimeOptions *options = nullptr);
30     ~CompilationConfig() = default;
31 
Is32Bit() const32     inline bool Is32Bit() const
33     {
34         return triple_ == Triple::TRIPLE_ARM32;
35     }
36 
IsAArch64() const37     inline bool IsAArch64() const
38     {
39         return triple_ == Triple::TRIPLE_AARCH64;
40     }
41 
IsAmd64() const42     inline bool IsAmd64() const
43     {
44         return triple_ == Triple::TRIPLE_AMD64;
45     }
46 
Is64Bit() const47     inline bool Is64Bit() const
48     {
49         return IsAArch64() || IsAmd64();
50     }
51 
GetTriple() const52     Triple GetTriple() const
53     {
54         return triple_;
55     }
56 
GetTripleStr() const57     std::string GetTripleStr() const
58     {
59         return tripleStr_;
60     }
61 
IsTraceBC() const62     bool IsTraceBC() const
63     {
64         return isTraceBc_;
65     }
66 
IsProfiling() const67     bool IsProfiling() const
68     {
69         return profiling_;
70     }
71 
IsStressDeopt() const72     bool IsStressDeopt() const
73     {
74         return stressDeopt_;
75     }
76 
IsVerifyVTbale() const77     bool IsVerifyVTbale() const
78     {
79         return verifyVTable_;
80     }
81 
IsTypedOpProfiling() const82     bool IsTypedOpProfiling() const
83     {
84         return typedOpProfiling_;
85     }
86 
87 private:
GetTripleFromString(const std::string &triple)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 
113 class Label {
114 public:
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;
Seal()123     inline void Seal()
124     {
125         return impl_->Seal();
126     }
WriteVariable(Variable *var, GateRef value)127     inline void WriteVariable(Variable *var, GateRef value)
128     {
129         impl_->WriteVariable(var, value);
130     }
ReadVariable(Variable *var)131     inline GateRef ReadVariable(Variable *var)
132     {
133         return impl_->ReadVariable(var);
134     }
Bind()135     inline void Bind()
136     {
137         impl_->Bind();
138     }
MergeAllControl()139     inline void MergeAllControl()
140     {
141         impl_->MergeAllControl();
142     }
MergeAllDepend()143     inline void MergeAllDepend()
144     {
145         impl_->MergeAllDepend();
146     }
AppendPredecessor(const Label *predecessor)147     inline void AppendPredecessor(const Label *predecessor)
148     {
149         impl_->AppendPredecessor(predecessor->GetRawLabel());
150     }
GetPredecessors() const151     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     }
SetControl(GateRef control)159     inline void SetControl(GateRef control)
160     {
161         impl_->SetControl(control);
162     }
SetPreControl(GateRef control)163     inline void SetPreControl(GateRef control)
164     {
165         impl_->SetPreControl(control);
166     }
MergeControl(GateRef control)167     inline void MergeControl(GateRef control)
168     {
169         impl_->MergeControl(control);
170     }
GetControl() const171     inline GateRef GetControl() const
172     {
173         return impl_->GetControl();
174     }
GetDepend() const175     inline GateRef GetDepend() const
176     {
177         return impl_->GetDepend();
178     }
SetDepend(GateRef depend)179     inline void SetDepend(GateRef depend)
180     {
181         return impl_->SetDepend(depend);
182     }
183 
184 private:
185     class LabelImpl {
186     public:
LabelImpl(Environment *env, GateRef control)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);
GetPredecessors() const201         std::vector<LabelImpl *> GetPredecessors() const
202         {
203             return predecessors_;
204         }
SetControl(GateRef control)205         void SetControl(GateRef control)
206         {
207             control_ = control;
208         }
SetPreControl(GateRef control)209         void SetPreControl(GateRef control)
210         {
211             predeControl_ = control;
212         }
MergeControl(GateRef control)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         }
GetControl() const222         GateRef GetControl() const
223         {
224             return control_;
225         }
SetDepend(GateRef depend)226         void SetDepend(GateRef depend)
227         {
228             depend_ = depend;
229         }
GetDepend() const230         GateRef GetDepend() const
231         {
232             return depend_;
233         }
234 
235     private:
236         bool IsNeedSeal() const;
IsSealed() const237         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 
Label(LabelImpl *impl)257     explicit Label(LabelImpl *impl) : impl_(impl) {}
258     friend class Environment;
GetRawLabel() const259     LabelImpl *GetRawLabel() const
260     {
261         return impl_;
262     }
263     LabelImpl *impl_ {nullptr};
264 };
265 
266 class Environment {
267 public:
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();
GetCurrentLabel() const274     Label *GetCurrentLabel() const
275     {
276         return currentLabel_;
277     }
SetCurrentLabel(Label *label)278     void SetCurrentLabel(Label *label)
279     {
280         currentLabel_ = label;
281     }
GetBuilder() const282     CircuitBuilder *GetBuilder() const
283     {
284         return circuitBuilder_;
285     }
GetCircuit() const286     Circuit *GetCircuit() const
287     {
288         return circuit_;
289     }
NextVariableId()290     int NextVariableId()
291     {
292         return nextVariableId_++;
293     }
SetCompilationConfig(const CompilationConfig *cfg)294     void SetCompilationConfig(const CompilationConfig *cfg)
295     {
296         ccfg_ = cfg;
297     }
GetCompilationConfig() const298     const CompilationConfig *GetCompilationConfig() const
299     {
300         return ccfg_;
301     }
Is32Bit() const302     inline bool Is32Bit() const
303     {
304         return ccfg_->Is32Bit();
305     }
IsAArch64() const306     inline bool IsAArch64() const
307     {
308         return ccfg_->IsAArch64();
309     }
IsAmd64() const310     inline bool IsAmd64() const
311     {
312         return ccfg_->IsAmd64();
313     }
IsArch64Bit() const314     inline bool IsArch64Bit() const
315     {
316         return ccfg_->IsAmd64() ||  ccfg_->IsAArch64();
317     }
IsAsmInterp() const318     inline bool IsAsmInterp() const
319     {
320         return circuit_->GetFrameType() == FrameType::ASM_INTERPRETER_FRAME;
321     }
IsBaselineBuiltin() const322     inline bool IsBaselineBuiltin() const
323     {
324         return circuit_->GetFrameType() == FrameType::BASELINE_BUILTIN_FRAME;
325     }
IsArch32Bit() const326     inline bool IsArch32Bit() const
327     {
328         return ccfg_->Is32Bit();
329     }
GetArgument(size_t index) const330     inline GateRef GetArgument(size_t index) const
331     {
332         return arguments_.at(index);
333     }
GetLabelFromSelector(GateRef sel)334     inline Label GetLabelFromSelector(GateRef sel)
335     {
336         Label::LabelImpl *rawlabel = phiToLabels_[sel];
337         return Label(rawlabel);
338     }
AddSelectorToLabel(GateRef sel, Label label)339     inline void AddSelectorToLabel(GateRef sel, Label label)
340     {
341         phiToLabels_[sel] = label.GetRawLabel();
342     }
NewLabel(Environment *env, GateRef control = -1)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     }
SubCfgEntry(Label *entry)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     }
SubCfgExit()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     }
GetInput(size_t index) const373     inline GateRef GetInput(size_t index) const
374     {
375         return inputList_.at(index);
376     }
377 
378 private:
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 
392 class Variable {
393 public:
Variable(Environment *env, VariableType type, uint32_t id, GateRef value)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     }
Variable(CircuitBuilder *cirbuilder, VariableType type, uint32_t id, GateRef value)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);
Bind(GateRef value)408     void Bind(GateRef value)
409     {
410         currentValue_ = value;
411     }
Value() const412     GateRef Value() const
413     {
414         return currentValue_;
415     }
Type() const416     VariableType Type() const
417     {
418         return type_;
419     }
IsBound() const420     bool IsBound() const
421     {
422         return currentValue_ != 0;
423     }
operator =(const GateRef value)424     Variable &operator=(const GateRef value)
425     {
426         env_->GetCurrentLabel()->WriteVariable(this, value);
427         Bind(value);
428         return *this;
429     }
operator *()430     GateRef operator*()
431     {
432         return env_->GetCurrentLabel()->ReadVariable(this);
433     }
ReadVariable()434     GateRef ReadVariable()
435     {
436         return env_->GetCurrentLabel()->ReadVariable(this);
437     }
WriteVariable(GateRef value)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);
GetId() const446     uint32_t GetId() const
447     {
448         return id_;
449     }
450 
451 private:
GetCircuit() const452     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