diff --git a/.gitignore b/.gitignore
index 951d953..0182915 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,14 @@ CMakeScripts
cmake_install.cmake
install_manifest.txt
CTestTestfile.cmake
+build
+buildmir
+omrjit
+buildllvm
+.vscode
+.idea
+cmake-build-debug
+cmake-build-release
+buildnojit
+nojit
+nojita
diff --git a/.travis.yml b/.travis.yml
index 341281e..543d229 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -14,7 +14,7 @@ addons:
- gcc
- ccache
install:
- - curl http://releases.llvm.org/6.0.1/clang+llvm-6.0.1-x86_64-linux-gnu-ubuntu-16.04.tar.xz | tar -xJf -
+ - curl https://releases.llvm.org/6.0.1/clang+llvm-6.0.1-x86_64-linux-gnu-ubuntu-16.04.tar.xz | tar -xJf -
script:
- mkdir $TRAVIS_BUILD_DIR/build
- cd $TRAVIS_BUILD_DIR/build && cmake -DCMAKE_BUILD_TYPE=Debug -DLLVM_DIR=$TRAVIS_BUILD_DIR/clang+llvm-6.0.1-x86_64-linux-gnu-ubuntu-16.04/lib/cmake/llvm -G "Unix Makefiles" -DLLVM_JIT=ON ..
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8abfbfd..da66e92 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -108,6 +108,21 @@ if (COMPUTED_GOTO AND NOT MSVC)
endif ()
endif ()
+include(CheckCCompilerFlag)
+check_c_compiler_flag("-march=native" COMPILER_OPT_ARCH_NATIVE_SUPPORTED)
+if (COMPILER_OPT_ARCH_NATIVE_SUPPORTED AND NOT CMAKE_C_FLAGS MATCHES "-march=")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native")
+endif()
+check_c_compiler_flag("-fno-common" COMPILER_OPT_NO_COMMON_SUPPORTED)
+if (COMPILER_OPT_NO_COMMON_SUPPORTED AND NOT CMAKE_C_FLAGS MATCHES "-fno-common")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-common")
+endif()
+check_c_compiler_flag("-fno-stack-protector" COMPILER_OPT_NO_STACK_PROTECTOR_SUPPORTED)
+if (COMPILER_OPT_NO_STACK_PROTECTOR_SUPPORTED AND NOT CMAKE_C_FLAGS MATCHES "-fno-stack-protector")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-stack-protector")
+endif()
+
+
set(EMBEDDED_DMRC ON)
if (LLVM_JIT)
find_package(LLVM REQUIRED CONFIG)
diff --git a/README.rst b/README.rst
index 72325a6..009ee93 100644
--- a/README.rst
+++ b/README.rst
@@ -5,7 +5,7 @@ Ravi Programming Language
:target: https://travis-ci.org/dibyendumajumdar/ravi
Ravi is a derivative/dialect of `Lua 5.3 `_ with limited optional static typing and
-features `LLVM `_ and `Eclipse OMR `_
+features `MIR `_, `LLVM `_ and `Eclipse OMR `_
powered JIT compilers. The name Ravi comes from the Sanskrit word for the Sun.
Interestingly a precursor to Lua was `Sol `_ which had support for
static types; Sol means the Sun in Portugese.
@@ -33,10 +33,9 @@ Features
* Optional static typing - for details `see the reference manual `_.
* Type specific bytecodes to improve performance
* Compatibility with Lua 5.3 (see Compatibility section below)
+* New! JIT backend `MIR `_; only Linux and x86-64 supported for now.
* `LLVM `_ powered JIT compiler
* `Eclipse OMR `_ powered JIT compiler
-* New (wip) small JIT backend based on `MIR `_; only Linux and x86-64 supported.
-* Built-in C pre-processor, parser and JIT compiler
* A `distribution with batteries `_.
Documentation
@@ -102,7 +101,7 @@ History
- New JIT backend `MIR `_.
* 2020 (Plan)
- - New optimizing byte code generator based on new parser / type checker
+ - `New optimizing byte code generator based on new parser / type checker `_
- Ravi 1.0 release
License
diff --git a/include/lfunc.h b/include/lfunc.h
index 7d42b79..8910e5c 100644
--- a/include/lfunc.h
+++ b/include/lfunc.h
@@ -35,8 +35,12 @@
*/
struct UpVal {
TValue *v; /* points to stack or to its own value */
+#ifdef RAVI_DEFER_STATEMENT
unsigned int refcount; /* reference counter */
unsigned int flags; /* Used to mark deferred values */
+#else
+ lu_mem refcount; /* reference counter */
+#endif
union {
struct { /* (when open) */
UpVal *next; /* linked list */
@@ -54,7 +58,11 @@ LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nelems);
LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nelems);
LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
+#ifdef RAVI_DEFER_STATEMENT
LUAI_FUNC int luaF_close (lua_State *L, StkId level, int status);
+#else
+LUAI_FUNC void luaF_close (lua_State *L, StkId level);
+#endif
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
/* The additional type argument is a Ravi extension */
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
diff --git a/include/llex.h b/include/llex.h
index 4dc619f..6b66fa9 100644
--- a/include/llex.h
+++ b/include/llex.h
@@ -27,7 +27,11 @@ enum RESERVED {
/* terminal symbols denoted by reserved words */
TK_AND = FIRST_RESERVED, TK_BREAK,
TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION,
+#ifdef RAVI_DEFER_STATEMENT
TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_DEFER, TK_NIL, TK_NOT, TK_OR, TK_REPEAT,
+#else
+ TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT,
+#endif
TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE,
/* other terminal symbols */
TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE,
diff --git a/include/lopcodes.h b/include/lopcodes.h
index 3bc624f..e5381eb 100644
--- a/include/lopcodes.h
+++ b/include/lopcodes.h
@@ -280,13 +280,16 @@ OP_RAVI_GETFIELD, /* A B C R(A) := R(B)[RK(C)], string key */
OP_RAVI_SELF_SK, /* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)], string key */
OP_RAVI_SETFIELD, /* A B C R(A)[RK(B)] := RK(C), string key */
OP_RAVI_GETTABUP_SK, /* A B C R(A) := UpValue[B][RK(C)], string key */
-
+#ifdef RAVI_DEFER_STATEMENT
OP_RAVI_DEFER, /* A mark variable A "deferred" */
-
+#endif
} OpCode;
-
+#ifdef RAVI_DEFER_STATEMENT
#define NUM_OPCODES (cast(int, OP_RAVI_DEFER) + 1)
+#else
+#define NUM_OPCODES (cast(int, OP_RAVI_GETTABUP_SK) + 1)
+#endif
/*===========================================================================
Notes:
diff --git a/include/luaconf.h b/include/luaconf.h
index c73e1cb..5dd6d23 100644
--- a/include/luaconf.h
+++ b/include/luaconf.h
@@ -834,6 +834,8 @@
/* If following is defined as true then LLVM instructions emitted for arithmetic ops
priority floating point ops, else default is to prioritise integer ops */
#define RAVI_USE_LLVM_ARITH_FLOATPRIORITY 1
+/* Enables the 'defer' statement - RAVI extension */
+#define RAVI_DEFER_STATEMENT
#endif
diff --git a/include/lvm.h b/include/lvm.h
index 924db5d..2d378b0 100644
--- a/include/lvm.h
+++ b/include/lvm.h
@@ -161,7 +161,9 @@ LUAI_FUNC void raviV_gettable_i(lua_State *L, const TValue *t, TValue *key, StkI
LUAI_FUNC void raviV_settable_i(lua_State *L, const TValue *t, TValue *key, StkId val);
LUAI_FUNC void raviV_op_totype(lua_State *L, TValue *ra, TValue *rb);
LUAI_FUNC int raviV_check_usertype(lua_State *L, TString *name, const TValue *o);
+#ifdef RAVI_DEFER_STATEMENT
LUAI_FUNC void raviV_op_defer(lua_State *L, TValue *ra);
+#endif
LUAI_FUNC void raviV_debug_trace(lua_State *L, int opCode, int pc);
#endif
diff --git a/include/ravi_llvmcodegen.h b/include/ravi_llvmcodegen.h
index 7d4c7fe..c49c569 100644
--- a/include/ravi_llvmcodegen.h
+++ b/include/ravi_llvmcodegen.h
@@ -288,7 +288,9 @@ struct LuaLLVMTypes {
llvm::FunctionType *raviV_gettable_iT;
llvm::FunctionType *raviV_settable_iT;
llvm::FunctionType *raviV_op_totypeT;
+#ifdef RAVI_DEFER_STATEMENT
llvm::FunctionType *raviV_op_deferT;
+#endif
llvm::FunctionType *raviH_set_intT;
llvm::FunctionType *raviH_set_floatT;
@@ -830,7 +832,9 @@ struct RaviFunctionDef {
llvm::Function *raviV_gettable_iF;
llvm::Function *raviV_settable_iF;
llvm::Function *raviV_op_totypeF;
+#ifdef RAVI_DEFER_STATEMENT
llvm::Function *raviV_op_deferF;
+#endif
// array setters
llvm::Function *raviH_set_intF;
@@ -1373,7 +1377,9 @@ class RaviCodeGenerator {
void emit_BNOT(RaviFunctionDef *def, int A, int B, int pc);
+#ifdef RAVI_DEFER_STATEMENT
void emit_DEFER(RaviFunctionDef *def, int A, int pc);
+#endif
void emit_bitwise_shiftl(RaviFunctionDef *def, llvm::Value *ra, int B, lua_Integer y);
diff --git a/mir/CMakeLists.txt b/mir/CMakeLists.txt
index e3790a5..3c48e0b 100644
--- a/mir/CMakeLists.txt
+++ b/mir/CMakeLists.txt
@@ -6,7 +6,11 @@ message(STATUS "OS type is ${CMAKE_SYSTEM_NAME}")
message(STATUS "System processor is ${CMAKE_HOST_SYSTEM_PROCESSOR}")
message(STATUS "Build type is ${CMAKE_BUILD_TYPE}")
-set(TARGET x86_64)
+if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)")
+ set(TARGET x86_64)
+else()
+ message(FATAL "Unsupported platform")
+endif()
set(MIR_HEADERS
mir.h
diff --git a/mir/MIR.md b/mir/MIR.md
new file mode 100644
index 0000000..dc9d551
--- /dev/null
+++ b/mir/MIR.md
@@ -0,0 +1,585 @@
+# Medium Intermediate Representation (file mir.h)
+ * This document describes MIR itself, API for its creation, and MIR textual representation
+ * MIR textual representation is assembler like. Each directive or insn should be put on a separate line
+ * In MIR textual syntax we use
+ * `[]` for optional construction
+ * `{}` for repeating zero or more times
+ * `<>` for some informal construction description or construction already described or will be described
+
+## MIR context
+ * MIR API code has an implicit state called by MIR context
+ * MIR context is represented by data of `MIR_context_t`
+ * MIR context is created by function `MIR_context_t MIR_init (void)`
+ * Every MIR API function (except for `MIR_init`) requires MIR context passed through the first argument of type `MIR_context_t`
+ * You can use MIR functions in different threads without any synchronization
+ if they work with different contexts in each thread
+
+## MIR program
+ * MIR program consists of MIR **modules**
+ * To start work with MIR program, you should first call API function `MIR_init`
+ * API function `MIR_finish (MIR_context_t ctx)` should be called last. It frees all internal data used to work with MIR program and all IR (insns, functions, items, and modules) created in this context
+ * API function `MIR_output (MIR_context_t ctx, FILE *f)` outputs MIR textual representation of the program into given file
+ * API function `MIR_scan_string (MIR_context_t ctx, const char *str)` reads textual MIR representation given by a string
+ * API functions `MIR_write (MIR_context_t ctx, FILE *f)` and
+ `MIR_read (MIR_context_t ctx, FILE *f)` outputs and reads
+ **binary MIR representation** to/from given file. There are also
+ functions `MIR_write_with_func (MIR_context_t ctx, const int
+ (*writer_func) (MIR_context_t, uint8_t))` and `MIR_read_with_func
+ (MIR_context_t ctx, const int (*reader_func) (MIR_context_t))` to
+ output and read **binary MIR representation** through a function
+ given as an argument. The reader function should return EOF as
+ the end of the binary MIR representation, the writer function
+ should be return the number of successfully output bytes
+ * Binary MIR representation much more compact and faster to read than textual one
+
+## MIR data type
+ * MIR program works with the following **data types**:
+ * `MIR_T_I8` and `MIR_T_U8` -- signed and unsigned 8-bit integer values
+ * `MIR_T_I16` and `MIR_T_U16` -- signed and unsigned 16-bit integer values
+ * `MIR_T_I32` and `MIR_T_U32` -- signed and unsigned 32-bit integer values
+ * `MIR_T_I64` and `MIR_T_U64` -- signed and unsigned 64-bit integer values
+ * ??? signed and unsigned 64-bit integer types in most cases
+ are interchangeable as insns themselves decide how to treat
+ their value
+ * `MIR_T_F` and `MIR_T_D` -- IEEE single and double precision floating point values
+ * `MIR_T_LD` - long double values. It is machine-dependent and can be IEEE double, x86 80-bit FP,
+ or IEEE quad precision FP values
+ * `MIR_T_P` -- pointer values. Depending on the target pointer value is actually 32-bit or 64-bit integer value
+ * MIR textual representation of the types are correspondingly `i8`,
+ `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `f`, `d`, `p`,
+ and `v`
+ * Function `int MIR_int_type_p (MIR_type_t t)` returns TRUE if given type is an integer one (it includes pointer type too)
+ * Function `int MIR_fp_type_p (MIR_type_t t)` returns TRUE if given type is a floating point type
+
+## MIR module
+ * Module is a high level entity of MIR program
+ * Module is created through API function `MIR_module_t MIR_new_module (const char *name)`
+ * Module creation is finished by calling API function `MIR_finish_module`
+ * You can create only one module at any given time
+ * List of all created modules can be gotten by function `DLIST (MIR_module_t) *MIR_get_module_list (MIR_context_t ctx)`
+ * MIR module consists of **items**. There are following **item types** (and function for their creation):
+ * **Function**: `MIR_func_item`
+ * **Import**: `MIR_import_item` (`MIR_item_t MIR_new_import (MIR_context_t ctx, const char *name)`)
+ * **Export**: `MIR_export_item` (`MIR_item_t MIR_new_export (MIR_context_t ctx, const char *name)`)
+ * **Forward declaration**: `MIR_forward_item` (`MIR_item_t MIR_new_forward (MIR_context_t ctx, const char *name)`)
+ * **Prototype**: `MIR_proto_item` (`MIR_new_proto_arr`, `MIR_new_proto`, `MIR_new_vararg_proto_arr`,
+ `MIR_new_vararg_proto` analogous to `MIR_new_func_arr`, `MIR_new_func`, `MIR_new_vararg_func_arr` and
+ `MIR_new_vararg_func` -- see below). The only difference is that
+ two or more prototype argument names can be the same
+ * **Data**: `MIR_data_item` with optional name
+ (`MIR_item_t MIR_new_data (MIR_context_t ctx, const char *name, MIR_type_t el_type, size_t nel, const void *els)`
+ or `MIR_item_t MIR_new_string_data (MIR_context_t ctx, const char *name, MIR_str_t str)`)
+ * **Reference data**: `MIR_ref_data_item` with optional name
+ (`MIR_item_t MIR_new_ref_data (MIR_context_t ctx, const char *name, MIR_item_t item, int64_t disp)`
+ * The address of the item after linking plus `disp` is used to initialize the data
+ * **Expression Data**: `MIR_expr_data_item` with optional name
+ (`MIR_item_t MIR_new_expr_data (MIR_context_t ctx, const char *name, MIR_item_func_item)`)
+ * Not all MIR functions can be used for expression data. The expression function should have
+ only one result, have no arguments, not use any call or any instruction with memory
+ * The expression function is called during linking and its result is used to initialize the data
+ * **Memory segment**: `MIR_bss_item` with optional name (`MIR_item_t MIR_new_bss (MIR_context_t ctx, const char *name, size_t len)`)
+ * Names of MIR functions, imports, and prototypes should be unique in a module
+ * API functions `MIR_output_item (MIR_context_t ctx, FILE *f, MIR_item_t item)`
+ and `MIR_output_module (MIR_context_t ctx, FILE *f, MIR_module_t module)` output item or module
+ textual representation into given file
+ * MIR text module syntax looks the following:
+```
+ : module
+ {}
+ endmodule
+```
+
+## MIR function
+ * Function is an module item
+ * Function has a **frame**, a stack memory reserved for each function invocation
+ * Function has **local variables** (sometimes called **registers**), a part of which are **arguments**
+ * A variable should have an unique name in the function
+ * A variable is represented by a structure of type `MIR_var_t`
+ * The structure contains variable name and its type
+ * MIR function with its arguments is created through API function `MIR_item_t MIR_new_func (MIR_context_t ctx, const
+ char *name, size_t nres, MIR_type_t *res_types, size_t nargs, ...)`
+ or function `MIR_item_t MIR_new_func_arr (MIR_context_t ctx, const char *name, size_t nres, MIR_type_t *res_types, size_t nargs, MIR_var_t *arg_vars)`
+ * Argument variables can be any type
+ * This type only denotes how the argument value is passed
+ * Any integer type argument variable has actually type `MIR_T_I64`
+ * MIR functions with variable number of arguments are created through API functions
+ `MIR_item_t MIR_new_vararg_func (MIR_context_t ctx, const char *name, size_t nres, MIR_type_t *res_types, size_t nargs, ...)`
+ or function `MIR_item_t MIR_new_vararg_func_arr (MIR_context_t ctx, const char *name, size_t nres, MIR_type_t *res_types, size_t nargs, MIR_var_t *arg_vars)`
+ * `nargs` and `arg_vars` define only fixed arguments
+ * MIR functions can have more one result but possible number of results
+ and combination of their types are machine-defined. For example, for x86-64
+ the function can have upto six results and return two integer
+ values, two float or double values, and two long double values
+ in any combination
+ * MIR function creation is finished by calling API function `MIR_finish_func (MIR_context_t ctx)`
+ * You can create only one MIR function at any given time
+ * MIR text function syntax looks the following (arg-var always has a name besides type):
+```
+ : func {, } [ arg-var {, } [, ...]]
+ {}
+ endfun
+```
+ * Non-argument function variables are created through API function
+ `MIR_reg_t MIR_new_func_reg (MIR_context_t ctx, MIR_func_t func, MIR_type_t type, const char *name)`
+ * The only permitted integer type for the variable is `MIR_T_I64` (or MIR_T_U64???)
+ * Names in form `t` can not be used as they are fixed for internal purposes
+ * You can create function variables even after finishing the
+ function creation. This can be used to modify function insns,
+ e.g. for optimizations
+ * Non-argument variable declaration syntax in MIR textual representation looks the following:
+```
+ local [ : {, :} ]
+```
+ * In MIR textual representation variable should be defined through `local` before its use
+
+## MIR insn operands
+ * MIR insns work with operands
+ * There are following operands:
+ * Signed or unsigned **64-bit integer value operands** created through API functions
+ `MIR_op_t MIR_new_int_op (MIR_context_t ctx, int64_t v)` and `MIR_op_t MIR_new_uint_op (MIR_context_t ctx, uint64_t v)`
+ * In MIR text they are represented the same way as C integer numbers (e.g. octal, decimal, hexadecimal ones)
+ * **Float, double or long double value operands** created through API functions `MIR_op_t MIR_new_float_op (MIR_context_t ctx, float v)`,
+ `MIR_op_t MIR_new_double_op (MIR_context_t ctx, double v)`, and `MIR_op_t MIR_new_ldouble_op (MIR_context_t ctx, long double v)`
+ * In MIR text they are represented the same way as C floating point numbers
+ * **String operands** created through API functions `MIR_op_t MIR_new_str_op (MIR_context_t ctx, MIR_str_t str)`
+ * In MIR text they are represented by `typedef struct MIR_str {size_t len; const char *s;} MIR_str_t`
+ * Strings for each operand are put into memory (which can be modified) and the memory address actually presents the string
+ * **Label operand** created through API function `MIR_op_t MIR_new_label_op (MIR_context_t ctx, MIR_label_t label)`
+ * Here `label` is a special insn created by API function `MIR_insn_t MIR_new_label (MIR_context_t ctx)`
+ * In MIR text, they are represented by unique label name
+ * **Reference operands** created through API function `MIR_op_t MIR_new_ref_op (MIR_context_t ctx, MIR_item_t item)`
+ * In MIR text, they are represented by the corresponding item name
+ * **Register (variable) operands** created through API function `MIR_op_t MIR_new_reg_op (MIR_context_t ctx, MIR_reg_t reg)`
+ * In MIR text they are represented by the corresponding variable name
+ * Value of type `MIR_reg_t` is returned by function `MIR_new_func_reg`
+ or can be gotten by function `MIR_reg_t MIR_reg (MIR_context_t ctx, const char *reg_name, MIR_func_t func)`, e.g. for argument-variables
+ * **Memory operands** consists of type, displacement, base
+ register, index register and index scale. Memory operand is
+ created through API function `MIR_op_t MIR_new_mem_op (MIR_context_t ctx, MIR_type_t type,
+ MIR_disp_t disp, MIR_reg_t base, MIR_reg_t index, MIR_scale_t
+ scale)`
+ * The arguments define address of memory as `disp + base + index * scale`
+ * Integer type input memory is transformed to 64-bit integer value with sign or zero extension
+ depending on signedness of the type
+ * result 64-bit integer value is truncated to integer memory type
+ * Memory operand has the following syntax in MIR text (absent displacement means zero one,
+ absent scale means one, scale should be 1, 2, 4, or 8):
+
+```
+ :
+ : [] ( [, [, ]])
+```
+ * API function `MIR_output_op (MIR_context_t ctx, FILE *f, MIR_op_t op, MIR_func_t func)` outputs the operand
+ textual representation into given file
+
+
+## MIR insns
+ * All MIR insns (but call or ret one) expects fixed number of operands
+ * Most MIR insns are 3-operand insns: two inputs and one output
+ * In majority cases **the first insn operand** describes where the insn result (if any) will be placed
+ * Only register or memory operand can be insn output (result) operand
+ * MIR insn can be created through API functions `MIR_insn_t MIR_new_insn (MIR_context_t ctx, MIR_insn_code_t code, ...)`
+ and `MIR_insn_t MIR_new_insn_arr (MIR_context_t ctx, MIR_insn_code_t code, size_t nops, MIR_op_t *ops)`
+ * Number of operands and their types should be what is expected by the insn being created
+ * You can not use `MIR_new_insn` for the creation of call and ret insns as these insns have a variable number of operands.
+ To create such insns you should use `MIR_new_insn_arr` or special functions
+ `MIR_insn_t MIR_new_call_insn (MIR_context_t ctx, size_t nops, ...)` and `MIR_insn_t MIR_new_ret_insn (MIR_context_t ctx, size_t nops, ...)`
+ * You can get insn name and number of insn operands through API functions
+ `const char *MIR_insn_name (MIR_context_t ctx, MIR_insn_code_t code)` and `size_t MIR_insn_nops (MIR_context_t ctx, MIR_insn_t insn)`
+ * You can add a created insn at the beginning or end of function insn list through API functions
+ `MIR_prepend_insn (MIR_context_t ctx, MIR_item_t func, MIR_insn_t insn)` and `MIR_append_insn (MIR_context_t ctx, MIR_item_t func, MIR_insn_t insn)`
+ * You can insert a created insn in the middle of function insn list through API functions
+ `MIR_insert_insn_after (MIR_context_t ctx, MIR_item_t func, MIR_insn_t after, MIR_insn_t insn)` and
+ `MIR_insert_insn_before (MIR_context_t ctx, MIR_item_t func, MIR_insn_t before, MIR_insn_t insn)`
+ * The insn `after` and `before` should be already in the list
+ * You can remove insn from the function list through API function `MIR_remove_insn (MIR_context_t ctx, MIR_item_t func, MIR_insn_t insn)`
+ * The insn should be not inserted in the list if it is already there
+ * The insn should be not removed form the list if it is not there
+ * API function `MIR_output_insn (MIR_context_t ctx, FILE *f, MIR_insn_t insn, MIR_func_t func, int newline_p)` outputs the insn
+ textual representation into given file with a newline at the end depending on value of `newline_p`
+ * Insn has the following syntax in MIR text:
+```
+ {:} [ {, }]
+```
+ * More one insn can be put on the same line by separating the insns by `;`
+
+### MIR move insns
+ * There are following MIR move insns:
+
+ | Insn Code | Nops | Description |
+ |-------------------------|-----:|--------------------------------------------------------|
+ | `MIR_MOV` | 2 | move 64-bit integer values |
+ | `MIR_FMOV` | 2 | move **single precision** floating point values |
+ | `MIR_DMOV` | 2 | move **double precision** floating point values |
+ | `MIR_LDMOV` | 2 | move **long double** floating point values |
+
+### MIR integer insns
+ * If insn has suffix `S` in insn name, the insn works with lower 32-bit part of 64-bit integer value
+ * The higher part of 32-bit insn result is undefined
+ * If insn has prefix `U` in insn name, the insn treats integer as unsigned integers
+ * Some insns has no unsigned variant as MIR is oriented to CPUs with two complement integer arithmetic
+ (the huge majority of all CPUs)
+
+ | Insn Code | Nops | Description |
+ |-------------------------|-----:|--------------------------------------------------------|
+ | `MIR_EXT8` | 2 | **sign** extension of lower **8 bit** input part |
+ | `MIR_UEXT8` | 2 | **zero** extension of lower **8 bit** input part |
+ | `MIR_EXT16` | 2 | **sign** extension of lower **16 bit** input part |
+ | `MIR_UEXT16` | 2 | **zero** extension of lower **16 bit** input part |
+ | `MIR_EXT32` | 2 | **sign** extension of lower **32 bit** input part |
+ | `MIR_UEXT32` | 2 | **zero** extension of lower **32 bit** input part |
+ | | | |
+ | `MIR_NEG` | 2 | changing sign of **64-bit* integer value |
+ | `MIR_NEGS` | 2 | changing sign of **32-bit* integer value |
+ | | | |
+ | `MIR_ADD`, `MIR_SUB` | 3 | **64-bit** integer addition and subtraction |
+ | `MIR_ADDS`, `MIR_SUBS` | 3 | **32-bit** integer addition and subtraction |
+ | `MIR_MUL`, `MIR_DIV` | 3 | **64-bit signed** multiplication and divison |
+ | `MIR_UMUL`, `MIR_UDIV` | 3 | **64-bit unsigned** integer multiplication and divison |
+ | `MIR_MULS`, `MIR_DIVS` | 3 | **32-bit signed** multiplication and divison |
+ | `MIR_UMULS`, `MIR_UDIVS`| 3 | **32-bit unsigned** integer multiplication and divison |
+ | `MIR_MOD` | 3 | **64-bit signed** modulo operation |
+ | `MIR_UMOD` | 3 | **64-bit unsigned** integer modulo operation |
+ | `MIR_MODS` | 3 | **32-bit signed** modulo operation |
+ | `MIR_UMODS` | 3 | **32-bit unsigned** integer modulo operation |
+ | | | |
+ | `MIR_AND`, `MIR_OR` | 3 | **64-bit** integer bitwise AND and OR |
+ | `MIR_ANDS`, `MIR_ORS` | 3 | **32-bit** integer bitwise AND and OR |
+ | `MIR_XOR` | 3 | **64-bit** integer bitwise XOR |
+ | `MIR_XORS` | 3 | **32-bit** integer bitwise XOR |
+ | | | |
+ | `MIR_LSH` | 3 | **64-bit** integer left shift |
+ | `MIR_LSHS` | 3 | **32-bit** integer left shift |
+ | `MIR_RSH` | 3 | **64-bit** integer right shift with **sign** extension |
+ | `MIR_RSHS` | 3 | **32-bit** integer right shift with **sign** extension |
+ | `MIR_URSH` | 3 | **64-bit** integer right shift with **zero** extension |
+ | `MIR_URSHS` | 3 | **32-bit** integer right shift with **zero** extension |
+ | | | |
+ | `MIR_EQ`, `MIR_NE` | 3 | equality/inequality of **64-bit** integers |
+ | `MIR_EQS`, `MIR_NES` | 3 | equality/inequality of **32-bit** integers |
+ | `MIR_LT`, `MIR_LE` | 3 | **64-bit signed** less than/less than or equal |
+ | `MIR_ULT`, `MIR_ULE` | 3 | **64-bit unsigned** less than/less than or equal |
+ | `MIR_LTS`, `MIR_LES` | 3 | **32-bit signed** less than/less than or equal |
+ | `MIR_ULTS`, `MIR_ULES` | 3 | **32-bit unsigned** less than/less than or equal |
+ | `MIR_GT`, `MIR_GE` | 3 | **64-bit signed** greater than/greater than or equal |
+ | `MIR_UGT`, `MIR_UGE` | 3 | **64-bit unsigned** greater than/greater than or equal |
+ | `MIR_GTS`, `MIR_GES` | 3 | **32-bit signed** greater than/greater than or equal |
+ | `MIR_UGTS`, `MIR_UGES` | 3 | **32-bit unsigned** greater than/greater than or equal |
+
+### MIR floating point insns
+ * If insn has prefix `F` in insn name, the insn is single precision float point insn. Its operands should have `MIR_T_F` type
+ * If insn has prefix `D` in insn name, the insn is double precision float point insn. Its operands should have `MIR_T_D` type
+ * Otherwise, insn has prefix `LD` in insn name and the insn is a long double insn.
+ Its operands should have `MIR_T_LD` type.
+ * The result of comparison insn is a 64-bit integer value, so the result operand should be of integer type
+
+ | Insn Code | Nops | Description |
+ |--------------------------------------|-----:|-----------------------------------------------------------------|
+ | `MIR_F2I`, `MIR_D2I`, `MIR_LD2I` | 2 | transforming floating point value into 64-bit integer |
+ | `MIR_F2D` | 2 | transforming single to double precision FP value |
+ | `MIR_F2LD` | 2 | transforming single precision to long double FP value |
+ | `MIR_D2F` | 2 | transforming double to single precision FP value |
+ | `MIR_D2LD` | 2 | transforming double precision to long double FP value |
+ | `MIR_LD2F` | 2 | transforming long double to single precision FP value |
+ | `MIR_LD2D` | 2 | transforming long double to double precision FP value |
+ | `MIR_I2F`, `MIR_I2D`, `MIR_I2LD` | 2 | transforming 64-bit integer into a floating point value |
+ | `MIR_UI2F`, `MIR_UI2D`, `MIR_UI2LD` | 2 | transforming unsigned 64-bit integer into a floating point value|
+ | `MIR_FNEG`, `MIR_DNEG`, `MIR_LDNEG` | 2 | changing sign of floating point value |
+ | `MIR_FADD`, `MIR_FSUB` | 3 | **single** precision addition and subtraction |
+ | `MIR_DADD`, `MIR_DSUB` | 3 | **double** precision addition and subtraction |
+ | `MIR_LDADD`, `MIR_LDSUB` | 3 | **long double** addition and subtraction |
+ | `MIR_FMUL`, `MIR_FDIV` | 3 | **single** precision multiplication and divison |
+ | `MIR_DMUL`, `MIR_DDIV` | 3 | **double** precision multiplication and divison |
+ | `MIR_LDMUL`, `MIR_LDDIV` | 3 | **long double** multiplication and divison |
+ | `MIR_FEQ`, `MIR_FNE` | 3 | equality/inequality of **single** precision values |
+ | `MIR_DEQ`, `MIR_DNE` | 3 | equality/inequality of **double** precision values |
+ | `MIR_LDEQ`, `MIR_LDNE` | 3 | equality/inequality of **long double** values |
+ | `MIR_FLT`, `MIR_FLE` | 3 | **single** precision less than/less than or equal |
+ | `MIR_DLT`, `MIR_DLE` | 3 | **double** precision less than/less than or equal |
+ | `MIR_LDLT`, `MIR_LDLE` | 3 | **long double** less than/less than or equal |
+ | `MIR_FGT`, `MIR_FGE` | 3 | **single** precision greater than/greater than or equal |
+ | `MIR_DGT`, `MIR_DGE` | 3 | **double** precision greater than/greater than or equal |
+ | `MIR_LDGT`, `MIR_LDGE` | 3 | **long double** greater than/greater than or equal |
+
+### MIR branch insns
+ * The first operand of the insn should be label
+
+ | Insn Code | Nops | Description |
+ |-------------------------|-----:|---------------------------------------------------------------|
+ | `MIR_JMP` | 1 | unconditional jump to the label |
+ | `MIR_BT` | 2 | jump to the label when 2nd **64-bit** operand is **nonzero** |
+ | `MIR_BTS` | 2 | jump to the label when 2nd **32-bit** operand is **nonzero** |
+ | `MIR_BF` | 2 | jump to the label when 2nd **64-bit** operand is **zero** |
+ | `MIR_BFS` | 2 | jump to the label when 2nd **32-bit** operand is **zero** |
+
+### MIR switch insn
+ * The first operand of `MIR_SWITCH` insn should have an integer value from 0 to `N - 1` inclusive
+ * The rest operands should be `N` labels, where `N > 0`
+ * Execution of the insn will be an jump on the label corresponding to the first operand value
+ * If the first operand value is out of the range of permitted values, the execution result is undefined
+
+### MIR integer comparison and branch insn
+ * The first operand of the insn should be label. Label will be the next executed insn if the result of comparison is non-zero
+
+ | Insn Code | Nops | Description |
+ |-------------------------|-----:|---------------------------------------------------------------|
+ | `MIR_BEQ`, `MIR_BNE` | 3 | jump on **64-bit** equality/inequality |
+ | `MIR_BEQS`, `MIR_BNES` | 3 | jump on **32-bit** equality/inequality |
+ | `MIR_BLT`, `MIR_BLE` | 3 | jump on **signed 64-bit** less than/less than or equal |
+ | `MIR_UBLT`, `MIR_UBLE` | 3 | jump on **unsigned 64-bit** less than/less than or equal |
+ | `MIR_BLTS`, `MIR_BLES` | 3 | jump on **signed 32-bit** less than/less than or equal |
+ | `MIR_UBLTS`, `MIR_UBLES`| 3 | jump on **unsigned 32-bit** less than/less than or equal |
+ | `MIR_BGT`, `MIR_BGE` | 3 | jump on **signed 64-bit** greater than/greater than or equal |
+ | `MIR_UBGT`, `MIR_UBGE` | 3 | jump on **unsigned 64-bit** greater than/greater than or equal|
+ | `MIR_BGTS`, `MIR_BGES` | 3 | jump on **signed 32-bit** greater than/greater than or equal |
+ | `MIR_UBGTS`, `MIR_UBLES`| 3 | jump on **unsigned 32-bit** greater than/greater than or equal|
+
+### MIR floating point comparison and branch insn
+ * The first operand of the insn should be label. Label will be the next executed insn if the result of comparison is non-zero
+ * See comparison semantics in the corresponding comparison insns
+
+ | Insn Code | Nops | Description |
+ |---------------------------|-----:|----------------------------------------------------------------|
+ | `MIR_FBEQ`, `MIR_FBNE` | 3 | jump on **single** precision equality/inequality |
+ | `MIR_DBEQ`, `MIR_DBNE` | 3 | jump on **double** precision equality/inequality |
+ | `MIR_LDBEQ`, `MIR_LDBNE` | 3 | jump on **long double** equality/inequality |
+ | `MIR_FBLT`, `MIR_FBLE` | 3 | jump on **single** precision less than/less than or equal |
+ | `MIR_DBLT`, `MIR_DBLE` | 3 | jump on **double** precision less than/less than or equal |
+ | `MIR_LDBLT`, `MIR_LDBLE` | 3 | jump on **long double** less than/less than or equal |
+ | `MIR_FBGT`, `MIR_FBGE` | 3 | jump on **single** precision greater than/greater than or equal|
+ | `MIR_DBGT`, `MIR_DBGE` | 3 | jump on **double** precision greater than/less/ than or equal |
+ | `MIR_LDBGT`, `MIR_LDBGE` | 3 | jump on **long double** greater than/less/ than or equal |
+
+### MIR return insn
+ * Return insn has zero or more operands
+ * Return insn operands should correspond to return types of the function
+ * 64-bit integer value is truncated to the corresponding function return type first
+ * The return values will be the function call values
+
+### MIR_CALL insn
+ * The insn has variable number of operands
+ * The first operand is a prototype reference operand
+ * The second operand is a called function address
+ * The prototype should correspond MIR function definition if function address represents a MIR function
+ * The prototype should correspond C function definition if the address is C function address
+ * If the prototype has *N* return types, the next *N* operands are
+ output operands which will contain the result values of the function
+ call
+ * The subsequent operands are arguments. Their types and number and should be the same as in the prototype
+ * Integer arguments are truncated according to integer prototype argument type
+
+### MIR_INLINE insn
+ * This insn is analogous to `MIR_CALL` but after linking this insn
+ will be changed by inlined function body if it is possible
+ * Calls of vararg functions are never inlined
+
+### MIR_ALLOCA insn
+ * Reserve memory on the stack whose size is given as the 2nd operand and assign the memory address to the 1st operand
+ * The reserved memory will be aligned according target ABI
+
+### MIR_BSTART and MIR_BEND insns
+ * MIR users can use them implement blocks with automatic
+ deallocation of memory allocated by `MIR_ALLOCA` inside the
+ blocks. But mostly these insns are used to implement call
+ inlining of functions using alloca
+ * The both insns use one operand
+ * The first insn saves the stack pointer in the operand
+ * The second insn restores stack pointer from the operand
+
+### MIR_VA_START, MIR_VA_ARG, and MIR_VA_END insns
+ * These insns are only for variable number arguments functions
+ * `MIR_VA_START` and `MIR_VA_END` have one input operand, an address
+ of va_list structure (see C stdarg.h for more details). Unlike C
+ va_start, MIR_VA_START just takes one parameter
+ * `MIR_VA_ARG` takes va_list and any memory operand and returns
+ address of the next argument in the 1st insn operand. The memory
+ operand type defines the type of the argument
+ * va_list operand can be memory with undefined type. In this case
+ address of the va_list is not in the memory but is the
+ memory address
+
+## MIR API example
+ * The following code on C creates MIR analog of C code
+ `int64_t loop (int64_t arg1) {int64_t count = 0; while (count < arg1) count++; return count;}`
+```
+ MIR_module_t m = MIR_new_module (ctx, "m");
+ MIR_item_t func = MIR_new_func (ctx, "loop", MIR_T_I64, 1, MIR_T_I64, "arg1");
+ MIR_reg_t COUNT = MIR_new_func_reg (ctx, func->u.func, MIR_T_I64, "count");
+ MIR_reg_t ARG1 = MIR_reg (ctx, "arg1", func->u.func);
+ MIR_label_t fin = MIR_new_label (ctx), cont = MIR_new_label (ctx);
+
+ MIR_append_insn (ctx, func, MIR_new_insn (ctx, MIR_MOV, MIR_new_reg_op (ctx, COUNT),
+ MIR_new_int_op (ctx, 0)));
+ MIR_append_insn (ctx, func, MIR_new_insn (ctx, MIR_BGE, MIR_new_label_op (ctx, fin),
+ MIR_new_reg_op (ctx, COUNT), MIR_new_reg_op (ctx, ARG1)));
+ MIR_append_insn (ctx, func, cont);
+ MIR_append_insn (ctx, func, MIR_new_insn (ctx, MIR_ADD, MIR_new_reg_op (ctx, COUNT),
+ MIR_new_reg_op (ctx, COUNT), MIR_new_int_op (ctx, 1)));
+ MIR_append_insn (ctx, func, MIR_new_insn (ctx, MIR_BLT, MIR_new_label_op (ctx, cont),
+ MIR_new_reg_op (ctx, COUNT), MIR_new_reg_op (ctx, ARG1)));
+ MIR_append_insn (ctx, func, fin);
+ MIR_append_insn (ctx, func, MIR_new_ret_insn (ctx, 1, MIR_new_reg_op (ctx, COUNT)));
+ MIR_finish_func (ctx);
+ MIR_finish_module (ctx);
+```
+
+## MIR text example
+
+```
+m_sieve: module
+ export sieve
+sieve: func i32, i32:N
+ local i64:iter, i64:count, i64:i, i64:k, i64:prime, i64:temp, i64:flags
+ alloca flags, 819000
+ mov iter, 0
+loop: bge fin, iter, N
+ mov count, 0; mov i, 0
+loop2: bge fin2, i, 819000
+ mov u8:(flags, i), 1; add i, i, 1
+ jmp loop2
+fin2: mov i, 0
+loop3: bge fin3, i, 819000
+ beq cont3, u8:(flags,i), 0
+ add temp, i, i; add prime, temp, 3; add k, i, prime
+loop4: bge fin4, k, 819000
+ mov u8:(flags, k), 0; add k, k, prime
+ jmp loop4
+fin4: add count, count, 1
+cont3: add i, i, 1
+ jmp loop3
+fin3: add iter, iter, 1
+ jmp loop
+fin: rets count
+ endfunc
+ endmodule
+m_ex100: module
+format: string "sieve (10) = %d\n"
+p_printf: proto p:fmt, i32:v
+p_seive: proto i32, i32:iter
+ export ex100
+ import sieve, printf
+ex100: func v
+ local i64:r
+ call p_sieve, sieve, r, 100
+ call p_printf, printf, format, r
+ endfunc
+ endmodule
+```
+
+## Other MIR API functions
+ * MIR API can find a lot of errors. They are reported through a
+ error function of type `void (*MIR_error_func_t) (MIR_context ctx, MIR_error_type_t
+ error_type, const char *message)`. The function is considered to
+ never return. To see all error types, please look at the
+ definition of error type `MIR_error_type_t` in file mir.h
+ * You can get and set up the current error function through API
+ functions `MIR_error_func_t MIR_get_error_func (MIR_context ctx)` and `MIR_set_error_func
+ (MIR_context ctx, MIR_error_func_t func)`.
+ * The default error function prints the message into stderr and call `exit (1)`
+ * MIR is pretty flexible and can describe complex insns, e.g. insns
+ whose all operands are memory. Sometimes you need a very simple
+ form of MIR representation. During load of module all its functions are simplified as much
+ as possible by adding new insns and registers resulting in a form in which:
+ * immediate, memory, reference operands can be used only in move insns
+ * memory have only base register (no displacement and index register)
+ * string and float immediate operands (if `mem_float_p`) are changed onto
+ references for new string and data items
+ * Before execution of MIR code (through interpreter or machine code generated by JIT),
+ you need to load and link it
+ * You can load MIR module through API function `MIR_load_module
+ (MIR_context ctx, MIR_module_t m)`. The function simplifies module code.
+ It also allocates the module data/bss
+ and makes visible the exported module items to other module
+ during subsequent linking. There is a guarantee that the
+ different data/bss items will be in adjacent memory if the
+ data/bss items go one after another and all the data/bss items
+ except the first one are anonymous (it means they have no name).
+ Such adjacent data/bss items are called a **section**.
+ Alignment of the section is malloc alignment. There are no any
+ memory space between data/bss in the section. If you need to
+ provide necessary alignment of a data/bss in the section you
+ should do it yourself by putting additional anonymous data/bss
+ before given data/bss if it is necessary. BSS memory is
+ initialized by zero and data memory is initialized by the
+ corresponding data. If there is already an exported item with
+ the same name, it will be not visible for linking anymore. Such
+ visibility mechanism permits usage of different versions of the
+ same function
+ * Reference data are initialized not during loading but during linking after
+ the referenced item address is known. The address is used for the data
+ initialization
+ * Expression data are also initialized not during loading but during linking after
+ all addresses are known. The expression function is evaluated by the interpreter
+ and its evaluation result is used for the data initialization. For example, if
+ you need to initialize data by item address plus offset you should use
+ an expression data
+ * MIR permits to use imported items not implemented in MIR, for
+ example to use C standard function `strcmp`. You need to inform
+ MIR about it. API function `MIR_load_external (MIR_context ctx, const char
+ *name, void *addr)` informs that imported items with given name
+ have given address (e.g. C function address or data)
+ * Imports/exports of modules loaded since the last link can be
+ linked through API function `MIR_link (MIR_context ctx, void (*set_interface) (MIR_item_t item),
+ void * (*import_resolver) (const char *))`
+ * `MIR_link` function inlines most `MIR_INLINE` calls
+ * `MIR_link` function also sets up call interface
+ * If you pass `MIR_set_interp_interface` to `MIR_link`, then
+ called functions from MIR code will be interpreted
+ * If you pass `MIR_set_gen_interface` to `MIR_link`, then
+ MIR-generator will generate machine code for all loaded MIR
+ functions and called functions from MIR code will execute the
+ machine code
+ * If you pass `MIR_set_lazy_gen_interface` to `MIR_link`, then
+ MIR-generator will generate machine code only on the first
+ function call and called functions from MIR code will execute
+ the machine code
+ * If you pass non-null `import_resolver` function, it will be
+ called for defining address for import without definition.
+ The function get the import name and return the address which
+ will be used for the import item. This function can be useful
+ for searching `dlopen` library symbols when use of
+ MIR_load_external is not convenient
+
+# MIR code execution
+ * Linked MIR code can be executed by an **interpreter** or machine code generated by **MIR generator**
+
+# MIR code interpretation
+ * The interpreter is an obligatory part of MIR API because it can be used during linking
+ * The interpreter is automatically initialized and finished with MIR API initialization and finishing
+ * The interpreter works with values represented by type `MIR_val_t` which is union
+ `union {..., int64_t i; uint64_t u; float f; double d; long double d;}`
+ * You can execute a MIR function code by API functions `void
+ MIR_interp (MIR_context ctx, MIR_item_t func_item, MIR_val_t *results, size_t nargs, ...)` and
+ `void MIR_interp_arr (MIR_context ctx, MIR_item_t func_item, MIR_val_t *results, size_t nargs,
+ MIR_val_t *vals)`
+ * The function results are returned through parameter `results`. You should pass
+ a container of enough size to return all function results.
+ * You can execute a MIR function code also through C function call
+ mechanism. First you need to setup the C function interface
+ through API function `MIR_set_interp_interface (MIR_context ctx, MIR_item_t
+ func_item)`. After that you can `func_item->addr` to call the
+ MIR function as usual C function
+ * C function interface is implemented by generation of machine
+ code specialized for MIR function. Therefore the interface
+ works only on the same targets as MIR generator
+
+# MIR generator (file mir-gen.h)
+ * Before use of MIR generator you should initialize it by API function `MIR_gen_init (MIR_context ctx)`
+ * API function `MIR_gen_finish (MIR_context ctx)` should be called last after any generator usage.
+ It frees all internal generator data
+ * API function `void *MIR_gen (MIR_context ctx, MIR_item_t func_item)` generates machine code of given MIR function
+ and returns an address to call it. You can call the code as usual C function by using this address
+ as the called function address
+ * API function `void MIR_gen_set_debug_file (MIR_context_t ctx, FILE *f)` sets up MIR generator debug file to `f`.
+ If it is not NULL a lot of debugging and optimization information will be output to the file. It is useful mostly
+ for MIR developers
+ * API function `void MIR_gen_set_optimize_level (MIR_context_t ctx, unsigned int level)` sets up optimization
+ level for MIR generator:
+ * `0` means only register allocator and machine code generator work
+ * `1` means additional code selection task. On this level MIR generator creates more compact and faster
+ code than on zero level with practically on the same speed
+ * `2` means additionally common sub-expression elimination and sparse conditional constant propagation.
+ This is a default level. This level is valuable if you generate bad input MIR code with a lot redundancy
+ and constants. The generation speed on level `1` is about 50% faster than on level `2`
+ * `3` means additionally register renaming and loop invariant code motion. The generation speed
+ on level `2` is about 50% faster than on level `3`
diff --git a/mir/c2mir/aarch64/caarch64-code.c b/mir/c2mir/aarch64/caarch64-code.c
new file mode 100644
index 0000000..dd13844
--- /dev/null
+++ b/mir/c2mir/aarch64/caarch64-code.c
@@ -0,0 +1,23 @@
+/* This file is a part of MIR project.
+ Copyright (C) 2020 Vladimir Makarov .
+*/
+
+#include "../mirc.h"
+#include "mirc-aarch64-linux.h"
+
+static const char *standard_includes[] = {mirc, aarch64_mirc};
+
+static const char *standard_include_dirs[] = {"include/mirc/", "include/mirc/aarch64/"};
+
+#define MAX_ALIGNMENT 16
+
+#define ADJUST_VAR_ALIGNMENT(c2m_ctx, align, type) \
+ aarch64_adjust_var_alignment (c2m_ctx, align, type)
+
+static int aarch64_adjust_var_alignment (c2m_ctx_t c2m_ctx, int align, struct type *type) {
+ return align;
+}
+
+static int invalid_alignment (mir_llong align) {
+ return align != 0 && align != 1 && align != 2 && align != 4 && align != 8 && align != 16;
+}
diff --git a/mir/c2mir/aarch64/caarch64.h b/mir/c2mir/aarch64/caarch64.h
new file mode 100644
index 0000000..0ca92b7
--- /dev/null
+++ b/mir/c2mir/aarch64/caarch64.h
@@ -0,0 +1,50 @@
+/* This file is a part of MIR project.
+ Copyright (C) 2020 Vladimir Makarov .
+*/
+
+#include
+
+#define MIR_CHAR_BIT 8
+
+typedef int8_t mir_schar;
+typedef int16_t mir_short;
+typedef int32_t mir_int;
+typedef int64_t mir_long;
+typedef int64_t mir_llong;
+
+#define MIR_SCHAR_MIN INT8_MIN
+#define MIR_SCHAR_MAX INT8_MAX
+#define MIR_SHORT_MIN INT16_MIN
+#define MIR_SHORT_MAX INT16_MAX
+#define MIR_INT_MIN INT32_MIN
+#define MIR_INT_MAX INT32_MAX
+#define MIR_LONG_MIN INT64_MIN
+#define MIR_LONG_MAX INT64_MAX
+#define MIR_LLONG_MIN INT64_MIN
+#define MIR_LLONG_MAX INT64_MAX
+
+typedef uint8_t mir_uchar;
+typedef uint16_t mir_ushort;
+typedef uint32_t mir_uint;
+typedef uint64_t mir_ulong;
+typedef uint64_t mir_ullong;
+
+#define MIR_UCHAR_MAX UINT8_MAX
+#define MIR_USHORT_MAX UINT16_MAX
+#define MIR_UINT_MAX UINT32_MAX
+#define MIR_ULONG_MAX UINT64_MAX
+#define MIR_ULLONG_MAX UINT64_MAX
+
+typedef mir_schar mir_char;
+#define MIR_CHAR_MIN MIR_SCHAR_MIN
+#define MIR_CHAR_MAX MIR_SCHAR_MAX
+
+typedef float mir_float;
+typedef double mir_double;
+typedef long double mir_ldouble;
+
+typedef uint8_t mir_bool;
+typedef int64_t mir_ptrdiff_t;
+typedef uint64_t mir_size_t;
+
+#define MIR_SIZE_MAX UINT64_MAX
diff --git a/mir/c2mir/aarch64/mirc-aarch64-linux.h b/mir/c2mir/aarch64/mirc-aarch64-linux.h
new file mode 100644
index 0000000..e8b961a
--- /dev/null
+++ b/mir/c2mir/aarch64/mirc-aarch64-linux.h
@@ -0,0 +1,93 @@
+/* This file is a part of MIR project.
+ Copyright (C) 2020 Vladimir Makarov .
+*/
+
+static char aarch64_mirc[]
+ = "#define __aarch64__ 1\n"
+ "#define _LP64 1\n"
+ "#define __LP64__ 1\n"
+ "#define __ARM_ARCH 8\n"
+ "\n"
+ "#define __SIZEOF_DOUBLE__ 8\n"
+ "#define __SIZEOF_FLOAT__ 4\n"
+ "#define __SIZEOF_INT__ 4\n"
+ "#define __SIZEOF_LONG_DOUBLE__ 16\n"
+ "#define __SIZEOF_LONG_LONG__ 8\n"
+ "#define __SIZEOF_LONG__ 8\n"
+ "#define __SIZEOF_POINTER__ 8\n"
+ "#define __SIZEOF_PTRDIFF_T__ 8\n"
+ "#define __SIZEOF_SHORT__ 2\n"
+ "#define __SIZEOF_SIZE_T__ 8\n"
+ "\n"
+ "#define __BYTE_ORDER__ 1234\n"
+ "#define __ORDER_LITTLE_ENDIAN__ 1234\n"
+ "#define __ORDER_BIG_ENDIAN__ 4321\n"
+ "\n"
+ "/* Some GCC predefined macros: */\n"
+ "#define __SIZE_TYPE__ unsigned long\n"
+ "#define __PTRDIFF_TYPE__ long\n"
+ "#define __INTMAX_TYPE__ long\n"
+ "#define __UINTMAX_TYPE__ unsigned long\n"
+ "#define __INT8_TYPE__ signed char\n"
+ "#define __INT16_TYPE__ short\n"
+ "#define __INT32_TYPE__ int\n"
+ "#define __INT64_TYPE__ long\n"
+ "#define __UINT8_TYPE__ unsigned char\n"
+ "#define __UINT16_TYPE__ unsigned short\n"
+ "#define __UINT32_TYPE__ unsigned int\n"
+ "#define __UINT64_TYPE__ unsigned long\n"
+ "#define __INTPTR_TYPE__ long\n"
+ "#define __UINTPTR_TYPE__ unsigned long\n"
+ "\n"
+ "#define __CHAR_BIT__ 8\n"
+ "#define __INT8_MAX__ 127\n"
+ "#define __INT16_MAX__ 32767\n"
+ "#define __INT32_MAX__ 2147483647\n"
+ "#define __INT64_MAX__ 9223372036854775807l\n"
+ "#define __UINT8_MAX__ (__INT8_MAX__ * 2u + 1u)\n"
+ "#define __UINT16_MAX__ (__INT16_MAX__ * 2u + 1u)\n"
+ "#define __UINT32_MAX__ (__INT32_MAX__ * 2u + 1u)\n"
+ "#define __UINT64_MAX__ (__INT64_MAX__ * 2u + 1u)\n"
+ "#define __SCHAR_MAX__ __INT8_MAX__\n"
+ "#define __SHRT_MAX__ __INT16_MAX__\n"
+ "#define __INT_MAX__ __INT32_MAX__\n"
+ "#define __LONG_MAX__ __INT64_MAX__\n"
+ "#define __LONG_LONG_MAX__ __INT64_MAX__\n"
+ "#define __SIZE_MAX__ __UINT64_MAX__\n"
+ "#define __PTRDIFF_MAX__ __INT64_MAX__\n"
+ "#define __INTMAX_MAX__ __INT64_MAX__\n"
+ "#define __UINTMAX_MAX__ __UINT64_MAX__\n"
+ "#define __INTPTR_MAX__ __INT64_MAX__\n"
+ "#define __UINTPTR_MAX__ __UINT64_MAX__\n"
+ "\n"
+ "#define __FLT_MIN_EXP__ (-125)\n"
+ "#define __FLT_MAX_EXP__ 128\n"
+ "#define __FLT_DIG__ 6\n"
+ "#define __FLT_DECIMAL_DIG__ 9\n"
+ "#define __FLT_MANT_DIG__ 24\n"
+ "#define __FLT_MIN__ 1.17549435082228750796873653722224568e-38F\n"
+ "#define __FLT_MAX__ 3.40282346638528859811704183484516925e+38F\n"
+ "#define __FLT_EPSILON__ 1.19209289550781250000000000000000000e-7F\n"
+ "\n"
+ "#define __DBL_MIN_EXP__ (-1021)\n"
+ "#define __DBL_MAX_EXP__ 1024\n"
+ "#define __DBL_DIG__ 15\n"
+ "#define __DBL_DECIMAL_DIG__ 17\n"
+ "#define __DBL_MANT_DIG__ 53\n"
+ "#define __DBL_MAX__ ((double) 1.79769313486231570814527423731704357e+308L)\n"
+ "#define __DBL_MIN__ ((double) 2.22507385850720138309023271733240406e-308L)\n"
+ "#define __DBL_EPSILON__ ((double) 2.22044604925031308084726333618164062e-16L)\n"
+ "\n"
+ "typedef unsigned short char16_t;\n"
+ "typedef unsigned int char32_t;\n"
+ "\n"
+#if defined(__linux__)
+ "#define __gnu_linux__ 1\n"
+ "#define __linux 1\n"
+ "#define __linux__ 1\n"
+ "#define linux 1\n"
+ "#define __unix 1\n"
+ "#define __unix__ 1\n"
+#endif
+ "\n"
+ "void *alloca (unsigned long);\n";
diff --git a/mir/c2mir/c2mir.c b/mir/c2mir/c2mir.c
index e394a5b..eb18ae3 100644
--- a/mir/c2mir/c2mir.c
+++ b/mir/c2mir/c2mir.c
@@ -25,12 +25,23 @@
#include "c2mir.h"
-#ifdef __x86_64__
+#if defined(__x86_64__)
#include "x86_64/cx86_64.h"
+#elif defined(__aarch64__)
+#include "aarch64/caarch64.h"
+#elif defined(__PPC64__)
+#include "ppc64/cppc64.h"
#else
#error "undefined or unsupported generation target for C"
#endif
+#define SWAP(a1, a2, t) \
+ do { \
+ t = a1; \
+ a1 = a2; \
+ a2 = t; \
+ } while (0)
+
typedef enum {
C_alloc_error,
C_unfinished_comment,
@@ -300,8 +311,12 @@ static mir_size_t raw_type_size (c2m_ctx_t c2m_ctx, struct type *type) {
return type->raw_size;
}
-#ifdef __x86_64__
+#if defined(__x86_64__)
#include "x86_64/cx86_64-code.c"
+#elif defined(__aarch64__)
+#include "aarch64/caarch64-code.c"
+#elif defined(__PPC64__)
+#include "ppc64/cppc64-code.c"
#else
#error "undefined or unsupported generation target for C"
#endif
@@ -332,18 +347,18 @@ static int char_is_signed_p (void) { return MIR_CHAR_MAX == MIR_SCHAR_MAX; }
enum str_flag { FLAG_EXT = 1, FLAG_C89, FLAG_EXT89 };
-static int str_eq (str_t str1, str_t str2) {
+static int str_eq (str_t str1, str_t str2, void *arg) {
return str1.len == str2.len && memcmp (str1.s, str2.s, str1.len) == 0;
}
-static htab_hash_t str_hash (str_t str) { return mir_hash (str.s, str.len, 0x42); }
-static int str_key_eq (str_t str1, str_t str2) { return str1.key == str2.key; }
-static htab_hash_t str_key_hash (str_t str) { return mir_hash64 (str.key, 0x24); }
+static htab_hash_t str_hash (str_t str, void *arg) { return mir_hash (str.s, str.len, 0x42); }
+static int str_key_eq (str_t str1, str_t str2, void *arg) { return str1.key == str2.key; }
+static htab_hash_t str_key_hash (str_t str, void *arg) { return mir_hash64 (str.key, 0x24); }
static str_t uniq_cstr (c2m_ctx_t c2m_ctx, const char *str);
static void str_init (c2m_ctx_t c2m_ctx) {
- HTAB_CREATE (str_t, str_tab, 1000, str_hash, str_eq);
- HTAB_CREATE (str_t, str_key_tab, 200, str_key_hash, str_key_eq);
+ HTAB_CREATE (str_t, str_tab, 1000, str_hash, str_eq, NULL);
+ HTAB_CREATE (str_t, str_key_tab, 200, str_key_hash, str_key_eq, NULL);
empty_str = uniq_cstr (c2m_ctx, "");
}
@@ -927,11 +942,7 @@ static char *reverse (VARR (char) * v) {
int i, j, temp, last = (int) VARR_LENGTH (char, v) - 1;
if (last >= 0 && addr[last] == '\0') last--;
- for (i = last, j = 0; i > j; i--, j++) {
- temp = addr[i];
- addr[i] = addr[j];
- addr[j] = temp;
- }
+ for (i = last, j = 0; i > j; i--, j++) SWAP (addr[i], addr[j], temp);
return addr;
}
@@ -1804,11 +1815,11 @@ static void add_to_temp_string (c2m_ctx_t c2m_ctx, const char *str) {
VARR_PUSH (char, temp_string, '\0');
}
-static int macro_eq (macro_t macro1, macro_t macro2) {
+static int macro_eq (macro_t macro1, macro_t macro2, void *arg) {
return macro1->id->repr == macro2->id->repr;
}
-static htab_hash_t macro_hash (macro_t macro) {
+static htab_hash_t macro_hash (macro_t macro, void *arg) {
return mir_hash (macro->id->repr, strlen (macro->id->repr), 0x42);
}
@@ -1823,7 +1834,7 @@ static void init_macros (c2m_ctx_t c2m_ctx) {
VARR (token_t) * params;
VARR_CREATE (macro_t, macros, 2048);
- HTAB_CREATE (macro_t, macro_tab, 2048, macro_hash, macro_eq);
+ HTAB_CREATE (macro_t, macro_tab, 2048, macro_hash, macro_eq, NULL);
/* Standard macros : */
new_std_macro (c2m_ctx, "__DATE__");
new_std_macro (c2m_ctx, "__TIME__");
@@ -3529,17 +3540,19 @@ typedef struct {
DEF_HTAB (tpname_t);
static HTAB (tpname_t) * tpname_tab;
-static int tpname_eq (tpname_t tpname1, tpname_t tpname2) {
+static int tpname_eq (tpname_t tpname1, tpname_t tpname2, void *arg) {
return tpname1.id->u.s.s == tpname2.id->u.s.s && tpname1.scope == tpname2.scope;
}
-static htab_hash_t tpname_hash (tpname_t tpname) {
+static htab_hash_t tpname_hash (tpname_t tpname, void *arg) {
return (mir_hash_finish (
mir_hash_step (mir_hash_step (mir_hash_init (0x42), (uint64_t) tpname.id->u.s.s),
(uint64_t) tpname.scope)));
}
-static void tpname_init (void) { HTAB_CREATE (tpname_t, tpname_tab, 1000, tpname_hash, tpname_eq); }
+static void tpname_init (void) {
+ HTAB_CREATE (tpname_t, tpname_tab, 1000, tpname_hash, tpname_eq, NULL);
+}
static int tpname_find (node_t id, node_t scope, tpname_t *res) {
int found_p;
@@ -5013,21 +5026,22 @@ struct check_ctx {
static int supported_alignment_p (mir_llong align) { return TRUE; } // ???
-static int symbol_eq (symbol_t s1, symbol_t s2) {
+static int symbol_eq (symbol_t s1, symbol_t s2, void *arg) {
return s1.mode == s2.mode && s1.id->u.s.s == s2.id->u.s.s && s1.scope == s2.scope;
}
-static htab_hash_t symbol_hash (symbol_t s) {
+static htab_hash_t symbol_hash (symbol_t s, void *arg) {
return (mir_hash_finish (
mir_hash_step (mir_hash_step (mir_hash_step (mir_hash_init (0x42), (uint64_t) s.mode),
(uint64_t) s.id->u.s.s),
(uint64_t) s.scope)));
}
-static void symbol_clear (symbol_t sym) { VARR_DESTROY (node_t, sym.defs); }
+static void symbol_clear (symbol_t sym, void *arg) { VARR_DESTROY (node_t, sym.defs); }
static void symbol_init (c2m_ctx_t c2m_ctx) {
- HTAB_CREATE_WITH_FREE_FUNC (symbol_t, symbol_tab, 5000, symbol_hash, symbol_eq, symbol_clear);
+ HTAB_CREATE_WITH_FREE_FUNC (symbol_t, symbol_tab, 5000, symbol_hash, symbol_eq, symbol_clear,
+ NULL);
}
static int symbol_find (c2m_ctx_t c2m_ctx, enum symbol_mode mode, node_t id, node_t scope,
@@ -5183,13 +5197,6 @@ static struct type integer_promotion (const struct type *type) {
return res;
}
-#define SWAP(a1, a2, t) \
- do { \
- t = a1; \
- a1 = a2; \
- a2 = t; \
- } while (0)
-
static struct type arithmetic_conversion (const struct type *type1, const struct type *type2) {
struct type res, t1, t2;
@@ -5884,10 +5891,8 @@ static node_t process_tag (c2m_ctx_t c2m_ctx, node_t r, node_t id, node_t decl_l
error (c2m_ctx, id->pos, "tag %s redeclaration", id->u.s.s);
} else {
if (decl_list->code != N_IGNORE) { /* swap decl lists */
- DLIST (node_t) temp = r->ops;
-
- r->ops = sym.def_node->ops;
- sym.def_node->ops = temp;
+ DLIST (node_t) temp;
+ SWAP (r->ops, sym.def_node->ops, temp);
}
r = sym.def_node;
}
@@ -6302,9 +6307,13 @@ static void adjust_param_type (c2m_ctx_t c2m_ctx, struct type **type_ptr) {
if (type->mode == TM_ARR) { // ??? static, old type qual
arr_type = type->u.arr_type;
- type->mode = TM_PTR;
- type->u.ptr_type = arr_type->el_type;
- type->type_qual = arr_type->ind_type_qual;
+ par_type = create_type (c2m_ctx, NULL);
+ par_type->mode = TM_PTR;
+ par_type->pos_node = type->pos_node;
+ par_type->u.ptr_type = arr_type->el_type;
+ par_type->type_qual = arr_type->ind_type_qual;
+ par_type->arr_type = type;
+ *type_ptr = type = par_type;
make_type_complete (c2m_ctx, type);
} else if (type->mode == TM_FUNC) {
par_type = create_type (c2m_ctx, NULL);
@@ -7486,7 +7495,7 @@ static struct expr *check_assign_op (c2m_ctx_t c2m_ctx, node_t r, node_t op1, no
return e;
}
-static unsigned case_hash (case_t el) {
+static unsigned case_hash (case_t el, void *arg) {
node_t case_expr = NL_HEAD (el->case_node->ops);
struct expr *expr;
@@ -7498,7 +7507,7 @@ static unsigned case_hash (case_t el) {
return mir_hash (&expr->u.u_val, sizeof (expr->u.u_val), 0x42);
}
-static int case_eq (case_t el1, case_t el2) {
+static int case_eq (case_t el1, case_t el2, void *arg) {
node_t case_expr1 = NL_HEAD (el1->case_node->ops);
node_t case_expr2 = NL_HEAD (el2->case_node->ops);
struct expr *expr1, *expr2;
@@ -9050,7 +9059,7 @@ static void context_init (MIR_context_t ctx) {
symbol_init (c2m_ctx);
in_params_p = FALSE;
curr_unnamed_anon_struct_union_member = NULL;
- HTAB_CREATE (case_t, case_tab, 100, case_hash, case_eq);
+ HTAB_CREATE (case_t, case_tab, 100, case_hash, case_eq, NULL);
VARR_CREATE (decl_t, func_decls_for_allocation, 1024);
}
@@ -9162,14 +9171,18 @@ static op_t new_op (decl_t decl, MIR_op_t mir_op) {
return res;
}
-static htab_hash_t reg_var_hash (reg_var_t r) { return mir_hash (r.name, strlen (r.name), 0x42); }
-static int reg_var_eq (reg_var_t r1, reg_var_t r2) { return strcmp (r1.name, r2.name) == 0; }
+static htab_hash_t reg_var_hash (reg_var_t r, void *arg) {
+ return mir_hash (r.name, strlen (r.name), 0x42);
+}
+static int reg_var_eq (reg_var_t r1, reg_var_t r2, void *arg) {
+ return strcmp (r1.name, r2.name) == 0;
+}
static void init_reg_vars (MIR_context_t ctx) {
c2m_ctx_t c2m_ctx = *c2m_ctx_loc (ctx);
reg_free_mark = 0;
- HTAB_CREATE (reg_var_t, reg_var_tab, 128, reg_var_hash, reg_var_eq);
+ HTAB_CREATE (reg_var_t, reg_var_tab, 128, reg_var_hash, reg_var_eq, NULL);
}
static void finish_curr_func_reg_vars (MIR_context_t ctx) {
@@ -9328,6 +9341,29 @@ static void emit_insn (MIR_context_t ctx, MIR_insn_t insn) {
MIR_append_insn (ctx, curr_func, insn);
}
+/* BCOND T, L1; JMP L2; L1: => BNCOND T, L2; L1:
+ JMP L; L: => L: */
+static void emit_label_insn_opt (MIR_context_t ctx, MIR_insn_t insn) {
+ c2m_ctx_t c2m_ctx = *c2m_ctx_loc (ctx);
+ MIR_insn_code_t rev_code;
+ MIR_insn_t last, prev;
+
+ assert (insn->code == MIR_LABEL);
+ if ((last = DLIST_TAIL (MIR_insn_t, curr_func->u.func->insns)) != NULL
+ && (prev = DLIST_PREV (MIR_insn_t, last)) != NULL && last->code == MIR_JMP
+ && (rev_code = MIR_reverse_branch_code (prev->code)) != MIR_INSN_BOUND
+ && prev->ops[0].mode == MIR_OP_LABEL && prev->ops[0].u.label == insn) {
+ prev->ops[0] = last->ops[0];
+ prev->code = rev_code;
+ MIR_remove_insn (ctx, curr_func, last);
+ }
+ if ((last = DLIST_TAIL (MIR_insn_t, curr_func->u.func->insns)) != NULL && last->code == MIR_JMP
+ && last->ops[0].mode == MIR_OP_LABEL && last->ops[0].u.label == insn) {
+ MIR_remove_insn (ctx, curr_func, last);
+ }
+ MIR_append_insn (ctx, curr_func, insn);
+}
+
/* Change t1 = expr; v = t1 to v = expr */
static void emit_insn_opt (MIR_context_t ctx, MIR_insn_t insn) {
c2m_ctx_t c2m_ctx = *c2m_ctx_loc (ctx);
@@ -9589,16 +9625,22 @@ static op_t mem_to_address (MIR_context_t ctx, op_t mem) {
static op_t force_val (MIR_context_t ctx, op_t op, int arr_p) {
op_t temp_op;
int sh;
+ c2m_ctx_t c2m_ctx;
if (arr_p && op.mir_op.mode == MIR_OP_MEM) {
/* an array -- use a pointer: */
return mem_to_address (ctx, op);
}
if (op.decl == NULL || op.decl->bit_offset < 0) return op;
+ c2m_ctx = *c2m_ctx_loc (ctx);
assert (op.mir_op.mode == MIR_OP_MEM);
temp_op = get_new_temp (ctx, MIR_T_I64);
emit2 (ctx, MIR_MOV, temp_op.mir_op, op.mir_op);
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
sh = 64 - op.decl->bit_offset - op.decl->width;
+#else
+ sh = op.decl->bit_offset + (64 - type_size (c2m_ctx, op.decl->decl_spec.type) * MIR_CHAR_BIT);
+#endif
if (sh != 0) emit3 (ctx, MIR_LSH, temp_op.mir_op, temp_op.mir_op, MIR_new_int_op (ctx, sh));
emit3 (ctx,
signed_integer_type_p (op.decl->decl_spec.type)
@@ -9820,7 +9862,7 @@ static void emit_label (MIR_context_t ctx, node_t r) {
assert (labels->code == N_LIST);
if (NL_HEAD (labels->ops) == NULL) return;
if (labels->attr == NULL) labels->attr = MIR_new_label (ctx);
- emit_insn (ctx, labels->attr);
+ emit_label_insn_opt (ctx, labels->attr);
}
static MIR_label_t get_label (MIR_context_t ctx, node_t target) {
@@ -9877,7 +9919,7 @@ static void block_move (MIR_context_t ctx, op_t var, op_t val, mir_size_t size)
emit2 (ctx, MIR_MOV, index.mir_op, MIR_new_int_op (ctx, size));
val = modify_for_block_move (ctx, val, index);
var = modify_for_block_move (ctx, var, index);
- emit_insn (ctx, repeat_label);
+ emit_label_insn_opt (ctx, repeat_label);
emit3 (ctx, MIR_SUB, index.mir_op, index.mir_op, one_op.mir_op);
assert (var.mir_op.mode == MIR_OP_MEM && val.mir_op.mode == MIR_OP_MEM);
val.mir_op.u.mem.type = var.mir_op.u.mem.type = MIR_T_I8;
@@ -10234,10 +10276,16 @@ static void emit_scalar_assign (MIR_context_t ctx, op_t var, op_t *val, MIR_type
int width = var.decl->width;
uint64_t mask, mask2;
op_t temp_op1, temp_op2, temp_op3, temp_op4;
+ c2m_ctx_t c2m_ctx = *c2m_ctx_loc (ctx);
+ size_t size = type_size (c2m_ctx, var.decl->decl_spec.type) * MIR_CHAR_BIT;
assert (var.mir_op.mode == MIR_OP_MEM);
mask = 0xffffffffffffffff >> (64 - width);
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
mask2 = ~(mask << var.decl->bit_offset);
+#else
+ mask2 = ~(mask << (size - var.decl->bit_offset - width));
+#endif
temp_op1 = get_new_temp (ctx, MIR_T_I64);
temp_op2 = get_new_temp (ctx, MIR_T_I64);
temp_op3 = get_new_temp (ctx, MIR_T_I64);
@@ -10255,12 +10303,21 @@ static void emit_scalar_assign (MIR_context_t ctx, op_t var, op_t *val, MIR_type
}
emit3 (ctx, MIR_AND, temp_op3.mir_op, temp_op1.mir_op, MIR_new_uint_op (ctx, mask));
temp_op4 = get_new_temp (ctx, MIR_T_I64);
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
if (var.decl->bit_offset == 0) {
temp_op4 = temp_op3;
} else {
emit3 (ctx, MIR_LSH, temp_op4.mir_op, temp_op3.mir_op,
MIR_new_int_op (ctx, var.decl->bit_offset));
}
+#else
+ if (size - var.decl->bit_offset - width == 0) {
+ temp_op4 = temp_op3;
+ } else {
+ emit3 (ctx, MIR_LSH, temp_op4.mir_op, temp_op3.mir_op,
+ MIR_new_int_op (ctx, size - var.decl->bit_offset - width));
+ }
+#endif
if (!ignore_others_p) {
emit3 (ctx, MIR_OR, temp_op4.mir_op, temp_op4.mir_op, temp_op2.mir_op);
}
@@ -10268,19 +10325,29 @@ static void emit_scalar_assign (MIR_context_t ctx, op_t var, op_t *val, MIR_type
}
}
-static void add_bit_field (uint64_t *u, uint64_t v, decl_t member_decl) {
+static void add_bit_field (MIR_context_t ctx, uint64_t *u, uint64_t v, decl_t member_decl) {
uint64_t mask, mask2;
int bit_offset = member_decl->bit_offset, width = member_decl->width;
+ c2m_ctx_t c2m_ctx = *c2m_ctx_loc (ctx);
+ size_t size = type_size (c2m_ctx, member_decl->decl_spec.type) * MIR_CHAR_BIT;
mask = 0xffffffffffffffff >> (64 - width);
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
mask2 = ~(mask << bit_offset);
+#else
+ mask2 = ~(mask << (size - bit_offset - width));
+#endif
*u &= mask2;
- v &= mask;
if (signed_integer_type_p (member_decl->decl_spec.type)) {
v <<= (64 - width);
v = (int64_t) v >> (64 - width);
}
+ v &= mask;
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
v <<= bit_offset;
+#else
+ v <<= size - bit_offset - width;
+#endif
*u |= v;
}
@@ -10400,14 +10467,14 @@ static void gen_initializer (MIR_context_t ctx, size_t init_start, op_t var,
uint64_t u = 0;
assert (val.mir_op.mode == MIR_OP_INT || val.mir_op.mode == MIR_OP_UINT);
- add_bit_field (&u, val.mir_op.u.u, init_el.member_decl);
+ add_bit_field (ctx, &u, val.mir_op.u.u, init_el.member_decl);
for (; i + 1 < VARR_LENGTH (init_el_t, init_els); i++, init_el = next_init_el) {
next_init_el = VARR_GET (init_el_t, init_els, i + 1);
if (next_init_el.offset != init_el.offset) break;
if (next_init_el.member_decl->bit_offset == init_el.member_decl->bit_offset) continue;
val = gen (ctx, next_init_el.init, NULL, NULL, TRUE, NULL);
assert (val.mir_op.mode == MIR_OP_INT || val.mir_op.mode == MIR_OP_UINT);
- add_bit_field (&u, val.mir_op.u.u, next_init_el.member_decl);
+ add_bit_field (ctx, &u, val.mir_op.u.u, next_init_el.member_decl);
}
val.mir_op.u.u = u;
}
@@ -10589,19 +10656,19 @@ static op_t gen (MIR_context_t ctx, node_t r, MIR_label_t true_label, MIR_label_
assert (t_label != NULL && f_label != NULL);
gen (ctx, NL_HEAD (r->ops), r->code == N_ANDAND ? temp_label : t_label,
r->code == N_ANDAND ? f_label : temp_label, FALSE, NULL);
- emit_insn (ctx, temp_label);
+ emit_label_insn_opt (ctx, temp_label);
gen (ctx, NL_EL (r->ops, 1), t_label, f_label, FALSE, NULL);
if (make_val_p) {
MIR_label_t end_label = MIR_new_label (ctx);
type = ((struct expr *) r->attr)->type;
res = get_new_temp (ctx, get_mir_type (ctx, type));
- emit_insn (ctx, t_label);
+ emit_label_insn_opt (ctx, t_label);
emit2 (ctx, MIR_MOV, res.mir_op, one_op.mir_op);
emit1 (ctx, MIR_JMP, MIR_new_label_op (ctx, end_label));
- emit_insn (ctx, f_label);
+ emit_label_insn_opt (ctx, f_label);
emit2 (ctx, MIR_MOV, res.mir_op, zero_op.mir_op);
- emit_insn (ctx, end_label);
+ emit_label_insn_opt (ctx, end_label);
}
true_label = false_label = NULL;
} else if (true_label != NULL) {
@@ -10633,12 +10700,12 @@ static op_t gen (MIR_context_t ctx, node_t r, MIR_label_t true_label, MIR_label_
res = get_new_temp (ctx, MIR_T_I64);
gen (ctx, NL_HEAD (r->ops), t_label, f_label, FALSE, NULL);
- emit_insn (ctx, t_label);
+ emit_label_insn_opt (ctx, t_label);
emit2 (ctx, MIR_MOV, res.mir_op, zero_op.mir_op);
emit1 (ctx, MIR_JMP, MIR_new_label_op (ctx, end_label));
- emit_insn (ctx, f_label);
+ emit_label_insn_opt (ctx, f_label);
emit2 (ctx, MIR_MOV, res.mir_op, one_op.mir_op);
- emit_insn (ctx, end_label);
+ emit_label_insn_opt (ctx, end_label);
}
break;
case N_ADD:
@@ -10705,8 +10772,10 @@ static op_t gen (MIR_context_t ctx, node_t r, MIR_label_t true_label, MIR_label_
t = get_mir_type (ctx, type);
var = gen (ctx, NL_HEAD (r->ops), NULL, NULL, FALSE, NULL);
op1 = force_val (ctx, var, FALSE);
- res = get_new_temp (ctx, t);
- emit2 (ctx, tp_mov (t), res.mir_op, op1.mir_op);
+ if (val_p || true_label != NULL) {
+ res = get_new_temp (ctx, t);
+ emit2 (ctx, tp_mov (t), res.mir_op, op1.mir_op);
+ }
val = promote (ctx, op1, t, TRUE);
op2 = promote (ctx,
type->mode != TM_PTR
@@ -10756,7 +10825,7 @@ static op_t gen (MIR_context_t ctx, node_t r, MIR_label_t true_label, MIR_label_
t = get_op_type (ctx, var);
op2
= gen (ctx, NL_EL (r->ops, 1), NULL, NULL, t != MIR_T_UNDEF, t != MIR_T_UNDEF ? NULL : &var);
- if (t == MIR_T_UNDEF) {
+ if ((!val_p && true_label == NULL) || t == MIR_T_UNDEF) {
res = var;
val = op2;
} else {
@@ -10769,7 +10838,7 @@ static op_t gen (MIR_context_t ctx, node_t r, MIR_label_t true_label, MIR_label_
assert (t != MIR_T_UNDEF);
val = cast (ctx, val, get_mir_type (ctx, ((struct expr *) r->attr)->type), FALSE);
emit_scalar_assign (ctx, var, &val, t, FALSE);
- if (r->code != N_POST_INC && r->code != N_POST_DEC)
+ if ((val_p || true_label != NULL) && r->code != N_POST_INC && r->code != N_POST_DEC)
emit2_noopt (ctx, tp_mov (t), res.mir_op, val.mir_op);
} else { /* block move */
mir_size_t size = type_size (c2m_ctx, ((struct expr *) r->attr)->type);
@@ -10929,7 +10998,7 @@ static op_t gen (MIR_context_t ctx, node_t r, MIR_label_t true_label, MIR_label_
if (!void_p) t = get_mir_type (ctx, type);
gen (ctx, cond, true_label, false_label, FALSE, NULL);
- emit_insn (ctx, true_label);
+ emit_label_insn_opt (ctx, true_label);
op1 = gen (ctx, true_expr, NULL, NULL, !void_p && t != MIR_T_UNDEF, NULL);
if (!void_p) {
if (t != MIR_T_UNDEF) {
@@ -10945,7 +11014,7 @@ static op_t gen (MIR_context_t ctx, node_t r, MIR_label_t true_label, MIR_label_
}
}
emit1 (ctx, MIR_JMP, MIR_new_label_op (ctx, end_label));
- emit_insn (ctx, false_label);
+ emit_label_insn_opt (ctx, false_label);
op1 = gen (ctx, false_expr, NULL, NULL, !void_p && t != MIR_T_UNDEF, NULL);
if (!void_p) {
if (t != MIR_T_UNDEF) {
@@ -10958,7 +11027,7 @@ static op_t gen (MIR_context_t ctx, node_t r, MIR_label_t true_label, MIR_label_
block_move (ctx, res, op1, size);
}
}
- emit_insn (ctx, end_label);
+ emit_label_insn_opt (ctx, end_label);
break;
}
case N_ALIGNOF:
@@ -11317,12 +11386,12 @@ static op_t gen (MIR_context_t ctx, node_t r, MIR_label_t true_label, MIR_label_
assert (false_label == NULL && true_label == NULL);
emit_label (ctx, r);
top_gen (ctx, expr, if_label, else_label);
- emit_insn (ctx, if_label);
+ emit_label_insn_opt (ctx, if_label);
gen (ctx, if_stmt, NULL, NULL, FALSE, NULL);
emit1 (ctx, MIR_JMP, MIR_new_label_op (ctx, end_label));
- emit_insn (ctx, else_label);
+ emit_label_insn_opt (ctx, else_label);
gen (ctx, else_stmt, NULL, NULL, FALSE, NULL);
- emit_insn (ctx, end_label);
+ emit_label_insn_opt (ctx, end_label);
break;
}
case N_SWITCH: {
@@ -11421,14 +11490,14 @@ static op_t gen (MIR_context_t ctx, node_t r, MIR_label_t true_label, MIR_label_
emit3 (ctx, short_p ? MIR_UBLES : MIR_UBLE, MIR_new_label_op (ctx, label),
case_reg_op.mir_op, MIR_new_int_op (ctx, e2->u.i_val));
}
- emit_insn (ctx, cont_label);
+ emit_label_insn_opt (ctx, cont_label);
}
}
if (c == NULL) /* no default: */
emit1 (ctx, MIR_JMP, MIR_new_label_op (ctx, break_label));
}
top_gen (ctx, stmt, NULL, NULL);
- emit_insn (ctx, break_label);
+ emit_label_insn_opt (ctx, break_label);
break_label = saved_break_label;
break;
}
@@ -11442,11 +11511,11 @@ static op_t gen (MIR_context_t ctx, node_t r, MIR_label_t true_label, MIR_label_
continue_label = MIR_new_label (ctx);
break_label = MIR_new_label (ctx);
emit_label (ctx, r);
- emit_insn (ctx, start_label);
+ emit_label_insn_opt (ctx, start_label);
gen (ctx, stmt, NULL, NULL, FALSE, NULL);
- emit_insn (ctx, continue_label);
+ emit_label_insn_opt (ctx, continue_label);
top_gen (ctx, expr, start_label, break_label);
- emit_insn (ctx, break_label);
+ emit_label_insn_opt (ctx, break_label);
continue_label = saved_continue_label;
break_label = saved_break_label;
break;
@@ -11461,12 +11530,12 @@ static op_t gen (MIR_context_t ctx, node_t r, MIR_label_t true_label, MIR_label_
continue_label = MIR_new_label (ctx);
break_label = MIR_new_label (ctx);
emit_label (ctx, r);
- emit_insn (ctx, continue_label);
+ emit_label_insn_opt (ctx, continue_label);
top_gen (ctx, expr, stmt_label, break_label);
- emit_insn (ctx, stmt_label);
+ emit_label_insn_opt (ctx, stmt_label);
gen (ctx, stmt, NULL, NULL, FALSE, NULL);
- emit1 (ctx, MIR_JMP, MIR_new_label_op (ctx, continue_label));
- emit_insn (ctx, break_label);
+ top_gen (ctx, expr, stmt_label, break_label);
+ emit_label_insn_opt (ctx, break_label);
continue_label = saved_continue_label;
break_label = saved_break_label;
break;
@@ -11476,7 +11545,7 @@ static op_t gen (MIR_context_t ctx, node_t r, MIR_label_t true_label, MIR_label_
node_t cond = NL_NEXT (init);
node_t iter = NL_NEXT (cond);
node_t stmt = NL_NEXT (iter);
- MIR_label_t start_label = MIR_new_label (ctx), stmt_label = MIR_new_label (ctx);
+ MIR_label_t stmt_label = MIR_new_label (ctx);
MIR_label_t saved_continue_label = continue_label, saved_break_label = break_label;
assert (false_label == NULL && true_label == NULL);
@@ -11484,15 +11553,18 @@ static op_t gen (MIR_context_t ctx, node_t r, MIR_label_t true_label, MIR_label_
break_label = MIR_new_label (ctx);
emit_label (ctx, r);
top_gen (ctx, init, NULL, NULL);
- emit_insn (ctx, start_label);
if (cond->code != N_IGNORE) /* non-empty condition: */
top_gen (ctx, cond, stmt_label, break_label);
- emit_insn (ctx, stmt_label);
+ emit_label_insn_opt (ctx, stmt_label);
gen (ctx, stmt, NULL, NULL, FALSE, NULL);
- emit_insn (ctx, continue_label);
+ emit_label_insn_opt (ctx, continue_label);
top_gen (ctx, iter, NULL, NULL);
- emit1 (ctx, MIR_JMP, MIR_new_label_op (ctx, start_label));
- emit_insn (ctx, break_label);
+ if (cond->code == N_IGNORE) { /* empty condition: */
+ emit1 (ctx, MIR_JMP, MIR_new_label_op (ctx, stmt_label));
+ } else {
+ top_gen (ctx, cond, stmt_label, break_label);
+ }
+ emit_label_insn_opt (ctx, break_label);
continue_label = saved_continue_label;
break_label = saved_break_label;
break;
@@ -11579,7 +11651,7 @@ finish:
DEF_HTAB (MIR_item_t);
static HTAB (MIR_item_t) * proto_tab;
-static htab_hash_t proto_hash (MIR_item_t pi) {
+static htab_hash_t proto_hash (MIR_item_t pi, void *arg) {
MIR_proto_t p = pi->u.proto;
MIR_var_t *args = VARR_ADDR (MIR_var_t, p->args);
uint64_t h = mir_hash_init (42);
@@ -11594,7 +11666,7 @@ static htab_hash_t proto_hash (MIR_item_t pi) {
return mir_hash_finish (h);
}
-static int proto_eq (MIR_item_t pi1, MIR_item_t pi2) {
+static int proto_eq (MIR_item_t pi1, MIR_item_t pi2, void *arg) {
MIR_proto_t p1 = pi1->u.proto, p2 = pi2->u.proto;
if (p1->nres != p2->nres || p1->vararg_p != p2->vararg_p
@@ -11639,7 +11711,7 @@ static void gen_mir_protos (MIR_context_t ctx) {
MIR_type_t ret_type;
curr_mir_proto_num = 0;
- HTAB_CREATE (MIR_item_t, proto_tab, 512, proto_hash, proto_eq);
+ HTAB_CREATE (MIR_item_t, proto_tab, 512, proto_hash, proto_eq, NULL);
for (size_t i = 0; i < VARR_LENGTH (node_t, call_nodes); i++) {
call = VARR_GET (node_t, call_nodes, i);
assert (call->code == N_CALL);
@@ -12105,6 +12177,8 @@ static void init_include_dirs (MIR_context_t ctx) {
#endif
#if defined(__linux__) && defined(__x86_64__)
VARR_PUSH (char_ptr_t, system_headers, "/usr/include/x86_64-linux-gnu");
+#elif defined(__linux__) && defined(__aarch64__)
+ VARR_PUSH (char_ptr_t, system_headers, "/usr/include/aarch64-linux-gnu");
#endif
#if defined(__APPLE__) || defined(__unix__)
VARR_PUSH (char_ptr_t, system_headers, "/usr/include");
diff --git a/mir/c2mir/ppc64/cppc64-code.c b/mir/c2mir/ppc64/cppc64-code.c
new file mode 100644
index 0000000..38f62bf
--- /dev/null
+++ b/mir/c2mir/ppc64/cppc64-code.c
@@ -0,0 +1,23 @@
+/* This file is a part of MIR project.
+ Copyright (C) 2020 Vladimir Makarov .
+*/
+
+#include "../mirc.h"
+#include "mirc-ppc64-linux.h"
+
+static const char *standard_includes[] = {mirc, ppc64_mirc};
+
+static const char *standard_include_dirs[] = {"include/mirc/", "include/mirc/ppc64/"};
+
+#define MAX_ALIGNMENT 16
+
+#define ADJUST_VAR_ALIGNMENT(c2m_ctx, align, type) \
+ ppc64_adjust_var_alignment (c2m_ctx, align, type)
+
+static int ppc64_adjust_var_alignment (c2m_ctx_t c2m_ctx, int align, struct type *type) {
+ return align;
+}
+
+static int invalid_alignment (mir_llong align) {
+ return align != 0 && align != 1 && align != 2 && align != 4 && align != 8 && align != 16;
+}
diff --git a/mir/c2mir/ppc64/cppc64.h b/mir/c2mir/ppc64/cppc64.h
new file mode 100644
index 0000000..0ca92b7
--- /dev/null
+++ b/mir/c2mir/ppc64/cppc64.h
@@ -0,0 +1,50 @@
+/* This file is a part of MIR project.
+ Copyright (C) 2020 Vladimir Makarov .
+*/
+
+#include
+
+#define MIR_CHAR_BIT 8
+
+typedef int8_t mir_schar;
+typedef int16_t mir_short;
+typedef int32_t mir_int;
+typedef int64_t mir_long;
+typedef int64_t mir_llong;
+
+#define MIR_SCHAR_MIN INT8_MIN
+#define MIR_SCHAR_MAX INT8_MAX
+#define MIR_SHORT_MIN INT16_MIN
+#define MIR_SHORT_MAX INT16_MAX
+#define MIR_INT_MIN INT32_MIN
+#define MIR_INT_MAX INT32_MAX
+#define MIR_LONG_MIN INT64_MIN
+#define MIR_LONG_MAX INT64_MAX
+#define MIR_LLONG_MIN INT64_MIN
+#define MIR_LLONG_MAX INT64_MAX
+
+typedef uint8_t mir_uchar;
+typedef uint16_t mir_ushort;
+typedef uint32_t mir_uint;
+typedef uint64_t mir_ulong;
+typedef uint64_t mir_ullong;
+
+#define MIR_UCHAR_MAX UINT8_MAX
+#define MIR_USHORT_MAX UINT16_MAX
+#define MIR_UINT_MAX UINT32_MAX
+#define MIR_ULONG_MAX UINT64_MAX
+#define MIR_ULLONG_MAX UINT64_MAX
+
+typedef mir_schar mir_char;
+#define MIR_CHAR_MIN MIR_SCHAR_MIN
+#define MIR_CHAR_MAX MIR_SCHAR_MAX
+
+typedef float mir_float;
+typedef double mir_double;
+typedef long double mir_ldouble;
+
+typedef uint8_t mir_bool;
+typedef int64_t mir_ptrdiff_t;
+typedef uint64_t mir_size_t;
+
+#define MIR_SIZE_MAX UINT64_MAX
diff --git a/mir/c2mir/ppc64/mirc-ppc64-linux.h b/mir/c2mir/ppc64/mirc-ppc64-linux.h
new file mode 100644
index 0000000..9e5ac20
--- /dev/null
+++ b/mir/c2mir/ppc64/mirc-ppc64-linux.h
@@ -0,0 +1,95 @@
+/* This file is a part of MIR project.
+ Copyright (C) 2020 Vladimir Makarov .
+*/
+
+static char ppc64_mirc[]
+ = "#define __PPC64__ 1\n"
+ "#define _ARCH_PPC64 1\n"
+ "#define _LP64 1\n"
+ "#define __LP64__ 1\n"
+ "\n"
+ "#define __LONG_DOUBLE_128__ 1\n" // ???
+ "#define __SIZEOF_DOUBLE__ 8\n"
+ "#define __SIZEOF_FLOAT__ 4\n"
+ "#define __SIZEOF_INT__ 4\n"
+ "#define __SIZEOF_LONG_DOUBLE__ 16\n"
+ "#define __SIZEOF_LONG_LONG__ 8\n"
+ "#define __SIZEOF_LONG__ 8\n"
+ "#define __SIZEOF_POINTER__ 8\n"
+ "#define __SIZEOF_PTRDIFF_T__ 8\n"
+ "#define __SIZEOF_SHORT__ 2\n"
+ "#define __SIZEOF_SIZE_T__ 8\n"
+ "\n"
+ "#define _BIG_ENDIAN 1\n" // ??? Implement LE too
+ "#define __ORDER_LITTLE_ENDIAN__ 1234\n"
+ "#define __ORDER_BIG_ENDIAN__ 4321\n"
+ "#define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__\n"
+ "\n"
+ "/* Some GCC predefined macros: */\n"
+ "#define __SIZE_TYPE__ unsigned long\n"
+ "#define __PTRDIFF_TYPE__ long\n"
+ "#define __INTMAX_TYPE__ long\n"
+ "#define __UINTMAX_TYPE__ unsigned long\n"
+ "#define __INT8_TYPE__ signed char\n"
+ "#define __INT16_TYPE__ short\n"
+ "#define __INT32_TYPE__ int\n"
+ "#define __INT64_TYPE__ long\n"
+ "#define __UINT8_TYPE__ unsigned char\n"
+ "#define __UINT16_TYPE__ unsigned short\n"
+ "#define __UINT32_TYPE__ unsigned int\n"
+ "#define __UINT64_TYPE__ unsigned long\n"
+ "#define __INTPTR_TYPE__ long\n"
+ "#define __UINTPTR_TYPE__ unsigned long\n"
+ "\n"
+ "#define __CHAR_BIT__ 8\n"
+ "#define __INT8_MAX__ 127\n"
+ "#define __INT16_MAX__ 32767\n"
+ "#define __INT32_MAX__ 2147483647\n"
+ "#define __INT64_MAX__ 9223372036854775807l\n"
+ "#define __UINT8_MAX__ (__INT8_MAX__ * 2u + 1u)\n"
+ "#define __UINT16_MAX__ (__INT16_MAX__ * 2u + 1u)\n"
+ "#define __UINT32_MAX__ (__INT32_MAX__ * 2u + 1u)\n"
+ "#define __UINT64_MAX__ (__INT64_MAX__ * 2u + 1u)\n"
+ "#define __SCHAR_MAX__ __INT8_MAX__\n"
+ "#define __SHRT_MAX__ __INT16_MAX__\n"
+ "#define __INT_MAX__ __INT32_MAX__\n"
+ "#define __LONG_MAX__ __INT64_MAX__\n"
+ "#define __LONG_LONG_MAX__ __INT64_MAX__\n"
+ "#define __SIZE_MAX__ __UINT64_MAX__\n"
+ "#define __PTRDIFF_MAX__ __INT64_MAX__\n"
+ "#define __INTMAX_MAX__ __INT64_MAX__\n"
+ "#define __UINTMAX_MAX__ __UINT64_MAX__\n"
+ "#define __INTPTR_MAX__ __INT64_MAX__\n"
+ "#define __UINTPTR_MAX__ __UINT64_MAX__\n"
+ "\n"
+ "#define __FLT_MIN_EXP__ (-125)\n"
+ "#define __FLT_MAX_EXP__ 128\n"
+ "#define __FLT_DIG__ 6\n"
+ "#define __FLT_DECIMAL_DIG__ 9\n"
+ "#define __FLT_MANT_DIG__ 24\n"
+ "#define __FLT_MIN__ 1.17549435082228750796873653722224568e-38F\n"
+ "#define __FLT_MAX__ 3.40282346638528859811704183484516925e+38F\n"
+ "#define __FLT_EPSILON__ 1.19209289550781250000000000000000000e-7F\n"
+ "\n"
+ "#define __DBL_MIN_EXP__ (-1021)\n"
+ "#define __DBL_MAX_EXP__ 1024\n"
+ "#define __DBL_DIG__ 15\n"
+ "#define __DBL_DECIMAL_DIG__ 17\n"
+ "#define __DBL_MANT_DIG__ 53\n"
+ "#define __DBL_MAX__ ((double) 1.79769313486231570814527423731704357e+308L)\n"
+ "#define __DBL_MIN__ ((double) 2.22507385850720138309023271733240406e-308L)\n"
+ "#define __DBL_EPSILON__ ((double) 2.22044604925031308084726333618164062e-16L)\n"
+ "\n"
+ "typedef unsigned short char16_t;\n"
+ "typedef unsigned int char32_t;\n"
+ "\n"
+#if defined(__linux__)
+ "#define __gnu_linux__ 1\n"
+ "#define __linux 1\n"
+ "#define __linux__ 1\n"
+ "#define linux 1\n"
+ "#define __unix 1\n"
+ "#define __unix__ 1\n"
+#endif
+ "\n"
+ "void *alloca (unsigned long);\n";
diff --git a/mir/c2mir/x86_64/mirc-x86_64-linux.h b/mir/c2mir/x86_64/mirc-x86_64-linux.h
index fcbe6af..f5bf74a 100644
--- a/mir/c2mir/x86_64/mirc-x86_64-linux.h
+++ b/mir/c2mir/x86_64/mirc-x86_64-linux.h
@@ -1,3 +1,7 @@
+/* This file is a part of MIR project.
+ Copyright (C) 2019-2020 Vladimir Makarov .
+*/
+
static char x86_64_mirc[]
= "#define __amd64 1\n"
"#define __amd64__ 1\n"
@@ -9,7 +13,7 @@ static char x86_64_mirc[]
"#define __SIZEOF_DOUBLE__ 8\n"
"#define __SIZEOF_FLOAT__ 4\n"
"#define __SIZEOF_INT__ 4\n"
- "#define __SIZEOF_LONG_DOUBLE__ 8\n"
+ "#define __SIZEOF_LONG_DOUBLE__ 16\n"
"#define __SIZEOF_LONG_LONG__ 8\n"
"#define __SIZEOF_LONG__ 8\n"
"#define __SIZEOF_POINTER__ 8\n"
diff --git a/mir/mir-aarch64.c b/mir/mir-aarch64.c
new file mode 100644
index 0000000..2f1e661
--- /dev/null
+++ b/mir/mir-aarch64.c
@@ -0,0 +1,375 @@
+/* This file is a part of MIR project.
+ Copyright (C) 2018-2020 Vladimir Makarov .
+*/
+
+#define VA_LIST_IS_ARRAY_P 0
+
+// _MIR_get_thunk, _MIR_redirect_thunk, _MIR_get_interp_shim, _MIR_get_ff_call, _MIR_get_wrapper
+
+void *_MIR_get_bstart_builtin (MIR_context_t ctx) {
+ static const uint32_t bstart_code[] = {
+ 0x910003e0, /* r0 = rsp */
+ 0xd65f03c0, /* ret r30 */
+ };
+ return _MIR_publish_code (ctx, (uint8_t *) bstart_code, sizeof (bstart_code));
+}
+
+void *_MIR_get_bend_builtin (MIR_context_t ctx) {
+ static const uint32_t bend_code[] = {
+ 0x9100001f, /* rsp = r0 */
+ 0xd65f03c0, /* ret r30 */
+ };
+ return _MIR_publish_code (ctx, (uint8_t *) bend_code, sizeof (bend_code));
+}
+
+struct aarch64_va_list {
+ /* address following the last (highest addressed) named incoming
+ argument on the stack, rounded upwards to a multiple of 8 bytes,
+ or if there are no named arguments on the stack, then the value
+ of the stack pointer when the function was entered. */
+ void *__stack;
+ /* the address of the byte immediately following the general
+ register argument save area, the end of the save area being
+ aligned to a 16 byte boundary. */
+ void *__gr_top;
+ /* the address of the byte immediately following the FP/SIMD
+ register argument save area, the end of the save area being
+ aligned to a 16 byte boundary. */
+ void *__vr_top;
+ int __gr_offs; /* set to 0 – ((8 – named_gr) * 8) */
+ int __vr_offs; /* set to 0 – ((8 – named_vr) * 16) */
+};
+
+void *va_arg_builtin (void *p, uint64_t t) {
+ struct aarch64_va_list *va = p;
+ MIR_type_t type = t;
+ int fp_p = type == MIR_T_F || type == MIR_T_D || type == MIR_T_LD;
+ void *a;
+
+ if (fp_p && va->__vr_offs < 0) {
+ a = (char *) va->__vr_top + va->__vr_offs;
+ va->__vr_offs += 16;
+ } else if (!fp_p && va->__gr_offs < 0) {
+ a = (char *) va->__gr_top + va->__gr_offs;
+ va->__gr_offs += 8;
+ } else {
+ if (type == MIR_T_LD) va->__stack = (void *) (((uint64_t) va->__stack + 15) % 16);
+ a = va->__stack;
+ va->__stack = (char *) va->__stack + (type == MIR_T_LD ? 16 : 8);
+ }
+ return a;
+}
+
+void va_start_interp_builtin (MIR_context_t ctx, void *p, void *a) {
+ struct aarch64_va_list *va = p;
+ va_list *vap = a;
+
+ assert (sizeof (struct aarch64_va_list) == sizeof (va_list));
+ *va = *(struct aarch64_va_list *) vap;
+}
+
+void va_end_interp_builtin (MIR_context_t ctx, void *p) {}
+
+static int setup_imm64_insns (MIR_context_t ctx, uint32_t *to, int reg, uint64_t imm64) {
+ /* xd=imm64 */
+ static const uint32_t imm64_pat[] = {
+ 0xd2800000, /* 0: mov xd, xxxx(0-15) */
+ 0xf2a00000, /* 4: movk xd, xxxx(16-31) */
+ 0xf2c00000, /* 8: movk xd, xxxx(32-47) */
+ 0xf2e00000, /* 12: movk xd, xxxx(48-63) */
+ };
+ uint32_t mask = ~(0xffff << 5);
+
+ mir_assert (0 <= reg && reg <= 31);
+ to[0] = (imm64_pat[0] & mask) | ((uint32_t) (imm64 & 0xffff) << 5) | reg;
+ to[1] = (imm64_pat[1] & mask) | (((uint32_t) (imm64 >> 16) & 0xffff) << 5) | reg;
+ to[2] = (imm64_pat[2] & mask) | (((uint32_t) (imm64 >> 32) & 0xffff) << 5) | reg;
+ to[3] = (imm64_pat[3] & mask) | (((uint32_t) (imm64 >> 48) & 0xffff) << 5) | reg;
+ return sizeof (imm64_pat) / sizeof (uint32_t);
+}
+
+static void push_insns (MIR_context_t ctx, const uint32_t *pat, size_t pat_len) {
+ uint8_t *p = (uint8_t *) pat;
+
+ for (size_t i = 0; i < pat_len; i++) VARR_PUSH (uint8_t, machine_insns, p[i]);
+}
+
+static size_t gen_mov_addr (MIR_context_t ctx, int reg, void *addr) {
+ uint32_t insns[4];
+ int insns_num = setup_imm64_insns (ctx, insns, reg, (uint64_t) addr);
+
+ mir_assert (insns_num == 4 && sizeof (insns) == insns_num * sizeof (uint32_t));
+ push_insns (ctx, insns, insns_num * sizeof (uint32_t));
+ return insns_num * sizeof (uint32_t);
+}
+
+#define BR_OFFSET_BITS 26
+#define MAX_BR_OFFSET (1 << (BR_OFFSET_BITS - 1)) /* 1 for sign */
+#define BR_OFFSET_MASK (~(-1 << BR_OFFSET_BITS))
+
+static void gen_call_addr (MIR_context_t ctx, void *base_addr, int temp_reg, void *call_addr) {
+ static const uint32_t call_pat1 = 0x94000000; /* bl x */
+ static const uint32_t call_pat2 = 0xd63f0000; /* blr x */
+ uint32_t insn;
+ int64_t offset = (uint32_t *) call_addr - (uint32_t *) base_addr;
+
+ mir_assert (0 <= temp_reg && temp_reg <= 31);
+ if (base_addr != NULL && -(int64_t) MAX_BR_OFFSET <= offset && offset < (int64_t) MAX_BR_OFFSET) {
+ insn = call_pat1 | ((uint32_t) offset & BR_OFFSET_MASK);
+ } else {
+ gen_mov_addr (ctx, temp_reg, call_addr);
+ insn = call_pat2 | (temp_reg << 5);
+ }
+ push_insns (ctx, &insn, sizeof (insn));
+}
+
+#define NOP 0xd503201f
+
+void *_MIR_get_thunk (MIR_context_t ctx) {
+ int pat[5] = {NOP, NOP, NOP, NOP, NOP}; /* maximal size thunk -- see _MIR_redirect_thunk */
+
+ return _MIR_publish_code (ctx, (uint8_t *) pat, sizeof (pat));
+}
+
+void _MIR_redirect_thunk (MIR_context_t ctx, void *thunk, void *to) {
+ static const uint32_t branch_pat1 = 0xd61f0120; /* br x9 */
+ static const uint32_t branch_pat2 = 0x14000000; /* b x */
+ int64_t offset = (uint32_t *) to - (uint32_t *) thunk;
+ uint32_t code[5];
+
+ mir_assert (((uint64_t) thunk & 0x3) == 0 && ((uint64_t) to & 0x3) == 0); /* alignment */
+ if (-(int64_t) MAX_BR_OFFSET <= offset && offset < (int64_t) MAX_BR_OFFSET) {
+ code[0] = branch_pat2 | ((uint32_t) offset & BR_OFFSET_MASK);
+ _MIR_change_code (ctx, thunk, (uint8_t *) &code[0], sizeof (code[0]));
+ } else {
+ int n = setup_imm64_insns (ctx, code, 9, (uint64_t) to);
+
+ mir_assert (n == 4);
+ code[4] = branch_pat1;
+ _MIR_change_code (ctx, thunk, (uint8_t *) code, sizeof (code));
+ }
+}
+
+/* save r0-r7, v0-v7 */
+static const uint32_t save_insns[] = {
+ 0xa9bf1fe6, /* stp R6, R7, [SP, #-16]! */
+ 0xa9bf17e4, /* stp R4, R5, [SP, #-16]! */
+ 0xa9bf0fe2, /* stp R2, R3, [SP, #-16]! */
+ 0xa9bf07e0, /* stp R0, R1, [SP, #-16]! */
+ 0xadbf1fe6, /* stp Q6, Q7, [SP, #-32]! */
+ 0xadbf17e4, /* stp Q4, Q5, [SP, #-32]! */
+ 0xadbf0fe2, /* stp Q2, Q3, [SP, #-32]! */
+ 0xadbf07e0, /* stp Q0, Q1, [SP, #-32]! */
+};
+
+static const uint32_t restore_insns[] = {
+ 0xacc107e0, /* ldp Q0, Q1, SP, #32 */
+ 0xacc10fe2, /* ldp Q2, Q3, SP, #32 */
+ 0xacc117e4, /* ldp Q4, Q5, SP, #32 */
+ 0xacc11fe6, /* ldp Q6, Q7, SP, #32 */
+ 0xa8c107e0, /* ldp R0, R1, SP, #16 */
+ 0xa8c10fe2, /* ldp R2, R3, SP, #16 */
+ 0xa8c117e4, /* ldp R4, R5, SP, #16 */
+ 0xa8c11fe6, /* ldp R6, R7, SP, #16 */
+};
+
+static const uint32_t ld_pat = 0xf9400260; /* ldr x, [x19], offset */
+static const uint32_t lds_pat = 0xbd400260; /* ldr s, [x19], offset */
+static const uint32_t ldd_pat = 0xfd400260; /* ldr d, [x19], offset */
+static const uint32_t ldld_pat = 0x3dc00260; /* ldr q, [x19], offset */
+
+/* Generation: fun (fun_addr, res_arg_addresses):
+ push x19, x30; sp-=sp_offset; x9=fun_addr; x19=res/arg_addrs
+ x8=mem[x19,]; (arg_reg=mem[x8] or x8=mem[x8];mem[sp,sp_offset]=x8) ...
+ call fun_addr; sp+=offset
+ x8=mem[x19,]; res_reg=mem[x8]; ...
+ pop x19, x30; ret x30. */
+void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, size_t nargs,
+ MIR_type_t *arg_types, int vararg_p) {
+ static const uint32_t prolog[] = {
+ 0xa9bf7bf3, /* stp x19,x30,[sp, -16]! */
+ 0xd10003ff, /* sub sp,sp, */
+ 0xaa0003e9, /* mov x9,x0 # fun addr */
+ 0xaa0103f3, /* mov x19, x1 # result/arg addresses */
+ };
+ static const uint32_t call_end[] = {
+ 0xd63f0120, /* blr x9 */
+ 0x910003ff, /* add sp,sp, */
+ };
+ static const uint32_t epilog[] = {
+ 0xa8c17bf3, /* ldp x19,x30,[sp],16 */
+ 0xd65f03c0, /* ret x30 */
+ };
+ static const uint32_t st_pat = 0xf9000000; /* str x, [xn|sp], offset */
+ static const uint32_t sts_pat = 0xbd000000; /* str s, [xn|sp], offset */
+ static const uint32_t std_pat = 0xfd000000; /* str d, [xn|sp], offset */
+ static const uint32_t stld_pat = 0x3d800000; /* str q, [xn|sp], offset */
+ uint32_t n_xregs = 0, n_vregs = 0, sp_offset = 0, pat, offset_imm, scale, sp = 31;
+ uint32_t *addr;
+ const uint32_t temp_reg = 8; /* x8 or v9 */
+
+ VARR_TRUNC (uint8_t, machine_insns, 0);
+ push_insns (ctx, prolog, sizeof (prolog));
+ mir_assert (sizeof (long double) == 16);
+ for (size_t i = 0; i < nargs; i++) { /* args */
+ scale = arg_types[i] == MIR_T_F ? 2 : arg_types[i] == MIR_T_LD ? 4 : 3;
+ offset_imm = (((i + nres) * sizeof (long double) << 10)) >> scale;
+ if ((MIR_T_I8 <= arg_types[i] && arg_types[i] <= MIR_T_U64) || arg_types[i] == MIR_T_P) {
+ if (n_xregs < 8) {
+ pat = ld_pat | offset_imm | n_xregs++;
+ } else {
+ pat = ld_pat | offset_imm | temp_reg;
+ push_insns (ctx, &pat, sizeof (pat));
+ pat = st_pat | ((sp_offset >> scale) << 10) | temp_reg | (sp << 5);
+ sp_offset += 8;
+ }
+ push_insns (ctx, &pat, sizeof (pat));
+ } else if (arg_types[i] == MIR_T_F || arg_types[i] == MIR_T_D || arg_types[i] == MIR_T_LD) {
+ pat = arg_types[i] == MIR_T_F ? lds_pat : arg_types[i] == MIR_T_D ? ldd_pat : ldld_pat;
+ if (n_vregs < 8) {
+ pat |= offset_imm | n_vregs++;
+ } else {
+ if (arg_types[i] == MIR_T_LD) sp_offset = (sp_offset + 15) % 16;
+ pat |= offset_imm | temp_reg;
+ push_insns (ctx, &pat, sizeof (pat));
+ pat = arg_types[i] == MIR_T_F ? sts_pat : arg_types[i] == MIR_T_D ? std_pat : stld_pat;
+ pat |= ((sp_offset >> scale) << 10) | temp_reg | (sp << 5);
+ sp_offset += arg_types[i] == MIR_T_LD ? 16 : 8;
+ }
+ push_insns (ctx, &pat, sizeof (pat));
+ } else {
+ (*error_func) (MIR_call_op_error, "wrong type of arg value");
+ }
+ }
+ sp_offset = (sp_offset + 15) / 16 * 16;
+ mir_assert (sp_offset < (1 << 12));
+ ((uint32_t *) VARR_ADDR (uint8_t, machine_insns))[1] |= sp_offset << 10; /* sub sp,sp, */
+ push_insns (ctx, call_end, sizeof (call_end));
+ ((uint32_t *) (VARR_ADDR (uint8_t, machine_insns) + VARR_LENGTH (uint8_t, machine_insns)))[-1]
+ |= sp_offset << 10;
+ n_xregs = n_vregs = 0;
+ for (size_t i = 0; i < nres; i++) { /* results */
+ offset_imm = i * sizeof (long double) << 10;
+ offset_imm >>= res_types[i] == MIR_T_F ? 2 : res_types[i] == MIR_T_D ? 3 : 4;
+ if (((MIR_T_I8 <= res_types[i] && res_types[i] <= MIR_T_U64) || res_types[i] == MIR_T_P)
+ && n_xregs < 8) {
+ pat = st_pat | offset_imm | n_xregs++ | (19 << 5);
+ push_insns (ctx, &pat, sizeof (pat));
+ } else if ((res_types[i] == MIR_T_F || res_types[i] == MIR_T_D || res_types[i] == MIR_T_LD)
+ && n_vregs < 8) {
+ pat = res_types[i] == MIR_T_F ? sts_pat : res_types[i] == MIR_T_D ? std_pat : stld_pat;
+ pat |= offset_imm | n_vregs++ | (19 << 5);
+ push_insns (ctx, &pat, sizeof (pat));
+ } else {
+ (*error_func) (MIR_ret_error, "x86-64 can not handle this combination of return values");
+ }
+ }
+ push_insns (ctx, epilog, sizeof (epilog));
+ return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
+ VARR_LENGTH (uint8_t, machine_insns));
+}
+
+/* Transform C call to call of void handler (MIR_context_t ctx, MIR_item_t func_item,
+ va_list va, MIR_val_t *results) */
+void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handler) {
+ static const uint32_t save_x19_pat = 0xf81f0ff3; /* str x19, [sp,-16]! */
+ static const uint32_t prepare_pat[] = {
+ 0xd10083ff, /* sub sp, sp, 32 # allocate va_list */
+ 0x910003e8, /* mov x8, sp # va_list addr */
+ 0x128007e9, /* mov w9, #-64 # gr_offs */
+ 0xb9001909, /* str w9,[x8, 24] # va_list.gr_offs */
+ 0x12800fe9, /* mov w9, #-128 # vr_offs */
+ 0xb9001d09, /* str w9,[x8, 28] #va_list.vr_offs */
+ 0x910383e9, /* add x9, sp, #224 # gr_top */
+ 0xf9000509, /* str x9,[x8, 8] # va_list.gr_top */
+ 0x91004129, /* add x9, x9, #16 # stack */
+ 0xf9000109, /* str x9,[x8] # valist.stack */
+ 0x910283e9, /* add x9, sp, #160 # vr_top*/
+ 0xf9000909, /* str x9,[x8, 16] # va_list.vr_top */
+ 0xaa0803e2, /* mov x2, x8 # va arg */
+ 0xd2800009, /* mov x9, <(nres+1)*16> */
+ 0xcb2963ff, /* sub sp, sp, x9 */
+ 0x910043e3, /* add x3, sp, 16 # results arg */
+ 0xaa0303f3, /* mov x19, x3 # results */
+ 0xf90003fe, /* str x30, [sp] # save lr */
+ };
+ static const uint32_t shim_end[] = {
+ 0xf94003fe, /* ldr x30, [sp] */
+ 0xd2800009, /* mov x9, 224+(nres+1)*16 */
+ 0x8b2963ff, /* add sp, sp, x9 */
+ 0xf84107f3, /* ldr x19, sp, 16 */
+ 0xd65f03c0, /* ret x30 */
+ };
+ uint32_t pat, imm, n_xregs, n_vregs, offset, offset_imm;
+ uint32_t nres = func_item->u.func->nres;
+ MIR_type_t *results = func_item->u.func->res_types;
+
+ VARR_TRUNC (uint8_t, machine_insns, 0);
+ push_insns (ctx, &save_x19_pat, sizeof (save_x19_pat));
+ push_insns (ctx, save_insns, sizeof (save_insns));
+ push_insns (ctx, prepare_pat, sizeof (prepare_pat));
+ imm = (nres + 1) * 16;
+ mir_assert (imm < (1 << 16));
+ ((uint32_t *) (VARR_ADDR (uint8_t, machine_insns) + VARR_LENGTH (uint8_t, machine_insns)))[-5]
+ |= imm << 5;
+ gen_mov_addr (ctx, 0, ctx); /* mov x0, ctx */
+ gen_mov_addr (ctx, 1, func_item); /* mov x1, func_item */
+ gen_call_addr (ctx, NULL, 9, handler);
+ /* move results: */
+ n_xregs = n_vregs = offset = 0;
+ mir_assert (sizeof (long double) == 16);
+ for (uint32_t i = 0; i < nres; i++) {
+ if ((results[i] == MIR_T_F || results[i] == MIR_T_D || results[i] == MIR_T_LD) && n_vregs < 8) {
+ pat = results[i] == MIR_T_F ? lds_pat : results[i] == MIR_T_D ? ldd_pat : ldld_pat;
+ pat |= n_vregs;
+ n_vregs++;
+ } else if (n_xregs < 8) { // ??? ltp use
+ pat = ld_pat | n_xregs;
+ n_xregs++;
+ } else {
+ (*error_func) (MIR_ret_error, "aarch64 can not handle this combination of return values");
+ }
+ offset_imm = offset >> (results[i] == MIR_T_F ? 2 : results[i] == MIR_T_LD ? 4 : 3);
+ mir_assert (offset_imm < (1 << 12));
+ pat |= offset_imm << 10;
+ push_insns (ctx, &pat, sizeof (pat));
+ offset += 16;
+ }
+ push_insns (ctx, shim_end, sizeof (shim_end));
+ imm = 224 + (nres + 1) * 16;
+ mir_assert (imm < (1 << 16));
+ ((uint32_t *) (VARR_ADDR (uint8_t, machine_insns) + VARR_LENGTH (uint8_t, machine_insns)))[-4]
+ |= imm << 5;
+ return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
+ VARR_LENGTH (uint8_t, machine_insns));
+}
+
+/* Save regs x0-x7, q0-q7; x9 = call hook_address (ctx, called_func); restore regs; br x9 */
+void *_MIR_get_wrapper (MIR_context_t ctx, MIR_item_t called_func, void *hook_address) {
+ static const uint32_t jmp_insn = 0xd61f0120; /* br x9 */
+ static const uint32_t move_insn = 0xaa0003e9; /* mov x9, x0 */
+ static const uint32_t save_fplr = 0xa9bf7bfd; /* stp R29, R30, [SP, #-16]! */
+ static const uint32_t restore_fplr = 0xa8c17bfd; /* ldp R29, R30, SP, #16 */
+ uint8_t *base_addr, *curr_addr, *code;
+ size_t len = sizeof (save_insns) + sizeof (restore_insns); /* initial code length */
+
+ for (;;) {
+ curr_addr = base_addr = _MIR_get_new_code_addr (ctx, len);
+ if (curr_addr == NULL) return NULL;
+ VARR_TRUNC (uint8_t, machine_insns, 0);
+ push_insns (ctx, &save_fplr, sizeof (save_fplr));
+ curr_addr += 4;
+ push_insns (ctx, save_insns, sizeof (save_insns));
+ curr_addr += sizeof (save_insns);
+ curr_addr += gen_mov_addr (ctx, 0, ctx); /*mov x0,ctx */
+ curr_addr += gen_mov_addr (ctx, 1, called_func); /*mov x1,called_func */
+ gen_call_addr (ctx, curr_addr, 10, hook_address); /*call , use x10 as temp */
+ push_insns (ctx, &move_insn, sizeof (move_insn));
+ push_insns (ctx, restore_insns, sizeof (restore_insns));
+ push_insns (ctx, &restore_fplr, sizeof (restore_fplr));
+ push_insns (ctx, &jmp_insn, sizeof (jmp_insn));
+ len = VARR_LENGTH (uint8_t, machine_insns);
+ code = _MIR_publish_code_by_addr (ctx, base_addr, VARR_ADDR (uint8_t, machine_insns), len);
+ if (code != NULL) return code;
+ }
+}
diff --git a/mir/mir-bitmap.h b/mir/mir-bitmap.h
index 084dee3..7d9004c 100644
--- a/mir/mir-bitmap.h
+++ b/mir/mir-bitmap.h
@@ -11,6 +11,7 @@
#include
#include
#include
+#include
#include "mir-varr.h"
#define FALSE 0
@@ -99,6 +100,40 @@ static inline int bitmap_clear_bit_p (bitmap_t bm, size_t nb) {
return res;
}
+static inline int bitmap_set_or_clear_bit_range_p (bitmap_t bm, size_t nb, size_t len, int set_p) {
+ size_t nw, lsh, rsh, range_len;
+ bitmap_el_t mask, *addr;
+ int res = 0;
+
+ bitmap_expand (bm, nb + len);
+ addr = VARR_ADDR (bitmap_el_t, bm);
+ while (len > 0) {
+ nw = nb / BITMAP_WORD_BITS;
+ lsh = nb % BITMAP_WORD_BITS;
+ rsh = len >= BITMAP_WORD_BITS - lsh ? 0 : BITMAP_WORD_BITS - (nb + len) % BITMAP_WORD_BITS;
+ mask = ((~(bitmap_el_t) 0) >> (rsh + lsh)) << lsh;
+ if (set_p) {
+ res |= (~addr[nw] & mask) != 0;
+ addr[nw] |= mask;
+ } else {
+ res |= (addr[nw] & mask) != 0;
+ addr[nw] &= ~mask;
+ }
+ range_len = BITMAP_WORD_BITS - rsh - lsh;
+ len -= range_len;
+ nb += range_len;
+ }
+ return res;
+}
+
+static inline int bitmap_set_bit_range_p (bitmap_t bm, size_t nb, size_t len) {
+ return bitmap_set_or_clear_bit_range_p (bm, nb, len, TRUE);
+}
+
+static inline int bitmap_clear_bit_range_p (bitmap_t bm, size_t nb, size_t len) {
+ return bitmap_set_or_clear_bit_range_p (bm, nb, len, FALSE);
+}
+
static inline void bitmap_copy (bitmap_t dst, const_bitmap_t src) {
size_t dst_len = VARR_LENGTH (bitmap_el_t, dst);
size_t src_len = VARR_LENGTH (bitmap_el_t, src);
@@ -271,16 +306,32 @@ static inline int bitmap_ior_and_compl (bitmap_t dst, bitmap_t src1, bitmap_t sr
return bitmap_op3 (dst, src1, src2, src3, bitmap_el_ior_and_compl);
}
-static inline void bitmap_for_each (bitmap_t bm, void (*func) (size_t, void *), void *data) {
- size_t i, nb, len = VARR_LENGTH (bitmap_el_t, bm);
- bitmap_el_t el, *addr = VARR_ADDR (bitmap_el_t, bm);
+typedef struct {
+ bitmap_t bitmap;
+ size_t nbit;
+} bitmap_iterator_t;
- for (i = 0; i < len; i++) {
- if ((el = addr[i]) != 0) {
- for (nb = 0; el != 0; el >>= 1, nb++)
- if (el & 1) func (i * BITMAP_WORD_BITS + nb, data);
- }
- }
+static inline void bitmap_iterator_init (bitmap_iterator_t *iter, bitmap_t bitmap) {
+ iter->bitmap = bitmap;
+ iter->nbit = 0;
}
+static inline int bitmap_iterator_next (bitmap_iterator_t *iter, size_t *nbit) {
+ const size_t el_bits_num = sizeof (bitmap_el_t) * CHAR_BIT;
+ size_t curr_nel = iter->nbit / el_bits_num, len = VARR_LENGTH (bitmap_el_t, iter->bitmap);
+ bitmap_el_t el, *addr = VARR_ADDR (bitmap_el_t, iter->bitmap);
+
+ for (; curr_nel < len; curr_nel++, iter->nbit = curr_nel * el_bits_num)
+ if ((el = addr[curr_nel]) != 0)
+ for (el >>= iter->nbit % el_bits_num; el != 0; el >>= 1, iter->nbit++)
+ if (el & 1) {
+ *nbit = iter->nbit++;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+#define FOREACH_BITMAP_BIT(iter, bitmap, nbit) \
+ for (bitmap_iterator_init (&iter, bitmap); bitmap_iterator_next (&iter, &nbit);)
+
#endif /* #ifndef MIR_BITMAP_H */
diff --git a/mir/mir-gen-aarch64.c b/mir/mir-gen-aarch64.c
new file mode 100644
index 0000000..458f08e
--- /dev/null
+++ b/mir/mir-gen-aarch64.c
@@ -0,0 +1,2132 @@
+/* This file is a part of MIR project.
+ Copyright (C) 2020 Vladimir Makarov .
+*/
+
+static void fancy_abort (int code) {
+ if (!code) abort ();
+}
+#undef gen_assert
+#define gen_assert(c) fancy_abort (c)
+
+#include
+
+#define HREG_EL(h) h##_HARD_REG
+#define REP_SEP ,
+enum {
+ REP8 (HREG_EL, R0, R1, R2, R3, R4, R5, R6, R7),
+ REP8 (HREG_EL, R8, R9, R10, R11, R12, R13, R14, R15),
+ REP8 (HREG_EL, R16, R17, R18, R19, R20, R21, R22, R23),
+ REP8 (HREG_EL, R24, R25, R26, R27, R28, R29, R30, SP),
+ ZR_HARD_REG = SP_HARD_REG,
+ REP8 (HREG_EL, V0, V1, V2, V3, V4, V5, V6, V7),
+ REP8 (HREG_EL, V8, V9, V10, V11, V12, V13, V14, V15),
+ REP8 (HREG_EL, V16, V17, V18, V19, V20, V21, V22, V23),
+ REP8 (HREG_EL, V24, V25, V26, V27, V28, V29, V30, V31),
+};
+#undef REP_SEP
+
+static const MIR_reg_t MAX_HARD_REG = V31_HARD_REG;
+static const MIR_reg_t FP_HARD_REG = R29_HARD_REG;
+static const MIR_reg_t LINK_HARD_REG = R30_HARD_REG;
+
+static int target_locs_num (MIR_reg_t loc, MIR_type_t type) {
+ return loc > MAX_HARD_REG && type == MIR_T_LD ? 2 : 1;
+}
+
+/* Hard regs not used in machinized code, preferably call used ones. */
+const MIR_reg_t TEMP_INT_HARD_REG1 = R9_HARD_REG, TEMP_INT_HARD_REG2 = R10_HARD_REG;
+const MIR_reg_t TEMP_FLOAT_HARD_REG1 = V16_HARD_REG, TEMP_FLOAT_HARD_REG2 = V17_HARD_REG;
+const MIR_reg_t TEMP_DOUBLE_HARD_REG1 = V16_HARD_REG, TEMP_DOUBLE_HARD_REG2 = V17_HARD_REG;
+const MIR_reg_t TEMP_LDOUBLE_HARD_REG1 = V16_HARD_REG;
+const MIR_reg_t TEMP_LDOUBLE_HARD_REG2 = V17_HARD_REG;
+
+static inline int target_hard_reg_type_ok_p (MIR_reg_t hard_reg, MIR_type_t type) {
+ assert (hard_reg <= MAX_HARD_REG);
+ return MIR_fp_type_p (type) ? hard_reg >= V0_HARD_REG : hard_reg < V0_HARD_REG;
+}
+
+static inline int target_fixed_hard_reg_p (MIR_reg_t hard_reg) {
+ assert (hard_reg <= MAX_HARD_REG);
+ return (hard_reg == FP_HARD_REG || hard_reg == SP_HARD_REG || hard_reg == TEMP_INT_HARD_REG1
+ || hard_reg == TEMP_INT_HARD_REG2 || hard_reg == TEMP_FLOAT_HARD_REG1
+ || hard_reg == TEMP_FLOAT_HARD_REG2 || hard_reg == TEMP_DOUBLE_HARD_REG1
+ || hard_reg == TEMP_DOUBLE_HARD_REG2 || hard_reg == TEMP_LDOUBLE_HARD_REG1
+ || hard_reg == TEMP_LDOUBLE_HARD_REG2);
+}
+
+static inline int target_call_used_hard_reg_p (MIR_reg_t hard_reg) {
+ assert (hard_reg <= MAX_HARD_REG);
+ return !((hard_reg >= R19_HARD_REG && hard_reg <= R28_HARD_REG)
+ || (hard_reg >= V8_HARD_REG && hard_reg <= V15_HARD_REG));
+}
+
+/* Stack layout (sp refers to the last reserved stack slot address)
+ from higher address to lower address memory:
+
+ | ... | prev func stack (start aligned to 16 bytes)
+ |---------------|
+ | gr save area | 64 bytes optional area for vararg func integer reg save area
+ |---------------|
+ | vr save area | 128 bytes optional area for vararg func fp reg save area
+ |---------------|
+ | saved regs | callee saved regs used in the func (known only after RA), rounded 16 bytes
+ |---------------|
+ | slots assigned| can be absent for small functions (known only after RA), rounded 16 bytes
+ | to pseudos |
+ |---------------|
+ | previous | 16-bytes setup in prolog, used only for varag func or args passed on stack
+ | stack start | to move args and to setup va_start on machinize pass
+ |---------------|
+ | LR | sp before prologue and after saving LR = start sp
+ |---------------|
+ | old FP | frame pointer for previous func stack frame; new FP refers for here
+ | | it has lowest address as 12-bit offsets are only positive
+ |---------------|
+ | alloca areas | optional
+ |---------------|
+ | slots for | dynamically allocated/deallocated by caller
+ | passing args |
+
+ size of slots and saved regs is multiple of 16 bytes
+
+ */
+
+static const int int_reg_save_area_size = 8 * 8;
+static const int reg_save_area_size = 8 * 8 + 8 * 16;
+
+static const MIR_insn_code_t target_io_dup_op_insn_codes[] = {MIR_INSN_BOUND};
+
+static MIR_insn_code_t get_ext_code (MIR_type_t type) {
+ switch (type) {
+ case MIR_T_I8: return MIR_EXT8;
+ case MIR_T_U8: return MIR_UEXT8;
+ case MIR_T_I16: return MIR_EXT16;
+ case MIR_T_U16: return MIR_UEXT16;
+ case MIR_T_I32: return MIR_EXT32;
+ case MIR_T_U32: return MIR_UEXT32;
+ default: return MIR_INVALID_INSN;
+ }
+}
+
+static MIR_reg_t get_arg_reg (MIR_type_t arg_type, size_t *int_arg_num, size_t *fp_arg_num,
+ MIR_insn_code_t *mov_code) {
+ MIR_reg_t arg_reg;
+
+ if (arg_type == MIR_T_F || arg_type == MIR_T_D || arg_type == MIR_T_LD) {
+ switch (*fp_arg_num) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7: arg_reg = V0_HARD_REG + *fp_arg_num; break;
+ default: arg_reg = MIR_NON_HARD_REG; break;
+ }
+ (*fp_arg_num)++;
+ *mov_code = arg_type == MIR_T_F ? MIR_FMOV : arg_type == MIR_T_D ? MIR_DMOV : MIR_LDMOV;
+ } else {
+ switch (*int_arg_num) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7: arg_reg = R0_HARD_REG + *int_arg_num; break;
+ default: arg_reg = MIR_NON_HARD_REG; break;
+ }
+ (*int_arg_num)++;
+ *mov_code = MIR_MOV;
+ }
+ return arg_reg;
+}
+
+static void machinize_call (MIR_context_t ctx, MIR_insn_t call_insn) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ MIR_func_t func = curr_func_item->u.func;
+ MIR_proto_t proto = call_insn->ops[0].u.ref->u.proto;
+ size_t nargs, nops = MIR_insn_nops (ctx, call_insn), start = proto->nres + 2;
+ size_t int_arg_num = 0, fp_arg_num = 0, mem_size = 0;
+ MIR_type_t type, mem_type;
+ MIR_op_mode_t mode;
+ MIR_var_t *arg_vars = NULL;
+ MIR_reg_t arg_reg;
+ MIR_op_t arg_op, temp_op, arg_reg_op, ret_reg_op, mem_op;
+ MIR_insn_code_t new_insn_code, ext_code;
+ MIR_insn_t new_insn, prev_insn, next_insn, ext_insn;
+ MIR_insn_t prev_call_insn = DLIST_PREV (MIR_insn_t, call_insn);
+ uint32_t n_iregs, n_vregs;
+
+ if (call_insn->code == MIR_INLINE) call_insn->code = MIR_CALL;
+ if (proto->args == NULL) {
+ nargs = 0;
+ } else {
+ gen_assert (nops >= VARR_LENGTH (MIR_var_t, proto->args)
+ && (proto->vararg_p || nops - start == VARR_LENGTH (MIR_var_t, proto->args)));
+ nargs = VARR_LENGTH (MIR_var_t, proto->args);
+ arg_vars = VARR_ADDR (MIR_var_t, proto->args);
+ }
+ if (call_insn->ops[1].mode != MIR_OP_REG && call_insn->ops[1].mode != MIR_OP_HARD_REG) {
+ // ??? to optimize (can be immediate operand for func call)
+ temp_op = MIR_new_reg_op (ctx, gen_new_temp_reg (ctx, MIR_T_I64, func));
+ new_insn = MIR_new_insn (ctx, MIR_MOV, temp_op, call_insn->ops[1]);
+ call_insn->ops[1] = temp_op;
+ gen_add_insn_before (ctx, call_insn, new_insn);
+ }
+ for (size_t i = start; i < nops; i++) {
+ arg_op = call_insn->ops[i];
+ gen_assert (arg_op.mode == MIR_OP_REG || arg_op.mode == MIR_OP_HARD_REG);
+ if (i - start < nargs) {
+ type = arg_vars[i - start].type;
+ } else {
+ mode = call_insn->ops[i].value_mode; // ??? smaller ints
+ gen_assert (mode == MIR_OP_INT || mode == MIR_OP_UINT || mode == MIR_OP_FLOAT
+ || mode == MIR_OP_DOUBLE || mode == MIR_OP_LDOUBLE);
+ if (mode == MIR_OP_FLOAT)
+ (*MIR_get_error_func (ctx)) (MIR_call_op_error,
+ "passing float variadic arg (should be passed as double)");
+ type = mode == MIR_OP_DOUBLE ? MIR_T_D : mode == MIR_OP_LDOUBLE ? MIR_T_LD : MIR_T_I64;
+ }
+ ext_insn = NULL;
+ if ((ext_code = get_ext_code (type)) != MIR_INVALID_INSN) { /* extend arg if necessary */
+ temp_op = MIR_new_reg_op (ctx, gen_new_temp_reg (ctx, MIR_T_I64, func));
+ ext_insn = MIR_new_insn (ctx, ext_code, temp_op, arg_op);
+ call_insn->ops[i] = arg_op = temp_op;
+ }
+ if ((arg_reg = get_arg_reg (type, &int_arg_num, &fp_arg_num, &new_insn_code))
+ != MIR_NON_HARD_REG) {
+ /* put arguments to argument hard regs */
+ if (ext_insn != NULL) gen_add_insn_before (ctx, call_insn, ext_insn);
+ arg_reg_op = _MIR_new_hard_reg_op (ctx, arg_reg);
+ new_insn = MIR_new_insn (ctx, new_insn_code, arg_reg_op, arg_op);
+ gen_add_insn_before (ctx, call_insn, new_insn);
+ call_insn->ops[i] = arg_reg_op;
+ } else { /* put arguments on the stack */
+ if (type == MIR_T_LD && mem_size % 16 != 0) mem_size = (mem_size + 15) / 16 * 16;
+ mem_type = type == MIR_T_F || type == MIR_T_D || type == MIR_T_LD ? type : MIR_T_I64;
+ new_insn_code
+ = (type == MIR_T_F ? MIR_FMOV
+ : type == MIR_T_D ? MIR_DMOV : type == MIR_T_LD ? MIR_LDMOV : MIR_MOV);
+ mem_op = _MIR_new_hard_reg_mem_op (ctx, mem_type, mem_size, SP_HARD_REG, MIR_NON_HARD_REG, 1);
+ new_insn = MIR_new_insn (ctx, new_insn_code, mem_op, arg_op);
+ gen_assert (prev_call_insn != NULL); /* call_insn should not be 1st after simplification */
+ MIR_insert_insn_after (ctx, curr_func_item, prev_call_insn, new_insn);
+ prev_insn = DLIST_PREV (MIR_insn_t, new_insn);
+ next_insn = DLIST_NEXT (MIR_insn_t, new_insn);
+ create_new_bb_insns (ctx, prev_insn, next_insn, call_insn);
+ call_insn->ops[i] = mem_op;
+ mem_size += type == MIR_T_LD ? 16 : 8;
+ if (ext_insn != NULL) gen_add_insn_after (ctx, prev_call_insn, ext_insn);
+ }
+ }
+ n_iregs = n_vregs = 0;
+ for (size_t i = 0; i < proto->nres; i++) {
+ int float_p;
+
+ ret_reg_op = call_insn->ops[i + 2];
+ gen_assert (ret_reg_op.mode == MIR_OP_REG || ret_reg_op.mode == MIR_OP_HARD_REG);
+ type = proto->res_types[i];
+ float_p = type == MIR_T_F || type == MIR_T_D || type == MIR_T_LD;
+ if (float_p && n_vregs < 8) {
+ new_insn
+ = MIR_new_insn (ctx, type == MIR_T_F ? MIR_FMOV : type == MIR_T_D ? MIR_DMOV : MIR_LDMOV,
+ ret_reg_op, _MIR_new_hard_reg_op (ctx, V0_HARD_REG + n_vregs));
+ n_vregs++;
+ } else if (!float_p && n_iregs < 8) {
+ new_insn = MIR_new_insn (ctx, MIR_MOV, ret_reg_op,
+ _MIR_new_hard_reg_op (ctx, R0_HARD_REG + n_iregs));
+ n_iregs++;
+ } else {
+ (*MIR_get_error_func (ctx)) (MIR_ret_error,
+ "aarch64 can not handle this combination of return values");
+ }
+ MIR_insert_insn_after (ctx, curr_func_item, call_insn, new_insn);
+ call_insn->ops[i + 2] = new_insn->ops[1];
+ if ((ext_code = get_ext_code (type)) != MIR_INVALID_INSN) {
+ MIR_insert_insn_after (ctx, curr_func_item, new_insn,
+ MIR_new_insn (ctx, ext_code, ret_reg_op, ret_reg_op));
+ new_insn = DLIST_NEXT (MIR_insn_t, new_insn);
+ }
+ create_new_bb_insns (ctx, call_insn, DLIST_NEXT (MIR_insn_t, new_insn), call_insn);
+ }
+ if (mem_size != 0) { /* allocate/deallocate stack for args passed on stack */
+ mem_size = (mem_size + 15) / 16 * 16; /* make it of several 16 bytes */
+ new_insn
+ = MIR_new_insn (ctx, MIR_SUB, _MIR_new_hard_reg_op (ctx, SP_HARD_REG),
+ _MIR_new_hard_reg_op (ctx, SP_HARD_REG), MIR_new_int_op (ctx, mem_size));
+ MIR_insert_insn_after (ctx, curr_func_item, prev_call_insn, new_insn);
+ next_insn = DLIST_NEXT (MIR_insn_t, new_insn);
+ create_new_bb_insns (ctx, prev_call_insn, next_insn, call_insn);
+ new_insn
+ = MIR_new_insn (ctx, MIR_ADD, _MIR_new_hard_reg_op (ctx, SP_HARD_REG),
+ _MIR_new_hard_reg_op (ctx, SP_HARD_REG), MIR_new_int_op (ctx, mem_size));
+ MIR_insert_insn_after (ctx, curr_func_item, call_insn, new_insn);
+ next_insn = DLIST_NEXT (MIR_insn_t, new_insn);
+ create_new_bb_insns (ctx, call_insn, next_insn, call_insn);
+ }
+}
+
+static long double mir_i2ld (int64_t i) { return i; }
+static const char *I2LD = "mir.i2ld";
+static const char *I2LD_P = "mir.i2ld.p";
+
+static long double mir_ui2ld (uint64_t i) { return i; }
+static const char *UI2LD = "mir.ui2ld";
+static const char *UI2LD_P = "mir.ui2ld.p";
+
+static long double mir_f2ld (float f) { return f; }
+static const char *F2LD = "mir.f2ld";
+static const char *F2LD_P = "mir.f2ld.p";
+
+static long double mir_d2ld (double d) { return d; }
+static const char *D2LD = "mir.d2ld";
+static const char *D2LD_P = "mir.d2ld.p";
+
+static int64_t mir_ld2i (long double ld) { return ld; }
+static const char *LD2I = "mir.ld2i";
+static const char *LD2I_P = "mir.ld2i.p";
+
+static float mir_ld2f (long double ld) { return ld; }
+static const char *LD2F = "mir.ld2f";
+static const char *LD2F_P = "mir.ld2f.p";
+
+static double mir_ld2d (long double ld) { return ld; }
+static const char *LD2D = "mir.ld2d";
+static const char *LD2D_P = "mir.ld2d.p";
+
+static long double mir_ldadd (long double d1, long double d2) { return d1 + d2; }
+static const char *LDADD = "mir.ldadd";
+static const char *LDADD_P = "mir.ldadd.p";
+
+static long double mir_ldsub (long double d1, long double d2) { return d1 - d2; }
+static const char *LDSUB = "mir.ldsub";
+static const char *LDSUB_P = "mir.ldsub.p";
+
+static long double mir_ldmul (long double d1, long double d2) { return d1 * d2; }
+static const char *LDMUL = "mir.ldmul";
+static const char *LDMUL_P = "mir.ldmul.p";
+
+static long double mir_lddiv (long double d1, long double d2) { return d1 / d2; }
+static const char *LDDIV = "mir.lddiv";
+static const char *LDDIV_P = "mir.lddiv.p";
+
+static long double mir_ldneg (long double d) { return -d; }
+static const char *LDNEG = "mir.ldneg";
+static const char *LDNEG_P = "mir.ldneg.p";
+
+static const char *VA_ARG_P = "mir.va_arg.p";
+static const char *VA_ARG = "mir.va_arg";
+
+static int64_t mir_ldeq (long double d1, long double d2) { return d1 == d2; }
+static const char *LDEQ = "mir.ldeq";
+static const char *LDEQ_P = "mir.ldeq.p";
+
+static int64_t mir_ldne (long double d1, long double d2) { return d1 != d2; }
+static const char *LDNE = "mir.ldne";
+static const char *LDNE_P = "mir.ldne.p";
+
+static int64_t mir_ldlt (long double d1, long double d2) { return d1 < d2; }
+static const char *LDLT = "mir.ldlt";
+static const char *LDLT_P = "mir.ldlt.p";
+
+static int64_t mir_ldge (long double d1, long double d2) { return d1 >= d2; }
+static const char *LDGE = "mir.ldge";
+static const char *LDGE_P = "mir.ldge.p";
+
+static int64_t mir_ldgt (long double d1, long double d2) { return d1 > d2; }
+static const char *LDGT = "mir.ldgt";
+static const char *LDGT_P = "mir.ldgt.p";
+
+static int64_t mir_ldle (long double d1, long double d2) { return d1 <= d2; }
+static const char *LDLE = "mir.ldle";
+static const char *LDLE_P = "mir.ldle.p";
+
+static int get_builtin (MIR_context_t ctx, MIR_insn_code_t code, MIR_item_t *proto_item,
+ MIR_item_t *func_import_item) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ MIR_type_t res_type;
+
+ *func_import_item = *proto_item = NULL; /* to remove uninitialized warning */
+ switch (code) {
+ case MIR_I2LD:
+ res_type = MIR_T_LD;
+ *proto_item
+ = _MIR_builtin_proto (ctx, curr_func_item->module, I2LD_P, 1, &res_type, 1, MIR_T_I64, "v");
+ *func_import_item = _MIR_builtin_func (ctx, curr_func_item->module, I2LD, mir_i2ld);
+ return 1;
+ case MIR_UI2LD:
+ res_type = MIR_T_LD;
+ *proto_item
+ = _MIR_builtin_proto (ctx, curr_func_item->module, UI2LD_P, 1, &res_type, 1, MIR_T_I64, "v");
+ *func_import_item = _MIR_builtin_func (ctx, curr_func_item->module, UI2LD, mir_ui2ld);
+ return 1;
+ case MIR_F2LD:
+ res_type = MIR_T_LD;
+ *proto_item
+ = _MIR_builtin_proto (ctx, curr_func_item->module, F2LD_P, 1, &res_type, 1, MIR_T_F, "v");
+ *func_import_item = _MIR_builtin_func (ctx, curr_func_item->module, F2LD, mir_f2ld);
+ return 1;
+ case MIR_D2LD:
+ res_type = MIR_T_LD;
+ *proto_item
+ = _MIR_builtin_proto (ctx, curr_func_item->module, D2LD_P, 1, &res_type, 1, MIR_T_D, "v");
+ *func_import_item = _MIR_builtin_func (ctx, curr_func_item->module, D2LD, mir_d2ld);
+ return 1;
+ case MIR_LD2I:
+ res_type = MIR_T_I64;
+ *proto_item
+ = _MIR_builtin_proto (ctx, curr_func_item->module, LD2I_P, 1, &res_type, 1, MIR_T_LD, "v");
+ *func_import_item = _MIR_builtin_func (ctx, curr_func_item->module, LD2I, mir_ld2i);
+ return 1;
+ case MIR_LD2F:
+ res_type = MIR_T_F;
+ *proto_item
+ = _MIR_builtin_proto (ctx, curr_func_item->module, LD2F_P, 1, &res_type, 1, MIR_T_LD, "v");
+ *func_import_item = _MIR_builtin_func (ctx, curr_func_item->module, LD2F, mir_ld2f);
+ return 1;
+ case MIR_LD2D:
+ res_type = MIR_T_D;
+ *proto_item
+ = _MIR_builtin_proto (ctx, curr_func_item->module, LD2D_P, 1, &res_type, 1, MIR_T_LD, "v");
+ *func_import_item = _MIR_builtin_func (ctx, curr_func_item->module, LD2D, mir_ld2d);
+ return 1;
+ case MIR_LDADD:
+ res_type = MIR_T_LD;
+ *proto_item = _MIR_builtin_proto (ctx, curr_func_item->module, LDADD_P, 1, &res_type, 2,
+ MIR_T_LD, "d1", MIR_T_LD, "d2");
+ *func_import_item = _MIR_builtin_func (ctx, curr_func_item->module, LDADD, mir_ldadd);
+ return 2;
+ case MIR_LDSUB:
+ res_type = MIR_T_LD;
+ *proto_item = _MIR_builtin_proto (ctx, curr_func_item->module, LDSUB_P, 1, &res_type, 2,
+ MIR_T_LD, "d1", MIR_T_LD, "d2");
+ *func_import_item = _MIR_builtin_func (ctx, curr_func_item->module, LDSUB, mir_ldsub);
+ return 2;
+ case MIR_LDMUL:
+ res_type = MIR_T_LD;
+ *proto_item = _MIR_builtin_proto (ctx, curr_func_item->module, LDMUL_P, 1, &res_type, 2,
+ MIR_T_LD, "d1", MIR_T_LD, "d2");
+ *func_import_item = _MIR_builtin_func (ctx, curr_func_item->module, LDMUL, mir_ldmul);
+ return 2;
+ case MIR_LDDIV:
+ res_type = MIR_T_LD;
+ *proto_item = _MIR_builtin_proto (ctx, curr_func_item->module, LDDIV_P, 1, &res_type, 2,
+ MIR_T_LD, "d1", MIR_T_LD, "d2");
+ *func_import_item = _MIR_builtin_func (ctx, curr_func_item->module, LDDIV, mir_lddiv);
+ return 2;
+ case MIR_LDNEG:
+ res_type = MIR_T_LD;
+ *proto_item
+ = _MIR_builtin_proto (ctx, curr_func_item->module, LDNEG_P, 1, &res_type, 1, MIR_T_LD, "d");
+ *func_import_item = _MIR_builtin_func (ctx, curr_func_item->module, LDNEG, mir_ldneg);
+ return 1;
+ case MIR_LDEQ:
+ res_type = MIR_T_I64;
+ *proto_item = _MIR_builtin_proto (ctx, curr_func_item->module, LDEQ_P, 1, &res_type, 2,
+ MIR_T_LD, "d1", MIR_T_LD, "d2");
+ *func_import_item = _MIR_builtin_func (ctx, curr_func_item->module, LDEQ, mir_ldeq);
+ return 2;
+ case MIR_LDNE:
+ res_type = MIR_T_I64;
+ *proto_item = _MIR_builtin_proto (ctx, curr_func_item->module, LDNE_P, 1, &res_type, 2,
+ MIR_T_LD, "d1", MIR_T_LD, "d2");
+ *func_import_item = _MIR_builtin_func (ctx, curr_func_item->module, LDNE, mir_ldne);
+ return 2;
+ case MIR_LDLT:
+ res_type = MIR_T_I64;
+ *proto_item = _MIR_builtin_proto (ctx, curr_func_item->module, LDLT_P, 1, &res_type, 2,
+ MIR_T_LD, "d1", MIR_T_LD, "d2");
+ *func_import_item = _MIR_builtin_func (ctx, curr_func_item->module, LDLT, mir_ldlt);
+ return 2;
+ case MIR_LDGE:
+ res_type = MIR_T_I64;
+ *proto_item = _MIR_builtin_proto (ctx, curr_func_item->module, LDGE_P, 1, &res_type, 2,
+ MIR_T_LD, "d1", MIR_T_LD, "d2");
+ *func_import_item = _MIR_builtin_func (ctx, curr_func_item->module, LDGE, mir_ldge);
+ return 2;
+ case MIR_LDGT:
+ res_type = MIR_T_I64;
+ *proto_item = _MIR_builtin_proto (ctx, curr_func_item->module, LDGT_P, 1, &res_type, 2,
+ MIR_T_LD, "d1", MIR_T_LD, "d2");
+ *func_import_item = _MIR_builtin_func (ctx, curr_func_item->module, LDGT, mir_ldgt);
+ return 2;
+ case MIR_LDLE:
+ res_type = MIR_T_I64;
+ *proto_item = _MIR_builtin_proto (ctx, curr_func_item->module, LDLE_P, 1, &res_type, 2,
+ MIR_T_LD, "d1", MIR_T_LD, "d2");
+ *func_import_item = _MIR_builtin_func (ctx, curr_func_item->module, LDLE, mir_ldle);
+ return 2;
+ case MIR_VA_ARG:
+ res_type = MIR_T_I64;
+ *proto_item = _MIR_builtin_proto (ctx, curr_func_item->module, VA_ARG_P, 1, &res_type, 2,
+ MIR_T_I64, "va", MIR_T_I64, "type");
+ *func_import_item = _MIR_builtin_func (ctx, curr_func_item->module, VA_ARG, va_arg_builtin);
+ return 2;
+ default: return 0;
+ }
+}
+
+static void gen_mov (MIR_context_t ctx, MIR_insn_t anchor, MIR_insn_code_t code, MIR_op_t dst_op,
+ MIR_op_t src_op) {
+ gen_add_insn_before (ctx, anchor, MIR_new_insn (ctx, code, dst_op, src_op));
+}
+
+DEF_VARR (int);
+DEF_VARR (uint8_t);
+DEF_VARR (uint64_t);
+
+struct insn_pattern_info {
+ int start, num;
+};
+
+typedef struct insn_pattern_info insn_pattern_info_t;
+DEF_VARR (insn_pattern_info_t);
+
+struct label_ref {
+ int abs_addr_p, short_p;
+ size_t label_val_disp;
+ MIR_label_t label;
+};
+
+typedef struct label_ref label_ref_t;
+DEF_VARR (label_ref_t);
+
+DEF_VARR (MIR_code_reloc_t);
+
+struct target_ctx {
+ unsigned char alloca_p, stack_arg_func_p, leaf_p;
+ VARR (int) * pattern_indexes;
+ VARR (insn_pattern_info_t) * insn_pattern_info;
+ VARR (uint8_t) * result_code;
+ VARR (label_ref_t) * label_refs;
+ VARR (uint64_t) * abs_address_locs;
+ VARR (MIR_code_reloc_t) * relocs;
+};
+
+#define alloca_p gen_ctx->target_ctx->alloca_p
+#define stack_arg_func_p gen_ctx->target_ctx->stack_arg_func_p
+#define leaf_p gen_ctx->target_ctx->leaf_p
+#define pattern_indexes gen_ctx->target_ctx->pattern_indexes
+#define insn_pattern_info gen_ctx->target_ctx->insn_pattern_info
+#define result_code gen_ctx->target_ctx->result_code
+#define label_refs gen_ctx->target_ctx->label_refs
+#define abs_address_locs gen_ctx->target_ctx->abs_address_locs
+#define relocs gen_ctx->target_ctx->relocs
+
+static MIR_disp_t target_get_stack_slot_offset (MIR_context_t ctx, MIR_type_t type,
+ MIR_reg_t slot) {
+ /* slot is 0, 1, ... */
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ size_t offset = curr_func_item->u.func->vararg_p || stack_arg_func_p ? 32 : 16;
+
+ return ((MIR_disp_t) slot * 8 + offset);
+}
+
+static void target_machinize (MIR_context_t ctx) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ MIR_func_t func;
+ MIR_type_t type, mem_type, res_type;
+ MIR_insn_code_t code, new_insn_code;
+ MIR_insn_t insn, next_insn, new_insn, anchor;
+ MIR_reg_t ret_reg, arg_reg;
+ MIR_op_t ret_reg_op, arg_reg_op, mem_op, prev_sp_op, temp_op;
+ size_t i, int_arg_num, fp_arg_num, mem_size;
+
+ assert (curr_func_item->item_type == MIR_func_item);
+ func = curr_func_item->u.func;
+ stack_arg_func_p = FALSE;
+ anchor = DLIST_HEAD (MIR_insn_t, func->insns);
+ for (i = int_arg_num = fp_arg_num = mem_size = 0; i < func->nargs; i++) {
+ /* Argument extensions is already done in simplify */
+ /* Prologue: generate arg_var = hard_reg|stack mem ... */
+ type = VARR_GET (MIR_var_t, func->vars, i).type;
+ arg_reg = get_arg_reg (type, &int_arg_num, &fp_arg_num, &new_insn_code);
+ if (arg_reg != MIR_NON_HARD_REG) {
+ arg_reg_op = _MIR_new_hard_reg_op (ctx, arg_reg);
+ gen_mov (ctx, anchor, new_insn_code, MIR_new_reg_op (ctx, i + 1), arg_reg_op);
+ } else {
+ /* arg is on the stack */
+ if (!stack_arg_func_p) {
+ stack_arg_func_p = TRUE;
+ prev_sp_op = _MIR_new_hard_reg_op (ctx, R8_HARD_REG);
+ gen_mov (ctx, anchor, MIR_MOV, prev_sp_op,
+ _MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, 16, FP_HARD_REG, MIR_NON_HARD_REG, 1));
+ }
+ mem_type = type == MIR_T_F || type == MIR_T_D || type == MIR_T_LD ? type : MIR_T_I64;
+ if (type == MIR_T_LD) mem_size = (mem_size + 15) / 16 * 16;
+ new_insn_code
+ = (type == MIR_T_F ? MIR_FMOV
+ : type == MIR_T_D ? MIR_DMOV : type == MIR_T_LD ? MIR_LDMOV : MIR_MOV);
+ mem_op = _MIR_new_hard_reg_mem_op (ctx, mem_type, mem_size, R8_HARD_REG, MIR_NON_HARD_REG, 1);
+ gen_mov (ctx, anchor, new_insn_code, MIR_new_reg_op (ctx, i + 1), mem_op);
+ mem_size += type == MIR_T_LD ? 16 : 8;
+ }
+ }
+ alloca_p = FALSE;
+ leaf_p = TRUE;
+ for (insn = DLIST_HEAD (MIR_insn_t, func->insns); insn != NULL; insn = next_insn) {
+ MIR_item_t proto_item, func_import_item;
+ int nargs;
+
+ next_insn = DLIST_NEXT (MIR_insn_t, insn);
+ code = insn->code;
+ if (code == MIR_LDBEQ || code == MIR_LDBNE || code == MIR_LDBLT || code == MIR_LDBGE
+ || code == MIR_LDBGT || code == MIR_LDBLE) {
+ temp_op = MIR_new_reg_op (ctx, gen_new_temp_reg (ctx, MIR_T_I64, func));
+ code = (code == MIR_LDBEQ
+ ? MIR_LDEQ
+ : code == MIR_LDBNE
+ ? MIR_LDNE
+ : code == MIR_LDBLT
+ ? MIR_LDLT
+ : code == MIR_LDBGE ? MIR_LDGE : code == MIR_LDBGT ? MIR_LDGT : MIR_LDLE);
+ new_insn = MIR_new_insn (ctx, code, temp_op, insn->ops[1], insn->ops[2]);
+ gen_add_insn_before (ctx, insn, new_insn);
+ next_insn = MIR_new_insn (ctx, MIR_BT, insn->ops[0], temp_op);
+ gen_add_insn_after (ctx, new_insn, next_insn);
+ gen_delete_insn (ctx, insn);
+ insn = new_insn;
+ }
+ if ((nargs = get_builtin (ctx, code, &proto_item, &func_import_item)) > 0) {
+ if (code == MIR_VA_ARG) { /* do nothing */
+ /* Use a builtin func call:
+ mov func_reg, func ref; mov flag_reg, ; call proto, func_reg, res_reg, va_reg,
+ flag_reg */
+ MIR_op_t ops[5], func_reg_op, flag_reg_op;
+ MIR_op_t res_reg_op = insn->ops[0], va_reg_op = insn->ops[1], mem_op = insn->ops[2];
+
+ assert (res_reg_op.mode == MIR_OP_REG && va_reg_op.mode == MIR_OP_REG
+ && mem_op.mode == MIR_OP_MEM);
+ func_reg_op = MIR_new_reg_op (ctx, gen_new_temp_reg (ctx, MIR_T_I64, func));
+ flag_reg_op = MIR_new_reg_op (ctx, gen_new_temp_reg (ctx, MIR_T_I64, func));
+ next_insn = new_insn
+ = MIR_new_insn (ctx, MIR_MOV, func_reg_op, MIR_new_ref_op (ctx, func_import_item));
+ gen_add_insn_before (ctx, insn, new_insn);
+ new_insn = MIR_new_insn (ctx, MIR_MOV, flag_reg_op,
+ MIR_new_int_op (ctx, (int64_t) mem_op.u.mem.type));
+ gen_add_insn_before (ctx, insn, new_insn);
+ ops[0] = MIR_new_ref_op (ctx, proto_item);
+ ops[1] = func_reg_op;
+ ops[2] = res_reg_op;
+ ops[3] = va_reg_op;
+ ops[4] = flag_reg_op;
+ new_insn = MIR_new_insn_arr (ctx, MIR_CALL, 5, ops);
+ gen_add_insn_before (ctx, insn, new_insn);
+ gen_delete_insn (ctx, insn);
+ } else { /* Use builtin: mov freg, func ref; call proto, freg, res_reg, op_reg[, op_reg2] */
+ MIR_op_t freg_op, res_reg_op = insn->ops[0], op_reg_op = insn->ops[1], ops[5];
+
+ assert (res_reg_op.mode == MIR_OP_REG && op_reg_op.mode == MIR_OP_REG);
+ freg_op = MIR_new_reg_op (ctx, gen_new_temp_reg (ctx, MIR_T_I64, func));
+ next_insn = new_insn
+ = MIR_new_insn (ctx, MIR_MOV, freg_op, MIR_new_ref_op (ctx, func_import_item));
+ gen_add_insn_before (ctx, insn, new_insn);
+ ops[0] = MIR_new_ref_op (ctx, proto_item);
+ ops[1] = freg_op;
+ ops[2] = res_reg_op;
+ ops[3] = op_reg_op;
+ if (nargs == 2) ops[4] = insn->ops[2];
+ new_insn = MIR_new_insn_arr (ctx, MIR_CALL, nargs + 3, ops);
+ gen_add_insn_before (ctx, insn, new_insn);
+ gen_delete_insn (ctx, insn);
+ }
+ } else if (code == MIR_VA_START) {
+ MIR_op_t treg_op = MIR_new_reg_op (ctx, gen_new_temp_reg (ctx, MIR_T_I64, func));
+ MIR_op_t prev_sp_op = MIR_new_reg_op (ctx, gen_new_temp_reg (ctx, MIR_T_I64, func));
+ MIR_op_t va_op = insn->ops[0];
+ MIR_reg_t va_reg;
+ int gp_offset, fp_offset;
+ MIR_var_t var;
+
+ assert (func->vararg_p && va_op.mode == MIR_OP_REG);
+ gp_offset = (int_arg_num >= 8 ? 0 : 8 * int_arg_num - 64);
+ fp_offset = (fp_arg_num >= 8 ? 0 : 16 * fp_arg_num - 128);
+ va_reg = va_op.u.reg;
+ /* Insns can be not simplified as soon as they match a machine insn. */
+ /* mem32[va_reg].__gr_offset = gp_offset; mem32[va_reg].__vr_offset = fp_offset */
+ gen_mov (ctx, insn, MIR_MOV, treg_op, MIR_new_int_op (ctx, gp_offset));
+ gen_mov (ctx, insn, MIR_MOV, MIR_new_mem_op (ctx, MIR_T_U32, 24, va_reg, 0, 1), treg_op);
+ gen_mov (ctx, insn, MIR_MOV, treg_op, MIR_new_int_op (ctx, fp_offset));
+ gen_mov (ctx, insn, MIR_MOV, MIR_new_mem_op (ctx, MIR_T_U32, 28, va_reg, 0, 1), treg_op);
+ /* __stack: prev_sp = mem64[fp + 16]; mem64[va_reg].__stack = prev_sp + mem_size */
+ gen_mov (ctx, insn, MIR_MOV, prev_sp_op,
+ _MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, 16, FP_HARD_REG, MIR_NON_HARD_REG, 1));
+ new_insn = MIR_new_insn (ctx, MIR_ADD, treg_op, prev_sp_op, MIR_new_int_op (ctx, mem_size));
+ gen_add_insn_before (ctx, insn, new_insn);
+ gen_mov (ctx, insn, MIR_MOV, MIR_new_mem_op (ctx, MIR_T_I64, 0, va_reg, 0, 1), treg_op);
+ /* __gr_top: mem64[va_reg].__gr_top = prev_sp */
+ gen_mov (ctx, insn, MIR_MOV, MIR_new_mem_op (ctx, MIR_T_I64, 8, va_reg, 0, 1), prev_sp_op);
+ /* __vr_top: treg = prev_sp - int_reg_save_area; mem64[va_reg].__vr_top = treg */
+ new_insn = MIR_new_insn (ctx, MIR_SUB, treg_op, prev_sp_op,
+ MIR_new_int_op (ctx, int_reg_save_area_size));
+ gen_add_insn_before (ctx, insn, new_insn);
+ gen_mov (ctx, insn, MIR_MOV, MIR_new_mem_op (ctx, MIR_T_I64, 16, va_reg, 0, 1), treg_op);
+ gen_delete_insn (ctx, insn);
+ } else if (code == MIR_VA_END) { /* do nothing */
+ gen_delete_insn (ctx, insn);
+ } else if (MIR_call_code_p (code)) {
+ machinize_call (ctx, insn);
+ leaf_p = FALSE;
+ } else if (code == MIR_ALLOCA) {
+ alloca_p = TRUE;
+ } else if (code == MIR_RET) {
+ /* In simplify we already transformed code for one return insn
+ and added extension insn (if any). */
+ uint32_t n_iregs = 0, n_vregs = 0;
+
+ assert (func->nres == MIR_insn_nops (ctx, insn));
+ for (size_t i = 0; i < func->nres; i++) {
+ assert (insn->ops[i].mode == MIR_OP_REG);
+ res_type = func->res_types[i];
+ if ((res_type == MIR_T_F || res_type == MIR_T_D || res_type == MIR_T_LD) && n_vregs < 8) {
+ new_insn_code
+ = res_type == MIR_T_F ? MIR_FMOV : res_type == MIR_T_D ? MIR_DMOV : MIR_LDMOV;
+ ret_reg = V0_HARD_REG + n_vregs++;
+ } else if (n_iregs < 8) {
+ new_insn_code = MIR_MOV;
+ ret_reg = R0_HARD_REG + n_iregs++;
+ } else {
+ (*MIR_get_error_func (ctx)) (MIR_ret_error,
+ "aarch64 can not handle this combination of return values");
+ }
+ ret_reg_op = _MIR_new_hard_reg_op (ctx, ret_reg);
+ gen_mov (ctx, insn, new_insn_code, ret_reg_op, insn->ops[i]);
+ insn->ops[i] = ret_reg_op;
+ }
+ }
+ }
+}
+
+static void isave (MIR_context_t ctx, MIR_insn_t anchor, int disp, MIR_reg_t hard_reg) {
+ gen_mov (ctx, anchor, MIR_MOV,
+ _MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, disp, SP_HARD_REG, MIR_NON_HARD_REG, 1),
+ _MIR_new_hard_reg_op (ctx, hard_reg));
+}
+
+static void fsave (MIR_context_t ctx, MIR_insn_t anchor, int disp, MIR_reg_t hard_reg) {
+ gen_mov (ctx, anchor, MIR_LDMOV,
+ _MIR_new_hard_reg_mem_op (ctx, MIR_T_LD, disp, SP_HARD_REG, MIR_NON_HARD_REG, 1),
+ _MIR_new_hard_reg_op (ctx, hard_reg));
+}
+
+static void target_make_prolog_epilog (MIR_context_t ctx, bitmap_t used_hard_regs,
+ size_t stack_slots_num) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ MIR_func_t func;
+ MIR_insn_t anchor, new_insn;
+ MIR_op_t sp_reg_op, fp_reg_op, treg_op;
+ int64_t start;
+ int save_prev_stack_p;
+ size_t i, offset, frame_size, frame_size_after_saved_regs, saved_iregs_num, saved_fregs_num;
+
+ assert (curr_func_item->item_type == MIR_func_item);
+ func = curr_func_item->u.func;
+ for (i = saved_iregs_num = saved_fregs_num = 0; i <= MAX_HARD_REG; i++)
+ if (!target_call_used_hard_reg_p (i) && bitmap_bit_p (used_hard_regs, i)) {
+ if (i < V0_HARD_REG)
+ saved_iregs_num++;
+ else
+ saved_fregs_num++;
+ }
+ if (leaf_p && !alloca_p && saved_iregs_num == 0 && saved_fregs_num == 0 && !func->vararg_p
+ && stack_slots_num == 0)
+ return;
+ sp_reg_op = _MIR_new_hard_reg_op (ctx, SP_HARD_REG);
+ fp_reg_op = _MIR_new_hard_reg_op (ctx, FP_HARD_REG);
+ /* Prologue: */
+ anchor = DLIST_HEAD (MIR_insn_t, func->insns);
+ frame_size = func->vararg_p ? reg_save_area_size : 0;
+ for (i = 0; i <= MAX_HARD_REG; i++)
+ if (!target_call_used_hard_reg_p (i) && bitmap_bit_p (used_hard_regs, i)) {
+ if (i < V0_HARD_REG) {
+ frame_size += 8;
+ } else {
+ if (frame_size % 16 != 0) frame_size = (frame_size + 15) / 16 * 16;
+ frame_size += 16;
+ }
+ }
+ if (frame_size % 16 != 0) frame_size = (frame_size + 15) / 16 * 16;
+ frame_size_after_saved_regs = frame_size;
+ frame_size += stack_slots_num * 8;
+ if (frame_size % 16 != 0) frame_size = (frame_size + 15) / 16 * 16;
+ save_prev_stack_p = func->vararg_p || stack_arg_func_p;
+ if (save_prev_stack_p) { /* prev stack pointer */
+ treg_op = _MIR_new_hard_reg_op (ctx, R9_HARD_REG);
+ gen_mov (ctx, anchor, MIR_MOV, treg_op, sp_reg_op);
+ frame_size += 16;
+ }
+ frame_size += 16; /* lr/fp */
+ new_insn = MIR_new_insn (ctx, MIR_SUB, sp_reg_op, sp_reg_op, MIR_new_int_op (ctx, frame_size));
+ gen_add_insn_before (ctx, anchor, new_insn); /* sp = sp - frame_size */
+ if (save_prev_stack_p)
+ gen_mov (ctx, anchor, MIR_MOV,
+ _MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, 16, SP_HARD_REG, MIR_NON_HARD_REG, 1),
+ treg_op); /* mem[sp + 16] = treg */
+ gen_mov (ctx, anchor, MIR_MOV,
+ _MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, 8, SP_HARD_REG, MIR_NON_HARD_REG, 1),
+ _MIR_new_hard_reg_op (ctx, LINK_HARD_REG)); /* mem[sp + 8] = lr */
+ gen_mov (ctx, anchor, MIR_MOV,
+ _MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, 0, SP_HARD_REG, MIR_NON_HARD_REG, 1),
+ _MIR_new_hard_reg_op (ctx, FP_HARD_REG)); /* mem[sp] = fp */
+ gen_mov (ctx, anchor, MIR_MOV, fp_reg_op, sp_reg_op); /* fp = sp */
+ if (func->vararg_p) {
+ start = (int64_t) frame_size - reg_save_area_size;
+ fsave (ctx, anchor, start, V0_HARD_REG);
+ fsave (ctx, anchor, start + 16, V1_HARD_REG);
+ fsave (ctx, anchor, start + 32, V2_HARD_REG);
+ fsave (ctx, anchor, start + 48, V3_HARD_REG);
+ fsave (ctx, anchor, start + 64, V4_HARD_REG);
+ fsave (ctx, anchor, start + 80, V5_HARD_REG);
+ fsave (ctx, anchor, start + 96, V6_HARD_REG);
+ fsave (ctx, anchor, start + 112, V7_HARD_REG);
+ isave (ctx, anchor, start + 128, R0_HARD_REG);
+ isave (ctx, anchor, start + 136, R1_HARD_REG);
+ isave (ctx, anchor, start + 144, R2_HARD_REG);
+ isave (ctx, anchor, start + 152, R3_HARD_REG);
+ isave (ctx, anchor, start + 160, R4_HARD_REG);
+ isave (ctx, anchor, start + 168, R5_HARD_REG);
+ isave (ctx, anchor, start + 176, R6_HARD_REG);
+ isave (ctx, anchor, start + 184, R7_HARD_REG);
+ }
+ /* Saving callee saved hard registers: */
+ offset = frame_size - frame_size_after_saved_regs;
+ for (i = 0; i <= MAX_HARD_REG; i++)
+ if (!target_call_used_hard_reg_p (i) && bitmap_bit_p (used_hard_regs, i)) {
+ if (i < V0_HARD_REG) {
+ gen_mov (ctx, anchor, MIR_MOV,
+ _MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, offset, FP_HARD_REG, MIR_NON_HARD_REG,
+ 1),
+ _MIR_new_hard_reg_op (ctx, i));
+ offset += 8;
+ } else {
+ if (offset % 16 != 0) offset = (offset + 15) / 16 * 16;
+ gen_mov (ctx, anchor, MIR_LDMOV,
+ _MIR_new_hard_reg_mem_op (ctx, MIR_T_LD, offset, FP_HARD_REG, MIR_NON_HARD_REG, 1),
+ _MIR_new_hard_reg_op (ctx, i));
+ offset += 16;
+ }
+ }
+ /* Epilogue: */
+ anchor = DLIST_TAIL (MIR_insn_t, func->insns);
+ assert (anchor->code == MIR_RET);
+ /* Restoring hard registers: */
+ offset = frame_size - frame_size_after_saved_regs;
+ for (i = 0; i <= MAX_HARD_REG; i++)
+ if (!target_call_used_hard_reg_p (i) && bitmap_bit_p (used_hard_regs, i)) {
+ if (i < V0_HARD_REG) {
+ gen_mov (ctx, anchor, MIR_MOV, _MIR_new_hard_reg_op (ctx, i),
+ _MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, offset, FP_HARD_REG, MIR_NON_HARD_REG,
+ 1));
+ offset += 8;
+ } else {
+ if (offset % 16 != 0) offset = (offset + 15) / 16 * 16;
+ gen_mov (ctx, anchor, MIR_LDMOV, _MIR_new_hard_reg_op (ctx, i),
+ _MIR_new_hard_reg_mem_op (ctx, MIR_T_LD, offset, FP_HARD_REG, MIR_NON_HARD_REG,
+ 1));
+ offset += 16;
+ }
+ }
+ /* Restore lr, sp, fp */
+ gen_mov (ctx, anchor, MIR_MOV, _MIR_new_hard_reg_op (ctx, LINK_HARD_REG),
+ _MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, 8, FP_HARD_REG, MIR_NON_HARD_REG, 1));
+ new_insn = MIR_new_insn (ctx, MIR_ADD, sp_reg_op, fp_reg_op, MIR_new_int_op (ctx, frame_size));
+ gen_add_insn_before (ctx, anchor, new_insn); /* sp = fp + frame_size */
+ gen_mov (ctx, anchor, MIR_MOV, fp_reg_op,
+ _MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, 0, FP_HARD_REG, MIR_NON_HARD_REG, 1));
+}
+
+struct pattern {
+ MIR_insn_code_t code;
+ /* Pattern elements:
+ blank - ignore
+ X - match everything
+ $ - finish successfully matching
+ r - register
+ h[0-63] - hard register with given number
+
+ memory with indexed reg offset:
+ m[0-3] - int (signed or unsigned) type memory of size 8,16,32,64-bits
+ ms[0-3] - signed int type memory of size 8,16,32,64-bits
+ mu[0-3] - unsigned int type memory of size 8,16,32,64-bits
+ option(field[13..15]) == 011 -- shifted reg (Rm=R31 means SP)
+ option == 010 (UXTW), 110 (SXTW), 111 (SXTX) -- extended reg (RM=R31 means ZR)
+ we use option == 111 only for non-index mem and 011 for indexed memory
+
+ memory with immediate offset:
+ M[0-3] - int (signed or unsigned) type memory of size 8,16,32,64-bits
+ Ms[0-3] - signed int type memory of size 8,16,32,64-bits
+ Mu[0-3] - unsigned int type memory of size 8,16,32,64-bits
+ zero extended scaled 12-bit offset (field[10..21])
+
+ N[0-2] - 2nd immediate (or reference) operand can be created by movn and n movk insns
+ Z[0-2] - 2nd immediate (or reference) operand can be created by movz and n movk insns
+ Z3 - any 2nd 64-bit immediate (or reference) operand
+
+ Zf - floating point 0.0
+ Zd - double floating point 0.0
+
+ memory with indexed reg offset:
+ mf - memory of float
+ md - memory of double
+ mld - memory of long double
+
+ memory with immediate offset:
+ Mf - memory of float
+ Md - memory of double
+ Mld - memory of long double
+ I -- immediate as 3th op for arithemtic insn (12-bit unsigned with possible 12-bit LSL)
+ Iu -- immediate for arithemtic insn roundup to 16
+ SR -- any immediate for right 64-bit shift (0-63)
+ Sr -- any immediate for right 32-bit shift (0-31)
+ SL -- any immediate for left 64-bit shift (0-63)
+ Sl -- any immediate for left 32-bit shift (0-31)
+ L - reference or label as the 1st or 2nd op which can be present by signed 26-bit pc offset (in
+ 4 insn bytes) l - label as the 1st op which can be present by signed 19-bit pc offset (in 4
+ insn bytes)
+
+ Remember we have no float or (long) double immediate at this stage. They are represented
+ by a reference to data item. */
+
+ const char *pattern;
+ /* Replacement elements:
+ blank - ignore
+ ; - insn separation
+ hex:hex - opcode and its mask (the mask should include opcode, the mask defines bits
+ which can not be changed by other fields)
+ rd[0-2] - put n-th operand register into rd field [0..4]
+ rn[0-2] - put n-th operand register into rn field [5..9]
+ rm[0-2] - put n-th operand register into rm field [16..20]
+ ra[0-2] - put n-th operand register into ra field [10..14]
+ h(d,n,m) - hardware register with given number in rd,rn,rm field
+ m = 1st or 2nd operand is (8-,16-,32-,64-bit) mem with base, scaled index
+ M = 1st or 2nd operand is (8-,16-,32-,64-bit) mem with base, scaled imm12 disp [10..21]
+ S - immr[16..21] for right shift SR/Sr
+ SL, Sl - immr[16..21] and imms[10..15] for left shift SL/Sl
+
+ Z[0-3] -- n-th 16-bit immediate[5..20] from Z[0-3] and its shift [21..22]
+ N[0-3] -- n-th 16-bit immediate[5..20] from N[0-3] and its shift [21..22]
+ I -- arithmetic op 12-bit immediate [10..21] and its shift [22..23]
+ Iu -- arithmetic op immediate [10..21] got from roundup value to 16 and its shift [22..23]
+ L -- operand-label as 26-bit offset
+ l -- operand-label as 19-bit offset
+ T -- pc-relative address [5..23]
+ */
+ const char *replacement;
+};
+
+static const struct pattern patterns[] = {
+ {MIR_MOV, "r h31", "91000000:fffffc00 rd0 hn1f"}, /* mov Rd,SP */
+ {MIR_MOV, "h31 r", "91000000:fffffc00 hd1f rn1"}, /* mov SP,Rn */
+ {MIR_MOV, "r r", "aa0003e0:ffe0ffe0 rd0 rm1"}, /* mov Rd,Rm */
+
+ // ??? patterns to extend 32-bit index register
+ {MIR_MOV, "r m3", "f8600800:ffe00c00 rd0 m"}, /* ldr Rd,[Rn,Rm{,#3}] */
+ {MIR_MOV, "m3 r", "f8200800:ffe00c00 rd1 m"}, /* str Rd,[Rn,Rm{,#3}] */
+ {MIR_MOV, "r M3", "f9400000:ffc00000 rd0 M"}, /* ldr Rd,[Rn,{,#imm12}] */
+ {MIR_MOV, "M3 r", "f9000000:ffc00000 rd1 M"}, /* str Rd,[Rn,Rm{,#imm12}] */
+
+ {MIR_MOV, "r mu2", "b8600800:ffe00c00 rd0 m"}, /* ldr Wd,[Rn,Rm{,#2}] */
+ {MIR_MOV, "m2 r", "b8200800:ffe00c00 rd1 m"}, /* str Wd,[Rn,Rm{,#2}] */
+ {MIR_MOV, "r Mu2", "b9400000:ffc00000 rd0 M"}, /* ldr Wd,[Rn{,#imm12}] */
+ {MIR_MOV, "M2 r", "b9000000:ffc00000 rd1 M"}, /* str Wd,[Rn,Rm{,#imm12}] */
+
+ {MIR_MOV, "r ms2", "b8a00800:ffe00c00 rd0 m"}, /* ldrsw Rd,[Rn,Rm{,#2}] */
+ {MIR_MOV, "r Ms2", "b9800000:ffc00000 rd0 M"}, /* ldrsw Rd,[Rn{,#imm12}] */
+
+ {MIR_MOV, "r mu1", "78600800:ffe00c00 rd0 m"}, /* ldrh Wd,[Rn,Rm{,#1}] */
+ {MIR_MOV, "m1 r", "78200800:ffe00c00 rd1 m"}, /* strh Wd,[Rn,Rm{,#1}] */
+ {MIR_MOV, "r Mu1", "79400000:ffc00000 rd0 M"}, /* ldrh Wd,[Rn{,#imm12}] */
+ {MIR_MOV, "M1 r", "79000000:ffc00000 rd1 M"}, /* strh Wd,[Rn,Rm{,#imm12}] */
+
+ {MIR_MOV, "r ms1", "78a00800:ffe00c00 rd0 m"}, /* ldrsh Wd,[Rn,Rm{,#2}] */
+ {MIR_MOV, "r Ms1", "79800000:ffc00000 rd0 M"}, /* ldrsh Wd,[Rn{,#imm12}] */
+
+ {MIR_MOV, "r mu0", "38600800:ffe00c00 rd0 m"}, /* ldrb Wd,[Rn,Rm{,#1}] */
+ {MIR_MOV, "m0 r", "38200800:ffe00c00 rd1 m"}, /* strb Wd,[Rn,Rm{,#1}] */
+ {MIR_MOV, "r Mu0", "39400000:ffc00000 rd0 M"}, /* ldrb Wd,[Rn{,#imm12}] */
+ {MIR_MOV, "M0 r", "39000000:ffc00000 rd1 M"}, /* strb Wd,[Rn,Rm{,#imm12}] */
+
+ {MIR_MOV, "r ms0", "38a00800:ffa00c00 rd0 m"}, /* ldrsb Rd,[Rn,Rm{,#1}] */
+ {MIR_MOV, "r Ms0", "39800000:ffc00000 rd0 M"}, /* ldrsb Rd,[Rn{,#imm12}] */
+
+ {MIR_MOV, "r Z0", "d2800000:ff800000 rd0 Z0"}, /* movz Rd, imm */
+ {MIR_MOV, "r N0", "92800000:ff800000 rd0 N0"}, /* movn Rd, imm */
+ /* movn Rd, imm0, sh0; movk Rd, imm1, sh1: */
+ {MIR_MOV, "r Z1", "d2800000:ff800000 rd0 Z0; f2800000:ff800000 rd0 Z1"},
+ /* movn imm0, sh0; movk Rd, imm1, sh1: */
+ {MIR_MOV, "r N1", "92800000:ff800000 rd0 N0; f2800000:ff800000 rd0 N1"},
+ /* movz Rd, imm0, sh0; movk Rd, imm1, sh1; movk Rd, imm3, sh3: */
+ {MIR_MOV, "r Z2", "d2800000:ff800000 rd0 Z0; f2800000:ff800000 rd0 Z1; f2800000:ff800000 rd0 Z2"},
+ /* movn Rd, imm0, sh0; movk Rd, imm1, sh1; movk Rd, imm3, sh3: */
+ {MIR_MOV, "r N2", "92800000:ff800000 rd0 N0; f2800000:ff800000 rd0 N1; f2800000:ff800000 rd0 N2"},
+ /* movz Rd, imm0, sh0; movk Rd, imm1, sh1; movk Rd, imm2, sh2; movk Rd, imm3, sh3: */
+ {MIR_MOV, "r Z3",
+ "d2800000:ff800000 rd0 Z0; f2800000:ff800000 rd0 Z1; f2800000:ff800000 rd0 Z2;"
+ "f2800000:ff800000 rd0 Z3"},
+
+ {MIR_FMOV, "r r", "1e204000:fffffc00 vd0 vn1"}, /* fmov Sd,Sn */
+ {MIR_FMOV, "r mf", "bc600800:ff600c00 vd0 m"}, /* ldr Sd,[Rn,Rm{,#2}] */
+ {MIR_FMOV, "mf r", "bc200800:ff600c00 vd1 m"}, /* str Sd,[Rn,Rm{,#2}] */
+ {MIR_FMOV, "r Mf", "bd400000:ffc00000 vd0 M"}, /* ldr Sd,[Rn,{,#imm12}] */
+ {MIR_FMOV, "Mf r", "bd000000:ffc00000 vd1 M"}, /* str Sd,[Rn,Rm{,#imm12}] */
+
+ {MIR_DMOV, "r r", "1e604000:fffffc00 vd0 vn1"}, /* fmov Dd,Dn */
+ {MIR_DMOV, "r md", "fc600800:ff600c00 vd0 m"}, /* ldr Dd,[Rn,Rm{,#3}] */
+ {MIR_DMOV, "md r", "fc200800:ff600c00 vd1 m"}, /* str Dd,[Rn,Rm{,#3}] */
+ {MIR_DMOV, "r Md", "fd400000:ffc00000 vd0 M"}, /* ldr Dd,[Rn,{,#imm12}] */
+ {MIR_DMOV, "Md r", "fd000000:ffc00000 vd1 M"}, /* str Dd,[Rn,Rm{,#imm12}] */
+
+ {MIR_LDMOV, "r r", "4ea01c00:ffe0fc00 vd0 vm1 vn1"}, /* orr Qd.16b,Qm.16b,Qn.16b */
+ {MIR_LDMOV, "r mld", "3ce00800:ffe00c00 vd0 m"}, /* ldr Qd,[Rn,Rm{,#4}] */
+ {MIR_LDMOV, "mld r", "3ca00800:ffe00c00 vd1 m"}, /* str Qd,[Rn,Rm{,#4}] */
+ {MIR_LDMOV, "r Mld", "3dc00000:ffc00000 vd0 M"}, /* ldr Qd,[Rn,{,#imm12}] */
+ {MIR_LDMOV, "Mld r", "3d800000:ffc00000 vd1 M"}, /* str Qd,[Rn,Rm{,#imm12}] */
+
+ {MIR_EXT8, "r r", "93401c00:fffffc00 rd0 rn1"}, /* sxtb rd, wn */
+ {MIR_EXT16, "r r", "93403c00:fffffc00 rd0 rn1"}, /* sxth rd, wn */
+ {MIR_EXT32, "r r", "93407c00:fffffc00 rd0 rn1"}, /* sxtw rd, wn */
+
+ {MIR_UEXT8, "r r", "53001c00:fffffc00 rd0 rn1"}, /* uxtb wd, wn */
+ {MIR_UEXT16, "r r", "53003c00:fffffc00 rd0 rn1"}, /* uxth wd, wn */
+ {MIR_UEXT32, "r r", "2a0003e0:7fe0ffe0 rd0 rm1"}, /* mov wd, wm */
+
+ // ??? add extended reg insns:
+ {MIR_ADD, "r r r", "8b000000:ff200000 rd0 rn1 rm2"}, /* add Rd,Rn,Rm*/
+ {MIR_ADD, "r r I", "91000000:ff000000 rd0 rn1 I"}, /* add Rd,Rn,I,shift */
+ {MIR_ADDS, "r r r", "0b000000:ff200000 rd0 rn1 rm2"}, /* add Wd,Wn,Wm*/
+ {MIR_ADDS, "r r I", "11000000:ff000000 rd0 rn1 I"}, /* add Wd,Wn,I,shift */
+ {MIR_FADD, "r r r", "1e202800:ffe0fc00 vd0 vn1 vm2"}, /* fadd Sd,Sn,Sm*/
+ {MIR_DADD, "r r r", "1e602800:ffe0fc00 vd0 vn1 vm2"}, /* fadd Dd,Dn,Dm*/
+ // ldadd is implemented through builtin
+
+ {MIR_SUB, "r r r", "cb000000:ff200000 rd0 rn1 rm2"}, /* sub Rd,Rn,Rm*/
+ {MIR_SUB, "r r I", "d1000000:ff000000 rd0 rn1 I"}, /* sub Rd,Rn,I,shift */
+ {MIR_SUBS, "r r r", "4b000000:ff200000 rd0 rn1 rm2"}, /* sub Wd,Wn,Wm*/
+ {MIR_SUBS, "r r I", "51000000:ff000000 rd0 rn1 I"}, /* sub Wd,Wn,I,shift */
+ {MIR_FSUB, "r r r", "1e203800:ffe0fc00 vd0 vn1 vm2"}, /* fsub Sd,Sn,Sm*/
+ {MIR_DSUB, "r r r", "1e603800:ffe0fc00 vd0 vn1 vm2"}, /* fsub Dd,Dn,Dm*/
+ // ldsub is implemented through builtin
+
+ {MIR_MUL, "r r r", "9b007c00:ffe0fc00 rd0 rn1 rm2"}, /* mul Rd,Rn,Rm*/
+ {MIR_MULS, "r r r", "1b007c00:ffe0fc00 rd0 rn1 rm2"}, /* mul Wd,Wn,Wm*/
+ {MIR_FMUL, "r r r", "1e200800:ffe0fc00 vd0 vn1 vm2"}, /* fmul Sd,Sn,Sm*/
+ {MIR_DMUL, "r r r", "1e600800:ffe0fc00 vd0 vn1 vm2"}, /* fmul Dd,Dn,Dm*/
+ // ldmul is implemented through builtin
+
+ {MIR_DIV, "r r r", "9ac00c00:ffe0fc00 rd0 rn1 rm2"}, /* sdiv Rd,Rn,Rm*/
+ {MIR_DIVS, "r r r", "1ac00c00:ffe0fc00 rd0 rn1 rm2"}, /* sdiv Wd,Wn,Wm*/
+ {MIR_UDIV, "r r r", "9ac00800:ffe0fc00 rd0 rn1 rm2"}, /* udiv Rd,Rn,Rm*/
+ {MIR_UDIVS, "r r r", "1ac00800:ffe0fc00 rd0 rn1 rm2"}, /* udiv Wd,Wn,Wm*/
+ {MIR_FDIV, "r r r", "1e201800:ffe0fc00 vd0 vn1 vm2"}, /* fdiv Sd,Sn,Sm*/
+ {MIR_DDIV, "r r r", "1e601800:ffe0fc00 vd0 vn1 vm2"}, /* fmul Dd,Dn,Dm*/
+ // lddiv is implemented through builtin
+
+ /* sdiv r8,Rn,Rm;msub Rd,r8,Rm,Rn: */
+ {MIR_MOD, "r r r", "9ac00c00:ffe0fc00 hd8 rn1 rm2;9b008000:ffe08000 rd0 hm8 rn2 ra1"},
+ /* sdiv r8,Wn,Wm;msub Wd,r8,Wm,Wn: */
+ {MIR_MODS, "r r r", "1ac00c00:ffe0fc00 hd8 rn1 rm2;1b008000:ffe08000 rd0 hm8 rn2 ra1"},
+ /* udiv r8,Rn,Rm;msub Rd,r8,Rm,Rn: */
+ {MIR_UMOD, "r r r", "9ac00800:ffe0fc00 hd8 rn1 rm2;9b008000:ffe08000 rd0 hm8 rn2 ra1"},
+ /* udiv r8,Wn,Wm;msub Wd,r8,Wm,Wn: */
+ {MIR_UMODS, "r r r", "1ac00800:ffe0fc00 hd8 rn1 rm2;1b008000:ffe08000 rd0 hm8 rn2 ra1"},
+
+#define CMPR "eb00001f:ff20001f rn1 rm2"
+#define CMPI "f100001f:ff00001f rn1 I"
+#define SCMPR "6b00001f:ff20001f rn1 rm2"
+#define SCMPI "7100001f:ff00001f rn1 I"
+#define FCMP "1e202010:ffe0fc1f vn1 vm2"
+#define DCMP "1e602010:ffe0fc1f vn1 vm2"
+
+#define REQ "9a9f17e0:ffffffe0 rd0"
+#define REQS "1a9f17e0:ffffffe0 rd0"
+ // ??? add extended reg cmp insns:
+ // all ld insn are changed to builtins
+ /* cmp Rn,Rm; cset Rd,eq */
+ {MIR_EQ, "r r r", CMPR "; " REQ},
+ /* cmp Rn,I,shift ; cset Wd,eq */
+ {MIR_EQ, "r r I", CMPI "; " REQ},
+ /* cmp Wn,Wm;cset Rd,eq */
+ {MIR_EQS, "r r r", SCMPR "; " REQS},
+ /* cmp Wn,I,shift; cset Wd,eq */
+ {MIR_EQS, "r r I", SCMPI "; " REQS},
+ /* fcmpe Sn,Sm; cset Rd,mi */
+ {MIR_FEQ, "r r r", FCMP "; " REQ},
+ /* fcmpe Dn,Dm; cset Rd,mi */
+ {MIR_DEQ, "r r r", DCMP "; " REQ},
+ /* fcmpe Sn,0.0; cset Rd,mi */
+ {MIR_FEQ, "r r Zf", "1e202018:fffffc1f vn1 vm2; " REQ},
+ /* fcmpe Dn,0.0; cset Rd,mi */
+ {MIR_DEQ, "r r Zd", "1e602018:fffffc1f vn1 vm2; " REQ},
+
+#define RNE "9a9f07e0:ffffffe0 rd0"
+#define RNES "1a9f07e0:ffffffe0 rd0"
+ /* cmp Rn,Rm; cset Rd,ne */
+ {MIR_NE, "r r r", CMPR "; " RNE},
+ /* cmp Rn,I,shift ; cset Wd,ne */
+ {MIR_NE, "r r I", CMPI "; " RNE},
+ /* cmp Wn,Wm;cset Rd,ne */
+ {MIR_NES, "r r r", SCMPR "; " RNES},
+ /* cmp Wn,I,shift; cset Wd,ne */
+ {MIR_NES, "r r I", SCMPI "; " RNES},
+ /* fcmpe Sn,Sm; cset Rd,ne */
+ {MIR_FNE, "r r r", FCMP "; " RNE},
+ /* fcmpe Dn,Dm; cset Rd,ne */
+ {MIR_DNE, "r r r", DCMP "; " RNE},
+ /* fcmpe Sn,0.0; cset Rd,ne */
+ {MIR_FNE, "r r Zf", "1e202018:fffffc1f vn1 vm2; " RNE},
+ /* fcmpe Dn,0.0; cset Rd,ne */
+ {MIR_DNE, "r r Zd", "1e602018:fffffc1f vn1 vm2; " RNE},
+
+#define RLT "9a9fa7e0:ffffffe0 rd0"
+#define RLTS "1a9fa7e0:ffffffe0 rd0"
+#define RULT "9a9f27e0:ffffffe0 rd0"
+#define RULTS "1a9f27e0:ffffffe0 rd0"
+#define FLT "9a9f57e0:ffffffe0 rd0"
+ /* cmp Rn,Rm; cset Rd,lt */
+ {MIR_LT, "r r r", CMPR "; " RLT},
+ /* cmp Rn,I,shift ; cset Wd,lt */
+ {MIR_LT, "r r I", CMPI "; " RLT},
+ /* cmp Wn,Wm;cset Rd,lt */
+ {MIR_LTS, "r r r", SCMPR "; " RLTS},
+ /* cmp Wn,I,shift; cset Wd,lt */
+ {MIR_LTS, "r r I", SCMPI "; " RLTS},
+ /* cmp Rn,Rm; cset Rd,ult */
+ {MIR_ULT, "r r r", CMPR "; " RULT},
+ /* cmp Rn,I,shift ; cset Wd,cc */
+ {MIR_ULT, "r r I", CMPI "; " RULT},
+ /* cmp Wn,Wm;cset Rd,cc */
+ {MIR_ULTS, "r r r", SCMPR "; " RULTS},
+ /* cmp Wn,I,shift; cset Wd,cc */
+ {MIR_ULTS, "r r I", SCMPI "; " RULTS},
+ /* fcmpe Sn,Sm; cset Rd,mi */
+ {MIR_FLT, "r r r", FCMP "; " FLT},
+ /* fcmpe Dn,Dm; cset Rd,mi */
+ {MIR_DLT, "r r r", DCMP "; " FLT},
+ /* fcmpe Sn,0.0; cset Rd,mi */
+ {MIR_FLT, "r r Zf", "1e202018:fffffc1f vn1 vm2; " FLT},
+ /* fcmpe Dn,0.0; cset Rd,mi */
+ {MIR_DLT, "r r Zd", "1e602018:fffffc1f vn1 vm2; " FLT},
+
+#define RGE "9a9fb7e0:ffffffe0 rd0"
+#define RGES "1a9fb7e0:ffffffe0 rd0"
+#define RUGE "9a9f37e0:ffffffe0 rd0"
+#define RUGES "1a9f37e0:ffffffe0 rd0"
+ /* cmp Rn,Rm; cset Rd,ge */
+ {MIR_GE, "r r r", CMPR "; " RGE},
+ /* cmp Rn,I,shift ; cset Wd,ge */
+ {MIR_GE, "r r I", CMPI "; " RGE},
+ /* cmp Wn,Wm;cset Rd,ge */
+ {MIR_GES, "r r r", SCMPR "; " RGES},
+ /* cmp Wn,I,shift; cset Wd,ge */
+ {MIR_GES, "r r I", SCMPI "; " RGES},
+ /* cmp Rn,Rm; cset Rd,cs */
+ {MIR_UGE, "r r r", CMPR "; " RUGE},
+ /* cmp Rn,I,shift ; cset Wd,cs */
+ {MIR_UGE, "r r I", CMPI "; " RUGE},
+ /* cmp Wn,Wm;cset Rd,cs */
+ {MIR_UGES, "r r r", SCMPR "; " RUGES},
+ /* cmp Wn,I,shift; cset Wd,cs */
+ {MIR_UGES, "r r I", SCMPI "; " RUGES},
+ /* fcmpe Sn,Sm; cset Rd,ge */
+ {MIR_FGE, "r r r", FCMP "; " RGE},
+ /* fcmpe Dn,Dm; cset Rd,ge */
+ {MIR_DGE, "r r r", DCMP "; " RGE},
+ /* fcmpe Sn,0.0; cset Rd,ge */
+ {MIR_FGE, "r r Zf", "1e202018:fffffc1f vn1 vm2; " RGE},
+ /* fcmpe Dn,0.0; cset Rd,ge */
+ {MIR_DGE, "r r Zd", "1e602018:fffffc1f vn1 vm2; " RGE},
+
+#define RGT "9a9fd7e0:ffffffe0 rd0"
+#define RGTS "1a9fd7e0:ffffffe0 rd0"
+#define RUGT "9a9f97e0:ffffffe0 rd0"
+#define RUGTS "1a9f97e0:ffffffe0 rd0"
+ /* cmp Rn,Rm; cset Rd,gt */
+ {MIR_GT, "r r r", CMPR "; " RGT},
+ /* cmp Rn,I,shift ; cset Wd,gt */
+ {MIR_GT, "r r I", CMPI "; " RGT},
+ /* cmp Wn,Wm;cset Rd,gt */
+ {MIR_GTS, "r r r", SCMPR "; " RGTS},
+ /* cmp Wn,I,shift; cset Wd,gt */
+ {MIR_GTS, "r r I", SCMPI "; " RGTS},
+ /* cmp Rn,Rm; cset Rd,hi */
+ {MIR_UGT, "r r r", CMPR "; " RUGT},
+ /* cmp Rn,I,shift ; cset Wd,hi */
+ {MIR_UGT, "r r I", CMPI "; " RUGT},
+ /* cmp Wn,Wm;cset Rd,hi */
+ {MIR_UGTS, "r r r", SCMPR "; " RUGTS},
+ /* cmp Wn,I,shift; cset Wd,hi */
+ {MIR_UGTS, "r r I", SCMPI "; " RUGTS},
+ /* fcmpe Sn,Sm; cset Rd,gt */
+ {MIR_FGT, "r r r", FCMP "; " RGT},
+ /* fcmpe Dn,Dm; cset Rd,gt */
+ {MIR_DGT, "r r r", DCMP "; " RGT},
+ /* fcmpe Sn,0.0; cset Rd,gt */
+ {MIR_FGT, "r r Zf", "1e202018:fffffc1f vn1 vm2; " RGT},
+ /* fcmpe Dn,0.0; cset Rd,gt */
+ {MIR_DGT, "r r Zd", "1e602018:fffffc1f vn1 vm2; " RGT},
+
+#define RLE "9a9fc7e0:ffffffe0 rd0"
+#define RLES "1a9fc7e0:ffffffe0 rd0"
+#define RULE "9a9f87e0:ffffffe0 rd0"
+#define RULES "1a9f87e0:ffffffe0 rd0"
+#define FLE "9a9f87e0:ffffffe0 rd0"
+ /* cmp Rn,Rm; cset Rd,le */
+ {MIR_LE, "r r r", CMPR "; " RLE},
+ /* cmp Rn,I,shift ; cset Wd,le */
+ {MIR_LE, "r r I", CMPI "; " RLE},
+ /* cmp Wn,Wm;cset Rd,le */
+ {MIR_LES, "r r r", SCMPR "; " RLES},
+ /* cmp Wn,I,shift; cset Wd,le */
+ {MIR_LES, "r r I", SCMPI "; " RLES},
+ /* cmp Rn,Rm; cset Rd,ls */
+ {MIR_ULE, "r r r", CMPR "; " RULE},
+ /* cmp Rn,I,shift ; cset Wd,ls */
+ {MIR_ULE, "r r I", CMPI "; " RULE},
+ /* cmp Wn,Wm;cset Rd,ls */
+ {MIR_ULES, "r r r", SCMPR "; " RULES},
+ /* cmp Wn,I,shift; cset Wd,ls */
+ {MIR_ULES, "r r I", SCMPI "; " RULES},
+ /* fcmpe Sn,Sm; cset Rd,ls */
+ {MIR_FLE, "r r r", FCMP "; " FLE},
+ /* fcmpe Dn,Dm; cset Rd,ls */
+ {MIR_DLE, "r r r", DCMP "; " FLE},
+ /* fcmpe Sn,0.0; cset Rd,ls */
+ {MIR_FLE, "r r Zf", "1e202018:fffffc1f vn1 vm2; " FLE},
+ /* fcmpe Dn,0.0; cset Rd,ls */
+ {MIR_DLE, "r r Zd", "1e602018:fffffc1f vn1 vm2; " FLE},
+
+ {MIR_JMP, "L", "14000000:fc000000 L"}, /* 26-bit offset jmp */
+
+ {MIR_BT, "l r", "b5000000:ff000000 rd1 l"}, /* cbnz rd,l */
+ {MIR_BTS, "l r", "35000000:ff000000 rd1 l"}, /* cbnz wd,l */
+ {MIR_BF, "l r", "b4000000:ff000000 rd1 l"}, /* cbz rd,l */
+ {MIR_BFS, "l r", "34000000:ff000000 rd1 l"}, /* cbz wd,l */
+
+#define BEQ "54000000:ff00001f l"
+ // ??? add extended reg cmp insns:
+ // all ld insn are changed to builtins and bt/bts
+ /* cmp Rn,Rm; beq l */
+ {MIR_BEQ, "l r r", CMPR "; " BEQ},
+ /* cmp Rn,I,shift ; beq l */
+ {MIR_BEQ, "l r I", CMPI "; " BEQ},
+ /* cmp Wn,Wm;beq l */
+ {MIR_BEQS, "l r r", SCMPR "; " BEQ},
+ /* cmp Wn,I,shift; beq l */
+ {MIR_BEQS, "l r I", SCMPI "; " BEQ},
+ /* fcmpe Sn,Sm; beq l */
+ {MIR_FBEQ, "l r r", FCMP "; " BEQ},
+ /* fcmpe Dn,Dm; beq l */
+ {MIR_DBEQ, "l r r", DCMP "; " BEQ},
+ /* fcmpe Sn,0.0; beq l */
+ {MIR_FBEQ, "l r Zf", "1e202018:fffffc1f vn1 vm2; " BEQ},
+ /* fcmpe Dn,0.0; beq l */
+ {MIR_DBEQ, "l r Zd", "1e602018:fffffc1f vn1 vm2; " BEQ},
+
+#define BNE "54000001:ff00001f l"
+ /* cmp Rn,Rm; bne l */
+ {MIR_BNE, "l r r", CMPR "; " BNE},
+ /* cmp Rn,I,shift ; bne l */
+ {MIR_BNE, "l r I", CMPI "; " BNE},
+ /* cmp Wn,Wm;bne l */
+ {MIR_BNES, "l r r", SCMPR "; " BNE},
+ /* cmp Wn,I,shift; bne l */
+ {MIR_BNES, "l r I", SCMPI "; " BNE},
+ /* fcmpe Sn,Sm; bne l */
+ {MIR_FBNE, "l r r", FCMP "; " BNE},
+ /* fcmpe Dn,Dm; bne l */
+ {MIR_DBNE, "l r r", DCMP "; " BNE},
+ /* fcmpe Sn,0.0; bne l */
+ {MIR_FBNE, "l r Zf", "1e202018:fffffc1f vn1 vm2; " BNE},
+ /* fcmpe Dn,0.0; bne l */
+ {MIR_DBNE, "l r Zd", "1e602018:fffffc1f vn1 vm2; " BNE},
+
+#define BLT "5400000b:ff00001f l"
+#define UBLT "54000003:ff00001f l"
+ /* cmp Rn,Rm; blt l */
+ {MIR_BLT, "l r r", CMPR "; " BLT},
+ /* cmp Rn,I,shift ; blt l */
+ {MIR_BLT, "l r I", CMPI "; " BLT},
+ /* cmp Wn,Wm;blt l */
+ {MIR_BLTS, "l r r", SCMPR "; " BLT},
+ /* cmp Wn,I,shift; blt l */
+ {MIR_BLTS, "l r I", SCMPI "; " BLT},
+ /* cmp Rn,Rm; bcc l */
+ {MIR_UBLT, "l r r", CMPR "; " UBLT},
+ /* cmp Rn,I,shift ; bcc l */
+ {MIR_UBLT, "l r I", CMPI "; " UBLT},
+ /* cmp Wn,Wm;bcc l */
+ {MIR_UBLTS, "l r r", SCMPR "; " UBLT},
+ /* cmp Wn,I,shift; bcc l */
+ {MIR_UBLTS, "l r I", SCMPI "; " UBLT},
+ /* fcmpe Sn,Sm; blt l */
+ {MIR_FBLT, "l r r", FCMP "; " BLT},
+ /* fcmpe Dn,Dm; blt l */
+ {MIR_DBLT, "l r r", DCMP "; " BLT},
+ /* fcmpe Sn,0.0; blt l */
+ {MIR_FBLT, "l r Zf", "1e202018:fffffc1f vn1 vm2; " BLT},
+ /* fcmpe Dn,0.0; blt l */
+ {MIR_DBLT, "l r Zd", "1e602018:fffffc1f vn1 vm2; " BLT},
+
+#define BGE "5400000a:ff00001f l"
+#define UBGE "54000002:ff00001f l"
+#define FBGE "54000005:ff00001f l"
+ /* cmp Rn,Rm; bge l */
+ {MIR_BGE, "l r r", CMPR "; " BGE},
+ /* cmp Rn,I,shift ; bge l */
+ {MIR_BGE, "l r I", CMPI "; " BGE},
+ /* cmp Wn,Wm;bge l */
+ {MIR_BGES, "l r r", SCMPR "; " BGE},
+ /* cmp Wn,I,shift; bge l */
+ {MIR_BGES, "l r I", SCMPI "; " BGE},
+ /* cmp Rn,Rm; bcs l */
+ {MIR_UBGE, "l r r", CMPR "; " UBGE},
+ /* cmp Rn,I,shift ; bcs l */
+ {MIR_UBGE, "l r I", CMPI "; " UBGE},
+ /* cmp Wn,Wm;bcs l */
+ {MIR_UBGES, "l r r", SCMPR "; " UBGE},
+ /* cmp Wn,I,shift; bcs l */
+ {MIR_UBGES, "l r I", SCMPI "; " UBGE},
+ /* fcmpe Sn,Sm; bpl l */
+ {MIR_FBGE, "l r r", FCMP "; " FBGE},
+ /* fcmpe Dn,Dm; bpl l */
+ {MIR_DBGE, "l r r", DCMP "; " FBGE},
+ /* fcmpe Sn,0.0; bpl l */
+ {MIR_FBGE, "l r Zf", "1e202018:fffffc1f vn1 vm2; " FBGE},
+ /* fcmpe Dn,0.0; bpl l */
+ {MIR_DBGE, "l r Zd", "1e602018:fffffc1f vn1 vm2; " FBGE},
+
+#define BGT "5400000c:ff00001f l"
+#define UBGT "54000008:ff00001f l"
+ /* cmp Rn,Rm; bgt l */
+ {MIR_BGT, "l r r", CMPR "; " BGT},
+ /* cmp Rn,I,shift ; bgt l */
+ {MIR_BGT, "l r I", CMPI "; " BGT},
+ /* cmp Wn,Wm;bgt l */
+ {MIR_BGTS, "l r r", SCMPR "; " BGT},
+ /* cmp Wn,I,shift; bgt l */
+ {MIR_BGTS, "l r I", SCMPI "; " BGT},
+ /* cmp Rn,Rm; bhi l */
+ {MIR_UBGT, "l r r", CMPR "; " UBGT},
+ /* cmp Rn,I,shift ; bhi l */
+ {MIR_UBGT, "l r I", CMPI "; " UBGT},
+ /* cmp Wn,Wm;bhi l */
+ {MIR_UBGTS, "l r r", SCMPR "; " UBGT},
+ /* cmp Wn,I,shift; bhi l */
+ {MIR_UBGTS, "l r I", SCMPI "; " UBGT},
+ /* fcmpe Sn,Sm; bhi l */
+ {MIR_FBGT, "l r r", FCMP "; " UBGT},
+ /* fcmpe Dn,Dm; bhi l */
+ {MIR_DBGT, "l r r", DCMP "; " UBGT},
+ /* fcmpe Sn,0.0; bhi l */
+ {MIR_FBGT, "l r Zf", "1e202018:fffffc1f vn1 vm2; " UBGT},
+ /* fcmpe Dn,0.0; bhi l */
+ {MIR_DBGT, "l r Zd", "1e602018:fffffc1f vn1 vm2; " UBGT},
+
+#define BLE "5400000d:ff00001f l"
+#define UBLE "54000009:ff00001f l"
+ /* cmp Rn,Rm; ble l */
+ {MIR_BLE, "l r r", CMPR "; " BLE},
+ /* cmp Rn,I,shift ; ble l */
+ {MIR_BLE, "l r I", CMPI "; " BLE},
+ /* cmp Wn,Wm;ble l */
+ {MIR_BLES, "l r r", SCMPR "; " BLE},
+ /* cmp Wn,I,shift; ble l */
+ {MIR_BLES, "l r I", SCMPI "; " BLE},
+ /* cmp Rn,Rm; bls l */
+ {MIR_UBLE, "l r r", CMPR "; " UBLE},
+ /* cmp Rn,I,shift ; bls l */
+ {MIR_UBLE, "l r I", CMPI "; " UBLE},
+ /* cmp Wn,Wm;bls l */
+ {MIR_UBLES, "l r r", SCMPR "; " UBLE},
+ /* cmp Wn,I,shift; bls l */
+ {MIR_UBLES, "l r I", SCMPI "; " UBLE},
+ /* fcmpe Sn,Sm; ble l */
+ {MIR_FBLE, "l r r", FCMP "; " BLE},
+ /* fcmpe Dn,Dm; ble l */
+ {MIR_DBLE, "l r r", DCMP "; " BLE},
+ /* fcmpe Sn,0.0; ble l */
+ {MIR_FBLE, "l r Zf", "1e202018:fffffc1f vn1 vm2; " BLE},
+ /* fcmpe Dn,0.0; ble l */
+ {MIR_DBLE, "l r Zd", "1e602018:fffffc1f vn1 vm2; " BLE},
+
+ // ??? with shift
+ {MIR_NEG, "r r", "cb0003e0:ff2003e0 rd0 rm1"}, /* neg Rd,Rm */
+ {MIR_NEGS, "r r", "4b0003e0:ff2003e0 rd0 rm1"}, /* neg Wd,Wm */
+ {MIR_FNEG, "r r", "1e214000:fffffc00 vd0 vn1"}, /* fneg Sd,Sn */
+ {MIR_DNEG, "r r", "1e614000:fffffc00 vd0 vn1"}, /* fneg Dd,Dn */
+ // ldneg is a builtin
+
+ {MIR_LSH, "r r r", "9ac02000:ffe0fc00 rd0 rn1 rm2"}, /* lsl Rd,Rn,Rm */
+ {MIR_LSHS, "r r r", "1ac02000:ffe0fc00 rd0 rn1 rm2"}, /* lsl Wd,Wn,Wm */
+ {MIR_LSH, "r r SL", "d3400000:ffc00000 rd0 rn1 SL"}, /* ubfm Rd,Rn,immr,imms */
+ {MIR_LSHS, "r r Sl", "53000000:ffc00000 rd0 rn1 Sl"}, /* ubfm Wd,Wn,immr,imms */
+
+ {MIR_RSH, "r r r", "9ac02800:ffe0fc00 rd0 rn1 rm2"}, /* asr Rd,Rn,Rm */
+ {MIR_RSHS, "r r r", "1ac02800:ffe0fc00 rd0 rn1 rm2"}, /* asr Wd,Wn,Wm */
+ {MIR_RSH, "r r SR", "9340fc00:ffc0fc00 rd0 rn1 S"}, /* asr Rd,Rn,S */
+ {MIR_RSHS, "r r Sr", "13007c00:ffc0fc00 rd0 rn1 S"}, /* asr Wd,Wn,S */
+
+ {MIR_URSH, "r r r", "9ac02400:ffe0fc00 rd0 rn1 rm2"}, /* lsr Rd,Rn,Rm */
+ {MIR_URSHS, "r r r", "1ac02400:ffe0fc00 rd0 rn1 rm2"}, /* lsr Wd,Wn,Wm */
+ {MIR_URSH, "r r SR", "d340fc00:ffc0fc00 rd0 rn1 S"}, /* lsr Rd,Rn,S */
+ {MIR_URSHS, "r r Sr", "53007c00:ffc0fc00 rd0 rn1 S"}, /* lsr Wd,Wn,S */
+
+ // ??? adding shift, negate, immediate
+ {MIR_AND, "r r r", "8a000000:ffe0fc00 rd0 rn1 rm2"}, /* and Rd,Rn,Rm */
+ {MIR_ANDS, "r r r", "0a000000:ffe0fc00 rd0 rn1 rm2"}, /* and Wd,Wn,Wm */
+
+ {MIR_OR, "r r r", "aa000000:ffe0fc00 rd0 rn1 rm2"}, /* orr Rd,Rn,Rm */
+ {MIR_ORS, "r r r", "2a000000:ffe0fc00 rd0 rn1 rm2"}, /* orr Wd,Wn,Wm */
+
+ {MIR_XOR, "r r r", "ca000000:ffe0fc00 rd0 rn1 rm2"}, /* eor Rd,Rn,Rm */
+ {MIR_XORS, "r r r", "4a000000:ffe0fc00 rd0 rn1 rm2"}, /* eor Wd,Wn,Wm */
+
+ // ??? can we add scale
+ {MIR_I2F, "r r", "9e220000:ffff0000 vd0 rn1"}, /* scvtf Sd,Rn */
+ {MIR_I2D, "r r", "9e620000:ffff0000 vd0 rn1"}, /* scvtf Dd,Rn */
+ {MIR_UI2F, "r r", "9e230000:ffff0000 vd0 rn1"}, /* ucvtf Sd,Rn */
+ {MIR_UI2D, "r r", "9e630000:ffff0000 vd0 rn1"}, /* ucvtf Dd,Rn */
+ {MIR_F2I, "r r", "9e380000:ffff0000 rd0 vn1"}, /* fcvtzs Rd,Sn */
+ {MIR_D2I, "r r", "9e780000:ffff0000 rd0 vn1"}, /* fcvtzs Rd,Dn */
+ {MIR_F2D, "r r", "1e22c000:fffffc00 vd0 vn1"}, /* fcvt Dd,Sn */
+ {MIR_D2F, "r r", "1e624000:fffffc00 vd0 vn1"}, /* fcvt Sd,Dn */
+ // i2ld, ui2ld, ld2i, f2ld, d2ld, ld2f, ld2d are builtins
+
+ {MIR_CALL, "X r $", "d63f0000:fffffc1f rn1"}, /* blr *Rn */
+ {MIR_CALL, "X L $", "94000000:fc000000 rn1"}, /* bl address */
+ {MIR_INLINE, "X r $", "d63f0000:fffffc1f rn1"}, /* blr *Rn */
+ {MIR_INLINE, "X L $", "94000000:fc000000 rn1"}, /* bl address */
+ {MIR_RET, "$", "d65f0000:fffffc1f hn1e"}, /* ret R30 */
+
+ /* add r0, r1, 15; and r0, r0, -16; sub sp, sp, r0; mov r0, sp: */
+ {MIR_ALLOCA, "r r",
+ "91003c00:fffffc00 rd0 rn1; 927cec00:fffffc00 rd0 rn0;" /* add r0,r1,15;and r0,r0,-16
+ */
+ "cb206000:ffe0fc00 hn1f hd1f rm0; 91000000:fffffc00 rd0 hn1f"}, /* sub sp,sp,r0; mov r0,sp */
+ /* sub sp, sp, roundup (imm, 16); mov r0, sp: */
+ {MIR_ALLOCA, "r Iu", "d1000000:ff000000 hd1f hn1f Iu; 91000000:fffffc00 rd0 hn1f"},
+
+ {MIR_BSTART, "r", "91000000:fffffc00 rd0 hn1f"}, /* Rd = sp */
+ {MIR_BEND, "r", "91000000:fffffc00 hd1f rn0"}, /* sp = Rn */
+
+ /* adr r9,PC-relative TableAddress; ldr r9,(r9,r,8);br r9; TableContent */
+ {MIR_SWITCH, "r $",
+ "10000000:ff000000 hd9 T; f8607800:ffe0fc00 hd9 hn9 rm0; d61f0000:fffffc00 hn9;"},
+
+};
+
+static void target_get_early_clobbered_hard_regs (MIR_insn_t insn, MIR_reg_t *hr1, MIR_reg_t *hr2) {
+ *hr1 = *hr2 = MIR_NON_HARD_REG;
+ if (insn->code == MIR_MOD || insn->code == MIR_MODS || insn->code == MIR_UMOD
+ || insn->code == MIR_UMODS)
+ *hr1 = R8_HARD_REG;
+}
+
+static int pattern_index_cmp (const void *a1, const void *a2) {
+ int i1 = *(const int *) a1, i2 = *(const int *) a2;
+ int c1 = (int) patterns[i1].code, c2 = (int) patterns[i2].code;
+
+ return c1 != c2 ? c1 - c2 : (long) i1 - (long) i2;
+}
+
+static void patterns_init (MIR_context_t ctx) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ int i, ind, n = sizeof (patterns) / sizeof (struct pattern);
+ MIR_insn_code_t prev_code, code;
+ insn_pattern_info_t *info_addr;
+ insn_pattern_info_t pinfo = {0, 0};
+
+ VARR_CREATE (int, pattern_indexes, 0);
+ for (i = 0; i < n; i++) VARR_PUSH (int, pattern_indexes, i);
+ qsort (VARR_ADDR (int, pattern_indexes), n, sizeof (int), pattern_index_cmp);
+ VARR_CREATE (insn_pattern_info_t, insn_pattern_info, 0);
+ for (i = 0; i < MIR_INSN_BOUND; i++) VARR_PUSH (insn_pattern_info_t, insn_pattern_info, pinfo);
+ info_addr = VARR_ADDR (insn_pattern_info_t, insn_pattern_info);
+ for (prev_code = MIR_INSN_BOUND, i = 0; i < n; i++) {
+ ind = VARR_GET (int, pattern_indexes, i);
+ if ((code = patterns[ind].code) != prev_code) {
+ if (i != 0) info_addr[prev_code].num = i - info_addr[prev_code].start;
+ info_addr[code].start = i;
+ prev_code = code;
+ }
+ }
+ assert (prev_code != MIR_INSN_BOUND);
+ info_addr[prev_code].num = n - info_addr[prev_code].start;
+}
+
+struct imm {
+ int v, shift;
+};
+
+/* Return number of insn mov{n|z} movk* to express constant V. Return immediates with their shifts
+ for mov{n|z}, movk in IMMS. */
+static int movnzk_const (uint64_t v, int n_p, struct imm *imms) {
+ int i16, shift, n = 0;
+
+ if (n_p) v = ~v;
+ if (v == 0) {
+ imms[0].v = 0;
+ imms[0].shift = 0;
+ return 1;
+ }
+ for (shift = 0; v != 0; v >>= 16, shift += 16) {
+ for (; (i16 = v & 0xffff) == 0; shift += 16) v >>= 16;
+ gen_assert (n < 4);
+ imms[n].v = n_p && n != 0 ? (~i16 & 0xffff) : i16;
+ imms[n++].shift = shift;
+ }
+ return n;
+}
+
+/* Return shift flag (0 or 1) for arithm insn 12-bit immediate. If V cannot be represented, return
+ -1. */
+static int arithm_const (uint64_t v, int *imm) {
+ if (v < (1 << 12)) {
+ *imm = v;
+ return 0;
+ }
+ if ((v & 0xfff) == 0 && (v >> 12) < (1 << 12)) {
+ *imm = v >> 12;
+ return 1;
+ }
+ return -1;
+}
+
+/* Return shift flag (0 or 1) for arithm insn 12-bit immediate rounded
+ up to 16. If the rounded V cannot be represented, return -1. */
+static int arithm_roundup_const (uint64_t v, int *imm) {
+ return arithm_const ((v + 15) / 16 * 16, imm);
+}
+
+/* Return immr for right 64-bit or 32-bit (if SHORT_P) shift by V. If the
+ shift can not be be represented, return FALSE. */
+static int rshift_const (int64_t v, int short_p) {
+ return v < 0 || v > 63 || (short_p && v > 31) ? -1 : v;
+}
+
+/* Return immr and imms for left 64-bit or 32-bit (if SHORT_P) shift
+ by V. If the shift can not be be represented, return FALSE. */
+static int lshift_const_p (int64_t v, int short_p, int *immr, int *imms) {
+ if (short_p) {
+ if (v < 0 || v > 31) return FALSE;
+ *immr = (-v) & 0x1f;
+ *imms = 31 - v;
+ } else {
+ if (v < 0 || v > 63) return FALSE;
+ *immr = (-v) & 0x3f;
+ *imms = 63 - v;
+ }
+ return TRUE;
+}
+
+static int pattern_match_p (MIR_context_t ctx, const struct pattern *pat, MIR_insn_t insn) {
+ int nop, n;
+ size_t nops = MIR_insn_nops (ctx, insn);
+ const char *p;
+ char ch, start_ch;
+ MIR_op_mode_t mode;
+ MIR_op_t op, original;
+ MIR_reg_t hr;
+
+ for (nop = 0, p = pat->pattern; *p != 0; p++, nop++) {
+ while (*p == ' ' || *p == '\t') p++;
+ if (*p == '$') return TRUE;
+ if (MIR_call_code_p (insn->code) && nop >= nops) return FALSE;
+ gen_assert (nop < nops);
+ op = insn->ops[nop];
+ switch (start_ch = *p) {
+ case 'X': break;
+ case 'r':
+ if (op.mode != MIR_OP_HARD_REG) return FALSE;
+ break;
+ case 'h':
+ if (op.mode != MIR_OP_HARD_REG) return FALSE;
+ ch = *++p;
+ gen_assert ('0' <= ch && ch <= '9');
+ hr = ch - '0';
+ ch = *++p;
+ if ('0' <= ch && ch <= '9')
+ hr = hr * 10 + ch - '0';
+ else
+ --p;
+ gen_assert (hr <= MAX_HARD_REG);
+ if (op.u.hard_reg != hr) return FALSE;
+ break;
+ case 'm':
+ case 'M': {
+ MIR_type_t type, type2, type3 = MIR_T_BOUND;
+ int scale, u_p, s_p;
+
+ if (op.mode != MIR_OP_HARD_REG_MEM) return FALSE;
+ u_p = s_p = TRUE;
+ ch = *++p;
+ switch (ch) {
+ case 'f':
+ type = MIR_T_F;
+ type2 = MIR_T_BOUND;
+ scale = 4;
+ break;
+ case 'd':
+ type = MIR_T_D;
+ type2 = MIR_T_BOUND;
+ scale = 8;
+ break;
+ case 'l':
+ ch = *++p;
+ gen_assert (ch == 'd');
+ type = MIR_T_LD;
+ type2 = MIR_T_BOUND;
+ scale = 16;
+ break;
+ case 'u':
+ case 's':
+ u_p = ch == 'u';
+ s_p = ch == 's';
+ ch = *++p;
+ /* Fall through: */
+ default:
+ gen_assert ('0' <= ch && ch <= '3');
+ scale = 1 << (ch - '0');
+ if (ch == '0') {
+ type = u_p ? MIR_T_U8 : MIR_T_I8;
+ type2 = u_p && s_p ? MIR_T_I8 : MIR_T_BOUND;
+ } else if (ch == '1') {
+ type = u_p ? MIR_T_U16 : MIR_T_I16;
+ type2 = u_p && s_p ? MIR_T_I16 : MIR_T_BOUND;
+ } else if (ch == '2') {
+ type = u_p ? MIR_T_U32 : MIR_T_I32;
+ type2 = u_p && s_p ? MIR_T_I32 : MIR_T_BOUND;
+#if MIR_PTR32
+ if (u_p) type3 = MIR_T_P;
+#endif
+ } else {
+ type = u_p ? MIR_T_U64 : MIR_T_I64;
+ type2 = u_p && s_p ? MIR_T_I64 : MIR_T_BOUND;
+#if MIR_PTR64
+ type3 = MIR_T_P;
+#endif
+ }
+ }
+ if (op.u.hard_reg_mem.type != type && op.u.hard_reg_mem.type != type2
+ && op.u.hard_reg_mem.type != type3)
+ return FALSE;
+ if (start_ch == 'm'
+ && (op.u.hard_reg_mem.disp != 0
+ || (op.u.hard_reg_mem.index != MIR_NON_HARD_REG && op.u.hard_reg_mem.scale != 1
+ && op.u.hard_reg_mem.scale != scale)))
+ return FALSE;
+ if (start_ch == 'M'
+ && (op.u.hard_reg_mem.index != MIR_NON_HARD_REG || op.u.hard_reg_mem.disp < 0
+ || op.u.hard_reg_mem.disp % scale != 0
+ || op.u.hard_reg_mem.disp / scale >= (1 << 12)))
+ return FALSE;
+ break;
+ }
+ case 'Z':
+ case 'N': {
+ int n;
+ uint64_t v;
+ struct imm imms[4];
+
+ ch = *++p;
+ if (ch == 'f' && op.mode == MIR_OP_FLOAT) {
+ if (op.u.f != 0.0f) return FALSE;
+ } else if (ch == 'd' && op.mode == MIR_OP_DOUBLE) {
+ if (op.u.d != 0.0) return FALSE;
+ } else {
+ if (op.mode != MIR_OP_INT && op.mode != MIR_OP_UINT && op.mode != MIR_OP_REF) return FALSE;
+ gen_assert ('0' <= ch && ch <= '2' || start_ch == 'Z' && ch == '3');
+ n = ch - '0';
+ if (op.mode != MIR_OP_REF) {
+ v = op.u.u;
+ } else if (op.u.ref->item_type == MIR_data_item && op.u.ref->u.data->name != NULL
+ && _MIR_reserved_ref_name_p (ctx, op.u.ref->u.data->name)) {
+ v = (uint64_t) op.u.ref->u.data->u.els;
+ } else {
+ v = (uint64_t) op.u.ref->addr;
+ }
+ if (movnzk_const (v, start_ch == 'N', imms) > n + 1) return FALSE;
+ gen_assert (nop == 1); /* only 2nd move operand */
+ }
+ break;
+ }
+ case 'I': {
+ int imm;
+
+ if (op.mode != MIR_OP_INT && op.mode != MIR_OP_UINT) return FALSE;
+ ch = *++p;
+ if (ch == 'u') {
+ if (arithm_roundup_const (op.u.u, &imm) < 0) return FALSE;
+ } else {
+ p--;
+ if (arithm_const (op.u.u, &imm) < 0) return FALSE;
+ }
+ break;
+ }
+ case 'S': {
+ int immr, imms;
+
+ if (op.mode != MIR_OP_INT && op.mode != MIR_OP_UINT) return FALSE;
+ gen_assert (op.mode != MIR_OP_INT || op.u.i >= 0);
+ ch = *++p;
+ if (ch == 'r' || ch == 'R') {
+ if ((op.mode == MIR_OP_UINT && op.u.i < 0) || rshift_const (op.u.i, ch == 'r') < 0)
+ return FALSE;
+ } else {
+ gen_assert (ch == 'l' || ch == 'L');
+ if ((op.mode == MIR_OP_UINT && op.u.i < 0)
+ || !lshift_const_p (op.u.i, ch == 'l', &immr, &imms))
+ return FALSE;
+ }
+ break;
+ }
+ case 'l':
+ if (op.mode != MIR_OP_LABEL) return FALSE;
+ break;
+ case 'L':
+ if (op.mode != MIR_OP_LABEL && op.mode != MIR_OP_REF) return FALSE;
+ break;
+ default: gen_assert (FALSE);
+ }
+ }
+ gen_assert (nop == nops);
+ return TRUE;
+}
+
+static const char *find_insn_pattern_replacement (MIR_context_t ctx, MIR_insn_t insn) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ int i;
+ const struct pattern *pat;
+ insn_pattern_info_t info = VARR_GET (insn_pattern_info_t, insn_pattern_info, insn->code);
+
+ for (i = 0; i < info.num; i++) {
+ pat = &patterns[VARR_GET (int, pattern_indexes, info.start + i)];
+ if (pattern_match_p (ctx, pat, insn)) return pat->replacement;
+ }
+ return NULL;
+}
+
+static void patterns_finish (MIR_context_t ctx) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+
+ VARR_DESTROY (int, pattern_indexes);
+ VARR_DESTROY (insn_pattern_info_t, insn_pattern_info);
+}
+
+static int hex_value (int ch) {
+ return ('0' <= ch && ch <= '9'
+ ? ch - '0'
+ : 'A' <= ch && ch <= 'F' ? ch - 'A' + 10 : 'a' <= ch && ch <= 'f' ? ch - 'a' + 10 : -1);
+}
+
+static uint64_t read_hex (const char **ptr) {
+ int v;
+ const char *p;
+ uint64_t res = 0;
+
+ for (p = *ptr; (v = hex_value (*p)) >= 0; p++) {
+ gen_assert ((res >> 60) == 0);
+ res = res * 16 + v;
+ }
+ gen_assert (p != *ptr);
+ *ptr = p - 1;
+ return res;
+}
+
+static void put_byte (struct gen_ctx *gen_ctx, int byte) { VARR_PUSH (uint8_t, result_code, byte); }
+
+static void put_uint64 (struct gen_ctx *gen_ctx, uint64_t v, int nb) {
+ for (; nb > 0; nb--) {
+ put_byte (gen_ctx, v & 0xff);
+ v >>= 8;
+ }
+}
+
+static void set_int64 (uint8_t *addr, int64_t v, int nb) { /* Little endian */
+ for (; nb > 0; nb--) {
+ *addr++ = v & 0xff;
+ v >>= 8;
+ }
+}
+
+static int64_t get_int64 (uint8_t *addr, int nb) { /* Little endian */
+ int64_t v = 0;
+ int i, sh = (8 - nb) * 8;
+
+ for (i = nb - 1; i >= 0; i--) v = (v << 8) | addr[i];
+ if (sh > 0) v = (v << sh) >> sh; /* make it signed */
+ return v;
+}
+
+static uint32_t check_and_set_mask (uint32_t opcode_mask, uint32_t mask) {
+ gen_assert ((opcode_mask & mask) == 0);
+ return opcode_mask | mask;
+}
+
+static void out_insn (MIR_context_t ctx, MIR_insn_t insn, const char *replacement) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ size_t offset;
+ const char *p, *insn_str;
+ label_ref_t lr;
+ int switch_table_adr_insn_start = -1;
+
+ if (insn->code == MIR_ALLOCA
+ && (insn->ops[1].mode == MIR_OP_INT || insn->ops[1].mode == MIR_OP_UINT))
+ insn->ops[1].u.u = (insn->ops[1].u.u + 15) & -16;
+ for (insn_str = replacement;; insn_str = p + 1) {
+ char ch, ch2, start_ch, d;
+ uint32_t opcode = 0, opcode_mask = 0xffffffff;
+ int rd = -1, rn = -1, rm = -1, ra = -1, disp = -1, scale = -1;
+ int immr = -1, imms = -1, imm16 = -1, imm16_shift = -1, imm12 = -1, imm12_shift = -1;
+ MIR_op_t op;
+ int label_ref_num = -1, switch_table_addr_p = FALSE;
+
+ for (p = insn_str; (ch = *p) != '\0' && ch != ';'; p++) {
+ if ((d = hex_value (ch = *p)) >= 0) { /* opcode and mask */
+ gen_assert (opcode == 0 && opcode_mask == 0xffffffff);
+ do {
+ opcode = opcode * 16 + d;
+ p++;
+ } while ((d = hex_value (*p)) >= 0);
+ if ((ch = *p) == ':') {
+ p++;
+ opcode_mask = 0;
+ while ((d = hex_value (ch = *p)) >= 0) {
+ opcode_mask = opcode_mask * 16 + d;
+ p++;
+ }
+ }
+ gen_assert ((opcode & ~opcode_mask) == 0);
+ }
+ if ((ch = *p) == 0 || ch == ';') break;
+ switch ((start_ch = ch = *p)) {
+ case ' ':
+ case '\t': break;
+ case 'r':
+ case 'v':
+ case 'h': {
+ int reg;
+
+ ch2 = *++p;
+ gen_assert (ch2 == 'd' || ch2 == 'n' || ch2 == 'm'
+ || (ch2 == 'a'
+ && (insn->code == MIR_MOD || insn->code == MIR_MODS
+ || insn->code == MIR_UMOD || insn->code == MIR_UMODS)));
+ ch = *++p;
+ if (start_ch == 'h') {
+ reg = read_hex (&p);
+ } else {
+ gen_assert ('0' <= ch && ch <= '2' && ch - '0' < insn->nops);
+ op = insn->ops[ch - '0'];
+ gen_assert (op.mode == MIR_OP_HARD_REG);
+ reg = op.u.hard_reg;
+ if (start_ch != 'v') {
+ gen_assert (reg < V0_HARD_REG);
+ } else {
+ gen_assert (reg >= V0_HARD_REG);
+ reg -= V0_HARD_REG;
+ }
+ }
+ gen_assert (reg <= 31);
+ if (ch2 == 'd')
+ rd = reg;
+ else if (ch2 == 'n')
+ rn = reg;
+ else if (ch2 == 'm')
+ rm = reg;
+ else
+ ra = reg;
+ break;
+ }
+ case 'm':
+ op = insn->ops[0].mode == MIR_OP_HARD_REG_MEM ? insn->ops[0] : insn->ops[1];
+ rn = op.u.hard_reg_mem.base;
+ rm = op.u.hard_reg_mem.index == MIR_NON_HARD_REG ? ZR_HARD_REG : op.u.hard_reg_mem.index;
+ scale = op.u.hard_reg_mem.scale;
+ break;
+ case 'M': {
+ int scale;
+
+ op = insn->ops[0].mode == MIR_OP_HARD_REG_MEM ? insn->ops[0] : insn->ops[1];
+ switch (op.u.hard_reg_mem.type) {
+ case MIR_T_I8:
+ case MIR_T_U8: scale = 1; break;
+ case MIR_T_I16:
+ case MIR_T_U16: scale = 2; break;
+#if MIR_PTR32
+ case MIR_T_P:
+#endif
+ case MIR_T_I32:
+ case MIR_T_U32:
+ case MIR_T_F: scale = 4; break;
+#if MIR_PTR64
+ case MIR_T_P:
+#endif
+ case MIR_T_I64:
+ case MIR_T_U64:
+ case MIR_T_D: scale = 8; break;
+ case MIR_T_LD: scale = 16; break;
+ default: assert (FALSE);
+ }
+ gen_assert (op.u.hard_reg_mem.disp % scale == 0);
+ rn = op.u.hard_reg_mem.base;
+ disp = op.u.hard_reg_mem.disp / scale;
+ gen_assert (disp < (1 << 12));
+ break;
+ }
+ case 'S': { /* S, SL, Sl */
+ int flag, r, s;
+
+ op = insn->ops[2];
+ gen_assert (op.mode == MIR_OP_INT || op.mode == MIR_OP_UINT);
+ ch = *++p;
+ if (ch == 'L' || ch == 'l') {
+ flag = lshift_const_p (op.u.i, ch == 'l', &immr, &imms);
+ gen_assert (flag);
+ } else {
+ p--;
+ immr = rshift_const (op.u.i, FALSE);
+ gen_assert (immr >= 0);
+ }
+ break;
+ }
+ case 'N':
+ case 'Z': {
+ int n, n2;
+ uint64_t v;
+ struct imm imms[4];
+
+ ch = *++p;
+ gen_assert ('0' <= ch && ch <= '3');
+ op = insn->ops[1];
+ n = ch - '0';
+ if (op.mode != MIR_OP_REF) {
+ v = op.u.u;
+ } else if (op.u.ref->item_type == MIR_data_item && op.u.ref->u.data->name != NULL
+ && _MIR_reserved_ref_name_p (ctx, op.u.ref->u.data->name)) {
+ v = (uint64_t) op.u.ref->u.data->u.els;
+ } else {
+ v = (uint64_t) op.u.ref->addr;
+ }
+ n2 = movnzk_const (v, start_ch == 'N', imms);
+ gen_assert (n < n2);
+ imm16 = imms[n].v;
+ imm16_shift = imms[n].shift >> 4;
+ break;
+ }
+ case 'I': {
+ ch = *++p;
+ if (ch != 'u') { /* I */
+ op = insn->ops[2];
+ gen_assert (op.mode == MIR_OP_INT || op.mode == MIR_OP_UINT);
+ imm12_shift = arithm_const (op.u.u, &imm12);
+ p--;
+ } else {
+ op = insn->ops[1];
+ gen_assert (op.mode == MIR_OP_INT || op.mode == MIR_OP_UINT);
+ imm12_shift = arithm_roundup_const (op.u.u, &imm12);
+ }
+ break;
+ }
+ case 'T': {
+ gen_assert (!switch_table_addr_p && switch_table_adr_insn_start < 0);
+ switch_table_addr_p = TRUE;
+ break;
+ }
+ case 'l':
+ case 'L': {
+ op = insn->ops[start_ch == 'l' || (insn->code != MIR_CALL && insn->code != MIR_INLINE) ? 0
+ : 1];
+ gen_assert (op.mode == MIR_OP_LABEL || (start_ch == 'L' && op.mode == MIR_OP_REF));
+ lr.abs_addr_p = FALSE;
+ lr.short_p = start_ch == 'l';
+ lr.label_val_disp = 0;
+ lr.label = op.u.label;
+ label_ref_num = VARR_LENGTH (label_ref_t, label_refs);
+ VARR_PUSH (label_ref_t, label_refs, lr);
+ break;
+ }
+ default: gen_assert (FALSE);
+ }
+ }
+
+ if (rd >= 0) {
+ gen_assert (rd <= 31);
+ opcode |= rd;
+ opcode_mask = check_and_set_mask (opcode_mask, 0x1f);
+ }
+ if (rn >= 0) {
+ gen_assert (rn <= 31);
+ opcode |= rn << 5;
+ opcode_mask = check_and_set_mask (opcode_mask, 0x1f << 5);
+ }
+ if (rm >= 0) {
+ gen_assert (rm <= 31);
+ opcode |= rm << 16;
+ opcode_mask = check_and_set_mask (opcode_mask, 0x1f << 16);
+ }
+ if (ra >= 0) {
+ gen_assert (rm <= 31);
+ opcode |= ra << 10;
+ opcode_mask = check_and_set_mask (opcode_mask, 0x1f << 10);
+ }
+ if (scale >= 0) {
+ opcode |= (scale == 1 ? 0x6 : 0x7) << 12;
+ opcode_mask = check_and_set_mask (opcode_mask, 0xf << 12);
+ }
+ if (disp >= 0) {
+ gen_assert (disp < (1 << 12));
+ opcode |= disp << 10;
+ opcode_mask = check_and_set_mask (opcode_mask, 0xfff << 10);
+ }
+ if (immr >= 0) {
+ gen_assert (immr < (1 << 6));
+ opcode |= immr << 16;
+ opcode_mask = check_and_set_mask (opcode_mask, 0x3f << 16);
+ }
+ if (imms >= 0) {
+ gen_assert (imms < (1 << 6));
+ opcode |= imms << 10;
+ opcode_mask = check_and_set_mask (opcode_mask, 0x3f << 10);
+ }
+ if (imm16 >= 0) {
+ gen_assert (imm16 < (1 << 16));
+ opcode |= imm16 << 5;
+ opcode_mask = check_and_set_mask (opcode_mask, 0xffff << 5);
+ }
+ if (imm16_shift >= 0) {
+ gen_assert (imm16_shift < (1 << 2));
+ opcode |= imm16_shift << 21;
+ opcode_mask = check_and_set_mask (opcode_mask, 0x3 << 21);
+ }
+ if (imm12 >= 0) {
+ gen_assert (imm12 < (1 << 12));
+ opcode |= imm12 << 10;
+ opcode_mask = check_and_set_mask (opcode_mask, 0xfff << 10);
+ }
+ if (imm12_shift >= 0) {
+ gen_assert (imm12_shift < (1 << 2));
+ opcode |= imm12_shift << 22;
+ opcode_mask = check_and_set_mask (opcode_mask, 0x3 << 22);
+ }
+ if (label_ref_num >= 0)
+ VARR_ADDR (label_ref_t, label_refs)
+ [label_ref_num].label_val_disp
+ = VARR_LENGTH (uint8_t, result_code);
+
+ if (switch_table_addr_p) switch_table_adr_insn_start = VARR_LENGTH (uint8_t, result_code);
+ put_uint64 (gen_ctx, opcode, 4); /* output the machine insn */
+
+ if (*p == 0) break;
+ }
+ if (switch_table_adr_insn_start < 0) return;
+ if (VARR_LENGTH (uint8_t, result_code) % 8 == 4) put_uint64 (gen_ctx, 0, 4);
+ offset = (VARR_LENGTH (uint8_t, result_code) - switch_table_adr_insn_start) / 4; /* pc offset */
+ *(uint32_t *) (VARR_ADDR (uint8_t, result_code) + switch_table_adr_insn_start) |= (offset << 5);
+ gen_assert (insn->code == MIR_SWITCH);
+ for (size_t i = 1; i < insn->nops; i++) {
+ gen_assert (insn->ops[i].mode == MIR_OP_LABEL);
+ lr.abs_addr_p = TRUE;
+ lr.short_p = FALSE;
+ lr.label_val_disp = VARR_LENGTH (uint8_t, result_code);
+ lr.label = insn->ops[i].u.label;
+ VARR_PUSH (label_ref_t, label_refs, lr);
+ put_uint64 (gen_ctx, 0, 8);
+ }
+}
+
+static int target_insn_ok_p (MIR_context_t ctx, MIR_insn_t insn) {
+ return find_insn_pattern_replacement (ctx, insn) != NULL;
+}
+
+static uint8_t *target_translate (MIR_context_t ctx, size_t *len) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ size_t i;
+ MIR_insn_t insn;
+ const char *replacement;
+
+ gen_assert (curr_func_item->item_type == MIR_func_item);
+ VARR_TRUNC (uint8_t, result_code, 0);
+ VARR_TRUNC (label_ref_t, label_refs, 0);
+ VARR_TRUNC (uint64_t, abs_address_locs, 0);
+ for (insn = DLIST_HEAD (MIR_insn_t, curr_func_item->u.func->insns); insn != NULL;
+ insn = DLIST_NEXT (MIR_insn_t, insn)) {
+ if (insn->code == MIR_LABEL) {
+ set_label_disp (insn, VARR_LENGTH (uint8_t, result_code));
+ } else {
+ replacement = find_insn_pattern_replacement (ctx, insn);
+ if (replacement == NULL) {
+ fprintf (stderr, "fatal failure in matching insn:");
+ MIR_output_insn (ctx, stderr, insn, curr_func_item->u.func, TRUE);
+ exit (1);
+ } else {
+ gen_assert (replacement != NULL);
+ out_insn (ctx, insn, replacement);
+ }
+ }
+ }
+ /* Setting up labels */
+ for (i = 0; i < VARR_LENGTH (label_ref_t, label_refs); i++) {
+ label_ref_t lr = VARR_GET (label_ref_t, label_refs, i);
+
+ if (!lr.abs_addr_p) {
+ int64_t offset
+ = (int64_t) get_label_disp (lr.label) - (int64_t) lr.label_val_disp; /* pc offset */
+ gen_assert ((offset & 0x3) == 0);
+ if (lr.short_p)
+ *(uint32_t *) (VARR_ADDR (uint8_t, result_code) + lr.label_val_disp)
+ |= ((offset / 4) & 0x7ffff) << 5; /* 19-bit */
+ else
+ *(uint32_t *) (VARR_ADDR (uint8_t, result_code) + lr.label_val_disp)
+ |= (offset / 4) & 0x3ffffff; /* 26-bit */
+ } else {
+ set_int64 (&VARR_ADDR (uint8_t, result_code)[lr.label_val_disp],
+ (int64_t) get_label_disp (lr.label), 8);
+ VARR_PUSH (uint64_t, abs_address_locs, lr.label_val_disp);
+ }
+ }
+ while (VARR_LENGTH (uint8_t, result_code) % 16 != 0) /* Align the pool */
+ VARR_PUSH (uint8_t, result_code, 0);
+ *len = VARR_LENGTH (uint8_t, result_code);
+ return VARR_ADDR (uint8_t, result_code);
+}
+
+static void target_rebase (MIR_context_t ctx, uint8_t *base) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ MIR_code_reloc_t reloc;
+
+ VARR_TRUNC (MIR_code_reloc_t, relocs, 0);
+ for (size_t i = 0; i < VARR_LENGTH (uint64_t, abs_address_locs); i++) {
+ reloc.offset = VARR_GET (uint64_t, abs_address_locs, i);
+ reloc.value = base + get_int64 (base + reloc.offset, 8);
+ VARR_PUSH (MIR_code_reloc_t, relocs, reloc);
+ }
+ _MIR_update_code_arr (ctx, base, VARR_LENGTH (MIR_code_reloc_t, relocs),
+ VARR_ADDR (MIR_code_reloc_t, relocs));
+}
+
+static void target_init (MIR_context_t ctx) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+
+ gen_ctx->target_ctx = gen_malloc (ctx, sizeof (struct target_ctx));
+ VARR_CREATE (uint8_t, result_code, 0);
+ VARR_CREATE (label_ref_t, label_refs, 0);
+ VARR_CREATE (uint64_t, abs_address_locs, 0);
+ VARR_CREATE (MIR_code_reloc_t, relocs, 0);
+ patterns_init (ctx);
+}
+
+static void target_finish (MIR_context_t ctx) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+
+ patterns_finish (ctx);
+ VARR_DESTROY (uint8_t, result_code);
+ VARR_DESTROY (label_ref_t, label_refs);
+ VARR_DESTROY (uint64_t, abs_address_locs);
+ VARR_DESTROY (MIR_code_reloc_t, relocs);
+ free (gen_ctx->target_ctx);
+ gen_ctx->target_ctx = NULL;
+}
diff --git a/mir/mir-gen-ppc64.c b/mir/mir-gen-ppc64.c
new file mode 100644
index 0000000..049bf11
--- /dev/null
+++ b/mir/mir-gen-ppc64.c
@@ -0,0 +1 @@
+#include "mir-gen-stub.c"
diff --git a/mir/mir-gen-stub.c b/mir/mir-gen-stub.c
new file mode 100644
index 0000000..2a6538d
--- /dev/null
+++ b/mir/mir-gen-stub.c
@@ -0,0 +1,95 @@
+/* This file is a part of MIR project.
+ Copyright (C) 2018-2020 Vladimir Makarov .
+
+ Stub for MIR generator machine dependent file. It contains
+ definitions used by MIR generator. You can use this file for
+ successful compilation of mir-gen.c.
+
+ See HOW-TO-PORT-MIR.md document for the definitions description.
+*/
+
+enum {
+ R0_HARD_REG,
+ R1_HARD_REG,
+ R2_HARD_REG,
+ R3_HARD_REG,
+ R4_HARD_REG,
+ R5_HARD_REG,
+ R6_HARD_REG,
+ R7_HARD_REG,
+ F0_HARD_REG,
+ F1_HARD_REG,
+ F2_HARD_REG,
+ F3_HARD_REG,
+ F4_HARD_REG,
+ F5_HARD_REG,
+ F6_HARD_REG,
+ F7_HARD_REG
+};
+
+static const MIR_reg_t MAX_HARD_REG = F7_HARD_REG; /* max value for the previous regs */
+static const MIR_reg_t FP_HARD_REG = R6_HARD_REG; /* stack frame pointer according ABI */
+static const MIR_reg_t SP_HARD_REG = R7_HARD_REG; /* stack pointer according ABI */
+
+const MIR_reg_t TEMP_INT_HARD_REG1 = R2_HARD_REG, TEMP_INT_HARD_REG2 = R3_HARD_REG;
+const MIR_reg_t TEMP_FLOAT_HARD_REG1 = F2_HARD_REG, TEMP_FLOAT_HARD_REG2 = F3_HARD_REG;
+const MIR_reg_t TEMP_DOUBLE_HARD_REG1 = F2_HARD_REG, TEMP_DOUBLE_HARD_REG2 = F3_HARD_REG;
+const MIR_reg_t TEMP_LDOUBLE_HARD_REG1 = F2_HARD_REG;
+const MIR_reg_t TEMP_LDOUBLE_HARD_REG2 = F3_HARD_REG;
+
+static int target_locs_num (MIR_reg_t loc, MIR_type_t type) {
+ return loc > MAX_HARD_REG && type == MIR_T_LD ? 2 : 1;
+}
+
+static inline int target_hard_reg_type_ok_p (MIR_reg_t hard_reg, MIR_type_t type) {
+ assert (hard_reg <= MAX_HARD_REG);
+ return (type == MIR_T_F || type == MIR_T_D || type == MIR_T_LD ? hard_reg >= F0_HARD_REG
+ : hard_reg < F0_HARD_REG);
+}
+
+static inline int target_fixed_hard_reg_p (MIR_reg_t hard_reg) {
+ assert (hard_reg <= MAX_HARD_REG);
+ return (hard_reg == FP_HARD_REG || hard_reg == SP_HARD_REG
+ || hard_reg == TEMP_INT_HARD_REG1 || hard_reg == TEMP_INT_HARD_REG2
+ || hard_reg == TEMP_FLOAT_HARD_REG1 || hard_reg == TEMP_FLOAT_HARD_REG2
+ || hard_reg == TEMP_DOUBLE_HARD_REG1 || hard_reg == TEMP_DOUBLE_HARD_REG2
+ || hard_reg == TEMP_LDOUBLE_HARD_REG1 || hard_reg == TEMP_LDOUBLE_HARD_REG2);
+}
+
+static inline int target_call_used_hard_reg_p (MIR_reg_t hard_reg) {
+ assert (hard_reg <= MAX_HARD_REG);
+ return !((hard_reg >= R4_HARD_REG && hard_reg <= R5_HARD_REG)
+ || (hard_reg >= F2_HARD_REG && hard_reg <= F7_HARD_REG));
+}
+
+static const int slots_offset = 176; /* It is used in this file but not in MIR generator */
+
+static MIR_disp_t target_get_stack_slot_offset (MIR_context_t ctx, MIR_type_t type,
+ MIR_reg_t slot) {
+ /* slot is 0, 1, ... */
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+
+ return -((MIR_disp_t) (slot + (type == MIR_T_LD ? 2 : 1)) * 8 + slots_offset);
+}
+
+static const MIR_insn_code_t target_io_dup_op_insn_codes[] = {MIR_INSN_BOUND};
+
+static void target_machinize (MIR_context_t ctx) {}
+
+static void target_make_prolog_epilog (MIR_context_t ctx, bitmap_t used_hard_regs,
+ size_t stack_slots_num) {}
+
+static void target_get_early_clobbered_hard_regs (MIR_insn_t insn, MIR_reg_t *hr1, MIR_reg_t *hr2) {
+ *hr1 = *hr2 = MIR_NON_HARD_REG;
+}
+
+static int target_insn_ok_p (MIR_context_t ctx, MIR_insn_t insn) { return FALSE; }
+static uint8_t *target_translate (MIR_context_t ctx, size_t *len) { return NULL; }
+static void target_rebase (MIR_context_t ctx, uint8_t *base) {}
+
+static void target_init (MIR_context_t ctx) {
+ fprintf (stderr, "Your generator target dependent file is just a stub!\n");
+ fprintf (stderr, "MIR generator can not use it -- good bye.\n");
+ exit (1);
+}
+static void target_finish (MIR_context_t ctx) {}
diff --git a/mir/mir-gen-x86_64.c b/mir/mir-gen-x86_64.c
index 2499ca0..4a99dbf 100644
--- a/mir/mir-gen-x86_64.c
+++ b/mir/mir-gen-x86_64.c
@@ -16,9 +16,9 @@ enum {
#undef REP_SEP
static const MIR_reg_t MAX_HARD_REG = ST1_HARD_REG;
-static const MIR_reg_t HARD_REG_FRAME_POINTER = BP_HARD_REG;
+static const MIR_reg_t FP_HARD_REG = BP_HARD_REG;
-static int locs_num (MIR_reg_t loc, MIR_type_t type) {
+static int target_locs_num (MIR_reg_t loc, MIR_type_t type) {
return loc > MAX_HARD_REG && type == MIR_T_LD ? 2 : 1;
}
@@ -29,15 +29,15 @@ const MIR_reg_t TEMP_DOUBLE_HARD_REG1 = XMM8_HARD_REG, TEMP_DOUBLE_HARD_REG2 = X
const MIR_reg_t TEMP_LDOUBLE_HARD_REG1 = MIR_NON_HARD_REG;
const MIR_reg_t TEMP_LDOUBLE_HARD_REG2 = MIR_NON_HARD_REG;
-static inline int hard_reg_type_ok_p (MIR_reg_t hard_reg, MIR_type_t type) {
+static inline int target_hard_reg_type_ok_p (MIR_reg_t hard_reg, MIR_type_t type) {
assert (hard_reg <= MAX_HARD_REG);
/* For LD we need x87 stack regs and it is too complicated so no
hard register allocation for LD: */
if (type == MIR_T_LD) return FALSE;
- return type == MIR_T_F || type == MIR_T_D ? hard_reg >= XMM0_HARD_REG : hard_reg < XMM0_HARD_REG;
+ return MIR_int_type_p (type) ? hard_reg < XMM0_HARD_REG : hard_reg >= XMM0_HARD_REG;
}
-static inline int fixed_hard_reg_p (MIR_reg_t hard_reg) {
+static inline int target_fixed_hard_reg_p (MIR_reg_t hard_reg) {
assert (hard_reg <= MAX_HARD_REG);
return (hard_reg == BP_HARD_REG || hard_reg == SP_HARD_REG || hard_reg == TEMP_INT_HARD_REG1
|| hard_reg == TEMP_INT_HARD_REG2 || hard_reg == TEMP_FLOAT_HARD_REG1
@@ -46,7 +46,7 @@ static inline int fixed_hard_reg_p (MIR_reg_t hard_reg) {
|| hard_reg == ST1_HARD_REG);
}
-static inline int call_used_hard_reg_p (MIR_reg_t hard_reg) {
+static inline int target_call_used_hard_reg_p (MIR_reg_t hard_reg) {
assert (hard_reg <= MAX_HARD_REG);
return !(hard_reg == BX_HARD_REG || (hard_reg >= R12_HARD_REG && hard_reg <= R15_HARD_REG));
}
@@ -79,7 +79,8 @@ static inline int call_used_hard_reg_p (MIR_reg_t hard_reg) {
static const int reg_save_area_size = 176;
-static MIR_disp_t get_stack_slot_offset (MIR_context_t ctx, MIR_type_t type, MIR_reg_t slot) {
+static MIR_disp_t target_get_stack_slot_offset (MIR_context_t ctx, MIR_type_t type,
+ MIR_reg_t slot) {
/* slot is 0, 1, ... */
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
@@ -87,17 +88,16 @@ static MIR_disp_t get_stack_slot_offset (MIR_context_t ctx, MIR_type_t type, MIR
+ (curr_func_item->u.func->vararg_p ? reg_save_area_size : 0));
}
-static const MIR_insn_code_t io_dup_op_insn_codes[] = {
+static const MIR_insn_code_t target_io_dup_op_insn_codes[] = {
/* see possible patterns */
- MIR_FADD, MIR_DADD, MIR_LDADD, MIR_SUB, MIR_SUBS, MIR_FSUB, MIR_DSUB, MIR_LDSUB,
- MIR_MUL, MIR_MULS, MIR_FMUL, MIR_DMUL, MIR_LDMUL, MIR_DIV, MIR_DIVS, MIR_UDIV,
- MIR_FDIV, MIR_DDIV, MIR_LDDIV, MIR_MOD, MIR_MODS, MIR_UMOD, MIR_UMODS, MIR_AND,
- MIR_ANDS, MIR_OR, MIR_ORS, MIR_XOR, MIR_XORS, MIR_LSH, MIR_LSHS, MIR_RSH,
- MIR_RSHS, MIR_URSH, MIR_URSHS, MIR_NEG, MIR_NEGS, MIR_FNEG, MIR_DNEG, MIR_LDNEG,
+ MIR_FADD, MIR_DADD, MIR_LDADD, MIR_SUB, MIR_SUBS, MIR_FSUB, MIR_DSUB,
+ MIR_LDSUB, MIR_MUL, MIR_MULS, MIR_FMUL, MIR_DMUL, MIR_LDMUL, MIR_DIV,
+ MIR_DIVS, MIR_UDIV, MIR_FDIV, MIR_DDIV, MIR_LDDIV, MIR_MOD, MIR_MODS,
+ MIR_UMOD, MIR_UMODS, MIR_AND, MIR_ANDS, MIR_OR, MIR_ORS, MIR_XOR,
+ MIR_XORS, MIR_LSH, MIR_LSHS, MIR_RSH, MIR_RSHS, MIR_URSH, MIR_URSHS,
+ MIR_NEG, MIR_NEGS, MIR_FNEG, MIR_DNEG, MIR_LDNEG, MIR_INSN_BOUND,
};
-typedef enum { GC_INSN_PUSH = MIR_INSN_BOUND, GC_INSN_BOUND } MIR_full_insn_code_t;
-
static MIR_insn_code_t get_ext_code (MIR_type_t type) {
switch (type) {
case MIR_T_I8: return MIR_EXT8;
@@ -110,6 +110,44 @@ static MIR_insn_code_t get_ext_code (MIR_type_t type) {
}
}
+static MIR_reg_t get_fp_arg_reg (size_t fp_arg_num) {
+ switch (fp_arg_num) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+#ifndef _WIN64
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+#endif
+ return XMM0_HARD_REG + fp_arg_num;
+ default: return MIR_NON_HARD_REG;
+ }
+}
+
+static MIR_reg_t get_int_arg_reg (size_t int_arg_num) {
+ switch (int_arg_num
+#ifdef _WIN64
+ + 2
+#endif
+ ) {
+ case 0: return DI_HARD_REG;
+ case 1: return SI_HARD_REG;
+#ifdef _WIN64
+ case 2: return CX_HARD_REG;
+ case 3: return DX_HARD_REG;
+#else
+ case 2: return DX_HARD_REG;
+ case 3: return CX_HARD_REG;
+#endif
+ case 4: return R8_HARD_REG;
+ case 5: return R9_HARD_REG;
+ default: return MIR_NON_HARD_REG;
+ }
+}
+
static MIR_reg_t get_arg_reg (MIR_type_t arg_type, size_t *int_arg_num, size_t *fp_arg_num,
MIR_insn_code_t *mov_code) {
MIR_reg_t arg_reg;
@@ -118,42 +156,17 @@ static MIR_reg_t get_arg_reg (MIR_type_t arg_type, size_t *int_arg_num, size_t *
arg_reg = MIR_NON_HARD_REG;
*mov_code = MIR_LDMOV;
} else if (arg_type == MIR_T_F || arg_type == MIR_T_D) {
- switch (*fp_arg_num) {
- case 0:
- case 1:
- case 2:
- case 3:
-#ifndef _WIN64
- case 4:
- case 5:
- case 6:
- case 7:
-#endif
- arg_reg = XMM0_HARD_REG + *fp_arg_num;
- break;
- default: arg_reg = MIR_NON_HARD_REG; break;
- }
+ arg_reg = get_fp_arg_reg(*fp_arg_num);
(*fp_arg_num)++;
- *mov_code = arg_type == MIR_T_F ? MIR_FMOV : MIR_DMOV;
- } else {
- switch (*int_arg_num
#ifdef _WIN64
- + 2
+ (*int_arg_num)++; /* arg slot used by fp, skip int register */
#endif
- ) {
- case 0: arg_reg = DI_HARD_REG; break;
- case 1: arg_reg = SI_HARD_REG; break;
+ *mov_code = arg_type == MIR_T_F ? MIR_FMOV : MIR_DMOV;
+ } else {
+ arg_reg = get_int_arg_reg(*int_arg_num);
#ifdef _WIN64
- case 2: arg_reg = CX_HARD_REG; break;
- case 3: arg_reg = DX_HARD_REG; break;
-#else
- case 2: arg_reg = DX_HARD_REG; break;
- case 3: arg_reg = CX_HARD_REG; break;
+ (*fp_arg_num)++; /* arg slot used by int, skip fp register */
#endif
- case 4: arg_reg = R8_HARD_REG; break;
- case 5: arg_reg = R9_HARD_REG; break;
- default: arg_reg = MIR_NON_HARD_REG; break;
- }
(*int_arg_num)++;
*mov_code = MIR_MOV;
}
@@ -185,6 +198,9 @@ static void machinize_call (MIR_context_t ctx, MIR_insn_t call_insn) {
nargs = VARR_LENGTH (MIR_var_t, proto->args);
arg_vars = VARR_ADDR (MIR_var_t, proto->args);
}
+#ifdef _WIN64
+ if (nargs > 4 || proto->vararg_p) mem_size = 32; /* spill space for register args */
+#endif
if (call_insn->ops[1].mode != MIR_OP_REG && call_insn->ops[1].mode != MIR_OP_HARD_REG) {
temp_op = MIR_new_reg_op (ctx, gen_new_temp_reg (ctx, MIR_T_I64, func));
new_insn = MIR_new_insn (ctx, MIR_MOV, temp_op, call_insn->ops[1]);
@@ -220,6 +236,21 @@ static void machinize_call (MIR_context_t ctx, MIR_insn_t call_insn) {
new_insn = MIR_new_insn (ctx, new_insn_code, arg_reg_op, arg_op);
gen_add_insn_before (ctx, call_insn, new_insn);
call_insn->ops[i] = arg_reg_op;
+#ifdef _WIN64
+ /* copy fp reg varargs into corresponding int regs */
+ if (proto->vararg_p && type == MIR_T_D) {
+ gen_assert (int_arg_num > 0 && int_arg_num <= 4);
+ arg_reg = get_int_arg_reg (int_arg_num - 1);
+ setup_call_hard_reg_args (call_insn, arg_reg);
+ /* mir does not support moving fp to int regs directly, spill and load them instead */
+ mem_op = _MIR_new_hard_reg_mem_op (ctx, MIR_T_D, 8, SP_HARD_REG, MIR_NON_HARD_REG, 1);
+ new_insn = MIR_new_insn (ctx, MIR_DMOV, mem_op, arg_op);
+ gen_add_insn_before (ctx, call_insn, new_insn);
+ mem_op = _MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, 8, SP_HARD_REG, MIR_NON_HARD_REG, 1);
+ new_insn = MIR_new_insn (ctx, MIR_MOV, _MIR_new_hard_reg_op (ctx, arg_reg), mem_op);
+ gen_add_insn_before (ctx, call_insn, new_insn);
+ }
+#endif
} else { /* put arguments on the stack */
mem_type = type == MIR_T_F || type == MIR_T_D || type == MIR_T_LD ? type : MIR_T_I64;
new_insn_code
@@ -237,12 +268,14 @@ static void machinize_call (MIR_context_t ctx, MIR_insn_t call_insn) {
if (ext_insn != NULL) gen_add_insn_after (ctx, prev_call_insn, ext_insn);
}
}
+#ifndef _WIN64
if (proto->vararg_p) {
setup_call_hard_reg_args (call_insn, AX_HARD_REG);
new_insn = MIR_new_insn (ctx, MIR_MOV, _MIR_new_hard_reg_op (ctx, AX_HARD_REG),
MIR_new_int_op (ctx, xmm_args));
gen_add_insn_before (ctx, call_insn, new_insn);
}
+#endif
n_iregs = n_xregs = n_fregs = 0;
for (size_t i = 0; i < proto->nres; i++) {
ret_reg_op = call_insn->ops[i + 2];
@@ -417,7 +450,7 @@ struct target_ctx {
#define abs_address_locs gen_ctx->target_ctx->abs_address_locs
#define relocs gen_ctx->target_ctx->relocs
-static void machinize (MIR_context_t ctx) {
+static void target_machinize (MIR_context_t ctx) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
MIR_func_t func;
MIR_type_t type, mem_type, res_type;
@@ -451,7 +484,7 @@ static void machinize (MIR_context_t ctx) {
mem_op = _MIR_new_hard_reg_mem_op (ctx, mem_type,
mem_size + 8 /* ret */
+ start_sp_from_bp_offset,
- BP_HARD_REG, MIR_NON_HARD_REG, 1);
+ FP_HARD_REG, MIR_NON_HARD_REG, 1);
new_insn = MIR_new_insn (ctx, new_insn_code, MIR_new_reg_op (ctx, i + 1), mem_op);
MIR_prepend_insn (ctx, curr_func_item, new_insn);
next_insn = DLIST_NEXT (MIR_insn_t, new_insn);
@@ -507,12 +540,12 @@ static void machinize (MIR_context_t ctx) {
gen_mov (ctx, insn, MIR_MOV, MIR_new_mem_op (ctx, MIR_T_U32, 4, va_reg, 0, 1),
MIR_new_int_op (ctx, fp_offset));
/* overflow_arg_area_reg: treg = start sp + 8; mem64[va_reg + 8] = treg */
- new_insn = MIR_new_insn (ctx, MIR_ADD, treg_op, _MIR_new_hard_reg_op (ctx, BP_HARD_REG),
+ new_insn = MIR_new_insn (ctx, MIR_ADD, treg_op, _MIR_new_hard_reg_op (ctx, FP_HARD_REG),
MIR_new_int_op (ctx, 8 /*ret*/ + start_sp_from_bp_offset));
gen_add_insn_before (ctx, insn, new_insn);
gen_mov (ctx, insn, MIR_MOV, MIR_new_mem_op (ctx, MIR_T_I64, 8, va_reg, 0, 1), treg_op);
/* reg_save_area: treg = start sp - reg_save_area_size; mem64[va_reg + 16] = treg */
- new_insn = MIR_new_insn (ctx, MIR_ADD, treg_op, _MIR_new_hard_reg_op (ctx, BP_HARD_REG),
+ new_insn = MIR_new_insn (ctx, MIR_ADD, treg_op, _MIR_new_hard_reg_op (ctx, FP_HARD_REG),
MIR_new_int_op (ctx, -reg_save_area_size));
gen_add_insn_before (ctx, insn, new_insn);
gen_mov (ctx, insn, MIR_MOV, MIR_new_mem_op (ctx, MIR_T_I64, 16, va_reg, 0, 1), treg_op);
@@ -637,8 +670,8 @@ static void dsave (MIR_context_t ctx, MIR_insn_t anchor, int disp, MIR_reg_t har
_MIR_new_hard_reg_op (ctx, hard_reg));
}
-static void make_prolog_epilog (MIR_context_t ctx, bitmap_t used_hard_regs,
- size_t stack_slots_num) {
+static void target_make_prolog_epilog (MIR_context_t ctx, bitmap_t used_hard_regs,
+ size_t stack_slots_num) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
MIR_func_t func;
MIR_insn_t anchor, new_insn;
@@ -649,12 +682,12 @@ static void make_prolog_epilog (MIR_context_t ctx, bitmap_t used_hard_regs,
assert (curr_func_item->item_type == MIR_func_item);
func = curr_func_item->u.func;
for (i = saved_hard_regs_num = 0; i <= MAX_HARD_REG; i++)
- if (!call_used_hard_reg_p (i) && bitmap_bit_p (used_hard_regs, i)) saved_hard_regs_num++;
+ if (!target_call_used_hard_reg_p (i) && bitmap_bit_p (used_hard_regs, i)) saved_hard_regs_num++;
if (leaf_p && !alloca_p && saved_hard_regs_num == 0 && !func->vararg_p && stack_slots_num == 0)
return;
sp_reg_op.mode = fp_reg_op.mode = MIR_OP_HARD_REG;
sp_reg_op.u.hard_reg = SP_HARD_REG;
- fp_reg_op.u.hard_reg = BP_HARD_REG;
+ fp_reg_op.u.hard_reg = FP_HARD_REG;
/* Prologue: */
anchor = DLIST_HEAD (MIR_insn_t, func->insns);
new_insn
@@ -694,12 +727,12 @@ static void make_prolog_epilog (MIR_context_t ctx, bitmap_t used_hard_regs,
bp_saved_reg_offset = block_size + (func->vararg_p ? reg_save_area_size : 0);
/* Saving callee saved hard registers: */
for (i = n = 0; i <= MAX_HARD_REG; i++)
- if (!call_used_hard_reg_p (i) && bitmap_bit_p (used_hard_regs, i)) {
+ if (!target_call_used_hard_reg_p (i) && bitmap_bit_p (used_hard_regs, i)) {
assert (i <= R15_HARD_REG); /* xmm regs are always callee-clobbered */
new_insn = MIR_new_insn (ctx, MIR_MOV,
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64,
(int64_t) (n++ * 8) - bp_saved_reg_offset,
- BP_HARD_REG, MIR_NON_HARD_REG, 1),
+ FP_HARD_REG, MIR_NON_HARD_REG, 1),
_MIR_new_hard_reg_op (ctx, i));
gen_add_insn_before (ctx, anchor, new_insn); /* disp(sp) = saved hard reg */
}
@@ -707,11 +740,11 @@ static void make_prolog_epilog (MIR_context_t ctx, bitmap_t used_hard_regs,
anchor = DLIST_TAIL (MIR_insn_t, func->insns);
/* Restoring hard registers: */
for (i = n = 0; i <= MAX_HARD_REG; i++)
- if (!call_used_hard_reg_p (i) && bitmap_bit_p (used_hard_regs, i)) {
+ if (!target_call_used_hard_reg_p (i) && bitmap_bit_p (used_hard_regs, i)) {
new_insn = MIR_new_insn (ctx, MIR_MOV, _MIR_new_hard_reg_op (ctx, i),
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64,
(int64_t) (n++ * 8) - bp_saved_reg_offset,
- BP_HARD_REG, MIR_NON_HARD_REG, 1));
+ FP_HARD_REG, MIR_NON_HARD_REG, 1));
gen_add_insn_before (ctx, anchor, new_insn); /* hard reg = disp(sp) */
}
new_insn = MIR_new_insn (ctx, MIR_ADD, sp_reg_op, fp_reg_op, MIR_new_int_op (ctx, 8));
@@ -743,7 +776,7 @@ struct pattern {
l - label which can be present by 32-bit
[0-9] - an operand matching n-th operand (n should be less than given operand number)
- Remmeber we have no float or (long) double immediate at this stage. They are represented by
+ Remember we have no float or (long) double immediate at this stage. They are represented by
a reference to data item. */
const char *pattern;
/* Replacement elements:
@@ -1092,7 +1125,7 @@ static const struct pattern patterns[] = {
{MIR_RET, "$", "C3"}, /* ret ax, dx, xmm0, xmm1, st0, st1 */
};
-static void get_early_clobbered_hard_reg (MIR_insn_t insn, MIR_reg_t *hr1, MIR_reg_t *hr2) {
+static void target_get_early_clobbered_hard_regs (MIR_insn_t insn, MIR_reg_t *hr1, MIR_reg_t *hr2) {
MIR_insn_code_t code = insn->code;
*hr1 = *hr2 = MIR_NON_HARD_REG;
@@ -1807,7 +1840,7 @@ static uint8_t MIR_UNUSED get_short_jump_opcode (uint8_t *long_jump_opcode) {
return long_jump_opcode[1] - 0x10;
}
-static int insn_ok_p (MIR_context_t ctx, MIR_insn_t insn) {
+static int target_insn_ok_p (MIR_context_t ctx, MIR_insn_t insn) {
return find_insn_pattern_replacement (ctx, insn) != NULL;
}
diff --git a/mir/mir-gen.c b/mir/mir-gen.c
index 9fa3cec..212cb14 100644
--- a/mir/mir-gen.c
+++ b/mir/mir-gen.c
@@ -9,24 +9,37 @@
---------------- ----------- | Elimination | | Elimination |
------------------ -------------
|
- v
- ------------- ------------ --------- ----------- ----------------------
- | Build Live |<---| Build Live |<---| Finding |<---| Machinize |<--| Sparse Conditional |
- | Ranges | | Info | | Loops | ----------- | Constant Propagation |
- ------------- ------------ --------- ----------------------
- |
- v
- --------- --------- --------- ------------- ---------------
- | Assign |-->| Rewrite |-->| Combine |-->| Dead Code |--->| Generate |---> Machine
- --------- --------- --------- | Elimination | | machine insns | Insns
- ------------- ---------------
-
+ V
+ ---------------- ------------ --------- ----------- ------------
+ | Loop Invariant | | Reaching | | Finding | | Variable | | Reaching |
+ | Code Motion |<--| Definitons |<--| Loops |<--| Renaming |<--| Definitons |
+ ---------------- | Analysis | --------- ----------- | Analysis |
+ | ------------ ------------
+ V
+ ---------------------- ----------- --------- ------------ -------------
+ | Sparse Conditional |-->| Machinize |-->| Finding |-->| Build Live |-->| Build Live |
+ | Constant Propagation | ----------- | Loops | | Info | | Ranges |
+ ---------------------- --------- ------------ -------------
+ |
+ V
+ --------------- ------------- --------- --------- ---------
+ Machine <--| Generate |<--| Dead Code |<--| Combine |<--| Rewrite |<--| Assign |
+ Insns | machine insns | | Elimination | --------- --------- ---------
+ --------------- ------------
Simplify: Lowering MIR (in mir.c).
- Build CGF: Builing Control Flow Graph (basic blocks and CFG edges).
- Common Sub-Expression Elimination: Reusing calculated values
+ Build CGF: Building Control Flow Graph (basic blocks and CFG edges).
+ Common Sub-Expression Elimination: Reusing calculated values (it is before SCCP because
+ we need the right value numbering after simplification)
Dead code elimination: Removing insns with unused outputs.
+ Reaching definition Analysis: Analysis required for subsequent variable renaming
+ Variable renaming: Rename disjoint live ranges of variables which is beneficial for
+ register allocation and loop invariant code motion.
+ Finding Loops: Building loop tree which is used in subsequent loop invariant code motion.
+ Reaching definition Analysis: Analysis required for subsequent loop invariant code motion
+ Loop Invariant Code Motion (LICM): Register pressure sensitive moves loop invariant insns out
+ of the loop.
Sparse Conditional Constant Propagation: constant propagation and removing death paths of CFG
Machinize: Machine-dependent code (e.g. in mir-gen-x86_64.c)
transforming MIR for calls ABI, 2-op insns, etc.
@@ -92,14 +105,10 @@ static size_t get_label_disp (MIR_insn_t insn);
static void create_new_bb_insns (MIR_context_t ctx, MIR_insn_t before, MIR_insn_t after,
MIR_insn_t insn_for_bb);
static void gen_delete_insn (MIR_context_t ctx, MIR_insn_t insn);
-static void gen_add_insn_before (MIR_context_t ctx, MIR_insn_t insn, MIR_insn_t before);
-static void gen_add_insn_after (MIR_context_t ctx, MIR_insn_t insn, MIR_insn_t after);
+static void gen_add_insn_before (MIR_context_t ctx, MIR_insn_t before, MIR_insn_t insn);
+static void gen_add_insn_after (MIR_context_t ctx, MIR_insn_t after, MIR_insn_t insn);
static void setup_call_hard_reg_args (MIR_insn_t call_insn, MIR_reg_t hard_reg);
-#ifndef MIR_GEN_DEBUG
-#define MIR_GEN_DEBUG 0
-#endif
-
#ifndef MIR_GEN_CALL_TRACE
#define MIR_GEN_CALL_TRACE 0
#endif
@@ -109,6 +118,9 @@ typedef struct func_cfg *func_cfg_t;
struct target_ctx;
struct data_flow_ctx;
struct cse_ctx;
+struct rdef_ctx;
+struct rename_ctx;
+struct licm_ctx;
struct ccp_ctx;
struct lr_ctx;
struct ra_ctx;
@@ -118,8 +130,9 @@ typedef struct loop_node *loop_node_t;
DEF_VARR (loop_node_t);
struct gen_ctx {
+ unsigned int optimize_level; /* 0:only RA; 1:+combiner; 2: +CSE/CCP (default); >=3: everything */
MIR_item_t curr_func_item;
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
FILE *debug_file;
#endif
bitmap_t insn_to_consider, temp_bitmap, temp_bitmap2, all_vars;
@@ -129,15 +142,20 @@ struct gen_ctx {
struct target_ctx *target_ctx;
struct data_flow_ctx *data_flow_ctx;
struct cse_ctx *cse_ctx;
+ struct rename_ctx *rename_ctx;
+ struct licm_ctx *licm_ctx;
+ struct rdef_ctx *rdef_ctx;
struct ccp_ctx *ccp_ctx;
struct lr_ctx *lr_ctx;
struct ra_ctx *ra_ctx;
struct selection_ctx *selection_ctx;
VARR (loop_node_t) * loop_nodes, *queue_nodes, *loop_entries; /* used in building loop tree */
+ int max_int_hard_regs, max_fp_hard_regs;
};
static inline struct gen_ctx **gen_ctx_loc (MIR_context_t ctx) { return (struct gen_ctx **) ctx; }
+#define optimize_level gen_ctx->optimize_level
#define curr_func_item gen_ctx->curr_func_item
#define debug_file gen_ctx->debug_file
#define insn_to_consider gen_ctx->insn_to_consider
@@ -151,9 +169,15 @@ static inline struct gen_ctx **gen_ctx_loc (MIR_context_t ctx) { return (struct
#define loop_nodes gen_ctx->loop_nodes
#define queue_nodes gen_ctx->queue_nodes
#define loop_entries gen_ctx->loop_entries
+#define max_int_hard_regs gen_ctx->max_int_hard_regs
+#define max_fp_hard_regs gen_ctx->max_fp_hard_regs
#ifdef __x86_64__
#include "mir-gen-x86_64.c"
+#elif defined(__aarch64__)
+#include "mir-gen-aarch64.c"
+#elif defined(__PPC64__)
+#include "mir-gen-ppc64.c"
#else
#error "undefined or unsupported generation target"
#endif
@@ -173,8 +197,9 @@ static void make_io_dup_op_insns (MIR_context_t ctx) {
gen_assert (curr_func_item->item_type == MIR_func_item);
func = curr_func_item->u.func;
- for (i = 0; i < sizeof (io_dup_op_insn_codes) / sizeof (MIR_insn_code_t); i++)
- bitmap_set_bit_p (insn_to_consider, io_dup_op_insn_codes[i]);
+ for (i = 0; target_io_dup_op_insn_codes[i] != MIR_INSN_BOUND; i++)
+ bitmap_set_bit_p (insn_to_consider, target_io_dup_op_insn_codes[i]);
+ if (bitmap_empty_p (insn_to_consider)) return;
for (insn = DLIST_HEAD (MIR_insn_t, func->insns); insn != NULL; insn = next_insn) {
next_insn = DLIST_NEXT (MIR_insn_t, insn);
code = insn->code;
@@ -251,7 +276,8 @@ DEF_DLIST (dead_var_t, dead_var_link);
struct bb_insn {
MIR_insn_t insn;
- unsigned int flag; /* used for CPP */
+ unsigned char flag, flag2; /* used for CCP and LICM */
+ size_t index; /* used for LICM */
DLIST_LINK (bb_insn_t) bb_insn_link;
bb_t bb;
DLIST (dead_var_t) dead_vars;
@@ -262,8 +288,8 @@ struct bb_insn {
DEF_DLIST (bb_insn_t, bb_insn_link);
struct bb {
- size_t index, pre, rpost;
- unsigned int flag : 1; /* used for CPP */
+ size_t index, pre, rpost, bfs; /* preorder, reverse post order, breadth first order */
+ unsigned int flag; /* used for CCP */
DLIST_LINK (bb_t) bb_link;
DLIST (in_edge_t) in_edges;
/* The out edges order: optional fall through bb, optional label bb,
@@ -272,7 +298,9 @@ struct bb {
DLIST (bb_insn_t) bb_insns;
size_t freq;
bitmap_t in, out, gen, kill; /* var bitmaps for different data flow problems */
+ bitmap_t dom_in, dom_out; /* additional var bitmaps LICM */
loop_node_t loop_node;
+ int max_int_pressure, max_fp_pressure;
};
DEF_DLIST (bb_t, bb_link);
@@ -281,12 +309,15 @@ DEF_DLIST_LINK (loop_node_t);
DEF_DLIST_TYPE (loop_node_t);
struct loop_node {
- size_t index;
- bb_t bb; /* NULL for internal tree node */
+ size_t index; /* if BB != NULL, it is index of BB */
+ bb_t bb; /* NULL for internal tree node */
loop_node_t entry;
loop_node_t parent;
+ bb_t preheader; /* used in LICM */
+ unsigned int call_p; /* used in LICM: call is present in the loop */
DLIST (loop_node_t) children;
DLIST_LINK (loop_node_t) children_link;
+ int max_int_pressure, max_fp_pressure;
};
DEF_DLIST_CODE (loop_node_t, children_link);
@@ -337,7 +368,7 @@ typedef struct {
} u;
} const_t;
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
static void print_const (FILE *f, const_t c) {
if (c.uns_p)
fprintf (f, "%" PRIu64, c.u.u);
@@ -475,8 +506,8 @@ static void create_new_bb_insns (MIR_context_t ctx, MIR_insn_t before, MIR_insn_
DLIST_INSERT_AFTER (bb_insn_t, bb->bb_insns, bb_insn, new_bb_insn);
}
} else {
- bb_insn = after->data;
gen_assert (after != NULL);
+ bb_insn = after->data;
insn = (before == NULL ? DLIST_HEAD (MIR_insn_t, curr_func_item->u.func->insns)
: DLIST_NEXT (MIR_insn_t, before));
for (; insn != after; insn = DLIST_NEXT (MIR_insn_t, insn)) {
@@ -497,15 +528,23 @@ static void gen_delete_insn (MIR_context_t ctx, MIR_insn_t insn) {
}
static void gen_add_insn_before (MIR_context_t ctx, MIR_insn_t before, MIR_insn_t insn) {
+ MIR_insn_t insn_for_bb = before;
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ gen_assert (!MIR_branch_code_p (insn->code) && insn->code != MIR_LABEL);
+ if (before->code == MIR_LABEL) {
+ insn_for_bb = DLIST_PREV (MIR_insn_t, before);
+ gen_assert (insn_for_bb == NULL || !MIR_branch_code_p (insn_for_bb->code));
+ }
MIR_insert_insn_before (ctx, curr_func_item, before, insn);
- create_new_bb_insns (ctx, DLIST_PREV (MIR_insn_t, insn), before, before);
+ create_new_bb_insns (ctx, DLIST_PREV (MIR_insn_t, insn), before, insn_for_bb);
}
static void gen_add_insn_after (MIR_context_t ctx, MIR_insn_t after, MIR_insn_t insn) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ gen_assert (insn->code != MIR_LABEL);
+ gen_assert (!MIR_branch_code_p (after->code));
MIR_insert_insn_after (ctx, curr_func_item, after, insn);
create_new_bb_insns (ctx, after, DLIST_NEXT (MIR_insn_t, insn), after);
}
@@ -529,8 +568,9 @@ static size_t get_label_disp (MIR_insn_t insn) {
static bb_t create_bb (MIR_context_t ctx, MIR_insn_t insn) {
bb_t bb = gen_malloc (ctx, sizeof (struct bb));
- bb->pre = bb->rpost = 0;
+ bb->pre = bb->rpost = bb->bfs = 0;
bb->flag = FALSE;
+ bb->loop_node = NULL;
DLIST_INIT (bb_insn_t, bb->bb_insns);
DLIST_INIT (in_edge_t, bb->in_edges);
DLIST_INIT (out_edge_t, bb->out_edges);
@@ -538,6 +578,9 @@ static bb_t create_bb (MIR_context_t ctx, MIR_insn_t insn) {
bb->out = bitmap_create2 (DEFAULT_INIT_BITMAP_BITS_NUM);
bb->gen = bitmap_create2 (DEFAULT_INIT_BITMAP_BITS_NUM);
bb->kill = bitmap_create2 (DEFAULT_INIT_BITMAP_BITS_NUM);
+ bb->dom_in = bitmap_create2 (DEFAULT_INIT_BITMAP_BITS_NUM);
+ bb->dom_out = bitmap_create2 (DEFAULT_INIT_BITMAP_BITS_NUM);
+ bb->max_int_pressure = bb->max_fp_pressure = 0;
if (insn != NULL) add_new_bb_insn (ctx, insn, bb);
return bb;
}
@@ -549,13 +592,18 @@ static void add_bb (MIR_context_t ctx, bb_t bb) {
bb->index = curr_bb_index++;
}
-static edge_t create_edge (MIR_context_t ctx, bb_t src, bb_t dst) {
+static edge_t create_edge (MIR_context_t ctx, bb_t src, bb_t dst, int append_p) {
edge_t e = gen_malloc (ctx, sizeof (struct edge));
e->src = src;
e->dst = dst;
- DLIST_APPEND (in_edge_t, dst->in_edges, e);
- DLIST_APPEND (out_edge_t, src->out_edges, e);
+ if (append_p) {
+ DLIST_APPEND (in_edge_t, dst->in_edges, e);
+ DLIST_APPEND (out_edge_t, src->out_edges, e);
+ } else {
+ DLIST_PREPEND (in_edge_t, dst->in_edges, e);
+ DLIST_PREPEND (out_edge_t, src->out_edges, e);
+ }
e->back_edge_p = e->skipped_p = FALSE;
return e;
}
@@ -583,6 +631,8 @@ static void delete_bb (MIR_context_t ctx, bb_t bb) {
bitmap_destroy (bb->out);
bitmap_destroy (bb->gen);
bitmap_destroy (bb->kill);
+ bitmap_destroy (bb->dom_in);
+ bitmap_destroy (bb->dom_out);
free (bb);
}
@@ -612,6 +662,18 @@ static loop_node_t top_loop_node (bb_t bb) {
if (loop_node->parent == NULL) return loop_node;
}
+static int in_loop_p (loop_node_t node, loop_node_t loop) {
+ for (loop_node_t curr_node = node; curr_node != NULL; curr_node = curr_node->parent)
+ if (curr_node == loop) return TRUE;
+ return FALSE;
+}
+
+static int bb_loop_exit_p (MIR_context_t ctx, bb_t bb, loop_node_t loop) {
+ for (edge_t e = DLIST_HEAD (out_edge_t, bb->out_edges); e != NULL; e = DLIST_PREV (out_edge_t, e))
+ if (!in_loop_p (e->dst->loop_node, loop)) return TRUE;
+ return FALSE;
+}
+
static loop_node_t create_loop_node (MIR_context_t ctx, bb_t bb) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
loop_node_t loop_node = gen_malloc (ctx, sizeof (struct loop_node));
@@ -621,11 +683,13 @@ static loop_node_t create_loop_node (MIR_context_t ctx, bb_t bb) {
if (bb != NULL) bb->loop_node = loop_node;
loop_node->parent = NULL;
loop_node->entry = NULL;
+ loop_node->preheader = NULL;
+ loop_node->max_int_pressure = loop_node->max_fp_pressure = 0;
DLIST_INIT (loop_node_t, loop_node->children);
return loop_node;
}
-static void process_loop (MIR_context_t ctx, bb_t entry_bb) {
+static int process_loop (MIR_context_t ctx, bb_t entry_bb) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
edge_t e;
loop_node_t loop_node, new_loop_node, queue_node;
@@ -645,7 +709,7 @@ static void process_loop (MIR_context_t ctx, bb_t entry_bb) {
queue_node = VARR_POP (loop_node_t, queue_nodes);
if ((queue_bb = queue_node->bb) == NULL) queue_bb = queue_node->entry->bb; /* subloop */
/* entry block is achieved which means multiple entry loop -- just ignore */
- if (queue_bb == DLIST_HEAD (bb_t, curr_cfg->bbs)) return;
+ if (queue_bb == DLIST_HEAD (bb_t, curr_cfg->bbs)) return FALSE;
for (e = DLIST_HEAD (in_edge_t, queue_bb->in_edges); e != NULL; e = DLIST_NEXT (in_edge_t, e))
if (e->src != entry_bb) {
loop_node = top_loop_node (e->src);
@@ -663,6 +727,23 @@ static void process_loop (MIR_context_t ctx, bb_t entry_bb) {
DLIST_APPEND (loop_node_t, new_loop_node->children, loop_node);
loop_node->parent = new_loop_node;
}
+ return TRUE;
+}
+
+static void setup_loop_pressure (MIR_context_t ctx, loop_node_t loop_node) {
+ for (loop_node_t curr = DLIST_HEAD (loop_node_t, loop_node->children); curr != NULL;
+ curr = DLIST_NEXT (loop_node_t, curr)) {
+ if (curr->bb == NULL) {
+ setup_loop_pressure (ctx, curr);
+ } else {
+ curr->max_int_pressure = curr->bb->max_int_pressure;
+ curr->max_fp_pressure = curr->bb->max_fp_pressure;
+ }
+ if (loop_node->max_int_pressure < curr->max_int_pressure)
+ loop_node->max_int_pressure = curr->max_int_pressure;
+ if (loop_node->max_fp_pressure < curr->max_fp_pressure)
+ loop_node->max_fp_pressure = curr->max_fp_pressure;
+ }
}
static int compare_bb_loop_nodes (const void *p1, const void *p2) {
@@ -671,10 +752,11 @@ static int compare_bb_loop_nodes (const void *p1, const void *p2) {
return bb1->rpost > bb2->rpost ? -1 : bb1->rpost < bb2->rpost ? 1 : 0;
}
-static void build_loop_tree (MIR_context_t ctx) {
+static int build_loop_tree (MIR_context_t ctx) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
loop_node_t loop_node;
edge_t e;
+ int loops_p = FALSE;
curr_loop_node_index = 0;
enumerate_bbs (ctx);
@@ -691,24 +773,29 @@ static void build_loop_tree (MIR_context_t ctx) {
qsort (VARR_ADDR (loop_node_t, loop_entries), VARR_LENGTH (loop_node_t, loop_entries),
sizeof (loop_node_t), compare_bb_loop_nodes);
for (size_t i = 0; i < VARR_LENGTH (loop_node_t, loop_entries); i++)
- process_loop (ctx, VARR_GET (loop_node_t, loop_entries, i)->bb);
+ if (process_loop (ctx, VARR_GET (loop_node_t, loop_entries, i)->bb)) loops_p = TRUE;
curr_cfg->root_loop_node = create_loop_node (ctx, NULL);
for (bb_t bb = DLIST_HEAD (bb_t, curr_cfg->bbs); bb != NULL; bb = DLIST_NEXT (bb_t, bb))
if ((loop_node = top_loop_node (bb)) != curr_cfg->root_loop_node) {
DLIST_APPEND (loop_node_t, curr_cfg->root_loop_node->children, loop_node);
loop_node->parent = curr_cfg->root_loop_node;
}
+ setup_loop_pressure (ctx, curr_cfg->root_loop_node);
+ return loops_p;
}
static void destroy_loop_tree (MIR_context_t ctx, loop_node_t root) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
loop_node_t node, next;
- if (root->bb == NULL)
+ if (root->bb != NULL) {
+ root->bb->loop_node = NULL;
+ } else {
for (node = DLIST_HEAD (loop_node_t, root->children); node != NULL; node = next) {
next = DLIST_NEXT (loop_node_t, node);
destroy_loop_tree (ctx, node);
}
+ }
free (root);
}
@@ -741,6 +828,10 @@ static MIR_reg_t var2reg (struct gen_ctx *gen_ctx, MIR_reg_t var) {
gen_assert (var > MAX_HARD_REG);
return breg2reg (gen_ctx, var - MAX_HARD_REG - 1);
}
+static MIR_reg_t var2breg (struct gen_ctx *gen_ctx, MIR_reg_t var) {
+ gen_assert (var > MAX_HARD_REG);
+ return var - MAX_HARD_REG - 1;
+}
static MIR_reg_t get_nregs (MIR_context_t ctx) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
@@ -766,7 +857,72 @@ static int imm_move_p (MIR_insn_t insn) {
|| insn->ops[1].mode == MIR_OP_LDOUBLE || insn->ops[1].mode == MIR_OP_REF));
}
-#if MIR_GEN_DEBUG
+typedef struct {
+ MIR_insn_t insn;
+ size_t nops, op_num, op_part_num, passed_mem_num;
+} insn_var_iterator_t;
+
+static inline void insn_var_iterator_init (MIR_context_t ctx, insn_var_iterator_t *iter,
+ MIR_insn_t insn) {
+ iter->insn = insn;
+ iter->nops = MIR_insn_nops (ctx, insn);
+ iter->op_num = 0;
+ iter->op_part_num = 0;
+ iter->passed_mem_num = 0;
+}
+
+static inline int insn_var_iterator_next (MIR_context_t ctx, insn_var_iterator_t *iter,
+ MIR_reg_t *var, int *out_p, int *mem_p,
+ size_t *passed_mem_num) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ MIR_op_t op;
+
+ while (iter->op_num < iter->nops) {
+ MIR_insn_op_mode (ctx, iter->insn, iter->op_num, out_p);
+ op = iter->insn->ops[iter->op_num];
+ *mem_p = FALSE;
+ *passed_mem_num = iter->passed_mem_num;
+ while (iter->op_part_num < 2) {
+ if (op.mode == MIR_OP_MEM || op.mode == MIR_OP_HARD_REG_MEM) {
+ *mem_p = TRUE;
+ *passed_mem_num = ++iter->passed_mem_num;
+ *out_p = FALSE;
+ if (op.mode == MIR_OP_MEM) {
+ *var = iter->op_part_num == 0 ? op.u.mem.base : op.u.mem.index;
+ if (*var == 0) {
+ iter->op_part_num++;
+ continue;
+ }
+ *var = reg2var (gen_ctx, *var);
+ } else {
+ *var = iter->op_part_num == 0 ? op.u.hard_reg_mem.base : op.u.hard_reg_mem.index;
+ if (*var == MIR_NON_HARD_REG) {
+ iter->op_part_num++;
+ continue;
+ }
+ }
+ } else if (iter->op_part_num > 0) {
+ break;
+ } else if (op.mode == MIR_OP_REG) {
+ *var = reg2var (gen_ctx, op.u.reg);
+ } else if (op.mode == MIR_OP_HARD_REG) {
+ *var = op.u.hard_reg;
+ } else
+ break;
+ iter->op_part_num++;
+ return TRUE;
+ }
+ iter->op_num++;
+ iter->op_part_num = 0;
+ }
+ return FALSE;
+}
+
+#define FOREACH_INSN_VAR(ctx, iterator, insn, var, out_p, mem_p, passed_mem_num) \
+ for (insn_var_iterator_init (ctx, &iterator, insn); \
+ insn_var_iterator_next (ctx, &iterator, &var, &out_p, &mem_p, &passed_mem_num);)
+
+#if !MIR_NO_GEN_DEBUG
static void output_in_edges (MIR_context_t ctx, bb_t bb) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
edge_t e;
@@ -791,23 +947,21 @@ static void output_out_edges (MIR_context_t ctx, bb_t bb) {
fprintf (debug_file, "\n");
}
-static void output_live_element (size_t nel, void *data) {
- MIR_context_t ctx = data;
- struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
-
- fprintf (debug_file, "%3lu", (unsigned long) nel);
- if (var_is_reg_p (nel))
- fprintf (debug_file, "(%s:%s)",
- MIR_type_str (ctx, MIR_reg_type (ctx, var2reg (gen_ctx, nel), curr_func_item->u.func)),
- MIR_reg_name (ctx, var2reg (gen_ctx, nel), curr_func_item->u.func));
-}
-
-static void output_bitmap (MIR_context_t ctx, const char *head, bitmap_t bm) {
+static void output_bitmap (MIR_context_t ctx, const char *head, bitmap_t bm, int var_p) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ size_t nel;
+ bitmap_iterator_t bi;
if (bm == NULL || bitmap_empty_p (bm)) return;
fprintf (debug_file, "%s", head);
- bitmap_for_each (bm, output_live_element, ctx);
+ FOREACH_BITMAP_BIT (bi, bm, nel) {
+ fprintf (debug_file, " %3lu", (unsigned long) nel);
+ if (var_p && var_is_reg_p (nel))
+ fprintf (debug_file, "(%s:%s)",
+ MIR_type_str (ctx,
+ MIR_reg_type (ctx, var2reg (gen_ctx, nel), curr_func_item->u.func)),
+ MIR_reg_name (ctx, var2reg (gen_ctx, nel), curr_func_item->u.func));
+ }
fprintf (debug_file, "\n");
}
@@ -833,13 +987,20 @@ static void print_bb_insn (MIR_context_t ctx, bb_insn_t bb_insn, int with_notes_
fprintf (debug_file, "\n");
}
-static void print_CFG (MIR_context_t ctx, int bb_p, int insns_p,
+static void print_CFG (MIR_context_t ctx, int bb_p, int pressure_p, int insns_p, int insn_index_p,
void (*bb_info_print_func) (MIR_context_t, bb_t)) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
for (bb_t bb = DLIST_HEAD (bb_t, curr_cfg->bbs); bb != NULL; bb = DLIST_NEXT (bb_t, bb)) {
if (bb_p) {
- fprintf (debug_file, "BB %3lu:\n", (unsigned long) bb->index);
+ fprintf (debug_file, "BB %3lu", (unsigned long) bb->index);
+ if (pressure_p)
+ fprintf (debug_file, " (pressure: int=%d, fp=%d)", bb->max_int_pressure,
+ bb->max_fp_pressure);
+ if (bb->loop_node == NULL)
+ fprintf (debug_file, "\n");
+ else
+ fprintf (debug_file, " (loop%3lu):\n", (unsigned long) bb->loop_node->parent->index);
output_in_edges (ctx, bb);
output_out_edges (ctx, bb);
if (bb_info_print_func != NULL) {
@@ -849,33 +1010,42 @@ static void print_CFG (MIR_context_t ctx, int bb_p, int insns_p,
}
if (insns_p) {
for (bb_insn_t bb_insn = DLIST_HEAD (bb_insn_t, bb->bb_insns); bb_insn != NULL;
- bb_insn = DLIST_NEXT (bb_insn_t, bb_insn))
+ bb_insn = DLIST_NEXT (bb_insn_t, bb_insn)) {
+ if (insn_index_p) fprintf (debug_file, " %-5lu", (unsigned long) bb_insn->index);
print_bb_insn (ctx, bb_insn, TRUE);
+ }
fprintf (debug_file, "\n");
}
}
}
-static void print_loop_subtree (MIR_context_t ctx, loop_node_t root, int level) {
+static void print_loop_subtree (MIR_context_t ctx, loop_node_t root, int level, int bb_p) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ if (root->bb != NULL && !bb_p) return;
for (int i = 0; i < 2 * level + 2; i++) fprintf (debug_file, " ");
if (root->bb != NULL) {
gen_assert (DLIST_HEAD (loop_node_t, root->children) == NULL);
- fprintf (debug_file, "BB%-3lu\n", (unsigned long) root->bb->index);
+ fprintf (debug_file, "BB%-3lu (pressure: int=%d, fp=%d)\n", (unsigned long) root->bb->index,
+ root->max_int_pressure, root->max_fp_pressure);
return;
}
- fprintf (debug_file, "Loop%-3lu\n", (unsigned long) root->index);
+ fprintf (debug_file, "Loop%3lu (pressure: int=%d, fp=%d)", (unsigned long) root->index,
+ root->max_int_pressure, root->max_fp_pressure);
+ if (curr_cfg->root_loop_node == root)
+ fprintf (debug_file, ":\n");
+ else
+ fprintf (debug_file, " (entry - bb%lu):\n", (unsigned long) root->entry->bb->index);
for (loop_node_t node = DLIST_HEAD (loop_node_t, root->children); node != NULL;
node = DLIST_NEXT (loop_node_t, node))
- print_loop_subtree (ctx, node, level + 1);
+ print_loop_subtree (ctx, node, level + 1, bb_p);
}
-static void print_loop_tree (MIR_context_t ctx) {
+static void print_loop_tree (MIR_context_t ctx, int bb_p) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
- fprintf (debug_file, "Loop Tree:\n");
- print_loop_subtree (ctx, curr_cfg->root_loop_node, 0);
+ fprintf (debug_file, "Loop Tree\n");
+ print_loop_subtree (ctx, curr_cfg->root_loop_node, 0, bb_p);
}
#endif
@@ -931,7 +1101,7 @@ static void build_func_cfg (MIR_context_t ctx) {
prev_bb = bb;
bb = create_bb (ctx, NULL);
add_bb (ctx, bb);
- create_edge (ctx, prev_bb, bb);
+ create_edge (ctx, prev_bb, bb, TRUE);
}
}
for (; insn != NULL; insn = next_insn) {
@@ -948,7 +1118,7 @@ static void build_func_cfg (MIR_context_t ctx) {
bb = create_bb (ctx, next_insn);
add_bb (ctx, bb);
if (insn->code != MIR_JMP && insn->code != MIR_RET && insn->code != MIR_SWITCH)
- create_edge (ctx, prev_bb, bb);
+ create_edge (ctx, prev_bb, bb, TRUE);
}
for (i = 0; i < nops; i++)
if ((op = &insn->ops[i])->mode == MIR_OP_LABEL) {
@@ -957,7 +1127,7 @@ static void build_func_cfg (MIR_context_t ctx) {
label_bb_insn = op->u.label->data;
}
bb_insn = insn->data;
- create_edge (ctx, bb_insn->bb, label_bb_insn->bb);
+ create_edge (ctx, bb_insn->bb, label_bb_insn->bb, TRUE);
} else if (op->mode == MIR_OP_REG) {
update_min_max_reg (ctx, op->u.reg);
} else if (op->mode == MIR_OP_MEM) {
@@ -968,9 +1138,9 @@ static void build_func_cfg (MIR_context_t ctx) {
/* Add additional edges with entry and exit */
for (bb = DLIST_HEAD (bb_t, curr_cfg->bbs); bb != NULL; bb = DLIST_NEXT (bb_t, bb)) {
if (bb != entry_bb && DLIST_HEAD (in_edge_t, bb->in_edges) == NULL)
- create_edge (ctx, entry_bb, bb);
+ create_edge (ctx, entry_bb, bb, TRUE);
if (bb != exit_bb && DLIST_HEAD (out_edge_t, bb->out_edges) == NULL)
- create_edge (ctx, bb, exit_bb);
+ create_edge (ctx, bb, exit_bb, TRUE);
}
enumerate_bbs (ctx);
VARR_CREATE (reg_info_t, curr_cfg->breg_info, 128);
@@ -1067,7 +1237,8 @@ struct data_flow_ctx {
#define bb_to_consider gen_ctx->data_flow_ctx->bb_to_consider
static void solve_dataflow (MIR_context_t ctx, int forward_p, void (*con_func_0) (bb_t),
- int (*con_func_n) (MIR_context_t, bb_t), int (*trans_func) (bb_t)) {
+ int (*con_func_n) (MIR_context_t, bb_t),
+ int (*trans_func) (MIR_context_t, bb_t)) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
size_t i, iter;
bb_t bb, *addr;
@@ -1099,7 +1270,7 @@ static void solve_dataflow (MIR_context_t ctx, int forward_p, void (*con_func_0)
else
changed_p |= con_func_n (ctx, bb);
}
- if (changed_p && trans_func (bb)) {
+ if (changed_p && trans_func (ctx, bb)) {
if (forward_p) {
for (e = DLIST_HEAD (out_edge_t, bb->out_edges); e != NULL;
e = DLIST_NEXT (out_edge_t, e))
@@ -1146,9 +1317,8 @@ static void finish_data_flow (MIR_context_t ctx) {
#define av_gen gen
typedef struct expr {
- MIR_insn_t insn; /* operation and input operands are the expr keys */
- unsigned int num; /* the expression number (0, 1 ...) */
- MIR_context_t ctx;
+ MIR_insn_t insn; /* operation and input operands are the expr keys */
+ unsigned int num; /* the expression number (0, 1 ...) */
MIR_reg_t temp_reg; /* ??? */
} * expr_t;
@@ -1176,17 +1346,17 @@ static int op_eq (MIR_context_t ctx, MIR_op_t op1, MIR_op_t op2) {
return MIR_op_eq_p (ctx, op1, op2);
}
-static int expr_eq (expr_t e1, expr_t e2) {
+static int expr_eq (expr_t e1, expr_t e2, void *arg) {
+ MIR_context_t ctx = arg;
size_t i, nops;
int out_p;
- assert (e1->ctx == e2->ctx);
if (e1->insn->code != e2->insn->code) return FALSE;
- nops = MIR_insn_nops (e1->ctx, e1->insn);
+ nops = MIR_insn_nops (ctx, e1->insn);
for (i = 0; i < nops; i++) {
- MIR_insn_op_mode (e1->ctx, e1->insn, i, &out_p);
+ MIR_insn_op_mode (ctx, e1->insn, i, &out_p);
if (out_p) continue;
- if (!op_eq (e1->ctx, e1->insn->ops[i], e2->insn->ops[i])) return FALSE;
+ if (!op_eq (ctx, e1->insn->ops[i], e2->insn->ops[i])) return FALSE;
}
return TRUE;
}
@@ -1195,17 +1365,18 @@ static htab_hash_t add_op_hash (MIR_context_t ctx, htab_hash_t h, MIR_op_t op) {
return MIR_op_hash_step (ctx, h, op);
}
-static htab_hash_t expr_hash (expr_t e) {
+static htab_hash_t expr_hash (expr_t e, void *arg) {
+ MIR_context_t ctx = arg;
size_t i, nops;
int out_p;
htab_hash_t h = mir_hash_init (0x42);
h = mir_hash_step (h, (uint64_t) e->insn->code);
- nops = MIR_insn_nops (e->ctx, e->insn);
+ nops = MIR_insn_nops (ctx, e->insn);
for (i = 0; i < nops; i++) {
- MIR_insn_op_mode (e->ctx, e->insn, i, &out_p);
+ MIR_insn_op_mode (ctx, e->insn, i, &out_p);
if (out_p) continue;
- h = add_op_hash (e->ctx, h, e->insn->ops[i]);
+ h = add_op_hash (ctx, h, e->insn->ops[i]);
}
return mir_hash_finish (h);
}
@@ -1215,7 +1386,6 @@ static int find_expr (MIR_context_t ctx, MIR_insn_t insn, expr_t *e) {
struct expr es;
es.insn = insn;
- es.ctx = ctx;
return HTAB_DO (expr_t, expr_tab, &es, HTAB_FIND, *e);
}
@@ -1275,7 +1445,6 @@ static expr_t add_expr (MIR_context_t ctx, MIR_insn_t insn) {
gen_assert (!MIR_call_code_p (insn->code) && insn->code != MIR_RET);
e->insn = insn;
e->num = VARR_LENGTH (expr_t, exprs);
- e->ctx = ctx;
mode = MIR_insn_op_mode (ctx, insn, 0, &out_p);
e->temp_reg
= gen_new_temp_reg (ctx,
@@ -1309,7 +1478,7 @@ static int cse_con_func_n (MIR_context_t ctx, bb_t bb) {
return !bitmap_equal_p (bb->av_in, prev_av_in);
}
-static int cse_trans_func (bb_t bb) {
+static int cse_trans_func (MIR_context_t ctx, bb_t bb) {
return bitmap_ior_and_compl (bb->av_out, bb->av_gen, bb->av_in, bb->av_kill);
}
@@ -1325,7 +1494,7 @@ static void create_exprs (MIR_context_t ctx) {
if (!MIR_branch_code_p (insn->code) && insn->code != MIR_RET && insn->code != MIR_SWITCH
&& insn->code != MIR_LABEL && !MIR_call_code_p (insn->code) && insn->code != MIR_ALLOCA
&& insn->code != MIR_BSTART && insn->code != MIR_BEND && insn->code != MIR_VA_START
- && insn->code != MIR_VA_END && !move_p (insn)
+ && insn->code != MIR_VA_ARG && insn->code != MIR_VA_END && !move_p (insn)
&& (!imm_move_p (insn) || insn->ops[1].mode == MIR_OP_REF)
/* After simplification we have only one store form: mem = reg.
It is unprofitable to add the reg as an expression. */
@@ -1335,8 +1504,7 @@ static void create_exprs (MIR_context_t ctx) {
}
}
-static void make_obsolete_var_exprs (size_t nel, void *data) {
- MIR_context_t ctx = data;
+static void make_obsolete_var_exprs (MIR_context_t ctx, size_t nel) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
MIR_reg_t var = nel;
bitmap_t b;
@@ -1350,10 +1518,16 @@ static void make_obsolete_var_exprs (size_t nel, void *data) {
static void create_av_bitmaps (MIR_context_t ctx) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ size_t nel, exprs_num = VARR_LENGTH (expr_t, exprs);
+ bitmap_t all_expr_bitmap = temp_bitmap2;
+ bitmap_iterator_t bi;
+ bitmap_clear (all_expr_bitmap);
+ bitmap_set_bit_range_p (all_expr_bitmap, 0, exprs_num);
for (bb_t bb = DLIST_HEAD (bb_t, curr_cfg->bbs); bb != NULL; bb = DLIST_NEXT (bb_t, bb)) {
bitmap_clear (bb->av_in);
bitmap_clear (bb->av_out);
+ if (bb != DLIST_HEAD (bb_t, curr_cfg->bbs)) bitmap_copy (bb->av_out, all_expr_bitmap);
bitmap_clear (bb->av_kill);
bitmap_clear (bb->av_gen);
curr_bb_av_gen = bb->av_gen;
@@ -1371,8 +1545,8 @@ static void create_av_bitmaps (MIR_context_t ctx) {
|| insn->code == MIR_SWITCH || insn->code == MIR_LABEL)
continue;
if (!MIR_call_code_p (insn->code) && insn->code != MIR_ALLOCA && insn->code != MIR_BSTART
- && insn->code != MIR_BEND && insn->code != MIR_VA_START && insn->code != MIR_VA_END
- && !move_p (insn)
+ && insn->code != MIR_BEND && insn->code != MIR_VA_START && insn->code != MIR_VA_ARG
+ && insn->code != MIR_VA_END && !move_p (insn)
&& (!imm_move_p (insn) || insn->ops[1].mode == MIR_OP_REF)
/* See create_expr comments: */
&& insn->ops[0].mode != MIR_OP_MEM && insn->ops[0].mode != MIR_OP_HARD_REG_MEM) {
@@ -1382,11 +1556,12 @@ static void create_av_bitmaps (MIR_context_t ctx) {
}
bitmap_set_bit_p (bb->av_gen, e->num);
}
- get_early_clobbered_hard_reg (insn, &early_clobbered_hard_reg1, &early_clobbered_hard_reg2);
+ target_get_early_clobbered_hard_regs (insn, &early_clobbered_hard_reg1,
+ &early_clobbered_hard_reg2);
if (early_clobbered_hard_reg1 != MIR_NON_HARD_REG)
- make_obsolete_var_exprs (early_clobbered_hard_reg1, ctx);
+ make_obsolete_var_exprs (ctx, early_clobbered_hard_reg1);
if (early_clobbered_hard_reg2 != MIR_NON_HARD_REG)
- make_obsolete_var_exprs (early_clobbered_hard_reg2, ctx);
+ make_obsolete_var_exprs (ctx, early_clobbered_hard_reg2);
nops = MIR_insn_nops (ctx, insn);
for (i = 0; i < nops; i++) {
MIR_insn_op_mode (ctx, insn, i, &out_p);
@@ -1396,15 +1571,16 @@ static void create_av_bitmaps (MIR_context_t ctx) {
bitmap_and_compl (bb->av_gen, bb->av_gen, memory_exprs);
bitmap_ior (bb->av_kill, bb->av_kill, memory_exprs);
} else if (op.mode == MIR_OP_REG || op.mode == MIR_OP_HARD_REG) {
- make_obsolete_var_exprs (op.mode == MIR_OP_HARD_REG ? op.u.hard_reg
- : reg2var (gen_ctx, op.u.reg),
- ctx);
+ make_obsolete_var_exprs (ctx, op.mode == MIR_OP_HARD_REG ? op.u.hard_reg
+ : reg2var (gen_ctx, op.u.reg));
}
}
if (MIR_call_code_p (insn->code)) {
gen_assert (bb_insn->call_hard_reg_args != NULL);
- bitmap_for_each (bb_insn->call_hard_reg_args, make_obsolete_var_exprs, ctx);
- bitmap_for_each (call_used_hard_regs, make_obsolete_var_exprs, ctx);
+ FOREACH_BITMAP_BIT (bi, bb_insn->call_hard_reg_args, nel) {
+ make_obsolete_var_exprs (ctx, nel);
+ }
+ FOREACH_BITMAP_BIT (bi, call_used_hard_regs, nel) { make_obsolete_var_exprs (ctx, nel); }
bitmap_and_compl (bb->av_gen, bb->av_gen, memory_exprs);
bitmap_ior (bb->av_kill, bb->av_kill, memory_exprs);
}
@@ -1416,6 +1592,8 @@ static void cse_modify (MIR_context_t ctx) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
bb_insn_t bb_insn, new_bb_insn, next_bb_insn;
bitmap_t av = temp_bitmap;
+ size_t nel;
+ bitmap_iterator_t bi;
curr_bb_av_gen = temp_bitmap;
curr_bb_av_kill = NULL;
@@ -1436,8 +1614,8 @@ static void cse_modify (MIR_context_t ctx) {
|| insn->code == MIR_LABEL)
continue;
if (!MIR_call_code_p (insn->code) && insn->code != MIR_ALLOCA && insn->code != MIR_BSTART
- && insn->code != MIR_BEND && insn->code != MIR_VA_START && insn->code != MIR_VA_END
- && !move_p (insn)
+ && insn->code != MIR_BEND && insn->code != MIR_VA_START && insn->code != MIR_VA_ARG
+ && insn->code != MIR_VA_END && !move_p (insn)
&& (!imm_move_p (insn) || insn->ops[1].mode == MIR_OP_REF)
/* See create_expr comments: */
&& insn->ops[0].mode != MIR_OP_MEM && insn->ops[0].mode != MIR_OP_HARD_REG_MEM) {
@@ -1461,7 +1639,7 @@ static void cse_modify (MIR_context_t ctx) {
MIR_insert_insn_after (ctx, curr_func_item, insn, new_insn);
DLIST_INSERT_AFTER (bb_insn_t, bb->bb_insns, bb_insn, new_bb_insn);
next_bb_insn = DLIST_NEXT (bb_insn_t, new_bb_insn);
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) {
fprintf (debug_file, " adding insn ");
MIR_output_insn (ctx, debug_file, new_insn, curr_func_item->u.func, FALSE);
@@ -1472,7 +1650,7 @@ static void cse_modify (MIR_context_t ctx) {
} else {
new_insn = MIR_new_insn (ctx, move_code, insn->ops[0], op);
gen_add_insn_after (ctx, insn, new_insn);
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) {
fprintf (debug_file, " adding insn ");
MIR_output_insn (ctx, debug_file, new_insn, curr_func_item->u.func, FALSE);
@@ -1483,11 +1661,12 @@ static void cse_modify (MIR_context_t ctx) {
insn = new_insn;
}
}
- get_early_clobbered_hard_reg (insn, &early_clobbered_hard_reg1, &early_clobbered_hard_reg2);
+ target_get_early_clobbered_hard_regs (insn, &early_clobbered_hard_reg1,
+ &early_clobbered_hard_reg2);
if (early_clobbered_hard_reg1 != MIR_NON_HARD_REG)
- make_obsolete_var_exprs (early_clobbered_hard_reg1, ctx);
+ make_obsolete_var_exprs (ctx, early_clobbered_hard_reg1);
if (early_clobbered_hard_reg2 != MIR_NON_HARD_REG)
- make_obsolete_var_exprs (early_clobbered_hard_reg2, ctx);
+ make_obsolete_var_exprs (ctx, early_clobbered_hard_reg2);
nops = MIR_insn_nops (ctx, insn);
for (i = 0; i < nops; i++) {
op = insn->ops[i];
@@ -1496,94 +1675,1003 @@ static void cse_modify (MIR_context_t ctx) {
if (op.mode == MIR_OP_MEM || op.mode == MIR_OP_HARD_REG_MEM) {
bitmap_and_compl (av, av, memory_exprs);
} else if (op.mode == MIR_OP_REG || op.mode == MIR_OP_HARD_REG) {
- make_obsolete_var_exprs (op.mode == MIR_OP_HARD_REG ? op.u.hard_reg
- : reg2var (gen_ctx, op.u.reg),
- ctx);
+ make_obsolete_var_exprs (ctx, op.mode == MIR_OP_HARD_REG ? op.u.hard_reg
+ : reg2var (gen_ctx, op.u.reg));
}
}
if (MIR_call_code_p (insn->code)) {
gen_assert (bb_insn->call_hard_reg_args != NULL);
- bitmap_for_each (bb_insn->call_hard_reg_args, make_obsolete_var_exprs, ctx);
- bitmap_for_each (call_used_hard_regs, make_obsolete_var_exprs, ctx);
+ FOREACH_BITMAP_BIT (bi, bb_insn->call_hard_reg_args, nel) {
+ make_obsolete_var_exprs (ctx, nel);
+ }
+ FOREACH_BITMAP_BIT (bi, call_used_hard_regs, nel) { make_obsolete_var_exprs (ctx, nel); }
bitmap_and_compl (av, av, memory_exprs);
}
}
}
}
-static void cse (MIR_context_t ctx) {
- create_exprs (ctx);
- create_av_bitmaps (ctx);
- solve_dataflow (ctx, TRUE, cse_con_func_0, cse_con_func_n, cse_trans_func);
- cse_modify (ctx);
+static void cse (MIR_context_t ctx) {
+ create_exprs (ctx);
+ create_av_bitmaps (ctx);
+ solve_dataflow (ctx, TRUE, cse_con_func_0, cse_con_func_n, cse_trans_func);
+ cse_modify (ctx);
+}
+
+#if !MIR_NO_GEN_DEBUG
+static void print_exprs (MIR_context_t ctx) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+
+ fprintf (debug_file, " Expressions:\n");
+ for (size_t i = 0; i < VARR_LENGTH (expr_t, exprs); i++) {
+ size_t nops;
+ expr_t e = VARR_GET (expr_t, exprs, i);
+
+ fprintf (debug_file, " %3lu: ", (unsigned long) i);
+ fprintf (debug_file, "%s _", MIR_insn_name (ctx, e->insn->code));
+ nops = MIR_insn_nops (ctx, e->insn);
+ for (size_t j = 1; j < nops; j++) {
+ fprintf (debug_file, ", ");
+ MIR_output_op (ctx, debug_file, e->insn->ops[j], curr_func_item->u.func);
+ }
+ fprintf (debug_file, "\n");
+ }
+}
+
+static void output_bb_cse_info (MIR_context_t ctx, bb_t bb) {
+ output_bitmap (ctx, " av_in:", bb->av_in, TRUE);
+ output_bitmap (ctx, " av_out:", bb->av_out, TRUE);
+ output_bitmap (ctx, " av_gen:", bb->av_gen, TRUE);
+ output_bitmap (ctx, " av_kill:", bb->av_kill, TRUE);
+}
+#endif
+
+static void cse_clear (MIR_context_t ctx) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+
+ HTAB_CLEAR (expr_t, expr_tab);
+ while (VARR_LENGTH (expr_t, exprs) != 0) free (VARR_POP (expr_t, exprs));
+ while (VARR_LENGTH (bitmap_t, var2dep_expr) != 0) {
+ bitmap_t b = VARR_POP (bitmap_t, var2dep_expr);
+
+ if (b != NULL) bitmap_destroy (b);
+ }
+ bitmap_clear (memory_exprs);
+}
+
+static void init_cse (MIR_context_t ctx) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+
+ gen_ctx->cse_ctx = gen_malloc (ctx, sizeof (struct cse_ctx));
+ VARR_CREATE (expr_t, exprs, 512);
+ VARR_CREATE (bitmap_t, var2dep_expr, 512);
+ memory_exprs = bitmap_create2 (DEFAULT_INIT_BITMAP_BITS_NUM);
+ HTAB_CREATE (expr_t, expr_tab, 1024, expr_hash, expr_eq, ctx);
+}
+
+static void finish_cse (MIR_context_t ctx) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+
+ VARR_DESTROY (expr_t, exprs);
+ bitmap_destroy (memory_exprs);
+ VARR_DESTROY (bitmap_t, var2dep_expr);
+ HTAB_DESTROY (expr_t, expr_tab);
+ free (gen_ctx->cse_ctx);
+ gen_ctx->cse_ctx = NULL;
+}
+
+#undef av_in
+#undef av_out
+#undef av_kill
+#undef av_gen
+
+/* New Page */
+
+/* Reaching definitions. */
+
+#define rdef_in in
+#define rdef_out out
+#define rdef_kill kill
+#define rdef_gen gen
+
+DEF_VARR (bb_insn_t);
+
+struct rdef_ctx {
+ VARR (bb_insn_t) * def_bb_insns;
+ VARR (bitmap_t) * var_uses, *var_defs;
+ bitmap_t artificial_def_bitmap, curr_rdef_bitmap;
+};
+
+#define def_bb_insns gen_ctx->rdef_ctx->def_bb_insns
+#define var_uses gen_ctx->rdef_ctx->var_uses
+#define var_defs gen_ctx->rdef_ctx->var_defs
+#define artificial_def_bitmap gen_ctx->rdef_ctx->artificial_def_bitmap
+#define curr_rdef_bitmap gen_ctx->rdef_ctx->curr_rdef_bitmap
+
+static void rdef_con_func_0 (bb_t bb) { bitmap_clear (bb->rdef_in); }
+
+static int rdef_con_func_n (MIR_context_t ctx, bb_t bb) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ int first_bb_p = bb == DLIST_EL (bb_t, curr_cfg->bbs, 2);
+ edge_t e, head;
+ bitmap_t prev_rdef_in = temp_bitmap;
+
+ if (first_bb_p) bitmap_ior (bb->rdef_in, bb->rdef_in, artificial_def_bitmap);
+ bitmap_copy (prev_rdef_in, bb->rdef_in);
+ head = DLIST_HEAD (in_edge_t, bb->in_edges);
+ bitmap_copy (bb->rdef_in, head->src->rdef_out);
+ for (e = DLIST_NEXT (in_edge_t, head); e != NULL; e = DLIST_NEXT (in_edge_t, e))
+ bitmap_ior (bb->rdef_in, bb->rdef_in, e->src->rdef_out); /* rdef_in |= rdef_out */
+ if (first_bb_p) bitmap_ior (bb->rdef_in, bb->rdef_in, artificial_def_bitmap);
+ return !bitmap_equal_p (bb->rdef_in, prev_rdef_in);
+}
+
+static int rdef_trans_func (MIR_context_t ctx, bb_t bb) {
+ return bitmap_ior_and_compl (bb->rdef_out, bb->rdef_gen, bb->rdef_in, bb->rdef_kill);
+}
+
+static bitmap_t get_var_uses_or_defs (MIR_context_t ctx, MIR_reg_t var, int uses_p) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ bitmap_t bm;
+ VARR (bitmap_t) *bitmap_varr = uses_p ? var_uses : var_defs;
+
+ while (VARR_LENGTH (bitmap_t, bitmap_varr) <= var) VARR_PUSH (bitmap_t, bitmap_varr, NULL);
+ if ((bm = VARR_GET (bitmap_t, bitmap_varr, var)) != NULL) return bm;
+ bm = bitmap_create2 (2 * curr_cfg->max_reg);
+ VARR_SET (bitmap_t, bitmap_varr, var, bm);
+ return bm;
+}
+
+static void calculate_reaching_defs (MIR_context_t ctx) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ MIR_func_t func = curr_func_item->u.func;
+ bb_t entry_bb = DLIST_HEAD (bb_t, curr_cfg->bbs);
+ int out_p, mem_p;
+ size_t i, passed_mem_num, n_out, def;
+ MIR_reg_t var;
+ const char *var_name;
+ bitmap_t def_bitmap;
+ insn_var_iterator_t iter;
+
+ VARR_TRUNC (bb_insn_t, def_bb_insns, 0);
+ for (bb_t bb = entry_bb; bb != NULL; bb = DLIST_NEXT (bb_t, bb)) {
+ /* Set up: var -> def insn indexes; bb_insn -> insn index; var = use insn indexes */
+ for (bb_insn_t bb_insn = DLIST_HEAD (bb_insn_t, bb->bb_insns); bb_insn != NULL;
+ bb_insn = DLIST_NEXT (bb_insn_t, bb_insn)) {
+ n_out = 0;
+ bb_insn->index = VARR_LENGTH (bb_insn_t, def_bb_insns);
+ VARR_PUSH (bb_insn_t, def_bb_insns, bb_insn);
+ FOREACH_INSN_VAR (ctx, iter, bb_insn->insn, var, out_p, mem_p, passed_mem_num) {
+ if (!out_p) {
+ bitmap_set_bit_p (get_var_uses_or_defs (ctx, var, TRUE), bb_insn->index);
+ } else {
+ if (n_out != 0) VARR_PUSH (bb_insn_t, def_bb_insns, bb_insn);
+ bitmap_set_bit_p (get_var_uses_or_defs (ctx, var, FALSE), bb_insn->index + n_out++);
+ }
+ }
+ }
+ }
+ /* Add special defs for each fucn arg */
+ bitmap_clear (artificial_def_bitmap);
+#if !MIR_NO_GEN_DEBUG
+ if (debug_file != NULL && func->nargs > 0)
+ fprintf (debug_file, " Adding special defs name(reg,def):");
+#endif
+ for (i = 0; i < func->nargs; i++) {
+ var_name = VARR_GET (MIR_var_t, func->vars, i).name;
+ var = reg2var (gen_ctx, MIR_reg (ctx, var_name, func));
+ gen_assert (var_is_reg_p (var));
+ def_bitmap = get_var_uses_or_defs (ctx, var, FALSE);
+ def = VARR_LENGTH (bb_insn_t, def_bb_insns);
+#if !MIR_NO_GEN_DEBUG
+ if (debug_file != NULL)
+ fprintf (debug_file, " %s(%lu,%lu)", var_name, (unsigned long) var2reg (gen_ctx, var),
+ (unsigned long) def);
+#endif
+ VARR_PUSH (bb_insn_t, def_bb_insns, NULL);
+ bitmap_set_bit_p (def_bitmap, def);
+ bitmap_set_bit_p (artificial_def_bitmap, def);
+ }
+#if !MIR_NO_GEN_DEBUG
+ if (debug_file != NULL && i > 0) fprintf (debug_file, "\n");
+#endif
+ for (bb_t bb = entry_bb; bb != NULL; bb = DLIST_NEXT (bb_t, bb)) {
+ /* Set up rdef gen/kill; initialize rdef in/out */
+ bitmap_clear (bb->rdef_in);
+ bitmap_clear (bb->rdef_out);
+ bitmap_clear (bb->rdef_gen);
+ bitmap_clear (bb->rdef_kill);
+ for (bb_insn_t bb_insn = DLIST_HEAD (bb_insn_t, bb->bb_insns); bb_insn != NULL;
+ bb_insn = DLIST_NEXT (bb_insn_t, bb_insn)) {
+ n_out = 0;
+ FOREACH_INSN_VAR (ctx, iter, bb_insn->insn, var, out_p, mem_p, passed_mem_num) {
+ if (!out_p) continue;
+ def_bitmap = get_var_uses_or_defs (ctx, var, FALSE);
+ gen_assert (def_bitmap != NULL);
+ bitmap_ior (bb->rdef_kill, bb->rdef_kill, def_bitmap);
+ bitmap_and_compl (bb->rdef_gen, bb->rdef_gen, def_bitmap);
+ bitmap_set_bit_p (bb->rdef_gen, bb_insn->index + n_out++);
+ }
+ }
+ }
+ solve_dataflow (ctx, TRUE, rdef_con_func_0, rdef_con_func_n, rdef_trans_func);
+}
+
+#if !MIR_NO_GEN_DEBUG
+static void output_bb_rdef_info (MIR_context_t ctx, bb_t bb) {
+ output_bitmap (ctx, " rdef_in:", bb->rdef_in, FALSE);
+ output_bitmap (ctx, " rdef_out:", bb->rdef_out, FALSE);
+ output_bitmap (ctx, " rdef_gen:", bb->rdef_gen, FALSE);
+ output_bitmap (ctx, " rdef_kill:", bb->rdef_kill, FALSE);
+}
+#endif
+
+static void rdef_clear (MIR_context_t ctx) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ bitmap_t bm;
+
+ while (VARR_LENGTH (bitmap_t, var_uses) != 0)
+ if ((bm = VARR_POP (bitmap_t, var_uses)) != NULL) bitmap_destroy (bm);
+ while (VARR_LENGTH (bitmap_t, var_defs) != 0)
+ if ((bm = VARR_POP (bitmap_t, var_defs)) != NULL) bitmap_destroy (bm);
+}
+
+static void init_rdef (MIR_context_t ctx) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+
+ gen_ctx->rdef_ctx = gen_malloc (ctx, sizeof (struct rdef_ctx));
+ VARR_CREATE (bb_insn_t, def_bb_insns, 0);
+ VARR_CREATE (bitmap_t, var_uses, 0);
+ VARR_CREATE (bitmap_t, var_defs, 0);
+ artificial_def_bitmap = bitmap_create ();
+ curr_rdef_bitmap = bitmap_create ();
+}
+
+static void finish_rdef (MIR_context_t ctx) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+
+ VARR_DESTROY (bb_insn_t, def_bb_insns);
+ VARR_DESTROY (bitmap_t, var_uses);
+ VARR_DESTROY (bitmap_t, var_defs);
+ bitmap_destroy (artificial_def_bitmap);
+ bitmap_destroy (curr_rdef_bitmap);
+ free (gen_ctx->rdef_ctx);
+ gen_ctx->rdef_ctx = NULL;
+}
+
+#undef rdef_in
+#undef rdef_out
+#undef rdef_kill
+#undef rdef_gen
+
+/* New Page */
+
+/* Register (variable) renaming. Reaching definitions info should exist. */
+
+#define rdef_in in
+#define rdef_out out
+#define rdef_kill kill
+#define rdef_gen gen
+
+struct web_node {
+ MIR_reg_t var; /* web_node_tab key */
+ int def_p; /* web_node_tab key: TRUE for definition, FALSE otherwise */
+ bb_insn_t bb_insn; /* web_node_tab key: NULL for an artificial definition */
+ size_t n_out; /* web_node_tab key: output number of insn, 0 for input */
+ size_t first, next; /* first, next node index in the web: 0 is NULL */
+};
+
+typedef struct web_node web_node_t;
+
+DEF_VARR (web_node_t);
+DEF_HTAB (size_t);
+DEF_VARR (size_t);
+DEF_VARR (char);
+
+struct rename_ctx {
+ VARR (web_node_t) * web_nodes;
+ HTAB (size_t) * web_node_htab;
+ VARR (size_t) * curr_var_indexes;
+ VARR (char) * reg_name;
+};
+
+#define web_nodes gen_ctx->rename_ctx->web_nodes
+#define web_node_htab gen_ctx->rename_ctx->web_node_htab
+#define curr_var_indexes gen_ctx->rename_ctx->curr_var_indexes
+#define reg_name gen_ctx->rename_ctx->reg_name
+
+static int web_node_eq (size_t wn_ind1, size_t wn_ind2, void *arg) {
+ MIR_context_t ctx = arg;
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ web_node_t *addr = VARR_ADDR (web_node_t, web_nodes), *n1 = &addr[wn_ind1], *n2 = &addr[wn_ind2];
+
+ return (n1->bb_insn == n2->bb_insn && n1->n_out == n2->n_out && n1->var == n2->var
+ && n1->def_p == n2->def_p);
+ return 0;
+}
+
+static htab_hash_t web_node_hash (size_t wn_ind, void *arg) {
+ MIR_context_t ctx = arg;
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ web_node_t *addr = VARR_ADDR (web_node_t, web_nodes);
+ htab_hash_t h = mir_hash_init (0x24);
+
+ if (addr[wn_ind].bb_insn != NULL) h = mir_hash_step (h, (uint64_t) addr[wn_ind].bb_insn);
+ h = mir_hash_step (h, (uint64_t) addr[wn_ind].n_out);
+ h = mir_hash_step (h, (uint64_t) addr[wn_ind].var);
+ h = mir_hash_step (h, (uint64_t) addr[wn_ind].def_p);
+ return mir_hash_finish (h);
+ return 0;
+}
+
+static size_t get_web_node_ind (MIR_context_t ctx, MIR_reg_t var, int def_p, bb_insn_t bb_insn,
+ size_t n_out) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ size_t tab_el, ind = VARR_LENGTH (web_node_t, web_nodes);
+ web_node_t wn = (struct web_node){var, def_p, bb_insn, n_out, ind, 0};
+
+ VARR_PUSH (web_node_t, web_nodes, wn);
+ if (!HTAB_DO (size_t, web_node_htab, ind, HTAB_INSERT, tab_el)) {
+ gen_assert (ind == tab_el);
+ return ind;
+ }
+ VARR_POP (web_node_t, web_nodes);
+ return tab_el;
+}
+
+static void link_web_nodes (MIR_context_t ctx, size_t ind1, size_t ind2) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ web_node_t *addr = VARR_ADDR (web_node_t, web_nodes);
+ size_t curr, last, first1 = addr[ind1].first, first2 = addr[ind2].first;
+
+ if (first1 == first2) return; /* already linked */
+ for (curr = ind1; curr != 0; curr = addr[curr].next) last = curr;
+ for (curr = first2; curr != 0; curr = addr[curr].next) addr[curr].first = first1;
+ addr[last].next = first2;
+}
+
+static void build_webs (MIR_context_t ctx) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ MIR_reg_t var;
+ bb_insn_t bb_insn, def_bb_insn;
+ int out_p, mem_p;
+ size_t nbit, passed_mem_num, web_node_ind, web_node_ind2, n_out;
+ web_node_t wn;
+ bitmap_t def_bitmap = temp_bitmap, var_rdef_bitmap = temp_bitmap2;
+ bitmap_iterator_t bi;
+ insn_var_iterator_t iter;
+
+ HTAB_CLEAR (size_t, web_node_htab);
+ VARR_TRUNC (web_node_t, web_nodes, 0);
+ VARR_PUSH (web_node_t, web_nodes, wn); /* to avoid nodes with 0-th index */
+ for (bb_t bb = DLIST_HEAD (bb_t, curr_cfg->bbs); bb != NULL; bb = DLIST_NEXT (bb_t, bb)) {
+ bitmap_copy (curr_rdef_bitmap, bb->rdef_in);
+ for (bb_insn = DLIST_HEAD (bb_insn_t, bb->bb_insns); bb_insn != NULL;
+ bb_insn = DLIST_NEXT (bb_insn_t, bb_insn)) {
+ FOREACH_INSN_VAR (ctx, iter, bb_insn->insn, var, out_p, mem_p, passed_mem_num) {
+ if (!var_is_reg_p (var) || out_p) continue; /* ignore hard regs here */
+ bitmap_and (var_rdef_bitmap, curr_rdef_bitmap, get_var_uses_or_defs (ctx, var, FALSE));
+ web_node_ind = get_web_node_ind (ctx, var, FALSE, bb_insn, 0);
+ if (bitmap_empty_p (var_rdef_bitmap)) {
+ web_node_ind2 = get_web_node_ind (ctx, var, TRUE, NULL, 0); /* an artificial def */
+ link_web_nodes (ctx, web_node_ind, web_node_ind2);
+ } else {
+ FOREACH_BITMAP_BIT (bi, var_rdef_bitmap, nbit) {
+ def_bb_insn = VARR_GET (bb_insn_t, def_bb_insns, nbit);
+ gen_assert (def_bb_insn == NULL || nbit >= def_bb_insn->index);
+ web_node_ind2 = get_web_node_ind (ctx, var, TRUE, def_bb_insn,
+ def_bb_insn == NULL ? 0 : nbit - def_bb_insn->index);
+ link_web_nodes (ctx, web_node_ind, web_node_ind2);
+ }
+ }
+ }
+ /* Update curr_rdef_bitmap: */
+ n_out = 0;
+ FOREACH_INSN_VAR (ctx, iter, bb_insn->insn, var, out_p, mem_p, passed_mem_num) {
+ if (!out_p) continue;
+ def_bitmap = get_var_uses_or_defs (ctx, var, FALSE);
+ gen_assert (def_bitmap != NULL);
+ bitmap_and_compl (curr_rdef_bitmap, curr_rdef_bitmap, def_bitmap);
+ bitmap_set_bit_p (curr_rdef_bitmap, bb_insn->index + n_out++);
+ }
+ }
+ }
+}
+
+static MIR_reg_t get_new_reg (MIR_context_t ctx, MIR_reg_t reg, size_t index) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ MIR_func_t func = curr_func_item->u.func;
+ MIR_type_t type = MIR_reg_type (ctx, reg, func);
+ const char *name = MIR_reg_name (ctx, reg, func);
+ char ind_str[20];
+ MIR_reg_t new_reg;
+
+ VARR_TRUNC (char, reg_name, 0);
+ VARR_PUSH_ARR (char, reg_name, name, strlen (name));
+ VARR_PUSH (char, reg_name, '@');
+ sprintf (ind_str, "%lu", (unsigned long) index); /* ??? should be enough to unique */
+ VARR_PUSH_ARR (char, reg_name, ind_str, strlen (ind_str) + 1);
+ new_reg = MIR_new_func_reg (ctx, func, type, VARR_ADDR (char, reg_name));
+ update_min_max_reg (ctx, new_reg);
+#if !MIR_NO_GEN_DEBUG
+ if (debug_file != NULL)
+ fprintf (debug_file, " Renaming %s to %s in", name, VARR_ADDR (char, reg_name));
+#endif
+ return new_reg;
+}
+
+static void reg_rename (MIR_context_t ctx) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ MIR_func_t func = curr_func_item->u.func;
+ MIR_insn_t insn;
+ MIR_reg_t var, reg, new_reg;
+ MIR_op_t op, *ops;
+ bb_insn_t bb_insn;
+ size_t i, j, nops, index, curr;
+ int def_p, out_p, change_p;
+ web_node_t *addr;
+
+ build_webs (ctx);
+ VARR_TRUNC (size_t, curr_var_indexes, 0);
+ addr = VARR_ADDR (web_node_t, web_nodes);
+ for (i = 1; i < VARR_LENGTH (web_node_t, web_nodes); i++) {
+ if (addr[i].first != i) continue;
+ var = addr[i].var;
+ reg = var2reg (gen_ctx, var);
+#if !MIR_NO_GEN_DEBUG
+ if (debug_file != NULL) {
+ fprintf (debug_file, "web reg=%d(%s):", reg, MIR_reg_name (ctx, reg, func));
+ for (curr = i; curr != 0; curr = addr[curr].next)
+ if (addr[curr].bb_insn == NULL)
+ fprintf (debug_file, " art_def(%s)", addr[curr].def_p ? "def" : "use");
+ else
+ fprintf (debug_file, " %lu(%s)",
+ (long unsigned) addr[curr].bb_insn->index + addr[curr].n_out,
+ addr[curr].def_p ? "def" : "use");
+ fprintf (debug_file, "\n");
+ }
+#endif
+ while (VARR_LENGTH (size_t, curr_var_indexes) <= var) VARR_PUSH (size_t, curr_var_indexes, 0);
+ index = VARR_GET (size_t, curr_var_indexes, var);
+ VARR_SET (size_t, curr_var_indexes, var, index + 1);
+ if (index == 0) continue; /* use the old names */
+ new_reg = get_new_reg (ctx, reg, index);
+ for (curr = i; curr != 0; curr = addr[curr].next) {
+ bb_insn = addr[curr].bb_insn;
+ if (bb_insn == NULL) continue; /* an artificial def */
+ insn = bb_insn->insn;
+ def_p = addr[curr].def_p;
+ nops = MIR_insn_nops (ctx, insn);
+ ops = insn->ops;
+ for (j = 0; j < nops; j++) {
+ MIR_insn_op_mode (ctx, insn, j, &out_p);
+ op = ops[j];
+ if (op.mode == MIR_OP_MEM) out_p = FALSE;
+ if ((def_p && !out_p) || (!def_p && out_p)) continue;
+ change_p = FALSE;
+ if (op.mode == MIR_OP_REG && op.u.reg == reg) {
+ ops[j].u.reg = new_reg;
+ change_p = TRUE;
+ } else if (op.mode == MIR_OP_MEM) {
+ if (op.u.mem.base == reg) {
+ ops[j].u.mem.base = new_reg;
+ change_p = TRUE;
+ }
+ if (op.u.mem.index == reg) {
+ ops[j].u.mem.index = new_reg;
+ change_p = TRUE;
+ }
+ }
+#if !MIR_NO_GEN_DEBUG
+ if (change_p && debug_file != NULL)
+ fprintf (debug_file, " %lu(%s)", (unsigned long) bb_insn->index + addr[curr].n_out,
+ def_p ? "def" : "use");
+#endif
+ }
+ }
+#if !MIR_NO_GEN_DEBUG
+ if (debug_file != NULL) fprintf (debug_file, "\n");
+#endif
+ }
+}
+
+static void init_rename (MIR_context_t ctx) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+
+ gen_ctx->rename_ctx = gen_malloc (ctx, sizeof (struct rename_ctx));
+ VARR_CREATE (web_node_t, web_nodes, 4096);
+ HTAB_CREATE (size_t, web_node_htab, 4096, web_node_hash, web_node_eq, ctx);
+ VARR_CREATE (size_t, curr_var_indexes, 4096);
+ VARR_CREATE (char, reg_name, 20);
+}
+
+static void finish_rename (MIR_context_t ctx) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+
+ VARR_DESTROY (web_node_t, web_nodes);
+ HTAB_DESTROY (size_t, web_node_htab);
+ VARR_DESTROY (size_t, curr_var_indexes);
+ VARR_DESTROY (char, reg_name);
+ free (gen_ctx->rename_ctx);
+ gen_ctx->rename_ctx = NULL;
+}
+
+#undef rdef_in
+#undef rdef_out
+#undef rdef_kill
+#undef rdef_gen
+
+/* New Page */
+
+/* Loop Invariant Code Motion. Reaching defs should be present for it. */
+
+#define rdef_in in
+#define rdef_out out
+#define rdef_kill kill
+#define rdef_gen gen
+
+struct licm_ctx {
+ VARR (bb_t) * licm_temp_bbs, *loop_bbs, *curr_exit_loop_bbs;
+ VARR (bb_insn_t) * loop_stores, *invariant_bb_insns;
+ bitmap_t loop_defs_bitmap;
+};
+
+#define licm_temp_bbs gen_ctx->licm_ctx->licm_temp_bbs
+#define loop_bbs gen_ctx->licm_ctx->loop_bbs
+#define loop_stores gen_ctx->licm_ctx->loop_stores
+#define curr_exit_loop_bbs gen_ctx->licm_ctx->curr_exit_loop_bbs
+#define invariant_bb_insns gen_ctx->licm_ctx->invariant_bb_insns
+#define loop_defs_bitmap gen_ctx->licm_ctx->loop_defs_bitmap
+
+static edge_t find_loop_entry_edge (MIR_context_t ctx, bb_t loop_entry) {
+ edge_t e, entry_e = NULL;
+ bb_insn_t head, tail;
+
+ for (e = DLIST_HEAD (in_edge_t, loop_entry->in_edges); e != NULL; e = DLIST_NEXT (in_edge_t, e)) {
+ if (e->back_edge_p) continue;
+ if (entry_e != NULL) return NULL;
+ entry_e = e;
+ }
+ gen_assert (entry_e != NULL);
+ tail = DLIST_TAIL (bb_insn_t, entry_e->src->bb_insns);
+ head = DLIST_HEAD (bb_insn_t, entry_e->dst->bb_insns);
+ if (tail != NULL && head != NULL && DLIST_NEXT (MIR_insn_t, tail->insn) != head->insn)
+ return NULL; /* not fall through */
+ return entry_e;
+}
+
+static void create_preheader_from_edge (MIR_context_t ctx, edge_t e, loop_node_t loop) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ bb_t new_bb = create_bb (ctx, NULL);
+ loop_node_t bb_loop_node = create_loop_node (ctx, new_bb), parent = loop->parent;
+
+ add_bb (ctx, new_bb);
+ DLIST_REMOVE (bb_t, curr_cfg->bbs, new_bb);
+ DLIST_INSERT_BEFORE (bb_t, curr_cfg->bbs, e->dst, new_bb); /* insert before loop entry */
+ create_edge (ctx, e->src, new_bb, FALSE); /* fall through should be the 1st edge */
+ create_edge (ctx, new_bb, e->dst, FALSE);
+ delete_edge (e);
+ gen_assert (parent != NULL);
+ DLIST_APPEND (loop_node_t, parent->children, bb_loop_node);
+ bb_loop_node->parent = parent;
+ loop->preheader = new_bb;
+}
+
+static void licm_add_loop_preheaders (MIR_context_t ctx, loop_node_t loop) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ bb_insn_t bb_insn;
+ edge_t e;
+
+ for (loop_node_t node = DLIST_HEAD (loop_node_t, loop->children); node != NULL;
+ node = DLIST_NEXT (loop_node_t, node))
+ if (node->bb == NULL) /* process sub-loops */
+ licm_add_loop_preheaders (ctx, node);
+ if (loop == curr_cfg->root_loop_node) return;
+ loop->preheader = NULL;
+ if ((e = find_loop_entry_edge (ctx, loop->entry->bb)) == NULL) return;
+ if ((bb_insn = DLIST_TAIL (bb_insn_t, e->src->bb_insns)) == NULL
+ || !MIR_branch_code_p (bb_insn->insn->code))
+ loop->preheader = e->src; /* The preheader already exists */
+ else
+ create_preheader_from_edge (ctx, e, loop);
+}
+
+static void dom_con_func_0 (bb_t bb) { bitmap_clear (bb->dom_in); }
+
+static int dom_con_func_n (MIR_context_t ctx, bb_t bb) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ edge_t e, head;
+ bitmap_t prev_dom_in = temp_bitmap;
+
+ bitmap_copy (prev_dom_in, bb->dom_in);
+ head = DLIST_HEAD (in_edge_t, bb->in_edges);
+ bitmap_copy (bb->dom_in, head->src->dom_out);
+ for (e = DLIST_NEXT (in_edge_t, head); e != NULL; e = DLIST_NEXT (in_edge_t, e))
+ bitmap_and (bb->dom_in, bb->dom_in, e->src->dom_out); /* dom_in &= dom_out */
+ return !bitmap_equal_p (bb->dom_in, prev_dom_in);
+}
+
+static int dom_trans_func (MIR_context_t ctx, bb_t bb) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+
+ bitmap_clear (temp_bitmap);
+ bitmap_set_bit_p (temp_bitmap, bb->index);
+ return bitmap_ior (bb->dom_out, bb->dom_in, temp_bitmap);
+}
+
+static void calculate_dominators (MIR_context_t ctx) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ bb_t entry_bb = DLIST_HEAD (bb_t, curr_cfg->bbs);
+
+ bitmap_clear (entry_bb->dom_out);
+ for (bb_t bb = DLIST_NEXT (bb_t, entry_bb); bb != NULL; bb = DLIST_NEXT (bb_t, bb))
+ bitmap_set_bit_range_p (bb->dom_out, 0, curr_bb_index);
+ solve_dataflow (ctx, TRUE, dom_con_func_0, dom_con_func_n, dom_trans_func);
+}
+
+static int invariant_reaching_definitions_p (MIR_context_t ctx, loop_node_t loop, MIR_reg_t var,
+ bitmap_t var_rdefs) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ size_t nbit;
+ bb_insn_t bb_insn;
+ bitmap_iterator_t iter;
+
+ FOREACH_BITMAP_BIT (iter, var_rdefs, nbit) {
+ bb_insn = VARR_GET (bb_insn_t, def_bb_insns, nbit);
+ if (bb_insn == NULL) continue; /* a special def insn */
+ if (in_loop_p (bb_insn->bb->loop_node, loop) && !bb_insn->flag) return FALSE;
+ }
+ return TRUE;
+}
+
+static int dominate_curr_loop_exits_p (MIR_context_t ctx, bb_t bb) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+
+ for (size_t i = 0; i < VARR_LENGTH (bb_t, curr_exit_loop_bbs); i++)
+ if (!bitmap_bit_p (VARR_GET (bb_t, curr_exit_loop_bbs, i)->dom_out, bb->index)) return FALSE;
+ return TRUE;
+}
+
+static int dominate_uses_p (MIR_context_t ctx, bb_insn_t def_bb_insn, MIR_reg_t var) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ bitmap_iterator_t iter;
+ bb_insn_t use_bb_insn;
+ bb_t use_bb, def_bb = def_bb_insn->bb;
+ bitmap_t var_defs_bitmap = get_var_uses_or_defs (ctx, var, FALSE);
+ size_t nbit;
+
+ bitmap_and (temp_bitmap, get_var_uses_or_defs (ctx, var, TRUE), loop_defs_bitmap);
+ FOREACH_BITMAP_BIT (iter, temp_bitmap, nbit) {
+ use_bb_insn = VARR_GET (bb_insn_t, def_bb_insns, nbit);
+ use_bb = use_bb_insn->bb;
+ if (use_bb == def_bb) {
+ if (use_bb_insn->index <= def_bb_insn->index) return FALSE;
+ continue; /* def before use in the same BB */
+ }
+ bitmap_and (temp_bitmap2, use_bb->rdef_in, var_defs_bitmap);
+ if (!bitmap_clear_bit_p (temp_bitmap2, def_bb_insn->index) /* does not reach use_bb */
+ || !bitmap_empty_p (temp_bitmap2)) /* another def reaches use_bb */
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static int another_def_reaching_def_p (MIR_context_t ctx, bb_insn_t def_bb_insn, MIR_reg_t var) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ MIR_reg_t ignore_var;
+ bitmap_iterator_t bi;
+ bb_insn_t another_def_bb_insn;
+ bb_t another_def_bb, def_bb = def_bb_insn->bb;
+ int out_p, mem_p;
+ size_t nbit, passed_mem_num, n_out;
+ insn_var_iterator_t iter;
+
+ bitmap_and (temp_bitmap, get_var_uses_or_defs (ctx, var, FALSE), loop_defs_bitmap);
+ bitmap_and (temp_bitmap2, def_bb->rdef_in, temp_bitmap);
+ n_out = 0;
+ FOREACH_INSN_VAR (ctx, iter, def_bb_insn->insn, ignore_var, out_p, mem_p, passed_mem_num) {
+ if (!out_p) continue;
+ bitmap_clear_bit_p (temp_bitmap2, def_bb_insn->index + n_out++); /* exclude insn defs itself */
+ }
+ if (!bitmap_empty_p (temp_bitmap2)) return TRUE; /* another def reaches def bb */
+ FOREACH_BITMAP_BIT (bi, temp_bitmap, nbit) { /* check defs in the same BB: */
+ if ((another_def_bb_insn = VARR_GET (bb_insn_t, def_bb_insns, nbit)) == def_bb_insn) continue;
+ another_def_bb = another_def_bb_insn->bb;
+ if (another_def_bb == def_bb && another_def_bb_insn->index < def_bb_insn->index) return TRUE;
+ }
+ return FALSE;
+}
+
+static int loop_invariant_insn_p (MIR_context_t ctx, loop_node_t loop, bb_insn_t bb_insn,
+ size_t stores_start) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ MIR_insn_t insn = bb_insn->insn;
+ bb_t bb = bb_insn->bb;
+ size_t i, passed_mem_num;
+ int out_p, mem_p;
+ MIR_reg_t var;
+ bitmap_t var_rdef_bitmap = temp_bitmap;
+ insn_var_iterator_t iter;
+
+ if (MIR_branch_code_p (insn->code) || insn->code == MIR_RET || insn->code == MIR_SWITCH
+ || insn->code == MIR_LABEL || MIR_call_code_p (insn->code) || insn->code == MIR_ALLOCA
+ || insn->code == MIR_BSTART || insn->code == MIR_BEND || insn->code == MIR_VA_START
+ || insn->code == MIR_VA_ARG || insn->code == MIR_VA_END)
+ return FALSE;
+ if (!dominate_curr_loop_exits_p (ctx, bb)) return FALSE; /* can not safely move */
+ FOREACH_INSN_VAR (ctx, iter, insn, var, out_p, mem_p, passed_mem_num) {
+ /* no stores in the loop ??? aliasing should be used here */
+ if (passed_mem_num != 0
+ && (loop->call_p || stores_start != VARR_LENGTH (bb_insn_t, loop_stores)))
+ return FALSE;
+ if (!out_p) {
+ /* in var: check reaching defs of var is outside the loop or loop invariant */
+ bitmap_and (var_rdef_bitmap, curr_rdef_bitmap, get_var_uses_or_defs (ctx, var, FALSE));
+ if (!invariant_reaching_definitions_p (ctx, loop, var, var_rdef_bitmap)) return FALSE;
+ } else { /* out var: check all uses in the loop are dominated by the def (bb_insn) */
+ if (!dominate_uses_p (ctx, bb_insn, var)) return FALSE;
+ if (another_def_reaching_def_p (ctx, bb_insn, var)) return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static int collect_loop_bb_invariants (MIR_context_t ctx, loop_node_t loop, bb_t bb,
+ size_t stores_start) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ bitmap_t def_bitmap;
+ MIR_reg_t var;
+ int out_p, mem_p, change_p = FALSE;
+ size_t passed_mem_num, n_out;
+ insn_var_iterator_t iter;
+
+ bitmap_copy (curr_rdef_bitmap, bb->rdef_in);
+ for (bb_insn_t bb_insn = DLIST_HEAD (bb_insn_t, bb->bb_insns); bb_insn != NULL;
+ bb_insn = DLIST_NEXT (bb_insn_t, bb_insn)) {
+ if (!bb_insn->flag && loop_invariant_insn_p (ctx, loop, bb_insn, stores_start)) {
+ bb_insn->flag = TRUE;
+ VARR_PUSH (bb_insn_t, invariant_bb_insns, bb_insn);
+ change_p = TRUE;
+ }
+ /* Update curr_rdef_bitmap: */
+ n_out = 0;
+ FOREACH_INSN_VAR (ctx, iter, bb_insn->insn, var, out_p, mem_p, passed_mem_num) {
+ if (!out_p) continue;
+ def_bitmap = get_var_uses_or_defs (ctx, var, FALSE);
+ gen_assert (def_bitmap != NULL);
+ bitmap_and_compl (curr_rdef_bitmap, curr_rdef_bitmap, def_bitmap);
+ bitmap_set_bit_p (curr_rdef_bitmap, bb_insn->index + n_out++);
+ }
+ }
+ return change_p;
+}
+
+static int compare_bb_bfs (const void *p1, const void *p2) {
+ const bb_t *bb1 = (const bb_t *) p1, *bb2 = (const bb_t *) p2;
+
+ return (*bb1)->bfs < (*bb2)->bfs ? -1 : (*bb1)->bfs > (*bb2)->bfs ? 1 : 0;
+}
+
+static int int_var_type_p (MIR_context_t ctx, MIR_reg_t var) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+
+ if (!var_is_reg_p (var)) return target_hard_reg_type_ok_p (var, MIR_T_I32);
+ return MIR_int_type_p (MIR_reg_type (ctx, var2reg (gen_ctx, var), curr_func_item->u.func));
+}
+
+static void find_profitable_loop_invariants (MIR_context_t ctx, loop_node_t loop) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ bb_insn_t bb_insn;
+ MIR_insn_t insn;
+ MIR_op_mode_t mode;
+ MIR_reg_t var;
+ int out_p, mem_p, move_p, dep_p, int_p;
+ int int_pressure, fp_pressure;
+ size_t passed_mem_num;
+ insn_var_iterator_t iterator;
+ bitmap_t live = temp_bitmap;
+
+ bitmap_clear (live);
+ for (size_t i = VARR_LENGTH (bb_insn_t, invariant_bb_insns); i != 0;) {
+ i--;
+ bb_insn = VARR_GET (bb_insn_t, invariant_bb_insns, i);
+ gen_assert (bb_insn->flag);
+ insn = bb_insn->insn;
+ move_p = !(insn->code == MIR_MOV
+ && ((mode = insn->ops[1].mode) == MIR_OP_INT || mode == MIR_OP_UINT
+ || mode == MIR_OP_REG || mode == MIR_OP_HARD_REG)); /* ??? */
+ dep_p = FALSE;
+ int_pressure = loop->max_int_pressure;
+ fp_pressure = loop->max_fp_pressure;
+ bb_insn->flag2 = TRUE; /* cheap or pressure */
+ FOREACH_INSN_VAR (ctx, iterator, insn, var, out_p, mem_p, passed_mem_num) {
+ if (!out_p) continue;
+ if (bitmap_bit_p (live, var)) {
+ move_p = dep_p = TRUE;
+ break;
+ }
+ /* inaccurate reg pressure evaluation: */
+ if ((int_p = int_var_type_p (ctx, var))) {
+ if (++int_pressure >= max_int_hard_regs) bb_insn->flag2 = move_p = FALSE;
+ } else {
+ if (++fp_pressure >= max_fp_hard_regs) bb_insn->flag2 = move_p = FALSE;
+ }
+ int_p ? int_pressure++ : fp_pressure++;
+ }
+ if (move_p || dep_p) { /* update live: ignore killed vars here */
+ bb_insn->flag = FALSE;
+ FOREACH_INSN_VAR (ctx, iterator, insn, var, out_p, mem_p, passed_mem_num) {
+ if (!out_p) bitmap_set_bit_p (live, var);
+ }
+ }
+ }
+}
+
+static void licm_move_insn (MIR_context_t ctx, bb_insn_t bb_insn, bb_t to, bb_insn_t before) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ bb_t bb = bb_insn->bb;
+ MIR_insn_t insn = bb_insn->insn;
+
+ gen_assert (before != NULL);
+ DLIST_REMOVE (bb_insn_t, bb->bb_insns, bb_insn);
+ DLIST_APPEND (bb_insn_t, to->bb_insns, bb_insn);
+ bb_insn->bb = to;
+ DLIST_REMOVE (MIR_insn_t, curr_func_item->u.func->insns, insn);
+ MIR_insert_insn_before (ctx, curr_func_item, before->insn, insn);
}
-#if MIR_GEN_DEBUG
-static void print_exprs (MIR_context_t ctx) {
+static void move_loop_invariants (MIR_context_t ctx, loop_node_t loop) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ bb_t entry_bb = loop->entry->bb;
- fprintf (debug_file, " Expressions:\n");
- for (size_t i = 0; i < VARR_LENGTH (expr_t, exprs); i++) {
- size_t nops;
- expr_t e = VARR_GET (expr_t, exprs, i);
-
- fprintf (debug_file, " %3lu: ", (unsigned long) i);
- fprintf (debug_file, "%s _", MIR_insn_name (ctx, e->insn->code));
- nops = MIR_insn_nops (ctx, e->insn);
- for (size_t j = 1; j < nops; j++) {
- fprintf (debug_file, ", ");
- MIR_output_op (ctx, debug_file, e->insn->ops[j], curr_func_item->u.func);
+ find_profitable_loop_invariants (ctx, loop);
+#if !MIR_NO_GEN_DEBUG
+ if (debug_file != NULL)
+ fprintf (debug_file, "Loop%3lu (pressure: int=%d, fp=%d) -- invariant insns:\n",
+ (unsigned long) loop->index, loop->max_int_pressure, loop->max_fp_pressure);
+#endif
+ for (size_t i = 0; i < VARR_LENGTH (bb_insn_t, invariant_bb_insns); i++) {
+ bb_insn_t bb_insn = VARR_GET (bb_insn_t, invariant_bb_insns, i);
+#if !MIR_NO_GEN_DEBUG
+ if (debug_file != NULL) {
+ fprintf (debug_file, " %15s %-5lu",
+ !bb_insn->flag ? "move" : bb_insn->flag2 ? "keep cheap" : "keep pressure",
+ (unsigned long) bb_insn->index);
+ print_bb_insn (ctx, bb_insn, TRUE);
+ }
+#endif
+ if (!bb_insn->flag) {
+ gen_assert (entry_bb != NULL);
+ licm_move_insn (ctx, bb_insn, loop->preheader, DLIST_HEAD (bb_insn_t, entry_bb->bb_insns));
}
- fprintf (debug_file, "\n");
}
}
-static void output_bb_cse_info (MIR_context_t ctx, bb_t bb) {
- output_bitmap (ctx, " av_in:", bb->av_in);
- output_bitmap (ctx, " av_out:", bb->av_out);
- output_bitmap (ctx, " av_gen:", bb->av_gen);
- output_bitmap (ctx, " av_kill:", bb->av_kill);
+static int store_p (MIR_insn_t insn) {
+ MIR_insn_code_t code = insn->code;
+
+ if (code != MIR_MOV && code != MIR_DMOV && code != MIR_FMOV && code != MIR_LDMOV) return FALSE;
+ return insn->ops[0].mode == MIR_OP_MEM || insn->ops[0].mode == MIR_OP_HARD_REG_MEM;
}
-#endif
-static void cse_clear (MIR_context_t ctx) {
+static void loop_licm (MIR_context_t ctx, loop_node_t loop) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ MIR_reg_t var;
+ size_t i, n_out, passed_mem_num;
+ int out_p, mem_p, change_p;
+ bb_t bb;
+ insn_var_iterator_t iter;
+ size_t loop_bbs_start = VARR_LENGTH (bb_t, loop_bbs);
+ size_t stores_start = VARR_LENGTH (bb_insn_t, loop_stores);
- HTAB_CLEAR (expr_t, expr_tab);
- while (VARR_LENGTH (expr_t, exprs) != 0) free (VARR_POP (expr_t, exprs));
- while (VARR_LENGTH (bitmap_t, var2dep_expr) != 0) {
- bitmap_t b = VARR_POP (bitmap_t, var2dep_expr);
+ for (loop_node_t node = DLIST_HEAD (loop_node_t, loop->children); node != NULL;
+ node = DLIST_NEXT (loop_node_t, node))
+ if (node->bb == NULL) { /* process sub-loops first */
+ loop_licm (ctx, node);
+ } else {
+ VARR_PUSH (bb_t, loop_bbs, node->bb); /* collect loop bbs */
+ }
+ if (loop == curr_cfg->root_loop_node || loop->preheader == NULL) return;
+ VARR_TRUNC (bb_t, curr_exit_loop_bbs, 0);
+ bitmap_clear (loop_defs_bitmap);
+ loop->call_p = TRUE;
+ for (i = loop_bbs_start; i < VARR_LENGTH (bb_t, loop_bbs); i++) {
+ bb = VARR_GET (bb_t, loop_bbs, i);
+ if (bb_loop_exit_p (ctx, bb, loop)) VARR_PUSH (bb_t, curr_exit_loop_bbs, bb);
+ for (bb_insn_t bb_insn = DLIST_HEAD (bb_insn_t, bb->bb_insns); bb_insn != NULL;
+ bb_insn = DLIST_NEXT (bb_insn_t, bb_insn)) {
+ if (store_p (bb_insn->insn)) VARR_PUSH (bb_insn_t, loop_stores, bb_insn);
+ if (MIR_call_code_p (bb_insn->insn->code)) loop->call_p = TRUE;
+ bb_insn->flag = FALSE; /* clear invariant flag */
+ n_out = 0;
+ FOREACH_INSN_VAR (ctx, iter, bb_insn->insn, var, out_p, mem_p, passed_mem_num) {
+ if (out_p) bitmap_set_bit_p (loop_defs_bitmap, bb_insn->index + n_out++);
+ }
+ }
+ }
+ qsort (VARR_ADDR (bb_t, loop_bbs) + loop_bbs_start, VARR_LENGTH (bb_t, loop_bbs) - loop_bbs_start,
+ sizeof (bb_t), compare_bb_bfs);
+ VARR_TRUNC (bb_insn_t, invariant_bb_insns, 0);
+ do {
+ change_p = FALSE;
+ for (i = loop_bbs_start; i < VARR_LENGTH (bb_t, loop_bbs); i++) {
+ bb = VARR_GET (bb_t, loop_bbs, i);
+ if (collect_loop_bb_invariants (ctx, loop, bb, stores_start)) change_p = TRUE;
+ }
+ } while (change_p);
+ move_loop_invariants (ctx, loop);
+}
- if (b != NULL) bitmap_destroy (b);
+static void BFS (MIR_context_t ctx) { /* breadth-first search */
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ bb_t bb, dst;
+ edge_t e;
+ size_t bfs = 0;
+
+ VARR_TRUNC (bb_t, licm_temp_bbs, 0);
+ VARR_PUSH (bb_t, licm_temp_bbs, DLIST_HEAD (bb_t, curr_cfg->bbs)); /* entry */
+ while (VARR_LENGTH (bb_t, licm_temp_bbs) != 0) {
+ bb = VARR_POP (bb_t, licm_temp_bbs);
+ bb->bfs = bfs++;
+ for (e = DLIST_TAIL (out_edge_t, bb->out_edges); e != NULL; e = DLIST_PREV (out_edge_t, e))
+ if ((dst = e->dst)->bfs == 0) VARR_PUSH (bb_t, licm_temp_bbs, dst);
+ for (e = DLIST_HEAD (out_edge_t, bb->out_edges); e != NULL; e = DLIST_NEXT (out_edge_t, e))
+ if ((dst = e->dst)->bfs == 0) dst->bfs = bfs++;
}
- bitmap_clear (memory_exprs);
}
-static void init_cse (MIR_context_t ctx) {
+static int licm (MIR_context_t ctx) { /* loop invariant code motion */
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
- gen_ctx->cse_ctx = gen_malloc (ctx, sizeof (struct cse_ctx));
- VARR_CREATE (expr_t, exprs, 512);
- VARR_CREATE (bitmap_t, var2dep_expr, 512);
- memory_exprs = bitmap_create2 (DEFAULT_INIT_BITMAP_BITS_NUM);
- HTAB_CREATE (expr_t, expr_tab, 1024, expr_hash, expr_eq);
+#if !MIR_NO_GEN_DEBUG
+ if (debug_file != NULL) print_loop_tree (ctx, FALSE);
+#endif
+ BFS (ctx);
+ calculate_dominators (ctx);
+ VARR_TRUNC (bb_t, licm_temp_bbs, 0);
+ VARR_TRUNC (bb_t, loop_bbs, 0);
+ VARR_TRUNC (bb_insn_t, loop_stores, 0);
+ loop_licm (ctx, curr_cfg->root_loop_node);
+ return TRUE;
}
-static void finish_cse (MIR_context_t ctx) {
+#if !MIR_NO_GEN_DEBUG
+static void output_bb_licm_info (MIR_context_t ctx, bb_t bb) {
+ output_bitmap (ctx, " dom_in:", bb->dom_in, FALSE);
+ output_bitmap (ctx, " dom_out:", bb->dom_out, FALSE);
+ output_bb_rdef_info (ctx, bb);
+}
+#endif
+
+static void init_licm (MIR_context_t ctx) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
- VARR_DESTROY (expr_t, exprs);
- bitmap_destroy (memory_exprs);
- VARR_DESTROY (bitmap_t, var2dep_expr);
- HTAB_DESTROY (expr_t, expr_tab);
- free (gen_ctx->cse_ctx);
- gen_ctx->cse_ctx = NULL;
+ gen_ctx->licm_ctx = gen_malloc (ctx, sizeof (struct licm_ctx));
+ VARR_CREATE (bb_t, licm_temp_bbs, 0);
+ VARR_CREATE (bb_t, loop_bbs, 0);
+ VARR_CREATE (bb_insn_t, loop_stores, 0);
+ VARR_CREATE (bb_t, curr_exit_loop_bbs, 0);
+ VARR_CREATE (bb_insn_t, invariant_bb_insns, 0);
+ loop_defs_bitmap = bitmap_create ();
}
-#undef av_in
-#undef av_out
-#undef av_kill
-#undef av_gen
+static void finish_licm (MIR_context_t ctx) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+
+ VARR_DESTROY (bb_t, licm_temp_bbs);
+ VARR_DESTROY (bb_t, loop_bbs);
+ VARR_DESTROY (bb_insn_t, loop_stores);
+ VARR_DESTROY (bb_t, curr_exit_loop_bbs);
+ VARR_DESTROY (bb_insn_t, invariant_bb_insns);
+ bitmap_destroy (loop_defs_bitmap);
+ free (gen_ctx->licm_ctx);
+ gen_ctx->licm_ctx = NULL;
+}
+
+#undef rdef_in
+#undef rdef_out
+#undef rdef_kill
+#undef rdef_gen
/* New Page */
@@ -1637,8 +2725,6 @@ typedef struct {
DEF_VARR (var_producer_t);
-DEF_VARR (bb_insn_t);
-
struct ccp_ctx {
VARR (bb_start_occ_list_t) * bb_start_occ_list_varr;
bb_start_occ_list_t *bb_start_occ_lists;
@@ -1647,7 +2733,6 @@ struct ccp_ctx {
int curr_producer_age, curr_op_age;
var_producer_t *producers;
VARR (var_producer_t) * producer_varr;
- bb_t ccp_end_bb;
bitmap_t bb_visited;
VARR (bb_t) * ccp_bbs;
VARR (var_occ_t) * ccp_var_occs;
@@ -1662,13 +2747,12 @@ struct ccp_ctx {
#define curr_op_age gen_ctx->ccp_ctx->curr_op_age
#define producers gen_ctx->ccp_ctx->producers
#define producer_varr gen_ctx->ccp_ctx->producer_varr
-#define ccp_end_bb gen_ctx->ccp_ctx->ccp_end_bb
#define bb_visited gen_ctx->ccp_ctx->bb_visited
#define ccp_bbs gen_ctx->ccp_ctx->ccp_bbs
#define ccp_var_occs gen_ctx->ccp_ctx->ccp_var_occs
#define ccp_insns gen_ctx->ccp_ctx->ccp_insns
-static htab_hash_t var_occ_hash (var_occ_t vo) {
+static htab_hash_t var_occ_hash (var_occ_t vo, void *arg) {
gen_assert (vo->place.type != OCC_INSN);
return mir_hash_finish (
mir_hash_step (mir_hash_step (mir_hash_step (mir_hash_init (0x54), (uint64_t) vo->var),
@@ -1676,7 +2760,7 @@ static htab_hash_t var_occ_hash (var_occ_t vo) {
(uint64_t) vo->place.u.bb));
}
-static int var_occ_eq (var_occ_t vo1, var_occ_t vo2) {
+static int var_occ_eq (var_occ_t vo1, var_occ_t vo2, void *arg) {
return (vo1->var == vo2->var && vo1->place.type == vo2->place.type
&& vo1->place.u.bb == vo2->place.u.bb);
}
@@ -1780,17 +2864,6 @@ static void process_op_use (MIR_context_t ctx, MIR_op_t *op, bb_insn_t bb_insn)
}
}
-static void process_bb_end (size_t el, void *data) {
- MIR_context_t ctx = data;
- struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
- MIR_reg_t var = el;
- var_occ_t use = get_bb_var_occ (ctx, var, OCC_BB_END, ccp_end_bb);
- var_occ_t def = get_var_def (ctx, var, ccp_end_bb);
-
- use->def = def;
- DLIST_APPEND (var_occ_t, def->uses, use);
-}
-
/* Build a web of def-use with auxiliary usages and definitions at BB
borders to emulate SSA on which the sparse conditional propagation
is usually done. We could do non-sparse CCP w/o building the web
@@ -1799,12 +2872,13 @@ static void build_var_occ_web (MIR_context_t ctx) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
MIR_op_t *op;
MIR_insn_t insn;
- size_t i, nops;
+ size_t i, nops, nel;
int out_p;
MIR_reg_t dst_var;
var_occ_t var_occ;
var_producer_t var_producer;
bb_start_occ_list_t list;
+ bitmap_iterator_t bi;
DLIST_INIT (var_occ_t, list);
while (VARR_LENGTH (bb_start_occ_list_t, bb_start_occ_list_varr) < curr_bb_index)
@@ -1839,8 +2913,14 @@ static void build_var_occ_web (MIR_context_t ctx) {
}
}
}
- ccp_end_bb = bb;
- bitmap_for_each (bb->live_out, process_bb_end, ctx);
+ FOREACH_BITMAP_BIT (bi, bb->live_out, nel) {
+ MIR_reg_t var = nel;
+ var_occ_t use = get_bb_var_occ (ctx, var, OCC_BB_END, bb);
+ var_occ_t def = get_var_def (ctx, var, bb);
+
+ use->def = def;
+ DLIST_APPEND (var_occ_t, def->uses, use);
+ }
}
}
@@ -1863,7 +2943,7 @@ static void init_var_occs (MIR_context_t ctx) {
VARR_CREATE (var_occ_t, var_occs, 1024);
curr_producer_age = curr_op_age = 0;
VARR_CREATE (var_producer_t, producer_varr, 256);
- HTAB_CREATE (var_occ_t, var_occ_tab, 1024, var_occ_hash, var_occ_eq);
+ HTAB_CREATE (var_occ_t, var_occ_tab, 1024, var_occ_hash, var_occ_eq, NULL);
}
static void finish_var_occs (MIR_context_t ctx) {
@@ -2339,7 +3419,7 @@ static void ccp_push_used_insns (MIR_context_t ctx, var_occ_t def) {
if (bb_insn->flag) continue; /* already in ccp_insns */
VARR_PUSH (bb_insn_t, ccp_insns, bb_insn);
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) {
fprintf (debug_file, " pushing bb%lu insn: ", (unsigned long) bb_insn->bb->index);
MIR_output_insn (ctx, debug_file, bb_insn->insn, curr_func_item->u.func, TRUE);
@@ -2359,7 +3439,7 @@ static void ccp_push_used_insns (MIR_context_t ctx, var_occ_t def) {
vos.place.u.bb = e->dst;
if (!HTAB_DO (var_occ_t, var_occ_tab, &vos, HTAB_FIND, tab_var_occ) || tab_var_occ->flag)
continue; /* var_occ at the start of BB in subsequent BB is already in ccp_var_occs */
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL)
fprintf (debug_file, " pushing var%lu(%s) at start of bb%lu\n",
(long unsigned) vos.var,
@@ -2381,7 +3461,7 @@ static void ccp_process_bb_start_var_occ (MIR_context_t ctx, var_occ_t var_occ,
var_occ_t tab_var_occ, def;
int change_p;
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL)
fprintf (debug_file,
" %sprocessing var%lu(%s) at start of bb%lu:", from_bb_process_p ? " " : "",
@@ -2393,12 +3473,12 @@ static void ccp_process_bb_start_var_occ (MIR_context_t ctx, var_occ_t var_occ,
#endif
gen_assert (var_occ->place.type == OCC_BB_START && bb == var_occ->place.u.bb);
if (var_occ->val_kind == CCP_VARYING) {
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) fprintf (debug_file, " already varying\n");
#endif
return;
} else if (bb->index == 0) { /* Non-parameter at entry BB (it means using undefined value) */
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) fprintf (debug_file, " making varying\n");
#endif
var_occ->val_kind = CCP_VARYING;
@@ -2434,7 +3514,7 @@ static void ccp_process_bb_start_var_occ (MIR_context_t ctx, var_occ_t var_occ,
}
}
}
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) {
if (var_occ->val_kind != CCP_CONST) {
fprintf (debug_file, " %s%s\n", change_p ? "changed to " : "",
@@ -2453,7 +3533,7 @@ static void ccp_process_active_edge (MIR_context_t ctx, edge_t e) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
if (e->skipped_p && !e->dst->flag) {
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL)
fprintf (debug_file, " Make edge bb%lu->bb%lu active\n",
(unsigned long) e->src->index, (unsigned long) e->dst->index);
@@ -2471,7 +3551,7 @@ static void ccp_make_insn_update (MIR_context_t ctx, MIR_insn_t insn) {
var_occ_t var_occ;
if (!ccp_insn_update (ctx, insn, NULL)) {
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) {
if (MIR_call_code_p (insn->code)) {
fprintf (debug_file, " -- keep all results varying");
@@ -2499,7 +3579,7 @@ static void ccp_make_insn_update (MIR_context_t ctx, MIR_insn_t insn) {
var_occ = op.data;
ccp_push_used_insns (ctx, var_occ);
}
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL && def_p) {
if (MIR_call_code_p (insn->code)) {
fprintf (debug_file, " -- make all results varying");
@@ -2524,7 +3604,7 @@ static void ccp_process_insn (MIR_context_t ctx, bb_insn_t bb_insn) {
bb_t bb = bb_insn->bb;
MIR_insn_t insn = bb_insn->insn;
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) {
fprintf (debug_file, " processing bb%lu insn: ", (unsigned long) bb_insn->bb->index);
MIR_output_insn (ctx, debug_file, bb_insn->insn, curr_func_item->u.func, FALSE);
@@ -2534,7 +3614,7 @@ static void ccp_process_insn (MIR_context_t ctx, bb_insn_t bb_insn) {
ccp_make_insn_update (ctx, insn);
return;
}
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) fprintf (debug_file, "\n");
#endif
if ((ccp_res = ccp_branch_update (insn, &res)) == CCP_CONST) {
@@ -2554,7 +3634,7 @@ static void ccp_process_bb (MIR_context_t ctx, bb_t bb) {
bb_insn_t bb_insn;
edge_t e;
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL)
fprintf (debug_file, " processing bb%lu\n", (unsigned long) bb->index);
#endif
@@ -2564,7 +3644,7 @@ static void ccp_process_bb (MIR_context_t ctx, bb_t bb) {
if (!bitmap_set_bit_p (bb_visited, bb->index)) return;
for (bb_insn = DLIST_HEAD (bb_insn_t, bb->bb_insns); bb_insn != NULL;
bb_insn = DLIST_NEXT (bb_insn_t, bb_insn)) {
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) {
fprintf (debug_file, " processing insn: ");
MIR_output_insn (ctx, debug_file, bb_insn->insn, curr_func_item->u.func, FALSE);
@@ -2625,7 +3705,7 @@ static int ccp_modify (MIR_context_t ctx) {
next_bb = DLIST_NEXT (bb_t, bb);
if (!bb->flag) {
change_p = TRUE;
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL)
fprintf (debug_file, " deleting unreachable bb%lu and its edges\n",
(unsigned long) bb->index);
@@ -2648,7 +3728,7 @@ static int ccp_modify (MIR_context_t ctx) {
&& bb_insn->insn->ops[1].mode != MIR_OP_UINT))) {
gen_assert (!MIR_call_code_p (bb_insn->insn->code));
change_p = TRUE;
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) {
fprintf (debug_file, " changing insn ");
MIR_output_insn (ctx, debug_file, bb_insn->insn, curr_func_item->u.func, FALSE);
@@ -2668,7 +3748,7 @@ static int ccp_modify (MIR_context_t ctx) {
MIR_remove_insn (ctx, curr_func_item, bb_insn->insn);
insn->data = bb_insn;
bb_insn->insn = insn;
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) {
fprintf (debug_file, " on insn ");
MIR_output_insn (ctx, debug_file, insn, curr_func_item->u.func, TRUE);
@@ -2682,7 +3762,7 @@ static int ccp_modify (MIR_context_t ctx) {
first_insn = DLIST_HEAD (bb_insn_t, bb->bb_insns)->insn;
if (first_insn->code == MIR_LABEL && (prev_insn = DLIST_PREV (MIR_insn_t, first_insn)) != NULL
&& prev_insn->code == MIR_JMP && prev_insn->ops[0].u.label == first_insn) {
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) {
fprintf (debug_file, " removing useless jump insn ");
MIR_output_insn (ctx, debug_file, prev_insn, curr_func_item->u.func, TRUE);
@@ -2696,7 +3776,7 @@ static int ccp_modify (MIR_context_t ctx) {
continue;
change_p = TRUE;
if (!res) {
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) {
fprintf (debug_file, " removing branch insn ");
MIR_output_insn (ctx, debug_file, bb_insn->insn, curr_func_item->u.func, TRUE);
@@ -2707,7 +3787,7 @@ static int ccp_modify (MIR_context_t ctx) {
delete_edge (DLIST_EL (out_edge_t, bb->out_edges, 1));
} else {
insn = MIR_new_insn (ctx, MIR_JMP, bb_insn->insn->ops[0]); /* label is always 0-th op */
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) {
fprintf (debug_file, " changing branch insn ");
MIR_output_insn (ctx, debug_file, bb_insn->insn, curr_func_item->u.func, FALSE);
@@ -2729,7 +3809,7 @@ static int ccp_modify (MIR_context_t ctx) {
static int ccp (MIR_context_t ctx) { /* conditional constant propagation */
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) fprintf (debug_file, " CCP analysis:\n");
#endif
build_var_occ_web (ctx);
@@ -2758,7 +3838,7 @@ static int ccp (MIR_context_t ctx) { /* conditional constant propagation */
ccp_process_insn (ctx, bb_insn);
}
}
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) fprintf (debug_file, " CCP modification:\n");
#endif
return ccp_modify (ctx);
@@ -2809,7 +3889,7 @@ static int live_con_func_n (MIR_context_t ctx, bb_t bb) {
return change_p;
}
-static int live_trans_func (bb_t bb) {
+static int live_trans_func (MIR_context_t ctx, bb_t bb) {
return bitmap_ior_and_compl (bb->live_in, bb->live_gen, bb->live_out, bb->live_kill);
}
@@ -2822,15 +3902,24 @@ static int bb_loop_level (bb_t bb) {
return level;
}
+static void increase_pressure (int int_p, bb_t bb, int *int_pressure, int *fp_pressure) {
+ if (int_p) {
+ if (bb->max_int_pressure < ++(*int_pressure)) bb->max_int_pressure = *int_pressure;
+ } else {
+ if (bb->max_fp_pressure < ++(*fp_pressure)) bb->max_fp_pressure = *fp_pressure;
+ }
+}
+
static size_t initiate_bb_live_info (MIR_context_t ctx, bb_t bb, int moves_p) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
MIR_insn_t insn;
- size_t nops, i, niter, bb_freq, mvs_num = 0;
- MIR_reg_t early_clobbered_hard_reg1, early_clobbered_hard_reg2;
- MIR_op_t op;
- int out_p;
+ size_t i, niter, passed_mem_num, bb_freq, mvs_num = 0;
+ MIR_reg_t var, early_clobbered_hard_reg1, early_clobbered_hard_reg2;
+ int out_p, mem_p, int_p;
+ int bb_int_pressure, max_bb_int_pressure, bb_fp_pressure, max_bb_fp_pressure;
mv_t mv;
reg_info_t *breg_infos;
+ insn_var_iterator_t insn_var_iter;
gen_assert (bb->live_in != NULL && bb->live_out != NULL && bb->live_gen != NULL
&& bb->live_kill != NULL);
@@ -2842,67 +3931,43 @@ static size_t initiate_bb_live_info (MIR_context_t ctx, bb_t bb, int moves_p) {
bb_freq = 1;
if (moves_p)
for (int i = bb_loop_level (bb); i > 0; i--) bb_freq *= 5;
+ bb->max_int_pressure = bb_int_pressure = bb->max_fp_pressure = bb_fp_pressure = 0;
for (bb_insn_t bb_insn = DLIST_TAIL (bb_insn_t, bb->bb_insns); bb_insn != NULL;
bb_insn = DLIST_PREV (bb_insn_t, bb_insn)) {
insn = bb_insn->insn;
- nops = MIR_insn_nops (ctx, insn);
if (MIR_call_code_p (insn->code)) {
bitmap_ior (bb->live_kill, bb->live_kill, call_used_hard_regs);
bitmap_and_compl (bb->live_gen, bb->live_gen, call_used_hard_regs);
}
/* Process output ops on 0-th iteration, then input ops. */
for (niter = 0; niter <= 1; niter++) {
- for (i = 0; i < nops; i++) {
- op = insn->ops[i];
- MIR_insn_op_mode (ctx, insn, i, &out_p);
- switch (op.mode) {
- case MIR_OP_REG:
- if (!out_p && niter != 0)
- bitmap_set_bit_p (bb->live_gen, reg2var (gen_ctx, op.u.reg));
- else if (niter == 0) {
- bitmap_clear_bit_p (bb->live_gen, reg2var (gen_ctx, op.u.reg));
- bitmap_set_bit_p (bb->live_kill, reg2var (gen_ctx, op.u.reg));
- }
- breg_infos[reg2breg (gen_ctx, op.u.reg)].freq += bb_freq;
- break;
- case MIR_OP_HARD_REG:
- if (!out_p && niter != 0)
- bitmap_set_bit_p (bb->live_gen, op.u.hard_reg);
- else if (niter == 0) {
- bitmap_clear_bit_p (bb->live_gen, op.u.hard_reg);
- bitmap_set_bit_p (bb->live_kill, op.u.hard_reg);
- }
- break;
- case MIR_OP_MEM:
- if (niter == 0) break;
- if (op.u.mem.base != 0) {
- bitmap_set_bit_p (bb->live_gen, reg2var (gen_ctx, op.u.mem.base));
- breg_infos[reg2breg (gen_ctx, op.u.mem.base)].freq += bb_freq;
- }
- if (op.u.mem.index != 0) {
- bitmap_set_bit_p (bb->live_gen, reg2var (gen_ctx, op.u.mem.index));
- breg_infos[reg2breg (gen_ctx, op.u.mem.index)].freq += bb_freq;
- }
- break;
- case MIR_OP_HARD_REG_MEM:
- if (niter == 0) break;
- if (op.u.hard_reg_mem.base != MIR_NON_HARD_REG)
- bitmap_set_bit_p (bb->live_gen, op.u.hard_reg_mem.base);
- if (op.u.hard_reg_mem.index != MIR_NON_HARD_REG)
- bitmap_set_bit_p (bb->live_gen, op.u.hard_reg_mem.index);
- break;
- default: /* do nothing */ break;
+ FOREACH_INSN_VAR (ctx, insn_var_iter, insn, var, out_p, mem_p, passed_mem_num) {
+ if (!out_p && niter != 0) {
+ if (bitmap_set_bit_p (bb->live_gen, var))
+ increase_pressure (int_var_type_p (ctx, var), bb, &bb_int_pressure, &bb_fp_pressure);
+ } else if (niter == 0) {
+ if (bitmap_clear_bit_p (bb->live_gen, var))
+ (int_var_type_p (ctx, var) ? bb_int_pressure-- : bb_fp_pressure--);
+ bitmap_set_bit_p (bb->live_kill, var);
}
+ if (var_is_reg_p (var)) breg_infos[var2breg (gen_ctx, var)].freq += bb_freq;
}
}
- get_early_clobbered_hard_reg (insn, &early_clobbered_hard_reg1, &early_clobbered_hard_reg2);
+ target_get_early_clobbered_hard_regs (insn, &early_clobbered_hard_reg1,
+ &early_clobbered_hard_reg2);
if (early_clobbered_hard_reg1 != MIR_NON_HARD_REG) {
+ int_p = int_var_type_p (ctx, early_clobbered_hard_reg1);
+ increase_pressure (int_p, bb, &bb_int_pressure, &bb_fp_pressure);
bitmap_clear_bit_p (bb->live_gen, early_clobbered_hard_reg1);
bitmap_set_bit_p (bb->live_kill, early_clobbered_hard_reg1);
+ (int_p ? bb_int_pressure-- : bb_fp_pressure--);
}
if (early_clobbered_hard_reg2 != MIR_NON_HARD_REG) {
+ int_p = int_var_type_p (ctx, early_clobbered_hard_reg2);
+ increase_pressure (int_p, bb, &bb_int_pressure, &bb_fp_pressure);
bitmap_clear_bit_p (bb->live_gen, early_clobbered_hard_reg2);
bitmap_set_bit_p (bb->live_kill, early_clobbered_hard_reg2);
+ (int_p ? bb_int_pressure-- : bb_fp_pressure--);
}
if (MIR_call_code_p (insn->code))
bitmap_ior (bb->live_gen, bb->live_gen, bb_insn->call_hard_reg_args);
@@ -2915,7 +3980,7 @@ static size_t initiate_bb_live_info (MIR_context_t ctx, bb_t bb, int moves_p) {
if (insn->ops[1].mode == MIR_OP_REG)
DLIST_APPEND (src_mv_t, breg_infos[reg2breg (gen_ctx, insn->ops[1].u.reg)].src_moves, mv);
mvs_num++;
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) {
fprintf (debug_file, " move with freq %10lu:", (unsigned long) mv->freq);
MIR_output_insn (ctx, debug_file, bb_insn->insn, curr_func_item->u.func, TRUE);
@@ -2953,20 +4018,36 @@ static void initiate_live_info (MIR_context_t ctx, int moves_p) {
if (moves_p) curr_cfg->non_conflicting_moves = mvs_num;
}
+static void update_bb_pressure (MIR_context_t ctx) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ size_t nel;
+ bitmap_iterator_t bi;
+
+ for (bb_t bb = DLIST_HEAD (bb_t, curr_cfg->bbs); bb != NULL; bb = DLIST_NEXT (bb_t, bb)) {
+ int int_pressure = bb->max_int_pressure, fp_pressure = bb->max_fp_pressure;
+
+ FOREACH_BITMAP_BIT (bi, bb->live_out, nel) {
+ increase_pressure (int_var_type_p (ctx, (MIR_reg_t) nel), bb, &int_pressure, &fp_pressure);
+ }
+ }
+}
+
static void calculate_func_cfg_live_info (MIR_context_t ctx, int moves_p) {
initiate_live_info (ctx, moves_p);
solve_dataflow (ctx, FALSE, live_con_func_0, live_con_func_n, live_trans_func);
+ update_bb_pressure (ctx);
}
static void add_bb_insn_dead_vars (MIR_context_t ctx) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
MIR_insn_t insn;
bb_insn_t bb_insn, prev_bb_insn;
- size_t nops, i;
- MIR_reg_t var, var2, early_clobbered_hard_reg1, early_clobbered_hard_reg2;
+ size_t passed_mem_num;
+ MIR_reg_t var, early_clobbered_hard_reg1, early_clobbered_hard_reg2;
MIR_op_t op;
- int out_p, live_start1_p, live_start2_p;
+ int out_p, mem_p;
bitmap_t live;
+ insn_var_iterator_t insn_var_iter;
live = bitmap_create2 (DEFAULT_INIT_BITMAP_BITS_NUM);
for (bb_t bb = DLIST_HEAD (bb_t, curr_cfg->bbs); bb != NULL; bb = DLIST_NEXT (bb_t, bb)) {
@@ -2975,44 +4056,16 @@ static void add_bb_insn_dead_vars (MIR_context_t ctx) {
prev_bb_insn = DLIST_PREV (bb_insn_t, bb_insn);
clear_bb_insn_dead_vars (bb_insn);
insn = bb_insn->insn;
- nops = MIR_insn_nops (ctx, insn);
- for (i = 0; i < nops; i++) {
- op = insn->ops[i];
- MIR_insn_op_mode (ctx, insn, i, &out_p);
- if (!out_p || (op.mode != MIR_OP_REG && op.mode != MIR_OP_HARD_REG)) continue;
- var = op.mode == MIR_OP_HARD_REG ? op.u.hard_reg : reg2var (gen_ctx, op.u.reg);
- bitmap_clear_bit_p (live, var);
+ FOREACH_INSN_VAR (ctx, insn_var_iter, insn, var, out_p, mem_p, passed_mem_num) {
+ if (out_p) bitmap_clear_bit_p (live, var);
}
if (MIR_call_code_p (insn->code)) bitmap_and_compl (live, live, call_used_hard_regs);
- for (i = 0; i < nops; i++) {
- op = insn->ops[i];
- MIR_insn_op_mode (ctx, insn, i, &out_p);
- live_start1_p = live_start2_p = FALSE;
- switch (op.mode) {
- case MIR_OP_REG:
- if (!out_p) live_start1_p = bitmap_set_bit_p (live, var = reg2var (gen_ctx, op.u.reg));
- break;
- case MIR_OP_HARD_REG:
- if (!out_p) live_start1_p = bitmap_set_bit_p (live, var = op.u.hard_reg);
- break;
- case MIR_OP_MEM:
- if (op.u.mem.base != 0)
- live_start1_p = bitmap_set_bit_p (live, var = reg2var (gen_ctx, op.u.mem.base));
- if (op.u.mem.index != 0)
- live_start2_p = bitmap_set_bit_p (live, var2 = reg2var (gen_ctx, op.u.mem.index));
- break;
- case MIR_OP_HARD_REG_MEM:
- if (op.u.hard_reg_mem.base != MIR_NON_HARD_REG)
- live_start1_p = bitmap_set_bit_p (live, var = op.u.hard_reg_mem.base);
- if (op.u.hard_reg_mem.index != MIR_NON_HARD_REG)
- live_start2_p = bitmap_set_bit_p (live, var2 = op.u.hard_reg_mem.index);
- break;
- default: break;
- }
- if (live_start1_p) add_bb_insn_dead_var (ctx, bb_insn, var);
- if (live_start2_p) add_bb_insn_dead_var (ctx, bb_insn, var2);
+ FOREACH_INSN_VAR (ctx, insn_var_iter, insn, var, out_p, mem_p, passed_mem_num) {
+ if (out_p) continue;
+ if (bitmap_set_bit_p (live, var)) add_bb_insn_dead_var (ctx, bb_insn, var);
}
- get_early_clobbered_hard_reg (insn, &early_clobbered_hard_reg1, &early_clobbered_hard_reg2);
+ target_get_early_clobbered_hard_regs (insn, &early_clobbered_hard_reg1,
+ &early_clobbered_hard_reg2);
if (early_clobbered_hard_reg1 != MIR_NON_HARD_REG)
bitmap_clear_bit_p (live, early_clobbered_hard_reg1);
if (early_clobbered_hard_reg2 != MIR_NON_HARD_REG)
@@ -3087,44 +4140,7 @@ static int make_var_live (MIR_context_t ctx, MIR_reg_t var, int point) {
return TRUE;
}
-static int make_reg_dead (MIR_context_t ctx, MIR_reg_t reg, int hard_reg_p, int point) {
- struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
-
- return make_var_dead (ctx, hard_reg_p ? reg : reg2var (gen_ctx, reg), point);
-}
-
-static int make_reg_live (MIR_context_t ctx, MIR_reg_t reg, int hard_reg_p, int point) {
- struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
-
- return make_var_live (ctx, hard_reg_p ? reg : reg2var (gen_ctx, reg), point);
-}
-
-static void make_live (size_t nb, void *data) {
- MIR_context_t ctx = data;
- struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
-
- make_var_live ((MIR_context_t) data, nb, curr_point);
-}
-static void make_dead (size_t nb, void *data) {
- MIR_context_t ctx = data;
- struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
-
- make_var_dead ((MIR_context_t) data, nb, curr_point);
-}
-
-static void make_live_through_call (size_t nb, void *data) {
- reg_info_t *bri;
- MIR_reg_t breg;
- MIR_context_t ctx = data;
- struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
-
- if (!var_is_reg_p (nb)) return;
- breg = reg2breg (gen_ctx, var2reg (gen_ctx, nb));
- bri = &VARR_ADDR (reg_info_t, curr_cfg->breg_info)[breg];
- bri->calls_num++;
-}
-
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
static void print_live_ranges (MIR_context_t ctx) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
size_t i;
@@ -3149,88 +4165,75 @@ static void print_live_ranges (MIR_context_t ctx) {
static void build_live_ranges (MIR_context_t ctx) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
MIR_insn_t insn;
- MIR_reg_t nvars, early_clobbered_hard_reg1, early_clobbered_hard_reg2;
- size_t i, nops;
- int incr_p, out_p;
- MIR_op_t op;
+ MIR_reg_t var, nvars, early_clobbered_hard_reg1, early_clobbered_hard_reg2;
+ size_t i, nel, passed_mem_num;
+ int incr_p, out_p, mem_p;
+ bitmap_iterator_t bi;
+ insn_var_iterator_t insn_var_iter;
curr_point = 0;
nvars = get_nvars (ctx);
gen_assert (VARR_LENGTH (live_range_t, var_live_ranges) == 0);
for (i = 0; i < nvars; i++) VARR_PUSH (live_range_t, var_live_ranges, NULL);
for (bb_t bb = DLIST_HEAD (bb_t, curr_cfg->bbs); bb != NULL; bb = DLIST_NEXT (bb_t, bb)) {
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL)
fprintf (debug_file, " ------BB%u end: point=%d\n", (unsigned) bb->index, curr_point);
#endif
bitmap_clear (live_vars);
- if (bb->live_out != NULL) bitmap_for_each (bb->live_out, make_live, ctx);
+ if (bb->live_out != NULL) FOREACH_BITMAP_BIT (bi, bb->live_out, nel) {
+ make_var_live (ctx, nel, curr_point);
+ }
for (bb_insn_t bb_insn = DLIST_TAIL (bb_insn_t, bb->bb_insns); bb_insn != NULL;
bb_insn = DLIST_PREV (bb_insn_t, bb_insn)) {
insn = bb_insn->insn;
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) {
fprintf (debug_file, " p%-5d", curr_point);
print_bb_insn (ctx, bb_insn, TRUE);
}
#endif
- nops = MIR_insn_nops (ctx, insn);
incr_p = FALSE;
- for (i = 0; i < nops; i++) {
- op = insn->ops[i];
- MIR_insn_op_mode (ctx, insn, i, &out_p);
- if (op.mode == MIR_OP_REG && out_p)
- incr_p |= make_reg_dead (ctx, op.u.reg, FALSE, curr_point);
- else if (op.mode == MIR_OP_HARD_REG && out_p)
- incr_p |= make_reg_dead (ctx, op.u.hard_reg, TRUE, curr_point);
+ FOREACH_INSN_VAR (ctx, insn_var_iter, insn, var, out_p, mem_p, passed_mem_num) {
+ if (out_p) incr_p |= make_var_dead (ctx, var, curr_point);
}
if (MIR_call_code_p (insn->code)) {
- bitmap_for_each (call_used_hard_regs, make_dead, ctx);
- bitmap_for_each (bb_insn->call_hard_reg_args, make_live, ctx);
- bitmap_for_each (live_vars, make_live_through_call, ctx);
+ FOREACH_BITMAP_BIT (bi, call_used_hard_regs, nel) { make_var_dead (ctx, nel, curr_point); }
+ FOREACH_BITMAP_BIT (bi, bb_insn->call_hard_reg_args, nel) {
+ make_var_live (ctx, nel, curr_point);
+ }
+ FOREACH_BITMAP_BIT (bi, live_vars, nel) {
+ reg_info_t *bri;
+ MIR_reg_t breg;
+
+ if (!var_is_reg_p (nel)) continue;
+ breg = reg2breg (gen_ctx, var2reg (gen_ctx, nel));
+ bri = &VARR_ADDR (reg_info_t, curr_cfg->breg_info)[breg];
+ bri->calls_num++;
+ }
}
if (incr_p) curr_point++;
incr_p = FALSE;
- for (i = 0; i < nops; i++) {
- op = insn->ops[i];
- switch (op.mode) {
- case MIR_OP_REG:
- MIR_insn_op_mode (ctx, insn, i, &out_p);
- if (!out_p) incr_p |= make_reg_live (ctx, op.u.reg, FALSE, curr_point);
- break;
- case MIR_OP_HARD_REG:
- MIR_insn_op_mode (ctx, insn, i, &out_p);
- if (!out_p) incr_p |= make_reg_live (ctx, op.u.hard_reg, TRUE, curr_point);
- break;
- case MIR_OP_MEM:
- if (op.u.mem.base != 0) incr_p |= make_reg_live (ctx, op.u.mem.base, FALSE, curr_point);
- if (op.u.mem.index != 0) incr_p |= make_reg_live (ctx, op.u.mem.index, FALSE, curr_point);
- break;
- case MIR_OP_HARD_REG_MEM:
- if (op.u.hard_reg_mem.base != MIR_NON_HARD_REG)
- incr_p |= make_reg_live (ctx, op.u.hard_reg_mem.base, TRUE, curr_point);
- if (op.u.hard_reg_mem.index != MIR_NON_HARD_REG)
- incr_p |= make_reg_live (ctx, op.u.hard_reg_mem.index, TRUE, curr_point);
- break;
- default: /* do nothing */ break;
- }
+ FOREACH_INSN_VAR (ctx, insn_var_iter, insn, var, out_p, mem_p, passed_mem_num) {
+ if (!out_p) incr_p |= make_var_live (ctx, var, curr_point);
}
- get_early_clobbered_hard_reg (insn, &early_clobbered_hard_reg1, &early_clobbered_hard_reg2);
+ target_get_early_clobbered_hard_regs (insn, &early_clobbered_hard_reg1,
+ &early_clobbered_hard_reg2);
if (early_clobbered_hard_reg1 != MIR_NON_HARD_REG) {
- incr_p |= make_reg_live (ctx, early_clobbered_hard_reg1, TRUE, curr_point);
- incr_p |= make_reg_dead (ctx, early_clobbered_hard_reg1, TRUE, curr_point);
+ incr_p |= make_var_live (ctx, early_clobbered_hard_reg1, curr_point);
+ incr_p |= make_var_dead (ctx, early_clobbered_hard_reg1, curr_point);
}
if (early_clobbered_hard_reg2 != MIR_NON_HARD_REG) {
- incr_p |= make_reg_live (ctx, early_clobbered_hard_reg2, TRUE, curr_point);
- incr_p |= make_reg_dead (ctx, early_clobbered_hard_reg2, TRUE, curr_point);
+ incr_p |= make_var_live (ctx, early_clobbered_hard_reg2, curr_point);
+ incr_p |= make_var_dead (ctx, early_clobbered_hard_reg2, curr_point);
}
if (incr_p) curr_point++;
}
gen_assert (bitmap_equal_p (live_vars, bb->live_in));
- bitmap_for_each (live_vars, make_dead, ctx);
+ FOREACH_BITMAP_BIT (bi, live_vars, nel) { make_var_dead (ctx, nel, curr_point); }
if (!bitmap_empty_p (bb->live_in)) curr_point++;
}
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) print_live_ranges (ctx);
#endif
}
@@ -3244,12 +4247,12 @@ static void destroy_func_live_ranges (MIR_context_t ctx) {
VARR_TRUNC (live_range_t, var_live_ranges, 0);
}
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
static void output_bb_live_info (MIR_context_t ctx, bb_t bb) {
- output_bitmap (ctx, " live_in:", bb->live_in);
- output_bitmap (ctx, " live_out:", bb->live_out);
- output_bitmap (ctx, " live_gen:", bb->live_gen);
- output_bitmap (ctx, " live_kill:", bb->live_kill);
+ output_bitmap (ctx, " live_in:", bb->live_in, TRUE);
+ output_bitmap (ctx, " live_out:", bb->live_out, TRUE);
+ output_bitmap (ctx, " live_gen:", bb->live_gen, TRUE);
+ output_bitmap (ctx, " live_kill:", bb->live_kill, TRUE);
}
#endif
@@ -3280,7 +4283,6 @@ static void finish_live_ranges (MIR_context_t ctx) {
/* Register allocation */
DEF_VARR (MIR_reg_t);
-DEF_VARR (size_t);
typedef struct breg_info {
MIR_reg_t breg;
@@ -3451,12 +4453,12 @@ static void assign (MIR_context_t ctx) {
best_profit = 0;
type = MIR_reg_type (ctx, reg, curr_func_item->u.func);
for (loc = 0; loc <= func_stack_slots_num + MAX_HARD_REG; loc++) {
- if (loc <= MAX_HARD_REG && !hard_reg_type_ok_p (loc, type)) continue;
- slots_num = locs_num (loc, type);
+ if (loc <= MAX_HARD_REG && !target_hard_reg_type_ok_p (loc, type)) continue;
+ slots_num = target_locs_num (loc, type);
for (k = 0; k < slots_num; k++)
if ((loc + k <= MAX_HARD_REG
- && (fixed_hard_reg_p (loc + k)
- || (call_used_hard_reg_p (loc + k) && curr_breg_infos[breg].calls_num > 0)))
+ && (target_fixed_hard_reg_p (loc + k)
+ || (target_call_used_hard_reg_p (loc + k) && curr_breg_infos[breg].calls_num > 0)))
|| bitmap_bit_p (conflict_locs, loc + k))
break;
if (k < slots_num) continue;
@@ -3471,7 +4473,7 @@ static void assign (MIR_context_t ctx) {
}
if (best_loc != MIR_NON_HARD_REG && loc == MAX_HARD_REG) break;
}
- slots_num = locs_num (best_loc, type);
+ slots_num = target_locs_num (best_loc, type);
if (best_loc <= MAX_HARD_REG) {
for (k = 0; k < slots_num; k++) bitmap_set_bit_p (func_assigned_hard_regs, best_loc + k);
} else if (best_loc == MIR_NON_HARD_REG) { /* Add stack slot ??? */
@@ -3483,7 +4485,7 @@ static void assign (MIR_context_t ctx) {
func_stack_slots_num = best_loc - MAX_HARD_REG;
best_loc -= slots_num - 1;
}
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) {
MIR_reg_t thread_breg = curr_breg_infos[breg].thread_first;
@@ -3501,7 +4503,7 @@ static void assign (MIR_context_t ctx) {
for (k = 0; k < slots_num; k++) bitmap_set_bit_p (point_used_locs_addr[j], best_loc + k);
}
for (i = 0; i <= curr_point; i++) bitmap_destroy (VARR_POP (bitmap_t, point_used_locs));
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) {
fprintf (debug_file, "+++++++++++++Disposition after assignment:");
for (i = 0; i < nregs; i++) {
@@ -3548,8 +4550,8 @@ static MIR_reg_t change_reg (MIR_context_t ctx, MIR_op_t *mem_op, MIR_reg_t reg,
code = MIR_LDMOV;
hard_reg = first_p ? TEMP_LDOUBLE_HARD_REG1 : TEMP_LDOUBLE_HARD_REG2;
}
- offset = get_stack_slot_offset (ctx, type, loc - MAX_HARD_REG - 1);
- *mem_op = _MIR_new_hard_reg_mem_op (ctx, type, offset, BP_HARD_REG, MIR_NON_HARD_REG, 0);
+ offset = target_get_stack_slot_offset (ctx, type, loc - MAX_HARD_REG - 1);
+ *mem_op = _MIR_new_hard_reg_mem_op (ctx, type, offset, FP_HARD_REG, MIR_NON_HARD_REG, 0);
if (hard_reg == MIR_NON_HARD_REG) return hard_reg;
hard_reg_op = _MIR_new_hard_reg_op (ctx, hard_reg);
if (out_p) {
@@ -3573,7 +4575,7 @@ static void rewrite (MIR_context_t ctx) {
bb_insn_t bb_insn, next_bb_insn;
size_t nops, i;
MIR_op_t *op, mem_op;
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
MIR_op_t in_op = MIR_new_int_op (ctx, 0),
out_op = MIR_new_int_op (ctx, 0); /* To remove unitilized warning */
#endif
@@ -3592,7 +4594,7 @@ static void rewrite (MIR_context_t ctx) {
for (i = 0; i < nops; i++) {
op = &insn->ops[i];
data_mode = MIR_insn_op_mode (ctx, insn, i, &out_p);
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (out_p)
out_op = *op; /* we don't care about multiple call outputs here */
else
@@ -3632,7 +4634,7 @@ static void rewrite (MIR_context_t ctx) {
|| insn->code == MIR_LDMOV) {
movs_num++;
if (MIR_op_eq_p (ctx, insn->ops[0], insn->ops[1])) {
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) {
fprintf (debug_file, "Deleting noop move ");
MIR_output_insn (ctx, debug_file, insn, curr_func_item->u.func, FALSE);
@@ -3648,7 +4650,7 @@ static void rewrite (MIR_context_t ctx) {
}
}
}
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL)
fprintf (debug_file,
"Deleting moves: %lu deleted noop moves out of %lu non-conflicting moves (%.1f%%), "
@@ -3886,7 +4888,7 @@ static void combine_delete_insn (MIR_context_t ctx, MIR_insn_t def_insn, bb_insn
gen_assert (def_insn->ops[0].mode == MIR_OP_HARD_REG);
hr = def_insn->ops[0].u.hard_reg;
if (hreg_ref_ages_addr[hr] != curr_bb_hreg_ref_age || hreg_refs_addr[hr].del_p) return;
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
// deleted_insns_num++;
if (debug_file != NULL) {
fprintf (debug_file, " deleting now dead insn ");
@@ -3914,6 +4916,7 @@ static int64_t power2 (int64_t p) {
static int64_t int_log2 (int64_t i) {
int64_t n;
+ if (i == 0) return -1;
for (n = 0; (i & 1) == 0; n++, i >>= 1)
;
return i == 1 ? n : -1;
@@ -3945,7 +4948,9 @@ static int combine_substitute (MIR_context_t ctx, bb_insn_t bb_insn) {
if (!hreg_refs_addr[hr].def_p) continue;
gen_assert (!hreg_refs_addr[hr].del_p);
def_insn = hreg_refs_addr[hr].insn;
- if (def_insn->nops > 1 && obsolete_op_p (ctx, def_insn->ops[1], hreg_refs_addr[hr].insn_num))
+ if ((def_insn->nops > 1 && obsolete_op_p (ctx, def_insn->ops[1], hreg_refs_addr[hr].insn_num))
+ || (def_insn->nops > 2
+ && obsolete_op_p (ctx, def_insn->ops[2], hreg_refs_addr[hr].insn_num)))
continue; /* hr0 = ... hr1 ...; ...; hr1 = ...; ...; insn */
insn_hr_change_p = FALSE;
for (i = 0; i < nops; i++) { /* Change all hr occurences: */
@@ -4055,7 +5060,7 @@ static int combine_substitute (MIR_context_t ctx, bb_insn_t bb_insn) {
}
new_insn = MIR_new_insn (ctx, new_code, insn->ops[0], insn->ops[1], MIR_new_int_op (ctx, sh));
MIR_insert_insn_after (ctx, curr_func_item, insn, new_insn);
- if (insn_ok_p (ctx, new_insn)) {
+ if (target_insn_ok_p (ctx, new_insn)) {
insn->code = new_insn->code;
insn->ops[0] = new_insn->ops[0];
insn->ops[1] = new_insn->ops[1];
@@ -4065,7 +5070,7 @@ static int combine_substitute (MIR_context_t ctx, bb_insn_t bb_insn) {
insn_hr_change_p = TRUE;
}
if (insn_hr_change_p) {
- if ((success_p = i >= nops && insn_ok_p (ctx, insn))) insn_change_p = TRUE;
+ if ((success_p = i >= nops && target_insn_ok_p (ctx, insn))) insn_change_p = TRUE;
while (VARR_LENGTH (size_t, changed_op_numbers)) {
i = VARR_POP (size_t, changed_op_numbers);
if (success_p)
@@ -4076,7 +5081,7 @@ static int combine_substitute (MIR_context_t ctx, bb_insn_t bb_insn) {
if (success_p) {
gen_assert (def_insn != NULL);
combine_delete_insn (ctx, def_insn, bb_insn);
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) {
fprintf (debug_file, " changing to ");
print_bb_insn (ctx, bb_insn, TRUE);
@@ -4153,14 +5158,14 @@ static MIR_insn_t combine_branch_and_cmp (MIR_context_t ctx, bb_insn_t bb_insn)
return NULL;
new_insn = MIR_new_insn (ctx, code, insn->ops[0], def_insn->ops[1], def_insn->ops[2]);
MIR_insert_insn_before (ctx, curr_func_item, insn, new_insn);
- if (!insn_ok_p (ctx, new_insn)) {
+ if (!target_insn_ok_p (ctx, new_insn)) {
MIR_remove_insn (ctx, curr_func_item, new_insn);
return NULL;
} else {
MIR_remove_insn (ctx, curr_func_item, insn);
new_insn->data = bb_insn;
bb_insn->insn = new_insn;
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) {
fprintf (debug_file, " changing to ");
print_bb_insn (ctx, bb_insn, TRUE);
@@ -4193,7 +5198,7 @@ static void combine (MIR_context_t ctx) {
MIR_op_t temp_op, *op_ref;
MIR_reg_t early_clobbered_hard_reg1, early_clobbered_hard_reg2;
int out_p, change_p, block_change_p;
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
size_t insns_num = 0, deleted_insns_num = 0;
#endif
@@ -4201,7 +5206,7 @@ static void combine (MIR_context_t ctx) {
hreg_ref_ages_addr = VARR_ADDR (size_t, hreg_ref_ages);
for (bb_t bb = DLIST_HEAD (bb_t, curr_cfg->bbs); bb != NULL; bb = DLIST_NEXT (bb_t, bb)) {
do {
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) fprintf (debug_file, "Processing bb%lu\n", (unsigned long) bb->index);
#endif
block_change_p = FALSE;
@@ -4211,14 +5216,15 @@ static void combine (MIR_context_t ctx) {
bb_insn = DLIST_NEXT (bb_insn_t, bb_insn), curr_insn_num++) {
insn = bb_insn->insn;
nops = MIR_insn_nops (ctx, insn);
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (insn->code != MIR_LABEL) insns_num++;
if (debug_file != NULL) {
fprintf (debug_file, " Processing ");
print_bb_insn (ctx, bb_insn, TRUE);
}
#endif
- get_early_clobbered_hard_reg (insn, &early_clobbered_hard_reg1, &early_clobbered_hard_reg2);
+ target_get_early_clobbered_hard_regs (insn, &early_clobbered_hard_reg1,
+ &early_clobbered_hard_reg2);
if (early_clobbered_hard_reg1 != MIR_NON_HARD_REG)
setup_hreg_ref (ctx, early_clobbered_hard_reg1, insn, 0 /* whatever */, curr_insn_num,
TRUE);
@@ -4275,7 +5281,7 @@ static void combine (MIR_context_t ctx) {
}
} while (block_change_p);
}
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL)
fprintf (debug_file, " %lu deleted out of %lu (%.1f%%)\n", deleted_insns_num, insns_num,
100.0 * deleted_insns_num / insns_num);
@@ -4323,13 +5329,13 @@ static void dead_code_elimination (MIR_context_t ctx) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
MIR_insn_t insn;
bb_insn_t bb_insn, prev_bb_insn;
- size_t nops, i;
+ size_t passed_mem_num;
MIR_reg_t var, early_clobbered_hard_reg1, early_clobbered_hard_reg2;
- MIR_op_t op;
- int out_p, reg_def_p, dead_p;
+ int out_p, reg_def_p, dead_p, mem_p;
bitmap_t live;
+ insn_var_iterator_t insn_var_iter;
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) fprintf (debug_file, "+++++++++++++Dead code elimination:\n");
#endif
live = bitmap_create2 (DEFAULT_INIT_BITMAP_BITS_NUM);
@@ -4338,25 +5344,21 @@ static void dead_code_elimination (MIR_context_t ctx) {
for (bb_insn = DLIST_TAIL (bb_insn_t, bb->bb_insns); bb_insn != NULL; bb_insn = prev_bb_insn) {
prev_bb_insn = DLIST_PREV (bb_insn_t, bb_insn);
insn = bb_insn->insn;
- nops = MIR_insn_nops (ctx, insn);
reg_def_p = FALSE;
dead_p = TRUE;
- for (i = 0; i < nops; i++) {
- op = insn->ops[i];
- MIR_insn_op_mode (ctx, insn, i, &out_p);
- if (!out_p || (op.mode != MIR_OP_REG && op.mode != MIR_OP_HARD_REG)) continue;
+ FOREACH_INSN_VAR (ctx, insn_var_iter, insn, var, out_p, mem_p, passed_mem_num) {
+ if (!out_p) continue;
reg_def_p = TRUE;
- var = op.mode == MIR_OP_HARD_REG ? op.u.hard_reg : reg2var (gen_ctx, op.u.reg);
if (bitmap_clear_bit_p (live, var)) dead_p = FALSE;
}
if (!reg_def_p) dead_p = FALSE;
if (dead_p && !MIR_call_code_p (insn->code) && insn->code != MIR_RET
&& insn->code != MIR_ALLOCA && insn->code != MIR_BSTART && insn->code != MIR_BEND
- && insn->code != MIR_VA_START && insn->code != MIR_VA_END
+ && insn->code != MIR_VA_START && insn->code != MIR_VA_ARG && insn->code != MIR_VA_END
&& !(insn->ops[0].mode == MIR_OP_HARD_REG
- && (insn->ops[0].u.hard_reg == BP_HARD_REG
+ && (insn->ops[0].u.hard_reg == FP_HARD_REG
|| insn->ops[0].u.hard_reg == SP_HARD_REG))) {
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) {
fprintf (debug_file, " Removing dead insn");
MIR_output_insn (ctx, debug_file, insn, curr_func_item->u.func, TRUE);
@@ -4366,30 +5368,11 @@ static void dead_code_elimination (MIR_context_t ctx) {
continue;
}
if (MIR_call_code_p (insn->code)) bitmap_and_compl (live, live, call_used_hard_regs);
- for (i = 0; i < nops; i++) {
- op = insn->ops[i];
- MIR_insn_op_mode (ctx, insn, i, &out_p);
- switch (op.mode) {
- case MIR_OP_REG:
- if (!out_p) bitmap_set_bit_p (live, reg2var (gen_ctx, op.u.reg));
- break;
- case MIR_OP_HARD_REG:
- if (!out_p) bitmap_set_bit_p (live, op.u.hard_reg);
- break;
- case MIR_OP_MEM:
- if (op.u.mem.base != 0) bitmap_set_bit_p (live, reg2var (gen_ctx, op.u.mem.base));
- if (op.u.mem.index != 0) bitmap_set_bit_p (live, reg2var (gen_ctx, op.u.mem.index));
- break;
- case MIR_OP_HARD_REG_MEM:
- if (op.u.hard_reg_mem.base != MIR_NON_HARD_REG)
- bitmap_set_bit_p (live, op.u.hard_reg_mem.base);
- if (op.u.hard_reg_mem.index != MIR_NON_HARD_REG)
- bitmap_set_bit_p (live, op.u.hard_reg_mem.index);
- break;
- default: break;
- }
+ FOREACH_INSN_VAR (ctx, insn_var_iter, insn, var, out_p, mem_p, passed_mem_num) {
+ if (!out_p) bitmap_set_bit_p (live, var);
}
- get_early_clobbered_hard_reg (insn, &early_clobbered_hard_reg1, &early_clobbered_hard_reg2);
+ target_get_early_clobbered_hard_regs (insn, &early_clobbered_hard_reg1,
+ &early_clobbered_hard_reg2);
if (early_clobbered_hard_reg1 != MIR_NON_HARD_REG)
bitmap_clear_bit_p (live, early_clobbered_hard_reg1);
if (early_clobbered_hard_reg2 != MIR_NON_HARD_REG)
@@ -4402,7 +5385,7 @@ static void dead_code_elimination (MIR_context_t ctx) {
#undef live_out
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
#include
#include
@@ -4414,9 +5397,14 @@ static void print_code (MIR_context_t ctx, uint8_t *code, size_t code_len, void
char cfname[30];
char command[500];
FILE *f;
+#if !defined(__APPLE__)
+ char bfname[30];
+ FILE *bf;
+#endif
sprintf (cfname, "_mir_%lu.c", (unsigned long) getpid ());
if ((f = fopen (cfname, "w")) == NULL) return;
+#if defined(__APPLE__)
fprintf (f, "unsigned char code[] = {");
for (i = 0; i < code_len; i++) {
if (i != 0) fprintf (f, ", ");
@@ -4424,17 +5412,30 @@ static void print_code (MIR_context_t ctx, uint8_t *code, size_t code_len, void
}
fprintf (f, "};\n");
fclose (f);
+ sprintf (command, "gcc -c -o %s.o %s 2>&1 && objdump --section=.data -D %s.o; rm -f %s.o %s",
+ cfname, cfname, cfname, cfname, cfname);
+#else
+ sprintf (bfname, "_mir_%lu.bin", (unsigned long) getpid ());
+ if ((bf = fopen (bfname, "w")) == NULL) return;
+ fprintf (f, "void code (void) {}\n");
+ for (i = 0; i < code_len; i++) fputc (code[i], bf);
+ fclose (f);
+ fclose (bf);
sprintf (command,
- "gcc -c -o %s.o %s 2>&1 && objdump --section=.data --adjust-vma=0x%lx -D %s.o; rm -f "
- "%s.o %s",
- cfname, cfname, (unsigned long) start_addr, cfname, cfname, cfname);
+ "gcc -c -o %s.o %s 2>&1 && objcopy --update-section .text=%s %s.o && objdump "
+ "--adjust-vma=0x%lx -d %s.o; rm -f "
+ "%s.o %s %s",
+ cfname, cfname, bfname, cfname, (unsigned long) start_addr, cfname, cfname, cfname,
+ bfname);
+#endif
+ fprintf (stderr, "%s\n", command);
if ((f = popen (command, "r")) == NULL) return;
while ((ch = fgetc (f)) != EOF) fprintf (debug_file, "%c", ch);
pclose (f);
}
#endif
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
#include
static double real_usec_time (void) {
@@ -4457,7 +5458,7 @@ void *MIR_gen (MIR_context_t ctx, MIR_item_t func_item) {
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
uint8_t *code;
size_t code_len;
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
double start_time = 0.0;
#endif
@@ -4465,14 +5466,14 @@ void *MIR_gen (MIR_context_t ctx, MIR_item_t func_item) {
if (func_item->u.func->machine_code != NULL) {
gen_assert (func_item->u.func->call_addr != NULL);
_MIR_redirect_thunk (ctx, func_item->addr, func_item->u.func->call_addr);
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL)
fprintf (debug_file, "+++++++++++++The code for %s has been already generated\n",
MIR_item_name (ctx, func_item));
#endif
return func_item->addr;
}
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) {
start_time = real_usec_time ();
fprintf (debug_file, "+++++++++++++MIR before generator:\n");
@@ -4483,111 +5484,161 @@ void *MIR_gen (MIR_context_t ctx, MIR_item_t func_item) {
_MIR_duplicate_func_insns (ctx, func_item);
curr_cfg = func_item->data = gen_malloc (ctx, sizeof (struct func_cfg));
build_func_cfg (ctx);
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) {
fprintf (debug_file, "+++++++++++++MIR after building CFG:\n");
- print_CFG (ctx, TRUE, TRUE, NULL);
+ print_CFG (ctx, TRUE, FALSE, TRUE, FALSE, NULL);
}
#endif
#ifndef NO_CSE
-#if MIR_GEN_DEBUG
- if (debug_file != NULL) fprintf (debug_file, "+++++++++++++CSE:\n");
+ if (optimize_level >= 2) {
+#if !MIR_NO_GEN_DEBUG
+ if (debug_file != NULL) fprintf (debug_file, "+++++++++++++CSE:\n");
#endif
- cse (ctx);
-#if MIR_GEN_DEBUG
- if (debug_file != NULL) {
- print_exprs (ctx);
- fprintf (debug_file, "+++++++++++++MIR after CSE:\n");
- print_CFG (ctx, TRUE, TRUE, output_bb_cse_info);
- }
+ cse (ctx);
+#if !MIR_NO_GEN_DEBUG
+ if (debug_file != NULL) {
+ print_exprs (ctx);
+ fprintf (debug_file, "+++++++++++++MIR after CSE:\n");
+ print_CFG (ctx, TRUE, FALSE, TRUE, FALSE, output_bb_cse_info);
+ }
#endif
- cse_clear (ctx);
+ cse_clear (ctx);
+ }
#endif /* #ifndef NO_CSE */
calculate_func_cfg_live_info (ctx, FALSE);
#ifndef NO_CSE
- dead_code_elimination (ctx);
-#if MIR_GEN_DEBUG
- if (debug_file != NULL) {
- fprintf (debug_file, "+++++++++++++MIR after dead code elimination after CSE:\n");
- print_CFG (ctx, TRUE, TRUE, output_bb_live_info);
- }
+ if (optimize_level >= 2) {
+ dead_code_elimination (ctx);
+#if !MIR_NO_GEN_DEBUG
+ if (debug_file != NULL) {
+ fprintf (debug_file, "+++++++++++++MIR after dead code elimination after CSE:\n");
+ print_CFG (ctx, TRUE, TRUE, TRUE, FALSE, output_bb_live_info);
+ }
#endif
+ }
+#endif /* #ifndef NO_CSE */
+#ifndef NO_RENAME
+ if (optimize_level >= 3) {
+#if !MIR_NO_GEN_DEBUG
+ if (debug_file != NULL) fprintf (debug_file, "+++++++++++++Rename:\n");
#endif
-#ifndef NO_CCP
- if (ccp (ctx)) {
-#if MIR_GEN_DEBUG
+ calculate_reaching_defs (ctx);
+ reg_rename (ctx);
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) {
- fprintf (debug_file, "+++++++++++++MIR after CCP:\n");
- print_CFG (ctx, TRUE, TRUE, NULL);
+ fprintf (debug_file, "+++++++++++++MIR after rename:\n");
+ print_CFG (ctx, TRUE, FALSE, TRUE, TRUE, output_bb_rdef_info);
}
#endif
- dead_code_elimination (ctx);
-#if MIR_GEN_DEBUG
- if (debug_file != NULL) {
- fprintf (debug_file, "+++++++++++++MIR after dead code elimination after CCP:\n");
- print_CFG (ctx, TRUE, TRUE, output_bb_live_info);
+ rdef_clear (ctx);
+ calculate_func_cfg_live_info (ctx, FALSE); /* restore live info */
+ }
+#endif /* #ifndef NO_RENAME */
+#ifndef NO_LICM
+ if (optimize_level >= 3) {
+ if (build_loop_tree (ctx)) {
+ licm_add_loop_preheaders (ctx, curr_cfg->root_loop_node);
+ calculate_reaching_defs (ctx);
+#if !MIR_NO_GEN_DEBUG
+ if (debug_file != NULL) fprintf (debug_file, "+++++++++++++LICM:\n");
+#endif
+ licm (ctx);
+#if !MIR_NO_GEN_DEBUG
+ if (debug_file != NULL) {
+ fprintf (debug_file, "+++++++++++++MIR after LICM:\n");
+ print_CFG (ctx, TRUE, FALSE, TRUE, TRUE, output_bb_licm_info);
+ }
+#endif
+ rdef_clear (ctx);
+ calculate_func_cfg_live_info (ctx, FALSE); /* restore live info */
}
+ destroy_loop_tree (ctx, curr_cfg->root_loop_node);
+ curr_cfg->root_loop_node = NULL;
+ }
+#endif /* #ifndef NO_LICM */
+#ifndef NO_CCP
+ if (optimize_level >= 2) {
+#if !MIR_NO_GEN_DEBUG
+ if (debug_file != NULL) fprintf (debug_file, "+++++++++++++CCP:\n");
+#endif
+ if (ccp (ctx)) {
+#if !MIR_NO_GEN_DEBUG
+ if (debug_file != NULL) {
+ fprintf (debug_file, "+++++++++++++MIR after CCP:\n");
+ print_CFG (ctx, TRUE, FALSE, TRUE, FALSE, NULL);
+ }
+#endif
+ dead_code_elimination (ctx);
+#if !MIR_NO_GEN_DEBUG
+ if (debug_file != NULL) {
+ fprintf (debug_file, "+++++++++++++MIR after dead code elimination after CCP:\n");
+ print_CFG (ctx, TRUE, TRUE, TRUE, FALSE, output_bb_live_info);
+ }
#endif
+ }
}
#endif /* #ifndef NO_CCP */
ccp_clear (ctx);
make_io_dup_op_insns (ctx);
- machinize (ctx);
+ target_machinize (ctx);
add_new_bb_insns (ctx);
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) {
fprintf (debug_file, "+++++++++++++MIR after machinize:\n");
- print_CFG (ctx, FALSE, TRUE, NULL);
+ print_CFG (ctx, FALSE, FALSE, TRUE, FALSE, NULL);
}
#endif
build_loop_tree (ctx);
calculate_func_cfg_live_info (ctx, TRUE);
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) {
add_bb_insn_dead_vars (ctx);
fprintf (debug_file, "+++++++++++++MIR after building live_info:\n");
- print_loop_tree (ctx);
- print_CFG (ctx, TRUE, FALSE, output_bb_live_info);
+ print_loop_tree (ctx, TRUE);
+ print_CFG (ctx, TRUE, TRUE, FALSE, FALSE, output_bb_live_info);
}
#endif
build_live_ranges (ctx);
assign (ctx);
rewrite (ctx); /* After rewrite the BB live info is still valid */
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) {
fprintf (debug_file, "+++++++++++++MIR after rewrite:\n");
- print_CFG (ctx, FALSE, TRUE, NULL);
+ print_CFG (ctx, FALSE, FALSE, TRUE, FALSE, NULL);
}
#endif
calculate_func_cfg_live_info (ctx, FALSE);
add_bb_insn_dead_vars (ctx);
-#if MIR_GEN_DEBUG
- if (debug_file != NULL) {
- fprintf (debug_file, "+++++++++++++MIR before combine:\n");
- print_CFG (ctx, FALSE, TRUE, NULL);
- }
-#endif
#ifndef NO_COMBINE
- combine (ctx); /* After combine the BB live info is still valid */
-#if MIR_GEN_DEBUG
- if (debug_file != NULL) {
- fprintf (debug_file, "+++++++++++++MIR after combine:\n");
- print_CFG (ctx, FALSE, TRUE, NULL);
- }
+ if (optimize_level >= 1) {
+#if !MIR_NO_GEN_DEBUG
+ if (debug_file != NULL) {
+ fprintf (debug_file, "+++++++++++++MIR before combine:\n");
+ print_CFG (ctx, FALSE, FALSE, TRUE, FALSE, NULL);
+ }
#endif
- dead_code_elimination (ctx);
-#if MIR_GEN_DEBUG
- if (debug_file != NULL) {
- fprintf (debug_file, "+++++++++++++MIR after dead code elimination after combine:\n");
- print_CFG (ctx, TRUE, TRUE, output_bb_live_info);
- }
+ combine (ctx); /* After combine the BB live info is still valid */
+#if !MIR_NO_GEN_DEBUG
+ if (debug_file != NULL) {
+ fprintf (debug_file, "+++++++++++++MIR after combine:\n");
+ print_CFG (ctx, FALSE, FALSE, TRUE, FALSE, NULL);
+ }
#endif
+ dead_code_elimination (ctx);
+#if !MIR_NO_GEN_DEBUG
+ if (debug_file != NULL) {
+ fprintf (debug_file, "+++++++++++++MIR after dead code elimination after combine:\n");
+ print_CFG (ctx, TRUE, TRUE, TRUE, FALSE, output_bb_live_info);
+ }
+#endif
+ }
#endif /* #ifndef NO_COMBINE */
- make_prolog_epilog (ctx, func_assigned_hard_regs, func_stack_slots_num);
-#if MIR_GEN_DEBUG
+ target_make_prolog_epilog (ctx, func_assigned_hard_regs, func_stack_slots_num);
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) {
fprintf (debug_file, "+++++++++++++MIR after forming prolog/epilog:\n");
- print_CFG (ctx, FALSE, TRUE, NULL);
+ print_CFG (ctx, FALSE, FALSE, TRUE, FALSE, NULL);
}
#endif
code = target_translate (ctx, &code_len);
@@ -4597,7 +5648,7 @@ void *MIR_gen (MIR_context_t ctx, MIR_item_t func_item) {
#if MIR_GEN_CALL_TRACE
func_item->u.func->call_addr = _MIR_get_wrapper (ctx, func_item, print_and_execute_wrapper);
#endif
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL) {
print_code (ctx, func_item->u.func->machine_code, code_len, func_item->u.func->machine_code);
fprintf (debug_file, "code size = %lu:\n", (unsigned long) code_len);
@@ -4607,7 +5658,7 @@ void *MIR_gen (MIR_context_t ctx, MIR_item_t func_item) {
destroy_func_live_ranges (ctx);
destroy_loop_tree (ctx, curr_cfg->root_loop_node);
destroy_func_cfg (ctx);
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
if (debug_file != NULL)
fprintf (debug_file, "Generation of code for %s -- time %.0f usec\n",
MIR_item_name (ctx, func_item), real_usec_time () - start_time);
@@ -4617,34 +5668,49 @@ void *MIR_gen (MIR_context_t ctx, MIR_item_t func_item) {
}
void MIR_gen_set_debug_file (MIR_context_t ctx, FILE *f) {
-#if MIR_GEN_DEBUG
+#if !MIR_NO_GEN_DEBUG
struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ if (gen_ctx == NULL) {
+ fprintf (stderr, "Calling MIR_gen_set_debug_file before MIR_gen_init -- good bye\n");
+ exit (1);
+ }
debug_file = f;
#endif
}
+void MIR_gen_set_optimize_level (MIR_context_t ctx, unsigned int level) {
+ struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+
+ optimize_level = level;
+}
+
void MIR_gen_init (MIR_context_t ctx) {
struct gen_ctx **gen_ctx_ptr = gen_ctx_loc (ctx), *gen_ctx;
MIR_reg_t i;
-#ifdef TEST_MIR_GEN
- if (debug_file != NULL) fprintf (debug_file, "Page size = %lu\n", (unsigned long) page_size);
-#endif
*gen_ctx_ptr = gen_ctx = gen_malloc (ctx, sizeof (struct gen_ctx));
+ optimize_level = 2;
gen_ctx->target_ctx = NULL;
gen_ctx->data_flow_ctx = NULL;
gen_ctx->cse_ctx = NULL;
+ gen_ctx->rdef_ctx = NULL;
+ gen_ctx->rename_ctx = NULL;
+ gen_ctx->licm_ctx = NULL;
gen_ctx->ccp_ctx = NULL;
gen_ctx->lr_ctx = NULL;
gen_ctx->ra_ctx = NULL;
gen_ctx->selection_ctx = NULL;
+ debug_file = NULL;
VARR_CREATE (loop_node_t, loop_nodes, 32);
VARR_CREATE (loop_node_t, queue_nodes, 32);
VARR_CREATE (loop_node_t, loop_entries, 16);
init_dead_vars ();
init_data_flow (ctx);
init_cse (ctx);
+ init_rdef (ctx);
+ init_rename (ctx);
+ init_licm (ctx);
init_ccp (ctx);
temp_bitmap = bitmap_create2 (DEFAULT_INIT_BITMAP_BITS_NUM);
temp_bitmap2 = bitmap_create2 (DEFAULT_INIT_BITMAP_BITS_NUM);
@@ -4652,18 +5718,26 @@ void MIR_gen_init (MIR_context_t ctx) {
init_live_ranges (ctx);
init_ra (ctx);
init_selection (ctx);
+ target_init (ctx);
call_used_hard_regs = bitmap_create2 (MAX_HARD_REG + 1);
- for (i = 0; i <= MAX_HARD_REG; i++)
- if (call_used_hard_reg_p (i)) bitmap_set_bit_p (call_used_hard_regs, i);
+ max_int_hard_regs = max_fp_hard_regs = 0;
+ for (i = 0; i <= MAX_HARD_REG; i++) {
+ if (target_fixed_hard_reg_p (i)) continue;
+ if (target_call_used_hard_reg_p (i)) bitmap_set_bit_p (call_used_hard_regs, i);
+ target_hard_reg_type_ok_p (i, MIR_T_I32) ? max_int_hard_regs++ : max_fp_hard_regs++;
+ }
insn_to_consider = bitmap_create2 (1024);
- target_init (ctx);
}
void MIR_gen_finish (MIR_context_t ctx) {
- struct gen_ctx *gen_ctx = *gen_ctx_loc (ctx);
+ struct gen_ctx **gen_ctx_ptr = gen_ctx_loc (ctx);
+ struct gen_ctx *gen_ctx = *gen_ctx_ptr;
finish_data_flow (ctx);
finish_cse (ctx);
+ finish_rdef (ctx);
+ finish_rename (ctx);
+ finish_licm (ctx);
finish_ccp (ctx);
bitmap_destroy (temp_bitmap);
bitmap_destroy (temp_bitmap2);
@@ -4680,6 +5754,7 @@ void MIR_gen_finish (MIR_context_t ctx) {
VARR_DESTROY (loop_node_t, queue_nodes);
VARR_DESTROY (loop_node_t, loop_entries);
free (gen_ctx);
+ *gen_ctx_ptr = NULL;
}
void MIR_set_gen_interface (MIR_context_t ctx, MIR_item_t func_item) { MIR_gen (ctx, func_item); }
diff --git a/mir/mir-gen.h b/mir/mir-gen.h
index bec4252..9c18e31 100644
--- a/mir/mir-gen.h
+++ b/mir/mir-gen.h
@@ -8,15 +8,16 @@
#include "mir.h"
-#ifndef MIR_GEN_DEBUG
-#define MIR_GEN_DEBUG 0
+#ifndef MIR_NO_GEN_DEBUG
+#define MIR_NO_GEN_DEBUG 0
#endif
-extern void MIR_gen_init (MIR_context_t context);
-extern void MIR_gen_set_debug_file (MIR_context_t context, FILE *f);
-extern void *MIR_gen (MIR_context_t context, MIR_item_t func_item);
-extern void MIR_set_gen_interface (MIR_context_t context, MIR_item_t func_item);
-extern void MIR_set_lazy_gen_interface (MIR_context_t context, MIR_item_t func_item);
-extern void MIR_gen_finish (MIR_context_t context);
+extern void MIR_gen_init (MIR_context_t ctx);
+extern void MIR_gen_set_debug_file (MIR_context_t ctx, FILE *f);
+extern void MIR_gen_set_optimize_level (MIR_context_t ctx, unsigned int level);
+extern void *MIR_gen (MIR_context_t ctx, MIR_item_t func_item);
+extern void MIR_set_gen_interface (MIR_context_t ctx, MIR_item_t func_item);
+extern void MIR_set_lazy_gen_interface (MIR_context_t ctx, MIR_item_t func_item);
+extern void MIR_gen_finish (MIR_context_t ctx);
#endif /* #ifndef MIR_GEN_H */
diff --git a/mir/mir-htab.h b/mir/mir-htab.h
index ef3cee1..6dffa22 100644
--- a/mir/mir-htab.h
+++ b/mir/mir-htab.h
@@ -72,149 +72,157 @@ DEF_VARR (htab_ind_t)
DEF_VARR (HTAB_EL (T)) \
typedef struct { \
htab_size_t els_num, els_start, els_bound, collisions; \
- htab_hash_t (*hash_func) (T el); \
- int (*eq_func) (T el1, T el2); \
- void (*free_func) (T el); \
+ void *arg; \
+ htab_hash_t (*hash_func) (T el, void *arg); \
+ int (*eq_func) (T el1, T el2, void *arg); \
+ void (*free_func) (T el, void *arg); \
VARR (HTAB_EL (T)) * els; \
VARR (htab_ind_t) * entries; \
} HTAB (T);
-#define DEF_HTAB(T) \
- HTAB_T (T) \
- \
- static inline void HTAB_OP_DEF (T, create) (HTAB (T) * *htab, htab_size_t min_size, \
- htab_hash_t (*hash_func) (T el), \
- int (*eq_func) (T el1, T el2), \
- void (*free_func) (T el)) { \
- HTAB (T) * ht; \
- htab_size_t i, size; \
- \
- for (size = 2; min_size > size; size *= 2) \
- ; \
- ht = malloc (sizeof (*ht)); \
- if (ht == NULL) mir_htab_error ("htab: no memory"); \
- VARR_CREATE (HTAB_EL (T), ht->els, size); \
- VARR_TAILOR (HTAB_EL (T), ht->els, size); \
- VARR_CREATE (htab_ind_t, ht->entries, 2 * size); \
- ht->hash_func = hash_func; \
- ht->eq_func = eq_func; \
- ht->free_func = free_func; \
- ht->els_num = ht->els_start = ht->els_bound = ht->collisions = 0; \
- for (i = 0; i < 2 * size; i++) VARR_PUSH (htab_ind_t, ht->entries, HTAB_EMPTY_IND); \
- *htab = ht; \
- } \
- \
- static inline void HTAB_OP_DEF (T, clear) (HTAB (T) * htab) { \
- htab_ind_t *addr; \
- htab_size_t i, size; \
- HTAB_EL (T) * els_addr; \
- \
- HTAB_ASSERT (htab != NULL, "clear", T); \
- if (htab->free_func != NULL) { \
- els_addr = VARR_ADDR (HTAB_EL (T), htab->els); \
- size = VARR_LENGTH (HTAB_EL (T), htab->els); \
- for (i = 0; i < htab->els_bound; i++) \
- if (els_addr[i].hash != HTAB_DELETED_HASH) htab->free_func (els_addr[i].el); \
- } \
- htab->els_num = htab->els_start = htab->els_bound = 0; \
- addr = VARR_ADDR (htab_ind_t, htab->entries); \
- size = VARR_LENGTH (htab_ind_t, htab->entries); \
- for (i = 0; i < size; i++) addr[i] = HTAB_EMPTY_IND; \
- } \
- \
- static inline void HTAB_OP_DEF (T, destroy) (HTAB (T) * *htab) { \
- HTAB_ASSERT (*htab != NULL, "destroy", T); \
- if ((*htab)->free_func != NULL) HTAB_OP (T, clear) (*htab); \
- VARR_DESTROY (HTAB_EL (T), (*htab)->els); \
- VARR_DESTROY (htab_ind_t, (*htab)->entries); \
- free (*htab); \
- *htab = NULL; \
- } \
- \
- static inline int HTAB_OP_DEF (T, do) (HTAB (T) * htab, T el, enum htab_action action, \
- T * res) { \
- htab_ind_t ind, el_ind, *entry, *first_deleted_entry = NULL; \
- htab_hash_t hash, peterb; \
- htab_size_t els_size, size, mask, start, bound, i; \
- htab_ind_t *addr; \
- HTAB_EL (T) * els_addr; \
- \
- HTAB_ASSERT (htab != NULL, "do htab", T); \
- size = VARR_LENGTH (htab_ind_t, htab->entries); \
- els_size = VARR_LENGTH (HTAB_EL (T), htab->els); \
- HTAB_ASSERT (els_size * 2 == size, "do size", T); \
- if ((action == HTAB_INSERT || action == HTAB_REPLACE) && htab->els_bound == els_size) { \
- size *= 2; \
- VARR_TAILOR (htab_ind_t, htab->entries, size); \
- addr = VARR_ADDR (htab_ind_t, htab->entries); \
- for (i = 0; i < size; i++) addr[i] = HTAB_EMPTY_IND; \
- VARR_TAILOR (HTAB_EL (T), htab->els, els_size * 2); \
- els_addr = VARR_ADDR (HTAB_EL (T), htab->els); \
- start = htab->els_start; \
- bound = htab->els_bound; \
- htab->els_start = htab->els_bound = htab->els_num = 0; \
- for (i = start; i < bound; i++) \
- if (els_addr[i].hash != HTAB_DELETED_HASH) { \
- HTAB_OP (T, do) (htab, els_addr[i].el, HTAB_INSERT, res); \
- HTAB_ASSERT ((*htab->eq_func) (*res, els_addr[i].el), "do expand", T); \
- } \
- HTAB_ASSERT (bound - start >= htab->els_bound, "do bound", T); \
- } \
- mask = size - 1; \
- hash = (*htab->hash_func) (el); \
- if (hash == HTAB_DELETED_HASH) hash += 1; \
- peterb = hash; \
- ind = hash & mask; \
- addr = VARR_ADDR (htab_ind_t, htab->entries); \
- els_addr = VARR_ADDR (HTAB_EL (T), htab->els); \
- for (;; htab->collisions++) { \
- entry = addr + ind; \
- el_ind = *entry; \
- if (el_ind != HTAB_EMPTY_IND) { \
- if (el_ind == HTAB_DELETED_IND) { \
- first_deleted_entry = entry; \
- } else if (els_addr[el_ind].hash == hash && (*htab->eq_func) (els_addr[el_ind].el, el)) { \
- if (action == HTAB_REPLACE) { \
- if (htab->free_func != NULL) htab->free_func (els_addr[el_ind].el); \
- els_addr[el_ind].el = el; \
- } \
- if (action != HTAB_DELETE) { \
- *res = els_addr[el_ind].el; \
- } else { \
- htab->els_num--; \
- *entry = HTAB_DELETED_IND; \
- if (htab->free_func != NULL) htab->free_func (els_addr[el_ind].el); \
- els_addr[el_ind].hash = HTAB_DELETED_HASH; \
- } \
- return TRUE; \
- } \
- } else { \
- if (action == HTAB_INSERT || action == HTAB_REPLACE) { \
- htab->els_num++; \
- if (first_deleted_entry != NULL) entry = first_deleted_entry; \
- els_addr[htab->els_bound].hash = hash; \
- els_addr[htab->els_bound].el = el; \
- *entry = htab->els_bound++; \
- *res = el; \
- } \
- return FALSE; \
- } \
- peterb >>= 11; \
- ind = (5 * ind + peterb + 1) & mask; \
- } \
- } \
- \
- static inline htab_size_t HTAB_OP_DEF (T, els_num) (HTAB (T) * htab) { \
- HTAB_ASSERT (htab != NULL, "els_num", T); \
- return htab->els_num; \
- } \
- static inline htab_size_t HTAB_OP_DEF (T, collisions) (HTAB (T) * htab) { \
- HTAB_ASSERT (htab != NULL, "collisions", T); \
- return htab->collisions; \
+#define DEF_HTAB(T) \
+ HTAB_T (T) \
+ \
+ static inline void HTAB_OP_DEF (T, create) (HTAB (T) * *htab, htab_size_t min_size, \
+ htab_hash_t (*hash_func) (T el, void *arg), \
+ int (*eq_func) (T el1, T el2, void *arg), \
+ void (*free_func) (T el, void *arg), void *arg) { \
+ HTAB (T) * ht; \
+ htab_size_t i, size; \
+ \
+ for (size = 2; min_size > size; size *= 2) \
+ ; \
+ ht = malloc (sizeof (*ht)); \
+ if (ht == NULL) mir_htab_error ("htab: no memory"); \
+ VARR_CREATE (HTAB_EL (T), ht->els, size); \
+ VARR_TAILOR (HTAB_EL (T), ht->els, size); \
+ VARR_CREATE (htab_ind_t, ht->entries, 2 * size); \
+ ht->arg = arg; \
+ ht->hash_func = hash_func; \
+ ht->eq_func = eq_func; \
+ ht->free_func = free_func; \
+ ht->els_num = ht->els_start = ht->els_bound = ht->collisions = 0; \
+ for (i = 0; i < 2 * size; i++) VARR_PUSH (htab_ind_t, ht->entries, HTAB_EMPTY_IND); \
+ *htab = ht; \
+ } \
+ \
+ static inline void HTAB_OP_DEF (T, clear) (HTAB (T) * htab) { \
+ htab_ind_t *addr; \
+ htab_size_t i, size; \
+ HTAB_EL (T) * els_addr; \
+ void *arg; \
+ \
+ HTAB_ASSERT (htab != NULL, "clear", T); \
+ arg = htab->arg; \
+ if (htab->free_func != NULL) { \
+ els_addr = VARR_ADDR (HTAB_EL (T), htab->els); \
+ size = VARR_LENGTH (HTAB_EL (T), htab->els); \
+ for (i = 0; i < htab->els_bound; i++) \
+ if (els_addr[i].hash != HTAB_DELETED_HASH) htab->free_func (els_addr[i].el, arg); \
+ } \
+ htab->els_num = htab->els_start = htab->els_bound = 0; \
+ addr = VARR_ADDR (htab_ind_t, htab->entries); \
+ size = VARR_LENGTH (htab_ind_t, htab->entries); \
+ for (i = 0; i < size; i++) addr[i] = HTAB_EMPTY_IND; \
+ } \
+ \
+ static inline void HTAB_OP_DEF (T, destroy) (HTAB (T) * *htab) { \
+ HTAB_ASSERT (*htab != NULL, "destroy", T); \
+ if ((*htab)->free_func != NULL) HTAB_OP (T, clear) (*htab); \
+ VARR_DESTROY (HTAB_EL (T), (*htab)->els); \
+ VARR_DESTROY (htab_ind_t, (*htab)->entries); \
+ free (*htab); \
+ *htab = NULL; \
+ } \
+ \
+ static inline int HTAB_OP_DEF (T, do) (HTAB (T) * htab, T el, enum htab_action action, \
+ T * res) { \
+ htab_ind_t ind, el_ind, *entry, *first_deleted_entry = NULL; \
+ htab_hash_t hash, peterb; \
+ htab_size_t els_size, size, mask, start, bound, i; \
+ htab_ind_t *addr; \
+ HTAB_EL (T) * els_addr; \
+ void *arg; \
+ \
+ HTAB_ASSERT (htab != NULL, "do htab", T); \
+ size = VARR_LENGTH (htab_ind_t, htab->entries); \
+ els_size = VARR_LENGTH (HTAB_EL (T), htab->els); \
+ arg = htab->arg; \
+ HTAB_ASSERT (els_size * 2 == size, "do size", T); \
+ if ((action == HTAB_INSERT || action == HTAB_REPLACE) && htab->els_bound == els_size) { \
+ size *= 2; \
+ VARR_TAILOR (htab_ind_t, htab->entries, size); \
+ addr = VARR_ADDR (htab_ind_t, htab->entries); \
+ for (i = 0; i < size; i++) addr[i] = HTAB_EMPTY_IND; \
+ VARR_TAILOR (HTAB_EL (T), htab->els, els_size * 2); \
+ els_addr = VARR_ADDR (HTAB_EL (T), htab->els); \
+ start = htab->els_start; \
+ bound = htab->els_bound; \
+ htab->els_start = htab->els_bound = htab->els_num = 0; \
+ for (i = start; i < bound; i++) \
+ if (els_addr[i].hash != HTAB_DELETED_HASH) { \
+ HTAB_OP (T, do) (htab, els_addr[i].el, HTAB_INSERT, res); \
+ HTAB_ASSERT ((*htab->eq_func) (*res, els_addr[i].el, arg), "do expand", T); \
+ } \
+ HTAB_ASSERT (bound - start >= htab->els_bound, "do bound", T); \
+ } \
+ mask = size - 1; \
+ hash = (*htab->hash_func) (el, arg); \
+ if (hash == HTAB_DELETED_HASH) hash += 1; \
+ peterb = hash; \
+ ind = hash & mask; \
+ addr = VARR_ADDR (htab_ind_t, htab->entries); \
+ els_addr = VARR_ADDR (HTAB_EL (T), htab->els); \
+ for (;; htab->collisions++) { \
+ entry = addr + ind; \
+ el_ind = *entry; \
+ if (el_ind != HTAB_EMPTY_IND) { \
+ if (el_ind == HTAB_DELETED_IND) { \
+ first_deleted_entry = entry; \
+ } else if (els_addr[el_ind].hash == hash \
+ && (*htab->eq_func) (els_addr[el_ind].el, el, arg)) { \
+ if (action == HTAB_REPLACE) { \
+ if (htab->free_func != NULL) htab->free_func (els_addr[el_ind].el, arg); \
+ els_addr[el_ind].el = el; \
+ } \
+ if (action != HTAB_DELETE) { \
+ *res = els_addr[el_ind].el; \
+ } else { \
+ htab->els_num--; \
+ *entry = HTAB_DELETED_IND; \
+ if (htab->free_func != NULL) htab->free_func (els_addr[el_ind].el, arg); \
+ els_addr[el_ind].hash = HTAB_DELETED_HASH; \
+ } \
+ return TRUE; \
+ } \
+ } else { \
+ if (action == HTAB_INSERT || action == HTAB_REPLACE) { \
+ htab->els_num++; \
+ if (first_deleted_entry != NULL) entry = first_deleted_entry; \
+ els_addr[htab->els_bound].hash = hash; \
+ els_addr[htab->els_bound].el = el; \
+ *entry = htab->els_bound++; \
+ *res = el; \
+ } \
+ return FALSE; \
+ } \
+ peterb >>= 11; \
+ ind = (5 * ind + peterb + 1) & mask; \
+ } \
+ } \
+ \
+ static inline htab_size_t HTAB_OP_DEF (T, els_num) (HTAB (T) * htab) { \
+ HTAB_ASSERT (htab != NULL, "els_num", T); \
+ return htab->els_num; \
+ } \
+ static inline htab_size_t HTAB_OP_DEF (T, collisions) (HTAB (T) * htab) { \
+ HTAB_ASSERT (htab != NULL, "collisions", T); \
+ return htab->collisions; \
}
-#define HTAB_CREATE(T, V, S, H, EQ) (HTAB_OP (T, create) (&(V), S, H, EQ, NULL))
-#define HTAB_CREATE_WITH_FREE_FUNC(T, V, S, H, EQ, F) (HTAB_OP (T, create) (&(V), S, H, EQ, F))
+#define HTAB_CREATE(T, V, S, H, EQ, A) (HTAB_OP (T, create) (&(V), S, H, EQ, NULL, A))
+#define HTAB_CREATE_WITH_FREE_FUNC(T, V, S, H, EQ, F, A) \
+ (HTAB_OP (T, create) (&(V), S, H, EQ, F, A))
#define HTAB_CLEAR(T, V) (HTAB_OP (T, clear) (V))
#define HTAB_DESTROY(T, V) (HTAB_OP (T, destroy) (&(V)))
/* It returns TRUE if the element existed in the table. */
diff --git a/mir/mir-interp.c b/mir/mir-interp.c
index 9063f5b..1fa6bc31 100644
--- a/mir/mir-interp.c
+++ b/mir/mir-interp.c
@@ -51,6 +51,7 @@ DEF_VARR (MIR_val_t);
struct ff_interface {
size_t nres, nargs;
+ int vararg_p;
MIR_type_t *res_types, *arg_types;
void *interface_addr;
};
@@ -731,7 +732,7 @@ static ALWAYS_INLINE int64_t get_mem_addr (MIR_val_t *bp, code_t c) { return bp[
*((mem_type *) a) = v; \
} while (0)
-#if defined(__GNUC__) && !defined(__clang__)
+#if !MIR_INTERP_TRACE && defined(__GNUC__) && !defined(__clang__)
#define OPTIMIZE \
__attribute__ ((__optimize__ ("O2"))) __attribute__ ((__optimize__ ("-fno-ipa-cp-clone")))
#else
@@ -806,7 +807,7 @@ static void finish_insn_trace (MIR_context_t ctx, MIR_full_insn_code_t code, cod
case MIR_OP_LDOUBLE:
fprintf (stderr, "\t# res = %.*Le", LDBL_DECIMAL_DIG, bp[ops[0].i].ld);
break;
- default: assert (FALSE);
+ default: assert (op_mode == MIR_OP_UNDEF);
}
fprintf (stderr, "\n");
}
@@ -1336,23 +1337,25 @@ static inline func_desc_t get_func_desc (MIR_item_t func_item) {
return func_item->data;
}
-static htab_hash_t ff_interface_hash (ff_interface_t i) {
- return mir_hash_finish (
- mir_hash_step (mir_hash_step (mir_hash_step (mir_hash_init (0), i->nres), i->nargs),
- mir_hash (i->res_types, sizeof (MIR_type_t) * i->nres,
- mir_hash (i->arg_types, sizeof (MIR_type_t) * i->nargs, 42))));
+static htab_hash_t ff_interface_hash (ff_interface_t i, void *arg) {
+ htab_hash_t h = mir_hash_step (mir_hash_init (0), i->nres);
+ h = mir_hash_step (h, i->nargs);
+ h = mir_hash_step (h, i->vararg_p);
+ h = mir_hash (i->res_types, sizeof (MIR_type_t) * i->nres, h);
+ h = mir_hash (i->arg_types, sizeof (MIR_type_t) * i->nargs, h);
+ return mir_hash_finish (h);
}
-static int ff_interface_eq (ff_interface_t i1, ff_interface_t i2) {
- return (i1->nres == i2->nres && i1->nargs == i2->nargs
+static int ff_interface_eq (ff_interface_t i1, ff_interface_t i2, void *arg) {
+ return (i1->nres == i2->nres && i1->nargs == i2->nargs && i1->vararg_p == i2->vararg_p
&& memcmp (i1->res_types, i2->res_types, sizeof (MIR_type_t) * i1->nres) == 0
&& memcmp (i1->arg_types, i2->arg_types, sizeof (MIR_type_t) * i1->nargs) == 0);
}
-static void ff_interface_clear (ff_interface_t ffi) { free (ffi); }
+static void ff_interface_clear (ff_interface_t ffi, void *arg) { free (ffi); }
static void *get_ff_interface (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, size_t nargs,
- MIR_type_t *arg_types) {
+ MIR_type_t *arg_types, int vararg_p) {
struct interp_ctx *interp_ctx = ctx->interp_ctx;
struct ff_interface ffi_s;
ff_interface_t tab_ffi, ffi;
@@ -1360,6 +1363,7 @@ static void *get_ff_interface (MIR_context_t ctx, size_t nres, MIR_type_t *res_t
ffi_s.nres = nres;
ffi_s.nargs = nargs;
+ ffi_s.vararg_p = !!vararg_p;
ffi_s.res_types = res_types;
ffi_s.arg_types = arg_types;
if (HTAB_DO (ff_interface_t, ff_interface_tab, &ffi_s, HTAB_FIND, tab_ffi))
@@ -1367,11 +1371,12 @@ static void *get_ff_interface (MIR_context_t ctx, size_t nres, MIR_type_t *res_t
ffi = malloc (sizeof (struct ff_interface) + sizeof (MIR_type_t) * (nres + nargs));
ffi->nres = nres;
ffi->nargs = nargs;
+ ffi->vararg_p = !!vararg_p;
ffi->res_types = (MIR_type_t *) ((char *) ffi + sizeof (struct ff_interface));
ffi->arg_types = ffi->res_types + nres;
memcpy (ffi->res_types, res_types, sizeof (MIR_type_t) * nres);
memcpy (ffi->arg_types, arg_types, sizeof (MIR_type_t) * nargs);
- ffi->interface_addr = _MIR_get_ff_call (ctx, nres, res_types, nargs, call_arg_types);
+ ffi->interface_addr = _MIR_get_ff_call (ctx, nres, res_types, nargs, call_arg_types, vararg_p);
htab_res = HTAB_DO (ff_interface_t, ff_interface_tab, ffi, HTAB_INSERT, tab_ffi);
mir_assert (!htab_res && ffi == tab_ffi);
return ffi->interface_addr;
@@ -1419,7 +1424,7 @@ static void call (MIR_context_t ctx, MIR_val_t *bp, MIR_op_t *insn_arg_ops, code
= (mode == MIR_OP_DOUBLE ? MIR_T_D : mode == MIR_OP_LDOUBLE ? MIR_T_LD : MIR_T_I64);
}
ff_interface_addr = ffi_address_ptr->a
- = get_ff_interface (ctx, nres, proto->res_types, nargs, call_arg_types);
+ = get_ff_interface (ctx, nres, proto->res_types, nargs, call_arg_types, proto->vararg_p);
}
for (i = 0; i < nargs; i++) {
@@ -1482,7 +1487,7 @@ static void interp_init (MIR_context_t ctx) {
call_res_args = VARR_ADDR (MIR_val_t, call_res_args_varr);
call_arg_types = VARR_ADDR (MIR_type_t, call_arg_types_varr);
HTAB_CREATE_WITH_FREE_FUNC (ff_interface_t, ff_interface_tab, 1000, ff_interface_hash,
- ff_interface_eq, ff_interface_clear);
+ ff_interface_eq, ff_interface_clear, NULL);
#if MIR_INTERP_TRACE
trace_insn_ident = 0;
#endif
@@ -1504,8 +1509,14 @@ static void interp_finish (MIR_context_t ctx) {
ctx->interp_ctx = NULL;
}
+#if VA_LIST_IS_ARRAY_P
+typedef va_list va_t;
+#else
+ typedef va_list *va_t;
+#endif
+
static void interp_arr_varg (MIR_context_t ctx, MIR_item_t func_item, MIR_val_t *results,
- size_t nargs, MIR_val_t *vals, va_list va) {
+ size_t nargs, MIR_val_t *vals, va_t va) {
func_desc_t func_desc;
MIR_val_t *bp;
@@ -1519,7 +1530,12 @@ static void interp_arr_varg (MIR_context_t ctx, MIR_item_t func_item, MIR_val_t
bp[0].i = 0;
memcpy (&bp[1], vals, sizeof (MIR_val_t) * nargs);
eval (ctx, func_desc, bp, results);
- if (va != NULL) va_end (va);
+ if (va != NULL)
+#if VA_LIST_IS_ARRAY_P
+ va_end (va);
+#else
+ va_end (*va);
+#endif
}
void MIR_interp (MIR_context_t ctx, MIR_item_t func_item, MIR_val_t *results, size_t nargs, ...) {
@@ -1531,7 +1547,11 @@ void MIR_interp (MIR_context_t ctx, MIR_item_t func_item, MIR_val_t *results, si
arg_vals = VARR_ADDR (MIR_val_t, arg_vals_varr);
va_start (argp, nargs);
for (i = 0; i < nargs; i++) arg_vals[i] = va_arg (argp, MIR_val_t);
+#if VA_LIST_IS_ARRAY_P
interp_arr_varg (ctx, func_item, results, nargs, arg_vals, argp);
+#else
+ interp_arr_varg (ctx, func_item, results, nargs, arg_vals, (va_t) &argp);
+#endif
}
void MIR_interp_arr_varg (MIR_context_t ctx, MIR_item_t func_item, MIR_val_t *results, size_t nargs,
@@ -1543,7 +1563,11 @@ void MIR_interp_arr_varg (MIR_context_t ctx, MIR_item_t func_item, MIR_val_t *re
if (func_item->data == NULL) generate_icode (ctx, func_item);
func_desc = get_func_desc (func_item);
bp = alloca ((func_desc->nregs + 1) * sizeof (MIR_val_t));
+#if VA_LIST_IS_ARRAY_P
bp[0].a = va;
+#else
+ bp[0].a = &va;
+#endif
bp++;
if (func_desc->nregs < nargs + 1) nargs = func_desc->nregs - 1;
bp[0].i = 0;
@@ -1586,7 +1610,11 @@ static void interp (MIR_context_t ctx, MIR_item_t func_item, va_list va, MIR_val
float f;
} u;
u.d = va_arg (va, double);
- arg_vals[i].f = u.f;
+#if defined(__PPC64__)
+ arg_vals[i].f = u.d;
+#else
+ arg_vals[i].f = u.f;
+#endif
break;
}
case MIR_T_D: arg_vals[i].d = va_arg (va, double); break;
@@ -1595,7 +1623,11 @@ static void interp (MIR_context_t ctx, MIR_item_t func_item, va_list va, MIR_val
default: mir_assert (FALSE);
}
}
+#if VA_LIST_IS_ARRAY_P
interp_arr_varg (ctx, func_item, results, nargs, arg_vals, va);
+#else
+ interp_arr_varg (ctx, func_item, results, nargs, arg_vals, (va_t) &va);
+#endif
}
static void redirect_interface_to_interp (MIR_context_t ctx, MIR_item_t func_item) {
diff --git a/mir/mir-ppc64.c b/mir/mir-ppc64.c
new file mode 100644
index 0000000..bcb00a5
--- /dev/null
+++ b/mir/mir-ppc64.c
@@ -0,0 +1,467 @@
+/* This file is a part of MIR project.
+ Copyright (C) 2018-2020 Vladimir Makarov .
+*/
+
+// _MIR_get_thunk, _MIR_redirect_thunk, _MIR_get_interp_shim, _MIR_get_ff_call, _MIR_get_wrapper
+#define VA_LIST_IS_ARRAY_P 1 /* one element which is a pointer to args */
+
+#define FUNC_DESC_LEN 24
+static void ppc64_push_func_desc (MIR_context_t ctx);
+void (*ppc64_func_desc) (MIR_context_t ctx) = ppc64_push_func_desc;
+
+static void ppc64_push_func_desc (MIR_context_t ctx) {
+ VARR_TRUNC (uint8_t, machine_insns, 0);
+ for (int i = 0; i < FUNC_DESC_LEN; i++)
+ VARR_PUSH (uint8_t, machine_insns, ((uint8_t *) ppc64_func_desc)[i]);
+}
+
+static void ppc64_redirect_func_desc (MIR_context_t ctx, void *desc, void *to) {
+ mir_assert (((uint64_t) desc & 0x3) == 0 && ((uint64_t) to & 0x3) == 0); /* alignment */
+ _MIR_change_code (ctx, desc, (uint8_t *) &to, sizeof (to));
+}
+
+static void *ppc64_publish_func_and_redirect (MIR_context_t ctx) {
+ void *res = _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
+ VARR_LENGTH (uint8_t, machine_insns));
+ ppc64_redirect_func_desc (ctx, res, (uint8_t *) res + FUNC_DESC_LEN);
+ return res;
+}
+
+static void push_insn (MIR_context_t ctx, uint32_t insn) {
+ uint8_t *p = (uint8_t *) &insn;
+ for (size_t i = 0; i < 4; i++) VARR_PUSH (uint8_t, machine_insns, p[i]);
+}
+
+static void push_insns (MIR_context_t ctx, const uint32_t *pat, size_t pat_len) {
+ uint8_t *p = (uint8_t *) pat;
+ for (size_t i = 0; i < pat_len; i++) VARR_PUSH (uint8_t, machine_insns, p[i]);
+}
+
+void *_MIR_get_bstart_builtin (MIR_context_t ctx) {
+ static const uint32_t bstart_code[] = {
+ 0x7c230b78, /* mr 3,1 */
+ 0x4e800020, /* blr */
+ };
+ ppc64_push_func_desc (ctx);
+ push_insns (ctx, bstart_code, sizeof (bstart_code));
+ return ppc64_publish_func_and_redirect (ctx);
+}
+
+void *_MIR_get_bend_builtin (MIR_context_t ctx) {
+ static const uint32_t bend_code[] = {
+ 0xe8010000, /* ld r0,0(r1) */
+ 0xf8030000, /* std r0,0(r3) */
+ 0xe8010028, /* ld r0,40(r1) */
+ 0xf8030028, /* std r0,40(r3) */
+ 0x7c611b78, /* mr r1,r3 */
+ 0x4e800020, /* blr */
+ };
+ ppc64_push_func_desc (ctx);
+ push_insns (ctx, bend_code, sizeof (bend_code));
+ return ppc64_publish_func_and_redirect (ctx);
+}
+
+void *_MIR_get_thunk (MIR_context_t ctx) { /* emit 3 doublewords for func descriptor: */
+ ppc64_push_func_desc (ctx);
+ return ppc64_publish_func_and_redirect (ctx);
+}
+
+void _MIR_redirect_thunk (MIR_context_t ctx, void *thunk, void *to) {
+ ppc64_redirect_func_desc (ctx, thunk, to);
+}
+
+struct ppc64_va_list {
+ uint64_t *arg_area;
+};
+
+void *va_arg_builtin (void *p, uint64_t t) {
+ struct ppc64_va_list *va = p;
+ MIR_type_t type = t;
+ int fp_p = type == MIR_T_F || type == MIR_T_D;
+ void *a = va->arg_area;
+
+ if (type == MIR_T_F || type == MIR_T_I32) {
+ a = (char *) a + 4; /* 2nd word of doubleword */
+ va->arg_area = (uint64_t *) ((char *) a + 4);
+ } else if (type == MIR_T_LD) {
+ va->arg_area += 2;
+ } else {
+ va->arg_area++;
+ }
+ return a;
+}
+
+void va_start_interp_builtin (MIR_context_t ctx, void *p, void *a) {
+ struct ppc64_va_list **va = p;
+ va_list *vap = a;
+
+ assert (sizeof (struct ppc64_va_list) == sizeof (va_list));
+ *va = (struct ppc64_va_list *) vap;
+}
+
+void va_end_interp_builtin (MIR_context_t ctx, void *p) {}
+
+static void ppc64_gen_mov (MIR_context_t ctx, unsigned to, unsigned from) {
+ /* or to,from,from: */
+ push_insn (ctx, (31 << 26) | (444 << 1) | (from << 21) | (to << 16) | (from << 11));
+}
+
+static void ppc64_gen_addi (MIR_context_t ctx, unsigned rt_reg, unsigned ra_reg, int disp) {
+ push_insn (ctx, (14 << 26) | (rt_reg << 21) | (ra_reg << 16) | (disp & 0xffff));
+}
+
+static void ppc64_gen_ld (MIR_context_t ctx, unsigned to, unsigned base, int disp,
+ MIR_type_t type) {
+ int single_p = type == MIR_T_F;
+ int double_p = type == MIR_T_D || type == MIR_T_LD;
+ /* (ld | lf[sd]) to, disp(base): */
+ assert (base != 0 && base < 32 && to < 32 && (single_p || double_p || (disp & 0x3) == 0));
+ push_insn (ctx, ((single_p ? 48 : double_p ? 50 : 58) << 26) | (to << 21) | (base << 16)
+ | (disp & 0xffff));
+}
+
+static void ppc64_gen_st (MIR_context_t ctx, unsigned from, unsigned base, int disp,
+ MIR_type_t type) {
+ int single_p = type == MIR_T_F;
+ int double_p = type == MIR_T_D || type == MIR_T_LD;
+ /* std|stf[sd] from, disp(base): */
+ assert (base != 0 && base < 32 && from < 32 && (single_p || double_p || (disp & 0x3) == 0));
+ push_insn (ctx, ((single_p ? 52 : double_p ? 54 : 62) << 26) | (from << 21) | (base << 16)
+ | (disp & 0xffff));
+}
+
+static void ppc64_gen_stdu (MIR_context_t ctx, int disp) {
+ assert ((disp & 0x3) == 0);
+ push_insn (ctx, 0xf8210001 | disp & 0xfffc); /* stdu 1, disp (1) */
+}
+
+static void ppc64_gen_address (MIR_context_t ctx, unsigned int reg, void *p) {
+ uint64_t a = (uint64_t) p;
+ if ((a >> 32) == 0) {
+ if (((a >> 31) & 1) == 0) { /* lis r,0,Z2 */
+ push_insn (ctx, (15 << 26) | (reg << 21) | (0 << 16) | (a >> 16) & 0xffff);
+ } else { /* xor r,r,r; oris r,r,Z2 */
+ push_insn (ctx, (31 << 26) | (316 << 1) | (reg << 21) | (reg << 16) | (reg << 11));
+ push_insn (ctx, (25 << 26) | (reg << 21) | (reg << 16) | (a >> 16) & 0xffff);
+ }
+ } else {
+ /* lis r,0,Z0; ori r,r,Z1; rldicr r,r,32,31; oris r,r,Z2; ori r,r,Z3: */
+ push_insn (ctx, (15 << 26) | (reg << 21) | (0 << 16) | (a >> 48));
+ push_insn (ctx, (24 << 26) | (reg << 21) | (reg << 16) | (a >> 32) & 0xffff);
+ push_insn (ctx, (30 << 26) | (reg << 21) | (reg << 16) | 0x07c6);
+ push_insn (ctx, (25 << 26) | (reg << 21) | (reg << 16) | (a >> 16) & 0xffff);
+ }
+ push_insn (ctx, (24 << 26) | (reg << 21) | (reg << 16) | a & 0xffff);
+}
+
+static void ppc64_gen_jump (MIR_context_t ctx, unsigned int reg, int call_p) {
+ ppc64_gen_ld (ctx, 0, reg, 0, MIR_T_I64); /* 0 = func addr */
+ ppc64_gen_ld (ctx, 2, reg, 8, MIR_T_I64); /* r2 = TOC */
+ push_insn (ctx, (31 << 26) | (467 << 1) | (0 << 21) | (9 << 16)); /* mctr 0 */
+ push_insn (ctx, (19 << 26) | (528 << 1) | (20 << 21) | (call_p ? 1 : 0)); /* bcctr[l] */
+}
+
+/* Generation: fun (fun_addr, res_arg_addresses):
+ save lr (r1 + 16); allocate and form minimal stack frame (with necessary param area); save r14;
+ r12=fun_addr (r3); r14 = res_arg_addresses (r4);
+ r0=mem[r14,]; (arg_reg=mem[r0] or r0=mem[r0];mem[r1,r1_offset]=r0) ...
+ if func is vararg: put fp args also in gp regs
+ call *r12;
+ r0=mem[r14,]; res_reg=mem[r0]; ...
+ restore r14, r1, lr; return. */
+void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, size_t nargs,
+ MIR_type_t *arg_types, int vararg_p) {
+ static uint32_t start_pattern[] = {
+ 0x7c0802a6, /* mflr r0 */
+ 0xf8010010, /* std r0,16(r1) */
+ };
+ static uint32_t finish_pattern[] = {
+ 0xe8010010, /* ld r0,16(r1) */
+ 0x7c0803a6, /* mtlr r0 */
+ 0x4e800020, /* blr */
+ };
+ MIR_type_t type;
+ int n_gpregs = 0, n_fpregs = 0, res_reg = 14, frame_size, disp, param_offset, param_size = 0;
+
+ ppc64_push_func_desc (ctx);
+ for (uint32_t i = 0; i < nargs; i++) param_size += arg_types[i] == MIR_T_LD ? 16 : 8;
+ if (param_size < 64) param_size = 64;
+ frame_size = 48 + param_size + 8; /* +local var to save res_reg */
+ if (frame_size % 8 != 0) frame_size += 8; /* align */
+ ppc64_gen_st (ctx, 2, 1, 40, MIR_T_I64);
+ push_insns (ctx, start_pattern, sizeof (start_pattern));
+ ppc64_gen_stdu (ctx, -frame_size);
+ ppc64_gen_st (ctx, res_reg, 1, 48 + param_size, MIR_T_I64); /* save res_reg */
+ mir_assert (sizeof (long double) == 16);
+ ppc64_gen_mov (ctx, res_reg, 4); /* results & args */
+ ppc64_gen_mov (ctx, 12, 3); /* func addr */
+ n_gpregs = n_fpregs = 0;
+ param_offset = nres * 16; /* args start */
+ disp = 48; /* param area start */
+ for (uint32_t i = 0; i < nargs; i++) { /* load args: */
+ type = arg_types[i];
+ if ((type == MIR_T_F || type == MIR_T_D || type == MIR_T_LD) && n_fpregs < 13) {
+ ppc64_gen_ld (ctx, 1 + n_fpregs, res_reg, param_offset, type);
+ if (vararg_p) {
+ if (n_gpregs >= 8) {
+ ppc64_gen_st (ctx, 1 + n_fpregs, 1, disp, MIR_T_D);
+ } else { /* load gp reg to */
+ ppc64_gen_st (ctx, 1 + n_fpregs, 1, -8, MIR_T_D);
+ ppc64_gen_ld (ctx, 3 + n_gpregs, 1, -8, MIR_T_I64);
+ }
+ }
+ n_fpregs++;
+ if (type == MIR_T_LD) {
+ if (n_fpregs < 13) {
+ ppc64_gen_ld (ctx, 1 + n_fpregs, res_reg, param_offset + 8, type);
+ if (vararg_p) {
+ if (n_gpregs + 1 >= 8) {
+ ppc64_gen_st (ctx, 1 + n_fpregs, 1, disp + 8, MIR_T_D);
+ } else { /* load gp reg to */
+ ppc64_gen_st (ctx, 1 + n_fpregs, 1, -8, MIR_T_D);
+ ppc64_gen_ld (ctx, 4 + n_gpregs, 1, -8, MIR_T_I64);
+ }
+ }
+ n_fpregs++;
+ } else {
+ ppc64_gen_ld (ctx, 0, res_reg, param_offset + 8, type);
+ ppc64_gen_st (ctx, 0, 1, disp + 8, MIR_T_D);
+ }
+ }
+ } else if (n_gpregs < 8) {
+ ppc64_gen_ld (ctx, n_gpregs + 3, res_reg, param_offset, MIR_T_I64);
+ } else if (type == MIR_T_F || type == MIR_T_D || type == MIR_T_LD) {
+ ppc64_gen_ld (ctx, 0, res_reg, param_offset, type);
+ ppc64_gen_st (ctx, 0, 1, disp, MIR_T_D);
+ if (type == MIR_T_LD) {
+ ppc64_gen_ld (ctx, 0, res_reg, param_offset + 8, type);
+ ppc64_gen_st (ctx, 0, 1, disp + 8, MIR_T_D);
+ }
+ } else {
+ ppc64_gen_ld (ctx, 0, res_reg, param_offset, MIR_T_I64);
+ ppc64_gen_st (ctx, 0, 1, disp, MIR_T_I64);
+ }
+ disp += type == MIR_T_LD ? 16 : 8;
+ param_offset += 16;
+ n_gpregs += type == MIR_T_LD ? 2 : 1;
+ }
+ ppc64_gen_jump (ctx, 12, TRUE); /* call func_addr */
+ n_gpregs = n_fpregs = 0;
+ disp = 0;
+ for (uint32_t i = 0; i < nres; i++) {
+ type = res_types[i];
+ if ((type == MIR_T_F || type == MIR_T_D || type == MIR_T_LD) && n_fpregs < 4) {
+ ppc64_gen_st (ctx, n_fpregs + 1, res_reg, disp, type);
+ n_fpregs++;
+ if (type == MIR_T_LD) {
+ if (n_fpregs >= 4)
+ (*error_func) (MIR_ret_error, "ppc64 can not handle this combination of return values");
+ ppc64_gen_st (ctx, n_fpregs + 1, res_reg, disp + 8, type);
+ n_fpregs++;
+ }
+ } else if (n_gpregs < 1) { // just one gp reg
+ ppc64_gen_st (ctx, n_gpregs + 3, res_reg, disp, MIR_T_I64);
+ n_gpregs++;
+ } else {
+ (*error_func) (MIR_ret_error, "ppc64 can not handle this combination of return values");
+ }
+ disp += 16;
+ }
+ ppc64_gen_ld (ctx, res_reg, 1, 48 + param_size, MIR_T_I64); /* restore res_reg */
+ ppc64_gen_addi (ctx, 1, 1, frame_size);
+ push_insns (ctx, finish_pattern, sizeof (finish_pattern));
+ return ppc64_publish_func_and_redirect (ctx);
+}
+
+/* Transform C call to call of void handler (MIR_context_t ctx, MIR_item_t func_item,
+ va_list va, MIR_val_t *results):
+ Brief: put all C call args to local vars (or if va_arg do nothing); save lr (r1+16), r14;
+ allocate and form minimal shim stack frame (param area = 8 * 8);
+ call handler with args; move results(r14) to return regs; restore lr,r14,r1; return */
+void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handler) {
+ MIR_func_t func = func_item->u.func;
+ uint32_t nres = func->nres, nargs = func->nargs;
+ int vararg_p = func->vararg_p;
+ MIR_type_t type, *res_types = func->res_types;
+ MIR_var_t *arg_vars = VARR_ADDR (MIR_var_t, func->vars);
+ int disp, size, frame_size, local_var_size, param_offset, va_reg = 11, caller_r1 = 12,
+ res_reg = 14;
+ int n_gpregs, n_fpregs;
+ static uint32_t start_pattern[] = {
+ 0x7c0802a6, /* mflr r0 */
+ 0xf8010010, /* std r0,16(r1) */
+ };
+ static uint32_t finish_pattern[] = {
+ 0xe8010010, /* ld r0,16(r1) */
+ 0x7c0803a6, /* mtlr r0 */
+ 0x4e800020, /* blr */
+ };
+ static uint32_t save_gp_regs_pattern[] = {
+ 0xf8610030, /* std r3,48(r1) */
+ 0xf8810038, /* std r4,56(r1) */
+ 0xf8a10040, /* std r5,64(r1) */
+ 0xf8c10048, /* std r6,72(r1) */
+ 0xf8e10050, /* std r7,80(r1) */
+ 0xf9010058, /* std r8,88(r1) */
+ 0xf9210060, /* std r9,96(r1) */
+ 0xf9410068, /* std r10,104(r1) */
+ };
+
+ VARR_TRUNC (uint8_t, machine_insns, 0);
+ frame_size = 112; /* 6(frame start) + 8(param area) */
+ local_var_size = nres * 16 + 8; /* saved r14, results */
+ if (vararg_p) {
+ push_insns (ctx, save_gp_regs_pattern, sizeof (save_gp_regs_pattern));
+ ppc64_gen_addi (ctx, va_reg, 1, 48);
+ } else {
+ ppc64_gen_mov (ctx, caller_r1, 1); /* caller frame r1 */
+ for (uint32_t i = 0; i < nargs; i++) {
+ type = arg_vars[i].type;
+ local_var_size += type == MIR_T_LD ? 16 : 8;
+ }
+ }
+ frame_size += local_var_size;
+ if (frame_size % 8 != 0) frame_size += 8; /* align */
+ push_insns (ctx, start_pattern, sizeof (start_pattern));
+ ppc64_gen_stdu (ctx, -frame_size);
+ ppc64_gen_st (ctx, res_reg, 1, 48 + 64, MIR_T_I64); /* save res_reg */
+ if (!vararg_p) { /* save args in local vars: */
+ disp = 112 + nres * 16 + 8; /* 48 + 64 + nres * 16 + 8: start of local vars to keep args */
+ ppc64_gen_addi (ctx, va_reg, 1, disp);
+ param_offset = 48;
+ n_gpregs = n_fpregs = 0;
+ for (uint32_t i = 0; i < nargs; i++) {
+ type = arg_vars[i].type;
+ if ((type == MIR_T_F || type == MIR_T_D || type == MIR_T_LD) && n_fpregs < 13) {
+ ppc64_gen_st (ctx, n_fpregs + 1, 1, disp, MIR_T_D);
+ n_fpregs++;
+ if (type == MIR_T_LD) {
+ if (n_fpregs < 13) {
+ ppc64_gen_st (ctx, n_fpregs + 1, 1, disp + 8, MIR_T_D);
+ n_fpregs++;
+ } else {
+ ppc64_gen_ld (ctx, 0, caller_r1, param_offset + 8, MIR_T_D);
+ ppc64_gen_st (ctx, 0, 1, disp + 8, MIR_T_D);
+ }
+ }
+ } else if (n_gpregs < 8) {
+ ppc64_gen_st (ctx, n_gpregs + 3, 1, disp, MIR_T_I64);
+ } else if (type == MIR_T_F || type == MIR_T_D || type == MIR_T_LD) {
+ ppc64_gen_ld (ctx, 0, caller_r1, param_offset + (type == MIR_T_F ? 4 : 0), type);
+ ppc64_gen_st (ctx, 0, 1, disp, MIR_T_D);
+ if (type == MIR_T_LD) {
+ ppc64_gen_ld (ctx, 0, caller_r1, param_offset + 8, MIR_T_D);
+ ppc64_gen_st (ctx, 0, 1, disp + 8, MIR_T_D);
+ }
+ } else {
+ ppc64_gen_ld (ctx, 0, caller_r1, param_offset, MIR_T_I64);
+ ppc64_gen_st (ctx, 0, 1, disp, MIR_T_I64);
+ }
+ size = type == MIR_T_LD ? 16 : 8;
+ disp += size;
+ param_offset += size;
+ n_gpregs += type == MIR_T_LD ? 2 : 1;
+ }
+ }
+ ppc64_gen_addi (ctx, res_reg, 1, 64 + 48 + 8);
+ ppc64_gen_address (ctx, 3, ctx);
+ ppc64_gen_address (ctx, 4, func_item);
+ ppc64_gen_mov (ctx, 5, va_reg);
+ ppc64_gen_mov (ctx, 6, res_reg);
+ ppc64_gen_address (ctx, 7, handler);
+ ppc64_gen_jump (ctx, 7, TRUE);
+ disp = n_gpregs = n_fpregs = 0;
+ for (uint32_t i = 0; i < nres; i++) {
+ type = res_types[i];
+ if ((type == MIR_T_F || type == MIR_T_D || type == MIR_T_LD) && n_fpregs < 4) {
+ ppc64_gen_ld (ctx, n_fpregs + 1, res_reg, disp, type);
+ n_fpregs++;
+ if (type == MIR_T_LD) {
+ if (n_fpregs >= 4)
+ (*error_func) (MIR_ret_error, "ppc64 can not handle this combination of return values");
+ ppc64_gen_ld (ctx, n_fpregs + 1, res_reg, disp + 8, type);
+ n_fpregs++;
+ }
+ } else if (n_gpregs < 1) { // just one gp reg
+ ppc64_gen_ld (ctx, n_gpregs + 3, res_reg, disp, MIR_T_I64);
+ n_gpregs++;
+ } else {
+ (*error_func) (MIR_ret_error, "ppc64 can not handle this combination of return values");
+ }
+ disp += 16;
+ }
+ ppc64_gen_ld (ctx, res_reg, 1, 48 + 64, MIR_T_I64); /* restore res_reg */
+ ppc64_gen_addi (ctx, 1, 1, frame_size);
+ push_insns (ctx, finish_pattern, sizeof (finish_pattern));
+ return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
+ VARR_LENGTH (uint8_t, machine_insns));
+}
+
+/* Brief: save lr (r1+16); update r1, save all param regs (r1+112);
+ allocate and form minimal wrapper stack frame (param area = 8*8);
+ r3 = call hook_address (ctx, called_func);
+ restore params regs (r1+112), r1, lr (r1+16); ctr=r11; b *ctr */
+void *_MIR_get_wrapper (MIR_context_t ctx, MIR_item_t called_func, void *hook_address) {
+ static uint32_t prologue[] = {
+ 0x7c0802a6, /* mflr r0 */
+ 0xf8010010, /* std r0,16(r1) */
+ 0xf821fee9, /* stdu r1,-280(r1): 6(frame start) + 8(gp args) + 13(fp args) + 8(param area) */
+ 0xf8610070, /* std r3,112(r1) */
+ 0xf8810078, /* std r4,120(r1) */
+ 0xf8a10080, /* std r5,128(r1) */
+ 0xf8c10088, /* std r6,136(r1) */
+ 0xf8e10090, /* std r7,144(r1) */
+ 0xf9010098, /* std r8,152(r1) */
+ 0xf92100a0, /* std r9,160(r1) */
+ 0xf94100a8, /* std r10,168(r1) */
+ 0xd82100b0, /* stfd f1,176(r1) */
+ 0xd84100b8, /* stfd f2,184(r1) */
+ 0xd86100c0, /* stfd f3,192(r1) */
+ 0xd88100c8, /* stfd f4,200(r1) */
+ 0xd8a100d0, /* stfd f5,208(r1) */
+ 0xd8c100d8, /* stfd f6,216(r1) */
+ 0xd8e100e0, /* stfd f7,224(r1) */
+ 0xd90100e8, /* stfd f8,232(r1) */
+ 0xd92100f0, /* stfd f9,240(r1) */
+ 0xd94100f8, /* stfd f10,248(r1) */
+ 0xd9610100, /* stfd f11,256(r1) */
+ 0xd9810108, /* stfd f12,264(r1) */
+ 0xd9a10110, /* stfd f13,272(r1) */
+ };
+ static uint32_t epilogue[] = {
+ 0xe8610070, /* ld r3,112(r1) */
+ 0xe8810078, /* ld r4,120(r1) */
+ 0xe8a10080, /* ld r5,128(r1) */
+ 0xe8c10088, /* ld r6,136(r1) */
+ 0xe8e10090, /* ld r7,144(r1) */
+ 0xe9010098, /* ld r8,152(r1) */
+ 0xe92100a0, /* ld r9,160(r1) */
+ 0xe94100a8, /* ld r10,168(r1) */
+ 0xc82100b0, /* lfd f1,176(r1) */
+ 0xc84100b8, /* lfd f2,184(r1) */
+ 0xc86100c0, /* lfd f3,192(r1) */
+ 0xc88100c8, /* lfd f4,200(r1) */
+ 0xc8a100d0, /* lfd f5,208(r1) */
+ 0xc8c100d8, /* lfd f6,216(r1) */
+ 0xc8e100e0, /* lfd f7,224(r1) */
+ 0xc90100e8, /* lfd f8,232(r1) */
+ 0xc92100f0, /* lfd f9,240(r1) */
+ 0xc94100f8, /* lfd f10,248(r1) */
+ 0xc9610100, /* lfd f11,256(r1) */
+ 0xc9810108, /* lfd f12,264(r1) */
+ 0xc9a10110, /* lfd f13,272(r1) */
+ 0x38210118, /* addi r1,r1,280 */
+ 0xe8010010, /* ld r0,16(r1) */
+ 0x7c0803a6, /* mtlr r0 */
+ };
+
+ VARR_TRUNC (uint8_t, machine_insns, 0);
+ push_insns (ctx, prologue, sizeof (prologue));
+ ppc64_gen_address (ctx, 3, ctx);
+ ppc64_gen_address (ctx, 4, called_func);
+ ppc64_gen_address (ctx, 5, hook_address);
+ ppc64_gen_jump (ctx, 5, TRUE);
+ ppc64_gen_mov (ctx, 11, 3);
+ push_insns (ctx, epilogue, sizeof (epilogue));
+ ppc64_gen_jump (ctx, 11, FALSE);
+}
diff --git a/mir/mir-x86_64.c b/mir/mir-x86_64.c
index 64c64ca..b22d5d2 100644
--- a/mir/mir-x86_64.c
+++ b/mir/mir-x86_64.c
@@ -2,6 +2,8 @@
Copyright (C) 2018-2020 Vladimir Makarov .
*/
+#define VA_LIST_IS_ARRAY_P 1
+
void *_MIR_get_bstart_builtin (MIR_context_t ctx) {
static const uint8_t bstart_code[] = {
0x48, 0x8d, 0x44, 0x24, 0x08, /* rax = rsp + 8 (lea) */
@@ -170,7 +172,7 @@ static void gen_st80 (MIR_context_t ctx, uint32_t src_offset) {
r10=mem[rbx,]; res_reg=mem[r10]; ...
pop rbx; ret. */
void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, size_t nargs,
- MIR_type_t *arg_types) {
+ MIR_type_t *arg_types, int vararg_p) {
static const uint8_t prolog[] = {
0x53, /* pushq %rbx */
0x48, 0x81, 0xec, 0, 0, 0, 0, /* subq , %rsp */
@@ -238,32 +240,33 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
VARR_LENGTH (uint8_t, machine_insns));
}
+/* Transform C call to call of void handler (MIR_context_t ctx, MIR_item_t func_item,
+ va_list va, MIR_val_t *results) */
void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handler) {
static const uint8_t push_rbx[] = {0x53, /*push %rbx */};
static const uint8_t prepare_pat[] = {
/* 0: */ 0x48, 0x83, 0xec, 0x20, /* sub 32,%rsp */
/* 4: */ 0x48, 0x89, 0xe2, /* mov %rsp,%rdx */
/* 7: */ 0xc7, 0x02, 0, 0, 0, 0, /* movl 0,(%rdx) */
- /* d: */ 0xc7, 0x42, 0x04, 0x30, 0, 0, 0, /* movl 48, 4(%rdx) */
+ /* d: */ 0xc7, 0x42, 0x04, 0x30, 0, 0, 0, /* movl 48, 4(%rdx) */
/* 14: */ 0x48, 0x8d, 0x44, 0x24, 0x20, /* lea 32(%rsp),%rax */
- /* 19: */ 0x48, 0x89, 0x42, 0x10, /* mov %rax,16(%rdx) */
- /* 1d: */ 0x48, 0x8d, 0x84, 0x24, 0xe0, 0, 0, 0, /* lea 224(%rsp),%rax */
+ /* 19: */ 0x48, 0x89, 0x42, 0x10, /* mov %rax,16(%rdx) */
+ /* 1d: */ 0x48, 0x8d, 0x84, 0x24, 0xe0, 0, 0, 0, /* lea 224(%rsp),%rax */
/* 25: */ 0x48, 0x89, 0x42, 0x08, /* mov %rax,8(%rdx) */
/* 29: */ 0x48, 0x81, 0xec, 0, 0, 0, 0, /* sub ,%rsp */
/* 30: */ 0x48, 0x89, 0xe3, /* mov %rsp,%rbx */
/* 33: */ 0x48, 0x89, 0xe1, /* mov %rsp,%rcx */
- /* 36: */ 0x48, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, /* movabs ,%rdi */
- /* 40: */ 0x48, 0xbe, 0, 0, 0, 0, 0, 0, 0, 0, /* movabs ,%rsi */
- /* 4a: */ 0x48, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, /* movabs ,%rax */
- /* 54: */ 0xff, 0xd0, /* callq *%rax */
+ /* 36: */ 0x48, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, /* movabs ,%rdi */
+ /* 40: */ 0x48, 0xbe, 0, 0, 0, 0, 0, 0, 0, 0, /* movabs ,%rsi*/
+ /* 4a: */ 0x48, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, /* movabs ,%rax */
+ /* 54: */ 0xff, 0xd0, /* callq *%rax */
};
static const uint8_t shim_end[] = {
/* 0: */ 0x48, 0x81, 0xc4, 0, 0, 0, 0, /*add 208+n,%rsp*/
/* 7: */ 0x5b, /*pop %rbx*/
/* 8: */ 0xc3, /*retq */
};
- static const uint8_t ld_pat[]
- = {0x48, 0x8b, 0x83, 0, 0, 0, 0}; /* movss (%rbx), %xmm[01] */
+ static const uint8_t ld_pat[] = {0x48, 0x8b, 0x83, 0, 0, 0, 0}; /* mov (%rbx), %reg */
static const uint8_t movss_pat[]
= {0xf3, 0x0f, 0x10, 0x83, 0, 0, 0, 0}; /* movss (%rbx), %xmm[01] */
static const uint8_t movsd_pat[]
@@ -348,7 +351,3 @@ void *_MIR_get_wrapper (MIR_context_t ctx, MIR_item_t called_func, void *hook_ad
return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
VARR_LENGTH (uint8_t, machine_insns));
}
-
-static void machine_init (MIR_context_t ctx) { VARR_CREATE (uint8_t, machine_insns, 1024); }
-
-static void machine_finish (MIR_context_t ctx) { VARR_DESTROY (uint8_t, machine_insns); }
diff --git a/mir/mir.c b/mir/mir.c
index 425300f..2123fa3 100644
--- a/mir/mir.c
+++ b/mir/mir.c
@@ -328,9 +328,11 @@ static void check_and_prepare_insn_descs (MIR_context_t ctx) {
}
static MIR_op_mode_t type2mode (MIR_type_t type) {
- return (type == MIR_T_F
- ? MIR_OP_FLOAT
- : type == MIR_T_D ? MIR_OP_DOUBLE : type == MIR_T_LD ? MIR_OP_LDOUBLE : MIR_OP_INT);
+ return (type == MIR_T_UNDEF
+ ? MIR_OP_UNDEF
+ : type == MIR_T_F
+ ? MIR_OP_FLOAT
+ : type == MIR_T_D ? MIR_OP_DOUBLE : type == MIR_T_LD ? MIR_OP_LDOUBLE : MIR_OP_INT);
}
/* New Page */
@@ -351,8 +353,10 @@ struct string_ctx {
#define strings ctx->string_ctx->strings
#define string_tab ctx->string_ctx->string_tab
-static htab_hash_t str_hash (string_t str) { return mir_hash (str.str.s, str.str.len, 0); }
-static int str_eq (string_t str1, string_t str2) {
+static htab_hash_t str_hash (string_t str, void *arg) {
+ return mir_hash (str.str.s, str.str.len, 0);
+}
+static int str_eq (string_t str1, string_t str2, void *arg) {
return str1.str.len == str2.str.len && memcmp (str1.str.s, str2.str.s, str1.str.len) == 0;
}
@@ -361,7 +365,7 @@ static void string_init (VARR (string_t) * *strs, HTAB (string_t) * *str_tab) {
VARR_CREATE (string_t, *strs, 0);
VARR_PUSH (string_t, *strs, string); /* don't use 0th string */
- HTAB_CREATE (string_t, *str_tab, 1000, str_hash, str_eq);
+ HTAB_CREATE (string_t, *str_tab, 1000, str_hash, str_eq, NULL);
}
static int string_find (VARR (string_t) * *strs, HTAB (string_t) * *str_tab, MIR_str_t str,
@@ -409,56 +413,47 @@ typedef struct reg_desc {
DEF_VARR (reg_desc_t);
-typedef struct size_ctx {
- size_t rdn;
- MIR_context_t ctx;
-} size_ctx_t;
-
-DEF_HTAB (size_ctx_t);
+DEF_HTAB (size_t);
struct reg_ctx {
VARR (reg_desc_t) * reg_descs;
- HTAB (size_ctx_t) * namenum2rdn_tab;
- HTAB (size_ctx_t) * reg2rdn_tab;
+ HTAB (size_t) * namenum2rdn_tab;
+ HTAB (size_t) * reg2rdn_tab;
};
#define reg_descs ctx->reg_ctx->reg_descs
#define namenum2rdn_tab ctx->reg_ctx->namenum2rdn_tab
#define reg2rdn_tab ctx->reg_ctx->reg2rdn_tab
-static int namenum2rdn_eq (size_ctx_t sc1, size_ctx_t sc2) {
- MIR_context_t ctx = sc1.ctx;
+static int namenum2rdn_eq (size_t rdn1, size_t rdn2, void *arg) {
+ MIR_context_t ctx = arg;
reg_desc_t *addr = VARR_ADDR (reg_desc_t, reg_descs);
- mir_assert (ctx == sc2.ctx);
- return (addr[sc1.rdn].name_num == addr[sc2.rdn].name_num
- && addr[sc1.rdn].func == addr[sc2.rdn].func);
+ return (addr[rdn1].name_num == addr[rdn2].name_num && addr[rdn1].func == addr[rdn2].func);
}
-static htab_hash_t namenum2rdn_hash (size_ctx_t sc) {
- MIR_context_t ctx = sc.ctx;
+static htab_hash_t namenum2rdn_hash (size_t rdn, void *arg) {
+ MIR_context_t ctx = arg;
reg_desc_t *addr = VARR_ADDR (reg_desc_t, reg_descs);
return mir_hash_finish (
- mir_hash_step (mir_hash_step (mir_hash_init (0), (uint64_t) addr[sc.rdn].func),
- (uint64_t) addr[sc.rdn].name_num));
+ mir_hash_step (mir_hash_step (mir_hash_init (0), (uint64_t) addr[rdn].func),
+ (uint64_t) addr[rdn].name_num));
}
-static int reg2rdn_eq (size_ctx_t sc1, size_ctx_t sc2) {
- MIR_context_t ctx = sc1.ctx;
+static int reg2rdn_eq (size_t rdn1, size_t rdn2, void *arg) {
+ MIR_context_t ctx = arg;
reg_desc_t *addr = VARR_ADDR (reg_desc_t, reg_descs);
- mir_assert (ctx == sc2.ctx);
- return addr[sc1.rdn].reg == addr[sc2.rdn].reg && addr[sc1.rdn].func == addr[sc2.rdn].func;
+ return addr[rdn1].reg == addr[rdn2].reg && addr[rdn1].func == addr[rdn2].func;
}
-static htab_hash_t reg2rdn_hash (size_ctx_t sc) {
- MIR_context_t ctx = sc.ctx;
+static htab_hash_t reg2rdn_hash (size_t rdn, void *arg) {
+ MIR_context_t ctx = arg;
reg_desc_t *addr = VARR_ADDR (reg_desc_t, reg_descs);
return mir_hash_finish (
- mir_hash_step (mir_hash_step (mir_hash_init (0), (uint64_t) addr[sc.rdn].func),
- addr[sc.rdn].reg));
+ mir_hash_step (mir_hash_step (mir_hash_init (0), (uint64_t) addr[rdn].func), addr[rdn].reg));
}
static void reg_init (MIR_context_t ctx) {
@@ -468,14 +463,14 @@ static void reg_init (MIR_context_t ctx) {
(*error_func) (MIR_alloc_error, "Not enough memory for ctx");
VARR_CREATE (reg_desc_t, reg_descs, 300);
VARR_PUSH (reg_desc_t, reg_descs, rd); /* for 0 reg */
- HTAB_CREATE (size_ctx_t, namenum2rdn_tab, 300, namenum2rdn_hash, namenum2rdn_eq);
- HTAB_CREATE (size_ctx_t, reg2rdn_tab, 300, reg2rdn_hash, reg2rdn_eq);
+ HTAB_CREATE (size_t, namenum2rdn_tab, 300, namenum2rdn_hash, namenum2rdn_eq, ctx);
+ HTAB_CREATE (size_t, reg2rdn_tab, 300, reg2rdn_hash, reg2rdn_eq, ctx);
}
static MIR_reg_t create_func_reg (MIR_context_t ctx, MIR_func_t func, const char *name,
MIR_reg_t reg, MIR_type_t type, int any_p) {
reg_desc_t rd;
- size_ctx_t sc, tab_sc;
+ size_t rdn, tab_rdn;
int htab_res;
if (!any_p && _MIR_reserved_name_p (ctx, name))
@@ -484,24 +479,23 @@ static MIR_reg_t create_func_reg (MIR_context_t ctx, MIR_func_t func, const char
rd.func = func;
rd.type = type;
rd.reg = reg; /* 0 is reserved */
- sc.rdn = VARR_LENGTH (reg_desc_t, reg_descs);
- sc.ctx = ctx;
+ rdn = VARR_LENGTH (reg_desc_t, reg_descs);
VARR_PUSH (reg_desc_t, reg_descs, rd);
- if (HTAB_DO (size_ctx_t, namenum2rdn_tab, sc, HTAB_FIND, tab_sc)) {
+ if (HTAB_DO (size_t, namenum2rdn_tab, rdn, HTAB_FIND, tab_rdn)) {
VARR_POP (reg_desc_t, reg_descs);
(*error_func) (MIR_repeated_decl_error, "Repeated reg declaration %s", name);
}
- htab_res = HTAB_DO (size_ctx_t, namenum2rdn_tab, sc, HTAB_INSERT, tab_sc);
+ htab_res = HTAB_DO (size_t, namenum2rdn_tab, rdn, HTAB_INSERT, tab_rdn);
mir_assert (!htab_res);
- htab_res = HTAB_DO (size_ctx_t, reg2rdn_tab, sc, HTAB_INSERT, tab_sc);
+ htab_res = HTAB_DO (size_t, reg2rdn_tab, rdn, HTAB_INSERT, tab_rdn);
mir_assert (!htab_res);
return reg;
}
static void reg_finish (MIR_context_t ctx) {
VARR_DESTROY (reg_desc_t, reg_descs);
- HTAB_DESTROY (size_ctx_t, namenum2rdn_tab);
- HTAB_DESTROY (size_ctx_t, reg2rdn_tab);
+ HTAB_DESTROY (size_t, namenum2rdn_tab);
+ HTAB_DESTROY (size_t, reg2rdn_tab);
free (ctx->reg_ctx);
ctx->reg_ctx = NULL;
}
@@ -519,11 +513,11 @@ const char *MIR_item_name (MIR_context_t ctx, MIR_item_t item) {
: item->item_type == MIR_proto_item
? item->u.proto->name
: item->item_type == MIR_import_item
- ? item->u.import
+ ? item->u.import_id
: item->item_type == MIR_export_item
- ? item->u.export
+ ? item->u.export_id
: item->item_type == MIR_forward_item
- ? item->u.forward
+ ? item->u.forward_id
: item->item_type == MIR_bss_item
? item->u.bss->name
: item->item_type == MIR_data_item
@@ -550,12 +544,12 @@ MIR_error_func_t MIR_get_error_func (MIR_context_t ctx) { return error_func; }
void MIR_set_error_func (MIR_context_t ctx, MIR_error_func_t func) { error_func = func; }
-static htab_hash_t item_hash (MIR_item_t it) {
+static htab_hash_t item_hash (MIR_item_t it, void *arg) {
return mir_hash_finish (
mir_hash_step (mir_hash_step (mir_hash_init (28), (uint64_t) MIR_item_name (NULL, it)),
(uint64_t) it->module));
}
-static int item_eq (MIR_item_t it1, MIR_item_t it2) {
+static int item_eq (MIR_item_t it1, MIR_item_t it2, void *arg) {
return it1->module == it2->module && MIR_item_name (NULL, it1) == MIR_item_name (NULL, it2);
}
@@ -624,7 +618,7 @@ MIR_context_t MIR_init (void) {
#endif
VARR_CREATE (MIR_module_t, modules_to_link, 0);
init_module (ctx, &environment_module, ".environment");
- HTAB_CREATE (MIR_item_t, module_item_tab, 512, item_hash, item_eq);
+ HTAB_CREATE (MIR_item_t, module_item_tab, 512, item_hash, item_eq, NULL);
code_init (ctx);
interp_init (ctx);
inlined_calls = inline_insns_before = inline_insns_after = 0;
@@ -775,6 +769,7 @@ static const char *type_str (MIR_type_t tp) {
case MIR_T_D: return "d";
case MIR_T_LD: return "ld";
case MIR_T_P: return "p";
+ case MIR_T_UNDEF: return "undef";
default: return "";
}
}
@@ -802,6 +797,7 @@ static const char *mode_str (MIR_op_mode_t mode) {
case MIR_OP_HARD_REG_MEM: return "hard_reg_mem";
case MIR_OP_LABEL: return "label";
case MIR_OP_BOUND: return "bound";
+ case MIR_OP_UNDEF: return "undef";
default: return "";
}
}
@@ -819,14 +815,15 @@ static MIR_item_t add_item (MIR_context_t ctx, MIR_item_t item) {
case MIR_import_item:
if (item->item_type != MIR_import_item)
(*error_func) (MIR_import_export_error,
- "existing module definition %s already defined as import", tab_item->u.import);
+ "existing module definition %s already defined as import",
+ tab_item->u.import_id);
item = tab_item;
break;
case MIR_export_item:
case MIR_forward_item:
replace_p = FALSE;
if (item->item_type == MIR_import_item) {
- (*error_func) (MIR_import_export_error, "export/forward of import %s", item->u.import);
+ (*error_func) (MIR_import_export_error, "export/forward of import %s", item->u.import_id);
} else if (item->item_type != MIR_export_item && item->item_type != MIR_forward_item) {
replace_p = TRUE;
DLIST_APPEND (MIR_item_t, curr_module->items, item);
@@ -867,7 +864,7 @@ static MIR_item_t add_item (MIR_context_t ctx, MIR_item_t item) {
DLIST_APPEND (MIR_item_t, curr_module->items, item);
item->ref_def = tab_item;
} else if (item->item_type == MIR_import_item) {
- (*error_func) (MIR_import_export_error, "import of local definition %s", item->u.import);
+ (*error_func) (MIR_import_export_error, "import of local definition %s", item->u.import_id);
} else {
(*error_func) (MIR_repeated_decl_error, "Repeated item declaration %s",
MIR_item_name (ctx, item));
@@ -904,11 +901,11 @@ static MIR_item_t new_export_import_forward (MIR_context_t ctx, const char *name
item = create_item (ctx, item_type, item_name);
uniq_name = string_store (ctx, &strings, &string_tab, (MIR_str_t){strlen (name) + 1, name}).str.s;
if (item_type == MIR_export_item)
- item->u.export = uniq_name;
+ item->u.export_id = uniq_name;
else if (item_type == MIR_import_item)
- item->u.import = uniq_name;
+ item->u.import_id = uniq_name;
else
- item->u.forward = uniq_name;
+ item->u.forward_id = uniq_name;
if (create_only_p) return item;
if ((tab_item = add_item (ctx, item)) != item) {
free (item);
@@ -1235,41 +1232,39 @@ MIR_reg_t MIR_new_func_reg (MIR_context_t ctx, MIR_func_t func, MIR_type_t type,
}
static reg_desc_t *find_rd_by_name_num (MIR_context_t ctx, size_t name_num, MIR_func_t func) {
- size_ctx_t sc, temp_sc;
+ size_t rdn, temp_rdn;
reg_desc_t rd;
rd.name_num = name_num;
rd.func = func; /* keys */
rd.type = MIR_T_I64;
rd.reg = 0; /* to eliminate warnings */
- temp_sc.rdn = VARR_LENGTH (reg_desc_t, reg_descs);
- temp_sc.ctx = ctx;
+ temp_rdn = VARR_LENGTH (reg_desc_t, reg_descs);
VARR_PUSH (reg_desc_t, reg_descs, rd);
- if (!HTAB_DO (size_ctx_t, namenum2rdn_tab, temp_sc, HTAB_FIND, sc)) {
+ if (!HTAB_DO (size_t, namenum2rdn_tab, temp_rdn, HTAB_FIND, rdn)) {
VARR_POP (reg_desc_t, reg_descs);
return NULL; /* undeclared */
}
VARR_POP (reg_desc_t, reg_descs);
- return &VARR_ADDR (reg_desc_t, reg_descs)[sc.rdn];
+ return &VARR_ADDR (reg_desc_t, reg_descs)[rdn];
}
static reg_desc_t *find_rd_by_reg (MIR_context_t ctx, MIR_reg_t reg, MIR_func_t func) {
- size_ctx_t sc, temp_sc;
+ size_t rdn, temp_rdn;
reg_desc_t rd;
rd.reg = reg;
rd.func = func; /* keys */
rd.name_num = 0;
rd.type = MIR_T_I64; /* to eliminate warnings */
- temp_sc.rdn = VARR_LENGTH (reg_desc_t, reg_descs);
- temp_sc.ctx = ctx;
+ temp_rdn = VARR_LENGTH (reg_desc_t, reg_descs);
VARR_PUSH (reg_desc_t, reg_descs, rd);
- if (!HTAB_DO (size_ctx_t, reg2rdn_tab, temp_sc, HTAB_FIND, sc)) {
+ if (!HTAB_DO (size_t, reg2rdn_tab, temp_rdn, HTAB_FIND, rdn)) {
VARR_POP (reg_desc_t, reg_descs);
(*error_func) (MIR_undeclared_func_reg_error, "undeclared reg %u of func %s", reg, func->name);
}
VARR_POP (reg_desc_t, reg_descs);
- return &VARR_ADDR (reg_desc_t, reg_descs)[sc.rdn];
+ return &VARR_ADDR (reg_desc_t, reg_descs)[rdn];
}
void MIR_finish_func (MIR_context_t ctx) {
@@ -1369,8 +1364,12 @@ void MIR_finish_func (MIR_context_t ctx) {
break;
}
insn->ops[i].value_mode = mode;
- if (expected_mode != MIR_OP_UNDEF
- && (mode == MIR_OP_UINT ? MIR_OP_INT : mode) != expected_mode) {
+ if (mode == MIR_OP_UNDEF && insn->ops[i].mode == MIR_OP_MEM
+ && ((code == MIR_VA_START && i == 0) || (code == MIR_VA_ARG && i == 1)
+ || (code == MIR_VA_END && i == 1))) { /* a special case: va_list as undef type mem */
+ insn->ops[i].value_mode = expected_mode;
+ } else if (expected_mode != MIR_OP_UNDEF
+ && (mode == MIR_OP_UINT ? MIR_OP_INT : mode) != expected_mode) {
curr_func = NULL;
(*error_func) (MIR_op_mode_error,
"in instruction '%s': unexpected operand mode for operand #%d. Got '%s', "
@@ -1543,28 +1542,28 @@ void MIR_link (MIR_context_t ctx, void (*set_interface) (MIR_context_t ctx, MIR_
item = DLIST_NEXT (MIR_item_t, item))
if (item->item_type == MIR_func_item) {
assert (item->data == NULL);
- if (simplify_func (ctx, item, TRUE)) item->data = (void *) 1;
+ if (simplify_func (ctx, item, TRUE)) item->data = (void *) 1; /* flag inlining */
} else if (item->item_type == MIR_import_item) {
- if ((tab_item = find_item (ctx, item->u.import, &environment_module)) == NULL) {
- if (import_resolver == NULL || (addr = import_resolver (item->u.import)) == NULL)
+ if ((tab_item = find_item (ctx, item->u.import_id, &environment_module)) == NULL) {
+ if (import_resolver == NULL || (addr = import_resolver (item->u.import_id)) == NULL)
(*error_func) (MIR_undeclared_op_ref_error, "import of undefined item %s",
- item->u.import);
- MIR_load_external (ctx, item->u.import, addr);
- tab_item = find_item (ctx, item->u.import, &environment_module);
+ item->u.import_id);
+ MIR_load_external (ctx, item->u.import_id, addr);
+ tab_item = find_item (ctx, item->u.import_id, &environment_module);
mir_assert (tab_item != NULL);
}
item->addr = tab_item->addr;
item->ref_def = tab_item;
} else if (item->item_type == MIR_export_item) {
- if ((tab_item = find_item (ctx, item->u.export, m)) == NULL)
+ if ((tab_item = find_item (ctx, item->u.export_id, m)) == NULL)
(*error_func) (MIR_undeclared_op_ref_error, "export of undefined item %s",
- item->u.export);
+ item->u.export_id);
item->addr = tab_item->addr;
item->ref_def = tab_item;
} else if (item->item_type == MIR_forward_item) {
- if ((tab_item = find_item (ctx, item->u.forward, m)) == NULL)
+ if ((tab_item = find_item (ctx, item->u.forward_id, m)) == NULL)
(*error_func) (MIR_undeclared_op_ref_error, "forward of undefined item %s",
- item->u.forward);
+ item->u.forward_id);
item->addr = tab_item->addr;
item->ref_def = tab_item;
}
@@ -1576,6 +1575,10 @@ void MIR_link (MIR_context_t ctx, void (*set_interface) (MIR_context_t ctx, MIR_
if (item->item_type == MIR_func_item && item->data != NULL) {
process_inlines (ctx, item);
item->data = NULL;
+#if 0
+ fprintf (stderr, "+++++ Function after inlining:\n");
+ MIR_output_item (ctx, stderr, func_item);
+#endif
} else if (item->item_type == MIR_ref_data_item) {
assert (item->u.ref_data->ref_item->addr != NULL);
addr = (char *) item->u.ref_data->ref_item->addr + item->u.ref_data->disp;
@@ -2174,7 +2177,7 @@ void MIR_output_op (MIR_context_t ctx, FILE *f, MIR_op_t op, MIR_func_t func) {
case MIR_OP_UINT: fprintf (f, "%" PRIu64, op.u.u); break;
case MIR_OP_FLOAT: fprintf (f, "%.*ef", FLT_MANT_DIG, op.u.f); break;
case MIR_OP_DOUBLE: fprintf (f, "%.*e", DBL_MANT_DIG, op.u.d); break;
- case MIR_OP_LDOUBLE: fprintf (f, "%.*Le", LDBL_MANT_DIG, op.u.ld); break;
+ case MIR_OP_LDOUBLE: fprintf (f, "%.*LeL", LDBL_MANT_DIG, op.u.ld); break;
case MIR_OP_MEM:
case MIR_OP_HARD_REG_MEM: {
MIR_reg_t no_reg = op.mode == MIR_OP_MEM ? 0 : MIR_NON_HARD_REG;
@@ -2267,15 +2270,15 @@ void MIR_output_item (MIR_context_t ctx, FILE *f, MIR_item_t item) {
mir_assert (f != NULL && item != NULL);
if (item->item_type == MIR_export_item) {
- fprintf (f, "\texport\t%s\n", item->u.export);
+ fprintf (f, "\texport\t%s\n", item->u.export_id);
return;
}
if (item->item_type == MIR_import_item) {
- fprintf (f, "\timport\t%s\n", item->u.import);
+ fprintf (f, "\timport\t%s\n", item->u.import_id);
return;
}
if (item->item_type == MIR_forward_item) {
- fprintf (f, "\tforward\t%s\n", item->u.forward);
+ fprintf (f, "\tforward\t%s\n", item->u.forward_id);
return;
}
if (item->item_type == MIR_bss_item) {
@@ -2312,7 +2315,7 @@ void MIR_output_item (MIR_context_t ctx, FILE *f, MIR_item_t item) {
case MIR_T_F: fprintf (f, "%.*ef", FLT_MANT_DIG, ((float *) data->u.els)[i]); break;
case MIR_T_D: fprintf (f, "%.*e", DBL_MANT_DIG, ((double *) data->u.els)[i]); break;
case MIR_T_LD:
- fprintf (f, "%.*Le", LDBL_MANT_DIG, ((long double *) data->u.els)[i]);
+ fprintf (f, "%.*LeL", LDBL_MANT_DIG, ((long double *) data->u.els)[i]);
break;
/* only ptr as ref ??? */
case MIR_T_P: fprintf (f, "0x%" PRIxPTR, ((uintptr_t *) data->u.els)[i]); break;
@@ -2385,7 +2388,6 @@ typedef struct {
MIR_type_t type;
MIR_op_t op1, op2;
MIR_reg_t reg;
- MIR_context_t ctx;
} val_t;
DEF_HTAB (val_t);
@@ -2396,27 +2398,28 @@ struct simplify_ctx {
#define val_tab ctx->simplify_ctx->val_tab
-static htab_hash_t val_hash (val_t v) {
+static htab_hash_t val_hash (val_t v, void *arg) {
+ MIR_context_t ctx = arg;
htab_hash_t h;
h = mir_hash_step (mir_hash_init (0), (uint64_t) v.code);
h = mir_hash_step (h, (uint64_t) v.type);
- h = MIR_op_hash_step (v.ctx, h, v.op1);
- if (v.code != MIR_INSN_BOUND) h = MIR_op_hash_step (v.ctx, h, v.op2);
+ h = MIR_op_hash_step (ctx, h, v.op1);
+ if (v.code != MIR_INSN_BOUND) h = MIR_op_hash_step (ctx, h, v.op2);
return mir_hash_finish (h);
}
-static int val_eq (val_t v1, val_t v2) {
- assert (v1.ctx == v2.ctx);
- if (v1.code != v2.code || v1.type != v2.type || !MIR_op_eq_p (v1.ctx, v1.op1, v2.op1))
- return FALSE;
- return v1.code == MIR_INSN_BOUND || MIR_op_eq_p (v1.ctx, v1.op2, v2.op2);
+static int val_eq (val_t v1, val_t v2, void *arg) {
+ MIR_context_t ctx = arg;
+
+ if (v1.code != v2.code || v1.type != v2.type || !MIR_op_eq_p (ctx, v1.op1, v2.op1)) return FALSE;
+ return v1.code == MIR_INSN_BOUND || MIR_op_eq_p (ctx, v1.op2, v2.op2);
}
static void vn_init (MIR_context_t ctx) {
if ((ctx->simplify_ctx = malloc (sizeof (struct simplify_ctx))) == NULL)
(*error_func) (MIR_alloc_error, "Not enough memory for ctx");
- HTAB_CREATE (val_t, val_tab, 512, val_hash, val_eq);
+ HTAB_CREATE (val_t, val_tab, 512, val_hash, val_eq, ctx);
}
static void vn_finish (MIR_context_t ctx) {
@@ -2435,7 +2438,6 @@ static MIR_reg_t vn_add_val (MIR_context_t ctx, MIR_func_t func, MIR_type_t type
val.code = code;
val.op1 = op1;
val.op2 = op2;
- val.ctx = ctx;
if (HTAB_DO (val_t, val_tab, val, HTAB_FIND, tab_val)) return tab_val.reg;
val.reg = _MIR_new_temp_reg (ctx, type, func);
HTAB_DO (val_t, val_tab, val, HTAB_INSERT, tab_val);
@@ -2604,6 +2606,10 @@ void MIR_simplify_op (MIR_context_t ctx, MIR_item_t func_item, MIR_insn_t insn,
mem_op.u.mem.scale = 0;
if (move_p && (nop == 1 || insn->ops[1].mode == MIR_OP_REG)) {
*op = mem_op;
+ } else if (((code == MIR_VA_START && nop == 0) || (code == MIR_VA_ARG && nop == 1)
+ || (code == MIR_VA_END && nop == 0))
+ && mem_op.u.mem.type == MIR_T_UNDEF) {
+ *op = MIR_new_reg_op (ctx, addr_reg);
} else {
type = (mem_op.u.mem.type == MIR_T_F || mem_op.u.mem.type == MIR_T_D
|| mem_op.u.mem.type == MIR_T_LD
@@ -2730,7 +2736,7 @@ static void remove_unused_labels (MIR_context_t ctx, MIR_item_t func_item) {
}
}
-static MIR_insn_code_t reverse_branch_code (MIR_insn_code_t code) {
+MIR_insn_code_t MIR_reverse_branch_code (MIR_insn_code_t code) {
switch (code) {
case MIR_BT: return MIR_BF;
case MIR_BTS: return MIR_BFS;
@@ -2756,7 +2762,7 @@ static MIR_insn_code_t reverse_branch_code (MIR_insn_code_t code) {
case MIR_BGES: return MIR_BLTS;
case MIR_UBGE: return MIR_UBLT;
case MIR_UBGES: return MIR_UBLTS;
- default: assert (FALSE); return code;
+ default: return MIR_INSN_BOUND;
}
}
@@ -2772,7 +2778,7 @@ static const int MAX_JUMP_CHAIN_LEN = 32;
static int simplify_func (MIR_context_t ctx, MIR_item_t func_item, int mem_float_p) {
MIR_func_t func = func_item->u.func;
MIR_insn_t insn, next_insn, next_next_insn, jmp_insn, new_insn;
- MIR_insn_code_t ext_code;
+ MIR_insn_code_t ext_code, rev_code;
int jmps_num = 0, inline_p = FALSE;
if (func_item->item_type != MIR_func_item)
@@ -2890,13 +2896,14 @@ static int simplify_func (MIR_context_t ctx, MIR_item_t func_item, int mem_float
}
MIR_remove_insn (ctx, func_item, insn);
// ??? make imm always second, what is about mem?
- } else if (MIR_int_branch_code_p (code) && next_insn != NULL && next_insn->code == MIR_JMP
+ } else if ((rev_code = MIR_reverse_branch_code (insn->code)) != MIR_INSN_BOUND
+ && next_insn != NULL && next_insn->code == MIR_JMP
&& (next_next_insn = DLIST_NEXT (MIR_insn_t, next_insn)) != NULL
&& next_next_insn->code == MIR_LABEL && insn->ops[0].mode == MIR_OP_LABEL
&& skip_labels (next_next_insn, insn->ops[0].u.label) == insn->ops[0].u.label) {
/* BCond L;JMP L2;L: => BNCond L2;L: */
insn->ops[0] = next_insn->ops[0];
- insn->code = reverse_branch_code (insn->code);
+ insn->code = rev_code;
MIR_remove_insn (ctx, func_item, next_insn);
next_insn = insn;
} else if (MIR_branch_code_p (code) && insn->ops[0].mode == MIR_OP_LABEL
@@ -2928,6 +2935,10 @@ static int simplify_func (MIR_context_t ctx, MIR_item_t func_item, int mem_float
}
make_one_ret (ctx, func_item);
remove_unused_labels (ctx, func_item);
+#if 0
+ fprintf (stderr, "+++++ Function after simplification:\n");
+ MIR_output_item (ctx, stderr, func_item);
+#endif
return inline_p;
}
@@ -3210,42 +3221,73 @@ struct machine_code_ctx {
#define page_size ctx->machine_code_ctx->page_size
#define machine_insns ctx->machine_code_ctx->machine_insns
-uint8_t *_MIR_publish_code (MIR_context_t ctx, const uint8_t *code, size_t code_len) {
- uint8_t *start, *mem;
- size_t len;
- code_holder_t ch;
+static code_holder_t *get_last_code_holder (MIR_context_t ctx, size_t size) {
+ uint8_t *mem, *free_adddr;
+ size_t len, npages;
+ code_holder_t ch, *ch_ptr;
int new_p = TRUE;
if ((len = VARR_LENGTH (code_holder_t, code_holders)) > 0) {
- code_holder_t *ch_ptr = VARR_ADDR (code_holder_t, code_holders) + len - 1;
- uint8_t *free_addr = (uint8_t *) ((uint64_t) (ch_ptr->free + 15) / 16 * 16); /* align */
-
- if (free_addr + code_len < ch_ptr->bound) {
- mem = free_addr;
- ch_ptr->free = free_addr + code_len;
- new_p = FALSE;
- start = ch_ptr->start;
- len = ch_ptr->bound - start;
- ch = *ch_ptr;
- }
+ ch_ptr = VARR_ADDR (code_holder_t, code_holders) + len - 1;
+ ch_ptr->free = (uint8_t *) ((uint64_t) (ch_ptr->free + 15) / 16 * 16); /* align */
+ if (ch_ptr->free + size <= ch_ptr->bound) return ch_ptr;
}
- if (new_p) {
- size_t npages = (code_len + page_size - 1) / page_size;
-
- len = page_size * npages;
- mem = (uint8_t *) mmap (NULL, len, PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if (mem == MAP_FAILED) return NULL;
- start = ch.start = mem;
- ch.free = mem + code_len;
- ch.bound = mem + len;
- VARR_PUSH (code_holder_t, code_holders, ch);
- }
- mprotect (ch.start, ch.bound - ch.start, PROT_WRITE | PROT_EXEC);
+ npages = (size + page_size) / page_size;
+ len = page_size * npages;
+ mem = (uint8_t *) mmap (NULL, len, PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (mem == MAP_FAILED) return NULL;
+ ch.start = mem;
+ ch.free = mem;
+ ch.bound = mem + len;
+ VARR_PUSH (code_holder_t, code_holders, ch);
+ len = VARR_LENGTH (code_holder_t, code_holders);
+ return VARR_ADDR (code_holder_t, code_holders) + len - 1;
+}
+
+static uint8_t *add_code (MIR_context_t ctx, code_holder_t *ch_ptr, const uint8_t *code,
+ size_t code_len) {
+ uint8_t *mem = ch_ptr->free;
+
+ ch_ptr->free += code_len;
+ mir_assert (ch_ptr->free <= ch_ptr->bound);
+ mprotect (ch_ptr->start, ch_ptr->bound - ch_ptr->start, PROT_WRITE | PROT_EXEC);
memcpy (mem, code, code_len);
- mprotect (ch.start, ch.bound - ch.start, PROT_EXEC);
+ mprotect (ch_ptr->start, ch_ptr->bound - ch_ptr->start, PROT_READ | PROT_EXEC);
return mem;
}
+uint8_t *_MIR_publish_code (MIR_context_t ctx, const uint8_t *code, size_t code_len) {
+ code_holder_t *ch_ptr;
+
+ if ((ch_ptr = get_last_code_holder (ctx, code_len)) == NULL) return NULL;
+ return add_code (ctx, ch_ptr, code, code_len);
+}
+
+uint8_t *_MIR_get_new_code_addr (MIR_context_t ctx, size_t size) {
+ code_holder_t *ch_ptr = get_last_code_holder (ctx, size);
+
+ return ch_ptr == NULL ? NULL : ch_ptr->free;
+}
+
+uint8_t *_MIR_publish_code_by_addr (MIR_context_t ctx, void *addr, const uint8_t *code,
+ size_t code_len) {
+ code_holder_t *ch_ptr = get_last_code_holder (ctx, 0);
+
+ if (ch_ptr == NULL || ch_ptr->free != addr || ch_ptr->free + code_len >= ch_ptr->bound)
+ return NULL;
+ return add_code (ctx, ch_ptr, code, code_len);
+}
+
+void _MIR_change_code (MIR_context_t ctx, uint8_t *addr, const uint8_t *code, size_t code_len) {
+ size_t len, start;
+
+ start = (size_t) addr / page_size * page_size;
+ len = (size_t) addr + code_len - start;
+ mprotect ((uint8_t *) start, len, PROT_WRITE | PROT_EXEC);
+ memcpy (addr, code, code_len);
+ mprotect ((uint8_t *) start, len, PROT_READ | PROT_EXEC);
+}
+
void _MIR_update_code_arr (MIR_context_t ctx, uint8_t *base, size_t nloc,
const MIR_code_reloc_t *relocs) {
size_t i, len, start, max_offset = 0;
@@ -3285,15 +3327,12 @@ void _MIR_update_code (MIR_context_t ctx, uint8_t *base, size_t nloc, ...) {
va_end (args);
}
-static void machine_init (MIR_context_t ctx);
-static void machine_finish (MIR_context_t ctx);
-
static void code_init (MIR_context_t ctx) {
if ((ctx->machine_code_ctx = malloc (sizeof (struct machine_code_ctx))) == NULL)
(*error_func) (MIR_alloc_error, "Not enough memory for ctx");
page_size = sysconf (_SC_PAGE_SIZE);
VARR_CREATE (code_holder_t, code_holders, 128);
- machine_init (ctx);
+ VARR_CREATE (uint8_t, machine_insns, 1024);
}
static void code_finish (MIR_context_t ctx) {
@@ -3302,7 +3341,7 @@ static void code_finish (MIR_context_t ctx) {
munmap (ch.start, ch.bound - ch.start);
}
VARR_DESTROY (code_holder_t, code_holders);
- machine_finish (ctx);
+ VARR_DESTROY (uint8_t, machine_insns);
free (ctx->machine_code_ctx);
ctx->machine_code_ctx = NULL;
}
@@ -3651,17 +3690,17 @@ static size_t write_item (MIR_context_t ctx, writer_func_t writer, MIR_item_t it
if (item->item_type == MIR_import_item) {
len += write_name (ctx, writer, "import");
- len += write_name (ctx, writer, item->u.import);
+ len += write_name (ctx, writer, item->u.import_id);
return len;
}
if (item->item_type == MIR_export_item) {
len += write_name (ctx, writer, "export");
- len += write_name (ctx, writer, item->u.export);
+ len += write_name (ctx, writer, item->u.export_id);
return len;
}
if (item->item_type == MIR_forward_item) {
len += write_name (ctx, writer, "forward");
- len += write_name (ctx, writer, item->u.forward);
+ len += write_name (ctx, writer, item->u.forward_id);
return len;
}
if (item->item_type == MIR_bss_item) {
@@ -4508,10 +4547,10 @@ typedef struct insn_name {
MIR_insn_code_t code;
} insn_name_t;
-static int insn_name_eq (insn_name_t in1, insn_name_t in2) {
+static int insn_name_eq (insn_name_t in1, insn_name_t in2, void *arg) {
return strcmp (in1.name, in2.name) == 0;
}
-static htab_hash_t insn_name_hash (insn_name_t in) {
+static htab_hash_t insn_name_hash (insn_name_t in, void *arg) {
return mir_hash (in.name, strlen (in.name), 0);
}
@@ -4566,7 +4605,13 @@ struct scan_ctx {
static void MIR_NO_RETURN MIR_UNUSED process_error (MIR_context_t ctx,
enum MIR_error_type error_type,
- const char *message) {
+ const char *format, ...) {
+#define MAX_MESSAGE_LEN 300
+ char message[MAX_MESSAGE_LEN];
+ va_list va;
+
+ va_start (va, format);
+ vsnprintf (message, MAX_MESSAGE_LEN, format, va);
(*error_func) (error_type, "ln %lu: %s", (unsigned long) curr_lno, message);
longjmp (error_jmp_buf, TRUE);
}
@@ -4661,8 +4706,11 @@ static void scan_string (MIR_context_t ctx, token_t *t, int c, int get_char (MIR
mir_assert (c == '\"');
VARR_TRUNC (char, temp_string, 0);
for (;;) {
- if ((c = get_char (ctx)) == EOF || c == '\n')
- process_error (ctx, MIR_syntax_error, "unfinished string");
+ if ((c = get_char (ctx)) == EOF || c == '\n') {
+ VARR_PUSH (char, temp_string, '\0');
+ process_error (ctx, MIR_syntax_error, "unfinished string \"%s",
+ VARR_ADDR (char, temp_string));
+ }
if (c == '"') break;
if (c == '\\') {
if ((c = get_char (ctx)) == 'n')
@@ -4703,7 +4751,11 @@ static void scan_string (MIR_context_t ctx, token_t *t, int c, int get_char (MIR
ch_code = 0;
for (int i = 2; i > 0; i--) {
c = get_char (ctx);
- if (!isxdigit (c)) process_error (ctx, MIR_syntax_error, "wrong hexadecimal escape");
+ if (!isxdigit (c)) {
+ VARR_PUSH (char, temp_string, '\0');
+ process_error (ctx, MIR_syntax_error, "wrong hexadecimal escape in %s",
+ VARR_ADDR (char, temp_string));
+ }
c = '0' <= c && c <= '9' ? c - '0' : 'a' <= c && c <= 'f' ? c - 'a' + 10 : c - 'A' + 10;
ch_code = (ch_code << 4) | c;
}
@@ -4777,7 +4829,8 @@ static void scan_token (MIR_context_t ctx, token_t *token, int (*get_char) (MIR_
if (ch == '+' || ch == '-') {
next_ch = get_char (ctx);
- if (!isdigit (next_ch)) process_error (ctx, MIR_syntax_error, "no number after a sign");
+ if (!isdigit (next_ch))
+ process_error (ctx, MIR_syntax_error, "no number after a sign %c", ch);
unget_char (ctx, next_ch);
}
scan_number (ctx, ch, get_char, unget_char, &base, &float_p, &double_p, &ldouble_p);
@@ -4802,14 +4855,19 @@ static void scan_token (MIR_context_t ctx, token_t *token, int (*get_char) (MIR_
;
return;
} else {
- process_error (ctx, MIR_syntax_error, "wrong char");
+ VARR_PUSH (char, temp_string, '\0');
+ process_error (ctx, MIR_syntax_error, "wrong char after %s", VARR_ADDR (char, temp_string));
}
}
}
}
-static int label_eq (label_desc_t l1, label_desc_t l2) { return strcmp (l1.name, l2.name) == 0; }
-static htab_hash_t label_hash (label_desc_t l) { return mir_hash (l.name, strlen (l.name), 0); }
+static int label_eq (label_desc_t l1, label_desc_t l2, void *arg) {
+ return strcmp (l1.name, l2.name) == 0;
+}
+static htab_hash_t label_hash (label_desc_t l, void *arg) {
+ return mir_hash (l.name, strlen (l.name), 0);
+}
static MIR_label_t create_label_desc (MIR_context_t ctx, const char *name) {
MIR_label_t label;
@@ -4842,16 +4900,15 @@ MIR_type_t MIR_str2type (MIR_context_t ctx, const char *type_name) {
}
static int func_reg_p (MIR_context_t ctx, MIR_func_t func, const char *name) {
- size_ctx_t sc, tab_sc;
+ size_t rdn, tab_rdn;
reg_desc_t rd;
int res;
rd.name_num = string_store (ctx, &strings, &string_tab, (MIR_str_t){strlen (name) + 1, name}).num;
rd.func = func;
- sc.rdn = VARR_LENGTH (reg_desc_t, reg_descs);
- sc.ctx = ctx;
+ rdn = VARR_LENGTH (reg_desc_t, reg_descs);
VARR_PUSH (reg_desc_t, reg_descs, rd);
- res = HTAB_DO (size_ctx_t, namenum2rdn_tab, sc, HTAB_FIND, tab_sc);
+ res = HTAB_DO (size_t, namenum2rdn_tab, rdn, HTAB_FIND, tab_rdn);
VARR_POP (reg_desc_t, reg_descs);
return res;
}
@@ -4997,7 +5054,7 @@ void MIR_scan_string (MIR_context_t ctx, const char *str) {
} else {
in.name = name;
if (!HTAB_DO (insn_name_t, insn_name_tab, in, HTAB_FIND, el))
- process_error (ctx, MIR_syntax_error, "Unknown insn");
+ process_error (ctx, MIR_syntax_error, "Unknown insn %s", name);
insn_code = el.code;
for (n = 0; n < VARR_LENGTH (label_name_t, label_names); n++) {
label = create_label_desc (ctx, VARR_GET (label_name_t, label_names, n));
@@ -5043,17 +5100,17 @@ void MIR_scan_string (MIR_context_t ctx, const char *str) {
} else if ((item = find_item (ctx, name, module)) != NULL) {
op = MIR_new_ref_op (ctx, item);
} else {
- process_error (ctx, MIR_syntax_error, "undeclared name");
+ process_error (ctx, MIR_syntax_error, "undeclared name %s", name);
}
break;
}
/* Memory, type only, arg, or var */
type = MIR_str2type (ctx, name);
if (type == MIR_T_BOUND)
- process_error (ctx, MIR_syntax_error, "Unknown type");
+ process_error (ctx, MIR_syntax_error, "Unknown type %s", name);
else if (local_p && type != MIR_T_I64 && type != MIR_T_F && type != MIR_T_D
&& type != MIR_T_LD)
- process_error (ctx, MIR_syntax_error, "wrong type for local var");
+ process_error (ctx, MIR_syntax_error, "wrong type %s for local var", name);
op = MIR_new_mem_op (ctx, type, 0, 0, 0, 1);
if (proto_p || func_p || local_p) {
if (t.code == TC_COL) {
@@ -5314,8 +5371,8 @@ static void scan_init (MIR_context_t ctx) {
if ((ctx->scan_ctx = malloc (sizeof (struct scan_ctx))) == NULL)
(*error_func) (MIR_alloc_error, "Not enough memory for ctx");
VARR_CREATE (label_name_t, label_names, 0);
- HTAB_CREATE (label_desc_t, label_desc_tab, 100, label_hash, label_eq);
- HTAB_CREATE (insn_name_t, insn_name_tab, MIR_INSN_BOUND, insn_name_hash, insn_name_eq);
+ HTAB_CREATE (label_desc_t, label_desc_tab, 100, label_hash, label_eq, NULL);
+ HTAB_CREATE (insn_name_t, insn_name_tab, MIR_INSN_BOUND, insn_name_hash, insn_name_eq, NULL);
for (i = 0; i < MIR_INSN_BOUND; i++) {
in.code = i;
in.name = MIR_insn_name (ctx, i);
@@ -5337,10 +5394,10 @@ static void scan_finish (MIR_context_t ctx) {
#if defined(__x86_64__)
#include "mir-x86_64.c"
-#elif defined(__PPC64__)
-#include "mir-ppc64.c"
#elif defined(__aarch64__)
#include "mir-aarch64.c"
+#elif defined(__PPC64__)
+#include "mir-ppc64.c"
#else
#error "undefined or unsupported generation target"
#endif
diff --git a/mir/mir.h b/mir/mir.h
index 33f2f55..20a2c24 100644
--- a/mir/mir.h
+++ b/mir/mir.h
@@ -143,6 +143,12 @@ typedef enum {
REP2 (TYPE_EL, UNDEF, BOUND),
} MIR_type_t;
+static inline int MIR_int_type_p (MIR_type_t t) {
+ return (MIR_T_I8 <= t && t <= MIR_T_U64) || t == MIR_T_P;
+}
+
+static inline int MIR_fp_type_p (MIR_type_t t) { return MIR_T_F <= t && t <= MIR_T_LD; }
+
#if UINTPTR_MAX == 0xffffffff
#define MIR_PTR32 1
#define MIR_PTR64 0
@@ -342,9 +348,9 @@ struct MIR_item {
union {
MIR_func_t func;
MIR_proto_t proto;
- MIR_name_t import;
- MIR_name_t export;
- MIR_name_t forward;
+ MIR_name_t import_id;
+ MIR_name_t export_id;
+ MIR_name_t forward_id;
MIR_data_t data;
MIR_ref_data_t ref_data;
MIR_expr_data_t expr_data;
@@ -481,6 +487,8 @@ extern void MIR_insert_insn_before (MIR_context_t ctx, MIR_item_t func, MIR_insn
MIR_insn_t insn);
extern void MIR_remove_insn (MIR_context_t ctx, MIR_item_t func, MIR_insn_t insn);
+extern MIR_insn_code_t MIR_reverse_branch_code (MIR_insn_code_t code);
+
extern const char *MIR_type_str (MIR_context_t ctx, MIR_type_t tp);
extern void MIR_output_op (MIR_context_t ctx, FILE *f, MIR_op_t op, MIR_func_t func);
extern void MIR_output_insn (MIR_context_t ctx, FILE *f, MIR_insn_t insn, MIR_func_t func,
@@ -557,7 +565,9 @@ extern MIR_item_t _MIR_builtin_func (MIR_context_t ctx, MIR_module_t module, con
void *addr);
extern uint8_t *_MIR_publish_code (MIR_context_t ctx, const uint8_t *code, size_t code_len);
-
+extern uint8_t *_MIR_get_new_code_addr (MIR_context_t ctx, size_t size);
+extern uint8_t *_MIR_publish_code_by_addr (MIR_context_t ctx, void *addr, const uint8_t *code,
+ size_t code_len);
struct MIR_code_reloc {
size_t offset;
void *value;
@@ -565,6 +575,8 @@ struct MIR_code_reloc {
typedef struct MIR_code_reloc MIR_code_reloc_t;
+extern void _MIR_change_code (MIR_context_t ctx, uint8_t *addr, const uint8_t *code,
+ size_t code_len);
extern void _MIR_update_code_arr (MIR_context_t ctx, uint8_t *base, size_t nloc,
const MIR_code_reloc_t *relocs);
extern void _MIR_update_code (MIR_context_t ctx, uint8_t *base, size_t nloc, ...);
@@ -577,7 +589,7 @@ extern void *_MIR_get_bstart_builtin (MIR_context_t ctx);
extern void *_MIR_get_bend_builtin (MIR_context_t ctx);
extern void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, size_t nargs,
- MIR_type_t *arg_types);
+ MIR_type_t *arg_types, int vararg_p);
extern void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handler);
extern void *_MIR_get_thunk (MIR_context_t ctx);
extern void _MIR_redirect_thunk (MIR_context_t ctx, void *thunk, void *to);
diff --git a/ravi-tests/ravi_tests1.ravi b/ravi-tests/ravi_tests1.ravi
index 920ba23..0c66148 100644
--- a/ravi-tests/ravi_tests1.ravi
+++ b/ravi-tests/ravi_tests1.ravi
@@ -1736,6 +1736,8 @@ compile(x)
assert(x(2,3) == 2^3)
print 'Test 77 OK'
+--
+
-- Test defer statement
y = 0
function x()
@@ -1836,6 +1838,8 @@ assert(z.count == 0)
assert(y == 1)
print 'Test 82 OK'
+--
+
for k,v in pairs(opcodes_coverage)
do
print(k, v)
diff --git a/ravi-tests/sieve.lua b/ravi-tests/sieve.lua
index d01da89..e19e922 100644
--- a/ravi-tests/sieve.lua
+++ b/ravi-tests/sieve.lua
@@ -1,7 +1,7 @@
-- Copyright vnmakarov see https://github.com/vnmakarov/mir/issues/2
local function sieve()
- local i: integer, k: integer, prime: integer, count: integer
- local flags: integer[] = table.intarray(8190)
+ local i, k, prime, count
+ local flags = {}
for iter=0,100000 do
count = 0
@@ -21,7 +21,7 @@ local function sieve()
return count
end
-if ravi.jit() then
+if ravi and ravi.jit() then
print('JIT ON')
ravi.optlevel(2)
ravi.compile(sieve, {omitArrayGetRangeCheck=1})
diff --git a/ravi-tests/sieve.ravi b/ravi-tests/sieve.ravi
new file mode 100644
index 0000000..d01da89
--- /dev/null
+++ b/ravi-tests/sieve.ravi
@@ -0,0 +1,37 @@
+-- Copyright vnmakarov see https://github.com/vnmakarov/mir/issues/2
+local function sieve()
+ local i: integer, k: integer, prime: integer, count: integer
+ local flags: integer[] = table.intarray(8190)
+
+ for iter=0,100000 do
+ count = 0
+ for i=0,8190 do
+ flags[i] = 1
+ end
+ for i=0,8190 do
+ if flags[i] == 1 then
+ prime = i + i + 3;
+ for k = i + prime, 8190, prime do
+ flags[k] = 0
+ end
+ count = count + 1
+ end
+ end
+ end
+ return count
+end
+
+if ravi.jit() then
+ print('JIT ON')
+ ravi.optlevel(2)
+ ravi.compile(sieve, {omitArrayGetRangeCheck=1})
+end
+-- ravi.dumplua(sieve)
+-- ravi.dumpir(sieve)
+
+local t1 = os.clock()
+local count = sieve()
+local t2 = os.clock()
+print("time taken ", t2-t1)
+print(count)
+assert(count == 1899)
diff --git a/readthedocs/ravi-overview.rst b/readthedocs/ravi-overview.rst
index fb783b0..009ee93 100644
--- a/readthedocs/ravi-overview.rst
+++ b/readthedocs/ravi-overview.rst
@@ -1,9 +1,11 @@
=========================
Ravi Programming Language
=========================
+.. image:: https://travis-ci.org/dibyendumajumdar/ravi.svg?branch=master
+ :target: https://travis-ci.org/dibyendumajumdar/ravi
Ravi is a derivative/dialect of `Lua 5.3 `_ with limited optional static typing and
-features `LLVM `_ and `Eclipse OMR `_
+features `MIR `_, `LLVM `_ and `Eclipse OMR `_
powered JIT compilers. The name Ravi comes from the Sanskrit word for the Sun.
Interestingly a precursor to Lua was `Sol `_ which had support for
static types; Sol means the Sun in Portugese.
@@ -31,10 +33,9 @@ Features
* Optional static typing - for details `see the reference manual `_.
* Type specific bytecodes to improve performance
* Compatibility with Lua 5.3 (see Compatibility section below)
+* New! JIT backend `MIR `_; only Linux and x86-64 supported for now.
* `LLVM `_ powered JIT compiler
* `Eclipse OMR `_ powered JIT compiler
-* New (wip) small JIT backend based on `MIR `_; only Linux and x86-64 supported.
-* Built-in C pre-processor, parser and JIT compiler
* A `distribution with batteries `_.
Documentation
@@ -50,6 +51,7 @@ Lua Goodies
===========
* `An Introduction to Lua `_ attempts to provide a quick overview of Lua for folks coming from other languages.
* `Lua 5.3 Bytecode Reference `_ is my attempt to bring up to date the `Lua 5.1 Bytecode Reference `_.
+* A `patch for Lua 5.3 `_ implements the 'defer' statement.
Compatibility with Lua
======================
@@ -99,7 +101,7 @@ History
- New JIT backend `MIR `_.
* 2020 (Plan)
- - New optimizing byte code generator based on new parser / type checker
+ - `New optimizing byte code generator based on new parser / type checker `_
- Ravi 1.0 release
License
diff --git a/src/ldo.c b/src/ldo.c
index bc0cdbd..999ad3a 100644
--- a/src/ldo.c
+++ b/src/ldo.c
@@ -681,7 +681,11 @@ static int recover (lua_State *L, int status) {
if (ci == NULL) return 0; /* no recovery point */
/* "finish" luaD_pcall */
oldtop = restorestack(L, ci->extra);
+#ifdef RAVI_DEFER_STATEMENT
luaF_close(L, oldtop, status);
+#else
+ luaF_close(L, oldtop);
+#endif
luaD_seterrorobj(L, status, oldtop);
L->ci = ci;
L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */
@@ -826,12 +830,18 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u,
status = luaD_rawrunprotected(L, func, u);
if (status != LUA_OK) { /* an error occurred? */
StkId oldtop = restorestack(L, old_top);
+#ifndef RAVI_DEFER_STATEMENT
+ luaF_close(L, oldtop); /* close possible pending closures */
+ luaD_seterrorobj(L, status, oldtop);
+#endif
L->ci = old_ci;
L->allowhook = old_allowhooks;
L->nny = old_nny;
+#ifdef RAVI_DEFER_STATEMENT
status = luaF_close(L, oldtop, status); /* close possible pending closures */
oldtop = restorestack(L, old_top);
luaD_seterrorobj(L, status, oldtop);
+#endif
luaD_shrinkstack(L);
}
L->errfunc = old_errfunc;
diff --git a/src/lfunc.c b/src/lfunc.c
index f209720..5851597 100644
--- a/src/lfunc.c
+++ b/src/lfunc.c
@@ -68,15 +68,22 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
lua_assert(isintwups(L) || L->openupval == NULL);
while (*pp != NULL && (p = *pp)->v >= level) {
lua_assert(upisopen(p));
+#ifdef RAVI_DEFER_STATEMENT
if (p->v == level && !p->flags) /* found a corresponding upvalue that is not a deferred value? */ {
return p; /* return it */
}
+#else
+ if (p->v == level) /* found a corresponding upvalue? */
+ return p; /* return it */
+#endif
pp = &p->u.open.next;
}
/* not found: create a new upvalue */
uv = luaM_new(L, UpVal);
uv->refcount = 0;
+#ifdef RAVI_DEFER_STATEMENT
uv->flags = 0;
+#endif
uv->u.open.next = *pp; /* link it to list of open upvalues */
uv->u.open.touched = 1;
*pp = uv;
@@ -88,6 +95,7 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
return uv;
}
+#ifdef RAVI_DEFER_STATEMENT
static void calldeferred(lua_State *L, void *ud) {
UNUSED(ud);
luaD_callnoyield(L, L->top - 2, 0);
@@ -167,6 +175,22 @@ int luaF_close (lua_State *L, StkId level, int status) {
}
return status;
}
+#else
+void luaF_close (lua_State *L, StkId level) {
+ UpVal *uv;
+ while (L->openupval != NULL && (uv = L->openupval)->v >= level) {
+ lua_assert(upisopen(uv));
+ L->openupval = uv->u.open.next; /* remove from 'open' list */
+ if (uv->refcount == 0) /* no references? */
+ luaM_free(L, uv); /* free upvalue */
+ else {
+ setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */
+ uv->v = &uv->u.value; /* now current value lives here */
+ luaC_upvalbarrier(L, uv);
+ }
+ }
+}
+#endif
Proto *luaF_newproto (lua_State *L) {
diff --git a/src/llex.c b/src/llex.c
index 5443549..391b12e 100644
--- a/src/llex.c
+++ b/src/llex.c
@@ -40,7 +40,11 @@
static const char *const luaX_tokens [] = {
"and", "break", "do", "else", "elseif",
"end", "false", "for", "function", "goto", "if",
+#ifdef RAVI_DEFER_STATEMENT
"in", "local", "defer", "nil", "not", "or", "repeat",
+#else
+ "in", "local", "nil", "not", "or", "repeat",
+#endif
"return", "then", "true", "until", "while",
"//", "..", "...", "==", ">=", "<=", "~=",
"<<", ">>", "::", "",
diff --git a/src/lopcodes.c b/src/lopcodes.c
index bdba681..210a616 100644
--- a/src/lopcodes.c
+++ b/src/lopcodes.c
@@ -164,7 +164,9 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = {
"SELF_SK", /* _SK*/ /* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */
"SETFIELD", /*_SK */ /* A B C R(A)[RK(B)] := RK(C), string key */
"GETTABUP_SK",
+#ifdef RAVI_DEFER_STATEMENT
"DEFER",
+#endif
NULL
};
@@ -306,9 +308,9 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_RAVI_SELF_SK */
,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_RAVI_SETFIELD */
,opmode(0, 1, OpArgU, OpArgK, iABC) /* OP_RAVI_GETTABUP_SK */
-
+#ifdef RAVI_DEFER_STATEMENT
,opmode(0, 1, OpArgN, OpArgN, iABC) /* OP_RAVI_DEFER */
-
+#endif
};
diff --git a/src/lparser.c b/src/lparser.c
index 30f50c6..20b4f18 100644
--- a/src/lparser.c
+++ b/src/lparser.c
@@ -920,6 +920,7 @@ static Proto *addprototype (LexState *ls) {
** so that, if it invokes the GC, the GC knows which registers
** are in use at that time.
*/
+#ifdef RAVI_DEFER_STATEMENT
static void codeclosure (LexState *ls, expdesc *v, int deferred) {
FuncState *fs = ls->fs->prev;
int pc = -1;
@@ -933,6 +934,14 @@ static void codeclosure (LexState *ls, expdesc *v, int deferred) {
}
DEBUG_VARS(raviY_printf(ls->fs, "codeclosure -> closure created %e\n", v));
}
+#else
+static void codeclosure (LexState *ls, expdesc *v) {
+ FuncState *fs = ls->fs->prev;
+ init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1), RAVI_TFUNCTION, NULL);
+ luaK_exp2nextreg(fs, v); /* fix it at the last register */
+ DEBUG_VARS(raviY_printf(ls->fs, "codeclosure -> closure created %e\n", v));
+}
+#endif
static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) {
@@ -1290,7 +1299,7 @@ static void parlist (LexState *ls) {
}
}
-
+#ifdef RAVI_DEFER_STATEMENT
static void body (LexState *ls, expdesc *e, int ismethod, int line, int deferred) {
/* body -> '(' parlist ')' block END */
FuncState new_fs;
@@ -1313,6 +1322,28 @@ static void body (LexState *ls, expdesc *e, int ismethod, int line, int deferred
codeclosure(ls, e, deferred);
close_func(ls);
}
+#else
+static void body (LexState *ls, expdesc *e, int ismethod, int line) {
+ /* body -> '(' parlist ')' block END */
+ FuncState new_fs;
+ BlockCnt bl;
+ new_fs.f = addprototype(ls);
+ new_fs.f->linedefined = line;
+ open_func(ls, &new_fs, &bl);
+ checknext(ls, '(');
+ if (ismethod) {
+ new_localvarliteral(ls, "self"); /* create 'self' parameter */
+ adjustlocalvars(ls, 1);
+ }
+ parlist(ls);
+ checknext(ls, ')');
+ statlist(ls);
+ new_fs.f->lastlinedefined = ls->linenumber;
+ check_match(ls, TK_END, TK_FUNCTION, line);
+ codeclosure(ls, e);
+ close_func(ls);
+}
+#endif
/* parse expression list */
static int explist (LexState *ls, expdesc *v) {
@@ -1602,7 +1633,11 @@ static void simpleexp (LexState *ls, expdesc *v) {
}
case TK_FUNCTION: {
luaX_next(ls);
+#ifdef RAVI_DEFER_STATEMENT
body(ls, v, 0, ls->linenumber, 0);
+#else
+ body(ls, v, 0, ls->linenumber);
+#endif
return;
}
default: {
@@ -2187,6 +2222,7 @@ static void ifstat (LexState *ls, int line) {
}
/* parse a local function statement - called from statement() */
+#ifdef RAVI_DEFER_STATEMENT
static void localfunc (LexState *ls, int defer) {
expdesc b = {.ravi_type = RAVI_TANY, .pc = -1};
FuncState *fs = ls->fs;
@@ -2203,6 +2239,18 @@ static void localfunc (LexState *ls, int defer) {
/* debug information will only see the variable after this point! */
getlocvar(fs, b.u.info)->startpc = fs->pc;
}
+#else
+static void localfunc (LexState *ls) {
+ expdesc b = {.ravi_type = RAVI_TANY, .pc = -1};
+ FuncState *fs = ls->fs;
+ /* RAVI change - add type */
+ new_localvar(ls, str_checkname(ls), RAVI_TFUNCTION, NULL); /* new local variable */
+ adjustlocalvars(ls, 1); /* enter its scope */
+ body(ls, &b, 0, ls->linenumber); /* function created in next register */
+ /* debug information will only see the variable after this point! */
+ getlocvar(fs, b.u.info)->startpc = fs->pc;
+}
+#endif
/* parse a local variable declaration statement - called from statement() */
static void localstat (LexState *ls) {
@@ -2262,7 +2310,11 @@ static void funcstat (LexState *ls, int line) {
luaX_next(ls); /* skip FUNCTION */
ismethod = funcname(ls, &v);
DEBUG_VARS(raviY_printf(ls->fs, "funcstat -> declaring function %e\n", &v));
+#ifdef RAVI_DEFER_STATEMENT
body(ls, &b, ismethod, line, 0);
+#else
+ body(ls, &b, ismethod, line);
+#endif
luaK_storevar(ls->fs, &v, &b);
luaK_fixline(ls->fs, line); /* definition "happens" in the first line */
}
@@ -2355,16 +2407,22 @@ static void statement (LexState *ls) {
case TK_LOCAL: { /* stat -> localstat */
luaX_next(ls); /* skip LOCAL */
if (testnext(ls, TK_FUNCTION)) /* local function? */
+#ifdef RAVI_DEFER_STATEMENT
localfunc(ls, 0);
+#else
+ localfunc(ls);
+#endif
else
localstat(ls);
break;
}
+#ifdef RAVI_DEFER_STATEMENT
case TK_DEFER: { /* stat -> deferstat */
luaX_next(ls); /* skip DEFER */
localfunc(ls, 1);
break;
}
+#endif
case TK_DBCOLON: { /* stat -> label */
luaX_next(ls); /* skip double colon */
labelstat(ls, str_checkname(ls), line);
diff --git a/src/lstate.c b/src/lstate.c
index 1bd3f1b..7877710 100644
--- a/src/lstate.c
+++ b/src/lstate.c
@@ -266,7 +266,11 @@ void *ravi_alloc_f(void *msp, void *ptr, size_t osize, size_t nsize)
static void close_state (lua_State *L) {
global_State *g = G(L);
+#ifdef RAVI_DEFER_STATEMENT
luaF_close(L, L->stack, -1); /* close all upvalues for this thread */
+#else
+ luaF_close(L, L->stack); /* close all upvalues for this thread */
+#endif
luaC_freeallobjects(L); /* collect all objects */
if (g->version) /* closing a fully built state? */
luai_userstateclose(L);
@@ -313,7 +317,11 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
void luaE_freethread (lua_State *L, lua_State *L1) {
LX *l = fromstate(L1);
+#ifdef RAVI_DEFER_STATEMENT
luaF_close(L1, L1->stack, -1); /* close all upvalues for this thread */
+#else
+ luaF_close(L1, L1->stack); /* close all upvalues for this thread */
+#endif
lua_assert(L1->openupval == NULL);
luai_userstatefree(L, L1);
freestack(L1);
diff --git a/src/lvm.c b/src/lvm.c
index 9799d72..3cd2306 100644
--- a/src/lvm.c
+++ b/src/lvm.c
@@ -1025,6 +1025,7 @@ void luaV_finishOp (lua_State *L) {
** Execute a jump instruction. The 'updatemask' allows signals to stop
** tight loops. (Without it, the local copy of 'mask' could never change.)
*/
+#ifdef RAVI_DEFER_STATEMENT
#define dojump(ci, i, e) \
{ \
int a = GETARG_A(i); \
@@ -1033,6 +1034,12 @@ void luaV_finishOp (lua_State *L) {
pc += GETARG_sBx(i) + e; \
updatemask(L); \
}
+#else
+#define dojump(ci,i,e) \
+ { int a = GETARG_A(i); \
+ if (a != 0) luaF_close(L, ci->u.l.base + a - 1); \
+ pc += GETARG_sBx(i) + e; updatemask(L); }
+#endif
/* for test instructions, execute the jump instruction that follows it */
#define donextjump(ci) { i = *pc; dojump(ci, i, 1); }
@@ -1274,7 +1281,9 @@ int luaV_execute (lua_State *L) {
&&vmlabel(OP_RAVI_SELF_SK),
&&vmlabel(OP_RAVI_SETFIELD),
&&vmlabel(OP_RAVI_GETTABUP_SK),
+#ifdef RAVI_DEFER_STATEMENT
&&vmlabel(OP_RAVI_DEFER),
+#endif
};
#endif
@@ -1717,8 +1726,12 @@ int luaV_execute (lua_State *L) {
StkId lim = nci->u.l.base + getproto(nfunc)->numparams;
int aux;
/* close all upvalues from previous call */
+#ifdef RAVI_DEFER_STATEMENT
if (cl->p->sizep > 0)
Protect_base(luaF_close(L, oci->u.l.base, LUA_OK));
+#else
+ if (cl->p->sizep > 0) luaF_close(L, oci->u.l.base);
+#endif
/* move new frame into old one */
for (aux = 0; nfunc + aux < lim; aux++)
setobjs2s(L, ofunc + aux, nfunc + aux);
@@ -1735,8 +1748,12 @@ int luaV_execute (lua_State *L) {
}
vmcase(OP_RETURN) {
int b = GETARG_B(i);
+#ifdef RAVI_DEFER_STATEMENT
if (cl->p->sizep > 0)
Protect_base(luaF_close(L, base, LUA_OK));
+#else
+ if (cl->p->sizep > 0) luaF_close(L, base);
+#endif
savepc(L);
int nres = (b != 0 ? b - 1 : cast_int(L->top - ra));
b = luaD_poscall(L, ci, ra, nres);
@@ -2494,12 +2511,14 @@ int luaV_execute (lua_State *L) {
}
vmbreak;
}
+#ifdef RAVI_DEFER_STATEMENT
vmcase(OP_RAVI_DEFER) {
UpVal *up = luaF_findupval(L, ra); /* create new upvalue */
up->flags = 1; /* mark it as deferred */
setnilvalue(ra); /* initialize it with nil */
vmbreak;
}
+#endif
}
}
}
@@ -3032,6 +3051,7 @@ void raviV_op_totype(lua_State *L, TValue *ra, TValue *rb) {
luaG_runerror(L, "type mismatch: expected %s", getstr(key));
}
+#ifdef RAVI_DEFER_STATEMENT
/*
** OP_RAVI_DEFER
*/
@@ -3040,6 +3060,7 @@ void raviV_op_defer(lua_State *L, TValue *ra) {
up->flags = 1; /* mark it as deferred */
setnilvalue(ra); /* initialize it with nil */
}
+#endif
/* }================================================================== */
diff --git a/src/ravi_ast_parse.c b/src/ravi_ast_parse.c
index 8980594..bdd6c4f 100644
--- a/src/ravi_ast_parse.c
+++ b/src/ravi_ast_parse.c
@@ -11,7 +11,7 @@ Copyright (C) 2018-2020 Dibyendu Majumdar
*/
-#include
+#include "ravi_ast.h"
/* forward declarations */
static struct ast_node *parse_expression(struct parser_state *);
@@ -24,6 +24,7 @@ static void end_scope(struct parser_state *parser);
static struct ast_node *new_literal_expression(struct parser_state *parser, ravitype_t type);
static struct ast_node *generate_label(struct parser_state *parser, TString *label);
static struct ast_container *new_ast_container(lua_State *L);
+static void add_local_symbol_to_current_scope(struct parser_state *parser, struct lua_symbol *sym);
static void add_symbol(struct ast_container *container, struct lua_symbol_list **list, struct lua_symbol *sym) {
ptrlist_add((struct ptr_list **)list, sym, &container->ptrlist_allocator);
@@ -118,11 +119,6 @@ static struct lua_symbol *new_local_symbol(struct parser_state *parser, TString
symbol->symbol_type = SYM_LOCAL;
symbol->var.block = scope;
symbol->var.var_name = name;
- symbol->var.pseudo = NULL;
- add_symbol(parser->container, &scope->symbol_list, symbol); // Add to the end of the symbol list
- add_symbol(parser->container, &scope->function->function_expr.locals, symbol);
- // Note that Lua allows multiple local declarations of the same name
- // so a new instance just gets added to the end
return symbol;
}
@@ -541,6 +537,7 @@ static bool parse_parameter_list(struct parser_state *parser, struct lua_symbol_
/* RAVI change - add type */
struct lua_symbol *symbol = declare_local_variable(parser);
add_symbol(parser->container, list, symbol);
+ add_local_symbol_to_current_scope(parser, symbol);
nparams++;
break;
}
@@ -934,6 +931,13 @@ static struct ast_node *parse_expression(struct parser_state *parser) {
** =======================================================================
*/
+static void add_local_symbol_to_current_scope(struct parser_state *parser, struct lua_symbol *sym) {
+ // Note that Lua allows multiple local declarations of the same name
+ // so a new instance just gets added to the end
+ add_symbol(parser->container, &parser->current_scope->symbol_list, sym);
+ add_symbol(parser->container, &parser->current_scope->function->function_expr.locals, sym);
+}
+
static struct block_scope *parse_block(struct parser_state *parser, struct ast_node_list **statement_list) {
/* block -> statlist */
struct block_scope *scope = new_scope(parser);
@@ -1039,7 +1043,9 @@ static void parse_forbody(struct parser_state *parser, struct ast_node *stmt, in
static void parse_fornum_statement(struct parser_state *parser, struct ast_node *stmt, TString *varname, int line) {
LexState *ls = parser->ls;
/* fornum -> NAME = exp1,exp1[,exp1] forbody */
- add_symbol(parser->container, &stmt->for_stmt.symbols, new_local_symbol(parser, varname, RAVI_TANY, NULL));
+ struct lua_symbol *local = new_local_symbol(parser, varname, RAVI_TANY, NULL);
+ add_symbol(parser->container, &stmt->for_stmt.symbols, local);
+ add_local_symbol_to_current_scope(parser, local);
checknext(ls, '=');
/* get the type of each expression */
add_ast_node(parser->container, &stmt->for_stmt.expr_list, parse_expression(parser)); /* initial value */
@@ -1057,10 +1063,13 @@ static void parse_for_list(struct parser_state *parser, struct ast_node *stmt, T
/* forlist -> NAME {,NAME} IN explist forbody */
int nvars = 4; /* gen, state, control, plus at least one declared var */
/* create declared variables */
- add_symbol(parser->container, &stmt->for_stmt.symbols, new_local_symbol(parser, indexname, RAVI_TANY, NULL));
+ struct lua_symbol *local = new_local_symbol(parser, indexname, RAVI_TANY, NULL);
+ add_symbol(parser->container, &stmt->for_stmt.symbols, local);
+ add_local_symbol_to_current_scope(parser, local);
while (testnext(ls, ',')) {
- add_symbol(parser->container, &stmt->for_stmt.symbols,
- new_local_symbol(parser, check_name_and_next(ls), RAVI_TANY, NULL));
+ local = new_local_symbol(parser, check_name_and_next(ls), RAVI_TANY, NULL);
+ add_symbol(parser->container, &stmt->for_stmt.symbols, local);
+ add_local_symbol_to_current_scope(parser, local);
nvars++;
}
checknext(ls, TK_IN);
@@ -1157,6 +1166,8 @@ static struct ast_node *parse_local_function_statement(struct parser_state *pars
LexState *ls = parser->ls;
struct lua_symbol *symbol =
new_local_symbol(parser, check_name_and_next(ls), RAVI_TFUNCTION, NULL); /* new local variable */
+ /* local function f ... is parsed as local f; f = function ... */
+ add_local_symbol_to_current_scope(parser, symbol);
struct ast_node *function_ast = new_function(parser);
parse_function_body(parser, function_ast, 0, ls->linenumber); /* function created in next register */
end_function(parser);
@@ -1191,6 +1202,10 @@ static struct ast_node *parse_local_statement(struct parser_state *parser) {
/* nexps = 0; */
;
}
+ /* local symbols are only added to scope at the end of the local statement */
+ struct lua_symbol *sym = NULL;
+ FOR_EACH_PTR(node->local_stmt.var_list, sym) { add_local_symbol_to_current_scope(parser, sym); }
+ END_FOR_EACH_PTR(sym);
return node;
}
@@ -1651,7 +1666,6 @@ static struct ast_container *new_ast_container(lua_State *L) {
dmrC_allocator_init(&container->symbol_allocator, "symbols", sizeof(struct lua_symbol), sizeof(double), CHUNK);
container->main_function = NULL;
container->killed = false;
- container->linearizer = NULL;
luaL_getmetatable(L, AST_type);
lua_setmetatable(L, -2);
return container;
@@ -1661,10 +1675,6 @@ static struct ast_container *new_ast_container(lua_State *L) {
static int collect_ast_container(lua_State *L) {
struct ast_container *container = check_Ravi_AST(L, 1);
if (!container->killed) {
- if (container->linearizer) {
- raviA_destroy_linearizer(container->linearizer);
- free(container->linearizer);
- }
dmrC_allocator_destroy(&container->symbol_allocator);
dmrC_allocator_destroy(&container->block_scope_allocator);
dmrC_allocator_destroy(&container->ast_node_allocator);
@@ -1674,37 +1684,8 @@ static int collect_ast_container(lua_State *L) {
return 0;
}
-static int ast_linearize(lua_State *L) {
- struct ast_container *container = check_Ravi_AST(L, 1);
- if (container->linearizer) {
- luaL_error(L, "Already linearized");
- }
- struct linearizer *linearizer = (struct linearizer *)calloc(1, sizeof(struct linearizer));
- raviA_init_linearizer(linearizer, container);
- container->linearizer = linearizer;
- raviA_ast_linearize(container->linearizer);
- return 0;
-}
-
-static int ast_show_linearized(lua_State *L) {
- struct ast_container *container = check_Ravi_AST(L, 1);
- if (!container->linearizer) {
- luaL_error(L, "Not yet linearized");
- return 0;
- }
- membuff_t mb;
- membuff_init(&mb, 1024);
- raviA_show_linearizer(container->linearizer, &mb);
- lua_pushstring(L, mb.buf);
- membuff_free(&mb);
- return 1;
-}
-
-static const luaL_Reg container_methods[] = {{"tostring", ast_container_to_string},
- {"release", collect_ast_container},
- {"linearize", ast_linearize},
- {"showlinear", ast_show_linearized},
- {NULL, NULL}};
+static const luaL_Reg container_methods[] = {
+ {"tostring", ast_container_to_string}, {"release", collect_ast_container}, {NULL, NULL}};
static const luaL_Reg astlib[] = {
/* Entrypoint for new AST */
diff --git a/src/ravi_jitshared.c b/src/ravi_jitshared.c
index bc718e5..953a595 100644
--- a/src/ravi_jitshared.c
+++ b/src/ravi_jitshared.c
@@ -517,8 +517,12 @@ static const char Lua_header[] =
"};\n"
"struct UpVal {\n"
" TValue *v;\n"
+#ifdef RAVI_DEFER_STATEMENT
" unsigned int refcount;\n"
" unsigned int flags;\n"
+#else
+ " lu_mem refcount;\n"
+#endif
" union {\n"
" struct {\n"
" UpVal *next;\n"
@@ -547,7 +551,11 @@ static const char Lua_header[] =
" (ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,LUA_FLOORN2I))\n"
"extern int luaV_tonumber_(const TValue *obj, lua_Number *n);\n"
"extern int luaV_tointeger(const TValue *obj, lua_Integer *p, int mode);\n"
+#ifdef RAVI_DEFER_STATEMENT
"extern int luaF_close (lua_State *L, StkId level, int status);\n"
+#else
+ "extern void luaF_close (lua_State *L, StkId level);\n"
+#endif
"extern int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres);\n"
"extern int luaV_equalobj(lua_State *L, const TValue *t1, const TValue *t2);\n"
"extern int luaV_lessthan(lua_State *L, const TValue *l, const TValue *r);\n"
@@ -583,7 +591,9 @@ static const char Lua_header[] =
"extern void raviV_settable_sskey(lua_State *L, const TValue *t, TValue *key, TValue *val);\n"
"extern void raviV_gettable_i(lua_State *L, const TValue *t, TValue *key, TValue *val);\n"
"extern void raviV_settable_i(lua_State *L, const TValue *t, TValue *key, TValue *val);\n"
+#ifdef RAVI_DEFER_STATEMENT
"extern void raviV_op_defer(lua_State *L, TValue *ra);\n"
+#endif
"extern lua_Integer luaV_shiftl(lua_Integer x, lua_Integer y);\n"
"extern void ravi_dump_value(lua_State *L, const struct lua_TValue *v);\n"
"extern void raviV_op_bnot(lua_State *L, TValue *ra, TValue *rb);\n"
@@ -967,6 +977,25 @@ static void emit_comparison(struct function *fn, int A, int B, int C, int j, int
membuff_add_fstring(&fn->body, "result = (fltvalue(rb) %s fltvalue(rc));\n", oper);
}
break;
+ case OP_LT:
+ oper = "<";
+ goto Lemit;
+ case OP_LE:
+ oper = "<=";
+ Lemit:
+ emit_reg_or_k(fn, "rb", B);
+ emit_reg_or_k(fn, "rc", C);
+ membuff_add_string(&fn->body, "if (ttisinteger(rb) && ttisinteger(rc))\n");
+ membuff_add_fstring(&fn->body, " result = (ivalue(rb) %s ivalue(rc));\n", oper);
+ membuff_add_string(&fn->body, "else {\n");
+ emit_update_savedpc(fn, pc);
+ membuff_add_fstring(&fn->body, " result = %s(L, rb, rc);\n", compfunc);
+ // Reload pointer to base as the call to luaV_equalobj() may
+ // have invoked a Lua function and as a result the stack may have
+ // been reallocated - so the previous base pointer could be stale
+ membuff_add_string(&fn->body, " base = ci->u.l.base;\n");
+ membuff_add_string(&fn->body, "}\n");
+ break;
default:
emit_reg_or_k(fn, "rb", B);
emit_reg_or_k(fn, "rc", C);
@@ -981,8 +1010,12 @@ static void emit_comparison(struct function *fn, int A, int B, int C, int j, int
membuff_add_fstring(&fn->body, "if (result == %d) {\n", A);
if (jA > 0) {
membuff_add_fstring(&fn->body, " ra = R(%d);\n", jA - 1);
+#ifdef RAVI_DEFER_STATEMENT
membuff_add_string(&fn->body, " luaF_close(L, ra, LUA_OK);\n");
membuff_add_string(&fn->body, " base = ci->u.l.base;\n");
+#else
+ membuff_add_string(&fn->body, " luaF_close(L, ra);\n");
+#endif
}
membuff_add_fstring(&fn->body, " goto Lbc_%d;\n", j);
membuff_add_string(&fn->body, "}\n");
@@ -1021,9 +1054,13 @@ static void emit_op_loadk(struct function *fn, int A, int Bx, int pc) {
static void emit_op_return(struct function *fn, int A, int B, int pc) {
(void)pc;
emit_reg(fn, "ra", A);
+#ifdef RAVI_DEFER_STATEMENT
membuff_add_string(&fn->body, "if (cl->p->sizep > 0) {\n luaF_close(L, base, LUA_OK);\n");
membuff_add_string(&fn->body, " base = ci->u.l.base;\n");
membuff_add_string(&fn->body, "}\n");
+#else
+ membuff_add_string(&fn->body, "if (cl->p->sizep > 0) luaF_close(L, base);\n");
+#endif
membuff_add_fstring(&fn->body, "result = (%d != 0 ? %d - 1 : cast_int(L->top - ra));\n", B, B);
membuff_add_string(&fn->body, "return luaD_poscall(L, ci, ra, result);\n");
}
@@ -1048,8 +1085,12 @@ static void emit_op_jmp(struct function *fn, int A, int sBx, int pc) {
(void)pc;
if (A > 0) {
membuff_add_fstring(&fn->body, "ra = R(%d);\n", A - 1);
+#ifdef RAVI_DEFER_STATEMENT
membuff_add_string(&fn->body, "luaF_close(L, ra, LUA_OK);\n");
membuff_add_string(&fn->body, "base = ci->u.l.base;\n");
+#else
+ membuff_add_string(&fn->body, "luaF_close(L, ra);\n");
+#endif
}
membuff_add_fstring(&fn->body, "goto Lbc_%d;\n", sBx);
}
@@ -1077,8 +1118,12 @@ static void emit_op_test(struct function *fn, int A, int B, int C, int j, int jA
membuff_add_fstring(&fn->body, "if (!result) {\n", A);
if (jA > 0) {
membuff_add_fstring(&fn->body, " ra = R(%d);\n", jA - 1);
+#ifdef RAVI_DEFER_STATEMENT
membuff_add_string(&fn->body, " luaF_close(L, ra, LUA_OK);\n");
membuff_add_string(&fn->body, " base = ci->u.l.base;\n");
+#else
+ membuff_add_string(&fn->body, " luaF_close(L, ra);\n");
+#endif
}
membuff_add_fstring(&fn->body, " goto Lbc_%d;\n", j);
membuff_add_string(&fn->body, " }\n");
@@ -1098,8 +1143,12 @@ static void emit_op_testset(struct function *fn, int A, int B, int C, int j, int
membuff_add_string(&fn->body, " setobjs2s(L, ra, rb);");
if (jA > 0) {
membuff_add_fstring(&fn->body, " ra = R(%d);\n", jA - 1);
+#ifdef RAVI_DEFER_STATEMENT
membuff_add_string(&fn->body, " luaF_close(L, ra, LUA_OK);\n");
membuff_add_string(&fn->body, " base = ci->u.l.base;\n");
+#else
+ membuff_add_string(&fn->body, " luaF_close(L, ra);\n");
+#endif
}
membuff_add_fstring(&fn->body, " goto Lbc_%d;\n", j);
membuff_add_string(&fn->body, " }\n");
@@ -1303,9 +1352,21 @@ static void emit_binary_op(struct function *fn, int A, int B, int C, OpCode op,
void emit_ff_op(struct function *fn, int A, int B, int C, int pc, const char *op) {
(void)pc;
emit_reg(fn, "ra", A);
- emit_reg_or_k(fn, "rb", B);
- emit_reg_or_k(fn, "rc", C);
- membuff_add_fstring(&fn->body, "setfltvalue(ra, fltvalue(rb) %s fltvalue(rc));\n", op);
+ if (ISK(B)) {
+ TValue *Konst1 = &fn->p->k[INDEXK(B)];
+ emit_reg_or_k(fn, "rc", C);
+ membuff_add_fstring(&fn->body, "setfltvalue(ra, %.17g %s fltvalue(rc));\n", Konst1->value_.n, op);
+ }
+ else if (ISK(C)) {
+ TValue *Konst1 = &fn->p->k[INDEXK(C)];
+ emit_reg_or_k(fn, "rb", B);
+ membuff_add_fstring(&fn->body, "setfltvalue(ra, fltvalue(rb) %s %.17g);\n", op, Konst1->value_.n);
+ }
+ else {
+ emit_reg_or_k(fn, "rb", B);
+ emit_reg_or_k(fn, "rc", C);
+ membuff_add_fstring(&fn->body, "setfltvalue(ra, fltvalue(rb) %s fltvalue(rc));\n", op);
+ }
}
static void emit_fi_op(struct function *fn, int A, int B, int C, int pc, const char *op) {
@@ -1327,9 +1388,21 @@ static void emit_if_op(struct function *fn, int A, int B, int C, int pc, const c
static void emit_ii_op(struct function *fn, int A, int B, int C, int pc, const char *op) {
(void)pc;
emit_reg(fn, "ra", A);
- emit_reg_or_k(fn, "rb", B);
- emit_reg_or_k(fn, "rc", C);
- membuff_add_fstring(&fn->body, "setivalue(ra, ivalue(rb) %s ivalue(rc));\n", op);
+ if (ISK(B)) {
+ TValue *Konst1 = &fn->p->k[INDEXK(B)];
+ emit_reg_or_k(fn, "rc", C);
+ membuff_add_fstring(&fn->body, "setivalue(ra, %lld %s ivalue(rc));\n", Konst1->value_.i, op);
+ }
+ else if (ISK(C)) {
+ TValue *Konst1 = &fn->p->k[INDEXK(C)];
+ emit_reg_or_k(fn, "rb", B);
+ membuff_add_fstring(&fn->body, "setivalue(ra, ivalue(rb) %s %lld);\n", op, Konst1->value_.i);
+ }
+ else {
+ emit_reg_or_k(fn, "rb", B);
+ emit_reg_or_k(fn, "rc", C);
+ membuff_add_fstring(&fn->body, "setivalue(ra, ivalue(rb) %s ivalue(rc));\n", op);
+ }
}
static void emit_op_divii(struct function *fn, int A, int B, int C, int pc) {
@@ -1342,11 +1415,13 @@ static void emit_op_divii(struct function *fn, int A, int B, int C, int pc) {
"(lua_Number)(ivalue(rc)));\n");
}
+#ifdef RAVI_DEFER_STATEMENT
static void emit_op_defer(struct function *fn, int A, int pc) {
(void)pc;
emit_reg(fn, "ra", A);
membuff_add_string(&fn->body, "raviV_op_defer(L, ra);\n");
}
+#endif
static void emit_op_loadfz(struct function *fn, int A, int pc) {
(void)pc;
@@ -2210,9 +2285,11 @@ bool raviJ_codegen(struct lua_State *L, struct Proto *p, struct ravi_compile_opt
int B = GETARG_B(i);
emit_op_len(&fn, A, B, pc);
} break;
+#ifdef RAVI_DEFER_STATEMENT
case OP_RAVI_DEFER: {
emit_op_defer(&fn, A, pc);
} break;
+#endif
case OP_RAVI_SHR_II:
case OP_RAVI_SHL_II:
case OP_RAVI_BXOR_II:
diff --git a/src/ravi_llvmcall.cpp b/src/ravi_llvmcall.cpp
index 9a82dd2..aa52b50 100644
--- a/src/ravi_llvmcall.cpp
+++ b/src/ravi_llvmcall.cpp
@@ -51,10 +51,14 @@ void RaviCodeGenerator::emit_JMP(RaviFunctionDef *def, int A, int sBx, int pc) {
emit_load_base(def);
// base + a - 1
llvm::Value *val = emit_gep_register(def, A - 1);
+#ifdef RAVI_DEFER_STATEMENT
if (!traced)
emit_update_savedpc(def, pc);
// Call luaF_close
CreateCall3(def->builder, def->luaF_closeF, def->L, val, def->types->kInt[LUA_OK]);
+#else
+ CreateCall2(def->builder, def->luaF_closeF, def->L, val);
+#endif
}
// Do the actual jump
@@ -173,11 +177,13 @@ void RaviCodeGenerator::emit_CALL(RaviFunctionDef *def, int A, int B, int C,
def->builder->SetInsertPoint(end_block);
}
+#ifdef RAVI_DEFER_STATEMENT
void RaviCodeGenerator::emit_DEFER(RaviFunctionDef *def, int A, int pc) {
emit_debug_trace(def, OP_RAVI_DEFER, pc);
emit_load_base(def);
llvm::Value *ra = emit_gep_register(def, A);
CreateCall2(def->builder, def->raviV_op_deferF, def->L, ra);
}
+#endif
}
\ No newline at end of file
diff --git a/src/ravi_llvmcodegen.cpp b/src/ravi_llvmcodegen.cpp
index f8661d2..81bac0e 100644
--- a/src/ravi_llvmcodegen.cpp
+++ b/src/ravi_llvmcodegen.cpp
@@ -1204,10 +1204,11 @@ void RaviCodeGenerator::emit_extern_declarations(RaviFunctionDef *def) {
def->raviV_op_totypeF = def->raviF->addExternFunction(
def->types->raviV_op_totypeT, reinterpret_cast(&raviV_op_totype),
"raviV_op_totype");
+#ifdef RAVI_DEFER_STATEMENT
def->raviV_op_deferF = def->raviF->addExternFunction(
def->types->raviV_op_deferT, reinterpret_cast(&raviV_op_defer),
"raviV_op_defer");
-
+#endif
#if 0
// DEBUG routines
def->ravi_dump_valueF = def->raviF->addExternFunction(
@@ -1337,7 +1338,11 @@ llvm::Value *RaviCodeGenerator::emit_gep_upval_v(RaviFunctionDef *def,
// Get &upval->value -> result is TValue *
llvm::Value *RaviCodeGenerator::emit_gep_upval_value(
RaviFunctionDef *def, llvm::Instruction *pupval) {
+#ifdef RAVI_DEFER_STATEMENT
return emit_gep(def, "value", pupval, 0, 3);
+#else
+ return emit_gep(def, "value", pupval, 0, 2);
+#endif
}
// Alternative code generator uses dmrC based C front-end
@@ -2022,9 +2027,11 @@ bool RaviCodeGenerator::compile(lua_State *L, Proto *p,
int B = GETARG_B(i);
emit_UNM(def, A, B, pc);
} break;
+#ifdef RAVI_DEFER_STATEMENT
case OP_RAVI_DEFER: {
emit_DEFER(def, A, pc);
} break;
+#endif
default: {
fprintf(stderr, "Unexpected bytecode %d\n", op);
abort();
diff --git a/src/ravi_llvmcomp.cpp b/src/ravi_llvmcomp.cpp
index 8d5e0de..e613989 100644
--- a/src/ravi_llvmcomp.cpp
+++ b/src/ravi_llvmcomp.cpp
@@ -131,10 +131,14 @@ void RaviCodeGenerator::emit_EQ(RaviFunctionDef *def, int A, int B, int C,
// base + a - 1
llvm::Value *val = emit_gep_register(def, jA - 1);
+#ifdef RAVI_DEFER_STATEMENT
if (!traced)
emit_update_savedpc(def, pc);
// Call luaF_close
CreateCall3(def->builder, def->luaF_closeF, def->L, val, def->types->kInt[LUA_OK]);
+#else
+ CreateCall2(def->builder, def->luaF_closeF, def->L, val);
+#endif
}
// Do the jump
def->builder->CreateBr(def->jmp_targets[j].jmp1);
@@ -238,10 +242,14 @@ void RaviCodeGenerator::emit_TEST(RaviFunctionDef *def, int A, int B, int C,
// base + a - 1
llvm::Value *val = emit_gep_register(def, jA - 1);
+#ifdef RAVI_DEFER_STATEMENT
if (!traced)
emit_update_savedpc(def, pc);
// Call luaF_close
CreateCall3(def->builder, def->luaF_closeF, def->L, val, def->types->kInt[LUA_OK]);
+#else
+ CreateCall2(def->builder, def->luaF_closeF, def->L, val);
+#endif
}
// Do the jump
def->builder->CreateBr(def->jmp_targets[j].jmp1);
@@ -311,10 +319,14 @@ void RaviCodeGenerator::emit_TESTSET(RaviFunctionDef *def, int A, int B, int C,
// base + a - 1
llvm::Value *val = emit_gep_register(def, jA - 1);
+#ifdef RAVI_DEFER_STATEMENT
if (!traced)
emit_update_savedpc(def, pc);
// Call luaF_close
CreateCall3(def->builder, def->luaF_closeF, def->L, val, def->types->kInt[LUA_OK]);
+#else
+ CreateCall2(def->builder, def->luaF_closeF, def->L, val);
+#endif
}
// Do the jump
def->builder->CreateBr(def->jmp_targets[j].jmp1);
diff --git a/src/ravi_llvmreturn.cpp b/src/ravi_llvmreturn.cpp
index d33d760..847809d 100644
--- a/src/ravi_llvmreturn.cpp
+++ b/src/ravi_llvmreturn.cpp
@@ -56,6 +56,14 @@ void RaviCodeGenerator::emit_RETURN(RaviFunctionDef *def, int A, int B,
bool traced = emit_debug_trace(def, OP_RETURN, pc);
+#ifndef RAVI_DEFER_STATEMENT
+ // Load pointer to base
+ emit_load_base(def);
+
+ // Get pointer to register A
+ llvm::Value *ra_ptr = emit_gep_register(def, A);
+#endif
+
// if (cl->p->sizep > 0) luaF_close(L, base);
// Get pointer to Proto->sizep
llvm::Instruction *psize = emit_load_proto_sizep(def);
@@ -70,22 +78,28 @@ void RaviCodeGenerator::emit_RETURN(RaviFunctionDef *def, int A, int B,
def->builder->CreateCondBr(psize_gt_0, then_block, else_block);
def->builder->SetInsertPoint(then_block);
+#ifdef RAVI_DEFER_STATEMENT
// Load pointer to base
emit_load_base(def);
// Get pointer to register A
llvm::Value *ra_ptr = emit_gep_register(def, A);
if (!traced)
emit_update_savedpc(def, pc);
+#endif
// Call luaF_close
+#ifdef RAVI_DEFER_STATEMENT
CreateCall3(def->builder, def->luaF_closeF, def->L, def->base_ptr, def->types->kInt[LUA_OK]);
+#else
+ CreateCall2(def->builder, def->luaF_closeF, def->L, def->base_ptr);
+#endif
def->builder->CreateBr(else_block);
def->f->getBasicBlockList().push_back(else_block);
def->builder->SetInsertPoint(else_block);
-
+#ifdef RAVI_DEFER_STATEMENT
emit_load_base(def); // As luaF_close() may have changed the stack
ra_ptr = emit_gep_register(def, A); // load RA
-
+#endif
//* b = luaD_poscall(L, ra, (b != 0 ? b - 1 : L->top - ra));
llvm::Value *nresults = NULL;
if (B != 0)
diff --git a/src/ravi_llvmtypes.cpp b/src/ravi_llvmtypes.cpp
index b96c832..e6ffc8b 100644
--- a/src/ravi_llvmtypes.cpp
+++ b/src/ravi_llvmtypes.cpp
@@ -694,8 +694,12 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
// struct UpVal {
// struct TValue *v; /* points to stack or to its own value */
+#ifdef RAVI_DEFER_STATEMENT
// unsigned int refcount; /* reference counter */
// unsigned int flags; /* Used to mark deferred values */
+#else
+ // unsigned long long refcount; /* reference counter */
+#endif
// union {
// struct { /* (when open) */
// struct UpVal *next; /* linked list */
@@ -706,8 +710,12 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
//};
elements.clear();
elements.push_back(pTValueT);
+#ifdef RAVI_DEFER_STATEMENT
elements.push_back(C_intT);
elements.push_back(C_intT);
+#else
+ elements.push_back(C_size_t);
+#endif
elements.push_back(TValueT);
UpValT->setBody(elements);
@@ -747,22 +755,31 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
elements.push_back(plua_StateT);
luaV_executeT = llvm::FunctionType::get(C_intT, elements, false);
+#ifdef RAVI_DEFER_STATEMENT
// int luaF_close (lua_State *L, StkId level, int status)
+#else
+ // void luaF_close (lua_State *L, StkId level)
+#endif
elements.clear();
elements.push_back(plua_StateT);
elements.push_back(StkIdT);
+#ifdef RAVI_DEFER_STATEMENT
elements.push_back(C_intT);
luaF_closeT =
llvm::FunctionType::get(C_intT, elements, false);
+#else
+ luaF_closeT =
+ llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false);
+#endif
// int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2)
elements.clear();
elements.push_back(plua_StateT);
elements.push_back(pTValueT);
-
+#ifdef RAVI_DEFER_STATEMENT
// void raviV_op_defer(lua_State *L, TValue *ra);
raviV_op_deferT = llvm::FunctionType::get(llvm::Type::getVoidTy(context), elements, false);
-
+#endif
elements.push_back(pTValueT);
luaV_equalobjT = llvm::FunctionType::get(C_intT, elements, false);
@@ -1266,8 +1283,12 @@ LuaLLVMTypes::LuaLLVMTypes(llvm::LLVMContext &context) : mdbuilder(context) {
nodes.clear();
nodes.push_back(std::pair(tbaa_pointerT, 0));
+#ifdef RAVI_DEFER_STATEMENT
nodes.push_back(std::pair(tbaa_intT, 4));
nodes.push_back(std::pair(tbaa_intT, 4));
+#else
+ nodes.push_back(std::pair(tbaa_longlongT, 8));
+#endif
nodes.push_back(std::pair(tbaa_TValueT, 16));
tbaa_UpValT = mdbuilder.createTBAAStructTypeNode("UpVal", nodes);
tbaa_UpVal_vT =
diff --git a/src/ravi_mirjit.c b/src/ravi_mirjit.c
index 74c3afe..08ab313 100644
--- a/src/ravi_mirjit.c
+++ b/src/ravi_mirjit.c
@@ -111,7 +111,9 @@ static LuaFunc Lua_functions[] = {
{ "raviV_settable_sskey", raviV_settable_sskey },
{ "raviV_gettable_i", raviV_gettable_i },
{ "raviV_settable_i", raviV_settable_i },
+#ifdef RAVI_DEFER_STATEMENT
{ "raviV_op_defer", raviV_op_defer },
+#endif
{ "raviV_op_bnot", raviV_op_bnot},
{ "lua_absindex", lua_absindex },
@@ -404,6 +406,7 @@ void *MIR_compile_C_module(
}
MIR_load_module (ctx, module);
MIR_gen_init (ctx);
+ MIR_gen_set_optimize_level(ctx, 3);
MIR_link (ctx, MIR_set_gen_interface, Import_resolver_func);
fun_addr = MIR_gen (ctx, main_func);
MIR_gen_finish (ctx);
diff --git a/src/ravi_omrjit.c b/src/ravi_omrjit.c
index 12ef842..8ae9166 100644
--- a/src/ravi_omrjit.c
+++ b/src/ravi_omrjit.c
@@ -319,8 +319,10 @@ int raviV_initjit(struct lua_State *L) {
register_builtin_arg2(jit->jit, "lua_setmetatable", lua_setmetatable, JIT_Int32, JIT_Address, JIT_Int32);
//LUA_API void (lua_setuservalue)(lua_State *L, int idx);
register_builtin_arg2(jit->jit, "lua_setuservalue", lua_setuservalue, JIT_NoType, JIT_Address, JIT_Int32);
+#ifdef RAVI_DEFER_STATEMENT
//LUA_API void raviV_op_defer(lua_State *L, TValue *ra);
register_builtin_arg2(jit->jit, "raviV_op_defer", raviV_op_defer, JIT_NoType, JIT_Address, JIT_Address);
+#endif
//LUAI_FUNC lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y);
register_builtin_arg2(jit->jit, "luaV_shiftl", luaV_shiftl, JIT_Int64, JIT_Int64, JIT_Int64);
// extern void raviV_op_bnot(lua_State *L, TValue *ra, TValue *rb);