Merge branch 'ravi-compiler' of https://github.com/dibyendumajumdar/ravi into ravi-compiler

ravi-compiler
Dibyendu Majumdar 4 years ago
commit b1f36a56e1

@ -130,18 +130,30 @@ else ()
PROPERTY INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/mir;${CMAKE_SOURCE_DIR}/mir/c2mir")
set_property(SOURCE ${MIR_SRCS} ${C2MIR_SRCS} ${MIR_JIT_SRCS}
APPEND
PROPERTY COMPILE_DEFINITIONS "MIR_NO_IO=0;MIR_NO_SCAN=1")
PROPERTY COMPILE_DEFINITIONS "MIR_NO_IO=0;MIR_NO_SCAN=1;MIR_NO_INTERP=1")
if ($ENV{CLION_IDE})
# CLion seems unable to handle include paths set on sources
include_directories("${CMAKE_SOURCE_DIR}/mir;${CMAKE_SOURCE_DIR}/mir/c2mir")
endif ()
else()
set(JIT_SRCS ${NO_JIT_SRCS})
endif ()
endif ()
if (RAVICOMP)
if (RAVICOMP AND MIR_JIT)
# Need MIR_JIT for the compiler add-on
find_package(RaviComp REQUIRED)
set(ADDON_SRCS ${RAVICOMP_SRCS})
set_property(SOURCE ${RAVICOMP_SRCS}
APPEND
PROPERTY INCLUDE_DIRECTORIES ${RAVICOMP_INCLUDE_DIRS})
set_property(SOURCE ${RAVICOMP_SRCS}
APPEND
PROPERTY INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/mir;${CMAKE_SOURCE_DIR}/mir/c2mir")
if ($ENV{CLION_IDE})
# CLion seems unable to handle include paths set on sources
include_directories(${RAVICOMP_INCLUDE_DIRS})
endif ()
endif()
# IDE stuff

@ -10,5 +10,6 @@ find_library(RAVICOMP_LIBRARIES
PATHS
c:/Software/ravicomp/lib
~/Software/ravicomp/lib
~/Software/ravicomp/lib64
)

@ -563,7 +563,39 @@ typedef struct Proto {
#define getfcf_tag(typecode) (typecode >> 8)
/*
** Upvalues for Lua closures
* Upvalues for Lua closures. The UpVal structure mediates the connection between a
* closure and a variable. An upvalue may be two states: open or closed.
* When the upvalue is created, it is open, and its pointer points to the corresponding
* variable in the Lua stack. That is, an open upvalue is one that's v is pointing to
* the stack. When the upvalue is closed, the value is moved from the stack to the
* UpVal structure itself (value) and the pointer v is corrected to point internally.
*
* At any point a variable can have at most one upvalue pointing to it, and all
* closures that reference the upvalue access this shared upvalue. Lua keeps a
* linked list of open upvalues of a stack. This list is ordered by the level of the
* corresponding variables on the stack. When Lua needs an upvalue for a local variable
* it traverse this linked list. If it finds an upvalue for the variable it reuses it
* thus ensuring that closures share the same upvalue.
*
* Because the list is ordered and there is at most one upvalue for each variable
* the maximum number of elements to be traversed when looking for a variable in this
* list can be known at compile time. This maximum is the number of variables that escape
* to inner closures and that are declared between the closure and the external variable.
* For instance
*
* function foo()
* local a, b, c, d
* local f1 = function() return d + b end
* local f2 = function() return f() + a end
*
* When Lua instantiates f2 it will traverse exactly three upvalues before realizing
* that a has no upvalue yet: f1, d, and b in that order.
*
* When a variable goes out of scope, its corrsponding update (if there is one) must
* be closed. The list of open upvalues is also used for this task. When compiling a
* block that contains variables that escape, a "close" operation must be emitted (in Ravi
* there is no explicit close op, the JMP instruction takes care of it) to close all
* upvalues up to this level, at the end of the block.
*/
typedef struct UpVal {
@ -598,7 +630,7 @@ typedef struct CClosure {
typedef struct LClosure {
ClosureHeader;
struct Proto *p;
UpVal *upvals[1]; /* list of upvalues */
UpVal *upvals[1]; /* list of upvalues - each upvalue represents one non-local variable used by the closure */
} LClosure;

@ -44,6 +44,17 @@ struct ravi_State {
struct c2mir_options options; /* MIR options */
};
extern void mir_prepare(MIR_context_t ctx, int optlevel);
extern void mir_cleanup(MIR_context_t ctx);
extern MIR_item_t mir_find_function(MIR_module_t module, const char *func_name);
extern MIR_module_t mir_compile_C_module(
struct c2mir_options *options,
MIR_context_t ctx,
const char *inputbuffer, /* Code to be compiled */
const char *source_name /* Name of the function, must be unique */
);
extern void *mir_get_func(MIR_context_t ctx, MIR_module_t module, const char *func_name);
#ifdef __cplusplus
};
#endif

@ -2089,6 +2089,7 @@ static void define (c2m_ctx_t c2m_ctx) {
error (c2m_ctx, id->pos, "macro definition of %s", name);
} else {
new_macro (c2m_ctx, id, params, repl);
params = NULL;
}
} else if (m->replacement == NULL) {
error (c2m_ctx, id->pos, "standard macro %s redefinition", name);
@ -2097,6 +2098,8 @@ static void define (c2m_ctx_t c2m_ctx) {
error (c2m_ctx, id->pos, "different macro redefinition of %s", name);
VARR_DESTROY (token_t, repl);
}
if (params != NULL)
VARR_DESTROY(token_t, params);
}
#ifdef C2MIR_PREPRO_DEBUG
@ -5071,9 +5074,22 @@ static void symbol_insert (c2m_ctx_t c2m_ctx, enum symbol_mode mode, node_t id,
symbol.def_node = def_node;
symbol.aux_node = aux_node;
VARR_CREATE (node_t, symbol.defs, 4);
VARR_PUSH (node_t, symbol.defs, def_node);
HTAB_DO (symbol_t, symbol_tab, symbol, HTAB_INSERT, el);
}
static void symbol_def_replace (c2m_ctx_t c2m_ctx, symbol_t symbol, node_t def_node) {
symbol_t el;
VARR (node_t) * defs;
VARR_CREATE (node_t, defs, 4);
for (size_t i = 0; i < VARR_LENGTH (node_t, symbol.defs); i++)
VARR_PUSH (node_t, defs, VARR_GET (node_t, symbol.defs, i));
symbol.defs = defs;
symbol.def_node = def_node;
HTAB_DO (symbol_t, symbol_tab, symbol, HTAB_REPLACE, el);
}
static void symbol_finish (c2m_ctx_t c2m_ctx) {
if (symbol_tab != NULL) HTAB_DESTROY (symbol_t, symbol_tab);
}
@ -5284,6 +5300,10 @@ struct decl {
int bit_offset, width; /* for bitfields, -1 bit_offset for non bitfields. */
mir_size_t offset; /* var offset in frame or bss */
node_t scope; /* declaration scope */
/* The next 2 members are used only for param decls. The 1st member is number of the start MIR
func arg. The 2nd one is number or MIR func args used to pass param value, it is positive only
for aggregates passed by value. */
uint32_t param_args_start, param_args_num;
struct decl_spec decl_spec;
/* Unnamed member if this scope is anon struct/union for the member,
NULL otherwise: */
@ -5938,6 +5958,9 @@ static void def_symbol (c2m_ctx_t c2m_ctx, enum symbol_mode mode, node_t id, nod
|| (decl_spec.linkage == N_STATIC && linkage == N_EXTERN))
warning (c2m_ctx, id->pos, "%s defined with external and internal linkage", id->u.s.s);
VARR_PUSH (node_t, sym.defs, def_node);
if (!incomplete_type_p (c2m_ctx, decl_spec.type)
&& incomplete_type_p (c2m_ctx, tab_decl_spec.type))
symbol_def_replace (c2m_ctx, sym, def_node);
}
static void make_type_complete (c2m_ctx_t c2m_ctx, struct type *type) {
@ -7128,6 +7151,7 @@ static void init_decl (c2m_ctx_t c2m_ctx, decl_t decl) {
decl->reg_p = decl->used_p = FALSE;
decl->offset = 0;
decl->bit_offset = -1;
decl->param_args_start = decl->param_args_num = 0;
decl->scope = curr_scope;
decl->containing_unnamed_anon_struct_union_member = curr_unnamed_anon_struct_union_member;
decl->item = NULL;
@ -8198,12 +8222,7 @@ static void check (c2m_ctx_t c2m_ctx, node_t r, node_t context) {
*e->type = *t2;
} else if ((t2->mode == TM_PTR && null_const_p (e3, t3))
|| (t3->mode == TM_PTR && null_const_p (e2, t2))) {
e->type->mode = TM_PTR;
e->type->pos_node = r;
e->type->u.ptr_type = create_type (c2m_ctx, NULL);
e->type->u.ptr_type->pos_node = r;
e->type->u.ptr_type->mode = TM_BASIC;
e->type->u.ptr_type->u.basic_type = TP_VOID;
e->type = null_const_p (e3, t2) ? t3 : t2;
} else if (t2->mode != TM_PTR && t3->mode != TM_PTR) {
error (c2m_ctx, r->pos, "incompatible types in true and false parts of cond-expression");
break;
@ -9087,6 +9106,7 @@ static void context_finish (MIR_context_t ctx) {
static const char *FP_NAME = "fp";
static const char *RET_ADDR_NAME = "Ret_Addr";
static const char *RET_VAL_NAME = "Ret_Val";
/* New attribute for non-empty label LIST is a MIR label. */
@ -9117,8 +9137,8 @@ struct reg_var {
typedef struct reg_var reg_var_t;
DEF_HTAB (reg_var_t);
static VARR (MIR_var_t) * vars;
DEF_VARR (int);
DEF_VARR (MIR_type_t);
struct init_el {
mir_size_t num, offset;
@ -9139,7 +9159,11 @@ struct gen_ctx {
HTAB (reg_var_t) * reg_var_tab;
int reg_free_mark;
MIR_label_t continue_label, break_label;
VARR (node_t) * mem_params;
struct {
int res_ref_p; /* flag of returning an aggregate by reference */
VARR (MIR_type_t) * ret_types;
VARR (MIR_var_t) * arg_vars;
} proto_info;
VARR (init_el_t) * init_els;
MIR_item_t memset_proto, memset_item;
MIR_item_t memcpy_proto, memcpy_item;
@ -9156,7 +9180,7 @@ struct gen_ctx {
#define reg_free_mark c2m_ctx->gen_ctx->reg_free_mark
#define continue_label c2m_ctx->gen_ctx->continue_label
#define break_label c2m_ctx->gen_ctx->break_label
#define mem_params c2m_ctx->gen_ctx->mem_params
#define proto_info c2m_ctx->gen_ctx->proto_info
#define init_els c2m_ctx->gen_ctx->init_els
#define memset_proto c2m_ctx->gen_ctx->memset_proto
#define memset_item c2m_ctx->gen_ctx->memset_item
@ -9593,14 +9617,26 @@ static op_t promote (MIR_context_t ctx, op_t op, MIR_type_t t, int new_op_p) {
return cast (ctx, op, t, new_op_p);
}
static op_t mem_to_address (MIR_context_t ctx, op_t mem) {
static op_t mem_to_address (MIR_context_t ctx, op_t mem, int reg_p) {
op_t temp;
if (mem.mir_op.mode == MIR_OP_STR) return mem;
if (mem.mir_op.mode == MIR_OP_STR) {
if (!reg_p) return mem;
temp = get_new_temp (ctx, MIR_T_I64);
emit2 (ctx, MIR_MOV, temp.mir_op, mem.mir_op);
temp.mir_op.value_mode = MIR_OP_INT;
return temp;
}
assert (mem.mir_op.mode == MIR_OP_MEM);
if (mem.mir_op.u.mem.base == 0 && mem.mir_op.u.mem.index == 0) {
mem.mir_op.mode = MIR_OP_INT;
mem.mir_op.u.i = mem.mir_op.u.mem.disp;
if (!reg_p) {
mem.mir_op.mode = MIR_OP_INT;
mem.mir_op.u.i = mem.mir_op.u.mem.disp;
} else {
temp = get_new_temp (ctx, MIR_T_I64);
emit2 (ctx, MIR_MOV, temp.mir_op, MIR_new_int_op (ctx, mem.mir_op.u.mem.disp));
mem = temp;
}
} else if (mem.mir_op.u.mem.index == 0 && mem.mir_op.u.mem.disp == 0) {
mem.mir_op.mode = MIR_OP_REG;
mem.mir_op.u.reg = mem.mir_op.u.mem.base;
@ -9633,7 +9669,7 @@ static op_t force_val (MIR_context_t ctx, op_t op, int arr_p) {
if (arr_p && op.mir_op.mode == MIR_OP_MEM) {
/* an array -- use a pointer: */
return mem_to_address (ctx, op);
return mem_to_address (ctx, op, FALSE);
}
if (op.decl == NULL || op.decl->bit_offset < 0) return op;
c2m_ctx = *c2m_ctx_loc (ctx);
@ -9914,7 +9950,7 @@ static void block_move (MIR_context_t ctx, op_t var, op_t val, mir_size_t size)
if (MIR_op_eq_p (ctx, var.mir_op, val.mir_op)) return;
if (size > 5) {
var = mem_to_address (ctx, var);
var = mem_to_address (ctx, var, TRUE);
assert (var.mir_op.mode == MIR_OP_REG);
gen_memcpy (ctx, 0, var.mir_op.u.reg, val, size);
} else {
@ -9975,54 +10011,98 @@ static const char *get_func_static_var_name (MIR_context_t ctx, const char *suff
return get_func_var_name (ctx, prefix, suffix);
}
static const char *get_param_name (MIR_context_t ctx, MIR_type_t *type, struct type *param_type,
const char *name) {
*type = (param_type->mode == TM_STRUCT || param_type->mode == TM_UNION
? MIR_POINTER_TYPE
: get_mir_type (ctx, param_type));
return get_reg_var_name (ctx, promote_mir_int_type (*type), name, 0);
static const char *get_param_name (MIR_context_t ctx, struct type *param_type, const char *name) {
MIR_type_t type = (param_type->mode == TM_STRUCT || param_type->mode == TM_UNION
? MIR_POINTER_TYPE
: get_mir_type (ctx, param_type));
return get_reg_var_name (ctx, promote_mir_int_type (type), name, 0);
}
static void collect_args_and_func_types (MIR_context_t ctx, struct func_type *func_type,
MIR_type_t *ret_type) {
#if 0 && defined(__x86_64__)
#include "x86_64/cx86_64-ABI-code.c"
#endif
#ifndef ATYPICAL_CALL_ABI
typedef int target_arg_info_t;
static void target_init_arg_vars (MIR_context_t ctx, target_arg_info_t *arg_info) {}
static void target_add_res (MIR_context_t ctx, struct func_type *func_type,
target_arg_info_t *arg_info) {
MIR_var_t var;
c2m_ctx_t c2m_ctx = *c2m_ctx_loc (ctx);
node_t declarator, id, first_param, p;
struct type *param_type;
proto_info.res_ref_p = FALSE;
if (void_type_p (func_type->ret_type)) return;
if (func_type->ret_type->mode != TM_STRUCT && func_type->ret_type->mode != TM_UNION) {
VARR_PUSH (MIR_type_t, proto_info.ret_types, get_mir_type (ctx, func_type->ret_type));
return;
}
var.name = RET_ADDR_NAME;
var.type = MIR_POINTER_TYPE;
VARR_PUSH (MIR_var_t, proto_info.arg_vars, var);
proto_info.res_ref_p = TRUE;
}
static void target_add_param (MIR_context_t ctx, const char *name, struct type *param_type,
decl_t param_decl, target_arg_info_t *arg_info) {
MIR_var_t var;
MIR_type_t type;
c2m_ctx_t c2m_ctx = *c2m_ctx_loc (ctx);
first_param = NL_HEAD (func_type->param_list->ops);
VARR_TRUNC (MIR_var_t, vars, 0);
VARR_TRUNC (node_t, mem_params, 0);
if (func_type->ret_type->mode == TM_STRUCT || func_type->ret_type->mode == TM_UNION) {
var.name = RET_ADDR_NAME;
var.type = MIR_POINTER_TYPE;
VARR_PUSH (MIR_var_t, vars, var);
if (param_decl != NULL) {
param_decl->param_args_num = 0;
param_decl->param_args_start = VARR_LENGTH (MIR_var_t, proto_info.arg_vars);
}
type = (param_type->mode == TM_STRUCT || param_type->mode == TM_UNION
#ifdef BLK_PARAM
? MIR_T_BLK
#else
? MIR_POINTER_TYPE
#endif
: get_mir_type (ctx, param_type));
var.name = name;
var.type = type;
#ifdef BLK_PARAM
if (type == MIR_T_BLK) var.size = type_size (c2m_ctx, param_type);
#endif
VARR_PUSH (MIR_var_t, proto_info.arg_vars, var);
}
#endif
static void collect_args_and_func_types (MIR_context_t ctx, struct func_type *func_type) {
c2m_ctx_t c2m_ctx = *c2m_ctx_loc (ctx);
node_t declarator, id, first_param, p;
struct type *param_type;
decl_t param_decl;
const char *name;
target_arg_info_t arg_info;
first_param = NL_HEAD (func_type->param_list->ops);
VARR_TRUNC (MIR_var_t, proto_info.arg_vars, 0);
VARR_TRUNC (MIR_type_t, proto_info.ret_types, 0);
proto_info.res_ref_p = FALSE;
target_init_arg_vars (ctx, &arg_info);
set_type_layout (c2m_ctx, func_type->ret_type);
target_add_res (ctx, func_type, &arg_info);
if (first_param != NULL && !void_param_p (first_param)) {
for (p = first_param; p != NULL; p = NL_NEXT (p)) {
if (p->code == N_TYPE) {
var.name = "p";
name = "p";
param_type = ((struct decl_spec *) p->attr)->type;
type = (param_type->mode == TM_STRUCT || param_type->mode == TM_UNION
? MIR_POINTER_TYPE
: get_mir_type (ctx, param_type));
param_decl = NULL;
} else {
declarator = NL_EL (p->ops, 1);
assert (p->code == N_SPEC_DECL && declarator != NULL && declarator->code == N_DECL);
id = NL_HEAD (declarator->ops);
param_type = ((decl_t) p->attr)->decl_spec.type;
var.name = get_param_name (ctx, &type, param_type, id->u.s.s);
if (param_type->mode == TM_STRUCT || param_type->mode == TM_UNION
|| !((decl_t) p->attr)->reg_p)
VARR_PUSH (node_t, mem_params, p);
param_decl = p->attr;
param_type = param_decl->decl_spec.type;
name = get_param_name (ctx, param_type, id->u.s.s);
}
var.type = type;
VARR_PUSH (MIR_var_t, vars, var);
target_add_param (ctx, name, param_type, param_decl, &arg_info);
}
}
set_type_layout (c2m_ctx, func_type->ret_type);
*ret_type = get_mir_type (ctx, func_type->ret_type);
}
static mir_size_t get_object_path_offset (c2m_ctx_t c2m_ctx) {
@ -10268,7 +10348,7 @@ static void gen_memcpy (MIR_context_t ctx, MIR_disp_t disp, MIR_reg_t base, op_t
emit3 (ctx, MIR_ADD, treg_op, MIR_new_reg_op (ctx, base), MIR_new_int_op (ctx, disp));
}
args[3] = treg_op;
args[4] = mem_to_address (ctx, val).mir_op;
args[4] = mem_to_address (ctx, val, FALSE).mir_op;
args[5] = MIR_new_uint_op (ctx, len);
emit_insn (ctx, MIR_new_insn_arr (ctx, MIR_CALL, 6 /* args + proto + func + res */, args));
}
@ -11008,10 +11088,11 @@ static op_t gen (MIR_context_t ctx, node_t r, MIR_label_t true_label, MIR_label_
if (!void_p) {
if (t != MIR_T_UNDEF) {
res = get_new_temp (ctx, t);
op1 = cast (ctx, op1, t, FALSE);
emit2 (ctx, tp_mov (t), res.mir_op, op1.mir_op);
} else if (desirable_dest == NULL) {
res = get_new_temp (ctx, MIR_T_I64);
addr = mem_to_address (ctx, op1);
addr = mem_to_address (ctx, op1, FALSE);
emit2 (ctx, MIR_MOV, res.mir_op, addr.mir_op);
} else {
block_move (ctx, *desirable_dest, op1, size);
@ -11023,9 +11104,10 @@ static op_t gen (MIR_context_t ctx, node_t r, MIR_label_t true_label, MIR_label_
op1 = gen (ctx, false_expr, NULL, NULL, !void_p && t != MIR_T_UNDEF, NULL);
if (!void_p) {
if (t != MIR_T_UNDEF) {
op1 = cast (ctx, op1, t, FALSE);
emit2 (ctx, tp_mov (t), res.mir_op, op1.mir_op);
} else if (desirable_dest == NULL) {
addr = mem_to_address (ctx, op1);
addr = mem_to_address (ctx, op1, FALSE);
emit2 (ctx, MIR_MOV, res.mir_op, addr.mir_op);
res = new_op (NULL, MIR_new_mem_op (ctx, MIR_T_I8, 0, res.mir_op.u.reg, 0, 1));
} else {
@ -11138,13 +11220,25 @@ static op_t gen (MIR_context_t ctx, node_t r, MIR_label_t true_label, MIR_label_
if (va_arg_p) {
op1 = get_new_temp (ctx, MIR_T_I64);
op2 = gen (ctx, NL_HEAD (args->ops), NULL, NULL, TRUE, NULL);
MIR_append_insn (ctx, curr_func,
MIR_new_insn (ctx, MIR_VA_ARG, op1.mir_op, op2.mir_op,
MIR_new_mem_op (ctx, t, 0, 0, 0, 1)));
op2 = get_new_temp (ctx, t);
MIR_append_insn (ctx, curr_func,
MIR_new_insn (ctx, tp_mov (t), op2.mir_op,
MIR_new_mem_op (ctx, t, 0, op1.mir_op.u.reg, 0, 1)));
#ifdef BLK_PARAM
if (type->mode == TM_STRUCT || type->mode == TM_UNION) {
MIR_append_insn (ctx, curr_func,
MIR_new_insn (ctx, MIR_VA_STACK_ARG, op1.mir_op, op2.mir_op,
MIR_new_int_op (ctx, type_size (c2m_ctx, type))));
op2 = op1;
} else
#endif
{
if (op2.mir_op.mode == MIR_OP_MEM && op2.mir_op.u.mem.type == MIR_T_UNDEF)
op2 = mem_to_address (ctx, op2, FALSE);
MIR_append_insn (ctx, curr_func,
MIR_new_insn (ctx, MIR_VA_ARG, op1.mir_op, op2.mir_op,
MIR_new_mem_op (ctx, t, 0, 0, 0, 1)));
op2 = get_new_temp (ctx, t);
MIR_append_insn (ctx, curr_func,
MIR_new_insn (ctx, tp_mov (t), op2.mir_op,
MIR_new_mem_op (ctx, t, 0, op1.mir_op.u.reg, 0, 1)));
}
if (res.mir_op.mode == MIR_OP_REG) {
res = op2;
} else {
@ -11153,6 +11247,8 @@ static op_t gen (MIR_context_t ctx, node_t r, MIR_label_t true_label, MIR_label_
}
} else if (va_start_p) {
op1 = gen (ctx, NL_HEAD (args->ops), NULL, NULL, TRUE, NULL);
if (op1.mir_op.mode == MIR_OP_MEM && op1.mir_op.u.mem.type == MIR_T_UNDEF)
op1 = mem_to_address (ctx, op1, FALSE);
MIR_append_insn (ctx, curr_func, MIR_new_insn (ctx, MIR_VA_START, op1.mir_op));
} else if (alloca_p) {
res = get_new_temp (ctx, t);
@ -11169,7 +11265,12 @@ static op_t gen (MIR_context_t ctx, node_t r, MIR_label_t true_label, MIR_label_
|| func_type->u.func_type->dots_p);
if (struct_p) { /* pass an adress of struct/union: */
assert (op2.mir_op.mode == MIR_OP_MEM);
op2 = mem_to_address (ctx, op2);
op2 = mem_to_address (ctx, op2, TRUE);
#ifdef BLK_PARAM
assert (op2.mir_op.mode == MIR_OP_REG);
op2 = new_op (NULL /*???*/, MIR_new_mem_op (ctx, MIR_T_BLK, type_size (c2m_ctx, e->type),
op2.mir_op.u.reg, 0, 1));
#endif
} else if (param != NULL) {
assert (param->code == N_SPEC_DECL || param->code == N_TYPE);
decl_spec = get_param_decl_spec (param);
@ -11303,7 +11404,7 @@ static op_t gen (MIR_context_t ctx, node_t r, MIR_label_t true_label, MIR_label_
struct node_scope *ns = stmt->attr;
decl_t param_decl, decl = r->attr;
struct type *decl_type = decl->decl_spec.type;
node_t param, param_declarator, param_id;
node_t first_param, param, param_declarator, param_id;
struct type *param_type;
MIR_insn_t insn;
MIR_type_t res_type, param_mir_type;
@ -11316,13 +11417,17 @@ static op_t gen (MIR_context_t ctx, node_t r, MIR_label_t true_label, MIR_label_
reg_free_mark = 0;
curr_func_def = r;
curr_call_arg_area_offset = 0;
collect_args_and_func_types (ctx, decl_type->u.func_type, &res_type);
curr_func
= ((decl_type->u.func_type->dots_p
? MIR_new_vararg_func_arr
: MIR_new_func_arr) (ctx, NL_HEAD (declarator->ops)->u.s.s,
res_type == MIR_T_UNDEF ? 0 : 1, &res_type,
VARR_LENGTH (MIR_var_t, vars), VARR_ADDR (MIR_var_t, vars)));
collect_args_and_func_types (ctx, decl_type->u.func_type);
res_type = (VARR_LENGTH (MIR_type_t, proto_info.ret_types) == 0
? MIR_T_UNDEF
: VARR_GET (MIR_type_t, proto_info.ret_types, 0));
curr_func = ((decl_type->u.func_type->dots_p
? MIR_new_vararg_func_arr
: MIR_new_func_arr) (ctx, NL_HEAD (declarator->ops)->u.s.s,
VARR_LENGTH (MIR_type_t, proto_info.ret_types),
VARR_ADDR (MIR_type_t, proto_info.ret_types),
VARR_LENGTH (MIR_var_t, proto_info.arg_vars),
VARR_ADDR (MIR_var_t, proto_info.arg_vars)));
decl->item = curr_func;
if (ns->stack_var_p /* we can have empty struct only with size 0 and still need a frame: */
|| ns->size > 0) {
@ -11331,28 +11436,34 @@ static op_t gen (MIR_context_t ctx, node_t r, MIR_label_t true_label, MIR_label_
MIR_new_insn (ctx, MIR_ALLOCA, MIR_new_reg_op (ctx, fp_reg),
MIR_new_int_op (ctx, ns->size)));
}
for (size_t i = 0; i < VARR_LENGTH (MIR_var_t, vars); i++)
get_reg_var (ctx, MIR_T_UNDEF, VARR_GET (MIR_var_t, vars, i).name);
for (size_t i = 0; i < VARR_LENGTH (node_t, mem_params); i++) {
param = VARR_GET (node_t, mem_params, i);
param_declarator = NL_EL (param->ops, 1);
param_decl = param->attr;
assert (param_declarator != NULL && param_declarator->code == N_DECL);
param_id = NL_HEAD (param_declarator->ops);
param_type = param_decl->decl_spec.type;
name = get_param_name (ctx, &param_mir_type, param_type, param_id->u.s.s);
if (param_type->mode == TM_STRUCT || param_type->mode == TM_UNION) {
param_reg = get_reg_var (ctx, MIR_POINTER_TYPE, name).reg;
val = new_op (NULL, MIR_new_mem_op (ctx, MIR_T_UNDEF, 0, param_reg, 0, 1));
var = new_op (param_decl, MIR_new_mem_op (ctx, MIR_T_UNDEF, param_decl->offset,
for (size_t i = 0; i < VARR_LENGTH (MIR_var_t, proto_info.arg_vars); i++)
get_reg_var (ctx, MIR_T_UNDEF, VARR_GET (MIR_var_t, proto_info.arg_vars, i).name);
if ((first_param = NL_HEAD (decl_type->u.func_type->param_list->ops)) != NULL
&& !void_param_p (first_param)) {
for (param = first_param; param != NULL; param = NL_NEXT (param)) {
param_declarator = NL_EL (param->ops, 1);
assert (param_declarator != NULL && param_declarator->code == N_DECL);
param_decl = param->attr;
param_id = NL_HEAD (param_declarator->ops);
param_type = param_decl->decl_spec.type;
assert (!param_decl->reg_p
|| (param_type->mode != TM_STRUCT && param_type->mode != TM_UNION));
if (param_decl->reg_p) continue;
name = get_param_name (ctx, param_type, param_id->u.s.s);
if (param_type->mode == TM_STRUCT || param_type->mode == TM_UNION) {
param_reg = get_reg_var (ctx, MIR_POINTER_TYPE, name).reg;
val = new_op (NULL, MIR_new_mem_op (ctx, MIR_T_UNDEF, 0, param_reg, 0, 1));
var
= new_op (param_decl, MIR_new_mem_op (ctx, MIR_T_UNDEF, param_decl->offset,
MIR_reg (ctx, FP_NAME, curr_func->u.func), 0, 1));
block_move (ctx, var, val, type_size (c2m_ctx, param_type));
} else {
assert (!param_decl->reg_p);
emit2 (ctx, tp_mov (param_mir_type),
MIR_new_mem_op (ctx, param_mir_type, param_decl->offset,
MIR_reg (ctx, FP_NAME, curr_func->u.func), 0, 1),
MIR_new_reg_op (ctx, get_reg_var (ctx, MIR_T_UNDEF, name).reg));
block_move (ctx, var, val, type_size (c2m_ctx, param_type));
} else {
param_mir_type = get_mir_type (ctx, param_type);
emit2 (ctx, tp_mov (param_mir_type),
MIR_new_mem_op (ctx, param_mir_type, param_decl->offset,
MIR_reg (ctx, FP_NAME, curr_func->u.func), 0, 1),
MIR_new_reg_op (ctx, get_reg_var (ctx, MIR_T_UNDEF, name).reg));
}
}
}
gen (ctx, stmt, NULL, NULL, FALSE, NULL);
@ -11668,6 +11779,7 @@ static htab_hash_t proto_hash (MIR_item_t pi, void *arg) {
for (size_t i = 0; i < VARR_LENGTH (MIR_var_t, p->args); i++) {
h = mir_hash_step (h, args[i].type);
h = mir_hash_step (h, mir_hash (args[i].name, strlen (args[i].name), 24));
if (args[i].type == MIR_T_BLK) h = mir_hash_step (h, args[i].size);
}
return mir_hash_finish (h);
}
@ -11684,11 +11796,13 @@ static int proto_eq (MIR_item_t pi1, MIR_item_t pi2, void *arg) {
MIR_var_t *args1 = VARR_ADDR (MIR_var_t, p1->args), *args2 = VARR_ADDR (MIR_var_t, p2->args);
for (size_t i = 0; i < VARR_LENGTH (MIR_var_t, p1->args); i++)
if (args1[i].type != args2[i].type || strcmp (args1[i].name, args2[i].name) != 0) return FALSE;
if (args1[i].type != args2[i].type || strcmp (args1[i].name, args2[i].name) != 0
|| args1[i].type == MIR_T_BLK && args1[i].size != args2[i].size)
return FALSE;
return TRUE;
}
static MIR_item_t get_mir_proto (MIR_context_t ctx, int vararg_p, MIR_type_t ret_type,
static MIR_item_t get_mir_proto (MIR_context_t ctx, int vararg_p, VARR (MIR_type_t) * ret_types,
VARR (MIR_var_t) * vars) {
c2m_ctx_t c2m_ctx = *c2m_ctx_loc (ctx);
struct MIR_item pi, *el;
@ -11697,14 +11811,15 @@ static MIR_item_t get_mir_proto (MIR_context_t ctx, int vararg_p, MIR_type_t ret
pi.u.proto = &p;
p.vararg_p = vararg_p;
p.nres = ret_type == MIR_T_UNDEF ? 0 : 1;
p.res_types = &ret_type;
p.nres = VARR_LENGTH (MIR_type_t, proto_info.ret_types);
p.res_types = VARR_ADDR (MIR_type_t, proto_info.ret_types);
p.args = vars;
if (HTAB_DO (MIR_item_t, proto_tab, &pi, HTAB_FIND, el)) return el;
sprintf (buf, "proto%d", curr_mir_proto_num++);
el = (vararg_p ? MIR_new_vararg_proto_arr : MIR_new_proto_arr) (ctx, buf, p.nres, &ret_type,
VARR_LENGTH (MIR_var_t, vars),
VARR_ADDR (MIR_var_t, vars));
el = (vararg_p ? MIR_new_vararg_proto_arr
: MIR_new_proto_arr) (ctx, buf, p.nres, p.res_types,
VARR_LENGTH (MIR_var_t, proto_info.arg_vars),
VARR_ADDR (MIR_var_t, proto_info.arg_vars));
HTAB_DO (MIR_item_t, proto_tab, el, HTAB_INSERT, el);
return el;
}
@ -11714,7 +11829,6 @@ static void gen_mir_protos (MIR_context_t ctx) {
node_t call, func;
struct type *type;
struct func_type *func_type;
MIR_type_t ret_type;
curr_mir_proto_num = 0;
HTAB_CREATE (MIR_item_t, proto_tab, 512, proto_hash, proto_eq, NULL);
@ -11727,10 +11841,10 @@ static void gen_mir_protos (MIR_context_t ctx) {
set_type_layout (c2m_ctx, type);
func_type = type->u.ptr_type->u.func_type;
assert (func_type->param_list->code == N_LIST);
collect_args_and_func_types (ctx, func_type, &ret_type);
collect_args_and_func_types (ctx, func_type);
func_type->proto_item
= get_mir_proto (ctx, func_type->dots_p || NL_HEAD (func_type->param_list->ops) == NULL,
ret_type, vars);
proto_info.ret_types, proto_info.arg_vars);
}
HTAB_DESTROY (MIR_item_t, proto_tab);
}
@ -11740,8 +11854,8 @@ static void gen_finish (MIR_context_t ctx) {
if (c2m_ctx == NULL || c2m_ctx->gen_ctx == NULL) return;
finish_reg_vars (ctx);
if (vars != NULL) VARR_DESTROY (MIR_var_t, vars);
if (mem_params != NULL) VARR_DESTROY (node_t, mem_params);
if (proto_info.arg_vars != NULL) VARR_DESTROY (MIR_var_t, proto_info.arg_vars);
if (proto_info.ret_types != NULL) VARR_DESTROY (MIR_type_t, proto_info.ret_types);
if (call_ops != NULL) VARR_DESTROY (MIR_op_t, call_ops);
if (switch_ops != NULL) VARR_DESTROY (MIR_op_t, switch_ops);
if (switch_cases != NULL) VARR_DESTROY (case_t, switch_cases);
@ -11757,8 +11871,8 @@ static void gen_mir (MIR_context_t ctx, node_t r) {
one_op = new_op (NULL, MIR_new_int_op (ctx, 1));
minus_one_op = new_op (NULL, MIR_new_int_op (ctx, -1));
init_reg_vars (ctx);
VARR_CREATE (MIR_var_t, vars, 32);
VARR_CREATE (node_t, mem_params, 16);
VARR_CREATE (MIR_var_t, proto_info.arg_vars, 32);
VARR_CREATE (MIR_type_t, proto_info.ret_types, 16);
gen_mir_protos (ctx);
VARR_CREATE (MIR_op_t, call_ops, 32);
VARR_CREATE (MIR_op_t, switch_ops, 128);

@ -0,0 +1,230 @@
/* This file is a part of MIR project.
Copyright (C) 2018-2020 Vladimir Makarov <vmakarov.gcc@gmail.com>.
x86_64 ABI target specific code.
*/
#define ATYPICAL_CALL_ABI
/* See https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-1.0.pdf. We use MIR_T_UNDEF for
MEMORY. */
enum { NO_CLASS = MIR_T_BOUND + 1, X87UP_CLASS };
#define MAX_QWORDS 8
static MIR_type_t get_result_type (MIR_type_t arg_type1, MIR_type_t arg_type2) {
if (arg_type1 == arg_type2) return arg_type1;
if (arg_type1 == NO_CLASS) return arg_type2;
if (arg_type2 == NO_CLASS) return arg_type1;
if (arg_type1 == MIR_T_UNDEF || arg_type2 == MIR_T_UNDEF) return MIR_T_UNDEF;
if ((arg_type1 == MIR_T_I32 && arg_type2 == MIR_T_F)
|| (arg_type2 == MIR_T_I32 && arg_type1 == MIR_T_F))
return MIR_T_I32;
if (arg_type1 == MIR_T_I64 || arg_type1 == MIR_T_I32 || arg_type2 == MIR_T_I64
|| arg_type2 == MIR_T_I32)
return MIR_T_I64;
if (arg_type1 == MIR_T_LD || arg_type2 == MIR_T_LD || arg_type1 == X87UP_CLASS
|| arg_type2 == X87UP_CLASS)
return MIR_T_UNDEF;
return MIR_T_D;
}
static int classify_arg (MIR_context_t ctx, struct type *type, MIR_type_t types[MAX_QWORDS],
mir_size_t offset, int bit_field_p) {
c2m_ctx_t c2m_ctx = *c2m_ctx_loc (ctx);
size_t size = type_size (c2m_ctx, type);
int i, n_el_qwords, n_qwords = (size + 7) / 8;
MIR_type_t mir_type;
if (type->mode == TM_STRUCT || type->mode == TM_UNION || type->mode == TM_STRUCT) {
MIR_type_t subtypes[MAX_QWORDS];
if (n_qwords > 8) return 0; /* too big aggregate */
for (i = 0; i < n_qwords; i++) types[i] = NO_CLASS;
switch (type->mode) {
case TM_ARR: { /* Arrays are handled as small records. */
n_el_qwords = classify_arg (ctx, type->u.arr_type->el_type, subtypes, 0, FALSE);
if (n_el_qwords == 0) return 0;
/* make full types: */
if (subtypes[0] == MIR_T_F && size != 4) subtypes[0] = MIR_T_D;
if (subtypes[0] == MIR_T_I32 && (bit_field_p || size != 4)) subtypes[0] = MIR_T_I64;
for (i = 0; i < n_qwords; i++) types[i] = subtypes[i % n_el_qwords];
break;
}
case TM_STRUCT:
case TM_UNION:
for (node_t el = NL_HEAD (NL_EL (type->u.tag_type->ops, 1)->ops); el != NULL;
el = NL_NEXT (el))
if (el->code == N_MEMBER) {
decl_t decl = el->attr;
int start_qword = (offset + decl->offset) / 8;
if (decl->bit_offset >= 0) {
types[start_qword] = get_result_type (MIR_T_I64, types[start_qword]);
} else {
n_el_qwords = classify_arg (ctx, decl->decl_spec.type, subtypes,
offset + (type->mode == TM_STRUCT ? decl->offset : 0),
decl->bit_offset >= 0);
if (n_el_qwords == 0) return 0;
for (i = 0; i < n_el_qwords && (i + start_qword) < n_qwords; i++)
types[i + start_qword] = get_result_type (subtypes[i], types[i + start_qword]);
}
}
break;
default: assert (FALSE);
}
if (n_qwords > 2) return 0; /* as we don't have vector values (see SSEUP_CLASS) */
for (i = 0; i < n_qwords; i++) {
if (types[i] == MIR_T_UNDEF) return 0; /* pass in memory if a word class is memory. */
if (types[i] == X87UP_CLASS && (i == 0 || types[i - 1] != MIR_T_LD)) return 0;
}
return n_qwords;
}
assert (scalar_type_p (type));
switch (mir_type = get_mir_type (ctx, type)) {
case MIR_T_F: types[0] = offset % 8 != 0 ? MIR_T_D : MIR_T_F; return 1;
case MIR_T_D: types[0] = MIR_T_D; return 1;
case MIR_T_LD:
types[0] = MIR_T_LD;
types[1] = X87UP_CLASS;
return 2;
default:
if (!bit_field_p && offset % 8 + size <= 4) {
types[0] = MIR_T_I32;
} else {
assert (size <= 8);
types[0] = MIR_T_I64;
}
return 1;
}
}
typedef struct target_arg_info {
int n_iregs, n_fregs;
} target_arg_info_t;
static void target_init_arg_vars (MIR_context_t ctx, target_arg_info_t *arg_info) {
arg_info->n_iregs = arg_info->n_fregs = 0;
}
static const char *qword_name (MIR_context_t ctx, const char *name, int num) {
c2m_ctx_t c2m_ctx = *c2m_ctx_loc (ctx);
char prefix[50];
sprintf (prefix, "Q%u_", num);
VARR_TRUNC (char, temp_string, 0);
add_to_temp_string (c2m_ctx, prefix);
add_to_temp_string (c2m_ctx, name);
return uniq_cstr (c2m_ctx, VARR_ADDR (char, temp_string)).s;
}
static void target_add_res (MIR_context_t ctx, struct func_type *func_type,
target_arg_info_t *arg_info) {
MIR_var_t var;
MIR_type_t type;
c2m_ctx_t c2m_ctx = *c2m_ctx_loc (ctx);
MIR_type_t qword_types[MAX_QWORDS];
int n_iregs, n_fregs, n_stregs, n, n_qwords, curr;
if (void_type_p (func_type->ret_type)) return;
n_qwords = classify_arg (ctx, func_type->ret_type, qword_types, 0, FALSE);
if (n_qwords != 0) {
n_iregs = n_fregs = n_stregs = curr = 0;
for (n = 0; n < n_qwords; n++) { /* start from the last qword */
type = qword_types[n];
qword_types[curr++] = type;
switch (type) {
case MIR_T_I32:
case MIR_T_I64: n_iregs++; break;
case MIR_T_F:
case MIR_T_D: n_fregs++; break;
case MIR_T_LD: n_stregs++; break;
case X87UP_CLASS:
n_qwords--;
curr--;
break;
case NO_CLASS:
case MIR_T_UNDEF: assert (FALSE);
}
}
if (n_iregs > 2 || n_fregs > 2 || n_stregs > 1) {
n_qwords = 0;
}
}
proto_info.res_ref_p = FALSE;
if (n_qwords == 0) { /* return by reference */
var.name = RET_ADDR_NAME;
var.type = MIR_POINTER_TYPE;
VARR_PUSH (MIR_var_t, proto_info.arg_vars, var);
proto_info.res_ref_p = TRUE;
arg_info->n_iregs++;
return;
} else {
for (n = 0; n < n_qwords; n++) VARR_PUSH (MIR_type_t, proto_info.ret_types, qword_types[n]);
}
}
static void target_add_param (MIR_context_t ctx, const char *name, struct type *param_type,
decl_t param_decl, target_arg_info_t *arg_info) {
MIR_var_t var;
MIR_type_t type;
c2m_ctx_t c2m_ctx = *c2m_ctx_loc (ctx);
MIR_type_t qword_types[MAX_QWORDS];
int n_iregs, n_fregs, n;
int n_qwords = classify_arg (ctx, param_type, qword_types, 0, FALSE);
if (n_qwords != 0) {
n_iregs = n_fregs = 0;
for (n = 0; n < n_qwords; n++) { /* start from the last qword */
switch ((type = qword_types[n])) {
case MIR_T_I32:
case MIR_T_I64: n_iregs++; break;
case MIR_T_F:
case MIR_T_D: n_fregs++; break;
case X87UP_CLASS:
case MIR_T_LD: n_qwords = 0; goto pass_by_ref;
case NO_CLASS:
case MIR_T_UNDEF: assert (FALSE);
}
}
if (arg_info->n_iregs + n_iregs > 6 || arg_info->n_fregs + n_fregs > 8) {
n_qwords = 0;
} else { /* aggregate passed by value: */
arg_info->n_iregs += n_iregs;
arg_info->n_fregs += n_fregs;
if (param_decl != NULL) {
param_decl->param_args_num = n_iregs + n_fregs;
param_decl->param_args_start = VARR_LENGTH (MIR_var_t, proto_info.arg_vars);
}
for (n = 0; n < n_qwords; n++) {
var.name = qword_name (ctx, name, n);
var.type = qword_types[n];
VARR_PUSH (MIR_var_t, proto_info.arg_vars, var);
}
}
}
pass_by_ref:
if (n_qwords == 0) { /* pass by ref for aggregates and pass by value for others: */
type = (param_type->mode == TM_STRUCT || param_type->mode == TM_UNION
? MIR_POINTER_TYPE
: get_mir_type (ctx, param_type));
var.name = name;
var.type = type;
VARR_PUSH (MIR_var_t, proto_info.arg_vars, var);
if (type == MIR_T_F || type == MIR_T_D)
arg_info->n_fregs += n_fregs;
else if (type != MIR_T_LD)
arg_info->n_iregs += n_iregs;
}
}

@ -60,6 +60,8 @@ void *va_arg_builtin (void *p, uint64_t t) {
return a;
}
void *va_stack_arg_builtin (void *p, size_t s) { return *(void **) va_arg_builtin (p, MIR_T_I64); }
void va_start_interp_builtin (MIR_context_t ctx, void *p, void *a) {
struct aarch64_va_list *va = p;
va_list *vap = a;
@ -88,10 +90,11 @@ static int setup_imm64_insns (MIR_context_t ctx, uint32_t *to, int reg, uint64_t
return sizeof (imm64_pat) / sizeof (uint32_t);
}
static void push_insns (MIR_context_t ctx, const uint32_t *pat, size_t pat_len) {
static uint8_t *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]);
return VARR_ADDR (uint8_t, machine_insns) + VARR_LENGTH (uint8_t, machine_insns) - pat_len;
}
static size_t gen_mov_addr (MIR_context_t ctx, int reg, void *addr) {
@ -150,6 +153,34 @@ void _MIR_redirect_thunk (MIR_context_t ctx, void *thunk, void *to) {
}
}
static void gen_blk_mov (MIR_context_t ctx, uint32_t offset, uint32_t addr_offset, uint32_t qwords,
uint32_t addr_reg) {
static const uint32_t blk_mov_pat[] = {
/* 0:*/ 0xf940026c, /* ldr x12, [x19,<addr_offset>]*/
/* 4:*/ 0x910003e0, /* add <addr_reg>, sp, <offset>*/
/* 8:*/ 0xd280000b, /* mov x11, 0*/
/* c:*/ 0xd280000e, /* mov x14, <qwords>*/
/* 10:*/ 0xf86c696a, /* ldr x10, [x11,x12]*/
/* 14:*/ 0xd10005ce, /* sub x14, x14, #0x1*/
/* 18:*/ 0xf820696a, /* str x10, [x11,<addr_reg>x13]*/
/* 1c:*/ 0xf10001df, /* cmp x14, 0*/
/* 20:*/ 0x9100216b, /* add x11, x11, 8*/
/* 24:*/ 0x54ffff61, /* b.ne 10 */
};
if (qwords == 0) {
uint32_t pat = 0x910003e0 | addr_reg | (offset << 10); /* add <add_reg>, sp, <offset>*/
push_insns (ctx, &pat, sizeof (pat));
} else {
uint32_t *addr = (uint32_t *) push_insns (ctx, blk_mov_pat, sizeof (blk_mov_pat));
mir_assert (offset < (1 << 12) && addr_offset % 8 == 0 && (addr_offset >> 3) < (1 << 12));
mir_assert (addr_reg < 32 && qwords < (1 << 16));
addr[0] |= (addr_offset >> 3) << 10;
addr[1] |= addr_reg | (offset << 10);
addr[3] |= qwords << 5;
addr[6] |= addr_reg << 16;
}
}
/* save r0-r7, v0-v7 */
static const uint32_t save_insns[] = {
0xa9bf1fe6, /* stp R6, R7, [SP, #-16]! */
@ -180,12 +211,14 @@ 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,<offset>]; (arg_reg=mem[x8] or x8=mem[x8];mem[sp,sp_offset]=x8) ...
x8=mem[x19,<offset>]; (arg_reg=mem[x8](or addr of blk copy on the stack)
or x8=mem[x8] or x13=addr of blk copy on the stack;
mem[sp,sp_offset]=x8|x13) ...
call fun_addr; sp+=offset
x8=mem[x19,<offset>]; 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) {
_MIR_arg_desc_t *arg_descs, int vararg_p) {
static const uint32_t prolog[] = {
0xa9bf7bf3, /* stp x19,x30,[sp, -16]! */
0xd10003ff, /* sub sp,sp,<sp_offset> */
@ -204,17 +237,42 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
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;
MIR_type_t type;
uint32_t n_xregs = 0, n_vregs = 0, sp_offset = 0, blk_offset = 0, pat, offset_imm, scale;
uint32_t sp = 31, addr_reg, qwords;
uint32_t *addr;
const uint32_t temp_reg = 8; /* x8 or v9 */
mir_assert (sizeof (long double) == 16);
for (size_t i = 0; i < nargs; i++) { /* caclulate offset for blk params */
type = arg_descs[i].type;
if ((MIR_T_I8 <= type && type <= MIR_T_U64) || type == MIR_T_P || type == MIR_T_BLK) {
if (n_xregs++ >= 8) blk_offset += 8;
} else if (type == MIR_T_F || type == MIR_T_D || type == MIR_T_LD) {
if (n_vregs++ >= 8) blk_offset += type == MIR_T_LD ? 16 : 8;
} else {
(*error_func) (MIR_call_op_error, "wrong type of arg value");
}
}
blk_offset = (blk_offset + 15) / 16 * 16;
VARR_TRUNC (uint8_t, machine_insns, 0);
push_insns (ctx, prolog, sizeof (prolog));
mir_assert (sizeof (long double) == 16);
n_xregs = n_vregs = 0;
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;
type = arg_descs[i].type;
scale = type == MIR_T_F ? 2 : type == 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 (type == MIR_T_BLK) {
qwords = (arg_descs[i].size + 7) / 8;
addr_reg = n_xregs < 8 ? n_xregs : 13;
gen_blk_mov (ctx, blk_offset, (i + nres) * sizeof (long double), qwords, addr_reg);
blk_offset += qwords * 8;
if (n_xregs++ >= 8) {
pat = st_pat | ((sp_offset >> scale) << 10) | addr_reg | (sp << 5);
push_insns (ctx, &pat, sizeof (pat));
sp_offset += 8;
}
} else if ((MIR_T_I8 <= type && type <= MIR_T_U64) || type == MIR_T_P) {
if (n_xregs < 8) {
pat = ld_pat | offset_imm | n_xregs++;
} else {
@ -224,24 +282,24 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
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;
} else if (type == MIR_T_F || type == MIR_T_D || type == MIR_T_LD) {
pat = type == MIR_T_F ? lds_pat : type == 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;
if (type == 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 = type == MIR_T_F ? sts_pat : type == 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;
sp_offset += type == 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;
blk_offset = (blk_offset + 15) / 16 * 16;
if (blk_offset != 0) sp_offset = blk_offset;
mir_assert (sp_offset < (1 << 12));
((uint32_t *) VARR_ADDR (uint8_t, machine_insns))[1] |= sp_offset << 10; /* sub sp,sp,<offset> */
push_insns (ctx, call_end, sizeof (call_end));

@ -56,10 +56,10 @@ static inline int target_fixed_hard_reg_p (MIR_reg_t hard_reg) {
|| hard_reg == TEMP_LDOUBLE_HARD_REG2);
}
static inline int target_call_used_hard_reg_p (MIR_reg_t hard_reg) {
static inline int target_call_used_hard_reg_p (MIR_reg_t hard_reg, MIR_type_t type) {
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));
if (hard_reg <= SP_HARD_REG) return !(hard_reg >= R19_HARD_REG && hard_reg <= R28_HARD_REG);
return type == MIR_T_LD || !(hard_reg >= V8_HARD_REG && hard_reg <= V15_HARD_REG);
}
/* Stack layout (sp refers to the last reserved stack slot address)
@ -128,7 +128,7 @@ static MIR_reg_t get_arg_reg (MIR_type_t arg_type, size_t *int_arg_num, size_t *
}
(*fp_arg_num)++;
*mov_code = arg_type == MIR_T_F ? MIR_FMOV : arg_type == MIR_T_D ? MIR_DMOV : MIR_LDMOV;
} else {
} else { /* including BLK: */
switch (*int_arg_num) {
case 0:
case 1:
@ -146,12 +146,80 @@ static MIR_reg_t get_arg_reg (MIR_type_t arg_type, size_t *int_arg_num, size_t *
return arg_reg;
}
static void mir_blk_mov (uint64_t *to, uint64_t *from, uint64_t nwords) {
for (; nwords > 0; nwords--) *to++ = *from++;
}
static void gen_mov (gen_ctx_t gen_ctx, MIR_insn_t anchor, MIR_insn_code_t code, MIR_op_t dst_op,
MIR_op_t src_op) {
gen_add_insn_before (gen_ctx, anchor, MIR_new_insn (gen_ctx->ctx, code, dst_op, src_op));
}
static const char *BLK_MOV = "mir.blk_mov";
static const char *BLK_MOV_P = "mir.blk_mov.p";
static void gen_blk_mov (gen_ctx_t gen_ctx, MIR_insn_t anchor, size_t to_disp,
MIR_reg_t to_base_hard_reg, size_t from_disp, MIR_reg_t from_base_reg,
size_t qwords, int save_regs) {
MIR_context_t ctx = gen_ctx->ctx;
MIR_func_t func = curr_func_item->u.func;
MIR_item_t proto_item, func_import_item;
MIR_insn_t new_insn;
MIR_op_t ops[5], freg_op, treg_op, treg_op2, treg_op3;
treg_op = MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, func));
if (qwords <= 16) {
for (; qwords > 0; qwords--, to_disp += 8, from_disp += 8) {
gen_mov (gen_ctx, anchor, MIR_MOV, treg_op,
MIR_new_mem_op (ctx, MIR_T_I64, from_disp, from_base_reg, 0, 1));
gen_mov (gen_ctx, anchor, MIR_MOV,
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, to_disp, to_base_hard_reg,
MIR_NON_HARD_REG, 1),
treg_op);
}
return;
}
treg_op2 = MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, func));
treg_op3 = MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, func));
/* Save arg regs: */
if (save_regs > 0) gen_mov (gen_ctx, anchor, MIR_MOV, treg_op, _MIR_new_hard_reg_op (ctx, R0_HARD_REG));
if (save_regs > 1) gen_mov (gen_ctx, anchor, MIR_MOV, treg_op2, _MIR_new_hard_reg_op (ctx, R1_HARD_REG));
if (save_regs > 2) gen_mov (gen_ctx, anchor, MIR_MOV, treg_op3, _MIR_new_hard_reg_op (ctx, R2_HARD_REG));
/* call blk move: */
proto_item = _MIR_builtin_proto (ctx, curr_func_item->module, BLK_MOV_P, 0, NULL, 3, MIR_T_I64,
"to", MIR_T_I64, "from", MIR_T_I64, "nwords");
func_import_item = _MIR_builtin_func (ctx, curr_func_item->module, BLK_MOV, mir_blk_mov);
freg_op = MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, func));
new_insn = MIR_new_insn (ctx, MIR_MOV, freg_op, MIR_new_ref_op (ctx, func_import_item));
gen_add_insn_before (gen_ctx, anchor, new_insn);
gen_add_insn_before (gen_ctx, anchor,
MIR_new_insn (gen_ctx->ctx, MIR_ADD, _MIR_new_hard_reg_op (ctx, R0_HARD_REG),
_MIR_new_hard_reg_op (ctx, to_base_hard_reg),
MIR_new_int_op (ctx, to_disp)));
gen_add_insn_before (gen_ctx, anchor,
MIR_new_insn (gen_ctx->ctx, MIR_ADD, _MIR_new_hard_reg_op (ctx, R1_HARD_REG),
MIR_new_reg_op (ctx, from_base_reg),
MIR_new_int_op (ctx, from_disp)));
gen_mov (gen_ctx, anchor, MIR_MOV, _MIR_new_hard_reg_op (ctx, R2_HARD_REG), MIR_new_int_op (ctx, qwords));
ops[0] = MIR_new_ref_op (ctx, proto_item);
ops[1] = freg_op;
ops[2] = _MIR_new_hard_reg_op (ctx, R0_HARD_REG);
ops[3] = _MIR_new_hard_reg_op (ctx, R1_HARD_REG);
ops[4] = _MIR_new_hard_reg_op (ctx, R2_HARD_REG);
new_insn = MIR_new_insn_arr (ctx, MIR_CALL, 5, ops);
gen_add_insn_before (gen_ctx, anchor, new_insn);
/* Restore arg regs: */
if (save_regs > 0) gen_mov (gen_ctx, anchor, MIR_MOV, _MIR_new_hard_reg_op (ctx, R0_HARD_REG), treg_op);
if (save_regs > 1) gen_mov (gen_ctx, anchor, MIR_MOV, _MIR_new_hard_reg_op (ctx, R1_HARD_REG), treg_op2);
if (save_regs > 2) gen_mov (gen_ctx, anchor, MIR_MOV, _MIR_new_hard_reg_op (ctx, R2_HARD_REG), treg_op3);
}
static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_insn) {
MIR_context_t ctx = gen_ctx->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;
size_t int_arg_num = 0, fp_arg_num = 0, mem_size = 0, blk_offset = 0, qwords;
MIR_type_t type, mem_type;
MIR_op_mode_t mode;
MIR_var_t *arg_vars = NULL;
@ -178,11 +246,12 @@ static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_insn) {
call_insn->ops[1] = temp_op;
gen_add_insn_before (gen_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);
for (size_t i = start; i < nops; i++) { /* caclulate offset for blk params */
if (i - start < nargs) {
type = arg_vars[i - start].type;
} else if (call_insn->ops[i].mode == MIR_OP_MEM) {
type = MIR_T_BLK;
gen_assert (call_insn->ops[i].u.mem.type == 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
@ -192,14 +261,45 @@ static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_insn) {
"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;
}
if (get_arg_reg (type, &int_arg_num, &fp_arg_num, &new_insn_code) == MIR_NON_HARD_REG) {
if (type == MIR_T_LD && blk_offset % 16 != 0) blk_offset = (blk_offset + 15) / 16 * 16;
blk_offset += type == MIR_T_LD ? 16 : 8;
}
}
blk_offset = (blk_offset + 15) / 16 * 16;
int_arg_num = fp_arg_num = 0;
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
|| (arg_op.mode == MIR_OP_MEM && arg_op.u.mem.type == MIR_T_BLK));
if (i - start < nargs) {
type = arg_vars[i - start].type;
} else if (call_insn->ops[i].mode == MIR_OP_MEM) {
type = MIR_T_BLK;
gen_assert (call_insn->ops[i].u.mem.type == type);
} else {
mode = call_insn->ops[i].value_mode; // ??? smaller ints
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 (gen_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 (type == MIR_T_BLK) {
gen_assert (arg_op.mode == MIR_OP_MEM && arg_op.u.mem.disp >= 0 && arg_op.u.mem.index == 0);
qwords = (arg_op.u.mem.disp + 7) / 8;
gen_blk_mov (gen_ctx, call_insn, blk_offset, SP_HARD_REG, 0, arg_op.u.mem.base, qwords, int_arg_num);
arg_op = MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, func));
gen_add_insn_before (gen_ctx, call_insn,
MIR_new_insn (gen_ctx->ctx, MIR_ADD, arg_op,
_MIR_new_hard_reg_op (ctx, SP_HARD_REG),
MIR_new_int_op (ctx, blk_offset)));
blk_offset += qwords * 8;
}
if ((arg_reg = get_arg_reg (type, &int_arg_num, &fp_arg_num, &new_insn_code))
!= MIR_NON_HARD_REG) {
!= MIR_NON_HARD_REG) {
/* put arguments to argument hard regs */
if (ext_insn != NULL) gen_add_insn_before (gen_ctx, call_insn, ext_insn);
arg_reg_op = _MIR_new_hard_reg_op (ctx, arg_reg);
@ -224,6 +324,8 @@ static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_insn) {
if (ext_insn != NULL) gen_add_insn_after (gen_ctx, prev_call_insn, ext_insn);
}
}
blk_offset = (blk_offset + 15) / 16 * 16;
if (blk_offset != 0) mem_size = blk_offset;
n_iregs = n_vregs = 0;
for (size_t i = 0; i < proto->nres; i++) {
int float_p;
@ -321,6 +423,8 @@ 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 const char *VA_STACK_ARG_P = "mir.va_stack_arg.p";
static const char *VA_STACK_ARG = "mir.va_stack_arg";
static int64_t mir_ldeq (long double d1, long double d2) { return d1 == d2; }
static const char *LDEQ = "mir.ldeq";
@ -467,15 +571,17 @@ static int get_builtin (gen_ctx_t gen_ctx, MIR_insn_code_t code, MIR_item_t *pro
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;
case MIR_VA_STACK_ARG:
res_type = MIR_T_I64;
*proto_item = _MIR_builtin_proto (ctx, curr_func_item->module, VA_STACK_ARG_P, 1, &res_type, 2,
MIR_T_I64, "va", MIR_T_I64, "size");
*func_import_item
= _MIR_builtin_func (ctx, curr_func_item->module, VA_STACK_ARG, va_stack_arg_builtin);
return 2;
default: return 0;
}
}
static void gen_mov (gen_ctx_t gen_ctx, MIR_insn_t anchor, MIR_insn_code_t code, MIR_op_t dst_op,
MIR_op_t src_op) {
gen_add_insn_before (gen_ctx, anchor, MIR_new_insn (gen_ctx->ctx, code, dst_op, src_op));
}
DEF_VARR (int);
DEF_VARR (uint8_t);
DEF_VARR (uint64_t);
@ -728,7 +834,7 @@ static void target_make_prolog_epilog (gen_ctx_t gen_ctx, bitmap_t used_hard_reg
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 (!target_call_used_hard_reg_p (i, MIR_T_UNDEF) && bitmap_bit_p (used_hard_regs, i)) {
if (i < V0_HARD_REG)
saved_iregs_num++;
else
@ -743,7 +849,7 @@ static void target_make_prolog_epilog (gen_ctx_t gen_ctx, bitmap_t used_hard_reg
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 (!target_call_used_hard_reg_p (i, MIR_T_UNDEF) && bitmap_bit_p (used_hard_regs, i)) {
if (i < V0_HARD_REG) {
frame_size += 8;
} else {
@ -812,7 +918,7 @@ static void target_make_prolog_epilog (gen_ctx_t gen_ctx, bitmap_t used_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 (!target_call_used_hard_reg_p (i, MIR_T_UNDEF) && bitmap_bit_p (used_hard_regs, i)) {
if (i < V0_HARD_REG) {
gen_mov (gen_ctx, anchor, MIR_MOV,
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, offset, FP_HARD_REG, MIR_NON_HARD_REG,
@ -833,7 +939,7 @@ static void target_make_prolog_epilog (gen_ctx_t gen_ctx, bitmap_t used_hard_reg
/* 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 (!target_call_used_hard_reg_p (i, MIR_T_UNDEF) && bitmap_bit_p (used_hard_regs, i)) {
if (i < V0_HARD_REG) {
gen_mov (gen_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,

@ -63,7 +63,7 @@ static inline int target_fixed_hard_reg_p (MIR_reg_t hard_reg) {
|| 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) {
static inline int target_call_used_hard_reg_p (MIR_reg_t hard_reg, MIR_type_t type) {
assert (hard_reg <= MAX_HARD_REG);
return ((R0_HARD_REG <= hard_reg && hard_reg <= R13_HARD_REG)
|| (F0_HARD_REG <= hard_reg && hard_reg <= F13_HARD_REG));
@ -165,12 +165,75 @@ static void gen_mov (gen_ctx_t gen_ctx, MIR_insn_t anchor, MIR_insn_code_t code,
gen_add_insn_before (gen_ctx, anchor, MIR_new_insn (gen_ctx->ctx, code, dst_op, src_op));
}
static void mir_blk_mov (uint64_t *to, uint64_t *from, uint64_t nwords) {
for (; nwords > 0; nwords--) *to++ = *from++;
}
static const char *BLK_MOV = "mir.blk_mov";
static const char *BLK_MOV_P = "mir.blk_mov.p";
static void gen_blk_mov (gen_ctx_t gen_ctx, MIR_insn_t anchor, size_t to_disp,
MIR_reg_t to_base_hard_reg, size_t from_disp, MIR_reg_t from_base_reg,
size_t qwords, int save_regs) {
MIR_context_t ctx = gen_ctx->ctx;
MIR_func_t func = curr_func_item->u.func;
MIR_item_t proto_item, func_import_item;
MIR_insn_t new_insn;
MIR_op_t ops[5], freg_op, treg_op, treg_op2, treg_op3;
treg_op = MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, func));
if (qwords <= 16) {
for (; qwords > 0; qwords--, to_disp += 8, from_disp += 8) {
gen_mov (gen_ctx, anchor, MIR_MOV, treg_op,
MIR_new_mem_op (ctx, MIR_T_I64, from_disp, from_base_reg, 0, 1));
gen_mov (gen_ctx, anchor, MIR_MOV,
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, to_disp, to_base_hard_reg,
MIR_NON_HARD_REG, 1),
treg_op);
}
return;
}
treg_op2 = MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, func));
treg_op3 = MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, func));
/* Save arg regs: */
if (save_regs > 0) gen_mov (gen_ctx, anchor, MIR_MOV, treg_op, _MIR_new_hard_reg_op (ctx, 3));
if (save_regs > 1) gen_mov (gen_ctx, anchor, MIR_MOV, treg_op2, _MIR_new_hard_reg_op (ctx, 4));
if (save_regs > 2) gen_mov (gen_ctx, anchor, MIR_MOV, treg_op3, _MIR_new_hard_reg_op (ctx, 5));
/* call blk move: */
proto_item = _MIR_builtin_proto (ctx, curr_func_item->module, BLK_MOV_P, 0, NULL, 3, MIR_T_I64,
"to", MIR_T_I64, "from", MIR_T_I64, "nwords");
func_import_item = _MIR_builtin_func (ctx, curr_func_item->module, BLK_MOV, mir_blk_mov);
freg_op = MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, func));
new_insn = MIR_new_insn (ctx, MIR_MOV, freg_op, MIR_new_ref_op (ctx, func_import_item));
gen_add_insn_before (gen_ctx, anchor, new_insn);
gen_add_insn_before (gen_ctx, anchor,
MIR_new_insn (gen_ctx->ctx, MIR_ADD, _MIR_new_hard_reg_op (ctx, 3),
_MIR_new_hard_reg_op (ctx, to_base_hard_reg),
MIR_new_int_op (ctx, to_disp)));
gen_add_insn_before (gen_ctx, anchor,
MIR_new_insn (gen_ctx->ctx, MIR_ADD, _MIR_new_hard_reg_op (ctx, 4),
MIR_new_reg_op (ctx, from_base_reg),
MIR_new_int_op (ctx, from_disp)));
gen_mov (gen_ctx, anchor, MIR_MOV, _MIR_new_hard_reg_op (ctx, 5), MIR_new_int_op (ctx, qwords));
ops[0] = MIR_new_ref_op (ctx, proto_item);
ops[1] = freg_op;
ops[2] = _MIR_new_hard_reg_op (ctx, 3);
ops[3] = _MIR_new_hard_reg_op (ctx, 4);
ops[4] = _MIR_new_hard_reg_op (ctx, 5);
new_insn = MIR_new_insn_arr (ctx, MIR_CALL, 5, ops);
gen_add_insn_before (gen_ctx, anchor, new_insn);
/* Restore arg regs: */
if (save_regs > 0) gen_mov (gen_ctx, anchor, MIR_MOV, _MIR_new_hard_reg_op (ctx, 3), treg_op);
if (save_regs > 1) gen_mov (gen_ctx, anchor, MIR_MOV, _MIR_new_hard_reg_op (ctx, 4), treg_op2);
if (save_regs > 2) gen_mov (gen_ctx, anchor, MIR_MOV, _MIR_new_hard_reg_op (ctx, 5), treg_op3);
}
static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_insn) {
MIR_context_t ctx = gen_ctx->ctx;
MIR_func_t func = curr_func_item->u.func;
MIR_proto_t proto = call_insn->ops[0].u.ref->u.proto;
int vararg_p = proto->vararg_p;
size_t nargs, nops = MIR_insn_nops (ctx, call_insn), start = proto->nres + 2;
size_t qwords, disp, nargs, nops = MIR_insn_nops (ctx, call_insn), start = proto->nres + 2;
size_t mem_size = 0, n_iregs = 0, n_fregs = 0;
MIR_type_t type, mem_type;
MIR_op_mode_t mode;
@ -198,9 +261,13 @@ static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_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);
gen_assert (arg_op.mode == MIR_OP_REG || arg_op.mode == MIR_OP_HARD_REG
|| (arg_op.mode == MIR_OP_MEM && arg_op.u.mem.type == MIR_T_BLK));
if (i - start < nargs) {
type = arg_vars[i - start].type;
} else if (call_insn->ops[i].mode == MIR_OP_MEM) {
type = MIR_T_BLK;
gen_assert (call_insn->ops[i].u.mem.type == 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
@ -248,6 +315,21 @@ static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_insn) {
}
}
n_fregs += type == MIR_T_LD ? 2 : 1;
} else if (type == MIR_T_BLK) {
gen_assert (arg_op.mode == MIR_OP_MEM && arg_op.u.mem.disp >= 0 && arg_op.u.mem.index == 0);
qwords = (arg_op.u.mem.disp + 7) / 8;
for (disp = 0; qwords > 0 && n_iregs < 8; qwords--, n_iregs++, mem_size += 8, disp += 8) {
arg_reg_op = _MIR_new_hard_reg_op (ctx, R3_HARD_REG + n_iregs);
gen_mov (gen_ctx, call_insn, MIR_MOV, arg_reg_op,
MIR_new_mem_op (ctx, MIR_T_I64, disp, arg_op.u.mem.base, 0, 1));
setup_call_hard_reg_args (gen_ctx, call_insn, R3_HARD_REG + n_iregs);
}
if (qwords > 0)
gen_blk_mov (gen_ctx, call_insn, mem_size + PPC64_STACK_HEADER_SIZE, SP_HARD_REG, disp,
arg_op.u.mem.base, qwords, n_iregs);
mem_size += qwords * 8;
n_iregs += qwords;
continue;
} else if (type != MIR_T_F && type != MIR_T_D && type != MIR_T_LD && n_iregs < 8) {
if (ext_insn != NULL) gen_add_insn_before (gen_ctx, call_insn, ext_insn);
arg_reg_op = _MIR_new_hard_reg_op (ctx, R3_HARD_REG + n_iregs);
@ -350,6 +432,8 @@ 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 const char *VA_STACK_ARG_P = "mir.va_stack_arg.p";
static const char *VA_STACK_ARG = "mir.va_stack_arg";
static int64_t mir_ldeq (long double d1, long double d2) { return d1 == d2; }
static const char *LDEQ = "mir.ldeq";
@ -496,6 +580,13 @@ static int get_builtin (gen_ctx_t gen_ctx, MIR_insn_code_t code, MIR_item_t *pro
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;
case MIR_VA_STACK_ARG:
res_type = MIR_T_I64;
*proto_item = _MIR_builtin_proto (ctx, curr_func_item->module, VA_STACK_ARG_P, 1, &res_type, 2,
MIR_T_I64, "va", MIR_T_I64, "size");
*func_import_item
= _MIR_builtin_func (ctx, curr_func_item->module, VA_STACK_ARG, va_stack_arg_builtin);
return 2;
default: return 0;
}
}
@ -508,8 +599,9 @@ static MIR_disp_t target_get_stack_slot_offset (gen_ctx_t gen_ctx, MIR_type_t ty
static void set_prev_sp_op (gen_ctx_t gen_ctx, MIR_insn_t anchor, MIR_op_t *prev_sp_op) {
if (!stack_arg_func_p) {
/* don't use r11 as we can have spilled param<-mem in param set up which needs r11 as a temp */
stack_arg_func_p = TRUE;
*prev_sp_op = _MIR_new_hard_reg_op (gen_ctx->ctx, R11_HARD_REG);
*prev_sp_op = _MIR_new_hard_reg_op (gen_ctx->ctx, R12_HARD_REG);
gen_mov (gen_ctx, anchor, MIR_MOV, *prev_sp_op,
_MIR_new_hard_reg_mem_op (gen_ctx->ctx, MIR_T_I64, 0, SP_HARD_REG, MIR_NON_HARD_REG,
1));
@ -524,7 +616,7 @@ static void target_machinize (gen_ctx_t gen_ctx) {
MIR_insn_t insn, next_insn, new_insn, anchor;
MIR_reg_t ret_reg;
MIR_op_t ret_reg_op, arg_reg_op, prev_sp_op, temp_op, arg_var_op;
size_t i, int_arg_num, fp_arg_num, disp, var_args_start;
size_t i, int_arg_num, fp_arg_num, disp, var_args_start, qwords, offset;
assert (curr_func_item->item_type == MIR_func_item);
func = curr_func_item->u.func;
@ -544,7 +636,7 @@ static void target_machinize (gen_ctx_t gen_ctx) {
set_prev_sp_op (gen_ctx, anchor, &prev_sp_op);
arg_reg_op = _MIR_new_hard_reg_op (ctx, F14_HARD_REG);
gen_mov (gen_ctx, anchor, MIR_DMOV, arg_reg_op,
_MIR_new_hard_reg_mem_op (ctx, MIR_T_D, disp + 8, R11_HARD_REG, MIR_NON_HARD_REG,
_MIR_new_hard_reg_mem_op (ctx, MIR_T_D, disp + 8, R12_HARD_REG, MIR_NON_HARD_REG,
1));
}
arg_reg_op = _MIR_new_hard_reg_op (ctx, F1_HARD_REG + fp_arg_num);
@ -556,14 +648,33 @@ static void target_machinize (gen_ctx_t gen_ctx) {
set_prev_sp_op (gen_ctx, anchor, &prev_sp_op);
gen_mov (gen_ctx, anchor, type == MIR_T_F ? MIR_FMOV : type == MIR_T_D ? MIR_DMOV : MIR_LDMOV,
arg_var_op,
_MIR_new_hard_reg_mem_op (ctx, type, disp, R11_HARD_REG, MIR_NON_HARD_REG, 1));
_MIR_new_hard_reg_mem_op (ctx, type, disp, R12_HARD_REG, MIR_NON_HARD_REG, 1));
} else if (type == MIR_T_BLK) { // ??? FBLK
qwords = (VARR_GET (MIR_var_t, func->vars, i).size + 7) / 8;
offset = int_arg_num < 8 ? PPC64_STACK_HEADER_SIZE + int_arg_num * 8 : disp;
set_prev_sp_op (gen_ctx, anchor, &prev_sp_op);
for (; qwords > 0 && int_arg_num < 8; qwords--, int_arg_num++, disp += 8) {
if (!func->vararg_p)
gen_mov (gen_ctx, anchor, MIR_MOV,
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64,
PPC64_STACK_HEADER_SIZE + int_arg_num * 8,
R12_HARD_REG, MIR_NON_HARD_REG, 1),
_MIR_new_hard_reg_op (ctx, R3_HARD_REG + int_arg_num));
}
gen_add_insn_before (gen_ctx, anchor,
MIR_new_insn (ctx, MIR_ADD, arg_var_op,
_MIR_new_hard_reg_op (ctx, R12_HARD_REG),
MIR_new_int_op (ctx, offset)));
disp += qwords * 8;
int_arg_num += qwords;
continue;
} else if (int_arg_num < 8) { /* mov arg, arg_hard_reg */
arg_reg_op = _MIR_new_hard_reg_op (ctx, R3_HARD_REG + int_arg_num);
gen_mov (gen_ctx, anchor, MIR_MOV, arg_var_op, arg_reg_op);
} else { /* mov arg, arg_memory */
set_prev_sp_op (gen_ctx, anchor, &prev_sp_op);
gen_mov (gen_ctx, anchor, MIR_MOV, arg_var_op,
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, disp, R11_HARD_REG, MIR_NON_HARD_REG, 1));
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, disp, R12_HARD_REG, MIR_NON_HARD_REG, 1));
}
disp += type == MIR_T_LD ? 16 : 8;
int_arg_num += type == MIR_T_LD ? 2 : 1;
@ -723,7 +834,7 @@ static void target_make_prolog_epilog (gen_ctx_t gen_ctx, bitmap_t used_hard_reg
isave (gen_ctx, anchor, PPC64_STACK_HEADER_SIZE + i * 8, i + R3_HARD_REG);
}
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 (!target_call_used_hard_reg_p (i, MIR_T_UNDEF) && bitmap_bit_p (used_hard_regs, i)) {
if (i < F0_HARD_REG)
saved_iregs_num++;
else
@ -757,7 +868,7 @@ static void target_make_prolog_epilog (gen_ctx_t gen_ctx, bitmap_t used_hard_reg
MIR_NON_HARD_REG, 1),
_MIR_new_hard_reg_op (ctx, R2_HARD_REG)); /* mem[r1+toc_off] = r2 */
for (n = i = 0; i <= MAX_HARD_REG; i++)
if (!target_call_used_hard_reg_p (i) && bitmap_bit_p (used_hard_regs, i)) {
if (!target_call_used_hard_reg_p (i, MIR_T_UNDEF) && bitmap_bit_p (used_hard_regs, i)) {
if (i < F0_HARD_REG)
isave (gen_ctx, anchor, start_save_regs_offset + (n++) * 8, i);
else
@ -770,7 +881,7 @@ static void target_make_prolog_epilog (gen_ctx_t gen_ctx, bitmap_t used_hard_reg
assert (anchor->code == MIR_RET);
/* Restoring hard registers: */
for (i = n = 0; i <= MAX_HARD_REG; i++)
if (!target_call_used_hard_reg_p (i) && bitmap_bit_p (used_hard_regs, i)) {
if (!target_call_used_hard_reg_p (i, MIR_T_UNDEF) && bitmap_bit_p (used_hard_regs, i)) {
if (i < F0_HARD_REG) {
gen_mov (gen_ctx, anchor, MIR_MOV, _MIR_new_hard_reg_op (ctx, i),
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, start_save_regs_offset + (n++) * 8,
@ -972,11 +1083,11 @@ static const struct pattern patterns[] = {
{MIR_LDMOV, "r mld", "o50 rt0 m; o50 nt0 mn"}, /* lfd rt,disp-mem; lfd rt+1,disp+8-mem */
{MIR_LDMOV, "mld r", "o54 rt1 m; o54 nt1 mn"}, /* stfd rt,disp-mem; stfdx rt+1,disp+8-mem */
{MIR_LDMOV, "r mld0",
"o31 O444 ha10 hs0 hb0; o50 rt0 ha10; o50 nt0 ha10 i8"}, /* mr r10,r0; lfd rt,(r10); lfd
rt+1,8(r10) */
"o31 O444 ha11 hs0 hb0; o50 rt0 ha11; o50 nt0 ha11 i8"}, /* mr r11,r0; lfd rt,(r11); lfd
rt+1,8(r11) */
{MIR_LDMOV, "mld0 r",
"o31 O444 ha10 hs0 hb0; o54 rt1 ha10; o54 nt1 ha10 i8"}, /* mr r10,r0; stfd rt,(r10); stfdx
rt+1,8(r10) */
"o31 O444 ha11 hs0 hb0; o54 rt1 ha11; o54 nt1 ha11 i8"}, /* mr r11,r0; stfd rt,(r11); stfdx
rt+1,8(r11) */
{MIR_EXT8, "r r", "o31 O954 ra0 rs1"}, /* extsb ra,rs */
{MIR_EXT16, "r r", "o31 O922 ra0 rs1"}, /* extsh ra,rs */
@ -1336,7 +1447,7 @@ static void target_get_early_clobbered_hard_regs (MIR_insn_t insn, MIR_reg_t *hr
|| code == MIR_F2I || code == MIR_D2I) {
*hr1 = F0_HARD_REG;
} else if (code == MIR_LDMOV) { /* if mem base reg is R0 */
*hr1 = R10_HARD_REG;
*hr1 = R11_HARD_REG; /* don't use arg regs as ldmov can be used in param passing part */
} else if (code == MIR_CALL || code == MIR_INLINE) {
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
*hr1 = R12_HARD_REG;

@ -62,7 +62,7 @@ static inline int target_fixed_hard_reg_p (MIR_reg_t hard_reg) {
|| hard_reg == TEMP_LDOUBLE_HARD_REG2);
}
static inline int target_call_used_hard_reg_p (MIR_reg_t hard_reg) {
static inline int target_call_used_hard_reg_p (MIR_reg_t hard_reg, MIR_type_t type) {
gen_assert (hard_reg <= MAX_HARD_REG);
return ((R0_HARD_REG <= hard_reg && hard_reg <= R5_HARD_REG) || hard_reg == R14_HARD_REG
|| (F0_HARD_REG <= hard_reg && hard_reg <= F7_HARD_REG));
@ -143,7 +143,7 @@ DEF_VARR (MIR_code_reloc_t);
struct target_ctx {
unsigned char alloca_p, leaf_p, stack_param_p, switch_p;
size_t param_save_area_size, ld_value_save_area_size;
size_t param_save_area_size, blk_ld_value_save_area_size;
VARR (int) * pattern_indexes;
VARR (insn_pattern_info_t) * insn_pattern_info;
VARR (uint8_t) * result_code;
@ -160,7 +160,7 @@ struct target_ctx {
#define stack_param_p gen_ctx->target_ctx->stack_param_p
#define switch_p gen_ctx->target_ctx->switch_p
#define param_save_area_size gen_ctx->target_ctx->param_save_area_size
#define ld_value_save_area_size gen_ctx->target_ctx->ld_value_save_area_size
#define blk_ld_value_save_area_size gen_ctx->target_ctx->blk_ld_value_save_area_size
#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
@ -176,13 +176,84 @@ static void gen_mov (gen_ctx_t gen_ctx, MIR_insn_t anchor, MIR_insn_code_t code,
gen_add_insn_before (gen_ctx, anchor, MIR_new_insn (gen_ctx->ctx, code, dst_op, src_op));
}
static void mir_blk_mov (uint64_t *to, uint64_t *from, uint64_t nwords) {
for (; nwords > 0; nwords--) *to++ = *from++;
}
static const char *BLK_MOV = "mir.blk_mov";
static const char *BLK_MOV_P = "mir.blk_mov.p";
static void gen_blk_mov (gen_ctx_t gen_ctx, MIR_insn_t anchor, size_t to_disp,
MIR_reg_t to_base_hard_reg, size_t from_disp, MIR_reg_t from_base_reg,
size_t qwords, int save_regs) {
MIR_context_t ctx = gen_ctx->ctx;
MIR_func_t func = curr_func_item->u.func;
MIR_item_t proto_item, func_import_item;
MIR_insn_t new_insn;
MIR_op_t ops[5], freg_op, treg_op, treg_op2, treg_op3;
treg_op = MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, func));
if (qwords <= 16) {
for (; qwords > 0; qwords--, to_disp += 8, from_disp += 8) {
gen_mov (gen_ctx, anchor, MIR_MOV, treg_op,
MIR_new_mem_op (ctx, MIR_T_I64, from_disp, from_base_reg, 0, 1));
gen_mov (gen_ctx, anchor, MIR_MOV,
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, to_disp, to_base_hard_reg,
MIR_NON_HARD_REG, 1),
treg_op);
}
return;
}
treg_op2 = MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, func));
treg_op3 = MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, func));
/* Save arg regs: */
if (save_regs > 0)
gen_mov (gen_ctx, anchor, MIR_MOV, treg_op, _MIR_new_hard_reg_op (ctx, R2_HARD_REG));
if (save_regs > 1)
gen_mov (gen_ctx, anchor, MIR_MOV, treg_op2, _MIR_new_hard_reg_op (ctx, R3_HARD_REG));
if (save_regs > 2)
gen_mov (gen_ctx, anchor, MIR_MOV, treg_op3, _MIR_new_hard_reg_op (ctx, R4_HARD_REG));
/* call blk move: */
proto_item = _MIR_builtin_proto (ctx, curr_func_item->module, BLK_MOV_P, 0, NULL, 3, MIR_T_I64,
"to", MIR_T_I64, "from", MIR_T_I64, "nwords");
func_import_item = _MIR_builtin_func (ctx, curr_func_item->module, BLK_MOV, mir_blk_mov);
freg_op = MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, func));
new_insn = MIR_new_insn (ctx, MIR_MOV, freg_op, MIR_new_ref_op (ctx, func_import_item));
gen_add_insn_before (gen_ctx, anchor, new_insn);
gen_add_insn_before (gen_ctx, anchor,
MIR_new_insn (gen_ctx->ctx, MIR_ADD, _MIR_new_hard_reg_op (ctx, R2_HARD_REG),
_MIR_new_hard_reg_op (ctx, to_base_hard_reg),
MIR_new_int_op (ctx, to_disp)));
gen_add_insn_before (gen_ctx, anchor,
MIR_new_insn (gen_ctx->ctx, MIR_ADD, _MIR_new_hard_reg_op (ctx, R3_HARD_REG),
MIR_new_reg_op (ctx, from_base_reg),
MIR_new_int_op (ctx, from_disp)));
gen_mov (gen_ctx, anchor, MIR_MOV, _MIR_new_hard_reg_op (ctx, R4_HARD_REG),
MIR_new_int_op (ctx, qwords));
ops[0] = MIR_new_ref_op (ctx, proto_item);
ops[1] = freg_op;
ops[2] = _MIR_new_hard_reg_op (ctx, R2_HARD_REG);
ops[3] = _MIR_new_hard_reg_op (ctx, R3_HARD_REG);
ops[4] = _MIR_new_hard_reg_op (ctx, R4_HARD_REG);
new_insn = MIR_new_insn_arr (ctx, MIR_CALL, 5, ops);
gen_add_insn_before (gen_ctx, anchor, new_insn);
/* Restore arg regs: */
if (save_regs > 0)
gen_mov (gen_ctx, anchor, MIR_MOV, _MIR_new_hard_reg_op (ctx, R2_HARD_REG), treg_op);
if (save_regs > 1)
gen_mov (gen_ctx, anchor, MIR_MOV, _MIR_new_hard_reg_op (ctx, R3_HARD_REG), treg_op2);
if (save_regs > 2)
gen_mov (gen_ctx, anchor, MIR_MOV, _MIR_new_hard_reg_op (ctx, R4_HARD_REG), treg_op3);
}
static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_insn) {
MIR_context_t ctx = gen_ctx->ctx;
MIR_func_t func = curr_func_item->u.func;
MIR_proto_t proto = call_insn->ops[0].u.ref->u.proto;
int vararg_p = proto->vararg_p;
size_t nargs, nops = MIR_insn_nops (ctx, call_insn), start = proto->nres + 2;
size_t param_mem_size, call_ld_value_area_size, ld_n_iregs, n_iregs, n_fregs, ld_value_disp;
size_t param_mem_size, call_blk_ld_value_area_size, ld_n_iregs, n_iregs, n_fregs;
size_t qwords, blk_ld_value_disp;
MIR_type_t type, mem_type;
MIR_op_mode_t mode;
MIR_var_t *arg_vars = NULL;
@ -206,15 +277,19 @@ static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_insn) {
call_insn->ops[1] = temp_op;
gen_add_insn_before (gen_ctx, call_insn, new_insn);
}
n_iregs = n_fregs = param_mem_size = call_ld_value_area_size = 0;
n_iregs = n_fregs = param_mem_size = call_blk_ld_value_area_size = 0;
for (size_t i = 2; i < nops; i++) {
/* process long double results and args to calculate memory for them: */
arg_op = call_insn->ops[i];
/* process long double results and ld and block args to calculate memory for them: */
if (i < start) {
type = proto->res_types[i - 2];
} else if (i - start < nargs) {
type = arg_vars[i - start].type;
} else if (arg_op.mode == MIR_OP_MEM) {
type = MIR_T_BLK;
gen_assert (arg_op.u.mem.type == type);
} else {
mode = call_insn->ops[i].value_mode; // ??? smaller ints
mode = arg_op.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)
@ -223,7 +298,12 @@ static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_insn) {
type = mode == MIR_OP_DOUBLE ? MIR_T_D : mode == MIR_OP_LDOUBLE ? MIR_T_LD : MIR_T_I64;
}
if (type != MIR_T_LD && i < start) continue;
if (type == MIR_T_LD) call_ld_value_area_size += 16;
if (type == MIR_T_LD)
call_blk_ld_value_area_size += 16;
else if (type == MIR_T_BLK) {
gen_assert (arg_op.mode == MIR_OP_MEM && arg_op.u.mem.disp >= 0 && arg_op.u.mem.index == 0);
call_blk_ld_value_area_size += (arg_op.u.mem.disp + 7) / 8 * 8;
}
if ((type == MIR_T_F || type == MIR_T_D) && n_fregs < 4) {
/* put arguments to argument hard regs: */
n_fregs++;
@ -234,17 +314,21 @@ static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_insn) {
}
}
if (param_save_area_size < param_mem_size) param_save_area_size = param_mem_size;
if (ld_value_save_area_size < call_ld_value_area_size)
ld_value_save_area_size = call_ld_value_area_size;
ld_value_disp = param_mem_size;
if (blk_ld_value_save_area_size < call_blk_ld_value_area_size)
blk_ld_value_save_area_size = call_blk_ld_value_area_size;
blk_ld_value_disp = param_mem_size;
param_mem_size = n_fregs = n_iregs = 0;
for (size_t i = 2; i < nops; i++) { /* process args and ???long double results: */
arg_op = call_insn->ops[i];
gen_assert (arg_op.mode == MIR_OP_REG || arg_op.mode == MIR_OP_HARD_REG);
gen_assert (arg_op.mode == MIR_OP_REG || arg_op.mode == MIR_OP_HARD_REG
|| (arg_op.mode == MIR_OP_MEM && arg_op.u.mem.type == MIR_T_BLK));
if (i < start) {
type = proto->res_types[i - 2];
} else if (i - start < nargs) {
type = arg_vars[i - start].type;
} else if (call_insn->ops[i].mode == MIR_OP_MEM) {
type = MIR_T_BLK;
gen_assert (call_insn->ops[i].u.mem.type == type);
} else {
mode = call_insn->ops[i].value_mode; // ??? smaller ints
gen_assert (mode == MIR_OP_INT || mode == MIR_OP_UINT || mode == MIR_OP_DOUBLE
@ -258,17 +342,24 @@ static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_insn) {
ext_insn = MIR_new_insn (ctx, ext_code, temp_op, arg_op);
call_insn->ops[i] = arg_op = temp_op;
}
if (type == MIR_T_LD) {
if (i >= start) { /* put arg value in saved ld value area: */
mem_op = _MIR_new_hard_reg_mem_op (ctx, MIR_T_LD, ld_value_disp + S390X_STACK_HEADER_SIZE,
FP_HARD_REG, MIR_NON_HARD_REG, 1);
gen_mov (gen_ctx, call_insn, MIR_LDMOV, mem_op, arg_op);
if (type == MIR_T_LD || type == MIR_T_BLK) {
if (i >= start) { /* put arg value in saved blk/ld value area: */
if (type == MIR_T_LD) {
mem_op
= _MIR_new_hard_reg_mem_op (ctx, MIR_T_LD, blk_ld_value_disp + S390X_STACK_HEADER_SIZE,
FP_HARD_REG, MIR_NON_HARD_REG, 1);
gen_mov (gen_ctx, call_insn, MIR_LDMOV, mem_op, arg_op);
} else {
qwords = (arg_op.u.mem.disp + 7) / 8;
gen_blk_mov (gen_ctx, call_insn, S390X_STACK_HEADER_SIZE + blk_ld_value_disp, FP_HARD_REG,
0, arg_op.u.mem.base, qwords, n_iregs);
}
}
arg_op = MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, func));
new_insn = MIR_new_insn (ctx, MIR_ADD, arg_op, _MIR_new_hard_reg_op (ctx, FP_HARD_REG),
MIR_new_int_op (ctx, S390X_STACK_HEADER_SIZE + ld_value_disp));
MIR_new_int_op (ctx, S390X_STACK_HEADER_SIZE + blk_ld_value_disp));
gen_add_insn_before (gen_ctx, call_insn, new_insn);
ld_value_disp += 16;
blk_ld_value_disp += type == MIR_T_LD ? 16 : qwords * 8;
}
mem_type = type == MIR_T_F || type == MIR_T_D ? type : MIR_T_I64;
if ((type == MIR_T_F || type == MIR_T_D) && n_fregs < 4) {
@ -295,7 +386,7 @@ static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_insn) {
}
}
ld_n_iregs = n_iregs = n_fregs = 0;
ld_value_disp = param_mem_size;
blk_ld_value_disp = param_mem_size;
for (size_t i = 0; i < proto->nres; i++) {
ret_op = call_insn->ops[i + 2];
gen_assert (ret_op.mode == MIR_OP_REG || ret_op.mode == MIR_OP_HARD_REG);
@ -303,14 +394,14 @@ static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_insn) {
if (type == MIR_T_LD) { /* returned by address */
new_insn_code = MIR_LDMOV;
call_res_op = ret_val_op
= _MIR_new_hard_reg_mem_op (ctx, MIR_T_LD, S390X_STACK_HEADER_SIZE + ld_value_disp,
= _MIR_new_hard_reg_mem_op (ctx, MIR_T_LD, S390X_STACK_HEADER_SIZE + blk_ld_value_disp,
FP_HARD_REG, MIR_NON_HARD_REG, 1);
if (n_iregs < 5) { /* use it as a call result to keep assignment to ld_n_iregs: */
call_res_op = _MIR_new_hard_reg_mem_op (ctx, MIR_T_LD, 0, R2_HARD_REG + ld_n_iregs,
MIR_NON_HARD_REG, 1);
ld_n_iregs++;
}
ld_value_disp += 16;
blk_ld_value_disp += 16;
} else if ((type == MIR_T_F || type == MIR_T_D) && n_fregs < 4) {
new_insn_code = type == MIR_T_F ? MIR_FMOV : MIR_DMOV;
call_res_op = ret_val_op = _MIR_new_hard_reg_op (ctx, F0_HARD_REG + n_fregs * 2);
@ -386,6 +477,8 @@ 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 const char *VA_STACK_ARG_P = "mir.va_stack_arg.p";
static const char *VA_STACK_ARG = "mir.va_stack_arg";
static int64_t mir_ldeq (long double d1, long double d2) { return d1 == d2; }
static const char *LDEQ = "mir.ldeq";
@ -532,6 +625,13 @@ static int get_builtin (gen_ctx_t gen_ctx, MIR_insn_code_t code, MIR_item_t *pro
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;
case MIR_VA_STACK_ARG:
res_type = MIR_T_I64;
*proto_item = _MIR_builtin_proto (ctx, curr_func_item->module, VA_STACK_ARG_P, 1, &res_type, 2,
MIR_T_I64, "va", MIR_T_I64, "size");
*func_import_item
= _MIR_builtin_func (ctx, curr_func_item->module, VA_STACK_ARG, va_stack_arg_builtin);
return 2;
default: return 0;
}
}
@ -540,7 +640,7 @@ static MIR_disp_t target_get_stack_slot_offset (gen_ctx_t gen_ctx, MIR_type_t ty
MIR_reg_t slot) {
/* slot is 0, 1, ... */
return ((MIR_disp_t) slot * 8 + S390X_STACK_HEADER_SIZE + param_save_area_size
+ ld_value_save_area_size);
+ blk_ld_value_save_area_size);
}
static void set_prev_sp_reg (gen_ctx_t gen_ctx, MIR_insn_t anchor, int *prev_sp_set_p,
@ -627,7 +727,7 @@ static void target_machinize (gen_ctx_t gen_ctx) {
stack_param_p = disp != 0;
switch_p = alloca_p = FALSE;
leaf_p = TRUE;
param_save_area_size = ld_value_save_area_size = 0;
param_save_area_size = blk_ld_value_save_area_size = 0;
for (insn = DLIST_HEAD (MIR_insn_t, func->insns); insn != NULL; insn = next_insn) {
MIR_item_t proto_item, func_import_item;
int nargs;
@ -815,7 +915,7 @@ static void target_make_prolog_epilog (gen_ctx_t gen_ctx, bitmap_t used_hard_reg
fsave (gen_ctx, anchor, S390X_FP_REG_ARG_SAVE_AREA_START + i * 8, i * 2 + F0_HARD_REG);
}
for (i = 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 (!target_call_used_hard_reg_p (i, MIR_T_UNDEF) && bitmap_bit_p (used_hard_regs, i)) {
saved_regs_p = TRUE;
if (i >= F0_HARD_REG) saved_fregs_num++;
}
@ -825,7 +925,7 @@ static void target_make_prolog_epilog (gen_ctx_t gen_ctx, bitmap_t used_hard_reg
r14_reg_op = _MIR_new_hard_reg_op (ctx, R14_HARD_REG);
r15_reg_op = _MIR_new_hard_reg_op (ctx, R15_HARD_REG);
/* Prologue: */
frame_size = (param_save_area_size + S390X_STACK_HEADER_SIZE + ld_value_save_area_size
frame_size = (param_save_area_size + S390X_STACK_HEADER_SIZE + blk_ld_value_save_area_size
+ stack_slots_num * 8);
start_saved_fregs_offset = frame_size;
frame_size += saved_fregs_num * 8;
@ -839,7 +939,7 @@ static void target_make_prolog_epilog (gen_ctx_t gen_ctx, bitmap_t used_hard_reg
R15_HARD_REG, MIR_NON_HARD_REG, 1),
r11_reg_op); /* mem[r15+76] = r11 */
for (i = R2_HARD_REG; i < R15_HARD_REG; i++) /* exclude r15 */
if (!target_call_used_hard_reg_p (i) && bitmap_bit_p (used_hard_regs, i)
if (!target_call_used_hard_reg_p (i, MIR_T_UNDEF) && bitmap_bit_p (used_hard_regs, i)
&& (i != 6 || !func->vararg_p))
isave (gen_ctx, anchor, S390X_GP_REG_RSAVE_AREA_START + (i - R2_HARD_REG) * 8, i);
gen_mov (gen_ctx, anchor, MIR_MOV, r0_reg_op, r15_reg_op); /* r0 = r15 */
@ -849,7 +949,7 @@ static void target_make_prolog_epilog (gen_ctx_t gen_ctx, bitmap_t used_hard_reg
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, 0, R15_HARD_REG, MIR_NON_HARD_REG, 1),
r0_reg_op); /* mem[r15] = r0 */
for (n = 0, i = F0_HARD_REG; i <= MAX_HARD_REG; i++)
if (!target_call_used_hard_reg_p (i) && bitmap_bit_p (used_hard_regs, i))
if (!target_call_used_hard_reg_p (i, MIR_T_UNDEF) && bitmap_bit_p (used_hard_regs, i))
fsave (gen_ctx, anchor, start_saved_fregs_offset + (n++) * 8, i);
gen_mov (gen_ctx, anchor, MIR_MOV, r11_reg_op, r15_reg_op); /* r11 = r15 */
/* Epilogue: */
@ -857,7 +957,7 @@ static void target_make_prolog_epilog (gen_ctx_t gen_ctx, bitmap_t used_hard_reg
gen_assert (anchor->code == MIR_RET || anchor->code == MIR_JMP);
/* Restoring fp hard registers: */
for (n = 0, i = F0_HARD_REG; i <= MAX_HARD_REG; i++)
if (!target_call_used_hard_reg_p (i) && bitmap_bit_p (used_hard_regs, i))
if (!target_call_used_hard_reg_p (i, MIR_T_UNDEF) && bitmap_bit_p (used_hard_regs, i))
gen_mov (gen_ctx, anchor, MIR_DMOV, _MIR_new_hard_reg_op (ctx, i),
_MIR_new_hard_reg_mem_op (ctx, MIR_T_D, start_saved_fregs_offset + (n++) * 8,
R11_HARD_REG, MIR_NON_HARD_REG, 1));
@ -865,7 +965,7 @@ static void target_make_prolog_epilog (gen_ctx_t gen_ctx, bitmap_t used_hard_reg
gen_add_insn_before (gen_ctx, anchor, new_insn); /* r15 = r11 + frame_size */
/* Restore saved gp regs (including r11 and excluding r15) and r14 */
for (i = R2_HARD_REG; i < R15_HARD_REG; i++)
if (!target_call_used_hard_reg_p (i) && bitmap_bit_p (used_hard_regs, i))
if (!target_call_used_hard_reg_p (i, MIR_T_UNDEF) && bitmap_bit_p (used_hard_regs, i))
gen_mov (gen_ctx, anchor, MIR_MOV, _MIR_new_hard_reg_op (ctx, i),
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64,
S390X_GP_REG_RSAVE_AREA_START + (i - R2_HARD_REG) * 8,

@ -53,7 +53,7 @@ static inline int target_fixed_hard_reg_p (MIR_reg_t hard_reg) {
|| hard_reg == ST1_HARD_REG);
}
static inline int target_call_used_hard_reg_p (MIR_reg_t hard_reg) {
static inline int target_call_used_hard_reg_p (MIR_reg_t hard_reg, MIR_type_t type) {
assert (hard_reg <= MAX_HARD_REG);
#ifndef _WIN64
return !(hard_reg == BX_HARD_REG || (hard_reg >= R12_HARD_REG && hard_reg <= R15_HARD_REG));
@ -226,9 +226,13 @@ static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_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);
gen_assert (arg_op.mode == MIR_OP_REG || arg_op.mode == MIR_OP_HARD_REG
|| (arg_op.mode == MIR_OP_MEM && arg_op.u.mem.type == MIR_T_BLK)
|| (arg_op.mode == MIR_OP_HARD_REG_MEM && arg_op.u.hard_reg_mem.type == MIR_T_BLK));
if (i - start < nargs) {
type = arg_vars[i - start].type;
} else if (arg_op.mode == MIR_OP_MEM || arg_op.mode == MIR_OP_HARD_REG_MEM) {
type = MIR_T_BLK;
} else {
mode = call_insn->ops[i].value_mode; // ??? smaller ints
gen_assert (mode == MIR_OP_INT || mode == MIR_OP_UINT || mode == MIR_OP_FLOAT
@ -245,8 +249,70 @@ static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_insn) {
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) {
if (type == MIR_T_BLK) { /* put block arg on the stack */
MIR_insn_t load_insn;
size_t size, disp;
int first_p;
gen_assert (arg_op.mode == MIR_OP_MEM);
size = (arg_op.u.mem.disp + 7) / 8 * 8;
gen_assert (prev_call_insn != NULL); /* call_insn should not be 1st after simplification */
if (size > 0 && size <= 8 * 8) { /* upto 8 moves */
disp = 0;
first_p = TRUE;
temp_op = MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, func));
while (size != 0) {
mem_op = MIR_new_mem_op (ctx, MIR_T_I64, disp, arg_op.u.mem.base, 0, 1);
load_insn = MIR_new_insn (ctx, MIR_MOV, temp_op, mem_op);
gen_add_insn_after (gen_ctx, prev_call_insn, load_insn);
disp += 8;
mem_op
= _MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, mem_size, SP_HARD_REG, MIR_NON_HARD_REG, 1);
new_insn = MIR_new_insn (ctx, MIR_MOV, mem_op, temp_op);
mem_size += 8;
size -= 8;
gen_add_insn_after (gen_ctx, load_insn, new_insn);
if (first_p) {
call_insn->ops[i] = _MIR_new_hard_reg_mem_op (ctx, MIR_T_BLK, mem_size, SP_HARD_REG,
MIR_NON_HARD_REG, 1);
first_p = FALSE;
}
}
} else { /* generate memcpy call before call arg moves */
MIR_reg_t dest_reg;
MIR_op_t freg_op, dest_reg_op, ops[5];
MIR_item_t memcpy_proto_item
= _MIR_builtin_proto (ctx, curr_func_item->module, "mir.arg_memcpy.p", 0, NULL, 3,
MIR_T_I64, "dest", MIR_T_I64, "src", MIR_T_I64, "n");
MIR_item_t memcpy_import_item
= _MIR_builtin_func (ctx, curr_func_item->module, "mir.arg_memcpy", memcpy);
freg_op
= MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, curr_func_item->u.func));
dest_reg = gen_new_temp_reg (gen_ctx, MIR_T_I64, curr_func_item->u.func);
dest_reg_op = MIR_new_reg_op (ctx, dest_reg);
ops[0] = MIR_new_ref_op (ctx, memcpy_proto_item);
ops[1] = freg_op;
ops[2] = _MIR_new_hard_reg_op (ctx, get_int_arg_reg (0));
ops[3] = _MIR_new_hard_reg_op (ctx, get_int_arg_reg (1));
ops[4] = _MIR_new_hard_reg_op (ctx, get_int_arg_reg (2));
new_insn = MIR_new_insn_arr (ctx, MIR_CALL, 5, ops);
gen_add_insn_after (gen_ctx, prev_call_insn, new_insn);
new_insn = MIR_new_insn (ctx, MIR_MOV, ops[4], MIR_new_int_op (ctx, size));
gen_add_insn_after (gen_ctx, prev_call_insn, new_insn);
new_insn = MIR_new_insn (ctx, MIR_MOV, ops[3], MIR_new_reg_op (ctx, arg_op.u.mem.base));
gen_add_insn_after (gen_ctx, prev_call_insn, new_insn);
new_insn = MIR_new_insn (ctx, MIR_MOV, ops[2], dest_reg_op);
gen_add_insn_after (gen_ctx, prev_call_insn, new_insn);
new_insn = MIR_new_insn (ctx, MIR_ADD, dest_reg_op, _MIR_new_hard_reg_op (ctx, SP_HARD_REG),
MIR_new_int_op (ctx, mem_size));
gen_add_insn_after (gen_ctx, prev_call_insn, new_insn);
new_insn = MIR_new_insn (ctx, MIR_MOV, ops[1], MIR_new_ref_op (ctx, memcpy_import_item));
gen_add_insn_after (gen_ctx, prev_call_insn, new_insn);
call_insn->ops[i] = MIR_new_mem_op (ctx, MIR_T_BLK, arg_op.u.mem.disp, dest_reg, 0, 1);
mem_size += size;
}
} else 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 (gen_ctx, call_insn, ext_insn);
arg_reg_op = _MIR_new_hard_reg_op (ctx, arg_reg);
@ -366,6 +432,8 @@ static const char *LD2I_P = "mir.ld2i.p";
static const char *VA_ARG_P = "mir.va_arg.p";
static const char *VA_ARG = "mir.va_arg";
static const char *VA_STACK_ARG_P = "mir.va_stack_arg.p";
static const char *VA_STACK_ARG = "mir.va_stack_arg";
static void get_builtin (gen_ctx_t gen_ctx, MIR_insn_code_t code, MIR_item_t *proto_item,
MIR_item_t *func_import_item) {
@ -404,6 +472,13 @@ static void get_builtin (gen_ctx_t gen_ctx, MIR_insn_code_t code, MIR_item_t *pr
MIR_T_I64, "va", MIR_T_I64, "type");
*func_import_item = _MIR_builtin_func (ctx, curr_func_item->module, VA_ARG, va_arg_builtin);
break;
case MIR_VA_STACK_ARG:
res_type = MIR_T_I64;
*proto_item = _MIR_builtin_proto (ctx, curr_func_item->module, VA_STACK_ARG_P, 1, &res_type, 2,
MIR_T_I64, "va", MIR_T_I64, "size");
*func_import_item
= _MIR_builtin_func (ctx, curr_func_item->module, VA_STACK_ARG, va_stack_arg_builtin);
break;
default: assert (FALSE);
}
}
@ -489,10 +564,20 @@ static void target_machinize (gen_ctx_t gen_ctx) {
start_sp_from_bp_offset = 8;
for (i = 0; i < func->nargs; i++) {
/* Argument extensions is already done in simplify */
/* Prologue: generate arg_var = hard_reg|stack mem ... */
/* Prologue: generate arg_var = hard_reg|stack mem|stack addr ... */
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) {
if (type == MIR_T_BLK) {
stack_arg_func_p = TRUE;
new_insn = MIR_new_insn (ctx, MIR_ADD, MIR_new_reg_op (ctx, i + 1),
_MIR_new_hard_reg_op (ctx, FP_HARD_REG),
MIR_new_int_op (ctx, mem_size + 8 /* ret */
+ start_sp_from_bp_offset));
MIR_prepend_insn (ctx, curr_func_item, new_insn);
next_insn = DLIST_NEXT (MIR_insn_t, new_insn);
create_new_bb_insns (gen_ctx, NULL, next_insn, NULL);
mem_size += (VARR_GET (MIR_var_t, func->vars, i).size + 7) / 8 * 8;
} else if ((arg_reg = get_arg_reg (type, &int_arg_num, &fp_arg_num, &new_insn_code))
!= MIR_NON_HARD_REG) {
arg_reg_op = _MIR_new_hard_reg_op (ctx, arg_reg);
new_insn = MIR_new_insn (ctx, new_insn_code, MIR_new_reg_op (ctx, i + 1), arg_reg_op);
MIR_prepend_insn (ctx, curr_func_item, new_insn);
@ -544,16 +629,23 @@ static void target_machinize (gen_ctx_t gen_ctx) {
MIR_op_t va_op = insn->ops[0];
MIR_reg_t va_reg;
#ifndef _WIN64
int gp_offset = 0, fp_offset = 48;
int gp_offset = 0, fp_offset = 48, mem_offset = 0;
MIR_var_t var;
assert (func->vararg_p && (va_op.mode == MIR_OP_REG || va_op.mode == MIR_OP_HARD_REG));
for (uint32_t i = 0; i < func->nargs; i++) {
var = VARR_GET (MIR_var_t, func->vars, i);
if (var.type == MIR_T_F || var.type == MIR_T_D)
if (var.type == MIR_T_F || var.type == MIR_T_D) {
fp_offset += 16;
else
if (gp_offset >= 176) mem_offset += 8;
} else if (var.type == MIR_T_LD) {
mem_offset += 16;
} else if (var.type == MIR_T_BLK) {
mem_offset += var.size;
} else {
gp_offset += 8;
if (gp_offset >= 48) mem_offset += 8;
}
}
va_reg = va_op.mode == MIR_OP_REG ? va_op.u.reg : va_op.u.hard_reg;
/* Insns can be not simplified as soon as they match a machine insn. */
@ -563,9 +655,10 @@ static void target_machinize (gen_ctx_t gen_ctx) {
next_insn = DLIST_PREV (MIR_insn_t, insn);
gen_mov (gen_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, FP_HARD_REG),
MIR_new_int_op (ctx, 8 /*ret*/ + start_sp_from_bp_offset));
/* overflow_arg_area_reg: treg = start sp + 8 + mem_offset; mem64[va_reg + 8] = treg */
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*/ + mem_offset + start_sp_from_bp_offset));
gen_add_insn_before (gen_ctx, insn, new_insn);
gen_mov (gen_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 */
@ -596,33 +689,35 @@ static void target_machinize (gen_ctx_t gen_ctx) {
gen_delete_insn (gen_ctx, insn);
} else if (code == MIR_VA_END) { /* do nothing */
gen_delete_insn (gen_ctx, insn);
} else if (code == MIR_VA_ARG) { /* do nothing */
} else if (code == MIR_VA_ARG || code == MIR_VA_STACK_ARG) {
#ifndef _WIN64
/* Use a builtin func call:
mov func_reg, func ref; mov flag_reg, <0|1>; call proto, func_reg, res_reg, va_reg,
flag_reg */
mov func_reg, func ref; [mov reg3, type;] call proto, func_reg, res_reg, va_reg,
reg3 */
MIR_item_t proto_item, func_import_item;
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];
MIR_op_t ops[5], func_reg_op, reg_op3;
MIR_op_t res_reg_op = insn->ops[0], va_reg_op = insn->ops[1], op3 = insn->ops[2];
get_builtin (gen_ctx, code, &proto_item, &func_import_item);
assert (res_reg_op.mode == MIR_OP_REG && va_reg_op.mode == MIR_OP_REG
&& mem_op.mode == MIR_OP_MEM);
&& op3.mode == (code == MIR_VA_ARG ? MIR_OP_MEM : MIR_OP_REG));
func_reg_op
= MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, curr_func_item->u.func));
flag_reg_op
= MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, curr_func_item->u.func));
reg_op3 = MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, curr_func_item->u.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 (gen_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 (gen_ctx, insn, new_insn);
if (code == MIR_VA_ARG) {
new_insn
= MIR_new_insn (ctx, MIR_MOV, reg_op3, MIR_new_int_op (ctx, (int64_t) op3.u.mem.type));
op3 = reg_op3;
gen_add_insn_before (gen_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;
ops[4] = op3;
new_insn = MIR_new_insn_arr (ctx, MIR_CALL, 5, ops);
gen_add_insn_before (gen_ctx, insn, new_insn);
#else
@ -753,11 +848,11 @@ static void target_make_prolog_epilog (gen_ctx_t gen_ctx, bitmap_t used_hard_reg
assert (curr_func_item->item_type == MIR_func_item);
func = curr_func_item->u.func;
for (i = saved_hard_regs_size = 0; i <= R15_HARD_REG; i++)
if (!target_call_used_hard_reg_p (i) && bitmap_bit_p (used_hard_regs, i))
if (!target_call_used_hard_reg_p (i, MIR_T_UNDEF) && bitmap_bit_p (used_hard_regs, i))
saved_hard_regs_size += 8;
#ifdef _WIN64
for (; i <= XMM15_HARD_REG; i++)
if (!target_call_used_hard_reg_p (i) && bitmap_bit_p (used_hard_regs, i))
if (!target_call_used_hard_reg_p (i, MIR_T_UNDEF) && bitmap_bit_p (used_hard_regs, i))
saved_hard_regs_size += 16;
#endif
if (leaf_p && !alloca_p && !stack_arg_func_p && saved_hard_regs_size == 0 && !func->vararg_p
@ -807,7 +902,7 @@ static void target_make_prolog_epilog (gen_ctx_t gen_ctx, bitmap_t used_hard_reg
offset = -bp_saved_reg_offset;
#ifdef _WIN64
for (i = XMM0_HARD_REG; i <= XMM15_HARD_REG; i++)
if (!target_call_used_hard_reg_p (i) && bitmap_bit_p (used_hard_regs, i)) {
if (!target_call_used_hard_reg_p (i, MIR_T_UNDEF) && bitmap_bit_p (used_hard_regs, i)) {
new_insn = _MIR_new_unspec_insn (ctx, 3, MIR_new_int_op (ctx, MOVDQA_CODE),
_MIR_new_hard_reg_mem_op (ctx, MIR_T_D, offset, FP_HARD_REG,
MIR_NON_HARD_REG, 1),
@ -817,7 +912,7 @@ static void target_make_prolog_epilog (gen_ctx_t gen_ctx, bitmap_t used_hard_reg
}
#endif
for (i = 0; i <= R15_HARD_REG; i++)
if (!target_call_used_hard_reg_p (i) && bitmap_bit_p (used_hard_regs, i)) {
if (!target_call_used_hard_reg_p (i, MIR_T_UNDEF) && bitmap_bit_p (used_hard_regs, i)) {
new_insn = MIR_new_insn (ctx, MIR_MOV,
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, offset, FP_HARD_REG,
MIR_NON_HARD_REG, 1),
@ -831,7 +926,7 @@ static void target_make_prolog_epilog (gen_ctx_t gen_ctx, bitmap_t used_hard_reg
offset = -bp_saved_reg_offset;
#ifdef _WIN64
for (i = XMM0_HARD_REG; i <= XMM15_HARD_REG; i++)
if (!target_call_used_hard_reg_p (i) && bitmap_bit_p (used_hard_regs, i)) {
if (!target_call_used_hard_reg_p (i, MIR_T_UNDEF) && bitmap_bit_p (used_hard_regs, i)) {
new_insn = _MIR_new_unspec_insn (ctx, 3, MIR_new_int_op (ctx, MOVDQA_CODE),
_MIR_new_hard_reg_op (ctx, i),
_MIR_new_hard_reg_mem_op (ctx, MIR_T_D, offset, FP_HARD_REG,
@ -841,7 +936,7 @@ static void target_make_prolog_epilog (gen_ctx_t gen_ctx, bitmap_t used_hard_reg
}
#endif
for (i = 0; i <= R15_HARD_REG; i++)
if (!target_call_used_hard_reg_p (i) && bitmap_bit_p (used_hard_regs, i)) {
if (!target_call_used_hard_reg_p (i, MIR_T_UNDEF) && 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, offset, FP_HARD_REG,
MIR_NON_HARD_REG, 1));

@ -153,7 +153,7 @@ struct gen_ctx {
FILE *debug_file;
#endif
bitmap_t insn_to_consider, temp_bitmap, temp_bitmap2;
bitmap_t call_used_hard_regs, func_used_hard_regs;
bitmap_t call_used_hard_regs[MIR_T_BOUND], func_used_hard_regs;
func_cfg_t curr_cfg;
size_t curr_bb_index, curr_loop_node_index;
struct target_ctx *target_ctx;
@ -1009,6 +1009,9 @@ static void output_bitmap (gen_ctx_t gen_ctx, const char *head, bitmap_t bm, int
static void print_bb_insn (gen_ctx_t gen_ctx, bb_insn_t bb_insn, int with_notes_p) {
MIR_context_t ctx = gen_ctx->ctx;
MIR_op_t op;
int first_p;
size_t nel;
bitmap_iterator_t bi;
MIR_output_insn (ctx, debug_file, bb_insn->insn, curr_func_item->u.func, FALSE);
if (with_notes_p) {
@ -1024,6 +1027,13 @@ static void print_bb_insn (gen_ctx_t gen_ctx, bb_insn_t bb_insn, int with_notes_
fprintf (debug_file, dv == DLIST_HEAD (dead_var_t, bb_insn->dead_vars) ? " # dead: " : " ");
MIR_output_op (ctx, debug_file, op, curr_func_item->u.func);
}
if (MIR_call_code_p (bb_insn->insn->code)) {
first_p = TRUE;
FOREACH_BITMAP_BIT (bi, bb_insn->call_hard_reg_args, nel) {
fprintf (debug_file, first_p ? " # call used: hr%ld" : " hr%ld", (unsigned long) nel);
first_p = FALSE;
}
}
}
fprintf (debug_file, "\n");
}
@ -1617,7 +1627,7 @@ static void create_av_bitmaps (gen_ctx_t gen_ctx) {
FOREACH_BITMAP_BIT (bi, bb_insn->call_hard_reg_args, nel) {
make_obsolete_var_exprs (gen_ctx, nel);
}
FOREACH_BITMAP_BIT (bi, call_used_hard_regs, nel) {
FOREACH_BITMAP_BIT (bi, call_used_hard_regs[MIR_T_UNDEF], nel) {
make_obsolete_var_exprs (gen_ctx, nel);
}
bitmap_and_compl (bb->av_gen, bb->av_gen, memory_exprs);
@ -1720,7 +1730,7 @@ static void cse_modify (gen_ctx_t gen_ctx) {
FOREACH_BITMAP_BIT (bi, bb_insn->call_hard_reg_args, nel) {
make_obsolete_var_exprs (gen_ctx, nel);
}
FOREACH_BITMAP_BIT (bi, call_used_hard_regs, nel) {
FOREACH_BITMAP_BIT (bi, call_used_hard_regs[MIR_T_UNDEF], nel) {
make_obsolete_var_exprs (gen_ctx, nel);
}
bitmap_and_compl (av, av, memory_exprs);
@ -3853,8 +3863,8 @@ static size_t initiate_bb_live_info (gen_ctx_t gen_ctx, bb_t bb, int moves_p) {
bb_insn = DLIST_PREV (bb_insn_t, bb_insn)) {
insn = bb_insn->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);
bitmap_ior (bb->live_kill, bb->live_kill, call_used_hard_regs[MIR_T_UNDEF]);
bitmap_and_compl (bb->live_gen, bb->live_gen, call_used_hard_regs[MIR_T_UNDEF]);
}
/* Process output ops on 0-th iteration, then input ops. */
for (niter = 0; niter <= 1; niter++) {
@ -3972,7 +3982,7 @@ static void add_bb_insn_dead_vars (gen_ctx_t gen_ctx) {
FOREACH_INSN_VAR (gen_ctx, insn_var_iter, insn, var, op_num, 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);
if (MIR_call_code_p (insn->code)) bitmap_and_compl (live, live, call_used_hard_regs[MIR_T_UNDEF]);
FOREACH_INSN_VAR (gen_ctx, insn_var_iter, insn, var, op_num, out_p, mem_p, passed_mem_num) {
if (out_p) continue;
if (bitmap_set_bit_p (live, var)) add_bb_insn_dead_var (gen_ctx, bb_insn, var);
@ -4171,7 +4181,7 @@ static void build_live_ranges (gen_ctx_t gen_ctx) {
if (out_p) incr_p |= make_var_dead (gen_ctx, var, curr_point);
}
if (MIR_call_code_p (insn->code)) {
FOREACH_BITMAP_BIT (bi, call_used_hard_regs, nel) {
FOREACH_BITMAP_BIT (bi, call_used_hard_regs[MIR_T_UNDEF], nel) {
make_var_dead (gen_ctx, nel, curr_point);
}
FOREACH_BITMAP_BIT (bi, bb_insn->call_hard_reg_args, nel) {
@ -4422,7 +4432,7 @@ static void assign (gen_ctx_t gen_ctx) {
best_profit = 0;
type = MIR_reg_type (gen_ctx->ctx, reg, curr_func_item->u.func);
if (curr_breg_infos[breg].calls_num > 0)
bitmap_ior (conflict_locs, conflict_locs, call_used_hard_regs);
bitmap_ior (conflict_locs, conflict_locs, call_used_hard_regs[type]);
for (loc = 0; loc <= MAX_HARD_REG; loc++) {
if (bitmap_bit_p (conflict_locs, loc)) continue;
if (!target_hard_reg_type_ok_p (loc, type) || target_fixed_hard_reg_p (loc)) continue;
@ -5200,7 +5210,7 @@ static void combine (gen_ctx_t gen_ctx) {
TRUE);
if (MIR_call_code_p (code = insn->code)) {
for (size_t hr = 0; hr <= MAX_HARD_REG; hr++)
if (bitmap_bit_p (call_used_hard_regs, hr)) {
if (bitmap_bit_p (call_used_hard_regs[MIR_T_UNDEF], hr)) {
setup_hreg_ref (gen_ctx, hr, insn, 0 /* whatever */, curr_insn_num, TRUE);
}
} else if (code == MIR_RET) {
@ -5328,7 +5338,7 @@ static void dead_code_elimination (gen_ctx_t gen_ctx) {
gen_delete_insn (gen_ctx, insn);
continue;
}
if (MIR_call_code_p (insn->code)) bitmap_and_compl (live, live, call_used_hard_regs);
if (MIR_call_code_p (insn->code)) bitmap_and_compl (live, live, call_used_hard_regs[MIR_T_UNDEF]);
FOREACH_INSN_VAR (gen_ctx, insn_var_iter, insn, var, op_num, out_p, mem_p, passed_mem_num) {
if (!out_p) bitmap_set_bit_p (live, var);
}
@ -5710,7 +5720,7 @@ static MIR_reg_t assign_to_loc (gen_ctx_t gen_ctx, insn_var_t *insn_var_ref, int
}
}
if (live_before_p && live_after_p && MIR_call_code_p (insn->code)) {
bitmap_ior (blocked_hard_regs, blocked_hard_regs, call_used_hard_regs);
bitmap_ior (blocked_hard_regs, blocked_hard_regs, call_used_hard_regs[MIR_T_UNDEF]);
}
hreg = out_p ? insn_var_ref->hreg : curr_var_infos[var].hreg;
if (hreg != MIR_NON_HARD_REG && !locs_in_bitmap_p (blocked_hard_regs, hreg, type)) {
@ -5908,7 +5918,7 @@ static void fast_gen (gen_ctx_t gen_ctx) {
if (hard_reg2 != MIR_NON_HARD_REG && !target_fixed_hard_reg_p (hard_reg2))
spill_vars (gen_ctx, hard_reg2, hard_reg2, MIR_T_UNDEF, insn);
if (MIR_call_code_p (code)) {
FOREACH_BITMAP_BIT (bi, call_used_hard_regs, nel) {
FOREACH_BITMAP_BIT (bi, call_used_hard_regs[MIR_T_UNDEF], nel) {
if (!target_fixed_hard_reg_p (nel)) {
spill_vars (gen_ctx, nel, nel, MIR_T_UNDEF, insn);
}
@ -6344,13 +6354,18 @@ void MIR_gen_init (MIR_context_t ctx) {
init_selection (gen_ctx);
init_fast_gen (gen_ctx);
target_init (gen_ctx);
call_used_hard_regs = bitmap_create2 (MAX_HARD_REG + 1);
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++;
}
for (MIR_type_t type = MIR_T_I8; type < MIR_T_BOUND; type++) {
call_used_hard_regs[type] = bitmap_create2 (MAX_HARD_REG + 1);
for (i = 0; i <= MAX_HARD_REG; i++) {
if (target_fixed_hard_reg_p (i)) continue;
if (target_call_used_hard_reg_p (i, type)) bitmap_set_bit_p (call_used_hard_regs[type], i);
}
}
insn_to_consider = bitmap_create2 (1024);
func_used_hard_regs = bitmap_create2 (MAX_HARD_REG + 1);
}
@ -6371,7 +6386,8 @@ void MIR_gen_finish (MIR_context_t ctx) {
finish_ra (gen_ctx);
finish_selection (gen_ctx);
finish_fast_gen (gen_ctx);
bitmap_destroy (call_used_hard_regs);
for (MIR_type_t type = MIR_T_I8; type < MIR_T_BOUND; type++)
bitmap_destroy (call_used_hard_regs[type]);
bitmap_destroy (insn_to_consider);
bitmap_destroy (func_used_hard_regs);
target_finish (gen_ctx);

@ -4,6 +4,18 @@
File contains MIR interpreter which is an obligatory part of MIR API.
*/
#ifdef MIR_NO_INTERP
static void interp_init (MIR_context_t ctx) {}
static void finish_func_interpretation (MIR_item_t func_item) {}
static void interp_finish (MIR_context_t ctx) {}
void MIR_interp (MIR_context_t ctx, MIR_item_t func_item, MIR_val_t *results, size_t nargs, ...) {}
void MIR_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) {}
void MIR_interp_arr (MIR_context_t ctx, MIR_item_t func_item, MIR_val_t *results, size_t nargs,
MIR_val_t *vals) {}
void MIR_set_interp_interface (MIR_context_t ctx, MIR_item_t func_item) {}
#else
#ifndef MIR_INTERP_TRACE
#define MIR_INTERP_TRACE 0
#endif
@ -28,10 +40,14 @@ typedef struct func_desc {
MIR_val_t code[1];
} * func_desc_t;
static void update_max_nreg (MIR_reg_t reg, MIR_reg_t *max_nreg) {
if (*max_nreg < reg) *max_nreg = reg;
}
static MIR_reg_t get_reg (MIR_op_t op, MIR_reg_t *max_nreg) {
/* We do not interpret code with hard regs */
mir_assert (op.mode == MIR_OP_REG);
if (*max_nreg < op.u.reg) *max_nreg = op.u.reg;
update_max_nreg (op.u.reg, max_nreg);
return op.u.reg;
}
@ -52,13 +68,16 @@ DEF_VARR (MIR_val_t);
struct ff_interface {
size_t nres, nargs;
int vararg_p;
MIR_type_t *res_types, *arg_types;
MIR_type_t *res_types;
_MIR_arg_desc_t *arg_descs;
void *interface_addr;
};
typedef struct ff_interface *ff_interface_t;
DEF_HTAB (ff_interface_t);
DEF_VARR (_MIR_arg_desc_t);
struct interp_ctx {
#if DIRECT_THREADED_DISPATCH
void *dispatch_label_tab[IC_INSN_BOUND];
@ -74,8 +93,8 @@ struct interp_ctx {
void (*bend_builtin) (void *);
VARR (MIR_val_t) * call_res_args_varr;
MIR_val_t *call_res_args;
VARR (MIR_type_t) * call_arg_types_varr;
MIR_type_t *call_arg_types;
VARR (_MIR_arg_desc_t) * call_arg_descs_varr;
_MIR_arg_desc_t *call_arg_descs;
HTAB (ff_interface_t) * ff_interface_tab;
};
@ -90,8 +109,8 @@ struct interp_ctx {
#define bend_builtin interp_ctx->bend_builtin
#define call_res_args_varr interp_ctx->call_res_args_varr
#define call_res_args interp_ctx->call_res_args
#define call_arg_types_varr interp_ctx->call_arg_types_varr
#define call_arg_types interp_ctx->call_arg_types
#define call_arg_descs_varr interp_ctx->call_arg_descs_varr
#define call_arg_descs interp_ctx->call_arg_descs
#define ff_interface_tab interp_ctx->ff_interface_tab
static void get_icode (struct interp_ctx *interp_ctx, MIR_val_t *v, int code) {
@ -389,6 +408,10 @@ static void generate_icode (MIR_context_t ctx, MIR_item_t func_item) {
} else if (code == MIR_SWITCH && i > 0) {
mir_assert (ops[i].mode == MIR_OP_LABEL);
v.i = 0;
} else if (MIR_call_code_p (code) && ops[i].mode == MIR_OP_MEM) {
mir_assert (ops[i].u.mem.type == MIR_T_BLK);
v.i = ops[i].u.mem.base;
update_max_nreg (v.i, &max_nreg);
} else {
mir_assert (ops[i].mode == MIR_OP_REG);
v.i = get_reg (ops[i], &max_nreg);
@ -888,7 +911,8 @@ static void OPTIMIZE eval (MIR_context_t ctx, func_desc_t func_desc, MIR_val_t *
REP8 (LAB_EL, MIR_BGTS, MIR_UBGT, MIR_UBGTS, MIR_FBGT, MIR_DBGT, MIR_LDBGT, MIR_BGE, MIR_BGES);
REP5 (LAB_EL, MIR_UBGE, MIR_UBGES, MIR_FBGE, MIR_DBGE, MIR_LDBGE);
REP4 (LAB_EL, MIR_CALL, MIR_INLINE, MIR_SWITCH, MIR_RET);
REP6 (LAB_EL, MIR_ALLOCA, MIR_BSTART, MIR_BEND, MIR_VA_ARG, MIR_VA_START, MIR_VA_END);
REP3 (LAB_EL, MIR_ALLOCA, MIR_BSTART, MIR_BEND);
REP4 (LAB_EL, MIR_VA_ARG, MIR_VA_STACK_ARG, MIR_VA_START, MIR_VA_END);
REP8 (LAB_EL, IC_LDI8, IC_LDU8, IC_LDI16, IC_LDU16, IC_LDI32, IC_LDU32, IC_LDI64, IC_LDF);
REP8 (LAB_EL, IC_LDD, IC_LDLD, IC_STI8, IC_STU8, IC_STI16, IC_STU16, IC_STI32, IC_STU32);
REP8 (LAB_EL, IC_STI64, IC_STF, IC_STD, IC_STLD, IC_MOVI, IC_MOVP, IC_MOVF, IC_MOVD);
@ -1277,6 +1301,13 @@ static void OPTIMIZE eval (MIR_context_t ctx, func_desc_t func_desc, MIR_val_t *
*r = (uint64_t) va_arg_builtin ((void *) va, tp);
END_INSN;
}
CASE (MIR_VA_STACK_ARG, 3) {
int64_t *r, va, size;
r = get_3iops (bp, ops, &va, &size);
*r = (uint64_t) va_stack_arg_builtin ((void *) va, size);
END_INSN;
}
SCASE (MIR_VA_START, 1, va_start_interp_builtin (ctx, bp[get_i (ops)].a, bp[-1].a));
SCASE (MIR_VA_END, 1, va_end_interp_builtin (ctx, bp[get_i (ops)].a));
@ -1342,20 +1373,28 @@ static htab_hash_t ff_interface_hash (ff_interface_t i, void *arg) {
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);
for (size_t n = 0; n < i->nargs; n++) {
h = mir_hash_step (h, i->arg_descs[n].type);
if (i->arg_descs[n].type == MIR_T_BLK) h = mir_hash_step (h, i->arg_descs[n].size);
}
return mir_hash_finish (h);
}
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);
if (i1->nres != i2->nres || i1->nargs != i2->nargs || i1->vararg_p != i2->vararg_p) return FALSE;
if (memcmp (i1->res_types, i2->res_types, sizeof (MIR_type_t) * i1->nres) != 0) return FALSE;
for (size_t n = 0; n < i1->nargs; n++) {
if (i1->arg_descs[n].type != i2->arg_descs[n].type) return FALSE;
if (i1->arg_descs[n].type == MIR_T_BLK && i1->arg_descs[n].size != i2->arg_descs[n].size)
return FALSE;
}
return TRUE;
}
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, int vararg_p) {
_MIR_arg_desc_t *arg_descs, int vararg_p) {
struct interp_ctx *interp_ctx = ctx->interp_ctx;
struct ff_interface ffi_s;
ff_interface_t tab_ffi, ffi;
@ -1365,18 +1404,19 @@ static void *get_ff_interface (MIR_context_t ctx, size_t nres, MIR_type_t *res_t
ffi_s.nargs = nargs;
ffi_s.vararg_p = !!vararg_p;
ffi_s.res_types = res_types;
ffi_s.arg_types = arg_types;
ffi_s.arg_descs = arg_descs;
if (HTAB_DO (ff_interface_t, ff_interface_tab, &ffi_s, HTAB_FIND, tab_ffi))
return tab_ffi->interface_addr;
ffi = malloc (sizeof (struct ff_interface) + sizeof (MIR_type_t) * (nres + nargs));
ffi = malloc (sizeof (struct ff_interface) + sizeof (_MIR_arg_desc_t) * nargs
+ sizeof (MIR_type_t) * nres);
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;
ffi->arg_descs = (_MIR_arg_desc_t *) ((char *) ffi + sizeof (struct ff_interface));
ffi->res_types = (MIR_type_t *) ((char *) ffi->arg_descs + nargs * sizeof (_MIR_arg_desc_t));
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, vararg_p);
memcpy (ffi->arg_descs, arg_descs, sizeof (_MIR_arg_desc_t) * nargs);
ffi->interface_addr = _MIR_get_ff_call (ctx, nres, res_types, nargs, call_arg_descs, 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;
@ -1404,27 +1444,34 @@ static void call (MIR_context_t ctx, MIR_val_t *bp, MIR_op_t *insn_arg_ops, code
}
nres = proto->nres;
if (VARR_EXPAND (MIR_val_t, call_res_args_varr, nargs + nres)
|| VARR_EXPAND (MIR_type_t, call_arg_types_varr, nargs + nres)) {
|| VARR_EXPAND (_MIR_arg_desc_t, call_arg_descs_varr, nargs)) {
call_res_args = VARR_ADDR (MIR_val_t, call_res_args_varr);
call_arg_types = VARR_ADDR (MIR_type_t, call_arg_types_varr);
call_arg_descs = VARR_ADDR (_MIR_arg_desc_t, call_arg_descs_varr);
}
if ((ff_interface_addr = ffi_address_ptr->a) == NULL) {
for (i = 0; i < nargs; i++) {
if (i < arg_vars_num) {
call_arg_types[i] = arg_vars[i].type;
call_arg_descs[i].type = arg_vars[i].type;
if (arg_vars[i].type == MIR_T_BLK) call_arg_descs[i].size = arg_vars[i].size;
continue;
}
mode = insn_arg_ops[i].value_mode;
mir_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)");
call_arg_types[i]
= (mode == MIR_OP_DOUBLE ? MIR_T_D : mode == MIR_OP_LDOUBLE ? MIR_T_LD : MIR_T_I64);
if (insn_arg_ops[i].mode == MIR_OP_MEM) { /* block arg */
mir_assert (insn_arg_ops[i].u.mem.type == MIR_T_BLK);
call_arg_descs[i].type = MIR_T_BLK;
call_arg_descs[i].size = insn_arg_ops[i].u.mem.disp;
} else {
mode = insn_arg_ops[i].value_mode;
mir_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)");
call_arg_descs[i].type
= (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, proto->vararg_p);
= get_ff_interface (ctx, nres, proto->res_types, nargs, call_arg_descs, proto->vararg_p);
}
for (i = 0; i < nargs; i++) {
@ -1445,7 +1492,8 @@ static void call (MIR_context_t ctx, MIR_val_t *bp, MIR_op_t *insn_arg_ops, code
case MIR_T_F: call_res_args[i + nres].f = arg_vals[i].f; break;
case MIR_T_D: call_res_args[i + nres].d = arg_vals[i].d; break;
case MIR_T_LD: call_res_args[i + nres].ld = arg_vals[i].ld; break;
case MIR_T_P: call_res_args[i + nres].u = (uint64_t) arg_vals[i].a; break;
case MIR_T_P:
case MIR_T_BLK: call_res_args[i + nres].u = (uint64_t) arg_vals[i].a; break;
default: mir_assert (FALSE);
}
}
@ -1483,9 +1531,9 @@ static void interp_init (MIR_context_t ctx) {
VARR_CREATE (MIR_val_t, arg_vals_varr, 0);
arg_vals = VARR_ADDR (MIR_val_t, arg_vals_varr);
VARR_CREATE (MIR_val_t, call_res_args_varr, 0);
VARR_CREATE (MIR_type_t, call_arg_types_varr, 0);
VARR_CREATE (_MIR_arg_desc_t, call_arg_descs_varr, 0);
call_res_args = VARR_ADDR (MIR_val_t, call_res_args_varr);
call_arg_types = VARR_ADDR (MIR_type_t, call_arg_types_varr);
call_arg_descs = VARR_ADDR (_MIR_arg_desc_t, call_arg_descs_varr);
HTAB_CREATE_WITH_FREE_FUNC (ff_interface_t, ff_interface_tab, 1000, ff_interface_hash,
ff_interface_eq, ff_interface_clear, NULL);
#if MIR_INTERP_TRACE
@ -1502,7 +1550,7 @@ static void interp_finish (MIR_context_t ctx) {
VARR_DESTROY (MIR_val_t, code_varr);
VARR_DESTROY (MIR_val_t, arg_vals_varr);
VARR_DESTROY (MIR_val_t, call_res_args_varr);
VARR_DESTROY (MIR_type_t, call_arg_types_varr);
VARR_DESTROY (_MIR_arg_desc_t, call_arg_descs_varr);
HTAB_DESTROY (ff_interface_t, ff_interface_tab);
/* Clear func descs??? */
free (ctx->interp_ctx);
@ -1620,6 +1668,13 @@ static void interp (MIR_context_t ctx, MIR_item_t func_item, va_list va, MIR_val
case MIR_T_D: arg_vals[i].d = va_arg (va, double); break;
case MIR_T_LD: arg_vals[i].ld = va_arg (va, long double); break;
case MIR_T_P: arg_vals[i].a = va_arg (va, void *); break;
case MIR_T_BLK:
#if defined(__PPC64__) || defined(__aarch64__)
arg_vals[i].a = va_stack_arg_builtin (&va, arg_vars[i].size);
#else
arg_vals[i].a = va_stack_arg_builtin (va, arg_vars[i].size);
#endif
break;
default: mir_assert (FALSE);
}
}
@ -1637,3 +1692,5 @@ static void redirect_interface_to_interp (MIR_context_t ctx, MIR_item_t func_ite
void MIR_set_interp_interface (MIR_context_t ctx, MIR_item_t func_item) {
redirect_interface_to_interp (ctx, func_item);
}
#endif /* #ifdef MIR_NO_INTERP */

@ -59,6 +59,10 @@ static void ppc64_gen_addi (MIR_context_t ctx, unsigned rt_reg, unsigned ra_reg,
push_insn (ctx, (14 << 26) | (rt_reg << 21) | (ra_reg << 16) | (disp & 0xffff));
}
static void ppc64_gen_add (MIR_context_t ctx, unsigned rt_reg, unsigned ra_reg, unsigned rb_reg) {
push_insn (ctx, (31 << 26) | (266 << 1) | (rt_reg << 21) | (ra_reg << 16) | (rb_reg << 11));
}
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;
@ -116,6 +120,30 @@ static void ppc64_gen_jump (MIR_context_t ctx, unsigned int reg, int call_p) {
push_insn (ctx, (19 << 26) | (528 << 1) | (20 << 21) | (call_p ? 1 : 0)); /* bcctr[l] */
}
/* r11=addr_reg+addr_disp; r15=r1(sp)+sp_offset; r0=qwords-1;
ctr=r0; L: r0=mem[r11]; r11+=8; mem[r15]=r0; r15+=8; bdnz L; */
static void gen_blk_mov (MIR_context_t ctx, size_t sp_offset, unsigned int addr_reg, int addr_disp,
size_t qwords) {
static const uint32_t blk_mov_loop[] = {
/*0:*/ 0x7c0903a6, /*mctr r0*/
/*4:*/ 0xe80b0000, /*ld r0,0(r11)*/
/*8:*/ 0x396b0008, /*addi r11,r11,8*/
/*12:*/ 0xf80f0000, /*std r0,0(r15)*/
/*16:*/ 0x39ef0008, /*addi r15,r15,8*/
/*20:*/ 0x4200fff0, /*bdnz 4*/
};
/* r11=addr_reg+addr_disp: */
if (addr_reg != 11 || addr_disp != 0) ppc64_gen_addi (ctx, 11, addr_reg, addr_disp);
if (sp_offset < 0x10000) {
ppc64_gen_addi (ctx, 15, 1, sp_offset);
} else {
ppc64_gen_address (ctx, 15, (void *) sp_offset);
ppc64_gen_add (ctx, 15, 15, 1);
}
ppc64_gen_address (ctx, 0, (void *) qwords); /*r0 = qwords*/
push_insns (ctx, blk_mov_loop, sizeof (blk_mov_loop));
}
void *_MIR_get_bstart_builtin (MIR_context_t ctx) {
static const uint32_t bstart_code[] = {
0x7c230b78, /* mr 3,1 */
@ -191,6 +219,14 @@ void *va_arg_builtin (void *p, uint64_t t) {
return a;
}
void *va_stack_arg_builtin (void *p, size_t s) {
struct ppc64_va_list *va = p;
void *a = va->arg_area;
va->arg_area += (s + sizeof (uint64_t) - 1) / sizeof (uint64_t);
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;
@ -202,15 +238,13 @@ void va_start_interp_builtin (MIR_context_t ctx, void *p, void *a) {
void va_end_interp_builtin (MIR_context_t ctx, void *p) {}
/* 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,<args_offset>]; (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,<offset>]; res_reg=mem[r0]; ...
restore r14, r1, lr; return. */
save lr (r1 + 16); allocate and form minimal stack frame (with necessary param area); save
r14,r15; r12=fun_addr (r3); r14 = res_arg_addresses (r4); r0=mem[r14,<args_offset>];
(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,<offset>]; res_reg=mem[r0]; ... restore r15, 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) {
_MIR_arg_desc_t *arg_descs, int vararg_p) {
static uint32_t start_pattern[] = {
0x7c0802a6, /* mflr r0 */
0xf8010010, /* std r0,16(r1) */
@ -221,18 +255,24 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
0x4e800020, /* blr */
};
MIR_type_t type;
int n_gpregs = 0, n_fpregs = 0, res_reg = 14, frame_size, disp, param_offset, param_size = 0;
int n_gpregs = 0, n_fpregs = 0, res_reg = 14, qwords, frame_size;
int disp, blk_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;
for (uint32_t i = 0; i < nargs; i++)
if ((type = arg_descs[i].type) == MIR_T_BLK)
param_size += (arg_descs[i].size + 7) / 8 * 8;
else
param_size += type == MIR_T_LD ? 16 : 8;
if (param_size < 64) param_size = 64;
frame_size = PPC64_STACK_HEADER_SIZE + param_size + 8; /* +local var to save res_reg */
if (frame_size % 16 != 0) frame_size += 8; /* align */
frame_size = PPC64_STACK_HEADER_SIZE + param_size + 16; /* +local var to save res_reg and 15 */
if (frame_size % 16 != 0) frame_size += 8; /* align */
ppc64_gen_st (ctx, 2, 1, PPC64_TOC_OFFSET, MIR_T_I64);
push_insns (ctx, start_pattern, sizeof (start_pattern));
ppc64_gen_stdu (ctx, -frame_size);
ppc64_gen_st (ctx, res_reg, 1, PPC64_STACK_HEADER_SIZE + param_size,
MIR_T_I64); /* save res_reg */
MIR_T_I64); /* save res_reg */
ppc64_gen_st (ctx, 15, 1, PPC64_STACK_HEADER_SIZE + param_size + 8, MIR_T_I64); /* save 15 */
mir_assert (sizeof (long double) == 16);
ppc64_gen_mov (ctx, res_reg, 4); /* results & args */
ppc64_gen_mov (ctx, 12, 3); /* func addr */
@ -240,7 +280,7 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
param_offset = nres * 16; /* args start */
disp = PPC64_STACK_HEADER_SIZE; /* param area start */
for (uint32_t i = 0; i < nargs; i++) { /* load args: */
type = arg_types[i];
type = arg_descs[i].type;
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) {
@ -276,6 +316,30 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
ppc64_gen_ld (ctx, 0, res_reg, param_offset + 8, type);
ppc64_gen_st (ctx, 0, 1, disp + 8, MIR_T_D);
}
} else if (type == MIR_T_BLK) {
qwords = (arg_descs[i].size + 7) / 8;
if (qwords > 0) ppc64_gen_ld (ctx, 11, res_reg, param_offset, MIR_T_I64);
for (blk_disp = 0; qwords > 0 && n_gpregs < 8; qwords--, n_gpregs++, blk_disp += 8, disp += 8)
ppc64_gen_ld (ctx, n_gpregs + 3, 11, blk_disp, MIR_T_I64);
#if 0
/* passing FBLK: */
for (blk_disp = 0, qwords = (arg_descs[i].size + 7) / 8;
qwords > 0 && n_fpregs < 13;
qwords--, n_fpregs++, blk_disp += 8, disp += 8) {
ppc64_gen_ld (ctx, n_fpregs + 1, 11, blk_disp, MIR_T_D);
if (vararg_p) {
if (n_gpregs < 8) { /* load into gp reg too */
ppc64_gen_ld (ctx, n_gpregs + 3, 11, blk_disp, MIR_T_I64);
} else {
ppc64_gen_st (ctx, 1 + n_fpregs, 1, disp, MIR_T_D);
}
}
}
#endif
if (qwords > 0) gen_blk_mov (ctx, disp, 11, blk_disp, qwords);
disp += qwords * 8;
param_offset += 16;
continue;
} else if (n_gpregs < 8) {
ppc64_gen_ld (ctx, n_gpregs + 3, res_reg, param_offset, MIR_T_I64);
} else {
@ -310,6 +374,7 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
}
ppc64_gen_ld (ctx, res_reg, 1, PPC64_STACK_HEADER_SIZE + param_size,
MIR_T_I64); /* restore res_reg */
ppc64_gen_ld (ctx, 15, 1, PPC64_STACK_HEADER_SIZE + param_size + 8, MIR_T_I64); /* restore r15 */
ppc64_gen_addi (ctx, 1, 1, frame_size);
push_insns (ctx, finish_pattern, sizeof (finish_pattern));
return ppc64_publish_func_and_redirect (ctx);
@ -326,8 +391,8 @@ void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handl
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 disp, start_disp, qwords, size, frame_size, local_var_size, param_offset;
int va_reg = 11, caller_r1 = 12, res_reg = 14;
int n_gpregs, n_fpregs;
static uint32_t start_pattern[] = {
0x7c0802a6, /* mflr r0 */
@ -341,27 +406,28 @@ void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handl
VARR_TRUNC (uint8_t, machine_insns, 0);
frame_size = PPC64_STACK_HEADER_SIZE + 64; /* header + 8(param area) */
local_var_size = nres * 16 + 8; /* saved r14, results */
local_var_size = nres * 16 + 16; /* saved r14, r15, results */
if (vararg_p) {
for (unsigned reg = 3; reg <= 10; reg++) /* std rn,dispn(r1) : */
ppc64_gen_st (ctx, reg, 1, PPC64_STACK_HEADER_SIZE + (reg - 3) * 8, MIR_T_I64);
ppc64_gen_addi (ctx, va_reg, 1, PPC64_STACK_HEADER_SIZE);
} 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;
}
for (uint32_t i = 0; i < nargs; i++)
if ((type = arg_vars[i].type) == MIR_T_BLK)
local_var_size += (arg_vars[i].size + 7) / 8 * 8;
else
local_var_size += type == MIR_T_LD ? 16 : 8;
}
frame_size += local_var_size;
if (frame_size % 16 != 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, PPC64_STACK_HEADER_SIZE + 64, MIR_T_I64); /* save res_reg */
ppc64_gen_st (ctx, 15, 1, PPC64_STACK_HEADER_SIZE + 72, MIR_T_I64); /* save r15 */
if (!vararg_p) { /* save args in local vars: */
/* header_size + 64 + nres * 16 + 8 -- start of stack memory to keep args: */
disp = PPC64_STACK_HEADER_SIZE + 64 + nres * 16 + 8;
ppc64_gen_addi (ctx, va_reg, 1, disp);
/* header_size + 64 + nres * 16 + 16 -- start of stack memory to keep args: */
start_disp = disp = PPC64_STACK_HEADER_SIZE + 64 + nres * 16 + 16;
param_offset = PPC64_STACK_HEADER_SIZE;
n_gpregs = n_fpregs = 0;
for (uint32_t i = 0; i < nargs; i++) {
@ -378,6 +444,16 @@ void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handl
ppc64_gen_st (ctx, 0, 1, disp + 8, MIR_T_D);
}
}
} else if (type == MIR_T_BLK) { // ??? FBLK
qwords = (arg_vars[i].size + 7) / 8;
for (; qwords > 0 && n_gpregs < 8; qwords--, n_gpregs++, disp += 8, param_offset += 8)
ppc64_gen_st (ctx, n_gpregs + 3, 1, disp, MIR_T_I64);
if (qwords > 0) {
gen_blk_mov (ctx, disp, caller_r1, param_offset, qwords);
disp += qwords * 8;
param_offset += qwords * 8;
}
continue;
} 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) {
@ -396,8 +472,9 @@ void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handl
param_offset += size;
n_gpregs += type == MIR_T_LD ? 2 : 1;
}
ppc64_gen_addi (ctx, va_reg, 1, start_disp);
}
ppc64_gen_addi (ctx, res_reg, 1, 64 + PPC64_STACK_HEADER_SIZE + 8);
ppc64_gen_addi (ctx, res_reg, 1, 64 + PPC64_STACK_HEADER_SIZE + 16);
ppc64_gen_address (ctx, 3, ctx);
ppc64_gen_address (ctx, 4, func_item);
ppc64_gen_mov (ctx, 5, va_reg);
@ -425,6 +502,7 @@ void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handl
disp += 16;
}
ppc64_gen_ld (ctx, res_reg, 1, PPC64_STACK_HEADER_SIZE + 64, MIR_T_I64); /* restore res_reg */
ppc64_gen_ld (ctx, 15, 1, PPC64_STACK_HEADER_SIZE + 72, MIR_T_I64); /* restore r15 */
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),

@ -12,8 +12,9 @@
#define S390X_STACK_HEADER_SIZE 160
static void push_insns (MIR_context_t ctx, const uint8_t *pat, size_t pat_len) {
static uint8_t *push_insns (MIR_context_t ctx, const uint8_t *pat, size_t pat_len) {
for (size_t i = 0; i < pat_len; i++) VARR_PUSH (uint8_t, machine_insns, pat[i]);
return VARR_ADDR (uint8_t, machine_insns) + VARR_LENGTH (uint8_t, machine_insns) - pat_len;
}
static void s390x_gen_mov (MIR_context_t ctx, unsigned to, unsigned from) {
@ -109,6 +110,26 @@ static void s390x_gen_3addrs (MIR_context_t ctx, unsigned int r1, void *a1, unsi
push_insns (ctx, (uint8_t *) &a3, 8);
}
static void s390x_gen_blk_mov (MIR_context_t ctx, uint32_t param_offset, uint32_t addr_offset,
uint32_t qwords, uint32_t addr_reg) {
uint16_t *addr;
static const uint16_t blk_mov_pat[] = {
/*0:*/ 0xa7a9, 0x0000, /* lghi %r10,<size> */
/*4:*/ 0xa7ab, 0xfff8, /* aghi %r10,-8 */
/*8:*/ 0xe30a, 0x9000, 0x0004, /* lg %r0,0(%r10,%r9) */
/*14:*/ 0xe30a, 0x0000, 0x0024, /* stg %r0,0(%r10,<addr_reg:2-6,8>) */
/*20:*/ 0xb902, 0x00aa, /* ltgr %r10,%r10 */
/*24:*/ 0xa724, 0xfff6, /* jh 4 */
};
s390x_gen_addi (ctx, addr_reg, 15, addr_offset); /* lay <addr_reg>,addr_offset(r15) */
if (qwords == 0) return;
assert (qwords * 8 < (1 << 15) && addr_reg < 16 && addr_offset % 8 == 0);
s390x_gen_ld (ctx, 9, 7, param_offset, MIR_T_I64); /* lg* 9,param_offset(r7) */
addr = (uint16_t *) push_insns (ctx, (uint8_t *) blk_mov_pat, sizeof (blk_mov_pat));
addr[1] |= qwords * 8; /* lghi */
addr[8] |= addr_reg << 12; /* stg */
}
void *_MIR_get_bstart_builtin (MIR_context_t ctx) {
VARR_TRUNC (uint8_t, machine_insns, 0);
s390x_gen_mov (ctx, 2, 15); /* lgr r2,15 */
@ -193,6 +214,8 @@ void *va_arg_builtin (void *p, uint64_t t) {
return a;
}
void *va_stack_arg_builtin (void *p, size_t s) { return *(void **) va_arg_builtin (p, MIR_T_I64); }
void va_start_interp_builtin (MIR_context_t ctx, void *p, void *a) {
struct s390x_va_list *va = p;
va_list *vap = a;
@ -208,31 +231,34 @@ void va_end_interp_builtin (MIR_context_t ctx, void *p) {}
allocate and stack frame (S390X_STACK_HEADER_SIZE + param area size + ld arg values size);
r1=r2 (fun_addr);
r7=r3 (res_arg_addresses);
(arg_reg=mem[r7,arg_offset] or (f1,r0)=mem[r7,arg_offset];mem[r15,S390X_STACK_HEADER_SIZE+offset]=(f1,r0)) ...
call *r1;
(arg_reg=mem[r7,arg_offset] or
(f1,r0)=mem[r7,arg_offset];mem[r15,S390X_STACK_HEADER_SIZE+offset]=(f1,r0)) ... call *r1;
r0=mem[r7,<res_offset>]; res_reg=mem[r0]; ...
restore r15; restore r6, r7, r14; 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) {
_MIR_arg_desc_t *arg_descs, int vararg_p) {
MIR_type_t type;
int n_gpregs = 0, n_fpregs = 0, res_reg = 7, frame_size, disp, param_offset, param_size = 0;
int n_gpregs = 0, n_fpregs = 0, res_reg = 7, frame_size, disp, param_offset, blk_offset;
uint32_t qwords, addr_reg;
VARR_TRUNC (uint8_t, machine_insns, 0);
frame_size = S390X_STACK_HEADER_SIZE;
blk_offset = frame_size = S390X_STACK_HEADER_SIZE;
if (nres > 0 && res_types[0] == MIR_T_LD) n_gpregs++; /* ld address */
for (uint32_t i = 0; i < nargs; i++) { /* calculate param area size: */
type = arg_types[i];
if (type == MIR_T_LD) frame_size += 16; /* address for ld value */
type = arg_descs[i].type;
if (type == MIR_T_BLK) frame_size += (arg_descs[i].size + 7) / 8; /* blk value space */
if ((type == MIR_T_F || type == MIR_T_D) && n_fpregs < 4) {
n_fpregs++;
} else if (type != MIR_T_F && type != MIR_T_D && n_gpregs < 5) {
n_gpregs++;
} else {
frame_size += 8;
param_size += 8;
blk_offset += 8;
}
}
s390x_gen_ldstm (ctx, 6, 7, 15, 48, FALSE); /* stmg 6,7,48(r15) : */
s390x_gen_ldstm (ctx, 8, 9, 15, 64, FALSE); /* stmg 8,9,64(r15) : */
s390x_gen_st (ctx, 10, 15, 80, MIR_T_I64); /* stg r10,80(r15) */
s390x_gen_st (ctx, 14, 15, 112, MIR_T_I64); /* stg r14,112(r15) */
s390x_gen_addi (ctx, 15, 15, -frame_size); /* lay r15,-frame_size(r15) */
s390x_gen_mov (ctx, 1, 2); /* fun_addr */
@ -245,14 +271,14 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
n_gpregs++;
}
for (uint32_t i = 0; i < nargs; i++) { /* load args: */
type = arg_types[i];
type = arg_descs[i].type;
if ((type == MIR_T_F || type == MIR_T_D) && n_fpregs < 4) {
/* (le,ld) (f0,f2,f4,f6),param_ofset(r7) */
s390x_gen_ld (ctx, n_fpregs * 2, res_reg, param_offset, type);
n_fpregs++;
} else if (type == MIR_T_F || type == MIR_T_D) {
s390x_gen_ld (ctx, 1, res_reg, param_offset, type); /* (le,ld) f1,param_offset(r7) */
s390x_gen_st (ctx, 1, 15, disp, type); /* (ste,std) f1,disp(r15) */
s390x_gen_ld (ctx, 1, res_reg, param_offset, type); /* (le,ld) f1,param_offset(r7) */
s390x_gen_st (ctx, 1, 15, disp, type); /* (ste,std) f1,disp(r15) */
disp += 8;
} else if (type == MIR_T_LD && n_gpregs < 5) { /* ld address */
s390x_gen_addi (ctx, n_gpregs + 2, res_reg, param_offset); /* lay rn,param_offset(r7) */
@ -261,12 +287,24 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
s390x_gen_addi (ctx, 0, res_reg, param_offset); /* lay r0,param_offset(r7) */
s390x_gen_st (ctx, 0, 15, disp, MIR_T_I64); /* stg r0,disp(r15) */
disp += 8;
} else if (type == MIR_T_BLK) {
qwords = (arg_descs[i].size + 7) / 8;
addr_reg = n_gpregs < 5 ? n_gpregs + 2 : 8;
s390x_gen_blk_mov (ctx, param_offset, blk_offset, qwords, addr_reg);
blk_offset += qwords * 8;
if (n_gpregs < 5) {
n_gpregs++;
} else {
s390x_gen_st (ctx, 8, 15, disp, MIR_T_I64); /* stg r8,disp(r15) */
disp += 8;
}
} else if (n_gpregs < 5) {
s390x_gen_ld (ctx, n_gpregs + 2, res_reg, param_offset, MIR_T_I64); /* lg* rn,param_offset(r7) */
s390x_gen_ld (ctx, n_gpregs + 2, res_reg, param_offset,
MIR_T_I64); /* lg* rn,param_offset(r7) */
n_gpregs++;
} else {
s390x_gen_ld (ctx, 0, res_reg, param_offset, MIR_T_I64); /* lg* r0,param_offset(r7) */
s390x_gen_st (ctx, 0, 15, disp, MIR_T_I64); /* stg* r0,disp(r15) */
s390x_gen_st (ctx, 0, 15, disp, MIR_T_I64); /* stg* r0,disp(r15) */
disp += 8;
}
param_offset += 16;
@ -290,6 +328,8 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
}
s390x_gen_addi (ctx, 15, 15, frame_size); /* lay 15,frame_size(15) */
s390x_gen_ldstm (ctx, 6, 7, 15, 48, TRUE); /* lmg 6,7,48(r15) : */
s390x_gen_ldstm (ctx, 8, 9, 15, 64, TRUE); /* lmg 8,9,64(r15) : */
s390x_gen_ld (ctx, 10, 15, 80, MIR_T_I64); /* lg 10,80(r15) */
s390x_gen_ld (ctx, 14, 15, 112, MIR_T_I64); /* lg 14,112(r15) */
s390x_gen_jump (ctx, 14, FALSE); /* bcr m15,r14 */
return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),
@ -358,7 +398,7 @@ void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handl
disp += 16;
}
s390x_gen_addi (ctx, 15, 15, frame_size); /* lay 15,frame_size(15) */
s390x_gen_ld (ctx, 6, 15, 48, MIR_T_I64); /* lg 6,48(r15) : */
s390x_gen_ld (ctx, 6, 15, 48, MIR_T_I64); /* lg 6,48(r15) : */
s390x_gen_ld (ctx, 14, 15, 112, MIR_T_I64); /* lg 14,112(r15) */
s390x_gen_jump (ctx, 14, FALSE); /* bcr m15,r14 */
return _MIR_publish_code (ctx, VARR_ADDR (uint8_t, machine_insns),

@ -51,6 +51,14 @@ void *va_arg_builtin (void *p, uint64_t t) {
return a;
}
void *va_stack_arg_builtin (void *p, size_t s) {
struct x86_64_va_list *va = p;
void *a = va->overflow_arg_area;
va->overflow_arg_area += (s + sizeof (uint64_t) - 1) / sizeof (uint64_t);
return a;
}
void va_start_interp_builtin (MIR_context_t ctx, void *p, void *a) {
struct x86_64_va_list *va = p;
va_list *vap = a;
@ -70,6 +78,13 @@ void *va_arg_builtin (void *p, uint64_t t) {
return a;
}
void *va_stack_arg_builtin (void *p, size_t s) {
struct x86_64_va_list *va = p;
void *a = va->arg_area;
va->arg_area += (s + sizeof (uint64_t) - 1) / sizeof (uint64_t);
return a;
}
void va_start_interp_builtin (MIR_context_t ctx, void *p, void *a) {
struct x86_64_va_list **va = p;
va_list *vap = a;
@ -114,10 +129,10 @@ static const uint8_t save_pat[] = {
0x56, /*push %rsi */
0x57, /*push %rdi */
#else
0x48, 0x89, 0x4c, 0x24, 0x08, /*mov %rcx,0x08(%rsp) */
0x48, 0x89, 0x54, 0x24, 0x10, /*mov %rdx,0x10(%rsp) */
0x4c, 0x89, 0x44, 0x24, 0x18, /*mov %r8, 0x18(%rsp) */
0x4c, 0x89, 0x4c, 0x24, 0x20, /*mov %r9, 0x20(%rsp) */
0x48, 0x89, 0x4c, 0x24, 0x08, /*mov %rcx,0x08(%rsp) */
0x48, 0x89, 0x54, 0x24, 0x10, /*mov %rdx,0x10(%rsp) */
0x4c, 0x89, 0x44, 0x24, 0x18, /*mov %r8, 0x18(%rsp) */
0x4c, 0x89, 0x4c, 0x24, 0x20, /*mov %r9, 0x20(%rsp) */
#endif
};
@ -139,14 +154,14 @@ static const uint8_t restore_pat[] = {
0xf3, 0x0f, 0x6f, 0x7c, 0x24, 0x70, /*movdqu 0x70(%rsp),%xmm7 */
0x48, 0x81, 0xc4, 0x80, 0, 0, 0, /*add $0x80,%rsp */
#else
0x48, 0x8b, 0x4c, 0x24, 0x08, /*mov 0x08(%rsp),%rcx */
0x48, 0x8b, 0x54, 0x24, 0x10, /*mov 0x10(%rsp),%rdx */
0x4c, 0x8b, 0x44, 0x24, 0x18, /*mov 0x18(%rsp),%r8 */
0x4c, 0x8b, 0x4c, 0x24, 0x20, /*mov 0x20(%rsp),%r9 */
0xf3, 0x0f, 0x7e, 0x44, 0x24, 0x08, /*movq 0x08(%rsp),%xmm0*/
0xf3, 0x0f, 0x7e, 0x4c, 0x24, 0x10, /*movq 0x10(%rsp),%xmm1*/
0xf3, 0x0f, 0x7e, 0x54, 0x24, 0x18, /*movq 0x18(%rsp),%xmm2*/
0xf3, 0x0f, 0x7e, 0x5c, 0x24, 0x20, /*movq 0x20(%rsp),%xmm3*/
0x48, 0x8b, 0x4c, 0x24, 0x08, /*mov 0x08(%rsp),%rcx */
0x48, 0x8b, 0x54, 0x24, 0x10, /*mov 0x10(%rsp),%rdx */
0x4c, 0x8b, 0x44, 0x24, 0x18, /*mov 0x18(%rsp),%r8 */
0x4c, 0x8b, 0x4c, 0x24, 0x20, /*mov 0x20(%rsp),%r9 */
0xf3, 0x0f, 0x7e, 0x44, 0x24, 0x08, /*movq 0x08(%rsp),%xmm0*/
0xf3, 0x0f, 0x7e, 0x4c, 0x24, 0x10, /*movq 0x10(%rsp),%xmm1*/
0xf3, 0x0f, 0x7e, 0x54, 0x24, 0x18, /*movq 0x18(%rsp),%xmm2*/
0xf3, 0x0f, 0x7e, 0x5c, 0x24, 0x20, /*movq 0x20(%rsp),%xmm3*/
#endif
};
@ -166,6 +181,23 @@ static void gen_mov (MIR_context_t ctx, uint32_t offset, uint32_t reg, int ld_p)
addr[2] |= (reg & 7) << 3;
}
static void gen_blk_mov (MIR_context_t ctx, uint32_t offset, uint32_t addr_offset,
uint32_t qwords) {
static const uint8_t blk_mov_pat[] = {
/*0:*/ 0x4c, 0x8b, 0xa3, 0, 0, 0, 0, /*mov <addr_offset>(%rbx),%r12*/
/*7:*/ 0x48, 0xc7, 0xc0, 0, 0, 0, 0, /*mov <qwords>,%rax*/
/*e:*/ 0x48, 0x83, 0xe8, 0x01, /*sub $0x1,%rax*/
/*12:*/ 0x4d, 0x8b, 0x14, 0xc4, /*mov (%r12,%rax,8),%r10*/
/*16:*/ 0x4c, 0x89, 0x94, 0xc4, 0, 0, 0, 0, /*mov %r10,<offset>(%rsp,%rax,8)*/
/*1e:*/ 0x48, 0x85, 0xc0, /*test %rax,%rax*/
/*21:*/ 0x7f, 0xeb, /*jg e <L0>*/
};
uint8_t *addr = push_insns (ctx, blk_mov_pat, sizeof (blk_mov_pat));
memcpy (addr + 3, &addr_offset, sizeof (uint32_t));
memcpy (addr + 10, &qwords, sizeof (uint32_t));
memcpy (addr + 26, &offset, sizeof (uint32_t));
}
static void gen_movxmm (MIR_context_t ctx, uint32_t offset, uint32_t reg, int b32_p, int ld_p) {
static const uint8_t ld_xmm_reg_pat[] = {
0xf2, 0x0f, 0x10, 0x83, 0, 0, 0, 0 /* movs[sd] <offset>(%rbx),%xmm */
@ -211,24 +243,29 @@ static void gen_st80 (MIR_context_t ctx, uint32_t src_offset) {
}
/* Generation: fun (fun_addr, res_arg_addresses):
push rbx; sp-=sp_offset; r11=fun_addr; rbx=res/arg_addrs
r10=mem[rbx,<offset>]; (arg_reg=mem[r10] or r10=mem[r10];mem[sp,sp_offset]=r10) ...
push r12, push rbx; sp-=sp_offset; r11=fun_addr; rbx=res/arg_addrs
r10=mem[rbx,<offset>]; (arg_reg=mem[r10] or r10=mem[r10];mem[sp,sp_offset]=r10
or r12=mem[rbx,arg_offset];rax=qwords;
L:rax-=1;r10=mem[r12,rax]; mem[sp,sp_offset,rax]=r10;
goto L if rax > 0) ...
rax=8; call *r11; sp+=offset
r10=mem[rbx,<offset>]; res_reg=mem[r10]; ...
pop rbx; ret. */
pop rbx; push r12; 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, int vararg_p) {
_MIR_arg_desc_t *arg_descs, int vararg_p) {
static const uint8_t prolog[] = {
#ifndef _WIN64
0x41, 0x54, /* pushq %r12 */
0x53, /* pushq %rbx */
0x48, 0x81, 0xec, 0, 0, 0, 0, /* subq <sp_offset>, %rsp */
0x49, 0x89, 0xfb, /* mov $rdi, $r11 -- fun addr */
0x48, 0x89, 0xf3, /* mov $rsi, $rbx -- result/arg addresses */
#else
0x53, /* pushq %rbx */
0x48, 0x81, 0xec, 0, 0, 0, 0, /* subq <sp_offset>, %rsp */
0x49, 0x89, 0xcb, /* mov $rcx, $r11 -- fun addr */
0x48, 0x89, 0xd3, /* mov $rdx, $rbx -- result/arg addresses */
0x41, 0x54, /* pushq %r12 */
0x53, /* pushq %rbx */
0x48, 0x81, 0xec, 0, 0, 0, 0, /* subq <sp_offset>, %rsp */
0x49, 0x89, 0xcb, /* mov $rcx, $r11 -- fun addr */
0x48, 0x89, 0xd3, /* mov $rdx, $rbx -- result/arg addresses */
#endif
};
static const uint8_t call_end[] = {
@ -239,8 +276,9 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
0x48, 0x81, 0xc4, 0, 0, 0, 0, /* addq <sp_offset>, %rsp */
};
static const uint8_t epilog[] = {
0x5b, /* pop %rbx */
0xc3, /* ret */
0x5b, /* pop %rbx */
0x41, 0x5c, /* pop %r12 */
0xc3, /* ret */
};
#ifndef _WIN64
static const uint8_t iregs[] = {7, 6, 2, 1, 8, 9}; /* rdi, rsi, rdx, rcx, r8, r9 */
@ -251,13 +289,15 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
static const uint32_t max_iregs = 4, max_xregs = 4;
uint32_t sp_offset = 32;
#endif
uint32_t n_iregs = 0, n_xregs = 0, n_fregs;
uint32_t n_iregs = 0, n_xregs = 0, n_fregs, qwords;
uint8_t *addr;
VARR_TRUNC (uint8_t, machine_insns, 0);
push_insns (ctx, prolog, sizeof (prolog));
for (size_t i = 0; i < nargs; i++) {
if ((MIR_T_I8 <= arg_types[i] && arg_types[i] <= MIR_T_U64) || arg_types[i] == MIR_T_P) {
MIR_type_t type = arg_descs[i].type;
if ((MIR_T_I8 <= type && type <= MIR_T_U64) || type == MIR_T_P) {
if (n_iregs < max_iregs) {
gen_mov (ctx, (i + nres) * sizeof (long double), iregs[n_iregs++], TRUE);
#ifdef _WIN64
@ -267,27 +307,31 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
gen_ldst (ctx, sp_offset, (i + nres) * sizeof (long double), TRUE);
sp_offset += 8;
}
} else if (arg_types[i] == MIR_T_F || arg_types[i] == MIR_T_D) {
} else if (type == MIR_T_F || type == MIR_T_D) {
if (n_xregs < max_xregs) {
gen_movxmm (ctx, (i + nres) * sizeof (long double), n_xregs++, arg_types[i] == MIR_T_F,
TRUE);
gen_movxmm (ctx, (i + nres) * sizeof (long double), n_xregs++, type == MIR_T_F, TRUE);
#ifdef _WIN64
gen_mov (ctx, (i + nres) * sizeof (long double), iregs[n_iregs++], TRUE);
#endif
} else {
gen_ldst (ctx, sp_offset, (i + nres) * sizeof (long double), arg_types[i] == MIR_T_D);
gen_ldst (ctx, sp_offset, (i + nres) * sizeof (long double), type == MIR_T_D);
sp_offset += 8;
}
} else if (arg_types[i] == MIR_T_LD) {
} else if (type == MIR_T_LD) {
gen_ldst80 (ctx, sp_offset, (i + nres) * sizeof (long double));
sp_offset += 16;
} else if (type == MIR_T_BLK) {
qwords = (arg_descs[i].size + 7) / 8;
gen_blk_mov (ctx, sp_offset, (i + nres) * sizeof (long double), qwords);
sp_offset += qwords * 8;
} else {
(*error_func) (MIR_call_op_error, "wrong type of arg value");
}
}
sp_offset = (sp_offset + 15) / 16 * 16;
sp_offset += 8;
addr = VARR_ADDR (uint8_t, machine_insns);
memcpy (addr + 4, &sp_offset, sizeof (uint32_t));
memcpy (addr + 6, &sp_offset, sizeof (uint32_t));
addr = push_insns (ctx, call_end, sizeof (call_end));
memcpy (addr + sizeof (call_end) - 4, &sp_offset, sizeof (uint32_t));
#ifdef _WIN64
@ -430,7 +474,7 @@ void *_MIR_get_wrapper (MIR_context_t ctx, MIR_item_t called_func, void *hook_ad
static const uint8_t push_rax[] = {0x50, /*push %rax */};
static const uint8_t wrap_end[] = {
#ifndef _WIN64
0x58, /*pop %rax */
0x58, /*pop %rax */
#endif
0x41, 0xff, 0xe2, /*jmpq *%r10 */
};
@ -442,15 +486,15 @@ void *_MIR_get_wrapper (MIR_context_t ctx, MIR_item_t called_func, void *hook_ad
0x41, 0xff, 0xd2, /*callq *%r10 */
0x49, 0x89, 0xc2, /*mov %rax,%r10 */
#else
0x48, 0xba, 0, 0, 0, 0, 0, 0, 0, 0, /*movabs called_func,%rdx */
0x48, 0xb9, 0, 0, 0, 0, 0, 0, 0, 0, /*movabs ctx,%rcx */
0x49, 0xba, 0, 0, 0, 0, 0, 0, 0, 0, /*movabs <hook_address>,%r10*/
0x50, /*push %rax */
0x48, 0x83, 0xec, 0x20, /*sub 32,%rsp */
0x41, 0xff, 0xd2, /*callq *%r10 */
0x49, 0x89, 0xc2, /*mov %rax,%r10 */
0x48, 0x83, 0xc4, 0x20, /*add 32,%rsp */
0x58, /*pop %rax */
0x48, 0xba, 0, 0, 0, 0, 0, 0, 0, 0, /*movabs called_func,%rdx */
0x48, 0xb9, 0, 0, 0, 0, 0, 0, 0, 0, /*movabs ctx,%rcx */
0x49, 0xba, 0, 0, 0, 0, 0, 0, 0, 0, /*movabs <hook_address>,%r10*/
0x50, /*push %rax */
0x48, 0x83, 0xec, 0x20, /*sub 32,%rsp */
0x41, 0xff, 0xd2, /*callq *%r10 */
0x49, 0x89, 0xc2, /*mov %rax,%r10 */
0x48, 0x83, 0xc4, 0x20, /*add 32,%rsp */
0x58, /*pop %rax */
#endif
};
uint8_t *addr;

@ -312,6 +312,9 @@ static const struct insn_desc insn_descs[] = {
{MIR_BSTART, "bstart", {MIR_OP_INT | OUTPUT_FLAG, MIR_OP_BOUND}},
{MIR_BEND, "bend", {MIR_OP_INT, MIR_OP_BOUND}},
{MIR_VA_ARG, "va_arg", {MIR_OP_INT | OUTPUT_FLAG, MIR_OP_INT, MIR_OP_UNDEF, MIR_OP_BOUND}},
{MIR_VA_STACK_ARG,
"va_stack_arg",
{MIR_OP_INT | OUTPUT_FLAG, MIR_OP_INT, MIR_OP_INT, MIR_OP_BOUND}},
{MIR_VA_START, "va_start", {MIR_OP_INT, MIR_OP_BOUND}},
{MIR_VA_END, "va_end", {MIR_OP_INT, MIR_OP_BOUND}},
{MIR_LABEL, "label", {MIR_OP_BOUND}},
@ -785,6 +788,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_BLK: return "blk";
case MIR_T_UNDEF: return "undef";
default: return "";
}
@ -988,12 +992,19 @@ size_t _MIR_type_size (MIR_context_t ctx, MIR_type_t type) {
}
}
static int wrong_type_p (MIR_type_t type) { return type < MIR_T_I8 || type >= MIR_T_BLK; }
MIR_item_t MIR_new_data (MIR_context_t ctx, const char *name, MIR_type_t el_type, size_t nel,
const void *els) {
MIR_item_t tab_item, item = create_item (ctx, MIR_data_item, "data");
MIR_data_t data;
size_t el_len = _MIR_type_size (ctx, el_type);
size_t el_len;
if (wrong_type_p (el_type)) {
free (item);
(*error_func) (MIR_wrong_type_error, "wrong type in data %s", name);
}
el_len = _MIR_type_size (ctx, el_type);
item->u.data = data = malloc (sizeof (struct MIR_data) + el_len * nel);
if (data == NULL) {
free (item);
@ -1098,6 +1109,9 @@ static MIR_item_t new_proto_arr (MIR_context_t ctx, const char *name, size_t nre
if (curr_module == NULL)
(*error_func) (MIR_no_module_error, "Creating proto %s outside module", name);
for (size_t i = 0; i < nres; i++)
if (wrong_type_p (res_types[i]))
(*error_func) (MIR_wrong_type_error, "wrong result type in proto %s", name);
proto_item = create_item (ctx, MIR_proto_item, "proto");
proto_item->u.proto = create_proto (ctx, name, nres, res_types, nargs, vararg_p, args);
tab_item = add_item (ctx, proto_item);
@ -1164,6 +1178,9 @@ static MIR_item_t new_func_arr (MIR_context_t ctx, const char *name, size_t nres
if (nargs == 0 && vararg_p)
(*error_func) (MIR_vararg_func_error, "Variable arg function %s w/o any mandatory argument",
name);
for (size_t i = 0; i < nres; i++)
if (wrong_type_p (res_types[i]))
(*error_func) (MIR_wrong_type_error, "wrong result type in func %s", name);
func_item = create_item (ctx, MIR_func_item, "function");
curr_func = func_item->u.func = func
= malloc (sizeof (struct MIR_func) + nres * sizeof (MIR_type_t));
@ -1316,11 +1333,13 @@ void MIR_finish_func (MIR_context_t ctx) {
(*error_func) (MIR_vararg_func_error, "func %s: va_start is not in vararg function",
func_name);
} else if (code == MIR_RET && actual_nops != curr_func->nres) {
int nres = curr_func->nres;
curr_func = NULL;
(*error_func) (MIR_vararg_func_error,
"func %s: in instruction '%s': number of operands in return does not "
"correspond number of function returns. Expected %d, got %d",
func_name, insn_descs[code].name, curr_func->nres, actual_nops);
func_name, insn_descs[code].name, nres, actual_nops);
} else if (MIR_call_code_p (code))
expr_p = FALSE;
for (i = 0; i < actual_nops; i++) {
@ -1362,6 +1381,18 @@ void MIR_finish_func (MIR_context_t ctx) {
break;
case MIR_OP_MEM:
expr_p = FALSE;
if (wrong_type_p (insn->ops[i].u.mem.type)
&& (insn->ops[i].u.mem.type != MIR_T_BLK || !MIR_call_code_p (code))) {
curr_func = NULL;
(*error_func) (MIR_wrong_type_error, "func %s: in instruction '%s': wrong type memory",
func_name, insn_descs[code].name);
}
if (insn->ops[i].u.mem.type == MIR_T_BLK && insn->ops[i].u.mem.disp < 0) {
curr_func = NULL;
(*error_func) (MIR_wrong_type_error,
"func %s: in instruction '%s': block type memory with disp < 0", func_name,
insn_descs[code].name);
}
if (insn->ops[i].u.mem.base != 0) {
rd = find_rd_by_reg (ctx, insn->ops[i].u.mem.base, curr_func);
mir_assert (rd != NULL && insn->ops[i].u.mem.base == rd->reg);
@ -1400,7 +1431,8 @@ void MIR_finish_func (MIR_context_t ctx) {
}
insn->ops[i].value_mode = 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_START && i == 0)
|| ((code == MIR_VA_ARG || code == MIR_VA_STACK_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
@ -1616,8 +1648,8 @@ void MIR_link (MIR_context_t ctx, void (*set_interface) (MIR_context_t ctx, MIR_
process_inlines (ctx, item);
item->data = NULL;
#if 0
fprintf (stderr, "+++++ Function after inlining:\n");
MIR_output_item (ctx, stderr, func_item);
fprintf (stderr, "+++++ Function after inlining:\n");
MIR_output_item (ctx, stderr, item);
#endif
} else if (item->item_type == MIR_ref_data_item) {
assert (item->u.ref_data->ref_item->addr != NULL);
@ -1784,7 +1816,7 @@ static MIR_insn_t new_insn1 (MIR_context_t ctx, MIR_insn_code_t code) {
MIR_insn_t MIR_new_insn_arr (MIR_context_t ctx, MIR_insn_code_t code, size_t nops, MIR_op_t *ops) {
MIR_insn_t insn;
MIR_proto_t proto;
size_t args_start, i = 0, expected_nops = insn_code_nops (ctx, code);
size_t args_start, narg, i = 0, expected_nops = insn_code_nops (ctx, code);
mir_assert (ops != NULL);
if (!MIR_call_code_p (code) && code != MIR_UNSPEC && code != MIR_RET && code != MIR_SWITCH
@ -1812,7 +1844,34 @@ MIR_insn_t MIR_new_insn_arr (MIR_context_t ctx, MIR_insn_code_t code, size_t nop
(*error_func) (code == MIR_UNSPEC ? MIR_unspec_op_error : MIR_call_op_error,
"number of %s operands or results does not correspond to prototype %s",
code == MIR_UNSPEC ? "unspec" : "call", proto->name);
} else if (code == MIR_VA_ARG) {
for (i = args_start; i < nops; i++) {
if (ops[i].mode == MIR_OP_MEM && ops[i].u.mem.type == MIR_T_BLK) {
if (i - args_start < proto->nres)
(*error_func) (MIR_wrong_type_error, "result of %s is block type memory",
code == MIR_UNSPEC ? "unspec" : "call");
else if ((narg = i - args_start - proto->nres) < VARR_LENGTH (MIR_var_t, proto->args)) {
if (VARR_GET (MIR_var_t, proto->args, narg).type != MIR_T_BLK) {
(*error_func) (MIR_wrong_type_error,
"arg of %s is block type memory but param is not of block type",
code == MIR_UNSPEC ? "unspec" : "call");
} else if (VARR_GET (MIR_var_t, proto->args, narg).size != ops[i].u.mem.disp) {
(*error_func) (MIR_wrong_type_error,
"different sizes (%lu vs %lu) of arg and param block memory in %s insn",
(unsigned long) VARR_GET (MIR_var_t, proto->args, narg).size,
(unsigned long) ops[i].u.mem.disp,
code == MIR_UNSPEC ? "unspec" : "call");
}
}
} else if (i - args_start >= proto->nres
&& (narg = i - args_start - proto->nres) < VARR_LENGTH (MIR_var_t, proto->args)
&& VARR_GET (MIR_var_t, proto->args, narg).type == MIR_T_BLK) {
(*error_func) (MIR_wrong_type_error,
"param of %s is of block type but arg is not of block type memory "
"but ",
code == MIR_UNSPEC ? "unspec" : "call");
}
}
} else if (code == MIR_VA_ARG) { // undef mem ???
if (ops[2].mode != MIR_OP_MEM)
(*error_func) (MIR_op_mode_error,
"3rd operand of va_arg should be any memory with given type");
@ -2379,7 +2438,10 @@ static void output_func_proto (FILE *f, size_t nres, MIR_type_t *types, size_t n
var = VARR_GET (MIR_var_t, args, i);
if (i != 0 || nres != 0) fprintf (f, ", ");
mir_assert (var.name != NULL);
fprintf (f, "%s:%s", MIR_type_str (NULL, var.type), var.name);
if (var.type != MIR_T_BLK)
fprintf (f, "%s:%s", MIR_type_str (NULL, var.type), var.name);
else
fprintf (f, "%s:%lu(%s)", MIR_type_str (NULL, var.type), (unsigned long) var.size, var.name);
}
if (vararg_p) fprintf (f, nargs == 0 && nres == 0 ? "..." : ", ...");
fprintf (f, "\n");
@ -2734,11 +2796,12 @@ 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)
} else if (((code == MIR_VA_START && nop == 0)
|| ((code == MIR_VA_ARG || code == MIR_VA_STACK_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 {
} else if (mem_op.u.mem.type != MIR_T_BLK || !MIR_call_code_p (code)) {
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
? mem_op.u.mem.type
@ -3092,6 +3155,45 @@ static void set_inline_reg_map (MIR_context_t ctx, MIR_reg_t old_reg, MIR_reg_t
#define MIR_MAX_CALLER_SIZE_FOR_ANY_GROWTH_INLINE MIR_MAX_INSNS_FOR_INLINE
#endif
static void add_blk_move (MIR_context_t ctx, MIR_item_t func_item, MIR_insn_t before, MIR_op_t dest,
MIR_op_t src, size_t src_size) { /* simplified MIR only */
MIR_func_t func = func_item->u.func;
size_t blk_size = (src_size + 7) / 8 * 8;
MIR_insn_t insn;
MIR_reg_t addr_reg = _MIR_new_temp_reg (ctx, MIR_T_I64, func);
MIR_op_t addr = MIR_new_reg_op (ctx, addr_reg);
MIR_op_t disp = MIR_new_reg_op (ctx, _MIR_new_temp_reg (ctx, MIR_T_I64, func));
MIR_op_t size = MIR_new_reg_op (ctx, _MIR_new_temp_reg (ctx, MIR_T_I64, func));
MIR_op_t step = MIR_new_reg_op (ctx, _MIR_new_temp_reg (ctx, MIR_T_I64, func));
MIR_op_t temp = MIR_new_reg_op (ctx, _MIR_new_temp_reg (ctx, MIR_T_I64, func));
MIR_label_t loop = MIR_new_label (ctx), skip = MIR_new_label (ctx);
insn = MIR_new_insn (ctx, MIR_MOV, size, MIR_new_int_op (ctx, blk_size));
MIR_insert_insn_before (ctx, func_item, before, insn);
insn = MIR_new_insn (ctx, MIR_ALLOCA, dest, size);
MIR_insert_insn_before (ctx, func_item, before, insn);
insn = MIR_new_insn (ctx, MIR_MOV, disp, MIR_new_int_op (ctx, 0));
MIR_insert_insn_before (ctx, func_item, before, insn);
insn = MIR_new_insn (ctx, MIR_BLT, MIR_new_label_op (ctx, skip), size, disp);
MIR_insert_insn_before (ctx, func_item, before, insn);
MIR_insert_insn_before (ctx, func_item, before, loop);
insn = MIR_new_insn (ctx, MIR_ADD, addr, src, disp);
MIR_insert_insn_before (ctx, func_item, before, insn);
insn = MIR_new_insn (ctx, MIR_MOV, temp, MIR_new_mem_op (ctx, MIR_T_I64, 0, addr_reg, 0, 1));
MIR_insert_insn_before (ctx, func_item, before, insn);
insn = MIR_new_insn (ctx, MIR_ADD, addr, dest, disp);
MIR_insert_insn_before (ctx, func_item, before, insn);
insn = MIR_new_insn (ctx, MIR_MOV, MIR_new_mem_op (ctx, MIR_T_I64, 0, addr_reg, 0, 1), temp);
MIR_insert_insn_before (ctx, func_item, before, insn);
insn = MIR_new_insn (ctx, MIR_MOV, step, MIR_new_int_op (ctx, 8));
MIR_insert_insn_before (ctx, func_item, before, insn);
insn = MIR_new_insn (ctx, MIR_ADD, disp, disp, step);
MIR_insert_insn_before (ctx, func_item, before, insn);
insn = MIR_new_insn (ctx, MIR_BLT, MIR_new_label_op (ctx, loop), disp, size);
MIR_insert_insn_before (ctx, func_item, before, insn);
MIR_insert_insn_before (ctx, func_item, before, skip);
}
/* Only simplified code should be inlined because we need already
extensions and one return. */
static void process_inlines (MIR_context_t ctx, MIR_item_t func_item) {
@ -3103,7 +3205,7 @@ static void process_inlines (MIR_context_t ctx, MIR_item_t func_item) {
MIR_insn_t func_insn, next_func_insn, call, insn, new_insn, ret_insn, ret_label;
MIR_item_t called_func_item;
MIR_func_t func, called_func;
size_t func_insns_num, called_func_insns_num;
size_t func_insns_num, called_func_insns_num, blk_size;
char buff[50];
mir_assert (func_item->item_type == MIR_func_item);
@ -3162,13 +3264,21 @@ static void process_inlines (MIR_context_t ctx, MIR_item_t func_item) {
new_reg = MIR_new_func_reg (ctx, func, type, VARR_ADDR (char, temp_string));
set_inline_reg_map (ctx, old_reg, new_reg);
if (i < nargs && call->nops > i + 2 + called_func->nres) { /* Parameter passing */
new_insn
= MIR_new_insn (ctx,
type == MIR_T_F
? MIR_FMOV
: type == MIR_T_D ? MIR_DMOV : type == MIR_T_LD ? MIR_LDMOV : MIR_MOV,
MIR_new_reg_op (ctx, new_reg), call->ops[i + 2 + called_func->nres]);
MIR_insert_insn_before (ctx, func_item, ret_label, new_insn);
if (var.type == MIR_T_BLK) { /* alloca and block move: */
MIR_op_t op = call->ops[i + 2 + called_func->nres];
mir_assert (op.mode == MIR_OP_MEM);
add_blk_move (ctx, func_item, ret_label, MIR_new_reg_op (ctx, new_reg),
MIR_new_reg_op (ctx, op.u.mem.base), var.size);
} else {
new_insn
= MIR_new_insn (ctx,
type == MIR_T_F
? MIR_FMOV
: type == MIR_T_D ? MIR_DMOV : type == MIR_T_LD ? MIR_LDMOV : MIR_MOV,
MIR_new_reg_op (ctx, new_reg), call->ops[i + 2 + called_func->nres]);
MIR_insert_insn_before (ctx, func_item, ret_label, new_insn);
}
}
}
/* ??? No frame only alloca */
@ -3183,8 +3293,8 @@ static void process_inlines (MIR_context_t ctx, MIR_item_t func_item) {
inline_insns_after++;
actual_nops = MIR_insn_nops (ctx, insn);
new_insn = MIR_copy_insn (ctx, insn);
mir_assert (insn->code != MIR_VA_ARG && insn->code != MIR_VA_START
&& insn->code != MIR_VA_END);
mir_assert (insn->code != MIR_VA_ARG && insn->code != MIR_VA_STACK_ARG
&& insn->code != MIR_VA_START && insn->code != MIR_VA_END);
if (insn->code == MIR_ALLOCA) alloca_p = TRUE;
for (i = 0; i < actual_nops; i++) switch (new_insn->ops[i].mode) {
case MIR_OP_REG:
@ -3955,6 +4065,7 @@ static size_t write_item (MIR_context_t ctx, writer_func_t writer, MIR_item_t it
var = VARR_GET (MIR_var_t, proto->args, i);
len += write_type (ctx, writer, var.type);
len += write_name (ctx, writer, var.name);
if (var.type == MIR_T_BLK) len += write_uint (ctx, writer, var.size);
}
len += put_byte (ctx, writer, TAG_EOI);
return len;
@ -3969,6 +4080,7 @@ static size_t write_item (MIR_context_t ctx, writer_func_t writer, MIR_item_t it
var = VARR_GET (MIR_var_t, func->vars, i);
len += write_type (ctx, writer, var.type);
len += write_name (ctx, writer, var.name);
if (var.type == MIR_T_BLK) len += write_uint (ctx, writer, var.size);
}
len += put_byte (ctx, writer, TAG_EOI);
nlocals = VARR_LENGTH (MIR_var_t, func->vars) - func->nargs;
@ -4383,6 +4495,7 @@ static int func_proto_read (MIR_context_t ctx, MIR_module_t module, uint64_t *nr
(*error_func) (MIR_binary_io_error, "wrong prototype arg type tag %d", tag);
var.type = tag_type (tag);
var.name = read_name (ctx, module, "wrong arg name");
if (var.type == MIR_T_BLK) var.size = read_uint (ctx, "wrong block arg size");
VARR_PUSH (MIR_var_t, temp_vars, var);
}
*nres_ptr = nres;
@ -5098,7 +5211,9 @@ static void read_func_proto (MIR_context_t ctx, size_t nops, MIR_op_t *ops) {
if (ops[i].mode != MIR_OP_MEM) scan_error (ctx, "wrong prototype/func arg");
var.type = ops[i].u.mem.type;
var.name = (const char *) ops[i].u.mem.disp;
if (var.name == NULL) scan_error (ctx, "all func/prototype args should have type:name form");
if (var.name == NULL)
scan_error (ctx, "all func/prototype args should have form type:name or blk:size(name)");
if (var.type == MIR_T_BLK) var.size = ops[i].u.mem.base;
VARR_PUSH (MIR_var_t, temp_vars, var);
}
}
@ -5116,6 +5231,7 @@ static MIR_type_t str2type (const char *type_name) {
if (strcmp (type_name, "u16") == 0) return MIR_T_U16;
if (strcmp (type_name, "i8") == 0) return MIR_T_I8;
if (strcmp (type_name, "u8") == 0) return MIR_T_U8;
if (strcmp (type_name, "blk") == 0) return MIR_T_BLK;
return MIR_T_BOUND;
}
@ -5300,8 +5416,22 @@ void MIR_scan_string (MIR_context_t ctx, const char *str) {
if (proto_p || func_p || local_p) {
if (t.code == TC_COL) {
scan_token (ctx, &t, get_string_char, unget_string_char);
if (t.code != TC_NAME) scan_error (ctx, func_p ? "wrong arg" : "wrong local var");
op.u.mem.disp = (MIR_disp_t) t.u.name;
if (t.code == TC_NAME) {
op.u.mem.disp = (MIR_disp_t) t.u.name;
} else if (local_p || t.code != TC_INT || type != MIR_T_BLK) {
scan_error (ctx, local_p ? "wrong var" : "wrong arg");
} else {
op.u.mem.base = t.u.i;
if (t.u.i <= 0 || t.u.i >= (1l << sizeof (MIR_reg_t) * 8))
scan_error (ctx, "invalid block arg size");
scan_token (ctx, &t, get_string_char, unget_string_char);
if (t.code != TC_LEFT_PAR) scan_error (ctx, "wrong block arg");
scan_token (ctx, &t, get_string_char, unget_string_char);
if (t.code != TC_NAME) scan_error (ctx, "wrong block arg");
op.u.mem.disp = (MIR_disp_t) t.u.name;
scan_token (ctx, &t, get_string_char, unget_string_char);
if (t.code != TC_RIGHT_PAR) scan_error (ctx, "wrong block arg");
}
scan_token (ctx, &t, get_string_char, unget_string_char);
}
} else {

@ -52,8 +52,8 @@ typedef enum MIR_error_type {
REP8 (ERR_EL, no, syntax, binary_io, alloc, finish, no_module, nested_module, no_func),
REP4 (ERR_EL, func, vararg_func, nested_func, wrong_param_value),
REP5 (ERR_EL, reserved_name, import_export, undeclared_func_reg, repeated_decl, reg_type),
REP8 (ERR_EL, unique_reg, undeclared_op_ref, ops_num, call_op, unspec_op, ret, op_mode, out_op),
ERR_EL (invalid_insn)
REP6 (ERR_EL, wrong_type, unique_reg, undeclared_op_ref, ops_num, call_op, unspec_op),
REP4 (ERR_EL, ret, op_mode, out_op, invalid_insn)
} MIR_error_type_t;
#ifdef __GNUC__
@ -125,7 +125,8 @@ typedef enum {
INSN_EL (ALLOCA), /* 2 operands: result address and size */
REP2 (INSN_EL, BSTART, BEND), /* block start: result addr; block end: addr from block start */
/* Special insns: */
INSN_EL (VA_ARG), /* result is arg address, operands: va_list addr and memory */
INSN_EL (VA_ARG), /* result is arg address, operands: va_list addr and memory */
INSN_EL (VA_STACK_ARG), /* result is arg address, operands: va_list addr and integer (size) */
INSN_EL (VA_START),
INSN_EL (VA_END), /* operand is va_list */
INSN_EL (LABEL), /* One immediate operand is unique label number */
@ -140,7 +141,7 @@ typedef enum {
typedef enum {
REP8 (TYPE_EL, I8, U8, I16, U16, I32, U32, I64, U64), /* Integer types of different size: */
REP3 (TYPE_EL, F, D, LD), /* Float or (long) double type */
TYPE_EL (P), /* Pointer */
REP2 (TYPE_EL, P, BLK), /* Pointer and memory block */
REP2 (TYPE_EL, UNDEF, BOUND),
} MIR_type_t;
@ -257,8 +258,9 @@ struct MIR_insn {
DEF_DLIST (MIR_insn_t, insn_link);
typedef struct MIR_var {
MIR_type_t type;
MIR_type_t type; /* MIR_T_BLK can be used only args */
const char *name;
size_t size; /* ignored for type != MIR_T_BLK */
} MIR_var_t;
DEF_VARR (MIR_var_t);
@ -588,14 +590,20 @@ extern void _MIR_update_code_arr (MIR_context_t ctx, uint8_t *base, size_t nloc,
extern void _MIR_update_code (MIR_context_t ctx, uint8_t *base, size_t nloc, ...);
extern void *va_arg_builtin (void *p, uint64_t t);
extern void *va_stack_arg_builtin (void *p, size_t s);
extern void va_start_interp_builtin (MIR_context_t ctx, void *p, void *a);
extern void va_end_interp_builtin (MIR_context_t ctx, void *p);
extern void *_MIR_get_bstart_builtin (MIR_context_t ctx);
extern void *_MIR_get_bend_builtin (MIR_context_t ctx);
typedef struct {
MIR_type_t type;
size_t size; /* used only for block arg (type == MIR_T_BLK) */
} _MIR_arg_desc_t;
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, int vararg_p);
_MIR_arg_desc_t *arg_descs, 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);

@ -2,6 +2,8 @@
#define LUA_CORE
#include "ravi_mirjit.h"
#include "lua.h"
#include "lapi.h"
#include "lauxlib.h"
@ -9,147 +11,241 @@
#include "lmem.h"
#include "lstring.h"
#include "ltable.h"
#include "lvm.h"
#include <string.h>
struct CompilerContext {
lua_State* L;
Table* h; /* to avoid collection/reuse strings */
lua_State* L;
ravi_State* jit;
Table* h; /* to avoid collection/reuse strings */
};
static void debug_message(void* context, const char* filename, long long line, const char* message) {
struct CompilerContext* ccontext = (struct CompilerContext*)context;
ravi_writestring(ccontext->L, filename, strlen(filename));
char temp[80];
snprintf(temp, sizeof temp, "%lld: ", line);
ravi_writestring(ccontext->L, temp, strlen(temp));
ravi_writestring(ccontext->L, message, strlen(message));
ravi_writeline(ccontext->L);
}
void error_message(void* context, const char* message) {
struct CompilerContext* ccontext = (struct CompilerContext*)context;
ravi_writestring(ccontext->L, message, strlen(message));
ravi_writeline(ccontext->L);
}
/* Create a new proto and insert it into parent's list of protos */
static Proto* lua_newProto(void* context, Proto* parent) {
struct CompilerContext* ccontext = (struct CompilerContext*)context;
lua_State* L = ccontext->L;
Proto* p = luaF_newproto(L);
if (parent) {
int old_size = parent->sizep;
int new_size = parent->sizep + 1;
luaM_growvector(L, parent->p, old_size, new_size, Proto*, MAXARG_Bx, "functions");
parent->p[parent->sizep++] = p;
// luaC_objbarrier(L, f, clp);
}
return p;
struct CompilerContext* ccontext = (struct CompilerContext*)context;
lua_State* L = ccontext->L;
Proto* p = luaF_newproto(L);
assert(parent);
/* FIXME make this more efficient */
int old_size = parent->sizep;
int new_size = parent->sizep + 1;
luaM_reallocvector(L, parent->p, old_size, new_size, Proto*);
parent->p[old_size] = p;
parent->sizep++;
lua_assert(parent->sizep == new_size);
luaC_objbarrier(L, parent, p);
return p;
}
/*
* Based off the Lua lexer code.
*/
TString* create_newstring(lua_State* L, Table *h, const char* str, size_t l) {
TValue* o; /* entry for 'str' */
TString* ts = luaS_newlstr(L, str, l); /* create new string */
setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */
o = luaH_set(L, h, L->top - 1);
if (ttisnil(o)) { /* not in use yet? */
/* boolean value does not need GC barrier;
table has no metatable, so it does not need to invalidate cache */
setbvalue(o, 1); /* t[string] = true */
luaC_checkGC(L);
}
else { /* string already present */
ts = tsvalue(keyfromval(o)); /* re-use value previously stored */
}
L->top--; /* remove string from stack */
return ts;
* Based off the Lua lexer code. Strings are anchored in a table initially - eventually
* ending up either in a Proto constant table or some other structure related to
* protos.
*/
TString* intern_string(lua_State* L, Table* h, const char* str, size_t l) {
TValue* o; /* entry for 'str' */
TString* ts = luaS_newlstr(L, str, l); /* create new string */
setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */
o = luaH_set(L, h, L->top - 1);
if (ttisnil(o)) { /* not in use yet? */
/* boolean value does not need GC barrier;
table has no metatable, so it does not need to invalidate cache */
setbvalue(o, 1); /* t[string] = true */
luaC_checkGC(L);
}
else { /* string already present */
ts = tsvalue(keyfromval(o)); /* re-use value previously stored */
}
L->top--; /* remove string from stack */
return ts;
}
/*
** Add constant 'v' to prototype's list of constants (field 'k').
** Use scanner's table to cache position of constants in constant list
** and try to reuse constants. Because some values should not be used
** as keys (nil cannot be a key, integer keys can collapse with float
** keys), the caller must provide a useful 'key' for indexing the cache.
** Use parser's table to cache position of constants in constant list
** and try to reuse constants.
*/
static int addk(lua_State *L, Proto* f, Table* h, TValue* key, TValue* v) {
TValue* idx = luaH_set(L, h, key); /* index scanner table */
int k, oldsize;
if (ttisinteger(idx)) { /* is there an index there? */
k = cast_int(ivalue(idx));
/* correct value? (warning: must distinguish floats from integers!) */
if (k < f->sizek && ttype(&f->k[k]) == ttype(v) &&
luaV_rawequalobj(&f->k[k], v))
return k; /* reuse index */
}
/* constant not found; create a new entry */
oldsize = f->sizek;
k = f->sizek;
/* numerical value does not need GC barrier;
table has no metatable, so it does not need to invalidate cache */
setivalue(idx, k);
luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants");
while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]);
setobj(L, &f->k[k], v);
f->sizek++;
luaC_barrier(L, f, v);
return k;
static int add_konstant(lua_State* L, Proto* f, Table* h, TValue* key, TValue* v) {
TValue* idx = luaH_set(L, h, key); /* The k index is cached against the key */
int k, oldsize, newsize;
if (ttisinteger(idx)) { /* is there an integer value index there? */
k = cast_int(ivalue(idx));
/* correct value? (warning: must distinguish floats from integers!) */
if (k >= 0 && k < f->sizek && ttype(&f->k[k]) == ttype(v) && luaV_rawequalobj(&f->k[k], v))
return k; /* reuse index */
}
/* constant not found; create a new entry in Proto->k */
oldsize = k = f->sizek;
newsize = oldsize + 1;
/* numerical value does not need GC barrier;
table has no metatable, so it does not need to invalidate cache */
setivalue(idx, k);
// FIXME make the allocation more efficient
luaM_reallocvector(L, f->k, oldsize, newsize, TValue);
setobj(L, &f->k[k], v); /* record the position k in the table against key */
f->sizek++;
lua_assert(f->sizek == newsize);
luaC_barrier(L, f, v);
return k;
}
/*
** Add a string to list of constants and return its index.
*/
static int lua_stringK(lua_State *L, Proto* p, Table *h, TString* s) {
TValue o;
setsvalue(L, &o, s);
return addk(L, p, h, &o, &o); /* use string itself as key */
static int add_string_konstant(lua_State* L, Proto* p, Table* h, TString* s) {
TValue o;
setsvalue(L, &o, s);
return add_konstant(L, p, h, &o, &o); /* use string itself as key */
}
/* Create a Lua TString object from a string. Save it so that we can avoid creating same
* string again.
*/
static inline TString* create_luaString(lua_State* L, Table* h, struct string_object* s) {
if (s->userdata == NULL) {
/* Create and save it */
s->userdata = intern_string(L, h, s->str, s->len);
}
return (TString*)s->userdata;
}
/* Add a string constant to Proto and return its index */
static int lua_newStringConstant(void *context, Proto* proto, struct string_object *s) {
struct CompilerContext* ccontext = (struct CompilerContext*)context;
lua_State* L = ccontext->L;
Table* h = ccontext->h;
TString* ts = NULL;
if (s->userdata == NULL) {
ts = create_newstring(L, h, s->str, s->len);
s->userdata = ts;
}
else {
ts = (TString *) s->userdata;
}
return lua_stringK(L, proto, h, ts);
static int lua_newStringConstant(void* context, Proto* proto, struct string_object* s) {
struct CompilerContext* ccontext = (struct CompilerContext*)context;
lua_State* L = ccontext->L;
Table* h = ccontext->h;
TString* ts = create_luaString(L, h, s);
return add_string_konstant(L, proto, h, ts);
}
/* Compile the C code for the given proto, and C source */
int lua_compileProto(void *context, Proto* proto, const char* C_src, unsigned len) {
struct CompilerContext* ccontext = (struct CompilerContext*)context;
lua_State* L = ccontext->L;
/* Add an upvalue. If the upvalue refers to a local variable in parent proto then idx should contain
* the register for the local variable and instack should be true, else idx should have the index of
* upvalue in parent proto and instack should be false.
*/
static int lua_addUpValue(void* context, Proto* f, struct string_object* name, unsigned idx, int instack, unsigned tc,
struct string_object* usertype) {
ravitype_t typecode = (ravitype_t)tc;
struct CompilerContext* ccontext = (struct CompilerContext*)context;
lua_State* L = ccontext->L;
Table* h = ccontext->h;
int oldsize = f->sizeupvalues;
int newsize = oldsize + 1;
int pos = oldsize;
// checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues");
// FIXME optimize the allocation
luaM_reallocvector(L, f->upvalues, oldsize, newsize, Upvaldesc);
f->sizeupvalues++;
lua_assert(f->sizeupvalues == newsize);
f->upvalues[pos].instack = cast_byte(instack); /* is the upvalue in parent function's local stack ? */
f->upvalues[pos].idx = cast_byte(idx); /* If instack then parent's local register else parent's upvalue index */
TString* tsname = create_luaString(L, h, name); /* name of the variable */
f->upvalues[pos].name = tsname;
f->upvalues[pos].ravi_type = typecode;
if (usertype != NULL) {
/* User type string goes into the proto's constant table */
int kpos = lua_newStringConstant(context, f, usertype);
f->upvalues[pos].usertype = tsvalue(&f->k[kpos]);
}
else {
f->upvalues[pos].usertype = NULL;
}
luaC_objbarrier(L, f, tsname);
return pos;
}
static void init_C_compiler(void* context) {
struct CompilerContext* ccontext = (struct CompilerContext*)context;
mir_prepare(ccontext->jit->jit, 2);
}
static void* compile_C(void* context, const char* C_src, unsigned len) {
struct CompilerContext* ccontext = (struct CompilerContext*)context;
fprintf(stdout, "%s\n", C_src);
return mir_compile_C_module(&ccontext->jit->options, ccontext->jit->jit, C_src, "input");
}
static void finish_C_compiler(void* context) {
struct CompilerContext* ccontext = (struct CompilerContext*)context;
mir_cleanup(ccontext->jit->jit);
}
static lua_CFunction get_compiled_function(void* context, void* module, const char* name) {
struct CompilerContext* ccontext = (struct CompilerContext*)context;
MIR_module_t M = (MIR_module_t)module;
return (lua_CFunction)mir_get_func(ccontext->jit->jit, M, name);
}
static void lua_setProtoFunction(void* context, Proto* p, lua_CFunction func) {
p->ravi_jit.jit_function = func;
p->ravi_jit.jit_status = RAVI_JIT_COMPILED;
}
static void lua_setVarArg(void* context, Proto* p) { p->is_vararg = 1; }
static void lua_setNumParams(void* context, Proto* p, unsigned num_params) { p->numparams = cast_byte(num_params); }
static void lua_setMaxStackSize(void *context, Proto *p, unsigned max_stack_size) {
p->maxstacksize = cast_byte(max_stack_size);
}
static int load_and_compile(lua_State* L) {
const char* s = luaL_checkstring(L, 1);
struct CompilerContext ccontext = { .L = L };
LClosure* cl = luaF_newLclosure(L, 1); /* create main closure */
setclLvalue(L, L->top, cl); /* anchor it (to avoid being collected) */
luaD_inctop(L);
ccontext.h = luaH_new(L); /* create table for string constants */
sethvalue(L, L->top, ccontext.h); /* anchor it */
luaD_inctop(L);
Proto *main_proto = cl->p = luaF_newproto(L);
luaC_objbarrier(L, cl, cl->p);
struct Ravi_CompilerInterface ravicomp_interface = {
.source = s,
.source_len = strlen(s),
.source_name = "input",
.lua_newProto = lua_newProto,
.lua_newStringConstant = lua_newStringConstant,
.main_proto = main_proto,
.context = &ccontext
};
int rc = raviX_compile(&ravicomp_interface);
L->top--; /* remove table */
lua_assert(cl->nupvalues == cl->p->sizeupvalues);
luaF_initupvals(L, cl);
const char* s = luaL_checkstring(L, 1);
struct CompilerContext ccontext = {.L = L, .jit = G(L)->ravi_state};
LClosure* cl = luaF_newLclosure(L, 1); /* create main closure with 1 up-value for _ENV */
setclLvalue(L, L->top, cl); /* anchor it (to avoid being collected) */
luaD_inctop(L);
ccontext.h = luaH_new(L); /* create table for string constants */
sethvalue(L, L->top, ccontext.h); /* anchor it */
luaD_inctop(L);
Proto* main_proto = cl->p = luaF_newproto(L);
luaC_objbarrier(L, cl, cl->p);
struct Ravi_CompilerInterface ravicomp_interface = {.source = s,
.source_len = strlen(s),
.source_name = "input",
.main_proto = main_proto,
.context = &ccontext,
.lua_newProto = lua_newProto,
.lua_newStringConstant = lua_newStringConstant,
.lua_addUpValue = lua_addUpValue,
.lua_setVarArg = lua_setVarArg,
.lua_setProtoFunction = lua_setProtoFunction,
.lua_setNumParams = lua_setNumParams,
.lua_setMaxStackSize = lua_setMaxStackSize,
.init_C_compiler = init_C_compiler,
.compile_C = compile_C,
.finish_C_compiler = finish_C_compiler,
.get_compiled_function = get_compiled_function,
.debug_message = debug_message,
.error_message = error_message};
int rc = raviX_compile(&ravicomp_interface);
L->top--; /* remove table for string constants */
if (rc == 0) {
lua_assert(cl->nupvalues == cl->p->sizeupvalues);
luaF_initupvals(L, cl);
return 1;
}
else {
lua_error(L);
return 0;
}
}
static const luaL_Reg ravilib[] = {
{NULL, NULL} };
static const luaL_Reg ravilib[] = {{"load", load_and_compile}, {NULL, NULL}};
int (raviopen_compiler)(lua_State *L) {
luaL_newlib(L, ravilib);
return 1;
int(raviopen_compiler)(lua_State* L) {
luaL_newlib(L, ravilib);
return 1;
}

@ -188,7 +188,7 @@ int raviV_initjit(struct lua_State *L) {
jit->enabled_ = 1;
jit->min_code_size_ = 150;
jit->min_exec_count_ = 50;
jit->opt_level_ = 1;
jit->opt_level_ = 2;
// The parameter true means we will be dumping stuff as we compile
jit->jit = MIR_init();
G->ravi_state = jit;
@ -281,7 +281,7 @@ int raviV_getjitenabled(lua_State *L) {
void raviV_setoptlevel(lua_State *L, int value) {
global_State *G = G(L);
if (!G->ravi_state) return;
G->ravi_state->opt_level_ = value;
G->ravi_state->opt_level_ = value >= 0 && value <= 3 ? value : G->ravi_state->opt_level_;
}
int raviV_getoptlevel(lua_State *L) {
global_State *G = G(L);
@ -364,7 +364,7 @@ static int t_getc (void *data) {
}
/* Searches within a Module for a function by name */
static MIR_item_t find_function(MIR_module_t module, const char *func_name) {
MIR_item_t mir_find_function(MIR_module_t module, const char *func_name) {
MIR_item_t func, main_func = NULL;
for (func = DLIST_HEAD (MIR_item_t, module->items); func != NULL;
func = DLIST_NEXT (MIR_item_t, func)) {
@ -374,21 +374,21 @@ static MIR_item_t find_function(MIR_module_t module, const char *func_name) {
return main_func;
}
void *MIR_compile_C_module(
MIR_module_t mir_compile_C_module(
struct c2mir_options *options,
MIR_context_t ctx,
const char *inputbuffer, /* Code to be compiled */
const char *func_name, /* Name of the function, must be unique */
void *(Import_resolver_func)(const char *name)) /* Resolve external symbols */
const char *source_name /* Name of the function, must be unique */
)
{
int ret_code = 0;
int (*fun_addr) (void *) = NULL;
char module_name[30];
struct ReadBuffer read_buffer = {.Current_char = 0, .Source_code = inputbuffer};
MIR_module_t module = NULL;
c2mir_init(ctx);
options->module_num++;
snprintf(module_name, sizeof module_name, "__mod_%lld__", options->module_num);
options->message_file = stderr;
if (!c2mir_compile(ctx, options, t_getc, &read_buffer, func_name, NULL)) {
if (!c2mir_compile(ctx, options, t_getc, &read_buffer, module_name, NULL)) {
ret_code = 1;
}
else {
@ -399,22 +399,50 @@ void *MIR_compile_C_module(
ret_code = 1;
}
if (ret_code == 0 && module) {
MIR_item_t main_func = find_function(module, func_name);
if (main_func == NULL) {
fprintf(stderr, "Error: Compiled function %s not found\n", func_name);
exit(1);
}
MIR_load_module (ctx, module);
MIR_gen_init (ctx);
MIR_gen_set_optimize_level(ctx, 2);
MIR_link (ctx, MIR_set_gen_interface, Import_resolver_func);
fun_addr = MIR_gen (ctx, main_func);
MIR_gen_finish (ctx);
MIR_link (ctx, MIR_set_gen_interface, import_resolver);
}
return ret_code == 0 && module ? module : NULL;
}
void *mir_get_func(MIR_context_t ctx, MIR_module_t module, const char *func_name) {
MIR_item_t main_func = mir_find_function(module, func_name);
if (main_func == NULL) {
fprintf(stderr, "Error: Compiled function %s not found\n", func_name);
exit(1);
}
return MIR_gen (ctx, main_func);
}
void mir_prepare(MIR_context_t ctx, int optlevel) {
c2mir_init(ctx);
MIR_gen_init (ctx);
MIR_gen_set_optimize_level(ctx, optlevel);
}
void mir_cleanup(MIR_context_t ctx) {
MIR_gen_finish (ctx);
c2mir_finish (ctx);
}
static void *compile_C_module(
struct c2mir_options *options,
MIR_context_t ctx,
const char *inputbuffer, /* Code to be compiled */
const char *func_name /* Name of the function, must be unique */
)
{
int (*fun_addr) (void *) = NULL;
mir_prepare(ctx, 2);
MIR_module_t module = mir_compile_C_module(options, ctx, inputbuffer, func_name);
if (module) {
fun_addr = mir_get_func(ctx, module, func_name);
}
mir_cleanup(ctx);
return fun_addr;
}
// Compile a Lua function
// If JIT is turned off then compilation is skipped
// Compilation occurs if either auto compilation is ON (subject to some
@ -469,7 +497,7 @@ int raviV_compile(struct lua_State *L, struct Proto *p, ravi_compile_options_t *
ravi_writestring(L, buf.buf, strlen(buf.buf));
ravi_writeline(L);
}
fp = MIR_compile_C_module(&G->ravi_state->options, G->ravi_state->jit, buf.buf, fname, import_resolver);
fp = compile_C_module(&G->ravi_state->options, G->ravi_state->jit, buf.buf, fname);
if (!fp) {
p->ravi_jit.jit_status = RAVI_JIT_CANT_COMPILE;
}

@ -0,0 +1,10 @@
f = compiler.load("return 1, 'hello', 5.6, true")
assert(f and type(f) == 'function')
local x = 4.3
local a,b,c,d,e = f()
assert(a == 1)
assert(b == 'hello')
assert(c == 5.6)
assert(d == true)
assert(x == 4.3)
assert(e == nil)

@ -0,0 +1,8 @@
f = compiler.load("local a, b, c = 4.2, true, 'hi' return a, b, c")
assert(f and type(f) == 'function')
local z = 62
local a,b,c,d = f()
assert(z == 62)
assert(a == 4.2)
assert(b == true)
assert(c == 'hi')

@ -0,0 +1,3 @@
f = compiler.load("local a,b = 1,2 return a or b");
assert(f and type(f) == 'function')
assert(f() == 1)

@ -0,0 +1,3 @@
f = compiler.load("local a,b = 1,2 return a and b");
assert(f and type(f) == 'function')
assert(f() == 2)

@ -0,0 +1,3 @@
f = compiler.load("local a = 2 return 1 or a");
assert(f and type(f) == 'function')
assert(f() == 1)

@ -0,0 +1,3 @@
f = compiler.load("local a = 2 return 1 and a");
assert(f and type(f) == 'function')
assert(f() == 2)
Loading…
Cancel
Save