issue #169 Update MIR

cmake
Dibyendu Majumdar 3 years ago
parent 9cc59144ad
commit e6890743f0

@ -28,12 +28,17 @@ typedef uint16_t mir_ushort;
typedef uint32_t mir_uint;
typedef uint64_t mir_ulong;
typedef uint64_t mir_ullong;
typedef uint32_t mir_wchar;
typedef uint16_t mir_char16;
typedef uint32_t mir_char32;
#define MIR_UCHAR_MAX UINT8_MAX
#define MIR_USHORT_MAX UINT16_MAX
#define MIR_UINT_MAX UINT32_MAX
#define MIR_ULONG_MAX UINT64_MAX
#define MIR_ULLONG_MAX UINT64_MAX
#define MIR_WCHAR_MIN 0
#define MIR_WCHAR_MAX UINT32_MAX
typedef mir_schar mir_char;
#define MIR_CHAR_MIN MIR_SCHAR_MIN

@ -21,6 +21,7 @@
#include <errno.h>
#include <setjmp.h>
#include <math.h>
#include <wchar.h>
#include "time.h"
#include "c2mir.h"
@ -452,7 +453,8 @@ void c2mir_finish (MIR_context_t ctx) {
'}'. The input is parse tokens and the output is the following AST
nodes (the AST root is transl_unit):
expr : N_I | N_L | N_LL | N_U | N_UL | N_ULL | N_F | N_D | N_LD | N_CH | N_STR | N_ID
expr : N_I | N_L | N_LL | N_U | N_UL | N_ULL | N_F | N_D | N_LD
| N_CH | N_CH16 | N_CH32 | N_STR | N_STR16 | N_STR32 | N_ID
| N_ADD (expr) | N_SUB (expr) | N_ADD (expr, expr) | N_SUB (expr, expr)
| N_MUL (expr, expr) | N_DIV (expr, expr) | N_MOD (expr, expr)
| N_LSH (expr, expr) | N_RSH (expr, expr)
@ -479,7 +481,7 @@ stmt: compound_stmt | N_IF(N_LIST:(label)*, expr, stmt, stmt?)
| N_RETURN(N_LIST:(label)*, expr?) | N_EXPR(N_LIST:(label)*, expr)
compound_stmt: N_BLOCK(N_LIST:(label)*, N_LIST:(declaration | stmt)*)
declaration: N_SPEC_DECL(N_SHARE(declaration_specs), declarator?, initializer?) | st_assert
st_assert: N_ST_ASSERT(const_expr, N_STR)
st_assert: N_ST_ASSERT(const_expr, N_STR | N_STR16 | N_STR32)
declaration_specs: N_LIST:(align_spec|sc_spec|type_qual|func_spec|type_spec)*
align_spec: N_ALIGNAS(type_name|const_expr)
sc_spec: N_TYPEDEF|N_EXTERN|N_STATIC|N_AUTO|N_REGISTER|N_THREAD_LOCAL
@ -549,7 +551,8 @@ static token_code_t FIRST_KW = T_BOOL, LAST_KW = T_WHILE;
typedef enum {
REP8 (NODE_EL, IGNORE, I, L, LL, U, UL, ULL, F),
REP8 (NODE_EL, D, LD, CH, STR, ID, COMMA, ANDAND, OROR),
REP8 (NODE_EL, D, LD, CH, CH16, CH32, STR, STR16, STR32),
REP4 (NODE_EL, ID, COMMA, ANDAND, OROR),
REP8 (NODE_EL, EQ, NE, LT, LE, GT, GE, ASSIGN, BITWISE_NOT),
REP8 (NODE_EL, NOT, AND, AND_ASSIGN, OR, OR_ASSIGN, XOR, XOR_ASSIGN, LSH),
REP8 (NODE_EL, LSH_ASSIGN, RSH, RSH_ASSIGN, ADD, ADD_ASSIGN, SUB, SUB_ASSIGN, MUL),
@ -580,7 +583,7 @@ struct node {
mir_char ch;
mir_long l;
mir_llong ll;
mir_ulong ul;
mir_ulong ul; /* includes CH16 and CH32 */
mir_ullong ull;
mir_float f;
mir_double d;
@ -693,67 +696,66 @@ static node_t new_pos_node4 (c2m_ctx_t c2m_ctx, node_code_t nc, pos_t p, node_t
}
static node_t new_ch_node (c2m_ctx_t c2m_ctx, int ch, pos_t p) {
node_t n = new_pos_node (c2m_ctx, N_CH, p);
n->u.ch = ch;
return n;
}
static node_t new_ch16_node (c2m_ctx_t c2m_ctx, mir_ulong ch, pos_t p) {
node_t n = new_pos_node (c2m_ctx, N_CH16, p);
n->u.ul = ch;
return n;
}
static node_t new_ch32_node (c2m_ctx_t c2m_ctx, mir_ulong ch, pos_t p) {
node_t n = new_pos_node (c2m_ctx, N_CH32, p);
n->u.ul = ch;
return n;
}
static node_t new_i_node (c2m_ctx_t c2m_ctx, long l, pos_t p) {
node_t n = new_pos_node (c2m_ctx, N_I, p);
n->u.l = l;
return n;
}
static node_t new_l_node (c2m_ctx_t c2m_ctx, long l, pos_t p) {
node_t n = new_pos_node (c2m_ctx, N_L, p);
n->u.l = l;
return n;
}
static node_t new_ll_node (c2m_ctx_t c2m_ctx, long long ll, pos_t p) {
node_t n = new_pos_node (c2m_ctx, N_LL, p);
n->u.ll = ll;
return n;
}
static node_t new_u_node (c2m_ctx_t c2m_ctx, unsigned long ul, pos_t p) {
node_t n = new_pos_node (c2m_ctx, N_U, p);
n->u.ul = ul;
return n;
}
static node_t new_ul_node (c2m_ctx_t c2m_ctx, unsigned long ul, pos_t p) {
node_t n = new_pos_node (c2m_ctx, N_UL, p);
n->u.ul = ul;
return n;
}
static node_t new_ull_node (c2m_ctx_t c2m_ctx, unsigned long long ull, pos_t p) {
node_t n = new_pos_node (c2m_ctx, N_ULL, p);
n->u.ull = ull;
return n;
}
static node_t new_f_node (c2m_ctx_t c2m_ctx, float f, pos_t p) {
node_t n = new_pos_node (c2m_ctx, N_F, p);
n->u.f = f;
return n;
}
static node_t new_d_node (c2m_ctx_t c2m_ctx, double d, pos_t p) {
node_t n = new_pos_node (c2m_ctx, N_D, p);
n->u.d = d;
return n;
}
static node_t new_ld_node (c2m_ctx_t c2m_ctx, long double ld, pos_t p) {
node_t n = new_pos_node (c2m_ctx, N_LD, p);
n->u.ld = ld;
return n;
}
static node_t new_str_node (c2m_ctx_t c2m_ctx, node_code_t nc, str_t s, pos_t p) {
node_t n = new_pos_node (c2m_ctx, nc, p);
n->u.s = s;
return n;
}
@ -1036,30 +1038,87 @@ static void remove_string_stream (c2m_ctx_t c2m_ctx) {
cs = VARR_LAST (stream_t, streams);
}
static void set_string_val (c2m_ctx_t c2m_ctx, token_t t, VARR (char) * temp) {
int i, str_len, curr_c;
#define MAX_UTF8 0x1FFFFF
/* We use UTF-32 for 32-bit wchars and UTF-16 for 16-bit wchar (LE/BE
depending on endianess of the target), UTF-8 for anything else. */
static void push_str_char (c2m_ctx_t c2m_ctx, VARR (char) * temp, uint64_t ch, int type) {
int i, len = 0;
switch (type) {
case ' ':
if (ch <= 0xFF) {
VARR_PUSH (char, temp, ch);
return;
}
/* Fall through */
case '8':
if (ch <= 0x7F) {
VARR_PUSH (char, temp, ch);
} else if (ch <= 0x7FF) {
VARR_PUSH (char, temp, 0xC0 | (ch >> 6));
VARR_PUSH (char, temp, 0x80 | (ch & 0x3F));
} else if (ch <= 0xFFFF) {
VARR_PUSH (char, temp, 0xE0 | (ch >> 12));
VARR_PUSH (char, temp, 0x80 | ((ch >> 6) & 0x3F));
VARR_PUSH (char, temp, 0x80 | (ch & 0x3F));
} else {
assert (ch <= MAX_UTF8);
VARR_PUSH (char, temp, 0xF0 | (ch >> 18));
VARR_PUSH (char, temp, 0x80 | ((ch >> 12) & 0x3F));
VARR_PUSH (char, temp, 0x80 | ((ch >> 6) & 0x3F));
VARR_PUSH (char, temp, 0x80 | (ch & 0x3F));
}
return;
case 'L':
if (sizeof (mir_wchar) == 4) goto U;
/* Fall through */
case 'u': len = 2; break;
case 'U':
U:
len = 4;
break;
default: assert (FALSE);
}
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
for (i = 0; i < len; i++) VARR_PUSH (char, temp, (ch >> i * 8) & 0xff);
#else
for (i = len - 1; i >= 0; i--) VARR_PUSH (char, temp, (ch >> i * 8) & 0xff);
#endif
}
static void set_string_val (c2m_ctx_t c2m_ctx, token_t t, VARR (char) * temp, int type) {
int i, str_len;
int64_t curr_c, last_c = -1;
int64_t max_char
= (type == 'u' ? UINT16_MAX
: type == 'U' ? UINT32_MAX : type == 'L' ? MIR_WCHAR_MAX : MIR_UCHAR_MAX);
int start = type == ' ' ? 0 : type == '8' ? 2 : 1;
int string_p = t->repr[start] == '"';
const char *str;
assert (t->code == T_STR || t->code == T_CH);
str = t->repr;
VARR_TRUNC (char, temp, 0);
str_len = strlen (str);
assert (str_len >= 2 && (str[0] == '"' || str[0] == '\'') && str[0] == str[str_len - 1]);
for (i = 1; i < str_len - 1; i++) {
curr_c = str[i];
assert (str_len >= start + 2 && (str[start] == '"' || str[start] == '\'')
&& str[start] == str[str_len - 1]);
for (i = start + 1; i < str_len - 1; i++) {
if (!string_p && last_c >= 0) error (c2m_ctx, t->pos, "multibyte character");
last_c = curr_c = str[i];
if (curr_c != '\\') {
VARR_PUSH (char, temp, curr_c);
push_str_char (c2m_ctx, temp, curr_c, type);
continue;
}
curr_c = str[++i];
last_c = curr_c = str[++i];
switch (curr_c) {
case 'a': curr_c = '\a'; break;
case 'b': curr_c = '\b'; break;
case 'n': curr_c = '\n'; break;
case 'f': curr_c = '\f'; break;
case 'r': curr_c = '\r'; break;
case 't': curr_c = '\t'; break;
case 'v': curr_c = '\v'; break;
case 'a': last_c = curr_c = '\a'; break;
case 'b': last_c = curr_c = '\b'; break;
case 'n': last_c = curr_c = '\n'; break;
case 'f': last_c = curr_c = '\f'; break;
case 'r': last_c = curr_c = '\r'; break;
case 't': last_c = curr_c = '\t'; break;
case 'v': last_c = curr_c = '\v'; break;
case '\\':
case '\'':
case '\?':
@ -1067,7 +1126,7 @@ static void set_string_val (c2m_ctx_t c2m_ctx, token_t t, VARR (char) * temp) {
case 'e':
(c2m_options->pedantic_p ? error : warning) (c2m_ctx, t->pos,
"non-standard escape sequence \\e");
curr_c = '\033';
last_c = curr_c = '\033';
break;
case '0':
case '1':
@ -1077,7 +1136,7 @@ static void set_string_val (c2m_ctx_t c2m_ctx, token_t t, VARR (char) * temp) {
case '5':
case '6':
case '7': {
unsigned long v = curr_c - '0';
uint64_t v = curr_c - '0';
curr_c = str[++i];
if (!isdigit (curr_c) || curr_c == '8' || curr_c == '9') {
@ -1090,42 +1149,77 @@ static void set_string_val (c2m_ctx_t c2m_ctx, token_t t, VARR (char) * temp) {
else
v = v * 8 + curr_c - '0';
}
curr_c = v;
last_c = curr_c = v;
break;
}
case 'x':
case 'X': {
int first_p = TRUE;
unsigned long v = 0;
uint64_t v = 0;
for (i++;; i++) {
curr_c = str[i];
if (!isxdigit (curr_c)) break;
first_p = FALSE;
v *= 16;
v += (isdigit (curr_c) ? curr_c - '0'
: islower (curr_c) ? curr_c - 'a' + 10 : curr_c - 'A' + 10);
if (v <= UINT32_MAX) {
v *= 16;
v += (isdigit (curr_c) ? curr_c - '0'
: islower (curr_c) ? curr_c - 'a' + 10 : curr_c - 'A' + 10);
}
}
if (first_p)
if (first_p) {
error (c2m_ctx, t->pos, "wrong hexadecimal char %c", curr_c);
else if (v > MIR_UCHAR_MAX)
} else if (v > max_char) {
(c2m_options->pedantic_p ? error : warning) (c2m_ctx, t->pos,
"too big hexadecimal char 0x%x", v);
curr_c = v;
curr_c = max_char;
}
last_c = curr_c = v;
i--;
break;
}
case 'u':
case 'U': {
int n, start_c = curr_c, digits_num = curr_c == 'u' ? 4 : 8;
int64_t v = 0;
for (i++, n = 0; n < digits_num; i++, n++) {
curr_c = str[i];
if (!isxdigit (curr_c)) break;
v *= 16;
v += (isdigit (curr_c) ? curr_c - '0'
: islower (curr_c) ? curr_c - 'a' + 10 : curr_c - 'A' + 10);
}
last_c = curr_c = v;
if (n < digits_num) {
error (c2m_ctx, t->pos, "unfinished \\%c<hex-digits>", start_c);
} else if (v > max_char && (!string_p || (type != ' ' && type != '8') || v > MAX_UTF8)) {
(c2m_options->pedantic_p ? error : warning) (c2m_ctx, t->pos,
"too big universal char 0x%lx in \\%c",
(unsigned long) v, start_c);
last_c = curr_c = max_char;
} else if ((0xD800 <= v && v <= 0xDFFF)
|| (v < 0xA0 && v != 0x24 && v != 0x40 && v != 0x60)) {
error (c2m_ctx, t->pos, "usage of reserved value 0x%lx in \\%c", (unsigned long) v,
start_c);
curr_c = -1;
}
if (n < digits_num) i--;
break;
}
default: error (c2m_ctx, t->pos, "wrong escape char 0x%x", curr_c); curr_c = -1;
}
if (t->repr[0] == '\'' || curr_c >= 0) VARR_PUSH (char, temp, curr_c);
if (!string_p || curr_c >= 0) push_str_char (c2m_ctx, temp, curr_c, type);
}
VARR_PUSH (char, temp, '\0');
if (t->repr[0] == '"')
push_str_char (c2m_ctx, temp, '\0', type);
if (string_p)
t->node->u.s = uniq_str (c2m_ctx, VARR_ADDR (char, temp), VARR_LENGTH (char, temp));
else if (VARR_LENGTH (char, temp) == 1)
else if (last_c < 0)
error (c2m_ctx, t->pos, "empty char constant");
else if (type == 'U' || type == 'u' || type == 'L')
t->node->u.ul = last_c;
else
t->node->u.ch = VARR_GET (char, temp, 0);
t->node->u.ch = last_c;
}
static token_t new_id_token (c2m_ctx_t c2m_ctx, pos_t pos, const char *id_str) {
@ -1138,7 +1232,7 @@ static token_t new_id_token (c2m_ctx_t c2m_ctx, pos_t pos, const char *id_str) {
}
static token_t get_next_pptoken_1 (c2m_ctx_t c2m_ctx, int header_p) {
int start_c, curr_c, nl_p, comment_char;
int start_c, curr_c, nl_p, comment_char, wide_type;
pos_t pos;
if (cs->fname != NULL && VARR_LENGTH (token_t, buffered_tokens) != 0)
@ -1495,7 +1589,9 @@ static token_t get_next_pptoken_1 (c2m_ctx_t c2m_ctx, int header_p) {
N_IGNORE);
}
case '\'':
case '\"': { /* ??? unicode and wchar */
case '\"':
wide_type = ' ';
literal : {
token_t t;
int stop = curr_c;
@ -1518,15 +1614,45 @@ static token_t get_next_pptoken_1 (c2m_ctx_t c2m_ctx, int header_p) {
VARR_PUSH (char, symbol_text, stop);
}
VARR_PUSH (char, symbol_text, '\0');
t = (stop == '\"' ? new_node_token (c2m_ctx, pos, VARR_ADDR (char, symbol_text), T_STR,
new_str_node (c2m_ctx, N_STR, empty_str, pos))
: new_node_token (c2m_ctx, pos, VARR_ADDR (char, symbol_text), T_CH,
new_ch_node (c2m_ctx, ' ', pos)));
set_string_val (c2m_ctx, t, symbol_text);
if (wide_type == 'U' || (sizeof (mir_wchar) == 4 && wide_type == 'L')) {
t = (stop == '\"' ? new_node_token (c2m_ctx, pos, VARR_ADDR (char, symbol_text), T_STR,
new_str_node (c2m_ctx, N_STR32, empty_str, pos))
: new_node_token (c2m_ctx, pos, VARR_ADDR (char, symbol_text), T_CH,
new_ch32_node (c2m_ctx, ' ', pos)));
} else if (wide_type == 'u' || wide_type == 'L') {
t = (stop == '\"' ? new_node_token (c2m_ctx, pos, VARR_ADDR (char, symbol_text), T_STR,
new_str_node (c2m_ctx, N_STR16, empty_str, pos))
: new_node_token (c2m_ctx, pos, VARR_ADDR (char, symbol_text), T_CH,
new_ch16_node (c2m_ctx, ' ', pos)));
} else {
t = (stop == '\"' ? new_node_token (c2m_ctx, pos, VARR_ADDR (char, symbol_text), T_STR,
new_str_node (c2m_ctx, N_STR, empty_str, pos))
: new_node_token (c2m_ctx, pos, VARR_ADDR (char, symbol_text), T_CH,
new_ch_node (c2m_ctx, ' ', pos)));
}
set_string_val (c2m_ctx, t, symbol_text, wide_type);
return t;
}
default:
if (isalpha (curr_c) || curr_c == '_') {
if (curr_c == 'L' || curr_c == 'u' || curr_c == 'U') {
wide_type = curr_c;
if ((curr_c = cs_get (c2m_ctx)) == '\"' || curr_c == '\'') {
VARR_PUSH (char, symbol_text, wide_type);
goto literal;
} else if (wide_type == 'u' && curr_c == '8') {
wide_type = '8';
if ((curr_c = cs_get (c2m_ctx)) == '\"') {
VARR_PUSH (char, symbol_text, 'u');
VARR_PUSH (char, symbol_text, '8');
goto literal;
}
cs_unget (c2m_ctx, curr_c);
curr_c = '8';
}
cs_unget (c2m_ctx, curr_c);
curr_c = wide_type;
}
pos = cs->pos;
do {
VARR_PUSH (char, symbol_text, curr_c);
@ -1624,7 +1750,7 @@ static token_t token_stringify (c2m_ctx_t c2m_ctx, token_t t, VARR (token_t) * t
VARR_PUSH (char, temp_string, '"');
VARR_PUSH (char, temp_string, '\0');
t->repr = uniq_cstr (c2m_ctx, VARR_ADDR (char, temp_string)).s;
set_string_val (c2m_ctx, t, temp_string);
set_string_val (c2m_ctx, t, temp_string, ' ');
return t;
}
@ -2316,7 +2442,6 @@ 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);
@ -2325,6 +2450,7 @@ static void check_pragma (c2m_ctx_t c2m_ctx, token_t t, VARR (token_t) * tokens)
#ifdef _WIN32
if (i + 1 == tokens_len && tokens_arr[i]->code == T_ID
&& strcmp (tokens_arr[i]->repr, "once") == 0) {
pre_ctx_t pre_ctx = c2m_ctx->pre_ctx;
VARR_PUSH (char_ptr_t, once_include_files, cs->fname);
return;
}
@ -2828,7 +2954,7 @@ static void process_directive (c2m_ctx_t c2m_ctx) {
error (c2m_ctx, t1->pos, "garbage at the end of #%s", t1->repr);
skip_nl (c2m_ctx, NULL, NULL);
}
if (VARR_LENGTH (ifstate_t, ifs) < cs->ifs_length_at_stream_start)
if (VARR_LENGTH (ifstate_t, ifs) <= cs->ifs_length_at_stream_start)
error (c2m_ctx, t1->pos, "unmatched #%s", t1->repr);
else if (strcmp (t1->repr, "endif") == 0) {
pop_ifstate (c2m_ctx);
@ -3241,6 +3367,8 @@ static struct val eval (c2m_ctx_t c2m_ctx, node_t tree) {
else
res.u.i_val = tree->u.ch;
break;
case N_CH16:
case N_CH32: res.u.u_val = tree->u.ul; break;
case N_I:
case N_L:
res.uns_p = FALSE;
@ -3428,7 +3556,7 @@ static void processing (c2m_ctx_t c2m_ctx, int ignore_directive_p) {
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));
set_string_val (c2m_ctx, t, temp_string);
set_string_val (c2m_ctx, t, temp_string, ' ');
out_token (c2m_ctx, t);
} else if (strcmp (t->repr, "__LINE__") == 0) {
char str[50];
@ -3541,17 +3669,48 @@ static void pre_out (c2m_ctx_t c2m_ctx, token_t t) {
if (t->code == T_STR && VARR_LENGTH (token_t, recorded_tokens) != 0
&& VARR_LAST (token_t, recorded_tokens)->code == T_STR) { /* concat strings */
token_t last_t = VARR_POP (token_t, recorded_tokens);
int type = ' ', last_t_quot_off = 0, t_quot_off = 0, err_p = FALSE;
const char *s;
VARR_TRUNC (char, temp_string, 0);
for (const char *s = last_t->repr; *s != 0; s++) VARR_PUSH (char, temp_string, *s);
assert (VARR_LAST (char, temp_string) == '"' && t->repr[0] == '"');
if (last_t->repr[0] == 'u' && last_t->repr[1] == '8') {
err_p = t->repr[0] != '\"' && (t->repr[0] != 'u' || t->repr[1] != '8');
last_t_quot_off = 2;
} else if (last_t->repr[0] == 'L' || last_t->repr[0] == 'u' || last_t->repr[0] == 'U') {
err_p = t->repr[0] != '\"' && (t->repr[0] != last_t->repr[0] || t->repr[1] == '8');
last_t_quot_off = 1;
}
if (t->repr[0] == 'u' && t->repr[1] == '8') {
err_p = last_t->repr[0] != '\"' && (last_t->repr[0] != 'u' || last_t->repr[1] != '8');
t_quot_off = 2;
} else if (t->repr[0] == 'L' || t->repr[0] == 'u' || t->repr[0] == 'U') {
err_p = last_t->repr[0] != '\"' && (t->repr[0] != last_t->repr[0] || last_t->repr[1] == '8');
t_quot_off = 1;
}
if (err_p) error (c2m_ctx, t->pos, "concatenation of different type string literals");
if (sizeof (mir_wchar) == 4 && (last_t->repr[0] == 'L' || t->repr[0] == 'L')) {
type = 'L';
} else if (last_t->repr[0] == 'U' || t->repr[0] == 'U') {
type = 'U';
} else if (last_t->repr[0] == 'L' || t->repr[0] == 'L') {
type = 'L';
} else if ((last_t->repr[0] == 'u' && last_t->repr[1] == '8')
|| (t->repr[0] == 'u' && t->repr[1] == '8')) {
VARR_PUSH (char, temp_string, 'u');
type = '8';
} else if ((last_t->repr[0] == 'u' || t->repr[0] == 'u')) {
type = 'u';
}
if (type != ' ') VARR_PUSH (char, temp_string, type);
for (s = last_t->repr + last_t_quot_off; *s != 0; s++) VARR_PUSH (char, temp_string, *s);
assert (VARR_LAST (char, temp_string) == '"');
VARR_POP (char, temp_string);
for (const char *s = &t->repr[1]; *s != 0; s++) VARR_PUSH (char, temp_string, *s);
for (s = t->repr + t_quot_off + 1; *s != 0; s++) VARR_PUSH (char, temp_string, *s);
t = last_t;
assert (VARR_LAST (char, temp_string) == '"');
VARR_PUSH (char, temp_string, '\0');
t->repr = uniq_cstr (c2m_ctx, VARR_ADDR (char, temp_string)).s;
set_string_val (c2m_ctx, t, temp_string);
set_string_val (c2m_ctx, t, temp_string, type);
}
VARR_PUSH (token_t, recorded_tokens, t);
}
@ -6393,7 +6552,6 @@ static struct decl_spec check_decl_spec (c2m_ctx_t c2m_ctx, node_t r, node_t dec
} else {
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;
@ -7001,6 +7159,22 @@ static int update_init_object_path (c2m_ctx_t c2m_ctx, size_t mark, struct type
}
}
static enum basic_type get_uint_basic_type (size_t size) {
if (sizeof (mir_uint) == size) return TP_UINT;
if (sizeof (mir_ulong) == size) return TP_ULONG;
if (sizeof (mir_ullong) == size) return TP_ULLONG;
if (sizeof (mir_ushort) == size) return TP_USHORT;
return TP_UCHAR;
}
static int init_compatible_string_p (node_t n, struct type *el_type) {
return ((n->code == N_STR && char_type_p (el_type))
|| (n->code == N_STR16 && el_type->mode == TM_BASIC
&& el_type->u.basic_type == get_uint_basic_type (2))
|| (n->code == N_STR32 && el_type->mode == TM_BASIC
&& el_type->u.basic_type == get_uint_basic_type (4)));
}
static int update_path_and_do (c2m_ctx_t c2m_ctx,
void (*action) (c2m_ctx_t c2m_ctx, decl_t member_decl,
struct type **type_ptr, node_t initializer,
@ -7021,7 +7195,7 @@ static int update_path_and_do (c2m_ctx_t c2m_ctx,
if (init_object.container_type->mode == TM_ARR) {
el_type = init_object.container_type->u.arr_type->el_type;
action (c2m_ctx, NULL,
(value->code == N_STR && char_type_p (el_type)
(init_compatible_string_p (value, el_type)
? &init_object.container_type
: &init_object.container_type->u.arr_type->el_type),
value, const_only_p, FALSE);
@ -7058,6 +7232,8 @@ static int check_const_addr_p (c2m_ctx_t c2m_ctx, node_t r, node_t *base, mir_ll
}
switch (r->code) {
case N_STR:
case N_STR16:
case N_STR32:
*base = r;
*offset = 0;
*deref = 0;
@ -7196,6 +7372,8 @@ static node_t get_compound_literal (node_t n, int *addr_p) {
case N_DEREF: addr--; break;
case N_CAST: break; // ???
case N_STR:
case N_STR16:
case N_STR32:
case N_COMPOUND_LITERAL:
if (addr < 0) return NULL;
*addr_p = addr > 0;
@ -7222,16 +7400,18 @@ static void check_initializer (c2m_ctx_t c2m_ctx, decl_t member_decl, struct typ
int addr_p = FALSE; /* to remove an uninitialized warning */
literal = get_compound_literal (initializer, &addr_p);
if (literal != NULL && !addr_p && initializer->code != N_STR) {
if (literal != NULL && !addr_p && initializer->code != N_STR && initializer->code != N_STR16
&& initializer->code != N_STR32) {
cexpr = initializer->attr;
check_assignment_types (c2m_ctx, type, NULL, cexpr, initializer);
initializer = NL_EL (literal->u.ops, 1);
}
check_one_value:
if (initializer->code != N_LIST
&& !(initializer->code == N_STR && type->mode == TM_ARR
&& char_type_p (type->u.arr_type->el_type))) {
if ((cexpr = initializer->attr)->const_p || initializer->code == N_STR || !const_only_p) {
&& !(type->mode == TM_ARR
&& init_compatible_string_p (initializer, type->u.arr_type->el_type))) {
if ((cexpr = initializer->attr)->const_p || initializer->code == N_STR
|| initializer->code == N_STR16 || initializer->code == N_STR32 || !const_only_p) {
check_assignment_types (c2m_ctx, type, NULL, cexpr, initializer);
} else {
setup_const_addr_p (c2m_ctx, initializer);
@ -7245,12 +7425,14 @@ check_one_value:
return;
}
init = NL_HEAD (initializer->u.ops);
if (((str = initializer)->code == N_STR /* string or string in parentheses */
if (((str = initializer)->code == N_STR || str->code == N_STR16
|| str->code == N_STR32 /* string or string in parentheses */
|| (init != NULL && init->code == N_INIT && NL_EL (initializer->u.ops, 1) == NULL
&& (des_list = NL_HEAD (init->u.ops))->code == N_LIST
&& NL_HEAD (des_list->u.ops) == NULL && NL_EL (init->u.ops, 1) != NULL
&& (str = NL_EL (init->u.ops, 1))->code == N_STR))
&& type->mode == TM_ARR && char_type_p (type->u.arr_type->el_type)) {
&& ((str = NL_EL (init->u.ops, 1))->code == N_STR || str->code == N_STR16
|| str->code == N_STR32)))
&& type->mode == TM_ARR && init_compatible_string_p (str, type->u.arr_type->el_type)) {
len = str->u.s.len;
if (incomplete_type_p (c2m_ctx, type)) {
assert (len < MIR_INT_MAX);
@ -7809,14 +7991,15 @@ static void classify_node (node_t n, int *expr_attr_p, int *stmt_p) {
*expr_attr_p = *stmt_p = FALSE;
switch (n->code) {
REP8 (NODE_CASE, I, L, LL, U, UL, ULL, F, D)
REP8 (NODE_CASE, LD, CH, STR, ID, COMMA, ANDAND, OROR, EQ)
REP7 (NODE_CASE, LD, CH, CH16, CH32, STR, STR16, STR32)
REP5 (NODE_CASE, ID, COMMA, ANDAND, OROR, EQ)
REP8 (NODE_CASE, NE, LT, LE, GT, GE, ASSIGN, BITWISE_NOT, NOT)
REP8 (NODE_CASE, AND, AND_ASSIGN, OR, OR_ASSIGN, XOR, XOR_ASSIGN, LSH, LSH_ASSIGN)
REP8 (NODE_CASE, RSH, RSH_ASSIGN, ADD, ADD_ASSIGN, SUB, SUB_ASSIGN, MUL, MUL_ASSIGN)
REP8 (NODE_CASE, DIV, DIV_ASSIGN, MOD, MOD_ASSIGN, IND, FIELD, ADDR, DEREF)
REP8 (NODE_CASE, DEREF_FIELD, COND, INC, DEC, POST_INC, POST_DEC, ALIGNOF, SIZEOF)
REP6 (NODE_CASE, EXPR_SIZEOF, CAST, COMPOUND_LITERAL, CALL, GENERIC, GENERIC_ASSOC)
*expr_attr_p = TRUE;
REP6 (NODE_CASE, EXPR_SIZEOF, CAST, COMPOUND_LITERAL, CALL, GENERIC, GENERIC_ASSOC) *expr_attr_p
= TRUE;
break;
REP8 (NODE_CASE, IF, SWITCH, WHILE, DO, FOR, GOTO, CONTINUE, BREAK)
REP4 (NODE_CASE, RETURN, EXPR, BLOCK, SPEC_DECL) /* SPEC DECL may have an initializer */
@ -7994,8 +8177,17 @@ static void check (c2m_ctx_t c2m_ctx, node_t r, node_t context) {
else
e->u.u_val = r->u.ch;
break;
case N_STR: {
case N_CH16:
case N_CH32:
e = create_basic_type_expr (c2m_ctx, r, get_uint_basic_type (r->code == N_CH16 ? 2 : 4));
e->const_p = TRUE;
e->u.u_val = r->u.ul;
break;
case N_STR:
case N_STR16:
case N_STR32: {
struct arr_type *arr_type;
int size = r->code == N_STR ? 1 : r->code == N_STR16 ? 2 : 4;
e = create_expr (c2m_ctx, r);
e->lvalue_node = r;
@ -8007,7 +8199,7 @@ static void check (c2m_ctx_t c2m_ctx, node_t r, node_t context) {
arr_type->el_type = create_type (c2m_ctx, NULL);
arr_type->el_type->pos_node = r;
arr_type->el_type->mode = TM_BASIC;
arr_type->el_type->u.basic_type = TP_CHAR;
arr_type->el_type->u.basic_type = size == 1 ? TP_CHAR : get_uint_basic_type (size);
arr_type->size = new_i_node (c2m_ctx, r->u.s.len, POS (r));
check (c2m_ctx, arr_type->size, NULL);
break;
@ -8367,7 +8559,8 @@ static void check (c2m_ctx_t c2m_ctx, node_t r, node_t context) {
} else if (e1->lvalue_node->code == N_COMPOUND_LITERAL) {
t2 = t1;
} else {
assert (e1->lvalue_node->code == N_STR);
assert (e1->lvalue_node->code == N_STR || e1->lvalue_node->code == N_STR16
|| e1->lvalue_node->code == N_STR32);
t2 = t1;
}
e->type->mode = TM_PTR;
@ -8842,7 +9035,9 @@ static void check (c2m_ctx_t c2m_ctx, node_t r, node_t context) {
else
ok_p = e1->u.u_val != 0;
if (!ok_p) {
assert (NL_NEXT (op1) != NULL && NL_NEXT (op1)->code == N_STR);
assert (NL_NEXT (op1) != NULL
&& (NL_NEXT (op1)->code == N_STR || NL_NEXT (op1)->code == N_STR16
|| NL_NEXT (op1)->code == N_STR32));
error (c2m_ctx, POS (r), "static assertion failed: \"%s\"",
NL_NEXT (op1)->u.s.s); // ???
}
@ -10350,6 +10545,10 @@ static void MIR_UNUSED simple_add_ret_ops (c2m_ctx_t c2m_ctx, struct type *ret_t
}
}
static MIR_type_t MIR_UNUSED simple_target_get_blk_type (c2m_ctx_t c2m_ctx, struct type *arg_type) {
return MIR_T_BLK;
}
static void MIR_UNUSED simple_add_arg_proto (c2m_ctx_t c2m_ctx, const char *name,
struct type *arg_type, void *arg_info,
VARR (MIR_var_t) * arg_vars) {
@ -10520,6 +10719,10 @@ static void target_add_ret_ops (c2m_ctx_t c2m_ctx, struct type *ret_type, op_t v
simple_add_ret_ops (c2m_ctx, ret_type, val);
}
/* Return BLK type should be used for VA_BLOCK_ARG for accessing aggregate type ARG_TYPE. */
static MIR_type_t target_get_blk_type (c2m_ctx_t c2m_ctx, struct type *arg_type) {
return simple_target_get_blk_type (c2m_ctx, arg_type);
}
/* Add one or more vars to arg_vars which pass arg NAME of ARG_TYPE. */
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) {
@ -10615,16 +10818,18 @@ static void collect_init_els (c2m_ctx_t c2m_ctx, decl_t member_decl, struct type
init_object_t init_object;
literal = get_compound_literal (initializer, &addr_p);
if (literal != NULL && !addr_p && initializer->code != N_STR)
if (literal != NULL && !addr_p && initializer->code != N_STR && initializer->code != N_STR16
&& initializer->code != N_STR32)
initializer = NL_EL (literal->u.ops, 1);
check_one_value:
if (initializer->code != N_LIST
&& !(initializer->code == N_STR && type->mode == TM_ARR
&& char_type_p (type->u.arr_type->el_type))) {
&& init_compatible_string_p (initializer, type->u.arr_type->el_type))) {
cexpr = initializer->attr;
/* static or thread local object initialization should be const expr or addr: */
assert (initializer->code == N_STR || !const_only_p || cexpr->const_p || cexpr->const_addr_p
|| (literal != NULL && addr_p));
assert (initializer->code == N_STR || initializer->code == N_STR16
|| initializer->code == N_STR32 || !const_only_p || cexpr->const_p
|| cexpr->const_addr_p || (literal != NULL && addr_p));
init_el.num = VARR_LENGTH (init_el_t, init_els);
init_el.offset = get_object_path_offset (c2m_ctx);
init_el.member_decl = member_decl;
@ -10634,12 +10839,14 @@ check_one_value:
return;
}
init = NL_HEAD (initializer->u.ops);
if (((str = initializer)->code == N_STR /* string or string in parentheses */
if (((str = initializer)->code == N_STR || str->code == N_STR16
|| str->code == N_STR32 /* string or string in parentheses */
|| (init != NULL && init->code == N_INIT && NL_EL (initializer->u.ops, 1) == NULL
&& (des_list = NL_HEAD (init->u.ops))->code == N_LIST
&& NL_HEAD (des_list->u.ops) == NULL && NL_EL (init->u.ops, 1) != NULL
&& (str = NL_EL (init->u.ops, 1))->code == N_STR))
&& type->mode == TM_ARR && char_type_p (type->u.arr_type->el_type)) {
&& ((str = NL_EL (init->u.ops, 1))->code == N_STR || str->code == N_STR16
|| str->code == N_STR32)))
&& type->mode == TM_ARR && init_compatible_string_p (str, type->u.arr_type->el_type)) {
init_el.num = VARR_LENGTH (init_el_t, init_els);
init_el.offset = get_object_path_offset (c2m_ctx);
init_el.member_decl = NULL;
@ -10912,6 +11119,39 @@ static void add_bit_field (c2m_ctx_t c2m_ctx, uint64_t *u, uint64_t v, decl_t me
*u |= v;
}
static MIR_item_t get_mir_str_op_data (c2m_ctx_t c2m_ctx, MIR_str_t str) {
MIR_context_t ctx = c2m_ctx->ctx;
MIR_item_t data;
char buff[50];
MIR_module_t module = DLIST_TAIL (MIR_module_t, *MIR_get_module_list (ctx));
_MIR_get_temp_item_name (ctx, module, buff, sizeof (buff));
data = MIR_new_string_data (ctx, buff, str);
move_item_to_module_start (module, data);
return data;
}
static MIR_item_t get_string_data (c2m_ctx_t c2m_ctx, node_t n) {
MIR_context_t ctx = c2m_ctx->ctx;
MIR_item_t data;
char buff[50];
MIR_module_t module = DLIST_TAIL (MIR_module_t, *MIR_get_module_list (ctx));
_MIR_get_temp_item_name (ctx, module, buff, sizeof (buff));
if (n->code == N_STR) {
data = MIR_new_string_data (ctx, buff, (MIR_str_t){n->u.s.len, n->u.s.s});
} else {
assert (n->code == N_STR16 || n->code == N_STR32);
if (n->code == N_STR16) {
data = MIR_new_data (ctx, buff, MIR_T_U16, n->u.s.len / 2, n->u.s.s);
} else {
data = MIR_new_data (ctx, buff, MIR_T_U32, n->u.s.len / 4, n->u.s.s);
}
}
move_item_to_module_start (module, data);
return data;
}
static void gen_initializer (c2m_ctx_t c2m_ctx, size_t init_start, op_t var,
const char *global_name, mir_size_t size, int local_p) {
gen_ctx_t gen_ctx = c2m_ctx->gen_ctx;
@ -10923,9 +11163,7 @@ static void gen_initializer (c2m_ctx_t c2m_ctx, size_t init_start, op_t var,
MIR_reg_t base;
MIR_type_t t;
MIR_item_t data;
MIR_module_t module;
struct expr *e;
char buff[50];
if (var.mir_op.mode == MIR_OP_REG) { /* scalar initialization: */
assert (local_p && offset == 0 && VARR_LENGTH (init_el_t, init_els) - init_start == 1);
@ -10950,9 +11188,13 @@ static void gen_initializer (c2m_ctx_t c2m_ctx, size_t init_start, op_t var,
val
= gen (c2m_ctx, init_el.init, NULL, NULL, t != MIR_T_UNDEF, t != MIR_T_UNDEF ? NULL : &val);
if (!scalar_type_p (init_el.el_type)) {
mir_size_t s = init_el.init->code == N_STR ? init_el.init->u.s.len
: raw_type_size (c2m_ctx, init_el.el_type);
mir_size_t s = init_el.init->code == N_STR
? init_el.init->u.s.len
: init_el.init->code == N_STR16
? init_el.init->u.s.len / 2
: init_el.init->code == N_STR32
? init_el.init->u.s.len / 4
: raw_type_size (c2m_ctx, init_el.el_type);
gen_memcpy (c2m_ctx, offset + rel_offset, base, val, s);
rel_offset = init_el.offset + s;
} else {
@ -10999,13 +11241,10 @@ static void gen_initializer (c2m_ctx_t c2m_ctx, size_t init_start, op_t var,
data = MIR_new_data (ctx, global_name, MIR_T_P, 1, &s);
data_size = _MIR_type_size (ctx, MIR_T_P);
} else {
if (def->code != N_STR) {
if (def->code != N_STR && def->code != N_STR16 && def->code != N_STR32) {
data = ((decl_t) def->attr)->item;
} else {
module = DLIST_TAIL (MIR_module_t, *MIR_get_module_list (ctx));
_MIR_get_temp_item_name (ctx, module, buff, sizeof (buff));
data = MIR_new_string_data (ctx, buff, (MIR_str_t){def->u.s.len, def->u.s.s});
move_item_to_module_start (module, data);
data = get_string_data (c2m_ctx, def);
}
data = MIR_new_ref_data (ctx, global_name, data, e->u.i_val);
data_size = _MIR_type_size (ctx, t);
@ -11068,10 +11307,7 @@ static void gen_initializer (c2m_ctx_t c2m_ctx, size_t init_start, op_t var,
if (data_size > str_len) MIR_new_bss (ctx, NULL, data_size - str_len);
}
} else {
module = DLIST_TAIL (MIR_module_t, *MIR_get_module_list (ctx));
_MIR_get_temp_item_name (ctx, module, buff, sizeof (buff));
data = MIR_new_string_data (ctx, buff, val.mir_op.u.str);
move_item_to_module_start (module, data);
data = get_mir_str_op_data (c2m_ctx, val.mir_op.u.str);
data = MIR_new_ref_data (ctx, global_name, data, 0);
data_size = _MIR_type_size (ctx, t);
}
@ -11201,6 +11437,10 @@ static op_t gen (c2m_ctx_t c2m_ctx, node_t r, MIR_label_t true_label, MIR_label_
: MIR_new_ldouble_op (ctx, ld)));
break;
case N_CH: ll = r->u.ch; goto int_val;
case N_CH16:
case N_CH32: ll = r->u.ul; goto int_val;
case N_STR16:
case N_STR32: res = new_op (NULL, MIR_new_ref_op (ctx, get_string_data (c2m_ctx, r))); break;
case N_STR:
res
= new_op (NULL,
@ -12400,7 +12640,8 @@ static const char *get_node_name (node_code_t code) {
switch (code) {
C (IGNORE);
REP8 (C, I, L, LL, U, UL, ULL, F, D);
REP8 (C, LD, CH, STR, ID, COMMA, ANDAND, OROR, EQ);
REP7 (C, LD, CH, CH16, CH32, STR, STR16, STR32);
REP5 (C, ID, COMMA, ANDAND, OROR, EQ);
REP8 (C, NE, LT, LE, GT, GE, ASSIGN, BITWISE_NOT, NOT);
REP8 (C, AND, AND_ASSIGN, OR, OR_ASSIGN, XOR, XOR_ASSIGN, LSH, LSH_ASSIGN);
REP8 (C, RSH, RSH_ASSIGN, ADD, ADD_ASSIGN, SUB, SUB_ASSIGN, MUL, MUL_ASSIGN);
@ -12420,19 +12661,31 @@ static const char *get_node_name (node_code_t code) {
#undef REP_SEP
}
static void print_char (FILE *f, int ch) {
static void print_char (FILE *f, mir_ulong ch) {
assert (ch >= 0);
if (ch == '"' || ch == '\"' || ch == '\\') fprintf (f, "\\");
if (isprint (ch))
fprintf (f, "%c", ch);
else
fprintf (f, "\\%o", ch);
if (ch >= 0x100) {
fprintf (f, ch <= 0xFFFF ? "\\u%04x" : "\\U%08x", (unsigned int) ch);
} else {
if (ch == '"' || ch == '\"' || ch == '\\') fprintf (f, "\\");
if (isprint (ch))
fprintf (f, "%c", (unsigned int) ch);
else
fprintf (f, "\\%o", (unsigned int) ch);
}
}
static void print_chars (FILE *f, const char *str, size_t len) {
for (size_t i = 0; i < len; i++) print_char (f, str[i]);
}
static void print_chars16 (FILE *f, const char *str, size_t len) {
for (size_t i = 0; i < len; i += 2) print_char (f, ((mir_char16 *) str)[i]);
}
static void print_chars32 (FILE *f, const char *str, size_t len) {
for (size_t i = 0; i < len; i += 4) print_char (f, ((mir_char32 *) str)[i]);
}
static void print_node (c2m_ctx_t c2m_ctx, FILE *f, node_t n, int indent, int attr_p);
void debug_node (c2m_ctx_t c2m_ctx, node_t n) { print_node (c2m_ctx, stderr, n, 0, TRUE); }
@ -12581,13 +12834,19 @@ static void print_node (c2m_ctx_t c2m_ctx, FILE *f, node_t n, int indent, int at
case N_D: fprintf (f, " %.*g", DBL_MANT_DIG, (double) n->u.d); goto expr;
case N_LD: fprintf (f, " %.*Lg", LDBL_MANT_DIG, (long double) n->u.ld); goto expr;
case N_CH:
fprintf (f, " '");
case N_CH16:
case N_CH32:
fprintf (f, " %s'", n->code == N_CH ? "" : n->code == N_CH16 ? "u" : "U");
print_char (f, n->u.ch);
fprintf (f, "'");
goto expr;
case N_STR:
fprintf (f, " \"");
print_chars (f, n->u.s.s, n->u.s.len);
case N_STR16:
case N_STR32:
fprintf (f, " %s\"", n->code == N_STR ? "" : n->code == N_STR16 ? "u" : "U");
(n->code == N_STR
? print_chars
: n->code == N_STR16 ? print_chars16 : print_chars32) (f, n->u.s.s, n->u.s.len);
fprintf (f, "\"");
goto expr;
case N_ID:

@ -28,12 +28,17 @@ typedef uint16_t mir_ushort;
typedef uint32_t mir_uint;
typedef uint64_t mir_ulong;
typedef uint64_t mir_ullong;
typedef uint32_t mir_wchar;
typedef uint16_t mir_char16;
typedef uint32_t mir_char32;
#define MIR_UCHAR_MAX UINT8_MAX
#define MIR_USHORT_MAX UINT16_MAX
#define MIR_UINT_MAX UINT32_MAX
#define MIR_ULONG_MAX UINT64_MAX
#define MIR_ULLONG_MAX UINT64_MAX
#define MIR_WCHAR_MIN 0
#define MIR_WCHAR_MAX UINT32_MAX
typedef mir_schar mir_char;
#define MIR_CHAR_MIN MIR_SCHAR_MIN

@ -28,12 +28,17 @@ typedef uint16_t mir_ushort;
typedef uint32_t mir_uint;
typedef uint64_t mir_ulong;
typedef uint64_t mir_ullong;
typedef uint32_t mir_wchar;
typedef uint16_t mir_char16;
typedef uint32_t mir_char32;
#define MIR_UCHAR_MAX UINT8_MAX
#define MIR_USHORT_MAX UINT16_MAX
#define MIR_UINT_MAX UINT32_MAX
#define MIR_ULONG_MAX UINT64_MAX
#define MIR_ULLONG_MAX UINT64_MAX
#define MIR_WCHAR_MIN 0
#define MIR_WCHAR_MAX UINT32_MAX
typedef mir_schar mir_char;
#define MIR_CHAR_MIN MIR_SCHAR_MIN

@ -322,7 +322,7 @@ static MIR_type_t get_blk_type (int n_qwords, MIR_type_t *qword_types) {
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]) {
switch ((int) qword_types[n]) {
case MIR_T_I8:
case MIR_T_I16:
case MIR_T_I32:
@ -334,10 +334,10 @@ static MIR_type_t get_blk_type (int n_qwords, MIR_type_t *qword_types) {
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;
if (n_iregs == n_qwords) return MIR_T_BLK + 1;
if (n_fregs == n_qwords) return MIR_T_BLK + 2;
if (qword_types[0] == MIR_T_F || qword_types[0] == MIR_T_D) return MIR_T_BLK + 4;
return MIR_T_BLK + 3;
}
static MIR_type_t target_get_blk_type (c2m_ctx_t c2m_ctx, struct type *arg_type) {

@ -35,21 +35,28 @@ typedef int64_t mir_llong;
typedef uint8_t mir_uchar;
typedef uint16_t mir_ushort;
typedef uint32_t mir_uint;
typedef uint64_t mir_ullong;
#ifdef _WIN32
typedef uint32_t mir_ulong;
typedef uint16_t mir_wchar;
#else
typedef uint64_t mir_ulong;
typedef uint32_t mir_wchar;
#endif
typedef uint64_t mir_ullong;
typedef uint16_t mir_char16;
typedef uint32_t mir_char32;
#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
#define MIR_WCHAR_MAX UINT16_MAX
#else
#define MIR_ULONG_MAX UINT64_MAX
#define MIR_WCHAR_MAX UINT32_MAX
#endif
#define MIR_WCHAR_MIN 0
#define MIR_ULLONG_MAX UINT64_MAX
typedef mir_schar mir_char;

@ -4,7 +4,7 @@
#define VA_LIST_IS_ARRAY_P 0
/* Small BLK..BLK5 (less or equal to two quadwords) args are passed in
/* Any small BLK type (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
@ -279,7 +279,7 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
VARR_CREATE (uint8_t, code, 128);
mir_assert (sizeof (long double) == 16);
for (size_t i = 0; i < nargs; i++) { /* caclulate offset for blk params */
for (size_t i = 0; i < nargs; i++) { /* calculate offset for blk params */
type = arg_descs[i].type;
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) {

@ -256,7 +256,7 @@ static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_insn) {
call_insn->ops[1] = temp_op;
gen_add_insn_before (gen_ctx, call_insn, new_insn);
}
for (size_t i = start; i < nops; i++) { /* caclulate offset for blk params */
for (size_t i = start; i < nops; i++) { /* calculate offset for blk params */
if (i - start < nargs) {
type = arg_vars[i - start].type;
} else if (call_insn->ops[i].mode == MIR_OP_MEM) {

@ -282,12 +282,12 @@ static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_insn) {
gen_assert (prev_call_insn != NULL); /* call_insn should not be 1st after simplification */
}
#ifndef _WIN32
if ((type == MIR_T_BLK2 && get_int_arg_reg (int_arg_num) != MIR_NON_HARD_REG
if ((type == MIR_T_BLK + 1 && 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
|| (type == MIR_T_BLK + 2 && 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_type_t mov_type = type == MIR_T_BLK + 1 ? 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);
@ -305,12 +305,12 @@ static void machinize_call (gen_ctx_t gen_ctx, MIR_insn_t call_insn) {
setup_call_hard_reg_args (gen_ctx, call_insn, reg2);
}
continue;
} else if ((type == MIR_T_BLK4 || type == MIR_T_BLK5)
} else if ((type == MIR_T_BLK + 3 || type == MIR_T_BLK + 4)
&& 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_type_t mov_type1 = type == MIR_T_BLK + 3 ? MIR_T_I64 : MIR_T_D;
MIR_type_t mov_type2 = type == MIR_T_BLK + 3 ? 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);
@ -717,12 +717,12 @@ static void target_machinize (gen_ctx_t gen_ctx) {
type = VARR_GET (MIR_var_t, func->vars, i).type;
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
if ((type == MIR_T_BLK + 1 && 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
|| (type == MIR_T_BLK + 2 && 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_type_t mov_type = type == MIR_T_BLK + 1 ? 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);
@ -740,12 +740,12 @@ static void target_machinize (gen_ctx_t gen_ctx) {
MIR_new_int_op (ctx, blk_size));
prepend_insn (gen_ctx, new_insn);
continue;
} else if ((type == MIR_T_BLK4 || type == MIR_T_BLK5)
} else if ((type == MIR_T_BLK + 3 || type == MIR_T_BLK + 4)
&& 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_type_t mov_type1 = type == MIR_T_BLK + 3 ? MIR_T_I64 : MIR_T_D;
MIR_type_t mov_type2 = type == MIR_T_BLK + 3 ? 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);

@ -401,11 +401,11 @@ static void generate_icode (MIR_context_t ctx, MIR_item_t func_item) {
mir_assert (ops[i].mode == MIR_OP_REF && ops[i].u.ref->item_type == MIR_proto_item);
v.a = ops[i].u.ref;
} else if (i == 1 && imm_call_p) {
mir_assert (ops[i].u.ref->item_type == MIR_import_item
|| ops[i].u.ref->item_type == MIR_export_item
|| ops[i].u.ref->item_type == MIR_forward_item
|| ops[i].u.ref->item_type == MIR_func_item);
v.a = ops[i].u.ref->addr;
MIR_item_t item = ops[i].u.ref;
mir_assert (item->item_type == MIR_import_item || item->item_type == MIR_export_item
|| item->item_type == MIR_forward_item || item->item_type == MIR_func_item);
v.a = item->addr;
} else if (code == MIR_VA_ARG && i == 2) { /* type */
mir_assert (ops[i].mode == MIR_OP_MEM);
v.i = ops[i].u.mem.type;
@ -830,10 +830,12 @@ static void finish_insn_trace (MIR_context_t ctx, MIR_full_insn_code_t code, cod
bp[ops[0].i].u, bp[ops[0].i].u);
break;
case MIR_OP_FLOAT: fprintf (stderr, "\t# res = %.*ef", FLT_DECIMAL_DIG, bp[ops[0].i].f); break;
case MIR_OP_DOUBLE: fprintf (stderr, "\t# res = %.*e", DBL_DECIMAL_DIG, bp[ops[0].i].d); break;
case MIR_OP_LDOUBLE:
#ifndef _WIN32
fprintf (stderr, "\t# res = %.*Le", LDBL_DECIMAL_DIG, bp[ops[0].i].ld);
break;
#endif
case MIR_OP_DOUBLE: fprintf (stderr, "\t# res = %.*e", DBL_DECIMAL_DIG, bp[ops[0].i].d); break;
default: assert (op_mode == MIR_OP_UNDEF);
}
fprintf (stderr, "\n");
@ -1261,8 +1263,37 @@ static void OPTIMIZE eval (MIR_context_t ctx, func_desc_t func_desc, MIR_val_t *
SCASE (MIR_DBGE, 3, BDCMP (>=));
SCASE (MIR_LDBGE, 3, BLDCMP (>=));
SCASE (MIR_CALL, 0, pc = call_insn_execute (ctx, pc, bp, ops, FALSE));
SCASE (IC_IMM_CALL, 0, pc = call_insn_execute (ctx, pc, bp, ops, TRUE));
CASE (MIR_CALL, 0) {
int (*func_addr) (void *buf) = *get_aop (bp, ops + 4);
if (func_addr != setjmp_addr) {
pc = call_insn_execute (ctx, pc, bp, ops, FALSE);
} else {
int64_t nops = get_i (ops); /* #args w/o nop, insn, and ff interface address */
MIR_item_t proto_item = get_a (ops + 3);
size_t start = proto_item->u.proto->nres + 5;
bp[get_i (ops + 5)].i = (*func_addr) (*get_aop (bp, ops + start));
pc += nops + 3; /* nops itself, the call insn, add ff interface address */
}
END_INSN;
}
CASE (IC_IMM_CALL, 0) {
int (*func_addr) (void *buf) = get_a (ops + 4);
if (func_addr != setjmp_addr) {
pc = call_insn_execute (ctx, pc, bp, ops, TRUE);
} else {
int64_t nops = get_i (ops); /* #args w/o nop, insn, and ff interface address */
MIR_item_t proto_item = get_a (ops + 3);
size_t start = proto_item->u.proto->nres + 5;
bp[get_i (ops + 5)].i = (*func_addr) (*get_aop (bp, ops + start));
pc += nops + 3; /* nops itself, the call insn, add ff interface address */
}
END_INSN;
}
SCASE (MIR_INLINE, 0, mir_assert (FALSE));
CASE (MIR_SWITCH, 0) {
@ -1497,14 +1528,11 @@ static void call (MIR_context_t ctx, MIR_val_t *bp, MIR_op_t *insn_arg_ops, code
case MIR_T_F: call_res_args[i + nres].f = arg_vals[i].f; break;
case MIR_T_D: call_res_args[i + nres].d = arg_vals[i].d; break;
case MIR_T_LD: call_res_args[i + nres].ld = arg_vals[i].ld; break;
case MIR_T_P:
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);
case MIR_T_P: call_res_args[i + nres].u = (uint64_t) arg_vals[i].a; break;
default:
mir_assert (MIR_all_blk_type_p (type));
call_res_args[i + nres].u = (uint64_t) arg_vals[i].a;
break;
}
}
((void (*) (void *, void *)) ff_interface_addr) (addr, call_res_args); /* call */
@ -1679,12 +1707,7 @@ static void interp (MIR_context_t ctx, MIR_item_t func_item, va_list va, MIR_val
case MIR_T_LD: arg_vals[i].ld = va_arg (va, long double); break;
case MIR_T_P:
case MIR_T_RBLK: arg_vals[i].a = va_arg (va, void *); break;
case MIR_T_BLK:
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);
default: mir_assert (MIR_blk_type_p (type)); 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
@ -1692,8 +1715,6 @@ static void interp (MIR_context_t ctx, MIR_item_t func_item, va_list va, MIR_val
#endif
break;
}
default: mir_assert (FALSE);
}
}
#if VA_LIST_IS_ARRAY_P
interp_arr_varg (ctx, func_item, results, nargs, arg_vals, va);

@ -2,8 +2,8 @@
Copyright (C) 2018-2020 Vladimir Makarov <vmakarov.gcc@gmail.com>.
*/
/* 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. */
/* All BLK type values 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 */

@ -4,7 +4,7 @@
/* Long doubles (-mlong-double=128) are always passed by its address (for args and results) */
/* BLK..BLK5 and RBLK args are always passed by address. */
/* All BLK type values and RBLK args are always passed by address. */
#if 0 && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#error "s390x works only in BE mode"

@ -3,11 +3,11 @@
*/
/* 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
BLK0 first is copied on the caller stack and passed implicitly.
BLK1 is passed in general regs
BLK2 is passed in fp regs
BLK3 is passed in gpr and then fpr
BLK4 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. */
@ -145,6 +145,7 @@ 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;
}
#endif
void va_end_interp_builtin (MIR_context_t ctx, void *p) {}
@ -292,6 +293,7 @@ static void gen_movxmm2 (VARR (uint8_t) * insn_varr, uint32_t offset, uint32_t r
addr[4] |= reg << 3;
}
#ifdef _WIN32
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 */
@ -301,6 +303,7 @@ static void gen_add (VARR (uint8_t) * insn_varr, uint32_t sp_offset, int reg) {
addr[2] |= (reg & 7) << 3;
if (reg > 7) addr[0] |= 4;
}
#endif
static void gen_st (VARR (uint8_t) * insn_varr, uint32_t sp_offset, int b64_p) {
static const uint8_t st_pat[] = {
@ -348,7 +351,7 @@ static void gen_st80 (VARR (uint8_t) * insn_varr, uint32_t src_offset) {
goto L if rax > 0) ...
rax=8; call *r11; sp+=offset
r10=mem[rbx,<offset>]; res_reg=mem[r10]; ...
pop rbx; push r12; ret. */
pop rbx; pop r12; ret. */
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[] = {
@ -359,21 +362,29 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
0x49, 0x89, 0xfb, /* mov $rdi, $r11 -- fun addr */
0x48, 0x89, 0xf3, /* mov $rsi, $rbx -- result/arg addresses */
#else
0x41, 0x54, /* pushq %r12 */
0x53, /* pushq %rbx */
0x48, 0x81, 0xec, 0, 0, 0, 0, /* subq <sp_offset>, %rsp */
0x49, 0x89, 0xcb, /* mov $rcx, $r11 -- fun addr */
0x48, 0x89, 0xd3, /* mov $rdx, $rbx -- result/arg addresses */
/* 0x0: */ 0x41, 0x54, /* pushq %r12 */
/* 0x2: */ 0x53, /* pushq %rbx */
/* 0x3: */ 0x55, /* push %rbp */
/* 0x4: */ 0x48, 0x89, 0xe5, /* mov %rsp,%rbp */
/* 0x7: */ 0x48, 0x81, 0xec, 0, 0, 0, 0, /* subq <sp_offset>, %rsp */
/* 0xe: */ 0x49, 0x89, 0xcb, /* mov $rcx, $r11 -- fun addr */
/* 0x11: */ 0x48, 0x89, 0xd3, /* mov $rdx, $rbx -- result/arg addresses */
#endif
};
static const uint8_t call_end[] = {
#ifndef _WIN32
0x48, 0xc7, 0xc0, 0x08, 0, 0, 0, /* mov $8, rax -- to save xmm varargs */
#endif
0x41, 0xff, 0xd3, /* callq *%r11 */
0x41, 0xff, 0xd3, /* callq *%r11 */
#ifndef _WIN32
0x48, 0x81, 0xc4, 0, 0, 0, 0, /* addq <sp_offset>, %rsp */
#endif
};
static const uint8_t epilog[] = {
#ifdef _WIN32 /* Strict form of windows epilogue for unwinding: */
0x48, 0x8d, 0x65, 0x0, /* lea 0x0(%rbp),%rsp */
0x5d, /* pop %rbp */
#endif
0x5b, /* pop %rbx */
0x41, 0x5c, /* pop %r12 */
0xc3, /* ret */
@ -423,7 +434,7 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
} 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) {
if (type == MIR_T_BLK + 1 && 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] */
@ -431,14 +442,14 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
n_iregs += qwords;
n_xregs += qwords;
continue;
} else if (type == MIR_T_BLK3 && n_xregs + qwords <= max_xregs) {
} else if (type == MIR_T_BLK + 2 && 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) {
} else if (type == MIR_T_BLK + 3 && 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] */
@ -447,7 +458,7 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
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) {
} else if (type == MIR_T_BLK + 4 && 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] */
@ -492,12 +503,19 @@ void *_MIR_get_ff_call (MIR_context_t ctx, size_t nres, MIR_type_t *res_types, s
if (blk_offset > sp_offset) sp_offset = blk_offset;
#endif
sp_offset = (sp_offset + 15) / 16 * 16;
sp_offset += 8;
#ifndef _WIN32
sp_offset += 8; /* align */
#endif
addr = VARR_ADDR (uint8_t, code);
#ifndef _WIN32
memcpy (addr + 6, &sp_offset, sizeof (uint32_t));
#else
memcpy (addr + 10, &sp_offset, sizeof (uint32_t));
#endif
addr = push_insns (code, call_end, sizeof (call_end));
#ifndef _WIN32
memcpy (addr + sizeof (call_end) - 4, &sp_offset, sizeof (uint32_t));
#ifdef _WIN32
#else
if (nres > 1)
MIR_get_error_func (ctx) (MIR_call_op_error,
"Windows x86-64 doesn't support multiple return values");
@ -550,27 +568,34 @@ void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handl
static const uint32_t hndl_offset = 0x4c;
static const uint32_t prep_stack_size = 208;
#else
/* 0: */ 0x4c, 0x8d, 0x44, 0x24, 0x08, /* lea 8(%rsp),%r8 */
/* 5: */ 0x53, /* push %rbx */
/* 6: */ 0x48, 0x81, 0xec, 0, 0, 0, 0, /* sub <n>,%rsp */
/* d: */ 0x48, 0x89, 0xe3, /* mov %rsp,%rbx */
/* 10: */ 0x49, 0x89, 0xe1, /* mov %rsp,%r9 */
/* 13: */ 0x48, 0x83, 0xec, 0x20, /* sub 32,%rsp */
/* 17: */ 0x48, 0xb9, 0, 0, 0, 0, 0, 0, 0, 0, /* movabs <ctx>,%rcx */
/* 21: */ 0x48, 0xba, 0, 0, 0, 0, 0, 0, 0, 0, /* movabs <func_item>,%rdx*/
/* 2b: */ 0x48, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, /* movabs <handler>,%rax */
/* 35: */ 0xff, 0xd0, /* callq *%rax */
/* 0: */ 0x53, /* push %rbx */
/* 1: */ 0x55, /* push %rbp */
/* 2: */ 0x48, 0x89, 0xe5, /* mov %rsp,%rbp */
/* 5: */ 0x4c, 0x8d, 0x44, 0x24, 0x18, /* lea 24(%rsp),%r8 */
/* a: */ 0x48, 0x81, 0xec, 0, 0, 0, 0, /* sub <n>,%rsp */
/* 11: */ 0x48, 0x89, 0xe3, /* mov %rsp,%rbx */
/* 14: */ 0x49, 0x89, 0xe1, /* mov %rsp,%r9 */
/* 17: */ 0x48, 0x83, 0xec, 0x20, /* sub 32,%rsp */
/* 1b: */ 0x48, 0xb9, 0, 0, 0, 0, 0, 0, 0, 0, /* movabs <ctx>,%rcx */
/* 25: */ 0x48, 0xba, 0, 0, 0, 0, 0, 0, 0, 0, /* movabs <func_item>,%rdx*/
/* 2f: */ 0x48, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, /* movabs <handler>,%rax */
/* 39: */ 0xff, 0xd0, /* callq *%rax */
};
static const uint32_t nres_offset = 0x09;
static const uint32_t ctx_offset = 0x19;
static const uint32_t func_offset = 0x23;
static const uint32_t hndl_offset = 0x2d;
static const uint32_t nres_offset = 0x0d;
static const uint32_t ctx_offset = 0x1d;
static const uint32_t func_offset = 0x27;
static const uint32_t hndl_offset = 0x31;
static const uint32_t prep_stack_size = 32;
#endif
static const uint8_t shim_end[] = {
#ifndef _WIN32
/* 0: */ 0x48, 0x81, 0xc4, 0, 0, 0, 0, /*add prep_stack_size+n,%rsp*/
/* 7: */ 0x5b, /*pop %rbx*/
/* 8: */ 0xc3, /*retq */
#else /* Strict form of windows epilogue for unwinding: */
/* 0 */ 0x48, 0x8d, 0x65, 0x0, /* lea 0x0(%rbp),%rsp */
/* 4: */ 0x5d, /* pop %rbp */
#endif
0x5b, /*pop %rbx*/
0xc3, /*retq */
};
static const uint8_t ld_pat[] = {0x48, 0x8b, 0x83, 0, 0, 0, 0}; /* mov <offset>(%rbx), %reg */
static const uint8_t movss_pat[]
@ -593,6 +618,9 @@ void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handl
push_insns (code, save_pat, sizeof (save_pat));
addr = push_insns (code, prepare_pat, sizeof (prepare_pat));
imm = nres * 16;
#ifdef _WIN32
imm += 8; /*align */
#endif
memcpy (addr + nres_offset, &imm, sizeof (uint32_t));
memcpy (addr + ctx_offset, &ctx, sizeof (void *));
memcpy (addr + func_offset, &func_item, sizeof (void *));
@ -632,8 +660,10 @@ void *_MIR_get_interp_shim (MIR_context_t ctx, MIR_item_t func_item, void *handl
offset += 16;
}
addr = push_insns (code, shim_end, sizeof (shim_end));
#ifndef _WIN32
imm = prep_stack_size + nres * 16;
memcpy (addr + 3, &imm, sizeof (uint32_t));
#endif
res = _MIR_publish_code (ctx, VARR_ADDR (uint8_t, code), VARR_LENGTH (uint8_t, code));
VARR_DESTROY (uint8_t, code);
return res;
@ -649,25 +679,33 @@ void *_MIR_get_wrapper (MIR_context_t ctx, MIR_item_t called_func, void *hook_ad
#endif
0x41, 0xff, 0xe2, /*jmpq *%r10 */
};
static const uint8_t call_pat[] = {
static const uint8_t call_pat[] =
#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 */
0x41, 0xff, 0xd2, /*callq *%r10 */
0x49, 0x89, 0xc2, /*mov %rax,%r10 */
{
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 */
0x41, 0xff, 0xd2, /* callq *%r10 */
0x49, 0x89, 0xc2, /* mov %rax,%r10 */
};
size_t call_func_offset = 2, ctx_offset = 12, hook_offset = 22;
#else
0x48, 0xba, 0, 0, 0, 0, 0, 0, 0, 0, /*movabs called_func,%rdx */
0x48, 0xb9, 0, 0, 0, 0, 0, 0, 0, 0, /*movabs ctx,%rcx */
0x49, 0xba, 0, 0, 0, 0, 0, 0, 0, 0, /*movabs <hook_address>,%r10*/
0x50, /*push %rax */
0x48, 0x83, 0xec, 0x20, /*sub 32,%rsp */
0x41, 0xff, 0xd2, /*callq *%r10 */
0x49, 0x89, 0xc2, /*mov %rax,%r10 */
0x48, 0x83, 0xc4, 0x20, /*add 32,%rsp */
0x58, /*pop %rax */
{
0x55, /* push %rbp */
0x48, 0x89, 0xe5, /* mov %rsp,%rbp */
0x48, 0xba, 0, 0, 0, 0, 0, 0, 0, 0, /* movabs called_func,%rdx */
0x48, 0xb9, 0, 0, 0, 0, 0, 0, 0, 0, /* movabs ctx,%rcx */
0x49, 0xba, 0, 0, 0, 0, 0, 0, 0, 0, /* movabs <hook_address>,%r10*/
0x50, /* push %rax */
0x48, 0x83, 0xec, 0x28, /* sub 40,%rsp */
0x41, 0xff, 0xd2, /* callq *%r10 */
0x49, 0x89, 0xc2, /* mov %rax,%r10 */
0x48, 0x83, 0xc4, 0x28, /* add 40,%rsp */
0x58, /* pop %rax */
0x5d, /* pop %rbp */
};
size_t call_func_offset = 6, ctx_offset = 16, hook_offset = 26;
#endif
};
uint8_t *addr;
VARR (uint8_t) * code;
void *res;
@ -678,9 +716,9 @@ void *_MIR_get_wrapper (MIR_context_t ctx, MIR_item_t called_func, void *hook_ad
#endif
push_insns (code, save_pat, sizeof (save_pat));
addr = push_insns (code, call_pat, sizeof (call_pat));
memcpy (addr + 2, &called_func, sizeof (void *));
memcpy (addr + 12, &ctx, sizeof (void *));
memcpy (addr + 22, &hook_address, sizeof (void *));
memcpy (addr + call_func_offset, &called_func, sizeof (void *));
memcpy (addr + ctx_offset, &ctx, sizeof (void *));
memcpy (addr + hook_offset, &hook_address, sizeof (void *));
push_insns (code, restore_pat, sizeof (restore_pat));
push_insns (code, wrap_end, sizeof (wrap_end));
res = _MIR_publish_code (ctx, VARR_ADDR (uint8_t, code), VARR_LENGTH (uint8_t, code));

@ -51,6 +51,7 @@ struct MIR_context {
struct io_ctx *io_ctx;
struct scan_ctx *scan_ctx;
struct interp_ctx *interp_ctx;
void *setjmp_addr; /* used in interpreter to call setjmp directly not from a shim and FFI */
};
#define ctx_mutex ctx->ctx_mutex
@ -66,6 +67,7 @@ struct MIR_context {
#define curr_label_num ctx->curr_label_num
#define all_modules ctx->all_modules
#define modules_to_link ctx->modules_to_link
#define setjmp_addr ctx->setjmp_addr
static void util_error (MIR_context_t ctx, const char *message);
#define MIR_VARR_ERROR util_error
@ -763,7 +765,10 @@ MIR_module_t MIR_new_module (MIR_context_t ctx, const char *name) {
DLIST (MIR_module_t) * MIR_get_module_list (MIR_context_t ctx) { return &all_modules; }
static const char *type_str (MIR_type_t tp) {
static const char *type_str (MIR_context_t ctx, MIR_type_t tp) {
int n;
char str[100];
switch (tp) {
case MIR_T_I8: return "i8";
case MIR_T_U8: return "u8";
@ -777,19 +782,19 @@ static const char *type_str (MIR_type_t tp) {
case MIR_T_D: return "d";
case MIR_T_LD: return "ld";
case MIR_T_P: return "p";
case MIR_T_BLK: return "blk";
case MIR_T_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 "";
default:
if (MIR_blk_type_p (tp) && (n = tp - MIR_T_BLK) >= 0 && n < MIR_BLK_NUM) {
sprintf (str, "blk%d", n);
return get_ctx_str (ctx, str);
}
return "";
}
}
const char *MIR_type_str (MIR_context_t ctx, MIR_type_t tp) {
const char *str = type_str (tp);
const char *str = type_str (ctx, tp);
if (strcmp (str, "") == 0)
MIR_get_error_func (ctx) (MIR_wrong_param_value_error, "MIR_type_str: wrong type");
@ -1264,7 +1269,7 @@ MIR_reg_t MIR_new_func_reg (MIR_context_t ctx, MIR_func_t func, MIR_type_t type,
if (type != MIR_T_I64 && type != MIR_T_F && type != MIR_T_D && type != MIR_T_LD)
MIR_get_error_func (ctx) (MIR_reg_type_error, "wrong type for register %s: got '%s'", name,
type_str (type));
type_str (ctx, type));
mir_assert (func != NULL);
res = create_func_reg (ctx, func, name, VARR_LENGTH (MIR_var_t, func->vars) + 1, type, FALSE,
&stored_name);
@ -1576,8 +1581,8 @@ void MIR_load_module (MIR_context_t ctx, MIR_module_t m) {
} else if (item->item_type == MIR_func_item) {
if (item->addr == NULL) {
item->addr = _MIR_get_thunk (ctx);
#ifdef MIR_DEBUG
fprintf (stderr, "%016lx: %s\n", (size_t) item->addr, item->u.func->name);
#if defined(MIR_DEBUG)
fprintf (stderr, "%016llx: %s\n", (unsigned long long) item->addr, item->u.func->name);
#endif
}
_MIR_redirect_thunk (ctx, item->addr, undefined_interface);
@ -1592,7 +1597,12 @@ void MIR_load_module (MIR_context_t ctx, MIR_module_t m) {
VARR_PUSH (MIR_module_t, modules_to_link, m);
}
#define SETJMP_NAME "setjmp"
#define SETJMP_NAME2 "_setjmp"
void MIR_load_external (MIR_context_t ctx, const char *name, void *addr) {
if (strcmp (name, SETJMP_NAME) == 0 || (SETJMP_NAME2 != NULL && strcmp (name, SETJMP_NAME2) == 0))
setjmp_addr = addr;
setup_global (ctx, name, addr, NULL);
}
@ -1998,7 +2008,7 @@ MIR_reg_t _MIR_new_temp_reg (MIR_context_t ctx, MIR_type_t type, MIR_func_t func
if (type != MIR_T_I64 && type != MIR_T_F && type != MIR_T_D && type != MIR_T_LD)
MIR_get_error_func (ctx) (MIR_reg_type_error, "wrong type %s for temporary register",
type_str (type));
type_str (ctx, type));
mir_assert (func != NULL);
for (;;) {
func->last_temp_num++;
@ -2398,7 +2408,9 @@ void MIR_change_module_ctx (MIR_context_t old_ctx, MIR_module_t m, MIR_context_t
}
}
static void output_type (FILE *f, MIR_type_t tp) { fprintf (f, "%s", MIR_type_str (NULL, tp)); }
static void output_type (MIR_context_t ctx, FILE *f, MIR_type_t tp) {
fprintf (f, "%s", MIR_type_str (ctx, tp));
}
static void output_disp (FILE *f, MIR_disp_t disp) { fprintf (f, "%" PRId64, (int64_t) disp); }
@ -2451,7 +2463,7 @@ void MIR_output_op (MIR_context_t ctx, FILE *f, MIR_op_t op, MIR_func_t func) {
case MIR_OP_HARD_REG_MEM: {
MIR_reg_t no_reg = op.mode == MIR_OP_MEM ? 0 : MIR_NON_HARD_REG;
output_type (f, op.u.mem.type);
output_type (ctx, f, op.u.mem.type);
fprintf (f, ":");
if (op.u.mem.disp != 0 || (op.u.mem.base == no_reg && op.u.mem.index == no_reg))
output_disp (f, op.u.mem.disp);
@ -2510,23 +2522,23 @@ void MIR_output_insn (MIR_context_t ctx, FILE *f, MIR_insn_t insn, MIR_func_t fu
if (newline_p) fprintf (f, "\n");
}
static void output_func_proto (FILE *f, size_t nres, MIR_type_t *types, size_t nargs,
VARR (MIR_var_t) * args, int vararg_p) {
static void output_func_proto (MIR_context_t ctx, FILE *f, size_t nres, MIR_type_t *types,
size_t nargs, VARR (MIR_var_t) * args, int vararg_p) {
size_t i;
MIR_var_t var;
for (i = 0; i < nres; i++) {
if (i != 0) fprintf (f, ", ");
fprintf (f, "%s", MIR_type_str (NULL, types[i]));
fprintf (f, "%s", MIR_type_str (ctx, types[i]));
}
for (i = 0; i < nargs; i++) {
var = VARR_GET (MIR_var_t, args, i);
if (i != 0 || nres != 0) fprintf (f, ", ");
mir_assert (var.name != NULL);
if (!MIR_all_blk_type_p (var.type))
fprintf (f, "%s:%s", MIR_type_str (NULL, var.type), var.name);
fprintf (f, "%s:%s", MIR_type_str (ctx, var.type), var.name);
else
fprintf (f, "%s:%lu(%s)", MIR_type_str (NULL, var.type), (unsigned long) var.size, var.name);
fprintf (f, "%s:%lu(%s)", MIR_type_str (ctx, var.type), (unsigned long) var.size, var.name);
}
if (vararg_p) fprintf (f, nargs == 0 && nres == 0 ? "..." : ", ...");
fprintf (f, "\n");
@ -2575,7 +2587,7 @@ void MIR_output_item (MIR_context_t ctx, FILE *f, MIR_item_t item) {
if (item->item_type == MIR_data_item) {
data = item->u.data;
if (data->name != NULL) fprintf (f, "%s:", data->name);
fprintf (f, "\t%s\t", MIR_type_str (NULL, data->el_type));
fprintf (f, "\t%s\t", MIR_type_str (ctx, data->el_type));
for (size_t i = 0; i < data->nel; i++) {
switch (data->el_type) {
case MIR_T_I8: fprintf (f, "%" PRId8, ((int8_t *) data->u.els)[i]); break;
@ -2607,13 +2619,13 @@ void MIR_output_item (MIR_context_t ctx, FILE *f, MIR_item_t item) {
if (item->item_type == MIR_proto_item) {
proto = item->u.proto;
fprintf (f, "%s:\tproto\t", proto->name);
output_func_proto (f, proto->nres, proto->res_types, VARR_LENGTH (MIR_var_t, proto->args),
output_func_proto (ctx, f, proto->nres, proto->res_types, VARR_LENGTH (MIR_var_t, proto->args),
proto->args, proto->vararg_p);
return;
}
func = item->u.func;
fprintf (f, "%s:\tfunc\t", func->name);
output_func_proto (f, func->nres, func->res_types, func->nargs, func->vars, func->vararg_p);
output_func_proto (ctx, f, func->nres, func->res_types, func->nargs, func->vars, func->vararg_p);
nlocals = VARR_LENGTH (MIR_var_t, func->vars) - func->nargs;
for (i = 0; i < nlocals; i++) {
var = VARR_GET (MIR_var_t, func->vars, i + func->nargs);
@ -2621,7 +2633,7 @@ void MIR_output_item (MIR_context_t ctx, FILE *f, MIR_item_t item) {
if (i != 0) fprintf (f, "\n");
fprintf (f, "\tlocal\t");
}
fprintf (f, i % 8 == 0 ? "%s:%s" : ", %s:%s", MIR_type_str (NULL, var.type), var.name);
fprintf (f, i % 8 == 0 ? "%s:%s" : ", %s:%s", MIR_type_str (ctx, var.type), var.name);
}
fprintf (f, "\n# %u arg%s, %u local%s\n", func->nargs, func->nargs == 1 ? "" : "s",
(unsigned) nlocals, nlocals == 1 ? "" : "s");
@ -3790,8 +3802,9 @@ 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),
REP8 (TAG_EL, TF, TD, TP, TV, TBLOCK, TBLOCK2, TBLOCK3, TBLOCK4),
REP3 (TAG_EL, TBLOCK5, TRBLOCK, EOI),
REP5 (TAG_EL, TF, TD, TP, TV, TBLOCK),
TAG_EL (TRBLOCK) = TAG_EL (TBLOCK) + MIR_BLK_NUM,
TAG_EL (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,
@ -4515,11 +4528,15 @@ 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)
REP8 (TAG_CASE, TF, TD, TP, TV, TBLOCK, TBLOCK2, TBLOCK3, TBLOCK4)
REP2 (TAG_CASE, TBLOCK5, TRBLOCK)
REP5 (TAG_CASE, TF, TD, TP, TV, 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);
default:
if (TAG_TBLOCK <= c && c < TAG_TBLOCK + MIR_BLK_NUM) {
attr->t = (MIR_type_t) (c - TAG_TBLOCK) + MIR_T_BLK;
break;
}
MIR_get_error_func (ctx) (MIR_binary_io_error, "wrong tag %d", c);
}
return c;
}
@ -4841,7 +4858,7 @@ void MIR_read_with_func (MIR_context_t ctx, int (*const reader) (MIR_context_t))
default:
MIR_get_error_func (ctx) (MIR_binary_io_error,
"data type %s does not correspond value type",
type_str (type));
type_str (ctx, type));
}
break;
case TAG_I1:
@ -4872,28 +4889,28 @@ void MIR_read_with_func (MIR_context_t ctx, int (*const reader) (MIR_context_t))
default:
MIR_get_error_func (ctx) (MIR_binary_io_error,
"data type %s does not correspond value type",
type_str (type));
type_str (ctx, type));
}
break;
case TAG_F:
if (type != MIR_T_F)
MIR_get_error_func (ctx) (MIR_binary_io_error,
"data type %s does not correspond value type",
type_str (type));
type_str (ctx, type));
push_data (ctx, (uint8_t *) &attr.f, sizeof (float));
break;
case TAG_D:
if (type != MIR_T_D)
MIR_get_error_func (ctx) (MIR_binary_io_error,
"data type %s does not correspond value type",
type_str (type));
type_str (ctx, type));
push_data (ctx, (uint8_t *) &attr.d, sizeof (double));
break;
case TAG_LD:
if (type != MIR_T_LD)
MIR_get_error_func (ctx) (MIR_binary_io_error,
"data type %s does not correspond value type",
type_str (type));
type_str (ctx, type));
push_data (ctx, (uint8_t *) &attr.ld, sizeof (long double));
break;
/* ??? ptr */
@ -4965,6 +4982,7 @@ void MIR_read (MIR_context_t ctx, FILE *f) {
}
static void io_init (MIR_context_t ctx) {
mir_assert (TAG_EOFILE < 127); /* see bin_tag_t */
if ((ctx->io_ctx = malloc (sizeof (struct io_ctx))) == NULL)
MIR_get_error_func (ctx) (MIR_alloc_error, "Not enough memory for ctx");
VARR_CREATE (MIR_var_t, proto_vars, 0);
@ -5401,11 +5419,11 @@ static MIR_type_t str2type (const char *type_name) {
if (strcmp (type_name, "u16") == 0) return MIR_T_U16;
if (strcmp (type_name, "i8") == 0) return MIR_T_I8;
if (strcmp (type_name, "u8") == 0) return MIR_T_U8;
if (strcmp (type_name, "blk") == 0) return MIR_T_BLK;
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 (strncmp (type_name, "blk", 3) == 0) {
int i, n = 0;
for (i = 3; isdigit (type_name[i]) && n < MIR_BLK_NUM; i++) n = n * 10 + (type_name[i] - '0');
if (type_name[i] == 0 && n < MIR_BLK_NUM) return MIR_T_BLK + n;
}
if (strcmp (type_name, "rblk") == 0) return MIR_T_RBLK;
return MIR_T_BOUND;
}

@ -176,11 +176,13 @@ typedef enum {
#define TYPE_EL(t) MIR_T_##t
#define MIR_BLK_NUM 5
/* Data types: */
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 */
REP7 (TYPE_EL, P, BLK, BLK2, BLK3, BLK4, BLK5, RBLK), /* Pointer, (return) memory block */
REP2 (TYPE_EL, P, BLK), /* Pointer, memory blocks */
TYPE_EL (RBLK) = TYPE_EL (BLK) + MIR_BLK_NUM, /* return block */
REP2 (TYPE_EL, UNDEF, BOUND),
} MIR_type_t;
@ -190,7 +192,7 @@ 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 MIR_T_BLK <= t && t <= MIR_T_BLK5; }
static inline int MIR_blk_type_p (MIR_type_t t) { return MIR_T_BLK <= t && t < MIR_T_RBLK; }
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

Loading…
Cancel
Save