From 20f4268ff8c65318e57e20a55620d9556fda0d79 Mon Sep 17 00:00:00 2001 From: yi_jiang Date: Mon, 16 Nov 2020 11:36:31 -0800 Subject: [PATCH] Support RISC-V target --- BUILD.gn | 17 - Makefile | 10 +- README.md | 40 +- build/config/BUILDCONFIG.gn | 1 + doc/setup_riscv_qemu_env.md | 70 + Tutorial.md => doc/tutorial.md | 65 +- envsetup.sh | 7 +- examples/C/README.md | 5 +- ...t2mpl.sh => maple_aarch64_with_ast2mpl.sh} | 6 +- ...mpl.sh => maple_aarch64_with_whirl2mpl.sh} | 15 +- examples/C/maple_riscv_with_whirl2mpl.sh | 50 + mapleall/BUILD.gn | 1 + mapleall/maple_be/.gitignore | 3 - mapleall/maple_be/BUILD.gn | 114 +- mapleall/maple_be/include/be/be_common.h | 2 +- mapleall/maple_be/include/be/be_lowerer.h | 2 +- .../include/be/riscv64/riscv64_rt_support.h | 72 + .../maple_be/include/cg/aarch64/.gitignore | 1 - .../include/cg/aarch64/aarch64_cg_func.h | 8 +- .../include/cg/aarch64/aarch64_color_ra.h | 46 +- .../include/cg/aarch64/aarch64_insn.h | 2 +- .../maple_be/include/cg/aarch64/aarch64_isa.h | 4 +- .../include/cg/aarch64/aarch64_md.def | 1439 +++++ .../include/cg/aarch64/aarch64_operand.h | 2 +- .../maple_be/include/cg/aarch64/gen_mop.pl | 34 - mapleall/maple_be/include/cg/arm/arm_md.def | 626 ++ mapleall/maple_be/include/cg/arm/gen_mop.pl | 33 - mapleall/maple_be/include/cg/cg.h | 2 + mapleall/maple_be/include/cg/cg_cfg.h | 21 +- mapleall/maple_be/include/cg/cg_func.h | 27 +- mapleall/maple_be/include/cg/cg_option.h | 6 +- mapleall/maple_be/include/cg/dbg.h | 1 + mapleall/maple_be/include/cg/ebo.h | 4 + mapleall/maple_be/include/cg/emit.h | 38 +- mapleall/maple_be/include/cg/operand.h | 7 +- mapleall/maple_be/include/cg/riscv64/README | 16 + .../maple_be/include/cg/riscv64/riscv64_abi.h | 184 + .../include/cg/riscv64/riscv64_cc.def | 32 + .../maple_be/include/cg/riscv64/riscv64_cg.h | 151 + .../include/cg/riscv64/riscv64_cg_func.h | 826 +++ .../include/cg/riscv64/riscv64_color_ra.h | 865 +++ .../include/cg/riscv64/riscv64_dep_analysis.h | 90 + .../maple_be/include/cg/riscv64/riscv64_ebo.h | 78 + .../cg/riscv64/riscv64_fp_simd_regs.def | 150 + .../include/cg/riscv64/riscv64_global_opt.h | 77 + .../include/cg/riscv64/riscv64_insn.h | 184 + .../include/cg/riscv64/riscv64_int_regs.def | 76 + .../maple_be/include/cg/riscv64/riscv64_isa.h | 400 ++ .../include/cg/riscv64/riscv64_isa_def.in | 498 ++ .../cg/riscv64/riscv64_live_analysis.h | 47 + .../include/cg/riscv64/riscv64_lvar.h | 132 + .../include/cg/riscv64/riscv64_md.def | 578 ++ .../include/cg/riscv64/riscv64_mem_layout.h | 246 + .../include/cg/riscv64/riscv64_operand.h | 726 +++ .../cg/riscv64/riscv64_optimize_common.h | 64 + .../include/cg/riscv64/riscv64_peep.h | 68 + .../include/cg/riscv64/riscv64_ra_opt.h | 100 + .../cg/riscv64/riscv64_reaching_definition.h | 63 + .../include/cg/riscv64/riscv64_reg_alloc.h | 606 ++ .../include/cg/riscv64/riscv64_schedule.h | 60 + .../cg/riscv64/riscv64_store_load_opt.h | 54 + mapleall/maple_be/include/cg/x86/gen_mop.pl | 33 - mapleall/maple_be/include/cg/x86/x86_md.def | 681 +++ .../src/be/aarch64/aarch64_rt_support.cpp | 22 + mapleall/maple_be/src/be/be_common.cpp | 15 +- mapleall/maple_be/src/be/be_lowerer.cpp | 46 +- .../src/be/riscv64/riscv64_rt_support.cpp | 22 + .../maple_be/src/cg/aarch64/aarch64_cg.cpp | 2 + .../src/cg/aarch64/aarch64_cg_func.cpp | 13 +- .../src/cg/aarch64/aarch64_color_ra.cpp | 673 +-- .../maple_be/src/cg/aarch64/aarch64_emit.cpp | 11 + .../src/cg/aarch64/aarch64_intrinsics.cpp | 59 +- .../maple_be/src/cg/aarch64/aarch64_md.def | 1439 ----- .../src/cg/aarch64/aarch64_mem_layout.cpp | 14 + .../src/cg/aarch64/aarch64_operand.cpp | 4 +- .../cg/aarch64/aarch64_optimize_common.cpp | 4 + .../src/cg/aarch64/aarch64_ra_opt.cpp | 6 +- .../src/cg/aarch64/aarch64_reg_alloc.cpp | 44 +- mapleall/maple_be/src/cg/ark/ark_emit.cpp | 2 + .../maple_be/src/cg/ark/ark_mem_layout.cpp | 20 + mapleall/maple_be/src/cg/ark/ark_mir_emit.cpp | 8 +- mapleall/maple_be/src/cg/arm/arm_md.def | 626 -- mapleall/maple_be/src/cg/cfg_optimizer.cpp | 9 +- mapleall/maple_be/src/cg/cg.cpp | 5 + mapleall/maple_be/src/cg/cg_bb.cpp | 1 + mapleall/maple_be/src/cg/cg_cfg.cpp | 13 +- mapleall/maple_be/src/cg/cg_driver.cpp | 28 +- mapleall/maple_be/src/cg/cg_func.cpp | 98 +- mapleall/maple_be/src/cg/cg_option.cpp | 43 +- mapleall/maple_be/src/cg/cg_phase_manager.cpp | 4 - mapleall/maple_be/src/cg/ebo.cpp | 39 +- mapleall/maple_be/src/cg/emit.cpp | 141 +- mapleall/maple_be/src/cg/emit_dbg.cpp | 663 +++ mapleall/maple_be/src/cg/lvar.cpp | 6 +- .../maple_be/src/cg/reaching_definition.cpp | 6 - .../maple_be/src/cg/riscv64/riscv64_abi.cpp | 703 +++ .../maple_be/src/cg/riscv64/riscv64_cg.cpp | 339 ++ .../src/cg/riscv64/riscv64_cg_func.cpp | 5253 +++++++++++++++++ .../src/cg/riscv64/riscv64_color_ra.cpp | 3486 +++++++++++ .../src/cg/riscv64/riscv64_dep_analysis.cpp | 909 +++ .../maple_be/src/cg/riscv64/riscv64_ebo.cpp | 994 ++++ .../maple_be/src/cg/riscv64/riscv64_emit.cpp | 1069 ++++ .../src/cg/riscv64/riscv64_global_opt.cpp | 1148 ++++ .../maple_be/src/cg/riscv64/riscv64_insn.cpp | 288 + .../src/cg/riscv64/riscv64_insn_slct.cpp | 2530 ++++++++ .../src/cg/riscv64/riscv64_intrinsics.cpp | 420 ++ .../src/cg/riscv64/riscv64_live_analysis.cpp | 284 + .../src/cg/riscv64/riscv64_load_store.cpp | 2119 +++++++ .../maple_be/src/cg/riscv64/riscv64_lvar.cpp | 1204 ++++ .../src/cg/riscv64/riscv64_mem_layout.cpp | 494 ++ .../src/cg/riscv64/riscv64_operand.cpp | 213 + .../maple_be/src/cg/riscv64/riscv64_opnd.def | 177 + .../cg/riscv64/riscv64_optimize_common.cpp | 379 ++ .../maple_be/src/cg/riscv64/riscv64_peep.cpp | 907 +++ .../src/cg/riscv64/riscv64_ra_opt.cpp | 289 + .../riscv64/riscv64_reaching_definition.cpp | 1501 +++++ .../src/cg/riscv64/riscv64_reg_alloc.cpp | 4292 ++++++++++++++ .../src/cg/riscv64/riscv64_schedule.cpp | 535 ++ .../src/cg/riscv64/riscv64_store_load_opt.cpp | 804 +++ .../src/cg/riscv64/riscv64_vec_insn_slct.cpp | 52 + mapleall/maple_be/src/cg/script/gen_mop.py | 113 - .../maple_be/src/cg/script/gen_mopfor_gn.py | 82 - mapleall/maple_be/src/cg/super_bb.cpp | 4 + mapleall/maple_be/src/cg/x86/x86_cg.cpp | 2 + mapleall/maple_be/src/cg/x86/x86_md.def | 681 --- mapleall/maple_driver/BUILD.gn | 8 + mapleall/maple_driver/src/driver_runner.cpp | 32 +- mapleall/maple_ipa/BUILD.gn | 1 - mapleall/maple_ir/BUILD.gn | 19 +- mapleall/maple_ir/include/debug_info.h | 420 ++ mapleall/maple_ir/include/gen-intrin.pl | 35 - mapleall/maple_ir/include/mir_module.h | 3 + mapleall/maple_ir/include/mir_type.h | 8 +- mapleall/maple_ir/include/prim_types.def | 1 - mapleall/maple_ir/src/bin_func_import.cpp | 1 + mapleall/maple_ir/src/bin_mpl_import.cpp | 4 + mapleall/maple_ir/src/debug_info.cpp | 1311 ++++ mapleall/maple_ir/src/debug_info_util.cpp | 156 + mapleall/maple_ir/src/lexer.cpp | 3 + mapleall/maple_ir/src/mir_module.cpp | 6 + mapleall/maple_ir/src/mir_parser_stmt.cpp | 1 + mapleall/maple_ir/src/mir_type.cpp | 8 +- mapleall/maple_ir/src/mpl_dbg.cpp | 119 + mapleall/maple_ir/src/parser.cpp | 12 + mapleall/maple_me/src/me_function.cpp | 7 +- mapleall/maple_me/src/me_phase_manager.cpp | 2 +- mapleall/mpl2mpl/BUILD.gn | 3 - tools/setup_tools.sh | 17 +- 148 files changed, 43460 insertions(+), 3940 deletions(-) create mode 100644 doc/setup_riscv_qemu_env.md rename Tutorial.md => doc/tutorial.md (61%) rename examples/C/{maple_with_ast2mpl.sh => maple_aarch64_with_ast2mpl.sh} (86%) rename examples/C/{maple_with_whirl2mpl.sh => maple_aarch64_with_whirl2mpl.sh} (60%) create mode 100755 examples/C/maple_riscv_with_whirl2mpl.sh delete mode 100755 mapleall/maple_be/.gitignore create mode 100644 mapleall/maple_be/include/be/riscv64/riscv64_rt_support.h delete mode 100755 mapleall/maple_be/include/cg/aarch64/.gitignore create mode 100644 mapleall/maple_be/include/cg/aarch64/aarch64_md.def delete mode 100644 mapleall/maple_be/include/cg/aarch64/gen_mop.pl create mode 100644 mapleall/maple_be/include/cg/arm/arm_md.def delete mode 100644 mapleall/maple_be/include/cg/arm/gen_mop.pl create mode 100644 mapleall/maple_be/include/cg/riscv64/README create mode 100644 mapleall/maple_be/include/cg/riscv64/riscv64_abi.h create mode 100644 mapleall/maple_be/include/cg/riscv64/riscv64_cc.def create mode 100644 mapleall/maple_be/include/cg/riscv64/riscv64_cg.h create mode 100644 mapleall/maple_be/include/cg/riscv64/riscv64_cg_func.h create mode 100644 mapleall/maple_be/include/cg/riscv64/riscv64_color_ra.h create mode 100644 mapleall/maple_be/include/cg/riscv64/riscv64_dep_analysis.h create mode 100644 mapleall/maple_be/include/cg/riscv64/riscv64_ebo.h create mode 100644 mapleall/maple_be/include/cg/riscv64/riscv64_fp_simd_regs.def create mode 100644 mapleall/maple_be/include/cg/riscv64/riscv64_global_opt.h create mode 100644 mapleall/maple_be/include/cg/riscv64/riscv64_insn.h create mode 100644 mapleall/maple_be/include/cg/riscv64/riscv64_int_regs.def create mode 100644 mapleall/maple_be/include/cg/riscv64/riscv64_isa.h create mode 100644 mapleall/maple_be/include/cg/riscv64/riscv64_isa_def.in create mode 100644 mapleall/maple_be/include/cg/riscv64/riscv64_live_analysis.h create mode 100644 mapleall/maple_be/include/cg/riscv64/riscv64_lvar.h create mode 100644 mapleall/maple_be/include/cg/riscv64/riscv64_md.def create mode 100644 mapleall/maple_be/include/cg/riscv64/riscv64_mem_layout.h create mode 100644 mapleall/maple_be/include/cg/riscv64/riscv64_operand.h create mode 100644 mapleall/maple_be/include/cg/riscv64/riscv64_optimize_common.h create mode 100644 mapleall/maple_be/include/cg/riscv64/riscv64_peep.h create mode 100644 mapleall/maple_be/include/cg/riscv64/riscv64_ra_opt.h create mode 100644 mapleall/maple_be/include/cg/riscv64/riscv64_reaching_definition.h create mode 100644 mapleall/maple_be/include/cg/riscv64/riscv64_reg_alloc.h create mode 100644 mapleall/maple_be/include/cg/riscv64/riscv64_schedule.h create mode 100644 mapleall/maple_be/include/cg/riscv64/riscv64_store_load_opt.h delete mode 100644 mapleall/maple_be/include/cg/x86/gen_mop.pl create mode 100644 mapleall/maple_be/include/cg/x86/x86_md.def create mode 100644 mapleall/maple_be/src/be/aarch64/aarch64_rt_support.cpp create mode 100644 mapleall/maple_be/src/be/riscv64/riscv64_rt_support.cpp delete mode 100644 mapleall/maple_be/src/cg/aarch64/aarch64_md.def delete mode 100644 mapleall/maple_be/src/cg/arm/arm_md.def create mode 100644 mapleall/maple_be/src/cg/emit_dbg.cpp create mode 100644 mapleall/maple_be/src/cg/riscv64/riscv64_abi.cpp create mode 100644 mapleall/maple_be/src/cg/riscv64/riscv64_cg.cpp create mode 100644 mapleall/maple_be/src/cg/riscv64/riscv64_cg_func.cpp create mode 100644 mapleall/maple_be/src/cg/riscv64/riscv64_color_ra.cpp create mode 100644 mapleall/maple_be/src/cg/riscv64/riscv64_dep_analysis.cpp create mode 100644 mapleall/maple_be/src/cg/riscv64/riscv64_ebo.cpp create mode 100644 mapleall/maple_be/src/cg/riscv64/riscv64_emit.cpp create mode 100644 mapleall/maple_be/src/cg/riscv64/riscv64_global_opt.cpp create mode 100644 mapleall/maple_be/src/cg/riscv64/riscv64_insn.cpp create mode 100644 mapleall/maple_be/src/cg/riscv64/riscv64_insn_slct.cpp create mode 100644 mapleall/maple_be/src/cg/riscv64/riscv64_intrinsics.cpp create mode 100644 mapleall/maple_be/src/cg/riscv64/riscv64_live_analysis.cpp create mode 100644 mapleall/maple_be/src/cg/riscv64/riscv64_load_store.cpp create mode 100644 mapleall/maple_be/src/cg/riscv64/riscv64_lvar.cpp create mode 100644 mapleall/maple_be/src/cg/riscv64/riscv64_mem_layout.cpp create mode 100644 mapleall/maple_be/src/cg/riscv64/riscv64_operand.cpp create mode 100644 mapleall/maple_be/src/cg/riscv64/riscv64_opnd.def create mode 100644 mapleall/maple_be/src/cg/riscv64/riscv64_optimize_common.cpp create mode 100644 mapleall/maple_be/src/cg/riscv64/riscv64_peep.cpp create mode 100644 mapleall/maple_be/src/cg/riscv64/riscv64_ra_opt.cpp create mode 100644 mapleall/maple_be/src/cg/riscv64/riscv64_reaching_definition.cpp create mode 100644 mapleall/maple_be/src/cg/riscv64/riscv64_reg_alloc.cpp create mode 100644 mapleall/maple_be/src/cg/riscv64/riscv64_schedule.cpp create mode 100644 mapleall/maple_be/src/cg/riscv64/riscv64_store_load_opt.cpp create mode 100644 mapleall/maple_be/src/cg/riscv64/riscv64_vec_insn_slct.cpp delete mode 100755 mapleall/maple_be/src/cg/script/gen_mop.py delete mode 100755 mapleall/maple_be/src/cg/script/gen_mopfor_gn.py delete mode 100644 mapleall/maple_be/src/cg/x86/x86_md.def create mode 100644 mapleall/maple_ir/include/debug_info.h delete mode 100644 mapleall/maple_ir/include/gen-intrin.pl create mode 100644 mapleall/maple_ir/src/debug_info.cpp create mode 100644 mapleall/maple_ir/src/debug_info_util.cpp create mode 100644 mapleall/maple_ir/src/mpl_dbg.cpp diff --git a/BUILD.gn b/BUILD.gn index 6e10d3e..e35c304 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -18,20 +18,3 @@ group("mapleall") { "${MAPLEALL_ROOT}:mapleall" ] } - -group("aarch64isa_headers"){ - exec_script("${MAPLEALL_ROOT}/maple_be/src/cg/script/gen_mopfor_gn.py", [ - rebase_path("${MAPLEALL_ROOT}/maple_be/src/cg/aarch64/aarch64_md.def", root_build_dir), - rebase_path("${MAPLEALL_ROOT}/maple_be/include/cg/aarch64/aarch64_isa.def", root_build_dir), - ]) -} - -if (X86_ARK==1) { - group("x86isa_headers"){ - exec_script("${MAPLEALL_ROOT}/maple_be/src/cg/script/gen_mopfor_gn.py", [ - rebase_path("${MAPLEALL_ROOT}/maple_be/src/cg/x86/x86_md.def", root_build_dir), - rebase_path("${MAPLEALL_ROOT}/maple_be/include/cg/x86/x86_isa.def", root_build_dir), - ]) - } -} - diff --git a/Makefile b/Makefile index 16644f2..f944bdf 100644 --- a/Makefile +++ b/Makefile @@ -31,10 +31,14 @@ RC_TESTING := OFF USE_MALLOC := COV_CHECK := 0 -ifeq ($(TARGET_PROCESSOR), arm64) +ifeq ($(TARGET_PROCESSOR), aarch64) TARGET=aarch64 else - TARGET=ark + ifeq ($(TARGET_PROCESSOR), riscv64) + TARGET=riscv64 + else + TARGET=ark + endif endif ifeq ($(TARGET_SCOPE), release) @@ -65,7 +69,7 @@ default: mapleall .PHONY: mapleall mapleall: - $(call build_gn, ${GN_OPTIONS}, irbuild maple) + $(call build_gn, ${GN_OPTIONS}, irbuild maple mplcg) .PHONY: install install: mapleall diff --git a/README.md b/README.md index b77782f..4f0fea8 100644 --- a/README.md +++ b/README.md @@ -22,14 +22,14 @@ The directory structure as follows: ``` $MAPLE_ROOT README.md : this file - Tutorial.md : Tutorial & FAQ Copyright : Copyright file license : Mulan license file doc : MapleIR documentation + : tutorial & FAQ mapleall : maple compiler source maple_engine : maple engine opcode header file bin/ast2mpl : C frontend: clangAST to MapleIR - tools : ninja, gn and opencc for C frontend + tools : ninja, gn and clangfe for C frontend : downloaded by setup_tools.sh Makefile : makefile build : environment set up and build files @@ -39,26 +39,32 @@ The directory structure as follows: ``` ### Set up tools -1. cd $MAPLE_ROOT -2. cd tools -3. ./setup_tools.sh +1. `cd $MAPLE_ROOT` +2. `cd tools` +3. `./setup_tools.sh` ### Build compiler -1. cd $MAPLE_ROOT -2. choose {**TARGET**, **VERSION**} combo from four flavors {**arm**/**engine**(or **ark**), **release**/**debug**} - where **arm** for arm64 target .s and **engine** (or **ark**) for maple engine target .s -3. source envsetup.sh **TARGET** **VERSION** -4. make -5. make install +1. `cd $MAPLE_ROOT` +2. choose {**TARGET**, **VERSION**} combo from {**arm**/**engine**(or **ark**)/**riscv**, **release**/**debug**} + where **arm** for aarch64 target .s, **engine** (or **ark**) for maple engine target .s and riscv for riscv64 target .s +3. `source envsetup.sh` **TARGET** **VERSION** + * for example: + * `source envsetup.sh arm release` + * `source envsetup.sh engine release` + * `source envsetup.sh ark release` + * `source envsetup.sh riscv release` +4. `make` +5. `make install` ### Output maple excutables are in $MAPLE_ROOT/bin directory ### Usage refer to examples/ for C language examples -1. cd examples/C -2. ./maple_with_ast2mpl.sh -3. ./maple_with_whirl2mpl.sh +1. `cd examples/C` +2. `./maple_aarch64_with_ast2mpl.sh` +3. `./maple_aarch64_with_whirl2mpl.sh` +3. `./maple_riscv64_with_whirl2mpl.sh` refer to maple_engine git repository for java2asm.sh and asm2so.sh scripts @@ -66,7 +72,9 @@ refer to maple_engine git repository for java2asm.sh and asm2so.sh scripts 2. asm2so.sh : .s -> .so ### Tutorial -Please find step by step instructions to build Maple and run examples in the [Tutorial.md](Tutorial.md). +Please find step by step instructions to build Maple and run examples in the [tutorial.md](./doc/tutorial.md). + +If we want to build Maple for RISC-V, please follow the [instructions](./doc/setup_riscv_qemu_env.md) to prepare QEMU cross-compilation and execution environment. ### Possible issues You might need to install required packages like: @@ -76,4 +84,4 @@ You might need to install required packages like: sudo apt-get install libssl-dev ``` -Please refer to the [FAQ](Tutorial.md#faq-and-errors) page for anwswers to more questions and issues. \ No newline at end of file +Please refer to the [FAQ](./doc/tutorial.md#faq-and-errors) page for anwswers to more questions and issues. diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn index 6ae172c..bbed5be 100644 --- a/build/config/BUILDCONFIG.gn +++ b/build/config/BUILDCONFIG.gn @@ -65,6 +65,7 @@ GN_RUNTIME_OUTPUT_DIRECTORY = "${GN_INSTALL_PREFIX}/out/${MAPLE_BUILD_TYPE}/bin" MAPLEALL_ROOT = "${MAPLE_ROOT}/mapleall" MAPLE_RE_ROOT = "${MAPLE_ROOT}/maple_engine" HUAWEI_SECURE_C_ROOT = "${MAPLE_ROOT}/huawei_secure_c" +DWARF_ROOT = "${MAPLE_ROOT}/tools/dwarf" # Toolchain setup if (USE_CLANG == 1) { diff --git a/doc/setup_riscv_qemu_env.md b/doc/setup_riscv_qemu_env.md new file mode 100644 index 0000000..d5ef88e --- /dev/null +++ b/doc/setup_riscv_qemu_env.md @@ -0,0 +1,70 @@ +#Set up a QEMU Environment for Cross Compilation and Execution in RISC-V +last updated: 2020-11-10 + + +Here are step-by-step instructions for setting up . We did this demo in the environment below: + + Operating System: Ubuntu 18.04.5 LTS + Kernel: 4.15.0 + GCC: 7.5.0 + + Note: ubuntu 16.04.4 LTS with gcc 5.4.0 also works + +##Build the RISC-V Linux GNU Toolchain + +1. Update environment with required packages for building GNU toolchain. + + sudo apt install -y autoconf automake autotools-dev bc bison bison build-essential curl flex gawk gperf libexpat-dev libgmp-dev libmpc-dev libmpfr-dev libtool patchutils python3 texinfo zlib1g-dev + +2. Clone the repository from the gitee to your local environment. + + git clone --recursive https://github.com/riscv/riscv-gnu-toolchain + + sudo mkdir /usr/riscv64-linux-gnu + export PATH=/usr/riscv64-linux-gnu/bin:$PATH + + cd riscv-gnu-toolchain/ + ./configure --prefix=/usr/riscv64-linux-gnu + sudo make -j linux + + sudo ln -s /usr/riscv64-linux-gnu/sysroot/lib/ld-linux-riscv64-lp64d.so.1 /lib + +##Build the QEMU + +3. Update environment with required packages for building QEMU. + + sudo apt install -y libglib2.0-dev libpixman-1-dev pkg-config zlib1g-dev + +4. Build QEMU + + cd qemu + + ./configure --static --disable-system --target-list=riscv64-linux-user + make -j + + sudo cp riscv64-linux-user/qemu-riscv64 /usr/bin + +##Test It + +5. Prepare a C source file with content below, and put the file name as **hello_world.c** + +```c + #include + + int main() { + printf("Hello World from RISC-V QEMU!\n"); + return 0; + } +``` + + +6. Compile the above helllo-world example and run it for fun. + + /usr/riscv64-linux-gnu/bin/riscv64-unknown-linux-gnu-gcc hello_world.c + LD_LIBRARY_PATH=/usr/riscv64-linux-gnu/sysroot/lib qemu-riscv64 ./a.out + + The output is as below: + + qemu $ LD_LIBRARY_PATH=/usr/riscv64-linux-gnu/sysroot/lib qemu-riscv64 ./a.out + Hello World from RISC-V QEMU! + qemu $ diff --git a/Tutorial.md b/doc/tutorial.md similarity index 61% rename from Tutorial.md rename to doc/tutorial.md index d2dc958..7d4357a 100644 --- a/Tutorial.md +++ b/doc/tutorial.md @@ -10,6 +10,8 @@ Here is a step by step example of building Maple for ARM relase and running a re Note: ubuntu 16.04.4 LTS with gcc 5.4.0 also works +If we want to build Maple for RISC-V, please follow the [instructions](setup_riscv_qemu_env.md) to prepare QEMU cross-compilation and execution environment. + 1. Clone the repository from the gitee to your local environment. git clone https://gitee.com/openarkcompiler-incubator/mapleall.git @@ -21,11 +23,13 @@ Here is a step by step example of building Maple for ARM relase and running a re ./setup_tools.sh cd .. -3. Initialize the environment for building the Maple for ARM with the release version. +3. Initialize the environment for building the relese version of Maple compilers for ARM or RISCV targets. source envsetup.sh arm release + or + source envsetup.sh riscv release -4. Now, can we make and install the Maple, and all maple excutables are in **$MAPLE_ROOT/bin** directory +4. Now, we can make and install the Maple, and all maple excutables are in **$MAPLE_ROOT/bin** directory make make install @@ -35,17 +39,17 @@ Here is a step by step example of building Maple for ARM relase and running a re First, we will use **ast2mpl** as C Frontend to print the ASCII text. cd examples/C - ./maple_with_ast2mpl.sh + ./maple_aarch64_with_ast2mpl.sh The output is as below: - cd /home/lin/mapleall/examples/C/use_ast2mp + cd /home/lin/mapleall/examples/C/aarch64_use_ast2mp ======================================================================== ================== Use ast2mpl as C Frontend =========================== ======================================================================== INC=/usr/bin/../lib/gcc/x86_64-linux-gnu/7.5.0 /home/lin/mapleall/bin/ast2mpl printHuawei.c -I /usr/bin/../lib/gcc/x86_64-linux-gnu/7.5.0/include - /home/lin/mapleall/bin/arm64-clang-release/maple -exe=me,mplcg -option="-O2 --quiet:-O2 -quiet" printHuawei.mpl + /home/lin/mapleall/bin/aarch64-clang-release/maple -exe=me,mplcg -option="-O2 --quiet:-O2 -quiet" printHuawei.mpl /usr/bin/aarch64-linux-gnu-gcc -o printHuawei.out printHuawei.s -lm qemu-aarch64 -L /usr/aarch64-linux-gnu/ printHuawei.out @@ -73,17 +77,17 @@ Here is a step by step example of building Maple for ARM relase and running a re Then, we can use **opencc/whirl2mpl** as C Frontend to print the same text. - ./maple_with_whirl2mpl.sh + ./maple_aarch64_with_whirl2mpl.sh Here is the output: - cd /home/lin/mapleall/examples/C/use_whirl2mpl + cd /home/lin/mapleall/examples/C/aarch64_use_whirl2mpl ======================================================================== ============= Use clangfe/whirl2mpl as C Frontend ======================= ======================================================================== - /home/lin/mapleall/tools/aarch64/bin/clangfe -cc1 -emit-llvm -triple aarch64-linux-gnu -D__clang__ -D__BLOCKS__ -isystem /usr/aarch64-linux-gnu/include -isystem /usr/lib/gcc-cross/aarch64-linux-gnu/5/include printHuawei.c - /home/lin/mapleall/tools/aarch64/bin/whirl2mpl printHuawei.B - /home/lin/mapleall/bin/arm64-clang-release/maple -exe=me,mplcg -option="-O2 --quiet:-O2 -quiet" printHuawei.mpl + /home/lin/mapleall/tools/open64_prebuilt/x86/aarch64/bin/clangfe -cc1 -emit-llvm -triple aarch64-linux-gnu -D__clang__ -D__BLOCKS__ -isystem /usr/aarch64-linux-gnu/include -isystem /usr/lib/gcc-cross/aarch64-linux-gnu/5/include printHuawei.c + /home/lin/mapleall/tools/open64_prebuilt/x86/aarch64/bin/whirl2mpl printHuawei.B + /home/lin/mapleall/bin/aarch64-clang-release/maple -exe=me,mplcg -option="-O2 --quiet:-O2 -quiet" printHuawei.mpl /usr/bin/aarch64-linux-gnu-gcc -o printHuawei.out printHuawei.s -lm qemu-aarch64 -L /usr/aarch64-linux-gnu/ printHuawei.out @@ -108,6 +112,43 @@ Here is a step by step example of building Maple for ARM relase and running a re HHHHHH HHHHHH HHHHHHHHHHHHHHH HHHHHH HHHHHH HHHHHHH HHHHHHH HHHHHHHHHHHHHH HHHHHH HHHHHH HHHHHH HHHHHHHHHHH HHHHHH HHHHHH HHHHHH HHHHHH HHHHHHHHHHHH HHHHHH + After building maple compilers for riscv64 target, we can run + + ./maple_riscv64_with_whirl2mpl.sh + + Here is the output: + + cd /home/lin/mapleall/examples/C/riscv64_use_whirl2mpl + ======================================================================== + ============= Use clangfe/whirl2mpl as C Frontend ======================= + ======================================================================== + + /home/lin/mapleall/tools/open64_prebuilt/x86/riscv64/bin/clangfe -cc1 -emit-llvm -triple riscv64-linux-gnu -D__clang__ -D__BLOCKS__ -D__riscv_xlen=64 -U __riscv_float_abi_soft -D__riscv_float_abi_double -isystem /usr/riscv64-linux-gnu/lib/gcc/riscv64-unknown-linux-gnu/10.1.0/include -isystem /usr/riscv64-linux-gnu/sysroot/usr/include -U __SIZEOF_INT128__ printHuawei.c + /home/lin/mapleall/tools/open64_prebuilt/x86/riscv64/bin/whirl2mpl printHuawei.B + /home/lin/mapleall/bin/riscv64-clang-release/maple -exe=me,mplcg -option=-O2 --quiet:-O2 -quiet printHuawei.bpl + /usr/riscv64-linux-gnu/bin/riscv64-unknown-linux-gnu-gcc -o printHuawei.out printHuawei.s + LD_LIBRARY_PATH=/usr/riscv64-linux-gnu/sysroot/lib /usr/bin/qemu-riscv64 printHuawei.out + + HHHHHH HHHHHH HHHHHH HHHHHH HHHHH HHHHHH HHHHHH HHHHHH HHHHHHHHHHHHHH HHHHHH + HHHHHH HHHHHH HHHHHH HHHHHH HHHHHHH HHHHHH HHHHHHHH HHHHHH HHHHHHHHHHHHHHH HHHHHH + HHHHHH HHHHHH HHHHHH HHHHHH HHHHHHHHH HHHHHH HHHHHHHH HHHHHH HHHHHHHHHHHHHHHH HHHHHH + HHHHHH HHHHHH HHHHHH HHHHHH HHHHHHHHH HHHHHH HHHHHHHHH HHHHHH HHHHHHHHHHHHHHHHH HHHHHH + HHHHHH HHHHHH HHHHHH HHHHHH HHHHHHHHHHH HHHHH HHHHHHHHHH HHHHH HHHHHHH HHHHHH + HHHHHH HHHHHH HHHHHH HHHHHH HHHHHHHHHHH HHHHHH HHHHHHHHHH HHHHHH HHHHHH HHHHHH + HHHHHH HHHHHH HHHHHH HHHHHH HHHHHH HHHHHH HHHHHH HHHHHHHHHHH HHHHHH HHHHHH HHHHHH + HHHHHHHHHHHHHHHHHHHHH HHHHHH HHHHHH HHHHHH HHHHHH HHHHH HHHHH HHHHHH HHHHH HHHHHHHHHHHHHHHHHHH HHHHHH + HHHHHHHHHHHHHHHHHHHHH HHHHHH HHHHHH HHHHHH HHHHHH HHHHHH HHHHH HHHHH HHHHHH HHHHHHHHHHHHHHHHHHH HHHHHH + HHHHHHHHHHHHHHHHHHHHH HHHHHH HHHHHH HHHHHH HHHHHH HHHHHH HHHHHH HHHHHH HHHHH HHHHHHHHHHHHHHHHHHH HHHHHH + HHHHHHHHHHHHHHHHHHHHH HHHHHH HHHHHH HHHHHH HHHHHH HHHHHH HHHHH HHHHHH HHHHH HHHHHHHHHHHHHHHHHHH HHHHHH + HHHHHH HHHHHH HHHHHH HHHHHH HHHHHHHHHHHHHHHHH HHHHH HHHHH HHHHH HHHHH HHHHHH HHHHHH + HHHHHH HHHHHH HHHHHH HHHHHH HHHHHHHHHHHHHHHHHHH HHHHHHHHHHH HHHHHHHHHHH HHHHHH HHHHHH + HHHHHH HHHHHH HHHHHH HHHHHH HHHHHHHHHHHHHHHHHHH HHHHHHHHHH HHHHHHHHHH HHHHHHH HHHHHH + HHHHHH HHHHHH HHHHHH HHHHHH HHHHHHHHHHHHHHHHHHHHH HHHHHHHHH HHHHHHHHH HHHHHH HHHHHH + HHHHHH HHHHHH HHHHHH HHHHHH HHHHHH HHHHHH HHHHHHHHH HHHHHHHHH HHHHHHHH HHHHHH + HHHHHH HHHHHH HHHHHHHHHHHHHHHHHHH HHHHHH HHHHHH HHHHHHHH HHHHHHHH HHHHHHHHHHHHHHHHH HHHHHH + HHHHHH HHHHHH HHHHHHHHHHHHHHHHH HHHHHH HHHHHH HHHHHHHH HHHHHHHH HHHHHHHHHHHHHHHH HHHHHH + HHHHHH HHHHHH HHHHHHHHHHHHHHH HHHHHH HHHHHH HHHHHHH HHHHHHH HHHHHHHHHHHHHH HHHHHH + HHHHHH HHHHHH HHHHHHHHHHH HHHHHH HHHHHH HHHHHH HHHHHH HHHHHHHHHHHH HHHHHH *** @@ -133,7 +174,7 @@ Here is a step by step example of building Maple for ARM relase and running a re 3. The build lools for **aarch64-linux-gnu-gcc** which requires the **ARM cross compiling toolchain**. - ./maple_with_ast2mpl.sh: line 44: /usr/bin/aarch64-linux-gnu-gcc: No such file or directory + ./maple_aarch64_with_ast2mpl.sh: line 44: /usr/bin/aarch64-linux-gnu-gcc: No such file or directory **[Solution]** @@ -144,7 +185,7 @@ Here is a step by step example of building Maple for ARM relase and running a re 4. If the execution of example complains the missing command **qemu-aarch64** as below, we need install the QEMU for ARM. - ./maple_with_ast2mpl.sh: line 48: qemu-aarch64: command not found + ./maple_aarch64_with_ast2mpl.sh: line 48: qemu-aarch64: command not found **[Solution]** diff --git a/envsetup.sh b/envsetup.sh index dba3e3b..fbfda04 100755 --- a/envsetup.sh +++ b/envsetup.sh @@ -15,7 +15,7 @@ function print_usage { echo " " - echo "usage: source envsetup.sh arm/engine release/debug" + echo "usage: source envsetup.sh arm/engine/riscv release/debug" echo " " } @@ -32,7 +32,7 @@ unset TARGET_ARCH export TARGET_ARCH=64 if [ $1 = "arm" ]; then - PLATFORM=arm64 + PLATFORM=aarch64 USEOJ=0 elif [ $1 = "engine" ]; then PLATFORM=ark @@ -43,6 +43,9 @@ elif [ $1 = "ark" ]; then elif [ $1 = "ark2" ]; then PLATFORM=ark USEOJ=2 +elif [ $1 = "riscv" ]; then + PLATFORM=riscv64 + USEOJ=0 else print_usage return diff --git a/examples/C/README.md b/examples/C/README.md index 0468916..58a836d 100644 --- a/examples/C/README.md +++ b/examples/C/README.md @@ -26,4 +26,7 @@ Besides maple compiler, included are processes using two C front end tools: source code is available at https://gitee.com/open64ark/open64ark #### 使用说明 - run either maple_with_ast2mpl.sh or maple_with_whirl2mpl.sh for details + run the following scripts for details + + maple_aarch64_with_ast2mpl.sh + maple_aarch64_with_whirl2mpl.sh diff --git a/examples/C/maple_with_ast2mpl.sh b/examples/C/maple_aarch64_with_ast2mpl.sh similarity index 86% rename from examples/C/maple_with_ast2mpl.sh rename to examples/C/maple_aarch64_with_ast2mpl.sh index 385e7e4..a85ebda 100755 --- a/examples/C/maple_with_ast2mpl.sh +++ b/examples/C/maple_aarch64_with_ast2mpl.sh @@ -15,7 +15,7 @@ [ -n "$MAPLE_ROOT" ] || { echo MAPLE_ROOT not set. Please source envsetup.sh.; exit 1; } CURRDIR=`pwd` -WORKDIR=$CURRDIR/use_ast2mp +WORKDIR=$CURRDIR/aarch64_use_ast2mp mkdir $WORKDIR echo cd $WORKDIR @@ -36,8 +36,8 @@ echo $MAPLE_ROOT/bin/ast2mpl $name.c -I $INC/include $MAPLE_ROOT/bin/ast2mpl $name.c -I $INC/include # .mpl -> .s -echo $MAPLE_ROOT/bin/arm64-clang-release/maple -exe=me,mplcg -option=\"-O2 --quiet:-O2 -quiet\" $name.mpl -$MAPLE_ROOT/bin/arm64-clang-release/maple -exe=me,mplcg -option="-O2 --quiet:-O2 -quiet" $name.mpl > doit.log +echo $MAPLE_ROOT/bin/aarch64-clang-release/maple -exe=me,mplcg -option=\"-O2 --quiet:-O2 -quiet\" $name.mpl +$MAPLE_ROOT/bin/aarch64-clang-release/maple -exe=me,mplcg -option="-O2 --quiet:-O2 -quiet" $name.mpl > doit.log # .s -> .out echo /usr/bin/aarch64-linux-gnu-gcc -o $name.out $name.s diff --git a/examples/C/maple_with_whirl2mpl.sh b/examples/C/maple_aarch64_with_whirl2mpl.sh similarity index 60% rename from examples/C/maple_with_whirl2mpl.sh rename to examples/C/maple_aarch64_with_whirl2mpl.sh index a8bdc9f..5c9c5db 100755 --- a/examples/C/maple_with_whirl2mpl.sh +++ b/examples/C/maple_aarch64_with_whirl2mpl.sh @@ -15,7 +15,7 @@ [ -n "$MAPLE_ROOT" ] || { echo MAPLE_ROOT not set. Please source envsetup.sh.; exit 1; } CURRDIR=`pwd` -WORKDIR=$CURRDIR/use_whirl2mpl +WORKDIR=$CURRDIR/aarch64_use_whirl2mpl mkdir $WORKDIR echo cd $WORKDIR @@ -29,14 +29,15 @@ echo ======================================================================== cp $CURRDIR/$name.c . -echo $MAPLE_ROOT/tools/aarch64/bin/clangfe -cc1 -emit-llvm -triple aarch64-linux-gnu -D__clang__ -D__BLOCKS__ -isystem /usr/aarch64-linux-gnu/include -isystem /usr/lib/gcc-cross/aarch64-linux-gnu/5/include $name.c -$MAPLE_ROOT/tools/aarch64/bin/clangfe -cc1 -emit-llvm -triple aarch64-linux-gnu -D__clang__ -D__BLOCKS__ -isystem /usr/aarch64-linux-gnu/include -isystem /usr/lib/gcc-cross/aarch64-linux-gnu/5/include $name.c > doit.log 2>&1 +FLAGS="-cc1 -emit-llvm -triple aarch64-linux-gnu -D__clang__ -D__BLOCKS__ -isystem /usr/aarch64-linux-gnu/include -isystem /usr/lib/gcc-cross/aarch64-linux-gnu/5/include" +echo $MAPLE_ROOT/tools/open64_prebuilt/x86/aarch64/bin/clangfe $FLAGS $name.c +$MAPLE_ROOT/tools/open64_prebuilt/x86/aarch64/bin/clangfe $FLAGS $name.c > doit.log 2>&1 -echo $MAPLE_ROOT/tools/aarch64/bin/whirl2mpl $name.B -$MAPLE_ROOT/tools/aarch64/bin/whirl2mpl $name.B >> doit.log 2>&1 +echo $MAPLE_ROOT/tools/open64_prebuilt/x86/aarch64/bin/whirl2mpl $name.B +$MAPLE_ROOT/tools/open64_prebuilt/x86/aarch64/bin/whirl2mpl $name.B >> doit.log 2>&1 -echo $MAPLE_ROOT/bin/arm64-clang-release/maple -exe=me,mplcg -option=\"-O2 --quiet:-O2 -quiet\" $name.mpl -$MAPLE_ROOT/bin/arm64-clang-release/maple -exe=me,mplcg -option="-O2 --quiet:-O2 -quiet" $name.bpl >> doit.log 2>&1 +echo $MAPLE_ROOT/bin/aarch64-clang-release/maple -exe=me,mplcg -option=\"-O2 --quiet:-O2 -quiet\" $name.bpl +$MAPLE_ROOT/bin/aarch64-clang-release/maple -exe=me,mplcg -option="-O2 --quiet:-O2 -quiet" $name.bpl >> doit.log 2>&1 echo /usr/bin/aarch64-linux-gnu-gcc -o $name.out $name.s /usr/bin/aarch64-linux-gnu-gcc -o $name.out $name.s diff --git a/examples/C/maple_riscv_with_whirl2mpl.sh b/examples/C/maple_riscv_with_whirl2mpl.sh new file mode 100755 index 0000000..a4bc859 --- /dev/null +++ b/examples/C/maple_riscv_with_whirl2mpl.sh @@ -0,0 +1,50 @@ +# Copyright (C) [2020] Futurewei Technologies, Inc. All rights reverved. +# +# Licensed under the Mulan Permissive Software License v2 +# You can use this software according to the terms and conditions of the MulanPSL - 2.0. +# You may obtain a copy of MulanPSL - 2.0 at: +# +# https://opensource.org/licenses/MulanPSL-2.0 +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the MulanPSL - 2.0 for more details. +# + +[ -n "$MAPLE_ROOT" ] || { echo MAPLE_ROOT not set. Please source envsetup.sh.; exit 1; } + +CURRDIR=`pwd` +WORKDIR=$CURRDIR/riscv_use_whirl2mpl + +mkdir $WORKDIR +echo cd $WORKDIR +cd $WORKDIR + +name=printHuawei + +echo ======================================================================== +echo ============= Use clangfe/whirl2mpl as C Frontend ======================= +echo ======================================================================== + +cp $CURRDIR/$name.c . + +# to handle proper version +INC=$(find /usr/riscv64-linux-gnu/lib/gcc/riscv64-unknown-linux-gnu/*/include | head -1) +FLAGS="-cc1 -emit-llvm -triple riscv64-linux-gnu -D__clang__ -D__BLOCKS__ -D__riscv_xlen=64 -U __riscv_float_abi_soft -D__riscv_float_abi_double -isystem $INC -isystem /usr/riscv64-linux-gnu/sysroot/usr/include -U __SIZEOF_INT128__" +echo $MAPLE_ROOT/tools/open64_prebuilt/x86/riscv64/bin/clangfe $FLAGS $name.c +$MAPLE_ROOT/tools/open64_prebuilt/x86/riscv64/bin/clangfe $FLAGS $name.c > doit.log 2>&1 + +echo $MAPLE_ROOT/tools/open64_prebuilt/x86/riscv64/bin/whirl2mpl $name.B +$MAPLE_ROOT/tools/open64_prebuilt/x86/riscv64/bin/whirl2mpl $name.B >> doit.log 2>&1 + +echo $MAPLE_ROOT/bin/riscv64-clang-release/maple -exe=me,mplcg -option="-O2 --quiet:-O2 -quiet" $name.bpl +$MAPLE_ROOT/bin/riscv64-clang-release/maple -exe=me,mplcg -option="-O2 --quiet:-O2 -quiet" $name.bpl >> doit.log 2>&1 + +echo /usr/riscv64-linux-gnu/bin/riscv64-unknown-linux-gnu-gcc -o $name.out $name.s +/usr/riscv64-linux-gnu/bin/riscv64-unknown-linux-gnu-gcc -o $name.out $name.s + +echo LD_LIBRARY_PATH=/usr/riscv64-linux-gnu/sysroot/lib /usr/bin/qemu-riscv64 $name.out +LD_LIBRARY_PATH=/usr/riscv64-linux-gnu/sysroot/lib /usr/bin/qemu-riscv64 $name.out + + diff --git a/mapleall/BUILD.gn b/mapleall/BUILD.gn index 7f64e8e..1f16e2e 100644 --- a/mapleall/BUILD.gn +++ b/mapleall/BUILD.gn @@ -96,6 +96,7 @@ group("mapleall"){ "${MAPLEALL_ROOT}/maple_ir:irbuild", "${MAPLEALL_ROOT}/maple_ir:mmpl2cmpl", "${MAPLEALL_ROOT}/maple_ir:cmpl2mmpl", + "${MAPLEALL_ROOT}/maple_ir:mpldbg", "${MAPLEALL_ROOT}/maple_ir:mplverf", "${MAPLEALL_ROOT}/maple_me:mplme", "${MAPLEALL_ROOT}/mempool:MemPool", diff --git a/mapleall/maple_be/.gitignore b/mapleall/maple_be/.gitignore deleted file mode 100755 index f8da874..0000000 --- a/mapleall/maple_be/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.out -__tmp_diff.txt -eh_tests_build_out.txt diff --git a/mapleall/maple_be/BUILD.gn b/mapleall/maple_be/BUILD.gn index 23eea80..e1bea0d 100644 --- a/mapleall/maple_be/BUILD.gn +++ b/mapleall/maple_be/BUILD.gn @@ -41,6 +41,12 @@ if(TARGET == "aarch64"){ ] } +if(TARGET == "riscv64"){ + cflags_cc += [ + "-DTARGRISCV64", + ] +} + if(TARGET == "ark"){ cflags_cc += [ "-DTARGARK", @@ -73,10 +79,12 @@ include_directories = [ "${MAPLEALL_ROOT}/maple_be/include/cg", "${MAPLEALL_ROOT}/maple_be/include/cg/aarch64", "${MAPLEALL_ROOT}/maple_be/include/cg/ark", + "${MAPLEALL_ROOT}/maple_be/include/cg/riscv64", "${MAPLEALL_ROOT}/maple_be/include/ad", "${MAPLEALL_ROOT}/maple_be/include/ad/cortex_a55", "${MAPLEALL_ROOT}/maple_be/include/be/aarch64", "${MAPLEALL_ROOT}/maple_be/include/be/ark", + "${MAPLEALL_ROOT}/maple_be/include/be/riscv64", "${MAPLEALL_ROOT}/maple_be/include/be/mmpl", "${MAPLEALL_ROOT}/maple_be/include/be/nonmmpl", "${MAPLEALL_ROOT}/maple_be/include/be", @@ -87,6 +95,7 @@ include_directories = [ "${MAPLEALL_ROOT}/maple_ipa/include", "${MAPLEALL_ROOT}/maple_phase/include", "${HUAWEI_SECURE_C_ROOT}/include", + "${DWARF_ROOT}/include", "${MAPLE_RE_ROOT}/include", "${MAPLEALL_ROOT}/maple_driver/include", ] @@ -127,6 +136,22 @@ source_set("libmplad"){ } } +source_set("libbeaarch64"){ + sources = [ + "src/be/aarch64/aarch64_rt_support.cpp", + ] + + include_dirs = include_directories +} + +source_set("libberiscv64"){ + sources = [ + "src/be/riscv64/riscv64_rt_support.cpp", + ] + + include_dirs = include_directories +} + source_set("libmmpllowerer"){ sources = [ "src/be/mmpl/mmpl_lowerer.cpp", @@ -160,6 +185,7 @@ static_library("libmplbe"){ deps += [ ":libcglowerer", + ":libbeaarch64", ] }else{ deps += [ @@ -172,21 +198,6 @@ static_library("libmplbe"){ output_dir = "${root_out_dir}/lib/${HOST_ARCH}" } -action("aarch64isa.headers"){ - script = "src/cg/script/gen_mopfor_gn.py" - input = "src/cg/aarch64/aarch64_md.def" - output = "${target_out_dir}/aarch64_isa.def" - output1 = "${MAPLEALL_ROOT}/maple_be/include/cg/aarch64/aarch64_isa.def" - outputs = [ - output, - ] - - args = [ - rebase_path(input, root_build_dir), - rebase_path(output1, root_build_dir), - ] -} - source_set("libcgaarch64"){ sources = [ "src/cg/aarch64/aarch64_abi.cpp", @@ -225,6 +236,40 @@ source_set("libcgaarch64"){ } } +source_set("libcgriscv64"){ + sources = [ + "src/cg/riscv64/riscv64_abi.cpp", + "src/cg/riscv64/riscv64_cg_func.cpp", + "src/cg/riscv64/riscv64_load_store.cpp", + "src/cg/riscv64/riscv64_lvar.cpp", + "src/cg/riscv64/riscv64_operand.cpp", + "src/cg/riscv64/riscv64_ra_opt.cpp", + "src/cg/riscv64/riscv64_color_ra.cpp", + "src/cg/riscv64/riscv64_reg_alloc.cpp", + "src/cg/riscv64/riscv64_cg.cpp", + "src/cg/riscv64/riscv64_emit.cpp", + "src/cg/riscv64/riscv64_insn.cpp", + "src/cg/riscv64/riscv64_insn_slct.cpp", + "src/cg/riscv64/riscv64_vec_insn_slct.cpp", + "src/cg/riscv64/riscv64_intrinsics.cpp", + "src/cg/riscv64/riscv64_mem_layout.cpp", + "src/cg/riscv64/riscv64_peep.cpp", + "src/cg/riscv64/riscv64_ebo.cpp", + "src/cg/riscv64/riscv64_reaching_definition.cpp", + "src/cg/riscv64/riscv64_store_load_opt.cpp", + "src/cg/riscv64/riscv64_global_opt.cpp", + "src/cg/riscv64/riscv64_optimize_common.cpp", + "src/cg/riscv64/riscv64_live_analysis.cpp", + "src/cg/riscv64/riscv64_schedule.cpp", + "src/cg/riscv64/riscv64_dep_analysis.cpp", + ] + + include_dirs = include_directories + + # TODO: replace this + cflags_cc += [ "-DMPLAD_CORTEX_A55", ] +} + source_set("libcgark"){ sources = [ "src/cg/ark/ark_abi.cpp", @@ -243,21 +288,6 @@ source_set("libcgark"){ } } -action("armisa.headers"){ - script = "src/cg/script/gen_mopfor_gn.py" - input = "src/cg/arm/arm_md.def" - output = "${target_out_dir}/arm_isa.def" - output1 = "${MAPLEALL_ROOT}/maple_be/include/cg/arm/arm_isa.def" - outputs = [ - output, - ] - - args = [ - rebase_path(input, root_build_dir), - rebase_path(output1, root_build_dir), - ] -} - if(TARGET == "arm"){ source_set("libcgarm"){ sources = [ @@ -278,20 +308,6 @@ if(TARGET == "arm"){ } } -action("x86isa.headers"){ - script = "src/cg/script/gen_mopfor_gn.py" - input = "src/cg/x86/x86_md.def" - output = "${target_out_dir}/x86_isa.def" - output1 = "${MAPLEALL_ROOT}/maple_be/include/cg/x86/x86_isa.def" - outputs = [ - output, - ] - - args = [ - rebase_path(input, root_build_dir), - rebase_path(output1, root_build_dir), - ] -} if(TARGET == "X86"){ source_set("libcgx86"){ sources = [ @@ -343,6 +359,7 @@ static_library("libcg"){ "src/cg/emit.cpp", "src/cg/cg_option.cpp", "src/cg/cg_phase_manager.cpp", + "src/cg/emit_dbg.cpp", "src/cg/mem_layout.cpp", "src/cg/special_func.cpp", ] @@ -356,6 +373,13 @@ static_library("libcg"){ ] } + if(TARGET == "riscv64"){ + deps = [ + ":libcgcpu", + ":libcgriscv64", + ] + } + if(TARGET == "ark"){ deps = [ ":libcgark", @@ -366,7 +390,6 @@ static_library("libcg"){ deps = [ ":libcgcpu", ":libcgarm", - ":armisa.headers", ] } @@ -374,7 +397,6 @@ static_library("libcg"){ deps = [ ":libcgcpu", ":libcgx86", - ":x86_headers", ] } } diff --git a/mapleall/maple_be/include/be/be_common.h b/mapleall/maple_be/include/be/be_common.h index 7c3ce53..2fdb4cc 100644 --- a/mapleall/maple_be/include/be/be_common.h +++ b/mapleall/maple_be/include/be/be_common.h @@ -31,7 +31,7 @@ namespace maplebe { -#if TARGX86_64 || TARGAARCH64 || TARGARK +#if TARGX86_64 || TARGAARCH64 || TARGARK || TARGRISCV64 #define LOWERED_PTR_TYPE PTY_a64 #define SIZEOFPTR 8 #elif TARGX86 || TARGARM || TARGVM diff --git a/mapleall/maple_be/include/be/be_lowerer.h b/mapleall/maple_be/include/be/be_lowerer.h index f9eae55..7b81689 100644 --- a/mapleall/maple_be/include/be/be_lowerer.h +++ b/mapleall/maple_be/include/be/be_lowerer.h @@ -183,7 +183,7 @@ class BELowerer { virtual void LowerFunc(MIRFunction *); -#if TARGARM || TARGAARCH64 || TARGARK +#if TARGARM || TARGAARCH64 || TARGARK || TARGRISCV64 BlockNode *LowerReturnStruct(NaryStmtNode *); #endif virtual BlockNode *LowerReturn(NaryStmtNode *); diff --git a/mapleall/maple_be/include/be/riscv64/riscv64_rt_support.h b/mapleall/maple_be/include/be/riscv64/riscv64_rt_support.h new file mode 100644 index 0000000..bb2a9eb --- /dev/null +++ b/mapleall/maple_be/include/be/riscv64/riscv64_rt_support.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +/// Copyright[year] +#ifndef MAPLEBE_INCLUDE_CG_AARCH64RTSUPPORT_H +#define MAPLEBE_INCLUDE_CG_AARCH64RTSUPPORT_H + +#include "common_utils.h" +#include "rt_support.h" + +#include + +namespace maplebe { + +/** + * This class contains constants that describes the object (memory) layout at + * run time. + * + * WARNING: DO NOT USE `sizeof` OR `alignof`! This class runs on the host, but + * describes the target which is usually different, therefore `sizeof` and + * `alignof` does not match the sizes and alignments on the target. In the + * MapleJava project, we run `mplcg` on x86_64, but run the application on + * Riscv64. + */ +class Riscv64RTSupport { + +public: + static const uint64_t kObjectAlignment = 8; // Word size. Suitable for all Java types. + static const uint64_t kObjectHeaderSize = 8; // java object header used by MM. + + // When the array layout changed, change these two numbers to tell the + // GC where the `length` field is, and where array elements begin. + // + // Assumed layout for `Object[]`: (update me when layout changes) + // struct Array { + // reffield_t klass; // 4/8-bytes + // int32_t monitor; + // int32_t length; + // reffield_t elements[]; // 4/8-byte aligned + // }; + +#ifdef USE_32BIT_REF + static const uint32_t kRefFieldSize = 4; // reference field in java object + static const uint32_t kRefFieldAlign = 4; +#else + static const uint32_t kRefFieldSize = 8; // reference field in java object + static const uint32_t kRefFieldAlign = 8; +#endif // USE_32BIT_REF + // The array length offset is fixed since CONTENT_OFFSET is fixed to simplify code + static const int64_t kArrayLengthOffset = 12; // shadow + monitor + [padding] + // The array content offset is aligned to 8B to alow hosting of size-8B elements + static const int64_t kArrayContentOffset = 16; // fixed + static const int64_t kGcTibOffset = -8; + static const int64_t kGcTibOffsetAbs = -kGcTibOffset; +}; + +} // namespace maplebe + +#endif + diff --git a/mapleall/maple_be/include/cg/aarch64/.gitignore b/mapleall/maple_be/include/cg/aarch64/.gitignore deleted file mode 100755 index b803f36..0000000 --- a/mapleall/maple_be/include/cg/aarch64/.gitignore +++ /dev/null @@ -1 +0,0 @@ -aarch64isa.def diff --git a/mapleall/maple_be/include/cg/aarch64/aarch64_cg_func.h b/mapleall/maple_be/include/cg/aarch64/aarch64_cg_func.h index 46fb4ad..70a5015 100644 --- a/mapleall/maple_be/include/cg/aarch64/aarch64_cg_func.h +++ b/mapleall/maple_be/include/cg/aarch64/aarch64_cg_func.h @@ -98,10 +98,6 @@ class AArch64CGFunc : public CGFunc { MapleVector callee_saved_regs; MapleVector formal_reg_list_; // store the parameters register used by this function MapleSet gen_memopnds_requiring_offset_adjustment_; - MapleList intrinsic_func_name; // For RA to mark special function name, which function may not change - // some caller-saved registers. - MapleList intrinsic_caller_mask; // upper 32 bits fp, lower 32 bits int - unsigned int refCount; // Ref count number. 0 if function don't have "bl MCC_InitializeLocalStackRef" int beginOffset; // Begin offset based x29. Insn *yieldPointInsn; // The insn of yield point at the entry of the func. @@ -193,8 +189,6 @@ class AArch64CGFunc : public CGFunc { callee_saved_regs(mallocator->Adapter()), formal_reg_list_(mallocator->Adapter()), gen_memopnds_requiring_offset_adjustment_(mallocator->Adapter()), - intrinsic_func_name(mallocator->Adapter()), - intrinsic_caller_mask(mallocator->Adapter()), refCount(0), beginOffset(0), yieldPointInsn(nullptr) { @@ -654,6 +648,8 @@ class AArch64CGFunc : public CGFunc { return (((num_intreg_to_callee_save + num_fpreg_to_callee_save) & 0x1) == 0); } + void DBGFixCallFrameLocationOffsets() override; + inline bool ShouldSaveFPLR() { return (cg->UseFP() || HasCall() || cg->NeedInsertInstrumentationFunction()); } diff --git a/mapleall/maple_be/include/cg/aarch64/aarch64_color_ra.h b/mapleall/maple_be/include/cg/aarch64/aarch64_color_ra.h index 123273a..7907bc8 100644 --- a/mapleall/maple_be/include/cg/aarch64/aarch64_color_ra.h +++ b/mapleall/maple_be/include/cg/aarch64/aarch64_color_ra.h @@ -37,9 +37,6 @@ namespace maplebe { #define PROPAGATE_REG // for robust test -#undef USE_VEC -#undef COPY_VEC -#undef CONFLICT_CHECK #undef CONSISTENT_MEMOPND #undef RANDOM_PRIORITY @@ -254,9 +251,6 @@ class LiveRange { uint64 *bmember; // Same as smember, but use bit array // bit vector of array for each vreg's lr // bit_vector[bb->id] = 1 if vreg is live in bb -#ifdef USE_VEC - MapleSet smember; // set of BB in live range -#endif // USE_VEC MapleVector pregveto; // pregs cannot be assigned -- SplitLr may clear forbidden MapleVector forbidden; // pregs cannot be assigned uint32 numBconflicts; // number of bits set in bconflict @@ -264,9 +258,6 @@ class LiveRange { uint32 numForbidden; uint64 *bconflict; // vreg interference from graph neighbors (bit) uint64 *oldConflict; -#ifdef USE_VEC - MapleSet sconflict; // vreg interference from graph neighbors (set) -#endif // USE_VEC MapleSet prefs; // pregs that prefer MapleMap luMap; // info for each bb LiveRange *splitLr; // The 1st part of the split @@ -292,9 +283,6 @@ class LiveRange { priority(0.0), numBmembers(0), bmember(nullptr), -#ifdef USE_VEC - smember(mallocator->Adapter()), -#endif // USE_VEC pregveto(mallocator->Adapter()), forbidden(mallocator->Adapter()), numBconflicts(0), @@ -302,9 +290,6 @@ class LiveRange { numForbidden(0), bconflict(nullptr), oldConflict(nullptr), -#ifdef USE_VEC - sconflict(mallocator->Adapter()), -#endif // USE_VEC prefs(mallocator->Adapter()), luMap(mallocator->Adapter()), splitLr(nullptr), @@ -663,7 +648,20 @@ class GraphColorRegAllocator : public RegAllocator { regBuckets(0), spillMemopnd0(nullptr), spillMemopnd1(nullptr), - spillMemopnd2(nullptr) { + spillMemopnd2(nullptr), +#ifdef USE_LRA + doLRA(true), +#else + doLRA(false);, +#endif // USE_LRA +#ifdef OPTIMIZE_FOR_PROLOG + doOptProlog(true), +#else + doOptProlog(false), +#endif // OPTIMIZE_FOR_PROLOG + hasSpill(false) { + intSpillFillRegs[0] = intSpillFillRegs[1] = intSpillFillRegs[2] = 0; + fpSpillFillRegs[0] = fpSpillFillRegs[1] = fpSpillFillRegs[2] = 0; numVregs = cgfunc_->GetMaxVReg(); lrVec.resize(numVregs); localRegVec.resize(cgfunc_->NumBBs()); @@ -740,10 +738,15 @@ class GraphColorRegAllocator : public RegAllocator { MemOperand *spillMemopnd1; MemOperand *spillMemopnd2; + regno_t intSpillFillRegs[3]; + regno_t fpSpillFillRegs[3]; + + bool doLRA; + bool doOptProlog; + bool hasSpill; + void PrintLiveUnitMap(const LiveRange *lr) const; void PrintLiveRangeConflicts(const LiveRange *lr) const; - void CheckLiveRangeConflicts(const LiveRange *lr) const; - void PrintLiveBbSet(const LiveRange *li, const string str) const; void PrintLiveBbBit(const LiveRange *li) const; void PrintLiveRange(const LiveRange *li, const string str) const; void PrintLiveRanges() const; @@ -785,11 +788,8 @@ class GraphColorRegAllocator : public RegAllocator { void ComputeLiveOut(BB *bb); void ComputeLiveRanges(); MemOperand *CreateSpillMem(uint32 spillIdx); - void CopyInterference(); void CheckInterference(LiveRange *lr1, LiveRange *lr2); void BuildInterferenceGraphSeparateIntFp(std::vector &intLrVec, std::vector &fpLrVec); - void BuildInterferenceGraphCopyVec(); - void BuildInterferenceGraphErrorCheck(); void BuildInterferenceGraph(); void SetBbInfoGlobalAssigned(uint32 bbid, regno_t regno); bool HaveAvailableColor(LiveRange *lr, uint32 num); @@ -830,6 +830,9 @@ class GraphColorRegAllocator : public RegAllocator { void MarkCalleeSaveRegs(); void MarkUsedRegs(Operand *opnd, uint64 &usedRegMask); uint64 FinalizeRegisterPreprocess(FinalizeRegisterInfo *fInfo, Insn *insn); + void GenerateSpillFillRegs(Insn *insn); + RegOperand *CreateSpillFillCode(RegOperand *opnd, Insn *insn, uint32 spillCnt, bool isdef = false); + void SpillLiveRangeForSpills(); void FinalizeRegisters(); MapleVector::iterator GetHighPriorityLr(MapleVector &lrSet); @@ -843,7 +846,6 @@ class GraphColorRegAllocator : public RegAllocator { bool UseIsUncovered(BB *bb, BB *startBb); void FindUseForSplit(LiveRange *lr, SplitBbInfo &bbInfo, bool &remove, set &candidateInLoop, set &defInLoop); - void SplitCopyVecMember(LiveRange *lr); void FindBbSharedInSplit(LiveRange *lr, set &candidateInLoop, set &defInLoop); void ComputeBbForNewSplit(LiveRange *newLr, LiveRange *oldLr); void ClearLrBbFlags(set &member); diff --git a/mapleall/maple_be/include/cg/aarch64/aarch64_insn.h b/mapleall/maple_be/include/cg/aarch64/aarch64_insn.h index c753dbe..3340454 100644 --- a/mapleall/maple_be/include/cg/aarch64/aarch64_insn.h +++ b/mapleall/maple_be/include/cg/aarch64/aarch64_insn.h @@ -61,7 +61,7 @@ class AArch64Insn : public Insn { } bool IsImmaterialInsn() override { - return (GetMachineOpcode() == MOP_comment); + return (dynamic_cast(this) || GetMachineOpcode() == MOP_comment); } bool IsMachineInstruction() override { diff --git a/mapleall/maple_be/include/cg/aarch64/aarch64_isa.h b/mapleall/maple_be/include/cg/aarch64/aarch64_isa.h index 0959e83..d13f167 100644 --- a/mapleall/maple_be/include/cg/aarch64/aarch64_isa.h +++ b/mapleall/maple_be/include/cg/aarch64/aarch64_isa.h @@ -21,10 +21,12 @@ #include "operand.h" #include "mad.h" +#define DEFINE_MOP(op,a2,a3,a4,a5,a6,a7,a8,a9,aa,ab,ac) op, enum AArch64MOP_t { -#include "aarch64_isa.def" +#include "aarch64_md.def" kMopLast }; +#undef DEFINE_MOP namespace maplebe { diff --git a/mapleall/maple_be/include/cg/aarch64/aarch64_md.def b/mapleall/maple_be/include/cg/aarch64/aarch64_md.def new file mode 100644 index 0000000..361bd18 --- /dev/null +++ b/mapleall/maple_be/include/cg/aarch64/aarch64_md.def @@ -0,0 +1,1439 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +// MOP_undef, +DEFINE_MOP(MOP_undef, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"","", 0, 0) + +// # Definitions + +// AARCH64 MOVES +// MOP_xmovrr +DEFINE_MOP(MOP_xmovrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtAlu,"mov","0,1", 1, 1) +// MOP_wmovrr +DEFINE_MOP(MOP_wmovrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtAlu,"mov","0,1", 1, 1) +// MOP_xmovri32 +DEFINE_MOP(MOP_xmovri32, {MOPD_Reg32ID,MOPD_Imm32,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtAlu,"mov","0,1", 1, 1) +// MOP_xmovri64 +DEFINE_MOP(MOP_xmovri64, {MOPD_Reg64ID,MOPD_Imm64,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtAlu,"mov","0,1", 1, 1) + +// MOP_xvmovsr +DEFINE_MOP(MOP_xvmovsr, {MOPD_Reg32FD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtR2f,"fmov","0,1", 1, 1) +// MOP_xvmovdr +DEFINE_MOP(MOP_xvmovdr, {MOPD_Reg64FD,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtR2f,"fmov","0,1", 1, 1) +// MOP_xvmovrs +DEFINE_MOP(MOP_xvmovrs, {MOPD_Reg32ID,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtF2r,"fmov","0,1", 1, 1) +// MOP_xvmovrd +DEFINE_MOP(MOP_xvmovrd, {MOPD_Reg64ID,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtF2r,"fmov","0,1", 1, 1) +// MOP_xvmovs +DEFINE_MOP(MOP_xvmovs, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtFpalu,"fmov","0,1", 1, 1) +// MOP_xvmovd +DEFINE_MOP(MOP_xvmovd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtFpalu,"fmov","0,1", 1, 1) + +// Vector SIMD mov +// MOP_vmovrr +DEFINE_MOP(MOP_vmovrr, {MOPD_Reg128FD,MOPD_Reg128FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtFpalu,"mov","0,1", 1, 1) +// Vector SIMD dup +DEFINE_MOP(MOP_vdupi32, {MOPD_Reg128FD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtFpalu,"dup","0,1", 1, 1) +DEFINE_MOP(MOP_vdupi64, {MOPD_Reg128FD,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtFpalu,"dup","0,1", 1, 1) +DEFINE_MOP(MOP_vdupf32, {MOPD_Reg128FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtFpalu,"dup","0,1", 1, 1) +DEFINE_MOP(MOP_vdupf64, {MOPD_Reg128FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtFpalu,"dup","0,1", 1, 1) + + +// MOP_xvmovvv +DEFINE_MOP(MOP_xvmovvv, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtFpalu,"mov","0,1", 1, 1) +// MOP_xmovvr +DEFINE_MOP(MOP_xvmovvr, {MOPD_Reg32FD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtR2f,"mov","0,1", 1, 1) +// MOP_xmovrv +DEFINE_MOP(MOP_xvmovrv, {MOPD_Reg32ID,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtF2r,"mov","0,1", 1, 1) + +// MOP_xadrp +DEFINE_MOP(MOP_xadrp, {MOPD_Reg64ID,MOPD_Literal,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOADADDR,kLtShift,"adrp","0,1", 1, 1) +// MOP_xadr +DEFINE_MOP(MOP_xadri64, {MOPD_Reg64ID,MOPD_Imm64,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOADADDR,kLtShift,"adr","0,1", 1, 1) +// MOP_xadrpl12 +DEFINE_MOP(MOP_xadrpl12, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Literal_L12,MOPD_Undef,MOPD_Undef},0,kLtAlu,"add","0,1,2", 1, 2) + +// MOP_xaddrrr AARCH64 Arithmetic: add +DEFINE_MOP(MOP_xaddrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"add","0,1,2", 1, 2) +// MOP_xaddrrrs +DEFINE_MOP(MOP_xaddrrrs, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_BitShift64,MOPD_Undef},0,kLtAluShift,"add","0,1,2,3", 1, 3) + +// Vector SIMD add +// MOP_vaddf32rrr AARCH64 Arithmetic: add +DEFINE_MOP(MOP_vaddf32rrr, {MOPD_Reg128FD, MOPD_Reg128FS, MOPD_Reg128FS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"fadd","0,1,2", 1, 2) +// MOP_vaddf64rrr AARCH64 Arithmetic: add +DEFINE_MOP(MOP_vaddf64rrr, {MOPD_Reg128FD, MOPD_Reg128FS, MOPD_Reg128FS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"fadd","0,1,2", 1, 2) +// MOP_vadd32rrr AARCH64 Arithmetic: add +DEFINE_MOP(MOP_vadd32rrr, {MOPD_Reg128ID,MOPD_Reg128IS,MOPD_Reg128IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"add","0,1,2", 1, 2) +// MOP_vadd64rrr AARCH64 Arithmetic: add +DEFINE_MOP(MOP_vadd64rrr, {MOPD_Reg128LD,MOPD_Reg128LS,MOPD_Reg128LS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"add","0,1,2", 1, 2) + + +// MOP_xxwaddrrre +DEFINE_MOP(MOP_xxwaddrrre, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg32IS,MOPD_ExtendShift64,MOPD_Undef},0,kLtAluShift,"add","0,1,2,3", 1, 3) +// MOP_xaddrri24 + +DEFINE_MOP(MOP_xaddrri24, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm12,MOPD_LSL12,MOPD_Undef},0,kLtShift,"add","0,1,2,3", 1, 3) +// MOP_xaddrri12 +DEFINE_MOP(MOP_xaddrri12, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,kLtAlu,"add","0,1,2", 1, 2) +// MOP_waddrrr +DEFINE_MOP(MOP_waddrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"add","0,1,2", 1, 2) +// MOP_waddrrrs +DEFINE_MOP(MOP_waddrrrs, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_BitShift32,MOPD_Undef},0,kLtAluShift,"add","0,1,2,3", 1, 3) +// MOP_waddrri24 +DEFINE_MOP(MOP_waddrri24, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm12,MOPD_LSL12,MOPD_Undef},0,kLtAluShift,"add","0,1,2,3", 1, 3) +// MOP_waddrri12 +DEFINE_MOP(MOP_waddrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,kLtAlu,"add","0,1,2", 1, 2) +// MOP_dadd +DEFINE_MOP(MOP_dadd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fadd","0,1,2", 1, 2) +// MOP_sadd +DEFINE_MOP(MOP_sadd, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fadd","0,1,2", 1, 2) + +// MOP_xsubrrr AARCH64 Arithmetic: sub +DEFINE_MOP(MOP_xsubrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"sub","0,1,2", 1, 2) +// MOP_xsubrrrs +DEFINE_MOP(MOP_xsubrrrs, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_BitShift64,MOPD_Undef},0,kLtAluShift,"sub","0,1,2,3", 1, 3) +// MOP_xsubrri24 +DEFINE_MOP(MOP_xsubrri24, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm12,MOPD_LSL12,MOPD_Undef},0,kLtAluShift,"sub","0,1,2,3", 1, 3) +// MOP_xsubrri12 +DEFINE_MOP(MOP_xsubrri12, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,kLtAlu,"sub","0,1,2", 1, 2) +// MOP_wsubrrr +DEFINE_MOP(MOP_wsubrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"sub","0,1,2", 1, 2) +// MOP_wsubrrrs +DEFINE_MOP(MOP_wsubrrrs, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_BitShift32,MOPD_Undef},0,kLtAluShift,"sub","0,1,2,3", 1, 3) +// MOP_wsubrri24 +DEFINE_MOP(MOP_wsubrri24, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm12,MOPD_LSL12,MOPD_Undef},0,kLtAluShift,"sub","0,1,2,3", 1, 3) +// MOP_wsubrri12 +DEFINE_MOP(MOP_wsubrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,kLtAlu,"sub","0,1,2", 1, 2) +// MOP_dsub +DEFINE_MOP(MOP_dsub, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fsub","0,1,2", 1, 2) +// MOP_ssub +DEFINE_MOP(MOP_ssub, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fsub","0,1,2", 1, 2) + +// AARCH64 Arithmetic: multiply +// MOP_Tbxmulrrr +DEFINE_MOP(MOP_xmulrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtMul,"mul","0,1,2", 1, 2) +// MOP_wmulrrr +DEFINE_MOP(MOP_wmulrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,kLtMul,"mul","0,1,2", 1, 2) +// MOP_Tbxvmuls +DEFINE_MOP(MOP_xvmuls, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,kLtFpmul,"fmul","0,1,2", 1, 2) +// MOP_Tbxvmuld +DEFINE_MOP(MOP_xvmuld, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,kLtFpmul,"fmul","0,1,2", 1, 2) +//MOP_xsmullrrr +DEFINE_MOP(MOP_xsmullrrr, {MOPD_Reg64ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,kLtMul,"smull","0,1,2", 1, 2) + +// AARCH64 leading zeros, reverse bits (for trailing zeros) +// MOP_wclz +DEFINE_MOP(MOP_wclz, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtAlu,"clz","0,1", 1, 1) +// MOP_xclz +DEFINE_MOP(MOP_xclz, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtAlu,"clz","0,1", 1, 1) +// MOP_wrbit +DEFINE_MOP(MOP_wrbit, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtAlu,"rbit","0,1", 1, 1) +// MOP_xrbit +DEFINE_MOP(MOP_xrbit, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtAlu,"rbit","0,1", 1, 1) + +// AARCH64 Conversions +// MOP_xsxtb32 +DEFINE_MOP(MOP_xsxtb32, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtAluShift,"sxtb","0,1", 1, 1) +// MOP_xsxtb64 +DEFINE_MOP(MOP_xsxtb64, {MOPD_Reg64ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtAluShift,"sxtb","0,1", 1, 1) +// MOP_xsxth32 +DEFINE_MOP(MOP_xsxth32, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtAluShift,"sxth","0,1", 1, 1) +// MOP_xsxth64 +DEFINE_MOP(MOP_xsxth64, {MOPD_Reg64ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtAluShift,"sxth","0,1", 1, 1) +// MOP_xsxtw64 +DEFINE_MOP(MOP_xsxtw64, {MOPD_Reg64ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtAluShift,"sxtw","0,1", 1, 1) + +// MOP_xuxtb32 +DEFINE_MOP(MOP_xuxtb32, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtAluShift,"uxtb","0,1", 1, 1) +// MOP_xuxth32 +DEFINE_MOP(MOP_xuxth32, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtAluShift,"uxth","0,1", 1, 1) +// MOP_xuxtw64 Same as mov w0,w0 +DEFINE_MOP(MOP_xuxtw64, {MOPD_Reg64ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtAluShift,"uxtw","0,1", 1, 1) + +// MOP_xvcvtfd +DEFINE_MOP(MOP_xvcvtfd, {MOPD_Reg32FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtFpalu,"fcvt","0,1", 1, 1) +// MOP_xvcvtdf +DEFINE_MOP(MOP_xvcvtdf, {MOPD_Reg64FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtFpalu,"fcvt","0,1", 1, 1) + +// MOP_vcvtrf fcvtzs w,s +DEFINE_MOP(MOP_vcvtrf, {MOPD_Reg32ID,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvtzs","0,1", 1, 1) +// MOP_xvcvtrf fcvtzs x,s +DEFINE_MOP(MOP_xvcvtrf, {MOPD_Reg64ID,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvtzs","0,1", 1, 1) +// MOP_vcvturf fcvtzu w,s +DEFINE_MOP(MOP_vcvturf, {MOPD_Reg32ID,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvtzu","0,1", 1, 1) +// MOP_xvcvturf fcvtzu x,s +DEFINE_MOP(MOP_xvcvturf, {MOPD_Reg64ID,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvtzu","0,1", 1, 1) + +// MOP_vcvtas fcvtas w,s (for round) +DEFINE_MOP(MOP_vcvtas, {MOPD_Reg32ID,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvtas","0,1", 1, 1) +// MOP_xvcvtas fcvtas x,s +DEFINE_MOP(MOP_xvcvtas, {MOPD_Reg64ID,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvtas","0,1", 1, 1) +// MOP_vcvtms fcvtms w,s (for floor) +DEFINE_MOP(MOP_vcvtms, {MOPD_Reg32ID,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvtms","0,1", 1, 1) +// MOP_xvcvtms fcvtms x,s +DEFINE_MOP(MOP_xvcvtms, {MOPD_Reg64ID,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvtms","0,1", 1, 1) +// MOP_vcvtps fcvtps w,s (for ceil) +DEFINE_MOP(MOP_vcvtps, {MOPD_Reg32ID,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvtps","0,1", 1, 1) +// MOP_xvcvtps fcvtps x,d +DEFINE_MOP(MOP_xvcvtps, {MOPD_Reg64ID,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvtps","0,1", 1, 1) + +// MOP_vcvtrd fcvtzs w,d +DEFINE_MOP(MOP_vcvtrd, {MOPD_Reg32ID,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvtzs","0,1", 1, 1) +// MOP_xvcvtrd fcvtzs x,d +DEFINE_MOP(MOP_xvcvtrd, {MOPD_Reg64ID,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvtzs","0,1", 1, 1) +// MOP_vcvturd fcvtzu w,d +DEFINE_MOP(MOP_vcvturd, {MOPD_Reg32ID,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvtzu","0,1", 1, 1) +// MOP_xvcvturd fcvtzu x,d +DEFINE_MOP(MOP_xvcvturd, {MOPD_Reg64ID,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvtzu","0,1", 1, 1) + +// MOP_vcvtfr scvtf s,w +DEFINE_MOP(MOP_vcvtfr, {MOPD_Reg32FD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtR2fCvt,"scvtf","0,1", 1, 1) +// MOP_xvcvtfr scvtf s,x +DEFINE_MOP(MOP_xvcvtfr, {MOPD_Reg32FD,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtR2fCvt,"scvtf","0,1", 1, 1) +// MOP_vcvtufr ucvtf s,w +DEFINE_MOP(MOP_vcvtufr, {MOPD_Reg32FD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtR2fCvt,"ucvtf","0,1", 1, 1) +// MOP_xvcvtufr ucvtf s,x +DEFINE_MOP(MOP_xvcvtufr, {MOPD_Reg32FD,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtR2fCvt,"ucvtf","0,1", 1, 1) + +// MOP_vcvtdr scvtf d,w +DEFINE_MOP(MOP_vcvtdr, {MOPD_Reg64FD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtR2fCvt,"scvtf","0,1", 1, 1) +// MOP_xvcvtdr scvtf d,x +DEFINE_MOP(MOP_xvcvtdr, {MOPD_Reg64FD,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtR2fCvt,"scvtf","0,1", 1, 1) +// MOP_vcvtudr ucvtf d,w +DEFINE_MOP(MOP_vcvtudr, {MOPD_Reg64FD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtR2fCvt,"ucvtf","0,1", 1, 1) +// MOP_xvcvtudr ucvtf d,x +DEFINE_MOP(MOP_xvcvtudr, {MOPD_Reg64FD,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtR2fCvt,"ucvtf","0,1", 1, 1) + +// MOP_xcsel +DEFINE_MOP(MOP_wcselrrrc, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Cond,MOPD_Undef},ISCONDDEF,kLtAlu,"csel","0,1,2,3", 1, 3) +DEFINE_MOP(MOP_xcselrrrc, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Cond,MOPD_Undef},ISCONDDEF,kLtAlu,"csel","0,1,2,3", 1, 3) + +// MOP_xcset -- all conditions minus AL & NV +DEFINE_MOP(MOP_wcsetrc, {MOPD_Reg32ID,MOPD_Cond,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONDSET | ISCONDDEF,kLtAlu,"cset","0,1", 1, 1) +DEFINE_MOP(MOP_xcsetrc, {MOPD_Reg64ID,MOPD_Cond,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONDSET | ISCONDDEF,kLtAlu,"cset","0,1", 1, 1) + +// MOP_xcsinc +DEFINE_MOP(MOP_wcsincrrrc, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Cond,MOPD_Undef},ISCONDDEF,kLtAlu,"csinc","0,1,2,3", 1, 3) +DEFINE_MOP(MOP_xcsincrrrc, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Cond,MOPD_Undef},ISCONDDEF,kLtAlu,"csinc","0,1,2,3", 1, 3) + +// MOP_xcsinv +DEFINE_MOP(MOP_wcsinvrrrc, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Cond,MOPD_Undef},ISCONDDEF,kLtAlu,"csinv","0,1,2,3", 1, 3) +DEFINE_MOP(MOP_xcsinvrrrc, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Cond,MOPD_Undef},ISCONDDEF,kLtAlu,"csinv","0,1,2,3", 1, 3) + +// MOP_xandrrr +DEFINE_MOP(MOP_xandrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"and","0,1,2", 1, 2) +// MOP_xandrrrs +DEFINE_MOP(MOP_xandrrrs, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_BitShift64,MOPD_Undef},0,kLtAluShift,"and","0,1,2,3", 1, 3) +// MOP_xandrri13 +DEFINE_MOP(MOP_xandrri13, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm13,MOPD_Undef,MOPD_Undef},0,kLtAlu,"and","0,1,2", 1, 2) +// MOP_wandrrr +DEFINE_MOP(MOP_wandrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"and","0,1,2", 1, 2) +// MOP_wandrrrs +DEFINE_MOP(MOP_wandrrrs, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_BitShift32,MOPD_Undef},0,kLtAluShift,"and","0,1,2,3", 1, 3) +// MOP_wandrri12 +DEFINE_MOP(MOP_wandrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,kLtAlu,"and","0,1,2", 1, 2) + +// MOP_xiorrrr +DEFINE_MOP(MOP_xiorrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"orr","0,1,2", 1, 2) +// MOP_xiorrrrs +DEFINE_MOP(MOP_xiorrrrs, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_BitShift64,MOPD_Undef},0,kLtAlu,"orr","0,1,2,3", 1, 3) +// MOP_xiorrri13 +DEFINE_MOP(MOP_xiorrri13, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm13,MOPD_Undef,MOPD_Undef},0,kLtAlu,"orr","0,1,2", 1, 2) +// MOP_wiorrrr +DEFINE_MOP(MOP_wiorrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"orr","0,1,2", 1, 2) +// MOP_wiorrrrs +DEFINE_MOP(MOP_wiorrrrs, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_BitShift32,MOPD_Undef},0,kLtAlu,"orr","0,1,2,3", 1, 3) +// MOP_wiorrri12 +DEFINE_MOP(MOP_wiorrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,kLtAlu,"orr","0,1,2", 1, 2) + +// MOP_xiorri13r +DEFINE_MOP(MOP_xiorri13r, {MOPD_Reg64ID,MOPD_Imm13,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"orr","0,2,1", 1, 2) +// MOP_wiorri12r +DEFINE_MOP(MOP_wiorri12r, {MOPD_Reg32ID,MOPD_Imm12,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"orr","0,2,1", 1, 2) + +// MOP_xeorrrr +DEFINE_MOP(MOP_xeorrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"eor","0,1,2", 1, 2) +// MOP_xeorrrrs +DEFINE_MOP(MOP_xeorrrrs, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_BitShift64,MOPD_Undef},0,kLtAlu,"eor","0,1,2,3", 1, 3) +// MOP_xeorrri13 +DEFINE_MOP(MOP_xeorrri13, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm13,MOPD_Undef,MOPD_Undef},0,kLtAlu,"eor","0,1,2", 1, 2) +// MOP_weorrrr +DEFINE_MOP(MOP_weorrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"eor","0,1,2", 1, 2) +// MOP_weorrrrs +DEFINE_MOP(MOP_weorrrrs, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_BitShift32,MOPD_Undef},0,kLtAlu,"eor","0,1,2,3", 1, 3) +// MOP_weorrri12 +DEFINE_MOP(MOP_weorrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,kLtAlu,"eor","0,1,2", 1, 2) + +// MOP_weorrri8m +DEFINE_MOP(MOP_weorrri8m, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,kLtAlu,"eor","0,1,2", 1, 2) + +// MOP_xnotrr +DEFINE_MOP(MOP_xnotrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtAlu,"mvn","0,1", 1, 1) +// MOP_wnotrr +DEFINE_MOP(MOP_wnotrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtAlu,"mvn","0,1", 1, 1) + +// MOP_wfmaxrrr +DEFINE_MOP(MOP_wfmaxrrr, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fmax","0,1,2", 1, 2) +// MOP_xfmaxrrr +DEFINE_MOP(MOP_xfmaxrrr, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fmax","0,1,2", 1, 2) +// MOP_wfminrrr +DEFINE_MOP(MOP_wfminrrr, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fmin","0,1,2", 1, 2) +// MOP_xfminrrr +DEFINE_MOP(MOP_xfminrrr, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fmin","0,1,2", 1, 2) + +// MOP_wsdivrrr +DEFINE_MOP(MOP_wsdivrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},CANTHROW,kLtDiv,"sdiv","0,1,2", 1, 2) +// MOP_xsdivrrr +DEFINE_MOP(MOP_xsdivrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},CANTHROW,kLtDiv,"sdiv","0,1,2", 1, 2) +// MOP_wudivrrr +DEFINE_MOP(MOP_wudivrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},CANTHROW,kLtDiv,"udiv","0,1,2", 1, 2) +// MOP_xudivrrr +DEFINE_MOP(MOP_xudivrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},CANTHROW,kLtDiv,"udiv","0,1,2", 1, 2) + +// MOP_wmsubrrrr +DEFINE_MOP(MOP_wmsubrrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,kLtMul,"msub","0,1,2,3", 1, 3) +// MOP_xmsubrrrr +DEFINE_MOP(MOP_xmsubrrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef},0,kLtMul,"msub","0,1,2,3", 1, 3) + +// MPO_wubfxrri5i5 +DEFINE_MOP(MOP_wubfxrri5i5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm5,MOPD_Imm5,MOPD_Undef},0,kLtAluShift,"ubfx","0,1,2,3", 1, 3) +// MPO_xubfxrri6i6 +DEFINE_MOP(MOP_xubfxrri6i6, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm6,MOPD_Imm6,MOPD_Undef},0,kLtAluShift,"ubfx","0,1,2,3", 1, 3) + +// MPO_wsbfxrri5i5 -- Signed Bitfield Extract +DEFINE_MOP(MOP_wsbfxrri5i5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm5,MOPD_Imm5,MOPD_Undef},0,kLtAluShift,"sbfx","0,1,2,3", 1, 3) +// MPO_xsbfxrri6i6 +DEFINE_MOP(MOP_xsbfxrri6i6, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm6,MOPD_Imm6,MOPD_Undef},0,kLtAluShift,"sbfx","0,1,2,3", 1, 3) + +// MPO_wubfizrri5i5 -- Unsigned Bitfield Insert in Zero +DEFINE_MOP(MOP_wubfizrri5i5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm5,MOPD_Imm5,MOPD_Undef},0,kLtAluShift,"ubfiz","0,1,2,3", 1, 3) +// MPO_xubfizrri6i6 +DEFINE_MOP(MOP_xubfizrri6i6, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm6,MOPD_Imm6,MOPD_Undef},0,kLtAluShift,"ubfiz","0,1,2,3", 1, 3) + +// MPO_wbfirri5i5 -- Bitfield Insert +DEFINE_MOP(MPO_wbfirri5i5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm5,MOPD_Imm5,MOPD_Undef},0,kLtAluShift,"bfi","0,1,2,3", 1, 3) +// MPO_xbfirri6i6 +DEFINE_MOP(MPO_xbfirri6i6, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm6,MOPD_Imm6,MOPD_Undef},0,kLtAluShift,"bfi","0,1,2,3", 1, 3) + + +// MOP_xlslrri6,--- Logical Shift Left +DEFINE_MOP(MOP_xlslrri6, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm6,MOPD_Undef,MOPD_Undef},0,kLtAluShift,"lsl","0,1,2", 1, 2) +// MOP_wlslrri5 +DEFINE_MOP(MOP_wlslrri5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,kLtAluShift,"lsl","0,1,2", 1, 2) +// MOP_xasrrri6, +DEFINE_MOP(MOP_xasrrri6, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm6,MOPD_Undef,MOPD_Undef},0,kLtAluShift,"asr","0,1,2", 1, 2) +// MOP_wasrrri5 +DEFINE_MOP(MOP_wasrrri5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,kLtAluShift,"asr","0,1,2", 1, 2) +// MOP_xlsrrri6, +DEFINE_MOP(MOP_xlsrrri6, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm6,MOPD_Undef,MOPD_Undef},0,kLtAluShift,"lsr","0,1,2", 1, 2) +// MOP_wlsrrri5 +DEFINE_MOP(MOP_wlsrrri5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,kLtAluShift,"lsr","0,1,2", 1, 2) +// MOP_xlslrrr, +DEFINE_MOP(MOP_xlslrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAluShiftReg,"lsl","0,1,2", 1, 2) +// MOP_wlslrrr +DEFINE_MOP(MOP_wlslrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,kLtAluShiftReg,"lsl","0,1,2", 1, 2) +// MOP_xasrrrr, +DEFINE_MOP(MOP_xasrrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAluShiftReg,"asr","0,1,2", 1, 2) +// MOP_wasrrrr +DEFINE_MOP(MOP_wasrrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,kLtAluShiftReg,"asr","0,1,2", 1, 2) +// MOP_xlsrrrr, +DEFINE_MOP(MOP_xlsrrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAluShiftReg,"lsr","0,1,2", 1, 2) +// MOP_wlsrrrr +DEFINE_MOP(MOP_wlsrrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,kLtAluShiftReg,"lsr","0,1,2", 1, 2) + +// MOP_wsfmovrr w->s +DEFINE_MOP(MOP_wsfmovrr, {MOPD_Reg32FD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtR2f,"fmov","0,1", 1, 1) +// MOP_wsfmovri imm8->s +DEFINE_MOP(MOP_wsfmovri, {MOPD_Reg32FD,MOPD_Imm8,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtFconst,"fmov","0,1", 1, 1) +// MOP_swfmovrr s->w +DEFINE_MOP(MOP_swfmovrr, {MOPD_Reg32ID,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtF2r,"fmov","0,1", 1, 1) +// MOP_xdfmovrr x->d +DEFINE_MOP(MOP_xdfmovrr, {MOPD_Reg64FD,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtR2f,"fmov","0,1", 1, 1) +// MOP_xdfmovri imm8->d +DEFINE_MOP(MOP_xdfmovri, {MOPD_Reg64FD,MOPD_Imm8,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtFconst,"fmov","0,1", 1, 1) +// MOP_dxfmovrr d->x +DEFINE_MOP(MOP_dxfmovrr, {MOPD_Reg64ID,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtF2r,"fmov","0,1", 1, 1) + +// MOP_xcsneg -- Conditional Select Negation +DEFINE_MOP(MOP_wcsnegrrrc, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Cond,MOPD_Undef},ISCONDDEF,kLtAlu,"csneg","0,1,2,3", 1, 3) +DEFINE_MOP(MOP_xcsnegrrrc, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Cond,MOPD_Undef},ISCONDDEF,kLtAlu,"csneg","0,1,2,3", 1, 3) + +// MOP_habsrr +DEFINE_MOP(MOP_habsrr, {MOPD_Reg16FD,MOPD_Reg16FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fabs","0,1", 1, 1) +// MOP_sabsrr +DEFINE_MOP(MOP_sabsrr, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fabs","0,1", 1, 1) +// MOP_dabsrr +DEFINE_MOP(MOP_dabsrr, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fabs","0,1", 1, 1) + +// neg i32 +DEFINE_MOP(MOP_winegrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtAlu,"neg","0,1", 1, 1) +// neg i64 +DEFINE_MOP(MOP_xinegrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtAlu,"neg","0,1", 1, 1) +// neg f32 +DEFINE_MOP(MOP_wfnegrr, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fneg","0,1", 1, 1) +// neg f64 +DEFINE_MOP(MOP_xfnegrr, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fneg","0,1", 1, 1) + +// MOP_hdivrrr +DEFINE_MOP(MOP_hdivrrr, {MOPD_Reg16FD,MOPD_Reg16FS,MOPD_Reg16FS,MOPD_Undef,MOPD_Undef},CANTHROW,kLtAdvsimdDivS,"fdiv","0,1,2", 1, 2) +// MOP_sdivrrr +DEFINE_MOP(MOP_sdivrrr, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},CANTHROW,kLtAdvsimdDivS,"fdiv","0,1,2", 1, 2) +// MOP_ddivrrr +DEFINE_MOP(MOP_ddivrrr, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},CANTHROW,kLtAdvsimdDivD,"fdiv","0,1,2", 1, 2) + +// MOP_hcselrrrc --- Floating-point Conditional Select +DEFINE_MOP(MOP_hcselrrrc, {MOPD_Reg16FD,MOPD_Reg16FS,MOPD_Reg16FS,MOPD_Cond,MOPD_Undef},ISCONDDEF,kLtFpalu,"fcsel","0,1,2,3", 1, 3) +// MOP_scselrrrc +DEFINE_MOP(MOP_scselrrrc, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Cond,MOPD_Undef},ISCONDDEF,kLtFpalu,"fcsel","0,1,2,3", 1, 3) +// MOP_dcselrrrc +DEFINE_MOP(MOP_dcselrrrc, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Cond,MOPD_Undef},ISCONDDEF,kLtFpalu,"fcsel","0,1,2,3", 1, 3) + +// MOP_wldli -- load 32-bit literal +DEFINE_MOP(MOP_wldli, {MOPD_Reg32ID,MOPD_Imm32LI,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtLoad2,"ldr","0,1", 1, 1) +// MOP_xldli -- load 64-bit literal +DEFINE_MOP(MOP_xldli, {MOPD_Reg64ID,MOPD_Imm64LI,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtLoad2,"ldr","0,1", 1, 1) +// MOP_sldli -- load 32-bit literal +DEFINE_MOP(MOP_sldli, {MOPD_Reg32FD,MOPD_Imm32LI,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtLoad2,"ldr","0,1", 1, 1) +// MOP_dldli -- load 64-bit literal +DEFINE_MOP(MOP_dldli, {MOPD_Reg64FD,MOPD_Imm64LI,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtLoad2,"ldr","0,1", 1, 1) + +// AArch64 branches/calls +// MOP_xbl -- branch with link (call); this is a special definition +DEFINE_MOP(MOP_xbl, {MOPD_FuncName,MOPD_LISTS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCALL|CANTHROW,kLtBranch,"bl","0", 0, 2) +// MOP_xblr -- branch with link (call) to register; this is a special definition +DEFINE_MOP(MOP_xblr, {MOPD_Reg64IS,MOPD_LISTS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCALL|CANTHROW,kLtBranch,"blr","0", 0, 2) + +// AARCH64 LOADS +// MOP_wldrsb --- Load Register Signed Byte +DEFINE_MOP(MOP_wldrsb, {MOPD_Reg32ID,MOPD_Mem8S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtLoad1,"ldrsb","0,1", 1, 1) +// MOP_wldrb +DEFINE_MOP(MOP_wldrb, {MOPD_Reg32ID,MOPD_Mem8S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtLoad1,"ldrb","0,1", 1, 1) +// MOP_wldrsh --- Load Register Signed Halfword +DEFINE_MOP(MOP_wldrsh, {MOPD_Reg32ID,MOPD_Mem16S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtLoad1,"ldrsh","0,1", 1, 1) +// MOP_wldrh +DEFINE_MOP(MOP_wldrh, {MOPD_Reg32ID, MOPD_Mem16S, MOPD_Undef, MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtLoad1,"ldrh","0,1", 1, 1) +// MOP_wldr +DEFINE_MOP(MOP_wldr, {MOPD_Reg32ID,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtLoad1,"ldr","0,1", 1, 1) +// MOP_xldr +DEFINE_MOP(MOP_xldr, {MOPD_Reg64ID,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtLoad2,"ldr","0,1", 1, 1) +// MOP_bldr +DEFINE_MOP(MOP_bldr, {MOPD_Reg8FD,MOPD_Mem8S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtFLoad64,"ldr","0,1", 1, 1) +// MOP_hldr +DEFINE_MOP(MOP_hldr, {MOPD_Reg16FD,MOPD_Mem16S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtFLoad64,"ldr","0,1", 1, 1) +// MOP_sldr +DEFINE_MOP(MOP_sldr, {MOPD_Reg32FD,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtFLoadMany,"ldr","0,1", 1, 1) +// MOP_dldr +DEFINE_MOP(MOP_dldr, {MOPD_Reg64FD,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtFLoadMany,"ldr","0,1", 1, 1) +// MOP_vldr +DEFINE_MOP(MOP_vldr, {MOPD_Reg128FD,MOPD_Mem128S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtFLoadMany,"ldr","0,1", 1, 1) + +// AArch64 LDP/LDPSW +// MOP_wldp +DEFINE_MOP(MOP_wldp, {MOPD_Reg32ID,MOPD_Reg32ID,MOPD_Mem32S,MOPD_Undef,MOPD_Undef},ISLOAD|ISLOADPAIR|CANTHROW,kLtLoad2,"ldp","0,1,2", 2, 1) +// MOP_xldp +DEFINE_MOP(MOP_xldp, {MOPD_Reg64ID,MOPD_Reg64ID,MOPD_Mem64S,MOPD_Undef,MOPD_Undef},ISLOAD|ISLOADPAIR|CANTHROW,kLtLoad3plus,"ldp","0,1,2", 2, 1) +// MOP_xldpsw +DEFINE_MOP(MOP_xldpsw, {MOPD_Reg64ID,MOPD_Reg64ID,MOPD_Mem32S,MOPD_Undef,MOPD_Undef},ISLOAD|ISLOADPAIR|CANTHROW,kLtLoad2,"ldpsw","0,1,2", 2, 1) +// MOP_sldp +DEFINE_MOP(MOP_sldp, {MOPD_Reg32FD,MOPD_Reg32FD,MOPD_Mem32S,MOPD_Undef,MOPD_Undef},ISLOAD|ISLOADPAIR|CANTHROW,kLtFLoad64,"ldp","0,1,2", 2, 1) +// MOP_dldp +DEFINE_MOP(MOP_dldp, {MOPD_Reg64FD,MOPD_Reg64FD,MOPD_Mem64S,MOPD_Undef,MOPD_Undef},ISLOAD|ISLOADPAIR|CANTHROW,kLtFLoadMany,"ldp","0,1,2", 2, 1) + +// AARCH64 Load with Acquire semantics +// MOP_wldarb +DEFINE_MOP(MOP_wldarb, {MOPD_Reg32ID,MOPD_Mem8S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|HASACQUIRE|CANTHROW,kLtUndef,"ldarb","0,1", 1, 1) +// MOP_wldarh +DEFINE_MOP(MOP_wldarh, {MOPD_Reg32ID, MOPD_Mem16S, MOPD_Undef, MOPD_Undef,MOPD_Undef},ISLOAD|HASACQUIRE|CANTHROW,kLtUndef,"ldarh","0,1", 1, 1) +// MOP_wldar +DEFINE_MOP(MOP_wldar, {MOPD_Reg32ID,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|HASACQUIRE|CANTHROW,kLtUndef,"ldar","0,1", 1, 1) +// MOP_xldar +DEFINE_MOP(MOP_xldar, {MOPD_Reg64ID,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|HASACQUIRE|CANTHROW,kLtUndef,"ldar","0,1", 1, 1) + +// AARCH64 Load with LOAcquire semantics +// MOP_wldlarb +DEFINE_MOP(MOP_wldlarb, {MOPD_Reg32ID,MOPD_Mem8S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|HASLOACQUIRE|CANTHROW,kLtUndef,"ldlarb","0,1", 1, 1) +// MOP_wldlarh +DEFINE_MOP(MOP_wldlarh, {MOPD_Reg32ID, MOPD_Mem16S, MOPD_Undef, MOPD_Undef,MOPD_Undef},ISLOAD|HASLOACQUIRE|CANTHROW,kLtUndef,"ldlarh","0,1", 1, 1) +// MOP_wldlar +DEFINE_MOP(MOP_wldlar, {MOPD_Reg32ID,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|HASLOACQUIRE|CANTHROW,kLtUndef,"ldlar","0,1", 1, 1) +// MOP_xldlar +DEFINE_MOP(MOP_xldlar, {MOPD_Reg64ID,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|HASLOACQUIRE|CANTHROW,kLtUndef,"ldlar","0,1", 1, 1) + +// AARCH64 Load with Acquire RCpc semantics +// MOP_wldaprb +DEFINE_MOP(MOP_wldaprb, {MOPD_Reg32ID,MOPD_Mem8S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|HASACQUIRERCPC|CANTHROW,kLtUndef,"ldaprb","0,1", 1, 1) +// MOP_wldaprh +DEFINE_MOP(MOP_wldaprh, {MOPD_Reg32ID, MOPD_Mem16S, MOPD_Undef, MOPD_Undef,MOPD_Undef},ISLOAD|HASACQUIRERCPC|CANTHROW,kLtUndef,"ldaprh","0,1", 1, 1) +// MOP_wldapr +DEFINE_MOP(MOP_wldapr, {MOPD_Reg32ID,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|HASACQUIRERCPC|CANTHROW,kLtUndef,"ldapr","0,1", 1, 1) +// MOP_xldapr +DEFINE_MOP(MOP_xldapr, {MOPD_Reg64ID,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|HASACQUIRERCPC|CANTHROW,kLtUndef,"ldapr","0,1", 1, 1) + +// MOP_wmovkri16 -- LSL4/LSL6 is not encoding LSL per se. For the moment assumes it is LSL only. +DEFINE_MOP(MOP_wmovkri16, {MOPD_Reg32IDS,MOPD_Imm16,MOPD_LSL4,MOPD_Undef,MOPD_Undef},ISMOVE|ISPARTDEF,kLtShift,"movk","0,1,2", 1, 3) +// MOP_xmovkri16 +DEFINE_MOP(MOP_xmovkri16, {MOPD_Reg64IDS,MOPD_Imm16,MOPD_LSL6,MOPD_Undef,MOPD_Undef},ISMOVE|ISPARTDEF,kLtShift,"movk","0,1,2", 1, 3) + +// MOP_wmovzri16 +DEFINE_MOP(MOP_wmovzri16, {MOPD_Reg32ID,MOPD_Imm16,MOPD_LSL4,MOPD_Undef,MOPD_Undef},ISMOVE|ISPARTDEF,kLtShift,"movz","0,1,2", 1, 2) +// MOP_xmovzri16 +DEFINE_MOP(MOP_xmovzri16, {MOPD_Reg64ID,MOPD_Imm16,MOPD_LSL6,MOPD_Undef,MOPD_Undef},ISMOVE|ISPARTDEF,kLtShift,"movz","0,1,2", 1, 2) + +// MOP_wmovnri16 +DEFINE_MOP(MOP_wmovnri16, {MOPD_Reg32ID,MOPD_Imm16,MOPD_LSL4,MOPD_Undef,MOPD_Undef},ISMOVE|ISPARTDEF,kLtShift,"movn","0,1,2", 1, 2) +// MOP_xmovnri16 +DEFINE_MOP(MOP_xmovnri16, {MOPD_Reg64ID,MOPD_Imm16,MOPD_LSL6,MOPD_Undef,MOPD_Undef},ISMOVE|ISPARTDEF,kLtShift,"movn","0,1,2", 1, 2) + +// AARCH64 Load exclusive with/without acquire semantics +DEFINE_MOP(MOP_wldxrb, {MOPD_Reg32ID,MOPD_Mem8S, MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|ISATOMIC|CANTHROW,kLtUndef,"ldxrb","0,1", 1, 1) +DEFINE_MOP(MOP_wldxrh, {MOPD_Reg32ID,MOPD_Mem16S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|ISATOMIC|CANTHROW,kLtUndef,"ldxrh","0,1", 1, 1) +DEFINE_MOP(MOP_wldxr, {MOPD_Reg32ID,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|ISATOMIC|CANTHROW,kLtUndef,"ldxr","0,1", 1, 1) +DEFINE_MOP(MOP_xldxr, {MOPD_Reg64ID,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|ISATOMIC|CANTHROW,kLtUndef,"ldxr","0,1", 1, 1) + +DEFINE_MOP(MOP_wldaxrb,{MOPD_Reg32ID,MOPD_Mem8S, MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|ISATOMIC|HASACQUIRE|CANTHROW,kLtUndef,"ldaxrb","0,1", 1, 1) +DEFINE_MOP(MOP_wldaxrh,{MOPD_Reg32ID,MOPD_Mem16S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|ISATOMIC|HASACQUIRE|CANTHROW,kLtUndef,"ldaxrh","0,1", 1, 1) +DEFINE_MOP(MOP_wldaxr, {MOPD_Reg32ID,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|ISATOMIC|HASACQUIRE|CANTHROW,kLtUndef,"ldaxr","0,1", 1, 1) +DEFINE_MOP(MOP_xldaxr, {MOPD_Reg64ID,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|ISATOMIC|HASACQUIRE|CANTHROW,kLtUndef,"ldaxr","0,1", 1, 1) + +DEFINE_MOP(MOP_wldaxp, {MOPD_Reg32ID,MOPD_Reg32ID,MOPD_Mem32S,MOPD_Undef,MOPD_Undef},ISLOAD|ISLOADPAIR|ISATOMIC|HASACQUIRE|CANTHROW,kLtUndef,"ldaxp","0,1,2", 2, 1) +DEFINE_MOP(MOP_xldaxp, {MOPD_Reg64ID,MOPD_Reg64ID,MOPD_Mem64S,MOPD_Undef,MOPD_Undef},ISLOAD|ISLOADPAIR|ISATOMIC|HASACQUIRE|CANTHROW,kLtUndef,"ldaxp","0,1,2", 2, 1) + +// MOP_vsqrts +DEFINE_MOP(MOP_vsqrts, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},CANTHROW,kLtAdvsimdDivS,"fsqrt","0,1", 1, 1) +// MOP_vsqrtd +DEFINE_MOP(MOP_vsqrtd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},CANTHROW,kLtAdvsimdDivD,"fsqrt","0,1", 1, 1) + + +// # Non Definitions +// # As far as register allocation is concerned, the instructions below are non-definitions. + +// MOP_beq +DEFINE_MOP(MOP_beq, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"beq","1", 0, 2) +// MOP_bne +DEFINE_MOP(MOP_bne, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bne","1", 0, 2) +// MOP_blt +DEFINE_MOP(MOP_blt, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"blt","1", 0, 2) +// MOP_ble +DEFINE_MOP(MOP_ble, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"ble","1", 0, 2) +// MOP_bgt +DEFINE_MOP(MOP_bgt, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bgt","1", 0, 2) +// MOP_bge +DEFINE_MOP(MOP_bge, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bge","1", 0, 2) +// MOP_blo equal to MOP_blt for unsigned comparison +DEFINE_MOP(MOP_blo, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"blo","1", 0, 2) +// MOP_bls equal to MOP_bls for unsigned comparison +DEFINE_MOP(MOP_bls, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bls","1", 0, 2) +// MOP_bhs equal to MOP_bge for unsigned comparison +DEFINE_MOP(MOP_bhs, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bhs","1", 0, 2) +// MOP_bhi equal to MOP_bgt for float comparison +DEFINE_MOP(MOP_bhi, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bhi","1", 0, 2) +// MOP_bpl equal to MOP_bge for float comparison +DEFINE_MOP(MOP_bpl, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bpl","1", 0, 2) +DEFINE_MOP(MOP_bmi, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bmi","1", 0, 2) +DEFINE_MOP(MOP_bvc, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bvc","1", 0, 2) +DEFINE_MOP(MOP_bvs, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bvs","1", 0, 2) +DEFINE_MOP(MOP_bal, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bal","1", 0, 2) + +// MOP_xret AARCH64 Specific +DEFINE_MOP(MOP_xret, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},CANTHROW,kLtBranch,"ret","", 0, 0) + +// AARCH64 Floating-Point COMPARES signaling versions +// MOP_hcmperi -- AArch64 cmp has no dest operand +DEFINE_MOP(MOP_hcmperi, {MOPD_RegCCD, MOPD_Reg16FS,MOPD_FPZeroImm8,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fcmpe","1,2", 1, 2) +// MOP_hcmperr -- register, shifted register, AArch64 cmp has no dest operand +DEFINE_MOP(MOP_hcmperr, {MOPD_RegCCD, MOPD_Reg16FS,MOPD_Reg16FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fcmpe","1,2", 1, 2) + +// MOP_scmperi -- AArch64 cmp has no dest operand +DEFINE_MOP(MOP_scmperi, {MOPD_RegCCD, MOPD_Reg32FS,MOPD_FPZeroImm8,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fcmpe","1,2", 1, 2) +// MOP_scmperr +DEFINE_MOP(MOP_scmperr, {MOPD_RegCCD, MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fcmpe","1,2", 1, 2) + +// MOP_dcmperi -- AArch64 cmp has no dest operand +DEFINE_MOP(MOP_dcmperi, {MOPD_RegCCD, MOPD_Reg64FS,MOPD_FPZeroImm8,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fcmpe","1,2", 1, 2) +// MOP_dcmperr +DEFINE_MOP(MOP_dcmperr, {MOPD_RegCCD, MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fcmpe","1,2", 1, 2) + +// AARCH64 Floating-Point COMPARES non-signaling (quiet) versions +// MOP_hcmpqri -- AArch64 cmp has no dest operand +DEFINE_MOP(MOP_hcmpqri, {MOPD_RegCCD, MOPD_Reg16FS,MOPD_FPZeroImm8,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fcmp","1,2", 1, 2) +// MOP_hcmpqrr -- register, shifted register, AArch64 cmp has no dest operand +DEFINE_MOP(MOP_hcmpqrr, {MOPD_RegCCD, MOPD_Reg16FS,MOPD_Reg16FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fcmp","1,2", 1, 2) + +// MOP_scmpqri -- AArch64 cmp has no dest operand +DEFINE_MOP(MOP_scmpqri, {MOPD_RegCCD, MOPD_Reg32FS,MOPD_FPZeroImm8,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fcmp","1,2", 1, 2) +// MOP_scmpqrr +DEFINE_MOP(MOP_scmpqrr, {MOPD_RegCCD, MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fcmp","1,2", 1, 2) + +// MOP_dcmpqri -- AArch64 cmp has no dest operand +DEFINE_MOP(MOP_dcmpqri, {MOPD_RegCCD, MOPD_Reg64FS,MOPD_FPZeroImm8,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fcmp","1,2", 1, 2) +// MOP_dcmpqrr +DEFINE_MOP(MOP_dcmpqrr, {MOPD_RegCCD, MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fcmp","1,2", 1, 2) + +// AARCH64 Integer COMPARES +// MOP_wcmpri -- AArch64 cmp has no dest operand +DEFINE_MOP(MOP_wcmpri, {MOPD_RegCCD, MOPD_Reg32IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,kLtAlu,"cmp","1,2", 1, 2) +// MOP_wcmprr -- register, shifted register, AArch64 cmp has no dest operand +DEFINE_MOP(MOP_wcmprr, {MOPD_RegCCD, MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"cmp","1,2", 1, 2) +// MOP_xcmpri -- AArch64 cmp has no dest operand +DEFINE_MOP(MOP_xcmpri, {MOPD_RegCCD, MOPD_Reg64IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,kLtAlu,"cmp","1,2", 1, 2) +// MOP_xcmprr -- register, shifted register, AArch64 cmp has no dest operand +DEFINE_MOP(MOP_xcmprr, {MOPD_RegCCD, MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"cmp","1,2", 1, 2) + +// MOP_wccmpriic -- AArch64 cmp has no dest operand +DEFINE_MOP(MOP_wccmpriic, {MOPD_RegCCD, MOPD_Reg32IS,MOPD_Imm5,MOPD_Imm4,MOPD_Cond},0,kLtAlu,"ccmp","1,2,3,4", 1, 4) +// MOP_wccmprric -- register, shifted register, AArch64 cmp has no dest operand +DEFINE_MOP(MOP_wccmprric, {MOPD_RegCCD, MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Imm4,MOPD_Cond},0,kLtAlu,"ccmp","1,2,3,4", 1, 4) +// MOP_xccmpriic -- AArch64 cmp has no dest operand +DEFINE_MOP(MOP_xccmpriic, {MOPD_RegCCD, MOPD_Reg64IS,MOPD_Imm5,MOPD_Imm4,MOPD_Cond},0,kLtAlu,"ccmp","1,2,3,4", 1, 4) +// MOP_xccmprric -- register, shifted register, AArch64 cmp has no dest operand +DEFINE_MOP(MOP_xccmprric, {MOPD_RegCCD, MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Imm4,MOPD_Cond},0,kLtAlu,"ccmp","1,2,3,4", 1, 4) + +// MOP_wcmnri -- AArch64 cmp has no dest operand +DEFINE_MOP(MOP_wcmnri, {MOPD_RegCCD, MOPD_Reg32IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,kLtAlu,"cmn","1,2", 1, 2) +// MOP_wcmnrr -- register, shifted register, AArch64 cmp has no dest operand +DEFINE_MOP(MOP_wcmnrr, {MOPD_RegCCD, MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"cmn","1,2", 1, 2) +// MOP_xcmnri -- AArch64 cmp has no dest operand +DEFINE_MOP(MOP_xcmnri, {MOPD_RegCCD, MOPD_Reg64IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,kLtAlu,"cmn","1,2", 1, 2) +// MOP_xcmnrr -- register, shifted register, AArch64 cmp has no dest operand +DEFINE_MOP(MOP_xcmnrr, {MOPD_RegCCD, MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"cmn","1,2", 1, 2) + +// AArch64 branches +// MOP_xbr -- branch to register +DEFINE_MOP(MOP_xbr, {MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"br","0", 0, 1) +// MOP_Tbbuncond +DEFINE_MOP(MOP_xuncond, {MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"b","0", 0, 1) + +// MOP_wcbnz --- Compare and Branch on Nonzero +DEFINE_MOP(MOP_wcbnz, {MOPD_Reg32IS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"cbnz","0,1", 0, 2) +// MOP_xcbnz +DEFINE_MOP(MOP_xcbnz, {MOPD_Reg64IS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"cbnz","0,1", 0, 2) +// MOP_wcbz --- Compare and Branch on zero +DEFINE_MOP(MOP_wcbz, {MOPD_Reg32IS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"cbz","0,1", 0, 2) +// MOP_xcbz +DEFINE_MOP(MOP_xcbz, {MOPD_Reg64IS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"cbz","0,1", 0, 2) + +// MOP_wtbnz --- Test bit and Branch if Nonzero +DEFINE_MOP(MOP_wtbnz, {MOPD_Reg32IS,MOPD_Imm8,MOPD_Label,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"tbnz","0,1,2", 0, 3) +// MOP_xtbnz +DEFINE_MOP(MOP_xtbnz, {MOPD_Reg64IS,MOPD_Imm8,MOPD_Label,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"tbnz","0,1,2", 0, 3) +// MOP_wtbz --- Test bit and Branch if Zero +DEFINE_MOP(MOP_wtbz, {MOPD_Reg32IS,MOPD_Imm8,MOPD_Label,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"tbz","0,1,2", 0, 3) +// MOP_xtbz +DEFINE_MOP(MOP_xtbz, {MOPD_Reg64IS,MOPD_Imm8,MOPD_Label,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"tbz","0,1,2", 0, 3) + +// AARCH64 STORES +// MOP_wstrb -- Store Register Byte +DEFINE_MOP(MOP_wstrb, {MOPD_Reg32IS,MOPD_Mem8D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtStore1,"strb","0,1", 1, 1) +// MOP_wstrh -- Store Register Halfword +DEFINE_MOP(MOP_wstrh, {MOPD_Reg32IS,MOPD_Mem16D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtStore1,"strh","0,1", 1, 1) +// MOP_wstr -- Store Register Word +DEFINE_MOP(MOP_wstr, {MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtStore1,"str","0,1", 1, 1) +// MOP_xstr -- Store Register Double word +DEFINE_MOP(MOP_xstr, {MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtStore2,"str","0,1", 1, 1) + +// MOP_sstr -- Store Register SIMD/FP Float +DEFINE_MOP(MOP_sstr, {MOPD_Reg32FS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtStore2,"str","0,1", 1, 1) +// MOP_dstr -- Store Register SIMD/FP Double +DEFINE_MOP(MOP_dstr, {MOPD_Reg64FS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtStore3plus,"str","0,1", 1, 1) + +// MOP_vstr -- Store Register SIMD +DEFINE_MOP(MOP_vstr, {MOPD_Reg128FS,MOPD_Mem128D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtStore2,"str","0,1", 1, 1) + +// AArch64 STP. +// MOP_wstp +DEFINE_MOP(MOP_wstp, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef},ISSTORE|ISSTOREPAIR|CANTHROW,kLtStore2,"stp","0,1,2", 1, 2) +// MOP_xstp +DEFINE_MOP(MOP_xstp, {MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef},ISSTORE|ISSTOREPAIR|CANTHROW,kLtStore3plus,"stp","0,1,2", 1, 2) +// AArch64 does not define STPSW. It has no practical value. +// MOP_sstp +DEFINE_MOP(MOP_sstp, {MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef},ISSTORE|ISSTOREPAIR|CANTHROW,kLtAdvsimdMulQ,"stp","0,1,2", 1, 2) +// MOP_dstp +DEFINE_MOP(MOP_dstp, {MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef},ISSTORE|ISSTOREPAIR|CANTHROW,kLtAdvsimdMulQ,"stp","0,1,2", 1, 2) + + + +// AARCH64 Store with Release semantics +// MOP_wstlrb -- Store-Release Register Byte +DEFINE_MOP(MOP_wstlrb, {MOPD_Reg32IS,MOPD_Mem8D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"stlrb","0,1", 1, 1) +// MOP_wstlrh -- Store-Release Register Halfword +DEFINE_MOP(MOP_wstlrh, {MOPD_Reg32IS,MOPD_Mem16D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"stlrh","0,1", 1, 1) +// MOP_wstlr -- Store-Release Register Word +DEFINE_MOP(MOP_wstlr, {MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"stlr","0,1", 1, 1) +// MOP_xstlr -- Store-Release Register Double word +DEFINE_MOP(MOP_xstlr, {MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"stlr","0,1", 1, 1) + +// AARCH64 Store with LORelease semantics +// MOP_wstllrb -- Store-LORelease Register Byte +DEFINE_MOP(MOP_wstllrb, {MOPD_Reg32IS,MOPD_Mem8D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASLORELEASE|CANTHROW,kLtUndef,"stllrb","0,1", 1, 1) +// MOP_wstllrh -- Store-LORelease Register Halfword +DEFINE_MOP(MOP_wstllrh, {MOPD_Reg32IS,MOPD_Mem16D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASLORELEASE|CANTHROW,kLtUndef,"stllrh","0,1", 1, 1) +// MOP_wstllr -- Store-LORelease Register Word +DEFINE_MOP(MOP_wstllr, {MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASLORELEASE|CANTHROW,kLtUndef,"stllr","0,1", 1, 1) +// MOP_xstllr -- Store-LORelease Register Double word +DEFINE_MOP(MOP_xstllr, {MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASLORELEASE|CANTHROW,kLtUndef,"stllr","0,1", 1, 1) + +// AARCH64 Store exclusive with/without release semantics +DEFINE_MOP(MOP_wstxrb, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Mem8D, MOPD_Undef,MOPD_Undef},ISSTORE|ISATOMIC|CANTHROW,kLtUndef,"stxrb","0,1,2", 1, 2) +DEFINE_MOP(MOP_wstxrh, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Mem16D,MOPD_Undef,MOPD_Undef},ISSTORE|ISATOMIC|CANTHROW,kLtUndef,"stxrh","0,1,2", 1, 2) +DEFINE_MOP(MOP_wstxr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef},ISSTORE|ISATOMIC|CANTHROW,kLtUndef,"stxr","0,1,2", 1, 2) +DEFINE_MOP(MOP_xstxr, {MOPD_Reg32ID,MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef},ISSTORE|ISATOMIC|CANTHROW,kLtUndef,"stxr","0,1,2", 1, 2) + +DEFINE_MOP(MOP_wstlxrb,{MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Mem8D, MOPD_Undef,MOPD_Undef},ISSTORE|ISATOMIC|HASRELEASE|CANTHROW,kLtUndef,"stlxrb","0,1,2", 1, 2) +DEFINE_MOP(MOP_wstlxrh,{MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Mem16D,MOPD_Undef,MOPD_Undef},ISSTORE|ISATOMIC|HASRELEASE|CANTHROW,kLtUndef,"stlxrh","0,1,2", 1, 2) +DEFINE_MOP(MOP_wstlxr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef},ISSTORE|ISATOMIC|HASRELEASE|CANTHROW,kLtUndef,"stlxr","0,1,2", 1, 2) +DEFINE_MOP(MOP_xstlxr, {MOPD_Reg32ID,MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef},ISSTORE|ISATOMIC|HASRELEASE|CANTHROW,kLtUndef,"stlxr","0,1,2", 1, 2) + +DEFINE_MOP(MOP_wstlxp, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Mem64D,MOPD_Undef},ISSTORE|ISSTOREPAIR|ISATOMIC|HASRELEASE|CANTHROW,kLtUndef,"stlxp","0,1,2,3", 1, 3) +DEFINE_MOP(MOP_xstlxp, {MOPD_Reg32ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef},ISSTORE|ISSTOREPAIR|ISATOMIC|HASRELEASE|CANTHROW,kLtUndef,"stlxp","0,1,2,3", 1, 3) + +// Atomic add without release +// MOP_wstaddb +DEFINE_MOP(MOP_wstaddb, {MOPD_Reg32IS,MOPD_Mem8D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtUndef,"staddb","0,1", 1, 1) +// MOP_wstaddh +DEFINE_MOP(MOP_wstaddh, {MOPD_Reg32IS,MOPD_Mem16D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtUndef,"staddh","0,1", 1, 1) +// MOP_wstadd +DEFINE_MOP(MOP_wstadd, {MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtUndef,"stadd","0,1", 1, 1) +// MOP_xstadd +DEFINE_MOP(MOP_xstadd, {MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtUndef,"stadd","0,1", 1, 1) + +// Atomic add with release +// MOP_wstaddlb +DEFINE_MOP(MOP_wstaddlb, {MOPD_Reg32IS,MOPD_Mem8D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"staddlb","0,1", 1, 1) +// MOP_wstaddlh +DEFINE_MOP(MOP_wstaddlh, {MOPD_Reg32IS,MOPD_Mem16D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"staddlh","0,1", 1, 1) +// MOP_wstaddl +DEFINE_MOP(MOP_wstaddl, {MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"staddl","0,1", 1, 1) +// MOP_xstaddl +DEFINE_MOP(MOP_xstaddl, {MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"staddl","0,1", 1, 1) + +// Atomic bit clear +// MOP_wstclrb +DEFINE_MOP(MOP_wstclrb, {MOPD_Reg32IS,MOPD_Mem8D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtUndef,"stclrb","0,1", 1, 1) +// MOP_wstclrh +DEFINE_MOP(MOP_wstclrh, {MOPD_Reg32IS,MOPD_Mem16D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtUndef,"stclrh","0,1", 1, 1) +// MOP_wstclr +DEFINE_MOP(MOP_wstclr, {MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtUndef,"stclr","0,1", 1, 1) +// MOP_xstclr +DEFINE_MOP(MOP_xstclr, {MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtUndef,"stclr","0,1", 1, 1) + +// Atomic clr with release +// MOP_wstclrlb +DEFINE_MOP(MOP_wstclrlb, {MOPD_Reg32IS,MOPD_Mem8D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"stclrlb","0,1", 1, 1) +// MOP_wstclrlh +DEFINE_MOP(MOP_wstclrlh, {MOPD_Reg32IS,MOPD_Mem16D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"stclrlh","0,1", 1, 1) +// MOP_wstclrl +DEFINE_MOP(MOP_wstclrl, {MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"stclrl","0,1", 1, 1) +// MOP_xstclrl +DEFINE_MOP(MOP_xstclrl, {MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"stclrl","0,1", 1, 1) + +// Atomic XOR +// MOP_wsteorb +DEFINE_MOP(MOP_wsteorb, {MOPD_Reg32IS,MOPD_Mem8D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtUndef,"steorb","0,1", 1, 1) +// MOP_wsteorh +DEFINE_MOP(MOP_wsteorh, {MOPD_Reg32IS,MOPD_Mem16D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtUndef,"steorh","0,1", 1, 1) +// MOP_wsteor +DEFINE_MOP(MOP_wsteor, {MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtUndef,"steor","0,1", 1, 1) +// MOP_xsteor +DEFINE_MOP(MOP_xsteor, {MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtUndef,"steor","0,1", 1, 1) + +// Atomic eor with release +// MOP_wsteorlb +DEFINE_MOP(MOP_wsteorlb, {MOPD_Reg32IS,MOPD_Mem8D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"steorlb","0,1", 1, 1) +// MOP_wsteorlh +DEFINE_MOP(MOP_wsteorlh, {MOPD_Reg32IS,MOPD_Mem16D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"steorlh","0,1", 1, 1) +// MOP_wsteorl +DEFINE_MOP(MOP_wsteorl, {MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"steorl","0,1", 1, 1) +// MOP_xsteorl +DEFINE_MOP(MOP_xsteorl, {MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"steorl","0,1", 1, 1) + +// Memory barriers +// MOP_dmb_ishld +DEFINE_MOP(MOP_dmb_ishld, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef}, HASACQUIRE|ISDMB,kLtBranch, "dmb ishld", "", 0, 0) +// MOP_dmb_ishst +DEFINE_MOP(MOP_dmb_ishst, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef}, HASRELEASE|ISDMB,kLtBranch, "dmb ishst", "", 0, 0) +// MOP_dmb_ish +DEFINE_MOP(MOP_dmb_ish, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef}, HASACQUIRE|HASRELEASE|ISDMB,kLtBranch, "dmb ish", "", 0, 0) + +// MOP_clinit +// will be emit to four instructions in a row: +// adrp xd, :got:__classinfo__Ljava_2Futil_2Fconcurrent_2Fatomic_2FAtomicInteger_3B +// ldr xd, [xd,#:got_lo12:__classinfo__Ljava_2Futil_2Fconcurrent_2Fatomic_2FAtomicInteger_3B] +// ldr xd, [xd,#112] +// ldr wzr, [xd] +DEFINE_MOP(MOP_clinit, {MOPD_Reg64ID,MOPD_Literal,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISATOMIC|CANTHROW,kLtLoad1,"intrinsic_clinit","0,1", 1, 1) + +// will be emit to two instructions in a row: +// adrp xd, _PTR__cinf_Ljava_2Flang_2FSystem_3B +// ldr xd, [xd, #:lo12:_PTR__cinf_Ljava_2Flang_2FSystem_3B] +//MOP_adrp_ldr +DEFINE_MOP(MOP_adrp_ldr, {MOPD_Reg64ID, MOPD_Literal,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISATOMIC|CANTHROW,kLtLoad1,"intrinsic_adrpldr","0,1", 1, 1) + +// will be emit to two instructions in a row: +// adrp xd, label +// add xd, xd, #:lo12:label +//MOP_adrp_label +DEFINE_MOP(MOP_adrp_label, {MOPD_Reg64ID,MOPD_Imm64,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtAlu,"intrinsic_adrplabel","0,1", 1, 1) + +// ldr x17, [xs,#112] +// ldr wzr, [x17] +DEFINE_MOP(MOP_clinit_tail, {MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISATOMIC|CANTHROW,kLtLoad1,"intrinsic_clinit_tail","0", 0, 1) + + +// MOP_tail_call_opt_xbl -- branch without link (call); this is a special definition +DEFINE_MOP(MOP_tail_call_opt_xbl, {MOPD_FuncName,MOPD_LISTS,MOPD_Undef,MOPD_Undef,MOPD_Undef},CANTHROW,kLtBranch,"b","0", 0, 2) +// MOP_tail_call_opt_xblr -- branch without link (call) to register; this is a special definition +DEFINE_MOP(MOP_tail_call_opt_xblr, {MOPD_Reg64IS,MOPD_LISTS,MOPD_Undef,MOPD_Undef,MOPD_Undef},CANTHROW,kLtBranch,"br","0", 0, 2) + +// MOP_pseudo_param_def_x, +DEFINE_MOP(MOP_pseudo_param_def_x, {MOPD_Reg64ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"//MOP_pseudo_param_def","0", 1, 0) + +// MOP_pseudo_param_def_w, +DEFINE_MOP(MOP_pseudo_param_def_w, {MOPD_Reg32ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"//MOP_pseudo_param_def","0", 1, 0) + +// MOP_pseudo_param_def_d, +DEFINE_MOP(MOP_pseudo_param_def_d, {MOPD_Reg64FD,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"//MOP_pseudo_param_def","0", 1, 0) + +// MOP_pseudo_param_def_s, +DEFINE_MOP(MOP_pseudo_param_def_s, {MOPD_Reg32FD,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"//MOP_pseudo_param_def","0", 1, 0) + +// MOP_pseudo_param_store_x, +DEFINE_MOP(MOP_pseudo_param_store_x, {MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"//MOP_pseudo_param_store_x","0", 1, 0) + +// MOP_pseudo_param_store_w, +DEFINE_MOP(MOP_pseudo_param_store_w, {MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"//MOP_pseudo_param_store_w","0", 1, 0) + +// MOP_pseudo_ref_init_x, +DEFINE_MOP(MOP_pseudo_ref_init_x, {MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"//MOP_pseudo_ref_init_x","0", 1, 0) + +// MOP_pseudo_ret_int, +DEFINE_MOP(MOP_pseudo_ret_int, {MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"//MOP_pseudo_ret_int","", 0, 1) + +// MOP_pseudo_ret_float, +DEFINE_MOP(MOP_pseudo_ret_float, {MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"//MOP_pseudo_ret_float","", 0, 1) + +// When exception occurs, R0 and R1 may be defined by runtime code. +// MOP_pseudo_eh_def_x, +DEFINE_MOP(MOP_pseudo_eh_def_x, {MOPD_Reg64ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"//MOP_pseudo_eh_def_x","0", 1, 0) + +// for comments +// MOP_comment +DEFINE_MOP(MOP_comment, {MOPD_STRING,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"//","0", 0, 0) +//MOP_nop +DEFINE_MOP(MOP_nop, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtAlu,"nop","", 0, 0) + + +// A pseudo instruction that used for seperating dependence graph. +// MOP_pseudo_dependence_seperator, +DEFINE_MOP(MOP_pseudo_dependence_seperator, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"//MOP_pseudo_dependence_seperator","0", 0, 0) + + +// A pseudo instruction that used for replacing MOP_clinit_tail after clinit merge in scheduling. +// MOP_pseudo_none, +DEFINE_MOP(MOP_pseudo_none, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"//MOP_pseudo_none","0", 0, 0) + + +// end of AArch64 instructions + + + + + + + + + + +//// MOP_Tbadcrrr +//DEFINE_MOP(MOP_Tbadcrrr, {MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_RegCCS,MOPD_Undef},0,"adc","0,1,2") +//// MOP_Tbaddrri8 +//DEFINE_MOP(MOP_Tbaddrri8, {MOPD_Reg32ID,MOPD_Reg32IS, MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"add","0,1,2") +//// MOP_Tbaddrri3s +//DEFINE_MOP(MOP_Tbaddrri3s, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS, MOPD_Imm32,MOPD_Undef},0,"adds","1,2,3") +//// MOP_Tbaddri8 +//DEFINE_MOP(MOP_Tbaddri8, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"adds","") +//// MOP_Tbaddrrr +//DEFINE_MOP(MOP_Tbaddrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"add","0,1,2") +//// MOP_Tbadd64rrrs +//DEFINE_MOP(MOP_Tbadd64rrrs, {MOPD_RegCCD,MOPD_Reg64IDL,MOPD_Reg64ISL,MOPD_Reg64ISL,MOPD_Undef},0,"adds","1,2,3") +//DEFINE_MOP(MOP_Tbadd64rris, {MOPD_RegCCD,MOPD_Reg64IDL,MOPD_Reg64ISL,MOPD_Imm12,MOPD_Undef},0,"adds","1,2,3") +//// MOP_Tbaddrrlh +//DEFINE_MOP(MOP_Tbaddrrlh, {MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"add","") +//// MOP_Tbaddrrhl +//DEFINE_MOP(MOP_Tbaddrrhl, {MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"add","") +//// MOP_Tbaddrrhh +//DEFINE_MOP(MOP_Tbaddrrhh, {MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"add","") +//// MOP_Tbaddpcrel +//DEFINE_MOP(MOP_Tbaddpcrel, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"add","") +//// MOP_Tbaddsprel +//DEFINE_MOP(MOP_Tbaddsprel, {MOPD_Reg32ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"add","") +//// MOP_Tbaddspi7 +//DEFINE_MOP(MOP_Tbaddspi7, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"add","") +//// MOP_Tbandrr +//DEFINE_MOP(MOP_Tbandrr, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"ands","") +//// MOP_Tbasrrri5 +//DEFINE_MOP(MOP_Tbasrrri5, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"asrs","") +//// MOP_Tbasrsrrr +//DEFINE_MOP(MOP_Tbasrsrrr, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"asrs","1,2,3") +//// MOP_Tbbcond +//DEFINE_MOP(MOP_Tbbcond, {MOPD_RegCCS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"b!1c","") +//// MOP_Tbbicrr +//DEFINE_MOP(MOP_Tbbicrr, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"bics","") +//// MOP_Tbbkpt +//DEFINE_MOP(MOP_Tbbkpt, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"bkpt","") +//// MOP_Tbblx2 +//DEFINE_MOP(MOP_Tbblx2, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"blx_2","") +//// MOP_Tbbl1 +//DEFINE_MOP(MOP_Tbbl1, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"bl_1","") +//// MOP_Tbbl2 +//DEFINE_MOP(MOP_Tbbl2, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"bl_2","") +//// MOP_Tbblxr +//DEFINE_MOP(MOP_Tbblxr, {MOPD_Reg32IS,MOPD_LISTS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"blx","0") +//// MOP_Tbbx +//DEFINE_MOP(MOP_Tbbx, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"bx","0") +//// MOP_Tbcmnrr +//DEFINE_MOP(MOP_Tbcmnrr, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"cmn","") + +//// MOP_Tbcmpri8 TBD:Delete +//DEFINE_MOP(MOP_Tbcmpri8, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Imm32,MOPD_Undef,MOPD_Undef},0,"cmp","1,2") +//// MOP_Tbcmprr TBD:Delete +//DEFINE_MOP(MOP_Tbcmprr, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"cmp","1,2") +//// MOP_Tbcmplh TBD:Delete +//DEFINE_MOP(MOP_Tbcmplh, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"cmp","") +//// MOP_Tbcmphl TBD:Delete +//DEFINE_MOP(MOP_Tbcmphl, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"cmp","") +//// MOP_Tbcmphh TBD:Delete +//DEFINE_MOP(MOP_Tbcmphh, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"cmp","") +//// MOP_Tbeorrr +//DEFINE_MOP(MOP_Tbeorrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"eors","") +//// MOP_Tbldmia +//DEFINE_MOP(MOP_Tbldmia, {MOPD_Reg32IDS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldmia","") +//// MOP_Tbldwb +//DEFINE_MOP(MOP_Tbldwb, {MOPD_Reg32ID, MOPD_Reg32ID, MOPD_Mem32S,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","0, 2") +//// MOP_Tbld64l +//DEFINE_MOP(MOP_Tbld64l, {MOPD_Reg64IDL,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","0, 1") +//// MOP_Tbld64h +//DEFINE_MOP(MOP_Tbld64h, {MOPD_Reg64IDSH,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","0, 1") +//// MOP_Tbldrbrri5 +//DEFINE_MOP(MOP_Tbldrbrri5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrb","") +//// MOP_Tbldrhrri5 +//DEFINE_MOP(MOP_Tbldrhrri5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrh","") + + +//// MOP_Tblslrri5 +//DEFINE_MOP(MOP_Tblslrri5, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"lsls","") +//// MOP_Tblslsrrr +//DEFINE_MOP(MOP_Tblslsrrr, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"lsls","1,2,3") +//// MOP_Tblsrrri5 +//DEFINE_MOP(MOP_Tblsrrri5, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"lsrs","") +//// MOP_Tblsrsrrr +//DEFINE_MOP(MOP_Tblsrsrrr, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"lsrs","1,2,3") +//// MOP_Tbmovimm8 +//DEFINE_MOP(MOP_Tbmovimm8, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"movs","1,2") +//// MOP_Tbmovrr +//DEFINE_MOP(MOP_Tbmovrr, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISMOVE,"movs","") +//// MOP_Tbmovrr_h2h +//DEFINE_MOP(MOP_Tbmovrr_h2h, {MOPD_Reg64IDSH,MOPD_Reg64ISH,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mov","0,1") +//// MOP_Tbmovrr_l2l +//DEFINE_MOP(MOP_Tbmovrr_l2l, {MOPD_Reg64IDL,MOPD_Reg64ISL,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mov","0,1") +//// MOP_Tbmovrr_l2h +//DEFINE_MOP(MOP_Tbmovrr_l2h, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,"mov","") +//// MOP_Tbmov64ri12h +//DEFINE_MOP(MOP_Tbmov64ri12h, {MOPD_Reg64IDSH,MOPD_Imm12,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mov","0,1") +//// MOP_Tbmov64ri12l +//DEFINE_MOP(MOP_Tbmov64ri12l, {MOPD_Reg64IDL,MOPD_Imm12,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mov","0,1") +//// MOP_Tbmul +//DEFINE_MOP(MOP_Tbmul, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"muls","") +//// MOP_Tbmvn +//DEFINE_MOP(MOP_Tbmvn, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"mvns","") +//// MOP_Tbmvn64i12l +//DEFINE_MOP(MOP_Tbmvn64i12l, {MOPD_Reg64IDL,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,"mvn","0,1") +//// MOP_Tbmvn64i12h +//DEFINE_MOP(MOP_Tbmvn64i12h, {MOPD_Reg64IDSH,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,"mvn","0,1") +//// MOP_Tborr +//DEFINE_MOP(MOP_Tborr, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"orrs","") +//// MOP_Tbpop +//DEFINE_MOP(MOP_Tbpop, {MOPD_RSPD,MOPD_LISTS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"pop","1") +//// MOP_Tbpush +//DEFINE_MOP(MOP_Tbpush, {MOPD_RSPD,MOPD_LISTS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"push","1") +//// MOP_Tbrev +//DEFINE_MOP(MOP_Tbrev, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"rev","") +//// MOP_Tbrevsh +//DEFINE_MOP(MOP_Tbrevsh, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"rev","") +//// MOP_Tbrorrr +//DEFINE_MOP(MOP_Tbrorrr, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"rors","") +//// MOP_Tbsbc +//DEFINE_MOP(MOP_Tbsbc, {MOPD_RegCCDS,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"sbcs","") +//// MOP_Tbstmia +//DEFINE_MOP(MOP_Tbstmia, {MOPD_Reg32IDS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"stmia","") +//// MOP_Tbstr +//DEFINE_MOP(MOP_Tbstr, {MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"str","0,1") +//// MOP_Tbstrsprel +//DEFINE_MOP(MOP_Tbstrsprel, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"str","") +//// MOP_Tbstrbrri5 +//DEFINE_MOP(MOP_Tbstrbrri5, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strb","") +//// MOP_Tbstrhrri5 +//DEFINE_MOP(MOP_Tbstrhrri5, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strh","") +//// MOP_Tbsubrri3 +//DEFINE_MOP(MOP_Tbsubrri3, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"subs","") +//// MOP_Tbsubri8 +//DEFINE_MOP(MOP_Tbsubri8, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"subs","") +//// MOP_Tbsubspi7 +//DEFINE_MOP(MOP_Tbsubspi7, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"sub","") +//// MOP_Tbswi +//DEFINE_MOP(MOP_Tbswi, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"swi","") +//// MOP_Tbtst +//DEFINE_MOP(MOP_Tbtst, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"tst","") +//// MOP_Tb2vldrs +//DEFINE_MOP(MOP_Tb2vldrs, {MOPD_Reg32FD,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"flds","0,1") +//// MOP_Tb2vldrd +//DEFINE_MOP(MOP_Tb2vldrd, {MOPD_Reg64FD,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"fldd","0,1") +//// MOP_Tb2vmuls TBD:Delete +//DEFINE_MOP(MOP_Tb2vmuls, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,"fmuls","0,1,2") +//// MOP_Tb2vmuld TBD:Delete +//DEFINE_MOP(MOP_Tb2vmuld, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"fmuld","0,1,2") +//// MOP_Tb2vmlas TBD:Delete +//DEFINE_MOP(MOP_Tb2vmlas, {MOPD_Reg32FDS,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,"vmlas","") +//// MOP_Tb2vmlad TBD:Delete +//DEFINE_MOP(MOP_Tb2vmlad, {MOPD_Reg64FDS,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"vmlad","") +//// MOP_Tb2vmlss TBL:Delete +//DEFINE_MOP(MOP_Tb2vmlss, {MOPD_Reg32FDS,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,"vmlss","") +//// MOP_Tb2vmlsd TBD:Delete +//DEFINE_MOP(MOP_Tb2vmlsd, {MOPD_Reg64FDS,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"vmlsd","") +//// MOP_Tb2vstrs TBD:Delete +//DEFINE_MOP(MOP_Tb2vstrs, {MOPD_Reg32FS,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"fsts","0,1") +//// MOP_Tb2vstrd TBD:Delete +//DEFINE_MOP(MOP_Tb2vstrd, {MOPD_Reg64FS,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"fstd","0,1") +//// MOP_Tb2vsubs TBD:Delete +//DEFINE_MOP(MOP_Tb2vsubs, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,"fsubs","0,1,2") +//// MOP_Tb2vsubd TBD:Delete +//DEFINE_MOP(MOP_Tb2vsubd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"fsubd","0,1,2") +//// MOP_Tb2vadds TBD:Delete +//DEFINE_MOP(MOP_Tb2vadds, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,"fadds","0,1,2") +//// MOP_Tb2vaddd TBD:Delete +//DEFINE_MOP(MOP_Tb2vaddd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"faddd","0,1,2") +//// MOP_Tb2vdivs +//DEFINE_MOP(MOP_Tb2vdivs, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,"fdivs","0,1,2") +//// MOP_Tb2vdivd +//DEFINE_MOP(MOP_Tb2vdivd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"fdivd","0,1,2") +//// MOP_Tb2vmlaf64 +//DEFINE_MOP(MOP_Tb2vmlaf64, {MOPD_Reg64FDS,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"vmla","") +//// MOP_Tb2vcvtif +//DEFINE_MOP(MOP_Tb2vcvtif, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"ftosizs","0,1") +//// MOP_Tb2vcvtuf +//DEFINE_MOP(MOP_Tb2vcvtuf, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"ftouizs","0,1") +//// MOP_Tb2vcvtid +//DEFINE_MOP(MOP_Tb2vcvtid, {MOPD_Reg32FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"ftosizd","0,1") +//// MOP_Tb2vcvtud +//DEFINE_MOP(MOP_Tb2vcvtud, {MOPD_Reg32FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"ftouizd","0,1") +//// MOP_Tb2vcvtfi +//DEFINE_MOP(MOP_Tb2vcvtfi, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fsitos","0,1") +//// MOP_Tb2vcvtfu +//DEFINE_MOP(MOP_Tb2vcvtfu, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fuitos","0,1") +//// MOP_Tb2vcvtdi +//DEFINE_MOP(MOP_Tb2vcvtdi, {MOPD_Reg64FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fsitod","0,1") +//// MOP_Tb2vcvtdu +//DEFINE_MOP(MOP_Tb2vcvtdu, {MOPD_Reg64FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fuitod","0,1") +//// MOP_Tb2vcvtfd TBD:Delete +//DEFINE_MOP(MOP_Tb2vcvtfd, {MOPD_Reg32FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fcvtsd","0,1") +//// MOP_Tb2vcvtdf TBD:Delete +//DEFINE_MOP(MOP_Tb2vcvtdf, {MOPD_Reg64FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fcvtds","0,1") +//// MOP_Tb2vcvtf64s32 +//DEFINE_MOP(MOP_Tb2vcvtf64s32, {MOPD_Reg64FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"vcvt.f64.s32 ","") +//// MOP_Tb2vcvtf64u32 +//DEFINE_MOP(MOP_Tb2vcvtf64u32, {MOPD_Reg64FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"vcvt.f64.u32 ","") + +//DEFINE_MOP(MOP_Tb2movimm8, {MOPD_Reg32ID,MOPD_Imm8,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mov","0,1") +//// MOP_Tb2movi8m +//DEFINE_MOP(MOP_Tb2movi8m, {MOPD_Reg32ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mov","") +//// MOP_Tb2movimm12 +//DEFINE_MOP(MOP_Tb2movimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mov","0,1") +//// MOP_Tb2strrri12 +//DEFINE_MOP(MOP_Tb2strrri12, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"str","") +//// MOP_Tb2ldrrri12 +//DEFINE_MOP(MOP_Tb2ldrrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","") +//// MOP_Tb2strrri8predec +//DEFINE_MOP(MOP_Tb2strrri8predec, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"str","") +//// MOP_Tb2ldrrri8predec +//DEFINE_MOP(MOP_Tb2ldrrri8predec, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","") +//// MOP_Tb2cbz +//DEFINE_MOP(MOP_Tb2cbz, {MOPD_Reg32IS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"cbz","0,1") +//// MOP_Tb2addrri12 TBD:Delete +//DEFINE_MOP(MOP_Tb2addrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,"addw","0,1,2") +//// MOP_Tb2vmovs +//DEFINE_MOP(MOP_Tb2vmovs, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,"fcpys","0,1") +//// MOP_Tb2vmovd +//DEFINE_MOP(MOP_Tb2vmovd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,"fcpyd","0,1") +//// MOP_Tb2vmovsc +//DEFINE_MOP(MOP_Tb2vmovsc, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"fcpyseq","0,1") +//// MOP_Tb2vmovdc +//DEFINE_MOP(MOP_Tb2vmovdc, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"fcpydeq","0,1") +//// MOP_Tb2ldmia +//DEFINE_MOP(MOP_Tb2ldmia, {MOPD_Reg32IDS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldmia","") +//// MOP_Tb2stmia +//DEFINE_MOP(MOP_Tb2stmia, {MOPD_Reg32IDS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"stmia","") +//// MOP_Tb2addrrr +//DEFINE_MOP(MOP_Tb2addrrr, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"adds","1,2,3") +//// MOP_Tb2subrrr +//DEFINE_MOP(MOP_Tb2subrrr, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"subs","1,2,3") +//// MOP_Tb2sbcrrr +//DEFINE_MOP(MOP_Tb2sbcrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef},0,"sbc","0,1,2") +//// MOP_Tb2cmprr +//DEFINE_MOP(MOP_Tb2cmprr, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"cmp","") +//// MOP_Tb2subrri12 +//DEFINE_MOP(MOP_Tb2subrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,"sub","0,1,2") +//// MOP_Tb2mvni12 +//DEFINE_MOP(MOP_Tb2mvni12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mvn","0,1") +//// MOP_Tb2sel +//DEFINE_MOP(MOP_Tb2sel, {MOPD_RegCCS,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"sel","") +//// MOP_Tb2ubfx +//DEFINE_MOP(MOP_Tb2ubfx, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"ubfx","") +//// MOP_Tb2sbfx +//DEFINE_MOP(MOP_Tb2sbfx, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"sbfx","") +//// MOP_Tb2ldrrrr +//DEFINE_MOP(MOP_Tb2ldrrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","") +//// MOP_Tb2ldrhrrr +//DEFINE_MOP(MOP_Tb2ldrhrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrh","") +//// MOP_Tb2ldrsh +//DEFINE_MOP(MOP_Tb2ldrsh, {MOPD_Reg32ID,MOPD_Mem16S, MOPD_Undef, MOPD_Undef,MOPD_Undef},ISLOAD,"ldrsh","0,1") +//// MOP_Tb2ldrbrrr +//DEFINE_MOP(MOP_Tb2ldrbrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrb","") +//// MOP_Tb2ldrsbrrr +//DEFINE_MOP(MOP_Tb2ldrsbrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrsb","") +//// MOP_Tb2strrrr +//DEFINE_MOP(MOP_Tb2strrrr, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISSTORE,"str","") +//// MOP_Tb2strh +////{MOP_Tb2strh, {MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strh","") +//// MOP_Tb2strb +////{MOP_Tb2strb, {MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strb","0,1") +//// MOP_Tb2ldrhrri12 +//DEFINE_MOP(MOP_Tb2ldrhrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrh","") +//// MOP_Tb2ldrshrri12 +//DEFINE_MOP(MOP_Tb2ldrshrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrsh","") +//// MOP_Tb2ldrbrri12 +//DEFINE_MOP(MOP_Tb2ldrbrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrb","") +//// MOP_Tb2ldrsbrri12 +//DEFINE_MOP(MOP_Tb2ldrsbrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrsb","") +//// MOP_Tb2strhrri12 +//DEFINE_MOP(MOP_Tb2strhrri12, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strh","") +//// MOP_Tb2strbrri12 +//DEFINE_MOP(MOP_Tb2strbrri12, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strb","") +//// MOP_Tb2pop +//DEFINE_MOP(MOP_Tb2pop, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"pop","") +//// MOP_Tb2push +//DEFINE_MOP(MOP_Tb2push, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"push","") +//// MOP_Tb2cmpri8m +//DEFINE_MOP(MOP_Tb2cmpri8m, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"cmp","") +//// MOP_Tb2cmnri8m +//DEFINE_MOP(MOP_Tb2cmnri8m, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"cmn","") +//// MOP_Tb2adc64rrr +//DEFINE_MOP(MOP_Tb2adc64rrr, {MOPD_Reg64IDSH,MOPD_Reg64ISH,MOPD_Reg64ISH,MOPD_RegCCD,MOPD_Undef},0,"adc","0,1,2") +//// MOP_Tb2adc64rri +//DEFINE_MOP(MOP_Tb2adc64rri, {MOPD_Reg64IDSH,MOPD_Reg64ISH,MOPD_Imm8,MOPD_RegCCD,MOPD_Undef},0,"adc","0,1,2") +//// MOP_Tb2orr64lrrr +//DEFINE_MOP(MOP_Tb2orr64lrrr,{MOPD_Reg64ISL,MOPD_Reg64ISL,MOPD_Reg64ISL,MOPD_Undef,MOPD_Undef},0,"orr","0,1,2") +//// MOP_Tb2orr64hrrr +//DEFINE_MOP(MOP_Tb2orr64hrrr, {MOPD_Reg64IDSH,MOPD_Reg64ISH,MOPD_Reg64ISH,MOPD_Undef,MOPD_Undef},0,"orr","0,1,2") +//// MOP_Tb2and64lrrr +//DEFINE_MOP(MOP_Tb2and64lrrr,{MOPD_Reg64ISL,MOPD_Reg64ISL,MOPD_Reg64ISL,MOPD_Undef,MOPD_Undef},0,"and","0,1,2") +//// MOP_Tb2and64hrrr +//DEFINE_MOP(MOP_Tb2and64hrrr, {MOPD_Reg64IDSH,MOPD_Reg64ISH,MOPD_Reg64ISH,MOPD_Undef,MOPD_Undef},0,"and","0,1,2") +//// MOP_Tb2bicrrr +//DEFINE_MOP(MOP_Tb2bicrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"bic","") +//// MOP_Tb2cmnrr +//DEFINE_MOP(MOP_Tb2cmnrr, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"cmn","") +//// MOP_Tb2sdivrrr +//DEFINE_MOP(MOP_Tb2sdivrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"sdiv","") +//// MOP_Tb2udivrrr +//DEFINE_MOP(MOP_Tb2udivrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"udiv","") +//// MOP_Tb2rsubrri8 +//DEFINE_MOP(MOP_Tb2rsubrri8, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"rsb","0,1,2") +//// MOP_Tb2rsubsrri8 +//DEFINE_MOP(MOP_Tb2rsubsrri8, {MOPD_RegCCD, MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef},0,"rsbs","1,2,3") +//// MOP_Tb2tstrr +//DEFINE_MOP(MOP_Tb2tstrr, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"tst","") +//// MOP_Tb2rorrrr +//DEFINE_MOP(MOP_Tb2rorrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"ror","0,1,2") +//// MOP_Tb2rorrri5 +//DEFINE_MOP(MOP_Tb2rorrri5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"ror","0,1,2") +//// MOP_Tb2bicrri8m +//DEFINE_MOP(MOP_Tb2bicrri8m, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"bic","") +//// MOP_Tbandrri8 +//DEFINE_MOP(MOP_Tbandrri8, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"and","0,1,2") +//// MOP_Tbandrri8l +//DEFINE_MOP(MOP_Tbandrri8l, {MOPD_Reg64ISL,MOPD_Reg64ISL,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"and","0,1,2") +//// MOP_Tbandrri8h +//DEFINE_MOP(MOP_Tbandrri8h, {MOPD_Reg64ISH,MOPD_Reg64ISH,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"and","0,1,2") +//// MOP_Tb2andrri8m +//DEFINE_MOP(MOP_Tb2andrri8m, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"and","") +//// MOP_Tborrri8l +//DEFINE_MOP(MOP_Tborrri8l, {MOPD_Reg64ISL,MOPD_Reg64ISL,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"orr","0,1,2") +//// MOP_Tborrri8h +//DEFINE_MOP(MOP_Tborrri8h, {MOPD_Reg64ISH,MOPD_Reg64ISH,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"orr","0,1,2") +//// MOP_Tborrri8 +//DEFINE_MOP(MOP_Tborrri8, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"orr","0,1,2") +//// MOP_Tb2orrrri8m +//DEFINE_MOP(MOP_Tb2orrrri8m, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"orr","") +//// MOP_Tb2addrri8m +//DEFINE_MOP(MOP_Tb2addrri8m, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"adds","") +//// MOP_Tb2adcrri8m +//DEFINE_MOP(MOP_Tb2adcrri8m, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm12, MOPD_RegCCS,MOPD_Undef},0,"adc","0,1,2") +//// MOP_Tb2subsrri8 +//DEFINE_MOP(MOP_Tb2subsrri8, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef},0,"subs","1,2,3") +//// MOP_Tb2sbcrri8m +//DEFINE_MOP(MOP_Tb2sbcrri8m, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_RegCCS,MOPD_Undef},0,"sbc","0,1,2") +//// MOP_Tb2revrr +//DEFINE_MOP(MOP_Tb2revrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"rev","") +//// MOP_Tb2revshrr +//DEFINE_MOP(MOP_Tb2revshrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"revsh","") +//// MOP_Tb2it +//DEFINE_MOP(MOP_Tb2it, {MOPD_RegCCS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"it:!1b","") +//// MOP_Tb2fmstat +//DEFINE_MOP(MOP_Tb2fmstat, {MOPD_RegCCDS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fmstat","") +//// MOP_Tb2vcmpd +//DEFINE_MOP(MOP_Tb2vcmpd, {MOPD_RegCCD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"fcmped","1,2") +//// MOP_Tb2vcmps +//DEFINE_MOP(MOP_Tb2vcmps, {MOPD_RegCCD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,"fcmpes","1,2") +//// MOP_Tb2ldrpcrel12 +//DEFINE_MOP(MOP_Tb2ldrpcrel12, {MOPD_Reg32ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","") +//// MOP_Tb2bcond +//DEFINE_MOP(MOP_Tb2bcond, {MOPD_RegCCS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"b!1c","") +//// MOP_Tb2fmrs +//DEFINE_MOP(MOP_Tb2fmrs, {MOPD_Reg32ID,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fmrs","0,1") +//// MOP_Tb2fmsr +//DEFINE_MOP(MOP_Tb2fmsr, {MOPD_Reg32FD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fmsr","0,1") +//// MOP_Tb2fmrrd +//DEFINE_MOP(MOP_Tb2fmrrd, {MOPD_Reg32ID,MOPD_Reg32ID,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"fmrrd","0,1,2") +//// MOP_Tb2fmdrr +//DEFINE_MOP(MOP_Tb2fmdrr, {MOPD_Reg64FD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"fmdrr","0,1,2") +//// MOP_Tb2vabsd +//DEFINE_MOP(MOP_Tb2vabsd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fabsd","0,1") +//// MOP_Tb2vabss +//DEFINE_MOP(MOP_Tb2vabss, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fabss","0,1") +//// MOP_Tb2vmovs_imm8 +//DEFINE_MOP(MOP_Tb2vmovs_imm8, {MOPD_Reg32FD,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"vmov.f32","") +//// MOP_Tb2vmovd_imm8 +//DEFINE_MOP(MOP_Tb2vmovd_imm8, {MOPD_Reg64FD,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"vmov.f64","") +//// MOP_Tb2mla +//DEFINE_MOP(MOP_Tb2mla, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"mla","0,1,2,3") +//// MOP_Tb2mls +//DEFINE_MOP(MOP_Tb2mls, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"mls","") +//// MOP_Tb2umull +//DEFINE_MOP(MOP_Tb2umull, {MOPD_Reg32ID,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"umull","0,1,2,3") +//// MOP_Tb2ldrex +//DEFINE_MOP(MOP_Tb2ldrex, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrex","") +//// MOP_Tb2ldrexd +//DEFINE_MOP(MOP_Tb2ldrexd, {MOPD_Reg32ID,MOPD_Undef,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrexd","") +//// MOP_Tb2strex +//DEFINE_MOP(MOP_Tb2strex, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISSTORE,"strex","") +//// MOP_Tb2strexd +//DEFINE_MOP(MOP_Tb2strexd, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},ISSTORE,"strexd","") +//// MOP_Tb2clrex +//DEFINE_MOP(MOP_Tb2clrex, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"clrex","") +//// MOP_Tb2bfi +//DEFINE_MOP(MOP_Tb2bfi, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"bfi","") +//// MOP_Tb2bfc +//DEFINE_MOP(MOP_Tb2bfc, {MOPD_Reg32ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"bfc","") +//// MOP_Tb2dmb +//DEFINE_MOP(MOP_Tb2dmb, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"dmb","") +//// MOP_Tb2ldrpcreln12 +//DEFINE_MOP(MOP_Tb2ldrpcreln12, {MOPD_Reg32ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","") +//// MOP_Tb2stm +//DEFINE_MOP(MOP_Tb2stm, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"stm","") +//// MOP_Tbundefined +//DEFINE_MOP(MOP_Tbundefined, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"undefined","") +//// MOP_Tb2vpopcs +//DEFINE_MOP(MOP_Tb2vpopcs, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"vpop","") +//// MOP_Tb2vpushcs +//DEFINE_MOP(MOP_Tb2vpushcs, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"vpush","") +//// MOP_Tb2vldms +//DEFINE_MOP(MOP_Tb2vldms, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"vldms","") +//// MOP_Tb2vstms +//DEFINE_MOP(MOP_Tb2vstms, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"vstms","") +//// MOP_Tb2buncond +//DEFINE_MOP(MOP_Tb2buncond, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"b","") +//// MOP_Tb2movimm16h +//DEFINE_MOP(MOP_Tb2movimm16h, {MOPD_Reg32IDS,MOPD_Imm16,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"movt","0,1") +//// MOP_Tb2movimm16l +//DEFINE_MOP(MOP_Tb2movimm16l, {MOPD_Reg32ID,MOPD_Imm16,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"movw","0,1") +//// MOP_Tb2addpcr +//DEFINE_MOP(MOP_Tb2addpcr, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"add","") +//// MOP_Tb2adr +//DEFINE_MOP(MOP_Tb2adr, {MOPD_Reg32ID,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"adr","0,1") +//// MOP_Tb2movimm16lst TBD:Delete +//DEFINE_MOP(MOP_Tb2movimm16lst, {MOPD_Reg32ID,MOPD_Mem32SL,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"movw","0,1") +//// MOP_Tb2movimm16hst TBD:Delete +//DEFINE_MOP(MOP_Tb2movimm16hst, {MOPD_Reg32IDS,MOPD_Mem32SH,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"movt","0,1") +//// MOP_Tb2ldmiawb +//DEFINE_MOP(MOP_Tb2ldmiawb, {MOPD_Reg32IDS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldmia","") +//// MOP_Tb2orrsrrr +//DEFINE_MOP(MOP_Tb2orrsrrr, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"orrs","1,2,3") +//// MOP_Tb2push1 +//DEFINE_MOP(MOP_Tb2push1, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"push1","") +//// MOP_Tb2pop1 +//DEFINE_MOP(MOP_Tb2pop1, {MOPD_Reg32ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"pop1","") +//// MOP_Tb2rsubrrr +//DEFINE_MOP(MOP_Tb2rsubrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"rsb","0,1,2") +//// MOP_Tb2smull +//DEFINE_MOP(MOP_Tb2smull, {MOPD_Reg32ID,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"smull","") +//// MOP_Tb2ldrd +//DEFINE_MOP(MOP_Tb2ldrd, {MOPD_Reg64ID,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrd","0,1") +//// MOP_Tb2strd +//DEFINE_MOP(MOP_Tb2strd, {MOPD_Reg64IS,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strd","0,1") + +//// MOP_Tb2mul64rlh +//DEFINE_MOP(MOP_Tb2mul64rlh, {MOPD_Reg32ID,MOPD_Reg64ISL,MOPD_Reg64ISH,MOPD_Undef, MOPD_Undef},0,"mul","0,1,2") +//// MOP_Tb2mla64rhlr +//DEFINE_MOP(MOP_Tb2mla64rhlr, {MOPD_Reg32ID,MOPD_Reg64ISH,MOPD_Reg64ISL,MOPD_Reg32IS, MOPD_Undef},0,"mla","0,1,2,3") +//// MOP_Tb2umull64rrll +//DEFINE_MOP(MOP_Tb2umull64rrll, {MOPD_Reg32ID,MOPD_Reg32ID,MOPD_Reg64ISL, MOPD_Reg64ISL,MOPD_Undef},0,"umull","0,1,2,3") +//// MOP_Tb2mov64lr +//DEFINE_MOP(MOP_Tb2mov64lr, {MOPD_Reg64IDL,MOPD_Reg32IS, MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"mov","0,1") +//// MOP_Tb2add64hrr +//DEFINE_MOP(MOP_Tb2add64hrr, {MOPD_Reg64IDH,MOPD_Reg32IS,MOPD_Reg32IS, MOPD_Undef,MOPD_Undef},0,"add","0,1,2") +//// MOP_Tbrsbmiri +//DEFINE_MOP(MOP_Tbrsbmiri, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8, MOPD_RegCCS,MOPD_Undef},0,"rsbmi","0,1,2") +//// MOP_Tbitle +//DEFINE_MOP(MOP_Tbitle, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it le","") +//// MOP_Tbitls +//DEFINE_MOP(MOP_Tbitls, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it ls","") +//// MOP_Tbitlt +//DEFINE_MOP(MOP_Tbitlt, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it lt","") +//// MOP_Tbitcc +//DEFINE_MOP(MOP_Tbitcc, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it cc","") +//// MOP_Tbitge +//DEFINE_MOP(MOP_Tbitge, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it ge","") +//// MOP_Tbitcs +//DEFINE_MOP(MOP_Tbitcs, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it cs","") +//// MOP_Tbitgt +//DEFINE_MOP(MOP_Tbitgt, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it gt","") +//// MOP_Tbithi +//DEFINE_MOP(MOP_Tbithi, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it hi","") +//// MOP_Tbitmi +//DEFINE_MOP(MOP_Tbitmi, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it mi","") +//// MOP_Tbiteq +//DEFINE_MOP(MOP_Tbiteq, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it eq","") +//// MOP_Tbitne +//DEFINE_MOP(MOP_Tbitne, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it ne","") +//// MOP_Tbitpl +//DEFINE_MOP(MOP_Tbitpl, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it pl","") +//// MOP_Tbittpl +//DEFINE_MOP(MOP_Tbittpl, {MOPD_RegCCD,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"itt pl","") +//// MOP_Tbitele +//DEFINE_MOP(MOP_Tbitele, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite le","") +//// MOP_Tbitels +//DEFINE_MOP(MOP_Tbitels, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite ls","") +//// MOP_Tbitelt +//DEFINE_MOP(MOP_Tbitelt, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite lt","") +//// MOP_Tbitecc +//DEFINE_MOP(MOP_Tbitecc, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite cc","") +//// MOP_Tbitege +//DEFINE_MOP(MOP_Tbitege, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite ge","") +//// MOP_Tbitecs +//DEFINE_MOP(MOP_Tbitecs, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite cs","") +//// MOP_Tbitegt +//DEFINE_MOP(MOP_Tbitegt, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite gt","") +//// MOP_Tbitehi +//DEFINE_MOP(MOP_Tbitehi, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite hi","") +//// MOP_Tbitemi +//DEFINE_MOP(MOP_Tbitemi, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite mi","") +//// MOP_Tbiteeq +//DEFINE_MOP(MOP_Tbiteeq, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite eq","") +//// MOP_Tbitene +//DEFINE_MOP(MOP_Tbitene, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite ne","") +//// MOP_Tbitepl +//DEFINE_MOP(MOP_Tbitepl, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite pl","") +//// MOP_Tb2asrplrrr +//DEFINE_MOP(MOP_Tb2asrplrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_RegCCS,MOPD_Undef},0,"asrpl","0,1,2") +//// MOP_Tb2orrplrrr +//DEFINE_MOP(MOP_Tb2orrplrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_RegCCS,MOPD_Undef},0,"orrpl","0,1,2") +//// MOP_Tb2moveqimm12 +//DEFINE_MOP(MOP_Tb2moveqimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"moveq","0,1") +//// MOP_Tb2movneimm12 +//DEFINE_MOP(MOP_Tb2movneimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movne","0,1") +//// MOP_Tb2movleimm12 +//DEFINE_MOP(MOP_Tb2movleimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movle","0,1") +//// MOP_Tb2movlsimm12 +//DEFINE_MOP(MOP_Tb2movlsimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movls","0,1") +//// MOP_Tb2movltimm12 +//DEFINE_MOP(MOP_Tb2movltimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movlt","0,1") +//// MOP_Tb2movccimm12 +//DEFINE_MOP(MOP_Tb2movccimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movcc","0,1") +//// MOP_Tb2movgeimm12 +//DEFINE_MOP(MOP_Tb2movgeimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movge","0,1") +//// MOP_Tb2movcsimm12 +//DEFINE_MOP(MOP_Tb2movcsimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movcs","0,1") +//// MOP_Tb2movgtimm12 +//DEFINE_MOP(MOP_Tb2movgtimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movgt","0,1") +//// MOP_Tb2movhiimm12 +//DEFINE_MOP(MOP_Tb2movhiimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movhi","0,1") +//// MOP_Tb2movmiimm12 +//DEFINE_MOP(MOP_Tb2movmiimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movmi","0,1") +//// MOP_Tb2movplimm12 +//DEFINE_MOP(MOP_Tb2movplimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movpl","0,1") +//DEFINE_MOP(MOP_Tb2moveqrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"moveq","0,1") +//// MOP_Tb2fconsts +//DEFINE_MOP(MOP_Tb2fconsts, {MOPD_Reg32FD,MOPD_Imm8,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fconsts","0,1") +//// MOP_Tb2fconstd +//DEFINE_MOP(MOP_Tb2fconstd, {MOPD_Reg64FD,MOPD_Imm8,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fconstd","0,1") + + +//// MOP_Tbxpush AARCH64 PUSH/POP push single 32-bit int +////DEFINE_MOP(MOP_Tbxpush, {MOPD_Reg32IS,MOPD_Mem32SPRE,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"str","0,1") +//// MOP_Tbxpushl push single 64-bit int +////DEFINE_MOP(MOP_Tbxpushl, {MOPD_Reg64IS,MOPD_Mem64SPRE,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"str","0,1") +//// MOP_Tbxpushf push single 32-bit float +////DEFINE_MOP(MOP_Tbxpushf, {MOPD_Reg32FS,MOPD_Mem32SPRE,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"str","0,1") +//// MOP_Tbxpushd push single 64-bit double +////DEFINE_MOP(MOP_Tbxpushd, {MOPD_Reg64FS,MOPD_Mem64SPRE,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"str","0,1") +// +//// MOP_Tbxpushp push pair 32-bit ints +////DEFINE_MOP(MOP_Tbxpushp, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Mem32SPRE,MOPD_Undef,MOPD_Undef},ISSTORE,"stp","0,1,2") +//// MOP_Tbxpushpl push pair 64-bit ints +////DEFINE_MOP(MOP_Tbxpushpl, {MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Mem64SPRE,MOPD_Undef,MOPD_Undef},ISSTORE,"stp","0,1,2") +//// MOP_Tbxpushpf push pair 32-bit floats +////DEFINE_MOP(MOP_Tbxpushpf, {MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Mem32SPRE,MOPD_Undef,MOPD_Undef},ISSTORE,"stp","0,1,2") +//// MOP_Tbxpushpd push pair 64-bit double +////DEFINE_MOP(MOP_Tbxpushpd, {MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Mem64SPRE,MOPD_Undef,MOPD_Undef},ISSTORE,"stp","0,1,2") +// +//// MOP_Tbxpop pop single 32-bit int +////DEFINE_MOP(MOP_Tbxpop, {MOPD_Reg32IS,MOPD_Mem32SPOST,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","0,1") +//// MOP_Tbxpopl pop single 64-bit int +////DEFINE_MOP(MOP_Tbxpopl, {MOPD_Reg64IS,MOPD_Mem64SPOST,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","0,1") +//// MOP_Tbxpopf pop single 32-bit float +////DEFINE_MOP(MOP_Tbxpopf, {MOPD_Reg32FS,MOPD_Mem32SPOST,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","0,1") +//// MOP_Tbxpopd pop single 64-bit double +////DEFINE_MOP(MOP_Tbxpopd, {MOPD_Reg64FS,MOPD_Mem64SPOST,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","0,1") +// +//// MOP_Tbxpopp pop pair 32-bit ints +////DEFINE_MOP(MOP_Tbxpopp, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Mem32SPOST,MOPD_Undef,MOPD_Undef},ISLOAD,"ldp","0,1,2") +//// MOP_Tbxpoppl pop pair 64-bit ints +////DEFINE_MOP(MOP_Tbxpoppl, {MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Mem64SPOST,MOPD_Undef,MOPD_Undef},ISLOAD,"ldp","0,1,2") +//// MOP_Tbxpoppf pop pair 32-bit floats +////DEFINE_MOP(MOP_Tbxpoppf, {MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Mem32SPOST,MOPD_Undef,MOPD_Undef},ISLOAD,"ldp","0,1,2") +//// MOP_Tbxpoppd pop pair 64-bit double +////DEFINE_MOP(MOP_Tbxpoppd, {MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Mem64SPOST,MOPD_Undef,MOPD_Undef},ISLOAD,"ldp","0,1,2") + + +////// MOP_wldrmemli +////DEFINE_MOP(MOP_wldrmemli, {MOPD_Reg32ID,MOPD_Mem32LiteralS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","0,1") +//// MOP_xldrmemli +////DEFINE_MOP(MOP_xldrmemli, {MOPD_Reg64ID,MOPD_Mem64LiteralS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","0,1") + +// MOP_wstrmemli +//DEFINE_MOP(MOP_wstrmemli, {MOPD_Reg32IS,MOPD_Mem32LiteralS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"str","0,1") +// MOP_xstrmemli +////DEFINE_MOP(MOP_xstrmemli, {MOPD_Reg64IS,MOPD_Mem64LiteralS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"str","0,1") + diff --git a/mapleall/maple_be/include/cg/aarch64/aarch64_operand.h b/mapleall/maple_be/include/cg/aarch64/aarch64_operand.h index f9c5c29..1de3066 100644 --- a/mapleall/maple_be/include/cg/aarch64/aarch64_operand.h +++ b/mapleall/maple_be/include/cg/aarch64/aarch64_operand.h @@ -422,7 +422,7 @@ class StImmOperand : public Operand // representing for global variables addres } if (CGOptions::doPIC && (st_->GetStorageClass() == kScGlobal || st_->GetStorageClass() == kScExtern)) { emitter.Emit(":got:" + GetName()); - } else if (st_->storageClass == kScPstatic) { + } else if (st_->storageClass == kScPstatic && st_->sKind != kStConst && st_->IsLocal()) { emitter.Emit(GetName() + to_string(CG::curPuIdx)); } else { emitter.Emit(GetName()); diff --git a/mapleall/maple_be/include/cg/aarch64/gen_mop.pl b/mapleall/maple_be/include/cg/aarch64/gen_mop.pl deleted file mode 100644 index 2fe3776..0000000 --- a/mapleall/maple_be/include/cg/aarch64/gen_mop.pl +++ /dev/null @@ -1,34 +0,0 @@ -# -# Copyright (c) [2020] Huawei Technologies Co., Ltd. All rights reserved. -# -# Licensed under the Mulan Permissive Software License v2. -# You can use this software according to the terms and conditions of the MulanPSL - 2.0. -# You may obtain a copy of MulanPSL - 2.0 at: -# -# https://opensource.org/licenses/MulanPSL-2.0 -# -# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR -# FIT FOR A PARTICULAR PURPOSE. -# See the MulanPSL - 2.0 for more details. -# -open(my $aarch64_isa.def_h, '<', "aarch64isa.def.in") or die "can't open aarch64isa.def.in"; -open(my $aarch64_isa.def, '>', "aarch64isa.def") or die "can't open aarch64isa.def"; -print $aarch64_isa.def "\/\/Do not modify this file manually\n"; -my $insn_count=1; -while(my $line = <$aarch64_isa.def_h>) { - if ($line =~ /\/\//){ - next; - } - elsif ($line =~ /( )*MOP_/){ - $line =~ s/( )*MOP_/\#define MOP_/; - $line =~ s/,/ $insn_count/; - $insn_count++; - }else { - next; - } - print $aarch64_isa.def $line; -} -print $aarch64_isa.def "\#define kMopLast ".$insn_count."\n"; -close $aarch64_isa.def; -close $aarch64_isa.def_h; diff --git a/mapleall/maple_be/include/cg/arm/arm_md.def b/mapleall/maple_be/include/cg/arm/arm_md.def new file mode 100644 index 0000000..aa1dbe8 --- /dev/null +++ b/mapleall/maple_be/include/cg/arm/arm_md.def @@ -0,0 +1,626 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +// MOP_undef, +DEFINE_MOP(MOP_undef, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"","") +// MOP_Tbadcrrr +DEFINE_MOP(MOP_Tbadcrrr, {MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_RegCCS,MOPD_Undef},0,"adc","0,1,2") +// MOP_Tbaddrri8 +DEFINE_MOP(MOP_Tbaddrri8, {MOPD_Reg32ID,MOPD_Reg32IS, MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"add","0,1,2") +// MOP_Tbaddrri3s +DEFINE_MOP(MOP_Tbaddrri3s, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS, MOPD_Imm32,MOPD_Undef},0,"adds","1,2,3") +// MOP_Tbaddri8 +DEFINE_MOP(MOP_Tbaddri8, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"adds","") +// MOP_Tbaddrrr +DEFINE_MOP(MOP_Tbaddrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"add","0,1,2") +// MOP_Tbadd64rrrs +DEFINE_MOP(MOP_Tbadd64rrrs, {MOPD_RegCCD,MOPD_Reg64IDL,MOPD_Reg64ISL,MOPD_Reg64ISL,MOPD_Undef},0,"adds","1,2,3") +DEFINE_MOP(MOP_Tbadd64rris, {MOPD_RegCCD,MOPD_Reg64IDL,MOPD_Reg64ISL,MOPD_Imm12,MOPD_Undef},0,"adds","1,2,3") +// MOP_Tbaddrrlh +DEFINE_MOP(MOP_Tbaddrrlh, {MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"add","") +// MOP_Tbaddrrhl +DEFINE_MOP(MOP_Tbaddrrhl, {MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"add","") +// MOP_Tbaddrrhh +DEFINE_MOP(MOP_Tbaddrrhh, {MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"add","") +// MOP_Tbaddpcrel +DEFINE_MOP(MOP_Tbaddpcrel, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"add","") +// MOP_Tbaddsprel +DEFINE_MOP(MOP_Tbaddsprel, {MOPD_Reg32ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"add","") +// MOP_Tbaddspi7 +DEFINE_MOP(MOP_Tbaddspi7, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"add","") +// MOP_Tbandrr +DEFINE_MOP(MOP_Tbandrr, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"ands","") +// MOP_Tbasrrri5 +DEFINE_MOP(MOP_Tbasrrri5, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"asrs","") +// MOP_Tbasrsrrr +DEFINE_MOP(MOP_Tbasrsrrr, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"asrs","1,2,3") +// MOP_Tbbcond +DEFINE_MOP(MOP_Tbbcond, {MOPD_RegCCS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"b!1c","") +// MOP_Tbbuncond +DEFINE_MOP(MOP_Tbbuncond, {MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"b","0") +// MOP_Tbbicrr +DEFINE_MOP(MOP_Tbbicrr, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"bics","") +// MOP_Tbbkpt +DEFINE_MOP(MOP_Tbbkpt, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"bkpt","") +// MOP_Tbbl +DEFINE_MOP(MOP_Tbbl, {MOPD_Mem32S,MOPD_LISTS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCALL,"bl","0") +// MOP_Tbblx2 +DEFINE_MOP(MOP_Tbblx2, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"blx_2","") +// MOP_Tbbl1 +DEFINE_MOP(MOP_Tbbl1, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"bl_1","") +// MOP_Tbbl2 +DEFINE_MOP(MOP_Tbbl2, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"bl_2","") +// MOP_Tbblxr +DEFINE_MOP(MOP_Tbblxr, {MOPD_Reg32IS,MOPD_LISTS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"blx","0") +// MOP_Tbbx +DEFINE_MOP(MOP_Tbbx, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"bx","0") +// MOP_Tbcmnrr +DEFINE_MOP(MOP_Tbcmnrr, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"cmn","") +// MOP_Tbcmpri8 +DEFINE_MOP(MOP_Tbcmpri8, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Imm32,MOPD_Undef,MOPD_Undef},0,"cmp","1,2") +// MOP_Tbcmprr +DEFINE_MOP(MOP_Tbcmprr, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"cmp","1,2") +// MOP_Tbcmplh +DEFINE_MOP(MOP_Tbcmplh, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"cmp","") +// MOP_Tbcmphl +DEFINE_MOP(MOP_Tbcmphl, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"cmp","") +// MOP_Tbcmphh +DEFINE_MOP(MOP_Tbcmphh, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"cmp","") +// MOP_Tbeorrr +DEFINE_MOP(MOP_Tbeorrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"eors","") +// MOP_Tbldmia +DEFINE_MOP(MOP_Tbldmia, {MOPD_Reg32IDS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldmia","") +// MOP_Tbld +DEFINE_MOP(MOP_Tbld, {MOPD_Reg32ID,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","0, 1") +// MOP_Tbldwb +DEFINE_MOP(MOP_Tbldwb, {MOPD_Reg32ID, MOPD_Reg32ID, MOPD_Mem32S,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","0, 2") +// MOP_Tbld64l +DEFINE_MOP(MOP_Tbld64l, {MOPD_Reg64IDL,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","0, 1") +// MOP_Tbld64h +DEFINE_MOP(MOP_Tbld64h, {MOPD_Reg64IDSH,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","0, 1") +// MOP_Tbldrbrri5 +DEFINE_MOP(MOP_Tbldrbrri5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrb","") +// MOP_Tbldrb +DEFINE_MOP(MOP_Tbldrb, {MOPD_Reg32ID,MOPD_Mem8S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrb","0,1") +// MOP_Tbldrhrri5 +DEFINE_MOP(MOP_Tbldrhrri5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrh","") +// MOP_Tbldrh +DEFINE_MOP(MOP_Tbldrh, {MOPD_Reg32ID, MOPD_Mem16S, MOPD_Undef, MOPD_Undef,MOPD_Undef},ISLOAD,"ldrh","0,1") +// MOP_Tbldrsb +DEFINE_MOP(MOP_Tbldrsb, {MOPD_Reg32ID,MOPD_Mem8S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrsb","0,1") +// MOP_Tbldrsh +DEFINE_MOP(MOP_Tbldrsh, {MOPD_Reg32ID,MOPD_Mem16S,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrsh","0,1") +// MOP_Tblslrri5 +DEFINE_MOP(MOP_Tblslrri5, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"lsls","") +// MOP_Tblslsrrr +DEFINE_MOP(MOP_Tblslsrrr, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"lsls","1,2,3") +// MOP_Tblsrrri5 +DEFINE_MOP(MOP_Tblsrrri5, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"lsrs","") +// MOP_Tblsrsrrr +DEFINE_MOP(MOP_Tblsrsrrr, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"lsrs","1,2,3") +// MOP_Tbmovimm8 +DEFINE_MOP(MOP_Tbmovimm8, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"movs","1,2") +// MOP_Tbmovrr +DEFINE_MOP(MOP_Tbmovrr, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISMOVE,"movs","") +// MOP_Tbmovrr_h2h +DEFINE_MOP(MOP_Tbmovrr_h2h, {MOPD_Reg64IDSH,MOPD_Reg64ISH,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mov","0,1") +// MOP_Tbmovrr_l2l +DEFINE_MOP(MOP_Tbmovrr_l2l, {MOPD_Reg64IDL,MOPD_Reg64ISL,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mov","0,1") +// MOP_Tbmovrr_l2h +DEFINE_MOP(MOP_Tbmovrr_l2h, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,"mov","") +// MOP_Tbmov64ri12h +DEFINE_MOP(MOP_Tbmov64ri12h, {MOPD_Reg64IDSH,MOPD_Imm12,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mov","0,1") +// MOP_Tbmov64ri12l +DEFINE_MOP(MOP_Tbmov64ri12l, {MOPD_Reg64IDL,MOPD_Imm12,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mov","0,1") +// MOP_Tbmul +DEFINE_MOP(MOP_Tbmul, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"muls","") +// MOP_Tbmvn +DEFINE_MOP(MOP_Tbmvn, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"mvns","") +// MOP_Tbmvn64i12l +DEFINE_MOP(MOP_Tbmvn64i12l, {MOPD_Reg64IDL,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,"mvn","0,1") +// MOP_Tbmvn64i12h +DEFINE_MOP(MOP_Tbmvn64i12h, {MOPD_Reg64IDSH,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,"mvn","0,1") +// MOP_Tbneg +DEFINE_MOP(MOP_Tbneg, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"negs","") +// MOP_Tborr +DEFINE_MOP(MOP_Tborr, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"orrs","") +// MOP_Tbpop +DEFINE_MOP(MOP_Tbpop, {MOPD_RSPD,MOPD_LISTS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"pop","1") +// MOP_Tbpush +DEFINE_MOP(MOP_Tbpush, {MOPD_RSPD,MOPD_LISTS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"push","1") +// MOP_Tbrev +DEFINE_MOP(MOP_Tbrev, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"rev","") +// MOP_Tbrevsh +DEFINE_MOP(MOP_Tbrevsh, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"rev","") +// MOP_Tbrorrr +DEFINE_MOP(MOP_Tbrorrr, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"rors","") +// MOP_Tbsbc +DEFINE_MOP(MOP_Tbsbc, {MOPD_RegCCDS,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"sbcs","") +// MOP_Tbstmia +DEFINE_MOP(MOP_Tbstmia, {MOPD_Reg32IDS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"stmia","") +// MOP_Tbstr +DEFINE_MOP(MOP_Tbstr, {MOPD_Reg32IS,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"str","0,1") +// MOP_Tbstrsprel +DEFINE_MOP(MOP_Tbstrsprel, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"str","") +// MOP_Tbstrbrri5 +DEFINE_MOP(MOP_Tbstrbrri5, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strb","") +// MOP_Tbstrb +DEFINE_MOP(MOP_Tbstrb, {MOPD_Reg32IS,MOPD_Mem8S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strb","0,1") +// MOP_Tbstrhrri5 +DEFINE_MOP(MOP_Tbstrhrri5, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strh","") +// MOP_Tbstrh +DEFINE_MOP(MOP_Tbstrh, {MOPD_Reg32IS,MOPD_Mem16S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strh","0,1") +// MOP_Tbsubrri3 +DEFINE_MOP(MOP_Tbsubrri3, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"subs","") +// MOP_Tbsubri8 +DEFINE_MOP(MOP_Tbsubri8, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"subs","") +// MOP_Tbsubrrr +DEFINE_MOP(MOP_Tbsubrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"sub","0,1,2") +// MOP_Tbsubspi7 +DEFINE_MOP(MOP_Tbsubspi7, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"sub","") +// MOP_Tbswi +DEFINE_MOP(MOP_Tbswi, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"swi","") +// MOP_Tbtst +DEFINE_MOP(MOP_Tbtst, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"tst","") +// MOP_Tb2vldrs +DEFINE_MOP(MOP_Tb2vldrs, {MOPD_Reg32FD,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"flds","0,1") +// MOP_Tb2vldrd +DEFINE_MOP(MOP_Tb2vldrd, {MOPD_Reg64FD,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"fldd","0,1") +// MOP_Tb2vmuls +DEFINE_MOP(MOP_Tb2vmuls, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,"fmuls","0,1,2") +// MOP_Tb2vmuld +DEFINE_MOP(MOP_Tb2vmuld, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"fmuld","0,1,2") +// MOP_Tb2vmlas +DEFINE_MOP(MOP_Tb2vmlas, {MOPD_Reg32FDS,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,"vmlas","") +// MOP_Tb2vmlad +DEFINE_MOP(MOP_Tb2vmlad, {MOPD_Reg64FDS,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"vmlad","") +// MOP_Tb2vmlss +DEFINE_MOP(MOP_Tb2vmlss, {MOPD_Reg32FDS,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,"vmlss","") +// MOP_Tb2vmlsd +DEFINE_MOP(MOP_Tb2vmlsd, {MOPD_Reg64FDS,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"vmlsd","") +// MOP_Tb2vstrs +DEFINE_MOP(MOP_Tb2vstrs, {MOPD_Reg32FS,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"fsts","0,1") +// MOP_Tb2vstrd +DEFINE_MOP(MOP_Tb2vstrd, {MOPD_Reg64FS,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"fstd","0,1") +// MOP_Tb2vsubs +DEFINE_MOP(MOP_Tb2vsubs, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,"fsubs","0,1,2") +// MOP_Tb2vsubd +DEFINE_MOP(MOP_Tb2vsubd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"fsubd","0,1,2") +// MOP_Tb2vadds +DEFINE_MOP(MOP_Tb2vadds, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,"fadds","0,1,2") +// MOP_Tb2vaddd +DEFINE_MOP(MOP_Tb2vaddd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"faddd","0,1,2") +// MOP_Tb2vdivs +DEFINE_MOP(MOP_Tb2vdivs, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,"fdivs","0,1,2") +// MOP_Tb2vdivd +DEFINE_MOP(MOP_Tb2vdivd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"fdivd","0,1,2") +// MOP_Tb2vmlaf64 +DEFINE_MOP(MOP_Tb2vmlaf64, {MOPD_Reg64FDS,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"vmla","") +// MOP_Tb2vcvtif +DEFINE_MOP(MOP_Tb2vcvtif, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"ftosizs","0,1") +// MOP_Tb2vcvtuf +DEFINE_MOP(MOP_Tb2vcvtuf, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"ftouizs","0,1") +// MOP_Tb2vcvtid +DEFINE_MOP(MOP_Tb2vcvtid, {MOPD_Reg32FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"ftosizd","0,1") +// MOP_Tb2vcvtud +DEFINE_MOP(MOP_Tb2vcvtud, {MOPD_Reg32FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"ftouizd","0,1") +// MOP_Tb2vcvtfi +DEFINE_MOP(MOP_Tb2vcvtfi, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fsitos","0,1") +// MOP_Tb2vcvtfu +DEFINE_MOP(MOP_Tb2vcvtfu, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fuitos","0,1") +// MOP_Tb2vcvtdi +DEFINE_MOP(MOP_Tb2vcvtdi, {MOPD_Reg64FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fsitod","0,1") +// MOP_Tb2vcvtdu +DEFINE_MOP(MOP_Tb2vcvtdu, {MOPD_Reg64FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fuitod","0,1") +// MOP_Tb2vcvtfd +DEFINE_MOP(MOP_Tb2vcvtfd, {MOPD_Reg32FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fcvtsd","0,1") +// MOP_Tb2vcvtdf +DEFINE_MOP(MOP_Tb2vcvtdf, {MOPD_Reg64FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fcvtds","0,1") +// MOP_Tb2vcvtf64s32 +DEFINE_MOP(MOP_Tb2vcvtf64s32, {MOPD_Reg64FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"vcvt.f64.s32 ","") +// MOP_Tb2vcvtf64u32 +DEFINE_MOP(MOP_Tb2vcvtf64u32, {MOPD_Reg64FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"vcvt.f64.u32 ","") +// MOP_Tb2vsqrts +DEFINE_MOP(MOP_Tb2vsqrts, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fsqrts","0,1") +// MOP_Tb2vsqrtd +DEFINE_MOP(MOP_Tb2vsqrtd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fsqrtd","0,1") +DEFINE_MOP(MOP_Tb2movimm8, {MOPD_Reg32ID,MOPD_Imm8,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mov","0,1") +// MOP_Tb2movi8m +DEFINE_MOP(MOP_Tb2movi8m, {MOPD_Reg32ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mov","") +// MOP_Tb2movimm12 +DEFINE_MOP(MOP_Tb2movimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mov","0,1") +// MOP_Tb2strrri12 +DEFINE_MOP(MOP_Tb2strrri12, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"str","") +// MOP_Tb2ldrrri12 +DEFINE_MOP(MOP_Tb2ldrrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","") +// MOP_Tb2strrri8predec +DEFINE_MOP(MOP_Tb2strrri8predec, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"str","") +// MOP_Tb2ldrrri8predec +DEFINE_MOP(MOP_Tb2ldrrri8predec, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","") +// MOP_Tb2cbnz +DEFINE_MOP(MOP_Tb2cbnz, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"cbnz","") +// MOP_Tb2cbz +DEFINE_MOP(MOP_Tb2cbz, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"cbz","") +// MOP_Tb2addrri12 +DEFINE_MOP(MOP_Tb2addrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,"addw","0,1,2") +// MOP_Tb2movrr +DEFINE_MOP(MOP_Tb2movrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,"mov","0,1") +// MOP_Tb2vmovs +DEFINE_MOP(MOP_Tb2vmovs, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,"fcpys","0,1") +// MOP_Tb2vmovd +DEFINE_MOP(MOP_Tb2vmovd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,"fcpyd","0,1") +// MOP_Tb2vmovsc +DEFINE_MOP(MOP_Tb2vmovsc, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"fcpyseq","0,1") +// MOP_Tb2vmovdc +DEFINE_MOP(MOP_Tb2vmovdc, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"fcpydeq","0,1") +// MOP_Tb2ldmia +DEFINE_MOP(MOP_Tb2ldmia, {MOPD_Reg32IDS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldmia","") +// MOP_Tb2stmia +DEFINE_MOP(MOP_Tb2stmia, {MOPD_Reg32IDS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"stmia","") +// MOP_Tb2addrrr +DEFINE_MOP(MOP_Tb2addrrr, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"adds","1,2,3") +// MOP_Tb2subrrr +DEFINE_MOP(MOP_Tb2subrrr, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"subs","1,2,3") +// MOP_Tb2sbcrrr +DEFINE_MOP(MOP_Tb2sbcrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef},0,"sbc","0,1,2") +// MOP_Tb2cmprr +DEFINE_MOP(MOP_Tb2cmprr, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"cmp","") +// MOP_Tb2subrri12 +DEFINE_MOP(MOP_Tb2subrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,"sub","0,1,2") +// MOP_Tb2mvni12 +DEFINE_MOP(MOP_Tb2mvni12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mvn","0,1") +// MOP_Tb2sel +DEFINE_MOP(MOP_Tb2sel, {MOPD_RegCCS,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"sel","") +// MOP_Tb2ubfx +DEFINE_MOP(MOP_Tb2ubfx, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"ubfx","") +// MOP_Tb2sbfx +DEFINE_MOP(MOP_Tb2sbfx, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"sbfx","") +// MOP_Tb2ldrrrr +DEFINE_MOP(MOP_Tb2ldrrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","") +// MOP_Tb2ldrhrrr +DEFINE_MOP(MOP_Tb2ldrhrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrh","") +// MOP_Tb2ldrsh +DEFINE_MOP(MOP_Tb2ldrsh, {MOPD_Reg32ID,MOPD_Mem16S, MOPD_Undef, MOPD_Undef,MOPD_Undef},ISLOAD,"ldrsh","0,1") +// MOP_Tb2ldrbrrr +DEFINE_MOP(MOP_Tb2ldrbrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrb","") +// MOP_Tb2ldrsbrrr +DEFINE_MOP(MOP_Tb2ldrsbrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrsb","") +// MOP_Tb2strrrr +DEFINE_MOP(MOP_Tb2strrrr, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISSTORE,"str","") +// MOP_Tb2strh +DEFINE_MOP(MOP_Tb2strh, {MOPD_Reg32IS,MOPD_Mem16S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strh","") +// MOP_Tb2strb +DEFINE_MOP(MOP_Tb2strb, {MOPD_Reg32IS,MOPD_Mem8S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strb","0,1") +// MOP_Tb2ldrhrri12 +DEFINE_MOP(MOP_Tb2ldrhrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrh","") +// MOP_Tb2ldrshrri12 +DEFINE_MOP(MOP_Tb2ldrshrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrsh","") +// MOP_Tb2ldrbrri12 +DEFINE_MOP(MOP_Tb2ldrbrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrb","") +// MOP_Tb2ldrsbrri12 +DEFINE_MOP(MOP_Tb2ldrsbrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrsb","") +// MOP_Tb2strhrri12 +DEFINE_MOP(MOP_Tb2strhrri12, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strh","") +// MOP_Tb2strbrri12 +DEFINE_MOP(MOP_Tb2strbrri12, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strb","") +// MOP_Tb2pop +DEFINE_MOP(MOP_Tb2pop, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"pop","") +// MOP_Tb2push +DEFINE_MOP(MOP_Tb2push, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"push","") +// MOP_Tb2cmpri8m +DEFINE_MOP(MOP_Tb2cmpri8m, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"cmp","") +// MOP_Tb2cmnri8m +DEFINE_MOP(MOP_Tb2cmnri8m, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"cmn","") +// MOP_Tb2adc64rrr +DEFINE_MOP(MOP_Tb2adc64rrr, {MOPD_Reg64IDSH,MOPD_Reg64ISH,MOPD_Reg64ISH,MOPD_RegCCD,MOPD_Undef},0,"adc","0,1,2") +// MOP_Tb2adc64rri +DEFINE_MOP(MOP_Tb2adc64rri, {MOPD_Reg64IDSH,MOPD_Reg64ISH,MOPD_Imm8,MOPD_RegCCD,MOPD_Undef},0,"adc","0,1,2") +// MOP_Tb2orr64lrrr +DEFINE_MOP(MOP_Tb2orr64lrrr,{MOPD_Reg64ISL,MOPD_Reg64ISL,MOPD_Reg64ISL,MOPD_Undef,MOPD_Undef},0,"orr","0,1,2") +// MOP_Tb2orr64hrrr +DEFINE_MOP(MOP_Tb2orr64hrrr, {MOPD_Reg64IDSH,MOPD_Reg64ISH,MOPD_Reg64ISH,MOPD_Undef,MOPD_Undef},0,"orr","0,1,2") +// MOP_Tb2and64lrrr +DEFINE_MOP(MOP_Tb2and64lrrr,{MOPD_Reg64ISL,MOPD_Reg64ISL,MOPD_Reg64ISL,MOPD_Undef,MOPD_Undef},0,"and","0,1,2") +// MOP_Tb2and64hrrr +DEFINE_MOP(MOP_Tb2and64hrrr, {MOPD_Reg64IDSH,MOPD_Reg64ISH,MOPD_Reg64ISH,MOPD_Undef,MOPD_Undef},0,"and","0,1,2") +// MOP_Tb2andrrr +DEFINE_MOP(MOP_Tb2andrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"and","0,1,2") +// MOP_Tb2bicrrr +DEFINE_MOP(MOP_Tb2bicrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"bic","") +// MOP_Tb2cmnrr +DEFINE_MOP(MOP_Tb2cmnrr, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"cmn","") +// MOP_Tb2eorrrr +DEFINE_MOP(MOP_Tb2eorrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"eor","0,1,2") +// MOP_Tb2mulrrr +DEFINE_MOP(MOP_Tb2mulrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"mul","0,1,2") +// MOP_Tb2sdivrrr +DEFINE_MOP(MOP_Tb2sdivrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"sdiv","") +// MOP_Tb2udivrrr +DEFINE_MOP(MOP_Tb2udivrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"udiv","") +// MOP_Tb2mnvrr +DEFINE_MOP(MOP_Tb2mnvrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mvn","0,1") +// MOP_Tb2rsubrri8 +DEFINE_MOP(MOP_Tb2rsubrri8, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"rsb","0,1,2") +// MOP_Tb2rsubsrri8 +DEFINE_MOP(MOP_Tb2rsubsrri8, {MOPD_RegCCD, MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef},0,"rsbs","1,2,3") +// MOP_Tb2negrr +DEFINE_MOP(MOP_Tb2negrr, {MOPD_Reg32ID,MOPD_Reg32IS, MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"neg","0,1") +// MOP_Tb2orrrrr +DEFINE_MOP(MOP_Tb2orrrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"orr","0,1,2") +// MOP_Tb2tstrr +DEFINE_MOP(MOP_Tb2tstrr, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"tst","") +// MOP_Tb2lslrrr +DEFINE_MOP(MOP_Tb2lslrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"lsl","0,1,2") +// MOP_Tb2lsrrrr +DEFINE_MOP(MOP_Tb2lsrrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"lsr","0,1,2") +// MOP_Tb2asrrrr +DEFINE_MOP(MOP_Tb2asrrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"asr","0,1,2") +// MOP_Tb2rorrrr +DEFINE_MOP(MOP_Tb2rorrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"ror","0,1,2") +// MOP_Tb2lslrri5 +DEFINE_MOP(MOP_Tb2lslrri5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"lsl","0,1,2") +// MOP_Tb2lsrrri5 +DEFINE_MOP(MOP_Tb2lsrrri5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"lsr","0,1,2") +// MOP_Tb2asrrri5 +DEFINE_MOP(MOP_Tb2asrrri5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"asr","0,1,2") +// MOP_Tb2rorrri5 +DEFINE_MOP(MOP_Tb2rorrri5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"ror","0,1,2") +// MOP_Tb2bicrri8m +DEFINE_MOP(MOP_Tb2bicrri8m, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"bic","") +// MOP_Tbandrri8 +DEFINE_MOP(MOP_Tbandrri8, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"and","0,1,2") +// MOP_Tbandrri8l +DEFINE_MOP(MOP_Tbandrri8l, {MOPD_Reg64ISL,MOPD_Reg64ISL,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"and","0,1,2") +// MOP_Tbandrri8h +DEFINE_MOP(MOP_Tbandrri8h, {MOPD_Reg64ISH,MOPD_Reg64ISH,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"and","0,1,2") +// MOP_Tb2andrri8m +DEFINE_MOP(MOP_Tb2andrri8m, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"and","") +// MOP_Tborrri8l +DEFINE_MOP(MOP_Tborrri8l, {MOPD_Reg64ISL,MOPD_Reg64ISL,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"orr","0,1,2") +// MOP_Tborrri8h +DEFINE_MOP(MOP_Tborrri8h, {MOPD_Reg64ISH,MOPD_Reg64ISH,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"orr","0,1,2") +// MOP_Tborrri8 +DEFINE_MOP(MOP_Tborrri8, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"orr","0,1,2") +// MOP_Tb2orrrri8m +DEFINE_MOP(MOP_Tb2orrrri8m, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"orr","") +// MOP_Tb2eorrri8m +DEFINE_MOP(MOP_Tb2eorrri8m, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"eor","0,1,2") +// MOP_Tb2addrri8m +DEFINE_MOP(MOP_Tb2addrri8m, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"adds","") +// MOP_Tb2adcrri8m +DEFINE_MOP(MOP_Tb2adcrri8m, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm12, MOPD_RegCCS,MOPD_Undef},0,"adc","0,1,2") +// MOP_Tb2subsrri8 +DEFINE_MOP(MOP_Tb2subsrri8, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef},0,"subs","1,2,3") +// MOP_Tb2sbcrri8m +DEFINE_MOP(MOP_Tb2sbcrri8m, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_RegCCS,MOPD_Undef},0,"sbc","0,1,2") +// MOP_Tb2revrr +DEFINE_MOP(MOP_Tb2revrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"rev","") +// MOP_Tb2revshrr +DEFINE_MOP(MOP_Tb2revshrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"revsh","") +// MOP_Tb2it +DEFINE_MOP(MOP_Tb2it, {MOPD_RegCCS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"it:!1b","") +// MOP_Tb2fmstat +DEFINE_MOP(MOP_Tb2fmstat, {MOPD_RegCCDS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fmstat","") +// MOP_Tb2vcmpd +DEFINE_MOP(MOP_Tb2vcmpd, {MOPD_RegCCD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"fcmped","1,2") +// MOP_Tb2vcmps +DEFINE_MOP(MOP_Tb2vcmps, {MOPD_RegCCD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,"fcmpes","1,2") +// MOP_Tb2ldrpcrel12 +DEFINE_MOP(MOP_Tb2ldrpcrel12, {MOPD_Reg32ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","") +// MOP_Tb2bcond +DEFINE_MOP(MOP_Tb2bcond, {MOPD_RegCCS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"b!1c","") +// MOP_Tb2fmrs +DEFINE_MOP(MOP_Tb2fmrs, {MOPD_Reg32ID,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fmrs","0,1") +// MOP_Tb2fmsr +DEFINE_MOP(MOP_Tb2fmsr, {MOPD_Reg32FD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fmsr","0,1") +// MOP_Tb2fmrrd +DEFINE_MOP(MOP_Tb2fmrrd, {MOPD_Reg32ID,MOPD_Reg32ID,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"fmrrd","0,1,2") +// MOP_Tb2fmdrr +DEFINE_MOP(MOP_Tb2fmdrr, {MOPD_Reg64FD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"fmdrr","0,1,2") +// MOP_Tb2vabsd +DEFINE_MOP(MOP_Tb2vabsd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fabsd","0,1") +// MOP_Tb2vabss +DEFINE_MOP(MOP_Tb2vabss, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fabss","0,1") +// MOP_Tb2vnegd +DEFINE_MOP(MOP_Tb2vnegd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fnegd","0,1") +// MOP_Tb2vnegs +DEFINE_MOP(MOP_Tb2vnegs, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fnegs","0,1") +// MOP_Tb2vmovs_imm8 +DEFINE_MOP(MOP_Tb2vmovs_imm8, {MOPD_Reg32FD,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"vmov.f32","") +// MOP_Tb2vmovd_imm8 +DEFINE_MOP(MOP_Tb2vmovd_imm8, {MOPD_Reg64FD,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"vmov.f64","") +// MOP_Tb2mla +DEFINE_MOP(MOP_Tb2mla, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"mla","0,1,2,3") +// MOP_Tb2mls +DEFINE_MOP(MOP_Tb2mls, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"mls","") +// MOP_Tb2umull +DEFINE_MOP(MOP_Tb2umull, {MOPD_Reg32ID,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"umull","0,1,2,3") +// MOP_Tb2ldrex +DEFINE_MOP(MOP_Tb2ldrex, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrex","") +// MOP_Tb2ldrexd +DEFINE_MOP(MOP_Tb2ldrexd, {MOPD_Reg32ID,MOPD_Undef,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrexd","") +// MOP_Tb2strex +DEFINE_MOP(MOP_Tb2strex, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISSTORE,"strex","") +// MOP_Tb2strexd +DEFINE_MOP(MOP_Tb2strexd, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},ISSTORE,"strexd","") +// MOP_Tb2clrex +DEFINE_MOP(MOP_Tb2clrex, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"clrex","") +// MOP_Tb2bfi +DEFINE_MOP(MOP_Tb2bfi, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"bfi","") +// MOP_Tb2bfc +DEFINE_MOP(MOP_Tb2bfc, {MOPD_Reg32ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"bfc","") +// MOP_Tb2dmb +DEFINE_MOP(MOP_Tb2dmb, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"dmb","") +// MOP_Tb2ldrpcreln12 +DEFINE_MOP(MOP_Tb2ldrpcreln12, {MOPD_Reg32ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","") +// MOP_Tb2stm +DEFINE_MOP(MOP_Tb2stm, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"stm","") +// MOP_Tbundefined +DEFINE_MOP(MOP_Tbundefined, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"undefined","") +// MOP_Tb2vpopcs +DEFINE_MOP(MOP_Tb2vpopcs, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"vpop","") +// MOP_Tb2vpushcs +DEFINE_MOP(MOP_Tb2vpushcs, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"vpush","") +// MOP_Tb2vldms +DEFINE_MOP(MOP_Tb2vldms, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"vldms","") +// MOP_Tb2vstms +DEFINE_MOP(MOP_Tb2vstms, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"vstms","") +// MOP_Tb2buncond +DEFINE_MOP(MOP_Tb2buncond, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"b","") +// MOP_Tb2movimm16h +DEFINE_MOP(MOP_Tb2movimm16h, {MOPD_Reg32IDS,MOPD_Imm16,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"movt","0,1") +// MOP_Tb2movimm16l +DEFINE_MOP(MOP_Tb2movimm16l, {MOPD_Reg32ID,MOPD_Imm16,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"movw","0,1") +// MOP_Tb2addpcr +DEFINE_MOP(MOP_Tb2addpcr, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"add","") +// MOP_Tb2adr +DEFINE_MOP(MOP_Tb2adr, {MOPD_Reg32ID,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"adr","0,1") +// MOP_Tb2movimm16lst +DEFINE_MOP(MOP_Tb2movimm16lst, {MOPD_Reg32ID,MOPD_Mem32SL,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"movw","0,1") +// MOP_Tb2movimm16hst +DEFINE_MOP(MOP_Tb2movimm16hst, {MOPD_Reg32IDS,MOPD_Mem32SH,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"movt","0,1") +// MOP_Tb2ldmiawb +DEFINE_MOP(MOP_Tb2ldmiawb, {MOPD_Reg32IDS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldmia","") +// MOP_Tb2orrsrrr +DEFINE_MOP(MOP_Tb2orrsrrr, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"orrs","1,2,3") +// MOP_Tb2push1 +DEFINE_MOP(MOP_Tb2push1, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"push1","") +// MOP_Tb2pop1 +DEFINE_MOP(MOP_Tb2pop1, {MOPD_Reg32ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"pop1","") +// MOP_Tb2rsubrrr +DEFINE_MOP(MOP_Tb2rsubrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"rsb","0,1,2") +// MOP_Tb2smull +DEFINE_MOP(MOP_Tb2smull, {MOPD_Reg32ID,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"smull","") +// MOP_Tb2ldrd +DEFINE_MOP(MOP_Tb2ldrd, {MOPD_Reg64ID,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrd","0,1") +// MOP_Tb2strd +DEFINE_MOP(MOP_Tb2strd, {MOPD_Reg64IS,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strd","0,1") +// MOP_beq +DEFINE_MOP(MOP_beq, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"beq","1") +// MOP_bne +DEFINE_MOP(MOP_bne, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"bne","1") +// MOP_blt +DEFINE_MOP(MOP_blt, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"blt","1") +// MOP_ble +DEFINE_MOP(MOP_ble, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"ble","1") +// MOP_bgt +DEFINE_MOP(MOP_bgt, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"bgt","1") +// MOP_bge +DEFINE_MOP(MOP_bge, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"bge","1") +// MOP_blo equal to MOP_blt for unsigned comparison +DEFINE_MOP(MOP_blo, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"blo","1") +// MOP_bls equal to MOP_bls for unsigned comparison +DEFINE_MOP(MOP_bls, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"bls","1") +// MOP_bhs equal to MOP_bge for unsigned comparison +DEFINE_MOP(MOP_bhs, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"bhs","1") +// MOP_bhi equal to MOP_bgt for float comparison +DEFINE_MOP(MOP_bhi, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"bhi","1") +// MOP_bpl equal to MOP_bge for float comparison +DEFINE_MOP(MOP_bpl, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"bpl","1") +// MOP_Tb2mul64rlh +DEFINE_MOP(MOP_Tb2mul64rlh, {MOPD_Reg32ID,MOPD_Reg64ISL,MOPD_Reg64ISH,MOPD_Undef, MOPD_Undef},0,"mul","0,1,2") +// MOP_Tb2mla64rhlr +DEFINE_MOP(MOP_Tb2mla64rhlr, {MOPD_Reg32ID,MOPD_Reg64ISH,MOPD_Reg64ISL,MOPD_Reg32IS, MOPD_Undef},0,"mla","0,1,2,3") +// MOP_Tb2umull64rrll +DEFINE_MOP(MOP_Tb2umull64rrll, {MOPD_Reg32ID,MOPD_Reg32ID,MOPD_Reg64ISL, MOPD_Reg64ISL,MOPD_Undef},0,"umull","0,1,2,3") +// MOP_Tb2mov64lr +DEFINE_MOP(MOP_Tb2mov64lr, {MOPD_Reg64IDL,MOPD_Reg32IS, MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"mov","0,1") +// MOP_Tb2add64hrr +DEFINE_MOP(MOP_Tb2add64hrr, {MOPD_Reg64IDH,MOPD_Reg32IS,MOPD_Reg32IS, MOPD_Undef,MOPD_Undef},0,"add","0,1,2") +// MOP_Tbrsbmiri +DEFINE_MOP(MOP_Tbrsbmiri, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8, MOPD_RegCCS,MOPD_Undef},0,"rsbmi","0,1,2") +// MOP_Tbitle +DEFINE_MOP(MOP_Tbitle, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it le","") +// MOP_Tbitls +DEFINE_MOP(MOP_Tbitls, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it ls","") +// MOP_Tbitlt +DEFINE_MOP(MOP_Tbitlt, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it lt","") +// MOP_Tbitcc +DEFINE_MOP(MOP_Tbitcc, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it cc","") +// MOP_Tbitge +DEFINE_MOP(MOP_Tbitge, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it ge","") +// MOP_Tbitcs +DEFINE_MOP(MOP_Tbitcs, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it cs","") +// MOP_Tbitgt +DEFINE_MOP(MOP_Tbitgt, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it gt","") +// MOP_Tbithi +DEFINE_MOP(MOP_Tbithi, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it hi","") +// MOP_Tbitmi +DEFINE_MOP(MOP_Tbitmi, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it mi","") +// MOP_Tbiteq +DEFINE_MOP(MOP_Tbiteq, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it eq","") +// MOP_Tbitne +DEFINE_MOP(MOP_Tbitne, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it ne","") +// MOP_Tbitpl +DEFINE_MOP(MOP_Tbitpl, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it pl","") +// MOP_Tbittpl +DEFINE_MOP(MOP_Tbittpl, {MOPD_RegCCD,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"itt pl","") +// MOP_Tbitele +DEFINE_MOP(MOP_Tbitele, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite le","") +// MOP_Tbitels +DEFINE_MOP(MOP_Tbitels, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite ls","") +// MOP_Tbitelt +DEFINE_MOP(MOP_Tbitelt, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite lt","") +// MOP_Tbitecc +DEFINE_MOP(MOP_Tbitecc, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite cc","") +// MOP_Tbitege +DEFINE_MOP(MOP_Tbitege, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite ge","") +// MOP_Tbitecs +DEFINE_MOP(MOP_Tbitecs, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite cs","") +// MOP_Tbitegt +DEFINE_MOP(MOP_Tbitegt, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite gt","") +// MOP_Tbitehi +DEFINE_MOP(MOP_Tbitehi, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite hi","") +// MOP_Tbitemi +DEFINE_MOP(MOP_Tbitemi, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite mi","") +// MOP_Tbiteeq +DEFINE_MOP(MOP_Tbiteeq, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite eq","") +// MOP_Tbitene +DEFINE_MOP(MOP_Tbitene, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite ne","") +// MOP_Tbitepl +DEFINE_MOP(MOP_Tbitepl, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite pl","") +// MOP_Tb2asrplrrr +DEFINE_MOP(MOP_Tb2asrplrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_RegCCS,MOPD_Undef},0,"asrpl","0,1,2") +// MOP_Tb2orrplrrr +DEFINE_MOP(MOP_Tb2orrplrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_RegCCS,MOPD_Undef},0,"orrpl","0,1,2") +// MOP_Tb2moveqimm12 +DEFINE_MOP(MOP_Tb2moveqimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"moveq","0,1") +// MOP_Tb2movneimm12 +DEFINE_MOP(MOP_Tb2movneimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movne","0,1") +// MOP_Tb2movleimm12 +DEFINE_MOP(MOP_Tb2movleimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movle","0,1") +// MOP_Tb2movlsimm12 +DEFINE_MOP(MOP_Tb2movlsimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movls","0,1") +// MOP_Tb2movltimm12 +DEFINE_MOP(MOP_Tb2movltimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movlt","0,1") +// MOP_Tb2movccimm12 +DEFINE_MOP(MOP_Tb2movccimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movcc","0,1") +// MOP_Tb2movgeimm12 +DEFINE_MOP(MOP_Tb2movgeimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movge","0,1") +// MOP_Tb2movcsimm12 +DEFINE_MOP(MOP_Tb2movcsimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movcs","0,1") +// MOP_Tb2movgtimm12 +DEFINE_MOP(MOP_Tb2movgtimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movgt","0,1") +// MOP_Tb2movhiimm12 +DEFINE_MOP(MOP_Tb2movhiimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movhi","0,1") +// MOP_Tb2movmiimm12 +DEFINE_MOP(MOP_Tb2movmiimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movmi","0,1") +// MOP_Tb2movplimm12 +DEFINE_MOP(MOP_Tb2movplimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movpl","0,1") +DEFINE_MOP(MOP_Tb2moveqrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"moveq","0,1") +// MOP_Tb2fconsts +DEFINE_MOP(MOP_Tb2fconsts, {MOPD_Reg32FD,MOPD_Imm8,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fconsts","0,1") +// MOP_Tb2fconstd +DEFINE_MOP(MOP_Tb2fconstd, {MOPD_Reg64FD,MOPD_Imm8,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fconstd","0,1") diff --git a/mapleall/maple_be/include/cg/arm/gen_mop.pl b/mapleall/maple_be/include/cg/arm/gen_mop.pl deleted file mode 100644 index 7b256b1..0000000 --- a/mapleall/maple_be/include/cg/arm/gen_mop.pl +++ /dev/null @@ -1,33 +0,0 @@ -# -# Copyright (c) [2020] Huawei Technologies Co., Ltd. All rights reserved. -# -# Licensed under the Mulan Permissive Software License v2. -# You can use this software according to the terms and conditions of the MulanPSL - 2.0. -# You may obtain a copy of MulanPSL - 2.0 at: -# -# https://opensource.org/licenses/MulanPSL-2.0 -# -# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR -# FIT FOR A PARTICULAR PURPOSE. -# See the MulanPSL - 2.0 for more details. -# -open(my $armisa_def_h, '<', "armisa.def.h") or die "can't open armisa.def.h"; -open(my $armisa_def, '>', "armisa.def") or die "can't open armisa.def"; -my $insn_count=1; -while(my $line = <$armisa_def_h>) { - if ($line =~ /\/\//){ - next; - } - elsif ($line =~ /( )*MOP_/){ - $line =~ s/( )*MOP_/\#define MOP_/; - $line =~ s/,/ $insn_count/; - $insn_count++; - }else { - next; - } - print $armisa_def $line; -} -print $armisa_def "\#define kMopLast ".$insn_count."\n"; -close $armisa_def; -close $armisa_def_h; diff --git a/mapleall/maple_be/include/cg/cg.h b/mapleall/maple_be/include/cg/cg.h index d18dccc..95804c3 100644 --- a/mapleall/maple_be/include/cg/cg.h +++ b/mapleall/maple_be/include/cg/cg.h @@ -256,6 +256,8 @@ class CG { // Object map generation helper std::vector GetReferenceOffsets64(BECommon &beCommon, MIRStructType *structty); + void AddLabelDieToLabelIdxMapping(DBGDie *, LabelIdx); + }; // class CG } // namespace maplebe diff --git a/mapleall/maple_be/include/cg/cg_cfg.h b/mapleall/maple_be/include/cg/cg_cfg.h index 2c21070..87dbb22 100644 --- a/mapleall/maple_be/include/cg/cg_cfg.h +++ b/mapleall/maple_be/include/cg/cg_cfg.h @@ -78,13 +78,23 @@ class InsnVisitor { virtual bool IsCompareInsn(Insn *insn) = 0; virtual bool IsCompareAndBranchInsn(Insn *insn) = 0; virtual bool ModifyInsnOpnds(Insn *insn, Operand *src, Operand *tar) = 0; - virtual bool SyncRegs(Insn *lastMemAccessInsn, Insn *csel) = 0; + virtual bool SyncRegs(Insn *lastMemAccessInsn, Insn *csel) { + return false; + } virtual Insn *CreateCondSelectionInsn(Insn *branchInsn, MOperator originalMop, Operand *ret, Operand *srcIf, - Operand *srcElse) = 0; + Operand *srcElse) { + return nullptr; + } virtual Insn *CreateCmpInsn(Insn *condbr) = 0; - virtual Insn *BuildCondSet(Insn *branch, RegOperand *reg, bool inverse) = 0; - virtual Insn *BuildCondSel(Insn *branch, MOperator mop, RegOperand *dst, RegOperand *src1, RegOperand *src2) = 0; - virtual bool CanDoIco(Insn *insn) = 0; + virtual Insn *BuildCondSet(Insn *branch, RegOperand *reg, bool inverse) { + return nullptr; + } + virtual Insn *BuildCondSel(Insn *branch, MOperator mop, RegOperand *dst, RegOperand *src1, RegOperand *src2) { + return nullptr; + } + virtual bool CanDoIco(Insn *insn) { + return false; + } }; // class InsnVisitor; class CGCFG { @@ -173,7 +183,6 @@ class CGCFG { Insn *FindLastCmpInsn(BB *bb); Insn *FindLastDefInsn(BB *bb); - bool SyncRegs(Insn *lastMemAccessInsn, Insn *csel); Insn *BuildConditionSelectionInsn(BB *testBB, BB *ifBB, BB *elseBB); Insn *BuildCondSelForMove(BB *testBB, BB *ifBB, BB *elseBB); Insn *BuildCmpInsn(Insn *condbr); diff --git a/mapleall/maple_be/include/cg/cg_func.h b/mapleall/maple_be/include/cg/cg_func.h index d460d4c..f199482 100644 --- a/mapleall/maple_be/include/cg/cg_func.h +++ b/mapleall/maple_be/include/cg/cg_func.h @@ -38,6 +38,7 @@ /// MapleIR headers. #include "mir_parser.h" #include "mir_function.h" +#include "debug_info.h" /// Maple MP header #include "mempool_allocator.h" @@ -174,6 +175,10 @@ class CGFunc { uint32_t frequency; protected: + // debugging info + DebugInfo *dbginfo; + MapleVector dbg_callframe_locations; + int64 dbg_callframe_offset; ReachingDefinition *rd; SuperBBBuilder *sbb; @@ -245,8 +250,12 @@ class CGFunc { virtual void GenerateCleanupCodeForExtEpilog(BB *) = 0; - virtual Operand *GetOrCreateRflag() = 0; - virtual Operand *GetRflag() = 0; + virtual Operand *GetOrCreateRflag() { + return nullptr; + } + virtual Operand *GetRflag() { + return nullptr; + } virtual LabelOperand *GetOrCreateLabelOperand(LabelIdx labidx) = 0; virtual RegAllocator *NewRegAllocator(CGFunc *cgfunc, MemPool *mp, MapleAllocator *mallocator) = 0; @@ -331,6 +340,9 @@ class CGFunc { virtual void InsertJumpPad(Insn *) { return; } + virtual void ConvertJumpToRegJump(Insn *) { + return; + } // handle rc reset virtual void HandleRCCall(bool begin, MIRSymbol *retRef = nullptr) = 0; virtual void HandleRetCleanup(NaryStmtNode *retnode) = 0; @@ -624,7 +636,7 @@ class CGFunc { max_reg_count += 80; v_reg_table.resize(max_reg_count); } -#if TARGAARCH64 || TARGX86_64 +#if TARGAARCH64 || TARGX86_64 || TARGRISCV64 if (siz < 4) { siz = 4; } @@ -927,6 +939,15 @@ class CGFunc { return isAfterRegAlloc; } + // Debugging support + void SetDebugInfo(DebugInfo *di) { + dbginfo = di; + } + + void AddDIESymbolLocation(const MIRSymbol *sym, SymbolAlloc *loc); + + virtual void DBGFixCallFrameLocationOffsets(){}; + void TestSuperBBBuilder(MemPool *sbbMp); virtual RegType GetRegTyFromPrimTy(PrimType primType) { switch (primType) { diff --git a/mapleall/maple_be/include/cg/cg_option.h b/mapleall/maple_be/include/cg/cg_option.h index 0d647e6..9978b59 100644 --- a/mapleall/maple_be/include/cg/cg_option.h +++ b/mapleall/maple_be/include/cg/cg_option.h @@ -85,7 +85,7 @@ class CGOptions { function at each function entry. */ static const option_flag_t kDefaultOptions = option_flag_t( -#if TARGAARCH64 +#if TARGAARCH64 || TARGRISCV64 kDoCg | kUseFp | kGenPie | kDoColorRegAlloc #else kDoCg | kUseFp @@ -161,6 +161,7 @@ class CGOptions { static bool useRange; static bool inRange; static bool genEH; + static bool doPatchLongBranch; static bool doZeroExtend; static bool doConstFold; static bool doLiveAnalysisEh; @@ -169,11 +170,13 @@ class CGOptions { static bool doIco; static bool doStoreLoadOpt; static bool doGlobalOpt; + static bool doMultiPassColorRA; static bool doPreLsraOpt; static bool doPostLsraOpt; static bool doLocalRefSpill; static bool doLvarPathOpt; static bool doCalleeToSpill; + static bool doCallerCrossCall; static bool doStructFpInInt; static bool dumpOLog; static bool doPrePeephole; @@ -191,7 +194,6 @@ class CGOptions { static bool replaceasm; static bool printLowerIR; static bool printFunction; - static bool doSimplePrint; static unsigned int maplelinkerSuffix; std::string class_list_file; std::string ehexclusivefile; diff --git a/mapleall/maple_be/include/cg/dbg.h b/mapleall/maple_be/include/cg/dbg.h index fe2216f..c9aa3a2 100644 --- a/mapleall/maple_be/include/cg/dbg.h +++ b/mapleall/maple_be/include/cg/dbg.h @@ -17,6 +17,7 @@ #define MAPLEBE_INCLUDE_CG_DBG_H #include "insn.h" +#include "debug_info.h" #include "mempool_allocator.h" #define DWARF_VERSION 4 diff --git a/mapleall/maple_be/include/cg/ebo.h b/mapleall/maple_be/include/cg/ebo.h index c5594c1..5ebe023 100644 --- a/mapleall/maple_be/include/cg/ebo.h +++ b/mapleall/maple_be/include/cg/ebo.h @@ -283,6 +283,10 @@ class Ebo { insninfo_table[hashval] = info; } + void IncRef(OpndInfo *info, int32_t cnt) const { + info->refcount += cnt; + } + void IncRef(OpndInfo *info) const { info->refcount++; } diff --git a/mapleall/maple_be/include/cg/emit.h b/mapleall/maple_be/include/cg/emit.h index 37d95e6..7238b0b 100644 --- a/mapleall/maple_be/include/cg/emit.h +++ b/mapleall/maple_be/include/cg/emit.h @@ -25,6 +25,7 @@ /// Maple IR headers #include "mir_module.h" #include "mir_const.h" +#include "debug_info.h" #include "mempool_allocator.h" @@ -39,6 +40,12 @@ class MirGenerator; #endif +namespace maple { + +class DebugInfo; + +} + namespace maplebe { // forward declaration @@ -78,6 +85,7 @@ class Emitter { private: MOperator curr_mop; + MapleMap labdie2labidx_table; vector stringPtr; @@ -86,7 +94,8 @@ class Emitter { : cg_(cg), arraySize(0), isFlexibleArray(false), - curr_mop(UINT_MAX) { + curr_mop(UINT_MAX), + labdie2labidx_table(std::less(), cg->mirModule->memPoolAllocator.Adapter()) { out.open(asmFileName.c_str(), std::ios::trunc); MIRModule &mirModule = *cg_->mirModule; asminfo_ = mirModule.memPool->New(0, mirModule.memPool); @@ -108,6 +117,7 @@ class Emitter { curr_mop = mop; } + void EmitAsmLabel(Asmlabel al); void EmitAsmLabel(const MIRSymbol *st, Asmlabel al); void EmitFileInfo(const std::string &fileName); @@ -119,6 +129,7 @@ class Emitter { uint32 EmitPadForNextField(MIRConst *ct, uint32 byteUsed, uint32 align); void EmitAggConst(MIRConst *ct, bool newline, bool flag32); void EmitScalarConstant(MIRConst *ct, bool newline, bool flag32, bool isIndirect); + void EmitStr(const std::string& mplStr, bool emitAscii = false, bool emitNewline = false); void EmitStrConstant(MIRStrConst *ct, bool isAscci = false, bool isIndirect = false); void EmitStr16Constant(MIRStr16Const *ct); void EmitConstantTable(MIRSymbol *st, MIRConst *ct, const std::map &stridx2type); @@ -128,7 +139,6 @@ class Emitter { void EmitLiterals(std::vector> &literals, const std::map &stridx2type); void EmitFuncLayoutInfo(const MIRSymbol *layout); - void EmitSpecialChar(std::string str, size_t startPos, size_t endPos); void EmitStringPointers(); void EmitGlobalVars(std::vector> &globalvars); void EmitGlobalVar(MIRSymbol *globalvar); @@ -201,7 +211,31 @@ class Emitter { void EmitDecUnsigned(uint64 num); void EmitHexUnsigned(uint64 num); + // debug info + void FillInClassByteSize(DBGDie *die, DBGDieAttr *byteSizeAttr, DBGAbbrevEntry *diae); + void SetupDBGInfo(DebugInfo *); + void ApplyInPrefixOrder(DBGDie *die, const std::function &func); + + void AddLabelDieToLabelIdxMapping(DBGDie *, LabelIdx); + LabelIdx GetLabelIdxForLabelDie(DBGDie *); + void EmitDIHeader(); void EmitCFISectionNames(const char *const names[]); + void EmitDIFooter(); + void EmitDIHeaderFileInfo(); + void EmitDIDebugInfoSection(DebugInfo *); + void EmitDIDebugAbbrevSection(DebugInfo *); + void EmitDIDebugARangesSection(); + void EmitDIDebugRangesSection(); + void EmitDIDebugLineSection(); + void EmitDIDebugStrSection(); + + void EmitDIFormSpecification(const DBGDieAttr *attr) { + EmitDIFormSpecification(attr->dwform_); + } + + void EmitDIFormSpecification(unsigned int dwform); + + void EmitDIAttrValue(DBGDie *die, DBGDieAttr *attr, dw_at attrName, dw_tag tagName, DebugInfo *di); // GC header for primordial objects void EmitGCHeader(); diff --git a/mapleall/maple_be/include/cg/operand.h b/mapleall/maple_be/include/cg/operand.h index 9aa4c43..79dccac 100644 --- a/mapleall/maple_be/include/cg/operand.h +++ b/mapleall/maple_be/include/cg/operand.h @@ -254,13 +254,8 @@ class RegOperand : public Operand { const char *c[kRegTyLast] = { "[U]", "[I]", "[F]", "[CC]", "[X87]", "[Vra]" }; CG_ASSERT(type_ < kRegTyLast, ""); regno_t r = is_virtual ? reg_no_ : (reg_no_ - 1); - if (CGOptions::doSimplePrint) { - LogInfo::MapleLogger() << (is_virtual ? "vreg:" : " reg:") << p[type_] << r << c[type_] << "[" + LogInfo::MapleLogger() << (is_virtual ? "vreg:" : " reg:") << p[type_] << r << c[type_] << "[" << static_cast(validBitsNum) << "]"; - } else { - LogInfo::MapleLogger() << (is_virtual ? "vreg:" : " reg:") << p[type_] << r << " class: " << c[type_] << " validBitNum: [" - << static_cast(validBitsNum) << "]"; - } } virtual bool Less(Operand *right) const override { diff --git a/mapleall/maple_be/include/cg/riscv64/README b/mapleall/maple_be/include/cg/riscv64/README new file mode 100644 index 0000000..0bf1192 --- /dev/null +++ b/mapleall/maple_be/include/cg/riscv64/README @@ -0,0 +1,16 @@ +# +# Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. +# +# OpenArkCompiler is licensed under the Mulan PSL v1. +# You can use this software according to the terms and conditions of the Mulan PSL v1. +# You may obtain a copy of Mulan PSL v1 at: +# +# http://license.coscl.org.cn/MulanPSL +# +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +# FIT FOR A PARTICULAR PURPOSE. +# See the Mulan PSL v1 for more details. +# + +To add or modify a MOP, you need to change riscv64_isa.def.h, and then run "perl gen_mop.pl" to generate riscv64isa.def. You should NOT modify riscv64isa.def manually. diff --git a/mapleall/maple_be/include/cg/riscv64/riscv64_abi.h b/mapleall/maple_be/include/cg/riscv64/riscv64_abi.h new file mode 100644 index 0000000..a087fdc --- /dev/null +++ b/mapleall/maple_be/include/cg/riscv64/riscv64_abi.h @@ -0,0 +1,184 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#ifndef MAPLEBE_INCLUDE_CG_AARCH64ABI_H +#define MAPLEBE_INCLUDE_CG_AARCH64ABI_H + +#include "riscv64_isa.h" +#include "types_def.h" +#include "be_common.h" + +namespace maplebe { + +using namespace maple; + +namespace Riscv64Abi +{ +static const int32 kNumIntParmRegs = 8; +static const int32 kNumFloatParmRegs = 8; +static const int32 kNumIntReturnRegs = 2; +static const int32 kNumFloatReturnRegs = 2; +static const int32 kMaxInstrForCondBr = 4000; // approximately less than (2^12); + +constexpr static const Riscv64reg_t int_return_regs[kNumIntParmRegs] = { R10, R11 }; +constexpr static const Riscv64reg_t float_return_regs[kNumFloatParmRegs] = { V10, V11 }; +constexpr static const Riscv64reg_t int_parm_regs[kNumIntParmRegs] = { R10, R11, R12, R13, R14, R15, R16, R17 }; +constexpr static const Riscv64reg_t float_parm_regs[kNumFloatParmRegs] = { V10, V11, V12, V13, V14, V15, V16, V17 }; + +// Refer to ARM IHI 0055C_beta: Procedure Call Standard for +// ARM 64-bit Architecture. Section 5.5 +static const Riscv64reg_t kIntRetReg0 = R10; +static const Riscv64reg_t kFpRetReg0 = V10; + +// This is a temporary patch for a temporary physical register used after register allocation. +static const Riscv64reg_t kIntSpareReg = R1; +static const Riscv64reg_t kFpSpareReg = V31; + +inline bool IsCalleeSavedReg(Riscv64reg_t reg) { + return (reg >= R1 && reg <= R4) || (reg >= R8 && reg <= R9) || (reg >= R18 && reg <= R27) || + (reg >= V8 && reg <= V9) || (reg >= V18 && reg <= V27); +} + +} // namespace Riscv64Abi + +// Refer to ARM IHI 0055C_beta: Procedure Call Standard for +// ARM 64-bit Architecture. Table 1. +enum Riscv64_ArgumentClass { + kRiscv64NoClass, + kRiscv64IntegerClass, + kRiscv64FloatClass, + kRiscv64ShortVectorClass, + kRiscv64PointerClass, + kRiscv64CompositeTypeHFAClass, // Homegeneous Floating-point Aggregates + kRiscv64CompositeTypeHVAClass, // Homegeneous Short-Vector Aggregates + kRiscv64MemoryClass +}; + +// for specifying how a parameter is passed +struct PLocInfo { + Riscv64reg_t reg0; // 0 means parameter is stored on the stack + Riscv64reg_t reg1; + uint8 rsize0; // regsize occupied, 4 or 8 for agg's 1st/2nd reg + uint8 rsize1; + int32 memoffset; + int32 memsize; +}; + +/* + We use the names used in ARM IHI 0055C_beta. $ 5.4.2. + NGRN (= _int_parm_num) : Next General-purpose Register number + NSRN (= _float_parm_num): Next SIMD and Floating-point Register Number + NSAA (= _last_memoffset): Next Stacked Argument Address + NRGN : Next Return General-purpose Register number + NRFN : Next Return Floating-point Register Number + */ +// for processing an incoming or outgoing parameter list +class ParmLocator { + private: + BECommon &_be; + int32 _parm_num; // number of all types of parameters processed so far + int32 NGRN; // number of integer parameters processed so far + int32 NSRN; // number of float parameters processed so far + int32 NSAA; + int32 NRGN; // number of integer return processed so far + int32 NRFN; // number of float return processed so far + + public: + // IHI 0055C_beta $ 5.4.2 Stage A (NSAA is set to 0, meaning "relative to the current SP") + ParmLocator(BECommon &b) : _be(b), _parm_num(0), NGRN(0), NSRN(0), NSAA(0), NRGN(0), NRFN(0) {} + + virtual ~ParmLocator() {} + + // Return size of aggregate structure copy on stack. + int32 LocateNextParm(MIRType *ty, PLocInfo &ploc, bool isFirst = false, bool isvararg = false); + int32 LocateRetValue(MIRType *ty, PLocInfo &ploc); + void InitPlocInfo(PLocInfo &ploc); + + private: + inline Riscv64reg_t AllocateGPRegister() { + return (NGRN < Riscv64Abi::kNumIntParmRegs) ? Riscv64Abi::int_parm_regs[NGRN++] : kRinvalid; + } + + inline void AllocateTwoGPRegisters(PLocInfo &ploc) { + if (NGRN + 1 < Riscv64Abi::kNumIntParmRegs) { + ploc.reg0 = Riscv64Abi::int_parm_regs[NGRN++]; + ploc.reg1 = Riscv64Abi::int_parm_regs[NGRN++]; + } else { + ploc.reg0 = kRinvalid; + } + } + + inline Riscv64reg_t AllocateSIMDFPRegister() { + return (NSRN < Riscv64Abi::kNumFloatParmRegs) ? Riscv64Abi::float_parm_regs[NSRN++] : kRinvalid; + } + + inline void AllocateNSIMDFPRegisters(PLocInfo &ploc, uint32 num) { + if ((NSRN + num - 1) < Riscv64Abi::kNumFloatParmRegs) { + switch (num) { + case 1: + ploc.reg0 = Riscv64Abi::float_parm_regs[NSRN++]; + break; + case 2: + ploc.reg0 = Riscv64Abi::float_parm_regs[NSRN++]; + ploc.reg1 = Riscv64Abi::float_parm_regs[NSRN++]; + break; + default: + CHECK_FATAL(0, "AllocateNSIMDFPRegisters: unsupported"); + } + } else { + ploc.reg0 = kRinvalid; + } + } + + inline void RoundNGRNUpToNextEven() { + NGRN = static_cast((NGRN + 1) & ~static_cast(1)); + } + + inline Riscv64reg_t AllocateReturnGPRegister() { + return (NGRN < Riscv64Abi::kNumIntReturnRegs) ? Riscv64Abi::int_return_regs[NRGN++] : kRinvalid; + } + + inline Riscv64reg_t AllocateReturnFPRegister() { + return (NSRN < Riscv64Abi::kNumFloatReturnRegs) ? Riscv64Abi::float_return_regs[NRFN++] : kRinvalid; + } +}; + +// given the type of the return value, determines the return mechanism +class ReturnMechanism { + public: + uint8 regcount; // number of registers <= 2 storing the return value + // bool fake_first_parm; // whether returning in memory via fake first parameter + Riscv64reg_t reg0; // first register storing the return value + Riscv64reg_t reg1; // second register storing the return value + PrimType ptype0; // the primitive type stored in reg0 + PrimType ptype1; // the primitive type stored in reg1 + // There is no need for extra ptype, as reg2 and reg3 should be same as reg0 + + ReturnMechanism(MIRType *retty, BECommon &be); + + virtual ~ReturnMechanism() {} + + void SetupToReturnThroughMemory() { + regcount = 1; + reg0 = R8; + ptype0 = PTY_u64; + } + + void SetupSecondRetReg(MIRType *retty2); +}; + +} // namespace maplebe + +#endif // MAPLEBE_INCLUDE_CG_AARCH64ABI_H diff --git a/mapleall/maple_be/include/cg/riscv64/riscv64_cc.def b/mapleall/maple_be/include/cg/riscv64/riscv64_cc.def new file mode 100644 index 0000000..f43890e --- /dev/null +++ b/mapleall/maple_be/include/cg/riscv64/riscv64_cc.def @@ -0,0 +1,32 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +CONDCODE(EQ) // equal +CONDCODE(NE) // not equal +CONDCODE(CS) // carry set (== HS) +CONDCODE(HS) // unsigned higher or same (== CS) +CONDCODE(CC) // carry clear (== LO) +CONDCODE(LO) // Unsigned lower (== CC) +CONDCODE(MI) // Minus or negative result +CONDCODE(PL) // positive or zero result +CONDCODE(VS) // overflow +CONDCODE(VC) // no overflow +CONDCODE(HI) // unsigned higher +CONDCODE(LS) // unsigned lower or same +CONDCODE(GE) // signed greater than or equal +CONDCODE(LT) // signed less than +CONDCODE(GT) // signed greater than +CONDCODE(LE) // signed less than or equal +CONDCODE(AL) // always, this is the default. usually omitted. diff --git a/mapleall/maple_be/include/cg/riscv64/riscv64_cg.h b/mapleall/maple_be/include/cg/riscv64/riscv64_cg.h new file mode 100644 index 0000000..5eecffc --- /dev/null +++ b/mapleall/maple_be/include/cg/riscv64/riscv64_cg.h @@ -0,0 +1,151 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#ifndef MAPLEBE_INCLUDE_CG_AARCH64CG_H +#define MAPLEBE_INCLUDE_CG_AARCH64CG_H + +#include "cg.h" +#include "riscv64_cg_func.h" +#include "riscv64_live_analysis.h" +#include "riscv64_optimize_common.h" + +namespace maplebe { +#define SHORT_BR_DISTANCE (8 * 1024) +#define NEGATIVE_IMM_LOWER_LIMIT (-4096) +using namespace std; + +// Supporting classes for GCTIB merging +class GCTIBKey { + uint32_t header; + vector bitmap_words; + + public: + const uint32_t GetHeader() const { + return header; + } + + const vector GetBitmapWords() const { + return bitmap_words; + } + + GCTIBKey(uint32_t &rcHeader, vector &patternWords) : header(rcHeader), bitmap_words(patternWords) {} + virtual ~GCTIBKey() {} +}; + +class Hasher { + public: + size_t operator()(const GCTIBKey &key) const { + size_t hash = key.GetHeader(); + return hash; + } +}; + +class EqualFn { + public: + bool operator()(const GCTIBKey &t1, const GCTIBKey &t2) const { + vector t1Words = t1.GetBitmapWords(); + vector t2Words = t2.GetBitmapWords(); + + if (t1.GetHeader() != t2.GetHeader() || t1Words.size() != t2Words.size()) { + return false; + } + + for (int i = 0; i < t1Words.size(); i++) { + if (t1Words[i] != t2Words[i]) { + return false; + } + } + return true; + } +}; + +class GCTIBPattern { + int id; + string name; + GCTIBKey key; + + public: + int GetId() { + static int id = 0; + return id++; + } + + string GetName() const { + return name; + } + + void SetName(const string &ptnName) { + name = ptnName; + } + + GCTIBPattern(GCTIBKey &patternKey) : key(patternKey) { + id = GetId(); + name = GCTIB_PREFIX_STR + string("PTN_") + to_string(id); + } + virtual ~GCTIBPattern() {} +}; + +class Riscv64CG : public CG { + public: + const vector &eh_exclusive_name_vec; + const unordered_map> &cycle_pattern_map; + unordered_map key2pattern; + unordered_map sym2pattern; + + public: + explicit Riscv64CG(MIRModule *mod, const CGOptions &opts, bool runCg, const char *output, + const vector &namevec, const unordered_map> &patternMap) + : CG(mod, opts, runCg, output), eh_exclusive_name_vec(namevec), cycle_pattern_map(patternMap) {} + +#if DEBUG + explicit Riscv64CG(MIRModule *mod, const CGOptions &opts, bool run_cg, const char *output, + const vector &namevec, const unordered_map> &pattern_map, + bool cvt_locals_to_pregs) + : CG(mod, opts, run_cg, output), eh_exclusive_name_vec(namevec), cycle_pattern_map(pattern_map) {} + +#endif + + ~Riscv64CG() {} + + Insn *CreateGhostInstruction() override { + return BuildInstruction(Insn::GetMOPGhost()); + } + + CGFunc *CreateCGFunc(MIRModule *mod, MIRFunction *mirFunc, BECommon &bec, MemPool *mp, + MapleAllocator *mallocator) override { + return mp->New(mod, this, mirFunc, &bec, mp, mallocator); + } + + InsnVisitor *NewInsnModifier(CGFunc *cgfunc, MemPool *mp) override { + return mp->New(cgfunc); + } + + void GenerateObjectMaps(BECommon &becommon) override; + + bool IsExclusiveFunc(MIRFunction *) override; + + void FindOrCreateRepresentiveSym(vector &bitmapWords, uint32_t rcHeader, string name); + + string FindGCTIBPatternName(const string &name) override; + + public: + static const Riscv64MD kMd[kMopLast]; + enum { kR8List, kR16List, kR32List, kR64List, kV64List, kV128List, kRVLast}; + static const char *intRegNames[kRVLast][MAXREG]; +}; + +} // namespace maplebe + +#endif // MAPLEBE_INCLUDE_CG_AARCH64CG_H diff --git a/mapleall/maple_be/include/cg/riscv64/riscv64_cg_func.h b/mapleall/maple_be/include/cg/riscv64/riscv64_cg_func.h new file mode 100644 index 0000000..7371b48 --- /dev/null +++ b/mapleall/maple_be/include/cg/riscv64/riscv64_cg_func.h @@ -0,0 +1,826 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#ifndef MAPLEBE_INCLUDE_CG_AARCH64CGFUNC_H +#define MAPLEBE_INCLUDE_CG_AARCH64CGFUNC_H + +#include "cg_func.h" +#include "riscv64_abi.h" +#include "riscv64_operand.h" +#include "riscv64_insn.h" +#include "riscv64_mem_layout.h" +#include "riscv64_ebo.h" +#include "riscv64_live_analysis.h" +#include "riscv64_lvar.h" +#include "riscv64_reg_alloc.h" +#include "riscv64_color_ra.h" +#include "riscv64_store_load_opt.h" +#include "riscv64_global_opt.h" +#include "riscv64_reaching_definition.h" +//#include "riscv64_schedule.h" +#include "mpl_atomic.h" +#include "name_mangler.h" + +#define DWARF_SCALAR_REG_BEGIN 0 +#define DWARF_FP_REG_BEGIN 64 + +namespace maplebe { + +typedef VirtualRegNode V_RegNode; + +class Riscv64CGFunc : public CGFunc { + friend class CGFunc; + friend class DefaultO0RegAllocator; + friend class O1RegAllocator; + friend class Riscv64LinearScanRegAllocator; + friend class LSRALinearScanRegAllocator; + friend class GraphColorRegAllocator; + + private: + MapleMap vir_reg_operand_table; // virtual regnos to virtual register operands map + MapleMap phy_reg_operand_table; // machine register operand table + MapleMap hash_lblopnd_tb_; + MapleMap hash_ofstopnd_tb_; + MapleMap hash_memopnd_tb_; + // Local variables, formal parameters that are passed via registers + // need offset adjustment after callee-saved registers are known. + MapleMap memopnds_requiring_offset_adjustment_; + MapleMap memopnds_for_stkpassed_arguments; + MapleMap immopnds_requiring_offset_adjustment_; + MapleMap immopnds_requiring_offset_adjustment_for_stkarg_; + MapleMap immopnds_requiring_offset_adjustment_for_refloc_; + MapleMap callnativemap; + union { + regno_t regno_javaCatch; // For O2. + Operand *opnd_javaCatch; // For O0-O1. + } ujavaCatch; + enum fpParamState { + kNotFp, + kIsFp32bit, + kIsFp64bit, + kStateUnknown, + }; + Operand *rcc_; + Operand *vary_; + Operand *fsp_; // used to point the address of local variables and formal parameters + + int32 current_cfa_; + int32 mark_cfa_; + int num_intreg_to_callee_save; + int num_fpreg_to_callee_save; + bool fprl_added_to_callee_saved; + bool used_stp_sub_pair_to_allocate_call_frame; + bool isLibcore; + int split_stpldp_base_offset; + regno_t method_handle_vreg; + + MIRSymbol *reflect_strtab_sym; + MIRSymbol *reflect_start_hot_strtab_sym; + MIRSymbol *reflect_both_hot_strtab_sym; + MIRSymbol *reflect_run_hot_strtab_sym; + + public: + MapleVector callee_saved_regs; + MapleVector formal_reg_list_; // store the parameters register used by this function + MapleSet gen_memopnds_requiring_offset_adjustment_; + // some caller-saved registers. + unsigned int refCount; // Ref count number. 0 if function don't have "bl MCC_InitializeLocalStackRef" + int beginOffset; // Begin offset based x29. + Insn *yieldPointInsn; // The insn of yield point at the entry of the func. + + static const uint32 kParmMemcpySize = 40; + + private: + MOperator PickStInsn(uint32 bitsize, PrimType rtype, Riscv64isa::memory_ordering_t mo = Riscv64isa::kMoNone); + MOperator PickLdInsn(uint32 bitsize, PrimType rtype, Riscv64isa::memory_ordering_t mo = Riscv64isa::kMoNone); + + void SelectLoadAcquire(Operand *dest, PrimType dtype, Operand *src, PrimType stype, Riscv64isa::memory_ordering_t mo, + bool isDirect); + void SelectStoreRelease(Operand *dest, PrimType dtype, Operand *src, PrimType stype, Riscv64isa::memory_ordering_t mo, + bool isDirect); + + MOperator PickAddInsn(PrimType, bool); + MOperator PickMpyInsn(PrimType, bool); + MOperator PickVecDup(PrimType); + void PickCmovInsn(Opcode, PrimType, MOperator &, MOperator &, bool isels = false); + MOperator PickJmpInsn(Opcode brop, Opcode cmpop, bool isfloat, bool issigned, bool isZero = false); + void SelectSubI64(Operand *resopnd, Operand *opnd0, Operand *opnd1, PrimType prmtype); + bool IsInEpilogBB(BB *bb); + Operand *GetZeroOpnd(uint32_t size) override; + bool IsFrameReg(RegOperand *opnd) override; + + inline PrimType GetOperandType(bool isIntty, uint32 dsize, bool isSigned) { + CG_ASSERT(dsize <= 64, "shouldn't be here"); + CG_ASSERT(!isSigned || isIntty, ""); + return (isIntty ? (dsize == 64 ? (isSigned ? PTY_i64 : PTY_u64) : (isSigned ? PTY_i32 : PTY_u32)) + : (dsize == 64 ? PTY_f64 : PTY_f32)); + } + + inline RegOperand *LoadIntoRegister(Operand *o, bool isIntty, uint32 dsize, bool asSigned = false) { + return LoadIntoRegister(o, GetOperandType(isIntty, dsize, asSigned)); + } + + inline RegOperand *LoadIntoRegister(Operand *o, PrimType oty) { + return (o->IsRegister() ? static_cast(o) : SelectCopy(o, oty, oty)); + } + + Riscv64MemOperand *CreateReplacementMemOperand(Riscv64MemOperand *mo, uint32 bitlen, RegOperand *basereg, + int32 offset); + + Riscv64MemOperand *SplitOffsetWithAddInstruction(Riscv64MemOperand *mo, uint32 bitlen, + Riscv64reg_t baseReg = Riscv64reg_t::kRinvalid, + Insn *insn = nullptr, bool isDest = false); + Riscv64MemOperand *SplitStpLdpOffsetForCalleeSavedWithAddInstruction(Riscv64MemOperand *mo, uint32 bitlen, + Riscv64reg_t baseReg = Riscv64reg_t::kRinvalid); + + void CreateCallStructParamFieldPassByStack(int32 symSize, MIRSymbol *sym, uint32 symOffset, RegOperand *addropnd, int32 baseOffset); + void CreateCallStructParamPassByStack(int32 symSize, MIRSymbol *sym, RegOperand *addropnd, int32 baseOffset); + Riscv64RegOperand *GenUnalignedSymCallStructParam(Riscv64reg_t reg, MIRSymbol *sym, uint32 memOffset, PrimType pty, RegOperand *addropnd); + void CreateCallStructParamPassByReg(Riscv64reg_t reg, MemOperand *mopnd, Riscv64ListOperand *srcopnds, CSR_call_info_t &ci, MIRSymbol *sym, int32 offset, fpParamState state, RegOperand *addropnd = nullptr); + RegOperand *CreateCallStructParamMemcpy(MIRSymbol *sym, RegOperand *addropnd, uint32 structSize, int32 copyOffset, int32 fromOffset); + Riscv64RegOperand *CreateCallStructParamCopyToStack(uint32 numMemOp, MIRSymbol *sym, RegOperand *addropnd, int32 copyOffset, int32 fromOffset, PLocInfo *ploc); + void SelectParmList(StmtNode *narynode, Riscv64ListOperand *srcopnds, CSR_call_info_t &ci, bool iscallnative = false); + + Operand *SelectIgoto(Operand *opnd0) override; + void SelectCondGoto(LabelOperand *targetopnd, Opcode jmpop, Opcode cmpop, Operand *opnd0, Operand *opnd1, + PrimType primType, bool signedCond); + + void EmitRiscv64Insn(Insn *insn); + void EmitCfiInsn(Insn *insn); + + std::string GetReflectString(uint32_t offset); + + public: + explicit Riscv64CGFunc(MIRModule *mod, CG *c, MIRFunction *f, BECommon *b, MemPool *mp, MapleAllocator *mallocator) + : CGFunc(mod, c, f, b, mp, mallocator), + vir_reg_operand_table(std::less(), mallocator->Adapter()), + phy_reg_operand_table(std::less(), mallocator->Adapter()), + hash_lblopnd_tb_(std::less(), mallocator->Adapter()), + hash_ofstopnd_tb_(std::less(), mallocator->Adapter()), + hash_memopnd_tb_(std::less(), mallocator->Adapter()), + memopnds_requiring_offset_adjustment_(std::less(), mallocator->Adapter()), + memopnds_for_stkpassed_arguments(std::less(), mallocator->Adapter()), + immopnds_requiring_offset_adjustment_(std::less(), mallocator->Adapter()), + immopnds_requiring_offset_adjustment_for_stkarg_(std::less(), mallocator->Adapter()), + immopnds_requiring_offset_adjustment_for_refloc_(std::less(), mallocator->Adapter()), + callnativemap(std::less(), mallocator->Adapter()), + rcc_(nullptr), + vary_(nullptr), + fsp_(nullptr), + num_intreg_to_callee_save(0), + num_fpreg_to_callee_save(0), + fprl_added_to_callee_saved(false), + used_stp_sub_pair_to_allocate_call_frame(false), + split_stpldp_base_offset(0), + method_handle_vreg(-1), + callee_saved_regs(mallocator->Adapter()), + formal_reg_list_(mallocator->Adapter()), + gen_memopnds_requiring_offset_adjustment_(mallocator->Adapter()), + refCount(0), + beginOffset(0), + yieldPointInsn(nullptr) { + ujavaCatch.regno_javaCatch = 0; + current_cfa_ = 0; + mark_cfa_ = -1; + + CGFunc::memlayout = mp->New(b, f, mallocator); + CGFunc::memlayout->SetCurrFunction(this); + + isLibcore = + (GlobalTables::GetGsymTable().GetSymbolFromStrIdx(GlobalTables::GetStrTable().GetStrIdxFromName(NameMangler::GetInternalNameLiteral(NameMangler::kJavaLangObjectStr))) != nullptr); + + if (func->module->IsJavaModule()) { + reflect_strtab_sym = GlobalTables::GetGsymTable().GetSymbolFromStrIdx(GlobalTables::GetStrTable().GetStrIdxFromName(NameMangler::kReflectionStrtabPrefixStr + func->module->GetFileNameAsPostfix())); + reflect_start_hot_strtab_sym = GlobalTables::GetGsymTable().GetSymbolFromStrIdx(GlobalTables::GetStrTable().GetStrIdxFromName(NameMangler::kReflectionStartHotStrtabPrefixStr + + func->module->GetFileNameAsPostfix())); + reflect_both_hot_strtab_sym = + GlobalTables::GetGsymTable().GetSymbolFromStrIdx(GlobalTables::GetStrTable().GetStrIdxFromName(NameMangler::kReflectionBothHotStrTabPrefixStr + func->module->GetFileNameAsPostfix())); + reflect_run_hot_strtab_sym = + GlobalTables::GetGsymTable().GetSymbolFromStrIdx(GlobalTables::GetStrTable().GetStrIdxFromName(NameMangler::kReflectionRunHotStrtabPrefixStr + func->module->GetFileNameAsPostfix())); + } else { + reflect_strtab_sym = nullptr; + reflect_start_hot_strtab_sym = nullptr; + reflect_both_hot_strtab_sym = nullptr; + reflect_run_hot_strtab_sym = nullptr; + } + } + + ~Riscv64CGFunc() {} + + MOperator PickMovInsn(PrimType primtype); + MOperator PickMovInsn(RegOperand *, RegOperand *); + Ebo *NewEbo(CGFunc *cgfunc, MemPool *mp, LiveAnalysis *live, bool beforeRegalloc, const char *phase) override { + return mp->New(cgfunc, mp, live, beforeRegalloc, phase); + } + + StoreLoadOpt *NewStoreLoadOpt(CGFunc *cgfunc, MemPool *mp, ReachingDefinition *rd) override { + return mp->New(cgfunc, mp, rd); + } + + GlobalOpt *NewGlobalOpt(CGFunc *cgfunc, MemPool *mp) override { + return mp->New(cgfunc, mp); + } + + LiveAnalysis *NewLiveAnalysis(CGFunc *cgfunc, MemPool *mp) override { + return mp->New(cgfunc, mp); + } + + OptLocalRef *NewOptLocalRef(CGFunc *cgfunc, MemPool *mp) override { + return mp->New(cgfunc, mp); + } + + ReachingDefinition *NewReachingDefinition(CGFunc *cgfunc, MemPool *mp, MapleAllocator ma, + LiveAnalysis *live) override { + return mp->New(cgfunc, mp, ma, live); + } + + Schedule *NewSchedule(CGFunc *cgfunc, MemPool* mp, LiveAnalysis *live, const char *phaseName) override; + + RegAllocator *NewRegAllocator(CGFunc *cgfunc, MemPool *mp, MapleAllocator *mallocator) override { + if (g->optim_level == 0) { + return mp->New(cgfunc, mallocator); + } else if (g->optim_level == 1) { + return mp->New(cgfunc, mallocator); + } else { + if (cg->cgopt_.DoLinearScanRegisterAllocation()) { + return mp->New(cgfunc, mallocator); + } else if (cg->cgopt_.DoColoringBasedRegisterAllocation()) { + return mp->New(cgfunc, mallocator); + } else { + fprintf(stderr, "Warning: We only support Linear Scan and GraphColor register allocation\n"); + } + return nullptr; + } + } + + CallerSavedRegHandler *NewCallerSavedRegisterHandler(CGFunc *cgfunc, MemPool *mp) override { + return mp->New(cgfunc); + } + +// regno_t New_V_Rflag() override { +// CG_ASSERT(RFLAG < max_reg_count, "CG internal error."); +// new (&v_reg_table[RFLAG]) VirtualRegNode(kRegTyCc, 4); +// return RFLAG; +// } + + regno_t AdjustRegno(regno_t regno) override { + if (regno < VB32) { + // Do nothing. + } + else if (regno < VB64) { + regno = regno - VB32 + V0; + } + else if (regno < kMaxRegNum) { + regno = regno - VB64 + V0; + } + return regno; + } + VectorType PickVectorType(SubRegType subRegty) { + switch (subRegty) { + case kSubRegTyUndef: + return kVecNone; + case kSubRegTyInt32: + case kSubRegTyFloat32: + return kVecSingle; + case kSubRegTyInt64: + case kSubRegTyFloat64: + return kVecDouble; + } + } + + MOperator PickMovInsn(uint32_t bitlen, RegType rtype); + void Savelockinfo(BB *bb) override; + void GenSavemethodinfoCode(BB *bb) override; + void GenNonescapedobjcleanup(); + void HandleRCCall(bool begin, MIRSymbol *retRef = nullptr) override; + bool GenRetCleanup(IntrinsiccallNode *cleanupnode); + void HandleRetCleanup(NaryStmtNode *retnode) override; + void HandleParamRCDec(); + void MergeReturn() override; + + void SelectDassign(DassignNode *stmt, Operand *opnd0) override; + void SelectRegassign(RegassignNode *stmt, Operand *opnd0) override; + void SelectAssertnull(UnaryStmtNode *stmt) override; + void SelectAggDassign(DassignNode *stmt) override; + void SelectIassign(IassignNode *stmt) override; + void SelectAggIassign(IassignNode *stmt, Operand *lhsaddropnd) override; + void SelectReturn(NaryStmtNode *stmt, Operand *opnd0) override; + void SelectCondGoto(CondGotoNode *stmt, Operand *opnd0, Operand *opnd1) override; + void SelectCondSpecial(CondGotoNode *stmt, BaseNode *opnd0) override; + void SelectGoto(GotoNode *stmt) override; + void SelectCall(CallNode *callnode) override; + void SelectIcall(IcallNode *icallnode, Operand *fptropnd) override; + void SelectIntrinCall(IntrinsiccallNode *icallnode) override; + void SelectMembar(StmtNode *membar) override; + + void SelectComment(CommentNode *comment) override; + + void HandleJavaCatch() override; + + bool CanBBThrow(BB *) override; + + Operand *SelectDread(BaseNode *parent, AddrofNode *expr) override; + RegOperand *SelectRegread(BaseNode *parent, RegreadNode *expr) override; + + void SelectAddrof(Operand *result, StImmOperand *stimm); + void SelectAddrof(Operand *result, Riscv64MemOperand *memopnd); + Operand *SelectAddrof(AddrofNode *expr) override; + Operand *SelectAddroffunc(AddroffuncNode *expr) override; + Operand *SelectAddroflabel(AddroflabelNode *expr) override; + + Operand *SelectIread(BaseNode *parent, IreadNode *expr) override; + + Operand *SelectIntconst(MIRIntConst *expr, PrimType pty) override; + Operand *SelectFloatconst(MIRFloatConst *floatconst) override; + Operand *SelectDoubleconst(MIRDoubleConst *doubleconst) override; + Operand *SelectVectorIntconst(MIRVectorIntConst *expr) override; + Operand *SelectStrconst(MIRStrConst *strconst) override; + Operand *SelectStr16const(MIRStr16Const *strconst) override; + + void SelectAdd(Operand *reso, Operand *o0, Operand *o1, PrimType mtype) override; + void SelectVecAdd(Operand *reso, Operand *o0, Operand *o1, PrimType mtype); + Operand *SelectAdd(BinaryNode *node, Operand *o0, Operand *o1) override; + Operand *SelectCGArrayElemAdd(BinaryNode *node) override; + Operand *SelectShift(BinaryNode *node, Operand *o0, Operand *o1) override; + Operand *SelectSub(BinaryNode *node, Operand *o0, Operand *o1) override; + void SelectSub(Operand *reso, Operand *o0, Operand *o1, PrimType prmtype) override; + Operand *SelectBand(BinaryNode *node, Operand *o0, Operand *o1) override; + void SelectBand(Operand *reso, Operand *o0, Operand *o1, PrimType mtype) override; + void SelectTest(Operand *reso, Operand *o0, Operand *o1, PrimType dtype) override; + Operand *SelectBior(BinaryNode *node, Operand *o0, Operand *o1) override; + void SelectBior(Operand *reso, Operand *o0, Operand *o1, PrimType mtype) override; + Operand *SelectBxor(BinaryNode *node, Operand *o0, Operand *o1) override; + void SelectBxor(Operand *reso, Operand *o0, Operand *o1, PrimType mtype) override; + + Operand *SelectLand(BinaryNode *node, Operand *o0, Operand *o1) override; + Operand *SelectLor(BinaryNode *node, Operand *o0, Operand *o1, bool parentIsBr = false) override; + Operand *SelectMin(BinaryNode *node, Operand *o0, Operand *o1) override; + void SelectMin(Operand *reso, Operand *o0, Operand *o1, PrimType mtype) override; + Operand *SelectMax(BinaryNode *node, Operand *o0, Operand *o1) override; + void SelectMax(Operand *reso, Operand *o0, Operand *o1, PrimType mtype) override; + void SelectFMinFMax(Operand *reso, Operand *o0, Operand *o1, bool is64bits, bool isMin); + void SelectCmpOp(Operand *reso, Operand *o0, Operand *o1, Opcode opcode, PrimType prmtype); + + Operand *SelectCmpOp(CompareNode *node, Operand *o0, Operand *o1) override; + + void SelectRiscv64Cmp(Operand *o, Operand *i, bool isIntty, uint32 dsize); + void SelectFPCmpQuiet(Operand *o0, Operand *o1, uint32 dsize) override; + void SelectShift(Operand *reso, Operand *o0, Operand *o1, SHIFTDIRECTION direct, PrimType prmtype); + void SelectShift64(Operand *reso, Operand *o0, Operand *o1, SHIFTDIRECTION direct, PrimType prmtype); + Operand *SelectMpy(BinaryNode *node, Operand *o0, Operand *o1) override; + void SelectMpy(Operand *reso, Operand *o0, Operand *o1, PrimType prmtype) override; + // method description contains method information which is metadata for reflection. + void EmitMethodDesc(Emitter &emitter) override; + void EmitRefToMethodDesc(Emitter &emitter) override; + void EmitRefToMethodInfo(Emitter &emitter) override; + void Emit() override; + void EmitFullLSDA(); + void EmitFastLSDA(); + void EmitBBHeaderLabel(const char *name, LabelIdx labidx); + void EmitPersonalityCfi(); + void EmitCfiDirectives(Insn *insn, bool inEpilog); + void CheckImmMemSize(); + MemOperand *AdjustMemOperandIfOffsetOutOfRange(MemOperand *memopnd, regno_t regno, Insn *insn, + Riscv64reg_t regnum, uint8 &isOutOfRange, bool isDest = false); + // run insert yieldpoint phase. + void InsertYieldpoint() override; + bool IsImmediateOffsetOutOfRange(Riscv64MemOperand *mo, uint32 bitlen); + bool SizeIsRight(Insn *insn); + bool CallIsVararg(StmtNode *narynode, uint32 &namedFormals, BB *bb); + + private: + void SelectRem(Operand *resopnd, Operand *opnd0, Operand *opnd1, PrimType prmtype, bool issigned, bool is64bits); + + public: + Operand *SelectRem(BinaryNode *node, Operand *opnd0, Operand *opnd1) override; + + void SelectDiv(Operand *resopnd, Operand *opnd0, Operand *opnd1, PrimType prmtype) override; + Operand *SelectDiv(BinaryNode *node, Operand *opnd0, Operand *opnd1) override; + Operand *SelectAbs(UnaryNode *node, Operand *opnd0) override; + Operand *SelectBnot(UnaryNode *node, Operand *opnd0) override; + Operand *GenerateSext(Operand *resopnd, Operand *opnd0, PrimType ptype, uint32 bitSize); + Operand *SelectSext(ExtractbitsNode *node, Operand *opnd0) override; + Operand *SelectZeroSignExt(Operand *opnd0, PrimType ptype); + Operand *GenerateZext(Operand *resopnd, Operand *opnd0, PrimType ptype, uint32 bitSize); + Operand *SelectZext(ExtractbitsNode *node, Operand *opnd0) override; + Operand *SelectExtractbits(ExtractbitsNode *node, Operand *opnd0) override; + Operand *SelectDepositbits(DepositbitsNode *node, Operand *opnd0, Operand *opnd1) override; + void SelectDepositbits(Operand *resopnd, Operand *opnd0, Operand *opnd1, uint32 bitsOffset, uint32 bitsSize, PrimType rtyp, + PrimType dtyp) override; + Operand *SelectLnot(UnaryNode *node, Operand *opnd0) override; + Operand *SelectNeg(UnaryNode *node, Operand *opnd0) override; + void SelectNeg(Operand *dest, Operand *opnd0, PrimType prmtype); + void SelectMvn(Operand *dest, Operand *opnd0, PrimType prmtype); + Operand *SelectRecip(UnaryNode *node, Operand *opnd0) override; + Operand *SelectSqrt(UnaryNode *node, Operand *opnd0) override; + Operand *SelectCeil(TypeCvtNode *node, Operand *opnd0) override; + Operand *SelectFloor(TypeCvtNode *node, Operand *opnd0) override; + Operand *SelectRetype(TypeCvtNode *node, Operand *opnd0) override; + Operand *SelectRound(TypeCvtNode *node, Operand *opnd0) override; + Operand *SelectCvt(BaseNode *parent, TypeCvtNode *node, Operand *opnd0) override; + Operand *SelectTrunc(TypeCvtNode *node, Operand *opnd0) override; + bool IfParamVRegOperand(Operand *opnd); + + private: + void SelectCvtInt2Int(BaseNode *parent, Operand *&resopnd, Operand *opnd0, PrimType fromtype, PrimType totype); + void SelectCvtFloat2Float(Operand *resopnd, Operand *opnd0, PrimType fromtype, PrimType totype); + void SelectCvtFloat2Int(Operand *resopnd, Operand *opnd0, PrimType itype, PrimType ftype); + void SelectCvtInt2Float(Operand *resopnd, Operand *opnd0, PrimType itype, PrimType ftype); + int64 GetOrCreatSpillRegLocation(regno_t vrnum) { + Riscv64SymbolAlloc *symloc = static_cast(memlayout->GetLocOfSpillRegister(vrnum)); + int64 offset = GetBaseOffset(symloc); + return offset; + } + + void SelectMPLClinitCheck(IntrinsiccallNode *); + void SelectCVaStart(IntrinsiccallNode *); + Operand *SelectCclz(IntrinsicopNode *); + Operand *SelectCctz(IntrinsicopNode *); + Operand *SelectIntrinOp(IntrinsicopNode *intrinopnode) override; + + public: + Operand *SelectSelect(TernaryNode *node, Operand *opnd0, Operand *opnd1, Operand *opnd2) override; + Operand *SelectMalloc(UnaryNode *call, Operand *opnd0) override; + Operand *SelectAlloca(UnaryNode *call, Operand *opnd0) override; + Operand *SelectGCMalloc(GCMallocNode *call) override; + Operand *SelectJarrayMalloc(JarrayMallocNode *call, Operand *opnd0) override; + void SelectSelect(Operand *resopnd, Operand *condopnd, Operand *trueopnd, Operand *falseopnd, PrimType dtyp, + PrimType ctyp) override; + void SelectRiscv64SelectOp(Operand *dest, Operand *opnd0, Operand *opnd1, Operand *trueOpnd, Operand *falseOpnd, + Opcode opcode, uint32 dsize, bool unsignedInt); + void SelectRangegoto(RangegotoNode *rangegotonode, Operand *opnd0) override; + RegOperand *SelectCopy(Operand *src, PrimType stype, PrimType dtype) override; + void SelectCopy(Operand *dest, PrimType dtype, Operand *src, PrimType stype); + RegOperand *MoveImm16Bits(uint32 val); + RegOperand *CombineImmBits(Operand *dest, Operand *upper, Operand *lower, uint32 shift); + void SelectCopyImm(Operand *dest, Riscv64ImmOperand *src, PrimType dtype); + Operand *SelectCopyToVecRegister(Operand *, PrimType, PrimType); + void SelectLibCall(const char *, vector &, PrimType, PrimType, bool is2nd = false); + Operand *GetTargetRetOperand(PrimType ptype, int32 sreg) override; + Operand *GetOrCreatevaryreg(); + RegOperand *CreateRegisterOperandOfType(PrimType primtype); + RegOperand *CreateRegisterOperandOfType(RegType regtype, uint32 bytelen); + RegOperand *CreateRflagOperand(); + + RegOperand *GetOrCreateSpecialRegisterOperand(PregIdx sregidx, PrimType primType = PTY_i64); + + MemOperand *GetOrCreatSpillMem(regno_t vrnum, int32 spillOffset = 0); + void FreeSpillRegMem(regno_t vrnum); + void TestInterface() override; + Riscv64RegOperand *GetOrCreatePhysicalRegisterOperand(Riscv64reg_t regNo, uint8 size, RegType type, uint32 flag = 0, + VectorType vecType = kVecNone, int vecPos = 0); + + LabelOperand *GetOrCreateLabelOperand(LabelIdx labidx) override; + LabelOperand *CreateFuncLabelOperand(MIRSymbol *func); + + Riscv64ImmOperand *CreateImmOperand(PrimType primType, int64 val) override { + return CreateImmOperand(val, GetPrimTypeBitSize(primType), IsSignedInteger(primType)); + } + + Operand *CreateZeroOperand(PrimType primType) override { + CG_ASSERT(false, "NYI"); + return nullptr; + } + + Operand *CreateFPImmZero(PrimType primType) override { + return GetOrCreateFpZeroOperand(GetPrimTypeBitSize(primType)); + } + + // create an integer immediate operand + inline Riscv64ImmOperand *CreateImmOperand(int64 val, uint8 size, bool isSigned, bool isVary = false, + bool isFmov = false) { + return memPool->New(val, size, isSigned, isVary, isFmov); + } + + inline ImmFPZeroOperand *GetOrCreateFpZeroOperand(uint8 size) { + return ImmFPZeroOperand::allocate(size); + } + + Riscv64OfstOperand *GetOrCreateOfstOpnd(uint32 offset, uint32 size); + + Riscv64OfstOperand *CreateOfstOpnd(uint32 offset, uint32 size) { + return memPool->New(offset, size); + } + + inline StImmOperand *CreateStImmOperand(MIRSymbol *st, int64 offset, int32 relocs) { + return memPool->New(st, offset, relocs); + } + + RegOperand *GetOrCreateFramePointerRegOperand() override { + return GetOrCreateStackBaseRegOperand(); + } + + RegOperand *GetOrCreateStackBaseRegOperand() override { + if (cg->UseFP() || HasVLAOrAlloca()) { + return GetOrCreatePhysicalRegisterOperand(RFP, SIZEOFPTR * BITS_PER_BYTE, kRegTyInt); + } else { + return GetOrCreatePhysicalRegisterOperand(RSP, SIZEOFPTR * BITS_PER_BYTE, kRegTyInt); + } + } + + RegOperand *GenStructParamIndex(RegOperand *base, BaseNode *indexExpr, int shift); + + MemOperand *GetOrCreateMemOpnd(MIRSymbol *symbol, int32 offset, int32 size) override; + + MemOperand *GetOrCreateArgMemOpnd(MIRSymbol *symbol, int32 offset, int32 size); + + Riscv64MemOperand *GetOrCreateMemOpnd(int32, RegOperand *, RegOperand *, + Operand *, MIRSymbol *); + + inline MemOperand *CreateMemOpnd(Riscv64reg_t reg, int32 offset, int32 size) { + Riscv64RegOperand *baseOpnd = GetOrCreatePhysicalRegisterOperand(reg, SIZEOFPTR * BITS_PER_BYTE, kRegTyInt); + return CreateMemOpnd(baseOpnd, offset, size); + } + + MemOperand *CreateMemOpnd(RegOperand *baseOpnd, int32 offset, int32 size) override; + + MemOperand *CreateMemOpnd(RegOperand *baseOpnd, int32 offset, int32 size, MIRSymbol *sym) override; + + MemOperand *CreateMemOpnd(PrimType ptype, BaseNode *parent, BaseNode *addrExpr, int offset = 0, + Riscv64isa::memory_ordering_t mo = Riscv64isa::kMoNone); + + inline int32 GetCurrentCFA() { + return current_cfa_; + } + + inline void SetCurrentCFA(int32 v) { + current_cfa_ = v; + } + + inline int32 GetMarkCFA() { + return mark_cfa_; + } + + inline void SetMarkCFA(int32 v) { + mark_cfa_ = v; + } + + Operand *GetOrCreateFuncNameOpnd(MIRSymbol *symbol); + Insn *CreateMoveInsn(Operand *opnd); // create a move instruction that copy opnd + void ReplaceMachedOperand(Insn *orig, Insn *target, RegOperand *match, bool replaceOrigSrc); + void ForwardPropagateAndRename(Insn *mv, Insn *ld, BB *terminateBb); + bool BackwardFindDependency(BB *ifbb, BB *returnbb, RegOperand *tgtOpnd, Insn *&ld, Insn *&mov, Insn *&depMov, + std::list &list); + void EmitOperand(Operand *, OpndProp *); + void GenerateProlog(BB *) override; + void MoveRegargs(BB *) override; + void Genstackguard(BB *) override; + void MoveVRegargs(BB *) override; + BB *IsolateFastPath(BB *) override; + void GenerateEpilog(BB *) override; + void GenerateEpilogForCleanup(BB *) override; + void GenerateRet(BB *bb) override; + void GenerateYieldpoint(BB *) override; + void GenerateCleanupCode(BB *) override; + bool NeedCleanup() override; + + void GenerateCleanupCodeForExtEpilog(BB *) override; + + Operand *GetBaseReg(Riscv64SymbolAlloc *symballoc); + uint32 GetBaseOffset(SymbolAlloc *symalloc) override; + + inline Operand *CreateCommentOperand(const char *s) { + return memPool->New(s); + } + + inline Operand *CreateCommentOperand(const std::string s) { + return memPool->New(s.c_str()); + } + + inline Operand *CreateCommentOperand(const MapleString s) { + return memPool->New(s.c_str()); + } + + inline void AddtoCalleeSaved(Riscv64reg_t reg) { + MapleVector::iterator it; + for (it = callee_saved_regs.begin(); it != callee_saved_regs.end(); ++it) + if (*it == reg) { + return; + } + callee_saved_regs.push_back(reg); + CG_ASSERT((Riscv64isa::IsGPRegister(reg) || Riscv64isa::IsFPSIMDRegister(reg)), "Int or FP registers are expected"); + if (Riscv64isa::IsGPRegister(reg)) { + ++num_intreg_to_callee_save; + } else { + ++num_fpreg_to_callee_save; + } + } + + inline int32 SizeOfCalleeSaved() { + return ((num_intreg_to_callee_save + num_fpreg_to_callee_save) * kIntregBytelen); + } + + inline bool IsCalleeSavedPaired() { + return (((num_intreg_to_callee_save + num_fpreg_to_callee_save) & 0x1) == 0); + } + + void DBGFixCallFrameLocationOffsets() override; + + inline bool ShouldSaveFPLR() { + return (cg->UseFP() || HasCall() || cg->NeedInsertInstrumentationFunction()); + } + + inline void NoteFPLRAddedToCalleeSavedList() { + fprl_added_to_callee_saved = true; + } + + inline bool IsFPLRAddedToCalleeSavedList() { + return fprl_added_to_callee_saved; + } + + inline bool UsedStpSubPairForCallFrameAllocation() { + return used_stp_sub_pair_to_allocate_call_frame; + } + + inline MapleVector &GetCalleeSavedRegs() { + return callee_saved_regs; + } + + void OffsetAdjustmentForFPLR() override; + + void AppendInstructionPushSingle(Riscv64reg_t reg, RegType rty, int offset); + + void AppendInstructionPushPair(Riscv64reg_t reg0, Riscv64reg_t reg1, RegType rty, int offset); + + void AppendInstructionPushRZRPair(Riscv64reg_t reg0, Riscv64reg_t reg1, int offset); + + void AppendInstructionAllocateCallFrame(Riscv64reg_t reg0, Riscv64reg_t reg1, RegType rty); + + void AppendInstructionAllocateCallFrameDebug(Riscv64reg_t reg0, Riscv64reg_t reg1, RegType rty); + + void AppendInstructionPopSingle(Riscv64reg_t reg, RegType rty, int offset); + + void AppendInstructionPopPair(Riscv64reg_t reg0, Riscv64reg_t reg1, RegType rty, int offset); + + void AppendInstructionDeallocateCallFrame(Riscv64reg_t reg0, Riscv64reg_t reg1, RegType rty); + + void AppendInstructionDeallocateCallFrameDebug(Riscv64reg_t reg0, Riscv64reg_t reg1, RegType rty); + + void AppendInstructionStackCheck(Riscv64reg_t reg, RegType rty, int offset); + + void GeneratePushRegs(); + + void GeneratePopRegs(); + + Riscv64MemOperand *CreateStkTopOpnd(int32 offset, int32 size); + + // if offset < 0, allocation; otherwise, deallocation + Riscv64MemOperand *CreateCallFrameOperand(int32 offset, int32 size); + + inline bool UseFP() { + return cg->UseFP(); + } + + void AppendCall(MIRSymbol *func); + + void AppendJump(MIRSymbol *func); + +// riscv assembler does the long branch patch + int32 MaxCondBranchDistance() override { + return Riscv64Abi::kMaxInstrForCondBr; + } + + void InsertJumpPad(Insn *insn) override; + + void ConvertJumpToRegJump(Insn *insn) override; + + // CFI directives related stuffs + Operand *CreateCfiRegOperand(uint32 reg, uint8 size) override { + // Having kRinvalid=0 (see riscv64_isa.h) means + // each register gets assigned an id number one greater than + // its physical number + if (reg < V0) { + return memPool->New(reg - R0 + DWARF_SCALAR_REG_BEGIN, size); + } else { + return memPool->New(reg - V0 + DWARF_FP_REG_BEGIN, size); + } + } + + Insn *GenerateCfiRestores(BB *) override; + + // Store the address of `symbol` into the GCTIB field of a GC object. + // Used right after object allocation. + void SelectStoreGCTIB(RegOperand *obj, std::string symbol); + + void SetJavaCatchRegno(regno_t regno) { + ujavaCatch.regno_javaCatch = regno; + } + + regno_t GetJavaCatchRegno() { + return ujavaCatch.regno_javaCatch; + } + + void SetJavaCatchOpnd(Operand *opnd) { + ujavaCatch.opnd_javaCatch = opnd; + } + + Riscv64reg_t GetReturnRegisterNumber(); + + RegType GetRegTyFromPrimTy(PrimType pty) override { + return GetRegTyFromPrimTyRiscv64(pty); + } + + RegType GetRegTyFromPrimTyRiscv64(PrimType primType) { + switch (primType) { + case PTY_u1: + case PTY_i8: + case PTY_u8: + case PTY_i16: + case PTY_u16: + case PTY_i32: + case PTY_u32: + case PTY_i64: + case PTY_u64: + case PTY_a32: + case PTY_a64: + case PTY_ptr: + return kRegTyInt; + case PTY_f32: + case PTY_f64: + case PTY_v2i64: // simd uses the alias register bank of float + case PTY_v4i32: + case PTY_v8i16: + case PTY_v16i8: + case PTY_v2f64: + case PTY_v4f32: + return kRegTyFloat; + default: + return kRegTyUndef; + } + } + + /* + MemOperand* + GetorCreatSpillRegMemoryOperand(regno_t vrnum) override; + */ + private: + // Helper functions for translating complex Maple IR instructions/inrinsics + void SelectDassign(StIdx stIdx, FieldID fieldID, PrimType rhsPtyp, Operand *opnd0); + + LabelIdx CreateLabeledBB(StmtNode *stmt); + + void SaveReturnValueInLocal(CallReturnVector *retvals, size_t index, PrimType pty, Operand *value, + StmtNode *parentStmt); + + // Translation for load-link store-conditional, and atomic RMW operations. + MemOrd OperandToMemOrd(Operand *opnd); + MOperator PickLoadStoreExclInsn(int byteP2size, bool store, bool acqRel); + RegOperand *SelectLoadExcl(PrimType valPty, Riscv64MemOperand *loc, bool acquire); + RegOperand *SelectStoreExcl(PrimType valPty, Riscv64MemOperand *loc, RegOperand *newVal, bool release); + bool NeedAdjustOffSet(Riscv64Insn *insn); + + MemOperand *GetPseudoRegisterSpillMemoryOperand(PregIdx i) override; + + RegType GetRegType(regno_t r) override { + CG_ASSERT(Riscv64isa::IsPhysicalRegister(r), ""); + return Riscv64isa::GetRegType(static_cast(r)); + } + + bool IsCalleeSaved(regno_t r) override { + return Riscv64Abi::IsCalleeSavedReg(Riscv64reg_t(r)); + } + + bool IsCallerSaved(regno_t r) override { + return !IsCalleeSaved(r); + } + + bool HasStackLoadStore(); + + bool HasCall(); + + bool HasClinit(); + + bool HasLoop(); + + bool TailCallOpt() override; + + bool OptimizeTailBB(BB *bb, set &callInsns); + + void TailCallBBOpt(BB *exitBB, set &callInsns); + + bool TestPredsOfRetBB(BB *exitBB); + + bool IsCommentBB(BB *bb); + + void InitialSpillSlot(BB *bb); + + MemOperand *LoadStructCopyBase(MIRSymbol *symbol, int32 offset, int datasize) override; + + void ReplaceLargeStackOffsetImm(Insn *insn); +}; + +} // namespace maplebe + +#endif // MAPLEBE_INCLUDE_CG_AARCH64CGFUNC_H diff --git a/mapleall/maple_be/include/cg/riscv64/riscv64_color_ra.h b/mapleall/maple_be/include/cg/riscv64/riscv64_color_ra.h new file mode 100644 index 0000000..4b79f20 --- /dev/null +++ b/mapleall/maple_be/include/cg/riscv64/riscv64_color_ra.h @@ -0,0 +1,865 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#ifndef AARCH64COLORRA_H +#define AARCH64COLORRA_H +#include "reg_alloc.h" +#include "riscv64_operand.h" +#include "riscv64_insn.h" +#include "riscv64_abi.h" +#include "loop.h" + +namespace maplebe { + +#define RESERVED_REGS + +#undef DO_PRE_LRA +#define USE_LRA +#define USE_SPLIT +#undef USE_BB_FREQUENCY +#undef OPTIMIZE_FOR_PROLOG // riscv has no load/store double, evaluate this opt later +#define REUSE_SPILLMEM +#define REMOVE_INSN +#define COLOR_SPLIT +#undef MOVE_COALESCE +#define PROPAGATE_REG + +// for robust test +#undef CONSISTENT_MEMOPND +#undef RANDOM_PRIORITY + +#define CLEAR_BIT_ARR_ELEM(vec, buckets) \ + { \ + for (uint32 i = 0; i < buckets; i++) { \ + (vec)[i] = 0LL; \ + } \ + } + +#define SET_BIT_ARR_ELEM(vec, num) \ + { \ + uint32 index = (num) / (sizeof(uint64) * CHAR_BIT); \ + uint64 bit = (num) % (sizeof(uint64) * CHAR_BIT); \ + ((vec)[index] |= (1LL << bit)); \ + } + +#define SET_MEMBER_BIT_ARR_ELEM(lr, num) \ + { \ + uint32 index = (num) / (sizeof(uint64) * CHAR_BIT); \ + uint64 bit = (num) % (sizeof(uint64) * CHAR_BIT); \ + uint64 mask = 1LL << bit; \ + if (((lr)->bmember[index] & mask) == 0) { \ + (lr)->numBmembers++; \ + (lr)->bmember[index] |= mask; \ + } \ + } + +#define SET_CONFLICT_BIT_ARR_ELEM(lr, num) \ + { \ + uint32 index = (num) / (sizeof(uint64) * CHAR_BIT); \ + uint64 bit = (num) % (sizeof(uint64) * CHAR_BIT); \ + uint64 mask = 1LL << bit; \ + if (((lr)->bconflict[index] & mask) == 0) { \ + (lr)->numBconflicts++; \ + (lr)->bconflict[index] |= mask; \ + } \ + } + +#define UNSET_BIT_ARR_ELEM(vec, num) \ + { \ + uint32 index = (num) / (sizeof(uint64) * CHAR_BIT); \ + uint64 bit = (num) % (sizeof(uint64) * CHAR_BIT); \ + ((vec)[index] &= (~(1LL << bit))); \ + } + +#define UNSET_MEMBER_BIT_ARR_ELEM(lr, num) \ + { \ + uint32 index = (num) / (sizeof(uint64) * CHAR_BIT); \ + uint64 bit = (num) % (sizeof(uint64) * CHAR_BIT); \ + uint64 mask = 1LL << bit; \ + if ((lr)->bmember[index] & mask) { \ + (lr)->numBmembers--; \ + (lr)->bmember[index] &= (~mask); \ + } \ + } + +#define UNSET_CONFLICT_BIT_ARR_ELEM(lr, num) \ + { \ + uint32 index = (num) / (sizeof(uint64) * CHAR_BIT); \ + uint64 bit = (num) % (sizeof(uint64) * CHAR_BIT); \ + uint64 mask = 1LL << bit; \ + if ((lr)->bconflict[index] & mask) { \ + (lr)->numBconflicts--; \ + (lr)->bconflict[index] &= (~mask); \ + } \ + } + +#define IS_BIT_ARR_ELEM_SET(vec, num) \ + ({ \ + uint32 index = (num) / (sizeof(uint64) * CHAR_BIT); \ + uint64 bit = (num) % (sizeof(uint64) * CHAR_BIT); \ + bool isSet = ((vec)[index] & (1LL << bit)); \ + isSet; \ + }) + +#define BIT_ARR_AND(vec1, vec2, result, buckets) \ + { \ + for (uint32 i = 0; i < buckets; i++) { \ + (result)[i] = (vec1)[i] & (vec2)[i]; \ + } \ + } + +#define BIT_ARR_OR(vec1, vec2, result, buckets) \ + { \ + for (uint32 i = 0; i < buckets; i++) { \ + (result)[i] = (vec1)[i] | (vec2)[i]; \ + } \ + } + +#define IS_BIT_ARR_EMPTY(vec) \ + ({ \ + bool isEmpty = true; \ + for (uint32 i = 0; i < bbBuckets; i++) { \ + if ((vec)[i]) { \ + isEmpty = false; \ + break; \ + } \ + } \ + isEmpty; \ + }) + +#define SET_BB_OVERLAP(vec1, vec2) \ + ({ \ + bool isOverlap = false; \ + for (uint32 i = 0; i < bbBuckets; i++) { \ + if (((vec1)[i] & (vec2)[i]) != 0) { \ + isOverlap = true; \ + break; \ + } \ + } \ + isOverlap; \ + }) + +#define COPY_BIT_ARR_ELEM(to, from, buckets) \ + { \ + for (uint32 i = 0; i < buckets; i++) { \ + to[i] = from[i]; \ + } \ + } + +#define FOREACH_BB_ARR_ELEM(vec, num) \ + { \ + uint32 num; \ + for (uint32 i = 0; i < bbBuckets; i++) { \ + if ((vec)[i] == 0) continue; \ + for (uint32 b = 0; b < (sizeof(uint64) * CHAR_BIT); b++) { \ + if ((vec)[i] & (1LL << b)) { \ + num = i * sizeof(uint64) * CHAR_BIT + b; + +#define END_FOREACH_BB_ARR_ELEM \ + } \ + } \ + } \ + } + +#define FOREACH_REG_ARR_ELEM(vec, num) \ + { \ + regno_t num; \ + for (uint32 i = 0; i < regBuckets; i++) { \ + if ((vec)[i] == 0) continue; \ + for (uint32 b = 0; b < (sizeof(uint64) * CHAR_BIT); b++) { \ + if ((vec)[i] & (1LL << b)) { \ + num = i * sizeof(uint64) * CHAR_BIT + b; + +#define END_FOREACH_REG_ARR_ELEM \ + } \ + } \ + } \ + } + +#define FOREACH_REG_ARR_ELEM_NOT_SET(vec, num) \ + { \ + regno_t num; \ + for (uint32 i = 0; i < regBuckets; i++) { \ + for (uint32 b = 0; b < (sizeof(uint64) * CHAR_BIT); b++) { \ + if (!((vec)[i] & (1LL << b))) { \ + num = i * sizeof(uint64) * CHAR_BIT + b; + +#define END_FOREACH_REG_ARR_ELEM_NOT_SET \ + } \ + } \ + } \ + } + +#define FIND(set, item) (find((set).begin(), (set).end(), item)) + +#define FIND_NOT_IN(set, item) (FIND(set, item) == (set).end()) + +#define FIND_IN(set, item) (FIND(set, item) != (set).end()) + +// This is per bb per LR. +// LU info is particular to a bb in a LR. +class LiveUnit { + public: + uint32 bgn; // first encounter in bb + uint32 end; // last encounter in bb + bool hasCall; // bb has a call + uint32 defNum; + uint32 useNum; // used for priority calculation + bool needRlod; + bool needRstr; + + LiveUnit() : bgn(0), end(0), hasCall(false), defNum(0), useNum(0), needRlod(false), needRstr(false) {} + + void PrintLiveUnit() const; +}; + +struct SetBBCmpFunc { + bool operator()(const BB *lhs, const BB *rhs) const { + return (lhs->id < rhs->id); + } +}; + +struct SortedBBCmpFunc { + bool operator()(const BB *lhs, const BB *rhs) const { + return (lhs->level < rhs->level); + } +}; + +// LR is for each global vreg. +class LiveRange { + public: + MapleAllocator *allocator; + regno_t regno; + uint32 id; // for priority tie breaker + regno_t assigned; // color assigned + uint32 numCall; + RegType regtype; + float priority; + uint32 numBmembers; // number of bits set in bmember + uint64 *bmember; // Same as smember, but use bit array + // bit vector of array for each vreg's lr + // bit_vector[bb->id] = 1 if vreg is live in bb + MapleVector pregveto; // pregs cannot be assigned -- SplitLr may clear forbidden + MapleVector forbidden; // pregs cannot be assigned + uint32 numBconflicts; // number of bits set in bconflict + uint32 numPregveto; + uint32 numForbidden; + uint64 *bconflict; // vreg interference from graph neighbors (bit) + uint64 *oldConflict; + MapleSet prefs; // pregs that prefer + MapleMap luMap; // info for each bb + LiveRange *splitLr; // The 1st part of the split +#ifdef OPTIMIZE_FOR_PROLOG + uint32 numDefs; + uint32 numUses; + uint32 frequency; +#endif // OPTIMIZE_FOR_PROLOG + MemOperand *spillMem; // memory operand used for spill, if any + regno_t spillReg; // register operand for spill at current point + uint32 spillSize; // 32 or 64 bit spill + + bool spilled; // color assigned + bool isNonLocal; + + explicit LiveRange(MapleAllocator *mallocator) + : allocator(mallocator), + regno(0), + id(0), + assigned(0), + numCall(0), + regtype(kRegTyUndef), + priority(0.0), + numBmembers(0), + bmember(nullptr), + pregveto(mallocator->Adapter()), + forbidden(mallocator->Adapter()), + numBconflicts(0), + numPregveto(0), + numForbidden(0), + bconflict(nullptr), + oldConflict(nullptr), + prefs(mallocator->Adapter()), + luMap(mallocator->Adapter()), + splitLr(nullptr), +#ifdef OPTIMIZE_FOR_PROLOG + numDefs(0), + numUses(0), + frequency(0), +#endif // OPTIMIZE_FOR_PROLOG + spillMem(nullptr), + spillReg(0), + spillSize(0), + spilled(false), + isNonLocal(false) { + } + + void insertPregveto(regno_t reg) { + if (pregveto[reg] == false) { + numPregveto++; + pregveto[reg] = true; + } + } + + void insertForbidden(regno_t reg) { + if (forbidden[reg] == false) { + numForbidden++; + forbidden[reg] = true; + } + } +}; + +// One per bb, to communicate local usage to global RA +class LocalRaInfo { + public: + MapleAllocator *allocator; + MapleMap defCnt; + MapleMap useCnt; + //MapleSet globalPreg; + + //uint64 globalPregMask; // global phys reg used in bb + //uint64 localPregMask; // local phys reg used in bb + + explicit LocalRaInfo(MapleAllocator *mallocator) + : allocator(mallocator), + defCnt(mallocator->Adapter()), + useCnt(mallocator->Adapter()) {} + //globalPreg(mallocator->Adapter()), + //globalPregMask(0), + //localPregMask(0) {} +}; + +// For each bb, record info pertain to allocation +class BbAssignInfo { + public: + MapleAllocator *allocator; + MapleVector globalsAssigned; // globals used in a bb + MapleMap regMap; // local vreg to preg mapping + uint32 intLocalRegsNeeded; // num local reg needs for each bb + uint32 fpLocalRegsNeeded; // num local reg needs for each bb + uint32 numGlobalsAssigned; + + explicit BbAssignInfo(MapleAllocator *mallocator) + : allocator(mallocator), + globalsAssigned(mallocator->Adapter()), + regMap(mallocator->Adapter()), + intLocalRegsNeeded(0), + fpLocalRegsNeeded(0), + numGlobalsAssigned(0) {} + + void insertGlobalsAssigned(regno_t reg) { + if (globalsAssigned[reg] == false) { + numGlobalsAssigned++; + globalsAssigned[reg] = true; + } + } +}; + +class FinalizeRegisterInfo { + public: + MapleAllocator *allocator; + int32_t memOperandIdx; + Operand *baseOperand; + Operand *offsetOperand; + MapleVector defOperands; + MapleVector defIdx; + MapleVector useOperands; + MapleVector useIdx; + + FinalizeRegisterInfo(MapleAllocator *mallocator) + : allocator(mallocator), + memOperandIdx(0), + baseOperand(nullptr), + offsetOperand(nullptr), + defOperands(mallocator->Adapter()), + defIdx(mallocator->Adapter()), + useOperands(mallocator->Adapter()), + useIdx(mallocator->Adapter()) {} + + void ClearInfo() { + memOperandIdx = 0; + baseOperand = nullptr; + offsetOperand = nullptr; + defOperands.clear(); + defIdx.clear(); + useOperands.clear(); + useIdx.clear(); + } + + void SetBaseOperand(Operand *opnd, const int32_t idx) { + baseOperand = opnd; + memOperandIdx = idx; + } + + void SetOffsetOperand(Operand *opnd) { + offsetOperand = opnd; + } + + void SetDefOperand(Operand *opnd, const int32_t idx) { + defOperands.push_back(opnd); + defIdx.push_back(idx); + } + + void SetUseOperand(Operand *opnd, const int32_t idx) { + useOperands.push_back(opnd); + useIdx.push_back(idx); + } +}; + +#define FOREACH_LRA_REGS(isInt, regno, localRa) \ + { \ + for ((regno) = ((isInt) ? R0 : V0); (regno) <= ((isInt) ? R31 : V31); (regno)++) { \ + if (localRa->IsInRegs(regno, isInt) == false) { \ + continue; \ + } + +#define END_FOREACH_LRA_REGS \ + } \ + } + +class LocalRegAllocator { + public: + // The following local vars keeps track of allocation information in bb. + uint64 *intRegAssigned; // in this set if vreg is assigned + uint64 *fpRegAssigned; + MapleMap intRegAssignmentMap; // vreg -> preg map, which preg is the vreg assigned + MapleMap fpRegAssignmentMap; + uint64 intRegUsed; // pregs used in bb + uint64 fpRegUsed; + uint64 *intRegSpilled; // on this list if spilled + uint64 *fpRegSpilled; + + uint64 intRegs; // available regs for assignement + uint64 fpRegs; + MapleMap useInfo; // copy of local ra info for useCnt + + uint32 numIntRegUsed; + uint32 numFpRegUsed; + uint32 buckets; + + LocalRegAllocator(CGFunc *cgfunc, MapleAllocator *mallocator) + : intRegAssignmentMap(mallocator->Adapter()), + fpRegAssignmentMap(mallocator->Adapter()), + intRegUsed(0), + fpRegUsed(0), + intRegs(0), + fpRegs(0), + useInfo(mallocator->Adapter()), + numIntRegUsed(0), + numFpRegUsed(0) { + buckets = (cgfunc->GetMaxRegNum() / (sizeof(uint64) * CHAR_BIT)) + 1; + intRegAssigned = cgfunc->memPool->NewArray(buckets); + fpRegAssigned = cgfunc->memPool->NewArray(buckets); + intRegSpilled = cgfunc->memPool->NewArray(buckets); + fpRegSpilled = cgfunc->memPool->NewArray(buckets); + } + + void ClearLocalRaInfo() { + CLEAR_BIT_ARR_ELEM(intRegAssigned, buckets); + CLEAR_BIT_ARR_ELEM(fpRegAssigned, buckets); + intRegAssignmentMap.clear(); + fpRegAssignmentMap.clear(); + intRegUsed = 0; + fpRegUsed = 0; + CLEAR_BIT_ARR_ELEM(intRegSpilled, buckets); + CLEAR_BIT_ARR_ELEM(fpRegSpilled, buckets); + numIntRegUsed = 0; + numFpRegUsed = 0; + } + + regno_t RegBaseUpdate(bool isInt) { + if (isInt) { + return 0; + } else { + return V0 - R0; + } + } + + bool isInRegAssigned(regno_t regno, const bool isInt) { + bool isSet; + if (isInt) { + isSet = IS_BIT_ARR_ELEM_SET(intRegAssigned, regno); + } else { + isSet = IS_BIT_ARR_ELEM_SET(fpRegAssigned, regno); + } + return isSet; + } + + void SetRegAssigned(regno_t regno, const bool isInt) { + if (isInt) { + SET_BIT_ARR_ELEM(intRegAssigned, regno); + } else { + SET_BIT_ARR_ELEM(fpRegAssigned, regno); + } + } + + MapleMap *GetRegAssignmentMap(const bool isInt) { + if (isInt) { + return &intRegAssignmentMap; + } else { + return &fpRegAssignmentMap; + } + } + + uint64 GetRegUsed(const bool isInt) { + if (isInt) { + return intRegUsed; + } else { + return fpRegUsed; + } + } + + void SetRegUsed(regno_t regno, const bool isInt) { + if (isInt) { + uint64 mask = 1LL << (regno - R0); + if ((intRegUsed & mask) == 0) { + numIntRegUsed++; + intRegUsed |= mask; + } + } else { + uint64 mask = 1LL << (regno - V0); + if ((fpRegUsed & mask) == 0) { + numFpRegUsed++; + fpRegUsed |= mask; + } + } + } + + bool isInRegSpilled(regno_t regno, const bool isInt) { + bool isSet; + if (isInt) { + isSet = IS_BIT_ARR_ELEM_SET(intRegSpilled, regno); + } else { + isSet = IS_BIT_ARR_ELEM_SET(fpRegSpilled, regno); + } + return isSet; + } + + void SetRegSpilled(regno_t regno, const bool isInt) { + if (isInt) { + SET_BIT_ARR_ELEM(intRegSpilled, regno); + } else { + SET_BIT_ARR_ELEM(fpRegSpilled, regno); + } + } + + uint64 GetRegs(const bool isInt) { + if (isInt) { + return intRegs; + } else { + return fpRegs; + } + } + + void SetRegs(regno_t regno, const bool isInt) { + if (isInt) { + intRegs |= (1LL << (regno - RegBaseUpdate(true))); + } else { + fpRegs |= (1LL << (regno - RegBaseUpdate(false))); + } + } + + void ClearRegs(regno_t regno, const bool isInt) { + if (isInt) { + intRegs &= (~(1LL << (regno - RegBaseUpdate(true)))); + } else { + fpRegs &= (~(1LL << (regno - RegBaseUpdate(false)))); + } + } + + bool IsInRegs(regno_t regno, const bool isInt) { + bool isSet; + if (isInt) { + isSet = (intRegs & (1LL << (regno - RegBaseUpdate(true)))); + } else { + isSet = (fpRegs & (1LL << (regno - RegBaseUpdate(false)))); + } + return isSet; + } + + void InitRegs(uint32 intMax, uint32 fpMax, bool hasYield) { + // exclude 0th bit, no reserved regs like sp/fp + intRegs = 0x1fffffdc0ULL; +#ifdef RESERVED_REGS + fpRegs = 0x0fffffffeULL; +#else + fpRegs = 0x1fffffffeULL; +#endif + } +}; + +class SplitBbInfo { + public: + SplitBbInfo() : candidateBb(nullptr), startBb(nullptr) {} + + inline BB *GetCandidateBb() const { + return candidateBb; + } + + inline BB *GetStartBb() const { + return startBb; + } + + inline void SetCandidateBb(BB *bb) { + candidateBb = bb; + } + + inline void SetStartBb(BB *bb) { + startBb = bb; + } + + private: + BB *candidateBb; + BB *startBb; +}; + +class GraphColorRegAllocator : public RegAllocator { + public: + GraphColorRegAllocator(CGFunc *cgfunc, MapleAllocator *mallocator) + : RegAllocator(cgfunc), + allocator(mallocator), + visitedBBs(mallocator->Adapter()), + sortedBBs(mallocator->Adapter()), + bbVec(mallocator->Adapter()), + vregLive(mallocator->Adapter()), + pregLive(mallocator->Adapter()), + lrVec(mallocator->Adapter()), + localRegVec(mallocator->Adapter()), + bbRegInfo(mallocator->Adapter()), + unconstrained(mallocator->Adapter()), + constrained(mallocator->Adapter()), +#ifdef OPTIMIZE_FOR_PROLOG + intDelayed(mallocator->Adapter()), + fpDelayed(mallocator->Adapter()), +#endif // OPTIMIZE_FOR_PROLOG + intCallerRegSet(mallocator->Adapter()), + intCalleeRegSet(mallocator->Adapter()), + fpCallerRegSet(mallocator->Adapter()), + fpCalleeRegSet(mallocator->Adapter()), + intCalleeUsed(mallocator->Adapter()), + fpCalleeUsed(mallocator->Adapter()), + bbBuckets(0), + regBuckets(0), + spillMemopnd0(nullptr), + spillMemopnd1(nullptr), + spillMemopnd2(nullptr), +#ifdef USE_LRA + doLRA(true), +#else + doLRA(false), +#endif // USE_LRA +#ifdef OPTIMIZE_FOR_PROLOG + doOptProlog(true), +#else + doOptProlog(false), +#endif // OPTIMIZE_FOR_PROLOG + hasSpill(false) { + intSpillFillRegs[0] = intSpillFillRegs[1] = intSpillFillRegs[2] = 0; + fpSpillFillRegs[0] = fpSpillFillRegs[1] = fpSpillFillRegs[2] = 0; + numVregs = cgfunc_->GetMaxVReg(); + lrVec.resize(numVregs); + localRegVec.resize(cgfunc_->NumBBs()); + bbRegInfo.resize(cgfunc_->NumBBs()); + } + + ~GraphColorRegAllocator() override {} + + bool AllocateRegisters() override; + const char *PhaseName() { + return "regalloc"; + } + + private: + const uint16 kLargeUint16 = 0x7fff; + enum { kNoDelete, kDelayedDelete, kImmediateDelete}; + + struct SetLiveRangeCmpFunc { + bool operator()(const LiveRange *lhs, const LiveRange *rhs) const { + if (lhs->priority == rhs->priority) { + // This is to ensure the ordering is consistent as the reg# + // differs going through VtableImpl.mpl file. + if (lhs->id == rhs->id) { + return lhs->regno < rhs->regno; + } else { + return lhs->id < rhs->id; + } + } + return (lhs->priority > rhs->priority); + } + }; + + MapleAllocator *allocator; + MapleVector visitedBBs; + MapleVector sortedBBs; + MapleVector bbVec; + MapleSet vregLive; + MapleSet pregLive; + MapleVector lrVec; + MapleVector localRegVec; // local reg info for each bb, no local reg if null + MapleVector bbRegInfo; // register assignment info for each bb + MapleVector unconstrained; + MapleVector constrained; +#ifdef OPTIMIZE_FOR_PROLOG + MapleVector intDelayed; + MapleVector fpDelayed; +#endif // OPTIMIZE_FOR_PROLOG + MapleSet intCallerRegSet; // integer caller saved + MapleSet intCalleeRegSet; // callee + MapleSet fpCallerRegSet; // float caller saved + MapleSet fpCalleeRegSet; // callee + MapleSet intCalleeUsed; + MapleSet fpCalleeUsed; + + uint32 bbBuckets; // size of bit array for bb (each bucket == 64 bits) + uint32 regBuckets; // size of bit array for reg (each bucket == 64 bits) + uint32 intRegNum; // total available int preg + uint32 fpRegNum; // total available fp preg + uint32 numVregs; // number of vregs when starting + // For spilling of spill register if there are none available + // Example, all 3 operands spilled + // sp_reg1 -> [spillMemopnd1] + // sp_reg2 -> [spillMemopnd2] + // ld sp_reg1 <- [addr-reg2] + // ld sp_reg2 <- [addr-reg3] + // reg1 <- reg2, reg3 sp_reg1 <- sp_reg1, sp_reg2 + // st sp_reg1 -> [addr-reg1] + // sp_reg1 <- [spillMemopnd1] + // sp_reg2 <- [spillMemopnd2] + MemOperand *spillMemopnd0; + MemOperand *spillMemopnd1; + MemOperand *spillMemopnd2; + + regno_t intSpillFillRegs[3]; + regno_t fpSpillFillRegs[3]; + + bool doLRA; + bool doOptProlog; + bool hasSpill; + + void PrintLiveUnitMap(const LiveRange *lr) const; + void PrintLiveRangeConflicts(const LiveRange *lr) const; + void PrintLiveBbBit(const LiveRange *li) const; + void PrintLiveRange(const LiveRange *li, const string str) const; + void PrintLiveRanges() const; + void PrintLocalRaInfo(const string str) const; + void PrintBbAssignInfo() const; + void PrintBBs() const; + + bool AllPredBBVisited(BB *); + BB *MarkStraightLineBBInBFS(BB *); + BB *SearchForStraightLineBBs(BB *); + void BFS(BB *); + void ComputeBlockOrder(); + uint32 MaxIntPhysRegNum(); + uint32 MaxFloatPhysRegNum(); + void InitFreeRegPool(); + bool IsUnconcernedReg(regno_t regno); + bool IsUnconcernedReg(RegOperand *regOpnd); + LiveRange *NewLiveRange(); + void CalculatePriority(LiveRange *lr); + bool CreateLiveRangeHandleLocal(regno_t regno, BB *bb, bool isDef); + LiveRange *CreateLiveRangeAllocateAndUpdate(regno_t regno, BB *bb, bool isDef, uint32 currId); + bool CreateLiveRange(regno_t regno, BB *bb, bool isDef, bool isMovk, uint32 currPoint, bool update_cnt); + bool SetupLiveRangeByOpHandlePhysicalReg(RegOperand *op, Insn *insn, regno_t regno, bool isDef); + uint8 SetupLiveRangeByOp(Operand *op, Insn *insn, bool isDef); + void SetupLiveRangeByRegno(regno_t regno, BB *bb, uint32 currPoint); + void ComputeLiveRangesForEachOperand(Insn *insn); + void ComputeLiveRangesUpdateIfInsnIsCall(Insn *insn); + void ComputeLiveRangesUpdateLiveUnitInsnRange(BB *bb, uint32 currPoint); + void ComputeLiveRangesBmemberSize(); + void ComputeLiveOut(BB *bb); + void ComputeLiveRanges(); + MemOperand *CreateSpillMem(uint32 spillIdx); + void CheckInterference(LiveRange *lr1, LiveRange *lr2); + void BuildInterferenceGraphSeparateIntFp(std::vector &intLrVec, std::vector &fpLrVec); + void BuildInterferenceGraph(); + void SetBbInfoGlobalAssigned(uint32 bbid, regno_t regno); + bool HaveAvailableColor(LiveRange *lr, uint32 num); + void Separate(); + void SplitAndColor(); + void ColorForOptPrologEpilog(); + void SpillLiveRange(); + void ChooseColorForSpill(LiveRange *lr); + void SpillAll(); + bool IsLocalReg(regno_t regno); + bool IsLocalReg(LiveRange *lr); + void HandleLocalRaDebug(regno_t regno, LocalRegAllocator *localRa, bool isInt); + void HandleLocalRegAssignment(regno_t regno, LocalRegAllocator *localRa, bool isInt); + bool HandleLocalRegDefWithNoUse(regno_t regno, LocalRegAllocator *localRa, bool isInt, bool isDef); + void HandleLocalReg(Operand *op, LocalRegAllocator *localRa, BbAssignInfo *bbInfo, bool isDef, bool isInt); + void LocalRaRegSetEraseReg(LocalRegAllocator *localRa, regno_t regno); + bool LocalRaInitRegSet(LocalRegAllocator *localRa, uint32 bbid, bool doAllocate); + void LocalRaInitAllocatableRegs(LocalRegAllocator *localRa, uint32 bbid, bool doAllocate); + void LocalRaPrepareBb(BB *bb, LocalRegAllocator *localRa); + void LocalRaFinalAssignment(LocalRegAllocator *localRa, BbAssignInfo *bbInfo); + void LocalRaDebug(BB *bb, LocalRegAllocator *localRa); + void LocalRegisterAllocator(bool allocate); + MemOperand *GetSpillOrReuseMem(LiveRange *lr, uint32 regsize, uint8 &isOutOfRange, Insn *insn, bool isDef); + void SpillOperandForSpillPre(Insn *insn, Operand *opnd, RegOperand *phyOpnd, uint32 spillIdx, bool needSpill); + void SpillOperandForSpillPost(Insn *insn, Operand *opnd, RegOperand *phyOpnd, uint32 spillIdx, bool needSpill); + Insn *SpillOperand(Insn *insn, Operand *opnd, bool isDef, RegOperand *phyOpnd, uint32 &spillIdx); + MemOperand *GetConsistentReuseMem(uint32 vregno, uint32 size, RegType regtype); + MemOperand *GetCommonReuseMem(uint32 vregno, uint32 size, RegType regtype); + MemOperand *GetReuseMem(uint32 vregno, uint32 size, RegType regtype); + MemOperand *GetSpillMem(uint32 vregno, Insn *insn, Riscv64reg_t regno, uint8 &isOutOfRange); + bool GetAvailableSpillReg(set &cannotUseReg, LiveRange *lr, uint64 &usedRegMask); + void CollectCannotUseReg(set &cannotUseReg, LiveRange *lr, Insn *insn); + bool PickRegForSpill(LiveRange *lr, Insn *insn, uint64 &usedRegMask, bool isDef); + regno_t PickRegForLocalSpill(regno_t regno, RegType regtype, uint64 &usedRegMask); + bool GetSpillReg(Insn *insn, LiveRange *lr, uint64 &usedRegMask, bool isDef); + RegOperand *GetReplaceOpndForLRA(Insn *insn, Operand *opnd, uint32 &spillIdx, uint64 &usedRegMask, bool isDef); + RegOperand *GetReplaceOpnd(Insn *insn, Operand *opnd, uint32 &spillIdx, uint64 &usedRegMask, bool isDef); + void MarkCalleeSaveRegs(); + void MarkUsedRegs(Operand *opnd, uint64 &usedRegMask); + uint64 FinalizeRegisterPreprocess(FinalizeRegisterInfo *fInfo, Insn *insn); + void GenerateSpillFillRegs(Insn *insn); + RegOperand *CreateSpillFillCode(RegOperand *opnd, Insn *insn, uint32 spillCnt, bool isdef = false); + void SpillLiveRangeForSpills(); + void FinalizeRegisters(); + + MapleVector::iterator GetHighPriorityLr(MapleVector &lrSet); + void UpdateForbiddenForNeighbors(LiveRange *lr); + void UpdatePregvetoForNeighbors(LiveRange *lr); + regno_t FindColorForLr(LiveRange *lr); + bool ShouldUseCallee(LiveRange *lr, MapleSet &calleeUsed, MapleVector &delayed); + bool AssignColorToLr(LiveRange *lr, bool isDelayed = false); + void PruneLrForSplit(LiveRange *lr, BB *bb, bool remove, set &candidateInLoop, + set &defInLoop); + bool UseIsUncovered(BB *bb, BB *startBb); + void FindUseForSplit(LiveRange *lr, SplitBbInfo &bbInfo, bool &remove, set &candidateInLoop, + set &defInLoop); + void FindBbSharedInSplit(LiveRange *lr, set &candidateInLoop, set &defInLoop); + void ComputeBbForNewSplit(LiveRange *newLr, LiveRange *oldLr); + void ClearLrBbFlags(set &member); + void ComputeBbForOldSplit(LiveRange *newLr, LiveRange *oldLr); + bool LrCanBeColored(LiveRange *lr, BB *bbAdded, set &conflictRegs); + void MoveLrBbInfo(LiveRange *oldLr, LiveRange *newLr, BB *bb); + bool ContainsLoop(CgfuncLoops *loop, set &loops); + void GetAllLrMemberLoops(LiveRange *lr, set &loop); + bool SplitLrShouldSplit(LiveRange *lr); + bool SplitLrIsProfitable(LiveRange *newLr); + void ResetSplitLr(LiveRange *origLr, LiveRange *newLr); + bool SplitLrFindCandidateLr(LiveRange *lr, LiveRange *newLr, set &conflictRegs); + void SplitLrHandleLoops(LiveRange *lr, LiveRange *newLr, set &oldLoops, set &newLoops); + void SplitLrFixNewLrCallsAndRlod(LiveRange *newLr, set &origLoops); + void SplitLrFixOrigLrCalls(LiveRange *lr); + void SplitLrUpdateInterference(LiveRange *lr); + void SplitLrUpdateRegInfo(LiveRange *origLr, LiveRange *newLr, set &conflictRegs); + void SplitLrErrorCheckAndDebug(LiveRange *origLr, LiveRange *newLr); + LiveRange *SplitLr(LiveRange *lr); +}; + +} // namespace maplebe + +#endif // AARCH64COLORRA_H diff --git a/mapleall/maple_be/include/cg/riscv64/riscv64_dep_analysis.h b/mapleall/maple_be/include/cg/riscv64/riscv64_dep_analysis.h new file mode 100644 index 0000000..efc4698 --- /dev/null +++ b/mapleall/maple_be/include/cg/riscv64/riscv64_dep_analysis.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#ifndef AARCH64DEPANALYSIS_H +#define AARCH64DEPANALYSIS_H + +#include "dep_analysis.h" +#include "cg_func.h" + +namespace maplebe { + + +class Riscv64DepAnalysis : public DepAnalysis { + public: + Riscv64DepAnalysis(CGFunc *func, MemPool *p, bool beforeRA); + + ~Riscv64DepAnalysis() {} + + void Run(BB *bb, vector &nodes) override; + std::string GetDepTypeName(DepType depType) override; + void dumpDepNode(DepNode *node) override; + void dumpDepLink(DepLink *link, DepNode *node) override; + + protected: + void Init(BB *bb, vector &nodes) override; + void ClearAllDepData() override; + void AnalysisAmbiInsns(BB *bb) override; + void AppendRegUseList(Insn *insn, regno_t regno) override; + inline void AddDependence(DepNode* fromNode, DepNode *toNode, DepType tpy) override; + inline void RemoveSelfDeps(Insn *insn) override; + void CombineClinit(DepNode *firstNode, DepNode *secondNode, bool isAcrossSeparator) override; + void CombineDependence(DepNode *firstNode, DepNode *secondNode, bool isAcrossSeparator) override; + inline void BuildDepsUseReg(Insn *insn, regno_t regno) override; + inline void BuildDepsDefReg(Insn *insn, regno_t regno) override; + inline void BuildDepsAmbiInsn(Insn *insn) override; + inline void BuildDepsMayThrowInsn(Insn *insn) override; + void BuildDepsUseMem(Insn *insn, MemOperand * memOpnd) override; + void BuildDepsDefMem(Insn *insn, MemOperand * memOpnd) override; + void BuildDepsMemBar(Insn *insn) override; + void BuildDepsSeparator(DepNode *newSepNode, vector &nodes) override; + void BuildDepsControlAll(DepNode *depNode, vector &nodes) override; + void BuildDepsAccessStImmMem(Insn *insn, bool isDest) override; + void BuildCallerSavedDeps(Insn *insn) override; + inline void BuildDepsBetweenControlRegAndCall(Insn *insn, bool isDest) override; + void BuildStackPassArgsDeps(Insn *insn) override; + void BuildDepsDirtyStack(Insn *insn) override; + void BuildDepsUseStack(Insn *insn) override; + void BuildDepsDirtyHeap(Insn *insn) override; + DepNode *BuildSeparatorNode() override; + bool IfInAmbiRegs(regno_t regno) const override; + inline bool IsFrameReg(const RegOperand *) const override; + void AllocateRegPressure(DepNode *depNode) override; + + private: + Insn **regDefs; + RegList **regUses; + Insn *memBarInsn; + bool hasAmbiRegs; + Insn *lastCallInsn; + uint32 separatorIndex; + std::vector useRegnos; + std::vector defRegnos; + std::vector stackUses; + std::vector stackDefs; + std::vector heapUses; + std::vector heapDefs; + std::vector mayThrows; + + // instructions that can not across may throw instructions. + std::vector ambiInsns; + + // register number that catch bb and cleanup bb uses. + std::set ehInRegs; +}; + +} + +#endif //AARCH64DEPANALYSIS_H diff --git a/mapleall/maple_be/include/cg/riscv64/riscv64_ebo.h b/mapleall/maple_be/include/cg/riscv64/riscv64_ebo.h new file mode 100644 index 0000000..4459fea --- /dev/null +++ b/mapleall/maple_be/include/cg/riscv64/riscv64_ebo.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#ifndef MAPLEBE_INCLUDE_CG_AARCH64EBO_H_ +#define MAPLEBE_INCLUDE_CG_AARCH64EBO_H_ + +#include "ebo.h" +#include "riscv64_isa.h" +#include "operand.h" +#include "riscv64_operand.h" +#include "cg.h" +#include "emit.h" +#include "cg_assert.h" +#include +#include + +namespace maplebe { + +using namespace maple; +using namespace std; + +class Riscv64Ebo : public Ebo { + friend class Ebo; + + private: + void SetOpnd(Insn *insn, int i, Operand *opnd); + bool IsZeroRegister(Operand *opnd); + int32_t GetOffsetVal(MemOperand *mem) override; + bool OperandEqSpecial(Operand *op1, Operand *op2) override; + bool DoConstProp(Insn *insn, int i, Operand *opnd) override; + bool ConstantOperand(Insn *insn, Operand **opnds, OpndInfo **opndInfo) override; + bool ResoveCondBranch(Insn *insn, Operand **opnds) override; + bool RemoveRedundantLoad(BB *bb, Insn *insn, Operand **opnds, OpndInfo **opndInfo, OpndInfo **origInfo) override; + bool DeleteDupInsn(Insn *insn, OpndInfo **opndInfo, InsnInfo *insninfo) override; + bool DeleteDupMemInsn(Insn *insn, OpndInfo **opndInfo, InsnInfo *insninfo, InsnInfo *prevInfo) override; + bool IsImplicit(Insn *insn) override; + void InitCallerSaveRegisters() override; + void InitCallAndReturnUseRegisters() override; + void DefineCallerSaveRegisters(InsnInfo *insninfo) override; + void DefineReturnUseRegister(Insn *insn) override; + void DefineCallUseSpecialRegister(Insn *insn) override; + void DefineClinitSpecialRegisters(InsnInfo *insninfo) override; + bool SpecialSequence(Insn *insn, Operand **opnds, OpndInfo **origInfo) override; + bool ReplaceMovToVmov(Insn *insn, Insn *replaceInsn) override; + bool IsMovToSIMDVmov(Insn *insn, Insn *replaceInsn) override; + bool ChangeLdrMop(Insn *insn, Operand *opnd) override; + bool IsAdd(Insn *insn) override; + bool IsVecReg(Operand *opnd) override; + bool IsFmov(Insn *insn) override; + bool IsClinitCheck(Insn *insn) override; + regno_t GetLowVec(Operand *opnd) override; + regno_t GetHighVec(Operand *opnd) override; + bool IsFloatReg(RegOperand *opnd) override; + MOperator SelectMovMop(RegOperand *dstOpnd, RegOperand *srcOpnd); + + public: + explicit Riscv64Ebo(CGFunc *func, MemPool *mp, LiveAnalysis *live, bool before, const char *phase) + : Ebo(func, mp, live, before, phase), initCallerSaveRegs(false), initCallAndReturnRegs(false) {} + ~Riscv64Ebo() {} + + RegOperand *regOperand[kMaxRegNum]; + bool initCallerSaveRegs; + bool initCallAndReturnRegs; +}; +} // namespace maplebe +#endif diff --git a/mapleall/maple_be/include/cg/riscv64/riscv64_fp_simd_regs.def b/mapleall/maple_be/include/cg/riscv64/riscv64_fp_simd_regs.def new file mode 100644 index 0000000..6fce092 --- /dev/null +++ b/mapleall/maple_be/include/cg/riscv64/riscv64_fp_simd_regs.def @@ -0,0 +1,150 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +/* + ARM Compiler armasm User Guide version 6.6. + http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0473j/deb1353594352617.html + (retrieved on 3/24/2017) + */ +// ID, 128 bit vector prefix, followed by scalar prefixes +// scalar prefixes: 8-bit, 16-bit, 32-bit, 64-bit, 128-bit +// (e.g., we use D0 when V0 contains a 64-bit scalar FP number (aka, double)) +FP_SIMD_REG(0 , "V", "B", "H", "S", "D", "Q") +FP_SIMD_REG(1 , "V", "B", "H", "S", "D", "Q") +FP_SIMD_REG(2 , "V", "B", "H", "S", "D", "Q") +FP_SIMD_REG(3 , "V", "B", "H", "S", "D", "Q") +FP_SIMD_REG(4 , "V", "B", "H", "S", "D", "Q") +FP_SIMD_REG(5 , "V", "B", "H", "S", "D", "Q") +FP_SIMD_REG(6 , "V", "B", "H", "S", "D", "Q") +FP_SIMD_REG(7 , "V", "B", "H", "S", "D", "Q") +FP_SIMD_REG(8 , "V", "B", "H", "S", "D", "Q") +FP_SIMD_REG(9 , "V", "B", "H", "S", "D", "Q") +FP_SIMD_REG(10, "V", "B", "H", "S", "D", "Q") +FP_SIMD_REG(11, "V", "B", "H", "S", "D", "Q") +FP_SIMD_REG(12, "V", "B", "H", "S", "D", "Q") +FP_SIMD_REG(13, "V", "B", "H", "S", "D", "Q") +FP_SIMD_REG(14, "V", "B", "H", "S", "D", "Q") +FP_SIMD_REG(15, "V", "B", "H", "S", "D", "Q") +FP_SIMD_REG(16, "V", "B", "H", "S", "D", "Q") +FP_SIMD_REG(17, "V", "B", "H", "S", "D", "Q") +FP_SIMD_REG(18, "V", "B", "H", "S", "D", "Q") +FP_SIMD_REG(19, "V", "B", "H", "S", "D", "Q") +FP_SIMD_REG(20, "V", "B", "H", "S", "D", "Q") +FP_SIMD_REG(21, "V", "B", "H", "S", "D", "Q") +FP_SIMD_REG(22, "V", "B", "H", "S", "D", "Q") +FP_SIMD_REG(23, "V", "B", "H", "S", "D", "Q") +FP_SIMD_REG(24, "V", "B", "H", "S", "D", "Q") +FP_SIMD_REG(25, "V", "B", "H", "S", "D", "Q") +FP_SIMD_REG(26, "V", "B", "H", "S", "D", "Q") +FP_SIMD_REG(27, "V", "B", "H", "S", "D", "Q") +FP_SIMD_REG(28, "V", "B", "H", "S", "D", "Q") +FP_SIMD_REG(29, "V", "B", "H", "S", "D", "Q") +FP_SIMD_REG(30, "V", "B", "H", "S", "D", "Q") +FP_SIMD_REG(31, "V", "B", "H", "S", "D", "Q") + +FP_SIMD_EXT_BASE(32) + +// The following 32 simd are only used for differentiating +// regular 64 bit V# or upper/lower 32 bit V#. +// This is to bypass postebo which cannot distinguish between +// v#.s[0] and v#.s[1]. So creating this the same v# can +// be represented with v# and v(#+32), but are just the +// upper and lower part of the same v#. +FP_SIMD_EXT(32 , "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(33 , "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(34 , "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(35 , "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(36 , "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(37 , "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(38 , "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(39 , "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(40 , "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(41 , "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(42, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(43, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(44, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(45, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(46, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(47, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(48, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(49, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(50, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(51, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(52, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(53, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(54, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(55, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(56, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(57, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(59, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(60, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(61, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(62, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(63, "V", "B", "H", "S", "D", "Q") + +FP_SIMD_EXT_BASE(64) + +FP_SIMD_EXT(64, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(65 , "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(66 , "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(67 , "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(68 , "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(69 , "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(70 , "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(71 , "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(72 , "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(73 , "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(74 , "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(75, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(76, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(77, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(78, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(79, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(80, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(81, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(82, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(83, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(84, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(85, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(86, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(87, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(88, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(89, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(90, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(91, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(92, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(93, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(94, "V", "B", "H", "S", "D", "Q") +FP_SIMD_EXT(95, "V", "B", "H", "S", "D", "Q") + +// Alias ID +FP_SIMD_REG_ALIAS(0) +FP_SIMD_REG_ALIAS(1) +FP_SIMD_REG_ALIAS(2) +FP_SIMD_REG_ALIAS(3) +FP_SIMD_REG_ALIAS(4) +FP_SIMD_REG_ALIAS(5) +FP_SIMD_REG_ALIAS(6) +FP_SIMD_REG_ALIAS(7) + +//FP_SIMD_REG_ALIAS_64BIT_SCALAR(0) +//FP_SIMD_REG_ALIAS_64BIT_SCALAR(1) +//FP_SIMD_REG_ALIAS_64BIT_SCALAR(2) +//FP_SIMD_REG_ALIAS_64BIT_SCALAR(3) +//FP_SIMD_REG_ALIAS_64BIT_SCALAR(4) +//FP_SIMD_REG_ALIAS_64BIT_SCALAR(5) +//FP_SIMD_REG_ALIAS_64BIT_SCALAR(6) +//FP_SIMD_REG_ALIAS_64BIT_SCALAR(7) + diff --git a/mapleall/maple_be/include/cg/riscv64/riscv64_global_opt.h b/mapleall/maple_be/include/cg/riscv64/riscv64_global_opt.h new file mode 100644 index 0000000..ad91bdf --- /dev/null +++ b/mapleall/maple_be/include/cg/riscv64/riscv64_global_opt.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#ifndef MAPLEBE_INCLUDE_CG_AARCH64GLOBALOPT_H +#define MAPLEBE_INCLUDE_CG_AARCH64GLOBALOPT_H + +#include "global_opt.h" +#include "riscv64_operand.h" +#include "riscv64_isa.h" +#include + +namespace maplebe { +using namespace maple; + +class Riscv64GlobalOpt : public GlobalOpt { + private: + enum DefineType { + kRedefine, + kPredefine, + }; + + public: + explicit Riscv64GlobalOpt(CGFunc *func, MemPool *mp) : GlobalOpt(func, mp) {} + + ~Riscv64GlobalOpt() {} + + void Run() override; + void CmpCsetOptimize(); + void ConvertCselToCset(); + void DeleteRedundantUxt(); + + private: + bool FindAThroughPath(Insn *insnStart, Insn *insnEnd); + bool TraverseNext(BB *curBb, BB *target, std::set *traversedBb); + bool OnlyOneDefine(Insn *targetInsn); + void ForwardPropOfRegister(); + void BackPropOfRegister(); + void CleanDDForDestOperand(Insn *insn, unsigned short index); + bool NoOverlap(Insn *targetInsn, int opndidx, bool isBg); + static bool OpndOnlyUsedInCurBB(Insn *insn, short opndidx, bool isDest = true); + static bool OpndOnlyDefInCurBB(Insn *targetInsn, int opndidx); + void InsertDUUDForDestOperand(Insn *newInsn, short newIndex, unsigned short newProp, bool isRefInsnBeforeNewInsn); + void ReplaceInsnSrcOperand(Insn *mInsn, short i, unsigned short prop, Operand *newOpnd, Insn *defInsn); + bool HasMultiGen(Insn *newInsn); + bool IsPartialDominate(Insn *start, Insn *end, std::set *middleInsnSet); + bool TraverseDomNext(BB *start, BB *end, std::set *middleSet, std::set *traversed); + ReachingDefinition *GetRD() { + return cgfunc->GetRD(); + } + + int GetMaximumValidBit(Insn *insn, short udidx, std::set &insnChecked) const; + bool OpndDefByOne(Insn *insn, int useidx) const; + bool OpndDefByZero(Insn *insn, int useidx) const; + bool OpndDefByOneOrZero(Insn *insn, int useidx) const; + static int GetInsnValidBit(Insn *insn); + static bool InsnDefOne(Insn *insn); + static bool InsnDefZero(Insn *insn); + static bool InsnDefOneOrZero(Insn *insn); + static bool RedefPointIsExist(Insn *insn, short opndidx); + static bool IsSameReg(Operand *firstOpnd, Operand *secondOpnd); +}; + +} // namespace maplebe + +#endif // MAPLEBE_INCLUDE_CG_AARCH64GLOBALOPT_H diff --git a/mapleall/maple_be/include/cg/riscv64/riscv64_insn.h b/mapleall/maple_be/include/cg/riscv64/riscv64_insn.h new file mode 100644 index 0000000..7f83fa7 --- /dev/null +++ b/mapleall/maple_be/include/cg/riscv64/riscv64_insn.h @@ -0,0 +1,184 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#ifndef MAPLEBE_INCLUDE_CG_AARCH64INSN_H +#define MAPLEBE_INCLUDE_CG_AARCH64INSN_H + +#include "riscv64_isa.h" +#include "insn.h" +#include "riscv64_operand.h" +namespace maplebe { + +class Riscv64Insn : public Insn { + public: + explicit Riscv64Insn(MOperator opc, Operand *opnd0 = nullptr, Operand *opnd1 = nullptr, Operand *opnd2 = nullptr, + Operand *opnd3 = nullptr, Operand *opnd4 = nullptr) + : Insn(opc, opnd0, opnd1, opnd2, opnd3, opnd4) {} + + Riscv64Insn &operator=(const Riscv64Insn &p) = default; + + Riscv64Insn(const Riscv64Insn &originalInsn) + : Insn(originalInsn.mop_, originalInsn.opnds[0], originalInsn.opnds[1], originalInsn.opnds[2], + originalInsn.opnds[3], originalInsn.opnds[4]) { + prev = originalInsn.prev; + next = originalInsn.next; + bb = originalInsn.bb; + flags = originalInsn.flags; + mop_ = originalInsn.mop_; + for (int i = 0; i < kMaxOperandNum; i++) { + if (originalInsn.opnds[i] == nullptr) { + opnds[i] = nullptr; + } else { + opnds[i] = originalInsn.opnds[i]->Clone(CG::curCgFunc->memPool); + } + } + } + + ~Riscv64Insn() {} + + bool IsReturn() override { + return GetMachineOpcode() == MOP_xret; + } + + bool IsFixedInsn() override { + return (GetMachineOpcode() == MOP_clinit || GetMachineOpcode() == MOP_clinit_tail); + } + + bool IsComment() override { + return GetMachineOpcode() == MOP_comment; + } + + bool IsImmaterialInsn() override { + return (dynamic_cast(this) || GetMachineOpcode() == MOP_comment); + } + + bool IsMachineInstruction() override { + MOperator mop = GetMachineOpcode(); + return (MOP_undef < mop && mop < MOP_comment); + } + + bool IsPseudoInstruction() override { + MOperator mop = GetMachineOpcode(); + return (mop >= MOP_pseudo_first && mop <= MOP_pseudo_last); + } + + bool IsEffectiveCopy() override { + return CopyOperands() >= 0; + } + + int32_t GetResultNum() override; + int32_t GetOpndNum() override; + Operand *GetResult(int32_t i) override; + Operand *GetOpnd(int32_t i) override; + Operand *GetResultMemOpnd() override; + Operand *GetMemOpnd() override; + void SetOpnd(int32_t i, Operand *opnd) override; + int32_t CopyOperands() override; + bool IsGlobal() override final { + return GetMachineOpcode() == MOP_adrp || GetMachineOpcode() == MOP_adrpl12; + } + + bool IsCall() override final; + bool IsTailCall() const override final; + bool IsClinit() override final; + bool CanThrow() override final; + bool IsIndirectCall() override final { + return GetMachineOpcode() == MOP_xblr; + } + + bool IsCallToFunctionThatNeverReturns() override final; + bool MayThrow() override final; + bool IsBranch() override final; + bool IsMove() override final; + bool IsLoad() override final; + bool IsLoadStorePair(); + bool IsStore() override final; + bool IsLoadPair() override final; + bool IsStorePair() override final; + bool IsLoadAddress() override final; + bool IsAtomic() override final; + bool IsYieldpoint() override; + bool IsVolatile() override; + bool IsFallthruCall() override final { + return (GetMachineOpcode() == MOP_xblr || GetMachineOpcode() == MOP_xbl); + } + bool IsMemAccessBar() override; + bool IsMemAccess() override; + + Operand *GetCallTargetOperand() override { + CG_ASSERT(IsCall(), ""); + return GetOperand(0); + } + + ListOperand *GetCallArgumentOperand() override { + CG_ASSERT(IsCall(), ""); + CG_ASSERT(GetOperand(1)->IsList(), ""); + return static_cast(GetOperand(1)); + } + + bool IsDMBInsn() const override; + + void Emit(CG &, Emitter &) override; + + void dump() override; + + bool Check() override; + + // dfa + bool IsDefinition() const override; + + bool IsDestRegAlsoSrcReg() const override; + + bool IsDataMoveInstruction() const override; + + bool IsConversionInstruction() const override; + + bool IsConditionalSet() const override; + + RegOperand *GetOperandDefined() override; + + bool IsPartDef() const override; + + uint32 GetLatencyType() const override; + + int GetJumpTargetIdx() const override; + + private: + void CheckOpnd(Operand *opnd, OpndProp *mopd); + void EmitClinit(CG &, Emitter &); + void EmitAdrpLdr(CG &, Emitter &); + void EmitClinitTail(CG &, Emitter &); + void EmitAdrpLabel(CG &, Emitter &); + void EmitCheckThrowPendingException(CG &, Emitter &); +}; + +class Riscv64cleancallInsn : public Riscv64Insn { + public: + int ref_skipindex; + explicit Riscv64cleancallInsn(MOperator opc, Operand *opnd0 = nullptr, Operand *opnd1 = nullptr, + Operand *opnd2 = nullptr, Operand *opnd3 = nullptr, Operand *opnd4 = nullptr) + : Riscv64Insn(opc, opnd0, opnd1, opnd2, opnd3, opnd4), ref_skipindex(-1) {} + + Riscv64cleancallInsn &operator=(const Riscv64cleancallInsn &p) = default; + + Riscv64cleancallInsn(const Riscv64cleancallInsn &originalInsn) : Riscv64Insn(originalInsn) { + ref_skipindex = originalInsn.ref_skipindex; + } + ~Riscv64cleancallInsn() {} +}; + +} // namespace maplebe + +#endif // MAPLEBE_INCLUDE_CG_AARCH64INSN_H diff --git a/mapleall/maple_be/include/cg/riscv64/riscv64_int_regs.def b/mapleall/maple_be/include/cg/riscv64/riscv64_int_regs.def new file mode 100644 index 0000000..68e8eda --- /dev/null +++ b/mapleall/maple_be/include/cg/riscv64/riscv64_int_regs.def @@ -0,0 +1,76 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +/* + ARM Compiler armasm User Guide version 6.6. + http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0473j/deb1353594352617.html + (retrieved on 3/24/2017) + + $ 4.1 Registers in Riscv64 state + + There is no register named W31 or X31. + Depending on the instruction, register 31 is either the stack + pointer or the zero register. When used as the stack pointer, + you refer to it as "SP". When used as the zero register, you refer + to it as WZR in a 32-bit context or XZR in a 64-bit context. + The zero register returns 0 when read and discards data when + written (e.g., when setting the status register for testing). + */ +// ID, 32-bit prefix, 64-bit prefix +INT_REG(0 , "", "X") +INT_REG(1 , "", "X") +INT_REG(2 , "", "X") +INT_REG(3 , "", "X") +INT_REG(4 , "", "X") +INT_REG(5 , "", "X") +INT_REG(6 , "", "X") +INT_REG(7 , "", "X") +INT_REG(8 , "", "X") +INT_REG(9 , "", "X") +INT_REG(10, "", "X") +INT_REG(11, "", "X") +INT_REG(12, "", "X") +INT_REG(13, "", "X") +INT_REG(14, "", "X") +INT_REG(15, "", "X") +INT_REG(16, "", "X") +INT_REG(17, "", "X") +INT_REG(18, "", "X") +INT_REG(19, "", "X") +INT_REG(20, "", "X") +INT_REG(21, "", "X") +INT_REG(22, "", "X") +INT_REG(23, "", "X") +INT_REG(24, "", "X") +INT_REG(25, "", "X") +INT_REG(26, "", "X") +INT_REG(27, "", "X") +INT_REG(28, "", "X") +INT_REG(29, "", "X") +INT_REG(30, "", "X") +INT_REG(31, "", "X") + +// Alias ID, ID, 32-bit prefix, 64-bit prefix +INT_REG_ALIAS(ZERO, 0, "", "" ) +INT_REG_ALIAS(RA, 1, "", "" ) +INT_REG_ALIAS(SP, 2, "", "" ) +INT_REG_ALIAS(GP, 3, "", "" ) +INT_REG_ALIAS(TP, 4, "", "" ) +INT_REG_ALIAS(FP, 8, "", "" ) + +// R19 is reserved for yieldpoint +INT_REG_ALIAS(YP, 0, "", "" ) + +INT_REG_ALIAS(LAST_INT_REG, 31, "", "" ) diff --git a/mapleall/maple_be/include/cg/riscv64/riscv64_isa.h b/mapleall/maple_be/include/cg/riscv64/riscv64_isa.h new file mode 100644 index 0000000..413c110 --- /dev/null +++ b/mapleall/maple_be/include/cg/riscv64/riscv64_isa.h @@ -0,0 +1,400 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#ifndef MAPLEBE_INCLUDE_CG_AARCH64ISA_H +#define MAPLEBE_INCLUDE_CG_AARCH64ISA_H + +#include "isa.h" +#include "insn.h" +#include "operand.h" +#include "mad.h" + +#define DEFINE_MOP(op,a2,a3,a4,a5,a6,a7,a8,a9,aa,ab,ac) op, +enum Riscv64MOP_t { +#include "riscv64_md.def" + kMopLast +}; +#undef DEFINE_MOP + +namespace maplebe { + +/* + ARM Architecture Reference Manual (for ARMv8) + D1.8.2 + */ +#define RISCV64_STACK_PTR_ALIGNMENT 16 + +static const int kIntregBytelen = 8; /* 64-bit */ +static const int kFpregBytelen = 8; /* only lower 64 bits are used */ +static const int kSimdregBytelen = 16; /* 128-bit */ + +#define STP_LDP_IMM64_LOWER_BOUND -2048 +#define STP_LDP_IMM64_UPPER_BOUND 2048 +#define STP_LDP_IMM32_LOWER_BOUND -2048 +#define STP_LDP_IMM32_UPPER_BOUND 2048 + +#define STR_LDR_PRE_POST_LOWER_BOUND -256 +#define STR_LDR_PRE_POST_UPPER_BOUND 255 +#define STRALL_LDRALL_IMM_LOWER_BOUND 0 +#define STR_LDR_IMM32_UPPER_BOUND 2040 /* must be a multiple of 4 */ +#define STR_LDR_IMM64_UPPER_BOUND 2040 /* must be a multiple of 8 */ +#define STRB_LDRB_IMM_UPPER_BOUND 4095 +#define STRH_LDRH_IMM_UPPER_BOUND 8190 + +/* + Riscv64 Condition Code Suffixes + */ +enum Riscv64CC_t { +#define CONDCODE(a) CC_##a, +#include "riscv64_cc.def" +#undef CONDCODE + kCcLast +}; + +/* + ARM Compiler armasm User Guide version 6.6. + http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0473j/deb1353594352617.html + (retrieved on 3/24/2017) + + $ 4.1 Registers in Riscv64 state + ...When you use the 32-bit form of an instruction, the upper + 32 bits of the source registers are ignored and + the upper 32 bits of the destination register are set to zero. + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + There is no register named W31 or X31. + Depending on the instruction, register 31 is either the stack + pointer or the zero register. When used as the stack pointer, + you refer to it as "SP". When used as the zero register, you refer + to it as WZR in a 32-bit context or XZR in a 64-bit context. + The zero register returns 0 when read and discards data when + written (e.g., when setting the status register for testing). + */ +enum Riscv64reg_t { + kRinvalid = INVALID_REGNO, +// integer registers +#define INT_REG(ID, PREF32, PREF64) R##ID, +#define INT_REG_ALIAS(ALIAS, ID, PREF32, PREF64) +#include "riscv64_int_regs.def" +#undef INT_REG +#undef INT_REG_ALIAS +// fp-simd registers +#define FP_SIMD_REG(ID, PV, P8, P16, P32, P64, P128) V##ID, +#define FP_SIMD_EXT_BASE(ID) VB##ID, +#define FP_SIMD_EXT(ID, PV, P8, P16, P32, P64, P128) V##ID, +#define FP_SIMD_REG_ALIAS(ID) +#include "riscv64_fp_simd_regs.def" +#undef FP_SIMD_REG +#undef FP_SIMD_EXT_BASE +#undef FP_SIMD_EXT +#undef FP_SIMD_REG_ALIAS + kMaxRegNum, +// alias +#define INT_REG(ID, PREF32, PREF64) +#define INT_REG_ALIAS(ALIAS, ID, PREF32, PREF64) R##ALIAS = R##ID, +#include "riscv64_int_regs.def" +#undef INT_REG +#undef INT_REG_ALIAS +#define FP_SIMD_REG(ID, PV, P8, P16, P32, P64, P128) +#define FP_SIMD_EXT_BASE(ID) +#define FP_SIMD_EXT(ID, PV, P8, P16, P32, P64, P128) +#define FP_SIMD_REG_ALIAS(ID) S##ID = V##ID, +#include "riscv64_fp_simd_regs.def" +#undef FP_SIMD_REG +#undef FP_SIMD_EXT_BASE +#undef FP_SIMD_EXT +#undef FP_SIMD_REG_ALIAS +#define FP_SIMD_REG(ID, PV, P8, P16, P32, P64, P128) +#define FP_SIMD_EXT_BASE(ID) +#define FP_SIMD_EXT(ID, PV, P8, P16, P32, P64, P128) +#define FP_SIMD_REG_ALIAS(ID) D##ID = V##ID, +#include "riscv64_fp_simd_regs.def" +#undef FP_SIMD_REG +#undef FP_SIMD_EXT_BASE +#undef FP_SIMD_EXT +#undef FP_SIMD_REG_ALIAS +}; + +namespace Riscv64isa { + +static inline bool IsGPRegister(Riscv64reg_t r) { + return (R0 <= r && r <= R31); +} + +static inline bool IsFPSIMDRegister(Riscv64reg_t r) { + return (V0 <= r && r <= V31); +} + +static inline bool IsPhysicalRegister(regno_t r) { + return r < kMaxRegNum; +} + +static inline bool IsArgumentPassingRegister(regno_t r) { + return (R0 <= r && r <= R7) || (V0 <= r && r <= V7); +} + +static inline RegType GetRegType(Riscv64reg_t r) { + if (IsGPRegister(r)) { + return kRegTyInt; + } else if (IsFPSIMDRegister(r)) { + return kRegTyFloat; + } else { + CG_ASSERT(0, "No suitable register type to return?"); + return kRegTyUndef; + } +} + +enum memory_ordering_t : uint32_t { + kMoNone = 0, + kMoAcquire = (1UL << 0), // ARMv8 + kMoAcquireRcpc = (1UL << 1), // ARMv8.3 + kMoLoacquire = (1UL << 2), // ARMv8.1 + kMoRelease = (1UL << 3), // ARMv8 + kMoLorelease = (1UL << 4) // ARMv8.1 +}; + +} // namespace Riscv64isa + +#define MAXREG kMaxRegNum + +#define REGPROPUNDEF 0 +#define REGPROPDEF 0x1 +#define REGPROPUSE 0x2 +#define REGHIGH 0x4 +#define REGLOW 0x8 +#define MEMLOW12 0x10 +#define LITERAL_LOW12 MEMLOW12 +#define PREINC 0x20 +#define POSTINC 0x40 +#define LOADLITERAL 0x80 + +enum SubRegType{ + kSubRegTyUndef, + kSubRegTyInt32, + kSubRegTyInt64, + kSubRegTyFloat32, + kSubRegTyFloat64, +}; + +struct RegProp { + RegType regtype_ : 8; + SubRegType subRegType : 8; + Riscv64reg_t physical_reg_; + uint32 def_use_; // used for register use/define and other properties of other operand + RegProp(RegType t, SubRegType subt, Riscv64reg_t r, uint32 d) : regtype_(t), + subRegType(subt), physical_reg_(r), def_use_(d) {} +}; + +struct Riscv64OpndProp : public OpndProp { + Operand::OperandType opnd_ty_; + RegProp regprop_; + uint8 size_; + + Riscv64OpndProp(Operand::OperandType t, RegProp p, uint8 s) : opnd_ty_(t), regprop_(p), size_(s) {} + + bool IsPhysicalRegister() { + return opnd_ty_ == Operand::Opd_Register && regprop_.physical_reg_ < kMaxRegNum; + } + + bool IsRegister() { + return opnd_ty_ == Operand::Opd_Register; + } + + bool IsRegDef() { + return opnd_ty_ == Operand::Opd_Register && (regprop_.def_use_ & REGPROPDEF); + } + + bool IsRegUse() { + return opnd_ty_ == Operand::Opd_Register && (regprop_.def_use_ & REGPROPUSE); + } + + bool IsRegHigh() { + return opnd_ty_ == Operand::Opd_Register && (regprop_.def_use_ & REGHIGH); + } + + bool IsRegLow() { + return opnd_ty_ == Operand::Opd_Register && (regprop_.def_use_ & REGLOW); + } + + bool IsMemLow12() { + return opnd_ty_ == Operand::Opd_Mem && (regprop_.def_use_ & MEMLOW12); + } + + bool IsLiteralLow12() { + return opnd_ty_ == Operand::Opd_StImmediate && (regprop_.def_use_ & LITERAL_LOW12); + } + + bool IsMemPreIndex() { + return opnd_ty_ == Operand::Opd_Mem && (regprop_.def_use_ & PREINC); + } + + bool IsMemPostIndex() { + return opnd_ty_ == Operand::Opd_Mem && (regprop_.def_use_ & POSTINC); + } + + bool IsDef() { + return regprop_.def_use_ & REGPROPDEF; + } + + bool IsUse() { + return regprop_.def_use_ & REGPROPUSE; + } + + bool IsLoadLiteral() { + return (regprop_.def_use_ & LOADLITERAL); + } + + uint32 GetOperandSize() { + return static_cast(size_); + } +}; + +struct Riscv64MD { + MOperator opc_; + OpndProp *operand_[5]; + uint64 properties_; + LatencyType latencyType; + const char *name_; + const char *format_; + int32_t resnum; + int32_t opndnum; + + bool UseSpecReg() const { + return properties_ & USESPECREG; + } + + bool IsCall() const { + return properties_ & ISCALL; + } + + bool CanThrow() const { + return properties_ & CANTHROW; + } + + inline Riscv64OpndProp *GetOperand(int nth) const { + CG_ASSERT(nth < 5, ""); + return static_cast(operand_[nth]); + } + + inline uint32 GetOperandSize() const { + if (properties_ & (ISLOAD | ISSTORE)) + // use memory operand + { + return (GetOperand(1)->GetOperandSize()); + } else + // use dest operand + { + return (GetOperand(0)->GetOperandSize()); + } + } + + inline bool Is64Bit() const { + return (GetOperandSize() == 64); + } + + inline bool IsVector() const { + return (GetOperandSize() == 128); + } + + inline bool IsVolatile() const { + return (((properties_ & HASRELEASE) != 0) || ((properties_ & HASACQUIRE) != 0)); + } + + inline bool IsMemAccessBar() const { + return ((properties_ & (HASRELEASE | HASACQUIRE | HASACQUIRERCPC | HASLOACQUIRE | HASLORELEASE)) != 0); + } + + inline bool IsMemAccess() const { + return ((properties_ & (ISLOAD | ISSTORE | ISLOADPAIR | ISSTOREPAIR)) != 0); + } + + inline bool IsBranch() const { + return ((properties_ & (ISBRANCH)) != 0); + } + + inline bool IsMove() const { + return ((properties_ & (ISMOVE)) != 0); + } + + inline bool IsDMB() const { + return ((properties_ & (ISDMB)) != 0); + } + + inline bool IsLoad() const { + return ((properties_ & (ISLOAD)) != 0); + } + + inline bool IsStore() const { + return ((properties_ & (ISSTORE)) != 0); + } + + inline bool IsLoadPair() const { + return ((properties_ & (ISLOADPAIR)) != 0); + } + + inline bool IsStorePair() const { + return ((properties_ & (ISSTOREPAIR)) != 0); + } + + inline bool IsLoadStorePair() const { + return ((properties_ & (ISLOADPAIR | ISSTOREPAIR)) != 0); + } + + inline bool IsLoadAddress() const { + return ((properties_ & (ISLOADADDR)) != 0); + } + + inline bool IsAtomic() const { + return ((properties_ & ISATOMIC) != 0); + } + + inline bool IsCondDef() const { + return (properties_ & ISCONDDEF); + } + + inline bool IsPartDef() const { + return (properties_ & ISPARTDEF); + } + + inline int32_t GetResultNum() { + return resnum; + } + + inline int32_t GetOpndsNum() { + return opndnum; + } + + LatencyType GetLatencyType() const { + return latencyType; + } +}; + +/* + We save callee-saved registers from lower stack area to upper stack area. + If possible, we store a pair of registers (int/int and fp/fp) in the stack. + The Stack Pointer has to be aligned at 16-byte boundary. + On Riscv64, kIntregBytelen == 8 (see the above) + */ +static inline void GetNextOffsetCalleeSavedPair(int &offset) { + offset += kIntregBytelen * 2; +} + +static inline void GetNextOffsetCalleeSaved(int &offset) { + offset += kIntregBytelen; +} + +} // namespace maplebe + +#endif // MAPLEBE_INCLUDE_CG_AARCH64ISA_H diff --git a/mapleall/maple_be/include/cg/riscv64/riscv64_isa_def.in b/mapleall/maple_be/include/cg/riscv64/riscv64_isa_def.in new file mode 100644 index 0000000..290c47e --- /dev/null +++ b/mapleall/maple_be/include/cg/riscv64/riscv64_isa_def.in @@ -0,0 +1,498 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +MOP_Tbadcrrr, +MOP_Tbaddrri8, +MOP_Tbaddrri3s, +MOP_Tbaddri8, +MOP_Tbaddrrr, +MOP_Tbadd64rrrs, +MOP_Tbadd64rris, +MOP_Tbaddrrlh, +MOP_Tbaddrrhl, +MOP_Tbaddrrhh, +MOP_Tbaddpcrel, +MOP_Tbaddsprel, +MOP_Tbaddspi7, +MOP_Tbandrr, +MOP_Tbasrrri5, +MOP_Tbasrsrrr, +MOP_Tbbcond, +MOP_Tbbuncond, +MOP_Tbbicrr, +MOP_Tbbkpt, +MOP_Tbbl, +MOP_Tbblx2, +MOP_Tbbl1, +MOP_Tbbl2, +MOP_Tbblxr, +MOP_Tbbx, +MOP_Tbcmnrr, +MOP_Tbcmpri8, +MOP_Tbcmprr, +MOP_Tbcmplh, +MOP_Tbcmphl, +MOP_Tbcmphh, +MOP_Tbeorrr, +MOP_Tbldmia, +MOP_Tbldwb, +MOP_Tbld64l, +MOP_Tbld64h, +MOP_Tbldrbrri5, +MOP_Tbldrb, +MOP_Tbldrhrri5, +MOP_Tbldrh, +MOP_Tbldrsb, +MOP_Tbldrsh, +MOP_Tblslrri5, +MOP_Tblslsrrr, +MOP_Tblsrrri5, +MOP_Tblsrsrrr, +MOP_Tbmovimm8, +MOP_Tbmovrr, +MOP_Tbmovrr_h2h, +MOP_Tbmovrr_l2l, +MOP_Tbmovrr_l2h, +MOP_Tbmov64ri12h, +MOP_Tbmov64ri12l, +MOP_Tbmul, +MOP_Tbmvn, +MOP_Tbmvn64i12l, +MOP_Tbmvn64i12h, +MOP_Tborr, +MOP_Tbpop, +MOP_Tbpush, +MOP_Tbrev, +MOP_Tbrevsh, +MOP_Tbrorrr, +MOP_Tbsbc, +MOP_Tbstmia, +MOP_Tbstr, +MOP_Tbstrsprel, +MOP_Tbstrbrri5, +MOP_Tbstrb, +MOP_Tbstrhrri5, +MOP_Tbstrh, +MOP_Tbsubrri3, +MOP_Tbsubri8, +MOP_Tbsubspi7, +MOP_Tbswi, +MOP_Tbtst, +MOP_Tb2vldrs, +MOP_Tb2vldrd, +MOP_Tb2vmuls, +MOP_Tb2vmuld, +MOP_Tb2vmlas, +MOP_Tb2vmlad, +MOP_Tb2vmlss, +MOP_Tb2vmlsd, +MOP_Tb2vstrs, +MOP_Tb2vstrd, +MOP_Tb2vsubs, +MOP_Tb2vsubd, +MOP_Tb2vadds, +MOP_Tb2vaddd, +MOP_Tb2vdivs, +MOP_Tb2vdivd, +MOP_Tb2vmlaf64, +MOP_Tb2vcvtif, +MOP_Tb2vcvtuf, +MOP_Tb2vcvtid, +MOP_Tb2vcvtud, +MOP_Tb2vcvtfi, +MOP_Tb2vcvtfu, +MOP_Tb2vcvtdi, +MOP_Tb2vcvtdu, +MOP_Tb2vcvtfd, +MOP_Tb2vcvtdf, +MOP_Tb2vcvtf64s32, +MOP_Tb2vcvtf64u32, +MOP_Tb2vsqrts, +MOP_Tb2vsqrtd, +MOP_Tb2movimm8, +MOP_Tb2movi8m, +MOP_Tb2movimm12, +MOP_Tb2strrri12, +MOP_Tb2ldrrri12, +MOP_Tb2strrri8predec, +MOP_Tb2ldrrri8predec, +MOP_Tb2cbnz, +MOP_Tb2cbz, +MOP_Tb2addrri12, +MOP_Tb2movrr, +MOP_Tb2vmovs, +MOP_Tb2vmovd, +MOP_Tb2vmovsc, +MOP_Tb2vmovdc, +MOP_Tb2ldmia, +MOP_Tb2stmia, +MOP_Tb2addrrr, +MOP_Tb2subrrr, +MOP_Tb2sbcrrr, +MOP_Tb2cmprr, +MOP_Tb2subrri12, +MOP_Tb2mvni12, +MOP_Tb2sel, +MOP_Tb2ubfx, +MOP_Tb2sbfx, +MOP_Tb2ldrrrr, +MOP_Tb2ldrhrrr, +MOP_Tb2ldrsh, +MOP_Tb2ldrbrrr, +MOP_Tb2ldrsbrrr, +MOP_Tb2strrrr, +MOP_Tb2strh, +MOP_Tb2strb, +MOP_Tb2ldrhrri12, +MOP_Tb2ldrshrri12, +MOP_Tb2ldrbrri12, +MOP_Tb2ldrsbrri12, +MOP_Tb2strhrri12, +MOP_Tb2strbrri12, +MOP_Tb2pop, +MOP_Tb2push, +MOP_Tb2cmpri8m, +MOP_Tb2cmnri8m, +MOP_Tb2adc64rrr, +MOP_Tb2adc64rri, +MOP_Tb2orr64lrrr, +MOP_Tb2orr64hrrr, +MOP_Tb2and64lrrr, +MOP_Tb2and64hrrr, +MOP_Tb2bicrrr, +MOP_Tb2cmnrr, +MOP_Tb2mulrrr, +MOP_Tb2sdivrrr, +MOP_Tb2udivrrr, +MOP_Tb2mvnrr, +MOP_Tb2rsubrri8, +MOP_Tb2rsubsrri8, +MOP_Tb2tstrr, +MOP_Tb2lslrrr, +MOP_Tb2lsrrrr, +MOP_Tb2asrrrr, +MOP_Tb2rorrrr, +MOP_Tb2lslrri5, +MOP_Tb2lsrrri5, +MOP_Tb2asrrri5, +MOP_Tb2rorrri5, +MOP_Tb2bicrri8m, +MOP_Tbandrri8, +MOP_Tbandrri8l, +MOP_Tbandrri8h, +MOP_Tb2andrri8m, +MOP_Tborrri8l, +MOP_Tborrri8h, +MOP_Tborrri8, +MOP_Tb2orrrri8m, +MOP_Tb2addrri8m, +MOP_Tb2adcrri8m, +MOP_Tb2subsrri8, +MOP_Tb2sbcrri8m, +MOP_Tb2revrr, +MOP_Tb2revshrr, +MOP_Tb2it, +MOP_Tb2fmstat, +MOP_Tb2vcmpd, +MOP_Tb2vcmps, +MOP_Tb2ldrpcrel12, +MOP_Tb2bcond, +MOP_Tb2fmrs, +MOP_Tb2fmsr, +MOP_Tb2fmrrd, +MOP_Tb2fmdrr, +MOP_Tb2vabsd, +MOP_Tb2vabss, +MOP_Tb2vmovs_imm8, +MOP_Tb2vmovd_imm8, +MOP_Tb2mla, +MOP_Tb2mls, +MOP_Tb2umull, +MOP_Tb2ldrex, +MOP_Tb2ldrexd, +MOP_Tb2strex, +MOP_Tb2strexd, +MOP_Tb2clrex, +MOP_Tb2bfi, +MOP_Tb2bfc, +MOP_Tb2dmb, +MOP_Tb2ldrpcreln12, +MOP_Tb2stm, +MOP_Tbundefined, +MOP_Tb2vpopcs, +MOP_Tb2vpushcs, +MOP_Tb2vldms, +MOP_Tb2vstms, +MOP_Tb2buncond, +MOP_Tb2movimm16h, +MOP_Tb2movimm16l, +MOP_Tb2addpcr, +MOP_Tb2adr, +MOP_Tb2movimm16lst, +MOP_Tb2movimm16hst, +MOP_Tb2ldmiawb, +MOP_Tb2orrsrrr, +MOP_Tb2push1, +MOP_Tb2pop1, +MOP_Tb2rsubrrr, +MOP_Tb2smull, +MOP_Tb2ldrd, +MOP_Tb2strd, +MOP_beq, +MOP_bne, +MOP_blt, +MOP_ble, +MOP_bgt, +MOP_bge, +MOP_blo, +MOP_bls, +MOP_bhs, +MOP_bhi, +MOP_bpl, +MOP_Tb2mul64rlh, +MOP_Tb2mla64rhlr, +MOP_Tb2umull64rrll, +MOP_Tb2mov64lr, +MOP_Tb2add64hrr, +MOP_Tbrsbmiri, +MOP_Tbitle, +MOP_Tbitls, +MOP_Tbitlt, +MOP_Tbitcc, +MOP_Tbitge, +MOP_Tbitcs, +MOP_Tbitgt, +MOP_Tbithi, +MOP_Tbitmi, +MOP_Tbiteq, +MOP_Tbitne, +MOP_Tbitpl, +MOP_Tbittpl, +MOP_Tbitele, +MOP_Tbitels, +MOP_Tbitelt, +MOP_Tbitecc, +MOP_Tbitege, +MOP_Tbitecs, +MOP_Tbitegt, +MOP_Tbitehi, +MOP_Tbitemi, +MOP_Tbiteeq, +MOP_Tbitene, +MOP_Tbitepl, +MOP_Tb2asrplrrr, +MOP_Tb2orrplrrr, +MOP_Tb2moveqimm12, +MOP_Tb2movneimm12, +MOP_Tb2movleimm12, +MOP_Tb2movlsimm12, +MOP_Tb2movltimm12, +MOP_Tb2movccimm12, +MOP_Tb2movgeimm12, +MOP_Tb2movcsimm12, +MOP_Tb2movgtimm12, +MOP_Tb2movhiimm12, +MOP_Tb2movmiimm12, +MOP_Tb2movplimm12, +MOP_Tb2moveqrr, +MOP_Tb2fconsts, +MOP_Tb2fconstd, +MOP_xret, +MOP_Tbxmovrr, +MOP_Tbxmovri32, +MOP_Tbxmovri64, +MOP_Tbxvmovsr, +MOP_Tbxvmovdr, +MOP_Tbxvmovrs, +MOP_Tbxvmovrd, +MOP_Tbxvmovs, +MOP_Tbxvmovd, +MOP_Tbxadrp, +MOP_Tbxadrpl12, +MOP_xaddrrr, +MOP_xaddrrrs, +MOP_xaddrri24, +MOP_waddrrr, +MOP_waddrrrs, +MOP_waddrri24, +MOP_dadd, +MOP_sadd, + +MOP_xsubrrr, +MOP_xsubrrrs, +MOP_xsubrri24, +MOP_wsubrrr, +MOP_wsubrrrs, +MOP_wsubrri24, +MOP_dsub, +MOP_ssub, + +MOP_Tbxmulrrr, +MOP_Tbxvmuls, +MOP_Tbxvmuld, +MOP_Tbxsxtb32, +MOP_Tbxsxtb64, +MOP_Tbxsxth32, +MOP_Tbxsxth64, +MOP_Tbxsxtw64, +MOP_Tbxuxtb32, +MOP_Tbxuxth32, +MOP_Tbxuxtw64, +MOP_Tbxvcvtfd, +MOP_Tbxvcvtdf, +MOP_Tbvcvtrf, +MOP_Tbxvcvtrf, +MOP_Tbvcvturf, +MOP_Tbxvcvturf, +MOP_Tbvcvtas, +MOP_Tbxvcvtas, +MOP_Tbvcvtms, +MOP_Tbxvcvtms, +MOP_Tbvcvtps, +MOP_Tbxvcvtps, +MOP_Tbvcvtrd, +MOP_Tbxvcvtrd, +MOP_Tbvcvturd, +MOP_Tbxvcvturd, +MOP_Tbvcvtfr, +MOP_Tbxvcvtfr, +MOP_Tbvcvtufr, +MOP_Tbxvcvtufr, +MOP_Tbvcvtdr, +MOP_Tbxvcvtdr, +MOP_Tbvcvtudr, +MOP_Tbxvcvtudr, + +MOP_hcmperi, +MOP_hcmperr, +MOP_scmperi, +MOP_scmperr, +MOP_dcmperi, +MOP_dcmperr, + +MOP_hcmpqri, +MOP_hcmpqrr, +MOP_scmpqri, +MOP_scmpqrr, +MOP_dcmpqri, +MOP_dcmpqrr, + +MOP_wcmpri, +MOP_wcmprr, +MOP_xcmpri, +MOP_xcmprr, + +MOP_wccmpriic, +MOP_wccmprric, +MOP_xccmpriic, +MOP_xccmprric, + +MOP_wcselrrrc, +MOP_xcselrrrc, + +MOP_wcsetrc, +MOP_xcsetrc, + +MOP_wcsincrrrc, +MOP_xcsincrrrc, +MOP_wcsinvrrrc, +MOP_xcsinvrrrc, + +MOP_xandrrr, +MOP_xandrrrs, +MOP_xandrri13, +MOP_wandrrr, +MOP_wandrrrs, +MOP_wandrri12, +MOP_xiorrrr, +MOP_xiorrrrs, +MOP_xiorrri13, +MOP_wiorrrr, +MOP_wiorrrrs, +MOP_wiorrri12, +MOP_xeorrrr, +MOP_xeorrrrs, +MOP_xeorrri13, +MOP_weorrrr, +MOP_weorrrrs, +MOP_weorrri12, +MOP_weorrri8m, +MOP_xnotrr, +MOP_wfmaxrrr, +MOP_xfmaxrrr, +MOP_wfminrrr, +MOP_xfminrrr, +MOP_wsdivrrr, +MOP_xsdivrrr, +MOP_wudivrrr, +MOP_xudivrrr, +MOP_wmsubrrrr, +MOP_xmsubrrrr, +MOP_wubfxrri5i5, +MOP_xubfxrri6i6, +MOP_wsbfxrri5i5, +MOP_xsbfxrri6i6, +MOP_wubfizrri5i5, +MOP_xubfizrri6i6, +MOP_xlslrri6, +MOP_xasrrri6, +MOP_xlsrrri6, +MOP_xlslrrr, +MOP_xasrrrr, +MOP_xlsrrrr, +MOP_wsfmovrr, +MOP_swfmovrr, +MOP_xdfmovrr, +MOP_dxfmovrr, +MOP_wcsnegrrrc, +MOP_xcsnegrrrc, +MOP_habsrr, +MOP_sabsrr, +MOP_dabsrr, +MOP_winegrr, +MOP_xinegrr, +MOP_wfnegrr, +MOP_xfnegrr, +MOP_hdivrrr, +MOP_sdivrrr, +MOP_ddivrrr, +MOP_hcselrrrc, +MOP_scselrrrc, +MOP_dcselrrrc, +MOP_wldli, +MOP_xldli, +MOP_xbr, +MOP_xblr, +MOP_wldr, +MOP_xldr, +MOP_sldr, +MOP_dldr, +MOP_wstr, +MOP_xstr, +MOP_sstr, +MOP_dstr, +MOP_wstp, +MOP_xstp, +MOP_sstp, +MOP_dstp, +MOP_wldp, +MOP_xldp, +MOP_xldpsw, +MOP_sldp, +MOP_dldp, +MOP_wmovkri16, +MOP_xmovkri16, +MOP_comment, + diff --git a/mapleall/maple_be/include/cg/riscv64/riscv64_live_analysis.h b/mapleall/maple_be/include/cg/riscv64/riscv64_live_analysis.h new file mode 100644 index 0000000..7c3e27b --- /dev/null +++ b/mapleall/maple_be/include/cg/riscv64/riscv64_live_analysis.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#ifndef AARCH64LIVEANALYSIS_H +#define AARCH64LIVEANALYSIS_H + +#include "live_analysis.h" + +namespace maplebe { + +class Riscv64LiveAnalysis : public LiveAnalysis { + public: + uint32 subBBId; + + explicit Riscv64LiveAnalysis(CGFunc *func, MemPool *mp) + : LiveAnalysis(func, mp), + subBBId(func->NumBBs()) {} + + ~Riscv64LiveAnalysis() {} + + regno_t UpdateRegNum(RegOperand *opnd); + void CollectLiveInfo(BB *bb, Operand *opnd, bool isDef, bool isUse); + BB* CreateSubBB(BB *bb); + bool CanInsnThrow(Insn *insn); + void GetInsnDefUse(BB *bb, Insn *insn); + void BreakBBIntoSubBB(BB *bb); + void GetBBDefUse(BB *bb) override; + bool CleanupBBIgnoreReg(uint32 reg) override; + void FinalizeLiveAnalysis() override; + void InitEhDefine(BB *bb) override; +}; + +} // namespace maplebe + +#endif /* AARCH64LIVEANALYSIS_H */ diff --git a/mapleall/maple_be/include/cg/riscv64/riscv64_lvar.h b/mapleall/maple_be/include/cg/riscv64/riscv64_lvar.h new file mode 100644 index 0000000..9e136fd --- /dev/null +++ b/mapleall/maple_be/include/cg/riscv64/riscv64_lvar.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#ifndef MAPLEBE_INCLUDE_CG_AARCH64LVAR_H +#define MAPLEBE_INCLUDE_CG_AARCH64LVAR_H + +#include "cg_func.h" +#include "lvar.h" +#include "riscv64_operand.h" +#include + +namespace maplebe { + +using namespace std; + +class Iinfo; + +class Riscv64OptLocalRef : public OptLocalRef { + static const int32 kMaxTraceLen = 100; + static const int32 kMaxNumTraces = 2000; + + MapleAllocator olr_allocator; + uint32 min_imm; // smallest local ref imm pre-opt + uint32 max_imm; // largest local ref imm pre-opt + uint32 max_assigned; // post-opt largest imm + uint32 num_traces; + uint32 rc_stack_init_start_loc; // mrt-init call R0 + uint32 rc_localrefvar_slots; // mrt-init call R1 + MapleSet rc_cleanup_skip_num; // mrt-cleanupskip R2 + MapleVector imm_operands; // mem operands used by local ref + MapleVector visited_bbs; + MapleVector sorted_bbs; + MapleStack dfs_bbs; + MapleStack bb_walkback; + MapleList bb_trace; // trace used for opt + MapleStack rc_init_call; // mrt-init + MapleStack rc_cleanup_call; // mrt-cleanup + MapleStack rc_skip_call; // mrt-cleanupskip + MapleVector insn_info_in_bb; // list of localref insn for bb + MapleSet xzr_init_local_offset; // offset of 0 init for localref + MapleSet ld_st_pair_offset; + MapleSet other_opnd; // other memory opnd requires patching + + bool has_rc_init; + bool has_rc_cleanup; + bool giveup; // for some reason, do not opt + + private: + void PrintBbTraceList(string str, bool more = false); + + bool DetectCycle(); + bool CfgHasCycle(); + bool IsLdStLocalRefVar(Operand *opnd); + void ModifyParamValue(Insn *insn, uint32 reg, uint32 val); + uint32 GetParamValue(Insn *insn, uint32 reg); + void HandleCleanupBB(BB *bb); + bool IsRcStackCall(Insn *insn); + bool IsLdStPair(Insn *insn); + bool RecordXzrInit(Insn *insn); + void RecordLdStPair(Insn *insn); + bool CanGetMemOpndImm(Operand *opnd, int32 &imm); + bool ImmOffUsedInXzrInit(int32 imm); + bool ImmOffUsedInLdStPair(int32 imm); + void RemoveImmUsedInSkip(); + void RemoveImmUsedInLdSt(); + void OptLRInit(); + void OptLRFini(); + bool CanRenameConflictSlot(int32 imm); + void AssignLocalRefForTrace(); + void DFS(); + void DoOptimize(); + void FinalizeLocRef(); + void FixMrtCall(); + + public: + explicit Riscv64OptLocalRef(CGFunc *func, MemPool *mp) + : OptLocalRef(func, mp), + olr_allocator(mp), + min_imm(0x0fffffff), + max_imm(0), + max_assigned(0), + num_traces(0), + rc_stack_init_start_loc(0), + rc_localrefvar_slots(0), + rc_cleanup_skip_num(olr_allocator.Adapter()), + imm_operands(olr_allocator.Adapter()), + visited_bbs(olr_allocator.Adapter()), + sorted_bbs(olr_allocator.Adapter()), + dfs_bbs(olr_allocator.Adapter()), + bb_walkback(olr_allocator.Adapter()), + bb_trace(olr_allocator.Adapter()), + rc_init_call(olr_allocator.Adapter()), + rc_cleanup_call(olr_allocator.Adapter()), + rc_skip_call(olr_allocator.Adapter()), + insn_info_in_bb(olr_allocator.Adapter()), + xzr_init_local_offset(olr_allocator.Adapter()), + ld_st_pair_offset(olr_allocator.Adapter()), + other_opnd(olr_allocator.Adapter()), + has_rc_init(false), + has_rc_cleanup(false), + giveup(false) {} + + ~Riscv64OptLocalRef() {} + + void DoOptLocalRef() override; +}; + +class Iinfo { + public: + Insn *insn; + int32 imm; + int32 assigned; + Iinfo *next; + + Iinfo(Insn *insn, int32 imm) : insn(insn), imm(imm), assigned(0), next(nullptr) {} + virtual ~Iinfo() {} +}; + +} // namespace maplebe +#endif // MAPLEBE_INCLUDE_CG_AARCH64LVAR_H diff --git a/mapleall/maple_be/include/cg/riscv64/riscv64_md.def b/mapleall/maple_be/include/cg/riscv64/riscv64_md.def new file mode 100644 index 0000000..8a22639 --- /dev/null +++ b/mapleall/maple_be/include/cg/riscv64/riscv64_md.def @@ -0,0 +1,578 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +// MOP_undef, +DEFINE_MOP(MOP_undef, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"","", 0, 0) + +// # Definitions + +// MOVES +// MOP_xmovrr +DEFINE_MOP(MOP_xmovrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtAlu,"mv","0,1", 1, 1) +// MOP_wmovrr +DEFINE_MOP(MOP_wmovrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtAlu,"mv","0,1", 1, 1) +// MOP_xmovrrr last reg operand is not emitted +DEFINE_MOP(MOP_xmovrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},ISMOVE,kLtAlu,"mv","0,1", 1, 1) +// MOP_wmovrrr last reg operand is not emitted +DEFINE_MOP(MOP_wmovrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISMOVE,kLtAlu,"mv","0,1", 1, 1) +// MOP_xmovri64 +DEFINE_MOP(MOP_xmovri64, {MOPD_Reg64ID,MOPD_Imm64,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtAlu,"li","0,1", 1, 1) + +// MOP_wmov20up +DEFINE_MOP(MOP_xmov20up, {MOPD_Reg32ID,MOPD_Imm32,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtShift,"lui","0,1", 1, 1) +// MOP_xmov52up +DEFINE_MOP(MOP_xmov52up, {MOPD_Reg64ID,MOPD_Imm64,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtShift,"lui","0,1", 1, 1) + + +// MOP_xvmovsr +DEFINE_MOP(MOP_xvmovsr, {MOPD_Reg32FD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtR2f,"fmv.s.w","0,1", 1, 1) +// MOP_xvmovdr +DEFINE_MOP(MOP_xvmovdr, {MOPD_Reg64FD,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtR2f,"fmv.d.x","0,1", 1, 1) +// MOP_xvmovrs +DEFINE_MOP(MOP_xvmovrs, {MOPD_Reg32ID,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtF2r,"fmv.w.s","0,1", 1, 1) +// MOP_xvmovrd +DEFINE_MOP(MOP_xvmovrd, {MOPD_Reg64ID,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtF2r,"fmv.x.d","0,1", 1, 1) +// MOP_xvmovs +DEFINE_MOP(MOP_xvmovs, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtFpalu,"fmv.s","0,1", 1, 1) +// MOP_xvmovd +DEFINE_MOP(MOP_xvmovd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtFpalu,"fmv.d","0,1", 1, 1) +// MOP_xvmovss last reg operand is not emitted +DEFINE_MOP(MOP_xvmovss, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},ISMOVE,kLtFpalu,"fmv.s","0,1", 1, 1) +// MOP_xvmovdd last reg operand is not emitted +DEFINE_MOP(MOP_xvmovdd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},ISMOVE,kLtFpalu,"fmv.d","0,1", 1, 1) + +// Vector SIMD mov +// MOP_vmovrr +DEFINE_MOP(MOP_vmovrr, {MOPD_Reg128FD,MOPD_Reg128FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtFpalu,"err","0,1", 1, 1) +// Vector SIMD dup +DEFINE_MOP(MOP_vdupi32, {MOPD_Reg128FD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtFpalu,"err","0,1", 1, 1) +DEFINE_MOP(MOP_vdupi64, {MOPD_Reg128FD,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtFpalu,"err","0,1", 1, 1) +DEFINE_MOP(MOP_vdupf32, {MOPD_Reg128FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtFpalu,"err","0,1", 1, 1) +DEFINE_MOP(MOP_vdupf64, {MOPD_Reg128FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtFpalu,"err","0,1", 1, 1) + +// MOP_adrp // riscv64 load label address high +DEFINE_MOP(MOP_adrp, {MOPD_Reg64ID,MOPD_Literal,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOADADDR,kLtShift,"lui","0,1", 1, 1) +// MOP_laddr // riscv64 load label address +DEFINE_MOP(MOP_laddr, {MOPD_Reg64ID,MOPD_Literal,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOADADDR,kLtShift,"la","0,1", 1, 1) +// MOP_xadr (Java) +DEFINE_MOP(MOP_xadri64, {MOPD_Reg64ID,MOPD_Imm64,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOADADDR,kLtShift,"err","0,1", 1, 1) +// MOP_adrpl12 // riscv64 add label address low +DEFINE_MOP(MOP_adrpl12, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Literal_L12,MOPD_Undef,MOPD_Undef},0,kLtAlu,"addi","0,1,2", 1, 2) + +// Vector SIMD add +// MOP_vaddf32rrr Arithmetic: add +DEFINE_MOP(MOP_vaddf32rrr, {MOPD_Reg128FD, MOPD_Reg128FS, MOPD_Reg128FS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"err","0,1,2", 1, 2) +// MOP_vaddf64rrr Arithmetic: add +DEFINE_MOP(MOP_vaddf64rrr, {MOPD_Reg128FD, MOPD_Reg128FS, MOPD_Reg128FS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"err","0,1,2", 1, 2) +// MOP_vadd32rrr Arithmetic: add +DEFINE_MOP(MOP_vadd32rrr, {MOPD_Reg128ID,MOPD_Reg128IS,MOPD_Reg128IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"err","0,1,2", 1, 2) +// MOP_vadd64rrr Arithmetic: add +DEFINE_MOP(MOP_vadd64rrr, {MOPD_Reg128LD,MOPD_Reg128LS,MOPD_Reg128LS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"err","0,1,2", 1, 2) + +// MOP_xaddrrr Arithmetic: add +DEFINE_MOP(MOP_xaddrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"add","0,1,2", 1, 2) +// MOP_xaddrri12 +DEFINE_MOP(MOP_xaddrri12, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,kLtAlu,"addi","0,1,2", 1, 2) +// MOP_waddrrr +DEFINE_MOP(MOP_waddrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"addw","0,1,2", 1, 2) +// MOP_waddrri12 +DEFINE_MOP(MOP_waddrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,kLtAlu,"addiw","0,1,2", 1, 2) +// MOP_dadd +DEFINE_MOP(MOP_dadd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fadd.d","0,1,2", 1, 2) +// MOP_sadd +DEFINE_MOP(MOP_sadd, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fadd.s","0,1,2", 1, 2) + +// MOP_xsubrrr Arithmetic: sub +DEFINE_MOP(MOP_xsubrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"sub","0,1,2", 1, 2) +// MOP_xsubrri12 +DEFINE_MOP(MOP_xsubrri12, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,kLtAlu,"subi","0,1,2", 1, 2) +// MOP_wsubrrr +DEFINE_MOP(MOP_wsubrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"subw","0,1,2", 1, 2) +// MOP_wsubrri12 +DEFINE_MOP(MOP_wsubrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,kLtAlu,"subiw","0,1,2", 1, 2) +// MOP_dsub +DEFINE_MOP(MOP_dsub, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fsub.d","0,1,2", 1, 2) +// MOP_ssub +DEFINE_MOP(MOP_ssub, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fsub.s","0,1,2", 1, 2) + +// Arithmetic: multiply +// MOP_Tbxmulrrr +DEFINE_MOP(MOP_xmulrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtMul,"mul","0,1,2", 1, 2) +// MOP_Tbxvmuls +DEFINE_MOP(MOP_xvmuls, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,kLtFpmul,"fmul.s","0,1,2", 1, 2) +// MOP_Tbxvmuld +DEFINE_MOP(MOP_xvmuld, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,kLtFpmul,"fmul.d","0,1,2", 1, 2) + +// Conversions +// MOP_xsxtw64 +DEFINE_MOP(MOP_xsxtw64, {MOPD_Reg64ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtAluShift,"sext.w","0,1", 1, 1) +// variable bits sign extension, expanded to MOP_xlslrri6 and MOP_xasrrri6 +DEFINE_MOP(MOP_xsxtv64, {MOPD_Reg64ID,MOPD_Reg32IS,MOPD_Imm6,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtAluShift,"#vsext.w","0,1,2", 1, 2) + +// variable bits zero extension, expanded to MOP_xlslrri6 and MOP_xlsrrri6 +DEFINE_MOP(MOP_xuxtv64, {MOPD_Reg64ID,MOPD_Reg32IS,MOPD_Imm6,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtAluShift,"#vuxtw","0,1", 1, 1) + +// MOP_xvcvtfd +DEFINE_MOP(MOP_xvcvtfd, {MOPD_Reg32FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtFpalu,"fcvt.s.d","0,1", 1, 1) +// MOP_xvcvtdf +DEFINE_MOP(MOP_xvcvtdf, {MOPD_Reg64FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtFpalu,"fcvt.d.s","0,1", 1, 1) + +// MOP_vcvtrf fcvt.w.s w,s +DEFINE_MOP(MOP_vcvtrf, {MOPD_Reg32ID,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvt.w.s","0,1", 1, 1) +// MOP_vcvturf fcvt.wu.s w,s +DEFINE_MOP(MOP_vcvturf, {MOPD_Reg32ID,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvt.wu.s","0,1", 1, 1) +// MOP_xvcvtrf fcvt.l.s x,s +DEFINE_MOP(MOP_xvcvtrf, {MOPD_Reg64ID,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvt.l.s","0,1", 1, 1) +// MOP_xvcvturf fcvt.lu.s x,s +DEFINE_MOP(MOP_xvcvturf, {MOPD_Reg64ID,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvt.lu.s","0,1", 1, 1) +// MOP_vcvtrd fcvt.w.d w,d +DEFINE_MOP(MOP_vcvtrd, {MOPD_Reg32ID,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvt.w.d","0,1", 1, 1) +// MOP_vcvturd fcvt.wu.d w,d +DEFINE_MOP(MOP_vcvturd, {MOPD_Reg32ID,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvt.wu.d","0,1", 1, 1) +// MOP_xvcvtrd fcvt.l.d x,d +DEFINE_MOP(MOP_xvcvtrd, {MOPD_Reg64ID,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvt.l.d","0,1", 1, 1) +// MOP_xvcvturd fcvt.lu.d x,d +DEFINE_MOP(MOP_xvcvturd, {MOPD_Reg64ID,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvt.lu.d","0,1", 1, 1) + +// MOP_vcvtfr fcvt.s.w s,w +DEFINE_MOP(MOP_vcvtfr, {MOPD_Reg32FD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtR2fCvt,"fcvt.s.w","0,1", 1, 1) +// MOP_vcvtufr fcvt.s.wu s,w +DEFINE_MOP(MOP_vcvtufr, {MOPD_Reg32FD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtR2fCvt,"fcvt.s.wu","0,1", 1, 1) +// MOP_xvcvtfr fcvt.s.l s,x +DEFINE_MOP(MOP_xvcvtfr, {MOPD_Reg32FD,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtR2fCvt,"fcvt.s.l","0,1", 1, 1) +// MOP_xvcvtufr fcvt.s.lu s,x +DEFINE_MOP(MOP_xvcvtufr, {MOPD_Reg32FD,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtR2fCvt,"fcvt.s.lu","0,1", 1, 1) +// MOP_vcvtdr fcvt.d.w d,w +DEFINE_MOP(MOP_vcvtdr, {MOPD_Reg64FD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtR2fCvt,"fcvt.d.w","0,1", 1, 1) +// MOP_vcvtudr fcvt.d.wu d,w +DEFINE_MOP(MOP_vcvtudr, {MOPD_Reg64FD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtR2fCvt,"fcvt.d.wu","0,1", 1, 1) +// MOP_xvcvtdr fcvt.d.l d,x +DEFINE_MOP(MOP_xvcvtdr, {MOPD_Reg64FD,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtR2fCvt,"fcvt.d.l","0,1", 1, 1) +// MOP_xvcvtudr fcvt.d.lu d,x +DEFINE_MOP(MOP_xvcvtudr, {MOPD_Reg64FD,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtR2fCvt,"fcvt.d.lu","0,1", 1, 1) + +// MOP_xandrrr +DEFINE_MOP(MOP_xandrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"and","0,1,2", 1, 2) +// MOP_xandrri13 +DEFINE_MOP(MOP_xandrri13, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm13,MOPD_Undef,MOPD_Undef},0,kLtAlu,"andi","0,1,2", 1, 2) + +// MOP_xiorrrr +DEFINE_MOP(MOP_xiorrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"or","0,1,2", 1, 2) +// MOP_xiorrri13 +DEFINE_MOP(MOP_xiorrri13, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm13,MOPD_Undef,MOPD_Undef},0,kLtAlu,"ori","0,1,2", 1, 2) + +// MOP_xeorrrr +DEFINE_MOP(MOP_xeorrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"xor","0,1,2", 1, 2) +// MOP_xeorrri13 +DEFINE_MOP(MOP_xeorrri13, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm13,MOPD_Undef,MOPD_Undef},0,kLtAlu,"xori","0,1,2", 1, 2) + +// MOP_xnotrr +DEFINE_MOP(MOP_xnotrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtAlu,"not","0,1", 1, 1) + +// MOP_wfmaxrrr +DEFINE_MOP(MOP_wfmaxrrr, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fmax.s","0,1,2", 1, 2) +// MOP_xfmaxrrr +DEFINE_MOP(MOP_xfmaxrrr, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fmax.d","0,1,2", 1, 2) +// MOP_wfminrrr +DEFINE_MOP(MOP_wfminrrr, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fmin.s","0,1,2", 1, 2) +// MOP_xfminrrr +DEFINE_MOP(MOP_xfminrrr, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fmin.d","0,1,2", 1, 2) + +// MOP_wsdivrrr +DEFINE_MOP(MOP_wsdivrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},CANTHROW,kLtDiv,"divw","0,1,2", 1, 2) +// MOP_xsdivrrr +DEFINE_MOP(MOP_xsdivrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},CANTHROW,kLtDiv,"div","0,1,2", 1, 2) +// MOP_wudivrrr +DEFINE_MOP(MOP_wudivrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},CANTHROW,kLtDiv,"divuw","0,1,2", 1, 2) +// MOP_xudivrrr +DEFINE_MOP(MOP_xudivrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},CANTHROW,kLtDiv,"divu","0,1,2", 1, 2) + +// MOP_wsremrrr +DEFINE_MOP(MOP_wsremrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},CANTHROW,kLtDiv,"remw","0,1,2", 1, 2) +// MOP_xsremrrr +DEFINE_MOP(MOP_xsremrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},CANTHROW,kLtDiv,"rem","0,1,2", 1, 2) +// MOP_wuremrrr +DEFINE_MOP(MOP_wuremrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},CANTHROW,kLtDiv,"remuw","0,1,2", 1, 2) +// MOP_xuremrrr +DEFINE_MOP(MOP_xuremrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},CANTHROW,kLtDiv,"remu","0,1,2", 1, 2) + +// MOP_xlslrri6,--- Logical Shift Left +DEFINE_MOP(MOP_xlslrri6, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm6,MOPD_Undef,MOPD_Undef},0,kLtAluShift,"slli","0,1,2", 1, 2) +// MOP_wlslrri5 +DEFINE_MOP(MOP_wlslrri5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,kLtAluShift,"slliw","0,1,2", 1, 2) +// MOP_xasrrri6, +DEFINE_MOP(MOP_xasrrri6, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm6,MOPD_Undef,MOPD_Undef},0,kLtAluShift,"srai","0,1,2", 1, 2) +// MOP_wasrrri5 +DEFINE_MOP(MOP_wasrrri5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,kLtAluShift,"sraiw","0,1,2", 1, 2) +// MOP_xlsrrri6, +DEFINE_MOP(MOP_xlsrrri6, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm6,MOPD_Undef,MOPD_Undef},0,kLtAluShift,"srli","0,1,2", 1, 2) +// MOP_wlsrrri5 +DEFINE_MOP(MOP_wlsrrri5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,kLtAluShift,"srliw","0,1,2", 1, 2) +// MOP_xlslrrr, +DEFINE_MOP(MOP_xlslrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAluShiftReg,"sll","0,1,2", 1, 2) +// MOP_wlslrrr +DEFINE_MOP(MOP_wlslrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,kLtAluShiftReg,"sllw","0,1,2", 1, 2) +// MOP_xasrrrr, +DEFINE_MOP(MOP_xasrrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAluShiftReg,"sra","0,1,2", 1, 2) +// MOP_wasrrrr +DEFINE_MOP(MOP_wasrrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,kLtAluShiftReg,"sraw","0,1,2", 1, 2) +// MOP_xlsrrrr, +DEFINE_MOP(MOP_xlsrrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAluShiftReg,"srl","0,1,2", 1, 2) +// MOP_wlsrrrr +DEFINE_MOP(MOP_wlsrrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,kLtAluShiftReg,"srlw","0,1,2", 1, 2) + +// MOP_xslt +DEFINE_MOP(MOP_xslt, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"slt","0,1,2", 1, 2) +// MOP_xsltu -- 1 if rs1 < rs2 else 0 +DEFINE_MOP(MOP_xsltu, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"sltu","0,1,2", 1, 2) +// MOP_xslti +DEFINE_MOP(MOP_xslti, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,kLtAlu,"slti","0,1,2", 1, 2) +// MOP_xsltiu +DEFINE_MOP(MOP_xsltiu, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,kLtAlu,"sltiu","0,1,2", 1, 2) +// MOP_xsgt +DEFINE_MOP(MOP_xsgt, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"sgt","0,1,2", 1, 2) +// MOP_xsgtu +DEFINE_MOP(MOP_xsgtu, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"sgtu","0,1,2", 1, 2) +// MOP_xseqz +DEFINE_MOP(MOP_xseqz, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtAlu,"seqz","0,1", 1, 1) +// MOP_xsnez +DEFINE_MOP(MOP_xsnez, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtAlu,"snez","0,1", 1, 1) + +// MOP_sabsrr +DEFINE_MOP(MOP_sabsrr, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fabs.s","0,1", 1, 1) +// MOP_dabsrr +DEFINE_MOP(MOP_dabsrr, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fabs.d","0,1", 1, 1) + +// neg i32 +DEFINE_MOP(MOP_winegrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtAlu,"negw","0,1", 1, 1) +// neg i64 +DEFINE_MOP(MOP_xinegrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtAlu,"neg","0,1", 1, 1) +// neg f32 +DEFINE_MOP(MOP_wfnegrr, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fneg.s","0,1", 1, 1) +// neg f64 +DEFINE_MOP(MOP_xfnegrr, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fneg.d","0,1", 1, 1) + +// MOP_sdivrrr +DEFINE_MOP(MOP_sdivrrr, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},CANTHROW,kLtAdvsimdDivS,"fdiv.s","0,1,2", 1, 2) +// MOP_ddivrrr +DEFINE_MOP(MOP_ddivrrr, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},CANTHROW,kLtAdvsimdDivD,"fdiv.d","0,1,2", 1, 2) + +// branches/calls +// MOP_xbl -- branch with link (call); this is a special definition +DEFINE_MOP(MOP_xbl, {MOPD_FuncName,MOPD_LISTS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCALL|CANTHROW,kLtBranch,"call","0", 0, 2) +// MOP_xblr -- branch with link (call) to register; this is a special definition +DEFINE_MOP(MOP_xblr, {MOPD_Reg64IS,MOPD_LISTS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCALL|CANTHROW,kLtBranch,"jalr","0", 0, 2) + +// LOADS +// MOP_wldrsb --- Load Register Signed Byte +DEFINE_MOP(MOP_wldrsb, {MOPD_Reg32ID,MOPD_Mem8S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtLoad1,"lb","0,1", 1, 1) +// MOP_wldrb --- Load Register Unsigned Byte +DEFINE_MOP(MOP_wldrb, {MOPD_Reg32ID,MOPD_Mem8S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtLoad1,"lbu","0,1", 1, 1) +// MOP_wldrsh --- Load Register Signed Halfword +DEFINE_MOP(MOP_wldrsh, {MOPD_Reg32ID,MOPD_Mem16S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtLoad1,"lh","0,1", 1, 1) +// MOP_wldrh --- Load Register Unsigned Halfword +DEFINE_MOP(MOP_wldrh, {MOPD_Reg32ID, MOPD_Mem16S, MOPD_Undef, MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtLoad1,"lhu","0,1", 1, 1) +// MOP_wldrsw --- Load Register Signed word +DEFINE_MOP(MOP_wldrsw, {MOPD_Reg32ID,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtLoad1,"lw","0,1", 1, 1) +// MOP_wldr --- Load Register Unsigned word +DEFINE_MOP(MOP_wldr, {MOPD_Reg32ID,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtLoad1,"lwu","0,1", 1, 1) +// MOP_xldr +DEFINE_MOP(MOP_xldr, {MOPD_Reg64ID,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtLoad2,"ld","0,1", 1, 1) + +DEFINE_MOP(MOP_sldr, {MOPD_Reg32FD,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtFLoadMany,"flw","0,1", 1, 1) +// MOP_dldr +DEFINE_MOP(MOP_dldr, {MOPD_Reg64FD,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtFLoadMany,"fld","0,1", 1, 1) +// MOP_vldr +DEFINE_MOP(MOP_vldr, {MOPD_Reg128FD,MOPD_Mem128S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtFLoadMany,"err","0,1", 1, 1) + +// Load exclusive with/without acquire semantics +DEFINE_MOP(MOP_wldxr, {MOPD_Reg32ID,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|ISATOMIC|CANTHROW,kLtUndef,"err","0,1", 1, 1) +DEFINE_MOP(MOP_xldxr, {MOPD_Reg64ID,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|ISATOMIC|CANTHROW,kLtUndef,"err","0,1", 1, 1) + +DEFINE_MOP(MOP_wldaxr, {MOPD_Reg32ID,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|ISATOMIC|HASACQUIRE|CANTHROW,kLtUndef,"err","0,1", 1, 1) +DEFINE_MOP(MOP_xldaxr, {MOPD_Reg64ID,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|ISATOMIC|HASACQUIRE|CANTHROW,kLtUndef,"err","0,1", 1, 1) + +DEFINE_MOP(MOP_wldaxp, {MOPD_Reg32ID,MOPD_Reg32ID,MOPD_Mem32S,MOPD_Undef,MOPD_Undef},ISLOAD|ISLOADPAIR|ISATOMIC|HASACQUIRE|CANTHROW,kLtUndef,"err","0,1,2", 2, 1) +DEFINE_MOP(MOP_xldaxp, {MOPD_Reg64ID,MOPD_Reg64ID,MOPD_Mem64S,MOPD_Undef,MOPD_Undef},ISLOAD|ISLOADPAIR|ISATOMIC|HASACQUIRE|CANTHROW,kLtUndef,"err","0,1,2", 2, 1) + +// MOP_vsqrts +DEFINE_MOP(MOP_vsqrts, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},CANTHROW,kLtAdvsimdDivS,"fsqrt.s","0,1", 1, 1) +// MOP_vsqrtd +DEFINE_MOP(MOP_vsqrtd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},CANTHROW,kLtAdvsimdDivD,"fsqrt.d","0,1", 1, 1) + + +// # Non Definitions +// # As far as register allocation is concerned, the instructions below are non-definitions. + +// MOP_beq +DEFINE_MOP(MOP_beq, {MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Label,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"beq","0,1,2", 0, 3) +// MOP_bne +DEFINE_MOP(MOP_bne, {MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Label,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bne","0,1,2", 0, 3) +// MOP_blt +DEFINE_MOP(MOP_blt, {MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Label,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"blt","0,1,2", 0, 3) +// MOP_ble +DEFINE_MOP(MOP_ble, {MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Label,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"ble","0,1,2", 0, 3) +// MOP_bgt +DEFINE_MOP(MOP_bgt, {MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Label,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bgt","0,1,2", 0, 3) +// MOP_bge +DEFINE_MOP(MOP_bge, {MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Label,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bge","0,1,2", 0, 3) + +// compare against zero +DEFINE_MOP(MOP_beqz, {MOPD_Reg64IS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"beqz","0,1", 0, 2) +DEFINE_MOP(MOP_bnez, {MOPD_Reg64IS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bnez","0,1", 0, 2) +DEFINE_MOP(MOP_bltz, {MOPD_Reg64IS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bltz","0,1", 0, 2) +DEFINE_MOP(MOP_blez, {MOPD_Reg64IS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"blez","0,1", 0, 2) +DEFINE_MOP(MOP_bgtz, {MOPD_Reg64IS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bgtz","0,1", 0, 2) +DEFINE_MOP(MOP_bgez, {MOPD_Reg64IS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bgez","0,1", 0, 2) + +// MOP_blo equal to MOP_blt for unsigned comparison +DEFINE_MOP(MOP_blo, {MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Label,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bltu","0,1,2", 0, 3) +// MOP_bls equal to MOP_ble for unsigned comparison +DEFINE_MOP(MOP_bls, {MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Label,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bleu","0,1,2", 0, 3) +// MOP_bhs equal to MOP_bge for unsigned comparison +DEFINE_MOP(MOP_bhs, {MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Label,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bgeu","0,1,2", 0, 3) + +// MOP_bhi equal to MOP_bgt for float comparison +DEFINE_MOP(MOP_bhi, {MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Label,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bgtu","0,1,2", 0, 3) +// MOP_bpl equal to MOP_bge for float comparison +DEFINE_MOP(MOP_bpl, {MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bpl","0", 0, 1) + +// MOP_xret +DEFINE_MOP(MOP_xret, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},CANTHROW,kLtBranch,"ret","", 0, 0) + +// Floating-Point COMPARES signaling versions + +// MOP_scmperi +DEFINE_MOP(MOP_scmperi, {MOPD_Reg32FS,MOPD_FPZeroImm8,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"err","0,1", 0, 2) +// MOP_scmperr +DEFINE_MOP(MOP_scmperr, {MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"err","0,1", 0, 2) + +// MOP_scmp*rr for eq, gt, lt, ge, le +DEFINE_MOP(MOP_scmpeqrr, {MOPD_Reg64ID,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"feq.s","0,1,2", 1, 2) +DEFINE_MOP(MOP_scmpgtrr, {MOPD_Reg64ID,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fgt.s","0,1,2", 1, 2) +DEFINE_MOP(MOP_scmpltrr, {MOPD_Reg64ID,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"flt.s","0,1,2", 1, 2) +DEFINE_MOP(MOP_scmpgerr, {MOPD_Reg64ID,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fge.s","0,1,2", 1, 2) +DEFINE_MOP(MOP_scmplerr, {MOPD_Reg64ID,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fle.s","0,1,2", 1, 2) + +// MOP_dcmperi -- Riscv64 cmp has no dest operand +DEFINE_MOP(MOP_dcmperi, {MOPD_Reg64FS,MOPD_FPZeroImm8,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"err","0,1", 0, 2) +// MOP_dcmperr +DEFINE_MOP(MOP_dcmperr, {MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"err","0,1", 0, 2) + +// MOP_dcmp*rr for eq, gt, lt, ge, le +DEFINE_MOP(MOP_dcmpeqrr, {MOPD_Reg64ID,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"feq.d","0,1,2", 1, 2) +DEFINE_MOP(MOP_dcmpgtrr, {MOPD_Reg64ID,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fgt.d","0,1,2", 1, 2) +DEFINE_MOP(MOP_dcmpltrr, {MOPD_Reg64ID,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"flt.d","0,1,2", 1, 2) +DEFINE_MOP(MOP_dcmpgerr, {MOPD_Reg64ID,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fge.d","0,1,2", 1, 2) +DEFINE_MOP(MOP_dcmplerr, {MOPD_Reg64ID,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fle.d","0,1,2", 1, 2) + +// Floating-Point COMPARES non-signaling (quiet) versions + +// MOP_scmpqri -- Riscv64 cmp has no dest operand +DEFINE_MOP(MOP_scmpqri, {MOPD_Reg32FS,MOPD_FPZeroImm8,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"err","0,1", 0, 2) +// MOP_scmpqrr +DEFINE_MOP(MOP_scmpqrr, {MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"err","0,1", 0, 2) + +// MOP_dcmpqri +DEFINE_MOP(MOP_dcmpqri, {MOPD_Reg64FS,MOPD_FPZeroImm8,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"err","0,1", 0, 2) +// MOP_dcmpqrr +DEFINE_MOP(MOP_dcmpqrr, {MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"err","0,1", 0, 2) + +// Integer COMPARES +// MOP_wcmpri +DEFINE_MOP(MOP_wcmpri, {MOPD_Reg32IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtAlu,"err","0,1", 0, 2) +// MOP_wcmprr +DEFINE_MOP(MOP_wcmprr, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtAlu,"err","0,1", 0, 2) +// MOP_xcmpri +DEFINE_MOP(MOP_xcmpri, {MOPD_Reg64IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtAlu,"err","0,1", 0, 2) +// MOP_xcmprr +DEFINE_MOP(MOP_xcmprr, {MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtAlu,"err","0,1", 0, 2) + +// Riscv64 branches +// MOP_xbr -- branch to register +DEFINE_MOP(MOP_xbr, {MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"jr","0", 0, 1) +// MOP_Tbbuncond +DEFINE_MOP(MOP_xuncond, {MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"j","0", 0, 1) + +// RISCV64 STORES +// MOP_wstrb -- Store Register Byte +DEFINE_MOP(MOP_wstrb, {MOPD_Reg32IS,MOPD_Mem8D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtStore1,"sb","0,1", 1, 1) +// MOP_wstrh -- Store Register Halfword +DEFINE_MOP(MOP_wstrh, {MOPD_Reg32IS,MOPD_Mem16D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtStore1,"sh","0,1", 1, 1) +// MOP_wstr -- Store Register Word +DEFINE_MOP(MOP_wstr, {MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtStore1,"sw","0,1", 1, 1) +// MOP_xstr -- Store Register Double word +DEFINE_MOP(MOP_xstr, {MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtStore2,"sd","0,1", 1, 1) + +// MOP_sstr -- Store Register SIMD/FP Float +DEFINE_MOP(MOP_sstr, {MOPD_Reg32FS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtStore2,"fsw","0,1", 1, 1) +// MOP_dstr -- Store Register SIMD/FP Double +DEFINE_MOP(MOP_dstr, {MOPD_Reg64FS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtStore3plus,"fsd","0,1", 1, 1) + +// MOP_vstr -- Store Register SIMD +DEFINE_MOP(MOP_vstr, {MOPD_Reg128FS,MOPD_Mem128D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtStore2,"err","0,1", 1, 1) + + +// Store with Release semantics +// MOP_wstlr -- Store-Release Register Word +DEFINE_MOP(MOP_wstlr, {MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"err","0,1", 1, 1) +// MOP_xstlr -- Store-Release Register Double word +DEFINE_MOP(MOP_xstlr, {MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"err","0,1", 1, 1) + +// Store with LORelease semantics +// MOP_wstllr -- Store-LORelease Register Word +DEFINE_MOP(MOP_wstllr, {MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASLORELEASE|CANTHROW,kLtUndef,"err","0,1", 1, 1) +// MOP_xstllr -- Store-LORelease Register Double word +DEFINE_MOP(MOP_xstllr, {MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASLORELEASE|CANTHROW,kLtUndef,"err","0,1", 1, 1) + +// Store exclusive with/without release semantics +DEFINE_MOP(MOP_wstxr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef},ISSTORE|ISATOMIC|CANTHROW,kLtUndef,"err","0,1,2", 1, 2) +DEFINE_MOP(MOP_xstxr, {MOPD_Reg32ID,MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef},ISSTORE|ISATOMIC|CANTHROW,kLtUndef,"err","0,1,2", 1, 2) + +DEFINE_MOP(MOP_wstlxr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef},ISSTORE|ISATOMIC|HASRELEASE|CANTHROW,kLtUndef,"err","0,1,2", 1, 2) +DEFINE_MOP(MOP_xstlxr, {MOPD_Reg32ID,MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef},ISSTORE|ISATOMIC|HASRELEASE|CANTHROW,kLtUndef,"err","0,1,2", 1, 2) + +DEFINE_MOP(MOP_wstlxp, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Mem64D,MOPD_Undef},ISSTORE|ISSTOREPAIR|ISATOMIC|HASRELEASE|CANTHROW,kLtUndef,"err","0,1,2,3", 1, 3) +DEFINE_MOP(MOP_xstlxp, {MOPD_Reg32ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef},ISSTORE|ISSTOREPAIR|ISATOMIC|HASRELEASE|CANTHROW,kLtUndef,"err","0,1,2,3", 1, 3) + +// Atomic add without release +// MOP_wstadd +DEFINE_MOP(MOP_wstadd, {MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtUndef,"amoadd.w","0,1", 1, 1) +// MOP_xstadd +DEFINE_MOP(MOP_xstadd, {MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtUndef,"amoadd.d","0,1", 1, 1) + +// Atomic add with release +// MOP_wstaddlb +DEFINE_MOP(MOP_wstaddl, {MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"amoadd.w","0,1", 1, 1) +// MOP_xstaddl +DEFINE_MOP(MOP_xstaddl, {MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"amoadd.d","0,1", 1, 1) + +// Atomic bit clear +// MOP_wstclr +DEFINE_MOP(MOP_wstclr, {MOPD_Reg32ID,MOPD_Mem32D,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtUndef,"amoand.w","0,1,2", 1, 2) +// MOP_xstclr +DEFINE_MOP(MOP_xstclr, {MOPD_Reg64ID,MOPD_Mem64D,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtUndef,"amoand.d","0,1,2", 1, 2) + +// Atomic clr with release +// MOP_wstclrl +DEFINE_MOP(MOP_wstclrl, {MOPD_Reg32ID,MOPD_Mem32D,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"amoand.w","0,1,2", 1, 2) +// MOP_xstclrl +DEFINE_MOP(MOP_xstclrl, {MOPD_Reg64ID,MOPD_Mem64D,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"amoand.d","0,1,2", 1, 2) + +// Atomic XOR +// MOP_wsteor +DEFINE_MOP(MOP_wsteor, {MOPD_Reg32ID,MOPD_Mem32D,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtUndef,"amoxor.w","0,1,2", 1, 2) +// MOP_xsteor +DEFINE_MOP(MOP_xsteor, {MOPD_Reg64ID,MOPD_Mem64D,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtUndef,"amoxor.d","0,1,2", 1, 2) + +// Atomic eor with release +// MOP_wsteorl +DEFINE_MOP(MOP_wsteorl, {MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"steorl","0,1", 1, 1) +// MOP_xsteorl +DEFINE_MOP(MOP_xsteorl, {MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"steorl","0,1", 1, 1) + +// Memory barriers +// MOP_dmb_ishld +DEFINE_MOP(MOP_dmb_ishld, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef}, HASACQUIRE|ISDMB,kLtBranch, "err", "", 0, 0) +// MOP_dmb_ishst +DEFINE_MOP(MOP_dmb_ishst, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef}, HASRELEASE|ISDMB,kLtBranch, "err", "", 0, 0) +// MOP_dmb_ish +DEFINE_MOP(MOP_dmb_ish, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef}, HASACQUIRE|HASRELEASE|ISDMB,kLtBranch, "err", "", 0, 0) + +// MOP_clinit +// will be emit to four instructions in a row: +// adrp xd, :got:__classinfo__Ljava_2Futil_2Fconcurrent_2Fatomic_2FAtomicInteger_3B +// ldr xd, [xd,#:got_lo12:__classinfo__Ljava_2Futil_2Fconcurrent_2Fatomic_2FAtomicInteger_3B] +// ldr xd, [xd,#112] +// ldr wzr, [xd] +DEFINE_MOP(MOP_clinit, {MOPD_Reg64ID,MOPD_Literal,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISATOMIC|CANTHROW,kLtLoad1,"intrinsic_clinit","0,1", 1, 1) + +// will be emit to two instructions in a row: +// adrp xd, _PTR__cinf_Ljava_2Flang_2FSystem_3B +// ldr xd, [xd, #:lo12:_PTR__cinf_Ljava_2Flang_2FSystem_3B] +//MOP_adrp_ldr +DEFINE_MOP(MOP_adrp_ldr, {MOPD_Reg64ID, MOPD_Literal,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISATOMIC|CANTHROW,kLtLoad1,"intrinsic_adrpldr","0,1", 1, 1) + +// will be emit to two instructions in a row: +// adrp xd, label +// add xd, xd, #:lo12:label +//MOP_adrp_label +DEFINE_MOP(MOP_adrp_label, {MOPD_Reg64ID,MOPD_Imm64,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtAlu,"intrinsic_adrplabel","0,1", 1, 1) + +// ldr x17, [xs,#112] +// ldr wzr, [x17] +DEFINE_MOP(MOP_clinit_tail, {MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISATOMIC|CANTHROW,kLtLoad1,"intrinsic_clinit_tail","0", 0, 1) + +// MOP_tail_call_opt_xbl -- branch without link (call); this is a special definition +DEFINE_MOP(MOP_tail_call_opt_xbl, {MOPD_FuncName,MOPD_LISTS,MOPD_Undef,MOPD_Undef,MOPD_Undef},CANTHROW,kLtBranch,"tail","0", 0, 2) +// MOP_tail_call_opt_xblr -- branch without link (call) to register; this is a special definition +DEFINE_MOP(MOP_tail_call_opt_xblr, {MOPD_Reg64IS,MOPD_LISTS,MOPD_Undef,MOPD_Undef,MOPD_Undef},CANTHROW,kLtBranch,"br","0", 0, 2) + + +// All pseudo instructons need to be inserted after this point and before MOP_pseudo_last + +DEFINE_MOP(MOP_pseudo_first, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"#MOP_pseudo_first","", 0, 0) + +// MOP_pseudo_param_def_x, +DEFINE_MOP(MOP_pseudo_param_def_x, {MOPD_Reg64ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"#MOP_pseudo_param_def","0", 1, 0) + +// MOP_pseudo_param_def_w, +DEFINE_MOP(MOP_pseudo_param_def_w, {MOPD_Reg32ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"#MOP_pseudo_param_def","0", 1, 0) + +// MOP_pseudo_param_def_d, +DEFINE_MOP(MOP_pseudo_param_def_d, {MOPD_Reg64FD,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"#MOP_pseudo_param_def","0", 1, 0) + +// MOP_pseudo_param_def_s, +DEFINE_MOP(MOP_pseudo_param_def_s, {MOPD_Reg32FD,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"#MOP_pseudo_param_def","0", 1, 0) + +// MOP_pseudo_param_store_x, +DEFINE_MOP(MOP_pseudo_param_store_x, {MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"#MOP_pseudo_param_store_x","0", 1, 0) + +// MOP_pseudo_param_store_w, +DEFINE_MOP(MOP_pseudo_param_store_w, {MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"#MOP_pseudo_param_store_w","0", 1, 0) + +// MOP_pseudo_ref_init_x, +DEFINE_MOP(MOP_pseudo_ref_init_x, {MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"#MOP_pseudo_ref_init_x","0", 1, 0) + +// MOP_pseudo_ret_int, +DEFINE_MOP(MOP_pseudo_ret_int, {MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"#MOP_pseudo_ret_int","", 0, 1) + +// MOP_pseudo_ret_float, +DEFINE_MOP(MOP_pseudo_ret_float, {MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"#MOP_pseudo_ret_float","", 0, 1) + +// When exception occurs, R0 and R1 may be defined by runtime code. +// MOP_pseudo_eh_def_x, +DEFINE_MOP(MOP_pseudo_eh_def_x, {MOPD_Reg64ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"#MOP_pseudo_eh_def_x","0", 1, 0) + +DEFINE_MOP(MOP_pseudo_last, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"#MOP_pseudo_last","", 0, 0) + + +// for comments +// MOP_comment +DEFINE_MOP(MOP_comment, {MOPD_STRING,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"#","0", 0, 0) +//MOP_nop +DEFINE_MOP(MOP_nop, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtAlu,"nop","", 0, 0) + + +// A pseudo instruction that used for seperating dependence graph. +// MOP_pseudo_dependence_seperator, +DEFINE_MOP(MOP_pseudo_dependence_seperator, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"//MOP_pseudo_dependence_seperator","0", 0, 0) + + +// A pseudo instruction that used for replacing MOP_clinit_tail after clinit merge in scheduling. +// MOP_pseudo_none, +DEFINE_MOP(MOP_pseudo_none, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"//MOP_pseudo_none","0", 0, 0) + +// end of Riscv64 instructions diff --git a/mapleall/maple_be/include/cg/riscv64/riscv64_mem_layout.h b/mapleall/maple_be/include/cg/riscv64/riscv64_mem_layout.h new file mode 100644 index 0000000..2c48b08 --- /dev/null +++ b/mapleall/maple_be/include/cg/riscv64/riscv64_mem_layout.h @@ -0,0 +1,246 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#ifndef MAPLEBE_INCLUDE_CG_AARCH64MEMLAYOUT_H_ +#define MAPLEBE_INCLUDE_CG_AARCH64MEMLAYOUT_H_ + +#include "mem_layout.h" +#include "riscv64_abi.h" + +namespace maplebe { + +class Riscv64SymbolAlloc : public SymbolAlloc { + Riscv64reg_t reg0; + Riscv64reg_t reg1; + + public: + Riscv64SymbolAlloc() : reg0(kRinvalid), reg1(kRinvalid) {} + + ~Riscv64SymbolAlloc() {} + + void SetRegisters(Riscv64reg_t r0, Riscv64reg_t r1) { + reg0 = r0; + reg1 = r1; + } + + inline bool IsRegister() { + return reg0 != kRinvalid; + } + + inline Riscv64reg_t GetFirstRegister() { + return reg0; + } + + inline Riscv64reg_t GetSecondRegister() { + return reg1; + } +}; + +/* + On Riscv64, stack frames are structured as follows: + + The stack grows downward -- full descending (SP points + to a filled slot). + + Any of the parts of a frame is optional, i.e., it is + possible to write a caller-callee pair in such a way + that the particular part is absent in the frame. + + Before a call is made, the frame looks like: + | | + ||----------------------------| + | args passed on the stack | (we call them up-formals) + ||----------------------------|<- Stack Pointer + | | + + V1. + Right after a call is made + | | + ||----------------------------| + | args passed on the stack | + ||----------------------------|<- Stack Pointer + | PREV_FP, PREV_LR | + ||----------------------------|<- Frame Pointer + + After the prologue has run, + | | + ||----------------------------| + | args passed on the stack | + ||----------------------------| + | PREV_FP, PREV_LR | + ||----------------------------|<- Frame Pointer + | callee-saved registers | + ||----------------------------| + | empty space. should have | + | at least 16-byte alignment | + ||----------------------------| + | local variables | + ||----------------------------| + | variable-sized local vars | + | (VLAs) | + ||----------------------------|<- Stack Pointer + + * callee-saved registers include + 1. R19-R28 + 2. R8 if return value needs to be returned + thru memory and callee wants to use R8 + 3. we don't need to save R19 if it is used + as base register for PIE. + 4. V8-V15 + + V2. (this way, we may be able to save + on SP modifying instruction) + Right after a call is made + | | + ||----------------------------| + | args passed on the stack | + ||----------------------------|<- Stack Pointer + | | + | empty space | + | | + ||----------------------------| + | PREV_FP, PREV_LR | + ||----------------------------|<- Frame Pointer + + After the prologue has run, + | | + ||----------------------------| + | args passed on the stack | + ||----------------------------| + | callee-saved registers | + | including those used for | + | parameter passing | + ||----------------------------| + | empty space. should have | + | at least 16-byte alignment | + ||----------------------------| + | local variables | + ||----------------------------| + | PREV_FP, PREV_LR | + ||----------------------------|<- Frame Pointer + | variable-sized local vars | + | (VLAs) | + ||----------------------------| + | args to pass through stack | + ||----------------------------| + */ + +class Riscv64MemLayout : public MemLayout { + /* + inherited fields from MemLayout + MemSegment seg_upformal; // this is the segment for parameters passed thru stack + // because no available registers for them or they + // are too large to be passed thru registers according to + // the ABI. + MemSegment seg_formal; // this is the segment for parameters passed thru registers. + // We may need space for these on stack (not for Java, though) + MemSegment seg_actual; + */ + MemSegment seg_reflocals; + MemSegment seg_GRSavearea; + MemSegment seg_VRSavearea; + + // callee saved register R19-R28 (10) + MemSegment seg__spillreg; + + public: + MemSegment seg_lockobjslot; + MemSegment seg_locals; // these are accessed via Frame Pointer + int32 fixstacksize; + int32 lockinfosize; + int32 lockslotsize; + bool unusedslot; // true if the frame exist an unused 8 byte slot that is generated by roundup. + public: + explicit Riscv64MemLayout(BECommon *b, MIRFunction *f, MapleAllocator *mallocator) + : MemLayout(b, f, mallocator), + seg_reflocals(kMsReflocals), + seg_GRSavearea(kMsGRSavearea), + seg_VRSavearea(kMsVRSavearea), + seg__spillreg(kMsSpillReg), + seg_lockobjslot(kMsLockslot), + seg_locals(kMsLocals), + fixstacksize(0), + lockinfosize(SIZEOFPTR), + lockslotsize(2 * SIZEOFPTR), + unusedslot(false) {} + + ~Riscv64MemLayout() {} + + /* + Returns stack space required for a call + which is used to pass arguments that cannot be + passed through registers + */ + uint32 ComputeStackSpaceRequirementForCall(StmtNode *stmt, int32 &aggCopySize, bool isIcall) override; + + void LayoutStackFrame(int32 &structCopySize, int32 &maxParmStackSize) override; + + void AssignSpillLocationsToPseudoRegisters() override; + + SymbolAlloc *AssignLocationToSpillReg(regno_t vrnum) override; + + int32 StackFrameSize(); + + bool GetUnusedSlot(); + + int32 RealStackFrameSize(); + + int32 GetadjustforRefloc(); + + inline MemSegment &locals() { + return seg_locals; + } + + inline MemSegment &Reflocals() { + return seg_reflocals; + } + + inline MemSegment &GRSavearea() { + return seg_GRSavearea; + } + + inline MemSegment &VRSavearea() { + return seg_VRSavearea; + } + + inline int32 GetSizeOfSpillReg() { + return seg__spillreg.GetSize(); + } + + inline int32 GetSizeOfLocals() { + return seg_locals.GetSize(); + } + + inline int32 GetSizeOfRefLocals() { + return seg_reflocals.GetSize(); + } + + inline int32 GetSizeOfGRSavearea() { + return seg_GRSavearea.GetSize(); + } + + inline int32 GetSizeOfVRSavearea() { + return seg_VRSavearea.GetSize(); + } + + int32 GetReflocbaseLoc(); + int32 GetGRSaveareaBaseLoc(); + int32 GetVRSaveareaBaseLoc(); + void AdjustOffsetForCalleeSaved(SymbolAlloc &sym); +}; + +} // namespace maplebe + +#endif // MAPLEBE_INCLUDE_CG_AARCH64MEMLAYOUT_H_ diff --git a/mapleall/maple_be/include/cg/riscv64/riscv64_operand.h b/mapleall/maple_be/include/cg/riscv64/riscv64_operand.h new file mode 100644 index 0000000..6aca64a --- /dev/null +++ b/mapleall/maple_be/include/cg/riscv64/riscv64_operand.h @@ -0,0 +1,726 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#ifndef MAPLEBE_INCLUDE_CG_AARCH64OPERAND_H_ +#define MAPLEBE_INCLUDE_CG_AARCH64OPERAND_H_ + +#include "riscv64_isa.h" +#include "operand.h" +#include "cg.h" +#include "emit.h" +#include "cg_assert.h" + +#include +#include +#include +#include +#include + +namespace maplebe { + +using namespace maple; +using namespace std; + +enum VectorType { kVecDouble = 0, kVecSingle = 1, kVecNone }; + +class Riscv64RegOperand : public RegOperand { + private: + uint32 flag_; + VectorType vector_type; // double(2 * 64bits) or single(4 * 32bits) + uint8 vector_pos; // (0,1) for d, (0,3) for s + public: + static Riscv64RegOperand zero64; + static Riscv64RegOperand zero32; + bool isreffield_; + explicit Riscv64RegOperand(regno_t regNo, uint8 size, RegType kind, uint32 flag = 0, VectorType type = kVecNone, + uint8 position = 0) + : RegOperand(regNo, size, kind, false), flag_(flag), vector_type(type), vector_pos(position), isreffield_(false) { + CG_ASSERT(kind != kRegTyUndef, "Reg type must be specified"); + } + + ~Riscv64RegOperand() {} + + inline uint32 GetFlags() { + return flag_; + } + + VectorType GetVectorType() { + return vector_type; + } + + bool IsPhysicalRegister() const { + CG_ASSERT(GetRegisterNumber() < Riscv64reg_t::kMaxRegNum, ""); + return (!IsVirtualRegister()); + } + + inline bool IsInvalidRegister() override { + return (GetRegisterNumber() == Riscv64reg_t::kRinvalid); + } + + inline bool IsPhysicalRegister() override { + return Riscv64isa::IsPhysicalRegister(GetRegisterNumber()); + } + + bool IsSaveReg(MIRType *ty, BECommon &becommon) override; + + inline bool IsAsHigh32() { + return flag_ & REGOPNDSETHIGH32; + } + + inline Riscv64reg_t GetPhysicalRegister() { + CG_ASSERT(Riscv64isa::IsPhysicalRegister(GetRegisterNumber()), "not a physical register"); + return (Riscv64reg_t)GetRegisterNumber(); + } + + inline static Riscv64RegOperand &Get32bitZeroRegister() { + return zero32; + } + + inline static Riscv64RegOperand &Get64bitZeroRegister() { + return zero64; + } + + inline static Riscv64RegOperand *GetZeroRegister(uint32 bitleng) { + /* It is possible to have a bitleng < 32, eg stb. + * Set it to 32 if it is less than 32. + */ + if (bitleng < 32) { + bitleng = 32; + } + CG_ASSERT((bitleng == 32 || bitleng == 64), "illegal bit length = %d", bitleng); + return (bitleng == 32) ? &Get32bitZeroRegister() : &Get64bitZeroRegister(); + } + + bool IsZeroRegister() override { + return GetRegisterNumber() == RZERO; + } + + bool IsSimdVectorMode() { + return vector_type != kVecNone; + } + + VectorType GetSimdVectorType() { + return vector_type; + } + + void SetSimdVectorType(VectorType v) { + vector_type = v; + } + + int GetSimdVectorPosition() { + return static_cast(vector_pos); + } + + void SetSimdVectorPosition(uint8 v) { + if (vector_type == kVecDouble) { + CG_ASSERT(v < 2, "Simd FP index for d type out of bound"); + } else if (vector_type == kVecSingle) { + CG_ASSERT(v < 4, "Simd FP index for s type out of bound"); + } + vector_pos = v; + } + + Operand *Clone(MemPool *mp) const override { + return mp->Clone(*this); + } + + bool operator==(const Riscv64RegOperand &o) const { + regno_t myRn = GetRegisterNumber(); + uint32 mySz = GetSize(); + uint32 myFl = flag_; + regno_t otherRn = o.GetRegisterNumber(); + uint32 otherSz = o.GetSize(); + uint32 otherFl = o.flag_; + if (myRn != otherRn || mySz != otherSz || myFl != otherFl) { + return false; + } + if (vector_type == kVecNone) { + if (vector_type == o.vector_type) { + return true; + } else { + return false; + } + } else { + if (vector_type == o.vector_type && vector_pos == o.vector_pos) { + return true; + } else { + return false; + } + } + } + + bool IsCallArgumentPassingMachineRegister() const override { + return (IsPhysicalRegister() && Riscv64isa::IsArgumentPassingRegister(GetRegisterNumber())); + } + + bool IsReturnValueMachineRegister() const override { + return (IsPhysicalRegister() && (GetRegisterNumber() == R0 || GetRegisterNumber() == V0)); + } + + bool operator<(const Riscv64RegOperand &o) const { + // if kind_Clone(*this); + } + + bool IsInSimmBitSize(uint8 size) { + if (IsNegative()) { + if (IsInBitSize(size)) { + return true; + } + } else { + if (IsInBitSize(size - 1)) { + return true; + } + } + return false; + } + + inline bool IsSingleInstructionMovable() { + return (static_cast(val_) & 0x0fffULL) == static_cast(val_); + } + + void Emit(Emitter &emitter, OpndProp *prop) override { + if (!is_fmov_) { + if (prop && static_cast(prop)->IsLoadLiteral()) { + emitter.Emit("="); + } + if (is_signed_) { + if (size_ == 64) { + emitter.Emit(val_); + } else { + emitter.Emit(static_cast(static_cast(val_))); + } + } else { + if (size_ == 64) { + emitter.Emit(static_cast(val_)); + } else { + emitter.Emit(static_cast(val_)); + } + } + } else { + int exp = ((((unsigned int)val_ & 0x70) >> 4) ^ 0x4) - 3; + float mantissa = 1.0 + (static_cast(val_ & 0xf) / 16.0); + float result = std::pow(2, exp) * mantissa; + std::stringstream ss; + ss << std::setprecision(10) << result; + std::string res; + ss >> res; + size_t dot = res.find('.'); + if (dot == std::string::npos) { + res += ".0"; + dot = res.find('.'); + if (dot == std::string::npos) { + CG_ASSERT(false, "cannot find in string"); + } + } + res.erase(dot, 1); + std::string integer(res, 0, 1); + std::string fraction(res, 1); + while (fraction.size() != 1 && fraction[fraction.size() - 1] == '0') { + fraction.pop_back(); + } + std::string sign = static_cast(val_) & 0x80 ? "-" : ""; + emitter.Emit(sign).Emit(integer).Emit(".").Emit(fraction).Emit("e+").Emit(dot - 1); + } + } +}; + +class ImmFPZeroOperand : public Operand { + static ImmFPZeroOperand *instance32; + static ImmFPZeroOperand *instance64; + + public: + explicit ImmFPZeroOperand(uint32 sz) : Operand(Opd_FPZeroImmediate, uint8(sz)) {} + + ~ImmFPZeroOperand() {} + + static ImmFPZeroOperand *allocate(uint8 sz) { + CG_ASSERT((sz == 32 || sz == 64), "half-precession is yet to be supported"); + ImmFPZeroOperand *&inst = (sz == 32) ? instance32 : instance64; + // if( !inst ) { + MemPool *mp = CG::curCgFunc->memPool; + inst = mp->New(static_cast(sz)); + // } + return inst; + } + + Operand *Clone(MemPool *mp) const override { + return mp->Clone(*this); + } + + void Emit(Emitter &emitter, OpndProp *opndprop) override { + emitter.Emit("0.0"); + } + + bool Less(Operand *right) const override { + // For different type. + if (op_kind_ != right->op_kind_) { + return op_kind_ < right->op_kind_; + } + + return false; + } + + void dump() override { + cout << "imm fp" << size_ << ": 0.0"; + } +}; + +class Riscv64OfstOperand : public /*Riscv64ImmOperand*/ OfstOperand { + public: + explicit Riscv64OfstOperand(int32 val, uint8 size, bool isVary = false) + : OfstOperand(int64(val), size, true, isVary) {} + + ~Riscv64OfstOperand() {} + + Operand *Clone(MemPool *mp) const override { + return mp->Clone(*this); + } + + inline int32 GetOffsetValue() const { + return GetValue(); + } + + inline void SetOffsetValue(int32 ov) { + SetValue(static_cast(ov)); + } + + inline bool operator<(const Riscv64OfstOperand &opnd) const { + return GetValue() < opnd.GetValue(); + } + + inline bool operator==(const Riscv64OfstOperand &opnd) const { + return GetValue() == opnd.GetValue(); + } + + inline int32 operator-(const Riscv64OfstOperand &opnd) const { + return GetValue() - opnd.GetValue(); + } + + inline void AdjustOffset(int32 delta) { + Add(static_cast(delta)); + } + + void Emit(Emitter &emitter, OpndProp *prop) override { + if (prop && static_cast(prop)->IsLoadLiteral()) { + emitter.Emit("="); + } + emitter.Emit(size_ == 64 ? val_ : static_cast(static_cast(val_))); + } + + void dump() override { + cout << "ofst:" << val_; + } +}; + +class StImmOperand : public Operand // representing for global variables address +{ + MIRSymbol *st_; + int64 offset_; + int32 relocs_; + + public: + explicit StImmOperand(MIRSymbol *st, int64 offset, int32 relocs) + : Operand(Opd_StImmediate, 0), st_(st), offset_(offset), relocs_(relocs) {} + + ~StImmOperand() {} + + Operand *Clone(MemPool *mp) const override { + return mp->Clone(*this); + } + + inline MIRSymbol *GetSymbol() { + return st_; + } + + inline const std::string &GetName() { + return st_->GetName(); + } + + inline int64 GetOffset() { + return offset_; + } + + bool operator==(const StImmOperand &opnd) const { + return (st_ == opnd.st_ && offset_ == opnd.offset_ && relocs_ == opnd.relocs_); + } + + bool operator<(const StImmOperand &opnd) const { + return st_ < opnd.st_ || (st_ == opnd.st_ && offset_ < opnd.offset_) || + (st_ == opnd.st_ && offset_ == opnd.offset_ && relocs_ < opnd.relocs_); + } + + virtual bool Less(Operand *right) const override { + if (this == right) { + return false; + } + + // For different type. + if (op_kind_ != right->op_kind_) { + return op_kind_ < right->op_kind_; + } + + StImmOperand *rop = static_cast(right); + + if (st_ != rop->st_) { + return st_ < rop->st_; + } + if (offset_ != rop->offset_) { + return offset_ < rop->offset_; + } + return relocs_ < rop->relocs_; + } + + /* virtual */ void Emit(Emitter &emitter, OpndProp *opndprop) override { + bool isLower12 = static_cast(opndprop)->IsLiteralLow12(); + if (isLower12) { + emitter.Emit("%lo("); + } + if (CGOptions::doPIC && (st_->GetStorageClass() == kScGlobal || st_->GetStorageClass() == kScExtern)) { + emitter.Emit(":got:" + GetName()); + } else { + if (isLower12 == false) { + emitter.Emit("%hi("); + } + // check for sKind since it might be created by cg. (i.eg. LB_*) + if (st_->storageClass == kScPstatic && st_->sKind != kStConst && st_->IsLocal()) { + emitter.Emit(GetName() + to_string(CG::curPuIdx)); + } else { + emitter.Emit(GetName()); + } + } + if (offset_ != 0) { + emitter.Emit("+" + to_string(offset_)); + } + emitter.Emit(")"); + } + + /* virtual */ void dump() override { + cout << GetName(); + cout << "+offset:" << offset_; + } +}; + +class FunctionLabelOperand : public LabelOperand { + public: + explicit FunctionLabelOperand(const char *func) : LabelOperand(func, 0) {} + + ~FunctionLabelOperand() {} + + Operand *Clone(MemPool *mp) const override { + return mp->Clone(*this); + } + + /* virtual */ void Emit(Emitter &emitter, OpndProp *opndprop) override { + emitter.Emit(parent_func_); + } + + /* virtual */ void dump() override { + cout << "func :" << parent_func_; + } +}; + +// Use StImmOperand instead? +class FuncNameOperand : public Operand { + MIRSymbol *symbol_; + + public: + explicit FuncNameOperand(MIRSymbol *fsym) : Operand(Opd_BbAddress, 0), symbol_(fsym) {} + + ~FuncNameOperand() {} + + Operand *Clone(MemPool *mp) const override { + return mp->Clone(*this); + } + + inline const std::string &GetName() { + return symbol_->GetName(); + } + + MIRSymbol *GetFunctionSymbol() { + return symbol_; + } + + void SetFunctionSymbol(MIRSymbol *fsym) { + symbol_ = fsym; + } + + /* virtual */ void Emit(Emitter &emitter, OpndProp *opndprop) override { + emitter.Emit(GetName()); + } + + virtual bool Less(Operand *right) const override { + if (this == right) { + return false; + } + + // For different type. + if (op_kind_ != right->op_kind_) { + return op_kind_ < right->op_kind_; + } + + FuncNameOperand *rop = static_cast(right); + + return static_cast(symbol_) < static_cast(rop->symbol_); + } + + /* virtual */ void dump() override { + cout << GetName(); + } +}; + +class Riscv64CGFunc; + +class Riscv64MemOperand : public MemOperand { + public: + Riscv64MemOperand &operator=(const Riscv64MemOperand &p) = default; + + private: + static const int32 kMaxImm11 = 2047; // 2048 - 1 -> 0x7ff + + bool isStackMem; + + public: + explicit Riscv64MemOperand(Riscv64reg_t reg, int32 offset, int32 size) + : MemOperand(size, CG::curCgFunc->memPool->New(reg, 64, kRegTyInt), nullptr, + CG::curCgFunc->memPool->New(offset, 32), nullptr), + isStackMem(false) { + if (reg == RSP || reg == RFP) + isStackMem = true; + } + + explicit Riscv64MemOperand(int32 size, RegOperand *base, RegOperand *index, + Operand *offset, MIRSymbol *symbol) + : MemOperand(size, base, index, offset, symbol) { + if (base->GetRegisterNumber() == RSP || base->GetRegisterNumber() == RFP) + isStackMem = true; + } + + ~Riscv64MemOperand() {} + + /* + Copy constructor + */ + Riscv64MemOperand(const Riscv64MemOperand &mo) + : MemOperand(mo) {} + + Operand *Clone(MemPool *mp) const override { + return mp->Clone(*this); + } + + inline const std::string &GetSymbolName() { + return GetSymbol()->GetName(); + } + + inline void SetBaseRegister(Riscv64RegOperand *br) { + MemOperand::SetBaseRegister(br); + } + + inline bool IsStackMem() { + return isStackMem; + } + + inline void SetStackMem(bool b) { + isStackMem = b; + } + + Operand *GetOffset() override; + + inline Riscv64OfstOperand *GetOffsetImmediate() { + return static_cast(GetOffsetOperand()); + } + + inline void SetOffsetImmediate(OfstOperand *oo) { + MemOperand::SetOffsetOperand(oo); + } + + // Returns N where alignment == 2^N + inline static int32 GetImmediateOffsetAlignment(uint32 dsize) { + CG_ASSERT(8 <= dsize && dsize <= 64 && (dsize & (dsize - 1)) == 0, ""); + /* dsize==8: 0, dsize==16 : 1, dsize==32: 2, dsize==64: 3 */ + return __builtin_ctz(dsize) - 3; + } + + inline static int32 GetMaxPIMM(uint32 dsize) { + CG_ASSERT(8 <= dsize && dsize <= 64 && (dsize & (dsize - 1)) == 0, ""); + return kMaxImm11; + } + + inline bool IsOffsetMisaligned(uint32 dsize) { + if (dsize == 128) { + // hard coded for vector + return false; + } + CG_ASSERT(8 <= dsize && dsize <= 64 && (dsize & (dsize - 1)) == 0, ""); + if (dsize == 8) { + return false; + } + Riscv64OfstOperand *oo = GetOffsetImmediate(); + return ((oo->GetOffsetValue() & ((1 << GetImmediateOffsetAlignment(dsize)) - 1)) != 0); + } + + static inline bool IsPIMMOffsetOutOfRange(int32 offset, uint32 dsize) { + if (dsize == 128) { + // hard coded for vector + return false; + } + CG_ASSERT(8 <= dsize && dsize <= 64 && (dsize & (dsize - 1)) == 0, ""); + return (!(0 <= offset && offset <= GetMaxPIMM(dsize))); + } + + inline bool operator<(const Riscv64MemOperand &opnd) const { + return (GetBaseRegister() < opnd.GetBaseRegister()) || + (GetBaseRegister() == opnd.GetBaseRegister() && GetOffsetOperand() < opnd.GetOffsetOperand()) || + (GetBaseRegister() == opnd.GetBaseRegister() && GetOffsetOperand() == opnd.GetOffsetOperand() && + GetSymbol() < opnd.GetSymbol()) || + (GetBaseRegister() == opnd.GetBaseRegister() && GetOffsetOperand() == opnd.GetOffsetOperand() && + GetSymbol() == opnd.GetSymbol() && GetSize() < opnd.GetSize()); + } + + virtual bool Less(Operand *right) const override { + if (this == right) { + return false; + } + + // For different type. + if (op_kind_ != right->op_kind_) { + return op_kind_ < right->op_kind_; + } + + Riscv64MemOperand *rop = static_cast(right); + + RegOperand *baseReg = GetBaseRegister(); + RegOperand *rbaseReg = rop->GetBaseRegister(); + int nRet = baseReg->RegCompare(rbaseReg); + if (nRet == 0) { + Operand *ofstOpnd = GetOffsetOperand(); + Operand *rofstOpnd = rop->GetOffsetOperand(); + return ofstOpnd->Less(rofstOpnd); + } else { + return nRet < 0; + } + } + + bool NoAlias(Riscv64MemOperand *rop) { + RegOperand *baseReg = GetBaseRegister(); + RegOperand *rbaseReg = rop->GetBaseRegister(); + + if (baseReg->GetRegisterNumber() == RFP || rbaseReg->GetRegisterNumber() == RFP) { + Operand *ofstOpnd = GetOffsetOperand(); + Operand *rofstOpnd = rop->GetOffsetOperand(); + + CG_ASSERT(ofstOpnd && rofstOpnd, "offset operand should not be null."); + OfstOperand *ofst = static_cast(ofstOpnd); + OfstOperand *rofst = static_cast(rofstOpnd); + CG_ASSERT(ofst && rofst, "CG internal error, invalid type."); + + return (!ofst->ValueEquals(rofst)); + } + + return false; + } + + void Emit(Emitter &emitter, OpndProp *opndprop) override; + + void dump() override; + + // Return true if given operand has the same base reg and offset with this. + bool Equals(Operand *operand) override; + bool Equals(Riscv64MemOperand *opnd); +}; + +class Riscv64ListOperand : public ListOperand { + public: + explicit Riscv64ListOperand(MapleAllocator *allocator) : ListOperand(allocator) {} + + ~Riscv64ListOperand() {} + + Operand *Clone(MemPool *mp) const override { + return mp->Clone(*this); + } + + void Emit(Emitter &emitter, OpndProp *opndprop) override; +}; + +class CommentOperand : public Operand { + const char *comment; + + public: + explicit CommentOperand(const char *s) : Operand(Operand::Opd_String, 0), comment(s) {} + + explicit CommentOperand(const std::string &s) : Operand(Operand::Opd_String, 0), comment(s.c_str()) {} + + ~CommentOperand() {} + + inline const char *GetComment() { + return comment; + } + + Operand *Clone(MemPool *mp) const override { + return mp->Clone(*this); + } + + /* virtual */ void Emit(Emitter &emitter, OpndProp *opndprop) override { + emitter.Emit(comment); + } + + virtual bool Less(Operand *right) const override { + // For different type. + if (op_kind_ != right->op_kind_) { + return op_kind_ < right->op_kind_; + } + + return false; + } + + /* virtual */ void dump() override { + cout << "# " << comment << endl; + } +}; + +} // namespace maplebe + +#endif // MAPLEBE_INCLUDE_CG_AARCH64OPERAND_H_ diff --git a/mapleall/maple_be/include/cg/riscv64/riscv64_optimize_common.h b/mapleall/maple_be/include/cg/riscv64/riscv64_optimize_common.h new file mode 100644 index 0000000..c415cb6 --- /dev/null +++ b/mapleall/maple_be/include/cg/riscv64/riscv64_optimize_common.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#ifndef MAPLEALL_MAPLEBE_INCLUDE_CG_AARCH64_AARCH64OPTIMIZECOMMON_H +#define MAPLEALL_MAPLEBE_INCLUDE_CG_AARCH64_AARCH64OPTIMIZECOMMON_H + +#include "riscv64_isa.h" +#include "optimize_common.h" + +namespace maplebe { + +using namespace maple; +using namespace std; + +class Riscv64InsnVisitor : public InsnVisitor { + public: + Riscv64InsnVisitor(CGFunc *func) : InsnVisitor(func) {} + + ~Riscv64InsnVisitor() {} + + void ModifyJumpTarget(maple::LabelIdx targetLabel, BB *&bb) override; + void ModifyJumpTarget(Operand *targetOperand, BB *&bb) override; + void ModifyJumpTarget(BB *newTarget, BB *&bb) override; + // return true if successfully modified + bool ModifyBrInsn(maple::LabelIdx targetLabel, BB *&curbb) override; + // Check if it requires to add extra gotos when relocate bb + MOperator FlipConditionOp(MOperator flippedOp, int &targetIdx) override; + + bool IsConditionAlwaysHold(Insn *cmpInsn, Insn *conditionBrInsn, Operand *operands[]) override; + Insn *CreateGotoInsn(Insn *condBrInsn) override; + Insn *CloneInsn(Insn *originalInsn) override; + LabelIdx GetJumpLabel(Insn *insn) override; + Operand *GetStrTarget(Insn *insn) override; + Operand *GetStrSource(Insn *insn) override; + Operand *GetLdrTarget(Insn *insn) override; + Operand *GetLdrSource(Insn *insn) override; + bool EqualMemOperands(Operand *op1, Operand *op2) override; + bool IsCompareInsn(Insn *insn) override; + bool IsCompareAndBranchInsn(Insn *insn) override; + Insn *CreateLdrInsn(MOperator mop, RegOperand *reg, MemOperand *mem) override; + Insn *CreateMoveInsn(RegOperand *reg, RegOperand *mem) override; + Insn *CreateCmpInsn(Insn *condbr) override; + RegOperand *CreateVregFromReg(RegOperand *pReg) override; + bool ModifyInsnOpnds(Insn *insn, Operand *src, Operand *tar) override; + + private: + bool IsConditionAlwaysHold(MOperator mop, int64 cmpRet); +}; + +} // namespace maplebe + +#endif /* MAPLEALL_MAPLEBE_INCLUDE_CG_AARCH64_AARCH64OPTIMIZECOMMON_H */ diff --git a/mapleall/maple_be/include/cg/riscv64/riscv64_peep.h b/mapleall/maple_be/include/cg/riscv64/riscv64_peep.h new file mode 100644 index 0000000..02e7ac7 --- /dev/null +++ b/mapleall/maple_be/include/cg/riscv64/riscv64_peep.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#ifndef MAPLEBE_INCLUDE_CG_AARCH64PEEP_H +#define MAPLEBE_INCLUDE_CG_AARCH64PEEP_H + +#include "riscv64_cg.h" +#include "cg_assert.h" +#include +#include "optimize_common.h" +#include "mir_builder.h" + +namespace maplebe { + +class Riscv64Peep { + private: + CGFunc *cgfunc; + CG *cg; + + private: + bool IsMemOperandsIdentical(Insn *insn, Insn *ninsn); + bool IsSameReg(Operand *firstOpnd, Operand *secondOpnd); + bool PredBBCheck(BB *bb, bool checkcbz, Operand *opnd); + bool OpndDefByMovZero(Insn *insn); + bool NoPreDefine(Insn *testInsn); + bool OpndDefByOneValidBit(Insn *defInsn); + Insn *DefInsnOfOperandInBB(BB *bb, Insn *startinsn, Insn *checkinsn, int opndidx); + bool PatternMatch(std::vector &optInsn); + + public: + explicit Riscv64Peep(CGFunc *cf) : cgfunc(cf) { + cg = cgfunc->cg; + } + + ~Riscv64Peep(){}; + void RemoveIdenticalLoadAndStore(); + void Peephole0(); + void Peephole(); + void PostRemoveSext(); + void RemoveSext(); + void ConvertPseudoOps(); + void PeepholeOpt(); + void DeleteMovAfterCbzOrCbnz(); + void CmpCsetOptimize(); + void LongIntCompareWithZ(); + void ComplexMemOperandOpt(); + void ComplexMemOperandOptLSL(); + void ReplaceDivisionToMultiplication(); + void PrePeepholeOpt(); + void PrePeepholeOpt1(); + void ReplaceInstruction(); + +}; // class Riscv64Peep + +} // namespace maplebe +#endif diff --git a/mapleall/maple_be/include/cg/riscv64/riscv64_ra_opt.h b/mapleall/maple_be/include/cg/riscv64/riscv64_ra_opt.h new file mode 100644 index 0000000..878333c --- /dev/null +++ b/mapleall/maple_be/include/cg/riscv64/riscv64_ra_opt.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#ifndef MAPLEBE_INCLUDE_CG_AARCH64RAOPT_H +#define MAPLEBE_INCLUDE_CG_AARCH64RAOPT_H + +#include "cg.h" +#include "riscv64_cg.h" +#include "riscv64_insn.h" +#include "riscv64_operand.h" + +namespace maplebe { + +class X0OptInfo { + public: + X0OptInfo() : movSrc(nullptr), replaceReg(0), renameInsn(nullptr), renameOpnd(nullptr), renameReg(0) {} + + inline RegOperand *GetMovSrc() const { + return movSrc; + } + + inline regno_t GetReplaceReg() const { + return replaceReg; + } + + inline Insn *GetRenameInsn() const { + return renameInsn; + } + + inline Operand *GetRenameOpnd() const { + return renameOpnd; + } + + inline regno_t GetRenameReg() const { + return renameReg; + } + + inline void SetMovSrc(RegOperand *srcReg) { + movSrc = srcReg; + } + + inline void SetReplaceReg(regno_t regno) { + replaceReg = regno; + } + + inline void SetRenameInsn(Insn *insn) { + renameInsn = insn; + } + + inline void ResetRenameInsn() { + renameInsn = nullptr; + } + + inline void SetRenameOpnd(Operand *opnd) { + renameOpnd = opnd; + } + + inline void SetRenameReg(regno_t regno) { + renameReg = regno; + } + + private: + RegOperand *movSrc; + regno_t replaceReg; + Insn *renameInsn; + Operand *renameOpnd; + regno_t renameReg; +}; + +class RaX0Opt { + public: + RaX0Opt() {} + + bool PropagateX0CanReplace(Operand *opnd, regno_t replaceReg); + bool PropagateRenameReg(Insn *insn, X0OptInfo &optVal); + bool PropagateX0DetectX0(Insn *insn, X0OptInfo &optVal); + bool PropagateX0DetectRedefine(const Riscv64MD *md, Insn *ninsn, const X0OptInfo &optVal, uint32 index); + bool PropagateX0Optimize(const BB *bb, const Insn *insn, X0OptInfo &optVal); + bool PropagateX0ForCurrBb(BB *bb, X0OptInfo &optVal); + void PropagateX0ForNextBb(BB *nextBb, X0OptInfo &optVal); + void PropagateX0(CGFunc *); + + private: +}; + +} // namespace maplebe + +#endif // MAPLEBE_INCLUDE_CG_AARCH64RAOPT_H diff --git a/mapleall/maple_be/include/cg/riscv64/riscv64_reaching_definition.h b/mapleall/maple_be/include/cg/riscv64/riscv64_reaching_definition.h new file mode 100644 index 0000000..5c44f35 --- /dev/null +++ b/mapleall/maple_be/include/cg/riscv64/riscv64_reaching_definition.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#ifndef AARCH64REACHINGDEFINITION_H +#define AARCH64REACHINGDEFINITION_H + +#include "reaching_definition.h" + +namespace maplebe { + +class Riscv64ReachingDefinition : public ReachingDefinition { + public: + explicit Riscv64ReachingDefinition(CGFunc *func, MemPool *mp, MapleAllocator ma, LiveAnalysis *live) + : ReachingDefinition(func, mp, ma, live) {} + + ~Riscv64ReachingDefinition() {} + + void InitStartGen() override final; + void InitEhDefine(BB *bb) override final; + void InitKillGen(BB *bb, int mode) override final; + bool MayHasThrow(const Insn *headInsn, const Insn *tailInsn) override final; + void GenerateUseDef(BB *bb, int mode) override final; + void GenerateDefUse(BB *bb) override final; + void KillAllCallerSavedRegs(BB *bb, Insn *callInsn) override final; + void DirtyAllNonStackMem(BB *bb) override final; + void GenReturnValue(BB *bb, Insn *insn) override final; + void KillAllCallerSavedRegsOnBBIn(BB *bb, Insn *callInsn) override final; + void GenReturnValueOnBBIn(BB *bb, Insn *insn) override final; + void InsertUseToDef(DataInsnInfo &insnInfo, Insn *useInsn, short index, short userProperty) override final; + void AddRetPseudoInsn(BB *bb) override final; + void AddRetPseudoInsns() override final; + void DumpUDChain(BB *bb) override final; + void DumpDUChain(BB *bb) override final; + void DumpWAWDependence(BB *bb) override final; + void RemoveDUUDForInsn(Insn *insn) override final; + void InsertDUUDForDestOperand(Insn *newInsn, short newIndex, unsigned short newProp, Insn *refInsn, short refIndex, + unsigned short refProp, bool isRefInsnBeforeNewInsn) override final; + + void InsertDUUDForSrcOperand(Insn *newInsn, short newIndex, unsigned short newProp, Insn *refInsn, short refIndex, + unsigned short refProp) override final; + + void ReplaceInsnSrcOperand(Insn *insn, short index, unsigned short prop, Operand *newOpnd, Insn *refInsn, + short refIndex, unsigned short refProp) override final; + + void ReplaceInsnDestOperand(Insn *insn, short index, unsigned short prop, Operand *newOpnd, Insn *refInsn, + short refIndex, unsigned short refProp, bool isRefInsnBeforeInsn) override final; +}; + +} // namespace maplebe + +#endif /* AARCH64REACHINGDEFINITION_H */ diff --git a/mapleall/maple_be/include/cg/riscv64/riscv64_reg_alloc.h b/mapleall/maple_be/include/cg/riscv64/riscv64_reg_alloc.h new file mode 100644 index 0000000..5eb4374 --- /dev/null +++ b/mapleall/maple_be/include/cg/riscv64/riscv64_reg_alloc.h @@ -0,0 +1,606 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#ifndef MAPLEBE_INCLUDE_CG_AARCH64REGALLOC_H_ +#define MAPLEBE_INCLUDE_CG_AARCH64REGALLOC_H_ +#include "reg_alloc.h" +#include "riscv64_operand.h" +#include "riscv64_insn.h" +#include "riscv64_abi.h" + +#define O1_INT_REG_FOR_SPILL R15 +#define O1_FLT_REG_FOR_SPILL V31 +#define MAX_INT_SPILL 2 +#define MAX_FP_SPILL 2 + +namespace maplebe { + +class Riscv64RegAllocator : public RegAllocator { + protected: + bool avail_reg_set_[MAXREG]; + MapleMap reg_map_; // virtual-register-to-physical-register map + MapleSet live_reg_; // a set of currently live physical registers + MapleSet allocated_set_; // already allocated + MapleMap regLiveness; + + Riscv64reg_t atomic_store_result_reg; + + protected: + Operand *AllocSrcOpnd(Operand *opnd, OpndProp *opndprop = nullptr, Insn *insn = nullptr, BB *bb = nullptr); + + Operand *AllocDestOpnd(Operand *opnd, Insn *insn, uint32 index, BB *bb = nullptr); + + public: + Riscv64RegAllocator(CGFunc *cgfunc, MapleAllocator *mallocator) + : RegAllocator(cgfunc), + reg_map_(std::less(), mallocator->Adapter()), + live_reg_(std::less(), mallocator->Adapter()), + allocated_set_(std::less(), mallocator->Adapter()), + regLiveness(std::less(), mallocator->Adapter()), + atomic_store_result_reg(kRinvalid) { + for (int i = 0; i != MAXREG; i++) { + avail_reg_set_[i] = false; + } + } + + virtual ~Riscv64RegAllocator() {} + + void InitAvailReg(); + bool AllocatePhysicalRegister(RegOperand *opnd, OpndProp *prop); + void PreAllocate(); + void ReleaseReg(RegType regty, Riscv64reg_t reg); + void ReleaseReg(RegOperand *regopnd, OpndProp *prop); + void GetPhysicalRegisterBank(RegType regty, uint8 &start, uint8 &end); + void AllocHandleCallee(Insn *insn, const Riscv64MD *md); + bool IsSpecialReg(Riscv64reg_t reg); + bool IsUntouchableReg(uint32 regno); + void SaveCalleeSavedReg(RegOperand *opnd); + virtual void StorePseudoRegister(RegOperand *regopnd, Riscv64reg_t regNo, Insn *insn, BB *bb) {} + + virtual regno_t DoRegisterSpill(RegOperand *regopnd, Insn *insn, bool isDstRegister, BB *bb) { + return 0; + } + + const char *PhaseName() { + return "regalloc"; + } +}; + +class DefaultO0RegAllocator : public Riscv64RegAllocator { + public: + DefaultO0RegAllocator(CGFunc *cgfunc, MapleAllocator *mallocator) : Riscv64RegAllocator(cgfunc, mallocator) {} + + ~DefaultO0RegAllocator() override {} + + bool AllocateRegisters() override; +}; + +class O1RegAllocator : public Riscv64RegAllocator { + public: + O1RegAllocator(CGFunc *cgfunc, MapleAllocator *mallocator) + : Riscv64RegAllocator(cgfunc, mallocator), m_intRegIndex(0), m_floatRegIndex(0), m_validIndex(0) {} + + ~O1RegAllocator() override {} + + bool AllocateRegisters() override; + regno_t DoRegisterSpill(RegOperand *regopnd, Insn *insn, bool isSrcRegister, BB *bb) override; + void StorePseudoRegister(RegOperand *regopnd, Riscv64reg_t regNo, Insn *insn, BB *bb) override; + Operand *GetOperandFromAllocatedSet(regno_t); + regno_t GetVirtualRegFromPhysicalReg(Riscv64reg_t); + + private: + void CollectPRegUsesInExpr(BaseNode *expr, BB *bb); + + void CollectPRegUses(Opcode c, StmtNode *s, BB *bb); + + void CollectPRegDefsUses(BB *bb); + + void InitValidSpillRegIndex(Insn *insn); + + int GetNextIntRegIndex() { + while (!(m_validIndex & (0x1 << m_intRegIndex))) { + m_intRegIndex++; + } + return m_intRegIndex++; + } + + int GetNextFloatRegIndex() { + while (!(m_validIndex & (0x1 << (m_floatRegIndex + 8)))) { + m_floatRegIndex++; + } + return m_floatRegIndex++; + } + + void ClearRegIndex() { + m_intRegIndex = 0; + m_floatRegIndex = 0; + } + + unsigned int m_intRegIndex; + unsigned int m_floatRegIndex; + // bits[0-4] for integer registers, bits[8-12] for float registers. + unsigned int m_validIndex; +}; + +class Riscv64CallerSavedRegHandler : public CallerSavedRegHandler { + public: + Riscv64CallerSavedRegHandler(CGFunc *f /*, MapleAllocator* mallocator*/) : CallerSavedRegHandler(f) {} + + ~Riscv64CallerSavedRegHandler() {} + + inline static int Reg2BitPos(Riscv64reg_t r) { + return int(r) - 1; + } + + inline static Riscv64reg_t BitPos2Reg(int p) { + return Riscv64reg_t(p + 1); + } +}; + +static regno_t kFirstIntParamReg = R10; +static regno_t kLastIntParamReg = R17; +static regno_t kFirstIntParamEnum = kFirstIntParamReg - R0; +static regno_t kLastIntParamEnum = kLastIntParamReg - R0; + +static regno_t kFirstFpParamReg = V10; +static regno_t kLastFpParamReg = V17; +static regno_t kFirstFpParamEnum = kFirstFpParamReg - R0; +static regno_t kLastFpParamEnum = kLastFpParamReg - R0; + +static regno_t kFirstFpParamRegNum = kFirstFpParamReg - V0; +static regno_t kLastFpParamRegNum = kLastFpParamReg - V0; + +static regno_t kSpillRegEnum0 = 30; +static regno_t kSpillRegEnum1 = 31; + +class LSRALinearScanRegAllocator : public Riscv64RegAllocator { + enum SimdSlot { + /* + * Can only use slots 0 and 1 for spilling. Upper 64bits are not guaranteed + * to be preserved across a call. + */ + kRegSlot0 = 0, // enum used as index, make sure to assign proper value. + kRegSlot1 = 1, + kRegSlotNone + }; + + enum RegInCatch { + /* + * RA do not want to allocate certain registers if a live interval is + * only inside of catch blocks. + */ + kRegCatchNotInit = 0, // unitialized state + kRegNotInCatch = 1, // interval is part or all outside of catch + kRegAllInCatch // inteval is completely inside catch + }; + + enum RegInCleanup { + // Similar to reg_in_catch_t + kRegCleanupNotInit = 0, // unitialized state + kRegAllInFirstbb = 1, // interval is all in the first bb + kRegAllOutCleanup = 2, // interval is all outside of cleanup, must in normal bb, may in first bb. + kRegInCleanupAndFirstbb = 3, // inteval is in cleanup and first bb. + kRegInCleanupAndNormalbb = 4, // inteval is in cleanup and non-first bb. + kRegAllInCleanup // inteval is inside cleanup, except for bb 1 + }; + + enum IsLocalrefvar { + // Similar to reg_in_catch_t + kIsLocalrefvarUnknown = 0, + kIsLocalrefvarInvalid = 1, + kIsLocalrefvarValid + }; + + class LiveInterval { + public: + Insn *is_call; + uint32 first_def; + uint32 last_use; + uint32 phys_use; + uint32 regno; + /* physical register, using cg defined reg based on R0/V0. */ + uint32 assigned_reg; + uint32 stk_slot; + RegType regtype; + uint32 first_acrossed_call; + bool end_by_call; + bool use_before_def; + bool should_save; + bool multi_use_in_bb; // vreg has more than 1 use in bb + bool is_throwval; // only for R0(R1?) which are used for explicit incoming value of throwval; + bool is_simd_spilled; + bool is_caller_spilled; + bool must_allocate; // The register cannot be spilled (clinit pair) + uint32 ref_count; + float priority; + MapleVector> ranges; + MapleVector> holes; + MapleSet use_positions; + LiveInterval *li_parent; // Current li is in aother li's hole. + LiveInterval *li_child; // Another li is in current li's hole. + regno_t simd_spill_reg; // simd reg used for spilling + SimdSlot simd_slot; // s[0] or s[1] or none + int32 localrefvar_offset; // if spilled stack loc associated + uint32 result_count; // number of times this vreg has been written + uint32 localrefvar_count; // number of times this vreg is matched with localrefvar + private: + uint8 in_catch_state; // part or all of live interval is outside of catch blocks + uint8 in_cleanup_state; // part or all of live interval is outside of cleanup blocks + uint8 is_localrefvar_valid; // Is this live interval coupled with a local ref var + public: + LiveInterval(MapleAllocator *mallocator) + : is_call(nullptr), + first_def(0), + last_use(0), + phys_use(0), + regno(0), + assigned_reg(0), + stk_slot(-1), + regtype(kRegTyUndef), + first_acrossed_call(0), + end_by_call(false), + use_before_def(false), + should_save(false), + multi_use_in_bb(false), + is_throwval(false), + is_simd_spilled(false), + is_caller_spilled(false), + must_allocate(false), + ref_count(0), + priority(0.0), + ranges(mallocator->Adapter()), + holes(mallocator->Adapter()), + use_positions(mallocator->Adapter()), + li_parent(nullptr), + li_child(nullptr), + simd_spill_reg(0), + simd_slot(kRegSlotNone), + localrefvar_offset(0), + result_count(0), + localrefvar_count(0), + in_catch_state(kRegCatchNotInit), + in_cleanup_state(kRegCleanupNotInit), + is_localrefvar_valid(kIsLocalrefvarUnknown) {} + + virtual ~LiveInterval() {} + + void AddRange(uint32 from, uint32 to); + void AddUsePos(uint32 pos); + + void SetInCatchState() { + // Once in REG_NOT_IN_CATCH, it is irreversible since once an interval + // is not in a catch, it is not completely in a catch. + if (in_catch_state == kRegNotInCatch) { + return; + } + in_catch_state = kRegAllInCatch; + } + + void SetNotInCatchState() { + in_catch_state = kRegNotInCatch; + } + + bool IsInCatch() { + return (in_catch_state == kRegAllInCatch); + } + + void SetInCleanupState() { + switch (in_cleanup_state) { + case kRegCleanupNotInit: + in_cleanup_state = kRegAllInCleanup; + break; + case kRegAllInFirstbb: + in_cleanup_state = kRegInCleanupAndFirstbb; + break; + case kRegAllOutCleanup: + in_cleanup_state = kRegInCleanupAndNormalbb; + break; + case kRegInCleanupAndFirstbb: + break; + case kRegInCleanupAndNormalbb: + break; + case kRegAllInCleanup: + break; + default: + CG_ASSERT(false, "CG Internal error."); + break; + } + } + + void SetNotInCleanupState(bool isFirstBB) { + switch (in_cleanup_state) { + case kRegCleanupNotInit: { + if (isFirstBB) { + in_cleanup_state = kRegAllInFirstbb; + } else { + in_cleanup_state = kRegAllOutCleanup; + } + break; + } + case kRegAllInFirstbb: { + if (!isFirstBB) { + in_cleanup_state = kRegAllOutCleanup; + } + break; + } + case kRegAllOutCleanup: + break; + case kRegInCleanupAndFirstbb: { + if (!isFirstBB) { + in_cleanup_state = kRegInCleanupAndNormalbb; + } + break; + } + case kRegInCleanupAndNormalbb: + break; + case kRegAllInCleanup: { + if (isFirstBB) { + in_cleanup_state = kRegInCleanupAndFirstbb; + } else { + in_cleanup_state = kRegInCleanupAndNormalbb; + } + break; + } + default: + CG_ASSERT(false, "CG Internal error."); + break; + } + } + + bool IsAllInCleanupOrFirstBB() { + return (in_cleanup_state == kRegAllInCleanup || in_cleanup_state == kRegInCleanupAndFirstbb); + } + + bool IsAllOutCleanup() { + return in_cleanup_state == kRegAllInFirstbb || in_cleanup_state == kRegAllOutCleanup; + } + + void SetLocalRefVarStateValid() { + // Once in IS_LOCALREFVAR_INVALID, it is irreversible. + if (is_localrefvar_valid == kIsLocalrefvarInvalid) { + return; + } + is_localrefvar_valid = kIsLocalrefvarValid; + } + + void SetLocalRefVarStateInvalid() { + is_localrefvar_valid = kIsLocalrefvarInvalid; + } + + bool IsLocalRefVar() { + return is_localrefvar_valid == kIsLocalrefvarValid; + } + }; + + struct ActiveCmp { + bool operator()(const LiveInterval *lhs, const LiveInterval *rhs) const { + // elements considered equal if return false + if (lhs == rhs) { + return false; + } + if (lhs->first_def == rhs->first_def && lhs->last_use == rhs->last_use && lhs->regno == rhs->regno && + lhs->regtype == rhs->regtype && lhs->assigned_reg == rhs->assigned_reg) { + return false; + } + if (lhs->phys_use != 0 && rhs->phys_use != 0) { + if (lhs->first_def == rhs->first_def) { + return lhs->phys_use < rhs->phys_use; + } else { + return lhs->first_def < rhs->first_def; + } + } + // At this point, lhs != rhs + if (lhs->last_use == rhs->last_use) { + if (lhs->first_def > rhs->first_def) { + return false; + } else { + return true; + } + } + return lhs->last_use < rhs->last_use; + } + }; + + public: + // Comparison function for LiveInterval + MapleVector visited_bbs; + MapleVector sorted_bbs; + MapleStack dfs_bbs; + MapleVector LI_; + MapleVector last_int_param_li; + MapleVector last_fp_param_li; + MapleQueue initial_que; + typedef MapleQueue single_que; + MapleVector int_param_queue; + MapleVector fp_param_queue; + MapleList call_list; + MapleSet active; + MapleSet::iterator it_finded; + + // Change these into vectors so it can be added and deleted easily. + MapleSet simd_spill_regs; // using simd for spill int reg, both [1,0] + MapleSet simd_spill_0; // reg.s[0], available for spill + MapleSet simd_spill_1; // reg.s[1], available for spill + MapleSet int_caller_reg_set; // integer caller saved + MapleSet int_callee_reg_set; // callee + MapleSet int_param_reg_set; // parameter + MapleVector lvar_offset_regno_map; // mapping of stack offsets + // and register + uint32 int_caller_mask; // bit mask for all possible caller int + uint32 int_callee_mask; // callee + uint32 int_param_mask; // (physical-register) parameter + MapleSet fp_caller_reg_set; // float caller saved + MapleSet fp_callee_reg_set; // callee + MapleSet fp_param_reg_set; // parameter + MapleVector callee_use_cnt; // Number of time callee reg is seen + uint32_t last_simd_insn_num; + uint32_t last_simd_slot; + uint32 fp_caller_mask; // bit mask for all possible caller fp + uint32 fp_callee_mask; // callee + uint32 fp_param_mask; // (physical-register) parameter + regno_t int_spill_reg_set[MAX_INT_SPILL]; // integer regs put aside for spills + regno_t fp_spill_reg_set[MAX_FP_SPILL]; // float + regno_t simd_reg_reclaim[3]; + regno_t simd_reg_reclaim_slot[3]; + uint32 simd_reg_reclaim_idx; + uint32 int_bb_def_mask; // locally which physical reg is defined + uint32 fp_bb_def_mask; + uint32 debug_spill_cnt; + uint32 max_int_spill; // # of spill registers reserved + uint32 reg_used_in_bb_sz; + uint64 *reg_used_in_bb; + uint32 max_insn_num; + regno_t min_vreg_num; + regno_t max_vreg_num; + bool fast_alloc; + bool spill_all; + bool is_spill_zero; + bool is_mov_dst_simd_spilled; + bool is_mov_src_simd_spilled; + bool use_localvar_spill; + bool should_opt_int_callee; + bool should_opt_fp_callee; + uint64 spill_count; + uint64 reload_count; + uint64 caller_save_spill_count; + uint64 caller_save_reload_count; + uint64 simd_spill_count; + uint64 simd_reload_count; + MapleAllocator *allocator; + uint32 localrefvar_min_stack_loc; + uint32 localrefvar_max_stack_loc; + + public: + LSRALinearScanRegAllocator(CGFunc *cgfunc, MapleAllocator *mallocator) + : Riscv64RegAllocator(cgfunc, mallocator), + visited_bbs(mallocator->Adapter()), + sorted_bbs(mallocator->Adapter()), + dfs_bbs(mallocator->Adapter()), + LI_(mallocator->Adapter()), + last_int_param_li(mallocator->Adapter()), + last_fp_param_li(mallocator->Adapter()), + initial_que(mallocator->Adapter()), + int_param_queue(mallocator->Adapter()), + fp_param_queue(mallocator->Adapter()), + call_list(mallocator->Adapter()), + active(mallocator->Adapter()), + simd_spill_regs(mallocator->Adapter()), + simd_spill_0(mallocator->Adapter()), + simd_spill_1(mallocator->Adapter()), + int_caller_reg_set(mallocator->Adapter()), + int_callee_reg_set(mallocator->Adapter()), + int_param_reg_set(mallocator->Adapter()), + lvar_offset_regno_map(mallocator->Adapter()), + int_caller_mask(0), + int_callee_mask(0), + int_param_mask(0), + fp_caller_reg_set(mallocator->Adapter()), + fp_callee_reg_set(mallocator->Adapter()), + fp_param_reg_set(mallocator->Adapter()), + callee_use_cnt(mallocator->Adapter()), + last_simd_insn_num(0), + last_simd_slot(0), + fp_caller_mask(0), + fp_callee_mask(0), + fp_param_mask(0), + simd_reg_reclaim{ 0, 0, 0 }, + simd_reg_reclaim_slot{ 0, 0, 0 }, + simd_reg_reclaim_idx(0), + int_bb_def_mask(0), + fp_bb_def_mask(0), + debug_spill_cnt(0), + max_int_spill(MAX_INT_SPILL), + reg_used_in_bb_sz(0), + reg_used_in_bb(nullptr), + max_insn_num(0), + min_vreg_num(0xFFFFFFFF), + max_vreg_num(0), + fast_alloc(false), + spill_all(false), + is_spill_zero(false), + is_mov_dst_simd_spilled(false), + is_mov_src_simd_spilled(false), + use_localvar_spill(false), + should_opt_int_callee(false), + should_opt_fp_callee(false), + spill_count(0), + reload_count(0), + caller_save_spill_count(0), + caller_save_reload_count(0), + simd_spill_count(0), + simd_reload_count(0), + allocator(mallocator), + localrefvar_min_stack_loc(0), + localrefvar_max_stack_loc(0) { + for (int i = 0; i < 8; i++) { + int_param_queue.push_back(initial_que); + fp_param_queue.push_back(initial_que); + } + } + ~LSRALinearScanRegAllocator() override {} + + bool AllocateRegisters() override; + bool AllPredBBVisited(BB *); + BB *MarkStraightLineBBInBFS(BB *); + BB *SearchForStraightLineBBs(BB *); + void BFS(BB *); + void ComputeBlockOrder(); + void PrintRegSet(MapleSet set, string str); + void PrintLiveInterval(LiveInterval *li, string str); + void PrintLiveRanges(); + void PrintParamQueue(string str); + void PrintCallQueue(string str); + void PrintActiveList(string str, uint32 len = 0); + void PrintActiveListSimple(); + void PrintLiveIntervals(); + void DebugCheckActiveList(); + void InitFreeRegPool(); + void RecordCall(Insn *insn); + void RecordPhysRegs(Insn *insn, RegOperand *regOpnd, uint32 insnNum, bool isDef, bool isCall = false); + void SetupLiveInterval(Operand *opnd, Insn *insn, bool isDef, uint32 &nUses); + void ComputeLiveInterval(); + void FindLowestPrioInActive(LiveInterval **li, RegType regtype = kRegTyInt, bool startRa = false); + void LiveIntervalAnalysis(); + bool OpndNeedAllocation(Insn *insn, Operand *opnd, bool isdef, uint32 insnNum); + void InsertParamToActive(Operand *opnd, uint32 insnNum); + void InsertToActive(Operand *opnd, uint32 insnNum); + void ReturnPregToSet(LiveInterval *li, uint32 preg); + void ReleasePregToset(LiveInterval *li, uint32 preg); + void RetireFromActive(const Insn *insn); + void AssignPhysRegsForInsn(Insn *insn); + uint32 FindLocalRefVarStackLoc(Insn *insn, uint32 param); + bool DetectLocalRefVarInfo(Insn *insn, uint32 imm); + regno_t FindLocalRefVarReg(Insn *); + void MarkLocalRefVarForLiveInterval(Insn *, uint32 offset); + RegOperand *GetReplaceOpnd(Insn *insn, Operand *opnd, uint32 &spillIdx, bool isdef); + void FinalizeRegisters(); + bool UseSimdForSpill(Insn *insn, Operand *opnd, bool isDef, uint32 spillIdx = 0); + void SpillOperand(Insn *insn, Operand *opnd, bool isDef, uint32 spillIdx); + void SetOperandSpill(Operand *opnd); + RegOperand *HandleSpillForInsn(Insn *insn, Operand *opnd); + MemOperand *GetSpillMem(uint32 vregno, Insn *insn, Riscv64reg_t regno, uint8 &isOutOfRange); + RegOperand *InsertSpillReload(Insn *insn, Operand *opnd, bool isDef, uint32 spillIdx); + void InsertCallerSave(Insn *insn, Operand *opnd, bool isDef); + uint32 GetRegFromSet(MapleSet &set, regno_t offset, LiveInterval *li, regno_t forcedReg = 0); + uint32 AssignSpecialPhysRegPattern(Insn *insn, LiveInterval *li); + uint32 FindAvailablePhyReg(LiveInterval *li, Insn *insn); + RegOperand *AssignPhysRegs(Operand *opnd, Insn *insn); + void BuildIntervalRanges(); + uint32 FillInHole(LiveInterval *li); +}; + +} // namespace maplebe + +#endif // MAPLEBE_INCLUDE_CG_AARCH64REGALLOC_H_ diff --git a/mapleall/maple_be/include/cg/riscv64/riscv64_schedule.h b/mapleall/maple_be/include/cg/riscv64/riscv64_schedule.h new file mode 100644 index 0000000..c996b16 --- /dev/null +++ b/mapleall/maple_be/include/cg/riscv64/riscv64_schedule.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#ifndef AARCH64SCHEDULE_H +#define AARCH64SCHEDULE_H + +#include "schedule.h" +#include "riscv64_operand.h" + +namespace maplebe { + +enum RegisterType { + kRegisterUndef, + kRegisterInt, + kRegisterFloat, + kRegisterCc, + kRegisterLast, +}; + + +class Riscv64Schedule : public Schedule { + public: + Riscv64Schedule(CGFunc *func, MemPool *mp, LiveAnalysis *live, const char *phaseName) + : Schedule(func, mp, live, phaseName) {} + ~Riscv64Schedule() {} + protected: + void DumpDepGraph(const std::vector &nodes) const; + void GenerateDot(const BB *bb, const std::vector &nodes) const; + + private: + void Init() override; + void MemoryAccessPairOpt(BB *bb) override; + void ClinitPairOpt() override; + void RegPressureScheduling(const BB *bb, std::vector &nd) override; + void DoSchedule() override; + void ListScheduling(bool beforeRA) override; + void FinalizeScheduling(BB *bb, const DepAnalysis *depAnalysis) override; + uint32 ComputeEstart(uint32 cycle) override; + void ComputeLstart(uint32 maxEstart) override; + inline void UpdateELStartsOnCycle(uint32 cycle) override; + void RandomTest() override; + void EraseNodeFromReadyList(const DepNode *target) override; + inline uint32 GetNextSepIndex() const override; +}; + +} // namespace maplebe + +#endif // AARCH64SCHEDULE_H diff --git a/mapleall/maple_be/include/cg/riscv64/riscv64_store_load_opt.h b/mapleall/maple_be/include/cg/riscv64/riscv64_store_load_opt.h new file mode 100644 index 0000000..ce4bffe --- /dev/null +++ b/mapleall/maple_be/include/cg/riscv64/riscv64_store_load_opt.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#ifndef MAPLEBE_INCLUDE_CG_AARCH64SCHEDULING_H +#define MAPLEBE_INCLUDE_CG_AARCH64SCHEDULING_H + +#include "store_load_opt.h" + +namespace maplebe { + +using namespace maple; +using namespace std; + +class Riscv64StoreLoadOpt : public StoreLoadOpt { + private: + public: + MapleUnorderedMap> *moveInsn; + + explicit Riscv64StoreLoadOpt(CGFunc *func, MemPool *mp, ReachingDefinition *rd) + : StoreLoadOpt(func, mp, rd), + moveInsn(nullptr) {} + + ~Riscv64StoreLoadOpt() {} + + void run() override; + void DoStoreLoadOpt() override; + bool IsLiveAtInsn(Insn *defInsn, int index, Insn *startInsn, Insn *useInsn) override; + bool CanReachEndBBFromBB(BB *bb, BB *endBB, set &traversedBBSet) override; + bool IsLiveInAllPathBB(BB *startBB, BB *endBB, MapleSet &setBb, bool isParamPhyRegOpnd, + std::set &traversed) override; + void RemovDUUD(Insn *defInsn, Insn *useInsn) override; + void InsertDUUD(const DataInsnInfo &defInsnInfo, const DataInsnInfo &useInsnInfo) override; + + void DoLoadToMoveTransfer(Insn *stInsn, short stIdx, Insn *ldInsn, short ldIdx, enum OptVersion version, + const DataInsnInfo &defInsnInfo) override; + + void DoLoadZeroToMoveTransfer(Insn *stInsn, short stIdx, Insn *ldInsn, short ldIdx, enum OptVersion version) override; + + private: +}; +} // namespace maplebe +#endif // MAPLEBE_INCLUDE_CG_AARCH64SCHEDULING_H diff --git a/mapleall/maple_be/include/cg/x86/gen_mop.pl b/mapleall/maple_be/include/cg/x86/gen_mop.pl deleted file mode 100644 index 8122d4a..0000000 --- a/mapleall/maple_be/include/cg/x86/gen_mop.pl +++ /dev/null @@ -1,33 +0,0 @@ -# -# Copyright (c) [2020] Huawei Technologies Co., Ltd. All rights reserved. -# -# Licensed under the Mulan Permissive Software License v2. -# You can use this software according to the terms and conditions of the MulanPSL - 2.0. -# You may obtain a copy of MulanPSL - 2.0 at: -# -# https://opensource.org/licenses/MulanPSL-2.0 -# -# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR -# FIT FOR A PARTICULAR PURPOSE. -# See the MulanPSL - 2.0 for more details. -# -open(my $x86isa_def_h, '<', "x86isa.def.h") or die "can't open x86isa.def.h"; -open(my $x86isa_def, '>', "x86isa.def") or die "can't open x86isa.def"; -my $insn_count=1; -while(my $line = <$x86isa_def_h>) { - if ($line =~ /\/\//){ - next; - } - elsif ($line =~ /( )*MOP_/){ - $line =~ s/( )*MOP_/\#define MOP_/; - $line =~ s/,/ $insn_count/; - $insn_count++; - }else { - next; - } - print $x86isa_def $line; -} -print $x86isa_def "\#define kMopLast ".$insn_count."\n"; -close $x86isa_def; -close $x86isa_def_h; diff --git a/mapleall/maple_be/include/cg/x86/x86_md.def b/mapleall/maple_be/include/cg/x86/x86_md.def new file mode 100644 index 0000000..57c9f05 --- /dev/null +++ b/mapleall/maple_be/include/cg/x86/x86_md.def @@ -0,0 +1,681 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +// MOP_undef +DEFINE_MOP(MOP_undef, {MOPD_Undef, MOPD_Undef, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, nullptr, nullptr) +// arithmetic +// MOP_add32rr +DEFINE_MOP(MOP_add32rr, {MOPD_Reg32ID, MOPD_Reg, MOPD_Reg, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "addl", "2,0") +// MOP_add32ri, +DEFINE_MOP(MOP_add32ri, {MOPD_Reg32ID, MOPD_Reg, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "addl", "2,0") +// MOP_add32rm, +DEFINE_MOP(MOP_add32rm, {MOPD_Reg32ID, MOPD_Reg, MOPD_Mem, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "addl", "2,0") +// MOP_add32mr, +// MOP_add32mi, +// MOP_add64rr, +DEFINE_MOP(MOP_add64rr, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "addq", "2,0") +// MOP_add64ri, +DEFINE_MOP(MOP_add64ri, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "addq", "2,0") +// MOP_add64rm, +DEFINE_MOP(MOP_add64rm, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "addq", "2,0") +// MOP_add64mr, +// MOP_add64mi, +// MOP_addsdrr, +DEFINE_MOP(MOP_addsdrr, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "addsd", "2,0") +// MOP_addsdrm, +DEFINE_MOP(MOP_addsdrm, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "addsd", "2,0") +//MOP_addssrr, +DEFINE_MOP(MOP_addssrr, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "addss", "2,0") +//MOP_addssrm, +DEFINE_MOP(MOP_addssrm, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "addss", "2,0") +//MOP_addc32rr, +DEFINE_MOP(MOP_addc32rr, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Reg32ID, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "adcl", "2,0") +//MOP_addc32ri, +DEFINE_MOP(MOP_addc32ri, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "adcl", "2,0") +//MOP_addc32rm, +DEFINE_MOP(MOP_addc32rm, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "adcl", "2,0") +//MOP_addc32mr, +//MOP_addc32mi, +//MOP_div32r, // enhance when the operands is: eax edx eax edx int32 +DEFINE_MOP(MOP_div32r, {MOPD_RAX32D, MOPD_RDX32D, MOPD_RDX32S, MOPD_RAX32S, MOPD_Reg32IS}, USESPECREG, "divl", "4") +//MOP_div32m, +DEFINE_MOP(MOP_div32m, {MOPD_RAX32D, MOPD_RDX32D, MOPD_RDX32S, MOPD_RAX32S, MOPD_Mem32S}, USESPECREG, "divl", "4") +//MOP_div64r, +DEFINE_MOP(MOP_div64r, {MOPD_RAX64D, MOPD_RDX64D, MOPD_RDX64S, MOPD_RAX64S, MOPD_Reg64IS}, USESPECREG, "divq", "4") +//MOP_div64m, +DEFINE_MOP(MOP_div64m, {MOPD_RAX64D, MOPD_RDX64D, MOPD_RDX64S, MOPD_RAX64S, MOPD_Mem64S}, USESPECREG, "divq", "4") +//MOP_idiv32r, +DEFINE_MOP(MOP_idiv32r, {MOPD_RAX32D, MOPD_RDX32D, MOPD_RDX32S, MOPD_RAX32S, MOPD_Reg32IS}, USESPECREG, "idivl", "4") +//MOP_idiv32m, +DEFINE_MOP(MOP_idiv32m, {MOPD_RAX32D, MOPD_RDX32D, MOPD_RDX32S, MOPD_RAX32S, MOPD_Mem32S}, USESPECREG, "idivl", "4") +//MOP_idiv64r, +DEFINE_MOP(MOP_idiv64r, {MOPD_RAX64D, MOPD_RDX64D, MOPD_RDX64S, MOPD_RAX64S, MOPD_Reg64IS}, USESPECREG, "idivq", "4") +//MOP_idiv64m, +DEFINE_MOP(MOP_idiv64m, {MOPD_RAX64D, MOPD_RDX64D, MOPD_RDX64S, MOPD_RAX64S, MOPD_Mem64S}, USESPECREG, "idivq", "4") +//MOP_imul32rr, +DEFINE_MOP(MOP_imul32rr, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "imull", "2,0") +//MOP_imul32ri, +DEFINE_MOP(MOP_imul32ri, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "imull", "2,0") +//MOP_imul32rm, +DEFINE_MOP(MOP_imul32rm, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "imull", "2,0") +//MOP_imul64rr, +DEFINE_MOP(MOP_imul64rr, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "imulq", "2,0") +//MOP_imul64ri, +DEFINE_MOP(MOP_imul64ri, {MOPD_Reg64ID, MOPD_Reg64ID, MOPD_Imm64, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "imulq", "2,0") +//MOP_imul64rm, +DEFINE_MOP(MOP_imul64rm, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "imulq", "2,0") +//MOP_mul32, +DEFINE_MOP(MOP_mul32, {MOPD_RAX32D, MOPD_RDX32S, MOPD_RAX32S, MOPD_Reg32IS, MOPD_Undef}, USESPECREG, "mull", "3") +//MOP_mul64, +DEFINE_MOP(MOP_mul64, {MOPD_RAX64D, MOPD_RDX64S, MOPD_RAX64S, MOPD_Reg64IS, MOPD_Undef}, USESPECREG, "mulq", "3") +//MOP_mulsdrr, +DEFINE_MOP(MOP_mulsdrr, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "mulsd", "2,0") +//MOP_mulsdrm, +DEFINE_MOP(MOP_mulsdrm, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "mulsd", "2,0") +//MOP_mulssrr, +DEFINE_MOP(MOP_mulssrr, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "mulss", "2,0") +//MOP_mulssrm, +DEFINE_MOP(MOP_mulssrm, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "mulss", "2,0") +//MOP_inc32r, +DEFINE_MOP(MOP_inc32r, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "incl", "0") +//MOP_inc64r, +DEFINE_MOP(MOP_inc64r, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "incq", "0") +//MOP_inc32m, +//MOP_inc64m, +//MOP_dec32r, +DEFINE_MOP(MOP_dec32r, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "decl", "0") +//MOP_dec64r, +DEFINE_MOP(MOP_dec64r, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "decq", "0") +//MOP_dec32m, +//MOP_dec64m, +//MOP_xchg32rr, +DEFINE_MOP(MOP_xchg32rr, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "xchgl", "2,0") +//MOP_xchg32rm, +DEFINE_MOP(MOP_xchg32rm, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "xchgl", "2,0") +//MOP_xchg64rr, +DEFINE_MOP(MOP_xchg64rr, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "xchgq", "2,0") +//MOP_xchg64rm, +DEFINE_MOP(MOP_xchg64rm, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "xchgq", "2,0") +//MOP_neg32r, +DEFINE_MOP(MOP_neg32r, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "negl", "0") +//MOP_neg32m, +//MOP_neg64r, +DEFINE_MOP(MOP_neg64r, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "negq", "0") +//MOP_neg64m, +//MOP_sqrtss, +DEFINE_MOP(MOP_sqrtss, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "sqrtss", "0,1") +//MOP_sqrtsd, +DEFINE_MOP(MOP_sqrtsd, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "sqrtsd", "0,1") +//MOP_not32r, +DEFINE_MOP(MOP_not32r, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "notl", "0") +//MOP_not32m, +//MOP_not64r, +DEFINE_MOP(MOP_not64r, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "notq", "0") +//MOP_not64m, +//MOP_sub32rr, +DEFINE_MOP(MOP_sub32rr, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "subl", "2,0") +//MOP_sub32ri, +DEFINE_MOP(MOP_sub32ri, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "subl", "2,0") +//MOP_sub32rm, +DEFINE_MOP(MOP_sub32rm, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "subl", "2,0") +//MOP_sub32mr, +//MOP_sub32mi, +//MOP_sub64rr, +DEFINE_MOP(MOP_sub64rr, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "subq", "2,0") +//MOP_sub64ri, +DEFINE_MOP(MOP_sub64ri, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "subq", "2,0") +//MOP_sub64rm, +DEFINE_MOP(MOP_sub64rm, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "subq", "2,0") +//MOP_sub64mr, +//MOP_sub64mi, +//MOP_subsdrr, +DEFINE_MOP(MOP_subsdrr, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "subsd", "2,0") +//MOP_subsdrm, +DEFINE_MOP(MOP_subsdrm, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "subsd", "2,0") +//MOP_subssrr, +DEFINE_MOP(MOP_subssrr, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "subss", "2,0") +//MOP_subssrm, +DEFINE_MOP(MOP_subssrm, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "subss", "2,0") +//MOP_divssrr +DEFINE_MOP(MOP_divssrr, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "divss", "2,0") +//MOP_divssrm, +DEFINE_MOP(MOP_divssrm, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "divss", "2,0") +//MOP_divsdrr +DEFINE_MOP(MOP_divsdrr, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "divsd", "2,0") +//MOP_divsdrm, +DEFINE_MOP(MOP_divsdrm, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "divsd", "2,0") +// logic +//MOP_and32rr, +DEFINE_MOP(MOP_and32rr, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "andl", "2,0") +//MOP_and32ri, +DEFINE_MOP(MOP_and32ri, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "andl", "2,0") +//MOP_and32rm, +DEFINE_MOP(MOP_and32rm, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "andl", "2,0") +//MOP_and32mr, +//MOP_and32mi, +//MOP_and64rr, +DEFINE_MOP(MOP_and64rr, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "andq", "2,0") +//MOP_and64ri, +DEFINE_MOP(MOP_and64ri, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "andq", "2,0") +//MOP_and64rm, +DEFINE_MOP(MOP_and64rm, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "andq", "2,0") +//MOP_andpsrr, // FIXME: this is actually a vector operator +DEFINE_MOP(MOP_andpsrr, {MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "andps", "2,0") +//MOP_andpdrr, // FIXME: this is actually a vector operator +DEFINE_MOP(MOP_andpdrr, {MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "andpd", "2,0") +//MOP_andnpsrr, // FIXME: this is actually a vector operator +DEFINE_MOP(MOP_andnpsrr, {MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "andnps", "2,0") +//MOP_andnpdrr, // FIXME: this is actually a vector operator +DEFINE_MOP(MOP_andnpdrr, {MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "andnpd", "2,0") +//MOP_orpsrr, // FIXME: this is actually a vector operator +DEFINE_MOP(MOP_orpsrr, {MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "orps", "2,0") +//MOP_orpdrr, // FIXME: this is actually a vector operator +DEFINE_MOP(MOP_orpdrr, {MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "orpd", "2,0") +//MOP_and64mr, +//MOP_and64mi, +//MOP_or32rr, +DEFINE_MOP(MOP_or32rr, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "orl", "2,0") +//MOP_or32ri, +DEFINE_MOP(MOP_or32ri, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "orl", "2,0") +//MOP_or32rm, +DEFINE_MOP(MOP_or32rm, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "orl", "2,0") +//MOP_or32mr, +//MOP_or32mi, +//MOP_or64rr, +DEFINE_MOP(MOP_or64rr, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "orq", "2,0") +//MOP_or64ri, +DEFINE_MOP(MOP_or64ri, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "orq", "2,0") +//MOP_or64rm, +DEFINE_MOP(MOP_or64rm, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "orq", "2,0") +//MOP_or64mr, +//MOP_or64mi, +//MOP_ori32, +//MOP_ori64, +//MOP_ror32, +DEFINE_MOP(MOP_ror32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "rorl", "2,0") +//MOP_ror64, +DEFINE_MOP(MOP_ror64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "rorq", "2,0") +//MOP_rori32, +DEFINE_MOP(MOP_rori32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "rorl", "2,0") +//MOP_rori64, +DEFINE_MOP(MOP_rori64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "rorq", "2,0") +//MOP_rol32, +DEFINE_MOP(MOP_rol32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "roll", "2,0") +//MOP_rol64, +DEFINE_MOP(MOP_rol64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "rolq", "2,0") +//MOP_roli32, +DEFINE_MOP(MOP_roli32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "roll", "2,0") +//MOP_roli64, +DEFINE_MOP(MOP_roli64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "rolq", "2,0") +//MOP_xor32rr, +DEFINE_MOP(MOP_xor32rr, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "xorl", "2,0") +//MOP_xor32ri, +DEFINE_MOP(MOP_xor32ri, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "xorl", "2,0") +//MOP_xor32rm, +DEFINE_MOP(MOP_xor32rm, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "xorl", "2,0") +//MOP_xor64rr, +DEFINE_MOP(MOP_xor64rr, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "xorq", "2,0") +//MOP_xor64ri, +DEFINE_MOP(MOP_xor64ri, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "xorq", "2,0") +//MOP_xor64rm, +DEFINE_MOP(MOP_xor64rm, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Mem, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "xorq", "2,0") +//MOP_xorps32rr, +DEFINE_MOP(MOP_xorps32rr, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "xorps", "2,0") +//MOP_xorps32rm, +DEFINE_MOP(MOP_xorps32rm, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "xorps", "2,0") +//MOP_xorpd64rr, +DEFINE_MOP(MOP_xorpd64rr, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "xorpd", "2,0") +//MOP_xorpd64rm, // fixme mem here is 128 +DEFINE_MOP(MOP_xorpd64rm, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "xorpd", "2,0") +//MOP_xor64mr, +//MOP_xor64mi, +//MOP_ori32, +//MOP_ori64, +//MOP_sar32, +DEFINE_MOP(MOP_sar32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RCX8S, MOPD_Undef, MOPD_Undef}, ISX86STYLE | USESPECREG, "sarl", "2,0") +//MOP_sar64, +DEFINE_MOP(MOP_sar64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RCX8S, MOPD_Undef, MOPD_Undef}, ISX86STYLE | USESPECREG, "sarq", "2,0") +//MOP_sari32, +DEFINE_MOP(MOP_sari32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "sarl", "2,0") +//MOP_sari64, +DEFINE_MOP(MOP_sari64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "sarq", "2,0") +//MOP_shl32, +DEFINE_MOP(MOP_shl32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RCX8S, MOPD_Undef, MOPD_Undef}, ISX86STYLE | USESPECREG, "shll", "2,0") +//MOP_shld32, +DEFINE_MOP(MOP_shld32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Undef}, ISX86STYLE, "shldl", "2,0") +//MOP_shldi32, +DEFINE_MOP(MOP_shldi32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Imm32, MOPD_Undef}, ISX86STYLE, "shldl", "2,0") +//MOP_shrd32, +DEFINE_MOP(MOP_shrd32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Undef}, ISX86STYLE, "shrdl", "2,0") +//MOP_shrdi32, +DEFINE_MOP(MOP_shrdi32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Imm32, MOPD_Undef}, ISX86STYLE, "shrdl", "2,0") +//MOP_shl64, +DEFINE_MOP(MOP_shl64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RCX8S, MOPD_Undef, MOPD_Undef}, ISX86STYLE | USESPECREG, "shlq", "0") +//MOP_shli32, +DEFINE_MOP(MOP_shli32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "shll", "2,0") +//MOP_shli64, +DEFINE_MOP(MOP_shli64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "shlq", "2,0") +//MOP_shr32, +DEFINE_MOP(MOP_shr32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RCX8S, MOPD_Undef, MOPD_Undef}, ISX86STYLE | USESPECREG, "shrl", "0") +//MOP_shr64, +DEFINE_MOP(MOP_shr64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RCX8S, MOPD_Undef, MOPD_Undef}, ISX86STYLE | USESPECREG, "shlr", "0") +//MOP_shri32, +DEFINE_MOP(MOP_shri32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "shrl", "2,0") +//MOP_shri64, +DEFINE_MOP(MOP_shri64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "shrq", "2,0") +//MOP_minssrr, +DEFINE_MOP(MOP_minssrr, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "minss", "2,0") +//MOP_minssrm, +DEFINE_MOP(MOP_minssrm, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "minss", "2,0") +//MOP_minsdrr, +DEFINE_MOP(MOP_minsdrr, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "minsd", "2,0") +//MOP_minsdrm, +DEFINE_MOP(MOP_minsdrm, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "minsd", "2,0") +//MOP_maxssrr, +DEFINE_MOP(MOP_maxssrr, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "maxss", "2,0") +//MOP_maxssrm, +DEFINE_MOP(MOP_maxssrm, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "maxss", "2,0") +//MOP_maxsdrr, +DEFINE_MOP(MOP_maxsdrr, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "maxsd", "2,0") +//MOP_maxsdrm, +DEFINE_MOP(MOP_maxsdrm, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "maxsd", "2,0") +//MOP_cmp32rr, +DEFINE_MOP(MOP_cmp32rr, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef}, 0, "cmpl", "2,1") +//MOP_cmp32ri, +DEFINE_MOP(MOP_cmp32ri, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, 0, "cmpl", "2,1") +//MOP_cmp32rm, +DEFINE_MOP(MOP_cmp32rm, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, 0, "cmpl", "2,1") +//MOP_cmp64rr, +DEFINE_MOP(MOP_cmp64rr, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef}, 0, "cmpq", "2,1") +//MOP_cmp64ri, +DEFINE_MOP(MOP_cmp64ri, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, 0, "cmpq", "2,1") +//MOP_cmp64rm, +DEFINE_MOP(MOP_cmp64rm, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, 0, "cmpq", "2,1") +//MOP_comisdrr, +DEFINE_MOP(MOP_comisdrr, {MOPD_RegCCD, MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef}, 0, "comisd", "2,1") +//MOP_comisdrm, +DEFINE_MOP(MOP_comisdrm, {MOPD_RegCCD, MOPD_Reg64FS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, 0, "comisd", "2,1") +//MOP_comissrr, +DEFINE_MOP(MOP_comissrr, {MOPD_RegCCD, MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef}, 0, "comiss", "2,1") +//MOP_comissrm, +DEFINE_MOP(MOP_comissrm, {MOPD_RegCCD, MOPD_Reg32FS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, 0, "comiss", "2,1") +//MOP_ucomisdrr, +DEFINE_MOP(MOP_ucomisdrr, {MOPD_RegCCD, MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef}, 0, "ucomisd", "2,1") +//MOP_ucomisdrm, +DEFINE_MOP(MOP_ucomisdrm, {MOPD_RegCCD, MOPD_Reg64FS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, 0, "ucomisd", "2,1") +//MOP_ucomissrr, +DEFINE_MOP(MOP_ucomissrr, {MOPD_RegCCD, MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef}, 0, "ucomiss", "2,1") +//MOP_ucomissrm, +DEFINE_MOP(MOP_ucomissrm, {MOPD_RegCCD, MOPD_Reg32FS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, 0, "ucomiss", "2,1") +//MOP_cmpssrr, +DEFINE_MOP(MOP_cmpssrr, {MOPD_Reg, MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Imm32, MOPD_Undef}, ISX86STYLE, "cmpss", "3,2,0") +//MOP_cmpssrm, +DEFINE_MOP(MOP_cmpssrm, {MOPD_Reg, MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Mem32S, MOPD_Undef}, ISX86STYLE, "cmpss", "3,2,0") +//MOP_cmpsdrr, +DEFINE_MOP(MOP_cmpsdrr, {MOPD_Reg, MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Imm32, MOPD_Undef}, ISX86STYLE, "cmpsd", "3,2,0") +//MOP_cmpsdrm, +DEFINE_MOP(MOP_cmpsdrm, {MOPD_Reg, MOPD_Reg64FS, MOPD_Mem64S, MOPD_Imm32, MOPD_Undef}, ISX86STYLE, "cmpsd", "3,2,0") +//MOP_test32rr, +DEFINE_MOP(MOP_test32rr, {MOPD_RegCCD, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef}, 0, "testl", "2,1") +//MOP_test32ri, +DEFINE_MOP(MOP_test32ri, {MOPD_RegCCD, MOPD_Reg32IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, 0, "testl", "2,1") +//MOP_test32rm, +DEFINE_MOP(MOP_test32rm, {MOPD_RegCCD, MOPD_Reg32IS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, 0, "testl", "2,1") +//MOP_test64rr, +DEFINE_MOP(MOP_test64rr, {MOPD_RegCCD, MOPD_Reg64IS, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef}, 0, "testq", "2,1") +//MOP_test64ri, +DEFINE_MOP(MOP_test64ri, {MOPD_RegCCD, MOPD_Reg64IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, 0, "testq", "2,1") +//MOP_test64rm, +DEFINE_MOP(MOP_test64rm, {MOPD_RegCCD, MOPD_Reg64IS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, 0, "testq", "2,1") +// program flow +//MOP_call, +DEFINE_MOP(MOP_call, {MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "call", "0") +//MOP_icallr, +DEFINE_MOP(MOP_icallr, {MOPD_Reg64IS, MOPD_Undef, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "call", "*0") +//MOP_icallm, +DEFINE_MOP(MOP_icallm, {MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "call", "0") +//MOP_jb, +DEFINE_MOP(MOP_jb, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jb", "1") +//MOP_jae, +DEFINE_MOP(MOP_jae, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jae", "1") +//MOP_jp, +DEFINE_MOP(MOP_jp, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jp", "1") +//MOP_jnp, +DEFINE_MOP(MOP_jnp, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jnp", "1") +//MOP_je, +DEFINE_MOP(MOP_je, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "je", "1") +//MOP_jne, +DEFINE_MOP(MOP_jne, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jne", "1") +//MOP_jbe, +DEFINE_MOP(MOP_jbe, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jbe", "1") +//MOP_ja, +DEFINE_MOP(MOP_ja, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "ja", "1") +//MOP_jl, +DEFINE_MOP(MOP_jl, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jl", "1") +//MOP_jge, +DEFINE_MOP(MOP_jge, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jge", "1") +//MOP_jle, +DEFINE_MOP(MOP_jle, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jle", "1") +//MOP_jg, +DEFINE_MOP(MOP_jg, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jg", "1") +//MOP_jcxz, +DEFINE_MOP(MOP_jcxz, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jcxz", "1") +//MOP_jecxz, +DEFINE_MOP(MOP_jecxz, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jecxz", "1") +//MOP_jrcxz, +DEFINE_MOP(MOP_jrcxz, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jrcxz", "1") +//MOP_js, +DEFINE_MOP(MOP_js, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "js", "1") +//MOP_jns, +DEFINE_MOP(MOP_jns, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jns", "1") +//MOP_jmp, +DEFINE_MOP(MOP_jmp, {MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jmp", "0") +//MOP_ijmpr, +DEFINE_MOP(MOP_ijmpr, {MOPD_Reg64IS, MOPD_Undef, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jmp", "*0") +//MOP_ijmpm, +DEFINE_MOP(MOP_ijmpm, {MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jmp", "*0") +//MOP_leave, +DEFINE_MOP(MOP_leave, {MOPD_Reg, MOPD_Reg, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "leave", "") +//MOP_ret, +DEFINE_MOP(MOP_ret, {MOPD_Undef, MOPD_Undef, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "ret", "") +//MOP_reti, +DEFINE_MOP(MOP_reti, {MOPD_Imm64, MOPD_Undef, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "ret", "0") + +//MOP_seta, +DEFINE_MOP(MOP_seta, {MOPD_Reg8ID, MOPD_RegCCS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "seta", "0") +//MOP_setae, +DEFINE_MOP(MOP_setae, {MOPD_Reg8ID, MOPD_RegCCS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "setae", "0") + +//MOP_setb, +DEFINE_MOP(MOP_setb, {MOPD_Reg8ID, MOPD_RegCCS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "setb", "0") +//MOP_setbe, +DEFINE_MOP(MOP_setbe, {MOPD_Reg8ID, MOPD_RegCCS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "setbe", "0") + +//MOP_setc, +DEFINE_MOP(MOP_setc, {MOPD_Reg8ID, MOPD_RegCCS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "setc", "0") +//MOP_sete, +DEFINE_MOP(MOP_sete, {MOPD_Reg8ID, MOPD_RegCCS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "sete", "0") + +//MOP_setg, +DEFINE_MOP(MOP_setg, {MOPD_Reg8ID, MOPD_RegCCS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "setg", "0") +//MOP_setge, +DEFINE_MOP(MOP_setge, {MOPD_Reg8ID, MOPD_RegCCS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "setge", "0") + +//MOP_setl, +DEFINE_MOP(MOP_setl, {MOPD_Reg8ID, MOPD_RegCCS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "setl", "0") +//MOP_setle, +DEFINE_MOP(MOP_setle, {MOPD_Reg8ID, MOPD_RegCCS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "setle", "0") + +//MOP_setp, +DEFINE_MOP(MOP_setp, {MOPD_Reg8ID, MOPD_RegCCS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "setp", "0") +//MOP_setnp, +DEFINE_MOP(MOP_setnp, {MOPD_Reg8ID, MOPD_RegCCS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "setnp", "0") + +//MOP_setne, +DEFINE_MOP(MOP_setne, {MOPD_Reg8ID, MOPD_RegCCS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "setne", "0") + +// string operation +// data movement +//MOP_cmovb32, +DEFINE_MOP(MOP_cmovb32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovb", "1,0") +//MOP_cmovae32, +DEFINE_MOP(MOP_cmovae32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovae", "1,0") +//MOP_cmovp32, +DEFINE_MOP(MOP_cmovp32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovp", "1,0") +//MOP_cmovnp32, +DEFINE_MOP(MOP_cmovnp32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovnp", "1,0") +//MOP_cmove32, +DEFINE_MOP(MOP_cmove32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmove", "1,0") +//MOP_cmovne32, +DEFINE_MOP(MOP_cmovne32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovne", "1,0") +//MOP_cmovbe32, +DEFINE_MOP(MOP_cmovbe32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovbe", "1,0") +//MOP_cmova32, +DEFINE_MOP(MOP_cmova32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmova", "1,0") +//MOP_cmovl32, +DEFINE_MOP(MOP_cmovl32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovl", "1,0") +//MOP_cmovge32, +DEFINE_MOP(MOP_cmovge32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovge", "1,0") +//MOP_cmovle32, +DEFINE_MOP(MOP_cmovle32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovle", "1,0") +//MOP_cmovg32, +DEFINE_MOP(MOP_cmovg32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovg", "1,0") +//MOP_cmovs32, +DEFINE_MOP(MOP_cmovs32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovs", "1,0") +//MOP_cmovz32, +DEFINE_MOP(MOP_cmovz32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovz", "1,0") +//MOP_cmovo32, +DEFINE_MOP(MOP_cmovo32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovo", "1,0") +//MOP_cmovns32, +DEFINE_MOP(MOP_cmovns32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovns", "1,0") +//MOP_cmovb64, +DEFINE_MOP(MOP_cmovb64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovbq", "1,0") +//MOP_cmovae64, +DEFINE_MOP(MOP_cmovae64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovae", "1,0") +//MOP_cmovp64, +DEFINE_MOP(MOP_cmovp64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovp", "1,0") +//MOP_cmovnp64, +DEFINE_MOP(MOP_cmovnp64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovnp", "1,0") +//MOP_cmove64, +DEFINE_MOP(MOP_cmove64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmove", "1,0") +//MOP_cmovne64, +DEFINE_MOP(MOP_cmovne64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovne", "1,0") +//MOP_cmovbe64, +DEFINE_MOP(MOP_cmovbe64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovbe", "1,0") +//MOP_cmova64, +DEFINE_MOP(MOP_cmova64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmova", "1,0") +//MOP_cmovl64, +DEFINE_MOP(MOP_cmovl64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovl", "1,0") +//MOP_cmovge64, +DEFINE_MOP(MOP_cmovge64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovge", "1,0") +//MOP_cmovle64, +DEFINE_MOP(MOP_cmovle64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovle", "1,0") +//MOP_cmovg64, +DEFINE_MOP(MOP_cmovg64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovg", "1,0") +//MOP_cmovs64, +DEFINE_MOP(MOP_cmovs64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovs", "1,0") +//MOP_cmovz64, +DEFINE_MOP(MOP_cmovz64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovz", "1,0") +//MOP_cmovo64, +DEFINE_MOP(MOP_cmovo64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovo", "1,0") +//MOP_cmovns64, +DEFINE_MOP(MOP_cmovns64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovns", "1,0") +//MOP_ld8, +//MOP_ld16, +//MOP_ld32, +DEFINE_MOP(MOP_ld32, {MOPD_Reg32ID, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movl", "1,0") +//MOP_ld64, +DEFINE_MOP(MOP_ld64, {MOPD_Reg64ID, MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movq", "1,0") +//MOP_ldu8, +//MOP_ldu16, +//MOP_ldss, +DEFINE_MOP(MOP_ldss, {MOPD_Reg32FD, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movss", "1,0") +//MOP_ldsd, +DEFINE_MOP(MOP_ldsd, {MOPD_Reg64FD, MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movsd", "1,0") +//MOP_st8, +DEFINE_MOP(MOP_st8, {MOPD_Reg8IS, MOPD_Mem, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISSTORE, "movb", "0,1") +//MOP_st16, +DEFINE_MOP(MOP_st16, {MOPD_Reg16IS, MOPD_Mem, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISSTORE, "movw", "0,1") +//MOP_st32, +DEFINE_MOP(MOP_st32, {MOPD_Reg32IS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISSTORE, "movl", "0,1") +//MOP_st64, +DEFINE_MOP(MOP_st64, {MOPD_Reg64IS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISSTORE, "movq", "0,1") +//MOP_stss, +DEFINE_MOP(MOP_stss, {MOPD_Reg32FS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISSTORE, "movss", "0,1") +//MOP_stsd, +DEFINE_MOP(MOP_stsd, {MOPD_Reg64FS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISSTORE, "movsd", "0,1") +//MOP_lea32, +DEFINE_MOP(MOP_lea32, {MOPD_Reg32ID, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "leal", "1,0") +//MOP_lea64, +DEFINE_MOP(MOP_lea64, {MOPD_Reg64ID, MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "leaq", "1,0") +//MOP_ldc32, +DEFINE_MOP(MOP_ldc32, {MOPD_Reg32ID, MOPD_Imm32, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movl", "1,0") +//MOP_ldc64, +DEFINE_MOP(MOP_ldc64, {MOPD_Reg64ID, MOPD_Imm64, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movq", "1,0") +//MOP_ldc32abs, +DEFINE_MOP(MOP_ldc32abs, {MOPD_Reg32ID, MOPD_Imm32, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movabsl", "1,0") +//MOP_ldc64abs, +DEFINE_MOP(MOP_ldc64abs, {MOPD_Reg64ID, MOPD_Imm64, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movabsq", "1,0") +//MOP_mov32, +DEFINE_MOP(MOP_mov32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movl", "1,0") +//MOP_mov64, +DEFINE_MOP(MOP_mov64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movq", "1,0") +//MOP_movabs32, +DEFINE_MOP(MOP_movabs32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movabsl", "1,0") +//MOP_movabs64, +DEFINE_MOP(MOP_movabs64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movabsq", "1,0") +//MOP_movss, +DEFINE_MOP(MOP_movss, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movss", "1,0") +//MOP_movsd, +DEFINE_MOP(MOP_movsd, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movsd", "1,0") +//MOP_movsbl, +DEFINE_MOP(MOP_movsbl, {MOPD_Reg32ID, MOPD_Reg, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movsbl", "1,0") +//MOP_movzbl, +DEFINE_MOP(MOP_movzbl, {MOPD_Reg32ID, MOPD_Reg, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movzbl", "1,0") +//MOP_movswl, +DEFINE_MOP(MOP_movswl, {MOPD_Reg32ID, MOPD_Reg, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movswl", "1,0") +//MOP_movzwl, +DEFINE_MOP(MOP_movzwl, {MOPD_Reg32ID, MOPD_Reg, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movzwl", "1,0") +//MOP_movsbq, +DEFINE_MOP(MOP_movsbq, {MOPD_Reg64ID, MOPD_Reg, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movsbq", "1,0") +//MOP_movzbq, +DEFINE_MOP(MOP_movzbq, {MOPD_Reg64ID, MOPD_Reg, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movzbq", "1,0") +//MOP_movswq, +DEFINE_MOP(MOP_movswq, {MOPD_Reg64ID, MOPD_Reg, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movswq", "1,0") +//MOP_movzwq, +DEFINE_MOP(MOP_movzwq, {MOPD_Reg64ID, MOPD_Reg, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movzwq", "1,0") +//MOP_movslq, +DEFINE_MOP(MOP_movslq, {MOPD_Reg64ID, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movslq", "1,0") +//MOP_movzlq, +DEFINE_MOP(MOP_movzlq, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movl", "1,0") +//MOP_movzql, // trunc +DEFINE_MOP(MOP_movzql, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movl", "1,0") +//MOP_movi2fd, // for bit cast int to float +DEFINE_MOP(MOP_movi2fd, {MOPD_Reg32FD, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movd", "1,0") +//MOP_movi2fq, +DEFINE_MOP(MOP_movi2fq, {MOPD_Reg64FD, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movq", "1,0") +//MOP_movf2id, // for bit cast float to int +DEFINE_MOP(MOP_movf2id, {MOPD_Reg32ID, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movd", "1,0") +//MOP_movf2iq, +DEFINE_MOP(MOP_movf2iq, {MOPD_Reg64ID, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movq", "1,0") +//MOP_ldsbl, +DEFINE_MOP(MOP_ldsbl, {MOPD_Reg32ID, MOPD_Mem, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movsbl", "1,0") +//MOP_ldzbl, +DEFINE_MOP(MOP_ldzbl, {MOPD_Reg32ID, MOPD_Mem, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movzbl", "1,0") +//MOP_ldswl, +DEFINE_MOP(MOP_ldswl, {MOPD_Reg32ID, MOPD_Mem, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movswl", "1,0") +//MOP_ldzwl, +DEFINE_MOP(MOP_ldzwl, {MOPD_Reg32ID, MOPD_Mem, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movzwl", "1,0") +//MOP_ldsbq, +DEFINE_MOP(MOP_ldsbq, {MOPD_Reg64ID, MOPD_Mem, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movsbq", "1,0") +//MOP_ldzbq, +DEFINE_MOP(MOP_ldzbq, {MOPD_Reg64ID, MOPD_Mem, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movzbq", "1,0") +//MOP_ldswq, +DEFINE_MOP(MOP_ldswq, {MOPD_Reg64ID, MOPD_Mem, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movswq", "1,0") +//MOP_ldzwq, +DEFINE_MOP(MOP_ldzwq, {MOPD_Reg64ID, MOPD_Mem, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movzwq", "1,0") +//MOP_ldslq, +DEFINE_MOP(MOP_ldslq, {MOPD_Reg64ID, MOPD_Mem, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movslq", "1,0") +//MOP_ldzlq, // x86-64 is default by zero extended, so this is actually movl +DEFINE_MOP(MOP_ldzlq, {MOPD_Reg32ID, MOPD_Mem, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movl", "1,0") +//MOP_ldi2fd, +DEFINE_MOP(MOP_ldi2fd, {MOPD_Reg32FD, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movd", "1,0") +//MOP_ldi2fq, +DEFINE_MOP(MOP_ldi2fq, {MOPD_Reg64FD, MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movq", "1,0") + //MOP_ldf2id, +DEFINE_MOP(MOP_ldf2id, {MOPD_Reg32ID, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movd", "1,0") +//MOP_ldf2iq, +DEFINE_MOP(MOP_ldf2iq, {MOPD_Reg64ID, MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movq", "1,0") +//MOP_popl, +DEFINE_MOP(MOP_popl, {MOPD_Reg32ID, MOPD_Reg, MOPD_Reg, MOPD_Undef, MOPD_Undef}, 0, "popl", "0") +//MOP_popq, +DEFINE_MOP(MOP_popq, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef}, 0, "popq", "0") +//MOP_pushl, +DEFINE_MOP(MOP_pushl, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef}, 0, "pushl", "0") +//MOP_pushq, +DEFINE_MOP(MOP_pushq, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef}, 0, "pushq", "1") +//MOP_cvtss2sdr, +DEFINE_MOP(MOP_cvtss2sdr, {MOPD_Reg64FD, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtss2sd", "1,0") +//MOP_cvtss2sdm, +DEFINE_MOP(MOP_cvtss2sdm, {MOPD_Reg64FD, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtss2sd", "1,0") +//MOP_cvtsd2ssr, +DEFINE_MOP(MOP_cvtsd2ssr, {MOPD_Reg32FD, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtsd2ss", "1,0") +//MOP_cvtsd2ssm, +DEFINE_MOP(MOP_cvtsd2ssm, {MOPD_Reg32FD, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtsd2ss", "1,0") +//MOP_cvtsi2sdr, +DEFINE_MOP(MOP_cvtsi2sdr, {MOPD_Reg64FD, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtsi2sdl", "1,0") +//MOP_cvtsi2sdm, +DEFINE_MOP(MOP_cvtsi2sdm, {MOPD_Reg64FD, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtsi2sdl", "1,0") +//MOP_cvtsi2ssr, +DEFINE_MOP(MOP_cvtsi2ssr, {MOPD_Reg32FD, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtsi2ssl", "1,0") +//MOP_cvtsi2ssm, +DEFINE_MOP(MOP_cvtsi2ssm, {MOPD_Reg32FD, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtsi2ssl", "1,0") +//MOP_cvtsi2sdqr, +DEFINE_MOP(MOP_cvtsi2sdqr, {MOPD_Reg64FD, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtsi2sdq", "1,0") +//MOP_cvtsi2sdqm, +DEFINE_MOP(MOP_cvtsi2sdqm, {MOPD_Reg64FD, MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtsi2sdq", "1,0") +//MOP_cvtsi2ssqr, +DEFINE_MOP(MOP_cvtsi2ssqr, {MOPD_Reg32FD, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtsi2ssq", "1,0") +//MOP_cvtsi2ssqm, +DEFINE_MOP(MOP_cvtsi2ssqm, {MOPD_Reg32FD, MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtsi2ssq", "1,0") +//MOP_cvtss2sir, +DEFINE_MOP(MOP_cvtss2sir, {MOPD_Reg32ID, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtss2si", "1,0") +//MOP_cvtss2sim, +DEFINE_MOP(MOP_cvtss2sim, {MOPD_Reg32ID, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtss2si", "1,0") +//MOP_cvtsd2sir, +DEFINE_MOP(MOP_cvtsd2sir, {MOPD_Reg32ID, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtsd2si", "1,0") +//MOP_cvtsd2sim, +DEFINE_MOP(MOP_cvtsd2sim, {MOPD_Reg32ID, MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtsd2si", "1,0") +//MOP_cvtss2siqr, +DEFINE_MOP(MOP_cvtss2siqr, {MOPD_Reg64ID, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtss2siq", "1,0") +//MOP_cvtss2siqm, +DEFINE_MOP(MOP_cvtss2siqm, {MOPD_Reg64ID, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtss2siq", "1,0") +//MOP_cvtsd2siqr, +DEFINE_MOP(MOP_cvtsd2siqr, {MOPD_Reg64ID, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtsd2siq", "1,0") +//MOP_cvtsd2siqm, +DEFINE_MOP(MOP_cvtsd2siqm, {MOPD_Reg64ID, MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtsd2siq", "1,0") +//MOP_cvttss2sir, +DEFINE_MOP(MOP_cvttss2sir, {MOPD_Reg32ID, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvttss2si", "1,0") +//MOP_cvttss2sim, +DEFINE_MOP(MOP_cvttss2sim, {MOPD_Reg32ID, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvttss2si", "1,0") +//MOP_cvttss2si64r, +DEFINE_MOP(MOP_cvttss2si64r, {MOPD_Reg64ID, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvttss2si", "1,0") +//MOP_cvttss2si64m, +DEFINE_MOP(MOP_cvttss2si64m, {MOPD_Reg64ID, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvttss2si", "1,0") +//MOP_cvttsd2sir, +DEFINE_MOP(MOP_cvttsd2sir, {MOPD_Reg32ID, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvttsd2si", "1,0") +//MOP_cvttsd2sim, +DEFINE_MOP(MOP_cvttsd2sim, {MOPD_Reg32ID, MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvttsd2si", "1,0") +//MOP_cvttsd2si64r, +DEFINE_MOP(MOP_cvttsd2si64r, {MOPD_Reg64ID, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvttsd2si", "1,0") +//MOP_cvttsd2si64m, +DEFINE_MOP(MOP_cvttsd2si64m, {MOPD_Reg64ID, MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvttsd2si", "1,0") +//MOP_cvttss2siqr, +DEFINE_MOP(MOP_cvttss2siqr, {MOPD_Reg64ID, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvttss2siq", "1,0") +//MOP_cvttss2siqm, +DEFINE_MOP(MOP_cvttss2siqm, {MOPD_Reg64ID, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvttss2siq", "1,0") +//MOP_cvttsd2siqr, +DEFINE_MOP(MOP_cvttsd2siqr, {MOPD_Reg64ID, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvttsd2siq", "1,0") +//MOP_cvttsd2siqm, +DEFINE_MOP(MOP_cvttsd2siqm, {MOPD_Reg64ID, MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvttsd2siq", "1,0") +// mis +//MOP_cltd, +//MOP_cqto, +// MOP_zero32i +DEFINE_MOP(MOP_zero32i, {MOPD_Reg32ID, MOPD_Undef, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "xor", "0,0") +// MOP_zero32f +DEFINE_MOP(MOP_zero32f, {MOPD_Reg32FD, MOPD_Undef, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "xorps", "0,0") +// MOP_zero64f +DEFINE_MOP(MOP_zero64f, {MOPD_Reg64FD, MOPD_Undef, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "xorpd", "0,0") diff --git a/mapleall/maple_be/src/be/aarch64/aarch64_rt_support.cpp b/mapleall/maple_be/src/be/aarch64/aarch64_rt_support.cpp new file mode 100644 index 0000000..b62a0bd --- /dev/null +++ b/mapleall/maple_be/src/be/aarch64/aarch64_rt_support.cpp @@ -0,0 +1,22 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#include "aarch64_rt_support.h" + +namespace maplebe { + +// Currently nothing is here. + +} // namespace maplebe diff --git a/mapleall/maple_be/src/be/be_common.cpp b/mapleall/maple_be/src/be/be_common.cpp index f6b8dfa..1eecaea 100644 --- a/mapleall/maple_be/src/be/be_common.cpp +++ b/mapleall/maple_be/src/be/be_common.cpp @@ -183,9 +183,13 @@ void BECommon::ComputeTypeSizesAligns(MIRType *ty, uint8 align) { struct_fieldcount_table[structty->tyIdx.GetIdx()] = numFieldElems; if (numFieldElems == 0) { - // This is for C. For C++, size is 1. - type_size_table[i.GetIdx()] = 0; - type_align_table[i.GetIdx()] = 8; + if (structty->isCPlusPlus) { + type_size_table[i.GetIdx()] = 1; // empty struct in C++ has size 1 + type_align_table[i.GetIdx()] = 1; + } else { + type_size_table[i.GetIdx()] = 0; + type_align_table[i.GetIdx()] = 8; + } break; } @@ -265,6 +269,9 @@ void BECommon::ComputeTypeSizesAligns(MIRType *ty, uint8 align) { type_has_flexible_array[i.GetIdx()] = true; } } + if (allocedSize == 0 && structty->isCPlusPlus) { + allocedSize = 1; // empty struct in C++ has size 1 + } if (align) { type_size_table[i.GetIdx()] = RoundUp(allocedSize, align); } else { @@ -710,7 +717,7 @@ BaseNode *BECommon::GetAddressOfNode(BaseNode *node) { MIRType *pointedTy = GlobalTables::GetTypeTable().typeTable.at( static_cast(GlobalTables::GetTypeTable().typeTable.at(inode->tyIdx.GetIdx()))->pointedTyIdx.GetIdx()); std::pair bytebitoffset = GetFieldOffset(static_cast(pointedTy), inode->fieldID); -#if TARGAARCH64 +#if TARGAARCH64 || TARGRISCV64 ASSERT(GetAddressPrimType() == PTY_a64, "incorrect address type"); #endif return mirModule.mirBuilder->CreateExprBinary( diff --git a/mapleall/maple_be/src/be/be_lowerer.cpp b/mapleall/maple_be/src/be/be_lowerer.cpp index 6cf5ea7..ee95827 100644 --- a/mapleall/maple_be/src/be/be_lowerer.cpp +++ b/mapleall/maple_be/src/be/be_lowerer.cpp @@ -391,14 +391,9 @@ BaseNode *BELowerer::LowerArray(ArrayNode *array) { if (dim > 1) { BaseNode *prevNode = nullptr; for (int i = 0; (i < dim) && (i < numIndex); i++) { - if (i > 0) { - CHECK_FATAL(((!nestedArray && arraytype->sizeArray[i] > 0) || - (nestedArray && curArrayType->sizeArray[0] > 0)), "Zero size array dimension"); - int32 numO = array->NumOpnds(); - resNode = NodeConvert(array->primType, array->GetIndex(i)); - } uint32 mpyDim = 1; if (nestedArray) { + CHECK_FATAL(arraytype->sizeArray[0] > 0, "Zero size array dimension"); innerType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(curArrayType->eTyIdx); curArrayType = static_cast(innerType); while (innerType->GetKind() == kTypeArray) { @@ -407,13 +402,44 @@ BaseNode *BELowerer::LowerArray(ArrayNode *array) { innerType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(innerArrayType->eTyIdx); } } else { + CHECK_FATAL(arraytype->sizeArray[i] > 0, "Zero size array dimension"); for (int j = i + 1; j < dim; j++) { mpyDim *= arraytype->sizeArray[j]; } } + BaseNode *index = static_cast(array->GetIndex(i)); + bool isConst = false; + int32 indexVal = 0; + if (index->op == OP_constval) { + ConstvalNode *constNode = static_cast(index); + indexVal = (static_cast(constNode->constVal))->value; + isConst = true; + MIRIntConst *newConstNode = mirModule.memPool->New( + indexVal * mpyDim, + GlobalTables::GetTypeTable().GetTypeFromTyIdx(TyIdx(array->primType))); + BaseNode *newValNode = mirModule.CurFuncCodeMemPool()->New(newConstNode); + newValNode->primType = array->primType; + if (i == 0) { + prevNode = newValNode; + continue; + } else { + resNode = newValNode; + } + } + if (i > 0 && isConst == false) { + resNode = NodeConvert(array->primType, array->GetIndex(i)); + } + BaseNode *mpyNode; - if (mpyDim == 1 && prevNode) { + if (isConst) { + MIRIntConst *mulConst = mirModule.memPool->New( + mpyDim * indexVal, + GlobalTables::GetTypeTable().GetTypeFromTyIdx(TyIdx(array->primType))); + BaseNode *mulSize = mirModule.CurFuncCodeMemPool()->New(mulConst); + mulSize->primType = array->primType; + mpyNode = mulSize; + } else if (mpyDim == 1 && prevNode) { mpyNode = prevNode; prevNode = resNode; } else { @@ -775,7 +801,7 @@ BaseNode *BELowerer::LowerExpr(BaseNode *originParent, BaseNode *parent, BaseNod } } -#if TARGARM || TARGAARCH64 || TARGARK +#if TARGARM || TARGAARCH64 || TARGARK || TARGRISCV64 BlockNode *BELowerer::LowerReturnStruct(NaryStmtNode *retnode) { BlockNode *blk = mirModule.CurFuncCodeMemPool()->New(); for (uint32 i = 0; i < retnode->nOpnd.size(); i++) { @@ -1328,14 +1354,14 @@ BlockNode *BELowerer::LowerBlock(BlockNode *block) { case OP_intrinsiccall: case OP_call: case OP_icall: -#if TARGARM || TARGAARCH64 || TARGARK +#if TARGARM || TARGAARCH64 || TARGARK || TARGRISCV64 LowerCallStmt(stmt, nextstmt, newblk); #else LowerStmt(stmt, newblk); #endif break; case OP_return: { -#if TARGARM || TARGAARCH64 || TARGARK +#if TARGARM || TARGAARCH64 || TARGARK || TARGRISCV64 if (GetCurrentFunc()->IsReturnStruct()) { newblk->AppendStatementsFromBlock(LowerReturnStruct(static_cast(stmt))); } else diff --git a/mapleall/maple_be/src/be/riscv64/riscv64_rt_support.cpp b/mapleall/maple_be/src/be/riscv64/riscv64_rt_support.cpp new file mode 100644 index 0000000..b62a0bd --- /dev/null +++ b/mapleall/maple_be/src/be/riscv64/riscv64_rt_support.cpp @@ -0,0 +1,22 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#include "aarch64_rt_support.h" + +namespace maplebe { + +// Currently nothing is here. + +} // namespace maplebe diff --git a/mapleall/maple_be/src/cg/aarch64/aarch64_cg.cpp b/mapleall/maple_be/src/cg/aarch64/aarch64_cg.cpp index d80607d..947e8d4 100644 --- a/mapleall/maple_be/src/cg/aarch64/aarch64_cg.cpp +++ b/mapleall/maple_be/src/cg/aarch64/aarch64_cg.cpp @@ -29,9 +29,11 @@ using namespace std; namespace maplebe { #include "aarch64_opnd.def" +#define DEFINE_MOP(op,a2,a3,a4,a5,a6,a7,a8,a9,aa,ab,ac) {op,a2,a3,a4,a5,a6,a7,a8,a9,aa,ab,ac}, const AArch64MD AArch64CG::kMd[kMopLast] = { #include "aarch64_md.def" }; +#undef DEFINE_MOP bool AArch64CG::IsExclusiveFunc(MIRFunction *mirFunc) { const std::string &funcname = mirFunc->GetName(); diff --git a/mapleall/maple_be/src/cg/aarch64/aarch64_cg_func.cpp b/mapleall/maple_be/src/cg/aarch64/aarch64_cg_func.cpp index 79cbf1b..13b9350 100644 --- a/mapleall/maple_be/src/cg/aarch64/aarch64_cg_func.cpp +++ b/mapleall/maple_be/src/cg/aarch64/aarch64_cg_func.cpp @@ -3597,7 +3597,7 @@ AArch64RegOperand *AArch64CGFunc::CreateCallStructParamCopyToStack(uint32 numMem ldmopnd = GetOrCreateMemOpnd(AArch64MemOperand::kAddrModeBOi, 64, vreg, nullptr, GetOrCreateOfstOpnd(j * SIZEOFPTR + fromOffset, 32), static_cast(nullptr)); } else { - ldmopnd = GetOrCreateMemOpnd(sym, (j * SIZEOFPTR), dataSizeBits); + ldmopnd = GetOrCreateMemOpnd(sym, (j * SIZEOFPTR) + fromOffset, dataSizeBits); } } else { ldmopnd = GetOrCreateMemOpnd(AArch64MemOperand::kAddrModeBOi, 64, addropnd, nullptr, @@ -5073,6 +5073,17 @@ void AArch64CGFunc::InsertJumpPad(Insn *insn) { fallthruBB->preds.push_back(brBB); } +void AArch64CGFunc::DBGFixCallFrameLocationOffsets() { + for (DBGExprLoc *el : dbg_callframe_locations) { + if (el->simploc_->dwop_ == DW_OP_fbreg) { + SymbolAlloc *symloc = static_cast(el->symloc_); + int64_t offset = GetBaseOffset(symloc) - dbg_callframe_offset; + + el->SetFboffset(offset); + } + } +} + void AArch64CGFunc::OffsetAdjustmentForFPLR() { int64 argsToStkpassSize = memlayout->SizeOfArgsToStackpass(); FOR_ALL_BB(bb, this) { diff --git a/mapleall/maple_be/src/cg/aarch64/aarch64_color_ra.cpp b/mapleall/maple_be/src/cg/aarch64/aarch64_color_ra.cpp index 26949e4..f696c9c 100644 --- a/mapleall/maple_be/src/cg/aarch64/aarch64_color_ra.cpp +++ b/mapleall/maple_be/src/cg/aarch64/aarch64_color_ra.cpp @@ -111,57 +111,6 @@ void GraphColorRegAllocator::PrintLiveRangeConflicts(const LiveRange *lr) const LogInfo::MapleLogger() << "\n"; } -void GraphColorRegAllocator::CheckLiveRangeConflicts(const LiveRange *lr) const { -#ifdef USE_VEC - if (lr->sconflict.size() != lr->numBconflicts) { - LogInfo::MapleLogger() << "Error: PrintLiveRange inconsistent conflict num\n"; - CG_ASSERT(0, "Error: PrintLiveRange inconsistent conflict num"); - } - for (uint32 i = 0; i < regBuckets; i++) { - uint64 chunk = lr->bconflict[i]; - for (uint64 bit = 0; bit < (sizeof(uint64) * CHAR_BIT); bit++) { - if (chunk & (1LL << bit)) { - regno_t newno = i * sizeof(uint64) * CHAR_BIT + bit; - if (FIND_NOT_IN(lr->sconflict, newno)) { - LogInfo::MapleLogger() << "Error: PrintLiveRange inconsistent conflict member\n"; - CG_ASSERT(0, "Error: PrintLiveRange inconsistent conflict member"); - } - } - } - } -#endif // USE_VEC -} - -void GraphColorRegAllocator::PrintLiveBbSet(const LiveRange *lr, const string str) const { -#ifdef USE_VEC - if (lr->smember.size() != lr->numBmembers) { - LogInfo::MapleLogger() << "Error: PrintLiveBbSet inconsistent size\n"; - CG_ASSERT(0, "Error: PrintLiveBbSet inconsistent size"); - } - LogInfo::MapleLogger() << str << "(" << lr->smember.size() << "): "; - for (uint32 i = 0; i < cgfunc_->NumBBs(); i++) { - if (IS_BIT_ARR_ELEM_SET(lr->bmember, i)) { - if (FIND_NOT_IN(lr->smember, bbVec[i])) { - LogInfo::MapleLogger() << "Error: PrintLiveBbSet inconsistent member\n"; - CG_ASSERT(0, "Error: PrintLiveBbSet inconsistent member"); - } - LogInfo::MapleLogger() << i << " "; - } - } - LogInfo::MapleLogger() << "\n"; - // To match the ordering of bit by using bbid order. - set result; - for (auto bb : lr->smember) { - result.insert(bb); - } - LogInfo::MapleLogger() << str << "(" << lr->smember.size() << "): "; - for (auto bb : result) { - LogInfo::MapleLogger() << bb->id << " "; - } - LogInfo::MapleLogger() << "\n"; -#endif // USE_VEC -} - void GraphColorRegAllocator::PrintLiveBbBit(const LiveRange *lr) const { LogInfo::MapleLogger() << "live_bb(" << lr->numBmembers << "): "; for (uint32 i = 0; i < cgfunc_->NumBBs(); i++) { @@ -204,18 +153,7 @@ void GraphColorRegAllocator::PrintLiveRange(const LiveRange *lr, const string st LogInfo::MapleLogger() << " split"; } LogInfo::MapleLogger() << "\n"; -#ifdef USE_VEC - PrintLiveBbSet(lr, "\tlive_bb"); -#endif // USE_VEC PrintLiveBbBit(lr); -#ifdef USE_VEC - CheckLiveRangeConflicts(lr); - LogInfo::MapleLogger() << "\tinterfere(" << lr->sconflict.size() << "): "; - for (auto newno : lr->sconflict) { - LogInfo::MapleLogger() << newno << ","; - } - LogInfo::MapleLogger() << "\n"; -#endif // USE_VEC PrintLiveRangeConflicts(lr); PrintLiveUnitMap(lr); if (lr->splitLr) { @@ -224,6 +162,7 @@ void GraphColorRegAllocator::PrintLiveRange(const LiveRange *lr, const string st } void GraphColorRegAllocator::PrintLiveRanges() const { + cout << "PrintLiveRanges: size = " << lrVec.size() << endl; for (uint32_t i = 0; i < lrVec.size(); i++) { if (lrVec[i] == nullptr || lrVec[i]->regno == 0) { continue; @@ -280,32 +219,23 @@ void GraphColorRegAllocator::CalculatePriority(LiveRange *lr) { #endif // RANDOM_PRIORITY float pri = 0.0; uint32 bbNum = 0; -#ifdef USE_VEC - for (auto bb : lr->smember) { - auto lu = lr->luMap.find(bb->id); -#else // USE_VEC FOREACH_BB_ARR_ELEM(lr->bmember, bbid) - auto lu = lr->luMap.find(bbid); - BB *bb = bbVec[bbid]; -#endif // USE_VEC + auto lu = lr->luMap.find(bbid); + BB *bb = bbVec[bbid]; bbNum++; uint32 useCnt = lu->second->defNum + lu->second->useNum; uint32 mult; #ifdef USE_BB_FREQUENCY mult = bb->frequency; #else // USE_BB_FREQUENCY - if (bb->loop) { - mult = (uint32)pow(kLoopWeight, bb->loop->loopLevel); - } else { - mult = 1; - } + if (bb->loop) { + mult = (uint32)pow(kLoopWeight, bb->loop->loopLevel); + } else { + mult = 1; + } #endif // USE_BB_FREQUENCY pri += useCnt * mult; -#ifdef USE_VEC - } -#else // USE_VEC END_FOREACH_BB_ARR_ELEM -#endif // USE_VEC if (bbNum) { lr->priority = log(pri) / bbNum; } else { @@ -798,7 +728,7 @@ bool GraphColorRegAllocator::CreateLiveRange(regno_t regno, BB *bb, bool isDef, vregLive.erase(regno); } #ifdef OPTIMIZE_FOR_PROLOG - if (updateCount) { + if (doOptProlog && updateCount) { if (lr->numDefs == 0) { lr->frequency += bb->frequency; } @@ -808,7 +738,7 @@ bool GraphColorRegAllocator::CreateLiveRange(regno_t regno, BB *bb, bool isDef, } else { vregLive.insert(regno); #ifdef OPTIMIZE_FOR_PROLOG - if (updateCount) { + if (doOptProlog && updateCount) { if (lr->numUses == 0) { lr->frequency += bb->frequency; } @@ -821,9 +751,6 @@ bool GraphColorRegAllocator::CreateLiveRange(regno_t regno, BB *bb, bool isDef, } // only handle it in live_in and def point? -#ifdef USE_VEC - lr->smember.insert(bb); -#endif // USE_VEC SET_MEMBER_BIT_ARR_ELEM(lr, bb->id); lrVec[regno] = lr; @@ -1067,16 +994,6 @@ void GraphColorRegAllocator::ComputeLiveRangesBmemberSize() { if (lr == nullptr || lr->regno == 0) { continue; } -#if defined(USE_VEC) && defined(CONFLICT_CHECK) - if (lr->numBmembers != lr->smember.size()) { - LogInfo::MapleLogger() << "Err: bit size member " << lr->regno << endl; - PrintLiveRange(lr, "LR-SIZE-DIFF"); - } - if (lr->numBconflicts != lr->sconflict.size()) { - LogInfo::MapleLogger() << "Err: bit size conflict " << lr->regno << endl; - PrintLiveRange(lr, "LR-SIZE-DIFF"); - } -#endif // USE_VEC && CONFLICT_CHECK } } @@ -1183,7 +1100,9 @@ void GraphColorRegAllocator::ComputeLiveRanges() { LogInfo::MapleLogger() << "After ComputeLiveRanges\n"; PrintLiveRanges(); #ifdef USE_LRA - PrintLocalRaInfo("After ComputeLiveRanges"); + if (doLRA) { + PrintLocalRaInfo("After ComputeLiveRanges"); + } #endif // USE_LRA } return; @@ -1227,11 +1146,7 @@ bool GraphColorRegAllocator::IsLocalReg(regno_t regno) { if (lr->splitLr) { return false; } else { -#ifdef USE_VEC - return (lr->smember.size() == 1) && (!lr->isNonLocal); -#else // USE_VEC return (lr->numBmembers == 1) && (!lr->isNonLocal); -#endif // USE_VEC } } @@ -1239,45 +1154,8 @@ bool GraphColorRegAllocator::IsLocalReg(LiveRange *lr) { if (lr->splitLr) { return false; } else { -#ifdef USE_VEC - return (lr->smember.size() == 1) && (!lr->isNonLocal); -#else // USE_VEC return (lr->numBmembers == 1) && (!lr->isNonLocal); -#endif // USE_VEC - } -} - -void GraphColorRegAllocator::CopyInterference() { -#if !defined(COPY_VEC) && defined(USE_VEC) - set result; - result.clear(); - for (auto bb : lr1->smember) { - if (FIND_IN(lr2->smember, bb)) { - result.insert(bb); - } - if (result.size() > 1) { - break; - } - } - - if (result.size() == 0) { - // no interference - } else if (result.size() == 1) { - auto it = result.begin(); - auto lu1 = lr1->luMap.find((*it)->id); - auto lu2 = lr2->luMap.find((*it)->id); - if (lu1 != lr1->luMap.end() && lu2 != lr2->luMap.end() && - !((lu1->second->bgn < lu2->second->bgn && lu1->second->end < lu2->second->bgn) || - (lu2->second->bgn < lu1->second->end && lu2->second->end < lu1->second->bgn))) { - lr1->sconflict.insert(lr2->regno); - lr2->sconflict.insert(lr1->regno); - } - } else { - // interfere - lr1->sconflict.insert(lr2->regno); - lr2->sconflict.insert(lr1->regno); } -#endif // COPY_VEC && USE_VEC } void GraphColorRegAllocator::CheckInterference(LiveRange *lr1, LiveRange *lr2) { @@ -1324,9 +1202,6 @@ void GraphColorRegAllocator::CheckInterference(LiveRange *lr1, LiveRange *lr2) { SET_CONFLICT_BIT_ARR_ELEM(lr2, lr1->regno); } -#if !defined(COPY_VEC) && defined(USE_VEC) - void CopyInterference(); -#endif // COPY_VEC && USE_VEC return; } @@ -1337,11 +1212,7 @@ void GraphColorRegAllocator::BuildInterferenceGraphSeparateIntFp(std::vectorsmember.size() == 1) -#else // USE_VEC - if (lrVec[i]->numBmembers == 1) -#endif // USE_VEC + if (doLRA && lrVec[i]->numBmembers == 1) { continue; } @@ -1357,63 +1228,6 @@ void GraphColorRegAllocator::BuildInterferenceGraphSeparateIntFp(std::vector::iterator it; - for (it = intLrVec.begin(); it != intLrVec.end(); it++) { - LiveRange *lr = *it; - for (uint32 i = 0; i < regBuckets; i++) { - uint64 chunk = lr->bconflict[i]; - - uint64 size = sizeof(uint64) * CHAR_BIT; - for (uint64 bit = 0; bit < size; bit++) { - if (chunk & (1LL << bit)) { - regno_t regno = i * sizeof(uint64) * CHAR_BIT + bit; - lr->sconflict.insert(regno); - } - } - } - } - for (it = fpLrVec.begin(); it != fpLrVec.end(); it++) { - LiveRange *lr = *it; - for (uint32 i = 0; i < regBuckets; i++) { - uint64 chunk = lr->bconflict[i]; - - uint64 size = sizeof(uint64) * CHAR_BIT; - for (uint64 bit = 0; bit < size; bit++) { - if (chunk & (1LL << bit)) { - regno_t regno = i * sizeof(uint64) * CHAR_BIT + bit; - lr->sconflict.insert(regno); - } - } - } - } -#endif // COPY_VEC -} - -void GraphColorRegAllocator::BuildInterferenceGraphErrorCheck() { -#if defined(USE_VEC) && defined(CONFLICT_CHECK) - for (uint32_t i = 0; i < lrVec.size(); i++) { - if (lrVec[i] == nullptr) { - continue; - } - for (auto confReg : lrVec[i]->sconflict) { - if (IS_BIT_ARR_ELEM_SET(lrVec[i]->bconflict, confReg) == false) { - LogInfo::MapleLogger() << "Err: set conflict " << confReg << " in LR reg " << lrVec[i]->regno << "\n"; - PrintLiveRange(lrVec[i], "LR-SCONFLICT-DIFFER"); - } - } - FOREACH_REG_ARR_ELEM(lrVec[i]->bconflict, confReg) - if (FIND_NOT_IN(lrVec[i]->sconflict, confReg)) { - LogInfo::MapleLogger() << "Err: bit conflict " << confReg << " in LR reg " << lrVec[i]->regno << "\n"; - PrintLiveRange(lrVec[i], "LR-BCONFLICT-DIFFER"); - } - END_FOREACH_REG_ARR_ELEM - } -#endif // USE_VEC && CONFLICT_CHECK -} - // Based on intersection of LRs. When two LRs interfere, add to each other's // interference list. void GraphColorRegAllocator::BuildInterferenceGraph() { @@ -1444,14 +1258,6 @@ void GraphColorRegAllocator::BuildInterferenceGraph() { } } -#ifdef COPY_VEC - BuildInterferenceGraphCopyVec(); -#else // If copying, there is no need to check -#if defined(USE_VEC) && defined(CONFLICT_CHECK) - BuildInterferenceGraphErrorCheck(); -#endif // USE_VEC && CONFLICT_CHECK -#endif // COPY_VEC - if (GCRA_DUMP) { LogInfo::MapleLogger() << "After BuildInterferenceGraph\n"; PrintLiveRanges(); @@ -1488,12 +1294,13 @@ void GraphColorRegAllocator::Separate() { continue; } #ifdef USE_LRA - if (IsLocalReg(lr)) { + if (doLRA && IsLocalReg(lr)) { continue; } #endif // USE_LRA #ifdef OPTIMIZE_FOR_PROLOG - if ((lr->numDefs <= 1 && lr->numUses <= 1 && lr->numCall > 0) && + if (doOptProlog && + (lr->numDefs <= 1 && lr->numUses <= 1 && lr->numCall > 0) && (lr->frequency <= (cgfunc_->firstbb->frequency << 1))) { if (lr->regtype == kRegTyInt) { intDelayed.push_back(lr); @@ -1503,11 +1310,7 @@ void GraphColorRegAllocator::Separate() { continue; } #endif // OPTIMIZE_FOR_PROLOG -#ifdef USE_VEC - if (HaveAvailableColor(lr, lr->sconflict.size() + lr->pregveto.size() + lr->forbidden.size())) -#else // USE_VEC if (HaveAvailableColor(lr, lr->numBconflicts + lr->numPregveto + lr->numForbidden)) -#endif // USE_VEC { unconstrained.push_back(lr); } else { @@ -1545,36 +1348,20 @@ MapleVector::iterator GraphColorRegAllocator::GetHighPriorityLr(Map } void GraphColorRegAllocator::UpdateForbiddenForNeighbors(LiveRange *lr) { -#ifdef USE_VEC - for (auto regno : lr->sconflict) { -#else // USE_VEC FOREACH_REG_ARR_ELEM(lr->bconflict, regno) -#endif // USE_VEC LiveRange *newLr = lrVec[regno]; if (newLr->pregveto[lr->assigned] == false) { newLr->insertForbidden(lr->assigned); } -#ifdef USE_VEC - } -#else // USE_VEC END_FOREACH_REG_ARR_ELEM -#endif // USE_VEC return; } void GraphColorRegAllocator::UpdatePregvetoForNeighbors(LiveRange *lr) { -#ifdef USE_VEC - for (auto regno : lr->sconflict) { -#else // USE_VEC FOREACH_REG_ARR_ELEM(lr->bconflict, regno) -#endif // USE_VEC LiveRange *newLr = lrVec[regno]; newLr->insertPregveto(lr->assigned); -#ifdef USE_VEC - } -#else // USE_VEC END_FOREACH_REG_ARR_ELEM -#endif // USE_VEC return; } @@ -1664,7 +1451,7 @@ bool GraphColorRegAllocator::AssignColorToLr(LiveRange *lr, bool isDelayed) { return false; } #ifdef OPTIMIZE_FOR_PROLOG - if (isDelayed) { + if (doOptProlog && isDelayed) { if (lr->regtype == kRegTyInt) { if (!ShouldUseCallee(lr, intCalleeUsed, intDelayed)) { return false; @@ -1688,18 +1475,9 @@ bool GraphColorRegAllocator::AssignColorToLr(LiveRange *lr, bool isDelayed) { UpdateForbiddenForNeighbors(lr); -#ifdef USE_VEC - for (auto bb : lr->smember) { - uint32 bbid = bb->id; -#else // USE_VEC FOREACH_BB_ARR_ELEM(lr->bmember, bbid) -#endif // USE_VEC SetBbInfoGlobalAssigned(bbid, lr->assigned); -#ifdef USE_VEC - } -#else // USE_VEC END_FOREACH_BB_ARR_ELEM -#endif // USE_VEC if (GCRA_DUMP) { LogInfo::MapleLogger() << "assigned " << lr->assigned << " to R" << lr->regno << endl; } @@ -1764,43 +1542,18 @@ void GraphColorRegAllocator::PruneLrForSplit(LiveRange *lr, BB *bb, bool remove, } } -void GraphColorRegAllocator::SplitCopyVecMember(LiveRange *lr) { -#ifdef USE_VEC - lr->smember.clear(); // Use bmember to update smember - for (uint32 i = 0; i < bbBuckets; i++) { - uint64 chunk = lr->bmember[i]; - uint64 size = sizeof(uint64) * CHAR_BIT; - for (uint64 bit = 0; bit < size; bit++) { - if (chunk & (1LL << bit)) { - BB *bb = bbVec[i * sizeof(uint64) * CHAR_BIT + bit]; - lr->smember.insert(bb); - } - } - } -#endif // USE_VEC -} - void GraphColorRegAllocator::FindBbSharedInSplit(LiveRange *lr, set &candidateInLoop, set &defInLoop) { // A loop might be split into two. Need to see over the entire LR if there is a def in the loop. -#ifdef USE_VEC - for (auto bbit = lr->smember.begin(); bbit != lr->smember.end(); bbit++) { - BB *bb = *bbit; -#else // USE_VEC FOREACH_BB_ARR_ELEM(lr->bmember, bbid) BB *bb = bbVec[bbid]; -#endif // USE_VEC if (bb->loop && FIND_IN(candidateInLoop, bb->loop)) { auto lu = lr->luMap.find(bb->id); if (lu != lr->luMap.end() && lu->second->defNum > 0) { defInLoop.insert(bb->loop); } } -#ifdef USE_VEC - } -#else // USE_VEC END_FOREACH_BB_ARR_ELEM -#endif // USE_VEC } // Backward traversal of the top part of the split LR. @@ -1816,15 +1569,11 @@ void GraphColorRegAllocator::ComputeBbForNewSplit(LiveRange *newLr, LiveRange *o set candidateInLoop; // If a bb has a def and is in a loop, store that info. set defInLoop; -#ifdef USE_VEC - for (auto bbit = newLr->smember.rbegin(); bbit != newLr->smember.rend(); bbit++) -#else // USE_VEC set smember; FOREACH_BB_ARR_ELEM(newLr->bmember, bbid) smember.insert(bbVec[bbid]); END_FOREACH_BB_ARR_ELEM for (auto bbit = smember.rbegin(); bbit != smember.rend(); bbit++) -#endif // USE_VEC { BB *bb = *bbit; if (bb->internal_flag1) { @@ -1844,9 +1593,6 @@ void GraphColorRegAllocator::ComputeBbForNewSplit(LiveRange *newLr, LiveRange *o } } END_FOREACH_BB_ARR_ELEM -#ifdef USE_VEC - SplitCopyVecMember(newLr); -#endif // USE_VEC } bool GraphColorRegAllocator::UseIsUncovered(BB *bb, BB *startBb) { @@ -1961,17 +1707,12 @@ void GraphColorRegAllocator::ComputeBbForOldSplit(LiveRange *newLr, LiveRange *o SplitBbInfo bbInfo; bool remove = true; -#ifdef USE_VEC - ClearLrBbFlags(origLr->smember); - for (auto bb : origLr->smember) -#else // USE_VEC set smember; FOREACH_BB_ARR_ELEM(origLr->bmember, bbid) smember.insert(bbVec[bbid]); END_FOREACH_BB_ARR_ELEM ClearLrBbFlags(smember); for (auto bb : smember) -#endif // USE_VEC { if (bb->internal_flag1) { continue; @@ -1995,9 +1736,6 @@ void GraphColorRegAllocator::ComputeBbForOldSplit(LiveRange *newLr, LiveRange *o } } END_FOREACH_BB_ARR_ELEM -#ifdef USE_VEC - SplitCopyVecMember(origLr); -#endif // USE_VEC } // There is at least one available color for this BB from the neighbors @@ -2011,12 +1749,8 @@ bool GraphColorRegAllocator::LrCanBeColored(LiveRange *lr, BB *bbAdded, setregtype; set newConflict; -#ifdef USE_VEC - for (auto regno : lr->sconflict) { -#else // USE_VEC FOREACH_REG_ARR_ELEM(lr->bconflict, regno) -#endif // USE_VEC - // check the real conflict in current bb + // check the real conflict in current bb LiveRange *conflictLr = lrVec[regno]; // If the bb to be added to the new LR has an actual // conflict with another LR, and if that LR has already @@ -2035,11 +1769,7 @@ bool GraphColorRegAllocator::LrCanBeColored(LiveRange *lr, BB *bbAdded, setnumPregveto + conflictRegs.size(); @@ -2070,9 +1800,6 @@ void GraphColorRegAllocator::MoveLrBbInfo(LiveRange *oldLr, LiveRange *newLr, BB // initialize bb removal marker bb->internal_flag2 = false; // Insert BB into new LR -#ifdef USE_VEC - newLr->smember.insert(bb); -#endif // USE_VEC SET_MEMBER_BIT_ARR_ELEM(newLr, bb->id); // Move LU from old LR to new LR @@ -2083,12 +1810,6 @@ void GraphColorRegAllocator::MoveLrBbInfo(LiveRange *oldLr, LiveRange *newLr, BB } // Remove BB from old LR -#ifdef USE_VEC - auto lrIt = FIND(oldLr->smember, bb); - if (lrIt != oldLr->smember.end()) { - oldLr->smember.erase(lrIt); - } -#endif // USE_VEC UNSET_MEMBER_BIT_ARR_ELEM(oldLr, bb->id); } @@ -2106,41 +1827,25 @@ bool GraphColorRegAllocator::ContainsLoop(CgfuncLoops *loop, set } void GraphColorRegAllocator::GetAllLrMemberLoops(LiveRange *lr, set &loops) { -#ifdef USE_VEC - for (auto bb : lr->smember) { -#else // USE_VEC FOREACH_BB_ARR_ELEM(lr->bmember, bbid) BB *bb = bbVec[bbid]; -#endif // USE_VEC CgfuncLoops *loop = bb->loop; if (loop) { loops.insert(loop); } -#ifdef USE_VEC - } -#else // USE_VEC END_FOREACH_BB_ARR_ELEM -#endif // USE_VEC } bool GraphColorRegAllocator::SplitLrShouldSplit(LiveRange *lr) { -#ifdef USE_VEC - if (lr->splitLr || lr->smember.size() == 1) -#else // USE_VEC if (lr->splitLr || lr->numBmembers == 1) -#endif // USE_VEC { return false; } // Need to split within the same hierarchy int32 loopId = -1; -#ifdef USE_VEC - for (auto bb : lr->smember) { -#else // USE_VEC FOREACH_BB_ARR_ELEM(lr->bmember, bbid) BB *bb = bbVec[bbid]; -#endif // USE_VEC if (loopId == -1) { if (bb->loop) { loopId = bb->loop->header->id; @@ -2152,20 +1857,12 @@ bool GraphColorRegAllocator::SplitLrShouldSplit(LiveRange *lr) { return false; } } -#ifdef USE_VEC - } -#else // USE_VEC END_FOREACH_BB_ARR_ELEM -#endif // USE_VEC return true; } bool GraphColorRegAllocator::SplitLrIsProfitable(LiveRange *newLr) { -#ifdef USE_VEC - if (newLr->smember.size() == 0) -#else // USE_VEC if (newLr->numBmembers == 0) -#endif // USE_VEC { // split fail return false; @@ -2184,14 +1881,6 @@ bool GraphColorRegAllocator::SplitLrIsProfitable(LiveRange *newLr) { void GraphColorRegAllocator::ResetSplitLr(LiveRange *origLr, LiveRange *newLr) { FOREACH_BB_ARR_ELEM(newLr->bmember, bbid) { -#ifdef USE_VEC - BB *bb = bbVec[bbid]; - auto bbIt = FIND(newLr->smember, bb); - if (bbIt != newLr->smember.end()) { - newLr->smember.erase(bbIt); - } - origLr->smember.insert(bb); -#endif // USE_VEC UNSET_MEMBER_BIT_ARR_ELEM(newLr, bbid); SET_MEMBER_BIT_ARR_ELEM(origLr, bbid); @@ -2217,15 +1906,11 @@ bool GraphColorRegAllocator::SplitLrFindCandidateLr(LiveRange *lr, LiveRange *ne if (GCRA_DUMP) { LogInfo::MapleLogger() << "start split lr for vreg " << lr->regno << endl; } -#ifdef USE_VEC - for (auto bb : lr->smember) -#else // USE_VEC set smember; FOREACH_BB_ARR_ELEM(lr->bmember, bbid) smember.insert(bbVec[bbid]); END_FOREACH_BB_ARR_ELEM for (auto bb : smember) -#endif // USE_VEC { if (LrCanBeColored(lr, bb, conflictRegs)) { MoveLrBbInfo(lr, newLr, bb); @@ -2258,23 +1943,6 @@ void GraphColorRegAllocator::SplitLrHandleLoops(LiveRange *lr, LiveRange *newLr, // no longer in the LR. Remove those bb. ComputeBbForNewSplit(newLr, lr); // With new LR, recompute conflict. -#ifdef USE_VEC - for (auto bb : newLr->smember) { - for (auto regno : lr->sconflict) { - LiveRange *conf_lr = lrVec[regno]; - if (IS_BIT_ARR_ELEM_SET(conf_lr->bmember, bb->id)) { - // New LR getting the interference does not mean the - // old LR can remove the interference. - // Old LR's interference will be handled at the end of split. - newLr->sconflict.insert(regno); - SET_CONFLICT_BIT_ARR_ELEM(newLr, regno); - } else if (conf_lr->splitLr && FIND_IN(conf_lr->splitLr->smember, bb)) { - newLr->sconflict.insert(regno); - SET_CONFLICT_BIT_ARR_ELEM(newLr, regno); - } - } - } -#else // USE_VEC FOREACH_BB_ARR_ELEM(newLr->bmember, bbid) FOREACH_REG_ARR_ELEM(lr->bconflict, regno) LiveRange *conf_lr = lrVec[regno]; @@ -2288,7 +1956,6 @@ void GraphColorRegAllocator::SplitLrHandleLoops(LiveRange *lr, LiveRange *newLr, } END_FOREACH_REG_ARR_ELEM END_FOREACH_BB_ARR_ELEM -#endif // USE_VEC // update bb/loop same as for new LR. ComputeBbForOldSplit(newLr, lr); // Update the conflict interference for the original LR later. @@ -2296,11 +1963,7 @@ void GraphColorRegAllocator::SplitLrHandleLoops(LiveRange *lr, LiveRange *newLr, for (auto loop : newLoops) { if (ContainsLoop(loop, origLoops)) { for (auto bb : loop->loop_members) { -#ifdef USE_VEC - if (FIND_IN(newLr->smember, bb)) -#else // USE_VEC if (IS_BIT_ARR_ELEM_SET(newLr->bmember, bb->id)) -#endif // USE_VEC { LiveUnit *lu = newLr->luMap[bb->id]; if (lu->useNum != 0) { @@ -2315,13 +1978,8 @@ void GraphColorRegAllocator::SplitLrHandleLoops(LiveRange *lr, LiveRange *newLr, void GraphColorRegAllocator::SplitLrFixNewLrCallsAndRlod(LiveRange *newLr, set &origLoops) { // If a 2nd split loop is before the bb in 1st split bb. newLr->numCall = 0; -#ifdef USE_VEC - for (auto bb : newLr->smember) { - uint32 bbid = bb->id; -#else // USE_VEC FOREACH_BB_ARR_ELEM(newLr->bmember, bbid) BB *bb = bbVec[bbid]; -#endif // USE_VEC for (auto loop : origLoops) { if (loop->header->level < bb->level) { LiveUnit *lu = newLr->luMap[bbid]; @@ -2334,31 +1992,18 @@ void GraphColorRegAllocator::SplitLrFixNewLrCallsAndRlod(LiveRange *newLr, setnumBmembers > 1 && lu->hasCall) { newLr->numCall++; } -#ifdef USE_VEC - } -#else // USE_VEC END_FOREACH_BB_ARR_ELEM -#endif // USE_VEC } void GraphColorRegAllocator::SplitLrFixOrigLrCalls(LiveRange *lr) { lr->numCall = 0; if (lr->numBmembers > 1) { -#ifdef USE_VEC - for (auto bb : lr->smember) { - uint32 bbid = bb->id; -#else // USE_VEC FOREACH_BB_ARR_ELEM(lr->bmember, bbid) -#endif // USE_VEC LiveUnit *lu = lr->luMap[bbid]; if (lu->hasCall) { lr->numCall++; } -#ifdef USE_VEC - } -#else // USE_VEC END_FOREACH_BB_ARR_ELEM -#endif // USE_VEC } } @@ -2367,11 +2012,7 @@ void GraphColorRegAllocator::SplitLrUpdateInterference(LiveRange *lr) { // Update the interference info. // Also recompute the forbidden info lr->forbidden.clear(); -#ifdef USE_VEC - for (auto regno : lr->sconflict) { -#else // USE_VEC FOREACH_REG_ARR_ELEM(lr->bconflict, regno) -#endif // USE_VEC LiveRange *conf_lr = lrVec[regno]; if (SET_BB_OVERLAP(lr->bmember, conf_lr->bmember)) { // interfere @@ -2380,16 +2021,9 @@ void GraphColorRegAllocator::SplitLrUpdateInterference(LiveRange *lr) { } } else { // no interference -#ifdef USE_VEC - lr->sconflict.erase(regno); -#endif // USE_VEC UNSET_CONFLICT_BIT_ARR_ELEM(lr, regno); } -#ifdef USE_VEC - } -#else // USE_VEC END_FOREACH_REG_ARR_ELEM -#endif // USE_VEC } void GraphColorRegAllocator::SplitLrUpdateRegInfo(LiveRange *origLr, LiveRange *newLr, set &conflictRegs) { @@ -2406,17 +2040,6 @@ void GraphColorRegAllocator::SplitLrUpdateRegInfo(LiveRange *origLr, LiveRange * } void GraphColorRegAllocator::SplitLrErrorCheckAndDebug(LiveRange *origLr, LiveRange *newLr) { -#if defined(USE_VEC) && defined(CONFLICT_CHECK) - if (origLr->numBconflicts != origLr->sconflict.size()) { - LogInfo::MapleLogger() << "Err: lr bit size conflict " << origLr->regno << endl; - PrintLiveRange(origLr, "LR-SIZE-DIFF"); - } - if (newLr->numBconflicts != newLr->sconflict.size()) { - LogInfo::MapleLogger() << "Err: newLr bit size conflict " << origLr->regno << endl; - PrintLiveRange(origLr, "LR-SIZE-DIFF"); - } -#endif // USE_VEC && CONFLICT_CHECK - if (origLr->numBmembers == 0) { CG_ASSERT(origLr->numBconflicts == 0, "Error: member and conflict not match"); } @@ -2471,18 +2094,9 @@ LiveRange *GraphColorRegAllocator::SplitLr(LiveRange *lr) { newLr->assigned = FindColorForLr(newLr); // For the new LR, update assignment for local RA -#ifdef USE_VEC - for (auto bb : newLr->smember) { - uint32 bbid = bb->id; -#else // USE_VEC FOREACH_BB_ARR_ELEM(newLr->bmember, bbid) -#endif // USE_VEC SetBbInfoGlobalAssigned(bbid, newLr->assigned); -#ifdef USE_VEC - } -#else // USE_VEC END_FOREACH_BB_ARR_ELEM -#endif // USE_VEC UpdatePregvetoForNeighbors(newLr); @@ -2492,18 +2106,20 @@ LiveRange *GraphColorRegAllocator::SplitLr(LiveRange *lr) { void GraphColorRegAllocator::ColorForOptPrologEpilog() { #ifdef OPTIMIZE_FOR_PROLOG - for (auto lr : intDelayed) { - if (AssignColorToLr(lr, true)) { - continue; - } else { - lr->spilled = true; + if (doOptProlog) { + for (auto lr : intDelayed) { + if (AssignColorToLr(lr, true)) { + continue; + } else { + lr->spilled = true; + } } - } - for (auto lr : fpDelayed) { - if (AssignColorToLr(lr, true)) { - continue; - } else { - lr->spilled = true; + for (auto lr : fpDelayed) { + if (AssignColorToLr(lr, true)) { + continue; + } else { + lr->spilled = true; + } } } #endif @@ -2548,6 +2164,7 @@ void GraphColorRegAllocator::SplitAndColor() { if (AssignColorToLr(lr) == false) { #endif // COLOR_SPLIT lr->spilled = true; + hasSpill = true; #ifdef COLOR_SPLIT } #endif // COLOR_SPLIT @@ -2579,7 +2196,9 @@ void GraphColorRegAllocator::SplitAndColor() { } #ifdef OPTIMIZE_FOR_PROLOG - ColorForOptPrologEpilog(); + if (doOptProlog) { + ColorForOptPrologEpilog(); + } #endif // OPTIMIZE_FOR_PROLOG return; @@ -2753,7 +2372,7 @@ bool GraphColorRegAllocator::LocalRaInitRegSet(LocalRegAllocator *localRa, uint3 if (regno >= kMaxRegNum) { needLocalRa = true; #ifdef DO_PRE_LRA - } else { + } else if (doLRA) { if (!doAllocate) { // ? no need when have forbidden info LocalRaRegSetEraseReg(localRa, regno); @@ -3185,7 +2804,7 @@ Insn *GraphColorRegAllocator::SpillOperand(Insn *insn, Operand *opnd, bool isDef memopnd = GetSpillOrReuseMem(lr, regsize, isOutOfRange, insn, true); spillDefInsn = cg->BuildInstruction(a64cgfunc->PickStInsn(regsize, stype), phyopnd, memopnd); spillDefInsn->SetSpillOp(); - std::string comment = " SPILL vreg:" + std::to_string(regno); + std::string comment = " SPILL vreg: " + std::to_string(regno); spillDefInsn->AddComment(comment); if (isOutOfRange || (insn->next && insn->next->GetMachineOpcode() == MOP_clinit_tail)) { insn->bb->InsertInsnAfter(insn->next, spillDefInsn); @@ -3203,7 +2822,7 @@ Insn *GraphColorRegAllocator::SpillOperand(Insn *insn, Operand *opnd, bool isDef memopnd = GetSpillOrReuseMem(lr, regsize, isOutOfRange, insn, false); spillUseInsn = cg->BuildInstruction(a64cgfunc->PickLdInsn(regsize, stype), phyopnd, memopnd); spillUseInsn->SetSpillOp(); - std::string comment = " RELOAD vreg" + std::to_string(regno); + std::string comment = " RELOAD vreg: " + std::to_string(regno); spillUseInsn->AddComment(comment); insn->bb->InsertInsnBefore(insn, spillUseInsn); if (spillDefInsn) { @@ -3267,11 +2886,7 @@ void GraphColorRegAllocator::CollectCannotUseReg(set &cannotUseReg, Liv cannotUseReg.insert(regno); } } -#ifdef USE_VEC - for (auto regno : lr->sconflict) { -#else // USE_VEC FOREACH_REG_ARR_ELEM(lr->bconflict, regno) -#endif // USE_VEC LiveRange *conflictLr = lrVec[regno]; // conflictLr->assigned might be zero // caller save will be inserted so the assigned reg can be released actually @@ -3281,16 +2896,14 @@ void GraphColorRegAllocator::CollectCannotUseReg(set &cannotUseReg, Liv } cannotUseReg.insert(conflictLr->assigned); } -#ifdef USE_VEC - } -#else // USE_VEC END_FOREACH_REG_ARR_ELEM -#endif // USE_VEC #ifdef USE_LRA - BbAssignInfo *bbInfo = bbRegInfo[insn->bb->id]; - if (bbInfo) { - for (auto it : bbInfo->regMap) { - cannotUseReg.insert(it.second); + if (doLRA) { + BbAssignInfo *bbInfo = bbRegInfo[insn->bb->id]; + if (bbInfo) { + for (auto it : bbInfo->regMap) { + cannotUseReg.insert(it.second); + } } } #endif // USE_LRA @@ -3456,7 +3069,7 @@ RegOperand *GraphColorRegAllocator::GetReplaceOpnd(Insn *insn, Operand *opnd, ui } #ifdef USE_LRA - if (IsLocalReg(vregno)) { + if (doLRA && IsLocalReg(vregno)) { return GetReplaceOpndForLRA(insn, opnd, spillIdx, usedRegMask, isDef); } #endif // USE_LRA @@ -3568,18 +3181,175 @@ uint64 GraphColorRegAllocator::FinalizeRegisterPreprocess(FinalizeRegisterInfo * return usedRegMask; } -// Iterate through all instructions and change the vreg to preg. -void GraphColorRegAllocator::FinalizeRegisters() { +void GraphColorRegAllocator::GenerateSpillFillRegs(Insn *insn) { + static regno_t intregs[3] = { R10, R11, R12 }; // R9 is used for large stack offset temp + static regno_t fpregs[3] = { V10, V11, V12 }; + uint32 intUseCnt = 0; + uint32 fpUseCnt = 0; + for (int32_t i = 0; i < Insn::kMaxOperandNum; i++) { + Operand *opnd = insn->GetOperand(i); + if (!opnd) { + continue; + } + if (opnd->IsList()) { + // call parameters + } else if (opnd->IsMemoryAccessOperand()) { + MemOperand *memopnd = static_cast(opnd); + AArch64RegOperand *base = static_cast(memopnd->GetBaseRegister()); + if (base != nullptr && base->IsPhysicalRegister()) { + regno_t regno = base->GetRegisterNumber(); + if (regno == intregs[0] || regno == intregs[1] || regno == intregs[2]) { + intUseCnt++; + } + } + AArch64RegOperand *offset = static_cast(memopnd->GetIndexRegister()); + if (offset != nullptr && offset->IsPhysicalRegister()) { + regno_t regno = offset->GetRegisterNumber(); + if (regno == intregs[0] || regno == intregs[1] || regno == intregs[2]) { + intUseCnt++; + } + } + } else { + RegOperand *ropnd = static_cast(opnd); + if (ropnd && ropnd->IsVirtualRegister() == false) { + regno_t regno = ropnd->GetRegisterNumber(); + if (regno >= V0) { + if (regno == fpregs[0] || regno == fpregs[1] || regno == fpregs[2]) { + fpUseCnt++; + } + } else { + if (regno == intregs[0] || regno == intregs[1] || regno == intregs[2]) { + intUseCnt++; + } + } + } + } + } + intSpillFillRegs[0] = intregs[0] + intUseCnt; + intSpillFillRegs[1] = intregs[1] + intUseCnt; + intSpillFillRegs[2] = intregs[2] + intUseCnt; + fpSpillFillRegs[0] = fpregs[0] + fpUseCnt; + fpSpillFillRegs[1] = fpregs[1] + fpUseCnt; + fpSpillFillRegs[2] = fpregs[2] + fpUseCnt; +} + +RegOperand *GraphColorRegAllocator::CreateSpillFillCode(RegOperand *opnd, Insn *insn, uint32 spillCnt, bool isdef) { + regno_t vregno = opnd->GetRegisterNumber(); + LiveRange *lr = lrVec[vregno]; + if (lr && lr->spilled) { + AArch64CGFunc *a64cgfunc = static_cast(cgfunc_); + CG *cg = a64cgfunc->cg; + uint32 bits = opnd->GetValidBitsNum(); + if (bits < 32) { + bits = 32; + } + MemOperand *loadmem = a64cgfunc->GetOrCreatSpillMem(vregno); + uint8 isOutOfRange; + loadmem = a64cgfunc->AdjustMemOperandIfOffsetOutOfRange(loadmem, vregno, isdef, insn, R9, isOutOfRange); + PrimType pty = (lr->regtype == kRegTyInt) ? ((bits > 32) ? PTY_i64 : PTY_i32) + : ((bits > 32) ? PTY_f64 : PTY_f32); + regno_t spreg = 0; + RegType rtype = lr->regtype; + if (spillCnt == 0) { + // pregveto will take care of assignment, so pick a caller reg for temp + GenerateSpillFillRegs(insn); + } + CHECK_FATAL(spillCnt < 3, "spill count exceeded"); + spreg = (rtype == kRegTyInt) ? intSpillFillRegs[spillCnt] : fpSpillFillRegs[spillCnt]; + RegOperand *regopnd = a64cgfunc->GetOrCreatePhysicalRegisterOperand(static_cast(spreg), opnd->GetSize(), rtype); + + Insn *memInsn; + if (isdef) { + memInsn = cg->BuildInstruction(a64cgfunc->PickStInsn(bits, pty), regopnd, loadmem); + memInsn->SetSpillOp(); + std::string comment = " SPILLcolor vreg: " + std::to_string(vregno); + memInsn->AddComment(comment); + if (isOutOfRange) { + insn->bb->InsertInsnAfter(insn->next, memInsn); + } else { + insn->bb->InsertInsnAfter(insn, memInsn); + } + } else { + memInsn = cg->BuildInstruction(a64cgfunc->PickLdInsn(bits, pty), regopnd, loadmem); + memInsn->SetSpillOp(); + std::string comment = " RELOADcolor vreg: " + std::to_string(vregno); + memInsn->AddComment(comment); + insn->bb->InsertInsnBefore(insn, memInsn); + } + return regopnd; + } + return nullptr; +} + +void GraphColorRegAllocator::SpillLiveRangeForSpills() { + AArch64CGFunc *a64cgfunc = static_cast(cgfunc_); + CG *cg = a64cgfunc->cg; for (uint32_t bbIdx = 0; bbIdx < sortedBBs.size(); bbIdx++) { BB *bb = sortedBBs[bbIdx]; FOR_BB_INSNS(insn, bb) { - if (insn->IsImmaterialInsn()) { + uint32 spillCnt; + if (insn->IsImmaterialInsn() || !insn->IsMachineInstruction() || insn->id == 0) { continue; } - if (!insn->IsMachineInstruction()) { - continue; + spillCnt = 0; + const AArch64MD *md = &AArch64CG::kMd[static_cast(insn)->mop_]; + for (int32_t i = 0; i < Insn::kMaxOperandNum; i++) { + Operand *opnd = insn->GetOperand(i); + if (!opnd) { + continue; + } + if (opnd->IsList()) { + // call parameters + } else if (opnd->IsMemoryAccessOperand()) { + MemOperand *newmemopnd = nullptr; + MemOperand *memopnd = static_cast(opnd); + RegOperand *base = static_cast(memopnd->GetBaseRegister()); + if (base != nullptr && base->IsVirtualRegister()) { + RegOperand *replace = CreateSpillFillCode(base, insn, spillCnt); + if (replace) { + spillCnt++; + newmemopnd = static_cast(static_cast(opnd)->Clone(cgfunc_->memPool)); + newmemopnd->SetBaseRegister(replace); + insn->SetOperand(i, newmemopnd); + } + } + RegOperand *offset = static_cast(memopnd->GetIndexRegister()); + if (offset != nullptr && offset->IsVirtualRegister()) { + RegOperand *replace = CreateSpillFillCode(offset, insn, spillCnt); + if (replace) { + spillCnt++; + if (newmemopnd == nullptr) { + newmemopnd = static_cast(static_cast(opnd)->Clone(cgfunc_->memPool)); + } + newmemopnd->SetIndexRegister(replace); + insn->SetOperand(i, newmemopnd); + } + } + } else if (opnd->IsRegister()) { + bool isdef = static_cast(md->operand_[i])->IsRegDef(); + RegOperand *replace = CreateSpillFillCode(static_cast(opnd), insn, spillCnt, isdef); + if (replace) { + if (isdef == false) { + spillCnt++; + } + insn->SetOperand(i, replace); + } + } } - if (insn->id == 0) { + } + } +} + +// Iterate through all instructions and change the vreg to preg. +void GraphColorRegAllocator::FinalizeRegisters() { + if (CGOptions::doMultiPassColorRA && hasSpill) { + SpillLiveRangeForSpills(); + return; + } + for (uint32_t bbIdx = 0; bbIdx < sortedBBs.size(); bbIdx++) { + BB *bb = sortedBBs[bbIdx]; + FOR_BB_INSNS(insn, bb) { + if (insn->IsImmaterialInsn() || !insn->IsMachineInstruction() || insn->id == 0) { continue; } @@ -3656,8 +3426,10 @@ bool GraphColorRegAllocator::AllocateRegisters() { CG_ASSERT(cnt <= cgfunc_->GetTotalNumberOfInstructions(), "Incorrect insn count"); #ifdef PROPAGATE_REG - RaX0Opt x0Opt; - x0Opt.PropagateX0(cgfunc_); + if (cgfunc_->IsAfterRegAlloc() == false) { + RaX0Opt x0Opt; + x0Opt.PropagateX0(cgfunc_); + } if (GCRA_DUMP) { LogInfo::MapleLogger() << "******** CG IR After PreColorRA: *********" << endl; cgfunc_->DumpCGIR(); @@ -3666,6 +3438,11 @@ bool GraphColorRegAllocator::AllocateRegisters() { } #endif + if (CGOptions::doMultiPassColorRA) { + doLRA = false; + doOptProlog = false; + } + cgfunc_->SetIsAfterRegAlloc(); // EBO propgation extent the live range and might need to be turned off. InitFreeRegPool(); @@ -3675,7 +3452,9 @@ bool GraphColorRegAllocator::AllocateRegisters() { ComputeLiveRanges(); #ifdef DO_PRE_LRA - LocalRegisterAllocator(false); + if (doLRA) { + LocalRegisterAllocator(false); + } #endif // DO_PRE_LRA BuildInterferenceGraph(); @@ -3685,7 +3464,9 @@ bool GraphColorRegAllocator::AllocateRegisters() { SplitAndColor(); #ifdef USE_LRA - LocalRegisterAllocator(true); + if (doLRA) { + LocalRegisterAllocator(true); + } #endif // USE_LRA FinalizeRegisters(); @@ -3696,7 +3477,11 @@ bool GraphColorRegAllocator::AllocateRegisters() { cgfunc_->DumpCGIR(); } - return true; + if (CGOptions::doMultiPassColorRA && hasSpill) { + return false; + } else { + return true; + } } } // namespace maplebe diff --git a/mapleall/maple_be/src/cg/aarch64/aarch64_emit.cpp b/mapleall/maple_be/src/cg/aarch64/aarch64_emit.cpp index d5f93e8..b5ffd2b 100644 --- a/mapleall/maple_be/src/cg/aarch64/aarch64_emit.cpp +++ b/mapleall/maple_be/src/cg/aarch64/aarch64_emit.cpp @@ -95,6 +95,11 @@ void AArch64Insn::EmitClinit(CG &cg, Emitter &emitter) { OpndProp *prop0 = md->operand_[0]; StImmOperand *stopnd = static_cast(opnd1); CHECK_FATAL(stopnd != nullptr, "stopnd is null in AArch64Insn::EmitClinit"); + // emit nop for breakpoint + if (cg.cgopt_.WithDwarf()) { + emitter.Emit("\t").Emit("nop").Emit("\n"); + } + if (stopnd->GetSymbol()->IsMuidDataUndefTab()) { // emit adrp emitter.Emit("\t").Emit("adrp").Emit("\t"); @@ -159,6 +164,10 @@ void AArch64Insn::EmitAdrpLdr(CG &cg, Emitter &emitter) { OpndProp *prop0 = md->operand_[0]; StImmOperand *stopnd = static_cast(opnd1); CHECK_FATAL(stopnd != nullptr, "stopnd is null in AArch64Insn::EmitAdrpLdr"); + // emit nop for breakpoint + if (cg.cgopt_.WithDwarf()) { + emitter.Emit("\t").Emit("nop").Emit("\n"); + } // adrp xd, _PTR__cinf_Ljava_2Futil_2Fconcurrent_2Fatomic_2FAtomicInteger_3B emitter.Emit("\t").Emit("adrp").Emit("\t"); @@ -517,6 +526,8 @@ void AArch64CGFunc::Emit() { emitter.Emit("\t.hidden\t").Emit(funcSt->GetName()).Emit("\n"); } else if (funcSt->GetFunction()->GetAttr(FUNCATTR_local)) { emitter.Emit("\t.local\t").Emit(funcSt->GetName()).Emit("\n"); + } else if (funcSt->value.mirFunc && funcSt->value.mirFunc->classTyIdx == 0 && funcSt->value.mirFunc->IsStatic()) { + // nothing } else { emitter.Emit("\t.globl\t").Emit(funcSt->GetName()).Emit("\n"); emitter.Emit("\t.hidden\t").Emit(funcSt->GetName()).Emit("\n"); diff --git a/mapleall/maple_be/src/cg/aarch64/aarch64_intrinsics.cpp b/mapleall/maple_be/src/cg/aarch64/aarch64_intrinsics.cpp index 3e81bc7..7149fbd 100644 --- a/mapleall/maple_be/src/cg/aarch64/aarch64_intrinsics.cpp +++ b/mapleall/maple_be/src/cg/aarch64/aarch64_intrinsics.cpp @@ -104,13 +104,10 @@ void AArch64CGFunc::SelectCVaStart(IntrinsiccallNode *intrnnode) { Insn *insn; AArch64MemLayout *memlayout = static_cast(this->memlayout); int32 grAreaSize = memlayout->GetSizeOfGRSavearea(); - bool isSym = sym && (argexpr->op == OP_addrof); - // if first argument of va_start is not a symbol, load its value - if (!isSym) { - Operand *opnd = HandleExpr(intrnnode, argexpr); - opnd0 = LoadIntoRegister(opnd, PTY_a64); - } + // va_list is a passed struct with an address, load its address + Operand *opnd = HandleExpr(intrnnode, argexpr); + opnd0 = LoadIntoRegister(opnd, PTY_a64); // FPLR only pushed in regalloc() after intrin function if (UseFP() || UsedStpSubPairForCallFrameAllocation()) { @@ -144,24 +141,16 @@ void AArch64CGFunc::SelectCVaStart(IntrinsiccallNode *intrnnode) { } else { SelectAdd(vreg, stkOpnd, offsOpnd, PTY_a64); } - if (!isSym) { - AArch64OfstOperand *offopnd = GetOrCreateOfstOpnd(0, 64); - strOpnd = GetOrCreateMemOpnd(AArch64MemOperand::kAddrModeBOi, 64, opnd0, nullptr, - offopnd, static_cast(nullptr)); - } else { - strOpnd = GetOrCreateMemOpnd(sym, 0, 64); - } + AArch64OfstOperand *offopnd = GetOrCreateOfstOpnd(0, 64); + strOpnd = GetOrCreateMemOpnd(AArch64MemOperand::kAddrModeBOi, 64, opnd0, nullptr, + offopnd, static_cast(nullptr)); insn = cg->BuildInstruction(MOP_xstr, vreg, strOpnd); curbb->AppendInsn(insn); // __gr_top ; it's the same as __stack before the 1st va_arg - if (!isSym) { - AArch64OfstOperand *offopnd = GetOrCreateOfstOpnd(8, 64); - strOpnd = GetOrCreateMemOpnd(AArch64MemOperand::kAddrModeBOi, 64, opnd0, nullptr, - offopnd, static_cast(nullptr)); - } else { - strOpnd = GetOrCreateMemOpnd(sym, 8, 64); - } + offopnd = GetOrCreateOfstOpnd(8, 64); + strOpnd = GetOrCreateMemOpnd(AArch64MemOperand::kAddrModeBOi, 64, opnd0, nullptr, + offopnd, static_cast(nullptr)); SelectAdd(vreg, stkOpnd, offsOpnd, PTY_a64); insn = cg->BuildInstruction(MOP_xstr, vreg, strOpnd); curbb->AppendInsn(insn); @@ -170,13 +159,9 @@ void AArch64CGFunc::SelectCVaStart(IntrinsiccallNode *intrnnode) { offsOpnd2 = CreateImmOperand(RoundUp(grAreaSize, SIZEOFPTR*2), 64, false); SelectSub(vreg, offsOpnd, offsOpnd2, PTY_a64); // if 1st opnd is register => sub SelectAdd(vreg, stkOpnd, vreg, PTY_a64); - if (!isSym) { - AArch64OfstOperand *offopnd = GetOrCreateOfstOpnd(16, 64); - strOpnd = GetOrCreateMemOpnd(AArch64MemOperand::kAddrModeBOi, 64, opnd0, nullptr, - offopnd, static_cast(nullptr)); - } else { - strOpnd = GetOrCreateMemOpnd(sym, 16, 64); - } + offopnd = GetOrCreateOfstOpnd(16, 64); + strOpnd = GetOrCreateMemOpnd(AArch64MemOperand::kAddrModeBOi, 64, opnd0, nullptr, + offopnd, static_cast(nullptr)); insn = cg->BuildInstruction(MOP_xstr, vreg, strOpnd); curbb->AppendInsn(insn); @@ -185,13 +170,9 @@ void AArch64CGFunc::SelectCVaStart(IntrinsiccallNode *intrnnode) { offsOpnd = CreateImmOperand(offs, 32, false); tmpreg = CreateRegisterOperandOfType(PTY_i32); SelectCopyImm(tmpreg, offsOpnd, PTY_i32); - if (!isSym) { - AArch64OfstOperand *offopnd = GetOrCreateOfstOpnd(3*SIZEOFPTR, 32); - strOpnd = GetOrCreateMemOpnd(AArch64MemOperand::kAddrModeBOi, 32, opnd0, nullptr, - offopnd, static_cast(nullptr)); - } else { - strOpnd = GetOrCreateMemOpnd(sym, (3 * SIZEOFPTR), 32); - } + offopnd = GetOrCreateOfstOpnd(3*SIZEOFPTR, 32); + strOpnd = GetOrCreateMemOpnd(AArch64MemOperand::kAddrModeBOi, 32, opnd0, nullptr, + offopnd, static_cast(nullptr)); insn = cg->BuildInstruction(MOP_wstr, tmpreg, strOpnd); curbb->AppendInsn(insn); @@ -200,13 +181,9 @@ void AArch64CGFunc::SelectCVaStart(IntrinsiccallNode *intrnnode) { offsOpnd = CreateImmOperand(offs, 32, false); tmpreg = CreateRegisterOperandOfType(PTY_i32); SelectCopyImm(tmpreg, offsOpnd, PTY_i32); - if (!isSym) { - AArch64OfstOperand *offopnd = GetOrCreateOfstOpnd(3*SIZEOFPTR+sizeof(int32), 32); - strOpnd = GetOrCreateMemOpnd(AArch64MemOperand::kAddrModeBOi, 32, opnd0, nullptr, - offopnd, static_cast(nullptr)); - } else { - strOpnd = GetOrCreateMemOpnd(sym, (3*SIZEOFPTR+sizeof(int32)), 32); - } + offopnd = GetOrCreateOfstOpnd(3*SIZEOFPTR+sizeof(int32), 32); + strOpnd = GetOrCreateMemOpnd(AArch64MemOperand::kAddrModeBOi, 32, opnd0, nullptr, + offopnd, static_cast(nullptr)); insn = cg->BuildInstruction(MOP_wstr, tmpreg, strOpnd); curbb->AppendInsn(insn); return; diff --git a/mapleall/maple_be/src/cg/aarch64/aarch64_md.def b/mapleall/maple_be/src/cg/aarch64/aarch64_md.def deleted file mode 100644 index d79f63c..0000000 --- a/mapleall/maple_be/src/cg/aarch64/aarch64_md.def +++ /dev/null @@ -1,1439 +0,0 @@ -/* - * Copyright (c) [2020] Huawei Technologies Co., Ltd. All rights reserved. - * - * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. - * You can use this software according to the terms and conditions of the MulanPSL - 2.0. - * You may obtain a copy of MulanPSL - 2.0 at: - * - * https://opensource.org/licenses/MulanPSL-2.0 - * - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR - * FIT FOR A PARTICULAR PURPOSE. - * See the MulanPSL - 2.0 for more details. - */ - -// MOP_undef, -{MOP_undef, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"","", 0, 0}, - -// # Definitions - -// AARCH64 MOVES -// MOP_xmovrr -{MOP_xmovrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtAlu,"mov","0,1", 1, 1}, -// MOP_wmovrr -{MOP_wmovrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtAlu,"mov","0,1", 1, 1}, -// MOP_xmovri32 -{MOP_xmovri32, {MOPD_Reg32ID,MOPD_Imm32,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtAlu,"mov","0,1", 1, 1}, -// MOP_xmovri64 -{MOP_xmovri64, {MOPD_Reg64ID,MOPD_Imm64,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtAlu,"mov","0,1", 1, 1}, - -// MOP_xvmovsr -{MOP_xvmovsr, {MOPD_Reg32FD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtR2f,"fmov","0,1", 1, 1}, -// MOP_xvmovdr -{MOP_xvmovdr, {MOPD_Reg64FD,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtR2f,"fmov","0,1", 1, 1}, -// MOP_xvmovrs -{MOP_xvmovrs, {MOPD_Reg32ID,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtF2r,"fmov","0,1", 1, 1}, -// MOP_xvmovrd -{MOP_xvmovrd, {MOPD_Reg64ID,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtF2r,"fmov","0,1", 1, 1}, -// MOP_xvmovs -{MOP_xvmovs, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtFpalu,"fmov","0,1", 1, 1}, -// MOP_xvmovd -{MOP_xvmovd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtFpalu,"fmov","0,1", 1, 1}, - -// Vector SIMD mov -// MOP_vmovrr -{MOP_vmovrr, {MOPD_Reg128FD,MOPD_Reg128FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtFpalu,"mov","0,1", 1, 1}, -// Vector SIMD dup -{MOP_vdupi32, {MOPD_Reg128FD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtFpalu,"dup","0,1", 1, 1}, -{MOP_vdupi64, {MOPD_Reg128FD,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtFpalu,"dup","0,1", 1, 1}, -{MOP_vdupf32, {MOPD_Reg128FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtFpalu,"dup","0,1", 1, 1}, -{MOP_vdupf64, {MOPD_Reg128FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtFpalu,"dup","0,1", 1, 1}, - - -// MOP_xvmovvv -{MOP_xvmovvv, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtFpalu,"mov","0,1", 1, 1}, -// MOP_xmovvr -{MOP_xvmovvr, {MOPD_Reg32FD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtR2f,"mov","0,1", 1, 1}, -// MOP_xmovrv -{MOP_xvmovrv, {MOPD_Reg32ID,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtF2r,"mov","0,1", 1, 1}, - -// MOP_xadrp -{MOP_xadrp, {MOPD_Reg64ID,MOPD_Literal,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOADADDR,kLtShift,"adrp","0,1", 1, 1}, -// MOP_xadr -{MOP_xadri64, {MOPD_Reg64ID,MOPD_Imm64,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOADADDR,kLtShift,"adr","0,1", 1, 1}, -// MOP_xadrpl12 -{MOP_xadrpl12, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Literal_L12,MOPD_Undef,MOPD_Undef},0,kLtAlu,"add","0,1,2", 1, 2}, - -// MOP_xaddrrr AARCH64 Arithmetic: add -{MOP_xaddrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"add","0,1,2", 1, 2}, -// MOP_xaddrrrs -{MOP_xaddrrrs, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_BitShift64,MOPD_Undef},0,kLtAluShift,"add","0,1,2,3", 1, 3}, - -// Vector SIMD add -// MOP_vaddf32rrr AARCH64 Arithmetic: add -{MOP_vaddf32rrr, {MOPD_Reg128FD, MOPD_Reg128FS, MOPD_Reg128FS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"fadd","0,1,2", 1, 2}, -// MOP_vaddf64rrr AARCH64 Arithmetic: add -{MOP_vaddf64rrr, {MOPD_Reg128FD, MOPD_Reg128FS, MOPD_Reg128FS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"fadd","0,1,2", 1, 2}, -// MOP_vadd32rrr AARCH64 Arithmetic: add -{MOP_vadd32rrr, {MOPD_Reg128ID,MOPD_Reg128IS,MOPD_Reg128IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"add","0,1,2", 1, 2}, -// MOP_vadd64rrr AARCH64 Arithmetic: add -{MOP_vadd64rrr, {MOPD_Reg128LD,MOPD_Reg128LS,MOPD_Reg128LS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"add","0,1,2", 1, 2}, - - -// MOP_xxwaddrrre -{MOP_xxwaddrrre, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg32IS,MOPD_ExtendShift64,MOPD_Undef},0,kLtAluShift,"add","0,1,2,3", 1, 3}, -// MOP_xaddrri24 - -{MOP_xaddrri24, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm12,MOPD_LSL12,MOPD_Undef},0,kLtShift,"add","0,1,2,3", 1, 3}, -// MOP_xaddrri12 -{MOP_xaddrri12, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,kLtAlu,"add","0,1,2", 1, 2}, -// MOP_waddrrr -{MOP_waddrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"add","0,1,2", 1, 2}, -// MOP_waddrrrs -{MOP_waddrrrs, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_BitShift32,MOPD_Undef},0,kLtAluShift,"add","0,1,2,3", 1, 3}, -// MOP_waddrri24 -{MOP_waddrri24, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm12,MOPD_LSL12,MOPD_Undef},0,kLtAluShift,"add","0,1,2,3", 1, 3}, -// MOP_waddrri12 -{MOP_waddrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,kLtAlu,"add","0,1,2", 1, 2}, -// MOP_dadd -{MOP_dadd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fadd","0,1,2", 1, 2}, -// MOP_sadd -{MOP_sadd, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fadd","0,1,2", 1, 2}, - -// MOP_xsubrrr AARCH64 Arithmetic: sub -{MOP_xsubrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"sub","0,1,2", 1, 2}, -// MOP_xsubrrrs -{MOP_xsubrrrs, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_BitShift64,MOPD_Undef},0,kLtAluShift,"sub","0,1,2,3", 1, 3}, -// MOP_xsubrri24 -{MOP_xsubrri24, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm12,MOPD_LSL12,MOPD_Undef},0,kLtAluShift,"sub","0,1,2,3", 1, 3}, -// MOP_xsubrri12 -{MOP_xsubrri12, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,kLtAlu,"sub","0,1,2", 1, 2}, -// MOP_wsubrrr -{MOP_wsubrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"sub","0,1,2", 1, 2}, -// MOP_wsubrrrs -{MOP_wsubrrrs, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_BitShift32,MOPD_Undef},0,kLtAluShift,"sub","0,1,2,3", 1, 3}, -// MOP_wsubrri24 -{MOP_wsubrri24, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm12,MOPD_LSL12,MOPD_Undef},0,kLtAluShift,"sub","0,1,2,3", 1, 3}, -// MOP_wsubrri12 -{MOP_wsubrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,kLtAlu,"sub","0,1,2", 1, 2}, -// MOP_dsub -{MOP_dsub, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fsub","0,1,2", 1, 2}, -// MOP_ssub -{MOP_ssub, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fsub","0,1,2", 1, 2}, - -// AARCH64 Arithmetic: multiply -// MOP_Tbxmulrrr -{MOP_xmulrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtMul,"mul","0,1,2", 1, 2}, -// MOP_wmulrrr -{MOP_wmulrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,kLtMul,"mul","0,1,2", 1, 2}, -// MOP_Tbxvmuls -{MOP_xvmuls, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,kLtFpmul,"fmul","0,1,2", 1, 2}, -// MOP_Tbxvmuld -{MOP_xvmuld, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,kLtFpmul,"fmul","0,1,2", 1, 2}, -//MOP_xsmullrrr -{MOP_xsmullrrr, {MOPD_Reg64ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,kLtMul,"smull","0,1,2", 1, 2}, - -// AARCH64 leading zeros, reverse bits (for trailing zeros) -// MOP_wclz -{MOP_wclz, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtAlu,"clz","0,1", 1, 1}, -// MOP_xclz -{MOP_xclz, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtAlu,"clz","0,1", 1, 1}, -// MOP_wrbit -{MOP_wrbit, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtAlu,"rbit","0,1", 1, 1}, -// MOP_xrbit -{MOP_xrbit, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtAlu,"rbit","0,1", 1, 1}, - -// AARCH64 Conversions -// MOP_xsxtb32 -{MOP_xsxtb32, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtAluShift,"sxtb","0,1", 1, 1}, -// MOP_xsxtb64 -{MOP_xsxtb64, {MOPD_Reg64ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtAluShift,"sxtb","0,1", 1, 1}, -// MOP_xsxth32 -{MOP_xsxth32, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtAluShift,"sxth","0,1", 1, 1}, -// MOP_xsxth64 -{MOP_xsxth64, {MOPD_Reg64ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtAluShift,"sxth","0,1", 1, 1}, -// MOP_xsxtw64 -{MOP_xsxtw64, {MOPD_Reg64ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtAluShift,"sxtw","0,1", 1, 1}, - -// MOP_xuxtb32 -{MOP_xuxtb32, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtAluShift,"uxtb","0,1", 1, 1}, -// MOP_xuxth32 -{MOP_xuxth32, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtAluShift,"uxth","0,1", 1, 1}, -// MOP_xuxtw64 Same as mov w0,w0 -{MOP_xuxtw64, {MOPD_Reg64ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtAluShift,"uxtw","0,1", 1, 1}, - -// MOP_xvcvtfd -{MOP_xvcvtfd, {MOPD_Reg32FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtFpalu,"fcvt","0,1", 1, 1}, -// MOP_xvcvtdf -{MOP_xvcvtdf, {MOPD_Reg64FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtFpalu,"fcvt","0,1", 1, 1}, - -// MOP_vcvtrf fcvtzs w,s -{MOP_vcvtrf, {MOPD_Reg32ID,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvtzs","0,1", 1, 1}, -// MOP_xvcvtrf fcvtzs x,s -{MOP_xvcvtrf, {MOPD_Reg64ID,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvtzs","0,1", 1, 1}, -// MOP_vcvturf fcvtzu w,s -{MOP_vcvturf, {MOPD_Reg32ID,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvtzu","0,1", 1, 1}, -// MOP_xvcvturf fcvtzu x,s -{MOP_xvcvturf, {MOPD_Reg64ID,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvtzu","0,1", 1, 1}, - -// MOP_vcvtas fcvtas w,s (for round) -{MOP_vcvtas, {MOPD_Reg32ID,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvtas","0,1", 1, 1}, -// MOP_xvcvtas fcvtas x,s -{MOP_xvcvtas, {MOPD_Reg64ID,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvtas","0,1", 1, 1}, -// MOP_vcvtms fcvtms w,s (for floor) -{MOP_vcvtms, {MOPD_Reg32ID,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvtms","0,1", 1, 1}, -// MOP_xvcvtms fcvtms x,s -{MOP_xvcvtms, {MOPD_Reg64ID,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvtms","0,1", 1, 1}, -// MOP_vcvtps fcvtps w,s (for ceil) -{MOP_vcvtps, {MOPD_Reg32ID,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvtps","0,1", 1, 1}, -// MOP_xvcvtps fcvtps x,d -{MOP_xvcvtps, {MOPD_Reg64ID,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvtps","0,1", 1, 1}, - -// MOP_vcvtrd fcvtzs w,d -{MOP_vcvtrd, {MOPD_Reg32ID,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvtzs","0,1", 1, 1}, -// MOP_xvcvtrd fcvtzs x,d -{MOP_xvcvtrd, {MOPD_Reg64ID,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvtzs","0,1", 1, 1}, -// MOP_vcvturd fcvtzu w,d -{MOP_vcvturd, {MOPD_Reg32ID,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvtzu","0,1", 1, 1}, -// MOP_xvcvturd fcvtzu x,d -{MOP_xvcvturd, {MOPD_Reg64ID,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtF2rCvt,"fcvtzu","0,1", 1, 1}, - -// MOP_vcvtfr scvtf s,w -{MOP_vcvtfr, {MOPD_Reg32FD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtR2fCvt,"scvtf","0,1", 1, 1}, -// MOP_xvcvtfr scvtf s,x -{MOP_xvcvtfr, {MOPD_Reg32FD,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtR2fCvt,"scvtf","0,1", 1, 1}, -// MOP_vcvtufr ucvtf s,w -{MOP_vcvtufr, {MOPD_Reg32FD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtR2fCvt,"ucvtf","0,1", 1, 1}, -// MOP_xvcvtufr ucvtf s,x -{MOP_xvcvtufr, {MOPD_Reg32FD,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtR2fCvt,"ucvtf","0,1", 1, 1}, - -// MOP_vcvtdr scvtf d,w -{MOP_vcvtdr, {MOPD_Reg64FD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtR2fCvt,"scvtf","0,1", 1, 1}, -// MOP_xvcvtdr scvtf d,x -{MOP_xvcvtdr, {MOPD_Reg64FD,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtR2fCvt,"scvtf","0,1", 1, 1}, -// MOP_vcvtudr ucvtf d,w -{MOP_vcvtudr, {MOPD_Reg64FD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtR2fCvt,"ucvtf","0,1", 1, 1}, -// MOP_xvcvtudr ucvtf d,x -{MOP_xvcvtudr, {MOPD_Reg64FD,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONVERSION,kLtR2fCvt,"ucvtf","0,1", 1, 1}, - -// MOP_xcsel -{MOP_wcselrrrc, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Cond,MOPD_Undef},ISCONDDEF,kLtAlu,"csel","0,1,2,3", 1, 3}, -{MOP_xcselrrrc, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Cond,MOPD_Undef},ISCONDDEF,kLtAlu,"csel","0,1,2,3", 1, 3}, - -// MOP_xcset -- all conditions minus AL & NV -{MOP_wcsetrc, {MOPD_Reg32ID,MOPD_Cond,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONDSET | ISCONDDEF,kLtAlu,"cset","0,1", 1, 1}, -{MOP_xcsetrc, {MOPD_Reg64ID,MOPD_Cond,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCONDSET | ISCONDDEF,kLtAlu,"cset","0,1", 1, 1}, - -// MOP_xcsinc -{MOP_wcsincrrrc, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Cond,MOPD_Undef},ISCONDDEF,kLtAlu,"csinc","0,1,2,3", 1, 3}, -{MOP_xcsincrrrc, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Cond,MOPD_Undef},ISCONDDEF,kLtAlu,"csinc","0,1,2,3", 1, 3}, - -// MOP_xcsinv -{MOP_wcsinvrrrc, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Cond,MOPD_Undef},ISCONDDEF,kLtAlu,"csinv","0,1,2,3", 1, 3}, -{MOP_xcsinvrrrc, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Cond,MOPD_Undef},ISCONDDEF,kLtAlu,"csinv","0,1,2,3", 1, 3}, - -// MOP_xandrrr -{MOP_xandrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"and","0,1,2", 1, 2}, -// MOP_xandrrrs -{MOP_xandrrrs, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_BitShift64,MOPD_Undef},0,kLtAluShift,"and","0,1,2,3", 1, 3}, -// MOP_xandrri13 -{MOP_xandrri13, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm13,MOPD_Undef,MOPD_Undef},0,kLtAlu,"and","0,1,2", 1, 2}, -// MOP_wandrrr -{MOP_wandrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"and","0,1,2", 1, 2}, -// MOP_wandrrrs -{MOP_wandrrrs, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_BitShift32,MOPD_Undef},0,kLtAluShift,"and","0,1,2,3", 1, 3}, -// MOP_wandrri12 -{MOP_wandrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,kLtAlu,"and","0,1,2", 1, 2}, - -// MOP_xiorrrr -{MOP_xiorrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"orr","0,1,2", 1, 2}, -// MOP_xiorrrrs -{MOP_xiorrrrs, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_BitShift64,MOPD_Undef},0,kLtAlu,"orr","0,1,2,3", 1, 3}, -// MOP_xiorrri13 -{MOP_xiorrri13, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm13,MOPD_Undef,MOPD_Undef},0,kLtAlu,"orr","0,1,2", 1, 2}, -// MOP_wiorrrr -{MOP_wiorrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"orr","0,1,2", 1, 2}, -// MOP_wiorrrrs -{MOP_wiorrrrs, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_BitShift32,MOPD_Undef},0,kLtAlu,"orr","0,1,2,3", 1, 3}, -// MOP_wiorrri12 -{MOP_wiorrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,kLtAlu,"orr","0,1,2", 1, 2}, - -// MOP_xiorri13r -{MOP_xiorri13r, {MOPD_Reg64ID,MOPD_Imm13,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"orr","0,2,1", 1, 2}, -// MOP_wiorri12r -{MOP_wiorri12r, {MOPD_Reg32ID,MOPD_Imm12,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"orr","0,2,1", 1, 2}, - -// MOP_xeorrrr -{MOP_xeorrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"eor","0,1,2", 1, 2}, -// MOP_xeorrrrs -{MOP_xeorrrrs, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_BitShift64,MOPD_Undef},0,kLtAlu,"eor","0,1,2,3", 1, 3}, -// MOP_xeorrri13 -{MOP_xeorrri13, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm13,MOPD_Undef,MOPD_Undef},0,kLtAlu,"eor","0,1,2", 1, 2}, -// MOP_weorrrr -{MOP_weorrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"eor","0,1,2", 1, 2}, -// MOP_weorrrrs -{MOP_weorrrrs, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_BitShift32,MOPD_Undef},0,kLtAlu,"eor","0,1,2,3", 1, 3}, -// MOP_weorrri12 -{MOP_weorrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,kLtAlu,"eor","0,1,2", 1, 2}, - -// MOP_weorrri8m -{MOP_weorrri8m, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,kLtAlu,"eor","0,1,2", 1, 2}, - -// MOP_xnotrr -{MOP_xnotrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtAlu,"mvn","0,1", 1, 1}, -// MOP_wnotrr -{MOP_wnotrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtAlu,"mvn","0,1", 1, 1}, - -// MOP_wfmaxrrr -{MOP_wfmaxrrr, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fmax","0,1,2", 1, 2}, -// MOP_xfmaxrrr -{MOP_xfmaxrrr, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fmax","0,1,2", 1, 2}, -// MOP_wfminrrr -{MOP_wfminrrr, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fmin","0,1,2", 1, 2}, -// MOP_xfminrrr -{MOP_xfminrrr, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fmin","0,1,2", 1, 2}, - -// MOP_wsdivrrr -{MOP_wsdivrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},CANTHROW,kLtDiv,"sdiv","0,1,2", 1, 2}, -// MOP_xsdivrrr -{MOP_xsdivrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},CANTHROW,kLtDiv,"sdiv","0,1,2", 1, 2}, -// MOP_wudivrrr -{MOP_wudivrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},CANTHROW,kLtDiv,"udiv","0,1,2", 1, 2}, -// MOP_xudivrrr -{MOP_xudivrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},CANTHROW,kLtDiv,"udiv","0,1,2", 1, 2}, - -// MOP_wmsubrrrr -{MOP_wmsubrrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,kLtMul,"msub","0,1,2,3", 1, 3}, -// MOP_xmsubrrrr -{MOP_xmsubrrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef},0,kLtMul,"msub","0,1,2,3", 1, 3}, - -// MPO_wubfxrri5i5 -{MOP_wubfxrri5i5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm5,MOPD_Imm5,MOPD_Undef},0,kLtAluShift,"ubfx","0,1,2,3", 1, 3}, -// MPO_xubfxrri6i6 -{MOP_xubfxrri6i6, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm6,MOPD_Imm6,MOPD_Undef},0,kLtAluShift,"ubfx","0,1,2,3", 1, 3}, - -// MPO_wsbfxrri5i5 -- Signed Bitfield Extract -{MOP_wsbfxrri5i5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm5,MOPD_Imm5,MOPD_Undef},0,kLtAluShift,"sbfx","0,1,2,3", 1, 3}, -// MPO_xsbfxrri6i6 -{MOP_xsbfxrri6i6, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm6,MOPD_Imm6,MOPD_Undef},0,kLtAluShift,"sbfx","0,1,2,3", 1, 3}, - -// MPO_wubfizrri5i5 -- Unsigned Bitfield Insert in Zero -{MOP_wubfizrri5i5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm5,MOPD_Imm5,MOPD_Undef},0,kLtAluShift,"ubfiz","0,1,2,3", 1, 3}, -// MPO_xubfizrri6i6 -{MOP_xubfizrri6i6, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm6,MOPD_Imm6,MOPD_Undef},0,kLtAluShift,"ubfiz","0,1,2,3", 1, 3}, - -// MPO_wbfirri5i5 -- Bitfield Insert -{MPO_wbfirri5i5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm5,MOPD_Imm5,MOPD_Undef},0,kLtAluShift,"bfi","0,1,2,3", 1, 3}, -// MPO_xbfirri6i6 -{MPO_xbfirri6i6, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm6,MOPD_Imm6,MOPD_Undef},0,kLtAluShift,"bfi","0,1,2,3", 1, 3}, - - -// MOP_xlslrri6,--- Logical Shift Left -{MOP_xlslrri6, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm6,MOPD_Undef,MOPD_Undef},0,kLtAluShift,"lsl","0,1,2", 1, 2}, -// MOP_wlslrri5 -{MOP_wlslrri5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,kLtAluShift,"lsl","0,1,2", 1, 2}, -// MOP_xasrrri6, -{MOP_xasrrri6, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm6,MOPD_Undef,MOPD_Undef},0,kLtAluShift,"asr","0,1,2", 1, 2}, -// MOP_wasrrri5 -{MOP_wasrrri5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,kLtAluShift,"asr","0,1,2", 1, 2}, -// MOP_xlsrrri6, -{MOP_xlsrrri6, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Imm6,MOPD_Undef,MOPD_Undef},0,kLtAluShift,"lsr","0,1,2", 1, 2}, -// MOP_wlsrrri5 -{MOP_wlsrrri5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,kLtAluShift,"lsr","0,1,2", 1, 2}, -// MOP_xlslrrr, -{MOP_xlslrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAluShiftReg,"lsl","0,1,2", 1, 2}, -// MOP_wlslrrr -{MOP_wlslrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,kLtAluShiftReg,"lsl","0,1,2", 1, 2}, -// MOP_xasrrrr, -{MOP_xasrrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAluShiftReg,"asr","0,1,2", 1, 2}, -// MOP_wasrrrr -{MOP_wasrrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,kLtAluShiftReg,"asr","0,1,2", 1, 2}, -// MOP_xlsrrrr, -{MOP_xlsrrrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAluShiftReg,"lsr","0,1,2", 1, 2}, -// MOP_wlsrrrr -{MOP_wlsrrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,kLtAluShiftReg,"lsr","0,1,2", 1, 2}, - -// MOP_wsfmovrr w->s -{MOP_wsfmovrr, {MOPD_Reg32FD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtR2f,"fmov","0,1", 1, 1}, -// MOP_wsfmovri imm8->s -{MOP_wsfmovri, {MOPD_Reg32FD,MOPD_Imm8,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtFconst,"fmov","0,1", 1, 1}, -// MOP_swfmovrr s->w -{MOP_swfmovrr, {MOPD_Reg32ID,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtF2r,"fmov","0,1", 1, 1}, -// MOP_xdfmovrr x->d -{MOP_xdfmovrr, {MOPD_Reg64FD,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtR2f,"fmov","0,1", 1, 1}, -// MOP_xdfmovri imm8->d -{MOP_xdfmovri, {MOPD_Reg64FD,MOPD_Imm8,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtFconst,"fmov","0,1", 1, 1}, -// MOP_dxfmovrr d->x -{MOP_dxfmovrr, {MOPD_Reg64ID,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,kLtF2r,"fmov","0,1", 1, 1}, - -// MOP_xcsneg -- Conditional Select Negation -{MOP_wcsnegrrrc, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Cond,MOPD_Undef},ISCONDDEF,kLtAlu,"csneg","0,1,2,3", 1, 3}, -{MOP_xcsnegrrrc, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Cond,MOPD_Undef},ISCONDDEF,kLtAlu,"csneg","0,1,2,3", 1, 3}, - -// MOP_habsrr -{MOP_habsrr, {MOPD_Reg16FD,MOPD_Reg16FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fabs","0,1", 1, 1}, -// MOP_sabsrr -{MOP_sabsrr, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fabs","0,1", 1, 1}, -// MOP_dabsrr -{MOP_dabsrr, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fabs","0,1", 1, 1}, - -// neg i32 -{MOP_winegrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtAlu,"neg","0,1", 1, 1}, -// neg i64 -{MOP_xinegrr, {MOPD_Reg64ID,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtAlu,"neg","0,1", 1, 1}, -// neg f32 -{MOP_wfnegrr, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fneg","0,1", 1, 1}, -// neg f64 -{MOP_xfnegrr, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fneg","0,1", 1, 1}, - -// MOP_hdivrrr -{MOP_hdivrrr, {MOPD_Reg16FD,MOPD_Reg16FS,MOPD_Reg16FS,MOPD_Undef,MOPD_Undef},CANTHROW,kLtAdvsimdDivS,"fdiv","0,1,2", 1, 2}, -// MOP_sdivrrr -{MOP_sdivrrr, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},CANTHROW,kLtAdvsimdDivS,"fdiv","0,1,2", 1, 2}, -// MOP_ddivrrr -{MOP_ddivrrr, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},CANTHROW,kLtAdvsimdDivD,"fdiv","0,1,2", 1, 2}, - -// MOP_hcselrrrc --- Floating-point Conditional Select -{MOP_hcselrrrc, {MOPD_Reg16FD,MOPD_Reg16FS,MOPD_Reg16FS,MOPD_Cond,MOPD_Undef},ISCONDDEF,kLtFpalu,"fcsel","0,1,2,3", 1, 3}, -// MOP_scselrrrc -{MOP_scselrrrc, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Cond,MOPD_Undef},ISCONDDEF,kLtFpalu,"fcsel","0,1,2,3", 1, 3}, -// MOP_dcselrrrc -{MOP_dcselrrrc, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Cond,MOPD_Undef},ISCONDDEF,kLtFpalu,"fcsel","0,1,2,3", 1, 3}, - -// MOP_wldli -- load 32-bit literal -{MOP_wldli, {MOPD_Reg32ID,MOPD_Imm32LI,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtLoad2,"ldr","0,1", 1, 1}, -// MOP_xldli -- load 64-bit literal -{MOP_xldli, {MOPD_Reg64ID,MOPD_Imm64LI,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtLoad2,"ldr","0,1", 1, 1}, -// MOP_sldli -- load 32-bit literal -{MOP_sldli, {MOPD_Reg32FD,MOPD_Imm32LI,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtLoad2,"ldr","0,1", 1, 1}, -// MOP_dldli -- load 64-bit literal -{MOP_dldli, {MOPD_Reg64FD,MOPD_Imm64LI,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtLoad2,"ldr","0,1", 1, 1}, - -// AArch64 branches/calls -// MOP_xbl -- branch with link (call); this is a special definition -{MOP_xbl, {MOPD_FuncName,MOPD_LISTS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCALL|CANTHROW,kLtBranch,"bl","0", 0, 2}, -// MOP_xblr -- branch with link (call) to register; this is a special definition -{MOP_xblr, {MOPD_Reg64IS,MOPD_LISTS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCALL|CANTHROW,kLtBranch,"blr","0", 0, 2}, - -// AARCH64 LOADS -// MOP_wldrsb --- Load Register Signed Byte -{MOP_wldrsb, {MOPD_Reg32ID,MOPD_Mem8S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtLoad1,"ldrsb","0,1", 1, 1}, -// MOP_wldrb -{MOP_wldrb, {MOPD_Reg32ID,MOPD_Mem8S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtLoad1,"ldrb","0,1", 1, 1}, -// MOP_wldrsh --- Load Register Signed Halfword -{MOP_wldrsh, {MOPD_Reg32ID,MOPD_Mem16S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtLoad1,"ldrsh","0,1", 1, 1}, -// MOP_wldrh -{MOP_wldrh, {MOPD_Reg32ID, MOPD_Mem16S, MOPD_Undef, MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtLoad1,"ldrh","0,1", 1, 1}, -// MOP_wldr -{MOP_wldr, {MOPD_Reg32ID,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtLoad1,"ldr","0,1", 1, 1}, -// MOP_xldr -{MOP_xldr, {MOPD_Reg64ID,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtLoad2,"ldr","0,1", 1, 1}, -// MOP_bldr -{MOP_bldr, {MOPD_Reg8FD,MOPD_Mem8S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtFLoad64,"ldr","0,1", 1, 1}, -// MOP_hldr -{MOP_hldr, {MOPD_Reg16FD,MOPD_Mem16S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtFLoad64,"ldr","0,1", 1, 1}, -// MOP_sldr -{MOP_sldr, {MOPD_Reg32FD,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtFLoadMany,"ldr","0,1", 1, 1}, -// MOP_dldr -{MOP_dldr, {MOPD_Reg64FD,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtFLoadMany,"ldr","0,1", 1, 1}, -// MOP_vldr -{MOP_vldr, {MOPD_Reg128FD,MOPD_Mem128S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|CANTHROW,kLtFLoadMany,"ldr","0,1", 1, 1}, - -// AArch64 LDP/LDPSW -// MOP_wldp -{MOP_wldp, {MOPD_Reg32ID,MOPD_Reg32ID,MOPD_Mem32S,MOPD_Undef,MOPD_Undef},ISLOAD|ISLOADPAIR|CANTHROW,kLtLoad2,"ldp","0,1,2", 2, 1}, -// MOP_xldp -{MOP_xldp, {MOPD_Reg64ID,MOPD_Reg64ID,MOPD_Mem64S,MOPD_Undef,MOPD_Undef},ISLOAD|ISLOADPAIR|CANTHROW,kLtLoad3plus,"ldp","0,1,2", 2, 1}, -// MOP_xldpsw -{MOP_xldpsw, {MOPD_Reg64ID,MOPD_Reg64ID,MOPD_Mem32S,MOPD_Undef,MOPD_Undef},ISLOAD|ISLOADPAIR|CANTHROW,kLtLoad2,"ldpsw","0,1,2", 2, 1}, -// MOP_sldp -{MOP_sldp, {MOPD_Reg32FD,MOPD_Reg32FD,MOPD_Mem32S,MOPD_Undef,MOPD_Undef},ISLOAD|ISLOADPAIR|CANTHROW,kLtFLoad64,"ldp","0,1,2", 2, 1}, -// MOP_dldp -{MOP_dldp, {MOPD_Reg64FD,MOPD_Reg64FD,MOPD_Mem64S,MOPD_Undef,MOPD_Undef},ISLOAD|ISLOADPAIR|CANTHROW,kLtFLoadMany,"ldp","0,1,2", 2, 1}, - -// AARCH64 Load with Acquire semantics -// MOP_wldarb -{MOP_wldarb, {MOPD_Reg32ID,MOPD_Mem8S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|HASACQUIRE|CANTHROW,kLtUndef,"ldarb","0,1", 1, 1}, -// MOP_wldarh -{MOP_wldarh, {MOPD_Reg32ID, MOPD_Mem16S, MOPD_Undef, MOPD_Undef,MOPD_Undef},ISLOAD|HASACQUIRE|CANTHROW,kLtUndef,"ldarh","0,1", 1, 1}, -// MOP_wldar -{MOP_wldar, {MOPD_Reg32ID,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|HASACQUIRE|CANTHROW,kLtUndef,"ldar","0,1", 1, 1}, -// MOP_xldar -{MOP_xldar, {MOPD_Reg64ID,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|HASACQUIRE|CANTHROW,kLtUndef,"ldar","0,1", 1, 1}, - -// AARCH64 Load with LOAcquire semantics -// MOP_wldlarb -{MOP_wldlarb, {MOPD_Reg32ID,MOPD_Mem8S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|HASLOACQUIRE|CANTHROW,kLtUndef,"ldlarb","0,1", 1, 1}, -// MOP_wldlarh -{MOP_wldlarh, {MOPD_Reg32ID, MOPD_Mem16S, MOPD_Undef, MOPD_Undef,MOPD_Undef},ISLOAD|HASLOACQUIRE|CANTHROW,kLtUndef,"ldlarh","0,1", 1, 1}, -// MOP_wldlar -{MOP_wldlar, {MOPD_Reg32ID,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|HASLOACQUIRE|CANTHROW,kLtUndef,"ldlar","0,1", 1, 1}, -// MOP_xldlar -{MOP_xldlar, {MOPD_Reg64ID,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|HASLOACQUIRE|CANTHROW,kLtUndef,"ldlar","0,1", 1, 1}, - -// AARCH64 Load with Acquire RCpc semantics -// MOP_wldaprb -{MOP_wldaprb, {MOPD_Reg32ID,MOPD_Mem8S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|HASACQUIRERCPC|CANTHROW,kLtUndef,"ldaprb","0,1", 1, 1}, -// MOP_wldaprh -{MOP_wldaprh, {MOPD_Reg32ID, MOPD_Mem16S, MOPD_Undef, MOPD_Undef,MOPD_Undef},ISLOAD|HASACQUIRERCPC|CANTHROW,kLtUndef,"ldaprh","0,1", 1, 1}, -// MOP_wldapr -{MOP_wldapr, {MOPD_Reg32ID,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|HASACQUIRERCPC|CANTHROW,kLtUndef,"ldapr","0,1", 1, 1}, -// MOP_xldapr -{MOP_xldapr, {MOPD_Reg64ID,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|HASACQUIRERCPC|CANTHROW,kLtUndef,"ldapr","0,1", 1, 1}, - -// MOP_wmovkri16 -- LSL4/LSL6 is not encoding LSL per se. For the moment assumes it is LSL only. -{MOP_wmovkri16, {MOPD_Reg32IDS,MOPD_Imm16,MOPD_LSL4,MOPD_Undef,MOPD_Undef},ISMOVE|ISPARTDEF,kLtShift,"movk","0,1,2", 1, 3}, -// MOP_xmovkri16 -{MOP_xmovkri16, {MOPD_Reg64IDS,MOPD_Imm16,MOPD_LSL6,MOPD_Undef,MOPD_Undef},ISMOVE|ISPARTDEF,kLtShift,"movk","0,1,2", 1, 3}, - -// MOP_wmovzri16 -{MOP_wmovzri16, {MOPD_Reg32ID,MOPD_Imm16,MOPD_LSL4,MOPD_Undef,MOPD_Undef},ISMOVE|ISPARTDEF,kLtShift,"movz","0,1,2", 1, 2}, -// MOP_xmovzri16 -{MOP_xmovzri16, {MOPD_Reg64ID,MOPD_Imm16,MOPD_LSL6,MOPD_Undef,MOPD_Undef},ISMOVE|ISPARTDEF,kLtShift,"movz","0,1,2", 1, 2}, - -// MOP_wmovnri16 -{MOP_wmovnri16, {MOPD_Reg32ID,MOPD_Imm16,MOPD_LSL4,MOPD_Undef,MOPD_Undef},ISMOVE|ISPARTDEF,kLtShift,"movn","0,1,2", 1, 2}, -// MOP_xmovnri16 -{MOP_xmovnri16, {MOPD_Reg64ID,MOPD_Imm16,MOPD_LSL6,MOPD_Undef,MOPD_Undef},ISMOVE|ISPARTDEF,kLtShift,"movn","0,1,2", 1, 2}, - -// AARCH64 Load exclusive with/without acquire semantics -{MOP_wldxrb, {MOPD_Reg32ID,MOPD_Mem8S, MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|ISATOMIC|CANTHROW,kLtUndef,"ldxrb","0,1", 1, 1}, -{MOP_wldxrh, {MOPD_Reg32ID,MOPD_Mem16S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|ISATOMIC|CANTHROW,kLtUndef,"ldxrh","0,1", 1, 1}, -{MOP_wldxr, {MOPD_Reg32ID,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|ISATOMIC|CANTHROW,kLtUndef,"ldxr","0,1", 1, 1}, -{MOP_xldxr, {MOPD_Reg64ID,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|ISATOMIC|CANTHROW,kLtUndef,"ldxr","0,1", 1, 1}, - -{MOP_wldaxrb,{MOPD_Reg32ID,MOPD_Mem8S, MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|ISATOMIC|HASACQUIRE|CANTHROW,kLtUndef,"ldaxrb","0,1", 1, 1}, -{MOP_wldaxrh,{MOPD_Reg32ID,MOPD_Mem16S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|ISATOMIC|HASACQUIRE|CANTHROW,kLtUndef,"ldaxrh","0,1", 1, 1}, -{MOP_wldaxr, {MOPD_Reg32ID,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|ISATOMIC|HASACQUIRE|CANTHROW,kLtUndef,"ldaxr","0,1", 1, 1}, -{MOP_xldaxr, {MOPD_Reg64ID,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD|ISATOMIC|HASACQUIRE|CANTHROW,kLtUndef,"ldaxr","0,1", 1, 1}, - -{MOP_wldaxp, {MOPD_Reg32ID,MOPD_Reg32ID,MOPD_Mem32S,MOPD_Undef,MOPD_Undef},ISLOAD|ISLOADPAIR|ISATOMIC|HASACQUIRE|CANTHROW,kLtUndef,"ldaxp","0,1,2", 2, 1}, -{MOP_xldaxp, {MOPD_Reg64ID,MOPD_Reg64ID,MOPD_Mem64S,MOPD_Undef,MOPD_Undef},ISLOAD|ISLOADPAIR|ISATOMIC|HASACQUIRE|CANTHROW,kLtUndef,"ldaxp","0,1,2", 2, 1}, - -// MOP_vsqrts -{MOP_vsqrts, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},CANTHROW,kLtAdvsimdDivS,"fsqrt","0,1", 1, 1}, -// MOP_vsqrtd -{MOP_vsqrtd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},CANTHROW,kLtAdvsimdDivD,"fsqrt","0,1", 1, 1}, - - -// # Non Definitions -// # As far as register allocation is concerned, the instructions below are non-definitions. - -// MOP_beq -{MOP_beq, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"beq","1", 0, 2}, -// MOP_bne -{MOP_bne, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bne","1", 0, 2}, -// MOP_blt -{MOP_blt, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"blt","1", 0, 2}, -// MOP_ble -{MOP_ble, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"ble","1", 0, 2}, -// MOP_bgt -{MOP_bgt, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bgt","1", 0, 2}, -// MOP_bge -{MOP_bge, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bge","1", 0, 2}, -// MOP_blo equal to MOP_blt for unsigned comparison -{MOP_blo, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"blo","1", 0, 2}, -// MOP_bls equal to MOP_bls for unsigned comparison -{MOP_bls, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bls","1", 0, 2}, -// MOP_bhs equal to MOP_bge for unsigned comparison -{MOP_bhs, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bhs","1", 0, 2}, -// MOP_bhi equal to MOP_bgt for float comparison -{MOP_bhi, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bhi","1", 0, 2}, -// MOP_bpl equal to MOP_bge for float comparison -{MOP_bpl, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bpl","1", 0, 2}, -{MOP_bmi, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bmi","1", 0, 2}, -{MOP_bvc, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bvc","1", 0, 2}, -{MOP_bvs, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bvs","1", 0, 2}, -{MOP_bal, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"bal","1", 0, 2}, - -// MOP_xret AARCH64 Specific -{MOP_xret, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},CANTHROW,kLtBranch,"ret","", 0, 0}, - -// AARCH64 Floating-Point COMPARES signaling versions -// MOP_hcmperi -- AArch64 cmp has no dest operand -{MOP_hcmperi, {MOPD_RegCCD, MOPD_Reg16FS,MOPD_FPZeroImm8,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fcmpe","1,2", 1, 2}, -// MOP_hcmperr -- register, shifted register, AArch64 cmp has no dest operand -{MOP_hcmperr, {MOPD_RegCCD, MOPD_Reg16FS,MOPD_Reg16FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fcmpe","1,2", 1, 2}, - -// MOP_scmperi -- AArch64 cmp has no dest operand -{MOP_scmperi, {MOPD_RegCCD, MOPD_Reg32FS,MOPD_FPZeroImm8,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fcmpe","1,2", 1, 2}, -// MOP_scmperr -{MOP_scmperr, {MOPD_RegCCD, MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fcmpe","1,2", 1, 2}, - -// MOP_dcmperi -- AArch64 cmp has no dest operand -{MOP_dcmperi, {MOPD_RegCCD, MOPD_Reg64FS,MOPD_FPZeroImm8,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fcmpe","1,2", 1, 2}, -// MOP_dcmperr -{MOP_dcmperr, {MOPD_RegCCD, MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fcmpe","1,2", 1, 2}, - -// AARCH64 Floating-Point COMPARES non-signaling (quiet) versions -// MOP_hcmpqri -- AArch64 cmp has no dest operand -{MOP_hcmpqri, {MOPD_RegCCD, MOPD_Reg16FS,MOPD_FPZeroImm8,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fcmp","1,2", 1, 2}, -// MOP_hcmpqrr -- register, shifted register, AArch64 cmp has no dest operand -{MOP_hcmpqrr, {MOPD_RegCCD, MOPD_Reg16FS,MOPD_Reg16FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fcmp","1,2", 1, 2}, - -// MOP_scmpqri -- AArch64 cmp has no dest operand -{MOP_scmpqri, {MOPD_RegCCD, MOPD_Reg32FS,MOPD_FPZeroImm8,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fcmp","1,2", 1, 2}, -// MOP_scmpqrr -{MOP_scmpqrr, {MOPD_RegCCD, MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fcmp","1,2", 1, 2}, - -// MOP_dcmpqri -- AArch64 cmp has no dest operand -{MOP_dcmpqri, {MOPD_RegCCD, MOPD_Reg64FS,MOPD_FPZeroImm8,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fcmp","1,2", 1, 2}, -// MOP_dcmpqrr -{MOP_dcmpqrr, {MOPD_RegCCD, MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,kLtFpalu,"fcmp","1,2", 1, 2}, - -// AARCH64 Integer COMPARES -// MOP_wcmpri -- AArch64 cmp has no dest operand -{MOP_wcmpri, {MOPD_RegCCD, MOPD_Reg32IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,kLtAlu,"cmp","1,2", 1, 2}, -// MOP_wcmprr -- register, shifted register, AArch64 cmp has no dest operand -{MOP_wcmprr, {MOPD_RegCCD, MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"cmp","1,2", 1, 2}, -// MOP_xcmpri -- AArch64 cmp has no dest operand -{MOP_xcmpri, {MOPD_RegCCD, MOPD_Reg64IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,kLtAlu,"cmp","1,2", 1, 2}, -// MOP_xcmprr -- register, shifted register, AArch64 cmp has no dest operand -{MOP_xcmprr, {MOPD_RegCCD, MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"cmp","1,2", 1, 2}, - -// MOP_wccmpriic -- AArch64 cmp has no dest operand -{MOP_wccmpriic, {MOPD_RegCCD, MOPD_Reg32IS,MOPD_Imm5,MOPD_Imm4,MOPD_Cond},0,kLtAlu,"ccmp","1,2,3,4", 1, 4}, -// MOP_wccmprric -- register, shifted register, AArch64 cmp has no dest operand -{MOP_wccmprric, {MOPD_RegCCD, MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Imm4,MOPD_Cond},0,kLtAlu,"ccmp","1,2,3,4", 1, 4}, -// MOP_xccmpriic -- AArch64 cmp has no dest operand -{MOP_xccmpriic, {MOPD_RegCCD, MOPD_Reg64IS,MOPD_Imm5,MOPD_Imm4,MOPD_Cond},0,kLtAlu,"ccmp","1,2,3,4", 1, 4}, -// MOP_xccmprric -- register, shifted register, AArch64 cmp has no dest operand -{MOP_xccmprric, {MOPD_RegCCD, MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Imm4,MOPD_Cond},0,kLtAlu,"ccmp","1,2,3,4", 1, 4}, - -// MOP_wcmnri -- AArch64 cmp has no dest operand -{MOP_wcmnri, {MOPD_RegCCD, MOPD_Reg32IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,kLtAlu,"cmn","1,2", 1, 2}, -// MOP_wcmnrr -- register, shifted register, AArch64 cmp has no dest operand -{MOP_wcmnrr, {MOPD_RegCCD, MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"cmn","1,2", 1, 2}, -// MOP_xcmnri -- AArch64 cmp has no dest operand -{MOP_xcmnri, {MOPD_RegCCD, MOPD_Reg64IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,kLtAlu,"cmn","1,2", 1, 2}, -// MOP_xcmnrr -- register, shifted register, AArch64 cmp has no dest operand -{MOP_xcmnrr, {MOPD_RegCCD, MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Undef,MOPD_Undef},0,kLtAlu,"cmn","1,2", 1, 2}, - -// AArch64 branches -// MOP_xbr -- branch to register -{MOP_xbr, {MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"br","0", 0, 1}, -// MOP_Tbbuncond -{MOP_xuncond, {MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"b","0", 0, 1}, - -// MOP_wcbnz --- Compare and Branch on Nonzero -{MOP_wcbnz, {MOPD_Reg32IS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"cbnz","0,1", 0, 2}, -// MOP_xcbnz -{MOP_xcbnz, {MOPD_Reg64IS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"cbnz","0,1", 0, 2}, -// MOP_wcbz --- Compare and Branch on zero -{MOP_wcbz, {MOPD_Reg32IS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"cbz","0,1", 0, 2}, -// MOP_xcbz -{MOP_xcbz, {MOPD_Reg64IS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"cbz","0,1", 0, 2}, - -// MOP_wtbnz --- Test bit and Branch if Nonzero -{MOP_wtbnz, {MOPD_Reg32IS,MOPD_Imm8,MOPD_Label,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"tbnz","0,1,2", 0, 3}, -// MOP_xtbnz -{MOP_xtbnz, {MOPD_Reg64IS,MOPD_Imm8,MOPD_Label,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"tbnz","0,1,2", 0, 3}, -// MOP_wtbz --- Test bit and Branch if Zero -{MOP_wtbz, {MOPD_Reg32IS,MOPD_Imm8,MOPD_Label,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"tbz","0,1,2", 0, 3}, -// MOP_xtbz -{MOP_xtbz, {MOPD_Reg64IS,MOPD_Imm8,MOPD_Label,MOPD_Undef,MOPD_Undef},ISBRANCH,kLtBranch,"tbz","0,1,2", 0, 3}, - -// AARCH64 STORES -// MOP_wstrb -- Store Register Byte -{MOP_wstrb, {MOPD_Reg32IS,MOPD_Mem8D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtStore1,"strb","0,1", 1, 1}, -// MOP_wstrh -- Store Register Halfword -{MOP_wstrh, {MOPD_Reg32IS,MOPD_Mem16D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtStore1,"strh","0,1", 1, 1}, -// MOP_wstr -- Store Register Word -{MOP_wstr, {MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtStore1,"str","0,1", 1, 1}, -// MOP_xstr -- Store Register Double word -{MOP_xstr, {MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtStore2,"str","0,1", 1, 1}, - -// MOP_sstr -- Store Register SIMD/FP Float -{MOP_sstr, {MOPD_Reg32FS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtStore2,"str","0,1", 1, 1}, -// MOP_dstr -- Store Register SIMD/FP Double -{MOP_dstr, {MOPD_Reg64FS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtStore3plus,"str","0,1", 1, 1}, - -// MOP_vstr -- Store Register SIMD -{MOP_vstr, {MOPD_Reg128FS,MOPD_Mem128D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtStore2,"str","0,1", 1, 1}, - -// AArch64 STP. -// MOP_wstp -{MOP_wstp, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef},ISSTORE|ISSTOREPAIR|CANTHROW,kLtStore2,"stp","0,1,2", 1, 2}, -// MOP_xstp -{MOP_xstp, {MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef},ISSTORE|ISSTOREPAIR|CANTHROW,kLtStore3plus,"stp","0,1,2", 1, 2}, -// AArch64 does not define STPSW. It has no practical value. -// MOP_sstp -{MOP_sstp, {MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef},ISSTORE|ISSTOREPAIR|CANTHROW,kLtAdvsimdMulQ,"stp","0,1,2", 1, 2}, -// MOP_dstp -{MOP_dstp, {MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef},ISSTORE|ISSTOREPAIR|CANTHROW,kLtAdvsimdMulQ,"stp","0,1,2", 1, 2}, - - - -// AARCH64 Store with Release semantics -// MOP_wstlrb -- Store-Release Register Byte -{MOP_wstlrb, {MOPD_Reg32IS,MOPD_Mem8D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"stlrb","0,1", 1, 1}, -// MOP_wstlrh -- Store-Release Register Halfword -{MOP_wstlrh, {MOPD_Reg32IS,MOPD_Mem16D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"stlrh","0,1", 1, 1}, -// MOP_wstlr -- Store-Release Register Word -{MOP_wstlr, {MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"stlr","0,1", 1, 1}, -// MOP_xstlr -- Store-Release Register Double word -{MOP_xstlr, {MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"stlr","0,1", 1, 1}, - -// AARCH64 Store with LORelease semantics -// MOP_wstllrb -- Store-LORelease Register Byte -{MOP_wstllrb, {MOPD_Reg32IS,MOPD_Mem8D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASLORELEASE|CANTHROW,kLtUndef,"stllrb","0,1", 1, 1}, -// MOP_wstllrh -- Store-LORelease Register Halfword -{MOP_wstllrh, {MOPD_Reg32IS,MOPD_Mem16D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASLORELEASE|CANTHROW,kLtUndef,"stllrh","0,1", 1, 1}, -// MOP_wstllr -- Store-LORelease Register Word -{MOP_wstllr, {MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASLORELEASE|CANTHROW,kLtUndef,"stllr","0,1", 1, 1}, -// MOP_xstllr -- Store-LORelease Register Double word -{MOP_xstllr, {MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASLORELEASE|CANTHROW,kLtUndef,"stllr","0,1", 1, 1}, - -// AARCH64 Store exclusive with/without release semantics -{MOP_wstxrb, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Mem8D, MOPD_Undef,MOPD_Undef},ISSTORE|ISATOMIC|CANTHROW,kLtUndef,"stxrb","0,1,2", 1, 2}, -{MOP_wstxrh, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Mem16D,MOPD_Undef,MOPD_Undef},ISSTORE|ISATOMIC|CANTHROW,kLtUndef,"stxrh","0,1,2", 1, 2}, -{MOP_wstxr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef},ISSTORE|ISATOMIC|CANTHROW,kLtUndef,"stxr","0,1,2", 1, 2}, -{MOP_xstxr, {MOPD_Reg32ID,MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef},ISSTORE|ISATOMIC|CANTHROW,kLtUndef,"stxr","0,1,2", 1, 2}, - -{MOP_wstlxrb,{MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Mem8D, MOPD_Undef,MOPD_Undef},ISSTORE|ISATOMIC|HASRELEASE|CANTHROW,kLtUndef,"stlxrb","0,1,2", 1, 2}, -{MOP_wstlxrh,{MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Mem16D,MOPD_Undef,MOPD_Undef},ISSTORE|ISATOMIC|HASRELEASE|CANTHROW,kLtUndef,"stlxrh","0,1,2", 1, 2}, -{MOP_wstlxr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef},ISSTORE|ISATOMIC|HASRELEASE|CANTHROW,kLtUndef,"stlxr","0,1,2", 1, 2}, -{MOP_xstlxr, {MOPD_Reg32ID,MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef},ISSTORE|ISATOMIC|HASRELEASE|CANTHROW,kLtUndef,"stlxr","0,1,2", 1, 2}, - -{MOP_wstlxp, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Mem64D,MOPD_Undef},ISSTORE|ISSTOREPAIR|ISATOMIC|HASRELEASE|CANTHROW,kLtUndef,"stlxp","0,1,2,3", 1, 3}, -{MOP_xstlxp, {MOPD_Reg32ID,MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef},ISSTORE|ISSTOREPAIR|ISATOMIC|HASRELEASE|CANTHROW,kLtUndef,"stlxp","0,1,2,3", 1, 3}, - -// Atomic add without release -// MOP_wstaddb -{MOP_wstaddb, {MOPD_Reg32IS,MOPD_Mem8D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtUndef,"staddb","0,1", 1, 1}, -// MOP_wstaddh -{MOP_wstaddh, {MOPD_Reg32IS,MOPD_Mem16D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtUndef,"staddh","0,1", 1, 1}, -// MOP_wstadd -{MOP_wstadd, {MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtUndef,"stadd","0,1", 1, 1}, -// MOP_xstadd -{MOP_xstadd, {MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtUndef,"stadd","0,1", 1, 1}, - -// Atomic add with release -// MOP_wstaddlb -{MOP_wstaddlb, {MOPD_Reg32IS,MOPD_Mem8D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"staddlb","0,1", 1, 1}, -// MOP_wstaddlh -{MOP_wstaddlh, {MOPD_Reg32IS,MOPD_Mem16D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"staddlh","0,1", 1, 1}, -// MOP_wstaddl -{MOP_wstaddl, {MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"staddl","0,1", 1, 1}, -// MOP_xstaddl -{MOP_xstaddl, {MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"staddl","0,1", 1, 1}, - -// Atomic bit clear -// MOP_wstclrb -{MOP_wstclrb, {MOPD_Reg32IS,MOPD_Mem8D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtUndef,"stclrb","0,1", 1, 1}, -// MOP_wstclrh -{MOP_wstclrh, {MOPD_Reg32IS,MOPD_Mem16D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtUndef,"stclrh","0,1", 1, 1}, -// MOP_wstclr -{MOP_wstclr, {MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtUndef,"stclr","0,1", 1, 1}, -// MOP_xstclr -{MOP_xstclr, {MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtUndef,"stclr","0,1", 1, 1}, - -// Atomic clr with release -// MOP_wstclrlb -{MOP_wstclrlb, {MOPD_Reg32IS,MOPD_Mem8D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"stclrlb","0,1", 1, 1}, -// MOP_wstclrlh -{MOP_wstclrlh, {MOPD_Reg32IS,MOPD_Mem16D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"stclrlh","0,1", 1, 1}, -// MOP_wstclrl -{MOP_wstclrl, {MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"stclrl","0,1", 1, 1}, -// MOP_xstclrl -{MOP_xstclrl, {MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"stclrl","0,1", 1, 1}, - -// Atomic XOR -// MOP_wsteorb -{MOP_wsteorb, {MOPD_Reg32IS,MOPD_Mem8D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtUndef,"steorb","0,1", 1, 1}, -// MOP_wsteorh -{MOP_wsteorh, {MOPD_Reg32IS,MOPD_Mem16D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtUndef,"steorh","0,1", 1, 1}, -// MOP_wsteor -{MOP_wsteor, {MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtUndef,"steor","0,1", 1, 1}, -// MOP_xsteor -{MOP_xsteor, {MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|CANTHROW,kLtUndef,"steor","0,1", 1, 1}, - -// Atomic eor with release -// MOP_wsteorlb -{MOP_wsteorlb, {MOPD_Reg32IS,MOPD_Mem8D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"steorlb","0,1", 1, 1}, -// MOP_wsteorlh -{MOP_wsteorlh, {MOPD_Reg32IS,MOPD_Mem16D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"steorlh","0,1", 1, 1}, -// MOP_wsteorl -{MOP_wsteorl, {MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"steorl","0,1", 1, 1}, -// MOP_xsteorl -{MOP_xsteorl, {MOPD_Reg64IS,MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE|HASRELEASE|CANTHROW,kLtUndef,"steorl","0,1", 1, 1}, - -// Memory barriers -// MOP_dmb_ishld -{MOP_dmb_ishld, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef}, HASACQUIRE|ISDMB,kLtBranch, "dmb ishld", "", 0, 0}, -// MOP_dmb_ishst -{MOP_dmb_ishst, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef}, HASRELEASE|ISDMB,kLtBranch, "dmb ishst", "", 0, 0}, -// MOP_dmb_ish -{MOP_dmb_ish, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef}, HASACQUIRE|HASRELEASE|ISDMB,kLtBranch, "dmb ish", "", 0, 0}, - -// MOP_clinit -// will be emit to four instructions in a row: -// adrp xd, :got:__classinfo__Ljava_2Futil_2Fconcurrent_2Fatomic_2FAtomicInteger_3B -// ldr xd, [xd,#:got_lo12:__classinfo__Ljava_2Futil_2Fconcurrent_2Fatomic_2FAtomicInteger_3B] -// ldr xd, [xd,#112] -// ldr wzr, [xd] -{MOP_clinit, {MOPD_Reg64ID,MOPD_Literal,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISATOMIC|CANTHROW,kLtLoad1,"intrinsic_clinit","0,1", 1, 1}, - -// will be emit to two instructions in a row: -// adrp xd, _PTR__cinf_Ljava_2Flang_2FSystem_3B -// ldr xd, [xd, #:lo12:_PTR__cinf_Ljava_2Flang_2FSystem_3B] -//MOP_adrp_ldr -{MOP_adrp_ldr, {MOPD_Reg64ID, MOPD_Literal,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISATOMIC|CANTHROW,kLtLoad1,"intrinsic_adrpldr","0,1", 1, 1}, - -// will be emit to two instructions in a row: -// adrp xd, label -// add xd, xd, #:lo12:label -//MOP_adrp_label -{MOP_adrp_label, {MOPD_Reg64ID,MOPD_Imm64,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtAlu,"intrinsic_adrplabel","0,1", 1, 1}, - -// ldr x17, [xs,#112] -// ldr wzr, [x17] -{MOP_clinit_tail, {MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISATOMIC|CANTHROW,kLtLoad1,"intrinsic_clinit_tail","0", 0, 1}, - - -// MOP_tail_call_opt_xbl -- branch without link (call); this is a special definition -{MOP_tail_call_opt_xbl, {MOPD_FuncName,MOPD_LISTS,MOPD_Undef,MOPD_Undef,MOPD_Undef},CANTHROW,kLtBranch,"b","0", 0, 2}, -// MOP_tail_call_opt_xblr -- branch without link (call) to register; this is a special definition -{MOP_tail_call_opt_xblr, {MOPD_Reg64IS,MOPD_LISTS,MOPD_Undef,MOPD_Undef,MOPD_Undef},CANTHROW,kLtBranch,"br","0", 0, 2}, - -// MOP_pseudo_param_def_x, -{MOP_pseudo_param_def_x, {MOPD_Reg64ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"//MOP_pseudo_param_def","0", 1, 0}, - -// MOP_pseudo_param_def_w, -{MOP_pseudo_param_def_w, {MOPD_Reg32ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"//MOP_pseudo_param_def","0", 1, 0}, - -// MOP_pseudo_param_def_d, -{MOP_pseudo_param_def_d, {MOPD_Reg64FD,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"//MOP_pseudo_param_def","0", 1, 0}, - -// MOP_pseudo_param_def_s, -{MOP_pseudo_param_def_s, {MOPD_Reg32FD,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"//MOP_pseudo_param_def","0", 1, 0}, - -// MOP_pseudo_param_store_x, -{MOP_pseudo_param_store_x, {MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"//MOP_pseudo_param_store_x","0", 1, 0}, - -// MOP_pseudo_param_store_w, -{MOP_pseudo_param_store_w, {MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"//MOP_pseudo_param_store_w","0", 1, 0}, - -// MOP_pseudo_ref_init_x, -{MOP_pseudo_ref_init_x, {MOPD_Mem64D,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"//MOP_pseudo_ref_init_x","0", 1, 0}, - -// MOP_pseudo_ret_int, -{MOP_pseudo_ret_int, {MOPD_Reg64IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"//MOP_pseudo_ret_int","", 0, 1}, - -// MOP_pseudo_ret_float, -{MOP_pseudo_ret_float, {MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"//MOP_pseudo_ret_float","", 0, 1}, - -// When exception occurs, R0 and R1 may be defined by runtime code. -// MOP_pseudo_eh_def_x, -{MOP_pseudo_eh_def_x, {MOPD_Reg64ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"//MOP_pseudo_eh_def_x","0", 1, 0}, - -// for comments -// MOP_comment -{MOP_comment, {MOPD_STRING,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"//","0", 0, 0}, -//MOP_nop -{MOP_nop, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtAlu,"nop","", 0, 0}, - - -// A pseudo instruction that used for seperating dependence graph. -// MOP_pseudo_dependence_seperator, -{MOP_pseudo_dependence_seperator, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"//MOP_pseudo_dependence_seperator","0", 0, 0}, - - -// A pseudo instruction that used for replacing MOP_clinit_tail after clinit merge in scheduling. -// MOP_pseudo_none, -{MOP_pseudo_none, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,kLtUndef,"//MOP_pseudo_none","0", 0, 0}, - - -// end of AArch64 instructions - - - - - - - - - - -//// MOP_Tbadcrrr -//{MOP_Tbadcrrr, {MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_RegCCS,MOPD_Undef},0,"adc","0,1,2"}, -//// MOP_Tbaddrri8 -//{MOP_Tbaddrri8, {MOPD_Reg32ID,MOPD_Reg32IS, MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"add","0,1,2"}, -//// MOP_Tbaddrri3s -//{MOP_Tbaddrri3s, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS, MOPD_Imm32,MOPD_Undef},0,"adds","1,2,3"}, -//// MOP_Tbaddri8 -//{MOP_Tbaddri8, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"adds",""}, -//// MOP_Tbaddrrr -//{MOP_Tbaddrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"add","0,1,2"}, -//// MOP_Tbadd64rrrs -//{MOP_Tbadd64rrrs, {MOPD_RegCCD,MOPD_Reg64IDL,MOPD_Reg64ISL,MOPD_Reg64ISL,MOPD_Undef},0,"adds","1,2,3"}, -//{MOP_Tbadd64rris, {MOPD_RegCCD,MOPD_Reg64IDL,MOPD_Reg64ISL,MOPD_Imm12,MOPD_Undef},0,"adds","1,2,3"}, -//// MOP_Tbaddrrlh -//{MOP_Tbaddrrlh, {MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"add",""}, -//// MOP_Tbaddrrhl -//{MOP_Tbaddrrhl, {MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"add",""}, -//// MOP_Tbaddrrhh -//{MOP_Tbaddrrhh, {MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"add",""}, -//// MOP_Tbaddpcrel -//{MOP_Tbaddpcrel, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"add",""}, -//// MOP_Tbaddsprel -//{MOP_Tbaddsprel, {MOPD_Reg32ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"add",""}, -//// MOP_Tbaddspi7 -//{MOP_Tbaddspi7, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"add",""}, -//// MOP_Tbandrr -//{MOP_Tbandrr, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"ands",""}, -//// MOP_Tbasrrri5 -//{MOP_Tbasrrri5, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"asrs",""}, -//// MOP_Tbasrsrrr -//{MOP_Tbasrsrrr, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"asrs","1,2,3"}, -//// MOP_Tbbcond -//{MOP_Tbbcond, {MOPD_RegCCS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"b!1c",""}, -//// MOP_Tbbicrr -//{MOP_Tbbicrr, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"bics",""}, -//// MOP_Tbbkpt -//{MOP_Tbbkpt, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"bkpt",""}, -//// MOP_Tbblx2 -//{MOP_Tbblx2, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"blx_2",""}, -//// MOP_Tbbl1 -//{MOP_Tbbl1, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"bl_1",""}, -//// MOP_Tbbl2 -//{MOP_Tbbl2, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"bl_2",""}, -//// MOP_Tbblxr -//{MOP_Tbblxr, {MOPD_Reg32IS,MOPD_LISTS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"blx","0"}, -//// MOP_Tbbx -//{MOP_Tbbx, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"bx","0"}, -//// MOP_Tbcmnrr -//{MOP_Tbcmnrr, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"cmn",""}, - -//// MOP_Tbcmpri8 TBD:Delete -//{MOP_Tbcmpri8, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Imm32,MOPD_Undef,MOPD_Undef},0,"cmp","1,2"}, -//// MOP_Tbcmprr TBD:Delete -//{MOP_Tbcmprr, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"cmp","1,2"}, -//// MOP_Tbcmplh TBD:Delete -//{MOP_Tbcmplh, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"cmp",""}, -//// MOP_Tbcmphl TBD:Delete -//{MOP_Tbcmphl, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"cmp",""}, -//// MOP_Tbcmphh TBD:Delete -//{MOP_Tbcmphh, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"cmp",""}, -//// MOP_Tbeorrr -//{MOP_Tbeorrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"eors",""}, -//// MOP_Tbldmia -//{MOP_Tbldmia, {MOPD_Reg32IDS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldmia",""}, -//// MOP_Tbldwb -//{MOP_Tbldwb, {MOPD_Reg32ID, MOPD_Reg32ID, MOPD_Mem32S,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","0, 2"}, -//// MOP_Tbld64l -//{MOP_Tbld64l, {MOPD_Reg64IDL,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","0, 1"}, -//// MOP_Tbld64h -//{MOP_Tbld64h, {MOPD_Reg64IDSH,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","0, 1"}, -//// MOP_Tbldrbrri5 -//{MOP_Tbldrbrri5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrb",""}, -//// MOP_Tbldrhrri5 -//{MOP_Tbldrhrri5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrh",""}, - - -//// MOP_Tblslrri5 -//{MOP_Tblslrri5, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"lsls",""}, -//// MOP_Tblslsrrr -//{MOP_Tblslsrrr, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"lsls","1,2,3"}, -//// MOP_Tblsrrri5 -//{MOP_Tblsrrri5, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"lsrs",""}, -//// MOP_Tblsrsrrr -//{MOP_Tblsrsrrr, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"lsrs","1,2,3"}, -//// MOP_Tbmovimm8 -//{MOP_Tbmovimm8, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"movs","1,2"}, -//// MOP_Tbmovrr -//{MOP_Tbmovrr, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISMOVE,"movs",""}, -//// MOP_Tbmovrr_h2h -//{MOP_Tbmovrr_h2h, {MOPD_Reg64IDSH,MOPD_Reg64ISH,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mov","0,1"}, -//// MOP_Tbmovrr_l2l -//{MOP_Tbmovrr_l2l, {MOPD_Reg64IDL,MOPD_Reg64ISL,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mov","0,1"}, -//// MOP_Tbmovrr_l2h -//{MOP_Tbmovrr_l2h, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,"mov",""}, -//// MOP_Tbmov64ri12h -//{MOP_Tbmov64ri12h, {MOPD_Reg64IDSH,MOPD_Imm12,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mov","0,1"}, -//// MOP_Tbmov64ri12l -//{MOP_Tbmov64ri12l, {MOPD_Reg64IDL,MOPD_Imm12,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mov","0,1"}, -//// MOP_Tbmul -//{MOP_Tbmul, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"muls",""}, -//// MOP_Tbmvn -//{MOP_Tbmvn, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"mvns",""}, -//// MOP_Tbmvn64i12l -//{MOP_Tbmvn64i12l, {MOPD_Reg64IDL,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,"mvn","0,1"}, -//// MOP_Tbmvn64i12h -//{MOP_Tbmvn64i12h, {MOPD_Reg64IDSH,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,"mvn","0,1"}, -//// MOP_Tborr -//{MOP_Tborr, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"orrs",""}, -//// MOP_Tbpop -//{MOP_Tbpop, {MOPD_RSPD,MOPD_LISTS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"pop","1"}, -//// MOP_Tbpush -//{MOP_Tbpush, {MOPD_RSPD,MOPD_LISTS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"push","1"}, -//// MOP_Tbrev -//{MOP_Tbrev, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"rev",""}, -//// MOP_Tbrevsh -//{MOP_Tbrevsh, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"rev",""}, -//// MOP_Tbrorrr -//{MOP_Tbrorrr, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"rors",""}, -//// MOP_Tbsbc -//{MOP_Tbsbc, {MOPD_RegCCDS,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"sbcs",""}, -//// MOP_Tbstmia -//{MOP_Tbstmia, {MOPD_Reg32IDS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"stmia",""}, -//// MOP_Tbstr -//{MOP_Tbstr, {MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"str","0,1"}, -//// MOP_Tbstrsprel -//{MOP_Tbstrsprel, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"str",""}, -//// MOP_Tbstrbrri5 -//{MOP_Tbstrbrri5, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strb",""}, -//// MOP_Tbstrhrri5 -//{MOP_Tbstrhrri5, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strh",""}, -//// MOP_Tbsubrri3 -//{MOP_Tbsubrri3, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"subs",""}, -//// MOP_Tbsubri8 -//{MOP_Tbsubri8, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"subs",""}, -//// MOP_Tbsubspi7 -//{MOP_Tbsubspi7, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"sub",""}, -//// MOP_Tbswi -//{MOP_Tbswi, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"swi",""}, -//// MOP_Tbtst -//{MOP_Tbtst, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"tst",""}, -//// MOP_Tb2vldrs -//{MOP_Tb2vldrs, {MOPD_Reg32FD,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"flds","0,1"}, -//// MOP_Tb2vldrd -//{MOP_Tb2vldrd, {MOPD_Reg64FD,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"fldd","0,1"}, -//// MOP_Tb2vmuls TBD:Delete -//{MOP_Tb2vmuls, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,"fmuls","0,1,2"}, -//// MOP_Tb2vmuld TBD:Delete -//{MOP_Tb2vmuld, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"fmuld","0,1,2"}, -//// MOP_Tb2vmlas TBD:Delete -//{MOP_Tb2vmlas, {MOPD_Reg32FDS,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,"vmlas",""}, -//// MOP_Tb2vmlad TBD:Delete -//{MOP_Tb2vmlad, {MOPD_Reg64FDS,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"vmlad",""}, -//// MOP_Tb2vmlss TBL:Delete -//{MOP_Tb2vmlss, {MOPD_Reg32FDS,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,"vmlss",""}, -//// MOP_Tb2vmlsd TBD:Delete -//{MOP_Tb2vmlsd, {MOPD_Reg64FDS,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"vmlsd",""}, -//// MOP_Tb2vstrs TBD:Delete -//{MOP_Tb2vstrs, {MOPD_Reg32FS,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"fsts","0,1"}, -//// MOP_Tb2vstrd TBD:Delete -//{MOP_Tb2vstrd, {MOPD_Reg64FS,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"fstd","0,1"}, -//// MOP_Tb2vsubs TBD:Delete -//{MOP_Tb2vsubs, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,"fsubs","0,1,2"}, -//// MOP_Tb2vsubd TBD:Delete -//{MOP_Tb2vsubd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"fsubd","0,1,2"}, -//// MOP_Tb2vadds TBD:Delete -//{MOP_Tb2vadds, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,"fadds","0,1,2"}, -//// MOP_Tb2vaddd TBD:Delete -//{MOP_Tb2vaddd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"faddd","0,1,2"}, -//// MOP_Tb2vdivs -//{MOP_Tb2vdivs, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,"fdivs","0,1,2"}, -//// MOP_Tb2vdivd -//{MOP_Tb2vdivd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"fdivd","0,1,2"}, -//// MOP_Tb2vmlaf64 -//{MOP_Tb2vmlaf64, {MOPD_Reg64FDS,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"vmla",""}, -//// MOP_Tb2vcvtif -//{MOP_Tb2vcvtif, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"ftosizs","0,1"}, -//// MOP_Tb2vcvtuf -//{MOP_Tb2vcvtuf, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"ftouizs","0,1"}, -//// MOP_Tb2vcvtid -//{MOP_Tb2vcvtid, {MOPD_Reg32FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"ftosizd","0,1"}, -//// MOP_Tb2vcvtud -//{MOP_Tb2vcvtud, {MOPD_Reg32FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"ftouizd","0,1"}, -//// MOP_Tb2vcvtfi -//{MOP_Tb2vcvtfi, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fsitos","0,1"}, -//// MOP_Tb2vcvtfu -//{MOP_Tb2vcvtfu, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fuitos","0,1"}, -//// MOP_Tb2vcvtdi -//{MOP_Tb2vcvtdi, {MOPD_Reg64FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fsitod","0,1"}, -//// MOP_Tb2vcvtdu -//{MOP_Tb2vcvtdu, {MOPD_Reg64FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fuitod","0,1"}, -//// MOP_Tb2vcvtfd TBD:Delete -//{MOP_Tb2vcvtfd, {MOPD_Reg32FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fcvtsd","0,1"}, -//// MOP_Tb2vcvtdf TBD:Delete -//{MOP_Tb2vcvtdf, {MOPD_Reg64FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fcvtds","0,1"}, -//// MOP_Tb2vcvtf64s32 -//{MOP_Tb2vcvtf64s32, {MOPD_Reg64FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"vcvt.f64.s32 ",""}, -//// MOP_Tb2vcvtf64u32 -//{MOP_Tb2vcvtf64u32, {MOPD_Reg64FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"vcvt.f64.u32 ",""}, - -//{MOP_Tb2movimm8, {MOPD_Reg32ID,MOPD_Imm8,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mov","0,1"}, -//// MOP_Tb2movi8m -//{MOP_Tb2movi8m, {MOPD_Reg32ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mov",""}, -//// MOP_Tb2movimm12 -//{MOP_Tb2movimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mov","0,1"}, -//// MOP_Tb2strrri12 -//{MOP_Tb2strrri12, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"str",""}, -//// MOP_Tb2ldrrri12 -//{MOP_Tb2ldrrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr",""}, -//// MOP_Tb2strrri8predec -//{MOP_Tb2strrri8predec, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"str",""}, -//// MOP_Tb2ldrrri8predec -//{MOP_Tb2ldrrri8predec, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr",""}, -//// MOP_Tb2cbz -//{MOP_Tb2cbz, {MOPD_Reg32IS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"cbz","0,1"}, -//// MOP_Tb2addrri12 TBD:Delete -//{MOP_Tb2addrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,"addw","0,1,2"}, -//// MOP_Tb2vmovs -//{MOP_Tb2vmovs, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,"fcpys","0,1"}, -//// MOP_Tb2vmovd -//{MOP_Tb2vmovd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,"fcpyd","0,1"}, -//// MOP_Tb2vmovsc -//{MOP_Tb2vmovsc, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"fcpyseq","0,1"}, -//// MOP_Tb2vmovdc -//{MOP_Tb2vmovdc, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"fcpydeq","0,1"}, -//// MOP_Tb2ldmia -//{MOP_Tb2ldmia, {MOPD_Reg32IDS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldmia",""}, -//// MOP_Tb2stmia -//{MOP_Tb2stmia, {MOPD_Reg32IDS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"stmia",""}, -//// MOP_Tb2addrrr -//{MOP_Tb2addrrr, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"adds","1,2,3"}, -//// MOP_Tb2subrrr -//{MOP_Tb2subrrr, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"subs","1,2,3"}, -//// MOP_Tb2sbcrrr -//{MOP_Tb2sbcrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef},0,"sbc","0,1,2"}, -//// MOP_Tb2cmprr -//{MOP_Tb2cmprr, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"cmp",""}, -//// MOP_Tb2subrri12 -//{MOP_Tb2subrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,"sub","0,1,2"}, -//// MOP_Tb2mvni12 -//{MOP_Tb2mvni12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mvn","0,1"}, -//// MOP_Tb2sel -//{MOP_Tb2sel, {MOPD_RegCCS,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"sel",""}, -//// MOP_Tb2ubfx -//{MOP_Tb2ubfx, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"ubfx",""}, -//// MOP_Tb2sbfx -//{MOP_Tb2sbfx, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"sbfx",""}, -//// MOP_Tb2ldrrrr -//{MOP_Tb2ldrrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr",""}, -//// MOP_Tb2ldrhrrr -//{MOP_Tb2ldrhrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrh",""}, -//// MOP_Tb2ldrsh -//{MOP_Tb2ldrsh, {MOPD_Reg32ID,MOPD_Mem16S, MOPD_Undef, MOPD_Undef,MOPD_Undef},ISLOAD,"ldrsh","0,1"}, -//// MOP_Tb2ldrbrrr -//{MOP_Tb2ldrbrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrb",""}, -//// MOP_Tb2ldrsbrrr -//{MOP_Tb2ldrsbrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrsb",""}, -//// MOP_Tb2strrrr -//{MOP_Tb2strrrr, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISSTORE,"str",""}, -//// MOP_Tb2strh -////{MOP_Tb2strh, {MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strh",""}, -//// MOP_Tb2strb -////{MOP_Tb2strb, {MOPD_Reg32IS,MOPD_Mem32D,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strb","0,1"}, -//// MOP_Tb2ldrhrri12 -//{MOP_Tb2ldrhrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrh",""}, -//// MOP_Tb2ldrshrri12 -//{MOP_Tb2ldrshrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrsh",""}, -//// MOP_Tb2ldrbrri12 -//{MOP_Tb2ldrbrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrb",""}, -//// MOP_Tb2ldrsbrri12 -//{MOP_Tb2ldrsbrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrsb",""}, -//// MOP_Tb2strhrri12 -//{MOP_Tb2strhrri12, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strh",""}, -//// MOP_Tb2strbrri12 -//{MOP_Tb2strbrri12, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strb",""}, -//// MOP_Tb2pop -//{MOP_Tb2pop, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"pop",""}, -//// MOP_Tb2push -//{MOP_Tb2push, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"push",""}, -//// MOP_Tb2cmpri8m -//{MOP_Tb2cmpri8m, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"cmp",""}, -//// MOP_Tb2cmnri8m -//{MOP_Tb2cmnri8m, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"cmn",""}, -//// MOP_Tb2adc64rrr -//{MOP_Tb2adc64rrr, {MOPD_Reg64IDSH,MOPD_Reg64ISH,MOPD_Reg64ISH,MOPD_RegCCD,MOPD_Undef},0,"adc","0,1,2"}, -//// MOP_Tb2adc64rri -//{MOP_Tb2adc64rri, {MOPD_Reg64IDSH,MOPD_Reg64ISH,MOPD_Imm8,MOPD_RegCCD,MOPD_Undef},0,"adc","0,1,2"}, -//// MOP_Tb2orr64lrrr -//{MOP_Tb2orr64lrrr,{MOPD_Reg64ISL,MOPD_Reg64ISL,MOPD_Reg64ISL,MOPD_Undef,MOPD_Undef},0,"orr","0,1,2"}, -//// MOP_Tb2orr64hrrr -//{MOP_Tb2orr64hrrr, {MOPD_Reg64IDSH,MOPD_Reg64ISH,MOPD_Reg64ISH,MOPD_Undef,MOPD_Undef},0,"orr","0,1,2"}, -//// MOP_Tb2and64lrrr -//{MOP_Tb2and64lrrr,{MOPD_Reg64ISL,MOPD_Reg64ISL,MOPD_Reg64ISL,MOPD_Undef,MOPD_Undef},0,"and","0,1,2"}, -//// MOP_Tb2and64hrrr -//{MOP_Tb2and64hrrr, {MOPD_Reg64IDSH,MOPD_Reg64ISH,MOPD_Reg64ISH,MOPD_Undef,MOPD_Undef},0,"and","0,1,2"}, -//// MOP_Tb2bicrrr -//{MOP_Tb2bicrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"bic",""}, -//// MOP_Tb2cmnrr -//{MOP_Tb2cmnrr, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"cmn",""}, -//// MOP_Tb2sdivrrr -//{MOP_Tb2sdivrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"sdiv",""}, -//// MOP_Tb2udivrrr -//{MOP_Tb2udivrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"udiv",""}, -//// MOP_Tb2rsubrri8 -//{MOP_Tb2rsubrri8, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"rsb","0,1,2"}, -//// MOP_Tb2rsubsrri8 -//{MOP_Tb2rsubsrri8, {MOPD_RegCCD, MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef},0,"rsbs","1,2,3"}, -//// MOP_Tb2tstrr -//{MOP_Tb2tstrr, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"tst",""}, -//// MOP_Tb2rorrrr -//{MOP_Tb2rorrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"ror","0,1,2"}, -//// MOP_Tb2rorrri5 -//{MOP_Tb2rorrri5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"ror","0,1,2"}, -//// MOP_Tb2bicrri8m -//{MOP_Tb2bicrri8m, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"bic",""}, -//// MOP_Tbandrri8 -//{MOP_Tbandrri8, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"and","0,1,2"}, -//// MOP_Tbandrri8l -//{MOP_Tbandrri8l, {MOPD_Reg64ISL,MOPD_Reg64ISL,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"and","0,1,2"}, -//// MOP_Tbandrri8h -//{MOP_Tbandrri8h, {MOPD_Reg64ISH,MOPD_Reg64ISH,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"and","0,1,2"}, -//// MOP_Tb2andrri8m -//{MOP_Tb2andrri8m, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"and",""}, -//// MOP_Tborrri8l -//{MOP_Tborrri8l, {MOPD_Reg64ISL,MOPD_Reg64ISL,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"orr","0,1,2"}, -//// MOP_Tborrri8h -//{MOP_Tborrri8h, {MOPD_Reg64ISH,MOPD_Reg64ISH,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"orr","0,1,2"}, -//// MOP_Tborrri8 -//{MOP_Tborrri8, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"orr","0,1,2"}, -//// MOP_Tb2orrrri8m -//{MOP_Tb2orrrri8m, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"orr",""}, -//// MOP_Tb2addrri8m -//{MOP_Tb2addrri8m, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"adds",""}, -//// MOP_Tb2adcrri8m -//{MOP_Tb2adcrri8m, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm12, MOPD_RegCCS,MOPD_Undef},0,"adc","0,1,2"}, -//// MOP_Tb2subsrri8 -//{MOP_Tb2subsrri8, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef},0,"subs","1,2,3"}, -//// MOP_Tb2sbcrri8m -//{MOP_Tb2sbcrri8m, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_RegCCS,MOPD_Undef},0,"sbc","0,1,2"}, -//// MOP_Tb2revrr -//{MOP_Tb2revrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"rev",""}, -//// MOP_Tb2revshrr -//{MOP_Tb2revshrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"revsh",""}, -//// MOP_Tb2it -//{MOP_Tb2it, {MOPD_RegCCS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"it:!1b",""}, -//// MOP_Tb2fmstat -//{MOP_Tb2fmstat, {MOPD_RegCCDS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fmstat",""}, -//// MOP_Tb2vcmpd -//{MOP_Tb2vcmpd, {MOPD_RegCCD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"fcmped","1,2"}, -//// MOP_Tb2vcmps -//{MOP_Tb2vcmps, {MOPD_RegCCD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,"fcmpes","1,2"}, -//// MOP_Tb2ldrpcrel12 -//{MOP_Tb2ldrpcrel12, {MOPD_Reg32ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr",""}, -//// MOP_Tb2bcond -//{MOP_Tb2bcond, {MOPD_RegCCS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"b!1c",""}, -//// MOP_Tb2fmrs -//{MOP_Tb2fmrs, {MOPD_Reg32ID,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fmrs","0,1"}, -//// MOP_Tb2fmsr -//{MOP_Tb2fmsr, {MOPD_Reg32FD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fmsr","0,1"}, -//// MOP_Tb2fmrrd -//{MOP_Tb2fmrrd, {MOPD_Reg32ID,MOPD_Reg32ID,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"fmrrd","0,1,2"}, -//// MOP_Tb2fmdrr -//{MOP_Tb2fmdrr, {MOPD_Reg64FD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"fmdrr","0,1,2"}, -//// MOP_Tb2vabsd -//{MOP_Tb2vabsd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fabsd","0,1"}, -//// MOP_Tb2vabss -//{MOP_Tb2vabss, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fabss","0,1"}, -//// MOP_Tb2vmovs_imm8 -//{MOP_Tb2vmovs_imm8, {MOPD_Reg32FD,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"vmov.f32",""}, -//// MOP_Tb2vmovd_imm8 -//{MOP_Tb2vmovd_imm8, {MOPD_Reg64FD,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"vmov.f64",""}, -//// MOP_Tb2mla -//{MOP_Tb2mla, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"mla","0,1,2,3"}, -//// MOP_Tb2mls -//{MOP_Tb2mls, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"mls",""}, -//// MOP_Tb2umull -//{MOP_Tb2umull, {MOPD_Reg32ID,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"umull","0,1,2,3"}, -//// MOP_Tb2ldrex -//{MOP_Tb2ldrex, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrex",""}, -//// MOP_Tb2ldrexd -//{MOP_Tb2ldrexd, {MOPD_Reg32ID,MOPD_Undef,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrexd",""}, -//// MOP_Tb2strex -//{MOP_Tb2strex, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISSTORE,"strex",""}, -//// MOP_Tb2strexd -//{MOP_Tb2strexd, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},ISSTORE,"strexd",""}, -//// MOP_Tb2clrex -//{MOP_Tb2clrex, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"clrex",""}, -//// MOP_Tb2bfi -//{MOP_Tb2bfi, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"bfi",""}, -//// MOP_Tb2bfc -//{MOP_Tb2bfc, {MOPD_Reg32ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"bfc",""}, -//// MOP_Tb2dmb -//{MOP_Tb2dmb, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"dmb",""}, -//// MOP_Tb2ldrpcreln12 -//{MOP_Tb2ldrpcreln12, {MOPD_Reg32ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr",""}, -//// MOP_Tb2stm -//{MOP_Tb2stm, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"stm",""}, -//// MOP_Tbundefined -//{MOP_Tbundefined, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"undefined",""}, -//// MOP_Tb2vpopcs -//{MOP_Tb2vpopcs, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"vpop",""}, -//// MOP_Tb2vpushcs -//{MOP_Tb2vpushcs, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"vpush",""}, -//// MOP_Tb2vldms -//{MOP_Tb2vldms, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"vldms",""}, -//// MOP_Tb2vstms -//{MOP_Tb2vstms, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"vstms",""}, -//// MOP_Tb2buncond -//{MOP_Tb2buncond, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"b",""}, -//// MOP_Tb2movimm16h -//{MOP_Tb2movimm16h, {MOPD_Reg32IDS,MOPD_Imm16,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"movt","0,1"}, -//// MOP_Tb2movimm16l -//{MOP_Tb2movimm16l, {MOPD_Reg32ID,MOPD_Imm16,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"movw","0,1"}, -//// MOP_Tb2addpcr -//{MOP_Tb2addpcr, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"add",""}, -//// MOP_Tb2adr -//{MOP_Tb2adr, {MOPD_Reg32ID,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"adr","0,1"}, -//// MOP_Tb2movimm16lst TBD:Delete -//{MOP_Tb2movimm16lst, {MOPD_Reg32ID,MOPD_Mem32SL,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"movw","0,1"}, -//// MOP_Tb2movimm16hst TBD:Delete -//{MOP_Tb2movimm16hst, {MOPD_Reg32IDS,MOPD_Mem32SH,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"movt","0,1"}, -//// MOP_Tb2ldmiawb -//{MOP_Tb2ldmiawb, {MOPD_Reg32IDS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldmia",""}, -//// MOP_Tb2orrsrrr -//{MOP_Tb2orrsrrr, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"orrs","1,2,3"}, -//// MOP_Tb2push1 -//{MOP_Tb2push1, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"push1",""}, -//// MOP_Tb2pop1 -//{MOP_Tb2pop1, {MOPD_Reg32ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"pop1",""}, -//// MOP_Tb2rsubrrr -//{MOP_Tb2rsubrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"rsb","0,1,2"}, -//// MOP_Tb2smull -//{MOP_Tb2smull, {MOPD_Reg32ID,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"smull",""}, -//// MOP_Tb2ldrd -//{MOP_Tb2ldrd, {MOPD_Reg64ID,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrd","0,1"}, -//// MOP_Tb2strd -//{MOP_Tb2strd, {MOPD_Reg64IS,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strd","0,1"}, - -//// MOP_Tb2mul64rlh -//{MOP_Tb2mul64rlh, {MOPD_Reg32ID,MOPD_Reg64ISL,MOPD_Reg64ISH,MOPD_Undef, MOPD_Undef},0,"mul","0,1,2"}, -//// MOP_Tb2mla64rhlr -//{MOP_Tb2mla64rhlr, {MOPD_Reg32ID,MOPD_Reg64ISH,MOPD_Reg64ISL,MOPD_Reg32IS, MOPD_Undef},0,"mla","0,1,2,3"}, -//// MOP_Tb2umull64rrll -//{MOP_Tb2umull64rrll, {MOPD_Reg32ID,MOPD_Reg32ID,MOPD_Reg64ISL, MOPD_Reg64ISL,MOPD_Undef},0,"umull","0,1,2,3"}, -//// MOP_Tb2mov64lr -//{MOP_Tb2mov64lr, {MOPD_Reg64IDL,MOPD_Reg32IS, MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"mov","0,1"}, -//// MOP_Tb2add64hrr -//{MOP_Tb2add64hrr, {MOPD_Reg64IDH,MOPD_Reg32IS,MOPD_Reg32IS, MOPD_Undef,MOPD_Undef},0,"add","0,1,2"}, -//// MOP_Tbrsbmiri -//{MOP_Tbrsbmiri, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8, MOPD_RegCCS,MOPD_Undef},0,"rsbmi","0,1,2"}, -//// MOP_Tbitle -//{MOP_Tbitle, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it le",""}, -//// MOP_Tbitls -//{MOP_Tbitls, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it ls",""}, -//// MOP_Tbitlt -//{MOP_Tbitlt, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it lt",""}, -//// MOP_Tbitcc -//{MOP_Tbitcc, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it cc",""}, -//// MOP_Tbitge -//{MOP_Tbitge, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it ge",""}, -//// MOP_Tbitcs -//{MOP_Tbitcs, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it cs",""}, -//// MOP_Tbitgt -//{MOP_Tbitgt, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it gt",""}, -//// MOP_Tbithi -//{MOP_Tbithi, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it hi",""}, -//// MOP_Tbitmi -//{MOP_Tbitmi, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it mi",""}, -//// MOP_Tbiteq -//{MOP_Tbiteq, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it eq",""}, -//// MOP_Tbitne -//{MOP_Tbitne, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it ne",""}, -//// MOP_Tbitpl -//{MOP_Tbitpl, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it pl",""}, -//// MOP_Tbittpl -//{MOP_Tbittpl, {MOPD_RegCCD,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"itt pl",""}, -//// MOP_Tbitele -//{MOP_Tbitele, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite le",""}, -//// MOP_Tbitels -//{MOP_Tbitels, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite ls",""}, -//// MOP_Tbitelt -//{MOP_Tbitelt, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite lt",""}, -//// MOP_Tbitecc -//{MOP_Tbitecc, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite cc",""}, -//// MOP_Tbitege -//{MOP_Tbitege, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite ge",""}, -//// MOP_Tbitecs -//{MOP_Tbitecs, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite cs",""}, -//// MOP_Tbitegt -//{MOP_Tbitegt, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite gt",""}, -//// MOP_Tbitehi -//{MOP_Tbitehi, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite hi",""}, -//// MOP_Tbitemi -//{MOP_Tbitemi, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite mi",""}, -//// MOP_Tbiteeq -//{MOP_Tbiteeq, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite eq",""}, -//// MOP_Tbitene -//{MOP_Tbitene, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite ne",""}, -//// MOP_Tbitepl -//{MOP_Tbitepl, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite pl",""}, -//// MOP_Tb2asrplrrr -//{MOP_Tb2asrplrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_RegCCS,MOPD_Undef},0,"asrpl","0,1,2"}, -//// MOP_Tb2orrplrrr -//{MOP_Tb2orrplrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_RegCCS,MOPD_Undef},0,"orrpl","0,1,2"}, -//// MOP_Tb2moveqimm12 -//{MOP_Tb2moveqimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"moveq","0,1"}, -//// MOP_Tb2movneimm12 -//{MOP_Tb2movneimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movne","0,1"}, -//// MOP_Tb2movleimm12 -//{MOP_Tb2movleimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movle","0,1"}, -//// MOP_Tb2movlsimm12 -//{MOP_Tb2movlsimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movls","0,1"}, -//// MOP_Tb2movltimm12 -//{MOP_Tb2movltimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movlt","0,1"}, -//// MOP_Tb2movccimm12 -//{MOP_Tb2movccimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movcc","0,1"}, -//// MOP_Tb2movgeimm12 -//{MOP_Tb2movgeimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movge","0,1"}, -//// MOP_Tb2movcsimm12 -//{MOP_Tb2movcsimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movcs","0,1"}, -//// MOP_Tb2movgtimm12 -//{MOP_Tb2movgtimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movgt","0,1"}, -//// MOP_Tb2movhiimm12 -//{MOP_Tb2movhiimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movhi","0,1"}, -//// MOP_Tb2movmiimm12 -//{MOP_Tb2movmiimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movmi","0,1"}, -//// MOP_Tb2movplimm12 -//{MOP_Tb2movplimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movpl","0,1"}, -//{MOP_Tb2moveqrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"moveq","0,1"}, -//// MOP_Tb2fconsts -//{MOP_Tb2fconsts, {MOPD_Reg32FD,MOPD_Imm8,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fconsts","0,1"}, -//// MOP_Tb2fconstd -//{MOP_Tb2fconstd, {MOPD_Reg64FD,MOPD_Imm8,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fconstd","0,1"}, - - -//// MOP_Tbxpush AARCH64 PUSH/POP push single 32-bit int -////{MOP_Tbxpush, {MOPD_Reg32IS,MOPD_Mem32SPRE,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"str","0,1"}, -//// MOP_Tbxpushl push single 64-bit int -////{MOP_Tbxpushl, {MOPD_Reg64IS,MOPD_Mem64SPRE,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"str","0,1"}, -//// MOP_Tbxpushf push single 32-bit float -////{MOP_Tbxpushf, {MOPD_Reg32FS,MOPD_Mem32SPRE,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"str","0,1"}, -//// MOP_Tbxpushd push single 64-bit double -////{MOP_Tbxpushd, {MOPD_Reg64FS,MOPD_Mem64SPRE,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"str","0,1"}, -// -//// MOP_Tbxpushp push pair 32-bit ints -////{MOP_Tbxpushp, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Mem32SPRE,MOPD_Undef,MOPD_Undef},ISSTORE,"stp","0,1,2"}, -//// MOP_Tbxpushpl push pair 64-bit ints -////{MOP_Tbxpushpl, {MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Mem64SPRE,MOPD_Undef,MOPD_Undef},ISSTORE,"stp","0,1,2"}, -//// MOP_Tbxpushpf push pair 32-bit floats -////{MOP_Tbxpushpf, {MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Mem32SPRE,MOPD_Undef,MOPD_Undef},ISSTORE,"stp","0,1,2"}, -//// MOP_Tbxpushpd push pair 64-bit double -////{MOP_Tbxpushpd, {MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Mem64SPRE,MOPD_Undef,MOPD_Undef},ISSTORE,"stp","0,1,2"}, -// -//// MOP_Tbxpop pop single 32-bit int -////{MOP_Tbxpop, {MOPD_Reg32IS,MOPD_Mem32SPOST,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","0,1"}, -//// MOP_Tbxpopl pop single 64-bit int -////{MOP_Tbxpopl, {MOPD_Reg64IS,MOPD_Mem64SPOST,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","0,1"}, -//// MOP_Tbxpopf pop single 32-bit float -////{MOP_Tbxpopf, {MOPD_Reg32FS,MOPD_Mem32SPOST,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","0,1"}, -//// MOP_Tbxpopd pop single 64-bit double -////{MOP_Tbxpopd, {MOPD_Reg64FS,MOPD_Mem64SPOST,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","0,1"}, -// -//// MOP_Tbxpopp pop pair 32-bit ints -////{MOP_Tbxpopp, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Mem32SPOST,MOPD_Undef,MOPD_Undef},ISLOAD,"ldp","0,1,2"}, -//// MOP_Tbxpoppl pop pair 64-bit ints -////{MOP_Tbxpoppl, {MOPD_Reg64IS,MOPD_Reg64IS,MOPD_Mem64SPOST,MOPD_Undef,MOPD_Undef},ISLOAD,"ldp","0,1,2"}, -//// MOP_Tbxpoppf pop pair 32-bit floats -////{MOP_Tbxpoppf, {MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Mem32SPOST,MOPD_Undef,MOPD_Undef},ISLOAD,"ldp","0,1,2"}, -//// MOP_Tbxpoppd pop pair 64-bit double -////{MOP_Tbxpoppd, {MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Mem64SPOST,MOPD_Undef,MOPD_Undef},ISLOAD,"ldp","0,1,2"}, - - -////// MOP_wldrmemli -////{MOP_wldrmemli, {MOPD_Reg32ID,MOPD_Mem32LiteralS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","0,1"}, -//// MOP_xldrmemli -////{MOP_xldrmemli, {MOPD_Reg64ID,MOPD_Mem64LiteralS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","0,1"}, - -// MOP_wstrmemli -//{MOP_wstrmemli, {MOPD_Reg32IS,MOPD_Mem32LiteralS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"str","0,1"}, -// MOP_xstrmemli -////{MOP_xstrmemli, {MOPD_Reg64IS,MOPD_Mem64LiteralS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"str","0,1"}, - diff --git a/mapleall/maple_be/src/cg/aarch64/aarch64_mem_layout.cpp b/mapleall/maple_be/src/cg/aarch64/aarch64_mem_layout.cpp index edf4b45..d432dc3 100644 --- a/mapleall/maple_be/src/cg/aarch64/aarch64_mem_layout.cpp +++ b/mapleall/maple_be/src/cg/aarch64/aarch64_mem_layout.cpp @@ -216,6 +216,10 @@ void AArch64MemLayout::LayoutStackFrame(int32 &structCopySize, int32 &maxParmSta // We need it as dictated by the AArch64 ABI $5.4.2 C12 seg__args_stkpassed.size = RoundUp(seg__args_stkpassed.size, SIZEOFPTR); } + if (cgfunc->cg->cgopt_.WithDwarf() && !nostackpara) { + // for O0 + cgfunc->AddDIESymbolLocation(sym, symloc); + } } // We do need this as LDR/STR with immediate @@ -275,6 +279,11 @@ void AArch64MemLayout::LayoutStackFrame(int32 &structCopySize, int32 &maxParmSta seg_locals.size += be.type_size_table[tyIdx.GetIdx()]; } } + + if (cgfunc->cg->cgopt_.WithDwarf()) { + // for O0 + cgfunc->AddDIESymbolLocation(sym, symloc); + } } // handle ret_ref sym now @@ -292,6 +301,11 @@ void AArch64MemLayout::LayoutStackFrame(int32 &structCopySize, int32 &maxParmSta seg_reflocals.size = RoundUp(seg_reflocals.size, be.type_align_table[tyIdx.GetIdx()]); symloc->offset = seg_reflocals.size; seg_reflocals.size += be.type_size_table[tyIdx.GetIdx()]; + + if (cgfunc->cg->cgopt_.WithDwarf()) { + // for O0 + cgfunc->AddDIESymbolLocation(sym, symloc); + } } seg__args_to_stkpass.size = FindLargestActualArea(structCopySize); diff --git a/mapleall/maple_be/src/cg/aarch64/aarch64_operand.cpp b/mapleall/maple_be/src/cg/aarch64/aarch64_operand.cpp index 9c2ccdb..25df643 100644 --- a/mapleall/maple_be/src/cg/aarch64/aarch64_operand.cpp +++ b/mapleall/maple_be/src/cg/aarch64/aarch64_operand.cpp @@ -241,7 +241,7 @@ void AArch64MemOperand::Emit(Emitter &emitter, OpndProp *prop) { CG_ASSERT(offset, ""); emitter.Emit(", #:lo12:"); - if (GetSymbol()->storageClass == kScPstatic) { + if (GetSymbol()->storageClass == kScPstatic && GetSymbol()->IsLocal()) { emitter.Emit(GetSymbolName() + to_string(CG::curPuIdx)); } else { emitter.Emit(GetSymbolName()); @@ -295,7 +295,7 @@ void AArch64MemOperand::dump() { LogInfo::MapleLogger() << "offset:"; AArch64OfstOperand *offopnd = GetOffsetImmediate(); LogInfo::MapleLogger() << "#:lo12:"; - if (GetSymbol()->storageClass == kScPstatic) { + if (GetSymbol()->storageClass == kScPstatic && GetSymbol()->IsLocal()) { LogInfo::MapleLogger() << GetSymbolName() << to_string(CG::curPuIdx); } else { LogInfo::MapleLogger() << GetSymbolName(); diff --git a/mapleall/maple_be/src/cg/aarch64/aarch64_optimize_common.cpp b/mapleall/maple_be/src/cg/aarch64/aarch64_optimize_common.cpp index dde473f..79b994a 100644 --- a/mapleall/maple_be/src/cg/aarch64/aarch64_optimize_common.cpp +++ b/mapleall/maple_be/src/cg/aarch64/aarch64_optimize_common.cpp @@ -17,6 +17,7 @@ #include "aarch64_isa.h" #include "aarch64_cg_func.h" #include "cg_bb.h" +#include "dbg.h" namespace maplebe { @@ -172,6 +173,9 @@ Insn *AArch64InsnVisitor::CloneInsn(Insn *originalInsn) { newInsn->opnds[i] = originalInsn->opnds[i]; } return newInsn; + } else if (dynamic_cast(originalInsn)) { + mpldbg::DbgInsn *tobeCloned = static_cast(originalInsn); + return mp->Clone(*tobeCloned); } else if (dynamic_cast(originalInsn)) { cfi::CfiInsn *tobeCloned = static_cast(originalInsn); return mp->Clone(*tobeCloned); diff --git a/mapleall/maple_be/src/cg/aarch64/aarch64_ra_opt.cpp b/mapleall/maple_be/src/cg/aarch64/aarch64_ra_opt.cpp index a1e95e1..28213f3 100644 --- a/mapleall/maple_be/src/cg/aarch64/aarch64_ra_opt.cpp +++ b/mapleall/maple_be/src/cg/aarch64/aarch64_ra_opt.cpp @@ -122,6 +122,9 @@ bool RaX0Opt::PropagateX0Optimize(const BB *bb, const Insn *insn, X0OptInfo &opt break; } } + if (redefined) { + break; + } // Look for move where src is the register equivalent to x0. if (ninsn->GetMachineOpcode() != MOP_xmovrr && ninsn->GetMachineOpcode() != MOP_wmovrr) { @@ -131,9 +134,6 @@ bool RaX0Opt::PropagateX0Optimize(const BB *bb, const Insn *insn, X0OptInfo &opt Operand *src = ninsn->GetOperand(1); RegOperand *srcreg = static_cast(src); if (srcreg->GetRegisterNumber() != optVal.GetReplaceReg()) { - if (redefined) { - break; - } continue; } diff --git a/mapleall/maple_be/src/cg/aarch64/aarch64_reg_alloc.cpp b/mapleall/maple_be/src/cg/aarch64/aarch64_reg_alloc.cpp index dd56035..ee8ef11 100644 --- a/mapleall/maple_be/src/cg/aarch64/aarch64_reg_alloc.cpp +++ b/mapleall/maple_be/src/cg/aarch64/aarch64_reg_alloc.cpp @@ -989,7 +989,7 @@ regno_t O1RegAllocator::DoRegisterSpill(RegOperand *regopnd, Insn *insn, bool is //= Linear Scan RA //================== -#define LSRA_DEBUG +#undef LSRA_DEBUG #ifdef LSRA_DEBUG #define LSRA_DUMP CGDEBUGFUNC(cgfunc_) @@ -4443,25 +4443,29 @@ bool LSRALinearScanRegAllocator::AllocateRegisters() { } AnalysisResult *CgDoRegAlloc::Run(CGFunc *cgfunc, CgFuncResultMgr *m) { - MemPool *phaseMp = mempoolctrler.NewMemPool("CG phase-wise pool"); - MapleAllocator phaseAllocator(phaseMp); - // It doesn't need live range information when -O1, because the register will not live out of bb. - if (g->optim_level >= 2) { - if (CGOptions::doLiveAnalysisEh) { - LiveAnalysis *live = static_cast(m->GetAnalysisResult(CgFuncPhase_LIVEEH, cgfunc)); - } else { - LiveAnalysis *live = static_cast(m->GetAnalysisResult(CgFuncPhase_LIVE, cgfunc)); - } - } - RegAllocator *regallocator = cgfunc->NewRegAllocator(cgfunc, phaseMp, &phaseAllocator); - CHECK_FATAL(regallocator != nullptr, "regallocator is null in CgDoRegAlloc::Run"); - m->GetAnalysisResult(CgFuncPhase_LOOP, cgfunc); - cgfunc->SetIsAfterRegAlloc(); - regallocator->AllocateRegisters(); - // the live range info may changed, so invalid the info. - m->InvalidAnalysisResult(CgFuncPhase_LIVE, cgfunc); - m->InvalidAnalysisResult(CgFuncPhase_LOOP, cgfunc); - mempoolctrler.DeleteMemPool(phaseMp); + bool success = false; + while (success == false) { + MemPool *phaseMp = mempoolctrler.NewMemPool("CG phase-wise pool"); + MapleAllocator phaseAllocator(phaseMp); + // It doesn't need live range information when -O1, because the register will not live out of bb. + if (g->optim_level >= 2) { + if (CGOptions::doLiveAnalysisEh) { + LiveAnalysis *live = static_cast(m->GetAnalysisResult(CgFuncPhase_LIVEEH, cgfunc)); + } else { + LiveAnalysis *live = static_cast(m->GetAnalysisResult(CgFuncPhase_LIVE, cgfunc)); + } + } + RegAllocator *regallocator = cgfunc->NewRegAllocator(cgfunc, phaseMp, &phaseAllocator); + CHECK_FATAL(regallocator != nullptr, "regallocator is null in CgDoRegAlloc::Run"); + m->GetAnalysisResult(CgFuncPhase_LOOP, cgfunc); + cgfunc->SetIsAfterRegAlloc(); + success = regallocator->AllocateRegisters(); + // the live range info may changed, so invalid the info. + m->InvalidAnalysisResult(CgFuncPhase_LIVEEH, cgfunc); + m->InvalidAnalysisResult(CgFuncPhase_LIVE, cgfunc); + m->InvalidAnalysisResult(CgFuncPhase_LOOP, cgfunc); + mempoolctrler.DeleteMemPool(phaseMp); + } return nullptr; } diff --git a/mapleall/maple_be/src/cg/ark/ark_emit.cpp b/mapleall/maple_be/src/cg/ark/ark_emit.cpp index 6bbb43c..93f62d6 100644 --- a/mapleall/maple_be/src/cg/ark/ark_emit.cpp +++ b/mapleall/maple_be/src/cg/ark/ark_emit.cpp @@ -191,6 +191,8 @@ void ArkCGFunc::Emit() { emitter.Emit("\t.hidden\t").Emit(funcSt->GetName()).Emit("\n"); } else if (funcSt->GetFunction()->GetAttr(FUNCATTR_local)) { emitter.Emit("\t.local\t").Emit(funcSt->GetName()).Emit("\n"); + } else if (funcSt->value.mirFunc && funcSt->value.mirFunc->classTyIdx == 0 && funcSt->value.mirFunc->IsStatic()) { + // nothing } else { emitter.Emit("\t.globl\t").Emit(funcSt->GetName()).Emit("\n"); emitter.Emit("\t.hidden\t").Emit(funcSt->GetName()).Emit("\n"); diff --git a/mapleall/maple_be/src/cg/ark/ark_mem_layout.cpp b/mapleall/maple_be/src/cg/ark/ark_mem_layout.cpp index 3b8c4fb..3f682bc 100644 --- a/mapleall/maple_be/src/cg/ark/ark_mem_layout.cpp +++ b/mapleall/maple_be/src/cg/ark/ark_mem_layout.cpp @@ -118,6 +118,12 @@ void ArkMemLayout::LayoutStackFrame(int32 &structCopySize, int32 &maxParmStackSi seg__args_stkpassed.size += be.type_size_table[ptyIdx]; // We need it as dictated by the AArch64 ABI $5.4.2 C12 seg__args_stkpassed.size = RoundUp(seg__args_stkpassed.size, SIZEOFPTR); + if (cgfunc->cg->cgopt_.WithDwarf() && !nostackpara) { + // for O0 + // LogInfo::MapleLogger() << "Add DIE for formal parameters" << endl + // << " and remember them" << endl; + cgfunc->AddDIESymbolLocation(sym, symloc); + } } // We do need this as LDR/STR with immediate @@ -168,6 +174,13 @@ void ArkMemLayout::LayoutStackFrame(int32 &structCopySize, int32 &maxParmStackSi seg_locals.size += be.type_size_table[tyIdx.GetIdx()]; } } + + if (cgfunc->cg->cgopt_.WithDwarf()) { + // for O0 + // LogInfo::MapleLogger() << "Add DIE for formal parameters" << endl + // << " and remember them" << endl; + cgfunc->AddDIESymbolLocation(sym, symloc); + } } // handle ret_ref sym now @@ -185,6 +198,13 @@ void ArkMemLayout::LayoutStackFrame(int32 &structCopySize, int32 &maxParmStackSi seg_reflocals.size = RoundUp(seg_reflocals.size, be.type_align_table[tyIdx.GetIdx()]); symloc->offset = seg_reflocals.size; seg_reflocals.size += be.type_size_table[tyIdx.GetIdx()]; + + if (cgfunc->cg->cgopt_.WithDwarf()) { + // for O0 + // LogInfo::MapleLogger() << "Add DIE for formal parameters" << endl + // << " and remember them" << endl; + cgfunc->AddDIESymbolLocation(sym, symloc); + } } ASSERT(0, "ArkMemLayout LayoutStackFrame need to handle new parameter"); diff --git a/mapleall/maple_be/src/cg/ark/ark_mir_emit.cpp b/mapleall/maple_be/src/cg/ark/ark_mir_emit.cpp index de795ca..be2da39 100644 --- a/mapleall/maple_be/src/cg/ark/ark_mir_emit.cpp +++ b/mapleall/maple_be/src/cg/ark/ark_mir_emit.cpp @@ -906,7 +906,7 @@ int MirGenerator::MaxEvalStack(MIRFunction *func) { } else { DreadNode *dread = static_cast(node->Opnd(0)); MIRSymbol *s = GetCurFunction()->GetLocalOrGlobalSymbol(dread->stIdx); - ASSERT(s->storageClass != kScFormal, "Parameters of calls of MCC_IncRef_NaiveRCFast between CLEANUP_LOCALREFVARS and Return should not be formals"); + //ToDo: s could be a formal curFunc.cleanupLocalVarsInc.insert(s); } } @@ -1048,6 +1048,8 @@ void MirGenerator::EmitAsmFormalArgInfo(MIRFunction *func) { if (arg->sKind != kStPreg) { if(curFunc.cleanupFormalVars.find(arg) != curFunc.cleanupFormalVars.end()) cleanupFlag = 1; + else + cleanupFlag = 2; } os << hex << ", 0x" << cleanupFlag << "\t// "; @@ -1240,8 +1242,8 @@ void MirGenerator::EmitAsmCall(CallNode *fstmt) { IntrinDesc *intrinDesc = &IntrinDesc::intrintable[intrn]; MIRType *retTyp = intrinDesc->GetReturnType(); - if (retTyp->primType != PTY_void && - pType != retTyp->primType && + if (retTyp->primType != PTY_void && + pType != retTyp->primType && IsAddress(pType) != IsAddress(retTyp->primType)) { fprintf(stderr, "Warning: Intrinsic Call ID %d return type is %d in IR but %d in def\n", intrn, pType, retTyp->primType); } diff --git a/mapleall/maple_be/src/cg/arm/arm_md.def b/mapleall/maple_be/src/cg/arm/arm_md.def deleted file mode 100644 index 9fd14d6..0000000 --- a/mapleall/maple_be/src/cg/arm/arm_md.def +++ /dev/null @@ -1,626 +0,0 @@ -/* - * Copyright (c) [2020] Huawei Technologies Co., Ltd. All rights reserved. - * - * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. - * You can use this software according to the terms and conditions of the MulanPSL - 2.0. - * You may obtain a copy of MulanPSL - 2.0 at: - * - * https://opensource.org/licenses/MulanPSL-2.0 - * - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR - * FIT FOR A PARTICULAR PURPOSE. - * See the MulanPSL - 2.0 for more details. - */ - -// MOP_undef, -{MOP_undef, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"",""}, -// MOP_Tbadcrrr -{MOP_Tbadcrrr, {MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_RegCCS,MOPD_Undef},0,"adc","0,1,2"}, -// MOP_Tbaddrri8 -{MOP_Tbaddrri8, {MOPD_Reg32ID,MOPD_Reg32IS, MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"add","0,1,2"}, -// MOP_Tbaddrri3s -{MOP_Tbaddrri3s, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS, MOPD_Imm32,MOPD_Undef},0,"adds","1,2,3"}, -// MOP_Tbaddri8 -{MOP_Tbaddri8, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"adds",""}, -// MOP_Tbaddrrr -{MOP_Tbaddrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"add","0,1,2"}, -// MOP_Tbadd64rrrs -{MOP_Tbadd64rrrs, {MOPD_RegCCD,MOPD_Reg64IDL,MOPD_Reg64ISL,MOPD_Reg64ISL,MOPD_Undef},0,"adds","1,2,3"}, -{MOP_Tbadd64rris, {MOPD_RegCCD,MOPD_Reg64IDL,MOPD_Reg64ISL,MOPD_Imm12,MOPD_Undef},0,"adds","1,2,3"}, -// MOP_Tbaddrrlh -{MOP_Tbaddrrlh, {MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"add",""}, -// MOP_Tbaddrrhl -{MOP_Tbaddrrhl, {MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"add",""}, -// MOP_Tbaddrrhh -{MOP_Tbaddrrhh, {MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"add",""}, -// MOP_Tbaddpcrel -{MOP_Tbaddpcrel, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"add",""}, -// MOP_Tbaddsprel -{MOP_Tbaddsprel, {MOPD_Reg32ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"add",""}, -// MOP_Tbaddspi7 -{MOP_Tbaddspi7, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"add",""}, -// MOP_Tbandrr -{MOP_Tbandrr, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"ands",""}, -// MOP_Tbasrrri5 -{MOP_Tbasrrri5, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"asrs",""}, -// MOP_Tbasrsrrr -{MOP_Tbasrsrrr, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"asrs","1,2,3"}, -// MOP_Tbbcond -{MOP_Tbbcond, {MOPD_RegCCS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"b!1c",""}, -// MOP_Tbbuncond -{MOP_Tbbuncond, {MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"b","0"}, -// MOP_Tbbicrr -{MOP_Tbbicrr, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"bics",""}, -// MOP_Tbbkpt -{MOP_Tbbkpt, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"bkpt",""}, -// MOP_Tbbl -{MOP_Tbbl, {MOPD_Mem32S,MOPD_LISTS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISCALL,"bl","0"}, -// MOP_Tbblx2 -{MOP_Tbblx2, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"blx_2",""}, -// MOP_Tbbl1 -{MOP_Tbbl1, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"bl_1",""}, -// MOP_Tbbl2 -{MOP_Tbbl2, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"bl_2",""}, -// MOP_Tbblxr -{MOP_Tbblxr, {MOPD_Reg32IS,MOPD_LISTS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"blx","0"}, -// MOP_Tbbx -{MOP_Tbbx, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"bx","0"}, -// MOP_Tbcmnrr -{MOP_Tbcmnrr, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"cmn",""}, -// MOP_Tbcmpri8 -{MOP_Tbcmpri8, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Imm32,MOPD_Undef,MOPD_Undef},0,"cmp","1,2"}, -// MOP_Tbcmprr -{MOP_Tbcmprr, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"cmp","1,2"}, -// MOP_Tbcmplh -{MOP_Tbcmplh, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"cmp",""}, -// MOP_Tbcmphl -{MOP_Tbcmphl, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"cmp",""}, -// MOP_Tbcmphh -{MOP_Tbcmphh, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"cmp",""}, -// MOP_Tbeorrr -{MOP_Tbeorrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"eors",""}, -// MOP_Tbldmia -{MOP_Tbldmia, {MOPD_Reg32IDS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldmia",""}, -// MOP_Tbld -{MOP_Tbld, {MOPD_Reg32ID,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","0, 1"}, -// MOP_Tbldwb -{MOP_Tbldwb, {MOPD_Reg32ID, MOPD_Reg32ID, MOPD_Mem32S,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","0, 2"}, -// MOP_Tbld64l -{MOP_Tbld64l, {MOPD_Reg64IDL,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","0, 1"}, -// MOP_Tbld64h -{MOP_Tbld64h, {MOPD_Reg64IDSH,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr","0, 1"}, -// MOP_Tbldrbrri5 -{MOP_Tbldrbrri5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrb",""}, -// MOP_Tbldrb -{MOP_Tbldrb, {MOPD_Reg32ID,MOPD_Mem8S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrb","0,1"}, -// MOP_Tbldrhrri5 -{MOP_Tbldrhrri5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrh",""}, -// MOP_Tbldrh -{MOP_Tbldrh, {MOPD_Reg32ID, MOPD_Mem16S, MOPD_Undef, MOPD_Undef,MOPD_Undef},ISLOAD,"ldrh","0,1"}, -// MOP_Tbldrsb -{MOP_Tbldrsb, {MOPD_Reg32ID,MOPD_Mem8S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrsb","0,1"}, -// MOP_Tbldrsh -{MOP_Tbldrsh, {MOPD_Reg32ID,MOPD_Mem16S,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrsh","0,1"}, -// MOP_Tblslrri5 -{MOP_Tblslrri5, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"lsls",""}, -// MOP_Tblslsrrr -{MOP_Tblslsrrr, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"lsls","1,2,3"}, -// MOP_Tblsrrri5 -{MOP_Tblsrrri5, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"lsrs",""}, -// MOP_Tblsrsrrr -{MOP_Tblsrsrrr, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"lsrs","1,2,3"}, -// MOP_Tbmovimm8 -{MOP_Tbmovimm8, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"movs","1,2"}, -// MOP_Tbmovrr -{MOP_Tbmovrr, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISMOVE,"movs",""}, -// MOP_Tbmovrr_h2h -{MOP_Tbmovrr_h2h, {MOPD_Reg64IDSH,MOPD_Reg64ISH,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mov","0,1"}, -// MOP_Tbmovrr_l2l -{MOP_Tbmovrr_l2l, {MOPD_Reg64IDL,MOPD_Reg64ISL,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mov","0,1"}, -// MOP_Tbmovrr_l2h -{MOP_Tbmovrr_l2h, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,"mov",""}, -// MOP_Tbmov64ri12h -{MOP_Tbmov64ri12h, {MOPD_Reg64IDSH,MOPD_Imm12,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mov","0,1"}, -// MOP_Tbmov64ri12l -{MOP_Tbmov64ri12l, {MOPD_Reg64IDL,MOPD_Imm12,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mov","0,1"}, -// MOP_Tbmul -{MOP_Tbmul, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"muls",""}, -// MOP_Tbmvn -{MOP_Tbmvn, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"mvns",""}, -// MOP_Tbmvn64i12l -{MOP_Tbmvn64i12l, {MOPD_Reg64IDL,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,"mvn","0,1"}, -// MOP_Tbmvn64i12h -{MOP_Tbmvn64i12h, {MOPD_Reg64IDSH,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,"mvn","0,1"}, -// MOP_Tbneg -{MOP_Tbneg, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"negs",""}, -// MOP_Tborr -{MOP_Tborr, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"orrs",""}, -// MOP_Tbpop -{MOP_Tbpop, {MOPD_RSPD,MOPD_LISTS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"pop","1"}, -// MOP_Tbpush -{MOP_Tbpush, {MOPD_RSPD,MOPD_LISTS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"push","1"}, -// MOP_Tbrev -{MOP_Tbrev, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"rev",""}, -// MOP_Tbrevsh -{MOP_Tbrevsh, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"rev",""}, -// MOP_Tbrorrr -{MOP_Tbrorrr, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"rors",""}, -// MOP_Tbsbc -{MOP_Tbsbc, {MOPD_RegCCDS,MOPD_Reg32IDS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"sbcs",""}, -// MOP_Tbstmia -{MOP_Tbstmia, {MOPD_Reg32IDS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"stmia",""}, -// MOP_Tbstr -{MOP_Tbstr, {MOPD_Reg32IS,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"str","0,1"}, -// MOP_Tbstrsprel -{MOP_Tbstrsprel, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"str",""}, -// MOP_Tbstrbrri5 -{MOP_Tbstrbrri5, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strb",""}, -// MOP_Tbstrb -{MOP_Tbstrb, {MOPD_Reg32IS,MOPD_Mem8S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strb","0,1"}, -// MOP_Tbstrhrri5 -{MOP_Tbstrhrri5, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strh",""}, -// MOP_Tbstrh -{MOP_Tbstrh, {MOPD_Reg32IS,MOPD_Mem16S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strh","0,1"}, -// MOP_Tbsubrri3 -{MOP_Tbsubrri3, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"subs",""}, -// MOP_Tbsubri8 -{MOP_Tbsubri8, {MOPD_RegCCD,MOPD_Reg32IDS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"subs",""}, -// MOP_Tbsubrrr -{MOP_Tbsubrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"sub","0,1,2"}, -// MOP_Tbsubspi7 -{MOP_Tbsubspi7, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"sub",""}, -// MOP_Tbswi -{MOP_Tbswi, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"swi",""}, -// MOP_Tbtst -{MOP_Tbtst, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"tst",""}, -// MOP_Tb2vldrs -{MOP_Tb2vldrs, {MOPD_Reg32FD,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"flds","0,1"}, -// MOP_Tb2vldrd -{MOP_Tb2vldrd, {MOPD_Reg64FD,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"fldd","0,1"}, -// MOP_Tb2vmuls -{MOP_Tb2vmuls, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,"fmuls","0,1,2"}, -// MOP_Tb2vmuld -{MOP_Tb2vmuld, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"fmuld","0,1,2"}, -// MOP_Tb2vmlas -{MOP_Tb2vmlas, {MOPD_Reg32FDS,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,"vmlas",""}, -// MOP_Tb2vmlad -{MOP_Tb2vmlad, {MOPD_Reg64FDS,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"vmlad",""}, -// MOP_Tb2vmlss -{MOP_Tb2vmlss, {MOPD_Reg32FDS,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,"vmlss",""}, -// MOP_Tb2vmlsd -{MOP_Tb2vmlsd, {MOPD_Reg64FDS,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"vmlsd",""}, -// MOP_Tb2vstrs -{MOP_Tb2vstrs, {MOPD_Reg32FS,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"fsts","0,1"}, -// MOP_Tb2vstrd -{MOP_Tb2vstrd, {MOPD_Reg64FS,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"fstd","0,1"}, -// MOP_Tb2vsubs -{MOP_Tb2vsubs, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,"fsubs","0,1,2"}, -// MOP_Tb2vsubd -{MOP_Tb2vsubd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"fsubd","0,1,2"}, -// MOP_Tb2vadds -{MOP_Tb2vadds, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,"fadds","0,1,2"}, -// MOP_Tb2vaddd -{MOP_Tb2vaddd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"faddd","0,1,2"}, -// MOP_Tb2vdivs -{MOP_Tb2vdivs, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,"fdivs","0,1,2"}, -// MOP_Tb2vdivd -{MOP_Tb2vdivd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"fdivd","0,1,2"}, -// MOP_Tb2vmlaf64 -{MOP_Tb2vmlaf64, {MOPD_Reg64FDS,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"vmla",""}, -// MOP_Tb2vcvtif -{MOP_Tb2vcvtif, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"ftosizs","0,1"}, -// MOP_Tb2vcvtuf -{MOP_Tb2vcvtuf, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"ftouizs","0,1"}, -// MOP_Tb2vcvtid -{MOP_Tb2vcvtid, {MOPD_Reg32FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"ftosizd","0,1"}, -// MOP_Tb2vcvtud -{MOP_Tb2vcvtud, {MOPD_Reg32FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"ftouizd","0,1"}, -// MOP_Tb2vcvtfi -{MOP_Tb2vcvtfi, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fsitos","0,1"}, -// MOP_Tb2vcvtfu -{MOP_Tb2vcvtfu, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fuitos","0,1"}, -// MOP_Tb2vcvtdi -{MOP_Tb2vcvtdi, {MOPD_Reg64FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fsitod","0,1"}, -// MOP_Tb2vcvtdu -{MOP_Tb2vcvtdu, {MOPD_Reg64FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fuitod","0,1"}, -// MOP_Tb2vcvtfd -{MOP_Tb2vcvtfd, {MOPD_Reg32FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fcvtsd","0,1"}, -// MOP_Tb2vcvtdf -{MOP_Tb2vcvtdf, {MOPD_Reg64FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fcvtds","0,1"}, -// MOP_Tb2vcvtf64s32 -{MOP_Tb2vcvtf64s32, {MOPD_Reg64FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"vcvt.f64.s32 ",""}, -// MOP_Tb2vcvtf64u32 -{MOP_Tb2vcvtf64u32, {MOPD_Reg64FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"vcvt.f64.u32 ",""}, -// MOP_Tb2vsqrts -{MOP_Tb2vsqrts, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fsqrts","0,1"}, -// MOP_Tb2vsqrtd -{MOP_Tb2vsqrtd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fsqrtd","0,1"}, -{MOP_Tb2movimm8, {MOPD_Reg32ID,MOPD_Imm8,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mov","0,1"}, -// MOP_Tb2movi8m -{MOP_Tb2movi8m, {MOPD_Reg32ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mov",""}, -// MOP_Tb2movimm12 -{MOP_Tb2movimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mov","0,1"}, -// MOP_Tb2strrri12 -{MOP_Tb2strrri12, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"str",""}, -// MOP_Tb2ldrrri12 -{MOP_Tb2ldrrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr",""}, -// MOP_Tb2strrri8predec -{MOP_Tb2strrri8predec, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"str",""}, -// MOP_Tb2ldrrri8predec -{MOP_Tb2ldrrri8predec, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr",""}, -// MOP_Tb2cbnz -{MOP_Tb2cbnz, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"cbnz",""}, -// MOP_Tb2cbz -{MOP_Tb2cbz, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"cbz",""}, -// MOP_Tb2addrri12 -{MOP_Tb2addrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,"addw","0,1,2"}, -// MOP_Tb2movrr -{MOP_Tb2movrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,"mov","0,1"}, -// MOP_Tb2vmovs -{MOP_Tb2vmovs, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,"fcpys","0,1"}, -// MOP_Tb2vmovd -{MOP_Tb2vmovd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISMOVE,"fcpyd","0,1"}, -// MOP_Tb2vmovsc -{MOP_Tb2vmovsc, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"fcpyseq","0,1"}, -// MOP_Tb2vmovdc -{MOP_Tb2vmovdc, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"fcpydeq","0,1"}, -// MOP_Tb2ldmia -{MOP_Tb2ldmia, {MOPD_Reg32IDS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldmia",""}, -// MOP_Tb2stmia -{MOP_Tb2stmia, {MOPD_Reg32IDS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"stmia",""}, -// MOP_Tb2addrrr -{MOP_Tb2addrrr, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"adds","1,2,3"}, -// MOP_Tb2subrrr -{MOP_Tb2subrrr, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"subs","1,2,3"}, -// MOP_Tb2sbcrrr -{MOP_Tb2sbcrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef},0,"sbc","0,1,2"}, -// MOP_Tb2cmprr -{MOP_Tb2cmprr, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"cmp",""}, -// MOP_Tb2subrri12 -{MOP_Tb2subrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm12,MOPD_Undef,MOPD_Undef},0,"sub","0,1,2"}, -// MOP_Tb2mvni12 -{MOP_Tb2mvni12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mvn","0,1"}, -// MOP_Tb2sel -{MOP_Tb2sel, {MOPD_RegCCS,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"sel",""}, -// MOP_Tb2ubfx -{MOP_Tb2ubfx, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"ubfx",""}, -// MOP_Tb2sbfx -{MOP_Tb2sbfx, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"sbfx",""}, -// MOP_Tb2ldrrrr -{MOP_Tb2ldrrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr",""}, -// MOP_Tb2ldrhrrr -{MOP_Tb2ldrhrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrh",""}, -// MOP_Tb2ldrsh -{MOP_Tb2ldrsh, {MOPD_Reg32ID,MOPD_Mem16S, MOPD_Undef, MOPD_Undef,MOPD_Undef},ISLOAD,"ldrsh","0,1"}, -// MOP_Tb2ldrbrrr -{MOP_Tb2ldrbrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrb",""}, -// MOP_Tb2ldrsbrrr -{MOP_Tb2ldrsbrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrsb",""}, -// MOP_Tb2strrrr -{MOP_Tb2strrrr, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISSTORE,"str",""}, -// MOP_Tb2strh -{MOP_Tb2strh, {MOPD_Reg32IS,MOPD_Mem16S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strh",""}, -// MOP_Tb2strb -{MOP_Tb2strb, {MOPD_Reg32IS,MOPD_Mem8S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strb","0,1"}, -// MOP_Tb2ldrhrri12 -{MOP_Tb2ldrhrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrh",""}, -// MOP_Tb2ldrshrri12 -{MOP_Tb2ldrshrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrsh",""}, -// MOP_Tb2ldrbrri12 -{MOP_Tb2ldrbrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrb",""}, -// MOP_Tb2ldrsbrri12 -{MOP_Tb2ldrsbrri12, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrsb",""}, -// MOP_Tb2strhrri12 -{MOP_Tb2strhrri12, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strh",""}, -// MOP_Tb2strbrri12 -{MOP_Tb2strbrri12, {MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strb",""}, -// MOP_Tb2pop -{MOP_Tb2pop, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"pop",""}, -// MOP_Tb2push -{MOP_Tb2push, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"push",""}, -// MOP_Tb2cmpri8m -{MOP_Tb2cmpri8m, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"cmp",""}, -// MOP_Tb2cmnri8m -{MOP_Tb2cmnri8m, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"cmn",""}, -// MOP_Tb2adc64rrr -{MOP_Tb2adc64rrr, {MOPD_Reg64IDSH,MOPD_Reg64ISH,MOPD_Reg64ISH,MOPD_RegCCD,MOPD_Undef},0,"adc","0,1,2"}, -// MOP_Tb2adc64rri -{MOP_Tb2adc64rri, {MOPD_Reg64IDSH,MOPD_Reg64ISH,MOPD_Imm8,MOPD_RegCCD,MOPD_Undef},0,"adc","0,1,2"}, -// MOP_Tb2orr64lrrr -{MOP_Tb2orr64lrrr,{MOPD_Reg64ISL,MOPD_Reg64ISL,MOPD_Reg64ISL,MOPD_Undef,MOPD_Undef},0,"orr","0,1,2"}, -// MOP_Tb2orr64hrrr -{MOP_Tb2orr64hrrr, {MOPD_Reg64IDSH,MOPD_Reg64ISH,MOPD_Reg64ISH,MOPD_Undef,MOPD_Undef},0,"orr","0,1,2"}, -// MOP_Tb2and64lrrr -{MOP_Tb2and64lrrr,{MOPD_Reg64ISL,MOPD_Reg64ISL,MOPD_Reg64ISL,MOPD_Undef,MOPD_Undef},0,"and","0,1,2"}, -// MOP_Tb2and64hrrr -{MOP_Tb2and64hrrr, {MOPD_Reg64IDSH,MOPD_Reg64ISH,MOPD_Reg64ISH,MOPD_Undef,MOPD_Undef},0,"and","0,1,2"}, -// MOP_Tb2andrrr -{MOP_Tb2andrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"and","0,1,2"}, -// MOP_Tb2bicrrr -{MOP_Tb2bicrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"bic",""}, -// MOP_Tb2cmnrr -{MOP_Tb2cmnrr, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"cmn",""}, -// MOP_Tb2eorrrr -{MOP_Tb2eorrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"eor","0,1,2"}, -// MOP_Tb2mulrrr -{MOP_Tb2mulrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"mul","0,1,2"}, -// MOP_Tb2sdivrrr -{MOP_Tb2sdivrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"sdiv",""}, -// MOP_Tb2udivrrr -{MOP_Tb2udivrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"udiv",""}, -// MOP_Tb2mnvrr -{MOP_Tb2mnvrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"mvn","0,1"}, -// MOP_Tb2rsubrri8 -{MOP_Tb2rsubrri8, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"rsb","0,1,2"}, -// MOP_Tb2rsubsrri8 -{MOP_Tb2rsubsrri8, {MOPD_RegCCD, MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef},0,"rsbs","1,2,3"}, -// MOP_Tb2negrr -{MOP_Tb2negrr, {MOPD_Reg32ID,MOPD_Reg32IS, MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"neg","0,1"}, -// MOP_Tb2orrrrr -{MOP_Tb2orrrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"orr","0,1,2"}, -// MOP_Tb2tstrr -{MOP_Tb2tstrr, {MOPD_RegCCD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"tst",""}, -// MOP_Tb2lslrrr -{MOP_Tb2lslrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"lsl","0,1,2"}, -// MOP_Tb2lsrrrr -{MOP_Tb2lsrrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"lsr","0,1,2"}, -// MOP_Tb2asrrrr -{MOP_Tb2asrrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"asr","0,1,2"}, -// MOP_Tb2rorrrr -{MOP_Tb2rorrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"ror","0,1,2"}, -// MOP_Tb2lslrri5 -{MOP_Tb2lslrri5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"lsl","0,1,2"}, -// MOP_Tb2lsrrri5 -{MOP_Tb2lsrrri5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"lsr","0,1,2"}, -// MOP_Tb2asrrri5 -{MOP_Tb2asrrri5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"asr","0,1,2"}, -// MOP_Tb2rorrri5 -{MOP_Tb2rorrri5, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"ror","0,1,2"}, -// MOP_Tb2bicrri8m -{MOP_Tb2bicrri8m, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"bic",""}, -// MOP_Tbandrri8 -{MOP_Tbandrri8, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"and","0,1,2"}, -// MOP_Tbandrri8l -{MOP_Tbandrri8l, {MOPD_Reg64ISL,MOPD_Reg64ISL,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"and","0,1,2"}, -// MOP_Tbandrri8h -{MOP_Tbandrri8h, {MOPD_Reg64ISH,MOPD_Reg64ISH,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"and","0,1,2"}, -// MOP_Tb2andrri8m -{MOP_Tb2andrri8m, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"and",""}, -// MOP_Tborrri8l -{MOP_Tborrri8l, {MOPD_Reg64ISL,MOPD_Reg64ISL,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"orr","0,1,2"}, -// MOP_Tborrri8h -{MOP_Tborrri8h, {MOPD_Reg64ISH,MOPD_Reg64ISH,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"orr","0,1,2"}, -// MOP_Tborrri8 -{MOP_Tborrri8, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"orr","0,1,2"}, -// MOP_Tb2orrrri8m -{MOP_Tb2orrrri8m, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"orr",""}, -// MOP_Tb2eorrri8m -{MOP_Tb2eorrri8m, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef,MOPD_Undef},0,"eor","0,1,2"}, -// MOP_Tb2addrri8m -{MOP_Tb2addrri8m, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"adds",""}, -// MOP_Tb2adcrri8m -{MOP_Tb2adcrri8m, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm12, MOPD_RegCCS,MOPD_Undef},0,"adc","0,1,2"}, -// MOP_Tb2subsrri8 -{MOP_Tb2subsrri8, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_Undef},0,"subs","1,2,3"}, -// MOP_Tb2sbcrri8m -{MOP_Tb2sbcrri8m, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8,MOPD_RegCCS,MOPD_Undef},0,"sbc","0,1,2"}, -// MOP_Tb2revrr -{MOP_Tb2revrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"rev",""}, -// MOP_Tb2revshrr -{MOP_Tb2revshrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"revsh",""}, -// MOP_Tb2it -{MOP_Tb2it, {MOPD_RegCCS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"it:!1b",""}, -// MOP_Tb2fmstat -{MOP_Tb2fmstat, {MOPD_RegCCDS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fmstat",""}, -// MOP_Tb2vcmpd -{MOP_Tb2vcmpd, {MOPD_RegCCD,MOPD_Reg64FS,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"fcmped","1,2"}, -// MOP_Tb2vcmps -{MOP_Tb2vcmps, {MOPD_RegCCD,MOPD_Reg32FS,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef},0,"fcmpes","1,2"}, -// MOP_Tb2ldrpcrel12 -{MOP_Tb2ldrpcrel12, {MOPD_Reg32ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr",""}, -// MOP_Tb2bcond -{MOP_Tb2bcond, {MOPD_RegCCS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"b!1c",""}, -// MOP_Tb2fmrs -{MOP_Tb2fmrs, {MOPD_Reg32ID,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fmrs","0,1"}, -// MOP_Tb2fmsr -{MOP_Tb2fmsr, {MOPD_Reg32FD,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fmsr","0,1"}, -// MOP_Tb2fmrrd -{MOP_Tb2fmrrd, {MOPD_Reg32ID,MOPD_Reg32ID,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef},0,"fmrrd","0,1,2"}, -// MOP_Tb2fmdrr -{MOP_Tb2fmdrr, {MOPD_Reg64FD,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"fmdrr","0,1,2"}, -// MOP_Tb2vabsd -{MOP_Tb2vabsd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fabsd","0,1"}, -// MOP_Tb2vabss -{MOP_Tb2vabss, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fabss","0,1"}, -// MOP_Tb2vnegd -{MOP_Tb2vnegd, {MOPD_Reg64FD,MOPD_Reg64FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fnegd","0,1"}, -// MOP_Tb2vnegs -{MOP_Tb2vnegs, {MOPD_Reg32FD,MOPD_Reg32FS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fnegs","0,1"}, -// MOP_Tb2vmovs_imm8 -{MOP_Tb2vmovs_imm8, {MOPD_Reg32FD,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"vmov.f32",""}, -// MOP_Tb2vmovd_imm8 -{MOP_Tb2vmovd_imm8, {MOPD_Reg64FD,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"vmov.f64",""}, -// MOP_Tb2mla -{MOP_Tb2mla, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"mla","0,1,2,3"}, -// MOP_Tb2mls -{MOP_Tb2mls, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"mls",""}, -// MOP_Tb2umull -{MOP_Tb2umull, {MOPD_Reg32ID,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"umull","0,1,2,3"}, -// MOP_Tb2ldrex -{MOP_Tb2ldrex, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrex",""}, -// MOP_Tb2ldrexd -{MOP_Tb2ldrexd, {MOPD_Reg32ID,MOPD_Undef,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrexd",""}, -// MOP_Tb2strex -{MOP_Tb2strex, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},ISSTORE,"strex",""}, -// MOP_Tb2strexd -{MOP_Tb2strexd, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},ISSTORE,"strexd",""}, -// MOP_Tb2clrex -{MOP_Tb2clrex, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"clrex",""}, -// MOP_Tb2bfi -{MOP_Tb2bfi, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"bfi",""}, -// MOP_Tb2bfc -{MOP_Tb2bfc, {MOPD_Reg32ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"bfc",""}, -// MOP_Tb2dmb -{MOP_Tb2dmb, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"dmb",""}, -// MOP_Tb2ldrpcreln12 -{MOP_Tb2ldrpcreln12, {MOPD_Reg32ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldr",""}, -// MOP_Tb2stm -{MOP_Tb2stm, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"stm",""}, -// MOP_Tbundefined -{MOP_Tbundefined, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"undefined",""}, -// MOP_Tb2vpopcs -{MOP_Tb2vpopcs, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"vpop",""}, -// MOP_Tb2vpushcs -{MOP_Tb2vpushcs, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"vpush",""}, -// MOP_Tb2vldms -{MOP_Tb2vldms, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"vldms",""}, -// MOP_Tb2vstms -{MOP_Tb2vstms, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"vstms",""}, -// MOP_Tb2buncond -{MOP_Tb2buncond, {MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"b",""}, -// MOP_Tb2movimm16h -{MOP_Tb2movimm16h, {MOPD_Reg32IDS,MOPD_Imm16,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"movt","0,1"}, -// MOP_Tb2movimm16l -{MOP_Tb2movimm16l, {MOPD_Reg32ID,MOPD_Imm16,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"movw","0,1"}, -// MOP_Tb2addpcr -{MOP_Tb2addpcr, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"add",""}, -// MOP_Tb2adr -{MOP_Tb2adr, {MOPD_Reg32ID,MOPD_Mem32S,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"adr","0,1"}, -// MOP_Tb2movimm16lst -{MOP_Tb2movimm16lst, {MOPD_Reg32ID,MOPD_Mem32SL,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"movw","0,1"}, -// MOP_Tb2movimm16hst -{MOP_Tb2movimm16hst, {MOPD_Reg32IDS,MOPD_Mem32SH,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"movt","0,1"}, -// MOP_Tb2ldmiawb -{MOP_Tb2ldmiawb, {MOPD_Reg32IDS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldmia",""}, -// MOP_Tb2orrsrrr -{MOP_Tb2orrsrrr, {MOPD_RegCCD,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"orrs","1,2,3"}, -// MOP_Tb2push1 -{MOP_Tb2push1, {MOPD_Reg32IS,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"push1",""}, -// MOP_Tb2pop1 -{MOP_Tb2pop1, {MOPD_Reg32ID,MOPD_Undef,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"pop1",""}, -// MOP_Tb2rsubrrr -{MOP_Tb2rsubrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef,MOPD_Undef},0,"rsb","0,1,2"}, -// MOP_Tb2smull -{MOP_Tb2smull, {MOPD_Reg32ID,MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_Undef},0,"smull",""}, -// MOP_Tb2ldrd -{MOP_Tb2ldrd, {MOPD_Reg64ID,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISLOAD,"ldrd","0,1"}, -// MOP_Tb2strd -{MOP_Tb2strd, {MOPD_Reg64IS,MOPD_Mem64S,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISSTORE,"strd","0,1"}, -// MOP_beq -{MOP_beq, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"beq","1"}, -// MOP_bne -{MOP_bne, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"bne","1"}, -// MOP_blt -{MOP_blt, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"blt","1"}, -// MOP_ble -{MOP_ble, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"ble","1"}, -// MOP_bgt -{MOP_bgt, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"bgt","1"}, -// MOP_bge -{MOP_bge, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"bge","1"}, -// MOP_blo equal to MOP_blt for unsigned comparison -{MOP_blo, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"blo","1"}, -// MOP_bls equal to MOP_bls for unsigned comparison -{MOP_bls, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"bls","1"}, -// MOP_bhs equal to MOP_bge for unsigned comparison -{MOP_bhs, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"bhs","1"}, -// MOP_bhi equal to MOP_bgt for float comparison -{MOP_bhi, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"bhi","1"}, -// MOP_bpl equal to MOP_bge for float comparison -{MOP_bpl, {MOPD_RegCCS,MOPD_Label,MOPD_Undef,MOPD_Undef,MOPD_Undef},ISBRANCH,"bpl","1"}, -// MOP_Tb2mul64rlh -{MOP_Tb2mul64rlh, {MOPD_Reg32ID,MOPD_Reg64ISL,MOPD_Reg64ISH,MOPD_Undef, MOPD_Undef},0,"mul","0,1,2"}, -// MOP_Tb2mla64rhlr -{MOP_Tb2mla64rhlr, {MOPD_Reg32ID,MOPD_Reg64ISH,MOPD_Reg64ISL,MOPD_Reg32IS, MOPD_Undef},0,"mla","0,1,2,3"}, -// MOP_Tb2umull64rrll -{MOP_Tb2umull64rrll, {MOPD_Reg32ID,MOPD_Reg32ID,MOPD_Reg64ISL, MOPD_Reg64ISL,MOPD_Undef},0,"umull","0,1,2,3"}, -// MOP_Tb2mov64lr -{MOP_Tb2mov64lr, {MOPD_Reg64IDL,MOPD_Reg32IS, MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"mov","0,1"}, -// MOP_Tb2add64hrr -{MOP_Tb2add64hrr, {MOPD_Reg64IDH,MOPD_Reg32IS,MOPD_Reg32IS, MOPD_Undef,MOPD_Undef},0,"add","0,1,2"}, -// MOP_Tbrsbmiri -{MOP_Tbrsbmiri, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Imm8, MOPD_RegCCS,MOPD_Undef},0,"rsbmi","0,1,2"}, -// MOP_Tbitle -{MOP_Tbitle, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it le",""}, -// MOP_Tbitls -{MOP_Tbitls, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it ls",""}, -// MOP_Tbitlt -{MOP_Tbitlt, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it lt",""}, -// MOP_Tbitcc -{MOP_Tbitcc, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it cc",""}, -// MOP_Tbitge -{MOP_Tbitge, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it ge",""}, -// MOP_Tbitcs -{MOP_Tbitcs, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it cs",""}, -// MOP_Tbitgt -{MOP_Tbitgt, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it gt",""}, -// MOP_Tbithi -{MOP_Tbithi, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it hi",""}, -// MOP_Tbitmi -{MOP_Tbitmi, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it mi",""}, -// MOP_Tbiteq -{MOP_Tbiteq, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it eq",""}, -// MOP_Tbitne -{MOP_Tbitne, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it ne",""}, -// MOP_Tbitpl -{MOP_Tbitpl, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"it pl",""}, -// MOP_Tbittpl -{MOP_Tbittpl, {MOPD_RegCCD,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"itt pl",""}, -// MOP_Tbitele -{MOP_Tbitele, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite le",""}, -// MOP_Tbitels -{MOP_Tbitels, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite ls",""}, -// MOP_Tbitelt -{MOP_Tbitelt, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite lt",""}, -// MOP_Tbitecc -{MOP_Tbitecc, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite cc",""}, -// MOP_Tbitege -{MOP_Tbitege, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite ge",""}, -// MOP_Tbitecs -{MOP_Tbitecs, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite cs",""}, -// MOP_Tbitegt -{MOP_Tbitegt, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite gt",""}, -// MOP_Tbitehi -{MOP_Tbitehi, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite hi",""}, -// MOP_Tbitemi -{MOP_Tbitemi, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite mi",""}, -// MOP_Tbiteeq -{MOP_Tbiteeq, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite eq",""}, -// MOP_Tbitene -{MOP_Tbitene, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite ne",""}, -// MOP_Tbitepl -{MOP_Tbitepl, {MOPD_Undef,MOPD_Undef,MOPD_Undef, MOPD_Undef,MOPD_Undef},0,"ite pl",""}, -// MOP_Tb2asrplrrr -{MOP_Tb2asrplrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_RegCCS,MOPD_Undef},0,"asrpl","0,1,2"}, -// MOP_Tb2orrplrrr -{MOP_Tb2orrplrrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_Reg32IS,MOPD_RegCCS,MOPD_Undef},0,"orrpl","0,1,2"}, -// MOP_Tb2moveqimm12 -{MOP_Tb2moveqimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"moveq","0,1"}, -// MOP_Tb2movneimm12 -{MOP_Tb2movneimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movne","0,1"}, -// MOP_Tb2movleimm12 -{MOP_Tb2movleimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movle","0,1"}, -// MOP_Tb2movlsimm12 -{MOP_Tb2movlsimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movls","0,1"}, -// MOP_Tb2movltimm12 -{MOP_Tb2movltimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movlt","0,1"}, -// MOP_Tb2movccimm12 -{MOP_Tb2movccimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movcc","0,1"}, -// MOP_Tb2movgeimm12 -{MOP_Tb2movgeimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movge","0,1"}, -// MOP_Tb2movcsimm12 -{MOP_Tb2movcsimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movcs","0,1"}, -// MOP_Tb2movgtimm12 -{MOP_Tb2movgtimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movgt","0,1"}, -// MOP_Tb2movhiimm12 -{MOP_Tb2movhiimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movhi","0,1"}, -// MOP_Tb2movmiimm12 -{MOP_Tb2movmiimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movmi","0,1"}, -// MOP_Tb2movplimm12 -{MOP_Tb2movplimm12, {MOPD_Reg32ID,MOPD_Imm12,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"movpl","0,1"}, -{MOP_Tb2moveqrr, {MOPD_Reg32ID,MOPD_Reg32IS,MOPD_RegCCS,MOPD_Undef,MOPD_Undef},0,"moveq","0,1"}, -// MOP_Tb2fconsts -{MOP_Tb2fconsts, {MOPD_Reg32FD,MOPD_Imm8,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fconsts","0,1"}, -// MOP_Tb2fconstd -{MOP_Tb2fconstd, {MOPD_Reg64FD,MOPD_Imm8,MOPD_Undef,MOPD_Undef,MOPD_Undef},0,"fconstd","0,1"}, diff --git a/mapleall/maple_be/src/cg/cfg_optimizer.cpp b/mapleall/maple_be/src/cg/cfg_optimizer.cpp index 2a648f1..0b4f345 100644 --- a/mapleall/maple_be/src/cg/cfg_optimizer.cpp +++ b/mapleall/maple_be/src/cg/cfg_optimizer.cpp @@ -19,6 +19,9 @@ #if TARGAARCH64 #include "aarch64_insn.h" #include "aarch64_operand.h" +#elif TARGRISCV64 +#include "riscv64_insn.h" +#include "riscv64_operand.h" #endif #include "cg_assert.h" #include @@ -67,7 +70,7 @@ bool ChainingPattern::NoInsnBetween(BB *from, BB *to) { // return true if insns in bb1 and bb2 are the same except the last goto insn. bool ChainingPattern::DoSameThing(BB *bb1, Insn *last1, BB *bb2, Insn *last2) { -#if TARGAARCH64 +#if TARGAARCH64 || TARGRISCV64 Insn *insn1 = bb1->firstinsn; Insn *insn2 = bb2->firstinsn; while (insn1 && insn1 != last1->next && insn2 && insn2 != last2->next) { @@ -84,6 +87,8 @@ bool ChainingPattern::DoSameThing(BB *bb1, Insn *last1, BB *bb2, Insn *last2) { } #if TARGAARCH64 for (int i = 0; i < AArch64Insn::kMaxOperandNum; i++) { +#elif TARGRISCV64 + for (int i = 0; i < Riscv64Insn::kMaxOperandNum; i++) { #endif Operand *op1 = insn1->GetOperand(i); Operand *op2 = insn2->GetOperand(i); @@ -110,7 +115,7 @@ bool ChainingPattern::DoSameThing(BB *bb1, Insn *last1, BB *bb2, Insn *last2) { // 2. unnecessary jumps elimination // 3. Remove duplicates Basic block. bool ChainingPattern::Optimize(BB *&curbb) { -#if TARGAARCH64 +#if TARGAARCH64 || TARGRISCV64 if (curbb->GetKind() == BB::kBBFallthru) { /*BB2 can be merged into BB1, if * 1. BB1's kind is fallthrough; diff --git a/mapleall/maple_be/src/cg/cg.cpp b/mapleall/maple_be/src/cg/cg.cpp index 48a3ec2..26441e7 100644 --- a/mapleall/maple_be/src/cg/cg.cpp +++ b/mapleall/maple_be/src/cg/cg.cpp @@ -442,4 +442,9 @@ vector CG::GetReferenceOffsets64(BECommon &beCommon, MIRStructType *str return result; } +void CG::AddLabelDieToLabelIdxMapping(DBGDie *lbldie, LabelIdx lblidx) { + CG_ASSERT(emitter_, ""); + emitter_->AddLabelDieToLabelIdxMapping(lbldie, lblidx); +} + } // namespace maplebe diff --git a/mapleall/maple_be/src/cg/cg_bb.cpp b/mapleall/maple_be/src/cg/cg_bb.cpp index f0fb81e..c09fb10 100644 --- a/mapleall/maple_be/src/cg/cg_bb.cpp +++ b/mapleall/maple_be/src/cg/cg_bb.cpp @@ -14,6 +14,7 @@ */ #include "cg_bb.h" +#include "dbg.h" #include namespace maplebe { diff --git a/mapleall/maple_be/src/cg/cg_cfg.cpp b/mapleall/maple_be/src/cg/cg_cfg.cpp index 8d3352f..5c4f720 100644 --- a/mapleall/maple_be/src/cg/cg_cfg.cpp +++ b/mapleall/maple_be/src/cg/cg_cfg.cpp @@ -18,6 +18,9 @@ #if TARGAARCH64 #include "aarch64/aarch64_insn.h" #include "aarch64/aarch64_operand.h" +#elif TARGRISCV64 +#include "riscv64/riscv64_insn.h" +#include "riscv64/riscv64_operand.h" #endif #include "cg_option.h" #include "securec.h" @@ -37,8 +40,6 @@ void CGCFG::BuildCFG() { BB::BBKind k = curbb->kind; switch (k) { case BB::kBBIntrinsic: - // An intrinsic BB append a MOP_wcbnz instruction at the end, check - // AArch64CGFunc::SelectIntrinCall(IntrinsiccallNode *intrinsiccallnode) for details if (!curbb->lastinsn->IsBranch()) { break; } @@ -911,10 +912,6 @@ Insn *CGCFG::FindLastCondBrInsn(BB *bb) { return nullptr; } -bool CGCFG::SyncRegs(Insn *lastMemAccessInsn, Insn *csel) { - return insnVisitor->SyncRegs(lastMemAccessInsn, csel); -} - /** * Find out if the data is manipulated between memory or register. * Return 0 for empty bb, 1 for register, 2 for memory, 3 for neither. @@ -959,7 +956,7 @@ RegOperand *CGCFG::CheckSrcForDef(BB *bb, Insn *insn) { #if !TARGARK // "movk" only modify some bits of the source register, the other bits will not changed. // Can not do optimization on these cases. - if (insn->mop_ == MOP_wmovkri16 || insn->mop_ == MOP_xmovkri16) { + if (insn->IsPartDef()) { return nullptr; } #endif @@ -1069,7 +1066,7 @@ bool CGCFG::CheckCondMoveBB(BB *bb, map &destSrcMap, vecto } bool CGCFG::IsSetInsn(Insn *insn, Operand *&dest, Operand *&src) { -#if TARGAARCH64 +#if TARGAARCH64 || TARGRISCV64 MOperator mopcode = insn->mop_; if (mopcode >= MOP_xmovrr && mopcode <= MOP_xvmovd) { dest = insn->GetOperand(0); diff --git a/mapleall/maple_be/src/cg/cg_driver.cpp b/mapleall/maple_be/src/cg/cg_driver.cpp index be151e1..e358e08 100644 --- a/mapleall/maple_be/src/cg/cg_driver.cpp +++ b/mapleall/maple_be/src/cg/cg_driver.cpp @@ -22,6 +22,8 @@ #include "arm_cg.h" #elif TARGAARCH64 #include "aarch64_cg.h" +#elif TARGRISCV64 +#include "riscv64_cg.h" #elif TARGARK #include "ark_mir_emit.h" #include "ark_cg.h" @@ -129,6 +131,9 @@ int main(int argc, char **argv) { #elif TARGAARCH64 AArch64CG thecg(themodule, cgoption, cgoption.run_cg_flag, output.c_str(), ehExclusiveFunctionName, CGOptions::cyclePatternMap); +#elif TARGRISCV64 + Riscv64CG thecg(themodule, cgoption, cgoption.run_cg_flag, output.c_str(), ehExclusiveFunctionName, + CGOptions::cyclePatternMap); #elif TARGARK ArkCG thecg(themodule, cgoption, cgoption.run_cg_flag, output.c_str(), ehExclusiveFunctionName, CGOptions::cyclePatternMap); @@ -197,6 +202,9 @@ int main(int argc, char **argv) { themodule->profile.DeCompress(CGOptions::classMetaProFile, javaName); #endif + if (cgoption.WithDwarf()) { + thecg.emitter_->EmitDIHeader(); + } // 3. generate phase pipeline based on function. unsigned long rangeNum = 0; if (!CGOptions::quiet) { @@ -242,6 +250,9 @@ int main(int argc, char **argv) { MapleAllocator funcscopeAllocator(funcMp); // 4, Create CGFunc CGFunc *cgfunc = thecg.CreateCGFunc(themodule, mirFunc, becommon, funcMp, &funcscopeAllocator); + if (cgoption.WithDwarf()) { + cgfunc->SetDebugInfo(themodule->dbgInfo); + } CG::curCgFunc = cgfunc; CG::curPuIdx = cgfunc->mirModule.CurFunction()->puIdx; // 5. Run the cg optimizations phases. @@ -261,7 +272,11 @@ int main(int argc, char **argv) { CGOptions::inRange = false; } -#if TARGAARCH64 + if (cgoption.WithDwarf()) { + thecg.emitter_->EmitDIFooter(); + } + +#if TARGAARCH64 || TARGRISCV64 // Emit duplicated asm func to delete plt call if (!cgoption.duplicateAsmFile.empty()) { if (JAVALANG) { @@ -303,6 +318,17 @@ int main(int argc, char **argv) { thecg.emitter_->EmitGxxPersonalityV0(); thecg.emitter_->EmitInitArraySection(); } + // 10. emit debug infomation. + if (cgoption.WithDwarf()) { + thecg.emitter_->SetupDBGInfo(themodule->dbgInfo); + thecg.emitter_->EmitDIHeaderFileInfo(); + thecg.emitter_->EmitDIDebugInfoSection(themodule->dbgInfo); + thecg.emitter_->EmitDIDebugAbbrevSection(themodule->dbgInfo); + thecg.emitter_->EmitDIDebugARangesSection(); + thecg.emitter_->EmitDIDebugRangesSection(); + thecg.emitter_->EmitDIDebugLineSection(); + thecg.emitter_->EmitDIDebugStrSection(); + } thecg.emitter_->CloseOutput(); } else { cerr << "Skipped generating .s because -no-cg is given" << endl; diff --git a/mapleall/maple_be/src/cg/cg_func.cpp b/mapleall/maple_be/src/cg/cg_func.cpp index 8b79759..3b47d0f 100644 --- a/mapleall/maple_be/src/cg/cg_func.cpp +++ b/mapleall/maple_be/src/cg/cg_func.cpp @@ -17,13 +17,18 @@ #include "cg.h" #if TARGAARCH64 #include "aarch64/aarch64_cg.h" +#elif TARGRISCV64 +#include "riscv64/riscv64_cg.h" #endif #include "insn.h" #include "reg_alloc.h" #if TARGAARCH64 #include "aarch64_insn.h" +#elif TARGRISCV64 +#include "riscv64_insn.h" #endif #include "mir_builder.h" +#include "debug_info.h" #include "name_mangler.h" #include "cg_cfg.h" #include "cg_assert.h" @@ -89,6 +94,9 @@ CGFunc::CGFunc(MIRModule *mod, CG *c, MIRFunction *f, BECommon *bec, MemPool *mp hasTakenLabel(false), hasAlloca(false), frequency(0), + dbginfo(nullptr), + dbg_callframe_locations(mallocator->Adapter()), + dbg_callframe_offset(0), rd(nullptr), sbb(nullptr) { mirModule.SetCurFunction(func); @@ -155,6 +163,12 @@ void CGFunc::CreateStartEndLabel() { end_label = mirbuilder->CreateStmtLabel(endLblidx); func->body->InsertLast(end_label); CG_ASSERT(func->body->GetLast() == end_label, ""); + if (cg->cgopt_.WithDwarf()) { + DebugInfo *di = mirModule.dbgInfo; + DBGDie *fdie = di->GetDie(func); + fdie->SetAttr(DW_AT_low_pc, startLblidx); + fdie->SetAttr(DW_AT_high_pc, endLblidx); + } } void CGFunc::HandleLabel(LabelNode *stmt) { @@ -165,6 +179,32 @@ void CGFunc::HandleLabel(LabelNode *stmt) { CG_ASSERT(newbb, ""); lab2bbmap[newbb->labidx] = newbb; curbb = newbb; + + if (cg->cgopt_.WithDwarf()) { + if (lbnode->labelIdx < first_cggen_labelidx) { + DebugInfo *di = mirModule.dbgInfo; + GStrIdx gStrIdx = func->GetLabelStringIndex(lbnode->labelIdx); + DBGDie *lbldie = di->GetLocalDie(func, gStrIdx); + if (lbldie) { + for (auto a : lbldie->attrvec_) + if (a->dwattr_ == DW_AT_name) { + CG_ASSERT(a->val_.id == gStrIdx.GetIdx(), ""); + } + cg->AddLabelDieToLabelIdxMapping(lbldie, lbnode->labelIdx); + } +#if DEBUG + else if (!CGOptions::quiet) { + LogInfo::MapleLogger() << "Warning: label idx = " << lbnode->labelIdx + << " seems added before CodeGen starts but after parsing is done" << endl; + } +#endif + } +#if DEBUG + else if (!CGOptions::quiet) { + LogInfo::MapleLogger() << "label idx = " << lbnode->labelIdx << " ; CG Gen, skip it" << endl; + } +#endif + } } void CGFunc::HandleGoto(GotoNode *stmt) { @@ -191,6 +231,8 @@ void CGFunc::HandleIgoto(UnaryStmtNode *stmt) { curbb->SetKind(BB::kBBIgoto); #if TARGAARCH64 curbb->AppendInsn(cg->BuildInstruction(MOP_xbr, targetOpnd)); +#elif TARGRISCV64 + curbb->AppendInsn(cg->BuildInstruction(MOP_xbr, targetOpnd)); #endif curbb = StartNewBB(stmt); #endif @@ -228,7 +270,7 @@ void CGFunc::HandleCondbr(CondGotoNode *stmt) { zeroopnd = CreateImmOperand(primType, 0); } else { CG_ASSERT((PTY_f32 == primType || PTY_f64 == primType), "we don't support half-precision FP operands yet"); -#if TARGAARCH64 +#if TARGAARCH64 || TARGRISCV64 zeroopnd = CreateFPImmZero(primType); #else zeroopnd = CreateZeroOperand(primType); @@ -286,6 +328,8 @@ void CGFunc::HandleCondbr(CondGotoNode *stmt) { LabelOperand *targetopnd = GetOrCreateLabelOperand(labelIdx); #if TARGAARCH64 curbb->AppendInsn(cg->BuildInstruction(MOP_blo, rflag, targetopnd)); +#elif TARGRISCV64 + curbb->AppendInsn(cg->BuildInstruction(MOP_blo, rflag, targetopnd)); #endif curbb = StartNewBB(stmt); return; @@ -774,7 +818,11 @@ Insn *CGFunc::InsertCFIDefCfaOffset(int &cfiOffset /*in-out*/, Insn *insertAfter cfiOffset = AddtoOffsetFromCFA(cfiOffset); Insn *cfiInsn = cg->BuildInstruction(cfi::OP_CFI_def_cfa_offset, CreateCfiImmOperand(cfiOffset, 64)); Insn *newIpoint = curbb->InsertInsnAfter(insertAfter, cfiInsn); - CG_ASSERT(0, "InsertCFIDefCfaOffset() should be called only once?"); + if (dbg_callframe_offset == 0) { + dbg_callframe_offset = cfiOffset; + } else { + CG_ASSERT(0, "InsertCFIDefCfaOffset() should be called only once?"); + } return newIpoint; } #endif @@ -924,7 +972,7 @@ void CGFunc::DetermineReturnTypeofCall() { if (nextInsn == nullptr) { continue; } -#if TARGAARCH64 +#if TARGAARCH64 || TARGRISCV64 if ((nextInsn->IsMove() && nextInsn->opnds[1]->IsRegister()) || nextInsn->IsStore() || (nextInsn->IsCall() && nextInsn->opnds[0]->IsRegister())) { RegOperand *srcOpnd = static_cast(nextInsn->GetOpnd(0)); @@ -947,7 +995,7 @@ void CGFunc::PatchLongBranch() { BB *next; for (BB *bb = firstbb; bb; bb = next) { next = bb->next; - if (bb->GetKind() != BB::kBBIf) { + if (bb->GetKind() != BB::kBBIf && bb->GetKind() != BB::kBBGoto) { continue; } Insn * insn = bb->lastinsn; @@ -959,7 +1007,11 @@ void CGFunc::PatchLongBranch() { if ((tbb->internal_flag1 - bb->internal_flag1) < MaxCondBranchDistance()) { continue; } - InsertJumpPad(insn); + if (bb->GetKind() == BB::kBBIf) { + InsertJumpPad(insn); + } else { + ConvertJumpToRegJump(insn); + } } } @@ -991,10 +1043,35 @@ void CGFunc::HandleFunction(void) { bool isJavaCatchCall = false; Insn *tempinsn = nullptr; - cout << "===============================================\n"; for (; stmt; stmt = stmt->GetNext()) { needSplit = false; - stmt->Dump(func->module,0); + // insert Insn for .loc before cg for the stmt + //stmt->Dump(func->module,0); + if (cg->cgopt_.WithLoc() && stmt->op != OP_label && stmt->op != OP_comment) { + // if original src file location info is availiable for this stmt, + // use it and skip mpl file location info for this stmt + uint32 newsrcloc = cg->cgopt_.WithSrc() ? stmt->srcPosition.Linenum() : 0; + if (newsrcloc != 0 && newsrcloc != lastsrcloc) { + // .loc for original src file + uint32 fileid = stmt->srcPosition.Filenum(); + Operand *o0 = CreateDbgImmOperand(fileid); + Operand *o1 = CreateDbgImmOperand(newsrcloc); + Insn *loc = cg->BuildInstruction(mpldbg::OP_DBG_loc, o0, o1); + curbb->AppendInsn(loc); + lastsrcloc = newsrcloc; + } else { + // .loc for mpl file + uint32 newmplloc = cg->cgopt_.WithMpl() ? stmt->srcPosition.MplLinenum() : 0; + if (newmplloc != 0 && newmplloc != lastmplloc) { + uint32 fileid = 1; + Operand *o0 = CreateDbgImmOperand(fileid); + Operand *o1 = CreateDbgImmOperand(newmplloc); + Insn *loc = cg->BuildInstruction(mpldbg::OP_DBG_loc, o0, o1); + curbb->AppendInsn(loc); + lastmplloc = newmplloc; + } + } + } isVolLoad = false; opcode = stmt->op; StmtNode *next = stmt->GetRealNext(); @@ -1238,7 +1315,9 @@ void CGFunc::HandleFunction(void) { DetermineReturnTypeofCall(); theCFG->MarkLabelTakenBB(); theCFG->UnreachCodeAnalysis(); - PatchLongBranch(); + if (CGOptions::doPatchLongBranch) { + PatchLongBranch(); + } } void CGFunc::DumpCFG(void) { @@ -1378,6 +1457,9 @@ AnalysisResult *CgDoOffAdjFPLR::Run(CGFunc *cgfunc, CgFuncResultMgr *m) { } AnalysisResult *CgFixCFLocOsft::Run(CGFunc *cgfunc, CgFuncResultMgr *m) { + if (cgfunc->cg->cgopt_.WithDwarf()) { + cgfunc->DBGFixCallFrameLocationOffsets(); + } return nullptr; } diff --git a/mapleall/maple_be/src/cg/cg_option.cpp b/mapleall/maple_be/src/cg/cg_option.cpp index b86bf59..26b01e2 100644 --- a/mapleall/maple_be/src/cg/cg_option.cpp +++ b/mapleall/maple_be/src/cg/cg_option.cpp @@ -59,6 +59,11 @@ bool CGOptions::useBarriersForVolatile = false; bool CGOptions::useRange = false; bool CGOptions::inRange = false; bool CGOptions::quiet = false; +#if TARGRISCV64 +bool CGOptions::doPatchLongBranch = false; +#else +bool CGOptions::doPatchLongBranch = true; +#endif bool CGOptions::doZeroExtend = false; bool CGOptions::doConstFold = true; bool CGOptions::exclusiveEh = false; @@ -67,6 +72,7 @@ bool CGOptions::doEbo = false; bool CGOptions::doCfgo = false; bool CGOptions::doIco = false; bool CGOptions::doStoreLoadOpt = false; +bool CGOptions::doMultiPassColorRA = true; bool CGOptions::doPreLsraOpt = false; bool CGOptions::doGlobalOpt = false; bool CGOptions::doPostLsraOpt = false; @@ -74,6 +80,7 @@ bool CGOptions::doLocalRefSpill = false; bool CGOptions::doLvarPathOpt = false; bool CGOptions::checkarraystore = false; bool CGOptions::doCalleeToSpill = false; +bool CGOptions::doCallerCrossCall = false; bool CGOptions::doStructFpInInt = true; bool CGOptions::dumpOLog = false; bool CGOptions::doPrePeephole = false; @@ -91,7 +98,6 @@ bool CGOptions::replaceasm = false; bool CGOptions::emitBlockMarker = true; bool CGOptions::printLowerIR = false; bool CGOptions::printFunction = false; -bool CGOptions::doSimplePrint = false; bool CGOptions::nativeopt = false; bool CGOptions::withDwarf = false; @@ -165,12 +171,14 @@ enum OptionIndex { kPeep, kPreSchedule, kSchedule, + kMultiPassRA, kPrelsraopt, kPostlsraopt, kNativeOpt, kLocalrefSpill, kLocalrefvarPathOpt, kOptcallee, + kCallerCrossCall, kStructFpInInt, kPie, PIC, @@ -186,6 +194,7 @@ enum OptionIndex { kGenPrimorList, kRaLinear, kRaColor, + kPatchLongBranch, kZeroextend, kConstfold, kSuppressFinfo, @@ -240,7 +249,6 @@ enum OptionIndex { kFieldMetaProfile, kPrintLowerIR, kPrintFunction, - kPrintSimple, kDumpPhases, kSkipPhases, kSkipFrom, @@ -325,6 +333,10 @@ const Descriptor kUsage[] = { " --schedule Perform scheduling" }, { kSchedule, OTI_DISABLED, "", "no-schedule", kBuildTypeAll, kArgCheckPolicyNone, " --no-schedule\n" }, + { kMultiPassRA, OTI_ENABLED, "", "fullcolor", kBuildTypeAll, kArgCheckPolicyNone, + " --fullcolor Perform multi-pass coloring RA\n" }, + { kMultiPassRA, OTI_DISABLED, "", "no-fullcolor", kBuildTypeAll, kArgCheckPolicyNone, " --no-fullcolor\n" }, + { kPrelsraopt, OTI_ENABLED, "", "prelsra", kBuildTypeAll, kArgCheckPolicyNone, " --prelsra Perform live interval simplification in LSRA\n" }, { kPrelsraopt, OTI_DISABLED, "", "no-prelsra", kBuildTypeAll, kArgCheckPolicyNone, " --no-prelsra\n" }, @@ -349,6 +361,9 @@ const Descriptor kUsage[] = { { kOptcallee, OTI_ENABLED, "", "lsra-optcallee", kBuildTypeAll, kArgCheckPolicyNone, " --lsra-optcallee Spill callee if only one def to use\n" }, { kOptcallee, OTI_DISABLED, "", "no-lsra-optcallee", kBuildTypeAll, kArgCheckPolicyNone, " --no-lsra-optcallee\n" }, + { kCallerCrossCall, OTI_ENABLED, "", "lsra-caller-cross-call", kBuildTypeAll, kArgCheckPolicyNone, + " --lsra-caller-cross-call Use caller like callee for special mrt funcs\n" }, + { kCallerCrossCall, OTI_DISABLED, "", "no-lsra-caller-cross-call", kBuildTypeAll, kArgCheckPolicyNone, " --no-lsra-caller-cross-call\n" }, { kStructFpInInt, OTI_ENABLED, "", "allow-struct-parm-in-fp", kBuildTypeAll, kArgCheckPolicyNone, " --allow-struct-parm-in-fp Pass struct in int regs instead of fp regs\n" }, { kStructFpInInt, OTI_DISABLED, "", "no-allow-struct-parm-in-fp", kBuildTypeAll, kArgCheckPolicyNone, " --no-allow-struct-parm-in-fp" }, @@ -426,6 +441,8 @@ const Descriptor kUsage[] = { " --with-ra-linear-scan Do linear-scan register allocation" }, { kRaColor, 0, "", "with-ra-graph-color", kBuildTypeAll, kArgCheckPolicyNone, " --with-ra-graph-color Do coloring-based register allocation" }, + { kPatchLongBranch, OTI_ENABLED, "", "patch-long-branch", kBuildTypeAll, kArgCheckPolicyNone, " --patch-long-branch Enable patching of long distance branch" }, + { kPatchLongBranch, OTI_DISABLED, "","no-patch-long-branch", kBuildTypeAll, kArgCheckPolicyNone, " --no-patch-long-branch Disable patching of long distance branch" }, { kZeroextend, OTI_ENABLED, "", "zero-extend", kBuildTypeAll, kArgCheckPolicyNone, " --zero-extend Enable zero extension" }, { kZeroextend, OTI_DISABLED, "","no-zero-extend", kBuildTypeAll, kArgCheckPolicyNone, " --no-zero-extend Disable zero extension" }, { kConstfold, OTI_ENABLED, "", "const-fold", kBuildTypeAll, kArgCheckPolicyNone, " --const-fold Enable constant folding" }, @@ -478,7 +495,6 @@ const Descriptor kUsage[] = { { kDumpssadef, 0, "", "dump-ssadef", kBuildTypeAll, kArgCheckPolicyNone, " --dump-ssadef" }, { kPrintLowerIR, 0, "", "print-ir", kBuildTypeAll, kArgCheckPolicyNone, " --print-ir" }, { kPrintFunction, 0, "", "print-func", kBuildTypeAll, kArgCheckPolicyNone, " --print-func" }, - { kPrintSimple, 0, "", "print-simple", kBuildTypeAll, kArgCheckPolicyNone, " --print-simple" }, { kCheckComplete, 0, "", "check-complete", kBuildTypeAll, kArgCheckPolicyNone, " --check-complete Check incomplete types" }, #if DEBUG { kLocalvarsToPregs, 0, "", "convert-java-localvars-to-pregs", kBuildTypeAll, kArgCheckPolicyNone, " --convert-java-localvars-to-pregs" }, @@ -649,9 +665,6 @@ bool CGOptions::ParseOptions(int argc, char **argv, string &fileName) { case kPrintFunction: printFunction = true; break; - case kPrintSimple: - doSimplePrint = true; - break; case kTrace: SetOption(options_, kAddDebugTrace); break; @@ -661,6 +674,9 @@ bool CGOptions::ParseOptions(int argc, char **argv, string &fileName) { case kSuppressFinfo: SetOption(options_, kSuppressFileinfo); break; + case kPatchLongBranch: + doPatchLongBranch = (opt.Type() == OTI_ENABLED); + break; case kZeroextend: doZeroExtend = (opt.Type() == OTI_ENABLED); if (doZeroExtend) { @@ -774,6 +790,9 @@ bool CGOptions::ParseOptions(int argc, char **argv, string &fileName) { case kSchedule: doSchedule = (opt.Type() == OTI_ENABLED); break; + case kMultiPassRA: + doMultiPassColorRA = (opt.Type() == OTI_ENABLED); + break; case kPrelsraopt: doPreLsraOpt = (opt.Type() == OTI_ENABLED); break; @@ -792,6 +811,9 @@ bool CGOptions::ParseOptions(int argc, char **argv, string &fileName) { case kOptcallee: doCalleeToSpill = (opt.Type() == OTI_ENABLED); break; + case kCallerCrossCall: + doCallerCrossCall = (opt.Type() == OTI_ENABLED); + break; case kStructFpInInt: doStructFpInInt = (opt.Type() == OTI_ENABLED); break; @@ -919,6 +941,15 @@ bool CGOptions::ParseOptions(int argc, char **argv, string &fileName) { ClearOption(options_, kDebugFriendly); } + // override some options when dwarf is generated + if (WithDwarf()) { + doEbo = false; + doCfgo = false; + doIco = false; + generate_gdb_friendly_code = true; + SetOption(options_, kDebugFriendly); + } + if (result) { if (optionParser.GetNonOptionsCount() != 1) { LogInfo::MapleLogger(kLlErr) << "expecting one .mpl file as last argument, found: "; diff --git a/mapleall/maple_be/src/cg/cg_phase_manager.cpp b/mapleall/maple_be/src/cg/cg_phase_manager.cpp index 473b5d1..e2a0479 100644 --- a/mapleall/maple_be/src/cg/cg_phase_manager.cpp +++ b/mapleall/maple_be/src/cg/cg_phase_manager.cpp @@ -108,11 +108,9 @@ void CgFuncPhaseManager::AddPhases(std::vector &phases) { ADDPHASE("storeloadopt"); } -#if !(TARGRISCV64) if (CGOptions::doGlobalOpt) { ADDPHASE("globalopt"); } -#endif if (CGOptions::doPrePeephole) { ADDPHASE("prepeephole1"); @@ -136,11 +134,9 @@ void CgFuncPhaseManager::AddPhases(std::vector &phases) { if (CGOptions::doPeephole) { ADDPHASE("peephole0"); } -#if !(TARGRISCV64) if (CGOptions::doEbo) { ADDPHASE("postebo"); } -#endif if (CGOptions::doCfgo) { ADDPHASE("postcfgo"); diff --git a/mapleall/maple_be/src/cg/ebo.cpp b/mapleall/maple_be/src/cg/ebo.cpp index c34fe7e..a26ba98 100644 --- a/mapleall/maple_be/src/cg/ebo.cpp +++ b/mapleall/maple_be/src/cg/ebo.cpp @@ -899,6 +899,10 @@ bool Ebo::BuildOperandInfo(BB *bb) { OpndInfo **origInfo = ebomp->NewArray(maxOpnds); while (insn && insn != bb->lastinsn->next) { + if (!insn->IsMachineInstruction()) { + insn = insn->next; + continue; + } Insn *prev = insn->prev; int32_t opndnum = insn->GetOpndNum(); int32_t resnum = insn->GetResultNum(); @@ -1042,7 +1046,7 @@ bool Ebo::BuildOperandInfo(BB *bb) { } } // forward prop for registers. - if (!opnd->IsConstant() && + if (!opnd->IsConstant() && !insn->IsPseudoInstruction() && (!before_regalloc || (HasAssignedReg(old) == HasAssignedReg(opndReplace)) || opnd->IsConstReg() || !insn->IsMove()) && opndinfo != nullptr && (!before_regalloc || opndinfo->bb == bb || !GRAHomeable(opndReplace)) && @@ -1130,9 +1134,7 @@ bool Ebo::BuildOperandInfo(BB *bb) { } } else if (!insnReplaced && !insn->HasSideEffects() && !insn->AccessRegBank()) { if (opndsConstant && (opndnum > 1)) { - if (IsBranchCmpSpecial(insn)) { - insnReplaced = ResoveCondBranch(insn, opnds); - } else if (insn->GetResultNum() >= 1) { + if (insn->GetResultNum() >= 1) { insnReplaced = DoConstantFold(insn, opnds, opndInfo); } } else if (opndnum >= 1) { @@ -1326,24 +1328,7 @@ void Ebo::RemoveUnusedInsns(BB *bb, bool normal) { if (insn->IsEffectiveCopy()) { int32_t idx = insn->CopyOperands(); OpndInfo *opinfo = insninfo->orig_opnd[idx]; - InsnInfo *previnfo = insninfo->prev; - if (previnfo && previnfo->insn && opinfo && opinfo->opnd->IsRegister() && IsVecReg(opinfo->opnd)) { - Insn *prev = previnfo->insn; - if (prev->IsEffectiveCopy() && previnfo->orig_opnd[prev->CopyOperands()] == opinfo) { - OpndInfo *resinfo = previnfo->result[0]; - InsnInfo *nextinfo = insninfo->next; - CG_ASSERT(insn->GetResult(0) != nullptr, "insn->GetResult(0) is null in Ebo::RemoveUnusedInsns"); - if (nextinfo && nextinfo->insn && nextinfo->orig_opnd[0] == resinfo && resinfo->refcount == 1 && - IsOfSameClass(resinfo->opnd, insn->GetResult(0)) && IsCmp(nextinfo->insn) && - !LiveOutOfBB(resinfo->opnd, opinfo->bb)) { - nextinfo->insn->SetOpnd(0, insn->GetResult(0)); - nextinfo->orig_opnd[0] = insninfo->result[0]; - resinfo->refcount--; - insninfo->result[0]->refcount++; - } - } - } - previnfo = LocateInsnInfo(opinfo); + InsnInfo *previnfo = LocateInsnInfo(opinfo); if (opinfo != nullptr && previnfo && opinfo->insn && opinfo->opnd->IsRegister() && !IsVecReg(opndinfo->opnd)) { Insn *prev = opinfo->insn; RegOperand *reg = static_cast(opinfo->opnd); @@ -1429,7 +1414,7 @@ void Ebo::RemoveUnusedInsns(BB *bb, bool normal) { if (meminfo && meminfo->GetBaseInfo() == opinfo) { pattern4 = true; meminfo->SetBaseInfo(resinfo); - resinfo->refcount++; + IncRef(resinfo); } } } @@ -1445,7 +1430,7 @@ void Ebo::RemoveUnusedInsns(BB *bb, bool normal) { if (pattern2) { next->SetOperand(1, res1); nextinfo->orig_opnd[0] = resinfo; - resinfo->refcount++; + IncRef(resinfo); } else if (pattern4) { CG_ASSERT(next->GetOpnd(0) != nullptr, "next->GetOpnd(0) is null in Ebo::RemoveUnusedInsns"); MemOperand *memopnd = static_cast(next->GetOpnd(0)->Clone(cgfunc->memPool)); @@ -1475,7 +1460,7 @@ void Ebo::RemoveUnusedInsns(BB *bb, bool normal) { } // propagate use count for this opnd to it's input operand. if (opndinfo->same != nullptr) { - opndinfo->same->refcount += opndinfo->refcount; + IncRef(opndinfo->same, opndinfo->refcount); } // remove the copy causes the previous def to reach the end of the block. @@ -1554,7 +1539,7 @@ insn_is_needed: } else { /* Couldn't find the insninfo entry. Make sure that the operand has a use count so that the defining insn will not be deleted. */ - nextinfo->refcount += opndinfo->refcount; + IncRef(nextinfo, opndinfo->refcount); } } nextinfo = nextinfo->same; @@ -1576,7 +1561,7 @@ insn_is_needed: } else { /* Couldn't find the insninfo entry. Make sure that the operand has a use count so that the defining insn will not be deleted. */ - nextinfo->refcount += opndinfo->refcount; + IncRef(nextinfo, opndinfo->refcount); } } nextinfo = nextinfo->same; diff --git a/mapleall/maple_be/src/cg/emit.cpp b/mapleall/maple_be/src/cg/emit.cpp index ce457ec..f94eef2 100644 --- a/mapleall/maple_be/src/cg/emit.cpp +++ b/mapleall/maple_be/src/cg/emit.cpp @@ -79,7 +79,7 @@ Asmlabel Emitter::GetTypeAsmInfoName(PrimType pty) { case 1: return kAsmByte; case 2: -#if TARGAARCH64 || TARGARK +#if TARGAARCH64 || TARGARK || TARGRISCV64 return kAsmShort; #else return kAsmValue; @@ -201,7 +201,7 @@ void Emitter::EmitAsmLabel(Asmlabel al) { void Emitter::EmitAsmLabel(const MIRSymbol *st, Asmlabel al) { MIRType *ty = st->GetType(); std::string syName; - if (st->storageClass == kScPstatic) { + if (st->storageClass == kScPstatic && st->IsLocal()) { syName = st->GetName() + to_string(CG::curPuIdx); } else { syName = st->GetName(); @@ -245,7 +245,7 @@ void Emitter::EmitAsmLabel(const MIRSymbol *st, Asmlabel al) { Emit(size.c_str()); Emit(", "); #if PECOFF -#if TARGARM || TARGAARCH64 || TARGARK +#if TARGARM || TARGAARCH64 || TARGARK || TARGRISCV64 std::string align = std::to_string(static_cast(log2(g->becommon->type_align_table[ty->tyIdx.GetIdx()]))); #else std::string align = std::to_string(g->becommon->type_align_table[ty->tyIdx.GetIdx()]); @@ -284,7 +284,7 @@ void Emitter::EmitAsmLabel(const MIRSymbol *st, Asmlabel al) { align = "3"; } else { -#if TARGARM || TARGAARCH64 || TARGARK +#if TARGARM || TARGAARCH64 || TARGARK || TARGRISCV64 align = std::to_string(static_cast(log2(g->becommon->type_align_table[ty->tyIdx.GetIdx()]))); #else align = std::to_string(g->becommon->type_align_table[ty->tyIdx.GetIdx()]); @@ -387,46 +387,36 @@ void Emitter::EmitBitFieldConstant(StructEmitInfo *semitinfo, MIRConst *ct, cons } } -void Emitter::EmitStrConstant(MIRStrConst *ct, bool isAscii, bool isIndirect) { - if (isIndirect) { - uint32 strId = ct->value.GetIdx(); - if (stringPtr[strId] == 0) { - stringPtr[strId] = ct->value; - } - Emit("\t.dword\t").Emit(".LSTR__").Emit(std::to_string(strId).c_str()); - return; +void Emitter::EmitStr(const std::string& mplStr, bool emitAscii, bool emitNewline) { + const char *str = mplStr.c_str(); + size_t len = mplStr.size(); + + if (emitAscii) { + Emit("\t.ascii\t\""); // Do not terminate with \0 + } else { + Emit("\t.string\t\""); } + // don't expand special character in a writeout to .s, // convert all \s to \\s in string for storing in .string - const string ustr = GlobalTables::GetUStrTable().GetStringFromStrIdx(ct->value); - const char *str = ustr.c_str(); - size_t len = ustr.size(); - if (isAscii) { - Emit("\t.ascii \""); // Do not terminate with \0 - if (isFlexibleArray) { - arraySize += len; - } - } else { - Emit("\t.string \""); - if (isFlexibleArray) { - arraySize += len + 1; - } - } for (int i = 0; i < len; i++) { + // Referred to GNU AS: 3.6.1.1 Strings char buf[5]; if (isprint(*str)) { buf[0] = *str; + buf[1] = 0; if (*str == '\\' || *str == '\"') { - // other escape sequence are handled in the else - buf[1] = buf[0]; buf[0] = '\\'; + buf[1] = *str; buf[2] = 0; - } else { - buf[1] = 0; } Emit(buf); + } else if (*str == '\b') { + Emit("\\b"); } else if (*str == '\n') { Emit("\\n"); + } else if (*str == '\r') { + Emit("\\r"); } else if (*str == '\t') { Emit("\\t"); } else if (*str == '\0') { @@ -445,7 +435,33 @@ void Emitter::EmitStrConstant(MIRStrConst *ct, bool isAscii, bool isIndirect) { } str++; } + Emit("\""); + if (emitNewline) Emit("\n"); +} + +void Emitter::EmitStrConstant(MIRStrConst *ct, bool isAscii, bool isIndirect) { + if (isIndirect) { + uint32 strId = ct->value.GetIdx(); + if (stringPtr[strId] == 0) { + stringPtr[strId] = ct->value; + } + Emit("\t.dword\t").Emit(".LSTR__").Emit(std::to_string(strId).c_str()); + return; + } + + const string ustr = GlobalTables::GetUStrTable().GetStringFromStrIdx(ct->value); + size_t len = ustr.size(); + if (isAscii) { + if (isFlexibleArray) { + arraySize += len; + } + } else { + if (isFlexibleArray) { + arraySize += len + 1; + } + } + EmitStr(ustr, isAscii, false); } void Emitter::EmitStr16Constant(MIRStr16Const *ct) { @@ -714,7 +730,7 @@ void Emitter::EmitScalarConstant(MIRConst *ct, bool newline = true, bool flag32 bool isGlobal = stidx.IsGlobal(); MIRSymbol *symaddrSym = isGlobal ? GlobalTables::GetGsymTable().GetSymbolFromStIdx(stidx.Idx()) : CG::curCgFunc->mirModule.CurFunction()->symTab->GetSymbolFromStIdx(stidx.Idx()); - if (symaddrSym->storageClass == kScPstatic) { + if (isGlobal == false && symaddrSym->storageClass == kScPstatic) { Emit("\t.quad\t" + symaddrSym->GetName() + to_string(CG::curPuIdx)); } else { Emit("\t.quad\t" + symaddrSym->GetName()); @@ -1542,6 +1558,8 @@ void Emitter::EmitLiterals(std::vector> &literals, ifstream infile; infile.open(CGOptions::literalProFile); if (infile.fail()) { + // no profile available, emit literals as usual + cerr << "Cannot open literal profile file " << CGOptions::literalProFile << "\n"; for (auto literalPair : literals) { EmitLiteral(literalPair.first, stridx2type); } @@ -1639,23 +1657,6 @@ void Emitter::MarkVtabOrItabEndFlag(std::vector &symV, std::vector< } } -void Emitter::EmitSpecialChar(std::string str, size_t startPos, size_t endPos) { - Emit(str.substr(startPos, endPos - startPos)); - Emit("\\"); - size_t pos = str.find("\"", endPos + 1); - if (pos == string::npos) { - for(char& c : str.substr(endPos)) { - if (c == '\\') { - Emit("\\\\"); - } else { - Emit(std::string(1, c)); - } - } - } else { - EmitSpecialChar(str, endPos, pos); - } -} - void Emitter::EmitStringPointers() { Emit(asminfo_->asm_section).Emit(asminfo_->asm_data).Emit("\n"); for (auto idx: stringPtr) { @@ -1666,48 +1667,8 @@ void Emitter::EmitStringPointers() { const char *str = GlobalTables::GetUStrTable().GetStringFromStrIdx(idx).c_str(); Emit("\t.align 3\n"); Emit(".LSTR__").Emit(strId).Emit(":\n"); - - int start = 0; - int len = strlen(str); - std::string newstr(str); - if (len == 0) { - Emit("\t.string\t\"\"\n"); - } - for (int i = 0; i < len; i++) { - if (str[i] == '\n' || str[i] == '\0' || ((i + 1) == len)) { - if ((i + 1) == len) { - Emit("\t.string\t\""); - } else { - Emit("\t.ascii\t\""); - } - size_t pos; - std::string sub; - if (str[i] == '\n' || str[i] == '\0') { - sub = newstr.substr(start, i - start); - } else { - sub = newstr.substr(start, i - start + 1); - } - pos = sub.find("\""); - if (pos == string::npos) { - //Emit(newstr.substr(start, i - start)); - for(char& c : sub) { - if (c == '\\') { - Emit("\\\\"); - } else { - Emit(std::string(1, c)); - } - } - } else { - EmitSpecialChar(sub, 0, pos); - } - if (str[i] == '\n') { - Emit("\\n\"\n"); - } else { - Emit("\"\n"); - } - start = i+1; - } - } + std::string mplstr(str); + EmitStr(mplstr, false, true); } } diff --git a/mapleall/maple_be/src/cg/emit_dbg.cpp b/mapleall/maple_be/src/cg/emit_dbg.cpp new file mode 100644 index 0000000..43b903c --- /dev/null +++ b/mapleall/maple_be/src/cg/emit_dbg.cpp @@ -0,0 +1,663 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#include "emit.h" +#include "name_mangler.h" +#include "dbg.h" +#include "cg_assert.h" +#include "be_common.h" // SIZEOFPTR +#include "global_tables.h" +#include "mir_symbol.h" + +namespace maple { +const char *get_DW_TAG_name(unsigned n); +const char *get_DW_FORM_name(unsigned n); +const char *get_DW_AT_name(unsigned n); +} // namespace maple + +namespace maplebe { + +using namespace maple; + +// extern bool do_pie; + +using namespace cfi; + +DBGDie *LFindDieWithName(DBGDie *die, dw_tag tag, GStrIdx key) { + if (die->tag_ == tag) { + for (auto a : die->attrvec_) { + if (a->dwattr_ == DW_AT_name) { + if (a->dwform_ == DW_FORM_string && a->val_.id == key.GetIdx()) { + return die; + } else { + break; + } + } + } + } + + for (auto c : die->subdievec_) { + DBGDie *res = LFindDieWithName(c, tag, key); + if (res) { + return res; + } + } + return nullptr; +} + +DBGDie *LFindChildDieWithName(DBGDie *die, dw_tag tag, GStrIdx key) { + for (DBGDie *c : die->subdievec_) { + if (c->tag_ == tag) { + for (DBGDieAttr *a : c->attrvec_) { + if (a->dwattr_ == DW_AT_name) { + if ((a->dwform_ == DW_FORM_string || a->dwform_ == DW_FORM_strp) && a->val_.id == key.GetIdx()) { + return c; + } else { + break; + } + } + } + } + } + return nullptr; +} + +DBGDieAttr *LFindDieAttr(DBGDie *die, dw_at attrname) { + for (DBGDieAttr *attr : die->attrvec_) { + if (attr->dwattr_ == attrname) { + return attr; + } + } + return nullptr; +} + +void LReplaceFORMValueInAbbrevEntry(DBGAbbrevEntry *diae, dw_at attrName, dw_form formValue) { + MapleVector &attrpairs = diae->attrpairs_; // kDwAt kDwForm pairs + for (int i = 0; i < attrpairs.size(); i += 2) { + if (attrpairs[i] == attrName) { + // If the following CG_ASSERTion ever fires off, instead of replacing + // DW_FOMR value in place, we should clone the abbrev entry, make change to + // to the cloned one, and replace the abbrev entry in the referring DIE. + CG_ASSERT(attrpairs[i + 1] == DW_FORM_data1 || (attrpairs[i + 1] == formValue), + "Conflicting change? Read the above comment."); + attrpairs[i + 1] = formValue; + return; + } + } +} + +static void LUpdateAttrValue(DBGDieAttr *attr, int64_t newval, DBGAbbrevEntry *diae) { + attr->val_.i = int32_t(newval); + return; +} + +void CGFunc::AddDIESymbolLocation(const MIRSymbol *sym, SymbolAlloc *loc) { + CG_ASSERT(dbginfo, ""); + DBGDie *sdie = dbginfo->GetLocalDie(func, sym->GetNameStridx()); + if (!sdie) { + return; + } + CG_ASSERT(sdie, ""); + + DBGExprLoc *exprloc = sdie->GetExprLoc(); + CHECK_FATAL(exprloc != nullptr, "exprloc is null in CGFunc::AddDIESymbolLocation"); + exprloc->symloc_ = loc; + + dbg_callframe_locations.push_back(exprloc); +} + +#define XSTR(s) str(s) +#define str(s) #s + +void Emitter::EmitDIHeader() { + Emit(".L" XSTR(TEXT_BEGIN) ":\n"); +} + +void Emitter::EmitDIFooter() { + Emit("\t.text\n"); + Emit(".L" XSTR(TEXT_END) ":\n"); +} + +void Emitter::EmitDIHeaderFileInfo() { + Emit("// dummy header file 1\n"); + Emit("// dummy header file 2\n"); + Emit("// dummy header file 3\n"); +} + +void Emitter::AddLabelDieToLabelIdxMapping(DBGDie *lbldie, LabelIdx lblidx) { + labdie2labidx_table.insert(pair(lbldie, lblidx)); +} + +LabelIdx Emitter::GetLabelIdxForLabelDie(DBGDie *lbldie) { + auto it = labdie2labidx_table.find(lbldie); + CHECK_FATAL(it != labdie2labidx_table.end(), ""); + return it->second; +} + +void Emitter::ApplyInPrefixOrder(DBGDie *die, const std::function &func) { + func(die); + CG_ASSERT(die, ""); + if (die->subdievec_.size() > 0) { + for (auto c : die->subdievec_) { + ApplyInPrefixOrder(c, func); + } + // mark the end of the sibling list + func(nullptr); + } +} + +DBGDieAttr *LFindAttribute(MapleVector &vec, dw_at key) { + for (DBGDieAttr *at : vec) + if (at->dwattr_ == key) { + return at; + } + return nullptr; +} + +DBGAbbrevEntry *LFindAbbrevEntry(MapleVector &abbvec, unsigned int key) { + for (DBGAbbrevEntry *daie : abbvec) { + if (!daie) { + continue; + } + if (daie->abbrevid_ == key) { + return daie; + } + } + CG_ASSERT(0, ""); + return nullptr; +} + +bool LShouldEmit(unsigned int dwform) { + switch (dwform) { + case DW_FORM_flag_present: + return false; + } + return true; +} + +void Emitter::EmitDIFormSpecification(unsigned int dwform) { + switch (dwform) { + case DW_FORM_string: + Emit(".string "); + break; + case DW_FORM_strp: + case DW_FORM_data4: + case DW_FORM_ref4: + Emit(".4byte "); + break; + case DW_FORM_data1: + Emit(".byte "); + break; + case DW_FORM_data2: + Emit(".2byte "); + break; + case DW_FORM_data8: + Emit(".8byte "); + break; + case DW_FORM_sec_offset: + // if DWARF64, should be .8byte? + Emit(".4byte "); + break; + case DW_FORM_addr: /* Should we use DWARF64? for now, we generate .8byte as gcc does for DW_FORM_addr */ + Emit(".8byte "); + break; + case DW_FORM_exprloc: + Emit(".uleb128 "); + break; + default: + CHECK_FATAL(maple::get_DW_FORM_name(dwform) != nullptr, + "get_DW_FORM_name return null in Emitter::EmitDIFormSpecification"); + LogInfo::MapleLogger() << "unhandled : " << maple::get_DW_FORM_name(dwform) << endl; + CG_ASSERT(0, "NYI"); + } +} + +void Emitter::EmitDIAttrValue(DBGDie *die, DBGDieAttr *attr, dw_at attrName, dw_tag tagName, DebugInfo *di) { + MapleVector &attrvec = die->attrvec_; + + switch (attr->dwattr_) { + case DW_AT_decl_file: + EmitHexUnsigned(1); // file num, 1 for debugging .mpl + return; + default: + break; + } + + switch (attr->dwform_) { + case DW_FORM_string: { + const string &name = GlobalTables::GetStrTable().GetStringFromStrIdx(attr->val_.id); + Emit("\"").Emit(name).Emit("\""); + Emit("\t// len = "); + EmitDecUnsigned(name.length() + 1); + } break; + case DW_FORM_strp: + Emit(".L" XSTR(DEBUG_STR_LABEL)); + out << attr->val_.id; + break; + case DW_FORM_data1: +#if DEBUG + if (attr->val_.i == kDbgDefaultVal) { + EmitHexUnsigned(attr->val_.i); + } else +#endif + EmitHexUnsigned(uint8_t(attr->val_.i)); + break; + case DW_FORM_data2: +#if DEBUG + if (attr->val_.i == kDbgDefaultVal) { + EmitHexUnsigned(attr->val_.i); + } else +#endif + EmitHexUnsigned(uint16_t(attr->val_.i)); + break; + case DW_FORM_data4: +#if DEBUG + if (attr->val_.i == kDbgDefaultVal) { + EmitHexUnsigned(attr->val_.i); + } else +#endif + EmitHexUnsigned(uint32_t(attr->val_.i)); + break; + case DW_FORM_data8: + if (attrName == DW_AT_high_pc) { + if (tagName == DW_TAG_compile_unit) { + Emit(".L" XSTR(TEXT_END) "-.L" XSTR(TEXT_BEGIN)); + } else if (tagName == DW_TAG_subprogram) { + DBGDieAttr *name = LFindAttribute(attrvec, DW_AT_name); + if (name == nullptr) { + DBGDieAttr *spec = LFindAttribute(attrvec, DW_AT_specification); + CHECK_FATAL(spec != nullptr, "spec is null in Emitter::EmitDIAttrValue"); + DBGDie *decl = di->GetDie(spec->val_.id); + name = LFindAttribute(decl->attrvec_, DW_AT_name); + } + CHECK_FATAL(name != nullptr, "name is null in Emitter::EmitDIAttrValue"); + const string &str = GlobalTables::GetStrTable().GetStringFromStrIdx(name->val_.id); + EmitLabelRef(str.c_str(), attr->val_.id); + Emit("-"); + DBGDieAttr *lowpc = LFindAttribute(attrvec, DW_AT_low_pc); + CHECK_FATAL(lowpc != nullptr, "lowpc is null in Emitter::EmitDIAttrValue"); + EmitLabelRef(str.c_str(), lowpc->val_.id); + } + } else { + EmitHexUnsigned(attr->val_.i); + } + break; + case DW_FORM_sec_offset: + if (attrName == DW_AT_stmt_list) { + Emit(".L"); + Emit(XSTR(DEBUG_LINE_0)); + } + break; + case DW_FORM_addr: + if (attrName == DW_AT_low_pc) { + if (tagName == DW_TAG_compile_unit) { + Emit(".L" XSTR(TEXT_BEGIN)); + } else if (tagName == DW_TAG_subprogram) { + // if decl, name should be found; if def, we try DW_AT_specification + DBGDieAttr *name = LFindAttribute(attrvec, DW_AT_name); + if (name == nullptr) { + DBGDieAttr *spec = LFindAttribute(attrvec, DW_AT_specification); + CHECK_FATAL(spec != nullptr, "spec is null in Emitter::EmitDIAttrValue"); + DBGDie *decl = di->GetDie(spec->val_.id); + name = LFindAttribute(decl->attrvec_, DW_AT_name); + } + CHECK_FATAL(name != nullptr, "name is null in Emitter::EmitDIAttrValue"); + const string &str = GlobalTables::GetStrTable().GetStringFromStrIdx(name->val_.id); + EmitLabelRef(str.c_str(), attr->val_.id); + } else if (tagName == DW_TAG_label) { + LabelIdx labelIdx = GetLabelIdxForLabelDie(die); + DBGDie *subpgm = die->parent; + CG_ASSERT(subpgm->tag_ == DW_TAG_subprogram, "Label DIE should be a child of a Subprogram DIE"); + DBGDieAttr *fnameAttr = LFindAttribute(subpgm->attrvec_, DW_AT_name); + if (!fnameAttr) { + DBGDieAttr *specAttr = LFindAttribute(subpgm->attrvec_, DW_AT_specification); + CHECK_FATAL(specAttr, "pointer is null"); + DBGDie *twin = di->GetDie(specAttr->val_.u); + fnameAttr = LFindAttribute(twin->attrvec_, DW_AT_name); + } + CHECK_FATAL(fnameAttr, ""); + const string &fnameStr = GlobalTables::GetStrTable().GetStringFromStrIdx(fnameAttr->val_.id); + LabelOperand *res = memPool->New(fnameStr.c_str(), labelIdx); + res->Emit(*this, nullptr); + } + } else if (attrName == DW_AT_high_pc) { + if (tagName == DW_TAG_compile_unit) { + Emit(".L" XSTR(TEXT_END) "-.L" XSTR(TEXT_BEGIN)); + } + } else { + Emit("XXX--ADDR--XXX"); + } + break; + case DW_FORM_ref4: + if (attrName == DW_AT_type) { + DBGDie *die = di->GetDie(attr->val_.u); + if (die->Offset) { + EmitHexUnsigned(die->Offset); + } else { + // unknown type, missing mplt + EmitHexUnsigned(di->dummytypedie_->Offset); + Emit("\t// Warning: dummy type used"); + } + } else if (attrName == DW_AT_specification || attrName == DW_AT_sibling) { + DBGDie *die = di->GetDie(attr->val_.u); + CG_ASSERT(die->Offset, ""); + EmitHexUnsigned(die->Offset); + } else if (attrName == DW_AT_object_pointer) { + GStrIdx thisIdx = GlobalTables::GetStrTable().GetStrIdxFromName(DEBUG_MAPLE_THIS); + DBGDie *that = LFindChildDieWithName(die, DW_TAG_formal_parameter, thisIdx); + // need to find the this or self based on the source language + // what is the name for 'this' used in mapleir? + // this has to be with respect to a function + if (that) { + EmitHexUnsigned(that->Offset); + } else { + EmitHexUnsigned(attr->val_.u); + } + } else { + Emit(" OFFSET "); + EmitHexUnsigned(attr->val_.u); + } + break; + case DW_FORM_exprloc: { + DBGExprLoc *elp = attr->val_.ptr; + switch (elp->GetOp()) { + case DW_OP_call_frame_cfa: + EmitHexUnsigned(1); + Emit("\n\t.byte "); + EmitHexUnsigned(elp->GetOp()); + break; + case DW_OP_addr: + EmitHexUnsigned(9); + Emit("\n\t.byte "); + EmitHexUnsigned(elp->GetOp()); + Emit("\n\t.8byte "); + Emit(GlobalTables::GetStrTable().GetStringFromStrIdx(elp->GetGvarStridx()).c_str()); + break; + case DW_OP_fbreg: + EmitHexUnsigned(1 + NameMangler::GetSleb128Size(elp->GetFboffset())); + Emit("\n\t.byte "); + EmitHexUnsigned(elp->GetOp()); + Emit("\n\t.sleb128 "); + EmitDecSigned(elp->GetFboffset()); + break; + default: + EmitHexUnsigned(uintptr_t(elp)); + break; + } + } break; + default: + CHECK_FATAL(maple::get_DW_FORM_name(attr->dwform_) != nullptr, + "get_DW_FORM_name return null in Emitter::EmitDIAttrValue"); + LogInfo::MapleLogger() << "unhandled : " << maple::get_DW_FORM_name(attr->dwform_) << endl; + CG_ASSERT(0, "NYI"); + } +} + +void Emitter::EmitDIDebugInfoSection(DebugInfo *mirdi) { + // From DWARF Standard Specification V4. 7.5.1 + // collect section size + Emit("\t.section\t.debug_info,\"\",@progbits\n"); + // label to mark start of the .debug_info section + Emit(".L" XSTR(DEBUG_INFO_0) ":\n"); + // $ 7.5.1.1 + Emit("\t.4byte\t"); + EmitHexUnsigned(mirdi->debug_info_length_); + Emit(" // section length\n"); + // DWARF version. uhalf. + Emit("\t.2byte\t0x" XSTR(DWARF_VERSION) "\n"); // 4 for version 4. + // debug_abbrev_offset. 4byte for 32-bit, 8byte for 64-bit + Emit("\t.4byte\t.L" XSTR(DEBUG_ABBREV_0) "\n"); + // address size. ubyte + Emit("\t.byte\t0x" XSTR(SIZEOFPTR) "\n"); + /* + * 7.5.1.2 type unit header + * currently empty... + * + * 7.5.2 Debugging Information Entry (DIE) + */ + Emitter *emitter = this; + MapleVector &abbrevVec = mirdi->abbrev_vec_; + ApplyInPrefixOrder(mirdi->cu_, [&abbrevVec, &emitter, &mirdi](DBGDie *die) { + if (!die) { + // emit the null entry and return + emitter->Emit("\t.byte 0x0\n"); + return; + } + bool verbose = emitter->cg_->GenerateVerboseAsm(); + if (verbose) { + emitter->Emit("\n"); + } + emitter->Emit("\t.uleb128 "); + emitter->EmitHexUnsigned(die->abbrevid_); + if (verbose) { + emitter->Emit("\t// "); + CHECK_FATAL(maple::get_DW_TAG_name(die->tag_) != nullptr, + "get_DW_TAG_name(die->tag_) return null in Emitter::EmitDIDebugInfoSection"); + emitter->Emit(maple::get_DW_TAG_name(die->tag_)); + emitter->Emit(" Offset= "); + emitter->EmitHexUnsigned(die->Offset); + emitter->Emit(" ("); + emitter->EmitDecUnsigned(die->Offset); + emitter->Emit(" ), Size= "); + emitter->EmitHexUnsigned(die->Size); + emitter->Emit(" ("); + emitter->EmitDecUnsigned(die->Size); + emitter->Emit(" )\n"); + } else { + emitter->Emit("\n"); + } + DBGAbbrevEntry *diae = LFindAbbrevEntry(abbrevVec, die->abbrevid_); + CHECK_FATAL(diae != nullptr, "diae is null in Emitter::EmitDIDebugInfoSection"); + MapleVector &apl = diae->attrpairs_; // attribute pair list + + for (int i = 0; i < diae->attrpairs_.size(); i += 2) { + DBGDieAttr *attr = LFindAttribute(die->attrvec_, dw_at(apl[i])); + if (!LShouldEmit(unsigned(apl[i + 1]))) { + continue; + } + emitter->Emit("\t"); + emitter->EmitDIFormSpecification(unsigned(apl[i + 1])); + emitter->EmitDIAttrValue(die, attr, unsigned(apl[i]), diae->tag_, mirdi); + if (verbose) { + emitter->Emit("\t// "); + emitter->Emit(maple::get_DW_AT_name(unsigned(apl[i]))); + emitter->Emit(" : "); + emitter->Emit(maple::get_DW_FORM_name(unsigned(apl[i + 1]))); + if (apl[i + 1] == DW_FORM_strp || apl[i + 1] == DW_FORM_string) { + emitter->Emit(" : "); + emitter->Emit(GlobalTables::GetStrTable().GetStringFromStrIdx(attr->val_.id).c_str()); + } else if (apl[i] == DW_AT_data_member_location) { + emitter->Emit(" : "); + emitter->Emit(apl[i + 1]).Emit(" attr= "); + emitter->EmitHexUnsigned(uintptr_t(attr)); + } + } + emitter->Emit("\n"); + } + }); +} + +void Emitter::EmitDIDebugAbbrevSection(DebugInfo *mirdi) { + Emit("\t.section\t.debug_abbrev,\"\",@progbits\n"); + Emit(".L" XSTR(DEBUG_ABBREV_0) ":\n"); + + // construct a list of DI abbrev entries + // 1. DW_TAG_compile_unit 0x11 + // 2. DW_TAG_subprogram 0x2e + bool verbose = cg_->GenerateVerboseAsm(); + for (DBGAbbrevEntry *diae : mirdi->abbrev_vec_) { + if (!diae) { + continue; + } + // ID + if (verbose) { + Emit("\n"); + } + Emit("\t.uleb128 "); + EmitHexUnsigned(diae->abbrevid_); + if (verbose) { + Emit("\t// Abbrev Entry ID"); + } + Emit("\n"); + // TAG + Emit("\t.uleb128 "); + EmitHexUnsigned(diae->tag_); + CHECK_FATAL(maple::get_DW_TAG_name(diae->tag_) != nullptr, + "get_DW_TAG_name return null in Emitter::EmitDIDebugAbbrevSection"); + if (verbose) { + Emit("\t// "); + Emit(maple::get_DW_TAG_name(diae->tag_)); + } + Emit("\n"); + + MapleVector &apl = diae->attrpairs_; // attribute pair list + // children? + Emit("\t.byte "); + EmitHexUnsigned(diae->withchildren_); + if (verbose) { + Emit(diae->withchildren_ ? "\t// DW_CHILDREN_yes" : "\t// DW_CHILDREN_no"); + } + Emit("\n"); + + for (int i = 0; i < diae->attrpairs_.size(); i += 2) { + // odd entry -- DW_AT_*, even entry -- DW_FORM_* + Emit("\t.uleb128 "); + EmitHexUnsigned(apl[i]); + CHECK_FATAL(maple::get_DW_AT_name(unsigned(apl[i])) != nullptr, + "get_DW_AT_name return null in Emitter::EmitDIDebugAbbrevSection"); + if (verbose) { + Emit("\t// "); + Emit(maple::get_DW_AT_name(unsigned(apl[i]))); + } + Emit("\n"); + Emit("\t.uleb128 "); + EmitHexUnsigned(apl[i + 1]); + CHECK_FATAL(maple::get_DW_FORM_name(unsigned(apl[i + 1])) != nullptr, + "get_DW_FORM_name return null in Emitter::EmitDIDebugAbbrevSection"); + if (verbose) { + Emit("\t// "); + Emit(maple::get_DW_FORM_name(unsigned(apl[i + 1]))); + } + Emit("\n"); + } + // end of an abbreviation record + Emit("\t.byte 0x0\n"); + Emit("\t.byte 0x0\n"); + } + Emit("\t.byte 0x0\n"); +} + +void Emitter::EmitDIDebugARangesSection() { + Emit("\t.section\t.debug_aranges,\"\",@progbits\n"); +} + +void Emitter::EmitDIDebugRangesSection() { + Emit("\t.section\t.debug_ranges,\"\",@progbits\n"); +} + +void Emitter::EmitDIDebugLineSection() { + Emit("\t.section\t.debug_line,\"\",@progbits\n"); + Emit(".L" XSTR(DEBUG_LINE_0) ":\n"); +} + +void Emitter::EmitDIDebugStrSection() { + Emit("\t.section\t.debug_str,\"MS\",@progbits,1\n"); + for (auto it : cg_->mirModule->dbgInfo->strps_) { + Emit(".L" XSTR(DEBUG_STR_LABEL)); + out << it; + Emit(":\n"); + const string &name = GlobalTables::GetStrTable().GetStringFromStrIdx(it); + Emit("\t.string \"").Emit(name).Emit("\"\n"); + } +} + +void Emitter::FillInClassByteSize(DBGDie *die, DBGDieAttr *byteSizeAttr, DBGAbbrevEntry *diae) { + CG_ASSERT(byteSizeAttr->dwform_ == DW_FORM_data1 || byteSizeAttr->dwform_ == DW_FORM_data2 || + byteSizeAttr->dwform_ == DW_FORM_data4 || byteSizeAttr->dwform_ == DW_FORM_data8, + "Unknown FORM value for DW_AT_byte_size"); + if (byteSizeAttr->val_.i == static_cast(kDbgDefaultVal)) { + // get class size + DBGDieAttr *nameAttr = LFindDieAttr(die, DW_AT_name); + CHECK_FATAL(nameAttr != nullptr, "name_attr is nullptr in Emitter::FillInClassByteSize"); + TyIdx tyIdx = + GlobalTables::GetTypeNameTable().GetTyIdxFromGStrIdx(GStrIdx(nameAttr->val_.id)); // hope this is a global string index as it is a type name + CHECK_FATAL(tyIdx.GetIdx() < g->becommon->type_size_table.size(), "index out of range in Emitter::FillInClassByteSize"); + int64_t byteSize = g->becommon->type_size_table[tyIdx.GetIdx()]; + LUpdateAttrValue(byteSizeAttr, byteSize, diae); + } +} + +void Emitter::SetupDBGInfo(DebugInfo *mirdi) { + Emitter *emitter = this; + MapleVector &abbrevVec = mirdi->abbrev_vec_; + ApplyInPrefixOrder(mirdi->cu_, [&abbrevVec, &emitter](DBGDie *die) { + if (!die) { + return; + } + + CHECK_FATAL(maple::get_DW_TAG_name(die->tag_) != nullptr, + "maple::get_DW_TAG_name(die->tag_) is nullptr in Emitter::SetupDBGInfo"); + if (die->abbrevid_ == 0) { + LogInfo::MapleLogger() << maple::get_DW_TAG_name(die->tag_) << endl; + } + CHECK_FATAL(die->abbrevid_ < abbrevVec.size(), "index out of range in Emitter::SetupDBGInfo"); + CG_ASSERT(abbrevVec[die->abbrevid_]->abbrevid_ == die->abbrevid_, ""); + DBGAbbrevEntry *diae = abbrevVec[die->abbrevid_]; + switch (diae->tag_) { + case DW_TAG_subprogram: { + DBGExprLoc *exprloc = emitter->memPool->New(emitter->cg_->mirModule); + exprloc->simploc_->dwop_ = DW_OP_call_frame_cfa; + die->SetAttr(DW_AT_frame_base, exprloc); + } break; + case DW_TAG_structure_type: + case DW_TAG_class_type: + case DW_TAG_interface_type: { + DBGDieAttr *byteSizeAttr = LFindDieAttr(die, DW_AT_byte_size); + if (byteSizeAttr) { + emitter->FillInClassByteSize(die, byteSizeAttr, diae); + } + // get the name + DBGDieAttr *atName = LFindDieAttr(die, DW_AT_name); + CHECK_FATAL(atName != nullptr, "at_name is null in Emitter::SetupDBGInfo"); + // get the type from string name + TyIdx ctyIdx = GlobalTables::GetTypeNameTable().GetTyIdxFromGStrIdx(GStrIdx(atName->val_.id)); + MIRType *mty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(ctyIdx); + MIRStructType *sty = static_cast(mty); + CHECK_FATAL(sty != nullptr, "pointer cast failed"); + CHECK_FATAL(sty->tyIdx.GetIdx() < g->becommon->struct_fieldcount_table.size(), ""); + int32_t myEnd = g->becommon->struct_fieldcount_table[sty->tyIdx.GetIdx()]; + int32_t myBegin = myEnd - sty->fields.size() + 1; + for (int i = myBegin; i <= myEnd; i++) { + int offset = g->becommon->GetFieldOffset(sty, i).first; + GStrIdx fldName = sty->fields[i - myBegin].first; + DBGDie *cdie = LFindChildDieWithName(die, DW_TAG_member, fldName); + CHECK_FATAL(cdie != nullptr, "cdie is null in Emitter::SetupDBGInfo"); + DBGDieAttr *mloc = LFindDieAttr(cdie, DW_AT_data_member_location); + CHECK_FATAL(mloc != nullptr, "mloc is null in Emitter::SetupDBGInfo"); + DBGAbbrevEntry *childDiae = abbrevVec[cdie->abbrevid_]; + CHECK_FATAL(childDiae != nullptr, "child_diae is null in Emitter::SetupDBGInfo"); + LUpdateAttrValue(mloc, offset, childDiae); + } + } break; + default: + break; + } + }); + + // compute DIE sizes and offsets + mirdi->ComputeSizeAndOffsets(); +} + +} // namespace maplebe diff --git a/mapleall/maple_be/src/cg/lvar.cpp b/mapleall/maple_be/src/cg/lvar.cpp index 86d3970..6dfedf7 100644 --- a/mapleall/maple_be/src/cg/lvar.cpp +++ b/mapleall/maple_be/src/cg/lvar.cpp @@ -25,10 +25,8 @@ void OptLocalRef::Run() { } AnalysisResult *CgDoOptLocalRef::Run(CGFunc *cgfunc, CgFuncResultMgr *m) { - if (CGOptions::doLvarPathOpt == false) { - return nullptr; - } - if (g->optim_level < 2) { + if (cgfunc->func->module->IsCModule() || (CGOptions::doLvarPathOpt == false) || + (g->optim_level < 2)) { return nullptr; } MemPool *refmp = mempoolctrler.NewMemPool("optlocalref"); diff --git a/mapleall/maple_be/src/cg/reaching_definition.cpp b/mapleall/maple_be/src/cg/reaching_definition.cpp index 23bebc8..f7335c4 100644 --- a/mapleall/maple_be/src/cg/reaching_definition.cpp +++ b/mapleall/maple_be/src/cg/reaching_definition.cpp @@ -353,9 +353,6 @@ bool ReachingDefinition::GenerateOut(BB *bb, setgen) { - if (m.first.GetOperand()->IsConditionCode() || m.first.GetOperand() == cgfunc->GetRflag()) { - continue; - } set tmpset; tmpset.insert(m.second); bb->out.insert(pair>(m.first, tmpset)); @@ -393,9 +390,6 @@ bool ReachingDefinition::GenerateIn(BB *bb, setpreds) { for (auto outElem : prevBB->out) { Operand *elemFirst = outElem.first.GetOperand(); - if (elemFirst->IsConditionCode() || elemFirst == cgfunc->GetRflag()) { - continue; - } map, DataAnalysisInfoCmp>::iterator itMap; itMap = bb->in.find(outElem.first); bool mayMultiGgen = CheckMultigenPossibility(bb, prevBB, outElem.first); diff --git a/mapleall/maple_be/src/cg/riscv64/riscv64_abi.cpp b/mapleall/maple_be/src/cg/riscv64/riscv64_abi.cpp new file mode 100644 index 0000000..4194bd5 --- /dev/null +++ b/mapleall/maple_be/src/cg/riscv64/riscv64_abi.cpp @@ -0,0 +1,703 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#include "riscv64_abi.h" +#include "riscv64_cg_func.h" +#include "be_common.h" +#include "cg_assert.h" + +namespace maplebe { + +using namespace maple; + +void ParmLocator::InitPlocInfo(PLocInfo &ploc) { + ploc.reg0 = kRinvalid; + ploc.reg1 = kRinvalid; + ploc.rsize0 = 0; + ploc.rsize1 = 0; + ploc.memoffset = NSAA; +} + +static Riscv64_ArgumentClass ClassifyIntFpScalar(PrimType ty) { + switch (ty) { + case PTY_u1: + case PTY_u8: + case PTY_i8: + case PTY_u16: + case PTY_i16: + case PTY_a32: + case PTY_u32: + case PTY_i32: + case PTY_a64: + case PTY_ptr: + case PTY_ref: + case PTY_u64: + case PTY_i64: + return kRiscv64IntegerClass; + case PTY_f32: + case PTY_f64: + return kRiscv64FloatClass; + default: + return kRiscv64NoClass; + } +} + +// This function ONLY handles FP Calling Convention, under which a riscv64 +// small struct can have at most 2 fields, it can reside in 2 fpregs or intreg+fpreg, +// as indicated by the referenced classes. Otherwise PTY_void is returned indicating +// the struct is to follow the subsequent Integer Calling Convention. +static PrimType TraverseStructFieldsForFp(MIRType *ty, uint32 &numregs, Riscv64_ArgumentClass classes[2], uint32 sizes[2]) { + if (numregs >= 2) { + return PTY_void; // only 2 registers max + } + + if (ty->typeKind == kTypeArray) { + MIRArrayType *arrtype = static_cast(ty); + MIRType *pty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(arrtype->eTyIdx); + if (pty->typeKind == kTypeArray || pty->typeKind == kTypeStruct) { + return TraverseStructFieldsForFp(pty, numregs, classes, sizes); + } + uint32 n = 0; // real size of array + for (uint32 i = 0; i < arrtype->dim; ++i) { + n += arrtype->sizeArray[i]; + } + if (n == 0 || n > 2) { + return PTY_void; + } + Riscv64_ArgumentClass ptyp = ClassifyIntFpScalar(pty->primType); + uint32 psz = GetPrimTypeSize(pty->primType); + if (ptyp != kRiscv64FloatClass) { + return PTY_void; + } + for (uint32 i = 0; i < n; i++) { + classes[i] = ptyp; + sizes[i] = psz; + } + numregs = n; // number of regs used + return pty->primType; + } else if (ty->typeKind == kTypeStruct) { + MIRStructType *sttype = static_cast(ty); + FieldVector fields = sttype->fields; + PrimType ptype = PTY_void; + for (uint32 fcnt = 0; fcnt < fields.size(); ++fcnt) { + TyIdx fieldtyidx = fields[fcnt].second.first; + MIRType *fieldty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(fieldtyidx); + ptype = TraverseStructFieldsForFp(fieldty, numregs, classes, sizes); + if (ptype == PTY_void) { + return PTY_void; + } + } + return ptype; // doesn't matter which one, as long as it's not PTY_void + } else if (ty->typeKind == kTypeUnion) { + return PTY_void; + } else { + classes[numregs] = ClassifyIntFpScalar(ty->primType); + sizes[numregs] = GetPrimTypeSize(ty->primType); + numregs++; + return ty->primType; + } +} + +static int32 ClassifyFpCCAggregate(BECommon &be, MIRType *ty, Riscv64_ArgumentClass classes[2], uint32 sizes[2]) { + uint32 sizeofty = be.type_size_table.at(ty->tyIdx.GetIdx()); + // to be handled by intCC + if (sizeofty > 16 || sizeofty == 0) { + return 0; + } + if (ty->typeKind == kTypeStruct) { + MIRStructType *sty = static_cast(ty); + FieldVector fields = sty->fields; + uint32 numregs = 0; + if (fields.size() > 2) { + return 0; + } + for (uint32 fcnt = 0; fcnt < fields.size(); ++fcnt) { + TyIdx fieldtyidx = fields[fcnt].second.first; + MIRType *fieldty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(fieldtyidx); + PrimType ptype = TraverseStructFieldsForFp(fieldty, numregs, classes, sizes); + if (ptype == PTY_void) { + return 0; + } + } + if (numregs == 1 && classes[0] == kRiscv64FloatClass) { + return 1; + } else if (numregs == 2 && + ((classes[0] == kRiscv64FloatClass && classes[0] == classes[1]) || + (classes[0] == kRiscv64FloatClass && classes[1] == kRiscv64IntegerClass) || + (classes[0] == kRiscv64IntegerClass && classes[1] == kRiscv64FloatClass))) { + return 2; + } else { + classes[0] = kRiscv64NoClass; + classes[1] = kRiscv64NoClass; + return 0; + } + } + return 0; +} + +// return 0 -- to be passed on stack +// return 1 -- one intreg +// return 2 -- either 2 intregs or +// 1 intreg (kRiscv64IntegerClass) + 1 stack (kRiscv64MemoryClass) +static int32 ClassifyIntCCAggregate(BECommon &be, MIRType *ty, Riscv64_ArgumentClass classes[2]) { + uint32 sizeofty = be.type_size_table.at(ty->tyIdx.GetIdx()); + if (sizeofty > 16 || sizeofty == 0) { + return 0; + } + + // An argument of any Integer class takes up an integer register + // which is a single double-word. + int32 sizeoftyInDwords = RoundUp(sizeofty, 8) >> 3; + CG_ASSERT(sizeoftyInDwords == 1 || sizeoftyInDwords == 2, ""); + classes[0] = kRiscv64NoClass; + classes[1] = kRiscv64NoClass; + + if (ty->typeKind != kTypeStruct && ty->typeKind != kTypeUnion && ty->typeKind != kTypeArray) { + // scalar type + switch (ty->GetPrimType()) { + case PTY_u1: + case PTY_u8: + case PTY_i8: + case PTY_u16: + case PTY_i16: + case PTY_a32: + case PTY_u32: + case PTY_i32: + case PTY_a64: + case PTY_ptr: + case PTY_ref: + case PTY_u64: + case PTY_i64: + classes[0] = kRiscv64IntegerClass; + return 1; + case PTY_f32: + case PTY_f64: + CG_ASSERT(0, "FP argument not possible here"); + default: + CG_ASSERT(false, ""); + } + // should not reach to this point + return 0; + } else { + // struct, union and array + classes[0] = kRiscv64IntegerClass; + if (sizeoftyInDwords == 2) { + classes[1] = kRiscv64IntegerClass; + } + return sizeoftyInDwords; + } + return 0; +} + +int32 ParmLocator::LocateRetValue(MIRType *retty, PLocInfo &ploc) { + InitPlocInfo(ploc); + uint32 retsz = _be.type_size_table[retty->tyIdx.GetIdx()]; + if (retsz == 0) { + // For return struct size 0 there is no return value. + return 0; + } else if (retsz <= 16) { + // For return struct size less or equal to 16 bytes, the values + // are returned in register pairs. + Riscv64_ArgumentClass classes[2]; // Max of four floats. + uint32 sizes[2]; + int32 numregs = ClassifyFpCCAggregate(_be, retty, classes, sizes); + ploc.memsize = retsz; + if (numregs) { + if (classes[0] == kRiscv64FloatClass) { + ploc.reg0 = AllocateReturnFPRegister(); + } else { + ploc.reg0 = AllocateReturnGPRegister(); + } + ploc.rsize0 = sizes[0]; + if (numregs == 2) { + if (classes[1] == kRiscv64FloatClass) { + ploc.reg1 = AllocateReturnFPRegister(); + } else { + ploc.reg1 = AllocateReturnGPRegister(); + } + ploc.rsize1 = sizes[1]; + } + } else { // use IntCC + numregs = ClassifyIntCCAggregate(_be, retty, classes); + CG_ASSERT(numregs, "Invalid numregs from IntCC"); + ploc.reg0 = AllocateReturnGPRegister(); + ploc.rsize0 = 8; + if (numregs == 2) { + ploc.reg1 = AllocateReturnGPRegister(); + ploc.rsize1 = (retsz > 8 && retsz <= 12) ? 4 : 8; + } + } + } else { + // For return struct size > 16 bytes the pointer returns in a0 + ploc.reg0 = AllocateGPRegister(); + ploc.rsize0 = 8; + ploc.memsize = retsz; + } + return 0; +} + +// LocateNextParm should be called with each parameter in the parameter list +// starting from the beginning, one call per parameter in sequence; it returns +// the information on how each parameter is passed in ploc +int32 ParmLocator::LocateNextParm(MIRType *ty, PLocInfo &ploc, bool isFirst, bool isVararg) { + InitPlocInfo(ploc); + if (isFirst) { + MIRFunction *func = _be.mirModule.CurFunction(); + auto funcIt = _be.funcReturnType.find(func); + if (funcIt != _be.funcReturnType.end()) { + TyIdx retidx = funcIt->second; + uint32 retsz = _be.type_size_table[retidx.GetIdx()]; + if (retsz == 0) { + // For return struct size 0 there is no return value. + return 0; + } else if (retsz <= 16) { + // For return struct size less or equal to 16 bytes, the values + // are returned in register pairs. + Riscv64_ArgumentClass classes[2]; // Max of four floats. + MIRType *retty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(retidx); + + uint32 sizes[2]; + int32 numregs = ClassifyFpCCAggregate(_be, ty, classes, sizes); + ploc.memsize = retsz; + if (numregs) { + if (classes[0] == kRiscv64FloatClass) { + ploc.reg0 = AllocateReturnFPRegister(); + } else { + ploc.reg0 = AllocateReturnGPRegister(); + } + ploc.rsize0 = sizes[0]; + if (numregs == 2) { + if (classes[1] == kRiscv64FloatClass) { + ploc.reg1 = AllocateReturnFPRegister(); + } else { + ploc.reg1 = AllocateReturnGPRegister(); + } + ploc.rsize1 = sizes[1]; + } + } else { // use IntCC + numregs = ClassifyIntCCAggregate(_be, retty, classes); + CG_ASSERT(numregs, "Invalid numregs from IntCC"); + ploc.reg0 = AllocateReturnGPRegister(); + ploc.rsize0 = 8; + if (numregs == 2) { + ploc.reg1 = AllocateReturnGPRegister(); + ploc.rsize1 = (retsz > 8 && retsz <= 12) ? 4 : 8; + } + } + } else { + // For return struct size > 16 bytes the pointer returns in a0 + ploc.reg0 = AllocateGPRegister(); + ploc.rsize0 = 8; + ploc.memsize = retsz; + } + return 0; + } + } + int typesize = _be.type_size_table.at(ty->tyIdx.GetIdx()); + if (typesize == 0) { + return 0; + } + int typealign = _be.type_align_table[ty->tyIdx.GetIdx()]; + CG_ASSERT((NSAA & (std::max(typealign, 8) - 1)) == 0, "alignment requirement is violated"); + ploc.memsize = typesize; + _parm_num++; + + // Do Floating Point Calling Convention first + int32 aggCopySize = 0; + PrimType pt = isVararg ? PTY_void : ty->GetPrimType(); // intCC only for vararg + switch (pt) { + case PTY_f32: + case PTY_f64: + CG_ASSERT(GetPrimTypeSize(PTY_f64) == 8, ""); + typesize = 8; // 8 bytes + ploc.reg0 = AllocateSIMDFPRegister(); + if (ploc.reg0 == kRinvalid) { + break; // no register, continue with IntCC + } + ploc.rsize0 = GetPrimTypeSize(ty->GetPrimType()); + return 0; + break; + + case PTY_c64: + CG_ASSERT(0, "Complex type not supported"); + break; + + case PTY_agg: { + Riscv64_ArgumentClass classes[2]; // Max of 2 values, can be int, fp + // or (invalid) redo it in intCC below + + if (ty->typeKind == kTypeUnion) + break; // move to intCC below + + ploc.memsize = typesize; + if (typesize > 16) { + aggCopySize = RoundUp(typesize, SIZEOFPTR); + } + if (typealign == 16) { + RoundNGRNUpToNextEven(); + } + + uint32 sizes[2]; + int32 numregs = ClassifyFpCCAggregate(_be, ty, classes, sizes); + CHECK_FATAL(numregs <= 2, "LocateNextParm: illegal number of regs"); + if (numregs == 1 ) { + if (classes[0] == kRiscv64FloatClass) { + AllocateNSIMDFPRegisters(ploc, numregs); + } else if (classes[0] == kRiscv64IntegerClass) { + ploc.reg0 = AllocateGPRegister(); + } else { + CHECK_FATAL(0, "LocateNextParam: illegal class returned"); + } + if (ploc.reg0 == kRinvalid) { + break; // no fpreg, continue with IntCC + } + ploc.rsize0 = sizes[0]; + return 0; // 0 aggCopySize, in reg + } else if (numregs == 2) { + CHECK_FATAL(!(classes[0] == kRiscv64IntegerClass && classes[0] == classes[1]), + "FpCC must not have 2 intregs"); + if (classes[0] == kRiscv64FloatClass) { + ploc.reg0 = AllocateSIMDFPRegister(); + } else if (classes[0] == kRiscv64IntegerClass) { + ploc.reg0 = AllocateGPRegister(); + } + if (ploc.reg0 == kRinvalid) { + break; // no 1st int/fpreg, continue with IntCC + } + if (classes[1] == kRiscv64FloatClass) { + ploc.reg1 = AllocateSIMDFPRegister(); + } else if (classes[1] == kRiscv64IntegerClass) { + ploc.reg1 = AllocateGPRegister(); + } + if (ploc.reg1 == kRinvalid) { + break; // no 2nd int/fpreg, continue with IntCC + } + ploc.rsize0 = sizes[0]; + ploc.rsize1 = sizes[1]; + return 0; // 0 aggCopySize, in regs + } + } // case PTY_agg + + default: + break; // continue in Integer Calling Convention + } + + // Start Integer Calling Convention + int32 numregs = 0; + Riscv64reg_t tReg; + switch (ty->GetPrimType()) { + case PTY_u1: + case PTY_u8: + case PTY_i8: + case PTY_u16: + case PTY_i16: + case PTY_a32: + case PTY_u32: + case PTY_i32: + case PTY_ptr: + case PTY_ref: + case PTY_a64: + case PTY_u64: + case PTY_i64: + case PTY_f32: + case PTY_f64: + CG_ASSERT(GetPrimTypeSize(PTY_i64) == 8, ""); + typesize = 8; // 8 bytes + ploc.reg0 = AllocateGPRegister(); + if (ploc.reg0 != kRinvalid) { + ploc.rsize0 = GetPrimTypeSize(ty->GetPrimType()); + } + CG_ASSERT(NGRN <= Riscv64Abi::kNumIntParmRegs, ""); + break; + + case PTY_agg: { + Riscv64_ArgumentClass classes[2]; + ploc.memsize = typesize; + if (typesize > 16) { + aggCopySize = RoundUp(typesize, SIZEOFPTR); + } + + numregs = ClassifyIntCCAggregate(_be, ty, classes); + if (numregs == 1) { // passing in registers + typesize = 8; + if (classes[0] == kRiscv64FloatClass) { + CHECK_FATAL(0, "PTY_agg: param passing in FP reg not allowed."); + } else { + ploc.reg0 = AllocateGPRegister(); + if (ploc.reg0 != kRinvalid) { + ploc.rsize0 = (typesize > 4) ? 8 : 4; + } + CG_ASSERT(ploc.reg0 != kRinvalid || NGRN <= Riscv64Abi::kNumIntParmRegs, ""); + } + } else if (numregs == 2) { + ploc.reg0 = AllocateGPRegister(); + if (ploc.reg0 != kRinvalid) { + ploc.rsize0 = 8; + } + ploc.reg1 = AllocateGPRegister(); + if (ploc.reg1 != kRinvalid) { + if (typesize > 12) { // 1st: 8, 2nd: 8 + ploc.rsize1 = 8; + } else if (typesize > 8 && typesize <= 12) { // 1st: 8, 2nd: 4 + ploc.rsize1 = 4; + } + } else if (ploc.reg0 != kRinvalid) { + ploc.memsize -= 8; // 1st half in reg, 2nd half on stack + } + } else { + // 0 returned from ClassifyIntCCAggregate(). This means the whole data + // is passed thru memory, typesize > 16 + // + // Try to allocate an intreg for addr + typesize = 8; + ploc.reg0 = AllocateGPRegister(); + ploc.memsize = 8; + if (ploc.reg0 != kRinvalid) { + ploc.rsize0 = 8; + numregs = 1; + } + } + // compute rightpad + if (numregs == 0 || ploc.reg0 == kRinvalid || + (numregs == 2 && ploc.reg0 != kRinvalid && ploc.reg1 == kRinvalid)) { + int32 paddSize = RoundUp(ploc.memsize, 8); + typesize = paddSize; + } + break; + } // case PTY_agg + + default: + CG_ASSERT(false, ""); + break; + } // intCC + + if (ploc.reg0 == kRinvalid || + (numregs == 2 && ploc.reg0 != kRinvalid && ploc.reg1 == kRinvalid)) { + // being passed in memory + NSAA = ploc.memoffset + typesize; + } + return aggCopySize; +} + +// instantiated with the type of the function return value, it describes how +// the return value is to be passed back to the caller +ReturnMechanism::ReturnMechanism(MIRType *retty, BECommon &be) + : regcount(0), reg0(kRinvalid), reg1(kRinvalid), ptype0(kPtyInvalid), ptype1(kPtyInvalid) { + PrimType primType = retty->GetPrimType(); + switch (primType) { + case PTY_void: + break; + case PTY_u1: + case PTY_u8: + case PTY_i8: + case PTY_u16: + case PTY_i16: + case PTY_a32: + case PTY_u32: + case PTY_i32: + regcount = 1; + reg0 = Riscv64Abi::int_return_regs[0]; + ptype0 = IsSignedInteger(primType) ? PTY_i32 : PTY_u32; // promote the type + return; + + case PTY_ptr: + case PTY_ref: + CHECK_FATAL(false, "PTY_ptr should have been lowered", ""); + + case PTY_a64: + case PTY_u64: + case PTY_i64: + regcount = 1; + reg0 = Riscv64Abi::int_return_regs[0]; + ptype0 = IsSignedInteger(primType) ? PTY_i64 : PTY_u64; // promote the type + return; + + /* + for c64 complex numbers, we assume + - callers marshall the two f32 numbers into one f64 register + - callees de-marshall one f64 value into the real and the imaginery part + */ + case PTY_f32: + case PTY_f64: + case PTY_c64: + regcount = 1; + reg0 = Riscv64Abi::float_return_regs[0]; + ptype0 = primType; + return; + + /* + for c128 complex numbers, we assume + - callers marshall the two f64 numbers into one f128 register + - callees de-marshall one f128 value into the real and the imaginery part + */ + case PTY_c128: + regcount = 1; + reg0 = Riscv64Abi::float_return_regs[0]; + ptype0 = primType; + return; + + // Otherwise, the caller shall reserve a block of memory of + // sufficient size and alignment to hold the result. The + // address of the memory block shall be passed as an additional + // argument to the function in a0. The callee may modify the + // result memory block at any point during the execution of the + // subroutine (there is no requirement for the callee to preserve + // the value stored in a0)." + case PTY_agg: { + uint64 size = be.type_size_table.at(retty->tyIdx.GetIdx()); + if (size > 16 || size == 0) { + // The return value is returned via memory. + // The address is in a0 and passed by the caller. + SetupToReturnThroughMemory(); + return; + } + Riscv64_ArgumentClass classes[2]; + uint32 sizes[2]; + uint32 intRegCnt = 0; + uint32 fpRegCnt = 0; + regcount = ClassifyFpCCAggregate(be, retty, classes, sizes); + ptype0 = ptype1 = PTY_i64; + if (regcount) { + if (classes[0] == kRiscv64FloatClass) { + reg0 = Riscv64Abi::float_return_regs[fpRegCnt++]; + ptype0 = sizes[0] <= 4 ? PTY_f32 : PTY_f64; + } else { + reg0 = Riscv64Abi::int_return_regs[intRegCnt++]; + } + if (regcount == 2) { + if (classes[1] == kRiscv64FloatClass) { + reg1 = Riscv64Abi::float_return_regs[fpRegCnt++]; + ptype1 = sizes[1] <= 4 ? PTY_f32 : PTY_f64; + } else { + reg1 = Riscv64Abi::int_return_regs[intRegCnt++]; + } + } + } else { // use IntCC + regcount = ClassifyIntCCAggregate(be, retty, classes); + if (regcount) { + reg0 = Riscv64Abi::int_return_regs[0]; + if (regcount == 2) { + reg1 = Riscv64Abi::int_return_regs[1]; + } + } else { + SetupToReturnThroughMemory(); // should never happen? + } + } + return; + } + + default: + CHECK_FATAL(0, "NYI"); + return; + } +} + +void ReturnMechanism::SetupSecondRetReg(MIRType *retty2) { + CG_ASSERT(reg1 == kRinvalid, ""); + PrimType primType = retty2->GetPrimType(); + switch (primType) { + case PTY_void: + break; + case PTY_u1: + case PTY_u8: + case PTY_i8: + case PTY_u16: + case PTY_i16: + case PTY_a32: + case PTY_u32: + case PTY_i32: + case PTY_ptr: + case PTY_ref: + case PTY_a64: + case PTY_u64: + case PTY_i64: + reg1 = Riscv64Abi::int_return_regs[1]; + ptype1 = IsSignedInteger(primType) ? PTY_i64 : PTY_u64; // promote the type + break; + default: + CG_ASSERT(false, "NYI"); + } +} + +/* + From "ARM Procedure Call Standard for ARM 64-bit Architecture" + ARM IHI 0055C_beta, 6th November 2013 + $ 5.1 machine Registers + $ 5.1.1 General-Purpose Registers + Note + SP Stack Pointer + R30/LR Link register Stores the return address. + We push it into stack along with FP on function + entry using STP and restore it on function exit + using LDP even if the function is a leaf (i.e., + it does not call any other function) because it + is free (we have to store FP anyway). So, if a + function is a leaf, we may use it as a temporary + register. + R29/FP Frame Pointer + R19-R28 Callee-saved + registers + R18 Platform reg Can we use it as a temporary register? + R16,R17 IP0,IP1 Maybe used as temporary registers. Should be + given lower priorities. (i.e., we push them + into the free register stack before the others) + R9-R15 Temporary registers, caller-saved + + + + Note: + R16 and R17 may be used by a linker as a scratch register between + a routine and any subroutine it calls. They can also be used within a + routine to hold intermediate values between subroutine calls. + + The role of R18 is platform specific. If a platform ABI has need of + a dedicated general purpose register to carry inter-procedural state + (for example, the thread context) then it should use this register for + that purpose. If the platform ABI has no such requirements, then it should + use R18 as an additional temporary register. The platform ABI specification + must document the usage for this register. + + A subroutine invocation must preserve the contents of the registers R19-R29 + and SP. All 64 bits of each value stored in R19-R29 must be preserved, even + when using the ILP32 data model. + + $ 5.1.2 SIMD and Floating-Point Registers + + The first eight registers, V0-V7, are used to pass argument values into + a subroutine and to return result values from a function. They may also + be used to hold intermediate values within a routine. + + V8-V15 must be preserved by a callee across subroutine calls; the + remaining registers do not need to be preserved( or caller-saved). + Additionally, only the bottom 64 bits of each value stored in V8- + V15 need to be preserved. + + */ +/* + Temporary registers: basically, caller-saved. + if one is alive after a call, the caller should spill it and reload it after the control returns from the call. + + parameter passing : they are basically caller-saved, temporary except their values are defined on entry + and not available initially. + + then, callee-saved. If a function wants to use it, unless the function is the start of function execution (i.e., + main) it has to stash the old value, and restore it before the control leaves the function. + + so, there are two kinds. caller-saved, temporary and callee-saved + We allocate registers from caller-saved first, then calee-saved if the former runs out. + We also need to have float-type register files as well. + */ + +} // namespace maplebe diff --git a/mapleall/maple_be/src/cg/riscv64/riscv64_cg.cpp b/mapleall/maple_be/src/cg/riscv64/riscv64_cg.cpp new file mode 100644 index 0000000..c70f351 --- /dev/null +++ b/mapleall/maple_be/src/cg/riscv64/riscv64_cg.cpp @@ -0,0 +1,339 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#include +#include +#include + +#include "riscv64_rt_support.h" +#include "riscv64_cg.h" +#include "cg_assert.h" +#include "mir_builder.h" +#include "be_common.h" +#include "special_func.h" + +using namespace std; + +namespace maplebe { + +#include "riscv64_opnd.def" +#define DEFINE_MOP(op,a2,a3,a4,a5,a6,a7,a8,a9,aa,ab,ac) {op,a2,a3,a4,a5,a6,a7,a8,a9,aa,ab,ac}, +const Riscv64MD Riscv64CG::kMd[kMopLast] = { +#include "riscv64_md.def" +}; +#undef DEFINE_MOP + +bool Riscv64CG::IsExclusiveFunc(MIRFunction *mirFunc) { + const std::string &funcname = mirFunc->GetName(); + for (auto it : eh_exclusive_name_vec) { + if (it.compare(funcname) == 0) { + return true; + } + } + return false; +} + +// Generate object maps. +// +// Currently, object maps are generated in a separate section +// (OBJECT_MAP_SECTION_NAME) of the resulting ELF image together with GCTIBs. A +// GCTIB starts with a label (GCTIB_PREFIX_STR + ClassName), followed by the +// GCTIB content as described in `mapleall/runtime/doc/object-layout.markdown`. +// +// For example, if a scalar object has five ptr fields at offsets 0, 8, 24, 40, +// 64, the generated code will be like: +// +// MCC_GCTIB__TheClassName: +// .quad 1 // one word in the bitmap +// .quad 0x12b // 0xab = 100101011 +// ... + +static const uint32_t kBitsPerMapWord = 64; +static const uint32_t kLogBitsPerMapWord = 6; +#ifdef USE_32BIT_REF +static const uint32_t kReferenceWordSize = 4; +static const uint32_t kLog2ReferenceWordSize = 2; +#else +static const uint32_t kReferenceWordSize = 8; +static const uint32_t kLog2ReferenceWordSize = 3; +#endif +static const uint32_t kInMapWordOffsetMask = (((kReferenceWordSize * kBitsPerMapWord)) - 1); +static const uint32_t kInMapWordIndexShift = (kLog2ReferenceWordSize); +static const uint32_t kMapWordIndexShift = (kLog2ReferenceWordSize + kLogBitsPerMapWord); +/* + * Give a structrue type, calculate its bitmap_vector + */ +static void GetGCTIBBitMapWords(BECommon &becommon, MIRStructType *structty, vector &bitmapWords) { + bitmapWords.clear(); + if (structty->typeKind == kTypeClass) { + uint64_t curBitmap = 0; + uint32_t curBitmapIndex = 0; + uint32_t prevOffset = 0; + for (auto fieldInfo : becommon.GetJClassLayout(static_cast(structty))) { + if (fieldInfo.is_ref) { + uint32_t curOffset = fieldInfo.offset; + // skip meta field + if (curOffset == 0) { + continue; + } + CHECK_FATAL(curOffset > prevOffset || (prevOffset == 0), "not ascending offset"); + uint32_t wordIndex = curOffset >> kMapWordIndexShift; + if (wordIndex > curBitmapIndex) { + bitmapWords.push_back(curBitmap); + for (uint32_t i = curBitmapIndex + 1; i < wordIndex; i++) { + bitmapWords.push_back(0); + } + curBitmap = 0; + curBitmapIndex = wordIndex; + } + uint32_t bit_offset = (curOffset & kInMapWordOffsetMask) >> kInMapWordIndexShift; + if (fieldInfo.is_unowned == false) { + // ref + curBitmap |= ((((uint64_t)1) << bit_offset)); + } + prevOffset = curOffset; + } + } + if (curBitmap != 0) { + bitmapWords.push_back(curBitmap); + } + } else if (structty->typeKind != kTypeInterface) { + // interface doesn't have reference fields + CHECK_FATAL(false, "GetGCTIBBitMapWords unexpected type"); + } +} + +/* + * Find if there exist same GCTIB (both rcheader and bitmap are smae) + * for different class. If ture reuse, if not emit and record new GCTIB. + */ +void Riscv64CG::FindOrCreateRepresentiveSym(vector &bitmapWords, uint32_t rcHeader, string name) { + GCTIBKey *key = mirModule->memPool->New(rcHeader, bitmapWords); + string gctibName = GCTIB_PREFIX_STR + name; + unordered_map::const_iterator iter = key2pattern.find(*key); + + if (iter == key2pattern.end()) { + // Emit the GCTIB label for the class + GCTIBPattern *ptn = mirModule->memPool->New(*key); + + string str = GCTIB_PREFIX_STR + string(NameMangler::kJavaLangObjectStr); + if (gctibName.compare(str) == 0) { + ptn->SetName(str); + } + key2pattern.insert(make_pair(*key, *ptn)); + sym2pattern.insert(make_pair(gctibName, *ptn)); + + // Emit GCTIB pattern + string ptnString = "\t.type " + ptn->GetName() + ", \%object\n" + "\t.data\n" + "\t.align 3\n"; + + MIRSymbol *gctibSym = GlobalTables::GetGsymTable().GetSymbolFromStrIdx(GlobalTables::GetStrTable().GetStrIdxFromName(gctibName.c_str())); + if (gctibSym && gctibSym->GetStorageClass() == kScFstatic) { + ptnString += "\t.local "; + } else { + ptnString += "\t.global "; + } + + emitter_->Emit(ptnString); + emitter_->Emit(ptn->GetName()); + emitter_->Emit("\n"); + + // Emit the GCTIB pattern label for the class + emitter_->Emit(ptn->GetName()); + emitter_->Emit(":\n"); + + emitter_->Emit("\t.long "); + emitter_->EmitHexUnsigned(rcHeader); + emitter_->Emit("\n"); + + // generate n_bitmap word + emitter_->Emit("\t.long "); // Riscv64-specific. Generate a 64-bit value. + emitter_->EmitDecUnsigned(bitmapWords.size()); + emitter_->Emit("\n"); + + // Emit each bitmap word + for (auto bitmapWord : bitmapWords) { + if (!DoItQuietly()) { + printf(" bitmap_word: 0x%" PRIx64 "\n", bitmapWord); + } + emitter_->Emit("\t.quad "); // Riscv64-specific. Generate a 64-bit value. + emitter_->EmitHexUnsigned(bitmapWord); + emitter_->Emit("\n"); + } + } else { + sym2pattern.insert(make_pair(gctibName, iter->second)); + } +} + +string Riscv64CG::FindGCTIBPatternName(const string &name) { + CHECK_FATAL(sym2pattern.find(name) != sym2pattern.end(), "No GCTIB pattern found for symbol: %s", name.c_str()); + + unordered_map::const_iterator iter = sym2pattern.find(name); + CHECK_FATAL(iter != sym2pattern.end(), "map find return error"); + return iter->second.GetName(); +} + +void Riscv64CG::GenerateObjectMaps(BECommon &becommon) { + if (!DoItQuietly()) { + printf("DEBUG: Generating object maps...\n"); + } + + // Create a new section for object map. + // emitter_->emit(".section "); + // emitter_->emit(RTSupport::OBJECT_MAP_SECTION_NAME); + // No "w" flag indicates this is read-only + // emitter_->emit(", \"a\", @progbits\n"); + + for (auto tyid : mirModule->classList) { + if (!DoItQuietly()) { + printf("Class tyIdx: %" PRIu32 "\n", tyid); + } + TyIdx tyIdx(tyid); + MIRType *ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx); + + // Only emit GCTIB for classes owned by this module + CHECK_FATAL(dynamic_cast(ty) != nullptr, "ty isn't MIRStructType* in Riscv64CG::GenerateObjectMaps"); + if (!dynamic_cast(ty)->IsLocal()) { + continue; + } + + GStrIdx nameIdx = ty->nameStrIdx; + + const string &name = GlobalTables::GetStrTable().GetStringFromStrIdx(nameIdx); + + // Emit for a class + if (!DoItQuietly()) { + printf(" name: %s\n", name.c_str()); + } + + MIRStructType *strty = dynamic_cast(ty); + if (strty != nullptr) { + vector bitmapWords; + GetGCTIBBitMapWords(becommon, strty, bitmapWords); + uint32_t rcHeader = (bitmapWords.size() > 0) ? 0x40 : 0; + FindOrCreateRepresentiveSym(bitmapWords, rcHeader, name); + } else { + if (!DoItQuietly()) { + printf(" ** Not a struct. This is weird, because it is from the class list.\n"); + } + } + } +} + +void Riscv64Insn::CheckOpnd(Operand *opnd, OpndProp *prop) { + Riscv64OpndProp *mopd = static_cast(prop); + CG_ASSERT(mopd, "an empty operand"); + switch (opnd->op_kind_) { + case Operand::Opd_Register: + CG_ASSERT(mopd->opnd_ty_ == Operand::Opd_Register, "expect reg"); + break; + case Operand::Opd_Immediate: + CG_ASSERT(mopd->opnd_ty_ == Operand::Opd_Immediate, "expect imm"); + break; + case Operand::Opd_FPImmediate: + CG_ASSERT(mopd->opnd_ty_ == Operand::Opd_FPImmediate, "expect fpimm"); + break; + case Operand::Opd_FPZeroImmediate: + CG_ASSERT(mopd->opnd_ty_ == Operand::Opd_FPZeroImmediate, "expect fpzero"); + break; + case Operand::Opd_Mem: + CG_ASSERT(mopd->opnd_ty_ == Operand::Opd_Mem, "expect mem"); + break; + case Operand::Opd_BbAddress: + CG_ASSERT(mopd->opnd_ty_ == Operand::Opd_BbAddress, "expect address"); + break; + case Operand::Opd_List: + CG_ASSERT(mopd->opnd_ty_ == Operand::Opd_List, "expect list operand"); + break; + case Operand::Opd_Cond: + CG_ASSERT(mopd->opnd_ty_ == Operand::Opd_Cond, "expect cond operand"); + break; + case Operand::Opd_Shift: + CG_ASSERT(mopd->opnd_ty_ == Operand::Opd_Shift, "expect LSL operand"); + break; + case Operand::Opd_StImmediate: + CG_ASSERT(mopd->opnd_ty_ == Operand::Opd_StImmediate, "expect symbol name (literal)"); + break; + case Operand::Opd_String: + CG_ASSERT(mopd->opnd_ty_ == Operand::Opd_String, "expect a string"); + break; + default: + CG_ASSERT(false, "NYI"); + } +} + +bool Riscv64Insn::Check() { + MOperator mop = GetMachineOpcode(); + const Riscv64MD *md = &Riscv64CG::kMd[mop]; + for (int i = 0; i < kMaxOperandNum; ++i) { + Operand *opnd = GetOperand(i); + // maybe if !opnd, break ? + if (opnd) { + CheckOpnd(opnd, md->operand_[i]); + } + } + return true; +} + +void Riscv64Insn::dump() { + MOperator mop = GetMachineOpcode(); + const Riscv64MD *md = &Riscv64CG::kMd[mop]; + + LogInfo::MapleLogger() << "< " << id << " > "; + LogInfo::MapleLogger() << md->name_ << "(" << mop << ")"; + + for (int i = 0; i < kMaxOperandNum; ++i) { + Operand *opnd = GetOperand(i); + // maybe if !opnd, break ? + if (opnd) { + LogInfo::MapleLogger() << " (opnd" << i << ": "; + opnd->dump(); + LogInfo::MapleLogger() << ")"; + } + } + LogInfo::MapleLogger() << std::endl; +} + +bool Riscv64Insn::IsDefinition() const { + // check if we are seeing ldp or not + CG_ASSERT(!Riscv64CG::kMd[mop_].GetOperand(1) || !Riscv64CG::kMd[mop_].GetOperand(1)->IsRegDef(), ""); + if (Riscv64CG::kMd[mop_].GetOperand(0) == nullptr) { + return false; + } + return Riscv64CG::kMd[mop_].GetOperand(0)->IsRegDef(); +} + +bool Riscv64Insn::IsDestRegAlsoSrcReg() const { + Riscv64OpndProp *prop0 = static_cast(Riscv64CG::kMd[mop_].GetOperand(0)); + return prop0->IsRegDef() && prop0->IsRegUse(); +} + +bool Riscv64Insn::IsDataMoveInstruction() const { + return ((Riscv64CG::kMd[mop_].properties_ & ISMOVE) != 0); +} + +bool Riscv64Insn::IsConversionInstruction() const { + return ((Riscv64CG::kMd[mop_].properties_ & ISCONVERSION) != 0); +} + +bool Riscv64Insn::IsConditionalSet() const { + return ((Riscv64CG::kMd[mop_].properties_ & ISCONDSET) != 0); +} + +RegOperand *Riscv64Insn::GetOperandDefined() { + CG_ASSERT(IsDefinition(), ""); + return static_cast(GetOperand(0)); +} + +} // namespace maplebe diff --git a/mapleall/maple_be/src/cg/riscv64/riscv64_cg_func.cpp b/mapleall/maple_be/src/cg/riscv64/riscv64_cg_func.cpp new file mode 100644 index 0000000..b1487a7 --- /dev/null +++ b/mapleall/maple_be/src/cg/riscv64/riscv64_cg_func.cpp @@ -0,0 +1,5253 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#include "riscv64_cg_func.h" +#include "riscv64_cg.h" +#include "cfi.h" +#include "cg_assert.h" +#include +#include "reflection_analysis.h" +#include "special_func.h" +#include "riscv64_schedule.h" + +#define SOE_CHCK_OFFSET 8192 +namespace maplebe { + +using namespace maple; +const int kFreqBase = 10000; +enum RegsPushPop { + kRegsPushOp, + kRegsPopOp, +}; + +#define PUSH_POP_SINGLE 0 +#define PUSH_POP_PAIR 1 +#define PUSH_POP_VECTOR 2 + +#define CLANG (mirModule.IsCModule()) + +static MOperator pushPopOps[2][3][3] /*[2]*/ = { { + /* push */ + { /*undef*/ 0 }, + { + /*kRegTyInt*/ + /* single */ MOP_xstr, + /* pair */ MOP_undef, + }, + { + /*kRegTyFloat*/ + /* single */ MOP_dstr, + /* pair */ MOP_undef, + /* vector */MOP_undef, + }, + }, + { + /* pop */ + { /*undef*/ 0 }, + { + /*kRegTyInt*/ + /* single */ MOP_xldr, + /* pair */ MOP_undef, + }, + { + /*kRegTyFloat*/ + /* single */ MOP_dldr, + /* pair */ MOP_undef, + /* vector */MOP_undef, + }, + } }; + +static inline void AppendInstructionTo(Insn *i, CGFunc *f) { + f->curbb->AppendInsn(i); +} + +Operand *Riscv64CGFunc::GetZeroOpnd(uint32_t size) { + return Riscv64RegOperand::GetZeroRegister(size <= 32 ? 32 : 64); +} + +bool Riscv64CGFunc::IsFrameReg(RegOperand *opnd) { + uint32_t fpno = UseFP() ? 30 : 32; + if (opnd->GetRegisterNumber() == fpno) { + return true; + } else { + return false; + } +} + +bool Riscv64CGFunc::NeedCleanup() { + Riscv64MemLayout *layout = static_cast(memlayout); + if (layout->GetSizeOfRefLocals() > 0) { + return true; + } + for (uint32 i = 0; i < func->formalDefVec.size(); i++) { + TypeAttrs tA = func->formalDefVec[i].formalAttrs; + if (tA.GetAttr(ATTR_localrefvar)) { + return true; + } + } + // On-stack non-escaped objects always need cleanup + if (hasNonescapedVar) { + return true; + } + + return false; +} + +Schedule *Riscv64CGFunc::NewSchedule(CGFunc *cgfunc, MemPool* mp, LiveAnalysis *live, const char *phaseName) { + return mp->New(cgfunc, mp, live, phaseName); +} + +void Riscv64CGFunc::HandleParamRCDec() { + if (!cg->GenLocalRC()) { + // handle local rc is disabled. + return; + } + + MIRSymbol *sym = nullptr; + for (uint32 i = 0; i < func->formalDefVec.size(); i++) { + sym = func->formalDefVec[i].formalSym; + TypeAttrs tA = func->formalDefVec[i].formalAttrs; + if (!tA.GetAttr(ATTR_localrefvar)) { + continue; + } + + RegOperand *phyopnd = GetOrCreatePhysicalRegisterOperand(R0, 64, kRegTyInt); + if (sym->IsPreg()) { + PregIdx pregIdx = func->pregTab->GetPregIdxFromPregNo(sym->GetPreg()->pregNo); + RegOperand *dstRegopnd = GetOrCreateVirtualRegisterOperand(GetVirtualRegNoFromPseudoRegIdx(pregIdx)); + int datasize = GetPrimTypeSize(sym->GetPreg()->primType) * BITS_PER_BYTE; + MOperator mop = PickMovInsn(datasize, kRegTyInt); + + Insn *ins = cg->BuildInstruction(mop, phyopnd, dstRegopnd); + curbb->AppendInsn(ins); + + } else { + PrimType symty = sym->GetType()->primType; + int datasize = GetPrimTypeSize(symty) * BITS_PER_BYTE; + MemOperand *memopnd = GetOrCreateMemOpnd(sym, 0, datasize); + CHECK_FATAL(static_cast(memopnd), + "static_cast(memopnd) is null in Riscv64CGFunc::HandleParamRCDec"); + if (IsImmediateOffsetOutOfRange(static_cast(memopnd), datasize)) { + memopnd = SplitOffsetWithAddInstruction(static_cast(memopnd), datasize); + } + + Insn *ldInsn = cg->BuildInstruction(PickLdInsn(64, symty), phyopnd, memopnd); + curbb->AppendInsn(ldInsn); + } + Riscv64ListOperand *srcOpnds = memPool->New(funcscope_allocator_); + srcOpnds->PushOpnd(phyopnd); + MIRSymbol *callsym = GlobalTables::GetGsymTable().CreateSymbol(kScopeGlobal); + std::string funcname(GetIntrinsicFuncName(INTRN_MCCDecRef)); + callsym->SetNameStridx(GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(funcname)); + callsym->storageClass = kScText; + callsym->sKind = kStFunc; + + Operand *targetopnd = GetOrCreateFuncNameOpnd(callsym); + Insn *callInsn = cg->BuildInstruction(MOP_xbl, targetopnd, srcOpnds); + curbb->AppendInsn(callInsn); + + curbb->SetKind(BB::kBBCall); + BB *newbb = CreateNewBB(); + curbb->AppendBB(newbb); + // now all stmts has been handled + newbb->frequency = curbb->frequency; + curbb = newbb; + } +} + +// bb must be the cleanup bb. +// this function must be invoked before register allocation. +// extended epilogue is specific for fast exception handling and is made up of +// clean up code and epilogue. +// clean up code is generated here while epilogue is generated in GeneratePrologEpilog() +void Riscv64CGFunc::GenerateCleanupCodeForExtEpilog(BB *bb) { + CG_ASSERT(lastbb->prev->firststmt == cleanup_label, "must be"); + + if (NeedCleanup()) { + // this is necessary for code insertion. + curbb = bb; + + Riscv64RegOperand *regr0 = + GetOrCreatePhysicalRegisterOperand(R0, SIZEOFPTR * BITS_PER_BYTE, kRegTyInt); + Riscv64RegOperand *regr1 = + GetOrCreatePhysicalRegisterOperand(R1, SIZEOFPTR * BITS_PER_BYTE, kRegTyInt); + Riscv64MemOperand *frameAlloc = CreateCallFrameOperand(-16, SIZEOFPTR * BITS_PER_BYTE); + Insn *allocInsn = cg->BuildInstruction(MOP_xstr, regr0, frameAlloc); + allocInsn->do_not_remove = true; + AppendInstructionTo(allocInsn, this); + frameAlloc = CreateCallFrameOperand(-8, SIZEOFPTR * BITS_PER_BYTE); + allocInsn = cg->BuildInstruction(MOP_xstr, regr1, frameAlloc); + allocInsn->do_not_remove = true; + AppendInstructionTo(allocInsn, this); + + // invoke MCC_CleanupLocalStackRef(). + HandleRCCall(false); + // handle special ref param + HandleParamRCDec(); + + Riscv64MemOperand *frameDealloc = CreateCallFrameOperand(16, SIZEOFPTR * BITS_PER_BYTE); + Insn *deallocInsn = cg->BuildInstruction(MOP_xldr, regr0, frameDealloc); + deallocInsn->do_not_remove = true; + AppendInstructionTo(deallocInsn, this); + frameDealloc = CreateCallFrameOperand(24, SIZEOFPTR * BITS_PER_BYTE); + deallocInsn = cg->BuildInstruction(MOP_xldr, regr1, frameDealloc); + deallocInsn->do_not_remove = true; + AppendInstructionTo(deallocInsn, this); + // Update cleanupbb since bb may have been splitted + cleanupbb = curbb; + } +} + +// bb must be the cleanup bb. +// this function must be invoked before register allocation. +void Riscv64CGFunc::GenerateCleanupCode(BB *bb) { + CG_ASSERT(lastbb->prev->firststmt == cleanup_label, "must be"); + + if (!NeedCleanup()) { + return; + } + + // this is necessary for code insertion. + curbb = bb; + + // R0 is lived-in for clean-up code, save R0 before invocation + Riscv64RegOperand *livein = GetOrCreatePhysicalRegisterOperand(R0, 64, kRegTyInt); + RegOperand *backupRegop = nullptr; + + if (!cg->GenLocalRC()) { + // by pass local RC operations. + } else if (g->optim_level > 0) { + regno_t vreg = New_V_Reg(kRegTyInt, GetPrimTypeSize(PTY_a64)); + backupRegop = CreateVirtualRegisterOperand(vreg); + backupRegop->SetRegNotBBLocal(); + SelectCopy(backupRegop, PTY_a64, livein, PTY_a64); + + // invoke MCC_CleanupLocalStackRef(). + HandleRCCall(false); + // handle special ref param + HandleParamRCDec(); + SelectCopy(livein, PTY_a64, backupRegop, PTY_a64); + } else { + // Register Allocation for O0 can not handle this case, so use a callee saved register directly. + // If yieldpoint is enabled, we use R20 instead R19. + Riscv64reg_t backupRegno = cg->GenYieldpoint() ? R20 : R19; + backupRegop = GetOrCreatePhysicalRegisterOperand(backupRegno, 64, kRegTyInt); + SelectCopy(backupRegop, PTY_a64, livein, PTY_a64); + // invoke MCC_CleanupLocalStackRef(). + HandleRCCall(false); + // handle special ref param + HandleParamRCDec(); + SelectCopy(livein, PTY_a64, backupRegop, PTY_a64); + } + + // invoke _Unwind_Resume + std::string funcname("_Unwind_Resume"); + MIRSymbol *sym = GlobalTables::GetGsymTable().CreateSymbol(kScopeGlobal); + sym->SetNameStridx(GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(funcname)); + sym->storageClass = kScText; + sym->sKind = kStFunc; + Riscv64ListOperand *srcOpnds = memPool->New(funcscope_allocator_); + srcOpnds->PushOpnd(livein); + Operand *targetopnd = GetOrCreateFuncNameOpnd(sym); + Insn *callInsn = cg->BuildInstruction(MOP_xbl, targetopnd, srcOpnds); + curbb->AppendInsn(callInsn); + + curbb->SetKind(BB::kBBCall); + BB *newbb = CreateNewBB(); + if (firstbb->frequency != 0) { + newbb->frequency = kFreqBase / 100; + } + curbb->AppendBB(newbb); + curbb = newbb; + + // this instruction is unreachable, but we need it as the return address of previous + // "bl _Unwind_Resume" for stack unwinding. + Insn *nop = cg->BuildInstruction(MOP_xblr, livein, srcOpnds); + curbb->AppendInsn(nop); + + curbb->SetKind(BB::kBBCall); + newbb = CreateNewBB(); + if (firstbb->frequency != 0) { + newbb->frequency = kFreqBase / 100; + } + curbb->AppendBB(newbb); + curbb = newbb; + // Update cleanupbb since bb may have been splitted + cleanupbb = curbb; +} + +void Riscv64CGFunc::AppendInstructionPushSingle(Riscv64reg_t reg, RegType rty, int offset) { + MOperator mop = pushPopOps[kRegsPushOp][rty][PUSH_POP_SINGLE]; + Operand *o0 = GetOrCreatePhysicalRegisterOperand(reg, SIZEOFPTR * BITS_PER_BYTE, rty); + Operand *o1 = CreateStkTopOpnd(offset, SIZEOFPTR * BITS_PER_BYTE); + + uint32 datasize = SIZEOFPTR * BITS_PER_BYTE; + if (IsImmediateOffsetOutOfRange(static_cast(o1), datasize)) { + o1 = SplitOffsetWithAddInstruction(static_cast(o1), datasize, R9); + } + + Insn *pushInsn = cg->BuildInstruction(mop, o0, o1); + string comment = "SAVE"; + pushInsn->AddComment(comment); + AppendInstructionTo(pushInsn, this); + + // Append CFI code + if (cg->GenerateCfiDirectives()) { + int64 stackFrameSize = static_cast(memlayout)->RealStackFrameSize(); + if (cg->UseFP() || HasVLAOrAlloca()) { + stackFrameSize -= memlayout->SizeOfArgsToStackpass(); + } + int cfiOffset = stackFrameSize - offset; + curbb->InsertInsnAfter(pushInsn, + cg->BuildInstruction(cfi::OP_CFI_offset, CreateCfiRegOperand(reg, 64), + CreateCfiImmOperand(-cfiOffset, 64))); + } +} + +void Riscv64CGFunc::AppendInstructionPushRZRPair(Riscv64reg_t reg0, Riscv64reg_t reg1, int offset) { + Operand *o0 = nullptr; + Operand *o1 = nullptr; + if (reg0 == RZERO) { + o0 = GetZeroOpnd(64); + } else { + o0 = GetOrCreatePhysicalRegisterOperand(reg0, SIZEOFPTR * BITS_PER_BYTE, kRegTyInt); + } + + if (reg1 == RZERO) { + o1 = GetZeroOpnd(64); + } else { + o1 = GetOrCreatePhysicalRegisterOperand(reg1, SIZEOFPTR * BITS_PER_BYTE, kRegTyInt); + } + + Operand *o2 = CreateStkTopOpnd(offset, SIZEOFPTR * BITS_PER_BYTE); + + uint32 datasize = SIZEOFPTR * BITS_PER_BYTE; + CG_ASSERT(offset >= 0, ""); + if (offset > STP_LDP_IMM64_UPPER_BOUND) { + o2 = SplitStpLdpOffsetForCalleeSavedWithAddInstruction(static_cast(o2), datasize, Riscv64Abi::kIntSpareReg); + } + Insn *push_insn = cg->BuildInstruction(MOP_xstr, o0, o2); + AppendInstructionTo(push_insn, this); + o2 = CreateStkTopOpnd(offset + 8, SIZEOFPTR * BITS_PER_BYTE); + if (offset > STP_LDP_IMM64_UPPER_BOUND) { + o2 = SplitStpLdpOffsetForCalleeSavedWithAddInstruction(static_cast(o2), datasize, Riscv64Abi::kIntSpareReg); + } + push_insn = cg->BuildInstruction(MOP_xstr, o1, o2); + AppendInstructionTo(push_insn, this); + + // Append CFi code + if (cg->GenerateCfiDirectives()) { + int64 stackFrameSize = static_cast(memlayout)->RealStackFrameSize(); + if (cg->UseFP() || HasVLAOrAlloca()) { + stackFrameSize -= memlayout->SizeOfArgsToStackpass(); + } + int cfi_offset = stackFrameSize - offset; + if (reg0 != RZERO) { + push_insn = curbb->InsertInsnAfter( + push_insn, cg->BuildInstruction(cfi::OP_CFI_offset, CreateCfiRegOperand(reg0, 64), + CreateCfiImmOperand(-cfi_offset, 64))); + } + if (reg1 != RZERO) { + curbb->InsertInsnAfter(push_insn, + cg->BuildInstruction(cfi::OP_CFI_offset, CreateCfiRegOperand(reg1, 64), + CreateCfiImmOperand(-cfi_offset + 8, 64))); + } + } +} + +// if offset < 0, allocation; otherwise, deallocation +Riscv64MemOperand *Riscv64CGFunc::CreateCallFrameOperand(int32 offset, int32 size) { + CHECK_FATAL(0, "NYI"); +} + +void Riscv64CGFunc::AppendInstructionAllocateCallFrame(Riscv64reg_t reg0, Riscv64reg_t reg1, RegType rty) { + if (cg->GenerateVerboseAsm()) { + curbb->AppendInsn( + cg->BuildInstruction(MOP_comment, CreateCommentOperand("allocate activation frame"))); + } + + Insn *ipoint = nullptr; + // stack_frame_size includes the size of args to stack-pass + // if a function has neither VLA nor alloca. + int64 stackFrameSize = static_cast(memlayout)->RealStackFrameSize(); + int64 argsToStkpassSize = memlayout->SizeOfArgsToStackpass(); + // ldp/stp's imm should be within -512 and 504; + // if stp's imm > 512, we fall back to the stp-sub version + bool useStpSub = false; + int64 offset = 0; + int cfiOffset = 0; + if (!HasVLAOrAlloca() && argsToStkpassSize > 0) { + // stack_frame_size == size of formal parameters + callee-saved (including FP/RL) + // + size of local vars + // + size of actuals + // (when passing more than 8 args, its caller's responsibility to + // allocate space for it. size of actuals represent largest such size in the function. + Operand *spOpnd = GetOrCreatePhysicalRegisterOperand(RSP, 64, kRegTyInt); + Operand *immopnd = CreateImmOperand(stackFrameSize, 32, true); + SelectSub(spOpnd, spOpnd, immopnd, PTY_u64); + ipoint = curbb->lastinsn; + cfiOffset = stackFrameSize; + } else { + if (stackFrameSize > STP_LDP_IMM64_UPPER_BOUND) { + useStpSub = true; + offset = 16; + stackFrameSize -= offset; + } else { + offset = stackFrameSize; + } + MOperator mop = pushPopOps[kRegsPushOp][rty][PUSH_POP_SINGLE]; + Riscv64RegOperand *o0 = GetOrCreatePhysicalRegisterOperand(reg0, SIZEOFPTR * BITS_PER_BYTE, rty); + Riscv64MemOperand *o1 = CreateCallFrameOperand(-offset, SIZEOFPTR * BITS_PER_BYTE); + Insn *allocInsn = cg->BuildInstruction(mop, o0, o1); + AppendInstructionTo(allocInsn, this); + o0 = GetOrCreatePhysicalRegisterOperand(reg1, SIZEOFPTR * BITS_PER_BYTE, rty); + Riscv64OfstOperand *ofopnd = GetOrCreateOfstOpnd(SIZEOFPTR, 32); + Riscv64RegOperand *rsp = GetOrCreatePhysicalRegisterOperand(RSP, SIZEOFPTR * 8, kRegTyInt); + o1 = GetOrCreateMemOpnd(SIZEOFPTR * BITS_PER_BYTE, rsp, nullptr, ofopnd, 0); + allocInsn = cg->BuildInstruction(mop, o0, o1); + AppendInstructionTo(allocInsn, this); + ipoint = allocInsn; + cfiOffset = offset; + if (cg->NeedInsertInstrumentationFunction()) { + AppendCall(cg->GetInstrumentationFunction()); + } else if (cg->InstrumentWithDebugTraceCall()) { + AppendCall(cg->GetDebugTraceEnterFunction()); + } else if (cg->InstrumentWithProfile()) { + AppendCall(cg->GetProfileFunction()); + } + } + + if (cg->GenerateCfiDirectives()) { + ipoint = InsertCFIDefCfaOffset(cfiOffset, ipoint); + } + + if (!HasVLAOrAlloca() && argsToStkpassSize > 0) { + CG_ASSERT(!useStpSub, "Invalid assumption"); + MOperator mop = pushPopOps[kRegsPushOp][rty][PUSH_POP_PAIR]; + Insn *allocInsn = nullptr; + if (argsToStkpassSize > STP_LDP_IMM64_UPPER_BOUND) { + if (argsToStkpassSize <= STR_LDR_IMM64_UPPER_BOUND - 8) { + mop = pushPopOps[kRegsPushOp][rty][PUSH_POP_SINGLE]; + Riscv64RegOperand *o0 = GetOrCreatePhysicalRegisterOperand(reg0, SIZEOFPTR * BITS_PER_BYTE, rty); + Riscv64MemOperand *o2 = memPool->New(RSP, argsToStkpassSize, SIZEOFPTR * BITS_PER_BYTE); + allocInsn = cg->BuildInstruction(mop, o0, o2); + AppendInstructionTo(allocInsn, this); + Riscv64RegOperand *o1 = GetOrCreatePhysicalRegisterOperand(reg1, SIZEOFPTR * BITS_PER_BYTE, rty); + o2 = memPool->New(RSP, argsToStkpassSize + SIZEOFPTR, SIZEOFPTR * BITS_PER_BYTE); + allocInsn = cg->BuildInstruction(mop, o1, o2); + AppendInstructionTo(allocInsn, this); + } else { + Riscv64RegOperand *oo = GetOrCreatePhysicalRegisterOperand(R9, SIZEOFPTR * BITS_PER_BYTE, kRegTyInt); + Riscv64ImmOperand *io = CreateImmOperand(argsToStkpassSize, 64, true); + SelectCopyImm(oo, io, PTY_i64); + + Riscv64RegOperand *o0 = GetOrCreatePhysicalRegisterOperand(reg0, SIZEOFPTR * BITS_PER_BYTE, rty); + Riscv64RegOperand *rsp = GetOrCreatePhysicalRegisterOperand(RSP, SIZEOFPTR * 8, kRegTyInt); + AppendInstructionTo(cg->BuildInstruction(MOP_xaddrrr, oo, rsp, oo), this); + Riscv64OfstOperand *ofopnd = GetOrCreateOfstOpnd(0, 32); + Riscv64MemOperand *mo = GetOrCreateMemOpnd(SIZEOFPTR * BITS_PER_BYTE, oo, nullptr, ofopnd, 0); + allocInsn = cg->BuildInstruction(MOP_xstr, o0, mo); + AppendInstructionTo(allocInsn, this); + + io = CreateImmOperand(SIZEOFPTR, 64, true); + SelectAdd(oo, oo, io, PTY_i64); + + Riscv64RegOperand *o1 = GetOrCreatePhysicalRegisterOperand(reg1, SIZEOFPTR * BITS_PER_BYTE, rty); + ofopnd = GetOrCreateOfstOpnd(0, 32); + mo = GetOrCreateMemOpnd(SIZEOFPTR * BITS_PER_BYTE, oo, nullptr, ofopnd, 0); + allocInsn = cg->BuildInstruction(MOP_xstr, o1, mo); + AppendInstructionTo(allocInsn, this); + } + } else { + Operand *o0 = GetOrCreatePhysicalRegisterOperand(reg0, SIZEOFPTR * BITS_PER_BYTE, rty); + Operand *o1 = GetOrCreatePhysicalRegisterOperand(reg1, SIZEOFPTR * BITS_PER_BYTE, rty); + Operand *o2 = memPool->New(RSP, argsToStkpassSize, SIZEOFPTR * BITS_PER_BYTE); + Operand *o3 = memPool->New(RSP, argsToStkpassSize+SIZEOFPTR, SIZEOFPTR * BITS_PER_BYTE); + //allocInsn = cg->BuildInstruction(mop, o0, o1, o2); + allocInsn = cg->BuildInstruction(mop, o0, o2); + AppendInstructionTo(allocInsn, this); + allocInsn = cg->BuildInstruction(mop, o1, o3); + AppendInstructionTo(allocInsn, this); + } + ipoint = allocInsn; + if (cg->NeedInsertInstrumentationFunction()) { + AppendCall(cg->GetInstrumentationFunction()); + } else if (cg->InstrumentWithDebugTraceCall()) { + AppendCall(cg->GetDebugTraceEnterFunction()); + } else if (cg->InstrumentWithProfile()) { + AppendCall(cg->GetProfileFunction()); + } + } + + if (useStpSub) { + Operand *spOpnd = GetOrCreatePhysicalRegisterOperand(RSP, 64, kRegTyInt); + Operand *immopnd = CreateImmOperand(stackFrameSize, 32, true); + SelectSub(spOpnd, spOpnd, immopnd, PTY_u64); + ipoint = curbb->lastinsn; + this->used_stp_sub_pair_to_allocate_call_frame = true; + } + + if (cg->GenerateCfiDirectives()) { + CG_ASSERT(ipoint, "ipoint should not be nullptr at this point"); + cfiOffset = 0; + if (useStpSub) { + cfiOffset = stackFrameSize; + ipoint = InsertCFIDefCfaOffset(cfiOffset, ipoint); + } + cfiOffset = GetOffsetFromCFA(); + if (!HasVLAOrAlloca()) { + cfiOffset -= argsToStkpassSize; + } + ipoint = curbb->InsertInsnAfter(ipoint, + cg->BuildInstruction(cfi::OP_CFI_offset, CreateCfiRegOperand(RFP, 64), + CreateCfiImmOperand(-cfiOffset, 64))); + (void)curbb->InsertInsnAfter(ipoint, + cg->BuildInstruction(cfi::OP_CFI_offset, CreateCfiRegOperand(RRA, 64), + CreateCfiImmOperand(-cfiOffset + 8, 64))); + } +} + +void Riscv64CGFunc::AppendInstructionAllocateCallFrameDebug(Riscv64reg_t reg0, Riscv64reg_t reg1, RegType rty) { + if (cg->GenerateVerboseAsm()) { + curbb->AppendInsn( + cg->BuildInstruction(MOP_comment, CreateCommentOperand("allocate activation frame for debugging"))); + } + + int64 stackFrameSize = static_cast(memlayout)->RealStackFrameSize(); + int64 argsToStkpassSize = memlayout->SizeOfArgsToStackpass(); + + Insn *ipoint = nullptr; + int cfiOffset = 0; + + if (argsToStkpassSize > 0) { + Operand *spOpnd = GetOrCreatePhysicalRegisterOperand(RSP, 64, kRegTyInt); + Operand *immopnd = CreateImmOperand(stackFrameSize, 32, true); + SelectSub(spOpnd, spOpnd, immopnd, PTY_u64); + ipoint = curbb->lastinsn; + cfiOffset = stackFrameSize; + if (cg->GenerateCfiDirectives()) { + ipoint = InsertCFIDefCfaOffset(cfiOffset, ipoint); + } + + MOperator mop = pushPopOps[kRegsPushOp][rty][PUSH_POP_SINGLE]; + Insn *allocInsn = nullptr; + if (argsToStkpassSize > STP_LDP_IMM64_UPPER_BOUND) { + if (argsToStkpassSize <= STR_LDR_IMM64_UPPER_BOUND - 8) { + mop = pushPopOps[kRegsPushOp][rty][PUSH_POP_SINGLE]; + Riscv64RegOperand *o0 = GetOrCreatePhysicalRegisterOperand(reg0, SIZEOFPTR * BITS_PER_BYTE, rty); + Riscv64MemOperand *o2 = memPool->New(RSP, argsToStkpassSize, SIZEOFPTR * BITS_PER_BYTE); + allocInsn = cg->BuildInstruction(mop, o0, o2); + AppendInstructionTo(allocInsn, this); + if (cg->GenerateCfiDirectives()) { + ipoint = allocInsn; + cfiOffset = GetOffsetFromCFA() - argsToStkpassSize; + ipoint = curbb->InsertInsnAfter( + ipoint, cg->BuildInstruction(cfi::OP_CFI_offset, + CreateCfiRegOperand(RFP, 64), CreateCfiImmOperand(-cfiOffset, 64))); + } + + Riscv64RegOperand *o1 = GetOrCreatePhysicalRegisterOperand(reg1, SIZEOFPTR * BITS_PER_BYTE, rty); + o2 = memPool->New(RSP, argsToStkpassSize + SIZEOFPTR, SIZEOFPTR * BITS_PER_BYTE); + allocInsn = cg->BuildInstruction(mop, o1, o2); + AppendInstructionTo(allocInsn, this); + if (cg->GenerateCfiDirectives()) { + ipoint = allocInsn; + curbb->InsertInsnAfter( + ipoint, cg->BuildInstruction(cfi::OP_CFI_offset, + CreateCfiRegOperand(RRA, 64), CreateCfiImmOperand(-cfiOffset + 8, 64))); + } + } else { + Riscv64RegOperand *oo = GetOrCreatePhysicalRegisterOperand(R9, SIZEOFPTR * BITS_PER_BYTE, kRegTyInt); + Riscv64ImmOperand *io = CreateImmOperand(argsToStkpassSize, 64, true); + SelectCopyImm(oo, io, PTY_i64); + + Riscv64RegOperand *rsp = GetOrCreatePhysicalRegisterOperand(RSP, SIZEOFPTR * 8, kRegTyInt); + AppendInstructionTo(cg->BuildInstruction(MOP_xaddrrr, oo, rsp, oo), this); + + Riscv64RegOperand *o0 = GetOrCreatePhysicalRegisterOperand(reg0, SIZEOFPTR * BITS_PER_BYTE, rty); + Riscv64OfstOperand *ofopnd = GetOrCreateOfstOpnd(0, 32); + Riscv64MemOperand *mo = GetOrCreateMemOpnd(SIZEOFPTR * BITS_PER_BYTE, oo, nullptr, ofopnd, 0); + allocInsn = cg->BuildInstruction(MOP_xstr, o0, mo); + AppendInstructionTo(allocInsn, this); + if (cg->GenerateCfiDirectives()) { + ipoint = allocInsn; + cfiOffset = GetOffsetFromCFA() - argsToStkpassSize; + ipoint = curbb->InsertInsnAfter( + ipoint, cg->BuildInstruction(cfi::OP_CFI_offset, + CreateCfiRegOperand(RFP, 64), CreateCfiImmOperand(-cfiOffset, 64))); + } + + io = CreateImmOperand(SIZEOFPTR, 64, true); + SelectAdd(oo, oo, io, PTY_i64); + + Riscv64RegOperand *o1 = GetOrCreatePhysicalRegisterOperand(reg1, SIZEOFPTR * BITS_PER_BYTE, rty); + ofopnd = GetOrCreateOfstOpnd(0, 32); + mo = GetOrCreateMemOpnd(SIZEOFPTR * BITS_PER_BYTE, oo, nullptr, ofopnd, 0); + allocInsn = cg->BuildInstruction(MOP_xstr, o1, mo); + AppendInstructionTo(allocInsn, this); + if (cg->GenerateCfiDirectives()) { + ipoint = allocInsn; + curbb->InsertInsnAfter( + ipoint, cg->BuildInstruction(cfi::OP_CFI_offset, + CreateCfiRegOperand(RRA, 64), CreateCfiImmOperand(-cfiOffset + 8, 64))); + } + } + } else { + Operand *o0 = GetOrCreatePhysicalRegisterOperand(reg0, SIZEOFPTR * BITS_PER_BYTE, rty); + Operand *o1 = GetOrCreatePhysicalRegisterOperand(reg1, SIZEOFPTR * BITS_PER_BYTE, rty); + Operand *o2 = memPool->New(RSP, argsToStkpassSize, SIZEOFPTR * BITS_PER_BYTE); + Operand *o3 = memPool->New(RSP, argsToStkpassSize+SIZEOFPTR, SIZEOFPTR * BITS_PER_BYTE); + //allocInsn = cg->BuildInstruction(mop, o0, o1, o2); + allocInsn = cg->BuildInstruction(mop, o0, o2); + AppendInstructionTo(allocInsn, this); + if (cg->GenerateCfiDirectives()) { + ipoint = allocInsn; + cfiOffset = GetOffsetFromCFA() - argsToStkpassSize; + ipoint = curbb->InsertInsnAfter( + ipoint, cg->BuildInstruction(cfi::OP_CFI_offset, + CreateCfiRegOperand(RFP, 64), CreateCfiImmOperand(-cfiOffset, 64))); + } + allocInsn = cg->BuildInstruction(mop, o1, o3); + AppendInstructionTo(allocInsn, this); + if (cg->GenerateCfiDirectives()) { + ipoint = allocInsn; + curbb->InsertInsnAfter( + ipoint, cg->BuildInstruction(cfi::OP_CFI_offset, + CreateCfiRegOperand(RRA, 64), CreateCfiImmOperand(-cfiOffset + 8, 64))); + } + } + ipoint = allocInsn; + if (cg->NeedInsertInstrumentationFunction()) { + AppendCall(cg->GetInstrumentationFunction()); + } else if (cg->InstrumentWithDebugTraceCall()) { + AppendCall(cg->GetDebugTraceEnterFunction()); + } else if (cg->InstrumentWithProfile()) { + AppendCall(cg->GetProfileFunction()); + } + } else { + bool useStpSub = false; + + if (stackFrameSize > STP_LDP_IMM64_UPPER_BOUND) { + useStpSub = true; + Riscv64RegOperand *spOpnd = GetOrCreatePhysicalRegisterOperand(RSP, 64, kRegTyInt); + ImmOperand *immopnd = CreateImmOperand(stackFrameSize, 32, true); + SelectSub(spOpnd, spOpnd, immopnd, PTY_u64); + ipoint = curbb->lastinsn; + cfiOffset = stackFrameSize; + if (cg->GenerateCfiDirectives()) { + ipoint = InsertCFIDefCfaOffset(cfiOffset, ipoint); + } + } else { + // Generate new sp + RegOperand *rsp = GetOrCreatePhysicalRegisterOperand(RSP, SIZEOFPTR * 8, kRegTyInt); + ImmOperand *iopnd = CreateImmOperand(-stackFrameSize, 32, true); + Insn *spAdd = cg->BuildInstruction(MOP_xaddrri12, rsp, rsp, iopnd); + AppendInstructionTo(spAdd, this); + ipoint = spAdd; + cfiOffset = stackFrameSize; + if (cg->GenerateCfiDirectives()) { + ipoint = InsertCFIDefCfaOffset(cfiOffset, ipoint); + } + // Save regs on new stack + MOperator mop = pushPopOps[kRegsPushOp][rty][PUSH_POP_SINGLE]; + Riscv64RegOperand *o0 = GetOrCreatePhysicalRegisterOperand(reg0, SIZEOFPTR * BITS_PER_BYTE, rty); + Riscv64OfstOperand *ofopnd = GetOrCreateOfstOpnd(0, 32); + Riscv64MemOperand *o1 = GetOrCreateMemOpnd(SIZEOFPTR * BITS_PER_BYTE, rsp, nullptr, ofopnd, 0); + Insn *allocInsn = cg->BuildInstruction(mop, o0, o1); + AppendInstructionTo(allocInsn, this); + if (cg->GenerateCfiDirectives()) { + ipoint = allocInsn; + cfiOffset = GetOffsetFromCFA() - argsToStkpassSize; + ipoint = curbb->InsertInsnAfter( + ipoint, cg->BuildInstruction(cfi::OP_CFI_offset, + CreateCfiRegOperand(RFP, 64), CreateCfiImmOperand(-cfiOffset, 64))); + } + o0 = GetOrCreatePhysicalRegisterOperand(reg1, SIZEOFPTR * BITS_PER_BYTE, rty); + ofopnd = GetOrCreateOfstOpnd(SIZEOFPTR, 32); + o1 = GetOrCreateMemOpnd(SIZEOFPTR * BITS_PER_BYTE, rsp, nullptr, ofopnd, 0); + allocInsn = cg->BuildInstruction(mop, o0, o1); + AppendInstructionTo(allocInsn, this); + if (cg->GenerateCfiDirectives()) { + ipoint = allocInsn; + curbb->InsertInsnAfter( + ipoint, cg->BuildInstruction(cfi::OP_CFI_offset, + CreateCfiRegOperand(RRA, 64), CreateCfiImmOperand(-cfiOffset + 8, 64))); + } + } + + if (useStpSub) { + MOperator mop = pushPopOps[kRegsPushOp][rty][PUSH_POP_SINGLE]; + Riscv64RegOperand *o0 = GetOrCreatePhysicalRegisterOperand(reg0, SIZEOFPTR * BITS_PER_BYTE, rty); + Riscv64MemOperand *o2 = memPool->New(RSP, 0, SIZEOFPTR * BITS_PER_BYTE); + Insn *allocInsn = cg->BuildInstruction(mop, o0, o2); + AppendInstructionTo(allocInsn, this); + if (cg->GenerateCfiDirectives()) { + ipoint = allocInsn; + cfiOffset = GetOffsetFromCFA() - argsToStkpassSize; + ipoint = curbb->InsertInsnAfter( + ipoint, cg->BuildInstruction(cfi::OP_CFI_offset, + CreateCfiRegOperand(RFP, 64), CreateCfiImmOperand(-cfiOffset, 64))); + } + + Riscv64RegOperand *o1 = GetOrCreatePhysicalRegisterOperand(reg1, SIZEOFPTR * BITS_PER_BYTE, rty); + o2 = memPool->New(RSP, SIZEOFPTR, SIZEOFPTR * BITS_PER_BYTE); + allocInsn = cg->BuildInstruction(mop, o1, o2); + AppendInstructionTo(allocInsn, this); + if (cg->GenerateCfiDirectives()) { + ipoint = allocInsn; + curbb->InsertInsnAfter( + ipoint, cg->BuildInstruction(cfi::OP_CFI_offset, + CreateCfiRegOperand(RRA, 64), CreateCfiImmOperand(-cfiOffset + 8, 64))); + } + } + + if (cg->NeedInsertInstrumentationFunction()) { + AppendCall(cg->GetInstrumentationFunction()); + } else if (cg->InstrumentWithDebugTraceCall()) { + AppendCall(cg->GetDebugTraceEnterFunction()); + } else if (cg->InstrumentWithProfile()) { + AppendCall(cg->GetProfileFunction()); + } + } +} + +void Riscv64CGFunc::AppendInstructionPopSingle(Riscv64reg_t reg, RegType rty, int offset) { + MOperator mop = pushPopOps[kRegsPopOp][rty][PUSH_POP_SINGLE]; + Operand *o0 = GetOrCreatePhysicalRegisterOperand(reg, SIZEOFPTR * BITS_PER_BYTE, rty); + Operand *o1 = CreateStkTopOpnd(offset, SIZEOFPTR * BITS_PER_BYTE); + + uint32 datasize = SIZEOFPTR * BITS_PER_BYTE; + if (IsImmediateOffsetOutOfRange(static_cast(o1), datasize)) { + o1 = SplitOffsetWithAddInstruction(static_cast(o1), datasize, Riscv64Abi::kIntSpareReg); + } + + Insn *popInsn = cg->BuildInstruction(mop, o0, o1); + string comment = "RESTORE"; + popInsn->AddComment(comment); + curbb->AppendInsn(popInsn); + + // Append CFI code. + if (cg->GenerateCfiDirectives()) { + Insn *restoreCfiInsn = cg->BuildInstruction(cfi::OP_CFI_restore, CreateCfiRegOperand(reg, 64)); + curbb->AppendInsn(restoreCfiInsn); + } +} + +void Riscv64CGFunc::AppendInstructionPopPair(Riscv64reg_t reg0, Riscv64reg_t reg1, RegType rty, int offset) { + MOperator mop = pushPopOps[kRegsPopOp][rty][PUSH_POP_PAIR]; + Operand *o0 = GetOrCreatePhysicalRegisterOperand(reg0, SIZEOFPTR * BITS_PER_BYTE, rty); + Operand *o1 = GetOrCreatePhysicalRegisterOperand(reg1, SIZEOFPTR * BITS_PER_BYTE, rty); + Operand *o2 = CreateStkTopOpnd(offset, SIZEOFPTR * BITS_PER_BYTE); + + uint32 datasize = SIZEOFPTR * BITS_PER_BYTE; + CG_ASSERT(offset >= 0, ""); + if (offset > STP_LDP_IMM64_UPPER_BOUND) { + o2 = SplitStpLdpOffsetForCalleeSavedWithAddInstruction(static_cast(o2), datasize, R16); + } + Insn *popInsn = cg->BuildInstruction(mop, o0, o1, o2); + string comment = "RESTORE RESTORE"; + popInsn->AddComment(comment); + curbb->AppendInsn(popInsn); + + // Append CFI code + Insn *restoreCfiInsn = cg->BuildInstruction(cfi::OP_CFI_restore, CreateCfiRegOperand(reg0, 64)); + curbb->AppendInsn(restoreCfiInsn); + restoreCfiInsn = cg->BuildInstruction(cfi::OP_CFI_restore, CreateCfiRegOperand(reg1, 64)); + curbb->AppendInsn(restoreCfiInsn); +} + +void Riscv64CGFunc::AppendInstructionDeallocateCallFrame(Riscv64reg_t reg0, Riscv64reg_t reg1, RegType rty) { + MOperator mop = pushPopOps[kRegsPopOp][rty][PUSH_POP_SINGLE]; + Operand *o0 = GetOrCreatePhysicalRegisterOperand(reg0, SIZEOFPTR * BITS_PER_BYTE, rty); + Operand *o1 = GetOrCreatePhysicalRegisterOperand(reg1, SIZEOFPTR * BITS_PER_BYTE, rty); + int64 stackFrameSize = static_cast(memlayout)->RealStackFrameSize(); + int64 argsToStkpassSize = memlayout->SizeOfArgsToStackpass(); + // ldp/stp's imm should be within -512 and 504; + // if ldp's imm > 504, we fall back to the ldp-add version + bool useLdpAdd = false; + int64 offset = 0; + + Operand *o2 = nullptr; + Operand *o3 = nullptr; + if (!HasVLAOrAlloca() && argsToStkpassSize > 0) { + o2 = memPool->New(RSP, argsToStkpassSize, SIZEOFPTR * BITS_PER_BYTE); + o3 = memPool->New(RSP, argsToStkpassSize+SIZEOFPTR, SIZEOFPTR * BITS_PER_BYTE); + } else { + if (stackFrameSize > STP_LDP_IMM64_UPPER_BOUND) { + useLdpAdd = true; + offset = 16; + stackFrameSize -= offset; + } else { + offset = stackFrameSize; + } + o2 = CreateCallFrameOperand(offset, SIZEOFPTR * BITS_PER_BYTE); + o3 = CreateCallFrameOperand(offset+SIZEOFPTR, SIZEOFPTR * BITS_PER_BYTE); + } + + if (useLdpAdd) { + Operand *spOpnd = GetOrCreatePhysicalRegisterOperand(RSP, 64, kRegTyInt); + Operand *immopnd = CreateImmOperand(stackFrameSize, 32, true); + SelectAdd(spOpnd, spOpnd, immopnd, PTY_u64); + if (cg->GenerateCfiDirectives()) { + int cfiOffset = GetOffsetFromCFA(); + (void)curbb->InsertInsnAfter( + curbb->lastinsn, cg->BuildInstruction(cfi::OP_CFI_def_cfa, CreateCfiRegOperand(RSP, 64), + CreateCfiImmOperand(cfiOffset - stackFrameSize, 64))); + } + } + + if (!HasVLAOrAlloca() && argsToStkpassSize > 0) { + CG_ASSERT(!useLdpAdd, "Invalid assumption"); + if (argsToStkpassSize > STP_LDP_IMM64_UPPER_BOUND) { + if (argsToStkpassSize <= STR_LDR_IMM64_UPPER_BOUND - 8) { + mop = pushPopOps[kRegsPopOp][rty][PUSH_POP_SINGLE]; + o0 = GetOrCreatePhysicalRegisterOperand(reg0, SIZEOFPTR * BITS_PER_BYTE, rty); + o2 = memPool->New(RSP, argsToStkpassSize, SIZEOFPTR * BITS_PER_BYTE); + Insn *popInsn = cg->BuildInstruction(mop, o0, o2); + AppendInstructionTo(popInsn, this); + o1 = GetOrCreatePhysicalRegisterOperand(reg1, SIZEOFPTR * BITS_PER_BYTE, rty); + o2 = memPool->New(RSP, argsToStkpassSize + SIZEOFPTR, SIZEOFPTR * BITS_PER_BYTE); + popInsn = cg->BuildInstruction(mop, o1, o2); + AppendInstructionTo(popInsn, this); + } else { + Riscv64RegOperand *oo = GetOrCreatePhysicalRegisterOperand(R9, SIZEOFPTR * BITS_PER_BYTE, kRegTyInt); + Riscv64ImmOperand *io = CreateImmOperand(argsToStkpassSize, 64, true); + SelectCopyImm(oo, io, PTY_i64); + + o0 = GetOrCreatePhysicalRegisterOperand(reg0, SIZEOFPTR * BITS_PER_BYTE, rty); + Riscv64RegOperand *rsp = GetOrCreatePhysicalRegisterOperand(RSP, SIZEOFPTR * 8, kRegTyInt); + AppendInstructionTo(cg->BuildInstruction(MOP_xaddrrr, oo, rsp, oo), this); + Riscv64OfstOperand *ofopnd = GetOrCreateOfstOpnd(0, 32); + Riscv64MemOperand *mo = GetOrCreateMemOpnd(SIZEOFPTR * BITS_PER_BYTE, oo, nullptr, ofopnd, 0); + Insn *popInsn = cg->BuildInstruction(MOP_xldr, o0, mo); + AppendInstructionTo(popInsn, this); + + io = CreateImmOperand(SIZEOFPTR, 64, true); + SelectAdd(oo, oo, io, PTY_i64); + + o1 = GetOrCreatePhysicalRegisterOperand(reg1, SIZEOFPTR * BITS_PER_BYTE, rty); + ofopnd = GetOrCreateOfstOpnd(0, 32); + mo = GetOrCreateMemOpnd(SIZEOFPTR * BITS_PER_BYTE, oo, nullptr, ofopnd, 0); + popInsn = cg->BuildInstruction(MOP_xldr, o1, mo); + AppendInstructionTo(popInsn, this); + } + } else { + //Insn *deallocInsn = cg->BuildInstruction(mop, o0, o1, o2); + Insn *deallocInsn = cg->BuildInstruction(mop, o0, o2); + curbb->AppendInsn(deallocInsn); + deallocInsn = cg->BuildInstruction(mop, o1, o3); + curbb->AppendInsn(deallocInsn); + } + Operand *spOpnd = GetOrCreatePhysicalRegisterOperand(RSP, 64, kRegTyInt); + Operand *immopnd = CreateImmOperand(stackFrameSize, 32, true); + SelectAdd(spOpnd, spOpnd, immopnd, PTY_u64); + } else { + Insn *deallocInsn = cg->BuildInstruction(mop, o0, o1, o2); + curbb->AppendInsn(deallocInsn); + } + + // Append CFI restore + curbb->AppendInsn(cg->BuildInstruction(cfi::OP_CFI_restore, CreateCfiRegOperand(RFP, 64))); + curbb->AppendInsn(cg->BuildInstruction(cfi::OP_CFI_restore, CreateCfiRegOperand(RRA, 64))); +} + +void Riscv64CGFunc::AppendInstructionDeallocateCallFrameDebug(Riscv64reg_t reg0, Riscv64reg_t reg1, RegType rty) { + MOperator mop = pushPopOps[kRegsPopOp][rty][PUSH_POP_SINGLE]; + Operand *o0 = GetOrCreatePhysicalRegisterOperand(reg0, SIZEOFPTR * BITS_PER_BYTE, rty); + Operand *o1 = GetOrCreatePhysicalRegisterOperand(reg1, SIZEOFPTR * BITS_PER_BYTE, rty); + int64 stackFrameSize = static_cast(memlayout)->RealStackFrameSize(); + int64 argsToStkpassSize = memlayout->SizeOfArgsToStackpass(); + /* ldp/stp's imm should be within -512 and 504; + * if ldp's imm > 504, we fall back to the ldp-add version + */ + if (HasVLAOrAlloca() || argsToStkpassSize == 0) { + stackFrameSize -= argsToStkpassSize; + if (stackFrameSize > STP_LDP_IMM64_UPPER_BOUND) { + Operand *o2; + o2 = memPool->New(RSP, 0, SIZEOFPTR * BITS_PER_BYTE); + Insn *deallocInsn = cg->BuildInstruction(mop, o0, o2); + curbb->AppendInsn(deallocInsn); + curbb->AppendInsn(cg->BuildInstruction(cfi::OP_CFI_restore, CreateCfiRegOperand(RFP, 64))); + o2 = memPool->New(RSP, SIZEOFPTR, SIZEOFPTR * BITS_PER_BYTE); + deallocInsn = cg->BuildInstruction(mop, o1, o2); + curbb->AppendInsn(deallocInsn); + // Append CFI restore + curbb->AppendInsn(cg->BuildInstruction(cfi::OP_CFI_restore, CreateCfiRegOperand(RRA, 64))); + Operand *spOpnd = GetOrCreatePhysicalRegisterOperand(RSP, 64, kRegTyInt); + Operand *immopnd = CreateImmOperand(stackFrameSize, 32, true); + SelectAdd(spOpnd, spOpnd, immopnd, PTY_u64); + } else { + RegOperand *rsp = GetOrCreatePhysicalRegisterOperand(RSP, SIZEOFPTR * 8, kRegTyInt); + Riscv64OfstOperand *ofopnd = GetOrCreateOfstOpnd(0, 32); + Riscv64MemOperand *o2 = GetOrCreateMemOpnd(SIZEOFPTR * BITS_PER_BYTE, rsp, nullptr, ofopnd, 0); + Insn *deallocInsn = cg->BuildInstruction(mop, o0, o2); + curbb->AppendInsn(deallocInsn); + curbb->AppendInsn(cg->BuildInstruction(cfi::OP_CFI_restore, CreateCfiRegOperand(RFP, 64))); + ofopnd = GetOrCreateOfstOpnd(SIZEOFPTR, 32); + o2 = GetOrCreateMemOpnd(SIZEOFPTR * BITS_PER_BYTE, rsp, nullptr, ofopnd, 0); + deallocInsn = cg->BuildInstruction(mop, o1, o2); + curbb->AppendInsn(deallocInsn); + curbb->AppendInsn(cg->BuildInstruction(cfi::OP_CFI_restore, CreateCfiRegOperand(RRA, 64))); + // Restore old sp + ImmOperand *iopnd = CreateImmOperand(stackFrameSize, 32, true); + Insn *spAdd = cg->BuildInstruction(MOP_xaddrri12, rsp, rsp, iopnd); + curbb->AppendInsn(spAdd); + } + + } else { + Operand *o2; + o2 = memPool->New(RSP, argsToStkpassSize, SIZEOFPTR * BITS_PER_BYTE); + if (argsToStkpassSize > STP_LDP_IMM64_UPPER_BOUND) { + if (argsToStkpassSize <= STR_LDR_IMM64_UPPER_BOUND - 8) { + mop = pushPopOps[kRegsPopOp][rty][PUSH_POP_SINGLE]; + Riscv64RegOperand *o0 = GetOrCreatePhysicalRegisterOperand(reg0, SIZEOFPTR * BITS_PER_BYTE, rty); + Riscv64MemOperand *o2 = memPool->New(RSP, argsToStkpassSize, SIZEOFPTR * BITS_PER_BYTE); + Insn *popInsn = cg->BuildInstruction(mop, o0, o2); + AppendInstructionTo(popInsn, this); + curbb->AppendInsn(cg->BuildInstruction(cfi::OP_CFI_restore, CreateCfiRegOperand(RFP, 64))); + + Riscv64RegOperand *o1 = GetOrCreatePhysicalRegisterOperand(reg1, SIZEOFPTR * BITS_PER_BYTE, rty); + o2 = memPool->New(RSP, argsToStkpassSize + SIZEOFPTR, SIZEOFPTR * BITS_PER_BYTE); + popInsn = cg->BuildInstruction(mop, o1, o2); + AppendInstructionTo(popInsn, this); + curbb->AppendInsn(cg->BuildInstruction(cfi::OP_CFI_restore, CreateCfiRegOperand(RRA, 64))); + } else { + Riscv64RegOperand *oo = GetOrCreatePhysicalRegisterOperand(R9, SIZEOFPTR * BITS_PER_BYTE, kRegTyInt); + Riscv64ImmOperand *io = CreateImmOperand(argsToStkpassSize, 64, true); + SelectCopyImm(oo, io, PTY_i64); + + Riscv64RegOperand *o0 = GetOrCreatePhysicalRegisterOperand(reg0, SIZEOFPTR * BITS_PER_BYTE, rty); + Riscv64RegOperand *rsp = GetOrCreatePhysicalRegisterOperand(RSP, SIZEOFPTR * 8, kRegTyInt); + AppendInstructionTo(cg->BuildInstruction(MOP_xaddrrr, oo, rsp, oo), this); + Riscv64OfstOperand *ofopnd = GetOrCreateOfstOpnd(0, 32); + Riscv64MemOperand *mo = GetOrCreateMemOpnd(SIZEOFPTR * BITS_PER_BYTE, oo, nullptr, ofopnd, 0); + Insn *popInsn = cg->BuildInstruction(MOP_xldr, o0, mo); + AppendInstructionTo(popInsn, this); + curbb->AppendInsn(cg->BuildInstruction(cfi::OP_CFI_restore, CreateCfiRegOperand(RFP, 64))); + + io = CreateImmOperand(SIZEOFPTR, 64, true); + SelectAdd(oo, oo, io, PTY_i64); + + Riscv64RegOperand *o1 = GetOrCreatePhysicalRegisterOperand(reg1, SIZEOFPTR * BITS_PER_BYTE, rty); + ofopnd = GetOrCreateOfstOpnd(0, 32); + mo = GetOrCreateMemOpnd(SIZEOFPTR * BITS_PER_BYTE, oo, nullptr, ofopnd, 0); + popInsn = cg->BuildInstruction(MOP_xldr, o1, mo); + AppendInstructionTo(popInsn, this); + curbb->AppendInsn(cg->BuildInstruction(cfi::OP_CFI_restore, CreateCfiRegOperand(RRA, 64))); + } + } else { + Operand *o3 = memPool->New(RSP, argsToStkpassSize+SIZEOFPTR, SIZEOFPTR * BITS_PER_BYTE); + //Insn *deallocInsn = cg->BuildInstruction(mop, o0, o1, o2); + Insn *deallocInsn = cg->BuildInstruction(mop, o0, o2); + curbb->AppendInsn(deallocInsn); + curbb->AppendInsn(cg->BuildInstruction(cfi::OP_CFI_restore, CreateCfiRegOperand(RFP, 64))); + deallocInsn = cg->BuildInstruction(mop, o1, o3); + curbb->AppendInsn(deallocInsn); + curbb->AppendInsn(cg->BuildInstruction(cfi::OP_CFI_restore, CreateCfiRegOperand(RRA, 64))); + } + + Operand *spOpnd = GetOrCreatePhysicalRegisterOperand(RSP, 64, kRegTyInt); + Operand *immopnd = CreateImmOperand(stackFrameSize, 32, true); + SelectAdd(spOpnd, spOpnd, immopnd, PTY_u64); + } +} + +Insn *Riscv64CGFunc::GenerateCfiRestores(BB *lastbb) { + Insn *ipoint = nullptr; + Insn *restoreRlrInst = cg->BuildInstruction(cfi::OP_CFI_restore, CreateCfiRegOperand(RRA, 64)); + if (lastbb->firstinsn) { + ipoint = lastbb->InsertInsnAfter(lastbb->lastinsn, restoreRlrInst); + } else { + ipoint = lastbb->firstinsn = lastbb->lastinsn = restoreRlrInst; + } + ipoint = lastbb->InsertInsnAfter( + ipoint, cg->BuildInstruction(cfi::OP_CFI_restore, CreateCfiRegOperand(RFP, 64))); + return lastbb->InsertInsnAfter( + ipoint, + cg->BuildInstruction(cfi::OP_CFI_def_cfa, CreateCfiRegOperand(RSP, 64), CreateCfiImmOperand(0, 64))); +} + +Riscv64MemOperand *Riscv64CGFunc::CreateStkTopOpnd(int32 offset, int32 size) { + if (cg->UseFP() || HasVLAOrAlloca()) { + return memPool->New(RFP, offset, size); + } else { + return memPool->New(RSP, offset, size); + } +} + +/* + From Riscv64 Reference Manual + C1.3.3 Load/Store Addressing Mode + ... + When stack alignment checking is enabled by system software and + the base register is the SP, the current stack pointer must be + initially quadword aligned, that is aligned to 16 bytes. Misalignment + generates a Stack Alignment fault. The offset does not have to + be a multiple of 16 bytes unless the specific Load/Store instruction + requires this. SP cannot be used as a register offset. + */ +void Riscv64CGFunc::GeneratePushRegs() { + MapleVector ®sToSave = GetCalleeSavedRegs(); + + CG_ASSERT(regsToSave.size() > 0, "FP/LR not added to callee-saved list?"); + + if (cg->GenerateVerboseAsm()) { + curbb->AppendInsn( + cg->BuildInstruction(MOP_comment, CreateCommentOperand("save callee-saved registers"))); + } + + // Even if we don't use RFP, since we push a pair of registers in one instruction + // and the stack needs be aligned on a 16-byte boundary, push RFP as well if function has a call + // Make sure this is reflected when computing callee_saved_regs.size() + if (cg->GenerateDebugFriendlyCode()) { + AppendInstructionAllocateCallFrameDebug(RFP, RRA, kRegTyInt); + } else { + CHECK_FATAL(0, "Should not reach here"); + AppendInstructionAllocateCallFrame(RFP, RRA, kRegTyInt); + } + + if (cg->UseFP() || HasVLAOrAlloca()) { + if (cg->GenerateVerboseAsm()) { + curbb->AppendInsn(cg->BuildInstruction(MOP_comment, CreateCommentOperand("copy SP to FP"))); + } + Operand *spOpnd = GetOrCreatePhysicalRegisterOperand(RSP, 64, kRegTyInt); + Operand *fpOpnd = GetOrCreatePhysicalRegisterOperand(RFP, 64, kRegTyInt); + int64 argsToStkpassSize = memlayout->SizeOfArgsToStackpass(); + if (argsToStkpassSize > 0) { + Operand *immopnd = CreateImmOperand(argsToStkpassSize, 32, true); + SelectAdd(fpOpnd, spOpnd, immopnd, PTY_u64); + if (cg->GenerateCfiDirectives()) { + cfi::ImmOperand *imm = memPool->New( + static_cast(memlayout)->RealStackFrameSize() - argsToStkpassSize, 64); + curbb->AppendInsn(cg->BuildInstruction(cfi::OP_CFI_def_cfa, CreateCfiRegOperand(RFP, 64), imm)); + } + + } else { + SelectCopy(fpOpnd, PTY_u64, spOpnd, PTY_u64); + curbb->AppendInsn(cg->BuildInstruction(cfi::OP_CFI_def_cfa_register, CreateCfiRegOperand(RFP, 64))); + } + } + + MapleVector::iterator it = regsToSave.begin(); + // skip the first two registers + CG_ASSERT(*it == RFP, "The first two callee saved regs are expected to be RFP and RRA"); + ++it; + CG_ASSERT(*it == RRA, "The first two callee saved regs are expected to be RFP and RRA"); + ++it; + + int offsetCalleeSingle = static_cast(memlayout)->RealStackFrameSize() - + (SizeOfCalleeSaved() - 2 * kIntregBytelen /*for FP/LR*/); + + if (cg->UseFP() || HasVLAOrAlloca()) { + offsetCalleeSingle -= memlayout->SizeOfArgsToStackpass(); + } + + if (CLANG && func->GetAttr(FUNCATTR_varargs)) { + // GR/VR save areas are above the callee save area + Riscv64MemLayout *ml = static_cast(memlayout); + int saveareasize = RoundUp(ml->GetSizeOfGRSavearea(), SIZEOFPTR*2); + offsetCalleeSingle -= saveareasize; + } + + for (; it != regsToSave.end(); ++it) { + Riscv64reg_t reg = *it; + CG_ASSERT(reg != RFP && reg != RRA, "stray RFP/RRA in callee_saved_list?"); + + RegType rty = Riscv64isa::IsGPRegister(reg) ? kRegTyInt : kRegTyFloat; + AppendInstructionPushSingle(reg, rty, offsetCalleeSingle); + GetNextOffsetCalleeSaved(offsetCalleeSingle); + } + + // in case we split stp/ldp instructions, + // so that we generate a load-into-base-register instruction + // for pop pairs as well. + split_stpldp_base_offset = 0; +} + +void Riscv64CGFunc::GeneratePopRegs() { + MapleVector ®sToRestore = GetCalleeSavedRegs(); + + CG_ASSERT(regsToRestore.size() > 0, "FP/LR not added to callee-saved list?"); + + if (cg->GenerateVerboseAsm()) { + curbb->AppendInsn( + cg->BuildInstruction(MOP_comment, CreateCommentOperand("restore callee-saved registers"))); + } + + MapleVector::iterator it = regsToRestore.begin(); + // Even if we don't use FP, since we push a pair of registers + // in a single instruction (i.e., stp) and the stack needs be aligned + // on a 16-byte boundary, push FP as well if the function has a call. + // Make sure this is reflected when computing callee_saved_regs.size() + // skip the first two registers + CG_ASSERT(*it == RFP, "The first two callee saved regs are expected to be RFP and RRA"); + ++it; + CG_ASSERT(*it == RRA, "The first two callee saved regs are expected to be RFP and RRA"); + ++it; + + int offsetCalleeSingle = static_cast(memlayout)->RealStackFrameSize() - + (SizeOfCalleeSaved() - 2 * kIntregBytelen /*for FP/LR*/); + + if (cg->UseFP() || HasVLAOrAlloca()) { + offsetCalleeSingle -= memlayout->SizeOfArgsToStackpass(); + } + + if (CLANG && func->GetAttr(FUNCATTR_varargs)) { + // GR/VR save areas are above the callee save area + Riscv64MemLayout *ml = static_cast(memlayout); + int saveareasize = RoundUp(ml->GetSizeOfGRSavearea(), SIZEOFPTR*2); + offsetCalleeSingle -= saveareasize; + } + + // We are using a cleared dummy block; so insertPoint cannot be ret; + // see GenerateEpilog() + for (; it != regsToRestore.end(); ++it) { + Riscv64reg_t reg = *it; + CG_ASSERT(reg != RFP && reg != RRA, "stray RFP/RRA in callee_saved_list?"); + + RegType rty = Riscv64isa::IsGPRegister(reg) ? kRegTyInt : kRegTyFloat; + AppendInstructionPopSingle(reg, rty, offsetCalleeSingle); + GetNextOffsetCalleeSaved(offsetCalleeSingle); + } + + if (cg->GenerateDebugFriendlyCode()) { + AppendInstructionDeallocateCallFrameDebug(RFP, RRA, kRegTyInt); + } else { + AppendInstructionDeallocateCallFrame(RFP, RRA, kRegTyInt); + } + + if (cg->GenerateCfiDirectives()) { + curbb->AppendInsn(cg->BuildInstruction(cfi::OP_CFI_def_cfa, CreateCfiRegOperand(RSP, 64), + CreateCfiImmOperand(0, 64))); + } + // in case we split stp/ldp instructions, + // so that we generate a load-into-base-register instruction + // for the next function, maybe? (seems not necessary, but...) + split_stpldp_base_offset = 0; +} + +void Riscv64CGFunc::Genstackguard(BB *bb) { + if (cg->AddStackGuard()) { + BB *formerCurbb = curbb; + dummybb->ClearInsns(); + curbb = dummybb; + + MIRSymbol *stkguardsym = GlobalTables::GetGsymTable().GetSymbolFromStrIdx(GlobalTables::GetStrTable().GetStrIdxFromName("__stack_chk_guard")); + StImmOperand *stopnd = CreateStImmOperand(stkguardsym, 0, 0); + Riscv64RegOperand *staddropnd = + static_cast(GetOrCreatePhysicalRegisterOperand(R9, SIZEOFPTR * 8, kRegTyInt)); + SelectAddrof(staddropnd, stopnd); + Riscv64MemOperand *guardmemopn = + memPool->New(SIZEOFPTR * 8, staddropnd, + static_cast(nullptr), GetOrCreateOfstOpnd(0, 32), stkguardsym); + MOperator mop = PickLdInsn(64, PTY_u64); + Insn *ins = cg->BuildInstruction(mop, staddropnd, guardmemopn); + ins->do_not_remove = true; + curbb->AppendInsn(ins); + + int varea = 0; + if (CLANG && func->GetAttr(FUNCATTR_varargs)) { + Riscv64MemLayout *ml = static_cast(memlayout); + int vsize = ml->GetSizeOfGRSavearea(); + if (vsize > 0) { + varea += RoundUp(vsize, RISCV64_STACK_PTR_ALIGNMENT); + } + } + + Riscv64MemOperand *downstk = nullptr; + if (cg->UseFP() || HasVLAOrAlloca()) { + int32 stksize = static_cast(memlayout)->RealStackFrameSize() - + static_cast(memlayout)->SizeOfArgsToStackpass() - + varea; + downstk = memPool->New(RFP, stksize - 8, SIZEOFPTR * BITS_PER_BYTE); + } else { + downstk = memPool->New(RSP, static_cast(memlayout)->RealStackFrameSize() - 8 - varea, + SIZEOFPTR * BITS_PER_BYTE); + } + if (IsImmediateOffsetOutOfRange(static_cast(downstk), 64)) { + downstk = SplitOffsetWithAddInstruction(static_cast(downstk), 64, R10); + } + mop = PickStInsn(SIZEOFPTR * BITS_PER_BYTE, PTY_u64); + ins = cg->BuildInstruction(mop, staddropnd, downstk); + ins->do_not_remove = true; + curbb->AppendInsn(ins); + + bb->InsertAtBeginning(dummybb); + curbb = formerCurbb; + } +} + +void Riscv64CGFunc::MoveRegargs(BB *bb) { + BB *formerCurbb = curbb; + dummybb->ClearInsns(); + curbb = dummybb; + ParmLocator parmlocator(becommon); + PLocInfo ploc; + + for (uint32 i = 0; i < func->formalDefVec.size(); i++) { + if (i == 0) { + MIRFunction *func = becommon.mirModule.CurFunction(); + if (func->IsReturnStruct()) { + auto funcIt = becommon.funcReturnType.find(func); + if (funcIt != becommon.funcReturnType.end() && becommon.type_size_table[funcIt->second.GetIdx()] <= 16) { + continue; + } + } + } + + MIRType *typ = GlobalTables::GetTypeTable().GetTypeFromTyIdx(func->formalDefVec[i].formalTyIdx); + parmlocator.LocateNextParm(typ, ploc, i == 0); + + MIRSymbol *sym = func->formalDefVec[i].formalSym; + if (sym->IsPreg()) { + continue; + } + Riscv64SymbolAlloc *symloc = + static_cast(memlayout->sym_alloc_table[sym->GetStIndex()]); + Riscv64RegOperand *baseOpnd = static_cast(GetBaseReg(symloc)); + int32 stoffset = GetBaseOffset(symloc); + + Riscv64ImmOperand *zeroOffset = CreateImmOperand(0, 64, false); + PrimType ty = typ->GetPrimType(); + uint32 sz = 0; + MemOperand *memOpnd; + + // Save param or 1st half of agg param + if (ploc.reg0 != kRinvalid) { + RegType firstRegType = ploc.reg0 < V0 ? kRegTyInt : kRegTyFloat; + // Size of parameter is based on its primType. As the stack space is computed + // based on the alignment and size required, the store generated here must + // follow that. + if (ty == PTY_agg || (ploc.reg0 < V0 && IsPrimitiveInteger(ty) == false)) { + // Riscv calling convention uses int parm regs to pass after + // using all of fp parm regs for fp parms. + ty = ploc.reg0 < V0 ? (ploc.rsize0 > 4 ? PTY_i64 : PTY_i32) : (ploc.rsize0 < 8 ? PTY_f32 : PTY_f64); + } + sz = GetPrimTypeSize(ty); + if (Riscv64MemOperand::IsPIMMOffsetOutOfRange(stoffset, sz * BITS_PER_BYTE)) { + RegOperand *baseReg = GetOrCreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + Riscv64ImmOperand *offsetOpnd = CreateImmOperand(stoffset, 64, false); + SelectAdd(baseReg, baseOpnd, offsetOpnd, PTY_a64); + memOpnd = memPool->New(sz * BITS_PER_BYTE, + baseReg, (Riscv64RegOperand *)nullptr, zeroOffset, sym); + } else { + Riscv64OfstOperand *offsetOpnd = CreateOfstOpnd(stoffset, 32); + if (symloc->mem_segment->kind == kMsArgsStkpassed) { + offsetOpnd->SetVary(true); + } + memOpnd = + memPool->New(sz * BITS_PER_BYTE, + baseOpnd, (Riscv64RegOperand *)nullptr, offsetOpnd, sym); + } + MOperator mop = PickStInsn(GetPrimTypeSize(ty) * BITS_PER_BYTE, ty); + RegOperand *regOpnd = GetOrCreatePhysicalRegisterOperand(ploc.reg0, sz * BITS_PER_BYTE, firstRegType); + Insn *ins = cg->BuildInstruction(mop, regOpnd, memOpnd); + if (cg->GenerateVerboseAsm()) { + ins->AddComment(std::string("store param: ").append(sym->GetName())); + } + curbb->AppendInsn(ins); + } + + // Restore the primType overwritten by ploc.reg0. + ty = typ->GetPrimType(); + // Save 2nd half of agg param + if (ploc.reg1 != kRinvalid) { + RegType secondRegType = ploc.reg1 < V0 ? kRegTyInt : kRegTyFloat; + if (ploc.rsize1 != 0) { // 2nd valid reg may exist for agg + if (ploc.rsize0 <= 4 && ploc.rsize1 <= 4) { + stoffset += 4; + } else { + stoffset += SIZEOFPTR; + } + if (ty == PTY_agg || (ploc.reg0 < V0 && IsPrimitiveInteger(ty) == false)) { + ty = ploc.reg1 < V0 ? (ploc.rsize1 > 4 ? PTY_i64 : PTY_i32) : (ploc.rsize1 < 8 ? PTY_f32 : PTY_f64); + } + sz = GetPrimTypeSize(ty); + if (Riscv64MemOperand::IsPIMMOffsetOutOfRange(stoffset, sz * BITS_PER_BYTE)) { + RegOperand *baseReg = GetOrCreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + Riscv64ImmOperand *offsetOpnd = CreateImmOperand(stoffset, 64, false); + SelectAdd(baseReg, baseOpnd, offsetOpnd, PTY_a64); + memOpnd = memPool->New(sz * BITS_PER_BYTE, + baseReg, (Riscv64RegOperand *)nullptr, zeroOffset, sym); + } else { + Riscv64OfstOperand *offsetOpnd = CreateOfstOpnd(stoffset, 32); + if (symloc->mem_segment->kind == kMsArgsStkpassed) { + offsetOpnd->SetVary(true); + } + memOpnd = memPool->New(sz * BITS_PER_BYTE, + baseOpnd, (Riscv64RegOperand *)nullptr, offsetOpnd, sym); + } + MOperator mop = PickStInsn(GetPrimTypeSize(ty) * BITS_PER_BYTE, ty); + RegOperand *regOpnd = GetOrCreatePhysicalRegisterOperand(ploc.reg1, sz * BITS_PER_BYTE, secondRegType); + Insn *ins = cg->BuildInstruction(mop, regOpnd, memOpnd); + if (cg->GenerateVerboseAsm()) { + ins->AddComment(std::string("store param: ").append(sym->GetName())); + } + curbb->AppendInsn(ins); + } + } + + // Half in register, half on stack, store the half on stack into its local location + uint32 aggSize = becommon.type_size_table.at(typ->tyIdx.GetIdx()); + Riscv64RegOperand *baseOpnd2; + if (ploc.reg0 != kRinvalid && ploc.reg1 == kRinvalid && + aggSize <= 16 && aggSize > ploc.memsize && aggSize > ploc.reg0) { + // load from stack + if (UseFP() || HasVLAOrAlloca()) { + baseOpnd2 = GetOrCreatePhysicalRegisterOperand(RFP, 64, kRegTyInt); + } else { + baseOpnd2 = GetOrCreatePhysicalRegisterOperand(RSP, 64, kRegTyInt); + } + RegOperand *baseReg = GetOrCreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + // StackFrameSize is not fixed yet, use isvary + Riscv64ImmOperand *offsetOpnd = + CreateImmOperand(0, 64, true, true); // isvary reset StackFrameSize + if (ploc.memoffset) { + Riscv64ImmOperand *offsetOpnd2 = CreateImmOperand(ploc.memoffset, 64, false); + SelectAdd(baseReg, offsetOpnd, offsetOpnd2, PTY_a64); + SelectAdd(baseReg, baseOpnd2, baseReg, PTY_a64); + } else { + SelectAdd(baseReg, baseOpnd2, offsetOpnd, PTY_a64); + } + memOpnd = GetOrCreateMemOpnd(64, baseReg, nullptr, + zeroOffset, static_cast(nullptr)); + RegOperand *regOpnd = GetOrCreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + Insn *insn0 = cg->BuildInstruction(MOP_xldr, regOpnd, memOpnd); + curbb->AppendInsn(insn0); + + // store to local location + if (Riscv64MemOperand::IsPIMMOffsetOutOfRange(stoffset, SIZEOFPTR * BITS_PER_BYTE)) { + RegOperand *baseReg = GetOrCreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + Riscv64ImmOperand *offsetOpnd = CreateImmOperand(stoffset+8, 64, false); + SelectAdd(baseReg, baseOpnd2, offsetOpnd, PTY_a64); + memOpnd = memPool->New(64, + baseReg, (Riscv64RegOperand *)nullptr, zeroOffset, sym); + } else { + Riscv64OfstOperand *offsetOpnd = CreateOfstOpnd(stoffset+8, 32); + if (symloc->mem_segment->kind == kMsArgsStkpassed) { + offsetOpnd->SetVary(true); + } + memOpnd = memPool->New(64, + baseOpnd, (Riscv64RegOperand *)nullptr, offsetOpnd, sym); + } + MOperator mop = PickStInsn(GetPrimTypeSize(PTY_i64) * BITS_PER_BYTE, ty); + Insn *ins = cg->BuildInstruction(mop, regOpnd, memOpnd); + if (cg->GenerateVerboseAsm()) { + ins->AddComment(std::string("store param: ").append(sym->GetName())); + } + curbb->AppendInsn(ins); + } + } + + bb->InsertAtBeginning(dummybb); + curbb = formerCurbb; +} + +void Riscv64CGFunc::MoveVRegargs(BB *bb) { + BB *formerCurbb = curbb; + dummybb->ClearInsns(); + curbb = dummybb; + ParmLocator parmlocator(becommon); + PLocInfo ploc; + + for (uint32 i = 0; i < func->formalDefVec.size(); i++) { + if (i == 0) { + MIRFunction *func = becommon.mirModule.CurFunction(); + if (func->IsReturnStruct()) { + auto funcIt = becommon.funcReturnType.find(func); + if (funcIt != becommon.funcReturnType.end() && becommon.type_size_table[funcIt->second.GetIdx()] <= 16) { + continue; + } + } + } + MIRType *ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(func->formalDefVec[i].formalTyIdx); + parmlocator.LocateNextParm(ty, ploc, i == 0); + + MIRSymbol *sym = func->formalDefVec[i].formalSym; + if (!sym->IsPreg()) { + continue; + } + + PrimType stype = sym->GetType()->primType; + int bytesize = GetPrimTypeSize(stype); + + PregIdx pregIdx = func->pregTab->GetPregIdxFromPregNo(sym->GetPreg()->pregNo); + RegOperand *dstRegopnd = GetOrCreateVirtualRegisterOperand(GetVirtualRegNoFromPseudoRegIdx(pregIdx)); + + if (ploc.reg0 == 0) { + // load stack parameters to the vreg. + int bitsize = bytesize * BITS_PER_BYTE; + MemOperand *memopnd = GetOrCreateMemOpnd(sym, 0, bitsize); + + Insn *insn = cg->BuildInstruction(PickLdInsn(GetPrimTypeBitSize(stype), stype), dstRegopnd, memopnd); + + if (cg->GenerateVerboseAsm()) { + std::string key = "param: %%"; + + key += std::to_string(sym->GetPreg()->pregNo); + CG_ASSERT(sym->GetStorageClass() == kScFormal, "vreg parameters should be kScFormal type."); + + insn->AddComment(key); + } + + curbb->InsertInsnBegin(insn); + } else { + RegType regtype = ploc.reg0 < V0 ? kRegTyInt : kRegTyFloat; + + uint8 srcBitsize = uint8((bytesize < 4 ? 4 : bytesize) * BITS_PER_BYTE); + dstRegopnd->size_ = srcBitsize; + + RegOperand *srcRegopnd = GetOrCreatePhysicalRegisterOperand(ploc.reg0, srcBitsize, regtype); + + CG_ASSERT(sym->storageClass == kScFormal, "should be args"); + + MOperator mop = PickMovInsn(srcBitsize, regtype); + Insn *ins = cg->BuildInstruction(mop, dstRegopnd, srcRegopnd); + if (cg->GenerateVerboseAsm()) { + std::string key = "param: %%"; + key += std::to_string(sym->GetPreg()->pregNo); + ins->AddComment(key); + } + curbb->InsertInsnBegin(ins); + } + + if (ploc.reg1 == 0) { + continue; + } + } + + bb->InsertAtBeginning(dummybb); + curbb = formerCurbb; +} + +/* + * The following functions are for pattern matching for fast path + * where function has early return of spedified pattern load/test/return + */ +void Riscv64CGFunc::ReplaceMachedOperand(Insn *orig, Insn *target, RegOperand *matchedOpnd, bool isFirstDst) { + for (int s = 0; s < target->GetOpndNum(); s++) { + Operand *src = target->GetOpnd(s); + CHECK_FATAL(src, "src is null in ReplaceMachedOperand"); + if (src->IsRegister()) { + RegOperand *reg = static_cast(src); + if (reg != matchedOpnd) { + continue; + } + RegOperand *phys = nullptr; + if (isFirstDst) { + Operand *origSrc = orig->GetOpnd(0); + RegOperand *origPhys = static_cast(origSrc); + CHECK_FATAL(origPhys, "pointer is null"); + regno_t regno = origPhys->GetRegisterNumber(); + phys = GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)(regno), matchedOpnd->GetSize(), kRegTyInt); + } else { + /* Replace the operand with the src of inst */ + phys = GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)(R16), reg->GetSize(), kRegTyInt); + } + target->SetOpnd(s, phys); + return; + } else if (src->IsMemoryAccessOperand()) { + MemOperand *memopnd = static_cast(src); + Operand *base = memopnd->GetBaseRegister(); + Operand *offset = memopnd->GetIndexRegister(); + if (base && base->IsRegister()) { + RegOperand *reg = static_cast(base); + if (reg != matchedOpnd) { + continue; + } + RegOperand *phys = nullptr; + if (isFirstDst) { + Operand *origSrc = orig->GetOpnd(0); + RegOperand *origPhys = static_cast(origSrc); + CHECK_FATAL(origPhys, "orig_phys cast failed"); + regno_t regno = origPhys->GetRegisterNumber(); + phys = GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)(regno), matchedOpnd->GetSize(), kRegTyInt); + } else { + /* Replace the operand with the src of inst */ + phys = GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)(R16), base->GetSize(), kRegTyInt); + } + memopnd->SetBaseRegister(phys); + return; + } + if (offset && offset->IsRegister()) { + RegOperand *reg = static_cast(offset); + if (reg != matchedOpnd) { + continue; + } + RegOperand *phys = nullptr; + if (isFirstDst) { + Operand *origSrc = orig->GetOpnd(0); + RegOperand *origPhys = static_cast(origSrc); + CHECK_FATAL(origPhys, "orig_phys is nullptr in ReplaceMachedOperand"); + regno_t regno = origPhys->GetRegisterNumber(); + phys = GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)(regno), matchedOpnd->GetSize(), kRegTyInt); + } else { + /* Replace the operand with the src of inst */ + phys = GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)(R16), offset->GetSize(), kRegTyInt); + } + memopnd->SetIndexRegister(phys); + return; + } + } + } + if (isFirstDst == false) { + RegOperand *phys; + phys = GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)(R16), matchedOpnd->GetSize(), kRegTyInt); + orig->SetResult(0, phys); + } + return; +} + +void Riscv64CGFunc::ForwardPropagateAndRename(Insn *mov, Insn *load, BB *terminateBb) { + // This is specialized function to work with IsolateFastPath(). + // The control flow and instruction pattern must be recognized. + Insn *insn = mov; + bool isFirstDst = true; + for (int i = 0; i < 2; i++) { + /* Finish the bb the mov is in */ + for (Insn *target = insn->next; target; target = target->next) { + if (target->IsImmaterialInsn()) { + continue; + } + if (!target->IsMachineInstruction()) { + continue; + } + Operand *dst = insn->GetResult(0); + RegOperand *rdst = static_cast(dst); + CHECK_FATAL(rdst, "rdst is nullptr in ForwardPropagateAndRename"); + ReplaceMachedOperand(insn, target, rdst, isFirstDst); + } + BB *bb = insn->bb->succs.front(); + while (1) { + FOR_BB_INSNS(target, bb) { + if (target->IsImmaterialInsn()) { + continue; + } + if (!target->IsMachineInstruction()) { + continue; + } + Operand *dst = insn->GetResult(0); + RegOperand *rdst = static_cast(dst); + CHECK_FATAL(rdst, "rdst is nullptr in ForwardPropagateAndRename"); + ReplaceMachedOperand(insn, target, rdst, isFirstDst); + } + if (bb == terminateBb) { + break; + } + bb = bb->succs.front(); + } + insn = load; + isFirstDst = false; + } +} + +bool Riscv64CGFunc::BackwardFindDependency(BB *ifbb, BB *returnbb, RegOperand *targetOpnd, Insn *&load, Insn *&mov, + Insn *&depMov, std::list &list) { + load = nullptr; + mov = nullptr; + depMov = nullptr; + BB *pred = ifbb; + /* Pattern match, (*) instruction are moved down below branch. + * mov reg1, R0 mov reg1, R0 * + * ld Rx , [reg1, const] ld R16 , [R0, const] + * mov reg2, Rx => mov reg2, R16 <- this may exist * + * mov Rx , R16 <- replicate * + * cbr Rx, label cbr R16, label + * + * R16 is used because it is used as spill register. + * Need to modify if different register allcoation mechanism is used. + */ + do { + FOR_BB_INSNS_REV(insn, pred) { + if (insn == ifbb->lastinsn) { + continue; + } + if (insn->IsImmaterialInsn()) { + continue; + } + if (!insn->IsMachineInstruction()) { + continue; + } + + bool found = false; // allowing for only one src to be register + for (int r = 0; r < insn->GetResultNum(); r++) { + Operand *dst = insn->GetResult(r); + CHECK_FATAL(dst, "pointer is null"); + if (!dst->IsRegister()) { + continue; + } + RegOperand *regopnd = static_cast(dst); + if (regopnd != targetOpnd) { + continue; + } + if (load != nullptr) { + if (mov != nullptr) { + return false; + } + MOperator opcode = insn->GetMachineOpcode(); + if (opcode == MOP_xmovrr) { + Operand *mvSrc = insn->GetOpnd(0); + RegOperand *mvRegsrc = static_cast(mvSrc); + CHECK_FATAL(mvRegsrc, "mv_regsrc cast failed"); + regno_t mvReg = mvRegsrc->GetRegisterNumber(); + // make it very specific for now + if (mvReg != R0) { + return false; + } + Operand *mvDst = insn->GetResult(0); + RegOperand *mvRegdst = static_cast(mvDst); + CHECK_FATAL(mvRegdst, "mv_regdst cast failed"); + mvReg = mvRegdst->GetRegisterNumber(); + if (mvReg != R20) { + return false; + } + mov = insn; + } else { + return false; + } + } + /* Found def, continue dep chain with src */ + for (int s = 0; s < insn->GetOpndNum(); s++) { + Operand *src = insn->GetOpnd(s); + CHECK_FATAL(src != nullptr, "src is nullptr in BackwardFindDependency"); + if (src->IsRegister()) { + if (found) { + return false; + } + RegOperand *preg = static_cast(src); + targetOpnd = preg; + if (preg->IsPhysicalRegister() && insn->GetMachineOpcode() == MOP_xmovrr) { + /* Skipping the start of the dependency chain because + * the the parameter reg will be propagated leaving + * the mov instruction alone to be relocated down + * to the cold path. + */ + found = false; + } else { + return false; + } + } else if (src->IsMemoryAccessOperand()) { + MemOperand *memopnd = static_cast(src); + Operand *base = memopnd->GetBaseRegister(); + Operand *offset = memopnd->GetIndexRegister(); + if (base && base->IsRegister()) { + if (found) { + return false; + } + load = insn; + targetOpnd = static_cast(base); + found = true; + Operand *ldDst = insn->GetResult(0); + RegOperand *ldRdst = static_cast(ldDst); + CHECK_FATAL(ldRdst != nullptr, "ld_rdst is nullptr in BackwardFindDependency"); + if (ldRdst->GetRegisterNumber() != R1) { + return false; // hard code for now. + } + // Make sure instruction depending on load is mov and cond br + for (Insn *ni = insn->next; ni; ni = ni->next) { + if (ni->GetMachineOpcode() == MOP_xmovrr || ni->GetMachineOpcode() == MOP_wmovrr) { + Operand *dep = ni->GetOpnd(0); + RegOperand *rdep = static_cast(dep); + if (rdep == ldRdst) { + if (depMov == nullptr) { + depMov = ni; + } else { + return false; + } + } + } + } + } + if (offset && offset->IsRegister()) { + return false; + } + } + } + } + if (found == false) { + list.push_back(insn); + } + } + if (pred->preds.empty()) { + break; + } + pred = pred->preds.front(); + } while (pred); + + return true; +} + +BB *Riscv64CGFunc::IsolateFastPath(BB *bb) { + // Issue #1103 + /* Detect "if (cond) return" fast path, and move extra instructions + * to the slow path. + * Must match the following block structure. BB1 can be a series of + * single-pred/single-succ blocks. + * BB1 ops1 cmp-br to BB3 BB1 cmp-br to BB3 + * BB2 ops2 br to retBB ==> BB2 ret + * BB3 slow path BB3 ops1 ops2 + * BB3 will be used to generate prolog stuff. + */ + if (bb->prev) { + return nullptr; + } + BB *ifbb = nullptr; + BB *returnbb = nullptr; + BB *coldbb = nullptr; + { + BB *curbb = bb; + /* Look for straight line code */ + while (1) { + if (curbb->eh_succs.size() != 0) { + return nullptr; + } + if (curbb->succs.size() == 1) { + if (curbb->GetKind() == BB::kBBCall) { + return nullptr; + } + BB *succ = curbb->succs.front(); + if (succ->preds.size() != 1 || succ->eh_preds.size() != 0) { + return nullptr; + } + curbb = succ; + } else if (curbb->GetKind() == BB::kBBIf) { + ifbb = curbb; + break; + } else { + return nullptr; + } + } + } + /* targets of if bb can only be reached by if bb */ + { + BB *first = ifbb->succs.front(); + BB *second = ifbb->succs.back(); + if (first->preds.size() != 1 || first->eh_preds.size() != 0) { + return nullptr; + } + if (second->preds.size() != 1 || second->eh_preds.size() != 0) { + return nullptr; + } + + /* One target of the if bb jumps to a return bb */ + if (first->GetKind() == BB::kBBGoto && first->succs.front()->GetKind() == BB::kBBReturn) { + if (second->succs.size() == 0) { + return nullptr; + } + returnbb = first; + coldbb = second; + } else { + return nullptr; + } + } + /* The control flow matches at this point. + * Make sure the hot bb contains atmost a + * 'mov x0, value' and 'b'. + */ + { + if (returnbb->NumInsn() > 2) { + return nullptr; + } + Insn *first = returnbb->firstinsn; + while (first->IsImmaterialInsn()) { + first = first->next; + } + if (first == returnbb->lastinsn) { + if (!first->IsBranch()) { + return nullptr; + } + } else { + MOperator opcode = first->GetMachineOpcode(); + /* only allow mov constant */ + if (opcode != MOP_xmovri64) { + return nullptr; + } + Insn *last = returnbb->lastinsn; + if (!last->IsBranch()) { + return nullptr; + } + } + } + /* + * Resolve any register usage issues. + * 1) Any use of parameter registes must be renamed + * 2) Any usage of callee saved register that needs saving in prolog + * must be able to move down into the cold path. + */ + RegOperand *targetOpnd = nullptr; + { + /* Find the branch's src register for backward propagation. */ + Insn *condbr = ifbb->lastinsn; + Operand *srcopnd1 = condbr->opnds[0]; + if (srcopnd1 == nullptr) { + return nullptr; + } + targetOpnd = static_cast(srcopnd1); + if (targetOpnd->GetRegisterType() != kRegTyInt) { + return nullptr; + } + } + /* Search backward looking for dependencies for the cond branch */ + std::list insnlist; // instructions to be moved to coldbb + Insn *ld = nullptr; + Insn *mv = nullptr; + Insn *depmv = nullptr; + // The mv is the 1st move using the parameter register leading to the branch + // The ld is the load using the parameter register indirectly for the branch + // The depmv is the move which preserves the result of the load but might + // destroy a parameter register which will be moved below the branch. + if (BackwardFindDependency(ifbb, returnbb, targetOpnd, ld, mv, depmv, insnlist) == false) { + return nullptr; + } + if (ld == nullptr || mv == nullptr) { + return nullptr; + } + /* depmv can be live out, so duplicate it + * and set dest to output of ld and src R16 + */ + if (depmv) { + CG_ASSERT(depmv->GetMachineOpcode(), "return check"); + Insn *newMv = cg->BuildInstruction( + depmv->GetMachineOpcode(), ld->opnds[0], + GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)(R16), depmv->opnds[1]->GetSize(), kRegTyInt)); + insnlist.push_front(newMv); + /* temporary put it some where */ + coldbb->InsertInsnBegin(newMv); + } else { + uint32 regsize = ld->opnds[0]->GetSize(); + Insn *newMv = + cg->BuildInstruction(MOP_xmovri64, ld->opnds[0], + GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)(R16), regsize, kRegTyInt)); + insnlist.push_front(newMv); + /* temporary put it some where */ + coldbb->InsertInsnBegin(newMv); + } + + ForwardPropagateAndRename(mv, ld, returnbb); + + std::list::iterator it; + for (it = insnlist.begin(); it != insnlist.end(); it++) { + Insn *in = *it; + in->bb->RemoveInsn(in); + coldbb->InsertInsnBegin(in); + } + + // All instructions are in the right place, replace branch to ret bb to just ret. + returnbb->RemoveInsn(returnbb->lastinsn); + returnbb->AppendInsn(cg->BuildInstruction(MOP_xret)); + // bb is now a retbb and has no succ. + returnbb->SetKind(BB::kBBReturn); + BB *tgtBB = returnbb->succs.front(); + auto predIt = std::find(tgtBB->preds.begin(), tgtBB->preds.end(), returnbb); + tgtBB->preds.erase(predIt); + returnbb->succs.clear(); + + return coldbb; +} + +void Riscv64CGFunc::Savelockinfo(BB * bb) { + BB *formerCurbb = curbb; + dummybb->ClearInsns(); + curbb = dummybb; + RegOperand *baseOpnd = GetOrCreateStackBaseRegOperand(); + RegOperand *tmpreg = CreateRegisterOperandOfType(PTY_u64); + Riscv64ImmOperand *locknum = CreateImmOperand(func->lockslotnum, 64, false); + + Riscv64SymbolAlloc symalloc; + Riscv64MemLayout *memlayout = static_cast(this->memlayout); + symalloc.mem_segment = &memlayout->seg_lockobjslot; + symalloc.offset = 0; + + int32 slotbase = GetBaseOffset(&symalloc); + + MemOperand *stackloc = CreateMemOpnd(baseOpnd, slotbase, 64); + + if (func->lockslotnum == 0) { + tmpreg = &Riscv64RegOperand::Get64bitZeroRegister(); + } else { + SelectCopy(tmpreg, PTY_u64, locknum, PTY_u64); + } + + auto allocInsn = cg->BuildInstruction(MOP_xstr, tmpreg, stackloc); + curbb->AppendInsn(allocInsn); + + bb->InsertAtBeginning(dummybb); + curbb = formerCurbb; +} + +void Riscv64CGFunc::GenSavemethodinfoCode(BB * bb) { + if (cg->UseFastUnwind()) { + BB *formerCurbb = curbb; + dummybb->ClearInsns(); + curbb = dummybb; + // FUNCATTR_bridge for function: Ljava_2Flang_2FString_3B_7CcompareTo_7C_28Ljava_2Flang_2FObject_3B_29I, to + // exclude this funciton this function is a bridge function generated for Java Genetic + if ((func->GetAttr(FUNCATTR_native) || func->GetAttr(FUNCATTR_fast_native)) && + !func->GetAttr(FUNCATTR_critical_native) && !func->GetAttr(FUNCATTR_bridge)) { + RegOperand *fpreg = GetOrCreatePhysicalRegisterOperand(RFP, SIZEOFPTR * BITS_PER_BYTE, kRegTyInt); + + Riscv64ListOperand *srcOpnds = memPool->New(funcscope_allocator_); + Riscv64RegOperand *parmregopnd = GetOrCreatePhysicalRegisterOperand(R0, 64, kRegTyInt); + srcOpnds->PushOpnd(parmregopnd); + Operand *immopnd = CreateImmOperand(0, 64, false); + curbb->AppendInsn(cg->BuildInstruction(MOP_xadri64, parmregopnd, immopnd)); + parmregopnd = GetOrCreatePhysicalRegisterOperand(R1, 64, kRegTyInt); + srcOpnds->PushOpnd(parmregopnd); + SelectCopy(parmregopnd, PTY_a64, fpreg, PTY_a64); + + MIRSymbol *sym = GlobalTables::GetGsymTable().CreateSymbol(kScopeGlobal); + std::string funcname(GetIntrinsicFuncName(INTRN_MCCSetRiskyUnwindContext)); + sym->SetNameStridx(GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(funcname)); + + sym->storageClass = kScText; + sym->sKind = kStFunc; + + Operand *targetopnd = GetOrCreateFuncNameOpnd(sym); + Insn *callInsn = cg->BuildInstruction(MOP_xbl, targetopnd, srcOpnds); + curbb->AppendInsn(callInsn); + bb->SetKind(BB::kBBCall); + } + + bb->InsertAtBeginning(dummybb); + curbb = formerCurbb; + } +} + +/* Insert stp/str xzr, [mem] for each spill slot. */ +void Riscv64CGFunc::InitialSpillSlot(BB * bb) { + Riscv64MemLayout *riscv64MemLayout = static_cast(memlayout); + int32 offset = riscv64MemLayout->RealStackFrameSize() - (SizeOfCalleeSaved() - 2 * kIntregBytelen /*for FP/LR*/); + + if (riscv64MemLayout->GetUnusedSlot()) { + offset -= kIntregBytelen; + } + + int32 spillSize = RoundUp(riscv64MemLayout->GetSizeOfSpillReg(), SIZEOFPTR); + offset -= spillSize; + + if (cg->UseFP() || HasVLAOrAlloca()) { + offset -= memlayout->SizeOfArgsToStackpass(); + } + + int32 i = 0; + for (; i <= spillSize - 2 * kIntregBytelen; i += (2 * kIntregBytelen)) { + if ((offset + i) > STP_LDP_IMM64_UPPER_BOUND) { + break; + } + Insn *pushInsn0 = cg->BuildInstruction(MOP_xstr, GetZeroOpnd(64), + CreateStkTopOpnd(offset + i, SIZEOFPTR * BITS_PER_BYTE)); + Insn *pushInsn1 = cg->BuildInstruction(MOP_xstr, GetZeroOpnd(64), + CreateStkTopOpnd(offset + i + 8, SIZEOFPTR * BITS_PER_BYTE)); + if (cg->GenerateVerboseAsm()) { + std::string key = "initial spill slot"; + pushInsn0->AddComment(key); + pushInsn1->AddComment(key); + } + bb->AppendInsn(pushInsn0); + bb->AppendInsn(pushInsn1); + } + + for (; i <= spillSize - kIntregBytelen; i += kIntregBytelen) { + uint32 datasize = SIZEOFPTR * BITS_PER_BYTE; + Operand* memopnd = CreateStkTopOpnd(offset + i, datasize); + if (IsImmediateOffsetOutOfRange(static_cast(memopnd), datasize)) { + memopnd = SplitOffsetWithAddInstruction(static_cast(memopnd), datasize, R9); + } + + Insn* pushInsn = cg->BuildInstruction( MOP_xstr, GetZeroOpnd(64), memopnd); + if (cg->GenerateVerboseAsm()) { + std::string key = "initial spill slot"; + pushInsn->AddComment(key); + } + bb->AppendInsn(pushInsn); + } +} + +void Riscv64CGFunc::AppendInstructionStackCheck(Riscv64reg_t reg, RegType rty, int offset) { + // sub x16, sp, #0x2000 + auto x16Opnd = GetOrCreatePhysicalRegisterOperand(reg, 64, rty); + auto spOpnd = GetOrCreatePhysicalRegisterOperand(RSP, 64, rty); + auto imm1 = CreateImmOperand(offset, 64, true); + SelectSub(x16Opnd, spOpnd, imm1, PTY_u64); + + // ldr wzr, [x16] + auto &wzr = Riscv64RegOperand::Get32bitZeroRegister(); + auto refX16 = CreateMemOpnd(reg, 0, 64); + auto soeInstr = cg->BuildInstruction(MOP_wldr, &wzr, refX16); + if (cg->GenerateVerboseAsm()) { + soeInstr->AddComment("soerror"); + } + soeInstr->do_not_remove = true; + AppendInstructionTo(soeInstr, this); +} + +void Riscv64CGFunc::GenerateProlog(BB * bb) { + BB *formerCurbb = curbb; + dummybb->ClearInsns(); + dummybb->isProEpilog = true; + curbb = dummybb; + ParmLocator parmlocator(becommon); + Operand *spOpnd = GetOrCreatePhysicalRegisterOperand(RSP, 64, kRegTyInt); + Operand *fpOpnd = GetOrCreatePhysicalRegisterOperand(RFP, 64, kRegTyInt); + if (!hasProEpilogue) { + return; + } + + if (func->IsJava()) { + // modify return-address to tag this frame as Java frame + Operand *lrOpnd = GetOrCreatePhysicalRegisterOperand(RRA, 64, kRegTyInt); + Operand *imm1 = CreateImmOperand(1, 64, true); + SelectAdd(lrOpnd, lrOpnd, imm1, PTY_u64); + } + + // insert .loc for function + if (cg->cgopt_.WithLoc()) { + if (cg->cgopt_.WithSrc()) { + uint32 tempmaxsize = mirModule.srcFileInfo.size(); + uint32 endfilenum = mirModule.srcFileInfo[tempmaxsize - 1].second; + if (func->srcPosition.Filenum() != 0 && func->srcPosition.Filenum() <= endfilenum) { + Operand *o0 = CreateDbgImmOperand(func->srcPosition.Filenum()); + // Operand *o1 = CreateDbgImmOperand((func->srcPosition->Linenum() ? func->srcPosition->Linenum() : 1)); + int64_t lineNum = func->srcPosition.Linenum(); + if (lineNum == 0) { + if (func->funcAttrs.GetAttr(FUNCATTR_native)) { + lineNum = 0xffffe; + } else { + lineNum = 0xffffd; + } + } + Operand *o1 = CreateDbgImmOperand(lineNum); + Insn *loc = cg->BuildInstruction(mpldbg::OP_DBG_loc, o0, o1); + curbb->AppendInsn(loc); + } + } else { + Operand *o0 = CreateDbgImmOperand(1); + // line number might not be available. + //CG_ASSERT(func->srcPosition.MplLinenum(), "return check"); + Operand *o1 = CreateDbgImmOperand(func->srcPosition.MplLinenum()); + Insn *loc = cg->BuildInstruction(mpldbg::OP_DBG_loc, o0, o1); + curbb->AppendInsn(loc); + } + } + + MapleVector ®sToSave = GetCalleeSavedRegs(); + if (regsToSave.size() > 0) { + // Among other things, push the FP & LR pair. + // FP/LR are added to the callee-saved list in AllocateRegisters() + // We add them to the callee-saved list regardless of UseFP() being true/false. + // Activation Frame is allocated as part of pushing FP/LR pair + GeneratePushRegs(); + } else { + int64 stackFrameSize = static_cast(memlayout)->RealStackFrameSize(); + if (stackFrameSize > 0) { + if (cg->GenerateVerboseAsm()) { + curbb->AppendInsn( + cg->BuildInstruction(MOP_comment, CreateCommentOperand("allocate activation frame"))); + } + Operand *immopnd = CreateImmOperand(stackFrameSize, 32, true); + SelectSub(spOpnd, spOpnd, immopnd, PTY_u64); + + if (cg->GenerateCfiDirectives()) { + int offset = stackFrameSize; + (void)InsertCFIDefCfaOffset(offset, curbb->lastinsn); + } + } + if (cg->UseFP() || HasVLAOrAlloca()) { + if (cg->GenerateVerboseAsm()) { + curbb->AppendInsn(cg->BuildInstruction(MOP_comment, CreateCommentOperand("copy SP to FP"))); + } + int64 argsToStkpassSize = memlayout->SizeOfArgsToStackpass(); + if (argsToStkpassSize > 0) { + Operand *immopnd = CreateImmOperand(argsToStkpassSize, 32, true); + SelectAdd(fpOpnd, spOpnd, immopnd, PTY_u64); + if (cg->GenerateCfiDirectives()) { + // curbb->AppendInsn(cg->BuildInstruction( cfi::OP_CFI_def_cfa_register, + // CreateCfiRegOperand(RFP,64))); + cfi::ImmOperand *imm = memPool->New( + static_cast(memlayout)->RealStackFrameSize() - argsToStkpassSize, 64); + curbb->AppendInsn( + cg->BuildInstruction(cfi::OP_CFI_def_cfa, CreateCfiRegOperand(RFP, 64), imm)); + } + } else { + SelectCopy(fpOpnd, PTY_u64, spOpnd, PTY_u64); + if (cg->GenerateCfiDirectives()) { + curbb->AppendInsn( + cg->BuildInstruction(cfi::OP_CFI_def_cfa_register, CreateCfiRegOperand(RFP, 64))); + } + } + } + } + if (CLANG && func->GetAttr(FUNCATTR_varargs)) { + Riscv64MemLayout *memlayout = static_cast(this->memlayout); + uint32 dataSizeBits = SIZEOFPTR * BITS_PER_BYTE; + int32 offset = memlayout->GetGRSaveareaBaseLoc(); + if (memlayout->GetSizeOfGRSavearea() % RISCV64_STACK_PTR_ALIGNMENT) { + offset += SIZEOFPTR; // End of area should be aligned. Hole between VR and GR area + } + int32 start_regno = 8 - (memlayout->GetSizeOfGRSavearea() / SIZEOFPTR); + CG_ASSERT(start_regno <= 8, "Incorrect starting GR regno for GR Save Area"); + for (int32 i = start_regno + (int)R10; i <= (int)R17; i++) { + Operand *stackloc = CreateStkTopOpnd(offset, dataSizeBits); + RegOperand *reg= GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)i, 64, kRegTyInt); + Insn *inst = cg->BuildInstruction( + PickStInsn(dataSizeBits, PTY_i64), reg, stackloc); + curbb->AppendInsn(inst); + offset += SIZEOFPTR; + } + } + if (cg->DoCheckSOE()) { + AppendInstructionStackCheck(R16, kRegTyInt, SOE_CHCK_OFFSET); + } + bb->InsertAtBeginning(dummybb); + curbb = formerCurbb; + dummybb->isProEpilog = false; +} + +void Riscv64CGFunc::GenerateRet(BB * bb) { + bb->AppendInsn(cg->BuildInstruction(MOP_xret)); +} + +bool Riscv64CGFunc::HasStackLoadStore() { + FOR_ALL_BB(bb, this) { + FOR_BB_INSNS(insn, bb) { + for (int32_t i = 0; i < Insn::kMaxOperandNum; i++) { + Operand *opnd = insn->GetOperand(i); + if (!opnd) { + continue; + } + + if (opnd->IsMemoryAccessOperand()) { + MemOperand *memopnd = static_cast(opnd); + Operand *base = memopnd->GetBaseRegister(); + + if (base != nullptr && base->IsRegister()) { + RegOperand *regOpnd = static_cast(base); + RegType regtype = regOpnd->GetRegisterType(); + uint32 regno = regOpnd->GetRegisterNumber(); + if ((regtype != kRegTyCc && (regno == RFP || regno == RSP)) || regtype == kRegTyVary) { + return true; + } + } + } + } + } + } + return false; +} + +bool Riscv64CGFunc::HasClinit() { + FOR_ALL_BB(bb, this) { + FOR_BB_INSNS(insn, bb) { + if (insn->mop_ == MOP_clinit || insn->mop_ == MOP_clinit_tail) { + return true; + } + } + } + return false; +} + +bool Riscv64CGFunc::HasCall() { + FOR_ALL_BB(bb, this) { + FOR_BB_INSNS(insn, bb) { + if (insn->IsCall()) { + return true; + } + } + } + return false; +} + +bool Riscv64CGFunc::HasLoop() { + FOR_ALL_BB(bb, this) { + if (bb->IsBackEdgeDest()) { + return true; + } + } + return false; +} + +/* + Remove redundant mov and mark optimizable bl/blr insn in the BB. + Return value: true if is empty bb, otherwise false. + */ +bool Riscv64CGFunc::OptimizeTailBB(BB * bb, set & callInsns) { + FOR_BB_INSNS_REV_SAFE(insn, bb, prev_insn) { + if (!insn->IsMachineInstruction()) { + continue; + } + MOperator insnMop = insn->GetMachineOpcode(); + switch (insnMop) { + case MOP_wmovrr: + case MOP_xmovrr: { + CG_ASSERT(insn->GetOperand(0)->IsRegister() && insn->GetOperand(1)->IsRegister(), "expects registers"); + Riscv64RegOperand *reg1 = static_cast(insn->GetOperand(0)); + Riscv64RegOperand *reg2 = static_cast(insn->GetOperand(1)); + CG_ASSERT((reg1 && reg2), "invalid insn"); + + if (reg1->GetRegisterNumber() != R10 || reg2->GetRegisterNumber() != R10) { + return false; + } + + bb->RemoveInsn(insn); + break; + } + case MOP_xbl: { + callInsns.insert(insn); + return false; + } + case MOP_xblr: { + callInsns.insert(insn); + return false; + } + default: + return false; + } + } + + return true; +} + +/* Recursively invoke this function until exitBB's precursor not exist.*/ +void Riscv64CGFunc::TailCallBBOpt(BB * exitBB, set & callInsns) { + for (auto tmpBB : exitBB->preds) { + if (tmpBB->succs.size() != 1 || tmpBB->eh_succs.size() != 0 || + (tmpBB->GetKind() != BB::kBBFallthru && tmpBB->GetKind() != BB::kBBCall)) { + continue; + } + + if (OptimizeTailBB(tmpBB, callInsns)) { + TailCallBBOpt(tmpBB, callInsns); + } + } +} + +/* + If a function without callee-saved register, and end with a function call, + then transfer bl/blr to b/br. + Return value: true if function do not need Prologue/Epilogue. false otherwise. + */ +bool Riscv64CGFunc::TailCallOpt() { + BB *exitBB = nullptr; + MapleVector ®sToRestore = GetCalleeSavedRegs(); + + CG_ASSERT(regsToRestore.size() >= 2, "Forgot FP and LR ?"); + + if ((mirModule.IsCModule()) && + static_cast(memlayout)->locals().size > 0) { + return false; + } + + if (CLANG && func->GetAttr(FUNCATTR_varargs)) { + return false; + } + + if (regsToRestore.size() > 2 || HasStackLoadStore() || HasLoop() || func->GetAttr(FUNCATTR_callersensitive) || + (mirModule.IsJavaModule() && IsFuncNeedFrame(GetName()))) { + return false; + } + + uint32 exitbbsize = exitbbsvec.size(); + + CG_ASSERT(exitbbsize == 1, "Should not be exist multiple exits."); + + if (exitbbsize == 0) { + if (lastbb->prev->firststmt == cleanup_label && lastbb->prev->prev) { + exitBB = lastbb->prev->prev; + } else { + exitBB = lastbb->prev; + } + } else { + exitBB = exitbbsvec.front(); + } + + CG_ASSERT(exitBB->firstinsn == nullptr, "exit bb should be empty."); + + // Count how many call insns in the whole function. + int nCount = 0; + bool hasGetStackClass = false; + + FOR_ALL_BB(bb, this) { + FOR_BB_INSNS(insn, bb) { + if (insn->IsCall()) { + if (insn->GetMachineOpcode() == MOP_xbl) { + FuncNameOperand *target = static_cast(insn->opnds[0]); + if (mirModule.IsJavaModule() && IsFuncNeedFrame(target->GetName())) { + hasGetStackClass = true; + } + } + nCount++; + } + } + } + + if (nCount > 0 && func->GetAttr(FUNCATTR_interface)) { + return false; + } + + if (hasGetStackClass) { + return false; + } + + set callInsns; + + TailCallBBOpt(exitBB, callInsns); + + if (nCount == callInsns.size()) { + // Replace all of the call insns. + for (auto callInsn : callInsns) { + MOperator insnMop = callInsn->GetMachineOpcode(); + switch (insnMop) { + case MOP_xbl: { + callInsn->SetMOP(MOP_tail_call_opt_xbl); + break; + } + case MOP_xblr: { + callInsn->SetMOP(MOP_tail_call_opt_xblr); + break; + } + default: + CG_ASSERT(false, "Internal error."); + } + } + } else { + return false; + } + + return true; +} + +void Riscv64CGFunc::GenerateEpilogForCleanup(BB * bb) { + CG_ASSERT(exitbbsvec.size() > 0, "exit bb size is zero!"); + if (exitbbsvec[0]->unreachable) { // if exitbb is unreachable then exitbb can not be generated + GenerateEpilog(bb); + } else if (NeedCleanup()) { // bl to the exit epilogue + LabelOperand *targetopnd = GetOrCreateLabelOperand(exitbbsvec[0]->labidx); + bb->AppendInsn(cg->BuildInstruction(MOP_xuncond, targetopnd)); + } +} + +bool Riscv64CGFunc::IsCommentBB(BB * bb) { + FOR_BB_INSNS(insn, bb) { + if (!insn->IsMachineInstruction()) { + continue; + } else { + return false; + } + } + return true; +} + +/* If all the preds of exitBB made the TailcallOpt(replace blr/bl with br/b), return true, we don't create ret insn. + Otherwise, return false, create the ret insn. + */ +bool Riscv64CGFunc::TestPredsOfRetBB(BB * exitBB) { + for (auto tmpBB : exitBB->preds) { + Insn *firstInsn = tmpBB->firstinsn; + if ((firstInsn == nullptr || IsCommentBB(tmpBB)) && (!tmpBB->preds.empty())) { + if (TestPredsOfRetBB(tmpBB)) { + continue; + } else { + return false; + } + } else { + Insn *lastInsn = tmpBB->lastinsn; + if (lastInsn != nullptr) { + MOperator insnMop = lastInsn->GetMachineOpcode(); + if (MOP_tail_call_opt_xbl == insnMop || MOP_tail_call_opt_xblr == insnMop) { + continue; + } else { + return false; + } + } else { + return false; + } + } + } + return true; +} + +void Riscv64CGFunc::GenerateEpilog(BB * bb) { + BB *formerCurbb = curbb; + dummybb->ClearInsns(); + dummybb->isProEpilog = true; + curbb = dummybb; + + if (!hasProEpilogue) { + if (bb->preds.empty()) { + GenerateRet(curbb); + bb->AppendBBInsns(curbb); + curbb = formerCurbb; + } else { + if (!TestPredsOfRetBB(bb)) { + GenerateRet(curbb); + bb->AppendBBInsns(curbb); + curbb = formerCurbb; + } + } + return; + } + + if (cg->AddStackGuard()) { // && CGOptions::inRange) + MIRSymbol *stkguardsym = GlobalTables::GetGsymTable().GetSymbolFromStrIdx(GlobalTables::GetStrTable().GetStrIdxFromName("__stack_chk_guard")); + StImmOperand *stopnd = CreateStImmOperand(stkguardsym, 0, 0); + Riscv64RegOperand *staddropnd = + static_cast(GetOrCreatePhysicalRegisterOperand(R9, SIZEOFPTR * 8, kRegTyInt)); + SelectAddrof(staddropnd, stopnd); + Riscv64MemOperand *guardmemopn = + memPool->New(SIZEOFPTR * 8, staddropnd, + static_cast(nullptr), GetOrCreateOfstOpnd(0, 32), stkguardsym); + MOperator mop = PickLdInsn(64, PTY_u64); + Insn *ins = cg->BuildInstruction(mop, staddropnd, guardmemopn); + ins->do_not_remove = true; + curbb->AppendInsn(ins); + + int varea = 0; + if (CLANG && func->GetAttr(FUNCATTR_varargs)) { + Riscv64MemLayout *ml = static_cast(memlayout); + int vsize = ml->GetSizeOfGRSavearea(); + if (vsize > 0) { + varea += RoundUp(vsize, RISCV64_STACK_PTR_ALIGNMENT); + } + } + + Riscv64RegOperand *checkopn = + static_cast(GetOrCreatePhysicalRegisterOperand(R12, SIZEOFPTR * 8, kRegTyInt)); + Riscv64MemOperand *downstk = nullptr; + if (cg->UseFP() || HasVLAOrAlloca()) { + int32 stksize = static_cast(memlayout)->RealStackFrameSize() - + static_cast(memlayout)->SizeOfArgsToStackpass() - + varea; + downstk = memPool->New(RFP, stksize - 8, SIZEOFPTR * BITS_PER_BYTE); + } else { + downstk = memPool->New(RSP, static_cast(memlayout)->RealStackFrameSize() - 8 - varea, + SIZEOFPTR * BITS_PER_BYTE); + } + + if (IsImmediateOffsetOutOfRange(static_cast(downstk), 64)) { + downstk = SplitOffsetWithAddInstruction(static_cast(downstk), 64, R12); + } + + mop = PickLdInsn(SIZEOFPTR * BITS_PER_BYTE, PTY_u64); + ins = cg->BuildInstruction(mop, checkopn, downstk); + ins->do_not_remove = true; + curbb->AppendInsn(ins); + SelectBxor(staddropnd, staddropnd, checkopn, PTY_u64); + LabelIdx faillable = CreateLabel(); + RegOperand *zero = GetOrCreatePhysicalRegisterOperand(R0, SIZEOFPTR * 8, kRegTyInt); + SelectCondGoto(GetOrCreateLabelOperand(faillable), OP_brtrue, OP_eq, staddropnd, zero, PTY_u64, false); + MIRSymbol *failfunc = GlobalTables::GetGsymTable().GetSymbolFromStrIdx(GlobalTables::GetStrTable().GetStrIdxFromName("__stack_chk_fail")); + Operand *targetopnd = GetOrCreateFuncNameOpnd(failfunc); + Riscv64ListOperand *srcOpnds = memPool->New(funcscope_allocator_); + Insn *callInsn = cg->BuildInstruction(MOP_xbl, targetopnd, srcOpnds); + callInsn->do_not_remove = true; + curbb->AppendInsn(callInsn); + + bb->AppendBBInsns(curbb); + + BB *newbb = CreateNewBB(); + newbb->AddLabel(faillable); + lab2bbmap[newbb->labidx] = newbb; + bb->AppendBB(newbb); + if (lastbb == bb) { + lastbb = newbb; + } + newbb->unreachable = bb->unreachable; + curbb = newbb; + dummybb->isProEpilog = false; + bb = newbb; + } + + Operand *spOpnd = GetOrCreatePhysicalRegisterOperand(RSP, 64, kRegTyInt); + Operand *fpOpnd = GetOrCreatePhysicalRegisterOperand(RFP, 64, kRegTyInt); + + if (HasVLAOrAlloca()) { + SelectCopy(spOpnd, PTY_u64, fpOpnd, PTY_u64); + } + + // exit bb should always be reachable, since we need its existance for ".cfi_remember_state" + if (cg->GenerateCfiDirectives() && bb != lastbb && bb->next) { + BB *nextBB = bb->next; + do { + if (nextBB == lastbb || !nextBB->IsEmpty()) { + break; + } else { + nextBB = nextBB->next; + } + } while (nextBB); + if (!(nextBB == nullptr || nextBB->IsEmpty())) { + curbb->AppendInsn(cg->BuildInstruction(cfi::OP_CFI_remember_state)); + nextBB->InsertInsnBefore(nextBB->firstinsn, cg->BuildInstruction(cfi::OP_CFI_restore_state)); + } + } + + MapleVector ®sToSave = GetCalleeSavedRegs(); + if (regsToSave.size() > 0) { + GeneratePopRegs(); + } else { + int64 stackFrameSize = static_cast(memlayout)->RealStackFrameSize(); + if (stackFrameSize > 0) { + if (cg->GenerateVerboseAsm()) { + curbb->AppendInsn( + cg->BuildInstruction(MOP_comment, CreateCommentOperand("pop up activation frame"))); + } + + if (HasVLAOrAlloca()) { + stackFrameSize -= static_cast(memlayout)->seg__args_to_stkpass.size; + } + + if (stackFrameSize > 0) { + Operand *immopnd = CreateImmOperand(stackFrameSize, 32, true); + SelectAdd(spOpnd, spOpnd, immopnd, PTY_u64); + if (cg->GenerateCfiDirectives()) { + curbb->AppendInsn(cg->BuildInstruction(cfi::OP_CFI_def_cfa, CreateCfiRegOperand(RSP, 64), + CreateCfiImmOperand(0, 64))); + } + } + } + } + + if (func->IsJava()) { + // restore return-address before leaving a Java frame + Operand *lrOpnd = GetOrCreatePhysicalRegisterOperand(RRA, 64, kRegTyInt); + Operand *imm1 = CreateImmOperand(1, 64, true); + SelectSub(lrOpnd, lrOpnd, imm1, PTY_u64); + } + + if (cg->InstrumentWithDebugTraceCall()) { + AppendJump(cg->GetDebugTraceExitFunction()); + } + + GenerateRet(curbb); + if (!(cg->AddStackGuard())) { // && CGOptions::inRange)) + bb->AppendBBInsns(curbb); + } + curbb = formerCurbb; + dummybb->isProEpilog = false; +} + +void Riscv64CGFunc::GenerateYieldpoint(BB * bb) { + // ldr wzr, [RYP] # RYP hold address of the polling page. + auto &wzr = Riscv64RegOperand::Get32bitZeroRegister(); + auto pollingPage = CreateMemOpnd(RYP, 0, 32); + auto yieldPoint = cg->BuildInstruction(MOP_wldr, &wzr, pollingPage); + if (cg->GenerateVerboseAsm()) { + yieldPoint->AddComment("yieldpoint"); + } + bb->AppendInsn(yieldPoint); +} + +Operand *Riscv64CGFunc::GetTargetRetOperand(PrimType ptype, int32 sreg) { + uint8 bitsize = GetPrimTypeBitSize(ptype) < 32 ? 32 : GetPrimTypeBitSize(ptype); + Riscv64reg_t preg; + switch (sreg) { + case kSregRetval0: + preg = IsPrimitiveFloat(ptype) ? V10 : R10; + break; + case kSregRetval1: + preg = R11; + break; + default: + preg = RLAST_INT_REG; + CG_ASSERT(0, "GetTargetRetOperand: NYI"); + } + return GetOrCreatePhysicalRegisterOperand(preg, bitsize, GetRegTyFromPrimTyRiscv64(ptype)); +} + +RegOperand *Riscv64CGFunc::CreateRegisterOperandOfType(PrimType primtype) { + RegType regty = GetRegTyFromPrimTyRiscv64(primtype); + uint32 bytelen = GetPrimTypeSize(primtype); + return CreateRegisterOperandOfType(regty, bytelen); +} + +RegOperand *Riscv64CGFunc::CreateRegisterOperandOfType(RegType regty, uint32 bytelen) { + // Enhance when half-precision floating point operations are supported. + if (bytelen < 4) { + bytelen = 4; // Riscv64 has 32-bit and 64-bit registers only + } + regno_t vRegNo = New_V_Reg(regty, bytelen); + return CreateVirtualRegisterOperand(vRegNo); +} + +void Riscv64CGFunc::MergeReturn() { + CG_ASSERT(((mirModule.IsCModule()) + || (curbb->prev->firststmt == cleanup_label)), "must be"); + + BB *tmpBb = nullptr; + uint32 exitbbsize = exitbbsvec.size(); + if (exitbbsize == 0) { + return; + } + if (exitbbsize == 1 && exitbbsvec[0] == curbb) { + return; + } + if (1 == exitbbsize) { + BB *onlyExitBB = exitbbsvec[0]; + BB *onlyExitBbNext = onlyExitBB->next; + StmtNode *stmt = onlyExitBbNext->firststmt; + // only deal with the return_BB in the middle + if (stmt != cleanup_label) { + BB *retbb = CreateNewBB(); + retbb->SetKind(BB::kBBReturn); + retbb->frequency = onlyExitBB->frequency; + onlyExitBB->AppendBB(retbb); + LabelIdx labidx = CreateLabel(); + retbb->AddLabel(labidx); + lab2bbmap[labidx] = retbb; + // modify the original return BB. + BB::BBKind k = onlyExitBB->kind; + CG_ASSERT(k == BB::kBBReturn, "Error: suppose to merge multi return bb"); + onlyExitBB->SetKind(BB::kBBFallthru); + + exitbbsvec.pop_back(); + exitbbsvec.push_back(retbb); + return; + } + } + BB *retbb = CreateNewBB(); + cleanupbb->PrependBB(retbb); + retbb->SetKind(BB::kBBReturn); + LabelIdx labidx = CreateLabel(); + retbb->AddLabel(labidx); + lab2bbmap[labidx] = retbb; + LabelOperand *targetopnd = GetOrCreateLabelOperand(labidx); + + uint32_t freq = 0; + for (uint32 i = 0; i < exitbbsize; i++) { + tmpBb = exitbbsvec[i]; + BB::BBKind k = tmpBb->kind; + CG_ASSERT(k == BB::kBBReturn, "Error: suppose to merge multi return bb"); + tmpBb->SetKind(BB::kBBGoto); + tmpBb->AppendInsn(cg->BuildInstruction(MOP_xuncond, targetopnd)); + freq += tmpBb->frequency; + } + for (uint32 i = 0; i < exitbbsize; i++) { + exitbbsvec.pop_back(); + } + retbb->frequency = freq; + exitbbsvec.push_back(retbb); + return; +} + +void Riscv64CGFunc::HandleRetCleanup(NaryStmtNode * retnode) { + if (!cg->GenLocalRC()) { + // handle local rc is disabled. + return; + } + + Opcode ops[15] = { OP_label, OP_goto, OP_brfalse, OP_brtrue, OP_return, OP_call, + OP_icall, OP_rangegoto, OP_javacatch, OP_javatry, OP_catch, OP_try, + OP_cpptry, OP_cppcatch, OP_endtry }; + set branchop(ops, ops + 11); + + // get cleanup intrinsic + bool found = false; + StmtNode *cleanupnode = retnode->GetPrev(); + while (cleanupnode) { + if (branchop.find(cleanupnode->op) != branchop.end()) { + if (cleanupnode->op == OP_call) { + CallNode *callnode = static_cast(cleanupnode); + MIRFunction *fn = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(callnode->puIdx); + MIRSymbol *fsym = mirModule.CurFunction()->GetLocalOrGlobalSymbol(fn->stIdx, false); + if (IsRtCleanupFunc(fsym->GetName())) { + cleanupnode = cleanupnode->GetPrev(); + continue; + } else { + break; + } + } else { + break; + } + } + + if (OP_intrinsiccall == cleanupnode->op) { + IntrinsiccallNode *tempnode = static_cast(cleanupnode); + if (tempnode->intrinsic == INTRN_MPL_CLEANUP_LOCALREFVARS || + tempnode->intrinsic == INTRN_MPL_CLEANUP_LOCALREFVARS_SKIP) { + if (GenRetCleanup(tempnode) && hasNonescapedVar) { + GenNonescapedobjcleanup(); + } + found = true; + break; + } + } + cleanupnode = cleanupnode->GetPrev(); + } + + if (!found) { + MIRSymbol *retRef = nullptr; + if (retnode->NumOpnds() != 0) { + retRef = GetRetRefSymbol(static_cast(retnode)->Opnd(0)); + } + HandleRCCall(false, retRef); + } +} + +bool Riscv64CGFunc::GenRetCleanup(IntrinsiccallNode * cleanupnode) { +#undef CC_DEBUG_INFO + +#ifdef CC_DEBUG_INFO + LogInfo::MapleLogger() << "==============" << func->GetName() << "==============" << endl; +#endif + + int32 minbyteoffset = INT_MAX; + int32 maxbyteoffset = 0; + + int skipindex = -1; + MIRSymbol *skipsym = nullptr; + int32 refsymnum = 0; + if (cleanupnode->intrinsic == INTRN_MPL_CLEANUP_LOCALREFVARS) { + refsymnum = cleanupnode->NumOpnds(); + if (refsymnum < 1) { + return true; + } + } else if (cleanupnode->intrinsic == INTRN_MPL_CLEANUP_LOCALREFVARS_SKIP) { + refsymnum = cleanupnode->NumOpnds(); + if (refsymnum < 2) { + return true; + } + BaseNode *skipexpr = cleanupnode->Opnd(refsymnum - 1); + + CHECK_FATAL(skipexpr->op == OP_dread, "should be dread"); + DreadNode *refnode = static_cast(skipexpr); + skipsym = mirModule.CurFunction()->GetLocalOrGlobalSymbol(refnode->stIdx); + + refsymnum -= 1; + } + + // now compute the offset range + Riscv64MemLayout *memlayout = static_cast(this->memlayout); + for (int i = 0; i < refsymnum; i++) { + BaseNode *argexpr = cleanupnode->Opnd(i); + CHECK_FATAL(argexpr->op == OP_dread, "should be dread"); + DreadNode *refnode = static_cast(argexpr); + MIRSymbol *refsymbol = mirModule.CurFunction()->GetLocalOrGlobalSymbol(refnode->stIdx); + CHECK_FATAL(memlayout->sym_alloc_table.size() > refsymbol->GetStIndex(), "access memlayout->sym_alloc_table failed"); + Riscv64SymbolAlloc *symloc = + static_cast(memlayout->sym_alloc_table[refsymbol->GetStIndex()]); + int32 tempoff = GetBaseOffset(symloc); +#ifdef CC_DEBUG_INFO + LogInfo::MapleLogger() << "refsym " << refsymbol->GetName() << " offset " << tempoff << endl; +#endif + minbyteoffset = minbyteoffset > tempoff ? tempoff : minbyteoffset; + maxbyteoffset = maxbyteoffset < tempoff ? tempoff : maxbyteoffset; + } + + // get the skip offset + int32 skipoffset = -1; + if (skipsym) { + Riscv64SymbolAlloc *symloc = static_cast(memlayout->sym_alloc_table[skipsym->GetStIndex()]); + skipoffset = GetBaseOffset(symloc); + +#ifdef CC_DEBUG_INFO + LogInfo::MapleLogger() << "skip " << skipsym->GetName() << " offset " << skipoffset << endl; +#endif + + skipindex = symloc->offset / kIntregBytelen; + } + + // call runtime cleanup + + if (minbyteoffset < INT_MAX) { + int32 reflocbase = memlayout->GetReflocbaseLoc(); + uint32 refNum = memlayout->GetSizeOfRefLocals() / kIntregBytelen; + int32 reflocend = reflocbase + (refNum - 1) * kIntregBytelen; + int32 realmin = minbyteoffset < reflocbase ? reflocbase : minbyteoffset; + int32 realmax = maxbyteoffset > reflocend ? reflocend : maxbyteoffset; +#ifdef CC_DEBUG_INFO + LogInfo::MapleLogger() << " realmin " << realmin << " realmax " << realmax << endl; +#endif + if (realmax < realmin) { + HandleRCCall(false, skipsym); + return false; + } + + // optimization for little slot cleanup + if (realmax == realmin) { + RegOperand *phyopnd = GetOrCreatePhysicalRegisterOperand(R0, 64, kRegTyInt); + Operand *stackloc = CreateStkTopOpnd(realmin, SIZEOFPTR * BITS_PER_BYTE); + Insn *ldInsn = cg->BuildInstruction(PickLdInsn(64, PTY_a64), phyopnd, stackloc); + curbb->AppendInsn(ldInsn); + + Riscv64ListOperand *srcOpnds = memPool->New(funcscope_allocator_); + srcOpnds->PushOpnd(phyopnd); + MIRSymbol *callsym = GlobalTables::GetGsymTable().CreateSymbol(kScopeGlobal); + std::string funcname(GetIntrinsicFuncName(INTRN_MCCDecRef)); + callsym->SetNameStridx(GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(funcname)); + callsym->storageClass = kScText; + callsym->sKind = kStFunc; + + Operand *targetopnd = GetOrCreateFuncNameOpnd(callsym); + Insn *callInsn = cg->BuildInstruction(MOP_xbl, targetopnd, srcOpnds); + static_cast(callInsn)->ref_skipindex = skipindex; + curbb->AppendInsn(callInsn); + + curbb->SetKind(BB::kBBCall); + // because of return stmt is often the last stmt + curbb->frequency = frequency; + BB *newbb = CreateNewBB(); + curbb->AppendBB(newbb); + curbb = newbb; + + return true; + } + Riscv64ListOperand *srcOpnds = memPool->New(funcscope_allocator_); + + Riscv64ImmOperand *beginopnd = CreateImmOperand(realmin, 64, true); + + regno_t vreg0no = New_V_Reg(kRegTyInt, GetPrimTypeSize(PTY_a64)); + RegOperand *vreg0 = CreateVirtualRegisterOperand(vreg0no); + RegOperand *fpopnd = GetOrCreateStackBaseRegOperand(); + SelectAdd(vreg0, fpopnd, beginopnd, PTY_i64); + + Riscv64RegOperand *parmregopnd = GetOrCreatePhysicalRegisterOperand(R0, 64, kRegTyInt); + srcOpnds->PushOpnd(parmregopnd); + SelectCopy(parmregopnd, PTY_a64, vreg0, PTY_a64); + + uint32 realRefNum = (realmax - realmin) / kIntregBytelen + 1; + + Riscv64ImmOperand *countopnd = CreateImmOperand(realRefNum, 64, true); + + parmregopnd = GetOrCreatePhysicalRegisterOperand(R1, 64, kRegTyInt); + srcOpnds->PushOpnd(parmregopnd); + SelectCopyImm(parmregopnd, countopnd, PTY_i64); + + MIRSymbol *funcsym = GlobalTables::GetGsymTable().CreateSymbol(kScopeGlobal); + if (skipsym && skipoffset >= realmin && skipoffset <= realmax) { + // call cleanupskip + uint32 stoffset = (skipoffset - realmin) / kIntregBytelen; + Riscv64ImmOperand *retLoc = CreateImmOperand(stoffset, 64, true); + + parmregopnd = GetOrCreatePhysicalRegisterOperand(R2, 64, kRegTyInt); + srcOpnds->PushOpnd(parmregopnd); + SelectCopyImm(parmregopnd, retLoc, PTY_i64); + + std::string funcname(GetIntrinsicFuncName(INTRN_MCCCleanupLocalStackRefSkipNaiveRCFast)); + funcsym->SetNameStridx(GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(funcname)); +#ifdef CC_DEBUG_INFO + LogInfo::MapleLogger() << "num " << real_ref_num << " skip loc " << stoffset << endl; +#endif + } else { + // call cleanup + std::string funcname(GetIntrinsicFuncName(INTRN_MCCCleanupLocalStackRefNaiveRCFast)); + funcsym->SetNameStridx(GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(funcname)); +#ifdef CC_DEBUG_INFO + LogInfo::MapleLogger() << "num " << real_ref_num << endl; +#endif + } + + funcsym->storageClass = kScText; + funcsym->sKind = kStFunc; + + Operand *targetopnd = GetOrCreateFuncNameOpnd(funcsym); + Insn *callInsn = cg->BuildInstruction(MOP_xbl, targetopnd, srcOpnds); + static_cast(callInsn)->ref_skipindex = skipindex; + curbb->AppendInsn(callInsn); + + curbb->SetKind(BB::kBBCall); + curbb->frequency = frequency; + BB *newbb = CreateNewBB(); + curbb->AppendBB(newbb); + curbb = newbb; + } + return true; +} + +void Riscv64CGFunc::GenNonescapedobjcleanup() { + // Cleanup non-escaped objects that have been allocated on stack + for (size_t i = 1; i < func->symTab->GetSymbolTableSize(); i++) { + MIRSymbol *sym = func->symTab->GetSymbolFromStIdx(i); + if (!sym || !sym->GetType() || sym->GetType()->typeKind != kTypeClass) { + continue; + } + + Riscv64SymbolAlloc *symloc = static_cast(memlayout->sym_alloc_table[sym->GetStIndex()]); + Riscv64ImmOperand *offsetopnd = CreateImmOperand(GetBaseOffset(symloc), 64, true); + regno_t vreg0no = New_V_Reg(kRegTyInt, GetPrimTypeSize(PTY_a64)); + RegOperand *vreg0 = CreateVirtualRegisterOperand(vreg0no); + RegOperand *fpopnd = GetOrCreateStackBaseRegOperand(); + SelectAdd(vreg0, fpopnd, offsetopnd, PTY_i64); + + Riscv64RegOperand *parmregopnd = GetOrCreatePhysicalRegisterOperand(R0, 64, kRegTyInt); + Riscv64ListOperand *srcOpnds = memPool->New(funcscope_allocator_); + srcOpnds->PushOpnd(parmregopnd); + SelectCopy(parmregopnd, PTY_a64, vreg0, PTY_a64); + + MIRSymbol *callsym = GlobalTables::GetGsymTable().CreateSymbol(kScopeGlobal); + callsym->SetNameStridx(GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(GetIntrinsicFuncName(INTRN_MCCCleanupNonEscapedVar))); + callsym->storageClass = kScText; + callsym->sKind = kStFunc; + Operand *targetopnd = GetOrCreateFuncNameOpnd(callsym); + Insn *callInsn = cg->BuildInstruction(MOP_xbl, targetopnd, srcOpnds); + curbb->AppendInsn(callInsn); + curbb->SetKind(BB::kBBCall); + // Stmts are not all handled yet. + if (frequency != 0) { + curbb->frequency = frequency; + } + BB *newbb = CreateNewBB(); + newbb->frequency = curbb->frequency; + curbb->AppendBB(newbb); + curbb = newbb; + } +} + +void Riscv64CGFunc::HandleRCCall(bool begin, MIRSymbol *retRef) { + if (!cg->GenLocalRC()) { + // handle local rc is disabled. + return; + } + + if (!begin) { + GenNonescapedobjcleanup(); + } + Riscv64MemLayout *memlayout = static_cast(this->memlayout); + + uint32 refNum = memlayout->GetSizeOfRefLocals() / kIntregBytelen; + if (!refNum) { + if (begin) { + GenerateYieldpoint(curbb); + yieldPointInsn = curbb->lastinsn; + } + return; + } + + // no MCC_CleanupLocalStackRefSkip when ret_ref is the only ref symbol + if (refNum == 1 && retRef != nullptr) { + if (begin) { + GenerateYieldpoint(curbb); + yieldPointInsn = curbb->lastinsn; + } + return; + } + CHECK_FATAL(refNum < 0xFFFF, "not enough room for size."); + int32 reflocbase = memlayout->GetReflocbaseLoc(); + CHECK_FATAL(reflocbase >= 0 && reflocbase < 0xFFFF, "not enough room for offset."); + if (begin && refNum <= 6 && (reflocbase + 8 * (refNum - 1)) < STP_LDP_IMM64_UPPER_BOUND) { + int ind = 0; + while (ind < refNum) { + int offset = memlayout->GetReflocbaseLoc() + 8 * ind; + Operand *zeroop = GetZeroOpnd(64); + Operand *stackloc = CreateStkTopOpnd(offset, SIZEOFPTR * BITS_PER_BYTE); + Insn *setinc = cg->BuildInstruction(MOP_xstr, zeroop, stackloc); + curbb->AppendInsn(setinc); + ind++; + } + // Insert Yield Point just after localrefvar are initialized. + GenerateYieldpoint(curbb); + yieldPointInsn = curbb->lastinsn; + return; + } + + if (refNum == 1 && !begin && !retRef) { + RegOperand *phyopnd = GetOrCreatePhysicalRegisterOperand(R0, 64, kRegTyInt); + Operand *stackloc = CreateStkTopOpnd(memlayout->GetReflocbaseLoc(), SIZEOFPTR * BITS_PER_BYTE); + Insn *ldInsn = cg->BuildInstruction(PickLdInsn(64, PTY_a64), phyopnd, stackloc); + curbb->AppendInsn(ldInsn); + + Riscv64ListOperand *srcOpnds = memPool->New(funcscope_allocator_); + srcOpnds->PushOpnd(phyopnd); + MIRSymbol *callsym = GlobalTables::GetGsymTable().CreateSymbol(kScopeGlobal); + std::string funcname(GetIntrinsicFuncName(INTRN_MCCDecRef)); + callsym->SetNameStridx(GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(funcname)); + callsym->storageClass = kScText; + callsym->sKind = kStFunc; + + Operand *targetopnd = GetOrCreateFuncNameOpnd(callsym); + Insn *callInsn = cg->BuildInstruction(MOP_xbl, targetopnd, srcOpnds); + curbb->AppendInsn(callInsn); + + curbb->SetKind(BB::kBBCall); + if (frequency != 0) { + curbb->frequency = frequency; + } + BB *newbb = CreateNewBB(); + // After handle all stmts. + if (frequency == 0) { + newbb->frequency = curbb->frequency; + } + curbb->AppendBB(newbb); + curbb = newbb; + return; + } + + if (refNum == 2 && !begin && retRef) { + Riscv64SymbolAlloc *symloc = static_cast(memlayout->sym_alloc_table[retRef->GetStIndex()]); + int32 stoffset = symloc->offset / kIntregBytelen; + RegOperand *phyopnd = GetOrCreatePhysicalRegisterOperand(R0, 64, kRegTyInt); + Operand *stackloc = nullptr; + if (stoffset == 0) { + // just have to Dec the next one + stackloc = CreateStkTopOpnd(memlayout->GetReflocbaseLoc() + kIntregBytelen, SIZEOFPTR * BITS_PER_BYTE); + } else { + // just have to Dec the current one + stackloc = CreateStkTopOpnd(memlayout->GetReflocbaseLoc(), SIZEOFPTR * BITS_PER_BYTE); + } + Insn *ldInsn = cg->BuildInstruction(PickLdInsn(64, PTY_a64), phyopnd, stackloc); + curbb->AppendInsn(ldInsn); + + Riscv64ListOperand *srcOpnds = memPool->New(funcscope_allocator_); + srcOpnds->PushOpnd(phyopnd); + MIRSymbol *callsym = GlobalTables::GetGsymTable().CreateSymbol(kScopeGlobal); + std::string funcname(GetIntrinsicFuncName(INTRN_MCCDecRef)); + callsym->SetNameStridx(GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(funcname)); + callsym->storageClass = kScText; + callsym->sKind = kStFunc; + + Operand *targetopnd = GetOrCreateFuncNameOpnd(callsym); + Insn *callInsn = cg->BuildInstruction(MOP_xbl, targetopnd, srcOpnds); + static_cast(callInsn)->ref_skipindex = stoffset; + curbb->AppendInsn(callInsn); + + curbb->SetKind(BB::kBBCall); + if (frequency != 0) { + curbb->frequency = frequency; + } + BB *newbb = CreateNewBB(); + if (frequency == 0) { + newbb->frequency = curbb->frequency; + } + curbb->AppendBB(newbb); + curbb = newbb; + return; + } + + bool needSkip = false; + Riscv64ListOperand *srcOpnds = memPool->New(funcscope_allocator_); + + Riscv64ImmOperand *beginopnd = CreateImmOperand(memlayout->GetReflocbaseLoc(), 64, true); + Riscv64ImmOperand *countopnd = CreateImmOperand(refNum, 64, true); + int refskipindex = -1; + if (!begin && retRef) { + Riscv64SymbolAlloc *symloc = static_cast(memlayout->sym_alloc_table[retRef->GetStIndex()]); + int32 stoffset = symloc->offset / kIntregBytelen; + refskipindex = stoffset; + if (stoffset == 0) { + // ret_ref at begin + beginopnd = CreateImmOperand(memlayout->GetReflocbaseLoc() + kIntregBytelen, 64, true); + countopnd = CreateImmOperand(refNum - 1, 64, true); + } else if (stoffset == (refNum - 1)) { + // ret_ref at end + countopnd = CreateImmOperand(refNum - 1, 64, true); + } else { + needSkip = true; + } + } + + regno_t vreg0no = New_V_Reg(kRegTyInt, GetPrimTypeSize(PTY_a64)); + RegOperand *vreg0 = CreateVirtualRegisterOperand(vreg0no); + RegOperand *fpopnd = GetOrCreateStackBaseRegOperand(); + SelectAdd(vreg0, fpopnd, beginopnd, PTY_i64); + + Riscv64RegOperand *parmregopnd = GetOrCreatePhysicalRegisterOperand(R0, 64, kRegTyInt); + srcOpnds->PushOpnd(parmregopnd); + SelectCopy(parmregopnd, PTY_a64, vreg0, PTY_a64); + + regno_t vreg1no = New_V_Reg(kRegTyInt, GetPrimTypeSize(PTY_a64)); + RegOperand *vreg1 = CreateVirtualRegisterOperand(vreg1no); + SelectCopyImm(vreg1, countopnd, PTY_i64); + + parmregopnd = GetOrCreatePhysicalRegisterOperand(R1, 64, kRegTyInt); + srcOpnds->PushOpnd(parmregopnd); + SelectCopy(parmregopnd, PTY_a64, vreg1, PTY_a64); + + MIRSymbol *sym = GlobalTables::GetGsymTable().CreateSymbol(kScopeGlobal); + if (begin) { + std::string funcname(GetIntrinsicFuncName(INTRN_MCCInitializeLocalStackRef)); + sym->SetNameStridx(GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(funcname)); + CG_ASSERT(countopnd->GetValue() > 0, "refCount should be greater than 0."); + refCount = countopnd->GetValue(); + beginOffset = beginopnd->GetValue(); + } else if (!needSkip) { + std::string funcname(GetIntrinsicFuncName(INTRN_MCCCleanupLocalStackRefNaiveRCFast)); + sym->SetNameStridx(GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(funcname)); + } else { + CHECK_FATAL(retRef->GetStIndex() < memlayout->sym_alloc_table.size(), + "index out of range in Riscv64CGFunc::HandleRCCall"); + Riscv64SymbolAlloc *symloc = static_cast(memlayout->sym_alloc_table[retRef->GetStIndex()]); + int32 stoffset = symloc->offset / kIntregBytelen; + Riscv64ImmOperand *retLoc = CreateImmOperand(stoffset, 64, true); + + regno_t vreg2no = New_V_Reg(kRegTyInt, GetPrimTypeSize(PTY_a64)); + RegOperand *vreg2 = CreateVirtualRegisterOperand(vreg2no); + SelectCopyImm(vreg2, retLoc, PTY_i64); + + parmregopnd = GetOrCreatePhysicalRegisterOperand(R2, 64, kRegTyInt); + srcOpnds->PushOpnd(parmregopnd); + SelectCopy(parmregopnd, PTY_a64, vreg2, PTY_a64); + + std::string funcname(GetIntrinsicFuncName(INTRN_MCCCleanupLocalStackRefSkipNaiveRCFast)); + sym->SetNameStridx(GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(funcname)); + } + sym->storageClass = kScText; + sym->sKind = kStFunc; + + Operand *targetopnd = GetOrCreateFuncNameOpnd(sym); + Insn *callInsn = cg->BuildInstruction(MOP_xbl, targetopnd, srcOpnds); + static_cast(callInsn)->ref_skipindex = refskipindex; + curbb->AppendInsn(callInsn); + if (frequency != 0) { + curbb->frequency = frequency; + } + curbb->SetKind(BB::kBBCall); + BB *newbb = CreateNewBB(); + if (frequency == 0) { + newbb->frequency = curbb->frequency; + } + curbb->AppendBB(newbb); + curbb = newbb; + if (begin) { + // Insert Yield Point just after localrefvar are initialized. + GenerateYieldpoint(curbb); + yieldPointInsn = curbb->lastinsn; + } + return; +} + +void Riscv64CGFunc::CreateCallStructParamFieldPassByStack(int32 symSize, MIRSymbol *sym, uint32 symOffset, + RegOperand *addropnd, int32 baseOffset) { + MemOperand *ldmopnd, *stmopnd; + regno_t vreg; + RegOperand *vreg2; + + if (symSize == 0) { + return; + } + + uint32 dataSize = GetPrimTypeSize(PTY_a64); + uint32 dataSizeBits = dataSize * BITS_PER_BYTE; + + CG_ASSERT(symSize <= 8, "ParamField size should not be > 8"); + if (sym) { + ldmopnd = GetOrCreateMemOpnd(sym, symOffset, dataSizeBits); + } else { + ldmopnd = GetOrCreateMemOpnd(64, addropnd, nullptr, + GetOrCreateOfstOpnd(symOffset, 32), static_cast(nullptr)); + } + + vreg = New_V_Reg(kRegTyInt, dataSize); + vreg2 = CreateVirtualRegisterOperand(vreg); + curbb->AppendInsn( + cg->BuildInstruction(PickLdInsn(dataSizeBits, PTY_i64), vreg2, ldmopnd) + ); + + stmopnd = CreateMemOpnd(RSP, (baseOffset + 0), dataSizeBits); + curbb->AppendInsn( + cg->BuildInstruction(PickStInsn(dataSizeBits, PTY_i64), vreg2, stmopnd) + ); +} + +void Riscv64CGFunc::CreateCallStructParamPassByStack(int32 symSize, MIRSymbol *sym, + RegOperand *addropnd, int32 baseOffset) { + MemOperand *ldmopnd, *stmopnd; + regno_t vreg; + RegOperand *vreg2; + + if (symSize == 0) { + return; + } + + uint32 dataSize = GetPrimTypeSize(PTY_a64); + uint32 dataSizeBits = dataSize * BITS_PER_BYTE; + + uint32 numRegNeeded = (symSize <= 8) ? 1 : 2; + for (int j = 0; j < numRegNeeded; j++) { + if (sym) { + ldmopnd = GetOrCreateMemOpnd(sym, (j * SIZEOFPTR), dataSizeBits); + } else { + ldmopnd = GetOrCreateMemOpnd(64, addropnd, nullptr, + GetOrCreateOfstOpnd(j * SIZEOFPTR, 32), static_cast(nullptr)); + } + + vreg = New_V_Reg(kRegTyInt, dataSize); + vreg2 = CreateVirtualRegisterOperand(vreg); + curbb->AppendInsn( + cg->BuildInstruction(PickLdInsn(dataSizeBits, PTY_i64), vreg2, ldmopnd) + ); + + stmopnd = CreateMemOpnd(RSP, (baseOffset + (j * SIZEOFPTR)), dataSizeBits); + curbb->AppendInsn( + cg->BuildInstruction(PickStInsn(dataSizeBits, PTY_i64), vreg2, stmopnd) + ); + } +} + +Riscv64RegOperand *Riscv64CGFunc::GenUnalignedSymCallStructParam(Riscv64reg_t reg, MIRSymbol *sym, uint32 memOffset, PrimType pty, RegOperand *addropnd) { + int32 ldOffStart, ldOffDec, shftStart, ldSize; + if (pty == PTY_u8) { + ldOffStart = 7; + ldOffDec = 1; + shftStart = 56; + ldSize = 8; + } else if (pty == PTY_u16) { + ldOffStart = 6; + ldOffDec = 2; + shftStart = 48; + ldSize = 16; + } else if (pty == PTY_u32) { + ldOffStart = 4; + ldOffDec = 4; + shftStart = 32; + ldSize = 32; + } else { + CHECK_FATAL(0, "Unknown primtype"); + } + + Riscv64RegOperand *parmOpnd; + MemOperand *mopnd; + RegOperand *ropnd, *rdst; + parmOpnd = GetOrCreatePhysicalRegisterOperand(reg, 32, kRegTyInt); + for (int32 ldOff = ldOffStart, shft = shftStart; ldOff >= 0; + ldOff -= ldOffDec, shft -= ldSize) { + ropnd = GetOrCreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 4)); + if (sym) { + mopnd = GetOrCreateMemOpnd(sym, memOffset + ldOff, 32); + } else { + Riscv64OfstOperand *offopnd = GetOrCreateOfstOpnd(ldOff, 32); + mopnd = GetOrCreateMemOpnd(32, addropnd, + nullptr, offopnd, static_cast(nullptr)); + } + curbb->AppendInsn(cg->BuildInstruction(PickLdInsn(ldSize, PTY_u8), ropnd, mopnd)); + if (ldOff == 0) { + rdst = ropnd; + } else { + Riscv64ImmOperand *shiftImm; + shiftImm = CreateImmOperand(shft, 64, false); + if (ldOff == ldOffStart) { + curbb->AppendInsn(cg->BuildInstruction(MOP_xlslrri6, parmOpnd, ropnd, shiftImm)); + rdst = parmOpnd; + } else { + rdst = GetOrCreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 4)); + curbb->AppendInsn(cg->BuildInstruction(MOP_xlslrri6, rdst, ropnd, shiftImm)); + } + } + if (ldOff != ldOffStart) { + curbb->AppendInsn(cg->BuildInstruction(MOP_xiorrrr, parmOpnd, parmOpnd, rdst)); + } + } + + return parmOpnd; +} + +void Riscv64CGFunc::CreateCallStructParamPassByReg(Riscv64reg_t reg, MemOperand *mopnd, + Riscv64ListOperand *srcopnds, CSR_call_info_t &ci, + MIRSymbol *sym, int32 memOffset, fpParamState state, RegOperand *addropnd) { + Riscv64RegOperand *parmOpnd; + OfstOperand *offsetOpnd = static_cast(mopnd->GetOffsetOperand()); + int64 val = offsetOpnd->GetValue(); + char handleUnaligned = 0; + if (val > 256) { // mem offset is limited if access is unaligned + if (val & 0x1) { + handleUnaligned = 1; + } else if (val & 0x3) { + handleUnaligned = 2; + } else if (val & 0x7) { + handleUnaligned = 4; + } + } + if (handleUnaligned == 1) { + /* ldb v1, [offset + 7] + * lsl parmreg, v1, 56 + * ldh v2, [offset + 6] + * lsl v3, v2, 48 + * orr parmreg, parmreg, v3 + * ... + * ldh v4, [offset + 1] + * lsl v5, v4, 8 + * orr parmreg, parmreg, v5 + * ldh v6, [offset + 0] + * orr parmreg, parmreg, v6 + */ + parmOpnd = GenUnalignedSymCallStructParam(reg, sym, memOffset, PTY_u8, addropnd); + } else if (handleUnaligned == 2) { + /* ldh v1, [offset + 6] + * lsl parmreg, v1, 48 + * ldh v2, [offset + 4] + * lsl v3, v2, 32 + * orr parmreg, parmreg, v3 + * ldh v4, [offset + 2] + * lsl v5, v4, 16 + * orr parmreg, parmreg, v5 + * ldh v6, [offset + 0] + * orr parmreg, parmreg, v6 + */ + parmOpnd = GenUnalignedSymCallStructParam(reg, sym, memOffset, PTY_u16, addropnd); + } else if (handleUnaligned == 4) { + /* ldw v1, [offset + 4] + * lsl parmreg, v1, 32 + * ldw v2, [offset + 0] + * orr parmreg, parmreg, v2 + */ + parmOpnd = GenUnalignedSymCallStructParam(reg, sym, memOffset, PTY_u32, addropnd); + } else { + uint32 dataSizeBits = 0; + PrimType pt = PTY_void; + parmOpnd = nullptr; + if (state == kNotFp) { + parmOpnd = GetOrCreatePhysicalRegisterOperand(reg, 64, kRegTyInt); + dataSizeBits = GetPrimTypeSize(PTY_i64) * BITS_PER_BYTE; + pt = PTY_i64; + } else if (state == kIsFp32bit) { + parmOpnd = GetOrCreatePhysicalRegisterOperand(reg, 32, kRegTyFloat); + dataSizeBits = GetPrimTypeSize(PTY_f32) * BITS_PER_BYTE; + pt = PTY_f32; + } else if (state == kIsFp64bit) { + parmOpnd = GetOrCreatePhysicalRegisterOperand(reg, 64, kRegTyFloat); + dataSizeBits = GetPrimTypeSize(PTY_f64) * BITS_PER_BYTE; + pt = PTY_f64; + } else { + CG_ASSERT(0, "CreateCallStructParamPassByReg: Unknown state"); + } + if (sym && sym->storageClass == kScFormal && memOffset >= 0) { + RegOperand *base = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + curbb->AppendInsn(cg->BuildInstruction(PickLdInsn(64, PTY_i64), base, mopnd)); + uint32 msize = (state == kIsFp32bit) ? 32 : 64; + MemOperand *dataopnd = CreateMemOpnd(base, memOffset, msize); + curbb->AppendInsn(cg->BuildInstruction(PickLdInsn(dataSizeBits, pt), parmOpnd, dataopnd)); + } else { + curbb->AppendInsn( + cg->BuildInstruction( + PickLdInsn(dataSizeBits, pt), + parmOpnd, mopnd) + ); + } + } + + if (ci.store_insertion_point == nullptr) { + ci.store_insertion_point = curbb->lastinsn; + } + srcopnds->PushOpnd(parmOpnd); + CallerSavedRegHandler::CsrBitsetSet(ci.regs_used, + Riscv64CallerSavedRegHandler::Reg2BitPos(reg)); +} + +RegOperand *Riscv64CGFunc::CreateCallStructParamMemcpy(MIRSymbol *sym, RegOperand *addropnd, uint32 structSize, int32 copyOffset, int32 fromOffset) { + vector opndvec; + RegOperand *vreg; + + vreg = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + opndvec.push_back(vreg); // result + + RegOperand *parmOpnd = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + RegOperand *spReg = GetOrCreatePhysicalRegisterOperand(RSP, SIZEOFPTR * BITS_PER_BYTE, kRegTyInt); + Riscv64ImmOperand *offsetOpnd = CreateImmOperand(copyOffset, 64, false); + SelectAdd(parmOpnd, spReg, offsetOpnd, PTY_a64); + opndvec.push_back(parmOpnd); // param 0 + + if (sym) { + vreg = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + if (sym->storageClass == kScGlobal || sym->storageClass == kScExtern) { + StImmOperand *stopnd = CreateStImmOperand(sym, 0, 0); + Riscv64RegOperand *staddropnd = static_cast(CreateRegisterOperandOfType(PTY_u64)); + SelectAddrof(staddropnd, stopnd); + opndvec.push_back(staddropnd); // param 1 + } else if (sym->storageClass == kScAuto || sym->storageClass == kScFormal) { + Riscv64SymbolAlloc *symloc = static_cast(memlayout->sym_alloc_table[sym->GetStIndex()]); + Riscv64RegOperand *baseOpnd = static_cast(GetBaseReg(symloc)); + int32 stoffset = GetBaseOffset(symloc); + Riscv64ImmOperand *offsetOpnd = CreateImmOperand(stoffset, 64, false); + curbb->AppendInsn( + cg->BuildInstruction(MOP_xaddrri12, vreg, baseOpnd, offsetOpnd)); + if (sym->storageClass == kScFormal) { + MemOperand *ldmopnd = GetOrCreateMemOpnd(64, vreg, nullptr, + GetOrCreateOfstOpnd(0, 32), static_cast(nullptr)); + RegOperand *tmpreg = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + vreg = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + curbb->AppendInsn(cg->BuildInstruction(PickLdInsn(64, PTY_a64), tmpreg, ldmopnd)); + curbb->AppendInsn(cg->BuildInstruction(MOP_xaddrri12, vreg, tmpreg, CreateImmOperand(fromOffset, 64, false))); + } + opndvec.push_back(vreg); // param 1 + } else if (sym->storageClass == kScPstatic || sym->storageClass == kScFstatic) { + if (sym->sKind == kStConst) { + CHECK_FATAL(0,"Unsupported sym const for struct param"); + } + StImmOperand *stopnd = CreateStImmOperand(sym, 0, 0); + Riscv64RegOperand *staddropnd = static_cast(CreateRegisterOperandOfType(PTY_u64)); + curbb->AppendInsn(cg->BuildInstruction(MOP_adrp, staddropnd, stopnd)); + curbb->AppendInsn(cg->BuildInstruction(MOP_adrpl12, staddropnd, staddropnd, stopnd)); + opndvec.push_back(staddropnd); // param 1 + } else { + CHECK_FATAL(0,"Unsupported sym for struct param"); + } + } else { + opndvec.push_back(addropnd); // param 1 + } + + vreg = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + Riscv64ImmOperand *sizeOpnd = CreateImmOperand(structSize, 64, false); + curbb->AppendInsn( + cg->BuildInstruction(MOP_xmovri64, vreg, sizeOpnd)); + opndvec.push_back(vreg); // param 2 + + SelectLibCall("memcpy", opndvec, PTY_a64, PTY_a64); + + return parmOpnd; +} + +Riscv64RegOperand *Riscv64CGFunc::CreateCallStructParamCopyToStack(uint32 numMemOp, MIRSymbol *sym, + RegOperand *addropnd, int32 copyOffset, int32 fromOffset, PLocInfo *ploc) { + Riscv64reg_t reg = ploc->reg0; + uint32 dataSize = GetPrimTypeSize(PTY_a64); + uint32 dataSizeBits = dataSize * BITS_PER_BYTE; + // Create the struct copies. + MemOperand *ldmopnd, *stmopnd; + RegOperand *vreg; + for (int j = 0; j < numMemOp; j++) { + if (sym) { + if (sym->storageClass == kScFormal) { + ldmopnd = GetOrCreateMemOpnd(sym, 0, dataSizeBits); + vreg = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, dataSize)); + Insn *ldInsn = cg->BuildInstruction(PickLdInsn(dataSizeBits, PTY_i64), vreg, ldmopnd); + curbb->AppendInsn(ldInsn); + ldmopnd = GetOrCreateMemOpnd(64, vreg, nullptr, + GetOrCreateOfstOpnd(j * SIZEOFPTR + fromOffset, 32), static_cast(nullptr)); + } else { + ldmopnd = GetOrCreateMemOpnd(sym, (j * SIZEOFPTR) + fromOffset, dataSizeBits); + } + } else { + ldmopnd = GetOrCreateMemOpnd(64, addropnd, nullptr, + GetOrCreateOfstOpnd(j * SIZEOFPTR + fromOffset, 32), static_cast(nullptr)); + } + vreg = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, dataSize)); + Insn *ldInsn = cg->BuildInstruction(PickLdInsn(dataSizeBits, PTY_i64), vreg, ldmopnd); + curbb->AppendInsn(ldInsn); + if (IsImmediateOffsetOutOfRange(static_cast(ldmopnd), 64)) { + ldmopnd = SplitOffsetWithAddInstruction(static_cast(ldmopnd), 64, Riscv64reg_t::kRinvalid, ldInsn); + ldInsn->opnds[1] = ldmopnd; + } + + stmopnd = CreateMemOpnd(RSP, (copyOffset + (j * SIZEOFPTR)), dataSizeBits); + curbb->AppendInsn( + cg->BuildInstruction(PickStInsn(dataSizeBits, PTY_i64), vreg, stmopnd) + ); + } + // Create the copy address parameter for the struct + Riscv64RegOperand *parmOpnd; + Riscv64ImmOperand *offset = CreateImmOperand(copyOffset, 64, false); + if (reg != kRinvalid) { + // if a parameter register still available + parmOpnd = GetOrCreatePhysicalRegisterOperand(reg, 64, kRegTyInt); + RegOperand *fpopnd = GetOrCreatePhysicalRegisterOperand(RSP, SIZEOFPTR * BITS_PER_BYTE, kRegTyInt); + SelectAdd(parmOpnd, fpopnd, offset, PTY_a64); + } else { + // no more parameter register available, push address to stack + RegOperand *fpopnd = GetOrCreatePhysicalRegisterOperand(RSP, SIZEOFPTR * BITS_PER_BYTE, kRegTyInt); + RegOperand *res = CreateRegisterOperandOfType(PTY_u64); + SelectAdd(res, fpopnd, offset, PTY_u64); + stmopnd = CreateMemOpnd(RSP, ploc->memoffset, dataSizeBits); + curbb->AppendInsn( + cg->BuildInstruction(PickStInsn(dataSizeBits, PTY_i64), res, stmopnd)); + return nullptr; + } + + return parmOpnd; +} + +// Determine if the caller is a vararg call or not +bool Riscv64CGFunc::CallIsVararg(StmtNode *narynode, uint32 &namedFormals, BB *bb) { + bool varargFunc = false; + + if (CallNode *callNode = dynamic_cast(narynode)) { + MIRFunction *func = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(callNode->puIdx); + varargFunc = CLANG && func->GetAttr(FUNCATTR_varargs) ? true : false; + namedFormals = func->formalDefVec.size(); + } else if (IcallNode *icallNode = dynamic_cast(narynode)) { + BaseNode *fNode = icallNode->Opnd(0); + MIRFuncType *fType = nullptr; + MIRPtrType *pType = nullptr; + if (fNode->op == OP_dread) { + DreadNode *dNode = static_cast(fNode); + MIRSymbol *symbol = mirModule.CurFunction()->GetLocalOrGlobalSymbol(dNode->stIdx); + pType = static_cast(symbol->GetType()); + MIRType *ty = pType; + if (dNode->fieldID != 0) { + CG_ASSERT(ty->typeKind == kTypeStruct || ty->typeKind == kTypeClass, ""); + FieldPair thepair; + if (ty->typeKind == kTypeStruct) { + thepair = static_cast(ty)->TraverseToField(dNode->fieldID); + } else { + thepair = static_cast(ty)->TraverseToField(dNode->fieldID); + } + pType = static_cast(GlobalTables::GetTypeTable().GetTypeFromTyIdx(thepair.second.first)); + } + fType = static_cast(pType->GetPointedType()); + varargFunc = fType->isVarArgs; + namedFormals = fType->paramTypeList.size(); + } else if (fNode->op == OP_iread) { + IreadNode *iNode = static_cast(fNode); + MIRPtrType *pointerty = static_cast(GlobalTables::GetTypeTable().GetTypeFromTyIdx(iNode->tyIdx)); + MIRType *pointedType = pointerty->GetPointedType(); + if (iNode->fieldID != 0) { + pointedType = static_cast(pointedType)->GetFieldType(iNode->fieldID); + } + if (pointedType->typeKind == kTypeFunction) { + fType = static_cast(pointedType); + } else if (pointedType->typeKind == kTypePointer) { + fType = dynamic_cast(static_cast(pointedType)->GetPointedType()); + CHECK_FATAL(fType != nullptr, "Cannot determine if icall is variadic"); + } + varargFunc = fType->isVarArgs; + namedFormals = fType->paramTypeList.size(); + } else if (fNode->op == OP_select) { + TernaryNode *sNode = static_cast(fNode); + BaseNode *expr = sNode->Opnd(1); + // both function ptrs under select should have the same signature, chk op1 only + AddroffuncNode *afNode = static_cast(expr); + MIRFunction *func = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(afNode->puIdx); + varargFunc = CLANG && func->GetAttr(FUNCATTR_varargs); + namedFormals = func->formalDefVec.size(); + if (bb) { + bb->SetKind(BB::kBBCall); + } + } else if (fNode->op == OP_regread) { + RegreadNode *rNode = static_cast(fNode); + PregIdx pregidx = rNode->regIdx; + MIRPreg *preg = func->pregTab->PregFromPregIdx(pregidx); + MIRPtrType *pType = dynamic_cast(preg->mirType); + if (!pType) { + return false; + } + MIRFuncType *fType = dynamic_cast(pType->GetPointedType()); + if (!fType) { + CG_ASSERT(0, "cannot process this icall"); + }; + varargFunc = fType->isVarArgs; + namedFormals = fType->paramTypeList.size(); + } else { + CG_ASSERT(0, "cannot process this icall"); + } + } + return varargFunc; +} + +/* + SelectParmList generates an instrunction for each of the parameters + to load the parameter value into the corresponding register. + We return a list of registers to the call instruction because + they may be needed in the register allocation phase. + */ +void Riscv64CGFunc::SelectParmList(StmtNode * narynode, Riscv64ListOperand * srcopnds, CSR_call_info_t & ci, + bool iscallnative) { + ParmLocator parmlocator(becommon); + PLocInfo ploc; + int32 i = 0; + if (narynode->op == OP_icall || iscallnative) { + i++; + } + MIRSymbol *fsym = nullptr; + CallNode *callnode = dynamic_cast(narynode); + bool islockcall = false; + if (callnode) { + MIRFunction *fn = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(callnode->puIdx); + fsym = mirModule.CurFunction()->GetLocalOrGlobalSymbol(fn->stIdx, false); + } + + if (fsym && IsRtLockCall(fsym->GetName())) { + islockcall = true; + } + + uint32 retSize = 0; + int32 structCopyOffset = GetMaxParamStackSize() - GetStructCopySize(); + RegOperand *bigParm = nullptr; + vector offsetList; + MIRFunction *callfunc = nullptr; + bool varargFunc = false; + uint32 namedFormals = 0; + if (becommon.mirModule.IsCModule()) { + // Preprocess for converting big struct param to memcpy. + int32 pi = i; + for (; pi < narynode->NumOpnds(); pi++) { + bigParm = nullptr; + BaseNode *argexpr = narynode->Opnd(pi); + PrimType ptype = argexpr->primType; + if (ptype == PTY_agg) { + int32 symSize; + RegOperand *addropnd = nullptr; + MIRSymbol *sym = nullptr; + int32 rhsoffset = 0; + if (argexpr->op == OP_iread) { + IreadNode *iread = static_cast(argexpr); + MIRPtrType *pointerty = static_cast(GlobalTables::GetTypeTable().GetTypeFromTyIdx(iread->tyIdx)); + MIRType *ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(pointerty->pointedTyIdx); + if (iread->fieldID != 0) { + MIRStructType *rhsstructty = static_cast(ty); + FieldPair thepair = rhsstructty->TraverseToField(iread->fieldID); + ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(thepair.second.first); + rhsoffset = becommon.GetFieldOffset(rhsstructty, iread->fieldID).first; + } + symSize = becommon.type_size_table.at(ty->tyIdx.GetIdx()); + if (symSize > kParmMemcpySize) { + addropnd = static_cast(HandleExpr(iread, iread->Opnd(0))); + addropnd = LoadIntoRegister(addropnd, iread->Opnd(0)->primType); + curbb->AppendInsn( + cg->BuildInstruction(MOP_xaddrri12, addropnd, addropnd, CreateImmOperand(rhsoffset, 64, false))); + } + } else if (argexpr->op == OP_dread) { + DreadNode *dread = static_cast(argexpr); + sym = becommon.mirModule.CurFunction()->GetLocalOrGlobalSymbol(dread->stIdx); + MIRType *ty = sym->GetType(); + if (dread->fieldID != 0) { + MIRStructType *structty = static_cast(ty); + FieldPair thepair = structty->TraverseToField(dread->fieldID); + ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(thepair.second.first); + rhsoffset = becommon.GetFieldOffset(structty, dread->fieldID).first; + } + symSize = becommon.type_size_table.at(ty->tyIdx.GetIdx()); + } else { + CHECK_FATAL(0, "call param is agg but not dread or iread"); + } + if (symSize > kParmMemcpySize) { + bigParm = CreateCallStructParamMemcpy(sym, addropnd, symSize, structCopyOffset, rhsoffset); + offsetList.push_back(structCopyOffset); + structCopyOffset += RoundUp(symSize, SIZEOFPTR); + + if (ci.store_insertion_point == nullptr) { + ci.store_insertion_point = curbb->lastinsn; + } + CallerSavedRegHandler::CsrBitsetSet(ci.regs_used, Riscv64CallerSavedRegHandler::Reg2BitPos(R0)); + CallerSavedRegHandler::CsrBitsetSet(ci.regs_used, Riscv64CallerSavedRegHandler::Reg2BitPos(R1)); + CallerSavedRegHandler::CsrBitsetSet(ci.regs_used, Riscv64CallerSavedRegHandler::Reg2BitPos(R2)); + BB *oldBB = curbb; + curbb = StartNewBB(narynode); + SplitCallBB(oldBB); + curbb->SetKind(BB::kBBCall); + } + } + } + // Determine if call is variadic + varargFunc = CallIsVararg(narynode, namedFormals, curbb); + if (callnode) { + callfunc = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(callnode->puIdx); + TyIdx retIdx = callfunc->GetReturnTyIdx(); + retSize = becommon.type_size_table[retIdx.GetIdx()]; + if (retSize == 0) { + auto funcIt = becommon.funcReturnType.find(callfunc); + if (funcIt != becommon.funcReturnType.end()) { + retSize = becommon.type_size_table[funcIt->second.GetIdx()]; + } + } + } else { + IcallNode *icallnode = dynamic_cast(narynode); + if (icallnode) { + CallReturnVector *p2nrets = &icallnode->returnValues; + if (p2nrets->size() == 1) { + StIdx stIdx = (*p2nrets)[0].first; + MIRSymbol *sym = becommon.mirModule.CurFunction()->symTab->GetSymbolFromStIdx(stIdx.Idx()); + if (sym) { + MIRType *rettype = GlobalTables::GetTypeTable().GetTypeFromTyIdx(sym->tyIdx); + retSize = becommon.type_size_table[sym->tyIdx.GetIdx()]; + } + } + } + } + } + string fname = fsym ? fsym->GetName() : "icall"; + //LogInfo::MapleLogger() << fname << " varargFunc: " << varargFunc << endl; + for (int32 pidx = 0, pnum = 0; i < narynode->NumOpnds(); i++, pnum++) { + MIRType *ty = nullptr; + BaseNode *argexpr = narynode->Opnd(i); + PrimType ptype = argexpr->primType; + CG_ASSERT(ptype != PTY_void, ""); + bool variadArg = varargFunc && (pnum+1 > namedFormals); + if (ptype != PTY_agg) { + ty = GlobalTables::GetTypeTable().typeTable[static_cast(ptype)]; + RegOperand *expregopnd = nullptr; + if (!(i == 1 && islockcall)) { + Operand *opnd = HandleExpr(narynode, argexpr); + if (!opnd->IsRegister()) { + opnd = LoadIntoRegister(opnd, ptype); + } + expregopnd = static_cast(opnd); + } + + parmlocator.LocateNextParm(ty, ploc, pnum == 0 && retSize > 16, variadArg); + if (ploc.reg0 != 0) { // load to the register + Riscv64RegOperand *parmregopnd = nullptr; + if (islockcall && i == 1) { + ConstvalNode *soff = static_cast(argexpr); + int32 stackoff = static_cast(soff->constVal)->GetValueUnderType(); + + parmregopnd = GetOrCreatePhysicalRegisterOperand(ploc.reg0, 64, kRegTyInt); + Riscv64SymbolAlloc symalloc; + Riscv64MemLayout *memlayout = static_cast(this->memlayout); + symalloc.mem_segment = &memlayout->seg_lockobjslot; + symalloc.offset = 0; + + uint32 slotbase = GetBaseOffset(&symalloc); + uint32 slotoffset = slotbase + memlayout->lockinfosize + (stackoff - 1) * memlayout->lockslotsize; + Riscv64ImmOperand *offoper = CreateImmOperand(slotoffset, 64, true); + RegOperand *fpopnd = GetOrCreateStackBaseRegOperand(); + SelectAdd(parmregopnd, fpopnd, offoper, PTY_a64); + } else { + CHECK_FATAL(expregopnd, "null ptr check"); + PrimType ptype2 = ptype; + if (ploc.reg0 <= R17) { // fp passed in intreg + ptype2 = (ptype == PTY_f32) ? PTY_i32 : ((ptype == PTY_f64) ? PTY_i64 : ptype); + } + parmregopnd = GetOrCreatePhysicalRegisterOperand(ploc.reg0, expregopnd->size_, GetRegTyFromPrimTyRiscv64(ptype2)); + SelectCopy(parmregopnd, ptype2, expregopnd, ptype); + } + + if (ci.store_insertion_point == nullptr) { + ci.store_insertion_point = curbb->lastinsn; + } + srcopnds->PushOpnd(parmregopnd); + CallerSavedRegHandler::CsrBitsetSet(ci.regs_used, Riscv64CallerSavedRegHandler::Reg2BitPos(ploc.reg0)); + } else { // store to the memory segment for stack-passsed arguments + Operand *actmemopnd = CreateMemOpnd(RSP, ploc.memoffset, GetPrimTypeBitSize(ptype)); + curbb->AppendInsn( + cg->BuildInstruction(PickStInsn(GetPrimTypeBitSize(ptype), ptype), expregopnd, actmemopnd)); + } + CG_ASSERT(ploc.reg1 == 0, "SelectCall NYI"); + } else { + // The param passing stack layout: + // ------------------------------ previous call frame + // incoming call param stk loc + // ------------------------------ previous call frame - #param_regs_size + // locals, spills, ... + // ------------------------------ %fp + 8 + // %fp and %lr + // ------------------------------ %fp = %sp + max call params + struct copy offset + // struct copy area + // ------------------------------ %sp + maximum call parameter offset + // out flow params beyong %x7 + // ------------------------------ %sp + 0 + uint32 dataSize = GetPrimTypeSize(PTY_a64); + uint32 dataSizeBits = dataSize * BITS_PER_BYTE; + if (argexpr->op == OP_iread) { + IreadNode *iread = static_cast(argexpr); + MIRPtrType *pointerty = static_cast(GlobalTables::GetTypeTable().GetTypeFromTyIdx(iread->tyIdx)); + ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(pointerty->pointedTyIdx); + int32 rhsoffset = 0; + if (iread->fieldID != 0) { + MIRStructType *rhsstructty = static_cast(ty); + FieldPair thepair = rhsstructty->TraverseToField(iread->fieldID); + ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(thepair.second.first); + rhsoffset = becommon.GetFieldOffset(rhsstructty, iread->fieldID).first; + } + int32 symSize = becommon.type_size_table.at(ty->tyIdx.GetIdx()); + parmlocator.LocateNextParm(ty, ploc, false, variadArg); + if (symSize <= 16) { + RegOperand *addropnd = static_cast(HandleExpr(iread, iread->Opnd(0))); + addropnd = LoadIntoRegister(addropnd, iread->Opnd(0)->primType); + if (ploc.reg0 == 0) { + // No param regs available, pass on stack. + CreateCallStructParamPassByStack(symSize, nullptr, addropnd, ploc.memoffset); + } else { + if (symSize > 8 && ploc.reg1 == kRinvalid) { + // half of the agg is to be passed in reg below, the 2nd half on stack + CreateCallStructParamFieldPassByStack(symSize-8, nullptr, 8, addropnd, ploc.memoffset); + } + // pass by param regs. + fpParamState state = kStateUnknown; + uint32 msize = 0; + if (ploc.reg0 < V0) { + state = kNotFp; + msize = 64; + } else { + if (ploc.rsize0 <= 4) { + state = kIsFp32bit; + msize = 32; + } else { + state = kIsFp64bit; + msize = 64; + } + } + Riscv64OfstOperand *offopnd = GetOrCreateOfstOpnd(rhsoffset, 32); + MemOperand *mopnd; + mopnd = GetOrCreateMemOpnd(msize, addropnd, + nullptr, offopnd, static_cast(nullptr)); + CreateCallStructParamPassByReg(ploc.reg0, mopnd, srcopnds, ci, (MIRSymbol*)nullptr, 0, state, addropnd); + if (ploc.reg1) { + if (ploc.reg0 < V0) { + state = kNotFp; + msize = 64; + } else { + if (ploc.rsize0 <= 4) { + state = kIsFp32bit; + msize = 32; + } else { + state = kIsFp64bit; + msize = 64; + } + } + offopnd = GetOrCreateOfstOpnd(ploc.rsize0 + rhsoffset, 32); + mopnd = GetOrCreateMemOpnd(msize, addropnd, + nullptr, offopnd, static_cast(nullptr)); + CreateCallStructParamPassByReg(ploc.reg1, mopnd, srcopnds, ci, (MIRSymbol*)nullptr, 0, state, addropnd); + } + } + } else if (symSize > kParmMemcpySize) { + // This has been dealt with at the beginning of this func with memcpy + RegOperand *spReg = GetOrCreatePhysicalRegisterOperand(RSP, SIZEOFPTR * BITS_PER_BYTE, kRegTyInt); + Riscv64ImmOperand *offsetOpnd = CreateImmOperand(offsetList[pidx], 64, false); + pidx++; + if (ploc.reg0) { + RegOperand *res = GetOrCreatePhysicalRegisterOperand(ploc.reg0, 64, kRegTyInt); + SelectAdd(res, spReg, offsetOpnd, PTY_a64); + srcopnds->PushOpnd(res); + } else { + regno_t vregno = New_V_Reg(kRegTyInt, 8); + RegOperand *parmOpnd = CreateVirtualRegisterOperand(vregno); + SelectAdd(parmOpnd, spReg, offsetOpnd, PTY_a64); + MemOperand *stmopnd = CreateMemOpnd(RSP, ploc.memoffset, dataSizeBits); + curbb->AppendInsn( + cg->BuildInstruction(PickStInsn(dataSizeBits, PTY_i64), parmOpnd, stmopnd)); + } + } else { + // Pass larger sized struct on stack. + RegOperand *addropnd = static_cast(HandleExpr(iread, iread->Opnd(0))); + addropnd = LoadIntoRegister(addropnd, iread->Opnd(0)->primType); + Riscv64RegOperand *parmOpnd; + uint32 numMemOp = RoundUp(symSize, SIZEOFPTR) / SIZEOFPTR; // round up + parmOpnd = CreateCallStructParamCopyToStack(numMemOp, nullptr, addropnd, structCopyOffset, rhsoffset, &ploc); + structCopyOffset += (numMemOp * SIZEOFPTR); + if (ci.store_insertion_point == nullptr) { + ci.store_insertion_point = curbb->lastinsn; + } + if (ploc.reg0) { + srcopnds->PushOpnd(parmOpnd); + CallerSavedRegHandler::CsrBitsetSet(ci.regs_used, Riscv64CallerSavedRegHandler::Reg2BitPos(ploc.reg0)); + } + } + continue; + } + CHECK_FATAL((argexpr->op == OP_dread), "call param is agg but not dread or iread"); + DreadNode *dread = static_cast(argexpr); + MIRSymbol *sym = becommon.mirModule.CurFunction()->GetLocalOrGlobalSymbol(dread->stIdx); + ty = sym->GetType(); + int32 rhsoffset = 0; + if (dread->fieldID != 0) { + MIRStructType *structty = static_cast(ty); + FieldPair thepair = structty->TraverseToField(dread->fieldID); + ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(thepair.second.first); + rhsoffset = becommon.GetFieldOffset(structty, dread->fieldID).first; + } + int32 symSize = becommon.type_size_table.at(ty->tyIdx.GetIdx()); + parmlocator.LocateNextParm(ty, ploc, false, variadArg); + if (symSize <= 16) { + // in two param regs if possible + // If struct is <= 8 bytes, then it fits into one param reg. + // If struct is <= 16 bytes, then it fits into two param regs. + // Otherwise, it goes onto the stack. + // If the number of available param reg is less than what is + // needed to fit the entire struct into them, then the param + // reg is skipped and the struct goes onto the stack. + // Example 1. + // struct size == 8 bytes. + // param regs a0 to a6 are used. + // struct is passed in a7. + // Example 2. + // struct is 16 bytes. + // param regs a0 to a5 are used. + // struct is passed in a6 and a7. + // Example 3. + // struct is 16 bytes. + // param regs a0 to a6 are used. a7 alone is not enough to pass the struct. + // Other other half is passed on the stack. + if (ploc.reg0 == 0) { + // No param regs available, pass on stack. + CreateCallStructParamPassByStack(symSize, sym, nullptr, ploc.memoffset); + } else { + if (symSize > 8 && ploc.reg1 == kRinvalid) { + // half of the agg is to be passed in reg below, the 2nd half on stack + CreateCallStructParamFieldPassByStack(symSize-8, sym, 8, nullptr, ploc.memoffset); + } + // pass by param regs. + fpParamState state = kStateUnknown; + if (ploc.reg0 < V0) { + state = kNotFp; + dataSizeBits = 64; + } else { + if (ploc.rsize0 <= 4) { + state = kIsFp32bit; + dataSizeBits = 32; + } else { + state = kIsFp64bit; + dataSizeBits = 64; + } + } + MemOperand *mopnd; + int32 dataOffset; + if (sym->storageClass == kScFormal && dread->fieldID > 0) { + mopnd = GetOrCreateMemOpnd(sym, 0, dataSizeBits); + dataOffset = rhsoffset; + } else { + mopnd = GetOrCreateMemOpnd(sym, rhsoffset, dataSizeBits); + dataOffset = -1; + } + CreateCallStructParamPassByReg(ploc.reg0, mopnd, srcopnds, ci, sym, dataOffset, state); + if (ploc.reg1) { + if (ploc.reg1 < V0) { + state = kNotFp; + dataSizeBits = 64; + } else { + if (ploc.rsize1 <= 4) { + state = kIsFp32bit; + dataSizeBits = 32; + } else { + state = kIsFp64bit; + dataSizeBits = 64; + } + } + int32 symOffset; + if (sym->storageClass == kScFormal && dread->fieldID > 0) { + symOffset = 0; + dataOffset = SIZEOFPTR + rhsoffset; + } else if (ploc.reg1 >= V0) { + if (ploc.rsize1 <= 4) { + symOffset = 4 + rhsoffset; + } else { + symOffset = 8 + rhsoffset; + } + dataOffset = -1; + } else { + symOffset = SIZEOFPTR + rhsoffset; + dataOffset = -1; + } + mopnd = GetOrCreateMemOpnd(sym, symOffset, dataSizeBits); + CreateCallStructParamPassByReg(ploc.reg1, mopnd, srcopnds, ci, sym, dataOffset, state); + } + } + } else if (symSize > kParmMemcpySize) { + // This has been dealt with at the beginning of this func with memcpy + RegOperand *spReg = GetOrCreatePhysicalRegisterOperand(RSP, SIZEOFPTR * BITS_PER_BYTE, kRegTyInt); + Riscv64ImmOperand *offsetOpnd = CreateImmOperand(offsetList[pidx], 64, false); + pidx++; + if (ploc.reg0) { + RegOperand *res = GetOrCreatePhysicalRegisterOperand(ploc.reg0, 64, kRegTyInt); + SelectAdd(res, spReg, offsetOpnd, PTY_a64); + srcopnds->PushOpnd(res); + } else { + regno_t vregno = New_V_Reg(kRegTyInt, 8); + RegOperand *parmOpnd = CreateVirtualRegisterOperand(vregno); + SelectAdd(parmOpnd, spReg, offsetOpnd, PTY_a64); + MemOperand *stmopnd = CreateMemOpnd(RSP, ploc.memoffset, dataSizeBits); + curbb->AppendInsn( + cg->BuildInstruction(PickStInsn(dataSizeBits, PTY_i64), parmOpnd, stmopnd)); + } + } else { + // Pass larger sized struct on stack. + // Need to copy the entire structure onto the stack. + // The pointer to the starting address of the copied struct is then + // used as the parameter for the struct. + // This pointer is passed as the next parameter. + // Example 1: + // struct is 23 bytes. + // param regs x0 to x5 are used. + // First around up 23 to 24, so 3 of 8-byte slots. + // Copy struct to a created space on the stack. + // Pointer of copied struct is passed in x6. + // Example 2: + // struct is 25 bytes. + // param regs x0 to x7 are used. + // First around up 25 to 32, so 4 of 8-byte slots. + // Copy struct to a created space on the stack. + // Pointer of copied struct is passed on stack as the 9th parameter. + + Riscv64RegOperand *parmOpnd; + uint32 numMemOp = RoundUp(symSize, SIZEOFPTR) / SIZEOFPTR; // round up + parmOpnd = CreateCallStructParamCopyToStack(numMemOp, sym, nullptr, structCopyOffset, rhsoffset, &ploc); + structCopyOffset += (numMemOp * SIZEOFPTR); + if (ci.store_insertion_point == nullptr) { + ci.store_insertion_point = curbb->lastinsn; + } + if (ploc.reg0) { + srcopnds->PushOpnd(parmOpnd); + CallerSavedRegHandler::CsrBitsetSet(ci.regs_used, Riscv64CallerSavedRegHandler::Reg2BitPos(ploc.reg0)); + } + } + } + } +} + +void Riscv64CGFunc::SelectCall(CallNode * callnode) { + MIRFunction *fn = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(callnode->puIdx); + MIRSymbol *fsym = mirModule.CurFunction()->GetLocalOrGlobalSymbol(fn->stIdx, false); + MIRType *rettype = GlobalTables::GetTypeTable().GetTypeFromTyIdx(fn->GetReturnTyIdx()); + + CSR_call_info_t ci; + CG_ASSERT(ci.store_insertion_point == nullptr && ci.load_insertion_point == nullptr, ""); + + if (cg->GenerateVerboseAsm()) { + string *comment = new string(fsym->GetName()); + const char *str = comment->c_str(); + curbb->AppendInsn(cg->BuildInstruction(MOP_comment, CreateCommentOperand(str))); + } + + Riscv64ListOperand *srcOpnds = memPool->New(funcscope_allocator_); + + bool callnative = false; + if (IsRtNativeCall(fsym->GetName())) { + callnative = true; + } + + SelectParmList(callnode, srcOpnds, ci, callnative); + if (callnative) { + curbb->AppendInsn(cg->BuildInstruction(MOP_comment, CreateCommentOperand("call native func"))); + + BaseNode *funcargexpr = callnode->Opnd(0); + PrimType ptype = funcargexpr->primType; + Operand *funcopnd = HandleExpr(callnode, funcargexpr); + Riscv64RegOperand *livein = GetOrCreatePhysicalRegisterOperand(RSP, 64, kRegTyInt); + SelectCopy(livein, ptype, funcopnd, ptype); + callnativemap[curbb->lastinsn] = nullptr; + } + + Operand *targetopnd = GetOrCreateFuncNameOpnd(fsym); + Insn *callInsn = cg->BuildInstruction(MOP_xbl, targetopnd, srcOpnds); + if (rettype) { + callInsn->SetRetSize(rettype->GetSize()); + callInsn->SetRetSignType(IsUnsignedInteger(rettype->GetPrimType())); + } + curbb->AppendInsn(callInsn); + + func->SetHasCall(); + if (IsThrowOrNonReturnFunc(fsym->GetName())) { + callInsn->is_throw = true; + curbb->SetKind(BB::kBBThrow); + } + + if (ci.store_insertion_point == nullptr) { + ci.store_insertion_point = callInsn; + } + if (ci.load_insertion_point == nullptr) { + ci.load_insertion_point = callInsn; + } + + // We collect the return value info in SelectRegread() where we process kSregRetval0 + + call_info_map.insert(pair(callInsn, ci)); +} + +void Riscv64CGFunc::SelectIcall(IcallNode * icallnode, Operand * fptropnd) { + CSR_call_info_t ci; + CG_ASSERT(ci.store_insertion_point == nullptr && ci.load_insertion_point == nullptr, ""); + + Riscv64ListOperand *srcOpnds = memPool->New(funcscope_allocator_); + SelectParmList(icallnode, srcOpnds, ci); + + if (fptropnd->op_kind_ != Operand::Opd_Register) { + PrimType ty = icallnode->Opnd(0)->primType; + fptropnd = SelectCopy(fptropnd, ty, ty); + } + + RegOperand *regopnd = dynamic_cast(fptropnd); + CG_ASSERT(regopnd, "SelectIcall: function pointer not RegOperand"); + Insn *callInsn = cg->BuildInstruction(MOP_xblr, regopnd, srcOpnds); + + MIRType *rettype = GlobalTables::GetTypeTable().GetTypeFromTyIdx(icallnode->retTyIdx); + if (rettype) { + callInsn->SetRetSize(rettype->GetSize()); + callInsn->SetRetSignType(IsUnsignedInteger(rettype->GetPrimType())); + } + + curbb->AppendInsn(callInsn); + CG_ASSERT(curbb->GetKind() == BB::kBBCall && curbb->lastinsn->IsCall(), ""); + func->SetHasCall(); + + if (ci.store_insertion_point == nullptr) { + ci.store_insertion_point = callInsn; + } + if (ci.load_insertion_point == nullptr) { + ci.load_insertion_point = callInsn; + } + + // We collect the return value info in SelectRegread() where we process kSregRetval0 + + call_info_map.insert(pair(callInsn, ci)); +} + +void Riscv64CGFunc::HandleJavaCatch() { + if (g->optim_level == 2) { + regno_t regno = ujavaCatch.regno_javaCatch; + RegOperand *vregOpnd = GetOrCreateVirtualRegisterOperand(regno); + curbb->AppendInsn( + cg->BuildInstruction(MOP_xmovrr, vregOpnd, GetOrCreatePhysicalRegisterOperand(R0, 64, kRegTyInt))); + } else + curbb->AppendInsn(cg->BuildInstruction(PickStInsn(ujavaCatch.opnd_javaCatch->GetSize(), PTY_a64), + GetOrCreatePhysicalRegisterOperand(R0, 64, kRegTyInt), + ujavaCatch.opnd_javaCatch)); + + return; +} + +bool Riscv64CGFunc::CanBBThrow(BB * bb) { + FOR_BB_INSNS(insn, bb) { + if (insn->CanThrow()) { + if (insn->GetMachineOpcode() == MOP_xbl) { + FuncNameOperand *target = dynamic_cast(insn->GetCallTargetOperand()); + if (target) { + MIRSymbol *funcst = target->GetFunctionSymbol(); + if (CanFuncThrow(funcst->GetName())) { + return true; + } + continue; + } + } else if (insn->IsMemAccess()) { + Operand *opnd = insn->GetMemOpnd(); + if (opnd->IsMemoryAccessOperand()) { + MemOperand *memopnd = static_cast(opnd); + Operand *base = memopnd->GetBaseRegister(); + if (base) { + RegOperand *ropnd = static_cast(base); + if (ropnd->IsPhysicalRegister() && + (ropnd->GetRegisterNumber() == RFP || ropnd->GetRegisterNumber() == RSP)) { + continue; + } + } + } + } + return true; + } + } + return false; +} + +void Riscv64CGFunc::SelectMembar(StmtNode * membar) { + switch (membar->op) { + case OP_membaracquire: + curbb->AppendInsn(cg->BuildInstruction(MOP_dmb_ishld)); + break; + case OP_membarrelease: + curbb->AppendInsn(cg->BuildInstruction(MOP_dmb_ishst)); + break; + case OP_membarstoreload: + curbb->AppendInsn(cg->BuildInstruction(MOP_dmb_ish)); + break; + case OP_membarstorestore: + curbb->AppendInsn(cg->BuildInstruction(MOP_dmb_ishst)); + break; + + default: + CG_ASSERT(false, "NYI"); + break; + } +} + +void Riscv64CGFunc::SelectComment(CommentNode * comment) { + curbb->AppendInsn(cg->BuildInstruction(MOP_comment, CreateCommentOperand(comment->comment))); +} + +void Riscv64CGFunc::SelectReturn(NaryStmtNode * stmt, Operand * opnd0) { + ReturnMechanism retmech(GlobalTables::GetTypeTable().GetTypeFromTyIdx(func->GetReturnTyIdx()), becommon); + Riscv64RegOperand *retopnd = nullptr; + if (retmech.regcount > 0) { + if (RegOperand *regopnd = dynamic_cast(opnd0)) { + if (regopnd->GetRegisterNumber() != retmech.reg0) { + retopnd = + GetOrCreatePhysicalRegisterOperand(retmech.reg0, regopnd->size_, GetRegTyFromPrimTyRiscv64(retmech.ptype0)); + SelectCopy(retopnd, retmech.ptype0, regopnd, retmech.ptype0); + } + } else if (Riscv64MemOperand *memopnd = dynamic_cast(opnd0)) { + retopnd = GetOrCreatePhysicalRegisterOperand(retmech.reg0, GetPrimTypeBitSize(retmech.ptype0), + GetRegTyFromPrimTyRiscv64(retmech.ptype0)); + MOperator mop = PickLdInsn(memopnd->size_, retmech.ptype0); + curbb->AppendInsn(cg->BuildInstruction(mop, retopnd, memopnd)); + } else if (opnd0->IsConstImmediate()) { + ImmOperand *immopnd = static_cast(opnd0); + retopnd = GetOrCreatePhysicalRegisterOperand(retmech.reg0, GetPrimTypeBitSize(retmech.ptype0), + GetRegTyFromPrimTyRiscv64(retmech.ptype0)); + SelectCopy(retopnd, retmech.ptype0, immopnd, retmech.ptype0); + } else { + CG_ASSERT(false, "nyi"); + } + } else if (opnd0 != nullptr) { // pass in memory + CG_ASSERT(false, "SelectReturn: return in memory NYI"); + } + exitbbsvec.push_back(curbb); +} + +RegOperand *Riscv64CGFunc::GetOrCreateSpecialRegisterOperand(PregIdx sregidx, PrimType primType) { + Riscv64reg_t reg = R0; + switch (sregidx) { + case kSregSp: + reg = RSP; + break; + case kSregFp: + reg = RFP; + break; + case kSregThrownval: { /* uses x0 == R0 */ + CG_ASSERT(ujavaCatch.regno_javaCatch > 0, "regno_javaCatch should greater than 0."); + + RegOperand *regOpnd = nullptr; + if (g->optim_level < 2) { + regOpnd = GetOrCreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + curbb->AppendInsn(cg->BuildInstruction(PickLdInsn(ujavaCatch.opnd_javaCatch->GetSize(), PTY_a64), + regOpnd, ujavaCatch.opnd_javaCatch)); + } else { + regOpnd = GetOrCreateVirtualRegisterOperand(ujavaCatch.regno_javaCatch); + } + return regOpnd; + } + case kSregRetval0: + if (!IsPrimitiveInteger(primType)) { + reg = V0; + } + /* else (if-integer) uses x0 == R0 */ + break; + case kSregMethodhdl: + if (method_handle_vreg == regno_t(-1)) { + method_handle_vreg = New_V_Reg(kRegTyInt, 8); + } + return GetOrCreateVirtualRegisterOperand(method_handle_vreg); + default: + CG_ASSERT(0, "Special pseudo registers NYI"); + break; + } + return GetOrCreatePhysicalRegisterOperand(reg, 64, kRegTyInt); +} + +Riscv64RegOperand *Riscv64CGFunc::GetOrCreatePhysicalRegisterOperand(Riscv64reg_t regNo, uint8 size, RegType kind, + uint32 flag, VectorType vecType, int vecPos) { + if (size <= 32) { + size = 32; + } else if (size <= 64){ + size = 64; + } else if (size <= 128) { + size = 128; + } else { + CG_ASSERT(false, "NYI"); + } + + auto it = phy_reg_operand_table.find(Riscv64RegOperand(regNo, size, kind, flag, vecType, vecPos)); + if (it != phy_reg_operand_table.end()) { + return it->second; + } + + Riscv64RegOperand *o = memPool->New(regNo, size, kind, flag, vecType, vecPos); + phy_reg_operand_table[*o] = o; + return o; +} + +LabelOperand *Riscv64CGFunc::GetOrCreateLabelOperand(LabelIdx labidx) { + MapleMap::iterator it = hash_lblopnd_tb_.find(labidx); + if (it != hash_lblopnd_tb_.end()) { + return it->second; + } + MIRSymbol *funcSt = GlobalTables::GetGsymTable().GetSymbolFromStIdx(func->stIdx.Idx()); + const char *funcName = MapleString(funcSt->GetName(), memPool).c_str(); + LabelOperand *res = memPool->New(funcName, labidx); + hash_lblopnd_tb_[labidx] = res; + return res; +} + +LabelOperand *Riscv64CGFunc::CreateFuncLabelOperand(MIRSymbol * func) { + const char *funcName = memPool->New(func->GetName())->c_str(); + return memPool->New(funcName); +} + +Riscv64OfstOperand *Riscv64CGFunc::GetOrCreateOfstOpnd(uint32 offset, uint32 size) { + Riscv64OfstOperand tofstopnd(offset, size); + auto it = hash_ofstopnd_tb_.find(tofstopnd); + if (it != hash_ofstopnd_tb_.end()) { + return it->second; + } + Riscv64OfstOperand *res = memPool->New(offset, size); + hash_ofstopnd_tb_[tofstopnd] = res; + return res; +} + +MemOperand *Riscv64CGFunc::GetOrCreateArgMemOpnd(MIRSymbol * symbol, int32 offset, int32 size) { + MIRStorageClass storageClass = symbol->storageClass; + + Riscv64SymbolAlloc *symloc = static_cast(memlayout->sym_alloc_table[symbol->GetStIndex()]); + CG_ASSERT(symloc, "sym loc should have been defined"); + // At this point, we don't know which registers the callee needs to save. + CG_ASSERT((IsFPLRAddedToCalleeSavedList() || SizeOfCalleeSaved() == 0), + "CalleeSaved won't be known until after Register Allocation"); + StIdx idx = symbol->GetStIdx(); + auto it = memopnds_requiring_offset_adjustment_.find(idx); + CG_ASSERT((!IsFPLRAddedToCalleeSavedList() || + (it != memopnds_requiring_offset_adjustment_.end() || + storageClass == kScFormal)), + "Memory operand of this symbol should have been added to the hash table"); + if (it != memopnds_requiring_offset_adjustment_.end()) { + return it->second; + } + it = memopnds_for_stkpassed_arguments.find(idx); + if (it != memopnds_for_stkpassed_arguments.end()) { + return it->second; + } + + RegOperand *tempreg = GetOrCreatePhysicalRegisterOperand(R9, SIZEOFPTR * 8, kRegTyInt); + + Riscv64RegOperand *baseOpnd = static_cast(GetBaseReg(symloc)); + int32 stoffset = GetBaseOffset(symloc); + int32 totalOffset = stoffset + offset; + // needs a fresh copy of OfstOperand as we may adjust its offset at a later stage + Riscv64MemOperand *res = nullptr; + if (symloc->mem_segment->kind == kMsArgsStkpassed && Riscv64MemOperand::IsPIMMOffsetOutOfRange(totalOffset, size)) { + Riscv64ImmOperand *offsetopran; + offsetopran = CreateImmOperand(totalOffset, 64, true, true); + SelectCopy(tempreg, PTY_i64, offsetopran, PTY_i64); + curbb->AppendInsn(cg->BuildInstruction(MOP_xaddrrr, tempreg, tempreg, baseOpnd)); + Riscv64OfstOperand *offsetOpnd = memPool->New(0, 64); + res = memPool->New(size, tempreg, + nullptr, offsetOpnd, symbol); + } else if (symloc->mem_segment->kind == kMsReflocals && false) { + Riscv64ImmOperand *offsetopran; + auto iOpndIt = immopnds_requiring_offset_adjustment_for_refloc_.find(symloc); + if (iOpndIt != immopnds_requiring_offset_adjustment_for_refloc_.end()) { + offsetopran = (*iOpndIt).second; + } else { + offsetopran = CreateImmOperand(totalOffset, 64, true); + immopnds_requiring_offset_adjustment_for_refloc_[symloc] = offsetopran; + } + + SelectCopy(tempreg, PTY_i64, offsetopran, PTY_i64); + curbb->AppendInsn(cg->BuildInstruction(MOP_xaddrrr, tempreg, tempreg, baseOpnd)); + Riscv64OfstOperand *offsetOpnd = memPool->New(0, 64); + res = memPool->New(size, tempreg, + nullptr, offsetOpnd, symbol); + + } else { + Riscv64OfstOperand *offsetOpnd = memPool->New(totalOffset, 64); + if (symloc->mem_segment->kind == kMsArgsStkpassed) { + offsetOpnd->SetVary(true); + } + res = memPool->New(size, baseOpnd, nullptr, + offsetOpnd, symbol); + memopnds_requiring_offset_adjustment_[idx] = res; + } + return res; +} + +MemOperand *Riscv64CGFunc::GetOrCreateMemOpnd(MIRSymbol * symbol, int32 offset, int32 size) { + MIRStorageClass storageClass = symbol->storageClass; + if (storageClass == kScAuto || storageClass == kScFormal) { + Riscv64SymbolAlloc *symloc = + static_cast(memlayout->sym_alloc_table.at(symbol->GetStIndex())); + CG_ASSERT(symloc, "sym loc should have been defined"); + // At this point, we don't know which registers the callee needs to save. + CG_ASSERT((IsFPLRAddedToCalleeSavedList() || SizeOfCalleeSaved() == 0), + "CalleeSaved won't be known until after Register Allocation"); + StIdx idx = symbol->GetStIdx(); + auto it = memopnds_requiring_offset_adjustment_.find(idx); + CG_ASSERT( + (!IsFPLRAddedToCalleeSavedList() || + (it != memopnds_requiring_offset_adjustment_.end() || + storageClass == kScFormal)), + "Memory operand of this symbol should have been added to the hash table"); + int32 stoffset = GetBaseOffset(symloc); + if (it != memopnds_requiring_offset_adjustment_.end()) { + if (mirModule.IsJavaModule()) { + return it->second; + } else { + Operand *offopnd = (it->second)->GetOffset(); + if (((static_cast(offopnd))->GetOffsetValue() == (stoffset + offset)) && + (it->second->GetSize() == size)) { + return it->second; + } + } + } + it = memopnds_for_stkpassed_arguments.find(idx); + if (it != memopnds_for_stkpassed_arguments.end()) { + return it->second; + } + + Riscv64RegOperand *baseOpnd = static_cast(GetBaseReg(symloc)); + int32 totalOffset = stoffset + offset; + // needs a fresh copy of OfstOperand as we may adjust its offset at a later stage + Riscv64MemOperand *res = nullptr; + if (symloc->mem_segment->kind == kMsArgsStkpassed && + Riscv64MemOperand::IsPIMMOffsetOutOfRange(totalOffset, size)) { + Riscv64ImmOperand *offsetopran; + offsetopran = CreateImmOperand(totalOffset, 64, true, true); + RegOperand *tempreg = SelectCopy(offsetopran, PTY_i64, PTY_i64); + curbb->AppendInsn(cg->BuildInstruction(MOP_xaddrrr, tempreg, tempreg, baseOpnd)); + Riscv64OfstOperand *offsetOpnd = memPool->New(0, 64); + res = memPool->New(size, tempreg, + nullptr, offsetOpnd, symbol); + } else if (symloc->mem_segment->kind == kMsReflocals && false) { + Riscv64ImmOperand *offsetopran; + auto iOpndIt = immopnds_requiring_offset_adjustment_for_refloc_.find(symloc); + if (iOpndIt != immopnds_requiring_offset_adjustment_for_refloc_.end()) { + offsetopran = (*iOpndIt).second; + } else { + offsetopran = CreateImmOperand(totalOffset, 64, true); + immopnds_requiring_offset_adjustment_for_refloc_[symloc] = offsetopran; + } + RegOperand *tempreg = SelectCopy(offsetopran, PTY_i64, PTY_i64); + curbb->AppendInsn(cg->BuildInstruction(MOP_xaddrrr, tempreg, tempreg, baseOpnd)); + Riscv64OfstOperand *offsetOpnd = memPool->New(0, 64); + res = memPool->New(size, tempreg, + nullptr, offsetOpnd, symbol); + } else { + Riscv64OfstOperand *offsetOpnd = memPool->New(totalOffset, 64); + if (symloc->mem_segment->kind == kMsArgsStkpassed) { + offsetOpnd->SetVary(true); + } + res = memPool->New(size, baseOpnd, + nullptr, offsetOpnd, symbol); + if (symbol->GetType()->typeKind != kTypeClass) { + memopnds_requiring_offset_adjustment_[idx] = res; + } + } + return res; + } else if (storageClass == kScGlobal || storageClass == kScExtern || + storageClass == kScPstatic || storageClass == kScFstatic) { + StImmOperand *stopnd = CreateStImmOperand(symbol, offset, 0); + Riscv64RegOperand *staddropnd = static_cast(CreateRegisterOperandOfType(PTY_u64)); + SelectAddrof(staddropnd, stopnd); + /* Riscv64MemOperand::AddrMode_B_OI */ + /* Since adrp of the symbol already took care of the offset from the symbol base, + there is no need to repeat the offset in the actual mem opnd. + */ + return memPool->New(size, staddropnd, + static_cast(nullptr), GetOrCreateOfstOpnd(0, 32), symbol); + } else { + CG_ASSERT(false, "NYI"); + } + return nullptr; +} + +Riscv64MemOperand *Riscv64CGFunc::GetOrCreateMemOpnd(int32 size, RegOperand * base, RegOperand * index, Operand * offset, + MIRSymbol * st) { + Riscv64MemOperand tmemopnd(size, base, index, offset, st); + auto it = hash_memopnd_tb_.find(tmemopnd); + if (it != hash_memopnd_tb_.end()) { + return it->second; + } + Riscv64MemOperand *res = memPool->New(tmemopnd); + hash_memopnd_tb_[tmemopnd] = res; + return res; +} + +// offset: base offset from FP or SP +MemOperand *Riscv64CGFunc::CreateMemOpnd(RegOperand * baseOpnd, int32 offset, int32 datasize) { + if (Riscv64MemOperand::IsPIMMOffsetOutOfRange(offset, datasize)) { + Riscv64ImmOperand *offsetopran = CreateImmOperand(offset, SIZEOFPTR * 8, true, true); + regno_t vreg = New_V_Reg(kRegTyInt, GetPrimTypeSize(PTY_a64)); + RegOperand *tempreg = CreateVirtualRegisterOperand(vreg); + SelectCopy(tempreg, PTY_i64, offsetopran, PTY_i64); + curbb->AppendInsn(cg->BuildInstruction(MOP_xaddrrr, tempreg, tempreg, baseOpnd)); + Riscv64OfstOperand *offsetOpnd = memPool->New(0, 64); + return memPool->New(datasize, tempreg, + nullptr, offsetOpnd, (MIRSymbol *)nullptr); + } else if (!ImmOperand::IsInBitSizeRot(12, offset)) { + Operand *resimmopnd = SelectCopy(CreateImmOperand(offset, 32, true), PTY_i32, PTY_i32); + return memPool->New(datasize, baseOpnd, + static_cast(resimmopnd), nullptr, nullptr); + } else { + Riscv64OfstOperand *offsetOpnd = CreateOfstOpnd(offset, 32); + return memPool->New(datasize, baseOpnd, + nullptr, offsetOpnd, (MIRSymbol *)nullptr); + } +} + +// offset: base offset + #:lo12:Label+immediate +MemOperand *Riscv64CGFunc::CreateMemOpnd(RegOperand * baseOpnd, int32 offset, int32 datasize, MIRSymbol * sym) { + Riscv64OfstOperand *offsetOpnd = CreateOfstOpnd(offset, 32); + CG_ASSERT(ImmOperand::IsInBitSizeRot(12, offset), ""); + return memPool->New(datasize, baseOpnd, + static_cast(nullptr), offsetOpnd, sym); +} + +RegOperand *Riscv64CGFunc::GenStructParamIndex(RegOperand *base, BaseNode *indexExpr, int shift) { + RegOperand *index = static_cast(LoadIntoRegister(HandleExpr(indexExpr, indexExpr->Opnd(0)), PTY_a64)); + RegOperand *tmpopnd = CreateRegisterOperandOfType(PTY_a64); + ImmOperand *imm = CreateImmOperand(PTY_a64, shift); + SelectShift(tmpopnd, index, imm, kShiftLeft, PTY_a64); + RegOperand *result = CreateRegisterOperandOfType(PTY_a64); + SelectAdd(result, base, tmpopnd, PTY_a64); + + Riscv64OfstOperand *offopnd = CreateOfstOpnd(0, 32); + Riscv64MemOperand *mo = + GetOrCreateMemOpnd(SIZEOFPTR * BITS_PER_BYTE, + static_cast(result), + nullptr, offopnd, nullptr); + regno_t vregno = New_V_Reg(kRegTyInt, GetPrimTypeSize(PTY_a64)); + RegOperand *structAddr = CreateVirtualRegisterOperand(vregno); + curbb->AppendInsn(cg->BuildInstruction(MOP_xldr, structAddr, mo)); + + return structAddr; +} + +// Create a memory operand with specified data type and memory ordering, making +// use of riscv64 extend register addressing mode when possible. +MemOperand *Riscv64CGFunc::CreateMemOpnd(PrimType ptype, BaseNode * parent, BaseNode * addrExpr, int offset, + Riscv64isa::memory_ordering_t mo) { + aggParamReg = nullptr; + MemOperand *memopnd = nullptr; + +#if 0 + if (mo == Riscv64isa::kMoNone && IsPrimitiveInteger(ptype) && + addrExpr->op == OP_add && offset == 0) { + BaseNode *baseExpr = addrExpr->Opnd(0); + BaseNode *addendExpr = addrExpr->Opnd(1); + + if (addendExpr->op == OP_mul) { + BaseNode *indexExpr, *scaleExpr; + indexExpr = addendExpr->Opnd(0); + scaleExpr = addendExpr->Opnd(1); + + if (scaleExpr->op == OP_constval) { + ConstvalNode *constvalnode = static_cast(scaleExpr); + MIRIntConst *mirintconst = dynamic_cast(constvalnode->constVal); + CHECK_FATAL(mirintconst != nullptr, "just checking"); + + int scale = mirintconst->value; + if (scale == GetPrimTypeSize(ptype)) { + if (indexExpr->op == OP_cvt) { + int shift = scale == 8 ? 3 : (scale == 4 ? 2 : (scale == 2 ? 1 : 0)); + RegOperand *base = static_cast(LoadIntoRegister(HandleExpr(addrExpr, baseExpr), PTY_a64)); + TypeCvtNode *typecvtnode = static_cast(indexExpr); + PrimType fromtype = typecvtnode->fromPrimType; + PrimType totype = typecvtnode->primType; + + if (isAggParamInReg) { + aggParamReg = GenStructParamIndex(base, indexExpr, shift); + return nullptr; + } + + if (fromtype == PTY_i32 && totype == PTY_a64) { + RegOperand *index = + static_cast(LoadIntoRegister(HandleExpr(indexExpr, indexExpr->Opnd(0)), PTY_i32)); + memopnd = GetOrCreateMemOpnd(Riscv64MemOperand::kAddrModeBOrX, GetPrimTypeBitSize(ptype), base, index, + shift, true); + } else if (fromtype == PTY_u32 && totype == PTY_a64) { + RegOperand *index = + static_cast(LoadIntoRegister(HandleExpr(indexExpr, indexExpr->Opnd(0)), PTY_u32)); + memopnd = GetOrCreateMemOpnd(Riscv64MemOperand::kAddrModeBOrX, GetPrimTypeBitSize(ptype), base, index, + shift, false); + } + } + } + } + } + } +#endif + + if (memopnd == nullptr) { + Operand *addropnd = HandleExpr(parent, addrExpr); + addropnd = static_cast(LoadIntoRegister(addropnd, PTY_a64)); + Riscv64OfstOperand *offopnd = GetOrCreateOfstOpnd(offset, 32); + memopnd = GetOrCreateMemOpnd(GetPrimTypeBitSize(ptype), + static_cast(addropnd), nullptr, offopnd, nullptr); + } + + return memopnd; +} + +Operand *Riscv64CGFunc::GetOrCreateFuncNameOpnd(MIRSymbol * symbol) { + return memPool->New(symbol); +} + +Operand *Riscv64CGFunc::GetOrCreatevaryreg() { + // TODO : To use SP or FP in OffsetAdjustmentForFPLR() for the future, this register type + // is not needed as IsVary() accomplish the same. + if (vary_ == nullptr) { + regno_t vRegNo = New_V_Reg(kRegTyVary, 8); + vary_ = CreateVirtualRegisterOperand(vRegNo); + } + return vary_; +} + +// the first operand in opndvec is return opnd +void Riscv64CGFunc::SelectLibCall(const char *name, vector &opndvec, PrimType primtype, + PrimType retprmtype, bool is2ndret) { + MIRSymbol *st = GlobalTables::GetGsymTable().CreateSymbol(kScopeGlobal); + std::string funcname(name); + st->SetNameStridx(GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(funcname)); + st->storageClass = kScText; + st->sKind = kStFunc; + // setup the type of the callee function + std::vector vec; + std::vector vecAt; + for (uint32 i = 1; i < opndvec.size(); i++) { + vec.push_back(GlobalTables::GetTypeTable().typeTable[static_cast(primtype)]->tyIdx); + vecAt.push_back(TypeAttrs()); + } + + MIRType *rettype = GlobalTables::GetTypeTable().typeTable[static_cast(primtype)]; + st->SetTyIdx(becommon.BeGetOrCreateFunctionType(rettype->tyIdx, vec, vecAt)->tyIdx); + + if (cg->GenerateVerboseAsm()) { + string comment = "lib call : " + funcname; + const char *str = comment.c_str(); + curbb->AppendInsn(cg->BuildInstruction(MOP_comment, CreateCommentOperand(str))); + } + + ParmLocator parmlocator(becommon); + PLocInfo ploc; + CG_ASSERT(primtype != PTY_void, ""); + // setup actual parameters + Riscv64ListOperand *srcOpnds = memPool->New(funcscope_allocator_); + for (uint32 i = 1; i < opndvec.size(); i++) { + MIRType *ty; + ty = GlobalTables::GetTypeTable().typeTable[static_cast(primtype)]; + Operand *stOpnd = opndvec[i]; + if (stOpnd->op_kind_ != Operand::Opd_Register) { + stOpnd = SelectCopy(stOpnd, primtype, primtype); + } + RegOperand *expregopnd = static_cast(stOpnd); + parmlocator.LocateNextParm(ty, ploc); + if (ploc.reg0 != 0) { // load to the register + Riscv64RegOperand *parmregopnd = + GetOrCreatePhysicalRegisterOperand(ploc.reg0, expregopnd->size_, GetRegTyFromPrimTyRiscv64(primtype)); + SelectCopy(parmregopnd, primtype, expregopnd, primtype); + srcOpnds->PushOpnd(parmregopnd); + } + CG_ASSERT(ploc.reg1 == 0, "SelectCall NYI"); + } + + Operand *targetopnd = + GetOrCreateFuncNameOpnd(mirModule.CurFunction()->GetLocalOrGlobalSymbol(st->GetStIdx(), false)); + Insn *callInsn = cg->BuildInstruction(MOP_xbl, targetopnd, srcOpnds); + MIRType *callRettype = GlobalTables::GetTypeTable().typeTable[static_cast(retprmtype)]; + if (callRettype) { + callInsn->SetRetSize(callRettype->GetSize()); + callInsn->SetRetSignType(IsUnsignedInteger(rettype->GetPrimType())); + } + curbb->AppendInsn(callInsn); + func->SetHasCall(); + // get return value + Operand *opnd0 = opndvec[0]; + ReturnMechanism retmech(GlobalTables::GetTypeTable().typeTable.at(retprmtype), becommon); + Riscv64RegOperand *retopnd = nullptr; + if (retmech.regcount > 0) { + if (RegOperand *regopnd = dynamic_cast(opnd0)) { + Riscv64reg_t regnum = is2ndret ? retmech.reg1 : retmech.reg0; + if (regopnd->GetRegisterNumber() != regnum) { + retopnd = GetOrCreatePhysicalRegisterOperand(regnum, regopnd->GetSize(), GetRegTyFromPrimTyRiscv64(retprmtype)); + SelectCopy(opnd0, retprmtype, retopnd, retprmtype); + } + } else { + CG_ASSERT(false, "nyi"); + } + } else { + CG_ASSERT(false, "should return from register"); + } +} + +Operand *Riscv64CGFunc::GetBaseReg(Riscv64SymbolAlloc * symballoc) { + MemSegmentKind sgkind = symballoc->mem_segment->kind; + CG_ASSERT((sgkind == kMsArgsRegpassed || sgkind == kMsLocals || sgkind == kMsReflocals || + sgkind == kMsArgsToStkpass || sgkind == kMsArgsStkpassed), + "NYI"); + + if (sgkind == kMsArgsStkpassed) { + return GetOrCreatevaryreg(); + } + + if (!fsp_) { + fsp_ = GetOrCreatePhysicalRegisterOperand(UseFP() || HasVLAOrAlloca() ? RFP : RSP, SIZEOFPTR * 8, kRegTyInt); + } + return fsp_; +} + +uint32 Riscv64CGFunc::GetBaseOffset(SymbolAlloc * sa) { + Riscv64SymbolAlloc *symalloc = static_cast(sa); + /* Call Frame layout of Riscv64 + Refer to V2 in riscv64_mem_layout.h. + Do Not change this unless you know what you do + */ + int sizeofFplr = 2 * kIntregBytelen; + MemSegmentKind sgkind = symalloc->mem_segment->kind; + Riscv64MemLayout *memlayout = static_cast(this->memlayout); + int64 argsToStkpassSize = memlayout->SizeOfArgsToStackpass(); + if (sgkind == kMsArgsStkpassed) { // for callees + uint32 offset = symalloc->offset; + return offset; + } else if (sgkind == kMsArgsRegpassed) { + int baseOffset = memlayout->GetSizeOfLocals() + symalloc->offset + memlayout->GetSizeOfRefLocals() + + memlayout->seg_lockobjslot.size; + if (!UseFP() && !HasVLAOrAlloca() && argsToStkpassSize > 0) { + baseOffset += argsToStkpassSize; + } + return baseOffset + sizeofFplr; + } else if (sgkind == kMsReflocals) { + int baseOffset = symalloc->offset + memlayout->GetSizeOfLocals() + memlayout->seg_lockobjslot.size; + if (!UseFP() && !HasVLAOrAlloca() && argsToStkpassSize > 0) { + baseOffset += argsToStkpassSize; + } + return baseOffset + sizeofFplr; + } else if (sgkind == kMsLocals) { + int baseOffset = symalloc->offset + memlayout->seg_lockobjslot.size; + if (!UseFP() && !HasVLAOrAlloca() && argsToStkpassSize > 0) { + baseOffset += argsToStkpassSize; + } + return baseOffset + sizeofFplr; + } else if (sgkind == kMsLockslot) { + int baseOffset = symalloc->offset; + if (!UseFP() && !HasVLAOrAlloca() && argsToStkpassSize > 0) { + baseOffset += argsToStkpassSize; + } + return baseOffset + sizeofFplr; + } else if (sgkind == kMsSpillReg) { + int baseOffset = symalloc->offset + memlayout->SizeOfArgsRegisterPassed() + memlayout->GetSizeOfLocals() + + memlayout->GetSizeOfRefLocals() + memlayout->seg_lockobjslot.size; + if (!UseFP() && !HasVLAOrAlloca() && argsToStkpassSize > 0) { + baseOffset += argsToStkpassSize; + } + return baseOffset + sizeofFplr; + } else if (sgkind == kMsArgsToStkpass) { // this is for callers + return static_cast(symalloc->offset); + } else { + CG_ASSERT(false, ""); + } + return 0; +} + +void Riscv64CGFunc::AppendCall(MIRSymbol * func) { + Riscv64ListOperand *srcOpnds = memPool->New(funcscope_allocator_); + Operand *targetopnd = GetOrCreateFuncNameOpnd(func); + curbb->AppendInsn(cg->BuildInstruction(MOP_xbl, targetopnd, srcOpnds)); +} + +void Riscv64CGFunc::AppendJump(MIRSymbol * func) { + Operand *targetopnd = CreateFuncLabelOperand(func); + curbb->AppendInsn(cg->BuildInstruction(MOP_xuncond, targetopnd)); +} + +/* For long reach branch, insert a branch in between. + * convert + * condbr target_label + * fallthruBB + * to + * condbr pad_label bb + * uncondbr bypass_label brBB + * pad_label padBB + * uncondbr target_label + * bypass_label bypassBB + * ... fallthruBB + */ +void Riscv64CGFunc::InsertJumpPad(Insn *insn) { + BB *bb = insn->bb; + CG_ASSERT(bb, "instruction has no bb"); + CG_ASSERT(bb->GetKind() == BB::kBBIf, "instruction is not in a if bb"); + + LabelIdx labidx = static_cast(insn->GetOperand(insn->GetJumpTargetIdx()))->labidx_; + LabelIdx padLabel = CreateLabel(); + BB *brBB = CreateNewBB(); + BB *padBB = CreateNewBB(); + lab2bbmap[padLabel] = padBB; + padBB->AddLabel(padLabel); + + BB *targetBB; + BB *fallthruBB = bb->next; + CG_ASSERT(bb->succs.size() == 2, "if bb should have 2 successors"); + if (bb->succs.front() == fallthruBB) { + targetBB = bb->succs.back(); + } else { + targetBB = bb->succs.front(); + } + // Regardless targetBB as is or an non-empty successor, it needs to be removed + bb->succs.remove(targetBB); + targetBB->preds.remove(bb); + while (targetBB->GetKind() == BB::kBBFallthru && targetBB->NumInsn() == 0) { + targetBB = targetBB->next; + } + bb->next = brBB; + brBB->next = padBB; + padBB->next = fallthruBB; + brBB->prev = bb; + padBB->prev = brBB; + fallthruBB->prev = padBB; + // adjust bb branch preds succs for jump to padBB + LabelOperand *padLabelOpnd = GetOrCreateLabelOperand(padLabel); + uint32 idx = insn->GetJumpTargetIdx(); + insn->SetOperand(idx, padLabelOpnd); + bb->succs.remove(fallthruBB); + bb->succs.push_back(brBB); // new fallthru + bb->succs.push_back(padBB); // new target + // + targetBB->preds.remove(bb); + targetBB->preds.push_back(padBB); + // + LabelIdx bypassLabel = fallthruBB->labidx; + if (bypassLabel == 0) { + bypassLabel = CreateLabel(); + lab2bbmap[bypassLabel] = fallthruBB; + fallthruBB->AddLabel(bypassLabel); + } + LabelOperand *bypassLabelOpnd = GetOrCreateLabelOperand(bypassLabel); + brBB->AppendInsn(cg->BuildInstruction(MOP_xuncond, bypassLabelOpnd)); + brBB->SetKind(BB::kBBGoto); + brBB->preds.push_back(bb); + brBB->succs.push_back(fallthruBB); + // + RegOperand *targetAddr = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + LabelIdx targetLabel = targetBB->labidx; + if (targetLabel == 0) { + targetLabel = CreateLabel(); + lab2bbmap[targetLabel] = targetBB; + targetBB->AddLabel(targetLabel); + } + LabelOperand *targetLabelOpnd = GetOrCreateLabelOperand(targetLabel); + padBB->AppendInsn(cg->BuildInstruction(MOP_laddr, targetAddr, targetLabelOpnd)); + padBB->AppendInsn(cg->BuildInstruction(MOP_xbr, targetAddr)); + padBB->SetKind(BB::kBBIgoto); + padBB->preds.push_back(bb); + padBB->succs.push_back(targetBB); + // + fallthruBB->preds.remove(bb); + fallthruBB->preds.push_back(brBB); +} + +void Riscv64CGFunc::ConvertJumpToRegJump(Insn *insn) { + BB *bb = insn->bb; + CG_ASSERT(bb, "instruction has no bb"); + CG_ASSERT(bb->GetKind() == BB::kBBGoto, "instruction is not in a goto bb"); + + LabelIdx labidx = static_cast(insn->GetOperand(insn->GetJumpTargetIdx()))->labidx_; + RegOperand *targetAddr = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + LabelOperand *targetLabelOpnd = GetOrCreateLabelOperand(labidx); + Insn *loadLabelInsn = cg->BuildInstruction(MOP_laddr, targetAddr, targetLabelOpnd); + bb->InsertInsnBefore(insn, loadLabelInsn); + + Insn *regJumpInsn = cg->BuildInstruction(MOP_xbr, targetAddr); + bb->ReplaceInsn(insn, regJumpInsn); +} + +void Riscv64CGFunc::DBGFixCallFrameLocationOffsets() { + // LogInfo::MapleLogger() << "DBGFixCallFrameLocationOffsets " << " DBG callframe offset = " << dbg_callframe_offset << endl; + for (DBGExprLoc *el : dbg_callframe_locations) { + if (el->simploc_->dwop_ == DW_OP_fbreg) { + SymbolAlloc *symloc = static_cast(el->symloc_); + int64_t offset = GetBaseOffset(symloc) - dbg_callframe_offset; + + el->SetFboffset(offset); + } + } +} + +void Riscv64CGFunc::OffsetAdjustmentForFPLR() { + int64 argsToStkpassSize = memlayout->SizeOfArgsToStackpass(); + FOR_ALL_BB(bb, this) { + FOR_BB_INSNS_SAFE(insn, bb, ninsn) { + for (int i = 0; i < Insn::kMaxOperandNum; i++) { + Operand *oper = insn->opnds[i]; + if (oper) { + if (oper->IsRegister()) { + RegOperand *regop = dynamic_cast(oper); + if (regop && regop->IsOfVary()) { + insn->SetOperand(i, GetOrCreateStackBaseRegOperand()); + } + } else if (oper->IsMemoryAccessOperand()) { + Riscv64MemOperand *memoper = dynamic_cast(oper); + if (memoper && + memoper->GetBaseRegister() && memoper->GetBaseRegister()->IsOfVary()) { + memoper->SetBaseRegister(static_cast(GetOrCreateStackBaseRegOperand())); + } + + if (memoper) { + Riscv64OfstOperand *oo = memoper->GetOffsetImmediate(); + if (oo->IsVary()) { + if (!UseFP() && !HasVLAOrAlloca() && argsToStkpassSize > 0) { + oo->AdjustOffset(static_cast(memlayout)->RealStackFrameSize()); + } else { + oo->AdjustOffset(static_cast(memlayout)->RealStackFrameSize() - + argsToStkpassSize); + } + oo->SetVary(false); + } + } + + } else if (oper->IsIntImmediate()) { + ImmOperand *imo = dynamic_cast(oper); + OfstOperand *imo1 = dynamic_cast(oper); + if (imo || imo1) { + if (imo->IsVary()) { + if (!UseFP() && !HasVLAOrAlloca() && argsToStkpassSize > 0) { + imo->Add(static_cast(memlayout)->RealStackFrameSize()); + } else { + imo->Add(static_cast(memlayout)->RealStackFrameSize() - argsToStkpassSize); + if (insn->GetMachineOpcode() != MOP_xmovri64 && + !static_cast(imo)->IsInBitSize(11)) { + ReplaceLargeStackOffsetImm(insn); + bb->RemoveInsn(insn); + } + } + } + imo->SetVary(false); + } + } + } else { + break; + } + } + } + } + +#undef STKLAY_DBUG +#ifdef STKLAY_DBUG + // int32 total = + // seg__args_regpassed.size + // + static_cast(cgfunc)->SizeOfCalleeSaved() + // + GetSizeOfRefLocals() + locals().size + GetSizeOfSpillReg() + seg_lockobjslot.size; + + // if the function does not have VLA nor alloca, + // we allocate space for arguments to stack-pass + // in the call frame; otherwise, it has to be allocated for each call and reclaimed afterward. + // total += seg__args_to_stkpass.size; + Riscv64MemLayout *riscv64memlayout = static_cast(this->memlayout); + LogInfo::MapleLogger() << "stkpass: " << riscv64memlayout->seg__args_to_stkpass.size << endl; + LogInfo::MapleLogger() << "lockslot: " << riscv64memlayout->seg_lockobjslot.size << endl; + LogInfo::MapleLogger() << "local: " << riscv64memlayout->GetSizeOfLocals() << endl; + LogInfo::MapleLogger() << "ref local: " << riscv64memlayout->GetSizeOfRefLocals() << endl; + LogInfo::MapleLogger() << "regpass: " << riscv64memlayout->seg__args_regpassed.size << endl; + LogInfo::MapleLogger() << "regspill: " << riscv64memlayout->GetSizeOfSpillReg() << endl; + LogInfo::MapleLogger() << "calleesave: " << SizeOfCalleeSaved() << endl; + +#endif +} + +bool Riscv64CGFunc::SizeIsRight(Insn * insn) { + CG_ASSERT(insn->IsMachineInstruction(), "insn should be instruction"); + MOperator mop = insn->GetMachineOpcode(); + switch (mop) { + case MOP_xaddrri12: + case MOP_waddrri12: + case MOP_xsubrri12: + case MOP_wsubrri12: { + Riscv64ImmOperand *immopnd = static_cast(insn->GetOperand(2)); + return immopnd->IsInSignedBitSize(12); + } + case MOP_xandrri13: + case MOP_xiorrri13: + case MOP_xeorrri13: { + Riscv64ImmOperand *immopnd = static_cast(insn->GetOperand(2)); + return immopnd->IsInBitSize(12); + } + case MOP_wlslrri5: + case MOP_wasrrri5: + case MOP_wlsrrri5: { + Riscv64ImmOperand *immopnd = static_cast(insn->GetOperand(2)); + return immopnd->IsInBitSize(8); + } + case MOP_xlslrri6: + case MOP_xasrrri6: + case MOP_xlsrrri6: { + Riscv64ImmOperand *immopnd = static_cast(insn->GetOperand(2)); + return immopnd->IsInBitSize(6); + } + case MOP_wldrb: + case MOP_wstrb: + case MOP_wldrsb: { + Riscv64MemOperand *memopnd = static_cast(insn->GetOperand(1)); + return memopnd->GetSize() == 8; + } + case MOP_wldrh: + case MOP_wstrh: + case MOP_wldrsh: { + Riscv64MemOperand *memopnd = static_cast(insn->GetOperand(1)); + return memopnd->GetSize() == 16; + } + case MOP_sldr: + case MOP_wldaxr: + case MOP_wstr: + case MOP_sstr: + case MOP_wstlr: + case MOP_wstllr: + case MOP_wstadd: + case MOP_wstaddl: + case MOP_wstclr: + case MOP_wstclrl: + case MOP_wsteor: + case MOP_wsteorl: + case MOP_wldr: { + Riscv64MemOperand *memopnd = static_cast(insn->GetOperand(1)); + return memopnd->GetSize() == 32; + } + case MOP_dldr: + case MOP_xldxr: + case MOP_xldaxr: + case MOP_xstr: + case MOP_dstr: + case MOP_xstlr: + case MOP_xstllr: + case MOP_xstadd: + case MOP_xstaddl: + case MOP_xstclr: + case MOP_xstclrl: + case MOP_xsteor: + case MOP_xsteorl: + case MOP_xldr: { + Riscv64MemOperand *memopnd = static_cast(insn->GetOperand(1)); + return memopnd->GetSize() == 64; + } + case MOP_wldaxp: + case MOP_wstxr: + case MOP_wstlxr: { + Riscv64MemOperand *memopnd = static_cast(insn->GetOperand(2)); + return memopnd->GetSize() == 32; + } + case MOP_xldaxp: + case MOP_xstxr: + case MOP_xstlxr: { + Riscv64MemOperand *memopnd = static_cast(insn->GetOperand(2)); + return memopnd->GetSize() == 64; + } + case MOP_xstlxp: + case MOP_wstlxp: { + Riscv64MemOperand *memopnd = static_cast(insn->GetOperand(3)); + return memopnd->GetSize() == 64; + } + default: + return true; + } +} + +void Riscv64CGFunc::CheckImmMemSize() { + FOR_ALL_BB(bb, this) { + FOR_BB_INSNS(insn, bb) { + if (!insn->IsMachineInstruction()) { + continue; + } + if (!SizeIsRight(insn)) { + LogInfo::MapleLogger() << "Warning: ImmOperand or MemOperand size is unreasonable in function " << GetName() << std::endl; + insn->dump(); + } + } + } +} + +MemOperand *Riscv64CGFunc::AdjustMemOperandIfOffsetOutOfRange( + MemOperand * memopnd, regno_t vrnum, Insn * insn, Riscv64reg_t regnum, uint8 & isOutOfRange, bool isDest) { + CHECK_FATAL(vrnum < v_reg_table.size(), "index out of range in Riscv64CGFunc::AdjustMemOperandIfOffsetOutOfRange"); + int32 datasize = v_reg_table[vrnum].GetSize() * BITS_PER_BYTE; + if (IsImmediateOffsetOutOfRange(static_cast(memopnd), datasize)) { + isOutOfRange = 1; + memopnd = + SplitOffsetWithAddInstruction(static_cast(memopnd), datasize, regnum, insn, isDest); + } else { + isOutOfRange = 0; + } + return memopnd; +} + +void Riscv64CGFunc::TestInterface() { + regno_t vn1 = New_V_Reg(kRegTyInt, 4); + regno_t vn2 = New_V_Reg(kRegTyInt, 8); + MemOperand *rm1 = GetOrCreatSpillMem(vn1); + MemOperand *rm2 = GetOrCreatSpillMem(vn2); + FreeSpillRegMem(vn1); + FreeSpillRegMem(vn2); + + regno_t vn3 = New_V_Reg(kRegTyInt, 4); + regno_t vn4 = New_V_Reg(kRegTyInt, 8); + MemOperand *rm3 = GetOrCreatSpillMem(vn3); + MemOperand *rm4 = GetOrCreatSpillMem(vn4); + + LogInfo::MapleLogger() << "rm1 addr: " << static_cast(rm1->GetOffsetOperand())->GetOffsetValue() << endl; + LogInfo::MapleLogger() << "rm3 addr: " << static_cast(rm3->GetOffsetOperand())->GetOffsetValue() << endl; + LogInfo::MapleLogger() << "rm2 addr: " << static_cast(rm2->GetOffsetOperand())->GetOffsetValue() << endl; + LogInfo::MapleLogger() << "rm4 addr: " << static_cast(rm4->GetOffsetOperand())->GetOffsetValue() << endl; +} + +void Riscv64CGFunc::FreeSpillRegMem(regno_t vrnum) { + MemOperand *memop = nullptr; + + auto vrIt = spillreg_mem_operands.find(vrnum); + if (vrIt != spillreg_mem_operands.end()) { + memop = vrIt->second; + } + + if (!memop && IsVRegNoForPseudoRegister(vrnum)) { + auto p = preg_spill_mem_operands.find(GetPseudoRegIdxFromVirtualRegNo(vrnum)); + if (p != preg_spill_mem_operands.end()) { + memop = p->second; + } + } + + if (!memop) { + CG_ASSERT(false, " free spillreg have no mem"); + return; + } + + uint32 size = memop->GetSize(); + MapleMap::iterator iter; + if ((iter = reusespillloc_mem.find(size)) != reusespillloc_mem.end()) { + iter->second->Add(memop); + } else { + reusespillloc_mem[size] = memPool->New(funcscope_allocator_); + reusespillloc_mem[size]->Add(memop); + } +} + +MemOperand *Riscv64CGFunc::GetOrCreatSpillMem(regno_t vrnum, int32 spillOffset) { + // NOTES: must used in RA, not used in other place + if (spillOffset == 0 && IsVRegNoForPseudoRegister(vrnum)) { + auto p = preg_spill_mem_operands.find(GetPseudoRegIdxFromVirtualRegNo(vrnum)); + if (p != preg_spill_mem_operands.end()) { + return p->second; + } + } + + auto p = spillreg_mem_operands.find(vrnum); + if (p == spillreg_mem_operands.end()) { + CHECK_FATAL(vrnum < v_reg_table.size(), "index out of range in Riscv64CGFunc::FreeSpillRegMem"); + uint32 datasize = v_reg_table[vrnum].GetSize() * BITS_PER_BYTE; + auto it = reusespillloc_mem.find(datasize); + if (spillOffset == 0 && it != reusespillloc_mem.end()) { + MemOperand *memopnd = it->second->GetOne(); + if (memopnd) { + spillreg_mem_operands.insert(pair(vrnum, memopnd)); + return memopnd; + } + } + + RegOperand *baseOpnd = GetOrCreateStackBaseRegOperand(); + int32 offset; + if (spillOffset) { + offset = spillOffset; + } else { + offset = GetOrCreatSpillRegLocation(vrnum); + } + Riscv64OfstOperand *offsetOpnd = memPool->New(offset, 64); + MemOperand *memopnd = memPool->New(datasize, baseOpnd, + static_cast(nullptr), offsetOpnd, nullptr); + spillreg_mem_operands.insert(pair(vrnum, memopnd)); + spillreg_mem_operands_adj.insert(memopnd); + return memopnd; + } else { + return p->second; + } +} + +MemOperand *Riscv64CGFunc::GetPseudoRegisterSpillMemoryOperand(PregIdx i) { + MemOperand *memopnd = nullptr; + MapleMap::iterator p; + if (g->optim_level == 0) { + p = preg_spill_mem_operands.end(); + } else { + p = preg_spill_mem_operands.find(i); + } + if (p == preg_spill_mem_operands.end()) { + int64 offset = GetPseudoRegisterSpillLocation(i); + MIRPreg *preg = func->pregTab->PregFromPregIdx(i); + uint32_t bitlen = GetPrimTypeSize(preg->primType) * BITS_PER_BYTE; + RegOperand *base = GetOrCreateFramePointerRegOperand(); + + Riscv64OfstOperand *offopnd = GetOrCreateOfstOpnd(offset, 32); + memopnd = GetOrCreateMemOpnd(bitlen, base, nullptr, offopnd, nullptr); + if (IsImmediateOffsetOutOfRange(static_cast(memopnd), bitlen)) { + memopnd = SplitOffsetWithAddInstruction(static_cast(memopnd), bitlen); + } + preg_spill_mem_operands.insert(pair(i, memopnd)); + } else { + memopnd = p->second; + } + return memopnd; +} + +/* Get the number of return register of current function. + */ +Riscv64reg_t Riscv64CGFunc::GetReturnRegisterNumber() { + ReturnMechanism retmech(GlobalTables::GetTypeTable().GetTypeFromTyIdx(func->GetReturnTyIdx()), becommon); + if (retmech.regcount > 0) { + return retmech.reg0; + } else { + return kRinvalid; + } +} + +void Riscv64CGFunc::InsertYieldpoint() { + string str = string(NameMangler::kReflectionClassesPrefixStr) + string(NameMangler::kReference) + string(NameMangler::kCinitStr) + + string(NameMangler::kJavaLangObjectStr) + string(NameMangler::kJavaLangRef) + string(NameMangler::kReferenceQueue); + if (strncmp((func->GetName()).c_str(), str.c_str(), strlen(str.c_str())) == 0) { + // skip insert yieldpoint in reference constructor, avoid rc verify issue + CG_ASSERT (yieldPointInsn != nullptr, "the entry yield point has been inserted"); + yieldPointInsn->bb->RemoveInsn(yieldPointInsn); + return; + } + // Converting x31 to x9 for alternate calling convention used in special functions. + for (auto &p : callnativemap) { + Insn *in = p.first; + Riscv64RegOperand *funcreg = GetOrCreatePhysicalRegisterOperand(R9, 64, kRegTyInt); + in->SetOperand(0, funcreg); + } + // do not insert yieldpoint in function that not saved X30 into stack, + // because X30 will be changed after yieldpoint is taken. + if (!hasProEpilogue) { + CG_ASSERT (yieldPointInsn != nullptr, "the entry yield point has been inserted"); + yieldPointInsn->bb->RemoveInsn(yieldPointInsn); + return; + } + // skip if no firstbb. + if (firstbb == nullptr) { + return; + } + // The yield point in the entry of the func is inserted just after the initialization + // of localrefvars in HandleRCCall. + // for BBs after firstbb. + for (BB *bb = firstbb->next; bb != nullptr; bb = bb->next) { + if (g->optim_level >= 2) { + // insert a yieldpoint before the last jump instruction of a goto BB. + if (bb->IsBackEdgeDest()) { + dummybb->ClearInsns(); + GenerateYieldpoint(dummybb); + bb->InsertAtBeginning(dummybb); + continue; + } + } else { + // when -O0, there is no backedge info available. + if (bb->GetKind() == BB::kBBGoto && bb->lastinsn != nullptr && bb->lastinsn->IsBranch()) { + dummybb->ClearInsns(); + GenerateYieldpoint(dummybb); + bb->InsertAtBeginning(dummybb); + continue; + } + // insert yieldpoint for empty loop (CondGoto backward), + // aka. last instruction jump to the top of the BB. + if (bb->lastinsn && bb->lastinsn->IsBranch()) { + // the jump instruction. + Insn *jump = bb->lastinsn; + // skip if no jump target. + if (jump->GetOpndNum() == 0) { + continue; + } + // get the jump target operand. + Operand *op = jump->GetOpnd(jump->GetOpndNum() - 1); + // last operand not found or not a label operand. + if (op == nullptr || !op->IsLabel()) { + continue; + } + // the label operand of the jump instruction. + LabelOperand *label = dynamic_cast(op); + if (label == nullptr || label->GetLabelIndex() != bb->labidx) { + continue; + } + // insert yieldpoint before jump instruction. + dummybb->ClearInsns(); + GenerateYieldpoint(dummybb); + bb->InsertAtBeginning(dummybb); + } + } + } +} + +MemOperand *Riscv64CGFunc::LoadStructCopyBase(MIRSymbol *symbol, int32 offset, int datasize) { + // For struct formals > 16 bytes, this is the pointer to the struct copy. + // Load the base pointer first. + uint32 dataSize = GetPrimTypeSize(PTY_a64); + uint32 dataSizeBits = dataSize * BITS_PER_BYTE; + regno_t vreg = New_V_Reg(kRegTyInt, dataSize); + RegOperand *vreg2 = CreateVirtualRegisterOperand(vreg); + MemOperand *memopnd = GetOrCreateMemOpnd(symbol, 0, dataSizeBits); + curbb->AppendInsn( + cg->BuildInstruction( + PickLdInsn(dataSizeBits, PTY_i64), vreg2, memopnd) + ); + // Create the indirect load mem opnd from the base pointer. + return CreateMemOpnd(vreg2, offset, datasize); +} + +void Riscv64CGFunc::ReplaceLargeStackOffsetImm(Insn *insn) { + CHECK_FATAL(0, "FIX"); +} + +} // namespace maplebe diff --git a/mapleall/maple_be/src/cg/riscv64/riscv64_color_ra.cpp b/mapleall/maple_be/src/cg/riscv64/riscv64_color_ra.cpp new file mode 100644 index 0000000..7fb1be0 --- /dev/null +++ b/mapleall/maple_be/src/cg/riscv64/riscv64_color_ra.cpp @@ -0,0 +1,3486 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#include "riscv64/riscv64_color_ra.h" +#include "riscv64/riscv64_insn.h" +#include "riscv64/riscv64_cg.h" +#include "riscv64/riscv64_ra_opt.h" +#include "mir_lower.h" +#include "cg_assert.h" +#include "securec.h" + +#include +#include +#include +#include +#include "securec.h" + +/* + * Based on concepts from Chow and Hennessey. + * Phases are as follows: + * Prepass to collect local BB information. + * Compute local register allocation demands for global RA. + * Compute live ranges. + * Live ranges LR represented by a vector of size #BBs. + * for each cross bb vreg, a bit is set in the vector. + * Build interference graph with basic block as granularity. + * When intersection of two LRs is not null, they interfere. + * Separate unconstrained and constrained LRs. + * unconstrained - LR with connect edges less than available colors. + * These LR can always be colored. + * constrained - not uncontrained. + * Split LR based on priority cost + * Repetitive adding BB from original LR to new LR until constrained. + * Update all LR the new LR interferes with. + * Color the new LR + * Each LR has a forbidden list, the registers cannot be assigned + * Coalesce move using preferred color first. + * Mark the remaining uncolorable LR after split as spill. + * Local register allocate. + * Emit and insert spills. + */ + +namespace maplebe { + +// for physical regopnd phyOpnd, +// R0->GetRegisterNumber() == 1 +// V0->GetRegisterNumber() == 33 +const uint32 k32 = sizeof(int) * CHAR_BIT; +const uint32 k64 = sizeof(long long) * CHAR_BIT; +const uint32 kCondBrNum = 2; +const uint32 kSwitchCaseNum = 5; +const uint32 kLoopWeight = 10; +const uint32 kMaxParamNum = 8; +const uint32 kNumPregBits = V31 + 1; + +#define GCRA_DUMP CGDEBUGFUNC(cgfunc_) + +void LiveUnit::PrintLiveUnit() const { + LogInfo::MapleLogger() << "[" << bgn << "," << end << "]"; + LogInfo::MapleLogger() << ""; + if (hasCall == false) { + // Too many calls, so only print when there is no call. + LogInfo::MapleLogger() << " nc"; + } + if (needRlod) { + LogInfo::MapleLogger() << " rlod"; + } + if (needRstr) { + LogInfo::MapleLogger() << " rstr"; + } +} + +void GraphColorRegAllocator::PrintLiveUnitMap(const LiveRange *lr) const { + LogInfo::MapleLogger() << "\n\tlu:"; + for (uint32 i = 0; i < cgfunc_->NumBBs(); i++) { + if (IS_BIT_ARR_ELEM_SET(lr->bmember, i)) { + auto lu = lr->luMap.find(i); + if (lu != lr->luMap.end()) { + LogInfo::MapleLogger() << "(" << i << " "; + lu->second->PrintLiveUnit(); + LogInfo::MapleLogger() << ")"; + } + } + } + LogInfo::MapleLogger() << endl; +} + +void GraphColorRegAllocator::PrintLiveRangeConflicts(const LiveRange *lr) const { + LogInfo::MapleLogger() << "\n\tinterfere(" << lr->numBconflicts << "): "; + for (uint32 i = 0; i < regBuckets; i++) { + uint64 chunk = lr->bconflict[i]; + for (uint64 bit = 0; bit < (sizeof(uint64) * CHAR_BIT); bit++) { + if (chunk & (1LL << bit)) { + regno_t newno = i * sizeof(uint64) * CHAR_BIT + bit; + LogInfo::MapleLogger() << newno << ","; + } + } + } + LogInfo::MapleLogger() << "\n"; +} + +void GraphColorRegAllocator::PrintLiveBbBit(const LiveRange *lr) const { + LogInfo::MapleLogger() << "live_bb(" << lr->numBmembers << "): "; + for (uint32 i = 0; i < cgfunc_->NumBBs(); i++) { + if (IS_BIT_ARR_ELEM_SET(lr->bmember, i)) { + LogInfo::MapleLogger() << i << " "; + } + } + LogInfo::MapleLogger() << "\n"; +} + +void GraphColorRegAllocator::PrintLiveRange(const LiveRange *lr, const string str) const { + LogInfo::MapleLogger() << str << "\n"; + + LogInfo::MapleLogger() << "R" << lr->regno; + if (lr->regtype == kRegTyInt) { + LogInfo::MapleLogger() << "(I)"; + } else if (lr->regtype == kRegTyFloat) { + LogInfo::MapleLogger() << "(F)"; + } else { + LogInfo::MapleLogger() << "(U)"; + } + LogInfo::MapleLogger() << "\tnumCall " << lr->numCall; + LogInfo::MapleLogger() << "\tpriority " << lr->priority; + LogInfo::MapleLogger() << "\tforbidden: "; + for (regno_t preg = 0; preg < kNumPregBits; preg++) { + if (lr->forbidden[preg]) { + LogInfo::MapleLogger() << preg << ","; + } + } + LogInfo::MapleLogger() << "\tpregveto: "; + for (regno_t preg = 0; preg < kNumPregBits; preg++) { + if (lr->pregveto[preg]) { + LogInfo::MapleLogger() << preg << ","; + } + } + if (lr->spilled) { + LogInfo::MapleLogger() << " spilled"; + } + if (lr->splitLr) { + LogInfo::MapleLogger() << " split"; + } + LogInfo::MapleLogger() << "\n"; + PrintLiveBbBit(lr); + PrintLiveRangeConflicts(lr); + PrintLiveUnitMap(lr); + if (lr->splitLr) { + PrintLiveRange(lr->splitLr, "===>Split LR"); + } +} + +void GraphColorRegAllocator::PrintLiveRanges() const { + cout << "PrintLiveRanges: size = " << lrVec.size() << endl; + for (uint32_t i = 0; i < lrVec.size(); i++) { + if (lrVec[i] == nullptr || lrVec[i]->regno == 0) { + continue; + } + PrintLiveRange(lrVec[i], ""); + } + LogInfo::MapleLogger() << "\n"; +} + +void GraphColorRegAllocator::PrintLocalRaInfo(const string str) const { + LogInfo::MapleLogger() << str << endl; + for (uint32 id = 0; id < cgfunc_->NumBBs(); id++) { + LocalRaInfo *lraInfo = localRegVec[id]; + if (lraInfo == nullptr) { + continue; + } + LogInfo::MapleLogger() << "bb " << id << " def "; + for (auto it : lraInfo->defCnt) { + LogInfo::MapleLogger() << "[" << it.first << ":" << it.second << "],"; + } + LogInfo::MapleLogger() << "\n"; + LogInfo::MapleLogger() << "use "; + for (auto it : lraInfo->useCnt) { + LogInfo::MapleLogger() << "[" << it.first << ":" << it.second << "],"; + } + LogInfo::MapleLogger() << "\n"; + } +} + +void GraphColorRegAllocator::PrintBbAssignInfo() const { + for (uint32 id = 0; id < sortedBBs.size(); id++) { + uint32 bbid = sortedBBs[id]->id; + BbAssignInfo *bbInfo = bbRegInfo[bbid]; + if (bbInfo == nullptr) { + continue; + } + LogInfo::MapleLogger() << "BBinfo(" << id << ")"; + LogInfo::MapleLogger() << " lra-needed int " << bbInfo->intLocalRegsNeeded; + LogInfo::MapleLogger() << " fp " << bbInfo->fpLocalRegsNeeded; + LogInfo::MapleLogger() << " greg-used "; + for (regno_t regno = 0; regno < kNumPregBits; regno++) { + if (bbInfo->globalsAssigned[regno]) { + LogInfo::MapleLogger() << regno << ","; + } + } + LogInfo::MapleLogger() << "\n"; + } +} + +void GraphColorRegAllocator::CalculatePriority(LiveRange *lr) { +#ifdef RANDOM_PRIORITY + lr->priority = 1 / rand(); + return; +#endif // RANDOM_PRIORITY + float pri = 0.0; + uint32 bbNum = 0; + FOREACH_BB_ARR_ELEM(lr->bmember, bbid) + auto lu = lr->luMap.find(bbid); + BB *bb = bbVec[bbid]; + bbNum++; + uint32 useCnt = lu->second->defNum + lu->second->useNum; + uint32 mult; +#ifdef USE_BB_FREQUENCY + mult = bb->frequency; +#else // USE_BB_FREQUENCY + if (bb->loop) { + mult = (uint32)pow(kLoopWeight, bb->loop->loopLevel); + } else { + mult = 1; + } +#endif // USE_BB_FREQUENCY + pri += useCnt * mult; + END_FOREACH_BB_ARR_ELEM + if (bbNum) { + lr->priority = log(pri) / bbNum; + } else { + lr->priority = 0.0; + } + return; +} + +bool GraphColorRegAllocator::AllPredBBVisited(BB *bb) { + bool isAllPredsVisited = true; + for (MapleList::iterator predIt = bb->preds.begin(); predIt != bb->preds.end(); ++predIt) { + BB *predBb = *predIt; + // See if pred bb is a loop back edge + bool isBackEdge = false; + for (MapleList::iterator loopIt = predBb->loop_succs.begin(); loopIt != predBb->loop_succs.end(); ++loopIt) { + BB *loopBb = *loopIt; + if (loopBb == bb) { + isBackEdge = true; + break; + } + } + if ((isBackEdge == false) && (visitedBBs[predBb->id] == false)) { + isAllPredsVisited = false; + break; + } + } + for (MapleList::iterator predIt = bb->eh_preds.begin(); predIt != bb->eh_preds.end(); ++predIt) { + BB *predBb = *predIt; + bool isBackEdge = false; + for (MapleList::iterator loopIt = predBb->loop_succs.begin(); loopIt != predBb->loop_succs.end(); ++loopIt) { + BB *loopBb = *loopIt; + if (loopBb == bb) { + isBackEdge = true; + break; + } + } + if ((isBackEdge == false) && (visitedBBs[predBb->id] == false)) { + isAllPredsVisited = false; + break; + } + } + return isAllPredsVisited; +} + +// During live interval construction, bb has only one predecessor and/or one +// successor are stright line bb. It can be considered to be a single large bb +// for the purpose of finding live interval. This is to prevent extending live +// interval of registers unnecessarily when interleaving bb from other paths. +BB *GraphColorRegAllocator::MarkStraightLineBBInBFS(BB *bb) { + while (1) { + if (bb->succs.size() == 1 && bb->eh_succs.size() == 0) { + BB *sbb = bb->succs.front(); + if (visitedBBs[sbb->id] == true) { + break; + } + if (sbb->preds.size() == 1 && sbb->eh_preds.size() == 0) { + sortedBBs.push_back(sbb); + visitedBBs[sbb->id] = true; + bb = sbb; + } else { + break; + } + } else { + break; + } + } + return bb; +} + +BB *GraphColorRegAllocator::SearchForStraightLineBBs(BB *bb) { + /* Special case for issue #1863. + * Switch cases containing a simple if(){bbs} break; + * Try to group if and bbs together. + */ + if (bb->succs.size() != kCondBrNum || bb->eh_succs.size() != 0) { + return bb; + } + BB *sbb1 = bb->succs.front(); + BB *sbb2 = bb->succs.back(); + uint32 predSz1 = sbb1->preds.size(); + uint32 predSz2 = sbb2->preds.size(); + BB *candidateBb; + if (predSz1 == 1 && predSz2 > kSwitchCaseNum) { + candidateBb = sbb1; + } else if (predSz2 == 1 && predSz1 > kSwitchCaseNum) { + candidateBb = sbb2; + } else { + return bb; + } + CG_ASSERT(candidateBb->id < visitedBBs.size(), "index out of range in GCRA::SearchForStraightLineBBs"); + if (visitedBBs[candidateBb->id] == true) { + return bb; + } + if (candidateBb->eh_preds.size() != 0) { + return bb; + } + if (candidateBb->succs.size() != 1) { + return bb; + } + + sortedBBs.push_back(candidateBb); + visitedBBs[candidateBb->id] = true; + return MarkStraightLineBBInBFS(candidateBb); +} + +void GraphColorRegAllocator::BFS(BB *curbb) { + std::queue worklist; + worklist.push(curbb); + CG_ASSERT(curbb->id < cgfunc_->NumBBs(), "GCRA::BFS visitedBBs overflow"); + CG_ASSERT(curbb->id < visitedBBs.size(), "index out of range in GCRA::BFS"); + visitedBBs[curbb->id] = true; + do { + BB *bb = worklist.front(); + sortedBBs.push_back(bb); + CG_ASSERT(bb->id < cgfunc_->NumBBs(), "GCRA::BFS visitedBBs overflow"); + visitedBBs[bb->id] = true; + worklist.pop(); + // Look for straight line bb + bb = MarkStraightLineBBInBFS(bb); + // Look for an 'if' followed by some straight-line bb + bb = SearchForStraightLineBBs(bb); + for (MapleList::iterator it = bb->succs.begin(); it != bb->succs.end(); ++it) { + BB *ibb = *it; + // See if there are unvisited predecessor + if (visitedBBs[ibb->id] == false) { + if (AllPredBBVisited(ibb) == true) { + worklist.push(ibb); + CG_ASSERT(ibb->id < cgfunc_->NumBBs(), "GCRA::BFS visitedBBs overflow"); + visitedBBs[ibb->id] = true; + } + } + } + } while (!worklist.empty()); + return; +} + +void GraphColorRegAllocator::PrintBBs() const { + for (uint32_t i = 0; i < sortedBBs.size(); i++) { + LogInfo::MapleLogger() << "\n< === > "; + LogInfo::MapleLogger() << sortedBBs[i]->id; + LogInfo::MapleLogger() << " succs:"; + MapleList succs = sortedBBs[i]->succs; + for (MapleList::iterator it = succs.begin(); it != succs.end(); it++) { + BB *succBb = static_cast(*it); + LogInfo::MapleLogger() << " " << succBb->id; + } + LogInfo::MapleLogger() << " eh_succs:"; + succs = sortedBBs[i]->eh_succs; + for (MapleList::iterator it = succs.begin(); it != succs.end(); it++) { + BB *succBb = static_cast(*it); + LogInfo::MapleLogger() << " " << succBb->id; + } + } + LogInfo::MapleLogger() << "\n"; + return; +} + +void GraphColorRegAllocator::ComputeBlockOrder() { + visitedBBs.clear(); + sortedBBs.clear(); + visitedBBs.resize(cgfunc_->NumBBs()); + for (uint32_t i = 0; i < cgfunc_->NumBBs(); i++) { + visitedBBs[i] = false; + } + BB *cleanupBb = nullptr; + FOR_ALL_BB(bb, cgfunc_) { + bb->internal_flag1 = 0; + if (bb->firststmt == cgfunc_->cleanup_label) { + cleanupBb = bb; + } + } + for (BB *bb = cleanupBb; bb; bb = bb->next) { + bb->internal_flag1 = 1; + } + + bool changed = false; + uint32 sortedCnt = 0; + bool done = false; + do { + if (GCRA_DUMP) { + LogInfo::MapleLogger() << "BFS iteration " << sortedBBs.size() << " " << cgfunc_->NumBBs() << "\n"; + } + changed = false; + FOR_ALL_BB(bb, cgfunc_) { + if (bb->internal_flag1 == 1) { + continue; + } + if (visitedBBs[bb->id] == false) { + changed = true; + if (AllPredBBVisited(bb) == true) { + BFS(bb); + } + } + } + // Make sure there is no infinite loop. + if (sortedCnt == sortedBBs.size()) { + if (done == false) { + done = true; + } else { + LogInfo::MapleLogger() << "Error: GCRA BFS loop " << sortedCnt << " in func " << cgfunc_->GetName() << "\n"; + } + } + sortedCnt = sortedBBs.size(); + } while (changed == true); + + for (BB *bb = cleanupBb; bb; bb = bb->next) { + sortedBBs.push_back(bb); + } + + if (GCRA_DUMP) { + PrintBBs(); + } +} + +uint32 GraphColorRegAllocator::MaxIntPhysRegNum() { + return (R31 - R0); +} + +uint32 GraphColorRegAllocator::MaxFloatPhysRegNum() { + return (V30 - V0); +} + +// ==== int regs ==== +// 0 ZR (zero register) +// 1 RA +// 2 SP +// 3 GP +// 4 TP +// 5 to 7 caller +// 8 FP +// 9 callee +// 10 to 17 parameters caller (10, 11 return values) +// 18 to 27 callee +// 28 to 31 caller +// ==== fp regs ==== +// 0 to 7 caller +// 8 to 9 callee +// 10 to 17 caller (10, 11 return values) +// 18 to 27 callee +// 28 to 31 caller + +void GraphColorRegAllocator::InitFreeRegPool() { + uint32 intNum = 0; + uint32 fpNum = 0; + // int caller + for (uint32 i = R5 - R0; i <= R7 - R0; i++) { + intCallerRegSet.insert(i); + } + intNum += 3; + for (uint32 i = R28 - R0; i <= R31 - R0; i++) { + intCallerRegSet.insert(i); + } + intNum += 4; + // int callee + intCalleeRegSet.insert(R9 - R0); + for (uint32 i = R18 - R0; i <= R27 - R0; i++) { + intCalleeRegSet.insert(i); + } + intNum += 11; + // fp caller + for (uint32 i = V0 - V0; i <= V7 - V0; i++) { + fpCallerRegSet.insert(i); + } + fpNum += 8; +#ifdef RESERVED_REGS + regno_t lastCaller = V30; + fpNum += 3; +#else + regno_t lastCaller = V31; + fpNum += 4; +#endif + for (uint32 i = V28 - V0; i <= lastCaller - V0; i++) { + fpCallerRegSet.insert(i); + } + // fp callee + for (uint32 i = V8 - V0; i <= V9 - V0; i++) { + fpCalleeRegSet.insert(i); + } + for (uint32 i = V18 - V0; i <= V27 - V0; i++) { + fpCalleeRegSet.insert(i); + } + fpNum += 12; + + // Add any physical registers that are not used. + // R10 to R17 for integer, V10-V17 for float + for (uint32 i = R10 - R0; i < (kMaxParamNum + R10 - R0); i++) { + intCallerRegSet.insert(i); + } + intNum += kMaxParamNum; + for (uint32 i = V10 - V0; i <= (kMaxParamNum + V10 - V0); i++) { + fpCallerRegSet.insert(i); + } + fpNum += kMaxParamNum; + + intRegNum = intNum; + fpRegNum = fpNum; +} + +bool GraphColorRegAllocator::IsUnconcernedReg(regno_t regno) { + switch (regno) { + case R0: // ZERO + case R1: // RA + case R2: // SP + case R3: // GP + case R4: // TP + case R8: // FP + return true; + default: + break; + } + + // when yieldpoint is enabled, the RYP(x19) can not be used. + if (cgfunc_->cg->GenYieldpoint() && regno == RYP) { + return true; + } + + return false; +} + +bool GraphColorRegAllocator::IsUnconcernedReg(RegOperand *regOpnd) { + uint32 regno = regOpnd->GetRegisterNumber(); + RegType regtype = regOpnd->GetRegisterType(); + if (regtype == kRegTyCc || regtype == kRegTyVary) { + return true; + } + if (regOpnd->IsConstReg()) { + return true; + } + return IsUnconcernedReg(regno); +} + +// Based on live analysis, the live-in and live-out set determines +// the bit to be set in the LR vector, which is of size #BBs. +// If a vreg is in the live-in and live-out set, it is live in the BB. +// +// Also keep track if a LR crosses a call. If a LR crosses a call, it +// interferes with all caller saved registers. Add all caller registers +// to the LR's forbidden list. +// +// Return true if LR created, else return false. +// +// maybe need extra info: +// Add info for setjmp. +// Add info for defBB, useBB, index in BB for def and use +// Add info for startingBB and endingBB +LiveRange *GraphColorRegAllocator::NewLiveRange() { + LiveRange *lr = cgfunc_->memPool->New(allocator); + + if (bbBuckets == 0) { + bbBuckets = (cgfunc_->NumBBs() / (sizeof(uint64) * CHAR_BIT)) + 1; + } + lr->bmember = cgfunc_->memPool->NewArray(bbBuckets); + memset_s(lr->bmember, bbBuckets * sizeof(uint64), 0, bbBuckets * sizeof(uint64)); + if (regBuckets == 0) { + regBuckets = (cgfunc_->GetMaxRegNum() / (sizeof(uint64) * CHAR_BIT)) + 1; + } + lr->bconflict = cgfunc_->memPool->NewArray(regBuckets); + memset_s(lr->bconflict, regBuckets * sizeof(uint64), 0, regBuckets * sizeof(uint64)); + + lr->pregveto.clear(); + lr->pregveto.resize(kNumPregBits); + lr->forbidden.clear(); + lr->forbidden.resize(kNumPregBits); + + return lr; +} + +// Create local info for LR. return true if reg is not local. +bool GraphColorRegAllocator::CreateLiveRangeHandleLocal(regno_t regno, BB *bb, bool isDef) { + if (FIND_NOT_IN(bb->liveout_regno, regno) && FIND_NOT_IN(bb->livein_regno, regno)) { + // register not in globals for the bb, so it is local. + // Compute local RA info. + LocalRaInfo *lraInfo = localRegVec[bb->id]; + if (lraInfo == nullptr) { + lraInfo = cgfunc_->memPool->New(allocator); + localRegVec[bb->id] = lraInfo; + } + if (isDef) { + // movk is handled by different id for use/def in the same insn. + lraInfo->defCnt[regno]++; + //lraInfo->localPregMask |= (1LL << regno); + } else { + lraInfo->useCnt[regno]++; + //lraInfo->localPregMask |= (1LL << regno); + } + // lr info is useful for lra, so continue lr info + } else if (regno < kMaxRegNum) { + // This is a cross bb physical reg + LocalRaInfo *lraInfo = localRegVec[bb->id]; + if (lraInfo == nullptr) { + lraInfo = cgfunc_->memPool->New(allocator); + localRegVec[bb->id] = lraInfo; + } + //lraInfo->globalPreg.insert(regno); + //lraInfo->globalPregMask |= (1LL << regno); + } else { + return true; + } + return false; +} + +LiveRange *GraphColorRegAllocator::CreateLiveRangeAllocateAndUpdate(regno_t regno, BB *bb, bool isDef, uint32 currId) { + LiveRange *lr; + if (lrVec[regno] == nullptr) { + lr = NewLiveRange(); + lr->regno = regno; + lr->id = currId; + + LiveUnit *lu = cgfunc_->memPool->New(); + lr->luMap[bb->id] = lu; + lu->bgn = lu->end = currId; + if (isDef) { + LogInfo::MapleLogger() << "no use after def for regno:" << regno << endl; + for (auto pregNo : pregLive) { + lr->insertPregveto(pregNo); + } + } + } else { + lr = lrVec[regno]; + + LiveUnit *lu = lr->luMap[bb->id]; + if (lu == nullptr) { + lu = cgfunc_->memPool->New(); + lr->luMap[bb->id] = lu; + lu->bgn = lu->end = currId; + } + if (lu->bgn > currId) { + lu->bgn = currId; + } + if (lu->end < currId) { + lu->end = currId; + } + } + + return lr; +} + +bool GraphColorRegAllocator::CreateLiveRange(regno_t regno, BB *bb, bool isDef, bool isMovk, uint32 currId, + bool updateCount) { + bool isNonLocal = CreateLiveRangeHandleLocal(regno, bb, isDef); + + if (!isDef) { + currId--; + } + + LiveRange *lr = CreateLiveRangeAllocateAndUpdate(regno, bb, isDef, currId); + lr->isNonLocal = isNonLocal; + if (isDef) { + if (isMovk == false) { + vregLive.erase(regno); + } +#ifdef OPTIMIZE_FOR_PROLOG + if (doOptProlog && updateCount) { + if (lr->numDefs == 0) { + lr->frequency += bb->frequency; + } + lr->numDefs++; + } +#endif // OPTIMIZE_FOR_PROLOG + } else { + vregLive.insert(regno); +#ifdef OPTIMIZE_FOR_PROLOG + if (doOptProlog && updateCount) { + if (lr->numUses == 0) { + lr->frequency += bb->frequency; + } + lr->numUses++; + } +#endif // OPTIMIZE_FOR_PROLOG + } + for (auto pregNo : pregLive) { + lr->insertPregveto(pregNo); + } + + // only handle it in live_in and def point? + SET_MEMBER_BIT_ARR_ELEM(lr, bb->id); + + lrVec[regno] = lr; + + return true; +} + +bool GraphColorRegAllocator::SetupLiveRangeByOpHandlePhysicalReg(RegOperand *regOpnd, Insn *insn, regno_t regno, + bool isDef) { + if (regOpnd->IsPhysicalRegister()) { + LocalRaInfo *lraInfo = nullptr; + lraInfo = localRegVec[insn->bb->id]; + if (lraInfo == nullptr) { + lraInfo = cgfunc_->memPool->New(allocator); + localRegVec[insn->bb->id] = lraInfo; + } + + if (isDef) { + pregLive.erase(regno); + + if (lraInfo) { + lraInfo->defCnt[regno] = lraInfo->defCnt[regno] + 1; + } + } else { + pregLive.insert(regno); + for (auto vregno : vregLive) { + if (IsUnconcernedReg(vregno)) { + continue; + } + LiveRange *lr = lrVec[vregno]; + lr->insertPregveto(regno); + } + + if (lraInfo) { + lraInfo->useCnt[regno]++; + } + } + return true; + } + return false; +} + +// add pregs to forbidden list of lr. If preg is in +// the live list, then it is forbidden for other vreg on the list. +// Return kImmediateDelete or kDelayedDelete if insn involved should be deleted. +// if return value is kImmediateDelete, then deletion can be immediate +// if return value is kDelayedDelete, then deletion needs to be done after +// finish processing the instruction. +uint8 GraphColorRegAllocator::SetupLiveRangeByOp(Operand *op, Insn *insn, bool isDef) { + if (!op->IsRegister()) { + return kNoDelete; + } + RegOperand *regOpnd = static_cast(op); + uint32 regno = regOpnd->GetRegisterNumber(); + if (IsUnconcernedReg(regOpnd)) { + if (lrVec[regno]) { + CG_ASSERT(0, "Unconcerned reg"); + lrVec[regno] = nullptr; + } + return kNoDelete; + } + if (SetupLiveRangeByOpHandlePhysicalReg(regOpnd, insn, regno, isDef)) { + return kNoDelete; + } +#ifdef REMOVE_INSN + if (isDef) { + if (lrVec[regno] == nullptr) { + return kImmediateDelete; + } else if (CGOptions::doLiveAnalysisEh && FIND_NOT_IN(vregLive,regno)) { + return kDelayedDelete; + } + } +#endif // REMOVE_INSN + if (CreateLiveRange(regno, insn->bb, isDef, false, insn->id, true)) { + LiveRange *lr = lrVec[regno]; + if (lr->regtype == kRegTyUndef) { + lr->regtype = regOpnd->GetRegisterType(); + } + if (isDef) { + lr->luMap[insn->bb->id]->defNum++; + } else { + lr->luMap[insn->bb->id]->useNum++; + } +#ifdef MOVE_COALESCE + if (insn->GetMachineOpcode() == MOP_xmovrr || insn->GetMachineOpcode() == MOP_wmovrr) { + RegOperand *opnd = static_cast(insn->GetOperand(1)); + if (opnd->GetRegisterNumber() < kMaxRegNum) { + lr->prefs.insert(opnd->GetRegisterNumber() - R0); + } + } +#endif // MOVE_COALESCE + } + return kNoDelete; +} + +// handle live range for bb->live_out +void GraphColorRegAllocator::SetupLiveRangeByRegno(regno_t lout, BB *bb, uint32 currPoint) { + if (IsUnconcernedReg(lout)) { + return; + } + if (lout < kMaxRegNum) { + pregLive.insert(lout); + for (auto vregno : vregLive) { + LiveRange *lr = lrVec[vregno]; + lr->insertPregveto(lout); + + // See if phys reg is livein also. Then assume it span the entire bb. + if (FIND_IN(bb->livein_regno, lout)) { + LocalRaInfo *lraInfo = localRegVec[bb->id]; + if (lraInfo == nullptr) { + lraInfo = cgfunc_->memPool->New(allocator); + localRegVec[bb->id] = lraInfo; + } + // Make it a large enough so no locals can be allocated. + lraInfo->useCnt[lout] = kLargeUint16; + } + } + return; + } + vregLive.insert(lout); + CreateLiveRange(lout, bb, false, false, currPoint, false); + return; +} + +void GraphColorRegAllocator::ComputeLiveRangesForEachOperand(Insn *insn) { + int32 delInsn = -1; + const Riscv64MD *md = &Riscv64CG::kMd[static_cast(insn)->GetMachineOpcode()]; + for (int32_t i = 0; i < Insn::kMaxOperandNum; i++) { + Operand *opnd = insn->GetOperand(i); + if (opnd == nullptr) { + continue; + } + bool isDef = static_cast(md->operand_[i])->IsRegDef(); + if (opnd->IsList()) { + ListOperand *listopnd = static_cast(opnd); + for (auto op : listopnd->GetOperands()) { + SetupLiveRangeByOp(op, insn, isDef); + } + } else if (opnd->IsMemoryAccessOperand()) { + MemOperand *memopnd = static_cast(opnd); + Operand *base = memopnd->GetBaseRegister(); + Operand *offset = memopnd->GetIndexRegister(); + isDef = false; + if (base != nullptr) { + SetupLiveRangeByOp(base, insn, isDef); + } + if (offset != nullptr) { + SetupLiveRangeByOp(offset, insn, isDef); + } + } else { + uint8 del = SetupLiveRangeByOp(opnd, insn, isDef); + /* -1: unknown. + 0: def liveout, cannot delete + 1: possible delete, unless other def is used + */ + if (isDef) { + if (delInsn != 0) { + if (del == kNoDelete) { + delInsn = 0; + } else if (del == kDelayedDelete) { + delInsn = 1; + } else if (del == kImmediateDelete) { + delInsn = 1; + //break; + } + } + } else if (delInsn == 1 && opnd->IsRegister()) { + regno_t vreg = (static_cast(opnd))->GetRegisterNumber(); + if (vreg > kMaxRegNum) { + lrVec[vreg]->luMap[insn->bb->id]->useNum--; + } + LocalRaInfo *lraInfo = localRegVec[insn->bb->id]; + if (lraInfo) { + if (lraInfo->useCnt.find(vreg) != lraInfo->useCnt.end()) { + lraInfo->useCnt[vreg]--; + } + } + } + } + } + if (delInsn == 1) { + if (GCRA_DUMP) { + LogInfo::MapleLogger() << "Remove insn: "; + insn->dump(); + } + insn->bb->RemoveInsn(insn); + } +} + +void GraphColorRegAllocator::ComputeLiveRangesUpdateIfInsnIsCall(Insn *insn) { + if (insn->IsCall()) { + for (auto vregno : vregLive) { + LiveRange *lr = lrVec[vregno]; + lr->numCall++; + + auto lu = lr->luMap.find(insn->bb->id); + if (lu != lr->luMap.end()) { + lu->second->hasCall = true; + } + } + // def the return value + pregLive.erase(R10); + pregLive.erase(V10); + + // active the parametes + Operand *opnd1 = insn->opnds[1]; + if (opnd1->IsList()) { + Riscv64ListOperand *srcopnds = static_cast(opnd1); + for (auto regopnd : srcopnds->GetOperands()) { + CG_ASSERT(!regopnd->IsVirtualRegister(), ""); + Riscv64reg_t physicalReg = (Riscv64reg_t)regopnd->GetRegisterNumber(); + pregLive.insert(physicalReg); + } + } + } +} + +void GraphColorRegAllocator::ComputeLiveRangesUpdateLiveUnitInsnRange(BB *bb, uint32 currPoint) { + for (auto lin : bb->livein_regno) { + if (lin < kMaxRegNum) { + continue; + } + LiveRange *lr = lrVec[lin]; + if (lr == nullptr) { + continue; + } + auto lu = lr->luMap.find(bb->id); + if (bb->firstinsn) { + lu->second->bgn = bb->firstinsn->id; + } else { + // since bb is empty, then use pointer as is + lu->second->bgn = currPoint; + } + lu->second->bgn = lu->second->bgn - 1; + } +} + +void GraphColorRegAllocator::ComputeLiveRangesBmemberSize() { + for (uint32_t i = 0; i < lrVec.size(); i++) { + LiveRange *lr = lrVec[i]; + if (lr == nullptr || lr->regno == 0) { + continue; + } + } +} + +void GraphColorRegAllocator::ComputeLiveOut(BB *bb) { + vregLive.clear(); + pregLive.clear(); + // No loop backedge + for (auto succ : bb->succs) { + if (FIND_IN(bb->loop_succs, succ)) { + continue; + } + for (auto regno : succ->livein_regno) { + if (IsUnconcernedReg(regno)) { + continue; + } + if (regno < kMaxRegNum) { + pregLive.insert(regno); + continue; + } + vregLive.insert(regno); + } + } + for (auto succ : bb->eh_succs) { + if (FIND_IN(bb->loop_succs, succ)) { + continue; + } + for (auto regno : succ->livein_regno) { + if (IsUnconcernedReg(regno)) { + continue; + } + if (regno < kMaxRegNum) { + pregLive.insert(regno); + continue; + } + vregLive.insert(regno); + } + } + // With instruction scheduling, other instructions might be placed between + // definition of return register and return block. Need to preserve return reg. + if (bb->HasCall() == false && bb->succs.size() == 1) { + Riscv64reg_t regno = static_cast(cgfunc_)->GetReturnRegisterNumber(); + if (regno != INVALID_REGNO) { + BB *succBB = bb->succs.front(); + if (succBB->HasReturn()) { + // Prevent local reg allocator using this return register. + SetBbInfoGlobalAssigned(bb->id, regno); + // Create proper live range for global reg allocator. + pregLive.insert(regno); + } + } + } +} + +#define UPDATE_INSN_CNT_AND_SKIP_USELESS(insn) \ + insn->id = currPoint; \ + if (insn->IsImmaterialInsn()) { \ + currPoint--; \ + continue; \ + } \ + if (!insn->IsMachineInstruction()) { \ + currPoint--; \ + continue; \ + } + +// For each succ bb->succs, if bb->liveout - succ->livein is not empty, the vreg(s) is +// dead on this path (but alive on the other path as there is some use of it on the +// other path). This might be useful for optimization of reload placement later for +// splits (lr split into lr1 & lr2 and lr2 will need to reload.) +// Not for now though. +void GraphColorRegAllocator::ComputeLiveRanges() { + bbVec.clear(); + bbVec.resize(cgfunc_->NumBBs()); + + uint32 currPoint = cgfunc_->GetTotalNumberOfInstructions() + sortedBBs.size(); + currPoint *= 2; + for (uint32_t bbIdx = sortedBBs.size(); bbIdx > 0; bbIdx--) { + BB *bb = sortedBBs[bbIdx - 1]; + bbVec[bb->id] = bb; + bb->level = bbIdx - 1; + + ComputeLiveOut(bb); + for (auto lout : bb->liveout_regno) { + SetupLiveRangeByRegno(lout, bb, currPoint); + } + currPoint--; + + FOR_BB_INSNS_REV_SAFE(insn, bb, ninsn) { + UPDATE_INSN_CNT_AND_SKIP_USELESS(insn); + + ComputeLiveRangesForEachOperand(insn); + + ComputeLiveRangesUpdateIfInsnIsCall(insn); + // distinguish use/def + currPoint -= 2; + } + ComputeLiveRangesUpdateLiveUnitInsnRange(bb, currPoint); + // move one more step for each BB + currPoint--; + } + + ComputeLiveRangesBmemberSize(); + + if (GCRA_DUMP) { + LogInfo::MapleLogger() << "After ComputeLiveRanges\n"; + PrintLiveRanges(); +#ifdef USE_LRA + if (doLRA) { + PrintLocalRaInfo("After ComputeLiveRanges"); + } +#endif // USE_LRA + } + return; +} + +#undef UPDATE_INSN_CNT_AND_SKIP_USELESS + +MemOperand *GraphColorRegAllocator::CreateSpillMem(uint32 spillIdx) { + // Create a common stack space for spilling with need_spill + if (spillIdx == 0) { + if (spillMemopnd0 == nullptr) { + regno_t reg = cgfunc_->New_V_Reg(kRegTyInt, sizeof(long long)); + Riscv64CGFunc *a64cgfunc = static_cast(cgfunc_); + spillMemopnd0 = a64cgfunc->GetOrCreatSpillMem(reg); + } + return spillMemopnd0; + } else if (spillIdx == 1) { + if (spillMemopnd1 == nullptr) { + regno_t reg = cgfunc_->New_V_Reg(kRegTyInt, sizeof(long long)); + Riscv64CGFunc *a64cgfunc = static_cast(cgfunc_); + spillMemopnd1 = a64cgfunc->GetOrCreatSpillMem(reg); + } + return spillMemopnd1; + } else if (spillIdx == 2) { + if (spillMemopnd2 == nullptr) { + regno_t reg = cgfunc_->New_V_Reg(kRegTyInt, sizeof(long long)); + Riscv64CGFunc *a64cgfunc = static_cast(cgfunc_); + spillMemopnd2 = a64cgfunc->GetOrCreatSpillMem(reg); + } + return spillMemopnd2; + } + return nullptr; +} + +bool GraphColorRegAllocator::IsLocalReg(regno_t regno) { + LiveRange *lr = lrVec[regno]; + if (lr == nullptr) { + LogInfo::MapleLogger() << "unexpected regno " << regno << endl; + return true; + } + if (lr->splitLr) { + return false; + } else { + return (lr->numBmembers == 1) && (!lr->isNonLocal); + } +} + +bool GraphColorRegAllocator::IsLocalReg(LiveRange *lr) { + if (lr->splitLr) { + return false; + } else { + return (lr->numBmembers == 1) && (!lr->isNonLocal); + } +} + +void GraphColorRegAllocator::CheckInterference(LiveRange *lr1, LiveRange *lr2) { + uint64 bitArr[bbBuckets]; + BIT_ARR_AND(lr1->bmember, lr2->bmember, bitArr, bbBuckets); + uint32 lastBitSet; + uint32 overlapNum = 0; + bool stop = false; + for (uint32 i = 0; i < bbBuckets; i++) { + uint64 val = bitArr[i]; + if (val) { + for (uint32 x = 0; x < (sizeof(uint64) * CHAR_BIT); x++) { + if (val & (1LL << x)) { + overlapNum++; + lastBitSet = i * sizeof(uint64) * CHAR_BIT + x; + if (overlapNum > 1) { + stop = true; + break; + } + } + } + if (stop) { + break; + } + } + } + if (overlapNum == 0) { + // no interference + } else if (overlapNum == 1) { + // bgn and end should be in the bb info (LU) + // Need to rethink this if. + // Under some circumstance, lr->bgn can occur after lr->end. + auto lu1 = lr1->luMap.find(lastBitSet); + auto lu2 = lr2->luMap.find(lastBitSet); + if (lu1 != lr1->luMap.end() && lu2 != lr2->luMap.end() && + !((lu1->second->bgn < lu2->second->bgn && lu1->second->end < lu2->second->bgn) || + (lu2->second->bgn < lu1->second->end && lu2->second->end < lu1->second->bgn))) { + SET_CONFLICT_BIT_ARR_ELEM(lr1, lr2->regno); + SET_CONFLICT_BIT_ARR_ELEM(lr2, lr1->regno); + } + } else { + // interfere + SET_CONFLICT_BIT_ARR_ELEM(lr1, lr2->regno); + SET_CONFLICT_BIT_ARR_ELEM(lr2, lr1->regno); + } + + return; +} + +void GraphColorRegAllocator::BuildInterferenceGraphSeparateIntFp(std::vector &intLrVec, + std::vector &fpLrVec) { + for (uint32_t i = 0; i < lrVec.size(); i++) { + if (lrVec[i] == nullptr || lrVec[i]->regno == 0) { + continue; + } +#ifdef USE_LRA + if (doLRA && lrVec[i]->numBmembers == 1) + { + continue; + } +#endif // USE_LRA + if (lrVec[i]->regtype == kRegTyInt) { + intLrVec.push_back(lrVec[i]); + } else if (lrVec[i]->regtype == kRegTyFloat) { + fpLrVec.push_back(lrVec[i]); + } else { + CG_ASSERT(0, "Illegal regtype in BuildInterferenceGraph"); + LogInfo::MapleLogger() << "error: Illegal regtype in BuildInterferenceGraph\n"; + } + } +} + +// Based on intersection of LRs. When two LRs interfere, add to each other's +// interference list. +void GraphColorRegAllocator::BuildInterferenceGraph() { + std::vector intLrVec; + std::vector fpLrVec; + BuildInterferenceGraphSeparateIntFp(intLrVec, fpLrVec); + + std::vector::iterator it1, it2; + for (it1 = intLrVec.begin(); it1 != intLrVec.end(); it1++) { + LiveRange *lr1 = *it1; + CalculatePriority(lr1); + for (it2 = it1 + 1; it2 != intLrVec.end(); it2++) { + LiveRange *lr2 = *it2; + if (lr1->regno < lr2->regno) { + CheckInterference(lr1, lr2); + } + } + } + + for (it1 = fpLrVec.begin(); it1 != fpLrVec.end(); it1++) { + LiveRange *lr1 = *it1; + CalculatePriority(lr1); + for (it2 = it1 + 1; it2 != fpLrVec.end(); it2++) { + LiveRange *lr2 = *it2; + if (lr1->regno < lr2->regno) { + CheckInterference(lr1, lr2); + } + } + } + + if (GCRA_DUMP) { + LogInfo::MapleLogger() << "After BuildInterferenceGraph\n"; + PrintLiveRanges(); + } + + return; +} + +void GraphColorRegAllocator::SetBbInfoGlobalAssigned(uint32 bbid, regno_t regno) { + BbAssignInfo *bbInfo = bbRegInfo[bbid]; + if (bbInfo == nullptr) { + bbInfo = cgfunc_->memPool->New(allocator); + bbRegInfo[bbid] = bbInfo; + bbInfo->globalsAssigned.clear(); + bbInfo->globalsAssigned.resize(kNumPregBits); + } + bbInfo->insertGlobalsAssigned(regno); +} + +bool GraphColorRegAllocator::HaveAvailableColor(LiveRange *lr, uint32 num) { + return ((lr->regtype == kRegTyInt && num < intRegNum) || (lr->regtype == kRegTyFloat && num < fpRegNum)); +} + +// If the members on the interference list is less than #colors, then +// it can be trivially assigned a register. Otherwise it is constrained. +// Separate the LR based on if it is contrained or not. +// +// The unconstrained LRs are colored last. +// +// Compute a sorted list of constrained LRs based on priority cost. +void GraphColorRegAllocator::Separate() { + for (auto lr : lrVec) { + if (lr == nullptr) { + continue; + } +#ifdef USE_LRA + if (doLRA && IsLocalReg(lr)) { + continue; + } +#endif // USE_LRA +#ifdef OPTIMIZE_FOR_PROLOG + if (doOptProlog && + (lr->numDefs <= 1 && lr->numUses <= 1 && lr->numCall > 0) && + (lr->frequency <= (cgfunc_->firstbb->frequency << 1))) { + if (lr->regtype == kRegTyInt) { + intDelayed.push_back(lr); + } else { + fpDelayed.push_back(lr); + } + continue; + } +#endif // OPTIMIZE_FOR_PROLOG + if (HaveAvailableColor(lr, lr->numBconflicts + lr->numPregveto + lr->numForbidden)) + { + unconstrained.push_back(lr); + } else { + constrained.push_back(lr); + } + } + if (GCRA_DUMP) { + LogInfo::MapleLogger() << "Unconstrained : "; + for (auto lr : unconstrained) { + LogInfo::MapleLogger() << lr->regno << " "; + } + LogInfo::MapleLogger() << "\n"; + LogInfo::MapleLogger() << "Constrained : "; + for (auto lr : constrained) { + LogInfo::MapleLogger() << lr->regno << " "; + } + LogInfo::MapleLogger() << "\n"; + } +} + +MapleVector::iterator GraphColorRegAllocator::GetHighPriorityLr(MapleVector &lrSet) { + MapleVector::iterator it = lrSet.begin(); + MapleVector::iterator highestIt = it; + LiveRange *startLr = *it; + float maxPrio = startLr->priority; + it++; + for (; it != lrSet.end(); it++) { + LiveRange *lr = *it; + if (lr->priority > maxPrio) { + maxPrio = lr->priority; + highestIt = it; + } + } + return highestIt; +} + +void GraphColorRegAllocator::UpdateForbiddenForNeighbors(LiveRange *lr) { + FOREACH_REG_ARR_ELEM(lr->bconflict, regno) + LiveRange *newLr = lrVec[regno]; + if (newLr->pregveto[lr->assigned] == false) { + newLr->insertForbidden(lr->assigned); + } + END_FOREACH_REG_ARR_ELEM + return; +} + +void GraphColorRegAllocator::UpdatePregvetoForNeighbors(LiveRange *lr) { + FOREACH_REG_ARR_ELEM(lr->bconflict, regno) + LiveRange *newLr = lrVec[regno]; + newLr->insertPregveto(lr->assigned); + END_FOREACH_REG_ARR_ELEM + return; +} + +// For cases with only one def/use and crosses a call. +// It might be more beneficial to spill vs save/restore in prolog/epilog. +// But if the callee register is already used, then it is ok to reuse it again. +// Or in certain cases, just use the callee. +bool GraphColorRegAllocator::ShouldUseCallee(LiveRange *lr, MapleSet &calleeUsed, + MapleVector &delayed) { + if (FIND_IN(calleeUsed, lr->assigned)) { + return true; + } else if (Riscv64Abi::IsCalleeSavedReg((Riscv64reg_t)(lr->assigned)) && calleeUsed.size() % 2 != 0) { + return true; + } else if (delayed.size() > 1 && calleeUsed.size() == 0) { + // If there are more than 1 vreg that can benefit from callee, use callee + return true; + } else { + lr->assigned = 0; + return false; + } +} + +regno_t GraphColorRegAllocator::FindColorForLr(LiveRange *lr) { + regno_t base; + regno_t reg = 0; + RegType regtype = lr->regtype; + MapleSet *currRegSet; + MapleSet *nextRegSet; + if (regtype == kRegTyInt) { + if (lr->numCall != 0) { + currRegSet = intCalleeRegSet.size() ? &intCalleeRegSet : &intCallerRegSet; + nextRegSet = intCallerRegSet.size() ? &intCallerRegSet : &intCalleeRegSet; + } else { + currRegSet = intCallerRegSet.size() ? &intCallerRegSet : &intCalleeRegSet; + nextRegSet = intCalleeRegSet.size() ? &intCalleeRegSet : &intCallerRegSet; + } + base = R0; + } else { + if (lr->numCall != 0) { + currRegSet = fpCalleeRegSet.size() ? &fpCalleeRegSet : &fpCallerRegSet; + nextRegSet = fpCallerRegSet.size() ? &fpCallerRegSet : &fpCalleeRegSet; + } else { + currRegSet = fpCallerRegSet.size() ? &fpCallerRegSet : &fpCalleeRegSet; + nextRegSet = fpCalleeRegSet.size() ? &fpCalleeRegSet : &fpCallerRegSet; + } + base = V0; + } +#ifdef MOVE_COALESCE + for (auto it : lr->prefs) { + reg = it + base; + if ((FIND_IN(*currRegSet, reg) || FIND_IN(*nextRegSet, reg)) && (lr->forbidden[reg] == false) && + lr->pregveto[reg] == false) { + return reg; + } + } +#endif // MOVE_COALESCE + + for (auto it = currRegSet->begin(); it != currRegSet->end(); it++) { + reg = *it + base; + if ((lr->forbidden[reg] == false) && lr->pregveto[reg] == false) { + return reg; + } + } + // Failed to allocate in first choice. Try 2nd choice. + for (auto it = nextRegSet->begin(); it != nextRegSet->end(); it++) { + reg = *it + base; + if ((lr->forbidden[reg] == false) && lr->pregveto[reg] == false) { + return reg; + } + } + //CG_ASSERT(0, "Failed to find a register"); + + return 0; +} + +// If forbidden list has more registers than max of all BB's local reg +// requirement, then LR can be colored. +// Update LR's color if success, return true, else return false. +bool GraphColorRegAllocator::AssignColorToLr(LiveRange *lr, bool isDelayed) { + if (lr->assigned > 0) { + // Already assigned. + return true; + } + if (HaveAvailableColor(lr, lr->numForbidden + lr->numPregveto)) { + lr->assigned = FindColorForLr(lr); + if (lr->assigned == 0) { + return false; + } +#ifdef OPTIMIZE_FOR_PROLOG + if (doOptProlog && isDelayed) { + if (lr->regtype == kRegTyInt) { + if (!ShouldUseCallee(lr, intCalleeUsed, intDelayed)) { + return false; + } + } else { + if (!ShouldUseCallee(lr, fpCalleeUsed, fpDelayed)) { + return false; + } + } + } +#endif // OPTIMIZE_FOR_PROLOG + + bool isCalleeReg = Riscv64Abi::IsCalleeSavedReg((Riscv64reg_t)(lr->assigned)); + if (isCalleeReg) { + if (lr->regtype == kRegTyInt) { + intCalleeUsed.insert((lr->assigned)); + } else { + fpCalleeUsed.insert((lr->assigned)); + } + } + + UpdateForbiddenForNeighbors(lr); + + FOREACH_BB_ARR_ELEM(lr->bmember, bbid) + SetBbInfoGlobalAssigned(bbid, lr->assigned); + END_FOREACH_BB_ARR_ELEM + if (GCRA_DUMP) { + LogInfo::MapleLogger() << "assigned " << lr->assigned << " to R" << lr->regno << endl; + } + return true; + } + return false; +} + +void GraphColorRegAllocator::PruneLrForSplit(LiveRange *lr, BB *bb, bool remove, set &candidateInLoop, + set &defInLoop) { + if (bb->internal_flag1) { + // already visited + return; + } + + bb->internal_flag1 = true; + auto lu = lr->luMap.find(bb->id); + uint32 defNum = 0; + uint32 useNum = 0; + if (lu != lr->luMap.end()) { + defNum = lu->second->defNum; + useNum = lu->second->useNum; + } + + if (remove) { + // In removal mode, has not encountered a ref yet. + if (defNum == 0 && useNum == 0) { + if (bb->loop && FIND_IN(candidateInLoop, bb->loop)) { + // Upward search has found a loop. Regardless of def/use + // The loop members must be included in the new LR. + remove = false; + } else { + // No ref in this bb. mark as potential remove. + bb->internal_flag2 = true; + } + } else { + // found a ref, no more removal of bb and preds. + remove = false; + } + } + + // With a def in loop, cannot prune that loop + if (bb->loop && defNum > 0) { + defInLoop.insert(bb->loop); + } + + if (remove == false) { + if (bb->loop) { + // bb in loop, need to make sure of loop carried dependency + candidateInLoop.insert(bb->loop); + } + for (auto pred : bb->preds) { + if (FIND_NOT_IN(bb->loop_preds, pred)) { + PruneLrForSplit(lr, pred, remove, candidateInLoop, defInLoop); + } + } + for (auto pred : bb->eh_preds) { + if (FIND_NOT_IN(bb->loop_preds, pred)) { + PruneLrForSplit(lr, pred, remove, candidateInLoop, defInLoop); + } + } + } +} + +void GraphColorRegAllocator::FindBbSharedInSplit(LiveRange *lr, set &candidateInLoop, + set &defInLoop) { + // A loop might be split into two. Need to see over the entire LR if there is a def in the loop. + FOREACH_BB_ARR_ELEM(lr->bmember, bbid) + BB *bb = bbVec[bbid]; + if (bb->loop && FIND_IN(candidateInLoop, bb->loop)) { + auto lu = lr->luMap.find(bb->id); + if (lu != lr->luMap.end() && lu->second->defNum > 0) { + defInLoop.insert(bb->loop); + } + } + END_FOREACH_BB_ARR_ELEM +} + +// Backward traversal of the top part of the split LR. +// Prune the part of the LR that has no downward exposing references. +// Take into account of loops and loop carried dependencies. +// The candidate bb to be removed, if in a loop, store that info. +// If a LR crosses a loop, even if the loop has no def/use, it must +// be included in the new LR. +void GraphColorRegAllocator::ComputeBbForNewSplit(LiveRange *newLr, LiveRange *origLr) { + // The candidate bb to be removed, if in a loop, store that info. + // If a LR crosses a loop, even if the loop has no def/use, it must + // be included in the new LR. + set candidateInLoop; + // If a bb has a def and is in a loop, store that info. + set defInLoop; + set smember; + FOREACH_BB_ARR_ELEM(newLr->bmember, bbid) + smember.insert(bbVec[bbid]); + END_FOREACH_BB_ARR_ELEM + for (auto bbit = smember.rbegin(); bbit != smember.rend(); bbit++) + { + BB *bb = *bbit; + if (bb->internal_flag1) { + continue; + } + PruneLrForSplit(newLr, bb, true, candidateInLoop, defInLoop); + } + FindBbSharedInSplit(origLr, candidateInLoop, defInLoop); + FOREACH_BB_ARR_ELEM(newLr->bmember, bbid) // prune the top LR. + BB *bb = bbVec[bbid]; + if (bb->internal_flag2) { + if (FIND_IN(candidateInLoop, bb->loop)) { + continue; + } + if (FIND_NOT_IN(defInLoop, bb->loop)) { // defInLoop should be a subset of candidateInLoop. remove. + UNSET_MEMBER_BIT_ARR_ELEM(newLr, bbid); + } + } + END_FOREACH_BB_ARR_ELEM +} + +bool GraphColorRegAllocator::UseIsUncovered(BB *bb, BB *startBb) { + for (auto pred : bb->preds) { + if (pred->level <= startBb->level) { + return true; + } + if (UseIsUncovered(pred, startBb)) { + return true; + } + } + for (auto pred : bb->eh_preds) { + if (pred->level <= startBb->level) { + return true; + } + if (UseIsUncovered(pred, startBb)) { + return true; + } + } + return false; +} + +void GraphColorRegAllocator::FindUseForSplit(LiveRange *lr, SplitBbInfo &bbInfo, bool &remove, + set &candidateInLoop, set &defInLoop) { + BB *bb = bbInfo.GetCandidateBb(); + BB *startBb = bbInfo.GetStartBb(); + if (bb->internal_flag1) { + // already visited + return; + } + for (auto pred : bb->preds) { + if (pred->internal_flag1 == false) { + return; + } + } + for (auto pred : bb->eh_preds) { + if (pred->internal_flag1 == false) { + return; + } + } + + bb->internal_flag1 = true; + auto lu = lr->luMap.find(bb->id); + uint32 defNum = 0; + uint32 useNum = 0; + if (lu != lr->luMap.end()) { + defNum = lu->second->defNum; + useNum = lu->second->useNum; + } + + if (remove) { + // In removal mode, has not encountered a ref yet. + if (defNum == 0 && useNum == 0) { + // No ref in this bb. mark as potential remove. + bb->internal_flag2 = true; + if (bb->loop) { + // bb in loop, need to make sure of loop carried dependency + candidateInLoop.insert(bb->loop); + } + } else { + // found a ref, no more removal of bb and preds. + remove = false; + // A potential point for a upward exposing use. (might be a def). + lu->second->needRlod = true; + } + } else if ((defNum > 0 || useNum > 0) && UseIsUncovered(bb, startBb)) { + lu->second->needRlod = true; + } + + // With a def in loop, cannot prune that loop + if (bb->loop && defNum > 0) { + defInLoop.insert(bb->loop); + } + + for (auto succ : bb->succs) { + if (FIND_NOT_IN(bb->loop_succs, succ)) { + bbInfo.SetCandidateBb(succ); + FindUseForSplit(lr, bbInfo, remove, candidateInLoop, defInLoop); + } + } + for (auto succ : bb->eh_succs) { + if (FIND_NOT_IN(bb->loop_succs, succ)) { + bbInfo.SetCandidateBb(succ); + FindUseForSplit(lr, bbInfo, remove, candidateInLoop, defInLoop); + } + } +} + +void GraphColorRegAllocator::ClearLrBbFlags(set &member) { + for (auto bb : member) { + bb->internal_flag1 = false; + bb->internal_flag2 = false; + for (auto pred : bb->preds) { + pred->internal_flag1 = false; + pred->internal_flag2 = false; + } + for (auto pred : bb->eh_preds) { + pred->internal_flag1 = false; + pred->internal_flag2 = false; + } + } +} + +// Downward traversal of the bottom part of the split LR. +// Prune the part of the LR that has no upward exposing references. +// Take into account of loops and loop carried dependencies. +void GraphColorRegAllocator::ComputeBbForOldSplit(LiveRange *newLr, LiveRange *origLr) { + // The candidate bb to be removed, if in a loop, store that info. + set candidateInLoop; + // If a bb has a def and is in a loop, store that info. + set defInLoop; + SplitBbInfo bbInfo; + bool remove = true; + + set smember; + FOREACH_BB_ARR_ELEM(origLr->bmember, bbid) + smember.insert(bbVec[bbid]); + END_FOREACH_BB_ARR_ELEM + ClearLrBbFlags(smember); + for (auto bb : smember) + { + if (bb->internal_flag1) { + continue; + } + for (auto pred : bb->preds) { + pred->internal_flag1 = true; + } + for (auto pred : bb->eh_preds) { + pred->internal_flag1 = true; + } + bbInfo.SetCandidateBb(bb); + bbInfo.SetStartBb(bb); + FindUseForSplit(origLr, bbInfo, remove, candidateInLoop, defInLoop); + } + FindBbSharedInSplit(newLr, candidateInLoop, defInLoop); + FOREACH_BB_ARR_ELEM(origLr->bmember, bbid) + BB *bb = bbVec[bbid]; + if (bb->internal_flag2) { + if (FIND_NOT_IN(defInLoop, bb->loop)) { + UNSET_MEMBER_BIT_ARR_ELEM(origLr, bbid); + } + } + END_FOREACH_BB_ARR_ELEM +} + +// There is at least one available color for this BB from the neighbors +// minus the ones reserved for local allocation. +// bbAdded : The new BB to be added into the split LR if color is available. +// conflictRegs : Reprent the LR before adding the bbAdded. These are the +// forbidden regs before adding the new BBs. +// Side effect : Adding the new forbidden regs from bbAdded into +// conflictRegs if the LR can still be colored. +bool GraphColorRegAllocator::LrCanBeColored(LiveRange *lr, BB *bbAdded, set &conflictRegs) { + RegType type = lr->regtype; + + set newConflict; + FOREACH_REG_ARR_ELEM(lr->bconflict, regno) + // check the real conflict in current bb + LiveRange *conflictLr = lrVec[regno]; + // If the bb to be added to the new LR has an actual + // conflict with another LR, and if that LR has already + // assigned a color that is not in the conflictRegs, + // then add it as a newConflict. + if (IS_BIT_ARR_ELEM_SET(conflictLr->bmember, bbAdded->id)) { + regno_t confReg = conflictLr->assigned; + if ((confReg > 0) && FIND_NOT_IN(conflictRegs, confReg) && lr->pregveto[confReg] == false) { + newConflict.insert(confReg); + } + } else if (conflictLr->splitLr && IS_BIT_ARR_ELEM_SET(conflictLr->splitLr->bmember, bbAdded->id)) { + // The after split LR is split into pieces, and this ensures + // the after split color is taken into consideration. + regno_t confReg = conflictLr->splitLr->assigned; + if ((confReg > 0) && FIND_NOT_IN(conflictRegs, confReg) && lr->pregveto[confReg] == false) { + newConflict.insert(confReg); + } + } + END_FOREACH_REG_ARR_ELEM + + uint32 numRegs; + numRegs = newConflict.size() + lr->numPregveto + conflictRegs.size(); + + bool canColor = false; + if (type == kRegTyInt) { + if (numRegs < intRegNum) { + canColor = true; + } + } else if (numRegs < fpRegNum) { + canColor = true; + } + + if (canColor) { + for (auto regno : newConflict) { + conflictRegs.insert(regno); + } + } + + // Update all the registers conflicting when adding thew new bb. + return canColor; +} + +// Support function for LR split. Move one BB from LR1 to LR2. +void GraphColorRegAllocator::MoveLrBbInfo(LiveRange *oldLr, LiveRange *newLr, BB *bb) { + // initialize backward traversal flag for the bb pruning phase + bb->internal_flag1 = false; + // initialize bb removal marker + bb->internal_flag2 = false; + // Insert BB into new LR + SET_MEMBER_BIT_ARR_ELEM(newLr, bb->id); + + // Move LU from old LR to new LR + auto luIt = oldLr->luMap.find(bb->id); + if (luIt != oldLr->luMap.end()) { + newLr->luMap[luIt->first] = luIt->second; + oldLr->luMap.erase(luIt); + } + + // Remove BB from old LR + UNSET_MEMBER_BIT_ARR_ELEM(oldLr, bb->id); +} + +// Is the set of loops inside the loop? +bool GraphColorRegAllocator::ContainsLoop(CgfuncLoops *loop, set &loops) { + for (auto lp : loops) { + while (lp) { + if (lp == loop) { + return true; + } + lp = lp->outer_loop; + } + } + return false; +} + +void GraphColorRegAllocator::GetAllLrMemberLoops(LiveRange *lr, set &loops) { + FOREACH_BB_ARR_ELEM(lr->bmember, bbid) + BB *bb = bbVec[bbid]; + CgfuncLoops *loop = bb->loop; + if (loop) { + loops.insert(loop); + } + END_FOREACH_BB_ARR_ELEM +} + +bool GraphColorRegAllocator::SplitLrShouldSplit(LiveRange *lr) { + if (lr->splitLr || lr->numBmembers == 1) + { + return false; + } + + // Need to split within the same hierarchy + int32 loopId = -1; + FOREACH_BB_ARR_ELEM(lr->bmember, bbid) + BB *bb = bbVec[bbid]; + if (loopId == -1) { + if (bb->loop) { + loopId = bb->loop->header->id; + } else { + loopId = 0; + } + } else { + if ((bb->loop && bb->loop->header->id != loopId) || (bb->loop == nullptr && loopId != 0)) { + return false; + } + } + END_FOREACH_BB_ARR_ELEM + return true; +} + +bool GraphColorRegAllocator::SplitLrIsProfitable(LiveRange *newLr) { + if (newLr->numBmembers == 0) + { + // split fail + return false; + } + bool hasUse = false; + FOREACH_BB_ARR_ELEM(newLr->bmember, bbid) { + auto lu = newLr->luMap.find(bbid); + if (lu->second->useNum > 0) { + hasUse = true; + break; + } + } + END_FOREACH_BB_ARR_ELEM + return hasUse; +} + +void GraphColorRegAllocator::ResetSplitLr(LiveRange *origLr, LiveRange *newLr) { + FOREACH_BB_ARR_ELEM(newLr->bmember, bbid) { + UNSET_MEMBER_BIT_ARR_ELEM(newLr, bbid); + SET_MEMBER_BIT_ARR_ELEM(origLr, bbid); + + auto luIt = newLr->luMap.find(bbid); + if (luIt != newLr->luMap.end()) { + origLr->luMap[luIt->first] = luIt->second; + newLr->luMap.erase(luIt); + } + } + END_FOREACH_BB_ARR_ELEM +} + +// When a BB in the LR has no def or use in it, then potentially +// there is no conflict within these BB for the new LR, since +// the new LR will need to spill the defs which terminates the +// new LR unless there is a use later which extends the new LR. +// There is no need to compute conflicting register set unless +// there is a def or use. +// It is assumed that the new LR is extended to the def or use. +// Initially newLr is empty, then add bb if can be colored. +// Return true if there is a split. +bool GraphColorRegAllocator::SplitLrFindCandidateLr(LiveRange *lr, LiveRange *newLr, set &conflictRegs) { + if (GCRA_DUMP) { + LogInfo::MapleLogger() << "start split lr for vreg " << lr->regno << endl; + } + set smember; + FOREACH_BB_ARR_ELEM(lr->bmember, bbid) + smember.insert(bbVec[bbid]); + END_FOREACH_BB_ARR_ELEM + for (auto bb : smember) + { + if (LrCanBeColored(lr, bb, conflictRegs)) { + MoveLrBbInfo(lr, newLr, bb); + } else { + break; + } + } + + if (SplitLrIsProfitable(newLr)) { + if (GCRA_DUMP) { + LogInfo::MapleLogger() << "Split:" << lr->regno << endl; + } + return true; + } else { + ResetSplitLr(lr, newLr); + if (GCRA_DUMP) { + LogInfo::MapleLogger() << "ResetSplit:" << lr->regno << endl; + } + return false; + } +} + +void GraphColorRegAllocator::SplitLrHandleLoops(LiveRange *lr, LiveRange *newLr, set &origLoops, + set &newLoops) { + // bb in loops might need a reload due to loop carried dependency. + // Compute this before pruning the LRs. + // if there is no re-definition, then reload is not necessary. + + // Part of the new LR region after the last reference is + // no longer in the LR. Remove those bb. + ComputeBbForNewSplit(newLr, lr); + // With new LR, recompute conflict. + FOREACH_BB_ARR_ELEM(newLr->bmember, bbid) + FOREACH_REG_ARR_ELEM(lr->bconflict, regno) + LiveRange *conf_lr = lrVec[regno]; + if (IS_BIT_ARR_ELEM_SET(conf_lr->bmember, bbid)) { + // New LR getting the interference does not mean the + // old LR can remove the interference. + // Old LR's interference will be handled at the end of split. + SET_CONFLICT_BIT_ARR_ELEM(newLr, regno); + } else if (conf_lr->splitLr && IS_BIT_ARR_ELEM_SET(conf_lr->splitLr->bmember, bbid)) { + SET_CONFLICT_BIT_ARR_ELEM(newLr, regno); + } + END_FOREACH_REG_ARR_ELEM + END_FOREACH_BB_ARR_ELEM + // update bb/loop same as for new LR. + ComputeBbForOldSplit(newLr, lr); + // Update the conflict interference for the original LR later. + + for (auto loop : newLoops) { + if (ContainsLoop(loop, origLoops)) { + for (auto bb : loop->loop_members) { + if (IS_BIT_ARR_ELEM_SET(newLr->bmember, bb->id)) + { + LiveUnit *lu = newLr->luMap[bb->id]; + if (lu->useNum != 0) { + lu->needRlod = true; + } + } + } + } + } +} + +void GraphColorRegAllocator::SplitLrFixNewLrCallsAndRlod(LiveRange *newLr, set &origLoops) { + // If a 2nd split loop is before the bb in 1st split bb. + newLr->numCall = 0; + FOREACH_BB_ARR_ELEM(newLr->bmember, bbid) + BB *bb = bbVec[bbid]; + for (auto loop : origLoops) { + if (loop->header->level < bb->level) { + LiveUnit *lu = newLr->luMap[bbid]; + if (lu->useNum != 0) { + lu->needRlod = true; + } + } + } + LiveUnit *lu = newLr->luMap[bbid]; + if (newLr->numBmembers > 1 && lu->hasCall) { + newLr->numCall++; + } + END_FOREACH_BB_ARR_ELEM +} + +void GraphColorRegAllocator::SplitLrFixOrigLrCalls(LiveRange *lr) { + lr->numCall = 0; + if (lr->numBmembers > 1) { + FOREACH_BB_ARR_ELEM(lr->bmember, bbid) + LiveUnit *lu = lr->luMap[bbid]; + if (lu->hasCall) { + lr->numCall++; + } + END_FOREACH_BB_ARR_ELEM + } +} + +void GraphColorRegAllocator::SplitLrUpdateInterference(LiveRange *lr) { + // newLr is now a separate LR from the original lr. + // Update the interference info. + // Also recompute the forbidden info + lr->forbidden.clear(); + FOREACH_REG_ARR_ELEM(lr->bconflict, regno) + LiveRange *conf_lr = lrVec[regno]; + if (SET_BB_OVERLAP(lr->bmember, conf_lr->bmember)) { + // interfere + if (conf_lr->assigned && lr->pregveto[conf_lr->assigned] == false) { + lr->insertForbidden(conf_lr->assigned); + } + } else { + // no interference + UNSET_CONFLICT_BIT_ARR_ELEM(lr, regno); + } + END_FOREACH_REG_ARR_ELEM +} + +void GraphColorRegAllocator::SplitLrUpdateRegInfo(LiveRange *origLr, LiveRange *newLr, set &conflictRegs) { + for (regno_t regno = 0; regno < kNumPregBits; regno++) { + if (origLr->pregveto[regno]) { + newLr->insertPregveto(regno); + } + } + for (auto regno : conflictRegs) { + if (newLr->pregveto[regno] == false) { + newLr->insertForbidden(regno); + } + } +} + +void GraphColorRegAllocator::SplitLrErrorCheckAndDebug(LiveRange *origLr, LiveRange *newLr) { + if (origLr->numBmembers == 0) { + CG_ASSERT(origLr->numBconflicts == 0, "Error: member and conflict not match"); + } + + if (GCRA_DUMP) { + LogInfo::MapleLogger() << "----->newLr->assigned " << newLr->assigned << endl; + PrintLiveRange(origLr, "LRs after split"); + } +} + +// Pick a starting BB, then expand to maximize the new LR. +// Return the new LR. +LiveRange *GraphColorRegAllocator::SplitLr(LiveRange *lr) { + if (SplitLrShouldSplit(lr) == false) { + return nullptr; + } + LiveRange *newLr = NewLiveRange(); + // For the new LR, whenever a BB with either a def or + // use is added, then add the registers that the neighbor + // is using to the conflict register set indicating that these + // registers cannot be used for the new LR's color. + set conflictRegs; + if (SplitLrFindCandidateLr(lr, newLr, conflictRegs) == false) { + return nullptr; + } +#ifdef REUSE_SPILLMEM + // Copy the original conflict vector for spill reuse optimization + lr->oldConflict = cgfunc_->memPool->NewArray(regBuckets); + COPY_BIT_ARR_ELEM(lr->oldConflict, lr->bconflict, regBuckets); +#endif // REUSE_SPILLMEM + + set newLoops; + set origLoops; + GetAllLrMemberLoops(newLr, newLoops); + GetAllLrMemberLoops(lr, origLoops); + SplitLrHandleLoops(lr, newLr, origLoops, newLoops); + SplitLrFixNewLrCallsAndRlod(newLr, origLoops); + SplitLrFixOrigLrCalls(lr); + + SplitLrUpdateRegInfo(lr, newLr, conflictRegs); + + CalculatePriority(lr); + // At this point, newLr should be unconstrained. + + lr->splitLr = newLr; + + newLr->regno = lr->regno; + newLr->regtype = lr->regtype; + newLr->id = lr->id; + CalculatePriority(newLr); + SplitLrUpdateInterference(lr); + newLr->assigned = FindColorForLr(newLr); + + // For the new LR, update assignment for local RA + FOREACH_BB_ARR_ELEM(newLr->bmember, bbid) + SetBbInfoGlobalAssigned(bbid, newLr->assigned); + END_FOREACH_BB_ARR_ELEM + + UpdatePregvetoForNeighbors(newLr); + + SplitLrErrorCheckAndDebug(lr, newLr); + return newLr; +} + +void GraphColorRegAllocator::ColorForOptPrologEpilog() { +#ifdef OPTIMIZE_FOR_PROLOG + if (doOptProlog) { + for (auto lr : intDelayed) { + if (AssignColorToLr(lr, true)) { + continue; + } else { + lr->spilled = true; + } + } + for (auto lr : fpDelayed) { + if (AssignColorToLr(lr, true)) { + continue; + } else { + lr->spilled = true; + } + } + } +#endif + return; +} + +// From the sorted list of constrained LRs, pick the most profitable LR. +// Split the LR into LRnew1 LRnew2 where LRnew1 has the maximum number of +// BB and is colorable. +// The starting BB for traversal must have a color available. +// +// Assign a color, update neighbor's forbidden list. +// +// Update the conflict graph by change the interference list. +// In the case of both LRnew1 and LRnew2 conflicts with a BB, this Bb's +// #neightbors increased. If this BB was unconstrained, must check if +// it is still unconstrained. Move to constrained if necessary. +// +// Color the unconstrained LRs. +void GraphColorRegAllocator::SplitAndColor() { + // handle constrained + while (constrained.size()) { + MapleVector::iterator highestIt = GetHighPriorityLr(constrained); + LiveRange *lr = *highestIt; + if (AssignColorToLr(lr)) { + if (highestIt != constrained.end()) { + constrained.erase(highestIt); + } else { + CG_ASSERT(0, "Error: not in constrained"); + } + } else { +#ifdef USE_SPLIT + LiveRange *newLr = nullptr; + newLr = SplitLr(lr); + // check those lrs in lr->sconflict which is in unconstrained whether it turns to constrined +#endif // USE_SPLIT + if (highestIt != constrained.end()) { + constrained.erase(highestIt); + // When LR is spilled, it potentially has no conflicts as + // each def/use is spilled/reloaded. +#ifdef COLOR_SPLIT + if (AssignColorToLr(lr) == false) { +#endif // COLOR_SPLIT + lr->spilled = true; + hasSpill = true; +#ifdef COLOR_SPLIT + } +#endif // COLOR_SPLIT + } else { + CG_ASSERT(0, "Error: not in constrained"); + } + } + } + + // assign color for unconstained + while (unconstrained.size() > 0) { + MapleVector::iterator highestIt = GetHighPriorityLr(unconstrained); + LiveRange *lr = *highestIt; + if (AssignColorToLr(lr)) { + if (highestIt != unconstrained.end()) { + unconstrained.erase(highestIt); + } else { + CG_ASSERT(0, "Error: not in unconstrained"); + LogInfo::MapleLogger() << "Error: not in unconstrained\n"; + // with error, iterator not erased + break; + } + } else { + CG_ASSERT(0, "LR should be colorable"); + LogInfo::MapleLogger() << "error: LR should be colorable " << lr->regno << "\n"; + // with error, iterator not erased + break; + } + } + +#ifdef OPTIMIZE_FOR_PROLOG + if (doOptProlog) { + ColorForOptPrologEpilog(); + } +#endif // OPTIMIZE_FOR_PROLOG + + return; +} + +void GraphColorRegAllocator::HandleLocalRegAssignment(regno_t regno, LocalRegAllocator *localRa, bool isInt) { + MapleMap *regAssignmentMap = localRa->GetRegAssignmentMap(isInt); + + // vreg, get a reg for it if not assigned already. + if (localRa->isInRegAssigned(regno, isInt) == false) { + // find an available phys reg + if (localRa->isInRegSpilled(regno, isInt) == false) { + bool founded = false; + uint32 preg; + FOREACH_LRA_REGS(isInt, preg, localRa) { + if (lrVec[regno]->pregveto[preg]) { + continue; + } + regno_t assignedReg = preg; + localRa->ClearRegs(assignedReg, isInt); + localRa->SetRegUsed(assignedReg, isInt); + localRa->SetRegAssigned(regno, isInt); + (*regAssignmentMap)[regno] = assignedReg; + founded = true; + break; + } + END_FOREACH_LRA_REGS; + if (!founded) { + localRa->SetRegSpilled(regno, isInt); + } + } + } else { + if (localRa->useInfo[regno] == 0) { + // last use of vreg, release assignment + localRa->SetRegs((*regAssignmentMap)[regno], isInt); + if (GCRA_DUMP) { + LogInfo::MapleLogger() << "\t\tlast use release reg " << (*regAssignmentMap)[regno] << " for " << regno << endl; + } + } + } +} + +bool GraphColorRegAllocator::HandleLocalRegDefWithNoUse(regno_t regno, LocalRegAllocator *localRa, bool isInt, + bool isDef) { + MapleMap *regAssignmentMap = localRa->GetRegAssignmentMap(isInt); + + auto usedIt = localRa->useInfo.find(regno); + if (usedIt == localRa->useInfo.end()) { + // local reg has no use, but obviously seen. + // If it is a vreg, then just assign it an unused preg + // no action needed since its live is dead right after. + if (regno >= kMaxRegNum) { + bool founded = false; + uint32 preg; + FOREACH_LRA_REGS(isInt, preg, localRa) { + if (lrVec[regno]->pregveto[preg]) { + continue; + } + founded = true; + regno_t assignedReg = preg; + localRa->SetRegAssigned(regno, isInt); + (*regAssignmentMap)[regno] = assignedReg; + break; + } + END_FOREACH_LRA_REGS; + } + // founded may be false + return true; + } + if (!isDef) { + // reg use, decrement count + CG_ASSERT(usedIt->second > 0, "Incorrect local ra info"); + localRa->useInfo[regno] = usedIt->second - 1; + if (GCRA_DUMP) { + LogInfo::MapleLogger() << "\t\treg " << regno << " update #use to " << localRa->useInfo[regno] << endl; + } + } + return false; +} + +void GraphColorRegAllocator::HandleLocalRaDebug(regno_t regno, LocalRegAllocator *localRa, bool isInt) { + LogInfo::MapleLogger() << "HandleLocalReg " << regno << endl; + LogInfo::MapleLogger() << "\tregUsed:"; + uint64 regUsed; + regUsed = localRa->GetRegUsed(isInt); + regno_t base = 0; + if (isInt) { + base = R0; + } else { + base = V0; + } + for (uint32 i = 0; i < R31; i++) { + if (regUsed & (1LL << i)) { + LogInfo::MapleLogger() << " " << (i + base); + } + } + LogInfo::MapleLogger() << endl; + LogInfo::MapleLogger() << "\tregs:"; + uint64 regs = localRa->GetRegs(isInt); + for (uint32 regno = 0; regno < R31; regno++) { + if (regs & (1LL << regno)) { + LogInfo::MapleLogger() << " " << (regno + base); + } + } + LogInfo::MapleLogger() << endl; +} + +void GraphColorRegAllocator::HandleLocalReg(Operand *op, LocalRegAllocator *localRa, BbAssignInfo *bbInfo, bool isDef, + bool isInt) { + if (!op->IsRegister()) { + return; + } + RegOperand *regOpnd = static_cast(op); + regno_t regno = regOpnd->GetRegisterNumber(); + + if (Riscv64isa::IsPhysicalRegister(regno)) { + return; + } + + if (IsUnconcernedReg(regOpnd)) { + return; + } + + // is this a local register ? + if (regno >= kMaxRegNum && !IsLocalReg(regno)) { + return; + } + + MapleMap *regAssignmentMap = localRa->GetRegAssignmentMap(isInt); + + if (GCRA_DUMP) { + HandleLocalRaDebug(regno, localRa, isInt); + } + + if (HandleLocalRegDefWithNoUse(regno, localRa, isInt, isDef)) { + return; + } + if (regOpnd->IsPhysicalRegister()) { + if (localRa->useInfo[regno] == 0) { + // See if it is needed by global RA + if (bbInfo && bbInfo->globalsAssigned[regno] == false) { + // This phys reg is now available for assignment for a vreg + localRa->SetRegs(regno, isInt); + if (GCRA_DUMP) { + LogInfo::MapleLogger() << "\t\tphys-reg " << regno << " now available\n"; + } + } + } + } else { + HandleLocalRegAssignment(regno, localRa, isInt); + } +} + +void GraphColorRegAllocator::LocalRaRegSetEraseReg(LocalRegAllocator *localRa, regno_t regno) { + bool isInt; + if (Riscv64isa::IsGPRegister(static_cast(regno))) { + isInt = true; + } else { + isInt = false; + } + if (localRa->IsInRegs(regno, isInt)) { + localRa->ClearRegs(regno, isInt); + } +} + +bool GraphColorRegAllocator::LocalRaInitRegSet(LocalRegAllocator *localRa, uint32 bbid, bool doAllocate) { + bool needLocalRa = false; + // Note physical regs start from R0, V0. + localRa->InitRegs(MaxIntPhysRegNum(), MaxFloatPhysRegNum(), cgfunc_->cg->GenYieldpoint()); + + localRa->useInfo.clear(); + LocalRaInfo *lraInfo = localRegVec[bbid]; + for (auto it : lraInfo->useCnt) { + regno_t regno = it.first; + if (regno >= kMaxRegNum) { + needLocalRa = true; +#ifdef DO_PRE_LRA + } else if (doLRA) { + if (!doAllocate) { + // ? no need when have forbidden info + LocalRaRegSetEraseReg(localRa, regno); + } +#endif + } + localRa->useInfo[it.first] = it.second; + } + return needLocalRa; +} + +void GraphColorRegAllocator::LocalRaInitAllocatableRegs(LocalRegAllocator *localRa, uint32 bbid, bool doAllocate) { + BbAssignInfo *bbInfo = bbRegInfo[bbid]; + if (bbInfo) { + for (regno_t regno = 0; regno < kNumPregBits; regno++) { + if (bbInfo->globalsAssigned[regno]) { + LocalRaRegSetEraseReg(localRa, regno); + } + } + } +} + +void GraphColorRegAllocator::LocalRaPrepareBb(BB *bb, LocalRegAllocator *localRa) { + BbAssignInfo *bbInfo = bbRegInfo[bb->id]; + FOR_BB_INSNS(insn, bb) { + if (!insn->IsMachineInstruction()) { + continue; + } + + // Use reverse operand order, assuming use first then def for allocation. + // need to free the use resource so it can be reused for def. + const Riscv64MD *md = &Riscv64CG::kMd[static_cast(insn)->GetMachineOpcode()]; + for (int32 i = (Insn::kMaxOperandNum - 1); i >= 0; i--) { + Operand *opnd = insn->GetOperand(i); + if (opnd == nullptr) { + continue; + } + if (opnd->IsList()) { + } else if (opnd->IsMemoryAccessOperand()) { + MemOperand *memopnd = static_cast(opnd); + Operand *base = memopnd->GetBaseRegister(); + if (base != nullptr) { + HandleLocalReg(base, localRa, bbInfo, false, true); + } + Operand *offset = memopnd->GetIndexRegister(); + if (offset != nullptr) { + HandleLocalReg(offset, localRa, bbInfo, false, true); + } + } else { + bool isDef = static_cast(md->operand_[i])->IsRegDef(); + RegOperand *regOpnd = static_cast(opnd); + if (regOpnd->GetRegisterType() == kRegTyInt) { + HandleLocalReg(opnd, localRa, bbInfo, isDef, true); + } else { + HandleLocalReg(opnd, localRa, bbInfo, isDef, false); + } + } + } + } +} + +void GraphColorRegAllocator::LocalRaFinalAssignment(LocalRegAllocator *localRa, BbAssignInfo *bbInfo) { + for (auto it : localRa->intRegAssignmentMap) { + regno_t regno = it.second; + if (GCRA_DUMP) { + LogInfo::MapleLogger() << "[" << it.first << "," << regno << "],"; + } + // Might need to get rid of this copy. + bbInfo->regMap[it.first] = regno; + if (Riscv64Abi::IsCalleeSavedReg((Riscv64reg_t)regno)) { + intCalleeUsed.insert(regno); + } + } + for (auto it : localRa->fpRegAssignmentMap) { + regno_t regno = it.second; + if (GCRA_DUMP) { + LogInfo::MapleLogger() << "[" << it.first << "," << regno << "],"; + } + // Might need to get rid of this copy. + bbInfo->regMap[it.first] = regno; + if (Riscv64Abi::IsCalleeSavedReg((Riscv64reg_t)regno)) { + fpCalleeUsed.insert(regno); + } + } +} + +void GraphColorRegAllocator::LocalRaDebug(BB *bb, LocalRegAllocator *localRa) { + LogInfo::MapleLogger() << "bb " << bb->id << " local ra INT need " << localRa->numIntRegUsed << " regs\n"; + LogInfo::MapleLogger() << "bb " << bb->id << " local ra FP need " << localRa->numFpRegUsed << " regs\n"; + LogInfo::MapleLogger() << "\tpotential assignments:"; + for (auto it : localRa->intRegAssignmentMap) { + LogInfo::MapleLogger() << "[" << it.first << "," << it.second << "],"; + } + for (auto it : localRa->fpRegAssignmentMap) { + LogInfo::MapleLogger() << "[" << it.first << "," << it.second << "],"; + } + LogInfo::MapleLogger() << "\n"; +} + +// When do_allocate is false, it is prepass: +// Traverse each BB, keep track of the number of registers required +// for local registers in the BB. Communicate this to global RA. +// +// When do_allocate is true: +// Allocate local registers for each BB based on unused registers +// from global RA. Spill if no register available. +void GraphColorRegAllocator::LocalRegisterAllocator(bool doAllocate) { + if (GCRA_DUMP) { + if (doAllocate) { + LogInfo::MapleLogger() << "LRA allocation start\n"; + PrintBbAssignInfo(); + } else { + LogInfo::MapleLogger() << "LRA preprocessing start\n"; + } + } + LocalRegAllocator *localRa = cgfunc_->memPool->New(cgfunc_, allocator); + for (uint32 idx = 0; idx < sortedBBs.size(); idx++) { + BB *bb = sortedBBs[idx]; + uint32 bbid = bb->id; + + LocalRaInfo *lraInfo = localRegVec[bb->id]; + if (lraInfo == nullptr) { + // No locals to allocate + continue; + } + + localRa->ClearLocalRaInfo(); + bool needLocalRa = LocalRaInitRegSet(localRa, bbid, doAllocate); + for (auto it : lraInfo->defCnt) { + if (it.first >= kMaxRegNum) { + needLocalRa = true; + break; + } + } + if (needLocalRa == false) { + // Only physical regs in bb, no local ra needed. + continue; + } + + if (doAllocate) { + LocalRaInitAllocatableRegs(localRa, bbid, doAllocate); + } + + LocalRaPrepareBb(bb, localRa); + + BbAssignInfo *bbInfo = bbRegInfo[bb->id]; + if (bbInfo == nullptr) { + bbInfo = cgfunc_->memPool->New(allocator); + bbRegInfo[bbid] = bbInfo; + bbInfo->globalsAssigned.clear(); + bbInfo->globalsAssigned.resize(kNumPregBits); + } + bbInfo->intLocalRegsNeeded = localRa->numIntRegUsed; + bbInfo->fpLocalRegsNeeded = localRa->numFpRegUsed; + + if (doAllocate) { + if (GCRA_DUMP) { + LogInfo::MapleLogger() << "\tbb(" << bb->id << ")final local ra assignments:"; + } + LocalRaFinalAssignment(localRa, bbInfo); + if (GCRA_DUMP) { + LogInfo::MapleLogger() << "\n"; + } + } else if (GCRA_DUMP) { + LocalRaDebug(bb, localRa); + } + } +} + +MemOperand *GraphColorRegAllocator::GetConsistentReuseMem(uint32 vregno, uint32 size, RegType regtype) { + LiveRange *lr = lrVec[vregno]; + uint64 *conflict; + if (lr->splitLr) { + // For split LR, the vreg liveness is optimized, but for spill location + // the stack location needs to be maintained for the entire LR. + conflict = lr->oldConflict; + } else { + conflict = lr->bconflict; + } + set sconflict; + FOREACH_REG_ARR_ELEM_NOT_SET(conflict, regno) { + if (regno >= numVregs) { + break; + } + if (lrVec[regno]) { + sconflict.insert(lrVec[regno]); + } + } + END_FOREACH_BB_ARR_ELEM + + set usedMemopnd; + FOREACH_REG_ARR_ELEM(conflict, regno) { + LiveRange *lr = lrVec[regno]; + if (lr->spillMem) { + usedMemopnd.insert(lr->spillMem); + } + } + END_FOREACH_REG_ARR_ELEM + + for (auto it : sconflict) { + LiveRange *noConflictLr = it; + if (noConflictLr && noConflictLr->regtype == regtype && noConflictLr->spillSize == size) { + if (usedMemopnd.find(noConflictLr->spillMem) == usedMemopnd.end()) { + return noConflictLr->spillMem; + } + } + } + return nullptr; +} + +MemOperand *GraphColorRegAllocator::GetCommonReuseMem(uint32 vregno, uint32 size, RegType regtype) { + LiveRange *lr = lrVec[vregno]; + uint64 *conflict; + if (lr->splitLr) { + // For split LR, the vreg liveness is optimized, but for spill location + // the stack location needs to be maintained for the entire LR. + conflict = lr->oldConflict; + } else { + conflict = lr->bconflict; + } + + set usedMemopnd; + FOREACH_REG_ARR_ELEM(conflict, regno) { + LiveRange *lr = lrVec[regno]; + if (lr->spillMem) { + usedMemopnd.insert(lr->spillMem); + } + } + END_FOREACH_REG_ARR_ELEM + + FOREACH_REG_ARR_ELEM_NOT_SET(conflict, regno) { + if (regno >= numVregs) { + break; + } + LiveRange *noConflictLr = lrVec[regno]; + if (noConflictLr && noConflictLr->regtype == regtype && noConflictLr->spillSize == size) { + if (usedMemopnd.find(noConflictLr->spillMem) == usedMemopnd.end()) { + return noConflictLr->spillMem; + } + } + } + + END_FOREACH_REG_ARR_ELEM_NOT_SET + return nullptr; +} + +// See if any of the non-conflict LR is spilled and use its memopnd. +MemOperand *GraphColorRegAllocator::GetReuseMem(uint32 vregno, uint32 size, RegType regtype) { + if (IsLocalReg(vregno)) { + return nullptr; + } + + size = (size <= k32) ? k32 : k64; + + // This is to order the search so memopnd given out is consistent. + // When vreg#s do not change going through VtableImpl.mpl file + // then this can be simplified. +#ifdef CONSISTENT_MEMOPND + return GetConsistentReuseMem(vregno, size, regtype); +#else // CONSISTENT_MEMOPND + return GetCommonReuseMem(vregno, size, regtype); +#endif // CONSISTENT_MEMOPND + + //return nullptr; +} + +MemOperand *GraphColorRegAllocator::GetSpillMem(uint32 vregno, Insn *insn, Riscv64reg_t regno, + uint8 &isOutOfRange) { + Riscv64CGFunc *a64cgfunc = static_cast(cgfunc_); + MemOperand *memopnd; + memopnd = a64cgfunc->GetOrCreatSpillMem(vregno); + return (a64cgfunc->AdjustMemOperandIfOffsetOutOfRange(memopnd, vregno, insn, regno, isOutOfRange)); +} + +void GraphColorRegAllocator::SpillOperandForSpillPre(Insn *insn, Operand *opnd, RegOperand *phyopnd, uint32 spillIdx, + bool needSpill) { + if (needSpill == false) { + return; + } + MemOperand *spillMem; + spillMem = CreateSpillMem(spillIdx); + Riscv64CGFunc *a64cgfunc = static_cast(cgfunc_); + CG *cg = a64cgfunc->cg; + + RegOperand *regOpnd = static_cast(opnd); + uint32 regno = regOpnd->GetRegisterNumber(); + uint32 regsize = regOpnd->GetSize(); + PrimType stype = (phyopnd->IsOfIntClass()) ? + ((regsize <= k32) ? PTY_i32 : PTY_i64) : + ((regsize <= k32) ? PTY_f32 : PTY_f64); + + if (a64cgfunc->IsImmediateOffsetOutOfRange(static_cast(spillMem), k64)) { + //CHECK_FATAL(0, "NYI"); + regno_t pregNo = Riscv64Abi::kIntSpareReg; + spillMem = a64cgfunc->SplitOffsetWithAddInstruction(static_cast(spillMem), k64, + (Riscv64reg_t)pregNo, insn); + } + Insn *stInsn = + cg->BuildInstruction(a64cgfunc->PickStInsn(spillMem->GetSize(), stype), phyopnd, spillMem); + stInsn->SetSpillOp(); + std::string comment = " SPILL for spill vreg: " + std::to_string(regno); + stInsn->AddComment(comment); + insn->bb->InsertInsnBefore(insn, stInsn); +} + +void GraphColorRegAllocator::SpillOperandForSpillPost(Insn *insn, Operand *opnd, RegOperand *phyopnd, uint32 spillIdx, + bool needSpill) { + if (needSpill == false) { + return; + } + if (insn == nullptr) { + return; + } + + MemOperand *spillMem; + spillMem = CreateSpillMem(spillIdx); + Riscv64CGFunc *a64cgfunc = static_cast(cgfunc_); + CG *cg = a64cgfunc->cg; + bool lastInsn = false; + if (insn->bb->kind == BB::kBBIf && insn->bb->lastinsn == insn) { + lastInsn = true; + } + + RegOperand *regOpnd = static_cast(opnd); + uint32 regno = regOpnd->GetRegisterNumber(); + uint32 regsize = regOpnd->GetSize(); + PrimType stype = (phyopnd->IsOfIntClass()) ? + ((regsize <= k32) ? PTY_i32 : PTY_i64) : + ((regsize <= k32) ? PTY_f32 : PTY_f64); + + bool isOutOfRange = false; + if (a64cgfunc->IsImmediateOffsetOutOfRange(static_cast(spillMem), k64)) { + regno_t pregNo = Riscv64Abi::kIntSpareReg; + // This split call will prepend extra instructions. So try to prepend it to the next insn. + // insn is either the spill of the def or the actual insn whose use opnd being spilled. + spillMem = a64cgfunc->SplitOffsetWithAddInstruction(static_cast(spillMem), k64, + (Riscv64reg_t)pregNo, + (insn->next) ? insn->next : insn); + isOutOfRange = true; + } + Insn *ldInsn = + cg->BuildInstruction(a64cgfunc->PickLdInsn(spillMem->GetSize(), stype), phyopnd, spillMem); + ldInsn->SetSpillOp(); + std::string comment = " RELOAD for spill vreg: " + std::to_string(regno); + ldInsn->AddComment(comment); + if (lastInsn) { + BB *newBB = nullptr; + BB *tgtBB = nullptr; + for (auto tbb : insn->bb->succs) { + Insn *newLd = cg->BuildInstruction(a64cgfunc->PickLdInsn(spillMem->GetSize(), stype), phyopnd, spillMem); + newLd->SetSpillOp(); + newLd->AddComment(comment); + if (insn->bb == tbb || insn->bb->level > tbb->level) { + // If it is a backward branch to itself or a block that is a predecessor. + CHECK_FATAL(newBB == nullptr, "targetBB already created"); + tgtBB = tbb; + newBB = cgfunc_->CreateNewBB(); + LabelIdx tgtLabel = cgfunc_->CreateLabel(); + newBB->AddLabel(tgtLabel); + newBB->level = insn->bb->level + 1; + cgfunc_->lab2bbmap[newBB->labidx] = newBB; + cgfunc_->lastbb->AppendBB(newBB); + cgfunc_->lastbb = newBB; + int tgtIdx = insn->GetJumpTargetIdx(); + LabelOperand *origTarget = static_cast(insn->opnds[tgtIdx]); + LabelOperand *newTarget = cgfunc_->GetOrCreateLabelOperand(tgtLabel); + insn->opnds[tgtIdx] = newTarget; + newBB->AppendInsn(newLd); + newBB->AppendInsn(cg->BuildInstruction(MOP_xuncond, origTarget)); + } else { + tbb->InsertInsnBegin(newLd); + } + } + if (newBB) { + insn->bb->RemoveFromSuccessorList(tgtBB); + insn->bb->succs.push_back(newBB); + newBB->succs.push_back(tgtBB); + + tgtBB->RemoveFromPredecessorList(insn->bb); + tgtBB->preds.push_back(newBB); + newBB->preds.push_back(insn->bb); + } + } else { + if (isOutOfRange && insn->next) { + insn->bb->InsertInsnAfter(insn->next->next, ldInsn); + } else { + insn->bb->InsertInsnAfter(insn, ldInsn); + } + } +} + +MemOperand *GraphColorRegAllocator::GetSpillOrReuseMem(LiveRange *lr, uint32 regsize, uint8 &isOutOfRange, Insn *insn, + bool isDef) { + MemOperand *memopnd; + if (lr->spillMem) { + // the saved memopnd cannot be out-of-range + memopnd = lr->spillMem; + } else { +#ifdef REUSE_SPILLMEM + memopnd = GetReuseMem(lr->regno, regsize, lr->regtype); + if (memopnd) { + lr->spillMem = memopnd; + lr->spillSize = (regsize <= k32) ? k32 : k64; + } else { +#endif // REUSE_SPILLMEM + regno_t baseRegNO; + if (!isDef) { + /* src will use its' spill reg as baseRegister when offset out-of-range + * add x16, x29, #max-offset //out-of-range + * ldr x16, [x16, #offset] //reload + * mov xd, x16 + */ + baseRegNO = lr->spillReg; + if ( baseRegNO > RLAST_INT_REG ) { + baseRegNO = Riscv64Abi::kFpSpareReg; + } + } else { + /* dest will use R17 as baseRegister when offset out-of-range + * mov x16, xs + * add x17, x29, #max-offset //out-of-range + * str x16, [x17, #offset] //spill + */ + baseRegNO = Riscv64Abi::kIntSpareReg; + } + ASSERT(baseRegNO != kRinvalid, "invalid base register number"); + memopnd = GetSpillMem(lr->regno, insn, (Riscv64reg_t)(baseRegNO), isOutOfRange); +#ifdef REUSE_SPILLMEM + if (isOutOfRange == 0) { + lr->spillMem = memopnd; + lr->spillSize = (regsize <= k32) ? k32 : k64; + } + } +#endif // REUSE_SPILLMEM + } + return memopnd; +} + +// Create spill insn for the operand. +// When need_spill is true, need to spill the spill operand register first +// then use it for the current spill, then reload it again. +Insn *GraphColorRegAllocator::SpillOperand(Insn *insn, Operand *opnd, bool isDef, RegOperand *phyopnd, + uint32 &spillIdx) { + RegOperand *regOpnd = static_cast(opnd); + uint32 regno = regOpnd->GetRegisterNumber(); + uint32 pregNo = phyopnd->GetRegisterNumber(); + if (GCRA_DUMP) { + LogInfo::MapleLogger() << "InsertSpillReload " << regno << "\n"; + } + + uint32 regsize = regOpnd->GetSize(); + uint8 isOutOfRange = 0; + PrimType stype; + RegType regtype = regOpnd->GetRegisterType(); + if (regtype == kRegTyInt) { + stype = (regsize <= k32) ? PTY_i32 : PTY_i64; + } else { + stype = (regsize <= k32) ? PTY_f32 : PTY_f64; + } + Riscv64CGFunc *a64cgfunc = static_cast(cgfunc_); + CG *cg = a64cgfunc->cg; + + Insn *spillDefInsn = nullptr; + MemOperand *memopnd; + if (isDef) { + LiveRange *lr = lrVec[regno]; + lr->spillReg = pregNo; + memopnd = GetSpillOrReuseMem(lr, regsize, isOutOfRange, insn, true); + spillDefInsn = cg->BuildInstruction(a64cgfunc->PickStInsn(regsize, stype), phyopnd, memopnd); + spillDefInsn->SetSpillOp(); + std::string comment = " SPILL vreg: " + std::to_string(regno); + spillDefInsn->AddComment(comment); + if (insn->next && insn->next->GetMachineOpcode() == MOP_clinit_tail) { + insn->bb->InsertInsnAfter(insn->next, spillDefInsn); + } else { + insn->bb->InsertInsnAfter(insn, spillDefInsn); + } + } + if (insn->GetMachineOpcode() == MOP_clinit_tail) { + return nullptr; + } + LiveRange *lr = lrVec[regno]; + Insn *spillUseInsn = nullptr; + lr->spillReg = pregNo; + memopnd = GetSpillOrReuseMem(lr, regsize, isOutOfRange, insn, false); + spillUseInsn = cg->BuildInstruction(a64cgfunc->PickLdInsn(regsize, stype), phyopnd, memopnd); + spillUseInsn->SetSpillOp(); + std::string comment = " RELOAD vreg: " + std::to_string(regno); + spillUseInsn->AddComment(comment); + insn->bb->InsertInsnBefore(insn, spillUseInsn); + if (spillDefInsn) { + return spillDefInsn; + } else { + return insn; + } + return spillDefInsn; +} + +// Try to find available reg for spill. +bool GraphColorRegAllocator::GetAvailableSpillReg(set &cannotUseReg, LiveRange *lr, uint64 &usedRegMask) { + regno_t spillReg; + RegType regtype = lr->regtype; + if (regtype == kRegTyInt) { + for (auto it : intCallerRegSet) { + spillReg = it + R0; + if (cannotUseReg.find(spillReg) == cannotUseReg.end() && (usedRegMask & (1LL << (spillReg))) == 0) { + lr->assigned = spillReg; + usedRegMask |= 1LL << (spillReg); + return true; + } + } + for (auto it : intCalleeRegSet) { + spillReg = it + R0; + if (cannotUseReg.find(spillReg) == cannotUseReg.end() && (usedRegMask & (1LL << (spillReg))) == 0) { + lr->assigned = spillReg; + usedRegMask |= 1LL << (spillReg); + return true; + } + } + + } else if (regtype == kRegTyFloat) { + for (auto it : fpCallerRegSet) { + spillReg = it + V0; + if (cannotUseReg.find(spillReg) == cannotUseReg.end() && (usedRegMask & (1LL << (spillReg))) == 0) { + lr->assigned = spillReg; + usedRegMask |= 1LL << (spillReg); + return true; + } + } + for (auto it : fpCalleeRegSet) { + spillReg = it + V0; + if (cannotUseReg.find(spillReg) == cannotUseReg.end() && (usedRegMask & (1LL << (spillReg))) == 0) { + lr->assigned = spillReg; + usedRegMask |= 1LL << (spillReg); + return true; + } + } + } else { + CG_ASSERT(0, "Illegal regtype in GetAvailableSpillReg"); + } + return false; +} + +void GraphColorRegAllocator::CollectCannotUseReg(set &cannotUseReg, LiveRange *lr, Insn *insn) { + // Find the bb in the conflict LR that actually conflicts with the current bb. + for (regno_t regno = 0; regno < kNumPregBits; regno++) { + if (lr->pregveto[regno]) { + cannotUseReg.insert(regno); + } + } + FOREACH_REG_ARR_ELEM(lr->bconflict, regno) + LiveRange *conflictLr = lrVec[regno]; + // conflictLr->assigned might be zero + // caller save will be inserted so the assigned reg can be released actually + if ((conflictLr->assigned > 0) && IS_BIT_ARR_ELEM_SET(conflictLr->bmember, insn->bb->id)) { + if (!Riscv64Abi::IsCalleeSavedReg((Riscv64reg_t)conflictLr->assigned) && conflictLr->numCall) { + continue; + } + cannotUseReg.insert(conflictLr->assigned); + } + END_FOREACH_REG_ARR_ELEM +#ifdef USE_LRA + if (doLRA) { + BbAssignInfo *bbInfo = bbRegInfo[insn->bb->id]; + if (bbInfo) { + for (auto it : bbInfo->regMap) { + cannotUseReg.insert(it.second); + } + } + } +#endif // USE_LRA +} + +// return true if need extra spill +bool GraphColorRegAllocator::PickRegForSpill(LiveRange *lr, Insn *insn, uint64 &usedRegMask, bool isDef) { + bool needSpillLr = false; + set cannotUseReg; + + // SPILL COALESCE + if (isDef == false && (insn->GetMachineOpcode() == MOP_xmovrr || insn->GetMachineOpcode() == MOP_wmovrr)) { + RegOperand *ropnd = static_cast(insn->GetOperand(0)); + if (ropnd->IsPhysicalRegister()) { + lr->assigned = ropnd->GetRegisterNumber(); + return false; + } + } + + CollectCannotUseReg(cannotUseReg, lr, insn); + + if (GetAvailableSpillReg(cannotUseReg, lr, usedRegMask)) { + return false; + } + + if (!lr->assigned) { + // All regs are assigned and none are free. + // Pick a reg to spill and reuse for this spill. + // Need to make sure the reg picked is not assigned to this insn, + // else there will be conflict. + regno_t base; + regno_t spillReg; + if (lr->regtype == kRegTyInt) { + base = R0; + } else { + base = V0; + } + for (spillReg = (MaxIntPhysRegNum() + base); spillReg > base; spillReg--) { + if ((usedRegMask & (1LL << (spillReg))) == 0) { + lr->assigned = spillReg; + usedRegMask |= 1LL << (spillReg); + needSpillLr = true; + break; + } + } + } + return needSpillLr; +} + +regno_t GraphColorRegAllocator::PickRegForLocalSpill(regno_t regno, RegType regtype, uint64 &usedRegMask) { + // use the reg that exclude livein/liveout/bbInfo->regMap + + // Need to make sure the reg picked is not assigned to this insn, + // else there will be conflict. + regno_t base; + regno_t spillReg = 0; + if (regtype == kRegTyInt) { + base = R0; + } else { + base = V0; + } + for (spillReg = (MaxIntPhysRegNum() + base); spillReg > base; spillReg--) { + if ((usedRegMask & (1LL << (spillReg))) == 0) { + usedRegMask |= 1LL << (spillReg); + break; + } + } + if (GCRA_DUMP) { + LogInfo::MapleLogger() << "\tassigning lra spill reg " << spillReg << endl; + } + return spillReg; +} + +RegOperand *GraphColorRegAllocator::GetReplaceOpndForLRA(Insn *insn, Operand *opnd, uint32 &spillIdx, + uint64 &usedRegMask, bool isDef) { + RegOperand *regOpnd = static_cast(opnd); + uint32 vregno = regOpnd->GetRegisterNumber(); + RegType regtype = regOpnd->GetRegisterType(); + BbAssignInfo *bbInfo = bbRegInfo[insn->bb->id]; + if (bbInfo) { + auto regIt = bbInfo->regMap.find(vregno); + if (regIt != bbInfo->regMap.end()) { + RegOperand *phyOpnd = static_cast(cgfunc_)->GetOrCreatePhysicalRegisterOperand( + (Riscv64reg_t)(regIt->second), regOpnd->GetSize(), regtype); + return phyOpnd; + } else { + if (GCRA_DUMP) { + LogInfo::MapleLogger() << "spill vreg " << vregno << endl; + } + regno_t spillReg; + if ((insn->GetMachineOpcode() == MOP_clinit_tail) || + (insn->next && isDef && insn->next->GetMachineOpcode() == MOP_clinit_tail)) { + spillReg = Riscv64Abi::kIntSpareReg; + } else { + spillReg = PickRegForLocalSpill(vregno, regtype, usedRegMask); + bool isCalleeReg = Riscv64Abi::IsCalleeSavedReg((Riscv64reg_t)(spillReg)); + if (isCalleeReg) { + if (regtype == kRegTyInt) { + intCalleeUsed.insert((spillReg)); + } else { + fpCalleeUsed.insert((spillReg)); + } + } + } + RegOperand *phyOpnd = static_cast(cgfunc_)->GetOrCreatePhysicalRegisterOperand( + (Riscv64reg_t)(spillReg), regOpnd->GetSize(), regtype); + SpillOperandForSpillPre(insn, regOpnd, phyOpnd, spillIdx, true); + Insn *spill = SpillOperand(insn, regOpnd, isDef, phyOpnd, spillIdx); + SpillOperandForSpillPost(spill, regOpnd, phyOpnd, spillIdx, true); + spillIdx++; + return phyOpnd; + } + } + return nullptr; +} + +// get spill reg and check if need extra spill +bool GraphColorRegAllocator::GetSpillReg(Insn *insn, LiveRange *lr, uint64 &usedRegMask, bool isDef) { + bool needSpillLr = false; + // Find a spill reg for the BB among interfereing LR. + // Without LRA, this info is very inaccurate. It will falsely interfere + // with all locals which the spill might not be interfering. + // For now, every instance of the spill requires a brand new reg assignment. + if (GCRA_DUMP) { + LogInfo::MapleLogger() << "LR-regno " << lr->regno << " spilled, finding a spill reg\n"; + } + if (insn->IsBranch() || insn->IsCall() || (insn->GetMachineOpcode() == MOP_clinit_tail) || + (insn->next && isDef && insn->next->GetMachineOpcode() == MOP_clinit_tail)) { + // When a cond branch reg is spilled, it cannot + // restore the value after the branch since it can be the target from other br. + // Todo it properly, it will require creating a intermediate bb for the reload. + // Use x16, it is taken out from available since it is used as a global in the system. + lr->assigned = Riscv64Abi::kIntSpareReg; + } else { + lr->assigned = 0; + needSpillLr = PickRegForSpill(lr, insn, usedRegMask, isDef); + bool isCalleeReg = Riscv64Abi::IsCalleeSavedReg((Riscv64reg_t)(lr->assigned)); + if (isCalleeReg) { + if (lr->regtype == kRegTyInt) { + intCalleeUsed.insert((lr->assigned)); + } else { + fpCalleeUsed.insert((lr->assigned)); + } + } + } + return needSpillLr; +} + +RegOperand *GraphColorRegAllocator::GetReplaceOpnd(Insn *insn, Operand *opnd, uint32 &spillIdx, uint64 &usedRegMask, + bool isDef) { + if (!opnd->IsRegister()) { + return nullptr; + } + RegOperand *regOpnd = static_cast(opnd); + + uint32 vregno = regOpnd->GetRegisterNumber(); + RegType regtype = regOpnd->GetRegisterType(); + if (vregno < kMaxRegNum) { + return nullptr; + } + if (IsUnconcernedReg(regOpnd)) { + return nullptr; + } + +#ifdef USE_LRA + if (doLRA && IsLocalReg(vregno)) { + return GetReplaceOpndForLRA(insn, opnd, spillIdx, usedRegMask, isDef); + } +#endif // USE_LRA + + CG_ASSERT(vregno < lrVec.size(), "index out of range of MapleVector in GraphColorRegAllocator::GetReplaceOpnd"); + LiveRange *lr = lrVec[vregno]; + + bool isSplitPart = false; + bool needSpillLr = false; + if (lr->splitLr && IS_BIT_ARR_ELEM_SET(lr->splitLr->bmember, insn->bb->id)) { + isSplitPart = true; + } + + if (lr->spilled && !isSplitPart) { + needSpillLr = GetSpillReg(insn, lr, usedRegMask, isDef); + } + + regno_t regno; + if (isSplitPart) { + regno = lr->splitLr->assigned; + } else { + regno = lr->assigned; + } + bool isCalleeReg = Riscv64Abi::IsCalleeSavedReg((Riscv64reg_t)regno); + RegOperand *phyOpnd = static_cast(cgfunc_)->GetOrCreatePhysicalRegisterOperand( + (Riscv64reg_t)(regno), opnd->GetSize(), regtype); + if (GCRA_DUMP) { + LogInfo::MapleLogger() << "replace R" << vregno << " with R" << regno << endl; + } + + std::string comment = insn->GetComment(); + comment += " [R" + std::to_string(vregno) + "] "; + insn->AddComment(comment); + + if (isSplitPart && (isCalleeReg || lr->splitLr->numCall == 0)) { + if (isDef) { + SpillOperand(insn, opnd, isDef, phyOpnd, spillIdx); + spillIdx++; + } else { + if (lr->splitLr->luMap[insn->bb->id]->needRlod) { + SpillOperand(insn, opnd, isDef, phyOpnd, spillIdx); + spillIdx++; + } + } + return phyOpnd; + } + + if (lr->spilled || (isSplitPart && lr->splitLr->numCall) || (lr->numCall && !isCalleeReg) || + (!isSplitPart && !(lr->spilled) && lr->luMap[insn->bb->id]->needRlod)) { + SpillOperandForSpillPre(insn, regOpnd, phyOpnd, spillIdx, needSpillLr); + Insn *spill = SpillOperand(insn, opnd, isDef, phyOpnd, spillIdx); + SpillOperandForSpillPost(spill, regOpnd, phyOpnd, spillIdx, needSpillLr); + spillIdx++; + } + + return phyOpnd; +} + +void GraphColorRegAllocator::MarkUsedRegs(Operand *opnd, uint64 &usedRegMask) { + RegOperand *regOpnd = static_cast(opnd); + uint32 vregno = regOpnd->GetRegisterNumber(); + LiveRange *lr = lrVec[vregno]; + if (lr && lr->assigned) { + usedRegMask |= (1LL << (lr->assigned)); + } +} + +uint64 GraphColorRegAllocator::FinalizeRegisterPreprocess(FinalizeRegisterInfo *fInfo, Insn *insn) { + uint64 usedRegMask = 0; + const Riscv64MD *md = &Riscv64CG::kMd[static_cast(insn)->GetMachineOpcode()]; + for (int32_t i = 0; i < Insn::kMaxOperandNum; i++) { + Operand *opnd = insn->GetOperand(i); + if (opnd == nullptr) { + continue; + } + CG_ASSERT((md->operand_[i]) != nullptr, "pointer is null in GraphColorRegAllocator::FinalizeRegisters"); + + if (opnd->IsList()) { + // For arm32, not arm64 + } else if (opnd->IsMemoryAccessOperand()) { + MemOperand *memopnd = static_cast(opnd); + CG_ASSERT(memopnd != nullptr, "memopnd is null in colorRA FinalizeRegisters"); + Operand *base = memopnd->GetBaseRegister(); + if (base != nullptr) { + fInfo->SetBaseOperand(opnd, i); + MarkUsedRegs(base, usedRegMask); + } + Operand *offset = memopnd->GetIndexRegister(); + if (offset != nullptr) { + fInfo->SetOffsetOperand(opnd); + MarkUsedRegs(offset, usedRegMask); + } + } else { + bool isDef = static_cast(md->operand_[i])->IsRegDef(); + if (isDef) { + fInfo->SetDefOperand(opnd, i); + + // Need to exclude def also, since it will clobber the result when the + // original value is reloaded. + MarkUsedRegs(opnd, usedRegMask); + } else { + fInfo->SetUseOperand(opnd, i); + if (opnd->IsRegister()) { + MarkUsedRegs(opnd, usedRegMask); + } + } + } + } // operand + return usedRegMask; +} + +void GraphColorRegAllocator::GenerateSpillFillRegs(Insn *insn) { + static regno_t intregs[3] = { R29, R30, R31 }; // R9 is used for large stack offset temp + static regno_t fpregs[3] = { V29, V30, V31 }; + uint32 intUseCnt = 0; + uint32 fpUseCnt = 0; + for (int32_t i = 0; i < Insn::kMaxOperandNum; i++) { + Operand *opnd = insn->GetOperand(i); + if (!opnd) { + continue; + } + if (opnd->IsList()) { + // call parameters + } else if (opnd->IsMemoryAccessOperand()) { + MemOperand *memopnd = static_cast(opnd); + Riscv64RegOperand *base = static_cast(memopnd->GetBaseRegister()); + if (base != nullptr && base->IsPhysicalRegister()) { + regno_t regno = base->GetRegisterNumber(); + if (regno == intregs[0] || regno == intregs[1] || regno == intregs[2]) { + intUseCnt++; + } + } + } else { + RegOperand *ropnd = static_cast(opnd); + if (ropnd && ropnd->IsVirtualRegister() == false) { + regno_t regno = ropnd->GetRegisterNumber(); + if (regno >= V0) { + if (regno == fpregs[0] || regno == fpregs[1] || regno == fpregs[2]) { + fpUseCnt++; + } + } else { + if (regno == intregs[0] || regno == intregs[1] || regno == intregs[2]) { + intUseCnt++; + } + } + } + } + } + intSpillFillRegs[0] = intregs[0] + intUseCnt; + intSpillFillRegs[1] = intregs[1] + intUseCnt; + intSpillFillRegs[2] = intregs[2] + intUseCnt; + fpSpillFillRegs[0] = fpregs[0] + fpUseCnt; + fpSpillFillRegs[1] = fpregs[1] + fpUseCnt; + fpSpillFillRegs[2] = fpregs[2] + fpUseCnt; +} + +RegOperand *GraphColorRegAllocator::CreateSpillFillCode(RegOperand *opnd, Insn *insn, uint32 spillCnt, bool isdef) { + regno_t vregno = opnd->GetRegisterNumber(); + LiveRange *lr = lrVec[vregno]; + if (lr && lr->spilled) { + Riscv64CGFunc *a64cgfunc = static_cast(cgfunc_); + CG *cg = a64cgfunc->cg; + uint32 bits = opnd->GetValidBitsNum(); + if (bits < 32) { + bits = 32; + } + MemOperand *loadmem = a64cgfunc->GetOrCreatSpillMem(vregno); + uint8 isOutOfRange; + loadmem = a64cgfunc->AdjustMemOperandIfOffsetOutOfRange(loadmem, vregno, insn, R28, isOutOfRange, isdef); + PrimType pty = (lr->regtype == kRegTyInt) ? ((bits > 32) ? PTY_i64 : PTY_i32) + : ((bits > 32) ? PTY_f64 : PTY_f32); + regno_t spreg = 0; + RegType rtype = lr->regtype; + if (spillCnt == 0) { + // pregveto will take care of assignment, so pick a caller reg for temp + GenerateSpillFillRegs(insn); + } + CHECK_FATAL(spillCnt < 3, "spill count exceeded"); + spreg = (rtype == kRegTyInt) ? intSpillFillRegs[spillCnt] : fpSpillFillRegs[spillCnt]; + RegOperand *regopnd = a64cgfunc->GetOrCreatePhysicalRegisterOperand(static_cast(spreg), opnd->GetSize(), rtype); + + Insn *memInsn; + if (isdef) { + memInsn = cg->BuildInstruction(a64cgfunc->PickStInsn(bits, pty), regopnd, loadmem); + memInsn->SetSpillOp(); + std::string comment = " SPILLcolor vreg: " + std::to_string(vregno); + memInsn->AddComment(comment); + if (isOutOfRange) { + insn->bb->InsertInsnAfter(insn->next->next, memInsn); + } else { + insn->bb->InsertInsnAfter(insn, memInsn); + } + } else { + memInsn = cg->BuildInstruction(a64cgfunc->PickLdInsn(bits, pty), regopnd, loadmem); + memInsn->SetSpillOp(); + std::string comment = " RELOADcolor vreg: " + std::to_string(vregno); + memInsn->AddComment(comment); + insn->bb->InsertInsnBefore(insn, memInsn); + } + return regopnd; + } + return nullptr; +} + +void GraphColorRegAllocator::SpillLiveRangeForSpills() { + Riscv64CGFunc *a64cgfunc = static_cast(cgfunc_); + CG *cg = a64cgfunc->cg; + for (uint32_t bbIdx = 0; bbIdx < sortedBBs.size(); bbIdx++) { + BB *bb = sortedBBs[bbIdx]; + FOR_BB_INSNS(insn, bb) { + uint32 spillCnt; + if (insn->IsImmaterialInsn() || !insn->IsMachineInstruction() || insn->id == 0) { + continue; + } + spillCnt = 0; + const Riscv64MD *md = &Riscv64CG::kMd[static_cast(insn)->mop_]; + for (int32_t i = 0; i < Insn::kMaxOperandNum; i++) { + Operand *opnd = insn->GetOperand(i); + if (!opnd) { + continue; + } + if (opnd->IsList()) { + // call parameters + } else if (opnd->IsMemoryAccessOperand()) { + MemOperand *newmemopnd = nullptr; + MemOperand *memopnd = static_cast(opnd); + RegOperand *base = static_cast(memopnd->GetBaseRegister()); + if (base != nullptr && base->IsVirtualRegister()) { + RegOperand *replace = CreateSpillFillCode(base, insn, spillCnt); + if (replace) { + spillCnt++; + newmemopnd = static_cast(static_cast(opnd)->Clone(cgfunc_->memPool)); + newmemopnd->SetBaseRegister(replace); + insn->SetOperand(i, newmemopnd); + } + } + RegOperand *offset = static_cast(memopnd->GetIndexRegister()); + if (offset != nullptr && offset->IsVirtualRegister()) { + RegOperand *replace = CreateSpillFillCode(offset, insn, spillCnt); + if (replace) { + spillCnt++; + if (newmemopnd == nullptr) { + newmemopnd = static_cast(static_cast(opnd)->Clone(cgfunc_->memPool)); + } + newmemopnd->SetIndexRegister(replace); + insn->SetOperand(i, newmemopnd); + } + } + } else if (opnd->IsRegister()) { + bool isdef = static_cast(md->operand_[i])->IsRegDef(); + RegOperand *replace = CreateSpillFillCode(static_cast(opnd), insn, spillCnt, isdef); + if (replace) { + if (isdef == false) { + spillCnt++; + } + insn->SetOperand(i, replace); + } + } + } + } + } +} + +// Iterate through all instructions and change the vreg to preg. +void GraphColorRegAllocator::FinalizeRegisters() { + if (CGOptions::doMultiPassColorRA && hasSpill) { + SpillLiveRangeForSpills(); + return; + } + for (uint32_t bbIdx = 0; bbIdx < sortedBBs.size(); bbIdx++) { + BB *bb = sortedBBs[bbIdx]; + FOR_BB_INSNS(insn, bb) { + if (insn->IsImmaterialInsn()) { + continue; + } + if (!insn->IsMachineInstruction()) { + continue; + } + if (insn->id == 0) { + continue; + } + + FinalizeRegisterInfo *fInfo = cgfunc_->memPool->New(allocator); + uint64 usedRegMask = FinalizeRegisterPreprocess(fInfo, insn); + + uint32 spillIdx = 0; + MemOperand *memopnd = nullptr; + if (fInfo->baseOperand) { + memopnd = static_cast(static_cast(fInfo->baseOperand)->Clone(cgfunc_->memPool)); + insn->SetOperand(fInfo->memOperandIdx, memopnd); + Operand *base = memopnd->GetBaseRegister(); + RegOperand *phyOpnd = GetReplaceOpnd(insn, base, spillIdx, usedRegMask, false); + if (phyOpnd) { + memopnd->SetBaseRegister(phyOpnd); + } + } + if (fInfo->offsetOperand) { + CG_ASSERT(memopnd != nullptr, "mem operand cannot be null"); + Operand *offset = memopnd->GetIndexRegister(); + RegOperand *phyOpnd = GetReplaceOpnd(insn, offset, spillIdx, usedRegMask, false); + if (phyOpnd) { + memopnd->SetIndexRegister(phyOpnd); + } + } + for (int32_t i = 0; i < fInfo->useOperands.size(); i++) { + Operand *opnd = fInfo->useOperands[i]; + RegOperand *phyOpnd = GetReplaceOpnd(insn, opnd, spillIdx, usedRegMask, false); + if (phyOpnd) { + insn->SetOperand(fInfo->useIdx[i], phyOpnd); + } + } + for (int32_t i = 0; i < fInfo->defOperands.size(); i++) { + Operand *opnd = fInfo->defOperands[i]; + RegOperand *phyOpnd = GetReplaceOpnd(insn, opnd, spillIdx, usedRegMask, true); + if (phyOpnd) { + insn->SetOperand(fInfo->defIdx[i], phyOpnd); + } + } + } // insn + } // BB +} + +void GraphColorRegAllocator::MarkCalleeSaveRegs() { + for (auto regno : intCalleeUsed) { + static_cast(cgfunc_)->AddtoCalleeSaved((Riscv64reg_t)regno); + } + for (auto regno : fpCalleeUsed) { + static_cast(cgfunc_)->AddtoCalleeSaved((Riscv64reg_t)regno); + } +} + +bool GraphColorRegAllocator::AllocateRegisters() { +#ifdef RANDOM_PRIORITY + // Change this seed for different random numbers + srand(0); +#endif // RANDOM_PRIORITY + Riscv64CGFunc *a64cgfunc = static_cast(cgfunc_); + + // we store both FP/LR if using FP or if not using FP, but func has a call + if (a64cgfunc->ShouldSaveFPLR()) { + // Using FP, record it for saving + a64cgfunc->AddtoCalleeSaved(RFP); + a64cgfunc->AddtoCalleeSaved(RRA); + a64cgfunc->NoteFPLRAddedToCalleeSavedList(); + } + + uint32 cnt = 0; + FOR_ALL_BB(bb, cgfunc_) { + FOR_BB_INSNS(insn, bb) { + cnt++; + } + } + CG_ASSERT(cnt <= cgfunc_->GetTotalNumberOfInstructions(), "Incorrect insn count"); + +#ifdef PROPAGATE_REG + if (cgfunc_->IsAfterRegAlloc() == false) { + RaX0Opt x0Opt; + x0Opt.PropagateX0(cgfunc_); + } + if (GCRA_DUMP) { + LogInfo::MapleLogger() << "******** CG IR After PreColorRA: *********" << endl; + cgfunc_->DumpCGIR(); + MIRModule &mirModule = cgfunc_->mirModule; + DotGenerator::GenerateDot("RAe", cgfunc_, &mirModule, true); + } +#endif + + if (CGOptions::doMultiPassColorRA) { + doLRA = false; + doOptProlog = false; + } + + cgfunc_->SetIsAfterRegAlloc(); + // EBO propgation extent the live range and might need to be turned off. + InitFreeRegPool(); + + ComputeBlockOrder(); + + ComputeLiveRanges(); + +#ifdef DO_PRE_LRA + if (doLRA) { + LocalRegisterAllocator(false); + } +#endif // DO_PRE_LRA + + BuildInterferenceGraph(); + + Separate(); + + SplitAndColor(); + +#ifdef USE_LRA + if (doLRA) { + LocalRegisterAllocator(true); + } +#endif // USE_LRA + + FinalizeRegisters(); + + MarkCalleeSaveRegs(); + + if (GCRA_DUMP) { + cgfunc_->DumpCGIR(); + } + + if (CGOptions::doMultiPassColorRA && hasSpill) { + return false; + } else { + return true; + } +} + +} // namespace maplebe diff --git a/mapleall/maple_be/src/cg/riscv64/riscv64_dep_analysis.cpp b/mapleall/maple_be/src/cg/riscv64/riscv64_dep_analysis.cpp new file mode 100644 index 0000000..f0d22b4 --- /dev/null +++ b/mapleall/maple_be/src/cg/riscv64/riscv64_dep_analysis.cpp @@ -0,0 +1,909 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + + +#include "riscv64_cg.h" +#include "riscv64_operand.h" +#include "riscv64_dep_analysis.h" +#include "reg_pressure.h" +#include "special_func.h" + +namespace maplebe { + +/* constructor */ +Riscv64DepAnalysis::Riscv64DepAnalysis(CGFunc *func, MemPool *p, bool beforeRA) + : DepAnalysis(func, p, beforeRA), regDefs(nullptr), regUses(nullptr), + memBarInsn(nullptr), hasAmbiRegs(false), lastCallInsn(nullptr), separatorIndex(0), + useRegnos(), defRegnos(), stackUses(), stackDefs(), heapUses(), heapDefs(), + mayThrows(), ambiInsns(), ehInRegs() { + uint32 maxRegNum; + if (beforeRA) { + maxRegNum = cgfunc->GetMaxVReg(); + } else { + maxRegNum = kMaxRegNum; + } + + regDefs = mp->NewArray(maxRegNum); + regUses = mp->NewArray(maxRegNum); + useRegnos.reserve(Insn::kMaxOperandNum); + defRegnos.reserve(Insn::kMaxOperandNum); + mad = g->mad; +} + +// print dep node information +void Riscv64DepAnalysis::dumpDepNode(DepNode *node) { + CG_ASSERT(node, ""); + node->GetInsn()->dump(); + int num = node->GetUnitNum(); + LogInfo::MapleLogger() << "unit num : " << num << ", "; + for (int i = 0; i < num; i++) { + PRINT_VAL(node->GetUnitByIndex(i)->GetUnitId()); + } + LogInfo::MapleLogger() << endl; + node->DumpRegPressure(); +} + +// print dep link information +void Riscv64DepAnalysis::dumpDepLink(DepLink *link, DepNode *node) { + CG_ASSERT(link, ""); + PRINT_VAL(GetDepTypeName(link->GetDepType())); + PRINT_STR_VAL("Latency: ", link->GetLatency()); + if (node) { + node->GetInsn()->dump(); + } else { + LogInfo::MapleLogger() << "from : "; + link->GetFrom()->GetInsn()->dump(); + LogInfo::MapleLogger() << "to : "; + link->GetTo()->GetInsn()->dump(); + } +} + +/* Append use register to the list. */ +void Riscv64DepAnalysis::AppendRegUseList(Insn *insn, regno_t regno) { + RegList *regList = mp->New(); + regList->insn = insn; + regList->next = nullptr; + if (!regUses[regno]) { + regUses[regno] = regList; + } else { + RegList *lastRegList = regUses[regno]; + while (lastRegList->next) { + lastRegList = lastRegList->next; + } + lastRegList->next = regList; + } +} + +/* Add dependence edge. + Two dependence node has a unique edge. + True dependence overwirtes other dependences. + */ +void Riscv64DepAnalysis::AddDependence(DepNode *fromNode, DepNode *toNode, DepType tpy) { + // Can not build a self loop dependence. + if (fromNode == toNode) + return; + + // Check if exist edge. + if (!fromNode->GetSuccs().empty()) { + DepLink *depLink = fromNode->GetSuccs().back(); + if (depLink->GetTo() == toNode) { + if (depLink->GetDepType() != kDependenceTypeTrue) { + if (tpy == kDependenceTypeTrue) { + // Has exist edge, replace it. + depLink->SetDepType(kDependenceTypeTrue); + depLink->SetLatency(mad->GetLatency(fromNode->GetInsn(), toNode->GetInsn())); + return; + } + } + return; + } + } + + DepLink *depLink = mp->New(fromNode, toNode, tpy); + if (tpy == kDependenceTypeTrue) { + depLink->SetLatency(mad->GetLatency(fromNode->GetInsn(), toNode->GetInsn())); + } + fromNode->AddSucc(depLink); + toNode->AddPred(depLink); +} + +// Remove self dependence (self loop) in dependence graph. +void Riscv64DepAnalysis::RemoveSelfDeps(Insn *insn) { + DepNode *node = insn->depNode; + CG_ASSERT(node->GetSuccs().back()->GetTo()->GetInsn() == insn, "Is not a self dependence."); + CG_ASSERT(node->GetPreds().back()->GetFrom()->GetInsn() == insn, "Is not a self dependence."); + node->RemoveSucc(); + node->RemovePred(); +} + +/* Build dependences of source register operand. + */ +void Riscv64DepAnalysis::BuildDepsUseReg(Insn *insn, regno_t regno) { + if (!beforeRA) { + regno = cgfunc->AdjustRegno(regno); + } + useRegnos.push_back(regno); + if (regDefs[regno]) { + // Build true dependences. + AddDependence(regDefs[regno]->depNode, insn->depNode, kDependenceTypeTrue); + } +} + +/* Build dependences of destination register operand. + */ +void Riscv64DepAnalysis::BuildDepsDefReg(Insn *insn, regno_t regno) { + if (!beforeRA) { + regno = cgfunc->AdjustRegno(regno); + } + defRegnos.push_back(regno); + // Build anti dependences. + RegList *regList = regUses[regno]; + while (regList) { + AddDependence(regList->insn->depNode, insn->depNode, kDependenceTypeAnti); + regList = regList->next; + } + // Build output depnedence. + if (regDefs[regno]) { + AddDependence(regDefs[regno]->depNode, insn->depNode, kDependenceTypeOutput); + } +} + +/* Combine adrpldr&clinit_tail to clinit. + */ +void Riscv64DepAnalysis::CombineClinit(DepNode *firstNode, DepNode *secondNode, bool isAcrossSeparator) { + CG_ASSERT(firstNode->GetInsn()->GetMachineOpcode() == MOP_adrp_ldr, "first insn should be adrpldr"); + CG_ASSERT(secondNode->GetInsn()->GetMachineOpcode() == MOP_clinit_tail, "second insn should be clinit_tail"); + CG_ASSERT(firstNode->GetCfiInsns().empty(), "There should not be any comment/cfi instructions between clinit."); + CG_ASSERT(secondNode->GetComments().empty(), "There should not be any comment/cfi instructions between clinit."); + + Insn *newInsn = cgfunc->cg->BuildInstruction(MOP_clinit, + firstNode->GetInsn()->opnds[0], firstNode->GetInsn()->opnds[1]); + newInsn->id = firstNode->GetInsn()->id; + + // Replace first node with new insn. + firstNode->AddClinitInsn(firstNode->GetInsn()); + firstNode->AddClinitInsn(secondNode->GetInsn()); + firstNode->SetInsn(newInsn); + Reservation *rev = mad->FindReservation(newInsn); + CG_ASSERT(rev, "reservation is nullptr."); + firstNode->SetReservation(rev); + firstNode->SetUnits(firstNode->GetReservation()->GetUnit()); + firstNode->SetUnitNum(firstNode->GetReservation()->GetUnitNum()); + newInsn->depNode = firstNode; + firstNode->SetCfiInsns(secondNode->GetCfiInsns()); + + // Clear second node information. + newInsn = cgfunc->cg->BuildInstruction(MOP_pseudo_none); + newInsn->depNode = secondNode; + secondNode->SetInsn(newInsn); + secondNode->SetType(kNodeTypeEmpty); + secondNode->SetReservation(mad->FindReservation(newInsn)); + secondNode->SetUnitNum(0); + secondNode->ClearCfiInsns(); + secondNode->SetUnits(nullptr); + + CombineDependence(firstNode, secondNode, isAcrossSeparator); +} + +/* Combine two dependence nodes to one*/ +void Riscv64DepAnalysis::CombineDependence(DepNode *firstNode, DepNode *secondNode, bool isAcrossSeparator) { + if (isAcrossSeparator) { + // Clear all latency of the second node. + for (auto predLink : secondNode->GetPreds()) { + predLink->SetLatency(0); + } + for (auto succLink : secondNode->GetSuccs()) { + succLink->SetLatency(0); + } + } else { + std::set uniqueNodes; + + for (auto predLink : firstNode->GetPreds()) { + if (predLink->GetDepType() == kDependenceTypeTrue) { + predLink->SetLatency(mad->GetLatency(predLink->GetFrom()->GetInsn(), firstNode->GetInsn())); + } + uniqueNodes.insert(predLink->GetFrom()); + } + + for (auto predLink : secondNode->GetPreds()) { + if (predLink->GetFrom() != firstNode) { + if (uniqueNodes.insert(predLink->GetFrom()).second) { + AddDependence(predLink->GetFrom(), firstNode, predLink->GetDepType()); + } + } + predLink->SetLatency(0); + } + + uniqueNodes.clear(); + + for (auto succLink : firstNode->GetSuccs()) { + if (succLink->GetDepType() == kDependenceTypeTrue) { + succLink->SetLatency(mad->GetLatency(succLink->GetFrom()->GetInsn(), firstNode->GetInsn())); + } + uniqueNodes.insert(succLink->GetTo()); + } + + for (auto succLink : secondNode->GetSuccs()) { + if (uniqueNodes.insert(succLink->GetTo()).second) { + AddDependence(firstNode, succLink->GetTo(), succLink->GetDepType()); + } + succLink->SetLatency(0); + } + } +} + +/* Build dependences of ambiguous instruction. + ambiguous instruction : instructions that can not across may throw instructions. + */ +void Riscv64DepAnalysis::BuildDepsAmbiInsn(Insn *insn) { + for (auto throwInsn : mayThrows) { + AddDependence(throwInsn->depNode, insn->depNode, kDependenceTypeThrow); + } + ambiInsns.push_back(insn); +} + +/* Build dependences of may throw instructions. + */ +void Riscv64DepAnalysis::BuildDepsMayThrowInsn(Insn *insn) { + for (auto ambiInsn : ambiInsns) { + AddDependence(ambiInsn->depNode, insn->depNode, kDependenceTypeThrow); + } +} + +bool Riscv64DepAnalysis::IsFrameReg(const RegOperand *opnd) const { + return opnd->GetRegisterNumber() == RFP || opnd->GetRegisterNumber() == RSP; +} + +void Riscv64DepAnalysis::AllocateRegPressure(DepNode *node) { + RegPressure *regPressure = mp->New(mp); + node->SetRegPressure(regPressure); + if (regPressure) { + int *p = mp->NewArray(RegPressure::GetMaxRegClassNum()); + node->SetPressure(p); + } +} + +/* Build dependences of symbol memory access. + Memory access with symbol must be a heap memory access. + */ +void Riscv64DepAnalysis::BuildDepsAccessStImmMem(Insn *insn, bool isDest) { + if (isDest) { + // Heap memory + // Build anti dependences. + for (auto useInsn : heapUses) { + AddDependence(useInsn->depNode, insn->depNode, kDependenceTypeAnti); + } + // Build output depnedence. + for (auto defInsn : heapDefs) { + AddDependence(defInsn->depNode, insn->depNode, kDependenceTypeOutput); + } + heapDefs.push_back(insn); + } else { + // Heap memory + for (auto defInsn : heapDefs) { + AddDependence(defInsn->depNode, insn->depNode, kDependenceTypeTrue); + } + + heapUses.push_back(insn); + } + + if (memBarInsn) { + AddDependence(memBarInsn->depNode, insn->depNode, kDependenceTypeMembar); + } + +} + +/* Build dependences of stack memory and heap memory uses. + */ +void Riscv64DepAnalysis::BuildDepsUseMem(Insn *insn, MemOperand * memOpnd) { + RegOperand * baseRegister = memOpnd->GetBaseRegister(); + Riscv64MemOperand * aarchMemOpnd = static_cast(memOpnd); + + if ((baseRegister && IsFrameReg(baseRegister)) || aarchMemOpnd->IsStackMem()) { + // Stack memory address + for (auto defInsn : stackDefs) { + if (defInsn->IsCall()) { + AddDependence(defInsn->depNode, insn->depNode, kDependenceTypeTrue); + continue; + } + Operand *defOpnd = defInsn->GetMemOpnd(); + Riscv64MemOperand *defMemOpnd = static_cast(defOpnd); + if (!aarchMemOpnd->NoAlias(defMemOpnd)) { + AddDependence(defInsn->depNode, insn->depNode, kDependenceTypeTrue); + continue; + } + } + + stackUses.push_back(insn); + } else { + // Heap memory + for (auto defInsn : heapDefs) { + AddDependence(defInsn->depNode, insn->depNode, kDependenceTypeTrue); + } + + heapUses.push_back(insn); + } + + if (memBarInsn) { + AddDependence(memBarInsn->depNode, insn->depNode, kDependenceTypeMembar); + } +} + +/* Build dependences of stack memory and heap memory definitions. + */ +void Riscv64DepAnalysis::BuildDepsDefMem(Insn *insn, MemOperand * memOpnd) { + RegOperand * baseRegister = memOpnd->GetBaseRegister(); + Riscv64MemOperand * aarchMemOpnd = static_cast(memOpnd); + + if ((baseRegister && IsFrameReg(baseRegister)) || aarchMemOpnd->IsStackMem()) { + // Stack memory address + // Build anti dependences. + for (auto useInsn : stackUses) { + Operand *useOpnd = useInsn->GetMemOpnd(); + Riscv64MemOperand *useMemOpnd = static_cast(useOpnd); + if (!aarchMemOpnd->NoAlias(useMemOpnd)) { + AddDependence(useInsn->depNode, insn->depNode, kDependenceTypeAnti); + continue; + } + } + + // Build output depnedence. + for (auto defInsn : stackDefs) { + if (defInsn->IsCall()) { + AddDependence(defInsn->depNode, insn->depNode, kDependenceTypeOutput); + continue; + } + Operand *defOpnd = defInsn->GetMemOpnd(); + Riscv64MemOperand *defMemOpnd = static_cast(defOpnd); + if (!aarchMemOpnd->NoAlias(defMemOpnd)) { + AddDependence(defInsn->depNode, insn->depNode, kDependenceTypeOutput); + continue; + } + } + + if (lastCallInsn) { + // Build a dependence between stack passed arguments and call. + if (baseRegister->GetRegisterNumber() == RSP) + AddDependence(lastCallInsn->depNode, insn->depNode, kDependenceTypeControl); + } + stackDefs.push_back(insn); + } else { + // Heap memory + // Build anti dependences. + for (auto useInsn : heapUses) { + AddDependence(useInsn->depNode, insn->depNode, kDependenceTypeAnti); + } + // Build output depnedence. + for (auto defInsn : heapDefs) { + AddDependence(defInsn->depNode, insn->depNode, kDependenceTypeOutput); + } + + heapDefs.push_back(insn); + } + + if (memBarInsn) { + AddDependence(memBarInsn->depNode, insn->depNode, kDependenceTypeMembar); + } + + // Memory definition can not across may-throw insns. + for (auto mayThrowInsn : mayThrows) { + AddDependence(mayThrowInsn->depNode, insn->depNode, kDependenceTypeThrow); + } +} + +/* Build dependences of memory barrior instructions. + */ +void Riscv64DepAnalysis::BuildDepsMemBar(Insn *insn) { + for (auto i : stackUses) { + if (insn != i) + AddDependence(i->depNode, insn->depNode, kDependenceTypeMembar); + } + for (auto i : heapUses) { + if (insn != i) + AddDependence(i->depNode, insn->depNode, kDependenceTypeMembar); + } + for (auto i : stackDefs) { + if (insn != i) + AddDependence(i->depNode, insn->depNode, kDependenceTypeMembar); + } + for (auto i : heapDefs) { + if (insn != i) + AddDependence(i->depNode, insn->depNode, kDependenceTypeMembar); + } + memBarInsn = insn; +} + +/* A pseudo separator node depends all the other nodes. */ +void Riscv64DepAnalysis::BuildDepsSeparator(DepNode *newSepNode, vector &nodes) { + uint32 nextSepIndex = (separatorIndex + kMaxDependenceNum) < nodes.size() + ? (separatorIndex + kMaxDependenceNum) + : nodes.size() - 1; + for (int i = separatorIndex; i < nextSepIndex; i++) { + AddDependence(nodes[i], newSepNode, kDependenceTypeSeparator); + } +} + +/* Build control dependence for branch/ret instructions. + */ +void Riscv64DepAnalysis::BuildDepsControlAll(DepNode *depNode, vector& nodes) { + for (int i = separatorIndex; i < depNode->GetIndex(); i++) { + AddDependence(nodes[i], depNode, kDependenceTypeControl); + } +} + +/* Build dependences of call instructions. + Caller-saved physical registers will defined by a call instruction. + Also a conditional register may modified by a call. + */ +void Riscv64DepAnalysis::BuildCallerSavedDeps(Insn *insn) { + // Build anti dependence and output dependence. + for (int i = R0; i <= R7; i++) { + BuildDepsDefReg(insn, i); + } + + for (int i = V0; i <= V7; i++) { + BuildDepsDefReg(insn, i); + } + + if (beforeRA) { + BuildDepsDefReg(insn, RSP); + } else { + for (int i = R8; i <= R18; i++) { + BuildDepsDefReg(insn, i); + } + for (int i = R29; i <= RSP; i++) { + BuildDepsUseReg(insn, i); + } + for (int i = V16; i <= V31; i++) { + BuildDepsDefReg(insn, i); + } + } +} + +/* Build dependence between control register and last call instruction. + insn : instruction that with control register operand. + isDest : if the control register operand is a destination operand. + */ +void Riscv64DepAnalysis::BuildDepsBetweenControlRegAndCall(Insn *insn, bool isDest) { + if (lastCallInsn) { + if (isDest) { + AddDependence(lastCallInsn->depNode, insn->depNode, kDependenceTypeOutput); + } else { + AddDependence(lastCallInsn->depNode, insn->depNode, kDependenceTypeAnti); + } + } +} + +struct OperandCmp{ + bool operator() (Operand * lhs, Operand * rhs) const { + return (lhs->Less(rhs)); + } +}; + +void Riscv64DepAnalysis::BuildStackPassArgsDeps(Insn * insn) { + for (auto stackDefInsn : stackDefs) { + Operand *opnd = stackDefInsn->GetMemOpnd(); + CG_ASSERT(opnd->IsMemoryAccessOperand(), ""); + + MemOperand *memOpnd = static_cast(opnd); + RegOperand *baseReg = memOpnd->GetBaseRegister(); + if (baseReg && (baseReg->GetRegisterNumber() == RSP)) + AddDependence(stackDefInsn->depNode, insn->depNode, kDependenceTypeControl); + } +} + +// Some insns may dirty all stack memory, such as "bl MCC_InitializeLocalStackRef". +void Riscv64DepAnalysis::BuildDepsDirtyStack(Insn * insn) { + // Build anti dependences. + for (auto useInsn : stackUses) { + AddDependence(useInsn->depNode, insn->depNode, kDependenceTypeAnti); + } + // Build output depnedence. + for (auto defInsn : stackDefs) { + AddDependence(defInsn->depNode, insn->depNode, kDependenceTypeOutput); + } + + stackDefs.push_back(insn); +} + +// Some call insns may use all stack memory, such as "bl MCC_CleanupLocalStackRef_NaiveRCFast". +void Riscv64DepAnalysis::BuildDepsUseStack(Insn * insn) { + // Build true dependences. + for (auto defInsn : stackDefs) { + AddDependence(defInsn->depNode, insn->depNode, kDependenceTypeTrue); + } +} + +// Some insns may dirty all heap memory, such as a call insn. +void Riscv64DepAnalysis::BuildDepsDirtyHeap(Insn * insn) { + // Build anti dependences. + for (auto useInsn : heapUses) { + AddDependence(useInsn->depNode, insn->depNode, kDependenceTypeAnti); + } + // Build output depnedence. + for (auto defInsn : heapDefs) { + AddDependence(defInsn->depNode, insn->depNode, kDependenceTypeOutput); + } + + heapDefs.push_back(insn); +} + +// Build a pseudo node to seperate dependence graph. +DepNode *Riscv64DepAnalysis::BuildSeparatorNode() { + Insn *pseudoSepInsn = cgfunc->cg->BuildInstruction(MOP_pseudo_dependence_seperator); + DepNode *separatorNode= mp->New(pseudoSepInsn); + separatorNode->SetType(kNodeTypeSeparator); + return separatorNode; +} + +void Riscv64DepAnalysis::Init(BB *bb, vector &nodes) { + uint32 maxRegNum; + if (beforeRA) { + maxRegNum = cgfunc->GetMaxVReg(); + } else { + maxRegNum = kMaxRegNum; + } + + memset_s(regDefs, sizeof(Insn *) * maxRegNum, 0, sizeof(Insn *) * maxRegNum); + memset_s(regUses, sizeof(RegList *) * maxRegNum, 0, sizeof(RegList *) * maxRegNum); + memBarInsn = nullptr; + lastCallInsn = nullptr; + + stackUses.clear(); + stackDefs.clear(); + heapUses.clear(); + heapDefs.clear(); + mayThrows.clear(); + ambiInsns.clear(); + lastComments.clear(); + + // Analysis live-in registers in catch BB. + AnalysisAmbiInsns(bb); + + // Clear all dependence nodes and push the first separator node. + nodes.clear(); + DepNode *separatorNode = BuildSeparatorNode(); + AllocateRegPressure(separatorNode); + nodes.push_back(separatorNode); + + separatorIndex = 0; +} + +/* When a separator build, it is the same as a new basic block. */ +void Riscv64DepAnalysis::ClearAllDepData() { + uint32 maxRegNum; + if (beforeRA) { + maxRegNum = cgfunc->GetMaxVReg(); + } else { + maxRegNum = kMaxRegNum; + } + + memset_s(regDefs, sizeof(Insn *) * maxRegNum, 0, sizeof(Insn *) * maxRegNum); + memset_s(regUses, sizeof(RegList *) * maxRegNum, 0, sizeof(RegList *) * maxRegNum); + memBarInsn = nullptr; + lastCallInsn = nullptr; + + stackUses.clear(); + stackDefs.clear(); + heapUses.clear(); + heapDefs.clear(); + mayThrows.clear(); + ambiInsns.clear(); +} + +/* Analysis live-in registers in catch bb and cleanup bb.*/ +void Riscv64DepAnalysis::AnalysisAmbiInsns(BB *bb) { + hasAmbiRegs = false; + + if (bb->eh_succs.empty()) { + return; + } + + // Union all catch bb + set ordered; + for (auto succBb : bb->eh_succs) { + ordered.insert(succBb->livein_regno.begin(), succBb->livein_regno.end()); + set_union(ordered.begin(), ordered.end(), + ehInRegs.begin(), ehInRegs.end(), + inserter(ehInRegs, ehInRegs.begin())); + ordered.clear(); + } + + // Union cleanup entry bb. + ordered.insert(cgfunc->cleanupEntrybb->livein_regno.begin(), cgfunc->cleanupEntrybb->livein_regno.end()); + set_union(ordered.begin(), ordered.end(), + ehInRegs.begin(), ehInRegs.end(), + inserter(ehInRegs, ehInRegs.begin())); + + // Subtract R0 and R1, that is defined by eh runtime. + ehInRegs.erase(R0); + ehInRegs.erase(R1); + + if (ehInRegs.empty()) { + return; + } + + hasAmbiRegs = true; + return; +} + +/* Check if regno is in ehInRegs. */ +bool Riscv64DepAnalysis::IfInAmbiRegs(regno_t regno) const { + if (!hasAmbiRegs) + return false; + + if (ehInRegs.find(regno) != ehInRegs.end()) { + return true; + } + + return false; +} + +/* Build dependence graph. + 1: Build dependence nodes. + 2: Build edges between dependence nodes. Edges are: + 2.1) True dependences + 2.2) Anti dependences + 2.3) Output dependences + 2.4) Barrier dependences + */ +void Riscv64DepAnalysis::Run(BB *bb, vector& nodes) { + // Initial internal datas. + Init(bb, nodes); + + uint32 nodeSum = 1; + std::vector comments; + // Loads that cannot move across calls, unless alias info tells otherwise. + std::vector loads; + + FOR_BB_INSNS(insn, bb) { + if( !insn->IsMachineInstruction()) { + if (insn->IsComment()) { + comments.push_back(insn); + } else if (insn->IsCfiInsn()) { + nodes.back()->AddCfiInsn(insn); + } + continue; + } + + if (nodeSum > 0 && nodeSum % kMaxDependenceNum == 0) { + CG_ASSERT(nodeSum == nodes.size(), "CG internal error, nodeSum should equal to nodes.size."); + // Add a pseudo node to seperate dependence graph. + DepNode *separatorNode = BuildSeparatorNode(); + AllocateRegPressure(separatorNode); + separatorNode->SetIndex(nodeSum); + nodes.push_back(separatorNode); + BuildDepsSeparator(separatorNode, nodes); + ClearAllDepData(); + separatorIndex = nodeSum++; + // Only preventing loads crossing call from the same separattor group + loads.clear(); + } + + DepNode * depNode = nullptr; + Reservation *rev = mad->FindReservation(insn); + CG_ASSERT(rev, "rev is nullptr"); + depNode= mp->New(insn, rev->GetUnit(), rev->GetUnitNum(), rev); + AllocateRegPressure(depNode); + /* + RegPressure *regPressure = mp->New(mp); + depNode->SetRegPressure(regPressure); + if (regPressure) { + int *p = mp->NewArray(RegPressure::GetMaxRegClassNum()); + depNode->SetPressure(p); + //RegPressure *p = mp->New(); + //depNode->SetRegPressure(p); + } + */ + depNode->SetIndex(nodeSum); + nodes.push_back(depNode); + nodeSum++; + insn->depNode = depNode; + + if (!comments.empty()) { + depNode->SetComments(comments); + comments.clear(); + } + + bool isMayThrowInsn = insn->MayThrow(); + if (isMayThrowInsn) { + BuildDepsMayThrowInsn(insn); + } + const Riscv64MD* md = &Riscv64CG::kMd[static_cast(insn)->mop_]; + MOperator mop = insn->GetMachineOpcode(); + + useRegnos.clear(); + defRegnos.clear(); + + for (int i = 0; i < Insn::kMaxOperandNum; i++) { + Operand* opnd = insn->opnds[i]; + if (opnd == nullptr) + continue; + + Riscv64OpndProp* regprop = static_cast(md->operand_[i]); + + if (opnd->IsMemoryAccessOperand()) { + Riscv64MemOperand *memopnd = static_cast(opnd); + RegOperand * baseRegister = memopnd->GetBaseRegister(); + if (baseRegister) { + regno_t regno = baseRegister->GetRegisterNumber(); + BuildDepsUseReg(insn, regno); + } + RegOperand * indexRegister = memopnd->GetIndexRegister(); + if (indexRegister) { + regno_t regno = indexRegister->GetRegisterNumber(); + BuildDepsUseReg(insn, regno); + } + + if (regprop->IsUse()) { + BuildDepsUseMem(insn, memopnd); + } else { + BuildDepsDefMem(insn, memopnd); + BuildDepsAmbiInsn(insn); + } + + if (insn->IsMemAccessBar()) { + BuildDepsMemBar(insn); + } + } else if (opnd->IsStImmediate()) { + if (mop != MOP_adrpl12) { + BuildDepsAccessStImmMem(insn, false); + } + } else if (opnd->IsRegister()) { + RegOperand *regOpnd = static_cast(opnd); + regno_t regno = regOpnd->GetRegisterNumber(); + + if (regprop->IsUse()) { + BuildDepsUseReg(insn, regno); + } + + if (regprop->IsDef()) { + BuildDepsDefReg(insn, regno); + } + } else if (opnd->IsConditionCode()) { + // For condition operand, such as NE, EQ, and so on. +// if (regprop->IsUse()) { +// BuildDepsUseReg(insn, RFLAG); +// BuildDepsBetweenControlRegAndCall(insn, false); +// } + +// if (regprop->IsDef()) { +// BuildDepsDefReg(insn, RFLAG); +// BuildDepsBetweenControlRegAndCall(insn, true); +// } + } else if (opnd->IsList()) { + ListOperand *listOpnd = static_cast(opnd); + // Build true dependences + for (auto lst : listOpnd->GetOperands()) { + regno_t regno = lst->GetRegisterNumber(); + BuildDepsUseReg(insn, regno); + } + } + } + + if (insn->IsCall() || insn->IsTailCall()) { + // Caller saved registers. + BuildCallerSavedDeps(insn); + BuildStackPassArgsDeps(insn); + + int dirtyHeap = true; + if (mop == MOP_xbl) { + FuncNameOperand *target = static_cast(insn->opnds[0]); + if (target->GetName() == GetIntrinsicFuncName(INTRN_MCCInitializeLocalStackRef)) { + // Write stack memory. + BuildDepsDirtyStack(insn); + dirtyHeap = false; + } else if (IsRtCleanupLocalStackCall(target->GetName())) { + // UseStackMemory. + BuildDepsUseStack(insn); + } + } + + if (dirtyHeap) { + BuildDepsDirtyHeap(insn); + } + + if (lastCallInsn) { + AddDependence(lastCallInsn->depNode, insn->depNode, kDependenceTypeControl); + } + for (auto ldInsn: loads) { + AddDependence(ldInsn->depNode, insn->depNode, kDependenceTypeAnti); + } + loads.clear(); + lastCallInsn = insn; + } else if (mop == MOP_clinit_tail || mop == MOP_clinit) { +// BuildDepsDirtyHeap(insn); +// BuildDepsDefReg(insn, RFLAG); + } else if (mop == MOP_xret || md->IsBranch()) { + BuildDepsControlAll(depNode, nodes); + } + + for (auto regno : defRegnos) { + if (IfInAmbiRegs(regno)) { + BuildDepsAmbiInsn(insn); + break; + } + } + + if (isMayThrowInsn) { + mayThrows.push_back(insn); + if (insn->IsLoad()) { + loads.push_back(insn); + } + + for (auto stackDefInsn : stackDefs) { + AddDependence(stackDefInsn->depNode, insn->depNode, kDependenceTypeThrow); + } + + for (auto heapDefInsn : heapDefs) { + AddDependence(heapDefInsn->depNode, insn->depNode, kDependenceTypeThrow); + } + } + + // Seperator exists. + AddDependence(nodes[separatorIndex], insn->depNode, kDependenceTypeSeparator); + + for (auto regno : useRegnos) { + AppendRegUseList(insn, regno); + depNode->AddUseReg(regno); + depNode->SetRegUses(regno, regUses[regno]); + } + for (auto regno : defRegnos) { + regDefs[regno] = insn; + regUses[regno] = nullptr; + depNode->AddDefReg(regno); + } + } + + DepNode * separatorNode = BuildSeparatorNode(); + AllocateRegPressure(separatorNode); + nodes.push_back(separatorNode); + BuildDepsSeparator(separatorNode, nodes); + + + if (!comments.empty()) { + lastComments = comments; + } + + comments.clear(); + +} + +// return dependence type name +std::string Riscv64DepAnalysis::GetDepTypeName(DepType depType) { + CG_ASSERT(depType <= kDependenceTypeNone, ""); + switch (depType) { + case kDependenceTypeTrue: + return "true-dep"; + case kDependenceTypeOutput: + return "output-dep"; + case kDependenceTypeAnti: + return "anti-dep"; + case kDependenceTypeControl: + return "control-dep"; + case kDependenceTypeMembar: + return "membar-dep"; + case kDependenceTypeThrow: + return "throw-dep"; + case kDependenceTypeNone: + return "none-dep"; + default: + return "none"; + } +} + +} // namespace maplebe + + diff --git a/mapleall/maple_be/src/cg/riscv64/riscv64_ebo.cpp b/mapleall/maple_be/src/cg/riscv64/riscv64_ebo.cpp new file mode 100644 index 0000000..1ea1c19 --- /dev/null +++ b/mapleall/maple_be/src/cg/riscv64/riscv64_ebo.cpp @@ -0,0 +1,994 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#include "riscv64_ebo.h" +#include "riscv64_cg.h" +#include "cg_assert.h" +namespace maplebe { + +using namespace maple; +#define EBODUMP CGDEBUGFUNC(cgfunc) + +// return the regno of the low 32bit. e.g opnd= d10, return v10.s[0] +regno_t Riscv64Ebo::GetLowVec(Operand *opnd) { + CG_ASSERT(opnd && opnd->IsRegister(), ""); + regno_t regno = static_cast(opnd)->GetRegisterNumber(); + return regno - V0 + VB32; +} + +// return the regno of the high 32bit. e.g opnd= d10, return v10.s[1] +regno_t Riscv64Ebo::GetHighVec(Operand *opnd) { + CG_ASSERT(opnd && opnd->IsRegister(), ""); + regno_t regno = static_cast(opnd)->GetRegisterNumber(); + return regno - V0 + VB64; +} + +bool Riscv64Ebo::IsFloatReg(RegOperand *regopnd) { + regno_t regno = regopnd->GetRegisterNumber(); + return (regno >= V0 && regno <= V31); +} + +bool Riscv64Ebo::IsFmov(Insn *insn) { + return (insn->mop_ >= MOP_xvmovsr && insn->mop_ <= MOP_xvmovrd); +} + +void Riscv64Ebo::SetOpnd(Insn *insn, int i, Operand *opnd) { + if (insn->IsDestRegAlsoSrcReg()) { + insn->SetOperand(i, opnd); + return; + } + const Riscv64MD *md = &Riscv64CG::kMd[insn->mop_]; + if (md->IsStore()) { + insn->SetOperand(i, opnd); + } else { + insn->SetOperand(insn->GetResultNum() + i, opnd); + } +} + +bool Riscv64Ebo::IsAdd(Insn *insn) { + return (insn->mop_ >= MOP_xaddrrr && insn->mop_ <= MOP_ssub); +} + +bool Riscv64Ebo::IsVecReg(Operand *opnd) { + if (!opnd->IsRegister()) { + return false; + } + Riscv64RegOperand *a64reg = static_cast(opnd); + return a64reg->IsSimdVectorMode(); +} + +bool Riscv64Ebo::IsZeroRegister(Operand *opnd) { + if (!opnd->IsRegister()) { + return false; + } + Riscv64RegOperand *aarreg = static_cast(opnd); + return aarreg->IsZeroRegister(); +} + +bool Riscv64Ebo::IsImplicit(Insn *insn) { + const Riscv64MD *md = &Riscv64CG::kMd[static_cast(insn)->mop_]; + if (md->IsCondDef()) { + return true; + } + for (uint32_t i = 0; i < Riscv64Insn::kMaxOperandNum; i++) { + Operand *op = insn->GetOperand(i); + if (op && op->IsConditionCode()) { + return true; + } + } + return false; +} + +bool Riscv64Ebo::IsClinitCheck(Insn *insn) { + if (insn == nullptr) { + return false; + } + MOperator mop = insn->GetMachineOpcode(); + return mop == MOP_clinit || mop == MOP_clinit_tail; +} + +void Riscv64Ebo::InitCallerSaveRegisters() { + if (initCallerSaveRegs) { + return; + } + initCallerSaveRegs = true; + Riscv64CGFunc *a64cgfunc = static_cast(cgfunc); + for (int i = R1; i <= R31; i++) { + if (Riscv64Abi::IsCalleeSavedReg((Riscv64reg_t)i)) { + continue; + } + regOperand[i] = a64cgfunc->GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)i, 64, kRegTyInt); + } + for (int i = V0; i <= V31; i++) { + if (Riscv64Abi::IsCalleeSavedReg((Riscv64reg_t)i)) { + continue; + } + regOperand[i] = a64cgfunc->GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)i, 64, kRegTyFloat); + } +} + +void Riscv64Ebo::InitCallAndReturnUseRegisters() { + if (initCallAndReturnRegs) { + return; + } + initCallAndReturnRegs = true; + Riscv64CGFunc *a64cgfunc = static_cast(cgfunc); + for (int i = R1; i <= R31; i++) { + if (Riscv64Abi::IsCalleeSavedReg((Riscv64reg_t)i) == false) { + continue; + } + regOperand[i] = a64cgfunc->GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)i, 64, kRegTyInt); + } + for (int i = V0; i <= V31; i++) { + if (Riscv64Abi::IsCalleeSavedReg((Riscv64reg_t)i) == false) { + continue; + } + regOperand[i] = a64cgfunc->GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)i, 64, kRegTyFloat); + } + regOperand[RSP] = a64cgfunc->GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)RSP, 64, kRegTyInt); +} + +void Riscv64Ebo::DefineClinitSpecialRegisters(InsnInfo *insninfo) { + Insn *insn = insninfo->insn; + RegOperand *phyopnd; + InitCallerSaveRegisters(); + phyopnd = regOperand[R16]; + OpndInfo *opndinfo = OperandInfoDef(insn->bb, insn, phyopnd); + opndinfo->insninfo = insninfo; + + phyopnd = regOperand[R17]; + opndinfo = OperandInfoDef(insn->bb, insn, phyopnd); + opndinfo->insninfo = insninfo; +} + +void Riscv64Ebo::DefineCallerSaveRegisters(InsnInfo *insninfo) { + RegOperand *phyopnd = nullptr; + Insn *insn = insninfo->insn; + + CG_ASSERT(insn->IsCall(), "insn should be a call insn."); + + // Define return register. + Riscv64CGFunc *a64cgfunc = static_cast(cgfunc); + InitCallerSaveRegisters(); + phyopnd = regOperand[Riscv64Abi::kIntRetReg0]; + OpndInfo *opndinfo = OperandInfoDef(insn->bb, insn, phyopnd); + opndinfo->insninfo = insninfo; + + phyopnd = regOperand[Riscv64Abi::kFpRetReg0]; + opndinfo = OperandInfoDef(insn->bb, insn, phyopnd); + opndinfo->insninfo = insninfo; + + // Define scalar caller save register. + for (int i = R1; i <= R31; i++) { + if (Riscv64Abi::IsCalleeSavedReg((Riscv64reg_t)i)) { + continue; + } + phyopnd = regOperand[i]; + opndinfo = OperandInfoDef(insn->bb, insn, phyopnd); + opndinfo->insninfo = insninfo; + } + + // Define FP caller save registers. + for (int i = V0; i <= V31; i++) { + if (Riscv64Abi::IsCalleeSavedReg((Riscv64reg_t)i)) { + continue; + } + phyopnd = regOperand[i]; + opndinfo = OperandInfoDef(insn->bb, insn, phyopnd); + opndinfo->insninfo = insninfo; + } +} + +void Riscv64Ebo::DefineReturnUseRegister(Insn *insn) { + RegOperand *phyopnd = nullptr; + + // Define return register. + Riscv64CGFunc *a64cgfunc = static_cast(cgfunc); + InitCallAndReturnUseRegisters(); + + // Define scalar callee save register and FP, LR. + for (int i = R1; i <= R31; i++) { + if (Riscv64Abi::IsCalleeSavedReg((Riscv64reg_t)i) == false) { + continue; + } + phyopnd = regOperand[i]; + OperandInfoUse(insn->bb, insn, phyopnd); + } + + // Define SP + phyopnd = regOperand[RSP]; + OperandInfoUse(insn->bb, insn, phyopnd); + + // Define FP caller save registers. + for (int i = V0; i <= V31; i++) { + if (Riscv64Abi::IsCalleeSavedReg((Riscv64reg_t)i) == false) { + continue; + } + phyopnd = regOperand[i]; + OperandInfoUse(insn->bb, insn, phyopnd); + } +} + +void Riscv64Ebo::DefineCallUseSpecialRegister(Insn *insn) { + RegOperand *phyopnd = nullptr; + + // Define return register. + InitCallAndReturnUseRegisters(); + + // Define FP, LR. + phyopnd = regOperand[R1]; + OperandInfoUse(insn->bb, insn, phyopnd); + phyopnd = regOperand[R8]; + OperandInfoUse(insn->bb, insn, phyopnd); + + // Define SP + phyopnd = regOperand[RSP]; + OperandInfoUse(insn->bb, insn, phyopnd); +} + +/*return true if op1 == op2*/ +bool Riscv64Ebo::OperandEqSpecial(Operand *op1, Operand *op2) { + switch (op1->GetKind()) { + case Operand::Opd_Register: { + Riscv64RegOperand *reg1 = static_cast(op1); + Riscv64RegOperand *reg2 = static_cast(op2); + return (*reg1) == (*reg2); + } + case Operand::Opd_Immediate: { + ImmOperand *imm1 = static_cast(op1); + ImmOperand *imm2 = static_cast(op2); + return (*imm1) == (*imm2); + } + case Operand::Opd_OfstImmediate: { + Riscv64OfstOperand *ofst1 = static_cast(op1); + Riscv64OfstOperand *ofst2 = static_cast(op2); + return (*ofst1) == (*ofst2); + } + case Operand::Opd_StImmediate: { + StImmOperand *stimm1 = static_cast(op1); + StImmOperand *stimm2 = static_cast(op2); + return (*stimm1) == (*stimm2); + } + case Operand::Opd_Mem: { + Riscv64MemOperand *mem1 = static_cast(op1); + Riscv64MemOperand *mem2 = static_cast(op2); + return (OperandEqual(mem1->GetBaseRegister(), mem2->GetBaseRegister()) && + OperandEqual(mem1->GetIndexRegister(), mem2->GetIndexRegister()) && + OperandEqual(mem1->GetOffsetOperand(), mem2->GetOffsetOperand()) && + (mem1->GetSymbol() == mem2->GetSymbol()) && (mem1->GetSize() == mem2->GetSize())); + } + default: { + return false; + } + } + return false; +} + +int32_t Riscv64Ebo::GetOffsetVal(MemOperand *mem) { + Riscv64MemOperand *memopnd = static_cast(mem); + Riscv64OfstOperand *offset = memopnd->GetOffsetImmediate(); + int32_t val = 0; + if (offset) { + val += offset->GetOffsetValue(); + + if (offset->op_kind_ == Operand::Opd_StImmediate) { + val += ((StImmOperand *)offset)->GetSymbol()->GetStIdx().Idx(); + } + } + return val; +} + +/* + *move vreg, 0 + *store vreg, mem + *===> + *store wzr, mem + *return true if do simplify successfully. + */ +bool Riscv64Ebo::DoConstProp(Insn *insn, int idx, Operand *opnd) { + Riscv64ImmOperand *src = static_cast(opnd); + // move vreg, 0 + // store vreg, mem + // ===> + // store wzr, mem + CG_ASSERT(insn->GetOpnd(idx), ""); + const Riscv64MD *md = &Riscv64CG::kMd[(insn->mop_)]; + // avoid the invalid case "cmp wzr, #0"/"add w1, wzr, #100" + if (src->IsZero() && insn->GetOpnd(idx)->IsRegister() && (insn->IsStore() || insn->IsMove() || md->IsCondDef())) { + SetOpnd(insn, idx, GetZeroOpnd(src->GetSize())); + return true; + } + MOperator mopcode = insn->GetMachineOpcode(); + switch (mopcode) { + case MOP_xiorrrr: { + if (src->GetValue() == 0) { + insn->mop_ = MOP_xiorrri13; + src->SetSize(12); + insn->SetOperand(idx + 1, src); + return true; + } + break; + } + case MOP_xmovrr: + case MOP_wmovrr: { + if (idx != 0) { + return false; + } + uint32_t targetSize = insn->GetOpnd(idx)->GetSize(); + if (src->GetSize() != targetSize) { + src = static_cast(src->Clone(cgfunc->memPool)); + CG_ASSERT(src != nullptr, ""); + src->size_ = targetSize; + } + if (static_cast(src)->IsInBitSize(11)) { + if (EBODUMP) { + LogInfo::MapleLogger() << " Do constprop:Prop constVal " << src->GetValue() << "into insn:\n"; + insn->dump(); + } + insn->SetOperand(1, src); + MOperator mop; + if (src->isUpperBits) { + mop = (mopcode == MOP_wmovrr) ? MOP_xmov20up : MOP_xmov52up; + } else { + mop = MOP_xmovri64; + } + insn->mop_ = mop; + if (EBODUMP) { + LogInfo::MapleLogger() << " after constprop the insn is:\n"; + insn->dump(); + } + return true; + } + break; + } + case MOP_xaddrrr: + case MOP_waddrrr: + case MOP_xsubrrr: + case MOP_wsubrrr: { + if (idx != 1 || !(src->IsInBitSize(11))) { + return false; + } + if (insn->GetResult(0) == nullptr) { + return false; + } + const Riscv64MD *md = &Riscv64CG::kMd[static_cast(insn)->mop_]; + bool is64bits = md->Is64Bit(); + if (EBODUMP) { + LogInfo::MapleLogger() << " Do constprop:Prop constVal " << src->GetValue() << "into insn:\n"; + insn->dump(); + } + if (src->IsZero() && src->IsVary() == false) { + insn->SetOperand(2, nullptr); + insn->mop_ = MOP_xmovrr; + if (EBODUMP) { + LogInfo::MapleLogger() << " after constprop the insn is:\n"; + insn->dump(); + } + return true; + } + insn->SetOperand(2, src); + if (mopcode == MOP_xaddrrr || mopcode == MOP_waddrrr) { + insn->mop_ = is64bits ? MOP_xaddrri12 : MOP_waddrri12; + } else if (mopcode == MOP_xsubrrr || mopcode == MOP_wsubrrr) { + insn->mop_ = is64bits ? MOP_xsubrri12 : MOP_wsubrri12; + } + if (EBODUMP) { + LogInfo::MapleLogger() << " after constprop the insn is:\n"; + insn->dump(); + } + return true; + break; + } + default: + break; + } + return false; +} + +/* + * Look at an exression that has a constant second operand and attempt to + * simplify the computations. + */ +bool Riscv64Ebo::ConstantOperand(Insn *insn, Operand **opnds, OpndInfo **opndInfo) { + BB *bb = insn->bb; + bool retval = false; + if (insn->GetOpndNum() < 1) { + return false; + } + Operand *op0 = opnds[0]; + Operand *op1 = opnds[1]; + Operand *res = insn->GetResult(0); + CHECK_FATAL(res, "null ptr check"); + const Riscv64MD *md = &Riscv64CG::kMd[static_cast(insn)->mop_]; + uint32_t dsize = md->GetOperandSize(); + bool first = op0->IsConstant() && !op1->IsConstant(); + CG_ASSERT((op1->IsConstant() && !op0->IsConstant()) || (op0->IsConstant() && !op1->IsConstant()), ""); + Riscv64ImmOperand *imm = nullptr; + Operand *op = nullptr; + int32_t idx0 = 0; + if (first) { + imm = static_cast(op0); + op = op1; + if (op->IsMemoryAccessOperand()) { + op = insn->GetOpnd(1); + } + idx0 = 1; + } else { + imm = static_cast(op1); + op = op0; + if (op->IsMemoryAccessOperand()) { + op = insn->GetOpnd(0); + } + } + // For orr insn and one of the opnd is zero + if (insn->GetMachineOpcode() == MOP_xiorrri13 && imm->IsZero()) { + bb->ReplaceInsn(insn, cgfunc->cg->BuildInstruction(dsize == 64 ? MOP_xmovrr : MOP_wmovrr, res, op)); + return true; + } + // For the imm is 0. Then replace the insn by a move insn. + if ((insn->GetMachineOpcode() >= MOP_xaddrrr && insn->GetMachineOpcode() <= MOP_sadd && imm->IsZero()) || + (!first && insn->GetMachineOpcode() >= MOP_xsubrrr && insn->GetMachineOpcode() <= MOP_ssub && imm->IsZero())) { + bb->ReplaceInsn(insn, cgfunc->cg->BuildInstruction(dsize == 64 ? MOP_xmovrr : MOP_wmovrr, res, op)); + return true; + } + + if (insn->GetMachineOpcode() == MOP_xaddrrr || insn->GetMachineOpcode() == MOP_waddrrr) { +// if (imm->IsInBitSize(24)) { + // ADD Wd|WSP, Wn|WSP, #imm{, shift} ; 32-bit general registers + // ADD Xd|SP, Xn|SP, #imm{, shift} ; 64-bit general registers + // imm : 0 ~ 4095, shift: none, LSL #0, or LSL #12 + // riscv64 assembly takes up to 24-bits, if the lower 12 bits is all 0 + if (imm->IsInBitSize(11)) { + bb->ReplaceInsn( + insn, cgfunc->cg->BuildInstruction(dsize == 64 ? MOP_xaddrri12 : MOP_waddrri12, res, op, imm)); + retval = true; + } +// } + } + // Look for the sequence which can be simpified. + if (retval == true || insn->GetMachineOpcode() == MOP_xaddrri12 || insn->GetMachineOpcode() == MOP_waddrri12) { + Insn *prev = opndInfo[idx0]->insn; + if (prev != nullptr && (prev->GetMachineOpcode() == MOP_xaddrri12 || prev->GetMachineOpcode() == MOP_waddrri12)) { + OpndInfo *previnfo0 = opndInfo[idx0]->insninfo->orig_opnd[0]; + // if prevop0 has been redefined. skip this optimiztation. + if (previnfo0->redefined) { + return retval; + } + Operand *prevop0 = prev->GetOpnd(0); + Riscv64ImmOperand *imm0 = static_cast(prev->GetOpnd(1)); + CHECK_FATAL(imm0 != nullptr, "imm0 is null in Riscv64Ebo::ConstantOperand "); + int64_t val = imm0->GetValue() + imm->GetValue(); + Riscv64CGFunc *aarchfunc = static_cast(cgfunc); + Riscv64ImmOperand *imm1 = aarchfunc->CreateImmOperand(val, dsize, imm0->IsSignedValue()); + if (imm0->IsVary()) { + imm1->SetVary(true); + } + if (imm1->IsInBitSize(11)) { + bb->ReplaceInsn(insn, cgfunc->cg->BuildInstruction(dsize == 64 ? MOP_xaddrri12 : MOP_waddrri12, + res, prevop0, imm1)); + retval = true; + } + } + } + return retval; +} + +/* + * Try to evaluate the condition of a branch when it's const. + * For CGIR conditonal branch has two insns. + */ +bool Riscv64Ebo::ResoveCondBranch(Insn *insn, Operand **opnds) { + BB *bb = insn->bb; + // Only concern with conditional branch. + if (bb == nullptr || bb->succs.size() != 2) { + return false; + } + return false; +} + +/* Do some special pattern*/ +bool Riscv64Ebo::SpecialSequence(Insn *insn, Operand **opnds, OpndInfo **origInfo) { + if (insn == nullptr) { + return false; + } + MOperator opc = insn->GetMachineOpcode(); + Riscv64CGFunc *aarchfunc = static_cast(cgfunc); + switch (opc) { + // mov R503, R0 + // mov R0, R503 + // ==> mov R0, R0 + case MOP_wmovrr: + case MOP_xmovrr: { + OpndInfo *opndinfo = origInfo[0]; + if (opndinfo == nullptr) { + return false; + } + Insn *prevInsn = origInfo[0]->insn; + if (prevInsn && (prevInsn->GetMachineOpcode() == opc) && (prevInsn == insn->GetPreviousMachineInsn()) && + !RegistersIdentical(prevInsn->GetOperand(0), prevInsn->GetOperand(1)) && + !RegistersIdentical(insn->GetOperand(0), insn->GetOperand(1))) { + Operand *reg1 = insn->GetResult(0); + Operand *reg2 = prevInsn->GetOperand(1); + Insn *newInsn = cgfunc->cg->BuildInstruction(insn->GetMachineOpcode(), reg1, reg2); + insn->bb->ReplaceInsn(insn, newInsn); + return true; + } + break; + } + case MOP_wstr: + case MOP_xstr: + case MOP_wldr: + case MOP_xldr: { + // add x2, x1, imm + // ldr x3, [x2] + // -> ldr x3, [x1, imm] + // --------------------- + // add x2, x1, imm + // str x3, [x2] + // -> str x3, [x1, imm] + CG_ASSERT(insn->GetResult(0), ""); + const Riscv64MD *md = &Riscv64CG::kMd[static_cast(insn)->mop_]; + bool is64bits = md->Is64Bit(); + int64 size = md->GetOperandSize(); + OpndInfo *opndinfo = origInfo[0]; + if (insn->IsLoad() && !opndinfo) { + return false; + } + + OpndInfo *baseinfo = nullptr; + MemOperand *memopnd = nullptr; + if (insn->IsLoad()) { + MemOpndInfo *meminfo = static_cast(opndinfo); + baseinfo = meminfo->GetBaseInfo(); + memopnd = static_cast(meminfo->opnd); + } else { + Operand *res = insn->GetResult(0); + CG_ASSERT(res != nullptr && res->IsMemoryAccessOperand(), ""); + memopnd = static_cast(res); + Operand *base = memopnd->GetBaseRegister(); + CG_ASSERT(base->IsRegister(), ""); + baseinfo = GetOpndInfo(base, -1); + } + + if (baseinfo && baseinfo->insn) { + Insn *insn1 = baseinfo->insn; + InsnInfo *insninfo1 = baseinfo->insninfo; + MOperator opc1 = insn1->GetMachineOpcode(); + if (opc1 == MOP_xaddrri12 || opc1 == MOP_waddrri12) { + if (!memopnd->GetOffset()) { + return false; + } + Riscv64ImmOperand *imm0 = static_cast(memopnd->GetOffset()); + if (!imm0) { + return false; + } + int64 imm0Val = imm0->GetValue(); + Operand *res = insn->GetOperand(0); + RegOperand *op1 = static_cast(insn1->GetOperand(1)); + Riscv64ImmOperand *imm1 = static_cast(insn1->GetOperand(2)); + CG_ASSERT(imm1 != nullptr, ""); + int64 immVal; + // don't use register if it was redefined. + OpndInfo *opndinfo1 = insninfo1->orig_opnd[0]; + if (opndinfo1 && opndinfo1->redefined) { + return false; + } else { + immVal = imm0Val + imm1->GetValue(); + } + if ((!is64bits && immVal < STR_LDR_IMM32_UPPER_BOUND && immVal % 4 == 0) || + (is64bits && immVal < STR_LDR_IMM64_UPPER_BOUND && immVal % 8 == 0)) { + MemOperand *mo = aarchfunc->CreateMemOpnd(op1, immVal, size); + Insn *ldInsn = cgfunc->cg->BuildInstruction(opc, res, mo); + insn->bb->ReplaceInsn(insn, ldInsn); + return true; + } + } + } + break; + } // end case MOP_xldr + default: + break; + } + return false; +} + +/* + *iii. mov w16, v10.s[1] // FMOV from simd 105 ---> replace_insn + mov w1, w16 ----->insn + ==> + mov w1, v10.s[1] + */ +bool Riscv64Ebo::IsMovToSIMDVmov(Insn *insn, Insn *replaceInsn) { + if (insn->GetMachineOpcode() == MOP_wmovrr && replaceInsn->GetMachineOpcode() == MOP_xvmovrs) { + insn->mop_ = replaceInsn->GetMachineOpcode(); + return true; + } + return false; +} + +/* + * i. fmov x10, d8 ----> replace_insn + * mov x1, x10 ----> insn + * ==> + * fmov x1, d8 + * ii. fmov w10, s8 ----> replace_insn + * mov w1, w10 ----> insn + * ==> + * fmov w1, s8 + * iii. mov w16, v10.s[1] ----> replace_insn + * mov w1, w16 ----> insn + * ==> + * mov w1, v10.s[1] + */ +bool Riscv64Ebo::ReplaceMovToVmov(Insn *insn, Insn *replaceInsn) { + if ((insn->GetMachineOpcode() == MOP_xmovrr && replaceInsn->GetMachineOpcode() == MOP_xvmovrd) || + (insn->GetMachineOpcode() == MOP_wmovrr && replaceInsn->GetMachineOpcode() == MOP_xvmovrs)) { + // Change opcode + insn->mop_ = replaceInsn->GetMachineOpcode(); + return true; + } + return false; +} + +bool Riscv64Ebo::ChangeLdrMop(Insn *insn, Operand *opnd) { + CG_ASSERT(insn->IsLoad(), ""); + CG_ASSERT(opnd->IsRegister(), ""); + + RegOperand *regOpnd = static_cast(opnd); + CG_ASSERT(static_cast(insn->GetOperand(0))->GetRegisterType() != regOpnd->GetRegisterType(), ""); + CHECK_FATAL(insn && insn->GetOpnd(0) && static_cast(insn->GetOpnd(0)), "null ptr check"); + if (static_cast(insn->GetOpnd(0))->GetIndexRegister()) { + return false; + } + + bool bRet = true; + if (regOpnd->GetRegisterType() == kRegTyFloat) { + switch (insn->mop_) { + case MOP_wldr: + insn->mop_ = MOP_sldr; + break; + case MOP_xldr: + insn->mop_ = MOP_dldr; + break; + case MOP_wldrsb: + case MOP_wldrsh: + default: + bRet = false; + break; + } + } else if (regOpnd->GetRegisterType() == kRegTyInt) { + switch (insn->mop_) { + case MOP_sldr: + insn->mop_ = MOP_wldr; + break; + case MOP_dldr: + insn->mop_ = MOP_xldr; + break; + default: + bRet = false; + break; + } + } else { + CG_ASSERT(false, "Internal error."); + bRet = false; + } + + return bRet; +} + +/* + * opnd_info[0]->insn + * eor(89) (opnd0: vreg:R107 class: [I]) (opnd1: vreg:R108 class: [I]) (opnd2: vreg:R109 class: [I]) + * orig_info[0]->insn + * str(213) (opnd0: vreg:R107 class: [I]) (opnd1: Mem:base: reg:R30 class: [I]offset:ofst:8) + * insn + * ldr(154) (opnd0: vreg:R113 class: [I]) (opnd1: Mem:base: reg:R30 class: [I]offset:ofst:8) + * + * store Rxx, base, offset + * load Rxx, base, offset + * + * load Rxx, base, offset + * load Rxx, base, offset + */ +bool Riscv64Ebo::RemoveRedundantLoad(BB *bb, Insn *insn, Operand **opnds, OpndInfo **opndInfo, OpndInfo **origInfo) { + if (insn == bb->firstinsn) { + return false; + } + RegOperand *base = static_cast(GetBase(insn)); + Operand *offset = GetOffset(insn); + RegOperand *reg = GetRegOpnd(insn); + if (!base || !offset || !reg || !IsFrameReg(base) || IsZeroRegister(reg)) { + return false; + } + + int32_t opndnum = insn->GetOpndNum(); + int32_t resnum = insn->GetResultNum(); + if (opndnum != 1 || resnum != 1) { + return false; + } + + MemOpndInfo *meminfo = static_cast(origInfo[0]); + if (meminfo == nullptr) { + return false; + } + OpndInfo *baseinfo = meminfo->GetBaseInfo(); + OpndInfo *offinfo = meminfo->GetOffsetInfo(); + + Insn *prevInsn = origInfo[0]->insn; + if (!prevInsn || !prevInsn->AccessMem()) { + return false; + } + InsnInfo *prevInsninfo = origInfo[0]->insninfo; + MemOpndInfo *prevMeminfo = GetMemInfo(prevInsninfo); + CHECK_FATAL(prevMeminfo, "null ptr check"); + OpndInfo *prevBaseinfo = prevMeminfo->GetBaseInfo(); + OpndInfo *prevOffinfo = prevMeminfo->GetOffsetInfo(); + + RegOperand *prevBase = static_cast(GetBase(prevInsn)); + Operand *prevOffset = GetOffset(prevInsn); + RegOperand *prevReg = GetRegOpnd(prevInsn); + OpndInfo *prevReginfo = prevInsn->IsStore() ? prevInsninfo->orig_opnd[0] : prevInsninfo->result[0]; + // prev_insn maybe str wzr mem. + if (baseinfo != prevBaseinfo || offinfo != prevOffinfo || offset != prevOffset || + (prevReginfo && prevReginfo->redefined)) { + return false; + } + + // limited to the same bb until O2 RA is enabled + if (origInfo[0]->bb != bb) { + return false; + } + + if (!reg->IsOfIntClass() || !prevReg->IsOfIntClass() || reg->GetSize() != prevReg->GetSize() || + (prevBase != nullptr && base->GetSize() != prevBase->GetSize()) || IsPhysicalReg(reg) || IsPhysicalReg(prevReg)) { + return false; + } + + // gen mov reg, prev_reg + if ((cgfunc->mirModule.IsCModule()) && + ((insn->GetMachineOpcode() == MOP_wldrb) || + (insn->GetMachineOpcode() == MOP_wldrh))) { + // C has unsigned value which can overflow. To be safe, replace with a zero ext. + // FIXME, replace insn with a zero extension + return true; + } + bb->ReplaceInsn(insn, cgfunc->cg->BuildInstruction(SelectMovMop(reg, prevReg), reg, prevReg)); + return true; +} + +MOperator Riscv64Ebo::SelectMovMop(RegOperand *dstOpnd, RegOperand *srcOpnd) { + MOperator mop; + uint32_t size = dstOpnd->GetSize(); + + if (Riscv64isa::IsFPSIMDRegister((Riscv64reg_t)dstOpnd->GetRegisterNumber())) { + if (Riscv64isa::IsFPSIMDRegister((Riscv64reg_t)srcOpnd->GetRegisterNumber())) { + mop = size == 64 ? MOP_xvmovd : MOP_xvmovs; + } else { + mop = size == 64 ? MOP_xvmovdr : MOP_xvmovsr; + } + } else { + if (Riscv64isa::IsFPSIMDRegister((Riscv64reg_t)srcOpnd->GetRegisterNumber())) { + mop = size == 64 ? MOP_xvmovrd : MOP_xvmovrs; + } else { + mop = size == 64 ? MOP_xmovrr : MOP_wmovrr; + } + } + return mop; +} + +bool Riscv64Ebo::DeleteDupMemInsn(Insn *insn, OpndInfo **opndInfo, InsnInfo *insninfo, InsnInfo *predInfo) { + if (cgfunc->mirModule.IsCModule()) { + // C has memory aliasing issue. For both load and store removal, there can + // have no intermediate load or store in between. Major overhaul required. + // Alias information is nice to have. + return false; + } + Insn *prevInsn = insninfo->insn; + if (!insn->AccessMem() || !prevInsn->AccessMem()) { + return false; + } + + int32_t resnum = insn->GetResultNum(); + if (resnum != 1) { + return false; + } + + resnum = prevInsn->GetResultNum(); + if (resnum != 1) { + return false; + } + + if (insn->bb != prevInsn->bb) { + return false; + } + + // Avoid load/store pairs now. + if (GetRegNumForMem(prevInsn) != 1 || GetRegNumForMem(insn) != 1) { + return false; + } + + CHECK_FATAL(GetMemOpnd(insn) != nullptr, "GetMemOpnd(insn) is null in Riscv64Ebo::DeleteDupMemInsn"); + const Riscv64MD *md = &Riscv64CG::kMd[static_cast(insn)->mop_]; + uint32_t currSize = md->GetOperandSize(); + CHECK_FATAL(GetMemOpnd(prevInsn) != nullptr, "GetMemOpnd(prev_insn) is null in Riscv64Ebo::DeleteDupMemInsn"); + const Riscv64MD *prevMd = &Riscv64CG::kMd[static_cast(prevInsn)->mop_]; + uint32_t prevSize = prevMd->GetOperandSize(); + if (currSize != prevSize) { + return false; + } + + RegOperand *reg = GetRegOpnd(insn); + RegOperand *prevReg = GetRegOpnd(prevInsn); + if (before_regalloc && (IsPhysicalReg(reg) || IsPhysicalReg(prevReg))) { + return false; + } + + if (insn->IsLoad() && prevInsn->IsLoad()) { + /* try to remove the second load */ + if (reg->GetRegisterType() != prevReg->GetRegisterType()) { + return false; + } + if (insn->GetMachineOpcode() != prevInsn->GetMachineOpcode()) { + return false; + } + if (!reg->IsOfIntClass() || IsZeroRegister(reg) || IsZeroRegister(prevReg)) { + return false; + } + + // gen mov reg, prev_reg + Insn *newinsn = cgfunc->cg->BuildInstruction(SelectMovMop(reg, prevReg), reg, prevReg); + + if (EBODUMP) { + LogInfo::MapleLogger() << "< ==== Replace Insn :\n"; + insn->dump(); + LogInfo::MapleLogger() << " To be : =====>\n"; + newinsn->dump(); + } + insn->bb->ReplaceInsn(insn, newinsn); + return true; + } else if (insn->IsLoad() && prevInsn->IsStore()) { + /* try to use mov instead of load */ + if (reg->GetRegisterType() != prevReg->GetRegisterType() || IsZeroRegister(reg)) { + return false; + } + if (!reg->IsOfIntClass()) { + return false; + } + + // gen mov reg, prev_reg + Insn *newinsn = cgfunc->cg->BuildInstruction(SelectMovMop(reg, prevReg), reg, prevReg); + if (EBODUMP) { + LogInfo::MapleLogger() << "< ==== Replace Insn :\n"; + insn->dump(); + LogInfo::MapleLogger() << " To be : =====>\n"; + newinsn->dump(); + } + insn->bb->ReplaceInsn(insn, newinsn); + return true; + } else if (insn->IsStore() && prevInsn->IsStore()) { + /* try to remove the first store */ + /* Skip the case: + < -1 : 0x65ba07f0 > < 0 > str(248) (opnd0: reg:R32 class: [I]) (opnd1: Mem:base: reg:R29 class: + [I]offset:ofst:40) < -1 : 0x65b9fb08 > < 0 > stp(252) (opnd0: reg:R32 class: [I]) (opnd1: reg:R32 class: [I]) + (opnd2: Mem:base: reg:R29 class: [I]offset:ofst:40 intact) */ + if (insn->GetMachineOpcode() != prevInsn->GetMachineOpcode()) { + return false; + } + if (reg->GetRegisterType() != prevReg->GetRegisterType()) { + return false; + } + + if (insninfo->mustnot_be_removed || prevInsn->do_not_remove) { + return false; + } + + // gen mov reg, prev_reg + if (EBODUMP) { + LogInfo::MapleLogger() << " Remove Duplicate store insn \n"; + prevInsn->dump(); + } + prevInsn->bb->RemoveInsn(prevInsn); + // remove the insninfo. + InsnInfo *prevInfo = insninfo->prev; + if (prevInfo) { + prevInfo->next = insninfo->next; + } + if (insninfo->next) { + insninfo->next->prev = prevInfo; + } + if (predInfo == nullptr) { + SetInsnInfo(insninfo->hash_index, insninfo->same); + } else { + predInfo->same = insninfo->same; + } + return false; + } else { + /* not opt chance for load - store */ + // ldr(161) (opnd0: vreg:R680 class: [I] validBitNum: 64) (opnd1: Mem:base: reg:R29 class: [I] validBitNum: + // 64offset:ofst:192) str(250) (opnd0: vreg:R680 class: [I] validBitNum: 64) (opnd1: Mem:base: reg:R29 class: [I] + // validBitNum: 64offset:ofst:192) + Riscv64RegOperand *reg1 = static_cast(reg); + Riscv64RegOperand *reg2 = static_cast(prevReg); + if ((*reg1) == (*reg2) && !insninfo->result[0]->redefined) { + Insn *newinsn = cgfunc->cg->BuildInstruction(SelectMovMop(reg, prevReg), reg, prevReg); + if (EBODUMP) { + LogInfo::MapleLogger() << "< ==== Remove insn who store the reg to the orig place. Replace Insn :\n"; + insn->dump(); + LogInfo::MapleLogger() << " with : =====>\n"; + newinsn->dump(); + } + insn->bb->ReplaceInsn(insn, newinsn); + return true; + } + return false; + } + return false; +} + +bool Riscv64Ebo::DeleteDupInsn(Insn *insn, OpndInfo **opndInfo, InsnInfo *insninfo) { + Insn *prevInsn = insninfo->insn; + int32_t resnum = insn->GetResultNum(); + if (resnum != 1) { + return false; + } + + resnum = prevInsn->GetResultNum(); + if (resnum != 1) { + return false; + } + + if (insn->bb != prevInsn->bb) { + return false; + } + + if (insn->AccessMem() || prevInsn->AccessMem()) { + return false; + } + + MOperator insnMop = insn->GetMachineOpcode(); + if (insnMop == MOP_xuxtv64) { + ImmOperand *imm0 = static_cast(insn->GetOperand(2)); + ImmOperand *imm1 = static_cast(prevInsn->GetOperand(2)); + if (imm0->GetValue() != imm1->GetValue()) { + return false; + } + } + + // Return false if insn is clinit. + if (insnMop == MOP_adrp_ldr && insn->do_not_remove) { + return false; + } + + RegOperand *reg = static_cast(insn->GetResult(0)); + RegOperand *prevReg = static_cast(prevInsn->GetResult(0)); + if (!reg || !prevReg || !reg->IsOfIntClass() || !prevReg->IsOfIntClass()) { + return false; + } + + if (EBODUMP) { + LogInfo::MapleLogger() << "< === Dup insn was found, origin insn is ===> \n"; + insn->dump(); + insninfo->insn->dump(); + } + Insn *newInsn = cgfunc->cg->BuildInstruction(SelectMovMop(reg, prevReg), reg, prevReg); + insn->bb->ReplaceInsn(insn, newInsn); + if (EBODUMP) { + LogInfo::MapleLogger() << "< === replaced insn is ===> \n"; + newInsn->dump(); + } + return true; +} + +} // namespace maplebe diff --git a/mapleall/maple_be/src/cg/riscv64/riscv64_emit.cpp b/mapleall/maple_be/src/cg/riscv64/riscv64_emit.cpp new file mode 100644 index 0000000..9779e09 --- /dev/null +++ b/mapleall/maple_be/src/cg/riscv64/riscv64_emit.cpp @@ -0,0 +1,1069 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#include "emit.h" +#include "riscv64_cg.h" +#include "cg_assert.h" +#include +#include +#include +#include +#include "reflection_analysis.h" +#include +#include "mpl_logging.h" +#include "securec.h" +#include "metadata_layout.h" +#include "special_func.h" + +namespace maplebe { +using namespace maple; + + const char *Riscv64CG::intRegNames[kRVLast][MAXREG] = { + { "err", "err0", "err1", "err2", "err3", "err4", "err5", "err6", "err7", "err8", "err9", "err10", + "err11", "err12", "err13", "err14", "err15", "err16", "err17", "err18", "err19", "err20", "err21", "err22", + "err23", "err24", "err25", "err26", "err27", "err28", "err29", "err30", "err31", + "err", "err0", "err1", "err2", "err3", "err4", "err5", "err6", "err7", "err8", "err9", "err10", + "err11", "err12", "err13", "err14", "err15", "err16", "err17", "err18", "err19", "err20", "err21", "err22", + "err23", "err24", "err25", "err26", "err27", "err28", "err29", "err30", "err31" }, + { "err", "err0", "err1", "err2", "err3", "err4", "err5", "err6", "err7", "err8", "err9", "err10", + "err11", "err12", "err13", "err14", "err15", "err16", "err17", "err18", "err19", "err20", "err21", "err22", + "err23", "err24", "err25", "err26", "err27", "err28", "err29", "err30", "err31", + "err", "err0", "err1", "err2", "err3", "err4", "err5", "err6", "err7", "err8", "err9", "err10", + "err11", "err12", "err13", "err14", "err15", "err16", "err17", "err18", "err19", "err20", "err21", "err22", + "err23", "err24", "err25", "err26", "err27", "err28", "err29", "err30", "err31" }, + { "err", "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "fp", "s1", "a0", "a1", "a2", "a3", "a4", + "a5", "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6", + "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7", "fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5", + "fa6", "fa7", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", "fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11" }, + { "err", "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "fp", "s1", "a0", "a1", "a2", "a3", "a4", + "a5", "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6", + "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7", "fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5", + "fa6", "fa7", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", "fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11" }, + // TODO - vector and quad naming + { "err", "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", "x14", + "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x28", "x29", "x30", + "sp", "xzr", "rflag", + "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", + "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31" }, + { "err", "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", "x14", + "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x28", "x29", "x30", + "sp", "xzr", "rflag", // x29 is fp + "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15", + "q16", "q17", "q18", "q19", "q20", "q21", "q22", "q23", "q24", "q25", "q26", "q27", "q28", "q29", "q30", "q31" } +}; + +void Riscv64CGFunc::EmitCfiDirectives(Insn *insn, bool inEpilog) { +} + +bool Riscv64CGFunc::IsInEpilogBB(BB *bb) { + if (cg->GenerateCfiDirectives() && bb->lastinsn) { + Riscv64Insn *insn = static_cast(bb->lastinsn); + if (insn->mop_ == MOP_xret) { + return true; + } + } + return false; +} + +void Riscv64Insn::EmitClinit(CG &cg, Emitter &emitter) { + /* adrp x3, __muid_data_undef_tab$$GetBoolean_dex+144 + * ldr x3, [x3, #:lo12:__muid_data_undef_tab$$GetBoolean_dex+144] + * or, + * adrp x3, _PTR__cinf_Ljava_2Futil_2Fconcurrent_2Fatomic_2FAtomicInteger_3B + * ldr x3, [x3, #:lo12:_PTR__cinf_Ljava_2Futil_2Fconcurrent_2Fatomic_2FAtomicInteger_3B] + * + * ldr x3, [x3,#112] + * ldr wzr, [x3] + */ + const Riscv64MD *md = &Riscv64CG::kMd[MOP_clinit]; + + Operand *opnd0 = opnds[0]; + Operand *opnd1 = opnds[1]; + OpndProp *prop0 = md->operand_[0]; + StImmOperand *stopnd = static_cast(opnd1); + CHECK_FATAL(stopnd != nullptr, "stopnd is null in Riscv64Insn::EmitClinit"); + // emit nop for breakpoint + if (cg.cgopt_.WithDwarf()) { + emitter.Emit("\t").Emit("nop").Emit("\n"); + } + + if (stopnd->GetSymbol()->IsMuidDataUndefTab()) { + // emit adrp + emitter.Emit("\t").Emit("adrp").Emit("\t"); + opnd0->Emit(emitter, prop0); + emitter.Emit(","); + emitter.Emit(stopnd->GetName()); + emitter.Emit("+").Emit(stopnd->GetOffset()); + emitter.Emit("\n"); + // emit ldr + emitter.Emit("\t").Emit("ldr").Emit("\t"); + opnd0->Emit(emitter, prop0); + emitter.Emit(","); + emitter.Emit("["); + opnd0->Emit(emitter, prop0); + emitter.Emit(","); + emitter.Emit("#"); + emitter.Emit(":lo12:").Emit(stopnd->GetName()); + emitter.Emit("+").Emit(stopnd->GetOffset()); + emitter.Emit("]"); + emitter.Emit("\n"); + } else { + // adrp x3, _PTR__cinf_Ljava_2Futil_2Fconcurrent_2Fatomic_2FAtomicInteger_3B + emitter.Emit("\tadrp\t"); + opnd0->Emit(emitter, prop0); + emitter.Emit(","); + emitter.Emit(NameMangler::kPtrPrefixStr + stopnd->GetName()); + emitter.Emit("\n"); + + // ldr x3, [x3, #:lo12:_PTR__cinf_Ljava_2Futil_2Fconcurrent_2Fatomic_2FAtomicInteger_3B] + emitter.Emit("\tldr\t"); + opnd0->Emit(emitter, prop0); + emitter.Emit(", ["); + opnd0->Emit(emitter, prop0); + emitter.Emit(", #:lo12:"); + emitter.Emit(NameMangler::kPtrPrefixStr + stopnd->GetName()); + emitter.Emit("]\n"); + } + // emit "ldr x0,[x0,#48]" + emitter.Emit("\t").Emit("ldr").Emit("\t"); + opnd0->Emit(emitter, prop0); + emitter.Emit(","); + emitter.Emit("["); + opnd0->Emit(emitter, prop0); + emitter.Emit(",#"); + emitter.Emit(static_cast(ClassMetadataOffsetOfInitFlag())); + emitter.Emit("]"); + emitter.Emit("\n"); + + // emit "ldr xzr, [x0]" + emitter.Emit("\t").Emit("ldr\txzr, ["); + opnd0->Emit(emitter, prop0); + emitter.Emit("]\n"); +} + +void Riscv64Insn::EmitAdrpLdr(CG &cg, Emitter &emitter) { + // adrp xd, _PTR__cinf_Ljava_2Futil_2Fconcurrent_2Fatomic_2FAtomicInteger_3B + // ldr xd, [xd, #:lo12:_PTR__cinf_Ljava_2Futil_2Fconcurrent_2Fatomic_2FAtomicInteger_3B] + const Riscv64MD *md = &Riscv64CG::kMd[MOP_adrp_ldr]; + + Operand *opnd0 = opnds[0]; + Operand *opnd1 = opnds[1]; + OpndProp *prop0 = md->operand_[0]; + StImmOperand *stopnd = static_cast(opnd1); + CHECK_FATAL(stopnd != nullptr, "stopnd is null in Riscv64Insn::EmitAdrpLdr"); + // emit nop for breakpoint + if (cg.cgopt_.WithDwarf()) { + emitter.Emit("\t").Emit("nop").Emit("\n"); + } + + // adrp xd, _PTR__cinf_Ljava_2Futil_2Fconcurrent_2Fatomic_2FAtomicInteger_3B + emitter.Emit("\t").Emit("adrp").Emit("\t"); + opnd0->Emit(emitter, prop0); + emitter.Emit(","); + emitter.Emit(stopnd->GetName()); + // emitter.emit("+").emit(stopnd->GetOffset()); + emitter.Emit("\n"); + + // ldr xd, [xd, #:lo12:_PTR__cinf_Ljava_2Futil_2Fconcurrent_2Fatomic_2FAtomicInteger_3B] + emitter.Emit("\tldr\t"); + static_cast(opnd0)->isreffield_ = true; + opnd0->Emit(emitter, prop0); + static_cast(opnd0)->isreffield_ = false; + emitter.Emit(","); + emitter.Emit("["); + opnd0->Emit(emitter, prop0); + emitter.Emit(","); + emitter.Emit("#"); + emitter.Emit(":lo12:").Emit(stopnd->GetName()); + emitter.Emit("]\n"); +} + +void Riscv64Insn::EmitClinitTail(CG &cg, Emitter &emitter) { + // ldr x17, [xs, #112] + // ldr wzr, [x17] + const Riscv64MD *md = &Riscv64CG::kMd[MOP_clinit_tail]; + + Operand *opnd0 = opnds[0]; + OpndProp *prop0 = md->operand_[0]; + + // emit "ldr x17,[xs,#112]" + emitter.Emit("\t").Emit("ldr").Emit("\tx17, ["); + opnd0->Emit(emitter, prop0); + emitter.Emit(", #"); + emitter.Emit(static_cast(ClassMetadataOffsetOfInitFlag())); + emitter.Emit("]"); + emitter.Emit("\n"); + + // emit "ldr xzr, [x17]" + emitter.Emit("\t").Emit("ldr\txzr, [x17]\n"); +} + +void Riscv64Insn::EmitAdrpLabel(CG &cg, Emitter &emitter) { + // adrp xd, label + // add xd, xd, #lo12:label + const Riscv64MD *md = &Riscv64CG::kMd[MOP_adrp_label]; + + Operand *opnd0 = opnds[0]; + Operand *opnd1 = opnds[1]; + OpndProp *prop0 = md->operand_[0]; + + LabelIdx lidx = static_cast(opnd1)->GetValue(); + + MIRSymbol *funcSt = GlobalTables::GetGsymTable().GetSymbolFromStIdx(CG::curCgFunc->mirModule.CurFunction()->stIdx.Idx()); + + //GStrIdx strIdx = CG::curCgFunc->mirModule.CurFunction()->labelTab->labelTable[lidx]; + //string labelStr = GlobalTables::GetStrTable().GetStringFromStrIdx(strIdx); + + // adrp xd, label + emitter.Emit("\t").Emit("lui").Emit("\t"); + opnd0->Emit(emitter, prop0); + emitter.Emit(", "); + const char *idx = std::to_string(CG::curPuIdx).c_str(); + emitter.Emit("%hi(").Emit(".label.").Emit(idx).Emit("__").Emit(lidx).Emit(")\n"); + + // add xd, xd, #lo12:label + emitter.Emit("\taddi\t"); + opnd0->Emit(emitter, prop0); + emitter.Emit(", "); + opnd0->Emit(emitter, prop0); + emitter.Emit(", "); + emitter.Emit("%lo(").Emit(".label.").Emit(idx).Emit("__").Emit(lidx).Emit(")\n"); +} + +void Riscv64Insn::EmitCheckThrowPendingException(CG &cg, Emitter &emitter) { + /* mrs x16, TPIDR_EL0 + * ldr x16, [x16, #64] + * ldr x16, [x16, #8] + * cbz x16, .lnoexception + * bl MCC_ThrowPendingException + * .lnoexception: + */ + emitter.Emit("\t").Emit("mrs").Emit("\tx16, TPIDR_EL0"); + emitter.Emit("\n"); + emitter.Emit("\t").Emit("ldr").Emit("\tx16, [x16, #64]"); + emitter.Emit("\n"); + emitter.Emit("\t").Emit("ldr").Emit("\tx16, [x16, #8]"); + emitter.Emit("\n"); + emitter.Emit("\t").Emit("cbz").Emit("\tx16, .lnoeh.").Emit(cg.curCgFunc->GetName()); + emitter.Emit("\n"); + emitter.Emit("\t").Emit("bl").Emit("\t").Emit(GetIntrinsicFuncName(INTRN_MCCThrowPendingException)); + emitter.Emit("\n"); + emitter.Emit(".lnoeh.").Emit(cg.curCgFunc->GetName()).Emit(":"); + emitter.Emit("\n"); + + return; +} + +void Riscv64Insn::Emit(CG &cg, Emitter &emitter) { + MOperator mop = GetMachineOpcode(); + emitter.SetCurrentMOP(mop); + const Riscv64MD *md = &Riscv64CG::kMd[mop]; + + if (!cg.GenerateVerboseAsm() && mop == MOP_comment) { + return; + } + if (mop == MOP_clinit) { + EmitClinit(cg, emitter); + return; + } else if (mop == MOP_adrp_ldr) { + EmitAdrpLdr(cg, emitter); + return; + } else if (mop == MOP_clinit_tail) { + EmitClinitTail(cg, emitter); + return; + } else if (mop == MOP_adrp_label) { + EmitAdrpLabel(cg, emitter); + return; + } + + if (CGOptions::nativeopt == true && mop == MOP_xbl) { + FuncNameOperand *nameopnd = static_cast(opnds[0]); + if (nameopnd->GetName() == GetIntrinsicFuncName(INTRN_MCCCheckThrowPendingException)) { + EmitCheckThrowPendingException(cg, emitter); + return; + } + } + + std::string format(md->format_); + emitter.Emit("\t").Emit(md->name_).Emit("\t"); + int seq[5]; + std::string prefix[5]; // used for print prefix like "*" in icall *rax + int index = 0; + + errno_t eNum = memset_s(seq, sizeof(seq), -1, sizeof(seq)); + if (eNum) { + FATAL(kLncFatal, "memset_s failed"); + } + int commaNum = 0; + for (uint32 i = 0; i < format.length(); i++) { + char c = format[i]; + if (c >= '0' && c <= '5') { + seq[index++] = c - '0'; + commaNum++; + } else if (c != ',') { + prefix[index].push_back(c); + } + } + + bool isreffield = false; + // set opnd0 ref-field flag, so we can emit the right register + if (IsAccessRefField() && AccessMem()) { + Operand *opnd0 = opnds[seq[0]]; + if (opnd0->IsRegister()) { + static_cast(opnd0)->isreffield_ = true; + isreffield = true; + } + } + + for (int i = 0; i < commaNum; i++) { + if (seq[i] == -1) { + continue; + } + if (prefix[i].length() > 0) { + emitter.Emit(prefix[i]); + } + + opnds[seq[i]]->Emit(emitter, md->operand_[seq[i]]); + // reset opnd0 ref-field flag, so following instruction has correct register + if (isreffield && (i == 0)) { + static_cast(opnds[seq[0]])->isreffield_ = false; + } + // Temporary comment the label:.label.debug.callee + /* + if (opnds[seq[i]]->op_kind_ == maplebe::Operand::Opd_String) { + std::string str_comment(((CommentOperand*)(opnds[seq[i]]))->GetComment()); + std::string mark_string = MARK_MUID_FUNC_UNDEF_STR; + if (str_comment.find(mark_string)== 0) { + uint32_t length = strlen(mark_string.c_str()); + std::string func_name = "debug.callee." + str_comment.substr(length,str_comment.length()-length); + uint64_t index = ++cg.label_debug_index; + emitter.emit("\n.label.").emit(func_name).emit(index).emit(":"); + } + } + */ + if (i != (commaNum - 1)) { + emitter.Emit(", "); + } + } + if (mop == MOP_vcvtrf || mop == MOP_vcvturf || mop == MOP_xvcvtrf || mop == MOP_xvcvturf || + mop == MOP_vcvtrd || mop == MOP_vcvturd || mop == MOP_xvcvtrd || mop == MOP_xvcvturd) { + // set rounding mode + emitter.Emit(", rtz"); + } + + if (cg.GenerateVerboseAsm()) { + std::string comment = GetComment(); + if (comment.c_str() && strlen(comment.c_str()) > 0) { + emitter.Emit("\t\t# ").Emit(comment.c_str()); + } + } + + emitter.Emit("\n"); +} + +void Riscv64CGFunc::EmitBBHeaderLabel(const char *funcName, LabelIdx labelIdx) { + cg->emitter_->EmitBBHeaderLabel(funcName, "#", labelIdx, *this); +} + +std::string Riscv64CGFunc::GetReflectString(uint32_t offset) { + std::stringstream ssfunc; + MIRAggConst *stragg = nullptr; + if ((offset & (3 << 30)) != 0) { + uint32_t tag = offset >> 30; + if (tag == HOT_LAYOUT::kStartUpHot) { + stragg = static_cast(reflect_start_hot_strtab_sym->GetConst()); + } else if (tag == HOT_LAYOUT::kBothHot) { + stragg = static_cast(reflect_both_hot_strtab_sym->GetConst()); + } else { + stragg = static_cast(reflect_run_hot_strtab_sym->GetConst()); + } + offset &= 0x3FFFFFFF; + } else { + stragg = static_cast(reflect_strtab_sym->GetConst()); + } + + for (auto starti = offset; starti < stragg->constVec.size(); starti++) { + MIRIntConst *onechar = static_cast(stragg->constVec[starti]); + CG_ASSERT(onechar != nullptr, "onechar is nullptr in Riscv64CGFunc::GetReflectString"); + char cc = static_cast(onechar->value); + if (!onechar->IsZero()) { + ssfunc << cc; + } else { + break; + } + } + return ssfunc.str(); +} + +static std::string &GetMethodDescLabel(const std::string &methodName, std::string &methodInfoLabel) { + methodInfoLabel.clear(); + methodInfoLabel.append("__method_desc__"); + methodInfoLabel.append(methodName); + return methodInfoLabel; +} + +// emit java method description which contains address and size of local reference area +// as well as method metadata. +void Riscv64CGFunc::EmitMethodDesc(Emitter &emitter) { + if (!func->IsJava()) { + return; + } + + emitter.Emit("\t.section\t.rodata\n"); + emitter.Emit("\t.align\t2\n"); + + std::string methodInfoLabel; + GetMethodDescLabel(func->GetFuncSymbol()->GetName(), methodInfoLabel); + emitter.Emit(methodInfoLabel).Emit(":\n"); + + EmitRefToMethodInfo(emitter); + + // local reference area + Riscv64MemLayout *memLayout = static_cast(this->memlayout); + int32 refOffset = memLayout->GetReflocbaseLoc(); + uint32 refNum = memLayout->GetSizeOfRefLocals() / kIntregBytelen; + + emitter.Emit("\t.short ").Emit(refOffset).Emit("\n"); + emitter.Emit("\t.short ").Emit(refNum).Emit("\n"); +} + +void Riscv64CGFunc::EmitRefToMethodDesc(Emitter &emitter) { + if (!func->IsJava()) { + return; + } + + std::string methodDescLabel; + GetMethodDescLabel(func->GetFuncSymbol()->GetName(), methodDescLabel); + emitter.Emit("\t.word ").Emit(methodDescLabel).Emit("-.\n"); +} + +void Riscv64CGFunc::EmitRefToMethodInfo(Emitter &emitter) { + if (func->module->IsJavaModule()) { + std::string classname = func->GetBaseClassName(); + std::string methodinfostr = METHODINFO_RO_PREFIX_STR + classname; + MIRSymbol *st = GlobalTables::GetGsymTable().GetSymbolFromStrIdx(GlobalTables::GetStrTable().GetStrIdxFromName(methodinfostr)); + bool methodinfoIsCompact = false; + if (!st) { + // methodinfo is in the cold format + methodinfoIsCompact = true; + methodinfostr = NameMangler::kMethodsInfoCompactPrefixStr + classname; + st = GlobalTables::GetGsymTable().GetSymbolFromStrIdx(GlobalTables::GetStrTable().GetStrIdxFromName(methodinfostr)); + } + + if (st) { + MIRAggConst *aggconst = static_cast(st->GetConst()); + CG_ASSERT(aggconst != nullptr, "aggconst is nullptr in Riscv64CGFunc::EmitRefToMethodInfo"); + bool found = false; + uint32 offset = 0; + for (uint32 i = 0; i < aggconst->constVec.size(); i++) { + MIRConst *elemcst = aggconst->constVec[i]; + MIRAggConst *onemethodconst = static_cast(elemcst); + CG_ASSERT(onemethodconst != nullptr, "onemethodconst is nullptr in Riscv64CGFunc::EmitRefToMethodInfo"); + MIRConst *funcnameindex = methodinfoIsCompact ? onemethodconst->constVec[METHOD_COMPACT::kMethodname] + : onemethodconst->constVec[METHOD_RO::kMethodname]; + MIRIntConst *intCt = static_cast(funcnameindex); + CG_ASSERT(intCt != nullptr, "int_ct is nullptr in Riscv64CGFunc::EmitRefToMethodInfo"); + std::string enfuncname = NameMangler::EncodeName(GetReflectString((uint32_t)intCt->value).c_str()); + + MIRConst *tttindex = methodinfoIsCompact ? onemethodconst->constVec[METHOD_COMPACT::kSigname] + : onemethodconst->constVec[METHOD_RO::kSigname]; + MIRIntConst *wwintCt = static_cast(tttindex); + std::string wenfuncname = NameMangler::EncodeName(GetReflectString((uint32_t)wwintCt->value).c_str()); + + if (func->GetBaseFuncName() == enfuncname && func->GetSignature() == wenfuncname) { + found = true; + offset = i; + break; + } + } + + if (found) { + if (methodinfoIsCompact) { + // Mark this is a compact format + emitter.Emit("\t.word ").Emit(methodinfostr); + emitter.Emit("+1"); + offset *= sizeof(MethodMetadataCompact); + } else { + // here we still emit the pointer to MethodMetadata instead of MethodMetadataRO, + // to let runtime have a consistent interface. + emitter.Emit("\t.word ").Emit(NameMangler::kMethodsInfoPrefixStr + classname); + offset *= sizeof(MethodMetadata); + } + if (offset > 0) { + emitter.Emit("+").Emit(offset); + } + emitter.Emit("-.\n"); + } else { + if (ehfunc && (ehfunc->NeedFullLSDA() || ehfunc->NeedFastLSDA())) { + CG_ASSERT(false, "cant't find method metadata"); + } + } + } + } +} + +void Riscv64CGFunc::Emit() { + // check the size of ImmOperand and MemOperand + if (g_enableDebug) { + CheckImmMemSize(); + } + // emit header of this function + Emitter &emitter = *cg->emitter_; + + emitter.Emit("\n"); + EmitMethodDesc(emitter); + + // emit java code to the java section. + if (func->IsJava()) { + std::string sectionName = NameMangler::kMuidJavatextPrefixStr; + emitter.Emit("\t.section ." + sectionName).Emit(",\"aw\"\n"); + } else { + emitter.Emit("\t.text\n"); + } + + emitter.Emit("\t.align 2\n"); + MIRSymbol *funcSt = GlobalTables::GetGsymTable().GetSymbolFromStIdx(func->stIdx.Idx()); + + // manually Replace function to optimized assembly language + // To Do + if (CGOptions::replaceasm && funcSt->GetName().compare( + string(NameMangler::kJavaLangStringStr) + string(NameMangler::kHashCodeStr)) == 0) { + std::string optFile = "maple/mrt/codetricks/asm/hashCode.s"; + struct stat buffer; + if (stat(optFile.c_str(), &buffer) == 0) { + std::ifstream hashCodeFd(optFile); + if (!hashCodeFd.is_open()) { + ERR(kLncErr, " %s open failed!", optFile.c_str()); + LogInfo::MapleLogger() << "wrong" << endl; + } else { + std::string contend; + while (getline(hashCodeFd, contend)) { + emitter.Emit(contend + "\n"); + } + } + } + return; + } + + if (funcSt->GetFunction()->GetAttr(FUNCATTR_weak)) { + emitter.Emit("\t.weak\t").Emit(funcSt->GetName()).Emit("\n"); + emitter.Emit("\t.hidden\t").Emit(funcSt->GetName()).Emit("\n"); + } else if (funcSt->GetFunction()->GetAttr(FUNCATTR_local)) { + emitter.Emit("\t.local\t").Emit(funcSt->GetName()).Emit("\n"); + } else if (funcSt->value.mirFunc && funcSt->value.mirFunc->classTyIdx == 0 && funcSt->value.mirFunc->IsStatic()) { + // nothing + } else { + emitter.Emit("\t.globl\t").Emit(funcSt->GetName()).Emit("\n"); + emitter.Emit("\t.hidden\t").Emit(funcSt->GetName()).Emit("\n"); + } + + emitter.Emit("\t.type\t").Emit(funcSt->GetName()).Emit(", %function\n"); + + // add these messege , solve the simpleperf tool error + EmitRefToMethodDesc(emitter); + + emitter.Emit(funcSt->GetName()).Emit(":\n"); + + // if the last insn is call, then insert nop + bool found = false; + FOR_ALL_BB_REV(bb, this) { + FOR_BB_INSNS_REV(insn, bb) { + if (insn->IsMachineInstruction()) { + if (insn->IsCall()) { + Insn *newinsn = cg->BuildInstruction(MOP_nop, nullptr, nullptr); + bb->InsertInsnAfter(insn, newinsn); + } + found = true; + break; + } + } + if (found) { + break; + } + } + // emit instructions + FOR_ALL_BB(bb, this) { + if (bb->frequency) { + emitter.Emit("# ").Emit("freq:").Emit(bb->frequency).Emit("\n"); + } + // emit bb headers + if (bb->labidx != 0) { + EmitBBHeaderLabel(funcSt->GetName().c_str(), bb->labidx); + } + + FOR_BB_INSNS(insn, bb) { + insn->Emit(*cg, emitter); + } + } + if (CGOptions::maplelinker) { + // Emit a label for calculating method size + emitter.Emit(".label.end.").Emit(funcSt->GetName()).Emit(":\n"); + } + + // emit LSDA + if (cg->GenerateCfiDirectives() && ehfunc) { + if (!hasProEpilogue) { + emitter.Emit("\t.word 0xFFFFFFFF\n"); + emitter.Emit("\t.word 0\n"); + } else if (ehfunc->NeedFullLSDA()) { + LSDAHeader *lsdaheader = ehfunc->lsda_header; + const char *funcname = funcSt->GetName().c_str(); + // .word .label.lsda_label-func_start_label + const char *idx = std::to_string(CG::curPuIdx).c_str(); + emitter.Emit("\t.word ") + .Emit(".label.") + .Emit(idx) + .Emit("__") + .Emit(lsdaheader->lsda_label->labelIdx) + .Emit("-") + .Emit(".label.") + .Emit(idx) + .Emit("__") + .Emit(start_label->labelIdx) + .Emit("\n"); + } else if (ehfunc->NeedFastLSDA()) { + EmitFastLSDA(); + } + } + uint32 size = (func->symTab == nullptr ? 0 : func->symTab->GetSymbolTableSize()); + for (size_t i = 0; i < size; i++) { + MIRSymbol *st = func->symTab->GetSymbolFromStIdx(i); + if (st == nullptr) { + continue; + } + MIRStorageClass storageClass = st->storageClass; + MIRSymKind sKind = st->sKind; + if (storageClass == kScPstatic && sKind == kStConst) { + emitter.Emit("\t.align 2\n"); + emitter.Emit(st->GetName().c_str()); + emitter.Emit(":\n"); + if (MIRStr16Const *str16const = dynamic_cast(st->GetConst())) { + emitter.EmitStr16Constant(str16const); + emitter.Emit("\n"); + continue; + } else if (MIRStrConst *strconst = dynamic_cast(st->GetConst())) { + emitter.EmitStrConstant(strconst); + emitter.Emit("\n"); + continue; + } + + switch (st->GetConst()->type->GetPrimType()) { + case PTY_u32: { + MIRIntConst *intconst = static_cast(st->GetConst()); + emitter.Emit("\t.long ").Emit(static_cast(intconst->value)).Emit("\n"); + break; + } + case PTY_f32: { + MIRFloatConst *floatconst = static_cast(st->GetConst()); + emitter.Emit("\t.word ").Emit(static_cast(floatconst->GetIntValue())).Emit("\n"); + break; + } + case PTY_f64: { + MIRDoubleConst *doubleconst = static_cast(st->GetConst()); + emitter.Emit("\t.word ").Emit(doubleconst->GetIntLow32()).Emit("\n"); + emitter.Emit("\t.word ").Emit(doubleconst->GetIntHigh32()).Emit("\n"); + break; + } + case PTY_v4i32: { + MIRVectorIntConst *vecIntconst = static_cast (st->GetConst()); + for (uint8 j = 0; j < vecIntconst->vecSize; j++) { + emitter.Emit("\t.long ").Emit(static_cast(vecIntconst->vecElems[i])).Emit("\n"); + } + break; + } + default: + CG_ASSERT(false, "NYI"); + break; + } + } + } + + for (MapleVector::iterator stit = emitstvec_.begin(); stit != emitstvec_.end(); + stit++) { // emit switch table only here + MIRSymbol *st = *stit; + CG_ASSERT(st->IsReadOnly(), "NYI"); + emitter.Emit("\n"); + emitter.Emit("\t.align 3\n"); + emitter.Emit(st->GetName().c_str()).Emit(":\n"); + MIRAggConst *arrayConst = static_cast(st->GetConst()); + CHECK_FATAL(arrayConst, "null ptr check"); + for (uint32 i = 0; i < arrayConst->constVec.size(); i++) { + MIRLblConst *lblconst = static_cast(arrayConst->constVec[i]); + CHECK_FATAL(lblconst, "null ptr check"); + emitter.Emit("\t.quad\t"); + const char *idx = std::to_string(CG::curPuIdx).c_str(); + emitter.Emit(".label.").Emit(idx).Emit("__").Emit(lblconst->value); + emitter.Emit(" - ").Emit(st->GetName().c_str()); + emitter.Emit("\n"); + } + } + + if (ehfunc && ehfunc->NeedFullLSDA()) { + EmitFullLSDA(); + } + + emitter.Emit("\t.text\n"); + emitter.Emit("\t.size\t").Emit(funcSt->GetName()).Emit(", .-").Emit(funcSt->GetName()).Emit("\n"); +} + +void Riscv64CGFunc::EmitFastLSDA() // the fast_exception_handling lsda +{ + Emitter *emitter = cg->emitter_; + MIRSymbol *funcSt = GlobalTables::GetGsymTable().GetSymbolFromStIdx(func->stIdx.Idx()); + const char *funcname = funcSt->GetName().c_str(); + // .word 0xFFFFFFFF + // .word .label.LTest_3B_7C_3Cinit_3E_7C_28_29V3-func_start_label + emitter->Emit("\t.word 0xFFFFFFFF\n"); + const char *idx = std::to_string(CG::curPuIdx).c_str(); + if (NeedCleanup()) { + emitter->Emit("\t.word ") + .Emit(".label.") + .Emit(idx) + .Emit("__") + .Emit(cleanup_label->labelIdx) + .Emit("-") + .Emit(".label.") + .Emit(idx) + .Emit("__") + .Emit(start_label->labelIdx) + .Emit("\n"); + } else { + CG_ASSERT(!exitbbsvec.empty(), "exitbbsvec is empty in Riscv64CGFunc::EmitFastLSDA"); + emitter->Emit("\t.word ") + .Emit(".label.") + .Emit(idx) + .Emit("__") + .Emit(exitbbsvec[0]->labidx) + .Emit("-") + .Emit(".label.") + .Emit(idx) + .Emit("__") + .Emit(start_label->labelIdx) + .Emit("\n"); + } +} + +void Riscv64CGFunc::EmitFullLSDA() // the normal gcc_except_table +{ + Emitter *emitter = cg->emitter_; + + // emit header + emitter->Emit("\t.align 2\n"); + emitter->Emit("\t.section .gcc_except_table,\"a\",@progbits\n"); + + // emit LSDA header + LSDAHeader *lsdaheader = ehfunc->lsda_header; + MIRSymbol *funcSt = GlobalTables::GetGsymTable().GetSymbolFromStIdx(func->stIdx.Idx()); + const char *funcname = funcSt->GetName().c_str(); + emitter->EmitStmtLabel(funcname, lsdaheader->lsda_label->labelIdx); + emitter->Emit("\t.byte ").Emit(lsdaheader->lpstart_encoding).Emit("\n"); + emitter->Emit("\t.byte ").Emit(lsdaheader->ttype_encoding).Emit("\n"); +#if 0 // not needed for riscv + emitter->Emit("\t.uleb128 "); + emitter->EmitLabelPair(funcname, lsdaheader->ttype_offset); + emitter->EmitStmtLabel(funcname, lsdaheader->ttype_offset.start_offset->labelIdx); + + // emit call site table + emitter->Emit("\t.byte ").Emit(lsdaheader->callsite_encoding).Emit("\n"); + // callsite table size + emitter->Emit("\t.uleb128 "); + emitter->EmitLabelPair(funcname, ehfunc->lsda_callsite_table->cs_table); + // callsite start + emitter->EmitStmtLabel(funcname, ehfunc->lsda_callsite_table->cs_table.start_offset->labelIdx); +#endif + MapleVector &callsiteTable = ehfunc->lsda_callsite_table->callsite_table; + std::sort(callsiteTable.begin(), callsiteTable.end(), [this](LSDACallSite *a, LSDACallSite *b) { + LabelIDOrder id1 = GetOrCreateLabelOperand(a->cs_start.end_offset->labelIdx)->GetLabelOrder(); + LabelIDOrder id2 = GetOrCreateLabelOperand(b->cs_start.end_offset->labelIdx)->GetLabelOrder(); + CG_ASSERT(id1 != -1u && id2 != -1u, "illegal label order assigned"); + return id1 <= id2; + }); +#if 1 // new for riscv + emitter->Emit("\t.byte ").Emit(37).Emit("\n"); // don't know why + emitter->Emit("\t.byte ").Emit(3).Emit("\n"); // don't know why + emitter->Emit("\t.byte ").Emit(callsiteTable.size()*13).Emit("\n"); +#endif + + for (uint32 i = 0; i < callsiteTable.size(); i++) { + LSDACallSite *lsdacallsite = callsiteTable[i]; + emitter->Emit("\t.4byte "); + emitter->EmitLabelPair(funcname, lsdacallsite->cs_start); + + emitter->Emit("\t.4byte "); + emitter->EmitLabelPair(funcname, lsdacallsite->cs_length); + + if (lsdacallsite->cs_landing_pad.start_offset) { + emitter->Emit("\t.4byte "); + emitter->EmitLabelPair(funcname, lsdacallsite->cs_landing_pad); + } else { + CG_ASSERT(lsdacallsite->cs_action == 0, ""); + if (NeedCleanup()) { + // if landing pad is 0, we emit this call site as cleanup code + LabelPair cleaupCode; + cleaupCode.start_offset = start_label; + cleaupCode.end_offset = cleanup_label; + emitter->Emit("\t.4byte "); + emitter->EmitLabelPair(funcname, cleaupCode); + } else if (func->IsJava()) { + CG_ASSERT(!exitbbsvec.empty(), "exitbbsvec is empty in Riscv64CGFunc::EmitFullLSDA"); + const char *idx = std::to_string(CG::curPuIdx).c_str(); + emitter->Emit("\t.4byte ") + .Emit(".label.") + .Emit(idx) + .Emit("__") + .Emit(exitbbsvec[0]->labidx) + .Emit(" - ") + .Emit(".label.") + .Emit(idx) + .Emit("__") + .Emit(start_label->labelIdx) + .Emit("\n"); + } else { + emitter->Emit("\t.4byte 0\n"); + } + } + + emitter->Emit("\t.byte ").Emit(lsdacallsite->cs_action).Emit("\n"); + } + + // quick hack: insert a call site entry for the whole function body. + // this will hand in any pending (uncaught) exception to its caller. Note that + // __gxx_personality_v0 in libstdc++ is coded so that if exception table exists, + // the call site table must have an entry for any possibly raised exception, + // otherwise __cxa_call_terminate will be invoked immediately, thus the caller + // does not get the chance to take charge. + if (NeedCleanup() || func->IsJava()) { + // call site for clean-up + LabelPair funcStart; + funcStart.start_offset = start_label; + funcStart.end_offset = start_label; + emitter->Emit("\t.uleb128 "); + emitter->EmitLabelPair(funcname, funcStart); + + LabelPair funcLength; + funcLength.start_offset = start_label; + funcLength.end_offset = cleanup_label; + emitter->Emit("\t.uleb128 "); + emitter->EmitLabelPair(funcname, funcLength); + + LabelPair cleaupCode; + cleaupCode.start_offset = start_label; + cleaupCode.end_offset = cleanup_label; + if (NeedCleanup()) { + emitter->Emit("\t.uleb128 "); + emitter->EmitLabelPair(funcname, cleaupCode); + } else { + CG_ASSERT(!exitbbsvec.empty(), "exitbbsvec is empty in Riscv64CGFunc::EmitFullLSDA"); + const char *idx = std::to_string(CG::curPuIdx).c_str(); + emitter->Emit("\t.uleb128 ") + .Emit(".label.") + .Emit(idx) + .Emit("__") + .Emit(exitbbsvec[0]->labidx) + .Emit(" - ") + .Emit(".label.") + .Emit(idx) + .Emit("__") + .Emit(start_label->labelIdx) + .Emit("\n"); + } + emitter->Emit("\t.uleb128 0\n"); + if (!func->IsJava()) { + // call site for stack unwind + LabelPair unwindStart; + unwindStart.start_offset = start_label; + unwindStart.end_offset = cleanup_label; + emitter->Emit("\t.uleb128 "); + emitter->EmitLabelPair(funcname, unwindStart); + + LabelPair unwindLength; + unwindLength.start_offset = cleanup_label; + unwindLength.end_offset = end_label; + emitter->Emit("\t.uleb128 "); + emitter->EmitLabelPair(funcname, unwindLength); + + emitter->Emit("\t.uleb128 0\n"); + emitter->Emit("\t.uleb128 0\n"); + } + } + + // callsite end label + emitter->EmitStmtLabel(funcname, ehfunc->lsda_callsite_table->cs_table.end_offset->labelIdx); + + // tt + LSDAActionTable *lsdaactiontable = ehfunc->lsda_action_table; + for (uint32 i = 0; i < lsdaactiontable->action_table.size(); i++) { + LSDAAction *lsdaaction = lsdaactiontable->action_table[i]; + emitter->Emit("\t.byte ").Emit(lsdaaction->action_index).Emit("\n"); + emitter->Emit("\t.byte ").Emit(lsdaaction->action_filter).Emit("\n"); + } + emitter->Emit("\t.align 2\n"); + if (mirModule.IsJavaModule()) { + for (int32 i = ehfunc->eh_ty_table.size() - 1; i >= 0; i--) { + MIRType *mirType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(ehfunc->eh_ty_table[i]); + if (mirType->typeKind == kTypeScalar && mirType->primType == PTY_void) { + continue; + } + CG_ASSERT(mirType->typeKind == kTypeClass, "NYI"); + const std::string &tyname = GlobalTables::GetStrTable().GetStringFromStrIdx(mirType->nameStrIdx); + std::string dwrefstring("DW.ref."); + dwrefstring.append(CLASSINFO_PREFIX_STR); + dwrefstring.append(tyname); + dwrefstring.append(" - ."); + emitter->Emit("\t.4byte ").Emit(dwrefstring.c_str()).Emit("\n"); + } + } else { + GStrIdx strIdx = GlobalTables::GetStrTable().GetStrIdxFromName("__TYPEINFO_TABLE__"); + MIRSymbol *typeinfoTableSym = func->symTab->GetSymbolFromStrIdx(strIdx); + if (typeinfoTableSym != nullptr) { + MIRAggConst *arrayConst = static_cast(typeinfoTableSym->value.konst); + if (arrayConst != nullptr) { + for (MIRConst *typeinfoEntryConst : arrayConst->constVec) { + MIRAggConst *aggconst = static_cast(typeinfoEntryConst); + if (aggconst->constVec[0]->kind != kConstAddrof) { + continue; + } + MIRAddrofConst *addrofConst = static_cast(aggconst->constVec[0]); + MIRSymbol *typeinfoSymbol = GlobalTables::GetGsymTable().GetSymbolFromStIdx(addrofConst->GetSymbolIndex().Idx()); + std::string dwrefstring("DW.ref."); + dwrefstring.append(typeinfoSymbol->GetName()); + dwrefstring.append(" - ."); + emitter->Emit("\t.4byte ").Emit(dwrefstring.c_str()).Emit("\n"); + } + } + } + } + // end of lsda + emitter->EmitStmtLabel(funcname, lsdaheader->ttype_offset.end_offset->labelIdx); +} + +/* + Table C1-6 A64 Load/Store addressing modes + | Offset + Addressing Mode | Immediate | Register | Extended Register + + Base register only | [base{,#0}] | - | - + (no offset) | B_OI_NONE | | + imm=0 + + Base plus offset | [base{,#imm}] | [base,Xm{,LSL #imm}] | [base,Wm,(S|U)XTW {#imm}] + B_OI_NONE | B_OR_X | B_OR_X + imm=0,1 (0,3) | imm=00,01,10,11 (0/2,s/u) + + Pre-indexed | [base, #imm]! | - | - + + Post-indexed | [base], #imm | [base], Xm(a) | - + + Literal | label | - | - + (PC-relative) + + a) The post-indexed by register offset mode can be used with the SIMD Load/Store + structure instructions described in Load/Store Vector on page C3-154. Otherwise + the post-indexed by register offset mode is not available. + */ +void Riscv64CGFunc::EmitOperand(Operand *opnd, OpndProp *prop) { + ofstream &outf = cg->emitter_->out; + Riscv64OpndProp *opndprop = static_cast(prop); + if (RegOperand *regopnd = dynamic_cast(opnd)) { + RegType regtype = regopnd->GetRegisterType(); + CG_ASSERT((!opndprop || (opndprop->opnd_ty_ == Operand::Opd_Register)), "operand type doesn't match"); + uint8 size = opndprop ? opndprop->size_ : regopnd->size_; // opndprop null means a sub emit, i.e from MemOperand + regno_t regNo = regopnd->GetRegisterNumber(); + switch (regtype) { + case kRegTyInt: + CG_ASSERT((size == 32 || size == 64), "illegal register size"); + outf << Riscv64CG::intRegNames[((size == 32) ? Riscv64CG::kR32List : Riscv64CG::kR64List)][regNo]; + break; + case kRegTyFloat: { + CG_ASSERT((size == 8 || size == 16 || size == 32 || size == 64), "illegal register size"); + Riscv64RegOperand *a64regopnd = static_cast(regopnd); + if (a64regopnd->IsSimdVectorMode()) { + // see if it is slot 0 or 1 of simd + if (regNo >= VB64) { + regNo -= VB64 + V0; + } else if (regNo >= VB32) { + regNo -= VB32 + V0; + } + outf << Riscv64CG::intRegNames[(Riscv64CG::kV64List)][regNo]; + if (a64regopnd->GetSimdVectorType() == 0) { + // 2 * 64bits + outf << ".d["; + } else { + CG_ASSERT(a64regopnd->GetSimdVectorType() == 1, "EmitOperand : wrong simd type"); + outf << ".s["; + } + outf << a64regopnd->GetSimdVectorPosition() << "]"; + } else { + outf << Riscv64CG::intRegNames[__builtin_ctz(size) - 3][regNo]; + } + break; + } + default: + CG_ASSERT(false, "NYI"); + break; + } + } else if (ImmOperand *immopnd = dynamic_cast(opnd)) { + outf << (opndprop->IsLoadLiteral() ? "=" : "#"); + outf << (immopnd->size_ == 64 ? immopnd->GetValue() : static_cast(static_cast(immopnd->GetValue()))); + } else if (dynamic_cast(opnd)) { + outf << "#0.0"; + } else if (Riscv64OfstOperand *ofstopnd = dynamic_cast(opnd)) { + outf << "#" << ofstopnd->GetOffsetValue(); + } else if (Riscv64MemOperand *memopnd = dynamic_cast(opnd)) { + outf << "["; + EmitOperand(memopnd->GetBaseRegister(), nullptr); + OfstOperand *offset = memopnd->GetOffsetImmediate(); + if (offset) { + if (!offset->IsZero()) { + outf << ","; + EmitOperand(offset, nullptr); + } + outf << "]"; + } else { + outf << "]"; + } + } else if (StImmOperand *stopnd = dynamic_cast(opnd)) { + if (opndprop->IsLiteralLow12()) { + outf << "#:lo12:"; + } + if (CGOptions::doPIC && + (stopnd->GetSymbol()->GetStorageClass() == kScGlobal || stopnd->GetSymbol()->GetStorageClass() == kScExtern)) { + outf << ":got:" + stopnd->GetName(); + } else { + outf << stopnd->GetName(); + } + } else if (LabelOperand *lblopnd = dynamic_cast(opnd)) { + const char *idx = std::to_string(CG::curPuIdx).c_str(); + outf << ".label." << idx << "__" << lblopnd->labidx_; + } else if (FuncNameOperand *fn = dynamic_cast(opnd)) { + outf << fn->GetName(); + } else if (ListOperand *listopnd = dynamic_cast(opnd)) { + uint32 size = listopnd->GetOperands().size(); + uint32 i = 0; + for (auto opnd : listopnd->GetOperands()) { + EmitOperand(opnd, nullptr); + if (i != (size - 1)) { + outf << ", "; + } + ++i; + } + } else if (CommentOperand *comment = dynamic_cast(opnd)) { + outf << comment->GetComment(); + } else { + CG_ASSERT(false, "NYI"); + } +} + +} // namespace maplebe diff --git a/mapleall/maple_be/src/cg/riscv64/riscv64_global_opt.cpp b/mapleall/maple_be/src/cg/riscv64/riscv64_global_opt.cpp new file mode 100644 index 0000000..dcc236a --- /dev/null +++ b/mapleall/maple_be/src/cg/riscv64/riscv64_global_opt.cpp @@ -0,0 +1,1148 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#include "riscv64_global_opt.h" +#include "riscv64_store_load_opt.h" +#include "riscv64_isa.h" +#include "riscv64_operand.h" +#include "riscv64_insn.h" +#include "riscv64_cg_func.h" +#include "riscv64_cg.h" +#include +#include "optimize_common.h" + +namespace maplebe { + +using namespace maple; + +void Riscv64GlobalOpt::Run() { + if (!cgfunc->GetSBB()) { + BackPropOfRegister(); + } + ForwardPropOfRegister(); + DeleteRedundantUxt(); +} + +/** + *this aim to find the pattern: + *insn1: mop vreg1, vreg2 + *insn2: mop vreg3, vreg4 + *... + * + **insn3: mov vreg4, vreg1 // target + **insn4: mop vreg4, .... + **insn5: mop .... , vreg1 + **If do bp of vreg4 in insn3 (replace all vreg1 with vreg4) will change the defination of vreg4 in insn2 and insn5 + **So, if this pattern appear, will not do back prop + * is_bg shows it is back_prop or forward prop + **target_insn is mov so use opndidx: 0 as dest_idx, opndidx: 1 as use_idx + */ +bool Riscv64GlobalOpt::NoOverlap(Insn *targetInsn, int opndidx, bool isBg) { + CHECK_FATAL((targetInsn->GetMachineOpcode() == MOP_xmovrr || targetInsn->GetMachineOpcode() == MOP_wmovrr) && + targetInsn->defs[1], + "must be"); + BB *curBb = targetInsn->bb; + Insn *defInsn = targetInsn->defs[1]->begin()->GetInsn(); + int defIndex = targetInsn->defs[1]->begin()->GetDUIndex(); + + int defId = defInsn->id; + if (isBg) { + if (targetInsn->predefine[0] == nullptr && targetInsn->redefine[0] == nullptr) { + return true; + } + if (targetInsn->predefine[0]) { + for (auto preDef : *(targetInsn->predefine[0])) { + Insn *preDefInsn = preDef.GetInsn(); + int preDefIndex = preDef.GetDUIndex(); + if (preDefInsn->uses[preDefIndex] == nullptr) { + continue; + } + for (auto preUse : *(preDefInsn->uses[preDefIndex])) { + Insn *preUseInsn = preUse.GetInsn(); + if (preUseInsn->bb == curBb && preUseInsn->id > defId) { + return false; + } + } + } + } + if (targetInsn->redefine[0]) { + for (auto reDef : *(targetInsn->redefine[0])) { + Insn *reDefInsn = reDef.GetInsn(); + if (reDefInsn->bb != curBb) { + continue; + } + for (auto defUse : *(defInsn->uses[defIndex])) { + Insn *defUseInsn = defUse.GetInsn(); + CHECK_FATAL(defUseInsn->bb == curBb, "must in same bb"); + if (defUseInsn->id > reDefInsn->id) { + return false; + } + } + } + } + } else { + if (defInsn->redefine[defIndex] == nullptr) { + return true; + } + for (auto redef : *(defInsn->redefine[defIndex])) { + Insn *reDef = redef.GetInsn(); + for (auto use : *(targetInsn->uses[0])) { + Insn *useInsn = use.GetInsn(); + if (reDef->bb == useInsn->bb) { + if (reDef->id < useInsn->id) { + return false; + } + } else { + if (FindAThroughPath(reDef, useInsn)) { + return false; + } + } + } + } + } + return true; +} + +/* + *try to find a path for insn_start to insn_end + *if exist return true + */ +bool Riscv64GlobalOpt::FindAThroughPath(Insn *insnStart, Insn *insnEnd) { + BB *bbStart = insnStart->bb; + BB *bbEnd = insnEnd->bb; + if (bbStart == bbEnd) { + if (insnStart->id < insnEnd->id) { + return true; + } + } + bool found = false; + std::set traversed; + traversed.insert(bbStart); + for (auto succ : bbStart->succs) { + found = found || TraverseNext(succ, bbEnd, &traversed); + } + for (auto ehSucc : bbStart->eh_succs) { + found = found || TraverseNext(ehSucc, bbEnd, &traversed); + } + return found; +} + +bool Riscv64GlobalOpt::TraverseNext(BB *curBb, BB *target, std::set *traversedBb) { + if (curBb == target) { + return true; + } + traversedBb->insert(curBb); + bool found = false; + for (auto succ : curBb->succs) { + if (succ != target && traversedBb->find(succ) != traversedBb->end()) { + continue; + } + found = found || TraverseNext(succ, target, traversedBb); + } + for (auto ehSucc : curBb->eh_succs) { + if (ehSucc != target && traversedBb->find(ehSucc) != traversedBb->end()) { + continue; + } + found = found || TraverseNext(ehSucc, target, traversedBb); + } + return found; +} + +/* + *If one of the relative insn have multigen prop return true + */ +bool Riscv64GlobalOpt::HasMultiGen(Insn *newInsn) { + CHECK_FATAL(newInsn->GetMachineOpcode() == MOP_xmovrr || newInsn->GetMachineOpcode() == MOP_wmovrr, "MUST BE"); + bool foundSelf = false; + for (auto def : *(newInsn->defs[1])) { + Insn *defInsn = def.GetInsn(); + unsigned short defProp = def.GetProperty(); + if (defProp & DataInsnInfo::kMultigen) { + return true; + } + int defIndex = def.GetDUIndex(); + CHECK_FATAL(defInsn->uses[defIndex], "impossible"); + for (auto defUse : *(defInsn->uses[defIndex])) { + if (defUse.GetInsn() == newInsn) { + foundSelf = true; + } + unsigned short defUseProp = defUse.GetProperty(); + if (defUseProp & DataInsnInfo::kMultigen) { + return true; + } + } + } + CHECK_FATAL(foundSelf, "impossible"); + return false; +} + +/* + * Do Forward prop when insn is mov + * mov xx, x1 + * ... /// BBs and x1 is live + * mop yy, xx + * + **=> + * mov x1, x1 + * ... /// BBs and x1 is live + * mop yy, x1 + */ +void Riscv64GlobalOpt::ForwardPropOfRegister() { + bool secondTime = false; + std::set modifiedBb; + do { + FOR_ALL_BB(bb, cgfunc) { + if (bb->unreachable || (secondTime && modifiedBb.find(bb) == modifiedBb.end())) { + continue; + } + if (secondTime) { + modifiedBb.erase(bb); + } + FOR_BB_INSNS(insn, bb) { + if (!insn->IsMachineInstruction()) { + continue; + } + if (insn->GetMachineOpcode() != MOP_xmovrr && insn->GetMachineOpcode() != MOP_wmovrr) { + continue; + } + if (!insn->opnds[1]->IsZeroRegister() && static_cast(insn->opnds[1])->IsVirtualRegister() && + static_cast(insn->opnds[0])->IsVirtualRegister() && insn->uses[0] != nullptr) { + if (insn->defs[1] != nullptr && !IsSameReg(insn->opnds[1], insn->opnds[0]) && OnlyOneDefine(insn) && + NoOverlap(insn, 0, false)) { + if (HasMultiGen(insn)) { + continue; + } + for (auto use : *(insn->uses[0])) { + Insn *useInsn = use.GetInsn(); + short i = use.GetIndex(); + CHECK_FATAL(i >= 0, "must not be call insn"); + if (useInsn->opnds[i]->IsRegister()) { + CHECK_FATAL(IsSameReg(useInsn->opnds[i], insn->opnds[0]), "must equal"); + useInsn->SetOperand(i, insn->opnds[1]); + if ((useInsn->GetMachineOpcode() == MOP_xmovrr || useInsn->GetMachineOpcode() == MOP_wmovrr) && + static_cast(useInsn->opnds[1])->IsVirtualRegister() && + static_cast(useInsn->opnds[0])->IsVirtualRegister()) { + modifiedBb.insert(useInsn->bb); + } + } else if (useInsn->opnds[i]->IsMemoryAccessOperand()) { + MemOperand *mem = static_cast(useInsn->opnds[i]); + bool memBaseSame = mem->GetBaseRegister() && IsSameReg(mem->GetBaseRegister(), insn->opnds[0]); + bool memIndexSame = mem->GetIndexRegister() && IsSameReg(mem->GetIndexRegister(), insn->opnds[0]); + if (memBaseSame || memIndexSame) { + MemOperand *newmem = static_cast(mem->Clone(cgfunc->memPool)); + CG_ASSERT(newmem != nullptr, "null ptr check"); + if (memBaseSame) { + newmem->SetBaseRegister(static_cast(insn->opnds[1])); + } + if (memIndexSame) { + newmem->SetIndexRegister(static_cast(insn->opnds[1])); + } + useInsn->SetOperand(i, newmem); + } + } else { + CHECK_FATAL(false, "impossible case"); + } + } + CleanDDForDestOperand(insn, 0); + InsertDUUDForDestOperand(insn, 0, DataInsnInfo::kNormal, true); + insn->SetOperand(0, insn->opnds[1]); + } + } + } + } + secondTime = true; + } while (!modifiedBb.empty()); +} + +/* + * Replace new_insn's dest opnd with its src opnd. + * After replacing, maintain the UDDU and WAW of the new dest opnd + * new_insn : mov insn + * isRefInsnBeforeNewInsn : indicate new_insn is inserted after refInsn or before + * new_index and new_prop : not used right now, but will used in future + * + */ +void Riscv64GlobalOpt::InsertDUUDForDestOperand(Insn *newInsn, short newIndex, unsigned short newProp, + bool isRefInsnBeforeNewInsn) { + CHECK_FATAL(newInsn, "CG internal error, new_insn should not be nullptr."); + std::set middleInsnSet; + MapleSet::iterator itSet; // for all others + MapleSet::iterator itSet2; // for use + if (isRefInsnBeforeNewInsn) { + CHECK_FATAL(newInsn->defs[1], "impossible"); + + for (auto def : *(newInsn->defs[1])) { + Insn *defInsn = def.GetInsn(); + short defI = def.GetIndex(); + CHECK_FATAL(defI >= 0, "def_insn is not call insn"); + if (defInsn->opnds[defI]->IsRegister()) { + CHECK_FATAL(IsSameReg(defInsn->opnds[defI], newInsn->opnds[1]), "must equal"); + } + int defIndex = def.GetDUIndex(); + CHECK_FATAL(defInsn->uses[defIndex], "impossible"); + // update ref's use and new insn's use && ref's use's def && def_insn's use + std::vector tmp; + for (auto defUse : *(defInsn->uses[defIndex])) { + tmp.push_back(defUse); + } + for (auto defUse : tmp) { + Insn *defUseInsn = defUse.GetInsn(); + if (defUseInsn == newInsn) { + continue; + } + short defUseI = defUse.GetIndex(); + CHECK_FATAL(defUseI >= 0, "def_use_insn can not be call"); + if (defUseInsn->opnds[defUseI]->IsRegister() && defInsn->opnds[defI]->IsRegister()) + CHECK_FATAL(IsSameReg(defUseInsn->opnds[defUseI], defInsn->opnds[defI]), "must equal"); + int defUseIndex = defUse.GetUDIndex(); + /// Insn middle dominate Insn end when begin from Insn start + middleInsnSet.clear(); + middleInsnSet.insert(newInsn); + for (auto defUseDef : *(defUseInsn->defs[defUseIndex])) { + Insn *defUseDefInsn = defUseDef.GetInsn(); + if (defUseDefInsn != defInsn) { + middleInsnSet.insert(defUseDefInsn); + } + } + if (IsPartialDominate(defInsn, defUseInsn, &middleInsnSet)) { + // remove def_use_insn from def_insn's use set + itSet2 = defInsn->uses[defIndex]->find(defUse); + defInsn->uses[defIndex]->erase(itSet2); + // remove def_insn from def_use_insn's def set + itSet = defUseInsn->defs[defUseIndex]->find(def); + defUseInsn->defs[defUseIndex]->erase(itSet); + // add def_use_insn into new_insn's use set + newInsn->uses[0]->insert(defUse); + // add new_insn into def_use_insn's def set + defUseInsn->defs[defUseIndex]->insert(DataInsnInfo(newInsn, 0)); + } else if (FindAThroughPath(newInsn, defUseInsn)) { + middleInsnSet.clear(); + for (auto defUseDef : *(defUseInsn->defs[defUseIndex])) { + Insn *defUseDefInsn = defUseDef.GetInsn(); + middleInsnSet.insert(defUseDefInsn); + } + if (!IsPartialDominate(newInsn, defUseInsn, &middleInsnSet)) { + // add def_use_insn into new_insn's use set + newInsn->uses[0]->insert(defUse); + // add new_insn into def_use_insn's def set + defUseInsn->defs[defUseIndex]->insert(DataInsnInfo(newInsn, 0)); + } + } + } + // update predef of new + if (newInsn->predefine[0] == nullptr) { + newInsn->predefine[0] = + GetRD()->GetMemPool()->New>(GetRD()->GetMemAllocator().Adapter()); + } + newInsn->predefine[0]->insert(def); + if (newInsn->redefine[0] == nullptr) { + newInsn->redefine[0] = + GetRD()->GetMemPool()->New>(GetRD()->GetMemAllocator().Adapter()); + } + tmp.clear(); + if (defInsn->redefine[defIndex]) { + for (auto defUse : *(defInsn->redefine[defIndex])) { + tmp.push_back(defUse); + } + } + // update redef of def_insn + if (defInsn->redefine[defIndex] == nullptr) { + defInsn->redefine[defIndex] = + GetRD()->GetMemPool()->New>(GetRD()->GetMemAllocator().Adapter()); + } + defInsn->redefine[defIndex]->insert(DataInsnInfo(newInsn, 0)); + // update redef of new && update redef of def_insn + for (auto defRedef : tmp) { + Insn *defRedefInsn = defRedef.GetInsn(); + short defRedefI = defRedef.GetIndex(); + CHECK_FATAL(defRedefI >= 0, "def_redef_insn must not be call insn"); + if (defRedefInsn->opnds[defRedefI]->IsRegister() && defInsn->opnds[defI]->IsRegister()) + CHECK_FATAL(IsSameReg(defRedefInsn->opnds[defRedefI], defInsn->opnds[defI]), "must equal"); + int defRedefIndex = defRedef.GetDUIndex(); + /// Insn middle dominate Insn end when begin from Insn start + middleInsnSet.clear(); + middleInsnSet.insert(newInsn); + for (auto defRedefPredef : *(defRedefInsn->predefine[defRedefIndex])) { + Insn *defRedefPredefInsn = defRedefPredef.GetInsn(); + if (defRedefPredefInsn != defInsn) { + middleInsnSet.insert(defRedefPredefInsn); + } + } + if (IsPartialDominate(defInsn, defRedefInsn, &middleInsnSet)) { + // remove def_redef_insn from def_insn's redef set + itSet = defInsn->redefine[defIndex]->find(defRedef); + defInsn->redefine[defIndex]->erase(itSet); + // remove def_insn from def_redef_insn's predef set + itSet = defRedefInsn->predefine[defRedefIndex]->find(def); + defRedefInsn->predefine[defRedefIndex]->erase(itSet); + // add def_redef_insn into new_insn's redef set + newInsn->redefine[0]->insert(defRedef); + // add new_insn into def_redef_insn's predef set + defRedefInsn->predefine[defRedefIndex]->insert(DataInsnInfo(newInsn, 0)); + } else if (FindAThroughPath(newInsn, defRedefInsn)) { + middleInsnSet.clear(); + for (auto defRedefPredef : *(defRedefInsn->predefine[defRedefIndex])) { + Insn *defRedefPredefInsn = defRedefPredef.GetInsn(); + middleInsnSet.insert(defRedefPredefInsn); + } + if (!IsPartialDominate(newInsn, defRedefInsn, &middleInsnSet)) { + // add def_redef_insn into new_insn's redef set + newInsn->redefine[0]->insert(defRedef); + // add new_insn into def_redef_insn's predef set + defRedefInsn->predefine[defRedefIndex]->insert(DataInsnInfo(newInsn, 0)); + } + } + } + } + + middleInsnSet.clear(); + for (auto def : *(newInsn->defs[1])) { + Insn *defInsn = def.GetInsn(); + middleInsnSet.insert(defInsn); + } + if (newInsn->bb->loop && !IsPartialDominate(newInsn, newInsn, &middleInsnSet)) { + newInsn->predefine[0]->insert(DataInsnInfo(newInsn, 0)); + newInsn->redefine[0]->insert(DataInsnInfo(newInsn, 0)); + newInsn->defs[1]->insert(DataInsnInfo(newInsn, 0)); + newInsn->uses[0]->insert(DataInsnInfo(newInsn, 1)); + } + } else { + CHECK_FATAL(false, "Not supported yet"); + } +} + +bool Riscv64GlobalOpt::TraverseDomNext(BB *start, BB *end, std::set *middleSet, std::set *traversed) { + if (start == end) { + return false; + } + for (auto middle : *middleSet) { + if (start == middle) { + return true; + } + } + traversed->insert(start->id); + for (auto succ : start->succs) { + if (succ != end && traversed->find(succ->id) != traversed->end()) { + continue; + } + if (!TraverseDomNext(succ, end, middleSet, traversed)) { + return false; + } + } + for (auto ehSucc : start->eh_succs) { + if (ehSucc != end && traversed->find(ehSucc->id) != traversed->end()) { + continue; + } + if (!TraverseDomNext(ehSucc, end, middleSet, traversed)) { + return false; + } + } + return true; +} + +/* + * if Insn middle partial dominate Insn end when begin from Insn start, return true + partial dominate : can not find a path from start to end that does not pass through middle_insn + prerequirement : exist a path from start to end + return true : Is partial dominate + return false : Is NOT partial dominate + */ +bool Riscv64GlobalOpt::IsPartialDominate(Insn *startInsn, Insn *endInsn, std::set *middleInsnSet) { + BB *start = startInsn->bb; + BB *end = endInsn->bb; + std::set middleSet; + for (auto middleInsn : *middleInsnSet) { + BB *middle = middleInsn->bb; + middleSet.insert(middle); + if (start == middle && middle != end) { + if (startInsn->id <= middleInsn->id) { + return true; + } else { + middleSet.erase(middle); + continue; + } + } else if (start != middle && middle == end) { + if (middleInsn->id <= endInsn->id) { + return true; + } else { + middleSet.erase(middle); + continue; + } + } else if (start == middle && start == end) { + CHECK_FATAL(middleInsn != endInsn, "check what happens"); + if (middleInsn == startInsn) { + return true; + } + if (endInsn != startInsn) { + if ((middleInsn->id < endInsn->id && startInsn->id < middleInsn->id) || + (startInsn->id > endInsn->id && middleInsn->id < endInsn->id)) { + return true; + } else { + middleSet.erase(middle); + continue; + } + } else { + return true; + } + } else if (start == end && end != middle) { + if (startInsn != endInsn && startInsn->id < endInsn->id) { + middleSet.erase(middle); + continue; + } + // if start_insn == end_insn || start_insn->id > end_insn->id fall through + } else { + CHECK_FATAL(start != end && start != middle && middle != end, "must be"); + } + } + if (middleSet.empty()) { + return false; + } + std::set traversed; + traversed.insert(start->id); + for (auto succ : start->succs) { + if (!TraverseDomNext(succ, end, &middleSet, &traversed)) { + return false; + } + } + for (auto ehSucc : start->eh_succs) { + if (!TraverseDomNext(ehSucc, end, &middleSet, &traversed)) { + return false; + } + } + return true; +} + +bool Riscv64GlobalOpt::OnlyOneDefine(Insn *targetInsn) { + for (auto use : *(targetInsn->uses[0])) { + Insn *useInsn = use.GetInsn(); + short useIdx = use.GetUDIndex(); + unsigned short useProp = use.GetProperty(); + if (useProp & DataInsnInfo::kMultigen) { + return false; + } + if (useInsn->defs[useIdx]->size() != 1) { + return false; + } + } + return true; +} + +bool Riscv64GlobalOpt::OpndOnlyDefInCurBB(Insn *targetInsn, int opndidx) { + BB *curBb = targetInsn->bb; + if (targetInsn->defs[opndidx] == nullptr) { + return false; + } + for (auto def : *(targetInsn->defs[opndidx])) { + if (def.GetInsn()->bb != curBb) { + return false; + } + } + return true; +} + +/* + * connect insn->predefinsn and insn->redefinsn + * delete insn->predef and insn->redef + * insn : target + * index : indicate the opnd + */ +void Riscv64GlobalOpt::CleanDDForDestOperand(Insn *insn, unsigned short index) { + if (insn->predefine[index] != nullptr && + insn->predefine[index]->find(DataInsnInfo(insn, index)) != insn->predefine[index]->end()) { + CHECK_FATAL(insn->redefine[index]->find(DataInsnInfo(insn, index)) != insn->redefine[index]->end(), "MUST NOT BE"); + insn->predefine[index]->erase(DataInsnInfo(insn, index)); + insn->redefine[index]->erase(DataInsnInfo(insn, index)); + } + // Rebuild redefine. + if (insn->predefine[index] != nullptr) { + for (auto predefInsnInfo : *(insn->predefine[index])) { + Insn *predefInsn = predefInsnInfo.GetInsn(); + int idx = predefInsnInfo.GetDUIndex(); + + CG_ASSERT(predefInsn->redefine[idx], "CG internal error."); + + predefInsn->redefine[idx]->erase(DataInsnInfo(insn, index)); + + if (insn->redefine[index]) { + for (auto redefInsnInfo : *(insn->redefine[index])) { + predefInsn->redefine[idx]->insert(redefInsnInfo); + Insn *redefInsn = redefInsnInfo.GetInsn(); + + // Call insn do not have predefine. + if (!redefInsn->IsCall()) { + int redefIdx = redefInsnInfo.GetDUIndex(); + + CG_ASSERT(redefInsn->predefine[redefIdx], "CG internal error."); + + redefInsn->predefine[redefIdx]->insert(predefInsnInfo); + } + } + } + } + insn->predefine[index]->clear(); + insn->predefine[index] = nullptr; + } + + // Remove predefine from redefInsn to insn. + if (insn->redefine[index]) { + for (auto redefInsnInfo : *(insn->redefine[index])) { + Insn *redefInsn = redefInsnInfo.GetInsn(); + + // Call insn do not have predefine. + if (!redefInsn->IsCall()) { + int redefIdx = redefInsnInfo.GetDUIndex(); + + CG_ASSERT(redefInsn->predefine[redefIdx], "CG internal error."); + + redefInsn->predefine[redefIdx]->erase(DataInsnInfo(insn, index)); + } + } + insn->redefine[index]->clear(); + insn->redefine[index] = nullptr; + } +} + +/* + * Do back propagate of vreg/preg when encount following insn: + * + * mov vreg/preg1, vreg2 + * + * back propagate reg1 to all vreg2's use points and def points, when all of them is in same bb + */ +void Riscv64GlobalOpt::BackPropOfRegister() { + bool secondTime = false; + std::set modifiedBb; + do { + FOR_ALL_BB(bb, cgfunc) { + if (bb->unreachable || (secondTime && modifiedBb.find(bb) == modifiedBb.end())) { + continue; + } + if (secondTime) { + modifiedBb.erase(bb); + } + FOR_BB_INSNS_REV(insn, bb) { + if (!insn->IsMachineInstruction() || + (insn->GetMachineOpcode() != MOP_xmovrr && insn->GetMachineOpcode() != MOP_wmovrr) || + IsSameReg(insn->opnds[0], insn->opnds[1]) || static_cast(insn->opnds[0])->IsZeroRegister() || + !static_cast(insn->opnds[1])->IsVirtualRegister() || insn->uses[0] == nullptr || + !OpndOnlyDefInCurBB(insn, 1) || !OpndOnlyUsedInCurBB(insn, 1, false) || !NoOverlap(insn, 1, true)) { + continue; + } + CHECK_FATAL(insn->defs[1]->size() == 1, "def point must be 1"); + Insn *defInsn = insn->defs[1]->begin()->GetInsn(); + unsigned short defProp = insn->defs[1]->begin()->GetProperty(); + short defI = insn->defs[1]->begin()->GetIndex(); + CHECK_FATAL(defI >= 0, "MUST NOT BE CALL INSN"); + int defIndex = insn->defs[1]->begin()->GetDUIndex(); + if (HasMultiGen(insn)) { + continue; + } + int targetId = insn->id; + CHECK_FATAL(IsSameReg(defInsn->opnds[defI], insn->opnds[1]), "must equal"); + MapleSet tmp(*(defInsn->uses[defIndex])); + modifiedBb.insert(bb); + for (auto use : tmp) { + Insn *useInsn = use.GetInsn(); + short i = use.GetIndex(); + CHECK_FATAL(i >= 0, "must not be call insn"); + CHECK_FATAL(useInsn->opnds[i], "Can not be null"); + if (useInsn->opnds[i]->IsRegister()) { + CHECK_FATAL(IsSameReg(useInsn->opnds[i], defInsn->opnds[defI]), "must equal"); + if (useInsn->id > targetId) { + ReplaceInsnSrcOperand(useInsn, i, use.GetProperty(), insn->opnds[0], insn); + } else { + useInsn->SetOperand(i, insn->opnds[0]); + } + } else if (useInsn->opnds[i]->IsMemoryAccessOperand()) { + MemOperand *mem = static_cast(useInsn->opnds[i]); + bool memBaseSame = mem->GetBaseRegister() && IsSameReg(mem->GetBaseRegister(), defInsn->opnds[defI]); + bool memIndexSame = mem->GetIndexRegister() && IsSameReg(mem->GetIndexRegister(), defInsn->opnds[defI]); + if (memBaseSame || memIndexSame) { + if (useInsn->id > targetId) { + ReplaceInsnSrcOperand(useInsn, i, use.GetProperty(), insn->opnds[0], insn); + } else { + MemOperand *newmem = static_cast(mem->Clone(cgfunc->memPool)); + CG_ASSERT(newmem != nullptr, "null ptr check"); + if (memBaseSame) { + newmem->SetBaseRegister(static_cast(insn->opnds[0])); + } + if (memIndexSame) { + newmem->SetIndexRegister(static_cast(insn->opnds[0])); + } + useInsn->SetOperand(i, newmem); + } + } + } else { + CHECK_FATAL(false, "impossible case"); + } + } + CleanDDForDestOperand(defInsn, defIndex); + GetRD()->InsertDUUDForDestOperand(defInsn, defI, defProp, insn, 0, DataInsnInfo::kNormal, false); + defInsn->SetOperand(0, insn->opnds[0]); + } + } + secondTime = true; + } while (!modifiedBb.empty()); +} + +/* + * replace m_insn i th opnd with new_opnd, and the new_opnd's def point is def_insn. + * m_insn and def_insn is in the same bb + * def_insn is mov + */ +void Riscv64GlobalOpt::ReplaceInsnSrcOperand(Insn *mInsn, short i, unsigned short prop, Operand *newOpnd, + Insn *defInsn) { + CHECK_FATAL(i >= 0, "must not be call insn"); + CHECK_FATAL(mInsn->bb == defInsn->bb, "must in the same bb"); + int mIndex = i + (prop & DataInsnInfo::kIndexQuickcalc); + MapleSet::iterator itSet2; + if (mInsn->defs[mIndex]) { + // Remove old def->use. + for (auto udInsnInfo : *(mInsn->defs[mIndex])) { + Insn *defInsn = udInsnInfo.GetInsn(); + int duIdx = udInsnInfo.GetDUIndex(); + + CG_ASSERT(defInsn->uses[duIdx], "CG internal error, defInsn should have uses."); + + itSet2 = defInsn->uses[duIdx]->find(DataInsnInfo(mInsn, i, prop & DataInsnInfo::kCallParam)); + CG_ASSERT(itSet2 != defInsn->uses[duIdx]->end(), "CG internal error, defInsn should have insn use."); + if (itSet2 != defInsn->uses[duIdx]->end()) { + defInsn->uses[duIdx]->erase(itSet2); + if (defInsn->uses[duIdx]->empty()) { + defInsn->uses[duIdx] = nullptr; + } + } + } + + // Remove all use->def. + mInsn->defs[mIndex]->clear(); + } + if (mInsn->defs[mIndex] == nullptr) { + mInsn->defs[mIndex] = + GetRD()->GetMemPool()->New>(GetRD()->GetMemAllocator().Adapter()); + } + if (defInsn->uses[0] == nullptr) { + defInsn->uses[0] = + GetRD()->GetMemPool()->New>(GetRD()->GetMemAllocator().Adapter()); + } + + defInsn->uses[0]->insert(DataInsnInfo(mInsn, i, prop)); + mInsn->defs[mIndex]->insert(DataInsnInfo(defInsn, 0)); + + switch (prop & DataInsnInfo::kAnyIndex) { + case DataInsnInfo::kNormal: + mInsn->opnds[i] = newOpnd; + break; + case DataInsnInfo::kSecondMemAddr: + CG_ASSERT(false, "CG internal error, Could not replace the second memory address."); + break; + case DataInsnInfo::kBaseReg: { + CG_ASSERT(newOpnd->IsRegister(), "CG Internal error, new_opnd should be a register operand."); + CG_ASSERT(mInsn->opnds[i]->IsMemoryAccessOperand(), + "CG Internal error, insn->opnds[index] should be a memory operand."); + + MemOperand *memOpnd = static_cast(static_cast(mInsn->opnds[i])->Clone(cgfunc->memPool)); + CG_ASSERT(memOpnd != nullptr, "null ptr check"); + mInsn->SetOperand(i, memOpnd); + memOpnd->SetBaseRegister(static_cast(newOpnd)); + break; + } + case DataInsnInfo::kIndexReg: { + CG_ASSERT(newOpnd->IsRegister(), "CG Internal error, new_opnd should be a register operand."); + CG_ASSERT(mInsn->opnds[i]->IsMemoryAccessOperand(), + "CG Internal error, insn->opnds[index] should be a memory operand."); + + MemOperand *memOpnd = static_cast(static_cast(mInsn->opnds[i])->Clone(cgfunc->memPool)); + mInsn->SetOperand(i, memOpnd); + break; + } + case DataInsnInfo::kCallParam: + CG_ASSERT(false, "CG internal error, we don't need to replace call params."); + break; + default: + CG_ASSERT(false, "CG invalid property."); + break; + } +} + +/*uxtb w0, w0 --> null + *uxth w0, w0 --> null + * + * condition: + * 1. validbits(w0)<=8,16,32 + * 2. the first operand is same as the second operand + * + **uxtb w0, w1 --> null + **uxth w0, w1 --> null + * + * condition: + * 1. validbits(w1)<=8,16,32 + * 2. the use points of w0 has only one define point, that is uxt w0, w1 + */ + +void Riscv64GlobalOpt::DeleteRedundantUxt() { +// FIXME +#if 0 + FOR_ALL_BB(bb, cgfunc) { + if (bb->unreachable) { + continue; + } + FOR_BB_INSNS_SAFE(insn, bb, ninsn) { + std::set insnChecked1; + std::set insnChecked2; + if ((insn->GetMachineOpcode() == MOP_xuxth32 && GetMaximumValidBit(insn, 1, insnChecked1) <= 16) || + (insn->GetMachineOpcode() == MOP_xuxtb32 && GetMaximumValidBit(insn, 1, insnChecked2) <= 8)) { + Operand *firstOpnd = insn->GetOperand(0); + Operand *secondOpnd = insn->GetOperand(1); + if (IsSameReg(firstOpnd, secondOpnd)) { + GetRD()->RemoveDUUDForInsn(insn); + bb->RemoveInsn(insn); + } else { + if (!insn->uses[0]) { + GetRD()->RemoveDUUDForInsn(insn); + bb->RemoveInsn(insn); + continue; + } + + CG_ASSERT(insn->uses[0], "Operand must be defined before used"); + bool toDoOpt = true; + vector useinfos; + for (auto useInfo : *(insn->uses[0])) { + Insn *useInsn = useInfo.GetInsn(); + int udidx = useInfo.GetUDIndex(); + useinfos.push_back(useInfo); + if (useInsn->defs[udidx]->size() > 1) { + toDoOpt = false; + break; + } + } + if (!toDoOpt) { + continue; + } + for (vector::iterator itr = useinfos.begin(); itr != useinfos.end(); itr++) { + GetRD()->ReplaceInsnSrcOperand(itr->GetInsn(), itr->GetIndex(), itr->GetProperty(), insn->GetOperand(1), + insn, 1, DataInsnInfo::kNormal); + } + GetRD()->RemoveDUUDForInsn(insn); + bb->RemoveInsn(insn); + } + } + } + } +#endif +} + +/* condition: + * 1. if operand is defined by mov, find the defination of it's src continually + * + **NOTE: + * set insn_checked is used to avoid loop defination,leading to program can't exit + * for example: + * + * mov reg1, reg2 <------- + * .... | + * uxth reg 3, reg2 | + * .... | + * mov reg2, reg1 ----| + */ +int Riscv64GlobalOpt::GetMaximumValidBit(Insn *insn, short udidx, std::set &insnChecked) const { + // CG_ASSERT(insn->defs[udidx], ",wrong arguments, operand must be defined before used"); + if (insn->defs[udidx] == nullptr) { + return 64; + } + + int validBit; + int nMaxValidBit = 0; + + for (auto defInfo : *(insn->defs[udidx])) { + Insn *defInsn = defInfo.GetInsn(); + // insn_checked is used to avoid loop definition + if (insnChecked.find(defInsn) == insnChecked.end()) { + insnChecked.insert(defInsn); + } else { + continue; + } + + MOperator mop = defInsn->GetMachineOpcode(); + if (mop == MOP_wmovrr || mop == MOP_xmovrr) { + validBit = GetMaximumValidBit(defInsn, 1, insnChecked); + } else { + validBit = GetInsnValidBit(defInsn); + } + + nMaxValidBit = nMaxValidBit < validBit ? validBit : nMaxValidBit; + + if (defInfo.IsMulGen()) { + DataInsnInfo *insnInfo = defInfo.GetPrevMultiGenInsn(); + CG_ASSERT(insnInfo, "get prev multigen insninfo failed"); + do { + Insn *insn = insnInfo->GetInsn(); + // insn_checked is used to avoid loop definition + if (insnChecked.find(insn) == insnChecked.end()) { + insnChecked.insert(insn); + } else { + insnInfo = insnInfo->GetPrevMultiGenInsn(); + continue; + } + + mop = defInsn->GetMachineOpcode(); + if (mop == MOP_wmovrr || mop == MOP_xmovrr) { + validBit = GetMaximumValidBit(defInsn, 1, insnChecked); + } else { + validBit = GetInsnValidBit(defInsn); + } + + nMaxValidBit = nMaxValidBit < validBit ? validBit : nMaxValidBit; + + insnInfo = insnInfo->GetPrevMultiGenInsn(); + } while (insnInfo); + } + } + + return nMaxValidBit; +} + +int Riscv64GlobalOpt::GetInsnValidBit(Insn *insn) { + MOperator mop = insn->GetMachineOpcode(); + int nRet; + switch (mop) { + case MOP_xslt: + case MOP_xsltu: + case MOP_xslti: + case MOP_xsltiu: + case MOP_xsgt: + case MOP_xsgtu: + case MOP_xseqz: + case MOP_xsnez: + nRet = 1; + break; + case MOP_wldrb: + case MOP_wldrsb: + nRet = 8; + break; + case MOP_wldrh: + case MOP_wldrsh: + nRet = 16; + break; + case MOP_wmovrr: + case MOP_wldr: + case MOP_wldxr: + case MOP_wldaxr: + case MOP_wldaxp: + nRet = 32; + break; + default: + nRet = 64; + break; + } + + return nRet; +} + +// if used Operand in insn is defined by one in all define insn, return true +bool Riscv64GlobalOpt::OpndDefByOne(Insn *insn, int useidx) const { + CG_ASSERT(insn->GetOperand(useidx) && insn->GetOperand(useidx)->IsRegister(), "the used Operand must be Register"); + // Zero Register don't need be defined + if (insn->GetOperand(useidx)->IsZeroRegister()) { + return false; + } + CG_ASSERT(insn->defs[useidx], "Operand must be defined before used"); + for (auto defInfo : *(insn->defs[useidx])) { + if (defInfo.IsMulGen()) { + return false; + } + Insn *definsn = defInfo.GetInsn(); + CG_ASSERT(definsn, "definsn must be exist"); + if (!InsnDefOne(definsn)) { + return false; + } + } + return true; +} + +// if used Operand in insn is defined by zero in all define insn, return true +bool Riscv64GlobalOpt::OpndDefByZero(Insn *insn, int useidx) const { + CG_ASSERT(insn->GetOperand(useidx) && insn->GetOperand(useidx)->IsRegister(), "the used Operand must be Register"); + // Zero Register don't need be defined + if (insn->GetOperand(useidx)->IsZeroRegister()) { + return true; + } + CG_ASSERT(insn->defs[useidx], "Operand must be defined before used"); + for (auto defInfo : *(insn->defs[useidx])) { + if (defInfo.IsMulGen()) { + return false; + } + Insn *definsn = defInfo.GetInsn(); + CG_ASSERT(definsn, "definsn must be exist"); + if (!InsnDefZero(definsn)) { + return false; + } + } + return true; +} + +// if defined operand(must be first insn currently) in insn is const one, return true +bool Riscv64GlobalOpt::InsnDefOne(Insn *insn) { + CG_ASSERT(insn, "insn must not be null"); + MOperator defMop = insn->GetMachineOpcode(); + switch (defMop) { + case MOP_xmovri64: { + Operand *srcOpnd = insn->GetOperand(1); + CG_ASSERT(srcOpnd->IsIntImmediate(), "expects ImmOperand"); + ImmOperand *srcConst = static_cast(srcOpnd); + int64 srcConstValue = srcConst->GetValue(); + if (srcConstValue == 1) { + return true; + } + return false; + } + default: + return false; + } +} + +// if defined operand(must be first insn currently) in insn is const zero, return true +bool Riscv64GlobalOpt::InsnDefZero(Insn *insn) { + CG_ASSERT(insn, "insn must not be null"); + MOperator defMop = insn->GetMachineOpcode(); + switch (defMop) { + case MOP_xmovri64: { + Operand *srcOpnd = insn->GetOperand(1); + CG_ASSERT(srcOpnd->IsIntImmediate(), "expects ImmOperand"); + ImmOperand *srcConst = static_cast(srcOpnd); + int64 srcConstValue = srcConst->GetValue(); + if (srcConstValue == 0) { + return true; + } + return false; + } + case MOP_xmovrr: + case MOP_wmovrr: + return insn->GetOperand(1)->IsZeroRegister(); + default: + return false; + } +} + +// if used Operand in insn is defined by one valid bit in all define insn, return true +bool Riscv64GlobalOpt::OpndDefByOneOrZero(Insn *insn, int useidx) const { + if (insn->GetOperand(useidx)->IsZeroRegister()) { + return true; + } + CG_ASSERT(insn->defs[useidx], "Operand must be defined before used"); + for (auto defInfo : *(insn->defs[useidx])) { + if (defInfo.IsMulGen()) { + return false; + } + Insn *definsn = defInfo.GetInsn(); + CG_ASSERT(definsn, "definsn must be exist"); + if (!InsnDefOneOrZero(definsn)) { + return false; + } + } + return true; +} + +// if defined operand(must be first insn currently) in insn has only one valid bit, return true +bool Riscv64GlobalOpt::InsnDefOneOrZero(Insn *insn) { + CG_ASSERT(insn, "insn must not be null"); + MOperator defMop = insn->GetMachineOpcode(); + switch (defMop) { + case MOP_xslt: + case MOP_xsltu: + case MOP_xslti: + case MOP_xsltiu: + case MOP_xsgt: + case MOP_xsgtu: + case MOP_xseqz: + case MOP_xsnez: + return true; + case MOP_xmovri64: { + Operand *defOpnd = insn->GetOperand(1); + CG_ASSERT(defOpnd->IsIntImmediate(), "expects ImmOperand"); + ImmOperand *defConst = static_cast(defOpnd); + int64 defConstValue = defConst->GetValue(); + if (defConstValue != 0 && defConstValue != 1) { + return false; + } else { + return true; + } + } + case MOP_xmovrr: + case MOP_wmovrr: { + return insn->GetOperand(1)->IsZeroRegister(); + } + case MOP_wlsrrri5: + case MOP_xlsrrri6: { + Operand *opnd2 = insn->GetOperand(2); + CG_ASSERT(opnd2 && opnd2->IsIntImmediate(), "expects ImmOperand"); + ImmOperand *opndimm = static_cast(opnd2); + int64 shiftbits = opndimm->GetValue(); + if ((defMop == MOP_wlsrrri5 && shiftbits == 31) || (defMop == MOP_xlsrrri6 && shiftbits == 63)) { + return true; + } else { + return false; + } + } + default: + return false; + } +} + +bool Riscv64GlobalOpt::OpndOnlyUsedInCurBB(Insn *insn, short opndidx, bool isDest) { + if (isDest) { + if (insn->uses[opndidx] == nullptr) { + return true; + } + BB *curBB = insn->bb; + for (auto useInfo : *(insn->uses[opndidx])) { + Insn *useinsn = useInfo.GetInsn(); + if (useinsn->bb != curBB) { + return false; + } + } + return true; + } else { + if (insn->defs[opndidx] == nullptr) { + return false; + } + BB *curBB = insn->bb; + for (auto def : *(insn->defs[opndidx])) { + Insn *defInsn = def.GetInsn(); + int defInsnIndex = def.GetDUIndex(); + for (auto use : *(defInsn->uses[defInsnIndex])) { + CHECK_FATAL(use.GetIndex() >= 0, "should be"); + if (use.GetInsn()->bb != curBB || !OpndOnlyDefInCurBB(use.GetInsn(), use.GetIndex())) { + return false; + } + } + } + return true; + } +} + +bool Riscv64GlobalOpt::RedefPointIsExist(Insn *insn, short opndidx) { + return insn->redefine[opndidx] != nullptr; +} + +bool Riscv64GlobalOpt::IsSameReg(Operand *firstOpnd, Operand *secondOpnd) { + CG_ASSERT(firstOpnd->IsRegister() && secondOpnd->IsRegister(), + "first_opnd and second_opnd should be Register Operand"); + RegOperand *firstReg = static_cast(firstOpnd); + RegOperand *secondReg = static_cast(secondOpnd); + return firstReg->RegNumEqual(secondReg) && firstReg->GetSize() == secondReg->GetSize(); +} + +} // namespace maplebe diff --git a/mapleall/maple_be/src/cg/riscv64/riscv64_insn.cpp b/mapleall/maple_be/src/cg/riscv64/riscv64_insn.cpp new file mode 100644 index 0000000..013b40d --- /dev/null +++ b/mapleall/maple_be/src/cg/riscv64/riscv64_insn.cpp @@ -0,0 +1,288 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#include "riscv64_insn.h" +#include "riscv64_cg.h" +#include "insn.h" +#include "cg_assert.h" +#include + +namespace maplebe { + +int32_t Riscv64Insn::GetResultNum() { + const Riscv64MD *md = &Riscv64CG::kMd[mop_]; + return md->resnum; +} + +int32_t Riscv64Insn::GetOpndNum() { + const Riscv64MD *md = &Riscv64CG::kMd[mop_]; + return md->opndnum; +} + +Operand *Riscv64Insn::GetResult(int32_t i) { + CG_ASSERT(i < GetResultNum(), "index out of range"); + const Riscv64MD *md = &Riscv64CG::kMd[mop_]; + if (md->IsStore()) { + return GetOperand(GetOpndNum() + i); + } else { + return GetOperand(i); + } +} + +Operand *Riscv64Insn::GetResultMemOpnd() { + const Riscv64MD *md = &Riscv64CG::kMd[mop_]; + if (md->IsStore()) { + return GetOperand(GetOpndNum()); + } else { + return GetOperand(GetResultNum()); + } +} + +void Riscv64Insn::SetOpnd(int32_t i, Operand *opnd) { + CG_ASSERT(i < GetOpndNum(), "index out of range"); + if (IsDestRegAlsoSrcReg()) { + opnds[i] = opnd; + } + if (IsStore()) { + opnds[i] = opnd; + } else { + opnds[GetResultNum() + i] = opnd; + } +} + +Operand *Riscv64Insn::GetOpnd(int32_t i) { + CG_ASSERT(i < GetOpndNum(), "index out of range"); + if (IsDestRegAlsoSrcReg()) { + return GetOperand(i); + } + const Riscv64MD *md = &Riscv64CG::kMd[mop_]; + if (md->IsStore()) { + return GetOperand(i); + } else { + return GetOperand(GetResultNum() + i); + } +} + +Operand *Riscv64Insn::GetMemOpnd() { + const Riscv64MD *md = &Riscv64CG::kMd[mop_]; + if (md->IsLoad()) { + return GetOperand(GetResultNum()); + } + return GetOperand(GetOpndNum()); +} + +bool Riscv64Insn::IsVolatile() { + const Riscv64MD *md = &Riscv64CG::kMd[mop_]; + return md->IsVolatile(); +} + +bool Riscv64Insn::IsMemAccessBar() { + const Riscv64MD *md = &Riscv64CG::kMd[mop_]; + return md->IsMemAccessBar(); +} + +bool Riscv64Insn::IsBranch() { + const Riscv64MD *md = &Riscv64CG::kMd[mop_]; + return md->IsBranch(); +} + +bool Riscv64Insn::IsCall() { + const Riscv64MD *md = &Riscv64CG::kMd[mop_]; + return md->IsCall(); +} + +bool Riscv64Insn::IsTailCall() const { + return mop_ == MOP_tail_call_opt_xbl || mop_ == MOP_tail_call_opt_xblr; +} + +bool Riscv64Insn::IsClinit() { + if (mop_ == MOP_clinit || mop_ == MOP_clinit_tail) { + return true; + } + return false; +} + +bool Riscv64Insn::CanThrow() { + const Riscv64MD *md = &Riscv64CG::kMd[mop_]; + return md->CanThrow(); +} + +bool Riscv64Insn::IsMemAccess() { + const Riscv64MD *md = &Riscv64CG::kMd[mop_]; + return md->IsMemAccess(); +} + +bool Riscv64Insn::MayThrow() { + const Riscv64MD *md = &Riscv64CG::kMd[mop_]; + if (md->IsMemAccess()) { + Riscv64MemOperand *aarchMemOpnd = static_cast(GetMemOpnd()); + CG_ASSERT(aarchMemOpnd, "CG invalid memory operand."); + RegOperand *baseRegister = aarchMemOpnd->GetBaseRegister(); + if (baseRegister && + (baseRegister->GetRegisterNumber() == RFP || baseRegister->GetRegisterNumber() == RSP)) { + return false; + } + } + return md->CanThrow(); +} + +bool Riscv64Insn::IsCallToFunctionThatNeverReturns() { + if (IsIndirectCall()) { + return false; + } + FuncNameOperand *target = static_cast(GetCallTargetOperand()); + CHECK_FATAL(target, "target is null in Riscv64Insn::IsCallToFunctionThatNeverReturns"); + MIRSymbol *funcst = target->GetFunctionSymbol(); + CG_ASSERT(funcst->sKind == kStFunc, ""); + MIRFunction *func = funcst->value.mirFunc; + return func->NeverReturns(); +} + +bool Riscv64Insn::IsDMBInsn() const { + const Riscv64MD *md = &Riscv64CG::kMd[mop_]; + return md->IsDMB(); +} + +bool Riscv64Insn::IsMove() { + const Riscv64MD *md = &Riscv64CG::kMd[mop_]; + return md->IsMove(); +} + +bool Riscv64Insn::IsLoad() { + const Riscv64MD *md = &Riscv64CG::kMd[mop_]; + return md->IsLoad(); +} + +bool Riscv64Insn::IsStore() { + const Riscv64MD *md = &Riscv64CG::kMd[mop_]; + return md->IsStore(); +} + +bool Riscv64Insn::IsLoadPair() { + const Riscv64MD *md = &Riscv64CG::kMd[mop_]; + return md->IsLoadPair(); +} + +bool Riscv64Insn::IsStorePair() { + const Riscv64MD *md = &Riscv64CG::kMd[mop_]; + return md->IsStorePair(); +} + +bool Riscv64Insn::IsLoadStorePair() { + const Riscv64MD *md = &Riscv64CG::kMd[mop_]; + return md->IsLoadStorePair(); +} + +bool Riscv64Insn::IsLoadAddress() { + const Riscv64MD *md = &Riscv64CG::kMd[mop_]; + return md->IsLoadAddress(); +} + +bool Riscv64Insn::IsAtomic() { + const Riscv64MD *md = &Riscv64CG::kMd[mop_]; + return md->IsAtomic(); +} + +bool Riscv64Insn::IsPartDef() const { + const Riscv64MD *md = &Riscv64CG::kMd[mop_]; + return md->IsPartDef(); +} + +uint32 Riscv64Insn::GetLatencyType() const { + const Riscv64MD *md = &Riscv64CG::kMd[mop_]; + return md->GetLatencyType(); +} + +bool Riscv64Insn::IsYieldpoint() { + // It is a yieldpoint if loading from a dedicated + // register holding polling page address: + // ldr wzr, [RYP] + if (IsLoad()) { + auto mem = static_cast(GetOpnd(0)); + return (mem != nullptr && mem->GetBaseRegister() != nullptr && mem->GetBaseRegister()->GetRegisterNumber() == RYP); + } + return false; +} + +int32_t Riscv64Insn::CopyOperands() { + MOperator opc = mop_; + if (this->IsMove()) { + return 0; + } else if ((mop_ >= MOP_xaddrrr && mop_ <= MOP_ssub) || (mop_ >= MOP_xlslrri6 && mop_ <= MOP_wlsrrrr)) { + ImmOperand *immopnd = nullptr; + Operand *opnd2 = GetOpnd(1); + if (opnd2 != nullptr && opnd2->IsIntImmediate()) { + immopnd = static_cast(opnd2); + if (immopnd != nullptr && immopnd->IsZero()) { + return 0; + } + } + } else if (opc > MOP_xmulrrr && opc <= MOP_xvmuld) { + Operand *opnd2 = GetOpnd(1); + if (opnd2 != nullptr && opnd2->IsIntImmediate()) { + ImmOperand *immopnd = static_cast(opnd2); + if (immopnd != nullptr && immopnd->GetValue() == 1) { + return 0; + } + } + } + return -1; +} + +/* + * Precondition: The given insn is a jump instruction. + * Get the jump target label operand index from the given instruction. + * Note: MOP_xbr is a jump instruction, but the target is unknown at compile time, + * because a register instead of label. So we don't take it as a branching instruction. + */ +int Riscv64Insn::GetJumpTargetIdx() const { + int operandIdx = 0; + switch (mop_) { + // unconditional jump + case MOP_xuncond: { + operandIdx = 0; + break; + } + // conditional jump + case MOP_beq: + case MOP_bne: + case MOP_blt: + case MOP_ble: + case MOP_bgt: + case MOP_bge: + case MOP_blo: + case MOP_bls: + case MOP_bhs: + case MOP_bhi: + { + operandIdx = 2; + break; + } + case MOP_beqz: + case MOP_bnez: + case MOP_bltz: + case MOP_blez: + case MOP_bgtz: + case MOP_bgez: + operandIdx = 1; + break; + default: + ASSERT(0, "Not a jump insn"); + } + + return operandIdx; +} + +} // namespace maplebe diff --git a/mapleall/maple_be/src/cg/riscv64/riscv64_insn_slct.cpp b/mapleall/maple_be/src/cg/riscv64/riscv64_insn_slct.cpp new file mode 100644 index 0000000..58685b2 --- /dev/null +++ b/mapleall/maple_be/src/cg/riscv64/riscv64_insn_slct.cpp @@ -0,0 +1,2530 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#include "riscv64_cg_func.h" +#include "riscv64_cg.h" +#include "riscv64_rt_support.h" +#include "opcode_info.h" // mapleir/include/opcode_info.h +#include "cg_assert.h" +#include "special_func.h" +#include +#include + +namespace maplebe { + +using namespace maple; + +#define CLANG (mirModule.IsCModule()) + +MOperator Riscv64CGFunc::PickAddInsn(PrimType primtype, bool ismem) { + CG_ASSERT(false, "NYI PickAddInsn"); + return MOP_undef; +} + +MOperator Riscv64CGFunc::PickMpyInsn(PrimType primtype, bool ismem) { + CG_ASSERT(false, "NYI PickAddInsn"); + return MOP_undef; +} + +MOperator Riscv64CGFunc::PickJmpInsn(Opcode brop, Opcode cmpop, bool isfloat, bool issigned, bool isZero) { + switch (cmpop) { + default: + CG_ASSERT(false, "PickJmpInsn error"); + case OP_ne: + if (isZero) { + return static_cast(brop == OP_brtrue ? MOP_bnez : MOP_beqz); + } else { + return static_cast(brop == OP_brtrue ? MOP_bne : MOP_beq); + } + case OP_eq: + if (isZero) { + return static_cast(brop == OP_brtrue ? MOP_beqz : MOP_bnez); + } else { + return static_cast(brop == OP_brtrue ? MOP_beq : MOP_bne); + } + case OP_lt: + if (isZero) { + return static_cast(brop == OP_brtrue ? MOP_bltz + : (isfloat ? MOP_bpl : MOP_bgez)); + } else { + return static_cast(brop == OP_brtrue ? (issigned ? MOP_blt : MOP_blo) + : (isfloat ? MOP_bpl : (issigned ? MOP_bge : MOP_bhs))); + } + case OP_le: + if (isZero) { + return static_cast(brop == OP_brtrue ? MOP_blez + : (isfloat ? MOP_bhi : MOP_bgtz)); + } else { + return static_cast(brop == OP_brtrue ? (issigned ? MOP_ble : MOP_bls) + : (isfloat ? MOP_bhi : (issigned ? MOP_bgt : MOP_bhi))); + } + case OP_gt: + if (isZero) { + return static_cast(brop == OP_brtrue ? (isfloat ? MOP_bhi : MOP_bgtz) : MOP_blez); + } else { + return static_cast(brop == OP_brtrue ? (isfloat ? MOP_bhi : (issigned ? MOP_bgt : MOP_bhi)) + : (issigned ? MOP_ble : MOP_bls)); + } + case OP_ge: + if (isZero) { + return static_cast(brop == OP_brtrue ? (isfloat ? MOP_bpl : MOP_bgez) : MOP_bltz); + } else { + return static_cast(brop == OP_brtrue ? (isfloat ? MOP_bpl : (issigned ? MOP_bge : MOP_bhs)) + : (issigned ? MOP_blt : MOP_blo)); + } + } +} + +void Riscv64CGFunc::SelectCondGoto(LabelOperand *targetopnd, Opcode jmpop, Opcode cmpop, Operand *opnd0, Operand *opnd1, + PrimType primType, bool signedCond) { + CG_ASSERT(targetopnd != nullptr, "no branch target"); + + bool isMem = (opnd0->op_kind_ == Operand::Opd_Mem); + if (opnd0->IsRegister()) { + opnd0 = SelectZeroSignExt(opnd0, primType); + } else { + opnd0 = LoadIntoRegister(opnd0, primType); + } +#if 0 + if (isMem && !(primType == PTY_u8 || primType == PTY_u16 || primType == PTY_u32 || primType == PTY_u64)) { + // Riscv operations need to be sign extended. + MOperator mop = MOP_undef; + switch (primType) { + case PTY_u8: + mop = MOP_xsxtb64; + break; + case PTY_u16: + mop = MOP_xsxth64; + break; + case PTY_u32: + mop = MOP_xsxtw64; + break; + default: + break; + } + if (mop != MOP_undef) { + Operand *dest = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, (opnd0->size_ == 32) ? 4 : 8)); + curbb->AppendInsn(cg->BuildInstruction(mop, dest, opnd0)); + opnd0 = dest; + } + } +#endif + + bool isfloat = IsPrimitiveFloat(primType); + MOperator branchOp; + if (isfloat) { + opnd1 = LoadIntoRegister(opnd1, primType); + + MOperator op; + RegOperand *fcmpResult; + branchOp = MOP_beq; + switch (cmpop) { + case OP_eq: + op = (primType == PTY_f32) ? MOP_scmpeqrr : MOP_dcmpeqrr; + if (jmpop == OP_brtrue) { + branchOp = MOP_bne; + } + break; + case OP_ne: + op = (primType == PTY_f32) ? MOP_scmpeqrr : MOP_dcmpeqrr; + if (jmpop == OP_brfalse) { + branchOp = MOP_bne; + } + break; + case OP_gt: + op = (primType == PTY_f32) ? MOP_scmpgtrr : MOP_dcmpgtrr; + if (jmpop == OP_brtrue) { + branchOp = MOP_bne; + } + break; + case OP_lt: + op = (primType == PTY_f32) ? MOP_scmpltrr : MOP_dcmpltrr; + if (jmpop == OP_brtrue) { + branchOp = MOP_bne; + } + break; + case OP_ge: + op = (primType == PTY_f32) ? MOP_scmpgerr : MOP_dcmpgerr; + if (jmpop == OP_brtrue) { + branchOp = MOP_bne; + } + break; + case OP_le: + op = (primType == PTY_f32) ? MOP_scmplerr : MOP_dcmplerr; + if (jmpop == OP_brtrue) { + branchOp = MOP_bne; + } + break; + default: + op = MOP_undef; + CG_ASSERT(false, "illegal logical operator"); + } + fcmpResult = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8u)); + curbb->AppendInsn(cg->BuildInstruction(op, fcmpResult, opnd0, opnd1)); + Riscv64RegOperand *xzr = Riscv64RegOperand::GetZeroRegister(64); + curbb->AppendInsn(cg->BuildInstruction(branchOp, fcmpResult, xzr, targetopnd)); + } else { + bool isimm = opnd1->op_kind_ == Operand::Opd_Immediate; + isMem = (opnd1->op_kind_ == Operand::Opd_Mem); + bool isReg = (opnd1->op_kind_ == Operand::Opd_Register); + if (!isReg && !isimm) { + opnd1 = SelectCopy(opnd1, primType, primType); + } else { + opnd0 = LoadIntoRegister(opnd0, primType); + if (isReg && (opnd1->size_ < 64)) { + opnd1 = SelectZeroSignExt(opnd1, primType); + } + } + + bool isZero = false; + if (isimm) { + RegOperand *dest; + if (static_cast(opnd1)->GetValue() == 0) { + isZero = true; + } else { + regno_t vRegNo = New_V_Reg(kRegTyInt, 8); + dest = CreateVirtualRegisterOperand(vRegNo); + curbb->AppendInsn(cg->BuildInstruction(MOP_xmovri64, dest, opnd1)); + opnd1 = dest; + } + } + bool issigned = IsPrimitiveInteger(primType) ? IsSignedInteger(primType) : (signedCond ? true : false); + branchOp = PickJmpInsn(jmpop, cmpop, isfloat, issigned, isZero); + if (isZero) { + curbb->AppendInsn(cg->BuildInstruction(branchOp, opnd0, targetopnd)); + } else { + curbb->AppendInsn(cg->BuildInstruction(branchOp, opnd0, opnd1, targetopnd)); + } + } + curbb->SetKind(BB::kBBIf); +} + +/* brtrue @label0 (ge u8 i32 ( + cmp i32 i64 (dread i64 %Reg2_J, dread i64 %Reg4_J), + constVal i32 0)) + ===> + cmp r1, r2 + bge Cond, label0 + */ +void Riscv64CGFunc::SelectCondSpecial(CondGotoNode *stmt, BaseNode *expr) { + CG_ASSERT((expr->op == OP_cmp && "unexpect opcode"), ""); + Operand *opnd0 = HandleExpr(expr, expr->Opnd(0)); + Operand *opnd1 = HandleExpr(expr, expr->Opnd(1)); + CompareNode *node = static_cast(expr); + bool isfloat = IsPrimitiveFloat(node->opndType); + opnd0 = LoadIntoRegister(opnd0, node->opndType); + // most of FP constants are passed as Riscv64MemOperand + // except 0.0 which is passed as Opd_FPZeroImmediate + Operand::OperandType opnd1ty = opnd1->op_kind_; + if (opnd1ty != Operand::Opd_Immediate && opnd1ty != Operand::Opd_FPZeroImmediate) { + opnd1 = LoadIntoRegister(opnd1, node->opndType); + } + SelectRiscv64Cmp(opnd0, opnd1, !isfloat, GetPrimTypeBitSize(node->opndType)); + // handle condgoto now. + LabelIdx labelIdx = stmt->offset; + BaseNode *condnode = stmt->Opnd(0); + LabelOperand *targetopnd = GetOrCreateLabelOperand(labelIdx); + Opcode cmpop = condnode->op; + PrimType primType = static_cast(condnode)->opndType; + isfloat = IsPrimitiveFloat(primType); + bool issigned = IsPrimitiveInteger(primType) ? IsSignedInteger(primType) : (IsSignedInteger(condnode->primType) ? true : false); + MOperator jmpOp = PickJmpInsn(stmt->op, cmpop, isfloat, issigned); + curbb->AppendInsn(cg->BuildInstruction(jmpOp, targetopnd)); +} + +void Riscv64CGFunc::SelectCondGoto(CondGotoNode *stmt, Operand *opnd0, Operand *opnd1) { + // handle brfalse/brtrue op, opnd0 can be a compare node or non-compare node + // such as a dread for example + LabelIdx labelIdx = stmt->offset; + BaseNode *condnode = stmt->Opnd(0); + LabelOperand *targetopnd = GetOrCreateLabelOperand(labelIdx); + Opcode cmpop; + + PrimType primType; + if (kOpcodeInfo.IsCompare(condnode->op)) { + cmpop = condnode->op; + primType = static_cast(condnode)->opndType; + } else { + // not a compare node; dread for example, take its ptype + cmpop = OP_ne; + primType = condnode->primType; + } + + SelectCondGoto(targetopnd, stmt->op, cmpop, opnd0, opnd1, primType, IsSignedInteger(condnode->primType)); +} + +void Riscv64CGFunc::SelectGoto(GotoNode *stmt) { + Operand *targetopnd = GetOrCreateLabelOperand(stmt->offset); + curbb->AppendInsn(cg->BuildInstruction(MOP_xuncond, targetopnd)); +} + +Operand *Riscv64CGFunc::SelectAdd(BinaryNode *node, Operand *opnd0, Operand *opnd1) { + PrimType dtype = node->primType; + RegOperand *resopnd = CreateRegisterOperandOfType(dtype); + PrimType prmtype; + if (!IsPrimitiveVector(dtype)) { + bool issigned = IsSignedInteger(dtype); + uint32 dsize = GetPrimTypeBitSize(dtype); + bool is64bits = (dsize == 64); + bool isfloat = IsPrimitiveFloat(dtype); + PrimType prmtype = + isfloat ? dtype : ((is64bits ? (issigned ? PTY_i64 : PTY_u64) : (issigned ? PTY_i32 : PTY_u32))); // promoted type + bool doExtend = false; + if (cg->cgopt_.DoZeroExtend()) { + doExtend = true; + } + // Need to zero extend a smaller sized unsigned type + uint32 size = (dtype == PTY_u8) ? 8 : ((dtype == PTY_u16) ? 16 : (dtype == PTY_u32 ? 32 : 0)); + if (doExtend && size > 0) { + RegOperand *tmpopnd = CreateRegisterOperandOfType(dtype); + SelectAdd(tmpopnd, opnd0, opnd1, prmtype); + GenerateZext(resopnd, tmpopnd, dtype, size); + } else { + SelectAdd(resopnd, opnd0, opnd1, prmtype); + } + } else { + prmtype = dtype; + SelectVecAdd(resopnd, opnd0, opnd1, prmtype); + } + return resopnd; +} + +void Riscv64CGFunc::SelectAdd(Operand *resopnd, Operand *opnd0, Operand *opnd1, PrimType prmtype) { + Operand::OperandType opnd0ty = opnd0->op_kind_; + Operand::OperandType opnd1ty = opnd1->op_kind_; + uint32 dsize = GetPrimTypeBitSize(prmtype); + bool is64bits = (dsize == 64); + if (opnd0ty != Operand::Opd_Register && opnd1ty != Operand::Opd_Register) { + SelectAdd(resopnd, SelectCopy(opnd0, prmtype, prmtype), opnd1, prmtype); + } else if (opnd0ty == Operand::Opd_Register && opnd1ty != Operand::Opd_Register) { + if (opnd1ty == Operand::Opd_Immediate) { + Riscv64ImmOperand *immopnd = static_cast(opnd1); + // Add can have immediate 2nd source but Sub cannot + if (immopnd->IsInBitSize(11)) { + curbb->AppendInsn( + cg->BuildInstruction(is64bits ? MOP_xaddrri12 : MOP_waddrri12, resopnd, opnd0, immopnd)); + } else { + // load into register + RegOperand *regopnd; + if (isAfterRegAlloc) { + CHECK_FATAL(curbb->isProEpilog, "Not prolog/epilog"); + + RegType regty = GetRegTyFromPrimTyRiscv64(prmtype); + uint8 bytelen = GetPrimTypeSize(prmtype); + // Use one of the temp reg, R31, since this is at the end of epilog + // where sp is being adjusted. No more instruction should be after this. + regopnd = GetOrCreatePhysicalRegisterOperand(R31, bytelen, regty); + } else { + regopnd = CreateRegisterOperandOfType(prmtype); + } + curbb->AppendInsn( + cg->BuildInstruction(MOP_xmovri64, regopnd, immopnd)); + curbb->AppendInsn( + cg->BuildInstruction(is64bits ? MOP_xaddrrr : MOP_waddrrr, resopnd, opnd0, regopnd)); + } + } else { + SelectAdd(resopnd, opnd0, SelectCopy(opnd1, prmtype, prmtype), prmtype); + } + } else if (opnd0ty != Operand::Opd_Register && opnd1ty == Operand::Opd_Register) { + SelectAdd(resopnd, opnd1, opnd0, prmtype); // commutative + } else { + if (IsPrimitiveFloat(prmtype)) { + curbb->AppendInsn(cg->BuildInstruction(is64bits ? MOP_dadd : MOP_sadd, resopnd, opnd0, opnd1)); + } else if (IsPrimitiveInteger(prmtype)) { + curbb->AppendInsn(cg->BuildInstruction(is64bits ? MOP_xaddrrr : MOP_waddrrr, resopnd, opnd0, opnd1)); + } else { + CG_ASSERT(false, "NYI add"); + } + } +} + +Operand *Riscv64CGFunc::SelectAddroflabel(AddroflabelNode *expr) { + // adrp reg, label-id + regno_t vRegNo = New_V_Reg(kRegTyInt, expr->SizeOfInstr()); + Operand *dst = CreateVirtualRegisterOperand(vRegNo); + Operand *immOpnd = CreateImmOperand(expr->offset, 64, false); + curbb->AppendInsn(cg->BuildInstruction(MOP_adrp_label, dst, immOpnd)); + return dst; +} + +Operand *Riscv64CGFunc::SelectCGArrayElemAdd(BinaryNode *node) { + BaseNode *opnd0 = node->Opnd(0); + BaseNode *opnd1 = node->Opnd(1); + CG_ASSERT(opnd1->op == OP_constval, "Internal error, opnd1->op should be OP_constval."); + + switch (opnd0->op) { + case OP_regread: { + RegreadNode *regreadnode = static_cast(opnd0); + return SelectRegread(nullptr, regreadnode); + } + case OP_addrof: { + AddrofNode *addrofnode = static_cast(opnd0); + MIRSymbol *symbol = mirModule.CurFunction()->GetLocalOrGlobalSymbol(addrofnode->stIdx); + CG_ASSERT(addrofnode->fieldID == 0, "For debug SelectCGArrayElemAdd."); + + PrimType primType = addrofnode->primType; + regno_t vRegNo = New_V_Reg(kRegTyInt, GetPrimTypeSize(primType)); + Operand *result = CreateVirtualRegisterOperand(vRegNo); + + // OP_constval + ConstvalNode *constvalnode = static_cast(opnd1); + MIRConst *mirconst = constvalnode->constVal; + MIRIntConst *mirintconst = dynamic_cast(mirconst); + CHECK_FATAL(mirintconst != nullptr, "dynamic_cast failed in SelectCGArrayElemAdd"); + SelectAddrof(result, CreateStImmOperand(symbol, mirintconst->value, 0)); + + return result; + } + default: + CHECK_FATAL(0, "Internal error, cannot handle opnd0."); + } +} + +void Riscv64CGFunc::SelectSub(Operand *resopnd, Operand *opnd0, Operand *opnd1, PrimType prmtype) { + Operand::OperandType opnd1ty = opnd1->op_kind_; + uint32 dsize = GetPrimTypeBitSize(prmtype); + bool is64bits = (dsize == 64); + bool isfloat = IsPrimitiveFloat(prmtype); + opnd0 = LoadIntoRegister(opnd0, prmtype); + if (opnd1ty != Operand::Opd_Register) { + if (opnd1ty == Operand::Opd_Immediate) { + Riscv64ImmOperand *immopnd = static_cast(opnd1); +/* if (immopnd->IsNegative()) { + immopnd->Negate(); + SelectAdd(resopnd, opnd0, immopnd, prmtype); + } else */if ((immopnd->IsInBitSize(11) || immopnd->IsInBitSize(12, 12))) { + // imm is positive, riscv has no subi. negate and use add + immopnd->Negate(); + SelectAdd(resopnd, opnd0, immopnd, prmtype); + } else { + RegOperand *regopnd; + if (isAfterRegAlloc) { + CHECK_FATAL(curbb->isProEpilog, "Not prolog/epilog"); + + RegType regty = GetRegTyFromPrimTyRiscv64(prmtype); + uint8 bytelen = GetPrimTypeSize(prmtype); + // Use one of the temp reg, R31, since this is at the start of prolog + // where sp is being adjusted. No more instruction should be before this. + regopnd = GetOrCreatePhysicalRegisterOperand(R31, bytelen, regty); + } else { + regopnd = CreateRegisterOperandOfType(prmtype); + } + curbb->AppendInsn( + cg->BuildInstruction(MOP_xmovri64, regopnd, immopnd)); + curbb->AppendInsn( + cg->BuildInstruction(is64bits ? MOP_xsubrrr : MOP_wsubrrr, resopnd, opnd0, regopnd)); + } + } else { + SelectSub(resopnd, opnd0, SelectCopy(opnd1, prmtype, prmtype), prmtype); + } + } else { + if (isfloat) { + curbb->AppendInsn(cg->BuildInstruction((is64bits ? MOP_dsub : MOP_ssub), resopnd, opnd0, opnd1)); + } else { + curbb->AppendInsn( + cg->BuildInstruction((is64bits ? MOP_xsubrrr : MOP_wsubrrr), resopnd, opnd0, opnd1)); + } + } +} + +Operand *Riscv64CGFunc::SelectSub(BinaryNode *node, Operand *opnd0, Operand *opnd1) { + PrimType dtype = node->primType; + CG_ASSERT(!IsPrimitiveVector(dtype), "NYI"); + bool issigned = IsSignedInteger(dtype); + uint32 dsize = GetPrimTypeBitSize(dtype); + bool is64bits = (dsize == 64); + bool isfloat = IsPrimitiveFloat(dtype); + PrimType prmtype = + isfloat ? dtype : ((is64bits ? (issigned ? PTY_i64 : PTY_u64) : (issigned ? PTY_i32 : PTY_u32))); // promoted type + RegOperand *resopnd = CreateRegisterOperandOfType(prmtype); + bool doExtend = false; + if (cg->cgopt_.DoZeroExtend()) { + doExtend = true; + } + // Need to zero extend a smaller sized unsigned type + uint32 size = (dtype == PTY_u8) ? 8 : ((dtype == PTY_u16) ? 16 : (dtype == PTY_u32 ? 32 : 0)); + if (doExtend && size > 0) { + RegOperand *tmpopnd = CreateRegisterOperandOfType(dtype); + SelectSub(tmpopnd, opnd0, opnd1, prmtype); + GenerateZext(resopnd, tmpopnd, dtype, size); + } else { + SelectSub(resopnd, opnd0, opnd1, prmtype); + } + return resopnd; +} + +Operand *Riscv64CGFunc::SelectMpy(BinaryNode *node, Operand *opnd0, Operand *opnd1) { + PrimType dtype = node->primType; + CG_ASSERT(!IsPrimitiveVector(dtype), "NYI"); + bool issigned = IsSignedInteger(dtype); + uint32 dsize = GetPrimTypeBitSize(dtype); + bool is64bits = (dsize == 64); + bool isfloat = IsPrimitiveFloat(dtype); + PrimType prmtype = + isfloat ? dtype : ((is64bits ? (issigned ? PTY_i64 : PTY_u64) : (issigned ? PTY_i32 : PTY_u32))); // promoted type + RegOperand *resopnd = CreateRegisterOperandOfType(prmtype); + bool doExtend = false; + if (cg->cgopt_.DoZeroExtend()) { + doExtend = true; + } + // Need to zero extend a smaller sized unsigned type + uint32 size = (dtype == PTY_u8) ? 8 : ((dtype == PTY_u16) ? 16 : (dtype == PTY_u32 ? 32 : 0)); + if (doExtend && size > 0) { + RegOperand *tmpopnd = CreateRegisterOperandOfType(dtype); + SelectMpy(tmpopnd, opnd0, opnd1, prmtype); + GenerateZext(resopnd, tmpopnd, dtype, size); + } else { + SelectMpy(resopnd, opnd0, opnd1, prmtype); + } + return resopnd; +} + +void Riscv64CGFunc::SelectMpy(Operand *resopnd, Operand *opnd0, Operand *opnd1, PrimType prmtype) { + Operand::OperandType opnd0ty = opnd0->op_kind_; + Operand::OperandType opnd1ty = opnd1->op_kind_; + uint32 dsize = GetPrimTypeBitSize(prmtype); + bool is64bits = (dsize == 64); + + if ((opnd0ty == Operand::Opd_Immediate || opnd1ty == Operand::Opd_Immediate) && IsPrimitiveInteger(prmtype)) { + ImmOperand *imm = + opnd0ty == Operand::Opd_Immediate ? static_cast(opnd0) : static_cast(opnd1); + Operand *otherop = opnd0ty == Operand::Opd_Immediate ? opnd1 : opnd0; + int64 immValue = llabs(imm->GetValue()); + if (immValue != 0 && (immValue & (immValue - 1)) == 0) { + if (otherop->op_kind_ != Operand::Opd_Register) { + otherop = SelectCopy(otherop, prmtype, prmtype); + } + Riscv64ImmOperand *shiftnum = CreateImmOperand(__builtin_ffsll(immValue) - 1, dsize, false); + SelectShift(resopnd, otherop, shiftnum, kShiftLeft, prmtype); + if (imm->GetValue() < 0) { + SelectNeg(resopnd, resopnd, prmtype); + } + + return; + } else if (immValue > 2) { + uint32 zeronum = __builtin_ffsll(immValue) - 1; + int64 headval = static_cast(immValue) >> zeronum; + if (((headval + 1) & headval) == 0) { + if (otherop->op_kind_ != Operand::Opd_Register) { + otherop = SelectCopy(otherop, prmtype, prmtype); + } + Riscv64ImmOperand *shiftnum = CreateImmOperand(__builtin_ffsll(headval + 1) - 1, dsize, false); + RegOperand *tmpopnd = CreateRegisterOperandOfType(prmtype); + SelectShift(tmpopnd, otherop, shiftnum, kShiftLeft, prmtype); + SelectSub(resopnd, tmpopnd, otherop, prmtype); + shiftnum = CreateImmOperand(zeronum, dsize, false); + SelectShift(resopnd, resopnd, shiftnum, kShiftLeft, prmtype); + if (imm->GetValue() < 0) { + SelectNeg(resopnd, resopnd, prmtype); + } + + return; + } + if (((headval - 1) & (headval - 2)) == 0) { + if (otherop->op_kind_ != Operand::Opd_Register) { + otherop = SelectCopy(otherop, prmtype, prmtype); + } + Riscv64ImmOperand *shiftnum = CreateImmOperand(__builtin_ffsll(headval - 1) - 1, dsize, false); + RegOperand *tmpopnd = CreateRegisterOperandOfType(prmtype); + SelectShift(tmpopnd, otherop, shiftnum, kShiftLeft, prmtype); + SelectAdd(resopnd, tmpopnd, otherop, prmtype); + shiftnum = CreateImmOperand(zeronum, dsize, false); + SelectShift(resopnd, resopnd, shiftnum, kShiftLeft, prmtype); + if (imm->GetValue() < 0) { + SelectNeg(resopnd, resopnd, prmtype); + } + + return; + } + } + } + + if (opnd0ty != Operand::Opd_Register && opnd1ty != Operand::Opd_Register) { + SelectMpy(resopnd, SelectCopy(opnd0, prmtype, prmtype), opnd1, prmtype); + } else if (opnd0ty == Operand::Opd_Register && opnd1ty != Operand::Opd_Register) { + SelectMpy(resopnd, opnd0, SelectCopy(opnd1, prmtype, prmtype), prmtype); + } else if (opnd0ty != Operand::Opd_Register && opnd1ty == Operand::Opd_Register) { + SelectMpy(resopnd, opnd1, opnd0, prmtype); + } else { + if (IsPrimitiveFloat(prmtype)) { + curbb->AppendInsn(cg->BuildInstruction(is64bits ? MOP_xvmuld : MOP_xvmuls, resopnd, opnd0, opnd1)); + } else if (IsPrimitiveInteger(prmtype)) { + curbb->AppendInsn(cg->BuildInstruction(MOP_xmulrrr, resopnd, opnd0, opnd1)); + } + } +} + +void Riscv64CGFunc::SelectDiv(Operand *resopnd, Operand *opnd0, Operand *opnd1, PrimType prmtype) { + opnd0 = LoadIntoRegister(opnd0, prmtype); + Operand::OperandType opnd0ty = opnd0->op_kind_; + Operand::OperandType opnd1ty = opnd1->op_kind_; + uint32 dsize = GetPrimTypeBitSize(prmtype); + bool is64bits = (dsize == 64); + +#if 0 // Need to revisit this optimization for RISCV + if (g->optim_level >= 2) { + if (opnd1ty == Operand::Opd_Immediate && IsSignedInteger(prmtype)) { + ImmOperand *imm = static_cast(opnd1); + int64 immValue = llabs(imm->GetValue()); + if (immValue != 0 && (immValue & (immValue - 1)) == 0) { + if (immValue == 1) { + if (imm->GetValue() > 0) { + uint32 mop = is64bits ? MOP_xmovrr : MOP_wmovrr; + curbb->AppendInsn(cg->BuildInstruction(mop, resopnd, opnd0)); + } else { + SelectNeg(resopnd, opnd0, prmtype); + } + + return; + } + int shiftnumber = __builtin_ffsll(immValue) - 1; + Riscv64ImmOperand *shiftnum = CreateImmOperand(shiftnumber, dsize, false); + SelectShift(resopnd, opnd0, CreateImmOperand(dsize - 1, dsize, false), kShiftAright, prmtype); + curbb->AppendInsn(cg->BuildInstruction(MOP_xlslrri6, resopnd, resopnd, CreateImmOperand(dsize - shiftnumber, is64bits ? 64 : 32, false))); + curbb->AppendInsn(cg->BuildInstruction(MOP_xaddrrr, resopnd, resopnd, opnd0)); + SelectShift(resopnd, resopnd, shiftnum, kShiftAright, prmtype); + if (imm->GetValue() < 0) { + SelectNeg(resopnd, resopnd, prmtype); + } + + return; + } + } else if (opnd1ty == Operand::Opd_Immediate && IsUnsignedInteger(prmtype)) { + ImmOperand *imm = static_cast(opnd1); + if (imm->GetValue() != 0) { + if (imm->GetValue() > 0 && (imm->GetValue() & (imm->GetValue() - 1)) == 0) { + Riscv64ImmOperand *shiftnum = CreateImmOperand(__builtin_ffsll(imm->GetValue()) - 1, dsize, false); + SelectShift(resopnd, opnd0, shiftnum, kShiftLright, prmtype); + + return; + } else if (imm->GetValue() < 0) { + SelectRiscv64Cmp(opnd0, imm, true, dsize); + SelectRiscv64CSet(resopnd, GetCondOperand(CC_CS), is64bits); + + return; + } + } + } + } +#endif + + if (opnd0ty != Operand::Opd_Register) { + SelectDiv(resopnd, SelectCopy(opnd0, prmtype, prmtype), opnd1, prmtype); + } else if (opnd1ty != Operand::Opd_Register) { + SelectDiv(resopnd, opnd0, SelectCopy(opnd1, prmtype, prmtype), prmtype); + } else { + if (IsPrimitiveFloat(prmtype)) { + // CG_ASSERT( (dsize == 32 || dsize == 64), "we don't support half-precision yet" ); + curbb->AppendInsn(cg->BuildInstruction(is64bits ? MOP_ddivrrr : MOP_sdivrrr, resopnd, opnd0, opnd1)); + } else if (IsPrimitiveInteger(prmtype)) { + bool issigned = IsSignedInteger(prmtype); + uint32 mopDiv = is64bits ? (issigned ? MOP_xsdivrrr : MOP_xudivrrr) : (issigned ? MOP_wsdivrrr : MOP_wudivrrr); + curbb->AppendInsn(cg->BuildInstruction(mopDiv, resopnd, opnd0, opnd1)); + } + } +} + +Operand *Riscv64CGFunc::SelectDiv(BinaryNode *node, Operand *opnd0, Operand *opnd1) { + PrimType dtype = node->primType; + CG_ASSERT(!IsPrimitiveVector(dtype), "NYI"); + bool issigned = IsSignedInteger(dtype); + uint32 dsize = GetPrimTypeBitSize(dtype); + bool is64bits = (dsize == 64); + bool isfloat = IsPrimitiveFloat(dtype); + PrimType prmtype = + isfloat ? dtype : ((is64bits ? (issigned ? PTY_i64 : PTY_u64) : (issigned ? PTY_i32 : PTY_u32))); // promoted type + RegOperand *resopnd = CreateRegisterOperandOfType(prmtype); + SelectDiv(resopnd, opnd0, opnd1, prmtype); + return resopnd; +} + +void Riscv64CGFunc::SelectRem(Operand *resopnd, Operand *opnd0, Operand *opnd1, PrimType prmtype, bool issigned, + bool is64bits) { + opnd0 = LoadIntoRegister(opnd0, prmtype); + opnd1 = LoadIntoRegister(opnd1, prmtype); + CG_ASSERT(IsPrimitiveInteger(prmtype), "Wrong type for REM"); + uint32 mopRem = is64bits ? (issigned ? MOP_xsremrrr : MOP_xuremrrr) : (issigned ? MOP_wsremrrr : MOP_wuremrrr); + curbb->AppendInsn(cg->BuildInstruction(mopRem, resopnd, opnd0, opnd1)); +} + +Operand *Riscv64CGFunc::SelectRem(BinaryNode *node, Operand *opnd0, Operand *opnd1) { + PrimType dtype = node->primType; + CG_ASSERT(IsPrimitiveInteger(dtype), "wrong type for rem"); + bool issigned = IsSignedInteger(dtype); + uint32 dsize = GetPrimTypeBitSize(dtype); + bool is64bits = (dsize == 64); + + PrimType prmtype = ((is64bits ? (issigned ? PTY_i64 : PTY_u64) : (issigned ? PTY_i32 : PTY_u32))); // promoted type + RegOperand *resopnd = CreateRegisterOperandOfType(prmtype); + SelectRem(resopnd, opnd0, opnd1, prmtype, issigned, is64bits); + return resopnd; +} + +void Riscv64CGFunc::SelectTest(Operand *resopnd, Operand *opnd0, Operand *opnd1, PrimType dtype) { + CG_ASSERT(false, "nyi"); +} + +Operand *Riscv64CGFunc::SelectLand(BinaryNode *node, Operand *opnd0, Operand *opnd1) { + PrimType prmtype = node->primType; + CG_ASSERT(IsPrimitiveInteger(prmtype), "Land should be integer type"); + bool is64bits = GetPrimTypeBitSize(prmtype) == 64; + RegOperand *resopnd = CreateRegisterOperandOfType(is64bits ? PTY_u64 : PTY_u32); + /* + * beq opnd0, 0, elselabel # curbb + * beq opnd1, 0, elselabel # bbcmp1 + * resopnd = 1 # bbtrue + * goto done + * elselabel: + * resopnd = 0 # bbfalse + * done: + * # newbb == new curbb + */ + BB *bbcmp1 = CreateNewBB(); + BB *bbtrue = CreateNewBB(); + BB *bbfalse = CreateNewBB(); + BB *newbb = CreateNewBB(); + curbb->AppendBB(bbcmp1); + bbcmp1->AppendBB(bbtrue); + bbtrue->AppendBB(bbfalse); + bbfalse->AppendBB(newbb); + + LabelIdx labidx1 = CreateLabel(); + bbfalse->AddLabel(labidx1); + lab2bbmap[labidx1] = bbfalse; + LabelOperand *bbfalseTargOpnd = GetOrCreateLabelOperand(labidx1); + + LabelIdx labidx2 = CreateLabel(); + newbb->AddLabel(labidx2); + lab2bbmap[labidx2] = newbb; + LabelOperand *newbbTargOpnd = GetOrCreateLabelOperand(labidx2); + + ImmOperand *fopnd = CreateImmOperand(0, is64bits ? 64 : 32, false); + RegOperand *zeroOpnd = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8u)); + curbb->AppendInsn(cg->BuildInstruction(MOP_xmovri64, zeroOpnd, fopnd)); + opnd0 = LoadIntoRegister(opnd0, prmtype); + curbb->SetKind(BB::kBBIf); + curbb->AppendInsn(cg->BuildInstruction(MOP_beq, opnd0, zeroOpnd, bbfalseTargOpnd)); + + curbb = bbcmp1; + opnd1 = LoadIntoRegister(opnd1, prmtype); + bbcmp1->SetKind(BB::kBBIf); + bbcmp1->AppendInsn(cg->BuildInstruction(MOP_beq, opnd1, zeroOpnd, bbfalseTargOpnd)); + + ImmOperand *topnd = CreateImmOperand(1, is64bits ? 64 : 32, false); + bbtrue->AppendInsn(cg->BuildInstruction(MOP_xmovri64, resopnd, topnd)); + bbtrue->SetKind(BB::kBBGoto); + bbtrue->AppendInsn(cg->BuildInstruction(MOP_xuncond, newbbTargOpnd)); + + bbfalse->AppendInsn(cg->BuildInstruction(MOP_xmovri64, resopnd, fopnd)); + + curbb = newbb; + + return resopnd; +} + +Operand *Riscv64CGFunc::SelectLor(BinaryNode *node, Operand *opnd0, Operand *opnd1, bool parentIsBr) { + PrimType prmtype = node->primType; + CG_ASSERT(IsPrimitiveInteger(prmtype), "Lior should be integer type"); + bool is64bits = GetPrimTypeBitSize(prmtype) == 64; + RegOperand *resopnd = CreateRegisterOperandOfType(is64bits ? PTY_u64 : PTY_u32); + /* + * bne opnd0, 0, iflabel # curbb + * beq opnd1, 0, elselabel # bbcmp1 + * iflabel: + * resopnd = 1 # bbtrue + * goto done + * elselabel: + * resopnd = 0 # bbfalse + * done: + * # newbb == new curbb + * + */ + BB *bbcmp1 = CreateNewBB(); + BB *bbtrue = CreateNewBB(); + BB *bbfalse = CreateNewBB(); + BB *newbb = CreateNewBB(); + curbb->AppendBB(bbcmp1); + bbcmp1->AppendBB(bbtrue); + bbtrue->AppendBB(bbfalse); + bbfalse->AppendBB(newbb); + + LabelIdx labidx0 = CreateLabel(); + bbtrue->AddLabel(labidx0); + lab2bbmap[labidx0] = bbtrue; + LabelOperand *bbtrueTargOpnd = GetOrCreateLabelOperand(labidx0); + + LabelIdx labidx1 = CreateLabel(); + bbfalse->AddLabel(labidx1); + lab2bbmap[labidx1] = bbfalse; + LabelOperand *bbfalseTargOpnd = GetOrCreateLabelOperand(labidx1); + + LabelIdx labidx2 = CreateLabel(); + newbb->AddLabel(labidx2); + lab2bbmap[labidx2] = newbb; + LabelOperand *newbbTargOpnd = GetOrCreateLabelOperand(labidx2); + + ImmOperand *fopnd = CreateImmOperand(0, is64bits ? 64 : 32, false); + RegOperand *zeroOpnd = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8u)); + curbb->AppendInsn(cg->BuildInstruction(MOP_xmovri64, zeroOpnd, fopnd)); + opnd0 = LoadIntoRegister(opnd0, prmtype); + curbb->SetKind(BB::kBBIf); + curbb->AppendInsn(cg->BuildInstruction(MOP_bne, opnd0, zeroOpnd, bbtrueTargOpnd)); + + curbb = bbcmp1; + opnd1 = LoadIntoRegister(opnd1, prmtype); + bbcmp1->SetKind(BB::kBBIf); + bbcmp1->AppendInsn(cg->BuildInstruction(MOP_beq, opnd1, zeroOpnd, bbfalseTargOpnd)); + + ImmOperand *topnd = CreateImmOperand(1, is64bits ? 64 : 32, false); + bbtrue->AppendInsn(cg->BuildInstruction(MOP_xmovri64, resopnd, topnd)); + bbtrue->SetKind(BB::kBBGoto); + bbtrue->AppendInsn(cg->BuildInstruction(MOP_xuncond, newbbTargOpnd)); + + bbfalse->AppendInsn(cg->BuildInstruction(MOP_xmovri64, resopnd, fopnd)); + + curbb = newbb; + + return resopnd; +} + +void Riscv64CGFunc::SelectCmpOp(Operand *resopnd, Operand *opnd0, Operand *opnd1, Opcode opcode, PrimType operandType) { + uint32 dsize = resopnd->size_; + bool isfloat = IsPrimitiveFloat(operandType); + bool doZext0 = false; + bool doZext1 = false; + + if (!IsSignedInteger(operandType) && dsize < 64) { + if (opnd0->IsRegister()) { // only for unsigned + opnd0 = SelectZeroSignExt(opnd0, operandType); + } + if (opnd1->IsRegister()) { + opnd1 = SelectZeroSignExt(opnd1, operandType); + } + } + opnd0 = LoadIntoRegister(opnd0, operandType); + + // most of FP constants are passed as Riscv64MemOperand + // except 0.0 which is passed as Opd_FPZeroImmediate + Operand::OperandType opnd1ty = opnd1->op_kind_; + if (opnd1ty != Operand::Opd_Immediate && opnd1ty != Operand::Opd_FPZeroImmediate) { + opnd1 = LoadIntoRegister(opnd1, operandType); + } + + bool unsignedIntegerComparison = !isfloat && !IsSignedInteger(operandType); + /* OP_cmp, OP_cmpl, OP_cmpg + * OP0, OP1 ; fcmp for OP_cmpl/OP_cmpg, cmp/fcmpe for OP_cmp + * CSINV RES, WZR, WZR, GE + * CSINC RES, RES, WZR, LE + * if OP_cmpl, CSINV RES, RES, WZR, VC (no overflow) + * if OP_cmpg, CSINC RES, RES, WZR, VC (no overflow) + */ + Riscv64RegOperand *xzr = Riscv64RegOperand::GetZeroRegister(dsize); + static_cast(resopnd)->SetValidBitsNum(1); + if (IsPrimitiveFloat(operandType)) { + ImmOperand *topnd = CreateImmOperand(1, dsize, false); + ImmOperand *fopnd = CreateImmOperand(0, dsize, false); + if (opnd0->size_ != opnd1->size_) { + LogInfo::MapleLogger() << "WARNING: SelectCmpOp: Inconsistent size" << endl; + } + uint32 sz = (opnd1->size_ <=32) ? 32 : 64; + SelectRiscv64SelectOp(resopnd, opnd0, opnd1, topnd, fopnd, opcode, sz, unsignedIntegerComparison); + return; + } + + MOperator mop; + regno_t vRegNo = New_V_Reg(kRegTyInt, GetPrimTypeSize(operandType)); + if (opnd1ty == Operand::Opd_Immediate) { + int64 value = static_cast(opnd1)->GetValue(); + if (value == 0) { + switch (opcode) { + case OP_eq: + case OP_ne: + mop = opcode == OP_eq ? MOP_xseqz : MOP_xsnez; + curbb->AppendInsn(cg->BuildInstruction(mop, resopnd, opnd0)); + break; + case OP_gt: + if (!unsignedIntegerComparison) { + curbb->AppendInsn(cg->BuildInstruction(MOP_xsgt, + resopnd, opnd0, xzr)); + } else { + curbb->AppendInsn(cg->BuildInstruction(MOP_xsnez, resopnd, opnd0)); + } + break; + case OP_le: { + if (!unsignedIntegerComparison) { + ImmOperand *iopnd = CreateImmOperand(1, dsize, false); + curbb->AppendInsn(cg->BuildInstruction(MOP_xslti, + resopnd, opnd0, iopnd)); + } else { + curbb->AppendInsn(cg->BuildInstruction(MOP_xseqz, resopnd, opnd0)); + } + break; + } + case OP_lt: + case OP_ge: { + if (unsignedIntegerComparison && opcode) { + if (opcode == OP_lt) { + SelectCopy(resopnd, operandType, xzr, operandType); + } else { + RegOperand *rtmp = CreateVirtualRegisterOperand(vRegNo); + ImmOperand *iopnd = CreateImmOperand(1, dsize, false); + SelectCopy(resopnd, operandType, iopnd, operandType); + } + break; + } + RegOperand *rtmp = CreateVirtualRegisterOperand(vRegNo); + if (opcode == OP_ge) { + curbb->AppendInsn(cg->BuildInstruction(MOP_xnotrr, rtmp, opnd0)); + } + ImmOperand *shiftNum = + CreateImmOperand(opnd0->GetSize() == 64 ? 63 : 31, opnd0->GetSize() == 64 ? 6 : 5, false); + curbb->AppendInsn(cg->BuildInstruction( + opnd0->GetSize() == 64 ? MOP_xlsrrri6 : MOP_wlsrrri5, resopnd, + opcode == OP_ge ? rtmp : opnd0, shiftNum)); + break; + } + default: + CHECK_FATAL(0, "Invalid set instruction"); + } + return; + } else { + // special case + if (opcode == OP_ge && value == 1) { + curbb->AppendInsn(cg->BuildInstruction(MOP_xsgt, + resopnd, opnd0, xzr)); + return; + } + // load imm int register, flow through to below + opnd1 = LoadIntoRegister(opnd1, operandType); + } + } + RegOperand *rtmp = CreateVirtualRegisterOperand(vRegNo); + switch (opcode) { + case OP_eq: + case OP_ne: { + SelectSub(rtmp, opnd0, opnd1, PTY_i64); + mop = (opcode == OP_eq) ? MOP_xseqz : MOP_xsnez; + curbb->AppendInsn(cg->BuildInstruction(mop, resopnd, rtmp)); + break; + } + case OP_lt: + case OP_le: + case OP_gt: + case OP_ge: { + if (unsignedIntegerComparison) { + mop = (opcode == OP_lt || opcode == OP_ge) ? MOP_xsltu : MOP_xsgtu; + } else { + mop = (opcode == OP_lt || opcode == OP_ge) ? MOP_xslt : MOP_xsgt; + } + if (opcode == OP_lt || opcode == OP_gt) { + curbb->AppendInsn(cg->BuildInstruction(mop, resopnd, opnd0, opnd1)); + } else { + curbb->AppendInsn(cg->BuildInstruction(mop, rtmp, opnd0, opnd1)); + ImmOperand *iopnd = CreateImmOperand(1, dsize, false); + SelectBxor(resopnd, rtmp, iopnd, operandType); + } + break; + } + default: + CHECK_FATAL(0, "Invalid set instruction"); + } +} + +Operand *Riscv64CGFunc::SelectCmpOp(CompareNode *node, Operand *opnd0, Operand *opnd1) { + RegOperand *resopnd = CreateRegisterOperandOfType(node->primType); + SelectCmpOp(resopnd, opnd0, opnd1, node->op, node->opndType); + return resopnd; +} + +void Riscv64CGFunc::SelectFPCmpQuiet(Operand *o0, Operand *o1, uint32 dsize) { + CHECK_FATAL((dsize == 32 || dsize == 64), ""); + MOperator mopcode = 0; + + if (o1->op_kind_ == Operand::Opd_FPZeroImmediate) { + mopcode = (dsize == 64) ? MOP_dcmpqri : MOP_scmpqri; + } else if (o1->op_kind_ == Operand::Opd_Register) { + mopcode = (dsize == 64) ? MOP_dcmpqrr : MOP_scmpqrr; + } else { + CG_ASSERT(false, "unsupported operand type"); + } + curbb->AppendInsn(cg->BuildInstruction(mopcode, o0, o1)); +} + +void Riscv64CGFunc::SelectRiscv64Cmp(Operand *o0, Operand *o1, bool isIntty, uint32 dsize) { + MOperator mopcode = 0; + if (isIntty) { + if (o1->op_kind_ == Operand::Opd_Immediate) { + ImmOperand *immopnd = static_cast(o1); + // imm : 0 ~ 4095, shift: none, LSL #0, or LSL #12 + // riscv64 assembly takes up to 24-bits, if the lower 12 bits is all 0 + if (immopnd->IsInBitSize(11)) { + mopcode = (dsize == 64) ? MOP_xcmpri : MOP_wcmpri; + } else { + // load into register + PrimType primType = (dsize == 64) ? PTY_i64 : PTY_i32; + o1 = SelectCopy(o1, primType, primType); + mopcode = (dsize == 64) ? MOP_xcmprr : MOP_wcmprr; + } + } else if (o1->op_kind_ == Operand::Opd_Register) { + mopcode = (dsize == 64) ? MOP_xcmprr : MOP_wcmprr; + } else { + CG_ASSERT(false, "unsupported operand type"); + } + } else { /* float */ + CHECK_FATAL((dsize == 32 || dsize == 64), ""); + if (o1->op_kind_ == Operand::Opd_FPZeroImmediate) { + mopcode = (dsize == 64) ? MOP_dcmperi : MOP_scmperi; + } else if (o1->op_kind_ == Operand::Opd_Register) { + mopcode = (dsize == 64) ? MOP_dcmperr : MOP_scmperr; + } else { + CG_ASSERT(false, "unsupported operand type"); + } + } + CG_ASSERT(mopcode != 0, "mopcode undefined"); + curbb->AppendInsn(cg->BuildInstruction(mopcode, o0, o1)); +} + +Operand *Riscv64CGFunc::SelectBand(BinaryNode *node, Operand *opnd0, Operand *opnd1) { + PrimType dtype = node->primType; + bool issigned = IsSignedInteger(dtype); + uint32 dsize = GetPrimTypeBitSize(dtype); + bool is64bits = (dsize == 64); + PrimType prmtype = is64bits ? (issigned ? PTY_i64 : PTY_u64) : (issigned ? PTY_i32 : PTY_u32); // promoted type + RegOperand *resopnd = CreateRegisterOperandOfType(prmtype); + SelectBand(resopnd, opnd0, opnd1, prmtype); + return resopnd; +} + +void Riscv64CGFunc::SelectBand(Operand *resopnd, Operand *opnd0, Operand *opnd1, PrimType prmtype) { + Operand::OperandType opnd0ty = opnd0->op_kind_; + Operand::OperandType opnd1ty = opnd1->op_kind_; + uint32 dsize = GetPrimTypeBitSize(prmtype); + bool is64bits = (dsize == 64); + if (opnd0ty != Operand::Opd_Register && opnd1ty != Operand::Opd_Register) { + SelectBand(resopnd, SelectCopy(opnd0, prmtype, prmtype), opnd1, prmtype); + } else if (opnd0ty == Operand::Opd_Register && opnd1ty != Operand::Opd_Register) { + if (opnd1ty == Operand::Opd_Immediate) { + Riscv64ImmOperand *immopnd = static_cast(opnd1); + if (immopnd->IsZero()) { + uint32 mopMv = is64bits ? MOP_xmovrr : MOP_wmovrr; + curbb->AppendInsn(cg->BuildInstruction(mopMv, resopnd, Riscv64RegOperand::GetZeroRegister(dsize))); + } else if ((is64bits && immopnd->IsAllOnes()) || (!is64bits && immopnd->IsAllOnes32bit())) { + SelectCopy(resopnd, prmtype, opnd0, prmtype); + } else if (immopnd->IsInSimmBitSize(12)) { + uint32 mopBand = /*is64bits ? */MOP_xandrri13/* : MOP_wandrri12*/; + curbb->AppendInsn(cg->BuildInstruction(mopBand, resopnd, opnd0, opnd1)); + } else { + int64 immVal = immopnd->GetValue(); + RegOperand *regopnd = CreateRegisterOperandOfType(prmtype); + SelectCopyImm(regopnd, immopnd, prmtype); + uint32 mopBand = /*is64bits ? */MOP_xandrrr/* : MOP_wandrrr*/; + curbb->AppendInsn(cg->BuildInstruction(mopBand, resopnd, opnd0, regopnd)); + } + } else { + SelectBand(resopnd, opnd0, SelectCopy(opnd1, prmtype, prmtype), prmtype); + } + } else if (opnd0ty != Operand::Opd_Register && opnd1ty == Operand::Opd_Register) { + SelectBand(resopnd, opnd1, opnd0, prmtype); + } else { + CG_ASSERT(IsPrimitiveInteger(prmtype), "NYI band"); + uint32 mopBand = /*is64bits ? */MOP_xandrrr/* : MOP_wandrrr*/; + curbb->AppendInsn(cg->BuildInstruction(mopBand, resopnd, opnd0, opnd1)); + } +} + +Operand *Riscv64CGFunc::SelectBior(BinaryNode *node, Operand *opnd0, Operand *opnd1) { + PrimType dtype = node->primType; + bool issigned = IsSignedInteger(dtype); + uint32 dsize = GetPrimTypeBitSize(dtype); + bool is64bits = (dsize == 64); + PrimType prmtype = is64bits ? (issigned ? PTY_i64 : PTY_u64) : (issigned ? PTY_i32 : PTY_u32); // promoted type + RegOperand *resopnd = CreateRegisterOperandOfType(prmtype); + SelectBior(resopnd, opnd0, opnd1, prmtype); + return resopnd; +} + +void Riscv64CGFunc::SelectBior(Operand *resopnd, Operand *opnd0, Operand *opnd1, PrimType prmtype) { + Operand::OperandType opnd0ty = opnd0->op_kind_; + Operand::OperandType opnd1ty = opnd1->op_kind_; + uint32 dsize = GetPrimTypeBitSize(prmtype); + bool is64bits = (dsize == 64); + if (opnd0ty != Operand::Opd_Register && opnd1ty != Operand::Opd_Register) { + SelectBior(resopnd, SelectCopy(opnd0, prmtype, prmtype), opnd1, prmtype); + } else if (opnd0ty == Operand::Opd_Register && opnd1ty != Operand::Opd_Register) { + if (opnd1ty == Operand::Opd_Immediate) { + Riscv64ImmOperand *immopnd = static_cast(opnd1); + + if (immopnd->IsZero()) { + SelectCopy(resopnd, prmtype, opnd0, prmtype); + } else if (immopnd->IsAllOnes()) { + curbb->AppendInsn( + cg->BuildInstruction(MOP_xinegrr, resopnd, Riscv64RegOperand::GetZeroRegister(dsize))); + } else if (immopnd->IsInSimmBitSize(12)) { + curbb->AppendInsn(cg->BuildInstruction(MOP_xiorrri13, resopnd, opnd0, opnd1)); + } else { + int64 immVal = immopnd->GetValue(); + RegOperand *regopnd = CreateRegisterOperandOfType(prmtype); + SelectCopyImm(regopnd, immopnd, prmtype); + curbb->AppendInsn(cg->BuildInstruction(MOP_xiorrrr, resopnd, opnd0, regopnd)); + } + } else { + SelectBior(resopnd, opnd0, SelectCopy(opnd1, prmtype, prmtype), prmtype); + } + } else if (opnd0ty != Operand::Opd_Register && opnd1ty == Operand::Opd_Register) { + SelectBior(resopnd, opnd1, opnd0, prmtype); + } else { + CG_ASSERT(IsPrimitiveInteger(prmtype), "NYI band"); + curbb->AppendInsn(cg->BuildInstruction(MOP_xiorrrr, resopnd, opnd0, opnd1)); + } +} + +Operand *Riscv64CGFunc::SelectMin(BinaryNode *node, Operand *opnd0, Operand *opnd1) { + PrimType dtype = node->primType; + bool issigned = IsSignedInteger(dtype); + uint32 dsize = GetPrimTypeBitSize(dtype); + bool is64bits = (dsize == 64); + bool isfloat = IsPrimitiveFloat(dtype); + PrimType prmtype = + isfloat ? dtype : ((is64bits ? (issigned ? PTY_i64 : PTY_u64) : (issigned ? PTY_i32 : PTY_u32))); // promoted type + RegOperand *resopnd = CreateRegisterOperandOfType(prmtype); + SelectMin(resopnd, opnd0, opnd1, prmtype); + return resopnd; +} + +void Riscv64CGFunc::SelectMin(Operand *resopnd, Operand *opnd0, Operand *opnd1, PrimType prmtype) { + uint32 dsize = GetPrimTypeBitSize(prmtype); + bool is64bits = (dsize == 64); + if (IsPrimitiveInteger(prmtype)) { + opnd0 = LoadIntoRegister(opnd0, prmtype); + opnd1 = LoadIntoRegister(opnd1, prmtype); + resopnd = LoadIntoRegister(resopnd, prmtype); + SelectRiscv64SelectOp(resopnd, opnd0, opnd1, opnd0, opnd1, OP_le, dsize, !IsSignedInteger(prmtype)); + } else if (IsPrimitiveFloat(prmtype)) { + opnd0 = LoadIntoRegister(opnd0, prmtype); + opnd1 = LoadIntoRegister(opnd1, prmtype); + SelectFMinFMax(resopnd, opnd0, opnd1, is64bits, true /*min*/); + } +} + +Operand *Riscv64CGFunc::SelectMax(BinaryNode *node, Operand *opnd0, Operand *opnd1) { + PrimType dtype = node->primType; + bool issigned = IsSignedInteger(dtype); + uint32 dsize = GetPrimTypeBitSize(dtype); + bool is64bits = (dsize == 64); + bool isfloat = IsPrimitiveFloat(dtype); + PrimType prmtype = + isfloat ? dtype : ((is64bits ? (issigned ? PTY_i64 : PTY_u64) : (issigned ? PTY_i32 : PTY_u32))); // promoted type + RegOperand *resopnd = CreateRegisterOperandOfType(prmtype); + SelectMax(resopnd, opnd0, opnd1, prmtype); + return resopnd; +} + +void Riscv64CGFunc::SelectMax(Operand *resopnd, Operand *opnd0, Operand *opnd1, PrimType prmtype) { + uint32 dsize = GetPrimTypeBitSize(prmtype); + bool is64bits = (dsize == 64); + if (IsPrimitiveInteger(prmtype)) { + opnd0 = LoadIntoRegister(opnd0, prmtype); + opnd1 = LoadIntoRegister(opnd1, prmtype); + resopnd = LoadIntoRegister(resopnd, prmtype); + SelectRiscv64SelectOp(resopnd, opnd0, opnd1, opnd0, opnd1, OP_ge, dsize, !IsSignedInteger(prmtype)); + } else if (IsPrimitiveFloat(prmtype)) { + opnd0 = LoadIntoRegister(opnd0, prmtype); + opnd1 = LoadIntoRegister(opnd1, prmtype); + SelectFMinFMax(resopnd, opnd0, opnd1, is64bits, false /*min*/); + } else { + CG_ASSERT(false, "NIY type max"); + } +} + +void Riscv64CGFunc::SelectFMinFMax(Operand *resopnd, Operand *opnd0, Operand *opnd1, bool is64bits, bool isMin) { + uint32 mopcode = isMin ? (is64bits ? MOP_xfminrrr : MOP_wfminrrr) : (is64bits ? MOP_xfmaxrrr : MOP_wfmaxrrr); + curbb->AppendInsn(cg->BuildInstruction(mopcode, resopnd, opnd0, opnd1)); +} + +Operand *Riscv64CGFunc::SelectBxor(BinaryNode *node, Operand *opnd0, Operand *opnd1) { + PrimType dtype = node->primType; + bool issigned = IsSignedInteger(dtype); + uint32 dsize = GetPrimTypeBitSize(dtype); + bool is64bits = (dsize == 64); + PrimType prmtype = is64bits ? (issigned ? PTY_i64 : PTY_u64) : (issigned ? PTY_i32 : PTY_u32); // promoted type + RegOperand *resopnd = CreateRegisterOperandOfType(prmtype); + SelectBxor(resopnd, opnd0, opnd1, prmtype); + return resopnd; +} + +void Riscv64CGFunc::SelectBxor(Operand *resopnd, Operand *opnd0, Operand *opnd1, PrimType prmtype) { + Operand::OperandType opnd0ty = opnd0->op_kind_; + Operand::OperandType opnd1ty = opnd1->op_kind_; + uint32 dsize = GetPrimTypeBitSize(prmtype); + bool is64bits = (dsize == 64); + if (opnd0ty != Operand::Opd_Register && opnd1ty != Operand::Opd_Register) { + SelectBxor(resopnd, SelectCopy(opnd0, prmtype, prmtype), opnd1, prmtype); + } else if (opnd0ty == Operand::Opd_Register && opnd1ty != Operand::Opd_Register) { + if (opnd1ty == Operand::Opd_Immediate) { + Riscv64ImmOperand *immopnd = static_cast(opnd1); + if (immopnd->IsZero()) { + SelectCopy(resopnd, prmtype, opnd0, prmtype); + } else if (immopnd->IsAllOnes()) { + SelectMvn(resopnd, opnd0, prmtype); + } else if (immopnd->IsInSimmBitSize(12)) { + curbb->AppendInsn(cg->BuildInstruction(MOP_xeorrri13, resopnd, opnd0, opnd1)); + } else { + int64 immVal = immopnd->GetValue(); + RegOperand *regopnd = CreateRegisterOperandOfType(prmtype); + SelectCopyImm(regopnd, immopnd, prmtype); + curbb->AppendInsn(cg->BuildInstruction(MOP_xeorrrr, resopnd, opnd0, regopnd)); + } + } else { + SelectBxor(resopnd, opnd0, SelectCopy(opnd1, prmtype, prmtype), prmtype); + } + } else if (opnd0ty != Operand::Opd_Register && opnd1ty == Operand::Opd_Register) { + SelectBxor(resopnd, opnd1, opnd0, prmtype); + } else { + CG_ASSERT(IsPrimitiveInteger(prmtype), "NYI bxor"); + curbb->AppendInsn(cg->BuildInstruction(MOP_xeorrrr, resopnd, opnd0, opnd1)); + } +} + +Operand *Riscv64CGFunc::SelectShift(BinaryNode *node, Operand *opnd0, Operand *opnd1) { + PrimType dtype = node->primType; + bool issigned = IsSignedInteger(dtype); + uint32 dsize = GetPrimTypeBitSize(dtype); + bool is64bits = (dsize == 64); + bool isfloat = IsPrimitiveFloat(dtype); + PrimType prmtype = + isfloat ? dtype : ((is64bits ? (issigned ? PTY_i64 : PTY_u64) : (issigned ? PTY_i32 : PTY_u32))); // promoted type + RegOperand *resopnd = CreateRegisterOperandOfType(prmtype); + Opcode opcode = node->op; + SHIFTDIRECTION direct = (opcode == OP_lshr) ? kShiftLright : (opcode == OP_ashr ? kShiftAright : kShiftLeft); + SelectShift(resopnd, opnd0, opnd1, direct, prmtype); + return resopnd; +} + +void Riscv64CGFunc::SelectShift(Operand *resopnd, Operand *opnd0, Operand *opnd1, SHIFTDIRECTION direct, + PrimType prmtype) { + Operand::OperandType opnd1ty = opnd1->op_kind_; + uint32 dsize = GetPrimTypeBitSize(prmtype); + bool is64bits = (dsize == 64); + opnd0 = LoadIntoRegister(opnd0, prmtype); + + MOperator mopShift; + if (opnd1ty == Operand::Opd_Immediate) { + Riscv64ImmOperand *immopnd1 = static_cast(opnd1); + const int64 kVal = immopnd1->GetValue(); + const uint32 kShiftamt = is64bits ? 63 : 31; + if (kVal == 0) { + SelectCopy(resopnd, prmtype, opnd0, prmtype); + return; + } + // CG_ASSERT(shiftamt >= val, "shift error oversize"); + // e.g. a >> -1 + if (kVal < 0 || kVal > kShiftamt) { + SelectShift(resopnd, opnd0, SelectCopy(opnd1, prmtype, prmtype), direct, prmtype); + return; + } + switch (direct) { + case kShiftLeft: + if (kVal == 1) { + SelectAdd(resopnd, opnd0, opnd0, prmtype); + return; + } + mopShift = is64bits ? MOP_xlslrri6 : MOP_wlslrri5; + break; + case kShiftAright: + mopShift = is64bits ? MOP_xasrrri6 : MOP_wasrrri5; + break; + case kShiftLright: + mopShift = is64bits ? MOP_xlsrrri6 : MOP_wlsrrri5; + break; + } + } else if (opnd1ty != Operand::Opd_Register) { + SelectShift(resopnd, opnd0, SelectCopy(opnd1, prmtype, prmtype), direct, prmtype); + return; + } else { + switch (direct) { + case kShiftLeft: + mopShift = is64bits ? MOP_xlslrrr : MOP_wlslrrr; + break; + case kShiftAright: + mopShift = is64bits ? MOP_xasrrrr : MOP_wasrrrr; + break; + case kShiftLright: + mopShift = is64bits ? MOP_xlsrrrr : MOP_wlsrrrr; + break; + } + } + + curbb->AppendInsn(cg->BuildInstruction(mopShift, resopnd, opnd0, opnd1)); +} + +Operand *Riscv64CGFunc::SelectAbs(UnaryNode *node, Operand *opnd0) { + PrimType dtyp = node->primType; + if (IsPrimitiveFloat(dtyp)) { + CG_ASSERT(GetPrimTypeBitSize(dtyp) >= 32, "We don't support hanf-word FP operands yet"); + bool is64bits = (GetPrimTypeBitSize(dtyp) == 64); + opnd0 = LoadIntoRegister(opnd0, dtyp); + RegOperand *resopnd = CreateRegisterOperandOfType(dtyp); + curbb->AppendInsn(cg->BuildInstruction(is64bits ? MOP_dabsrr : MOP_sabsrr, resopnd, opnd0)); + return resopnd; + } else { + // srai/w x <- val >> 63|31 + // xor y <- val, x + // sub/w result <- y, x + bool is64bits = (GetPrimTypeBitSize(dtyp) == 64); + PrimType prmtype = is64bits ? (PTY_i64) : (PTY_i32); // promoted type + RegOperand *resopnd = CreateRegisterOperandOfType(prmtype); + opnd0 = LoadIntoRegister(opnd0, prmtype); + MOperator mop = is64bits ? MOP_xasrrri6 : MOP_wasrrri5; + RegOperand *tmp1Dest = CreateRegisterOperandOfType(prmtype); + int32 shiftVal = opnd0->size_ - 1; + ImmOperand *shift = CreateImmOperand(shiftVal, 4, false); + curbb->AppendInsn(cg->BuildInstruction(mop, tmp1Dest, opnd0, shift)); + RegOperand *tmp2Dest = CreateRegisterOperandOfType(prmtype); + curbb->AppendInsn(cg->BuildInstruction(MOP_xeorrrr, tmp2Dest, opnd0, tmp1Dest)); + mop = is64bits ? MOP_xsubrrr : MOP_wsubrrr; + curbb->AppendInsn(cg->BuildInstruction(mop, resopnd, tmp2Dest, tmp1Dest)); + return resopnd; + } +} + +Operand *Riscv64CGFunc::SelectBnot(UnaryNode *node, Operand *opnd0) { + PrimType dtyp = node->primType; + RegOperand *resopnd = nullptr; + if (IsPrimitiveInteger(dtyp)) { + bool is64bits = (GetPrimTypeBitSize(dtyp) == 64); + bool issigned = IsSignedInteger(dtyp); + PrimType prmtype = is64bits ? (issigned ? PTY_i64 : PTY_u64) : (issigned ? PTY_i32 : PTY_u32); // promoted type + resopnd = CreateRegisterOperandOfType(prmtype); + + opnd0 = LoadIntoRegister(opnd0, prmtype); + + curbb->AppendInsn(cg->BuildInstruction(MOP_xnotrr, resopnd, opnd0)); + } else { + CG_ASSERT(false, "bnot expect integer or NYI"); + } + return resopnd; +} + +Operand *Riscv64CGFunc::SelectZeroSignExt(Operand *opnd, PrimType primType) { + if (opnd->IsRegister()) { + PrimType dtype = PTY_i64; + bool isSigned = false; + uint32 bitSz = 0; + switch (primType) { + case PTY_u8: + bitSz = 8; + dtype = PTY_u64; + break; + case PTY_u16: + bitSz = 16; + dtype = PTY_u64; + break; + case PTY_u32: + bitSz = 32; + dtype = PTY_u64; + break; + case PTY_i8: + isSigned = true; + bitSz = 8; + break; + case PTY_i16: + isSigned = true; + bitSz = 16; + break; + case PTY_i32: + isSigned = true; + bitSz = 32; + break; + default: + break; + } + if (bitSz > 0) { + RegOperand *dest = CreateRegisterOperandOfType(dtype); + opnd = isSigned ? GenerateSext(dest, opnd, dtype, bitSz) : GenerateZext(dest, opnd, dtype, bitSz); + } + } + return opnd; +} + +Operand *Riscv64CGFunc::GenerateSext(Operand *resopnd, Operand *opnd0, PrimType ptype, uint32 bitSize) { + opnd0 = LoadIntoRegister(opnd0, ptype); + if (bitSize == 32) { + curbb->AppendInsn(cg->BuildInstruction(MOP_xsxtw64, resopnd, opnd0)); + return resopnd; + } + if (g->optim_level == 0) { + RegOperand *tmp = CreateRegisterOperandOfType(ptype); + curbb->AppendInsn(cg->BuildInstruction(MOP_xlslrri6, tmp, opnd0, CreateImmOperand(64 - bitSize, 32, false))); + curbb->AppendInsn(cg->BuildInstruction(MOP_xasrrri6, resopnd, tmp, CreateImmOperand(64 - bitSize, 32, false))); + } else { + curbb->AppendInsn(cg->BuildInstruction(MOP_xsxtv64, resopnd, opnd0, CreateImmOperand(64 - bitSize, 32, false))); + } + return resopnd; +} + +Operand *Riscv64CGFunc::SelectSext(ExtractbitsNode *node, Operand *opnd0) { + //uint32 bitSz = node->bitsSize; + PrimType dtyp = node->primType; + RegOperand *resopnd = CreateRegisterOperandOfType(dtyp); + return GenerateSext(resopnd, opnd0, dtyp, node->bitsSize); +} + +Operand *Riscv64CGFunc::GenerateZext(Operand *resopnd, Operand *opnd0, PrimType ptype, uint32 bitSize) { +#if 0 + // slli val << (64 - bitSize) + // srli val >> (64 - bitSize) + opnd0 = LoadIntoRegister(opnd0, ptype); + PrimType pty = GetPrimTypeBitSize(ptype) <= 32 ? PTY_u32 : PTY_u64; + RegOperand *sllDest = CreateRegisterOperandOfType(pty); + curbb->AppendInsn(cg->BuildInstruction(MOP_xlslrri6, sllDest, opnd0, CreateImmOperand(64 - bitSize, 64, false))); + curbb->AppendInsn(cg->BuildInstruction(MOP_xlsrrri6, resopnd, sllDest, CreateImmOperand(64 - bitSize, 64, false))); +#else + opnd0 = LoadIntoRegister(opnd0, ptype); + PrimType pty = GetPrimTypeBitSize(ptype) <= 32 ? PTY_u32 : PTY_u64; + RegOperand *sllDest = CreateRegisterOperandOfType(pty); + curbb->AppendInsn(cg->BuildInstruction(MOP_xuxtv64, resopnd, opnd0, CreateImmOperand(64 - bitSize, 64, false))); +#endif + return resopnd; +} + +Operand *Riscv64CGFunc::SelectZext(ExtractbitsNode *node, Operand *opnd0) { + RegOperand *resopnd = CreateRegisterOperandOfType((GetPrimTypeSize(node->primType) <= 32) ? PTY_u32 : PTY_u64); + return GenerateZext(resopnd, opnd0, node->primType, node->bitsSize); +} + +Operand *Riscv64CGFunc::SelectExtractbits(ExtractbitsNode *node, Operand *opnd0) { + if (node->op == OP_sext) { + return SelectSext(node, opnd0); + } else if (node->op == OP_zext) { + return SelectZext(node, opnd0); + } + PrimType dtyp = node->primType; + RegOperand *resopnd = CreateRegisterOperandOfType(dtyp); + bool issigned = IsSignedInteger(dtyp); + uint8 bitsOffset = node->bitsOffset; + uint8 bitsSize = node->bitsSize; + bool is64bits = (GetPrimTypeBitSize(dtyp) == 64); + uint32 immWidth = 12; + opnd0 = LoadIntoRegister(opnd0, dtyp); + if (bitsOffset == 0 && !issigned && (bitsSize < immWidth)) { + curbb->AppendInsn(cg->BuildInstruction(MOP_xandrri13, resopnd, opnd0, CreateImmOperand((static_cast(1) << bitsSize) - 1, 4, false))); + return resopnd; + } + if (issigned) { + MOperator sllmop = (is64bits) ? MOP_xlslrri6 : MOP_wlslrri5; + MOperator sramop = (is64bits) ? MOP_xasrrri6 : MOP_wasrrri5; + RegOperand *sllDst = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + if (is64bits) { + curbb->AppendInsn(cg->BuildInstruction(sllmop, sllDst, opnd0, CreateImmOperand(64 - bitsOffset - bitsSize, 4, false))); + curbb->AppendInsn(cg->BuildInstruction(sramop, resopnd, sllDst, CreateImmOperand(64 - bitsSize, 4, false))); + } else { + curbb->AppendInsn(cg->BuildInstruction(sllmop, sllDst, opnd0, CreateImmOperand(32 - bitsOffset - bitsSize, 4, false))); + RegOperand *sraDst = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + curbb->AppendInsn(cg->BuildInstruction(sramop, sraDst, sllDst, CreateImmOperand(32 - bitsSize, 4, false))); + RegOperand *sll64Dst = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + curbb->AppendInsn(cg->BuildInstruction(MOP_xlslrri6, sll64Dst, sraDst, CreateImmOperand(32, 4, false))); + curbb->AppendInsn(cg->BuildInstruction(MOP_xlsrrri6, resopnd, sll64Dst, CreateImmOperand(32, 4, false))); + GenerateSext(resopnd, resopnd, dtyp, 32); + } + } else { + RegOperand *srl1Dst = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + curbb->AppendInsn(cg->BuildInstruction(MOP_xlsrrri6, srl1Dst, opnd0, CreateImmOperand(bitsOffset, 4, false))); + RegOperand *srl2Dst = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + if (is64bits) { + // li -1 -> one + // srli ones, 64 - bitsSize -> val2 + RegOperand *oneDst = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + curbb->AppendInsn(cg->BuildInstruction(MOP_xmovri64, oneDst, CreateImmOperand(-1, 8, true))); + curbb->AppendInsn(cg->BuildInstruction(MOP_xlsrrri6, srl2Dst, oneDst, CreateImmOperand(64 - bitsSize, 4, false))); + } else { + // li 1 << bitsSize -> mask + // addi mask - 1 -> val2 + RegOperand *maskDst = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + curbb->AppendInsn(cg->BuildInstruction(MOP_xmovri64, maskDst, CreateImmOperand(1 << bitsSize, 8, false))); + curbb->AppendInsn(cg->BuildInstruction(MOP_xaddrri12, srl2Dst, maskDst, CreateImmOperand(-1, 8, true))); + } + curbb->AppendInsn(cg->BuildInstruction(MOP_xandrrr, resopnd, srl1Dst, srl2Dst)); + } + + return resopnd; +} + +/* + operand fits in MOVK if + boffst == 0, 16, 32, 48 && bitsSize == 16 + */ +inline bool IsMoveWideKeepable(uint32 bitsOffset, uint32 bitsSize, bool is64bits) { + CG_ASSERT(is64bits || bitsOffset < 32, ""); + return (bitsSize == 16 && ((bitsOffset >> 4) & ~static_cast(is64bits ? 0x3 : 0x1)) == 0); +} + +// we use the fact that A ^ B ^ A == B, A ^ 0 = A +void Riscv64CGFunc::SelectDepositbits(Operand *resopnd, Operand *opnd0, Operand *opnd1, uint32 bitsOffset, uint32 bitsSize, + PrimType rtyp, PrimType dtyp) { + RegOperand *t1opnd = CreateRegisterOperandOfType(rtyp); + bool is64bits = GetPrimTypeBitSize(rtyp) == 64; + RegOperand *dest = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + if (is64bits) { + if (bitsSize < 32) { + // lui bottom 'bitsSize' 0 + // addiw 1 + // slli bitsOffset + // addi -1 + uint32 mask = -1; + for (uint i = 0; i < bitsSize; ++i) { + mask &= ~(1ULL << i); + } + uint64 mask_upper = mask >> 12; + RegOperand *luiDest = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + Riscv64ImmOperand *imm = CreateImmOperand(mask_upper, 32, false); + imm->isUpperBits = true; + curbb->AppendInsn(cg->BuildInstruction(MOP_xmov20up, luiDest, imm)); + RegOperand *addiwDest = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + curbb->AppendInsn(cg->BuildInstruction(MOP_waddrri12, addiwDest, luiDest, CreateImmOperand(1, 32, false))); + RegOperand *sllDest = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + curbb->AppendInsn(cg->BuildInstruction(MOP_xlslrri6, sllDest, addiwDest, CreateImmOperand(bitsOffset, 32, false))); + curbb->AppendInsn(cg->BuildInstruction(MOP_xaddrri12, dest, sllDest, CreateImmOperand(-1, 32, true))); + } else { + // addi zero, -1 + // slli bitsSize + // addi 1 + // slli bitsOffset + // addi -1 + RegOperand *add1Dest = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + Operand *zero = GetOrCreatePhysicalRegisterOperand(RZERO, 64, kRegTyInt); + curbb->AppendInsn(cg->BuildInstruction(MOP_xaddrri12, add1Dest, zero, CreateImmOperand(-1, 32, true))); + RegOperand *sll1Dest = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + curbb->AppendInsn(cg->BuildInstruction(MOP_xlslrri6, sll1Dest, add1Dest, CreateImmOperand(bitsSize, 32, false))); + RegOperand *add2Dest = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + curbb->AppendInsn(cg->BuildInstruction(MOP_xaddrri12, add2Dest, sll1Dest, CreateImmOperand(1, 32, false))); + RegOperand *sll2Dest = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + curbb->AppendInsn(cg->BuildInstruction(MOP_xlslrri6, sll2Dest, add2Dest, CreateImmOperand(bitsOffset, 32, false))); + curbb->AppendInsn(cg->BuildInstruction(MOP_xaddrri12, dest, sll2Dest, CreateImmOperand(-1, 32, true))); + } + } else { + uint32 mask = -1; + for (uint i = bitsOffset; i < (bitsSize + bitsOffset); ++i) { + mask &= ~(1ULL << i); + } + uint32 mask_upper = mask >> 12; + RegOperand *luiDest = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 4)); + Riscv64ImmOperand *imm = CreateImmOperand(mask_upper, 32, false); + imm->isUpperBits = true; + curbb->AppendInsn(cg->BuildInstruction(MOP_xmov20up, luiDest, imm)); + uint32 mask_lower = mask & 0x0fff; + if (mask_lower & 0x800) { + // negative + RegOperand *constDest = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 4)); + curbb->AppendInsn(cg->BuildInstruction(MOP_xmovri64, constDest, CreateImmOperand(mask_lower, 32, false))); + curbb->AppendInsn(cg->BuildInstruction(MOP_xaddrrr, dest, luiDest, constDest)); + } else { + // mask fits in imm with 11 bits + curbb->AppendInsn(cg->BuildInstruction(MOP_xiorrri13, dest, luiDest, CreateImmOperand(mask_lower, 32, false))); + } + } + + // Generate the bit value excluding target bitfield + RegOperand *andDest = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + curbb->AppendInsn(cg->BuildInstruction(MOP_xandrrr, andDest, opnd0, dest)); + + if (opnd1->IsIntImmediate()) { + opnd1 = SelectCopy(opnd1, rtyp, rtyp); + } + // Mask away the target bits upper part beyond its bit size limit + RegOperand *maskDest = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + uint64 fieldMask = 0; + for (uint i = 0; i < bitsSize; ++i) { + fieldMask |= (1ULL << i); + } + if (bitsSize <= 11) { + curbb->AppendInsn(cg->BuildInstruction(MOP_xandrri13, maskDest, opnd1, CreateImmOperand(fieldMask, 32, false))); + } else { + RegOperand *maskImmDest = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + curbb->AppendInsn(cg->BuildInstruction(MOP_xmovri64, maskImmDest, CreateImmOperand(fieldMask, 64, false))); + curbb->AppendInsn(cg->BuildInstruction(MOP_xandrrr, maskDest, opnd1, maskImmDest)); + } + opnd1 = maskDest; + if (bitsOffset > 0) { + // shift the target bit field into the right position + RegOperand *sllDest = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 4)); + curbb->AppendInsn(cg->BuildInstruction(MOP_xlslrri6, sllDest, opnd1, CreateImmOperand(bitsOffset, 32, false))); + opnd1 = sllDest; + } + curbb->AppendInsn(cg->BuildInstruction(MOP_xiorrrr, resopnd, andDest, opnd1)); +} + +Operand *Riscv64CGFunc::SelectDepositbits(DepositbitsNode *node, Operand *opnd0, Operand *opnd1) { + PrimType dtyp = node->primType; + RegOperand *resopnd = CreateRegisterOperandOfType(dtyp); + SelectDepositbits(resopnd, opnd0, opnd1, node->bitsOffset, node->bitsSize, dtyp, dtyp); + return resopnd; +} + +Operand *Riscv64CGFunc::SelectLnot(UnaryNode *node, Operand *opnd0) { + PrimType dtype = node->primType; + RegOperand *resopnd = CreateRegisterOperandOfType(dtype); + bool is64bits = (GetPrimTypeBitSize(dtype) == 64); + opnd0 = LoadIntoRegister(opnd0, dtype); + Operand *zero = GetOrCreatePhysicalRegisterOperand(RZERO, GetPrimTypeBitSize(dtype), kRegTyInt); + RegOperand *sltuDest = CreateRegisterOperandOfType(dtype); + curbb->AppendInsn(cg->BuildInstruction(MOP_xsltu, sltuDest, zero, opnd0)); + ImmOperand *neg = CreateImmOperand(1, 32, false); + curbb->AppendInsn(cg->BuildInstruction(MOP_xeorrri13, resopnd, opnd0, neg)); + return resopnd; +} + +Operand *Riscv64CGFunc::SelectNeg(UnaryNode *node, Operand *opnd0) { + PrimType dtyp = node->primType; + bool is64bits = (GetPrimTypeBitSize(dtyp) == 64); + PrimType prmtype; + if (IsPrimitiveFloat(dtyp)) { + prmtype = dtyp; + } else { + prmtype = is64bits ? (PTY_i64) : (PTY_i32); // promoted type + } + RegOperand *resopnd = CreateRegisterOperandOfType(prmtype); + SelectNeg(resopnd, opnd0, prmtype); + return resopnd; +} + +void Riscv64CGFunc::SelectNeg(Operand *dest, Operand *opnd0, PrimType prmtype) { + opnd0 = LoadIntoRegister(opnd0, prmtype); + bool is64bits = (GetPrimTypeBitSize(prmtype) == 64); + MOperator mop; + if (IsPrimitiveFloat(prmtype)) { + mop = is64bits ? MOP_xfnegrr : MOP_wfnegrr; + } else { + mop = is64bits ? MOP_xinegrr : MOP_winegrr; + } + curbb->AppendInsn(cg->BuildInstruction(mop, dest, opnd0)); +} + +void Riscv64CGFunc::SelectMvn(Operand *dest, Operand *opnd0, PrimType prmtype) { + opnd0 = LoadIntoRegister(opnd0, prmtype); + bool is64bits = (GetPrimTypeBitSize(prmtype) == 64); + MOperator mop; + CG_ASSERT(!IsPrimitiveFloat(prmtype), "Instruction 'mvn' do not have float version."); + curbb->AppendInsn(cg->BuildInstruction(MOP_xnotrr, dest, opnd0)); +} + +Operand *Riscv64CGFunc::SelectRecip(UnaryNode *node, Operand *opnd0) { + // fconsts s15, #112 + // fdivs s0, s15, s0 + PrimType dtyp = node->primType; + if (IsPrimitiveFloat(dtyp)) { + opnd0 = LoadIntoRegister(opnd0, dtyp); + RegOperand *resopnd = CreateRegisterOperandOfType(dtyp); + Operand *one = nullptr; + if (GetPrimTypeBitSize(dtyp) == 64) { + MIRDoubleConst *c = memPool->New(1.0, GlobalTables::GetTypeTable().typeTable.at(PTY_f64)); + one = SelectDoubleconst(c); + } else if (GetPrimTypeBitSize(dtyp) == 32) { + MIRFloatConst *c = memPool->New(1.0f, GlobalTables::GetTypeTable().typeTable.at(PTY_f32)); + one = SelectFloatconst(c); + } else { + CG_ASSERT(false, "we don't support half-precision fp operations yet"); + } + SelectDiv(resopnd, one, opnd0, dtyp); + return resopnd; + } else { + CG_ASSERT(false, "should be float type"); + } + return nullptr; +} + +Operand *Riscv64CGFunc::SelectSqrt(UnaryNode *node, Operand *opnd0) { + /* gcc generates code like below for better accurate + fsqrts s15, s0 + fcmps s15, s15 + fmstat + beq .L4 + push {r3, lr} + bl sqrtf + pop {r3, pc} + .L4: + fcpys s0, s15 + bx lr */ + PrimType dtyp = node->primType; + if (IsPrimitiveFloat(dtyp)) { + bool is64bits = (GetPrimTypeBitSize(dtyp) == 64); + opnd0 = LoadIntoRegister(opnd0, dtyp); + RegOperand *resopnd = CreateRegisterOperandOfType(dtyp); + curbb->AppendInsn(cg->BuildInstruction(is64bits ? MOP_vsqrtd : MOP_vsqrts, resopnd, opnd0)); + return resopnd; + } else { + CG_ASSERT(false, "should be float type"); + } + return nullptr; +} + +void Riscv64CGFunc::SelectCvtFloat2Int(Operand *resopnd, Operand *opnd0, PrimType itype, PrimType ftype) { + bool is64bitsFloat = (ftype == PTY_f64); + MOperator mop = 0; + + CG_ASSERT((ftype == PTY_f64 || ftype == PTY_f32), "wrong from type"); + + opnd0 = LoadIntoRegister(opnd0, ftype); + switch (itype) { + case PTY_i32: + mop = !is64bitsFloat ? MOP_vcvtrf : MOP_vcvtrd; + break; + case PTY_u32: + mop = !is64bitsFloat ? MOP_vcvturf : MOP_vcvturd; + break; + case PTY_i64: + mop = !is64bitsFloat ? MOP_xvcvtrf : MOP_xvcvtrd; + break; + case PTY_u64: + mop = !is64bitsFloat ? MOP_xvcvturf : MOP_xvcvturd; + break; + default: + CG_ASSERT(false, "unexpected type"); + } + curbb->AppendInsn(cg->BuildInstruction(mop, resopnd, opnd0)); +} + +void Riscv64CGFunc::SelectCvtInt2Float(Operand *resopnd, Operand *opnd0, PrimType totype, PrimType fromtype) { + bool is64bitsFloat = (totype == PTY_f64); + MOperator mop = 0; + + PrimType itype = (GetPrimTypeBitSize(fromtype) == 64) ? (IsSignedInteger(fromtype) ? PTY_i64 : PTY_u64) + : (IsSignedInteger(fromtype) ? PTY_i32 : PTY_u32); + + opnd0 = LoadIntoRegister(opnd0, itype); + switch (itype) { + case PTY_i32: + mop = !is64bitsFloat ? MOP_vcvtfr : MOP_vcvtdr; + break; + case PTY_u32: + mop = !is64bitsFloat ? MOP_vcvtufr : MOP_vcvtudr; + break; + case PTY_i64: + mop = !is64bitsFloat ? MOP_xvcvtfr : MOP_xvcvtdr; + break; + case PTY_u64: + mop = !is64bitsFloat ? MOP_xvcvtufr : MOP_xvcvtudr; + break; + default: + CG_ASSERT(false, "unexpected type"); + } + curbb->AppendInsn(cg->BuildInstruction(mop, resopnd, opnd0)); +} + +Operand *Riscv64CGFunc::SelectCeil(TypeCvtNode *node, Operand *opnd0) { + if (CLANG) { + // Generate C style ceilf() and ceil() calls + PrimType ftype = node->fromPrimType; + PrimType rtype = node->primType; + vector opndvec; + Riscv64RegOperand *physOpnd; + if (ftype == PTY_f64) { + physOpnd = GetOrCreatePhysicalRegisterOperand(D0, 64, kRegTyFloat); + } else { + physOpnd = GetOrCreatePhysicalRegisterOperand(S0, 32, kRegTyFloat); + } + Operand *resopnd = static_cast(physOpnd); + opndvec.push_back(resopnd); + opnd0 = LoadIntoRegister(opnd0, ftype); + opndvec.push_back(opnd0); + if (ftype == PTY_f32) { + SelectLibCall("ceilf", opndvec, ftype, rtype); + } else { + SelectLibCall("ceil", opndvec, ftype, rtype); + } + return resopnd; + } + PrimType ftype = node->fromPrimType; + PrimType itype = node->primType; + CG_ASSERT((ftype == PTY_f64 || ftype == PTY_f32), "wrong float type"); + bool is64bits = (ftype == PTY_f64); + RegOperand *resopnd = CreateRegisterOperandOfType(itype); + opnd0 = LoadIntoRegister(opnd0, ftype); + //curbb->AppendInsn(cg->BuildInstruction(is64bits ? : , resopnd, opnd0)); + CHECK_FATAL(0, "NYI none C path"); + return resopnd; +} + +// float to int floor +Operand *Riscv64CGFunc::SelectFloor(TypeCvtNode *node, Operand *opnd0) { + if (CLANG) { + // Generate C style floorf() and floor() calls + PrimType ftype = node->fromPrimType; + PrimType rtype = node->primType; + vector opndvec; + Riscv64RegOperand *physOpnd; + if (ftype == PTY_f64) { + physOpnd = GetOrCreatePhysicalRegisterOperand(D0, 64, kRegTyFloat); + } else { + physOpnd = GetOrCreatePhysicalRegisterOperand(S0, 32, kRegTyFloat); + } + Operand *resopnd = static_cast(physOpnd); + opndvec.push_back(resopnd); + opnd0 = LoadIntoRegister(opnd0, ftype); + opndvec.push_back(opnd0); + if (ftype == PTY_f32) { + SelectLibCall("floorf", opndvec, ftype, rtype); + } else { + SelectLibCall("floor", opndvec, ftype, rtype); + } + return resopnd; + } + PrimType ftype = node->fromPrimType; + PrimType itype = node->primType; + CG_ASSERT((ftype == PTY_f64 || ftype == PTY_f32), "wrong float type"); + bool is64bits = (ftype == PTY_f64); + RegOperand *resopnd = CreateRegisterOperandOfType(itype); + opnd0 = LoadIntoRegister(opnd0, ftype); + //curbb->AppendInsn(cg->BuildInstruction(is64bits ? : , resopnd, opnd0)); + CHECK_FATAL(0, "NYI none C path"); + return resopnd; +} + +static bool LIsPrimitivePointer(PrimType primType) { + return (PTY_ptr <= primType && primType <= PTY_a64); +} + +Operand *Riscv64CGFunc::SelectRetype(TypeCvtNode *node, Operand *opnd0) { + PrimType fromtype = node->Opnd(0)->primType; + PrimType totype = node->primType; + CG_ASSERT(GetPrimTypeSize(fromtype) == GetPrimTypeSize(totype), "retype bit widith doesn' match"); + if (LIsPrimitivePointer(fromtype) && LIsPrimitivePointer(totype)) { + return LoadIntoRegister(opnd0, totype); + } + Operand::OperandType opnd0ty = opnd0->op_kind_; + RegOperand *resopnd = CreateRegisterOperandOfType(totype); + if (IsPrimitiveInteger(fromtype) || IsPrimitiveFloat(fromtype)) { + bool isfromint = IsPrimitiveInteger(fromtype); + bool is64bits = GetPrimTypeBitSize(fromtype) == 64; + PrimType itype = isfromint + ? ((GetPrimTypeBitSize(fromtype) == 64) ? (IsSignedInteger(fromtype) ? PTY_i64 : PTY_u64) + : (IsSignedInteger(fromtype) ? PTY_i32 : PTY_u32)) + : (is64bits ? PTY_f64 : PTY_f32); + + // if source operand is in memory, + // simply read it as a value of 'totype 'into the dest operand + // and return + if (opnd0ty == Operand::Opd_Mem) { + resopnd = SelectCopy(opnd0, totype, totype); + return resopnd; + } + opnd0 = LoadIntoRegister(opnd0, itype); + if ((IsPrimitiveFloat(fromtype) && IsPrimitiveInteger(totype)) || + (IsPrimitiveFloat(totype) && IsPrimitiveInteger(fromtype))) { + uint32 mopFmov = + isfromint ? (is64bits ? MOP_xvmovdr : MOP_xvmovsr) : (is64bits ? MOP_xvmovrd : MOP_xvmovrs); + curbb->AppendInsn(cg->BuildInstruction(mopFmov, resopnd, opnd0)); + return resopnd; + } else { + return opnd0; + } + } else { + CG_ASSERT(false, "NYI retype"); + } + return nullptr; +} + +void Riscv64CGFunc::SelectCvtFloat2Float(Operand *resopnd, Operand *opnd0, PrimType fromty, PrimType toty) { + opnd0 = LoadIntoRegister(opnd0, fromty); + MOperator mop = 0; + switch (toty) { + case PTY_f32: { + switch (fromty) { + case PTY_f64: + mop = MOP_xvcvtfd; + break; + default: + CG_ASSERT(false, "unexpected cvt from type"); + } + break; + } + case PTY_f64: { + switch (fromty) { + case PTY_f32: + mop = MOP_xvcvtdf; + break; + default: + CG_ASSERT(false, "unexpected cvt from type"); + } + break; + } + default: + CG_ASSERT(false, "unexpected cvt to type"); + } + curbb->AppendInsn(cg->BuildInstruction(mop, resopnd, opnd0)); +} + +bool Riscv64CGFunc::IfParamVRegOperand(Operand *opnd) { + //ParmLocator parmlocator(becommon); + + CG_ASSERT(opnd->IsRegister(), "Operand should be a register operand."); + + RegOperand *regOpnd = static_cast(opnd); + regno_t regno = regOpnd->GetRegisterNumber(); + + for (uint32 i = 0; i < func->formalDefVec.size(); i++) { + MIRType *ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(func->formalDefVec[i].formalTyIdx); + + MIRSymbol *sym = func->formalDefVec[i].formalSym; + if (!sym->IsPreg()) { + continue; + } + + PregIdx pregIdx = func->pregTab->GetPregIdxFromPregNo(sym->GetPreg()->pregNo); + + if (GetVirtualRegNoFromPseudoRegIdx(pregIdx) == regno) { + return true; + } + } + + return false; +} + +/* + This should be regarded only as a reference. + + C11 specification. + 6.3.1.3 Signed and unsigned integers + 1 When a value with integer type is converted to another integer + type other than _Bool, if the value can be represented by the + new type, it is unchanged. + 2 Otherwise, if the new type is unsigned, the value is converted + by repeatedly adding or subtracting one more than the maximum + value that can be represented in the new type until the value + is in the range of the new type.60) + 3 Otherwise, the new type is signed and the value cannot be + represented in it; either the result is implementation-defined + or an implementation-defined signal is raised. + */ +void Riscv64CGFunc::SelectCvtInt2Int(BaseNode *parent, Operand *&resopnd, Operand *opnd0, PrimType fromty, + PrimType toty) { + int fsize = GetPrimTypeBitSize(fromty); + int tsize = GetPrimTypeBitSize(toty); + if (fsize == 64 && fsize == tsize && opnd0->GetSize() < 64) { + fsize = opnd0->GetSize(); + fromty = (fromty == PTY_u64) ? PTY_u32 : PTY_i32; + } + bool isexpand = tsize > fsize; + bool is64bit = tsize == 64; + if (parent && opnd0->IsIntImmediate() && + ((parent->op == OP_band) || (parent->op == OP_bior) || (parent->op == OP_bxor) || (parent->op == OP_ashr) || + (parent->op == OP_lshr) || (parent->op == OP_shl))) { + ImmOperand *simm = static_cast(opnd0); + CG_ASSERT(simm != nullptr, "simm is nullptr in Riscv64CGFunc::SelectCvtInt2Int"); + bool isSign = false; + int64 origValue = simm->GetValue(); + int64 newValue = origValue; + int64 signValue = 0; + if (isexpand) { + // LogInfo::MapleLogger()<<"expand "<GetSize()<32 + if (fsize > tsize) { + // LogInfo::MapleLogger()<<"before trunc "<GetSize()<(1 << tsize) - 1) & signValue; + } else { + newValue = origValue & (static_cast(1 << tsize) - 1); + } + // LogInfo::MapleLogger()<<"after trunc "<(CreateImmOperand(newValue, GetPrimTypeSize(toty) * 8, isSign)); + return; + } + if (isexpand) { // Expansion + /* + int8_t i8; + uint8_t ui8; + short s ; + unsigned short us ; + i8 = 0xFF; + ui8 = 0xFF; + s = (short)i8; + us = (unsigned short)i8; + printf( "signed to signed %d -> %d\n", i8, s ); + printf( "signed to unsigned %d -> %d\n", i8, us ); + s = (short)ui8; + us = (unsigned short)ui8; + printf( "unsigned to signed %u -> %d\n", ui8, s ); + printf( "unsigned to unsigned %u -> %d\n", ui8, us ); + + Output: + signed to signed -1 -> -1 + signed to unsigned -1 -> 65535 + unsigned to signed 255 -> 255 + unsigned to unsigned 255 -> 255 + */ + // if cvt expr's parent is add,and,xor and some other,we can use the imm version + PrimType prmty = + (fsize == 64 ? (IsSignedInteger(fromty) ? PTY_i64 : PTY_u64) : (IsSignedInteger(fromty) ? PTY_i32 : PTY_u32)); + opnd0 = LoadIntoRegister(opnd0, prmty); + + if (IsSignedInteger(fromty)) { + CG_ASSERT((is64bit || (fsize == 8 || fsize == 16)), "incorrect from size"); + GenerateSext(resopnd, opnd0, toty, fsize); + } else { + // Unsigned + if (is64bit) { + if (fsize == 8) { + ImmOperand *immopnd = CreateImmOperand(0xff, 64, false); + curbb->AppendInsn(cg->BuildInstruction(MOP_xandrri13, resopnd, opnd0, immopnd)); + } else if (fsize == 16) { + ImmOperand *immopnd = CreateImmOperand(0xffff, 64, false); + curbb->AppendInsn(cg->BuildInstruction(MOP_xandrri13, resopnd, opnd0, immopnd)); + } else { + GenerateZext(resopnd, opnd0, toty, fsize); + } + } else { + CG_ASSERT((fsize == 8 || fsize == 16), "incorrect from size"); + if (fsize == 8) { + static_cast(opnd0)->SetValidBitsNum(8); + static_cast(resopnd)->SetValidBitsNum(8); + } + if (fromty == PTY_u1) { + static_cast(opnd0)->SetValidBitsNum(1); + static_cast(resopnd)->SetValidBitsNum(1); + } + GenerateZext(resopnd, opnd0, toty, fsize); + } + } + } else { // Same size or truncate +#ifdef CNV_OPTIMIZE + // No code needed for riscv64 with same reg. + // Just update regno. + RegOperand *reg = static_cast(resopnd); + reg->reg_no_ = static_cast(opnd0)->reg_no_; +#else + /* + With GCC 5.4.1 + short s ; + unsigned short us ; + int w = 0x00FFFFFF; + s = (short) w; + us = (unsigned short) w; + printf( "signed %d -> %d\n", w, s ); + printf( "unsigned %d -> %d\n", w, us ); + + Output: + signed 16777215 -> -1 + unsigned 16777215 -> 65535 + */ + // This is not really needed if opnd0 is result from a load. + // Hopefully the FE will get rid of the redundant conversions for loads. + PrimType prmty = + (fsize == 64 ? (IsSignedInteger(fromty) ? PTY_i64 : PTY_u64) : (IsSignedInteger(fromty) ? PTY_i32 : PTY_u32)); + opnd0 = LoadIntoRegister(opnd0, prmty); + + if (fsize > tsize) { + IsSignedInteger(toty) ? GenerateSext(resopnd, opnd0, toty, tsize) + : GenerateZext(resopnd, opnd0, toty, tsize); + } else { + // same size, so resopnd can be set + if (IsSignedInteger(fromty) == IsSignedInteger(toty) || + GetPrimTypeSize(toty) > 4) { + Riscv64RegOperand *reg = static_cast(resopnd); + reg->SetRegisterNumber(static_cast(opnd0)->GetRegisterNumber()); + } else if (IsUnsignedInteger(toty)) { + GenerateZext(resopnd, opnd0, toty, GetPrimTypeBitSize(toty)); + } else { + GenerateSext(resopnd, opnd0, toty, GetPrimTypeBitSize(toty)); + } + } +#endif + } +} + +Operand *Riscv64CGFunc::SelectCvt(BaseNode *parent, TypeCvtNode *node, Operand *opnd0) { + PrimType fromtype = node->fromPrimType; + PrimType totype = node->primType; + if (fromtype == totype) { + return opnd0; // noop + } + Operand *resopnd = static_cast(CreateRegisterOperandOfType(totype)); + if (IsPrimitiveFloat(totype) && IsPrimitiveInteger(fromtype)) { + SelectCvtInt2Float(resopnd, opnd0, totype, fromtype); + return resopnd; + } else if (IsPrimitiveFloat(fromtype) && IsPrimitiveInteger(totype)) { + SelectCvtFloat2Int(resopnd, opnd0, totype, fromtype); + return resopnd; + } else if (IsPrimitiveInteger(fromtype) && IsPrimitiveInteger(totype)) { +#if 0 + if (GetPrimTypeSize(fromtype) == 8) { + if (GetPrimTypeSize(totype) < 8) { + if (fromtype == PTY_i64) { + GenerateSext(resopnd, opnd0, totype, GetPrimTypeSize(totype) * BITS_PER_BYTE); + } else { + GenerateZext(resopnd, opnd0, totype, GetPrimTypeSize(totype) * BITS_PER_BYTE); + } + return resopnd; + } + return opnd0; + } + bool signExtend = false; + switch (totype) { + case PTY_u8: + case PTY_u16: + case PTY_u32: + case PTY_u64: + case PTY_a64: + break; + case PTY_i8: + case PTY_i16: + case PTY_i32: + case PTY_i64: + signExtend = true; + break; + default: + CHECK_FATAL(0, "SelectCvt: unknown pty"); + break; + } + uint32 bitSize = GetPrimTypeSize(fromtype) * BITS_PER_BYTE; + opnd0 = LoadIntoRegister(opnd0, fromtype); + if (signExtend) { + GenerateSext(resopnd, opnd0, totype, bitSize); + } else { + GenerateZext(resopnd, opnd0, totype, bitSize); + } +#else + // u64 <- i32 sign extension + // i32 <- u64 sign extension + // i64 <- u32 zero extension + // u32 <- i64 sign extension + // u64 <- u32 zero extension + // u32 <- u64 sign extension + // i64 <- i32 sign extension + // i32 <- i64 sign extension + uint32 bitSize; + if (GetPrimTypeSize(fromtype) > GetPrimTypeSize(totype)) { + bitSize = GetPrimTypeSize(totype) * BITS_PER_BYTE; + } else { + bitSize = GetPrimTypeSize(fromtype) * BITS_PER_BYTE; + } + bool isFromUnsigned = + (fromtype == PTY_u8 || fromtype == PTY_u16 || fromtype == PTY_u32 || fromtype == PTY_u64) + ? true : false; + bool isToUnsigned = + (totype == PTY_u8 || totype == PTY_u16 || totype == PTY_u32 || totype == PTY_u64) + ? true : false; + opnd0 = LoadIntoRegister(opnd0, fromtype); + if (isFromUnsigned && + (isFromUnsigned == isToUnsigned || GetPrimTypeSize(fromtype) < GetPrimTypeSize(totype))) { + GenerateZext(resopnd, opnd0, totype, bitSize); + } else { + GenerateSext(resopnd, opnd0, totype, bitSize); + } +#endif + return resopnd; + } else { // both are float type + SelectCvtFloat2Float(resopnd, opnd0, fromtype, totype); + return resopnd; + } +} + +Operand *Riscv64CGFunc::SelectRound(TypeCvtNode *node, Operand *opnd0) { + if (CLANG) { + // Generate C style roundf() and round() calls + PrimType ftype = node->fromPrimType; + PrimType rtype = node->primType; + vector opndvec; + Riscv64RegOperand *physOpnd; + if (ftype == PTY_f64) { + physOpnd = GetOrCreatePhysicalRegisterOperand(D0, 64, kRegTyFloat); + } else { + physOpnd = GetOrCreatePhysicalRegisterOperand(S0, 32, kRegTyFloat); + } + Operand *resopnd = static_cast(physOpnd); + opndvec.push_back(resopnd); + opnd0 = LoadIntoRegister(opnd0, ftype); + opndvec.push_back(opnd0); + if (ftype == PTY_f32) { + SelectLibCall("roundf", opndvec, ftype, rtype); + } else { + SelectLibCall("round", opndvec, ftype, rtype); + } + return resopnd; + } + PrimType ftype = node->fromPrimType; + PrimType itype = node->primType; + CG_ASSERT((ftype == PTY_f64 || ftype == PTY_f32), "wrong float type"); + bool is64bits = (ftype == PTY_f64); + RegOperand *resopnd = CreateRegisterOperandOfType(itype); + opnd0 = LoadIntoRegister(opnd0, ftype); + //curbb->AppendInsn(cg->BuildInstruction(is64bits ? : , resopnd, opnd0)); + CHECK_FATAL(0, "NYI none C path"); + return resopnd; +} + +Operand *Riscv64CGFunc::SelectTrunc(TypeCvtNode *node, Operand *opnd0) { + PrimType ftype = node->fromPrimType; + bool is64bits = (GetPrimTypeBitSize(node->primType) == 64); + PrimType itype = (is64bits) ? (IsSignedInteger(node->primType) ? PTY_i64 : PTY_u64) + : (IsSignedInteger(node->primType) ? PTY_i32 : PTY_u32); // promoted type + RegOperand *resopnd = CreateRegisterOperandOfType(itype); + SelectCvtFloat2Int(resopnd, opnd0, itype, ftype); + return resopnd; +} + +void Riscv64CGFunc::SelectSelect(Operand *resopnd, Operand *condopnd, Operand *trueopnd, Operand *falseopnd, + PrimType dtyp, PrimType ctyp) { + CG_ASSERT(resopnd != condopnd, "resopnd cannot be the same as condopnd"); + condopnd = LoadIntoRegister(condopnd, ctyp); + trueopnd = LoadIntoRegister(trueopnd, dtyp); + falseopnd = LoadIntoRegister(falseopnd, dtyp); + + bool isIntty = IsPrimitiveInteger(dtyp); + uint32 dsize = GetPrimTypeBitSize(dtyp); + bool isUnsignedInt = isIntty && !IsSignedInteger(dtyp); + + Riscv64RegOperand *condopnd2 = Riscv64RegOperand::GetZeroRegister(GetPrimTypeBitSize(ctyp)); + SelectRiscv64SelectOp(resopnd, condopnd, condopnd2, falseopnd, trueopnd, OP_eq, dsize, isUnsignedInt); +} + +Operand *Riscv64CGFunc::SelectSelect(TernaryNode *node, Operand *opnd0, Operand *opnd1, Operand *opnd2) { + PrimType dtyp = node->primType; + PrimType ctyp = node->Opnd(0)->primType; + RegOperand *resopnd = CreateRegisterOperandOfType(dtyp); + SelectSelect(resopnd, opnd0, opnd1, opnd2, dtyp, ctyp); + return resopnd; +} + +void Riscv64CGFunc::SelectRiscv64SelectOp(Operand *dest, Operand *opnd0, Operand *opnd1, Operand *trueOpnd, Operand *falseOpnd, + Opcode opcode, uint32 dsize, bool unsignedInt) { + /* + * br (false cond) -> else + * dest = 1 + * jump to done + * else: + * dest = 0 + * done: + */ + MOperator mopcode = 0; + RegOperand *fcmpResult = nullptr; + if (static_cast(opnd0)->IsOfIntClass()) { + if (opnd0->op_kind_ == Operand::Opd_Register) { + if (dsize == 32) { + unsignedInt ? + GenerateZext(opnd0, opnd0, PTY_u64, 32) + : GenerateSext(opnd0, opnd0, PTY_i64, 32); + } + } + if (opnd1->op_kind_ == Operand::Opd_Immediate) { + // load into register + PrimType primType = (dsize == 64) ? PTY_i64 : PTY_i32; + opnd1 = SelectCopy(opnd1, primType, primType); + } else if (opnd1->op_kind_ == Operand::Opd_Register) { + if (dsize == 32) { + unsignedInt ? + GenerateZext(opnd1, opnd1, PTY_u64, 32) + : GenerateSext(opnd1, opnd1, PTY_i64, 32); + } + } + switch (opcode) { + case OP_eq: + mopcode = MOP_bne; + break; + case OP_ne: + mopcode = MOP_beq; + break; + case OP_gt: + mopcode = unsignedInt ? MOP_bls : MOP_ble; + break; + case OP_lt: + mopcode = unsignedInt ? MOP_bhs : MOP_bge; + break; + case OP_ge: + mopcode = unsignedInt ? MOP_blo : MOP_blt; + break; + case OP_le: + mopcode = unsignedInt ? MOP_bhi : MOP_bgt; + break; + default: + CG_ASSERT(false, "illegal logical operator"); + } + } else { + if (opnd1->op_kind_ == Operand::Opd_FPZeroImmediate) { + PrimType primType = (dsize == 64) ? PTY_f64 : PTY_f32; + opnd1 = SelectCopy(opnd1, primType, primType); + } + MOperator cmpop = 0; + mopcode = MOP_beq; + switch (opcode) { + case OP_eq: + cmpop = (dsize == 32) ? MOP_scmpeqrr : MOP_dcmpeqrr; + break; + case OP_ne: + cmpop = (dsize == 32) ? MOP_scmpeqrr : MOP_dcmpeqrr; + mopcode = MOP_bne; + break; + case OP_gt: + cmpop = (dsize == 32) ? MOP_scmpgtrr : MOP_dcmpgtrr; + break; + case OP_lt: + cmpop = (dsize == 32) ? MOP_scmpltrr : MOP_dcmpltrr; + break; + case OP_ge: + cmpop = (dsize == 32) ? MOP_scmpgerr : MOP_dcmpgerr; + break; + case OP_le: + cmpop = (dsize == 32) ? MOP_scmplerr : MOP_dcmplerr; + break; + default: + CG_ASSERT(false, "illegal logical operator"); + } + fcmpResult = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8u)); + curbb->AppendInsn(cg->BuildInstruction(cmpop, fcmpResult, opnd0, opnd1)); + } + + BB *ifbb = CreateNewBB(); + curbb->AppendBB(ifbb); + BB *elsebb = CreateNewBB(); + ifbb->AppendBB(elsebb); + BB *donebb = CreateNewBB(); + elsebb->AppendBB(donebb); + + LabelIdx elselabidx = CreateLabel(); + elsebb->AddLabel(elselabidx); + lab2bbmap[elselabidx] = elsebb; + LabelOperand *elseTargOpnd = GetOrCreateLabelOperand(elselabidx); + + LabelIdx donelabidx = CreateLabel(); + lab2bbmap[donelabidx] = donebb; + donebb->AddLabel(donelabidx); + LabelOperand *doneTargOpnd = GetOrCreateLabelOperand(donelabidx); + + curbb->SetKind(BB::kBBIf); + ifbb->SetKind(BB::kBBGoto); + + //SelectRiscv64CSet(dest, GetCondOperand(cc), (dsize == 64)); + if (fcmpResult) { + Operand *zero = GetOrCreatePhysicalRegisterOperand(RZERO, 64, kRegTyInt); + curbb->AppendInsn(cg->BuildInstruction(mopcode, fcmpResult, zero, elseTargOpnd)); + } else { + curbb->AppendInsn(cg->BuildInstruction(mopcode, opnd0, opnd1, elseTargOpnd)); + } + MOperator mop; + if (trueOpnd->op_kind_ == Operand::Opd_Immediate) { + ifbb->AppendInsn(cg->BuildInstruction(MOP_xmovri64, dest, trueOpnd)); + } else { + mop = (static_cast(trueOpnd)->IsOfIntClass()) ? + ((dsize == 32) ? MOP_wmovrrr : MOP_xmovrrr) : + ((dsize == 32) ? MOP_xvmovss : MOP_xvmovdd); + ifbb->AppendInsn(cg->BuildInstruction(mop, dest, trueOpnd, falseOpnd)); + } + if (falseOpnd->op_kind_ == Operand::Opd_Immediate) { + elsebb->AppendInsn(cg->BuildInstruction(MOP_xmovri64, dest, falseOpnd)); + } else { + mop = (static_cast(falseOpnd)->IsOfIntClass()) ? + ((dsize == 32) ? MOP_wmovrrr : MOP_xmovrrr) : + ((dsize == 32) ? MOP_xvmovss : MOP_xvmovdd); + elsebb->AppendInsn(cg->BuildInstruction(mop, dest, falseOpnd, trueOpnd)); + } + ifbb->AppendInsn(cg->BuildInstruction(MOP_xuncond, doneTargOpnd)); + + curbb = donebb; +} + +void Riscv64CGFunc::SelectRangegoto(RangegotoNode *rangegotonode, Operand *opnd0) { + SmallCaseVector &switchtable = rangegotonode->rangegotoTable; + MIRType *etype = GlobalTables::GetTypeTable().GetTypeFromTyIdx((TyIdx)PTY_a64); + /* + * we store 8-byte displacement ( jump_label - offset_table_address ) + * in the table. Refer to Riscv64Emit::Emit() in riscv64_emit.cpp + */ + vector sizeArray; + sizeArray.push_back(switchtable.size()); + MIRArrayType *arraytype = memPool->New(etype->tyIdx, sizeArray); + MIRAggConst *arrayconst = memPool->New(&mirModule, arraytype); + for (uint32 i = 0; i < switchtable.size(); i++) { + LabelIdx lidx = switchtable[i].second; + MIRConst *mirconst = memPool->New(lidx, func->puIdx, etype); + arrayconst->constVec.push_back(mirconst); + } + + MIRSymbol *lblst = func->symTab->CreateSymbol(kScopeLocal); + lblst->storageClass = kScFstatic; + lblst->sKind = kStConst; + lblst->SetTyIdx(arraytype->tyIdx); + lblst->SetConst(arrayconst); + std::string lblstr(".LB_"); + MIRSymbol *funcSt = GlobalTables::GetGsymTable().GetSymbolFromStIdx(func->stIdx.Idx()); + lblstr.append(funcSt->GetName()).append(to_string(labelIdx++)); + lblst->SetNameStridx(GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(lblstr)); + emitstvec_.push_back(lblst); + + PrimType ityp = rangegotonode->uOpnd->primType; + opnd0 = LoadIntoRegister(opnd0, ityp); + + regno_t vRegNo = New_V_Reg(kRegTyInt, 8u); + RegOperand *addopnd = CreateVirtualRegisterOperand(vRegNo); + + int32 minidx = switchtable[0].first; + SelectAdd(addopnd, opnd0, CreateImmOperand(-minidx - rangegotonode->tagOffset, GetPrimTypeBitSize(ityp), true), ityp); + + // contains the index + if (addopnd->GetSize() != GetPrimTypeBitSize(PTY_u64)) { + addopnd = static_cast(SelectCopy(addopnd, PTY_u64, PTY_u64)); + } + + RegOperand *baseopnd = CreateRegisterOperandOfType(PTY_u64); + StImmOperand *switchTable = CreateStImmOperand(lblst, 0, 0); + + // load the address of the switch table + curbb->AppendInsn(cg->BuildInstruction(MOP_adrp, baseopnd, switchTable)); + curbb->AppendInsn(cg->BuildInstruction(MOP_adrpl12, baseopnd, baseopnd, switchTable)); + + // Compute the address of the load + RegOperand *sllDst = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + curbb->AppendInsn(cg->BuildInstruction(MOP_xlslrri6, sllDst, addopnd, CreateImmOperand(3, 4, false))); + RegOperand *addDst = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + curbb->AppendInsn(cg->BuildInstruction(MOP_xaddrrr, addDst, baseopnd, sllDst)); + Riscv64OfstOperand *immOffset = CreateOfstOpnd(0, 32); + Operand *disp = memPool->New(64, addDst, nullptr, immOffset, nullptr); + RegOperand *tgt = CreateRegisterOperandOfType(PTY_a64); + SelectAdd(tgt, baseopnd, disp, PTY_u64); + curbb->AppendInsn(cg->BuildInstruction(MOP_xbr, tgt)); +} + +Operand *Riscv64CGFunc::SelectAlloca(UnaryNode *node, Operand *opnd0) { + hasAlloca = true; + PrimType rettype = node->primType; + CG_ASSERT((rettype == PTY_a64), "wrong type"); + PrimType stype = node->Opnd(0)->primType; + Operand *resopnd = opnd0; + if (GetPrimTypeBitSize(stype) < GetPrimTypeBitSize(PTY_u64)) { + resopnd = CreateRegisterOperandOfType(PTY_u64); + SelectCvtInt2Int(nullptr, resopnd, opnd0, stype, PTY_u64); + } + + RegOperand *aliop = CreateRegisterOperandOfType(PTY_u64); + + SelectAdd(aliop, resopnd, CreateImmOperand(RISCV64_STACK_PTR_ALIGNMENT - 1, 64, true), PTY_u64); + Operand *shifopnd = CreateImmOperand(__builtin_ctz(RISCV64_STACK_PTR_ALIGNMENT), 64, true); + SelectShift(aliop, aliop, shifopnd, kShiftLright, PTY_u64); + SelectShift(aliop, aliop, shifopnd, kShiftLeft, PTY_u64); + Operand *spOpnd = GetOrCreatePhysicalRegisterOperand(RSP, 64, kRegTyInt); + SelectSub(spOpnd, spOpnd, aliop, PTY_u64); + int64 argsToStkpassSize = memlayout->SizeOfArgsToStackpass(); + if (argsToStkpassSize > 0) { + RegOperand *resallo = CreateRegisterOperandOfType(PTY_u64); + SelectAdd(resallo, spOpnd, CreateImmOperand(argsToStkpassSize, 64, true), PTY_u64); + return resallo; + } else { + return SelectCopy(spOpnd, PTY_u64, PTY_u64); + } +} + +Operand *Riscv64CGFunc::SelectMalloc(UnaryNode *node, Operand *opnd0) { + PrimType rettype = node->primType; + CG_ASSERT((rettype == PTY_a64), "wrong type"); + + vector opndvec; + RegOperand *resopnd = CreateRegisterOperandOfType(rettype); + opndvec.push_back(resopnd); + opndvec.push_back(opnd0); + // Use calloc to make sure allocated memory is zero-initialized + const char *funcName; + funcName = "calloc"; + Operand *opnd1; + bool size32 = (opnd0->GetSize() <= 32); + if (size32) { + opnd1 = CreateImmOperand(1, PTY_u32, false); + } else { + opnd1 = CreateImmOperand(1, PTY_u64, false); + } + opndvec.push_back(opnd1); + if (size32) { + SelectLibCall(funcName, opndvec, PTY_u32, rettype); + } else { + SelectLibCall(funcName, opndvec, PTY_u64, rettype); + } + return resopnd; +} + +Operand *Riscv64CGFunc::SelectGCMalloc(GCMallocNode *node) { + PrimType rettype = node->primType; + CG_ASSERT((rettype == PTY_a64), "wrong type"); + + // Get the size and alignment of the type. + TyIdx tyIdx = node->tyIdx; + uint64_t size = becommon.type_size_table.at(tyIdx.GetIdx()); + uint8_t align = Riscv64RTSupport::kObjectAlignment; + + // Generate the call to MCC_NewObj + Operand *opndSize = CreateImmOperand(size, 64, false); + Operand *opndAlign = CreateImmOperand(align, 64, false); + + RegOperand *resopnd = CreateRegisterOperandOfType(rettype); + + vector opndvec{ resopnd, opndSize, opndAlign }; + + const char *funcName = GetIntrinsicFuncName(INTRN_MCCNewObj).c_str(); + SelectLibCall(funcName, opndvec, PTY_u64, rettype); + + return resopnd; +} + +Operand *Riscv64CGFunc::SelectJarrayMalloc(JarrayMallocNode *node, Operand *opnd0) { + PrimType rettype = node->primType; + CG_ASSERT((rettype == PTY_a64), "wrong type"); + + // Extract jarray type + TyIdx tyIdx = node->tyIdx; + MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx); + auto jarytype = dynamic_cast(type); + if (jarytype == nullptr) { + FATAL(kLncFatal, "dynamic cast is nullptr"); + } + CG_ASSERT((jarytype != nullptr), "Type param of gcmallocjarray is not a MIRJarrayType"); + + uint64_t fixedSize = Riscv64RTSupport::kArrayContentOffset; + uint8_t align = Riscv64RTSupport::kObjectAlignment; + + MIRType *elemType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(jarytype->elemTyIdx); + PrimType elemPrimtype = elemType->GetPrimType(); + uint64_t elemSize = GetPrimTypeSize(elemPrimtype); + + // Generate the cal to MCC_NewObj_flexible + Operand *opndFixedSize = CreateImmOperand(PTY_u64, fixedSize); + Operand *opndElemSize = CreateImmOperand(PTY_u64, elemSize); + + Operand *opndNElems = opnd0; + + Operand *opndNElems64 = static_cast(CreateRegisterOperandOfType(PTY_u64)); + SelectCvtInt2Int(nullptr, opndNElems64, opndNElems, PTY_u32, PTY_u64); + + Operand *opndAlign = CreateImmOperand(PTY_u64, align); + + RegOperand *resopnd = CreateRegisterOperandOfType(rettype); + + vector opndvec{ resopnd, opndFixedSize, opndElemSize, opndNElems64, opndAlign }; + + const char *funcName = GetIntrinsicFuncName(INTRN_MCCNewObjFlexibleCname).c_str(); + SelectLibCall(funcName, opndvec, PTY_u64, rettype); + + // Generate the store of the object length field + MemOperand *opndArrayLengthField = CreateMemOpnd(resopnd, Riscv64RTSupport::kArrayLengthOffset, 4); + RegOperand *regopndNElems = SelectCopy(opndNElems, PTY_u32, PTY_u32); + SelectCopy(opndArrayLengthField, PTY_u32, regopndNElems, PTY_u32); + + return resopnd; +} + +} // namespace maplebe diff --git a/mapleall/maple_be/src/cg/riscv64/riscv64_intrinsics.cpp b/mapleall/maple_be/src/cg/riscv64/riscv64_intrinsics.cpp new file mode 100644 index 0000000..0f6b17f --- /dev/null +++ b/mapleall/maple_be/src/cg/riscv64/riscv64_intrinsics.cpp @@ -0,0 +1,420 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#include +#include + +#include "riscv64_cg_func.h" +#include "riscv64_cg.h" +#include "riscv64_rt_support.h" +#include "opcode_info.h" // mapleir/include/opcode_info.h +#include "cg_assert.h" +#include "mir_builder.h" +#include "mpl_atomic.h" + +#include "mpl_logging.h" + +namespace maplebe { + +using namespace maple; + +void Riscv64CGFunc::SelectMPLClinitCheck(IntrinsiccallNode *intrnnode) { + CG_ASSERT(intrnnode->NumOpnds() == 1, "must be 1 operand"); + BaseNode *arg = intrnnode->Opnd(0); + Operand *stopnd = nullptr; + bool bClinitSeperate = false; + CG_ASSERT(CGOptions::doPIC, "must be doPIC"); + if (arg->op == OP_addrof) { + AddrofNode *addrof = static_cast(arg); + MIRSymbol *symbol = func->GetLocalOrGlobalSymbol(addrof->stIdx); + CG_ASSERT(symbol->GetName().find(CLASSINFO_PREFIX_STR) == 0, "must be a symbol with __classinfo__"); + + if (!symbol->IsMuidDataUndefTab()) { + std::string ptrName = NameMangler::kPtrPrefixStr + symbol->GetName(); + MIRType *ptrType = GlobalTables::GetTypeTable().GetPtr(); + symbol = mirModule.mirBuilder->GetOrCreateGlobalDecl(ptrName, ptrType); + bClinitSeperate = true; + symbol->storageClass = kScFstatic; + } + stopnd = CreateStImmOperand(symbol, 0, 0); + } else { + arg = arg->Opnd(0); + BaseNode *arg0 = arg->Opnd(0); + BaseNode *arg1 = arg->Opnd(1); + CG_ASSERT(arg0->op == OP_addrof, "expect the operand to be addrof"); + AddrofNode *addrof = static_cast(arg0); + CHECK_FATAL(addrof, "static_cast failed"); + MIRSymbol *symbol = func->GetLocalOrGlobalSymbol(addrof->stIdx); + CG_ASSERT(addrof->fieldID == 0, "For debug SelectCGArrayElemAdd."); + // CG_ASSERT(symbol->GetName().find (CLASSINFO_PREFIX_STR) == 0, "must be a symbol with __classinfo__"); + ConstvalNode *constvalnode = static_cast(arg1); + CHECK_FATAL(constvalnode, "static_cast failed"); + MIRConst *mirconst = constvalnode->constVal; + MIRIntConst *mirintconst = dynamic_cast(mirconst); + CHECK_FATAL(mirintconst, "dynamic_cast failed"); + stopnd = CreateStImmOperand(symbol, mirintconst->value, 0); + } + + //{ + // Riscv64ListOperand* src_opnds = memPool->New(funcscope_allocator_); + // //src_opnds->push_opnd(stopnd); + // MIRSymbol *st = globaltable.CreateSymbol(kScopeGlobal); + // std::string funcname("__mpl_pre_clinit"); + // st->SetNameStridx(globaltable.GetOrCreateGstridxFromName(funcname)); + // st->storageClass = kScText; + // st->sKind = kStFunc; + // Operand *targetopnd = GetOrCreateFuncNameOpnd(func->GetLocalOrGlobalSymbol(st->GetStIdx(), false)); + // curbb->AppendInsn(cg->BuildInstruction(MOP_xbl, targetopnd, src_opnds)); + //} + + regno_t vreg2no = New_V_Reg(kRegTyInt, GetPrimTypeSize(PTY_a64)); + RegOperand *vreg2 = CreateVirtualRegisterOperand(vreg2no); + vreg2->SetRegNotBBLocal(); + if (bClinitSeperate) { + // Seperate MOP_clinit to MOP_adrp_ldr + MOP_clinit_tail. + Insn *newinsn = cg->BuildInstruction(MOP_adrp_ldr, vreg2, stopnd); + curbb->AppendInsn(newinsn); + newinsn->do_not_remove = true; + + newinsn = cg->BuildInstruction(MOP_clinit_tail, vreg2); + newinsn->do_not_remove = true; + curbb->AppendInsn(newinsn); + } else { + Insn *newinsn = cg->BuildInstruction(MOP_clinit, vreg2, stopnd); + curbb->AppendInsn(newinsn); + } + + //{ + // Riscv64ListOperand* src_opnds = memPool->New(funcscope_allocator_); + // //src_opnds->push_opnd(stopnd); + // MIRSymbol *st = globaltable.CreateSymbol(kScopeGlobal); + // std::string funcname("__mpl_post_clinit"); + // st->SetNameStridx(globaltable.GetOrCreateGstridxFromName(funcname)); + // st->storageClass = kScText; + // st->sKind = kStFunc; + // Operand *targetopnd = GetOrCreateFuncNameOpnd(func->GetLocalOrGlobalSymbol(st->GetStIdx(), false)); + // curbb->AppendInsn(cg->BuildInstruction(MOP_xbl, targetopnd, src_opnds)); + //} +} + + +void Riscv64CGFunc::SelectCVaStart(IntrinsiccallNode *intrnnode) { + CG_ASSERT(intrnnode->NumOpnds() == 2, "must be 2 operands"); + // 2 operands, but only 1 needed. Don't need to emit code for second operand + + RegOperand *opnd0; // first argument of intrinisc + BaseNode *argexpr = intrnnode->Opnd(0); + AddrofNode *ad = static_cast(argexpr); + MIRSymbol *sym = mirModule.CurFunction()->GetLocalOrGlobalSymbol(ad->stIdx, false); + int32 offs = 0; + Riscv64ImmOperand *offsOpnd; + Riscv64ImmOperand *offsOpnd2; + RegOperand *tmpreg; // offs value to be assigned (rhs) + MemOperand *strOpnd; // mem operand in va_list struct (lhs) + regno_t vregno = New_V_Reg(kRegTyInt, GetPrimTypeSize(PTY_a64)); + RegOperand *vreg = CreateVirtualRegisterOperand(vregno); + Operand *stkOpnd; + Insn *insn; + Riscv64MemLayout *memlayout = static_cast(this->memlayout); + int32 grAreaSize = memlayout->GetSizeOfGRSavearea(); + bool isSym = sym && (argexpr->op == OP_addrof); + + // if first argument of va_start is not a symbol, load its value + if (!isSym) { + Operand *opnd = HandleExpr(intrnnode, argexpr); + opnd0 = LoadIntoRegister(opnd, PTY_a64); + } + + // FPLR only pushed in regalloc() after intrin function + if (UseFP() || UsedStpSubPairForCallFrameAllocation()) { + stkOpnd = GetOrCreatePhysicalRegisterOperand(RFP, 64, kRegTyInt); + } else { + stkOpnd = GetOrCreatePhysicalRegisterOperand(RSP, 64, kRegTyInt); + } + + // Find beginning of unnamed arg on stack. + // Maybe in the save area or on stack + // Ex. void foo(int i1, int i2, ... int i8, S s, int x); + // where struct S has size 32, s are on stack but they are named, to + // reach the unnamed x, we need to skip over the named ones on the stack + ParmLocator parmlocator(becommon); + PLocInfo ploc; + uint32 stksize = 0; + for (uint32 i = 0; i < func->formalDefVec.size(); i++) { + MIRType *ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(func->formalDefVec[i].formalTyIdx); + uint32_t ptyIdx = ty->tyIdx.GetIdx(); + parmlocator.LocateNextParm(ty, ploc); + if (ploc.reg0 == kRinvalid) { // on stack + stksize = ploc.memoffset + ploc.memsize; + } + } + stksize = RoundUp(stksize, SIZEOFPTR); + + offsOpnd = CreateImmOperand(0, 64, true, true); // isvary reset StackFrameSize + offsOpnd2 = CreateImmOperand(grAreaSize, 64, false); + SelectSub(vreg, offsOpnd, offsOpnd2, PTY_a64); // if 1st opnd is register => sub + SelectAdd(vreg, stkOpnd, vreg, PTY_a64); + if (stksize) { + offsOpnd = CreateImmOperand(stksize, 64, false); + SelectAdd(vreg, offsOpnd, vreg, PTY_a64); + } + if (!isSym) { + Riscv64OfstOperand *offopnd = GetOrCreateOfstOpnd(0, 64); + strOpnd = GetOrCreateMemOpnd(64, opnd0, nullptr, offopnd, static_cast(nullptr)); + } else { + strOpnd = GetOrCreateMemOpnd(sym, 0, 64); + } + insn = cg->BuildInstruction(MOP_xstr, vreg, strOpnd); + curbb->AppendInsn(insn); + + return; +} + +Operand *Riscv64CGFunc::SelectCclz(IntrinsicopNode *intrnnode) { + vector opndvec; + + CG_ASSERT(intrnnode->NumOpnds() == 1, "must be 1 operand"); + BaseNode *argexpr = intrnnode->Opnd(0); + PrimType ptype = argexpr->primType; + Operand *opnd = HandleExpr(intrnnode, argexpr); + + RegOperand *ret = CreateRegisterOperandOfType(ptype); + opndvec.push_back(ret); // ret val + opndvec.push_back(opnd); // param 0 + SelectLibCall("__clzdi2", opndvec, ptype, ptype); + + if (GetPrimTypeSize(ptype) == 4) { + RegOperand *dst = CreateRegisterOperandOfType(ptype); + curbb->AppendInsn(cg->BuildInstruction(MOP_xaddrri12, dst, ret, CreateImmOperand(-32, 8, true))); + return dst; + } + return ret; +} + +Operand *Riscv64CGFunc::SelectCctz(IntrinsicopNode *intrnnode) { + vector opndvec; + + CG_ASSERT(intrnnode->NumOpnds() == 1, "must be 1 operand"); + BaseNode *argexpr = intrnnode->Opnd(0); + PrimType ptype = argexpr->primType; + Operand *opnd = HandleExpr(intrnnode, argexpr); + + RegOperand *ret = CreateRegisterOperandOfType(ptype); + opndvec.push_back(ret); // ret val + opndvec.push_back(opnd); // param 0 + SelectLibCall("__ctzdi2", opndvec, ptype, ptype); + + return ret; +} + +Operand *Riscv64CGFunc::SelectIntrinOp(IntrinsicopNode *intrinsicopnode) { + MIRIntrinsicID intrinsic = intrinsicopnode->intrinsic; + if (intrinsic == INTRN_C_clz32 || intrinsic == INTRN_C_clz64) { + return SelectCclz(intrinsicopnode); + } + if (intrinsic == INTRN_C_ctz32 || intrinsic == INTRN_C_ctz64) { + return SelectCctz(intrinsicopnode); + } + CHECK_FATAL(0, "NYI"); +} + +void Riscv64CGFunc::SelectIntrinCall(IntrinsiccallNode *intrinsiccallnode) { + MIRIntrinsicID intrinsic = intrinsiccallnode->intrinsic; + + if (cg->GenerateVerboseAsm()) { + string *comment = new string(GetIntrinsicName(intrinsic)); + const char *str = comment->c_str(); + curbb->AppendInsn(cg->BuildInstruction(MOP_comment, CreateCommentOperand(str))); + } + + // At this moment, we eagerly evaluates all argument expressions. In theory, + // there could be intrinsics that extract meta-information of variables, such + // as their locations, rather than computing their values. Applications + // include building stack maps that help runtime libraries to find the values + // of local variables (See @stackmap in LLVM), in which case knowing their + // locations will suffice. + + if (intrinsic == INTRN_MPL_CLINIT_CHECK) { // special case + SelectMPLClinitCheck(intrinsiccallnode); + return; + } + if (intrinsic == INTRN_MPL_CLEANUP_LOCALREFVARS || intrinsic == INTRN_MPL_CLEANUP_LOCALREFVARS_SKIP || + intrinsic == INTRN_MPL_STACK) { + return; + } + if (intrinsic == INTRN_C_va_start) { + SelectCVaStart(intrinsiccallnode); + return; + } + std::vector operands; // Temporary. Deallocated on return. + for (int32_t i = 0; i < intrinsiccallnode->NumOpnds(); i++) { + BaseNode *argexpr = intrinsiccallnode->Opnd(i); + Operand *opnd = HandleExpr(intrinsiccallnode, argexpr); + operands.push_back(opnd); + } + + CallReturnVector *retvals = nullptr; + + auto icanode = dynamic_cast(intrinsiccallnode); + if (icanode) { + retvals = &icanode->returnValues; + } + + switch (intrinsic) { + case INTRN_MPL_ATOMIC_EXCHANGE_PTR: { + CG_ASSERT(curbb->GetKind() == BB::kBBCall, ""); + BB *origFtBb = curbb->next; + Operand *loc = operands[0]; + Operand *newVal = operands[1]; + Operand *memOrd = operands[2]; + + MemOrd ord = OperandToMemOrd(memOrd); + bool isAcquire = MemOrdIsAcquire(ord); + bool isRelease = MemOrdIsRelease(ord); + + const PrimType kValPty = PTY_a64; + + RegOperand *locReg = LoadIntoRegister(loc, PTY_a64); + // Because there is no live analysis when -O1 + if (g->optim_level < 2) { + locReg->SetRegNotBBLocal(); + } + Riscv64MemOperand *locMem = + GetOrCreateMemOpnd(64, locReg, nullptr, GetOrCreateOfstOpnd(0, 32), nullptr); + + RegOperand *newValReg = LoadIntoRegister(newVal, PTY_a64); + if (g->optim_level < 2) { + newValReg->SetRegNotBBLocal(); + } + curbb->SetKind(BB::kBBFallthru); + + LabelIdx retryLabidx = CreateLabeledBB(intrinsiccallnode); + + RegOperand *oldVal = SelectLoadExcl(kValPty, locMem, isAcquire); + if (g->optim_level < 2) { + oldVal->SetRegNotBBLocal(); + } + RegOperand *succ = SelectStoreExcl(kValPty, locMem, newValReg, isRelease); + if (g->optim_level < 2) { + succ->SetRegNotBBLocal(); + } + + curbb->AppendInsn(cg->BuildInstruction(MOP_bnez, succ, GetOrCreateLabelOperand(retryLabidx))); + curbb->SetKind(BB::kBBIntrinsic); + curbb->next = origFtBb; + + SaveReturnValueInLocal(retvals, 0, kValPty, oldVal, intrinsiccallnode); + break; + } + default: + CHECK_FATAL(false, "Intrinsic %d: %s not implemented by the Riscv64 CG.", intrinsic, GetIntrinsicName(intrinsic)); + break; + } +} + +/* NOTE: consider moving the following things into riscv64_cg.cpp They may + * serve not only inrinsics, but other MapleIR instructions as well. + + * Do it as if we are adding a label in straight-line assembly code. + */ +LabelIdx Riscv64CGFunc::CreateLabeledBB(StmtNode *stmt) { + LabelIdx labidx = CreateLabel(); + BB *newbb = StartNewBBImpl(stmt); + newbb->AddLabel(labidx); + CG_ASSERT(newbb, ""); + lab2bbmap[labidx] = newbb; + curbb = newbb; + return labidx; +} + +// Save value into the local variable for the index-th return value; +void Riscv64CGFunc::SaveReturnValueInLocal(CallReturnVector *retvals, size_t index, PrimType pty, Operand *value, + StmtNode *parentStmt) { + CHECK_FATAL(retvals, "The current intrinsic call does not have return values"); + CallReturnPair &pair = (*retvals).at(index); + BB tempBb((uint32_t)-1, funcscope_allocator_); + BB *realCurbb = curbb; + curbb = &tempBb; + if (!pair.second.IsReg()) { + SelectDassign(pair.first, pair.second.GetFieldid(), pty, value); + } else { + CHECK_FATAL(false, "NYI"); + } + if (!realCurbb->next) { + realCurbb->laststmt = parentStmt; + realCurbb->next = StartNewBBImpl(parentStmt); + realCurbb->next->SetKind(BB::kBBFallthru); + realCurbb->next->prev = realCurbb; + } else { + CG_ASSERT(0, ""); + } + realCurbb->next->InsertAtBeginning(curbb); + // restore it + curbb = realCurbb->next; +} + +//// The following are translation of LL/SC and atomic RMW operations + +MemOrd Riscv64CGFunc::OperandToMemOrd(Operand *opnd) { + auto immOpnd = dynamic_cast(opnd); + CHECK_FATAL(immOpnd, "Memory order must be an int constant."); + uint32_t val = immOpnd->GetValue(); + return MemOrdFromU32(val); +} + +// Generate ldxr or ldaxr instruction. +// +// byte_p2x: power-of-2 size of operand in bytes (0: 1B, 1: 2B, 2: 4B, 3: 8B). +MOperator Riscv64CGFunc::PickLoadStoreExclInsn(int byteP2size, bool store, bool acqRel) { + CHECK_FATAL(0 <= byteP2size && byteP2size < 4, "Illegal argument p2size: %d", byteP2size); + + // Riscv64 has only word and double word atomic load/store + CHECK_FATAL(byteP2size > 2, "Illegal size for atomic"); + static MOperator operators[4][2][2] = { { { MOP_undef, MOP_undef }, { MOP_undef, MOP_undef } }, + { { MOP_undef, MOP_undef }, { MOP_undef, MOP_undef } }, + { { MOP_wldxr, MOP_wldaxr }, { MOP_wstxr, MOP_wstlxr } }, + { { MOP_xldxr, MOP_xldaxr }, { MOP_xstxr, MOP_xstlxr } } }; + + MOperator optr = operators[byteP2size][store][acqRel]; + + CHECK_FATAL(optr != MOP_undef, "Unsupported type p2size: %d", byteP2size); + + return optr; +} + +RegOperand *Riscv64CGFunc::SelectLoadExcl(PrimType valPty, Riscv64MemOperand *loc, bool acquire) { + int p2size = GetPrimTypeP2Size(valPty); + + RegOperand *result = CreateRegisterOperandOfType(valPty); + + MOperator mop = PickLoadStoreExclInsn(p2size, false, acquire); + curbb->AppendInsn(cg->BuildInstruction(mop, result, loc)); + + return result; +} + +RegOperand *Riscv64CGFunc::SelectStoreExcl(PrimType valPty, Riscv64MemOperand *loc, RegOperand *newVal, bool release) { + int p2size = GetPrimTypeP2Size(valPty); + + // the result (success/fail) is to be stored in a 32-bit register + RegOperand *result = CreateRegisterOperandOfType(PTY_u32); + + MOperator mop = PickLoadStoreExclInsn(p2size, true, release); + curbb->AppendInsn(cg->BuildInstruction(mop, result, newVal, loc)); + + return result; +} + +} // namespace maplebe diff --git a/mapleall/maple_be/src/cg/riscv64/riscv64_live_analysis.cpp b/mapleall/maple_be/src/cg/riscv64/riscv64_live_analysis.cpp new file mode 100644 index 0000000..7c58722 --- /dev/null +++ b/mapleall/maple_be/src/cg/riscv64/riscv64_live_analysis.cpp @@ -0,0 +1,284 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#include "riscv64_live_analysis.h" +#include "riscv64_cg.h" +#include "cg_assert.h" + +namespace maplebe { + +void Riscv64LiveAnalysis::InitEhDefine(BB *bb) { + Riscv64CGFunc *aarchcgfunc = static_cast(cgfunc_); + + // Insert MOP_pseudo_eh_def_x R1. + RegOperand *regopnd = aarchcgfunc->GetOrCreatePhysicalRegisterOperand(R1, 64, kRegTyInt); + Insn *pseudoInsn = cgfunc_->cg->BuildInstruction(MOP_pseudo_eh_def_x, regopnd); + bb->InsertInsnBegin(pseudoInsn); + + // Insert MOP_pseudo_eh_def_x R0. + regopnd = aarchcgfunc->GetOrCreatePhysicalRegisterOperand(R0, 64, kRegTyInt); + pseudoInsn = cgfunc_->cg->BuildInstruction(MOP_pseudo_eh_def_x, regopnd); + bb->InsertInsnBegin(pseudoInsn); +} + +regno_t Riscv64LiveAnalysis::UpdateRegNum(RegOperand *opnd) { + // upper 8 bits are encoded bit vector bit position + // See cg_bb.h for comparison function for std::set + regno_t rno = opnd->GetRegisterNumber(); + if (CGOptions::lsraSimdMode == 2) { + return rno; + } + Riscv64RegOperand *aopnd = dynamic_cast(opnd); + if (aopnd && aopnd->IsSimdVectorMode()) { + VectorType type = aopnd->GetSimdVectorType(); + if (type == kVecSingle) { + switch (aopnd->GetSimdVectorPosition()) { + case 0: + rno |= LIVE_POS_0; + break; + case 1: + rno |= LIVE_POS_1; + break; + case 2: + rno |= LIVE_POS_2; + break; + case 3: + rno |= LIVE_POS_3; + break; + default: + CG_ASSERT(0, "Riscv64LiveAnalysis::UpdateRegNum Error"); + } + } else { + // VEC_DOUBLE + switch (aopnd->GetSimdVectorPosition()) { + case 0: + rno |= LIVE_POS_0_1; + break; + case 1: + rno |= LIVE_POS_2_3; + break; + default: + CG_ASSERT(0, "Riscv64LiveAnalysis::UpdateRegNum Error"); + } + } + } + return rno; +} + +/* build use and def sets of each BB according to the type of regopnd. */ +void Riscv64LiveAnalysis::CollectLiveInfo(BB *bb, Operand *opnd, bool isDef, bool isUse) { + if (!opnd || !opnd->IsRegister()) { + return; + } + RegOperand *regopnd = static_cast(opnd); + regno_t rno = UpdateRegNum(regopnd); + RegType regtype = regopnd->GetRegisterType(); + if (regtype == kRegTyVary) { + return; + } + if (isDef) { + bb->def_regno.push_back(rno); + if (!isUse) { + bb->EraseUseRegnoFromVector(rno); + } + } + if (isUse) { + bb->use_regno.push_back(rno); + bb->EraseDefRegnoFromVector(rno); + } +} + +BB* Riscv64LiveAnalysis::CreateSubBB(BB *bb) { + subBBId++; + BB *newSubBB = memPool->New(subBBId, bb->mallocator); + (*subBB)[bb->id].push_back(newSubBB); + return newSubBB; +} + +bool Riscv64LiveAnalysis::CanInsnThrow(Insn *insn) { + if (insn->CanThrow()) { + if (insn->IsMemAccess()) { + Operand *opnd = insn->GetMemOpnd(); + if (opnd->IsMemoryAccessOperand()) { + MemOperand *memopnd = static_cast(opnd); + Operand *base = memopnd->GetBaseRegister(); + if (base) { + RegOperand *ropnd = static_cast(base); + if (!ropnd->IsPhysicalRegister() || + ((ropnd->GetRegisterNumber() != RFP && ropnd->GetRegisterNumber() != RSP))) { + return true; + } + } + } + } else { + return true; + } + } + return false; +} + +void Riscv64LiveAnalysis::GetInsnDefUse(BB *bb, Insn *insn) { + if (insn->IsCall()) { + for (uint32 i = 0; i < 8; i++) { + Operand *phyopnd = static_cast(cgfunc_)->GetOrCreatePhysicalRegisterOperand( + (Riscv64reg_t)(R0 + i), 64, kRegTyInt); + CollectLiveInfo(bb, phyopnd, true, false); + + phyopnd = static_cast(cgfunc_)->GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)(V0 + i), 64, + kRegTyFloat); + CollectLiveInfo(bb, phyopnd, true, false); + } + } + const Riscv64MD *md = &Riscv64CG::kMd[static_cast(insn)->mop_]; + for (int i = 0; i < Insn::kMaxOperandNum; i++) { + Operand *opnd = insn->opnds[i]; + if (opnd == nullptr) { + continue; + } + Riscv64OpndProp *regprop = static_cast(md->operand_[i]); + bool isDef = regprop->IsRegDef(); + bool isUse = regprop->IsRegUse(); + if (opnd->IsList()) { + ListOperand *listopnd = static_cast(opnd); + for (auto op : listopnd->GetOperands()) { + CollectLiveInfo(bb, op, false, true); + } + } else if (opnd->IsMemoryAccessOperand()) { + MemOperand *memopnd = static_cast(opnd); + Operand *base = memopnd->GetBaseRegister(); + Operand *offset = memopnd->GetIndexRegister(); + if (base != nullptr) { + CollectLiveInfo(bb, base, false, true); + } + if (offset != nullptr) { + CollectLiveInfo(bb, offset, false, true); + } + } else { + CollectLiveInfo(bb, opnd, isDef, isUse); + } + } +} + +void Riscv64LiveAnalysis::BreakBBIntoSubBB(BB *bb) { + /* For a B that can throw, at least two subBBs will be created. + The insn that throws will be the first insn of the subBB. + */ + BB *newSubBB = nullptr; + Insn *prev = nullptr; + FOR_BB_INSNS(insn, bb) { + if (CanInsnThrow(insn)) { + if (newSubBB) { + newSubBB->lastinsn = prev; + newSubBB = CreateSubBB(bb); + newSubBB->firstinsn = insn; + } else { + // first insn of bb can throw + newSubBB = CreateSubBB(bb); + newSubBB->firstinsn = insn; + } + } else if (newSubBB == nullptr) { + // first insn of bb did not throw + newSubBB = CreateSubBB(bb); + newSubBB->firstinsn = insn; + } + prev = insn; + } + newSubBB->lastinsn = bb->lastinsn; + + for (auto sbb: (*subBB)[bb->id]) { + for (auto ehsucc: bb->eh_succs) { + sbb->eh_succs.push_back(ehsucc); + } + } + uint32 numSubBBs = (*subBB)[bb->id].size(); + for (uint32 idx = 0; idx < (numSubBBs - 1); idx++) { + ((*subBB)[bb->id])[idx]->succs.push_back( ((*subBB)[bb->id])[idx+1] ); + } + for (auto succ: bb->succs) { + ((*subBB)[bb->id])[numSubBBs-1]->succs.push_back(succ); + } +} + +/* entry of get def/use of bb. + getting the def or use info of each regopnd as parameters of CollectLiveInfo(). + build the subBB structure for Eh aware live analysis. + */ +void Riscv64LiveAnalysis::GetBBDefUse(BB *bb) { + if (bb->IsEmpty()) { + return; + } + if (GetDoEhLiveAnalysis() && bb->eh_succs.size() > 0) { + BreakBBIntoSubBB(bb); + + for (auto sbb = (*subBB)[bb->id].rbegin(); sbb != (*subBB)[bb->id].rend(); sbb++) { + FOR_SUBBB_INSNS_REV(insn, (*sbb)) { + if (!insn->IsMachineInstruction()) { + continue; + } + GetInsnDefUse((*sbb), insn); + } + } + // Live analysis does not need this info once it is split into sub-BBs. + // However some optimization phase uses this info. + FOR_BB_INSNS_REV(insn, bb) { + if (!insn->IsMachineInstruction()) { + continue; + } + GetInsnDefUse(bb, insn); + } + } else { + FOR_BB_INSNS_REV(insn, bb) { + if (!insn->IsMachineInstruction()) { + continue; + } + GetInsnDefUse(bb, insn); + } + } +} + +bool Riscv64LiveAnalysis::CleanupBBIgnoreReg(uint32 reg) { + if (reg < 8 || (reg >= 29 && reg <= 32)) { + return true; + } + return false; +} + +void Riscv64LiveAnalysis::FinalizeLiveAnalysis() { + FOR_ALL_BB(bb, cgfunc_) { + auto it = bb->livein_regno.begin(); + while (it != bb->livein_regno.end()) { + regno_t rno = *it; + if (rno & LIVE_SLOT_MASK) { + it = bb->livein_regno.erase(it); + bb->livein_regno.insert(rno & LIVE_REG_MASK); + } else { + it++; + } + } + + it = bb->liveout_regno.begin(); + while (it != bb->liveout_regno.end()) { + regno_t rno = *it; + if (rno & LIVE_SLOT_MASK) { + it = bb->liveout_regno.erase(it); + bb->liveout_regno.insert(rno & LIVE_REG_MASK); + } else { + it++; + } + } + } +} + +} // namespace maplebe diff --git a/mapleall/maple_be/src/cg/riscv64/riscv64_load_store.cpp b/mapleall/maple_be/src/cg/riscv64/riscv64_load_store.cpp new file mode 100644 index 0000000..a19b4b2 --- /dev/null +++ b/mapleall/maple_be/src/cg/riscv64/riscv64_load_store.cpp @@ -0,0 +1,2119 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#include "riscv64_cg_func.h" +#include "riscv64_cg.h" +#include "cg_assert.h" +#include "mir_builder.h" + +#include + +namespace maplebe { +using namespace maple; +using namespace std; + +extern bool doItQuietly; + +static MOperator ldis[2][4] = { + /* unsigned == 0 */ + { MOP_wldrb, MOP_wldrh, MOP_wldr, MOP_xldr }, + /* signed == 1 */ + { MOP_wldrsb, MOP_wldrsh, MOP_wldrsw, MOP_xldr } +}; +static MOperator stis[2][4] = { + /* unsigned == 0 */ + { MOP_wstrb, MOP_wstrh, MOP_wstr, MOP_xstr }, + /* signed == 1 */ + { MOP_wstrb, MOP_wstrh, MOP_wstr, MOP_xstr } +}; + +static MOperator stIsRel[2][4] = { + /* unsigned == 0 */ + { MOP_undef, MOP_undef, MOP_wstlr, MOP_xstlr }, + /* signed == 1 */ + { MOP_undef, MOP_undef, MOP_wstlr, MOP_xstlr } +}; + +static MOperator ldfs[2] = { MOP_sldr, MOP_dldr }; +static MOperator stfs[2] = { MOP_sstr, MOP_dstr }; + +static MOperator ldFsAcq[2] = { MOP_undef, MOP_undef }; +static MOperator stFsRel[2] = { MOP_undef, MOP_undef }; + +template +MOperator PickLdStInsn(uint32 bitsize, PrimType rtype, Riscv64isa::memory_ordering_t mo) { + CG_ASSERT(__builtin_popcount((unsigned int)mo) <= 1, ""); + CG_ASSERT(rtype != PTY_ptr && rtype != PTY_ref, "should have been lowered"); + CG_ASSERT(bitsize >= 8 && __builtin_popcount(bitsize) == 1, "PTY_u1 should have been lowered?"); + CG_ASSERT( + (is_load && (mo == Riscv64isa::kMoNone || mo == Riscv64isa::kMoAcquire || mo == Riscv64isa::kMoAcquireRcpc || + mo == Riscv64isa::kMoLoacquire)) || + (!is_load && (mo == Riscv64isa::kMoNone || mo == Riscv64isa::kMoRelease || mo == Riscv64isa::kMoLorelease)), + ""); + + /* __builtin_ffs(x) returns: 0 -> 0, 1 -> 1, 2 -> 2, 4 -> 3, 8 -> 4 */ + // int mo_idx = __builtin_ffs( (int)mo ); + + if (IsPrimitiveInteger(rtype)) { + MOperator(*table)[4]; + if (is_load) { + table = mo == Riscv64isa::kMoAcquire ? ldis : ldis; // need to support acquire + } else { + table = mo == Riscv64isa::kMoRelease ? stIsRel : stis; + } + + int signedUnsigned = IsUnsignedInteger(rtype) ? 0 : 1; + /* __builtin_ffs(x) returns: 8 -> 4, 16 -> 5, 32 -> 6, 64 -> 7 */ + unsigned int size = static_cast(__builtin_ffs(static_cast(bitsize))) - 4; + CG_ASSERT(size <= 3, ""); + return table[signedUnsigned][size]; + } else if (IsPrimitiveVector(rtype)) { + return is_load ? MOP_vldr : MOP_vstr; + } else { + MOperator *table = nullptr; + if (is_load) { + table = mo == Riscv64isa::kMoAcquire ? ldFsAcq : ldfs; + } else { + table = mo == Riscv64isa::kMoRelease ? stFsRel : stfs; + } + + /* __builtin_ffs(x) returns: 32 -> 6, 64 -> 7 */ + unsigned int size = static_cast(__builtin_ffs(static_cast(bitsize))) - 6; + CG_ASSERT(size <= 1, ""); + return table[size]; + } +} + +MOperator Riscv64CGFunc::PickVecDup(PrimType sPtyp) { + switch (sPtyp) { + case PTY_i32: + return MOP_vdupi32; + case PTY_i64: + return MOP_vdupi64; + case PTY_f32: + return MOP_vdupf32; + case PTY_f64: + return MOP_vdupf64; + default: + CG_ASSERT(false, "NYI"); + return MOP_undef; + } +} + +MOperator Riscv64CGFunc::PickLdInsn(uint32 bitsize, PrimType rtype, Riscv64isa::memory_ordering_t mo) { + return PickLdStInsn(bitsize, rtype, mo); +} + +MOperator Riscv64CGFunc::PickStInsn(uint32 bitsize, PrimType rtype, Riscv64isa::memory_ordering_t mo) { + return PickLdStInsn(bitsize, rtype, mo); +} + +MOperator Riscv64CGFunc::PickMovInsn(PrimType primtype) { + switch (primtype) { + case PTY_u8: + case PTY_u16: + case PTY_u32: + case PTY_i8: + case PTY_i16: + case PTY_i32: + return MOP_wmovrr; + case PTY_a32: + CG_ASSERT(0, "Invalid primitive type for Riscv64"); + return MOP_undef; + case PTY_ptr: + case PTY_ref: + CG_ASSERT(0, "PTY_ref and PTY_ptr should have been lowered"); + return MOP_undef; + case PTY_a64: + case PTY_u64: + case PTY_i64: + return MOP_xmovrr; + case PTY_f32: + return MOP_xvmovs; + case PTY_f64: + return MOP_xvmovd; + case PTY_v2i64: + case PTY_v4i32: + case PTY_v8i16: + case PTY_v16i8: + case PTY_v2f64: + case PTY_v4f32: + return MOP_vmovrr; + default: + CG_ASSERT(0, "NYI PickMovInsn"); + return MOP_undef; + } +} + +MOperator Riscv64CGFunc::PickMovInsn(RegOperand *lhs, RegOperand *rhs) { + CG_ASSERT(lhs->GetSize() == rhs->GetSize(), "PickMovInsn: unequal size NYI"); + //CG_ASSERT((lhs->GetSize() < 64 || lhs->GetRegisterType() == kRegTyFloat), "should split the 64 bits or more mov"); + if (lhs->GetRegisterType() == kRegTyInt) { + if (rhs->GetRegisterType() == kRegTyInt) { + return MOP_wmovrr; + } else { + return (rhs->GetSize() == 64) ? MOP_xvmovrd : MOP_xvmovrs; + } + } else if (lhs->GetRegisterType() == kRegTyFloat) { + if (rhs->GetRegisterType() == kRegTyFloat) { + return (lhs->GetSize() == 64) ? MOP_xvmovd : MOP_xvmovs; + } else { + return (lhs->GetSize() == 64) ? MOP_xvmovdr : MOP_xvmovsr; + } + } + CG_ASSERT(false, "PickMovInsn: kind NYI"); + return 0; +} + +MOperator Riscv64CGFunc::PickMovInsn(uint32_t bitlen, RegType rtype) { + CG_ASSERT(bitlen == 32 || bitlen == 64, ""); + CG_ASSERT(rtype == kRegTyInt || rtype == kRegTyFloat, ""); + if (rtype == kRegTyInt) { + return ((bitlen == 32) ? static_cast(MOP_wmovrr) : static_cast(MOP_xmovrr)); + } else { + return ((bitlen == 32) ? static_cast(MOP_xvmovs) : static_cast(MOP_xvmovd)); + } +} + +void Riscv64CGFunc::SelectLoadAcquire(Operand *dest, PrimType dtype, Operand *src, PrimType stype, + Riscv64isa::memory_ordering_t mo, bool isDirect) { + CG_ASSERT(src->op_kind_ == Operand::Opd_Mem, "Just checking"); + CG_ASSERT(mo != Riscv64isa::kMoNone, "Just checking"); + + Insn *insn = nullptr; + uint32 ssize = isDirect ? src->GetSize() : GetPrimTypeBitSize(dtype); + uint32 dsize = GetPrimTypeBitSize(dtype); + MOperator mop = PickLdInsn(ssize, stype, mo); + + Operand *newSrc = src; + Riscv64MemOperand *memopnd = static_cast(src); + Riscv64OfstOperand *immopnd = memopnd->GetOffsetImmediate(); + int32 offset = immopnd->GetOffsetValue(); + RegOperand *origBasereg = memopnd->GetBaseRegister(); + if (offset != 0) { + RegOperand *resopnd = CreateRegisterOperandOfType(PTY_i64); + SelectAdd(resopnd, origBasereg, immopnd, PTY_i64); + newSrc = CreateReplacementMemOperand(memopnd, ssize, resopnd, 0); + } + + std::string key; + if (isDirect && cg->GenerateVerboseAsm()) { + MIRSymbol *sym = static_cast(src)->GetSymbol(); + if (sym) { + MIRStorageClass sc = sym->GetStorageClass(); + if (sc == kScFormal) { + key = "param: "; + } else if (sc == kScAuto) { + key = "local var: "; + } else { + key = "global: "; + } + key.append(sym->GetName()); + } + } + + /* Check if the right load-acquire instruction is available. */ + if (mop != MOP_undef) { + insn = cg->BuildInstruction(mop, dest, newSrc); + if (isDirect && cg->GenerateVerboseAsm()) { + insn->AddComment(key); + } + curbb->AppendInsn(insn); + } else { + if (IsPrimitiveFloat(stype)) { + /* Uses signed integer version ldar followed by a floating-point move(fmov). */ + CG_ASSERT(stype == dtype, "Just checking"); + PrimType itype = stype == PTY_f32 ? PTY_i32 : PTY_i64; + RegOperand *regopnd = CreateRegisterOperandOfType(itype); + insn = cg->BuildInstruction(PickLdInsn(ssize, itype, mo), regopnd, newSrc); + if (isDirect && cg->GenerateVerboseAsm()) { + insn->AddComment(key); + } + curbb->AppendInsn(insn); + mop = stype == PTY_f32 ? MOP_xvmovsr : MOP_xvmovdr; + curbb->AppendInsn(cg->BuildInstruction(mop, dest, regopnd)); + } else if (IsPrimitiveInteger(stype)){ + /* Use unsigned version ldarb/ldarh followed by a sign-extension instruction(sxtb/sxth). */ + CG_ASSERT(ssize == 8 || ssize == 16, "Just checking"); + PrimType utype = ssize == 8 ? PTY_u8 : PTY_u16; + insn = cg->BuildInstruction(PickLdInsn(ssize, utype, mo), dest, newSrc); + if (isDirect && cg->GenerateVerboseAsm()) { + insn->AddComment(key); + } + curbb->AppendInsn(insn); + GenerateSext(dest, dest, dtype, ssize); + } else { + CG_ASSERT(false, "vector NYI"); + } + } +} + +void Riscv64CGFunc::SelectStoreRelease(Operand *dest, PrimType dtype, Operand *src, PrimType stype, + Riscv64isa::memory_ordering_t mo, bool isDirect) { + CG_ASSERT(dest->op_kind_ == Operand::Opd_Mem, "Just checking"); + CG_ASSERT(mo != Riscv64isa::kMoNone, "Just checking"); + + Insn *insn = nullptr; + uint32 dsize = isDirect ? dest->GetSize() : GetPrimTypeBitSize(stype); + MOperator mop = PickStInsn(dsize, stype, mo); + + Operand *newDest = dest; + Riscv64MemOperand *memopnd = static_cast(dest); + Riscv64OfstOperand *immopnd = memopnd->GetOffsetImmediate(); + int32 offset = immopnd->GetOffsetValue(); + RegOperand *origBasereg = memopnd->GetBaseRegister(); + if (offset != 0) { + RegOperand *resopnd = CreateRegisterOperandOfType(PTY_i64); + SelectAdd(resopnd, origBasereg, immopnd, PTY_i64); + newDest = CreateReplacementMemOperand(memopnd, dsize, resopnd, 0); + } + + std::string key; + if (isDirect && cg->GenerateVerboseAsm()) { + MIRSymbol *sym = static_cast(dest)->GetSymbol(); + if (sym) { + MIRStorageClass sc = sym->GetStorageClass(); + if (sc == kScFormal) { + key = "param: "; + } else if (sc == kScAuto) { + key = "local var: "; + } else { + key = "global: "; + } + key.append(sym->GetName()); + } + } + + /* Check if the right store-release instruction is available. */ + if (mop != MOP_undef) { + insn = cg->BuildInstruction(mop, src, newDest); + if (isDirect && cg->GenerateVerboseAsm()) { + insn->AddComment(key); + } + curbb->AppendInsn(insn); + } else { + /* Use a floating-point move(fmov) followed by a stlr. */ + CG_ASSERT(IsPrimitiveFloat(stype) && stype == dtype, "Just checking"); + PrimType itype = stype == PTY_f32 ? PTY_i32 : PTY_i64; + RegOperand *regopnd = CreateRegisterOperandOfType(itype); + mop = stype == PTY_f32 ? MOP_xvmovrs : MOP_xvmovrd; + curbb->AppendInsn(cg->BuildInstruction(mop, regopnd, src)); + insn = cg->BuildInstruction(PickStInsn(dsize, itype, mo), regopnd, newDest); + if (isDirect && cg->GenerateVerboseAsm()) { + insn->AddComment(key); + } + curbb->AppendInsn(insn); + } +} + +RegOperand *Riscv64CGFunc::MoveImm16Bits(uint32 val) { + RegOperand *dest = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 4)); + curbb->AppendInsn(cg->BuildInstruction(MOP_xmovri64, dest, CreateImmOperand(val, 4, false))); + return dest; +} + +RegOperand *Riscv64CGFunc::CombineImmBits(Operand *dest, Operand *upper, Operand *lower, uint32 shift) { + RegOperand *sllDest = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 4)); + curbb->AppendInsn(cg->BuildInstruction(MOP_xlslrri6, sllDest, upper, CreateImmOperand(shift, 4, false))); + if (dest == nullptr) { + dest = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 4)); + } + curbb->AppendInsn(cg->BuildInstruction(MOP_xiorrrr, dest, sllDest, lower)); + return static_cast(dest); +} + +void Riscv64CGFunc::SelectCopyImm(Operand *dest, Riscv64ImmOperand *src, PrimType dtype) { + uint32 dsize = GetPrimTypeBitSize(dtype); + CG_ASSERT(IsPrimitiveInteger(dtype), "The type of destination operand must be Integer"); + CG_ASSERT((dsize == 8 || dsize == 16 || dsize == 32 || dsize == 64), "The destination operand must be >= 8-bit"); + if (static_cast(src)->IsInBitSize(11)) { + curbb->AppendInsn(cg->BuildInstruction(MOP_xmovri64, dest, src)); + } else { + uint64 srcval = static_cast(src->GetValue()); + // using mov/movk to load the immediate value + if (dsize == 8) { + if (dtype == PTY_u8) { + // zero extend + srcval = (srcval << 56) >> 56; + dtype = PTY_u16; + } else { + // sign extend + srcval = ((static_cast(srcval)) << 56) >> 56; + dtype = PTY_i16; + } + dsize = 16; + } + if (dsize == 16) { + if (dtype == PTY_u16) { + // create an imm opereand which represents lower 16 bits of the immediate + ImmOperand *srcLower = CreateImmOperand((srcval & 0x0000FFFFULL), 16, false); + curbb->AppendInsn(cg->BuildInstruction(MOP_xmovri64, dest, srcLower)); + return; + } else { + // sign extend and let `dsize == 32` case take care of it + srcval = (((int64)srcval) << 48) >> 48; + dsize = 32; + } + } + if (dsize == 32) { + curbb->AppendInsn(cg->BuildInstruction(MOP_xmovri64, dest, CreateImmOperand(srcval, 32, src->IsSignedValue()))); + } else { + curbb->AppendInsn(cg->BuildInstruction(MOP_xmovri64, dest, CreateImmOperand(srcval, 64, src->IsSignedValue()))); + } + } +} + +void Riscv64CGFunc::SelectCopy(Operand *dest, PrimType dtype, Operand *src, PrimType stype) { + uint32 ssize = src->GetSize(); + CG_ASSERT(dest->IsRegister() || dest->IsMemoryAccessOperand(), ""); + uint32 dsize = GetPrimTypeBitSize(dtype); + if (dest->IsRegister()) { + dsize = dest->GetSize(); + } + Operand::OperandType opnd0ty = dest->op_kind_; + Operand::OperandType opnd1ty = src->op_kind_; + CG_ASSERT((dsize >= ssize || opnd0ty == Operand::Opd_Mem), "NYI"); + CG_ASSERT((opnd0ty == Operand::Opd_Register || opnd1ty == Operand::Opd_Register), + "either src or dest should be register"); + + switch (src->op_kind_) { + case Operand::Opd_Mem: { + Riscv64isa::memory_ordering_t mo = Riscv64isa::kMoNone; + MIRSymbol *sym = static_cast(src)->GetSymbol(); + if (sym && sym->GetStorageClass() == kScGlobal && sym->GetAttr(ATTR_memory_order_acquire)) { + mo = Riscv64isa::kMoAcquire; + } + + Insn *insn = nullptr; + if (mo == Riscv64isa::kMoNone) { + if (IsPrimitiveFloat(stype)) { + CG_ASSERT(dsize == ssize, ""); + insn = cg->BuildInstruction(PickLdInsn(ssize, stype), dest, src); + curbb->AppendInsn(insn); + } else { + PrimType symty = stype; +#if 0 + if (sym) { + PrimType tmpty = sym->GetType()->primType; + if (tmpty == PTY_u8 || tmpty == PTY_u16 || tmpty == PTY_u32) { + symty = tmpty; + } + } +#endif + +#if 0 + if (sym && dsize > ssize) { + RegOperand *ldDst = CreateRegisterOperandOfType(dtype); + insn = cg->BuildInstruction(PickLdInsn(ssize, symty), ldDst, src); + curbb->AppendInsn(insn); + switch (sym->GetType()->primType) { + case PTY_i8: + case PTY_i16: + case PTY_i32: + case PTY_i64: + GenerateSext(dest, ldDst, dtype, ssize); + break; + default: + GenerateZext(dest, ldDst, dtype, ssize); + } + } else { +#endif + { + insn = cg->BuildInstruction(PickLdInsn(ssize, symty), dest, src); + curbb->AppendInsn(insn); + } + } + + if (cg->GenerateVerboseAsm()) { + MIRSymbol *sym = static_cast(src)->GetSymbol(); + if (sym) { + std::string key; + MIRStorageClass sc = sym->GetStorageClass(); + if (sc == kScFormal) { + key = "param: "; + } else if (sc == kScAuto) { + key = "local var: "; + } else { + key = "global: "; + } + insn->AddComment(key.append(sym->GetName())); + } + } + } else { + Riscv64CGFunc::SelectLoadAcquire(dest, dtype, src, stype, mo, true); + } + } break; + + case Operand::Opd_Immediate: + SelectCopyImm(dest, static_cast(src), stype); + break; + + case Operand::Opd_FPZeroImmediate: + curbb->AppendInsn(cg->BuildInstruction(dsize == 32 ? MOP_xvmovsr : MOP_xvmovdr, dest, + Riscv64RegOperand::GetZeroRegister(dsize))); + break; + + case Operand::Opd_Register: { + if (opnd0ty == Operand::Opd_Mem) { + Riscv64isa::memory_ordering_t mo = Riscv64isa::kMoNone; + MIRSymbol *sym = static_cast(dest)->GetSymbol(); + if (sym && sym->GetStorageClass() == kScGlobal && sym->GetAttr(ATTR_memory_order_release)) { + mo = Riscv64isa::kMoRelease; + } + + if (mo == Riscv64isa::kMoNone) { + MOperator strmop = PickStInsn(dsize, stype); + if (dest->IsMemoryAccessOperand()) { + Riscv64MemOperand *mopnd = static_cast(dest); + CG_ASSERT(mopnd, "mopnd should not be nullptr"); + if (mopnd->GetOffsetOperand() == nullptr) { + curbb->AppendInsn(cg->BuildInstruction(strmop, src, dest)); + return; + } + ImmOperand *imopnd = static_cast(mopnd->GetOffsetOperand()); + CG_ASSERT(imopnd, "imopnd should not be nullptr"); + int64 immVal = imopnd->GetValue(); + bool isInRange = false; + bool isMopStr = false; + switch (strmop) { + case MOP_xstr: + case MOP_wstr: { + bool is64bits = (dest->GetSize() == 64) ? true : false; + isInRange = + ((!is64bits && immVal >= STRALL_LDRALL_IMM_LOWER_BOUND && immVal <= STR_LDR_IMM32_UPPER_BOUND) || + (is64bits && immVal >= STRALL_LDRALL_IMM_LOWER_BOUND && immVal <= STR_LDR_IMM64_UPPER_BOUND)); + isMopStr = true; + break; + } + case MOP_wstrb: + isInRange = + (immVal >= STRALL_LDRALL_IMM_LOWER_BOUND && immVal <= STRB_LDRB_IMM_UPPER_BOUND); + isMopStr = true; + break; + case MOP_wstrh: + isInRange = + (immVal >= STRALL_LDRALL_IMM_LOWER_BOUND && immVal <= STRH_LDRH_IMM_UPPER_BOUND); + isMopStr = true; + break; + case MOP_vstr: + isInRange = + (immVal >= STRALL_LDRALL_IMM_LOWER_BOUND && immVal <= STRH_LDRH_IMM_UPPER_BOUND); + isMopStr = true; + break; + default: + isMopStr = false; + break; + } + if (isInRange || !isMopStr) { + curbb->AppendInsn(cg->BuildInstruction(strmop, src, dest)); + } else { + RegOperand *immreg = CreateRegisterOperandOfType(PTY_i64); + curbb->AppendInsn(cg->BuildInstruction(MOP_xmovri64, immreg, imopnd)); + RegOperand *basereg = CreateRegisterOperandOfType(PTY_i64); + curbb->AppendInsn(cg->BuildInstruction(MOP_xaddrrr, basereg, mopnd->GetBaseRegister(), immreg)); + MemOperand *newDest = GetOrCreateMemOpnd(GetPrimTypeBitSize(dtype), + basereg, nullptr, GetOrCreateOfstOpnd(0, 32), + static_cast(nullptr)); + curbb->AppendInsn(cg->BuildInstruction(strmop, src, newDest)); + } + } else { + curbb->AppendInsn(cg->BuildInstruction(strmop, src, dest)); + } + } else { + Riscv64CGFunc::SelectStoreRelease(dest, dtype, src, stype, mo, true); + } + } else { + CG_ASSERT(stype != PTY_a32, ""); + curbb->AppendInsn(cg->BuildInstruction(PickMovInsn(static_cast(dest), static_cast(src)), dest, src)); + } + } break; + + default: + CG_ASSERT(false, "NYI"); + } +} + +// This function copies src to a register, the src can be an imm, mem or a label +RegOperand *Riscv64CGFunc::SelectCopy(Operand *src, PrimType stype, PrimType dtype) { + RegOperand *dest = CreateRegisterOperandOfType(dtype); + SelectCopy(dest, dtype, src, stype); + return dest; +} + +Operand *Riscv64CGFunc::SelectIgoto(Operand *opnd0) { + if (opnd0->GetKind() == Operand::Opd_Mem) { + regno_t vRegNo = New_V_Reg(kRegTyInt, 8); + Operand *dst = CreateVirtualRegisterOperand(vRegNo); + curbb->AppendInsn(cg->BuildInstruction(MOP_xldr, dst, opnd0)); + return dst; + } + return opnd0; +} + +/* + We need to adjust the offset of a stack allocated local variable + if we store FP/SP before any other local variables to save an instruction. + See Riscv64CGFunc::OffsetAdjustmentForFPLR() in riscv64_cg_func.cpp + + That is when we ShouldSaveFPLR() and !UsedStpSubPairForCallFrameAllocation(). + + Because we need to use the STP/SUB instruction pair to store FP/SP 'after' + local variables when the call frame size is greater that the max offset + value allowed for the STP instruction (we cannot use STP w/ prefix, LDP w/ + postfix), if UsedStpSubPairForCallFrameAllocation(), we don't need to + adjust the offsets. + */ +bool Riscv64CGFunc::IsImmediateOffsetOutOfRange(Riscv64MemOperand *mo, uint32 bitlen) { + CG_ASSERT(8 <= bitlen && bitlen <= 64 && (bitlen & (bitlen - 1)) == 0, ""); + int32 offsetValue = mo->GetOffsetImmediate()->GetOffsetValue(); + if (mo->GetOffsetImmediate()->IsVary()) { + offsetValue += static_cast(memlayout)->RealStackFrameSize() + 0xff; + } + offsetValue += 2 * kIntregBytelen; // Refer to the above comment + return Riscv64MemOperand::IsPIMMOffsetOutOfRange(offsetValue, bitlen); +} + +Riscv64MemOperand *Riscv64CGFunc::CreateReplacementMemOperand(Riscv64MemOperand *mo, uint32 bitlen, RegOperand *basereg, + int32 offset) { + return static_cast(CreateMemOpnd(basereg, offset, bitlen)); +} + +Riscv64MemOperand *Riscv64CGFunc::SplitOffsetWithAddInstruction(Riscv64MemOperand *mo, uint32 bitlen, + Riscv64reg_t baseregNum, Insn *insn, bool isDest) { + Riscv64OfstOperand *oo = mo->GetOffsetImmediate(); + int32 ov = oo->GetOffsetValue(); + + // li reg = offsetValue + // add reg = sp + reg + // load/store val -> [reg] + RegOperand *resopnd; + if (isAfterRegAlloc) { + resopnd = GetOrCreatePhysicalRegisterOperand(Riscv64Abi::kIntSpareReg, (bitlen <= 32) ? 4 : 8, kRegTyInt); + } else { + resopnd = CreateRegisterOperandOfType(PTY_a64); + } + Riscv64ImmOperand *immOpnd = CreateImmOperand(ov, 8, false); + if (mo->GetOffsetImmediate()->IsVary()) { + immOpnd->SetVary(true); + } + Insn *immInsn = cg->BuildInstruction(MOP_xmovri64, resopnd, immOpnd); + RegOperand *baseOpnd = mo->GetBaseRegister(); + Insn *addInsn = cg->BuildInstruction(MOP_xaddrrr, resopnd, baseOpnd, resopnd); + if (insn) { + if (isDest) { + insn->bb->InsertInsnAfter(insn, addInsn); + insn->bb->InsertInsnAfter(insn, immInsn); + } else { + insn->bb->InsertInsnBefore(insn, immInsn); + insn->bb->InsertInsnBefore(insn, addInsn); + } + } else { + curbb->AppendInsn(immInsn); + curbb->AppendInsn(addInsn); + } + + MemOperand *newMemOpnd = CreateMemOpnd(resopnd, 0, bitlen); + Riscv64MemOperand *retMopnd = dynamic_cast(newMemOpnd); + retMopnd->SetStackMem(mo->IsStackMem()); + return retMopnd; +} + +Riscv64MemOperand *Riscv64CGFunc::SplitStpLdpOffsetForCalleeSavedWithAddInstruction(Riscv64MemOperand *mo, + uint32 bitlen, + Riscv64reg_t baseregNum) { + Riscv64OfstOperand *oo = mo->GetOffsetImmediate(); + int32 ov = oo->GetOffsetValue(); + CG_ASSERT(ov > 0 && ((ov & 0x7) == 0), ""); + // if( ShouldSaveFPLR() ) + // ov += 2 * kIntregBytelen; // we need to adjust the offset by length(FP/SP) + // Offset adjustment due to FP/SP has already been done + // in Riscv64CGFunc::GeneratePushRegs() and Riscv64CGFunc::GeneratePopRegs() + Riscv64RegOperand *br = GetOrCreatePhysicalRegisterOperand(baseregNum, bitlen, kRegTyInt); + if (split_stpldp_base_offset == 0) { + split_stpldp_base_offset = ov; // remember the offset; don't forget to clear it + ImmOperand *immAddend = CreateImmOperand(ov, 64, true); + RegOperand *origBasereg = mo->GetBaseRegister(); + SelectAdd(br, origBasereg, immAddend, PTY_i64); + } + ov = ov - split_stpldp_base_offset; + return CreateReplacementMemOperand(mo, bitlen, br, ov); +} + +void Riscv64CGFunc::SelectDassign(DassignNode *stmt, Operand *opnd0) { + SelectDassign(stmt->stIdx, stmt->fieldID, stmt->GetRhs()->primType, opnd0); +} + +// NOTE: I divided SelectDassign so that we can create "virtual" assignments +// when selecting other complex Maple IR instructions. For example, the atomic +// exchange and other intrinsics will need to assign its results to local +// variables. Such Maple IR instructions are pltform-specific (e.g. +// atomic_exchange can be implemented as one single machine intruction on x86_64 +// and ARMv8.1, but ARMv8.0 needs an LL/SC loop), therefore they cannot (in +// principle) be lowered at BELowerer or CGLowerer. +void Riscv64CGFunc::SelectDassign(StIdx stIdx, FieldID fieldID, PrimType rhsPtyp, Operand *opnd0) { + MIRSymbol *symbol = mirModule.CurFunction()->GetLocalOrGlobalSymbol(stIdx); + int32 offset = 0; + bool parmCopy = false; + if (fieldID != 0) { + MIRStructType *structty = static_cast(symbol->GetType()); + CG_ASSERT(structty, "SelectDassign: non-zero fieldID for non-structure"); + offset = becommon.GetFieldOffset(structty, fieldID).first; + parmCopy = IsParamStructCopy(symbol); + } + int regsize = GetPrimTypeBitSize(rhsPtyp); + MIRType *type = symbol->GetType(); + Operand *stOpnd = LoadIntoRegister(opnd0, IsPrimitiveInteger(rhsPtyp), regsize, IsSignedInteger(type->GetPrimType())); + MOperator mop = MOP_undef; + if (type->typeKind == kTypeStruct || type->typeKind == kTypeUnion) { + MIRStructType *structType = static_cast(type); + TyIdx ftyidx = structType->TraverseToField(fieldID).second.first; + type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(ftyidx); + } else if (type->typeKind == kTypeClass) { + MIRClassType *classType = static_cast(type); + TyIdx ftyidx = classType->TraverseToField(fieldID).second.first; + type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(ftyidx); + } + + int datasize = GetPrimTypeBitSize(type->GetPrimType()); + if (type->GetPrimType() == PTY_agg) { + datasize = GetPrimTypeBitSize(PTY_a64); + } + MemOperand *memopnd; + if (parmCopy) { + memopnd = LoadStructCopyBase(symbol, offset, datasize); + } else { + memopnd = GetOrCreateMemOpnd(symbol, offset, datasize); + } + CHECK_FATAL(memopnd != nullptr && static_cast(memopnd) != nullptr, + "pointer is null in Riscv64CGFunc::SelectDassign"); + if (IsImmediateOffsetOutOfRange(static_cast(memopnd), datasize)) { + memopnd = SplitOffsetWithAddInstruction(static_cast(memopnd), datasize); + } + + MIRTypeKind tyKind = type->typeKind; + CG_ASSERT((tyKind == kTypeScalar || tyKind == kTypePointer || tyKind == kTypeStruct || tyKind == kTypeArray), + "NYI dassign type"); + PrimType primType = type->GetPrimType(); + if (primType == PTY_agg) { + if (static_cast(stOpnd)->IsOfIntClass()) { + primType = PTY_a64; + } else { + primType = PTY_f64; + } + } + + Riscv64isa::memory_ordering_t mo = Riscv64isa::kMoNone; + MIRSymbol *sym = static_cast(memopnd)->GetSymbol(); + if (sym && sym->GetStorageClass() == kScGlobal && isVolStore) { + mo = Riscv64isa::kMoRelease; + isVolStore = false; + } + Insn *insn = nullptr; + if (mo == Riscv64isa::kMoNone) { + mop = PickStInsn(GetPrimTypeBitSize(primType), primType); + insn = cg->BuildInstruction(mop, stOpnd, memopnd); + + if (cg->GenerateVerboseAsm()) { + MIRSymbol *sym = static_cast(memopnd)->GetSymbol(); + if (sym) { + std::string key; + MIRStorageClass sc = sym->GetStorageClass(); + if (sc == kScFormal) { + key = "param: "; + } else if (sc == kScAuto) { + key = "local var: "; + } else { + key = "global: "; + } + insn->AddComment(key.append(sym->GetName())); + } + } + + curbb->AppendInsn(insn); + } else { + Riscv64CGFunc::SelectStoreRelease(memopnd, primType, stOpnd, primType, mo, true); + } +} + +void Riscv64CGFunc::SelectAssertnull(UnaryStmtNode *stmt) { + Operand *opnd0 = HandleExpr(stmt, stmt->uOpnd); + RegOperand *basereg = LoadIntoRegister(opnd0, PTY_a64); + auto &zwr = Riscv64RegOperand::Get32bitZeroRegister(); + auto *mem = CreateMemOpnd(basereg, 0, 32); + Insn *loadref = cg->BuildInstruction(MOP_wldr, &zwr, mem); + loadref->do_not_remove = true; + if (cg->GenerateVerboseAsm()) { + loadref->AddComment("null pointer check"); + } + curbb->AppendInsn(loadref); +} + +void Riscv64CGFunc::SelectRegassign(RegassignNode *stmt, Operand *opnd0) { + RegOperand *regopnd = nullptr; + PregIdx pregidx = stmt->regIdx; + + if (IsSpecialPseudoRegister(pregidx)) { + // if it is one of special registers + CG_ASSERT(-pregidx != kSregRetval0, ""); + regopnd = GetOrCreateSpecialRegisterOperand(-pregidx); + } else { + regopnd = GetOrCreateVirtualRegisterOperand(GetVirtualRegNoFromPseudoRegIdx(pregidx)); + } + // look at rhs + PrimType rhstype = stmt->uOpnd->primType; + PrimType dtype = rhstype; + if (GetPrimTypeBitSize(dtype) < 32) { + CG_ASSERT(IsPrimitiveInteger(dtype), ""); + dtype = IsSignedInteger(dtype) ? PTY_i32 : PTY_u32; + } + SelectCopy(regopnd, dtype, opnd0, rhstype); + + if (g->optim_level == 0 && pregidx >= 0) { + MemOperand *dest = GetPseudoRegisterSpillMemoryOperand(pregidx); + PrimType stype = GetTypeFromPseudoRegIdx(pregidx); + MIRPreg *preg = func->pregTab->PregFromPregIdx(pregidx); + uint32_t srcbitlen = GetPrimTypeSize(preg->primType) * BITS_PER_BYTE; + curbb->AppendInsn(cg->BuildInstruction(PickStInsn(srcbitlen, stype), regopnd, dest)); + } + if (mirModule.IsCModule() && g->optim_level > 0 && pregidx >= 0) { + // Here it is assumed both lhs and rhs are of the same signed/unsigned type. + // Otherwise, IR is missing a conversion. + PrimType lhstype = stmt->primType; + uint32 rhssize = GetPrimTypeBitSize(rhstype); + uint32 lhssize = GetPrimTypeBitSize(lhstype); + MOperator mop = MOP_undef; + if (rhssize > lhssize) { + switch (lhstype) { + case PTY_i8: + GenerateSext(regopnd, regopnd, lhstype, 8); + return; + case PTY_i16: + GenerateSext(regopnd, regopnd, lhstype, 16); + return; + case PTY_i32: + mop = MOP_xsxtw64; + break; + case PTY_u8: + GenerateZext(regopnd, regopnd, lhstype, 8); + return; + case PTY_u16: + GenerateZext(regopnd, regopnd, lhstype, 16); + return; + case PTY_u32: + GenerateZext(regopnd, regopnd, lhstype, 32); + break; + default: + CHECK_FATAL(0,"Unsupported primtype"); + } + curbb->AppendInsn(cg->BuildInstruction(mop, regopnd, regopnd)); + } if (lhssize > rhssize) { + switch (rhstype) { + case PTY_i8: + //mop = MOP_xsxtb64; + GenerateSext(regopnd, regopnd, lhstype, 8); + return; + case PTY_i16: + //mop = MOP_xsxth64; + GenerateSext(regopnd, regopnd, lhstype, 16); + return; + case PTY_i32: + mop = MOP_xsxtw64; + break; + case PTY_u8: + //mop = MOP_xuxtb32; + GenerateZext(regopnd, regopnd, lhstype, 8); + return; + case PTY_u16: + //mop = MOP_xuxth32; + GenerateZext(regopnd, regopnd, lhstype, 16); + return; + case PTY_u32: + GenerateZext(regopnd, regopnd, lhstype, 32); + break; + default: + CHECK_FATAL(0,"Unsupported primtype"); + } + curbb->AppendInsn(cg->BuildInstruction(mop, regopnd, regopnd)); + } + } +} + +void Riscv64CGFunc::SelectAggDassign(DassignNode *stmt) { + MIRSymbol *lhssymbol = mirModule.CurFunction()->GetLocalOrGlobalSymbol(stmt->stIdx); + int32 lhsoffset = 0; + MIRType *lhsty = lhssymbol->GetType(); + if (stmt->fieldID != 0) { + MIRStructType *structty = static_cast(lhsty); + CG_ASSERT(structty, "SelectDassign: non-zero fieldID for non-structure"); + FieldPair thepair = structty->TraverseToField(stmt->fieldID); + lhsty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(thepair.second.first); + lhsoffset = becommon.GetFieldOffset(structty, stmt->fieldID).first; + } + uint32 lhsalign = becommon.type_align_table[lhsty->tyIdx.GetIdx()]; + uint32 stAlign = becommon.type_natural_align_table[lhsty->tyIdx.GetIdx()]; + if (stAlign && stAlign < lhsalign) { + lhsalign = stAlign; + } + uint32 lhssize = becommon.type_size_table.at(lhsty->tyIdx.GetIdx()); + + uint32 rhsalign; + uint32 alignused; + int32 rhsoffset = 0; + if (stmt->GetRhs()->op == OP_dread) { + AddrofNode *rhsdread = static_cast(stmt->GetRhs()); + MIRSymbol *rhssymbol = mirModule.CurFunction()->GetLocalOrGlobalSymbol(rhsdread->stIdx); + MIRType *rhsty = rhssymbol->GetType(); + if (rhsdread->fieldID != 0) { + MIRStructType *structty = static_cast(rhsty); + CG_ASSERT(structty, "SelectDassign: non-zero fieldID for non-structure"); + FieldPair thepair = structty->TraverseToField(rhsdread->fieldID); + rhsty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(thepair.second.first); + rhsoffset = becommon.GetFieldOffset(structty, rhsdread->fieldID).first; + } + rhsalign = becommon.type_align_table[rhsty->tyIdx.GetIdx()]; + uint32 stAlign = becommon.type_natural_align_table[rhsty->tyIdx.GetIdx()]; + if (stAlign && stAlign < rhsalign) { + rhsalign = stAlign; + } + + // arm64 can handle unaligned memory access, so there is + // is no need to split it into smaller accesses. + bool parmCopy = IsParamStructCopy(rhssymbol); + alignused = std::min(lhsalign, rhsalign); + Operand *rhsmemopnd = nullptr; + Operand *lhsmemopnd = nullptr; + for (uint32 i = 0; i < (lhssize / alignused); i++) { + // generate the load + if (parmCopy) { + rhsmemopnd = LoadStructCopyBase(rhssymbol, rhsoffset + i * alignused, alignused * BITS_PER_BYTE); + } else { + rhsmemopnd = GetOrCreateMemOpnd(rhssymbol, rhsoffset + i * alignused, alignused * BITS_PER_BYTE); + } + regno_t vRegNo = New_V_Reg(kRegTyInt, std::max(4u, alignused)); + RegOperand *result = CreateVirtualRegisterOperand(vRegNo); + curbb->AppendInsn(cg->BuildInstruction(PickLdInsn(alignused * 8, PTY_u32), result, rhsmemopnd)); + if (IsImmediateOffsetOutOfRange(static_cast(rhsmemopnd), alignused * 8)) { + curbb->lastinsn->opnds[1] = + SplitOffsetWithAddInstruction(static_cast(rhsmemopnd), alignused * 8, kRinvalid, curbb->lastinsn); + } + // generate the store + if (lhssymbol->storageClass == kScFormal && becommon.type_size_table[lhssymbol->tyIdx.GetIdx()] > 16) { + // formal of size of greater than 16 is copied by the caller and the pointer to it is passed. + // otherwise it is passed in register and is accessed directly. + RegOperand *vreg; + lhsmemopnd = GetOrCreateMemOpnd(lhssymbol, 0, alignused * BITS_PER_BYTE); + vreg = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + Insn *ldInsn = cg->BuildInstruction(PickLdInsn(64, PTY_i64), vreg, lhsmemopnd); + curbb->AppendInsn(ldInsn); + lhsmemopnd = GetOrCreateMemOpnd(64, vreg, nullptr, + GetOrCreateOfstOpnd(lhsoffset + i * alignused, 32), static_cast(nullptr)); + } else { + lhsmemopnd = GetOrCreateMemOpnd(lhssymbol, lhsoffset + i * alignused, alignused * 8); + } + curbb->AppendInsn(cg->BuildInstruction(PickStInsn(alignused * 8, PTY_u32), result, lhsmemopnd)); + if (IsImmediateOffsetOutOfRange(static_cast(lhsmemopnd), alignused * 8)) { + curbb->lastinsn->opnds[1] = + SplitOffsetWithAddInstruction(static_cast(lhsmemopnd), alignused * 8, kRinvalid, curbb->lastinsn); + } + } + // take care of extra content at the end less than the unit of alignused + uint32 lhssizeCovered = (lhssize / alignused) * alignused; + uint32 newalignused = alignused; + while (lhssizeCovered < lhssize) { + newalignused = newalignused >> 1; + if (lhssizeCovered + newalignused > lhssize) { + continue; + } + // generate the load + rhsmemopnd = GetOrCreateMemOpnd(rhssymbol, rhsoffset + lhssizeCovered, newalignused * 8); + regno_t vRegNo = New_V_Reg(kRegTyInt, std::max(4u, newalignused)); + RegOperand *result = CreateVirtualRegisterOperand(vRegNo); + curbb->AppendInsn(cg->BuildInstruction(PickLdInsn(newalignused * 8, PTY_u32), result, rhsmemopnd)); + if (IsImmediateOffsetOutOfRange(static_cast(rhsmemopnd), newalignused * 8)) { + curbb->lastinsn->opnds[1] = + SplitOffsetWithAddInstruction(static_cast(rhsmemopnd), newalignused * 8, kRinvalid, curbb->lastinsn); + } + // generate the store + if (lhssymbol->storageClass == kScFormal && becommon.type_size_table[lhssymbol->tyIdx.GetIdx()] > 16) { + RegOperand *vreg; + lhsmemopnd = GetOrCreateMemOpnd(lhssymbol, 0, newalignused * BITS_PER_BYTE); + vreg = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + Insn *ldInsn = cg->BuildInstruction(PickLdInsn(64, PTY_i64), vreg, lhsmemopnd); + curbb->AppendInsn(ldInsn); + lhsmemopnd = GetOrCreateMemOpnd(64, vreg, nullptr, + GetOrCreateOfstOpnd(lhsoffset + lhssizeCovered, 32), static_cast(nullptr)); + } else { + lhsmemopnd = GetOrCreateMemOpnd(lhssymbol, lhsoffset + lhssizeCovered, newalignused * 8); + } + curbb->AppendInsn(cg->BuildInstruction(PickStInsn(newalignused * 8, PTY_u32), result, lhsmemopnd)); + lhssizeCovered += newalignused; + if (IsImmediateOffsetOutOfRange(static_cast(lhsmemopnd), newalignused * 8)) { + curbb->lastinsn->opnds[1] = + SplitOffsetWithAddInstruction(static_cast(lhsmemopnd), newalignused * 8, kRinvalid, curbb->lastinsn); + } + } + } else if (stmt->GetRhs()->op == OP_iread) { // rhs is iread + IreadNode *rhsiread = static_cast(stmt->GetRhs()); + RegOperand *addropnd = static_cast(HandleExpr(rhsiread, rhsiread->Opnd(0))); + addropnd = LoadIntoRegister(addropnd, rhsiread->Opnd(0)->primType); + MIRPtrType *rhspointerty = static_cast(GlobalTables::GetTypeTable().GetTypeFromTyIdx(rhsiread->tyIdx)); + MIRType *rhsty = static_cast(GlobalTables::GetTypeTable().GetTypeFromTyIdx(rhspointerty->pointedTyIdx)); + bool isRefField = false; + if (rhsiread->fieldID != 0) { + MIRStructType *rhsstructty = static_cast(rhsty); + CG_ASSERT(rhsstructty, "SelectAggDassign: non-zero fieldID for non-structure"); + FieldPair thepair = rhsstructty->TraverseToField(rhsiread->fieldID); + rhsty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(thepair.second.first); + rhsoffset = becommon.GetFieldOffset(rhsstructty, rhsiread->fieldID).first; + isRefField = becommon.IsRefField(rhsstructty, rhsiread->fieldID); + } + + rhsalign = becommon.type_align_table[rhsty->tyIdx.GetIdx()]; + uint32 stAlign = becommon.type_natural_align_table[rhsty->tyIdx.GetIdx()]; + if (stAlign && stAlign < rhsalign) { + rhsalign = stAlign; + } + + if (lhsalign == 0 || rhsalign == 0) { + // workaround for IR where rhs alignment cannot be determined. + alignused = lhsalign == 0 ? rhsalign : (rhsalign == 0 ? lhsalign :0); + CG_ASSERT(alignused, ""); // both cannot be 0? + } else { + alignused = std::min(lhsalign, rhsalign); + } + Operand *rhsmemopnd = nullptr; + Operand *lhsmemopnd = nullptr; + for (uint32 i = 0; i < (lhssize / alignused); i++) { + // generate the load + Riscv64OfstOperand *offopnd = GetOrCreateOfstOpnd(rhsoffset + i * alignused, 32); + rhsmemopnd = GetOrCreateMemOpnd(alignused * 8, addropnd, nullptr, offopnd, + static_cast(nullptr)); + regno_t vRegNo = New_V_Reg(kRegTyInt, std::max(4u, alignused)); + RegOperand *result = CreateVirtualRegisterOperand(vRegNo); + Insn *insn = cg->BuildInstruction(PickLdInsn(alignused * 8, PTY_u32), result, rhsmemopnd); + insn->MarkAsAccessRefField(isRefField); + curbb->AppendInsn(insn); + if (IsImmediateOffsetOutOfRange(static_cast(rhsmemopnd), alignused * 8)) { + curbb->lastinsn->opnds[1] = + SplitOffsetWithAddInstruction(static_cast(rhsmemopnd), alignused * 8, kRinvalid, curbb->lastinsn); + } + // generate the store + if (lhssymbol->storageClass == kScFormal && becommon.type_size_table[lhssymbol->tyIdx.GetIdx()] > 16) { + RegOperand *vreg; + lhsmemopnd = GetOrCreateMemOpnd(lhssymbol, 0, alignused * BITS_PER_BYTE); + vreg = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + Insn *ldInsn = cg->BuildInstruction(PickLdInsn(64, PTY_i64), vreg, lhsmemopnd); + curbb->AppendInsn(ldInsn); + lhsmemopnd = GetOrCreateMemOpnd(64, vreg, nullptr, + GetOrCreateOfstOpnd(lhsoffset + i * alignused, 32), static_cast(nullptr)); + } else { + lhsmemopnd = GetOrCreateMemOpnd(lhssymbol, lhsoffset + i * alignused, alignused * 8); + } + curbb->AppendInsn(cg->BuildInstruction(PickStInsn(alignused * 8, PTY_u32), result, lhsmemopnd)); + if (IsImmediateOffsetOutOfRange(static_cast(lhsmemopnd), alignused * 8)) { + curbb->lastinsn->opnds[1] = + SplitOffsetWithAddInstruction(static_cast(lhsmemopnd), alignused * 8, kRinvalid, curbb->lastinsn); + } + } + // take care of extra content at the end less than the unit of alignused + uint32 lhssizeCovered = (lhssize / alignused) * alignused; + uint32 newalignused = alignused; + while (lhssizeCovered < lhssize) { + newalignused = newalignused >> 1; + if (lhssizeCovered + newalignused > lhssize) { + continue; + } + // generate the load + Riscv64OfstOperand *offopnd = GetOrCreateOfstOpnd(rhsoffset + lhssizeCovered, 32); + rhsmemopnd = GetOrCreateMemOpnd(newalignused * 8, addropnd, nullptr, offopnd, + static_cast(nullptr)); + regno_t vRegNo = New_V_Reg(kRegTyInt, std::max(4u, newalignused)); + RegOperand *result = CreateVirtualRegisterOperand(vRegNo); + Insn *insn = cg->BuildInstruction(PickLdInsn(newalignused * 8, PTY_u32), result, rhsmemopnd); + insn->MarkAsAccessRefField(isRefField); + curbb->AppendInsn(insn); + if (IsImmediateOffsetOutOfRange(static_cast(rhsmemopnd), newalignused * 8)) { + curbb->lastinsn->opnds[1] = + SplitOffsetWithAddInstruction(static_cast(rhsmemopnd), newalignused * 8, kRinvalid, curbb->lastinsn); + } + // generate the store + if (lhssymbol->storageClass == kScFormal && becommon.type_size_table[lhssymbol->tyIdx.GetIdx()] > 16) { + RegOperand *vreg; + lhsmemopnd = GetOrCreateMemOpnd(lhssymbol, 0, newalignused * BITS_PER_BYTE); + vreg = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, 8)); + Insn *ldInsn = cg->BuildInstruction(PickLdInsn(64, PTY_i64), vreg, lhsmemopnd); + curbb->AppendInsn(ldInsn); + lhsmemopnd = GetOrCreateMemOpnd(64, vreg, nullptr, + GetOrCreateOfstOpnd(lhsoffset + lhssizeCovered, 32), static_cast(nullptr)); + } else { + lhsmemopnd = GetOrCreateMemOpnd(lhssymbol, lhsoffset + lhssizeCovered, newalignused * 8); + } + curbb->AppendInsn(cg->BuildInstruction(PickStInsn(newalignused * 8, PTY_u32), result, lhsmemopnd)); + lhssizeCovered += newalignused; + if (IsImmediateOffsetOutOfRange(static_cast(lhsmemopnd), newalignused * 8)) { + curbb->lastinsn->opnds[1] = + SplitOffsetWithAddInstruction(static_cast(lhsmemopnd), newalignused * 8, kRinvalid, curbb->lastinsn); + } + } + } else { + CG_ASSERT(stmt->GetRhs()->op == OP_regread, "SelectAggDassign: NYI"); + bool isRet = false; + if (lhsty->typeKind == kTypeStruct || lhsty->typeKind == kTypeUnion) { + RegreadNode *rhsregread = static_cast(stmt->GetRhs()); + PregIdx pregidx = rhsregread->regIdx; + if (IsSpecialPseudoRegister(pregidx)) { + pregidx = GetSpecialPseudoRegisterIndex(pregidx); + if (pregidx == kSregRetval0) { + ParmLocator parmlocator(becommon); + PLocInfo ploc; + PrimType retpty; + RegType regtype; + uint32 memsize; + uint32 regsize; + parmlocator.LocateRetValue(lhsty, ploc); + Riscv64reg_t r[4]; + r[0] = ploc.reg0; + r[1] = ploc.reg1; + uint32 sizes[2]; + sizes[0] = ploc.rsize0; + sizes[1] = ploc.rsize1; + for (uint32 i = 0; i < 2; ++i) { + if (r[i] == kRinvalid) { + break; + } + if (r[i] >= V10) { + regsize = (sizes[i] == 4) ? 32 : 64; + memsize = sizes[i]; + retpty = (sizes[i] == 4) ? PTY_f32 : PTY_f64; + regtype = kRegTyFloat; + } else { + regsize = 64; + memsize = 8; + retpty = PTY_u64; + regtype = kRegTyInt; + } + RegOperand *parm = GetOrCreatePhysicalRegisterOperand(r[i], regsize, regtype); + Operand *memopnd = GetOrCreateMemOpnd(lhssymbol, memsize * i, regsize); + curbb->AppendInsn(cg->BuildInstruction(PickStInsn(regsize, retpty), parm, memopnd)); + if (IsImmediateOffsetOutOfRange(static_cast(memopnd), regsize)) { + curbb->lastinsn->opnds[1] = + SplitOffsetWithAddInstruction(static_cast(memopnd), regsize * 8, kRinvalid, curbb->lastinsn); + } + } + isRet = true; + } + } + } + CHECK_FATAL(isRet, "SelectAggDassign: NYI"); + } +} + +static MIRType *GetPointedToType(MIRPtrType *pointerty) { + MIRType *atype = GlobalTables::GetTypeTable().GetTypeFromTyIdx(pointerty->pointedTyIdx); + if (atype->GetKind() == kTypeArray) { + MIRArrayType *arraytype = static_cast(atype); + return GlobalTables::GetTypeTable().GetTypeFromTyIdx(arraytype->eTyIdx); + } + if (atype->GetKind() == kTypeFArray || atype->GetKind() == kTypeJArray) { + MIRFarrayType *farraytype = static_cast(atype); + return GlobalTables::GetTypeTable().GetTypeFromTyIdx(farraytype->elemTyIdx); + } + return atype; +} + +void Riscv64CGFunc::SelectIassign(IassignNode *stmt) { + int32 offset = 0; + MIRPtrType *pointerty = static_cast(GlobalTables::GetTypeTable().GetTypeFromTyIdx(stmt->tyIdx)); + CG_ASSERT(pointerty, "expect a pointer type at iassign node"); + MIRType *pointedType = nullptr; + bool isRefField = false; + Riscv64isa::memory_ordering_t mo = Riscv64isa::kMoNone; + + if (stmt->fieldID != 0) { + MIRType *pointedty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(pointerty->pointedTyIdx); + MIRStructType *structty = nullptr; + if (pointedty->GetKind() != kTypeJArray) { + structty = static_cast(pointedty); + CG_ASSERT(structty, "SelectIassign: non-zero fieldID for non-structure"); + } else { + // it's a Jarray type. using it's parent's field info: java.lang.Object + structty = static_cast(pointedty)->GetParentType(); + } + CG_ASSERT(structty, "SelectIassign: non-zero fieldID for non-structure"); + FieldPair thepair = structty->TraverseToField(stmt->fieldID); + pointedType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(thepair.second.first); + offset = becommon.GetFieldOffset(structty, stmt->fieldID).first; + isRefField = becommon.IsRefField(structty, stmt->fieldID); + } else { + pointedType = GetPointedToType(pointerty); + if (func->IsJava() && (pointedType->GetKind() == kTypePointer)) { + MIRType *nextPointedType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(static_cast(pointedType)->pointedTyIdx); + if (nextPointedType->GetKind() != kTypeScalar) { + isRefField = true; // write into an object array or a high-dimensional array + } + } + } + + PrimType styp = stmt->rhs->primType; + Operand *valopnd = HandleExpr(stmt, stmt->rhs); + PrimType destType = pointedType->GetPrimType(); + if (IsPrimitiveVector(styp)) { + CG_ASSERT(stmt->fieldID == 0, "NYI"); + MemOperand *memopnd = CreateMemOpnd(styp, stmt, stmt->addrExpr, offset); + SelectCopy(memopnd, styp, valopnd, styp); + return; + } + Operand *srcOpnd = LoadIntoRegister(valopnd, IsPrimitiveInteger(styp), GetPrimTypeBitSize(styp)); + + if (destType == PTY_agg) { + destType = PTY_a64; + } + + MemOperand *memopnd = CreateMemOpnd(destType, stmt, stmt->addrExpr, offset); + if (IsImmediateOffsetOutOfRange(static_cast(memopnd), GetPrimTypeBitSize(destType))) { + memopnd = SplitOffsetWithAddInstruction(static_cast(memopnd), GetPrimTypeBitSize(destType)); + } + if (isVolStore) { + mo = Riscv64isa::kMoRelease; + isVolStore = false; + } + + if (mo == Riscv64isa::kMoNone) { + SelectCopy(memopnd, destType, srcOpnd, destType); + } else { + Riscv64CGFunc::SelectStoreRelease(memopnd, destType, srcOpnd, destType, mo, false); + } + curbb->lastinsn->MarkAsAccessRefField(isRefField); +} + +void Riscv64CGFunc::SelectAggIassign(IassignNode *stmt, Operand *lhsaddropnd) { + MIRType *stmtty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(stmt->tyIdx); + MIRPtrType *lhspointerty; + MIRSymbol *addrsym; + if (stmtty->primType == PTY_agg) { + // Move into regs. + AddrofNode *addrofnode = dynamic_cast(stmt->addrExpr); + addrsym = mirModule.CurFunction()->GetLocalOrGlobalSymbol(addrofnode->stIdx); + MIRType *addrty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(addrsym->tyIdx); + lhspointerty = static_cast(GlobalTables::GetTypeTable().GetTypeFromTyIdx(addrty->tyIdx)); + } else { + lhsaddropnd = LoadIntoRegister(lhsaddropnd, stmt->addrExpr->primType); + lhspointerty = static_cast(GlobalTables::GetTypeTable().GetTypeFromTyIdx(stmt->tyIdx)); + } + int32 lhsoffset = 0; + MIRType *lhsty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(lhspointerty->pointedTyIdx); + if (stmt->fieldID != 0) { + MIRStructType *structty = static_cast(lhsty); + CG_ASSERT(structty, "SelectAggIassign: non-zero fieldID for non-structure"); + FieldPair thepair = structty->TraverseToField(stmt->fieldID); + lhsty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(thepair.second.first); + lhsoffset = becommon.GetFieldOffset(structty, stmt->fieldID).first; + } else if (MIRArrayType *arraylhsty = dynamic_cast(lhsty)) { + // access an array element + lhsty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(arraylhsty->eTyIdx); + MIRTypeKind tykind = lhsty->typeKind; + CG_ASSERT((tykind == kTypeScalar || tykind == kTypeStruct || tykind == kTypeClass || tykind == kTypePointer), + "unexpected array element type in iassign"); + } else if (MIRFarrayType *farraylhsty = dynamic_cast(lhsty)) { + // access an array element + lhsty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(farraylhsty->elemTyIdx); + MIRTypeKind tykind = lhsty->typeKind; + CG_ASSERT((tykind == kTypeScalar || tykind == kTypeStruct || tykind == kTypeClass || tykind == kTypePointer), + "unexpected array element type in iassign"); + } + + uint32 lhsalign = becommon.type_align_table[lhsty->tyIdx.GetIdx()]; + uint32 stAlign = becommon.type_natural_align_table[lhsty->tyIdx.GetIdx()]; + if (stAlign && stAlign < lhsalign) { + lhsalign = stAlign; + } + uint32 lhssize = becommon.type_size_table.at(lhsty->tyIdx.GetIdx()); + + uint32 rhsalign; + uint32 alignused; + int32 rhsoffset = 0; + if (stmt->rhs->op == OP_dread) { + AddrofNode *rhsdread = static_cast(stmt->rhs); + MIRSymbol *rhssymbol = mirModule.CurFunction()->GetLocalOrGlobalSymbol(rhsdread->stIdx); + MIRType *rhsty = rhssymbol->GetType(); + if (rhsdread->fieldID != 0) { + MIRStructType *structty = static_cast(rhssymbol->GetType()); + CG_ASSERT(structty, "SelectDassign: non-zero fieldID for non-structure"); + FieldPair thepair = structty->TraverseToField(rhsdread->fieldID); + rhsty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(thepair.second.first); + rhsoffset = becommon.GetFieldOffset(structty, rhsdread->fieldID).first; + } + if (stmtty->primType == PTY_agg) { + // generate move to regs. + CHECK_FATAL(lhssize <= 16, "SelectAggIassign: illegal struct size"); + ParmLocator parmlocator(becommon); + PLocInfo ploc; + MIRSymbol *retst = becommon.mirModule.CurFunction()->formalDefVec[0].formalSym; + if (retst == addrsym) { + // return value + parmlocator.LocateNextParm(lhsty, ploc, true); + } else { + parmlocator.InitPlocInfo(ploc); + } + + // aggregates are 8 byte aligned. + Operand *rhsmemopnd = nullptr; + RegOperand *result[2]; + uint32 loadSize; + RegType regtype; + PrimType retpty; + bool fpParm = false; + bool parmCopy = IsParamStructCopy(rhssymbol); + Riscv64reg_t regs[2]; + regs[0] = ploc.reg0; + regs[1] = ploc.reg1; + uint32 num = 0; + if (regs[0] != kRinvalid) { + num = regs[1] != kRinvalid ? 2 : 1; + } + CG_ASSERT(num <= 2, ""); + uint32 rsizes[2]; + rsizes[0] = ploc.rsize0; + rsizes[1] = ploc.rsize1; + for (uint32 i = 0; i < num; i++) { + loadSize = rsizes[i]; + if (regs[i] >= V10) { + fpParm = true; + regtype = kRegTyFloat; + retpty = (loadSize == 4) ? PTY_f32 : PTY_f64; + } else { + regtype = kRegTyInt; + retpty = (loadSize == 4) ? PTY_u32 : PTY_u64; + } + if (parmCopy) { + if (fpParm) { + rhsmemopnd = LoadStructCopyBase(rhssymbol, rhsoffset + i * loadSize, loadSize * BITS_PER_BYTE); + } else { + rhsmemopnd = LoadStructCopyBase(rhssymbol, rhsoffset + i * 8, loadSize * BITS_PER_BYTE); + } + } else if (fpParm) { + rhsmemopnd = GetOrCreateMemOpnd(rhssymbol, rhsoffset + i * loadSize, loadSize * BITS_PER_BYTE); + } else { + rhsmemopnd = GetOrCreateMemOpnd(rhssymbol, rhsoffset + i * 8, loadSize * BITS_PER_BYTE); + } + regno_t vRegNo = New_V_Reg(regtype, loadSize); + result[i] = CreateVirtualRegisterOperand(vRegNo); + Insn *ld = cg->BuildInstruction(PickLdInsn(loadSize * BITS_PER_BYTE, retpty), result[i], rhsmemopnd); + curbb->AppendInsn(ld); + if (IsImmediateOffsetOutOfRange(static_cast(rhsmemopnd), loadSize * 8)) { + curbb->lastinsn->opnds[1] = + SplitOffsetWithAddInstruction(static_cast(rhsmemopnd), loadSize * 8, kRinvalid, curbb->lastinsn); + } + } + for (uint32 i = 0; i < num; i++) { + Riscv64reg_t preg; + MOperator mop; + preg = regs[i]; + if (regs[i] >= V10) { + mop = (loadSize == 4) ? MOP_xvmovs : MOP_xvmovd; + } else { + mop = (loadSize == 4) ? MOP_wmovrr: MOP_xmovrr; + } + RegOperand *dest = GetOrCreatePhysicalRegisterOperand(preg, loadSize * BITS_PER_BYTE, regtype); + Insn *mov = cg->BuildInstruction(mop, dest, result[i]); + curbb->AppendInsn(mov); + } + for (uint32 i = 0; i < num; i++) { + Riscv64reg_t preg; + MOperator mop; + preg = regs[i]; + if (regs[i] >= V10) { + mop = MOP_pseudo_ret_float; + } else { + mop = MOP_pseudo_ret_int; + } + RegOperand *dest = GetOrCreatePhysicalRegisterOperand(preg, loadSize * BITS_PER_BYTE, regtype); + Insn *pseudo = cg->BuildInstruction(mop, dest); + curbb->AppendInsn(pseudo); + } + } else { + rhsalign = becommon.type_align_table[rhsty->tyIdx.GetIdx()]; + if (GetPrimTypeSize(stmtty->primType) < rhsalign) { + rhsalign = GetPrimTypeSize(stmtty->primType); + } + + alignused = std::min(lhsalign, rhsalign); + Operand *rhsmemopnd = nullptr; + Operand *lhsmemopnd = nullptr; + bool parmCopy = IsParamStructCopy(rhssymbol); + for (uint32 i = 0; i < (lhssize / alignused); i++) { + // generate the load + if (parmCopy) { + rhsmemopnd = LoadStructCopyBase(rhssymbol, rhsoffset + i * alignused, alignused * 8); + } else { + rhsmemopnd = GetOrCreateMemOpnd(rhssymbol, rhsoffset + i * alignused, alignused * 8); + } + regno_t vRegNo = New_V_Reg(kRegTyInt, std::max(4u, alignused)); + RegOperand *result = CreateVirtualRegisterOperand(vRegNo); + curbb->AppendInsn(cg->BuildInstruction(PickLdInsn(alignused * 8, PTY_u32), result, rhsmemopnd)); + if (IsImmediateOffsetOutOfRange(static_cast(rhsmemopnd), alignused * 8)) { + curbb->lastinsn->opnds[1] = + SplitOffsetWithAddInstruction(static_cast(rhsmemopnd), alignused * 8, kRinvalid, curbb->lastinsn); + } + // generate the store + Riscv64OfstOperand *offopnd = GetOrCreateOfstOpnd(lhsoffset + i * alignused, 32); + lhsmemopnd = + GetOrCreateMemOpnd(alignused * 8, + static_cast(lhsaddropnd), nullptr, offopnd, + static_cast(nullptr)); + curbb->AppendInsn(cg->BuildInstruction(PickStInsn(alignused * 8, PTY_u32), result, lhsmemopnd)); + if (IsImmediateOffsetOutOfRange(static_cast(lhsmemopnd), alignused * 8)) { + curbb->lastinsn->opnds[1] = + SplitOffsetWithAddInstruction(static_cast(lhsmemopnd), alignused * 8, kRinvalid, curbb->lastinsn); + } + } + // take care of extra content at the end less than the unit of alignused + uint32 lhssizeCovered = (lhssize / alignused) * alignused; + uint32 newalignused = alignused; + while (lhssizeCovered < lhssize) { + newalignused = newalignused >> 1; + if (lhssizeCovered + newalignused > lhssize) { + continue; + } + // generate the load + rhsmemopnd = GetOrCreateMemOpnd(rhssymbol, rhsoffset + lhssizeCovered, newalignused * 8); + regno_t vRegNo = New_V_Reg(kRegTyInt, std::max(4u, newalignused)); + Operand *result = CreateVirtualRegisterOperand(vRegNo); + curbb->AppendInsn(cg->BuildInstruction(PickLdInsn(newalignused * 8, PTY_u32), result, rhsmemopnd)); + if (IsImmediateOffsetOutOfRange(static_cast(rhsmemopnd), newalignused * 8)) { + curbb->lastinsn->opnds[1] = + SplitOffsetWithAddInstruction(static_cast(rhsmemopnd), newalignused * 8, kRinvalid, curbb->lastinsn); + } + // generate the store + Riscv64OfstOperand *offopnd = GetOrCreateOfstOpnd(lhsoffset + lhssizeCovered, 32); + lhsmemopnd = + GetOrCreateMemOpnd(newalignused * 8, + static_cast(lhsaddropnd), nullptr, offopnd, + static_cast(nullptr)); + curbb->AppendInsn(cg->BuildInstruction(PickStInsn(newalignused * 8, PTY_u32), result, lhsmemopnd)); + lhssizeCovered += newalignused; + if (IsImmediateOffsetOutOfRange(static_cast(lhsmemopnd), newalignused * 8)) { + curbb->lastinsn->opnds[1] = + SplitOffsetWithAddInstruction(static_cast(lhsmemopnd), newalignused * 8, kRinvalid, curbb->lastinsn); + } + } + } + } else { // rhs is iread + CG_ASSERT(stmt->rhs->op == OP_iread, "SelectAggDassign: NYI"); + IreadNode *rhsiread = static_cast(stmt->rhs); + RegOperand *rhsaddropnd = static_cast(HandleExpr(rhsiread, rhsiread->Opnd(0))); + rhsaddropnd = LoadIntoRegister(rhsaddropnd, rhsiread->Opnd(0)->primType); + MIRPtrType *rhspointerty = static_cast(GlobalTables::GetTypeTable().GetTypeFromTyIdx(rhsiread->tyIdx)); + MIRType *rhsty = static_cast(GlobalTables::GetTypeTable().GetTypeFromTyIdx(rhspointerty->pointedTyIdx)); + bool isRefField = false; + if (rhsiread->fieldID != 0) { + MIRStructType *rhsstructty = static_cast(rhsty); + CG_ASSERT(rhsstructty, "SelectAggDassign: non-zero fieldID for non-structure"); + FieldPair thepair = rhsstructty->TraverseToField(rhsiread->fieldID); + rhsty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(thepair.second.first); + rhsoffset = becommon.GetFieldOffset(rhsstructty, rhsiread->fieldID).first; + isRefField = becommon.IsRefField(rhsstructty, rhsiread->fieldID); + } + if (stmtty->primType == PTY_agg) { + // generate move to regs. + CHECK_FATAL(lhssize <= 16, "SelectAggIassign: illegal struct size"); + RegOperand *result[2]; + uint32 loadSize = (lhssize <= 4) ? 4 : 8; + uint32 num = (lhssize <= 8) ? 1 : 2; + for (uint32 i = 0; i < num; i++) { + Riscv64OfstOperand *rhsoffopnd = GetOrCreateOfstOpnd(rhsoffset + i * loadSize, loadSize * BITS_PER_BYTE); + Operand *rhsmemopnd = + GetOrCreateMemOpnd(loadSize * BITS_PER_BYTE, + static_cast(rhsaddropnd), nullptr, rhsoffopnd, + static_cast(nullptr)); + regno_t vRegNo = New_V_Reg(kRegTyInt, loadSize); + result[i] = CreateVirtualRegisterOperand(vRegNo); + Insn *ld = cg->BuildInstruction(PickLdInsn(loadSize * BITS_PER_BYTE, PTY_u32), result[i], rhsmemopnd); + ld->MarkAsAccessRefField(isRefField); + curbb->AppendInsn(ld); + if (IsImmediateOffsetOutOfRange(static_cast(rhsmemopnd), loadSize * 8)) { + curbb->lastinsn->opnds[1] = + SplitOffsetWithAddInstruction(static_cast(rhsmemopnd), loadSize * 8, kRinvalid, curbb->lastinsn); + } + } + for (uint32 i = 0; i < num; i++) { + Riscv64reg_t preg = (i == 0 ? R10 : R11); + RegOperand *dest = GetOrCreatePhysicalRegisterOperand(preg, loadSize * BITS_PER_BYTE, kRegTyInt); + Insn *mov = cg->BuildInstruction(MOP_xmovrr, dest, result[i]); + curbb->AppendInsn(mov); + } + for (uint32 i = 0; i < num; i++) { + Riscv64reg_t preg = (i == 0 ? R10 : R11); + RegOperand *dest = GetOrCreatePhysicalRegisterOperand(preg, loadSize * BITS_PER_BYTE, kRegTyInt); + Insn *pseudo = cg->BuildInstruction(MOP_pseudo_ret_int, dest); + curbb->AppendInsn(pseudo); + } + } else { + rhsalign = becommon.type_align_table[rhsty->tyIdx.GetIdx()]; + if (GetPrimTypeSize(stmtty->primType) < rhsalign) { + rhsalign = GetPrimTypeSize(stmtty->primType); + } + + alignused = std::min(lhsalign, rhsalign); + Operand *rhsmemopnd = nullptr; + Operand *lhsmemopnd = nullptr; + for (uint32 i = 0; i < (lhssize / alignused); i++) { + // generate the load + Riscv64OfstOperand *rhsoffopnd = GetOrCreateOfstOpnd(rhsoffset + i * alignused, 32); + rhsmemopnd = + GetOrCreateMemOpnd(alignused * 8, + static_cast(rhsaddropnd), nullptr, rhsoffopnd, + static_cast(nullptr)); + regno_t vRegNo = New_V_Reg(kRegTyInt, std::max(4u, alignused)); + RegOperand *result = CreateVirtualRegisterOperand(vRegNo); + Insn *insn = cg->BuildInstruction(PickLdInsn(alignused * 8, PTY_u32), result, rhsmemopnd); + insn->MarkAsAccessRefField(isRefField); + curbb->AppendInsn(insn); + if (IsImmediateOffsetOutOfRange(static_cast(rhsmemopnd), alignused * 8)) { + curbb->lastinsn->opnds[1] = + SplitOffsetWithAddInstruction(static_cast(rhsmemopnd), alignused * 8, kRinvalid, curbb->lastinsn); + } + // generate the store + Riscv64OfstOperand *lhsoffopnd = GetOrCreateOfstOpnd(lhsoffset + i * alignused, 32); + lhsmemopnd = + GetOrCreateMemOpnd(alignused * 8, + static_cast(lhsaddropnd), nullptr, lhsoffopnd, + static_cast(nullptr)); + curbb->AppendInsn(cg->BuildInstruction(PickStInsn(alignused * 8, PTY_u32), result, lhsmemopnd)); + if (IsImmediateOffsetOutOfRange(static_cast(lhsmemopnd), alignused * 8)) { + curbb->lastinsn->opnds[1] = + SplitOffsetWithAddInstruction(static_cast(lhsmemopnd), alignused * 8, kRinvalid, curbb->lastinsn); + } + } + // take care of extra content at the end less than the unit of alignused + uint32 lhssizeCovered = (lhssize / alignused) * alignused; + uint32 newalignused = alignused; + while (lhssizeCovered < lhssize) { + newalignused = newalignused >> 1; + if (lhssizeCovered + newalignused > lhssize) { + continue; + } + // generate the load + Riscv64OfstOperand *rhsoffopnd = GetOrCreateOfstOpnd(rhsoffset + lhssizeCovered, 32); + rhsmemopnd = + GetOrCreateMemOpnd(newalignused * 8, + static_cast(rhsaddropnd), nullptr, rhsoffopnd, + static_cast(nullptr)); + regno_t vRegNo = New_V_Reg(kRegTyInt, std::max(4u, newalignused)); + RegOperand *result = CreateVirtualRegisterOperand(vRegNo); + Insn *insn = cg->BuildInstruction(PickLdInsn(newalignused * 8, PTY_u32), result, rhsmemopnd); + insn->MarkAsAccessRefField(isRefField); + curbb->AppendInsn(insn); + if (IsImmediateOffsetOutOfRange(static_cast(rhsmemopnd), newalignused * 8)) { + curbb->lastinsn->opnds[1] = + SplitOffsetWithAddInstruction(static_cast(rhsmemopnd), newalignused * 8, (Riscv64reg_t)kRinvalid, curbb->lastinsn); + } + // generate the store + Riscv64OfstOperand *lhsoffopnd = GetOrCreateOfstOpnd(lhsoffset + lhssizeCovered, 32); + lhsmemopnd = + GetOrCreateMemOpnd(newalignused * 8, + static_cast(lhsaddropnd), nullptr, lhsoffopnd, + static_cast(nullptr)); + curbb->AppendInsn(cg->BuildInstruction(PickStInsn(newalignused * 8, PTY_u32), result, lhsmemopnd)); + lhssizeCovered += newalignused; + if (IsImmediateOffsetOutOfRange(static_cast(lhsmemopnd), newalignused * 8)) { + curbb->lastinsn->opnds[1] = + SplitOffsetWithAddInstruction(static_cast(lhsmemopnd), newalignused * 8, kRinvalid, curbb->lastinsn); + } + } + } + } +} + +Operand *Riscv64CGFunc::SelectCopyToVecRegister(Operand *srcOpnd, PrimType dPtyp, PrimType sPtyp) { + CG_ASSERT(GetPrimTypeBitSize(sPtyp) == srcOpnd->GetSize(), ""); + Operand *dRegopnd = srcOpnd; + if (srcOpnd->op_kind_ != Operand::Opd_Register) { + dRegopnd = CreateRegisterOperandOfType(sPtyp); + SelectCopy(dRegopnd, sPtyp, srcOpnd, sPtyp); + } + RegOperand *dVecopnd = CreateRegisterOperandOfType(dPtyp); + CG_ASSERT(GetPrimTypeBitSize(dPtyp) == 128, "NYI"); + curbb->AppendInsn(cg->BuildInstruction(PickVecDup(sPtyp), dVecopnd, dRegopnd)); + return dVecopnd; +} + +Operand *Riscv64CGFunc::SelectDread(BaseNode *parent, DreadNode *expr) { + MIRSymbol *symbol = mirModule.CurFunction()->GetLocalOrGlobalSymbol(expr->stIdx); + bool unionTy = false; + if (symbol->IsEhIndex()) { + // use the second register return by __builtin_eh_return(). + ReturnMechanism retmech(GlobalTables::GetTypeTable().GetTypeFromTyIdx((TyIdx)PTY_i32), becommon); + retmech.SetupSecondRetReg(GlobalTables::GetTypeTable().GetTypeFromTyIdx((TyIdx)PTY_i32)); + return GetOrCreatePhysicalRegisterOperand(retmech.reg1, 64, kRegTyInt); + ; + } + + PrimType symty = symbol->GetType()->primType; + int32 offset = 0; + bool parmCopy = false; + if (expr->fieldID != 0) { + MIRStructType *structty = static_cast(symbol->GetType()); + if (structty->typeKind == kTypeUnion) { + unionTy = true; + } + CG_ASSERT(structty, "SelectDread: non-zero fieldID for non-structure"); + FieldPair thepair = structty->TraverseToField(expr->fieldID); + symty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(thepair.second.first)->primType; + offset = becommon.GetFieldOffset(structty, expr->fieldID).first; + parmCopy = IsParamStructCopy(symbol); + } + int datasize = GetPrimTypeSize(symty) * BITS_PER_BYTE; + uint32 aggsize = 0; + if (symty == PTY_agg) { + if (expr->primType == PTY_agg) { + aggsize = becommon.type_size_table.at(symbol->GetType()->tyIdx.GetIdx()); + datasize = SIZEOFPTR; + } else { + datasize = GetPrimTypeSize(expr->primType) * BITS_PER_BYTE; + } + } + MemOperand *memopnd; + if (aggsize > 8) { + if (parent->op == OP_eval) { + if (symbol->typeAttrs.GetAttr(ATTR_volatile)) { + // Need to generate loads for the upper parts of the struct. + Operand *dest = Riscv64RegOperand::GetZeroRegister(SIZEOFPTR * BITS_PER_BYTE); + uint32 num = aggsize >> 3; + for (uint32 o = 0; o < num; ++o) { + if (parmCopy) { + memopnd = LoadStructCopyBase(symbol, offset + o * SIZEOFPTR , SIZEOFPTR); + } else { + memopnd = GetOrCreateMemOpnd(symbol, offset + o * SIZEOFPTR, SIZEOFPTR); + } + if (IsImmediateOffsetOutOfRange(static_cast(memopnd), SIZEOFPTR)) { + memopnd = SplitOffsetWithAddInstruction(static_cast(memopnd), SIZEOFPTR); + } + SelectCopy(dest, PTY_u64, memopnd, PTY_u64); + } + } else { + // No need to generate anything for eval. + } + } else { + CHECK_FATAL(0,"SelectDread: Illegal agg size"); + } + } + if (parmCopy) { + memopnd = LoadStructCopyBase(symbol, offset, datasize); + } else { + memopnd = GetOrCreateMemOpnd(symbol, offset, datasize); + } + CHECK_FATAL(static_cast(memopnd), "null ptr check"); + if (IsImmediateOffsetOutOfRange(static_cast(memopnd), datasize)) { + memopnd = SplitOffsetWithAddInstruction(static_cast(memopnd), datasize); + } + if (IsPrimitiveVector(expr->primType)) { + return SelectCopyToVecRegister(memopnd, expr->primType, symty); + } + if (symty == PTY_agg) { + return memopnd; + } + + Operand *desopnd = LoadIntoRegister(memopnd, symty); + PrimType dtype = expr->primType; + if (dtype != symty) { + uint32 loadSz = GetPrimTypeSize(symty); + uint32 destSz = GetPrimTypeSize(dtype); + if (loadSz > destSz) { + return desopnd; + } + bool signExt = false; + uint32 bitSz = 0; + switch (symty) { + case PTY_u8: + if (dtype == PTY_i8 || dtype == PTY_i16 || dtype == PTY_i32 || dtype == PTY_i64) { + signExt = true; + bitSz = 8; + } + break; + case PTY_u16: + if (dtype == PTY_i16 || dtype == PTY_i32 || dtype == PTY_i64) { + signExt = true; + bitSz = 16; + } + break; + case PTY_u32: + if (dtype == PTY_i32 || dtype == PTY_i64) { + signExt = true; + bitSz = 32; + } + break; + case PTY_i8: + if (dtype == PTY_u8 || dtype == PTY_u16 || dtype == PTY_u32 || dtype == PTY_u64) { + bitSz = 8; + } else if (unionTy && (dtype == PTY_i16 || dtype == PTY_i32 || dtype == PTY_i64)) { + bitSz = 8; + signExt = true; + } + break; + case PTY_i16: + if (dtype == PTY_u16 || dtype == PTY_u32 || dtype == PTY_u64) { + bitSz = 16; + } else if (unionTy && (dtype == PTY_i32 || dtype == PTY_i64)) { + bitSz = 16; + signExt = true; + } + break; + case PTY_i32: + if (dtype == PTY_u32 || dtype == PTY_u64) { + bitSz = 32; + } else if (unionTy && (dtype == PTY_i64)) { + bitSz = 32; + signExt = true; + } + break; + default: + break; + } + if (bitSz != 0) { + Operand *extopnd = CreateVirtualRegisterOperand(New_V_Reg(kRegTyInt, GetPrimTypeSize(dtype))); + if (signExt) { + return GenerateSext(extopnd, desopnd, dtype, bitSz); + } else { + return GenerateZext(extopnd, desopnd, dtype, bitSz); + } + } + } + + return desopnd; +} + +RegOperand *Riscv64CGFunc::SelectRegread(BaseNode *parent, RegreadNode *expr) { + PregIdx pregidx = expr->regIdx; + if (IsSpecialPseudoRegister(pregidx)) { + // if it is one of special registers + pregidx = GetSpecialPseudoRegisterIndex(pregidx); + RegOperand *reg = GetOrCreateSpecialRegisterOperand(pregidx, expr->primType); + if (pregidx == kSregRetval0) { + CG_ASSERT(curbb->lastinsn->IsCall(), "Dangling regread(SREG_retreg0)?"); + CG_ASSERT(call_info_map.find(curbb->lastinsn) != call_info_map.end(), "Dangling regread(SREG_retreg0)?"); + CSR_call_info_t &ci = call_info_map[curbb->lastinsn]; + CG_ASSERT(reg->GetRegisterType() == kRegTyInt || reg->GetRegisterType() == kRegTyFloat, ""); + Riscv64reg_t rn = reg->GetRegisterType() == kRegTyInt ? Riscv64Abi::kIntRetReg0 : Riscv64Abi::kFpRetReg0; + CallerSavedRegHandler::CsrBitsetSet(ci.regs_used, Riscv64CallerSavedRegHandler::Reg2BitPos(rn)); + } + return reg; + } else { + RegOperand *reg = GetOrCreateVirtualRegisterOperand(GetVirtualRegNoFromPseudoRegIdx(pregidx)); + if (g->optim_level == 0) { + MemOperand *src = GetPseudoRegisterSpillMemoryOperand(pregidx); + PrimType stype = expr->primType;//GetTypeFromPseudoRegIdx(pregidx); + MIRPreg *preg = func->pregTab->PregFromPregIdx(pregidx); + int32 bytelen = GetPrimTypeSize(stype); + uint32_t srcbitlen = bytelen * BITS_PER_BYTE; + RegType regty = GetRegTyFromPrimTyRiscv64(stype); + RegOperand *vreg = CreateVirtualRegisterOperand(New_V_Reg(regty, bytelen)); + curbb->AppendInsn(cg->BuildInstruction(PickLdInsn(srcbitlen, stype), vreg, src)); + return vreg; + } + return reg; + } +} + +void Riscv64CGFunc::SelectAddrof(Operand *result, StImmOperand *stimm) { + MIRSymbol *symbol = stimm->GetSymbol(); + if (symbol->storageClass == kScAuto || symbol->storageClass == kScFormal) { + if (!cg->DoItQuietly()) { + fprintf(stderr, "Warning: we expect AddrOf with StImmOperand is not used for local variables"); + } + Riscv64SymbolAlloc *symloc = static_cast(memlayout->sym_alloc_table.at(symbol->GetStIndex())); + Riscv64ImmOperand *offset = nullptr; + if (symloc->mem_segment->kind == kMsArgsStkpassed) { + offset = CreateImmOperand(GetBaseOffset(symloc) + stimm->GetOffset(), 64, false, true); + } else if (symloc->mem_segment->kind == kMsReflocals) { + auto it = immopnds_requiring_offset_adjustment_for_refloc_.find(symloc); + if (it != immopnds_requiring_offset_adjustment_for_refloc_.end()) { + offset = (*it).second; + } else { + offset = CreateImmOperand(GetBaseOffset(symloc) + stimm->GetOffset(), 64, false); + immopnds_requiring_offset_adjustment_for_refloc_[symloc] = offset; + } + } else if (mirModule.IsJavaModule()) { + auto it = immopnds_requiring_offset_adjustment_.find(symloc); + if (it != immopnds_requiring_offset_adjustment_.end()) { + offset = (*it).second; + } else { + offset = CreateImmOperand(GetBaseOffset(symloc) + stimm->GetOffset(), 64, false); + if (symbol->GetType()->typeKind != kTypeClass) { + immopnds_requiring_offset_adjustment_[symloc] = offset; + } + } + } else { + // Do not cache modified symbol location + offset = CreateImmOperand(GetBaseOffset(symloc) + stimm->GetOffset(), 64, false); + } + + SelectAdd(result, GetBaseReg(symloc), offset, PTY_u64); + if (cg->GenerateVerboseAsm()) { + // Add a comment + Insn *insn = curbb->lastinsn; + std::string comm = "local/formal var: "; + comm.append(symbol->GetName()); + insn->AddComment(comm); + } + } else { + curbb->AppendInsn(cg->BuildInstruction(MOP_adrp, result, stimm)); + if (CGOptions::doPIC && (symbol->GetStorageClass() == kScGlobal || symbol->GetStorageClass() == kScExtern)) { + // ldr x0, [x0, #:got_lo12:Ljava_2Flang_2FSystem_3B_7Cout] + Riscv64MemOperand *mo = GetOrCreateMemOpnd(SIZEOFPTR * BITS_PER_BYTE, + static_cast(result), nullptr, stimm, nullptr); + curbb->AppendInsn(cg->BuildInstruction(MOP_xldr, result, mo)); + } else { + curbb->AppendInsn(cg->BuildInstruction(MOP_adrpl12, result, result, stimm)); + } + } +} + +void Riscv64CGFunc::SelectAddrof(Operand *result, Riscv64MemOperand *memopnd) { + MIRSymbol *symbol = memopnd->GetSymbol(); + if (symbol->storageClass == kScAuto) { + SelectAdd(result, memopnd->GetBaseRegister(), + CreateImmOperand(static_cast(memopnd->GetOffsetImmediate())->GetOffsetValue(), + PTY_u32, false), + PTY_u32); + } else { + curbb->AppendInsn(cg->BuildInstruction(MOP_adrp, result, memopnd)); + curbb->AppendInsn(cg->BuildInstruction(MOP_adrpl12, result, result, memopnd)); + } +} + +Operand *Riscv64CGFunc::SelectAddrof(AddrofNode *expr) { + MIRSymbol *symbol = mirModule.CurFunction()->GetLocalOrGlobalSymbol(expr->stIdx); + int32 offset = 0; + if (expr->fieldID != 0) { + MIRStructType *structty = dynamic_cast(symbol->GetType()); + if (structty) { + CG_ASSERT(structty, "SelectAddrof: non-zero fieldID for non-structure"); + offset = becommon.GetFieldOffset(structty, expr->fieldID).first; + } + } + if ((symbol->storageClass == kScFormal) && (symbol->sKind == kStVar) && + ((expr->fieldID != 0) || + (becommon.type_size_table.at(symbol->GetType()->tyIdx.GetIdx()) > 16))) { + // Struct param is copied on the stack by caller if struct size > 16. + // Else if size < 16 then struct param is copied into one or two registers. + regno_t vregno; + vregno = New_V_Reg(kRegTyInt, GetPrimTypeSize(PTY_a64)); + Operand *stackAddr = CreateVirtualRegisterOperand(vregno); + // load the base address of the struct copy from stack. + SelectAddrof(stackAddr, CreateStImmOperand(symbol, 0, 0)); + Operand *structAddr; + if (becommon.type_size_table.at(symbol->GetType()->tyIdx.GetIdx()) <= 16) { + isAggParamInReg = true; + structAddr = stackAddr; + } else { + Riscv64OfstOperand *offopnd = CreateOfstOpnd(0, 32); + Riscv64MemOperand * + mo = GetOrCreateMemOpnd( SIZEOFPTR * BITS_PER_BYTE, + static_cast(stackAddr), + nullptr, offopnd, nullptr); + vregno = New_V_Reg(kRegTyInt, GetPrimTypeSize(PTY_a64)); + structAddr = CreateVirtualRegisterOperand(vregno); + curbb->AppendInsn(cg->BuildInstruction(MOP_xldr, structAddr, mo)); + } + if (offset == 0) { + return structAddr; + } else { + // add the struct offset to the base address + vregno = New_V_Reg(kRegTyInt, GetPrimTypeSize(PTY_a64)); + Operand *result = CreateVirtualRegisterOperand(vregno); + ImmOperand *imm = CreateImmOperand(PTY_a64, offset); + curbb->AppendInsn(cg->BuildInstruction(MOP_xaddrri12, result, + structAddr, imm)); + return result; + } + } + PrimType primType = expr->primType; + regno_t vRegNo = New_V_Reg(kRegTyInt, GetPrimTypeSize(primType)); + Operand *result = CreateVirtualRegisterOperand(vRegNo); + if (symbol->IsReflectionClassInfo() && !symbol->IsReflectionArrayClassInfo() && !isLibcore) { + // Turn addrof __cinf_X into a load of _PTR__cinf_X + // adrp x1, _PTR__cinf_Ljava_2Flang_2FSystem_3B + // ldr x1, [x1, #:lo12:_PTR__cinf_Ljava_2Flang_2FSystem_3B] + std::string ptrName = NameMangler::kPtrPrefixStr + symbol->GetName(); + MIRType *ptrType = GlobalTables::GetTypeTable().GetPtr(); + symbol = mirModule.mirBuilder->GetOrCreateGlobalDecl(ptrName, ptrType); + symbol->storageClass = kScFstatic; + + curbb->AppendInsn(cg->BuildInstruction(MOP_adrp_ldr, result, CreateStImmOperand(symbol, 0, 0))); + return result; + } + + SelectAddrof(result, CreateStImmOperand(symbol, offset, 0)); + return result; +} + +Operand *Riscv64CGFunc::SelectAddroffunc(AddroffuncNode *expr) { + regno_t vRegNo = New_V_Reg(kRegTyInt, expr->SizeOfInstr()); + Operand *operand = CreateVirtualRegisterOperand(vRegNo); + MIRFunction *func = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(expr->puIdx); + CG_ASSERT(func, "function not found for 'addroffunc'"); + SelectAddrof(operand, CreateStImmOperand(func->GetFuncSymbol(), 0, 0)); + return operand; +} + +Operand *Riscv64CGFunc::SelectIread(BaseNode *parent, IreadNode *expr) { + int32 offset = 0; + MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(expr->tyIdx); + MIRPtrType *pointerty = static_cast(type); + CG_ASSERT(pointerty, "expect a pointer type at iread node"); + MIRType *pointedType = nullptr; + bool isRefField = false; + Riscv64isa::memory_ordering_t mo = Riscv64isa::kMoNone; + + if (expr->fieldID != 0) { + MIRType *pointedty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(pointerty->pointedTyIdx); + MIRStructType *structty = nullptr; + if (pointedty->GetKind() != kTypeJArray) { + structty = static_cast(pointedty); + CG_ASSERT(structty != nullptr, "structty is null in Riscv64CGFunc::SelectIread"); + } else { + // it's a Jarray type. using it's parent's field info: java.lang.Object + structty = static_cast(pointedty)->GetParentType(); + } + + CG_ASSERT(structty, "SelectIread: non-zero fieldID for non-structure"); + FieldPair thepair = structty->TraverseToField(expr->fieldID); + pointedType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(thepair.second.first); + offset = becommon.GetFieldOffset(structty, expr->fieldID).first; + isRefField = becommon.IsRefField(structty, expr->fieldID); + } else { + pointedType = GetPointedToType(pointerty); + if (func->IsJava() && (pointedType->GetKind() == kTypePointer)) { + MIRType *nextPointedType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(static_cast(pointedType)->pointedTyIdx); + if (nextPointedType->GetKind() != kTypeScalar) { + isRefField = true; // read from an object array, or an high-dimentional array + } + } + } + + RegType regty; + if (expr->primType == PTY_agg) { + regty = kRegTyInt; + } else { + regty = GetRegTyFromPrimTyRiscv64(expr->primType); + } + uint32 regsize = GetPrimTypeSize(expr->primType); + if (expr->fieldID == 0 && pointedType->primType == PTY_agg) { + if (regty == kRegTyFloat) { + // regsize is correct + } else if (becommon.type_size_table.at(pointedType->tyIdx.GetIdx()) <= 4) { + regsize = 4; + } else { + regsize = 8; + } + } else { + if (regsize < 4) { + regsize = 4; // 32-bit + } + } + + PrimType destType = pointedType->GetPrimType(); + + uint32 bitsize = 0; + uint32 numLoads = 1; + if (pointedType->typeKind == kTypeStructIncomplete || pointedType->typeKind == kTypeClassIncomplete || + pointedType->typeKind == kTypeInterfaceIncomplete) { + bitsize = GetPrimTypeBitSize(expr->primType); + fprintf(stderr, "Warning: objsize is zero! \n"); + } else { + MIRStructType *structtype = dynamic_cast(pointedType); + if (structtype) { + bitsize = structtype->GetSize() << 3; + } else { + bitsize = GetPrimTypeBitSize(destType); + } + if (regty == kRegTyFloat) { + destType = expr->primType; + bitsize = GetPrimTypeBitSize(destType); + } else if (expr->fieldID == 0 && destType == PTY_agg) { // entire struct + switch (bitsize) { + case 8: + destType = PTY_u8; + break; + case 16: + destType = PTY_u16; + break; + case 32: + destType = PTY_u32; + break; + case 64: + destType = PTY_u64; + break; + default: + destType = PTY_u64; + numLoads = RoundUp(bitsize, 64) / 64; + bitsize = 64; + break; + } + } + } + + Operand *result; +#if 0 + if (parent->op == OP_eval) { + result = Riscv64RegOperand::GetZeroRegister(regsize << 3); + } else { + result = CreateVirtualRegisterOperand(New_V_Reg(regty, regsize)); + } +#else + result = CreateVirtualRegisterOperand(New_V_Reg(regty, regsize)); +#endif + + for (uint32 i = 0; i < numLoads; ++i) { + MemOperand *memopnd = CreateMemOpnd(destType, expr, expr->Opnd(0), offset, mo); + if (aggParamReg) { + isAggParamInReg = false; + return aggParamReg; + } + if (isVolLoad) { + mo = Riscv64isa::kMoAcquire; + isVolLoad = false; + } + + if (IsImmediateOffsetOutOfRange(static_cast(memopnd), bitsize)) { + memopnd = SplitOffsetWithAddInstruction(static_cast(memopnd), bitsize); + } + + if (mo == Riscv64isa::kMoNone) { + MOperator mop = PickLdInsn(bitsize, destType); + Insn *insn = cg->BuildInstruction(mop, result, memopnd); + if (parent->op == OP_eval && result->IsRegister() && static_cast(result)->IsZeroRegister()) { + insn->AddComment("null-check"); + } + curbb->AppendInsn(insn); + } else { + Riscv64CGFunc::SelectLoadAcquire(result, destType, memopnd, destType, mo, false); + } + curbb->lastinsn->MarkAsAccessRefField(isRefField); + offset += 8; + } + return result; +} + +Operand *Riscv64CGFunc::SelectIntconst(MIRIntConst *intconst, PrimType parentPtype) { + PrimType pty = intconst->type->primType; + if (pty != parentPtype) { + // Maple IR allows silent type conversion between sign/unsigned if size is the same. + if (GetPrimTypeSize(pty) == GetPrimTypeSize(parentPtype)) { + pty = parentPtype; + } + } + bool isSigned; + if (pty == PTY_i8 || pty == PTY_i16 || pty == PTY_i32 || pty == PTY_i64) { + isSigned = true; + } else { + isSigned = false; + } + int64 val = intconst->value; + if (isSigned == false && GetPrimTypeSize(pty) == 4) { + val = static_cast(val) & 0x0ffffffffULL; + } + return CreateImmOperand(val, GetPrimTypeSize(intconst->type->GetPrimType()) * 8, isSigned); +} + +template +Operand *SelectLiteral(T *c, MIRFunction *func, uint32 labelIdx, Riscv64CGFunc *cgfunc) { + MIRSymbol *st = func->symTab->CreateSymbol(kScopeLocal); + std::string lblstr(".LB_"); + MIRSymbol *funcSt = GlobalTables::GetGsymTable().GetSymbolFromStIdx(func->stIdx.Idx()); + std::string funcname = funcSt->GetName(); + lblstr.append(funcname).append(to_string(labelIdx)); + st->SetNameStridx(GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(lblstr)); + st->storageClass = kScPstatic; + st->sKind = kStConst; + st->SetConst(c); + PrimType primty = c->type->GetPrimType(); + st->SetTyIdx(c->type->tyIdx); + uint32 typeBitsize = GetPrimTypeBitSize(primty); + + switch (c->kind) { + case kConstFloatConst: + case kConstDoubleConst: { + // Handling of -0.0. Use zero reg only for +0.0, not -0.0. + if (cgfunc->mirModule.IsCModule()) { + return static_cast(cgfunc->GetOrCreateMemOpnd(st, 0, typeBitsize)); + } + return (c->IsZero() && !(c->IsNeg())) ? static_cast(cgfunc->GetOrCreateFpZeroOperand(typeBitsize)) + : static_cast(cgfunc->GetOrCreateMemOpnd(st, 0, typeBitsize)); + } + case kConstVecInt: { + return static_cast(cgfunc->GetOrCreateMemOpnd(st, 0, typeBitsize)); + } + default: { + ASSERT(0, "Unsupported const type"); + return nullptr; + } + } +} + +Operand *Riscv64CGFunc::SelectFloatconst(MIRFloatConst *floatconst) { + return SelectLiteral(floatconst, func, labelIdx++, this); +} + +Operand *Riscv64CGFunc::SelectDoubleconst(MIRDoubleConst *doubleconst) { + return SelectLiteral(doubleconst, func, labelIdx++, this); +} + +Operand *Riscv64CGFunc::SelectVectorIntconst(MIRVectorIntConst *vecIntconst) { + return SelectLiteral(vecIntconst, func, labelIdx++, this); +} + +template +Operand *SelectStrLiteral(T *c, Riscv64CGFunc *cgfunc) { + std::string labelStr; + if (c->kind == kConstStrConst) { + labelStr.append("__Ustr_"); + } else if (c->kind == kConstStr16Const) { + labelStr.append("__Ustr16_"); + } else { + ASSERT(0, "Unsupported literal type"); + } + labelStr.append(std::to_string(c->value.GetIdx())); + + MIRSymbol *labelSym = GlobalTables::GetGsymTable().GetSymbolFromStrIdx(GlobalTables::GetStrTable().GetStrIdxFromName(labelStr)); + if (!labelSym) { + labelSym = cgfunc->mirModule.mirBuilder->CreateGlobalDecl(labelStr, c->type, kScGlobal); + labelSym->storageClass = kScFstatic; + labelSym->sKind = kStConst; + // c may be local, we need a global node here + labelSym->SetConst(cgfunc->mirModule.memPool->New(c->value, c->type)); + } + + if (c->kPrimType == PTY_a64) { + StImmOperand *stopnd = cgfunc->CreateStImmOperand(labelSym, 0, 0); + RegOperand *addropnd = cgfunc->CreateRegisterOperandOfType(PTY_a64); + cgfunc->SelectAddrof(addropnd, stopnd); + return addropnd; + } else { + ASSERT(0, "Unsupported const string type"); + return nullptr; + } +} + +Operand *Riscv64CGFunc::SelectStrconst(MIRStrConst *strconst) { + return SelectStrLiteral(strconst, this); +} + +Operand *Riscv64CGFunc::SelectStr16const(MIRStr16Const *str16const) { + return SelectStrLiteral(str16const, this); +} + +} // namespace maplebe diff --git a/mapleall/maple_be/src/cg/riscv64/riscv64_lvar.cpp b/mapleall/maple_be/src/cg/riscv64/riscv64_lvar.cpp new file mode 100644 index 0000000..1f89267 --- /dev/null +++ b/mapleall/maple_be/src/cg/riscv64/riscv64_lvar.cpp @@ -0,0 +1,1204 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#include "riscv64_lvar.h" +#include "riscv64_insn.h" +#include "riscv64_operand.h" +#include "riscv64_mem_layout.h" +#include "cg_assert.h" +#include "special_func.h" + +#undef DEBUG +#define DEBUG 0 + +namespace maplebe { + +void Riscv64OptLocalRef::DoOptLocalRef() { + if (CfgHasCycle() == true) { + // Do not handle loops yet. + return; + } + OptLRInit(); + + if (giveup == true) { + goto optlrfini; + } + + DoOptimize(); + + if (giveup == true) { + goto optlrfini; + } + + FinalizeLocRef(); + FixMrtCall(); + +optlrfini: + OptLRFini(); +} + +void Riscv64OptLocalRef::PrintBbTraceList(string str, bool more) { + LogInfo::MapleLogger() << "===" << str << "===\n"; + if (more == false) { + CHECK_FATAL(bb_trace.size(), "container size check"); + BB *top = bb_trace.front(); + BB *cbb = top; + do { + LogInfo::MapleLogger() << cbb->id << " "; + bb_trace.pop_front(); + bb_trace.push_back(cbb); + cbb = bb_trace.front(); + } while (cbb != top); + LogInfo::MapleLogger() << "\n"; + return; + } + + MapleList::iterator it; + for (it = bb_trace.begin(); it != bb_trace.end(); it++) { + BB *bb = *it; + Iinfo *info = nullptr; + for (info = insn_info_in_bb[bb->id]; info; info = info->next) { + LogInfo::MapleLogger() << "bb " << info->insn->bb->id << " imm " << info->imm << " map " << info->assigned << "\n"; + } + } +} + +/* The current algorithm does not handle cycles. + * All traces has single path from entry to exit. + */ +bool Riscv64OptLocalRef::DetectCycle() { + BB *bb = nullptr; + bool childPushed; + while (dfs_bbs.empty() == false) { + childPushed = false; + bb = dfs_bbs.top(); + dfs_bbs.pop(); + CHECK_FATAL(bb != nullptr, "bb is null in Riscv64OptLocalRef::DFS"); + visited_bbs[bb->id] = true; + if (bb->level == 0) { + bb->level = 1; + } + std::stack succs; + // Mimic more of the recursive DFS by reversing the order of the succs. + for (MapleList::iterator it = bb->succs.begin(); it != bb->succs.end(); ++it) { + BB *ibb = *it; + succs.push(ibb); + } + while (succs.empty() == false) { + BB *ibb = succs.top(); + succs.pop(); + if (visited_bbs[ibb->id] == false) { + childPushed = true; + ibb->level = bb->level + 1; + sorted_bbs[ibb->id] = bb; // tracking parent of traversed child + dfs_bbs.push(ibb); + } else if ((ibb->level != 0) && (bb->level >= ibb->level)) { + // Backedge + return true; + } + } + for (MapleList::iterator it = bb->eh_succs.begin(); it != bb->eh_succs.end(); ++it) { + BB *ibb = *it; + succs.push(ibb); + } + while (succs.empty() == false) { + BB *ibb = succs.top(); + succs.pop(); + if (visited_bbs[ibb->id] == false) { + childPushed = true; + ibb->level = bb->level + 1; + sorted_bbs[ibb->id] = bb; // tracking parent of traversed child + dfs_bbs.push(ibb); + } else if ((ibb->level != 0) && (bb->level >= ibb->level)) { + // Backedge + return true; + } + } + // Remove duplicate bb that are visited from top of stack + if (dfs_bbs.empty() == false) { + BB *nbb = dfs_bbs.top(); + while (nbb) { + if (visited_bbs[nbb->id] == true) { + dfs_bbs.pop(); + } else { + break; + } + if (dfs_bbs.empty() == false) { + nbb = dfs_bbs.top(); + } else { + break; + } + } + } + if (childPushed == false && dfs_bbs.empty() == false) { + // reached the bottom of visited chain, reset level to the next visit bb + bb->level = 0; + BB *nbb = dfs_bbs.top(); + if (sorted_bbs[nbb->id]) { + nbb = sorted_bbs[nbb->id]; + // All bb up to the top of stack bb's parent's child (its sibling) + while (bb) { + // get parent bb + BB *pbb = sorted_bbs[bb->id]; + if (pbb == nullptr || pbb == nbb) { + break; + } + pbb->level = 0; + bb = pbb; + } + } + } + } + return false; +} + +bool Riscv64OptLocalRef::CfgHasCycle() { + visited_bbs.resize(cgfunc->NumBBs()); + for (uint32 i = 0; i < cgfunc->NumBBs(); i++) { + visited_bbs[i] = false; + sorted_bbs.push_back(nullptr); + } + FOR_ALL_BB(bb, cgfunc) { + bb->level = 0; + } + bool changed; + do { + changed = false; + FOR_ALL_BB(bb, cgfunc) { + if (visited_bbs[bb->id] == false) { + dfs_bbs.push(bb); + if (DetectCycle() == true) { + return true; + } + changed = true; + } + } + } while (changed == true); + return false; +} + +bool Riscv64OptLocalRef::IsLdStLocalRefVar(Operand *src) { + Riscv64MemOperand *memopnd = static_cast(src); + Operand *base = memopnd->GetBaseRegister(); + if (base && static_cast(base)->GetRegisterNumber() != RFP) { + return false; + } + Riscv64OfstOperand *imm = memopnd->GetOffsetImmediate(); + if (imm == nullptr) { + return false; + } + int32 val = imm->GetOffsetValue(); + if (val >= min_imm && val <= max_imm) { + return true; + } + return false; +} + +/* Given a call insn, look backward to find the immediate value that + * is assigned and modify it to the new value. + * This is used to change the slot numbers for MRT (init cleanup) calls. + */ +void Riscv64OptLocalRef::ModifyParamValue(Insn *insn, uint32 reg, uint32 val) { + // Assuming at this point the parameters are generated in order and in bb. + // Therefore x1, x2 will always not be the first insn in bb. + for (Insn *prev = insn->prev; prev; prev = prev->prev) { + Operand *dst = prev->GetOperand(0); + RegOperand *regopnd = static_cast(dst); + if (regopnd->GetRegisterNumber() == reg) { + Operand *src = nullptr; + if (prev->GetOpndNum() == 1) { + // move insn + src = prev->GetOpnd(0); + } else { + // add insn + src = prev->GetOpnd(1); + } + CHECK_FATAL(src, "null ptr check"); + if (src->IsRegister()) { + RegOperand *regsrc = static_cast(src); + return ModifyParamValue(prev, regsrc->GetRegisterNumber(), val); + } else { + CG_ASSERT(src->IsIntImmediate(), "ModifyParamValue not imm const"); + ImmOperand *imm = static_cast(src); + imm->SetValue(val); + return; + } + } + } + CG_ASSERT(0, "ModifyParamValue got no imm const"); +} + +/* Given a call insn, look backward to find the immediate value that + * is assigned and then returns that immediate value. + */ +uint32 Riscv64OptLocalRef::GetParamValue(Insn *insn, uint32 reg) { + // Assuming at this point the parameters are generated in order and in bb. + // Therefore x1, x2 will always not be the first insn in bb. + for (Insn *prev = insn->prev; prev; prev = prev->prev) { + Operand *dst = prev->GetOperand(0); + RegOperand *regopnd = static_cast(dst); + if (regopnd->GetRegisterNumber() == reg) { + Operand *src = nullptr; + if (prev->GetOpndNum() == 1) { + // move insn + src = prev->GetOpnd(0); + } else { + // add insn + src = prev->GetOpnd(1); + } + CHECK_FATAL(src, "null ptr check"); + if (src->IsRegister()) { + RegOperand *regsrc = static_cast(src); + return GetParamValue(prev, regsrc->GetRegisterNumber()); + } else { + CG_ASSERT(src->IsIntImmediate(), "GetParamValue not imm const"); + ImmOperand *imm = static_cast(src); + // LogInfo::MapleLogger() << "Return " << imm->GetValue() << "\n"; + return static_cast(imm->GetValue()); + } + } + } + CG_ASSERT(0, "GetParamValue got no imm const"); + return 0; +} + +/* At the end of the function, there might be a cleanup bbs + * which is jumped to when encountering exception. The cleanup + * bbs can be reached from anywhere, so treat it special. + */ +void Riscv64OptLocalRef::HandleCleanupBB(BB *bb) { + // Cleanup bbs should be at the end of the function. + // Nothing is afterward. + // Since it can be reached from anywhere, make sure the + // local ref stack slot is not modified. + for (; bb; bb = bb->next) { + FOR_BB_INSNS(insn, bb) { + if (IsRcStackCall(insn)) { + continue; + } + if (insn->IsLoad() == false) { + continue; + } + Operand *src = nullptr; + bool isLdPair = false; + if (IsLdStPair(insn)) { + src = insn->GetOperand(2); + isLdPair = true; + } else { + src = insn->GetOperand(1); + isLdPair = false; + } + int32 val; + if (CanGetMemOpndImm(src, val)) { + xzr_init_local_offset.insert(val); + if (isLdPair) { + xzr_init_local_offset.insert(val + 8); + } +#if (DEBUG > 1) + LogInfo::MapleLogger() << "HandleCleanupBB - insert cleanup xzr " << val << "\n"; +#endif + } + } + } +} + +/* Look for MRT (init, cleanup, cleanupskip) calls. + */ +bool Riscv64OptLocalRef::IsRcStackCall(Insn *insn) { + if (insn->IsCall()) { + Operand *opnd = insn->GetOperand(0); + FuncNameOperand *callName = dynamic_cast(opnd); + if (callName) { + string name = callName->GetName(); + if (name == GetIntrinsicFuncName(INTRN_MCCInitializeLocalStackRef)) { + CG_ASSERT(rc_stack_init_start_loc == 0, "IsRcStackCall-Init loc set already"); + rc_stack_init_start_loc = GetParamValue(insn, R0); +#if (DEBUG > 0) + LogInfo::MapleLogger() << "\tset rc_stack_init_start_loc to " << rc_stack_init_start_loc << "\n"; +#endif + rc_init_call.push(insn); + CG_ASSERT(rc_localrefvar_slots == 0, "IsRcStackCall-Init loc set already"); + rc_localrefvar_slots = GetParamValue(insn, R1); +#if (DEBUG > 0) + LogInfo::MapleLogger() << "\tset rc_localrefvar_slots to " << rc_localrefvar_slots << "\n"; +#endif + + min_imm = rc_stack_init_start_loc; + max_imm = rc_stack_init_start_loc + (rc_localrefvar_slots - 1) * 8; + has_rc_init = true; + return true; + } else if (name == GetIntrinsicFuncName(INTRN_MCCCleanupLocalStackRefNaiveRCFast)) { + if (has_rc_init == false) { + giveup = true; + return true; + } + rc_cleanup_call.push(insn); + int skipSlot = static_cast(insn)->ref_skipindex; + if (skipSlot != -1) { + giveup = true; + uint32 val = static_cast(skipSlot); + rc_cleanup_skip_num.insert(val); +#if (DEBUG > 0) + LogInfo::MapleLogger() << "\tinsert MrtCleanup skip num " << val << "\n"; +#endif + } + has_rc_cleanup = true; + return true; + } else if (name == GetIntrinsicFuncName(INTRN_MCCCleanupLocalStackRefSkipNaiveRCFast)) { + if (has_rc_init == false) { + giveup = true; + return true; + } + // x1: # slots, x2: skip slot + rc_skip_call.push(insn); + uint32 val = GetParamValue(insn, R1); + if (rc_localrefvar_slots != val) { + giveup = true; + return true; + } + int skipSlot = static_cast(insn)->ref_skipindex; + if (skipSlot != -1) { + giveup = true; + val = static_cast(skipSlot); + rc_cleanup_skip_num.insert(val); +#if (DEBUG > 0) + LogInfo::MapleLogger() << "\tinsert MrtCleanupSkip skip num " << val << "\n"; +#endif + } + has_rc_cleanup = true; + return true; + } else if (name == GetIntrinsicFuncName(INTRN_MCCDecRefReset)) { + giveup = true; + return true; + } + } + } + return false; +} + +/* load/store pair insn can be tricky to handle. Remember them. + */ +void Riscv64OptLocalRef::RecordLdStPair(Insn *insn) { + Operand *src = insn->GetOperand(2); + MemOperand *memopnd = static_cast(src); + Operand *base = memopnd->GetBaseRegister(); + if (base->IsRegister()) { + RegOperand *regOpnd = static_cast(base); + if (regOpnd->GetRegisterNumber() != R29) { + return; + } + } + Riscv64MemOperand *mem = static_cast(src); + Riscv64OfstOperand *imm = mem->GetOffsetImmediate(); + if (imm == nullptr) { + return; + } + int32 val = imm->GetOffsetValue(); + CG_ASSERT((val & 0x7) == 0, "Ld/St pair imm offset not 8 aligned"); + if (static_cast(insn->GetOperand(0))->IsZeroRegister() && + static_cast(insn->GetOperand(1))->IsZeroRegister()) { + xzr_init_local_offset.insert(val); + xzr_init_local_offset.insert(val + 8); +#if (DEBUG > 2) + LogInfo::MapleLogger() << "RecordLdStPair - insert pair xzr " << val << " + 8\n"; +#endif + } else { + ld_st_pair_offset.insert(val); + ld_st_pair_offset.insert(val + 8); +#if (DEBUG > 2) + LogInfo::MapleLogger() << "RecordLdStPair - insert pair ldst " << val << " + 8\n"; +#endif + } +} + +/* Localrefvar can be initialized by explicit store of 0 (XZR) instead + * of a call to MRT_Init. + * Although it is not handled now, remember them. + */ +bool Riscv64OptLocalRef::RecordXzrInit(Insn *insn) { + if (static_cast(insn->GetOperand(0))->IsZeroRegister()) { + Operand *src1 = insn->GetOperand(1); + MemOperand *memopnd = static_cast(src1); + Operand *base = memopnd->GetBaseRegister(); + if (base->IsRegister()) { + RegOperand *regOpnd = static_cast(base); + if (regOpnd->GetRegisterNumber() != R29) { + return false; + } + } + Riscv64MemOperand *mem = static_cast(src1); + Riscv64OfstOperand *imm = mem->GetOffsetImmediate(); + if (imm != nullptr) { + int32 val = imm->GetOffsetValue(); + CG_ASSERT((val & 0x7) == 0, "Ld/St pair imm offset not 8 aligned"); +#if (DEBUG > 2) + LogInfo::MapleLogger() << "RecordXzrInit - insert xzr " << val << "\n"; +#endif + xzr_init_local_offset.insert(val); + return true; + } + } + return false; +} + +bool Riscv64OptLocalRef::IsLdStPair(Insn *insn) { + switch (insn->mop_) { + case MOP_wldaxp: + case MOP_wstlxp: + CG_ASSERT(0, "Riscv64OptLocalRef IsLdStPair not handle 32 bit"); + case MOP_xldaxp: + case MOP_xstlxp: + return true; + } + return false; +} + +/* Make sure mem operand is af a certain format. + */ +bool Riscv64OptLocalRef::CanGetMemOpndImm(Operand *src, int32 &val) { + CG_ASSERT(src->IsMemoryAccessOperand(), "CanGetMemOpndImm - not mem operand"); + MemOperand *memopnd = static_cast(src); + Operand *base = memopnd->GetBaseRegister(); + if (base == nullptr) { + return false; + } + if (base->IsRegister()) { + RegOperand *regOpnd = static_cast(base); + if (regOpnd->GetRegisterNumber() != R29) { + return false; + } + } + Riscv64MemOperand *mem = static_cast(src); + Riscv64OfstOperand *imm = mem->GetOffsetImmediate(); + if (imm == nullptr) { + return false; + } + val = imm->GetOffsetValue(); + return true; +} + +bool Riscv64OptLocalRef::ImmOffUsedInXzrInit(int32 imm) { + MapleSet::iterator it; + for (it = xzr_init_local_offset.begin(); it != xzr_init_local_offset.end(); it++) { + int32 val = static_cast(*it); + if (imm == val) { + return true; + } + } + return false; +} + +bool Riscv64OptLocalRef::ImmOffUsedInLdStPair(int32 imm) { + MapleSet::iterator it; + for (it = ld_st_pair_offset.begin(); it != ld_st_pair_offset.end(); it++) { + int32 val = static_cast(*it); + if (imm == val) { + return true; + } + } + return false; +} + +/* To simplify opt, remove from consideration localrefvar fitting certain + * condition and do not modify these localrefvar. + */ +void Riscv64OptLocalRef::RemoveImmUsedInSkip() { + /* It is possible for MRT to skip initialization and cleanup. + * 1. Skip first location in cleanup. + * 2. Skip last location in cleanup. + * 3. If in middle, use the cleanupskip interface. + * The skipped locations are not relocated at this point. + */ + for (uint32 i = 0; i < cgfunc->NumBBs(); i++) { + Iinfo *insninfo = insn_info_in_bb[i]; + Iinfo *previnfo = nullptr; + while (insninfo != nullptr) { +#if (DEBUG > 3) + LogInfo::MapleLogger() << "bb(" << insninfo->insn->bb->id << ") imm(" << insninfo->imm << ")\n"; +#endif + int32 imm = insninfo->imm; + bool found = false; + MapleSet::iterator it; + for (it = rc_cleanup_skip_num.begin(); it != rc_cleanup_skip_num.end(); it++) { + int32 val = static_cast(*it); + uint32 offset = min_imm + (val << 3); +#if (DEBUG > 3) + LogInfo::MapleLogger() << "\ttest rc_cleanup_skip " << offset << "\n"; +#endif + if (imm == offset) { +#if (DEBUG > 3) + LogInfo::MapleLogger() << "\tfound\n"; +#endif + found = true; + break; + } + } + if (found == false) { + // it is not skipped +#if (DEBUG > 3) + LogInfo::MapleLogger() << "keep cleanup\n"; +#endif + previnfo = insninfo; + insninfo = insninfo->next; + } else if (previnfo == nullptr) { + // remove element +#if (DEBUG > 3) + LogInfo::MapleLogger() << "skip cleanup\n"; +#endif + insninfo = insninfo->next; + insn_info_in_bb[i] = insninfo; + } else { + // remove element +#if (DEBUG > 3) + LogInfo::MapleLogger() << "skip cleanup\n"; +#endif + insninfo = insninfo->next; + previnfo->next = insninfo; + } + } + } +} + +/* To simplify opt, remove from consideration localrefvar fitting certain + * condition and do not modify these localrefvar. + */ +void Riscv64OptLocalRef::RemoveImmUsedInLdSt() { + for (uint32 i = 0; i < cgfunc->NumBBs(); i++) { + Iinfo *insninfo = insn_info_in_bb[i]; + Iinfo *previnfo = nullptr; + while (insninfo != nullptr) { +#if (DEBUG > 3) + LogInfo::MapleLogger() << "bb(" << insninfo->insn->bb->id << ") imm(" << insninfo->imm << ")\n"; +#endif + int32 imm; + imm = insninfo->imm; + bool removed = false; + if (ImmOffUsedInLdStPair(imm) == false) { + // it is not used in ld/st pair +#if (DEBUG > 3) + LogInfo::MapleLogger() << "\tkeep pair\n"; +#endif + } else if (previnfo == nullptr) { + // remove element +#if (DEBUG > 3) + LogInfo::MapleLogger() << "\tskip pair\n"; +#endif + insninfo = insninfo->next; + insn_info_in_bb[i] = insninfo; + removed = true; + } else { + // remove element +#if (DEBUG > 3) + LogInfo::MapleLogger() << "\tskip pair\n"; +#endif + insninfo = insninfo->next; + previnfo->next = insninfo; + removed = true; + } + + if (removed == true) { + continue; + } + + if (ImmOffUsedInXzrInit(imm) == false) { +#if (DEBUG > 3) + LogInfo::MapleLogger() << "\tkeep xzr\n"; +#endif + } else if (previnfo == nullptr) { + // remove element +#if (DEBUG > 3) + LogInfo::MapleLogger() << "\tskip xzr\n"; +#endif + insninfo = insninfo->next; + insn_info_in_bb[i] = insninfo; + removed = true; + } else { + // remove element +#if (DEBUG > 3) + LogInfo::MapleLogger() << "\tskip xzr\n"; +#endif + insninfo = insninfo->next; + previnfo->next = insninfo; + removed = true; + } + + if (removed == true) { + continue; + } + + previnfo = insninfo; + insninfo = insninfo->next; + continue; + } + } +} + +/* Find all localrefvar and intialize a list of themfor each bb. + * Also try to remove localrefvar which should not be touched. + */ +void Riscv64OptLocalRef::OptLRInit() { + /* Discover potential local var stack locations. + * If a memory instruction is a local var but is not marked as auto, + * there are two cases. + * 1) There is no other mem-op with the same location marked as auto. + * In this case do not optimize, which is ok. + * 2) Another mem-op with the same location is marked as auto. + * Need to associate this instruction and location to local var. + * + * There are ldp/stp operate over consecutive stack locations. + * Need to bind these locations together, or do not optimize. + * + * Initially will only optimize stack locations for single dest. + */ + insn_info_in_bb.resize(cgfunc->NumBBs()); + for (uint32 i = 0; i < cgfunc->NumBBs(); i++) { + insn_info_in_bb[i] = nullptr; + } + uint32 icnt = 0; + FOR_ALL_BB(bb, cgfunc) { + if (bb->firststmt == cgfunc->cleanup_label) { +#if (DEBUG > 3) + LogInfo::MapleLogger() << "OptLRInit - cleanup bb " << bb->id << "\n"; +#endif + HandleCleanupBB(bb); + // HandleCleanupBB guarantees we have reached the end of function + break; + } + // LogInfo::MapleLogger() << "bb " << bb->id << "\n"; + FOR_BB_INSNS(insn, bb) { + // insn->dump(); + if (giveup) { +#if (DEBUG > 0) + LogInfo::MapleLogger() << "OptLRInit - give up in insn traversal\n"; +#endif + return; + } + if (insn->mop_ == MOP_comment) { + Operand *src = insn->GetOperand(0); + string str = static_cast(src)->GetComment(); + if (str == "MPL_CLEANUP_LOCALREFVARS") { + for (Insn *ninsn = insn->next; ninsn; ninsn = ninsn->next) { + if (!ninsn->IsCall()) { + continue; + } + FuncNameOperand *target = dynamic_cast(ninsn->GetCallTargetOperand()); + if (target) { + MIRSymbol *funcst = target->GetFunctionSymbol(); + CG_ASSERT(funcst->sKind == kStFunc, ""); + if (funcst->GetName() == GetIntrinsicFuncName(INTRN_MCCIncRef)) { + giveup = true; + return; + } + } + } + } + } + if (IsRcStackCall(insn)) { + continue; + } + if (insn->IsLoad() == false && insn->IsStore() == false) { + continue; + } + if (IsLdStPair(insn) == true) { + RecordLdStPair(insn); + continue; + } + if (RecordXzrInit(insn) == true) { + continue; + } + Operand *src = insn->GetOperand(1); + if (IsLdStLocalRefVar(src) == false) { + continue; + } + // Found target mem-op + int32 imm; + if (CanGetMemOpndImm(src, imm) == false) { + continue; + } + if (imm < min_imm || imm > max_imm) { + continue; + } + if (ImmOffUsedInXzrInit(imm) == true) { + continue; + } + if (ImmOffUsedInLdStPair(imm) == true) { + continue; + } + + insn->id = ++icnt; // Mark this insn as recorded. + Iinfo *insninfo = OptLocalRef::refmp->New(insn, imm); + Iinfo *tmp = insn_info_in_bb[insn->bb->id]; + insn_info_in_bb[insn->bb->id] = insninfo; + insninfo->next = tmp; + } + } + + if ((has_rc_init == false) || (has_rc_cleanup == false)) { +#if (DEBUG > 3) + LogInfo::MapleLogger() << "OptLRInit - give up after analysis\n"; +#endif + giveup = true; + return; + } + + /* There are ld/st which are not marked as local var. + * Need to add them also. + */ + FOR_ALL_BB(bb, cgfunc) { + FOR_BB_INSNS(insn, bb) { + if (insn->id != 0) { + continue; // Already recorded. + } + if (insn->IsLoad() == false && insn->IsStore() == false) { + continue; + } + if (IsLdStPair(insn) == true) { + continue; + } + Operand *src = insn->GetOperand(1); + int32 imm; + if (CanGetMemOpndImm(src, imm) == false) { + continue; + } + if (imm < min_imm) { + continue; + } + if (imm >= max_imm) { + other_opnd.insert(static_cast(src)); + continue; + } + if (ImmOffUsedInXzrInit(imm) == true) { + continue; + } + if (ImmOffUsedInLdStPair(imm) == true) { + continue; + } + + MapleSet::iterator it; + for (it = rc_cleanup_skip_num.begin(); it != rc_cleanup_skip_num.end(); it++) { + int32 val = static_cast(*it); + uint32 offset = min_imm + (val << 3); + if (imm == offset) { +#if (DEBUG > 2) + LogInfo::MapleLogger() << "OptLRInit - CleanupStackSkip skipping " << imm << "\n"; +#endif + continue; + } + } + + insn->id = ++icnt; // Mark this insn as recorded. + Iinfo *insninfo = OptLocalRef::refmp->New(insn, imm); + Iinfo *tmp = insn_info_in_bb[insn->bb->id]; + insn_info_in_bb[insn->bb->id] = insninfo; + insninfo->next = tmp; + } + } + + // Remember the src operands for later renaming. + imm_operands.resize(max_imm - min_imm + 1); + for (uint32 i = 0; i < cgfunc->NumBBs(); i++) { + Iinfo *insninfo = insn_info_in_bb[i]; + if (insninfo == nullptr) { + continue; + } + for (; insninfo; insninfo = insninfo->next) { + int32 imm = insninfo->imm; + uint32 pos = (imm - min_imm) >> 3; +#if (DEBUG > 3) + LogInfo::MapleLogger() << "OptLRInit - bb " << insninfo->insn->bb->id << " imm[" << pos << "]\n"; + insninfo->insn->GetOperand(1)->dump(); + LogInfo::MapleLogger() << "\n"; +#endif + imm_operands[pos] = insninfo->insn->GetOperand(1); + } + } + for (int i = 0; i < ((max_imm - min_imm) >> 3) + 1; i++) { + if (imm_operands[i]) { +#if (DEBUG > 0) + LogInfo::MapleLogger() << "i=" << i << " "; + imm_operands[i]->dump(); + LogInfo::MapleLogger() << "\n"; +#endif + } else { +#if (DEBUG > 0) + LogInfo::MapleLogger() << "i=" << i << "\n"; +#endif + giveup = true; + return; + } + } + + if (ld_st_pair_offset.empty() == false || xzr_init_local_offset.empty() == false) { + // Might have missed some ld/st pairs or xzr init + RemoveImmUsedInLdSt(); + } + // RC stack cleanup can skip, must retain the original mapping. + RemoveImmUsedInSkip(); +} + +/* Clear field for later phases. + */ +void Riscv64OptLocalRef::OptLRFini() { + FOR_ALL_BB(bb, cgfunc) { + FOR_BB_INSNS(insn, bb) { + insn->id = 0; + } + } +} + +/* There are situation where allocation of slots can conflict between + * traces. Attempt to rename the conflict to a higher unused slot. + */ +bool Riscv64OptLocalRef::CanRenameConflictSlot(int32 imm) { + uint32 offset = max_assigned; + while (offset < max_imm) { + offset = offset + 8; + if (ImmOffUsedInXzrInit(offset) || ImmOffUsedInLdStPair(offset)) { + continue; + } + bool matched = false; + MapleSet::iterator sit; + for (sit = rc_cleanup_skip_num.begin(); sit != rc_cleanup_skip_num.end(); sit++) { + int32 val = static_cast(*sit); + if (offset == (min_imm + (val << 3))) { + matched = true; + break; + } + } + if (matched) { + continue; + } + } + + if (offset > max_imm) { + return false; + } + max_assigned = offset; + + FOR_ALL_BB(bb, cgfunc) { + for (Iinfo *info = insn_info_in_bb[bb->id]; info; info = info->next) { + if (info->imm == imm) { + info->assigned = max_assigned; + } + } + } + return true; +} + +/* + * Perform mapping of discovered local ref's immediate offset + * to new offset. + * Does not do the insn modification. Its done later. + */ +void Riscv64OptLocalRef::AssignLocalRefForTrace() { + vector immMap; + vector seen; + vector assigned; + forward_list allocSlot; + + uint32 slots = ((max_imm - min_imm) >> 3) + 1; + immMap.resize(slots); + seen.resize(slots); + assigned.resize(slots); + for (int32 i = (slots - 1); i >= 0; i--) { + immMap[i] = 0; + seen[i] = false; + assigned[i] = false; + allocSlot.push_front(i); + } + + /* Get the already mapped offsets. + * Remove them from allocation slot. + */ + MapleList::iterator it; + for (it = bb_trace.begin(); it != bb_trace.end(); it++) { + BB *bb = *it; + // LogInfo::MapleLogger() << "\tAssign - bb " << bb->id << "\n"; + if (visited_bbs[bb->id] == false) { + continue; + } + Iinfo *info = nullptr; + // LogInfo::MapleLogger() << "bb " << bb->id << "\n"; + for (info = insn_info_in_bb[bb->id]; info; info = info->next) { + int32 imm = info->imm; + uint32 pos = (imm - min_imm) >> 3; + // LogInfo::MapleLogger() << "\tpos " << pos << " of imm " << imm << " assign " << info->assigned << "\n"; + if ((seen[pos] == false && assigned[(info->assigned - min_imm) >> 3]) || + (seen[pos] && immMap[pos] != info->assigned)) { + // Mapping conflict, abort + if (CanRenameConflictSlot(imm) == false) { + giveup = true; + return; + } + // LogInfo::MapleLogger() << "\tconflict after assign " << info->assigned << "\n"; + } + immMap[pos] = info->assigned; + seen[pos] = true; + + pos = (info->assigned - min_imm) >> 3; + assigned[pos] = true; + allocSlot.remove(pos); + } + } + + /* Some slots should not be changed. + * Remove them from allocation slot. + */ + for (int32 i = 0; i < slots; i++) { + uint32 offset = min_imm + (i >> 3); + if (ImmOffUsedInXzrInit(offset) || ImmOffUsedInLdStPair(offset)) { + immMap[i] = offset; + allocSlot.remove((offset - min_imm) >> 3); + } + } + MapleSet::iterator sit; + for (sit = rc_cleanup_skip_num.begin(); sit != rc_cleanup_skip_num.end(); sit++) { + int32 val = static_cast(*sit); + uint32 offset = min_imm + (val << 3); + immMap[val] = offset; + allocSlot.remove(val); + } + // New assignments + for (it = bb_trace.begin(); it != bb_trace.end(); it++) { + uint32 nextAllocSlot; + BB *bb = *it; + if (visited_bbs[bb->id]) { + continue; + } +#if (DEBUG > 0) + LogInfo::MapleLogger() << "AssignLocalRefForTrace - bb " << bb->id << "\n"; +#endif + visited_bbs[bb->id] = true; + for (Iinfo *info = insn_info_in_bb[bb->id]; info; info = info->next) { + int32 imm = info->imm; + uint32 pos = (imm - min_imm) >> 3; + if (immMap[pos] == 0) { + // Not assigned from previous traces. Assign new. + if (allocSlot.empty() == true) { + // Ran out of stack slots. + giveup = true; + return; + } + nextAllocSlot = allocSlot.front(); + allocSlot.pop_front(); + int32 assign = (nextAllocSlot << 3) + min_imm; + immMap[pos] = info->assigned = assign; + if (assign > max_assigned) { + max_assigned = assign; + } +#if (DEBUG > 0) + LogInfo::MapleLogger() << "empty pos " << pos << " of imm " << imm << " assgined " << info->assigned << "\n"; +#endif + } else { + info->assigned = immMap[pos]; +#if (DEBUG > 0) + LogInfo::MapleLogger() << "mapped pos " << pos << " of imm " << imm << " assigned " << info->assigned << "\n"; +#endif + } + } + } +} + +/* Generating a trace. + */ +void Riscv64OptLocalRef::DFS() { + // There should be no cycle at this point. + BB *bb = nullptr; + bool childPushed; + while (dfs_bbs.empty() == false) { + bb = dfs_bbs.top(); + dfs_bbs.pop(); + bb_trace.push_front(bb); + +#if (DEBUG > 5) + LogInfo::MapleLogger() << "\tvisit bb " << bb->id << " sz " << bb_trace.size() << "\n"; +#endif + childPushed = false; + MapleList::iterator it; + for (it = bb->succs.begin(); it != bb->succs.end(); ++it) { + BB *ibb = *it; + dfs_bbs.push(ibb); + childPushed = true; + } + for (it = bb->eh_succs.begin(); it != bb->eh_succs.end(); ++it) { + BB *ibb = *it; + dfs_bbs.push(ibb); + childPushed = true; + } + if ((bb->succs.size() + bb->eh_succs.size()) > 1) { + // On a cfg fork, need to walk back bb_trace list. + bb_walkback.push(bb); + } + if (childPushed == false) { + num_traces++; + if ((num_traces > kMaxNumTraces) || (bb_trace.size() > kMaxTraceLen)) { +#if (DEBUG > 0) + LogInfo::MapleLogger() << "DoOptimize - give up with too many traces\n"; + LogInfo::MapleLogger() << "num_traces " << num_traces << " MAX " << kMaxNumTraces << "\n"; + LogInfo::MapleLogger() << "trace size " << bb_trace.size() << " MAX " << kMaxTraceLen << "\n"; +#endif + giveup = true; + return; // Give up on large traces + } +#if (DEBUG > 0) + PrintBbTraceList("TRACE"); +#endif + AssignLocalRefForTrace(); + if (giveup) { +#if (DEBUG > 0) + LogInfo::MapleLogger() << "DoOptimize - give up with mapping conflicts\n"; +#endif + return; + } + // Walk back bb_trace list. + bool found = false; + do { + if (bb_walkback.empty()) { + break; + } + BB *lastForkBB = bb_walkback.top(); + if (bb_trace.front() != lastForkBB) { + do { + bb_trace.pop_front(); + } while (bb_trace.front() != lastForkBB); +#if (DEBUG > 4) + PrintBbTraceList("POP"); +#endif + } + /* When all child of the last_fork_bb has been visited + * (ie. every child is a part of a bb_trace) + * remove last_fork_bb from bb_walkback. + */ + if (dfs_bbs.empty() == false) { + // The next bb to be visited + // See if it is a child of last_fork_bb. + BB *dfsTopBb = dfs_bbs.top(); + for (it = lastForkBB->succs.begin(); it != lastForkBB->succs.end(); ++it) { + BB *ibb = *it; + if (ibb == dfsTopBb) { + found = true; + break; + } + } + if (found == false) { + for (it = lastForkBB->eh_succs.begin(); it != lastForkBB->eh_succs.end(); ++it) { + BB *ibb = *it; + if (ibb == dfsTopBb) { + found = true; + break; + } + } + } + } + if (found == false) { + // All successors visited, walkback. +#if (DEBUG > 4) + LogInfo::MapleLogger() << "\tpop walkback << " << bb_walkback.top()->id << "\n"; +#endif + bb_walkback.pop(); + } + } while (found == false); + } + } +} + +void Riscv64OptLocalRef::DoOptimize() { + visited_bbs.resize(cgfunc->NumBBs()); + for (uint32 i = 0; i < cgfunc->NumBBs(); i++) { + visited_bbs[i] = false; + } + while (dfs_bbs.empty() == false) { + dfs_bbs.pop(); + } + +#if (DEBUG > 0) + LogInfo::MapleLogger() << "min " << min_imm << " max " << max_imm << "\n"; +#endif + dfs_bbs.push(cgfunc->firstbb); + DFS(); + + if (max_assigned >= max_imm) { +#if (DEBUG > 0) + LogInfo::MapleLogger() << "DoOptimize - No benefit, giveup\n"; +#endif + giveup = true; + } +} + +/* Rename the slots for localrefvar. + */ +void Riscv64OptLocalRef::FinalizeLocRef() { + // Modify the actual insn. +#if (DEBUG > 0) + LogInfo::MapleLogger() << "FinalizeLocRef " << cgfunc->GetName() << "\n"; +#endif + FOR_ALL_BB(bb, cgfunc) { + if (visited_bbs[bb->id] == false) { + continue; // unreachable + } +#if (DEBUG > 0) + LogInfo::MapleLogger() << "bb " << bb->id << "\n"; +#endif + for (Iinfo *info = insn_info_in_bb[bb->id]; info; info = info->next) { + Insn *insn = info->insn; +#if (DEBUG > 0) + insn->dump(); + LogInfo::MapleLogger() << "===== assign =====>" << info->assigned << "\n"; +#endif + Operand *src = imm_operands[(info->assigned - min_imm) >> 3]; + CG_ASSERT(src, "FinalizeLocRef - no operand"); + insn->SetOperand(1, src); + } + } + + /* There are some memory operand offsets beyond the local vars that has already + * been computed based on the old local var slot numbers. Correct them. + */ + int32 diff = rc_stack_init_start_loc + rc_localrefvar_slots * 8 - (max_assigned + 8); + for (auto it = other_opnd.begin(); it != other_opnd.end(); it++) { + Riscv64MemOperand *src = *it; + Riscv64OfstOperand *ofstopnd = src->GetOffsetImmediate(); + int32 offset = ofstopnd->GetOffsetValue(); + if (offset <= max_assigned) { + continue; + } + Riscv64OfstOperand *offsetOpnd = cgfunc->memPool->New(offset - diff, 64); + src->SetOffsetImmediate(offsetOpnd); + } +} + +/* Patch the MRT calls. + */ +void Riscv64OptLocalRef::FixMrtCall() { + MapleStack::iterator it; + uint32 val = ((max_assigned - min_imm) >> 3) + 1; + for (it = rc_init_call.begin(); it != rc_init_call.end(); ++it) { + Insn *call = *it; + ModifyParamValue(call, R1, val); + } + for (it = rc_cleanup_call.begin(); it != rc_cleanup_call.end(); ++it) { + Insn *call = *it; + ModifyParamValue(call, R0, rc_stack_init_start_loc); + ModifyParamValue(call, R1, val); + } + for (it = rc_skip_call.begin(); it != rc_skip_call.end(); ++it) { + Insn *call = *it; + ModifyParamValue(call, R1, val); + } + // Update the new size of the local var on the stack. + static_cast(cgfunc->memlayout)->Reflocals().size = val * SIZEOFPTR; +} + +} // namespace maplebe diff --git a/mapleall/maple_be/src/cg/riscv64/riscv64_mem_layout.cpp b/mapleall/maple_be/src/cg/riscv64/riscv64_mem_layout.cpp new file mode 100644 index 0000000..2f94e2c --- /dev/null +++ b/mapleall/maple_be/src/cg/riscv64/riscv64_mem_layout.cpp @@ -0,0 +1,494 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#include "riscv64_mem_layout.h" +#include "riscv64_cg_func.h" +#include "riscv64_rt_support.h" +#include "be_common.h" +#include "mir_nodes.h" +#include "special_func.h" + +namespace maplebe { + +using namespace maple; + +#define CLANG (be.mirModule.IsCModule()) + +/* + Returns stack space required for a call + which is used to pass arguments that cannot be + passed through registers + */ +uint32 Riscv64MemLayout::ComputeStackSpaceRequirementForCall(StmtNode *stmt, int32 &aggCopySize, bool isIcall) { + ParmLocator parmlocator(be); // instantiate a parm locator + uint32 sizeOfArgsToStkpass = 0; + int32 i = 0; + if (isIcall) { /* An indirect call's first operand is the invocation target */ + i++; + } + + CallNode *callnode = dynamic_cast(stmt); + if (callnode) { + MIRFunction *fn = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(callnode->puIdx); + MIRSymbol *fsym = be.mirModule.CurFunction()->GetLocalOrGlobalSymbol(fn->stIdx, false); + if (IsRtNativeCall(fsym->GetName())) { + i++; + } + } + + bool varargFunc = false; + uint32 namedFormals = 0; + varargFunc = static_cast(cgfunc)->CallIsVararg(stmt, namedFormals, nullptr); + + int32 structCopySize = 0; + uint32 typesize = 0; + for (uint32 anum = 0; i < stmt->NumOpnds(); ++i, ++anum) { + base_node_t *opnd = stmt->Opnd(i); + MIRType *ty = nullptr; + if (opnd->primType != PTY_agg) { + ty = GlobalTables::GetTypeTable().typeTable[static_cast(opnd->primType)]; + typesize = be.type_size_table.at(ty->tyIdx.GetIdx()); + } else { + Opcode opndOpcode = opnd->op; + CG_ASSERT(opndOpcode == OP_dread || opndOpcode == OP_iread, ""); + if (opndOpcode == OP_dread) { + DreadNode *dread = static_cast(opnd); + MIRSymbol *sym = be.mirModule.CurFunction()->GetLocalOrGlobalSymbol(dread->stIdx); + ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(sym->GetTyIdx()); + typesize = be.type_size_table.at(ty->tyIdx.GetIdx()); + if (dread->fieldID != 0) { + CG_ASSERT(ty->typeKind == kTypeStruct || ty->typeKind == kTypeClass || + ty->typeKind == kTypeUnion, ""); + FieldPair thepair; + if (ty->typeKind == kTypeStruct || ty->typeKind == kTypeUnion) { + thepair = static_cast(ty)->TraverseToField(dread->fieldID); + } else { + thepair = static_cast(ty)->TraverseToField(dread->fieldID); + } + ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(thepair.second.first); + } + } else { // OP_iread + IreadNode *iread = static_cast(opnd); + ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(iread->tyIdx); + CG_ASSERT(ty->typeKind == kTypePointer, ""); + ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(static_cast(ty)->pointedTyIdx); + typesize = be.type_size_table.at(ty->tyIdx.GetIdx()); + if (iread->fieldID != 0) { + CG_ASSERT(ty->typeKind == kTypeStruct || ty->typeKind == kTypeClass || + ty->typeKind == kTypeUnion, ""); + FieldPair thepair; + if (ty->typeKind == kTypeStruct || ty->typeKind == kTypeUnion) { + thepair = static_cast(ty)->TraverseToField(iread->fieldID); + } else { + thepair = static_cast(ty)->TraverseToField(iread->fieldID); + } + ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(thepair.second.first); + } + } + } + PLocInfo ploc; + bool variadArg = varargFunc && (anum+1 > namedFormals); + structCopySize += parmlocator.LocateNextParm(ty, ploc, false, variadArg); + if (ploc.reg0 != 0 && !(typesize > 8 && ploc.reg1 == 0)) { + continue; // passed in register, so no effect on actual area + } + sizeOfArgsToStkpass = RoundUp(ploc.memoffset + ploc.memsize, SIZEOFPTR); + } + aggCopySize = structCopySize; + return sizeOfArgsToStkpass; +} + +void Riscv64MemLayout::LayoutStackFrame(int32 &structCopySize, int32 &maxParmStackSize) { + MIRSymbol *sym = nullptr; + ParmLocator parmlocator(be); + PLocInfo ploc; + bool nostackpara = false; + + // Count named args passed in registers + if (CLANG && func->GetAttr(FUNCATTR_varargs)) { + uint32 nintregs = 0; + ParmLocator vparmlocator(be); + PLocInfo vploc; + for (uint32 i = 0; i < func->formalDefVec.size(); i++) { + if (i == 0) { + auto funcIt = be.funcReturnType.find(func); + if (funcIt != be.funcReturnType.end() && be.type_size_table[funcIt->second.GetIdx()] <= 16) { + continue; + } + } + MIRType *ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(func->formalDefVec[i].formalTyIdx); + uint32_t ptyIdx = ty->tyIdx.GetIdx(); + vparmlocator.LocateNextParm(ty, vploc); + if (vploc.reg0 != kRinvalid) { + if (vploc.reg0 >= R10 && vploc.reg0 <= R17) { + nintregs++; + } + } + if (vploc.reg1 != kRinvalid) { + if (vploc.reg1 >= R10 && vploc.reg1 <= R17) { + nintregs++; + } + } + } + //LogInfo::MapleLogger() << "Number of named int regs: " << nintregs << endl; + seg_GRSavearea.size = (8 - nintregs) * SIZEOFPTR; + } + std::vector retDelays; + for (uint32 i = 0; i < func->formalDefVec.size(); i++) { + sym = func->formalDefVec[i].formalSym; + nostackpara = false; + uint32 stindex = sym->GetStIndex(); + Riscv64SymbolAlloc *symloc = mem_allocator->GetMemPool()->New(); + sym_alloc_table[stindex] = symloc; + CG_ASSERT(symloc, "sym loc should have been defined"); + if (i == 0) { + MIRFunction *func = be.mirModule.CurFunction(); + if (func->IsReturnStruct()) { + auto funcIt = be.funcReturnType.find(func); + if (funcIt != be.funcReturnType.end()) { + symloc->mem_segment = &seg__args_regpassed; + symloc->offset = seg__args_regpassed.size; + if (be.type_size_table[funcIt->second.GetIdx()] > 16) { + seg__args_regpassed.size += SIZEOFPTR; + } + continue; + } + } + } + MIRType *ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(func->formalDefVec[i].formalTyIdx); + uint32_t ptyIdx = ty->tyIdx.GetIdx(); + parmlocator.LocateNextParm(ty, ploc, i == 0); + uint32 align = be.type_align_table[ptyIdx]; + uint32 msize = be.type_size_table[ptyIdx]; + if (be.type_size_table[ptyIdx] > 16) { + align = 8; // size > 16 is passed on stack, the formal is just a pointer + msize = SIZEOFPTR; + } + if (ploc.reg0 != kRinvalid) { // register + + if (false && sym->IsRefType()) { + symloc->SetRegisters(ploc.reg0, ploc.reg1); + symloc->mem_segment = &seg_reflocals; + seg_reflocals.size = RoundUp(seg_reflocals.size, align); + symloc->offset = seg_reflocals.size; + seg_reflocals.size += msize; + seg_reflocals.size = RoundUp(seg_reflocals.size, SIZEOFPTR); + } else { + symloc->SetRegisters(ploc.reg0, ploc.reg1); + if (!sym->IsPreg()) { + symloc->mem_segment = &seg__args_regpassed; + + // the type's alignment requirement may be smaller than a registser's byte size + seg__args_regpassed.size = RoundUp(seg__args_regpassed.size, align); + symloc->offset = seg__args_regpassed.size; + seg__args_regpassed.size += msize; + } else { + nostackpara = true; + } + if (ploc.reg1 == kRinvalid && msize > 8) { // half in reg, half on stack + // the 2nd half on stack does not have individual symloc, it's to be + // assigned in MoveRegargs() into its local variable. Just increment + // the stkpassed size so subsequent stack args are properly located. + seg__args_stkpassed.size = RoundUp(seg__args_stkpassed.size, SIZEOFPTR); + seg__args_stkpassed.size += SIZEOFPTR; + } + } + } else { // stack + symloc->mem_segment = &seg__args_stkpassed; + seg__args_stkpassed.size = RoundUp(seg__args_stkpassed.size, align); + symloc->offset = seg__args_stkpassed.size; + seg__args_stkpassed.size += msize; + // We need it as dictated by the Riscv64 ABI $5.4.2 C12 + seg__args_stkpassed.size = RoundUp(seg__args_stkpassed.size, SIZEOFPTR); + } + if (cgfunc->cg->cgopt_.WithDwarf() && !nostackpara) { + // for O0 + // LogInfo::MapleLogger() << "Add DIE for formal parameters" << endl + // << " and remember them" << endl; + cgfunc->AddDIESymbolLocation(sym, symloc); + } + } + + // We do need this as LDR/STR with immediate + // requires imm be aligned at a 8/4-byte boundary, + // and local varirables may need 8-byte alignment. + seg__args_regpassed.size = RoundUp(seg__args_regpassed.size, SIZEOFPTR); + // we do need this as SP has to be aligned at a 16-bytes bounardy + seg__args_stkpassed.size = RoundUp(seg__args_stkpassed.size, SIZEOFPTR * 2); + // allocate the local variables in the stack + uint32 symtabsize = (func->symTab == nullptr ? 0 : func->symTab->GetSymbolTableSize()); + for (uint32 i = 0; i < symtabsize; i++) { + sym = func->symTab->GetSymbolFromStIdx(i); + if (!sym || sym->storageClass != kScAuto || sym->IsDeleted()) { + continue; + } + uint32 stindex = sym->GetStIndex(); + TyIdx tyIdx = sym->GetTyIdx(); + MIRType *ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx); + uint32 align = be.type_align_table[tyIdx.GetIdx()]; + Riscv64SymbolAlloc *symloc = mem_allocator->GetMemPool()->New(); + sym_alloc_table[stindex] = symloc; + CG_ASSERT(!symloc->IsRegister(), ""); + + if (sym->IsRefType()) { + if (func->retRefSym.find(sym) != func->retRefSym.end()) { + // try to put ret_ref at the end of seg_reflocals + retDelays.push_back(sym); + continue; + } + symloc->mem_segment = &seg_reflocals; + if (ty->GetPrimType() == PTY_agg && align < 8) { + seg_reflocals.size = RoundUp(seg_reflocals.size, 8); + } else { + seg_reflocals.size = RoundUp(seg_reflocals.size, align); + } + symloc->offset = seg_reflocals.size; + seg_reflocals.size += be.type_size_table[tyIdx.GetIdx()]; + + } else { + symloc->mem_segment = &seg_locals; + if (ty->GetPrimType() == PTY_agg && align < 8) { + seg_locals.size = RoundUp(seg_locals.size, 8); + } else { + seg_locals.size = RoundUp(seg_locals.size, align); + } + if (func->stackallocVarMap.find(sym) != func->stackallocVarMap.end()) { + symloc->offset = seg_locals.size; + MapleMap::iterator it = func->stackallocVarMap.find(sym); + seg_locals.size += it->second; + // LogInfo::MapleLogger()<<"symbol "<GetName()<<" offset "<offset<<" size "<second<typeKind == kTypeClass) { + // If this is a non-escaped object allocated on stack, we need to + // manufacture an extra object header for RC to work correctly + seg_locals.size += Riscv64RTSupport::kObjectHeaderSize; + } + symloc->offset = seg_locals.size; + seg_locals.size += be.type_size_table[tyIdx.GetIdx()]; + } + } + + if (cgfunc->cg->cgopt_.WithDwarf()) { + // for O0 + // LogInfo::MapleLogger() << "Add DIE for formal parameters" << endl + // << " and remember them" << endl; + cgfunc->AddDIESymbolLocation(sym, symloc); + } + } + + // handle ret_ref sym now + uint32 retsize = retDelays.size(); + for (uint32 i = 0; i < retsize; i++) { + sym = retDelays[i]; + uint32 stindex = sym->GetStIndex(); + TyIdx tyIdx = sym->GetTyIdx(); + Riscv64SymbolAlloc *symloc = mem_allocator->GetMemPool()->New(); + sym_alloc_table[stindex] = symloc; + CG_ASSERT(!symloc->IsRegister(), ""); + + CG_ASSERT(sym->IsRefType(), ""); + symloc->mem_segment = &seg_reflocals; + seg_reflocals.size = RoundUp(seg_reflocals.size, be.type_align_table[tyIdx.GetIdx()]); + symloc->offset = seg_reflocals.size; + seg_reflocals.size += be.type_size_table[tyIdx.GetIdx()]; + + if (cgfunc->cg->cgopt_.WithDwarf()) { + // for O0 + // LogInfo::MapleLogger() << "Add DIE for formal parameters" << endl + // << " and remember them" << endl; + cgfunc->AddDIESymbolLocation(sym, symloc); + } + } + + seg__args_to_stkpass.size = FindLargestActualArea(structCopySize); + maxParmStackSize = seg__args_to_stkpass.size; + if (g->optim_level < 2) { + AssignSpillLocationsToPseudoRegisters(); + } else { + Riscv64CGFunc *rvCgfunc = static_cast(cgfunc); + rvCgfunc->SetJavaCatchRegno(cgfunc->New_V_Reg(kRegTyInt, 8)); + } + + seg_reflocals.size = RoundUp(seg_reflocals.size, SIZEOFPTR); + seg_locals.size = RoundUp(seg_locals.size, SIZEOFPTR); + + // for the actual arguments that cannot be pass through registers + // need to allocate space for caller-save registers + for (uint32 i = 0; i < func->formalDefVec.size(); i++) { + if (i == 0) { + MIRFunction *func = be.mirModule.CurFunction(); + if (func->IsReturnStruct()) { + auto funcIt = be.funcReturnType.find(func); + if (funcIt != be.funcReturnType.end()) { + continue; + } + } + } + sym = func->formalDefVec[i].formalSym; + if (sym->IsPreg()) { + continue; + } + uint32 stindex = sym->GetStIndex(); + Riscv64SymbolAlloc *symloc = static_cast(sym_alloc_table[stindex]); + if (symloc->mem_segment == &seg__args_regpassed) { // register + /* + In O0, we store parameters passed via registers into memory. + So, each of such parameter needs to get assigned storage in stack. + If a function parameter is never accessed in the function body, + and if we don't create its memory operand here, its offset gets + computed when the instruction to store its value into stack + is generated in the prologue when its memory operand is created. + But, the parameter would see a different StackFrameSize than + the parameters that are accessed in the body, because + the size of the storage for FP/LR is added to the stack frame + size in between. + To make offset assignment easier, we create a memory operand + for each of function parameters in advance. + This has to be done after all of formal parameters and local + variables get assigned their respecitve storage, i.e. + CallFrameSize (discounting callee-saved and FP/LR) is known. + */ + MIRType *ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(func->formalDefVec[i].formalTyIdx); + uint32_t ptyIdx = ty->tyIdx.GetIdx(); + static_cast(cgfunc)->GetOrCreateMemOpnd(sym, 0, be.type_align_table[ptyIdx] * BITS_PER_BYTE); + } + } + + fixstacksize = RealStackFrameSize(); +} + +void Riscv64MemLayout::AssignSpillLocationsToPseudoRegisters() { + MIRPregTable *pregTab = cgfunc->func->pregTab; + + size_t nRegs = pregTab->Size(); + spill_loc_table.resize(nRegs); + for (uint32 i = 1; i < nRegs; i++) { + PrimType primType = pregTab->PregFromPregIdx(i)->primType; + Riscv64SymbolAlloc *symloc = mem_allocator->GetMemPool()->New(); + symloc->mem_segment = &seg_locals; + seg_locals.size = RoundUp(seg_locals.size, GetPrimTypeSize(primType)); + symloc->offset = seg_locals.size; + MIRType *mirty = GlobalTables::GetTypeTable().typeTable[primType]; + seg_locals.size += be.type_size_table[mirty->tyIdx.GetIdx()]; + + spill_loc_table[i] = symloc; + } + + // Allocate additional stack space for "thrownval". + seg_locals.size = RoundUp(seg_locals.size, 8); + Riscv64CGFunc *aarchCgfunc = static_cast(cgfunc); + RegOperand *baseOpnd = aarchCgfunc->GetOrCreateStackBaseRegOperand(); + int32 offset = seg_locals.size + seg_lockobjslot.size; + + if (!aarchCgfunc->UseFP() && !aarchCgfunc->HasVLAOrAlloca() && seg__args_to_stkpass.size > 0) { + offset += seg__args_to_stkpass.size; + } + + Riscv64OfstOperand *offsetOpnd = aarchCgfunc->memPool->New(offset + 16, 64); + Riscv64MemOperand *throwmem = aarchCgfunc->memPool->New( + 64, baseOpnd, static_cast(nullptr), offsetOpnd, nullptr); + aarchCgfunc->SetJavaCatchOpnd(throwmem); + aarchCgfunc->gen_memopnds_requiring_offset_adjustment_.insert(throwmem); + seg_locals.size += 8; +} + +SymbolAlloc *Riscv64MemLayout::AssignLocationToSpillReg(regno_t vrnum) { + Riscv64SymbolAlloc *symloc = mem_allocator->GetMemPool()->New(); + symloc->mem_segment = &seg__spillreg; + uint32_t regsize = cgfunc->GetVRegSize(vrnum); + seg__spillreg.size = RoundUp(seg__spillreg.size, regsize); + symloc->offset = seg__spillreg.size; + seg__spillreg.size += regsize; + spillreg_loc_map[vrnum] = symloc; + return symloc; +} + +int32 Riscv64MemLayout::GetadjustforRefloc() { + int32 total = seg__args_regpassed.size + locals().size + GetSizeOfSpillReg(); + Riscv64CGFunc *aarchCgfunc = static_cast(cgfunc); + if (!aarchCgfunc->UseFP() && !aarchCgfunc->HasVLAOrAlloca() && seg__args_to_stkpass.size > 0) { + total += seg__args_to_stkpass.size; + } + return total; +} + +int32 Riscv64MemLayout::StackFrameSize() { + int32 total = seg__args_regpassed.size + + static_cast(cgfunc)->SizeOfCalleeSaved() + + GetSizeOfRefLocals() + + locals().size + + GetSizeOfSpillReg() + + seg_lockobjslot.size; + + if (GetSizeOfGRSavearea() > 0) { + total += RoundUp(GetSizeOfGRSavearea(), RISCV64_STACK_PTR_ALIGNMENT); + } + + // if the function does not have VLA nor alloca, + // we allocate space for arguments to stack-pass + // in the call frame; otherwise, it has to be allocated for each call and reclaimed afterward. + total += seg__args_to_stkpass.size; + int finalsize = RoundUp(total, RISCV64_STACK_PTR_ALIGNMENT); + if (finalsize - total >= 8) { + unusedslot = true; + } else { + unusedslot = false; + } + + return finalsize; +} + +bool Riscv64MemLayout::GetUnusedSlot() { + return unusedslot; +} + +int32 Riscv64MemLayout::RealStackFrameSize() { + int32 size = StackFrameSize(); + if (cgfunc->cg->AddStackGuard()) { + size += RISCV64_STACK_PTR_ALIGNMENT; + } + return size; +} + +void Riscv64MemLayout::AdjustOffsetForCalleeSaved(SymbolAlloc &sym) { + sym.offset += static_cast(cgfunc)->SizeOfCalleeSaved(); +} + +int32 Riscv64MemLayout::GetReflocbaseLoc() { + Riscv64CGFunc *aarchCgfunc = static_cast(cgfunc); + int32 beforesize = GetSizeOfLocals() + seg_lockobjslot.size; + int32 argsToStkpassSize = SizeOfArgsToStackpass(); + if (!aarchCgfunc->UseFP() && !aarchCgfunc->HasVLAOrAlloca() && argsToStkpassSize > 0) { + beforesize += argsToStkpassSize; + } + int sizeofFplr = 2 * kIntregBytelen; + if (!aarchCgfunc->ShouldSaveFPLR() || aarchCgfunc->UsedStpSubPairForCallFrameAllocation()) { + return beforesize; + } + return beforesize + sizeofFplr; +} + +int32 Riscv64MemLayout::GetGRSaveareaBaseLoc() { + int32 total = RealStackFrameSize() - + RoundUp(GetSizeOfGRSavearea(), RISCV64_STACK_PTR_ALIGNMENT); + + Riscv64CGFunc *aarchCgfunc = static_cast(cgfunc); + if (aarchCgfunc->UseFP()) { + total -= SizeOfArgsToStackpass(); + } + return total; +} + +} // namespace maplebe diff --git a/mapleall/maple_be/src/cg/riscv64/riscv64_operand.cpp b/mapleall/maple_be/src/cg/riscv64/riscv64_operand.cpp new file mode 100644 index 0000000..a492f3d --- /dev/null +++ b/mapleall/maple_be/src/cg/riscv64/riscv64_operand.cpp @@ -0,0 +1,213 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#include "riscv64_operand.h" +#include "riscv64_abi.h" +#include "riscv64_cg_func.h" +#include "riscv64_cg.h" +#include "cg_assert.h" +#include +#include + +namespace maplebe { + +Riscv64RegOperand Riscv64RegOperand::zero64(RZERO, 64, kRegTyInt); +Riscv64RegOperand Riscv64RegOperand::zero32(RZERO, 32, kRegTyInt); + +ImmFPZeroOperand *ImmFPZeroOperand::instance32 = nullptr; +ImmFPZeroOperand *ImmFPZeroOperand::instance64 = nullptr; + +bool Riscv64RegOperand::IsSaveReg(MIRType *type, BECommon &becommon) { + ReturnMechanism retmech(type, becommon); + if (retmech.regcount > 0) { + return GetRegisterNumber() == retmech.reg0 || GetRegisterNumber() == retmech.reg1; + } + return false; +} + +void Riscv64RegOperand::Emit(Emitter &emitter, OpndProp *prop) { + CG_ASSERT((!prop || (static_cast(prop)->opnd_ty_ == Operand::Opd_Register)), + "operand type doesn't match"); + // prop null means a sub emit, i.e from MemOperand + uint8 size = prop ? static_cast(prop)->size_ : size_; + switch (GetRegisterType()) { + case kRegTyInt: { + CG_ASSERT((size == 32 || size == 64), "illegal register size"); +#ifdef USE_32BIT_REF + bool r32 = (size == 32) || isreffield_; +#else + bool r32 = (size == 32); +#endif // USE_32BIT_REF + emitter.Emit(Riscv64CG::intRegNames[(r32 ? Riscv64CG::kR32List : Riscv64CG::kR64List)][reg_no_]); + break; + } + case kRegTyFloat: { + bool isSimdvec = (size == 128); + CG_ASSERT((size == 8 || size == 16 || size == 32 || size == 64 || isSimdvec), + "illegal register size"); + if (IsSimdVectorMode()) { + // see if it is slot 0 or 1 of simd + if (reg_no_ >= VB64) { + reg_no_ = reg_no_ - VB64 + V0; + } else if (reg_no_ >= VB32) { + reg_no_ = reg_no_ - VB32 + V0; + } + if (isSimdvec) { + const Riscv64MD *md = &Riscv64CG::kMd[emitter.GetCurrentMOP()]; + if (md->IsMemAccess()) { + // emit things like str q0, [x1] ldr q1, .LB_testx2 + emitter.Emit(Riscv64CG::intRegNames[Riscv64CG::kV128List][reg_no_]); + } else { + emitter.Emit(Riscv64CG::intRegNames[(Riscv64CG::kV64List)][reg_no_]); + // emit things like dup v0.4s, w1; add v0.4s, v0.4s, v1.4s + emitter.Emit(GetSimdVectorType() == kVecDouble ? ".2d" : ".4s"); + } + } else { // not simd vector + emitter.Emit(Riscv64CG::intRegNames[(Riscv64CG::kV64List)][reg_no_]); + if (GetSimdVectorType() == kVecDouble) { + // 2 * 64bits + emitter.Emit(".d["); + CG_ASSERT(0, "Riscv64RegOperand::Emit - unsupported 128 bit simd"); + } else { + emitter.Emit(".s["); + } + int pos = GetSimdVectorPosition(); + switch (pos) { + case 0: + emitter.Emit("0]"); + break; + case 1: + emitter.Emit("1]"); + break; + case 2: + emitter.Emit("2]"); + break; + case 3: + emitter.Emit("3]"); + break; + } + } + } else { + /* + * FP reg cannot be reffield_. + */ + //#ifdef USE_32BIT_REF + // bool r32 = (size == 32) || isreffield_; + // uint32_t regset = r32 ? Riscv64CG::kR32List : (__builtin_ctz(size) - 3); + //#else + uint32_t regset = __builtin_ctz(size) - 3; + //#endif //USE_32BIT_REF + emitter.Emit(Riscv64CG::intRegNames[regset][reg_no_]); + } + break; + } + default: + CG_ASSERT(false, "NYI"); + break; + } +} + +bool Riscv64RegOperand::IsSPOrFP() { + if (!is_virtual && (reg_no_ == 30 || reg_no_ == 32)) { + return true; + } else { + return false; + } +} + +Operand *Riscv64MemOperand::GetOffset() { + return GetOffsetOperand(); +} + +void Riscv64MemOperand::Emit(Emitter &emitter, OpndProp *prop) { + Riscv64OpndProp *opndprop = static_cast(prop); + const Riscv64MD *md = &Riscv64CG::kMd[emitter.GetCurrentMOP()]; + bool is64bit = md->Is64Bit(); + bool isVector = md->IsVector(); + bool isLDSTpair = md->IsLoadStorePair(); +#if DEBUG + CG_ASSERT(isVector || is64bit || md->GetOperandSize() <= 32, ""); +#endif + Riscv64OfstOperand *offset = GetOffsetImmediate(); + if (offset) { + if (CGOptions::doPIC && offset->op_kind_ == Opd_StImmediate && + (((StImmOperand *)offset)->GetSymbol()->GetStorageClass() == kScGlobal || + ((StImmOperand *)offset)->GetSymbol()->GetStorageClass() == kScExtern)) { + emitter.Emit("#:got_lo12:"); + emitter.Emit(((StImmOperand *)offset)->GetName()); + } else { + CG_ASSERT(!IsPIMMOffsetOutOfRange(offset->GetOffsetValue(), size_), ""); + if (!offset->IsZero()) { + offset->Emit(emitter, nullptr); + } + } + } + emitter.Emit("("); + Riscv64RegOperand *baseReg = static_cast(GetBaseRegister()); + CG_ASSERT(baseReg, "expect an Riscv64RegOperand here"); + if (CGOptions::doPIC && (baseReg->GetSize() != 64)) { + baseReg->SetSize(64); + } + baseReg->Emit(emitter, nullptr); + emitter.Emit(")"); +} + +void Riscv64MemOperand::dump() { + LogInfo::MapleLogger() << "Mem:"; + LogInfo::MapleLogger() << "base:"; + GetBaseRegister()->dump(); + LogInfo::MapleLogger() << "offset:"; + GetOffsetOperand()->dump(); +} + +bool Riscv64MemOperand::Equals(Operand *operand) { + if (!dynamic_cast(operand)) { + return false; + } + Riscv64MemOperand *op = static_cast(operand); + return Equals(op); +} + +bool Riscv64MemOperand::Equals(Riscv64MemOperand *op) { + if (this == op) { + return true; + } + + if (GetBaseRegister()->GetRegisterNumber() == op->GetBaseRegister()->GetRegisterNumber() && + ((GetOffsetImmediate() && op->GetOffsetImmediate() && + GetOffsetImmediate()->GetValue() == op->GetOffsetImmediate()->GetValue()))) { + return true; + } else { + return false; + } +} + +// sort the register operand according to their number +void Riscv64ListOperand::Emit(Emitter &emitter, OpndProp *prop) { + uint32 nLeft = vec_opnds_.size(); + if (nLeft == 0) { + return; + } + + auto it = vec_opnds_.begin(); + for (; it != vec_opnds_.end(); ++it) { + (*it)->Emit(emitter, nullptr); + if (--nLeft >= 1) { + emitter.Emit(", "); + } + } +} + +} // namespace maplebe diff --git a/mapleall/maple_be/src/cg/riscv64/riscv64_opnd.def b/mapleall/maple_be/src/cg/riscv64/riscv64_opnd.def new file mode 100644 index 0000000..1684d9d --- /dev/null +++ b/mapleall/maple_be/src/cg/riscv64/riscv64_opnd.def @@ -0,0 +1,177 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +Riscv64OpndProp mopd_int32_reg_src = {Operand::Opd_Register, {kRegTyInt, kSubRegTyUndef, kMaxRegNum, REGPROPUSE }, 32}; +Riscv64OpndProp mopd_int32_reg_dest = {Operand::Opd_Register, {kRegTyInt, kSubRegTyUndef, kMaxRegNum, REGPROPDEF}, 32}; +Riscv64OpndProp mopd_int32_reg_dest_src = {Operand::Opd_Register, {kRegTyInt, kSubRegTyUndef, kMaxRegNum, REGPROPDEF | REGPROPUSE}, 32}; +Riscv64OpndProp mopd_int64_reg_src = {Operand::Opd_Register, {kRegTyInt, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 64}; +Riscv64OpndProp mopd_int64_reg_dest = {Operand::Opd_Register, {kRegTyInt, kSubRegTyUndef, kMaxRegNum, REGPROPDEF}, 64}; +Riscv64OpndProp mopd_int64_reg_dest_src = {Operand::Opd_Register, {kRegTyInt, kSubRegTyUndef, kMaxRegNum, REGPROPDEF | REGPROPUSE}, 64}; +Riscv64OpndProp mopd_int128s_reg_src = {Operand::Opd_Register, {kRegTyFloat, kSubRegTyInt32, kMaxRegNum, REGPROPUSE}, 128}; +Riscv64OpndProp mopd_int128s_reg_dest = {Operand::Opd_Register, {kRegTyFloat, kSubRegTyInt32, kMaxRegNum, REGPROPDEF}, 128}; +Riscv64OpndProp mopd_int128d_reg_src = {Operand::Opd_Register, {kRegTyFloat, kSubRegTyInt64, kMaxRegNum, REGPROPUSE}, 128}; +Riscv64OpndProp mopd_int128d_reg_dest = {Operand::Opd_Register, {kRegTyFloat, kSubRegTyInt64, kMaxRegNum, REGPROPDEF}, 128}; +Riscv64OpndProp mopd_f8_reg_src = {Operand::Opd_Register, {kRegTyFloat, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 8}; +Riscv64OpndProp mopd_f8_reg_dest = {Operand::Opd_Register, {kRegTyFloat, kSubRegTyUndef, kMaxRegNum, REGPROPDEF}, 8}; +Riscv64OpndProp mopd_f16_reg_src = {Operand::Opd_Register, {kRegTyFloat, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 16}; +Riscv64OpndProp mopd_f16_reg_dest = {Operand::Opd_Register, {kRegTyFloat, kSubRegTyUndef, kMaxRegNum, REGPROPDEF}, 16}; +Riscv64OpndProp mopd_f32_reg_src = {Operand::Opd_Register, {kRegTyFloat, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 32}; +Riscv64OpndProp mopd_f32_reg_dest = {Operand::Opd_Register, {kRegTyFloat, kSubRegTyUndef, kMaxRegNum, REGPROPDEF}, 32}; +Riscv64OpndProp mopd_f32_reg_dest_src = {Operand::Opd_Register, {kRegTyFloat, kSubRegTyUndef, kMaxRegNum, REGPROPDEF | REGPROPUSE}, 32}; +Riscv64OpndProp mopd_f64_reg_src = {Operand::Opd_Register, {kRegTyFloat, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 64}; +Riscv64OpndProp mopd_f64_reg_dest = {Operand::Opd_Register, {kRegTyFloat, kSubRegTyUndef, kMaxRegNum, REGPROPDEF}, 64}; +Riscv64OpndProp mopd_f64_reg_dest_src = {Operand::Opd_Register, {kRegTyFloat, kSubRegTyUndef, kMaxRegNum, REGPROPDEF | REGPROPUSE}, 64}; +Riscv64OpndProp mopd_f128s_reg_src = {Operand::Opd_Register, {kRegTyFloat, kSubRegTyFloat32, kMaxRegNum, REGPROPUSE}, 128}; +Riscv64OpndProp mopd_f128s_reg_dest = {Operand::Opd_Register, {kRegTyFloat, kSubRegTyFloat32, kMaxRegNum, REGPROPDEF}, 128}; +Riscv64OpndProp mopd_f128d_reg_src = {Operand::Opd_Register, {kRegTyFloat, kSubRegTyFloat64, kMaxRegNum, REGPROPUSE}, 128}; +Riscv64OpndProp mopd_f128d_reg_dest = {Operand::Opd_Register, {kRegTyFloat, kSubRegTyFloat64, kMaxRegNum, REGPROPDEF}, 128}; +Riscv64OpndProp mopd_int_imm4_src = {Operand::Opd_Immediate, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 4}; +Riscv64OpndProp mopd_int_imm5_src = {Operand::Opd_Immediate, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 5}; +Riscv64OpndProp mopd_int_imm6_src = {Operand::Opd_Immediate, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 6}; +Riscv64OpndProp mopd_int_imm8_src = {Operand::Opd_Immediate, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 8}; +Riscv64OpndProp mopd_int_imm12_src = {Operand::Opd_Immediate, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 12}; +Riscv64OpndProp mopd_int_imm13_src = {Operand::Opd_Immediate, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 13}; +Riscv64OpndProp mopd_int_imm16_src = {Operand::Opd_Immediate, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 16}; +Riscv64OpndProp mopd_int_imm24_src = {Operand::Opd_Immediate, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 24}; +Riscv64OpndProp mopd_int_imm32_src = {Operand::Opd_Immediate, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 32}; +Riscv64OpndProp mopd_int_imm32_literal = {Operand::Opd_Immediate, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE | LOADLITERAL}, 32}; +Riscv64OpndProp mopd_int_imm64_src = {Operand::Opd_Immediate, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 64}; +Riscv64OpndProp mopd_int_imm64_literal = {Operand::Opd_Immediate, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE | LOADLITERAL}, 64}; +Riscv64OpndProp mopd_fpzero_imm8_src = {Operand::Opd_FPZeroImmediate, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 8}; +Riscv64OpndProp mopd_mem8_src = {Operand::Opd_Mem, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 8}; +Riscv64OpndProp mopd_mem16_src = {Operand::Opd_Mem, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 16}; +Riscv64OpndProp mopd_mem32_src = {Operand::Opd_Mem, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 32}; +Riscv64OpndProp mopd_mem32_src_h = {Operand::Opd_Mem, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE | MEMLOW12}, 16}; +Riscv64OpndProp mopd_mem32_src_l = {Operand::Opd_Mem, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE | MEMLOW12}, 16}; +Riscv64OpndProp mopd_mem64_src = {Operand::Opd_Mem, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 64}; +Riscv64OpndProp mopd_mem64_src_l = {Operand::Opd_Mem, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE | MEMLOW12}, 12}; +Riscv64OpndProp mopd_mem128_src = {Operand::Opd_Mem, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 128}; + +Riscv64OpndProp mopd_mem8_dest = {Operand::Opd_Mem, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPDEF }, 8}; +Riscv64OpndProp mopd_mem16_dest = {Operand::Opd_Mem, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPDEF }, 16}; +Riscv64OpndProp mopd_mem32_dest = {Operand::Opd_Mem, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPDEF }, 32}; +Riscv64OpndProp mopd_mem64_dest = {Operand::Opd_Mem, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPDEF }, 64}; +Riscv64OpndProp mopd_mem128_dest = {Operand::Opd_Mem, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPDEF }, 128}; + +Riscv64OpndProp mopd_lbl64_src = {Operand::Opd_BbAddress, {kRegTyUndef, kSubRegTyUndef,kMaxRegNum, REGPROPUSE}, 64}; +Riscv64OpndProp mopd_literal_src = {Operand::Opd_StImmediate, {kRegTyUndef, kSubRegTyUndef,kMaxRegNum, REGPROPUSE}, 64}; +Riscv64OpndProp mopd_literal_l12_src = {Operand::Opd_StImmediate, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, LITERAL_LOW12}, 12}; +Riscv64OpndProp mopd_list_src = {Operand::Opd_List, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 1}; +Riscv64OpndProp mopd_cc_reg_src = {Operand::Opd_Register, {kRegTyCc, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 1}; +Riscv64OpndProp mopd_cc_reg_dest = {Operand::Opd_Register, {kRegTyCc, kSubRegTyUndef, kMaxRegNum, REGPROPDEF}, 1}; +Riscv64OpndProp mopd_cc_reg_dest_src = {Operand::Opd_Register, {kRegTyCc, kSubRegTyUndef, kMaxRegNum, REGPROPDEF | REGPROPUSE}, 1}; +Riscv64OpndProp mopd_sp_reg_dest = {Operand::Opd_Register, {kRegTyInt, kSubRegTyUndef, RSP, REGPROPDEF}, 32}; +Riscv64OpndProp mopd_mem32_src_pre = {Operand::Opd_Mem, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE | PREINC}, 32}; +Riscv64OpndProp mopd_mem32_src_post = {Operand::Opd_Mem, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE | POSTINC}, 32}; +Riscv64OpndProp mopd_mem64_src_pre = {Operand::Opd_Mem, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE | PREINC}, 64}; +Riscv64OpndProp mopd_mem64_src_post = {Operand::Opd_Mem, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE | POSTINC}, 64}; +Riscv64OpndProp mopd_mem32_literal_src = {Operand::Opd_Mem, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 32}; +Riscv64OpndProp mopd_mem64_literal_src = {Operand::Opd_Mem, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 64}; + +// or, could use Imm4? == NZCV +Riscv64OpndProp mopd_cond_src = {Operand::Opd_Cond, {kRegTyCc, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 4}; + +Riscv64OpndProp mopd_bitshift32_src = {Operand::Opd_Shift, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 5}; +Riscv64OpndProp mopd_bitshift64_src = {Operand::Opd_Shift, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 6}; +Riscv64OpndProp mopd_extendshift64_src = {Operand::Opd_Extend, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 3}; +Riscv64OpndProp mopd_lsl4_src = {Operand::Opd_Shift, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 4}; +Riscv64OpndProp mopd_lsl6_src = {Operand::Opd_Shift, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 6}; +Riscv64OpndProp mopd_lsl12_src = {Operand::Opd_Shift, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 12}; + +Riscv64OpndProp mopd_string = {Operand::Opd_String, {kRegTyUndef, kSubRegTyUndef, kMaxRegNum, REGPROPUSE}, 0}; + +// physical register + +Riscv64OpndProp *MOPD_Reg = &mopd_int32_reg_src; +// in MOPD_Reg32IS, Reg means register, 32 means 32-bits, I means integer(F means float), S means source, D means dest, H means high harf bits, L means low harf bits +Riscv64OpndProp *MOPD_Reg32IS = &mopd_int32_reg_src; +Riscv64OpndProp *MOPD_Reg32ID = &mopd_int32_reg_dest; +Riscv64OpndProp *MOPD_Reg32IDS = &mopd_int32_reg_dest_src; +Riscv64OpndProp *MOPD_Reg64IS = &mopd_int64_reg_src; +Riscv64OpndProp *MOPD_Reg64ID = &mopd_int64_reg_dest; +Riscv64OpndProp *MOPD_Reg64IDS = &mopd_int64_reg_dest_src; +Riscv64OpndProp *MOPD_Reg128IS = &mopd_int128s_reg_src; +Riscv64OpndProp *MOPD_Reg128ID = &mopd_int128s_reg_dest; +Riscv64OpndProp *MOPD_Reg128LS = &mopd_int128d_reg_src; +Riscv64OpndProp *MOPD_Reg128LD = &mopd_int128d_reg_dest; +Riscv64OpndProp *MOPD_Reg8FS = &mopd_f8_reg_src; +Riscv64OpndProp *MOPD_Reg8FD = &mopd_f8_reg_dest; +Riscv64OpndProp *MOPD_Reg16FS = &mopd_f16_reg_src; +Riscv64OpndProp *MOPD_Reg16FD = &mopd_f16_reg_dest; +Riscv64OpndProp *MOPD_Reg32FS = &mopd_f32_reg_src; +Riscv64OpndProp *MOPD_Reg32FD = &mopd_f32_reg_dest; +Riscv64OpndProp *MOPD_Reg32FDS = &mopd_f32_reg_dest_src; +Riscv64OpndProp *MOPD_Reg64FS = &mopd_f64_reg_src; +Riscv64OpndProp *MOPD_Reg64FD = &mopd_f64_reg_dest; +Riscv64OpndProp *MOPD_Reg64FDS = &mopd_f64_reg_dest_src; +Riscv64OpndProp *MOPD_Reg128FS = &mopd_f128s_reg_src; +Riscv64OpndProp *MOPD_Reg128FD = &mopd_f128s_reg_dest; +Riscv64OpndProp *MOPD_Reg128DS = &mopd_f128d_reg_src; +Riscv64OpndProp *MOPD_Reg128DD = &mopd_f128d_reg_dest; +Riscv64OpndProp *MOPD_Mem = &mopd_mem32_src; +Riscv64OpndProp *MOPD_Mem8S = &mopd_mem8_src; +Riscv64OpndProp *MOPD_Mem16S = &mopd_mem16_src; +Riscv64OpndProp *MOPD_Mem32S = &mopd_mem32_src; +Riscv64OpndProp *MOPD_Mem32SL = &mopd_mem32_src_l; +Riscv64OpndProp *MOPD_Mem32SH = &mopd_mem32_src_h; +Riscv64OpndProp *MOPD_Mem64S = &mopd_mem64_src; +Riscv64OpndProp *MOPD_Mem64SL = &mopd_mem64_src_l; +Riscv64OpndProp *MOPD_Mem128S = &mopd_mem128_src; +Riscv64OpndProp *MOPD_Mem8D = &mopd_mem8_dest; +Riscv64OpndProp *MOPD_Mem16D = &mopd_mem16_dest; +Riscv64OpndProp *MOPD_Mem32D = &mopd_mem32_dest; +Riscv64OpndProp *MOPD_Mem64D = &mopd_mem64_dest; +Riscv64OpndProp *MOPD_Mem128D = &mopd_mem128_dest; +Riscv64OpndProp *MOPD_Mem32SPRE = &mopd_mem32_src_pre; +Riscv64OpndProp *MOPD_Mem32SPOST = &mopd_mem32_src_post; +Riscv64OpndProp *MOPD_Mem64SPRE = &mopd_mem64_src_pre; +Riscv64OpndProp *MOPD_Mem64SPOST = &mopd_mem64_src_post; +Riscv64OpndProp *MOPD_Mem32LiteralS = &mopd_mem32_literal_src; +Riscv64OpndProp *MOPD_Mem64LiteralS = &mopd_mem64_literal_src; +Riscv64OpndProp *MOPD_Imm4 = &mopd_int_imm4_src; +Riscv64OpndProp *MOPD_Imm5 = &mopd_int_imm5_src; +Riscv64OpndProp *MOPD_Imm6 = &mopd_int_imm6_src; +Riscv64OpndProp *MOPD_Imm8 = &mopd_int_imm8_src; +Riscv64OpndProp *MOPD_Imm12 = &mopd_int_imm12_src; +Riscv64OpndProp *MOPD_Imm13 = &mopd_int_imm13_src; +Riscv64OpndProp *MOPD_Imm16 = &mopd_int_imm16_src; +Riscv64OpndProp *MOPD_Imm24 = &mopd_int_imm24_src; +Riscv64OpndProp *MOPD_Imm32 = &mopd_int_imm32_src; +Riscv64OpndProp* MOPD_Imm32LI = &mopd_int_imm32_literal; +Riscv64OpndProp *MOPD_Imm64 = &mopd_int_imm64_src; +Riscv64OpndProp* MOPD_Imm64LI = &mopd_int_imm64_literal; +Riscv64OpndProp *MOPD_FPZeroImm8 = &mopd_fpzero_imm8_src; +Riscv64OpndProp *MOPD_FuncName = &mopd_lbl64_src; +Riscv64OpndProp *MOPD_Label = &mopd_lbl64_src; +Riscv64OpndProp *MOPD_Literal = &mopd_literal_src; +Riscv64OpndProp *MOPD_Literal_L12 = &mopd_literal_l12_src; + +Riscv64OpndProp *MOPD_RegCCS = &mopd_cc_reg_src; +Riscv64OpndProp *MOPD_RegCCD = &mopd_cc_reg_dest; +Riscv64OpndProp *MOPD_RegCCDS = &mopd_cc_reg_dest_src; + +Riscv64OpndProp *MOPD_Cond = &mopd_cond_src; + +Riscv64OpndProp *MOPD_BitShift32 = &mopd_bitshift32_src; +Riscv64OpndProp *MOPD_BitShift64 = &mopd_bitshift64_src; +Riscv64OpndProp *MOPD_ExtendShift64 = &mopd_extendshift64_src; +Riscv64OpndProp *MOPD_LSL4 = &mopd_lsl4_src; +Riscv64OpndProp *MOPD_LSL6 = &mopd_lsl6_src; +Riscv64OpndProp *MOPD_LSL12 = &mopd_lsl12_src; + +Riscv64OpndProp *MOPD_RSPD = &mopd_sp_reg_dest; +Riscv64OpndProp *MOPD_LISTS = &mopd_list_src; +Riscv64OpndProp *MOPD_STRING = &mopd_string; +Riscv64OpndProp *MOPD_Undef = nullptr; diff --git a/mapleall/maple_be/src/cg/riscv64/riscv64_optimize_common.cpp b/mapleall/maple_be/src/cg/riscv64/riscv64_optimize_common.cpp new file mode 100644 index 0000000..a537e8f --- /dev/null +++ b/mapleall/maple_be/src/cg/riscv64/riscv64_optimize_common.cpp @@ -0,0 +1,379 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#include "riscv64_optimize_common.h" +#include "riscv64_isa.h" +#include "riscv64_cg_func.h" +#include "cg_bb.h" +#include "dbg.h" + +namespace maplebe { + +bool Riscv64InsnVisitor::ModifyBrInsn(maple::LabelIdx targetLabel, BB *&curbb) { + int targetIdx = curbb->lastinsn->GetJumpTargetIdx(); + MOperator flippedOp; + try { + flippedOp = FlipConditionOp(curbb->lastinsn->mop_, targetIdx); + } catch (...) { + return false; + } + LabelOperand *targetOperand = static_cast(GetCGFunc())->GetOrCreateLabelOperand(targetLabel); + curbb->lastinsn->mop_ = flippedOp; + curbb->lastinsn->SetOperand(targetIdx, targetOperand); + return true; +} + +MOperator Riscv64InsnVisitor::FlipConditionOp(MOperator originalOp, int &targetIdx) { + MOperator flippedOp = 0; + targetIdx = 2; + switch (originalOp) { + case Riscv64MOP_t::MOP_beq: + flippedOp = Riscv64MOP_t::MOP_bne; + break; + case Riscv64MOP_t::MOP_bne: + flippedOp = Riscv64MOP_t::MOP_beq; + break; + case Riscv64MOP_t::MOP_blt: + flippedOp = Riscv64MOP_t::MOP_bge; + break; + case Riscv64MOP_t::MOP_ble: + flippedOp = Riscv64MOP_t::MOP_bgt; + break; + case Riscv64MOP_t::MOP_bgt: + flippedOp = Riscv64MOP_t::MOP_ble; + break; + case Riscv64MOP_t::MOP_bge: + flippedOp = Riscv64MOP_t::MOP_blt; + break; + case Riscv64MOP_t::MOP_blo: + flippedOp = Riscv64MOP_t::MOP_bhs; + break; + case Riscv64MOP_t::MOP_bls: + flippedOp = Riscv64MOP_t::MOP_bhi; + break; + case Riscv64MOP_t::MOP_bhs: + flippedOp = Riscv64MOP_t::MOP_blo; + break; + case Riscv64MOP_t::MOP_bhi: + flippedOp = Riscv64MOP_t::MOP_bls; + break; + default: + // Don't need to flip for always + break; + } + return flippedOp; +} + +void Riscv64InsnVisitor::ModifyJumpTarget(Operand *targetOperand, BB *&bb) { + if (bb->GetKind() == BB::kBBIgoto) { + bool modified = false; + for (Insn *insn = bb->lastinsn; insn != nullptr; insn = insn->prev) { + if (insn->GetMachineOpcode() == MOP_adrp_label || + insn->GetMachineOpcode() == MOP_laddr) { + maple::LabelIdx labidx = static_cast(targetOperand)->labidx_; + ImmOperand *immopnd = static_cast(GetCGFunc())->CreateImmOperand(labidx, 8, false); + insn->SetOperand(1, immopnd); + modified = true; + } + } + CHECK_FATAL(modified, "ModifyJumpTarget: Could not change jump target"); + return; + } + int targetIdx = bb->lastinsn->GetJumpTargetIdx(); + bb->lastinsn->SetOperand(targetIdx, targetOperand); +} + +void Riscv64InsnVisitor::ModifyJumpTarget(maple::LabelIdx targetLabel, BB *&bb) { + LabelOperand *targetOperand = static_cast(GetCGFunc())->GetOrCreateLabelOperand(targetLabel); + ModifyJumpTarget(targetOperand, bb); +} + +void Riscv64InsnVisitor::ModifyJumpTarget(BB *newTarget, BB *&bb) { + int targetIdx = newTarget->lastinsn->GetJumpTargetIdx(); + Operand *targetOperand = newTarget->lastinsn->GetOperand(targetIdx); + ModifyJumpTarget(targetOperand, bb); +} + +Insn *Riscv64InsnVisitor::CreateGotoInsn(Insn *condBrInsn) { + int targetIdx = condBrInsn->GetJumpTargetIdx(); + Operand *target = condBrInsn->opnds[targetIdx]; + return new Riscv64Insn(MOP_xuncond, target); +} + +bool Riscv64InsnVisitor::IsConditionAlwaysHold(Insn *cmpInsn, Insn *conditionBrInsn, Operand *operands[]) { + switch (cmpInsn->mop_) { + case MOP_wcmpri: + case MOP_wcmprr: + case MOP_xcmpri: + case MOP_xcmprr: { + Riscv64ImmOperand *operand0 = static_cast(operands[0]); + Riscv64ImmOperand *operand1 = static_cast(operands[1]); + + int64 result = operand0->GetValue() - operand1->GetValue(); + return IsConditionAlwaysHold(conditionBrInsn->mop_, result); + } + default: + return false; + } +} + +Insn *Riscv64InsnVisitor::CloneInsn(Insn *originalInsn) { + MemPool *mp = CG::curCgFunc->memPool; + if (dynamic_cast(originalInsn)) { + // Cannot just plain duplicate the memory, as operands are shared + // across all instructions. Example - operand for vreg 200 is + // pointed to the same vreg:200 object. + // Further, operand objects are tracked in tables. Duplicating + // memory will lose track of these objects. + // For now, replace the operands, take care of leaks later. + Riscv64Insn *tobeCloned = static_cast(originalInsn); + Insn *newInsn = mp->Clone(*tobeCloned); + for (uint32 i = 0; i < Insn::kMaxOperandNum; i++) { + newInsn->opnds[i] = originalInsn->opnds[i]; + } + return newInsn; + } else if (dynamic_cast(originalInsn)) { + mpldbg::DbgInsn *tobeCloned = static_cast(originalInsn); + return mp->Clone(*tobeCloned); + } else if (dynamic_cast(originalInsn)) { + cfi::CfiInsn *tobeCloned = static_cast(originalInsn); + return mp->Clone(*tobeCloned); + } else { + CG_ASSERT(false, "Cannot clone"); + return nullptr; + } +} + +/** + * Precondition: The given insn is a jump instruction. + * Get the jump target label from the given instruction. + * Note: MOP_xbr is a branching instruction, but the target is unknown at compile time, + * because a register instead of label. So we don't take it as a branching instruction. + */ +LabelIdx Riscv64InsnVisitor::GetJumpLabel(Insn *insn) { + int operandIdx = insn->GetJumpTargetIdx(); + + if (dynamic_cast(insn->opnds[operandIdx])) { + return static_cast(insn->opnds[operandIdx])->labidx_; + } + + ASSERT(0, "Operand is not label"); + return 0; +} + +bool Riscv64InsnVisitor::IsConditionAlwaysHold(MOperator mop, int64 cmpRet) { + const char *erroMsg = "Not conditional branch instruction"; + if (cmpRet > 0) { + switch (mop) { + case MOP_bls: + case MOP_blt: + case MOP_ble: + case MOP_blo: + case MOP_beq: + return false; + case MOP_bpl: + case MOP_bhs: + case MOP_bhi: + case MOP_bgt: + case MOP_bge: + case MOP_bne: + return true; + default: + CG_ASSERT(false, "Not conditional branch instruction"); + return false; + } + } else if (cmpRet < 0) { + switch (mop) { + case MOP_bls: + case MOP_blt: + case MOP_ble: + case MOP_blo: + case MOP_bne: + return true; + case MOP_beq: + case MOP_bpl: + case MOP_bhs: + case MOP_bhi: + case MOP_bgt: + case MOP_bge: + return false; + default: + CG_ASSERT(false, "Not conditional branch instruction"); + return false; + } + } else { + switch (mop) { + case MOP_ble: + case MOP_bge: + case MOP_beq: + case MOP_bhs: + case MOP_bls: + return true; + case MOP_blt: + case MOP_blo: + case MOP_bne: + case MOP_bpl: + case MOP_bhi: + case MOP_bgt: + return false; + default: + CG_ASSERT(false, "Not conditional branch instruction"); + return false; + } + } +} + +Operand *Riscv64InsnVisitor::GetStrTarget(Insn *insn) { + return static_cast(static_cast(insn)->opnds[1]); +} + +Operand *Riscv64InsnVisitor::GetStrSource(Insn *insn) { + return static_cast(static_cast(insn)->opnds[0]); +} + +Operand *Riscv64InsnVisitor::GetLdrTarget(Insn *insn) { + return static_cast(static_cast(insn)->opnds[0]); +} + +Operand *Riscv64InsnVisitor::GetLdrSource(Insn *insn) { + return static_cast(static_cast(insn)->opnds[1]); +} + +bool Riscv64InsnVisitor::EqualMemOperands(Operand *op1, Operand *op2) { + return static_cast(op1)->Equals(static_cast(op2)); +} + +bool Riscv64InsnVisitor::IsCompareInsn(Insn *insn) { + switch (insn->mop_) { + case MOP_wcmpri: + case MOP_wcmprr: + case MOP_xcmpri: + case MOP_xcmprr: + case MOP_scmperi: + case MOP_scmperr: + case MOP_dcmperi: + case MOP_dcmperr: + case MOP_scmpqri: + case MOP_scmpqrr: + case MOP_dcmpqri: + case MOP_dcmpqrr: + return true; + default: + return false; + } +} + +bool Riscv64InsnVisitor::IsCompareAndBranchInsn(Insn *insn) { + switch (insn->mop_) { + case MOP_beq: + case MOP_bne: + case MOP_blt: + case MOP_ble: + case MOP_bgt: + case MOP_bge: + case MOP_beqz: + case MOP_bnez: + case MOP_bltz: + case MOP_blez: + case MOP_bgtz: + case MOP_bgez: + return true; + default: + return false; + } +} + +bool Riscv64InsnVisitor::ModifyInsnOpnds(Insn *insn, Operand *src, Operand *tar) { + if (!insn) { + return false; + } + if (insn->IsLoad() || insn->IsMove()) { + if (src) { + insn->opnds[1] = src; + } + if (tar) { + insn->opnds[0] = tar; + } + } else if (insn->IsStore()) { + if (src) { + insn->opnds[0] = src; + } + if (tar) { + insn->opnds[1] = tar; + } + } + + return true; +} + +RegOperand *Riscv64InsnVisitor::CreateVregFromReg(RegOperand *pReg) { + return static_cast(GetCGFunc()) + ->CreateRegisterOperandOfType(pReg->GetRegisterType(), pReg->GetSize() / 8); +} + +Insn *Riscv64InsnVisitor::CreateMoveInsn(RegOperand *dest, RegOperand *src) { + MOperator mop = (dest->GetSize() == 64 ? MOP_xmovrr : MOP_wmovrr); + return GetCGFunc()->cg->BuildInstruction(mop, dest, src); +} + +Insn *Riscv64InsnVisitor::CreateLdrInsn(MOperator branchMemOp, RegOperand *reg, MemOperand *mem) { + MOperator mop; + switch (branchMemOp) { + case MOP_wstrh: + case MOP_wldrh: + mop = MOP_wldrh; + break; + case MOP_wstr: + case MOP_wldr: + mop = MOP_wldr; + break; + case MOP_xstr: + case MOP_xldr: + mop = MOP_xldr; + break; + case MOP_sstr: + case MOP_sldr: + mop = MOP_sldr; + break; + case MOP_dstr: + case MOP_dldr: + mop = MOP_dldr; + break; + case MOP_wstrb: + case MOP_wldrb: + mop = MOP_wldrb; + break; + + default: + mop = 0; + } + if (!mop) { + return nullptr; + } else { + return GetCGFunc()->cg->BuildInstruction(mop, reg, mem); + } +} + +Insn *Riscv64InsnVisitor::CreateCmpInsn(Insn *condbr) { + Riscv64CGFunc *f = static_cast(GetCGFunc()); + RegOperand *reg = static_cast(condbr->GetOperand(0)); + PrimType primType = (reg->GetSize() == 64) ? PTY_u64 : PTY_u32; + ImmOperand *numZero = f->CreateImmOperand(primType, 0); + MOperator mopcode = (reg->GetSize() == 64) ? MOP_xcmpri : MOP_wcmpri; + Insn *cmpinsn = f->cg->BuildInstruction(mopcode, reg, numZero); + return cmpinsn; +} + +} // namespace maplebe diff --git a/mapleall/maple_be/src/cg/riscv64/riscv64_peep.cpp b/mapleall/maple_be/src/cg/riscv64/riscv64_peep.cpp new file mode 100644 index 0000000..61af315 --- /dev/null +++ b/mapleall/maple_be/src/cg/riscv64/riscv64_peep.cpp @@ -0,0 +1,907 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#include "riscv64_peep.h" +#include "cg.h" +#include "special_func.h" + +namespace maplebe { +#define JAVALANG (cgfunc->mirModule.IsJavaModule()) +/* + * Match identical operands for memory access of type [base + offset] only. + * Caller must check for the opcode. + * Make sure the base address is not modified. + */ +// function will need to consider load and store doubles. +bool Riscv64Peep::IsMemOperandsIdentical(Insn *insn, Insn *ninsn) { + regno_t regno1st = static_cast(insn->GetOperand(0))->GetRegisterNumber(); + regno_t regno2nd = static_cast(ninsn->GetOperand(0))->GetRegisterNumber(); + if (regno1st != regno2nd) { + return false; + } + // Match only [base + offset] + MemOperand *mopnd1st = static_cast(insn->GetOperand(1)); + MemOperand *mopnd2nd = static_cast(ninsn->GetOperand(1)); + + Operand *base1st = mopnd1st->GetBaseRegister(); + Operand *base2nd = mopnd2nd->GetBaseRegister(); + if (!(base1st && base1st->IsRegister())) { + return false; + } + if (!(base2nd && base2nd->IsRegister())) { + return false; + } + + regno_t baseRegno1st = static_cast(base1st)->GetRegisterNumber(); + // first insn re-write base addr reg1 <- [ reg1 + offset ] + if (baseRegno1st == regno1st) { + return false; + } + + regno_t baseRegno2nd = static_cast(base2nd)->GetRegisterNumber(); + if (baseRegno1st != baseRegno2nd) { + return false; + } + + if (static_cast(mopnd1st)->GetOffsetImmediate()->GetOffsetValue() != + static_cast(mopnd2nd)->GetOffsetImmediate()->GetOffsetValue()) { + return false; + } + return true; +} + +/* Looking for identical mem insn to eliminate. + * if two back-to-back is: + * 1. str + str + * 2. str + ldr + * And the [MEM] is pattern of [base + offset] + * 1. the [MEM] operand is exactly same then first + str can be eliminate. + * 2. the [MEM] operand is exactly same and src opnd + of str is same as the dest opnd of ldr then + ldr can be eliminate + */ + +void Riscv64Peep::RemoveIdenticalLoadAndStore() { + FOR_ALL_BB(bb, cgfunc) { + FOR_BB_INSNS_SAFE(insn, bb, ninsn) { + if (!ninsn) { + break; + } + + MOperator mop1st = insn->GetMachineOpcode(); + MOperator mop2nd = ninsn->GetMachineOpcode(); + if ((mop1st == MOP_wstr && mop2nd == MOP_wstr) || (mop1st == MOP_xstr && mop2nd == MOP_xstr)) { + if (IsMemOperandsIdentical(insn, ninsn)) { + bb->RemoveInsn(insn); + } + } else if ((mop1st == MOP_wstr && mop2nd == MOP_wldr) || (mop1st == MOP_xstr && mop2nd == MOP_xldr)) { + if (IsMemOperandsIdentical(insn, ninsn)) { + bb->RemoveInsn(ninsn); + ninsn = insn; + } + } + } + } +} + +void Riscv64Peep::Peephole0() { + RemoveIdenticalLoadAndStore(); + DeleteMovAfterCbzOrCbnz(); +} + +/* We optimize the following pattern in this function: + * A: Remove redundant mov which src and dest opnd is exactly same + * B: Combining 2 STRs into 1 stp or 2 LDRs into 1 ldp, when they are + back to back and the [MEM] they access is conjointed. + C: Eliminate the sxt[b|h|w] w0, w0;, when w0 is satisify following: + i) mov w0, #imm (#imm is not out of range) + ii) ldrs[b|h] w0, [MEM] + * D: Eliminate the uxt[b|h|w] w0, w0;when w0 is satisify following: + i) mov w0, #imm (#imm is not out of range) + ii) mov w0, R0(Is return value of call and return size is not of range) + iii)w0 is defined and used by special load insn and uxt[] pattern + * E: fmov ireg1 <- freg1 previous insn + fmov ireg2 <- freg1 current insn + use ireg2 may or may not be present + => + fmov ireg1 <- freg1 previous insn + mov ireg2 <- ireg1 current insn + use ireg1 may or may not be present + * F: cbnz x0, labelA + mov x0, 0 + b return-bb + labelA: + => + cbz x0, return-bb + labelA: + * G: When exist load after load or load after store, and [MEM] is + totally same. Then optimize them. + */ +void Riscv64Peep::Peephole() { + RemoveIdenticalLoadAndStore(); + Riscv64CGFunc *acgfunc = static_cast(cgfunc); + + // Delete insn moving the same register, this will simplify the following two passes. + FOR_ALL_BB(bb, acgfunc) { + FOR_BB_INSNS_SAFE(insn, bb, ninsn) { + if (!insn->IsMachineInstruction()) { + continue; + } + + MOperator thisMop = insn->GetMachineOpcode(); + switch (thisMop) { + case MOP_wmovrr: + case MOP_xmovrr: + case MOP_xvmovs: + case MOP_xvmovd: { + CG_ASSERT(insn->GetOperand(0)->IsRegister() && insn->GetOperand(1)->IsRegister(), "expects registers"); + Riscv64RegOperand *reg1 = static_cast(insn->GetOperand(0)); + Riscv64RegOperand *reg2 = static_cast(insn->GetOperand(1)); + CG_ASSERT((reg1 && reg2), "invalid insn"); + + if ((reg1->GetRegisterNumber() == reg2->GetRegisterNumber()) && (reg1->GetSize() == reg2->GetSize())) { + bb->RemoveInsn(insn); + } + } break; + } + } + } + + // To save compilation performance, we will have at most 2 + // iterations through the basic blocks, one pass forward and + // one pass backward + + FOR_ALL_BB(bb, cgfunc) { + Insn *prevInsn = nullptr; + // Forward scan + FOR_BB_INSNS_SAFE(insn, bb, ninsn) { + MOperator thisMop = insn->GetMachineOpcode(); + + if (!insn->IsMachineInstruction()) { + continue; + } + + switch (thisMop) { + case MOP_xldr: + case MOP_xstr: + case MOP_wldr: + case MOP_wstr: + case MOP_dldr: + case MOP_dstr: + case MOP_sldr: + case MOP_sstr: + { + } + break; + case MOP_xvmovrs: + case MOP_xvmovrd: + { + } + break; + case MOP_bnez: { + /* bnez x0, labelA + * mov x0, 0 + * b return-bb + * labelA: + * + * into + * beqz x0, return-bb + * labelA: + */ + CG_ASSERT(ninsn == nullptr, "peep: next inst is not null"); + // reg has to be R0, since return value is in R0 + RegOperand *regOpnd0 = static_cast(insn->GetOperand(0)); + if (regOpnd0->GetRegisterNumber() != R0) { + break; + } + BB *nbb = bb->next; + // Make sure nbb can only be reached by bb + if (nbb->preds.size() > 1 || nbb->eh_preds.size() != 0) { + break; + } + + BB *tbb = nullptr; + auto it = bb->succs.begin(); + if (*it == nbb) { + ++it; + tbb = *it; + } else { + tbb = *it; + } + // Make sure when nbb is empty, tbb is fallthru of bb. + if (tbb != nbb->next) { + break; + } + // Is nbb branch to the return-bb? + if (nbb->succs.size() != 1) { + break; + } + BB *nbbTarget = *(nbb->succs.begin()); + if (nbbTarget->kind != BB::kBBReturn) { + break; + } + + // Next insn should be a mov R0 = 0 + Insn *nextinsn = nbb->firstinsn; + while (nextinsn && !nextinsn->IsMachineInstruction()) { + nextinsn = nextinsn->next; + } + if (!nextinsn) { + break; + } + MOperator nextinsnMop = nextinsn->GetMachineOpcode(); + if (nextinsnMop != MOP_xmovri64) { + break; + } + RegOperand *movDest = static_cast(nextinsn->GetOperand(0)); + if (movDest->GetRegisterNumber() != R0) { + break; + } + ImmOperand *movImm = static_cast(nextinsn->GetOperand(1)); + if (movImm->GetValue() != 0) { + break; + } + Insn *nninsn = nextinsn->next; + while (nninsn && !nninsn->IsMachineInstruction()) { + nninsn = nninsn->next; + } + if (!nninsn) { + break; + } + if (nninsn->GetMachineOpcode() != MOP_xuncond) { + break; + } + // Control flow looks nice, instruction looks nice + Operand *brTarget = nninsn->GetOperand(0); + insn->SetOperand(1, brTarget); + insn->SetMOP(MOP_beqz); + nbb->RemoveInsn(nextinsn); + nbb->RemoveInsn(nninsn); + // nbb is now a fallthru bb, not a goto bb + nbb->SetKind(BB::kBBFallthru); + + // fix control flow, we have bb, nbb, tbb, nbb_target + // connect bb -> nbb_target erase tbb + it = bb->succs.begin(); + if (*it == tbb) { + bb->succs.erase(it); + bb->succs.push_front(nbbTarget); + } else { + it++; + bb->succs.erase(it); + bb->succs.push_back(nbbTarget); + } + for (it = tbb->preds.begin(); it != tbb->preds.end(); it++) { + if (*it == bb) { + tbb->preds.erase(it); + break; + } + } + for (it = nbbTarget->preds.begin(); it != nbbTarget->preds.end(); it++) { + if (*it == nbb) { + nbbTarget->preds.erase(it); + break; + } + } + nbbTarget->preds.push_back(bb); + + // nbb has no target, originally just branch target + nbb->succs.erase(nbb->succs.begin()); + CG_ASSERT(nbb->succs.size() == 0, "peep: branch target incorrect"); + // Now make nbb fallthru to tbb + nbb->succs.push_front(tbb); + tbb->preds.push_back(nbb); + break; + } + default: + break; + } // switch + } // Insn + + // Backward scan + for (Insn *insn = bb->lastinsn; insn && insn != bb->firstinsn; insn = prevInsn) { + prevInsn = insn->prev; + while (prevInsn && !prevInsn->GetMachineOpcode() && prevInsn != bb->firstinsn) { + prevInsn = prevInsn->prev; + } + + if (!insn->IsMachineInstruction() || !prevInsn) { + continue; + } + + bool loadafterstore = false; + bool loadafterload = false; + MOperator thisMop = insn->GetMachineOpcode(); + MOperator prevMop = prevInsn->GetMachineOpcode(); + + // store regB, RegC, offset + // load regA, RegC, offset + if ((thisMop == MOP_xldr && prevMop == MOP_xstr) || (thisMop == MOP_wldr && prevMop == MOP_wstr) || + (thisMop == MOP_dldr && prevMop == MOP_dstr) || (thisMop == MOP_sldr && prevMop == MOP_sstr)) { + loadafterstore = true; + } + + // load regA, RegC, offset + // load regB, RegC, offset + if ((thisMop == MOP_xldr || thisMop == MOP_wldr || thisMop == MOP_dldr || thisMop == MOP_sldr) && + prevMop == thisMop) { + loadafterload = true; + } + + if (loadafterstore || loadafterload) { + CG_ASSERT(insn->GetOperand(1)->IsMemoryAccessOperand() && prevInsn->GetOperand(1)->IsMemoryAccessOperand(), + "expects mem operands"); + + Riscv64RegOperand *reg1 = static_cast(insn->opnds[0]); + Riscv64MemOperand *mopnd1 = static_cast(insn->GetOperand(1)); + + Riscv64RegOperand *base1 = static_cast(mopnd1->GetBaseRegister()); + CG_ASSERT(base1 == nullptr || !base1->IsVirtualRegister(), "physical register has not been allocated?"); + Riscv64OfstOperand *offset1 = mopnd1->GetOffsetImmediate(); + + Riscv64RegOperand *reg2 = static_cast(prevInsn->opnds[0]); + Riscv64MemOperand *mopnd2 = static_cast(prevInsn->GetOperand(1)); + + Riscv64RegOperand *base2 = static_cast(mopnd2->GetBaseRegister()); + CG_ASSERT(base2 == nullptr || !base2->IsVirtualRegister(), "physical register has not been allocated?"); + Riscv64OfstOperand *offset2 = mopnd2->GetOffsetImmediate(); + + if (base1 == nullptr || base2 == nullptr || offset1 == nullptr || offset2 == nullptr) { + continue; + } + + int offsetVal1 = offset1->GetOffsetValue(); + int offsetVal2 = offset2->GetOffsetValue(); + + if (base1->GetRegisterNumber() == base2->GetRegisterNumber() && + reg1->GetRegisterType() == reg2->GetRegisterType() && reg1->GetSize() == reg2->GetSize() && + offsetVal1 == offsetVal2) { + if (loadafterstore && reg1->GetRegisterNumber() != reg2->GetRegisterNumber()) { + // replace it with mov + MOperator newOp = MOP_wmovrr; + if (reg1->GetRegisterType() == kRegTyInt) { + newOp = reg1->GetSize() <= 32 ? MOP_wmovrr : MOP_xmovrr; + } else if (reg1->GetRegisterType() == kRegTyFloat) { + newOp = reg1->GetSize() <= 32 ? MOP_xvmovs : MOP_xvmovd; + } + + bb->InsertInsnAfter(prevInsn, cg->BuildInstruction(newOp, reg1, reg2)); + bb->RemoveInsn(insn); + } else if (reg1->GetRegisterNumber() == reg2->GetRegisterNumber() && + base1->GetRegisterNumber() != reg2->GetRegisterNumber()) { + bb->RemoveInsn(insn); + } + } + } + } // Insn + + } // BB + + return; +} + +void Riscv64Peep::PostRemoveSext() { + Riscv64CGFunc *acgfunc = static_cast(cgfunc); + FOR_ALL_BB(bb, acgfunc) { + if (bb->firstinsn && bb->firstinsn->GetMachineOpcode() == MOP_wmovrr) { + RegOperand *reg1 = static_cast(bb->firstinsn->opnds[1]); + if (reg1->GetRegisterNumber() == R10 && + bb->preds.size() == 1 && bb->preds.front() == bb->prev && + (bb->prev->lastinsn->GetMachineOpcode() == MOP_xbl || + bb->prev->lastinsn->GetMachineOpcode() == MOP_xblr)) { + Insn *nextinsn = bb->firstinsn->GetNextMachineInsn(); + if (nextinsn) { + RegOperand *reg0 = static_cast(nextinsn->opnds[0]); + if (reg0->GetRegisterNumber() != R10) { + if (nextinsn->GetMachineOpcode() == MOP_xsxtw64) { + nextinsn->SetMOP(MOP_xmovrr); + } else if (nextinsn->GetMachineOpcode() == MOP_xsxtv64) { + nextinsn->SetMOP(MOP_xmovrr); + nextinsn->SetOperand(2, nullptr); + } + } + } + } + } + } +} + +void Riscv64Peep::RemoveSext() { + Riscv64CGFunc *acgfunc = static_cast(cgfunc); + FOR_ALL_BB(bb, acgfunc) { + FOR_BB_INSNS_REV_SAFE(insn, bb, ninsn) { + if (!insn->IsMachineInstruction()) { + continue; + } + Insn *previnsn = insn->GetPreviousMachineInsn(); + if (previnsn == nullptr) { + continue; + } + if (insn->GetMachineOpcode() == MOP_xsxtw64) { + switch (previnsn->GetMachineOpcode()) { + case MOP_xmovri64: + case MOP_waddrri12: + case MOP_waddrrr: + case MOP_xsxtv64: + case MOP_xslt: + case MOP_xsltu: + case MOP_xslti: + case MOP_xsltiu: + case MOP_xsgt: + case MOP_xsgtu: + case MOP_xseqz: + case MOP_xsnez: + case MOP_wldrsw: { + RegOperand *reg1 = static_cast(insn->opnds[1]); + RegOperand *reg2 = static_cast(previnsn->opnds[0]); + if (IsSameReg(reg1, reg2)) { + insn->SetMOP(MOP_xmovrr); + } + break; + } + } + Insn *prevprevinsn = previnsn->GetPreviousMachineInsn(); + if (prevprevinsn == nullptr) { + continue; + } + switch (prevprevinsn->GetMachineOpcode()) { + case MOP_xmovri64: + case MOP_waddrri12: + case MOP_waddrrr: + case MOP_xsxtv64: + case MOP_xseqz: + case MOP_xsnez: + case MOP_wldrsw: { + RegOperand *reg1 = static_cast(insn->opnds[1]); + RegOperand *reg2 = static_cast(prevprevinsn->opnds[0]); + if (IsSameReg(reg1, reg2)) { + insn->SetMOP(MOP_xmovrr); + } + break; + } + } + } else if (insn->GetMachineOpcode() == MOP_xsxtv64) { + switch (previnsn->GetMachineOpcode()) { + case MOP_wldrsb: + if (static_cast(insn->opnds[2])->GetValue() == 56) { + insn->SetMOP(MOP_xmovrr); + insn->SetOperand(2, nullptr); + } + break; + case MOP_wldrsh: + if (static_cast(insn->opnds[2])->GetValue() == 48) { + insn->SetMOP(MOP_xmovrr); + insn->SetOperand(2, nullptr); + } + break; + } + } + } + } +} + +void Riscv64Peep::ConvertPseudoOps() { + Riscv64CGFunc *acgfunc = static_cast(cgfunc); + FOR_ALL_BB(bb, acgfunc) { + FOR_BB_INSNS(insn, bb) { + switch(insn->GetMachineOpcode()) { + case MOP_xsxtv64: { + RegOperand *resopnd = static_cast(insn->opnds[0]); + RegOperand *opnd0 = static_cast(insn->opnds[1]); + ImmOperand *imm = static_cast(insn->opnds[2]); + bb->InsertInsnBefore(insn, cg->BuildInstruction(MOP_xlslrri6, resopnd, opnd0, imm)); + bb->InsertInsnBefore(insn, cg->BuildInstruction(MOP_xasrrri6, resopnd, resopnd, imm)); + bb->RemoveInsn(insn); + break; + } + case MOP_xuxtv64: { + RegOperand *resopnd = static_cast(insn->opnds[0]); + RegOperand *opnd0 = static_cast(insn->opnds[1]); + ImmOperand *imm = static_cast(insn->opnds[2]); + bb->InsertInsnBefore(insn, cg->BuildInstruction(MOP_xlslrri6, resopnd, opnd0, imm)); + bb->InsertInsnBefore(insn, cg->BuildInstruction(MOP_xlsrrri6, resopnd, resopnd, imm)); + bb->RemoveInsn(insn); + break; + } + case MOP_xsubrri12: { + int64 val = static_cast(insn->opnds[2])->GetValue(); + ImmOperand *imm = acgfunc->CreateImmOperand(-val, 8, true); + insn->SetOperand(2, imm); + insn->SetMOP(MOP_xaddrri12); + break; + } + case MOP_wsubrri12: { + int64 val = static_cast(insn->opnds[2])->GetValue(); + ImmOperand *imm = acgfunc->CreateImmOperand(-val, 8, true); + insn->SetOperand(2, imm); + insn->SetMOP(MOP_waddrri12); + break; + } + } + } + } +} + +void Riscv64Peep::PeepholeOpt() { + PostRemoveSext(); + Peephole(); +} + +bool Riscv64Peep::IsSameReg(Operand *firstOpnd, Operand *secondOpnd) { + CG_ASSERT(firstOpnd->IsRegister() && secondOpnd->IsRegister(), + "first_opnd and second_opnd should be Register Operand"); + RegOperand *firstReg = static_cast(firstOpnd); + RegOperand *secondReg = static_cast(secondOpnd); + return firstReg->RegNumEqual(secondReg); +} + +bool Riscv64Peep::PredBBCheck(BB *bb, bool checkcbz, Operand *opnd) { + if (bb->GetKind() != BB::kBBIf) { + return false; + } + + Insn *condbr = cgfunc->theCFG->FindLastCondBrInsn(bb); + CG_ASSERT(condbr, "condbr must be found"); + if (!cgfunc->theCFG->IsCompareAndBranchInsn(condbr)) { + return false; + } + MOperator mop = condbr->GetMachineOpcode(); + if (checkcbz && mop != MOP_beqz) { + return false; + } + if (!checkcbz && mop != MOP_bnez) { + return false; + } + return IsSameReg(condbr->GetOperand(0), opnd); +} + +/* help function for DeleteMovAfterCbzOrCbnz + * input: + * bb: the bb to be checked out + * checkcbz: to check out BB end with cbz or cbnz, if cbz, input true + * opnd: for MOV reg, #0, opnd indicate reg + **return: + * according to cbz, return true if insn is cbz or cbnz and the first operand of cbz(cbnz) is same as input + *operand + */ +bool Riscv64Peep::OpndDefByMovZero(Insn *insn) { + MOperator defMop = insn->GetMachineOpcode(); + switch (defMop) { + case MOP_xmovri64: { + Operand *defOpnd = insn->GetOperand(1); + CG_ASSERT(defOpnd->IsIntImmediate(), "expects ImmOperand"); + ImmOperand *defConst = static_cast(defOpnd); + int64 defConstValue = defConst->GetValue(); + if (defConstValue == 0) { + return true; + } + return false; + } + case MOP_xmovrr: + case MOP_wmovrr: { + Operand *secondOpnd = insn->GetOperand(1); + CG_ASSERT(secondOpnd && secondOpnd->IsRegister(), "expects RegOperand here"); + Riscv64RegOperand *regOpnd = static_cast(secondOpnd); + return regOpnd->IsZeroRegister(); + } + default: + return false; + } +} + +/* + *check wether predefine insn of first operand of test_insn is exist in current BB + * */ +bool Riscv64Peep::NoPreDefine(Insn *testInsn) { + Insn *ninsn = nullptr; + for (Insn *insn = testInsn->bb->firstinsn; insn && insn != testInsn; insn = ninsn) { + ninsn = insn->GetNextMachineInsn(); + if (!insn->IsMachineInstruction()) { + continue; + } + CG_ASSERT(!insn->IsCall(), "CG internal error, call insn should not be at the middle of the BB."); + const Riscv64MD *md = &Riscv64CG::kMd[static_cast(insn)->mop_]; + for (int i = 0; i < Insn::kMaxOperandNum; i++) { + Operand *opnd = insn->opnds[i]; + if (opnd == nullptr) { + continue; + } + Riscv64OpndProp *regprop = static_cast(md->operand_[i]); + if (regprop->IsDef()) { + if (opnd->IsMemoryAccessOperand() == false) { + CG_ASSERT(opnd->IsRegister(), "expects RegOperand"); + if (IsSameReg(testInsn->GetOperand(0), opnd)) { + return false; + } + } + } + } + } + return true; +} + +/* cbnz w0, @label + * .... + * mov w0, #0 (elseBB) -->this instruction can be deleted + * + * cbz w0, @label + * .... + * mov w0, #0 (ifBB) -->this instruction can be deleted + * + * condition: + * 1.there is not predefine points of w0 in elseBB(ifBB) + * 2.the first opearnd of cbnz insn is same as the first Operand of mov insn + * 3.w0 is defined by move 0 + * 4.all preds of elseBB(ifBB) end with cbnz or cbz + * + * NOTE: if there are multiple preds and there is not define point of w0 in one pred, + * (mov w0, 0) can't be deleted, avoiding use before def. + */ +void Riscv64Peep::DeleteMovAfterCbzOrCbnz() { + cgfunc->theCFG->InitInsnVisitor(cgfunc, cgfunc->memPool); + FOR_ALL_BB(bb, cgfunc) { + if (bb->GetKind() != BB::kBBIf) { + continue; + } + + Insn *condbr = cgfunc->theCFG->FindLastCondBrInsn(bb); + CG_ASSERT(condbr, "condbr must be found"); + if (!cgfunc->theCFG->IsCompareAndBranchInsn(condbr)) { + continue; + } + BB *processBb = nullptr; + MOperator condbrMop = condbr->GetMachineOpcode(); + if (condbrMop == MOP_bnez) { + processBb = bb->next; + } else { + processBb = cgfunc->theCFG->GetTargetSuc(bb); + } + + CG_ASSERT(processBb != nullptr, "process_bb is null in Riscv64Peep::DeleteMovAfterCbzOrCbnz"); + Insn *ninsn = nullptr; + for (Insn *insn = processBb->firstinsn; insn; insn = ninsn) { + ninsn = insn->GetNextMachineInsn(); + if (!insn->IsMachineInstruction()) { + continue; + } + if (OpndDefByMovZero(insn) && NoPreDefine(insn) && IsSameReg(insn->GetOperand(0), condbr->GetOperand(0))) { + bool toDoOpt = true; + // process elseBB, other preds must be cbz + if (condbrMop == MOP_bnez) { + // check out all preds of process_bb + for (auto processBbPred : processBb->preds) { + if (processBbPred == bb) { + continue; + } + if (!PredBBCheck(processBbPred, true, insn->GetOperand(0))) { + toDoOpt = false; + break; + } + } + } else { + if (processBb->preds.size() == 1) { + // conditional-bb target and fallthru is the same bb + toDoOpt = false; + } + // process ifBB, other preds can be cbz or cbnz(one at most) + for (auto processBbPred : processBb->preds) { + if (processBbPred == bb) { + continue; + } + // for cbnz pred, there is one at most + if (processBbPred == processBb->prev) { + if (!PredBBCheck(processBbPred, false, insn->GetOperand(0))) { + toDoOpt = false; + break; + } + } else { + // for cbz pred + if (!PredBBCheck(processBbPred, true, insn->GetOperand(0))) { + toDoOpt = false; + break; + } + } + } + } + if (!toDoOpt) { + continue; + } + processBb->RemoveInsn(insn); + } + } + } +} + +bool Riscv64Peep::OpndDefByOneValidBit(Insn *defInsn) { + CG_ASSERT(defInsn, "def_insn must not be null"); + MOperator defMop = defInsn->GetMachineOpcode(); + switch (defMop) { + case MOP_xslt: + case MOP_xsltu: + case MOP_xslti: + case MOP_xsltiu: + case MOP_xsgt: + case MOP_xsgtu: + case MOP_xseqz: + case MOP_xsnez: + return true; + case MOP_xmovri64: { + Operand *defOpnd = defInsn->GetOperand(1); + CG_ASSERT(defOpnd->IsIntImmediate(), "expects ImmOperand"); + ImmOperand *defConst = static_cast(defOpnd); + int64 defConstValue = defConst->GetValue(); + if (defConstValue != 0 && defConstValue != 1) { + return false; + } else { + return true; + } + } + case MOP_xmovrr: + case MOP_wmovrr: + CG_ASSERT(defInsn && defInsn->GetOperand(1), "Operand must not be null"); + return defInsn->GetOperand(1)->IsZeroRegister(); + case MOP_wlsrrri5: + case MOP_xlsrrri6: { + Operand *opnd2 = defInsn->GetOperand(2); + CG_ASSERT(opnd2 && opnd2->IsIntImmediate(), "expects ImmOperand"); + ImmOperand *opndimm = static_cast(opnd2); + int64 shiftbits = opndimm->GetValue(); + if ((defMop == MOP_wlsrrri5 && shiftbits == 31) || (defMop == MOP_xlsrrri6 && shiftbits == 63)) { + return true; + } else { + return false; + } + } + default: + return false; + } +} + +// if there is define point of checkinsn->GetOperand(opndidx) between startinsn and bb->firstinsn +// return define insn. else return nullptr +Insn *Riscv64Peep::DefInsnOfOperandInBB(BB *bb, Insn *startinsn, Insn *checkinsn, int opndidx) { + Insn *previnsn = nullptr; + for (Insn *insn = startinsn; insn && insn != bb->firstinsn->prev; insn = previnsn) { + previnsn = insn->GetPreviousMachineInsn(); + if (!insn->IsMachineInstruction()) { + continue; + } + // checkinsn->GetOperand(opndidx) is thought modified conservatively + if (insn->IsCall()) { + return insn; + } + const Riscv64MD *md = &Riscv64CG::kMd[static_cast(insn)->mop_]; + for (int i = 0; i < Insn::kMaxOperandNum; i++) { + Operand *opnd = insn->opnds[i]; + if (opnd == nullptr) { + continue; + } + Riscv64OpndProp *regprop = static_cast(md->operand_[i]); + if (regprop->IsDef()) { + // Operand is base reg of Memory, defined by str + if (opnd->IsMemoryAccessOperand() == false) { + CG_ASSERT(opnd->IsRegister(), "expects RegOperand"); + if (IsSameReg(checkinsn->GetOperand(opndidx), opnd)) { + return insn; + } + } + } + } + } + return nullptr; +} + +void Riscv64Peep::PrePeepholeOpt() { + RemoveSext(); + ReplaceInstruction(); +} + +void Riscv64Peep::PrePeepholeOpt1() { +} + +/* orr w21, w0, #0 ====> mov w21, w0 + orr w21, #0, w0 ====> mov w21, w0 + */ +void Riscv64Peep::ReplaceInstruction() { + Riscv64CGFunc *acgfunc = static_cast(cgfunc); + FOR_ALL_BB(bb, acgfunc) { + FOR_BB_INSNS(insn, bb) { + if (!insn->IsMachineInstruction()) { + continue; + } + Operand *opndOfOrr = nullptr; + Operand *opnd1OfMov = nullptr; + Operand *opnd2OfMov = nullptr; + ImmOperand *immOpnd = nullptr; + Riscv64RegOperand *reg1 = nullptr; + Riscv64RegOperand *reg2 = nullptr; + MOperator thisMop = insn->GetMachineOpcode(); + switch (thisMop) { + case MOP_xiorrri13: { // opnd1 is reg64 and opnd3 is immediate. + opndOfOrr = insn->opnds[2]; + CG_ASSERT(opndOfOrr->IsIntImmediate(), "expects immediate operand"); + immOpnd = static_cast(opndOfOrr); + if (0 == immOpnd->GetValue()) { + reg1 = static_cast(insn->opnds[0]); + reg2 = static_cast(insn->opnds[1]); + bb->ReplaceInsn(insn, cg->BuildInstruction(MOperator(MOP_xmovrr), reg1, reg2)); + } + break; + } + default: + break; + } + } + } +} + +AnalysisResult *CgDoPrePeepHole::Run(CGFunc *cgfunc, CgFuncResultMgr *m) { + LiveAnalysis *live = nullptr; + // It doesn't need live range information when -O1, because the register will not live out of bb. + if (g->optim_level >= 2) { + live = static_cast(m->GetAnalysisResult(CgFuncPhase_LIVE, cgfunc)); + } + Riscv64Peep *peep = new Riscv64Peep(cgfunc); + peep->PrePeepholeOpt(); + delete peep; + m->InvalidAnalysisResult(CgFuncPhase_LIVE, cgfunc); + return nullptr; +} + +AnalysisResult *CgDoPrePeepHole1::Run(CGFunc *cgfunc, CgFuncResultMgr *m) { + if (cgfunc->GetRDStatus()) { + cgfunc->GetRD()->ClearDefUseInfo(); + m->InvalidAnalysisResult(CgFuncPhase_LIVE, cgfunc); + m->InvalidAnalysisResult(CgFuncPhase_REACHDEF, cgfunc); + } + Riscv64Peep *peep = new Riscv64Peep(cgfunc); + peep->PrePeepholeOpt1(); + delete peep; + return nullptr; +} + +AnalysisResult *CgDoPeepHole0::Run(CGFunc *cgfunc, CgFuncResultMgr *m) { + LiveAnalysis *live = nullptr; + if (g->optim_level >= 2) { + live = static_cast(m->GetAnalysisResult(CgFuncPhase_LIVE, cgfunc)); + } + Riscv64Peep *peep = new Riscv64Peep(cgfunc); + peep->Peephole0(); + delete peep; + m->InvalidAnalysisResult(CgFuncPhase_LIVE, cgfunc); + return nullptr; +} + +AnalysisResult *CgDoPeepHole::Run(CGFunc *cgfunc, CgFuncResultMgr *m) { + LiveAnalysis *live = nullptr; + if (g->optim_level >= 2) { + live = static_cast(m->GetAnalysisResult(CgFuncPhase_LIVE, cgfunc)); + } + Riscv64Peep *peep = new Riscv64Peep(cgfunc); + peep->PeepholeOpt(); + delete peep; + m->InvalidAnalysisResult(CgFuncPhase_LIVE, cgfunc); + return nullptr; +} + +AnalysisResult *CgFixShortBranch::Run(CGFunc *cgfunc, CgFuncResultMgr *m) { + Riscv64Peep *peep = new Riscv64Peep(cgfunc); + peep->ConvertPseudoOps(); + delete peep; + return nullptr; +} + +} // namespace maplebe diff --git a/mapleall/maple_be/src/cg/riscv64/riscv64_ra_opt.cpp b/mapleall/maple_be/src/cg/riscv64/riscv64_ra_opt.cpp new file mode 100644 index 0000000..781a71b --- /dev/null +++ b/mapleall/maple_be/src/cg/riscv64/riscv64_ra_opt.cpp @@ -0,0 +1,289 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + + +#include "riscv64_ra_opt.h" + +#include + +namespace maplebe { + +using namespace std; + +bool RaX0Opt::PropagateX0CanReplace(Operand *opnd, regno_t replaceReg) { + if (opnd) { + RegOperand *regopnd = static_cast(opnd); + regno_t regCandidate = regopnd->GetRegisterNumber(); + if (regCandidate == replaceReg) { + return true; + } + } + return false; +} + +/* + * Replace replace_reg with rename_reg. + * return true if there is a redefinition that needs to terminate the propagation. + */ +bool RaX0Opt::PropagateRenameReg(Insn *ninsn, X0OptInfo &optVal) { + uint32 renameReg = static_cast(optVal.GetRenameOpnd())->GetRegisterNumber(); + const Riscv64MD *md = &Riscv64CG::kMd[static_cast(ninsn)->mop_]; + for (int32_t i = Insn::kMaxOperandNum - 1; i >= 0; i--) { + Operand *opnd = ninsn->GetOperand(i); + if (opnd == nullptr) { + continue; + } + if (opnd->IsList()) { + // call parameters + } else if (opnd->IsMemoryAccessOperand()) { + MemOperand *memopnd = static_cast(opnd); + if (PropagateX0CanReplace(memopnd->GetBaseRegister(), optVal.GetReplaceReg())) { + RegOperand *renameOpnd = static_cast(optVal.GetRenameOpnd()); + memopnd->SetBaseRegister(renameOpnd); + } + if (PropagateX0CanReplace(memopnd->GetIndexRegister(), optVal.GetReplaceReg())) { + RegOperand *renameOpnd = static_cast(optVal.GetRenameOpnd()); + memopnd->SetIndexRegister(renameOpnd); + } + } else if (opnd->IsRegister()) { + bool isdef = static_cast(md->operand_[i])->IsRegDef(); + RegOperand *regopnd = static_cast(opnd); + regno_t regCandidate = regopnd->GetRegisterNumber(); + if (isdef) { + // Continue if both replace_reg & rename_reg are not redefined. + if (regCandidate == optVal.GetReplaceReg() || regCandidate == renameReg) { + return true; + } + } else { + if (regCandidate == optVal.GetReplaceReg()) { + ninsn->SetOperand(i, optVal.GetRenameOpnd()); + } + } + } + } + return false; // false == no redefinition +} + +bool RaX0Opt::PropagateX0DetectX0(Insn *insn, X0OptInfo &optVal) { + /* Propagate x0 from a call return value to a def of x0. + * This eliminates some local reloads under high register pressure, since + * the use has been replaced by x0. + */ + if (insn->GetMachineOpcode() != MOP_xmovrr && insn->GetMachineOpcode() != MOP_wmovrr) { + return false; + } + RegOperand *movSrc = static_cast(insn->GetOperand(1)); + if (movSrc->GetRegisterNumber() != R0) { + return false; + } + + optVal.SetMovSrc(movSrc); + return true; +} + +bool RaX0Opt::PropagateX0DetectRedefine(const Riscv64MD *md, Insn *ninsn, const X0OptInfo &optVal, + uint32 index) { + bool isdef = static_cast(md->operand_[index])->IsRegDef(); + if (isdef) { + RegOperand *opnd = static_cast(ninsn->GetOperand(index)); + if (opnd->GetRegisterNumber() == optVal.GetReplaceReg()) { + return true; + } + } + return false; +} + +bool RaX0Opt::PropagateX0Optimize(const BB *bb, const Insn *insn, X0OptInfo &optVal) { + bool redefined = false; + for (Insn *ninsn = insn->next; ninsn && ninsn != bb->lastinsn->next; ninsn = ninsn->next) { + if (!ninsn->IsMachineInstruction()) { + continue; + } + + // Will continue as long as the reg being replaced is not redefined. + // Does not need to check for x0 redefinition. The mov instruction src + // being replaced already defines x0 and will terminate this loop. + const Riscv64MD *md = &Riscv64CG::kMd[static_cast(ninsn)->mop_]; + for (uint32 i = 0; i < ninsn->GetResultNum(); i++) { + redefined = PropagateX0DetectRedefine(md, ninsn, optVal, i); + if (redefined) { + break; + } + } + + if (redefined) { + break; + } + + // Look for move where src is the register equivalent to x0. + if (ninsn->GetMachineOpcode() != MOP_xmovrr && ninsn->GetMachineOpcode() != MOP_wmovrr) { + continue; + } + + Operand *src = ninsn->GetOperand(1); + RegOperand *srcreg = static_cast(src); + if (srcreg->GetRegisterNumber() != optVal.GetReplaceReg()) { + continue; + } + + // Setup for the next optmization pattern. + Operand *dst = ninsn->GetOperand(0); + RegOperand *dstreg = static_cast(dst); + if (dstreg->GetRegisterNumber() != R0) { + // This is to set up for further propagation later. + if (srcreg->GetRegisterNumber() == optVal.GetReplaceReg()) { + if (optVal.GetRenameInsn() != nullptr) { + redefined = true; + break; + } else { + optVal.SetRenameInsn(ninsn); + optVal.SetRenameOpnd(dst); + optVal.SetRenameReg(dstreg->GetRegisterNumber()); + } + } + continue; + } + + if (redefined) { + break; + } + + // x0 = x0 + ninsn->SetOperand(1, optVal.GetMovSrc()); + break; + } + + return redefined; +} + +bool RaX0Opt::PropagateX0ForCurrBb(BB *bb, X0OptInfo &optVal) { + bool redefined = false; + for (Insn *ninsn = optVal.GetRenameInsn()->next; ninsn && ninsn != bb->lastinsn->next; ninsn = ninsn->next) { + if (!ninsn->IsMachineInstruction()) { + continue; + } + redefined = PropagateRenameReg(ninsn, optVal); + if (redefined) { + break; + } + } + if (redefined == false) { + auto it = bb->liveout_regno.find(optVal.GetReplaceReg()); + if (it != bb->liveout_regno.end()) { + bb->liveout_regno.erase(it); + } + uint32 renameReg = static_cast(optVal.GetRenameOpnd())->GetRegisterNumber(); + bb->liveout_regno.insert(renameReg); + } + return redefined; +} + +void RaX0Opt::PropagateX0ForNextBb(BB *nextBb, X0OptInfo &optVal) { + bool redefined = false; + for (Insn *ninsn = nextBb->firstinsn; ninsn != nextBb->lastinsn->next; ninsn = ninsn->next) { + if (!ninsn->IsMachineInstruction()) { + continue; + } + redefined = PropagateRenameReg(ninsn, optVal); + if (redefined) { + break; + } + } + if (redefined == false) { + auto it = nextBb->livein_regno.find(optVal.GetReplaceReg()); + if (it != nextBb->livein_regno.end()) { + nextBb->livein_regno.erase(it); + } + uint32 renameReg = static_cast(optVal.GetRenameOpnd())->GetRegisterNumber(); + nextBb->livein_regno.insert(renameReg); + } +} + +// Perform optimization. +// First propagate x0 in a bb. +// Second propagation see comment in function. +void RaX0Opt::PropagateX0(CGFunc *cgfunc) { + FOR_ALL_BB(bb, cgfunc) { + X0OptInfo optVal; + + Insn *insn = bb->firstinsn; + while (insn && !insn->IsMachineInstruction()) { + insn = insn->next; + continue; + } + if (insn == nullptr) { + continue; + } + if (PropagateX0DetectX0(insn, optVal) == false) { + continue; + } + + // At this point the 1st insn is a mov from x0. + RegOperand *movDst = static_cast(insn->GetOperand(0)); + optVal.SetReplaceReg(movDst->GetRegisterNumber()); + + optVal.ResetRenameInsn(); + bool redefined = PropagateX0Optimize(bb, insn, optVal); + + if (redefined || (optVal.GetRenameInsn() == nullptr)) { + continue; + } + + /* Next pattern to help LSRA. Short cross bb live interval. + * Straight line code. Convert reg2 into bb local. + * bb1 + * mov reg2 <- x0 => mov reg2 <- x0 + * mov reg1 <- reg2 mov reg1 <- reg2 + * call call + * bb2 : livein< reg1 reg2 > + * use reg2 use reg1 + * .... + * reg2 not liveout + * + * Can allocate caller register for reg2. + */ + + // Further propagation of very short live interval cross bb reg + if (optVal.GetRenameReg() < kMaxRegNum) { // dont propagate physical reg + continue; + } + BB *nextBb = bb->next; + if (nextBb == nullptr) { + break; + } + if (bb->succs.size() != 1 || nextBb->preds.size() != 1) { + continue; + } + if (bb->succs.front() != nextBb || nextBb->preds.front() != bb) { + continue; + } + if (bb->liveout_regno.find(optVal.GetReplaceReg()) == bb->liveout_regno.end() || + bb->liveout_regno.find(optVal.GetRenameReg()) == bb->liveout_regno.end() || + nextBb->liveout_regno.find(optVal.GetReplaceReg()) != nextBb->liveout_regno.end()) { + continue; + } + + // Replace replace_reg by rename_reg. + redefined = PropagateX0ForCurrBb(bb, optVal); + + if (redefined) { + continue; + } + + PropagateX0ForNextBb(nextBb, optVal); + } +} + +} // namespace maplebe diff --git a/mapleall/maple_be/src/cg/riscv64/riscv64_reaching_definition.cpp b/mapleall/maple_be/src/cg/riscv64/riscv64_reaching_definition.cpp new file mode 100644 index 0000000..7d7fb07 --- /dev/null +++ b/mapleall/maple_be/src/cg/riscv64/riscv64_reaching_definition.cpp @@ -0,0 +1,1501 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#include "riscv64_reaching_definition.h" +#include "riscv64_cg.h" +#include "riscv64_operand.h" +namespace maplebe { + +/*check wether exception may be thrown between headInsn and tailInsn + return true if exception may be thrown. Otherwise return false. + */ +bool Riscv64ReachingDefinition::MayHasThrow(const Insn *headInsn, const Insn *tailInsn) { + CG_ASSERT(headInsn && tailInsn && headInsn->bb == tailInsn->bb, ""); + + if (headInsn->id >= tailInsn->id) { + return false; + } + + for (Insn *insn = tailInsn->prev; insn != headInsn; insn = insn->prev) { + if (!insn->IsMachineInstruction()) { + continue; + } + if (insn->CanThrow()) { + // If it is a memory operation and base register is FP, then continue. + if (insn->IsLoad() || insn->IsStore()) { + for (int i = 0; i < Insn::kMaxOperandNum; i++) { + Operand *opnd = insn->opnds[i]; + if (opnd == nullptr || !opnd->IsMemoryAccessOperand()) { + continue; + } + MemOperand *memopnd = static_cast(opnd); + Operand *base = memopnd->GetBaseRegister(); + if (base != nullptr && IsFrameReg(base)) { + break; + } else { + return true; + } + } + } else { + return true; + } + } + } + return false; +} + +/*insert pseudoInsn for parameters definition*/ +void Riscv64ReachingDefinition::InitStartGen() { + BB *bb = cgfunc->firstbb; + + // Parameters should be define first. + ParmLocator parmlocator(cgfunc->becommon); + PLocInfo ploc; + for (uint32 i = 0; i < cgfunc->func->formalDefVec.size(); i++) { + MIRType *ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(cgfunc->func->formalDefVec[i].formalTyIdx); + parmlocator.LocateNextParm(ty, ploc); + if (ploc.reg0 == 0) { + // If is a large frame, parameter addressing mode is based vreg:Vra. + continue; + } + + int32 symsize = cgfunc->becommon.type_size_table[ty->tyIdx.GetIdx()]; + if (symsize > 8) { + // For C structure passing in one or two registers. + symsize = 8; + } + RegType regtype = ploc.reg0 < V0 ? kRegTyInt : kRegTyFloat; + uint8 srcBitsize = uint8((symsize < 4 ? 4 : symsize) * BITS_PER_BYTE); + + Riscv64CGFunc *aarchcgfunc = static_cast(cgfunc); + RegOperand *regopnd = aarchcgfunc->GetOrCreatePhysicalRegisterOperand(ploc.reg0, srcBitsize, regtype); + + MOperator mop; + if (regtype == kRegTyInt) { + if (srcBitsize <= 32) { + mop = MOP_pseudo_param_def_w; + } else { + mop = MOP_pseudo_param_def_x; + } + } else { + if (srcBitsize <= 32) { + mop = MOP_pseudo_param_def_s; + } else { + mop = MOP_pseudo_param_def_d; + } + } + + Insn *pseudoInsn = cgfunc->cg->BuildInstruction(mop, regopnd); + bb->InsertInsnBegin(pseudoInsn); + pseudoInsns.insert(pseudoInsn); + + if (ploc.reg1) { + regopnd = aarchcgfunc->GetOrCreatePhysicalRegisterOperand(ploc.reg1, srcBitsize, regtype); + pseudoInsn = cgfunc->cg->BuildInstruction(mop, regopnd); + bb->InsertInsnBegin(pseudoInsn); + pseudoInsns.insert(pseudoInsn); + } + + { + /* Define memory address since store param may be transfered to stp and which with the short offset range. + We can not get the correct definition before RA. + Example: + add x8, sp, #712 + stp x0, x1, [x8] // store param: _this Reg40_R313644 + stp x2, x3, [x8,#16] // store param: Reg41_R333743 Reg42_R333622 + stp x4, x5, [x8,#32] // store param: Reg43_R401297 Reg44_R313834 + str x7, [x8,#48] // store param: Reg46_R401297 + + Fix me: Remove the following code. + Need to support base register = FP + constant value addressing mode. + */ + MIRSymbol *sym = cgfunc->func->formalDefVec[i].formalSym; + if (!sym->IsPreg()) { + MIRSymbol *firstsym = cgfunc->func->formalDefVec[i].formalSym; + Riscv64SymbolAlloc *firstsymloc = + static_cast(cgfunc->memlayout->sym_alloc_table[firstsym->GetStIndex()]); + int32 stoffset = cgfunc->GetBaseOffset(firstsymloc); + MIRType *firstty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(cgfunc->func->formalDefVec[i].formalTyIdx); + int32 firstsymsize = cgfunc->becommon.type_size_table[firstty->tyIdx.GetIdx()]; + int8 firststksize = firstsymsize < 4 ? 4 : firstsymsize; + + Riscv64MemOperand *memOpnd = cgfunc->memPool->New(RFP, stoffset, firststksize * 8); + MOperator mop = firststksize <= 4 ? MOP_pseudo_param_store_w : MOP_pseudo_param_store_x; + Insn *pseudoInsn = cgfunc->cg->BuildInstruction(mop, memOpnd); + bb->InsertInsnBegin(pseudoInsn); + pseudoInsns.insert(pseudoInsn); + } + } + } + + // If function has "bl MCC_InitializeLocalStackRef", should define corresponding memory. + Riscv64CGFunc *a64cgfunc = static_cast(cgfunc); + + for (int i = 0; i < a64cgfunc->refCount; i++) { + Riscv64MemOperand *memOpnd = cgfunc->memPool->New(RFP, a64cgfunc->beginOffset + i * 8, 64); + Insn *pseudoInsn = cgfunc->cg->BuildInstruction(MOP_pseudo_ref_init_x, memOpnd); + + bb->InsertInsnBegin(pseudoInsn); + pseudoInsns.insert(pseudoInsn); + } +} + +/*insert pseudoInsns for ehBB, R0 and R1 are defined in pseudoInsns*/ +void Riscv64ReachingDefinition::InitEhDefine(BB *bb) { + Riscv64CGFunc *aarchcgfunc = static_cast(cgfunc); + + // Insert MOP_pseudo_eh_def_x R1. + RegOperand *regopnd = aarchcgfunc->GetOrCreatePhysicalRegisterOperand(R1, 64, kRegTyInt); + Insn *pseudoInsn = cgfunc->cg->BuildInstruction(MOP_pseudo_eh_def_x, regopnd); + bb->InsertInsnBegin(pseudoInsn); + pseudoInsns.insert(pseudoInsn); + + // Insert MOP_pseudo_eh_def_x R0. + regopnd = aarchcgfunc->GetOrCreatePhysicalRegisterOperand(R0, 64, kRegTyInt); + pseudoInsn = cgfunc->cg->BuildInstruction(MOP_pseudo_eh_def_x, regopnd); + bb->InsertInsnBegin(pseudoInsn); + pseudoInsns.insert(pseudoInsn); +} + +/*insert pseudoInsns for return value R0/V0*/ +void Riscv64ReachingDefinition::AddRetPseudoInsn(BB *bb) { + Riscv64reg_t regno = static_cast(cgfunc)->GetReturnRegisterNumber(); + if (regno == INVALID_REGNO) { + return; + } + + Insn *retInsn = nullptr; + if (regno == R10) { + RegOperand *regopnd = + static_cast(cgfunc)->GetOrCreatePhysicalRegisterOperand(regno, 64, kRegTyInt); + retInsn = cgfunc->cg->BuildInstruction(MOP_pseudo_ret_int, regopnd); + } else { + CG_ASSERT(regno == V10, "CG internal error. Return value should be R0 or V0."); + RegOperand *regopnd = + static_cast(cgfunc)->GetOrCreatePhysicalRegisterOperand(regno, 64, kRegTyFloat); + retInsn = cgfunc->cg->BuildInstruction(MOP_pseudo_ret_float, regopnd); + } + + bb->AppendInsn(retInsn); + pseudoInsns.insert(retInsn); +} + +void Riscv64ReachingDefinition::AddRetPseudoInsns() { + uint32 exitbbsize = cgfunc->exitbbsvec.size(); + + if (exitbbsize == 0) { + if (cgfunc->lastbb->prev->firststmt == cgfunc->cleanup_label && cgfunc->lastbb->prev->prev) { + AddRetPseudoInsn(cgfunc->lastbb->prev->prev); + } else { + AddRetPseudoInsn(cgfunc->lastbb->prev); + } + } else { + for (uint32 i = 0; i < exitbbsize; i++) { + AddRetPseudoInsn(cgfunc->exitbbsvec[i]); + } + } +} + +/* We should add caller-saved regs to kill list, but it may significantly worse compile time. + Before RA: we just erase the corresponding gen eliment and add R0/V0 to kill list since only + R0/V0 may be defined more than once before RA. + Note: 1): Optimization: After merge call BB, add kill R0/V0 once each BB. + 2): Add caller-saved regs to kill list if analysis after RA. + */ +void Riscv64ReachingDefinition::KillAllCallerSavedRegs(BB *bb, Insn *callInsn) { + Riscv64CGFunc *a64cgfunc = static_cast(cgfunc); + RegOperand *phyopnd; + int i; + + phyopnd = a64cgfunc->GetOrCreatePhysicalRegisterOperand(R0, 64, kRegTyInt); + bb->kill.insert(DataAnalysisInfo(kInfoReg, phyopnd)); + bb->gen.erase(DataAnalysisInfo(kInfoReg, phyopnd)); + + phyopnd = a64cgfunc->GetOrCreatePhysicalRegisterOperand(V0, 64, kRegTyInt); + bb->kill.insert(DataAnalysisInfo(kInfoReg, phyopnd)); + bb->gen.erase(DataAnalysisInfo(kInfoReg, phyopnd)); + + for (i = R1; i <= R18; i++) { + phyopnd = a64cgfunc->GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)i, 64, kRegTyInt); + bb->gen.erase(DataAnalysisInfo(kInfoReg, phyopnd)); + } + + for (i = V0; i <= V7; i++) { + phyopnd = a64cgfunc->GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)i, 64, kRegTyInt); + bb->gen.erase(DataAnalysisInfo(kInfoReg, phyopnd)); + } + + for (i = V16; i <= V31; i++) { + phyopnd = a64cgfunc->GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)i, 64, kRegTyFloat); + bb->gen.erase(DataAnalysisInfo(kInfoReg, phyopnd)); + } +} + +void Riscv64ReachingDefinition::DirtyAllNonStackMem(BB *bb) { + return; +} + +/* We should add caller-saved regs to kill list, but it may significantly worse compile time. + So we just erase the corresponding gen eliment if before RA. + Note: Add caller-saved regs to kill list if analysis after RA. + */ +void Riscv64ReachingDefinition::KillAllCallerSavedRegsOnBBIn(BB *bb, Insn *callInsn) { + map, DataAnalysisInfoCmp>::iterator itIn; + Riscv64CGFunc *a64cgfunc = static_cast(cgfunc); + RegOperand *phyopnd = nullptr; + int i; + + for (i = R0; i <= R18; i++) { + phyopnd = a64cgfunc->GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)i, 64, kRegTyInt); + + itIn = bb->in.find(DataAnalysisInfo(kInfoReg, phyopnd)); + if (itIn != bb->in.end()) { + // Save redefine. + for (auto insnInfoElem : itIn->second) { + Insn *oldDefInsn = insnInfoElem.GetInsn(); + int idx = insnInfoElem.GetProperty() & DataInsnInfo::kIndexQuickcalc; + if (!oldDefInsn->redefine[idx]) { + oldDefInsn->redefine[idx] = mp->New>(rdalloc.Adapter()); + } + + oldDefInsn->redefine[idx]->insert(DataInsnInfo(callInsn, -1)); + } + + bb->in.erase(itIn); + } + } + + for (i = V0; i <= V7; i++) { + phyopnd = a64cgfunc->GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)i, 64, kRegTyInt); + + itIn = bb->in.find(DataAnalysisInfo(kInfoReg, phyopnd)); + if (itIn != bb->in.end()) { + // Save redefine. + for (auto insnInfoElem : itIn->second) { + Insn *oldDefInsn = insnInfoElem.GetInsn(); + int idx = insnInfoElem.GetProperty() & DataInsnInfo::kIndexQuickcalc; + if (!oldDefInsn->redefine[idx]) { + oldDefInsn->redefine[idx] = mp->New>(rdalloc.Adapter()); + } + + oldDefInsn->redefine[idx]->insert(DataInsnInfo(callInsn, -1)); + } + + bb->in.erase(itIn); + } + } + + for (i = V16; i <= V31; i++) { + phyopnd = a64cgfunc->GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)i, 64, kRegTyInt); + + itIn = bb->in.find(DataAnalysisInfo(kInfoReg, phyopnd)); + if (itIn != bb->in.end()) { + // Save redefine. + for (auto insnInfoElem : itIn->second) { + Insn *oldDefInsn = insnInfoElem.GetInsn(); + int idx = insnInfoElem.GetProperty() & DataInsnInfo::kIndexQuickcalc; + if (!oldDefInsn->redefine[idx]) { + oldDefInsn->redefine[idx] = mp->New>(rdalloc.Adapter()); + } + + oldDefInsn->redefine[idx]->insert(DataInsnInfo(callInsn, -1)); + } + + bb->in.erase(itIn); + } + } +} + +/* For riscv64, R0/V0 as the return register. + */ +void Riscv64ReachingDefinition::GenReturnValue(BB *bb, Insn *insn) { + map::iterator itGen; + + Riscv64CGFunc *a64cgfunc = static_cast(cgfunc); + RegOperand *phyopnd = nullptr; + if (insn->ret_type == Insn::kRegInt) { + phyopnd = a64cgfunc->GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)R0, 64, kRegTyInt); + bb->gen.insert(pair(DataAnalysisInfo(kInfoReg, phyopnd), DataInsnInfo(insn, -1))); + } else if (insn->ret_type == Insn::kRegFloat) { + phyopnd = a64cgfunc->GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)V0, 64, kRegTyFloat); + bb->gen.insert(pair(DataAnalysisInfo(kInfoReg, phyopnd), DataInsnInfo(insn, -1))); + } +} + +/* For riscv64, R0/V0 as the return register. + */ +void Riscv64ReachingDefinition::GenReturnValueOnBBIn(BB *bb, Insn *insn) { + map, DataAnalysisInfoCmp>::iterator itIn; + + Riscv64CGFunc *a64cgfunc = static_cast(cgfunc); + RegOperand *phyopnd = nullptr; + set s; + s.insert(DataInsnInfo(insn, -1)); + if (insn->ret_type == Insn::kRegInt) { + RegOperand *phyopnd = a64cgfunc->GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)R0, 64, kRegTyInt); + bb->in.insert(pair>(DataAnalysisInfo(kInfoReg, phyopnd), s)); + } else if (insn->ret_type == Insn::kRegFloat) { + phyopnd = a64cgfunc->GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)V0, 64, kRegTyFloat); + bb->in.insert(pair>(DataAnalysisInfo(kInfoReg, phyopnd), s)); + } +} + +/*initialize kill and gen for bb*/ +void Riscv64ReachingDefinition::InitKillGen(BB *bb, int mode) { + if (bb->IsEmpty()) { + return; + } + + FOR_BB_INSNS(insn, bb) { + if (!insn->IsMachineInstruction()) { + continue; + } + + const Riscv64MD *md = &Riscv64CG::kMd[static_cast(insn)->mop_]; + + if (insn->IsCall()) { + if (mode & RD_REGANALYSIS) { + // Kill all the caller-saved registers. + KillAllCallerSavedRegs(bb, insn); + + // Gen return value R0. + GenReturnValue(bb, insn); + } + continue; + } + + for (int i = 0; i < Insn::kMaxOperandNum; i++) { + Operand *opnd = insn->opnds[i]; + if (opnd == nullptr) { + continue; + } + Riscv64OpndProp *regprop = static_cast(md->operand_[i]); + bool isDef = regprop->IsDef(); + if (!isDef && !opnd->IsMemoryAccessOperand()) { + continue; + } + + if (opnd->IsList()) { + CG_ASSERT(false, "Internal error, list operand should not be defined."); + } else if (opnd->IsMemoryAccessOperand()) { + // Need to consider pre/post index addressing. + // Current not exist before RA. + Riscv64MemOperand *memopnd = static_cast(opnd); + RegOperand *base = memopnd->GetBaseRegister(); + RegOperand *index = memopnd->GetIndexRegister(); + + if (base == nullptr) { + // Do nothing. + } else { + // Check if it is a pre/post index memory operand. + if (!isDef || !(mode & RD_MEMANALYSIS)) { + continue; + }; + + if (IsFrameReg(base)) { + if (index) { + CG_ASSERT(false, "Exist [x29 + index register addressing ]."); + // Currently dirty all of the memory definition. + // Can do analysis of index register for optimization. + DirtyAllStackMemGen(bb); + + // For Reaching definition, internal_flag1 indicates this BB + // has an instruction that will dirty all the memory definition. + bb->internal_flag1 = true; + } else { + DefineMem(bb, memopnd, insn, i); + } + } else { + // Can build non-stack memory info here. + } + } + } else if (opnd->IsConditionCode()) { + // Can add RFlag mapping. + if (mode & RD_REGANALYSIS) { + DefineRegister(bb, static_cast(opnd), insn, i); + } + } else if (opnd->IsRegister()) { + // Register. + if (mode & RD_REGANALYSIS) { + if (insn->GetMachineOpcode() == MOP_pseudo_eh_def_x) { + DefineRegister(bb, static_cast(opnd), insn, i, DataInsnInfo::kMaydef); + } else if (insn->IsPartDef()) { + DefineRegister(bb, static_cast(opnd), insn, i, DataInsnInfo::kPartdef); + } else { + DefineRegister(bb, static_cast(opnd), insn, i, + i ? DataInsnInfo::kSecondMemAddr : DataInsnInfo::kNormal); + } + } + } + } + } +} + +/* This function will change bb->in + add definition DataInsnInfo for used Operand. + */ +void Riscv64ReachingDefinition::GenerateUseDef(BB *bb, int mode) { + map, DataAnalysisInfoCmp>::iterator itMap; + + for (Insn *insn = bb->firstinsn; insn; insn = insn->next) { + if (!insn->IsMachineInstruction()) { + continue; + } + + const Riscv64MD *md = &Riscv64CG::kMd[static_cast(insn)->mop_]; + + for (int i = 0; i < Insn::kMaxOperandNum; i++) { + Operand *opnd = insn->opnds[i]; + if (opnd == nullptr) { + continue; + } + + Riscv64OpndProp *regprop = static_cast(md->operand_[i]); + + if (opnd->IsMemoryAccessOperand()) { + // Build use->def from base/index register to it's define. + Riscv64MemOperand *memopnd = static_cast(opnd); + RegOperand *baseRegister = memopnd->GetBaseRegister(); + if (baseRegister) { + itMap = bb->in.find(DataAnalysisInfo(kInfoReg, baseRegister)); + if (itMap != bb->in.end()) { + insn->defs[i + 2] = mp->New>(rdalloc.Adapter()); + for (auto s : itMap->second) { + insn->defs[i + 2]->insert(s); + } + } + } + RegOperand *indexRegister = memopnd->GetIndexRegister(); + if (indexRegister) { + itMap = bb->in.find(DataAnalysisInfo(kInfoReg, indexRegister)); + if (itMap != bb->in.end()) { + insn->defs[i + 3] = mp->New>(rdalloc.Adapter()); + for (auto s : itMap->second) { + insn->defs[i + 3]->insert(s); + } + } + } + } + + if (regprop->IsUse()) { + if (opnd->IsRegister() || opnd->IsMemoryAccessOperand()) { + itMap = bb->in.find(DataAnalysisInfo(opnd->IsRegister() ? kInfoReg : kInfoMem, opnd)); + if (itMap != bb->in.end()) { + insn->defs[i] = mp->New>(rdalloc.Adapter()); + for (auto s : itMap->second) { + insn->defs[i]->insert(s); + } + } else { + // if (insn->IsLoad() && IsFrameReg(static_cast(opnd)->GetBaseRegister() ) ) + // CG_ASSERT(false, "Should not exist non-define use."); + } + } else if (opnd->IsList()) { + if (!(mode & RD_REGANALYSIS)) { + continue; + } + ListOperand *listOpnd = static_cast(opnd); + int j = 0; + for (auto lst : listOpnd->GetOperands()) { + itMap = bb->in.find(DataAnalysisInfo(kInfoReg, lst)); + if (itMap != bb->in.end()) { + CG_ASSERT((i + j) < Insn::kMaxUseOperandNum, "Error, out of range."); + insn->defs[i + j] = mp->New>(rdalloc.Adapter()); + for (auto s : itMap->second) { + insn->defs[i + j]->insert(s); + } + } else { + // if (insn->IsLoad() && IsFrameReg(static_cast(opnd)->GetBaseRegister() ) ) + // CG_ASSERT(false, "Should not exist non-define use."); + } + j++; + } + } + } + } + + if (insn->IsCall()) { + if (mode & RD_REGANALYSIS) { + // Kill all the caller-saved registers. + KillAllCallerSavedRegsOnBBIn(bb, insn); + + // Gen return value R0. + GenReturnValueOnBBIn(bb, insn); + } + continue; + } + + for (int i = 0; i < Insn::kMaxOperandNum; i++) { + Operand *opnd = insn->opnds[i]; + if (opnd == nullptr) { + continue; + } + + Riscv64OpndProp *regprop = static_cast(md->operand_[i]); + + if (regprop->IsDef()) { + if (opnd->IsMemoryAccessOperand()) { + if (!(mode & RD_MEMANALYSIS)) { + continue; + } + Riscv64MemOperand *memopnd = static_cast(opnd); + RegOperand *base = memopnd->GetBaseRegister(); + RegOperand *index = memopnd->GetIndexRegister(); + + if (base == nullptr) { + // Do nothing. + } else { + if (!(mode & RD_MEMANALYSIS)) { + continue; + } + + if (IsFrameReg(base)) { + if (index) { + // Currently dirty all of the memory definition. + // Can do analysis of index register for optimization. + DirtyAllStackMemOnBBIn(bb); + } else { + DefineMemOnBBIn(bb, memopnd, insn, i); + } + } + } + } else if (opnd->IsConditionCode()) { + if (mode & RD_REGANALYSIS) { + DefineRegisterOnBBIn(bb, opnd, insn, i); + } + } else if (opnd->IsRegister()) { + // Register. + if (mode & RD_REGANALYSIS) { + if (insn->GetMachineOpcode() == MOP_pseudo_eh_def_x) { + DefineRegisterOnBBIn(bb, opnd, insn, i, DataInsnInfo::kMaydef); + } else if (insn->IsPartDef()) { + DefineRegisterOnBBIn(bb, opnd, insn, i, DataInsnInfo::kPartdef); + } else { + DefineRegisterOnBBIn(bb, opnd, insn, i, i ? DataInsnInfo::kSecondMemAddr : DataInsnInfo::kNormal); + } + } + } + } + } + } +} + +void Riscv64ReachingDefinition::InsertUseToDef(DataInsnInfo &insnInfo, Insn *useInsn, short index, short userProperty) { + Insn *defInsn = insnInfo.GetInsn(); + unsigned short defProperty = insnInfo.GetProperty(); + int duIdx = defProperty & DataInsnInfo::kIndexQuickcalc; + + userProperty |= (defProperty & DataInsnInfo::kDataProp); + + if (useInsn->IsCall() && index > 0) { + CG_ASSERT(index > 0, "Internal error."); + + index--; + userProperty |= DataInsnInfo::kCallParam; + } + + if (!defInsn->uses[duIdx]) { + defInsn->uses[duIdx] = mp->New>(rdalloc.Adapter()); + } + + defInsn->uses[duIdx]->insert(DataInsnInfo(useInsn, index, userProperty)); + + if (!insnInfo.IsMulGen()) { + return; + } + + DataInsnInfo *prevMultiGenInsnInfo = insnInfo.GetPrevMultiGenInsn(); + while (prevMultiGenInsnInfo) { + defInsn = prevMultiGenInsnInfo->GetInsn(); + duIdx = prevMultiGenInsnInfo->GetProperty() & DataInsnInfo::kIndexQuickcalc; + + if (!defInsn->uses[duIdx]) { + defInsn->uses[duIdx] = mp->New>(rdalloc.Adapter()); + } + + defInsn->uses[duIdx]->insert(DataInsnInfo(useInsn, index, userProperty)); + + prevMultiGenInsnInfo = prevMultiGenInsnInfo->GetPrevMultiGenInsn(); + } +} + +/*add using DataInsnInfo for defined Operand.*/ +void Riscv64ReachingDefinition::GenerateDefUse(BB *bb) { + FOR_BB_INSNS(insn, bb) { + if (!insn->IsMachineInstruction()) { + continue; + } + + short userProperty = DataInsnInfo::kNormal; + int memOpndIdx = Insn::kMaxUseOperandNum; + + if (insn->IsLoad()) { + memOpndIdx = insn->GetResultNum(); + } else if (insn->IsStore()) { + memOpndIdx = insn->GetOpndNum(); + } + + for (int i = 0; i < Insn::kMaxUseOperandNum; i++) { + if (insn->defs[i]) { + int index = i; + + if (i > memOpndIdx) { + CG_ASSERT((i - memOpndIdx) <= 3, "Internal error."); + + index = memOpndIdx; + + // Set property SECONDMEMADDR or BASEREG or INDEXREG. + userProperty |= (i - memOpndIdx); + } + + for (auto defElem : *(insn->defs[i])) { + InsertUseToDef(defElem, insn, index, userProperty); + } + } + } + } +} + +void Riscv64ReachingDefinition::DumpUDChain(BB *bb) { + LogInfo::MapleLogger() << "\n Start to dump U-D chain: " << endl; + + FOR_BB_INSNS(insn, bb) { + if (!insn->IsMachineInstruction()) { + continue; + } + + LogInfo::MapleLogger() << " U-D chain for insn : "; + insn->dump(); + + MapleList::iterator it; + for (int i = 0; i < Insn::kMaxUseOperandNum; i++) { + if (!insn->defs[i] || insn->defs[i]->size() == 0) { + continue; + } + + if (insn->IsCall() && i > 0) { + LogInfo::MapleLogger() << " For operand[" << i << "] : "; + CG_ASSERT(insn->opnds[1]->IsList(), "Internal error."); + ListOperand *listOpnd = static_cast(insn->opnds[1]); + if (i == 1) { + it = listOpnd->GetOperands().begin(); + } + CG_ASSERT(it != listOpnd->GetOperands().end(), "Internal error."); + if (it != listOpnd->GetOperands().end()) { + (*it++)->dump(); + } + } else { + if (insn->IsLoad() || insn->IsStore()) { + int memOpndIdx = Insn::kMaxUseOperandNum; + if (insn->IsLoad()) { + memOpndIdx = insn->GetResultNum(); + } else if (insn->IsStore()) { + memOpndIdx = insn->GetOpndNum(); + } + + if (i <= memOpndIdx) { + CG_ASSERT(i < Insn::kMaxOperandNum, "Internal error."); + LogInfo::MapleLogger() << " For operand[" << i << "] : "; + insn->opnds[i]->dump(); + } else { + CG_ASSERT((i - memOpndIdx) <= 3, "Internal error."); + short property = i - memOpndIdx; + + switch (property) { + case DataInsnInfo::kNormal: { + LogInfo::MapleLogger() << " For first memory address operand : "; + insn->opnds[memOpndIdx]->dump(); + break; + } + case DataInsnInfo::kSecondMemAddr: { + LogInfo::MapleLogger() << " For second memory address operand : "; + insn->opnds[memOpndIdx]->dump(); + break; + } + case DataInsnInfo::kBaseReg: { + CG_ASSERT(insn->opnds[memOpndIdx]->IsMemoryAccessOperand(), + "CG internal error, should be memory operand."); + LogInfo::MapleLogger() << " For base register of the memory operand : "; + Riscv64MemOperand *memOpnd = static_cast(insn->opnds[memOpndIdx]); + memOpnd->GetBaseRegister()->dump(); + break; + } + case DataInsnInfo::kIndexReg: { + CG_ASSERT(insn->opnds[memOpndIdx]->IsMemoryAccessOperand(), + "CG internal error, should be memory operand."); + LogInfo::MapleLogger() << " For index register of the memory operand : "; + Riscv64MemOperand *memOpnd = static_cast(insn->opnds[memOpndIdx]); + memOpnd->GetIndexRegister()->dump(); + break; + } + default: + CG_ASSERT(false, "CG internal error."); + } + } + } else { + CG_ASSERT(i < Insn::kMaxOperandNum, "Internal error."); + LogInfo::MapleLogger() << " For operand[" << i << "] : "; + insn->opnds[i]->dump(); + } + } + + for (auto insnInfo : *(insn->defs[i])) { + LogInfo::MapleLogger() << "\n Define insn: "; + insnInfo.GetInsn()->dump(); + if (insnInfo.IsMulGen()) { + DataInsnInfo *tempinfo = insnInfo.GetPrevMultiGenInsn(); + if (!tempinfo) { + LogInfo::MapleLogger() << "\n-----mulgen but no prevmulgeninsn-----\n"; + } else { + LogInfo::MapleLogger() << "\n------prev multigen insn:------\n"; + tempinfo->GetInsn()->dump(); + } + } + + LogInfo::MapleLogger() << " SecondMemAddr[" << (insnInfo.IsSecondMemAddr() ? "true" : "false") << "], "; + LogInfo::MapleLogger() << "BaseReg[" << (insnInfo.IsBaseRegister() ? "true" : "false") << "], "; + LogInfo::MapleLogger() << "IndexReg[" << (insnInfo.IsIndexRegister() ? "true" : "false") << "], "; + LogInfo::MapleLogger() << "CallParam[" << (insnInfo.IsCallParam() ? "true" : "false") << "], "; + LogInfo::MapleLogger() << "Dirty[" << (insnInfo.IsDirty() ? "true" : "false") << "], "; + LogInfo::MapleLogger() << "MulGen[" << (insnInfo.IsMulGen() ? "true" : "false") << "], "; + LogInfo::MapleLogger() << "MayDef[" << (insnInfo.IsMayDef() ? "true" : "false") << "], "; + LogInfo::MapleLogger() << "PartDef[" << (insnInfo.IsPartDef() ? "true" : "false") << "]"; + LogInfo::MapleLogger() << endl; + } + } + } +} + +void Riscv64ReachingDefinition::DumpDUChain(BB *bb) { + LogInfo::MapleLogger() << "\n Start to dump D-U chain: " << endl; + + FOR_BB_INSNS(insn, bb) { + if (!insn->IsMachineInstruction()) { + continue; + } + + LogInfo::MapleLogger() << " D-U chain for insn : "; + insn->dump(); + + MapleList::iterator it; + for (int i = 0; i < Insn::kMaxDefineOperandNum; i++) { + if (!insn->uses[i] || insn->uses[i]->size() == 0) { + continue; + } + + if (insn->IsCall()) { + LogInfo::MapleLogger() << " For return value R0 : "; + + Riscv64CGFunc *a64cgfunc = static_cast(cgfunc); + RegOperand *phyopnd = a64cgfunc->GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)R0, 64, kRegTyInt); + phyopnd->dump(); + } else { + LogInfo::MapleLogger() << " For " << i << "th operand : "; + insn->opnds[i]->dump(); + } + + for (auto insnInfo : *(insn->uses[i])) { + LogInfo::MapleLogger() << "\n Use insn: "; + insnInfo.GetInsn()->dump(); + LogInfo::MapleLogger() << " SecondMemAddr[" << (insnInfo.IsSecondMemAddr() ? "true" : "false") << "], "; + LogInfo::MapleLogger() << "BaseReg[" << (insnInfo.IsBaseRegister() ? "true" : "false") << "], "; + LogInfo::MapleLogger() << "IndexReg[" << (insnInfo.IsIndexRegister() ? "true" : "false") << "], "; + LogInfo::MapleLogger() << "CallParam[" << (insnInfo.IsCallParam() ? "true" : "false") << "], "; + LogInfo::MapleLogger() << "Dirty[" << (insnInfo.IsDirty() ? "true" : "false") << "], "; + LogInfo::MapleLogger() << "MulGen[" << (insnInfo.IsMulGen() ? "true" : "false") << "], "; + LogInfo::MapleLogger() << "MayDef[" << (insnInfo.IsMayDef() ? "true" : "false") << "], "; + LogInfo::MapleLogger() << "PartDef[" << (insnInfo.IsPartDef() ? "true" : "false") << "]"; + LogInfo::MapleLogger() << endl; + } + } + } +} + +void Riscv64ReachingDefinition::DumpWAWDependence(BB *bb) { + LogInfo::MapleLogger() << "\n WAW dependence: " << endl; + + FOR_BB_INSNS(insn, bb) { + if (!insn->IsMachineInstruction()) { + continue; + } + + LogInfo::MapleLogger() << "\n WAW dependence for insn : "; + insn->dump(); + + MapleList::iterator it; + for (int i = 0; i < Insn::kMaxDefineOperandNum; i++) { + LogInfo::MapleLogger() << " For " << i << "th destination operand : "; + if (insn->redefine[i] && insn->redefine[i]->size()) { + for (auto redefInsn : *(insn->redefine[i])) { + LogInfo::MapleLogger() << "\n Redefine insn: \n "; + redefInsn.GetInsn()->dump(); + } + } + + if (insn->predefine[i] && insn->predefine[i]->size()) { + for (auto predefInsn : *(insn->predefine[i])) { + LogInfo::MapleLogger() << "\n Previous define insn: \n "; + predefInsn.GetInsn()->dump(); + } + } + } + } +} + +/* Remove insn and maintain data flow information. + Need to handle property changes. such as dirty, multidef, mayDef. + */ +void Riscv64ReachingDefinition::RemoveDUUDForInsn(Insn *insn) { + CG_ASSERT(insn, "CG internal error, insn should not be nullptr."); + + // For each uses of insn, remove D-U. + for (int i = 0; i < Insn::kMaxUseOperandNum; i++) { + if (insn->defs[i] == nullptr) { + continue; + } + + for (auto defInsnInfo : *(insn->defs[i])) { + Insn *defInsn = defInsnInfo.GetInsn(); + int idx = defInsnInfo.GetDUIndex(); + + CG_ASSERT(defInsn->uses[idx], "CG internal error."); + // property was used in the compare functor of set, so property can't be default + if (insn->IsCall() && i > 0) { + defInsn->uses[idx]->erase(DataInsnInfo(insn, i - 1, DataInsnInfo::kCallParam)); + } else { + defInsn->uses[idx]->erase(DataInsnInfo(insn, i)); + } + } + + insn->defs[i] = nullptr; + } + + // For each definition operand of insn, rebuild links between it's uses and it's predefine operands. + for (int i = 0; i < Insn::kMaxDefineOperandNum; i++) { + if (insn->uses[i] != nullptr) { + // If insn has predefine insn, then build duud between predefine insn and use insn. + if (insn->predefine[i] != nullptr) { + for (auto predefInsnInfo : *(insn->predefine[i])) { + Insn *predefInsn = predefInsnInfo.GetInsn(); + int predefIdx = predefInsnInfo.GetDUIndex(); + + CG_ASSERT(predefInsn->redefine[predefIdx], "CG internal error."); + + for (auto useInsnInfo : *(insn->uses[i])) { + Insn *useInsn = useInsnInfo.GetInsn(); + int useInsnIdx = useInsnInfo.GetUDIndex(); + + // Add def->use between predefInsn and useInsn. + if (predefInsn->uses[predefIdx] == nullptr) { + predefInsn->uses[predefIdx] = mp->New>(rdalloc.Adapter()); + } + + predefInsn->uses[predefIdx]->insert(useInsnInfo); + + // Add use-def between useInsn and predefInsn + CG_ASSERT(useInsn->defs[useInsnIdx], "CG internal error."); + useInsn->defs[useInsnIdx]->insert(predefInsnInfo); + } + } + } + + // Remove use->define between useInsn and insn. + for (auto useInsnInfo : *(insn->uses[i])) { + Insn *useInsn = useInsnInfo.GetInsn(); + int useInsnIdx = useInsnInfo.GetUDIndex(); + + CG_ASSERT(useInsn->defs[useInsnIdx], "CG internal error."); + useInsn->defs[useInsnIdx]->erase(DataInsnInfo(insn, 0)); + } + + // Remove def->use from insn to it's uses. + insn->uses[i]->clear(); + insn->uses[i] = nullptr; + } + } + + // Rebuild redefine. + for (int i = 0; i < Insn::kMaxDefineOperandNum; i++) { + if (insn->predefine[i] != nullptr) { + for (auto predefInsnInfo : *(insn->predefine[i])) { + Insn *predefInsn = predefInsnInfo.GetInsn(); + int idx = predefInsnInfo.GetDUIndex(); + + CG_ASSERT(predefInsn->redefine[idx], "CG internal error."); + + predefInsn->redefine[idx]->erase(DataInsnInfo(insn, 0)); + + if (insn->redefine[i]) { + for (auto redefInsnInfo : *(insn->redefine[i])) { + // if redefine insn is same as insn, don't need to build relation between predefine insn and define insn + if (redefInsnInfo.GetInsn() == insn) { + continue; + } + + predefInsn->redefine[idx]->insert(redefInsnInfo); + Insn *redefInsn = redefInsnInfo.GetInsn(); + + // Call insn do not have predefine. + if (!redefInsn->IsCall()) { + int redefIdx = redefInsnInfo.GetDUIndex(); + + CG_ASSERT(redefInsn->predefine[redefIdx], "CG internal error."); + + redefInsn->predefine[redefIdx]->insert(predefInsnInfo); + } + } + } + } + } + + if (insn->redefine[i]) { + for (auto redefInsnInfo : *(insn->redefine[i])) { + Insn *redefInsn = redefInsnInfo.GetInsn(); + + // Call insn do not have predefine. + if (!redefInsn->IsCall()) { + int redefIdx = redefInsnInfo.GetDUIndex(); + + CG_ASSERT(redefInsn->predefine[redefIdx], "CG internal error."); + + redefInsn->predefine[redefIdx]->erase(DataInsnInfo(insn, 0)); + } + } + } + } +} + +/* Uses: After insert an instruction, build data flow insns for one source operand. + Params: 1) new_insn: The insn inserted. + 2) new_index: The index of the destination operand. + 3) new_prop: Indicate the kind of the destination operand. (NORMAL / SECONDDEF / BASEREG / INDEXREG / + CALLPARAM) 4) ref_insn: The reference instruction with the same destination operand. nullptr if the operand is a new + operand without predefine/redefine/uses. 5) ref_index: The index of the destination operand. 6) ref_prop: Indicate + the kind of the destination operand. (NORMAL / SECONDDEF / BASEREG / INDEXREG / CALLPARAM) + */ +void Riscv64ReachingDefinition::InsertDUUDForSrcOperand(Insn *newInsn, short newIndex, unsigned short newProp, + Insn *refInsn, short refIndex, unsigned short refProp) { + CG_ASSERT(newInsn, "CG internal error, new_insn should not be nullptr."); + + if (refInsn == nullptr) { + LogInfo::MapleLogger() << "CG Warning, use without def. " << cgfunc->GetName() << std::endl; + return; + } + + int refInsnUDIdx = refProp & DataInsnInfo::kIndexQuickcalc; + + CG_ASSERT(refInsnUDIdx != DataInsnInfo::kIndexQuickcalc, "CG internal error."); + CG_ASSERT(!(refInsnUDIdx && (refProp & DataInsnInfo::kCallParam)), + "CG internal error, can not with both kIndexQuickcalc and CALLPARAM property."); + + refInsnUDIdx = refIndex + refInsnUDIdx; + // If is useInsn with CALLPARAM property, index indicates the ith parameter. + refInsnUDIdx = (refProp & DataInsnInfo::kCallParam) ? refInsnUDIdx + 1 : refInsnUDIdx; + + int newInsnUDIdx = newProp & DataInsnInfo::kIndexQuickcalc; + + CG_ASSERT(newInsnUDIdx != DataInsnInfo::kIndexQuickcalc, "CG internal error."); + CG_ASSERT(!(newInsnUDIdx && (newProp & DataInsnInfo::kCallParam)), + "CG internal error, can not with both kIndexQuickcalc and CALLPARAM property."); + + newInsnUDIdx = newIndex + newInsnUDIdx; + // If is useInsn with CALLPARAM property, index indicates the ith parameter. + newInsnUDIdx = (newProp & DataInsnInfo::kCallParam) ? newInsnUDIdx + 1 : newInsnUDIdx; + + if (refInsn->defs[refInsnUDIdx]) { + if (newInsn->defs[newInsnUDIdx] == nullptr) { + newInsn->defs[newInsnUDIdx] = mp->New>(rdalloc.Adapter()); + } + for (auto defInsnInfo : (*refInsn->defs[refInsnUDIdx])) { + // Build use->def from new_insn to desfInsn. + newInsn->defs[newInsnUDIdx]->insert(defInsnInfo); + + // Build def->use from defInsn to new_insn. + Insn *defInsn = defInsnInfo.GetInsn(); + int defInsnDUIdx = defInsnInfo.GetDUIndex(); + + CG_ASSERT(defInsn->uses[defInsnDUIdx] != nullptr, "CG internal error, defInsn should have uses."); + unsigned short newInsnProp = newProp | (defInsnInfo.GetProperty() & DataInsnInfo::kDataProp); + defInsn->uses[defInsnDUIdx]->insert(DataInsnInfo(newInsn, newIndex, newInsnProp)); + } + } else { + LogInfo::MapleLogger() << "CG Warning, use without def. " << cgfunc->GetName() << std::endl; + return; + } +} + +/* Uses: After insert an instruction, build data flow insns for one destination operand. + Params: 1) new_insn: The insn inserted. + 2) new_index: The index of the destination operand. + 3) new_prop: Indicate the kind of the destination operand. (NORMAL / SECONDDEF / BASEREG) + 4) ref_insn: The reference instruction with the same destination operand. ref_insn should not be a call insn. + nullptr if the operand is a new operand without predefine/redefine/uses. + 5) ref_index: The index of the destination operand. + 6) ref_prop: Indicate the kind of the destination operand. (NORMAL / SECONDDEF / BASEREG) + 7) isRefInsnBeforeNewInsn: true if new_insn is inserted just after ref_insn, otherwise false. + */ +void Riscv64ReachingDefinition::InsertDUUDForDestOperand(Insn *newInsn, short newIndex, unsigned short newProp, + Insn *refInsn, short refIndex, unsigned short refProp, + bool isRefInsnBeforeNewInsn) { + MapleSet::iterator itSet; + MapleSet::iterator itSet2; + + CG_ASSERT(newInsn, "CG internal error, new_insn should not be nullptr."); + + if (refInsn == nullptr) { + return; + } + + int refDuIdx = refIndex + (refProp & DataInsnInfo::kIndexQuickcalc); + int newDuIdx = newIndex + (newProp & DataInsnInfo::kIndexQuickcalc); + if (isRefInsnBeforeNewInsn) { + // new_insn is just after ref_insn. + if (refInsn->uses[refDuIdx] != nullptr) { + if (newInsn->uses[newDuIdx] == nullptr) { + newInsn->uses[newDuIdx] = mp->New>(rdalloc.Adapter()); + } + // Add Def->Use and Use->Def between new_insn and ref_insn's uses. + // Remove Def->Use and Use->Def between ref_insn and it's uses. + for (itSet2 = refInsn->uses[refDuIdx]->begin(); itSet2 != refInsn->uses[refDuIdx]->end();) { + const DataInsnInfo &useInsnInfo = (*itSet2); + Insn *useInsn = useInsnInfo.GetInsn(); + int useInsnIdx = useInsnInfo.GetUDIndex(); + + CG_ASSERT(useInsn->defs[useInsnIdx], "CG internal error."); + // find ref_insn in useInsn's defs and change ref_insn to new insn. + itSet = useInsn->defs[useInsnIdx]->find(DataInsnInfo(refInsn, DataInsnInfo::kAnyIndex)); + CG_ASSERT(itSet != useInsn->defs[useInsnIdx]->end(), "CG internal error, Use should have Def."); + const DataInsnInfo &refInsnInfo = (*itSet); + DataInsnInfo newInsnInfo(newInsn, newIndex, newProp); + newInsnInfo.SetProperty(refInsnInfo.GetProperty() & + (DataInsnInfo::kDirty | DataInsnInfo::kMultigen | DataInsnInfo::kMaydef)); + newInsnInfo.SetPrevMultiGenInsn(refInsnInfo.GetPrevMultiGenInsn()); + + if (useInsn != newInsn) { + // Remove use->def between useInsn and ref_insn, and build use->def between useInsn and new_insn. + useInsn->defs[useInsnIdx]->erase(itSet); + useInsn->defs[useInsnIdx]->insert(newInsnInfo); + + // Build def->use between new_insn and useInsn. + newInsn->uses[newDuIdx]->insert(useInsnInfo); + + // Remove ref_insn's def->use. + refInsn->uses[refDuIdx]->erase(itSet2++); + } else { + itSet2++; + } + } + + if (refInsn->uses[refDuIdx]->empty()) { + refInsn->uses[refDuIdx] = nullptr; + } + } + + if (refInsn->redefine[refDuIdx]) { + if (newInsn->redefine[newDuIdx] == nullptr) { + newInsn->redefine[newDuIdx] = mp->New>(rdalloc.Adapter()); + } + + for (auto redefInsnInfo : *(refInsn->redefine[refDuIdx])) { + // 1) Build redefine between new_insn and redefineInsns of ref_insn. + newInsn->redefine[newDuIdx]->insert(redefInsnInfo); + + // 2) Build predefine between redefineInsns of ref_insn and new_insn. + Insn *redefInsn = redefInsnInfo.GetInsn(); + int redefInsnIdx = redefInsnInfo.GetDUIndex(); + + // Call insn do not have predefine. + if (!redefInsn->IsCall()) { + CG_ASSERT(redefInsn->predefine[redefInsnIdx], "CG internal error."); + // find ref_insn in redefInsn's predefine and change ref_insn to new insn. + itSet = redefInsn->predefine[redefInsnIdx]->find(DataInsnInfo(refInsn, DataInsnInfo::kAnyIndex)); + CG_ASSERT(itSet != redefInsn->predefine[redefInsnIdx]->end(), + "CG internal error, redefInsn should have predef."); + + redefInsn->predefine[redefInsnIdx]->insert(DataInsnInfo(newInsn, newIndex, newProp)); + + // 3) Remove predefine between redefineInsns of ref_insn and ref_insn. + redefInsn->predefine[redefInsnIdx]->erase(itSet); + } + } + + // 4) Remove redefine between ref_insn and redefineInsns of ref_insn. + refInsn->redefine[refDuIdx]->clear(); + } else { + refInsn->redefine[refDuIdx] = mp->New>(rdalloc.Adapter()); + } + + // Build ref_insn's redefine between ref_insn and new_insn. + refInsn->redefine[refDuIdx]->insert(DataInsnInfo(newInsn, newIndex, newProp)); + + // Build new_insn's predefine between new_insn and ref_insn. + if (newInsn->predefine[newDuIdx] == nullptr) { + newInsn->predefine[newDuIdx] = mp->New>(rdalloc.Adapter()); + } + newInsn->predefine[newDuIdx]->insert(DataInsnInfo(refInsn, refIndex, refProp)); + } else { + // new_insn is just before ref_insn. + if (refInsn->predefine[refDuIdx]) { + // new_insn should have predefine too. + if (newInsn->predefine[newDuIdx] == nullptr) { + newInsn->predefine[newDuIdx] = mp->New>(rdalloc.Adapter()); + } + for (auto predefInsnInfo : *(refInsn->predefine[refDuIdx])) { + Insn *predefInsn = predefInsnInfo.GetInsn(); + int predefInsnIdx = predefInsnInfo.GetDUIndex(); + // Check if there is a new_insn's def->use is ref_insn's source operands. + if (predefInsn->uses[predefInsnIdx]) { + bool find = false; + do { + // ref_insn may have multiple same use operands. + itSet2 = predefInsn->uses[predefInsnIdx]->find(DataInsnInfo(refInsn, DataInsnInfo::kAnyIndex)); + if (itSet2 != predefInsn->uses[predefInsnIdx]->end()) { + find = true; + // Find it. Then: + // 1) Build a new def->use between new_insn and ref_insn. + if (newInsn->uses[newDuIdx] == nullptr) { + newInsn->uses[newDuIdx] = mp->New>(rdalloc.Adapter()); + } + DataInsnInfo useInsnInfo = (*itSet2); + useInsnInfo.ClearProperty(DataInsnInfo::kDirty | DataInsnInfo::kMultigen); + newInsn->uses[newDuIdx]->insert(useInsnInfo); + + // 2) Build a new use->def between ref_insn and new_insn. + Insn *useInsn = useInsnInfo.GetInsn(); + int useInsnIdx = useInsnInfo.GetUDIndex(); + + CG_ASSERT(useInsn->defs[useInsnIdx], "CG internal error."); + + useInsn->defs[useInsnIdx]->insert(DataInsnInfo(newInsn, newIndex, newProp)); + + // 3) Remove use->def between ref_insn and predefInsn. + // find ref_insn in predefInsn's uses and change ref_insn to new insn. + itSet = useInsn->defs[useInsnIdx]->find(DataInsnInfo(predefInsn, DataInsnInfo::kAnyIndex)); + CG_ASSERT(itSet != useInsn->defs[useInsnIdx]->end(), "CG internal error, Use should have Def."); + useInsn->defs[useInsnIdx]->erase(itSet); + + // 4) Remove def->use between predefInsn and ref_insn. + predefInsn->uses[predefInsnIdx]->erase(itSet2); + } + } while (find); + + if (predefInsn->uses[predefInsnIdx]->empty()) { + predefInsn->uses[predefInsnIdx] = nullptr; + } + } + + // Build predefine from new_insn to predefInsn. + newInsn->predefine[newDuIdx]->insert(predefInsnInfo); + + CG_ASSERT(predefInsn->redefine[predefInsnIdx], "CG internal error. predefInsn should have redefine data."); + + // Build redefine from predefInsn to new_insn. + predefInsn->redefine[predefInsnIdx]->insert(DataInsnInfo(newInsn, newIndex, newProp)); + + // Remove redefine from predefInsn to ref_insn. + itSet = predefInsn->redefine[predefInsnIdx]->find(DataInsnInfo(refInsn, DataInsnInfo::kAnyIndex)); + CG_ASSERT(itSet != predefInsn->redefine[predefInsnIdx]->end(), + "CG internal error. predefInsn should find ref_insn."); + + if (itSet != predefInsn->redefine[predefInsnIdx]->end()) { + predefInsn->redefine[predefInsnIdx]->erase(itSet); + } + } + + // Remove all predefine of ref_insn. + refInsn->predefine[refDuIdx]->clear(); + } else { + // ref_insn do not have predefine. + refInsn->predefine[refDuIdx] = mp->New>(rdalloc.Adapter()); + } + + // Call insn do not have predefine. + if (refInsn->IsCall()) { + CG_ASSERT(false, "CG internal error, ref_insn should not be a call insn here."); + } + + // Build predefine frome ref_insn to new_insn. + refInsn->predefine[refDuIdx]->insert(DataInsnInfo(newInsn, newIndex, newProp)); + + // Build redefine from new_insn to ref_insn. + if (!newInsn->redefine[newDuIdx]) { + newInsn->redefine[newDuIdx] = mp->New>(rdalloc.Adapter()); + } + newInsn->redefine[newDuIdx]->insert(DataInsnInfo(refInsn, refIndex, refProp)); + } +} + +/* Uses: Replace one of the insn operand, with maintaining data flow info. + Params: 1) insn: The replace insn. + 2) index: The index of the src operand that will replaced. + 3) prop: Indicate the kind of the replaced operand. (NORMAL / BASEREG / INDEXREG) + No need to replace CALLPARAM since they are physical registers. + 4) new_opnd: The new src operand of the insn. + 4) ref_insn: The reference instruction with the same new_opnd. + nullptr if the new src operand without defs. + 5) ref_index: The operand index of the ref_insn that with the same data flow info. + 6) ref_prop: Indicate the kind of the destination operand. (NORMAL / SECONDDEF / BASEREG / INDEXREG / + CALLPARAM) + */ +void Riscv64ReachingDefinition::ReplaceInsnSrcOperand(Insn *insn, short index, unsigned short prop, Operand *newOpnd, + Insn *refInsn, short refIndex, unsigned short refProp) { + MapleSet::iterator itSet2; + + CG_ASSERT(insn, "CG internal error, insn should not be nullptr."); + + int udIdx = index + (prop & DataInsnInfo::kIndexQuickcalc); + int refUdIdx = refIndex + (refProp & DataInsnInfo::kIndexQuickcalc) + ((refProp & DataInsnInfo::kCallParam) ? 1 : 0); + + if (insn->defs[udIdx]) { + // Remove old def->use. + for (auto udInsnInfo : *(insn->defs[udIdx])) { + Insn *defInsn = udInsnInfo.GetInsn(); + int duIdx = udInsnInfo.GetDUIndex(); + + CG_ASSERT(defInsn->uses[duIdx], "CG internal error, defInsn should have uses."); + + itSet2 = defInsn->uses[duIdx]->find(DataInsnInfo(insn, index, prop & DataInsnInfo::kCallParam)); + CG_ASSERT(itSet2 != defInsn->uses[duIdx]->end(), "CG internal error, defInsn should have insn use."); + if (itSet2 != defInsn->uses[duIdx]->end()) { + defInsn->uses[duIdx]->erase(itSet2); + if (defInsn->uses[duIdx]->empty()) { + defInsn->uses[duIdx] = nullptr; + } + } + } + + // Remove all use->def. + insn->defs[udIdx]->clear(); + } + + if (refInsn != nullptr && refInsn->defs[refUdIdx] != nullptr) { + if (insn->defs[udIdx] == nullptr) { + insn->defs[udIdx] = mp->New>(rdalloc.Adapter()); + } + + for (auto udInsnInfo : *(refInsn->defs[refUdIdx])) { + Insn *defInsn = udInsnInfo.GetInsn(); + int duIdx = udInsnInfo.GetDUIndex(); + + CG_ASSERT(defInsn->uses[duIdx], "CG internal error, defInsn should have uses."); + + itSet2 = defInsn->uses[duIdx]->find(DataInsnInfo(refInsn, refIndex, refProp & DataInsnInfo::kCallParam)); + CG_ASSERT(itSet2 != defInsn->uses[duIdx]->end(), "CG internal error, defInsn should have insn use."); + if (itSet2 != defInsn->uses[duIdx]->end()) { + // Build def->use from defInsn to insn. + unsigned short dataProp = itSet2->GetProperty() & DataInsnInfo::kDataProp; + defInsn->uses[duIdx]->insert(DataInsnInfo(insn, index, prop | dataProp)); + + // Build use->def from insn to defInsn. + insn->defs[udIdx]->insert(udInsnInfo); + } + } + } + + if (insn->defs[udIdx] && insn->defs[udIdx]->empty()) { + insn->defs[udIdx] = nullptr; + } + + switch (prop & DataInsnInfo::kAnyIndex) { + case DataInsnInfo::kNormal: + insn->opnds[index] = newOpnd; + break; + case DataInsnInfo::kSecondMemAddr: + CG_ASSERT(false, "CG internal error, Could not replace the second memory address."); + break; + case DataInsnInfo::kBaseReg: { + CG_ASSERT(newOpnd->IsRegister(), "CG Internal error, new_opnd should be a register operand."); + CG_ASSERT(insn->opnds[index]->IsMemoryAccessOperand(), + "CG Internal error, insn->opnds[index] should be a memory operand."); + + MemOperand *memOpnd = + static_cast(static_cast(insn->opnds[index])->Clone(cgfunc->memPool)); + insn->SetOperand(index, memOpnd); + memOpnd->SetBaseRegister(static_cast(newOpnd)); + break; + } + case DataInsnInfo::kIndexReg: { + CG_ASSERT(newOpnd->IsRegister(), "CG Internal error, new_opnd should be a register operand."); + CG_ASSERT(insn->opnds[index]->IsMemoryAccessOperand(), + "CG Internal error, insn->opnds[index] should be a memory operand."); + + MemOperand *memOpnd = + static_cast(static_cast(insn->opnds[index])->Clone(cgfunc->memPool)); + CG_ASSERT(memOpnd != nullptr, "memOpnd is null in Riscv64CGFunc::ReplaceInsnSrcOperand"); + insn->SetOperand(index, memOpnd); + memOpnd->SetIndexRegister(static_cast(newOpnd)); + break; + } + case DataInsnInfo::kCallParam: + CG_ASSERT(false, "CG internal error, we don't need to replace call params."); + break; + default: + CG_ASSERT(false, "CG invalid property."); + break; + } + + if (insn->defs[udIdx]->empty()) { + insn->defs[udIdx] = nullptr; + } +} + +/* Uses: Replace one of the insn operand, with maintaining data flow info. + Params: 1) insn: The replace insn. + 2) index: The index of the dest operand that will replaced. + 3) prop: Indicate the kind of the replaced operand. (NORMAL / BASEREG) + No need to replace CALLPARAM / INDEXREG since they won't be dest operands. + 4) new_opnd: The new src operand of the insn. + 4) ref_insn: The reference instruction with the same new_opnd. + nullptr if the new dest operand without predefine/redefine/uses. + 5) ref_index: The operand index of the ref_insn that with the same data flow info. + 6) ref_prop: Indicate the kind of the destination operand. (NORMAL / SECONDMEMADDR / BASEREG) + 7) isRefInsnBeforeInsn: true if ref_insn is before insn. otherwise false. + */ +void Riscv64ReachingDefinition::ReplaceInsnDestOperand(Insn *insn, short index, unsigned short prop, Operand *newOpnd, + Insn *refInsn, short refIndex, unsigned short refProp, + bool isRefInsnBeforeInsn) { + MapleSet::iterator itSet; + MapleSet::iterator itSet2; + + CG_ASSERT(insn, "CG internal error, insn should not be nullptr."); + + int duIdx = index + (prop & DataInsnInfo::kIndexQuickcalc); + + // For the definition operand of insn, rebuild links between it's uses and it's predefine operands. + if (insn->uses[duIdx] != nullptr) { + // If insn has predefine insn, then build duud between insn->predefine and insn->uses. + if (insn->predefine[duIdx] != nullptr) { + for (auto predefInsnInfo : *(insn->predefine[duIdx])) { + Insn *predefInsn = predefInsnInfo.GetInsn(); + int predefIdx = predefInsnInfo.GetDUIndex(); + + CG_ASSERT(predefInsn->redefine[predefIdx], "CG internal error."); + + for (auto useInsnInfo : *(insn->uses[duIdx])) { + Insn *useInsn = useInsnInfo.GetInsn(); + int useInsnIdx = useInsnInfo.GetUDIndex(); + + // Add def->use between predefInsn and useInsn. + if (predefInsn->uses[predefIdx] == nullptr) { + predefInsn->uses[predefIdx] = mp->New>(rdalloc.Adapter()); + } + + predefInsn->uses[predefIdx]->insert(useInsnInfo); + + // Add use-def between useInsn and predefInsn + CG_ASSERT(useInsn->defs[useInsnIdx], "CG internal error."); + useInsn->defs[useInsnIdx]->insert(predefInsnInfo); + } + } + } + + // Remove use->define between useInsn and insn. + for (auto useInsnInfo : *(insn->uses[duIdx])) { + Insn *useInsn = useInsnInfo.GetInsn(); + int useInsnIdx = useInsnInfo.GetUDIndex(); + + CG_ASSERT(useInsn->defs[useInsnIdx], "CG internal error."); + useInsn->defs[useInsnIdx]->erase(DataInsnInfo(insn, 0)); + } + + // Remove def->use from insn to it's uses. + insn->uses[duIdx]->clear(); + insn->uses[duIdx] = nullptr; + } + + // Rebuild redefine. + if (insn->predefine[duIdx] != nullptr) { + for (auto predefInsnInfo : *(insn->predefine[duIdx])) { + Insn *predefInsn = predefInsnInfo.GetInsn(); + int idx = predefInsnInfo.GetDUIndex(); + + CG_ASSERT(predefInsn->redefine[idx], "CG internal error."); + + predefInsn->redefine[idx]->erase(DataInsnInfo(insn, 0)); + + if (insn->redefine[duIdx]) { + for (auto redefInsnInfo : *(insn->redefine[duIdx])) { + predefInsn->redefine[idx]->insert(redefInsnInfo); + Insn *redefInsn = redefInsnInfo.GetInsn(); + + // Call insn do not have predefine. + if (!redefInsn->IsCall()) { + int redefIdx = redefInsnInfo.GetDUIndex(); + + CG_ASSERT(redefInsn->predefine[redefIdx], "CG internal error."); + + redefInsn->predefine[redefIdx]->insert(predefInsnInfo); + } + } + } + } + } + + // Remove predefine from redefInsn to insn. + if (insn->redefine[duIdx]) { + for (auto redefInsnInfo : *(insn->redefine[duIdx])) { + Insn *redefInsn = redefInsnInfo.GetInsn(); + + // Call insn do not have predefine. + if (!redefInsn->IsCall()) { + int redefIdx = redefInsnInfo.GetDUIndex(); + + CG_ASSERT(redefInsn->predefine[redefIdx], "CG internal error."); + + redefInsn->predefine[redefIdx]->erase(DataInsnInfo(insn, 0)); + } + } + } + + // Insert destination operand data flow info. + InsertDUUDForDestOperand(insn, index, prop, refInsn, refIndex, refProp, isRefInsnBeforeInsn); + + // Replace operand. + switch (prop & DataInsnInfo::kAnyIndex) { + case DataInsnInfo::kNormal: + insn->opnds[index] = newOpnd; + break; + case DataInsnInfo::kSecondMemAddr: + CG_ASSERT(false, "CG internal error, Could not replace the second memory address."); + break; + case DataInsnInfo::kBaseReg: { + CG_ASSERT(newOpnd->IsRegister(), "CG Internal error, new_opnd should be a register operand."); + CG_ASSERT(insn->opnds[index]->IsMemoryAccessOperand(), + "CG Internal error, insn->opnds[index] should be a memory operand."); + + MemOperand *memOpnd = + static_cast(static_cast(insn->opnds[index])->Clone(cgfunc->memPool)); + CG_ASSERT(memOpnd != nullptr, "memOpnd is null in Riscv64CGFunc::ReplaceInsnDestOperand"); + insn->SetOperand(index, memOpnd); + if (prop & DataInsnInfo::kBaseReg) { + memOpnd->SetBaseRegister(static_cast(newOpnd)); + } else { + memOpnd->SetIndexRegister(static_cast(newOpnd)); + } + + break; + } + case DataInsnInfo::kIndexReg: + CG_ASSERT(false, "CG internal error, index register of memory operand should not be a dest operand."); + break; + case DataInsnInfo::kCallParam: + CG_ASSERT(false, "CG internal error, we don't need to replace call params."); + break; + default: + CG_ASSERT(false, "CG invalid property."); + break; + } +} + +} // namespace maplebe diff --git a/mapleall/maple_be/src/cg/riscv64/riscv64_reg_alloc.cpp b/mapleall/maple_be/src/cg/riscv64/riscv64_reg_alloc.cpp new file mode 100644 index 0000000..005aa43 --- /dev/null +++ b/mapleall/maple_be/src/cg/riscv64/riscv64_reg_alloc.cpp @@ -0,0 +1,4292 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#include "riscv64_reg_alloc.h" +#include "riscv64_insn.h" +#include "riscv64_cg.h" +#include "riscv64_ra_opt.h" +#include "riscv64_operand.h" +#include "mir_lower.h" +#include "cg_assert.h" +#include "special_func.h" + +#include +#include +#include +#include "securec.h" + +namespace maplebe { + +/* + NB. As an optimization we can use X8 as a scratch (temporary) + register if the return value is not returned through memory. + */ + +Operand *Riscv64RegAllocator::AllocSrcOpnd(Operand *opnd, OpndProp *prop, Insn *insn, BB *bb) { + Riscv64OpndProp *opndprop = static_cast(prop); + if (opndprop && (opndprop->regprop_.regtype_ == kRegTyCc || opndprop->regprop_.regtype_ == kRegTyVary)) { + return opnd; + } + if (opnd->IsRegister()) { + RegOperand *regopnd = static_cast(opnd); + Riscv64CGFunc *riscv64Cgfunc = static_cast(cgfunc_); + VectorType vctType = kVecNone; + if (opndprop) + vctType = riscv64Cgfunc->PickVectorType(opndprop->regprop_.subRegType); + if (regopnd->IsOfCC() || regopnd->IsOfVary()) { + return opnd; + } + if (!regopnd->IsVirtualRegister()) { + avail_reg_set_[regopnd->GetRegisterNumber()] = false; + live_reg_.insert(regopnd->GetRegisterNumber()); + return static_cast(regopnd); + } + auto regMapIt = reg_map_.find(regopnd->GetRegisterNumber()); + if (regMapIt != reg_map_.end()) { // already allocated this register + CG_ASSERT(Riscv64isa::IsPhysicalRegister(regMapIt->second), ""); + Riscv64reg_t newRegno = regMapIt->second; + avail_reg_set_[newRegno] = false; // make sure the real register can not be allocated and live + live_reg_.insert(newRegno); + allocated_set_.insert(opnd); + return riscv64Cgfunc->GetOrCreatePhysicalRegisterOperand(newRegno, regopnd->GetSize(), + regopnd->GetRegisterType(), 0, vctType); + } + if (opndprop && opndprop->IsPhysicalRegister()) { + Riscv64reg_t newRegno = opndprop->regprop_.physical_reg_; + allocated_set_.insert(opnd); + avail_reg_set_[newRegno] = false; + live_reg_.insert(newRegno); + return riscv64Cgfunc->GetOrCreatePhysicalRegisterOperand(newRegno, regopnd->GetSize(), + regopnd->GetRegisterType(), 0, vctType); + } + if (AllocatePhysicalRegister(regopnd, opndprop)) { + allocated_set_.insert(opnd); + auto regMapIt = reg_map_.find(regopnd->GetRegisterNumber()); + CG_ASSERT(regMapIt != reg_map_.end(), " ERROR !! "); + return riscv64Cgfunc->GetOrCreatePhysicalRegisterOperand( + regMapIt->second, regopnd->GetSize(), regopnd->GetRegisterType(), + 0, vctType); + } + + regno_t regNo = DoRegisterSpill(regopnd, insn, false, bb); + CHECK_FATAL(regNo, "Cannot spill with O0 regalloc"); + return riscv64Cgfunc->GetOrCreatePhysicalRegisterOperand( + (Riscv64reg_t)regNo, regopnd->GetSize(), regopnd->GetRegisterType(), 0, vctType); + } else if (opnd->IsMemoryAccessOperand()) { + Riscv64MemOperand *memopnd = static_cast(opnd); + Operand *res = nullptr; + res = AllocSrcOpnd(memopnd->GetBaseRegister()); + //CG_ASSERT(res->IsRegister() && !static_cast(res)->IsVirtualRegister(), ""); + memopnd->SetBaseRegister(static_cast(res)); + allocated_set_.insert(opnd); + return memopnd; + } + CG_ASSERT(0, "NYI"); + return nullptr; +} + +Operand *Riscv64RegAllocator::AllocDestOpnd(Operand *opnd, Insn *insn, uint32 index, BB *bb) { + if (opnd->IsRegister()) { + RegOperand *regopnd = static_cast(opnd); + RegType regty = regopnd->GetRegisterType(); + const Riscv64MD *md = &Riscv64CG::kMd[static_cast(insn)->mop_]; + Riscv64OpndProp *opndprop = static_cast(md->operand_[index]); + if (!regopnd->IsVirtualRegister()) { + Riscv64reg_t rn = (Riscv64reg_t)regopnd->GetRegisterNumber(); + avail_reg_set_[rn] = true; + auto it = regLiveness.find(regopnd); + if (it != regLiveness.end()) { + if (it->second <= insn->id) { + ReleaseReg(opndprop->regprop_.regtype_, rn); + } + } + return opnd; + } + Riscv64CGFunc *riscv64Cgfunc = static_cast(cgfunc_); + VectorType vctType = kVecNone; + if (opndprop) + vctType = riscv64Cgfunc->PickVectorType(opndprop->regprop_.subRegType); + + if (opndprop->IsPhysicalRegister()) { // physical register + Riscv64reg_t physicalReg = opndprop->regprop_.physical_reg_; + CG_ASSERT(live_reg_.find(physicalReg) == live_reg_.end(), "physical register spill NYI"); + auto it = regLiveness.find(regopnd); + if (it != regLiveness.end()) { + if (it->second <= insn->id) { + ReleaseReg(opndprop->regprop_.regtype_, physicalReg); + } + } + return riscv64Cgfunc->GetOrCreatePhysicalRegisterOperand(physicalReg, regopnd->GetSize(), + regopnd->GetRegisterType(), 0, vctType); + } + + auto regMapIt = reg_map_.find(regopnd->GetRegisterNumber()); + if (regMapIt != reg_map_.end()) { + Riscv64reg_t reg = regMapIt->second; + if (!insn->IsCondDef()) { + auto it = regLiveness.find(regopnd); + if (it != regLiveness.end()) { + if (it->second <= insn->id) { + ReleaseReg(regty, reg); + } + } + } + } else { + // AllocatePhysicalRegister insert a mapping from vreg no to phy reg no into reg_map_ + if (AllocatePhysicalRegister(regopnd, opndprop)) { + regMapIt = reg_map_.find(regopnd->GetRegisterNumber()); + // Add opt by store it's value to the spill location if it has spilled before. + if (regopnd->IsVirtualRegister()) { + StorePseudoRegister(regopnd, regMapIt->second, insn, bb); + } + if (!insn->IsCondDef()) { + auto it = regLiveness.find(regopnd); + if (it != regLiveness.end()) { + if (it->second <= insn->id) { + ReleaseReg(regopnd->GetRegisterType(), regMapIt->second); + } + } + } + } else { + // For register spill. + regno_t regNo = DoRegisterSpill(regopnd, insn, true, bb); + return riscv64Cgfunc->GetOrCreatePhysicalRegisterOperand( + (Riscv64reg_t)regNo, regopnd->GetSize(), regopnd->GetRegisterType(), 0, vctType); + } + } + allocated_set_.insert(opnd); + return riscv64Cgfunc->GetOrCreatePhysicalRegisterOperand( + regMapIt->second, regopnd->GetSize(), regopnd->GetRegisterType(), 0, vctType); + } else { + CG_ASSERT(0, "result operand must be of type register"); + } + return nullptr; +} + +void Riscv64RegAllocator::PreAllocate() { + FOR_ALL_BB(bb, cgfunc_) { + if (bb->IsEmpty()) { + continue; + } + FOR_BB_INSNS_SAFE(insn, bb, next_insn) { + const Riscv64MD *md = &Riscv64CG::kMd[static_cast(insn)->mop_]; + if (!md->UseSpecReg()) { + continue; + } + for (int i = 0; i < Insn::kMaxOperandNum; i++) { + Operand *opnd = insn->opnds[i]; + if (!opnd) { + break; + } + Riscv64OpndProp *opndprop = static_cast(md->operand_[i]); + if (opndprop->IsPhysicalRegister()) { + Riscv64CGFunc *a64func = static_cast(cgfunc_); + RegOperand *regopnd = static_cast(opnd); + Riscv64RegOperand *phyreg = + a64func->GetOrCreatePhysicalRegisterOperand(opndprop->regprop_.physical_reg_, opnd->size_, kRegTyInt); + if (opndprop->IsRegDef()) { + Insn *newInsn = + a64func->cg->BuildInstruction(a64func->PickMovInsn(regopnd, phyreg), regopnd, phyreg); + bb->InsertInsnAfter(insn, newInsn); + } else { + Insn *newInsn = + a64func->cg->BuildInstruction(a64func->PickMovInsn(phyreg, regopnd), phyreg, regopnd); + bb->InsertInsnBefore(insn, newInsn); + } + insn->opnds[i] = phyreg; + } + } + } + } +} + +void Riscv64RegAllocator::AllocHandleCallee(Insn *insn, const Riscv64MD *md) { + Riscv64CGFunc *acgf = static_cast(cgfunc_); + Operand *opnd1 = insn->opnds[1]; + if (opnd1->IsList()) { + Riscv64ListOperand *srcopnds = static_cast(insn->opnds[1]); + Riscv64ListOperand *srcopndsNew = acgf->memPool->New(acgf->funcscope_allocator_); + for (auto regopnd : srcopnds->GetOperands()) { + CG_ASSERT(!regopnd->IsVirtualRegister(), ""); + Riscv64RegOperand *riscv64Regopnd = static_cast (regopnd); + Riscv64reg_t physicalReg = (Riscv64reg_t)regopnd->GetRegisterNumber(); + avail_reg_set_[physicalReg] = false; + live_reg_.insert(physicalReg); + srcopndsNew->PushOpnd( + acgf->GetOrCreatePhysicalRegisterOperand(physicalReg, regopnd->GetSize(), regopnd->GetRegisterType(), + 0, riscv64Regopnd->GetVectorType())); + } + insn->opnds[1] = srcopndsNew; + } + + Operand *opnd = insn->opnds[0]; + Riscv64OpndProp *opndProp0 = static_cast(md->operand_[0]); + if (opnd && opnd->IsRegister() && opndProp0->IsRegUse()) { + if (allocated_set_.find(opnd) != allocated_set_.end()) { + RegOperand *regopnd = static_cast(opnd); + Riscv64reg_t physicalReg = reg_map_[regopnd->GetRegisterNumber()]; + insn->opnds[0] = acgf->GetOrCreatePhysicalRegisterOperand( + physicalReg, regopnd->GetSize(), regopnd->GetRegisterType(), + 0, acgf->PickVectorType(opndProp0->regprop_.subRegType)); + } else { + insn->opnds[0] = AllocSrcOpnd(opnd, opndProp0); + } + } +} + +void Riscv64RegAllocator::GetPhysicalRegisterBank(RegType regty, uint8 &begin, uint8 &end) { + switch (regty) { + case kRegTyVary: + case kRegTyCc: + begin = kRinvalid; + end = kRinvalid; + break; + case kRegTyInt: + begin = R0; + end = R28; + break; + case kRegTyFloat: + begin = V0; + end = V31; + break; + default: + CG_ASSERT(false, "NYI"); + break; + } +} + +void Riscv64RegAllocator::InitAvailReg() { + errno_t eNum = memset_s(avail_reg_set_, MAXREG, 1, sizeof(avail_reg_set_)); + if (eNum) { + CHECK_FATAL(false, "memset_s failed"); + } + avail_reg_set_[RZERO] = false; + avail_reg_set_[RRA] = false; + avail_reg_set_[RSP] = false; + avail_reg_set_[RGP] = false; + avail_reg_set_[RTP] = false; + avail_reg_set_[RFP] = false; + + // when yieldpoint is enabled, + // the dedicated register is not available. + if (cgfunc_->cg->GenYieldpoint()) { + avail_reg_set_[RYP] = false; + } + + if (g->optim_level > 1) { + Riscv64CGFunc *cgfunc = static_cast(cgfunc_); + for (auto ® : cgfunc->formal_reg_list_) { + avail_reg_set_[reg] = false; + } + } +} + +bool Riscv64RegAllocator::IsSpecialReg(Riscv64reg_t reg) // these registers can not be allocated +{ + if (reg == RZERO || reg == RRA || reg == RSP || reg == RGP || reg == RTP || reg == RFP) { + return true; + } + + // when yieldpoint is enabled, the dedicated register can not be allocated. + if (cgfunc_->cg->GenYieldpoint() && reg == RYP) { + return true; + } + + Riscv64CGFunc *cgfunc = static_cast(cgfunc_); + for (MapleVector::iterator it = cgfunc->formal_reg_list_.begin(); it != cgfunc->formal_reg_list_.end(); + it++) { + if (*it == reg) { + return true; + } + } + return false; +} + +// Those registers can not be overwrite. +bool Riscv64RegAllocator::IsUntouchableReg(uint32 regno) { + if (regno == RZERO || regno == RSP || regno == RFP) { + return true; + } + + // when yieldpoint is enabled, the RYP(x19) can not be used. + if (cgfunc_->cg->GenYieldpoint() && regno == RYP) { + return true; + } + + return false; +} + +void Riscv64RegAllocator::ReleaseReg(RegOperand *regopnd, OpndProp *prop) { + ReleaseReg(regopnd->GetRegisterType(), reg_map_[regopnd->GetRegisterNumber()]); +} + +void Riscv64RegAllocator::ReleaseReg(RegType regty, Riscv64reg_t reg) { + CG_ASSERT(reg < 100, "can't release virtual register"); + live_reg_.erase(reg); + if (!IsSpecialReg((Riscv64reg_t)reg)) { + avail_reg_set_[reg] = true; + } +} + +// trying to allocate a physical register to opnd. return true if success +bool Riscv64RegAllocator::AllocatePhysicalRegister(RegOperand *opnd, OpndProp *prop) { + RegType regtype = opnd->GetRegisterType(); + uint8 regStart = 0; + uint8 regEnd = 0; + GetPhysicalRegisterBank(regtype, regStart, regEnd); + + for (uint8 reg = regStart; reg <= regEnd; reg++) { + if (!avail_reg_set_[reg]) { + continue; + } + + reg_map_[opnd->GetRegisterNumber()] = Riscv64reg_t(reg); + avail_reg_set_[reg] = false; + live_reg_.insert(reg); // this register is live now + return true; + } + return false; +} + +// If opnd is a callee saved register, save it in the prolog and restore it in the epilog +void Riscv64RegAllocator::SaveCalleeSavedReg(RegOperand *regopnd) { + regno_t regno = regopnd->GetRegisterNumber(); + Riscv64reg_t a64reg = (Riscv64reg_t)(regopnd->IsVirtualRegister() ? reg_map_[regno] : regno); + + // when yieldpoint is enabled, skip the reserved register for yieldpoint. + if (cgfunc_->cg->GenYieldpoint() && a64reg == RYP) { + return; + } + + if (Riscv64Abi::IsCalleeSavedReg(a64reg)) { + static_cast(cgfunc_)->AddtoCalleeSaved(a64reg); + } +} + +static void InsertPRegStoreInstruction(Insn *insn, BB *bb) { + switch (bb->GetKind()) { + case BB::kBBIf: { + Insn *cmpInsn = bb->lastinsn->prev; + // CG_ASSERT( ); + bb->InsertInsnBefore(cmpInsn, insn); + break; + } + case BB::kBBThrow: + case BB::kBBCall: { + const Riscv64MD *md = &Riscv64CG::kMd[static_cast(bb->lastinsn)->mop_]; + CG_ASSERT(md->IsCall(), ""); + Insn *endInsn = bb->firstinsn->prev; + Insn *insertAfterInsn = bb->lastinsn->prev; + CG_ASSERT(insertAfterInsn, "This block must have regassign; lastinsn->prev must not be nullptr"); + while (insertAfterInsn != endInsn) { + md = &Riscv64CG::kMd[static_cast(insertAfterInsn)->mop_]; + if (!md->IsMove() || static_cast(insertAfterInsn->GetOperand(0))->IsVirtualRegister() == true) { + break; + } + insertAfterInsn = insertAfterInsn->prev; + } + CG_ASSERT(insertAfterInsn != endInsn, "This block must have regassign; insert_after_insn must not be end_insn"); + bb->InsertInsnAfter(insertAfterInsn, insn); + break; + } + case BB::kBBGoto: + bb->InsertInsnBefore(bb->lastinsn, insn); + break; + default: + bb->AppendInsn(insn); + break; + } +} + +bool DefaultO0RegAllocator::AllocateRegisters() { + InitAvailReg(); + PreAllocate(); + cgfunc_->SetIsAfterRegAlloc(); + + Riscv64CGFunc *a64cgfunc = static_cast(cgfunc_); + // we store both FP/LR if using FP or if not using FP, but func has a call + if (a64cgfunc->ShouldSaveFPLR()) { + // Using FP, record it for saving + a64cgfunc->AddtoCalleeSaved(RFP); + a64cgfunc->AddtoCalleeSaved(RRA); + a64cgfunc->NoteFPLRAddedToCalleeSavedList(); + } + + FOR_ALL_BB_REV(bb, a64cgfunc) { + if (bb->IsEmpty()) { + continue; + } + regLiveness.clear(); + + bool isIntrinsicBb = bb->GetKind() == BB::kBBIntrinsic; + + uint32 id = 1; + FOR_BB_INSNS_REV(insn, bb) { + if (!insn->IsMachineInstruction()) continue; + insn->id = id; + id++; + const Riscv64MD *md = &Riscv64CG::kMd[static_cast(insn)->mop_]; + for (int i = 0; i < Insn::kMaxOperandNum; i++) { + Operand *opnd = insn->opnds[i]; + Riscv64OpndProp *riscv64Opndprop = static_cast(md->operand_[i]); + if (!opnd || !riscv64Opndprop->IsRegDef()) { + continue; + } + if (opnd->IsRegister()) { + regLiveness[opnd] = insn->id; + } + } + } + FOR_BB_INSNS_REV(insn, bb) { + if (!insn->IsMachineInstruction()) { + continue; + } + + const Riscv64MD *md = &Riscv64CG::kMd[static_cast(insn)->mop_]; + + if (md->IsCall() && insn->mop_ != MOP_clinit) { + AllocHandleCallee(insn, md); + continue; + } + + for (int i = 0; i < Insn::kMaxOperandNum; i++) { // the dest registers + Operand *opnd = insn->opnds[i]; + Riscv64OpndProp *riscv64Opndprop = static_cast(md->operand_[i]); + if (!opnd || !riscv64Opndprop->IsRegDef()) { + continue; + } + if (allocated_set_.find(opnd) != allocated_set_.end()) { + // free the live range of this register + RegOperand *regopnd = static_cast(opnd); + CG_ASSERT(regopnd, "only register can be a result"); + SaveCalleeSavedReg(regopnd); + if (isIntrinsicBb && insn->IsAtomicStore()) { + // remember the physical machine register assigned + CG_ASSERT(atomic_store_result_reg == kRinvalid, ""); + regno_t regno = regopnd->GetRegisterNumber(); + Riscv64reg_t a64reg = (Riscv64reg_t)(regopnd->IsVirtualRegister() ? reg_map_[regno] : regno); + atomic_store_result_reg = a64reg; + } else if (!insn->IsCondDef()) { + auto it = regLiveness.find(regopnd); + if (it != regLiveness.end()) { + if (it->second <= insn->id) { + ReleaseReg(regopnd, md->operand_[i]); + } + } + } + + insn->opnds[i] = a64cgfunc->GetOrCreatePhysicalRegisterOperand( + reg_map_[regopnd->GetRegisterNumber()], regopnd->GetSize(), regopnd->GetRegisterType(), + 0, a64cgfunc->PickVectorType(riscv64Opndprop->regprop_.subRegType)); + continue; // already allocated + } + + if (opnd->IsRegister()) { + insn->opnds[i] = AllocDestOpnd(opnd, insn, i); + SaveCalleeSavedReg(static_cast(opnd)); + } + } + + for (int i = 0; i < Insn::kMaxOperandNum; i++) { // the src registers + Operand *opnd = insn->opnds[i]; + if (!opnd || + !(static_cast(md->operand_[i])->IsRegUse() || opnd->op_kind_ == Operand::Opd_Mem)) { + continue; + } + if (allocated_set_.find(opnd) != allocated_set_.end() && opnd->IsRegister()) { + RegOperand *regopnd = static_cast(opnd); + Riscv64reg_t reg = reg_map_[regopnd->GetRegisterNumber()]; + avail_reg_set_[reg] = false; + live_reg_.insert(reg); // this register is live now + CG_ASSERT( regopnd->GetSize() != 128 || !regopnd->IsVirtualRegister(), "nyi"); + insn->opnds[i] = + a64cgfunc->GetOrCreatePhysicalRegisterOperand(reg, regopnd->GetSize(), regopnd->GetRegisterType()); + } else { + insn->opnds[i] = AllocSrcOpnd(opnd, md->operand_[i]); + } + } + } + + // hack. a better way to handle intrinsics? + if (atomic_store_result_reg != kRinvalid) { + ReleaseReg(kRegTyInt, atomic_store_result_reg); + atomic_store_result_reg = kRinvalid; + } + } + return true; +} + +void O1RegAllocator::CollectPRegUsesInExpr(BaseNode *expr, BB *bb) { + Opcode opr = expr->op; + switch (opr) { + case OP_regread: + if (!cgfunc_->IsSpecialPseudoRegister(static_cast(expr)->regIdx)) { + bb->AddPseudoRegisterToUseList(static_cast(expr)->regIdx); + } + break; + /* binary expressions */ + case OP_add: + case OP_ashr: + case OP_lshr: + case OP_shl: + case OP_mul: + case OP_div: + case OP_rem: + case OP_sub: + case OP_band: + case OP_bior: + case OP_bxor: + case OP_depositbits: + case OP_land: + case OP_lior: + case OP_min: + case OP_max: + case OP_le: + case OP_ge: + case OP_gt: + case OP_lt: + case OP_ne: + case OP_eq: + case OP_cmp: + case OP_cmpl: + case OP_cmpg: + CollectPRegUsesInExpr(expr->Opnd(0), bb); + CollectPRegUsesInExpr(expr->Opnd(1), bb); + break; + /* unary expressions */ + case OP_abs: + case OP_bnot: + case OP_sext: + case OP_zext: + case OP_extractbits: + case OP_lnot: + case OP_neg: + case OP_recip: + case OP_sqrt: + case OP_ceil: + case OP_floor: + case OP_retype: + case OP_cvt: + case OP_round: + case OP_trunc: + case OP_malloc: + case OP_gcmallocjarray: + case OP_gcpermallocjarray: + case OP_iread: + CollectPRegUsesInExpr(expr->Opnd(0), bb); + break; + /* tertiary expressions */ + case OP_select: + CollectPRegUsesInExpr(expr->Opnd(0), bb); + CollectPRegUsesInExpr(expr->Opnd(1), bb); + CollectPRegUsesInExpr(expr->Opnd(2), bb); + break; + default: + /* + case OP_dread: + case OP_constval: + case OP_conststr: + case OP_conststr16: + case OP_addrof: + case OP_gcmalloc: + case OP_gcpermalloc: + */ + break; + } +} + +void O1RegAllocator::CollectPRegUses(Opcode c, StmtNode *s, BB *bb) { + switch (c) { + /* unary statements */ + case OP_brfalse: + case OP_brtrue: + case OP_rangegoto: { + UnaryStmtNode *usn = static_cast(s); + CollectPRegUsesInExpr(usn->Opnd(0), bb); + break; + } + /* n-ary statements */ + case OP_return: + case OP_call: + case OP_icall: + case OP_intrinsiccall: + case OP_intrinsiccallassigned: + case OP_intrinsiccallwithtypeassigned: { + NaryStmtNode *nsn = static_cast(s); + for (auto o : nsn->nOpnd) { + CollectPRegUsesInExpr(o, bb); + } + break; + } + /* with rhs */ + case OP_dassign: { + DassignNode *dan = static_cast(s); + CollectPRegUsesInExpr(dan->GetRhs(), bb); + break; + } + case OP_regassign: + CG_ASSERT(0, "Should have already handled?"); + break; + /* with addrexpr and rhs */ + case OP_iassign: { + IassignNode *ian = static_cast(s); + CollectPRegUsesInExpr(ian->addrExpr, bb); + CollectPRegUsesInExpr(ian->rhs, bb); + break; + } + case OP_eval: + CG_ASSERT(0, "Not supported"); + break; + case OP_label: + case OP_goto: + case OP_comment: + case OP_javacatch: + case OP_javatry: + case OP_cppcatch: + case OP_cpptry: + case OP_catch: + case OP_try: + case OP_endtry: + break; + case OP_syncenter: + case OP_syncexit: + CG_ASSERT(0, "should have been lowered to a call or inlined"); + break; + default: + CG_ASSERT(0, "NYI"); + break; + } +} + +void O1RegAllocator::CollectPRegDefsUses(BB *bb) { + if (bb->laststmt && !bb->firststmt) { + LogInfo::MapleLogger() << "BB " << hex << bb << dec << " "; + bb->laststmt->Dump(&(cgfunc_->mirModule), 0); + } + + StmtNode *stmt = bb->laststmt; + StmtNode *endStmt = bb->firststmt->GetPrev(); + CHECK_FATAL(stmt != nullptr, "null ptr check"); + for (; stmt != endStmt; stmt = stmt->GetPrev()) { + Opcode opcode = stmt->op; + switch (opcode) { + case OP_regassign: { + PregIdx pregidx = static_cast(stmt)->regIdx; + if (pregidx >= + 0) { // Special registers should not be stored since they don't have corresponding virtual register. + bb->AddPseudoRegisterWritten(pregidx); + } + bb->RemovePseudoRegisterFromUseList(pregidx); + CollectPRegUsesInExpr(static_cast(stmt)->uOpnd, bb); + break; + } + + default: + CollectPRegUses(opcode, stmt, bb); + break; + } + } +} + +regno_t O1RegAllocator::GetVirtualRegFromPhysicalReg(Riscv64reg_t regT) { + for (auto it : reg_map_) { + if (it.second == regT) { + return (it.first); + } + } + CG_ASSERT(0, "There must be a map betwwen virtual register and physical register."); + return INVALID_REGNO; +} + +Operand *O1RegAllocator::GetOperandFromAllocatedSet(regno_t regNo) { + for (auto it : allocated_set_) { + if (static_cast(it)->GetRegisterNumber() == regNo) { + return (it); + } + } + + CG_ASSERT(0, "There must be an operand with reg_no in allocated_set_."); + return nullptr; +} + +void O1RegAllocator::StorePseudoRegister(RegOperand *regopnd, Riscv64reg_t regNo, Insn *insn, BB *bb) { + Riscv64CGFunc *a64cgfunc = static_cast(cgfunc_); + CG *cg = a64cgfunc->cg; + if (!a64cgfunc->IsVRegNoForPseudoRegister(regopnd->GetRegisterNumber())) { + return; + } + PregIdx pregIdx = a64cgfunc->GetPseudoRegIdxFromVirtualRegNo(regopnd->GetRegisterNumber()); + MemOperand *memOperand = a64cgfunc->GetPseudoRegisterSpillMemoryOperand(pregIdx); + CG_ASSERT( regopnd->GetSize() != 128 || !regopnd->IsVirtualRegister(), "nyi"); + RegOperand *physicalRegOperand = + a64cgfunc->GetOrCreatePhysicalRegisterOperand(regNo, regopnd->GetSize(), regopnd->GetRegisterType()); + PrimType stype = a64cgfunc->GetTypeFromPseudoRegIdx(pregIdx); + CHECK_FATAL(memOperand != nullptr, "memOperand is null in O1RegAllocator::StorePseudoRegister"); + Insn *stInsn = cg->BuildInstruction(a64cgfunc->PickStInsn(memOperand->GetSize(), stype), + physicalRegOperand, memOperand); + bb->InsertInsnAfter(insn, stInsn); +} + +bool O1RegAllocator::AllocateRegisters() { + InitAvailReg(); + PreAllocate(); + cgfunc_->SetIsAfterRegAlloc(); + + Riscv64CGFunc *a64cgfunc = static_cast(cgfunc_); + // we store both FP/LR if using FP or if not using FP, but func has a call + if (a64cgfunc->ShouldSaveFPLR()) { + // Using FP, record it for saving + a64cgfunc->AddtoCalleeSaved(RFP); + a64cgfunc->AddtoCalleeSaved(RRA); + a64cgfunc->NoteFPLRAddedToCalleeSavedList(); + } + + CG_ASSERT(g->optim_level == 1, ""); + + FOR_ALL_BB_REV(bb, a64cgfunc) { + if (bb->IsEmpty()) { + continue; + } + + bool isIntrinsicBb = bb->GetKind() == BB::kBBIntrinsic; + + CollectPRegDefsUses(bb); + + if (bb->GetKind() != BB::kBBReturn) { + CG *cg = a64cgfunc->cg; + RegOperand *src = nullptr; + for (PregIdx pr : bb->written_pseudo_regs) { + if (a64cgfunc->IsSpecialPseudoRegister(pr)) { + src = a64cgfunc->GetOrCreateSpecialRegisterOperand(-pr); + } else { + src = a64cgfunc->CreateVirtualRegisterOperand(a64cgfunc->GetVirtualRegNoFromPseudoRegIdx(pr)); + } + MemOperand *dest = a64cgfunc->GetPseudoRegisterSpillMemoryOperand(pr); + PrimType stype = a64cgfunc->GetTypeFromPseudoRegIdx(pr); + Insn *stInsn = cg->BuildInstruction(a64cgfunc->PickStInsn(src->GetSize(), stype), src, dest); + InsertPRegStoreInstruction(stInsn, bb); + } + } + + FOR_BB_INSNS_REV(insn, bb) { + if (!insn->IsMachineInstruction()) { + continue; + } + + const Riscv64MD *md = &Riscv64CG::kMd[static_cast(insn)->mop_]; + + if (md->IsCall() && insn->mop_ != MOP_clinit) { + AllocHandleCallee(insn, md); + continue; + } + + InitValidSpillRegIndex(insn); + + for (int i = 0; i < Insn::kMaxOperandNum; i++) { // the dest registers + Operand *opnd = insn->opnds[i]; + + if (!opnd || !static_cast(md->operand_[i])->IsRegDef()) { + continue; + } + + if (allocated_set_.find(opnd) != allocated_set_.end()) { + // free the live range of this register + RegOperand *regopnd = static_cast(opnd); + // CG_ASSERT( regopnd, "only register can be a result" ); + SaveCalleeSavedReg(regopnd); + if (isIntrinsicBb && insn->IsAtomicStore()) { + // remember the physical machine register assigned + CG_ASSERT(atomic_store_result_reg == kRinvalid, ""); + regno_t regno = regopnd->GetRegisterNumber(); + Riscv64reg_t a64reg = (Riscv64reg_t)(regopnd->IsVirtualRegister() ? reg_map_[regno] : regno); + atomic_store_result_reg = a64reg; + } else if (!insn->IsCondDef()) { + ReleaseReg(regopnd, md->operand_[i]); + allocated_set_.erase(opnd); + } + CG_ASSERT( regopnd->GetSize() != 128 || !regopnd->IsVirtualRegister(), "nyi"); + insn->opnds[i] = a64cgfunc->GetOrCreatePhysicalRegisterOperand( + reg_map_[regopnd->GetRegisterNumber()], regopnd->GetSize(), regopnd->GetRegisterType()); + continue; // already allocated + } + + if (opnd->IsRegister()) { + CG_ASSERT(!(isIntrinsicBb && insn->IsAtomicStore()), ""); + insn->opnds[i] = AllocDestOpnd(opnd, insn, i, bb); + SaveCalleeSavedReg(static_cast(opnd)); + } + } + + for (int i = 0; i < Insn::kMaxOperandNum; i++) { // the src registers + Operand *opnd = insn->opnds[i]; + if (!opnd || + !(static_cast(md->operand_[i])->IsRegUse() || opnd->op_kind_ == Operand::Opd_Mem)) { + continue; + } + if (allocated_set_.find(opnd) != allocated_set_.end() && opnd->IsRegister()) { + RegOperand *regopnd = static_cast(opnd); + Riscv64reg_t reg = reg_map_[regopnd->GetRegisterNumber()]; + avail_reg_set_[reg] = false; + live_reg_.insert(reg); // this register is live now + CG_ASSERT( regopnd->GetSize() != 128 || !regopnd->IsVirtualRegister(), "nyi"); + insn->opnds[i] = a64cgfunc->GetOrCreatePhysicalRegisterOperand( + reg_map_[regopnd->GetRegisterNumber()], regopnd->GetSize(), regopnd->GetRegisterType()); + } else { + insn->opnds[i] = AllocSrcOpnd(opnd, md->operand_[i], insn, bb); + } + } + } + + // hack. a better way to handle intrinsics? + if (atomic_store_result_reg != kRinvalid) { + ReleaseReg(kRegTyInt, atomic_store_result_reg); + atomic_store_result_reg = kRinvalid; + } + + { + // collect still assigned physical registers... + CG *cg = a64cgfunc->cg; + for (PregIdx pr : bb->GetUsePRegs()) { + regno_t vregNo = a64cgfunc->GetVirtualRegNoFromPseudoRegIdx(pr); + auto regMapIt = reg_map_.find(vregNo); + CG_ASSERT(regMapIt != reg_map_.end(), "The preg is not assigned physical register?"); + CG_ASSERT(Riscv64isa::IsPhysicalRegister(regMapIt->second), ""); + Riscv64reg_t assignedMachReg = regMapIt->second; + + MemOperand *src = a64cgfunc->GetPseudoRegisterSpillMemoryOperand(pr); + CG_ASSERT(src != nullptr, "src is null in O1RegAllocator::AllocateRegisters"); + PrimType stype = a64cgfunc->GetTypeFromPseudoRegIdx(pr); + RegType rtyp = IsPrimitiveInteger(stype) ? kRegTyInt : kRegTyFloat; + int rbitlen = (src->GetSize() < 32) ? 32 : src->GetSize(); + CG_ASSERT(rbitlen != 128, "NYI"); + Riscv64RegOperand *dest = a64cgfunc->GetOrCreatePhysicalRegisterOperand(assignedMachReg, rbitlen, rtyp); + // if the first statement is dassign from regread of retval0 + Insn *ldInsn = cg->BuildInstruction(a64cgfunc->PickLdInsn(src->GetSize(), stype), dest, src); + if (bb->firstinsn->IsSaveRetValToLocal()) { + CG_ASSERT(!bb->firstinsn->next->IsSaveRetValToLocal(), ""); + bb->InsertInsnAfter(bb->firstinsn, ldInsn); + } else { + bb->InsertInsnBegin(ldInsn); + } + + reg_map_.erase(vregNo); + } + } + } + CG_ASSERT(atomic_store_result_reg == kRinvalid, ""); + + return true; +} + +/* + * Check whether the reserve spill registers are valid. + * If an operand of a instruction maps a physical register, and the physical register is a reserve spill register, + * then set the corresponding bit of m_validIndex as 0. + */ +void O1RegAllocator::InitValidSpillRegIndex(Insn *insn) { + m_validIndex = 0xFFFF; + + ClearRegIndex(); + + for (int i = 0; i < Insn::kMaxOperandNum; i++) { + Operand *opnd = insn->opnds[i]; + + if (!opnd || !opnd->IsRegister()) { + continue; + } + + if (allocated_set_.find(opnd) != allocated_set_.end()) { + RegOperand *regopnd = static_cast(opnd); + CHECK_FATAL(regopnd != nullptr, "null ptr check"); + regno_t regno = regopnd->GetRegisterNumber(); + Riscv64reg_t a64reg = (Riscv64reg_t)(regopnd->IsVirtualRegister() ? reg_map_[regno] : regno); + if (a64reg <= O1_INT_REG_FOR_SPILL && (O1_INT_REG_FOR_SPILL - a64reg) < Insn::kMaxOperandNum) { + m_validIndex &= (~(0x1 << (O1_INT_REG_FOR_SPILL - a64reg))); + } + } + } +} + +regno_t O1RegAllocator::DoRegisterSpill(RegOperand *regopnd, Insn *insn, bool isDstRegister, BB *bb) { + RegOperand *regOperand = nullptr; + regno_t regNo; + PregIdx pregIdx, oldPregIdx; + Insn *ldInsn = nullptr; + CG_ASSERT(insn != nullptr, "insn should not be nullptr for function DoSrcRegisterSpill."); + Riscv64CGFunc *a64cgfunc = static_cast(cgfunc_); + CG *cg = a64cgfunc->cg; + + pregIdx = a64cgfunc->GetPseudoRegIdxFromVirtualRegNo(regopnd->GetRegisterNumber()); + PrimType stype = a64cgfunc->GetTypeFromPseudoRegIdx(pregIdx); + + if (IsPrimitiveInteger(stype)) { + regNo = O1_INT_REG_FOR_SPILL - GetNextIntRegIndex(); + } else { + regNo = O1_FLT_REG_FOR_SPILL - GetNextFloatRegIndex(); + } + CG_ASSERT( regopnd->GetSize() != 128 || !regopnd->IsVirtualRegister(), "nyi"); + + regOperand = + a64cgfunc->GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)regNo, regopnd->GetSize(), regopnd->GetRegisterType()); + regno_t oldRegNo = GetVirtualRegFromPhysicalReg((Riscv64reg_t)regNo); + + oldPregIdx = a64cgfunc->GetPseudoRegIdxFromVirtualRegNo(oldRegNo); + // GetOrCreateRegisterSpillMemoryOperand(..). + MemOperand *oldMemOperand = a64cgfunc->GetOrCreatSpillMem(oldPregIdx); + + PrimType oldStype = a64cgfunc->GetTypeFromPseudoRegIdx(oldPregIdx); + ldInsn = cg->BuildInstruction(a64cgfunc->PickLdInsn(oldMemOperand->GetSize(), oldStype), regOperand, + oldMemOperand); + bb->InsertInsnAfter(insn, ldInsn); + reg_map_.erase(oldRegNo); + allocated_set_.erase(GetOperandFromAllocatedSet(oldRegNo)); + + if (isDstRegister) { + // Store value after current instruction. + MemOperand *memOperand = a64cgfunc->GetOrCreatSpillMem(pregIdx); + Insn *stInsn = + cg->BuildInstruction(a64cgfunc->PickStInsn(regopnd->GetSize(), stype), regOperand, memOperand); + bb->InsertInsnAfter(insn, stInsn); + } else { + allocated_set_.insert(regopnd); + reg_map_[regopnd->GetRegisterNumber()] = Riscv64reg_t(regNo); + } + + return regNo; +} + +//================== +//= Linear Scan RA +//================== + +#undef LSRA_DEBUG + +#ifdef LSRA_DEBUG +#define LSRA_DUMP CGDEBUGFUNC(cgfunc_) +#else +#define LSRA_DUMP 0 +#endif + +#define SPILLED 1 + +#define IN_SPILL_RANGE \ + (cgfunc_->GetName().find(CGOptions::dumpFunc.c_str()) != string::npos && ++debug_spill_cnt && \ + (CGOptions::spillRanges[0] < debug_spill_cnt) && (debug_spill_cnt < CGOptions::spillRanges[1])) + +#undef LSRA_GRAPH + +// This LSRA implementation is an interpretation of the [Poletto97] paper. +// BFS BB ordering is used to order the instructions. The live intervals are vased on +// this instruction order. All vreg defines should come before an use, else a warning is +// given. +// Live interval is traversed in order from lower instruction order to higher order. +// When encountering a live interval for the first time, it is assumed to be live and placed +// inside the 'active' structure until the vreg's last access. During the time a vreg +// is in 'active', the vreg occupies a physical register allocation and no other vreg can +// be allocated the same physical register. + +void LSRALinearScanRegAllocator::PrintRegSet(MapleSet set, string str) { + LogInfo::MapleLogger() << str; + MapleSet::iterator it; + for (it = set.begin(); it != set.end(); it++) { + LogInfo::MapleLogger() << " " << *it; + } + LogInfo::MapleLogger() << "\n"; +} + +// This is a support routine to compute the overlapping live intervals in graph form. +// The output file can be viewed by gnuplot. +// Despite the function name of LiveRanges, it is using live intervals. +void LSRALinearScanRegAllocator::PrintLiveRanges() { + // ================= Output to plot.pg =============== + std::ofstream out("plot.pg"); + std::streambuf *coutbuf = LogInfo::MapleLogger().rdbuf(); // old buf + LogInfo::MapleLogger().rdbuf(out.rdbuf()); // new buf + + LogInfo::MapleLogger() << "#!/usr/bin/gnuplot\n"; + LogInfo::MapleLogger() << "#max_insn_num " << max_insn_num << "\n"; + LogInfo::MapleLogger() << "#min_vreg_num " << min_vreg_num << "\n"; + LogInfo::MapleLogger() << "#max_vreg_num " << max_vreg_num << "\n"; + LogInfo::MapleLogger() << "reset\nset terminal png\n"; + LogInfo::MapleLogger() << "set xrange [1:" << max_insn_num << "]\n"; + // LogInfo::MapleLogger() << "set yrange [" << min_vreg_num-1 << ":" << max_vreg_num+1 << "]\n"; + LogInfo::MapleLogger() << "set grid\nset style data linespoints\n"; + LogInfo::MapleLogger() << "set datafile missing '0'\n"; + std::vector> graph; + graph.resize(max_vreg_num); + for (uint32 i = 0; i < max_vreg_num; i++) { + graph[i].resize(max_insn_num); + } + uint32 minY = 0xFFFFFFFF; + uint32 maxY = 0; + for (uint32 i = 0; i < LI_.size(); i++) { + if (!LI_[i] || LI_[i]->regno == 0) { + continue; + } + LiveInterval *li = LI_[i]; + uint32 regno = li->regno; + if ((li->last_use - li->first_def) < 20) { + continue; + } + if (regno < minY) { + minY = regno; + } + if (regno > maxY) { + maxY = regno; + } + uint32 n; + for (n = 0; n <= (li->first_def - 1); n++) { + graph[regno - min_vreg_num][n] = 0; + } + if (li->last_use >= n) { + for (; n <= (li->last_use - 1); n++) { + graph[regno - min_vreg_num][n] = regno; + } + } + for (; n < max_insn_num; n++) { + graph[regno - min_vreg_num][n] = 0; + } + +#define CHECK_FOR_REG(opnd, regno, isdef) \ + { \ + if (!opnd->IsRegister()) { \ + continue; \ + } \ + RegOperand *RegOpnd = static_cast(opnd); \ + if (RegOpnd->GetRegisterType() == kRegTyCc || RegOpnd->GetRegisterType() == kRegTyVary) { \ + continue; \ + } \ + if (RegOpnd->GetRegisterNumber() == regno) { \ + LogInfo::MapleLogger() << "set object circle at " << insn->id << "," << li->regno << " size 5 fillcolor rgb \""; \ + if (isdef) \ + LogInfo::MapleLogger() << "black\"\n"; \ + else \ + LogInfo::MapleLogger() << "orange\"\n"; \ + } \ + } + + for (uint32_t bbIdx = 0; bbIdx < sorted_bbs.size(); bbIdx++) { + BB *bb = sorted_bbs[bbIdx]; + FOR_BB_INSNS(insn, bb) { + const Riscv64MD *md = &Riscv64CG::kMd[static_cast(insn)->mop_]; + for (int32_t i = 0; i < Insn::kMaxOperandNum; i++) { + Operand *opnd = insn->GetOperand(i); + if (!opnd) { + continue; + } + if (opnd->IsList()) { + } else if (opnd->IsMemoryAccessOperand()) { + MemOperand *memopnd = static_cast(opnd); + Operand *base = memopnd->GetBaseRegister(); + Operand *offset = memopnd->GetIndexRegister(); + if (base) { + CHECK_FOR_REG(base, regno, false); + } + if (offset) { + CHECK_FOR_REG(offset, regno, false); + } + } else { + bool isdef = static_cast(md->operand_[i])->IsRegDef(); + CHECK_FOR_REG(opnd, regno, isdef); + } + } + } + } +#undef CHECK_FOR_REG + // LogInfo::MapleLogger()<<"set object circle at "<first_def<<","<< li->regno << " size 0.1 fillcolor rgb \"red\"\n"; + // LogInfo::MapleLogger()<<"set object circle at "<last_use <<","<< li->regno << " size 0.1 fillcolor rgb \"black\"\n"; + } + LogInfo::MapleLogger() << "set yrange [" << minY - 1 << ":" << maxY + 1 << "]\n"; + + LogInfo::MapleLogger() << "plot \"plot.dat\" using 1:2 title \"R" << min_vreg_num << "\""; + for (uint32 i = 1; i < (max_vreg_num - min_vreg_num + 1); i++) { + LogInfo::MapleLogger() << ", \\\n\t\"\" using 1:" << i + 2 << " title \"R" << min_vreg_num + i << "\""; + } + LogInfo::MapleLogger() << ";\n"; + + // ================= Output to plot.dat =============== + std::ofstream out2("plot.dat"); + LogInfo::MapleLogger().rdbuf(out2.rdbuf()); // new buf + LogInfo::MapleLogger() << "##reg"; + for (uint32 i = min_vreg_num; i <= max_vreg_num; i++) { + LogInfo::MapleLogger() << " R" << i; + } + LogInfo::MapleLogger() << "\n"; + for (uint32 n = 0; n < max_insn_num; n++) { + LogInfo::MapleLogger() << n + 1; + for (uint32 i = min_vreg_num; i <= max_vreg_num; i++) { + LogInfo::MapleLogger() << " " << graph[i - min_vreg_num][n]; + } + LogInfo::MapleLogger() << "\n"; + } + LogInfo::MapleLogger().rdbuf(coutbuf); +} + +void LSRALinearScanRegAllocator::PrintLiveInterval(LiveInterval *li, string str) { + LogInfo::MapleLogger() << str << "\n"; + if (li->is_call != nullptr) { + LogInfo::MapleLogger() << " first_def " << li->first_def; + LogInfo::MapleLogger() << " is_call"; + } else if (li->phys_use) { + LogInfo::MapleLogger() << "\tregno " << li->regno; + LogInfo::MapleLogger() << " first_def " << li->first_def; + LogInfo::MapleLogger() << " phys_use " << li->phys_use; + LogInfo::MapleLogger() << " end_by_call " << li->end_by_call; + } else { + LogInfo::MapleLogger() << "\tregno " << setw(5) << li->regno; + LogInfo::MapleLogger() << " first_def " << setw(8) << li->first_def; + LogInfo::MapleLogger() << " last_use " << setw(8) << li->last_use; + LogInfo::MapleLogger() << " assigned " << li->assigned_reg; + LogInfo::MapleLogger() << " ref_count " << li->ref_count; + LogInfo::MapleLogger() << " priority " << li->priority; + } + LogInfo::MapleLogger() << " object_address 0x" << std::hex << li << std::dec << "\n"; +} + +void LSRALinearScanRegAllocator::PrintParamQueue(string str) { + LogInfo::MapleLogger() << str << "\n"; + for (uint32 i = 0; i < int_param_queue.size(); i++) { + if (int_param_queue[i].empty()) { + continue; + } + LiveInterval *li = int_param_queue[i].front(); + LiveInterval *last = int_param_queue[i].back(); + PrintLiveInterval(li, ""); + while (li != last) { + int_param_queue[i].pop_front(); + int_param_queue[i].push_back(li); + li = int_param_queue[i].front(); + PrintLiveInterval(li, ""); + } + int_param_queue[i].pop_front(); + int_param_queue[i].push_back(li); + } +} + +void LSRALinearScanRegAllocator::PrintCallQueue(string str) { + LogInfo::MapleLogger() << str << "\n"; + for (MapleList::iterator it = call_list.begin(); it != call_list.end(); it++) { + LiveInterval *li = static_cast(*it); + PrintLiveInterval(li, ""); + } +} + +void LSRALinearScanRegAllocator::PrintActiveList(string str, uint32 len) { + uint32 count = 0; + MapleSet::iterator it; + LogInfo::MapleLogger() << str << " " << active.size() << "\n"; + for (it = active.begin(); it != active.end(); it++) { + PrintLiveInterval(*it, ""); + count++; + if ((len != 0) && (count == len)) { + break; + } + } +} + +void LSRALinearScanRegAllocator::PrintActiveListSimple() { + MapleSet::iterator it; + for (it = active.begin(); it != active.end(); it++) { + LiveInterval *li = *it; + uint32 assignedReg = li->assigned_reg; + if (li->stk_slot == SPILLED) { + assignedReg = 16; + } + LogInfo::MapleLogger() << li->regno << "(" << assignedReg << ", "; + if (li->phys_use) { + LogInfo::MapleLogger() << "p) "; + } else { + LogInfo::MapleLogger() << li->first_acrossed_call; + } + LogInfo::MapleLogger() << "<" << li->first_def << "," << li->last_use << ">) "; + } + LogInfo::MapleLogger() << "\n"; +} + +void LSRALinearScanRegAllocator::PrintLiveIntervals() { + for (uint32_t i = 0; i < LI_.size(); i++) { + if (!LI_[i] || LI_[i]->regno == 0) { + continue; + } + PrintLiveInterval(LI_[i], ""); + } + LogInfo::MapleLogger() << "\n"; +} + +void LSRALinearScanRegAllocator::DebugCheckActiveList() { + LiveInterval *prev = nullptr; + MapleSet::iterator it; + for (it = active.begin(); it != active.end(); it++) { + LiveInterval *li = *it; + if (prev != nullptr) { + if ((li->regno <= V7) && (prev->regno > V7)) { + if (li->first_def < prev->first_def) { + LogInfo::MapleLogger() << "ERRer: active list with out of order phys + vreg\n"; + PrintLiveInterval(prev, "prev"); + PrintLiveInterval(li, "current"); + PrintActiveList("Active", 10); + } + } + if ((li->regno <= V7) && (prev->regno <= V7)) { + if (li->first_def < prev->first_def) { + LogInfo::MapleLogger() << "ERRer: active list with out of order phys reg use\n"; + PrintLiveInterval(prev, "prev"); + PrintLiveInterval(li, "current"); + PrintActiveList("Active", 10); + } + } + } else { + prev = li; + } + } +} + +// Prepare the free physical register pool for allocation. +// When a physical register is allocated, it is removed from the pool. +// The physical register is re-inserted into the pool when the associated live +// interval has ended. +void LSRALinearScanRegAllocator::InitFreeRegPool() { + // x2=sp x8=fp x10-x11=return x10-x17=param f10-f11=return f10-17=param + // caller x5-x7, x10-17, x28-x31 fp f0-f7, f10-f17, f28-f31 + // callee x9, x18-x27 fp f8-f9, f18-f27 + + // int caller + for (uint32 i = 5; i <= 7; i++) { + int_caller_reg_set.insert(i); + int_caller_mask |= (1 << i); + } + for (uint32 i = kFirstIntParamEnum; i <= kLastIntParamEnum; i++) { + int_param_reg_set.insert(i); + int_param_mask |= (1 << i); + } + for (uint32 i = 28; i <= 31; i++) { + int_caller_reg_set.insert(i); + int_caller_mask |= (1 << i); + } + // int callee + int_callee_reg_set.insert(9); + int_callee_mask |= (1 << 9); + for (uint32 i = 18; i <= 27; i++) { + int_callee_reg_set.insert(i); + int_callee_mask |= (1 << i); + } + // ==== fp regs ==== + for (uint32 i = 0; i <= 7; i++) { + fp_caller_reg_set.insert(i); + fp_caller_mask |= (1 << i); + } + for (uint32 i = kFirstFpParamRegNum; i <= kLastFpParamRegNum; i++) { + fp_param_reg_set.insert(i); + fp_param_mask |= (1 << i); + } + for (uint32 i = 28; i <= 31; i++) { + fp_caller_reg_set.insert(i); + fp_caller_mask |= (1 << i); + } + // fp callee + for (uint32 i = 8; i <= 9; i++) { + fp_callee_reg_set.insert(i); + fp_callee_mask |= (1 << i); + } + for (uint32 i = 18; i <= 27; i++) { + fp_callee_reg_set.insert(i); + fp_callee_mask |= (1 << i); + } + // function parameter registers + for (uint32 i = 10; i <= 17; i++) { + int_param_reg_set.insert(i); + int_param_mask |= (1 << i); + } + for (uint32 i = 10; i <= 17; i++) { + fp_param_reg_set.insert(i); + fp_param_mask |= (1 << i); + } + // The number of registers set aside for spill should equal to the max + // number of operands in one instruction. Assume two for now. + CG_ASSERT(MAX_INT_SPILL == 2, "LinearScanRegAllocator::InitFreeRegPool wrong # of spill regs"); + int_spill_reg_set[0] = kSpillRegEnum0; + int_spill_reg_set[1] = kSpillRegEnum1; + int_caller_reg_set.erase(kSpillRegEnum0); + int_caller_mask &= ~(1 << kSpillRegEnum0); + int_caller_reg_set.erase(kSpillRegEnum1); + int_caller_mask &= ~(1 << kSpillRegEnum1); + CG_ASSERT(MAX_FP_SPILL == 2, "LinearScanRegAllocator::InitFreeRegPool wrong # of spill regs"); + fp_spill_reg_set[0] = kSpillRegEnum0; + fp_spill_reg_set[1] = kSpillRegEnum1; + fp_caller_reg_set.erase(kSpillRegEnum0); + fp_caller_mask &= ~(1 << kSpillRegEnum0); + fp_caller_reg_set.erase(kSpillRegEnum1); + fp_caller_mask &= ~(1 << kSpillRegEnum1); + + if (LSRA_DUMP) { + PrintRegSet(int_caller_reg_set, "ALLOCATABLE_INT_CALLER"); + PrintRegSet(int_callee_reg_set, "ALLOCATABLE_INT_CALLEE"); + PrintRegSet(int_param_reg_set, "ALLOCATABLE_INT_PARAM"); + PrintRegSet(fp_caller_reg_set, "ALLOCATABLE_FP_CALLER"); + PrintRegSet(fp_callee_reg_set, "ALLOCATABLE_FP_CALLEE"); + PrintRegSet(fp_param_reg_set, "ALLOCATABLE_FP_PARAM"); + LogInfo::MapleLogger() << "INT_SPILL_REGS"; + for (uint i = 0; i < max_int_spill; i++) { + LogInfo::MapleLogger() << " " << int_spill_reg_set[i]; + } + LogInfo::MapleLogger() << "\n"; + LogInfo::MapleLogger() << "FP_SPILL_REGS"; + for (uint i = 0; i < MAX_FP_SPILL; i++) { + LogInfo::MapleLogger() << " " << fp_spill_reg_set[i]; + } + LogInfo::MapleLogger() << "\n"; + LogInfo::MapleLogger() << std::hex; + LogInfo::MapleLogger() << "INT_CALLER_MASK " << int_caller_mask << "\n"; + LogInfo::MapleLogger() << "INT_CALLEE_MASK " << int_callee_mask << "\n"; + LogInfo::MapleLogger() << "INT_PARAM_MASK " << int_param_mask << "\n"; + LogInfo::MapleLogger() << "FP_CALLER_FP_MASK " << fp_caller_mask << "\n"; + LogInfo::MapleLogger() << "FP_CALLEE_FP_MASK " << fp_callee_mask << "\n"; + LogInfo::MapleLogger() << "FP_PARAM_FP_MASK " << fp_param_mask << "\n"; + LogInfo::MapleLogger() << std::dec; + } +} + +bool LSRALinearScanRegAllocator::AllPredBBVisited(BB *bb) { + bool allPredVisited = true; + for (MapleList::iterator predIt = bb->preds.begin(); predIt != bb->preds.end(); ++predIt) { + BB *predBb = *predIt; + // See if pred bb is a loop back edge + bool isBackEdge = false; + for (MapleList::iterator loopIt = predBb->loop_succs.begin(); loopIt != predBb->loop_succs.end(); ++loopIt) { + BB *loopBb = *loopIt; + if (loopBb == bb) { + isBackEdge = true; + break; + } + } + if ((isBackEdge == false) && (visited_bbs[predBb->id] == false)) { + // LogInfo::MapleLogger() << "\t\tbb " << bb->id << " not visited pred bb " << pred_bb->id << "\n"; + allPredVisited = false; + break; + } + } + for (MapleList::iterator predIt = bb->eh_preds.begin(); predIt != bb->eh_preds.end(); ++predIt) { + BB *predBb = *predIt; + bool isBackEdge = false; + for (MapleList::iterator loopIt = predBb->loop_succs.begin(); loopIt != predBb->loop_succs.end(); ++loopIt) { + BB *loopBb = *loopIt; + if (loopBb == bb) { + isBackEdge = true; + break; + } + } + if ((isBackEdge == false) && (visited_bbs[predBb->id] == false)) { + // LogInfo::MapleLogger() << "\t\tbb " << bb->id << " not visited eh_pred bb " << pred_bb->id << "\n"; + allPredVisited = false; + break; + } + } + return allPredVisited; +} + +// During live interval construction, bb has only one predecessor and/or one +// successor are stright line bb. It can be considered to be a single large bb +// for the purpose of finding live interval. This is to prevent extending live +// interval of registers unnecessarily when interleaving bb from other paths. +BB *LSRALinearScanRegAllocator::MarkStraightLineBBInBFS(BB *bb) { + while (1) { + if (bb->succs.size() == 1 && bb->eh_succs.size() == 0) { + BB *sbb = bb->succs.front(); + if (visited_bbs[sbb->id] == true) { + break; + } + if (sbb->preds.size() == 1 && sbb->eh_preds.size() == 0) { + sorted_bbs.push_back(sbb); + // LogInfo::MapleLogger() <<"\tSorted sbb " << sbb->id << "\n"; + visited_bbs[sbb->id] = true; + bb = sbb; + } else { + break; + } + } else { + break; + } + } + return bb; +} + +BB *LSRALinearScanRegAllocator::SearchForStraightLineBBs(BB *bb) { + /* Special case for issue #1863. + * Switch cases containing a simple if(){bbs} break; + * Try to group if and bbs together. + */ + if (bb->succs.size() != 2 || bb->eh_succs.size() != 0) { + return bb; + } + BB *sbb1 = bb->succs.front(); + BB *sbb2 = bb->succs.back(); + uint32 predSz1 = sbb1->preds.size(); + uint32 predSz2 = sbb2->preds.size(); + BB *candidateBb = nullptr; + if (predSz1 == 1 && predSz2 > 5) { + candidateBb = sbb1; + } else if (predSz2 == 1 && predSz1 > 5) { + candidateBb = sbb2; + } else { + return bb; + } + CG_ASSERT(candidateBb->id < visited_bbs.size(), + "index out of range in LSRALinearScanRegAllocator::SearchForStraightLineBBs"); + if (visited_bbs[candidateBb->id] == true) { + return bb; + } + if (candidateBb->eh_preds.size() != 0) { + return bb; + } + if (candidateBb->succs.size() != 1) { + return bb; + } + + sorted_bbs.push_back(candidateBb); + visited_bbs[candidateBb->id] = true; + return MarkStraightLineBBInBFS(candidateBb); +} + +// breadth first search of bb for live interval computation. +void LSRALinearScanRegAllocator::BFS(BB *curbb) { + std::queue worklist; + worklist.push(curbb); + CG_ASSERT(curbb->id < cgfunc_->NumBBs(), "LinearScanRegAllocator::BFS visited_bbs overflow"); + CG_ASSERT(curbb->id < visited_bbs.size(), "index out of range in LSRALinearScanRegAllocator::BFS"); + visited_bbs[curbb->id] = true; + do { + BB *bb = worklist.front(); + sorted_bbs.push_back(bb); + // LogInfo::MapleLogger() <<"\tSorted bb " << bb->id << "\n"; + CG_ASSERT(bb->id < cgfunc_->NumBBs(), "LinearScanRegAllocator::BFS visited_bbs overflow"); + visited_bbs[bb->id] = true; + worklist.pop(); + // Look for straight line bb + bb = MarkStraightLineBBInBFS(bb); + // Look for an 'if' followed by some straight-line bb + bb = SearchForStraightLineBBs(bb); + for (MapleList::iterator it = bb->succs.begin(); it != bb->succs.end(); ++it) { + BB *ibb = *it; + // See if there are unvisited predecessor + if (visited_bbs[ibb->id] == false) { + if (AllPredBBVisited(ibb) == true) { + worklist.push(ibb); + CG_ASSERT(ibb->id < cgfunc_->NumBBs(), "LinearScanRegAllocator::BFS visited_bbs overflow"); + visited_bbs[ibb->id] = true; + } + } + } + } while (!worklist.empty()); + return; +} + +void LSRALinearScanRegAllocator::ComputeBlockOrder() { + visited_bbs.clear(); + sorted_bbs.clear(); + visited_bbs.resize(cgfunc_->NumBBs()); + for (uint32_t i = 0; i < cgfunc_->NumBBs(); i++) { + visited_bbs[i] = false; + } + + bool changed; + uint32 sortedCnt = 0; + bool done = false; + do { + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "BFS iteration " << sorted_bbs.size() << " " << cgfunc_->NumBBs() << "\n"; + } + changed = false; + FOR_ALL_BB(bb, cgfunc_) { + if (bb->internal_flag1 == 1) { + continue; + } + if (visited_bbs[bb->id] == false) { + // LogInfo::MapleLogger() << "Consider bb " << bb->id << "\n"; + changed = true; + if (AllPredBBVisited(bb) == true) { + // LogInfo::MapleLogger() << "\tBFS " << bb->id << "\n"; + BFS(bb); + } + } + } + // Make sure there is no infinite loop. + if (sortedCnt == sorted_bbs.size()) { + if (done == false) { + done = true; + } else { + LogInfo::MapleLogger() << "Error: LSRA BFS loop " << sortedCnt << "in func " << cgfunc_->GetName() << "\n"; + exit(0); + } + } + sortedCnt = sorted_bbs.size(); + } while (changed == true); + + BB *cleanupBb = nullptr; + FOR_ALL_BB(bb, cgfunc_) { + if (bb->firststmt == cgfunc_->cleanup_label) { + cleanupBb = bb; + break; + } + } + for (BB *bb = cleanupBb; bb; bb = bb->next) { + sorted_bbs.push_back(bb); + } + + if (LSRA_DUMP) { + for (uint32_t i = 0; i < sorted_bbs.size(); i++) { + LogInfo::MapleLogger() << "\n< === > "; + LogInfo::MapleLogger() << sorted_bbs[i]->id; + LogInfo::MapleLogger() << " succs:"; + MapleList succs = sorted_bbs[i]->succs; + for (MapleList::iterator it = succs.begin(); it != succs.end(); it++) { + BB *succBb = static_cast(*it); + LogInfo::MapleLogger() << " " << succBb->id; + } + LogInfo::MapleLogger() << " eh_succs:"; + succs = sorted_bbs[i]->eh_succs; + for (MapleList::iterator it = succs.begin(); it != succs.end(); it++) { + BB *succBb = static_cast(*it); + LogInfo::MapleLogger() << " " << succBb->id; + } + } + LogInfo::MapleLogger() << "\n"; + } +} + +// Remember calls for caller/callee allocation. +void LSRALinearScanRegAllocator::RecordCall(Insn *insn) { + // Maintain call at the beginning of active list + LiveInterval *li = cgfunc_->memPool->New(allocator); + li->first_def = insn->id; + li->is_call = insn; + call_list.push_back(li); +} + +// Handle parameter registers for live interval. +void LSRALinearScanRegAllocator::RecordPhysRegs(Insn *insn, RegOperand *regOpnd, uint32 insnNum, bool isDef, + bool isCall) { + RegType regtype = regOpnd->GetRegisterType(); + uint32 regno = regOpnd->GetRegisterNumber(); + if (regtype == kRegTyCc || regtype == kRegTyVary) { + return; + } + + if (IsUntouchableReg(regno) || regOpnd->IsConstReg()) { + return; + } + + if (regno == R30) { + return; + } + + if (regno >= V0 && regno <= V31) { + simd_spill_regs.erase(regno); + simd_spill_0.erase(regno); + simd_spill_1.erase(regno); + } + + bool maybeParam = (regtype == kRegTyInt && int_param_queue[regno - kFirstIntParamReg].size() == 0) || + (regtype == kRegTyFloat && fp_param_queue[regno - kFirstFpParamReg].size() == 0); + + if (isDef) { + // parameter register def is assumed to be live until a call. + LiveInterval *li = cgfunc_->memPool->New(allocator); + li->regno = regno; + li->regtype = regtype; + li->stk_slot = -1; + li->first_def = insnNum; + li->phys_use = insnNum; + li->assigned_reg = regno; + if (regtype == kRegTyInt) { + int_param_queue[regno - kFirstIntParamReg].push_back(li); + } else { + fp_param_queue[regno - kFirstFpParamReg].push_back(li); + } + } else if (maybeParam) { + CHECK_FATAL(false, "impossible"); + } else { + if (regtype == kRegTyInt) { + CHECK_FATAL((regno - R10) < int_param_queue.size(), "index out of range in LSRALinearScanRegAllocator::RecordPhysRegs"); + LiveInterval *li = int_param_queue[regno - kFirstIntParamReg].back(); + li->phys_use = insnNum; + } else { + LiveInterval *li = fp_param_queue[regno - kFirstFpParamReg].back(); + li->phys_use = insnNum; + } + } +} + +// main entry function for live interval computation. +void LSRALinearScanRegAllocator::SetupLiveInterval(Operand *opnd, Insn *insn, bool isDef, uint32 &nUses) { + if (!opnd->IsRegister()) { + return; + } + RegOperand *regOpnd = static_cast(opnd); + uint32 regno = regOpnd->GetRegisterNumber(); + uint32 insnNum = insn->id; + if (regOpnd->IsPhysicalRegister()) { + RecordPhysRegs(insn, regOpnd, insnNum, isDef); + return; + } + RegType regtype = regOpnd->GetRegisterType(); + if (regtype == kRegTyCc || regtype == kRegTyVary) { + return; + } + + LiveInterval *li = nullptr; + if (!LI_[regno]) { + li = cgfunc_->memPool->New(allocator); + li->regno = regno; + li->regtype = regtype; + li->stk_slot = -1; + LI_[regno] = li; + } else { + li = LI_[regno]; + } + + if (isDef) { + if (li->first_def == 0) { + li->first_def = insnNum; + li->last_use = insnNum + 1; + } else if (li->last_use < insnNum) { + if (insn->bb->unreachable == false) { + li->last_use = insnNum + 1; + } + } + // try-catch related + // Not set when extending live interval with bb's livein in ComputeLiveInterval. + li->regtype = regtype; + if (li->use_before_def == true) { + if (insn->bb->unreachable == false) { + li->last_use = insnNum + 1; + } + } + li->result_count++; + } else { + if (li->first_def == 0) { + CG_ASSERT(0, "SetupLiveInterval: use before def"); + } + /* + * In ComputeLiveInterval when extending live interval using + * live-out information, li created does not have a type. + */ + li->regtype = regtype; + if (insn->bb->unreachable == false) { + li->last_use = insnNum; + } + nUses++; + } + + if (insn->bb->is_catch) { + li->SetInCatchState(); + } else { + li->SetNotInCatchState(); + } + + if (insn->bb->internal_flag1) { + li->SetInCleanupState(); + } else { + if (insn->bb->id != 1) { + li->SetNotInCleanupState(false); + } else { + li->SetNotInCleanupState(true); + } + } + + li->ref_count++; + + uint32 index = regno / (sizeof(uint64) * 8); + uint64 bit = regno % (sizeof(uint64) * 8); + if (reg_used_in_bb[index] & (1 << bit)) { + li->multi_use_in_bb = true; + } + reg_used_in_bb[index] |= (1 << bit); + + if (min_vreg_num > regno) { + min_vreg_num = regno; + } + if (max_vreg_num < regno) { + max_vreg_num = regno; + } + + // setup the def/use point for it + CG_ASSERT(regno < LI_.size(), "out of range of vector LI_"); + + return; +} + +// Support 'hole' in LSRA. +// For a live interval, there might be multiple segments of live ranges, +// and between these segments a 'hole'. +// Some other short lived vreg can go into these 'holes'. +// +// from : starting instruction sequence id +// to : ending instruction sequence id +void LSRALinearScanRegAllocator::LiveInterval::AddRange(uint32 from, uint32 to) { + if (ranges.size() == 0) { + ranges.push_back(pair(from, to)); + } else { + if (to < ranges.front().first) { + ranges.insert(ranges.begin(), pair(from, to)); + } else if (to >= ranges.front().second && from < ranges.front().first) { + ranges.front().first = from; + ranges.front().second = to; + } else if (to >= ranges.front().first && from < ranges.front().first) { + ranges.front().first = from; + } else if (from > ranges.front().second) { + CG_ASSERT(0, "No possible on reverse traverse."); + } else { + // Do nothing. + } + } + return; +} + +void LSRALinearScanRegAllocator::LiveInterval::AddUsePos(uint32 pos) { + use_positions.insert(pos); +} + +// See if a vreg can fit in one of the holes of a longer live interval. +uint32 LSRALinearScanRegAllocator::FillInHole(LiveInterval *li) { + MapleSet::iterator it; + for (it = active.begin(); it != active.end(); it++) { + LiveInterval *ili = static_cast(*it); + + /* If ili is part in cleanup, the hole info will be not correct, + since cleanup bb do not have edge to normal func bb, and the + live-out info will not correct.*/ + if (!ili->IsAllOutCleanup() || ili->IsInCatch()) { + continue; + } + + if (ili->regtype == li->regtype && ili->stk_slot == -1 && ili->li_child == nullptr && ili->assigned_reg != 0) { + MapleVector>::iterator it; + for (it = ili->holes.begin(); it != ili->holes.end(); it++) { + if ((*it).first <= li->first_def && (*it).second >= li->last_use) { + ili->li_child = li; + li->li_parent = ili; + li->assigned_reg = ili->assigned_reg; + /* No need to modify simd_spill_regs since ili already updated it. */ + // If assigned physical register is callee save register, set should_save false; + uint32 phyRegIndx = 0; + if (li->regtype == kRegTyInt) { + phyRegIndx = li->assigned_reg - R0; + } else if (li->regtype == kRegTyFloat) { + phyRegIndx = li->assigned_reg - V0; + } else { + CG_ASSERT(false, "FillInHole, Invalid register type"); + } + + uint32 mask; + if (li->regtype == kRegTyInt) { + mask = int_callee_mask; + } else { + mask = fp_callee_mask; + } + if ((1 << phyRegIndx) & mask) { + li->should_save = false; + } + return ili->assigned_reg; + } else if ((*it).first > li->last_use) { + break; + } + } + } + } + return 0; +} + +// Support finding holes by searching for ranges where holes exist. +void LSRALinearScanRegAllocator::BuildIntervalRanges() { + uint32_t bbIdx = sorted_bbs.size(); + uint32 regno; + if (bbIdx == 0) { + return; + } + + do { + bbIdx--; + BB *bb = sorted_bbs[bbIdx]; + if (bb->firstinsn == nullptr || bb->lastinsn == nullptr) { + continue; + } + uint32 blockFrom = bb->firstinsn->id; + uint32 blockTo = bb->lastinsn->id + 1; + + for (auto it = bb->liveout_regno.begin(); it != bb->liveout_regno.end(); it++) { + regno = static_cast(*it); + if (regno < kMaxRegNum) { + // Do not consider physical regs. + continue; + } + LI_[regno]->AddRange(blockFrom, blockTo); + } + + FOR_BB_INSNS_REV(insn, bb) { + const Riscv64MD *md = &Riscv64CG::kMd[static_cast(insn)->mop_]; + for (int32_t i = 0; i < Insn::kMaxOperandNum; i++) { + Operand *opnd = insn->GetOperand(i); + if (!opnd) { + continue; + } + + if (opnd->IsMemoryAccessOperand()) { + MemOperand *memopnd = static_cast(opnd); + Operand *base = memopnd->GetBaseRegister(); + if (base != nullptr && base->IsRegister()) { + RegOperand *regOpnd = static_cast(base); + RegType regtype = regOpnd->GetRegisterType(); + if (regtype != kRegTyCc && regtype != kRegTyVary) { + regno = regOpnd->GetRegisterNumber(); + if (regno > kMaxRegNum) { + LI_[regno]->AddRange(blockFrom, insn->id); + LI_[regno]->use_positions.insert(insn->id); + } + } + } + } else { + if (opnd->IsRegister()) { + RegOperand *regOpnd = static_cast(opnd); + RegType regtype = regOpnd->GetRegisterType(); + if (regtype != kRegTyCc && regtype != kRegTyVary) { + bool isdef = static_cast(md->operand_[i])->IsRegDef(); + bool isuse = static_cast(md->operand_[i])->IsRegUse(); + regno = regOpnd->GetRegisterNumber(); + if (regno > kMaxRegNum) { + if (isdef) { + if (!LI_[regno]->ranges.empty()) { + LI_[regno]->ranges.front().first = insn->id; + LI_[regno]->use_positions.insert(insn->id); + } + } + if (isuse) { + LI_[regno]->AddRange(blockFrom, insn->id); + LI_[regno]->use_positions.insert(insn->id); + } + } + } + } + } + } + } + } while (bbIdx != 0); + + // Build holes. + for (int i = 0; i < cgfunc_->GetMaxVReg(); i++) { + LiveInterval *li = LI_[i]; + if (li == nullptr) { + continue; + } + if (li->ranges.size() < 2) { + continue; + } + + MapleVector>::iterator it; + MapleVector>::iterator itPrev = li->ranges.end(); + + for (it = li->ranges.begin(); it != li->ranges.end(); it++) { + if (itPrev == li->ranges.end()) { + itPrev = it; + continue; + } + if (((*it).first - (*itPrev).second) > 2) { + li->holes.push_back(std::pair((*itPrev).second, (*it).first)); + } + itPrev = it; + } + } +} + +void LSRALinearScanRegAllocator::ComputeLiveInterval() +// Preference is to put bracket as 1st char of a newline +{ + uint32_t insnNum; + // initialize block ordering + // Can be either breadth first or depth first. + // To avoid use before set, we prefer breadth first + ComputeBlockOrder(); + + callee_use_cnt.resize(kMaxRegNum); + LI_.resize(cgfunc_->GetMaxVReg()); + // LiveInterval queue for each param register + last_int_param_li.resize(8); + last_fp_param_li.resize(8); + + for (uint32 i = 0; i < 32; i++) { + if (((1 << i) & fp_callee_mask) == 0) { + continue; + } + simd_spill_regs.insert(i + V0); + simd_spill_0.insert(i + V0); + simd_spill_1.insert(i + V0); + } + insnNum = 1; + + for (uint32_t bbIdx = 0; bbIdx < sorted_bbs.size(); bbIdx++) { + BB *bb = sorted_bbs[bbIdx]; + // Extend live interval with live-in info + for (auto it = bb->livein_regno.begin(); it != bb->livein_regno.end(); it++) { + regno_t regno = static_cast(*it); + if (regno < kMaxRegNum) { + // Do not consider physical regs. + continue; + } + LiveInterval *li = LI_[regno]; + if (!li && (!bb->IsEmpty() || bb->id == 1)) { + // try-catch related + // Since it is livein but not seen before, its a use before def + LiveInterval *li = cgfunc_->memPool->New(allocator); + li->regno = regno; + // li->regtype = regtype; // Set in SetupLiveInterval + li->stk_slot = -1; + LI_[regno] = li; + li->first_def = insnNum; + li->use_before_def = true; + if (bb->unreachable == false && static_cast(cgfunc_)->GetJavaCatchRegno() != regno) { + if (bb->id != 1) { + LogInfo::MapleLogger() << "ERROR: " << regno << " use before def in bb " << bb->id << " : " << cgfunc_->GetName() << "\n"; + CHECK_FATAL(0, "There should only be [use before def in bb 1], temporarily."); + } + LogInfo::MapleLogger() << "WARNING: " << regno << " use before def in bb " << bb->id << " : " << cgfunc_->GetName() << "\n"; + } + // Need to insert to active list now, as live interval is + // conservatively to start at instruction 1 + active.insert(li); + + if (bb->is_catch) { + li->SetInCatchState(); + } else { + li->SetNotInCatchState(); + } + + if (bb->internal_flag1) { + li->SetInCleanupState(); + } else { + if (bb->id != 1) { + li->SetNotInCleanupState(false); + } else { + li->SetNotInCleanupState(true); + } + } + } + } + + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "bb(" << bb->id << ")LIVEOUT:"; + MapleSet::iterator it; + for (auto it = bb->liveout_regno.begin(); it != bb->liveout_regno.end(); + it++) { + regno_t regno = static_cast(*it); + LogInfo::MapleLogger() << " " << regno; + } + LogInfo::MapleLogger() << ".\n"; + LogInfo::MapleLogger() << "bb(" << bb->id << ")LIVEIN:"; + for (auto it = bb->livein_regno.begin(); it != bb->livein_regno.end(); it++) { + regno_t regno = static_cast(*it); + LogInfo::MapleLogger() << " " << regno; + } + LogInfo::MapleLogger() << ".\n"; + } + + reg_used_in_bb_sz = (cgfunc_->GetMaxVReg() / (sizeof(uint64) * 8) + 1); + reg_used_in_bb = new uint64[reg_used_in_bb_sz]; + errno_t rc = memset_s(reg_used_in_bb, reg_used_in_bb_sz * sizeof(uint64), 0, reg_used_in_bb_sz * sizeof(uint64)); + CG_ASSERT(rc == EOK, "call memset_s failed in LSRALinearScanRegAllocator::ComputeLiveInterval()"); + if (bb->firstinsn != nullptr) { + if (!bb->eh_preds.empty()) { + bb->livein_regno.insert(R0); + bb->livein_regno.insert(R1); + } + // traverse live in regno, for each live in regno create a new liveinterval + for (auto it = bb->livein_regno.begin(); it != bb->livein_regno.end(); it++) { + regno_t regno = static_cast(*it); + if ((regno >= kFirstIntParamReg && regno <= kLastIntParamReg) || + (regno >= kFirstFpParamReg && regno <= kLastFpParamReg)) { + LiveInterval *li = cgfunc_->memPool->New(allocator); + li->regno = regno; + li->stk_slot = -1; + li->first_def = insnNum; + li->phys_use = insnNum; + li->assigned_reg = regno; + if (regno >= kFirstIntParamReg && regno <= kLastIntParamReg) { + li->regtype = kRegTyInt; + int_param_queue[regno - kFirstIntParamReg].push_back(li); + } else { + li->regtype = kRegTyFloat; + fp_param_queue[regno - kFirstFpParamReg].push_back(li); + } + } + } + if (!bb->eh_preds.empty()) { + bb->livein_regno.erase(R0); + bb->livein_regno.erase(R1); + } + } + + FOR_BB_INSNS(insn, bb) { + uint32 numUses; + insn->id = insnNum; + + // skip comment and debug insn + if (insn->IsImmaterialInsn()) { + continue; + } + if (!insn->IsMachineInstruction()) { + continue; + } + if (insn->mop_ == MOP_clinit) { + RegOperand *dst = static_cast(insn->GetOperand(0)); + RegOperand *phyOpnd = static_cast(cgfunc_)->GetOrCreatePhysicalRegisterOperand( + (Riscv64reg_t)(R30), dst->GetSize(), dst->GetRegisterType()); + insn->SetOperand(0, phyOpnd); + } + + if (insn->IsCall()) { + bool skipCall = false; + if (!insn->IsIndirectCall()) { + FuncNameOperand *target = dynamic_cast(insn->GetCallTargetOperand()); + if (target) { + MIRSymbol *funcst = target->GetFunctionSymbol(); + CG_ASSERT(funcst->sKind == kStFunc, ""); + if (funcst->GetName() == "exit") { + // LogInfo::MapleLogger() << "skip exit func " <id << endl; + skipCall = true; + } else if ((localrefvar_max_stack_loc == 0) && (funcst->GetName() == GetIntrinsicFuncName(INTRN_MCCInitializeLocalStackRef))) { + // Detecting local ref var init size and start location. + localrefvar_min_stack_loc = FindLocalRefVarStackLoc(insn, R0); + uint32 slots = FindLocalRefVarStackLoc(insn, R1); + localrefvar_max_stack_loc = localrefvar_min_stack_loc + ((slots - 1) << 3); + lvar_offset_regno_map.resize(slots); + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "localrefvar stack loc " << localrefvar_min_stack_loc << " to " << localrefvar_max_stack_loc + << " slots " << slots << "\n"; + } + } + } + } + + if (!skipCall) { + if (!insn->is_throw || !bb->eh_succs.empty()) { + RecordCall(insn); + } + } + } + + numUses = 0; + const Riscv64MD *md = &Riscv64CG::kMd[static_cast(insn)->mop_]; + + // we need to process src opnd first just in case the src/dest vreg are the same and the src vreg belongs to the + // last interval. + bool isLocalrefvar = false; + uint32 immOffset = 0; + for (int32_t i = Insn::kMaxOperandNum - 1; i >= 0; i--) { + Operand *opnd = insn->GetOperand(i); + if (!opnd) { + continue; + } + + bool isdef = static_cast(md->operand_[i])->IsRegDef(); + if (opnd->IsList()) { + ListOperand *listopnd = static_cast(opnd); + for (auto op : listopnd->GetOperands()) { + SetupLiveInterval(op, insn, isdef, numUses); + } + } else if (opnd->IsMemoryAccessOperand()) { + MemOperand *memopnd = static_cast(opnd); + Operand *base = memopnd->GetBaseRegister(); + isdef = false; + // ldr(156) (opnd0: reg:V34 class: [F]) (opnd1: Mem:literal: + // .LB_Ljava_2Fnio_2FByteBuffer_3B_7CgetDouble_7C_28_29D2) + if (base != nullptr) { + SetupLiveInterval(base, insn, isdef, numUses); + } + + // Find a local ref var reference + if (base && localrefvar_max_stack_loc != 0 && base->IsRegister()) { + RegOperand *regOpnd = static_cast(base); + if (regOpnd->GetRegisterNumber() == R2) { + Riscv64MemOperand *mem = static_cast(opnd); + Riscv64OfstOperand *imm = mem->GetOffsetImmediate(); + if (imm != nullptr) { + immOffset = static_cast(imm->GetOffsetValue()); + isLocalrefvar = DetectLocalRefVarInfo(insn, immOffset); + } + } + } + } else { + SetupLiveInterval(opnd, insn, isdef, numUses); + } + } + if (isLocalrefvar) { + MarkLocalRefVarForLiveInterval(insn, immOffset); + } + insnNum++; + } + // traverse live out regno + // for each live out regno if the last corresponding live interval is created within this bb + // update this li->last_use to the end of BB + for (auto it = bb->liveout_regno.begin(); it != bb->liveout_regno.end(); it++) { + regno_t regno = static_cast(*it); + if ((regno >= kFirstIntParamReg && regno <= kLastIntParamReg) || + (regno >= kFirstFpParamReg && regno <= kLastFpParamReg)) { + // LogInfo::MapleLogger() << cgfunc_->func->GetName() << std::endl; + LiveInterval *li = nullptr; + if (regno >= kFirstIntParamReg && regno <= kLastIntParamReg) { + if (int_param_queue[regno - kFirstIntParamReg].size() == 0) { + continue; + } + li = int_param_queue[regno - kFirstIntParamReg].back(); + if (bb->firstinsn && li->first_def >= bb->firstinsn->id) { + li->phys_use = insnNum; + } + } else { + if (fp_param_queue[regno - kFirstFpParamReg].size() == 0) { + continue; + } + li = fp_param_queue[regno - kFirstFpParamReg].back(); + if (bb->firstinsn && li->first_def >= bb->firstinsn->id) { + li->phys_use = insnNum; + } + } + } + } + + delete[] reg_used_in_bb; + reg_used_in_bb = nullptr; + max_insn_num = insnNum - 1; // insn_num started from 1 + + // Extend live interval with live-out info + for (auto it = bb->liveout_regno.begin(); it != bb->liveout_regno.end(); it++) { + regno_t regno = static_cast(*it); + LiveInterval *li = LI_[regno]; + if (li != nullptr && !bb->IsEmpty()) { + li->last_use = bb->lastinsn->id; + + if (bb->is_catch) { + li->SetInCatchState(); + } else { + li->SetNotInCatchState(); + } + + if (bb->internal_flag1) { + li->SetInCleanupState(); + } else { + if (bb->id != 1) { + li->SetNotInCleanupState(false); + } else { + li->SetNotInCleanupState(true); + } + } + } + } + } + + for (uint32_t i = 0; i < LI_.size(); i++) { + LiveInterval *li = LI_[i]; + if (!li || li->regno == 0) { + continue; + } + if (li->is_call != nullptr || li->phys_use) { + continue; + } + if (li->last_use > li->first_def) { + li->priority = static_cast(li->ref_count) / static_cast(li->last_use - li->first_def); + } else { + li->priority = static_cast(li->ref_count) / static_cast(li->first_def - li->last_use); + } + } + + if (LSRA_DUMP) { + PrintLiveIntervals(); + } + // LogInfo::MapleLogger() << "Total " << insn_num << " insns in " << cgfunc_->GetName() << " \n"; + return; +} + +// A physical register is freed at the end of the live interval. Return to pool. +void LSRALinearScanRegAllocator::ReturnPregToSet(LiveInterval *li, uint32 preg) { + if (preg == 0) { + return; + } + if (li->regtype == kRegTyInt) { + preg -= R0; + } else if (li->regtype == kRegTyFloat) { + preg -= V0; + } else { + CG_ASSERT(0, "ReturnPregToSet: Invalid reg type"); + } + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "\trestoring preg " << preg << " as allocatable\n"; + } + uint32 mask = 1 << preg; + if (preg == 16 && li->stk_slot == -1) { + // this reg is temporary used for liveinterval which last_use-first_def == 1 + } else if (li->regtype == kRegTyInt) { + if (int_caller_mask & mask) { + int_caller_reg_set.insert(preg); + } else if (int_callee_mask & mask) { + int_callee_reg_set.insert(preg); + } else if (int_param_mask & mask) { + int_param_reg_set.insert(preg); + } else { + CG_ASSERT(0, "ReturnPregToSet: Unknown caller/callee type"); + } + } else if (fp_caller_mask & mask) { + fp_caller_reg_set.insert(preg); + } else if (fp_callee_mask & mask) { + fp_callee_reg_set.insert(preg); + } else if (fp_param_mask & mask) { + fp_param_reg_set.insert(preg); + } else { + CG_ASSERT(0, "ReturnPregToSet invalid physical register"); + } + return; +} + +// A physical register is removed from allocation as it is assigned. +void LSRALinearScanRegAllocator::ReleasePregToset(LiveInterval *li, uint32 preg) { + if (preg == 0) { + return; + } + if (li->regtype == kRegTyInt) { + preg -= R0; + } else if (li->regtype == kRegTyFloat) { + preg -= V0; + } else { + CG_ASSERT(0, "ReleasePregToset: Invalid reg type"); + } + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "\treleasing preg " << preg << " as allocatable\n"; + } + uint32 mask = 1 << preg; + if (preg == 16 && li->stk_slot == -1) { + // this reg is temporary used for liveinterval which last_use-first_def == 1 + } else if (li->regtype == kRegTyInt) { + if (int_caller_mask & mask) { + int_caller_reg_set.erase(preg); + } else if (int_callee_mask & mask) { + int_callee_reg_set.erase(preg); + } else if (int_param_mask & mask) { + int_param_reg_set.erase(preg); + } else { + CG_ASSERT(0, "ReleasePregToset: Unknown caller/callee type"); + } + } else if (fp_caller_mask & mask) { + fp_caller_reg_set.erase(preg); + } else if (fp_callee_mask & mask) { + fp_callee_reg_set.erase(preg); + } else if (fp_param_mask & mask) { + fp_param_reg_set.erase(preg); + } else { + CG_ASSERT(0, "ReleasePregToset invalid physical register"); + } + return; +} + +// Remove a live interval from 'active' list. +void LSRALinearScanRegAllocator::RetireFromActive(const Insn *insn) { + if ((insn->mop_ == MOP_adrp_ldr && insn->next && insn->next->mop_ == MOP_clinit_tail) || + (insn->mop_ == MOP_clinit_tail)) { + // Cannot spill for clinit pair + } else if (spill_all) { + return; + } + int instrNum = insn->id; + // active list is sorted based on increasing last_use + // any operand whose use is greater than current + // instruction number is still in use. + // If the use is less than or equal to instruction number + // then it is possible to retire this live interval and + // reclaim the physical register associated with it. + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "RetireFromActive instr_num " << instrNum << "\n"; + } + // Retire call from call queue + for (auto it = call_list.begin(); it != call_list.end();) { + LiveInterval *li = static_cast(*it); + if (li->first_def <= instrNum) { + call_list.pop_front(); + // at here, it is invalidated + it = call_list.begin(); + } else { + break; + } + } + + for (uint32 i = 0; i < int_param_queue.size(); i++) { + // push back the param not yet use <- as only one is popped, just push it back again + if (last_int_param_li[i]) { + int_param_queue[i].push_front(last_int_param_li[i]); + int_param_reg_set.insert(i + kFirstIntParamEnum); + last_int_param_li[i] = nullptr; + } + if (last_fp_param_li[i]) { + fp_param_queue[i].push_front(last_fp_param_li[i]); + fp_param_reg_set.insert(i + kFirstFpParamEnum); + last_fp_param_li[i] = nullptr; + } + } + + // Retire live intervals from active list + MapleSet::iterator it; + for (it = active.begin(); it != active.end(); /* erase will update */) { + LiveInterval *li = static_cast(*it); + if (li->last_use > instrNum) { + break; + } + // Is it phys reg? + if ((li->regno >= kFirstIntParamReg) && (li->regno <= kLastIntParamReg)) { + if (li->phys_use != 0 && li->phys_use <= instrNum) { + it = active.erase(it); + if (li->phys_use != 0) { + ReturnPregToSet(li, li->regno); + } + if (LSRA_DUMP) { + PrintLiveInterval(li, "\tRemoving phys_reg li\n"); + } + } else { + it++; + } + continue; + } else if ((li->regno >= V0) && (li->regno <= V7)) { + if (li->phys_use != 0 && li->phys_use <= instrNum) { + it = active.erase(it); + if (li->phys_use != 0) { + ReturnPregToSet(li, li->regno); + } + if (LSRA_DUMP) { + PrintLiveInterval(li, "\tRemoving phys_reg li\n"); + } + + } else { + it++; + } + continue; + } + // live interval ended for this reg in active + // release physical reg assigned to free reg pool + if (li->li_parent) { + li->li_parent->li_child = nullptr; + li->li_parent = nullptr; + } else { + ReturnPregToSet(li, li->assigned_reg); + } + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "Removing " + << "(" << li->assigned_reg << ")" + << "from regset\n"; + PrintLiveInterval(li, "\tRemoving virt_reg li\n"); + } + it = active.erase(it); + } +} + +// the return value is a physical reg +uint32 LSRALinearScanRegAllocator::GetRegFromSet(MapleSet &set, regno_t offset, LiveInterval *li, + regno_t forcedReg) { + uint32 regno; + if (forcedReg) { + // forced_reg is a caller save reg + regno = forcedReg; + } else { + CHECK(set.size() > 0, "set is null in LSRALinearScanRegAllocator::GetRegFromSet"); + regno = *(set.begin()); + } + set.erase(regno); + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "\tAssign " << regno << "\n"; + } + regno += offset; // Mapping into Maplecg reg + li->assigned_reg = regno; + if (regno >= V0 && regno <= V31) { + simd_spill_regs.erase(regno); + simd_spill_0.erase(regno); + simd_spill_1.erase(regno); + } + if (LSRA_DUMP) { + PrintRegSet(set, "Reg Set AFTER"); + PrintLiveInterval(li, "LiveInterval after assignment"); + } + return regno; +} + +// Handle adrp register assignment. Use the same register for the next +// instruction. +uint32 LSRALinearScanRegAllocator::AssignSpecialPhysRegPattern(Insn *insn, LiveInterval *li) { + MOperator opcode = insn->GetMachineOpcode(); + if (opcode != MOP_adrp) { + return 0; + } + Insn *ninsn = insn->next; + if (ninsn == nullptr || !ninsn->IsMachineInstruction() || ninsn->IsDMBInsn()) { + return 0; + } + + const Riscv64MD *md = &Riscv64CG::kMd[static_cast(ninsn)->mop_]; + bool isdef = static_cast(md->operand_[0])->IsRegDef(); + if (!isdef) { + return 0; + } + Operand *opnd = ninsn->GetOperand(0); + if (!opnd->IsRegister()) { + return 0; + } + RegOperand *regOpnd = static_cast(opnd); + if (!regOpnd->IsPhysicalRegister()) { + return 0; + } + uint32 regno = regOpnd->GetRegisterNumber(); + if (!(regno >= kFirstIntParamReg && regno <= kLastIntParamReg)) { + return 0; + } + + // next insn's dest is a physical param reg 'regno' + bool match = false; + for (int32 i = 1; i < Insn::kMaxOperandNum; i++) { + Operand *src = ninsn->GetOperand(i); + if (!src) { + continue; + } + if (src->IsMemoryAccessOperand()) { + MemOperand *memopnd = static_cast(src); + Operand *base = memopnd->GetBaseRegister(); + if (base) { + RegOperand *regSrc = static_cast(base); + uint32 srcRegno = regSrc->GetRegisterNumber(); + if (li->regno == srcRegno) { + match = true; + break; + } + } + } else if (src->IsRegister()) { + RegOperand *regSrc = static_cast(src); + uint32 srcRegno = regSrc->GetRegisterNumber(); + if (li->regno == srcRegno) { + bool srcIsdef = static_cast(md->operand_[i])->IsRegDef(); + if (srcIsdef) { + break; + } + match = true; + break; + } + } + } + if (match && li->last_use > ninsn->id) { + return 0; + } + // dest of adrp is src of next insn + if (match) { + return GetRegFromSet(int_param_reg_set, R0, li, regno - R0); + } + return 0; +} + +// Return a phys register number for the live interval. +uint32 LSRALinearScanRegAllocator::FindAvailablePhyReg(LiveInterval *li, Insn *insn) { + uint32 regno = 0; + if (fast_alloc) { + if (li->regtype == kRegTyInt) { + if (int_callee_reg_set.size() != 0) { + regno = GetRegFromSet(int_callee_reg_set, R0, li); + li->should_save = false; + } else if (int_caller_reg_set.size() != 0) { + regno = GetRegFromSet(int_caller_reg_set, R0, li); + li->should_save = true; + } else { + li->should_save = false; + } + } else if (li->regtype == kRegTyFloat) { + if (fp_callee_reg_set.size() != 0) { + regno = GetRegFromSet(fp_callee_reg_set, V0, li); + li->should_save = false; + } else if (fp_caller_reg_set.size() != 0) { + regno = GetRegFromSet(fp_caller_reg_set, V0, li); + li->should_save = true; + } else { + li->should_save = false; + } + } + return regno; + } + + uint32 vregno = li->regno; + bool saveAcrossCall = false; + // See if register is live accross a call + for (MapleList::iterator it = call_list.begin(); it != call_list.end(); it++) { + LiveInterval *cli = static_cast(*it); + if (cli->first_def > li->last_use) { + break; + } + bool isLiveout = false; + Insn *call = cli->is_call; + // Determine if vreg is live out from bb + if (g->optim_level >= 2 && call->bb->liveout_regno.find(vregno) != call->bb->liveout_regno.end()) { + isLiveout = true; + } + // Determine if live interval crosses the call + if (isLiveout && (cli->first_def > li->first_def) && (cli->first_def < li->last_use)) { + li->should_save = true; + + // Need to spill/fill around this call + if (!saveAcrossCall) { + li->first_acrossed_call = call->id; + saveAcrossCall = true; + } + } + } + + if (li->regtype == kRegTyInt) { + if (saveAcrossCall) { + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "\t\tlive interval crosses a call\n"; + } + if (regno == 0) { + if (li->IsInCatch() == false && li->IsAllInCleanupOrFirstBB() == false && int_callee_reg_set.size() != 0) { + // call in live interval, use callee if available + regno = GetRegFromSet(int_callee_reg_set, R0, li); + // Since it is callee saved, no need to continue search + li->should_save = false; + } else if (li->multi_use_in_bb) { + // allocate caller save if there are multiple uses in one bb + // else it is no different from spilling + if (int_caller_reg_set.size() != 0) { + regno = GetRegFromSet(int_caller_reg_set, R0, li); + } else if (int_param_reg_set.size() != 0) { + regno = GetRegFromSet(int_param_reg_set, R0, li); + } + } + } + if (regno == 0) { + // No register left for allocation + regno = FillInHole(li); + if (regno == 0) { + li->should_save = false; + } + } + return regno; + } else { + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "\t\tlive interval does not cross a call\n"; + } + regno = AssignSpecialPhysRegPattern(insn, li); + if (regno) { + return regno; + } + if (int_param_reg_set.size() != 0) { + regno = GetRegFromSet(int_param_reg_set, R0, li); + } + if (regno == 0) { + if (int_caller_reg_set.size() != 0) { + regno = GetRegFromSet(int_caller_reg_set, R0, li); + } else if (int_callee_reg_set.size() != 0) { + regno = GetRegFromSet(int_callee_reg_set, R0, li); + } else { + regno = FillInHole(li); + } + } + return regno; + } + } else if (li->regtype == kRegTyFloat) { + if (saveAcrossCall) { + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "\t\tlive interval crosses a call\n"; + } + if (regno == 0) { + if (li->IsInCatch() == false && li->IsAllInCleanupOrFirstBB() == false && fp_callee_reg_set.size() != 0) { + // call in live interval, use callee if available + regno = GetRegFromSet(fp_callee_reg_set, V0, li); + // Since it is callee saved, no need to continue search + li->should_save = false; + } else if (li->multi_use_in_bb) { + // allocate caller save if there are multiple uses in one bb + // else it is no different from spilling + if (fp_caller_reg_set.size() != 0 && li->multi_use_in_bb == true) { + regno = GetRegFromSet(fp_caller_reg_set, V0, li); + } else if (fp_param_reg_set.size() != 0) { + regno = GetRegFromSet(fp_param_reg_set, V0, li); + } + } + } + if (regno == 0) { + // No register left for allocation + regno = FillInHole(li); + if (regno == 0) { + li->should_save = false; + } + } + return regno; + } else { + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "\t\tlive interval does not cross a call\n"; + } + if (fp_param_reg_set.size() != 0) { + regno = GetRegFromSet(fp_param_reg_set, V0, li); + } + if (regno == 0) { + if (fp_caller_reg_set.size() != 0) { + regno = GetRegFromSet(fp_caller_reg_set, V0, li); + } else if (fp_callee_reg_set.size() != 0) { + regno = GetRegFromSet(fp_callee_reg_set, V0, li); + } else { + regno = FillInHole(li); + } + } + return regno; + } + } + + return regno; +} + +// Spill and reload for caller saved registers. +void LSRALinearScanRegAllocator::InsertCallerSave(Insn *insn, Operand *opnd, bool isDef) { + RegOperand *regOpnd = static_cast(opnd); + uint32 vregno = regOpnd->GetRegisterNumber(); + CHECK_FATAL(vregno < LI_.size(), "index out of range in LSRALinearScanRegAllocator::InsertCallerSave"); + LiveInterval *rli = LI_[vregno]; + RegType regtype = regOpnd->GetRegisterType(); + + is_spill_zero = false; + if (isDef == false) { + uint32 mask; + uint32 regbase; + if (regtype == kRegTyInt) { + mask = int_bb_def_mask; + regbase = R0; + // printf("InsertCallerSave int 0x%x\n", mask); + } else { + mask = fp_bb_def_mask; + regbase = V0; + // printf("InsertCallerSave fp 0x%x\n", mask); + } + // LogInfo::MapleLogger() << "assigned_reg " << rli->assigned_reg << "\n"; + if (mask & (1 << (rli->assigned_reg - regbase))) { + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "InsertCallerSave " << rli->assigned_reg << " skipping due to local def\n"; + } + return; + } + } + + if (!rli->should_save) { + return; + } + + uint32 regsize = regOpnd->GetSize(); + PrimType stype; + + if (regtype == kRegTyInt) { + stype = (regsize <= 32) ? PTY_i32 : PTY_i64; + int_bb_def_mask |= (1 << (rli->assigned_reg - R0)); + // printf("int_bb_def_mask set %d 0x%x\n", rli->assigned_reg-R0, int_bb_def_mask); + } else { + CG_ASSERT(regsize != 128, "NYI"); + stype = (regsize <= 32) ? PTY_f32 : PTY_f64; + fp_bb_def_mask |= (1 << (rli->assigned_reg - V0)); + // printf("fp_bb_def_mask set %d 0x%x\n", rli->assigned_reg-V0, fp_bb_def_mask); + } + + if (use_localvar_spill == false && UseSimdForSpill(insn, opnd, isDef, 0)) { + return; + } + + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "InsertCallerSave " << vregno << "\n"; + } + + if (isDef == false && rli->is_caller_spilled == false) { + LogInfo::MapleLogger() << "WARNING: " << vregno << " caller restore without spill in bb " << insn->bb->id << " : " + << cgfunc_->GetName() << "\n"; + } + rli->is_caller_spilled = true; + + if (isDef) { + MOperator opcode = insn->GetMachineOpcode(); + if (opcode == MOP_xmovri64) { + Operand *opnd1 = insn->GetOperand(1); + Riscv64ImmOperand *imm = static_cast(opnd1); + if (imm->IsZero()) { + is_spill_zero = true; + } + } else if (opcode == MOP_wmovrr || opcode == MOP_xmovrr) { + RegOperand *opnd1 = static_cast(insn->GetOperand(1)); + if (opnd1 && opnd1->IsZeroRegister()) { + is_spill_zero = true; + } + } + if (is_spill_zero) { + // This has to be a caller register + int_bb_def_mask &= ~(1 << (rli->assigned_reg - R0)); + } + } + + Riscv64CGFunc *a64cgfunc = static_cast(cgfunc_); + CG *cg = a64cgfunc->cg; + MemOperand *memopnd = nullptr; + RegOperand *phyopnd = nullptr; + + if (is_spill_zero) { + phyopnd = Riscv64RegOperand::GetZeroRegister(regsize); + } else { + phyopnd = a64cgfunc->GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)rli->assigned_reg, regsize, regtype); + } + + std::string comment; + uint8 isOutOfRange = 0; + if (isDef) { + memopnd = GetSpillMem(vregno, insn, (Riscv64reg_t)(int_spill_reg_set[0] + R0), isOutOfRange); + Insn *stInsn = cg->BuildInstruction(a64cgfunc->PickStInsn(regsize, stype), phyopnd, memopnd); + stInsn->SetSpillOp(); + comment = " SPILL for caller_save " + std::to_string(vregno); + caller_save_spill_count++; + if (rli->last_use == insn->id) { + if (LI_[vregno]->IsLocalRefVar() == false) { + a64cgfunc->FreeSpillRegMem(vregno); + } + comment += " end"; + } + if (use_localvar_spill) { + comment += " LocalVarSpill"; + } + stInsn->AddComment(comment); + if (isOutOfRange) { + insn->bb->InsertInsnAfter(insn->next, stInsn); + } else { + insn->bb->InsertInsnAfter(insn, stInsn); + } + } else { + memopnd = GetSpillMem(vregno, insn, (Riscv64reg_t)(int_spill_reg_set[0] + R0), isOutOfRange); + Insn *ldInsn = cg->BuildInstruction(a64cgfunc->PickLdInsn(regsize, stype), phyopnd, memopnd); + ldInsn->SetSpillOp(); + comment = " RELOAD for caller_save " + std::to_string(vregno); + caller_save_reload_count++; + if (rli->last_use == insn->id) { + if (LI_[vregno]->IsLocalRefVar() == false) { + a64cgfunc->FreeSpillRegMem(vregno); + } + comment += " end"; + } + if (use_localvar_spill) { + comment += " LocalVarReload"; + } + ldInsn->AddComment(comment); + insn->bb->InsertInsnBefore(insn, ldInsn); + } + return; +} + +// Shell function to find a physical register for an operand. +RegOperand *LSRALinearScanRegAllocator::AssignPhysRegs(Operand *opnd, Insn *insn) { + RegOperand *regOpnd = static_cast(opnd); + uint32 vregno = regOpnd->GetRegisterNumber(); + RegType regtype = regOpnd->GetRegisterType(); + CHECK_FATAL(vregno < LI_.size(), "index out of range in LSRALinearScanRegAllocator::AssignPhysRegs"); + LiveInterval *li = LI_[vregno]; + + bool doNotSpill = false; + if (li->must_allocate || (insn->mop_ == MOP_adrp_ldr && insn->next && insn->next->mop_ == MOP_clinit_tail) || + (insn->mop_ == MOP_clinit_tail)) { + // Cannot spill for clinit pair + doNotSpill = true; + } else if (spill_all) { + return nullptr; + } else if (IN_SPILL_RANGE) { + return nullptr; + } + + if (doNotSpill) { + li->must_allocate = true; + } + + // if only def, no use, then should assign a new phyreg, + // otherwise, there may be conflict + if (li->assigned_reg != 0 && (li->last_use != 0 || li->phys_use != 0)) { + if (Riscv64Abi::IsCalleeSavedReg((Riscv64reg_t)li->assigned_reg)) { + callee_use_cnt[li->assigned_reg]++; + } + if (li->stk_slot == -1) { + CG_ASSERT(opnd->GetSize() != 128, "NYI"); + return static_cast(cgfunc_)->GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)(li->assigned_reg), + opnd->GetSize(), regtype); + } else { + // need to reload + return nullptr; + } + } + + // pre spilled: + if (li->stk_slot != -1) { + return nullptr; + } + + if (LSRA_DUMP) { + uint32 activeSz = active.size(); + LogInfo::MapleLogger() << "\tAssignPhysRegs-active_sz " << activeSz << "\n"; + } + + uint32 regno = FindAvailablePhyReg(li, insn); + if (regno != 0) { + if (Riscv64Abi::IsCalleeSavedReg((Riscv64reg_t)regno)) { + if (!CGOptions::doCalleeToSpill) { + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "\tCallee-save register for save/restore in prologue/epilogue: " << regno << "\n"; + } + static_cast(cgfunc_)->AddtoCalleeSaved((Riscv64reg_t)regno); + } + callee_use_cnt[regno]++; + } + CG_ASSERT(opnd->GetSize() != 128, "NYI"); + return static_cast(cgfunc_)->GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)(li->assigned_reg), + opnd->GetSize(), regtype); + } + + return nullptr; +} + +MemOperand *LSRALinearScanRegAllocator::GetSpillMem(uint32 vregno, Insn *insn, Riscv64reg_t regno, + uint8 &isOutOfRange) { + Riscv64CGFunc *a64cgfunc = static_cast(cgfunc_); + MemOperand *memopnd = nullptr; + if (use_localvar_spill) { + memopnd = a64cgfunc->GetOrCreatSpillMem(vregno, LI_[vregno]->localrefvar_offset); + } else { + memopnd = a64cgfunc->GetOrCreatSpillMem(vregno); + } + return (a64cgfunc->AdjustMemOperandIfOffsetOutOfRange(memopnd, vregno, insn, regno, isOutOfRange)); +} + +// Set a vreg in live interval as being marked for spill. +void LSRALinearScanRegAllocator::SetOperandSpill(Operand *opnd) { + RegOperand *regOpnd = static_cast(opnd); + uint32 regno = regOpnd->GetRegisterNumber(); + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "SetOperandSpill " << regno; + LogInfo::MapleLogger() << "(" << LI_[regno]->first_acrossed_call; + LogInfo::MapleLogger() << ", ref_count " << LI_[regno]->ref_count << ")\n"; + } + + CG_ASSERT(regno < LI_.size(), "index out of vector size in LSRALinearScanRegAllocator::SetOperandSpill"); + LiveInterval *li = LI_[regno]; + li->stk_slot = SPILLED; + return; +} + +// See if there are available fp(simd) register so instead of a spill that +// a move to/from a simd register is generated. +bool LSRALinearScanRegAllocator::UseSimdForSpill(Insn *insn, Operand *opnd, bool isDef, uint32 spillIdx) { + is_spill_zero = false; + + if (CGOptions::lsraSimdMode == 2) { + return false; + } + + RegOperand *regOpnd = static_cast(opnd); + RegType regtype = regOpnd->GetRegisterType(); + if (regtype != kRegTyInt) { + return false; + } + + // See if a simd has already been allocated for spill + uint32 regno = regOpnd->GetRegisterNumber(); + // LogInfo::MapleLogger() << "UseSimdForSpill regno " << regno << "\n"; + LiveInterval *li = LI_[regno]; + + /* If it is a catch bb or cleanup bb, then do not use simd + * for spill, since that might incur overhead in prolog/epilog + * for save/restore. + */ + if (li->IsInCatch() || li->IsAllInCleanupOrFirstBB()) { + return false; + } + + if (li->assigned_reg && li->is_simd_spilled == false) { + // This reg has been spilled, but by whom? + if (li->should_save == false) { + return false; + } else if (li->is_caller_spilled) { + return false; + } + } + + regno_t simd; + SimdSlot slot; + uint32 regsize; + if (li->simd_spill_reg) { + // Is spilled by simd + simd = li->simd_spill_reg; + slot = li->simd_slot; + if (slot == kRegSlotNone) { + regsize = 64; + } else { + regsize = 32; + } + } else { +#undef SIMD_DEBUG +#ifdef SIMD_DEBUG + static int count = 1; + int limit = 5; // 4 pass 5 fail 20 total +#define SIMD_DEBUG_MACRO \ + { \ + if (cgfunc_->GetName().find("Lsun_2Fmisc_2FFloatingDecimal_24BinaryToASCIIBuffer_3B_7Cdtoa_7C_28IJIZ_29V") != \ + string::npos) { \ + LogInfo::MapleLogger() << "Do " << count << " " << cgfunc_->GetName() << "\n"; \ + if (count > limit) \ + return false; \ + count++; \ + } \ + } + +#else // SIMD_DEBUG +#define SIMD_DEBUG_MACRO ; +#endif // SIMD_DEBUG + regsize = regOpnd->GetSize(); + if (CGOptions::lsraSimdMode == 0 || regsize == 64) { + if (simd_spill_regs.empty()) { + // LogInfo::MapleLogger() << "\tsimd regs not available\n"; + return false; + } + SIMD_DEBUG_MACRO; + // Look for available 64bit simd reg to spill int reg + MapleSet::iterator it = simd_spill_regs.begin(); + simd = static_cast(*it); + simd_spill_regs.erase(it); + simd_spill_0.erase(simd); + simd_spill_1.erase(simd); + // For 64 bit spill, do not set vector mode for operand + slot = kRegSlotNone; + regsize = 64; + } else { + bool useSlot0 = false; + if ((insn->id - last_simd_insn_num) > 5) { + if (simd_spill_0.size() >= simd_spill_1.size()) { + useSlot0 = true; + } + } else { + // There are some penalty associated with using the same simd + // reg but different slot. Try to separate them. + if (last_simd_slot == 1) { + useSlot0 = true; + } + } + if (useSlot0) { + // look for 32bit from slot 0 + if (simd_spill_0.empty()) { + // LogInfo::MapleLogger() << "\tsimd regs not available\n"; + return false; + } + SIMD_DEBUG_MACRO; + MapleSet::iterator it = simd_spill_0.begin(); + simd = static_cast(*it); + simd_spill_0.erase(simd); + simd_spill_regs.erase(simd); + slot = kRegSlot0; + } else { + if (simd_spill_1.empty()) { + // LogInfo::MapleLogger() << "\tsimd regs not available\n"; + return false; + } + SIMD_DEBUG_MACRO; + // look for 32bit from slot 1 + MapleSet::iterator it = simd_spill_1.begin(); + simd = static_cast(*it); + simd_spill_1.erase(simd); + simd_spill_regs.erase(simd); + slot = kRegSlot1; + } + } + } + + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "InsertSpillReload using simd " << regno << " with simd reg " << simd << "\n"; + } + + static_cast(cgfunc_)->AddtoCalleeSaved((Riscv64reg_t)simd); + + Riscv64CGFunc *a64cgfunc = static_cast(cgfunc_); + CG *cg = a64cgfunc->cg; + + regno_t spreg; + li->is_simd_spilled = true; + if (li->should_save) { + // caller save + spreg = li->assigned_reg; + } else { + CG_ASSERT((spillIdx < max_int_spill), "UseSimdForSpill: ran out int spill reg"); + spreg = int_spill_reg_set[spillIdx] + R0; + li->assigned_reg = spreg; + } + + if (isDef) { + MOperator opcode = insn->GetMachineOpcode(); + if (opcode == MOP_xmovri64) { + Operand *opnd1 = insn->GetOperand(1); + Riscv64ImmOperand *imm = static_cast(opnd1); + if (imm->IsZero()) { + spreg = RZERO; + is_spill_zero = true; + } + } else if (opcode == MOP_wmovrr || opcode == MOP_xmovrr) { + RegOperand *opnd1 = static_cast(insn->GetOperand(1)); + if (opnd1 && opnd1->IsZeroRegister()) { + spreg = RZERO; + is_spill_zero = true; + } + } + if (is_spill_zero && li->assigned_reg >= R0 && li->assigned_reg < R16) { + /* The zero register opt is removing the definition of the assigned reg + * so the caller register must be regenerated in the same bb. + */ + int_bb_def_mask &= ~(1 << (li->assigned_reg - R0)); + } + } + + Riscv64RegOperand *fopnd = nullptr; + RegOperand *iopnd; + CG_ASSERT(regsize != 128, "NYI"); + iopnd = a64cgfunc->GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)spreg, regsize, kRegTyInt); + if (slot == kRegSlotNone) { + fopnd = a64cgfunc->GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)simd, regsize, kRegTyFloat); + } else { + regno_t renameSimd = simd - V0; + // To distinguish upper/lower part and regular fp, use an alias + if (slot == kRegSlot0) { + renameSimd += VB32; // add v# base, see riscv64_fp_simd_regs.def + } else if (slot == kRegSlot1) { + renameSimd += VB64; // add v# base, see riscv64_fp_simd_regs.def + } + // Can only be single here + fopnd = a64cgfunc->GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)renameSimd, regsize, kRegTyFloat, 0 /*flag*/, + kVecSingle, static_cast(slot)); + fopnd->SetSimdVectorType(kVecSingle); + fopnd->SetSimdVectorPosition(slot); + } + + if (isDef) { + is_mov_dst_simd_spilled = true; + } else { + is_mov_src_simd_spilled = true; + } + + Insn *mov = nullptr; + if (isDef) { + li->stk_slot = SPILLED; + simd_spill_count++; + if (regsize <= 32) { + mov = cg->BuildInstruction(MOP_xvmovsr, fopnd, iopnd); + } else { + mov = cg->BuildInstruction(MOP_xvmovdr, fopnd, iopnd); + } + std::string comment = " FMOV to simd " + std::to_string(regno); + if (li->should_save) { + comment += " caller"; + } + if (li->last_use == insn->id) { + simd_reg_reclaim[simd_reg_reclaim_idx] = simd; + simd_reg_reclaim_slot[simd_reg_reclaim_idx] = slot; + simd_reg_reclaim_idx++; + comment += " end"; + } + li->simd_spill_reg = simd; + li->simd_slot = slot; + mov->AddComment(comment); + insn->bb->InsertInsnAfter(insn, mov); + return true; + } else { + if (li->stk_slot == -1) { + LogInfo::MapleLogger() << "WARNING: " << regno << " simd restore without spill in" << cgfunc_->GetName() << "\n"; + } + simd_reload_count++; + if (regsize <= 32) { + mov = cg->BuildInstruction(MOP_xvmovrs, iopnd, fopnd); + } else { + mov = cg->BuildInstruction(MOP_xvmovrd, iopnd, fopnd); + } + std::string comment = " FMOV from simd " + std::to_string(regno); + if (li->should_save) { + comment += " caller"; + } + if (li->last_use == insn->id) { + simd_reg_reclaim[simd_reg_reclaim_idx] = simd; + simd_reg_reclaim_slot[simd_reg_reclaim_idx] = slot; + simd_reg_reclaim_idx++; + comment += " end"; + } + li->simd_spill_reg = simd; + li->simd_slot = slot; + mov->AddComment(comment); + insn->bb->InsertInsnBefore(insn, mov); + return true; + } +} + +// Generate spill/reload for an operand. +// spill_idx : one of 3 phys regs set aside for the purpose of spills. +void LSRALinearScanRegAllocator::SpillOperand(Insn *insn, Operand *opnd, bool isDef, uint32 spillIdx) { + if (use_localvar_spill == false && UseSimdForSpill(insn, opnd, isDef, spillIdx)) { + return; + } + + RegOperand *regOpnd = static_cast(opnd); + uint32 regno = regOpnd->GetRegisterNumber(); + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "InsertSpillReload " << regno << "\n"; + } + + is_spill_zero = false; + + regno_t spreg; + PrimType stype; + CHECK_FATAL(regno < LI_.size(), "index out of range in LSRALinearScanRegAllocator::SpillOperand"); + LiveInterval *li = LI_[regno]; + CG_ASSERT(li->should_save == false, "SpillOperand: Should not be caller"); + uint32 regsize = regOpnd->GetSize(); + Riscv64CGFunc *a64cgfunc = static_cast(cgfunc_); + CG *cg = a64cgfunc->cg; + RegType regtype = regOpnd->GetRegisterType(); + + if (isDef) { + MOperator opcode = insn->GetMachineOpcode(); + if (opcode == MOP_xmovri64) { + Operand *opnd1 = insn->GetOperand(1); + Riscv64ImmOperand *imm = static_cast(opnd1); + if (imm->IsZero()) { + is_spill_zero = true; + } + } else if (opcode == MOP_wmovrr || opcode == MOP_xmovrr) { + RegOperand *opnd1 = static_cast(insn->GetOperand(1)); + if (opnd1 && opnd1->IsZeroRegister()) { + is_spill_zero = true; + } + } + } + + if (li->regtype == kRegTyInt) { + CG_ASSERT((spillIdx < max_int_spill), "SpillOperand: ran out int spill reg"); + spreg = int_spill_reg_set[spillIdx] + R0; + stype = (regsize <= 32) ? PTY_i32 : PTY_i64; + } else { + CG_ASSERT((li->regtype == kRegTyFloat), "SpillOperand: Should be float type"); + CG_ASSERT((spillIdx < MAX_FP_SPILL), "SpillOperand: ran out fp spill reg"); + spreg = fp_spill_reg_set[spillIdx] + V0; + stype = (regsize <= 32) ? PTY_f32 : PTY_f64; + } + + uint8 isOutOfRange = 0; + RegOperand *phyopnd = nullptr; + if (is_spill_zero) { + phyopnd = Riscv64RegOperand::GetZeroRegister(regsize); + } else { + CG_ASSERT(regsize != 128, "NYI"); + phyopnd = a64cgfunc->GetOrCreatePhysicalRegisterOperand((Riscv64reg_t)spreg, regsize, regtype); + } + li->assigned_reg = phyopnd->GetRegisterNumber(); + + MemOperand *memopnd = nullptr; + if (isDef) { + // Need to assign spreg (one of the two spill reg) to the destination of the insn. + // spill_vreg <- opn1 op opn2 + // to + // spreg <- opn1 op opn2 + // store spreg -> spillmem + li->stk_slot = SPILLED; + + spill_count++; + memopnd = GetSpillMem(regno, insn, (Riscv64reg_t)(int_spill_reg_set[spillIdx + 1] + R0), isOutOfRange); + Insn *stInsn = cg->BuildInstruction(a64cgfunc->PickStInsn(regsize, stype), phyopnd, memopnd); + stInsn->SetSpillOp(); + std::string comment = " SPILL vreg:" + std::to_string(regno); + if (li->last_use == insn->id) { + if (LI_[regno]->IsLocalRefVar() == false) { + a64cgfunc->FreeSpillRegMem(regno); + } + comment += " end"; + } + if (use_localvar_spill) { + comment += " LocalVarSpill"; + } + stInsn->AddComment(comment); + if (isOutOfRange) { + insn->bb->InsertInsnAfter(insn->next, stInsn); + } else { + insn->bb->InsertInsnAfter(insn, stInsn); + } + return; + } else { + // Here, reverse of isDef, change either opn1 or opn2 to the spreg. + // CG_ASSERT((li->stk_slot != -1)&&"SpillOperand: should have been spilled"); + if (li->stk_slot == -1) { + LogInfo::MapleLogger() << "WARNING: " << regno << " assigned " << li->assigned_reg << " restore without spill in bb " + << insn->bb->id << " : " << cgfunc_->GetName() << "\n"; + } + reload_count++; + memopnd = GetSpillMem(regno, insn, (Riscv64reg_t)(int_spill_reg_set[spillIdx] + R0), isOutOfRange); + Insn *ldInsn = cg->BuildInstruction(a64cgfunc->PickLdInsn(regsize, stype), phyopnd, memopnd); + ldInsn->SetSpillOp(); + std::string comment = " RELOAD vreg" + std::to_string(regno); + if (li->last_use == insn->id) { + if (LI_[regno]->IsLocalRefVar() == false) { + a64cgfunc->FreeSpillRegMem(regno); + } + comment += " end"; + } + if (use_localvar_spill) { + comment += " LocalVarReload"; + } + ldInsn->AddComment(comment); + insn->bb->InsertInsnBefore(insn, ldInsn); + return; + } +} + +RegOperand *LSRALinearScanRegAllocator::HandleSpillForInsn(Insn *insn, Operand *opnd) { + // choose the lowest priority li to spill + RegOperand *regOpnd = static_cast(opnd); + uint32 regno = regOpnd->GetRegisterNumber(); + CG_ASSERT(regno < LI_.size(), "index out of range of MapleVector in LSRALinearScanRegAllocator::HandleSpillForInsn"); + LiveInterval *li = LI_[regno]; + RegType regtype = regOpnd->GetRegisterType(); + LiveInterval *spillLi = nullptr; + FindLowestPrioInActive(&spillLi, regtype, true); + + // compare spill_li with current li + // spill_li is null and li->stk_slot == Spilled when the li is spilled due to LiveIntervalAnalysis + if (!spillLi || spillLi->li_parent || spillLi->li_child || li->stk_slot == SPILLED || li->first_def != insn->id || + li->priority < spillLi->priority || li->ref_count < spillLi->ref_count || + !(Riscv64Abi::IsCalleeSavedReg((Riscv64reg_t)(spillLi->assigned_reg)))) { + // spill current li + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "Flexible Spill: still spill " << li->regno << ".\n"; + } + SetOperandSpill(opnd); + return nullptr; + } + + ReturnPregToSet(spillLi, spillLi->assigned_reg); + RegOperand *newOpnd = AssignPhysRegs(opnd, insn); + if (!newOpnd) { + ReleasePregToset(spillLi, spillLi->assigned_reg); + SetOperandSpill(opnd); + return nullptr; + } + + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "Flexible Spill: " << spillLi->regno << " instead of " << li->regno << ".\n"; + PrintLiveInterval(spillLi, "TO spill: "); + PrintLiveInterval(li, "Instead of: "); + } + + // spill this live interval + active.erase(it_finded); + spillLi->stk_slot = SPILLED; + + return newOpnd; +} + +bool LSRALinearScanRegAllocator::OpndNeedAllocation(Insn *insn, Operand *opnd, bool isdef, uint32 insnNum) { + if (!opnd->IsRegister()) { + return false; + } + RegOperand *regOpnd = static_cast(opnd); + RegType regtype = regOpnd->GetRegisterType(); + uint32 regno = regOpnd->GetRegisterNumber(); + if (regtype == kRegTyCc || regtype == kRegTyVary) { + return false; + } + if (IsUntouchableReg(regno) || regOpnd->IsConstReg()) { + return false; + } + if (regOpnd->IsPhysicalRegister()) { + if ((insn->mop_ == MOP_adrp_ldr && insn->next && insn->next->mop_ == MOP_clinit_tail) || + (insn->mop_ == MOP_clinit_tail)) { + // Cannot spill for clinit pair + } else if (spill_all) { + return false; + } + if (isdef) { + if (regtype == kRegTyInt) { + if (regno < kFirstIntParamReg && regno > kLastIntParamReg) { + return false; + } + if (int_param_queue[regno - kFirstIntParamReg].empty() == true) { + return false; + } + LiveInterval *li = int_param_queue[regno - kFirstIntParamReg].front(); + // li may have been inserted by InsertParamToActive + if (li->first_def == insnNum) { + int_param_reg_set.erase(regno - R0); + active.insert(li); + CG_ASSERT((regno - kFirstIntParamReg) < int_param_queue.size(), + "index out of range in LSRALinearScanRegAllocator::OpndNeedAllocation"); + int_param_queue[regno - R0].pop_front(); + } + } else { + if (regno < kFirstFpParamReg && regno > kLastFpParamReg) { + return false; + } + if (fp_param_queue[regno - kFirstFpParamReg].empty() == true) { + return false; + } + LiveInterval *li = fp_param_queue[regno - kFirstFpParamReg].front(); + // li may have been inserted by InsertParamToActive + if (li->first_def == insnNum) { + fp_param_reg_set.erase(regno - V0); + active.insert(li); + fp_param_queue[regno - V10].pop_front(); + } + } + } + return false; + } + // This is a virtual register + return true; +} + +void LSRALinearScanRegAllocator::InsertParamToActive(Operand *opnd, uint32 insnNum) { + RegOperand *regOpnd = static_cast(opnd); + uint32 regno = regOpnd->GetRegisterNumber(); + CHECK_FATAL(regno < LI_.size(), "index out of range in LSRALinearScanRegAllocator::InsertParamToActive"); + LiveInterval *li = LI_[regno]; + // Search for parameter registers that is in the live range to insert into queue + if (li->regtype == kRegTyInt) { + for (uint32 i = 0; i < int_param_queue.size(); i++) { + if (int_param_queue[i].empty()) { + continue; + } + LiveInterval *pli = int_param_queue[i].front(); + do { + if ((pli->first_def <= li->first_def) && (pli->phys_use <= li->first_def)) { + // just discard it + int_param_queue[i].pop_front(); + if (int_param_queue[i].empty()) { + break; + } + pli = int_param_queue[i].front(); + } else { + break; + } + } while (true); + if ((pli->first_def < li->last_use) && (pli->phys_use > li->first_def)) { + if (int_param_reg_set.find(i + kFirstIntParamEnum) != int_param_reg_set.end()) { + // reserve this param register and active the its first use + last_int_param_li[i] = pli; + int_param_reg_set.erase(i + kFirstIntParamEnum); + int_param_queue[i].pop_front(); + } + } + } + } else { + CG_ASSERT((li->regtype == kRegTyFloat), "InsertParamToActive: Incorrect register type"); + for (uint32 i = 0; i < fp_param_queue.size(); i++) { + if (fp_param_queue[i].empty()) { + continue; + } + LiveInterval *pli = fp_param_queue[i].front(); + do { + if ((pli->first_def <= li->first_def) && (pli->phys_use <= li->first_def)) { + // just discard it + fp_param_queue[i].pop_front(); + if (fp_param_queue[i].empty()) { + break; + } + pli = fp_param_queue[i].front(); + } else { + break; + } + } while (true); + if ((pli->first_def < li->last_use) && (pli->phys_use > li->first_def)) { + if (fp_param_reg_set.find(i + kFirstFpParamEnum) != fp_param_reg_set.end()) { + last_fp_param_li[i] = pli; + fp_param_reg_set.erase(i + kFirstFpParamEnum); + fp_param_queue[i].pop_front(); + } + } + } + } +} + +// Insert a live interval into the 'active' list. +void LSRALinearScanRegAllocator::InsertToActive(Operand *opnd, uint32 insnNum) { + RegOperand *regOpnd = static_cast(opnd); + uint32 regno = regOpnd->GetRegisterNumber(); + CHECK_FATAL(regno < LI_.size(), "index out of range in LSRALinearScanRegAllocator::InsertToActive"); + LiveInterval *li = LI_[regno]; + if (li->last_use <= insnNum) { + // insert first, and retire later, then the assigned reg can be released + active.insert(li); + if (LSRA_DUMP) { + PrintLiveInterval(li, "LiveInterval is skip due to past insn num --- opt to remove redunant insn"); + } + return; + } + active.insert(li); +} + +// find the lowest one and erase it from active +void LSRALinearScanRegAllocator::FindLowestPrioInActive(LiveInterval **targetLi, RegType regtype, bool startRa) { + float lowestPrio = 100.0; + bool found = false; + MapleSet::iterator it; + MapleSet::iterator lowestIt; + for (it = active.begin(); it != active.end(); it++) { + LiveInterval *li = static_cast(*it); + if (startRa && li->phys_use != 0) { + continue; + } + if (li->priority < lowestPrio && li->regtype == regtype) { + lowestPrio = li->priority; + lowestIt = it; + found = true; + } + } + if (found) { + *targetLi = *lowestIt; + it_finded = lowestIt; + } + return; +} + +// Calculate the weight of a live interval for pre-spill and flexible spill +void LSRALinearScanRegAllocator::LiveIntervalAnalysis() { + for (uint32_t bbIdx = 0; bbIdx < sorted_bbs.size(); bbIdx++) { + BB *bb = sorted_bbs[bbIdx]; + + // 1. calculate live interfere + FOR_BB_INSNS(insn, bb) { + if (insn->IsImmaterialInsn()) { + continue; + } + if (!insn->IsMachineInstruction()) { + continue; + } + if (insn->id == 0) { + // New instruction inserted by reg alloc (ie spill) + continue; + } + + // simple retire from active + MapleSet::iterator it; + for (it = active.begin(); it != active.end(); /* erase will update */) { + LiveInterval *li = static_cast(*it); + if (li->last_use > insn->id) { + break; + } + it = active.erase(it); + } + + // simple insert to active + const Riscv64MD *md = &Riscv64CG::kMd[static_cast(insn)->mop_]; + for (int32_t i = 0; i < Insn::kMaxOperandNum; i++) { + Operand *opnd = insn->GetOperand(i); + if (!opnd) { + continue; + } + + bool isdef = static_cast(md->operand_[i])->IsRegDef(); + if (isdef) { + RegOperand *regOpnd = static_cast(opnd); + if (regOpnd->IsVirtualRegister() && regOpnd->GetRegisterType() != kRegTyCc) { + uint32 regno = regOpnd->GetRegisterNumber(); + LiveInterval *li = LI_[regno]; + if (li->first_def == insn->id) { + active.insert(li); + } + } + } + } + + // get interfere info + uint32 interNum = active.size(); + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "In insn " << insn->id << ", " << interNum << " overlap live intervals.\n"; + } + + // 2. analysis which to spill + while (interNum > CGOptions::overlapNum) { + LiveInterval *lowestLi = nullptr; + FindLowestPrioInActive(&lowestLi); + if (lowestLi) { + if (LSRA_DUMP) { + PrintLiveInterval(lowestLi, "Pre spilled: "); + } + lowestLi->stk_slot = SPILLED; + active.erase(it_finded); + interNum = active.size(); + } else { + break; + } + } + } + } + + active.clear(); +} + +// Iterate through the operands of an instruction for allocation. +void LSRALinearScanRegAllocator::AssignPhysRegsForInsn(Insn *insn) { + const Riscv64MD *md = &Riscv64CG::kMd[static_cast(insn)->mop_]; + + // At the beginning of the landing pad, we handle the x1, x2 as if they are implicitly defined. + if (insn->bb->eh_preds.size() != 0 && insn == insn->bb->firstinsn) { + if (!int_param_queue[0].empty()) { + LiveInterval *li = int_param_queue[0].front(); + if (li->first_def == insn->id) { + int_param_reg_set.erase(li->assigned_reg - R0); + active.insert(li); + int_param_queue[0].pop_front(); + } + } + + if (!int_param_queue[1].empty()) { + LiveInterval *li = int_param_queue[1].front(); + if (li->first_def == insn->id) { + int_param_reg_set.erase(li->assigned_reg - R0); + active.insert(li); + int_param_queue[1].pop_front(); + } + } + } + + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "active in " << insn->id << " :"; + PrintActiveListSimple(); + } + for (int32_t i = 0; i < Insn::kMaxOperandNum; i++) { + Operand *opnd = insn->GetOperand(i); + if (!opnd) { + continue; + } + bool isdef = static_cast(md->operand_[i])->IsRegDef(); + RegOperand *newOpnd = nullptr; + if (opnd->IsList()) { + // For arm32, not arm64 + } else if (opnd->IsMemoryAccessOperand()) { + MemOperand *memopnd = static_cast(opnd); + Operand *base = memopnd->GetBaseRegister(); + isdef = false; + if (base != nullptr) { + if (OpndNeedAllocation(insn, base, isdef, insn->id)) { + newOpnd = AssignPhysRegs(base, insn); + if (!newOpnd) { + SetOperandSpill(base); + } + // add CG_ASSERT here. + // memopnd->SetBaseRegister(NewOpnd); + } + } + } else { + if (OpndNeedAllocation(insn, opnd, isdef, insn->id) == false) { + continue; + } + if (isdef && (fast_alloc == false)) { + InsertParamToActive(opnd, insn->id); + } + newOpnd = AssignPhysRegs(opnd, insn); + if (isdef != true && 0 /* check if active size change?*/) { + // Might want to warn here if use reg is not assigned a physical. + continue; + } + + if (newOpnd) { + if (isdef) { + InsertToActive(opnd, insn->id); + } + } else { + // If dest and both src are spilled, src will use both of the + // spill registers. + // dest can use any spill reg, choose 0 + if (isdef) { + newOpnd = HandleSpillForInsn(insn, opnd); + if (newOpnd) { + InsertToActive(opnd, insn->id); + } + } else { + SetOperandSpill(opnd); + } + } + } + } +} + +// Pattern matcher for a MCC_InitializeLocalStackRef to get the call parameter. +uint32 LSRALinearScanRegAllocator::FindLocalRefVarStackLoc(Insn *insn, uint32 param) { + // The caller already knows this insn is a call to "MCC_InitializeLocalStackRef". + // Assume parameters are in the same bb. + for (Insn *prev = insn->prev; prev; prev = prev->prev) { + Operand *dst = prev->GetOperand(0); + RegOperand *regopnd = static_cast(dst); + uint32 dstRegno = regopnd->GetRegisterNumber(); + if (dstRegno == param) { + Operand *src = nullptr; + if (prev->GetOpndNum() == 1) { + // move insn + src = prev->GetOpnd(0); + } else { + // add insn + src = prev->GetOpnd(1); + } + CG_ASSERT(src != nullptr, "src is null in LSRALinearScanRegAllocator::FindLocalRefVarStackLoc"); + if (src->IsRegister()) { + RegOperand *regsrc = static_cast(src); + return FindLocalRefVarStackLoc(prev, regsrc->GetRegisterNumber()); + } else { + CG_ASSERT(src->IsIntImmediate(), "FindLocalRefVarStackLoc not imm const"); + ImmOperand *imm = static_cast(src); + return static_cast(imm->GetValue()); + } + } + } + return 0; +} + +bool LSRALinearScanRegAllocator::DetectLocalRefVarInfo(Insn *insn, uint32 imm) { + if (imm < localrefvar_min_stack_loc || imm > localrefvar_max_stack_loc) { + return false; + } + if (!insn->IsStore()) { + return false; + } + + return true; +} + +/* To match a vreg to a localref var has several patterns. + * There might be more, but currently these are supported. + * case 1 + * mov Ry <- Rx // Match Ry + * str Rx -> [] // local ref var + * + * case 2 + * mov Ry <- 0 // Match Ry + * str R32 -> [] + * + * case 3 + * Rx <- R0 // Match Rx + * str Rx -> [] + * + * In each case, the matched reg is a candidate to be associated + * with the local ref var. + */ +regno_t LSRALinearScanRegAllocator::FindLocalRefVarReg(Insn *insn) { + CG_ASSERT((insn->IsStore() && (!insn->IsStorePair()) && (!insn->IsAtomic())), + "FindLocalRefVarReg: insn has to be a store"); + Insn *pinsn = insn->prev; + if (!pinsn) { + return 0; + } + // Check for matching size + Operand *iopnd = insn->GetOperand(0); + uint8 regsize = iopnd->GetSize(); + MOperator opcode = pinsn->GetMachineOpcode(); + if (regsize <= 32) { + if (opcode != MOP_wmovrr) { + return 0; + } + } else { + if (opcode != MOP_xmovrr && opcode != MOP_xmovri64) { + return 0; + } + } + + RegOperand *regOpnd = static_cast(iopnd); + Operand *psrc = pinsn->GetOperand(1); + if (opcode == MOP_xmovri64) { + ImmOperand *imm = static_cast(psrc); + if (imm == nullptr) { + return 0; + } + uint32 val = imm->GetValue(); + if (regOpnd->IsZeroRegister() && val == 0) { + Operand *dst = pinsn->GetOperand(0); + RegOperand *rdst = static_cast(dst); + // case 2 + if (!rdst->IsPhysicalRegister()) { + return rdst->GetRegisterNumber(); + } + } + } else { + // wmovrr or xmovrr + RegOperand *psrcOpnd = static_cast(psrc); + if (psrcOpnd->GetRegisterNumber() == R0) { + if (psrcOpnd->GetRegisterNumber() != regOpnd->GetRegisterNumber()) { + return 0; + } + // case 3 + RegOperand *pdstOpnd = static_cast(pinsn->GetOperand(0)); + if (!pdstOpnd->IsPhysicalRegister()) { + return pdstOpnd->GetRegisterNumber(); + } + } else if (psrcOpnd->GetRegisterNumber() == regOpnd->GetRegisterNumber()) { + // case 1 + RegOperand *pdst = static_cast(pinsn->GetOperand(0)); + if (!pdst->IsPhysicalRegister()) { + return pdst->GetRegisterNumber(); + } + } + } + return 0; +} + +// If a memory instruction is a localrefvar, mark it so it can be used +// for a spill/reload of operands accessing the same stack location. +void LSRALinearScanRegAllocator::MarkLocalRefVarForLiveInterval(Insn *insn, uint32 offset) { + if (!insn->IsStore()) { + return; + } + CG_ASSERT(insn->mop_ == MOP_xstr, "InvalidateLocalRefVarOffset: wrong store insn"); + + RegOperand *regOpnd = static_cast(insn->GetOperand(0)); + regno_t regno = FindLocalRefVarReg(insn); + if (regno == 0) { + if (!regOpnd->IsPhysicalRegister()) { + regno = regOpnd->GetRegisterNumber(); + LI_[regno]->SetLocalRefVarStateInvalid(); + uint32 idx = (offset - localrefvar_min_stack_loc) >> 3; + if (lvar_offset_regno_map[idx]) { + regno = lvar_offset_regno_map[idx]; + LI_[regno]->SetLocalRefVarStateInvalid(); + } else { + lvar_offset_regno_map[idx] = regno; + } + } + return; + } + + LiveInterval *li = LI_[regno]; + li->localrefvar_count++; + if (li->localrefvar_offset == 0) { + uint32 idx = (offset - localrefvar_min_stack_loc) >> 3; + if (lvar_offset_regno_map[idx]) { + // Another register mapped to this location, invalidate both registers + li->SetLocalRefVarStateInvalid(); + LI_[lvar_offset_regno_map[idx]]->SetLocalRefVarStateInvalid(); + return; + } + + lvar_offset_regno_map[idx] = regno; + li->SetLocalRefVarStateValid(); + li->localrefvar_offset = offset; + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "\t\tLocalVarRef set vreg " << regno << " imm " << offset << "\n"; + } + } else if (li->localrefvar_offset != offset) { + li->SetLocalRefVarStateInvalid(); + uint32 idx = (offset - localrefvar_min_stack_loc) >> 3; + if (lvar_offset_regno_map[idx]) { + LI_[lvar_offset_regno_map[idx]]->SetLocalRefVarStateInvalid(); + } else { + lvar_offset_regno_map[idx] = regno; + } + idx = (li->localrefvar_offset - localrefvar_min_stack_loc) >> 3; + if (lvar_offset_regno_map[idx]) { + LI_[lvar_offset_regno_map[idx]]->SetLocalRefVarStateInvalid(); + } else { + lvar_offset_regno_map[idx] = regno; + } + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "\t\tLocalVarRef unset vreg " << regno << " imm " << offset << "\n"; + } + } +} + +// Create an operand with physical register assigned, or a spill register +// in the case where a physical register cannot be assigned. +RegOperand *LSRALinearScanRegAllocator::GetReplaceOpnd(Insn *insn, Operand *opnd, uint32 &spillIdx, bool isdef) { + if (!opnd->IsRegister()) { + return nullptr; + } + RegOperand *regOpnd = static_cast(opnd); + + uint32 vregno = regOpnd->GetRegisterNumber(); + RegType regtype = regOpnd->GetRegisterType(); + if (regtype == kRegTyCc || regtype == kRegTyVary) { + return nullptr; + } + if (IsUntouchableReg(vregno) || regOpnd->IsConstReg()) { + return nullptr; + } + if (regOpnd->IsPhysicalRegister()) { + return nullptr; + } + + CG_ASSERT(vregno < LI_.size(), "index out of range of MapleVector in LSRALinearScanRegAllocator::GetReplaceOpnd"); + LiveInterval *li = LI_[vregno]; + + bool addCalleeToSaved = true; + regno_t regno = li->assigned_reg; + bool isCalleeReg = Riscv64Abi::IsCalleeSavedReg((Riscv64reg_t)regno); + if (CGOptions::doCalleeToSpill && + // prolog can use stp, so try to estimate if spill callee should be done. + ((should_opt_int_callee && li->regtype == kRegTyInt) || (should_opt_fp_callee && li->regtype == kRegTyFloat))) { + if (isCalleeReg) { + // Determine if it is worth keeping callee + if (callee_use_cnt[regno] == 2 && li->result_count == 1 && li->ref_count == 2) { + // This callee is allocated for one def and one use + li->stk_slot = SPILLED; + li->assigned_reg = 0; + addCalleeToSaved = false; + } + } + } + if (isCalleeReg && addCalleeToSaved) { + static_cast(cgfunc_)->AddtoCalleeSaved((Riscv64reg_t)regno); + } + + bool noSpill = false; + bool spillInserted = false; + use_localvar_spill = false; + if (li->should_save) { + // Determine if spill can reside in localref space + if (li->IsLocalRefVar() && CGOptions::doLocalRefSpill) { + // Make sure vreg writes and localref store match. + if (li->result_count == li->localrefvar_count) { + use_localvar_spill = true; + spillInserted = true; + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "\t\tcaller_use_localrefvar_spill " << li->regno << " imm " << li->localrefvar_offset << " "; + opnd->dump(); + LogInfo::MapleLogger() << "\n"; + } + } + } + if (insn->mop_ == MOP_adrp && insn->next && insn->next->mop_ == MOP_adrpl12 && li->assigned_reg != 0) { + RegOperand *ndst = static_cast(insn->next->GetOperand(0)); + RegOperand *nsrc = static_cast(insn->next->GetOperand(1)); + RegOperand *curdst = static_cast(insn->GetOperand(0)); + if (curdst->GetRegisterNumber() == ndst->GetRegisterNumber() && + curdst->GetRegisterNumber() == nsrc->GetRegisterNumber()) { + noSpill = true; + } + } + if (insn->mop_ == MOP_adrp_ldr && insn->next && insn->next->mop_ == MOP_clinit_tail) { + // clinit pair + li->assigned_reg = R16; + } else if (insn->mop_ == MOP_clinit_tail && insn->prev && insn->prev->mop_ == MOP_adrp_ldr) { + isdef = true; + InsertCallerSave(insn, opnd, isdef); + spillInserted = true; + } else { + InsertCallerSave(insn, opnd, isdef); + spillInserted = true; + } + } else if (li->stk_slot == SPILLED) { + // Determine if spill can reside in localref space + if (li->IsLocalRefVar() && CGOptions::doLocalRefSpill) { + // Make sure vreg writes and localref store match. + if (li->result_count == li->localrefvar_count) { + use_localvar_spill = true; + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "\t\tcallee_use_localrefvar_spill " << li->regno << " imm " << li->localrefvar_offset << " "; + opnd->dump(); + LogInfo::MapleLogger() << "\n"; + } + } + } + bool noSpill = false; + if (insn->mop_ == MOP_adrp && insn->next && insn->next->mop_ == MOP_adrpl12 && li->assigned_reg != 0) { + RegOperand *ndst = static_cast(insn->next->GetOperand(0)); + RegOperand *nsrc = static_cast(insn->next->GetOperand(1)); + RegOperand *curdst = static_cast(insn->GetOperand(0)); + if (curdst->GetRegisterNumber() == ndst->GetRegisterNumber() && + curdst->GetRegisterNumber() == nsrc->GetRegisterNumber()) { + noSpill = true; + } + } + if ((insn->mop_ == MOP_adrp_ldr && insn->next && insn->next->mop_ == MOP_clinit_tail)) { + // clinit pair + li->assigned_reg = R16; + } else if (insn->mop_ == MOP_clinit_tail && insn->prev && insn->prev->mop_ == MOP_adrp_ldr) { + isdef = true; + spillIdx = 0; + SpillOperand(insn, opnd, isdef, spillIdx); + spillInserted = true; + } else { + if (isdef) { + spillIdx = 0; + } + SpillOperand(insn, opnd, isdef, spillIdx); + spillInserted = true; + if (!isdef) { + spillIdx++; + } + } + } + + if (spillInserted && noSpill) { + insn->bb->RemoveInsn(insn->next); + } + + CG_ASSERT(opnd->GetSize() != 128, "NYI"); + RegOperand *phyOpnd = static_cast(cgfunc_)->GetOrCreatePhysicalRegisterOperand( + (Riscv64reg_t)(li->assigned_reg), opnd->GetSize(), regtype); + + return phyOpnd; +} + +// Iterate through all instructions and change the vreg to preg. +void LSRALinearScanRegAllocator::FinalizeRegisters() { + // Try to estimate if spill callee should be done based on even/odd for stp in prolog. + if (CGOptions::doCalleeToSpill) { + uint32 pairCnt = 0; + for (uint32 idx = 0; idx < 32; idx++) { + if (((1 << idx) & int_callee_mask) == 0) { + continue; + } + if (callee_use_cnt[idx] != 0) { + pairCnt++; + } + } + if (pairCnt & 0x01) { + should_opt_int_callee = true; + } + + for (uint32 idx = 0; idx < 32; idx++) { + if (((1 << idx) & fp_callee_mask) == 0) { + continue; + } + if (callee_use_cnt[idx] != 0) { + pairCnt++; + } + } + if (pairCnt & 0x01) { + should_opt_fp_callee = true; + } + } + // PrintRegSet(simd_spill_regs,"Available simd"); + for (uint32_t bbIdx = 0; bbIdx < sorted_bbs.size(); bbIdx++) { + BB *bb = sorted_bbs[bbIdx]; + int_bb_def_mask = 0; + fp_bb_def_mask = 0; + + FOR_BB_INSNS(insn, bb) { + if (insn->IsImmaterialInsn()) { + continue; + } + if (!insn->IsMachineInstruction()) { + continue; + } + if (insn->id == 0) { + continue; + } + + bool isMove = false; + bool isMove32 = false; + MOperator opcode = insn->GetMachineOpcode(); + if (opcode == MOP_wmovrr || opcode == MOP_xmovrr) { + isMove = true; + isMove32 = (opcode == MOP_wmovrr) ? true : false; + is_mov_src_simd_spilled = false; + is_mov_dst_simd_spilled = false; + } + + uint32 spillIdx = 0; + const Riscv64MD *md = &Riscv64CG::kMd[static_cast(insn)->mop_]; + + // Handle source opernads first + simd_reg_reclaim_idx = 0; + for (int32_t i = 0; i < Insn::kMaxOperandNum; i++) { + Operand *opnd = insn->GetOperand(i); + if (!opnd) { + continue; + } + + CG_ASSERT((md->operand_[i]) != nullptr, "pointer is null in LSRALinearScanRegAllocator::FinalizeRegisters"); + bool isdef = static_cast(md->operand_[i])->IsRegDef(); + if (isdef == true) { + continue; + } + RegOperand *phyOpnd = nullptr; + if (opnd->IsList()) { + // For arm32, not arm64 + } else if (opnd->IsMemoryAccessOperand()) { + MemOperand *memopnd = static_cast(static_cast(opnd)->Clone(cgfunc_->memPool)); + CG_ASSERT(memopnd != nullptr, "memopnd is null in LSRALinearScanRegAllocator::FinalizeRegisters"); + insn->SetOperand(i, memopnd); + Operand *base = memopnd->GetBaseRegister(); + if (base != nullptr) { + phyOpnd = GetReplaceOpnd(insn, base, spillIdx, false); + if (phyOpnd) { + memopnd->SetBaseRegister(phyOpnd); + } + } + } else { + phyOpnd = GetReplaceOpnd(insn, opnd, spillIdx, false); + if (phyOpnd) { + insn->SetOperand(i, phyOpnd); + } + } + } + // Handle dest opernads last + for (int32_t i = 0; i < Insn::kMaxOperandNum; i++) { + Operand *opnd = insn->GetOperand(i); + if (!opnd) { + continue; + } + + bool isdef = static_cast(md->operand_[i])->IsRegDef(); + if (isdef == false) { + continue; + } + is_spill_zero = false; + RegOperand *phyOpnd = nullptr; + phyOpnd = GetReplaceOpnd(insn, opnd, spillIdx, true); + if (phyOpnd) { + insn->SetOperand(i, phyOpnd); + if (is_spill_zero) { + insn->bb->RemoveInsn(insn); + } + } + } + + if (isMove && is_mov_src_simd_spilled && is_mov_dst_simd_spilled) { + /* mov reg1, reg2 -> both src & dest spill + * + * fmov reg2 <- fregx fmov reg2 <- fregx + * mov reg1 <- reg2 ===> fmov fregy <- fregx + * fmov fregy <- reg1 + * + * Cannot remove the first fmov due to caller save local use. + */ + CG_ASSERT(insn->prev, "LSRA spill has no prev insn"); + CG_ASSERT(insn->next, "LSRA spill has no next insn"); + + // Since reg1 is not defined, need to reload it for caller if + // it is necessary in the same bb. + RegOperand *dstRegopnd = static_cast(insn->GetOperand(0)); + RegOperand *srcRegopnd = static_cast(insn->GetOperand(1)); + if (dstRegopnd->GetSize() == srcRegopnd->GetSize()) { + regno_t regno = dstRegopnd->GetRegisterNumber(); + if (cgfunc_->IsCallerSaved(regno)) { + int_bb_def_mask &= ~(1 << (regno - R0)); + } + + Insn *ninsn = insn->next; + Operand *dst = ninsn->GetOperand(0); + Insn *pinsn = insn->prev; + Operand *src = pinsn->GetOperand(1); + + insn->SetOperand(0, dst); + insn->SetOperand(1, src); + if (isMove32) { + insn->SetMOP(MOP_xvmovs); + } else { + insn->SetMOP(MOP_xvmovd); + } + ninsn->bb->RemoveInsn(ninsn); + } + } + + for (int i = 0; i < simd_reg_reclaim_idx; i++) { + regno_t simd = simd_reg_reclaim[i]; + if (simd_reg_reclaim_slot[i] == kRegSlot0) { + simd_spill_0.insert(simd); + // if both [0,1] are available, then 64bit total is avail + for (MapleSet::iterator it = simd_spill_1.begin(); it != simd_spill_1.end(); it++) { + regno_t sreg = static_cast(*it); + if (sreg == simd) { + simd_spill_regs.insert(simd); + break; + } + } + } else if (simd_reg_reclaim_slot[i] == kRegSlot1) { + simd_spill_1.insert(simd); + // if both [0,1] are available, then 64bit total is avail + for (MapleSet::iterator it = simd_spill_0.begin(); it != simd_spill_0.end(); it++) { + regno_t sreg = static_cast(*it); + if (sreg == simd) { + simd_spill_regs.insert(simd); + break; + } + } + } else { + simd_spill_regs.insert(simd_reg_reclaim[i]); + } + } + } + } +} + +// Main entrance for the LSRA register allocator. +bool LSRALinearScanRegAllocator::AllocateRegisters() { + Riscv64CGFunc *a64cgfunc = static_cast(cgfunc_); + // we store both FP/LR if using FP or if not using FP, but func has a call + if (a64cgfunc->ShouldSaveFPLR()) { + // Using FP, record it for saving + a64cgfunc->AddtoCalleeSaved(RFP); + a64cgfunc->AddtoCalleeSaved(RRA); + a64cgfunc->NoteFPLRAddedToCalleeSavedList(); + } + + if (LSRA_DUMP) { + MIRModule &mirModule = cgfunc_->mirModule; + DotGenerator::GenerateDot("RA", cgfunc_, &mirModule); + DotGenerator::GenerateDot("RAe", cgfunc_, &mirModule, true); + //DotGenerator::GenerateDot("RAe", cgfunc_, &mirModule, true, 111); // Generate info for R111 + } + + if (CGOptions::doPreLsraOpt) { + RaX0Opt x0Opt; + x0Opt.PropagateX0(cgfunc_); + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "******** CG IR After PreLSRA: *********" << endl; + cgfunc_->DumpCGIR(); + } + } + + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "Entering LinearScanRegAllocator\n"; + } + + { + BB *cleanupBb = nullptr; + FOR_ALL_BB(bb, cgfunc_) { + bb->internal_flag1 = 0; // Use to mark cleanup bb + if (bb->firststmt == cgfunc_->cleanup_label) { + cleanupBb = bb; + } + } + for (BB *bb = cleanupBb; bb; bb = bb->next) { + bb->internal_flag1 = 1; + } + } + + ComputeLiveInterval(); + +#ifdef LSRA_GRAPH + PrintLiveRanges(); +#endif + LiveIntervalAnalysis(); + InitFreeRegPool(); + + BuildIntervalRanges(); + + if (CGOptions::fastAlloc == true) { + if (CGOptions::fastAllocMode == 0) { + fast_alloc = true; + } else { + spill_all = true; + } + // In-Range spill range can still be specified (only works with --dump-func=). + } else if (cgfunc_->NumBBs() > CGOptions::lsraBbOptSize) { + // instruction size is checked in ComputeLieveInterval() + fast_alloc = true; + } + + if (LSRA_DUMP) { + if (fast_alloc) { + LogInfo::MapleLogger() << "fast_alloc mode on\n"; + } + if (spill_all) { + LogInfo::MapleLogger() << "spill_all mode on\n"; + } + PrintParamQueue("Initial param queue"); + PrintCallQueue("Initial call queue"); + } + // handle param register + for (uint32 i = 0; i < int_param_queue.size(); i++) { + if (int_param_queue[i].size() != 0 && int_param_queue[i].front()->first_def == 0) { + LiveInterval *li = int_param_queue[i].front(); + int_param_reg_set.erase(li->assigned_reg - R0); + active.insert(li); + int_param_queue[i].pop_front(); + } + } + for (uint32 i = 0; i < fp_param_queue.size(); i++) { + if (fp_param_queue[i].size() != 0 && fp_param_queue[i].front()->first_def == 0) { + LiveInterval *li = fp_param_queue[i].front(); + fp_param_reg_set.erase(li->assigned_reg - V0); + active.insert(li); + fp_param_queue[i].pop_front(); + } + } + + for (uint32_t bbIdx = 0; bbIdx < sorted_bbs.size(); bbIdx++) { + BB *bb = sorted_bbs[bbIdx]; + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "======New BB=====" << bb->id << " " << std::hex << bb << std::dec << "\n"; + } + FOR_BB_INSNS(insn, bb) { + if (insn->IsImmaterialInsn()) { + continue; + } + if (!insn->IsMachineInstruction()) { + continue; + } + if (insn->id == 0) { + // New instruction inserted by reg alloc (ie spill) + continue; + } + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "======New Insn=====" << insn->id << " " << insn->bb->id << "\n"; + insn->dump(); + } + RetireFromActive(insn); +#ifdef LSRA_DEBUG + DebugCheckActiveList(); +#endif + AssignPhysRegsForInsn(insn); + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "======After Alloc=====" << insn->id << " " << insn->bb->id << "\n"; + insn->dump(); + } + } + } + FinalizeRegisters(); + + if (LSRA_DUMP) { + LogInfo::MapleLogger() << "Total " << spill_count << " spill_count in " << cgfunc_->GetName() << " \n"; + LogInfo::MapleLogger() << "Total " << reload_count << " reload_count\n"; + LogInfo::MapleLogger() << "Total " + << "(" << spill_count << "+ " << caller_save_spill_count << ") = " << spill_count + caller_save_spill_count + << " SPILL\n"; + LogInfo::MapleLogger() << "Total " + << "(" << reload_count << "+ " << caller_save_reload_count << ") = " << reload_count + caller_save_reload_count + << " RELOAD\n"; + + LogInfo::MapleLogger() << "Total " << simd_spill_count << " simd d <- x\n"; + LogInfo::MapleLogger() << "Total " << simd_reload_count << " simd x <- d\n"; + } + + return true; +} + +AnalysisResult *CgDoRegAlloc::Run(CGFunc *cgfunc, CgFuncResultMgr *m) { + bool success = false; + while (success == false) { + MemPool *phaseMp = mempoolctrler.NewMemPool("CG phase-wise pool"); + MapleAllocator phaseAllocator(phaseMp); + // It doesn't need live range information when -O1, because the register will not live out of bb. + if (g->optim_level >= 2) { + if (CGOptions::doLiveAnalysisEh) { + LiveAnalysis *live = static_cast(m->GetAnalysisResult(CgFuncPhase_LIVEEH, cgfunc)); + } else { + LiveAnalysis *live = static_cast(m->GetAnalysisResult(CgFuncPhase_LIVE, cgfunc)); + } + } + RegAllocator *regallocator = cgfunc->NewRegAllocator(cgfunc, phaseMp, &phaseAllocator); + CHECK_FATAL(regallocator != nullptr, "regallocator is null in CgDoRegAlloc::Run"); + m->GetAnalysisResult(CgFuncPhase_LOOP, cgfunc); + cgfunc->SetIsAfterRegAlloc(); + success = regallocator->AllocateRegisters(); + // the live range info may changed, so invalid the info. + m->InvalidAnalysisResult(CgFuncPhase_LIVEEH, cgfunc); + m->InvalidAnalysisResult(CgFuncPhase_LIVE, cgfunc); + m->InvalidAnalysisResult(CgFuncPhase_LOOP, cgfunc); + mempoolctrler.DeleteMemPool(phaseMp); + } + + return nullptr; +} + +} // namespace maplebe diff --git a/mapleall/maple_be/src/cg/riscv64/riscv64_schedule.cpp b/mapleall/maple_be/src/cg/riscv64/riscv64_schedule.cpp new file mode 100644 index 0000000..bba1a4a --- /dev/null +++ b/mapleall/maple_be/src/cg/riscv64/riscv64_schedule.cpp @@ -0,0 +1,535 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + + +#include "riscv64_schedule.h" +#include "riscv64_cg.h" +#include "riscv64_operand.h" +#include "riscv64_dep_analysis.h" +#include "reg_pressure.h" + +#include + +namespace maplebe { + +void Riscv64Schedule::Init() { + readyList.clear(); + nodeSize = nodes.size(); + lastSeparatorIndex = 0; + DepNode *node = nodes[0]; + + CG_ASSERT(node->GetType() == kNodeTypeSeparator, "CG internal error, the first node should be a separator node."); + + readyList.push_back(node); + node->SetState(kReady); + + // Init validPredsSize and validSuccsSize. + for (auto node : nodes) { + node->SetValidPredsSize(node->GetPreds().size()); + node->SetValidSuccsSize(node->GetSuccs().size()); + } +} + +void Riscv64Schedule::MemoryAccessPairOpt(BB *bb) { +} + +/* combine clinit pairs. + */ +void Riscv64Schedule::ClinitPairOpt() { + uint32 i = 0; + for (auto it = nodes.begin(); it != nodes.end(); it++, i++) { + auto nextIt = std::next(it, 1); + if (nextIt == nodes.end()) { + return; + } + + if ((*it)->GetInsn()->GetMachineOpcode() == MOP_adrp_ldr) { + if ((*nextIt)->GetInsn()->GetMachineOpcode() == MOP_clinit_tail) { + depAnalysis->CombineClinit(*it, *(nextIt), false); + } else if ((*nextIt)->GetType() == kNodeTypeSeparator){ + nextIt = std::next(nextIt, 1); + if (nextIt == nodes.end()) { + return; + } + + if ((*nextIt)->GetInsn()->GetMachineOpcode() == MOP_clinit_tail) { + // Do something. + depAnalysis->CombineClinit(*it, *(nextIt), true); + } + } + } + } +} + +uint32 Riscv64Schedule::GetNextSepIndex() const { + uint32 nextSepIndex = (lastSeparatorIndex + kMaxDependenceNum) < nodeSize + ? (lastSeparatorIndex + kMaxDependenceNum) + : nodes.size() - 1; + return nextSepIndex; +} + +void Riscv64Schedule::RegPressureScheduling(const BB *bb, std::vector &nodes) { + RegPressureSchedule* regSchedule = mp->New(cgfunc, mp); + // Get physical register amount currently + // undef, Int Reg, Floag Reg, Flag Reg + const int kregNum[] = {0/*, RFLAG*/, kMaxRegNum-V0+1, 1}; + regSchedule->InitBBInfo(bb, mp, nodes); + regSchedule->BuildPhyRegInfo(kregNum, sizeof(kregNum)); + regSchedule->DoScheduling(nodes); +} + +/* Compute earliest start of the node. + return value : the maximum estart. + */ +uint32 Riscv64Schedule::ComputeEstart(uint32 cycle) { + + std::vector readyNodes; + uint32 maxIndex = GetNextSepIndex(); + + // Check validPredsSize. + for (uint32 i = lastSeparatorIndex; i <= maxIndex; i++) { + DepNode *node = nodes[i]; + int schedNum = 0; + for (auto predLink : node->GetPreds()) { + if (predLink->GetFrom()->GetState() == kScheduled) + schedNum ++; + } + CG_ASSERT((node->GetPreds().size() - schedNum) == node->GetValidPredsSize(), "validPredsSize error."); + } + + CG_ASSERT(nodes[maxIndex]->GetType() == kNodeTypeSeparator, + "CG internal error, nodes[maxIndex] should be a separator node."); + + readyNodes.reserve(maxIndex - lastSeparatorIndex + 1); + readyNodes = readyList; + + uint32 maxEstart = cycle; + + for (uint32 i = lastSeparatorIndex; i <= maxIndex; i++) { + DepNode *node = nodes[i]; + node->SetVisit(0); + } + + for (auto node : readyNodes) { + CG_ASSERT(node->GetState() == kReady, "CG internal error, all nodes in ready list should be ready."); + node->SetEStart(cycle); + } + + for (auto it = readyNodes.begin(); it != readyNodes.end(); it++) { + DepNode *node = *it; + for (auto succLink : node->GetSuccs()) { + DepNode *succNode = succLink->GetTo(); + if (succNode->GetType() == kNodeTypeSeparator) + continue; + + if (succNode->GetEStart() < node->GetEStart() + succLink->GetLatency()) { + succNode->SetEStart(node->GetEStart() + succLink->GetLatency()); + maxEstart = (maxEstart < succNode->GetEStart() ? succNode->GetEStart() : maxEstart); + } + succNode->IncreaseVisit(); + if (succNode->GetVisit() >= succNode->GetValidPredsSize() && succNode->GetType() != kNodeTypeSeparator) { + readyNodes.push_back(succNode); + } + CG_ASSERT(succNode->GetVisit() <= succNode->GetValidPredsSize(), "CG internal error."); + } + } + return maxEstart; +} + +/* Compute latest start of the node. + */ +void Riscv64Schedule::ComputeLstart(uint32 maxEstart) { + std::vector readyNodes; + uint32 maxIndex = GetNextSepIndex(); + + CG_ASSERT(nodes[maxIndex]->GetType() == kNodeTypeSeparator, + "CG internal error, nodes[maxIndex] should be a separator node."); + + readyNodes.reserve(maxIndex - lastSeparatorIndex + 1); + + for (uint32 i = lastSeparatorIndex; i <= maxIndex; i++) { + DepNode *node = nodes[i]; + node->SetLStart(maxEstart); + node->SetVisit(0); + } + + readyNodes.push_back(nodes[maxIndex]); + + for (auto it = readyNodes.begin(); it != readyNodes.end(); it++) { + DepNode *node = *it; + for (auto predLink : node->GetPreds()) { + DepNode *predNode = predLink->GetFrom(); + if (predNode->GetState() == kScheduled) { + continue; + } + + if (predNode->GetLStart() > node->GetLStart() - predLink->GetLatency()) { + predNode->SetLStart(node->GetLStart() - predLink->GetLatency()); + } + predNode->IncreaseVisit(); + if (predNode->GetVisit() >= predNode->GetValidSuccsSize() && predNode->GetType() != kNodeTypeSeparator) { + readyNodes.push_back(predNode); + } + + CG_ASSERT(predNode->GetVisit() <= predNode->GetValidSuccsSize(), "CG internal error."); + } + } +} + +void Riscv64Schedule::UpdateELStartsOnCycle(uint32 cycle) { + ComputeLstart(ComputeEstart(cycle)); +} + +bool DepNode::CanBeScheduled() const { + for (int i = 0; i < unitNum; i++) { + Unit *unit = units[i]; + if (unit) { + if (!unit->IsFree(i)) { + return false; + } + } + } + + return true; +} + +void DepNode::OccupyUnits() { + for (int i = 0; i < unitNum; i++) { + Unit *unit = units[i]; + if (unit) { + unit->Occupy(insn, i); + } + } +} + +void Riscv64Schedule::RandomTest() { + Init(); + nodes.clear(); + + while (!readyList.empty()) { + DepNode *currNode = readyList.back(); + currNode->SetState(kScheduled); + readyList.pop_back(); + nodes.push_back(currNode); + + for (auto succLink : currNode->GetSuccs()) { + DepNode *succNode = succLink->GetTo(); + bool ready = true; + for (auto predLink : succNode->GetPreds()) { + DepNode *predNode = predLink->GetFrom(); + if (predNode->GetState() != kScheduled) { + ready = false; + break; + } + } + + if (ready) { + CG_ASSERT(succNode->GetState() == kNormal, ""); + readyList.push_back(succNode); + succNode->SetState(kReady); + } + } + } +} + +void Riscv64Schedule::EraseNodeFromReadyList(const DepNode *target) { + for (auto it = readyList.begin(); it != readyList.end(); it++) { + if ((*it) == target) { + readyList.erase(it); + return; + } + } + + CG_ASSERT(false, "CG internal error, erase node fail."); +} + +/* After building dependence graph, schedule insns. + */ +void Riscv64Schedule::DoSchedule() { + vector availableReadyList; + vector tempReadyList; + vector scheduledNodes; + + uint32 lastUpdateCycle = 0; + uint32 currCycle = 0; + bool advanceCycle = false; + bool isFirstSeparator = true; + + Init(); + + availableReadyList.reserve(nodeSize); + tempReadyList.reserve(nodeSize); + + UpdateELStartsOnCycle(currCycle); + + while (!readyList.empty()) { + if (advanceCycle) { + currCycle++; + mad->AdvanceCycle(); + advanceCycle = false; + } + tempReadyList.clear(); + availableReadyList.clear(); + + // Check if schedulable + for (auto node : readyList) { + if (node->CanBeScheduled()) { + availableReadyList.push_back(node); + } + } + + if (availableReadyList.empty()) { + // Advance cycle. + advanceCycle = true; + continue; + } + + if (lastUpdateCycle < currCycle) { + UpdateELStartsOnCycle(currCycle); + lastUpdateCycle = currCycle; + } + + // Check EStart. + for (auto node : availableReadyList) { + if (node->GetEStart() <= currCycle) { + tempReadyList.push_back(node); + } + } + + if (tempReadyList.empty()) { + // Advance cycle. + advanceCycle = true; + continue; + } else { + availableReadyList = tempReadyList; + tempReadyList.clear(); + } + + // Select minimum LStart. + if (availableReadyList.size() > 1) { + uint32 minlStart = -1; + for (auto node : availableReadyList) { + if (minlStart > node->GetLStart()) { + minlStart = node->GetLStart(); + } + } + + for (auto node : availableReadyList) { + if (minlStart == node->GetLStart()) { + tempReadyList.push_back(node); + } + } + + CG_ASSERT(tempReadyList.size() >= 1, "CG internal error."); + availableReadyList = tempReadyList; + tempReadyList.clear(); + } + + // Select slot0 first. + if (mad->IsSlot0Free() && availableReadyList.size() > 1) { + for (auto node : availableReadyList) { + enum SlotType slotType = node->GetReservation()->GetSlot(); + if (slotType == kSlot0 || slotType == kSlots) { + tempReadyList.push_back(node); + } + } + + if (!tempReadyList.empty()) { + availableReadyList = tempReadyList; + tempReadyList.clear(); + } + } + + // Select first node. + DepNode *targetNode = availableReadyList.front(); + targetNode->SetState(kScheduled); + scheduledNodes.push_back(targetNode); + + EraseNodeFromReadyList(targetNode); + targetNode->OccupyUnits(); + + // Update readyList. + for (auto succLink : targetNode->GetSuccs()) { + DepNode *succNode = succLink->GetTo(); + succNode->DescreaseValidPredsSize(); + if (succNode->GetValidPredsSize() == 0) { + readyList.push_back(succNode); + succNode->SetState(kReady); + } + } + + if (targetNode->GetType() == kNodeTypeSeparator) { + // If target node is separator node, update lastSeparatorIndex. + if (!isFirstSeparator) { + lastSeparatorIndex += kMaxDependenceNum; + } else { + isFirstSeparator = false; + } + } + + if (mad->IsFullIssued()) { + advanceCycle = true; + } + } + + CG_ASSERT(scheduledNodes.size() == nodes.size(), "CG internal error, Not all nodes scheduled."); + + nodes = scheduledNodes; +} + +/* Restore dependence graph to normal CGIR. + */ +void Riscv64Schedule::FinalizeScheduling(BB *bb, const DepAnalysis *depAnalysis) { + bb->ClearInsns(); + + for (auto node : nodes) { + // Append comments first. + for (auto comment : node->GetComments()) { + bb->AppendInsn(comment); + } + + // Append insn. + if (!node->GetClinitInsns().empty()) { + for (auto clinit : node->GetClinitInsns()) { + bb->AppendInsn(clinit); + } + } else if (node->GetType() == kNodeTypeNormal) { + bb->AppendInsn(node->GetInsn()); + } + + // Append cfi instructions. + for (auto cfi : node->GetCfiInsns()) { + bb->AppendInsn(cfi); + } + } + + for (auto lastComment : depAnalysis->GetLastComments()) { + bb->AppendInsn(lastComment); + } +} + +void Riscv64Schedule::DumpDepGraph(const std::vector &nodes) const { + for (auto node : nodes) { + depAnalysis->dumpDepNode(node); + LogInfo::MapleLogger() << "---------- preds ----------" << endl; + for (auto pred : node->GetPreds()) { + depAnalysis->dumpDepLink(pred, pred->GetFrom()); + } + LogInfo::MapleLogger() << "---------- succs ----------" << endl; + for (auto succ : node->GetSuccs()) { + depAnalysis->dumpDepLink(succ, succ->GetTo()); + } + LogInfo::MapleLogger() << "---------------------------" << endl; + } +} + +void Riscv64Schedule::GenerateDot(const BB *bb, const std::vector &nodes) const { + streambuf *coutbuf = LogInfo::MapleLogger().rdbuf(); /* keep original LogInfo::MapleLogger() buffer */ + ofstream dgFile; + streambuf *buf = dgFile.rdbuf(); + LogInfo::MapleLogger().rdbuf(buf); + + // construct the file name + std::string fileName; + fileName.append(phaseName); + fileName.append("_"); + fileName.append(cgfunc->GetName().c_str()); + fileName.append("_BB"); + auto str = std::to_string(bb->id); + fileName.append(str.c_str()); + fileName.append("_dep_graph.dot"); + + dgFile.open(fileName.c_str(), ios::trunc); + dgFile << "digraph {\n"; + for (auto node : nodes) { + for (auto succ : node->GetSuccs()) { + dgFile << "insn" << node->GetInsn() << " -> " << "insn" << succ->GetTo()->GetInsn(); + dgFile << " ["; + if (succ->GetDepType() == kDependenceTypeTrue) { + dgFile << "color=red,"; + } + dgFile << "label= \"" << succ->GetLatency() << "\""; + dgFile << "];\n"; + } + } + + for (auto node : nodes) { + MOperator mop = node->GetInsn()->GetMachineOpcode(); + const Riscv64MD *md = &Riscv64CG::kMd[mop]; + dgFile << "insn" << node->GetInsn() << "["; + dgFile << "shape=box,label= \" " << node->GetInsn()->id << ":\n"; + dgFile << "{ "; + dgFile << md->name_ << "\n"; + dgFile << "}\"];\n"; + } + dgFile << "}\n"; + dgFile.flush(); + dgFile.close(); + LogInfo::MapleLogger().rdbuf(coutbuf); +} + +//#define TimeCalculate + +/* A local list scheduling. + Schedule insns in basic blocks. + */ +void Riscv64Schedule::ListScheduling(bool beforeRA) { + MarkInsnId(); + + mad = g->mad; + depAnalysis = mp->New(cgfunc, mp, beforeRA); + RegPressure::SetMaxRegClassNum(kRegisterLast); + + FOR_ALL_BB(bb, cgfunc) { +#if TimeCalculate + clock_t startTime; + clock_t endTime; + startTime = clock(); +#endif //TimeCalculate + depAnalysis->Run(bb, nodes); +#if TimeCalculate + endTime = clock(); + uint32 bbsize; + if (bb->firstinsn == nullptr) { + bbsize = 0; + } else { + bbsize = bb->lastinsn->id - bb->firstinsn->id + 1; + } + LogInfo::MapleLogger() << "BB id = " << bb->id << "; BB size = " << bbsize << "; "; + LogInfo::MapleLogger() << "Dependence analysis Time : " << (endTime - startTime) << "ms" << std::endl; +#endif //TimeCalculate + ClinitPairOpt(); + if (LISTSCHEDDUMP) { + GenerateDot(bb, nodes); + } + if (beforeRA) { + MemoryAccessPairOpt(bb); + RegPressureScheduling(bb, nodes); + } else { +#if TimeCalculate + startTime = clock(); +#endif //if + DoSchedule(); +#if TimeCalculate + endTime = clock(); + LogInfo::MapleLogger() << "Schedule Time : " << (endTime - startTime) << "ms" << std::endl; +#endif //if + } + + FinalizeScheduling(bb, depAnalysis); + } +} + +} // namespace maplebe diff --git a/mapleall/maple_be/src/cg/riscv64/riscv64_store_load_opt.cpp b/mapleall/maple_be/src/cg/riscv64/riscv64_store_load_opt.cpp new file mode 100644 index 0000000..440038a --- /dev/null +++ b/mapleall/maple_be/src/cg/riscv64/riscv64_store_load_opt.cpp @@ -0,0 +1,804 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#include "riscv64_store_load_opt.h" +#include "riscv64_operand.h" +#include "riscv64_insn.h" +#include "riscv64_cg_func.h" +#include + +namespace maplebe { + +using namespace maple; + +static int gTestInfoStoreID = 0; +static int gTestInfoMovID = 0; + +bool Riscv64StoreLoadOpt::CanReachEndBBFromBB(BB *bb, BB *endBB, set &traversedBBSet) { + if (bb == endBB) { + return true; + } + + for (auto succ : bb->succs) { + if (traversedBBSet.find(succ) != traversedBBSet.end()) { + continue; + } else { + traversedBBSet.insert(succ); + if (succ == endBB) { + return true; + } + if (CanReachEndBBFromBB(succ, endBB, traversedBBSet)) { + return true; + } + } + } + + for (auto ehsucc : bb->eh_succs) { + if (traversedBBSet.find(ehsucc) != traversedBBSet.end()) { + continue; + } else { + traversedBBSet.insert(ehsucc); + if (ehsucc == endBB) { + return true; + } + if (CanReachEndBBFromBB(ehsucc, endBB, traversedBBSet)) { + return true; + } + } + } + + return false; +} + +bool Riscv64StoreLoadOpt::IsLiveInAllPathBB(BB *startBB, BB *endBB, MapleSet &setBb, + bool isParamPhyRegOpnd, std::set &traversed) { + set traversedPathSet; + + for (auto succ : startBB->succs) { + if (traversed.find(succ) != traversed.end()) { + continue; + } + + traversed.insert(succ); + traversedPathSet.clear(); + if ((succ != endBB || (succ == endBB && endBB->loop)) && + ((isParamPhyRegOpnd && succ->HasCall()) || (setBb.find(succ) != setBb.end())) && + CanReachEndBBFromBB(succ, endBB, traversedPathSet)) { + return false; + } + + bool isLive = IsLiveInAllPathBB(succ, endBB, setBb, isParamPhyRegOpnd, traversed); + if (!isLive) { + return false; + } + } + + for (auto ehsucc : startBB->eh_succs) { + if (traversed.find(ehsucc) != traversed.end()) { + continue; + } + + traversed.insert(ehsucc); + traversedPathSet.clear(); + if ((ehsucc != endBB || (ehsucc == endBB && endBB->loop)) && + ((isParamPhyRegOpnd && ehsucc->HasCall()) || (setBb.find(ehsucc) != setBb.end())) && + CanReachEndBBFromBB(ehsucc, endBB, traversedPathSet)) { + return false; + } + + bool isLive = IsLiveInAllPathBB(ehsucc, endBB, setBb, isParamPhyRegOpnd, traversed); + if (!isLive) { + return false; + } + } + + return true; +} + +/* Check if the definition operand of the defInsn is live from startInsn to endInsn point. + Params: + defInsn: The instruction of the operand defined. + index: The operand of the ith destination operand of the defInsn. + startInsn: The start point. + endInsn: The end point. + */ +bool Riscv64StoreLoadOpt::IsLiveAtInsn(Insn *defInsn, int index, Insn *startInsn, Insn *endInsn) { + if (defInsn->IsStore()) { + // Memory live info should consider dirty property. + CHECK_FATAL(false, "Currently no need to do this optimization."); + } else { + // Currently always return false. + if (defInsn->redefine[index] == nullptr) { + return true; + } + + bool isParamPhyRegOpnd = false; + if (defInsn->IsCall()) { + // For return value R0. + isParamPhyRegOpnd = true; + } else if (defInsn->GetOperand(index)->IsRegister()) { + RegOperand *regOpnd = static_cast(defInsn->GetOperand(index)); + regno_t regno = regOpnd->GetRegisterNumber(); + if ((regno >= R0 && regno <= R7) || (regno >= V0 && regno <= V7)) { + isParamPhyRegOpnd = true; + } + } + + MapleSet setBb(schdAlloc.Adapter()); + for (auto redef : *(defInsn->redefine[index])) { + Insn *redefInsn = redef.GetInsn(); + if (startInsn->bb != endInsn->bb) { + if (redefInsn->bb == endInsn->bb) { + if (redefInsn->id < endInsn->id) { + return false; + } + } else if (redefInsn->bb == startInsn->bb) { + if (redefInsn->id > startInsn->id) { + return false; + } + } else { + setBb.insert(redefInsn->bb); + } + } else { + CG_ASSERT(startInsn->id < endInsn->id, "Internal error. No possible."); + + if (redefInsn->bb == endInsn->bb) { + // All in the same BB. + if (redefInsn->id < endInsn->id && redefInsn->id > startInsn->id) { + return false; + } + } else { + // Do nothing. + } + } + } + // Check if there exist a redefinInsn in the BB that any paths from defInsn->bb to endInsn->bb may traverl through. + if (startInsn->bb != endInsn->bb) { + std::set traversed; + BB *startBB = startInsn->bb; + traversed.insert(startBB); + return IsLiveInAllPathBB(startBB, endInsn->bb, setBb, isParamPhyRegOpnd, traversed); + } + } + + return true; +} + +void Riscv64StoreLoadOpt::InsertDUUD(const DataInsnInfo &defInsnInfo, const DataInsnInfo &useInsnInfo) { + Insn *defInsn = defInsnInfo.GetInsn(); + short defUseIdx = defInsnInfo.GetDUIndex(); + Insn *useInsn = useInsnInfo.GetInsn(); + short useDefIdx = useInsnInfo.GetIndex(); + if (useDefIdx > 0 && (defInsnInfo.GetProperty() & DataInsnInfo::kCallParam)) { + useDefIdx++; + } + + if (defInsn->uses[defUseIdx] == nullptr) { + defInsn->uses[defUseIdx] = + rd->GetMemPool()->New>(rd->GetMemAllocator().Adapter()); + } + + defInsn->uses[defUseIdx]->insert(useInsnInfo); + + if (useInsn->defs[useDefIdx] == nullptr) { + useInsn->defs[useDefIdx] = + rd->GetMemPool()->New>(rd->GetMemAllocator().Adapter()); + } + + useInsn->defs[useDefIdx]->insert(defInsnInfo); +} + +void Riscv64StoreLoadOpt::RemovDUUD(Insn *defInsn, Insn *useInsn) { + MapleSet::iterator itSet; + MapleSet::iterator itSet2; + + for (int i = 0; i < Insn::kMaxDefineOperandNum; i++) { + if (defInsn->uses[i] == nullptr) { + continue; + } + + for (itSet2 = defInsn->uses[i]->begin(); itSet2 != defInsn->uses[i]->end();) { + if ((*itSet2).GetInsn() == useInsn) { + itSet2 = defInsn->uses[i]->erase(itSet2); + if (defInsn->uses[i]->empty()) { + break; + } + // Do not break here, since one insn may have multiple same use operand. + /* Such as: + x10 = ... + = x10, x10 + */ + } else { + itSet2++; + } + } + } + + for (int i = 0; i < Insn::kMaxUseOperandNum; i++) { + if (useInsn->defs[i] == nullptr) { + continue; + } + + for (itSet = useInsn->defs[i]->begin(); itSet != useInsn->defs[i]->end();) { + if ((*itSet).GetInsn() == defInsn) { + itSet = useInsn->defs[i]->erase(itSet); + break; + } else { + itSet++; + } + } + } +} + +/* Transfer: store x100, [MEM] + ... // May exist branches. + load x200, [MEM] + ==> + OPT_VERSION_STR_LIVE: + store x100, [MEM] + ... // May exist branches. if x100 not dead here. + mov x200, x100 + OPT_VERSION_STR_DIE: + store x100, [MEM] + mov x9000(new reg), x100 + ... // May exist branches. if x100 dead here. + mov x200, x9000 + Params: + stInsn: indicate store insn. + stIdx: index of source register operand of store insn. (x100 in this example) + ldInsn: indicate load insn. + ldIdx: index of source memory operand of the load insn. + defInsnInfo: insnInfo for x100. + */ +void Riscv64StoreLoadOpt::DoLoadToMoveTransfer(Insn *stInsn, short stIdx, Insn *ldInsn, short ldIdx, + enum OptVersion version, const DataInsnInfo &defInsnInfo) { + Operand *resOpnd = ldInsn->GetResult(0); + Operand *srcOpnd = stInsn->GetOperand(stIdx); + + CG_ASSERT(ldIdx == 1, "Currently only support ldr, not support ldp."); + CG_ASSERT(resOpnd && srcOpnd, "null ptr check"); + CG_ASSERT(resOpnd->GetSize() == srcOpnd->GetSize(), "For stack location, the size of src and dst should be same."); + CG_ASSERT(resOpnd->IsRegister() && srcOpnd->IsRegister(), "Operands of mov/fmov should be all register operands."); + CG_ASSERT(version & (kOptVersionStpLive | kOptVersionStrLive | kOptVersionStpDie | kOptVersionStrDie), + "version is not invalid."); + + RegOperand *resRegOpnd = static_cast(resOpnd); + RegOperand *srcRegOpnd = static_cast(srcOpnd); + + if (resRegOpnd->GetRegisterType() != srcRegOpnd->GetRegisterType()) { + return; + } + + uint64 index = (int64)(stInsn); + auto itMoveInsn = moveInsn->find(index); + Insn *movInsn = nullptr; + if (itMoveInsn != moveInsn->end()) { + if (stIdx == 0) { + movInsn = itMoveInsn->second.first; + } else { + movInsn = itMoveInsn->second.second; + } + } + + if (version & (kOptVersionStpLive | kOptVersionStrLive)) { + if (movInsn) { + RegOperand *vregOpnd = static_cast(movInsn->GetOperand(0)); + + ldInsn->SetOperand(ldIdx, vregOpnd); + if (resRegOpnd->IsOfFloatOrSIMDClass() && srcRegOpnd->IsOfFloatOrSIMDClass()) { + // fmov + ldInsn->SetMOP(resOpnd->GetSize() == 64 ? MOP_xvmovd : MOP_xvmovs); + } else { + // mov + ldInsn->SetMOP(resOpnd->GetSize() == 64 ? MOP_xmovrr : MOP_wmovrr); + } + + // Add comment. + std::string newComment = ldInsn->GetComment(); + if (version & kOptVersionStpLive) { + newComment += "; stp-load live version."; + } else { + newComment += "; str-load live version."; + } + + ldInsn->AddComment(newComment); + + // Update DU-UD info. + // 1: remove use of store insn. ([MEM]) + // 2: remove def of load insn. ([MEM]) + RemovDUUD(stInsn, ldInsn); + // 3: insert use of mov x9000. + // 4: insert def of the operand "x9000" of the mov insn. + DataInsnInfo movDefInsnInfo(movInsn, 0, DataInsnInfo::kNormal); + DataInsnInfo ldrUseInsnInfo(ldInsn, ldIdx, DataInsnInfo::kNormal); + InsertDUUD(movDefInsnInfo, ldrUseInsnInfo); + } else { + ldInsn->SetOperand(ldIdx, srcOpnd); + if (resRegOpnd->IsOfFloatOrSIMDClass() && srcRegOpnd->IsOfFloatOrSIMDClass()) { + // fmov + ldInsn->SetMOP(resOpnd->GetSize() == 64 ? MOP_xvmovd : MOP_xvmovs); + } else { + // mov + ldInsn->SetMOP(resOpnd->GetSize() == 64 ? MOP_xmovrr : MOP_wmovrr); + } + + // Add comment. + std::string newComment = ldInsn->GetComment(); + if (version & kOptVersionStpLive) { + newComment += "; stp-load live version."; + } else { + newComment += "; str-load live version."; + } + ldInsn->AddComment(newComment); + + // Update DU-UD info. + // 1: remove use of store insn. ([MEM]) + // 2: remove def of load insn. ([MEM]) + RemovDUUD(stInsn, ldInsn); + // 3: insert use of x100's definition insn. + // 4: insert def of the operand "x100" of the mov insn. + DataInsnInfo useInsnInfo(ldInsn, ldIdx, DataInsnInfo::kNormal); + InsertDUUD(defInsnInfo, useInsnInfo); + } + } else if (version & (kOptVersionStpDie | kOptVersionStrDie)) { + // To do. + CG_ASSERT(stIdx <= 2, "CG internal error."); + + RegType regty = srcRegOpnd->IsOfFloatOrSIMDClass() ? kRegTyFloat : kRegTyInt; + RegOperand *vregOpnd = nullptr; + MOperator newMop; + Insn *newMovInsn = nullptr; + + if (movInsn == nullptr) { + regno_t vRegNo = cgfunc->New_V_Reg(regty, srcRegOpnd->GetSize() <= 32 ? 4 : 8); + vregOpnd = cgfunc->CreateVirtualRegisterOperand(vRegNo); + + if (srcRegOpnd->IsOfFloatOrSIMDClass()) { + // fmov + newMop = resOpnd->GetSize() == 64 ? MOP_xvmovd : MOP_xvmovs; + } else { + newMop = resOpnd->GetSize() == 64 ? MOP_xmovrr : MOP_wmovrr; + } + + newMovInsn = cgfunc->cg->BuildInstruction(newMop, vregOpnd, srcRegOpnd); + if (stInsn->next && stInsn->next->id == stInsn->id + 1) { + newMovInsn->id = stInsn->id + 1; + stInsn->next->id = stInsn->id + 2; + } else { + newMovInsn->id = stInsn->id + 1; + } + stInsn->bb->InsertInsnAfter(stInsn, newMovInsn); + + if (stInsn->bb->loop) { + // insert pre/redefine for newMovInsn + newMovInsn->redefine[0] = cgfunc->GetRD()->GetMemPool()->New>( + cgfunc->GetRD()->GetMemAllocator().Adapter()); + newMovInsn->predefine[0] = cgfunc->GetRD()->GetMemPool()->New>( + cgfunc->GetRD()->GetMemAllocator().Adapter()); + newMovInsn->redefine[0]->insert(DataInsnInfo(newMovInsn, 0, DataInsnInfo::kNormal)); + newMovInsn->predefine[0]->insert(DataInsnInfo(newMovInsn, 0, DataInsnInfo::kNormal)); + } + + if (itMoveInsn != moveInsn->end()) { + if (stIdx == 0) { + itMoveInsn->second.first = newMovInsn; + } else { + itMoveInsn->second.second = newMovInsn; + } + } else { + uint64 index = (uint64)(stInsn); + if (stIdx == 0) { + (*moveInsn)[index] = make_pair(newMovInsn, nullptr); +//pair(newMovInsn, nullptr); + } else { + (*moveInsn)[index] = make_pair(nullptr, newMovInsn); +//pair(nullptr, newMovInsn); + } + } + } else { + newMovInsn = movInsn; + + CG_ASSERT((newMovInsn->GetMachineOpcode() == MOP_xvmovd || newMovInsn->GetMachineOpcode() == MOP_xvmovs || + newMovInsn->GetMachineOpcode() == MOP_xmovrr || newMovInsn->GetMachineOpcode() == MOP_wmovrr), + "CG internal error."); + + vregOpnd = static_cast(newMovInsn->GetOperand(0)); + } + + ldInsn->SetOperand(ldIdx, vregOpnd); + if (resRegOpnd->IsOfFloatOrSIMDClass() && srcRegOpnd->IsOfFloatOrSIMDClass()) { + // fmov + ldInsn->SetMOP(resOpnd->GetSize() == 64 ? MOP_xvmovd : MOP_xvmovs); + } else { + // mov + ldInsn->SetMOP(resOpnd->GetSize() == 64 ? MOP_xmovrr : MOP_wmovrr); + } + + // Add comment. + std::string newComment = ldInsn->GetComment(); + if (version & kOptVersionStpDie) { + newComment += "; stp-load die version."; + } else { + newComment += "; str-load die version."; + } + ldInsn->AddComment(newComment); + + // Update DU-UD info. + // 1: remove use of store insn. ([MEM]) + // 2: remove def of load insn. ([MEM]) + RemovDUUD(stInsn, ldInsn); + // 3: insert use of x100's definition insn. + // 4: insert def of the operand "x100" of the load insn. + DataInsnInfo movUseInsnInfo(newMovInsn, 1, DataInsnInfo::kNormal); + InsertDUUD(defInsnInfo, movUseInsnInfo); + + DataInsnInfo movDefInsnInfo(newMovInsn, 0, DataInsnInfo::kNormal); + DataInsnInfo ldrUseInsnInfo(ldInsn, ldIdx, DataInsnInfo::kNormal); + InsertDUUD(movDefInsnInfo, ldrUseInsnInfo); + } else { + CG_ASSERT(false, "No other optimization version."); + } + + if (cgfunc->cg->GenerateVerboseAsm() && cgfunc->cg->GenerateTestInfo()) { + // For test framework. + Riscv64CGFunc *a64cgfunc = static_cast(cgfunc); + + if (version & (kOptVersionStpLive | kOptVersionStpDie)) { + std::string comment = "stp_id: "; + comment += std::to_string(gTestInfoStoreID); + const char *str1 = comment.c_str(); + Insn *commentInsn = cgfunc->cg->BuildInstruction(MOP_comment, a64cgfunc->CreateCommentOperand(str1)); + stInsn->bb->InsertInsnAfter(stInsn, commentInsn); + + comment = "mov_pid: "; + comment += std::to_string(gTestInfoStoreID); + comment += "_"; + comment += std::to_string(stIdx); + comment += "-"; + comment += std::to_string(gTestInfoMovID++); + const char *str2 = comment.c_str(); + commentInsn = cgfunc->cg->BuildInstruction(MOP_comment, a64cgfunc->CreateCommentOperand(str2)); + ldInsn->bb->InsertInsnAfter(ldInsn, commentInsn); + } else { + std::string comment = "str_id: "; + comment += std::to_string(gTestInfoStoreID); + const char *str1 = comment.c_str(); + Insn *commentInsn = cgfunc->cg->BuildInstruction(MOP_comment, a64cgfunc->CreateCommentOperand(str1)); + stInsn->bb->InsertInsnAfter(stInsn, commentInsn); + + comment = "mov_id: "; + comment += std::to_string(gTestInfoStoreID); + comment += "-"; + comment += std::to_string(gTestInfoMovID++); + const char *str2 = comment.c_str(); + commentInsn = cgfunc->cg->BuildInstruction(MOP_comment, a64cgfunc->CreateCommentOperand(str2)); + + ldInsn->bb->InsertInsnAfter(ldInsn, commentInsn); + } + } +} + +/* Transfer: store wzr, [MEM] + ... // May exist branches. + load x200, [MEM] + ==> + OPT_VERSION_STP_ZERO / OPT_VERSION_STR_ZERO: + store wzr, [MEM] + ... // May exist branches. if x100 not dead here. + mov x200, wzr + + Params: + stInsn: indicate store insn. + stIdx: index of source register operand of store insn. (wzr in this example) + ldInsn: indicate load insn. + ldIdx: index of source memory operand of the load insn. + */ +void Riscv64StoreLoadOpt::DoLoadZeroToMoveTransfer(Insn *stInsn, short stIdx, Insn *ldInsn, short ldIdx, + enum OptVersion version) { + CG_ASSERT(stInsn && ldInsn, "null ptr check"); + Operand *resOpnd = ldInsn->GetResult(0); + RegOperand *resRegOpnd = static_cast(resOpnd); + Operand *srcOpnd = stInsn->GetOperand(stIdx); + + CG_ASSERT(resOpnd && srcOpnd, "null ptr check"); + CG_ASSERT(resOpnd->GetSize() == srcOpnd->GetSize(), "For stack location, the size of src and dst should be same."); + CG_ASSERT(version & (kOptVersionStpZero | kOptVersionStrZero), "version is invalid."); + + ldInsn->SetOperand(ldIdx, srcOpnd); + if (resRegOpnd->IsOfFloatOrSIMDClass()) { + // fmov + ldInsn->SetMOP(resOpnd->GetSize() == 64 ? MOP_xvmovd : MOP_xvmovs); + } else { + ldInsn->SetMOP(resOpnd->GetSize() == 64 ? MOP_xmovrr : MOP_wmovrr); + } + + // Update DU-UD info. + // 1: remove use of store insn. ([MEM]) + // 2: remove def of load insn. ([MEM]) + RemovDUUD(stInsn, ldInsn); + + // Add comment. + std::string newComment = ldInsn->GetComment(); + if (version & kOptVersionStpZero) { + newComment += "; stp-load zero version."; + } else { + newComment += "; str-load zero version."; + } + ldInsn->AddComment(newComment); + + if (cgfunc->cg->GenerateVerboseAsm() && cgfunc->cg->GenerateTestInfo()) { + // For test framework. + Riscv64CGFunc *a64cgfunc = static_cast(cgfunc); + + if (version == kOptVersionStpZero) { + std::string comment = "stp_id: "; + comment += std::to_string(gTestInfoStoreID); + + const char *str1 = comment.c_str(); + Insn *commentInsn = cgfunc->cg->BuildInstruction(MOP_comment, a64cgfunc->CreateCommentOperand(str1)); + stInsn->bb->InsertInsnAfter(stInsn, commentInsn); + + comment = "mov_pid: "; + comment += std::to_string(gTestInfoStoreID); + comment += "_"; + comment += std::to_string(stIdx); + comment += "-"; + comment += std::to_string(gTestInfoMovID++); + + const char *str2 = comment.c_str(); + commentInsn = cgfunc->cg->BuildInstruction(MOP_comment, a64cgfunc->CreateCommentOperand(str2)); + ldInsn->bb->InsertInsnAfter(ldInsn, commentInsn); + } else { + std::string comment = "str_id: "; + comment += std::to_string(gTestInfoStoreID); + + const char *str1 = comment.c_str(); + Insn *commentInsn = cgfunc->cg->BuildInstruction(MOP_comment, a64cgfunc->CreateCommentOperand(str1)); + stInsn->bb->InsertInsnAfter(stInsn, commentInsn); + + comment = "mov_id: "; + comment += std::to_string(gTestInfoStoreID); + comment += "-"; + comment += std::to_string(gTestInfoMovID++); + + const char *str2 = comment.c_str(); + commentInsn = cgfunc->cg->BuildInstruction(MOP_comment, a64cgfunc->CreateCommentOperand(str2)); + ldInsn->bb->InsertInsnAfter(ldInsn, commentInsn); + } + } +} + +/* Optimize: store x100, [MEM] + ... // May exist branches. + load x200, [MEM] + ==> + OPT_VERSION_STP_LIVE / OPT_VERSION_STR_LIVE: + store x100, [MEM] + ... // May exist branches. if x100 not dead here. + mov x200, x100 + OPT_VERSION_STP_DIE / OPT_VERSION_STR_DIE: + store x100, [MEM] + mov x9000(new reg), x100 + ... // May exist branches. if x100 dead here. + mov x200, x9000 + + Note: x100 may be wzr/xzr registers. + */ +void Riscv64StoreLoadOpt::DoStoreLoadOpt() { + MapleSet::iterator itSet2; + MapleSet::iterator itSetNext2; + + FOR_ALL_BB(bb, cgfunc) { + FOR_BB_INSNS(insn, bb) { + if (!insn->IsMachineInstruction()) { + continue; + } + + if (insn->IsStore()) { + gTestInfoStoreID++; + gTestInfoMovID = 0; + if (insn->uses[0]) { + CG_ASSERT(insn->GetOpnd(0) != nullptr, "Internal error."); + + RegOperand *regOpnd = static_cast(insn->GetOpnd(0)); + if (regOpnd && regOpnd->IsZeroRegister()) { + MapleSet &setUses = *(insn->uses[0]); + for (itSet2 = setUses.begin(); itSet2 != setUses.end(); itSet2 = itSetNext2) { + itSetNext2 = itSet2; + itSetNext2++; + + const DataInsnInfo &ldrInfo = *itSet2; + if (ldrInfo.IsDirty()) { + continue; + } + + Insn *ldrInsn = ldrInfo.GetInsn(); + + // Currently we don't support useInsn is ldp insn. + if (ldrInsn->GetResultNum() > 1) { + continue; + } + + // If load has multiple definition, continue. + CG_ASSERT(ldrInsn->defs[ldrInfo.GetIndex()], "load insn should have definitions."); + CG_ASSERT(ldrInfo.GetIndex() == 1, "memory address should be 1."); + if (ldrInsn->defs[1]->size() > 1 || ldrInsn->bb->is_cleanup) { + continue; + } + + // If load has multigen property, continue. + if (ldrInsn->defs[1]->begin()->IsMulGen()) { + continue; + } + + if (SCHDDUMP) { + LogInfo::MapleLogger() << "Do store-load optimization, str -- wzr/xzr version: "; + LogInfo::MapleLogger() << cgfunc->GetName() << std::endl; + LogInfo::MapleLogger() << "Store insn: "; + insn->dump(); + LogInfo::MapleLogger() << "Load insn: "; + ldrInsn->dump(); + } + DoLoadZeroToMoveTransfer(insn, 0, ldrInsn, ldrInfo.GetIndex(), kOptVersionStrZero); + } + + continue; + } + + if (insn->defs[0] == nullptr) { + LogInfo::MapleLogger() << "Warning: use without def." << std::endl; + continue; + } + + // Find x100's definition insn. + if (insn->defs[0]->size() != 1 || insn->bb->is_cleanup) { + continue; + } + + DataInsnInfo insnInfo = *(insn->defs[0]->begin()); + Insn *defInsn = insnInfo.GetInsn(); + int index = insnInfo.GetProperty() & DataInsnInfo::kIndexQuickcalc; + + MapleSet &setUses = *(insn->uses[0]); + for (itSet2 = setUses.begin(); itSet2 != setUses.end(); itSet2 = itSetNext2) { + itSetNext2 = itSet2; + itSetNext2++; + + const DataInsnInfo &ldrInfo = *itSet2; + if (ldrInfo.IsDirty()) { + continue; + } + + Insn *ldrInsn = ldrInfo.GetInsn(); + + // Currently we don't support useInsn is ldp insn. + if (ldrInsn->GetResultNum() > 1) { + continue; + } + + // If load has multiple definition, continue. + CG_ASSERT(ldrInsn->defs[ldrInfo.GetIndex()], "load insn should have definitions."); + CG_ASSERT(ldrInfo.GetIndex() == 1, "memory address should be 1."); + if (ldrInsn->defs[1]->size() > 1 || ldrInsn->bb->is_cleanup) { + continue; + } + + // If load has multigen property, continue. + if (ldrInsn->defs[1]->begin()->IsMulGen()) { + continue; + } + + // Check if use operand of store is live at load insn. + if (IsLiveAtInsn(defInsn, index, insn, ldrInsn)) { + // Do the optimization. + /* Optimize: store x100, [MEM] + ... // May exist branches. + load x200, [MEM] + ==> + store x100, [MEM] + ... // May exist branches + mov x200, x100 + */ + if (SCHDDUMP) { + LogInfo::MapleLogger() << "Do store-load optimization 1: str version"; + LogInfo::MapleLogger() << cgfunc->GetName() << std::endl; + LogInfo::MapleLogger() << "Store insn: "; + insn->dump(); + LogInfo::MapleLogger() << "Load insn: "; + ldrInsn->dump(); + } + DoLoadToMoveTransfer(insn, 0, ldrInsn, ldrInfo.GetIndex(), kOptVersionStrLive, insnInfo); + continue; + } else { + // Do the optimization. + /* Optimize: store x100, [MEM] + ... // May exist branches. x100 dead here. + load x200, [MEM] + ==> + store x100, [MEM] + mov x9000(new reg), x100 + ... // May exist branches. x100 dead here. + mov x200, x9000 + */ + if (SCHDDUMP) { + LogInfo::MapleLogger() << "Do store-load optimization 2: str version"; + LogInfo::MapleLogger() << cgfunc->GetName() << std::endl; + LogInfo::MapleLogger() << "Store insn: "; + insn->dump(); + LogInfo::MapleLogger() << "Load insn: "; + ldrInsn->dump(); + } + + DoLoadToMoveTransfer(insn, 0, ldrInsn, ldrInfo.GetIndex(), kOptVersionStrDie, insnInfo); + continue; + } + } + + if (setUses.empty()) { + insn->uses[0] = nullptr; + break; + } + } + } + } + } +} + +/* Optimize: store x100, [MEM] + ... // May exist branches. + load x200, [MEM] + ==> + OPT_VERSION_STP_LIVE / OPT_VERSION_STR_LIVE: + store x100, [MEM] + ... // May exist branches. if x100 not dead here. + mov x200, x100 + OPT_VERSION_STP_DIE / OPT_VERSION_STR_DIE: + store x100, [MEM] + mov x9000(new reg), x100 + ... // May exist branches. if x100 dead here. + mov x200, x9000 + + Note: x100 may be wzr/xzr registers. + */ + +void Riscv64StoreLoadOpt::run() { + // Give up this optimization if a non-escaped object has been allocated on stack, + // because the DU information collected at this CGIR level may not be accurate. + if (cgfunc->HasNonescapedVar()) { + return; + } + + MemPool *phaseMp = mempoolctrler.NewMemPool("CG StoreLoadOpt pool"); + MapleAllocator phaseAllocator(phaseMp); + MapleUnorderedMap> tmpInsns(phaseAllocator.Adapter()); + moveInsn = &tmpInsns; + + FindBackEdge(); + DoStoreLoadOpt(); + + if (SCHDDUMP) { + LogInfo::MapleLogger() << "$$$$$$$$$$$$$$$$$ End store-load optimization. $$$$$$$$$$$$$$$$$$$$" << std::endl; + + FOR_ALL_BB(bb, cgfunc) { + rd->DumpUDChain(bb); + rd->DumpDUChain(bb); + rd->DumpWAWDependence(bb); + } + } + + mempoolctrler.DeleteMemPool(phaseMp); +} + +} // namespace maplebe diff --git a/mapleall/maple_be/src/cg/riscv64/riscv64_vec_insn_slct.cpp b/mapleall/maple_be/src/cg/riscv64/riscv64_vec_insn_slct.cpp new file mode 100644 index 0000000..b880f4c --- /dev/null +++ b/mapleall/maple_be/src/cg/riscv64/riscv64_vec_insn_slct.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#include "riscv64_insn.h" +#include "riscv64_cg.h" +#include "insn.h" +#include "cg_assert.h" +#include + +namespace maplebe { +void Riscv64CGFunc::SelectVecAdd(Operand *resopnd, Operand *opnd0, Operand *opnd1, PrimType prmtyp) { + Operand::OperandType opnd0ty = opnd0->op_kind_; + Operand::OperandType opnd1ty = opnd1->op_kind_; + RegOperand *resOpnd = CreateRegisterOperandOfType(prmtyp); + Operand *newOpnd0 = opnd0; + Operand *newOpnd1 = opnd1; + if (opnd0ty != Operand::Opd_Register) { + newOpnd0 = SelectCopy(opnd0, prmtyp, prmtyp); + } + if (opnd1ty != Operand::Opd_Register) { + newOpnd1 = SelectCopy(opnd1, prmtyp, prmtyp); + } + MOperator mop; + switch (prmtyp) { + case PTY_v4i32: { + mop = MOP_vadd32rrr; + break; + } + case PTY_v2i64: + case PTY_v8i16: + case PTY_v16i8: + case PTY_v2f64: + case PTY_v4f32: + CHECK_FATAL(false, "NYI"); + default: + CHECK_FATAL(false, "not supposed to be here"); + } + curbb->AppendInsn(cg->BuildInstruction(mop, resopnd, newOpnd0, newOpnd1)); +} +} // namespace maplebe diff --git a/mapleall/maple_be/src/cg/script/gen_mop.py b/mapleall/maple_be/src/cg/script/gen_mop.py deleted file mode 100755 index 03212ce..0000000 --- a/mapleall/maple_be/src/cg/script/gen_mop.py +++ /dev/null @@ -1,113 +0,0 @@ -# -# Copyright (c) [2020] Huawei Technologies Co., Ltd. All rights reserved. -# -# Licensed under the Mulan Permissive Software License v2. -# You can use this software according to the terms and conditions of the MulanPSL - 2.0. -# You may obtain a copy of MulanPSL - 2.0 at: -# -# https://opensource.org/licenses/MulanPSL-2.0 -# -# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR -# FIT FOR A PARTICULAR PURPOSE. -# See the MulanPSL - 2.0 for more details. -# -#open(my $aarch64_isa.def_h, '<', "aarch64isa.def.in") or die "can't open aarch64isa.def.in"; -#open(my $aarch64_isa.def, '>', "aarch64isa.def") or die "can't open aarch64isa.def"; -#print $aarch64_isa.def "\/\/Do not modify this file manually\n"; -#my $insn_count=1; -#while(my $line = <$aarch64_isa.def_h>) { -# if ($line =~ /\/\//){ -# next; -# } -# elsif ($line =~ /( )*MOP_/){ -# $line =~ s/( )*MOP_/\#define MOP_/; -# $line =~ s/,/ $insn_count/; -# $insn_count++; -# }else { -# next; -# } -# print $aarch64_isa.def $line; -#} -#print $aarch64_isa.def "\#define MOP_last ".$insn_count."\n"; -#close $aarch64_isa.def; -#close $aarch64_isa.def_h; - -import sys -#import getopt - -''' read line {...} and process it ''' - -#def readmore(infile): -# return infile.read(4096) - -def check(line): - n = len(line) - if line[0] != '{': - raise Exception("Should begin with '{'"); - if line[n-1] != ',': - raise Exception("Record delimitter is missing"); - - s = 0 - for i in range(0,n): - c = line[i] - if c == '{': - s += 1 - elif c == '}': - s -= 1 - - if s < 0: - raise Exception("Unmatched '}'") - if s > 0: - raise Exception("Unmatched '{'") - -def process_line(line): - line = line.strip() - if len(line) == 0: - return - - if line[0] == '/' and line[1] == '/': - # comment - return - - try: - check(line) - except: - print "'"+line+"' is invalid" - return - - k = line.find(',',0) - key = line[1:k] - print key.strip() + "," - -def process(mdfilename): - with open( mdfilename, "r" ) as infile: - for l in infile: - process_line(l) - -def help(): - print "Usage: " + sys.argv[0] + " md-file" - -def main(): - # try: - # opts, args = getopt.getoopt(sys.argv[1:], "h", ["help"]) - #except getopt.error, msg: - # print msg - # print "for help, use --help" - # sys.exit(-1) - if len(sys.argv) != 2: - help() - return - - process(sys.argv[1]) - - #for o, a in opts: - # if o in ("-h","--help"): - # help() - # sys.exit(0) - - #for arg in args: - # process(arg) - -if __name__ == "__main__": - main() diff --git a/mapleall/maple_be/src/cg/script/gen_mopfor_gn.py b/mapleall/maple_be/src/cg/script/gen_mopfor_gn.py deleted file mode 100755 index 9e375bc..0000000 --- a/mapleall/maple_be/src/cg/script/gen_mopfor_gn.py +++ /dev/null @@ -1,82 +0,0 @@ -# -# Copyright (c) [2020] Huawei Technologies Co., Ltd. All rights reserved. -# -# Licensed under the Mulan Permissive Software License v2. -# You can use this software according to the terms and conditions of the MulanPSL - 2.0. -# You may obtain a copy of MulanPSL - 2.0 at: -# -# https://opensource.org/licenses/MulanPSL-2.0 -# -# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR -# FIT FOR A PARTICULAR PURPOSE. -# See the MulanPSL - 2.0 for more details. -# - -import os, sys -import time - -def check(line): - n = len(line) - if line[0] != '{': - raise Exception("Should begin with '{'"); - if line[n-1] != ',': - raise Exception("Record delimitter is missing"); - - s = 0 - for i in range(0,n): - c = line[i] - if c == '{': - s += 1 - elif c == '}': - s -= 1 - - if s < 0: - raise Exception("Unmatched '}'") - if s > 0: - raise Exception("Unmatched '{'") - -def process_line(line): - line = line.strip() - if len(line) == 0: - return None - - if line[0] == '/' and line[1] == '/': - # comment - return None - - try: - check(line) - except: - print ("'"+line+"' is invalid") - return None - - k = line.find(',',0) - key = line[1:k] - return key.strip() + ",\n" - - -def process(mdfilename, newmdfilename): - if(os.path.exists(newmdfilename) and (os.stat(mdfilename).st_mtime < os.stat(newmdfilename).st_mtime)): - pass - else: - with open( mdfilename, "r" ) as infile: - lines = [] - for l in infile: - if(process_line(l) != None): - lines.append(process_line(l)) - with open(newmdfilename, "w") as outfile: - for line in lines: - outfile.write(line) -# print lines - -def help(): - print ("Usage: " + sys.argv[0] + " md-file") - -def main(): - if len(sys.argv) != 3: - help(); - return - process(sys.argv[1], sys.argv[2]) -if __name__ == "__main__": - main() diff --git a/mapleall/maple_be/src/cg/super_bb.cpp b/mapleall/maple_be/src/cg/super_bb.cpp index bb83847..19e43d4 100644 --- a/mapleall/maple_be/src/cg/super_bb.cpp +++ b/mapleall/maple_be/src/cg/super_bb.cpp @@ -593,6 +593,7 @@ void SuperBBBuilder::SplitProcess() { if (insn->next) { oldBB = onlyBB; onlyBB = CreateNewFallThroughBB(onlyBB); + oldBB->SetKind(BB::kBBCall); haveSetFirst = false; } } @@ -703,11 +704,14 @@ BB *SuperBBBuilder::CreateNewFallThroughBB(BB *prevBB) { CG_ASSERT(itPrev!=nextBB->preds.end(),"Error: SplitProcess nextBB pred not found"); nextBB->preds.erase(itPrev); nextBB->preds.push_back(newBB); +#if BUGFIX_REMOVED nextBB->SetKind(prevBB->GetKind()); prevBB->SetKind(BB::kBBFallthru); +#endif } prevBB->succs.clear(); } + newBB->SetKind(prevBB->GetKind()); newBB->preds.push_back(prevBB); prevBB->succs.push_back(newBB); diff --git a/mapleall/maple_be/src/cg/x86/x86_cg.cpp b/mapleall/maple_be/src/cg/x86/x86_cg.cpp index 43700fc..51e2257 100644 --- a/mapleall/maple_be/src/cg/x86/x86_cg.cpp +++ b/mapleall/maple_be/src/cg/x86/x86_cg.cpp @@ -22,9 +22,11 @@ namespace maplebe { #include "x86_opnd.def" +#define DEFINE_MOP(op,a2,a3,a4,a5,a6,a7,a8,a9) {op,a2,a3,a4,a5,a6,a7,a8,a9}, const X86MD X86CG::thex86machine[MOP_last] = { #include "x86_md.def" }; +#undef DEFINE_MOP void X86Insn::CheckOpnd(Operand *opnd, OpndProp *prop) { X86OpndProp *mopd = static_cast(prop); diff --git a/mapleall/maple_be/src/cg/x86/x86_md.def b/mapleall/maple_be/src/cg/x86/x86_md.def deleted file mode 100644 index 71a2ca1..0000000 --- a/mapleall/maple_be/src/cg/x86/x86_md.def +++ /dev/null @@ -1,681 +0,0 @@ -/* - * Copyright (c) [2020] Huawei Technologies Co., Ltd. All rights reserved. - * - * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. - * You can use this software according to the terms and conditions of the MulanPSL - 2.0. - * You may obtain a copy of MulanPSL - 2.0 at: - * - * https://opensource.org/licenses/MulanPSL-2.0 - * - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR - * FIT FOR A PARTICULAR PURPOSE. - * See the MulanPSL - 2.0 for more details. - */ - - // MOP_undef - {MOP_undef, {MOPD_Undef, MOPD_Undef, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, nullptr, nullptr}, - // arithmetic - // MOP_add32rr - {MOP_add32rr, {MOPD_Reg32ID, MOPD_Reg, MOPD_Reg, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "addl", "2,0"}, - // MOP_add32ri, - {MOP_add32ri, {MOPD_Reg32ID, MOPD_Reg, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "addl", "2,0"}, - // MOP_add32rm, - {MOP_add32rm, {MOPD_Reg32ID, MOPD_Reg, MOPD_Mem, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "addl", "2,0"}, - // MOP_add32mr, - // MOP_add32mi, - // MOP_add64rr, - {MOP_add64rr, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "addq", "2,0"}, - // MOP_add64ri, - {MOP_add64ri, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "addq", "2,0"}, - // MOP_add64rm, - {MOP_add64rm, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "addq", "2,0"}, - // MOP_add64mr, - // MOP_add64mi, - // MOP_addsdrr, - {MOP_addsdrr, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "addsd", "2,0"}, - // MOP_addsdrm, - {MOP_addsdrm, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "addsd", "2,0"}, - //MOP_addssrr, - {MOP_addssrr, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "addss", "2,0"}, - //MOP_addssrm, - {MOP_addssrm, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "addss", "2,0"}, - //MOP_addc32rr, - {MOP_addc32rr, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Reg32ID, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "adcl", "2,0"}, - //MOP_addc32ri, - {MOP_addc32ri, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "adcl", "2,0"}, - //MOP_addc32rm, - {MOP_addc32rm, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "adcl", "2,0"}, - //MOP_addc32mr, - //MOP_addc32mi, - //MOP_div32r, // enhance when the operands is: eax edx eax edx int32 - {MOP_div32r, {MOPD_RAX32D, MOPD_RDX32D, MOPD_RDX32S, MOPD_RAX32S, MOPD_Reg32IS}, USESPECREG, "divl", "4"}, - //MOP_div32m, - {MOP_div32m, {MOPD_RAX32D, MOPD_RDX32D, MOPD_RDX32S, MOPD_RAX32S, MOPD_Mem32S}, USESPECREG, "divl", "4"}, - //MOP_div64r, - {MOP_div64r, {MOPD_RAX64D, MOPD_RDX64D, MOPD_RDX64S, MOPD_RAX64S, MOPD_Reg64IS}, USESPECREG, "divq", "4"}, - //MOP_div64m, - {MOP_div64m, {MOPD_RAX64D, MOPD_RDX64D, MOPD_RDX64S, MOPD_RAX64S, MOPD_Mem64S}, USESPECREG, "divq", "4"}, - //MOP_idiv32r, - {MOP_idiv32r, {MOPD_RAX32D, MOPD_RDX32D, MOPD_RDX32S, MOPD_RAX32S, MOPD_Reg32IS}, USESPECREG, "idivl", "4"}, - //MOP_idiv32m, - {MOP_idiv32m, {MOPD_RAX32D, MOPD_RDX32D, MOPD_RDX32S, MOPD_RAX32S, MOPD_Mem32S}, USESPECREG, "idivl", "4"}, - //MOP_idiv64r, - {MOP_idiv64r, {MOPD_RAX64D, MOPD_RDX64D, MOPD_RDX64S, MOPD_RAX64S, MOPD_Reg64IS}, USESPECREG, "idivq", "4"}, - //MOP_idiv64m, - {MOP_idiv64m, {MOPD_RAX64D, MOPD_RDX64D, MOPD_RDX64S, MOPD_RAX64S, MOPD_Mem64S}, USESPECREG, "idivq", "4"}, - //MOP_imul32rr, - {MOP_imul32rr, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "imull", "2,0"}, - //MOP_imul32ri, - {MOP_imul32ri, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "imull", "2,0"}, - //MOP_imul32rm, - {MOP_imul32rm, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "imull", "2,0"}, - //MOP_imul64rr, - {MOP_imul64rr, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "imulq", "2,0"}, - //MOP_imul64ri, - {MOP_imul64ri, {MOPD_Reg64ID, MOPD_Reg64ID, MOPD_Imm64, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "imulq", "2,0"}, - //MOP_imul64rm, - {MOP_imul64rm, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "imulq", "2,0"}, - //MOP_mul32, - {MOP_mul32, {MOPD_RAX32D, MOPD_RDX32S, MOPD_RAX32S, MOPD_Reg32IS, MOPD_Undef}, USESPECREG, "mull", "3"}, - //MOP_mul64, - {MOP_mul64, {MOPD_RAX64D, MOPD_RDX64S, MOPD_RAX64S, MOPD_Reg64IS, MOPD_Undef}, USESPECREG, "mulq", "3"}, - //MOP_mulsdrr, - {MOP_mulsdrr, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "mulsd", "2,0"}, - //MOP_mulsdrm, - {MOP_mulsdrm, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "mulsd", "2,0"}, - //MOP_mulssrr, - {MOP_mulssrr, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "mulss", "2,0"}, - //MOP_mulssrm, - {MOP_mulssrm, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "mulss", "2,0"}, - //MOP_inc32r, - {MOP_inc32r, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "incl", "0"}, - //MOP_inc64r, - {MOP_inc64r, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "incq", "0"}, - //MOP_inc32m, - //MOP_inc64m, - //MOP_dec32r, - {MOP_dec32r, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "decl", "0"}, - //MOP_dec64r, - {MOP_dec64r, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "decq", "0"}, - //MOP_dec32m, - //MOP_dec64m, - //MOP_xchg32rr, - {MOP_xchg32rr, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "xchgl", "2,0"}, - //MOP_xchg32rm, - {MOP_xchg32rm, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "xchgl", "2,0"}, - //MOP_xchg64rr, - {MOP_xchg64rr, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "xchgq", "2,0"}, - //MOP_xchg64rm, - {MOP_xchg64rm, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "xchgq", "2,0"}, - //MOP_neg32r, - {MOP_neg32r, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "negl", "0"}, - //MOP_neg32m, - //MOP_neg64r, - {MOP_neg64r, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "negq", "0"}, - //MOP_neg64m, - //MOP_sqrtss, - {MOP_sqrtss, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "sqrtss", "0,1"}, - //MOP_sqrtsd, - {MOP_sqrtsd, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "sqrtsd", "0,1"}, - //MOP_not32r, - {MOP_not32r, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "notl", "0"}, - //MOP_not32m, - //MOP_not64r, - {MOP_not64r, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "notq", "0"}, - //MOP_not64m, - //MOP_sub32rr, - {MOP_sub32rr, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "subl", "2,0"}, - //MOP_sub32ri, - {MOP_sub32ri, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "subl", "2,0"}, - //MOP_sub32rm, - {MOP_sub32rm, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "subl", "2,0"}, - //MOP_sub32mr, - //MOP_sub32mi, - //MOP_sub64rr, - {MOP_sub64rr, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "subq", "2,0"}, - //MOP_sub64ri, - {MOP_sub64ri, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "subq", "2,0"}, - //MOP_sub64rm, - {MOP_sub64rm, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "subq", "2,0"}, - //MOP_sub64mr, - //MOP_sub64mi, - //MOP_subsdrr, - {MOP_subsdrr, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "subsd", "2,0"}, - //MOP_subsdrm, - {MOP_subsdrm, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "subsd", "2,0"}, - //MOP_subssrr, - {MOP_subssrr, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "subss", "2,0"}, - //MOP_subssrm, - {MOP_subssrm, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "subss", "2,0"}, - //MOP_divssrr - {MOP_divssrr, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "divss", "2,0"}, - //MOP_divssrm, - {MOP_divssrm, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "divss", "2,0"}, - //MOP_divsdrr - {MOP_divsdrr, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "divsd", "2,0"}, - //MOP_divsdrm, - {MOP_divsdrm, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "divsd", "2,0"}, - // logic - //MOP_and32rr, - {MOP_and32rr, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "andl", "2,0"}, - //MOP_and32ri, - {MOP_and32ri, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "andl", "2,0"}, - //MOP_and32rm, - {MOP_and32rm, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "andl", "2,0"}, - //MOP_and32mr, - //MOP_and32mi, - //MOP_and64rr, - {MOP_and64rr, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "andq", "2,0"}, - //MOP_and64ri, - {MOP_and64ri, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "andq", "2,0"}, - //MOP_and64rm, - {MOP_and64rm, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "andq", "2,0"}, - //MOP_andpsrr, // FIXME: this is actually a vector operator - {MOP_andpsrr, {MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "andps", "2,0"}, - //MOP_andpdrr, // FIXME: this is actually a vector operator - {MOP_andpdrr, {MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "andpd", "2,0"}, - //MOP_andnpsrr, // FIXME: this is actually a vector operator - {MOP_andnpsrr, {MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "andnps", "2,0"}, - //MOP_andnpdrr, // FIXME: this is actually a vector operator - {MOP_andnpdrr, {MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "andnpd", "2,0"}, - //MOP_orpsrr, // FIXME: this is actually a vector operator - {MOP_orpsrr, {MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "orps", "2,0"}, - //MOP_orpdrr, // FIXME: this is actually a vector operator - {MOP_orpdrr, {MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "orpd", "2,0"}, - //MOP_and64mr, - //MOP_and64mi, - //MOP_or32rr, - {MOP_or32rr, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "orl", "2,0"}, - //MOP_or32ri, - {MOP_or32ri, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "orl", "2,0"}, - //MOP_or32rm, - {MOP_or32rm, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "orl", "2,0"}, - //MOP_or32mr, - //MOP_or32mi, - //MOP_or64rr, - {MOP_or64rr, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "orq", "2,0"}, - //MOP_or64ri, - {MOP_or64ri, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "orq", "2,0"}, - //MOP_or64rm, - {MOP_or64rm, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "orq", "2,0"}, - //MOP_or64mr, - //MOP_or64mi, - //MOP_ori32, - //MOP_ori64, - //MOP_ror32, - {MOP_ror32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "rorl", "2,0"}, - //MOP_ror64, - {MOP_ror64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "rorq", "2,0"}, - //MOP_rori32, - {MOP_rori32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "rorl", "2,0"}, - //MOP_rori64, - {MOP_rori64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "rorq", "2,0"}, - //MOP_rol32, - {MOP_rol32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "roll", "2,0"}, - //MOP_rol64, - {MOP_rol64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "rolq", "2,0"}, - //MOP_roli32, - {MOP_roli32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "roll", "2,0"}, - //MOP_roli64, - {MOP_roli64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "rolq", "2,0"}, - //MOP_xor32rr, - {MOP_xor32rr, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "xorl", "2,0"}, - //MOP_xor32ri, - {MOP_xor32ri, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "xorl", "2,0"}, - //MOP_xor32rm, - {MOP_xor32rm, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "xorl", "2,0"}, - //MOP_xor64rr, - {MOP_xor64rr, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "xorq", "2,0"}, - //MOP_xor64ri, - {MOP_xor64ri, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "xorq", "2,0"}, - //MOP_xor64rm, - {MOP_xor64rm, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Mem, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "xorq", "2,0"}, - //MOP_xorps32rr, - {MOP_xorps32rr, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "xorps", "2,0"}, - //MOP_xorps32rm, - {MOP_xorps32rm, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "xorps", "2,0"}, - //MOP_xorpd64rr, - {MOP_xorpd64rr, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "xorpd", "2,0"}, - //MOP_xorpd64rm, // fixme mem here is 128 - {MOP_xorpd64rm, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "xorpd", "2,0"}, - //MOP_xor64mr, - //MOP_xor64mi, - //MOP_ori32, - //MOP_ori64, - //MOP_sar32, - {MOP_sar32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RCX8S, MOPD_Undef, MOPD_Undef}, ISX86STYLE | USESPECREG, "sarl", "2,0"}, - //MOP_sar64, - {MOP_sar64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RCX8S, MOPD_Undef, MOPD_Undef}, ISX86STYLE | USESPECREG, "sarq", "2,0"}, - //MOP_sari32, - {MOP_sari32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "sarl", "2,0"}, - //MOP_sari64, - {MOP_sari64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "sarq", "2,0"}, - //MOP_shl32, - {MOP_shl32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RCX8S, MOPD_Undef, MOPD_Undef}, ISX86STYLE | USESPECREG, "shll", "2,0"}, - //MOP_shld32, - {MOP_shld32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Undef}, ISX86STYLE, "shldl", "2,0"}, - //MOP_shldi32, - {MOP_shldi32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Imm32, MOPD_Undef}, ISX86STYLE, "shldl", "2,0"}, - //MOP_shrd32, - {MOP_shrd32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Undef}, ISX86STYLE, "shrdl", "2,0"}, - //MOP_shrdi32, - {MOP_shrdi32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Imm32, MOPD_Undef}, ISX86STYLE, "shrdl", "2,0"}, - //MOP_shl64, - {MOP_shl64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RCX8S, MOPD_Undef, MOPD_Undef}, ISX86STYLE | USESPECREG, "shlq", "0"}, - //MOP_shli32, - {MOP_shli32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "shll", "2,0"}, - //MOP_shli64, - {MOP_shli64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "shlq", "2,0"}, - //MOP_shr32, - {MOP_shr32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RCX8S, MOPD_Undef, MOPD_Undef}, ISX86STYLE | USESPECREG, "shrl", "0"}, - //MOP_shr64, - {MOP_shr64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RCX8S, MOPD_Undef, MOPD_Undef}, ISX86STYLE | USESPECREG, "shlr", "0"}, - //MOP_shri32, - {MOP_shri32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "shrl", "2,0"}, - //MOP_shri64, - {MOP_shri64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "shrq", "2,0"}, - //MOP_minssrr, - {MOP_minssrr, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "minss", "2,0"}, - //MOP_minssrm, - {MOP_minssrm, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "minss", "2,0"}, - //MOP_minsdrr, - {MOP_minsdrr, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "minsd", "2,0"}, - //MOP_minsdrm, - {MOP_minsdrm, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "minsd", "2,0"}, - //MOP_maxssrr, - {MOP_maxssrr, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "maxss", "2,0"}, - //MOP_maxssrm, - {MOP_maxssrm, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "maxss", "2,0"}, - //MOP_maxsdrr, - {MOP_maxsdrr, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "maxsd", "2,0"}, - //MOP_maxsdrm, - {MOP_maxsdrm, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, ISX86STYLE, "maxsd", "2,0"}, - //MOP_cmp32rr, - {MOP_cmp32rr, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef}, 0, "cmpl", "2,1"}, - //MOP_cmp32ri, - {MOP_cmp32ri, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, 0, "cmpl", "2,1"}, - //MOP_cmp32rm, - {MOP_cmp32rm, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, 0, "cmpl", "2,1"}, - //MOP_cmp64rr, - {MOP_cmp64rr, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef}, 0, "cmpq", "2,1"}, - //MOP_cmp64ri, - {MOP_cmp64ri, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, 0, "cmpq", "2,1"}, - //MOP_cmp64rm, - {MOP_cmp64rm, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, 0, "cmpq", "2,1"}, - //MOP_comisdrr, - {MOP_comisdrr, {MOPD_RegCCD, MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef}, 0, "comisd", "2,1"}, - //MOP_comisdrm, - {MOP_comisdrm, {MOPD_RegCCD, MOPD_Reg64FS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, 0, "comisd", "2,1"}, - //MOP_comissrr, - {MOP_comissrr, {MOPD_RegCCD, MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef}, 0, "comiss", "2,1"}, - //MOP_comissrm, - {MOP_comissrm, {MOPD_RegCCD, MOPD_Reg32FS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, 0, "comiss", "2,1"}, - //MOP_ucomisdrr, - {MOP_ucomisdrr, {MOPD_RegCCD, MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef}, 0, "ucomisd", "2,1"}, - //MOP_ucomisdrm, - {MOP_ucomisdrm, {MOPD_RegCCD, MOPD_Reg64FS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, 0, "ucomisd", "2,1"}, - //MOP_ucomissrr, - {MOP_ucomissrr, {MOPD_RegCCD, MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef}, 0, "ucomiss", "2,1"}, - //MOP_ucomissrm, - {MOP_ucomissrm, {MOPD_RegCCD, MOPD_Reg32FS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, 0, "ucomiss", "2,1"}, - //MOP_cmpssrr, - {MOP_cmpssrr, {MOPD_Reg, MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Imm32, MOPD_Undef}, ISX86STYLE, "cmpss", "3,2,0"}, - //MOP_cmpssrm, - {MOP_cmpssrm, {MOPD_Reg, MOPD_Reg32FS, MOPD_Reg32FS, MOPD_Mem32S, MOPD_Undef}, ISX86STYLE, "cmpss", "3,2,0"}, - //MOP_cmpsdrr, - {MOP_cmpsdrr, {MOPD_Reg, MOPD_Reg64FS, MOPD_Reg64FS, MOPD_Imm32, MOPD_Undef}, ISX86STYLE, "cmpsd", "3,2,0"}, - //MOP_cmpsdrm, - {MOP_cmpsdrm, {MOPD_Reg, MOPD_Reg64FS, MOPD_Mem64S, MOPD_Imm32, MOPD_Undef}, ISX86STYLE, "cmpsd", "3,2,0"}, - //MOP_test32rr, - {MOP_test32rr, {MOPD_RegCCD, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef}, 0, "testl", "2,1"}, - //MOP_test32ri, - {MOP_test32ri, {MOPD_RegCCD, MOPD_Reg32IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, 0, "testl", "2,1"}, - //MOP_test32rm, - {MOP_test32rm, {MOPD_RegCCD, MOPD_Reg32IS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef}, 0, "testl", "2,1"}, - //MOP_test64rr, - {MOP_test64rr, {MOPD_RegCCD, MOPD_Reg64IS, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef}, 0, "testq", "2,1"}, - //MOP_test64ri, - {MOP_test64ri, {MOPD_RegCCD, MOPD_Reg64IS, MOPD_Imm32, MOPD_Undef, MOPD_Undef}, 0, "testq", "2,1"}, - //MOP_test64rm, - {MOP_test64rm, {MOPD_RegCCD, MOPD_Reg64IS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef}, 0, "testq", "2,1"}, - // program flow - //MOP_call, - {MOP_call, {MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "call", "0"}, - //MOP_icallr, - {MOP_icallr, {MOPD_Reg64IS, MOPD_Undef, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "call", "*0"}, - //MOP_icallm, - {MOP_icallm, {MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "call", "0"}, - //MOP_jb, - {MOP_jb, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jb", "1"}, - //MOP_jae, - {MOP_jae, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jae", "1"}, - //MOP_jp, - {MOP_jp, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jp", "1"}, - //MOP_jnp, - {MOP_jnp, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jnp", "1"}, - //MOP_je, - {MOP_je, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "je", "1"}, - //MOP_jne, - {MOP_jne, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jne", "1"}, - //MOP_jbe, - {MOP_jbe, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jbe", "1"}, - //MOP_ja, - {MOP_ja, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "ja", "1"}, - //MOP_jl, - {MOP_jl, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jl", "1"}, - //MOP_jge, - {MOP_jge, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jge", "1"}, - //MOP_jle, - {MOP_jle, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jle", "1"}, - //MOP_jg, - {MOP_jg, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jg", "1"}, - //MOP_jcxz, - {MOP_jcxz, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jcxz", "1"}, - //MOP_jecxz, - {MOP_jecxz, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jecxz", "1"}, - //MOP_jrcxz, - {MOP_jrcxz, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jrcxz", "1"}, - //MOP_js, - {MOP_js, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "js", "1"}, - //MOP_jns, - {MOP_jns, {MOPD_Reg, MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jns", "1"}, - //MOP_jmp, - {MOP_jmp, {MOPD_Label, MOPD_Undef, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jmp", "0"}, - //MOP_ijmpr, - {MOP_ijmpr, {MOPD_Reg64IS, MOPD_Undef, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jmp", "*0"}, - //MOP_ijmpm, - {MOP_ijmpm, {MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "jmp", "*0"}, - //MOP_leave, - {MOP_leave, {MOPD_Reg, MOPD_Reg, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "leave", ""}, - //MOP_ret, - {MOP_ret, {MOPD_Undef, MOPD_Undef, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "ret", ""}, - //MOP_reti, - {MOP_reti, {MOPD_Imm64, MOPD_Undef, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "ret", "0"}, - - //MOP_seta, - {MOP_seta, {MOPD_Reg8ID, MOPD_RegCCS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "seta", "0"}, - //MOP_setae, - {MOP_setae, {MOPD_Reg8ID, MOPD_RegCCS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "setae", "0"}, - - //MOP_setb, - {MOP_setb, {MOPD_Reg8ID, MOPD_RegCCS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "setb", "0"}, - //MOP_setbe, - {MOP_setbe, {MOPD_Reg8ID, MOPD_RegCCS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "setbe", "0"}, - - //MOP_setc, - {MOP_setc, {MOPD_Reg8ID, MOPD_RegCCS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "setc", "0"}, - //MOP_sete, - {MOP_sete, {MOPD_Reg8ID, MOPD_RegCCS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "sete", "0"}, - - //MOP_setg, - {MOP_setg, {MOPD_Reg8ID, MOPD_RegCCS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "setg", "0"}, - //MOP_setge, - {MOP_setge, {MOPD_Reg8ID, MOPD_RegCCS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "setge", "0"}, - - //MOP_setl, - {MOP_setl, {MOPD_Reg8ID, MOPD_RegCCS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "setl", "0"}, - //MOP_setle, - {MOP_setle, {MOPD_Reg8ID, MOPD_RegCCS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "setle", "0"}, - - //MOP_setp, - {MOP_setp, {MOPD_Reg8ID, MOPD_RegCCS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "setp", "0"}, - //MOP_setnp, - {MOP_setnp, {MOPD_Reg8ID, MOPD_RegCCS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "setnp", "0"}, - - //MOP_setne, - {MOP_setne, {MOPD_Reg8ID, MOPD_RegCCS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "setne", "0"}, - - // string operation - // data movement - //MOP_cmovb32, - {MOP_cmovb32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovb", "1,0"}, - //MOP_cmovae32, - {MOP_cmovae32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovae", "1,0"}, - //MOP_cmovp32, - {MOP_cmovp32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovp", "1,0"}, - //MOP_cmovnp32, - {MOP_cmovnp32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovnp", "1,0"}, - //MOP_cmove32, - {MOP_cmove32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmove", "1,0"}, - //MOP_cmovne32, - {MOP_cmovne32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovne", "1,0"}, - //MOP_cmovbe32, - {MOP_cmovbe32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovbe", "1,0"}, - //MOP_cmova32, - {MOP_cmova32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmova", "1,0"}, - //MOP_cmovl32, - {MOP_cmovl32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovl", "1,0"}, - //MOP_cmovge32, - {MOP_cmovge32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovge", "1,0"}, - //MOP_cmovle32, - {MOP_cmovle32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovle", "1,0"}, - //MOP_cmovg32, - {MOP_cmovg32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovg", "1,0"}, - //MOP_cmovs32, - {MOP_cmovs32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovs", "1,0"}, - //MOP_cmovz32, - {MOP_cmovz32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovz", "1,0"}, - //MOP_cmovo32, - {MOP_cmovo32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovo", "1,0"}, - //MOP_cmovns32, - {MOP_cmovns32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovns", "1,0"}, - //MOP_cmovb64, - {MOP_cmovb64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovbq", "1,0"}, - //MOP_cmovae64, - {MOP_cmovae64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovae", "1,0"}, - //MOP_cmovp64, - {MOP_cmovp64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovp", "1,0"}, - //MOP_cmovnp64, - {MOP_cmovnp64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovnp", "1,0"}, - //MOP_cmove64, - {MOP_cmove64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmove", "1,0"}, - //MOP_cmovne64, - {MOP_cmovne64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovne", "1,0"}, - //MOP_cmovbe64, - {MOP_cmovbe64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovbe", "1,0"}, - //MOP_cmova64, - {MOP_cmova64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmova", "1,0"}, - //MOP_cmovl64, - {MOP_cmovl64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovl", "1,0"}, - //MOP_cmovge64, - {MOP_cmovge64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovge", "1,0"}, - //MOP_cmovle64, - {MOP_cmovle64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovle", "1,0"}, - //MOP_cmovg64, - {MOP_cmovg64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovg", "1,0"}, - //MOP_cmovs64, - {MOP_cmovs64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovs", "1,0"}, - //MOP_cmovz64, - {MOP_cmovz64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovz", "1,0"}, - //MOP_cmovo64, - {MOP_cmovo64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovo", "1,0"}, - //MOP_cmovns64, - {MOP_cmovns64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_RegCCS, MOPD_Undef, MOPD_Undef}, ISCONDDEF, "cmovns", "1,0"}, - //MOP_ld8, - //MOP_ld16, - //MOP_ld32, - {MOP_ld32, {MOPD_Reg32ID, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movl", "1,0"}, - //MOP_ld64, - {MOP_ld64, {MOPD_Reg64ID, MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movq", "1,0"}, - //MOP_ldu8, - //MOP_ldu16, - //MOP_ldss, - {MOP_ldss, {MOPD_Reg32FD, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movss", "1,0"}, - //MOP_ldsd, - {MOP_ldsd, {MOPD_Reg64FD, MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movsd", "1,0"}, - //MOP_st8, - {MOP_st8, {MOPD_Reg8IS, MOPD_Mem, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISSTORE, "movb", "0,1"}, - //MOP_st16, - {MOP_st16, {MOPD_Reg16IS, MOPD_Mem, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISSTORE, "movw", "0,1"}, - //MOP_st32, - {MOP_st32, {MOPD_Reg32IS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISSTORE, "movl", "0,1"}, - //MOP_st64, - {MOP_st64, {MOPD_Reg64IS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISSTORE, "movq", "0,1"}, - //MOP_stss, - {MOP_stss, {MOPD_Reg32FS, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISSTORE, "movss", "0,1"}, - //MOP_stsd, - {MOP_stsd, {MOPD_Reg64FS, MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISSTORE, "movsd", "0,1"}, - //MOP_lea32, - {MOP_lea32, {MOPD_Reg32ID, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "leal", "1,0"}, - //MOP_lea64, - {MOP_lea64, {MOPD_Reg64ID, MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "leaq", "1,0"}, - //MOP_ldc32, - {MOP_ldc32, {MOPD_Reg32ID, MOPD_Imm32, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movl", "1,0"}, - //MOP_ldc64, - {MOP_ldc64, {MOPD_Reg64ID, MOPD_Imm64, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movq", "1,0"}, - //MOP_ldc32abs, - {MOP_ldc32abs, {MOPD_Reg32ID, MOPD_Imm32, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movabsl", "1,0"}, - //MOP_ldc64abs, - {MOP_ldc64abs, {MOPD_Reg64ID, MOPD_Imm64, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movabsq", "1,0"}, - //MOP_mov32, - {MOP_mov32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movl", "1,0"}, - //MOP_mov64, - {MOP_mov64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movq", "1,0"}, - //MOP_movabs32, - {MOP_movabs32, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movabsl", "1,0"}, - //MOP_movabs64, - {MOP_movabs64, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movabsq", "1,0"}, - //MOP_movss, - {MOP_movss, {MOPD_Reg32FD, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movss", "1,0"}, - //MOP_movsd, - {MOP_movsd, {MOPD_Reg64FD, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movsd", "1,0"}, - //MOP_movsbl, - {MOP_movsbl, {MOPD_Reg32ID, MOPD_Reg, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movsbl", "1,0"}, - //MOP_movzbl, - {MOP_movzbl, {MOPD_Reg32ID, MOPD_Reg, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movzbl", "1,0"}, - //MOP_movswl, - {MOP_movswl, {MOPD_Reg32ID, MOPD_Reg, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movswl", "1,0"}, - //MOP_movzwl, - {MOP_movzwl, {MOPD_Reg32ID, MOPD_Reg, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movzwl", "1,0"}, - //MOP_movsbq, - {MOP_movsbq, {MOPD_Reg64ID, MOPD_Reg, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movsbq", "1,0"}, - //MOP_movzbq, - {MOP_movzbq, {MOPD_Reg64ID, MOPD_Reg, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movzbq", "1,0"}, - //MOP_movswq, - {MOP_movswq, {MOPD_Reg64ID, MOPD_Reg, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movswq", "1,0"}, - //MOP_movzwq, - {MOP_movzwq, {MOPD_Reg64ID, MOPD_Reg, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movzwq", "1,0"}, - //MOP_movslq, - {MOP_movslq, {MOPD_Reg64ID, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movslq", "1,0"}, - //MOP_movzlq, - {MOP_movzlq, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movl", "1,0"}, - //MOP_movzql, // trunc - {MOP_movzql, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movl", "1,0"}, - //MOP_movi2fd, // for bit cast int to float - {MOP_movi2fd, {MOPD_Reg32FD, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movd", "1,0"}, - //MOP_movi2fq, - {MOP_movi2fq, {MOPD_Reg64FD, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movq", "1,0"}, - //MOP_movf2id, // for bit cast float to int - {MOP_movf2id, {MOPD_Reg32ID, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movd", "1,0"}, - //MOP_movf2iq, - {MOP_movf2iq, {MOPD_Reg64ID, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "movq", "1,0"}, - //MOP_ldsbl, - {MOP_ldsbl, {MOPD_Reg32ID, MOPD_Mem, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movsbl", "1,0"}, - //MOP_ldzbl, - {MOP_ldzbl, {MOPD_Reg32ID, MOPD_Mem, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movzbl", "1,0"}, - //MOP_ldswl, - {MOP_ldswl, {MOPD_Reg32ID, MOPD_Mem, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movswl", "1,0"}, - //MOP_ldzwl, - {MOP_ldzwl, {MOPD_Reg32ID, MOPD_Mem, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movzwl", "1,0"}, - //MOP_ldsbq, - {MOP_ldsbq, {MOPD_Reg64ID, MOPD_Mem, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movsbq", "1,0"}, - //MOP_ldzbq, - {MOP_ldzbq, {MOPD_Reg64ID, MOPD_Mem, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movzbq", "1,0"}, - //MOP_ldswq, - {MOP_ldswq, {MOPD_Reg64ID, MOPD_Mem, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movswq", "1,0"}, - //MOP_ldzwq, - {MOP_ldzwq, {MOPD_Reg64ID, MOPD_Mem, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movzwq", "1,0"}, - //MOP_ldslq, - {MOP_ldslq, {MOPD_Reg64ID, MOPD_Mem, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movslq", "1,0"}, - //MOP_ldzlq, // x86-64 is default by zero extended, so this is actually movl - {MOP_ldzlq, {MOPD_Reg32ID, MOPD_Mem, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movl", "1,0"}, - //MOP_ldi2fd, - {MOP_ldi2fd, {MOPD_Reg32FD, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movd", "1,0"}, - //MOP_ldi2fq, - {MOP_ldi2fq, {MOPD_Reg64FD, MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movq", "1,0"}, - //MOP_ldf2id, - {MOP_ldf2id, {MOPD_Reg32ID, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movd", "1,0"}, - //MOP_ldf2iq, - {MOP_ldf2iq, {MOPD_Reg64ID, MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, ISLOAD, "movq", "1,0"}, - //MOP_popl, - {MOP_popl, {MOPD_Reg32ID, MOPD_Reg, MOPD_Reg, MOPD_Undef, MOPD_Undef}, 0, "popl", "0"}, - //MOP_popq, - {MOP_popq, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef}, 0, "popq", "0"}, - //MOP_pushl, - {MOP_pushl, {MOPD_Reg32ID, MOPD_Reg32IS, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef}, 0, "pushl", "0"}, - //MOP_pushq, - {MOP_pushq, {MOPD_Reg64ID, MOPD_Reg64IS, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef}, 0, "pushq", "1"}, - //MOP_cvtss2sdr, - {MOP_cvtss2sdr, {MOPD_Reg64FD, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtss2sd", "1,0"}, - //MOP_cvtss2sdm, - {MOP_cvtss2sdm, {MOPD_Reg64FD, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtss2sd", "1,0"}, - //MOP_cvtsd2ssr, - {MOP_cvtsd2ssr, {MOPD_Reg32FD, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtsd2ss", "1,0"}, - //MOP_cvtsd2ssm, - {MOP_cvtsd2ssm, {MOPD_Reg32FD, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtsd2ss", "1,0"}, - //MOP_cvtsi2sdr, - {MOP_cvtsi2sdr, {MOPD_Reg64FD, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtsi2sdl", "1,0"}, - //MOP_cvtsi2sdm, - {MOP_cvtsi2sdm, {MOPD_Reg64FD, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtsi2sdl", "1,0"}, - //MOP_cvtsi2ssr, - {MOP_cvtsi2ssr, {MOPD_Reg32FD, MOPD_Reg32IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtsi2ssl", "1,0"}, - //MOP_cvtsi2ssm, - {MOP_cvtsi2ssm, {MOPD_Reg32FD, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtsi2ssl", "1,0"}, - //MOP_cvtsi2sdqr, - {MOP_cvtsi2sdqr, {MOPD_Reg64FD, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtsi2sdq", "1,0"}, - //MOP_cvtsi2sdqm, - {MOP_cvtsi2sdqm, {MOPD_Reg64FD, MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtsi2sdq", "1,0"}, - //MOP_cvtsi2ssqr, - {MOP_cvtsi2ssqr, {MOPD_Reg32FD, MOPD_Reg64IS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtsi2ssq", "1,0"}, - //MOP_cvtsi2ssqm, - {MOP_cvtsi2ssqm, {MOPD_Reg32FD, MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtsi2ssq", "1,0"}, - //MOP_cvtss2sir, - {MOP_cvtss2sir, {MOPD_Reg32ID, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtss2si", "1,0"}, - //MOP_cvtss2sim, - {MOP_cvtss2sim, {MOPD_Reg32ID, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtss2si", "1,0"}, - //MOP_cvtsd2sir, - {MOP_cvtsd2sir, {MOPD_Reg32ID, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtsd2si", "1,0"}, - //MOP_cvtsd2sim, - {MOP_cvtsd2sim, {MOPD_Reg32ID, MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtsd2si", "1,0"}, - //MOP_cvtss2siqr, - {MOP_cvtss2siqr, {MOPD_Reg64ID, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtss2siq", "1,0"}, - //MOP_cvtss2siqm, - {MOP_cvtss2siqm, {MOPD_Reg64ID, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtss2siq", "1,0"}, - //MOP_cvtsd2siqr, - {MOP_cvtsd2siqr, {MOPD_Reg64ID, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtsd2siq", "1,0"}, - //MOP_cvtsd2siqm, - {MOP_cvtsd2siqm, {MOPD_Reg64ID, MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvtsd2siq", "1,0"}, - //MOP_cvttss2sir, - {MOP_cvttss2sir, {MOPD_Reg32ID, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvttss2si", "1,0"}, - //MOP_cvttss2sim, - {MOP_cvttss2sim, {MOPD_Reg32ID, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvttss2si", "1,0"}, - //MOP_cvttss2si64r, - {MOP_cvttss2si64r, {MOPD_Reg64ID, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvttss2si", "1,0"}, - //MOP_cvttss2si64m, - {MOP_cvttss2si64m, {MOPD_Reg64ID, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvttss2si", "1,0"}, - //MOP_cvttsd2sir, - {MOP_cvttsd2sir, {MOPD_Reg32ID, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvttsd2si", "1,0"}, - //MOP_cvttsd2sim, - {MOP_cvttsd2sim, {MOPD_Reg32ID, MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvttsd2si", "1,0"}, - //MOP_cvttsd2si64r, - {MOP_cvttsd2si64r, {MOPD_Reg64ID, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvttsd2si", "1,0"}, - //MOP_cvttsd2si64m, - {MOP_cvttsd2si64m, {MOPD_Reg64ID, MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvttsd2si", "1,0"}, - //MOP_cvttss2siqr, - {MOP_cvttss2siqr, {MOPD_Reg64ID, MOPD_Reg32FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvttss2siq", "1,0"}, - //MOP_cvttss2siqm, - {MOP_cvttss2siqm, {MOPD_Reg64ID, MOPD_Mem32S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvttss2siq", "1,0"}, - //MOP_cvttsd2siqr, - {MOP_cvttsd2siqr, {MOPD_Reg64ID, MOPD_Reg64FS, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvttsd2siq", "1,0"}, - //MOP_cvttsd2siqm, - {MOP_cvttsd2siqm, {MOPD_Reg64ID, MOPD_Mem64S, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "cvttsd2siq", "1,0"}, - // mis - //MOP_cltd, - //MOP_cqto, - // MOP_zero32i - {MOP_zero32i, {MOPD_Reg32ID, MOPD_Undef, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "xor", "0,0"}, - // MOP_zero32f - {MOP_zero32f, {MOPD_Reg32FD, MOPD_Undef, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "xorps", "0,0"}, - // MOP_zero64f - {MOP_zero64f, {MOPD_Reg64FD, MOPD_Undef, MOPD_Undef, MOPD_Undef, MOPD_Undef}, 0, "xorpd", "0,0"}, diff --git a/mapleall/maple_driver/BUILD.gn b/mapleall/maple_driver/BUILD.gn index 093d16b..bb3edd5 100644 --- a/mapleall/maple_driver/BUILD.gn +++ b/mapleall/maple_driver/BUILD.gn @@ -22,6 +22,13 @@ if(TARGET == "aarch64"){ ] } +if(TARGET == "riscv64"){ + cflags_cc += [ + "-DTARGRISCV64", + "-DMAPLE_ROOT=\"${MAPLE_ROOT}\"", + ] +} + if(TARGET == "ark"){ cflags_cc += [ "-DTARGARK", @@ -47,6 +54,7 @@ include_directories = [ "${MAPLE_RE_ROOT}/include", "${MAPLEALL_ROOT}/mempool/include", "${HUAWEI_SECURE_C_ROOT}/include", + "${DWARF_ROOT}/include", ] executable("maple") { diff --git a/mapleall/maple_driver/src/driver_runner.cpp b/mapleall/maple_driver/src/driver_runner.cpp index 56df9cd..46864e6 100644 --- a/mapleall/maple_driver/src/driver_runner.cpp +++ b/mapleall/maple_driver/src/driver_runner.cpp @@ -30,6 +30,8 @@ #include "arm/arm_cg.h" #elif TARGAARCH64 #include "aarch64/aarch64_cg.h" +#elif TARGRISCV64 +#include "riscv64/riscv64_cg.h" #elif TARGARK #include "ark/ark_mir_emit.h" #include "ark/ark_cg.h" @@ -204,6 +206,10 @@ void DriverRunner::ProcessMpl2mplAndMeAndMplCgPhases(const std::string &interimO std::vector modprephases; std::vector mephases; std::vector modpostphases; + if (hasDebugFlag) { + std::cout << "set up debug info " << std::endl; + theModule->dbgInfo->BuildDebugInfo(); + } #include "phases.def" MInline::level = Options::inlineLev; MInline::inlineFuncList = MeOption::inlinefunclist; @@ -247,6 +253,9 @@ void DriverRunner::ProcessMpl2mplAndMeAndMplCgPhases(const std::string &interimO #elif TARGAARCH64 AArch64CG thecg(theModule, *cgOptions, cgOptions->run_cg_flag, outputFile.c_str(), ehExclusiveFunctionName, CGOptions::cyclePatternMap); +#elif TARGRISCV64 + Riscv64CG thecg(theModule, *cgOptions, cgOptions->run_cg_flag, outputFile.c_str(), ehExclusiveFunctionName, + CGOptions::cyclePatternMap); #elif TARGARK ArkCG thecg(theModule, *cgOptions, cgOptions->run_cg_flag, outputFile.c_str(), ehExclusiveFunctionName, CGOptions::cyclePatternMap); @@ -309,6 +318,9 @@ void DriverRunner::ProcessMpl2mplAndMeAndMplCgPhases(const std::string &interimO } #endif + if (cgOptions->WithDwarf()) { + thecg.emitter_->EmitDIHeader(); + } // 3. generate phase pipeline based on function. unsigned long rangeNum = 0; if (!CGOptions::quiet) { @@ -353,6 +365,9 @@ void DriverRunner::ProcessMpl2mplAndMeAndMplCgPhases(const std::string &interimO MapleAllocator funcscopeAllocator(funcMp); // 4, Create CGFunc CGFunc *cgfunc = thecg.CreateCGFunc(theModule, mirFunc, becommon, funcMp, &funcscopeAllocator); + if (cgOptions->WithDwarf()) { + cgfunc->SetDebugInfo(theModule->dbgInfo); + } CG::curCgFunc = cgfunc; CG::curPuIdx = cgfunc->mirModule.CurFunction()->puIdx; // 5. Run the cg optimizations phases. @@ -371,7 +386,11 @@ void DriverRunner::ProcessMpl2mplAndMeAndMplCgPhases(const std::string &interimO CGOptions::inRange = false; } -#if TARGAARCH64 + if (cgOptions->WithDwarf()) { + thecg.emitter_->EmitDIFooter(); + } + +#if TARGAARCH64 || TARGRISCV64 // Emit duplicated asm func to delete plt call if (!cgOptions->duplicateAsmFile.empty()) { struct stat buffer; @@ -410,6 +429,17 @@ void DriverRunner::ProcessMpl2mplAndMeAndMplCgPhases(const std::string &interimO thecg.emitter_->EmitGxxPersonalityV0(); thecg.emitter_->EmitInitArraySection(); } + // 10. emit debug infomation. + if (cgOptions->WithDwarf()) { + thecg.emitter_->SetupDBGInfo(theModule->dbgInfo); + thecg.emitter_->EmitDIHeaderFileInfo(); + thecg.emitter_->EmitDIDebugInfoSection(theModule->dbgInfo); + thecg.emitter_->EmitDIDebugAbbrevSection(theModule->dbgInfo); + thecg.emitter_->EmitDIDebugARangesSection(); + thecg.emitter_->EmitDIDebugRangesSection(); + thecg.emitter_->EmitDIDebugLineSection(); + thecg.emitter_->EmitDIDebugStrSection(); + } thecg.emitter_->CloseOutput(); } else { cerr << "Skipped generating .s because -no-cg is given" << endl; diff --git a/mapleall/maple_ipa/BUILD.gn b/mapleall/maple_ipa/BUILD.gn index 4c653cf..45f7296 100644 --- a/mapleall/maple_ipa/BUILD.gn +++ b/mapleall/maple_ipa/BUILD.gn @@ -25,7 +25,6 @@ include_directories = [ "${MAPLEALL_ROOT}/maple_ir/include", "${MAPLEALL_ROOT}/maple_util/include", "${MAPLEALL_ROOT}/maple_ipa/include", - "${MAPLEALL_ROOT}/mapleradar/include", "${MAPLEALL_ROOT}/maple_driver/include", "${HUAWEI_SECURE_C_ROOT}/include", ] diff --git a/mapleall/maple_ir/BUILD.gn b/mapleall/maple_ir/BUILD.gn index 28470d2..64d4a9f 100644 --- a/mapleall/maple_ir/BUILD.gn +++ b/mapleall/maple_ir/BUILD.gn @@ -28,16 +28,18 @@ include_directories = [ "${MAPLEALL_ROOT}/maple_util/include", "${MAPLEALL_ROOT}/mempool/include", "${HUAWEI_SECURE_C_ROOT}/include", - "${MAPLEALL_ROOT}/maplevm/include", "${MAPLEALL_ROOT}/maple_ipa/include", "${MAPLEALL_ROOT}/maple_me/include", "${MAPLEALL_ROOT}/maple_phase/include", "${MAPLEALL_ROOT}/maple_driver/include", + "${DWARF_ROOT}/include", ] static_library("libmplir"){ sources = [ "src/constant_fold.cpp", + "src/debug_info.cpp", + "src/debug_info_util.cpp", "src/global_tables.cpp", "src/intrinsics.cpp", "src/lexer.cpp", @@ -120,6 +122,21 @@ executable("cmpl2mmpl"){ ] } +executable("mpldbg"){ + sources = [ + "src/mpl_dbg.cpp" + ] + + include_dirs = include_directories + + deps = [ + ":libmplir", + "${MAPLEALL_ROOT}/mempool:libmempool", + "${MAPLEALL_ROOT}/maple_util:libmplutil", + "${HUAWEI_SECURE_C_ROOT}:libHWSecureC", + ] +} + executable("mplverf"){ sources = [ "src/verf_driver.cpp", diff --git a/mapleall/maple_ir/include/debug_info.h b/mapleall/maple_ir/include/debug_info.h new file mode 100644 index 0000000..776cea7 --- /dev/null +++ b/mapleall/maple_ir/include/debug_info.h @@ -0,0 +1,420 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#ifndef MAPLE_IR_INCLUDE_DBG_INFO_H +#define MAPLE_IR_INCLUDE_DBG_INFO_H +#include + +#include "mpl_logging.h" +#include "types_def.h" +#include "prim_types.h" +#include "mir_nodes.h" +#include "lexer.h" +#include "dwarf2.h" + +using namespace maple; + +namespace maple { + +// for more color code: http://ascii-table.com/ansi-escape-sequences.php +#define RESET "\x1B[0m" +#define BOLD "\x1B[1m" +#define RED "\x1B[31m" +#define GRN "\x1B[32m" +#define YEL "\x1B[33m" + +const uint32 kDbgDefaultVal = 0xdeadbeef; +#define HEX(val) std::hex << "0x" << val << std::dec + +class MIRModule; +class MIRType; +class MIRSymbol; +class MIRSymbolTable; +class MIRTypeNameTable; +class DBGBuilder; +class DBGCompileMsgInfo; +class MIRLexer; + +// for compiletime warnings +class DBGLine { + public: + uint32 linenum_; + const char *line_; + + DBGLine(uint32 lnum, const char *l) : linenum_(lnum), line_(l) {} + + void Dump() { + LogInfo::MapleLogger() << "LINE: " << linenum_ << " " << line_ << std::endl; + } +}; + +#define MAXLINELEN 4096 + +class DBGCompileMsgInfo { + public: + uint32 startline_; // mod 3 + uint32 err_l_num_; + uint32 err_c_num_; + uint32 errpos_; + uint32 linenum_[3]; + uint8 line_[3][MAXLINELEN]; // 3 round-robin line buffers + + DBGCompileMsgInfo(); + virtual ~DBGCompileMsgInfo() {} + void ClearLine(uint32 n); + void SetErrPos(uint32 lnum, uint32 cnum); + void UpdateMsg(uint32 lnum, const char *line); + void EmitMsg(); +}; + +enum DBGDieKind { kDwTag, kDwAt, kDwOp, kDwAte, kDwForm, kDwCfa }; + +typedef uint32 dw_tag; // for DW_TAG_* +typedef uint32 dw_at; // for DW_AT_* +typedef uint32 dw_op; // for DW_OP_* +typedef uint32 dw_ate; // for DW_ATE_* +typedef uint32 dw_form; // for DW_FORM_* +typedef uint32 dw_cfa; // for DW_CFA_* + +class DBGDieAttr; + +class DBGExpr { + public: + dw_op dwop_; + // for local var fboffset, global var strIdx + int val_; + MapleVector opnds_; + DBGExpr(MIRModule *m) : dwop_(0), val_(kDbgDefaultVal), opnds_(m->memPoolAllocator.Adapter()) {} + + DBGExpr(MIRModule *m, dw_op op) : dwop_(op), val_(kDbgDefaultVal), opnds_(m->memPoolAllocator.Adapter()) {} + + virtual ~DBGExpr() {} + + void AddOpnd(uint64 val) { + opnds_.push_back(val); + } +}; + +class DBGExprLoc { + public: + MIRModule *mod_; + DBGExpr *simploc_; + MapleVector expr_vec_; + void *symloc_; + + DBGExprLoc(MIRModule *m) : mod_(m), expr_vec_(m->memPoolAllocator.Adapter()), symloc_(nullptr) { + simploc_ = m->memPool->New(mod_); + } + + DBGExprLoc(MIRModule *m, dw_op op) : mod_(m), expr_vec_(m->memPoolAllocator.Adapter()), symloc_(nullptr) { + simploc_ = m->memPool->New(mod_, op); + } + + virtual ~DBGExprLoc() {} + + bool IsSimp() const { + return (expr_vec_.size() == 0 && simploc_->val_ != (int)kDbgDefaultVal); + } + + int GetFboffset() const { + return simploc_->val_; + } + + void SetFboffset(int offset) { + simploc_->val_ = offset; + } + + int GetGvarStridx() const { + return simploc_->val_; + } + + void SetGvarStridx(int idx) { + simploc_->val_ = idx; + } + + dw_op GetOp() const { + return simploc_->dwop_; + } + + uint32 GetSize() const { + return simploc_->opnds_.size(); + } + + void ClearOpnd() { + simploc_->opnds_.clear(); + } + + void AddSimpLocOpnd(uint64 val) { + simploc_->AddOpnd(val); + } + + void Dump(); +}; + +class DBGDieAttr { + public: + DBGDieKind kind_; + dw_at dwattr_; + dw_form dwform_; // type for the attribute value + union { + int32 i; + uint32 id; // dieid when dwform_ is of DW_FORM_ref + // strIdx when dwform_ is of DW_FORM_string + int64 j; + uint64 u; + float f; + double d; + + DBGExprLoc *ptr; + } val_; + + uint32 SizeOf(DBGDieAttr *attr); + DBGDieAttr(DBGDieKind k) : kind_(k), dwattr_(DW_AT_GNU_deleted), dwform_(DW_FORM_GNU_strp_alt) { + val_.u = kDbgDefaultVal; + } + + virtual ~DBGDieAttr() {} + + void AddSimpLocOpnd(uint64 val) { + val_.ptr->AddSimpLocOpnd(val); + } + + void ClearSimpLocOpnd() { + val_.ptr->ClearOpnd(); + } + + void Dump(int indent); +}; + +class DBGDie { + public: + MIRModule *mod_; + dw_tag tag_; + uint32 id; // starts from 1 which is root die cu_ + bool withchildren_; + DBGDie *parent; + DBGDie *sibling; + DBGDie *firstchild; + uint32 abbrevid_; // id in .debug_abbrev + uint32 tyidx_; // for type TAG + uint32 Offset; // Dwarf CU relative offset + uint32 Size; // DIE Size in .debug_info + MapleVector attrvec_; + MapleVector subdievec_; + + DBGDie(MIRModule *m, dw_tag tag); + virtual ~DBGDie() {} + void AddAttr(DBGDieAttr *attr); + void AddSubVec(DBGDie *die); + + DBGDieAttr *AddAttr(dw_at attr, dw_form form, uint64 val); + DBGDieAttr *AddSimpLocAttr(dw_at at, dw_form form, uint64 val); + DBGDieAttr *AddGlobalLocAttr(dw_at at, dw_form form, uint64 val); + DBGDieAttr *AddFrmBaseAttr(dw_at at, dw_form form, uint64 val); + DBGExprLoc *GetExprLoc(); + bool SetAttr(dw_at attr, uint64 val); + bool SetAttr(dw_at attr, int64 val); + bool SetAttr(dw_at attr, uint32 val); + bool SetAttr(dw_at attr, int32 val); + bool SetAttr(dw_at attr, float val); + bool SetAttr(dw_at attr, double val); + bool SetSimpLocAttr(dw_at attr, int64 val); + bool SetAttr(dw_at attr, DBGExprLoc *ptr); + void ResetParentDie(); + void Dump(int indent); +}; + +class DBGAbbrevEntry { + public: + dw_tag tag_; + uint32 abbrevid_; + bool withchildren_; + MapleVector attrpairs_; // kDwAt kDwForm pairs + DBGAbbrevEntry(MIRModule *m, DBGDie *die); + virtual ~DBGAbbrevEntry() {} + bool Equalto(DBGAbbrevEntry *entry); + void Dump(int indent); +}; + +class DBGAbbrevEntryVec { + public: + dw_tag tag_; + MapleVector entryvec_; + DBGAbbrevEntryVec(MIRModule *m, dw_tag tag) : tag_(tag), entryvec_(m->memPoolAllocator.Adapter()) {} + + virtual ~DBGAbbrevEntryVec() {} + + uint32 GetId(MapleVector &attrs); + void Dump(int indent); +}; + +class DebugInfo { + public: + MIRModule *mod_; + DBGDie *cu_; // root die: compilation unit + DBGDie *dummytypedie_; // workaround for unknown types + MIRLexer *lexer_; + uint32 maxid_; + DBGBuilder *builder_; + GStrIdx mplsrcidx_; + uint32 debug_info_length_; + + // for compilation messages + DBGCompileMsgInfo *compilemsg_; + + MapleStack parentdiestack_; + MapleMap id_die_map_; + MapleVector abbrev_vec_; // valid entry starting from index 1 + MapleMap tag_abbrev_map_; + + // to be used when derived type references a base type die + MapleMap tyidx_dieid_map_; + MapleMap stridx_dieid_map_; + MapleMap funcdef_stridx_dieid_map_; + MapleMap typedef_tyidx_map_; // prevtyidx_typidx_map + MapleMap pointed_pointer_map_; + MapleMap> func_lstridx_dieid_map_; + MapleMap> func_lstridx_labidx_map_; + MapleSet strps_; + + public: + DebugInfo(MIRModule *m) + : mod_(m), + cu_(nullptr), + dummytypedie_(nullptr), + lexer_(nullptr), + maxid_(1), + builder_(nullptr), + mplsrcidx_(0), + debug_info_length_(0), + compilemsg_(nullptr), + parentdiestack_(m->memPoolAllocator.Adapter()), + id_die_map_(std::less(), m->memPoolAllocator.Adapter()), + abbrev_vec_(m->memPoolAllocator.Adapter()), + tag_abbrev_map_(std::less(), m->memPoolAllocator.Adapter()), + tyidx_dieid_map_(std::less(), m->memPoolAllocator.Adapter()), + stridx_dieid_map_(std::less(), m->memPoolAllocator.Adapter()), + funcdef_stridx_dieid_map_(std::less(), m->memPoolAllocator.Adapter()), + typedef_tyidx_map_(std::less(), m->memPoolAllocator.Adapter()), + pointed_pointer_map_(std::less(), m->memPoolAllocator.Adapter()), + func_lstridx_dieid_map_(std::less(), m->memPoolAllocator.Adapter()), + func_lstridx_labidx_map_(std::less(), m->memPoolAllocator.Adapter()), + strps_(std::less(), m->memPoolAllocator.Adapter()) { + // valid entry starting from index 1 as abbrevid starting from 1 as well + abbrev_vec_.push_back(nullptr); + InitMsg(); + } + + virtual ~DebugInfo() {} + + void InitMsg() { + compilemsg_ = mod_->memPool->New(); + } + + void UpdateMsg(uint32 lnum, const char *line) { + compilemsg_->UpdateMsg(lnum, line); + } + + void SetErrPos(uint32 lnum, uint32 cnum) { + compilemsg_->SetErrPos(lnum, cnum); + } + + void EmitMsg() { + compilemsg_->EmitMsg(); + } + + DBGDie *GetDie(uint32 id) { + return id_die_map_[id]; + } + + DBGDie *GetDie(const MIRFunction *func); + + void Init(); + void Finish(); + void SetupCU(); + void BuildDebugInfo(); + void BuildAliasDIEs(); + void Dump(int indent); + + // build tree to populate withchildren_, sibling, firstchild + // also insert DW_AT_sibling attributes when needed + void BuildDieTree(); + + // replace type idx with die id in DW_AT_type attributes + void FillTypeAttrWithDieId(); + + void BuildAbbrev(); + uint32 GetAbbrevId(DBGAbbrevEntryVec *, DBGAbbrevEntry *); + + void SetLocalDie(GStrIdx strIdx, const DBGDie *die); + void SetLocalDie(MIRFunction *func, GStrIdx strIdx, const DBGDie *die); + DBGDie *GetLocalDie(GStrIdx strIdx); + DBGDie *GetLocalDie(MIRFunction *func, GStrIdx strIdx); + + LabelIdx GetLabelIdx(GStrIdx strIdx); + LabelIdx GetLabelIdx(MIRFunction *func, GStrIdx strIdx); + void SetLabelIdx(GStrIdx strIdx, LabelIdx idx); + void SetLabelIdx(MIRFunction *func, GStrIdx strIdx, LabelIdx idx); + + DBGDie *GetParentDie() { + return parentdiestack_.top(); + } + + void PushParentDie(DBGDie *die) { + parentdiestack_.push(die); + } + + void PopParentDie() { + parentdiestack_.pop(); + } + + void ResetParentDie() { + parentdiestack_.clear(); + parentdiestack_.push(cu_); + } + + void SetTyidxDieIdMap(TyIdx tyIdx, const DBGDie *die) { + tyidx_dieid_map_[tyIdx.GetIdx()] = die->id; + } + + DBGDieAttr *CreateAttr(dw_at attr, dw_form form, uint64 val); + + DBGDie *CreateVarDie(MIRSymbol *sym, uint32 lnum); + DBGDie *CreateFormalParaDie(MIRType *type, GStrIdx nameidx, uint32 lnum); + DBGDie *CreateFieldDie(maple::FieldPair pair, uint32 lnum); + DBGDie *CreateStructTypeDie(GStrIdx strIdx, const MIRStructType *type, bool update = false); + DBGDie *CreateClassTypeDie(GStrIdx strIdx, const MIRClassType *type); + DBGDie *CreateInterfaceTypeDie(GStrIdx strIdx, const MIRInterfaceType *type); + + DBGDie *GetOrCreateLabelDie(LabelIdx labid); + DBGDie *GetOrCreateTypeAttrDie(MIRSymbol *sym); + DBGDie *GetOrCreateConstTypeDie(TypeAttrs attr, DBGDie *typedie); + DBGDie *GetOrCreateVolatileTypeDie(TypeAttrs attr, DBGDie *typedie); + DBGDie *GetOrCreateFuncDeclDie(MIRFunction *func, uint32 lnum); + DBGDie *GetOrCreateFuncDefDie(MIRFunction *func, uint32 lnum); + DBGDie *GetOrCreatePrimTypeDie(PrimType pty); + DBGDie *GetOrCreateTypeDie(MIRType *type); + DBGDie *GetOrCreatePointTypeDie(const MIRPtrType *type); + DBGDie *GetOrCreateArrayTypeDie(const MIRArrayType *type); + DBGDie *GetOrCreateStructTypeDie(const MIRType *type); + + // Functions for calculating the size and offset of each DW_TAG_xxx and DW_AT_xxx + void ComputeSizeAndOffsets(); + void ComputeSizeAndOffset(DBGDie *die, uint32 &offset); +}; + +} // namespace maple + +#endif // MAPLE_IR_INCLUDE_DBG_INFO_H diff --git a/mapleall/maple_ir/include/gen-intrin.pl b/mapleall/maple_ir/include/gen-intrin.pl deleted file mode 100644 index d03e1b8..0000000 --- a/mapleall/maple_ir/include/gen-intrin.pl +++ /dev/null @@ -1,35 +0,0 @@ -# -# Copyright (c) [2020] Huawei Technologies Co., Ltd. All rights reserved. -# -# Licensed under the Mulan Permissive Software License v2. -# You can use this software according to the terms and conditions of the MulanPSL - 2.0. -# You may obtain a copy of MulanPSL - 2.0 at: -# -# https://opensource.org/licenses/MulanPSL-2.0 -# -# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR -# FIT FOR A PARTICULAR PURPOSE. -# See the MulanPSL - 2.0 for more details. -# - -open(my $intrin_def, '<', "intrinsicsop.def.h") or die "can't open intrinsics.def"; -open(my $intrin_h, '>', "intrinsicsop.def") or die "can't open intrinsics.h"; -open(my $intrinjs_def, '<', "./js2mpl/intrinsicsop.def.h") or die "can't open intrinsics.def"; -open(my $intrinjs_h, '>', "./js2mpl/intrinsicsop.def") or die "can't open intrinsics.h"; -my $insn_count=1; -while(my $line = <$intrin_def>) { - chomp $line; - print $intrin_h "\#define INTRINSIC_".$line." ".$insn_count."\n"; - $insn_count++; -} -while(my $line = <$intrinjs_def>) { - chomp $line; - print $intrin_h "\#define INTRINSIC_".$line." ".$insn_count."\n"; - $insn_count++; -} -print $intrin_h "\#define INTRINSIC_last ".$insn_count."\n"; -close $intrin_def; -close $intrin_h; -close $intrinjs_def; -close $intrinjs_h; diff --git a/mapleall/maple_ir/include/mir_module.h b/mapleall/maple_ir/include/mir_module.h index 0770a75..9001649 100644 --- a/mapleall/maple_ir/include/mir_module.h +++ b/mapleall/maple_ir/include/mir_module.h @@ -46,6 +46,7 @@ class MIRSymbolTable; class MIRTypeNameTable; class MIRFloatConst; class MIRDoubleConst; +class DebugInfo; class BinaryMplt; using MIRInfoPair = std::pair; using MIRInfoVector = MapleVector; @@ -114,6 +115,8 @@ class MIRModule : public mir_module_t { TyIdx throwableTyidx; // a special type that is the base of java exception type. only used for java + DebugInfo *dbgInfo; + bool withDbgInfo; bool withProfileInfo; //// for cg in mplt diff --git a/mapleall/maple_ir/include/mir_type.h b/mapleall/maple_ir/include/mir_type.h index 229d209..56ff3f9 100644 --- a/mapleall/maple_ir/include/mir_type.h +++ b/mapleall/maple_ir/include/mir_type.h @@ -666,8 +666,9 @@ class MIRStructType : public MIRType { MethodPtrVector iTableMethods; // the list of all interface functions for this type; For classes, they are // implementation functions, For interfaces, they are abstact functions. // Weak indicates the actual definition is in another module. - bool isImported; - bool isUsed; + bool isCPlusPlus : 1; // empty struct in C++ has size 1 byte + bool isImported : 1; + bool isUsed : 1; private: bool hasVolatileField; // for caching computed value @@ -686,6 +687,7 @@ class MIRStructType : public MIRType { methods(), vTableMethods(), iTableMethods(), + isCPlusPlus(false), isImported(false), isUsed(false), hasVolatileField(false), @@ -700,6 +702,7 @@ class MIRStructType : public MIRType { methods(), vTableMethods(), iTableMethods(), + isCPlusPlus(false), isImported(false), isUsed(false), hasVolatileField(false), @@ -813,6 +816,7 @@ class MIRStructType : public MIRType { methods.clear(); vTableMethods.clear(); iTableMethods.clear(); + isCPlusPlus = false; isImported = false; isUsed = false; hasVolatileField = false; diff --git a/mapleall/maple_ir/include/prim_types.def b/mapleall/maple_ir/include/prim_types.def index ae03025..dca5b39 100644 --- a/mapleall/maple_ir/include/prim_types.def +++ b/mapleall/maple_ir/include/prim_types.def @@ -15,7 +15,6 @@ #ifdef LOAD_ALGO_PRIMARY_TYPE #undef LOAD_ALGO_PRIMARY_TYPE -// NOTE: this ordering needs to be in sync with ptypesizetable[] in maplevm/src/vmfunc.cpp PRIMTYPE(void) PRIMTYPE(i8) PRIMTYPE(i16) diff --git a/mapleall/maple_ir/src/bin_func_import.cpp b/mapleall/maple_ir/src/bin_func_import.cpp index 0ea4d3e..ad6c88d 100644 --- a/mapleall/maple_ir/src/bin_func_import.cpp +++ b/mapleall/maple_ir/src/bin_func_import.cpp @@ -19,6 +19,7 @@ #include "name_mangler.h" #include "opcode_info.h" #include "mir_pragma.h" +#include "debug_info.h" #include "mir_builder.h" #include diff --git a/mapleall/maple_ir/src/bin_mpl_import.cpp b/mapleall/maple_ir/src/bin_mpl_import.cpp index 8071214..ae91328 100644 --- a/mapleall/maple_ir/src/bin_mpl_import.cpp +++ b/mapleall/maple_ir/src/bin_mpl_import.cpp @@ -23,6 +23,7 @@ #include "name_mangler.h" #include "opcode_info.h" #include "mir_pragma.h" +#include "debug_info.h" #include "mir_builder.h" using namespace std; @@ -641,6 +642,9 @@ TyIdx BinaryMplImport::ImportType() { case kBinKindTypeStruct: { MIRTypeKind kind = (MIRTypeKind)ReadNum(); MIRStructType *type = new MIRStructType(kind, strIdx); + if (mod.srcLang == kSrcLangCPlusPlus) { + type->isCPlusPlus = true; + } type->nameIsLocal = nameIsLocal; MIRType *origType = InsertInTypeTables(type); typ_tab.push_back(origType); diff --git a/mapleall/maple_ir/src/debug_info.cpp b/mapleall/maple_ir/src/debug_info.cpp new file mode 100644 index 0000000..88efdcc --- /dev/null +++ b/mapleall/maple_ir/src/debug_info.cpp @@ -0,0 +1,1311 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#include "mir_builder.h" +#include "printing.h" +#include "maple_string.h" +#include "name_mangler.h" +#include "debug_info.h" +#include "global_tables.h" +#include "mir_type.h" +#include +#include "securec.h" +#include "mpl_logging.h" + +namespace maple { + +extern const char *get_DW_TAG_name(unsigned n); +extern const char *get_DW_FORM_name(unsigned n); +extern const char *get_DW_AT_name(unsigned n); +extern const char *get_DW_OP_name(unsigned n); +extern const char *get_DW_ATE_name(unsigned n); +extern const char *get_DW_CFA_name(unsigned n); +extern dw_ate GetAteFromPTY(PrimType pty); + +// DBGDie methods +DBGDie::DBGDie(MIRModule *m, dw_tag tag) + : mod_(m), + tag_(tag), + id(m->dbgInfo->maxid_), + withchildren_(false), + sibling(nullptr), + firstchild(nullptr), + abbrevid_(0), + tyidx_(0), + Offset(0), + Size(0), + attrvec_(m->memPoolAllocator.Adapter()), + subdievec_(m->memPoolAllocator.Adapter()) { + if (mod_->dbgInfo->parentdiestack_.size()) { + parent = mod_->dbgInfo->parentdiestack_.top(); + } else { + parent = nullptr; + } + m->dbgInfo->id_die_map_[m->dbgInfo->maxid_++] = this; + attrvec_.clear(); + subdievec_.clear(); +} + +void DBGDie::ResetParentDie() { + mod_->dbgInfo->ResetParentDie(); +} + +DBGDieAttr *DBGDie::AddAttr(dw_at at, dw_form form, uint64 val) { + // collect strps which need label + if (form == DW_FORM_strp) { + mod_->dbgInfo->strps_.insert(val); + } + DBGDieAttr *attr = mod_->dbgInfo->CreateAttr(at, form, val); + AddAttr(attr); + return attr; +} + +DBGDieAttr *DBGDie::AddSimpLocAttr(dw_at at, dw_form form, uint64 val) { + DBGExprLoc *p = mod_->memPool->New(mod_, DW_OP_fbreg); + if (val != kDbgDefaultVal) { + p->AddSimpLocOpnd(val); + } + DBGDieAttr *attr = mod_->dbgInfo->CreateAttr(at, form, reinterpret_cast(p)); + AddAttr(attr); + return attr; +} + +DBGDieAttr *DBGDie::AddGlobalLocAttr(dw_at at, dw_form form, uint64 val) { + DBGExprLoc *p = mod_->memPool->New(mod_, DW_OP_addr); + p->SetGvarStridx(val); + DBGDieAttr *attr = mod_->dbgInfo->CreateAttr(at, form, reinterpret_cast(p)); + AddAttr(attr); + return attr; +} + +DBGDieAttr *DBGDie::AddFrmBaseAttr(dw_at at, dw_form form, uint64 val) { + DBGExprLoc *p = mod_->memPool->New(mod_, DW_OP_call_frame_cfa); + DBGDieAttr *attr = mod_->dbgInfo->CreateAttr(at, form, reinterpret_cast(p)); + AddAttr(attr); + return attr; +} + +DBGExprLoc *DBGDie::GetExprLoc() { + for (auto it : attrvec_) { + if (it->dwattr_ == DW_AT_location) { + return it->val_.ptr; + } + } + return nullptr; +} + +bool DBGDie::SetAttr(dw_at attr, uint64 val) { + for (auto it : attrvec_) { + if (it->dwattr_ == attr) { + it->val_.u = val; + return true; + } + } + return false; +} + +bool DBGDie::SetAttr(dw_at attr, int val) { + for (auto it : attrvec_) { + if (it->dwattr_ == attr) { + it->val_.i = val; + return true; + } + } + return false; +} + +bool DBGDie::SetAttr(dw_at attr, uint32 val) { + for (auto it : attrvec_) { + if (it->dwattr_ == attr) { + it->val_.id = val; + return true; + } + } + return false; +} + +bool DBGDie::SetAttr(dw_at attr, int64 val) { + for (auto it : attrvec_) { + if (it->dwattr_ == attr) { + it->val_.j = val; + return true; + } + } + return false; +} + +bool DBGDie::SetAttr(dw_at attr, float val) { + for (auto it : attrvec_) { + if (it->dwattr_ == attr) { + it->val_.f = val; + return true; + } + } + return false; +} + +bool DBGDie::SetAttr(dw_at attr, double val) { + for (auto it : attrvec_) { + if (it->dwattr_ == attr) { + it->val_.d = val; + return true; + } + } + return false; +} + +bool DBGDie::SetAttr(dw_at attr, DBGExprLoc *ptr) { + for (auto it : attrvec_) { + if (it->dwattr_ == attr) { + it->val_.ptr = ptr; + return true; + } + } + return false; +} + +void DBGDie::AddAttr(DBGDieAttr *attr) { + for (auto it : attrvec_) { + if (it->dwattr_ == attr->dwattr_) { + return; + } + } + attrvec_.push_back(attr); +} + +void DBGDie::AddSubVec(DBGDie *die) { + if (!die) return; + for (auto it : subdievec_) { + if (it->id == die->id) { + return; + } + } + subdievec_.push_back(die); + die->parent = this; +} + +// DBGAbbrevEntry methods +DBGAbbrevEntry::DBGAbbrevEntry(MIRModule *m, DBGDie *die) : attrpairs_(m->memPoolAllocator.Adapter()) { + tag_ = die->tag_; + abbrevid_ = 0; + withchildren_ = die->withchildren_; + for (auto it : die->attrvec_) { + attrpairs_.push_back(it->dwattr_); + attrpairs_.push_back(it->dwform_); + } +} + +bool DBGAbbrevEntry::Equalto(DBGAbbrevEntry *entry) { + if (attrpairs_.size() != entry->attrpairs_.size()) { + return false; + } + if (withchildren_ != entry->withchildren_) { + return false; + } + for (uint32 i = 0; i < attrpairs_.size(); i++) { + if (attrpairs_[i] != entry->attrpairs_[i]) { + return false; + } + } + return true; +} + +// DebugInfo methods +void DebugInfo::Init() { + mplsrcidx_ = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(mod_->fileName); + cu_ = mod_->memPool->New(mod_, DW_TAG_compile_unit); + mod_->withDbgInfo = true; + ResetParentDie(); +} + +void DebugInfo::SetupCU() { + cu_->withchildren_ = true; + /* Add the Producer (Compiler) Information */ + const char *producer = "Maple Version 0.5.0 (tags/RELEASE-xxx/final)"; + GStrIdx strIdx = mod_->mirBuilder->GetOrCreateStringIndex(producer); + cu_->AddAttr(DW_AT_producer, DW_FORM_strp, strIdx.GetIdx()); + + /* Source Languate */ + cu_->AddAttr(DW_AT_language, DW_FORM_data4, DW_LANG_C99); + + /* Add the compiled source file information */ + cu_->AddAttr(DW_AT_name, DW_FORM_strp, mplsrcidx_.GetIdx()); + strIdx = mod_->mirBuilder->GetOrCreateStringIndex("/to/be/done/current/path"); + cu_->AddAttr(DW_AT_comp_dir, DW_FORM_strp, strIdx.GetIdx()); + + cu_->AddAttr(DW_AT_low_pc, DW_FORM_addr, kDbgDefaultVal); + cu_->AddAttr(DW_AT_high_pc, DW_FORM_data8, kDbgDefaultVal); + + cu_->AddAttr(DW_AT_stmt_list, DW_FORM_sec_offset, kDbgDefaultVal); +} + +void DebugInfo::BuildAliasDIEs() { + for (auto it : func_lstridx_dieid_map_) { + MIRFunction *func = it.first; + for (std::pair i : func->aliasVarMap) { + DBGDie *die = GetLocalDie(func, i.second.memPoolStrIdx); + // this local mpl variable does not exist because it is optimized away + // by register renameing. please use mplme -O1 instead of -O2 + if (!die) { + continue; + } + DBGDie *aliasdie = mod_->memPool->New(mod_, DW_TAG_variable); + + // clone attributes, note DBGExprLoc pointer is copied as well + // so the fboffset are the same as aliased maple variable + for (auto attr : die->attrvec_) { + aliasdie->AddAttr(attr->dwattr_, attr->dwform_, attr->val_.u); + } + // update name with aliased src variable name + aliasdie->SetAttr(DW_AT_name, i.first.GetIdx()); + aliasdie->parent = die->parent; + + // add alias var name to debug_str section + strps_.insert(i.first.GetIdx()); + + uint32 funcdieid = stridx_dieid_map_[func->GetNameStridx().GetIdx()]; + DBGDie *funcdie = id_die_map_[funcdieid]; + funcdie->AddSubVec(aliasdie); + } + } +} + +void DebugInfo::Finish() { + SetupCU(); + FillTypeAttrWithDieId(); + BuildAliasDIEs(); + // build tree from root DIE cu_ + BuildDieTree(); + BuildAbbrev(); + ComputeSizeAndOffsets(); +} + +void DebugInfo::BuildDebugInfo() { + ASSERT(mod_->dbgInfo, "null dbgInfo"); + + Init(); + + // containner types + for (auto it : mod_->typeNameTab->gStrIdxToTyIdxMap) { + GStrIdx strIdx = it.first; + TyIdx tyIdx = it.second; + MIRType *type = GlobalTables::GetTypeTable().typeTable[tyIdx.GetIdx()]; + + switch (type->typeKind) { + case kTypeClass: + case kTypeClassIncomplete: + case kTypeInterface: + case kTypeInterfaceIncomplete: + case kTypeStruct: + case kTypeStructIncomplete: + case kTypeUnion: + { + (void) GetOrCreateStructTypeDie(type); + break; + } + default: + std::cout << "named type " << GlobalTables::GetStrTable().GetStringFromStrIdx(strIdx).c_str() << "\n"; + break; + } + } + + // setup debug info for functions + for (auto func : GlobalTables::GetFunctionTable().funcTable) { + // the first one in funcTable is nullptr + if (!func) { + continue; + } + // function decl + if (stridx_dieid_map_.find(func->GetNameStridx().GetIdx()) == stridx_dieid_map_.end()) { + GetOrCreateFuncDeclDie(func, 0); + } + // function def + if (funcdef_stridx_dieid_map_.find(func->GetNameStridx().GetIdx()) == funcdef_stridx_dieid_map_.end()) { + GetOrCreateFuncDefDie(func, 0); + } + } + + // finalize debug info + Finish(); +} + +DBGDieAttr *DebugInfo::CreateAttr(dw_at at, dw_form form, uint64 val) { + DBGDieAttr *attr = mod_->memPool->New(kDwAt); + attr->dwattr_ = at; + attr->dwform_ = form; + attr->val_.u = val; + return attr; +} + +void DebugInfo::SetLocalDie(MIRFunction *func, GStrIdx strIdx, const DBGDie *die) { + (func_lstridx_dieid_map_[func])[strIdx.GetIdx()] = die->id; +} + +DBGDie *DebugInfo::GetLocalDie(MIRFunction *func, GStrIdx strIdx) { + uint32 id = (func_lstridx_dieid_map_[func])[strIdx.GetIdx()]; + return id_die_map_[id]; +} + +void DebugInfo::SetLocalDie(GStrIdx strIdx, const DBGDie *die) { + (func_lstridx_dieid_map_[mod_->CurFunction()])[strIdx.GetIdx()] = die->id; +} + +DBGDie *DebugInfo::GetLocalDie(GStrIdx strIdx) { + uint32 id = (func_lstridx_dieid_map_[mod_->CurFunction()])[strIdx.GetIdx()]; + return id_die_map_[id]; +} + +void DebugInfo::SetLabelIdx(MIRFunction *func, GStrIdx strIdx, LabelIdx labidx) { + (func_lstridx_labidx_map_[func])[strIdx.GetIdx()] = labidx; +} + +LabelIdx DebugInfo::GetLabelIdx(MIRFunction *func, GStrIdx strIdx) { + LabelIdx labidx = (func_lstridx_labidx_map_[func])[strIdx.GetIdx()]; + return labidx; +} + +void DebugInfo::SetLabelIdx(GStrIdx strIdx, LabelIdx labidx) { + (func_lstridx_labidx_map_[mod_->CurFunction()])[strIdx.GetIdx()] = labidx; +} + +LabelIdx DebugInfo::GetLabelIdx(GStrIdx strIdx) { + LabelIdx labidx = (func_lstridx_labidx_map_[mod_->CurFunction()])[strIdx.GetIdx()]; + return labidx; +} + +DBGDie *DebugInfo::CreateFormalParaDie(MIRType *type, GStrIdx nameidx, uint32 lnum) { + DBGDie *die = mod_->memPool->New(mod_, DW_TAG_formal_parameter); + + (void)GetOrCreateTypeDie(type); + die->AddAttr(DW_AT_type, DW_FORM_ref4, type->tyIdx.GetIdx()); + + /* var Name */ + if (nameidx.GetIdx()) { + die->AddAttr(DW_AT_name, DW_FORM_strp, nameidx.GetIdx()); + die->AddAttr(DW_AT_decl_file, DW_FORM_data4, mplsrcidx_.GetIdx()); + die->AddAttr(DW_AT_decl_line, DW_FORM_data4, lnum); + die->AddSimpLocAttr(DW_AT_location, DW_FORM_exprloc, kDbgDefaultVal); + SetLocalDie(nameidx, die); + } + return die; +} + +DBGDie *DebugInfo::GetOrCreateLabelDie(LabelIdx labid) { + MIRFunction *func = mod_->CurFunction(); + CHECK(labid < func->labelTab->labelTable.size(), "index out of range in DebugInfo::GetOrCreateLabelDie"); + GStrIdx strid = func->labelTab->labelTable[labid]; + if ((func_lstridx_dieid_map_[func]).size() && + (func_lstridx_dieid_map_[func]).find(strid.GetIdx()) != (func_lstridx_dieid_map_[func]).end()) { + return GetLocalDie(strid); + } + + DBGDie *die = mod_->memPool->New(mod_, DW_TAG_label); + die->AddAttr(DW_AT_name, DW_FORM_strp, strid.GetIdx()); + die->AddAttr(DW_AT_decl_file, DW_FORM_data4, mplsrcidx_.GetIdx()); + die->AddAttr(DW_AT_decl_line, DW_FORM_data4, lexer_->GetLineNum()); + die->AddAttr(DW_AT_low_pc, DW_FORM_addr, kDbgDefaultVal); + GetParentDie()->AddSubVec(die); + SetLocalDie(strid, die); + SetLabelIdx(strid, labid); + return die; +} + +DBGDie *DebugInfo::CreateVarDie(MIRSymbol *sym, uint32 lnum) { + // filter vtab + if (sym->GetName().find(VTAB_PREFIX_STR) == 0) { + return nullptr; + } + + if (sym->GetName().find(GCTIB_PREFIX_STR) == 0) { + return nullptr; + } + + if (sym->storageClass == kScFormal) { + return nullptr; + } + + bool isLocal = sym->IsLocal(); + + if (isLocal) { + MIRFunction *func = mod_->CurFunction(); + if ((func_lstridx_dieid_map_[func]).size() && + (func_lstridx_dieid_map_[func]).find(sym->nameStrIdx.GetIdx()) != (func_lstridx_dieid_map_[func]).end()) { + return GetLocalDie(sym->nameStrIdx); + } + } else { + if (stridx_dieid_map_.find(sym->nameStrIdx.GetIdx()) != stridx_dieid_map_.end()) { + uint32 id = stridx_dieid_map_[sym->nameStrIdx.GetIdx()]; + return id_die_map_[id]; + } + } + + DBGDie *die = mod_->memPool->New(mod_, DW_TAG_variable); + + /* var Name */ + die->AddAttr(DW_AT_name, DW_FORM_strp, sym->nameStrIdx.GetIdx()); + die->AddAttr(DW_AT_decl_file, DW_FORM_data4, mplsrcidx_.GetIdx()); + die->AddAttr(DW_AT_decl_line, DW_FORM_data4, lnum); + + if (isLocal) { + die->AddSimpLocAttr(DW_AT_location, DW_FORM_exprloc, kDbgDefaultVal); + } else { + // global var just use its name as address in .s + uint64 idx = sym->nameStrIdx.GetIdx(); + if ((sym->IsReflectionClassInfo() && !sym->IsReflectionArrayClassInfo()) || sym->IsStatic()) { + std::string ptrName = std::string(NameMangler::kPtrPrefixStr) + sym->GetName(); + idx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(ptrName).GetIdx(); + } + die->AddGlobalLocAttr(DW_AT_location, DW_FORM_exprloc, idx); + } + + MIRType *type = sym->GetType(); + (void)GetOrCreateTypeDie(type); + die->AddAttr(DW_AT_type, DW_FORM_ref4, type->tyIdx.GetIdx()); + + GetParentDie()->AddSubVec(die); + if (isLocal) { + SetLocalDie(sym->nameStrIdx, die); + } else { + stridx_dieid_map_[sym->nameStrIdx.GetIdx()] = die->id; + } + return die; +} + +DBGDie *DebugInfo::GetOrCreateFuncDeclDie(MIRFunction *func, uint32 lnum) { + uint32 funcnameidx = func->GetNameStridx().GetIdx(); + if (stridx_dieid_map_.find(funcnameidx) != stridx_dieid_map_.end()) { + uint32 id = stridx_dieid_map_[funcnameidx]; + return id_die_map_[id]; + } + + DBGDie *die = mod_->memPool->New(mod_, DW_TAG_subprogram); + stridx_dieid_map_[funcnameidx] = die->id; + + die->AddAttr(DW_AT_external, DW_FORM_flag_present, 1); + + // Function Name + die->AddAttr(DW_AT_name, DW_FORM_strp, funcnameidx); + die->AddAttr(DW_AT_decl_file, DW_FORM_data4, mplsrcidx_.GetIdx()); + die->AddAttr(DW_AT_decl_line, DW_FORM_data4, lnum); + + // Attributes for DW_AT_accessibility + uint32 access = 0; + if (func->IsPublic()) { + access = DW_ACCESS_public; + } else if (func->IsPrivate()) { + access = DW_ACCESS_private; + } else if (func->IsProtected()) { + access = DW_ACCESS_protected; + } + if (access) { + die->AddAttr(DW_AT_accessibility, DW_FORM_data4, access); + } + + die->AddAttr(DW_AT_GNU_all_tail_call_sites, DW_FORM_flag_present, kDbgDefaultVal); + + PushParentDie(die); + + // formal parameter + GStrIdx strIdx(0); + for (uint32 i = 0; i < func->formalDefVec.size(); i++) { + MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(func->formalDefVec[i].formalTyIdx); + DBGDie *param = CreateFormalParaDie(type, strIdx, lnum); + die->AddSubVec(param); + } + + PopParentDie(); + + return die; +} + +bool LIsCompilerGenerated(const MIRFunction *func) { + return ((func->GetName().c_str())[0] != 'L'); +} + +DBGDie *DebugInfo::GetOrCreateFuncDefDie(MIRFunction *func, uint32 lnum) { + uint32 funcnameidx = func->GetNameStridx().GetIdx(); + if (funcdef_stridx_dieid_map_.find(funcnameidx) != funcdef_stridx_dieid_map_.end()) { + uint32 id = funcdef_stridx_dieid_map_[funcnameidx]; + return id_die_map_[id]; + } + + DBGDie *funcdecldie = GetOrCreateFuncDeclDie(func, lnum); + DBGDie *die = mod_->memPool->New(mod_, DW_TAG_subprogram); + // update funcdef_stridx_dieid_map_ and leave stridx_dieid_map_ for the func decl + funcdef_stridx_dieid_map_[funcnameidx] = die->id; + + die->AddAttr(DW_AT_specification, DW_FORM_ref4, funcdecldie->id); + die->AddAttr(DW_AT_decl_line, DW_FORM_data4, lnum); + die->AddAttr(DW_AT_low_pc, DW_FORM_addr, kDbgDefaultVal); + die->AddAttr(DW_AT_high_pc, DW_FORM_data8, kDbgDefaultVal); + die->AddFrmBaseAttr(DW_AT_frame_base, DW_FORM_exprloc, kDbgDefaultVal); + if (!func->IsStatic() && !LIsCompilerGenerated(func)) { + die->AddAttr(DW_AT_object_pointer, DW_FORM_ref4, kDbgDefaultVal); + } + die->AddAttr(DW_AT_GNU_all_tail_call_sites, DW_FORM_flag_present, kDbgDefaultVal); + + PushParentDie(die); + + // formal parameter + for (uint32 i = 0; i < func->formalDefVec.size(); i++) { + MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(func->formalDefVec[i].formalTyIdx); + DBGDie *pdie = CreateFormalParaDie(type, func->formalDefVec[i].formalStrIdx, lnum); + die->AddSubVec(pdie); + } + + if (func->symTab) { + // local variables, start from 1 + for (uint32 i = 1; i < func->symTab->GetSymbolTableSize(); i++) { + MIRSymbol *var = func->symTab->GetSymbolFromStIdx(i); + DBGDie *vdie = CreateVarDie(var, 0); + die->AddSubVec(vdie); + } + } + + PopParentDie(); + + return die; +} + +DBGDie *DebugInfo::GetOrCreatePrimTypeDie(PrimType pty) { + uint32 tid = static_cast(pty); + if (tyidx_dieid_map_.find(tid) != tyidx_dieid_map_.end()) { + uint32 id = tyidx_dieid_map_[tid]; + return id_die_map_[id]; + } + + DBGDie *die = mod_->memPool->New(mod_, DW_TAG_base_type); + die->tyidx_ = static_cast(pty); + + die->AddAttr(DW_AT_byte_size, DW_FORM_data4, GetPrimTypeSize(pty)); + die->AddAttr(DW_AT_encoding, DW_FORM_data4, GetAteFromPTY(pty)); + + cu_->AddSubVec(die); + tyidx_dieid_map_[static_cast(pty)] = die->id; + return die; +} + +DBGDie *DebugInfo::GetOrCreateTypeDie(MIRType *type) { + if (!type) { + return nullptr; + } + + uint32 tid = type->tyIdx.GetIdx(); + if (tyidx_dieid_map_.find(tid) != tyidx_dieid_map_.end()) { + uint32 id = tyidx_dieid_map_[tid]; + return id_die_map_[id]; + } + + uint32 sid = type->nameStrIdx.GetIdx(); + if (sid) + if (stridx_dieid_map_.find(sid) != stridx_dieid_map_.end()) { + uint32 id = stridx_dieid_map_[sid]; + return id_die_map_[id]; + } + + if (type && type->tyIdx == static_cast(type->primType)) { + return GetOrCreatePrimTypeDie(type->primType); + } + + DBGDie *die = nullptr; + switch (type->typeKind) { + case kTypePointer: { + MIRPtrType *ptype = static_cast(type); + die = GetOrCreatePointTypeDie(ptype); + break; + } + case kTypeArray: + case kTypeFArray: + case kTypeJArray: { + MIRArrayType *atype = static_cast(type); + die = GetOrCreateArrayTypeDie(atype); + break; + } + case kTypeUnion: + case kTypeStruct: + case kTypeStructIncomplete: + case kTypeClass: + case kTypeClassIncomplete: + case kTypeInterface: + case kTypeInterfaceIncomplete: { + die = GetOrCreateStructTypeDie(type); + break; + } + case kTypeBitField: + break; + default: + CHECK_FATAL(false, "TODO: support type"); + break; + } + + return die; +} + +DBGDie *DebugInfo::GetOrCreatePointTypeDie(const MIRPtrType *ptrtype) { + uint32 tid = ptrtype->tyIdx.GetIdx(); + if (tyidx_dieid_map_.find(tid) != tyidx_dieid_map_.end()) { + uint32 id = tyidx_dieid_map_[tid]; + return id_die_map_[id]; + } + + MIRType *type = ptrtype->GetPointedType(); + // for <* void> + if (type && type->primType == PTY_void) { + DBGDie *die = mod_->memPool->New(mod_, DW_TAG_pointer_type); + die->AddAttr(DW_AT_byte_size, DW_FORM_data4, 8); + tyidx_dieid_map_[ptrtype->tyIdx.GetIdx()] = die->id; + cu_->AddSubVec(die); + return die; + } + + (void)GetOrCreateTypeDie(type); + if (typedef_tyidx_map_.find(type->tyIdx.GetIdx()) != typedef_tyidx_map_.end()) { + uint32 tid = typedef_tyidx_map_[type->tyIdx.GetIdx()]; + if (pointed_pointer_map_.find(tid) != pointed_pointer_map_.end()) { + uint32 tyid = pointed_pointer_map_[tid]; + if (tyidx_dieid_map_.find(tyid) != tyidx_dieid_map_.end()) { + uint32 dieid = tyidx_dieid_map_[tyid]; + DBGDie *die = id_die_map_[dieid]; + return die; + } + } + } + + // update incomplete type from stridx_dieid_map_ to tyidx_dieid_map_ + MIRStructType *stype = dynamic_cast(type); + if (stype && stype->IsIncomplete()) { + uint32 sid = stype->nameStrIdx.GetIdx(); + if (stridx_dieid_map_.find(sid) != stridx_dieid_map_.end()) { + uint32 dieid = stridx_dieid_map_[sid]; + if (dieid) { + tyidx_dieid_map_[stype->tyIdx.GetIdx()] = dieid; + } + } + } + + DBGDie *die = mod_->memPool->New(mod_, DW_TAG_pointer_type); + die->AddAttr(DW_AT_byte_size, DW_FORM_data4, 8); + // fill with type idx instead of typedie->id to avoid nullptr typedie of + // forward reference of class types + die->AddAttr(DW_AT_type, DW_FORM_ref4, type->tyIdx.GetIdx()); + tyidx_dieid_map_[ptrtype->tyIdx.GetIdx()] = die->id; + + cu_->AddSubVec(die); + + return die; +} + +DBGDie *DebugInfo::GetOrCreateArrayTypeDie(const MIRArrayType *arraytype) { + uint32 tid = arraytype->tyIdx.GetIdx(); + if (tyidx_dieid_map_.find(tid) != tyidx_dieid_map_.end()) { + uint32 id = tyidx_dieid_map_[tid]; + return id_die_map_[id]; + } + + MIRType *type = arraytype->GetElemType(); + (void)GetOrCreateTypeDie(type); + + DBGDie *die = mod_->memPool->New(mod_, DW_TAG_array_type); + die->AddAttr(DW_AT_byte_size, DW_FORM_data4, 8); + // fill with type idx instead of typedie->id to avoid nullptr typedie of + // forward reference of class types + die->AddAttr(DW_AT_type, DW_FORM_ref4, type->tyIdx.GetIdx()); + tyidx_dieid_map_[arraytype->tyIdx.GetIdx()] = die->id; + + cu_->AddSubVec(die); + + // maple uses array of 1D array to represent 2D array + // so only one DW_TAG_subrange_type entry is needed + DBGDie *rangedie = mod_->memPool->New(mod_, DW_TAG_subrange_type); + PrimType prmtype = PTY_u32; + (void)GetOrCreatePrimTypeDie(prmtype); + rangedie->AddAttr(DW_AT_type, DW_FORM_ref4, PTY_u32); + rangedie->AddAttr(DW_AT_upper_bound, DW_FORM_data4, arraytype->sizeArray[0]); + + die->AddSubVec(rangedie); + + return die; +} + +DBGDie *DebugInfo::CreateFieldDie(maple::FieldPair pair, uint32 lnum) { + DBGDie *die = mod_->memPool->New(mod_, DW_TAG_member); + + die->AddAttr(DW_AT_name, DW_FORM_strp, pair.first.GetIdx()); + die->AddAttr(DW_AT_decl_file, DW_FORM_data4, mplsrcidx_.GetIdx()); + die->AddAttr(DW_AT_decl_line, DW_FORM_data4, lnum); + + MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(pair.second.first); + (void)GetOrCreateTypeDie(type); + // fill with type idx instead of typedie->id to avoid nullptr typedie of + // forward reference of class types + die->AddAttr(DW_AT_type, DW_FORM_ref4, type->tyIdx.GetIdx()); + + die->AddAttr(DW_AT_data_member_location, DW_FORM_data4, kDbgDefaultVal); + + return die; +} + +DBGDie *DebugInfo::GetOrCreateStructTypeDie(const MIRType *type) { + ASSERT(type, "null struture type"); + GStrIdx strIdx = type->nameStrIdx; + ASSERT(strIdx.GetIdx(), "struture type missing name"); + + if (tyidx_dieid_map_.find(type->tyIdx.GetIdx()) != tyidx_dieid_map_.end()) { + uint32 id = tyidx_dieid_map_[type->tyIdx.GetIdx()]; + return id_die_map_[id]; + } + + DBGDie *die = nullptr; + switch (type->typeKind) { + case kTypeClass: + case kTypeClassIncomplete: + { + const MIRClassType *classtype = static_cast(type); + die = CreateClassTypeDie(strIdx, classtype); + break; + } + case kTypeInterface: + case kTypeInterfaceIncomplete: + { + const MIRInterfaceType *interfacetype = static_cast(type); + die = CreateInterfaceTypeDie(strIdx, interfacetype); + break; + } + case kTypeStruct: + case kTypeStructIncomplete: + case kTypeUnion: + { + const MIRStructType *stype = static_cast(type); + die = CreateStructTypeDie(strIdx, stype, false); + break; + } + default: + std::cout << "named type " << GlobalTables::GetStrTable().GetStringFromStrIdx(strIdx).c_str() << "\n"; + break; + } + + GlobalTables::GetTypeNameTable().SetGStrIdxToTyIdx(strIdx, type->tyIdx); + return die; +} + +// shared between struct and union +DBGDie *DebugInfo::CreateStructTypeDie(GStrIdx strIdx, const MIRStructType *structtype, bool update) { + DBGDie *die = nullptr; + + if (update) { + uint32 id = tyidx_dieid_map_[structtype->tyIdx.GetIdx()]; + die = id_die_map_[id]; + ASSERT(die, "update type die not exist"); + } else { + dw_tag tag = structtype->typeKind == kTypeStruct ? DW_TAG_structure_type : DW_TAG_union_type; + die = mod_->memPool->New(mod_, tag); + tyidx_dieid_map_[structtype->tyIdx.GetIdx()] = die->id; + } + + if (strIdx.GetIdx()) { + stridx_dieid_map_[strIdx.GetIdx()] = die->id; + } + + cu_->AddSubVec(die); + + die->AddAttr(DW_AT_decl_line, DW_FORM_data4, 8888); + die->AddAttr(DW_AT_name, DW_FORM_strp, strIdx.GetIdx()); + die->AddAttr(DW_AT_byte_size, DW_FORM_data4, kDbgDefaultVal); + die->AddAttr(DW_AT_decl_file, DW_FORM_data4, mplsrcidx_.GetIdx()); + + PushParentDie(die); + + // fields + for (int64 i = 0; i < structtype->fields.size(); i++) { + FieldPair fp = structtype->fields[i]; + DBGDie *fdie = CreateFieldDie(fp, 0); + die->AddSubVec(fdie); + } + + // parentFields + for (int64 i = 0; i < structtype->parentFields.size(); i++) { + FieldPair fp = structtype->parentFields[i]; + DBGDie *fdie = CreateFieldDie(fp, 0); + die->AddSubVec(fdie); + } + + // member functions decl + for (auto fp : structtype->methods) { + MIRSymbol *symbol = GlobalTables::GetGsymTable().GetSymbolFromStIdx(fp.first.Idx()); + ASSERT(symbol && symbol->sKind == kStFunc, "member function symbol not exist"); + MIRFunction *func = symbol->value.mirFunc; + ASSERT(func, "member function not exist"); + DBGDie *fdie = GetOrCreateFuncDeclDie(func, 0); + die->AddSubVec(fdie); + } + + PopParentDie(); + + // member functions defination, these die are global + for (auto fp : structtype->methods) { + MIRSymbol *symbol = GlobalTables::GetGsymTable().GetSymbolFromStIdx(fp.first.Idx()); + ASSERT(symbol && symbol->sKind == kStFunc, "member function symbol not exist"); + MIRFunction *func = symbol->value.mirFunc; + ASSERT(func, "member function not exist"); + DBGDie *fdie = GetOrCreateFuncDefDie(func, 0); + cu_->AddSubVec(fdie); + } + + return die; +} + +DBGDie *DebugInfo::CreateClassTypeDie(GStrIdx strIdx, const MIRClassType *classtype) { + DBGDie *die = mod_->memPool->New(mod_, DW_TAG_class_type); + + PushParentDie(die); + + // parent + uint32 ptid = classtype->parentTyIdx.GetIdx(); + if (ptid) { + MIRType *parenttype = GlobalTables::GetTypeTable().GetTypeFromTyIdx(classtype->parentTyIdx); + DBGDie *parentdie = GetOrCreateTypeDie(parenttype); + if (parentdie) { + parentdie = mod_->memPool->New(mod_, DW_TAG_inheritance); + parentdie->AddAttr(DW_AT_name, DW_FORM_strp, parenttype->nameStrIdx.GetIdx()); + parentdie->AddAttr(DW_AT_type, DW_FORM_ref4, ptid); + + // set to DW_ACCESS_public for now + parentdie->AddAttr(DW_AT_accessibility, DW_FORM_data4, DW_ACCESS_public); + die->AddSubVec(parentdie); + } + } + + PopParentDie(); + + // update common fields + tyidx_dieid_map_[classtype->tyIdx.GetIdx()] = die->id; + DBGDie *die1 = CreateStructTypeDie(strIdx, classtype, true); + ASSERT(die == die1, "ClassTypeDie update wrong die"); + + return die; +} + +DBGDie *DebugInfo::CreateInterfaceTypeDie(GStrIdx strIdx, const MIRInterfaceType *interfacetype) { + DBGDie *die = mod_->memPool->New(mod_, DW_TAG_interface_type); + + PushParentDie(die); + + // parents + for (auto it : interfacetype->parentsTyIdx) { + MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(it); + DBGDie *parentdie = GetOrCreateTypeDie(type); + if (parentdie) { + continue; + } + parentdie = mod_->memPool->New(mod_, DW_TAG_inheritance); + parentdie->AddAttr(DW_AT_name, DW_FORM_strp, type->nameStrIdx.GetIdx()); + parentdie->AddAttr(DW_AT_type, DW_FORM_ref4, it.GetIdx()); + parentdie->AddAttr(DW_AT_data_member_location, DW_FORM_data4, kDbgDefaultVal); + + // set to DW_ACCESS_public for now + parentdie->AddAttr(DW_AT_accessibility, DW_FORM_data4, DW_ACCESS_public); + die->AddSubVec(parentdie); + } + + PopParentDie(); + + // update common fields + tyidx_dieid_map_[interfacetype->tyIdx.GetIdx()] = die->id; + DBGDie *die1 = CreateStructTypeDie(strIdx, interfacetype, true); + ASSERT(die == die1, "InterfaceTypeDie update wrong die"); + + return die; +} + +uint32 DebugInfo::GetAbbrevId(DBGAbbrevEntryVec *vec, DBGAbbrevEntry *entry) { + for (auto it : vec->entryvec_) { + if (it->Equalto(entry)) { + return it->abbrevid_; + } + } + return 0; +} + +void DebugInfo::BuildAbbrev() { + uint32 abbrevid = 1; + for (uint32 i = 1; i < maxid_; i++) { + DBGDie *die = id_die_map_[i]; + DBGAbbrevEntry *entry = mod_->memPool->New(mod_, die); + + if (!tag_abbrev_map_[die->tag_]) { + tag_abbrev_map_[die->tag_] = mod_->memPool->New(mod_, die->tag_); + } + + uint32 id = GetAbbrevId(tag_abbrev_map_[die->tag_], entry); + if (id) { + // using existing abbrev id + die->abbrevid_ = id; + // free(entry); + } else { + // add entry to vector + entry->abbrevid_ = abbrevid++; + tag_abbrev_map_[die->tag_]->entryvec_.push_back(entry); + abbrev_vec_.push_back(entry); + // update abbrevid in die + die->abbrevid_ = entry->abbrevid_; + } + } + for (uint32 i = 1; i < maxid_; i++) { + DBGDie *die = id_die_map_[i]; + if (die->abbrevid_ == 0) { + std::cout << "0 abbrevid_ i = " << i << " die->id = " << die->id << std::endl; + } + } +} + +void DebugInfo::BuildDieTree() { + for (auto it : id_die_map_) { + if (!it.first) { + continue; + } + DBGDie *die = it.second; + uint32 size = die->subdievec_.size(); + die->withchildren_ = (size > 0); + if (size) { + die->firstchild = die->subdievec_[0]; + for (uint32 i = 0; i < size - 1; i++) { + DBGDie *it = die->subdievec_[i]; + DBGDie *it1 = die->subdievec_[i + 1]; + if (it->subdievec_.size()) { + it->sibling = it1; + it->AddAttr(DW_AT_sibling, DW_FORM_ref4, it1->id); + } + } + } + } +} + +void DebugInfo::FillTypeAttrWithDieId() { + for (auto it : id_die_map_) { + DBGDie *die = it.second; + for (auto at : die->attrvec_) { + if (at->dwattr_ == DW_AT_type) { + uint32 tid = at->val_.id; + MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(TyIdx(tid)); + if (type) { + uint32 dieid = tyidx_dieid_map_[tid]; + if (dieid) { + at->val_.id = dieid; + } else { + LogInfo::MapleLogger() << "dieid not found, typeKind = " << type->typeKind << " primType = " << type->primType + << " nameStrIdx = " << type->nameStrIdx.GetIdx() << std::endl; + } + } else { + LogInfo::MapleLogger() << "type not found, tid = " << tid << std::endl; + } + break; + } + } + } +} + +DBGDie *DebugInfo::GetDie(const MIRFunction *func) { + uint32 id = stridx_dieid_map_[func->GetNameStridx().GetIdx()]; + if (id) { + return id_die_map_[id]; + } + return nullptr; +} + +// Methods for calculating Offset and Size of DW_AT_xxx +uint32 DBGDieAttr::SizeOf(DBGDieAttr *attr) { + dw_form form = attr->dwform_; + switch (form) { + // case DW_FORM_implicitconst: + case DW_FORM_flag_present: + return 0; // Not handled yet. + case DW_FORM_flag: + case DW_FORM_ref1: + case DW_FORM_data1: + return sizeof(int8); + case DW_FORM_ref2: + case DW_FORM_data2: + return sizeof(int16); + case DW_FORM_ref4: + case DW_FORM_data4: + return sizeof(int32); + case DW_FORM_ref8: + case DW_FORM_ref_sig8: + case DW_FORM_data8: + return sizeof(int64); + case DW_FORM_addr: + return sizeof(int64); + case DW_FORM_sec_offset: + case DW_FORM_ref_addr: + case DW_FORM_strp: + case DW_FORM_GNU_ref_alt: + // case DW_FORM_line_strp: + // case DW_FORM_strp_sup: + // case DW_FORM_ref_sup: + return 4; // DWARF32, 8 if DWARF64 + + case DW_FORM_string: { + const std::string &str = GlobalTables::GetStrTable().GetStringFromStrIdx(attr->val_.id); + return str.length() + 1 /* terminal null byte */; + } + case DW_FORM_exprloc: { + DBGExprLoc *ptr = attr->val_.ptr; + CHECK_FATAL(ptr != (DBGExprLoc *)0xdeadbeef, "wrong ptr"); + switch (ptr->GetOp()) { + case DW_OP_call_frame_cfa: + return 2; // size 1 byte + DW_OP_call_frame_cfa 1 byte + case DW_OP_fbreg: { + // DW_OP_fbreg 1 byte + uint32 size = 1 + NameMangler::GetSleb128Size(ptr->GetFboffset()); + return size + NameMangler::GetUleb128Size(size); + } + case DW_OP_addr: { + return NameMangler::GetUleb128Size(9) + 9; + } + default: + return 4; + } + } + default: + CHECK_FATAL(maple::get_DW_FORM_name(form) != nullptr, + "get_DW_FORM_name return null in DebugInfo::FillTypeAttrWithDieId"); + LogInfo::MapleLogger() << "unhandled SizeOf: " << maple::get_DW_FORM_name(form) << std::endl; + return 0; + } +} + +void DebugInfo::ComputeSizeAndOffsets() { + // CU-relative offset is reset to 0 here. + uint32 cuOffset = sizeof(int32_t) // Length of Unit Info + + sizeof(int16) // DWARF version number : 0x0004 + + sizeof(int32) // Offset into Abbrev. Section : 0x0000 + + sizeof(int8); // Pointer Size (in bytes) : 0x08 + + // After returning from this function, the length value is the size + // of the .debug_info section + ComputeSizeAndOffset(cu_, cuOffset); + debug_info_length_ = cuOffset - sizeof(int32_t); +} + +// Compute the size and offset of a DIE. The Offset is relative to start of the CU. +// It returns the offset after laying out the DIE. +void DebugInfo::ComputeSizeAndOffset(DBGDie *die, uint32 &cuOffset) { + uint32 cuOffsetOrg = cuOffset; + die->Offset = cuOffset; + + // Add the byte size of the abbreviation code + cuOffset += static_cast(NameMangler::GetUleb128Size(uint64_t(die->abbrevid_))); + + // Add the byte size of all the DIE attributes. + for (const auto &attr : die->attrvec_) { + cuOffset += attr->SizeOf(attr); + } + + die->Size = cuOffset - cuOffsetOrg; + + // Let the children compute their offsets. + if (die->withchildren_) { + uint32 size = die->subdievec_.size(); + + for (uint32 i = 0; i < size; i++) { + DBGDie *childDie = die->subdievec_[i]; + ComputeSizeAndOffset(childDie, cuOffset); + } + + // Each child chain is terminated with a zero byte, adjust the offset. + cuOffset += sizeof(int8); + } +} + +/////////////////////////////// +// Dumps +/////////////////////////////// +void DebugInfo::Dump(int indent) { + LogInfo::MapleLogger() << "\n" << std::endl; + LogInfo::MapleLogger() << "maple_debug_information {" + << " Length: " << HEX(debug_info_length_) << std::endl; + cu_->Dump(indent + 1); + LogInfo::MapleLogger() << "}\n" << std::endl; + LogInfo::MapleLogger() << "maple_debug_abbrev {" << std::endl; + for (uint32 i = 1; i < abbrev_vec_.size(); i++) { + abbrev_vec_[i]->Dump(indent + 1); + } + LogInfo::MapleLogger() << "}" << std::endl; + return; +} + +void DBGExprLoc::Dump() { + LogInfo::MapleLogger() << " " << HEX(GetOp()); + for (auto it : simploc_->opnds_) { + LogInfo::MapleLogger() << " " << HEX(it); + } +} + +void DBGDieAttr::Dump(int indent) { + PrintIndentation(indent); + CHECK_FATAL(get_DW_FORM_name(dwform_) && get_DW_AT_name(dwattr_), "null ptr check"); + LogInfo::MapleLogger() << get_DW_AT_name(dwattr_) << " " << get_DW_FORM_name(dwform_); + if (dwform_ == DW_FORM_string || dwform_ == DW_FORM_strp) { + GStrIdx idx(val_.id); + LogInfo::MapleLogger() << " 0x" << std::hex << val_.u << std::dec; + LogInfo::MapleLogger() << " \"" << GlobalTables::GetStrTable().GetStringFromStrIdx(idx).c_str() << "\""; + } else if (dwform_ == DW_FORM_ref4) { + LogInfo::MapleLogger() << " <" << HEX(val_.id) << ">"; + } else if (dwattr_ == DW_AT_encoding) { + CHECK_FATAL(get_DW_ATE_name(val_.u), "null ptr check"); + LogInfo::MapleLogger() << " " << get_DW_ATE_name(val_.u); + } else if (dwattr_ == DW_AT_location) { + val_.ptr->Dump(); + } else { + LogInfo::MapleLogger() << " 0x" << std::hex << val_.u << std::dec; + } + LogInfo::MapleLogger() << std::endl; +} + +void DBGDie::Dump(int indent) { + PrintIndentation(indent); + LogInfo::MapleLogger() << "<" << HEX(id) << "><" << HEX(Offset); + LogInfo::MapleLogger() << "><" << HEX(Size) << "><" + << "> abbrev id: " << HEX(abbrevid_); + CHECK_FATAL(get_DW_TAG_name(tag_), "null ptr check"); + LogInfo::MapleLogger() << " (" << get_DW_TAG_name(tag_) << ") "; + if (parent) { + LogInfo::MapleLogger() << "parent <" << HEX(parent->id); + } + LogInfo::MapleLogger() << "> {"; + if (tyidx_) { + MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(TyIdx(tyidx_)); + if (type->typeKind == kTypeStruct || type->typeKind == kTypeClass || type->typeKind == kTypeInterface) { + MIRStructType *stype = static_cast(type); + LogInfo::MapleLogger() << " # " << stype->GetName(); + } else { + LogInfo::MapleLogger() << " # " << GetPrimTypeName(type->primType); + } + } + LogInfo::MapleLogger() << std::endl; + ; + for (auto it : attrvec_) { + it->Dump(indent + 1); + } + PrintIndentation(indent); + LogInfo::MapleLogger() << "} "; + if (subdievec_.size()) { + LogInfo::MapleLogger() << " {" << std::endl; + for (auto it : subdievec_) { + it->Dump(indent + 1); + } + PrintIndentation(indent); + LogInfo::MapleLogger() << "}"; + } + LogInfo::MapleLogger() << std::endl; + return; +} + +void DBGAbbrevEntry::Dump(int indent) { + PrintIndentation(indent); + CHECK_FATAL(get_DW_TAG_name(tag_), "null ptr check "); + LogInfo::MapleLogger() << "<" << HEX(abbrevid_) << "> " << get_DW_TAG_name(tag_); + if (withchildren_) { + LogInfo::MapleLogger() << " [with children] {" << std::endl; + } else { + LogInfo::MapleLogger() << " [no children] {" << std::endl; + } + for (uint32 i = 0; i < attrpairs_.size(); i += 2) { + PrintIndentation(indent + 1); + CHECK_FATAL(get_DW_AT_name(attrpairs_[i]) && get_DW_FORM_name(attrpairs_[i + 1]), "NULLPTR CHECK"); + + LogInfo::MapleLogger() << " " << get_DW_AT_name(attrpairs_[i]) << " " << get_DW_FORM_name(attrpairs_[i + 1]) << " " << std::endl; + } + PrintIndentation(indent); + LogInfo::MapleLogger() << "}" << std::endl; + return; +} + +void DBGAbbrevEntryVec::Dump(int indent) { + for (auto it : entryvec_) { + PrintIndentation(indent); + it->Dump(indent); + } + return; +} + +// DBGCompileMsgInfo methods +void DBGCompileMsgInfo::ClearLine(uint32 n) { + errno_t eNum = memset_s(line_[n], MAXLINELEN, 0, MAXLINELEN); + if (eNum) { + FATAL(kLncFatal, "memset_s failed"); + } +} + +DBGCompileMsgInfo::DBGCompileMsgInfo() : startline_(0), errpos_(0) { + linenum_[0] = 0; + linenum_[1] = 0; + linenum_[2] = 0; + ClearLine(0); + ClearLine(1); + ClearLine(2); + err_l_num_ = 0; + err_c_num_ = 0; +} + +void DBGCompileMsgInfo::SetErrPos(uint32 lnum, uint32 cnum) { + err_l_num_ = lnum; + err_c_num_ = cnum; +} + +void DBGCompileMsgInfo::UpdateMsg(uint32 lnum, const char *line) { + // LogInfo::MapleLogger() << "get #" << lnum << " "<< line << std::endl; + size_t size = strlen(line); + if (size > MAXLINELEN - 1) { + size = MAXLINELEN - 1; + } + startline_ = (startline_ + 2) % 3; + ClearLine(startline_); + errno_t eNum = memcpy_s(line_[startline_], MAXLINELEN, line, size); + if (eNum) { + FATAL(kLncFatal, "memcpy_s failed"); + } + line_[startline_][size] = '\0'; + linenum_[startline_] = lnum; +} + +void DBGCompileMsgInfo::EmitMsg() { + char str[MAXLINELEN + 1]; + + errpos_ = err_c_num_; + errpos_ = (errpos_ < 2) ? 2 : errpos_; + errpos_ = (errpos_ > MAXLINELEN) ? MAXLINELEN : errpos_; + for (uint32 i = 0; i < errpos_ - 1; i++) { + str[i] = ' '; + } + str[errpos_ - 1] = '^'; + str[errpos_] = '\0'; + + fprintf(stderr, "\n===================================================================\n"); + fprintf(stderr, "=================="); + fprintf(stderr, BOLD YEL " Compilation Error Diagnosis " RESET); + fprintf(stderr, "==================\n"); + fprintf(stderr, "===================================================================\n"); + fprintf(stderr, "line %4d %s\n", linenum_[(startline_ + 2) % 3], + reinterpret_cast(line_[(startline_ + 2) % 3])); + fprintf(stderr, "line %4d %s\n", linenum_[(startline_ + 1) % 3], + reinterpret_cast(line_[(startline_ + 1) % 3])); + fprintf(stderr, "line %4d %s\n", linenum_[(startline_ + 0) % 3], + reinterpret_cast(line_[(startline_ + 0) % 3])); + fprintf(stderr, BOLD RED " %s\n" RESET, str); + fprintf(stderr, "===================================================================\n"); +} + +} // namespace maple diff --git a/mapleall/maple_ir/src/debug_info_util.cpp b/mapleall/maple_ir/src/debug_info_util.cpp new file mode 100644 index 0000000..0954608 --- /dev/null +++ b/mapleall/maple_ir/src/debug_info_util.cpp @@ -0,0 +1,156 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#include "mir_builder.h" +#include "printing.h" +#include "maple_string.h" +#include "name_mangler.h" +#include "debug_info.h" +#include "global_tables.h" +#include "mir_type.h" +#include +#include "securec.h" +#include "mpl_logging.h" + +namespace maple { + +// utility functions to get the string from tag value etc. +// get_DW_TAG_name(unsigned n) +#define DW_FIRST_TAG(name, value) \ + const char *get_DW_TAG_name(unsigned n) { \ + switch (n) { \ + DW_TAG(name, value) +#define DW_TAG(name, value) \ + case name: \ + return #name; +#define DW_END_TAG \ + } \ + return 0; \ + } +#define DW_TAG_DUP(name, value) + +// get_DW_FORM_name(unsigned n) +#define DW_FIRST_FORM(name, value) \ + const char *get_DW_FORM_name(unsigned n) { \ + switch (n) { \ + DW_FORM(name, value) +#define DW_FORM(name, value) \ + case name: \ + return #name; +#define DW_END_FORM \ + } \ + return 0; \ + } + +// get_DW_AT_name(unsigned n) +#define DW_FIRST_AT(name, value) \ + const char *get_DW_AT_name(unsigned n) { \ + switch (n) { \ + DW_AT(name, value) +#define DW_AT(name, value) \ + case name: \ + return #name; +#define DW_END_AT \ + } \ + return 0; \ + } +#define DW_AT_DUP(name, value) + +// get_DW_OP_name(unsigned n) +#define DW_FIRST_OP(name, value) \ + const char *get_DW_OP_name(unsigned n) { \ + switch (n) { \ + DW_OP(name, value) +#define DW_OP(name, value) \ + case name: \ + return #name; +#define DW_END_OP \ + } \ + return 0; \ + } +#define DW_OP_DUP(name, value) + +// get_DW_ATE_name(unsigned n) +#define DW_FIRST_ATE(name, value) \ + const char *get_DW_ATE_name(unsigned n) { \ + switch (n) { \ + DW_ATE(name, value) +#define DW_ATE(name, value) \ + case name: \ + return #name; +#define DW_END_ATE \ + } \ + return 0; \ + } +#define DW_ATE_DUP(name, value) + +// get_DW_CFA_name(unsigned n) +#define DW_FIRST_CFA(name, value) \ + const char *get_DW_CFA_name(unsigned n) { \ + switch (n) { \ + DW_CFA(name, value) +#define DW_CFA(name, value) \ + case name: \ + return #name; +#define DW_END_CFA \ + } \ + return 0; \ + } + +#define DW_CFA_DUP(name, value) +#define DW_FIRST_IDX(name, value) +#define DW_IDX(name, value) +#define DW_IDX_DUP(name, value) +#define DW_END_IDX + +#include "dwarf2.def" + +dw_ate GetAteFromPTY(PrimType pty) { + switch (pty) { + case PTY_u1: + return DW_ATE_boolean; + case PTY_u8: + return DW_ATE_unsigned_char; + case PTY_u16: + case PTY_u32: + case PTY_u64: + return DW_ATE_unsigned; + case PTY_i8: + return DW_ATE_signed_char; + case PTY_i16: + case PTY_i32: + case PTY_i64: + return DW_ATE_signed; + case PTY_f32: + case PTY_f64: + case PTY_f128: + return DW_ATE_float; + case PTY_agg: + case PTY_ref: + case PTY_ptr: + case PTY_a32: + case PTY_a64: + return DW_ATE_address; + case PTY_c64: + case PTY_c128: + return DW_ATE_complex_float; + case PTY_void: + return DW_ATE_void; + default: + return DW_ATE_void; + } +} + +} // namespace maple diff --git a/mapleall/maple_ir/src/lexer.cpp b/mapleall/maple_ir/src/lexer.cpp index 4fdf657..58074f3 100644 --- a/mapleall/maple_ir/src/lexer.cpp +++ b/mapleall/maple_ir/src/lexer.cpp @@ -19,6 +19,7 @@ #include #include "mpl_logging.h" #include "mir_module.h" +#include "debug_info.h" #include "securec.h" #include "utils.h" @@ -98,6 +99,7 @@ void MIRLexer::PrepareForFile(const char *filename) { lineNum = 1; } + module->dbgInfo->UpdateMsg(lineNum, line.c_str()); kind = TK_invalid; } @@ -547,6 +549,7 @@ TokenKind MIRLexer::LexToken(void) { return TK_eof; } lineNum++; // a new line readed. + module->dbgInfo->UpdateMsg(lineNum, line.c_str()); // skip spaces c = GetCurrentCharWithUpperCheck(); while (c == ' ' || c == '\t') { diff --git a/mapleall/maple_ir/src/mir_module.cpp b/mapleall/maple_ir/src/mir_module.cpp index 3a28fa6..ad474c3 100644 --- a/mapleall/maple_ir/src/mir_module.cpp +++ b/mapleall/maple_ir/src/mir_module.cpp @@ -19,6 +19,7 @@ #include "mir_function.h" #include "mir_builder.h" #include "intrinsics.h" +#include "debug_info.h" #include "bin_mplt.h" #define DEBUG_SYMBOL 1 @@ -71,10 +72,12 @@ MIRModule::MIRModule(const char *fn) globalWordsRefCounted = nullptr; mainFuncID = 0; numFuncs = 0; + withDbgInfo = false; withProfileInfo = false; GlobalTables::GetGsymTable().module = this; typeNameTab = memPool->New(&memPoolAllocator); mirBuilder = memPool->New(this); + dbgInfo = memPool->New(this); IntrinDesc::InitMIRModule(this); binMplt = nullptr; useFuncCodeMpTmp = false; @@ -678,6 +681,9 @@ void MIRModule::OutputAsciiMpl(const char *phaseName, const char *suffix, std::streambuf *backup = LogInfo::MapleLogger().rdbuf(); LogInfo::MapleLogger().rdbuf(mplfile.rdbuf()); // change LogInfo::MapleLogger()'s buffer to that of file Dump(emitStructureType, dumpFuncSet); + if (withDbgInfo) { + dbgInfo->Dump(0); + } LogInfo::MapleLogger().rdbuf(backup); // restore LogInfo::MapleLogger()'s buffer mplfile.close(); } else { diff --git a/mapleall/maple_ir/src/mir_parser_stmt.cpp b/mapleall/maple_ir/src/mir_parser_stmt.cpp index 29d837b..2c03125 100644 --- a/mapleall/maple_ir/src/mir_parser_stmt.cpp +++ b/mapleall/maple_ir/src/mir_parser_stmt.cpp @@ -16,6 +16,7 @@ #include "mir_parser.h" #include "mir_function.h" #include "opcode_info.h" +#include "debug_info.h" using namespace std; namespace maple { diff --git a/mapleall/maple_ir/src/mir_type.cpp b/mapleall/maple_ir/src/mir_type.cpp index aaae4c9..0807c5b 100644 --- a/mapleall/maple_ir/src/mir_type.cpp +++ b/mapleall/maple_ir/src/mir_type.cpp @@ -967,16 +967,13 @@ static void DumpInterfaces(std::vector interfaces, int indent) { size_t MIRStructType::GetSize() const { if (typeKind == kTypeUnion) { if (fields.size() == 0) { - return 0; + return isCPlusPlus ? 1 : 0; } size_t maxSize = 0; for (size_t i = 0; i < fields.size(); ++i) { TyidxFieldAttrPair tfap = GetTyidxFieldAttrPair(i); MIRType *fieldType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tfap.first); size_t size = RoundUp(fieldType->GetSize(), tfap.second.GetAlign()); - if (size == 0) { - return 0; - } if (maxSize < size) { maxSize = size; } @@ -1016,6 +1013,9 @@ size_t MIRStructType::GetSize() const { byteOfst = (bitOfst >> 3) + 1; } byteOfst = RoundUp(byteOfst, GetAlign()); + if (byteOfst == 0 && isCPlusPlus) { + return 1; // empty struct in C++ has size 1 + } return byteOfst; } diff --git a/mapleall/maple_ir/src/mpl_dbg.cpp b/mapleall/maple_ir/src/mpl_dbg.cpp new file mode 100644 index 0000000..67d22ad --- /dev/null +++ b/mapleall/maple_ir/src/mpl_dbg.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan Permissive Software License v2. + * You can use this software according to the terms and conditions of the MulanPSL - 2.0. + * You may obtain a copy of MulanPSL - 2.0 at: + * + * https://opensource.org/licenses/MulanPSL-2.0 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the MulanPSL - 2.0 for more details. + */ + +#include "mir_parser.h" +#include "debug_info.h" +#include "bin_mplt.h" +#include "opcode_info.h" +#include +#include "mir_function.h" +#include "constant_fold.h" +#include "mir_type.h" +#include +#include + +using namespace maple; + +std::unordered_set dumpFuncSet = {}; + +bool ConstantFoldModule(maple::MIRModule *module) { + maple::ConstantFold cf(module); + MapleVector &funcList = module->functionList; + for (MapleVector::iterator it = funcList.begin(); it != funcList.end(); it++) { + maple::MIRFunction *curfun = *it; + maple::BlockNode *block = curfun->body; + module->SetCurFunction(curfun); + if (!block) { + continue; + } + cf.Simplify(block); + } + return true; +} + +int main(int argc, char **argv) { + if (argc < 2) { + MIR_PRINTF("usage: mpldbg foo.mpl\n"); + exit(1); + } + std::vector themodule(argc, nullptr); + bool useBinary = false; + MIRSrcLang srcLang = kSrcLangUnknown; + // process the options which must come first + maple::int32 i = 1; + while (argv[i][0] == '-' ) { + if (argv[i][1] == 'b' && argv[i][2] == '\0') { + useBinary = true; + } else if (strncmp(argv[i], "-dumpfunc=", 10) == 0 && strlen(argv[i]) > 10) { + std::string funcName(&argv[i][10]); + dumpFuncSet.insert(funcName); + } else if (strcmp(argv[i], "-srclang=java") == 0 ) { + srcLang = kSrcLangJava; + } else if (strcmp(argv[i], "-srclang=c") == 0 ) { + srcLang = kSrcLangC; + } else if (strcmp(argv[i], "-srclang=c++") == 0 ) { + srcLang = kSrcLangCPlusPlus; + } else { + ERR(kLncErr, "mpldbg: unrecognized command line option"); + return 1; + } + i++; + } + // process the input files + while (i < argc) { + themodule[i] = new maple::MIRModule(argv[i]); + themodule[i]->srcLang = srcLang; + std::string::size_type lastdot = themodule[i]->fileName.find_last_of("."); + bool ismplt = themodule[i]->fileName.compare(lastdot, 5, ".mplt") == 0; + bool istmpl = themodule[i]->fileName.compare(lastdot, 5, ".tmpl") == 0; + bool ismpl = themodule[i]->fileName.compare(lastdot, 5, ".mpl\0") == 0; + bool isbpl = themodule[i]->fileName.compare(lastdot, 5, ".bpl\0") == 0; + if (!ismplt && !istmpl && !ismpl && !isbpl) { + ERR(kLncErr, "mpldbg: input must be .mplt or .mpl or .bpl or .tmpl file"); + return 1; + } + // input the file + if (ismpl || istmpl) { + maple::MIRParser theparser(*themodule[i]); + if (!theparser.ParseMIR()) { + theparser.EmitError(themodule[i]->fileName.c_str()); + return 1; + } + } else { + BinaryMplImport binMplt(*themodule[i]); + binMplt.imported = false; + std::string modid = themodule[i]->fileName; + if (!binMplt.Import(modid, true)) { + ERR(kLncErr, "mpldbg: cannot open .mplt or .bpl file: %s", modid.c_str()); + return 1; + } + } + + themodule[i]->dbgInfo->BuildDebugInfo(); + + // output the file + if (!useBinary) { + themodule[i]->OutputAsciiMpl(".dbg", (ismpl || isbpl) ? ".mpl" : ".tmpl", &dumpFuncSet, true, false); + } else { + BinaryMplt binMplt(*themodule[i]); + std::string modid = themodule[i]->fileName; + binMplt.GetBinExport().not2mplt = ismpl || isbpl; + std::string filestem = modid.substr(0, lastdot); + binMplt.Export(filestem + ((ismpl || isbpl) ? ".dbg.bpl" : ".dbg.mplt"), &dumpFuncSet); + } + i++; + } + return 0; +} diff --git a/mapleall/maple_ir/src/parser.cpp b/mapleall/maple_ir/src/parser.cpp index 6919efa..6fe5442 100644 --- a/mapleall/maple_ir/src/parser.cpp +++ b/mapleall/maple_ir/src/parser.cpp @@ -22,6 +22,7 @@ #include "name_mangler.h" #include "opcode_info.h" #include "mir_pragma.h" +#include "debug_info.h" #include "bin_mplt.h" #include "option.h" #include "clone.h" @@ -142,6 +143,8 @@ void MIRParser::Error(const char *str) { message.append(": "); message.append(lexer.GetTokenString()); message.append("\n"); + + mod.dbgInfo->SetErrPos(lexer.GetLineNum(), lexer.GetCurIdx()); } const std::string &MIRParser::GetError() { @@ -844,6 +847,9 @@ bool MIRParser::ParseStructType(TyIdx &styIdx) { return false; } MIRStructType structType(tkind); + if (mod.srcLang == kSrcLangCPlusPlus) { + structType.isCPlusPlus = true; + } if (!ParseFields(structType)) { return false; } @@ -1488,6 +1494,8 @@ bool MIRParser::ParseTypeDef() { TyIdx prevTyidx; MIRStructType *prevStype = nullptr; TyIdx tyIdx(0); + // dbginfo class/interface init + DBGDie *die = nullptr; if (tk == TK_gname) { if (isLocal) { Error("A local type must use local type name "); @@ -1587,6 +1595,7 @@ bool MIRParser::ParseTypeDef() { } } } + // dbginfo class/interface build // setup eh root type MIRType *ehtype = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx); if (mod.throwableTyidx == 0 && (ehtype->typeKind == kTypeClass || ehtype->typeKind == kTypeClassIncomplete)) { @@ -1596,6 +1605,7 @@ bool MIRParser::ParseTypeDef() { } } } + // dbginfo struct/union build return true; } @@ -1698,6 +1708,7 @@ bool MIRParser::ParseDeclareReg(MIRSymbol *st, MIRFunction *curfunc) { mod.CurFunction()->funcAttrs.SetAttr(FUNCATTR_generic); } + // add dbginfo return true; } @@ -3048,6 +3059,7 @@ void MIRParser::EmitError(const std::string &fileName) { if (!strlen(GetError().c_str())) { return; } + mod.dbgInfo->compilemsg_->EmitMsg(); ERR(kLncErr, "%s \n%s", fileName.c_str(), GetError().c_str()); } diff --git a/mapleall/maple_me/src/me_function.cpp b/mapleall/maple_me/src/me_function.cpp index 406d5cf..9bb6672 100644 --- a/mapleall/maple_me/src/me_function.cpp +++ b/mapleall/maple_me/src/me_function.cpp @@ -157,7 +157,12 @@ BaseNode *CreateDummyReturnValue(MIRBuilder *mirBuilder, MIRType *retty) { uint64 constzero = 0; return mirBuilder->CreateFloat128Const(&constzero); } - default: CHECK_FATAL(false, "CreateDummyReturnValue: NYI for non-scalar return type"); + default: { // create a dummy local var with the return type + static uint32 tempCount = 0; + std::string tempstr = string("__DummyRetTemp.").append(to_string(++tempCount)); + MIRSymbol *st = mirBuilder->CreateLocalDecl(tempstr.c_str(), retty); + return mirBuilder->CreateExprDread(retty, 0, st); + } } return nullptr; } diff --git a/mapleall/maple_me/src/me_phase_manager.cpp b/mapleall/maple_me/src/me_phase_manager.cpp index f37b105..e92288e 100644 --- a/mapleall/maple_me/src/me_phase_manager.cpp +++ b/mapleall/maple_me/src/me_phase_manager.cpp @@ -164,7 +164,7 @@ void MeFuncPhaseManager::AddPhases(const std::unordered_set &skipPh addPhase("may2dassign"); addPhase("condbasednpc"); } - if (o2) { + if (o2 && JAVALANG) { addPhase("cfgopt"); } if (o2) { diff --git a/mapleall/mpl2mpl/BUILD.gn b/mapleall/mpl2mpl/BUILD.gn index 4e5994d..75aa361 100644 --- a/mapleall/mpl2mpl/BUILD.gn +++ b/mapleall/mpl2mpl/BUILD.gn @@ -23,12 +23,9 @@ include_directories = [ "${MAPLEALL_ROOT}/maple_ir/include", "${MAPLEALL_ROOT}/maple_ipa/include", "${MAPLEALL_ROOT}/maple_me/include", - "${MAPLEALL_ROOT}/maple_loo/include", "${MAPLEALL_ROOT}/mempool/include", - "${MAPLEALL_ROOT}/maplevm/include", "${MAPLEALL_ROOT}/maple_phase/include", "${MAPLEALL_ROOT}/maple_util/include", - "${MAPLEALL_ROOT}/mapleradar/include", "${HUAWEI_SECURE_C_ROOT}/include", ] diff --git a/tools/setup_tools.sh b/tools/setup_tools.sh index e51adde..34068c4 100755 --- a/tools/setup_tools.sh +++ b/tools/setup_tools.sh @@ -39,8 +39,21 @@ if [ ! -f ./gn/gn ]; then echo Downloaded gn. fi -if [ ! -f ./aarch64/bin/whirl2mpl ]; then +if [ ! -f ./open64_prebuilt/README.md ]; then git clone https://gitee.com/open64ark/open64_prebuilt.git - tar zxf open64_prebuilt/x86/open64ark-aarch64.tar.gz +fi +if [ ! -f ./open64_prebuilt/x86/riscv64/bin/clangfe ]; then + cd ./open64_prebuilt/x86 + git pull + tar zxf open64ark-aarch64.tar.gz + tar zxf open64ark-riscv.tar.gz + mv riscv riscv64 + cd ../.. echo Downloaded open64_prebuilt. fi + +if [ ! -f ./dwarf/include/dwarf2.h ]; then + git clone https://gitee.com/hu-_-wen/dwarf_files.git dwarf + echo Downloaded dwarf header files. +fi + -- Gitee