diff --git a/tools/qfcc/source/emit.c b/tools/qfcc/source/emit.c index 5022d517f..af56d5590 100644 --- a/tools/qfcc/source/emit.c +++ b/tools/qfcc/source/emit.c @@ -208,11 +208,18 @@ emit_function_call (expr_t *e, def_t *dest) for (earg = e->e.expr.e2; earg; earg = earg->next) { ind--; parm = def_parms[ind]; - parm.type = types[extract_type (earg)]; - arg = emit_sub_expr (earg, &parm); - if (arg != &parm) { - op = opcode_find ("=", arg, &parm, &def_void); - emit_statement (e, op, arg, &parm, 0); + parm.type = get_type (earg); + if (parm.type->type == ev_struct) { + expr_t *a = assign_expr (new_def_expr (&parm), earg); + a->line = e->line; + a->file = e->file; + emit_expr (a); + } else { + arg = emit_sub_expr (earg, &parm); + if (arg != &parm) { + op = opcode_find ("=", arg, &parm, &def_void); + emit_statement (e, op, arg, &parm, 0); + } } } op = opcode_find (va ("", count), &def_function, &def_void, @@ -312,6 +319,28 @@ emit_bind_expr (expr_t *e1, expr_t *e2) return e2->e.temp.def; } +def_t * +emit_move_expr (expr_t *e) +{ + expr_t *e1 = e->e.expr.e1; + expr_t *e2 = e->e.expr.e2; + def_t *size, *src, *dst; + type_t *type; + opcode_t *op; + + src = emit_sub_expr (e2, 0); + dst = emit_sub_expr (e1, 0); + type = get_type (e1); + + if (type->type == ev_struct) { + size = emit_sub_expr (new_short_expr (type_size (dst->type)), 0); + } else { + size = emit_sub_expr (new_integer_expr (type_size (type->aux_type)), 0); + } + op = opcode_find ("", src, size, dst); + return emit_statement (e, op, src, size, dst); +} + def_t * emit_address_expr (expr_t *e) { @@ -558,6 +587,9 @@ emit_expr (expr_t *e) break; case ex_expr: switch (e->e.expr.op) { + case 'M': + emit_move_expr (e); + break; case PAS: case '=': emit_assign_expr (e->e.expr.op, e); diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index ba778fd23..f7c9b266e 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -2176,14 +2176,25 @@ assign_expr (expr_t *e1, expr_t *e2) } type = t1; if (is_indirect (e1) && is_indirect (e2)) { - expr_t *temp = new_temp_def_expr (t1); + if (options.code.progsversion == PROG_ID_VERSION) { + expr_t *temp = new_temp_def_expr (t1); - e = new_block_expr (); - append_expr (e, assign_expr (temp, e2)); - append_expr (e, assign_expr (e1, temp)); - e->e.block.result = temp; + e = new_block_expr (); + append_expr (e, assign_expr (temp, e2)); + append_expr (e, assign_expr (e1, temp)); + e->e.block.result = temp; + } else { + e1 = address_expr (e1, 0, 0); + e2 = address_expr (e2, 0, 0); + e = new_binary_expr ('M', e1, e2); + } return e; } else if (is_indirect (e1)) { + if (extract_type (e1) == ev_struct) { + e1 = address_expr (e1, 0, 0); + e2 = address_expr (e2, 0, 0); + return new_binary_expr ('M', e1, e2); + } if (e1->type == ex_expr) { if (get_type (e1->e.expr.e1) == &type_entity) { type = e1->e.expr.type; @@ -2200,6 +2211,11 @@ assign_expr (expr_t *e1, expr_t *e2) } } } else if (is_indirect (e2)) { + if (extract_type (e1) == ev_struct) { + e1 = address_expr (e1, 0, 0); + e2 = address_expr (e2, 0, 0); + return new_binary_expr ('M', e1, e2); + } if (e2->type == ex_uexpr) { e = e2->e.expr.e1; if (e->type != ex_pointer @@ -2213,6 +2229,9 @@ assign_expr (expr_t *e1, expr_t *e2) } } } + if (extract_type (e1) == ev_struct) { + return new_binary_expr ('M', e1, e2); + } if (!type) error (e1, "internal error");