2001-09-28 07:09:38 +00:00
|
|
|
/*
|
2002-10-22 14:53:18 +00:00
|
|
|
emit.c
|
2001-09-28 07:09:38 +00:00
|
|
|
|
2002-10-22 14:53:18 +00:00
|
|
|
statement emittion
|
2001-09-28 07:09:38 +00:00
|
|
|
|
2002-10-22 14:53:18 +00:00
|
|
|
Copyright (C) 2001 Bill Currie <bill@taniwha.org>
|
2001-09-28 07:09:38 +00:00
|
|
|
|
2002-10-22 14:53:18 +00:00
|
|
|
Author: Bill Currie <bill@taniwha.org>
|
|
|
|
Date: 2001/07/26
|
2001-09-28 07:09:38 +00:00
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License
|
|
|
|
as published by the Free Software Foundation; either version 2
|
|
|
|
of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to:
|
|
|
|
|
|
|
|
Free Software Foundation, Inc.
|
|
|
|
59 Temple Place - Suite 330
|
|
|
|
Boston, MA 02111-1307, USA
|
|
|
|
|
|
|
|
*/
|
2002-06-01 04:41:25 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
2003-01-15 15:31:36 +00:00
|
|
|
|
|
|
|
static __attribute__ ((unused)) const char rcsid[] =
|
|
|
|
"$Id$";
|
|
|
|
|
2002-06-01 04:41:25 +00:00
|
|
|
#ifdef HAVE_STRING_H
|
|
|
|
# include <string.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_STRINGS_H
|
|
|
|
# include <strings.h>
|
|
|
|
#endif
|
2001-07-26 05:15:34 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include <QF/mathlib.h>
|
|
|
|
#include <QF/va.h>
|
|
|
|
|
2002-06-04 21:23:39 +00:00
|
|
|
#include "def.h"
|
|
|
|
#include "debug.h"
|
2002-07-08 18:53:07 +00:00
|
|
|
#include "emit.h"
|
2002-06-01 05:30:16 +00:00
|
|
|
#include "expr.h"
|
2002-06-04 18:44:03 +00:00
|
|
|
#include "immediate.h"
|
2002-06-04 21:23:39 +00:00
|
|
|
#include "opcodes.h"
|
2002-06-04 18:44:03 +00:00
|
|
|
#include "options.h"
|
2002-06-04 21:23:39 +00:00
|
|
|
#include "qfcc.h"
|
2002-06-07 17:29:30 +00:00
|
|
|
#include "reloc.h"
|
2002-05-09 17:11:14 +00:00
|
|
|
#include "type.h"
|
2001-07-26 05:15:34 +00:00
|
|
|
#include "qc-parse.h"
|
|
|
|
|
2002-06-12 22:37:18 +00:00
|
|
|
static expr_t zero;
|
|
|
|
|
2002-07-08 20:31:59 +00:00
|
|
|
codespace_t *
|
|
|
|
codespace_new (void)
|
|
|
|
{
|
|
|
|
return calloc (1, sizeof (codespace_t));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
codespace_delete (codespace_t *codespace)
|
|
|
|
{
|
|
|
|
free (codespace->code);
|
|
|
|
free (codespace);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
codespace_addcode (codespace_t *codespace, dstatement_t *code, int size)
|
|
|
|
{
|
|
|
|
if (codespace->size + size > codespace->max_size) {
|
|
|
|
codespace->max_size = (codespace->size + size + 16383) & ~16383;
|
|
|
|
codespace->code = realloc (codespace->code,
|
|
|
|
codespace->max_size * sizeof (dstatement_t));
|
|
|
|
}
|
|
|
|
memcpy (codespace->code + codespace->size, code,
|
|
|
|
size * sizeof (dstatement_t));
|
|
|
|
codespace->size += size;
|
|
|
|
}
|
|
|
|
|
|
|
|
dstatement_t *
|
|
|
|
codespace_newstatement (codespace_t *codespace)
|
|
|
|
{
|
|
|
|
if (codespace->size >= codespace->max_size) {
|
|
|
|
codespace->max_size += 16384;
|
|
|
|
codespace->code = realloc (codespace->code,
|
|
|
|
codespace->max_size * sizeof (dstatement_t));
|
|
|
|
}
|
|
|
|
return codespace->code + codespace->size++;
|
|
|
|
}
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2003-08-21 02:21:30 +00:00
|
|
|
add_statement_ref (def_t *def, dstatement_t *st, int field)
|
2002-06-07 17:29:30 +00:00
|
|
|
{
|
|
|
|
if (def) {
|
2003-08-21 02:21:30 +00:00
|
|
|
int st_ofs = st - pr.code->code;
|
2002-06-07 17:29:30 +00:00
|
|
|
|
2003-08-22 18:16:30 +00:00
|
|
|
def->users--;
|
|
|
|
def->used = 1;
|
|
|
|
|
2003-08-21 02:21:30 +00:00
|
|
|
if (def->alias) {
|
2003-04-22 15:29:32 +00:00
|
|
|
def = def->alias;
|
2003-09-02 06:23:57 +00:00
|
|
|
def->users--;
|
2003-08-22 18:16:30 +00:00
|
|
|
def->used = 1;
|
2003-08-21 02:21:30 +00:00
|
|
|
reloc_op_def_ofs (def, st_ofs, field);
|
|
|
|
} else
|
|
|
|
reloc_op_def (def, st_ofs, field);
|
2002-06-07 17:29:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-07-26 05:15:34 +00:00
|
|
|
def_t *
|
2002-07-08 18:53:07 +00:00
|
|
|
emit_statement (expr_t *e, opcode_t *op, def_t *var_a, def_t *var_b,
|
2001-12-06 19:49:40 +00:00
|
|
|
def_t *var_c)
|
2001-07-26 05:15:34 +00:00
|
|
|
{
|
2001-12-06 19:49:40 +00:00
|
|
|
dstatement_t *statement;
|
|
|
|
def_t *ret;
|
2001-07-26 05:15:34 +00:00
|
|
|
|
|
|
|
if (!op) {
|
2003-04-22 15:29:32 +00:00
|
|
|
error (e, "ice ice baby");
|
2001-07-26 05:15:34 +00:00
|
|
|
abort ();
|
|
|
|
}
|
2001-10-26 06:43:56 +00:00
|
|
|
if (options.code.debug) {
|
2003-04-17 00:01:48 +00:00
|
|
|
unsigned int line = (e ? e->line : pr.source_line) - lineno_base;
|
2001-07-26 05:15:34 +00:00
|
|
|
|
2002-07-17 14:19:30 +00:00
|
|
|
if (line != pr.linenos[pr.num_linenos - 1].line) {
|
2001-12-06 19:49:40 +00:00
|
|
|
pr_lineno_t *lineno = new_lineno ();
|
|
|
|
|
2001-07-26 05:15:34 +00:00
|
|
|
lineno->line = line;
|
2002-07-08 20:31:59 +00:00
|
|
|
lineno->fa.addr = pr.code->size;
|
2001-07-26 05:15:34 +00:00
|
|
|
}
|
|
|
|
}
|
2002-07-08 20:31:59 +00:00
|
|
|
statement = codespace_newstatement (pr.code);
|
2001-07-26 05:15:34 +00:00
|
|
|
statement->op = op->opcode;
|
|
|
|
statement->a = var_a ? var_a->ofs : 0;
|
|
|
|
statement->b = var_b ? var_b->ofs : 0;
|
|
|
|
if (op->type_c == ev_void || op->right_associative) {
|
|
|
|
// ifs, gotos, and assignments don't need vars allocated
|
2005-06-12 09:54:01 +00:00
|
|
|
if (var_c)
|
2001-12-08 08:19:48 +00:00
|
|
|
statement->c = var_c->ofs;
|
2001-07-26 05:15:34 +00:00
|
|
|
ret = var_a;
|
2001-12-06 19:49:40 +00:00
|
|
|
} else { // allocate result space
|
2001-08-22 21:55:01 +00:00
|
|
|
if (!var_c) {
|
2003-08-22 19:48:14 +00:00
|
|
|
var_c = get_tempdef (ev_types[op->type_c], current_scope);
|
2001-08-22 21:55:01 +00:00
|
|
|
var_c->users += 2;
|
|
|
|
}
|
2001-07-26 05:15:34 +00:00
|
|
|
statement->c = var_c->ofs;
|
|
|
|
ret = var_c;
|
|
|
|
}
|
2004-01-25 08:59:55 +00:00
|
|
|
#if 0
|
2001-12-12 08:39:47 +00:00
|
|
|
printf ("%s %s(%d) %s(%d) %s(%d)\n", op->opname,
|
|
|
|
var_a ? var_a->name : "", statement->a,
|
|
|
|
var_b ? var_b->name : "", statement->b,
|
|
|
|
var_c ? var_c->name : "", statement->c);
|
|
|
|
#endif
|
2001-10-31 18:40:02 +00:00
|
|
|
|
2003-08-21 02:21:30 +00:00
|
|
|
add_statement_ref (var_a, statement, 0);
|
|
|
|
add_statement_ref (var_b, statement, 1);
|
|
|
|
add_statement_ref (var_c, statement, 2);
|
2001-07-26 05:15:34 +00:00
|
|
|
|
|
|
|
if (op->right_associative)
|
|
|
|
return var_a;
|
|
|
|
return var_c;
|
|
|
|
}
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static void
|
2002-07-08 18:53:07 +00:00
|
|
|
emit_branch (expr_t *_e, opcode_t *op, expr_t *e, expr_t *l)
|
2001-07-26 05:15:34 +00:00
|
|
|
{
|
|
|
|
dstatement_t *st;
|
2002-06-07 17:29:30 +00:00
|
|
|
reloc_t *ref;
|
2001-12-06 19:49:40 +00:00
|
|
|
def_t *def = 0;
|
2002-06-05 17:12:55 +00:00
|
|
|
int ofs;
|
2001-07-26 05:15:34 +00:00
|
|
|
|
|
|
|
if (e)
|
|
|
|
def = emit_sub_expr (e, 0);
|
2002-08-30 05:33:34 +00:00
|
|
|
ofs = pr.code->size;
|
2002-07-08 18:53:07 +00:00
|
|
|
emit_statement (_e, op, def, 0, 0);
|
2002-08-30 05:33:34 +00:00
|
|
|
st = &pr.code->code[ofs];
|
2002-06-05 17:12:55 +00:00
|
|
|
if (l->e.label.ofs) {
|
2001-07-26 05:15:34 +00:00
|
|
|
if (op == op_goto)
|
2002-06-05 17:12:55 +00:00
|
|
|
st->a = l->e.label.ofs - ofs;
|
2001-07-26 05:15:34 +00:00
|
|
|
else
|
2002-06-05 17:12:55 +00:00
|
|
|
st->b = l->e.label.ofs - ofs;
|
2001-07-26 05:15:34 +00:00
|
|
|
} else {
|
2002-06-07 17:29:30 +00:00
|
|
|
ref = new_reloc (ofs, op == op_goto ? rel_op_a_op : rel_op_b_op);
|
2001-07-26 05:15:34 +00:00
|
|
|
ref->next = l->e.label.refs;
|
|
|
|
l->e.label.refs = ref;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static def_t *
|
2001-07-26 05:15:34 +00:00
|
|
|
emit_function_call (expr_t *e, def_t *dest)
|
|
|
|
{
|
2001-12-06 19:49:40 +00:00
|
|
|
def_t *func = emit_sub_expr (e->e.expr.e1, 0);
|
2003-04-22 15:29:32 +00:00
|
|
|
def_t *ret;
|
2001-12-06 19:49:40 +00:00
|
|
|
def_t *arg;
|
2005-06-10 07:31:25 +00:00
|
|
|
def_t *p;
|
2005-06-12 09:54:01 +00:00
|
|
|
def_t *a[2] = {0, 0};
|
2001-12-06 19:49:40 +00:00
|
|
|
expr_t *earg;
|
2005-06-10 07:31:25 +00:00
|
|
|
expr_t *parm;
|
2001-12-06 19:49:40 +00:00
|
|
|
opcode_t *op;
|
|
|
|
int count = 0, ind;
|
2005-06-12 09:54:01 +00:00
|
|
|
const char *pref = "";
|
2001-07-26 05:15:34 +00:00
|
|
|
|
|
|
|
for (earg = e->e.expr.e2; earg; earg = earg->next)
|
|
|
|
count++;
|
|
|
|
ind = count;
|
|
|
|
for (earg = e->e.expr.e2; earg; earg = earg->next) {
|
|
|
|
ind--;
|
2005-06-10 07:31:25 +00:00
|
|
|
parm = new_param_expr (get_type (earg), ind);
|
2005-06-12 09:54:01 +00:00
|
|
|
if (options.code.progsversion != PROG_ID_VERSION && ind < 2) {
|
|
|
|
pref = "R";
|
|
|
|
a[ind] = emit_sub_expr (earg, emit_sub_expr (parm, 0));
|
|
|
|
continue;
|
|
|
|
}
|
2005-06-10 07:31:25 +00:00
|
|
|
if (extract_type (parm) == ev_struct) {
|
|
|
|
expr_t *a = assign_expr (parm, earg);
|
2002-10-16 17:07:01 +00:00
|
|
|
a->line = e->line;
|
|
|
|
a->file = e->file;
|
|
|
|
emit_expr (a);
|
|
|
|
} else {
|
2005-06-10 07:31:25 +00:00
|
|
|
if (options.code.vector_calls && earg->type == ex_vector) {
|
|
|
|
expr_t *a, *v, *n;
|
|
|
|
int i;
|
|
|
|
static const char *names[] = {"x", "y", "z"};
|
|
|
|
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
|
|
n = new_name_expr (names[i]);
|
|
|
|
v = new_float_expr (earg->e.vector_val[i]);
|
|
|
|
a = assign_expr (binary_expr ('.', parm, n), v);
|
|
|
|
parm = new_param_expr (get_type (earg), ind);
|
|
|
|
a->line = e->line;
|
|
|
|
a->file = e->file;
|
|
|
|
emit_expr (a);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
p = emit_sub_expr (parm, 0);
|
|
|
|
arg = emit_sub_expr (earg, p);
|
|
|
|
if (arg != p) {
|
|
|
|
op = opcode_find ("=", arg->type, arg->type, &type_void);
|
|
|
|
emit_statement (e, op, arg, p, 0);
|
|
|
|
}
|
2002-10-16 17:07:01 +00:00
|
|
|
}
|
2001-07-26 05:15:34 +00:00
|
|
|
}
|
|
|
|
}
|
2005-06-12 09:54:01 +00:00
|
|
|
op = opcode_find (va ("<%sCALL%d>", pref, count),
|
|
|
|
&type_function, &type_void, &type_void);
|
|
|
|
emit_statement (e, op, func, a[0], a[1]);
|
2001-07-26 05:15:34 +00:00
|
|
|
|
2003-04-22 15:29:32 +00:00
|
|
|
ret = emit_sub_expr (new_ret_expr (func->type->aux_type), 0);
|
2001-08-20 04:56:00 +00:00
|
|
|
if (dest) {
|
2003-04-22 15:29:32 +00:00
|
|
|
op = opcode_find ("=", dest->type, ret->type, &type_void);
|
|
|
|
emit_statement (e, op, ret, dest, 0);
|
2001-07-26 05:15:34 +00:00
|
|
|
return dest;
|
2001-08-20 04:56:00 +00:00
|
|
|
} else {
|
2003-04-22 15:29:32 +00:00
|
|
|
return ret;
|
2001-08-20 04:56:00 +00:00
|
|
|
}
|
2001-07-26 05:15:34 +00:00
|
|
|
}
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static def_t *
|
2001-12-12 20:35:58 +00:00
|
|
|
emit_assign_expr (int oper, expr_t *e)
|
2001-07-26 05:15:34 +00:00
|
|
|
{
|
2001-12-06 19:49:40 +00:00
|
|
|
def_t *def_a, *def_b, *def_c;
|
|
|
|
opcode_t *op;
|
|
|
|
expr_t *e1 = e->e.expr.e1;
|
|
|
|
expr_t *e2 = e->e.expr.e2;
|
2001-12-12 20:35:58 +00:00
|
|
|
const char *operator = get_op_string (oper);
|
2001-07-26 05:15:34 +00:00
|
|
|
|
pr_comp.h:
o add ev_uniteger to the types enum
o add opcodes for ifbe, ifb, ifae, ifa, jump, lt.ui, gt.ui, le.ui, ge.ui
progs.h:
o add uinteger accessors
pr_exec.c:
o implement ifbe, ifb, ifae, ifa, jump, lt.ui, gt.ui, le.ui, ge.ui
pr_opcode.c:
o add opcodes for ifbe, ifb, ifae, ifa, jump, lt.ui, gt.ui, le.ui, ge.ui
expr.h:
o prototype inc_users
qfcc.h:
o add externs for op_ifbe, op_ifb, op_ifae and op_ifa
emit.c:
o don't bother emiting an assignment to a temp def that's only used once
(ie, it's never read, only written to)
o support the new if* instructions
expr.c:
o support the new if* insructions
o dectect expression loops in append_expr
o support unsigned integers
o re-work temp def usage counting
pr_def.c
o debugging for temp def usage counts
pr_opcode.c:
o support the new if* instructions
qc-parse.y:
o provide defines for IFBE IFB IFAE IFA
switch.c:
o do binary searches for strings, floats and ints if there are more than
8 cases in a switch. Strings need more testing.
2001-11-09 00:58:16 +00:00
|
|
|
if (e1->type == ex_temp && e1->e.temp.users < 2) {
|
|
|
|
e1->e.temp.users--;
|
|
|
|
return 0;
|
|
|
|
}
|
2001-12-12 20:35:58 +00:00
|
|
|
if (oper == '=') {
|
2001-11-15 04:32:50 +00:00
|
|
|
def_a = emit_sub_expr (e1, 0);
|
2001-12-12 20:35:58 +00:00
|
|
|
if (def_a->constant) {
|
|
|
|
if (options.code.cow) {
|
2002-06-05 19:31:43 +00:00
|
|
|
int size = type_size (def_a->type);
|
2002-06-10 20:54:22 +00:00
|
|
|
int ofs = new_location (def_a->type, pr.near_data);
|
2001-12-12 20:35:58 +00:00
|
|
|
|
2002-06-10 20:54:22 +00:00
|
|
|
memcpy (G_POINTER (void, ofs), G_POINTER (void, def_a->ofs),
|
2002-06-09 03:57:20 +00:00
|
|
|
size);
|
2001-12-12 20:35:58 +00:00
|
|
|
def_a->ofs = ofs;
|
|
|
|
def_a->constant = 0;
|
2003-04-25 17:00:22 +00:00
|
|
|
def_a->nosave = 1;
|
2001-12-12 20:35:58 +00:00
|
|
|
if (options.warnings.cow)
|
|
|
|
warning (e1, "assignment to constant %s (Moooooooo!)",
|
|
|
|
def_a->name);
|
2001-12-12 08:39:47 +00:00
|
|
|
} else {
|
2004-02-17 00:39:21 +00:00
|
|
|
if (options.traditional) {
|
|
|
|
//FIXME correct option?
|
|
|
|
if (options.warnings.cow)
|
|
|
|
warning (e1, "assignment to constant %s", def_a->name);
|
|
|
|
} else
|
2002-02-18 06:23:59 +00:00
|
|
|
error (e1, "assignment to constant %s", def_a->name);
|
2001-12-12 08:39:47 +00:00
|
|
|
}
|
2001-12-12 20:35:58 +00:00
|
|
|
}
|
|
|
|
def_b = emit_sub_expr (e2, def_a);
|
|
|
|
if (def_b != def_a) {
|
2003-04-22 15:29:32 +00:00
|
|
|
op = opcode_find (operator, def_b->type, def_a->type, &type_void);
|
2002-07-08 18:53:07 +00:00
|
|
|
emit_statement (e, op, def_b, def_a, 0);
|
2001-12-12 20:35:58 +00:00
|
|
|
}
|
2001-12-12 20:55:55 +00:00
|
|
|
return def_a;
|
2001-12-12 20:35:58 +00:00
|
|
|
} else {
|
|
|
|
def_b = emit_sub_expr (e2, 0);
|
2002-02-21 20:34:04 +00:00
|
|
|
if (e->rvalue && def_b->managed)
|
|
|
|
def_b->users++;
|
2002-06-12 22:37:18 +00:00
|
|
|
if (e1->type == ex_expr && extract_type (e1->e.expr.e1) == ev_pointer
|
|
|
|
&& e1->e.expr.e1->type < ex_string) {
|
2001-12-12 20:35:58 +00:00
|
|
|
def_a = emit_sub_expr (e1->e.expr.e1, 0);
|
|
|
|
def_c = emit_sub_expr (e1->e.expr.e2, 0);
|
2003-04-22 15:29:32 +00:00
|
|
|
op = opcode_find (operator, def_b->type, def_a->type, def_c->type);
|
2001-11-15 04:32:50 +00:00
|
|
|
} else {
|
2001-12-12 20:35:58 +00:00
|
|
|
def_a = emit_sub_expr (e1, 0);
|
|
|
|
def_c = 0;
|
2003-04-22 15:29:32 +00:00
|
|
|
op = opcode_find (operator, def_b->type, def_a->type, &type_void);
|
2001-07-26 05:15:34 +00:00
|
|
|
}
|
2002-07-08 18:53:07 +00:00
|
|
|
emit_statement (e, op, def_b, def_a, def_c);
|
2001-12-12 20:55:55 +00:00
|
|
|
return def_b;
|
2001-07-26 05:15:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static def_t *
|
2001-11-13 18:11:19 +00:00
|
|
|
emit_bind_expr (expr_t *e1, expr_t *e2)
|
|
|
|
{
|
|
|
|
type_t *t1 = get_type (e1);
|
|
|
|
type_t *t2 = get_type (e2);
|
|
|
|
def_t *def;
|
|
|
|
|
|
|
|
if (!e2 || e2->type != ex_temp) {
|
|
|
|
error (e1, "internal error");
|
|
|
|
abort ();
|
|
|
|
}
|
|
|
|
def = emit_sub_expr (e1, e2->e.temp.def);
|
|
|
|
if (t1 != t2) {
|
2003-08-22 18:16:30 +00:00
|
|
|
def_t *tmp = new_def (t2, 0, def->scope);
|
2001-12-06 19:49:40 +00:00
|
|
|
|
2003-08-22 18:16:30 +00:00
|
|
|
tmp->ofs = 0;
|
|
|
|
tmp->alias = def;
|
2001-11-13 18:11:19 +00:00
|
|
|
tmp->users = e2->e.temp.users;
|
2001-12-06 19:49:40 +00:00
|
|
|
tmp->freed = 1; // don't free this offset when freeing def
|
2001-11-13 18:11:19 +00:00
|
|
|
def = tmp;
|
|
|
|
}
|
|
|
|
e2->e.temp.def = def;
|
|
|
|
return e2->e.temp.def;
|
|
|
|
}
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static def_t *
|
2002-10-16 17:07:01 +00:00
|
|
|
emit_move_expr (expr_t *e)
|
|
|
|
{
|
|
|
|
expr_t *e1 = e->e.expr.e1;
|
|
|
|
expr_t *e2 = e->e.expr.e2;
|
2002-10-20 02:35:12 +00:00
|
|
|
expr_t *size_expr;
|
2002-10-16 17:07:01 +00:00
|
|
|
def_t *size, *src, *dst;
|
2002-10-20 02:35:12 +00:00
|
|
|
type_t *src_type, *dst_type;
|
2002-10-16 17:07:01 +00:00
|
|
|
opcode_t *op;
|
|
|
|
|
2002-10-20 02:35:12 +00:00
|
|
|
dst_type = get_type (e1);
|
|
|
|
src_type = get_type (e2);
|
2002-10-16 17:07:01 +00:00
|
|
|
src = emit_sub_expr (e2, 0);
|
|
|
|
dst = emit_sub_expr (e1, 0);
|
2003-05-13 19:42:14 +00:00
|
|
|
|
2002-10-20 02:35:12 +00:00
|
|
|
if (dst_type->type == ev_struct && src_type->type == ev_struct) {
|
|
|
|
size_expr = new_short_expr (type_size (dst->type));
|
|
|
|
} else if (dst_type->type == ev_struct) {
|
2003-07-30 20:57:50 +00:00
|
|
|
if (dst->alias)
|
|
|
|
dst = dst->alias;
|
2002-10-20 02:35:12 +00:00
|
|
|
dst = emit_sub_expr (address_expr (new_def_expr (dst), 0, 0), 0);
|
|
|
|
size_expr = new_integer_expr (type_size (dst_type));
|
|
|
|
} else if (src_type->type == ev_struct) {
|
2003-07-30 20:57:50 +00:00
|
|
|
if (src->alias)
|
|
|
|
src = src->alias;
|
2002-10-20 02:35:12 +00:00
|
|
|
src = emit_sub_expr (address_expr (new_def_expr (src), 0, 0), 0);
|
|
|
|
size_expr = new_integer_expr (type_size (dst_type->aux_type));
|
2002-10-16 17:07:01 +00:00
|
|
|
} else {
|
2002-10-20 02:35:12 +00:00
|
|
|
size_expr = new_integer_expr (type_size (dst_type->aux_type));
|
2002-10-16 17:07:01 +00:00
|
|
|
}
|
2002-10-20 02:35:12 +00:00
|
|
|
size = emit_sub_expr (size_expr, 0);
|
|
|
|
|
2003-04-22 15:29:32 +00:00
|
|
|
op = opcode_find ("<MOVE>", src->type, size->type, dst->type);
|
2002-10-16 17:07:01 +00:00
|
|
|
return emit_statement (e, op, src, size, dst);
|
|
|
|
}
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static def_t *
|
2002-06-12 22:37:18 +00:00
|
|
|
emit_address_expr (expr_t *e)
|
|
|
|
{
|
|
|
|
def_t *def_a, *def_b, *d;
|
|
|
|
opcode_t *op;
|
|
|
|
|
|
|
|
def_a = emit_sub_expr (e->e.expr.e1, 0);
|
|
|
|
def_b = emit_sub_expr (e->e.expr.e2, 0);
|
2003-04-22 15:29:32 +00:00
|
|
|
op = opcode_find ("&", def_a->type, def_b->type, 0);
|
2002-07-08 18:53:07 +00:00
|
|
|
d = emit_statement (e, op, def_a, def_b, 0);
|
2002-06-12 22:37:18 +00:00
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
2003-01-06 18:28:13 +00:00
|
|
|
static def_t *
|
2002-06-12 22:37:18 +00:00
|
|
|
emit_deref_expr (expr_t *e, def_t *dest)
|
|
|
|
{
|
|
|
|
def_t *d;
|
|
|
|
type_t *type = e->e.expr.type;
|
2002-06-13 07:20:15 +00:00
|
|
|
def_t *z;
|
|
|
|
opcode_t *op;
|
2002-06-12 22:37:18 +00:00
|
|
|
|
|
|
|
e = e->e.expr.e1;
|
2002-06-13 07:20:15 +00:00
|
|
|
if (e->type == ex_pointer) {
|
2003-04-22 15:29:32 +00:00
|
|
|
if (e->e.pointer.def) {
|
2003-08-21 02:21:30 +00:00
|
|
|
d = new_def (e->e.pointer.type, 0, e->e.pointer.def->scope);
|
2003-04-22 15:29:32 +00:00
|
|
|
d->local = e->e.pointer.def->local;
|
2003-08-21 02:21:30 +00:00
|
|
|
d->ofs = e->e.pointer.val;
|
|
|
|
d->alias = e->e.pointer.def;
|
2003-04-22 15:29:32 +00:00
|
|
|
} else if (e->e.pointer.val >= 0 && e->e.pointer.val < 65536) {
|
2002-06-13 07:20:15 +00:00
|
|
|
d = new_def (e->e.pointer.type, 0, current_scope);
|
|
|
|
d->ofs = e->e.pointer.val;
|
|
|
|
} else {
|
|
|
|
d = ReuseConstant (e, 0);
|
|
|
|
zero.type = ex_short;
|
|
|
|
z = emit_sub_expr (&zero, 0);
|
2003-04-22 15:29:32 +00:00
|
|
|
op = opcode_find (".", d->type, z->type, dest->type);
|
2002-07-08 18:53:07 +00:00
|
|
|
d = emit_statement (e, op, d, z, dest);
|
2002-06-13 07:20:15 +00:00
|
|
|
}
|
|
|
|
return d;
|
|
|
|
}
|
2003-07-30 04:11:45 +00:00
|
|
|
if (e->type == ex_uexpr && e->e.expr.op == '&'
|
|
|
|
&& e->e.expr.e1->type == ex_def) {
|
|
|
|
d = new_def (e->e.expr.type->aux_type, 0, current_scope);
|
|
|
|
d->alias = e->e.expr.e1->e.def;
|
|
|
|
d->local = d->alias->local;
|
|
|
|
d->ofs = d->alias->ofs;
|
|
|
|
return d;
|
|
|
|
}
|
2003-05-15 05:58:31 +00:00
|
|
|
if (!dest) {
|
2002-06-12 22:37:18 +00:00
|
|
|
dest = get_tempdef (type, current_scope);
|
2004-01-25 08:55:03 +00:00
|
|
|
dest->line = e->line;
|
|
|
|
dest->file = e->file;
|
2002-06-12 22:37:18 +00:00
|
|
|
dest->users += 2;
|
|
|
|
}
|
2005-06-09 10:34:03 +00:00
|
|
|
if (dest->type->type == ev_struct) {
|
|
|
|
expr_t *d = new_def_expr (dest);
|
|
|
|
expr_t *m = new_move_expr (d, e, dest->type);
|
|
|
|
d->line = dest->line;
|
|
|
|
d->file = dest->file;
|
|
|
|
m->line = e->line;
|
|
|
|
m->file = e->file;
|
|
|
|
emit_sub_expr (m, 0);
|
|
|
|
return dest;
|
|
|
|
}
|
2002-06-13 07:22:53 +00:00
|
|
|
|
2002-06-12 22:37:18 +00:00
|
|
|
if (e->type == ex_expr
|
|
|
|
&& e->e.expr.op == '&'
|
|
|
|
&& e->e.expr.e1->type < ex_string)
|
|
|
|
e->e.expr.op = '.';
|
|
|
|
d = emit_sub_expr (e, dest);
|
2002-06-13 07:22:53 +00:00
|
|
|
|
2002-06-12 22:37:18 +00:00
|
|
|
if (dest && d != dest) {
|
|
|
|
zero.type = ex_short;
|
|
|
|
z = emit_sub_expr (&zero, 0);
|
2003-04-22 15:29:32 +00:00
|
|
|
op = opcode_find (".", d->type, z->type, dest->type);
|
2002-07-08 18:53:07 +00:00
|
|
|
d = emit_statement (e, op, d, z, dest);
|
2002-06-12 22:37:18 +00:00
|
|
|
} else {
|
|
|
|
if (!d->name)
|
|
|
|
d->type = type;
|
|
|
|
}
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
2003-10-22 08:05:17 +00:00
|
|
|
static void
|
|
|
|
build_bool_block (expr_t *block, expr_t *e)
|
|
|
|
{
|
|
|
|
switch (e->type) {
|
|
|
|
case ex_bool:
|
|
|
|
build_bool_block (block, e->e.bool.e);
|
2003-10-22 09:14:53 +00:00
|
|
|
free_tempdefs ();
|
2003-10-22 08:05:17 +00:00
|
|
|
return;
|
|
|
|
case ex_label:
|
|
|
|
e->next = 0;
|
|
|
|
append_expr (block, e);
|
2003-10-22 09:14:53 +00:00
|
|
|
free_tempdefs ();
|
2003-10-22 08:05:17 +00:00
|
|
|
return;
|
|
|
|
case ex_expr:
|
|
|
|
if (e->e.expr.op == OR || e->e.expr.op == AND) {
|
|
|
|
build_bool_block (block, e->e.expr.e1);
|
|
|
|
build_bool_block (block, e->e.expr.e2);
|
|
|
|
} else if (e->e.expr.op == 'i') {
|
|
|
|
e->next = 0;
|
|
|
|
append_expr (block, e);
|
|
|
|
} else if (e->e.expr.op == 'n') {
|
|
|
|
e->next = 0;
|
|
|
|
append_expr (block, e);
|
|
|
|
}
|
2003-10-22 09:14:53 +00:00
|
|
|
free_tempdefs ();
|
2003-10-22 08:05:17 +00:00
|
|
|
return;
|
|
|
|
case ex_uexpr:
|
|
|
|
if (e->e.expr.op == 'g') {
|
|
|
|
e->next = 0;
|
|
|
|
append_expr (block, e);
|
2003-10-22 09:14:53 +00:00
|
|
|
free_tempdefs ();
|
2003-10-22 08:05:17 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ex_block:
|
|
|
|
if (!e->e.block.result) {
|
|
|
|
expr_t *t;
|
|
|
|
for (e = e->e.block.head; e; e = t) {
|
|
|
|
t = e->next;
|
|
|
|
build_bool_block (block, e);
|
|
|
|
}
|
2003-10-22 09:14:53 +00:00
|
|
|
free_tempdefs ();
|
2003-10-22 08:05:17 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
;
|
|
|
|
}
|
|
|
|
error (e, "internal error");
|
|
|
|
abort ();
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
is_goto (expr_t *e)
|
|
|
|
{
|
|
|
|
return e && e->type == ex_uexpr && e->e.expr.op == 'g';
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
is_if (expr_t *e)
|
|
|
|
{
|
|
|
|
return e && e->type == ex_expr && e->e.expr.op == 'i';
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
is_ifnot (expr_t *e)
|
|
|
|
{
|
|
|
|
return e && e->type == ex_expr && e->e.expr.op == 'n';
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
emit_bool_expr (expr_t *e)
|
|
|
|
{
|
|
|
|
expr_t *block = new_block_expr ();
|
|
|
|
expr_t **s;
|
|
|
|
expr_t *l;
|
|
|
|
|
|
|
|
build_bool_block (block, e);
|
|
|
|
|
|
|
|
s = &block->e.block.head;
|
|
|
|
while (*s) {
|
|
|
|
if (is_if (*s) && is_goto ((*s)->next)) {
|
|
|
|
l = (*s)->e.expr.e2;
|
|
|
|
for (e = (*s)->next->next; e && e->type == ex_label; e = e->next) {
|
|
|
|
if (e == l) {
|
|
|
|
e = *s;
|
|
|
|
e->e.expr.op = 'n';
|
|
|
|
e->e.expr.e2 = e->next->e.expr.e1;
|
|
|
|
e->next = e->next->next;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
s = &(*s)->next;
|
|
|
|
} else if (is_ifnot (*s) && is_goto ((*s)->next)) {
|
|
|
|
l = (*s)->e.expr.e2;
|
|
|
|
for (e = (*s)->next->next; e && e->type == ex_label; e = e->next) {
|
|
|
|
if (e == l) {
|
|
|
|
e = *s;
|
|
|
|
e->e.expr.op = 'i';
|
|
|
|
e->e.expr.e2 = e->next->e.expr.e1;
|
|
|
|
e->next = e->next->next;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
s = &(*s)->next;
|
|
|
|
} else if (is_goto (*s)) {
|
|
|
|
l = (*s)->e.expr.e1;
|
|
|
|
for (e = (*s)->next; e && e->type == ex_label; e = e->next) {
|
|
|
|
if (e == l) {
|
|
|
|
*s = (*s)->next;
|
|
|
|
l = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (l)
|
|
|
|
s = &(*s)->next;
|
|
|
|
} else {
|
|
|
|
s = &(*s)->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
emit_expr (block);
|
|
|
|
}
|
|
|
|
|
2001-07-26 05:15:34 +00:00
|
|
|
def_t *
|
|
|
|
emit_sub_expr (expr_t *e, def_t *dest)
|
|
|
|
{
|
2001-08-22 21:55:01 +00:00
|
|
|
opcode_t *op;
|
2001-10-25 17:48:35 +00:00
|
|
|
const char *operator;
|
2001-08-22 21:55:01 +00:00
|
|
|
def_t *def_a, *def_b, *d = 0;
|
2002-01-17 19:32:04 +00:00
|
|
|
def_t *tmp = 0;
|
2001-07-26 05:15:34 +00:00
|
|
|
|
|
|
|
switch (e->type) {
|
|
|
|
case ex_block:
|
2001-08-11 21:15:24 +00:00
|
|
|
if (e->e.block.result) {
|
2002-09-13 17:12:26 +00:00
|
|
|
expr_t *res = e->e.block.result;
|
2001-08-11 21:15:24 +00:00
|
|
|
for (e = e->e.block.head; e; e = e->next)
|
|
|
|
emit_expr (e);
|
2002-09-13 17:12:26 +00:00
|
|
|
d = emit_sub_expr (res, dest);
|
2001-08-11 21:15:24 +00:00
|
|
|
}
|
2003-10-22 08:05:17 +00:00
|
|
|
break;
|
2004-02-11 01:43:33 +00:00
|
|
|
case ex_state:
|
2003-10-22 08:05:17 +00:00
|
|
|
case ex_bool:
|
2001-12-08 08:19:48 +00:00
|
|
|
case ex_name:
|
2001-10-17 18:36:19 +00:00
|
|
|
case ex_nil:
|
2001-08-11 21:15:24 +00:00
|
|
|
case ex_label:
|
2002-05-01 22:08:59 +00:00
|
|
|
case ex_error:
|
2001-07-26 05:15:34 +00:00
|
|
|
error (e, "internal error");
|
|
|
|
abort ();
|
|
|
|
case ex_expr:
|
2002-10-20 02:35:12 +00:00
|
|
|
if (e->e.expr.op == 'M') {
|
|
|
|
d = emit_move_expr (e);
|
|
|
|
break;
|
|
|
|
}
|
2002-10-09 19:16:55 +00:00
|
|
|
if (e->e.expr.op == 'b') {
|
|
|
|
d = emit_bind_expr (e->e.expr.e1, e->e.expr.e2);
|
|
|
|
break;
|
|
|
|
}
|
2001-08-22 21:55:01 +00:00
|
|
|
if (e->e.expr.op == 'c') {
|
|
|
|
d = emit_function_call (e, dest);
|
|
|
|
break;
|
|
|
|
}
|
2001-12-12 20:35:58 +00:00
|
|
|
if (e->e.expr.op == '=' || e->e.expr.op == PAS) {
|
|
|
|
d = emit_assign_expr (e->e.expr.op, e);
|
2001-12-12 21:29:04 +00:00
|
|
|
if (!d->managed)
|
|
|
|
d->users++;
|
2001-08-22 21:55:01 +00:00
|
|
|
break;
|
|
|
|
}
|
2002-06-12 22:37:18 +00:00
|
|
|
if (e->e.expr.op == '&' && e->e.expr.type->type == ev_pointer) {
|
|
|
|
d = emit_address_expr (e);
|
|
|
|
break;
|
|
|
|
}
|
2001-08-24 21:47:52 +00:00
|
|
|
if (e->e.expr.e1->type == ex_block
|
|
|
|
&& e->e.expr.e1->e.block.is_call) {
|
|
|
|
def_b = emit_sub_expr (e->e.expr.e2, 0);
|
|
|
|
def_a = emit_sub_expr (e->e.expr.e1, 0);
|
|
|
|
} else {
|
|
|
|
def_a = emit_sub_expr (e->e.expr.e1, 0);
|
|
|
|
def_b = emit_sub_expr (e->e.expr.e2, 0);
|
|
|
|
}
|
2001-10-25 17:48:35 +00:00
|
|
|
operator = get_op_string (e->e.expr.op);
|
2001-08-22 21:55:01 +00:00
|
|
|
if (!dest) {
|
2002-06-09 04:30:02 +00:00
|
|
|
dest = get_tempdef (e->e.expr.type, current_scope);
|
2004-01-25 08:55:03 +00:00
|
|
|
dest->file = e->file;
|
|
|
|
dest->line = e->line;
|
2001-08-22 21:55:01 +00:00
|
|
|
dest->users += 2;
|
|
|
|
}
|
2003-04-22 15:29:32 +00:00
|
|
|
op = opcode_find (operator, def_a->type, def_b->type,
|
2003-08-24 20:38:32 +00:00
|
|
|
dest->type);
|
2002-07-08 18:53:07 +00:00
|
|
|
d = emit_statement (e, op, def_a, def_b, dest);
|
2001-08-22 21:55:01 +00:00
|
|
|
break;
|
2001-07-26 05:15:34 +00:00
|
|
|
case ex_uexpr:
|
2002-01-17 19:32:04 +00:00
|
|
|
switch (e->e.expr.op) {
|
|
|
|
case '!':
|
|
|
|
operator = "!";
|
|
|
|
def_a = emit_sub_expr (e->e.expr.e1, 0);
|
2001-12-12 08:39:47 +00:00
|
|
|
def_b = &def_void;
|
2002-01-17 19:32:04 +00:00
|
|
|
break;
|
|
|
|
case '~':
|
|
|
|
operator = "~";
|
|
|
|
def_a = emit_sub_expr (e->e.expr.e1, 0);
|
|
|
|
def_b = &def_void;
|
|
|
|
break;
|
|
|
|
case '-':
|
|
|
|
zero.type = expr_types[extract_type (e->e.expr.e1)];
|
|
|
|
|
|
|
|
operator = "-";
|
2002-06-04 18:44:03 +00:00
|
|
|
def_a = ReuseConstant (&zero, 0);
|
2002-01-17 19:32:04 +00:00
|
|
|
def_b = emit_sub_expr (e->e.expr.e1, 0);
|
|
|
|
if (!dest) {
|
2002-06-09 04:30:02 +00:00
|
|
|
dest = get_tempdef (e->e.expr.type, current_scope);
|
2004-01-25 08:55:03 +00:00
|
|
|
dest->file = e->file;
|
|
|
|
dest->line = e->line;
|
2002-01-17 19:32:04 +00:00
|
|
|
dest->users += 2;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '&':
|
|
|
|
zero.type = ex_short;
|
|
|
|
|
|
|
|
operator = "&";
|
|
|
|
if (e->e.expr.e1->type == ex_expr
|
|
|
|
&& e->e.expr.e1->e.expr.op == '.') {
|
2002-06-09 04:30:02 +00:00
|
|
|
tmp = get_tempdef (e->e.expr.type, current_scope);
|
2004-01-25 08:55:03 +00:00
|
|
|
tmp->file = e->file;
|
|
|
|
tmp->line = e->line;
|
2002-01-17 19:32:04 +00:00
|
|
|
tmp->users += 2;
|
|
|
|
def_b = emit_sub_expr (&zero, 0);
|
|
|
|
} else {
|
|
|
|
def_b = &def_void;
|
|
|
|
}
|
|
|
|
def_a = emit_sub_expr (e->e.expr.e1, tmp);
|
|
|
|
if (!dest) {
|
2002-06-09 04:30:02 +00:00
|
|
|
dest = get_tempdef (e->e.expr.type, current_scope);
|
2004-01-25 08:55:03 +00:00
|
|
|
dest->file = e->file;
|
|
|
|
dest->line = e->line;
|
2002-01-17 19:32:04 +00:00
|
|
|
dest->users += 2;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '.':
|
2002-06-12 22:37:18 +00:00
|
|
|
return emit_deref_expr (e, dest);
|
2002-01-17 19:32:04 +00:00
|
|
|
case 'C':
|
2002-05-22 05:03:36 +00:00
|
|
|
def_a = emit_sub_expr (e->e.expr.e1, 0);
|
2003-03-10 21:23:05 +00:00
|
|
|
if ((def_a->type->type == ev_pointer
|
|
|
|
&& e->e.expr.type->type == ev_pointer)
|
|
|
|
|| (def_a->type->type == ev_func
|
|
|
|
&& e->e.expr.type->type == ev_func)) {
|
2002-05-22 05:03:36 +00:00
|
|
|
return def_a;
|
|
|
|
}
|
2003-08-24 08:03:25 +00:00
|
|
|
if ((def_a->type->type == ev_pointer
|
|
|
|
&& (e->e.expr.type->type == ev_integer
|
|
|
|
|| e->e.expr.type->type == ev_uinteger))
|
|
|
|
|| ((def_a->type->type == ev_integer
|
|
|
|
|| def_a->type->type == ev_uinteger)
|
2003-09-02 16:45:36 +00:00
|
|
|
&& e->e.expr.type->type == ev_pointer)
|
|
|
|
|| (def_a->type->type == ev_integer
|
|
|
|
&& e->e.expr.type->type == ev_uinteger)
|
|
|
|
|| (def_a->type->type == ev_uinteger
|
|
|
|
&& e->e.expr.type->type == ev_integer)) {
|
2003-08-24 08:03:25 +00:00
|
|
|
def_t *tmp;
|
|
|
|
tmp = new_def (e->e.expr.type, 0, def_a->scope);
|
|
|
|
tmp->ofs = 0;
|
|
|
|
tmp->alias = def_a;
|
2003-09-02 06:23:57 +00:00
|
|
|
tmp->users = def_a->users;
|
2003-08-24 08:03:25 +00:00
|
|
|
tmp->freed = 1;
|
|
|
|
return tmp;
|
|
|
|
}
|
2002-05-22 05:03:36 +00:00
|
|
|
def_b = &def_void;
|
2002-01-17 19:32:04 +00:00
|
|
|
if (!dest) {
|
2002-06-09 04:30:02 +00:00
|
|
|
dest = get_tempdef (e->e.expr.type, current_scope);
|
2004-01-25 08:55:03 +00:00
|
|
|
dest->file = e->file;
|
|
|
|
dest->line = e->line;
|
2002-01-17 19:32:04 +00:00
|
|
|
dest->users = 2;
|
|
|
|
}
|
|
|
|
operator = "=";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
abort ();
|
2001-07-26 05:15:34 +00:00
|
|
|
}
|
2003-04-22 15:29:32 +00:00
|
|
|
op = opcode_find (operator, def_a->type, def_b->type,
|
|
|
|
dest ? dest->type : 0);
|
2002-07-08 18:53:07 +00:00
|
|
|
d = emit_statement (e, op, def_a, def_b, dest);
|
2001-08-22 21:55:01 +00:00
|
|
|
break;
|
2001-07-26 05:15:34 +00:00
|
|
|
case ex_def:
|
2001-08-22 21:55:01 +00:00
|
|
|
d = e->e.def;
|
|
|
|
break;
|
2001-08-11 21:15:24 +00:00
|
|
|
case ex_temp:
|
2001-08-12 02:38:12 +00:00
|
|
|
if (!e->e.temp.def) {
|
|
|
|
if (dest)
|
|
|
|
e->e.temp.def = dest;
|
2004-01-25 08:55:03 +00:00
|
|
|
else {
|
2002-06-09 04:30:02 +00:00
|
|
|
e->e.temp.def = get_tempdef (e->e.temp.type, current_scope);
|
2004-01-25 08:55:03 +00:00
|
|
|
e->e.temp.def->line = e->line;
|
|
|
|
e->e.temp.def->file = e->file;
|
|
|
|
}
|
2001-08-22 21:55:01 +00:00
|
|
|
e->e.temp.def->users = e->e.temp.users;
|
|
|
|
e->e.temp.def->expr = e;
|
2001-12-12 21:29:04 +00:00
|
|
|
e->e.temp.def->managed = 1;
|
2001-08-12 02:38:12 +00:00
|
|
|
}
|
2001-08-22 21:55:01 +00:00
|
|
|
d = e->e.temp.def;
|
|
|
|
break;
|
2001-12-12 08:39:47 +00:00
|
|
|
case ex_pointer:
|
2001-07-26 05:15:34 +00:00
|
|
|
case ex_string:
|
|
|
|
case ex_float:
|
|
|
|
case ex_vector:
|
|
|
|
case ex_entity:
|
|
|
|
case ex_field:
|
|
|
|
case ex_func:
|
|
|
|
case ex_quaternion:
|
|
|
|
case ex_integer:
|
2001-11-13 08:58:54 +00:00
|
|
|
case ex_uinteger:
|
2002-06-04 18:44:03 +00:00
|
|
|
d = ReuseConstant (e, 0);
|
2001-08-22 21:55:01 +00:00
|
|
|
break;
|
2001-12-07 20:10:30 +00:00
|
|
|
case ex_short:
|
2002-07-12 16:01:40 +00:00
|
|
|
d = new_def (&type_short, 0, 0);
|
2001-12-07 20:10:30 +00:00
|
|
|
d->ofs = e->e.short_val;
|
|
|
|
d->absolute = 1;
|
2001-12-08 08:19:48 +00:00
|
|
|
d->users = 1;
|
2001-12-07 20:10:30 +00:00
|
|
|
break;
|
2001-07-26 05:15:34 +00:00
|
|
|
}
|
2002-06-09 04:30:02 +00:00
|
|
|
free_tempdefs ();
|
2001-08-22 21:55:01 +00:00
|
|
|
return d;
|
2001-07-26 05:15:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
emit_expr (expr_t *e)
|
|
|
|
{
|
2001-12-06 19:49:40 +00:00
|
|
|
def_t *def;
|
|
|
|
def_t *def_a;
|
|
|
|
def_t *def_b;
|
2004-02-11 01:43:33 +00:00
|
|
|
def_t *def_c;
|
2002-05-11 03:37:36 +00:00
|
|
|
ex_label_t *label;
|
2004-02-11 01:43:33 +00:00
|
|
|
opcode_t *op;
|
2001-07-26 05:15:34 +00:00
|
|
|
|
2002-02-21 20:34:04 +00:00
|
|
|
//printf ("%d ", e->line);
|
|
|
|
//print_expr (e);
|
|
|
|
//puts ("");
|
2001-07-26 05:15:34 +00:00
|
|
|
switch (e->type) {
|
2002-05-01 22:08:59 +00:00
|
|
|
case ex_error:
|
|
|
|
break;
|
2004-02-11 01:43:33 +00:00
|
|
|
case ex_state:
|
|
|
|
def_a = emit_sub_expr (e->e.state.frame, 0);
|
|
|
|
def_b = emit_sub_expr (e->e.state.think, 0);
|
|
|
|
if (e->e.state.step) {
|
|
|
|
def_c = emit_sub_expr (e->e.state.step, 0);
|
|
|
|
op = op_state_f;
|
|
|
|
} else {
|
|
|
|
def_c = 0;
|
|
|
|
op = op_state;
|
|
|
|
}
|
|
|
|
emit_statement (e, op, def_a, def_b, def_c);
|
|
|
|
break;
|
|
|
|
case ex_bool:
|
|
|
|
emit_bool_expr (e);
|
|
|
|
break;
|
2001-07-26 05:15:34 +00:00
|
|
|
case ex_label:
|
|
|
|
label = &e->e.label;
|
2002-07-08 20:31:59 +00:00
|
|
|
label->ofs = pr.code->size;
|
2002-07-17 18:45:17 +00:00
|
|
|
relocate_refs (label->refs, label->ofs);
|
2001-07-26 05:15:34 +00:00
|
|
|
break;
|
|
|
|
case ex_block:
|
|
|
|
for (e = e->e.block.head; e; e = e->next)
|
|
|
|
emit_expr (e);
|
|
|
|
break;
|
|
|
|
case ex_expr:
|
|
|
|
switch (e->e.expr.op) {
|
2002-10-16 17:07:01 +00:00
|
|
|
case 'M':
|
|
|
|
emit_move_expr (e);
|
|
|
|
break;
|
2001-12-12 08:39:47 +00:00
|
|
|
case PAS:
|
2001-07-26 05:15:34 +00:00
|
|
|
case '=':
|
2001-12-12 20:35:58 +00:00
|
|
|
emit_assign_expr (e->e.expr.op, e);
|
2001-07-26 05:15:34 +00:00
|
|
|
break;
|
|
|
|
case 'n':
|
2002-07-08 18:53:07 +00:00
|
|
|
emit_branch (e, op_ifnot, e->e.expr.e1, e->e.expr.e2);
|
2001-07-26 05:15:34 +00:00
|
|
|
break;
|
|
|
|
case 'i':
|
2002-07-08 18:53:07 +00:00
|
|
|
emit_branch (e, op_if, e->e.expr.e1, e->e.expr.e2);
|
2001-07-26 05:15:34 +00:00
|
|
|
break;
|
pr_comp.h:
o add ev_uniteger to the types enum
o add opcodes for ifbe, ifb, ifae, ifa, jump, lt.ui, gt.ui, le.ui, ge.ui
progs.h:
o add uinteger accessors
pr_exec.c:
o implement ifbe, ifb, ifae, ifa, jump, lt.ui, gt.ui, le.ui, ge.ui
pr_opcode.c:
o add opcodes for ifbe, ifb, ifae, ifa, jump, lt.ui, gt.ui, le.ui, ge.ui
expr.h:
o prototype inc_users
qfcc.h:
o add externs for op_ifbe, op_ifb, op_ifae and op_ifa
emit.c:
o don't bother emiting an assignment to a temp def that's only used once
(ie, it's never read, only written to)
o support the new if* instructions
expr.c:
o support the new if* insructions
o dectect expression loops in append_expr
o support unsigned integers
o re-work temp def usage counting
pr_def.c
o debugging for temp def usage counts
pr_opcode.c:
o support the new if* instructions
qc-parse.y:
o provide defines for IFBE IFB IFAE IFA
switch.c:
o do binary searches for strings, floats and ints if there are more than
8 cases in a switch. Strings need more testing.
2001-11-09 00:58:16 +00:00
|
|
|
case IFBE:
|
2002-07-08 18:53:07 +00:00
|
|
|
emit_branch (e, op_ifbe, e->e.expr.e1, e->e.expr.e2);
|
pr_comp.h:
o add ev_uniteger to the types enum
o add opcodes for ifbe, ifb, ifae, ifa, jump, lt.ui, gt.ui, le.ui, ge.ui
progs.h:
o add uinteger accessors
pr_exec.c:
o implement ifbe, ifb, ifae, ifa, jump, lt.ui, gt.ui, le.ui, ge.ui
pr_opcode.c:
o add opcodes for ifbe, ifb, ifae, ifa, jump, lt.ui, gt.ui, le.ui, ge.ui
expr.h:
o prototype inc_users
qfcc.h:
o add externs for op_ifbe, op_ifb, op_ifae and op_ifa
emit.c:
o don't bother emiting an assignment to a temp def that's only used once
(ie, it's never read, only written to)
o support the new if* instructions
expr.c:
o support the new if* insructions
o dectect expression loops in append_expr
o support unsigned integers
o re-work temp def usage counting
pr_def.c
o debugging for temp def usage counts
pr_opcode.c:
o support the new if* instructions
qc-parse.y:
o provide defines for IFBE IFB IFAE IFA
switch.c:
o do binary searches for strings, floats and ints if there are more than
8 cases in a switch. Strings need more testing.
2001-11-09 00:58:16 +00:00
|
|
|
break;
|
|
|
|
case IFB:
|
2002-07-08 18:53:07 +00:00
|
|
|
emit_branch (e, op_ifb, e->e.expr.e1, e->e.expr.e2);
|
pr_comp.h:
o add ev_uniteger to the types enum
o add opcodes for ifbe, ifb, ifae, ifa, jump, lt.ui, gt.ui, le.ui, ge.ui
progs.h:
o add uinteger accessors
pr_exec.c:
o implement ifbe, ifb, ifae, ifa, jump, lt.ui, gt.ui, le.ui, ge.ui
pr_opcode.c:
o add opcodes for ifbe, ifb, ifae, ifa, jump, lt.ui, gt.ui, le.ui, ge.ui
expr.h:
o prototype inc_users
qfcc.h:
o add externs for op_ifbe, op_ifb, op_ifae and op_ifa
emit.c:
o don't bother emiting an assignment to a temp def that's only used once
(ie, it's never read, only written to)
o support the new if* instructions
expr.c:
o support the new if* insructions
o dectect expression loops in append_expr
o support unsigned integers
o re-work temp def usage counting
pr_def.c
o debugging for temp def usage counts
pr_opcode.c:
o support the new if* instructions
qc-parse.y:
o provide defines for IFBE IFB IFAE IFA
switch.c:
o do binary searches for strings, floats and ints if there are more than
8 cases in a switch. Strings need more testing.
2001-11-09 00:58:16 +00:00
|
|
|
break;
|
|
|
|
case IFAE:
|
2002-07-08 18:53:07 +00:00
|
|
|
emit_branch (e, op_ifae, e->e.expr.e1, e->e.expr.e2);
|
pr_comp.h:
o add ev_uniteger to the types enum
o add opcodes for ifbe, ifb, ifae, ifa, jump, lt.ui, gt.ui, le.ui, ge.ui
progs.h:
o add uinteger accessors
pr_exec.c:
o implement ifbe, ifb, ifae, ifa, jump, lt.ui, gt.ui, le.ui, ge.ui
pr_opcode.c:
o add opcodes for ifbe, ifb, ifae, ifa, jump, lt.ui, gt.ui, le.ui, ge.ui
expr.h:
o prototype inc_users
qfcc.h:
o add externs for op_ifbe, op_ifb, op_ifae and op_ifa
emit.c:
o don't bother emiting an assignment to a temp def that's only used once
(ie, it's never read, only written to)
o support the new if* instructions
expr.c:
o support the new if* insructions
o dectect expression loops in append_expr
o support unsigned integers
o re-work temp def usage counting
pr_def.c
o debugging for temp def usage counts
pr_opcode.c:
o support the new if* instructions
qc-parse.y:
o provide defines for IFBE IFB IFAE IFA
switch.c:
o do binary searches for strings, floats and ints if there are more than
8 cases in a switch. Strings need more testing.
2001-11-09 00:58:16 +00:00
|
|
|
break;
|
|
|
|
case IFA:
|
2002-07-08 18:53:07 +00:00
|
|
|
emit_branch (e, op_ifa, e->e.expr.e1, e->e.expr.e2);
|
pr_comp.h:
o add ev_uniteger to the types enum
o add opcodes for ifbe, ifb, ifae, ifa, jump, lt.ui, gt.ui, le.ui, ge.ui
progs.h:
o add uinteger accessors
pr_exec.c:
o implement ifbe, ifb, ifae, ifa, jump, lt.ui, gt.ui, le.ui, ge.ui
pr_opcode.c:
o add opcodes for ifbe, ifb, ifae, ifa, jump, lt.ui, gt.ui, le.ui, ge.ui
expr.h:
o prototype inc_users
qfcc.h:
o add externs for op_ifbe, op_ifb, op_ifae and op_ifa
emit.c:
o don't bother emiting an assignment to a temp def that's only used once
(ie, it's never read, only written to)
o support the new if* instructions
expr.c:
o support the new if* insructions
o dectect expression loops in append_expr
o support unsigned integers
o re-work temp def usage counting
pr_def.c
o debugging for temp def usage counts
pr_opcode.c:
o support the new if* instructions
qc-parse.y:
o provide defines for IFBE IFB IFAE IFA
switch.c:
o do binary searches for strings, floats and ints if there are more than
8 cases in a switch. Strings need more testing.
2001-11-09 00:58:16 +00:00
|
|
|
break;
|
2001-07-26 05:15:34 +00:00
|
|
|
case 'c':
|
|
|
|
emit_function_call (e, 0);
|
|
|
|
break;
|
2001-08-24 21:14:04 +00:00
|
|
|
case 'b':
|
2001-11-13 18:11:19 +00:00
|
|
|
emit_bind_expr (e->e.expr.e1, e->e.expr.e2);
|
2001-08-24 21:14:04 +00:00
|
|
|
break;
|
2001-11-13 08:58:54 +00:00
|
|
|
case 'g':
|
|
|
|
def_a = emit_sub_expr (e->e.expr.e1, 0);
|
|
|
|
def_b = emit_sub_expr (e->e.expr.e2, 0);
|
2002-07-08 18:53:07 +00:00
|
|
|
emit_statement (e, op_jumpb, def_a, def_b, 0);
|
2001-11-13 08:58:54 +00:00
|
|
|
break;
|
2001-07-26 05:15:34 +00:00
|
|
|
default:
|
2004-02-17 00:39:21 +00:00
|
|
|
if (options.warnings.executable)
|
|
|
|
warning (e, "Non-executable statement; "
|
|
|
|
"executing programmer instead.");
|
2001-07-26 05:15:34 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ex_uexpr:
|
|
|
|
switch (e->e.expr.op) {
|
|
|
|
case 'r':
|
|
|
|
def = 0;
|
|
|
|
if (e->e.expr.e1)
|
|
|
|
def = emit_sub_expr (e->e.expr.e1, 0);
|
2002-07-08 18:53:07 +00:00
|
|
|
emit_statement (e, op_return, def, 0, 0);
|
2001-07-26 05:15:34 +00:00
|
|
|
break;
|
|
|
|
case 'g':
|
2002-07-08 18:53:07 +00:00
|
|
|
emit_branch (e, op_goto, 0, e->e.expr.e1);
|
2001-07-26 05:15:34 +00:00
|
|
|
break;
|
|
|
|
default:
|
2004-02-17 00:39:21 +00:00
|
|
|
if (options.warnings.executable)
|
|
|
|
warning (e, "Non-executable statement; "
|
|
|
|
"executing programmer instead.");
|
2001-07-26 05:15:34 +00:00
|
|
|
emit_expr (e->e.expr.e1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ex_def:
|
2001-08-11 21:15:24 +00:00
|
|
|
case ex_temp:
|
2001-07-26 05:15:34 +00:00
|
|
|
case ex_string:
|
|
|
|
case ex_float:
|
|
|
|
case ex_vector:
|
|
|
|
case ex_entity:
|
|
|
|
case ex_field:
|
|
|
|
case ex_func:
|
|
|
|
case ex_pointer:
|
|
|
|
case ex_quaternion:
|
|
|
|
case ex_integer:
|
2001-11-13 08:58:54 +00:00
|
|
|
case ex_uinteger:
|
2001-12-07 20:10:30 +00:00
|
|
|
case ex_short:
|
2002-02-21 20:34:04 +00:00
|
|
|
case ex_name:
|
|
|
|
case ex_nil:
|
2004-02-17 00:39:21 +00:00
|
|
|
if (options.warnings.executable)
|
|
|
|
warning (e, "Non-executable statement; "
|
|
|
|
"executing programmer instead.");
|
2001-07-26 05:15:34 +00:00
|
|
|
break;
|
|
|
|
}
|
2002-06-09 04:30:02 +00:00
|
|
|
free_tempdefs ();
|
2001-07-26 05:15:34 +00:00
|
|
|
}
|