mirror of
https://gitee.com/openharmony/arkcompiler_runtime_core
synced 2024-10-07 13:54:17 +00:00
Add unittest for bytecode
https://gitee.com/openharmony/arkcompiler_runtime_core/issues/I7KLRF Signed-off-by: lw19901203 <liuwei742@huawei.com>
This commit is contained in:
parent
eeee298c28
commit
6a8e952ebc
15
BUILD.gn
15
BUILD.gn
@ -274,21 +274,6 @@ concat_yamls("concat_inst_templates_yamls") {
|
||||
}
|
||||
|
||||
if (!ark_standalone_build) {
|
||||
group("bcopt_type_adapter_unit_test") {
|
||||
if (host_os == "mac") {
|
||||
if (host_cpu == "arm64") {
|
||||
deps = [ "$ark_root/bytecode_optimizer/tests:bcopt_type_adapter_unit_test($build_root/toolchain/mac:clang_arm64)" ]
|
||||
} else {
|
||||
deps = [ "$ark_root/bytecode_optimizer/tests:bcopt_type_adapter_unit_test($build_root/toolchain/mac:clang_x64)" ]
|
||||
}
|
||||
} else {
|
||||
deps = [
|
||||
"$ark_root/bytecode_optimizer/tests:bcopt_type_adapter_unit_test($build_root/toolchain/linux:clang_x64)",
|
||||
"$ark_root/bytecode_optimizer/tests:bcopt_type_adapter_unit_test($build_root/toolchain/mingw:mingw_x86_64)",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
group("ark_host_linux_defectscanaux_lib") {
|
||||
deps = []
|
||||
if (host_os == "linux") {
|
||||
|
@ -11,60 +11,12 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import("//arkcompiler/ets_frontend/es2panda/es2abc_config.gni")
|
||||
import("//arkcompiler/runtime_core/ark_config.gni")
|
||||
import("$ark_root/tests/test_helper.gni")
|
||||
|
||||
module_out_path = "$ark_root/bytecode_optimizer"
|
||||
|
||||
ohos_executable("bcopt_type_adapter_unit_test") {
|
||||
sources = [ "bcopt_type_adaption_test.cpp" ]
|
||||
|
||||
configs = [
|
||||
"$ark_root:ark_config",
|
||||
"$ark_root/assembler:arkassembler_public_config",
|
||||
"$ark_root/libpandabase:arkbase_public_config",
|
||||
"$ark_root/libpandafile:arkfile_public_config",
|
||||
"$ark_root/compiler:arkcompiler_public_config",
|
||||
"$ark_root/bytecode_optimizer:bytecodeopt_public_config",
|
||||
sdk_libc_secshared_config,
|
||||
]
|
||||
|
||||
deps = [ sdk_libc_secshared_dep ]
|
||||
|
||||
if (is_linux || is_mingw || is_mac) {
|
||||
deps += [
|
||||
"$ark_root/assembler:libarkassembler_frontend_static",
|
||||
"$ark_root/bytecode_optimizer:libarkbytecodeopt_frontend_static",
|
||||
"$ark_root/compiler:libarkcompiler_frontend_static",
|
||||
"$ark_root/libpandabase:libarkbase_frontend_static",
|
||||
"$ark_root/libpandafile:libarkfile_frontend_static",
|
||||
"$ark_root/libziparchive:libarkziparchive_frontend_static",
|
||||
]
|
||||
} else {
|
||||
deps += [
|
||||
"$ark_root/assembler:libarkassembler",
|
||||
"$ark_root/bytecode_optimizer:libarkbytecodeopt",
|
||||
"$ark_root/compiler:libarkcompiler",
|
||||
"$ark_root/libpandabase:libarkbase",
|
||||
"$ark_root/libpandafile:libarkfile",
|
||||
"$ark_root/libziparchive:libarkziparchive",
|
||||
]
|
||||
}
|
||||
|
||||
if (is_linux) {
|
||||
if (build_public_version) {
|
||||
ldflags = [ "-static-libstdc++" ]
|
||||
} else {
|
||||
libs = [ libcpp_static_lib ]
|
||||
}
|
||||
}
|
||||
|
||||
output_name = "bcopt_type_adapter_unit_test"
|
||||
install_enable = false
|
||||
part_name = "runtime_core"
|
||||
subsystem_name = "arkcompiler"
|
||||
}
|
||||
|
||||
bcopt_test_config = [
|
||||
"$ark_root:ark_config",
|
||||
"$ark_root/assembler:arkassembler_public_config",
|
||||
@ -85,14 +37,52 @@ bcopt_test_deps = [
|
||||
sdk_libc_secshared_dep,
|
||||
]
|
||||
|
||||
host_unittest_action("ExcludedKeysTest") {
|
||||
test_js_path = "//arkcompiler/runtime_core/bytecode_optimizer/tests/js/"
|
||||
graph_test_js_files = [
|
||||
"codegenTryCatch",
|
||||
"optimizeTryCatch",
|
||||
]
|
||||
|
||||
foreach(file, graph_test_js_files) {
|
||||
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 ]
|
||||
}
|
||||
}
|
||||
|
||||
host_unittest_action("BytecodeOptimizerTest") {
|
||||
module_out_path = module_output_path
|
||||
sources = [ "excluded_keys_test.cpp" ]
|
||||
sources = [
|
||||
"bcopt_type_adaption_test.cpp",
|
||||
"codegen_test.cpp",
|
||||
"excluded_keys_test.cpp",
|
||||
"optimize_bytecode_test.cpp",
|
||||
"reg_encoder_test.cpp",
|
||||
]
|
||||
configs = bcopt_test_config
|
||||
deps = bcopt_test_deps
|
||||
test_abc_dir = rebase_path(target_out_dir)
|
||||
|
||||
defines = [ "GRAPH_TEST_ABC_DIR=\"${test_abc_dir}/\"" ]
|
||||
|
||||
foreach(file, graph_test_js_files) {
|
||||
deps += [ ":gen_${file}_abc" ]
|
||||
}
|
||||
|
||||
defines += [
|
||||
"ARK_INTRINSIC_SET",
|
||||
"ENABLE_BYTECODE_OPT",
|
||||
"PANDA_WITH_ECMASCRIPT",
|
||||
]
|
||||
}
|
||||
|
||||
group("host_unittest") {
|
||||
testonly = true
|
||||
deps = [ ":ExcludedKeysTestAction" ]
|
||||
deps = [ ":BytecodeOptimizerTestAction" ]
|
||||
}
|
||||
|
@ -13,114 +13,145 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "assembler/meta.h"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "assembler/assembly-parser.h"
|
||||
#include "assembler/meta.h"
|
||||
#include "bytecode_optimizer/optimize_bytecode.h"
|
||||
|
||||
namespace panda::bytecodeopt::test {
|
||||
namespace panda::bytecodeopt {
|
||||
using ArrayValue = panda::pandasm::ArrayValue;
|
||||
using ScalarValue = panda::pandasm::ScalarValue;
|
||||
using AnnotationData = panda::pandasm::AnnotationData;
|
||||
using AnnotationElement = panda::pandasm::AnnotationElement;
|
||||
using TypeInfoMap = std::unordered_map<int32_t, TypeInfoIndex>;
|
||||
|
||||
class TestBase {
|
||||
class TypeAdaptionTest : public testing::Test {
|
||||
public:
|
||||
template <typename T1, typename T2>
|
||||
inline void TestAssertEqual(const T1 &left, const T2 &right) const
|
||||
{
|
||||
if (left != static_cast<T1>(right)) {
|
||||
std::cout << "assertion equal failed." << std::endl;
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
static void SetUpTestCase(void) {}
|
||||
static void TearDownTestCase(void) {}
|
||||
void SetUp() {}
|
||||
void TearDown() {}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
inline void TestAssertNotEqual(const T1 &left, const T2 &right) const
|
||||
TypeInfoMap ExtractTypeinfo(const panda::pandasm::Function &fun, const panda::pandasm::Program &prog) const
|
||||
{
|
||||
if (left == static_cast<T1>(right)) {
|
||||
std::cout << "assertion not equal failed." << std::endl;
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
inline void TestAssertTrue(bool val) const
|
||||
{
|
||||
if (!val) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
inline void TestAssertFalse(bool val) const
|
||||
{
|
||||
if (val) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class BytecodeOptimizerTypeAdaptionTest : TestBase {
|
||||
public:
|
||||
std::unordered_map<int32_t, int32_t> ExtractTypeinfo(const panda::pandasm::Function &fun) const
|
||||
{
|
||||
const auto *ele = fun.metadata->GetAnnotations()[0].GetElements()[0].GetValue();
|
||||
const auto &values = ele->GetAsArray()->GetValues();
|
||||
std::unordered_map<int32_t, int32_t> type_info;
|
||||
const size_t PAIR_GAP = 2;
|
||||
TestAssertEqual(values.size() % PAIR_GAP, 0); // must be even as it consits of pairs
|
||||
for (size_t i = 0; i < values.size(); i += PAIR_GAP) {
|
||||
type_info.emplace(values[i].GetValue<int32_t>(), values[i + 1].GetValue<int32_t>());
|
||||
const auto &annos = fun.metadata->GetAnnotations();
|
||||
EXPECT_FALSE(annos.empty());
|
||||
const auto &eles = annos[0].GetElements();
|
||||
EXPECT_FALSE(eles.empty());
|
||||
const auto *ele = eles[0].GetValue();
|
||||
EXPECT_NE(ele, nullptr);
|
||||
const auto key = ele->GetAsScalar()->GetValue<std::string>();
|
||||
auto array_liter = prog.literalarray_table.find(key);
|
||||
EXPECT_NE(array_liter, prog.literalarray_table.end());
|
||||
const auto &array = array_liter->second.literals_;
|
||||
// 4: size must be multiple of 4 because values consits of tuple of tag, order, tag, type
|
||||
EXPECT_EQ(array.size() % 4u, 0u);
|
||||
TypeInfoMap type_info;
|
||||
size_t i = 1; // 1: skip tag of order, so start from 1
|
||||
while (i < array.size()) {
|
||||
auto order = bit_cast<int32_t>(std::get<uint32_t>(array[i].value_));
|
||||
i += 2; // 2: skip tag between order and type
|
||||
TypeInfoIndex type;
|
||||
if (array[i].tag_ == panda_file::LiteralTag::LITERALARRAY) {
|
||||
type = std::get<std::string>(array[i].value_);
|
||||
} else {
|
||||
EXPECT_EQ(array[i].tag_, panda_file::LiteralTag::BUILTINTYPEINDEX);
|
||||
type = std::get<BuiltinIndexType>(array[i].value_);
|
||||
}
|
||||
type_info.emplace(order, type);
|
||||
i += 2; // 2: skip tag between order and type
|
||||
}
|
||||
return type_info;
|
||||
}
|
||||
|
||||
void CheckTypeExist(const std::unordered_map<int32_t, int32_t> &typeinfo, int32_t order, int32_t type) const
|
||||
void CheckTypeExist(const TypeInfoMap &typeinfo, int32_t order, const TypeInfoIndex &type) const
|
||||
{
|
||||
auto type_it = typeinfo.find(order);
|
||||
TestAssertNotEqual(type_it, typeinfo.end());
|
||||
TestAssertEqual(type_it->second, type);
|
||||
EXPECT_NE(type_it, typeinfo.end());
|
||||
EXPECT_EQ(type_it->second, type);
|
||||
}
|
||||
|
||||
void AddTypeinfo(std::vector<ScalarValue> *elements, int32_t order, int32_t type) const
|
||||
void AddTypeinfo(panda::pandasm::LiteralArray &lit_arr, int32_t order, TypeInfoIndex type) const
|
||||
{
|
||||
ScalarValue insn_order(ScalarValue::Create<panda::pandasm::Value::Type::I32>(order));
|
||||
elements->emplace_back(std::move(insn_order));
|
||||
ScalarValue insn_type(ScalarValue::Create<panda::pandasm::Value::Type::I32>(type));
|
||||
elements->emplace_back(std::move(insn_type));
|
||||
auto &arr = lit_arr.literals_;
|
||||
|
||||
panda::pandasm::LiteralArray::Literal order_tag;
|
||||
order_tag.tag_ = panda::panda_file::LiteralTag::TAGVALUE;
|
||||
order_tag.value_ = static_cast<uint8_t>(panda::panda_file::LiteralTag::INTEGER);
|
||||
arr.emplace_back(order_tag);
|
||||
|
||||
panda::pandasm::LiteralArray::Literal order_val;
|
||||
order_val.tag_ = panda::panda_file::LiteralTag::INTEGER;
|
||||
order_val.value_ = static_cast<uint32_t>(order);
|
||||
arr.emplace_back(order_val);
|
||||
|
||||
panda::pandasm::LiteralArray::Literal type_tag;
|
||||
panda::pandasm::LiteralArray::Literal type_val;
|
||||
type_tag.tag_ = panda::panda_file::LiteralTag::TAGVALUE;
|
||||
|
||||
if (std::holds_alternative<uint8_t>(type)) {
|
||||
type_tag.value_ = static_cast<uint8_t>(panda::panda_file::LiteralTag::BUILTINTYPEINDEX);
|
||||
type_val.tag_ = panda::panda_file::LiteralTag::BUILTINTYPEINDEX;
|
||||
type_val.value_ = std::get<uint8_t>(type);
|
||||
} else {
|
||||
EXPECT_TRUE(std::holds_alternative<std::string>(type));
|
||||
type_tag.value_ = static_cast<uint8_t>(panda::panda_file::LiteralTag::LITERALARRAY);
|
||||
type_val.tag_ = panda::panda_file::LiteralTag::LITERALARRAY;
|
||||
type_val.value_ = std::get<std::string>(type);
|
||||
}
|
||||
arr.emplace_back(type_tag);
|
||||
arr.emplace_back(type_val);
|
||||
}
|
||||
|
||||
void SetTypeAnnotationForFunc(const std::vector<ScalarValue> &elements, panda::pandasm::Function &func,
|
||||
void SetTypeAnnotationForFunc(const panda::pandasm::LiteralArray &arr, panda::pandasm::Function &func,
|
||||
panda::pandasm::Program &program) const
|
||||
{
|
||||
ArrayValue array_value(panda::pandasm::Value::Type::I32, elements);
|
||||
AnnotationElement anno_element(TSTYPE_ANNO_ELEMENT_NAME, std::make_unique<ArrayValue>(array_value));
|
||||
auto id = std::to_string(program.literalarray_table.size());
|
||||
program.literalarray_table.emplace(id, arr);
|
||||
|
||||
AnnotationElement element(TSTYPE_ANNO_ELEMENT_NAME, std::make_unique<ScalarValue>(
|
||||
ScalarValue::Create<panda::pandasm::Value::Type::LITERALARRAY>(id)));
|
||||
AnnotationData annotation(TSTYPE_ANNO_RECORD_NAME);
|
||||
annotation.AddElement(std::move(anno_element));
|
||||
annotation.AddElement(std::move(element));
|
||||
std::vector<AnnotationData> annos;
|
||||
annos.emplace_back(std::move(annotation));
|
||||
annos.emplace_back(annotation);
|
||||
func.metadata->SetAnnotations(std::move(annos));
|
||||
const auto iterator = program.record_table.find(TSTYPE_ANNO_RECORD_NAME.data());
|
||||
TestAssertNotEqual(iterator, program.record_table.end());
|
||||
EXPECT_NE(iterator, program.record_table.end());
|
||||
iterator->second.metadata->SetAccessFlags(panda::ACC_ANNOTATION);
|
||||
TestAssertTrue(program.record_table.find(TSTYPE_ANNO_RECORD_NAME.data())->second.metadata->IsAnnotation());
|
||||
EXPECT_TRUE(program.record_table.find(TSTYPE_ANNO_RECORD_NAME.data())->second.metadata->IsAnnotation());
|
||||
}
|
||||
|
||||
void EmitAndOptimize(const std::string &abc_file_name, panda::pandasm::Program &program) const
|
||||
// add a literalarray as a type
|
||||
TypeInfoIndex AddAnTypeLiteralArray(panda::pandasm::Program &program) const
|
||||
{
|
||||
panda::pandasm::LiteralArray arr;
|
||||
panda::pandasm::LiteralArray::Literal tag;
|
||||
tag.tag_ = panda::panda_file::LiteralTag::TAGVALUE;
|
||||
tag.value_ = static_cast<uint8_t>(panda::panda_file::LiteralTag::BUILTINTYPEINDEX);
|
||||
arr.literals_.emplace_back(tag);
|
||||
panda::pandasm::LiteralArray::Literal val;
|
||||
val.tag_ = panda::panda_file::LiteralTag::BUILTINTYPEINDEX;
|
||||
val.value_ = static_cast<uint8_t>(0u);
|
||||
arr.literals_.emplace_back(val);
|
||||
const std::string litKey = std::to_string(program.literalarray_table.size());
|
||||
program.literalarray_table.emplace(litKey, arr);
|
||||
TypeInfoIndex ret = litKey;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void EmitAndOptimize(const std::string &abcFileName, panda::pandasm::Program &program) const
|
||||
{
|
||||
std::map<std::string, size_t> *statp = nullptr;
|
||||
panda::pandasm::AsmEmitter::PandaFileToPandaAsmMaps maps {};
|
||||
panda::pandasm::AsmEmitter::PandaFileToPandaAsmMaps *mapsp = &maps;
|
||||
TestAssertTrue(panda::pandasm::AsmEmitter::Emit(abc_file_name, program, statp, mapsp, false));
|
||||
TestAssertTrue(panda::bytecodeopt::OptimizeBytecode(&program, mapsp, abc_file_name, true));
|
||||
EXPECT_TRUE(panda::pandasm::AsmEmitter::Emit(abcFileName, program, statp, mapsp, false));
|
||||
EXPECT_TRUE(panda::bytecodeopt::OptimizeBytecode(&program, mapsp, abcFileName, true));
|
||||
}
|
||||
|
||||
void TypeAdaptionTest() const;
|
||||
void TypeAdaptionTest_UnconditionalJump() const;
|
||||
|
||||
static constexpr int32_t NUM_TYPE = 1;
|
||||
static constexpr int32_t STR_TYPE = 4;
|
||||
};
|
||||
|
||||
void BytecodeOptimizerTypeAdaptionTest::TypeAdaptionTest() const
|
||||
HWTEST_F(TypeAdaptionTest, type_adaption_test_001, testing::ext::TestSize.Level1)
|
||||
{
|
||||
/* ts source code
|
||||
function foo(a:number, b:string, c:string):string
|
||||
@ -139,114 +170,114 @@ void BytecodeOptimizerTypeAdaptionTest::TypeAdaptionTest() const
|
||||
const auto source = R"(
|
||||
.language ECMAScript
|
||||
.record _ESTypeAnnotation <external>
|
||||
.function any foo(any a0, any a1, any a2) <static> {
|
||||
mov.dyn v2, a2
|
||||
mov.dyn v1, a1
|
||||
mov.dyn v0, a0
|
||||
ecma.ldlexenvdyn
|
||||
sta.dyn v6
|
||||
ldai.dyn 0x64
|
||||
sta.dyn v3
|
||||
lda.dyn v0
|
||||
sta.dyn v5
|
||||
lda.dyn v3
|
||||
ecma.greaterdyn v5
|
||||
.function any foo(any a0, any a1, any a2, any a3, any a4, any a5) <static> {
|
||||
mov v5, a5
|
||||
mov v4, a4
|
||||
mov v3, a3
|
||||
mov v2, a2
|
||||
mov v1, a1
|
||||
mov v0, a0
|
||||
ldai 0x64
|
||||
sta v6
|
||||
lda v3
|
||||
sta v9
|
||||
lda v6
|
||||
greater 0x0, v9
|
||||
jeqz jump_label_0
|
||||
lda.dyn v1
|
||||
sta.dyn v5
|
||||
lda.dyn v5
|
||||
return.dyn
|
||||
lda v4
|
||||
return
|
||||
jump_label_0:
|
||||
lda.dyn v0
|
||||
sta.dyn v5
|
||||
lda.dyn v3
|
||||
ecma.lessdyn v5
|
||||
lda v3
|
||||
sta v9
|
||||
lda v6
|
||||
less 0x1, v9
|
||||
jeqz jump_label_1
|
||||
lda.dyn v2
|
||||
sta.dyn v5
|
||||
lda.dyn v5
|
||||
return.dyn
|
||||
lda v5
|
||||
return
|
||||
jump_label_1:
|
||||
lda.dyn v1
|
||||
sta.dyn v5
|
||||
lda.dyn v2
|
||||
ecma.add2dyn v5
|
||||
sta.dyn v4
|
||||
lda.dyn v4
|
||||
sta.dyn v5
|
||||
lda.dyn v5
|
||||
return.dyn
|
||||
lda v4
|
||||
sta v9
|
||||
lda v5
|
||||
add2 0x2, v9
|
||||
sta v7
|
||||
lda v7
|
||||
return
|
||||
}
|
||||
)";
|
||||
panda::pandasm::Parser parser;
|
||||
auto res = parser.Parse(source);
|
||||
auto &program = res.Value();
|
||||
const std::string fun_name = "foo:(any,any,any)";
|
||||
const std::string fun_name = "foo:(any,any,any,any,any,any)";
|
||||
auto it = program.function_table.find(fun_name);
|
||||
TestAssertNotEqual(it, program.function_table.end());
|
||||
EXPECT_NE(it, program.function_table.end());
|
||||
|
||||
auto &func = it->second;
|
||||
std::vector<panda::pandasm::ScalarValue> elements;
|
||||
panda::pandasm::LiteralArray lit_arr;
|
||||
static const TypeInfoIndex NUM_TYPE = static_cast<uint8_t>(1);
|
||||
static const TypeInfoIndex STR_TYPE = static_cast<uint8_t>(4);
|
||||
// set arg type
|
||||
AddTypeinfo(&elements, -1, NUM_TYPE); // -1: first arg
|
||||
AddTypeinfo(&elements, -2, STR_TYPE); // -2: second arg
|
||||
AddTypeinfo(&elements, -3, STR_TYPE); // -3: third arg
|
||||
const auto THIS_TYPE = AddAnTypeLiteralArray(program);
|
||||
AddTypeinfo(lit_arr, -3, THIS_TYPE); // -3: the arg "this"
|
||||
AddTypeinfo(lit_arr, -4, NUM_TYPE); // -4: the first arg
|
||||
AddTypeinfo(lit_arr, -5, STR_TYPE); // -5: the second arg
|
||||
AddTypeinfo(lit_arr, -6, STR_TYPE); // -6: the third arg
|
||||
// set ins type
|
||||
const size_t LDAI_IDX = 5;
|
||||
TestAssertEqual(func.ins[LDAI_IDX].opcode, panda::pandasm::Opcode::LDAI_DYN);
|
||||
TestAssertEqual(func.ins[LDAI_IDX + 1].opcode, panda::pandasm::Opcode::STA_DYN);
|
||||
AddTypeinfo(&elements, static_cast<int32_t>(LDAI_IDX + 1), NUM_TYPE);
|
||||
const size_t ADD_IDX = 30;
|
||||
TestAssertEqual(func.ins[ADD_IDX].opcode, panda::pandasm::Opcode::ECMA_ADD2DYN);
|
||||
TestAssertEqual(func.ins[ADD_IDX + 1].opcode, panda::pandasm::Opcode::STA_DYN);
|
||||
const size_t LDAI_IDX = 6;
|
||||
EXPECT_EQ(func.ins[LDAI_IDX].opcode, panda::pandasm::Opcode::LDAI);
|
||||
EXPECT_EQ(func.ins[LDAI_IDX + 1].opcode, panda::pandasm::Opcode::STA);
|
||||
AddTypeinfo(lit_arr, static_cast<int32_t>(LDAI_IDX + 1), NUM_TYPE);
|
||||
const size_t ADD_IDX = 27;
|
||||
EXPECT_EQ(func.ins[ADD_IDX].opcode, panda::pandasm::Opcode::ADD2);
|
||||
EXPECT_EQ(func.ins[ADD_IDX + 1].opcode, panda::pandasm::Opcode::STA);
|
||||
int32_t num_invalid = std::count_if(func.ins.begin(), func.ins.begin() + ADD_IDX,
|
||||
[](const auto &in) { return in.opcode == panda::pandasm::Opcode::INVALID; });
|
||||
AddTypeinfo(&elements, ADD_IDX + 1 - num_invalid, STR_TYPE); // exclude invalid insns because they do not emit
|
||||
AddTypeinfo(lit_arr, ADD_IDX + 1 - num_invalid, STR_TYPE); // exclude invalid insns because they do not emit
|
||||
|
||||
SetTypeAnnotationForFunc(elements, func, program);
|
||||
SetTypeAnnotationForFunc(lit_arr, func, program);
|
||||
|
||||
EmitAndOptimize("TypeAdaptionTest.abc", program);
|
||||
|
||||
// check typeinfo after optimization
|
||||
it = program.function_table.find(fun_name);
|
||||
TestAssertNotEqual(it, program.function_table.end());
|
||||
EXPECT_NE(it, program.function_table.end());
|
||||
const auto &foo = it->second;
|
||||
const auto typeinfo = ExtractTypeinfo(foo);
|
||||
CheckTypeExist(typeinfo, -1, NUM_TYPE); // -1: means first arg
|
||||
CheckTypeExist(typeinfo, -2, STR_TYPE); // -2: means second arg
|
||||
CheckTypeExist(typeinfo, -3, STR_TYPE); // -3: means third arg
|
||||
const auto typeinfo = ExtractTypeinfo(foo, program);
|
||||
CheckTypeExist(typeinfo, -3, THIS_TYPE); // -3: the arg "this"
|
||||
CheckTypeExist(typeinfo, -4, NUM_TYPE); // -4: the first arg
|
||||
CheckTypeExist(typeinfo, -5, STR_TYPE); // -5: the second arg
|
||||
CheckTypeExist(typeinfo, -6, STR_TYPE); // -6: the third arg
|
||||
auto ldai_it = std::find_if(foo.ins.begin(), foo.ins.end(),
|
||||
[](const auto &in) { return in.opcode == panda::pandasm::Opcode::LDAI_DYN; });
|
||||
TestAssertNotEqual(ldai_it, foo.ins.end());
|
||||
[](const auto &in) { return in.opcode == panda::pandasm::Opcode::LDAI; });
|
||||
EXPECT_NE(ldai_it, foo.ins.end());
|
||||
const auto opt_ldai_idx = static_cast<size_t>(ldai_it - foo.ins.begin());
|
||||
TestAssertEqual(foo.ins[opt_ldai_idx].opcode, panda::pandasm::Opcode::LDAI_DYN);
|
||||
TestAssertTrue(opt_ldai_idx + 1 < foo.ins.size());
|
||||
TestAssertEqual(foo.ins[opt_ldai_idx + 1].opcode, panda::pandasm::Opcode::STA_DYN);
|
||||
EXPECT_EQ(foo.ins[opt_ldai_idx].opcode, panda::pandasm::Opcode::LDAI);
|
||||
EXPECT_LT(opt_ldai_idx + 1, foo.ins.size());
|
||||
EXPECT_EQ(foo.ins[opt_ldai_idx + 1].opcode, panda::pandasm::Opcode::STA);
|
||||
|
||||
num_invalid = std::count_if(foo.ins.begin(), ldai_it,
|
||||
[](const auto &in) { return in.opcode == panda::pandasm::Opcode::INVALID; });
|
||||
int32_t ldai_type_idx = opt_ldai_idx - num_invalid; // exclude invalid insns because they do not emit
|
||||
|
||||
CheckTypeExist(typeinfo, ldai_type_idx + 1, NUM_TYPE); // type is on sta.dyn
|
||||
CheckTypeExist(typeinfo, ldai_type_idx + 1, NUM_TYPE); // type is on sta
|
||||
|
||||
auto add_it = std::find_if(foo.ins.begin(), foo.ins.end(),
|
||||
[](const auto &in) { return in.opcode == panda::pandasm::Opcode::ECMA_ADD2DYN; });
|
||||
TestAssertNotEqual(add_it, foo.ins.end());
|
||||
[](const auto &in) { return in.opcode == panda::pandasm::Opcode::ADD2; });
|
||||
EXPECT_NE(add_it, foo.ins.end());
|
||||
const auto opt_add_idx = static_cast<size_t>(add_it - foo.ins.begin());
|
||||
TestAssertEqual(foo.ins[opt_add_idx].opcode, panda::pandasm::Opcode::ECMA_ADD2DYN);
|
||||
TestAssertTrue(opt_add_idx + 1 < foo.ins.size());
|
||||
TestAssertNotEqual(foo.ins[opt_add_idx + 1].opcode, panda::pandasm::Opcode::STA_DYN);
|
||||
EXPECT_EQ(foo.ins[opt_add_idx].opcode, panda::pandasm::Opcode::ADD2);
|
||||
EXPECT_LT(opt_add_idx + 1, foo.ins.size());
|
||||
EXPECT_NE(foo.ins[opt_add_idx + 1].opcode, panda::pandasm::Opcode::STA);
|
||||
|
||||
num_invalid = std::count_if(foo.ins.begin(), add_it,
|
||||
[](const auto &in) { return in.opcode == panda::pandasm::Opcode::INVALID; });
|
||||
int32_t add_type_idx = opt_add_idx - num_invalid; // exclude invalid insns because they do not emit
|
||||
CheckTypeExist(typeinfo, add_type_idx, STR_TYPE); // type is on ecma.add2dyn as it does not have sta.dyn
|
||||
CheckTypeExist(typeinfo, add_type_idx, STR_TYPE); // type is on add2 as it does not have sta
|
||||
}
|
||||
|
||||
void BytecodeOptimizerTypeAdaptionTest::TypeAdaptionTest_UnconditionalJump() const
|
||||
HWTEST_F(TypeAdaptionTest, unconditional_jump_case_test_001, testing::ext::TestSize.Level1)
|
||||
{
|
||||
/* ts source code
|
||||
function processResults(results: number) {
|
||||
function foo(results: number) {
|
||||
for (let i = 0; i < 1; i++) {
|
||||
results *= i;
|
||||
}
|
||||
@ -257,93 +288,88 @@ void BytecodeOptimizerTypeAdaptionTest::TypeAdaptionTest_UnconditionalJump() con
|
||||
const auto source = R"(
|
||||
.language ECMAScript
|
||||
.record _ESTypeAnnotation <external>
|
||||
.function any foo(any a0) <static> {
|
||||
mov.dyn v0, a0
|
||||
ecma.ldlexenvdyn
|
||||
sta.dyn v6
|
||||
ldai.dyn 0x0
|
||||
sta.dyn v1
|
||||
.function any foo(any a0, any a1, any a2, any a3) <static> {
|
||||
mov v0, a0
|
||||
mov v1, a1
|
||||
mov v2, a2
|
||||
mov v3, a3
|
||||
ldai 0x0
|
||||
sta v6
|
||||
jump_label_1:
|
||||
lda.dyn v1
|
||||
sta.dyn v4
|
||||
ldai.dyn 0x1
|
||||
ecma.lessdyn v4
|
||||
lda v6
|
||||
sta v7
|
||||
ldai 0x1
|
||||
less 0x0, v7
|
||||
jeqz jump_label_0
|
||||
lda.dyn v0
|
||||
sta.dyn v4
|
||||
lda.dyn v1
|
||||
ecma.mul2dyn v4
|
||||
sta.dyn v0
|
||||
lda.dyn v1
|
||||
sta.dyn v4
|
||||
ecma.incdyn v4
|
||||
sta.dyn v1
|
||||
ecma.tonumeric v4
|
||||
lda v3
|
||||
sta v7
|
||||
lda v6
|
||||
mul2 0x1, v7
|
||||
sta v3
|
||||
lda v6
|
||||
sta v7
|
||||
lda v7
|
||||
inc 0x2
|
||||
sta v6
|
||||
lda v7
|
||||
tonumeric 0x3
|
||||
jmp jump_label_1
|
||||
jump_label_0:
|
||||
lda.dyn v0
|
||||
sta.dyn v3
|
||||
ldai.dyn 0x2
|
||||
ecma.add2dyn v3
|
||||
sta.dyn v2
|
||||
lda.dyn v2
|
||||
sta.dyn v3
|
||||
lda.dyn v3
|
||||
return.dyn
|
||||
lda v3
|
||||
sta v6
|
||||
ldai 0x2
|
||||
add2 0x4, v6
|
||||
sta v4
|
||||
lda v4
|
||||
return
|
||||
}
|
||||
)";
|
||||
panda::pandasm::Parser parser;
|
||||
auto res = parser.Parse(source);
|
||||
auto &program = res.Value();
|
||||
const std::string fun_name = "foo:(any)";
|
||||
const std::string fun_name = "foo:(any,any,any,any)";
|
||||
auto it = program.function_table.find(fun_name);
|
||||
TestAssertNotEqual(it, program.function_table.end());
|
||||
EXPECT_NE(it, program.function_table.end());
|
||||
|
||||
auto &func = it->second;
|
||||
std::vector<panda::pandasm::ScalarValue> elements;
|
||||
panda::pandasm::LiteralArray lit_arr;
|
||||
static const TypeInfoIndex NUM_TYPE = static_cast<uint8_t>(1);
|
||||
static const TypeInfoIndex STR_TYPE = static_cast<uint8_t>(4);
|
||||
// set arg type
|
||||
AddTypeinfo(&elements, -1, NUM_TYPE); // -1: first arg
|
||||
const auto THIS_TYPE = AddAnTypeLiteralArray(program);
|
||||
AddTypeinfo(lit_arr, -3, THIS_TYPE); // -3: the arg "this"
|
||||
AddTypeinfo(lit_arr, -4, NUM_TYPE); // -4: the first arg
|
||||
// set ins type
|
||||
const size_t ADD_IDX = 26;
|
||||
TestAssertEqual(func.ins[ADD_IDX].opcode, panda::pandasm::Opcode::ECMA_ADD2DYN);
|
||||
TestAssertEqual(func.ins[ADD_IDX + 1].opcode, panda::pandasm::Opcode::STA_DYN);
|
||||
const size_t ADD_IDX = 29;
|
||||
EXPECT_EQ(func.ins[ADD_IDX].opcode, panda::pandasm::Opcode::ADD2);
|
||||
EXPECT_EQ(func.ins[ADD_IDX + 1].opcode, panda::pandasm::Opcode::STA);
|
||||
int32_t num_invalid = std::count_if(func.ins.begin(), func.ins.begin() + ADD_IDX,
|
||||
[](const auto &in) { return in.opcode == panda::pandasm::Opcode::INVALID; });
|
||||
AddTypeinfo(&elements, ADD_IDX + 1 - num_invalid, STR_TYPE); // exclude invalid insns because they do not emit
|
||||
AddTypeinfo(lit_arr, ADD_IDX + 1 - num_invalid, STR_TYPE); // exclude invalid insns because they do not emit
|
||||
|
||||
SetTypeAnnotationForFunc(elements, func, program);
|
||||
SetTypeAnnotationForFunc(lit_arr, func, program);
|
||||
|
||||
EmitAndOptimize("TypeAdaptionTest_UnconditionalJump.abc", program);
|
||||
|
||||
// check typeinfo after optimization
|
||||
it = program.function_table.find(fun_name);
|
||||
TestAssertNotEqual(it, program.function_table.end());
|
||||
EXPECT_NE(it, program.function_table.end());
|
||||
const auto &foo = it->second;
|
||||
const auto typeinfo = ExtractTypeinfo(foo);
|
||||
CheckTypeExist(typeinfo, -1, NUM_TYPE); // -1: first arg
|
||||
const auto typeinfo = ExtractTypeinfo(foo, program);
|
||||
CheckTypeExist(typeinfo, -3, THIS_TYPE); // -3: the arg "this"
|
||||
CheckTypeExist(typeinfo, -4, NUM_TYPE); // -4: the first arg
|
||||
auto add_it = std::find_if(foo.ins.begin(), foo.ins.end(),
|
||||
[](const auto &in) { return in.opcode == panda::pandasm::Opcode::ECMA_ADD2DYN; });
|
||||
TestAssertNotEqual(add_it, foo.ins.end());
|
||||
[](const auto &in) { return in.opcode == panda::pandasm::Opcode::ADD2; });
|
||||
EXPECT_NE(add_it, foo.ins.end());
|
||||
const auto opt_add_idx = static_cast<size_t>(add_it - foo.ins.begin());
|
||||
TestAssertEqual(foo.ins[opt_add_idx].opcode, panda::pandasm::Opcode::ECMA_ADD2DYN);
|
||||
TestAssertTrue(opt_add_idx + 1 < foo.ins.size());
|
||||
TestAssertNotEqual(foo.ins[opt_add_idx + 1].opcode, panda::pandasm::Opcode::STA_DYN);
|
||||
EXPECT_EQ(foo.ins[opt_add_idx].opcode, panda::pandasm::Opcode::ADD2);
|
||||
EXPECT_TRUE(opt_add_idx + 1 < foo.ins.size());
|
||||
EXPECT_NE(foo.ins[opt_add_idx + 1].opcode, panda::pandasm::Opcode::STA);
|
||||
|
||||
num_invalid = std::count_if(foo.ins.begin(), add_it,
|
||||
[](const auto &in) { return in.opcode == panda::pandasm::Opcode::INVALID; });
|
||||
int32_t add_type_idx = opt_add_idx - num_invalid; // exclude invalid insns because they do not emit
|
||||
CheckTypeExist(typeinfo, add_type_idx, STR_TYPE); // type is on ecma.add2dyn as it does not have sta.dyn
|
||||
CheckTypeExist(typeinfo, add_type_idx, STR_TYPE); // type is on add2 as it does not have sta
|
||||
}
|
||||
} // namespace panda::bytecodeopt::test
|
||||
|
||||
int main()
|
||||
{
|
||||
panda::bytecodeopt::test::BytecodeOptimizerTypeAdaptionTest test;
|
||||
std::cout << "BytecodeOptimizerTypeAdaptionTest: " << std::endl;
|
||||
test.TypeAdaptionTest();
|
||||
std::cout << "PASS!" << std::endl;
|
||||
std::cout << "BytecodeOptimizerTypeAdaptionTest_UnconditionalJump: " << std::endl;
|
||||
test.TypeAdaptionTest_UnconditionalJump();
|
||||
std::cout << "PASS!" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
} // namespace panda::bytecodeopt::test
|
||||
|
564
bytecode_optimizer/tests/codegen_test.cpp
Normal file
564
bytecode_optimizer/tests/codegen_test.cpp
Normal file
@ -0,0 +1,564 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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-parser.h"
|
||||
#include "codegen.h"
|
||||
#include "compiler/optimizer/optimizations/cleanup.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 "reg_acc_alloc.h"
|
||||
#include "reg_encoder.h"
|
||||
#include "graph_test.h"
|
||||
#include "mem/pool_manager.h"
|
||||
|
||||
using namespace testing::ext;
|
||||
|
||||
namespace panda::bytecodeopt {
|
||||
using namespace compiler;
|
||||
using namespace pandasm;
|
||||
using namespace panda;
|
||||
class CodegenTest : public testing::Test {
|
||||
public:
|
||||
static void SetUpTestCase(void) {}
|
||||
static void TearDownTestCase(void) {}
|
||||
void SetUp() {}
|
||||
void TearDown() {}
|
||||
|
||||
GraphTest graph_test_;
|
||||
};
|
||||
|
||||
std::unique_ptr<const panda_file::File> ParseAndEmit(const std::string &source)
|
||||
{
|
||||
panda::pandasm::Parser parser;
|
||||
auto res = parser.Parse(source);
|
||||
EXPECT_EQ(parser.ShowError().err, Error::ErrorType::ERR_NONE);
|
||||
auto &program = res.Value();
|
||||
return AsmEmitter::Emit(program);
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: codegen_test_001
|
||||
* @tc.desc: Verify the DoLda function.
|
||||
* @tc.type: FUNC
|
||||
* @tc.require: issueNumber
|
||||
*/
|
||||
HWTEST_F(CodegenTest, codegen_test_001, TestSize.Level1)
|
||||
{
|
||||
Register reg = 1; // 1: It's a random number
|
||||
std::vector<Ins> result;
|
||||
DoLda(reg, result);
|
||||
EXPECT_EQ(result[0].regs[0], reg);
|
||||
EXPECT_EQ(result[0].opcode, panda::pandasm::Opcode::LDA);
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: codegen_test_002
|
||||
* @tc.desc: Verify the DoSta function.
|
||||
* @tc.type: FUNC
|
||||
* @tc.require: issueNumber
|
||||
*/
|
||||
HWTEST_F(CodegenTest, codegen_test_002, TestSize.Level1)
|
||||
{
|
||||
Register reg = 1; // 1: It's a random number
|
||||
std::vector<Ins> result;
|
||||
DoSta(reg, result);
|
||||
EXPECT_EQ(result[0].regs[0], reg);
|
||||
EXPECT_EQ(result[0].opcode, panda::pandasm::Opcode::STA);
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: codegen_test_003
|
||||
* @tc.desc: Verify the EmitJump function.
|
||||
* @tc.type: FUNC
|
||||
* @tc.require: issueNumber
|
||||
*/
|
||||
HWTEST_F(CodegenTest, codegen_test_003, TestSize.Level1)
|
||||
{
|
||||
std::string pfile = GRAPH_TEST_ABC_DIR "codegenTryCatch.abc";
|
||||
const char *test_method_name = "func1";
|
||||
bool status = false;
|
||||
|
||||
graph_test_.TestBuildGraphFromFile(pfile, [test_method_name, &status](Graph* graph, std::string &method_name) {
|
||||
if (test_method_name != method_name) {
|
||||
return;
|
||||
}
|
||||
|
||||
EXPECT_NE(graph, nullptr);
|
||||
for (auto bb : graph->GetBlocksRPO()) {
|
||||
EXPECT_NE(bb, nullptr);
|
||||
if (bb->IsTryBegin()) {
|
||||
status = true;
|
||||
Function *function = nullptr;
|
||||
BytecodeOptIrInterface *interface = nullptr;
|
||||
Program *prog = nullptr;
|
||||
BytecodeGen bc_gen(graph, function, interface, prog);
|
||||
bc_gen.EmitJump(bb->GetSuccessor(1));
|
||||
EXPECT_FALSE(bc_gen.GetResult().empty());
|
||||
EXPECT_EQ(bc_gen.GetResult().back().ids[0], "label_6");
|
||||
bc_gen.EmitJump(bb->GetSuccessor(0));
|
||||
EXPECT_EQ(bc_gen.GetResult().back().ids[0], "label_3");
|
||||
}
|
||||
}
|
||||
});
|
||||
EXPECT_TRUE(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: codegen_test_004
|
||||
* @tc.desc: Verify the EmitJump function.
|
||||
* @tc.type: FUNC
|
||||
* @tc.require: issueNumber
|
||||
*/
|
||||
HWTEST_F(CodegenTest, codegen_test_004, TestSize.Level1)
|
||||
{
|
||||
std::string pfile = GRAPH_TEST_ABC_DIR "codegenTryCatch.abc";
|
||||
const char *test_method_name = "func2";
|
||||
bool status = false;
|
||||
|
||||
graph_test_.TestBuildGraphFromFile(pfile, [test_method_name, &status](Graph* graph, std::string &method_name) {
|
||||
if (test_method_name != method_name) {
|
||||
return;
|
||||
}
|
||||
|
||||
EXPECT_NE(graph, nullptr);
|
||||
for (auto bb : graph->GetBlocksRPO()) {
|
||||
EXPECT_NE(bb, nullptr);
|
||||
for(auto inst : bb->AllInsts()){
|
||||
if(inst->GetOpcode() == Opcode::IfImm){
|
||||
status = true;
|
||||
Function *function = nullptr;
|
||||
BytecodeOptIrInterface *interface = nullptr;
|
||||
Program *prog = nullptr;
|
||||
BytecodeGen bc_gen(graph, function, interface, prog);
|
||||
bc_gen.EmitJump(bb);
|
||||
EXPECT_FALSE(bc_gen.GetResult().empty());
|
||||
EXPECT_EQ(bc_gen.GetResult().back().opcode, panda::pandasm::Opcode::JMP);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
EXPECT_TRUE(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: codegen_test_005
|
||||
* @tc.desc: Verify the VisitConstant function.
|
||||
* @tc.type: FUNC
|
||||
* @tc.require: issueNumber
|
||||
*/
|
||||
HWTEST_F(CodegenTest, codegen_test_005, TestSize.Level1)
|
||||
{
|
||||
std::string pfile = GRAPH_TEST_ABC_DIR "codegenTryCatch.abc";
|
||||
const char *test_method_name = "func5";
|
||||
bool status = false;
|
||||
|
||||
graph_test_.TestBuildGraphFromFile(pfile, [test_method_name, &status](Graph* graph, std::string &method_name) {
|
||||
if (test_method_name != method_name) {
|
||||
return;
|
||||
}
|
||||
|
||||
EXPECT_NE(graph, nullptr);
|
||||
for (auto bb : graph->GetBlocksRPO()) {
|
||||
for(auto inst : bb->AllInsts()) {
|
||||
if (inst->GetOpcode() != Opcode::Constant) {
|
||||
continue;
|
||||
}
|
||||
status = true;
|
||||
Function *function = nullptr;
|
||||
BytecodeOptIrInterface *interface = nullptr;
|
||||
Program *prog = nullptr;
|
||||
|
||||
BytecodeGen graph_visitor(graph, function, interface, prog);
|
||||
|
||||
ConstantInst *const_inst = inst->CastToConstant();
|
||||
const_inst->SetType(DataType::Type::INT64);
|
||||
EXPECT_EQ(const_inst->GetType(), DataType::Type::INT64);
|
||||
Register reg = INVALID_REG;
|
||||
const_inst->SetDstReg(reg);
|
||||
EXPECT_EQ(const_inst->GetDstReg(), reg);
|
||||
BytecodeGen::VisitConstant(&graph_visitor, const_inst);
|
||||
EXPECT_FALSE(graph_visitor.GetResult().empty());
|
||||
EXPECT_EQ(graph_visitor.GetResult().back().opcode, panda::pandasm::Opcode::STA);
|
||||
|
||||
ConstantInst *const_inst1 = inst->CastToConstant();
|
||||
const_inst1->SetType(DataType::Type::FLOAT64);
|
||||
EXPECT_EQ(const_inst->GetType(), DataType::Type::FLOAT64);
|
||||
const_inst1->SetDstReg(reg);
|
||||
EXPECT_EQ(const_inst->GetDstReg(), reg);
|
||||
BytecodeGen::VisitConstant(&graph_visitor, const_inst1);
|
||||
EXPECT_FALSE(graph_visitor.GetResult().empty());
|
||||
EXPECT_EQ(graph_visitor.GetResult().back().opcode, panda::pandasm::Opcode::STA);
|
||||
|
||||
ConstantInst *const_inst2 = inst->CastToConstant();
|
||||
const_inst2->SetType(DataType::Type::INT32);
|
||||
EXPECT_EQ(const_inst->GetType(), DataType::Type::INT32);
|
||||
const_inst2->SetDstReg(reg);
|
||||
EXPECT_EQ(const_inst->GetDstReg(), reg);
|
||||
BytecodeGen::VisitConstant(&graph_visitor, const_inst2);
|
||||
EXPECT_FALSE(graph_visitor.GetResult().empty());
|
||||
EXPECT_EQ(graph_visitor.GetResult().back().opcode, panda::pandasm::Opcode::STA);
|
||||
}
|
||||
}
|
||||
});
|
||||
EXPECT_TRUE(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: codegen_test_006
|
||||
* @tc.desc: Verify the EncodeSta function.
|
||||
* @tc.type: FUNC
|
||||
* @tc.require: issueNumber
|
||||
*/
|
||||
HWTEST_F(CodegenTest, codegen_test_006, TestSize.Level1)
|
||||
{
|
||||
std::string pfile = GRAPH_TEST_ABC_DIR "codegenTryCatch.abc";
|
||||
const char *test_method_name = "func1";
|
||||
bool status = false;
|
||||
|
||||
graph_test_.TestBuildGraphFromFile(pfile, [test_method_name, &status](Graph* graph, std::string &method_name) {
|
||||
if (test_method_name != method_name) {
|
||||
return;
|
||||
}
|
||||
|
||||
EXPECT_NE(graph, nullptr);
|
||||
for (auto bb : graph->GetBlocksRPO()) {
|
||||
EXPECT_NE(bb, nullptr);
|
||||
if (bb->IsTryBegin()) {
|
||||
status = true;
|
||||
Register reg = 1; // 1: It's a random number
|
||||
Function *function = nullptr;
|
||||
BytecodeOptIrInterface *interface = nullptr;
|
||||
Program *prog = nullptr;
|
||||
BytecodeGen bc_gen(graph, function, interface, prog);
|
||||
bc_gen.EncodeSta(reg, DataType::Type::ANY);
|
||||
EXPECT_FALSE(bc_gen.GetResult().empty());
|
||||
EXPECT_EQ(bc_gen.GetResult().back().opcode, panda::pandasm::Opcode::STA);
|
||||
}
|
||||
}
|
||||
});
|
||||
EXPECT_TRUE(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: codegen_test_007
|
||||
* @tc.desc: Verify the VisitLoadString function.
|
||||
* @tc.type: FUNC
|
||||
* @tc.require: issueNumber
|
||||
*/
|
||||
HWTEST_F(CodegenTest, codegen_test_007, TestSize.Level1)
|
||||
{
|
||||
std::string pfile = GRAPH_TEST_ABC_DIR "codegenTryCatch.abc";
|
||||
const char *test_method_name = "func6";
|
||||
bool status = false;
|
||||
|
||||
graph_test_.TestBuildGraphFromFile(pfile, [test_method_name, &status](Graph* graph, std::string &method_name) {
|
||||
if (test_method_name != method_name) {
|
||||
return;
|
||||
}
|
||||
|
||||
EXPECT_NE(graph, nullptr);
|
||||
for (auto bb : graph->GetVectorBlocks()) {
|
||||
EXPECT_NE(bb, nullptr);
|
||||
for(auto inst1 : bb->AllInsts()) {
|
||||
if (inst1->GetOpcode() != Opcode::LoadString) {
|
||||
continue;
|
||||
}
|
||||
status = true;
|
||||
Function *function = nullptr;
|
||||
Program *prog = nullptr;
|
||||
AsmEmitter::PandaFileToPandaAsmMaps maps;
|
||||
uint32_t id = 2; // 2: It's a random number
|
||||
maps.strings.emplace(id, "i32[]");
|
||||
BytecodeOptIrInterface interface(&maps, prog);
|
||||
|
||||
BytecodeGen graph_visitor(graph, function, &interface, prog);
|
||||
auto inst = inst1->CastToLoadString();
|
||||
inst->SetTypeId(2);
|
||||
|
||||
unsigned index = 5; // 5: It's a random number
|
||||
unsigned size = 6; // 6: It's a random number
|
||||
User user(true, index, size);
|
||||
inst->AddUser(&user);
|
||||
|
||||
Register reg1 = ACC_REG_ID;
|
||||
inst->SetDstReg(reg1);
|
||||
BytecodeGen::VisitLoadString(&graph_visitor, inst);
|
||||
EXPECT_FALSE(graph_visitor.GetResult().empty());
|
||||
EXPECT_EQ(graph_visitor.GetResult().back().opcode, panda::pandasm::Opcode::LDA_STR);
|
||||
|
||||
Register reg2 = INVALID_REG;
|
||||
inst->SetDstReg(reg2);
|
||||
BytecodeGen::VisitLoadString(&graph_visitor, inst);
|
||||
EXPECT_FALSE(graph_visitor.GetResult().empty());
|
||||
EXPECT_EQ(graph_visitor.GetResult().back().opcode, panda::pandasm::Opcode::STA);
|
||||
}
|
||||
}
|
||||
});
|
||||
EXPECT_TRUE(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: codegen_test_008
|
||||
* @tc.desc: Verify the VisitDefault function.
|
||||
* @tc.type: FUNC
|
||||
* @tc.require: issueNumber
|
||||
*/
|
||||
HWTEST_F(CodegenTest, codegen_test_008, TestSize.Level1)
|
||||
{
|
||||
std::string pfile = GRAPH_TEST_ABC_DIR "codegenTryCatch.abc";
|
||||
const char *test_method_name = "func1";
|
||||
bool status = false;
|
||||
|
||||
graph_test_.TestBuildGraphFromFile(pfile, [test_method_name, &status](Graph* graph, std::string &method_name) {
|
||||
if (test_method_name != method_name) {
|
||||
return;
|
||||
}
|
||||
|
||||
EXPECT_NE(graph, nullptr);
|
||||
for (auto bb : graph->GetBlocksRPO()) {
|
||||
EXPECT_NE(bb, nullptr);
|
||||
if (bb->IsTryBegin()) {
|
||||
status = true;
|
||||
Function *function = nullptr;
|
||||
BytecodeOptIrInterface *interface = nullptr;
|
||||
Program *prog = nullptr;
|
||||
BytecodeGen bc_gen(graph, function, interface, prog);
|
||||
bc_gen.VisitDefault(bb->GetFirstInst());
|
||||
EXPECT_FALSE(bc_gen.GetStatus());
|
||||
}
|
||||
}
|
||||
});
|
||||
EXPECT_TRUE(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: codegen_test_009
|
||||
* @tc.desc: Verify the GetLiteralArrayByOffset function.
|
||||
* @tc.type: FUNC
|
||||
* @tc.require: issueNumber
|
||||
*/
|
||||
HWTEST_F(CodegenTest, codegen_test_009, TestSize.Level1)
|
||||
{
|
||||
AsmEmitter::PandaFileToPandaAsmMaps maps;
|
||||
uint32_t id = 2; // 2: It's a random number
|
||||
maps.literalarrays.emplace(id, "i32[]");
|
||||
maps.strings.emplace(id, "i33[]");
|
||||
Program *prog = nullptr;
|
||||
BytecodeOptIrInterface interface(&maps, prog);
|
||||
|
||||
uint32_t offset = 2; // 2: It's a random number
|
||||
EXPECT_EQ(interface.GetLiteralArrayByOffset(offset), "i32[]");
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: codegen_test_010
|
||||
* @tc.desc: Verify the GetTypeIdByOffset function.
|
||||
* @tc.type: FUNC
|
||||
* @tc.require: issueNumber
|
||||
*/
|
||||
HWTEST_F(CodegenTest, codegen_test_010, TestSize.Level1)
|
||||
{
|
||||
AsmEmitter::PandaFileToPandaAsmMaps maps;
|
||||
uint32_t id = 2; // 2: It's a random number
|
||||
maps.classes.emplace(id, "i32[]");
|
||||
Program *prog = nullptr;
|
||||
BytecodeOptIrInterface interface(&maps, prog);
|
||||
|
||||
uint32_t offset = 2; // 2: It's a random number
|
||||
EXPECT_EQ(interface.GetTypeIdByOffset(offset), "i32[]");
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: codegen_test_011
|
||||
* @tc.desc: Verify the GetFieldIdByOffset function.
|
||||
* @tc.type: FUNC
|
||||
* @tc.require: issueNumber
|
||||
*/
|
||||
HWTEST_F(CodegenTest, codegen_test_011, TestSize.Level1)
|
||||
{
|
||||
AsmEmitter::PandaFileToPandaAsmMaps maps;
|
||||
uint32_t id = 2; // 2: It's a random number
|
||||
maps.fields.emplace(id, "i32[]");
|
||||
Program *prog = nullptr;
|
||||
BytecodeOptIrInterface interface(&maps, prog);
|
||||
|
||||
uint32_t offset = 2; // 2: It's a random number
|
||||
interface.GetFieldIdByOffset(offset);
|
||||
EXPECT_EQ(interface.GetFieldIdByOffset(offset), "i32[]");
|
||||
EXPECT_TRUE(interface.IsMapsSet());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @tc.name: codegen_test_012
|
||||
* @tc.desc: Verify the GetMethodArgumentsCount function.
|
||||
* @tc.type: FUNC
|
||||
* @tc.require: issueNumber
|
||||
*/
|
||||
HWTEST_F(CodegenTest, codegen_test_012, TestSize.Level1)
|
||||
{
|
||||
auto source = std::string(R"(
|
||||
.function u1 foo() {
|
||||
sta v4
|
||||
lda v4
|
||||
return
|
||||
}
|
||||
)");
|
||||
std::unique_ptr<const panda_file::File> pfile = ParseAndEmit(source);
|
||||
BytecodeOptimizerRuntimeAdapter runtime_adapter(*pfile.get());
|
||||
|
||||
RuntimeInterface::MethodPtr caller = nullptr;
|
||||
BytecodeOptimizerRuntimeAdapter::MethodId id = 251; // 251: It's a random number
|
||||
EXPECT_EQ(runtime_adapter.GetMethodArgumentsCount(caller, id), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: codegen_test_013
|
||||
* @tc.desc: Verify the GetMethodFullName function.
|
||||
* @tc.type: FUNC
|
||||
* @tc.require: issueNumber
|
||||
*/
|
||||
HWTEST_F(CodegenTest, codegen_test_013, TestSize.Level1)
|
||||
{
|
||||
auto source = std::string(R"(
|
||||
.function u1 foo() {
|
||||
sta v4
|
||||
lda v4
|
||||
return
|
||||
}
|
||||
)");
|
||||
std::unique_ptr<const panda_file::File> pfile = ParseAndEmit(source);
|
||||
BytecodeOptimizerRuntimeAdapter runtime_adapter(*pfile.get());
|
||||
|
||||
int f = 222; // 222: It's a random number
|
||||
RuntimeInterface::MethodPtr method;
|
||||
method=(void*)(long)f;
|
||||
|
||||
EXPECT_EQ(runtime_adapter.GetMethodFullName(method, false), "L_ESSlotNumberAnnotation;::SlotNumber");
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: codegen_test_014
|
||||
* @tc.desc: Verify the GetBlocksToVisit function.
|
||||
* @tc.type: FUNC
|
||||
* @tc.require: issueNumber
|
||||
*/
|
||||
HWTEST_F(CodegenTest, codegen_test_014, TestSize.Level1)
|
||||
{
|
||||
std::string pfile = GRAPH_TEST_ABC_DIR "codegenTryCatch.abc";
|
||||
const char *test_method_name = "func1";
|
||||
bool status = false;
|
||||
|
||||
graph_test_.TestBuildGraphFromFile(pfile, [test_method_name, &status](Graph* graph, std::string &method_name) {
|
||||
if (test_method_name != method_name) {
|
||||
return;
|
||||
}
|
||||
status = true;
|
||||
EXPECT_NE(graph, nullptr);
|
||||
|
||||
Function *function = nullptr;
|
||||
BytecodeOptIrInterface *interface = nullptr;
|
||||
Program *prog = nullptr;
|
||||
size_t size = 10; // 10: It's block size
|
||||
BytecodeGen bc_gen(graph, function, interface, prog);
|
||||
EXPECT_EQ(bc_gen.GetBlocksToVisit().size(), size);
|
||||
});
|
||||
EXPECT_TRUE(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: codegen_test_015
|
||||
* @tc.desc: Verify the RunImpl function.
|
||||
* @tc.type: FUNC
|
||||
* @tc.require: issueNumber
|
||||
*/
|
||||
HWTEST_F(CodegenTest, codegen_test_015, TestSize.Level1)
|
||||
{
|
||||
const auto source = R"(
|
||||
.function any func_main_0(any a0, any a1, any a2) <static> {
|
||||
mov v0, a0
|
||||
mov v1, a1
|
||||
mov v2, a2
|
||||
try_begin_label_0:
|
||||
ldai 0x1
|
||||
trystglobalbyname 0x0, "a"
|
||||
try_end_label_0:
|
||||
jmp handler_end_label_0_0
|
||||
handler_begin_label_0_0:
|
||||
sta v4
|
||||
ldai 0x2
|
||||
trystglobalbyname 0x1, "a"
|
||||
handler_end_label_0_0:
|
||||
ldundefined
|
||||
returnundefined
|
||||
|
||||
.catchall try_begin_label_0, try_end_label_0, handler_begin_label_0_0, handler_end_label_0_0
|
||||
}
|
||||
)";
|
||||
|
||||
panda::pandasm::Parser parser;
|
||||
auto res = parser.Parse(source);
|
||||
auto &prog = res.Value();
|
||||
|
||||
auto &function = prog.function_table.at("func_main_0:(any,any,any)");
|
||||
|
||||
pandasm::AsmEmitter::PandaFileToPandaAsmMaps maps {};
|
||||
auto ir_interface = panda::bytecodeopt::BytecodeOptIrInterface(&maps, &prog);
|
||||
bool status = false;
|
||||
|
||||
graph_test_.TestBuildGraphFromFunc(prog, "func_main_0:(any,any,any)", maps, ir_interface, [&function,
|
||||
&ir_interface, &prog, &status](Graph* graph) {
|
||||
|
||||
EXPECT_NE(graph, nullptr);
|
||||
int32_t pc = -1; // -1: It's a random number
|
||||
uint8_t id1 = 2; // 2: It's a random number
|
||||
TypeInfoIndex type = static_cast<BuiltinIndexType>(id1);
|
||||
graph->GetRuntime()->AddPcTypePair(pc, type);
|
||||
|
||||
size_t id = 13; // 13: It's a random number
|
||||
graph->GetRuntime()->FillInstIdTypePairByPc(id, pc);
|
||||
|
||||
for (auto bb : graph->GetBlocksRPO()) {
|
||||
EXPECT_NE(bb, nullptr);
|
||||
if(bb->IsTryBegin()){
|
||||
status = true;
|
||||
graph->AppendTryBeginBlock(bb);
|
||||
}
|
||||
}
|
||||
EXPECT_TRUE(graph->RunPass<compiler::Cleanup>());
|
||||
LiteralArray lit;
|
||||
const auto &key = *(graph->GetRuntime()->GetTypeLiteralArrayKey());
|
||||
prog.literalarray_table[key] = lit;
|
||||
|
||||
EXPECT_FALSE(graph->RunPass<compiler::Cleanup>());
|
||||
EXPECT_FALSE(graph->RunPass<panda::compiler::ValNum>());
|
||||
EXPECT_TRUE(graph->RunPass<panda::compiler::Lowering>());
|
||||
EXPECT_TRUE(graph->RunPass<panda::compiler::MoveConstants>());
|
||||
EXPECT_FALSE(graph->RunPass<compiler::Cleanup>());
|
||||
EXPECT_TRUE(graph->RunPass<RegAccAlloc>());
|
||||
EXPECT_FALSE(graph->RunPass<compiler::Cleanup>());
|
||||
EXPECT_TRUE(RegAlloc(graph));
|
||||
EXPECT_FALSE(graph->RunPass<compiler::Cleanup>());
|
||||
EXPECT_TRUE(graph->RunPass<RegEncoder>());
|
||||
|
||||
EXPECT_TRUE(graph->RunPass<BytecodeGen>(&function, &ir_interface, &prog));
|
||||
});
|
||||
EXPECT_TRUE(status);
|
||||
}
|
||||
} // namespace panda::bytecodeopt
|
@ -35,7 +35,7 @@ public:
|
||||
{
|
||||
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::OptimizeBytecode(&program, &panda_file_to_asm_maps, abc_file_name, false));
|
||||
EXPECT_TRUE(panda::bytecodeopt::OptimizeBytecode(&program, &panda_file_to_asm_maps, abc_file_name, true));
|
||||
}
|
||||
};
|
||||
|
||||
|
108
bytecode_optimizer/tests/graph_test.h
Normal file
108
bytecode_optimizer/tests/graph_test.h
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 GRAPH_TEST_H
|
||||
#define GRAPH_TEST_H
|
||||
|
||||
#include "bytecode_optimizer/ir_interface.h"
|
||||
#include "bytecode_optimizer/runtime_adapter.h"
|
||||
#include "libpandafile/class_data_accessor.h"
|
||||
#include "libpandafile/class_data_accessor-inl.h"
|
||||
#include "libpandafile/file.h"
|
||||
#include "libpandafile/method_data_accessor.h"
|
||||
#include "libpandabase/mem/arena_allocator.h"
|
||||
#include "libpandabase/mem/pool_manager.h"
|
||||
#include "optimizer/ir/graph.h"
|
||||
#include "optimizer/ir/runtime_interface.h"
|
||||
#include "optimizer/ir_builder/ir_builder.h"
|
||||
|
||||
namespace panda::compiler {
|
||||
|
||||
class GraphTest {
|
||||
public:
|
||||
GraphTest()
|
||||
{
|
||||
PoolManager::Initialize(PoolType::MALLOC);
|
||||
}
|
||||
|
||||
~GraphTest()
|
||||
{
|
||||
PoolManager::Finalize();
|
||||
}
|
||||
|
||||
template <class Callback>
|
||||
void TestBuildGraphFromFile(const std::string &pfile_name, const Callback &cb)
|
||||
{
|
||||
auto pfile = panda_file::OpenPandaFile(pfile_name);
|
||||
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};
|
||||
cda.EnumerateMethods([&pfile, &cb](panda_file::MethodDataAccessor &mda) {
|
||||
if (!mda.IsExternal()) {
|
||||
ArenaAllocator allocator {SpaceType::SPACE_TYPE_COMPILER};
|
||||
ArenaAllocator local_allocator {SpaceType::SPACE_TYPE_COMPILER, nullptr, true};
|
||||
|
||||
auto method_ptr = reinterpret_cast<compiler::RuntimeInterface::MethodPtr>(
|
||||
mda.GetMethodId().GetOffset());
|
||||
panda::BytecodeOptimizerRuntimeAdapter adapter(mda.GetPandaFile());
|
||||
auto *graph = allocator.New<Graph>(&allocator, &local_allocator, Arch::NONE, method_ptr, &adapter,
|
||||
false, nullptr, true, true);
|
||||
graph->RunPass<panda::compiler::IrBuilder>();
|
||||
|
||||
auto method_name = std::string(utf::Mutf8AsCString(pfile->GetStringData(mda.GetNameId()).data));
|
||||
|
||||
cb(graph, method_name);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
template <class Callback>
|
||||
void TestBuildGraphFromFunc(pandasm::Program &prog, const char *method_name,
|
||||
pandasm::AsmEmitter::PandaFileToPandaAsmMaps &maps, bytecodeopt::BytecodeOptIrInterface &ir_interface,
|
||||
const Callback &cb)
|
||||
{
|
||||
auto pfile = pandasm::AsmEmitter::Emit(prog, &maps);
|
||||
for (uint32_t id : pfile->GetClasses()) {
|
||||
panda_file::File::EntityId record_id {id};
|
||||
panda_file::ClassDataAccessor cda {*pfile, record_id};
|
||||
cda.EnumerateMethods([maps, method_name, ir_interface, &cb](panda_file::MethodDataAccessor &mda) {
|
||||
auto func_name = ir_interface.GetMethodIdByOffset(mda.GetMethodId().GetOffset());
|
||||
if (func_name != method_name) {
|
||||
return;
|
||||
}
|
||||
|
||||
ArenaAllocator allocator {SpaceType::SPACE_TYPE_COMPILER};
|
||||
ArenaAllocator local_allocator {SpaceType::SPACE_TYPE_COMPILER, nullptr, true};
|
||||
|
||||
auto method_ptr = reinterpret_cast<compiler::RuntimeInterface::MethodPtr>(
|
||||
mda.GetMethodId().GetOffset());
|
||||
panda::BytecodeOptimizerRuntimeAdapter adapter(mda.GetPandaFile());
|
||||
auto *graph = allocator.New<Graph>(&allocator, &local_allocator, Arch::NONE, method_ptr, &adapter,
|
||||
false, nullptr, true, true);
|
||||
graph->RunPass<panda::compiler::IrBuilder>();
|
||||
cb(graph);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace panda::compiler
|
||||
|
||||
#endif // GRAPH_TEST_H
|
64
bytecode_optimizer/tests/js/codegenTryCatch.js
Normal file
64
bytecode_optimizer/tests/js/codegenTryCatch.js
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
Copyright (c) 2023 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.
|
||||
*/
|
||||
|
||||
|
||||
function func1() {
|
||||
let a = 1.5;
|
||||
try {
|
||||
a += 1;
|
||||
} catch(e) {
|
||||
a++;
|
||||
}
|
||||
a++;
|
||||
return a;
|
||||
}
|
||||
|
||||
function func2(a, b, c) {
|
||||
var a = 1;
|
||||
if (a) {
|
||||
return a;
|
||||
}
|
||||
else
|
||||
a += 1;
|
||||
}
|
||||
|
||||
function func3(a, b, c, d, e) {
|
||||
return a + b + c + d + e;
|
||||
}
|
||||
|
||||
function func4(x, y) {
|
||||
var a = x + y;
|
||||
var b = x - y;
|
||||
var c = x * y;
|
||||
var d = x / y;
|
||||
var e = x % y;
|
||||
return func3(e, d, c, b, a);
|
||||
}
|
||||
|
||||
function func5(i, j, l) {
|
||||
for (var i = 0; i <= 4; i++) {
|
||||
for (var j = 0; j <= 4; j++) {
|
||||
for(var k = 1; k <= 2; k++){
|
||||
System.out.printf(Loadstring);
|
||||
}
|
||||
}
|
||||
func4(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
function func6()
|
||||
{
|
||||
return "hello world";
|
||||
}
|
39
bytecode_optimizer/tests/js/optimizeTryCatch.js
Normal file
39
bytecode_optimizer/tests/js/optimizeTryCatch.js
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
Copyright (c) 2023 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.
|
||||
*/
|
||||
|
||||
|
||||
try {
|
||||
try {
|
||||
a = 1;
|
||||
} catch(e) {
|
||||
a;
|
||||
}
|
||||
if(a == "") {
|
||||
throw "null";
|
||||
}
|
||||
if(x > 100) {
|
||||
throw "max";
|
||||
} else {
|
||||
throw "min";
|
||||
}
|
||||
}
|
||||
catch(err) {
|
||||
func0(a, 10);
|
||||
}
|
||||
finally {
|
||||
console.log("error");
|
||||
}
|
||||
|
||||
|
225
bytecode_optimizer/tests/optimize_bytecode_test.cpp
Normal file
225
bytecode_optimizer/tests/optimize_bytecode_test.cpp
Normal file
@ -0,0 +1,225 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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-parser.h"
|
||||
#include "compiler/optimizer/ir/basicblock.h"
|
||||
#include "graph_test.h"
|
||||
#include "mem/pool_manager.h"
|
||||
#include "optimize_bytecode.h"
|
||||
|
||||
using namespace testing::ext;
|
||||
|
||||
namespace panda::bytecodeopt {
|
||||
using namespace compiler;
|
||||
using namespace panda::pandasm;
|
||||
|
||||
class OptimizeBytecodeTest : public testing::Test {
|
||||
public:
|
||||
static void SetUpTestCase(void) {}
|
||||
static void TearDownTestCase(void) {}
|
||||
void SetUp() {}
|
||||
void TearDown() {}
|
||||
|
||||
void EmitAndOptimize(const std::string &abc_file_name, panda::pandasm::Program &program) const
|
||||
{
|
||||
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::OptimizeBytecode(&program, &panda_file_to_asm_maps, abc_file_name, true));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @tc.name: optimize_bytecode_test_001
|
||||
* @tc.desc: Verify the OptimizeBytecode function.
|
||||
* @tc.type: FUNC
|
||||
* @tc.require: issueNumber
|
||||
*/
|
||||
HWTEST_F(OptimizeBytecodeTest, optimize_bytecode_test_001, TestSize.Level1) {
|
||||
const auto source = R"(
|
||||
.language ECMAScript
|
||||
.array array_unsigned_byte u8 3 { 1 2 3 }
|
||||
.record Asm4 { i32 asm1 }
|
||||
.function any func_main_0(any a0, any a1, any a2) <static> {
|
||||
ldundefined
|
||||
stglobalvar 0x0, "j"
|
||||
ldundefined
|
||||
stglobalvar 0x1, "n"
|
||||
lda.str "a b c"
|
||||
stglobalvar 0x2, "n"
|
||||
ldglobalvar 0x3, "n"
|
||||
getpropiterator
|
||||
sta v0
|
||||
jump_label_1:
|
||||
getnextpropname v0
|
||||
sta v1
|
||||
ldundefined
|
||||
eq 0x4, v1
|
||||
jnez jump_label_0
|
||||
lda v1
|
||||
stglobalvar 0x5, "j"
|
||||
tryldglobalbyname 0x6, "console"
|
||||
sta v1
|
||||
ldobjbyname 0x7, "log"
|
||||
sta v2
|
||||
ldglobalvar 0x9, "n"
|
||||
sta v3
|
||||
ldglobalvar 0xa, "j"
|
||||
ldobjbyvalue 0xb, v3
|
||||
sta v3
|
||||
lda v2
|
||||
callthis1 0xd, v1, v3
|
||||
jmp jump_label_1
|
||||
jump_label_0:
|
||||
ldundefined
|
||||
returnundefined
|
||||
}
|
||||
)";
|
||||
|
||||
panda::pandasm::Parser parser;
|
||||
auto res = parser.Parse(source);
|
||||
auto &program = res.Value();
|
||||
const std::string fun_name = "func_main_0:(any,any,any)";
|
||||
auto it = program.function_table.find(fun_name);
|
||||
EXPECT_NE(it, program.function_table.end());
|
||||
EmitAndOptimize("codegenTryCatch.abc", program);
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: optimize_bytecode_test_002
|
||||
* @tc.desc: Verify the OptimizeBytecode function.
|
||||
* @tc.type: FUNC
|
||||
* @tc.require: issueNumber
|
||||
*/
|
||||
HWTEST_F(OptimizeBytecodeTest, optimize_bytecode_test_002, TestSize.Level1) {
|
||||
const auto source = R"(
|
||||
.language ECMAScript
|
||||
.array array_unsigned_byte u8 3 { 1 2 3 }
|
||||
.record Asm4 { i32 asm1 }
|
||||
.function any func_main_0(any a0, any a1, any a2) <static> {
|
||||
ldundefined
|
||||
stglobalvar 0x0, "j"
|
||||
ldundefined
|
||||
stglobalvar 0x1, "n"
|
||||
lda.str "a b c"
|
||||
stglobalvar 0x2, "n"
|
||||
ldglobalvar 0x3, "n"
|
||||
getpropiterator
|
||||
sta v0
|
||||
jump_label_1:
|
||||
getnextpropname v0
|
||||
sta v1
|
||||
ldundefined
|
||||
eq 0x4, v1
|
||||
jnez jump_label_0
|
||||
lda v1
|
||||
stglobalvar 0x5, "j"
|
||||
tryldglobalbyname 0x6, "console"
|
||||
sta v1
|
||||
ldobjbyname 0x7, "log"
|
||||
sta v2
|
||||
ldglobalvar 0x9, "n"
|
||||
sta v3
|
||||
ldglobalvar 0xa, "j"
|
||||
ldobjbyvalue 0xb, v3
|
||||
sta v3
|
||||
lda v2
|
||||
callthis1 0xd, v1, v3
|
||||
jmp jump_label_1
|
||||
jump_label_0:
|
||||
ldundefined
|
||||
returnundefined
|
||||
}
|
||||
)";
|
||||
panda::pandasm::Parser parser;
|
||||
auto res = parser.Parse(source);
|
||||
auto &program = res.Value();
|
||||
const std::string fun_name = "func_main_0:(any,any,any)";
|
||||
auto it = program.function_table.find(fun_name);
|
||||
|
||||
EXPECT_NE(it, program.function_table.end());
|
||||
const std::string abc_file_name = "codegenTryCatch.abc";
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: optimize_bytecode_test_003
|
||||
* @tc.desc: Verify the OptimizeBytecode function.
|
||||
* @tc.type: FUNC
|
||||
* @tc.require: issueNumber
|
||||
*/
|
||||
HWTEST_F(OptimizeBytecodeTest, optimize_bytecode_test_003, TestSize.Level1) {
|
||||
const auto source = R"(
|
||||
.language ECMAScript
|
||||
.array array_unsigned_byte u8 3 { 1 2 3 }
|
||||
.record Asm4 { i32 asm1 }
|
||||
.function any func_main_0(any a0, any a1, any a2) <static> {
|
||||
ldundefined
|
||||
stglobalvar 0x0, "j"
|
||||
ldundefined
|
||||
stglobalvar 0x1, "n"
|
||||
lda.str "a b c"
|
||||
stglobalvar 0x2, "n"
|
||||
ldglobalvar 0x3, "n"
|
||||
getpropiterator
|
||||
sta v0
|
||||
jump_label_1:
|
||||
getnextpropname v0
|
||||
sta v1
|
||||
ldundefined
|
||||
eq 0x4, v1
|
||||
jnez jump_label_0
|
||||
lda v1
|
||||
stglobalvar 0x5, "j"
|
||||
tryldglobalbyname 0x6, "console"
|
||||
sta v1
|
||||
ldobjbyname 0x7, "log"
|
||||
sta v2
|
||||
ldglobalvar 0x9, "n"
|
||||
sta v3
|
||||
ldglobalvar 0xa, "j"
|
||||
ldobjbyvalue 0xb, v3
|
||||
sta v3
|
||||
lda v2
|
||||
callthis1 0xd, v1, v3
|
||||
jmp jump_label_1
|
||||
jump_label_0:
|
||||
ldundefined
|
||||
returnundefined
|
||||
}
|
||||
)";
|
||||
|
||||
panda::pandasm::Parser parser;
|
||||
auto res = parser.Parse(source);
|
||||
auto &program = res.Value();
|
||||
const std::string fun_name = "func_main_0:(any,any,any)";
|
||||
auto it = program.function_table.find(fun_name);
|
||||
|
||||
Function::CatchBlock cat;
|
||||
cat.try_end_label = "random"; // random: It's a random string
|
||||
it->second.catch_blocks.push_back(cat);
|
||||
EXPECT_NE(it, program.function_table.end());
|
||||
|
||||
const std::string abc_file_name = "codegenTryCatch.abc";
|
||||
|
||||
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));
|
||||
// do not optimize function having catch blocks"
|
||||
EXPECT_FALSE(panda::bytecodeopt::OptimizeBytecode(&program, &panda_file_to_asm_maps, abc_file_name, true));
|
||||
}
|
||||
} // namespace panda::bytecodeopt
|
86
bytecode_optimizer/tests/reg_encoder_test.cpp
Normal file
86
bytecode_optimizer/tests/reg_encoder_test.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 "compiler/optimizer/optimizations/regalloc/reg_alloc.h"
|
||||
#include "graph_test.h"
|
||||
#include "mem/pool_manager.h"
|
||||
#include "reg_acc_alloc.h"
|
||||
#include "reg_encoder.h"
|
||||
|
||||
using namespace testing::ext;
|
||||
|
||||
namespace panda::bytecodeopt {
|
||||
using namespace compiler;
|
||||
using namespace panda;
|
||||
class RegEncoderTest : public testing::Test {
|
||||
public:
|
||||
static void SetUpTestCase(void) {}
|
||||
static void TearDownTestCase(void) {}
|
||||
void SetUp() {}
|
||||
void TearDown() {}
|
||||
|
||||
GraphTest graph_test_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @tc.name: reg_encoder_test_001
|
||||
* @tc.desc: Verify the RunImpl function.
|
||||
* @tc.type: FUNC
|
||||
* @tc.require: issueNumber
|
||||
*/
|
||||
HWTEST_F(RegEncoderTest, reg_encoder_test_001, TestSize.Level1)
|
||||
{
|
||||
std::string pFile = GRAPH_TEST_ABC_DIR "codegenTryCatch.abc";
|
||||
const char *test_method_name = "func4";
|
||||
bool status = false;
|
||||
|
||||
graph_test_.TestBuildGraphFromFile(pFile, [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(RegAlloc(graph));
|
||||
EXPECT_TRUE(graph->RunPass<RegEncoder>());
|
||||
});
|
||||
EXPECT_TRUE(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* @tc.name: reg_encoder_test_002
|
||||
* @tc.desc: Verify the RunImpl function.
|
||||
* @tc.type: FUNC
|
||||
* @tc.require: issueNumber
|
||||
*/
|
||||
HWTEST_F(RegEncoderTest, reg_encoder_test_002, TestSize.Level1)
|
||||
{
|
||||
std::string pFile = GRAPH_TEST_ABC_DIR "optimizeTryCatch.abc";
|
||||
const char *test_method_name = "func_main_0";
|
||||
bool status = false;
|
||||
|
||||
graph_test_.TestBuildGraphFromFile(pFile, [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<RegAccAlloc>());
|
||||
});
|
||||
EXPECT_TRUE(status);
|
||||
}
|
||||
} // namespace panda::bytecodeopt
|
Loading…
Reference in New Issue
Block a user