From b9978bf60e6aee99773d8d1ad56f197df7521f1d Mon Sep 17 00:00:00 2001 From: zhaoziming Date: Sun, 21 Apr 2024 18:25:02 +0800 Subject: [PATCH] Support corss-file branch elimination issue: I9IS1Z Tests: runtime_core UT & defect_scan & verifier & test262 & frontend tests & standalone build Change-Id: I737706d219fb777184e65e359ffaf0e08f0c9a3c Signed-off-by: zhaoziming --- OAT.xml | 1 + bytecode_optimizer/BUILD.gn | 4 + .../bytecode_analysis_results.cpp | 231 +++++ .../bytecode_analysis_results.h | 108 +++ bytecode_optimizer/common.cpp | 9 + bytecode_optimizer/common.h | 3 + .../constant_propagation.cpp | 268 ++++-- .../constant_propagation.h | 35 +- .../constant_propagation/constant_value.h | 108 +++ .../constant_propagation/lattice_element.cpp | 28 +- .../constant_propagation/lattice_element.h | 34 +- bytecode_optimizer/ir_interface.h | 5 + .../module_constant_analyzer.cpp | 139 +++ bytecode_optimizer/module_constant_analyzer.h | 86 ++ bytecode_optimizer/optimize_bytecode.cpp | 208 +++- bytecode_optimizer/optimize_bytecode.h | 2 + bytecode_optimizer/runtime_adapter.h | 1 + bytecode_optimizer/tests/BUILD.gn | 31 + .../tests/analysis_bytecode_test.cpp | 116 +++ .../tests/constant_propagation_test.cpp | 537 +++++++++++ .../tests/js/bytecodeAnalysis.js | 30 + .../tests/js/constantProgagation.js | 99 +- compiler/BUILD.gn | 2 - .../optimizations/branch_elimination.cpp | 1 + compiler/tests/BUILD.gn | 7 +- .../tests/branch_elimination_new_test.cpp | 12 +- compiler/tests/constant_propagation_test.cpp | 898 ------------------ libpandafile/class_data_accessor.h | 5 + 28 files changed, 1947 insertions(+), 1061 deletions(-) create mode 100644 bytecode_optimizer/bytecode_analysis_results.cpp create mode 100644 bytecode_optimizer/bytecode_analysis_results.h rename {compiler/optimizer/optimizations => bytecode_optimizer}/constant_propagation/constant_propagation.cpp (62%) rename {compiler/optimizer/optimizations => bytecode_optimizer}/constant_propagation/constant_propagation.h (78%) create mode 100644 bytecode_optimizer/constant_propagation/constant_value.h rename {compiler/optimizer/optimizations => bytecode_optimizer}/constant_propagation/lattice_element.cpp (79%) rename {compiler/optimizer/optimizations => bytecode_optimizer}/constant_propagation/lattice_element.h (83%) create mode 100644 bytecode_optimizer/module_constant_analyzer.cpp create mode 100644 bytecode_optimizer/module_constant_analyzer.h create mode 100644 bytecode_optimizer/tests/analysis_bytecode_test.cpp create mode 100644 bytecode_optimizer/tests/constant_propagation_test.cpp create mode 100644 bytecode_optimizer/tests/js/bytecodeAnalysis.js rename {compiler => bytecode_optimizer}/tests/js/constantProgagation.js (96%) delete mode 100644 compiler/tests/constant_propagation_test.cpp diff --git a/OAT.xml b/OAT.xml index 67d6cf2014..c69672ce5c 100644 --- a/OAT.xml +++ b/OAT.xml @@ -57,6 +57,7 @@ + diff --git a/bytecode_optimizer/BUILD.gn b/bytecode_optimizer/BUILD.gn index 6ddb6aa196..bcfb5b11d7 100644 --- a/bytecode_optimizer/BUILD.gn +++ b/bytecode_optimizer/BUILD.gn @@ -24,8 +24,12 @@ config("bytecodeopt_public_config") { } libarkbytecodeopt_sources = [ + "$ark_root/bytecode_optimizer/bytecode_analysis_results.cpp", "$ark_root/bytecode_optimizer/codegen.cpp", "$ark_root/bytecode_optimizer/common.cpp", + "$ark_root/bytecode_optimizer/constant_propagation/constant_propagation.cpp", + "$ark_root/bytecode_optimizer/constant_propagation/lattice_element.cpp", + "$ark_root/bytecode_optimizer/module_constant_analyzer.cpp", "$ark_root/bytecode_optimizer/optimize_bytecode.cpp", "$ark_root/bytecode_optimizer/reg_acc_alloc.cpp", "$ark_root/bytecode_optimizer/reg_encoder.cpp", diff --git a/bytecode_optimizer/bytecode_analysis_results.cpp b/bytecode_optimizer/bytecode_analysis_results.cpp new file mode 100644 index 0000000000..43a96b40eb --- /dev/null +++ b/bytecode_optimizer/bytecode_analysis_results.cpp @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2024 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. + */ + +#include "bytecode_analysis_results.h" + +#include + +namespace panda::bytecodeopt { + +std::mutex BytecodeAnalysisResults::mutex_; +BytecodeAnalysisResultMap BytecodeAnalysisResults::analysis_results_; +BytecodeMapsMap BytecodeAnalysisResults::bytecode_maps_; + +void BytecodeAnalysisResult::SetModuleConstantAnalysisResult(const ModuleConstantAnalysisResult &result) +{ + for (auto &iter : result) { + uint32_t slot = iter.first; + if (slot < local_export_slot_external_names_.size()) { + const auto &external_names = local_export_slot_external_names_[slot]; + for (const auto &external_name_iter : external_names) { + constant_local_export_values_.emplace(external_name_iter, *iter.second); + } + } + } +} + +void BytecodeAnalysisResult::SetConstantLocalExportSlots(const std::unordered_set &slots) +{ + constant_local_export_slots_ = slots; +} + +void BytecodeAnalysisResult::SetLocalExportInfo(uint32_t slot, const std::string &external_name) +{ + if (slot == local_export_slot_external_names_.size()) { + auto &vec = local_export_slot_external_names_.emplace_back(); + vec.push_back(external_name); + } else { + ASSERT(slot < local_export_slot_external_names_.size()); + local_export_slot_external_names_[slot].push_back(external_name); + } +} + +void BytecodeAnalysisResult::SetRegularImportInfo(uint32_t slot, + const std::string &import_name, + const std::string &source_record) +{ + [[maybe_unused]] auto iter = regular_import_slot_infos_.find(slot); + ASSERT(iter == regular_import_slot_infos_.end()); + RegularImportInfo info {import_name, source_record}; + regular_import_slot_infos_.emplace(slot, info); +} + +void BytecodeAnalysisResult::SetNamespaceImportInfo(uint32_t slot, const std::string &source_record) +{ + namespace_import_slot_source_record_names_.emplace(slot, source_record); +} + +bool BytecodeAnalysisResult::GetLocalExportInfo(uint32_t slot, uint32_t name_idx, std::string &external_name) const +{ + if (slot >= local_export_slot_external_names_.size()) { + return false; + } + const auto &names = local_export_slot_external_names_[slot]; + if (name_idx > names.size()) { + return false; + } + external_name = names[name_idx]; + return true; +} + +bool BytecodeAnalysisResult::GetRegularImportInfo(uint32_t slot, + std::string &import_name, + std::string &source_record) const +{ + auto iter = regular_import_slot_infos_.find(slot); + if (iter == regular_import_slot_infos_.end()) { + return false; + } + import_name = iter->second.import_name; + source_record = iter->second.source_record_name; + return true; +} + +bool BytecodeAnalysisResult::GetNamespaceImportInfo(uint32_t slot, std::string &source_record) const +{ + auto iter = namespace_import_slot_source_record_names_.find(slot); + if (iter == namespace_import_slot_source_record_names_.end()) { + return false; + } + source_record = iter->second; + return true; +} + +bool BytecodeAnalysisResult::GetExportedConstantValue(const std::string &name, ConstantValue &value) const +{ + auto iter = constant_local_export_values_.find(name); + if (iter != constant_local_export_values_.end()) { + value = iter->second; + return true; + } + return false; +} + +void BytecodeAnalysisResult::Dump(std::ostream &os) +{ + os << "------------------------------------" << std::endl; + os << "Constant local export values: " << std::endl; + for (auto iter : constant_local_export_values_) { + os << iter.first << ": " << iter.second.ToString() << std::endl; + } + os << "Constant local export slots: " << std::endl; + for (auto iter : constant_local_export_slots_) { + os << iter << ", "; + } + os << std::endl; + os << "Local export slot external names: " << std::endl; + for (size_t i = 0; i < local_export_slot_external_names_.size(); i++) { + os << i << ": "; + for (auto iter : local_export_slot_external_names_[i]) { + os << iter << ", "; + } + os << std::endl; + } + os << "Regular import slot infos: " << std::endl; + for (auto iter : regular_import_slot_infos_) { + os << iter.first << ": import_name: " << iter.second.import_name + << ", source_record_name: " << iter.second.source_record_name << std::endl; + } + os << "Namespace import slot source record names: " << std::endl; + for (auto iter : namespace_import_slot_source_record_names_) { + os << iter.first << ": " << iter.second << std::endl; + } + os << "------------------------------------" << std::endl; +} + +pandasm::AsmEmitter::PandaFileToPandaAsmMaps &BytecodeAnalysisResults::GetOrCreateBytecodeMaps( + const std::string &filename, bool &exists) +{ + return GetOrCreateElementInMap(bytecode_maps_, filename, exists); +} + +void BytecodeAnalysisResults::DeleteBytecodeMaps(const std::string &filename) +{ + std::unique_lock lock(mutex_); + bytecode_maps_.erase(filename); +} + +BytecodeAnalysisResult &BytecodeAnalysisResults::GetOrCreateBytecodeAnalysisResult(const std::string &recordname, + bool &exists) +{ + return GetOrCreateElementInMap(analysis_results_, recordname, exists); +} + +bool BytecodeAnalysisResults::GetLocalExportConstForRecord(const std::string &recordname, + uint32_t local_export_slot, + ConstantValue &value) +{ + constexpr uint32_t DEFAULT_EXTERNAL_NAME_IDX = 0; + auto iter = analysis_results_.find(recordname); + if (iter == analysis_results_.end()) { + return false; + } + auto &analysis_resut = iter->second; + std::string external_name; + if (!analysis_resut->GetLocalExportInfo(local_export_slot, DEFAULT_EXTERNAL_NAME_IDX, external_name)) { + return false; + } + return analysis_resut->GetExportedConstantValue(external_name, value); +} + +bool BytecodeAnalysisResults::GetRegularImportConstForRecord(const std::string &recordname, + uint32_t regular_import_slot, + ConstantValue &value) +{ + auto iter = analysis_results_.find(recordname); + if (iter == analysis_results_.end()) { + return false; + } + std::string import_name; + std::string source_record; + if (!iter->second->GetRegularImportInfo(regular_import_slot, import_name, source_record)) { + return false; + } + + iter = analysis_results_.find(source_record); + if (iter == analysis_results_.end()) { + return false; + } + return iter->second->GetExportedConstantValue(import_name, value); +} + +bool BytecodeAnalysisResults::GetModuleNamespaceConstForRecord(const std::string &recordname, + uint32_t module_namespace_slot, + const std::string &property_name, + ConstantValue &value) +{ + auto iter = analysis_results_.find(recordname); + if (iter == analysis_results_.end()) { + return false; + } + std::string source_record; + if (!iter->second->GetNamespaceImportInfo(module_namespace_slot, source_record)) { + return false; + } + iter = analysis_results_.find(source_record); + if (iter == analysis_results_.end()) { + return false; + } + return iter->second->GetExportedConstantValue(property_name, value); +} + +void BytecodeAnalysisResults::Clear() +{ + std::unique_lock lock(mutex_); + bytecode_maps_.clear(); + analysis_results_.clear(); +} + +} // namespace panda::bytecodeopt \ No newline at end of file diff --git a/bytecode_optimizer/bytecode_analysis_results.h b/bytecode_optimizer/bytecode_analysis_results.h new file mode 100644 index 0000000000..db2c47db15 --- /dev/null +++ b/bytecode_optimizer/bytecode_analysis_results.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2024 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 BYTECODE_OPTIMIZER_BYTECODE_ANALYSIS_RESULT_H +#define BYTECODE_OPTIMIZER_BYTECODE_ANALYSIS_RESULT_H + +#include +#include "assembler/assembly-emitter.h" +#include "bytecode_optimizer/module_constant_analyzer.h" +#include "bytecode_optimizer/constant_propagation/constant_value.h" + +namespace panda::bytecodeopt { + +class BytecodeAnalysisResult { +public: + explicit BytecodeAnalysisResult() = default; + + const std::unordered_set &GetConstantLocalExportSlots() + { + return constant_local_export_slots_; + } + + void SetModuleConstantAnalysisResult(const ModuleConstantAnalysisResult &result); + void SetConstantLocalExportSlots(const std::unordered_set &slots); + void SetLocalExportInfo(uint32_t slot, const std::string &external_name); + void SetRegularImportInfo(uint32_t slot, const std::string &import_name, const std::string &source_record); + void SetNamespaceImportInfo(uint32_t slot, const std::string &source_record); + void Dump(std::ostream &os); + +private: + using LocalExportInfo = std::vector; + struct RegularImportInfo { + std::string import_name; + std::string source_record_name; + }; + + bool GetExportedConstantValue(const std::string &name, ConstantValue &value) const; + bool GetLocalExportInfo(uint32_t slot, uint32_t name_idx, std::string &external_name) const; + bool GetRegularImportInfo(uint32_t slot, std::string &import_name, std::string &source_record) const; + bool GetNamespaceImportInfo(uint32_t slot, std::string &source_record) const; + + std::unordered_map constant_local_export_values_; + std::unordered_set constant_local_export_slots_; + std::vector local_export_slot_external_names_; + std::unordered_map regular_import_slot_infos_; + std::unordered_map namespace_import_slot_source_record_names_; + + friend class BytecodeAnalysisResults; +}; + +using BytecodeAnalysisResultMap = std::unordered_map>; +using BytecodeMapsMap = + std::unordered_map>; + +class BytecodeAnalysisResults { +public: + static pandasm::AsmEmitter::PandaFileToPandaAsmMaps &GetOrCreateBytecodeMaps(const std::string &filename, + bool &exists); + static void DeleteBytecodeMaps(const std::string &filename); + + static BytecodeAnalysisResult &GetOrCreateBytecodeAnalysisResult(const std::string &recordname, bool &exists); + + static void Clear(); + + // Following methods should only be called when no writer modifying analysis results exists + static bool GetLocalExportConstForRecord(const std::string &recordname, uint32_t local_export_slot, + ConstantValue &value); + static bool GetRegularImportConstForRecord(const std::string &recordname, uint32_t regular_import_slot, + ConstantValue &value); + static bool GetModuleNamespaceConstForRecord(const std::string &recordname, uint32_t module_namespace_slot, + const std::string &property_name, ConstantValue &value); +private: + static BytecodeAnalysisResultMap analysis_results_; + static BytecodeMapsMap bytecode_maps_; + static std::mutex mutex_; + + template + static T& GetOrCreateElementInMap(std::unordered_map> &map, + const std::string &name, bool &exists) + { + std::unique_lock lock(mutex_); + auto iter = map.find(name); + if (iter == map.end()) { + exists = false; + auto new_element = std::make_unique(); + auto ret = map.emplace(name, std::move(new_element)); + ASSERT(ret.second == true); + return *ret.first->second; + } + return *(iter->second); + } +}; + +} // namespace panda::bytecodeopt + +#endif // BYTECODE_OPTIMIZER_BYTECODE_ANALYSIS_RESULT_H diff --git a/bytecode_optimizer/common.cpp b/bytecode_optimizer/common.cpp index 75f2aecbb5..2544144fc2 100644 --- a/bytecode_optimizer/common.cpp +++ b/bytecode_optimizer/common.cpp @@ -16,6 +16,8 @@ #include "common.h" #include "compiler/optimizer/ir/basicblock.h" #include "compiler/optimizer/ir/graph.h" +#include "libpandafile/file.h" +#include "libpandafile/file-inl.h" namespace panda::bytecodeopt { @@ -28,4 +30,11 @@ uint8_t AccReadIndex(const compiler::Inst *inst) } return 0; } + +std::string GetStringFromPandaFile(const panda_file::File &pfile, uint32_t offset) +{ + const auto sd = pfile.GetStringData(panda_file::File::EntityId(offset)); + std::string str(utf::Mutf8AsCString(sd.data)); + return str; +} } // namespace panda::bytecodeopt diff --git a/bytecode_optimizer/common.h b/bytecode_optimizer/common.h index ff12a24c38..98c486b0db 100644 --- a/bytecode_optimizer/common.h +++ b/bytecode_optimizer/common.h @@ -30,6 +30,9 @@ static constexpr uint32_t MAX_BYTECODE_SIZE = 100000U; // Get the position where accumulator read happens. uint8_t AccReadIndex(const compiler::Inst *inst); +// Get string from offset of a panda file +std::string GetStringFromPandaFile(const panda_file::File &pfile, uint32_t offset); + } // namespace panda::bytecodeopt #endif // BYTECODE_OPTIMIZER_COMMON_H diff --git a/compiler/optimizer/optimizations/constant_propagation/constant_propagation.cpp b/bytecode_optimizer/constant_propagation/constant_propagation.cpp similarity index 62% rename from compiler/optimizer/optimizations/constant_propagation/constant_propagation.cpp rename to bytecode_optimizer/constant_propagation/constant_propagation.cpp index 6e77859abb..670ae0c902 100644 --- a/compiler/optimizer/optimizations/constant_propagation/constant_propagation.cpp +++ b/bytecode_optimizer/constant_propagation/constant_propagation.cpp @@ -27,28 +27,31 @@ */ #include "constant_propagation.h" +#include "bytecode_optimizer/bytecode_analysis_results.h" #include "compiler_logger.h" -#include "compiler/optimizer/optimizations/cleanup.h" #include "compiler/optimizer/optimizations/lowering.h" -#include "optimizer/ir/basicblock.h" #include "optimizer/ir/graph.h" #include "optimizer/ir/inst.h" -namespace panda::compiler { +namespace panda::bytecodeopt { + enum class InputCount { NONE_INPUT, ONE_INPUT, TWO_INPUT, }; -ConstantPropagation::ConstantPropagation(Graph *graph) +ConstantPropagation::ConstantPropagation(compiler::Graph *graph, const BytecodeOptIrInterface *iface) : Optimization(graph), lattices_(graph->GetLocalAllocator()->Adapter()), flow_edges_(graph->GetLocalAllocator()->Adapter()), ssa_edges_(graph->GetLocalAllocator()->Adapter()), executable_flag_(graph->GetLocalAllocator()->Adapter()), - executed_node_(graph->GetLocalAllocator()->Adapter()) + executed_node_(graph->GetLocalAllocator()->Adapter()), + ir_interface_(iface) { + std::string classname = GetGraph()->GetRuntime()->GetClassNameFromMethod(GetGraph()->GetMethod()); + record_name_ = pandasm::Type::FromDescriptor(classname).GetName(); } bool ConstantPropagation::RunImpl() @@ -109,24 +112,44 @@ void ConstantPropagation::ReWriteInst() if (!pair.second->IsConstantElement() || pair.first->IsConst()) { continue; } - // Skip the CastValueToAnyType instruction to preserve the original IR structure of "Constant(double) -> - // CastValueToAnyType". This structure is necessary for certain GraphChecker checks. + // Skip the CastValueToAnyType instruction to preserve the original IR structure of + // "LoadString/Constant(double) -> CastValueToAnyType". + // This structure is necessary for certain GraphChecker checks. if (pair.first->GetOpcode() == compiler::Opcode::CastValueToAnyType) { continue; } - // Skip Intrisic.ldtrue and Intrisic.ldfalse + // Skip generate replacement inst for string constants for now, since it requires generating + // a string with a unique offset + if (pair.second->AsConstant()->GetType() == ConstantValue::CONSTANT_STRING) { + continue; + } if (pair.first->IsIntrinsic()) { auto id = pair.first->CastToIntrinsic()->GetIntrinsicId(); - if (id == RuntimeInterface::IntrinsicId::LDFALSE || id == RuntimeInterface::IntrinsicId::LDTRUE) { - // Clear flag NO_DCE, this inst will be cleanup if it has any user. - pair.first->ClearFlag(compiler::inst_flags::NO_DCE); - continue; + // Skip Intrinsic.ldtrue and Intrinsic.ldfalse since replacing them would create the same instruction. + // Skip ldlocal/externalmodulevar and ldobjbyname in case of possible side effects when accessing module + // constants. + switch (id) { + case compiler::RuntimeInterface::IntrinsicId::LDFALSE: + case compiler::RuntimeInterface::IntrinsicId::LDTRUE: + pair.first->ClearFlag(compiler::inst_flags::NO_DCE); + continue; + case RuntimeInterface::IntrinsicId::LDLOCALMODULEVAR_IMM8: + case RuntimeInterface::IntrinsicId::WIDE_LDLOCALMODULEVAR_PREF_IMM16: + case RuntimeInterface::IntrinsicId::LDEXTERNALMODULEVAR_IMM8: + case RuntimeInterface::IntrinsicId::WIDE_LDEXTERNALMODULEVAR_PREF_IMM16: + case RuntimeInterface::IntrinsicId::LDOBJBYNAME_IMM8_ID16: + case RuntimeInterface::IntrinsicId::LDOBJBYNAME_IMM16_ID16: + continue; + default: + break; } } auto replace_inst = CreateReplaceInst(pair.first, pair.second->AsConstant()); - for (auto &user : pair.first->GetUsers()) { - user.GetInst()->ReplaceInput(pair.first, replace_inst); + // This should never happen, but left here as a precaution for unexpected scenarios. + if (replace_inst == nullptr) { + continue; } + pair.first->ReplaceUsers(replace_inst); pair.first->ClearFlag(compiler::inst_flags::NO_DCE); } } @@ -169,9 +192,8 @@ void ConstantPropagation::VisitIfImm(GraphVisitor *v, Inst *inst) auto bb = inst->GetBasicBlock(); // According to inst_builder_gen.cpp.erb, the input of the IfImm IR is always a Compare IR generates DataType::BOOL. if (input_lattice->IsConstantElement() && - input_lattice->AsConstant()->GetType() == ConstantElement::CONSTANT_BOOL) { - auto cst = - static_cast(std::get(input_lattice->AsConstant()->GetVal())); + input_lattice->AsConstant()->GetType() == ConstantValue::CONSTANT_BOOL) { + auto cst = static_cast(input_lattice->AsConstant()->GetValue()); auto dstBlock = propagation->GetIfTargetBlock(inst->CastToIfImm(), cst) ? bb->GetTrueSuccessor() : bb->GetFalseSuccessor(); propagation->AddUntraversedFlowEdges(bb, dstBlock); @@ -212,7 +234,12 @@ void ConstantPropagation::VisitIntrinsic(GraphVisitor *v, Inst *inst) return; } auto id = inst->CastToIntrinsic()->GetIntrinsicId(); - LatticeElement *element = BottomElement::GetInstance(); + LatticeElement *element = propagation->FoldingModuleOperation(inst->CastToIntrinsic()); + if (element != nullptr) { + propagation->CheckAndAddToSsaEdge(inst, current, element); + return; + } + element = BottomElement::GetInstance(); auto count = inst->GetInputsCount(); if (inst->RequireState()) { count--; @@ -225,9 +252,7 @@ void ConstantPropagation::VisitIntrinsic(GraphVisitor *v, Inst *inst) auto lattices0 = propagation->GetOrCreateDefaultLattice(input0); auto lattices1 = propagation->GetOrCreateDefaultLattice(input1); if (lattices0->IsConstantElement() && lattices1->IsConstantElement()) { - auto const0 = lattices0->AsConstant(); - auto const1 = lattices1->AsConstant(); - element = propagation->FoldingConstant(const0, const1, id); + element = propagation->FoldingConstant(lattices0->AsConstant(), lattices1->AsConstant(), id); } break; } @@ -260,12 +285,19 @@ void ConstantPropagation::VisitCastValueToAnyType(GraphVisitor *v, Inst *inst) } LatticeElement *element = BottomElement::GetInstance(); auto type = inst->CastToCastValueToAnyType()->GetAnyType(); - // According to inst_builder.cpp, the fldai bytecode will generate an IR sequence as follows: Constant(double) -> - // CastValueToAnyType. We create the lattice value of the original double constant here and leave the IR unchanged. + // According to inst_builder.cpp: + // 1. The fldai bytecode will generate: Constant(double) -> CastValueToAnyType(ECMASCRIPT_DOUBLE_TYPE). + // 2. The lda.str bytecode will generate: LoadString -> CastValueToAnyType(ECMASCRIPT_STRING_TYPE). + // We create the lattice value of the original constant here and leave the IR unchanged. if (type == compiler::AnyBaseType::ECMASCRIPT_DOUBLE_TYPE) { - ASSERT(inst->GetInput(0).GetInst()->IsConst()); + ASSERT(inst->GetDataFlowInput(0)->IsConst()); element = propagation->GetGraph()->GetLocalAllocator()->New( - inst->GetInput(0).GetInst()->CastToConstant()->GetDoubleValue()); + inst->GetDataFlowInput(0)->CastToConstant()->GetDoubleValue()); + } else if (type == compiler::AnyBaseType::ECMASCRIPT_STRING_TYPE) { + ASSERT(inst->GetDataFlowInput(0)->GetOpcode() == compiler::Opcode::LoadString); + auto load_string_inst = inst->GetDataFlowInput(0)->CastToLoadString(); + element = propagation->GetGraph()->GetLocalAllocator()->New( + propagation->ir_interface_->GetStringIdByOffset(load_string_inst->GetTypeId())); } propagation->CheckAndAddToSsaEdge(inst, current, element); } @@ -273,25 +305,49 @@ void ConstantPropagation::VisitCastValueToAnyType(GraphVisitor *v, Inst *inst) void ConstantPropagation::VisitConstant(GraphVisitor *v, Inst *inst) { ASSERT(v); - ASSERT(inst->IsConst()); + ASSERT(inst && inst->IsConst()); auto propagation = static_cast(v); auto const_inst = inst->CastToConstant(); - if (propagation->lattices_.find(inst) == propagation->lattices_.end()) { - ConstantElement *element = nullptr; - if (const_inst->GetType() == DataType::INT32) { + auto current = propagation->GetOrCreateDefaultLattice(inst); + if (current->IsBottomElement()) { + return; + } + LatticeElement *element = BottomElement::GetInstance(); + switch (const_inst->GetType()) { + case compiler::DataType::INT32: { auto val = static_cast(const_inst->GetInt32Value()); element = propagation->GetGraph()->GetLocalAllocator()->New(val); - } else if (const_inst->GetType() == DataType::INT64) { + break; + } + case compiler::DataType::INT64: { auto val = static_cast(const_inst->GetRawValue()); element = propagation->GetGraph()->GetLocalAllocator()->New(val); - } else if (const_inst->GetType() == DataType::FLOAT64) { + break; + } + case compiler::DataType::FLOAT64: { auto val = const_inst->GetDoubleValue(); element = propagation->GetGraph()->GetLocalAllocator()->New(val); - } else { - UNREACHABLE(); + break; } - propagation->lattices_.emplace(inst, element); + default: + break; } + propagation->CheckAndAddToSsaEdge(inst, current, element); +} + +void ConstantPropagation::VisitLoadString(GraphVisitor *v, Inst *inst) +{ + ASSERT(v); + ASSERT(inst && inst->GetOpcode() == compiler::Opcode::LoadString); + auto propagation = static_cast(v); + auto load_string_inst = inst->CastToLoadString(); + auto current = propagation->GetOrCreateDefaultLattice(inst); + if (current->IsBottomElement()) { + return; + } + auto val = propagation->ir_interface_->GetStringIdByOffset(load_string_inst->GetTypeId()); + LatticeElement *element = propagation->GetGraph()->GetLocalAllocator()->New(val); + propagation->CheckAndAddToSsaEdge(inst, current, element); } void ConstantPropagation::VisitPhi(GraphVisitor *v, Inst *inst) @@ -327,14 +383,14 @@ void ConstantPropagation::AddUntraversedFlowEdges(BasicBlock *src, BasicBlock *d flow_edges_.push(edge); } -bool ConstantPropagation::GetIfTargetBlock(IfImmInst *inst, uint64_t val) +bool ConstantPropagation::GetIfTargetBlock(compiler::IfImmInst *inst, uint64_t val) { auto imm = inst->GetImm(); auto cc = inst->GetCc(); switch (cc) { - case ConditionCode::CC_NE: + case compiler::ConditionCode::CC_NE: return imm != val; - case ConditionCode::CC_EQ: + case compiler::ConditionCode::CC_EQ: return imm == val; default: UNREACHABLE(); @@ -377,6 +433,24 @@ LatticeElement *ConstantPropagation::FoldingConstant(ConstantElement *left, Cons } } +LatticeElement *ConstantPropagation::FoldingModuleOperation(compiler::IntrinsicInst *inst) +{ + auto id = inst->GetIntrinsicId(); + switch (id) { + case RuntimeInterface::IntrinsicId::LDLOCALMODULEVAR_IMM8: + case RuntimeInterface::IntrinsicId::WIDE_LDLOCALMODULEVAR_PREF_IMM16: + return FoldingLdlocalmodulevar(inst); + case RuntimeInterface::IntrinsicId::LDEXTERNALMODULEVAR_IMM8: + case RuntimeInterface::IntrinsicId::WIDE_LDEXTERNALMODULEVAR_PREF_IMM16: + return FoldingLdexternalmodulevar(inst); + case RuntimeInterface::IntrinsicId::LDOBJBYNAME_IMM8_ID16: + case RuntimeInterface::IntrinsicId::LDOBJBYNAME_IMM16_ID16: + return FoldingLdobjbyname(inst); + default: + return nullptr; + } +} + LatticeElement *ConstantPropagation::FoldingConstant(RuntimeInterface::IntrinsicId id) { switch (id) { @@ -394,10 +468,10 @@ LatticeElement *ConstantPropagation::FoldingConstant(ConstantElement *lattice, R switch (id) { case RuntimeInterface::IntrinsicId::ISFALSE: case RuntimeInterface::IntrinsicId::ISTRUE: { - if (lattice->GetType() != ConstantElement::CONSTANT_BOOL) { + if (lattice->GetType() != ConstantValue::CONSTANT_BOOL) { return BottomElement::GetInstance(); } - auto cst = std::get(lattice->GetVal()); + auto cst = lattice->GetValue(); return GetGraph()->GetLocalAllocator()->New( id == RuntimeInterface::IntrinsicId::ISTRUE ? cst : !cst); } @@ -407,24 +481,24 @@ LatticeElement *ConstantPropagation::FoldingConstant(ConstantElement *lattice, R } LatticeElement *ConstantPropagation::FoldingCompare(const ConstantElement *left, const ConstantElement *right, - ConditionCode cc) + compiler::ConditionCode cc) { ASSERT(left); ASSERT(right); // According to inst_builder_gen.cpp.erb, the input of the Compare IR are always ISTRUE/ISFALSE and a zero of i64. - if (left->GetType() != ConstantElement::CONSTANT_BOOL || right->GetType() != ConstantElement::CONSTANT_INT64) { + if (left->GetType() != ConstantValue::CONSTANT_BOOL || right->GetType() != ConstantValue::CONSTANT_INT64) { return BottomElement::GetInstance(); } - auto left_value = std::get(left->GetVal()); - auto right_value = std::get(right->GetVal()); + auto left_value = left->GetValue(); + auto right_value = right->GetValue(); if ((right_value != 0) && (right_value != 1)) { return BottomElement::GetInstance(); } switch (cc) { - case CC_EQ: { + case compiler::CC_EQ: { return GetGraph()->GetLocalAllocator()->New(left_value == right_value); } - case CC_NE: { + case compiler::CC_NE: { return GetGraph()->GetLocalAllocator()->New(left_value != right_value); } default: @@ -435,22 +509,22 @@ LatticeElement *ConstantPropagation::FoldingCompare(const ConstantElement *left, LatticeElement *ConstantPropagation::FoldingGreater(const ConstantElement *left, const ConstantElement *right, bool equal) { - if (left->GetType() != right->GetType()) { + if (left->GetType() != right->GetType() || left->GetType() == ConstantValue::CONSTANT_STRING) { return BottomElement::GetInstance(); } - auto left_value = left->GetVal(); - auto right_value = right->GetVal(); + auto left_value = left->GetValue(); + auto right_value = right->GetValue(); auto result = equal ? left_value >= right_value : left_value > right_value; return GetGraph()->GetLocalAllocator()->New(result); } LatticeElement *ConstantPropagation::FoldingLess(const ConstantElement *left, const ConstantElement *right, bool equal) { - if (left->GetType() != right->GetType()) { + if (left->GetType() != right->GetType() || left->GetType() == ConstantValue::CONSTANT_STRING) { return BottomElement::GetInstance(); } - auto left_value = left->GetVal(); - auto right_value = right->GetVal(); + auto left_value = left->GetValue(); + auto right_value = right->GetValue(); auto result = equal ? left_value <= right_value : left_value < right_value; return GetGraph()->GetLocalAllocator()->New(result); } @@ -460,8 +534,8 @@ LatticeElement *ConstantPropagation::FoldingEq(const ConstantElement *left, cons if (left->GetType() != right->GetType()) { return BottomElement::GetInstance(); } - auto left_value = left->GetVal(); - auto right_value = right->GetVal(); + auto left_value = left->GetValue(); + auto right_value = right->GetValue(); return GetGraph()->GetLocalAllocator()->New(left_value == right_value); } @@ -470,54 +544,99 @@ LatticeElement *ConstantPropagation::FoldingNotEq(const ConstantElement *left, c if (left->GetType() != right->GetType()) { return BottomElement::GetInstance(); } - auto left_value = left->GetVal(); - auto right_value = right->GetVal(); + auto left_value = left->GetValue(); + auto right_value = right->GetValue(); return GetGraph()->GetLocalAllocator()->New(left_value != right_value); } +LatticeElement *ConstantPropagation::FoldingLdlocalmodulevar(compiler::IntrinsicInst *inst) +{ + constexpr uint32_t LOCAL_EXPORT_SLOT_IDX = 0; + uint32_t local_export_slot = inst->GetImms()[LOCAL_EXPORT_SLOT_IDX]; + ConstantValue constant_value; + if (bytecodeopt::BytecodeAnalysisResults::GetLocalExportConstForRecord(record_name_, + local_export_slot, + constant_value)) { + return GetGraph()->GetLocalAllocator()->New(constant_value); + } + return BottomElement::GetInstance(); +} + +LatticeElement *ConstantPropagation::FoldingLdexternalmodulevar(compiler::IntrinsicInst *inst) +{ + constexpr uint32_t REGULAR_IMPORT_SLOT_IDX = 0; + auto regular_import_slot = inst->GetImms()[REGULAR_IMPORT_SLOT_IDX]; + ConstantValue constant_value; + if (bytecodeopt::BytecodeAnalysisResults::GetRegularImportConstForRecord(record_name_, + regular_import_slot, + constant_value)) { + return GetGraph()->GetLocalAllocator()->New(constant_value); + } + return BottomElement::GetInstance(); +} + +LatticeElement *ConstantPropagation::FoldingLdobjbyname(compiler::IntrinsicInst *inst) +{ + constexpr uint32_t PROPERTY_NAME_STRING_OFFSET_IDX = 1; + constexpr uint32_t MODULE_NAMESPACE_SLOT_IDX = 0; + constexpr uint32_t OBJECT_INPUT_IDX = 0; + Inst *object_inst = inst->GetDataFlowInput(OBJECT_INPUT_IDX); + if (object_inst->IsIntrinsic()) { + auto id = object_inst->CastToIntrinsic()->GetIntrinsicId(); + if (id == RuntimeInterface::IntrinsicId::GETMODULENAMESPACE_IMM8 || + id == RuntimeInterface::IntrinsicId::WIDE_GETMODULENAMESPACE_PREF_IMM16) { + uint32_t property_name_offset = inst->GetImms()[PROPERTY_NAME_STRING_OFFSET_IDX]; + std::string property_name = ir_interface_->GetStringIdByOffset(property_name_offset); + uint32_t module_namespace_slot = object_inst->CastToIntrinsic()->GetImms()[MODULE_NAMESPACE_SLOT_IDX]; + ConstantValue constant_value; + if (bytecodeopt::BytecodeAnalysisResults::GetModuleNamespaceConstForRecord(record_name_, + module_namespace_slot, + property_name, + constant_value)) { + return GetGraph()->GetLocalAllocator()->New(constant_value); + } + } + } + return BottomElement::GetInstance(); +} + Inst *ConstantPropagation::CreateReplaceInst(Inst *base_inst, ConstantElement *lattice) { - auto const_val = lattice->GetVal(); auto const_type = lattice->GetType(); Inst *replace_inst = nullptr; switch (const_type) { - case ConstantElement::CONSTANT_BOOL: { - auto inst = GetGraph()->CreateInstIntrinsic(compiler::DataType::ANY, base_inst->GetPc(), - std::get(const_val) - ? RuntimeInterface::IntrinsicId::LDTRUE - : RuntimeInterface::IntrinsicId::LDFALSE); + case ConstantValue::CONSTANT_BOOL: { + auto inst_intrinsic_id = lattice->GetValue() ? RuntimeInterface::IntrinsicId::LDTRUE + : RuntimeInterface::IntrinsicId::LDFALSE; + auto inst = GetGraph()->CreateInstIntrinsic(compiler::DataType::ANY, base_inst->GetPc(), inst_intrinsic_id); size_t args_count {1U}; // 1: input count inst->ReserveInputs(args_count); inst->AllocateInputTypes(GetGraph()->GetAllocator(), args_count); - SaveStateInst *save_state_inst = GetGraph()->CreateInstSaveState(); + compiler::SaveStateInst *save_state_inst = GetGraph()->CreateInstSaveState(); save_state_inst->SetPc(base_inst->GetPc()); save_state_inst->SetMethod(GetGraph()->GetMethod()); save_state_inst->ReserveInputs(0); inst->SetFlag(compiler::inst_flags::ACC_WRITE); inst->ClearFlag(compiler::inst_flags::NO_DCE); inst->AppendInput(save_state_inst); - inst->AddInputType(DataType::NO_TYPE); + inst->AddInputType(compiler::DataType::NO_TYPE); InsertSaveState(base_inst, save_state_inst); base_inst->GetBasicBlock()->InsertAfter(inst, save_state_inst); replace_inst = inst; break; } - case ConstantElement::CONSTANT_INT32: { - replace_inst = GetGraph()->FindOrCreateConstant( - static_cast(std::get(const_val))); + case ConstantValue::CONSTANT_INT32: { + replace_inst = GetGraph()->FindOrCreateConstant(static_cast(lattice->GetValue())); break; } - case ConstantElement::CONSTANT_INT64: { - replace_inst = GetGraph()->FindOrCreateConstant( - static_cast(std::get(const_val))); + case ConstantValue::CONSTANT_INT64: { + replace_inst = GetGraph()->FindOrCreateConstant(static_cast(lattice->GetValue())); break; } - - case ConstantElement::CONSTANT_DOUBLE: { - replace_inst = GetGraph()->FindOrCreateConstant(std::get(const_val)); + case ConstantValue::CONSTANT_DOUBLE: { + replace_inst = GetGraph()->FindOrCreateConstant(lattice->GetValue()); break; } - default: UNREACHABLE(); } @@ -548,4 +667,5 @@ void ConstantPropagation::CheckAndAddToSsaEdge(Inst *inst, LatticeElement *curre lattices_[inst] = dst; } } -} // namespace panda::compiler + +} // namespace panda::bytecodeopt diff --git a/compiler/optimizer/optimizations/constant_propagation/constant_propagation.h b/bytecode_optimizer/constant_propagation/constant_propagation.h similarity index 78% rename from compiler/optimizer/optimizations/constant_propagation/constant_propagation.h rename to bytecode_optimizer/constant_propagation/constant_propagation.h index a7273a959a..1466d1d5fc 100644 --- a/compiler/optimizer/optimizations/constant_propagation/constant_propagation.h +++ b/bytecode_optimizer/constant_propagation/constant_propagation.h @@ -26,9 +26,10 @@ * limitations under the License. */ -#ifndef COMPILER_OPTIMIZER_OPTIMIZATIONS_SCCP_H -#define COMPILER_OPTIMIZER_OPTIMIZATIONS_SCCP_H +#ifndef BYTECODE_OPTIMIZER_CONSTANT_PROPAGATION_CONSTANT_PROPAGATION_H +#define BYTECODE_OPTIMIZER_CONSTANT_PROPAGATION_CONSTANT_PROPAGATION_H +#include "bytecode_optimizer/ir_interface.h" #include "compiler/optimizer/ir/basicblock.h" #include "compiler/optimizer/ir/graph.h" #include "compiler/optimizer/ir/graph_visitor.h" @@ -36,10 +37,16 @@ #include "lattice_element.h" #include "utils/hash.h" -namespace panda::compiler { -class ConstantPropagation : public Optimization, public GraphVisitor { +namespace panda::bytecodeopt { + +using compiler::BasicBlock; +using compiler::Inst; +using compiler::Opcode; +using compiler::RuntimeInterface; + +class ConstantPropagation : public compiler::Optimization, public compiler::GraphVisitor { public: - explicit ConstantPropagation(Graph *graph); + explicit ConstantPropagation(compiler::Graph *graph, const BytecodeOptIrInterface *iface); NO_MOVE_SEMANTIC(ConstantPropagation); NO_COPY_SEMANTIC(ConstantPropagation); ~ConstantPropagation() override = default; @@ -85,6 +92,7 @@ protected: static void VisitIfImm(GraphVisitor *v, Inst *inst); static void VisitCompare(GraphVisitor *v, Inst *inst); static void VisitConstant(GraphVisitor *v, Inst *inst); + static void VisitLoadString(GraphVisitor *v, Inst *inst); static void VisitIntrinsic(GraphVisitor *v, Inst *inst); static void VisitCastValueToAnyType(GraphVisitor *v, Inst *inst); @@ -96,17 +104,22 @@ private: void RunFlowEdge(); void VisitInsts(BasicBlock *bb); void AddUntraversedFlowEdges(BasicBlock *src, BasicBlock *dst); - bool GetIfTargetBlock(IfImmInst *inst, uint64_t val); + bool GetIfTargetBlock(compiler::IfImmInst *inst, uint64_t val); LatticeElement *GetOrCreateDefaultLattice(Inst *inst); + LatticeElement *FoldingModuleOperation(compiler::IntrinsicInst *inst); LatticeElement *FoldingConstant(RuntimeInterface::IntrinsicId id); LatticeElement *FoldingConstant(ConstantElement *lattice, RuntimeInterface::IntrinsicId id); LatticeElement *FoldingConstant(ConstantElement *left, ConstantElement *right, RuntimeInterface::IntrinsicId id); - LatticeElement *FoldingCompare(const ConstantElement *left, const ConstantElement *right, ConditionCode cc); + LatticeElement *FoldingCompare(const ConstantElement *left, const ConstantElement *right, + compiler::ConditionCode cc); LatticeElement *FoldingGreater(const ConstantElement *left, const ConstantElement *right, bool equal = false); LatticeElement *FoldingLess(const ConstantElement *left, const ConstantElement *right, bool equal = false); LatticeElement *FoldingEq(const ConstantElement *left, const ConstantElement *right); LatticeElement *FoldingNotEq(const ConstantElement *left, const ConstantElement *right); + LatticeElement *FoldingLdlocalmodulevar(compiler::IntrinsicInst *inst); + LatticeElement *FoldingLdexternalmodulevar(compiler::IntrinsicInst *inst); + LatticeElement *FoldingLdobjbyname(compiler::IntrinsicInst *inst); Inst *CreateReplaceInst(Inst *base_inst, ConstantElement *lattice); void InsertSaveState(Inst *base_inst, Inst *save_state); @@ -118,6 +131,10 @@ private: ArenaQueue ssa_edges_; ArenaUnorderedSet executable_flag_; ArenaUnorderedSet executed_node_; + std::string record_name_; + const BytecodeOptIrInterface *ir_interface_; }; -} // namespace panda::compiler -#endif + +} // namespace panda::bytecodeopt + +#endif // BYTECODE_OPTIMIZER_CONSTANT_PROPAGATION_CONSTANT_PROPAGATION_H diff --git a/bytecode_optimizer/constant_propagation/constant_value.h b/bytecode_optimizer/constant_propagation/constant_value.h new file mode 100644 index 0000000000..bf53c84726 --- /dev/null +++ b/bytecode_optimizer/constant_propagation/constant_value.h @@ -0,0 +1,108 @@ +/** + * Copyright (c) 2024 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 BYTECODE_OPTIMIZER_CONSTANT_PROPAGATION_CONSTANT_VALUE_H +#define BYTECODE_OPTIMIZER_CONSTANT_PROPAGATION_CONSTANT_VALUE_H + +namespace panda::bytecodeopt { + +class ConstantValue { +public: + enum ConstantType { + CONSTANT_BOOL, + CONSTANT_INT32, + CONSTANT_INT64, + CONSTANT_DOUBLE, + CONSTANT_STRING, + CONSTANT_INVALID + }; + + explicit ConstantValue() + : type_(CONSTANT_INVALID), value_() {} + + ConstantValue(const ConstantValue &other) = default; + ConstantValue& operator=(const ConstantValue &other) = default; + ~ConstantValue() = default; + + explicit ConstantValue(bool val) + : type_(CONSTANT_BOOL), value_(val) {} + + explicit ConstantValue(int32_t val) + : type_(CONSTANT_INT32), value_(val) {} + + explicit ConstantValue(int64_t val) + : type_(CONSTANT_INT64), value_(val) {} + + explicit ConstantValue(double val) + : type_(CONSTANT_DOUBLE), value_(val) {} + + explicit ConstantValue(std::string val) + : type_(CONSTANT_STRING), value_(val) {} + + ConstantType GetType() const + { + return type_; + } + + template + T GetValue() const + { + ASSERT(std::holds_alternative(value_)); + return std::get(value_); + } + + auto& GetValue() const + { + return value_; + } + + std::string ToString() + { + std::stringstream ss; + switch (type_) { + case CONSTANT_BOOL: + ss << "[Bool: " << (std::get(value_) ? "True" : "False") << "]"; + break; + case CONSTANT_INT32: + ss << "[Int32: " << std::get(value_) << "]"; + break; + case CONSTANT_INT64: + ss << "[Int64: " << std::get(value_) << "]"; + break; + case CONSTANT_DOUBLE: + ss << "[Double: " << std::get(value_) << "]"; + break; + case CONSTANT_STRING: + ss << "[String: " << std::get(value_) << "]"; + break; + default: + ss << "[INVALID]"; + } + return ss.str(); + } + + bool operator==(const ConstantValue &other) const noexcept + { + return type_ == other.type_ && value_ == other.value_; + } + +private: + ConstantType type_; + std::variant value_; +}; + +} // namespace panda::bytecodeopt + +#endif // BYTECODE_OPTIMIZER_CONSTANT_PROPAGATION_CONSTANT_VALUE_H diff --git a/compiler/optimizer/optimizations/constant_propagation/lattice_element.cpp b/bytecode_optimizer/constant_propagation/lattice_element.cpp similarity index 79% rename from compiler/optimizer/optimizations/constant_propagation/lattice_element.cpp rename to bytecode_optimizer/constant_propagation/lattice_element.cpp index d6c15005a0..8bf6145d8a 100644 --- a/compiler/optimizer/optimizations/constant_propagation/lattice_element.cpp +++ b/bytecode_optimizer/constant_propagation/lattice_element.cpp @@ -28,7 +28,8 @@ #include "constant_propagation.h" -namespace panda::compiler { +namespace panda::bytecodeopt { + LatticeElement::LatticeElement(LatticeType type) : type_(type) {} TopElement::TopElement() : LatticeElement(LatticeType::LATTICE_TOP) {} @@ -68,22 +69,32 @@ std::string BottomElement::ToString() } ConstantElement::ConstantElement(bool val) - : LatticeElement(LatticeType::LATTICE_CONSTANT), type_(ConstantType::CONSTANT_BOOL), val_(val) + : LatticeElement(LatticeType::LATTICE_CONSTANT), value_(val) { } ConstantElement::ConstantElement(int32_t val) - : LatticeElement(LatticeType::LATTICE_CONSTANT), type_(ConstantType::CONSTANT_INT32), val_(val) + : LatticeElement(LatticeType::LATTICE_CONSTANT), value_(val) { } ConstantElement::ConstantElement(int64_t val) - : LatticeElement(LatticeType::LATTICE_CONSTANT), type_(ConstantType::CONSTANT_INT64), val_(val) + : LatticeElement(LatticeType::LATTICE_CONSTANT), value_(val) { } ConstantElement::ConstantElement(double val) - : LatticeElement(LatticeType::LATTICE_CONSTANT), type_(ConstantType::CONSTANT_DOUBLE), val_(val) + : LatticeElement(LatticeType::LATTICE_CONSTANT), value_(val) +{ +} + +ConstantElement::ConstantElement(std::string val) + : LatticeElement(LatticeType::LATTICE_CONSTANT), value_(val) +{ +} + +ConstantElement::ConstantElement(const ConstantValue &val) + : LatticeElement(LatticeType::LATTICE_CONSTANT), value_(val) { } @@ -96,7 +107,7 @@ LatticeElement *ConstantElement::Meet(LatticeElement *other) return other; } - if ((type_ == other->AsConstant()->GetType()) && (val_ == other->AsConstant()->GetVal())) { + if (value_ == other->AsConstant()->value_) { return this; } @@ -105,11 +116,12 @@ LatticeElement *ConstantElement::Meet(LatticeElement *other) std::string ConstantElement::ToString() { - return "Constant"; + return "Constant: " + value_.ToString(); } ConstantElement *ConstantElement::AsConstant() { return this; } -} // namespace panda::compiler + +} // namespace panda::bytecodeopt diff --git a/compiler/optimizer/optimizations/constant_propagation/lattice_element.h b/bytecode_optimizer/constant_propagation/lattice_element.h similarity index 83% rename from compiler/optimizer/optimizations/constant_propagation/lattice_element.h rename to bytecode_optimizer/constant_propagation/lattice_element.h index fe36b2fee6..48be34dc96 100644 --- a/compiler/optimizer/optimizations/constant_propagation/lattice_element.h +++ b/bytecode_optimizer/constant_propagation/lattice_element.h @@ -26,17 +26,19 @@ * limitations under the License. */ -#ifndef COMPILER_OPTIMIZER_OPTIMIZATIONS_LATTICE_H -#define COMPILER_OPTIMIZER_OPTIMIZATIONS_LATTICE_H +#ifndef BYTECODE_OPTIMIZER_CONSTANT_PROPAGATION_LATTICE_ELEMENT_H +#define BYTECODE_OPTIMIZER_CONSTANT_PROPAGATION_LATTICE_ELEMENT_H #include #include "compiler/optimizer/ir/basicblock.h" #include "compiler/optimizer/ir/graph.h" #include "compiler/optimizer/ir/graph_visitor.h" #include "compiler/optimizer/pass.h" +#include "constant_value.h" #include "utils/hash.h" -namespace panda::compiler { +namespace panda::bytecodeopt { + class ConstantElement; class LatticeElement { public: @@ -106,33 +108,39 @@ protected: class ConstantElement : public LatticeElement { public: - enum ConstantType { CONSTANT_BOOL, CONSTANT_INT32, CONSTANT_INT64, CONSTANT_DOUBLE }; - NO_MOVE_SEMANTIC(ConstantElement); NO_COPY_SEMANTIC(ConstantElement); explicit ConstantElement(bool val); explicit ConstantElement(int32_t val); explicit ConstantElement(int64_t val); explicit ConstantElement(double val); + explicit ConstantElement(std::string val); + explicit ConstantElement(const ConstantValue &val); ~ConstantElement() override = default; LatticeElement *Meet(LatticeElement *other) override; std::string ToString() override; ConstantElement *AsConstant() override; - auto &GetVal() const + template + T GetValue() const { - return val_; + return value_.GetValue(); } - ConstantType GetType() const + auto &GetValue() const { - return type_; + return value_.GetValue(); + } + + ConstantValue::ConstantType GetType() const + { + return value_.GetType(); } private: - ConstantType type_; - std::variant val_; + ConstantValue value_; }; -} // namespace panda::compiler -#endif +} // namespace panda::bytecodeopt + +#endif // BYTECODE_OPTIMIZER_CONSTANT_PROPAGATION_LATTICE_ELEMENT_H diff --git a/bytecode_optimizer/ir_interface.h b/bytecode_optimizer/ir_interface.h index afd945415b..ac26db6ac2 100644 --- a/bytecode_optimizer/ir_interface.h +++ b/bytecode_optimizer/ir_interface.h @@ -148,6 +148,11 @@ public: return prog_ != nullptr ? prog_->lang : panda_file::SourceLang::PANDA_ASSEMBLY; } + pandasm::Program *GetProgram() const + { + return prog_; + } + private: pandasm::Program *prog_ {nullptr}; const pandasm::AsmEmitter::PandaFileToPandaAsmMaps *maps_ {nullptr}; diff --git a/bytecode_optimizer/module_constant_analyzer.cpp b/bytecode_optimizer/module_constant_analyzer.cpp new file mode 100644 index 0000000000..a3df5daa0d --- /dev/null +++ b/bytecode_optimizer/module_constant_analyzer.cpp @@ -0,0 +1,139 @@ +/** + * Copyright (c) 2024 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. + */ + +#include "module_constant_analyzer.h" +#include "bytecode_optimizer/constant_propagation/constant_value.h" +#include "compiler/optimizer/ir/graph.h" +#include "compiler/optimizer/ir/runtime_interface.h" + +namespace panda::bytecodeopt { + +ModuleConstantAnalyzer::ModuleConstantAnalyzer(compiler::Graph *graph, + const std::unordered_set &const_local_export_slots, + ModuleConstantAnalysisResult &analysis_result, + const BytecodeOptIrInterface *iface) + : Analysis(graph), + const_local_export_slots_(const_local_export_slots), + analysis_result_(analysis_result), + ir_interface_(iface) +{ +} + +bool ModuleConstantAnalyzer::RunImpl() +{ + VisitGraph(); + return true; +} + +void ModuleConstantAnalyzer::VisitIntrinsic(compiler::GraphVisitor *visitor, compiler::Inst *inst) +{ + constexpr int STMODULEVAR_VALUE_INPUT_INDEX = 0; + constexpr int STMODULEVAR_SLOT_NUMBER_IMM_INDEX = 0; + auto module_constant_analyzer = static_cast(visitor); + auto intrinsic_inst = inst->CastToIntrinsic(); + auto id = intrinsic_inst->GetIntrinsicId(); + switch (id) { + case RuntimeInterface::IntrinsicId::STMODULEVAR_IMM8: + case RuntimeInterface::IntrinsicId::WIDE_STMODULEVAR_PREF_IMM16: { + int module_var_slot = intrinsic_inst->GetImms()[STMODULEVAR_SLOT_NUMBER_IMM_INDEX]; + if (!module_constant_analyzer->IsConstModuleVar(module_var_slot)) { + break; + } + auto input_inst = inst->GetDataFlowInput(STMODULEVAR_VALUE_INPUT_INDEX); + auto input_const_value = module_constant_analyzer->GetInstConstValue(input_inst); + if (input_const_value != nullptr) { + module_constant_analyzer->RecordModuleConstValue(module_var_slot, input_const_value); + } + break; + } + default: + break; + } +} + +ConstantValue *ModuleConstantAnalyzer::GetInstConstValue(Inst *inst) +{ + switch (inst->GetOpcode()) { + case Opcode::Constant: + return GetConstantInstConstValue(inst->CastToConstant()); + case Opcode::Intrinsic: + return GetIntrinsicInstConstValue(inst->CastToIntrinsic()); + case Opcode::LoadString: + return GetLoadStringInstConstValue(inst->CastToLoadString()); + case Opcode::CastValueToAnyType: + // According to inst_builder.cpp: + // 1. the fldai bytecode generates Constant(double) -> CastValueToAnyType, + // 1. the lda.str bytecode generates LoadString -> CastValueToAnyType, + // We handle such case here. 0 stands for the DataFlowInput corresponding to the Constant/LoadString + if (inst->GetDataFlowInput(0)->IsConst() || + inst->GetDataFlowInput(0)->GetOpcode() == compiler::Opcode::LoadString) { + return GetInstConstValue(inst->GetDataFlowInput(0)); + } + return nullptr; + default: + return nullptr; + } +} + +ConstantValue *ModuleConstantAnalyzer::GetConstantInstConstValue(compiler::ConstantInst *const_inst) +{ + switch (const_inst->GetType()) { + case compiler::DataType::INT32: { + auto val = static_cast(const_inst->GetInt32Value()); + return GetGraph()->GetAllocator()->New(val); + } + case compiler::DataType::INT64: { + auto val = static_cast(const_inst->GetRawValue()); + return GetGraph()->GetAllocator()->New(val); + } + case compiler::DataType::FLOAT64: { + auto val = const_inst->GetDoubleValue(); + return GetGraph()->GetAllocator()->New(val); + } + default: + UNREACHABLE(); + } +} + +ConstantValue *ModuleConstantAnalyzer::GetIntrinsicInstConstValue(compiler::IntrinsicInst *intrinsic_inst) +{ + switch (intrinsic_inst->GetIntrinsicId()) { + case RuntimeInterface::IntrinsicId::LDTRUE: + case RuntimeInterface::IntrinsicId::LDFALSE: { + bool is_true = intrinsic_inst->GetIntrinsicId() == RuntimeInterface::IntrinsicId::LDTRUE; + return GetGraph()->GetAllocator()->New(is_true); + } + default: + return nullptr; + } +} + +ConstantValue *ModuleConstantAnalyzer::GetLoadStringInstConstValue(compiler::LoadFromPool *inst) +{ + return GetGraph()->GetAllocator()->New( + ir_interface_->GetStringIdByOffset(inst->GetTypeId())); +} + +bool ModuleConstantAnalyzer::IsConstModuleVar(uint32_t slot) +{ + return const_local_export_slots_.count(slot) == 1; +} + +void ModuleConstantAnalyzer::RecordModuleConstValue(uint32_t slot, ConstantValue *value) +{ + analysis_result_.emplace(slot, value); +} + +} // namespace panda::bytecodeopt \ No newline at end of file diff --git a/bytecode_optimizer/module_constant_analyzer.h b/bytecode_optimizer/module_constant_analyzer.h new file mode 100644 index 0000000000..f8785252aa --- /dev/null +++ b/bytecode_optimizer/module_constant_analyzer.h @@ -0,0 +1,86 @@ +/** + * Copyright (c) 2021-2022 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 BYTECODE_OPTIMIZER_MODULE_CONSTANT_ANALYZER_H +#define BYTECODE_OPTIMIZER_MODULE_CONSTANT_ANALYZER_H + +#include +#include "bytecode_optimizer/ir_interface.h" +#include "compiler/optimizer/pass.h" +#include "compiler/optimizer/ir/graph.h" +#include "compiler/optimizer/ir/graph_visitor.h" +#include "libpandabase/utils/arena_containers.h" + +namespace panda::bytecodeopt { + +using compiler::BasicBlock; +using compiler::Inst; +using compiler::Opcode; +using compiler::RuntimeInterface; + +class ConstantValue; + +using ModuleConstantAnalysisResult = std::unordered_map; + +/* + * ModuleConstantAnalyzer is used to scan the IR of the given function, and + * analysis the initial value of all module constants (represented in + * BytecodeAnalysisResult for now, extracts from bytecode later after new + * stconstmodulevar instruction is enabled) + */ +class ModuleConstantAnalyzer : public compiler::Analysis, public compiler::GraphVisitor { +public: + explicit ModuleConstantAnalyzer(compiler::Graph *graph, + const std::unordered_set &const_local_export_slots, + ModuleConstantAnalysisResult &analysis_result, + const BytecodeOptIrInterface *iface); + + NO_MOVE_SEMANTIC(ModuleConstantAnalyzer); + NO_COPY_SEMANTIC(ModuleConstantAnalyzer); + ~ModuleConstantAnalyzer() override = default; + + const char *GetPassName() const override + { + return "ModuleConstantAnalysis"; + } + + bool RunImpl() override; + + const ArenaVector &GetBlocksToVisit() const override + { + return GetGraph()->GetBlocksRPO(); + } + +protected: + static void VisitIntrinsic(GraphVisitor *v, Inst *inst); + +#include "compiler/optimizer/ir/visitor.inc" + +private: + ConstantValue *GetInstConstValue(Inst *inst); + ConstantValue *GetConstantInstConstValue(compiler::ConstantInst *inst); + ConstantValue *GetIntrinsicInstConstValue(compiler::IntrinsicInst *inst); + ConstantValue *GetLoadStringInstConstValue(compiler::LoadFromPool *inst); + bool IsConstModuleVar(uint32_t slot); + void RecordModuleConstValue(uint32_t slot, ConstantValue *value); + + const std::unordered_set &const_local_export_slots_; + ModuleConstantAnalysisResult &analysis_result_; + const BytecodeOptIrInterface *ir_interface_; +}; + +} // namespace panda::bytecodeopt + +#endif // BYTECODE_OPTIMIZER_MODULE_CONSTANT_ANALYZER_H \ No newline at end of file diff --git a/bytecode_optimizer/optimize_bytecode.cpp b/bytecode_optimizer/optimize_bytecode.cpp index 7312cdde11..311743b482 100644 --- a/bytecode_optimizer/optimize_bytecode.cpp +++ b/bytecode_optimizer/optimize_bytecode.cpp @@ -19,6 +19,7 @@ #include "assembler/extensions/extensions.h" #include "bytecode_instruction.h" #include "bytecodeopt_options.h" +#include "bytecode_analysis_results.h" #include "codegen.h" #include "common.h" #include "compiler/optimizer/ir/constants.h" @@ -26,16 +27,19 @@ #include "compiler/optimizer/ir_builder/pbc_iterator.h" #include "compiler/optimizer/optimizations/branch_elimination.h" #include "compiler/optimizer/optimizations/cleanup.h" -#include "compiler/optimizer/optimizations/constant_propagation/constant_propagation.h" #include "compiler/optimizer/optimizations/lowering.h" #include "compiler/optimizer/optimizations/move_constants.h" #include "compiler/optimizer/optimizations/regalloc/reg_alloc.h" #include "compiler/optimizer/optimizations/vn.h" +#include "constant_propagation/constant_propagation.h" #include "libpandabase/mem/arena_allocator.h" #include "libpandabase/mem/pool_manager.h" #include "libpandafile/class_data_accessor.h" #include "libpandafile/class_data_accessor-inl.h" #include "libpandafile/method_data_accessor.h" +#include "libpandafile/field_data_accessor.h" +#include "libpandafile/module_data_accessor-inl.h" +#include "module_constant_analyzer.h" #include "reg_acc_alloc.h" #include "reg_encoder.h" #include "runtime_adapter.h" @@ -72,7 +76,7 @@ bool RunOptimizations(compiler::Graph *graph, BytecodeOptIrInterface *iface) ASSERT(graph->IsDynamicMethod()); if (compiler::options.IsCompilerBranchElimination()) { - RunOpts(graph); + graph->RunPass(iface); RunOpts(graph); } @@ -216,7 +220,205 @@ static void SetCompilerOptions(bool is_dynamic) if (is_dynamic) { panda::bytecodeopt::options.SetSkipMethodsWithEh(true); } - compiler::options.SetCompilerBranchElimination(false); +} + +static bool StringStartsWith(const std::string &str, const std::string &prefix) +{ + return (str.size() >= prefix.size()) && + std::equal(prefix.begin(), prefix.end(), str.begin()); +} + +static std::string ModuleRequestOffsetToRecordName(const panda_file::File &pfile, + uint32_t module_request_offset) +{ + constexpr char AND_TOKEN = '&'; + const std::string BUNDLE_PREFIX = "@bundle:"; + const std::string PACKAGE_PREFIX = "@package:"; + const std::string NORMALIZED_NON_NATIVE_PREFIX = "@normalized:N&"; + + auto record_ohmurl = GetStringFromPandaFile(pfile, module_request_offset); + // Assumptions of the current possible ohmurl formats: + // @bundle:record_name + // @package:record_name + // @normalized:N&xxxx&record_name + // Extract record_name from each possible cases. + if (StringStartsWith(record_ohmurl, BUNDLE_PREFIX)) { + return record_ohmurl.substr(BUNDLE_PREFIX.size()); + } else if (StringStartsWith(record_ohmurl, PACKAGE_PREFIX)) { + return record_ohmurl.substr(PACKAGE_PREFIX.size()); + } else if (StringStartsWith(record_ohmurl, NORMALIZED_NON_NATIVE_PREFIX)) { + size_t second_and_pos = record_ohmurl.find(AND_TOKEN, NORMALIZED_NON_NATIVE_PREFIX.size()); + if (second_and_pos != std::string::npos) { + return record_ohmurl.substr(second_and_pos + 1); + } + } + // Otherwise, return empty string to represent no ohmurl is found + return ""; +} + +static void AnalysisModuleRecordInfoOfModuleDataAccessor(const panda_file::File &pfile, + panda_file::ModuleDataAccessor &mda, + BytecodeAnalysisResult &result) +{ + const auto &request_modules_offsets = mda.getRequestModules(); + int regular_import_idx = 0; + std::unordered_set local_export_local_names; + mda.EnumerateModuleRecord([&](panda_file::ModuleTag tag, uint32_t export_name_offset, + uint32_t request_module_idx, uint32_t import_name_offset, + uint32_t local_name_offset) { + switch (tag) { + case panda_file::ModuleTag::LOCAL_EXPORT: { + std::string export_name = GetStringFromPandaFile(pfile, export_name_offset); + std::string local_name = GetStringFromPandaFile(pfile, local_name_offset); + // Slot of stmodulevar/ldlocalmodulevar is the index of its local name, while + // one local name can match multiple external names with "export...as...". + // Local export entries are sorted by their local name, thus using an unrodered_set + // can get the correct index form (size - 1) (starts from 0). + // See SourceTextModuleRecord::AssignIndexToModuleVariable for more details + local_export_local_names.insert(local_name); + result.SetLocalExportInfo(local_export_local_names.size() - 1, export_name); + break; + } + case panda_file::ModuleTag::REGULAR_IMPORT: { + std::string request_module_name = + ModuleRequestOffsetToRecordName(pfile, request_modules_offsets[request_module_idx]); + if (!request_module_name.empty()) { + std::string import_name = GetStringFromPandaFile(pfile, import_name_offset); + result.SetRegularImportInfo(regular_import_idx, import_name, request_module_name); + } + regular_import_idx++; + break; + } + case panda_file::ModuleTag::NAMESPACE_IMPORT: { + // Slot of getmodulenamespace bytecode is its request_module_idx + std::string namespace_name = + ModuleRequestOffsetToRecordName(pfile, request_modules_offsets[request_module_idx]); + if (!namespace_name.empty()) { + result.SetNamespaceImportInfo(request_module_idx, namespace_name); + } + break; + } + default: + break; + } + }); +} + +static void AnalysisModuleRecordInfo(const panda_file::File &pfile, + panda_file::ClassDataAccessor &cda, + BytecodeAnalysisResult &result) +{ + const std::string MODULE_RECORD_IDX_FIELD_NAME = "moduleRecordIdx"; + // RequireGlobalOptimization is true only under mergeAbc mode, where module record is stored + // in the moduleRecordIdx field according to Emitter::AddSourceTextModuleRecord + cda.EnumerateFields([&](panda_file::FieldDataAccessor &fda) -> void { + if (fda.IsExternal()) { + return; + } + std::string field_name = GetStringFromPandaFile(pfile, fda.GetNameId().GetOffset()); + if (field_name == MODULE_RECORD_IDX_FIELD_NAME) { + panda_file::File::EntityId module_entity_id(fda.GetValue().value()); + panda_file::ModuleDataAccessor mda(pfile, module_entity_id); + AnalysisModuleRecordInfoOfModuleDataAccessor(pfile, mda, result); + } + }); +} + +static void AnalysisModuleConstantValue(panda_file::ClassDataAccessor &cda, const std::string &record_name, + bool is_dynamic, const BytecodeOptIrInterface &ir_interface, + BytecodeAnalysisResult &result) +{ + const std::string MAIN_METHOD_NAME = ".func_main_0"; + cda.EnumerateMethods([MAIN_METHOD_NAME, record_name, is_dynamic, ir_interface, &result]( + panda_file::MethodDataAccessor &mda) { + if (mda.IsExternal()) { + return false; + } + + // Only analysis func_main_0 for now, since the assignment instruction of all exported constants + // are in func_main_0, and the bytecode analysis phase only contains analysing initial value of + // module constants for branch-elimination for now + auto func_name = ir_interface.GetMethodIdByOffset(mda.GetMethodId().GetOffset()); + if (func_name != record_name + MAIN_METHOD_NAME) { + return true; + } + + ArenaAllocator allocator {SpaceType::SPACE_TYPE_COMPILER}; + ArenaAllocator local_allocator {SpaceType::SPACE_TYPE_COMPILER, nullptr, true}; + + auto *prog = ir_interface.GetProgram(); + auto it = prog->function_table.find(func_name); + if (it == prog->function_table.end()) { + LOG(ERROR, BYTECODE_OPTIMIZER) << "Cannot find function: " << func_name; + return false; + } + + panda::pandasm::Function &function = it->second; + if (SkipFunction(function, func_name)) { + return false; + } + + auto method_ptr = reinterpret_cast(mda.GetMethodId().GetOffset()); + panda::BytecodeOptimizerRuntimeAdapter adapter(mda.GetPandaFile()); + auto graph = allocator.New(&allocator, &local_allocator, Arch::NONE, method_ptr, &adapter, + false, nullptr, is_dynamic, true); + if ((graph == nullptr) || !graph->RunPass()) { + LOG(ERROR, BYTECODE_OPTIMIZER) << "Analysis " << func_name << ": IR builder failed!"; + return false; + } + + ModuleConstantAnalysisResult module_constant_results; + ModuleConstantAnalyzer analyzer(graph, result.GetConstantLocalExportSlots(), + module_constant_results, &ir_interface); + graph->RunPass(&analyzer); + result.SetModuleConstantAnalysisResult(module_constant_results); + return true; + }); +} + +bool AnalysisBytecode(pandasm::Program *prog, const pandasm::AsmEmitter::PandaFileToPandaAsmMaps *maps, + const std::string &pfile_name, bool is_dynamic, bool has_memory_pool) +{ + if (!has_memory_pool) { + PoolManager::Initialize(PoolType::MALLOC); + } + + auto pfile = panda_file::OpenPandaFile(pfile_name); + if (!pfile) { + LOG(FATAL, BYTECODE_OPTIMIZER) << "Can not open binary file: " << pfile_name; + return false; + } + + for (uint32_t id : pfile->GetClasses()) { + panda_file::File::EntityId record_id {id}; + + if (pfile->IsExternal(record_id)) { + continue; + } + + panda_file::ClassDataAccessor cda {*pfile, record_id}; + // Skip annotation records since they do not contain real code for now + if (cda.IsAnnotation()) { + continue; + } + std::string record_type_descriptor(utf::Mutf8AsCString(cda.GetName().data)); + std::string record_name = pandasm::Type::FromDescriptor(record_type_descriptor).GetName(); + + bool exists = false; + auto &result = BytecodeAnalysisResults::GetOrCreateBytecodeAnalysisResult(record_name, exists); + if (exists) { + return true; + } + auto ir_interface = BytecodeOptIrInterface(maps, prog); + AnalysisModuleRecordInfo(*pfile, cda, result); + AnalysisModuleConstantValue(cda, record_name, is_dynamic, ir_interface, result); + } + + if (!has_memory_pool) { + PoolManager::Finalize(); + } + + return true; } bool OptimizeFunction(pandasm::Program *prog, const pandasm::AsmEmitter::PandaFileToPandaAsmMaps *maps, diff --git a/bytecode_optimizer/optimize_bytecode.h b/bytecode_optimizer/optimize_bytecode.h index bc9e5be518..a8fe35321c 100644 --- a/bytecode_optimizer/optimize_bytecode.h +++ b/bytecode_optimizer/optimize_bytecode.h @@ -22,6 +22,8 @@ #include "ir_interface.h" namespace panda::bytecodeopt { +bool AnalysisBytecode(pandasm::Program *prog, const pandasm::AsmEmitter::PandaFileToPandaAsmMaps *maps, + const std::string &pandafile_name, bool is_dynamic = false, bool has_memory_pool = false); bool RunOptimizations(compiler::Graph *graph, BytecodeOptIrInterface *iface = nullptr); bool OptimizeBytecode(pandasm::Program *prog, const pandasm::AsmEmitter::PandaFileToPandaAsmMaps *maps, const std::string &pandafile_name, bool is_dynamic = false, bool has_memory_pool = false); diff --git a/bytecode_optimizer/runtime_adapter.h b/bytecode_optimizer/runtime_adapter.h index 5f349a15a5..05f5e6815a 100644 --- a/bytecode_optimizer/runtime_adapter.h +++ b/bytecode_optimizer/runtime_adapter.h @@ -22,6 +22,7 @@ #include "libpandafile/code_data_accessor.h" #include "libpandafile/field_data_accessor.h" #include "libpandafile/file.h" +#include "libpandafile/file-inl.h" #include "libpandafile/file_items.h" #include "libpandafile/method_data_accessor.h" #include "libpandafile/proto_data_accessor.h" diff --git a/bytecode_optimizer/tests/BUILD.gn b/bytecode_optimizer/tests/BUILD.gn index 65c164700a..9b5d9f476e 100644 --- a/bytecode_optimizer/tests/BUILD.gn +++ b/bytecode_optimizer/tests/BUILD.gn @@ -19,6 +19,7 @@ module_out_path = "$ark_root/bytecode_optimizer" bcopt_test_config = [ "$ark_root:ark_config", + "$ark_root/abc2program:abc2program_public_config", "$ark_root/assembler:arkassembler_public_config", "$ark_root/libpandabase:arkbase_public_config", "$ark_root/libpandafile:arkfile_public_config", @@ -28,6 +29,7 @@ bcopt_test_config = [ ] bcopt_test_deps = [ + "$ark_root/abc2program:abc2program", "$ark_root/assembler:libarkassembler", "$ark_root/bytecode_optimizer:libarkbytecodeopt", "$ark_root/compiler:libarkcompiler", @@ -55,10 +57,36 @@ foreach(file, graph_test_js_files) { } } +graph_test_js_files_un_opt = [ + "bytecodeAnalysis", + "constantProgagation", +] + +foreach(file, graph_test_js_files_un_opt) { + es2abc_gen_abc("gen_${file}_abc") { + test_js = "${test_js_path}${file}.js" + test_abc = "$target_out_dir/${file}.abc" + + src_js = rebase_path(test_js) + dst_file = rebase_path(test_abc) + + in_puts = [ test_js ] + out_puts = [ test_abc ] + + extra_args = [ + "--debug", + "--module", + "--merge-abc", + ] + } +} + host_unittest_action("BytecodeOptimizerTest") { module_out_path = module_output_path sources = [ + "analysis_bytecode_test.cpp", "codegen_test.cpp", + "constant_propagation_test.cpp", "excluded_keys_test.cpp", "optimize_bytecode_test.cpp", "reg_encoder_test.cpp", @@ -73,6 +101,9 @@ host_unittest_action("BytecodeOptimizerTest") { foreach(file, graph_test_js_files) { deps += [ ":gen_${file}_abc" ] } + foreach(file, graph_test_js_files_un_opt) { + deps += [ ":gen_${file}_abc" ] + } defines += [ "ARK_INTRINSIC_SET", diff --git a/bytecode_optimizer/tests/analysis_bytecode_test.cpp b/bytecode_optimizer/tests/analysis_bytecode_test.cpp new file mode 100644 index 0000000000..d7a1fba73c --- /dev/null +++ b/bytecode_optimizer/tests/analysis_bytecode_test.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2024 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. + */ + +#include +#include + +#include "abc2program/abc2program_driver.h" +#include "assembler/assembly-emitter.h" +#include "bytecode_optimizer/bytecode_analysis_results.h" +#include "bytecode_optimizer/module_constant_analyzer.h" +#include "bytecode_optimizer/optimize_bytecode.h" +#include "mem/pool_manager.h" + +using namespace testing::ext; + +namespace panda::bytecodeopt { +class AnalysisBytecodeTest : public testing::Test { +public: + static void SetUpTestCase(void) {} + static void TearDownTestCase(void) {} + void SetUp() + { + compiler::options.SetCompilerUseSafepoint(false); + compiler::options.SetCompilerSupportInitObjectInst(true); + } + void TearDown() {} +}; + +/** + * @tc.name: analysis_bytecode_test_001 + * @tc.desc: Verify the AnalysisBytecode function. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(AnalysisBytecodeTest, analysis_bytecode_test_001, TestSize.Level1) +{ + const std::string RECORD_NAME = "bytecodeAnalysis"; + const std::string TEST_FILE_NAME = std::string(GRAPH_TEST_ABC_DIR) + RECORD_NAME + ".abc"; + const std::unordered_set const_slots = {0, 1}; + const std::string SOURCE_RECORD_MYAPP_TEST = "myapp/test"; + const std::string SOURCE_RECORD_NORMALIZED_MYAPP_TEST = "bundle&myapp/test&"; + const std::string ABC_FILE_NAME = "bytecodeAnalysis.unopt.abc"; + const std::string MOCK_CONST_NAME = "i"; + const std::string MOCK_CONST_VALUE = "0"; + constexpr uint32_t MOCK_SLOT = 0; + + bool exists = false; + auto &result = BytecodeAnalysisResults::GetOrCreateBytecodeAnalysisResult(RECORD_NAME, exists); + result.SetConstantLocalExportSlots(const_slots); + EXPECT_FALSE(exists); + + bool ignored; + auto &source_result = + BytecodeAnalysisResults::GetOrCreateBytecodeAnalysisResult(SOURCE_RECORD_MYAPP_TEST, ignored); + ModuleConstantAnalysisResult mock_result; + ConstantValue mock_value(MOCK_CONST_VALUE); + mock_result[0] = &mock_value; + source_result.SetLocalExportInfo(MOCK_SLOT, MOCK_CONST_NAME); + source_result.SetModuleConstantAnalysisResult(mock_result); + + auto &source_result_normalized = + BytecodeAnalysisResults::GetOrCreateBytecodeAnalysisResult(SOURCE_RECORD_NORMALIZED_MYAPP_TEST, ignored); + source_result_normalized.SetLocalExportInfo(MOCK_SLOT, MOCK_CONST_NAME); + source_result_normalized.SetModuleConstantAnalysisResult(mock_result); + + abc2program::Abc2ProgramDriver driver; + ASSERT_TRUE(driver.Compile(TEST_FILE_NAME)); + auto &program = driver.GetProgram(); + panda::pandasm::AsmEmitter::PandaFileToPandaAsmMaps panda_file_to_asm_maps {}; + EXPECT_TRUE(panda::pandasm::AsmEmitter::Emit(ABC_FILE_NAME, program, nullptr, &panda_file_to_asm_maps, false)); + EXPECT_TRUE(panda::bytecodeopt::AnalysisBytecode(const_cast(&program), + &panda_file_to_asm_maps, ABC_FILE_NAME, true, false)); + + ConstantValue analysis_result_value; + + // slot 0: module variable a, Constant(INT32, 1) + EXPECT_TRUE(BytecodeAnalysisResults::GetLocalExportConstForRecord(RECORD_NAME, 0, analysis_result_value)); + EXPECT_TRUE(analysis_result_value == ConstantValue(static_cast(1))); + + // slot 1: module variable b, Constant(INT32, 2) + EXPECT_TRUE(BytecodeAnalysisResults::GetLocalExportConstForRecord(RECORD_NAME, 1, analysis_result_value)); + EXPECT_TRUE(analysis_result_value == ConstantValue(static_cast(2))); + + // slot 0: module variable i1, MOCK_CONST_VALUE + EXPECT_TRUE(BytecodeAnalysisResults::GetRegularImportConstForRecord(RECORD_NAME, 0, analysis_result_value)); + EXPECT_TRUE(analysis_result_value == ConstantValue(MOCK_CONST_VALUE)); + + // slot 1: module variable i2, MOCK_CONST_VALUE + EXPECT_TRUE(BytecodeAnalysisResults::GetRegularImportConstForRecord(RECORD_NAME, 1, analysis_result_value)); + EXPECT_TRUE(analysis_result_value == ConstantValue(MOCK_CONST_VALUE)); + + // slot 2: module variable i3, MOCK_CONST_VALUE + EXPECT_TRUE(BytecodeAnalysisResults::GetRegularImportConstForRecord(RECORD_NAME, 2, analysis_result_value)); + EXPECT_TRUE(analysis_result_value == ConstantValue(MOCK_CONST_VALUE)); + + // slot 3: module variable i4, MOCK_CONST_VALUE + EXPECT_FALSE(BytecodeAnalysisResults::GetRegularImportConstForRecord(RECORD_NAME, 3, analysis_result_value)); + + // namespace import m4.i + EXPECT_TRUE(BytecodeAnalysisResults::GetModuleNamespaceConstForRecord( + RECORD_NAME, 0, MOCK_CONST_NAME, analysis_result_value)); + EXPECT_TRUE(analysis_result_value == ConstantValue(MOCK_CONST_VALUE)); +} +} // namespace panda::bytecodeopt \ No newline at end of file diff --git a/bytecode_optimizer/tests/constant_propagation_test.cpp b/bytecode_optimizer/tests/constant_propagation_test.cpp new file mode 100644 index 0000000000..a06585b9b0 --- /dev/null +++ b/bytecode_optimizer/tests/constant_propagation_test.cpp @@ -0,0 +1,537 @@ +/* + * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development 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. + * + * Copyright (c) 2024 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. + */ + +#include + +#include "assembler/assembly-emitter.h" +#include "bytecode_optimizer/constant_propagation/constant_propagation.h" +#include "compiler/optimizer/ir/basicblock.h" +#include "compiler/optimizer/ir/graph.h" +#include "compiler/tests/graph_test.h" +#include "mem/pool_manager.h" +#include "optimizer/analysis/dominators_tree.h" +#include "optimizer/optimizations/cleanup.h" + +using namespace testing::ext; + +namespace panda::bytecodeopt { + +enum class ExpectType { + EXPECT_LDTRUE, + EXPECT_LDFALSE, + EXPECT_BOTH_TRUE_FALSE, + EXPECT_CONST, + EXPECT_PHI, + EXPECT_OTHER, +}; + +static void VisitBlock(compiler::BasicBlock *bb, ExpectType type); + +class ConstantProgagationTest : public testing::Test { +public: + static void SetUpTestCase(void) {} + static void TearDownTestCase(void) {} + void SetUp() {} + void TearDown() {} + + compiler::GraphTest graph_test_; + + bool CheckFunction(const std::string &file, const char *test_method_name, ExpectType before, ExpectType after, + std::unordered_map *strings = nullptr) + { + bool status = false; + + graph_test_.TestBuildGraphFromFile(file, [test_method_name, before, after, strings, &status] + (compiler::Graph *graph, std::string &method_name) { + if (test_method_name != method_name) { + return; + } + status = true; + EXPECT_NE(graph, nullptr); + EXPECT_TRUE(graph->RunPass()); + EXPECT_TRUE(graph->RunPass()); + auto &bbs = graph->GetVectorBlocks(); + for (auto bb : bbs) { + VisitBlock(bb, before); + } + + pandasm::AsmEmitter::PandaFileToPandaAsmMaps maps; + pandasm::Program *prog = nullptr; + if (strings != nullptr) { + maps.strings = *strings; + } + BytecodeOptIrInterface interface(&maps, prog); + EXPECT_TRUE(graph->RunPass(&interface)); + auto modified = graph->RunPass(); + if (before != after) { + EXPECT_TRUE(modified); + } + for (auto bb : bbs) { + VisitBlock(bb, after); + } + }); + return status; + } +}; + +static void VisitBlock(BasicBlock *bb, ExpectType type) +{ + if (!bb) { + return; + } + for (auto inst : bb->Insts()) { + if (!inst->IsIntrinsic() || + inst->CastToIntrinsic()->GetIntrinsicId() != RuntimeInterface::IntrinsicId::CALLARG1_IMM8_V8) { + continue; + } + auto input = inst->GetInput(0).GetInst(); + + switch (type) { + case ExpectType::EXPECT_CONST: + ASSERT_TRUE(input->IsConst()); + break; + case ExpectType::EXPECT_PHI: + ASSERT_TRUE(input->IsPhi()); + break; + case ExpectType::EXPECT_LDTRUE: { + ASSERT_TRUE(input->IsIntrinsic()); + auto id = input->CastToIntrinsic()->GetIntrinsicId(); + EXPECT_TRUE(id == RuntimeInterface::IntrinsicId::LDTRUE); + break; + } + case ExpectType::EXPECT_LDFALSE: { + ASSERT_TRUE(input->IsIntrinsic()); + auto id = input->CastToIntrinsic()->GetIntrinsicId(); + EXPECT_TRUE(id == RuntimeInterface::IntrinsicId::LDFALSE); + break; + } + case ExpectType::EXPECT_BOTH_TRUE_FALSE: { + ASSERT_TRUE(input->IsIntrinsic()); + auto id = input->CastToIntrinsic()->GetIntrinsicId(); + EXPECT_TRUE(id == RuntimeInterface::IntrinsicId::LDFALSE || + id == RuntimeInterface::IntrinsicId::LDTRUE); + break; + } + case ExpectType::EXPECT_OTHER: { + ASSERT_TRUE(input->IsIntrinsic()); + auto id = input->CastToIntrinsic()->GetIntrinsicId(); + EXPECT_TRUE(id != RuntimeInterface::IntrinsicId::LDFALSE && + id != RuntimeInterface::IntrinsicId::LDTRUE); + break; + } + } + } +} + +static void VisitBlockCheckIf(BasicBlock *bb, bool optimize = false) +{ + if (!bb) { + return; + } + for (auto inst : bb->Insts()) { + if (inst->GetOpcode() != Opcode::IfImm) { + continue; + } + auto input = inst->GetInput(0).GetInst(); + if (!optimize) { + EXPECT_TRUE(input->GetOpcode() == Opcode::Compare); + } else { + auto id = input->CastToIntrinsic()->GetIntrinsicId(); + EXPECT_TRUE(id == RuntimeInterface::IntrinsicId::LDFALSE || id == RuntimeInterface::IntrinsicId::LDTRUE); + } + } +} + +/** + * @tc.name: constant_progagation_test_001 + * @tc.desc: Verify the pass to fold greater. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(ConstantProgagationTest, constant_progagation_test_001, TestSize.Level1) +{ + std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; + const char *test_method_name = "sccpFoldGreater"; + + EXPECT_TRUE(CheckFunction(file, test_method_name, + ExpectType::EXPECT_OTHER, ExpectType::EXPECT_BOTH_TRUE_FALSE)); +} + +/** + * @tc.name: constant_progagation_test_002 + * @tc.desc: Verify the pass to fold greater but has no effect. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(ConstantProgagationTest, constant_progagation_test_002, TestSize.Level1) +{ + std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; + const char *test_method_name = "sccpFoldGreaterNoEffect"; + + EXPECT_TRUE(CheckFunction(file, test_method_name, + ExpectType::EXPECT_OTHER, ExpectType::EXPECT_OTHER)); +} + +/** + * @tc.name: constant_progagation_test_003 + * @tc.desc: Verify the pass to fold greatereq. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(ConstantProgagationTest, constant_progagation_test_003, TestSize.Level1) +{ + std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; + const char *test_method_name = "sccpFoldGreaterEq"; + + EXPECT_TRUE(CheckFunction(file, test_method_name, + ExpectType::EXPECT_OTHER, ExpectType::EXPECT_BOTH_TRUE_FALSE)); +} + +/** + * @tc.name: constant_progagation_test_004 + * @tc.desc: Verify the pass to fold greatereq but has no effect. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(ConstantProgagationTest, constant_progagation_test_004, TestSize.Level1) +{ + std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; + const char *test_method_name = "sccpFoldGreaterEqNoEffect"; + + EXPECT_TRUE(CheckFunction(file, test_method_name, + ExpectType::EXPECT_OTHER, ExpectType::EXPECT_OTHER)); +} + +/** + * @tc.name: constant_progagation_test_005 + * @tc.desc: Verify the pass to fold less. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(ConstantProgagationTest, constant_progagation_test_005, TestSize.Level1) +{ + std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; + const char *test_method_name = "sccpFoldLess"; + + EXPECT_TRUE(CheckFunction(file, test_method_name, + ExpectType::EXPECT_OTHER, ExpectType::EXPECT_BOTH_TRUE_FALSE)); +} + +/** + * @tc.name: constant_progagation_test_006 + * @tc.desc: Verify the pass to fold less but has no effect. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(ConstantProgagationTest, constant_progagation_test_006, TestSize.Level1) +{ + std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; + const char *test_method_name = "sccpFoldLessNoEffect"; + + EXPECT_TRUE(CheckFunction(file, test_method_name, + ExpectType::EXPECT_OTHER, ExpectType::EXPECT_OTHER)); +} + +/** + * @tc.name: constant_progagation_test_007 + * @tc.desc: Verify the pass to fold lesseq. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(ConstantProgagationTest, constant_progagation_test_007, TestSize.Level1) +{ + std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; + const char *test_method_name = "sccpFoldLessEq"; + + EXPECT_TRUE(CheckFunction(file, test_method_name, + ExpectType::EXPECT_OTHER, ExpectType::EXPECT_BOTH_TRUE_FALSE)); +} + +/** + * @tc.name: constant_progagation_test_008 + * @tc.desc: Verify the pass to fold lesseq but has no effect. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(ConstantProgagationTest, constant_progagation_test_008, TestSize.Level1) +{ + std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; + const char *test_method_name = "sccpFoldLessEqNoEffect"; + + EXPECT_TRUE(CheckFunction(file, test_method_name, + ExpectType::EXPECT_OTHER, ExpectType::EXPECT_OTHER)); +} + +/** + * @tc.name: constant_progagation_test_009 + * @tc.desc: Verify the pass to fold eq. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(ConstantProgagationTest, constant_progagation_test_009, TestSize.Level1) +{ + std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; + const char *test_method_name = "sccpFoldEq"; + + EXPECT_TRUE(CheckFunction(file, test_method_name, + ExpectType::EXPECT_OTHER, ExpectType::EXPECT_BOTH_TRUE_FALSE)); +} + +/** + * @tc.name: constant_progagation_test_010 + * @tc.desc: Verify the pass to fold eq but has no effect. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(ConstantProgagationTest, constant_progagation_test_010, TestSize.Level1) +{ + std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; + const char *test_method_name = "sccpFoldEqNoEffect"; + EXPECT_TRUE(CheckFunction(file, test_method_name, + ExpectType::EXPECT_OTHER, ExpectType::EXPECT_OTHER)); +} + +/** + * @tc.name: constant_progagation_test_011 + * @tc.desc: Verify the pass to fold stricteq. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(ConstantProgagationTest, constant_progagation_test_011, TestSize.Level1) +{ + std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; + const char *test_method_name = "sccpFoldStrictEq"; + + EXPECT_TRUE(CheckFunction(file, test_method_name, + ExpectType::EXPECT_OTHER, ExpectType::EXPECT_BOTH_TRUE_FALSE)); +} + +/** + * @tc.name: constant_progagation_test_012 + * @tc.desc: Verify the pass to fold eq but has no effect. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(ConstantProgagationTest, constant_progagation_test_012, TestSize.Level1) +{ + std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; + const char *test_method_name = "sccpFoldStrictEqNoEffect"; + + EXPECT_TRUE(CheckFunction(file, test_method_name, + ExpectType::EXPECT_OTHER, ExpectType::EXPECT_OTHER)); +} + +/** + * @tc.name: constant_progagation_test_013 + * @tc.desc: Verify the pass to fold noteq. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(ConstantProgagationTest, constant_progagation_test_013, TestSize.Level1) +{ + std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; + const char *test_method_name = "sccpFoldStrictEq"; + + EXPECT_TRUE(CheckFunction(file, test_method_name, + ExpectType::EXPECT_OTHER, ExpectType::EXPECT_BOTH_TRUE_FALSE)); +} + +/** + * @tc.name: constant_progagation_test_014 + * @tc.desc: Verify the pass to fold noteq but has no effect. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(ConstantProgagationTest, constant_progagation_test_014, TestSize.Level1) +{ + std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; + const char *test_method_name = "sccpFoldStrictEqNoEffect"; + + EXPECT_TRUE(CheckFunction(file, test_method_name, + ExpectType::EXPECT_OTHER, ExpectType::EXPECT_OTHER)); +} + +/** + * @tc.name: constant_progagation_test_015 + * @tc.desc: Verify the pass to fold strictnoteq. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(ConstantProgagationTest, constant_progagation_test_015, TestSize.Level1) +{ + std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; + const char *test_method_name = "sccpFoldStrictNotEq"; + + EXPECT_TRUE(CheckFunction(file, test_method_name, + ExpectType::EXPECT_OTHER, ExpectType::EXPECT_BOTH_TRUE_FALSE)); +} + +/** + * @tc.name: constant_progagation_test_016 + * @tc.desc: Verify the pass to fold strictnoteq but has no effect. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(ConstantProgagationTest, constant_progagation_test_016, TestSize.Level1) +{ + std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; + const char *test_method_name = "sccpFoldStrictNotEqNoEffect"; + + EXPECT_TRUE(CheckFunction(file, test_method_name, + ExpectType::EXPECT_OTHER, ExpectType::EXPECT_OTHER)); +} + +/** + * @tc.name: constant_progagation_test_017 + * @tc.desc: Verify the pass without any effect with nan. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(ConstantProgagationTest, constant_progagation_test_017, TestSize.Level1) +{ + std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; + + EXPECT_TRUE(CheckFunction(file, "sccpNoEffectNanWithInt", + ExpectType::EXPECT_OTHER, ExpectType::EXPECT_OTHER)); + EXPECT_TRUE(CheckFunction(file, "sccpNoEffectNanWithBoolAndDouble", + ExpectType::EXPECT_OTHER, ExpectType::EXPECT_OTHER)); +} + +/** + * @tc.name: constant_progagation_test_018 + * @tc.desc: Verify the optimizion to Compare. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(ConstantProgagationTest, constant_progagation_test_018, TestSize.Level1) +{ + std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; + const char *test_method_name = "sccpIfCheck"; + bool status = false; + + graph_test_.TestBuildGraphFromFile(file, [test_method_name, &status](compiler::Graph *graph, + std::string &method_name) { + if (test_method_name != method_name) { + return; + } + status = true; + EXPECT_NE(graph, nullptr); + EXPECT_TRUE(graph->RunPass()); + EXPECT_TRUE(graph->RunPass()); + auto &bbs = graph->GetVectorBlocks(); + for (auto bb : bbs) { + VisitBlockCheckIf(bb, false); + } + pandasm::AsmEmitter::PandaFileToPandaAsmMaps maps; + pandasm::Program *prog = nullptr; + BytecodeOptIrInterface interface(&maps, prog); + EXPECT_TRUE(graph->RunPass(&interface)); + EXPECT_TRUE(graph->RunPass()); + for (auto bb : bbs) { + VisitBlockCheckIf(bb, true); + } + }); + EXPECT_TRUE(status); +} + +/** + * @tc.name: constant_progagation_test_019 + * @tc.desc: Verify the optimizion to Phi. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(ConstantProgagationTest, constant_progagation_test_019, TestSize.Level1) +{ + std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; + const char *test_method_name = "sccpPhi"; + + EXPECT_TRUE(CheckFunction(file, test_method_name, + ExpectType::EXPECT_PHI, ExpectType::EXPECT_BOTH_TRUE_FALSE)); +} + +/** + * @tc.name: constant_progagation_test_020 + * @tc.desc: Verify the optimizion to Phi. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(ConstantProgagationTest, constant_progagation_test_020, TestSize.Level1) +{ + std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; + const char *test_method_name = "sccpPhiNoEffect"; + + EXPECT_TRUE(CheckFunction(file, test_method_name, + ExpectType::EXPECT_PHI, ExpectType::EXPECT_PHI)); +} + +/** + * @tc.name: constant_progagation_test_021 + * @tc.desc: Verify the optimizion to Phi. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(ConstantProgagationTest, constant_progagation_test_021, TestSize.Level1) +{ + std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; + const char *test_method_name = "sccpPhi2"; + + EXPECT_TRUE(CheckFunction(file, test_method_name, + ExpectType::EXPECT_PHI, ExpectType::EXPECT_CONST)); +} + +/** + * @tc.name: constant_progagation_test_022 + * @tc.desc: Verify the pass without any effect with inf. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(ConstantProgagationTest, constant_progagation_test_022, TestSize.Level1) +{ + std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; + + EXPECT_TRUE(CheckFunction(file, "sccpNoEffectInfinityWithInt", + ExpectType::EXPECT_OTHER, ExpectType::EXPECT_OTHER)); + EXPECT_TRUE(CheckFunction(file, "sccpNoEffectInfinityWithBoolAndDouble", + ExpectType::EXPECT_OTHER, ExpectType::EXPECT_OTHER)); +} + +/** + * @tc.name: constant_progagation_test_023 + * @tc.desc: Verify the pass without any effect with math calculation. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F(ConstantProgagationTest, constant_progagation_test_023, TestSize.Level1) +{ + std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; + const char *test_method_name = "sccpNoEffectArithmetic"; + + EXPECT_TRUE(CheckFunction(file, test_method_name, + ExpectType::EXPECT_OTHER, ExpectType::EXPECT_OTHER)); +} +} // namespace panda::bytecodeopt diff --git a/bytecode_optimizer/tests/js/bytecodeAnalysis.js b/bytecode_optimizer/tests/js/bytecodeAnalysis.js new file mode 100644 index 0000000000..6fba62e6ce --- /dev/null +++ b/bytecode_optimizer/tests/js/bytecodeAnalysis.js @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024 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. + */ + +const a = 1; + +// local export +export {a}; +export {a as a1, b as b1, b as b2, a as a2}; +const b = 2; + +// regular import +import {i as i1, i5} from "@bundle:myapp/test"; +import {i as i2, i6} from "@package:myapp/test"; +import {i as i3, i7} from "@normalized:N&modulename&bundle&myapp/test&"; +import {i as i4, i8} from "test"; + +// namespace import +import * as m4 from "@bundle:myapp/test"; \ No newline at end of file diff --git a/compiler/tests/js/constantProgagation.js b/bytecode_optimizer/tests/js/constantProgagation.js similarity index 96% rename from compiler/tests/js/constantProgagation.js rename to bytecode_optimizer/tests/js/constantProgagation.js index bbd9463d9e..01f3e952dc 100644 --- a/compiler/tests/js/constantProgagation.js +++ b/bytecode_optimizer/tests/js/constantProgagation.js @@ -380,11 +380,9 @@ function sccpFoldStrictNotEqNoEffect() print(a !== b); } -function sccpNoEffectNan() { +function sccpNoEffectNanWithInt() { let a = NaN; let intVal = 1; - let trueVal = true; - let falseVal = false; let intMaxVal = 2147483647; let intMinVal = -2147483648; print(a === intVal); @@ -395,6 +393,33 @@ function sccpNoEffectNan() { print(b >= intVal); print(b > intVal); + // Check NAN with int min. + print(a === intMinVal); + print(a !== intMinVal); + print(a > intMinVal); + print(a >= intMinVal); + print(a < intMinVal); + print(a <= intMinVal); + print(a == intMinVal); + print(a != intMinVal); + + // Check NAN with int maxVal. + print(a === intMaxVal); + print(a !== intMaxVal); + print(a > intMaxVal); + print(a >= intMaxVal); + print(a < intMaxVal); + print(a <= intMaxVal); + print(a == intMaxVal); + print(a != intMaxVal); +} + +function sccpNoEffectNanWithBoolAndDouble() { + let a = NaN; + let doubleVal = 1.1; + let trueVal = true; + let falseVal = false; + // Check NAN with double val. print(a === doubleVal); print(a !== doubleVal); @@ -424,8 +449,23 @@ function sccpNoEffectNan() { print(a <= falseVal); print(a == falseVal); print(a != falseVal); +} - // Check NAN with int min. +function sccpNoEffectInfinityWithInt() { + let a = Infinity; + let intVal = 1; + let intMaxVal = 2147483647; + let intMinVal = -2147483648; + + print(a === intVal); + print(a != intVal); + print(a !== intVal); + print(a > intVal); + print(a >= intVal); + print(b >= intVal); + print(b > intVal); + + // Check Infinity with int min. print(a === intMinVal); print(a !== intMinVal); print(a > intMinVal); @@ -435,7 +475,7 @@ function sccpNoEffectNan() { print(a == intMinVal); print(a != intMinVal); - // Check NAN with int maxVal. + // Check Infinity with int maxVal. print(a === intMaxVal); print(a !== intMaxVal); print(a > intMaxVal); @@ -446,20 +486,10 @@ function sccpNoEffectNan() { print(a != intMaxVal); } -function sccpNoEffectInfinity() { - let a = Infinity; - let intVal = 1; +function sccpNoEffectInfinityWithBoolAndDouble() { + let doubleVal = 1.1; let trueVal = true; let falseVal = false; - let intMaxVal = 2147483647; - let intMinVal = -2147483648; - print(a === intVal); - print(a != intVal); - print(a !== intVal); - print(a > intVal); - print(a >= intVal); - print(b >= intVal); - print(b > intVal); // Check Infinity with double val. print(a === doubleVal); @@ -490,26 +520,6 @@ function sccpNoEffectInfinity() { print(a <= falseVal); print(a == falseVal); print(a != falseVal); - - // Check Infinity with int min. - print(a === intMinVal); - print(a !== intMinVal); - print(a > intMinVal); - print(a >= intMinVal); - print(a < intMinVal); - print(a <= intMinVal); - print(a == intMinVal); - print(a != intMinVal); - - // Check Infinity with int maxVal. - print(a === intMaxVal); - print(a !== intMaxVal); - print(a > intMaxVal); - print(a >= intMaxVal); - print(a < intMaxVal); - print(a <= intMaxVal); - print(a == intMaxVal); - print(a != intMaxVal); } function sccpNoEffectArithmetic() { @@ -544,20 +554,20 @@ function sccpIfCheck() { } let a = 1; let b = 2; - if(a < b) { + if (a < b) { print(true); } - if(a > b) { + if (a > b) { print(true); } } function sccpPhi(a) { let b = a; - if(a){ + if (a) { b = true; - }else { + } else { b = true; } print(b); @@ -576,11 +586,10 @@ function sccpPhi2() function sccpPhiNoEffect(a) { let b = a; - if(a){ + if (a){ b = true; - }else { + } else { b = false; } print(b); -} - +} \ No newline at end of file diff --git a/compiler/BUILD.gn b/compiler/BUILD.gn index f3a29afb7e..5ebd0873ed 100644 --- a/compiler/BUILD.gn +++ b/compiler/BUILD.gn @@ -62,8 +62,6 @@ libarkcompiler_sources = [ "optimizer/ir_builder/ir_builder.cpp", "optimizer/optimizations/branch_elimination.cpp", "optimizer/optimizations/cleanup.cpp", - "optimizer/optimizations/constant_propagation/constant_propagation.cpp", - "optimizer/optimizations/constant_propagation/lattice_element.cpp", "optimizer/optimizations/lowering.cpp", "optimizer/optimizations/move_constants.cpp", "optimizer/optimizations/regalloc/interference_graph.cpp", diff --git a/compiler/optimizer/optimizations/branch_elimination.cpp b/compiler/optimizer/optimizations/branch_elimination.cpp index 9e52d98a24..f68157069f 100644 --- a/compiler/optimizer/optimizations/branch_elimination.cpp +++ b/compiler/optimizer/optimizations/branch_elimination.cpp @@ -95,6 +95,7 @@ void BranchElimination::BranchEliminationIntrinsic(BasicBlock *ifBlock) << ifBlock->GetId(); bool constValue = conditionInst->GetIntrinsicId() == IntrinsicInst::IntrinsicId::LDTRUE; + ASSERT(ifImm->GetImm() == 0); bool condResult = (constValue == ifImm->GetImm()); if (ifImm->GetCc() == CC_NE) { condResult = !condResult; diff --git a/compiler/tests/BUILD.gn b/compiler/tests/BUILD.gn index 5fc17832ac..b2708375e7 100644 --- a/compiler/tests/BUILD.gn +++ b/compiler/tests/BUILD.gn @@ -61,10 +61,7 @@ foreach(file, graph_test_js_files) { } } -graph_test_js_files_un_opt = [ - "branchElimination", - "constantProgagation", -] +graph_test_js_files_un_opt = [ "branchElimination" ] foreach(file, graph_test_js_files_un_opt) { es2abc_gen_abc("gen_${file}_abc") { @@ -80,6 +77,7 @@ foreach(file, graph_test_js_files_un_opt) { extra_args = [ "--debug" ] } } + host_unittest_action("GraphInterfaceTest") { module_out_path = module_output_path sources = [ @@ -88,7 +86,6 @@ host_unittest_action("GraphInterfaceTest") { "compiler_graph_test.cpp", "compiler_inst_test.cpp", "compiler_optimizations_test.cpp", - "constant_propagation_test.cpp", "dominators_tree_new_test.cpp", "dump_test.cpp", "graph_checker_test.cpp", diff --git a/compiler/tests/branch_elimination_new_test.cpp b/compiler/tests/branch_elimination_new_test.cpp index 563271b0a0..d6b6dc040e 100644 --- a/compiler/tests/branch_elimination_new_test.cpp +++ b/compiler/tests/branch_elimination_new_test.cpp @@ -28,14 +28,15 @@ #include #include -#include "graph_test.h" +#include "bytecode_optimizer/constant_propagation/constant_propagation.h" +#include "bytecode_optimizer/ir_interface.h" +#include "compiler/tests/graph_test.h" #include "gtest/gtest.h" #include "optimizer/ir/basicblock.h" #include "optimizer/ir/graph.h" #include "optimizer/ir/inst.h" #include "optimizer/optimizations/branch_elimination.h" #include "optimizer/optimizations/cleanup.h" -#include "optimizer/optimizations/constant_propagation/constant_propagation.h" using namespace testing::ext; @@ -155,12 +156,15 @@ HWTEST_F(BranchEliminationTest, branch_elimination_test_001, TestSize.Level1) return; } EXPECT_NE(graph, nullptr); - - graph->RunPass(); + pandasm::AsmEmitter::PandaFileToPandaAsmMaps maps; + pandasm::Program *prog = nullptr; + bytecodeopt::BytecodeOptIrInterface interface(&maps, prog); + graph->RunPass(&interface); std::set dead_if_insts; std::set dead_blocks; CollectDeadBlocksWithIfInst(graph, dead_if_insts, dead_blocks); + EXPECT_FALSE(dead_if_insts.empty()); EXPECT_FALSE(dead_blocks.empty()); diff --git a/compiler/tests/constant_propagation_test.cpp b/compiler/tests/constant_propagation_test.cpp deleted file mode 100644 index 8a60da0e72..0000000000 --- a/compiler/tests/constant_propagation_test.cpp +++ /dev/null @@ -1,898 +0,0 @@ -/* - * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development 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. - * - * Copyright (c) 2024 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. - */ - -#include - -#include "compiler/optimizer/ir/basicblock.h" -#include "graph.h" -#include "graph_test.h" -#include "mem/pool_manager.h" -#include "optimizer/analysis/dominators_tree.h" -#include "optimizer/optimizations/cleanup.h" -#include "optimizer/optimizations/constant_propagation/constant_propagation.h" - -using namespace testing::ext; - -namespace panda::compiler { -class ConstantProgagationTest : public testing::Test { -public: - static void SetUpTestCase(void) {} - static void TearDownTestCase(void) {} - void SetUp() {} - void TearDown() {} - - GraphTest graph_test_; -}; - -enum class ExpectType { - EXPECT_LDTRUE, - EXPECT_LDFALSE, - EXPECT_BOTH_TRUE_FALSE, - EXPECT_CONST, - EXPECT_PHI, - EXPECT_OTHER, -}; - -static void VisitBlock(BasicBlock *bb, ExpectType type) -{ - if (!bb) { - return; - } - for (auto inst : bb->Insts()) { - if (!inst->IsIntrinsic() || - inst->CastToIntrinsic()->GetIntrinsicId() != RuntimeInterface::IntrinsicId::CALLARG1_IMM8_V8) { - continue; - } - auto input = inst->GetInput(0).GetInst(); - - switch (type) { - case ExpectType::EXPECT_CONST: - ASSERT_TRUE(input->IsConst()); - break; - case ExpectType::EXPECT_PHI: - ASSERT_TRUE(input->IsPhi()); - break; - case ExpectType::EXPECT_LDTRUE: { - ASSERT_TRUE(input->IsIntrinsic()); - auto id = input->CastToIntrinsic()->GetIntrinsicId(); - EXPECT_TRUE(id == RuntimeInterface::IntrinsicId::LDTRUE); - break; - } - case ExpectType::EXPECT_LDFALSE: { - ASSERT_TRUE(input->IsIntrinsic()); - auto id = input->CastToIntrinsic()->GetIntrinsicId(); - EXPECT_TRUE(id == RuntimeInterface::IntrinsicId::LDFALSE); - break; - } - case ExpectType::EXPECT_BOTH_TRUE_FALSE: { - ASSERT_TRUE(input->IsIntrinsic()); - auto id = input->CastToIntrinsic()->GetIntrinsicId(); - EXPECT_TRUE(id == RuntimeInterface::IntrinsicId::LDFALSE || - id == RuntimeInterface::IntrinsicId::LDTRUE); - break; - } - case ExpectType::EXPECT_OTHER: { - ASSERT_TRUE(input->IsIntrinsic()); - auto id = input->CastToIntrinsic()->GetIntrinsicId(); - EXPECT_TRUE(id != RuntimeInterface::IntrinsicId::LDFALSE && - id != RuntimeInterface::IntrinsicId::LDTRUE); - break; - } - } - } -} - -static void VisitBlockCheckIf(BasicBlock *bb, bool optimize = false) -{ - if (!bb) { - return; - } - for (auto inst : bb->Insts()) { - if (inst->GetOpcode() != Opcode::IfImm) { - continue; - } - auto input = inst->GetInput(0).GetInst(); - if (!optimize) { - EXPECT_TRUE(input->GetOpcode() == Opcode::Compare); - } else { - auto id = input->CastToIntrinsic()->GetIntrinsicId(); - EXPECT_TRUE(id == RuntimeInterface::IntrinsicId::LDFALSE || id == RuntimeInterface::IntrinsicId::LDTRUE); - } - } -} - -/** - * @tc.name: constant_progagation_test_001 - * @tc.desc: Verify the pass to fold greater. - * @tc.type: FUNC - * @tc.require: - */ -HWTEST_F(ConstantProgagationTest, constant_progagation_test_001, TestSize.Level1) -{ - std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; - const char *test_method_name = "sccpFoldGreater"; - bool status = false; - - graph_test_.TestBuildGraphFromFile(file, [test_method_name, &status](Graph *graph, std::string &method_name) { - if (test_method_name != method_name) { - return; - } - status = true; - EXPECT_NE(graph, nullptr); - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - auto &bbs = graph->GetVectorBlocks(); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_OTHER); - } - - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_BOTH_TRUE_FALSE); - } - }); - EXPECT_TRUE(status); -} - -/** - * @tc.name: constant_progagation_test_002 - * @tc.desc: Verify the pass to fold greater but has no effect. - * @tc.type: FUNC - * @tc.require: - */ -HWTEST_F(ConstantProgagationTest, constant_progagation_test_002, TestSize.Level1) -{ - std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; - const char *test_method_name = "sccpFoldGreaterNoEffect"; - bool status = false; - - graph_test_.TestBuildGraphFromFile(file, [test_method_name, &status](Graph *graph, std::string &method_name) { - if (test_method_name != method_name) { - return; - } - status = true; - EXPECT_NE(graph, nullptr); - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - auto &bbs = graph->GetVectorBlocks(); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_OTHER); - } - - EXPECT_TRUE(graph->RunPass()); - graph->RunPass(); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_OTHER); - } - }); - EXPECT_TRUE(status); -} - -/** - * @tc.name: constant_progagation_test_003 - * @tc.desc: Verify the pass to fold greatereq. - * @tc.type: FUNC - * @tc.require: - */ -HWTEST_F(ConstantProgagationTest, constant_progagation_test_003, TestSize.Level1) -{ - std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; - const char *test_method_name = "sccpFoldGreaterEq"; - bool status = false; - - graph_test_.TestBuildGraphFromFile(file, [test_method_name, &status](Graph *graph, std::string &method_name) { - if (test_method_name != method_name) { - return; - } - status = true; - EXPECT_NE(graph, nullptr); - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - auto &bbs = graph->GetVectorBlocks(); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_OTHER); - } - - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_BOTH_TRUE_FALSE); - } - }); - EXPECT_TRUE(status); -} - -/** - * @tc.name: constant_progagation_test_004 - * @tc.desc: Verify the pass to fold greatereq but has no effect. - * @tc.type: FUNC - * @tc.require: - */ -HWTEST_F(ConstantProgagationTest, constant_progagation_test_004, TestSize.Level1) -{ - std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; - const char *test_method_name = "sccpFoldGreaterEqNoEffect"; - bool status = false; - - graph_test_.TestBuildGraphFromFile(file, [test_method_name, &status](Graph *graph, std::string &method_name) { - if (test_method_name != method_name) { - return; - } - status = true; - EXPECT_NE(graph, nullptr); - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - auto &bbs = graph->GetVectorBlocks(); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_OTHER); - } - - EXPECT_TRUE(graph->RunPass()); - graph->RunPass(); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_OTHER); - } - }); - EXPECT_TRUE(status); -} - -/** - * @tc.name: constant_progagation_test_005 - * @tc.desc: Verify the pass to fold less. - * @tc.type: FUNC - * @tc.require: - */ -HWTEST_F(ConstantProgagationTest, constant_progagation_test_005, TestSize.Level1) -{ - std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; - const char *test_method_name = "sccpFoldLess"; - bool status = false; - - graph_test_.TestBuildGraphFromFile(file, [test_method_name, &status](Graph *graph, std::string &method_name) { - if (test_method_name != method_name) { - return; - } - status = true; - EXPECT_NE(graph, nullptr); - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - auto &bbs = graph->GetVectorBlocks(); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_OTHER); - } - - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_BOTH_TRUE_FALSE); - } - }); - EXPECT_TRUE(status); -} - -/** - * @tc.name: constant_progagation_test_006 - * @tc.desc: Verify the pass to fold less but has no effect. - * @tc.type: FUNC - * @tc.require: - */ -HWTEST_F(ConstantProgagationTest, constant_progagation_test_006, TestSize.Level1) -{ - std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; - const char *test_method_name = "sccpFoldLessNoEffect"; - bool status = false; - - graph_test_.TestBuildGraphFromFile(file, [test_method_name, &status](Graph *graph, std::string &method_name) { - if (test_method_name != method_name) { - return; - } - status = true; - EXPECT_NE(graph, nullptr); - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - auto &bbs = graph->GetVectorBlocks(); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_OTHER); - } - - EXPECT_TRUE(graph->RunPass()); - graph->RunPass(); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_OTHER); - } - }); - EXPECT_TRUE(status); -} - -/** - * @tc.name: constant_progagation_test_007 - * @tc.desc: Verify the pass to fold lesseq. - * @tc.type: FUNC - * @tc.require: - */ -HWTEST_F(ConstantProgagationTest, constant_progagation_test_007, TestSize.Level1) -{ - std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; - const char *test_method_name = "sccpFoldLessEq"; - bool status = false; - - graph_test_.TestBuildGraphFromFile(file, [test_method_name, &status](Graph *graph, std::string &method_name) { - if (test_method_name != method_name) { - return; - } - status = true; - EXPECT_NE(graph, nullptr); - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - auto &bbs = graph->GetVectorBlocks(); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_OTHER); - } - - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_BOTH_TRUE_FALSE); - } - }); - EXPECT_TRUE(status); -} - -/** - * @tc.name: constant_progagation_test_008 - * @tc.desc: Verify the pass to fold lesseq but has no effect. - * @tc.type: FUNC - * @tc.require: - */ -HWTEST_F(ConstantProgagationTest, constant_progagation_test_008, TestSize.Level1) -{ - std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; - const char *test_method_name = "sccpFoldLessEqNoEffect"; - bool status = false; - - graph_test_.TestBuildGraphFromFile(file, [test_method_name, &status](Graph *graph, std::string &method_name) { - if (test_method_name != method_name) { - return; - } - status = true; - EXPECT_NE(graph, nullptr); - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - auto &bbs = graph->GetVectorBlocks(); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_OTHER); - } - - EXPECT_TRUE(graph->RunPass()); - graph->RunPass(); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_OTHER); - } - }); - EXPECT_TRUE(status); -} - -/** - * @tc.name: constant_progagation_test_009 - * @tc.desc: Verify the pass to fold eq. - * @tc.type: FUNC - * @tc.require: - */ -HWTEST_F(ConstantProgagationTest, constant_progagation_test_009, TestSize.Level1) -{ - std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; - const char *test_method_name = "sccpFoldEq"; - bool status = false; - - graph_test_.TestBuildGraphFromFile(file, [test_method_name, &status](Graph *graph, std::string &method_name) { - if (test_method_name != method_name) { - return; - } - status = true; - EXPECT_NE(graph, nullptr); - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - auto &bbs = graph->GetVectorBlocks(); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_OTHER); - } - - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_BOTH_TRUE_FALSE); - } - }); - EXPECT_TRUE(status); -} - -/** - * @tc.name: constant_progagation_test_010 - * @tc.desc: Verify the pass to fold eq but has no effect. - * @tc.type: FUNC - * @tc.require: - */ -HWTEST_F(ConstantProgagationTest, constant_progagation_test_010, TestSize.Level1) -{ - std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; - const char *test_method_name = "sccpFoldEqNoEffect"; - bool status = false; - - graph_test_.TestBuildGraphFromFile(file, [test_method_name, &status](Graph *graph, std::string &method_name) { - if (test_method_name != method_name) { - return; - } - status = true; - EXPECT_NE(graph, nullptr); - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - auto &bbs = graph->GetVectorBlocks(); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_OTHER); - } - - EXPECT_TRUE(graph->RunPass()); - graph->RunPass(); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_OTHER); - } - }); - EXPECT_TRUE(status); -} - -/** - * @tc.name: constant_progagation_test_011 - * @tc.desc: Verify the pass to fold stricteq. - * @tc.type: FUNC - * @tc.require: - */ -HWTEST_F(ConstantProgagationTest, constant_progagation_test_011, TestSize.Level1) -{ - std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; - const char *test_method_name = "sccpFoldStrictEq"; - bool status = false; - - graph_test_.TestBuildGraphFromFile(file, [test_method_name, &status](Graph *graph, std::string &method_name) { - if (test_method_name != method_name) { - return; - } - status = true; - EXPECT_NE(graph, nullptr); - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - auto &bbs = graph->GetVectorBlocks(); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_OTHER); - } - - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_BOTH_TRUE_FALSE); - } - }); - EXPECT_TRUE(status); -} - -/** - * @tc.name: constant_progagation_test_012 - * @tc.desc: Verify the pass to fold eq but has no effect. - * @tc.type: FUNC - * @tc.require: - */ -HWTEST_F(ConstantProgagationTest, constant_progagation_test_012, TestSize.Level1) -{ - std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; - const char *test_method_name = "sccpFoldStrictEqNoEffect"; - bool status = false; - - graph_test_.TestBuildGraphFromFile(file, [test_method_name, &status](Graph *graph, std::string &method_name) { - if (test_method_name != method_name) { - return; - } - status = true; - EXPECT_NE(graph, nullptr); - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - auto &bbs = graph->GetVectorBlocks(); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_OTHER); - } - - EXPECT_TRUE(graph->RunPass()); - graph->RunPass(); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_OTHER); - } - }); - EXPECT_TRUE(status); -} - -/** - * @tc.name: constant_progagation_test_013 - * @tc.desc: Verify the pass to fold noteq. - * @tc.type: FUNC - * @tc.require: - */ -HWTEST_F(ConstantProgagationTest, constant_progagation_test_013, TestSize.Level1) -{ - std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; - const char *test_method_name = "sccpFoldStrictEq"; - bool status = false; - - graph_test_.TestBuildGraphFromFile(file, [test_method_name, &status](Graph *graph, std::string &method_name) { - if (test_method_name != method_name) { - return; - } - status = true; - EXPECT_NE(graph, nullptr); - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - auto &bbs = graph->GetVectorBlocks(); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_OTHER); - } - - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_BOTH_TRUE_FALSE); - } - }); - EXPECT_TRUE(status); -} - -/** - * @tc.name: constant_progagation_test_014 - * @tc.desc: Verify the pass to fold noteq but has no effect. - * @tc.type: FUNC - * @tc.require: - */ -HWTEST_F(ConstantProgagationTest, constant_progagation_test_014, TestSize.Level1) -{ - std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; - const char *test_method_name = "sccpFoldStrictEqNoEffect"; - bool status = false; - - graph_test_.TestBuildGraphFromFile(file, [test_method_name, &status](Graph *graph, std::string &method_name) { - if (test_method_name != method_name) { - return; - } - status = true; - EXPECT_NE(graph, nullptr); - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - auto &bbs = graph->GetVectorBlocks(); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_OTHER); - } - - EXPECT_TRUE(graph->RunPass()); - graph->RunPass(); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_OTHER); - } - }); - EXPECT_TRUE(status); -} - -/** - * @tc.name: constant_progagation_test_015 - * @tc.desc: Verify the pass to fold strictnoteq. - * @tc.type: FUNC - * @tc.require: - */ -HWTEST_F(ConstantProgagationTest, constant_progagation_test_015, TestSize.Level1) -{ - std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; - const char *test_method_name = "sccpFoldStrictNotEq"; - bool status = false; - - graph_test_.TestBuildGraphFromFile(file, [test_method_name, &status](Graph *graph, std::string &method_name) { - if (test_method_name != method_name) { - return; - } - status = true; - EXPECT_NE(graph, nullptr); - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - auto &bbs = graph->GetVectorBlocks(); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_OTHER); - } - - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_BOTH_TRUE_FALSE); - } - }); - EXPECT_TRUE(status); -} - -/** - * @tc.name: constant_progagation_test_016 - * @tc.desc: Verify the pass to fold strictnoteq but has no effect. - * @tc.type: FUNC - * @tc.require: - */ -HWTEST_F(ConstantProgagationTest, constant_progagation_test_016, TestSize.Level1) -{ - std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; - const char *test_method_name = "sccpFoldStrictNotEqNoEffect"; - bool status = false; - - graph_test_.TestBuildGraphFromFile(file, [test_method_name, &status](Graph *graph, std::string &method_name) { - if (test_method_name != method_name) { - return; - } - status = true; - EXPECT_NE(graph, nullptr); - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - auto &bbs = graph->GetVectorBlocks(); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_OTHER); - } - - EXPECT_TRUE(graph->RunPass()); - graph->RunPass(); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_OTHER); - } - }); - EXPECT_TRUE(status); -} - -/** - * @tc.name: constant_progagation_test_017 - * @tc.desc: Verify the pass without any effect with nan. - * @tc.type: FUNC - * @tc.require: - */ -HWTEST_F(ConstantProgagationTest, constant_progagation_test_017, TestSize.Level1) -{ - std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; - const char *test_method_name = "sccpNoEffectNan"; - bool status = false; - - graph_test_.TestBuildGraphFromFile(file, [test_method_name, &status](Graph *graph, std::string &method_name) { - if (test_method_name != method_name) { - return; - } - status = true; - EXPECT_NE(graph, nullptr); - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - auto &bbs = graph->GetVectorBlocks(); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_OTHER); - } - EXPECT_TRUE(graph->RunPass()); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_OTHER); - } - }); - EXPECT_TRUE(status); -} - -/** - * @tc.name: constant_progagation_test_018 - * @tc.desc: Verify the optimizion to Compare. - * @tc.type: FUNC - * @tc.require: - */ -HWTEST_F(ConstantProgagationTest, constant_progagation_test_018, TestSize.Level1) -{ - std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; - const char *test_method_name = "sccpIfCheck"; - bool status = false; - - graph_test_.TestBuildGraphFromFile(file, [test_method_name, &status](Graph *graph, std::string &method_name) { - if (test_method_name != method_name) { - return; - } - status = true; - EXPECT_NE(graph, nullptr); - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - auto &bbs = graph->GetVectorBlocks(); - for (auto bb : bbs) { - VisitBlockCheckIf(bb, false); - } - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - for (auto bb : bbs) { - VisitBlockCheckIf(bb, true); - } - }); - EXPECT_TRUE(status); -} - -/** - * @tc.name: constant_progagation_test_019 - * @tc.desc: Verify the optimizion to Phi. - * @tc.type: FUNC - * @tc.require: - */ -HWTEST_F(ConstantProgagationTest, constant_progagation_test_019, TestSize.Level1) -{ - std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; - const char *test_method_name = "sccpPhi"; - bool status = false; - - graph_test_.TestBuildGraphFromFile(file, [test_method_name, &status](Graph *graph, std::string &method_name) { - if (test_method_name != method_name) { - return; - } - status = true; - EXPECT_NE(graph, nullptr); - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - auto &bbs = graph->GetVectorBlocks(); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_PHI); - } - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_BOTH_TRUE_FALSE); - } - }); - EXPECT_TRUE(status); -} - -/** - * @tc.name: constant_progagation_test_020 - * @tc.desc: Verify the optimizion to Phi. - * @tc.type: FUNC - * @tc.require: - */ -HWTEST_F(ConstantProgagationTest, constant_progagation_test_020, TestSize.Level1) -{ - std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; - const char *test_method_name = "sccpPhiNoEffect"; - bool status = false; - - graph_test_.TestBuildGraphFromFile(file, [test_method_name, &status](Graph *graph, std::string &method_name) { - if (test_method_name != method_name) { - return; - } - status = true; - EXPECT_NE(graph, nullptr); - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - auto &bbs = graph->GetVectorBlocks(); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_PHI); - } - EXPECT_TRUE(graph->RunPass()); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_PHI); - } - }); - EXPECT_TRUE(status); -} - -/** - * @tc.name: constant_progagation_test_021 - * @tc.desc: Verify the optimizion to Phi. - * @tc.type: FUNC - * @tc.require: - */ -HWTEST_F(ConstantProgagationTest, constant_progagation_test_021, TestSize.Level1) -{ - std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; - const char *test_method_name = "sccpPhi2"; - bool status = false; - - graph_test_.TestBuildGraphFromFile(file, [test_method_name, &status](Graph *graph, std::string &method_name) { - if (test_method_name != method_name) { - return; - } - status = true; - EXPECT_NE(graph, nullptr); - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - auto &bbs = graph->GetVectorBlocks(); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_PHI); - } - EXPECT_TRUE(graph->RunPass()); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_CONST); - } - }); - EXPECT_TRUE(status); -} - -/** - * @tc.name: constant_progagation_test_022 - * @tc.desc: Verify the pass without any effect with inf. - * @tc.type: FUNC - * @tc.require: - */ -HWTEST_F(ConstantProgagationTest, constant_progagation_test_022, TestSize.Level1) -{ - std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; - const char *test_method_name = "sccpNoEffectInfinity"; - bool status = false; - - graph_test_.TestBuildGraphFromFile(file, [test_method_name, &status](Graph *graph, std::string &method_name) { - if (test_method_name != method_name) { - return; - } - status = true; - EXPECT_NE(graph, nullptr); - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - auto &bbs = graph->GetVectorBlocks(); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_OTHER); - } - EXPECT_TRUE(graph->RunPass()); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_OTHER); - } - }); - EXPECT_TRUE(status); -} - -/** - * @tc.name: constant_progagation_test_023 - * @tc.desc: Verify the pass without any effect with math calculation. - * @tc.type: FUNC - * @tc.require: - */ -HWTEST_F(ConstantProgagationTest, constant_progagation_test_023, TestSize.Level1) -{ - std::string file = GRAPH_TEST_ABC_DIR "constantProgagation.abc"; - const char *test_method_name = "sccpNoEffectArithmetic"; - bool status = false; - - graph_test_.TestBuildGraphFromFile(file, [test_method_name, &status](Graph *graph, std::string &method_name) { - if (test_method_name != method_name) { - return; - } - status = true; - EXPECT_NE(graph, nullptr); - EXPECT_TRUE(graph->RunPass()); - EXPECT_TRUE(graph->RunPass()); - auto &bbs = graph->GetVectorBlocks(); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_OTHER); - } - EXPECT_TRUE(graph->RunPass()); - for (auto bb : bbs) { - VisitBlock(bb, ExpectType::EXPECT_OTHER); - } - }); - EXPECT_TRUE(status); -} -} // namespace panda::compiler diff --git a/libpandafile/class_data_accessor.h b/libpandafile/class_data_accessor.h index 78cfae1c3b..6a38950cb0 100644 --- a/libpandafile/class_data_accessor.h +++ b/libpandafile/class_data_accessor.h @@ -40,6 +40,11 @@ public: return (access_flags_ & ACC_INTERFACE) != 0; } + bool IsAnnotation() const + { + return (access_flags_ & ACC_ANNOTATION) != 0; + } + uint32_t GetAccessFlags() const { return access_flags_;