issue #169 MIR update

llvm
Dibyendu Majumdar 3 years ago
parent 389c98ee35
commit f9acba8142

@ -400,7 +400,7 @@
* The first insn saves the stack pointer in the operand
* The second insn restores stack pointer from the operand
### MIR_VA_START, MIR_VA_ARG, MIR_VA_STACK_ARG, and MIR_VA_END insns
### MIR_VA_START, MIR_VA_ARG, MIR_VA_BLOCK_ARG, and MIR_VA_END insns
* These insns are only for variable number arguments functions
* `MIR_VA_START` and `MIR_VA_END` have one input operand, an address
of va_list structure (see C stdarg.h for more details). Unlike C
@ -408,9 +408,8 @@
* `MIR_VA_ARG` takes va_list and any memory operand and returns
address of the next argument in the 1st insn operand. The memory
operand type defines the type of the argument
* `MIR_VA_STACK_ARG` takes va_list and integer operand and returns
address of the next argument passed as a block argument
of the size given by the integer operand
* `MIR_VA_BLOCK_ARG` takes result address, va_list, and integer operand
and moves the next argument passed as block of give size to the result address
* va_list operand can be memory with undefined type. In this case
address of the va_list is not in the memory but is the
memory address
@ -606,17 +605,23 @@ main: func
works only on the same targets as MIR generator
# MIR generator (file mir-gen.h)
* Before use of MIR generator for given context you should initialize it by API function `MIR_gen_init (MIR_context ctx)`
* API function `MIR_gen_finish (MIR_context ctx)` frees all internal generator data for the context.
If you want to generate code for the context again after the `MIR_gen_finish` call, you should call `MIR_gen_init` again first
* API function `void *MIR_gen (MIR_context ctx, MIR_item_t func_item)` generates machine code of given MIR function
and returns an address to call it. You can call the code as usual C function by using this address
as the called function address
* API function `void MIR_gen_set_debug_file (MIR_context_t ctx, FILE *f)` sets up MIR generator debug file to `f`.
* Before use of MIR generator for given context you should initialize it by API function
`MIR_gen_init (MIR_context ctx, int gens_num)`. `gens_num` defines how many generator instances you need.
Each generator instance can be used in a different thread to compile different MIR functions from the same context.
If you pass a negative or zero number `gens_num`, it will have the same effect as value `1`
* API function `MIR_gen_finish (MIR_context ctx)` frees all internal generator data (and its instances) for the context.
If you want to generate code for the context again after the `MIR_gen_finish` call, you should call
`MIR_gen_init` again first
* API function `void *MIR_gen (MIR_context ctx, int gen_num, MIR_item_t func_item)` generates machine code
of given MIR function in generator instance `gen_num` and returns an address to call it. You can call
the code as usual C function by using this address as the called function address.
`gen_num` should be a number in the range `0` .. `gens_num - 1` from corresponding `MIR_gen_init`
* API function `void MIR_gen_set_debug_file (MIR_context_t ctx, int gen_num, FILE *f)` sets up MIR generator
debug file to `f` for generator instance `gen_num`.
If it is not NULL a lot of debugging and optimization information will be output to the file. It is useful mostly
for MIR developers
* API function `void MIR_gen_set_optimize_level (MIR_context_t ctx, unsigned int level)` sets up optimization
level for MIR generator:
* API function `void MIR_gen_set_optimize_level (MIR_context_t ctx, int gen_num, unsigned int level)` sets up optimization
level for MIR generator instance `gen_num`:
* `0` means only register allocator and machine code generator work
* `1` means additional code selection task. On this level MIR generator creates more compact and faster
code than on zero level with practically on the same speed

@ -78,6 +78,10 @@ static void target_add_ret_ops (c2m_ctx_t c2m_ctx, struct type *ret_type, op_t r
gen_multiple_load_store (c2m_ctx, ret_type, VARR_ADDR (MIR_op_t, ret_ops), res.mir_op, TRUE);
}
static MIR_type_t target_get_blk_type (c2m_ctx_t c2m_ctx, struct type *arg_type) {
return MIR_T_BLK; /* one BLK is enough */
}
static void target_add_arg_proto (c2m_ctx_t c2m_ctx, const char *name, struct type *arg_type,
target_arg_info_t *arg_info, VARR (MIR_var_t) * arg_vars) {
simple_add_arg_proto (c2m_ctx, name, arg_type, arg_info, arg_vars);

@ -3,11 +3,16 @@
*/
#include "../mirc.h"
#include "mirc-aarch64-linux.h"
#include "mirc_aarch64_linux.h"
static const char *standard_includes[] = {mirc, aarch64_mirc};
#include "mirc_aarch64_float.h"
#include "mirc_aarch64_limits.h"
#include "mirc_aarch64_stdarg.h"
#include "mirc_aarch64_stdint.h"
#include "mirc_aarch64_stddef.h"
static const char *standard_include_dirs[] = {"include/mirc/", "include/mirc/aarch64/"};
static string_include_t standard_includes[]
= {{NULL, mirc}, {NULL, aarch64_mirc}, TARGET_STD_INCLUDES};
#define MAX_ALIGNMENT 16

@ -0,0 +1,60 @@
/* This file is a part of MIR project.
Copyright (C) 2020 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
/* See C11 5.2.4.2.2 */
static char float_str[]
= "#ifndef __FLOAT_H\n"
"#define __FLOAT_H\n"
"\n"
"#define FLT_RADIX 2\n"
"\n"
"#define FLT_MANT_DIG 24\n"
"#define DBL_MANT_DIG 53\n"
"#define LDBL_MANT_DIG DBL_MANT_DIG\n"
"\n"
"#define FLT_DECIMAL_DIG 9\n"
"#define DBL_DECIMAL_DIG 17\n"
"#define LDBL_DECIMAL_DIG DBL_DECIMAL_DIG\n"
"#define FLT_DIG FLT_DECIMAL_DIG\n"
"#define DBL_DIG DBL_DECIMAL_DIG\n"
"#define LDBL_DIG LDBL_DECIMAL_DIG\n"
"\n"
"#define DECIMAL_DIG LDBL_DECIMAL_DIG\n"
"\n"
"#define FLT_MIN_EXP -125\n"
"#define DBL_MIN_EXP -1021\n"
"#define LDBL_MIN_EXP DBL_MIN_EXP\n"
"\n"
"#define FLT_MIN_10_EXP -37\n"
"#define DBL_MIN_10_EXP -307\n"
"#define LDBL_MIN_10_EXP DBL_MIN_10_EXP\n"
"\n"
"#define FLT_MAX_EXP 128\n"
"#define DBL_MAX_EXP 1024\n"
"#define LDBL_MAX_EXP DBL_MAX_EXP\n"
"\n"
"#define FLT_MAX_10_EXP 38\n"
"#define DBL_MAX_10_EXP 308\n"
"#define LDBL_MAX_10_EXP DBL_MAX_10_EXP\n"
"\n"
"#define FLT_MAX 0x1.fffffep+127\n"
"#define DBL_MAX 0x1.fffffffffffffp+1023\n"
"#define LDBL_MAX DBL_MAX\n"
"\n"
"#define FLT_EPSILON 0x1p-23\n"
"#define DBL_EPSILON 0x1p-52\n"
"#define LDBL_EPSILON DBL_EPSILON\n"
"\n"
"#define FLT_MIN 0x1p-126\n"
"#define DBL_MIN 0x1p-1022\n"
"#define LDBL_MIN DBL_MIN\n"
"\n"
"#define FLT_TRUE_MIN 0x1p-149\n"
"#define DBL_TRUE_MIN 0x0.0000000000001p-1022\n"
"#define LDBL_TRUE_MIN DBL_TRUE_MIN\n"
"\n"
"#define FLT_EVAL_METHOD 0\n"
"#define FLT_ROUNDS 1 /* round to the nearest */\n"
"\n"
"#endif /* #ifndef __FLOAT_H */\n";

@ -0,0 +1,38 @@
/* This file is a part of MIR project.
Copyright (C) 2020 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
/* See 5.2.4.2 */
static char limits_str[]
= "#ifndef __LIMITS_H\n"
"#define __LIMITS_H\n"
"\n"
"#define CHAR_BIT 8\n"
"\n"
"#define SCHAR_MIN (-SCHAR_MAX - 1)\n"
"#define SCHAR_MAX 127\n"
"#define UCHAR_MAX (SCHAR_MAX * 2 + 1)\n"
"\n"
"#define MB_LEN_MAX 1\n"
"\n"
"#define SHRT_MIN (-SHRT_MAX - 1)\n"
"#define SHRT_MAX 32767\n"
"#define USHRT_MAX (SHRT_MAX * 2 + 1)\n"
"\n"
"#define INT_MIN (-INT_MAX - 1)\n"
"#define INT_MAX 2147483647\n"
"#define UINT_MAX (INT_MAX * 2u + 1u)\n"
"\n"
"#define LONG_MIN (-LONG_MAX - 1l)\n"
"#define LONG_MAX 9223372036854775807l\n"
"#define ULONG_MAX (LONG_MAX * 2ul + 1ul)\n"
"\n"
"#define LLONG_MIN LONG_MIN\n"
"#define LLONG_MAX LONG_MAX\n"
"#define ULLONG_MAX ULONG_MAX\n"
"\n"
"/* signed char by default */\n"
"#define CHAR_MIN SCHAR_MIN\n"
"#define CHAR_MAX SCHAR_MAX\n"
"\n"
"#endif /* #ifndef __LIMITS_H */\n";

@ -0,0 +1,27 @@
/* This file is a part of MIR project.
Copyright (C) 2020 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
static char stdarg_str[]
= "#ifndef __STDARG_H\n"
"#define __STDARG_H\n"
"\n"
"typedef struct {\n"
" void *__stack;\n"
" void *__gr_top;\n"
" void *__vr_top;\n"
" int __gr_offs;\n"
" int __vr_offs;\n"
"} va_list;\n"
"\n"
"#define va_start(ap, param) __builtin_va_start (ap)\n"
"#define va_arg(ap, type) __builtin_va_arg(ap, (type *) 0)\n"
"#define va_end(ap) 0\n"
"#define va_copy(dest, src) ((dest)[0] = (src)[0])\n"
"\n"
"/* For standard headers of a GNU system: */\n"
"#ifndef __GNUC_VA_LIST\n"
"#define __GNUC_VA_LIST 1\n"
"#endif\n"
"typedef va_list __gnuc_va_list;\n"
"#endif /* #ifndef __STDARG_H */\n";

@ -0,0 +1,19 @@
/* This file is a part of MIR project.
Copyright (C) 2020 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
/* See C11 7.19 */
static char stddef_str[]
= "#ifndef __STDDEF_H\n"
"#define __STDDEF_H\n"
"\n"
"typedef long ptrdiff_t;\n"
"typedef unsigned long size_t;\n"
"typedef long double max_align_t;\n"
"typedef unsigned int wchar_t;\n"
"\n"
"#define NULL ((void *) 0)\n"
"\n"
"#define offsetof(type, member_designator) ((size_t) & ((type *) 0)->member_designator)\n"
"\n"
"#endif /* #ifndef __STDDEF_H */\n";

@ -0,0 +1,130 @@
/* This file is a part of MIR project.
Copyright (C) 2020 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
/* See C11 7.20 */
static char stdint_str[]
= "#ifndef _STDINT_H\n"
"#define _STDINT_H 1\n"
"\n"
"#ifndef __int8_t_defined\n"
"#define __int8_t_defined\n"
"typedef signed char int8_t;\n"
"#endif\n"
"typedef short int int16_t;\n"
"typedef int int32_t;\n"
"typedef long int int64_t;\n"
"\n"
"typedef unsigned char uint8_t;\n"
"typedef unsigned short int uint16_t;\n"
"typedef unsigned int uint32_t;\n"
"typedef unsigned long int uint64_t;\n"
"\n"
"typedef signed char int_least8_t;\n"
"typedef short int int_least16_t;\n"
"typedef int int_least32_t;\n"
"typedef long int int_least64_t;\n"
"\n"
"typedef unsigned char uint_least8_t;\n"
"typedef unsigned short int uint_least16_t;\n"
"typedef unsigned int uint_least32_t;\n"
"typedef unsigned long int uint_least64_t;\n"
"\n"
"typedef signed char int_fast8_t;\n"
"typedef long int int_fast16_t;\n"
"typedef long int int_fast32_t;\n"
"typedef long int int_fast64_t;\n"
"\n"
"typedef unsigned char uint_fast8_t;\n"
"typedef unsigned long int uint_fast16_t;\n"
"typedef unsigned long int uint_fast32_t;\n"
"typedef unsigned long int uint_fast64_t;\n"
"\n"
"#define __intptr_t_defined\n"
"typedef long int intptr_t;\n"
"typedef unsigned long int uintptr_t;\n"
"\n"
"typedef long int intmax_t;\n"
"typedef unsigned long int uintmax_t;\n"
"\n"
"#define __INT64_C(c) c##L\n"
"#define __UINT64_C(c) c##UL\n"
"\n"
"#define INT8_MIN (-128)\n"
"#define INT16_MIN (-32768)\n"
"#define INT32_MIN (-2147483648)\n"
"#define INT64_MIN (-9223372036854775808l)\n"
"\n"
"#define INT8_MAX (127)\n"
"#define INT16_MAX (32767)\n"
"#define INT32_MAX (2147483647)\n"
"#define INT64_MAX (9223372036854775807l)\n"
"\n"
"#define UINT8_MAX (255)\n"
"#define UINT16_MAX (65535)\n"
"#define UINT32_MAX (4294967295u)\n"
"#define UINT64_MAX (18446744073709551615ul)\n"
"\n"
"#define INT_LEAST8_MIN (-128)\n"
"#define INT_LEAST16_MIN (-32768)\n"
"#define INT_LEAST32_MIN (-2147483648)\n"
"#define INT_LEAST64_MIN (-9223372036854775808L)\n"
"\n"
"#define INT_LEAST8_MAX (127)\n"
"#define INT_LEAST16_MAX (32767)\n"
"#define INT_LEAST32_MAX (2147483647)\n"
"#define INT_LEAST64_MAX (9223372036854775807L)\n"
"\n"
"#define UINT_LEAST8_MAX (255)\n"
"#define UINT_LEAST16_MAX (65535)\n"
"#define UINT_LEAST32_MAX (4294967295U)\n"
"#define UINT_LEAST64_MAX (18446744073709551615UL)\n"
"\n"
"#define INT_FAST8_MIN (-128)\n"
"#define INT_FAST16_MIN (-9223372036854775808L)\n"
"#define INT_FAST32_MIN (-9223372036854775808L)\n"
"#define INT_FAST64_MIN (-9223372036854775808L)\n"
"\n"
"#define INT_FAST8_MAX (127)\n"
"#define INT_FAST16_MAX (9223372036854775807L)\n"
"#define INT_FAST32_MAX (9223372036854775807L)\n"
"#define INT_FAST64_MAX (9223372036854775807L)\n"
"\n"
"#define UINT_FAST8_MAX (255)\n"
"#define UINT_FAST16_MAX (18446744073709551615UL)\n"
"#define UINT_FAST32_MAX (18446744073709551615UL)\n"
"#define UINT_FAST64_MAX (18446744073709551615UL)\n"
"\n"
"#define INTPTR_MIN (-9223372036854775808L)\n"
"#define INTPTR_MAX (9223372036854775807L)\n"
"#define UINTPTR_MAX (18446744073709551615UL)\n"
"\n"
"#define INTMAX_MIN (-9223372036854775808L)\n"
"#define INTMAX_MAX (9223372036854775807L)\n"
"#define UINTMAX_MAX (18446744073709551615UL)\n"
"\n"
"#define PTRDIFF_MIN (-9223372036854775808L)\n"
"#define PTRDIFF_MAX (9223372036854775807L)\n"
"\n"
"#define SIZE_MAX (18446744073709551615UL)\n"
"\n"
"/* For signed wchar_t and wint_t: */\n"
"#define WCHAR_MIN INT32_MIN\n"
"#define WCHAR_MAX INT32_MAX\n"
"#define WINT_MIN WCHAR_MIN\n"
"#define WINT_MAX WCHAR_MAX\n"
"\n"
"#define INT8_C(value) value\n"
"#define INT16_C(value) value\n"
"#define INT32_C(value) value\n"
"#define INT64_C(value) value##L\n"
"\n"
"#define UINT8_C(value) value\n"
"#define UINT16_C(value) value\n"
"#define UINT32_C(value) value##U\n"
"#define UINT64_C(value) value##UL\n"
"\n"
"#define INTMAX_C(value) value##L\n"
"#define UINTMAX_C(value) value##UL\n"
"\n"
"#endif /* #ifndef _STDINT_H */\n";

@ -136,8 +136,8 @@ DEF_VARR (pos_t);
struct c2m_ctx {
MIR_context_t ctx;
jmp_buf env;
struct c2mir_options *options;
jmp_buf env; /* put it first as it might need 16-byte malloc allignment */
VARR (char_ptr_t) * headers;
VARR (char_ptr_t) * system_headers;
const char **header_dirs, **system_header_dirs;
@ -257,9 +257,6 @@ enum basic_type {
TP_LDOUBLE,
};
#define ENUM_BASIC_INT_TYPE TP_INT
#define ENUM_MIR_INT mir_int
struct type_qual {
unsigned int const_p : 1, restrict_p : 1, volatile_p : 1, atomic_p : 1; /* Type qualifiers */
};
@ -292,28 +289,24 @@ enum type_mode {
};
struct type {
struct type_qual type_qual;
node_t pos_node; /* set up and used only for checking type correctness */
struct type *arr_type; /* NULL or array type before its adjustment */
struct type_qual type_qual;
enum type_mode mode;
char unnamed_anon_struct_union_member_type_p;
int align; /* type align, undefined if < 0 */
/* Raw type size (w/o alignment type itself requirement but with
element alignment requirements), undefined if mir_size_max. */
mir_size_t raw_size;
int align; /* type align, undefined if < 0 */
enum type_mode mode;
char unnamed_anon_struct_union_member_type_p;
union {
enum basic_type basic_type;
node_t tag_type; /* struct/union/enum */
enum basic_type basic_type; /* also integer type */
node_t tag_type; /* struct/union/enum */
struct type *ptr_type;
struct arr_type *arr_type;
struct func_type *func_type;
} u;
};
static const struct type ENUM_INT_TYPE = {.raw_size = MIR_SIZE_MAX,
.align = -1,
.mode = TM_BASIC,
.u = {.basic_type = ENUM_BASIC_INT_TYPE}};
/*!*/ static struct type VOID_TYPE
= {.raw_size = MIR_SIZE_MAX, .align = -1, .mode = TM_BASIC, .u = {.basic_type = TP_VOID}};
@ -325,6 +318,10 @@ static mir_size_t raw_type_size (c2m_ctx_t c2m_ctx, struct type *type) {
return type->raw_size;
}
typedef struct {
const char *name, *content;
} string_include_t;
#if defined(__x86_64__) || defined(_M_AMD64)
#include "x86_64/cx86_64-code.c"
#elif defined(__aarch64__)
@ -982,6 +979,9 @@ static int get_line (c2m_ctx_t c2m_ctx) { /* translation phase 1 and 2 */
VARR_TRUNC (char, cs->ln, 0);
for (c = ln_get (c2m_ctx); c != EOF && c != '\n'; c = ln_get (c2m_ctx))
VARR_PUSH (char, cs->ln, c);
#ifdef _WIN32
if (VARR_LENGTH (char, cs->ln) != 0 && VARR_LAST (char, cs->ln) == '\r') VARR_POP (char, cs->ln);
#endif
eof_p = c == EOF;
if (eof_p) {
if (VARR_LENGTH (char, cs->ln) == 0) return FALSE;
@ -1416,7 +1416,7 @@ static token_t get_next_pptoken_1 (c2m_ctx_t c2m_ctx, int header_p) {
}
cs = VARR_LAST (stream_t, streams);
if (cs->f == NULL && cs->fname != NULL && !string_stream_p (cs)) {
if ((cs->f = fopen (cs->fname, "r")) == NULL) {
if ((cs->f = fopen (cs->fname, "rb")) == NULL) {
if (c2m_options->message_file != NULL)
fprintf (c2m_options->message_file, "cannot reopen file %s -- good bye\n", cs->fname);
longjmp (c2m_ctx->env, 1); // ???
@ -1797,6 +1797,7 @@ typedef struct macro_call {
DEF_VARR (macro_call_t);
struct pre_ctx {
VARR (char_ptr_t) * once_include_files;
VARR (token_t) * temp_tokens;
HTAB (macro_t) * macro_tab;
VARR (macro_t) * macros;
@ -1814,6 +1815,7 @@ struct pre_ctx {
void (*pre_out_token_func) (c2m_ctx_t c2m_ctx, token_t);
};
#define once_include_files pre_ctx->once_include_files
#define temp_tokens pre_ctx->temp_tokens
#define macro_tab pre_ctx->macro_tab
#define macros pre_ctx->macros
@ -1945,7 +1947,8 @@ static ifstate_t new_ifstate (int skip_p, int true_p, int else_p, pos_t if_pos)
static void pop_ifstate (c2m_ctx_t c2m_ctx) {
pre_ctx_t pre_ctx = c2m_ctx->pre_ctx;
free (VARR_POP (ifstate_t, ifs));
ifstate_t ifstate = VARR_POP (ifstate_t, ifs);
free (ifstate);
}
static void pre_init (c2m_ctx_t c2m_ctx) {
@ -1956,7 +1959,7 @@ static void pre_init (c2m_ctx_t c2m_ctx) {
c2m_ctx->pre_ctx = pre_ctx = c2mir_calloc (c2m_ctx, sizeof (struct pre_ctx));
no_out_p = skip_if_part_p = FALSE;
t = time (&time_loc);
#ifdef _MSC_VER
#if defined(_WIN32)
tm = localtime (&t);
#else
tm = localtime_r (&t, &tm_loc);
@ -1972,6 +1975,7 @@ static void pre_init (c2m_ctx_t c2m_ctx) {
date_str[strlen (date_str) - 1] = '\0';
strcpy (time_str, time_str_repr + 1);
time_str[strlen (time_str) - 1] = '\0';
VARR_CREATE (char_ptr_t, once_include_files, 64);
VARR_CREATE (token_t, temp_tokens, 128);
VARR_CREATE (token_t, output_buffer, 2048);
init_macros (c2m_ctx);
@ -1983,6 +1987,7 @@ static void pre_finish (c2m_ctx_t c2m_ctx) {
pre_ctx_t pre_ctx;
if (c2m_ctx == NULL || (pre_ctx = c2m_ctx->pre_ctx) == NULL) return;
if (once_include_files != NULL) VARR_DESTROY (char_ptr_t, once_include_files);
if (temp_tokens != NULL) VARR_DESTROY (token_t, temp_tokens);
if (output_buffer != NULL) VARR_DESTROY (token_t, output_buffer);
finish_macros (c2m_ctx);
@ -1998,17 +2003,23 @@ static void pre_finish (c2m_ctx_t c2m_ctx) {
free (c2m_ctx->pre_ctx);
}
static void add_include_stream (c2m_ctx_t c2m_ctx, const char *fname, pos_t err_pos) {
static void add_include_stream (c2m_ctx_t c2m_ctx, const char *fname, const char *content,
pos_t err_pos) {
pre_ctx_t pre_ctx = c2m_ctx->pre_ctx;
FILE *f;
for (int i = 0; i < VARR_LENGTH (char_ptr_t, once_include_files); i++)
if (strcmp (fname, VARR_GET (char_ptr_t, once_include_files, i)) == 0) return;
assert (fname != NULL);
if ((f = fopen (fname, "r")) == NULL) {
if (content == NULL && (f = fopen (fname, "rb")) == NULL) {
if (c2m_options->message_file != NULL)
error (c2m_ctx, err_pos, "error in opening file %s", fname);
longjmp (c2m_ctx->env, 1); // ???
}
add_stream (c2m_ctx, f, fname, NULL);
if (content == NULL)
add_stream (c2m_ctx, f, fname, NULL);
else
add_string_stream (c2m_ctx, fname, content);
cs->ifs_length_at_stream_start = VARR_LENGTH (ifstate_t, ifs);
}
@ -2205,7 +2216,7 @@ static int file_found_p (const char *name) {
static const char *get_full_name (c2m_ctx_t c2m_ctx, const char *base, const char *name,
int dir_base_p) {
const char *str, *last;
const char *str, *last, *last2, *slash = "/", *slash2 = NULL;
size_t len;
VARR_TRUNC (char, temp_string, 0);
@ -2213,24 +2224,34 @@ static const char *get_full_name (c2m_ctx_t c2m_ctx, const char *base, const cha
assert (name != NULL && name[0] != '\0');
return name;
}
#ifdef _WIN32
slash2 = "\\";
#endif
if (dir_base_p) {
len = strlen (base);
assert (len > 0);
add_to_temp_string (c2m_ctx, base);
if (base[len - 1] != '/') add_to_temp_string (c2m_ctx, "/");
} else if ((last = strrchr (base, '/')) == NULL) {
add_to_temp_string (c2m_ctx, "./");
if (base[len - 1] != slash[0]) add_to_temp_string (c2m_ctx, slash);
} else {
for (str = base; str <= last; str++) VARR_PUSH (char, temp_string, *str);
VARR_PUSH (char, temp_string, '\0');
last = strrchr (base, slash[0]);
last2 = slash2 != NULL ? strrchr (base, slash2[0]) : NULL;
if (last2 != NULL && (last == NULL || last2 > last)) last = last2;
if (last != NULL) {
for (str = base; str <= last; str++) VARR_PUSH (char, temp_string, *str);
VARR_PUSH (char, temp_string, '\0');
} else {
add_to_temp_string (c2m_ctx, ".");
add_to_temp_string (c2m_ctx, slash);
}
}
add_to_temp_string (c2m_ctx, name);
return VARR_ADDR (char, temp_string);
}
static const char *get_include_fname (c2m_ctx_t c2m_ctx, token_t t) {
static const char *get_include_fname (c2m_ctx_t c2m_ctx, token_t t, const char **content) {
const char *fullname, *name;
*content = NULL;
assert (t->code == T_STR || t->code == T_HEADER);
if ((name = t->node->u.s.s)[0] != '/') {
if (t->repr[0] == '"') {
@ -2244,6 +2265,11 @@ static const char *get_include_fname (c2m_ctx_t c2m_ctx, token_t t) {
if (file_found_p (fullname)) return uniq_cstr (c2m_ctx, fullname).s;
}
}
for (size_t i = 0; i < sizeof (standard_includes) / sizeof (string_include_t); i++)
if (standard_includes[i].name != NULL && strcmp (name, standard_includes[i].name) == 0) {
*content = standard_includes[i].content;
return name;
}
for (size_t i = 0; system_header_dirs[i] != NULL; i++) {
fullname = get_full_name (c2m_ctx, system_header_dirs[i], name, TRUE);
if (file_found_p (fullname)) return uniq_cstr (c2m_ctx, fullname).s;
@ -2290,11 +2316,19 @@ static pos_t check_line_directive_args (c2m_ctx_t c2m_ctx, VARR (token_t) * buff
}
static void check_pragma (c2m_ctx_t c2m_ctx, token_t t, VARR (token_t) * tokens) {
pre_ctx_t pre_ctx = c2m_ctx->pre_ctx;
token_t *tokens_arr = VARR_ADDR (token_t, tokens);
size_t i, tokens_len = VARR_LENGTH (token_t, tokens);
i = 0;
if (i < tokens_len && tokens_arr[i]->code == ' ') i++;
#ifdef _WIN32
if (i + 1 == tokens_len && tokens_arr[i]->code == T_ID
&& strcmp (tokens_arr[i]->repr, "once") == 0) {
VARR_PUSH (char_ptr_t, once_include_files, cs->fname);
return;
}
#endif
if (i >= tokens_len || tokens_arr[i]->code != T_ID || strcmp (tokens_arr[i]->repr, "STDC") != 0) {
warning (c2m_ctx, t->pos, "unknown pragma");
return;
@ -2727,9 +2761,11 @@ static void processing (c2m_ctx_t c2m_ctx, int ignore_directive_p);
static struct val eval_expr (c2m_ctx_t c2m_ctx, VARR (token_t) * buffer, token_t if_token);
static const char *get_header_name (c2m_ctx_t c2m_ctx, VARR (token_t) * buffer, pos_t err_pos) {
static const char *get_header_name (c2m_ctx_t c2m_ctx, VARR (token_t) * buffer, pos_t err_pos,
const char **content) {
int i;
*content = NULL;
transform_to_header (c2m_ctx, buffer);
i = 0;
if (VARR_LENGTH (token_t, buffer) != 0 && VARR_GET (token_t, buffer, 0)->code == ' ') i++;
@ -2739,7 +2775,7 @@ static const char *get_header_name (c2m_ctx_t c2m_ctx, VARR (token_t) * buffer,
error (c2m_ctx, err_pos, "wrong #include");
return NULL;
}
return get_include_fname (c2m_ctx, VARR_GET (token_t, buffer, i));
return get_include_fname (c2m_ctx, VARR_GET (token_t, buffer, i), content);
}
static void process_directive (c2m_ctx_t c2m_ctx) {
@ -2842,11 +2878,13 @@ static void process_directive (c2m_ctx_t c2m_ctx) {
} else if (strcmp (t->repr, "define") == 0) {
define (c2m_ctx);
} else if (strcmp (t->repr, "include") == 0) {
const char *content;
t = get_next_include_pptoken (c2m_ctx);
if (t->code == ' ') t = get_next_include_pptoken (c2m_ctx);
t1 = get_next_pptoken (c2m_ctx);
if ((t->code == T_STR || t->code == T_HEADER) && t1->code == '\n')
name = get_include_fname (c2m_ctx, t);
name = get_include_fname (c2m_ctx, t, &content);
else {
VARR_PUSH (token_t, temp_buffer, t);
skip_nl (c2m_ctx, t1, temp_buffer);
@ -2857,7 +2895,7 @@ static void process_directive (c2m_ctx_t c2m_ctx) {
processing (c2m_ctx, TRUE);
no_out_p = FALSE;
move_tokens (temp_buffer, output_buffer);
if ((name = get_header_name (c2m_ctx, temp_buffer, t->pos)) == NULL) {
if ((name = get_header_name (c2m_ctx, temp_buffer, t->pos, &content)) == NULL) {
error (c2m_ctx, t->pos, "wrong #include");
goto ret;
}
@ -2866,7 +2904,7 @@ static void process_directive (c2m_ctx_t c2m_ctx) {
error (c2m_ctx, t->pos, "more %d include levels", VARR_LENGTH (stream_t, streams) - 1);
goto ret;
}
add_include_stream (c2m_ctx, name, t->pos);
add_include_stream (c2m_ctx, name, content, t->pos);
} else if (strcmp (t->repr, "line") == 0) {
skip_nl (c2m_ctx, NULL, temp_buffer);
unget_next_pptoken (c2m_ctx, new_token (c2m_ctx, t->pos, "", T_EOP, N_IGNORE));
@ -3388,8 +3426,8 @@ static void processing (c2m_ctx_t c2m_ctx, int ignore_directive_p) {
} else if (strcmp (t->repr, "__FILE__") == 0) {
stringify (t->pos.fname, temp_string);
VARR_PUSH (char, temp_string, '\0');
t = new_node_token (c2m_ctx, t->pos, VARR_ADDR (char, temp_string),
T_STR, new_str_node (c2m_ctx, N_STR, empty_str, t->pos));
t = new_node_token (c2m_ctx, t->pos, VARR_ADDR (char, temp_string), T_STR,
new_str_node (c2m_ctx, N_STR, empty_str, t->pos));
set_string_val (c2m_ctx, t, temp_string);
out_token (c2m_ctx, t);
} else if (strcmp (t->repr, "__LINE__") == 0) {
@ -3409,7 +3447,7 @@ static void processing (c2m_ctx_t c2m_ctx, int ignore_directive_p) {
} else if (strcmp (t->repr, "__has_include") == 0) {
int res;
VARR (token_t) * arg;
const char *name;
const char *name, *content;
FILE *f;
if ((mc = try_param_macro_call (c2m_ctx, m, t)) != NULL) {
@ -3418,18 +3456,16 @@ static void processing (c2m_ctx_t c2m_ctx, int ignore_directive_p) {
res = 0;
} else {
arg = VARR_LAST (token_arr_t, mc->args);
if ((name = get_header_name (c2m_ctx, arg, t->pos)) != NULL) {
res = ((f = fopen (name, "r")) != NULL && !fclose (f)) ? 1 : 0;
if ((name = get_header_name (c2m_ctx, arg, t->pos, &content)) != NULL) {
res = content != NULL || ((f = fopen (name, "r")) != NULL && !fclose (f)) ? 1 : 0;
} else {
error (c2m_ctx, t->pos, "wrong arg of predefined __has_include");
res = 0;
}
}
m->ignore_p = TRUE;
unget_next_pptoken (c2m_ctx,
new_node_token (c2m_ctx, t->pos,
res ? "1" : "0", T_NUMBER,
new_i_node (c2m_ctx, res, t->pos)));
unget_next_pptoken (c2m_ctx, new_node_token (c2m_ctx, t->pos, res ? "1" : "0", T_NUMBER,
new_i_node (c2m_ctx, res, t->pos)));
}
} else {
assert (FALSE);
@ -3536,6 +3572,7 @@ static void pre (c2m_ctx_t c2m_ctx, const char *start_source_name) {
actual_pre_pos.ln_pos = 0;
pre_out_token_func = common_pre_out;
pptokens_num = 0;
VARR_TRUNC (char_ptr_t, once_include_files, 0);
if (!c2m_options->no_prepro_p) {
processing (c2m_ctx, FALSE);
} else {
@ -5060,19 +5097,12 @@ static void parse_init (c2m_ctx_t c2m_ctx) {
tpname_init (c2m_ctx);
}
#ifndef SOURCEDIR
#define SOURCEDIR "./"
#endif
#ifndef INSTALLDIR
#define INSTALLDIR "/usr/bin/"
#endif
static void add_standard_includes (c2m_ctx_t c2m_ctx) {
const char *str;
const char *str, *name;
for (int i = 0; i < sizeof (standard_includes) / sizeof (char *); i++) {
str = standard_includes[i];
for (int i = 0; i < sizeof (standard_includes) / sizeof (string_include_t); i++) {
if ((name = standard_includes[i].name) != NULL) continue;
str = standard_includes[i].content;
add_string_stream (c2m_ctx, "<environment>", str);
}
}
@ -5124,8 +5154,9 @@ static void parse_finish (c2m_ctx_t c2m_ctx) {
6. N_MODULE, N_BLOCK, N_FOR, N_FUNC have attribute "struct node_scope"
7. declaration_specs or spec_qual_list N_LISTs have attribute "struct decl_spec",
but as a part of N_COMPOUND_LITERAL have attribute "struct decl"
8. N_ENUM_CONST has attribute "struct enum_value"
9. N_CASE and N_DEFAULT have attribute "struct case_attr"
8. N_ENUM has attribute "struct enum_type"
9. N_ENUM_CONST has attribute "struct enum_value"
10. N_CASE and N_DEFAULT have attribute "struct case_attr"
*/
@ -5292,6 +5323,8 @@ static int integer_type_p (const struct type *type) {
return standard_integer_type_p (type) || type->mode == TM_ENUM;
}
static enum basic_type get_enum_basic_type (const struct type *type);
static int signed_integer_type_p (const struct type *type) {
if (standard_integer_type_p (type)) {
enum basic_type tp = type->u.basic_type;
@ -5299,7 +5332,10 @@ static int signed_integer_type_p (const struct type *type) {
return ((tp == TP_CHAR && char_is_signed_p ()) || tp == TP_SCHAR || tp == TP_SHORT
|| tp == TP_INT || tp == TP_LONG || tp == TP_LLONG);
}
if (type->mode == TM_ENUM) return signed_integer_type_p (&ENUM_INT_TYPE);
if (type->mode == TM_ENUM) {
enum basic_type basic_type = get_enum_basic_type (type);
return (basic_type == TP_INT || basic_type == TP_LONG || basic_type == TP_LLONG);
}
return FALSE;
}
@ -5325,9 +5361,12 @@ static struct type get_ptr_int_type (int signed_p) {
if (sizeof (mir_int) == sizeof (mir_size_t)) {
res.u.basic_type = signed_p ? TP_INT : TP_UINT;
return res;
} else if (sizeof (mir_long) == sizeof (mir_size_t)) {
res.u.basic_type = signed_p ? TP_LONG : TP_ULONG;
return res;
}
assert (sizeof (mir_long) == sizeof (mir_size_t));
res.u.basic_type = signed_p ? TP_LONG : TP_ULONG;
assert (sizeof (mir_llong) == sizeof (mir_size_t));
res.u.basic_type = signed_p ? TP_LLONG : TP_ULLONG;
return res;
}
@ -5347,7 +5386,7 @@ static struct type integer_promotion (const struct type *type) {
|| (type->u.basic_type == TP_USHORT && MIR_USHORT_MAX > MIR_INT_MAX)))
res.u.basic_type = TP_UINT;
else if (type->mode == TM_ENUM)
res.u.basic_type = ENUM_BASIC_INT_TYPE;
res.u.basic_type = get_enum_basic_type (type);
else if (type->mode == TM_BASIC && type->u.basic_type == TP_UINT)
res.u.basic_type = TP_UINT;
else
@ -5421,8 +5460,15 @@ struct decl_spec {
struct type *type;
};
struct enum_type {
enum basic_type enum_basic_type;
};
struct enum_value {
mir_int val;
union {
mir_llong i_val;
mir_ullong u_val;
} u;
};
struct node_scope {
@ -5450,6 +5496,11 @@ struct decl {
c2m_ctx_t c2m_ctx;
};
static enum basic_type get_enum_basic_type (const struct type *type) {
assert (type->mode == TM_ENUM);
return ((struct enum_type *) type->u.tag_type->attr)->enum_basic_type;
}
static struct decl_spec *get_param_decl_spec (node_t param) {
node_t MIR_UNUSED declarator;
@ -5503,9 +5554,9 @@ static int compatible_types_p (struct type *type1, struct type *type2, int ignor
if (type1->mode != type2->mode) {
if (!ignore_quals_p && !type_qual_eq_p (&type1->type_qual, &type2->type_qual)) return FALSE;
if (type1->mode == TM_ENUM && type2->mode == TM_BASIC)
return type2->u.basic_type == ENUM_BASIC_INT_TYPE;
return type2->u.basic_type == get_enum_basic_type (type1);
if (type2->mode == TM_ENUM && type1->mode == TM_BASIC)
return type1->u.basic_type == ENUM_BASIC_INT_TYPE;
return type1->u.basic_type == get_enum_basic_type (type2);
return FALSE;
}
if (type1->mode == TM_BASIC) {
@ -5623,7 +5674,7 @@ static void aux_set_type_align (c2m_ctx_t c2m_ctx, struct type *type) {
} else if (type->mode == TM_PTR) {
align = sizeof (mir_size_t);
} else if (type->mode == TM_ENUM) {
align = basic_type_align (ENUM_BASIC_INT_TYPE);
align = basic_type_align (get_enum_basic_type (type));
} else if (type->mode == TM_FUNC) {
align = sizeof (mir_size_t);
} else if (type->mode == TM_ARR) {
@ -5657,7 +5708,7 @@ static void aux_set_type_align (c2m_ctx_t c2m_ctx, struct type *type) {
static mir_size_t type_size (c2m_ctx_t c2m_ctx, struct type *type) {
mir_size_t size = raw_type_size (c2m_ctx, type);
return round_size (size, type->align);
return type->align == 0 ? size : round_size (size, type->align);
}
static mir_size_t var_align (c2m_ctx_t c2m_ctx, struct type *type) {
@ -5743,7 +5794,7 @@ static void set_type_layout (c2m_ctx_t c2m_ctx, struct type *type) {
} else if (type->mode == TM_PTR) {
overall_size = sizeof (mir_size_t);
} else if (type->mode == TM_ENUM) {
overall_size = basic_type_size (ENUM_BASIC_INT_TYPE);
overall_size = basic_type_size (get_enum_basic_type (type));
} else if (type->mode == TM_FUNC) {
overall_size = sizeof (mir_size_t);
} else if (type->mode == TM_ARR) {
@ -5814,7 +5865,7 @@ static void set_type_layout (c2m_ctx_t c2m_ctx, struct type *type) {
static int int_bit_size (struct type *type) {
assert (type->mode == TM_BASIC || type->mode == TM_ENUM);
return (basic_type_size (type->mode == TM_ENUM ? ENUM_BASIC_INT_TYPE : type->u.basic_type)
return (basic_type_size (type->mode == TM_ENUM ? get_enum_basic_type (type) : type->u.basic_type)
* MIR_CHAR_BIT);
}
@ -5913,24 +5964,23 @@ static void cast_value (struct expr *to_e, struct expr *from_e, struct type *to)
default: assert (FALSE); \
}
struct type temp, temp2;
if (to->mode == TM_ENUM) {
temp.mode = TM_BASIC;
temp.u.basic_type = get_enum_basic_type (to);
to = &temp;
}
if (from->mode == TM_ENUM) {
temp2.mode = TM_BASIC;
temp2.u.basic_type = get_enum_basic_type (from);
from = &temp2;
}
if (to->mode == from->mode && (from->mode == TM_PTR || from->mode == TM_ENUM)) {
to_e->u = from_e->u;
} else if (from->mode == TM_PTR) {
if (to->mode == TM_ENUM) {
to_e->u.i_val = (ENUM_MIR_INT) from_e->u.u_val;
} else {
BASIC_FROM_CONV (u_val);
}
} else if (from->mode == TM_ENUM) {
if (to->mode == TM_PTR) {
to_e->u.u_val = (mir_size_t) from_e->u.i_val;
} else {
BASIC_FROM_CONV (i_val);
}
BASIC_FROM_CONV (u_val);
} else if (to->mode == TM_PTR) {
BASIC_TO_CONV (mir_size_t, u_val);
} else if (to->mode == TM_ENUM) {
BASIC_TO_CONV (ENUM_MIR_INT, i_val);
} else {
switch (from->u.basic_type) {
case TP_BOOL:
@ -6088,7 +6138,7 @@ static void def_symbol (c2m_ctx_t c2m_ctx, enum symbol_mode mode, node_t id, nod
if (linkage == N_IGNORE) {
if (!decl_spec.typedef_p || !tab_decl_spec.typedef_p
|| !type_eq_p (decl_spec.type, tab_decl_spec.type))
#ifdef __APPLE__
#if defined(__APPLE__)
/* a hack to use our definition instead of macosx for non-GNU compiler */
if (strcmp (id->u.s.s, "__darwin_va_list") != 0)
#endif
@ -6341,8 +6391,14 @@ static struct decl_spec check_decl_spec (c2m_ctx_t c2m_ctx, node_t r, node_t dec
if (incomplete_type_p (c2m_ctx, type))
error (c2m_ctx, POS (n), "enum storage size is unknown");
} else {
mir_int curr_val = 0;
mir_llong curr_val = -1, min_val = 0;
mir_ullong max_val = 0;
enum basic_type basic_type;
struct enum_type *enum_type;
int neg_p = FALSE;
n->attr = enum_type = reg_malloc (c2m_ctx, sizeof (struct enum_type));
enum_type->enum_basic_type = TP_INT;
for (node_t en = NL_HEAD (enum_list->u.ops); en != NULL; en = NL_NEXT (en)) { // ??? id
node_t id, const_expr;
symbol_t sym;
@ -6357,22 +6413,49 @@ static struct decl_spec check_decl_spec (c2m_ctx_t c2m_ctx, node_t r, node_t dec
} else {
symbol_insert (c2m_ctx, S_REGULAR, id, curr_scope, en, n);
}
curr_val++;
if (curr_val == 0) neg_p = FALSE;
if (const_expr->code != N_IGNORE) {
struct expr *cexpr = const_expr->attr;
if (!cexpr->const_p)
if (!cexpr->const_p) {
error (c2m_ctx, POS (const_expr), "non-constant value in enum const expression");
else if (!integer_type_p (cexpr->type))
continue;
} else if (!integer_type_p (cexpr->type)) {
error (c2m_ctx, POS (const_expr), "enum const expression is not of an integer type");
else if ((signed_integer_type_p (cexpr->type) && cexpr->u.i_val > MIR_INT_MAX)
|| (!signed_integer_type_p (cexpr->type) && cexpr->u.u_val > MIR_INT_MAX))
error (c2m_ctx, POS (const_expr), "enum const expression is not represented by int");
else
curr_val = cexpr->u.i_val;
continue;
}
curr_val = cexpr->u.i_val;
neg_p = signed_integer_type_p (cexpr->type) && cexpr->u.i_val < 0;
}
en->attr = enum_value = reg_malloc (c2m_ctx, sizeof (struct enum_value));
enum_value->val = curr_val;
curr_val++;
if (!neg_p) {
if (max_val < (mir_ullong) curr_val) max_val = (mir_ullong) curr_val;
if (min_val < 0 && (mir_ullong) curr_val >= MIR_LLONG_MAX)
error (c2m_ctx, POS (const_expr),
"enum const expression is not represented by an int");
enum_value->u.u_val = (mir_ullong) curr_val;
} else {
if (min_val > curr_val) {
min_val = curr_val;
if (min_val < 0 && max_val >= MIR_LLONG_MAX)
error (c2m_ctx, POS (const_expr),
"enum const expression is not represented by an int");
} else if (curr_val >= 0 && max_val < curr_val) {
max_val = curr_val;
}
enum_value->u.i_val = curr_val;
}
enum_type->enum_basic_type
= (max_val <= MIR_INT_MAX && MIR_INT_MIN <= min_val
? TP_INT
: max_val <= MIR_UINT_MAX && 0 <= min_val
? TP_UINT
: max_val <= MIR_LONG_MAX && MIR_LONG_MIN <= min_val
? TP_LONG
: max_val <= MIR_ULONG_MAX && 0 <= min_val
? TP_ULONG
: min_val < 0 || max_val <= MIR_LLONG_MAX ? TP_LLONG : TP_ULLONG);
}
}
break;
@ -7768,7 +7851,8 @@ static void add__func__def (c2m_ctx_t c2m_ctx, node_t func_block, str_t func_nam
NL_APPEND (list->u.ops, new_pos_node3 (c2m_ctx, N_ARR, pos, new_pos_node (c2m_ctx, N_IGNORE, pos),
new_pos_node (c2m_ctx, N_LIST, pos),
new_pos_node (c2m_ctx, N_IGNORE, pos)));
declarator = new_pos_node2 (c2m_ctx, N_DECL, pos, new_str_node (c2m_ctx, N_ID, str.str, pos), list);
declarator
= new_pos_node2 (c2m_ctx, N_DECL, pos, new_str_node (c2m_ctx, N_ID, str.str, pos), list);
decl = new_pos_node3 (c2m_ctx, N_SPEC_DECL, pos, decl_specs, declarator,
new_str_node (c2m_ctx, N_STR, func_name, pos));
NL_PREPEND (NL_EL (func_block->u.ops, 1)->u.ops, decl);
@ -7958,7 +8042,7 @@ static void check (c2m_ctx_t c2m_ctx, node_t r, node_t context) {
e->type->pos_node = r;
e->type->u.tag_type = aux_node;
e->const_p = TRUE;
e->u.i_val = ((struct enum_value *) op1->attr)->val;
e->u.i_val = ((struct enum_value *) op1->attr)->u.i_val;
}
break;
}
@ -10207,7 +10291,6 @@ static int simple_return_by_addr_p (c2m_ctx_t c2m_ctx, struct type *ret_type) {
static void MIR_UNUSED simple_add_res_proto (c2m_ctx_t c2m_ctx, struct type *ret_type,
void *arg_info, VARR (MIR_type_t) * res_types,
VARR (MIR_var_t) * arg_vars) {
gen_ctx_t gen_ctx = c2m_ctx->gen_ctx;
MIR_var_t var;
if (void_type_p (ret_type)) return;
@ -11633,13 +11716,21 @@ static op_t gen (c2m_ctx_t c2m_ctx, node_t r, MIR_label_t true_label, MIR_label_
if (va_arg_p) {
op1 = get_new_temp (c2m_ctx, MIR_T_I64);
op2 = gen (c2m_ctx, NL_HEAD (args->u.ops), NULL, NULL, TRUE, NULL);
if (op2.mir_op.mode == MIR_OP_MEM && op2.mir_op.u.mem.type == MIR_T_UNDEF)
op2 = mem_to_address (c2m_ctx, op2, FALSE);
if (op2.mir_op.mode == MIR_OP_MEM) {
#ifndef _WIN32
if (op2.mir_op.u.mem.type == MIR_T_UNDEF)
#endif
op2 = mem_to_address (c2m_ctx, op2, FALSE);
}
if (type->mode == TM_STRUCT || type->mode == TM_UNION) {
assert (desirable_dest != NULL && desirable_dest->mir_op.mode == MIR_OP_MEM);
res = mem_to_address (c2m_ctx, *desirable_dest, TRUE);
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;
MIR_new_insn (ctx, MIR_VA_BLOCK_ARG, res.mir_op, op2.mir_op,
MIR_new_int_op (ctx, type_size (c2m_ctx, type)),
MIR_new_int_op (ctx, target_get_blk_type (c2m_ctx, type)
- MIR_T_BLK)));
res = *desirable_dest;
} else {
MIR_append_insn (ctx, curr_func,
MIR_new_insn (ctx, MIR_VA_ARG, op1.mir_op, op2.mir_op,
@ -11648,17 +11739,21 @@ static op_t gen (c2m_ctx_t c2m_ctx, node_t r, MIR_label_t true_label, MIR_label_
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 {
assert (res.mir_op.mode == MIR_OP_MEM);
res.mir_op.u.mem.base = op2.mir_op.u.reg;
if (res.mir_op.mode == MIR_OP_REG) {
res = op2;
} else {
assert (res.mir_op.mode == MIR_OP_MEM);
res.mir_op.u.mem.base = op2.mir_op.u.reg;
}
}
} else if (va_start_p) {
op1 = gen (c2m_ctx, NL_HEAD (args->u.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 (c2m_ctx, op1, FALSE);
if (op1.mir_op.mode == MIR_OP_MEM) {
#ifndef _WIN32
if (op1.mir_op.u.mem.type == MIR_T_UNDEF)
#endif
op1 = mem_to_address (c2m_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 (c2m_ctx, t);
@ -12187,7 +12282,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 (MIR_blk_type_p (args[i].type)) h = mir_hash_step (h, args[i].size);
if (MIR_all_blk_type_p (args[i].type)) h = mir_hash_step (h, args[i].size);
}
return mir_hash_finish (h);
}
@ -12205,7 +12300,7 @@ static int proto_eq (MIR_item_t pi1, MIR_item_t pi2, void *arg) {
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
|| (MIR_blk_type_p (args1[i].type) && args1[i].size != args2[i].size))
|| (MIR_all_blk_type_p (args1[i].type) && args1[i].size != args2[i].size))
return FALSE;
return TRUE;
}
@ -12356,31 +12451,32 @@ static void print_qual (FILE *f, struct type_qual type_qual) {
if (type_qual.atomic_p) fprintf (f, ", atomic");
}
static void print_basic_type (FILE *f, enum basic_type basic_type) {
switch (basic_type) {
case TP_UNDEF: fprintf (f, "undef type"); break;
case TP_VOID: fprintf (f, "void"); break;
case TP_BOOL: fprintf (f, "bool"); break;
case TP_CHAR: fprintf (f, "char"); break;
case TP_SCHAR: fprintf (f, "signed char"); break;
case TP_UCHAR: fprintf (f, "unsigned char"); break;
case TP_SHORT: fprintf (f, "short"); break;
case TP_USHORT: fprintf (f, "unsigned short"); break;
case TP_INT: fprintf (f, "int"); break;
case TP_UINT: fprintf (f, "unsigned int"); break;
case TP_LONG: fprintf (f, "long"); break;
case TP_ULONG: fprintf (f, "unsigned long"); break;
case TP_LLONG: fprintf (f, "long long"); break;
case TP_ULLONG: fprintf (f, "unsigned long long"); break;
case TP_FLOAT: fprintf (f, "float"); break;
case TP_DOUBLE: fprintf (f, "double"); break;
case TP_LDOUBLE: fprintf (f, "long double"); break;
default: assert (FALSE);
}
}
static void print_type (c2m_ctx_t c2m_ctx, FILE *f, struct type *type) {
switch (type->mode) {
case TM_UNDEF: fprintf (f, "undef type mode"); break;
case TM_BASIC:
switch (type->u.basic_type) {
case TP_UNDEF: fprintf (f, "undef type"); break;
case TP_VOID: fprintf (f, "void"); break;
case TP_BOOL: fprintf (f, "bool"); break;
case TP_CHAR: fprintf (f, "char"); break;
case TP_SCHAR: fprintf (f, "signed char"); break;
case TP_UCHAR: fprintf (f, "unsigned char"); break;
case TP_SHORT: fprintf (f, "short"); break;
case TP_USHORT: fprintf (f, "unsigned short"); break;
case TP_INT: fprintf (f, "int"); break;
case TP_UINT: fprintf (f, "unsigned int"); break;
case TP_LONG: fprintf (f, "long"); break;
case TP_ULONG: fprintf (f, "unsigned long"); break;
case TP_LLONG: fprintf (f, "long long"); break;
case TP_ULLONG: fprintf (f, "unsigned long long"); break;
case TP_FLOAT: fprintf (f, "float"); break;
case TP_DOUBLE: fprintf (f, "double"); break;
case TP_LDOUBLE: fprintf (f, "long double"); break;
default: assert (FALSE);
}
break;
case TM_BASIC: print_basic_type (f, type->u.basic_type); break;
case TM_ENUM: fprintf (f, "enum node %u", type->u.tag_type->uid); break;
case TM_PTR:
fprintf (f, "ptr (");
@ -12582,7 +12678,6 @@ static void print_node (c2m_ctx_t c2m_ctx, FILE *f, node_t n, int indent, int at
case N_SIGNED:
case N_UNSIGNED:
case N_BOOL:
case N_ENUM:
case N_CONST:
case N_RESTRICT:
case N_VOLATILE:
@ -12656,9 +12751,17 @@ static void print_node (c2m_ctx_t c2m_ctx, FILE *f, node_t n, int indent, int at
if (attr_p && n->attr != NULL) fprintf (f, ": target node %u\n", ((node_t) n->attr)->uid);
print_ops (c2m_ctx, f, n, indent, attr_p);
break;
case N_ENUM:
if (attr_p && n->attr != NULL) {
fprintf (f, ": enum_basic_type = ");
print_basic_type (f, ((struct enum_type *) n->attr)->enum_basic_type);
fprintf (f, "\n");
}
print_ops (c2m_ctx, f, n, indent, attr_p);
break;
case N_ENUM_CONST:
if (attr_p && n->attr != NULL)
fprintf (f, ": val = %lld\n", (long long) ((struct enum_value *) n->attr)->val);
if (attr_p && n->attr != NULL) // ???!!!
fprintf (f, ": val = %lld\n", (long long) ((struct enum_value *) n->attr)->u.i_val);
print_ops (c2m_ctx, f, n, indent, attr_p);
break;
default: abort ();
@ -12666,7 +12769,6 @@ static void print_node (c2m_ctx_t c2m_ctx, FILE *f, node_t n, int indent, int at
}
static void init_include_dirs (c2m_ctx_t c2m_ctx) {
const char *str;
int MIR_UNUSED added_p = FALSE;
VARR_CREATE (char_ptr_t, headers, 0);
@ -12676,19 +12778,6 @@ static void init_include_dirs (c2m_ctx_t c2m_ctx) {
VARR_PUSH (char_ptr_t, system_headers, c2m_options->include_dirs[i]);
}
VARR_PUSH (char_ptr_t, headers, NULL);
for (size_t i = 0; i < sizeof (standard_include_dirs) / sizeof (char *); i++) {
VARR_TRUNC (char, temp_string, 0);
add_to_temp_string (c2m_ctx, SOURCEDIR);
add_to_temp_string (c2m_ctx, standard_include_dirs[i]);
str = uniq_cstr (c2m_ctx, VARR_ADDR (char, temp_string)).s;
VARR_PUSH (char_ptr_t, system_headers, str);
VARR_TRUNC (char, temp_string, 0);
add_to_temp_string (c2m_ctx, INSTALLDIR);
add_to_temp_string (c2m_ctx, "../");
add_to_temp_string (c2m_ctx, standard_include_dirs[i]);
str = uniq_cstr (c2m_ctx, VARR_ADDR (char, temp_string)).s;
VARR_PUSH (char_ptr_t, system_headers, str);
}
#if defined(__APPLE__) || defined(__unix__)
VARR_PUSH (char_ptr_t, system_headers, "/usr/local/include");
#endif

@ -1,3 +1,7 @@
#ifndef C2MIR_H
#define C2MIR_H
#include "mir.h"
#define COMMAND_LINE_SOURCE_NAME "<command-line>"
@ -24,3 +28,5 @@ void c2mir_init (MIR_context_t ctx);
void c2mir_finish (MIR_context_t ctx);
int c2mir_compile (MIR_context_t ctx, struct c2mir_options *ops, int (*getc_func) (void *),
void *getc_data, const char *source_name, FILE *output_file);
#endif

@ -21,3 +21,15 @@ static const char mirc[]
"#define __signed__ signed\n"
"#define __volatile volatile\n"
"#define __volatile__ volatile\n";
#include "mirc_iso646.h"
#include "mirc_stdalign.h"
#include "mirc_stdbool.h"
#include "mirc_stdnoreturn.h"
#define TARGET_STD_INCLUDES \
{"iso646.h", iso646_str}, {"stdalign.h", stdalign_str}, {"stdbool.h", stdbool_str}, \
{"stdnoreturn.h", stdnoreturn_str}, {"float.h", float_str}, {"limits.h", limits_str}, \
{"stdarg.h", stdarg_str}, {"stdint.h", stdint_str}, { \
"stddef.h", stddef_str \
}

@ -0,0 +1,17 @@
/* See C11 7.9 */
static char iso646_str[]
= "#ifndef __ISO646_H\n"
"#define __ISO646_H\n"
"\n"
"#define and &&\n"
"#define and_eq &=\n"
"#define bitand &\n"
"#define bitor |\n"
"#define compl ~\n"
"#define not !\n"
"#define not_eq !=\n"
"#define or ||\n"
"#define or_eq |=\n"
"#define xor ^\n"
"#define xor_eq ^=\n"
"#endif /* #ifndef __ISO646_H */\n";

@ -0,0 +1,10 @@
/* See C11 7.15 */
static char stdalign_str[]
= "#ifndef __STDALIGN_H\n"
"#define __STDALIGN_H\n"
"\n"
"#define alignas _Alignas\n"
"#define alignof _Alignof\n"
"#define __alignas_is_defined 1\n"
"#define __alignof_is_defined 1\n"
"#endif /* #ifndef __STDALIGN_H */\n";

@ -0,0 +1,10 @@
/* See C11 7.18 */
static char stdbool_str[]
= "#ifndef __STDBOOL_H\n"
"#define __STDBOOL_H\n"
"\n"
"#define bool _Bool\n"
"#define true 1\n"
"#define false 0\n"
"#define __bool_true_false_are_defined 1\n"
"#endif /* #ifndef __STDBOOL_H */\n";

@ -0,0 +1,7 @@
/* See C11 7.23 */
static char stdnoreturn_str[]
= "#ifndef __STDNORETURN_H\n"
"#define __STDNORETURN_H\n"
"\n"
"#define noreturn _Noreturn\n"
"#endif /* #ifndef __STDNORETURN_H */\n";

@ -219,6 +219,10 @@ static void target_add_ret_ops (c2m_ctx_t c2m_ctx, struct type *ret_type, op_t r
}
}
static MIR_type_t target_get_blk_type (c2m_ctx_t c2m_ctx, struct type *arg_type) {
return MIR_T_BLK; /* one BLK is enough */
}
static void target_add_arg_proto (c2m_ctx_t c2m_ctx, const char *name, struct type *arg_type,
target_arg_info_t *arg_info, VARR (MIR_var_t) * arg_vars) {
MIR_var_t var;

@ -3,16 +3,20 @@
*/
#include "../mirc.h"
#include "mirc-ppc64-linux.h"
#include "mirc_ppc64_linux.h"
static const char *standard_includes[] = {mirc, ppc64_mirc};
#include "mirc_ppc64_float.h"
#include "mirc_ppc64_limits.h"
#include "mirc_ppc64_stdarg.h"
#include "mirc_ppc64_stdint.h"
#include "mirc_ppc64_stddef.h"
static const char *standard_include_dirs[] = {"include/mirc/", "include/mirc/ppc64/"};
static string_include_t standard_includes[]
= {{NULL, mirc}, {NULL, ppc64_mirc}, TARGET_STD_INCLUDES};
#define MAX_ALIGNMENT 16
#define ADJUST_VAR_ALIGNMENT(c2m_ctx, align, type) \
ppc64_adjust_var_alignment (c2m_ctx, align, type)
#define ADJUST_VAR_ALIGNMENT(c2m_ctx, align, type) ppc64_adjust_var_alignment (c2m_ctx, align, type)
static int ppc64_adjust_var_alignment (c2m_ctx_t c2m_ctx, int align, struct type *type) {
return align;

@ -0,0 +1,60 @@
/* This file is a part of MIR project.
Copyright (C) 2020 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
/* See C11 5.2.4.2.2 */
static char float_str[]
= "#ifndef __FLOAT_H\n"
"#define __FLOAT_H\n"
"\n"
"#define FLT_RADIX 2\n"
"\n"
"#define FLT_MANT_DIG 24\n"
"#define DBL_MANT_DIG 53\n"
"#define LDBL_MANT_DIG DBL_MANT_DIG\n"
"\n"
"#define FLT_DECIMAL_DIG 9\n"
"#define DBL_DECIMAL_DIG 17\n"
"#define LDBL_DECIMAL_DIG DBL_DECIMAL_DIG\n"
"#define FLT_DIG FLT_DECIMAL_DIG\n"
"#define DBL_DIG DBL_DECIMAL_DIG\n"
"#define LDBL_DIG LDBL_DECIMAL_DIG\n"
"\n"
"#define DECIMAL_DIG LDBL_DECIMAL_DIG\n"
"\n"
"#define FLT_MIN_EXP -125\n"
"#define DBL_MIN_EXP -1021\n"
"#define LDBL_MIN_EXP DBL_MIN_EXP\n"
"\n"
"#define FLT_MIN_10_EXP -37\n"
"#define DBL_MIN_10_EXP -307\n"
"#define LDBL_MIN_10_EXP DBL_MIN_10_EXP\n"
"\n"
"#define FLT_MAX_EXP 128\n"
"#define DBL_MAX_EXP 1024\n"
"#define LDBL_MAX_EXP DBL_MAX_EXP\n"
"\n"
"#define FLT_MAX_10_EXP 38\n"
"#define DBL_MAX_10_EXP 308\n"
"#define LDBL_MAX_10_EXP DBL_MAX_10_EXP\n"
"\n"
"#define FLT_MAX 0x1.fffffep+127\n"
"#define DBL_MAX 0x1.fffffffffffffp+1023\n"
"#define LDBL_MAX DBL_MAX\n"
"\n"
"#define FLT_EPSILON 0x1p-23\n"
"#define DBL_EPSILON 0x1p-52\n"
"#define LDBL_EPSILON DBL_EPSILON\n"
"\n"
"#define FLT_MIN 0x1p-126\n"
"#define DBL_MIN 0x1p-1022\n"
"#define LDBL_MIN DBL_MIN\n"
"\n"
"#define FLT_TRUE_MIN 0x1p-149\n"
"#define DBL_TRUE_MIN 0x0.0000000000001p-1022\n"
"#define LDBL_TRUE_MIN DBL_TRUE_MIN\n"
"\n"
"#define FLT_EVAL_METHOD 0\n"
"#define FLT_ROUNDS 1 /* round to the nearest */\n"
"\n"
"#endif /* #ifndef __FLOAT_H */\n";

@ -0,0 +1,38 @@
/* This file is a part of MIR project.
Copyright (C) 2020 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
/* See 5.2.4.2 */
static char limits_str[]
= "#ifndef __LIMITS_H\n"
"#define __LIMITS_H\n"
"\n"
"#define CHAR_BIT 8\n"
"\n"
"#define SCHAR_MIN (-SCHAR_MAX - 1)\n"
"#define SCHAR_MAX 127\n"
"#define UCHAR_MAX (SCHAR_MAX * 2 + 1)\n"
"\n"
"#define MB_LEN_MAX 1\n"
"\n"
"#define SHRT_MIN (-SHRT_MAX - 1)\n"
"#define SHRT_MAX 32767\n"
"#define USHRT_MAX (SHRT_MAX * 2 + 1)\n"
"\n"
"#define INT_MIN (-INT_MAX - 1)\n"
"#define INT_MAX 2147483647\n"
"#define UINT_MAX (INT_MAX * 2u + 1u)\n"
"\n"
"#define LONG_MIN (-LONG_MAX - 1l)\n"
"#define LONG_MAX 9223372036854775807l\n"
"#define ULONG_MAX (LONG_MAX * 2ul + 1ul)\n"
"\n"
"#define LLONG_MIN LONG_MIN\n"
"#define LLONG_MAX LONG_MAX\n"
"#define ULLONG_MAX ULONG_MAX\n"
"\n"
"/* unsigned char by default */\n"
"#define CHAR_MIN 0\n"
"#define CHAR_MAX UCHAR_MAX\n"
"\n"
"#endif /* #ifndef __LIMITS_H */\n";

@ -0,0 +1,21 @@
/* This file is a part of MIR project.
Copyright (C) 2020 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
static char stdarg_str[]
= "#ifndef __STDARG_H\n"
"#define __STDARG_H\n"
"\n"
"typedef void *va_list[1];\n"
"\n"
"#define va_start(ap, param) __builtin_va_start (ap)\n"
"#define va_arg(ap, type) __builtin_va_arg(ap, (type *) 0)\n"
"#define va_end(ap) 0\n"
"#define va_copy(dest, src) ((dest) = (src))\n"
"\n"
"/* For standard headers of a GNU system: */\n"
"#ifndef __GNUC_VA_LIST\n"
"#define __GNUC_VA_LIST 1\n"
"#endif\n"
"typedef va_list __gnuc_va_list;\n"
"#endif /* #ifndef __STDARG_H */\n";

@ -0,0 +1,19 @@
/* This file is a part of MIR project.
Copyright (C) 2020 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
/* See C11 7.19 */
static char stddef_str[]
= "#ifndef __STDDEF_H\n"
"#define __STDDEF_H\n"
"\n"
"typedef long ptrdiff_t;\n"
"typedef unsigned long size_t;\n"
"typedef long double max_align_t;\n"
"typedef unsigned int wchar_t;\n"
"\n"
"#define NULL ((void *) 0)\n"
"\n"
"#define offsetof(type, member_designator) ((size_t) & ((type *) 0)->member_designator)\n"
"\n"
"#endif /* #ifndef __STDDEF_H */\n";

@ -0,0 +1,130 @@
/* This file is a part of MIR project.
Copyright (C) 2020 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
/* See C11 7.20 */
static char stdint_str[]
= "#ifndef _STDINT_H\n"
"#define _STDINT_H 1\n"
"\n"
"#ifndef __int8_t_defined\n"
"#define __int8_t_defined\n"
"typedef signed char int8_t;\n"
"#endif\n"
"typedef short int int16_t;\n"
"typedef int int32_t;\n"
"typedef long int int64_t;\n"
"\n"
"typedef unsigned char uint8_t;\n"
"typedef unsigned short int uint16_t;\n"
"typedef unsigned int uint32_t;\n"
"typedef unsigned long int uint64_t;\n"
"\n"
"typedef signed char int_least8_t;\n"
"typedef short int int_least16_t;\n"
"typedef int int_least32_t;\n"
"typedef long int int_least64_t;\n"
"\n"
"typedef unsigned char uint_least8_t;\n"
"typedef unsigned short int uint_least16_t;\n"
"typedef unsigned int uint_least32_t;\n"
"typedef unsigned long int uint_least64_t;\n"
"\n"
"typedef signed char int_fast8_t;\n"
"typedef long int int_fast16_t;\n"
"typedef long int int_fast32_t;\n"
"typedef long int int_fast64_t;\n"
"\n"
"typedef unsigned char uint_fast8_t;\n"
"typedef unsigned long int uint_fast16_t;\n"
"typedef unsigned long int uint_fast32_t;\n"
"typedef unsigned long int uint_fast64_t;\n"
"\n"
"#define __intptr_t_defined\n"
"typedef long int intptr_t;\n"
"typedef unsigned long int uintptr_t;\n"
"\n"
"typedef long int intmax_t;\n"
"typedef unsigned long int uintmax_t;\n"
"\n"
"#define __INT64_C(c) c##L\n"
"#define __UINT64_C(c) c##UL\n"
"\n"
"#define INT8_MIN (-128)\n"
"#define INT16_MIN (-32768)\n"
"#define INT32_MIN (-2147483648)\n"
"#define INT64_MIN (-9223372036854775808l)\n"
"\n"
"#define INT8_MAX (127)\n"
"#define INT16_MAX (32767)\n"
"#define INT32_MAX (2147483647)\n"
"#define INT64_MAX (9223372036854775807l)\n"
"\n"
"#define UINT8_MAX (255)\n"
"#define UINT16_MAX (65535)\n"
"#define UINT32_MAX (4294967295u)\n"
"#define UINT64_MAX (18446744073709551615ul)\n"
"\n"
"#define INT_LEAST8_MIN (-128)\n"
"#define INT_LEAST16_MIN (-32768)\n"
"#define INT_LEAST32_MIN (-2147483648)\n"
"#define INT_LEAST64_MIN (-9223372036854775808L)\n"
"\n"
"#define INT_LEAST8_MAX (127)\n"
"#define INT_LEAST16_MAX (32767)\n"
"#define INT_LEAST32_MAX (2147483647)\n"
"#define INT_LEAST64_MAX (9223372036854775807L)\n"
"\n"
"#define UINT_LEAST8_MAX (255)\n"
"#define UINT_LEAST16_MAX (65535)\n"
"#define UINT_LEAST32_MAX (4294967295U)\n"
"#define UINT_LEAST64_MAX (18446744073709551615UL)\n"
"\n"
"#define INT_FAST8_MIN (-128)\n"
"#define INT_FAST16_MIN (-9223372036854775808L)\n"
"#define INT_FAST32_MIN (-9223372036854775808L)\n"
"#define INT_FAST64_MIN (-9223372036854775808L)\n"
"\n"
"#define INT_FAST8_MAX (127)\n"
"#define INT_FAST16_MAX (9223372036854775807L)\n"
"#define INT_FAST32_MAX (9223372036854775807L)\n"
"#define INT_FAST64_MAX (9223372036854775807L)\n"
"\n"
"#define UINT_FAST8_MAX (255)\n"
"#define UINT_FAST16_MAX (18446744073709551615UL)\n"
"#define UINT_FAST32_MAX (18446744073709551615UL)\n"
"#define UINT_FAST64_MAX (18446744073709551615UL)\n"
"\n"
"#define INTPTR_MIN (-9223372036854775808L)\n"
"#define INTPTR_MAX (9223372036854775807L)\n"
"#define UINTPTR_MAX (18446744073709551615UL)\n"
"\n"
"#define INTMAX_MIN (-9223372036854775808L)\n"
"#define INTMAX_MAX (9223372036854775807L)\n"
"#define UINTMAX_MAX (18446744073709551615UL)\n"
"\n"
"#define PTRDIFF_MIN (-9223372036854775808L)\n"
"#define PTRDIFF_MAX (9223372036854775807L)\n"
"\n"
"#define SIZE_MAX (18446744073709551615UL)\n"
"\n"
"/* For signed wchar_t and wint_t: */\n"
"#define WCHAR_MIN INT32_MIN\n"
"#define WCHAR_MAX INT32_MAX\n"
"#define WINT_MIN WCHAR_MIN\n"
"#define WINT_MAX WCHAR_MAX\n"
"\n"
"#define INT8_C(value) value\n"
"#define INT16_C(value) value\n"
"#define INT32_C(value) value\n"
"#define INT64_C(value) value##L\n"
"\n"
"#define UINT8_C(value) value\n"
"#define UINT16_C(value) value\n"
"#define UINT32_C(value) value##U\n"
"#define UINT64_C(value) value##UL\n"
"\n"
"#define INTMAX_C(value) value##L\n"
"#define UINTMAX_C(value) value##UL\n"
"\n"
"#endif /* #ifndef _STDINT_H */\n";

@ -36,6 +36,10 @@ static int reg_aggregate_p (c2m_ctx_t c2m_ctx, struct type *arg_type) {
return size == 1 || size == 2 || size == 4 || size == 8;
}
static MIR_type_t target_get_blk_type (c2m_ctx_t c2m_ctx, struct type *arg_type) {
return MIR_T_BLK; /* one BLK is enough */
}
static void target_add_arg_proto (c2m_ctx_t c2m_ctx, const char *name, struct type *arg_type,
target_arg_info_t *arg_info, VARR (MIR_var_t) * arg_vars) {
MIR_var_t var;

@ -3,16 +3,20 @@
*/
#include "../mirc.h"
#include "mirc-s390x-linux.h"
#include "mirc_s390x_linux.h"
static const char *standard_includes[] = {mirc, s390x_mirc};
#include "mirc_s390x_float.h"
#include "mirc_s390x_limits.h"
#include "mirc_s390x_stdarg.h"
#include "mirc_s390x_stdint.h"
#include "mirc_s390x_stddef.h"
static const char *standard_include_dirs[] = {"include/mirc/", "include/mirc/s390x/"};
static string_include_t standard_includes[]
= {{NULL, mirc}, {NULL, s390x_mirc}, TARGET_STD_INCLUDES};
#define MAX_ALIGNMENT 16
#define ADJUST_VAR_ALIGNMENT(c2m_ctx, align, type) \
s390x_adjust_var_alignment (c2m_ctx, align, type)
#define ADJUST_VAR_ALIGNMENT(c2m_ctx, align, type) s390x_adjust_var_alignment (c2m_ctx, align, type)
static int s390x_adjust_var_alignment (c2m_ctx_t c2m_ctx, int align, struct type *type) {
return align;

@ -0,0 +1,60 @@
/* This file is a part of MIR project.
Copyright (C) 2020 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
/* See C11 5.2.4.2.2 */
static char float_str[]
= "#ifndef __FLOAT_H\n"
"#define __FLOAT_H\n"
"\n"
"#define FLT_RADIX 2\n"
"\n"
"#define FLT_MANT_DIG 24\n"
"#define DBL_MANT_DIG 53\n"
"#define LDBL_MANT_DIG DBL_MANT_DIG\n"
"\n"
"#define FLT_DECIMAL_DIG 9\n"
"#define DBL_DECIMAL_DIG 17\n"
"#define LDBL_DECIMAL_DIG DBL_DECIMAL_DIG\n"
"#define FLT_DIG FLT_DECIMAL_DIG\n"
"#define DBL_DIG DBL_DECIMAL_DIG\n"
"#define LDBL_DIG LDBL_DECIMAL_DIG\n"
"\n"
"#define DECIMAL_DIG LDBL_DECIMAL_DIG\n"
"\n"
"#define FLT_MIN_EXP -125\n"
"#define DBL_MIN_EXP -1021\n"
"#define LDBL_MIN_EXP DBL_MIN_EXP\n"
"\n"
"#define FLT_MIN_10_EXP -37\n"
"#define DBL_MIN_10_EXP -307\n"
"#define LDBL_MIN_10_EXP DBL_MIN_10_EXP\n"
"\n"
"#define FLT_MAX_EXP 128\n"
"#define DBL_MAX_EXP 1024\n"
"#define LDBL_MAX_EXP DBL_MAX_EXP\n"
"\n"
"#define FLT_MAX_10_EXP 38\n"
"#define DBL_MAX_10_EXP 308\n"
"#define LDBL_MAX_10_EXP DBL_MAX_10_EXP\n"
"\n"
"#define FLT_MAX 0x1.fffffep+127\n"
"#define DBL_MAX 0x1.fffffffffffffp+1023\n"
"#define LDBL_MAX DBL_MAX\n"
"\n"
"#define FLT_EPSILON 0x1p-23\n"
"#define DBL_EPSILON 0x1p-52\n"
"#define LDBL_EPSILON DBL_EPSILON\n"
"\n"
"#define FLT_MIN 0x1p-126\n"
"#define DBL_MIN 0x1p-1022\n"
"#define LDBL_MIN DBL_MIN\n"
"\n"
"#define FLT_TRUE_MIN 0x1p-149\n"
"#define DBL_TRUE_MIN 0x0.0000000000001p-1022\n"
"#define LDBL_TRUE_MIN DBL_TRUE_MIN\n"
"\n"
"#define FLT_EVAL_METHOD 0\n"
"#define FLT_ROUNDS 1 /* round to the nearest */\n"
"\n"
"#endif /* #ifndef __FLOAT_H */\n";

@ -0,0 +1,38 @@
/* This file is a part of MIR project.
Copyright (C) 2020 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
/* See 5.2.4.2 */
static char limits_str[]
= "#ifndef __LIMITS_H\n"
"#define __LIMITS_H\n"
"\n"
"#define CHAR_BIT 8\n"
"\n"
"#define SCHAR_MIN (-SCHAR_MAX - 1)\n"
"#define SCHAR_MAX 127\n"
"#define UCHAR_MAX (SCHAR_MAX * 2 + 1)\n"
"\n"
"#define MB_LEN_MAX 1\n"
"\n"
"#define SHRT_MIN (-SHRT_MAX - 1)\n"
"#define SHRT_MAX 32767\n"
"#define USHRT_MAX (SHRT_MAX * 2 + 1)\n"
"\n"
"#define INT_MIN (-INT_MAX - 1)\n"
"#define INT_MAX 2147483647\n"
"#define UINT_MAX (INT_MAX * 2u + 1u)\n"
"\n"
"#define LONG_MIN (-LONG_MAX - 1l)\n"
"#define LONG_MAX 9223372036854775807l\n"
"#define ULONG_MAX (LONG_MAX * 2ul + 1ul)\n"
"\n"
"#define LLONG_MIN LONG_MIN\n"
"#define LLONG_MAX LONG_MAX\n"
"#define ULLONG_MAX ULONG_MAX\n"
"\n"
"/* unsigned char by default */\n"
"#define CHAR_MIN 0\n"
"#define CHAR_MAX UCHAR_MAX\n"
"\n"
"#endif /* #ifndef __LIMITS_H */\n";

@ -0,0 +1,25 @@
/* This file is a part of MIR project.
Copyright (C) 2020 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
static char stdarg_str[]
= "#ifndef __STDARG_H\n"
"#define __STDARG_H\n"
"\n"
"typedef struct {\n"
" long __gpr, __fpr;\n"
" void *__overflow_arg_area;\n"
" void *__reg_save_area;\n"
"} va_list[1];\n"
"\n"
"#define va_start(ap, param) __builtin_va_start (ap)\n"
"#define va_arg(ap, type) __builtin_va_arg(ap, (type *) 0)\n"
"#define va_end(ap) 0\n"
"#define va_copy(dest, src) ((dest) = (src))\n"
"\n"
"/* For standard headers of a GNU system: */\n"
"#ifndef __GNUC_VA_LIST\n"
"#define __GNUC_VA_LIST 1\n"
"#endif\n"
"typedef va_list __gnuc_va_list;\n"
"#endif /* #ifndef __STDARG_H */\n";

@ -0,0 +1,19 @@
/* This file is a part of MIR project.
Copyright (C) 2020 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
/* See C11 7.19 */
static char stddef_str[]
= "#ifndef __STDDEF_H\n"
"#define __STDDEF_H\n"
"\n"
"typedef long ptrdiff_t;\n"
"typedef unsigned long size_t;\n"
"typedef long double max_align_t;\n"
"typedef unsigned int wchar_t;\n"
"\n"
"#define NULL ((void *) 0)\n"
"\n"
"#define offsetof(type, member_designator) ((size_t) & ((type *) 0)->member_designator)\n"
"\n"
"#endif /* #ifndef __STDDEF_H */\n";

@ -0,0 +1,130 @@
/* This file is a part of MIR project.
Copyright (C) 2020 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
/* See C11 7.20 */
static char stdint_str[]
= "#ifndef _STDINT_H\n"
"#define _STDINT_H 1\n"
"\n"
"#ifndef __int8_t_defined\n"
"#define __int8_t_defined\n"
"typedef signed char int8_t;\n"
"#endif\n"
"typedef short int int16_t;\n"
"typedef int int32_t;\n"
"typedef long int int64_t;\n"
"\n"
"typedef unsigned char uint8_t;\n"
"typedef unsigned short int uint16_t;\n"
"typedef unsigned int uint32_t;\n"
"typedef unsigned long int uint64_t;\n"
"\n"
"typedef signed char int_least8_t;\n"
"typedef short int int_least16_t;\n"
"typedef int int_least32_t;\n"
"typedef long int int_least64_t;\n"
"\n"
"typedef unsigned char uint_least8_t;\n"
"typedef unsigned short int uint_least16_t;\n"
"typedef unsigned int uint_least32_t;\n"
"typedef unsigned long int uint_least64_t;\n"
"\n"
"typedef signed char int_fast8_t;\n"
"typedef long int int_fast16_t;\n"
"typedef long int int_fast32_t;\n"
"typedef long int int_fast64_t;\n"
"\n"
"typedef unsigned char uint_fast8_t;\n"
"typedef unsigned long int uint_fast16_t;\n"
"typedef unsigned long int uint_fast32_t;\n"
"typedef unsigned long int uint_fast64_t;\n"
"\n"
"#define __intptr_t_defined\n"
"typedef long int intptr_t;\n"
"typedef unsigned long int uintptr_t;\n"
"\n"
"typedef long int intmax_t;\n"
"typedef unsigned long int uintmax_t;\n"
"\n"
"#define __INT64_C(c) c##L\n"
"#define __UINT64_C(c) c##UL\n"
"\n"
"#define INT8_MIN (-128)\n"
"#define INT16_MIN (-32768)\n"
"#define INT32_MIN (-2147483648)\n"
"#define INT64_MIN (-9223372036854775808l)\n"
"\n"
"#define INT8_MAX (127)\n"
"#define INT16_MAX (32767)\n"
"#define INT32_MAX (2147483647)\n"
"#define INT64_MAX (9223372036854775807l)\n"
"\n"
"#define UINT8_MAX (255)\n"
"#define UINT16_MAX (65535)\n"
"#define UINT32_MAX (4294967295u)\n"
"#define UINT64_MAX (18446744073709551615ul)\n"
"\n"
"#define INT_LEAST8_MIN (-128)\n"
"#define INT_LEAST16_MIN (-32768)\n"
"#define INT_LEAST32_MIN (-2147483648)\n"
"#define INT_LEAST64_MIN (-9223372036854775808L)\n"
"\n"
"#define INT_LEAST8_MAX (127)\n"
"#define INT_LEAST16_MAX (32767)\n"
"#define INT_LEAST32_MAX (2147483647)\n"
"#define INT_LEAST64_MAX (9223372036854775807L)\n"
"\n"
"#define UINT_LEAST8_MAX (255)\n"
"#define UINT_LEAST16_MAX (65535)\n"
"#define UINT_LEAST32_MAX (4294967295U)\n"
"#define UINT_LEAST64_MAX (18446744073709551615UL)\n"
"\n"
"#define INT_FAST8_MIN (-128)\n"
"#define INT_FAST16_MIN (-9223372036854775808L)\n"
"#define INT_FAST32_MIN (-9223372036854775808L)\n"
"#define INT_FAST64_MIN (-9223372036854775808L)\n"
"\n"
"#define INT_FAST8_MAX (127)\n"
"#define INT_FAST16_MAX (9223372036854775807L)\n"
"#define INT_FAST32_MAX (9223372036854775807L)\n"
"#define INT_FAST64_MAX (9223372036854775807L)\n"
"\n"
"#define UINT_FAST8_MAX (255)\n"
"#define UINT_FAST16_MAX (18446744073709551615UL)\n"
"#define UINT_FAST32_MAX (18446744073709551615UL)\n"
"#define UINT_FAST64_MAX (18446744073709551615UL)\n"
"\n"
"#define INTPTR_MIN (-9223372036854775808L)\n"
"#define INTPTR_MAX (9223372036854775807L)\n"
"#define UINTPTR_MAX (18446744073709551615UL)\n"
"\n"
"#define INTMAX_MIN (-9223372036854775808L)\n"
"#define INTMAX_MAX (9223372036854775807L)\n"
"#define UINTMAX_MAX (18446744073709551615UL)\n"
"\n"
"#define PTRDIFF_MIN (-9223372036854775808L)\n"
"#define PTRDIFF_MAX (9223372036854775807L)\n"
"\n"
"#define SIZE_MAX (18446744073709551615UL)\n"
"\n"
"/* For signed wchar_t and wint_t: */\n"
"#define WCHAR_MIN INT32_MIN\n"
"#define WCHAR_MAX INT32_MAX\n"
"#define WINT_MIN WCHAR_MIN\n"
"#define WINT_MAX WCHAR_MAX\n"
"\n"
"#define INT8_C(value) value\n"
"#define INT16_C(value) value\n"
"#define INT32_C(value) value\n"
"#define INT64_C(value) value##L\n"
"\n"
"#define UINT8_C(value) value\n"
"#define UINT16_C(value) value\n"
"#define UINT32_C(value) value##U\n"
"#define UINT64_C(value) value##UL\n"
"\n"
"#define INTMAX_C(value) value##L\n"
"#define UINTMAX_C(value) value##UL\n"
"\n"
"#endif /* #ifndef _STDINT_H */\n";

@ -8,7 +8,7 @@
enum add_arg_class { NO_CLASS = MIR_T_BOUND + 1, X87UP_CLASS };
#ifndef _WIN64
#ifndef _WIN32
#define MAX_QWORDS 2
#else
#define MAX_QWORDS 1
@ -44,7 +44,7 @@ static int classify_arg (c2m_ctx_t c2m_ctx, struct type *type, MIR_type_t types[
if (n_qwords > MAX_QWORDS) return 0; /* too big aggregate */
#ifndef _WIN64
#ifndef _WIN32
for (i = 0; i < n_qwords; i++) types[i] = (MIR_type_t) NO_CLASS;
switch (type->mode) {
@ -112,16 +112,6 @@ static void target_init_arg_vars (c2m_ctx_t c2m_ctx, target_arg_info_t *arg_info
arg_info->n_iregs = arg_info->n_fregs = 0;
}
static const char *qword_name (c2m_ctx_t c2m_ctx, const char *name, int num) {
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 update_last_qword_type (c2m_ctx_t c2m_ctx, struct type *type,
MIR_type_t qword_types[MAX_QWORDS], int n) {
size_t last_size, size = type_size (c2m_ctx, type);
@ -326,21 +316,44 @@ static int process_aggregate_arg (c2m_ctx_t c2m_ctx, struct type *arg_type,
return n_qwords;
}
static MIR_type_t get_blk_type (int n_qwords, MIR_type_t *qword_types) {
int n, n_iregs = 0, n_fregs = 0;
assert (n_qwords <= 2);
if (n_qwords == 0) return MIR_T_BLK;
for (n = 0; n < n_qwords; n++) { /* start from the last qword */
switch (qword_types[n]) {
case MIR_T_I8:
case MIR_T_I16:
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: return MIR_T_BLK;
default: assert (FALSE);
}
}
if (n_iregs == n_qwords) return MIR_T_BLK2;
if (n_fregs == n_qwords) return MIR_T_BLK3;
if (qword_types[0] == MIR_T_F || qword_types[0] == MIR_T_D) return MIR_T_BLK5;
return MIR_T_BLK4;
}
static MIR_type_t target_get_blk_type (c2m_ctx_t c2m_ctx, struct type *arg_type) {
MIR_type_t qword_types[MAX_QWORDS];
int n_qwords = classify_arg (c2m_ctx, arg_type, qword_types, FALSE);
assert (arg_type->mode == TM_STRUCT || arg_type->mode == TM_UNION);
return get_blk_type (n_qwords, qword_types);
}
static void target_add_arg_proto (c2m_ctx_t c2m_ctx, const char *name, struct type *arg_type,
target_arg_info_t *arg_info, VARR (MIR_var_t) * arg_vars) {
MIR_var_t var;
MIR_type_t type;
MIR_type_t qword_types[MAX_QWORDS];
int n, n_qwords = process_aggregate_arg (c2m_ctx, arg_type, arg_info, qword_types);
int n_qwords = process_aggregate_arg (c2m_ctx, arg_type, arg_info, qword_types);
if (n_qwords != 0) {
for (n = 0; n < n_qwords; n++) {
var.name = qword_name (c2m_ctx, name, n);
var.type = promote_mir_int_type (qword_types[n]);
VARR_PUSH (MIR_var_t, arg_vars, var);
}
return;
}
/* pass aggregates on the stack and pass by value for others: */
var.name = name;
if (arg_type->mode != TM_STRUCT && arg_type->mode != TM_UNION) {
@ -351,7 +364,7 @@ static void target_add_arg_proto (c2m_ctx_t c2m_ctx, const char *name, struct ty
else if (type != MIR_T_LD)
arg_info->n_iregs++;
} else {
var.type = MIR_T_BLK;
var.type = get_blk_type (n_qwords, qword_types);
var.size = type_size (c2m_ctx, arg_type);
}
VARR_PUSH (MIR_var_t, arg_vars, var);
@ -363,22 +376,8 @@ static void target_add_call_arg_op (c2m_ctx_t c2m_ctx, struct type *arg_type,
MIR_context_t ctx = c2m_ctx->ctx;
MIR_type_t type;
MIR_type_t qword_types[MAX_QWORDS];
op_t temp;
int n, n_qwords = process_aggregate_arg (c2m_ctx, arg_type, arg_info, qword_types);
int n_qwords = process_aggregate_arg (c2m_ctx, arg_type, arg_info, qword_types);
if (n_qwords != 0) {
assert (arg.mir_op.mode == MIR_OP_MEM);
arg = mem_to_address (c2m_ctx, arg, TRUE);
for (n = 0; n < n_qwords; n++) {
type = qword_types[n];
temp = get_new_temp (c2m_ctx, promote_mir_int_type (type));
MIR_append_insn (ctx, curr_func,
MIR_new_insn (ctx, tp_mov (type), temp.mir_op,
MIR_new_mem_op (ctx, type, 8 * n, arg.mir_op.u.reg, 0, 1)));
VARR_PUSH (MIR_op_t, call_ops, temp.mir_op);
}
return;
}
/* pass aggregates on the stack and pass by value for others: */
if (arg_type->mode != TM_STRUCT && arg_type->mode != TM_UNION) {
type = get_mir_type (c2m_ctx, arg_type);
@ -390,40 +389,13 @@ static void target_add_call_arg_op (c2m_ctx_t c2m_ctx, struct type *arg_type,
} else {
assert (arg.mir_op.mode == MIR_OP_MEM);
arg = mem_to_address (c2m_ctx, arg, TRUE);
type = get_blk_type (n_qwords, qword_types);
VARR_PUSH (MIR_op_t, call_ops,
MIR_new_mem_op (ctx, MIR_T_BLK, type_size (c2m_ctx, arg_type), arg.mir_op.u.reg, 0,
1));
MIR_new_mem_op (ctx, type, type_size (c2m_ctx, arg_type), arg.mir_op.u.reg, 0, 1));
}
}
static int target_gen_gather_arg (c2m_ctx_t c2m_ctx, const char *name, struct type *arg_type,
decl_t param_decl, target_arg_info_t *arg_info) {
gen_ctx_t gen_ctx = c2m_ctx->gen_ctx;
MIR_context_t ctx = c2m_ctx->ctx;
MIR_type_t type;
reg_var_t reg_var;
MIR_type_t qword_types[MAX_QWORDS];
int i, n_qwords = process_aggregate_arg (c2m_ctx, arg_type, arg_info, qword_types);
if (arg_type->mode != TM_STRUCT && arg_type->mode != TM_UNION) {
assert (n_qwords == 0);
type = get_mir_type (c2m_ctx, arg_type);
if (type == MIR_T_F || type == MIR_T_D)
arg_info->n_fregs++;
else if (type != MIR_T_LD)
arg_info->n_iregs++;
return FALSE;
}
if (n_qwords == 0) return FALSE;
for (i = 0; i < n_qwords; i++) {
assert (!param_decl->reg_p);
type = qword_types[i];
reg_var = get_reg_var (c2m_ctx, type, qword_name (c2m_ctx, name, i));
MIR_append_insn (ctx, curr_func,
MIR_new_insn (ctx, tp_mov (type),
MIR_new_mem_op (ctx, type, param_decl->offset + 8 * i,
MIR_reg (ctx, FP_NAME, curr_func->u.func), 0, 1),
MIR_new_reg_op (ctx, reg_var.reg)));
}
return TRUE;
return FALSE;
}

@ -5,15 +5,19 @@
#include "../mirc.h"
#ifndef _WIN32
#include "mirc-x86_64-linux.h"
#include "mirc_x86_64_linux.h"
#else
#include "mirc-x86_64-win.h"
#include "mirc_x86_64_win.h"
#endif
#include "mirc_x86_64_float.h"
#include "mirc_x86_64_limits.h"
#include "mirc_x86_64_stdarg.h"
#include "mirc_x86_64_stdint.h"
#include "mirc_x86_64_stddef.h"
static const char *standard_includes[] = {mirc, x86_64_mirc};
static const char *standard_include_dirs[] = {"include/mirc/", "include/mirc/x86-64/"};
static string_include_t standard_includes[]
= {{NULL, mirc}, {NULL, x86_64_mirc}, TARGET_STD_INCLUDES};
#define MAX_ALIGNMENT 16

@ -9,7 +9,11 @@
typedef int8_t mir_schar;
typedef int16_t mir_short;
typedef int32_t mir_int;
#ifdef _WIN32
typedef int32_t mir_long;
#else
typedef int64_t mir_long;
#endif
typedef int64_t mir_llong;
#define MIR_SCHAR_MIN INT8_MIN
@ -18,21 +22,34 @@ typedef int64_t mir_llong;
#define MIR_SHORT_MAX INT16_MAX
#define MIR_INT_MIN INT32_MIN
#define MIR_INT_MAX INT32_MAX
#ifdef _WIN32
#define MIR_LONG_MIN INT32_MIN
#define MIR_LONG_MAX INT32_MAX
#else
#define MIR_LONG_MIN INT64_MIN
#define MIR_LONG_MAX INT64_MAX
#endif
#define MIR_LLONG_MIN INT64_MIN
#define MIR_LLONG_MAX INT64_MAX
typedef uint8_t mir_uchar;
typedef uint16_t mir_ushort;
typedef uint32_t mir_uint;
#ifdef _WIN32
typedef uint32_t mir_ulong;
#else
typedef uint64_t mir_ulong;
#endif
typedef uint64_t mir_ullong;
#define MIR_UCHAR_MAX UINT8_MAX
#define MIR_USHORT_MAX UINT16_MAX
#define MIR_UINT_MAX UINT32_MAX
#ifdef _WIN32
#define MIR_ULONG_MAX UINT32_MAX
#else
#define MIR_ULONG_MAX UINT64_MAX
#endif
#define MIR_ULLONG_MAX UINT64_MAX
typedef mir_schar mir_char;
@ -41,7 +58,11 @@ typedef mir_schar mir_char;
typedef float mir_float;
typedef double mir_double;
#ifdef _WIN32
typedef double mir_ldouble;
#else
typedef long double mir_ldouble;
#endif
typedef uint8_t mir_bool;
typedef int64_t mir_ptrdiff_t;

@ -0,0 +1,60 @@
/* This file is a part of MIR project.
Copyright (C) 2019-2020 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
/* See C11 5.2.4.2.2 */
static char float_str[]
= "#ifndef __FLOAT_H\n"
"#define __FLOAT_H\n"
"\n"
"#define FLT_RADIX 2\n"
"\n"
"#define FLT_MANT_DIG 24\n"
"#define DBL_MANT_DIG 53\n"
"#define LDBL_MANT_DIG DBL_MANT_DIG\n"
"\n"
"#define FLT_DECIMAL_DIG 9\n"
"#define DBL_DECIMAL_DIG 17\n"
"#define LDBL_DECIMAL_DIG DBL_DECIMAL_DIG\n"
"#define FLT_DIG FLT_DECIMAL_DIG\n"
"#define DBL_DIG DBL_DECIMAL_DIG\n"
"#define LDBL_DIG LDBL_DECIMAL_DIG\n"
"\n"
"#define DECIMAL_DIG LDBL_DECIMAL_DIG\n"
"\n"
"#define FLT_MIN_EXP -125\n"
"#define DBL_MIN_EXP -1021\n"
"#define LDBL_MIN_EXP DBL_MIN_EXP\n"
"\n"
"#define FLT_MIN_10_EXP -37\n"
"#define DBL_MIN_10_EXP -307\n"
"#define LDBL_MIN_10_EXP DBL_MIN_10_EXP\n"
"\n"
"#define FLT_MAX_EXP 128\n"
"#define DBL_MAX_EXP 1024\n"
"#define LDBL_MAX_EXP DBL_MAX_EXP\n"
"\n"
"#define FLT_MAX_10_EXP 38\n"
"#define DBL_MAX_10_EXP 308\n"
"#define LDBL_MAX_10_EXP DBL_MAX_10_EXP\n"
"\n"
"#define FLT_MAX 0x1.fffffep+127\n"
"#define DBL_MAX 0x1.fffffffffffffp+1023\n"
"#define LDBL_MAX DBL_MAX\n"
"\n"
"#define FLT_EPSILON 0x1p-23\n"
"#define DBL_EPSILON 0x1p-52\n"
"#define LDBL_EPSILON DBL_EPSILON\n"
"\n"
"#define FLT_MIN 0x1p-126\n"
"#define DBL_MIN 0x1p-1022\n"
"#define LDBL_MIN DBL_MIN\n"
"\n"
"#define FLT_TRUE_MIN 0x1p-149\n"
"#define DBL_TRUE_MIN 0x0.0000000000001p-1022\n"
"#define LDBL_TRUE_MIN DBL_TRUE_MIN\n"
"\n"
"#define FLT_EVAL_METHOD 0\n"
"#define FLT_ROUNDS 1 /* round to the nearest */\n"
"\n"
"#endif /* #ifndef __FLOAT_H */\n";

@ -0,0 +1,48 @@
/* This file is a part of MIR project.
Copyright (C) 2019-2020 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
/* See 5.2.4.2 */
static char limits_str[]
= "#ifndef __LIMITS_H\n"
"#define __LIMITS_H\n"
"\n"
"#define CHAR_BIT 8\n"
"\n"
"#define SCHAR_MIN (-SCHAR_MAX - 1)\n"
"#define SCHAR_MAX 127\n"
"#define UCHAR_MAX (SCHAR_MAX * 2 + 1)\n"
"\n"
"#define MB_LEN_MAX 1\n"
"\n"
"#define SHRT_MIN (-SHRT_MAX - 1)\n"
"#define SHRT_MAX 32767\n"
"#define USHRT_MAX (SHRT_MAX * 2 + 1)\n"
"\n"
"#define INT_MIN (-INT_MAX - 1)\n"
"#define INT_MAX 2147483647\n"
"#define UINT_MAX (INT_MAX * 2u + 1u)\n"
"\n"
#if defined(_WIN32)
"#define LONG_MIN (-LONG_MAX - 1l)\n"
"#define LONG_MAX 2147483647l\n"
"#define ULONG_MAX (LONG_MAX * 2ul + 1ul)\n"
"\n"
"#define LLONG_MIN (-LLONG_MAX - 1ll)\n"
"#define LLONG_MAX 9223372036854775807ll\n"
"#define ULLONG_MAX (LLONG_MAX * 2ull + 1ull)\n"
#else
"#define LONG_MIN (-LONG_MAX - 1l)\n"
"#define LONG_MAX 9223372036854775807l\n"
"#define ULONG_MAX (LONG_MAX * 2ul + 1ul)\n"
"\n"
"#define LLONG_MIN (-LLONG_MAX - 1ll)\n"
"#define LLONG_MAX 9223372036854775807ll\n"
"#define ULLONG_MAX (LLONG_MAX * 2ull + 1ull)\n"
#endif
"\n"
"/* signed char by default */\n"
"#define CHAR_MIN SCHAR_MIN\n"
"#define CHAR_MAX SCHAR_MAX\n"
"\n"
"#endif /* #ifndef __LIMITS_H */\n";

@ -92,6 +92,7 @@ static char x86_64_mirc[]
"#define __unix__ 1\n"
#elif defined(__APPLE__)
"#define __APPLE__ 1\n"
"#define __DARWIN_OS_INLINE static inline\n"
"typedef struct {\n"
" unsigned int gp_offset;\n"
" unsigned int fp_offset;\n"

@ -0,0 +1,41 @@
/* This file is a part of MIR project.
Copyright (C) 2019-2020 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
/* See C11 7.16 and https://www.uclibc.org/docs/psABI-x86_64.pdf */
static char stdarg_str[]
= "#ifndef __STDARG_H\n"
"#define __STDARG_H\n"
"\n"
#if defined(__APPLE__)
"typedef __darwin_va_list va_list;\n"
#elif defined(__WIN32)
"typedef char *va_list;\n"
#else
"typedef struct {\n"
" unsigned int gp_offset;\n"
" unsigned int fp_offset;\n"
" void *overflow_arg_area;\n"
" void *reg_save_area;\n"
"} va_list[1];\n"
#endif
"\n"
#if defined(__WIN32)
"#define va_start(ap, param) __va_start (ap, param)\n"
#else
"#define va_start(ap, param) __builtin_va_start (ap)\n"
#endif
"#define va_arg(ap, type) __builtin_va_arg(ap, (type *) 0)\n"
"#define va_end(ap) 0\n"
#if defined(__APPLE__) || defined(__WIN32)
"#define va_copy(dest, src) ((dest) = (src))\n"
#else
"#define va_copy(dest, src) ((dest)[0] = (src)[0])\n"
#endif
"\n"
"/* For standard headers of a GNU system: */\n"
"#ifndef __GNUC_VA_LIST\n"
"#define __GNUC_VA_LIST 1\n"
"#endif\n"
"typedef va_list __gnuc_va_list;\n"
"#endif /* #ifndef __STDARG_H */\n";

@ -0,0 +1,32 @@
/* This file is a part of MIR project.
Copyright (C) 2019-2020 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
/* See C11 7.19 */
static char stddef_str[]
= "#ifndef __STDDEF_H\n"
"#define __STDDEF_H\n"
"\n"
#ifdef _WIN32
"typedef long long int ptrdiff_t;\n"
"typedef unsigned long long size_t;\n"
#else
"typedef long ptrdiff_t;\n"
"typedef unsigned long size_t;\n"
#endif
"typedef long double max_align_t;\n"
#if defined(__APPLE__)
"typedef int wchar_t;\n"
#elif defined(_WIN32)
"typedef unsigned short wchar_t;\n"
#else
"typedef unsigned int wchar_t;\n"
#endif
"\n"
#if !defined(__APPLE__) && !defined(_WIN32)
"#define NULL ((void *) 0)\n"
#endif
"\n"
"#define offsetof(type, member_designator) ((size_t) & ((type *) 0)->member_designator)\n"
"\n"
"#endif /* #ifndef __STDDEF_H */\n";

@ -0,0 +1,175 @@
/* This file is a part of MIR project.
Copyright (C) 2019-2020 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
/* See C11 7.20 */
static char stdint_str[]
= "#ifndef _STDINT_H\n"
"#define _STDINT_H 1\n"
"\n"
"typedef signed char int8_t;\n"
"typedef short int int16_t;\n"
"typedef int int32_t;\n"
#if defined(__APPLE__) || defined(_WIN32)
"typedef long long int int64_t;\n"
#else
"typedef long int int64_t;\n"
#endif
"\n"
"typedef unsigned char uint8_t;\n"
"typedef unsigned short int uint16_t;\n"
"typedef unsigned int uint32_t;\n"
#if defined(__APPLE__) || defined(_WIN32)
"typedef unsigned long long int uint64_t;\n"
#else
"typedef unsigned long int uint64_t;\n"
#endif
"\n"
"typedef signed char int_least8_t;\n"
"typedef short int int_least16_t;\n"
"typedef int int_least32_t;\n"
#if defined(_WIN32)
"typedef long long int int_least64_t;\n"
#else
"typedef long int int_least64_t;\n"
#endif
"\n"
"typedef unsigned char uint_least8_t;\n"
"typedef unsigned short int uint_least16_t;\n"
"typedef unsigned int uint_least32_t;\n"
#if defined(_WIN32)
"typedef unsigned long long int uint_least64_t;\n"
#else
"typedef unsigned long int uint_least64_t;\n"
#endif
"\n"
"typedef signed char int_fast8_t;\n"
"typedef long int int_fast16_t;\n"
"typedef long int int_fast32_t;\n"
#if defined(_WIN32)
"typedef long long int int_fast64_t;\n"
#else
"typedef long int int_fast64_t;\n"
#endif
"\n"
"typedef unsigned char uint_fast8_t;\n"
"typedef unsigned long int uint_fast16_t;\n"
"typedef unsigned long int uint_fast32_t;\n"
#if defined(_WIN32)
"typedef unsigned long long int uint_fast64_t;\n"
#else
"typedef unsigned long int uint_fast64_t;\n"
#endif
"\n"
"#define __intptr_t_defined\n"
#if defined(_WIN32)
"typedef long long int intptr_t;\n"
"typedef unsigned long long int uintptr_t;\n"
"\n"
"typedef long long int intmax_t;\n"
"typedef unsigned long long int uintmax_t;\n"
"\n"
"#define __INT64_C(c) c##LL\n"
"#define __UINT64_C(c) c##ULL\n"
#else
"typedef long int intptr_t;\n"
"typedef unsigned long int uintptr_t;\n"
"\n"
"typedef long int intmax_t;\n"
"typedef unsigned long int uintmax_t;\n"
"\n"
"#define __INT64_C(c) c##L\n"
"#define __UINT64_C(c) c##UL\n"
#endif
"\n"
"#define INT8_MIN (-128)\n"
"#define INT16_MIN (-32768)\n"
"#define INT32_MIN (-2147483648)\n"
"#define INT64_MIN (-9223372036854775808l)\n"
"\n"
"#define INT8_MAX (127)\n"
"#define INT16_MAX (32767)\n"
"#define INT32_MAX (2147483647)\n"
"#define INT64_MAX (9223372036854775807l)\n"
"\n"
"#define UINT8_MAX (255)\n"
"#define UINT16_MAX (65535)\n"
"#define UINT32_MAX (4294967295u)\n"
"#define UINT64_MAX (18446744073709551615ul)\n"
"\n"
"#define INT_LEAST8_MIN (-128)\n"
"#define INT_LEAST16_MIN (-32768)\n"
"#define INT_LEAST32_MIN (-2147483648)\n"
"#define INT_LEAST64_MIN (-9223372036854775808L)\n"
"\n"
"#define INT_LEAST8_MAX (127)\n"
"#define INT_LEAST16_MAX (32767)\n"
"#define INT_LEAST32_MAX (2147483647)\n"
"#define INT_LEAST64_MAX (9223372036854775807L)\n"
"\n"
"#define UINT_LEAST8_MAX (255)\n"
"#define UINT_LEAST16_MAX (65535)\n"
"#define UINT_LEAST32_MAX (4294967295U)\n"
"#define UINT_LEAST64_MAX (18446744073709551615UL)\n"
"\n"
"#define INT_FAST8_MIN (-128)\n"
"#define INT_FAST16_MIN (-9223372036854775808L)\n"
"#define INT_FAST32_MIN (-9223372036854775808L)\n"
"#define INT_FAST64_MIN (-9223372036854775808L)\n"
"\n"
"#define INT_FAST8_MAX (127)\n"
"#define INT_FAST16_MAX (9223372036854775807L)\n"
"#define INT_FAST32_MAX (9223372036854775807L)\n"
"#define INT_FAST64_MAX (9223372036854775807L)\n"
"\n"
"#define UINT_FAST8_MAX (255)\n"
"#define UINT_FAST16_MAX (18446744073709551615UL)\n"
"#define UINT_FAST32_MAX (18446744073709551615UL)\n"
"#define UINT_FAST64_MAX (18446744073709551615UL)\n"
"\n"
"#define INTPTR_MIN (-9223372036854775808L)\n"
"#define INTPTR_MAX (9223372036854775807L)\n"
"#define UINTPTR_MAX (18446744073709551615UL)\n"
"\n"
"#define INTMAX_MIN (-9223372036854775808L)\n"
"#define INTMAX_MAX (9223372036854775807L)\n"
"#define UINTMAX_MAX (18446744073709551615UL)\n"
"\n"
"#define PTRDIFF_MIN (-9223372036854775808L)\n"
"#define PTRDIFF_MAX (9223372036854775807L)\n"
"\n"
"#define SIZE_MAX (18446744073709551615UL)\n"
"\n"
"/* For signed wchar_t and wint_t: */\n"
"#define WCHAR_MIN INT32_MIN\n"
"#define WCHAR_MAX INT32_MAX\n"
"#define WINT_MIN WCHAR_MIN\n"
"#define WINT_MAX WCHAR_MAX\n"
"\n"
"#define INT8_C(value) value\n"
"#define INT16_C(value) value\n"
"#define INT32_C(value) value\n"
#if defined(_WIN32)
"#define INT64_C(value) value##LL\n"
#else
"#define INT64_C(value) value##L\n"
#endif
"\n"
"#define UINT8_C(value) value\n"
"#define UINT16_C(value) value\n"
"#define UINT32_C(value) value##U\n"
#if defined(_WIN32)
"#define UINT64_C(value) value##ULL\n"
#else
"#define UINT64_C(value) value##UL\n"
#endif
"\n"
#if defined(_WIN32)
"#define INTMAX_C(value) value##L\n"
"#define UINTMAX_C(value) value##UL\n"
#else
"#define INTMAX_C(value) value##LL\n"
"#define UINTMAX_C(value) value##ULL\n"
#endif
"\n"
"#endif /* #ifndef _STDINT_H */\n";

@ -7,11 +7,13 @@ static char x86_64_mirc[]
"#define __amd64__ 1\n"
"#define __x86_64 1\n"
"#define __x86_64__ 1\n"
"#define _M_AMD64 1\n"
"#define _M_X64 1\n"
"\n"
"#define __SIZEOF_DOUBLE__ 8\n"
"#define __SIZEOF_FLOAT__ 4\n"
"#define __SIZEOF_INT__ 4\n"
#if __SIZEOF_LONG_DOUBLE__ == 16
#if !defined(_WIN32) && __SIZEOF_LONG_DOUBLE__ == 16
"#define __SIZEOF_LONG_DOUBLE__ 16\n"
#else
"#define __SIZEOF_LONG_DOUBLE__ 8\n"
@ -43,6 +45,19 @@ static char x86_64_mirc[]
"#define __INTPTR_TYPE__ long long int\n"
"#define __UINTPTR_TYPE__ long long unsigned int\n"
"\n"
"#define __int8 __INT8_TYPE__\n"
"#define __int16 __INT16_TYPE__\n"
"#define __int32 __INT32_TYPE__\n"
"#define __int64 __INT64_TYPE__\n"
"\n"
"#define __ptr32\n"
"#define __ptr64\n"
"#define __forceinline inline\n"
"#define __cdecl\n"
"#define __pragma(p)\n"
"#define __declspec(attr)\n"
"#define __unaligned\n"
"\n"
"#define __CHAR_BIT__ 8\n"
"#define __INT8_MAX__ 127\n"
"#define __INT16_MAX__ 32767\n"

@ -4,7 +4,7 @@
#define VA_LIST_IS_ARRAY_P 0
/* Small BLK (less or equal to two quadwords) args are passed in
/* Small BLK..BLK5 (less or equal to two quadwords) args are passed in
*fully* regs or on stack (w/o address), otherwise it is put
somehwere on stack and its address passed instead. First RBLK arg
is passed in r8. Other RBLK independently of size is always passed
@ -64,7 +64,7 @@ void *va_arg_builtin (void *p, uint64_t t) {
return a;
}
void *va_stack_arg_builtin (void *p, size_t s) {
void va_block_arg_builtin (void *res, void *p, size_t s, uint64_t ncase) {
struct aarch64_va_list *va = p;
void *a;
long size = (s + 7) / 8 * 8;
@ -73,7 +73,8 @@ void *va_stack_arg_builtin (void *p, size_t s) {
a = va->__stack;
va->__stack = (char *) va->__stack + size;
va->__gr_offs += size;
return a;
memcpy (res, a, s);
return;
}
if (size > 2 * 8) size = 8;
if (va->__gr_offs < 0) {
@ -83,8 +84,8 @@ void *va_stack_arg_builtin (void *p, size_t s) {
a = va->__stack;
va->__stack = (char *) va->__stack + size;
}
if (s > 2 * 8) return *(void **) a; /* address */
return a;
if (s > 2 * 8) a = *(void **) a; /* address */
memcpy (res, a, s);
}
void va_start_interp_builtin (MIR_context_t ctx, void *p, void *a) {
@ -280,8 +281,8 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
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 || MIR_blk_type_p (type)) {
if (type == MIR_T_BLK && (qwords = (arg_descs[i].size + 7) / 8) <= 2) {
if ((MIR_T_I8 <= type && type <= MIR_T_U64) || type == MIR_T_P || MIR_all_blk_type_p (type)) {
if (MIR_blk_type_p (type) && (qwords = (arg_descs[i].size + 7) / 8) <= 2) {
if (n_xregs + qwords > 8) blk_offset += qwords * 8;
n_xregs += qwords;
} else {
@ -300,7 +301,7 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
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 (type == MIR_T_BLK) {
if (MIR_blk_type_p (type)) {
qwords = (arg_descs[i].size + 7) / 8;
if (qwords <= 2) {
addr_reg = 13;
@ -486,9 +487,7 @@ void *_MIR_get_wrapper (MIR_context_t ctx, MIR_item_t called_func, void *hook_ad
size_t len = sizeof (save_insns) + sizeof (restore_insns); /* initial code length */
VARR (uint8_t) * code;
#if MIR_PARALLEL_GEN
pthread_mutex_lock (&code_mutex);
#endif
mir_mutex_lock (&code_mutex);
VARR_CREATE (uint8_t, code, 128);
for (;;) { /* dealing with moving code to another page */
curr_addr = base_addr = _MIR_get_new_code_addr (ctx, len);
@ -510,8 +509,6 @@ void *_MIR_get_wrapper (MIR_context_t ctx, MIR_item_t called_func, void *hook_ad
if (res_code != NULL) break;
}
VARR_DESTROY (uint8_t, code);
#if MIR_PARALLEL_GEN
pthread_mutex_unlock (&code_mutex);
#endif
mir_mutex_unlock (&code_mutex);
return res_code;
}

@ -261,7 +261,7 @@ static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_insn) {
type = arg_vars[i - start].type;
} else if (call_insn->ops[i].mode == MIR_OP_MEM) {
type = call_insn->ops[i].u.mem.type;
gen_assert (type == MIR_T_BLK || type == MIR_T_RBLK);
gen_assert (MIR_all_blk_type_p (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
@ -271,9 +271,9 @@ 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;
}
gen_assert (!MIR_blk_type_p (type) || call_insn->ops[i].mode == MIR_OP_MEM);
gen_assert (!MIR_all_blk_type_p (type) || call_insn->ops[i].mode == MIR_OP_MEM);
if (type == MIR_T_RBLK && i == start) continue; /* hidden arg */
if (type == MIR_T_BLK && (qwords = (call_insn->ops[i].u.mem.disp + 7) / 8) <= 2) {
if (MIR_blk_type_p (type) && (qwords = (call_insn->ops[i].u.mem.disp + 7) / 8) <= 2) {
if (int_arg_num + qwords > 8) blk_offset += qwords * 8;
int_arg_num += qwords;
} else if (get_arg_reg (type, &int_arg_num, &fp_arg_num, &new_insn_code) == MIR_NON_HARD_REG) {
@ -286,12 +286,12 @@ 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
|| (arg_op.mode == MIR_OP_MEM && MIR_blk_type_p (arg_op.u.mem.type)));
|| (arg_op.mode == MIR_OP_MEM && MIR_all_blk_type_p (arg_op.u.mem.type)));
if (i - start < nargs) {
type = arg_vars[i - start].type;
} else if (call_insn->ops[i].mode == MIR_OP_MEM) {
type = call_insn->ops[i].u.mem.type;
gen_assert (type == MIR_T_BLK || type == MIR_T_RBLK);
gen_assert (MIR_all_blk_type_p (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;
@ -303,14 +303,14 @@ static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_insn) {
call_insn->ops[i] = arg_op = temp_op;
}
gen_assert (
!MIR_blk_type_p (type)
!MIR_all_blk_type_p (type)
|| (arg_op.mode == MIR_OP_MEM && arg_op.u.mem.disp >= 0 && arg_op.u.mem.index == 0));
if (type == MIR_T_RBLK && i == start) { /* hidden arg */
arg_reg_op = _MIR_new_hard_reg_op (ctx, R8_HARD_REG);
gen_mov (gen_ctx, call_insn, MIR_MOV, arg_reg_op, MIR_new_reg_op (ctx, arg_op.u.mem.base));
call_insn->ops[i] = arg_reg_op;
continue;
} else if (type == MIR_T_BLK) {
} else if (MIR_blk_type_p (type)) {
qwords = (arg_op.u.mem.disp + 7) / 8;
if (qwords <= 2) {
arg_reg = R0_HARD_REG + int_arg_num;
@ -488,8 +488,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 const char *VA_BLOCK_ARG_P = "mir.va_block_arg.p";
static const char *VA_BLOCK_ARG = "mir.va_block_arg";
static int64_t mir_ldeq (long double d1, long double d2) { return d1 == d2; }
static const char *LDEQ = "mir.ldeq";
@ -636,13 +636,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");
case MIR_VA_BLOCK_ARG:
*proto_item
= _MIR_builtin_proto (ctx, curr_func_item->module, VA_BLOCK_ARG_P, 0, NULL, 4, MIR_T_I64,
"res", MIR_T_I64, "va", MIR_T_I64, "size", MIR_T_I64, "ncase");
*func_import_item
= _MIR_builtin_func (ctx, curr_func_item->module, VA_STACK_ARG, va_stack_arg_builtin);
return 2;
= _MIR_builtin_func (ctx, curr_func_item->module, VA_BLOCK_ARG, va_block_arg_builtin);
return 4;
default: return 0;
}
}
@ -670,7 +670,7 @@ DEF_VARR (label_ref_t);
DEF_VARR (MIR_code_reloc_t);
struct target_ctx {
unsigned char alloca_p, stack_arg_func_p, leaf_p;
unsigned char alloca_p, block_arg_func_p, leaf_p;
size_t small_aggregate_save_area;
VARR (int) * pattern_indexes;
VARR (insn_pattern_info_t) * insn_pattern_info;
@ -681,7 +681,7 @@ struct target_ctx {
};
#define alloca_p gen_ctx->target_ctx->alloca_p
#define stack_arg_func_p gen_ctx->target_ctx->stack_arg_func_p
#define block_arg_func_p gen_ctx->target_ctx->block_arg_func_p
#define leaf_p gen_ctx->target_ctx->leaf_p
#define small_aggregate_save_area gen_ctx->target_ctx->small_aggregate_save_area
#define pattern_indexes gen_ctx->target_ctx->pattern_indexes
@ -694,7 +694,7 @@ struct target_ctx {
static MIR_disp_t target_get_stack_slot_offset (gen_ctx_t gen_ctx, MIR_type_t type,
MIR_reg_t slot) {
/* slot is 0, 1, ... */
size_t offset = curr_func_item->u.func->vararg_p || stack_arg_func_p ? 32 : 16;
size_t offset = curr_func_item->u.func->vararg_p || block_arg_func_p ? 32 : 16;
return ((MIR_disp_t) slot * 8 + offset);
}
@ -712,7 +712,7 @@ static void target_machinize (gen_ctx_t gen_ctx) {
assert (curr_func_item->item_type == MIR_func_item);
func = curr_func_item->u.func;
stack_arg_func_p = FALSE;
block_arg_func_p = FALSE;
anchor = DLIST_HEAD (MIR_insn_t, func->insns);
small_aggregate_save_area = 0;
for (i = int_arg_num = fp_arg_num = mem_size = 0; i < func->nargs; i++) {
@ -724,7 +724,7 @@ static void target_machinize (gen_ctx_t gen_ctx) {
arg_reg_op = _MIR_new_hard_reg_op (ctx, R8_HARD_REG);
gen_mov (gen_ctx, anchor, MIR_MOV, MIR_new_reg_op (ctx, i + 1), arg_reg_op);
continue;
} else if (type == MIR_T_BLK && (qwords = (var.size + 7) / 8) <= 2) {
} else if (MIR_blk_type_p (type) && (qwords = (var.size + 7) / 8) <= 2) {
if (int_arg_num + qwords <= 8) {
small_aggregate_save_area += qwords * 8;
new_insn = MIR_new_insn (ctx, MIR_SUB, MIR_new_reg_op (ctx, i + 1),
@ -738,8 +738,8 @@ static void target_machinize (gen_ctx_t gen_ctx) {
gen_mov (gen_ctx, anchor, MIR_MOV, MIR_new_mem_op (ctx, MIR_T_I64, 8, i + 1, 0, 1),
_MIR_new_hard_reg_op (ctx, int_arg_num + 1));
} else { /* pass on stack w/o address: */
if (!stack_arg_func_p) {
stack_arg_func_p = TRUE;
if (!block_arg_func_p) {
block_arg_func_p = TRUE;
gen_mov (gen_ctx, anchor, MIR_MOV, _MIR_new_hard_reg_op (ctx, R8_HARD_REG),
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, 16, FP_HARD_REG, MIR_NON_HARD_REG, 1));
}
@ -758,8 +758,8 @@ static void target_machinize (gen_ctx_t gen_ctx) {
gen_mov (gen_ctx, anchor, new_insn_code, MIR_new_reg_op (ctx, i + 1), arg_reg_op);
} else {
/* arg is on the stack */
if (!stack_arg_func_p) {
stack_arg_func_p = TRUE;
if (!block_arg_func_p) {
block_arg_func_p = TRUE;
gen_mov (gen_ctx, anchor, MIR_MOV, _MIR_new_hard_reg_op (ctx, R8_HARD_REG),
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, 16, FP_HARD_REG, MIR_NON_HARD_REG, 1));
}
@ -799,29 +799,33 @@ static void target_machinize (gen_ctx_t gen_ctx) {
insn = new_insn;
}
if ((nargs = get_builtin (gen_ctx, code, &proto_item, &func_import_item)) > 0) {
if (code == MIR_VA_ARG) { /* do nothing */
/* Use a builtin func call:
mov func_reg, func ref; mov flag_reg, <type>; call proto, func_reg, res_reg, va_reg,
flag_reg */
MIR_op_t ops[5], func_reg_op, flag_reg_op;
MIR_op_t res_reg_op = insn->ops[0], va_reg_op = insn->ops[1], mem_op = insn->ops[2];
if (code == MIR_VA_ARG || code == MIR_VA_BLOCK_ARG) {
/* Use a builtin func call:
mov func_reg, func ref; [mov reg3, type;] call proto, func_reg, res_reg, va_reg,
reg3 */
MIR_op_t ops[6], func_reg_op, reg_op3;
MIR_op_t res_reg_op = insn->ops[0], va_reg_op = insn->ops[1], op3 = insn->ops[2];
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, func));
flag_reg_op = MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, func));
reg_op3 = MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, func));
next_insn = new_insn
= MIR_new_insn (ctx, MIR_MOV, func_reg_op, MIR_new_ref_op (ctx, func_import_item));
gen_add_insn_before (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;
new_insn = MIR_new_insn_arr (ctx, MIR_CALL, 5, ops);
ops[4] = op3;
if (code == MIR_VA_BLOCK_ARG) ops[5] = insn->ops[3];
new_insn = MIR_new_insn_arr (ctx, MIR_CALL, code == MIR_VA_ARG ? 5 : 6, ops);
gen_add_insn_before (gen_ctx, insn, new_insn);
gen_delete_insn (gen_ctx, insn);
} else { /* Use builtin: mov freg, func ref; call proto, freg, res_reg, op_reg[, op_reg2] */
@ -942,7 +946,7 @@ static void target_make_prolog_epilog (gen_ctx_t gen_ctx, bitmap_t used_hard_reg
saved_fregs_num++;
}
if (leaf_p && !alloca_p && saved_iregs_num == 0 && saved_fregs_num == 0 && !func->vararg_p
&& stack_slots_num == 0 && !stack_arg_func_p && small_aggregate_save_area == 0)
&& stack_slots_num == 0 && !block_arg_func_p && small_aggregate_save_area == 0)
return;
sp_reg_op = _MIR_new_hard_reg_op (ctx, SP_HARD_REG);
fp_reg_op = _MIR_new_hard_reg_op (ctx, FP_HARD_REG);
@ -962,7 +966,7 @@ static void target_make_prolog_epilog (gen_ctx_t gen_ctx, bitmap_t used_hard_reg
frame_size_after_saved_regs = frame_size;
frame_size += stack_slots_num * 8;
if (frame_size % 16 != 0) frame_size = (frame_size + 15) / 16 * 16;
save_prev_stack_p = func->vararg_p || stack_arg_func_p;
save_prev_stack_p = func->vararg_p || block_arg_func_p;
treg_op = _MIR_new_hard_reg_op (ctx, R9_HARD_REG);
if (save_prev_stack_p) { /* prev stack pointer */
gen_mov (gen_ctx, anchor, MIR_MOV, treg_op, sp_reg_op);

@ -138,7 +138,7 @@ DEF_VARR (label_ref_t);
DEF_VARR (MIR_code_reloc_t);
struct target_ctx {
unsigned char alloca_p, stack_arg_func_p, leaf_p, switch_p;
unsigned char alloca_p, block_arg_func_p, leaf_p, switch_p;
size_t param_save_area_size;
VARR (int) * pattern_indexes;
VARR (insn_pattern_info_t) * insn_pattern_info;
@ -149,7 +149,7 @@ struct target_ctx {
};
#define alloca_p gen_ctx->target_ctx->alloca_p
#define stack_arg_func_p gen_ctx->target_ctx->stack_arg_func_p
#define block_arg_func_p gen_ctx->target_ctx->block_arg_func_p
#define leaf_p gen_ctx->target_ctx->leaf_p
#define switch_p gen_ctx->target_ctx->switch_p
#define param_save_area_size gen_ctx->target_ctx->param_save_area_size
@ -262,12 +262,12 @@ 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
|| (arg_op.mode == MIR_OP_MEM && MIR_blk_type_p (arg_op.u.mem.type)));
|| (arg_op.mode == MIR_OP_MEM && MIR_all_blk_type_p (arg_op.u.mem.type)));
if (i - start < nargs) {
type = arg_vars[i - start].type;
} else if (call_insn->ops[i].mode == MIR_OP_MEM) {
type = arg_op.u.mem.type;
gen_assert (type == MIR_T_BLK || type == MIR_T_RBLK);
gen_assert (MIR_all_blk_type_p (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
@ -315,7 +315,7 @@ 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) {
} else if (MIR_blk_type_p (type)) {
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) {
@ -334,12 +334,12 @@ static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_insn) {
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);
if (type != MIR_T_RBLK) {
gen_mov (gen_ctx, call_insn, MIR_MOV, arg_reg_op, arg_op);
gen_mov (gen_ctx, call_insn, MIR_MOV, arg_reg_op, arg_op);
} else {
assert (arg_op.mode == MIR_OP_MEM);
gen_mov (gen_ctx, call_insn, MIR_MOV, arg_reg_op, MIR_new_reg_op (ctx, arg_op.u.mem.base));
arg_reg_op = _MIR_new_hard_reg_mem_op (ctx, MIR_T_RBLK, arg_op.u.mem.disp,
R3_HARD_REG + n_iregs, MIR_NON_HARD_REG, 1);
assert (arg_op.mode == MIR_OP_MEM);
gen_mov (gen_ctx, call_insn, MIR_MOV, arg_reg_op, MIR_new_reg_op (ctx, arg_op.u.mem.base));
arg_reg_op = _MIR_new_hard_reg_mem_op (ctx, MIR_T_RBLK, arg_op.u.mem.disp,
R3_HARD_REG + n_iregs, MIR_NON_HARD_REG, 1);
}
call_insn->ops[i] = arg_reg_op;
} else { /* put arguments on the stack */
@ -350,10 +350,11 @@ static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_insn) {
mem_op = _MIR_new_hard_reg_mem_op (ctx, mem_type, mem_size + PPC64_STACK_HEADER_SIZE,
SP_HARD_REG, MIR_NON_HARD_REG, 1);
if (type != MIR_T_RBLK) {
gen_mov (gen_ctx, call_insn, new_insn_code, mem_op, arg_op);
gen_mov (gen_ctx, call_insn, new_insn_code, mem_op, arg_op);
} else {
assert (arg_op.mode == MIR_OP_MEM);
gen_mov (gen_ctx, call_insn, new_insn_code, mem_op, MIR_new_reg_op (ctx, arg_op.u.mem.base));
assert (arg_op.mode == MIR_OP_MEM);
gen_mov (gen_ctx, call_insn, new_insn_code, mem_op,
MIR_new_reg_op (ctx, arg_op.u.mem.base));
}
call_insn->ops[i] = mem_op;
}
@ -444,8 +445,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 const char *VA_BLOCK_ARG_P = "mir.va_block_arg.p";
static const char *VA_BLOCK_ARG = "mir.va_block_arg";
static int64_t mir_ldeq (long double d1, long double d2) { return d1 == d2; }
static const char *LDEQ = "mir.ldeq";
@ -592,13 +593,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");
case MIR_VA_BLOCK_ARG:
*proto_item
= _MIR_builtin_proto (ctx, curr_func_item->module, VA_BLOCK_ARG_P, 0, NULL, 4, MIR_T_I64,
"res", MIR_T_I64, "va", MIR_T_I64, "size", MIR_T_I64, "ncase");
*func_import_item
= _MIR_builtin_func (ctx, curr_func_item->module, VA_STACK_ARG, va_stack_arg_builtin);
return 2;
= _MIR_builtin_func (ctx, curr_func_item->module, VA_BLOCK_ARG, va_block_arg_builtin);
return 4;
default: return 0;
}
}
@ -610,9 +611,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) {
if (!block_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;
block_arg_func_p = TRUE;
*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,
@ -632,7 +633,7 @@ static void target_machinize (gen_ctx_t gen_ctx) {
assert (curr_func_item->item_type == MIR_func_item);
func = curr_func_item->u.func;
stack_arg_func_p = FALSE;
block_arg_func_p = FALSE;
param_save_area_size = 0;
anchor = DLIST_HEAD (MIR_insn_t, func->insns);
if (func->vararg_p)
@ -661,7 +662,7 @@ static void target_machinize (gen_ctx_t gen_ctx) {
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, R12_HARD_REG, MIR_NON_HARD_REG, 1));
} else if (type == MIR_T_BLK) {
} else if (MIR_blk_type_p (type)) {
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);
@ -718,29 +719,33 @@ static void target_machinize (gen_ctx_t gen_ctx) {
insn = new_insn;
}
if ((nargs = get_builtin (gen_ctx, code, &proto_item, &func_import_item)) > 0) {
if (code == MIR_VA_ARG) {
/* Use a builtin func call:
mov func_reg, func ref; mov flag_reg, <type>; call proto, func_reg, res_reg, va_reg,
flag_reg */
MIR_op_t ops[5], func_reg_op, flag_reg_op;
MIR_op_t res_reg_op = insn->ops[0], va_reg_op = insn->ops[1], mem_op = insn->ops[2];
if (code == MIR_VA_ARG || code == MIR_VA_BLOCK_ARG) {
/* Use a builtin func call:
mov func_reg, func ref; [mov reg3, type;] call proto, func_reg, res_reg, va_reg,
reg3 */
MIR_op_t ops[6], func_reg_op, reg_op3;
MIR_op_t res_reg_op = insn->ops[0], va_reg_op = insn->ops[1], op3 = insn->ops[2];
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, func));
flag_reg_op = MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, func));
reg_op3 = MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, func));
next_insn = new_insn
= MIR_new_insn (ctx, MIR_MOV, func_reg_op, MIR_new_ref_op (ctx, func_import_item));
gen_add_insn_before (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;
new_insn = MIR_new_insn_arr (ctx, MIR_CALL, 5, ops);
ops[4] = op3;
if (code == MIR_VA_BLOCK_ARG) ops[5] = insn->ops[3];
new_insn = MIR_new_insn_arr (ctx, MIR_CALL, code == MIR_VA_ARG ? 5 : 6, ops);
gen_add_insn_before (gen_ctx, insn, new_insn);
gen_delete_insn (gen_ctx, insn);
} else { /* Use builtin: mov freg, func ref; call proto, freg, res_reg, op_reg[, op_reg2] */

@ -287,7 +287,7 @@ static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_insn) {
type = arg_vars[i - start].type;
} else if (arg_op.mode == MIR_OP_MEM) {
type = arg_op.u.mem.type;
gen_assert (type == MIR_T_BLK || type == MIR_T_RBLK);
gen_assert (MIR_all_blk_type_p (type));
} else {
mode = arg_op.value_mode; // ??? smaller ints
gen_assert (mode == MIR_OP_INT || mode == MIR_OP_UINT || mode == MIR_OP_FLOAT
@ -300,7 +300,7 @@ static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_insn) {
if (type != MIR_T_LD && i < start) continue;
if (type == MIR_T_LD)
call_blk_ld_value_area_size += 16;
else if (type == MIR_T_BLK) {
else if (MIR_blk_type_p (type)) {
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;
}
@ -321,14 +321,14 @@ static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_insn) {
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
|| (arg_op.mode == MIR_OP_MEM && MIR_blk_type_p (arg_op.u.mem.type)));
|| (arg_op.mode == MIR_OP_MEM && MIR_all_blk_type_p (arg_op.u.mem.type)));
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 = call_insn->ops[i].u.mem.type;
gen_assert (type == MIR_T_BLK || type == MIR_T_RBLK);
gen_assert (MIR_all_blk_type_p (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
@ -342,7 +342,7 @@ 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 || type == MIR_T_BLK) {
if (type == MIR_T_LD || MIR_blk_type_p (type)) {
if (i >= start) { /* put arg value in saved blk/ld value area: */
if (type == MIR_T_LD) {
mem_op
@ -490,8 +490,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 const char *VA_BLOCK_ARG_P = "mir.va_block_arg.p";
static const char *VA_BLOCK_ARG = "mir.va_block_arg";
static int64_t mir_ldeq (long double d1, long double d2) { return d1 == d2; }
static const char *LDEQ = "mir.ldeq";
@ -638,13 +638,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");
case MIR_VA_BLOCK_ARG:
*proto_item
= _MIR_builtin_proto (ctx, curr_func_item->module, VA_BLOCK_ARG_P, 0, NULL, 4, MIR_T_I64,
"res", MIR_T_I64, "va", MIR_T_I64, "size", MIR_T_I64, "ncase");
*func_import_item
= _MIR_builtin_func (ctx, curr_func_item->module, VA_STACK_ARG, va_stack_arg_builtin);
return 2;
= _MIR_builtin_func (ctx, curr_func_item->module, VA_BLOCK_ARG, va_block_arg_builtin);
return 4;
default: return 0;
}
}
@ -765,29 +765,33 @@ static void target_machinize (gen_ctx_t gen_ctx) {
insn = new_insn;
}
if ((nargs = get_builtin (gen_ctx, code, &proto_item, &func_import_item)) > 0) {
if (code == MIR_VA_ARG) {
/* Use a builtin func call:
mov func_reg, func ref; mov flag_reg, <type>; call proto, func_reg, res_reg, va_reg,
flag_reg */
MIR_op_t ops[5], func_reg_op, flag_reg_op;
MIR_op_t res_reg_op = insn->ops[0], va_reg_op = insn->ops[1], mem_op = insn->ops[2];
gen_assert (res_reg_op.mode == MIR_OP_REG && va_reg_op.mode == MIR_OP_REG
&& mem_op.mode == MIR_OP_MEM);
if (code == MIR_VA_ARG || code == MIR_VA_BLOCK_ARG) {
/* Use a builtin func call:
mov func_reg, func ref; [mov reg3, type;] call proto, func_reg, res_reg, va_reg,
reg3 */
MIR_op_t ops[6], func_reg_op, reg_op3;
MIR_op_t res_reg_op = insn->ops[0], va_reg_op = insn->ops[1], op3 = insn->ops[2];
assert (res_reg_op.mode == MIR_OP_REG && va_reg_op.mode == MIR_OP_REG
&& 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, func));
flag_reg_op = MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, func));
reg_op3 = MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, func));
next_insn = new_insn
= MIR_new_insn (ctx, MIR_MOV, func_reg_op, MIR_new_ref_op (ctx, func_import_item));
gen_add_insn_before (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;
new_insn = MIR_new_insn_arr (ctx, MIR_CALL, 5, ops);
ops[4] = op3;
if (code == MIR_VA_BLOCK_ARG) ops[5] = insn->ops[3];
new_insn = MIR_new_insn_arr (ctx, MIR_CALL, code == MIR_VA_ARG ? 5 : 6, ops);
gen_add_insn_before (gen_ctx, insn, new_insn);
gen_delete_insn (gen_ctx, insn);
} else { /* Use builtin: mov freg, func ref; call proto, freg, res_reg, op_reg[, op_reg2] */

@ -26,7 +26,7 @@ static inline MIR_reg_t target_nth_loc (MIR_reg_t loc, MIR_type_t type, int n) {
/* Hard regs not used in machinized code, preferably call used ones. */
const MIR_reg_t TEMP_INT_HARD_REG1 = R10_HARD_REG, TEMP_INT_HARD_REG2 = R11_HARD_REG;
#ifndef _WIN64
#ifndef _WIN32
const MIR_reg_t TEMP_FLOAT_HARD_REG1 = XMM8_HARD_REG, TEMP_FLOAT_HARD_REG2 = XMM9_HARD_REG;
const MIR_reg_t TEMP_DOUBLE_HARD_REG1 = XMM8_HARD_REG, TEMP_DOUBLE_HARD_REG2 = XMM9_HARD_REG;
#else
@ -55,7 +55,7 @@ static inline int target_fixed_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
#ifndef _WIN32
return !(hard_reg == BX_HARD_REG || (hard_reg >= R12_HARD_REG && hard_reg <= R15_HARD_REG));
#else
return !(hard_reg == BX_HARD_REG || hard_reg == SI_HARD_REG || hard_reg == DI_HARD_REG
@ -86,14 +86,14 @@ static inline int target_call_used_hard_reg_p (MIR_reg_t hard_reg, MIR_type_t ty
| slots for | dynamically allocated/deallocated by caller
| passing args |
|---------------|
| spill space | WIN64 only, 32 bytes spill space for register args
| spill space | WIN32 only, 32 bytes spill space for register args
|---------------|
size of slots and saved regs is multiple of 16 bytes
*/
#ifndef _WIN64
#ifndef _WIN32
static const int reg_save_area_size = 176;
static const int spill_space_size = 0;
#else
@ -136,7 +136,7 @@ static MIR_reg_t get_fp_arg_reg (size_t fp_arg_num) {
case 1:
case 2:
case 3:
#ifndef _WIN64
#ifndef _WIN32
case 4:
case 5:
case 6:
@ -149,13 +149,13 @@ static MIR_reg_t get_fp_arg_reg (size_t fp_arg_num) {
static MIR_reg_t get_int_arg_reg (size_t int_arg_num) {
switch (int_arg_num
#ifdef _WIN64
#ifdef _WIN32
+ 2
#endif
) {
case 0: return DI_HARD_REG;
case 1: return SI_HARD_REG;
#ifdef _WIN64
#ifdef _WIN32
case 2: return CX_HARD_REG;
case 3: return DX_HARD_REG;
#else
@ -168,6 +168,18 @@ static MIR_reg_t get_int_arg_reg (size_t int_arg_num) {
}
}
#ifdef _WIN32
static int get_int_arg_reg_num (MIR_reg_t arg_reg) {
switch (arg_reg) {
case CX_HARD_REG: return 0;
case DX_HARD_REG: return 1;
case R8_HARD_REG: return 2;
case R9_HARD_REG: return 3;
default: assert (FALSE); return 0;
}
}
#endif
static MIR_reg_t get_arg_reg (MIR_type_t arg_type, size_t *int_arg_num, size_t *fp_arg_num,
MIR_insn_code_t *mov_code) {
MIR_reg_t arg_reg;
@ -178,13 +190,13 @@ static MIR_reg_t get_arg_reg (MIR_type_t arg_type, size_t *int_arg_num, size_t *
} else if (arg_type == MIR_T_F || arg_type == MIR_T_D) {
arg_reg = get_fp_arg_reg (*fp_arg_num);
(*fp_arg_num)++;
#ifdef _WIN64
#ifdef _WIN32
(*int_arg_num)++; /* arg slot used by fp, skip int register */
#endif
*mov_code = arg_type == MIR_T_F ? MIR_FMOV : MIR_DMOV;
} else { /* including RBLK */
arg_reg = get_int_arg_reg (*int_arg_num);
#ifdef _WIN64
#ifdef _WIN32
(*fp_arg_num)++; /* arg slot used by int, skip fp register */
#endif
(*int_arg_num)++;
@ -193,12 +205,20 @@ static MIR_reg_t get_arg_reg (MIR_type_t arg_type, size_t *int_arg_num, size_t *
return arg_reg;
}
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 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, xmm_args = 0, mem_size = spill_space_size;
size_t size, nargs, nops = MIR_insn_nops (ctx, call_insn), start = proto->nres + 2;
size_t int_arg_num = 0, fp_arg_num = 0, xmm_args = 0, arg_stack_size = spill_space_size;
#ifdef _WIN32
size_t block_offset = spill_space_size;
#endif
MIR_type_t type, mem_type;
MIR_op_mode_t mode;
MIR_var_t *arg_vars = NULL;
@ -209,6 +229,7 @@ static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_insn) {
MIR_insn_t prev_call_insn = DLIST_PREV (MIR_insn_t, call_insn);
uint32_t n_iregs, n_xregs, n_fregs;
assert (prev_call_insn != NULL);
if (call_insn->code == MIR_INLINE) call_insn->code = MIR_CALL;
if (proto->args == NULL) {
nargs = 0;
@ -224,17 +245,20 @@ 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);
}
#ifdef _WIN32
if ((nops - start) > 4) block_offset = (nops - start) * 8;
#endif
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 && MIR_blk_type_p (arg_op.u.mem.type))
|| (arg_op.mode == MIR_OP_HARD_REG_MEM && MIR_blk_type_p (arg_op.u.hard_reg_mem.type)));
|| (arg_op.mode == MIR_OP_MEM && MIR_all_blk_type_p (arg_op.u.mem.type))
|| (arg_op.mode == MIR_OP_HARD_REG_MEM && MIR_all_blk_type_p (arg_op.u.hard_reg_mem.type)));
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 = arg_op.mode == MIR_OP_MEM ? arg_op.u.mem.type : arg_op.u.hard_reg_mem.type;
assert (type == MIR_T_BLK || type == MIR_T_RBLK);
assert (MIR_all_blk_type_p (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
@ -251,15 +275,74 @@ 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_BLK) { /* put block arg on the stack */
MIR_insn_t load_insn;
size_t size, disp;
int first_p;
size = 0;
if (MIR_blk_type_p (type)) {
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 <= 2 * 8) { /* upto 2 moves */
}
#ifndef _WIN32
if ((type == MIR_T_BLK2 && get_int_arg_reg (int_arg_num) != MIR_NON_HARD_REG
&& (size <= 8 || get_int_arg_reg (int_arg_num + 1) != MIR_NON_HARD_REG))
|| (type == MIR_T_BLK3 && get_fp_arg_reg (fp_arg_num) != MIR_NON_HARD_REG
&& (size <= 8 || get_fp_arg_reg (fp_arg_num + 1) != MIR_NON_HARD_REG))) {
/* all is passed in gprs or fprs */
MIR_type_t mov_type = type == MIR_T_BLK2 ? MIR_T_I64 : MIR_T_D;
MIR_insn_code_t mov_code;
MIR_reg_t reg2, reg1 = get_arg_reg (mov_type, &int_arg_num, &fp_arg_num, &mov_code);
assert (size <= 16);
new_insn = MIR_new_insn (ctx, mov_code, _MIR_new_hard_reg_op (ctx, reg1),
MIR_new_mem_op (ctx, mov_type, 0, arg_op.u.mem.base, 0, 1));
gen_add_insn_before (gen_ctx, call_insn, new_insn);
setup_call_hard_reg_args (gen_ctx, call_insn, reg1);
call_insn->ops[i].u.mem.base = 0; /* not used anymore */
if (size > 8) {
reg2 = get_arg_reg (mov_type, &int_arg_num, &fp_arg_num, &mov_code);
new_insn = MIR_new_insn (ctx, mov_code, _MIR_new_hard_reg_op (ctx, reg2),
MIR_new_mem_op (ctx, mov_type, 8, arg_op.u.mem.base, 0, 1));
gen_add_insn_before (gen_ctx, call_insn, new_insn);
setup_call_hard_reg_args (gen_ctx, call_insn, reg2);
}
continue;
} else if ((type == MIR_T_BLK4 || type == MIR_T_BLK5)
&& get_int_arg_reg (int_arg_num) != MIR_NON_HARD_REG
&& get_fp_arg_reg (fp_arg_num) != MIR_NON_HARD_REG) {
/* gpr and then fpr or fpr and then gpr */
MIR_type_t mov_type1 = type == MIR_T_BLK4 ? MIR_T_I64 : MIR_T_D;
MIR_type_t mov_type2 = type == MIR_T_BLK4 ? MIR_T_D : MIR_T_I64;
MIR_insn_code_t mov_code1, mov_code2;
MIR_reg_t reg1 = get_arg_reg (mov_type1, &int_arg_num, &fp_arg_num, &mov_code1);
MIR_reg_t reg2 = get_arg_reg (mov_type2, &int_arg_num, &fp_arg_num, &mov_code2);
assert (size > 8 && size <= 16);
new_insn = MIR_new_insn (ctx, mov_code1, _MIR_new_hard_reg_op (ctx, reg1),
MIR_new_mem_op (ctx, mov_type1, 0, arg_op.u.mem.base, 0, 1));
setup_call_hard_reg_args (gen_ctx, call_insn, reg1);
call_insn->ops[i].u.mem.base = 0; /* not used anymore */
gen_add_insn_before (gen_ctx, call_insn, new_insn);
new_insn = MIR_new_insn (ctx, mov_code2, _MIR_new_hard_reg_op (ctx, reg2),
MIR_new_mem_op (ctx, mov_type2, 8, arg_op.u.mem.base, 0, 1));
gen_add_insn_before (gen_ctx, call_insn, new_insn);
setup_call_hard_reg_args (gen_ctx, call_insn, reg2);
continue;
}
#endif
if (MIR_blk_type_p (type)) { /* put block arg on the stack */
MIR_insn_t load_insn;
size_t disp, dest_disp, start_dest_disp;
int first_p, by_val_p = FALSE;
#ifdef _WIN32
by_val_p = size <= 8;
#endif
if (by_val_p) {
temp_op = MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, func));
mem_op = MIR_new_mem_op (ctx, MIR_T_I64, 0, 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);
arg_op = temp_op;
} else if (size > 0 && size <= 2 * 8) { /* upto 2 moves */
disp = 0;
first_p = TRUE;
temp_op = MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, func));
@ -268,18 +351,32 @@ static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_insn) {
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);
#ifdef _WIN32
dest_disp = block_offset;
if (first_p) start_dest_disp = dest_disp;
block_offset += 8;
#else
dest_disp = arg_stack_size;
arg_stack_size += 8;
#endif
mem_op = _MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, dest_disp, 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);
call_insn->ops[i]
= _MIR_new_hard_reg_mem_op (ctx, type, dest_disp, SP_HARD_REG, MIR_NON_HARD_REG, 1);
first_p = FALSE;
}
}
#ifdef _WIN32
arg_op
= MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, curr_func_item->u.func));
new_insn = MIR_new_insn (ctx, MIR_ADD, arg_op, _MIR_new_hard_reg_op (ctx, SP_HARD_REG),
MIR_new_int_op (ctx, start_dest_disp));
gen_add_insn_before (gen_ctx, call_insn, new_insn);
#endif
} else { /* generate memcpy call before call arg moves */
MIR_reg_t dest_reg;
MIR_op_t freg_op, dest_reg_op, ops[5];
@ -305,14 +402,38 @@ static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_insn) {
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);
#ifdef _WIN32
start_dest_disp = block_offset;
block_offset += size;
#else
start_dest_disp = arg_stack_size;
arg_stack_size += size;
#endif
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));
MIR_new_int_op (ctx, start_dest_disp));
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;
#ifdef _WIN32
arg_op = dest_reg_op;
#endif
}
#ifdef _WIN32
if ((arg_reg = get_arg_reg (MIR_T_P, &int_arg_num, &fp_arg_num, &new_insn_code))
!= MIR_NON_HARD_REG) {
new_arg_op = _MIR_new_hard_reg_op (ctx, arg_reg);
new_insn = MIR_new_insn (ctx, MIR_MOV, new_arg_op, arg_op);
call_insn->ops[i] = new_arg_op;
} else {
mem_op = _MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, arg_stack_size, SP_HARD_REG,
MIR_NON_HARD_REG, 1);
new_insn = MIR_new_insn (ctx, MIR_MOV, mem_op, arg_op);
call_insn->ops[i] = mem_op;
arg_stack_size += 8;
}
gen_add_insn_before (gen_ctx, call_insn, new_insn);
#endif
} 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 */
@ -334,12 +455,12 @@ static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_insn) {
}
gen_add_insn_before (gen_ctx, call_insn, new_insn);
call_insn->ops[i] = new_arg_op;
#ifdef _WIN64
#ifdef _WIN32
/* copy fp reg varargs into corresponding int regs */
if (proto->vararg_p && type == MIR_T_D) {
gen_assert (int_arg_num > 0 && int_arg_num <= 4);
arg_reg = get_int_arg_reg (int_arg_num - 1);
setup_call_hard_reg_args (ctx, call_insn, arg_reg);
setup_call_hard_reg_args (gen_ctx, call_insn, arg_reg);
/* mir does not support moving fp to int regs directly, spill and load them instead */
mem_op = _MIR_new_hard_reg_mem_op (ctx, MIR_T_D, 8, SP_HARD_REG, MIR_NON_HARD_REG, 1);
new_insn = MIR_new_insn (ctx, MIR_DMOV, mem_op, arg_op);
@ -359,7 +480,8 @@ static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_insn) {
new_insn_code
= (type == MIR_T_F ? MIR_FMOV
: type == MIR_T_D ? MIR_DMOV : type == MIR_T_LD ? MIR_LDMOV : MIR_MOV);
mem_op = _MIR_new_hard_reg_mem_op (ctx, mem_type, mem_size, SP_HARD_REG, MIR_NON_HARD_REG, 1);
mem_op = _MIR_new_hard_reg_mem_op (ctx, mem_type, arg_stack_size, SP_HARD_REG,
MIR_NON_HARD_REG, 1);
new_insn = MIR_new_insn (ctx, new_insn_code, mem_op, arg_op);
gen_assert (prev_call_insn != NULL); /* call_insn should not be 1st after simplification */
MIR_insert_insn_after (ctx, curr_func_item, prev_call_insn, new_insn);
@ -367,11 +489,15 @@ static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_insn) {
next_insn = DLIST_NEXT (MIR_insn_t, new_insn);
create_new_bb_insns (gen_ctx, prev_insn, next_insn, call_insn);
call_insn->ops[i] = mem_op;
mem_size += type == MIR_T_LD ? 16 : 8;
#ifdef _WIN32
arg_stack_size += 8;
#else
arg_stack_size += type == MIR_T_LD ? 16 : 8;
#endif
if (ext_insn != NULL) gen_add_insn_after (gen_ctx, prev_call_insn, ext_insn);
}
}
#ifndef _WIN64
#ifndef _WIN32
if (proto->vararg_p) {
setup_call_hard_reg_args (gen_ctx, call_insn, AX_HARD_REG);
new_insn = MIR_new_insn (ctx, MIR_MOV, _MIR_new_hard_reg_op (ctx, AX_HARD_REG),
@ -420,17 +546,20 @@ static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_insn) {
}
create_new_bb_insns (gen_ctx, call_insn, DLIST_NEXT (MIR_insn_t, new_insn), call_insn);
}
if (mem_size != 0) { /* allocate/deallocate stack for args passed on stack */
mem_size = (mem_size + 15) / 16 * 16; /* make it of several 16 bytes */
new_insn
= MIR_new_insn (ctx, MIR_SUB, _MIR_new_hard_reg_op (ctx, SP_HARD_REG),
_MIR_new_hard_reg_op (ctx, SP_HARD_REG), MIR_new_int_op (ctx, mem_size));
#ifdef _WIN32
if (block_offset > arg_stack_size) arg_stack_size = block_offset;
#endif
if (arg_stack_size != 0) { /* allocate/deallocate stack for args passed on stack */
arg_stack_size = (arg_stack_size + 15) / 16 * 16; /* make it of several 16 bytes */
new_insn = MIR_new_insn (ctx, MIR_SUB, _MIR_new_hard_reg_op (ctx, SP_HARD_REG),
_MIR_new_hard_reg_op (ctx, SP_HARD_REG),
MIR_new_int_op (ctx, arg_stack_size));
MIR_insert_insn_after (ctx, curr_func_item, prev_call_insn, new_insn);
next_insn = DLIST_NEXT (MIR_insn_t, new_insn);
create_new_bb_insns (gen_ctx, prev_call_insn, next_insn, call_insn);
new_insn
= MIR_new_insn (ctx, MIR_ADD, _MIR_new_hard_reg_op (ctx, SP_HARD_REG),
_MIR_new_hard_reg_op (ctx, SP_HARD_REG), MIR_new_int_op (ctx, mem_size));
new_insn = MIR_new_insn (ctx, MIR_ADD, _MIR_new_hard_reg_op (ctx, SP_HARD_REG),
_MIR_new_hard_reg_op (ctx, SP_HARD_REG),
MIR_new_int_op (ctx, arg_stack_size));
MIR_insert_insn_after (ctx, curr_func_item, call_insn, new_insn);
next_insn = DLIST_NEXT (MIR_insn_t, new_insn);
create_new_bb_insns (gen_ctx, call_insn, next_insn, call_insn);
@ -452,8 +581,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 const char *VA_BLOCK_ARG_P = "mir.va_block_arg.p";
static const char *VA_BLOCK_ARG = "mir.va_block_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) {
@ -492,22 +621,17 @@ 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");
case MIR_VA_BLOCK_ARG:
*proto_item
= _MIR_builtin_proto (ctx, curr_func_item->module, VA_BLOCK_ARG_P, 0, NULL, 4, MIR_T_I64,
"res", MIR_T_I64, "va", MIR_T_I64, "size", MIR_T_I64, "ncase");
*func_import_item
= _MIR_builtin_func (ctx, curr_func_item->module, VA_STACK_ARG, va_stack_arg_builtin);
= _MIR_builtin_func (ctx, curr_func_item->module, VA_BLOCK_ARG, va_block_arg_builtin);
break;
default: assert (FALSE);
}
}
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);
@ -543,7 +667,7 @@ DEF_VARR (MIR_code_reloc_t);
#define MOVDQA_CODE 0
struct target_ctx {
unsigned char alloca_p, stack_arg_func_p, leaf_p;
unsigned char alloca_p, block_arg_func_p, leaf_p;
int start_sp_from_bp_offset;
VARR (int) * pattern_indexes;
VARR (insn_pattern_info_t) * insn_pattern_info;
@ -556,7 +680,7 @@ struct target_ctx {
};
#define alloca_p gen_ctx->target_ctx->alloca_p
#define stack_arg_func_p gen_ctx->target_ctx->stack_arg_func_p
#define block_arg_func_p gen_ctx->target_ctx->block_arg_func_p
#define leaf_p gen_ctx->target_ctx->leaf_p
#define start_sp_from_bp_offset gen_ctx->target_ctx->start_sp_from_bp_offset
#define pattern_indexes gen_ctx->target_ctx->pattern_indexes
@ -568,6 +692,11 @@ struct target_ctx {
#define abs_address_locs gen_ctx->target_ctx->abs_address_locs
#define relocs gen_ctx->target_ctx->relocs
static void prepend_insn (gen_ctx_t gen_ctx, MIR_insn_t new_insn) {
MIR_prepend_insn (gen_ctx->ctx, curr_func_item, new_insn);
create_new_bb_insns (gen_ctx, NULL, DLIST_NEXT (MIR_insn_t, new_insn), NULL);
}
static void target_machinize (gen_ctx_t gen_ctx) {
MIR_context_t ctx = gen_ctx->ctx;
MIR_func_t func;
@ -576,35 +705,109 @@ static void target_machinize (gen_ctx_t gen_ctx) {
MIR_insn_t insn, next_insn, new_insn;
MIR_reg_t ret_reg, arg_reg;
MIR_op_t ret_reg_op, arg_reg_op, mem_op;
size_t i, int_arg_num = 0, fp_arg_num = 0, mem_size = spill_space_size;
size_t i, blk_size, int_arg_num = 0, fp_arg_num = 0, mem_size = spill_space_size;
assert (curr_func_item->item_type == MIR_func_item);
func = curr_func_item->u.func;
stack_arg_func_p = FALSE;
block_arg_func_p = FALSE;
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|stack addr ... */
type = VARR_GET (MIR_var_t, func->vars, i).type;
if (type == MIR_T_BLK) {
stack_arg_func_p = TRUE;
blk_size = MIR_blk_type_p (type) ? (VARR_GET (MIR_var_t, func->vars, i).size + 7) / 8 * 8 : 0;
#ifndef _WIN32
if ((type == MIR_T_BLK2 && get_int_arg_reg (int_arg_num) != MIR_NON_HARD_REG
&& (blk_size <= 8 || get_int_arg_reg (int_arg_num + 1) != MIR_NON_HARD_REG))
|| (type == MIR_T_BLK3 && get_fp_arg_reg (fp_arg_num) != MIR_NON_HARD_REG
&& (blk_size <= 8 || get_fp_arg_reg (fp_arg_num + 1) != MIR_NON_HARD_REG))) {
/* all is passed in gprs or fprs */
MIR_type_t mov_type = type == MIR_T_BLK2 ? MIR_T_I64 : MIR_T_D;
MIR_insn_code_t mov_code1, mov_code2;
MIR_reg_t reg2, reg1 = get_arg_reg (mov_type, &int_arg_num, &fp_arg_num, &mov_code1);
assert (blk_size <= 16);
if (blk_size > 8) {
reg2 = get_arg_reg (mov_type, &int_arg_num, &fp_arg_num, &mov_code2);
new_insn = MIR_new_insn (ctx, mov_code1, MIR_new_mem_op (ctx, mov_type, 8, i + 1, 0, 1),
_MIR_new_hard_reg_op (ctx, reg2));
prepend_insn (gen_ctx, new_insn);
}
new_insn = MIR_new_insn (ctx, mov_code1, MIR_new_mem_op (ctx, mov_type, 0, i + 1, 0, 1),
_MIR_new_hard_reg_op (ctx, reg1));
prepend_insn (gen_ctx, new_insn);
new_insn = MIR_new_insn (ctx, MIR_ALLOCA, MIR_new_reg_op (ctx, i + 1),
MIR_new_int_op (ctx, blk_size));
prepend_insn (gen_ctx, new_insn);
continue;
} else if ((type == MIR_T_BLK4 || type == MIR_T_BLK5)
&& get_int_arg_reg (int_arg_num) != MIR_NON_HARD_REG
&& get_fp_arg_reg (fp_arg_num) != MIR_NON_HARD_REG) {
/* gpr and then fpr or fpr and then gpr */
MIR_type_t mov_type1 = type == MIR_T_BLK4 ? MIR_T_I64 : MIR_T_D;
MIR_type_t mov_type2 = type == MIR_T_BLK4 ? MIR_T_D : MIR_T_I64;
MIR_insn_code_t mov_code1, mov_code2;
MIR_reg_t reg1 = get_arg_reg (mov_type1, &int_arg_num, &fp_arg_num, &mov_code1);
MIR_reg_t reg2 = get_arg_reg (mov_type2, &int_arg_num, &fp_arg_num, &mov_code2);
assert (blk_size > 8 && blk_size <= 16);
new_insn = MIR_new_insn (ctx, mov_code2, MIR_new_mem_op (ctx, mov_type2, 8, i + 1, 0, 1),
_MIR_new_hard_reg_op (ctx, reg2));
prepend_insn (gen_ctx, new_insn);
new_insn = MIR_new_insn (ctx, mov_code1, MIR_new_mem_op (ctx, mov_type1, 0, i + 1, 0, 1),
_MIR_new_hard_reg_op (ctx, reg1));
prepend_insn (gen_ctx, new_insn);
new_insn = MIR_new_insn (ctx, MIR_ALLOCA, MIR_new_reg_op (ctx, i + 1),
MIR_new_int_op (ctx, blk_size));
prepend_insn (gen_ctx, new_insn);
continue;
}
#endif
int blk_p = MIR_blk_type_p (type);
#ifdef _WIN32
if (blk_p && blk_size > 8) { /* just address */
blk_p = FALSE;
type = MIR_T_I64;
}
#endif
if (blk_p) {
block_arg_func_p = TRUE;
#ifdef _WIN32
assert (blk_size <= 8);
if ((arg_reg = get_arg_reg (MIR_T_I64, &int_arg_num, &fp_arg_num, &new_insn_code))
== MIR_NON_HARD_REG) {
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));
mem_size += 8;
} else { /* put reg into spill space and use its address: prepend in reverse order: */
int disp = (mem_size + 8 /* ret */ + start_sp_from_bp_offset - spill_space_size
+ 8 * get_int_arg_reg_num (arg_reg));
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, disp));
prepend_insn (gen_ctx, new_insn);
arg_reg_op = _MIR_new_hard_reg_op (ctx, arg_reg);
mem_op = _MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, disp, FP_HARD_REG, MIR_NON_HARD_REG, 1);
new_insn = MIR_new_insn (ctx, MIR_MOV, mem_op, arg_reg_op);
}
#else
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 */
MIR_new_int_op (ctx, mem_size + 8 /* ret addr */
+ 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;
mem_size += blk_size;
#endif
prepend_insn (gen_ctx, new_insn);
} 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);
create_new_bb_insns (gen_ctx, NULL, DLIST_NEXT (MIR_insn_t, new_insn), NULL);
prepend_insn (gen_ctx, new_insn);
} else {
/* arg is on the stack */
stack_arg_func_p = TRUE;
block_arg_func_p = TRUE;
mem_type = type == MIR_T_F || type == MIR_T_D || type == MIR_T_LD ? type : MIR_T_I64;
new_insn_code
= (type == MIR_T_F ? MIR_FMOV
@ -614,9 +817,7 @@ static void target_machinize (gen_ctx_t gen_ctx) {
+ start_sp_from_bp_offset,
FP_HARD_REG, MIR_NON_HARD_REG, 1);
new_insn = MIR_new_insn (ctx, new_insn_code, MIR_new_reg_op (ctx, i + 1), mem_op);
MIR_prepend_insn (ctx, curr_func_item, new_insn);
next_insn = DLIST_NEXT (MIR_insn_t, new_insn);
create_new_bb_insns (gen_ctx, NULL, next_insn, NULL);
prepend_insn (gen_ctx, new_insn);
mem_size += type == MIR_T_LD ? 16 : 8;
}
}
@ -648,7 +849,7 @@ static void target_machinize (gen_ctx_t gen_ctx) {
= MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, curr_func_item->u.func));
MIR_op_t va_op = insn->ops[0];
MIR_reg_t va_reg;
#ifndef _WIN64
#ifndef _WIN32
int gp_offset = 0, fp_offset = 48, mem_offset = 0;
MIR_var_t var;
@ -660,7 +861,7 @@ static void target_machinize (gen_ctx_t gen_ctx) {
if (gp_offset >= 176) mem_offset += 8;
} else if (var.type == MIR_T_LD) {
mem_offset += 16;
} else if (var.type == MIR_T_BLK) {
} else if (MIR_blk_type_p (var.type)) {
mem_offset += var.size;
} else { /* including RBLK */
gp_offset += 8;
@ -687,17 +888,6 @@ static void target_machinize (gen_ctx_t gen_ctx) {
gen_add_insn_before (gen_ctx, insn, new_insn);
gen_mov (gen_ctx, insn, MIR_MOV, MIR_new_mem_op (ctx, MIR_T_I64, 16, va_reg, 0, 1), treg_op);
#else
stack_arg_func_p = TRUE;
/* spill reg args */
mem_size = 8 /*ret*/ + start_sp_from_bp_offset;
for (int i = 0; i < 4; i++) {
arg_reg = get_int_arg_reg (i);
mem_op
= _MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, mem_size, FP_HARD_REG, MIR_NON_HARD_REG, 1);
new_insn = MIR_new_insn (ctx, MIR_MOV, mem_op, _MIR_new_hard_reg_op (ctx, arg_reg));
gen_add_insn_before (gen_ctx, insn, new_insn);
mem_size += 8;
}
/* init va_list */
mem_size = 8 /*ret*/ + start_sp_from_bp_offset + func->nargs * 8;
new_insn = MIR_new_insn (ctx, MIR_ADD, treg_op, _MIR_new_hard_reg_op (ctx, FP_HARD_REG),
@ -709,21 +899,19 @@ 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 || code == MIR_VA_STACK_ARG) {
#ifndef _WIN64
} else if (code == MIR_VA_ARG || code == MIR_VA_BLOCK_ARG) {
/* Use a builtin func call:
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, reg_op3;
MIR_op_t ops[6], 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
&& 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));
reg_op3 = MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, curr_func_item->u.func));
func_reg_op = MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, func));
reg_op3 = MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, func));
next_insn = new_insn
= MIR_new_insn (ctx, MIR_MOV, func_reg_op, MIR_new_ref_op (ctx, func_import_item));
gen_add_insn_before (gen_ctx, insn, new_insn);
@ -738,23 +926,9 @@ static void target_machinize (gen_ctx_t gen_ctx) {
ops[2] = res_reg_op;
ops[3] = va_reg_op;
ops[4] = op3;
new_insn = MIR_new_insn_arr (ctx, MIR_CALL, 5, ops);
if (code == MIR_VA_BLOCK_ARG) ops[5] = insn->ops[3];
new_insn = MIR_new_insn_arr (ctx, MIR_CALL, code == MIR_VA_ARG ? 5 : 6, ops);
gen_add_insn_before (gen_ctx, insn, new_insn);
#else
MIR_op_t res_reg_op = insn->ops[0], va_reg_op = insn->ops[1], mem_op = insn->ops[2], treg_op;
assert (res_reg_op.mode == MIR_OP_REG && va_reg_op.mode == MIR_OP_REG
&& mem_op.mode == MIR_OP_MEM);
/* load and increment va pointer */
treg_op = MIR_new_reg_op (ctx, gen_new_temp_reg (gen_ctx, MIR_T_I64, curr_func_item->u.func));
gen_mov (gen_ctx, insn, MIR_MOV, treg_op,
MIR_new_mem_op (ctx, MIR_T_I64, 0, va_reg_op.u.reg, 0, 1));
new_insn = MIR_new_insn (ctx, MIR_MOV, res_reg_op, treg_op);
gen_add_insn_before (gen_ctx, insn, new_insn);
new_insn = MIR_new_insn (ctx, MIR_ADD, treg_op, treg_op, MIR_new_int_op (ctx, 8));
gen_add_insn_before (gen_ctx, insn, new_insn);
gen_mov (gen_ctx, insn, MIR_MOV, MIR_new_mem_op (ctx, MIR_T_I64, 0, va_reg_op.u.reg, 0, 1),
treg_op);
#endif
gen_delete_insn (gen_ctx, insn);
} else if (MIR_call_code_p (code)) {
machinize_call (gen_ctx, insn);
@ -766,7 +940,7 @@ static void target_machinize (gen_ctx_t gen_ctx) {
and added extension in return (if any). */
uint32_t n_iregs = 0, n_xregs = 0, n_fregs = 0;
#ifdef _WIN64
#ifdef _WIN32
if (curr_func_item->u.func->nres > 1)
(*MIR_get_error_func (ctx)) (MIR_ret_error,
"Windows x86-64 doesn't support multiple return values");
@ -870,18 +1044,18 @@ static void target_make_prolog_epilog (gen_ctx_t gen_ctx, bitmap_t used_hard_reg
for (i = saved_hard_regs_size = 0; i <= R15_HARD_REG; 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
#ifdef _WIN32
for (; i <= XMM15_HARD_REG; 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
if (leaf_p && !alloca_p && !block_arg_func_p && saved_hard_regs_size == 0 && !func->vararg_p
&& stack_slots_num == 0)
return;
anchor = DLIST_HEAD (MIR_insn_t, func->insns);
sp_reg_op = _MIR_new_hard_reg_op (ctx, SP_HARD_REG);
fp_reg_op = _MIR_new_hard_reg_op (ctx, FP_HARD_REG);
/* Prologue: */
anchor = DLIST_HEAD (MIR_insn_t, func->insns);
new_insn
= MIR_new_insn (ctx, MIR_MOV,
_MIR_new_hard_reg_mem_op (ctx, MIR_T_I64, -8, SP_HARD_REG, MIR_NON_HARD_REG, 1),
@ -890,6 +1064,14 @@ static void target_make_prolog_epilog (gen_ctx_t gen_ctx, bitmap_t used_hard_reg
/* Use add for matching LEA: */
new_insn = MIR_new_insn (ctx, MIR_ADD, fp_reg_op, sp_reg_op, MIR_new_int_op (ctx, -8));
gen_add_insn_before (gen_ctx, anchor, new_insn); /* bp = sp - 8 */
#ifdef _WIN32
if (func->vararg_p) { /* filling spill space */
for (i = 0, offset = 16 /* ret & bp */; i < 4; i++, offset += 8)
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, 1),
_MIR_new_hard_reg_op (ctx, get_int_arg_reg (i)));
}
#endif
service_area_size = func->vararg_p ? reg_save_area_size + 8 : 8;
stack_slots_size = stack_slots_num * 8;
/* stack slots, and saved regs as multiple of 16 bytes: */
@ -898,7 +1080,7 @@ static void target_make_prolog_epilog (gen_ctx_t gen_ctx, bitmap_t used_hard_reg
MIR_new_int_op (ctx, block_size + service_area_size));
gen_add_insn_before (gen_ctx, anchor, new_insn); /* sp -= block size + service_area_size */
bp_saved_reg_offset = block_size;
#ifndef _WIN64
#ifndef _WIN32
if (func->vararg_p) {
offset = block_size;
isave (gen_ctx, anchor, offset, DI_HARD_REG);
@ -920,7 +1102,7 @@ static void target_make_prolog_epilog (gen_ctx_t gen_ctx, bitmap_t used_hard_reg
#endif
/* Saving callee saved hard registers: */
offset = -bp_saved_reg_offset;
#ifdef _WIN64
#ifdef _WIN32
for (i = XMM0_HARD_REG; i <= XMM15_HARD_REG; 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),
@ -944,7 +1126,7 @@ static void target_make_prolog_epilog (gen_ctx_t gen_ctx, bitmap_t used_hard_reg
anchor = DLIST_TAIL (MIR_insn_t, func->insns);
/* Restoring hard registers: */
offset = -bp_saved_reg_offset;
#ifdef _WIN64
#ifdef _WIN32
for (i = XMM0_HARD_REG; i <= XMM15_HARD_REG; 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),

@ -1273,16 +1273,14 @@ static void build_func_cfg (gen_ctx_t gen_ctx) {
exit_bb = create_bb (gen_ctx, NULL);
add_bb (gen_ctx, exit_bb);
insn = DLIST_HEAD (MIR_insn_t, curr_func_item->u.func->insns);
if (insn != NULL) {
bb = create_bb (gen_ctx, NULL);
add_bb (gen_ctx, bb);
if (insn->code == MIR_LABEL) { /* Create one more BB. First BB will be empty. */
prev_bb = bb;
bb = create_bb (gen_ctx, NULL);
add_bb (gen_ctx, bb);
create_edge (gen_ctx, prev_bb, bb, TRUE);
}
}
if (insn == NULL || insn->code == MIR_LABEL || MIR_call_code_p (insn->code)) {
/* To deal with special cases like adding insns before call in
machinize or moving invariant out of loop: */
MIR_prepend_insn (ctx, curr_func_item, MIR_new_label (ctx));
insn = DLIST_HEAD (MIR_insn_t, curr_func_item->u.func->insns);
}
bb = create_bb (gen_ctx, NULL);
add_bb (gen_ctx, bb);
for (; insn != NULL; insn = next_insn) {
next_insn = DLIST_NEXT (MIR_insn_t, insn);
if (insn->data == NULL) {
@ -1666,7 +1664,7 @@ static void minimize_ssa (gen_ctx_t gen_ctx, size_t insns_num) {
} while (change_p);
DEBUG ({
fprintf (debug_file, "Minimizing SSA phis: from %ld to %ld phis (non-phi insns %ld)\n",
(long) VARR_LENGTH (bb_insn_t, deleted_phis) + VARR_LENGTH (bb_insn_t, phis),
(long) VARR_LENGTH (bb_insn_t, deleted_phis) + (long) VARR_LENGTH (bb_insn_t, phis),
(long) VARR_LENGTH (bb_insn_t, phis), (long) insns_num);
});
for (bb_t bb = DLIST_HEAD (bb_t, curr_cfg->bbs); bb != NULL; bb = DLIST_NEXT (bb_t, bb))
@ -1782,7 +1780,7 @@ static MIR_reg_t get_new_reg (gen_ctx_t gen_ctx, MIR_reg_t reg, size_t index) {
MIR_func_t func = curr_func_item->u.func;
MIR_type_t type = MIR_reg_type (ctx, reg, func);
const char *name = MIR_reg_name (ctx, reg, func);
char ind_str[20];
char ind_str[30];
MIR_reg_t new_reg;
VARR_TRUNC (char, reg_name, 0);
@ -2071,7 +2069,7 @@ static void copy_prop (gen_ctx_t gen_ctx) {
}
w = get_ext_params (insn->code, &sign_p);
if (w != 0 && insn->ops[1].mode == MIR_OP_REG && var_is_reg_p (insn->ops[1].u.reg)) {
se = insn->ops[op_num].data;
se = insn->ops[1].data;
def_insn = se->def->insn;
w2 = get_ext_params (def_insn->code, &sign2_p);
if (w2 != 0 && sign_p == sign2_p && w2 <= w
@ -2278,7 +2276,7 @@ static void gvn_modify (gen_ctx_t gen_ctx) {
for (bb_insn = DLIST_HEAD (bb_insn_t, bb->bb_insns); bb_insn != NULL; bb_insn = next_bb_insn) {
expr_t e, new_e;
MIR_op_t op;
int out_p, add_def_p;
int add_def_p;
MIR_type_t type;
MIR_insn_code_t move_code;
MIR_insn_t new_insn, def_insn, insn = bb_insn->insn;
@ -2310,6 +2308,7 @@ static void gvn_modify (gen_ctx_t gen_ctx) {
op = MIR_new_reg_op (ctx, temp_reg);
type = MIR_reg_type (ctx, temp_reg, curr_func_item->u.func);
#ifndef NDEBUG
int out_p;
MIR_insn_op_mode (ctx, insn, 0, &out_p); /* result here is always 0-th op */
gen_assert (out_p);
#endif
@ -3553,7 +3552,7 @@ static void print_live_ranges (gen_ctx_t gen_ctx) {
gen_assert (get_nvars (gen_ctx) == VARR_LENGTH (live_range_t, var_live_ranges));
for (size_t i = 0; i < VARR_LENGTH (live_range_t, var_live_ranges); i++) {
if ((lr = VARR_GET (live_range_t, var_live_ranges, i)) == NULL) continue;
fprintf (debug_file, "%lu", i);
fprintf (debug_file, "%lu", (unsigned long) i);
if (var_is_reg_p (i))
fprintf (debug_file, " (%s:%s)",
MIR_type_str (ctx, MIR_reg_type (ctx, var2reg (gen_ctx, i), curr_func_item->u.func)),
@ -4522,14 +4521,13 @@ static MIR_insn_t get_uptodate_def_insn (gen_ctx_t gen_ctx, int hr) {
static int combine_substitute (gen_ctx_t gen_ctx, bb_insn_t *bb_insn_ref) {
MIR_context_t ctx = gen_ctx->ctx;
MIR_insn_code_t code, new_code;
bb_insn_t bb_insn = *bb_insn_ref;
MIR_insn_t insn = bb_insn->insn, def_insn, new_insn;
MIR_insn_t insn = bb_insn->insn, def_insn;
size_t i, nops = insn->nops;
int out_p, insn_change_p, insn_hr_change_p, op_change_p, mem_reg_change_p, success_p;
MIR_op_t *op_ref, *src_op_ref, *src_op2_ref, saved_op;
MIR_reg_t hr, early_clobbered_hard_reg1, early_clobbered_hard_reg2;
int64_t scale, sh;
int64_t scale;
if (nops == 0) return FALSE;
VARR_TRUNC (MIR_op_t, last_right_ops, 0);
@ -4941,6 +4939,8 @@ static void combine (gen_ctx_t gen_ctx) {
setup_hreg_ref (gen_ctx, hr, insn, 0 /* whatever */, curr_insn_num, TRUE);
}
last_mem_ref_insn_num = curr_insn_num; /* Potentially call can change memory */
} else if (code == MIR_VA_BLOCK_ARG) {
last_mem_ref_insn_num = curr_insn_num; /* Change memory */
} else if (code == MIR_RET) {
/* ret is transformed in machinize and should be not modified after that */
} else if ((new_insn = combine_branch_and_cmp (gen_ctx, bb_insn)) != NULL
@ -4997,8 +4997,8 @@ static void combine (gen_ctx_t gen_ctx) {
} while (block_change_p);
}
DEBUG ({
fprintf (debug_file, " %lu deleted out of %lu (%.1f%%)\n", deleted_insns_num, insns_num,
100.0 * deleted_insns_num / insns_num);
fprintf (debug_file, " %lu deleted out of %lu (%.1f%%)\n", (long unsigned) deleted_insns_num,
(long unsigned) insns_num, 100.0 * deleted_insns_num / insns_num);
});
}
@ -5200,9 +5200,9 @@ static void print_code (gen_ctx_t gen_ctx, uint8_t *code, size_t code_len, void
fclose (bf);
sprintf (command,
"gcc -c -o %s.o %s 2>&1 && objcopy --update-section .text=%s %s.o && objdump "
"--adjust-vma=0x%lx -d %s.o; rm -f "
"--adjust-vma=0x%llx -d %s.o; rm -f "
"%s.o %s %s",
cfname, cfname, bfname, cfname, (unsigned long) start_addr, cfname, cfname, cfname,
cfname, cfname, bfname, cfname, (unsigned long long) start_addr, cfname, cfname, cfname,
bfname);
#endif
fprintf (stderr, "%s\n", command);
@ -5382,9 +5382,10 @@ void *MIR_gen (MIR_context_t ctx, int gen_num, MIR_item_t func_item) {
destroy_func_cfg (gen_ctx);
DEBUG ({
fprintf (debug_file,
"Generation of code for %s: %lu MIR insns (addr=%lx, len=%lu) -- time %.2f ms\n",
MIR_item_name (ctx, func_item), DLIST_LENGTH (MIR_insn_t, func_item->u.func->insns),
(unsigned long) machine_code, (unsigned long) code_len,
"Generation of code for %s: %lu MIR insns (addr=%llx, len=%lu) -- time %.2f ms\n",
MIR_item_name (ctx, func_item),
(long unsigned) DLIST_LENGTH (MIR_insn_t, func_item->u.func->insns),
(unsigned long long) machine_code, (unsigned long) code_len,
(real_usec_time () - start_time) / 1000.0);
});
_MIR_restore_func_insns (ctx, func_item);
@ -5481,7 +5482,6 @@ static void signal_threads_to_finish (struct all_gen_ctx *all_gen_ctx) {
void MIR_gen_init (MIR_context_t ctx, int gens_num) {
struct all_gen_ctx **all_gen_ctx_ptr = all_gen_ctx_loc (ctx), *all_gen_ctx;
gen_ctx_t gen_ctx;
MIR_reg_t reg;
#if !MIR_PARALLEL_GEN
gens_num = 1;

@ -116,13 +116,13 @@ DEF_VARR (htab_ind_t)
arg = htab->arg; \
if (htab->free_func != NULL) { \
els_addr = VARR_ADDR (HTAB_EL (T), htab->els); \
size = VARR_LENGTH (HTAB_EL (T), htab->els); \
size = (htab_size_t) VARR_LENGTH (HTAB_EL (T), htab->els); \
for (i = 0; i < htab->els_bound; i++) \
if (els_addr[i].hash != HTAB_DELETED_HASH) htab->free_func (els_addr[i].el, arg); \
} \
htab->els_num = htab->els_start = htab->els_bound = 0; \
addr = VARR_ADDR (htab_ind_t, htab->entries); \
size = VARR_LENGTH (htab_ind_t, htab->entries); \
size = (htab_size_t) VARR_LENGTH (htab_ind_t, htab->entries); \
for (i = 0; i < size; i++) addr[i] = HTAB_EMPTY_IND; \
} \
\
@ -145,8 +145,8 @@ DEF_VARR (htab_ind_t)
void *arg; \
\
HTAB_ASSERT (htab != NULL, "do htab", T); \
size = VARR_LENGTH (htab_ind_t, htab->entries); \
els_size = VARR_LENGTH (HTAB_EL (T), htab->els); \
size = (htab_size_t) VARR_LENGTH (htab_ind_t, htab->entries); \
els_size = (htab_size_t) VARR_LENGTH (HTAB_EL (T), htab->els); \
arg = htab->arg; \
HTAB_ASSERT (els_size * 2 == size, "do size", T); \
if ((action == HTAB_INSERT || action == HTAB_REPLACE) && htab->els_bound == els_size) { \

@ -413,7 +413,7 @@ static void generate_icode (MIR_context_t ctx, MIR_item_t func_item) {
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 (MIR_blk_type_p (ops[i].u.mem.type));
mir_assert (MIR_all_blk_type_p (ops[i].u.mem.type));
v.i = ops[i].u.mem.base;
update_max_nreg (v.i, &max_nreg);
} else {
@ -916,7 +916,7 @@ static void OPTIMIZE eval (MIR_context_t ctx, func_desc_t func_desc, MIR_val_t *
REP5 (LAB_EL, MIR_UBGE, MIR_UBGES, MIR_FBGE, MIR_DBGE, MIR_LDBGE);
REP4 (LAB_EL, MIR_CALL, MIR_INLINE, MIR_SWITCH, MIR_RET);
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);
REP4 (LAB_EL, MIR_VA_ARG, MIR_VA_BLOCK_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);
@ -1305,11 +1305,11 @@ 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) {
CASE (MIR_VA_BLOCK_ARG, 4) {
int64_t *r, va, size;
r = get_3iops (bp, ops, &va, &size);
*r = (uint64_t) va_stack_arg_builtin ((void *) va, size);
va_block_arg_builtin ((void *) *r, (void *) va, size, *get_iop (bp, ops + 3));
END_INSN;
}
SCASE (MIR_VA_START, 1, va_start_interp_builtin (ctx, bp[get_i (ops)].a, bp[-1].a));
@ -1379,7 +1379,7 @@ static htab_hash_t ff_interface_hash (ff_interface_t i, void *arg) {
h = mir_hash (i->res_types, sizeof (MIR_type_t) * i->nres, h);
for (size_t n = 0; n < i->nargs; n++) {
h = mir_hash_step (h, i->arg_descs[n].type);
if (MIR_blk_type_p (i->arg_descs[n].type)) h = mir_hash_step (h, i->arg_descs[n].size);
if (MIR_all_blk_type_p (i->arg_descs[n].type)) h = mir_hash_step (h, i->arg_descs[n].size);
}
return mir_hash_finish (h);
}
@ -1389,7 +1389,8 @@ static int ff_interface_eq (ff_interface_t i1, ff_interface_t i2, void *arg) {
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 (MIR_blk_type_p (i1->arg_descs[n].type) && i1->arg_descs[n].size != i2->arg_descs[n].size)
if (MIR_all_blk_type_p (i1->arg_descs[n].type)
&& i1->arg_descs[n].size != i2->arg_descs[n].size)
return FALSE;
}
return TRUE;
@ -1456,11 +1457,11 @@ static void call (MIR_context_t ctx, MIR_val_t *bp, MIR_op_t *insn_arg_ops, code
for (i = 0; i < nargs; i++) {
if (i < arg_vars_num) {
call_arg_descs[i].type = arg_vars[i].type;
if (MIR_blk_type_p (arg_vars[i].type)) call_arg_descs[i].size = arg_vars[i].size;
if (MIR_all_blk_type_p (arg_vars[i].type)) call_arg_descs[i].size = arg_vars[i].size;
continue;
}
if (insn_arg_ops[i].mode == MIR_OP_MEM) { /* (r)block arg */
mir_assert (MIR_blk_type_p (insn_arg_ops[i].u.mem.type));
mir_assert (MIR_all_blk_type_p (insn_arg_ops[i].u.mem.type));
call_arg_descs[i].type = insn_arg_ops[i].u.mem.type;
call_arg_descs[i].size = insn_arg_ops[i].u.mem.disp;
} else {
@ -1498,6 +1499,10 @@ static void call (MIR_context_t ctx, MIR_val_t *bp, MIR_op_t *insn_arg_ops, code
case MIR_T_LD: call_res_args[i + nres].ld = arg_vals[i].ld; break;
case MIR_T_P:
case MIR_T_BLK:
case MIR_T_BLK2:
case MIR_T_BLK3:
case MIR_T_BLK4:
case MIR_T_BLK5:
case MIR_T_RBLK: call_res_args[i + nres].u = (uint64_t) arg_vals[i].a; break;
default: mir_assert (FALSE);
}
@ -1675,12 +1680,18 @@ static void interp (MIR_context_t ctx, MIR_item_t func_item, va_list va, MIR_val
case MIR_T_P:
case MIR_T_RBLK: 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);
case MIR_T_BLK2:
case MIR_T_BLK3:
case MIR_T_BLK4:
case MIR_T_BLK5: {
arg_vals[i].a = alloca (arg_vars[i].size);
#if defined(__PPC64__) || defined(__aarch64__) || defined(_WIN32)
va_block_arg_builtin (arg_vals[i].a, &va, arg_vars[i].size, type - MIR_T_BLK);
#else
arg_vals[i].a = va_stack_arg_builtin (va, arg_vars[i].size);
va_block_arg_builtin (arg_vals[i].a, va, arg_vars[i].size, type - MIR_T_BLK);
#endif
break;
}
default: mir_assert (FALSE);
}
}

@ -2,7 +2,7 @@
Copyright (C) 2018-2020 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
/* BLK is passed in int regs, and if the regs are not enough, the rest is passed on the stack.
/* BLK..BLK5 is passed in int regs, and if the regs are not enough, the rest is passed on the stack.
RBLK is always passed by address. */
#define VA_LIST_IS_ARRAY_P 1 /* one element which is a pointer to args */
@ -17,10 +17,10 @@
#define PPC64_FUNC_DESC_LEN 24
#endif
static void ppc64_push_func_desc (VARR (uint8_t) ** insn_varr);
void (*ppc64_func_desc) (VARR (uint8_t) ** insn_varr) = ppc64_push_func_desc;
static void ppc64_push_func_desc (VARR (uint8_t) * *insn_varr);
void (*ppc64_func_desc) (VARR (uint8_t) * *insn_varr) = ppc64_push_func_desc;
static void ppc64_push_func_desc (VARR (uint8_t) ** insn_varr) {
static void ppc64_push_func_desc (VARR (uint8_t) * *insn_varr) {
VARR_CREATE (uint8_t, *insn_varr, 128);
for (int i = 0; i < PPC64_FUNC_DESC_LEN; i++)
VARR_PUSH (uint8_t, *insn_varr, ((uint8_t *) ppc64_func_desc)[i]);
@ -235,12 +235,11 @@ void *va_arg_builtin (void *p, uint64_t t) {
return a;
}
void *va_stack_arg_builtin (void *p, size_t s) {
void va_block_arg_builtin (void *res, void *p, size_t s, uint64_t ncase) {
struct ppc64_va_list *va = p;
void *a = va->arg_area;
memcpy (res, a, s);
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) {
@ -276,11 +275,13 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
VARR (uint8_t) * code;
ppc64_push_func_desc (&code);
for (uint32_t i = 0; i < nargs; i++)
if ((type = arg_descs[i].type) == MIR_T_BLK)
for (uint32_t i = 0; i < nargs; i++) {
type = arg_descs[i].type;
if (MIR_blk_type_p (type))
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 + 16; /* +local var to save res_reg and 15 */
if (frame_size % 16 != 0) frame_size += 8; /* align */
@ -333,7 +334,7 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
ppc64_gen_ld (code, 0, res_reg, param_offset + 8, type);
ppc64_gen_st (code, 0, 1, disp + 8, MIR_T_D);
}
} else if (type == MIR_T_BLK) {
} else if (MIR_blk_type_p (type)) {
qwords = (arg_descs[i].size + 7) / 8;
if (qwords > 0) ppc64_gen_ld (code, 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)
@ -419,11 +420,13 @@ void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handl
ppc64_gen_addi (code, va_reg, 1, PPC64_STACK_HEADER_SIZE);
} else {
ppc64_gen_mov (code, caller_r1, 1); /* caller frame r1 */
for (uint32_t i = 0; i < nargs; i++)
if ((type = arg_vars[i].type) == MIR_T_BLK)
for (uint32_t i = 0; i < nargs; i++) {
type = arg_vars[i].type;
if (MIR_blk_type_p (type))
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 */
@ -450,7 +453,7 @@ void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handl
ppc64_gen_st (code, 0, 1, disp + 8, MIR_T_D);
}
}
} else if (type == MIR_T_BLK) {
} else if (MIR_blk_type_p (type)) {
qwords = (arg_vars[i].size + 7) / 8;
for (; qwords > 0 && n_gpregs < 8; qwords--, n_gpregs++, disp += 8, param_offset += 8)
ppc64_gen_st (code, n_gpregs + 3, 1, disp, MIR_T_I64);

@ -4,7 +4,7 @@
/* Long doubles (-mlong-double=128) are always passed by its address (for args and results) */
/* BLK and RBLK args are always passed by address. */
/* BLK..BLK5 and RBLK args are always passed by address. */
#if 0 && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#error "s390x works only in BE mode"
@ -230,7 +230,9 @@ 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_block_arg_builtin (void *res, void *p, size_t s, uint64_t ncase) {
memcpy (res, *(void **) va_arg_builtin (p, MIR_T_I64), s);
}
void va_start_interp_builtin (MIR_context_t ctx, void *p, void *a) {
struct s390x_va_list *va = p;
@ -264,7 +266,7 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
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_descs[i].type;
if (type == MIR_T_BLK) frame_size += (arg_descs[i].size + 7) / 8; /* blk value space */
if (MIR_blk_type_p (type)) 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) { /* RBLK too */
@ -305,7 +307,7 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
s390x_gen_addi (code, 0, res_reg, param_offset); /* lay r0,param_offset(r7) */
s390x_gen_st (code, 0, 15, disp, MIR_T_I64); /* stg r0,disp(r15) */
disp += 8;
} else if (type == MIR_T_BLK) {
} else if (MIR_blk_type_p (type)) {
qwords = (arg_descs[i].size + 7) / 8;
addr_reg = n_gpregs < 5 ? n_gpregs + 2 : 8;
s390x_gen_blk_mov (code, param_offset, blk_offset, qwords, addr_reg);

@ -97,12 +97,12 @@ static inline void MIR_VARR_NO_RETURN mir_varr_error (const char *message) {
return varr->varr[varr->els_num - 1]; \
} \
\
static inline T VARR_OP_DEF (T, get) (const VARR (T) * varr, unsigned ix) { \
static inline T VARR_OP_DEF (T, get) (const VARR (T) * varr, size_t ix) { \
VARR_ASSERT (varr && varr->varr && ix < varr->els_num, "get", T); \
return varr->varr[ix]; \
} \
\
static inline T VARR_OP_DEF (T, set) (const VARR (T) * varr, unsigned ix, T obj) { \
static inline T VARR_OP_DEF (T, set) (const VARR (T) * varr, size_t ix, T obj) { \
T old_obj; \
VARR_ASSERT (varr && varr->varr && ix < varr->els_num, "set", T); \
old_obj = varr->varr[ix]; \

@ -2,7 +2,15 @@
Copyright (C) 2018-2020 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
/* BLK and RBLK args are always passed by address. BLK first is copied on the caller stack. */
/* RBLK args are always passed by address.
BLK first is copied on the caller stack and passed implicitly.
BLK2 is passed in general regs
BLK3 is passed in fp regs
BLK4 is passed in gpr and then fpr
BLK5 is passed in fpr and then gpr
If there are no enough regs, they work as BLK.
Windows: small BLKs (<= 8 bytes) are passed by value;
all other BLKs is always passed by pointer as regular int arg. */
#define VA_LIST_IS_ARRAY_P 1
@ -15,7 +23,7 @@ void *_MIR_get_bstart_builtin (MIR_context_t ctx) {
}
void *_MIR_get_bend_builtin (MIR_context_t ctx) {
static const uint8_t bend_code[] = {
#ifndef _WIN64
#ifndef _WIN32
0x48, 0x8b, 0x04, 0x24, /* rax = (rsp) */
0x48, 0x89, 0xfc, /* rsp = rdi */
0xff, 0xe0, /* jmp *rax */
@ -28,7 +36,7 @@ void *_MIR_get_bend_builtin (MIR_context_t ctx) {
return _MIR_publish_code (ctx, bend_code, sizeof (bend_code));
}
#ifndef _WIN64
#ifndef _WIN32
struct x86_64_va_list {
uint32_t gp_offset, fp_offset;
uint64_t *overflow_arg_area, *reg_save_area;
@ -53,12 +61,53 @@ void *va_arg_builtin (void *p, uint64_t t) {
return a;
}
void *va_stack_arg_builtin (void *p, size_t s) {
void va_block_arg_builtin (void *res, void *p, size_t s, uint64_t ncase) {
struct x86_64_va_list *va = p;
size_t size = ((s + 7) / 8) * 8;
void *a = va->overflow_arg_area;
va->overflow_arg_area += (s + sizeof (uint64_t) - 1) / sizeof (uint64_t);
return a;
union {
uint64_t i;
double d;
} u[2];
switch (ncase) {
case 1:
if (va->gp_offset + size > 48) break;
u[0].i = *(uint64_t *) ((char *) va->reg_save_area + va->gp_offset);
va->gp_offset += 8;
if (size > 8) {
u[1].i = *(uint64_t *) ((char *) va->reg_save_area + va->gp_offset);
va->gp_offset += 8;
}
memcpy (res, &u, s);
return;
case 2:
u[0].d = *(double *) ((char *) va->reg_save_area + va->fp_offset);
va->fp_offset += 16;
if (size > 8) {
u[1].d = *(double *) ((char *) va->reg_save_area + va->fp_offset);
va->fp_offset += 16;
}
memcpy (res, &u, s);
return;
case 3:
case 4:
if (va->fp_offset > 160 || va->gp_offset > 40) break;
if (ncase == 3) {
u[0].i = *(uint64_t *) ((char *) va->reg_save_area + va->gp_offset);
u[1].d = *(double *) ((char *) va->reg_save_area + va->fp_offset);
} else {
u[0].d = *(double *) ((char *) va->reg_save_area + va->fp_offset);
u[1].i = *(uint64_t *) ((char *) va->reg_save_area + va->gp_offset);
}
va->fp_offset += 8;
va->gp_offset += 8;
memcpy (res, &u, s);
return;
default: break;
}
memcpy (res, a, s);
va->overflow_arg_area += size / 8;
}
void va_start_interp_builtin (MIR_context_t ctx, void *p, void *a) {
@ -68,7 +117,9 @@ void va_start_interp_builtin (MIR_context_t ctx, void *p, void *a) {
assert (sizeof (struct x86_64_va_list) == sizeof (va_list));
*va = *(struct x86_64_va_list *) vap;
}
#else
struct x86_64_va_list {
uint64_t *arg_area;
};
@ -80,11 +131,11 @@ void *va_arg_builtin (void *p, uint64_t t) {
return a;
}
void *va_stack_arg_builtin (void *p, size_t s) {
void va_block_arg_builtin (void *res, void *p, size_t s, uint64_t ncase) {
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 *a = s <= 8 ? va->arg_area : *(void **) va->arg_area; /* pass by pointer */
memcpy (res, a, s);
va->arg_area++;
}
void va_start_interp_builtin (MIR_context_t ctx, void *p, void *a) {
@ -114,7 +165,7 @@ void _MIR_redirect_thunk (MIR_context_t ctx, void *thunk, void *to) {
}
static const uint8_t save_pat[] = {
#ifndef _WIN64
#ifndef _WIN32
0x48, 0x81, 0xec, 0x80, 0, 0, 0, /*sub $0x80,%rsp */
0xf3, 0x0f, 0x7f, 0x04, 0x24, /*movdqu %xmm0,(%rsp) */
0xf3, 0x0f, 0x7f, 0x4c, 0x24, 0x10, /*movdqu %xmm1,0x10(%rsp) */
@ -139,7 +190,7 @@ static const uint8_t save_pat[] = {
};
static const uint8_t restore_pat[] = {
#ifndef _WIN64
#ifndef _WIN32
0x5f, /*pop %rdi */
0x5e, /*pop %rsi */
0x5a, /*pop %rdx */
@ -183,6 +234,17 @@ static void gen_mov (VARR (uint8_t) * insn_varr, uint32_t offset, uint32_t reg,
addr[2] |= (reg & 7) << 3;
}
static void gen_mov2 (VARR (uint8_t) * insn_varr, uint32_t offset, uint32_t reg, int ld_p) {
static const uint8_t ld_gp_reg[] = {0x49, 0x8b, 0x44, 0x24, 0 /* mov <offset>(%r12),%reg */};
static const uint8_t st_gp_reg[] = {0x49, 0x89, 0x44, 0x24, 0 /* mov %reg,<offset>(%r12) */};
uint8_t *addr = push_insns (insn_varr, ld_p ? ld_gp_reg : st_gp_reg,
ld_p ? sizeof (ld_gp_reg) : sizeof (st_gp_reg));
addr[4] = offset;
assert (reg <= 15);
addr[0] |= (reg >> 1) & 4;
addr[2] |= (reg & 7) << 3;
}
static void gen_blk_mov (VARR (uint8_t) * insn_varr, uint32_t offset, uint32_t addr_offset,
uint32_t qwords) {
static const uint8_t blk_mov_pat[] = {
@ -216,19 +278,48 @@ static void gen_movxmm (VARR (uint8_t) * insn_varr, uint32_t offset, uint32_t re
if (b32_p) addr[0] |= 1;
}
static void gen_movxmm2 (VARR (uint8_t) * insn_varr, uint32_t offset, uint32_t reg, int ld_p) {
static const uint8_t ld_xmm_reg_pat[] = {
0xf2, 0x41, 0x0f, 0x10, 0x44, 0x24, 0 /* movsd <offset>(%r12),%xmm */
};
static const uint8_t st_xmm_reg_pat[] = {
0xf2, 0x41, 0x0f, 0x11, 0x44, 0x24, 0 /* movsd %xmm, <offset>(%r12) */
};
uint8_t *addr = push_insns (insn_varr, ld_p ? ld_xmm_reg_pat : st_xmm_reg_pat,
ld_p ? sizeof (ld_xmm_reg_pat) : sizeof (st_xmm_reg_pat));
addr[6] = offset;
assert (reg <= 7);
addr[4] |= reg << 3;
}
static void gen_add (VARR (uint8_t) * insn_varr, uint32_t sp_offset, int reg) {
static const uint8_t lea_pat[] = {
0x48, 0x8d, 0x84, 0x24, 0, 0, 0, 0, /* lea <sp_offset>(%sp),reg */
};
uint8_t *addr = push_insns (insn_varr, lea_pat, sizeof (lea_pat));
memcpy (addr + 4, &sp_offset, sizeof (uint32_t));
addr[2] |= (reg & 7) << 3;
if (reg > 7) addr[0] |= 4;
}
static void gen_st (VARR (uint8_t) * insn_varr, uint32_t sp_offset, int b64_p) {
static const uint8_t st_pat[] = {
0x44, 0x89, 0x94, 0x24, 0, 0, 0, 0, /* mov %r10,<sp_offset>(%sp) */
};
uint8_t *addr = push_insns (insn_varr, st_pat, sizeof (st_pat));
memcpy (addr + 4, &sp_offset, sizeof (uint32_t));
if (b64_p) addr[0] |= 8;
}
static void gen_ldst (VARR (uint8_t) * insn_varr, uint32_t sp_offset, uint32_t src_offset,
int b64_p) {
static const uint8_t ldst_pat[] = {
0x44, 0x8b, 0x93, 0, 0, 0, 0, /* mov <src_offset>(%rbx),%r10 */
0x44, 0x89, 0x94, 0x24, 0, 0, 0, 0, /* mov %r10,<sp_offset>(%sp) */
static const uint8_t ld_pat[] = {
0x44, 0x8b, 0x93, 0, 0, 0, 0, /* mov <src_offset>(%rbx),%r10 */
};
uint8_t *addr = push_insns (insn_varr, ldst_pat, sizeof (ldst_pat));
uint8_t *addr = push_insns (insn_varr, ld_pat, sizeof (ld_pat));
memcpy (addr + 3, &src_offset, sizeof (uint32_t));
memcpy (addr + 11, &sp_offset, sizeof (uint32_t));
if (b64_p) {
addr[0] |= 8;
addr[7] |= 8;
}
if (b64_p) addr[0] |= 8;
gen_st (insn_varr, sp_offset, b64_p);
}
static void gen_ldst80 (VARR (uint8_t) * insn_varr, uint32_t sp_offset, uint32_t src_offset) {
@ -249,6 +340,9 @@ static void gen_st80 (VARR (uint8_t) * insn_varr, uint32_t src_offset) {
/* Generation: fun (fun_addr, res_arg_addresses):
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]; arg_reg=mem[r12]
[;(arg_reg + 1)=mem[r12 + 8]]
...
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) ...
@ -258,7 +352,7 @@ static void gen_st80 (VARR (uint8_t) * insn_varr, uint32_t src_offset) {
void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, size_t nargs,
_MIR_arg_desc_t *arg_descs, int vararg_p) {
static const uint8_t prolog[] = {
#ifndef _WIN64
#ifndef _WIN32
0x41, 0x54, /* pushq %r12 */
0x53, /* pushq %rbx */
0x48, 0x81, 0xec, 0, 0, 0, 0, /* subq <sp_offset>, %rsp */
@ -273,7 +367,7 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
#endif
};
static const uint8_t call_end[] = {
#ifndef _WIN64
#ifndef _WIN32
0x48, 0xc7, 0xc0, 0x08, 0, 0, 0, /* mov $8, rax -- to save xmm varargs */
#endif
0x41, 0xff, 0xd3, /* callq *%r11 */
@ -284,14 +378,14 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
0x41, 0x5c, /* pop %r12 */
0xc3, /* ret */
};
#ifndef _WIN64
#ifndef _WIN32
static const uint8_t iregs[] = {7, 6, 2, 1, 8, 9}; /* rdi, rsi, rdx, rcx, r8, r9 */
static const uint32_t max_iregs = 6, max_xregs = 8;
uint32_t sp_offset = 0;
#else
static const uint8_t iregs[] = {1, 2, 8, 9}; /* rcx, rdx, r8, r9 */
static const uint32_t max_iregs = 4, max_xregs = 4;
uint32_t sp_offset = 32;
uint32_t blk_offset = nargs < 4 ? 32 : nargs * 8, sp_offset = 32; /* spill area */
#endif
uint32_t n_iregs = 0, n_xregs = 0, n_fregs, qwords;
uint8_t *addr;
@ -306,7 +400,7 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
if ((MIR_T_I8 <= type && type <= MIR_T_U64) || type == MIR_T_P || type == MIR_T_RBLK) {
if (n_iregs < max_iregs) {
gen_mov (code, (i + nres) * sizeof (long double), iregs[n_iregs++], TRUE);
#ifdef _WIN64
#ifdef _WIN32
n_xregs++;
#endif
} else {
@ -316,7 +410,7 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
} else if (type == MIR_T_F || type == MIR_T_D) {
if (n_xregs < max_xregs) {
gen_movxmm (code, (i + nres) * sizeof (long double), n_xregs++, type == MIR_T_F, TRUE);
#ifdef _WIN64
#ifdef _WIN32
gen_mov (code, (i + nres) * sizeof (long double), iregs[n_iregs++], TRUE);
#endif
} else {
@ -326,21 +420,84 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
} else if (type == MIR_T_LD) {
gen_ldst80 (code, sp_offset, (i + nres) * sizeof (long double));
sp_offset += 16;
} else if (type == MIR_T_BLK) {
} else if (MIR_blk_type_p (type)) {
qwords = (arg_descs[i].size + 7) / 8;
#ifndef _WIN32
if (type == MIR_T_BLK2 && n_iregs + qwords <= max_iregs) {
assert (qwords <= 2);
gen_mov (code, (i + nres) * sizeof (long double), 12, TRUE); /* r12 = block addr */
gen_mov2 (code, 0, iregs[n_iregs], TRUE); /* arg_reg = mem[r12] */
if (qwords == 2) gen_mov2 (code, 8, iregs[n_iregs + 1], TRUE); /* arg_reg = mem[r12 + 8] */
n_iregs += qwords;
n_xregs += qwords;
continue;
} else if (type == MIR_T_BLK3 && n_xregs + qwords <= max_xregs) {
assert (qwords <= 2);
gen_mov (code, (i + nres) * sizeof (long double), 12, TRUE); /* r12 = block addr */
gen_movxmm2 (code, 0, n_xregs, TRUE); /* xmm = mem[r12] */
if (qwords == 2) gen_movxmm2 (code, 8, n_xregs + 1, TRUE); /* xmm = mem[r12 + 8] */
n_xregs += qwords;
continue;
} else if (type == MIR_T_BLK4 && n_iregs < max_iregs && n_xregs < max_xregs) {
assert (qwords == 2);
gen_mov (code, (i + nres) * sizeof (long double), 12, TRUE); /* r12 = block addr */
gen_mov2 (code, 0, iregs[n_iregs], TRUE); /* arg_reg = mem[r12] */
n_iregs++;
n_xregs++;
gen_movxmm2 (code, 8, n_xregs, TRUE); /* xmm = mem[r12 + 8] */
n_xregs++;
continue;
} else if (type == MIR_T_BLK5 && n_iregs < max_iregs && n_xregs < max_xregs) {
assert (qwords == 2);
gen_mov (code, (i + nres) * sizeof (long double), 12, TRUE); /* r12 = block addr */
gen_movxmm2 (code, 0, n_xregs, TRUE); /* xmm = mem[r12] */
n_xregs++;
gen_mov2 (code, 8, iregs[n_iregs], TRUE); /* arg_reg = mem[r12 + 8] */
n_iregs++;
n_xregs++;
continue;
}
gen_blk_mov (code, sp_offset, (i + nres) * sizeof (long double), qwords);
sp_offset += qwords * 8;
#else
if (qwords <= 1) {
gen_mov (code, (i + nres) * sizeof (long double), 12, TRUE); /* r12 = mem[disp + rbx] */
if (n_iregs < max_iregs) {
gen_mov2 (code, 0, iregs[n_iregs++], TRUE); /* arg_reg = mem[r12] */
n_xregs++;
} else {
gen_mov2 (code, 0, 10, TRUE); /* r10 = mem[r12] */
gen_st (code, sp_offset, TRUE); /* mem[sp+sp_offset] = r10; */
sp_offset += 8;
}
} else {
/* r12 = mem[disp + rbx]; mem[rsp+blk_offset + nw] = r10 = mem[r12 + nw]; */
gen_blk_mov (code, blk_offset, (i + nres) * sizeof (long double), qwords);
if (n_iregs < max_iregs) {
gen_add (code, blk_offset, iregs[n_iregs++]); /* arg_reg = sp + blk_offset */
n_xregs++;
} else {
gen_add (code, blk_offset, 10); /* r10 = sp + blk_offset */
gen_st (code, sp_offset, TRUE); /* mem[sp+sp_offset] = r10; */
sp_offset += 8;
}
blk_offset += qwords * 8;
}
#endif
} else {
MIR_get_error_func (ctx) (MIR_call_op_error, "wrong type of arg value");
}
}
#ifdef _WIN32
if (blk_offset > sp_offset) sp_offset = blk_offset;
#endif
sp_offset = (sp_offset + 15) / 16 * 16;
sp_offset += 8;
addr = VARR_ADDR (uint8_t, code);
memcpy (addr + 6, &sp_offset, sizeof (uint32_t));
addr = push_insns (code, call_end, sizeof (call_end));
memcpy (addr + sizeof (call_end) - 4, &sp_offset, sizeof (uint32_t));
#ifdef _WIN64
#ifdef _WIN32
if (nres > 1)
MIR_get_error_func (ctx) (MIR_call_op_error,
"Windows x86-64 doesn't support multiple return values");
@ -370,7 +527,7 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handler) {
static const uint8_t push_rbx[] = {0x53, /*push %rbx */};
static const uint8_t prepare_pat[] = {
#ifndef _WIN64
#ifndef _WIN32
/* 0: */ 0x48, 0x83, 0xec, 0x20, /* sub 32,%rsp */
/* 4: */ 0x48, 0x89, 0xe2, /* mov %rsp,%rdx */
/* 7: */ 0xc7, 0x02, 0, 0, 0, 0, /* movl 0,(%rdx) */
@ -430,7 +587,7 @@ void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handl
void *res;
VARR_CREATE (uint8_t, code, 128);
#ifndef _WIN64
#ifndef _WIN32
push_insns (code, push_rbx, sizeof (push_rbx));
#endif
push_insns (code, save_pat, sizeof (save_pat));
@ -441,7 +598,7 @@ void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handl
memcpy (addr + func_offset, &func_item, sizeof (void *));
memcpy (addr + hndl_offset, &handler, sizeof (void *));
/* move results: */
#ifdef _WIN64
#ifdef _WIN32
if (nres > 1)
MIR_get_error_func (ctx) (MIR_call_op_error,
"Windows x86-64 doesn't support multiple return values");
@ -487,13 +644,13 @@ void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handl
void *_MIR_get_wrapper (MIR_context_t ctx, MIR_item_t called_func, void *hook_address) {
static const uint8_t push_rax[] = {0x50, /*push %rax */};
static const uint8_t wrap_end[] = {
#ifndef _WIN64
#ifndef _WIN32
0x58, /*pop %rax */
#endif
0x41, 0xff, 0xe2, /*jmpq *%r10 */
};
static const uint8_t call_pat[] = {
#ifndef _WIN64
#ifndef _WIN32
0x48, 0xbe, 0, 0, 0, 0, 0, 0, 0, 0, /*movabs called_func,%rsi */
0x48, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, /*movabs ctx,%rdi */
0x49, 0xba, 0, 0, 0, 0, 0, 0, 0, 0, /*movabs <hook_address>,%r10 */
@ -516,7 +673,7 @@ void *_MIR_get_wrapper (MIR_context_t ctx, MIR_item_t called_func, void *hook_ad
void *res;
VARR_CREATE (uint8_t, code, 128);
#ifndef _WIN64
#ifndef _WIN32
push_insns (code, push_rax, sizeof (push_rax));
#endif
push_insns (code, save_pat, sizeof (save_pat));

@ -128,10 +128,10 @@ int _MIR_reserved_name_p (MIR_context_t ctx, const char *name) {
struct insn_desc {
MIR_insn_code_t code;
const char *name;
unsigned op_modes[4];
unsigned char op_modes[5];
};
#define OUTPUT_FLAG (1 << 30)
#define OUTPUT_FLAG (1 << 7)
static const struct insn_desc insn_descs[] = {
{MIR_MOV, "mov", {MIR_OP_INT | OUTPUT_FLAG, MIR_OP_INT, MIR_OP_BOUND}},
@ -299,9 +299,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_BLOCK_ARG,
"va_block_arg",
{MIR_OP_INT, MIR_OP_INT, 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}},
@ -523,7 +523,7 @@ const char *MIR_item_name (MIR_context_t ctx, MIR_item_t item) {
case MIR_data_item: return item->u.data->name;
case MIR_ref_data_item: return item->u.ref_data->name;
case MIR_expr_data_item: return item->u.expr_data->name;
default: mir_assert (FALSE);
default: mir_assert (FALSE); return NULL;
}
}
@ -596,6 +596,7 @@ static void parallel_error (MIR_context_t ctx, const char *err_message) {
MIR_context_t MIR_init (void) {
MIR_context_t ctx;
mir_assert (MIR_OP_BOUND < OUTPUT_FLAG);
if ((ctx = malloc (sizeof (struct MIR_context))) == NULL)
default_error (MIR_alloc_error, "Not enough memory for ctx");
ctx->string_ctx = NULL;
@ -777,6 +778,10 @@ static const char *type_str (MIR_type_t tp) {
case MIR_T_LD: return "ld";
case MIR_T_P: return "p";
case MIR_T_BLK: return "blk";
case MIR_T_BLK2: return "blk2";
case MIR_T_BLK3: return "blk3";
case MIR_T_BLK4: return "blk4";
case MIR_T_BLK5: return "blk5";
case MIR_T_RBLK: return "rblk";
case MIR_T_UNDEF: return "undef";
default: return "";
@ -960,7 +965,7 @@ MIR_item_t MIR_new_bss (MIR_context_t ctx, const char *name, size_t len) {
}
static MIR_type_t canon_type (MIR_type_t type) {
#if __SIZEOF_LONG_DOUBLE__ == 8
#if defined(_WIN32) || __SIZEOF_LONG_DOUBLE__ == 8
if (type == MIR_T_LD) type = MIR_T_D;
#endif
return type;
@ -1381,13 +1386,13 @@ void MIR_finish_func (MIR_context_t ctx) {
case MIR_OP_MEM:
expr_p = FALSE;
if (wrong_type_p (insn->ops[i].u.mem.type)
&& (!MIR_blk_type_p (insn->ops[i].u.mem.type) || !MIR_call_code_p (code))) {
&& (!MIR_all_blk_type_p (insn->ops[i].u.mem.type) || !MIR_call_code_p (code))) {
curr_func = NULL;
MIR_get_error_func (ctx) (MIR_wrong_type_error,
"func %s: in instruction '%s': wrong type memory", func_name,
insn_descs[code].name);
}
if (MIR_blk_type_p (insn->ops[i].u.mem.type) && insn->ops[i].u.mem.disp < 0) {
if (MIR_all_blk_type_p (insn->ops[i].u.mem.type) && insn->ops[i].u.mem.disp < 0) {
curr_func = NULL;
MIR_get_error_func (ctx) (MIR_wrong_type_error,
"func %s: in instruction '%s': block type memory with disp < 0",
@ -1434,7 +1439,7 @@ 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 || code == MIR_VA_STACK_ARG) && i == 1)
|| ((code == MIR_VA_ARG || code == MIR_VA_BLOCK_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
@ -1787,7 +1792,7 @@ static MIR_insn_t create_insn (MIR_context_t ctx, size_t nops, MIR_insn_code_t c
insn = malloc (sizeof (struct MIR_insn) + sizeof (MIR_op_t) * (nops - 1));
if (insn == NULL)
MIR_get_error_func (ctx) (MIR_alloc_error, "Not enough memory for insn creation");
#if __SIZEOF_LONG_DOUBLE__ == 8
#if defined(_WIN32) || __SIZEOF_LONG_DOUBLE__ == 8
switch (code) {
case MIR_LDMOV: code = MIR_DMOV; break;
case MIR_I2LD: code = MIR_I2D; break;
@ -1863,7 +1868,7 @@ MIR_insn_t MIR_new_insn_arr (MIR_context_t ctx, MIR_insn_code_t code, size_t nop
"number of %s operands or results does not correspond to prototype %s",
code == MIR_UNSPEC ? "unspec" : "call", proto->name);
for (i = args_start; i < nops; i++) {
if (ops[i].mode == MIR_OP_MEM && MIR_blk_type_p (ops[i].u.mem.type)) {
if (ops[i].mode == MIR_OP_MEM && MIR_all_blk_type_p (ops[i].u.mem.type)) {
if (i - args_start < proto->nres)
MIR_get_error_func (ctx) (MIR_wrong_type_error, "result of %s is block type memory",
code == MIR_UNSPEC ? "unspec" : "call");
@ -1887,7 +1892,7 @@ MIR_insn_t MIR_new_insn_arr (MIR_context_t ctx, MIR_insn_code_t code, size_t nop
}
} else if (i - args_start >= proto->nres
&& (narg = i - args_start - proto->nres) < VARR_LENGTH (MIR_var_t, proto->args)
&& MIR_blk_type_p (VARR_GET (MIR_var_t, proto->args, narg).type)) {
&& MIR_all_blk_type_p (VARR_GET (MIR_var_t, proto->args, narg).type)) {
MIR_get_error_func (
ctx) (MIR_wrong_type_error,
"param of %s is of block type but arg is not of block type memory",
@ -2093,7 +2098,7 @@ MIR_op_t MIR_new_double_op (MIR_context_t ctx, double d) {
MIR_op_t MIR_new_ldouble_op (MIR_context_t ctx, long double ld) {
MIR_op_t op;
#if __SIZEOF_LONG_DOUBLE__ == 8
#if defined(_WIN32) || __SIZEOF_LONG_DOUBLE__ == 8
return MIR_new_double_op (ctx, ld);
#endif
mir_assert (sizeof (long double) == 16); /* machine-defined 80- or 128-bit FP */
@ -2382,7 +2387,6 @@ void MIR_change_module_ctx (MIR_context_t old_ctx, MIR_module_t m, MIR_context_t
if (item->item_type == MIR_proto_item) {
change_var_names (new_ctx, item->u.proto->args);
} else if (item->item_type == MIR_func_item) {
func_regs_t func_regs = item->u.func->internal;
change_var_names (new_ctx, item->u.func->vars);
for (MIR_insn_t insn = DLIST_HEAD (MIR_insn_t, item->u.func->insns); insn != NULL;
insn = DLIST_NEXT (MIR_insn_t, insn))
@ -2519,7 +2523,7 @@ 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);
if (!MIR_blk_type_p (var.type))
if (!MIR_all_blk_type_p (var.type))
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);
@ -2904,11 +2908,11 @@ void MIR_simplify_op (MIR_context_t ctx, MIR_item_t func_item, MIR_insn_t insn,
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 || code == MIR_VA_STACK_ARG) && nop == 1)
|| ((code == MIR_VA_ARG || code == MIR_VA_BLOCK_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 if (!MIR_blk_type_p (mem_op.u.mem.type) || !MIR_call_code_p (code)) {
} else if (!MIR_all_blk_type_p (mem_op.u.mem.type) || !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
@ -3374,8 +3378,8 @@ static void process_inlines (MIR_context_t ctx, MIR_item_t func_item) {
if (i < nargs && call->nops > i + 2 + called_func->nres) { /* Parameter passing */
MIR_op_t op = call->ops[i + 2 + called_func->nres];
mir_assert (!MIR_blk_type_p (type) || (op.mode == MIR_OP_MEM && type == MIR_T_I64));
if (var.type == MIR_T_BLK) { /* alloca and block move: */
mir_assert (!MIR_all_blk_type_p (type) || (op.mode == MIR_OP_MEM && type == MIR_T_I64));
if (MIR_blk_type_p (var.type)) { /* alloca and block move: */
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 {
@ -3786,7 +3790,8 @@ typedef enum {
REP3 (TAG_EL, MEM_DISP_INDEX, MEM_BASE_INDEX, MEM_DISP_BASE_INDEX),
/* MIR types. The same order as MIR types: */
REP8 (TAG_EL, TI8, TU8, TI16, TU16, TI32, TU32, TI64, TU64),
REP7 (TAG_EL, TF, TD, TP, TV, TBLOCK, TRBLOCK, EOI),
REP8 (TAG_EL, TF, TD, TP, TV, TBLOCK, TBLOCK2, TBLOCK3, TBLOCK4),
REP3 (TAG_EL, TBLOCK5, TRBLOCK, EOI),
TAG_EL (EOFILE), /* end of insn with variable number operands (e.g. a call) or end of file */
/* unsigned integer 0..127 is kept in one byte. The most significant bit of the byte is 1: */
U0_MASK = 0x7f,
@ -4199,7 +4204,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 (MIR_blk_type_p (var.type)) len += write_uint (ctx, writer, var.size);
if (MIR_all_blk_type_p (var.type)) len += write_uint (ctx, writer, var.size);
}
len += put_byte (ctx, writer, TAG_EOI);
return len;
@ -4214,7 +4219,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 (MIR_blk_type_p (var.type)) len += write_uint (ctx, writer, var.size);
if (MIR_all_blk_type_p (var.type)) len += write_uint (ctx, writer, var.size);
}
len += put_byte (ctx, writer, TAG_EOI);
nlocals = VARR_LENGTH (MIR_var_t, func->vars) - func->nargs;
@ -4510,7 +4515,8 @@ static bin_tag_t read_token (MIR_context_t ctx, token_attr_t *attr) {
REP3 (TAG_CASE, MEM_DISP_BASE_INDEX, EOI, EOFILE)
break;
REP8 (TAG_CASE, TI8, TU8, TI16, TU16, TI32, TU32, TI64, TU64)
REP6 (TAG_CASE, TF, TD, TP, TV, TBLOCK, TRBLOCK)
REP8 (TAG_CASE, TF, TD, TP, TV, TBLOCK, TBLOCK2, TBLOCK3, TBLOCK4)
REP2 (TAG_CASE, TBLOCK5, TRBLOCK)
attr->t = (MIR_type_t) (c - TAG_TI8) + MIR_T_I8;
break;
default: MIR_get_error_func (ctx) (MIR_binary_io_error, "wrong tag %d", c);
@ -4629,7 +4635,7 @@ static int func_proto_read (MIR_context_t ctx, MIR_module_t module, uint64_t *nr
MIR_get_error_func (ctx) (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 (MIR_blk_type_p (var.type)) var.size = read_uint (ctx, "wrong block arg size");
if (MIR_all_blk_type_p (var.type)) var.size = read_uint (ctx, "wrong block arg size");
VARR_PUSH (MIR_var_t, proto_vars, var);
}
*nres_ptr = nres;
@ -5038,7 +5044,7 @@ typedef struct label_desc {
DEF_HTAB (label_desc_t);
struct scan_ctx {
jmp_buf error_jmp_buf;
jmp_buf error_jmp_buf; /* keep it here to provide malloc alignment */
VARR (char) * error_msg_buf;
VARR (MIR_var_t) * scan_vars;
VARR (MIR_type_t) * scan_types;
@ -5152,7 +5158,7 @@ static void scan_number (MIR_context_t ctx, int ch, int get_char (MIR_context_t)
*double_p = FALSE;
ch = get_char (ctx);
} else if (ch == 'l' || ch == 'L') {
#if __SIZEOF_LONG_DOUBLE__ != 8
#if !defined(_WIN32) && __SIZEOF_LONG_DOUBLE__ != 8
*ldouble_p = TRUE;
*double_p = FALSE;
#endif
@ -5377,7 +5383,7 @@ static void read_func_proto (MIR_context_t ctx, size_t nops, MIR_op_t *ops) {
var.name = (const char *) ops[i].u.mem.disp;
if (var.name == NULL)
scan_error (ctx, "all func/prototype args should have form type:name or (r)blk:size(name)");
if (MIR_blk_type_p (var.type)) var.size = ops[i].u.mem.base;
if (MIR_all_blk_type_p (var.type)) var.size = ops[i].u.mem.base;
VARR_PUSH (MIR_var_t, scan_vars, var);
}
}
@ -5396,6 +5402,10 @@ static MIR_type_t str2type (const char *type_name) {
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;
if (strcmp (type_name, "blk2") == 0) return MIR_T_BLK2;
if (strcmp (type_name, "blk3") == 0) return MIR_T_BLK3;
if (strcmp (type_name, "blk4") == 0) return MIR_T_BLK4;
if (strcmp (type_name, "blk5") == 0) return MIR_T_BLK5;
if (strcmp (type_name, "rblk") == 0) return MIR_T_RBLK;
return MIR_T_BOUND;
}
@ -5583,7 +5593,7 @@ void MIR_scan_string (MIR_context_t ctx, const char *str) {
scan_token (ctx, &t, get_string_char, unget_string_char);
if (t.code == TC_NAME) {
op.u.mem.disp = (MIR_disp_t) t.u.name;
} else if (local_p || t.code != TC_INT || !MIR_blk_type_p (type)) {
} else if (local_p || t.code != TC_INT || !MIR_all_blk_type_p (type)) {
scan_error (ctx, local_p ? "wrong var" : "wrong arg");
} else {
op.u.mem.base = t.u.i;
@ -5645,7 +5655,7 @@ void MIR_scan_string (MIR_context_t ctx, const char *str) {
op.u.f = t.u.f;
break;
case TC_LDOUBLE: op.mode = MIR_OP_LDOUBLE; op.u.ld = t.u.ld;
#if __SIZEOF_LONG_DOUBLE__ != 8
#if !defined(_WIN32) && __SIZEOF_LONG_DOUBLE__ != 8
break;
#endif
case TC_DOUBLE:

@ -6,6 +6,10 @@
#define MIR_H
#if defined(_WIN32) && !defined(_WIN64)
#error "MIR does not work on 32-bit Windows"
#endif
#include <stdio.h>
#include <stdint.h>
#include <assert.h>
@ -35,7 +39,7 @@ static inline int mir_assert (int cond) { return 0 && cond; }
#define MIR_PARALLEL_GEN 0
#endif
#if MIR_PARALLEL_GEN && defined(_WIN64) /* TODO: Win64 thread primitives ??? */
#if MIR_PARALLEL_GEN && defined(_WIN32) /* TODO: Win thread primitives ??? */
#undef MIR_PARALLEL_GEN
#define MIR_PARALLEL_GEN 0
#endif
@ -78,6 +82,7 @@ typedef void MIR_NO_RETURN (*MIR_error_func_t) (MIR_error_type_t error_type, con
#include <pthread.h>
typedef pthread_mutex_t mir_mutex_t;
typedef pthread_cond_t mir_cond_t;
typedef pthread_attr_t mir_thread_attr_t;
#define mir_thread_create(m, attr, f, arg) pthread_create (m, attr, f, arg)
#define mir_thread_join(t, r) pthread_join (t, r)
#define mir_mutex_init(m, a) pthread_mutex_init (m, a)
@ -89,6 +94,8 @@ typedef pthread_cond_t mir_cond_t;
#define mir_cond_wait(c, m) pthread_cond_wait (c, m)
#define mir_cond_signal(c) pthread_cond_signal (c)
#define mir_cond_broadcast(c) pthread_cond_broadcast (c)
#define mir_thread_attr_init(a) pthread_attr_init (a)
#define mir_thread_attr_setstacksize(a, s) pthread_attr_setstacksize (a, s)
#else
#define mir_mutex_init(m, a) 0
#define mir_mutex_destroy(m) 0
@ -157,7 +164,7 @@ typedef enum {
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_STACK_ARG), /* result is arg address, operands: va_list addr and integer (size) */
INSN_EL (VA_BLOCK_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 */
@ -173,7 +180,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 */
REP3 (TYPE_EL, P, BLK, RBLK), /* Pointer, (return) memory block */
REP7 (TYPE_EL, P, BLK, BLK2, BLK3, BLK4, BLK5, RBLK), /* Pointer, (return) memory block */
REP2 (TYPE_EL, UNDEF, BOUND),
} MIR_type_t;
@ -183,7 +190,8 @@ static inline int MIR_int_type_p (MIR_type_t t) {
static inline int MIR_fp_type_p (MIR_type_t t) { return MIR_T_F <= t && t <= MIR_T_LD; }
static inline int MIR_blk_type_p (MIR_type_t t) { return t == MIR_T_BLK || t == MIR_T_RBLK; }
static inline int MIR_blk_type_p (MIR_type_t t) { return MIR_T_BLK <= t && t <= MIR_T_BLK5; }
static inline int MIR_all_blk_type_p (MIR_type_t t) { return MIR_T_BLK <= t && t <= MIR_T_RBLK; }
#if UINTPTR_MAX == 0xffffffff
#define MIR_PTR32 1
@ -292,9 +300,9 @@ struct MIR_insn {
DEF_DLIST (MIR_insn_t, insn_link);
typedef struct MIR_var {
MIR_type_t type; /* MIR_T_BLK and MIR_T_RBLK can be used only args */
MIR_type_t type; /* MIR_T_BLK .. MIR_T_RBLK can be used only args */
const char *name;
size_t size; /* ignored for type != MIR_T_BLK, MIR_T_RBLK */
size_t size; /* ignored for type != [MIR_T_BLK .. MIR_T_RBLK] */
} MIR_var_t;
DEF_VARR (MIR_var_t);
@ -628,7 +636,7 @@ 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_block_arg_builtin (void *res, void *p, size_t s, uint64_t t);
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);
@ -637,7 +645,7 @@ 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_T_RBLK) */
size_t size; /* used only for block arg (type == [MIR_T_BLK .. MIR_T_RBLK]) */
} _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,

Loading…
Cancel
Save