mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-22 12:31:10 +00:00
[qfcc] Build the Ruamoko function parameters
The parameter defs are allocated from the parameter space using a minimum alignment of 4, and varargs functions get a va_list struct in place of the ... An "args" expression is unconditionally injected into the call arguments list at the place where ... is in the list, with arguments passed through ... coming after the ... Arguments get through to functions now, but there's problems with taking the address of local variables: currently done using constant pointer defs, which can't work for the base register addressing used in Ruamoko progs. With the update to test-bi's printf (and a hack to qfcc for lea), triangle.r actually works, printing the expected results (but -1 instead of 1 for equality, though that too is actually expected). qfcc will take a bit longer because it seems there are some design issues in address expressions (ambiguity, and a few other things) that have pretty much always been there.
This commit is contained in:
parent
7e147e703c
commit
37f08f9d4f
9 changed files with 200 additions and 31 deletions
|
@ -495,7 +495,7 @@ PR_SetupParams (progs_t *pr, int num_params, int min_alignment)
|
||||||
}
|
}
|
||||||
*pr->globals.stack = stack;
|
*pr->globals.stack = stack;
|
||||||
pr->pr_params[0] = pr->pr_globals + stack;
|
pr->pr_params[0] = pr->pr_globals + stack;
|
||||||
num_params = min (num_params, PR_MAX_PARAMS);
|
num_params = max (num_params, PR_MAX_PARAMS);
|
||||||
for (int i = 1; i < num_params; i++) {
|
for (int i = 1; i < num_params; i++) {
|
||||||
pr->pr_params[i] = pr->pr_params[0] + i * 4;
|
pr->pr_params[i] = pr->pr_params[0] + i * 4;
|
||||||
}
|
}
|
||||||
|
|
|
@ -488,6 +488,14 @@ expr_t *new_temp_def_expr (const struct type_s *type);
|
||||||
*/
|
*/
|
||||||
expr_t *new_nil_expr (void);
|
expr_t *new_nil_expr (void);
|
||||||
|
|
||||||
|
/** Create a new args expression node
|
||||||
|
|
||||||
|
Marker between real parameters and those passed through ...
|
||||||
|
|
||||||
|
\return The new args expression node.
|
||||||
|
*/
|
||||||
|
expr_t *new_args_expr (void);
|
||||||
|
|
||||||
/** Create a new value expression node.
|
/** Create a new value expression node.
|
||||||
|
|
||||||
\param value The value to put in the expression node.
|
\param value The value to put in the expression node.
|
||||||
|
@ -725,6 +733,7 @@ void convert_name (expr_t *e);
|
||||||
expr_t *convert_vector (expr_t *e);
|
expr_t *convert_vector (expr_t *e);
|
||||||
|
|
||||||
expr_t *append_expr (expr_t *block, expr_t *e);
|
expr_t *append_expr (expr_t *block, expr_t *e);
|
||||||
|
expr_t *prepend_expr (expr_t *block, expr_t *e);
|
||||||
|
|
||||||
expr_t *reverse_expr_list (expr_t *e);
|
expr_t *reverse_expr_list (expr_t *e);
|
||||||
void print_expr (expr_t *e);
|
void print_expr (expr_t *e);
|
||||||
|
|
|
@ -61,5 +61,6 @@ EX_EXPR(branch) ///< branch expression (::ex_branch_t)
|
||||||
EX_EXPR(return) ///< return expression (::ex_return_t)
|
EX_EXPR(return) ///< return expression (::ex_return_t)
|
||||||
EX_EXPR(adjstk) ///< stack adjust expression (::ex_adjstk_t)
|
EX_EXPR(adjstk) ///< stack adjust expression (::ex_adjstk_t)
|
||||||
EX_EXPR(with) ///< with expression (::ex_with_t)
|
EX_EXPR(with) ///< with expression (::ex_with_t)
|
||||||
|
EX_EXPR(args) ///< @args marker in parameter list. no data
|
||||||
|
|
||||||
///@}
|
///@}
|
||||||
|
|
|
@ -654,6 +654,15 @@ print_with (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
|
||||||
e->e.with.mode, e->e.with.reg, e->line);
|
e->e.with.mode, e->e.with.reg, e->line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_args (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
|
||||||
|
{
|
||||||
|
int indent = level * 2 + 2;
|
||||||
|
|
||||||
|
dasprintf (dstr, "%*se_%p [label=\"...\\n%d\"];\n", indent, "", e,
|
||||||
|
e->line);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_print_expr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
|
_print_expr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
|
||||||
{
|
{
|
||||||
|
@ -682,6 +691,7 @@ _print_expr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
|
||||||
[ex_return] = print_return,
|
[ex_return] = print_return,
|
||||||
[ex_adjstk] = print_adjstk,
|
[ex_adjstk] = print_adjstk,
|
||||||
[ex_with] = print_with,
|
[ex_with] = print_with,
|
||||||
|
[ex_args] = print_args,
|
||||||
};
|
};
|
||||||
int indent = level * 2 + 2;
|
int indent = level * 2 + 2;
|
||||||
|
|
||||||
|
|
|
@ -274,6 +274,8 @@ get_type (expr_t *e)
|
||||||
break;
|
break;
|
||||||
case ex_assign:
|
case ex_assign:
|
||||||
return get_type (e->e.assign.dst);
|
return get_type (e->e.assign.dst);
|
||||||
|
case ex_args:
|
||||||
|
return &type_va_list;
|
||||||
case ex_count:
|
case ex_count:
|
||||||
internal_error (e, "invalid expression");
|
internal_error (e, "invalid expression");
|
||||||
}
|
}
|
||||||
|
@ -525,6 +527,10 @@ copy_expr (expr_t *e)
|
||||||
*n = *e;
|
*n = *e;
|
||||||
n->e.with.with = copy_expr (e->e.with.with);
|
n->e.with.with = copy_expr (e->e.with.with);
|
||||||
return n;
|
return n;
|
||||||
|
case ex_args:
|
||||||
|
n = new_expr ();
|
||||||
|
*n = *e;
|
||||||
|
return n;
|
||||||
case ex_count:
|
case ex_count:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -725,6 +731,14 @@ new_nil_expr (void)
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expr_t *
|
||||||
|
new_args_expr (void)
|
||||||
|
{
|
||||||
|
expr_t *e = new_expr ();
|
||||||
|
e->type = ex_args;
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
expr_t *
|
expr_t *
|
||||||
new_value_expr (ex_value_t *value)
|
new_value_expr (ex_value_t *value)
|
||||||
{
|
{
|
||||||
|
@ -1709,6 +1723,7 @@ has_function_call (expr_t *e)
|
||||||
case ex_memset:
|
case ex_memset:
|
||||||
case ex_adjstk:
|
case ex_adjstk:
|
||||||
case ex_with:
|
case ex_with:
|
||||||
|
case ex_args:
|
||||||
return 0;
|
return 0;
|
||||||
case ex_count:
|
case ex_count:
|
||||||
break;
|
break;
|
||||||
|
@ -1803,6 +1818,7 @@ unary_expr (int op, expr_t *e)
|
||||||
case ex_return:
|
case ex_return:
|
||||||
case ex_adjstk:
|
case ex_adjstk:
|
||||||
case ex_with:
|
case ex_with:
|
||||||
|
case ex_args:
|
||||||
internal_error (e, "unexpected expression type");
|
internal_error (e, "unexpected expression type");
|
||||||
case ex_uexpr:
|
case ex_uexpr:
|
||||||
if (e->e.expr.op == '-') {
|
if (e->e.expr.op == '-') {
|
||||||
|
@ -1907,6 +1923,7 @@ unary_expr (int op, expr_t *e)
|
||||||
case ex_return:
|
case ex_return:
|
||||||
case ex_adjstk:
|
case ex_adjstk:
|
||||||
case ex_with:
|
case ex_with:
|
||||||
|
case ex_args:
|
||||||
internal_error (e, "unexpected expression type");
|
internal_error (e, "unexpected expression type");
|
||||||
case ex_bool:
|
case ex_bool:
|
||||||
return new_bool_expr (e->e.bool.false_list,
|
return new_bool_expr (e->e.bool.false_list,
|
||||||
|
@ -1989,6 +2006,7 @@ unary_expr (int op, expr_t *e)
|
||||||
case ex_return:
|
case ex_return:
|
||||||
case ex_adjstk:
|
case ex_adjstk:
|
||||||
case ex_with:
|
case ex_with:
|
||||||
|
case ex_args:
|
||||||
internal_error (e, "unexpected expression type");
|
internal_error (e, "unexpected expression type");
|
||||||
case ex_uexpr:
|
case ex_uexpr:
|
||||||
if (e->e.expr.op == '~')
|
if (e->e.expr.op == '~')
|
||||||
|
@ -2048,12 +2066,13 @@ build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params)
|
||||||
{
|
{
|
||||||
expr_t *e;
|
expr_t *e;
|
||||||
expr_t *p;
|
expr_t *p;
|
||||||
int arg_count = 0, parm_count = 0;
|
int arg_count = 0, param_count = 0;
|
||||||
int i;
|
int i;
|
||||||
expr_t *args = 0, **a = &args;
|
expr_t *args = 0, **a = &args;
|
||||||
type_t *arg_types[PR_MAX_PARAMS];
|
type_t *arg_types[PR_MAX_PARAMS];
|
||||||
expr_t *arg_exprs[PR_MAX_PARAMS][2];
|
expr_t *arg_exprs[PR_MAX_PARAMS][2];
|
||||||
int arg_expr_count = 0;
|
int arg_expr_count = 0;
|
||||||
|
int emit_args = 0;
|
||||||
expr_t *assign;
|
expr_t *assign;
|
||||||
expr_t *call;
|
expr_t *call;
|
||||||
expr_t *err = 0;
|
expr_t *err = 0;
|
||||||
|
@ -2074,7 +2093,8 @@ build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params)
|
||||||
if (options.warnings.traditional)
|
if (options.warnings.traditional)
|
||||||
warning (fexpr, "too few arguments");
|
warning (fexpr, "too few arguments");
|
||||||
}
|
}
|
||||||
parm_count = -ftype->t.func.num_params - 1;
|
param_count = -ftype->t.func.num_params - 1;
|
||||||
|
emit_args = 1;
|
||||||
} else if (ftype->t.func.num_params >= 0) {
|
} else if (ftype->t.func.num_params >= 0) {
|
||||||
if (arg_count > ftype->t.func.num_params) {
|
if (arg_count > ftype->t.func.num_params) {
|
||||||
return error (fexpr, "too many arguments");
|
return error (fexpr, "too many arguments");
|
||||||
|
@ -2084,13 +2104,14 @@ build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params)
|
||||||
if (options.warnings.traditional)
|
if (options.warnings.traditional)
|
||||||
warning (fexpr, "too few arguments");
|
warning (fexpr, "too few arguments");
|
||||||
}
|
}
|
||||||
parm_count = ftype->t.func.num_params;
|
param_count = ftype->t.func.num_params;
|
||||||
}
|
}
|
||||||
|
// params is reversed (a, b, c) -> c, b, a
|
||||||
for (i = arg_count - 1, e = params; i >= 0; i--, e = e->next) {
|
for (i = arg_count - 1, e = params; i >= 0; i--, e = e->next) {
|
||||||
type_t *t;
|
type_t *t;
|
||||||
|
|
||||||
if (e->type == ex_compound) {
|
if (e->type == ex_compound) {
|
||||||
if (i < parm_count) {
|
if (i < param_count) {
|
||||||
t = ftype->t.func.param_types[i];
|
t = ftype->t.func.param_types[i];
|
||||||
} else {
|
} else {
|
||||||
return error (e, "cannot pass compound initializer "
|
return error (e, "cannot pass compound initializer "
|
||||||
|
@ -2109,7 +2130,7 @@ build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params)
|
||||||
if (type_size (t) > type_size (&type_param))
|
if (type_size (t) > type_size (&type_param))
|
||||||
err = error (e, "formal parameter %d is too large to be passed by"
|
err = error (e, "formal parameter %d is too large to be passed by"
|
||||||
" value", i + 1);
|
" value", i + 1);
|
||||||
if (i < parm_count) {
|
if (i < param_count) {
|
||||||
if (e->type == ex_nil)
|
if (e->type == ex_nil)
|
||||||
convert_nil (e, t = ftype->t.func.param_types[i]);
|
convert_nil (e, t = ftype->t.func.param_types[i]);
|
||||||
if (e->type == ex_bool)
|
if (e->type == ex_bool)
|
||||||
|
@ -2154,7 +2175,13 @@ build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params)
|
||||||
|
|
||||||
call = expr_file_line (new_block_expr (), fexpr);
|
call = expr_file_line (new_block_expr (), fexpr);
|
||||||
call->e.block.is_call = 1;
|
call->e.block.is_call = 1;
|
||||||
|
// args is built in reverse order so it matches params
|
||||||
for (p = params, i = 0; p; p = p->next, i++) {
|
for (p = params, i = 0; p; p = p->next, i++) {
|
||||||
|
if (emit_args && arg_count - i == param_count) {
|
||||||
|
emit_args = 0;
|
||||||
|
*a = new_args_expr ();
|
||||||
|
a = &(*a)->next;
|
||||||
|
}
|
||||||
expr_t *e = p;
|
expr_t *e = p;
|
||||||
if (e->type == ex_compound) {
|
if (e->type == ex_compound) {
|
||||||
e = expr_file_line (initialized_temp_expr (arg_types[i], e), e);
|
e = expr_file_line (initialized_temp_expr (arg_types[i], e), e);
|
||||||
|
@ -2175,6 +2202,11 @@ build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params)
|
||||||
}
|
}
|
||||||
a = &(*a)->next;
|
a = &(*a)->next;
|
||||||
}
|
}
|
||||||
|
if (emit_args) {
|
||||||
|
emit_args = 0;
|
||||||
|
*a = new_args_expr ();
|
||||||
|
a = &(*a)->next;
|
||||||
|
}
|
||||||
for (i = 0; i < arg_expr_count - 1; i++) {
|
for (i = 0; i < arg_expr_count - 1; i++) {
|
||||||
assign = assign_expr (arg_exprs[i][1], arg_exprs[i][0]);
|
assign = assign_expr (arg_exprs[i][1], arg_exprs[i][0]);
|
||||||
append_expr (call, expr_file_line (assign, arg_exprs[i][0]));
|
append_expr (call, expr_file_line (assign, arg_exprs[i][0]));
|
||||||
|
|
|
@ -140,6 +140,7 @@ is_lvalue (const expr_t *expr)
|
||||||
case ex_return:
|
case ex_return:
|
||||||
case ex_adjstk:
|
case ex_adjstk:
|
||||||
case ex_with:
|
case ex_with:
|
||||||
|
case ex_args:
|
||||||
break;
|
break;
|
||||||
case ex_count:
|
case ex_count:
|
||||||
internal_error (expr, "invalid expression");
|
internal_error (expr, "invalid expression");
|
||||||
|
|
|
@ -486,33 +486,15 @@ check_function (symbol_t *fsym)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
build_scope (symbol_t *fsym, symtab_t *parent)
|
build_v6p_scope (symbol_t *fsym)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
param_t *p;
|
param_t *p;
|
||||||
symbol_t *args = 0;
|
symbol_t *args = 0;
|
||||||
symbol_t *param;
|
symbol_t *param;
|
||||||
symtab_t *parameters;
|
symtab_t *parameters = fsym->s.func->parameters;
|
||||||
symtab_t *locals;
|
symtab_t *locals = fsym->s.func->locals;
|
||||||
|
|
||||||
check_function (fsym);
|
|
||||||
|
|
||||||
fsym->s.func->label_scope = new_symtab (0, stab_local);
|
|
||||||
|
|
||||||
parameters = new_symtab (parent, stab_local);
|
|
||||||
parameters->space = defspace_new (ds_virtual);
|
|
||||||
fsym->s.func->parameters = parameters;
|
|
||||||
|
|
||||||
locals = new_symtab (parameters, stab_local);
|
|
||||||
locals->space = defspace_new (ds_virtual);
|
|
||||||
fsym->s.func->locals = locals;
|
|
||||||
|
|
||||||
if (!fsym->s.func) {
|
|
||||||
internal_error (0, "function %s not defined", fsym->name);
|
|
||||||
}
|
|
||||||
if (!is_func (fsym->s.func->type)) {
|
|
||||||
internal_error (0, "function type %s not a funciton", fsym->name);
|
|
||||||
}
|
|
||||||
if (fsym->s.func->type->t.func.num_params < 0) {
|
if (fsym->s.func->type->t.func.num_params < 0) {
|
||||||
args = new_symbol_type (".args", &type_va_list);
|
args = new_symbol_type (".args", &type_va_list);
|
||||||
initialize_def (args, 0, parameters->space, sc_param, locals);
|
initialize_def (args, 0, parameters->space, sc_param, locals);
|
||||||
|
@ -541,6 +523,78 @@ build_scope (symbol_t *fsym, symtab_t *parent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
create_param (symtab_t *parameters, symbol_t *param)
|
||||||
|
{
|
||||||
|
defspace_t *space = parameters->space;
|
||||||
|
def_t *def = new_def (param->name, 0, space, sc_param);
|
||||||
|
int size = type_size (param->type);
|
||||||
|
int alignment = param->type->alignment;
|
||||||
|
if (alignment < 4) {
|
||||||
|
alignment = 4;
|
||||||
|
}
|
||||||
|
def->offset = defspace_alloc_aligned_highwater (space, size, alignment);
|
||||||
|
def->type = param->type;
|
||||||
|
param->s.def = def;
|
||||||
|
param->sy_type = sy_var;
|
||||||
|
symtab_addsymbol (parameters, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
build_rua_scope (symbol_t *fsym)
|
||||||
|
{
|
||||||
|
for (param_t *p = fsym->params; p; p = p->next) {
|
||||||
|
symbol_t *param;
|
||||||
|
if (!p->selector && !p->type && !p->name) {
|
||||||
|
// ellipsis marker
|
||||||
|
param = new_symbol_type (".args", &type_va_list);
|
||||||
|
} else {
|
||||||
|
if (!p->type) {
|
||||||
|
continue; // non-param selector
|
||||||
|
}
|
||||||
|
if (!p->name) {
|
||||||
|
error (0, "parameter name omitted");
|
||||||
|
p->name = save_string ("");
|
||||||
|
}
|
||||||
|
param = new_symbol_type (p->name, p->type);
|
||||||
|
}
|
||||||
|
create_param (fsym->s.func->parameters, param);
|
||||||
|
param->s.def->reg = fsym->s.func->temp_reg;;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
build_scope (symbol_t *fsym, symtab_t *parent)
|
||||||
|
{
|
||||||
|
symtab_t *parameters;
|
||||||
|
symtab_t *locals;
|
||||||
|
|
||||||
|
if (!fsym->s.func) {
|
||||||
|
internal_error (0, "function %s not defined", fsym->name);
|
||||||
|
}
|
||||||
|
if (!is_func (fsym->s.func->type)) {
|
||||||
|
internal_error (0, "function type %s not a funciton", fsym->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
check_function (fsym);
|
||||||
|
|
||||||
|
fsym->s.func->label_scope = new_symtab (0, stab_local);
|
||||||
|
|
||||||
|
parameters = new_symtab (parent, stab_local);
|
||||||
|
parameters->space = defspace_new (ds_virtual);
|
||||||
|
fsym->s.func->parameters = parameters;
|
||||||
|
|
||||||
|
locals = new_symtab (parameters, stab_local);
|
||||||
|
locals->space = defspace_new (ds_virtual);
|
||||||
|
fsym->s.func->locals = locals;
|
||||||
|
|
||||||
|
if (options.code.progsversion == PROG_VERSION) {
|
||||||
|
build_rua_scope (fsym);
|
||||||
|
} else {
|
||||||
|
build_v6p_scope (fsym);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function_t *
|
function_t *
|
||||||
new_function (const char *name, const char *nice_name)
|
new_function (const char *name, const char *nice_name)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1026,10 +1026,19 @@ expr_call_v6p (sblock_t *sblock, expr_t *call, operand_t **op)
|
||||||
statement_t *s;
|
statement_t *s;
|
||||||
|
|
||||||
// function arguments are in reverse order
|
// function arguments are in reverse order
|
||||||
for (a = args; a; a = a->next)
|
for (a = args; a; a = a->next) {
|
||||||
|
if (a->type == ex_args) {
|
||||||
|
// v6p uses callN and pr_argc
|
||||||
|
continue;
|
||||||
|
}
|
||||||
count++;
|
count++;
|
||||||
|
}
|
||||||
ind = count;
|
ind = count;
|
||||||
for (a = args; a; a = a->next) {
|
for (a = args; a; a = a->next) {
|
||||||
|
if (a->type == ex_args) {
|
||||||
|
// v6p uses callN and pr_argc
|
||||||
|
continue;
|
||||||
|
}
|
||||||
ind--;
|
ind--;
|
||||||
param = new_param_expr (get_type (a), ind);
|
param = new_param_expr (get_type (a), ind);
|
||||||
if (count && options.code.progsversion != PROG_ID_VERSION && ind < 2) {
|
if (count && options.code.progsversion != PROG_ID_VERSION && ind < 2) {
|
||||||
|
@ -1091,8 +1100,11 @@ expr_call (sblock_t *sblock, expr_t *call, operand_t **op)
|
||||||
defspace_t *arg_space = current_func->arguments;
|
defspace_t *arg_space = current_func->arguments;
|
||||||
expr_t *func = call->e.branch.target;
|
expr_t *func = call->e.branch.target;
|
||||||
expr_t *args = call->e.branch.args;
|
expr_t *args = call->e.branch.args;
|
||||||
|
expr_t *args_va_list = 0; // .args (...) parameter
|
||||||
|
expr_t *args_params = 0; // first arg in ...
|
||||||
operand_t *use = 0;
|
operand_t *use = 0;
|
||||||
operand_t *kill = 0;
|
operand_t *kill = 0;
|
||||||
|
int num_params = 0;
|
||||||
|
|
||||||
defspace_reset (arg_space);
|
defspace_reset (arg_space);
|
||||||
|
|
||||||
|
@ -1111,9 +1123,21 @@ expr_call (sblock_t *sblock, expr_t *call, operand_t **op)
|
||||||
def->offset = defspace_alloc_aligned_highwater (arg_space, size,
|
def->offset = defspace_alloc_aligned_highwater (arg_space, size,
|
||||||
alignment);
|
alignment);
|
||||||
def->type = arg_type;
|
def->type = arg_type;
|
||||||
expr_t *assign = assign_expr (new_def_expr (def), a);
|
def->reg = current_func->temp_reg;
|
||||||
expr_file_line (assign, call);
|
expr_t *def_expr = expr_file_line (new_def_expr (def), call);
|
||||||
sblock = statement_slist (sblock, assign);
|
if (a->type == ex_args) {
|
||||||
|
args_va_list = def_expr;
|
||||||
|
} else {
|
||||||
|
if (args_va_list && !args_params) {
|
||||||
|
args_params = def_expr;
|
||||||
|
}
|
||||||
|
if (args_va_list) {
|
||||||
|
num_params++;
|
||||||
|
}
|
||||||
|
expr_t *assign = assign_expr (def_expr, a);
|
||||||
|
expr_file_line (assign, call);
|
||||||
|
sblock = statement_slist (sblock, assign);
|
||||||
|
}
|
||||||
|
|
||||||
// The call both uses and kills the arguments: use is obvious, but kill
|
// The call both uses and kills the arguments: use is obvious, but kill
|
||||||
// is because the callee has direct access to them and might modify
|
// is because the callee has direct access to them and might modify
|
||||||
|
@ -1126,6 +1150,31 @@ expr_call (sblock_t *sblock, expr_t *call, operand_t **op)
|
||||||
k->next = kill;
|
k->next = kill;
|
||||||
kill = k;
|
kill = k;
|
||||||
}
|
}
|
||||||
|
if (args_va_list) {
|
||||||
|
expr_t *assign;
|
||||||
|
expr_t *count;
|
||||||
|
expr_t *list;
|
||||||
|
expr_t *args_count = field_expr (args_va_list,
|
||||||
|
new_name_expr ("count"));
|
||||||
|
expr_t *args_list = field_expr (args_va_list,
|
||||||
|
new_name_expr ("list"));
|
||||||
|
expr_file_line (args_count, call);
|
||||||
|
expr_file_line (args_list, call);
|
||||||
|
|
||||||
|
count = new_short_expr (num_params);
|
||||||
|
assign = assign_expr (args_count, count);
|
||||||
|
expr_file_line (assign, call);
|
||||||
|
sblock = statement_slist (sblock, assign);
|
||||||
|
|
||||||
|
if (args_params) {
|
||||||
|
list = address_expr (args_params, 0, &type_param);
|
||||||
|
} else {
|
||||||
|
list = new_nil_expr ();
|
||||||
|
}
|
||||||
|
assign = assign_expr (args_list, list);
|
||||||
|
expr_file_line (assign, call);
|
||||||
|
sblock = statement_slist (sblock, assign);
|
||||||
|
}
|
||||||
statement_t *s = new_statement (st_func, "call", call);
|
statement_t *s = new_statement (st_func, "call", call);
|
||||||
sblock = statement_subexpr (sblock, func, &s->opa);
|
sblock = statement_subexpr (sblock, func, &s->opa);
|
||||||
if (!op) {
|
if (!op) {
|
||||||
|
|
|
@ -55,6 +55,19 @@ bi_printf (progs_t *pr)
|
||||||
else
|
else
|
||||||
dstring_clear (dstr);
|
dstring_clear (dstr);
|
||||||
|
|
||||||
|
if (pr->progs->version == PROG_VERSION) {
|
||||||
|
__auto_type va_list = &P_PACKED (pr, pr_va_list_t, 1);
|
||||||
|
count = va_list->count;
|
||||||
|
if (count) {
|
||||||
|
args = alloca (count * sizeof (pr_type_t *));
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
args[i] = &pr->pr_globals[va_list->list + i * 4];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
args = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PR_Sprintf (pr, dstr, "bi_printf", fmt, count, args);
|
PR_Sprintf (pr, dstr, "bi_printf", fmt, count, args);
|
||||||
if (dstr->str)
|
if (dstr->str)
|
||||||
fputs (dstr->str, stdout);
|
fputs (dstr->str, stdout);
|
||||||
|
|
Loading…
Reference in a new issue