/* * Copyright (c) 2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ECMASCRIPT_COMPILER_CIRCUIT_BUILDER_HELPER_H #define ECMASCRIPT_COMPILER_CIRCUIT_BUILDER_HELPER_H #include "ecmascript/compiler/circuit_builder.h" #include "ecmascript/mem/region.h" #include "ecmascript/method.h" namespace panda::ecmascript::kungfu { class CompilationConfig { public: explicit CompilationConfig(const std::string &triple, const JSRuntimeOptions *options = nullptr) : tripleStr_(triple), triple_(GetTripleFromString(triple)) { if (options != nullptr) { isTraceBc_ = options->IsTraceBC(); profiling_ = options->GetOptCodeProfiler(); stressDeopt_ = options->GetStressDeopt(); verifyVTable_ = options->GetVerifyVTable(); typedOpProfiling_ = options->GetTypedOpProfiler(); } } ~CompilationConfig() = default; inline bool Is32Bit() const { return triple_ == Triple::TRIPLE_ARM32; } inline bool IsAArch64() const { return triple_ == Triple::TRIPLE_AARCH64; } inline bool IsAmd64() const { return triple_ == Triple::TRIPLE_AMD64; } inline bool Is64Bit() const { return IsAArch64() || IsAmd64(); } Triple GetTriple() const { return triple_; } std::string GetTripleStr() const { return tripleStr_; } bool IsTraceBC() const { return isTraceBc_; } bool IsProfiling() const { return profiling_; } bool IsStressDeopt() const { return stressDeopt_; } bool IsVerifyVTbale() const { return verifyVTable_; } bool IsTypedOpProfiling() const { return typedOpProfiling_; } private: inline Triple GetTripleFromString(const std::string &triple) { if (triple.compare(TARGET_X64) == 0) { return Triple::TRIPLE_AMD64; } if (triple.compare(TARGET_AARCH64) == 0) { return Triple::TRIPLE_AARCH64; } if (triple.compare(TARGET_ARM32) == 0) { return Triple::TRIPLE_ARM32; } LOG_ECMA(FATAL) << "this branch is unreachable"; UNREACHABLE(); } std::string tripleStr_; Triple triple_; bool isTraceBc_ {false}; bool profiling_ {false}; bool stressDeopt_ {false}; bool verifyVTable_ {false}; bool typedOpProfiling_ {false}; }; class Label { public: Label() = default; explicit Label(Environment *env); explicit Label(CircuitBuilder *cirBuilder); ~Label() = default; Label(Label const &label) = default; Label &operator=(Label const &label) = default; Label(Label &&label) = default; Label &operator=(Label &&label) = default; inline void Seal() { return impl_->Seal(); } inline void WriteVariable(Variable *var, GateRef value) { impl_->WriteVariable(var, value); } inline GateRef ReadVariable(Variable *var) { return impl_->ReadVariable(var); } inline void Bind() { impl_->Bind(); } inline void MergeAllControl() { impl_->MergeAllControl(); } inline void MergeAllDepend() { impl_->MergeAllDepend(); } inline void AppendPredecessor(const Label *predecessor) { impl_->AppendPredecessor(predecessor->GetRawLabel()); } inline std::vector<Label> GetPredecessors() const { std::vector<Label> labels; for (auto rawlabel : impl_->GetPredecessors()) { labels.emplace_back(Label(rawlabel)); } return labels; } inline void SetControl(GateRef control) { impl_->SetControl(control); } inline void SetPreControl(GateRef control) { impl_->SetPreControl(control); } inline void MergeControl(GateRef control) { impl_->MergeControl(control); } inline GateRef GetControl() const { return impl_->GetControl(); } inline GateRef GetDepend() const { return impl_->GetDepend(); } inline void SetDepend(GateRef depend) { return impl_->SetDepend(depend); } private: class LabelImpl { public: LabelImpl(Environment *env, GateRef control) : env_(env), control_(control), predeControl_(-1), isSealed_(false) { } ~LabelImpl() = default; NO_MOVE_SEMANTIC(LabelImpl); NO_COPY_SEMANTIC(LabelImpl); void Seal(); void WriteVariable(Variable *var, GateRef value); GateRef ReadVariable(Variable *var); void Bind(); void MergeAllControl(); void MergeAllDepend(); void AppendPredecessor(LabelImpl *predecessor); std::vector<LabelImpl *> GetPredecessors() const { return predecessors_; } void SetControl(GateRef control) { control_ = control; } void SetPreControl(GateRef control) { predeControl_ = control; } void MergeControl(GateRef control) { if (predeControl_ == Circuit::NullGate()) { predeControl_ = control; control_ = predeControl_; } else { otherPredeControls_.push_back(control); } } GateRef GetControl() const { return control_; } void SetDepend(GateRef depend) { depend_ = depend; } GateRef GetDepend() const { return depend_; } private: bool IsNeedSeal() const; bool IsSealed() const { return isSealed_; } bool IsLoopHead() const; bool IsControlCase() const; GateRef ReadVariableRecursive(Variable *var); Environment *env_; GateRef control_; GateRef predeControl_ {Circuit::NullGate()}; GateRef depend_ {Circuit::NullGate()}; GateRef loopDepend_ {Circuit::NullGate()}; std::vector<GateRef> otherPredeControls_; bool isSealed_ {false}; std::map<Variable *, GateRef> valueMap_; std::vector<GateRef> phi; std::vector<LabelImpl *> predecessors_; std::map<Variable *, GateRef> incompletePhis_; }; explicit Label(LabelImpl *impl) : impl_(impl) {} friend class Environment; LabelImpl *GetRawLabel() const { return impl_; } LabelImpl *impl_ {nullptr}; }; class Environment { public: using LabelImpl = Label::LabelImpl; Environment(GateRef hir, Circuit *circuit, CircuitBuilder *builder); Environment(GateRef stateEntry, GateRef dependEntry, const std::initializer_list<GateRef>& args, Circuit *circuit, CircuitBuilder *builder); Environment(size_t arguments, CircuitBuilder *builder); ~Environment(); Label *GetCurrentLabel() const { return currentLabel_; } void SetCurrentLabel(Label *label) { currentLabel_ = label; } CircuitBuilder *GetBuilder() const { return circuitBuilder_; } Circuit *GetCircuit() const { return circuit_; } int NextVariableId() { return nextVariableId_++; } void SetCompilationConfig(const CompilationConfig *cfg) { ccfg_ = cfg; } const CompilationConfig *GetCompilationConfig() const { return ccfg_; } inline bool Is32Bit() const { return ccfg_->Is32Bit(); } inline bool IsAArch64() const { return ccfg_->IsAArch64(); } inline bool IsAmd64() const { return ccfg_->IsAmd64(); } inline bool IsArch64Bit() const { return ccfg_->IsAmd64() || ccfg_->IsAArch64(); } inline bool IsAsmInterp() const { return circuit_->GetFrameType() == FrameType::ASM_INTERPRETER_FRAME; } inline bool IsArch32Bit() const { return ccfg_->Is32Bit(); } inline GateRef GetArgument(size_t index) const { return arguments_.at(index); } inline Label GetLabelFromSelector(GateRef sel) { Label::LabelImpl *rawlabel = phiToLabels_[sel]; return Label(rawlabel); } inline void AddSelectorToLabel(GateRef sel, Label label) { phiToLabels_[sel] = label.GetRawLabel(); } inline LabelImpl *NewLabel(Environment *env, GateRef control = -1) { auto impl = new Label::LabelImpl(env, control); rawLabels_.emplace_back(impl); return impl; } inline void SubCfgEntry(Label *entry) { if (currentLabel_ != nullptr) { GateRef control = currentLabel_->GetControl(); GateRef depend = currentLabel_->GetDepend(); stack_.push(currentLabel_); currentLabel_ = entry; currentLabel_->SetControl(control); currentLabel_->SetDepend(depend); } } inline void SubCfgExit() { if (currentLabel_ != nullptr) { GateRef control = currentLabel_->GetControl(); GateRef depend = currentLabel_->GetDepend(); if (!stack_.empty()) { currentLabel_ = stack_.top(); currentLabel_->SetControl(control); currentLabel_->SetDepend(depend); stack_.pop(); } } } inline GateRef GetInput(size_t index) const { return inputList_.at(index); } private: Label *currentLabel_ {nullptr}; Circuit *circuit_ {nullptr}; CircuitBuilder *circuitBuilder_ {nullptr}; std::unordered_map<GateRef, LabelImpl *> phiToLabels_; std::vector<GateRef> inputList_; Label entry_; std::vector<LabelImpl *> rawLabels_; std::stack<Label *> stack_; int nextVariableId_ {0}; std::vector<GateRef> arguments_; const CompilationConfig *ccfg_ {nullptr}; }; class Variable { public: Variable(Environment *env, VariableType type, uint32_t id, GateRef value) : id_(id), type_(type), env_(env) { Bind(value); env_->GetCurrentLabel()->WriteVariable(this, value); } Variable(CircuitBuilder *cirbuilder, VariableType type, uint32_t id, GateRef value) : id_(id), type_(type), env_(cirbuilder->GetCurrentEnvironment()) { Bind(value); env_->GetCurrentLabel()->WriteVariable(this, value); } ~Variable() = default; NO_MOVE_SEMANTIC(Variable); NO_COPY_SEMANTIC(Variable); void Bind(GateRef value) { currentValue_ = value; } GateRef Value() const { return currentValue_; } VariableType Type() const { return type_; } bool IsBound() const { return currentValue_ != 0; } Variable &operator=(const GateRef value) { env_->GetCurrentLabel()->WriteVariable(this, value); Bind(value); return *this; } GateRef operator*() { return env_->GetCurrentLabel()->ReadVariable(this); } GateRef ReadVariable() { return env_->GetCurrentLabel()->ReadVariable(this); } void WriteVariable(GateRef value) { env_->GetCurrentLabel()->WriteVariable(this, value); Bind(value); } GateRef AddPhiOperand(GateRef val); GateRef AddOperandToSelector(GateRef val, size_t idx, GateRef in); GateRef TryRemoveTrivialPhi(GateRef phi); uint32_t GetId() const { return id_; } private: Circuit* GetCircuit() const { return env_->GetCircuit(); } uint32_t id_; VariableType type_; GateRef currentValue_ {0}; Environment *env_; }; } #endif // ECMASCRIPT_COMPILER_CIRCUIT_BUILDER_H