Skip to content

Commit

Permalink
issue #169 Update MIR to latest version
Browse files Browse the repository at this point in the history
  • Loading branch information
dibyendumajumdar committed Aug 28, 2020
1 parent cde0a39 commit 90f5498
Show file tree
Hide file tree
Showing 15 changed files with 1,552 additions and 368 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ 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")
Expand Down
311 changes: 211 additions & 100 deletions mir/c2mir/c2mir.c

Large diffs are not rendered by default.

230 changes: 230 additions & 0 deletions mir/c2mir/x86_64/cx86_64-ABI-code.c
Original file line number Diff line number Diff line change
@@ -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;
}
}
86 changes: 72 additions & 14 deletions mir/mir-aarch64.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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]! */
Expand Down Expand Up @@ -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> */
Expand All @@ -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 {
Expand All @@ -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));
Expand Down
Loading

0 comments on commit 90f5498

Please sign in to comment.