mirror of
https://gitee.com/openharmony/arkcompiler_runtime_core
synced 2024-11-27 00:41:14 +00:00
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 <zhaoziming9@huawei.com>
This commit is contained in:
parent
5a8516c1c3
commit
b9978bf60e
1
OAT.xml
1
OAT.xml
@ -57,6 +57,7 @@
|
||||
<policyitem type="license" name="*" path="disassembler/tests/expected/.*" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter" desc=""/>
|
||||
<policyitem type="copyright" name="*" path="disassembler/tests/expected/.*" rule="may" group="defaultGroup" filefilter="copyrightPolicyFilter" desc=""/>
|
||||
<policyitem type="copyright" name="Shenzhen Kaihong Digital Industry Development Co., Ltd." path="compiler/.*" rule="may" group="defaultGroup" filefilter="copyrightPolicyFilter" desc=""/>
|
||||
<policyitem type="copyright" name="Shenzhen Kaihong Digital Industry Development Co., Ltd." path="bytecode_optimizer/.*" rule="may" group="defaultGroup" filefilter="copyrightPolicyFilter" desc=""/>
|
||||
</policy>
|
||||
</policylist>
|
||||
|
||||
|
@ -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",
|
||||
|
231
bytecode_optimizer/bytecode_analysis_results.cpp
Normal file
231
bytecode_optimizer/bytecode_analysis_results.cpp
Normal file
@ -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 <mutex>
|
||||
|
||||
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<uint32_t> &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<pandasm::AsmEmitter::PandaFileToPandaAsmMaps>(bytecode_maps_, filename, exists);
|
||||
}
|
||||
|
||||
void BytecodeAnalysisResults::DeleteBytecodeMaps(const std::string &filename)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
bytecode_maps_.erase(filename);
|
||||
}
|
||||
|
||||
BytecodeAnalysisResult &BytecodeAnalysisResults::GetOrCreateBytecodeAnalysisResult(const std::string &recordname,
|
||||
bool &exists)
|
||||
{
|
||||
return GetOrCreateElementInMap<BytecodeAnalysisResult>(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<std::mutex> lock(mutex_);
|
||||
bytecode_maps_.clear();
|
||||
analysis_results_.clear();
|
||||
}
|
||||
|
||||
} // namespace panda::bytecodeopt
|
108
bytecode_optimizer/bytecode_analysis_results.h
Normal file
108
bytecode_optimizer/bytecode_analysis_results.h
Normal file
@ -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 <mutex>
|
||||
#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<uint32_t> &GetConstantLocalExportSlots()
|
||||
{
|
||||
return constant_local_export_slots_;
|
||||
}
|
||||
|
||||
void SetModuleConstantAnalysisResult(const ModuleConstantAnalysisResult &result);
|
||||
void SetConstantLocalExportSlots(const std::unordered_set<uint32_t> &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<std::string>;
|
||||
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<std::string, ConstantValue> constant_local_export_values_;
|
||||
std::unordered_set<uint32_t> constant_local_export_slots_;
|
||||
std::vector<LocalExportInfo> local_export_slot_external_names_;
|
||||
std::unordered_map<uint32_t, RegularImportInfo> regular_import_slot_infos_;
|
||||
std::unordered_map<uint32_t, std::string> namespace_import_slot_source_record_names_;
|
||||
|
||||
friend class BytecodeAnalysisResults;
|
||||
};
|
||||
|
||||
using BytecodeAnalysisResultMap = std::unordered_map<std::string, std::unique_ptr<BytecodeAnalysisResult>>;
|
||||
using BytecodeMapsMap =
|
||||
std::unordered_map<std::string, std::unique_ptr<pandasm::AsmEmitter::PandaFileToPandaAsmMaps>>;
|
||||
|
||||
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<typename T>
|
||||
static T& GetOrCreateElementInMap(std::unordered_map<std::string, std::unique_ptr<T>> &map,
|
||||
const std::string &name, bool &exists)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
auto iter = map.find(name);
|
||||
if (iter == map.end()) {
|
||||
exists = false;
|
||||
auto new_element = std::make_unique<T>();
|
||||
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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
// 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<uint64_t>(std::get<ConstantElement::CONSTANT_BOOL>(input_lattice->AsConstant()->GetVal()));
|
||||
input_lattice->AsConstant()->GetType() == ConstantValue::CONSTANT_BOOL) {
|
||||
auto cst = static_cast<uint64_t>(input_lattice->AsConstant()->GetValue<bool>());
|
||||
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<ConstantElement>(
|
||||
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<ConstantElement>(
|
||||
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<ConstantPropagation *>(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<int32_t>(const_inst->GetInt32Value());
|
||||
element = propagation->GetGraph()->GetLocalAllocator()->New<ConstantElement>(val);
|
||||
} else if (const_inst->GetType() == DataType::INT64) {
|
||||
break;
|
||||
}
|
||||
case compiler::DataType::INT64: {
|
||||
auto val = static_cast<int64_t>(const_inst->GetRawValue());
|
||||
element = propagation->GetGraph()->GetLocalAllocator()->New<ConstantElement>(val);
|
||||
} else if (const_inst->GetType() == DataType::FLOAT64) {
|
||||
break;
|
||||
}
|
||||
case compiler::DataType::FLOAT64: {
|
||||
auto val = const_inst->GetDoubleValue();
|
||||
element = propagation->GetGraph()->GetLocalAllocator()->New<ConstantElement>(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<ConstantPropagation *>(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<ConstantElement>(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<ConstantElement::CONSTANT_BOOL>(lattice->GetVal());
|
||||
auto cst = lattice->GetValue<bool>();
|
||||
return GetGraph()->GetLocalAllocator()->New<ConstantElement>(
|
||||
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<ConstantElement::CONSTANT_BOOL>(left->GetVal());
|
||||
auto right_value = std::get<ConstantElement::CONSTANT_INT64>(right->GetVal());
|
||||
auto left_value = left->GetValue<bool>();
|
||||
auto right_value = right->GetValue<int64_t>();
|
||||
if ((right_value != 0) && (right_value != 1)) {
|
||||
return BottomElement::GetInstance();
|
||||
}
|
||||
switch (cc) {
|
||||
case CC_EQ: {
|
||||
case compiler::CC_EQ: {
|
||||
return GetGraph()->GetLocalAllocator()->New<ConstantElement>(left_value == right_value);
|
||||
}
|
||||
case CC_NE: {
|
||||
case compiler::CC_NE: {
|
||||
return GetGraph()->GetLocalAllocator()->New<ConstantElement>(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<ConstantElement>(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<ConstantElement>(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<ConstantElement>(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<ConstantElement>(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<ConstantElement>(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<ConstantElement>(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<ConstantElement>(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<ConstantElement::CONSTANT_BOOL>(const_val)
|
||||
? RuntimeInterface::IntrinsicId::LDTRUE
|
||||
: RuntimeInterface::IntrinsicId::LDFALSE);
|
||||
case ConstantValue::CONSTANT_BOOL: {
|
||||
auto inst_intrinsic_id = lattice->GetValue<bool>() ? 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<uint32_t>(std::get<ConstantElement::CONSTANT_INT32>(const_val)));
|
||||
case ConstantValue::CONSTANT_INT32: {
|
||||
replace_inst = GetGraph()->FindOrCreateConstant(static_cast<uint32_t>(lattice->GetValue<int32_t>()));
|
||||
break;
|
||||
}
|
||||
case ConstantElement::CONSTANT_INT64: {
|
||||
replace_inst = GetGraph()->FindOrCreateConstant(
|
||||
static_cast<uint64_t>(std::get<ConstantElement::CONSTANT_INT64>(const_val)));
|
||||
case ConstantValue::CONSTANT_INT64: {
|
||||
replace_inst = GetGraph()->FindOrCreateConstant(static_cast<uint64_t>(lattice->GetValue<int64_t>()));
|
||||
break;
|
||||
}
|
||||
|
||||
case ConstantElement::CONSTANT_DOUBLE: {
|
||||
replace_inst = GetGraph()->FindOrCreateConstant(std::get<ConstantElement::CONSTANT_DOUBLE>(const_val));
|
||||
case ConstantValue::CONSTANT_DOUBLE: {
|
||||
replace_inst = GetGraph()->FindOrCreateConstant(lattice->GetValue<double>());
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
@ -548,4 +667,5 @@ void ConstantPropagation::CheckAndAddToSsaEdge(Inst *inst, LatticeElement *curre
|
||||
lattices_[inst] = dst;
|
||||
}
|
||||
}
|
||||
} // namespace panda::compiler
|
||||
|
||||
} // namespace panda::bytecodeopt
|
@ -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<Inst *> ssa_edges_;
|
||||
ArenaUnorderedSet<Edge, EdgeHash, EdgeEqual> executable_flag_;
|
||||
ArenaUnorderedSet<uint32_t> 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
|
108
bytecode_optimizer/constant_propagation/constant_value.h
Normal file
108
bytecode_optimizer/constant_propagation/constant_value.h
Normal file
@ -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<class T>
|
||||
T GetValue() const
|
||||
{
|
||||
ASSERT(std::holds_alternative<T>(value_));
|
||||
return std::get<T>(value_);
|
||||
}
|
||||
|
||||
auto& GetValue() const
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
|
||||
std::string ToString()
|
||||
{
|
||||
std::stringstream ss;
|
||||
switch (type_) {
|
||||
case CONSTANT_BOOL:
|
||||
ss << "[Bool: " << (std::get<bool>(value_) ? "True" : "False") << "]";
|
||||
break;
|
||||
case CONSTANT_INT32:
|
||||
ss << "[Int32: " << std::get<int32_t>(value_) << "]";
|
||||
break;
|
||||
case CONSTANT_INT64:
|
||||
ss << "[Int64: " << std::get<int64_t>(value_) << "]";
|
||||
break;
|
||||
case CONSTANT_DOUBLE:
|
||||
ss << "[Double: " << std::get<double>(value_) << "]";
|
||||
break;
|
||||
case CONSTANT_STRING:
|
||||
ss << "[String: " << std::get<std::string>(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<bool, int32_t, int64_t, double, std::string> value_;
|
||||
};
|
||||
|
||||
} // namespace panda::bytecodeopt
|
||||
|
||||
#endif // BYTECODE_OPTIMIZER_CONSTANT_PROPAGATION_CONSTANT_VALUE_H
|
@ -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
|
@ -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 <variant>
|
||||
#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<class T>
|
||||
T GetValue() const
|
||||
{
|
||||
return val_;
|
||||
return value_.GetValue<T>();
|
||||
}
|
||||
|
||||
ConstantType GetType() const
|
||||
auto &GetValue() const
|
||||
{
|
||||
return type_;
|
||||
return value_.GetValue();
|
||||
}
|
||||
|
||||
ConstantValue::ConstantType GetType() const
|
||||
{
|
||||
return value_.GetType();
|
||||
}
|
||||
|
||||
private:
|
||||
ConstantType type_;
|
||||
std::variant<bool, int32_t, int64_t, double> val_;
|
||||
ConstantValue value_;
|
||||
};
|
||||
} // namespace panda::compiler
|
||||
|
||||
#endif
|
||||
} // namespace panda::bytecodeopt
|
||||
|
||||
#endif // BYTECODE_OPTIMIZER_CONSTANT_PROPAGATION_LATTICE_ELEMENT_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};
|
||||
|
139
bytecode_optimizer/module_constant_analyzer.cpp
Normal file
139
bytecode_optimizer/module_constant_analyzer.cpp
Normal file
@ -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<uint32_t> &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<ModuleConstantAnalyzer *>(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<int32_t>(const_inst->GetInt32Value());
|
||||
return GetGraph()->GetAllocator()->New<ConstantValue>(val);
|
||||
}
|
||||
case compiler::DataType::INT64: {
|
||||
auto val = static_cast<int64_t>(const_inst->GetRawValue());
|
||||
return GetGraph()->GetAllocator()->New<ConstantValue>(val);
|
||||
}
|
||||
case compiler::DataType::FLOAT64: {
|
||||
auto val = const_inst->GetDoubleValue();
|
||||
return GetGraph()->GetAllocator()->New<ConstantValue>(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<ConstantValue>(is_true);
|
||||
}
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ConstantValue *ModuleConstantAnalyzer::GetLoadStringInstConstValue(compiler::LoadFromPool *inst)
|
||||
{
|
||||
return GetGraph()->GetAllocator()->New<ConstantValue>(
|
||||
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
|
86
bytecode_optimizer/module_constant_analyzer.h
Normal file
86
bytecode_optimizer/module_constant_analyzer.h
Normal file
@ -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 <cstring>
|
||||
#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<uint32_t, ConstantValue *>;
|
||||
|
||||
/*
|
||||
* 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<uint32_t> &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<BasicBlock *> &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<uint32_t> &const_local_export_slots_;
|
||||
ModuleConstantAnalysisResult &analysis_result_;
|
||||
const BytecodeOptIrInterface *ir_interface_;
|
||||
};
|
||||
|
||||
} // namespace panda::bytecodeopt
|
||||
|
||||
#endif // BYTECODE_OPTIMIZER_MODULE_CONSTANT_ANALYZER_H
|
@ -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<compiler::ConstantPropagation>(graph);
|
||||
graph->RunPass<ConstantPropagation>(iface);
|
||||
RunOpts<compiler::BranchElimination>(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<std::string> 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<uint32_t>().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<compiler::RuntimeInterface::MethodPtr>(mda.GetMethodId().GetOffset());
|
||||
panda::BytecodeOptimizerRuntimeAdapter adapter(mda.GetPandaFile());
|
||||
auto graph = allocator.New<compiler::Graph>(&allocator, &local_allocator, Arch::NONE, method_ptr, &adapter,
|
||||
false, nullptr, is_dynamic, true);
|
||||
if ((graph == nullptr) || !graph->RunPass<panda::compiler::IrBuilder>()) {
|
||||
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<ModuleConstantAnalyzer>(&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,
|
||||
|
@ -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);
|
||||
|
@ -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"
|
||||
|
@ -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",
|
||||
|
116
bytecode_optimizer/tests/analysis_bytecode_test.cpp
Normal file
116
bytecode_optimizer/tests/analysis_bytecode_test.cpp
Normal file
@ -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 <cstdio>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#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<uint32_t> 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<pandasm::Program *>(&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<int32_t>(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<int32_t>(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
|
537
bytecode_optimizer/tests/constant_propagation_test.cpp
Normal file
537
bytecode_optimizer/tests/constant_propagation_test.cpp
Normal file
@ -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 <gtest/gtest.h>
|
||||
|
||||
#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<uint32_t, std::string> *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<compiler::Cleanup>());
|
||||
EXPECT_TRUE(graph->RunPass<compiler::DominatorsTree>());
|
||||
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<ConstantPropagation>(&interface));
|
||||
auto modified = graph->RunPass<compiler::Cleanup>();
|
||||
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<compiler::Cleanup>());
|
||||
EXPECT_TRUE(graph->RunPass<compiler::DominatorsTree>());
|
||||
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<ConstantPropagation>(&interface));
|
||||
EXPECT_TRUE(graph->RunPass<compiler::Cleanup>());
|
||||
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
|
30
bytecode_optimizer/tests/js/bytecodeAnalysis.js
Normal file
30
bytecode_optimizer/tests/js/bytecodeAnalysis.js
Normal file
@ -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";
|
@ -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() {
|
||||
@ -583,4 +593,3 @@ function sccpPhiNoEffect(a) {
|
||||
}
|
||||
print(b);
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
|
@ -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",
|
||||
|
@ -28,14 +28,15 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <set>
|
||||
#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<ConstantPropagation>();
|
||||
pandasm::AsmEmitter::PandaFileToPandaAsmMaps maps;
|
||||
pandasm::Program *prog = nullptr;
|
||||
bytecodeopt::BytecodeOptIrInterface interface(&maps, prog);
|
||||
graph->RunPass<bytecodeopt::ConstantPropagation>(&interface);
|
||||
|
||||
std::set<uint32_t> dead_if_insts;
|
||||
std::set<uint32_t> dead_blocks;
|
||||
CollectDeadBlocksWithIfInst(graph, dead_if_insts, dead_blocks);
|
||||
|
||||
EXPECT_FALSE(dead_if_insts.empty());
|
||||
EXPECT_FALSE(dead_blocks.empty());
|
||||
|
||||
|
@ -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 <gtest/gtest.h>
|
||||
|
||||
#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<Cleanup>());
|
||||
EXPECT_TRUE(graph->RunPass<DominatorsTree>());
|
||||
auto &bbs = graph->GetVectorBlocks();
|
||||
for (auto bb : bbs) {
|
||||
VisitBlock(bb, ExpectType::EXPECT_OTHER);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(graph->RunPass<ConstantPropagation>());
|
||||
EXPECT_TRUE(graph->RunPass<Cleanup>());
|
||||
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<Cleanup>());
|
||||
EXPECT_TRUE(graph->RunPass<DominatorsTree>());
|
||||
auto &bbs = graph->GetVectorBlocks();
|
||||
for (auto bb : bbs) {
|
||||
VisitBlock(bb, ExpectType::EXPECT_OTHER);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(graph->RunPass<ConstantPropagation>());
|
||||
graph->RunPass<Cleanup>();
|
||||
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<Cleanup>());
|
||||
EXPECT_TRUE(graph->RunPass<DominatorsTree>());
|
||||
auto &bbs = graph->GetVectorBlocks();
|
||||
for (auto bb : bbs) {
|
||||
VisitBlock(bb, ExpectType::EXPECT_OTHER);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(graph->RunPass<ConstantPropagation>());
|
||||
EXPECT_TRUE(graph->RunPass<Cleanup>());
|
||||
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<Cleanup>());
|
||||
EXPECT_TRUE(graph->RunPass<DominatorsTree>());
|
||||
auto &bbs = graph->GetVectorBlocks();
|
||||
for (auto bb : bbs) {
|
||||
VisitBlock(bb, ExpectType::EXPECT_OTHER);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(graph->RunPass<ConstantPropagation>());
|
||||
graph->RunPass<Cleanup>();
|
||||
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<Cleanup>());
|
||||
EXPECT_TRUE(graph->RunPass<DominatorsTree>());
|
||||
auto &bbs = graph->GetVectorBlocks();
|
||||
for (auto bb : bbs) {
|
||||
VisitBlock(bb, ExpectType::EXPECT_OTHER);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(graph->RunPass<ConstantPropagation>());
|
||||
EXPECT_TRUE(graph->RunPass<Cleanup>());
|
||||
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<Cleanup>());
|
||||
EXPECT_TRUE(graph->RunPass<DominatorsTree>());
|
||||
auto &bbs = graph->GetVectorBlocks();
|
||||
for (auto bb : bbs) {
|
||||
VisitBlock(bb, ExpectType::EXPECT_OTHER);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(graph->RunPass<ConstantPropagation>());
|
||||
graph->RunPass<Cleanup>();
|
||||
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<Cleanup>());
|
||||
EXPECT_TRUE(graph->RunPass<DominatorsTree>());
|
||||
auto &bbs = graph->GetVectorBlocks();
|
||||
for (auto bb : bbs) {
|
||||
VisitBlock(bb, ExpectType::EXPECT_OTHER);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(graph->RunPass<ConstantPropagation>());
|
||||
EXPECT_TRUE(graph->RunPass<Cleanup>());
|
||||
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<Cleanup>());
|
||||
EXPECT_TRUE(graph->RunPass<DominatorsTree>());
|
||||
auto &bbs = graph->GetVectorBlocks();
|
||||
for (auto bb : bbs) {
|
||||
VisitBlock(bb, ExpectType::EXPECT_OTHER);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(graph->RunPass<ConstantPropagation>());
|
||||
graph->RunPass<Cleanup>();
|
||||
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<Cleanup>());
|
||||
EXPECT_TRUE(graph->RunPass<DominatorsTree>());
|
||||
auto &bbs = graph->GetVectorBlocks();
|
||||
for (auto bb : bbs) {
|
||||
VisitBlock(bb, ExpectType::EXPECT_OTHER);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(graph->RunPass<ConstantPropagation>());
|
||||
EXPECT_TRUE(graph->RunPass<Cleanup>());
|
||||
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<Cleanup>());
|
||||
EXPECT_TRUE(graph->RunPass<DominatorsTree>());
|
||||
auto &bbs = graph->GetVectorBlocks();
|
||||
for (auto bb : bbs) {
|
||||
VisitBlock(bb, ExpectType::EXPECT_OTHER);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(graph->RunPass<ConstantPropagation>());
|
||||
graph->RunPass<Cleanup>();
|
||||
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<Cleanup>());
|
||||
EXPECT_TRUE(graph->RunPass<DominatorsTree>());
|
||||
auto &bbs = graph->GetVectorBlocks();
|
||||
for (auto bb : bbs) {
|
||||
VisitBlock(bb, ExpectType::EXPECT_OTHER);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(graph->RunPass<ConstantPropagation>());
|
||||
EXPECT_TRUE(graph->RunPass<Cleanup>());
|
||||
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<Cleanup>());
|
||||
EXPECT_TRUE(graph->RunPass<DominatorsTree>());
|
||||
auto &bbs = graph->GetVectorBlocks();
|
||||
for (auto bb : bbs) {
|
||||
VisitBlock(bb, ExpectType::EXPECT_OTHER);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(graph->RunPass<ConstantPropagation>());
|
||||
graph->RunPass<Cleanup>();
|
||||
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<Cleanup>());
|
||||
EXPECT_TRUE(graph->RunPass<DominatorsTree>());
|
||||
auto &bbs = graph->GetVectorBlocks();
|
||||
for (auto bb : bbs) {
|
||||
VisitBlock(bb, ExpectType::EXPECT_OTHER);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(graph->RunPass<ConstantPropagation>());
|
||||
EXPECT_TRUE(graph->RunPass<Cleanup>());
|
||||
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<Cleanup>());
|
||||
EXPECT_TRUE(graph->RunPass<DominatorsTree>());
|
||||
auto &bbs = graph->GetVectorBlocks();
|
||||
for (auto bb : bbs) {
|
||||
VisitBlock(bb, ExpectType::EXPECT_OTHER);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(graph->RunPass<ConstantPropagation>());
|
||||
graph->RunPass<Cleanup>();
|
||||
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<Cleanup>());
|
||||
EXPECT_TRUE(graph->RunPass<DominatorsTree>());
|
||||
auto &bbs = graph->GetVectorBlocks();
|
||||
for (auto bb : bbs) {
|
||||
VisitBlock(bb, ExpectType::EXPECT_OTHER);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(graph->RunPass<ConstantPropagation>());
|
||||
EXPECT_TRUE(graph->RunPass<Cleanup>());
|
||||
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<Cleanup>());
|
||||
EXPECT_TRUE(graph->RunPass<DominatorsTree>());
|
||||
auto &bbs = graph->GetVectorBlocks();
|
||||
for (auto bb : bbs) {
|
||||
VisitBlock(bb, ExpectType::EXPECT_OTHER);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(graph->RunPass<ConstantPropagation>());
|
||||
graph->RunPass<Cleanup>();
|
||||
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<Cleanup>());
|
||||
EXPECT_TRUE(graph->RunPass<DominatorsTree>());
|
||||
auto &bbs = graph->GetVectorBlocks();
|
||||
for (auto bb : bbs) {
|
||||
VisitBlock(bb, ExpectType::EXPECT_OTHER);
|
||||
}
|
||||
EXPECT_TRUE(graph->RunPass<ConstantPropagation>());
|
||||
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<Cleanup>());
|
||||
EXPECT_TRUE(graph->RunPass<DominatorsTree>());
|
||||
auto &bbs = graph->GetVectorBlocks();
|
||||
for (auto bb : bbs) {
|
||||
VisitBlockCheckIf(bb, false);
|
||||
}
|
||||
EXPECT_TRUE(graph->RunPass<ConstantPropagation>());
|
||||
EXPECT_TRUE(graph->RunPass<Cleanup>());
|
||||
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<Cleanup>());
|
||||
EXPECT_TRUE(graph->RunPass<DominatorsTree>());
|
||||
auto &bbs = graph->GetVectorBlocks();
|
||||
for (auto bb : bbs) {
|
||||
VisitBlock(bb, ExpectType::EXPECT_PHI);
|
||||
}
|
||||
EXPECT_TRUE(graph->RunPass<ConstantPropagation>());
|
||||
EXPECT_TRUE(graph->RunPass<Cleanup>());
|
||||
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<Cleanup>());
|
||||
EXPECT_TRUE(graph->RunPass<DominatorsTree>());
|
||||
auto &bbs = graph->GetVectorBlocks();
|
||||
for (auto bb : bbs) {
|
||||
VisitBlock(bb, ExpectType::EXPECT_PHI);
|
||||
}
|
||||
EXPECT_TRUE(graph->RunPass<ConstantPropagation>());
|
||||
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<Cleanup>());
|
||||
EXPECT_TRUE(graph->RunPass<DominatorsTree>());
|
||||
auto &bbs = graph->GetVectorBlocks();
|
||||
for (auto bb : bbs) {
|
||||
VisitBlock(bb, ExpectType::EXPECT_PHI);
|
||||
}
|
||||
EXPECT_TRUE(graph->RunPass<ConstantPropagation>());
|
||||
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<Cleanup>());
|
||||
EXPECT_TRUE(graph->RunPass<DominatorsTree>());
|
||||
auto &bbs = graph->GetVectorBlocks();
|
||||
for (auto bb : bbs) {
|
||||
VisitBlock(bb, ExpectType::EXPECT_OTHER);
|
||||
}
|
||||
EXPECT_TRUE(graph->RunPass<ConstantPropagation>());
|
||||
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<Cleanup>());
|
||||
EXPECT_TRUE(graph->RunPass<DominatorsTree>());
|
||||
auto &bbs = graph->GetVectorBlocks();
|
||||
for (auto bb : bbs) {
|
||||
VisitBlock(bb, ExpectType::EXPECT_OTHER);
|
||||
}
|
||||
EXPECT_TRUE(graph->RunPass<ConstantPropagation>());
|
||||
for (auto bb : bbs) {
|
||||
VisitBlock(bb, ExpectType::EXPECT_OTHER);
|
||||
}
|
||||
});
|
||||
EXPECT_TRUE(status);
|
||||
}
|
||||
} // namespace panda::compiler
|
@ -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_;
|
||||
|
Loading…
Reference in New Issue
Block a user