macro optimization - string constant optimisation
This commit is contained in:
parent
ab4da04aa9
commit
8ecc9cd789
1 changed files with 174 additions and 158 deletions
332
tcc.c
332
tcc.c
|
@ -588,8 +588,8 @@ void vswap(void);
|
||||||
void vdup(void);
|
void vdup(void);
|
||||||
int get_reg(int rc);
|
int get_reg(int rc);
|
||||||
|
|
||||||
void macro_subst(TokenString *tok_str,
|
static void macro_subst(TokenString *tok_str,
|
||||||
Sym **nested_list, int *macro_str);
|
Sym **nested_list, int *macro_str);
|
||||||
int save_reg_forced(int r);
|
int save_reg_forced(int r);
|
||||||
void gen_op(int op);
|
void gen_op(int op);
|
||||||
void force_charshort_cast(int t);
|
void force_charshort_cast(int t);
|
||||||
|
@ -2727,7 +2727,7 @@ int *macro_arg_subst(Sym **nested_list, int *macro_str, Sym *args)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* handle the '##' operator */
|
/* handle the '##' operator */
|
||||||
int *macro_twosharps(int *macro_str)
|
static int *macro_twosharps(void)
|
||||||
{
|
{
|
||||||
TokenSym *ts;
|
TokenSym *ts;
|
||||||
int *macro_ptr1;
|
int *macro_ptr1;
|
||||||
|
@ -2771,164 +2771,170 @@ int *macro_twosharps(int *macro_str)
|
||||||
return macro_str1.str;
|
return macro_str1.str;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* do macro substitution of macro_str and add result to
|
|
||||||
(tok_str,tok_len). If macro_str is NULL, then input stream token is
|
/* do macro substitution of current token with macro 's' and add
|
||||||
substituted. 'nested_list' is the list of all macros we got inside
|
result to (tok_str,tok_len). 'nested_list' is the list of all
|
||||||
to avoid recursing. */
|
macros we got inside to avoid recursing. Return non zero if no
|
||||||
void macro_subst(TokenString *tok_str,
|
substitution needs to be done */
|
||||||
Sym **nested_list, int *macro_str)
|
static int macro_subst_tok(TokenString *tok_str,
|
||||||
|
Sym **nested_list, Sym *s)
|
||||||
{
|
{
|
||||||
Sym *s, *args, *sa, *sa1;
|
Sym *args, *sa, *sa1;
|
||||||
int parlevel, *mstr, t, *saved_macro_ptr;
|
int mstr_allocated, parlevel, *mstr, t;
|
||||||
int mstr_allocated, *macro_str1;
|
|
||||||
CString cstr;
|
|
||||||
CValue cval;
|
|
||||||
TokenString str;
|
TokenString str;
|
||||||
char *cstrval;
|
char *cstrval;
|
||||||
|
CValue cval;
|
||||||
|
CString cstr;
|
||||||
|
|
||||||
|
/* if symbol is a macro, prepare substitution */
|
||||||
|
/* if nested substitution, do nothing */
|
||||||
|
if (sym_find2(*nested_list, tok))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* special macros */
|
||||||
|
if (tok == TOK___LINE__) {
|
||||||
|
cval.i = file->line_num;
|
||||||
|
tok_str_add2(tok_str, TOK_CINT, &cval);
|
||||||
|
} else if (tok == TOK___FILE__) {
|
||||||
|
cstrval = file->filename;
|
||||||
|
goto add_cstr;
|
||||||
|
tok_str_add2(tok_str, TOK_STR, &cval);
|
||||||
|
} else if (tok == TOK___DATE__) {
|
||||||
|
cstrval = "Jan 1 2002";
|
||||||
|
goto add_cstr;
|
||||||
|
} else if (tok == TOK___TIME__) {
|
||||||
|
cstrval = "00:00:00";
|
||||||
|
add_cstr:
|
||||||
|
cstr_new(&cstr);
|
||||||
|
cstr_cat(&cstr, cstrval);
|
||||||
|
cstr_ccat(&cstr, '\0');
|
||||||
|
cval.cstr = &cstr;
|
||||||
|
tok_str_add2(tok_str, TOK_STR, &cval);
|
||||||
|
cstr_free(&cstr);
|
||||||
|
} else {
|
||||||
|
mstr = (int *)s->c;
|
||||||
|
mstr_allocated = 0;
|
||||||
|
if (s->t == MACRO_FUNC) {
|
||||||
|
/* NOTE: we do not use next_nomacro to avoid eating the
|
||||||
|
next token. XXX: find better solution */
|
||||||
|
if (macro_ptr) {
|
||||||
|
t = *macro_ptr;
|
||||||
|
} else {
|
||||||
|
while (is_space(ch) || ch == '\n')
|
||||||
|
cinp();
|
||||||
|
t = ch;
|
||||||
|
}
|
||||||
|
if (t != '(') /* no macro subst */
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* argument macro */
|
||||||
|
next_nomacro();
|
||||||
|
next_nomacro();
|
||||||
|
args = NULL;
|
||||||
|
sa = s->next;
|
||||||
|
/* NOTE: empty args are allowed, except if no args */
|
||||||
|
for(;;) {
|
||||||
|
/* handle '()' case */
|
||||||
|
if (!args && tok == ')')
|
||||||
|
break;
|
||||||
|
if (!sa)
|
||||||
|
error("macro '%s' used with too many args",
|
||||||
|
get_tok_str(s->v, 0));
|
||||||
|
tok_str_new(&str);
|
||||||
|
parlevel = 0;
|
||||||
|
/* NOTE: non zero sa->t indicates VA_ARGS */
|
||||||
|
while ((parlevel > 0 ||
|
||||||
|
(tok != ')' &&
|
||||||
|
(tok != ',' || sa->t))) &&
|
||||||
|
tok != -1) {
|
||||||
|
if (tok == '(')
|
||||||
|
parlevel++;
|
||||||
|
else if (tok == ')')
|
||||||
|
parlevel--;
|
||||||
|
tok_str_add2(&str, tok, &tokc);
|
||||||
|
next_nomacro();
|
||||||
|
}
|
||||||
|
tok_str_add(&str, 0);
|
||||||
|
sym_push2(&args, sa->v & ~SYM_FIELD, sa->t, (int)str.str);
|
||||||
|
sa = sa->next;
|
||||||
|
if (tok == ')') {
|
||||||
|
/* special case for gcc var args: add an empty
|
||||||
|
var arg argument if it is omitted */
|
||||||
|
if (sa && sa->t && gnu_ext)
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (tok != ',')
|
||||||
|
expect(",");
|
||||||
|
next_nomacro();
|
||||||
|
}
|
||||||
|
if (sa) {
|
||||||
|
error("macro '%s' used with too few args",
|
||||||
|
get_tok_str(s->v, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now subst each arg */
|
||||||
|
mstr = macro_arg_subst(nested_list, mstr, args);
|
||||||
|
/* free memory */
|
||||||
|
sa = args;
|
||||||
|
while (sa) {
|
||||||
|
sa1 = sa->prev;
|
||||||
|
tok_str_free((int *)sa->c);
|
||||||
|
tcc_free(sa);
|
||||||
|
sa = sa1;
|
||||||
|
}
|
||||||
|
mstr_allocated = 1;
|
||||||
|
}
|
||||||
|
sym_push2(nested_list, s->v, 0, 0);
|
||||||
|
macro_subst(tok_str, nested_list, mstr);
|
||||||
|
/* pop nested defined symbol */
|
||||||
|
sa1 = *nested_list;
|
||||||
|
*nested_list = sa1->prev;
|
||||||
|
tcc_free(sa1);
|
||||||
|
if (mstr_allocated)
|
||||||
|
tok_str_free(mstr);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* do macro substitution of macro_str and add result to
|
||||||
|
(tok_str,tok_len). 'nested_list' is the list of all macros we got
|
||||||
|
inside to avoid recursing. */
|
||||||
|
static void macro_subst(TokenString *tok_str,
|
||||||
|
Sym **nested_list, int *macro_str)
|
||||||
|
{
|
||||||
|
Sym *s;
|
||||||
|
int *saved_macro_ptr;
|
||||||
|
int *macro_str1;
|
||||||
|
|
||||||
saved_macro_ptr = macro_ptr;
|
saved_macro_ptr = macro_ptr;
|
||||||
macro_ptr = macro_str;
|
macro_ptr = macro_str;
|
||||||
macro_str1 = NULL;
|
/* first scan for '##' operator handling */
|
||||||
if (macro_str) {
|
macro_str1 = macro_twosharps();
|
||||||
/* first scan for '##' operator handling */
|
macro_ptr = macro_str1;
|
||||||
macro_str1 = macro_twosharps(macro_str);
|
|
||||||
macro_ptr = macro_str1;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
next_nomacro();
|
next_nomacro();
|
||||||
if (tok == 0)
|
if (tok == 0)
|
||||||
break;
|
break;
|
||||||
if ((s = sym_find1(&define_stack, tok)) != NULL) {
|
s = sym_find1(&define_stack, tok);
|
||||||
/* if symbol is a macro, prepare substitution */
|
if (s != NULL) {
|
||||||
/* if nested substitution, do nothing */
|
if (macro_subst_tok(tok_str, nested_list, s) != 0)
|
||||||
if (sym_find2(*nested_list, tok))
|
|
||||||
goto no_subst;
|
goto no_subst;
|
||||||
|
|
||||||
/* special macros */
|
|
||||||
if (tok == TOK___LINE__) {
|
|
||||||
cval.i = file->line_num;
|
|
||||||
tok_str_add2(tok_str, TOK_CINT, &cval);
|
|
||||||
} else if (tok == TOK___FILE__) {
|
|
||||||
cstrval = file->filename;
|
|
||||||
goto add_cstr;
|
|
||||||
tok_str_add2(tok_str, TOK_STR, &cval);
|
|
||||||
} else if (tok == TOK___DATE__) {
|
|
||||||
cstrval = "Jan 1 2002";
|
|
||||||
goto add_cstr;
|
|
||||||
} else if (tok == TOK___TIME__) {
|
|
||||||
cstrval = "00:00:00";
|
|
||||||
add_cstr:
|
|
||||||
cstr_new(&cstr);
|
|
||||||
cstr_cat(&cstr, cstrval);
|
|
||||||
cstr_ccat(&cstr, '\0');
|
|
||||||
cval.cstr = &cstr;
|
|
||||||
tok_str_add2(tok_str, TOK_STR, &cval);
|
|
||||||
cstr_free(&cstr);
|
|
||||||
} else {
|
|
||||||
mstr = (int *)s->c;
|
|
||||||
mstr_allocated = 0;
|
|
||||||
if (s->t == MACRO_FUNC) {
|
|
||||||
/* NOTE: we do not use next_nomacro to avoid eating the
|
|
||||||
next token. XXX: find better solution */
|
|
||||||
if (macro_ptr) {
|
|
||||||
t = *macro_ptr;
|
|
||||||
} else {
|
|
||||||
while (is_space(ch) || ch == '\n')
|
|
||||||
cinp();
|
|
||||||
t = ch;
|
|
||||||
}
|
|
||||||
if (t != '(') /* no macro subst */
|
|
||||||
goto no_subst;
|
|
||||||
|
|
||||||
/* argument macro */
|
|
||||||
next_nomacro();
|
|
||||||
next_nomacro();
|
|
||||||
args = NULL;
|
|
||||||
sa = s->next;
|
|
||||||
/* NOTE: empty args are allowed, except if no args */
|
|
||||||
for(;;) {
|
|
||||||
/* handle '()' case */
|
|
||||||
if (!args && tok == ')')
|
|
||||||
break;
|
|
||||||
if (!sa)
|
|
||||||
error("macro '%s' used with too many args",
|
|
||||||
get_tok_str(s->v, 0));
|
|
||||||
tok_str_new(&str);
|
|
||||||
parlevel = 0;
|
|
||||||
/* NOTE: non zero sa->t indicates VA_ARGS */
|
|
||||||
while ((parlevel > 0 ||
|
|
||||||
(tok != ')' &&
|
|
||||||
(tok != ',' || sa->t))) &&
|
|
||||||
tok != -1) {
|
|
||||||
if (tok == '(')
|
|
||||||
parlevel++;
|
|
||||||
else if (tok == ')')
|
|
||||||
parlevel--;
|
|
||||||
tok_str_add2(&str, tok, &tokc);
|
|
||||||
next_nomacro();
|
|
||||||
}
|
|
||||||
tok_str_add(&str, 0);
|
|
||||||
sym_push2(&args, sa->v & ~SYM_FIELD, sa->t, (int)str.str);
|
|
||||||
sa = sa->next;
|
|
||||||
if (tok == ')') {
|
|
||||||
/* special case for gcc var args: add an empty
|
|
||||||
var arg argument if it is omitted */
|
|
||||||
if (sa && sa->t && gnu_ext)
|
|
||||||
continue;
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (tok != ',')
|
|
||||||
expect(",");
|
|
||||||
next_nomacro();
|
|
||||||
}
|
|
||||||
if (sa) {
|
|
||||||
error("macro '%s' used with too few args",
|
|
||||||
get_tok_str(s->v, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* now subst each arg */
|
|
||||||
mstr = macro_arg_subst(nested_list, mstr, args);
|
|
||||||
/* free memory */
|
|
||||||
sa = args;
|
|
||||||
while (sa) {
|
|
||||||
sa1 = sa->prev;
|
|
||||||
tok_str_free((int *)sa->c);
|
|
||||||
tcc_free(sa);
|
|
||||||
sa = sa1;
|
|
||||||
}
|
|
||||||
mstr_allocated = 1;
|
|
||||||
}
|
|
||||||
sym_push2(nested_list, s->v, 0, 0);
|
|
||||||
macro_subst(tok_str, nested_list, mstr);
|
|
||||||
/* pop nested defined symbol */
|
|
||||||
sa1 = *nested_list;
|
|
||||||
*nested_list = sa1->prev;
|
|
||||||
tcc_free(sa1);
|
|
||||||
if (mstr_allocated)
|
|
||||||
tok_str_free(mstr);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
no_subst:
|
no_subst:
|
||||||
/* no need to add if reading input stream */
|
|
||||||
if (!macro_str)
|
|
||||||
return;
|
|
||||||
tok_str_add2(tok_str, tok, &tokc);
|
tok_str_add2(tok_str, tok, &tokc);
|
||||||
}
|
}
|
||||||
/* only replace one macro while parsing input stream */
|
|
||||||
if (!macro_str)
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
macro_ptr = saved_macro_ptr;
|
macro_ptr = saved_macro_ptr;
|
||||||
if (macro_str1)
|
tok_str_free(macro_str1);
|
||||||
tok_str_free(macro_str1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return next token with macro substitution */
|
/* return next token with macro substitution */
|
||||||
void next(void)
|
void next(void)
|
||||||
{
|
{
|
||||||
Sym *nested_list;
|
Sym *nested_list, *s;
|
||||||
TokenString str;
|
TokenString str;
|
||||||
|
|
||||||
/* special 'ungettok' case for label parsing */
|
/* special 'ungettok' case for label parsing */
|
||||||
|
@ -2938,23 +2944,26 @@ void next(void)
|
||||||
tok1 = 0;
|
tok1 = 0;
|
||||||
} else {
|
} else {
|
||||||
redo:
|
redo:
|
||||||
|
next_nomacro();
|
||||||
if (!macro_ptr) {
|
if (!macro_ptr) {
|
||||||
/* if not reading from macro substituted string, then try
|
/* if not reading from macro substituted string, then try
|
||||||
to substitute */
|
to substitute macros */
|
||||||
/* XXX: optimize non macro case */
|
if (tok >= TOK_IDENT) {
|
||||||
tok_str_new(&str);
|
s = sym_find1(&define_stack, tok);
|
||||||
nested_list = NULL;
|
if (s) {
|
||||||
macro_subst(&str, &nested_list, NULL);
|
/* we have a macro: we try to substitute */
|
||||||
if (str.str) {
|
tok_str_new(&str);
|
||||||
tok_str_add(&str, 0);
|
nested_list = NULL;
|
||||||
macro_ptr = str.str;
|
if (macro_subst_tok(&str, &nested_list, s) == 0) {
|
||||||
macro_ptr_allocated = str.str;
|
/* substitution done, NOTE: maybe empty */
|
||||||
goto redo;
|
tok_str_add(&str, 0);
|
||||||
|
macro_ptr = str.str;
|
||||||
|
macro_ptr_allocated = str.str;
|
||||||
|
goto redo;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (tok == 0)
|
|
||||||
goto redo;
|
|
||||||
} else {
|
} else {
|
||||||
next_nomacro();
|
|
||||||
if (tok == 0) {
|
if (tok == 0) {
|
||||||
/* end of macro string: free it */
|
/* end of macro string: free it */
|
||||||
tok_str_free(macro_ptr_allocated);
|
tok_str_free(macro_ptr_allocated);
|
||||||
|
@ -6226,13 +6235,20 @@ static void decl_initializer(int t, Section *sec, unsigned long c,
|
||||||
if (!size_only) {
|
if (!size_only) {
|
||||||
if (cstr_len > nb)
|
if (cstr_len > nb)
|
||||||
warning("initializer-string for array is too long");
|
warning("initializer-string for array is too long");
|
||||||
for(i=0;i<nb;i++) {
|
/* in order to go faster for common case (char
|
||||||
if (tok == TOK_STR)
|
string in global variable, we handle it
|
||||||
ch = ((unsigned char *)cstr->data)[i];
|
specifically */
|
||||||
else
|
if (sec && tok == TOK_STR && size1 == 1) {
|
||||||
ch = ((int *)cstr->data)[i];
|
memcpy(sec->data + c + array_length, cstr->data, nb);
|
||||||
init_putv(t1, sec, c + (array_length + i) * size1,
|
} else {
|
||||||
ch, EXPR_VAL);
|
for(i=0;i<nb;i++) {
|
||||||
|
if (tok == TOK_STR)
|
||||||
|
ch = ((unsigned char *)cstr->data)[i];
|
||||||
|
else
|
||||||
|
ch = ((int *)cstr->data)[i];
|
||||||
|
init_putv(t1, sec, c + (array_length + i) * size1,
|
||||||
|
ch, EXPR_VAL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
array_length += nb;
|
array_length += nb;
|
||||||
|
|
Loading…
Reference in a new issue