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:
zhaoziming 2024-04-21 18:25:02 +08:00
parent 5a8516c1c3
commit b9978bf60e
28 changed files with 1947 additions and 1061 deletions

View File

@ -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>

View File

@ -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",

View 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

View 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View 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

View File

@ -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

View File

@ -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

View File

@ -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};

View 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

View 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

View File

@ -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,

View File

@ -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);

View File

@ -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"

View File

@ -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",

View 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

View 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

View 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";

View File

@ -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);
}

View File

@ -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",

View File

@ -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;

View File

@ -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",

View File

@ -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());

View File

@ -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

View File

@ -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_;