2002-10-22 14:53:18 +00:00
|
|
|
/*
|
|
|
|
def.c
|
2001-04-01 02:12:57 +00:00
|
|
|
|
2002-10-22 14:53:18 +00:00
|
|
|
def management and symbol tables
|
2001-04-01 02:12:57 +00:00
|
|
|
|
2002-10-22 14:53:18 +00:00
|
|
|
Copyright (C) 2002 Bill Currie <bill@taniwha.org>
|
|
|
|
Copyright (C) 1996-1997 Id Software, Inc.
|
2001-04-01 02:12:57 +00:00
|
|
|
|
2002-10-22 14:53:18 +00:00
|
|
|
Author: Bill Currie <bill@taniwha.org>
|
|
|
|
Date: 2002/06/09
|
|
|
|
|
|
|
|
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
|
2001-04-01 02:12:57 +00:00
|
|
|
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
2003-01-15 15:31:36 +00:00
|
|
|
|
2002-06-01 04:41:25 +00:00
|
|
|
#ifdef HAVE_STRING_H
|
|
|
|
# include <string.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_STRINGS_H
|
|
|
|
# include <strings.h>
|
|
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
2012-12-06 11:52:53 +00:00
|
|
|
#include "QF/alloc.h"
|
|
|
|
#include "QF/hash.h"
|
|
|
|
#include "QF/sys.h"
|
|
|
|
#include "QF/va.h"
|
2001-04-01 02:12:57 +00:00
|
|
|
|
2020-06-21 14:15:17 +00:00
|
|
|
#include "tools/qfcc/include/qfcc.h"
|
|
|
|
#include "tools/qfcc/include/class.h"
|
|
|
|
#include "tools/qfcc/include/def.h"
|
|
|
|
#include "tools/qfcc/include/defspace.h"
|
|
|
|
#include "tools/qfcc/include/diagnostic.h"
|
|
|
|
#include "tools/qfcc/include/emit.h"
|
|
|
|
#include "tools/qfcc/include/expr.h"
|
2023-08-21 03:32:17 +00:00
|
|
|
#include "tools/qfcc/include/evaluate.h"
|
2020-06-21 14:15:17 +00:00
|
|
|
#include "tools/qfcc/include/function.h"
|
|
|
|
#include "tools/qfcc/include/options.h"
|
|
|
|
#include "tools/qfcc/include/reloc.h"
|
|
|
|
#include "tools/qfcc/include/shared.h"
|
|
|
|
#include "tools/qfcc/include/strpool.h"
|
|
|
|
#include "tools/qfcc/include/struct.h"
|
|
|
|
#include "tools/qfcc/include/symtab.h"
|
|
|
|
#include "tools/qfcc/include/type.h"
|
|
|
|
#include "tools/qfcc/include/value.h"
|
2001-04-01 02:12:57 +00:00
|
|
|
|
2023-03-05 07:26:37 +00:00
|
|
|
ALLOC_STATE (def_t, defs);
|
2002-06-09 03:57:20 +00:00
|
|
|
|
2011-01-24 06:41:43 +00:00
|
|
|
static void
|
2002-07-02 21:34:40 +00:00
|
|
|
set_storage_bits (def_t *def, storage_class_t storage)
|
2002-06-17 02:43:38 +00:00
|
|
|
{
|
2002-07-02 21:34:40 +00:00
|
|
|
switch (storage) {
|
2012-12-02 01:11:30 +00:00
|
|
|
case sc_system:
|
2002-09-16 15:42:11 +00:00
|
|
|
def->system = 1;
|
|
|
|
// fall through
|
2012-12-02 01:11:30 +00:00
|
|
|
case sc_global:
|
2002-07-02 21:34:40 +00:00
|
|
|
def->global = 1;
|
|
|
|
def->external = 0;
|
2002-07-12 06:17:24 +00:00
|
|
|
def->local = 0;
|
2012-11-20 08:50:59 +00:00
|
|
|
def->param = 0;
|
2023-02-26 11:39:10 +00:00
|
|
|
def->argument = 0;
|
2002-07-02 21:34:40 +00:00
|
|
|
break;
|
2012-12-02 01:11:30 +00:00
|
|
|
case sc_extern:
|
2002-07-02 21:34:40 +00:00
|
|
|
def->global = 1;
|
|
|
|
def->external = 1;
|
2002-07-12 06:17:24 +00:00
|
|
|
def->local = 0;
|
2012-11-20 08:50:59 +00:00
|
|
|
def->param = 0;
|
2023-02-26 11:39:10 +00:00
|
|
|
def->argument = 0;
|
2002-07-02 21:34:40 +00:00
|
|
|
break;
|
2012-12-02 01:11:30 +00:00
|
|
|
case sc_static:
|
2002-07-02 21:34:40 +00:00
|
|
|
def->external = 0;
|
|
|
|
def->global = 0;
|
2002-07-12 06:17:24 +00:00
|
|
|
def->local = 0;
|
2012-11-20 08:50:59 +00:00
|
|
|
def->param = 0;
|
2023-02-26 11:39:10 +00:00
|
|
|
def->argument = 0;
|
2002-07-02 21:34:40 +00:00
|
|
|
break;
|
2012-12-02 01:11:30 +00:00
|
|
|
case sc_local:
|
2002-07-12 06:17:24 +00:00
|
|
|
def->external = 0;
|
|
|
|
def->global = 0;
|
|
|
|
def->local = 1;
|
2012-11-20 08:50:59 +00:00
|
|
|
def->param = 0;
|
2023-02-26 11:39:10 +00:00
|
|
|
def->argument = 0;
|
2012-11-20 08:50:59 +00:00
|
|
|
break;
|
2012-12-02 01:11:30 +00:00
|
|
|
case sc_param:
|
2012-11-20 08:50:59 +00:00
|
|
|
def->external = 0;
|
|
|
|
def->global = 0;
|
|
|
|
def->local = 1;
|
|
|
|
def->param = 1;
|
2023-02-26 11:39:10 +00:00
|
|
|
def->argument = 0;
|
|
|
|
break;
|
|
|
|
case sc_argument:
|
|
|
|
def->external = 0;
|
|
|
|
def->global = 0;
|
|
|
|
def->local = 1;
|
|
|
|
def->param = 0;
|
|
|
|
def->argument = 1;
|
2002-07-02 21:34:40 +00:00
|
|
|
break;
|
|
|
|
}
|
2002-07-02 23:08:44 +00:00
|
|
|
def->initialized = 0;
|
2002-06-17 02:43:38 +00:00
|
|
|
}
|
|
|
|
|
2003-07-23 18:28:31 +00:00
|
|
|
def_t *
|
2011-01-24 06:41:43 +00:00
|
|
|
new_def (const char *name, type_t *type, defspace_t *space,
|
2002-06-28 17:59:32 +00:00
|
|
|
storage_class_t storage)
|
2001-04-01 02:12:57 +00:00
|
|
|
{
|
2001-12-06 19:49:40 +00:00
|
|
|
def_t *def;
|
2001-04-01 02:12:57 +00:00
|
|
|
|
2002-06-05 21:13:29 +00:00
|
|
|
ALLOC (16384, def_t, defs, def);
|
2001-06-04 05:45:51 +00:00
|
|
|
|
2002-06-09 03:57:20 +00:00
|
|
|
def->return_addr = __builtin_return_address (0);
|
2001-04-01 02:12:57 +00:00
|
|
|
|
2002-07-03 19:12:29 +00:00
|
|
|
def->name = name ? save_string (name) : 0;
|
2001-04-01 02:12:57 +00:00
|
|
|
def->type = type;
|
|
|
|
|
2011-02-18 00:04:33 +00:00
|
|
|
def->file = pr.source_file;
|
|
|
|
def->line = pr.source_line;
|
|
|
|
|
|
|
|
set_storage_bits (def, storage);
|
|
|
|
|
|
|
|
if (space) {
|
2012-12-04 05:18:17 +00:00
|
|
|
if (space->type == ds_virtual && storage == sc_static)
|
|
|
|
internal_error (0, "static in a virtual space");
|
|
|
|
if (space->type != ds_virtual
|
|
|
|
&& (storage == sc_param || storage == sc_local))
|
|
|
|
internal_error (0, "param or local in a non-virtual space");
|
2011-02-18 00:04:33 +00:00
|
|
|
def->space = space;
|
|
|
|
*space->def_tail = def;
|
|
|
|
space->def_tail = &def->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!type)
|
|
|
|
return def;
|
|
|
|
|
2012-12-02 01:11:30 +00:00
|
|
|
if (!space && storage != sc_extern)
|
2011-02-18 00:04:33 +00:00
|
|
|
internal_error (0, "non-external def with no storage space");
|
|
|
|
|
2020-03-30 09:55:04 +00:00
|
|
|
if (is_class (type) || (is_array (type) && is_class(type->t.array.type))) {
|
2012-12-18 11:01:36 +00:00
|
|
|
error (0, "statically allocated instance of class %s",
|
|
|
|
type->t.class->name);
|
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
2012-12-02 01:11:30 +00:00
|
|
|
if (storage != sc_extern) {
|
2011-02-13 10:26:20 +00:00
|
|
|
int size = type_size (type);
|
2020-02-14 17:21:21 +00:00
|
|
|
int alignment = type->alignment;
|
|
|
|
|
2011-02-13 10:26:20 +00:00
|
|
|
if (!size) {
|
|
|
|
error (0, "%s has incomplete type", name);
|
|
|
|
size = 1;
|
2020-02-23 14:46:47 +00:00
|
|
|
alignment = 1;
|
2011-02-13 10:26:20 +00:00
|
|
|
}
|
2020-02-14 17:21:21 +00:00
|
|
|
if (alignment < 1) {
|
|
|
|
print_type (type);
|
2020-03-30 09:55:04 +00:00
|
|
|
internal_error (0, "type has no alignment");
|
2020-02-14 17:21:21 +00:00
|
|
|
}
|
|
|
|
def->offset = defspace_alloc_aligned_loc (space, size, alignment);
|
2011-02-09 15:15:19 +00:00
|
|
|
}
|
2001-12-06 19:49:40 +00:00
|
|
|
|
2001-06-05 05:22:11 +00:00
|
|
|
return def;
|
2001-06-04 17:52:50 +00:00
|
|
|
}
|
|
|
|
|
2011-01-25 06:42:26 +00:00
|
|
|
def_t *
|
2012-12-03 02:50:26 +00:00
|
|
|
alias_def (def_t *def, type_t *type, int offset)
|
2011-01-25 06:42:26 +00:00
|
|
|
{
|
|
|
|
def_t *alias;
|
|
|
|
|
2012-05-03 04:27:30 +00:00
|
|
|
if (def->alias) {
|
|
|
|
expr_t e;
|
|
|
|
e.file = def->file;
|
|
|
|
e.line = def->line;
|
2012-12-03 02:36:14 +00:00
|
|
|
internal_error (&e, "aliasing an alias def");
|
2012-05-03 04:27:30 +00:00
|
|
|
}
|
2012-12-03 02:38:55 +00:00
|
|
|
if (type_size (type) > type_size (def->type))
|
|
|
|
internal_error (0, "aliasing a def to a larger type");
|
2012-12-03 02:50:26 +00:00
|
|
|
if (offset < 0 || offset + type_size (type) > type_size (def->type))
|
|
|
|
internal_error (0, "invalid alias offset");
|
2012-12-03 03:40:00 +00:00
|
|
|
for (alias = def->alias_defs; alias; alias = alias->next) {
|
|
|
|
if (alias->type == type && alias->offset == offset)
|
|
|
|
return alias;
|
|
|
|
}
|
2011-01-25 06:42:26 +00:00
|
|
|
ALLOC (16384, def_t, defs, alias);
|
2021-01-31 07:01:20 +00:00
|
|
|
alias->name = save_string (va (0, "[%s:%d]", def->name, offset));
|
2011-03-23 12:32:14 +00:00
|
|
|
alias->return_addr = __builtin_return_address (0);
|
2012-12-03 02:50:26 +00:00
|
|
|
alias->offset = offset;
|
|
|
|
alias->offset_reloc = 1;
|
2011-01-25 06:42:26 +00:00
|
|
|
alias->type = type;
|
|
|
|
alias->alias = def;
|
2012-05-03 04:27:30 +00:00
|
|
|
alias->line = pr.source_line;
|
|
|
|
alias->file = pr.source_file;
|
2012-12-03 03:40:00 +00:00
|
|
|
alias->next = def->alias_defs;
|
2022-01-24 09:31:53 +00:00
|
|
|
alias->reg = def->reg;
|
2012-12-03 03:40:00 +00:00
|
|
|
def->alias_defs = alias;
|
2011-01-25 06:42:26 +00:00
|
|
|
return alias;
|
|
|
|
}
|
|
|
|
|
2011-03-23 12:32:14 +00:00
|
|
|
def_t *
|
2019-06-17 14:38:34 +00:00
|
|
|
temp_def (type_t *type)
|
2011-03-23 12:32:14 +00:00
|
|
|
{
|
|
|
|
def_t *temp;
|
2022-01-21 01:20:02 +00:00
|
|
|
defspace_t *space = current_func->locals->space;
|
2019-06-17 14:38:34 +00:00
|
|
|
int size = type_size (type);
|
2020-02-14 17:21:21 +00:00
|
|
|
int alignment = type->alignment;
|
2011-03-23 12:32:14 +00:00
|
|
|
|
[qfcc] Update sizes and alignments for dvec4 and friends
dvec4, lvec4 and ulvec4 need to be aligned to 8 words (32 bytes) in
order to avoid hardware exceptions. Rather than dealing with possibly
mixed alignment when a function has 8-word aligned locals but only
4-word aligned parameters, simply keep the stack frame 8-word aligned at
all times.
As for sizes, the temp def recycler was written before the Ruamoko ISA
was even a pipe dream and thus never expected temp def sizes over 4. At
least now any future adjustments can be done in one place.
My quick and dirty test program works :)
dvec4 xy = {1d, 2d, 0d, 0.5};
void printf(string fmt, ...) = #0;
int main()
{
dvec4 u = {3, 4, 3.14};
dvec4 v = {3, 4, 0, 1};
dvec4 w = v * xy + u;
printf ("[%g, %g, %g, %g]\n", w[0], w[1], w[2], w[3]);
return 0;
}
2022-02-03 23:46:58 +00:00
|
|
|
if (size < 1 || size > MAX_DEF_SIZE) {
|
2019-06-09 15:19:48 +00:00
|
|
|
internal_error (0, "%d invalid size for temp def", size);
|
|
|
|
}
|
2020-02-14 17:21:21 +00:00
|
|
|
if (alignment < 1) {
|
|
|
|
internal_error (0, "temp type has no alignment");
|
|
|
|
}
|
2012-11-18 10:08:16 +00:00
|
|
|
if ((temp = current_func->temp_defs[size - 1])) {
|
2012-11-19 01:33:03 +00:00
|
|
|
current_func->temp_defs[size - 1] = temp->temp_next;
|
|
|
|
temp->temp_next = 0;
|
2012-11-19 01:31:22 +00:00
|
|
|
} else {
|
|
|
|
ALLOC (16384, def_t, defs, temp);
|
2020-02-14 17:21:21 +00:00
|
|
|
temp->offset = defspace_alloc_aligned_loc (space, size, alignment);
|
2012-11-19 01:31:22 +00:00
|
|
|
*space->def_tail = temp;
|
|
|
|
space->def_tail = &temp->next;
|
2021-01-31 07:01:20 +00:00
|
|
|
temp->name = save_string (va (0, ".tmp%d", current_func->temp_num++));
|
2012-11-18 10:08:16 +00:00
|
|
|
}
|
2011-03-23 12:32:14 +00:00
|
|
|
temp->return_addr = __builtin_return_address (0);
|
2019-06-17 14:38:34 +00:00
|
|
|
temp->type = type;
|
2011-03-23 12:32:14 +00:00
|
|
|
temp->file = pr.source_file;
|
|
|
|
temp->line = pr.source_line;
|
2012-12-02 01:11:30 +00:00
|
|
|
set_storage_bits (temp, sc_local);
|
2011-03-23 12:32:14 +00:00
|
|
|
temp->space = space;
|
2022-01-21 11:34:43 +00:00
|
|
|
temp->reg = current_func->temp_reg;
|
2011-03-23 12:32:14 +00:00
|
|
|
return temp;
|
|
|
|
}
|
|
|
|
|
2012-11-18 10:08:16 +00:00
|
|
|
void
|
|
|
|
free_temp_def (def_t *temp)
|
|
|
|
{
|
|
|
|
int size = type_size (temp->type) - 1;
|
2012-11-19 01:33:03 +00:00
|
|
|
temp->temp_next = current_func->temp_defs[size];
|
2012-11-18 10:08:16 +00:00
|
|
|
current_func->temp_defs[size] = temp;
|
|
|
|
}
|
|
|
|
|
2001-06-04 17:52:50 +00:00
|
|
|
void
|
2011-01-24 06:41:43 +00:00
|
|
|
free_def (def_t *def)
|
2001-06-04 22:35:54 +00:00
|
|
|
{
|
2012-12-03 03:40:00 +00:00
|
|
|
if (!def->return_addr)
|
|
|
|
internal_error (0, "double free of def");
|
|
|
|
if (def->alias) {
|
|
|
|
def_t **a;
|
|
|
|
|
|
|
|
// pull the alias out of the base def's list of alias defs to avoid
|
|
|
|
// messing up the list when the alias def is freed.
|
|
|
|
for (a = &def->alias->alias_defs; *a; a = &(*a)->next) {
|
|
|
|
if (*a == def) {
|
|
|
|
*a = def->next;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (def->space) {
|
2011-01-24 06:41:43 +00:00
|
|
|
def_t **d;
|
2001-08-22 21:55:01 +00:00
|
|
|
|
2011-01-24 06:41:43 +00:00
|
|
|
for (d = &def->space->defs; *d && *d != def; d = &(*d)->next)
|
|
|
|
;
|
2011-02-14 01:35:54 +00:00
|
|
|
if (!*d)
|
|
|
|
internal_error (0, "freeing unlinked def %s", def->name);
|
2011-01-24 06:41:43 +00:00
|
|
|
*d = def->next;
|
2011-02-14 01:35:54 +00:00
|
|
|
if (&def->next == def->space->def_tail)
|
|
|
|
def->space->def_tail = d;
|
2011-02-11 09:27:07 +00:00
|
|
|
if (!def->external)
|
|
|
|
defspace_free_loc (def->space, def->offset, type_size (def->type));
|
2002-08-20 06:11:10 +00:00
|
|
|
}
|
2012-12-03 03:40:00 +00:00
|
|
|
def->return_addr = 0;
|
|
|
|
def->free_addr = __builtin_return_address (0);
|
2012-12-04 04:23:31 +00:00
|
|
|
FREE (defs, def);
|
2002-06-28 16:00:01 +00:00
|
|
|
}
|
2002-07-17 15:40:08 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
def_to_ddef (def_t *def, ddef_t *ddef, int aux)
|
|
|
|
{
|
2021-07-24 09:09:54 +00:00
|
|
|
const type_t *type = unalias_type (def->type);
|
2002-07-17 15:40:08 +00:00
|
|
|
|
|
|
|
if (aux)
|
2011-01-09 10:41:24 +00:00
|
|
|
type = type->t.fldptr.type; // aux is true only for fields
|
2002-07-17 15:40:08 +00:00
|
|
|
ddef->type = type->type;
|
2011-01-24 06:41:43 +00:00
|
|
|
ddef->ofs = def->offset;
|
2021-12-31 06:02:31 +00:00
|
|
|
ddef->name = ReuseString (def->name);
|
2002-07-17 15:40:08 +00:00
|
|
|
}
|
2011-01-25 03:07:02 +00:00
|
|
|
|
2020-02-27 11:30:07 +00:00
|
|
|
static int
|
|
|
|
zero_memory (expr_t *local_expr, def_t *def, type_t *zero_type,
|
|
|
|
int init_size, int init_offset)
|
|
|
|
{
|
|
|
|
int zero_size = type_size (zero_type);
|
|
|
|
expr_t *zero = convert_nil (new_nil_expr (), zero_type);
|
|
|
|
expr_t *dst;
|
|
|
|
|
|
|
|
for (; init_offset < init_size + 1 - zero_size; init_offset += zero_size) {
|
2020-03-17 03:13:09 +00:00
|
|
|
dst = new_def_expr (def);
|
|
|
|
dst = new_offset_alias_expr (zero_type, dst, init_offset);
|
|
|
|
append_expr (local_expr, assign_expr (dst, zero));
|
2020-02-27 11:30:07 +00:00
|
|
|
}
|
|
|
|
return init_offset;
|
|
|
|
}
|
|
|
|
|
2011-02-15 00:30:37 +00:00
|
|
|
static void
|
[qfcc] Rewrite init_elements
The end goal was to fix erroneous non-constant initializer errors for
the following (ie, nested initializer blocks):
typedef struct { int x; int y; } Point;
typedef struct { int width; int height; } Extent;
typedef struct Rect_s { Point offset; Extent extent; } Rect;
Rect makeRect (int xpos, int ypos, int xlen, int ylen)
{
Rect rect = {{xpos, ypos}, {xlen, ylen}};
return rect;
}
However, it turned out that nested initializer blocks for local
variables did not work at all in that the relocations were lost because
fake defs were being created for the generated instructions.
Thus, instead of creating fake defs, simply record the offset relative
to the base def, the type, and the basic type initializer expression,
then generate instructions that all refer to the correct def but with a
relative offset.
Other than using the new element system, static initializers are largely
unaffected.
2020-03-05 02:05:13 +00:00
|
|
|
init_elements_nil (def_t *def)
|
2011-02-15 00:30:37 +00:00
|
|
|
{
|
[qfcc] Rewrite init_elements
The end goal was to fix erroneous non-constant initializer errors for
the following (ie, nested initializer blocks):
typedef struct { int x; int y; } Point;
typedef struct { int width; int height; } Extent;
typedef struct Rect_s { Point offset; Extent extent; } Rect;
Rect makeRect (int xpos, int ypos, int xlen, int ylen)
{
Rect rect = {{xpos, ypos}, {xlen, ylen}};
return rect;
}
However, it turned out that nested initializer blocks for local
variables did not work at all in that the relocations were lost because
fake defs were being created for the generated instructions.
Thus, instead of creating fake defs, simply record the offset relative
to the base def, the type, and the basic type initializer expression,
then generate instructions that all refer to the correct def but with a
relative offset.
Other than using the new element system, static initializers are largely
unaffected.
2020-03-05 02:05:13 +00:00
|
|
|
if (def->local && local_expr) {
|
|
|
|
// memset to 0
|
|
|
|
int init_size = type_size (def->type);
|
|
|
|
int init_offset = 0;
|
|
|
|
|
|
|
|
if (options.code.progsversion != PROG_ID_VERSION) {
|
|
|
|
init_offset = zero_memory (local_expr, def, &type_zero,
|
|
|
|
init_size, init_offset);
|
|
|
|
}
|
|
|
|
// probably won't happen any time soon, but who knows...
|
|
|
|
if (options.code.progsversion != PROG_ID_VERSION
|
|
|
|
&& init_size - init_offset >= type_size (&type_quaternion)) {
|
|
|
|
init_offset = zero_memory (local_expr, def, &type_quaternion,
|
|
|
|
init_size, init_offset);
|
|
|
|
}
|
|
|
|
if (init_size - init_offset >= type_size (&type_vector)) {
|
|
|
|
init_offset = zero_memory (local_expr, def, &type_vector,
|
|
|
|
init_size, init_offset);
|
|
|
|
}
|
|
|
|
if (options.code.progsversion != PROG_ID_VERSION
|
|
|
|
&& init_size - init_offset >= type_size (&type_double)) {
|
|
|
|
init_offset = zero_memory (local_expr, def, &type_double,
|
|
|
|
init_size, init_offset);
|
|
|
|
}
|
|
|
|
if (init_size - init_offset >= type_size (type_default)) {
|
|
|
|
zero_memory (local_expr, def, type_default,
|
|
|
|
init_size, init_offset);
|
2020-02-27 11:30:07 +00:00
|
|
|
}
|
|
|
|
}
|
[qfcc] Rewrite init_elements
The end goal was to fix erroneous non-constant initializer errors for
the following (ie, nested initializer blocks):
typedef struct { int x; int y; } Point;
typedef struct { int width; int height; } Extent;
typedef struct Rect_s { Point offset; Extent extent; } Rect;
Rect makeRect (int xpos, int ypos, int xlen, int ylen)
{
Rect rect = {{xpos, ypos}, {xlen, ylen}};
return rect;
}
However, it turned out that nested initializer blocks for local
variables did not work at all in that the relocations were lost because
fake defs were being created for the generated instructions.
Thus, instead of creating fake defs, simply record the offset relative
to the base def, the type, and the basic type initializer expression,
then generate instructions that all refer to the correct def but with a
relative offset.
Other than using the new element system, static initializers are largely
unaffected.
2020-03-05 02:05:13 +00:00
|
|
|
// it's a global, so already initialized to 0
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
init_elements (struct def_s *def, expr_t *eles)
|
|
|
|
{
|
|
|
|
expr_t *c;
|
|
|
|
pr_type_t *g;
|
|
|
|
element_chain_t element_chain;
|
|
|
|
element_t *element;
|
|
|
|
|
|
|
|
if (eles->type == ex_nil) {
|
|
|
|
init_elements_nil (def);
|
|
|
|
return;
|
2011-02-15 00:30:37 +00:00
|
|
|
}
|
[qfcc] Rewrite init_elements
The end goal was to fix erroneous non-constant initializer errors for
the following (ie, nested initializer blocks):
typedef struct { int x; int y; } Point;
typedef struct { int width; int height; } Extent;
typedef struct Rect_s { Point offset; Extent extent; } Rect;
Rect makeRect (int xpos, int ypos, int xlen, int ylen)
{
Rect rect = {{xpos, ypos}, {xlen, ylen}};
return rect;
}
However, it turned out that nested initializer blocks for local
variables did not work at all in that the relocations were lost because
fake defs were being created for the generated instructions.
Thus, instead of creating fake defs, simply record the offset relative
to the base def, the type, and the basic type initializer expression,
then generate instructions that all refer to the correct def but with a
relative offset.
Other than using the new element system, static initializers are largely
unaffected.
2020-03-05 02:05:13 +00:00
|
|
|
|
|
|
|
element_chain.head = 0;
|
|
|
|
element_chain.tail = &element_chain.head;
|
|
|
|
build_element_chain (&element_chain, def->type, eles, 0);
|
|
|
|
|
|
|
|
if (def->local && local_expr) {
|
2020-03-17 03:13:09 +00:00
|
|
|
expr_t *dst = new_def_expr (def);
|
|
|
|
assign_elements (local_expr, dst, &element_chain);
|
[qfcc] Rewrite init_elements
The end goal was to fix erroneous non-constant initializer errors for
the following (ie, nested initializer blocks):
typedef struct { int x; int y; } Point;
typedef struct { int width; int height; } Extent;
typedef struct Rect_s { Point offset; Extent extent; } Rect;
Rect makeRect (int xpos, int ypos, int xlen, int ylen)
{
Rect rect = {{xpos, ypos}, {xlen, ylen}};
return rect;
}
However, it turned out that nested initializer blocks for local
variables did not work at all in that the relocations were lost because
fake defs were being created for the generated instructions.
Thus, instead of creating fake defs, simply record the offset relative
to the base def, the type, and the basic type initializer expression,
then generate instructions that all refer to the correct def but with a
relative offset.
Other than using the new element system, static initializers are largely
unaffected.
2020-03-05 02:05:13 +00:00
|
|
|
} else {
|
|
|
|
def_t dummy = *def;
|
|
|
|
for (element = element_chain.head; element; element = element->next) {
|
2020-03-13 08:57:58 +00:00
|
|
|
if (!element->expr
|
|
|
|
|| ((c = constant_expr (element->expr))->type == ex_nil)) {
|
|
|
|
// nil is type agnostic 0 and defspaces are initialized to
|
|
|
|
// 0 on creation
|
|
|
|
continue;
|
2020-03-06 11:38:40 +00:00
|
|
|
}
|
|
|
|
if (c->type == ex_nil) {
|
|
|
|
c = convert_nil (c, element->type);
|
2011-02-15 00:30:37 +00:00
|
|
|
}
|
[qfcc] Rewrite init_elements
The end goal was to fix erroneous non-constant initializer errors for
the following (ie, nested initializer blocks):
typedef struct { int x; int y; } Point;
typedef struct { int width; int height; } Extent;
typedef struct Rect_s { Point offset; Extent extent; } Rect;
Rect makeRect (int xpos, int ypos, int xlen, int ylen)
{
Rect rect = {{xpos, ypos}, {xlen, ylen}};
return rect;
}
However, it turned out that nested initializer blocks for local
variables did not work at all in that the relocations were lost because
fake defs were being created for the generated instructions.
Thus, instead of creating fake defs, simply record the offset relative
to the base def, the type, and the basic type initializer expression,
then generate instructions that all refer to the correct def but with a
relative offset.
Other than using the new element system, static initializers are largely
unaffected.
2020-03-05 02:05:13 +00:00
|
|
|
dummy.offset = def->offset + element->offset;
|
|
|
|
g = D_POINTER (pr_type_t, &dummy);
|
|
|
|
if (c->type == ex_labelref) {
|
2020-03-11 14:52:12 +00:00
|
|
|
// reloc_def_* use only the def's offset and space, so dummy
|
|
|
|
// is ok
|
[qfcc] Rewrite init_elements
The end goal was to fix erroneous non-constant initializer errors for
the following (ie, nested initializer blocks):
typedef struct { int x; int y; } Point;
typedef struct { int width; int height; } Extent;
typedef struct Rect_s { Point offset; Extent extent; } Rect;
Rect makeRect (int xpos, int ypos, int xlen, int ylen)
{
Rect rect = {{xpos, ypos}, {xlen, ylen}};
return rect;
}
However, it turned out that nested initializer blocks for local
variables did not work at all in that the relocations were lost because
fake defs were being created for the generated instructions.
Thus, instead of creating fake defs, simply record the offset relative
to the base def, the type, and the basic type initializer expression,
then generate instructions that all refer to the correct def but with a
relative offset.
Other than using the new element system, static initializers are largely
unaffected.
2020-03-05 02:05:13 +00:00
|
|
|
reloc_def_op (c->e.labelref.label, &dummy);
|
2011-02-15 00:30:37 +00:00
|
|
|
continue;
|
[qfcc] Rewrite init_elements
The end goal was to fix erroneous non-constant initializer errors for
the following (ie, nested initializer blocks):
typedef struct { int x; int y; } Point;
typedef struct { int width; int height; } Extent;
typedef struct Rect_s { Point offset; Extent extent; } Rect;
Rect makeRect (int xpos, int ypos, int xlen, int ylen)
{
Rect rect = {{xpos, ypos}, {xlen, ylen}};
return rect;
}
However, it turned out that nested initializer blocks for local
variables did not work at all in that the relocations were lost because
fake defs were being created for the generated instructions.
Thus, instead of creating fake defs, simply record the offset relative
to the base def, the type, and the basic type initializer expression,
then generate instructions that all refer to the correct def but with a
relative offset.
Other than using the new element system, static initializers are largely
unaffected.
2020-03-05 02:05:13 +00:00
|
|
|
} else if (c->type == ex_value) {
|
2022-04-29 11:52:57 +00:00
|
|
|
type_t *ctype = get_type (c);
|
|
|
|
if (ctype != element->type
|
|
|
|
&& type_assignable (element->type, ctype)) {
|
|
|
|
if (!c->implicit
|
|
|
|
&& !type_promotes (element->type, ctype)) {
|
|
|
|
warning (c, "initialization of %s with %s"
|
|
|
|
" (use a cast)\n)",
|
|
|
|
get_type_string (element->type),
|
|
|
|
get_type_string (ctype));
|
|
|
|
}
|
|
|
|
expr_t *n = cast_expr (element->type, c);
|
2022-04-28 08:37:56 +00:00
|
|
|
n->line = c->line;
|
|
|
|
n->file = c->line;
|
|
|
|
c = n;
|
2020-03-12 10:37:55 +00:00
|
|
|
}
|
[qfcc] Rewrite init_elements
The end goal was to fix erroneous non-constant initializer errors for
the following (ie, nested initializer blocks):
typedef struct { int x; int y; } Point;
typedef struct { int width; int height; } Extent;
typedef struct Rect_s { Point offset; Extent extent; } Rect;
Rect makeRect (int xpos, int ypos, int xlen, int ylen)
{
Rect rect = {{xpos, ypos}, {xlen, ylen}};
return rect;
}
However, it turned out that nested initializer blocks for local
variables did not work at all in that the relocations were lost because
fake defs were being created for the generated instructions.
Thus, instead of creating fake defs, simply record the offset relative
to the base def, the type, and the basic type initializer expression,
then generate instructions that all refer to the correct def but with a
relative offset.
Other than using the new element system, static initializers are largely
unaffected.
2020-03-05 02:05:13 +00:00
|
|
|
if (get_type (c) != element->type) {
|
|
|
|
error (c, "type mismatch in initializer");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!def->local || !local_expr) {
|
|
|
|
error (c, "non-constant initializer");
|
|
|
|
continue;
|
|
|
|
}
|
2011-02-15 00:30:37 +00:00
|
|
|
}
|
[qfcc] Rewrite init_elements
The end goal was to fix erroneous non-constant initializer errors for
the following (ie, nested initializer blocks):
typedef struct { int x; int y; } Point;
typedef struct { int width; int height; } Extent;
typedef struct Rect_s { Point offset; Extent extent; } Rect;
Rect makeRect (int xpos, int ypos, int xlen, int ylen)
{
Rect rect = {{xpos, ypos}, {xlen, ylen}};
return rect;
}
However, it turned out that nested initializer blocks for local
variables did not work at all in that the relocations were lost because
fake defs were being created for the generated instructions.
Thus, instead of creating fake defs, simply record the offset relative
to the base def, the type, and the basic type initializer expression,
then generate instructions that all refer to the correct def but with a
relative offset.
Other than using the new element system, static initializers are largely
unaffected.
2020-03-05 02:05:13 +00:00
|
|
|
if (c->type != ex_value) {
|
2011-03-05 00:21:12 +00:00
|
|
|
internal_error (c, "bogus expression type in init_elements()");
|
[qfcc] Rewrite init_elements
The end goal was to fix erroneous non-constant initializer errors for
the following (ie, nested initializer blocks):
typedef struct { int x; int y; } Point;
typedef struct { int width; int height; } Extent;
typedef struct Rect_s { Point offset; Extent extent; } Rect;
Rect makeRect (int xpos, int ypos, int xlen, int ylen)
{
Rect rect = {{xpos, ypos}, {xlen, ylen}};
return rect;
}
However, it turned out that nested initializer blocks for local
variables did not work at all in that the relocations were lost because
fake defs were being created for the generated instructions.
Thus, instead of creating fake defs, simply record the offset relative
to the base def, the type, and the basic type initializer expression,
then generate instructions that all refer to the correct def but with a
relative offset.
Other than using the new element system, static initializers are largely
unaffected.
2020-03-05 02:05:13 +00:00
|
|
|
}
|
2018-10-12 13:05:17 +00:00
|
|
|
if (c->e.value->lltype == ev_string) {
|
2022-04-26 06:10:00 +00:00
|
|
|
EMIT_STRING (def->space, *(pr_string_t *) g,
|
2012-07-18 14:01:09 +00:00
|
|
|
c->e.value->v.string_val);
|
2011-02-15 00:30:37 +00:00
|
|
|
} else {
|
2012-07-18 14:01:09 +00:00
|
|
|
memcpy (g, &c->e.value->v, type_size (get_type (c)) * 4);
|
2011-02-15 00:30:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
[qfcc] Rewrite init_elements
The end goal was to fix erroneous non-constant initializer errors for
the following (ie, nested initializer blocks):
typedef struct { int x; int y; } Point;
typedef struct { int width; int height; } Extent;
typedef struct Rect_s { Point offset; Extent extent; } Rect;
Rect makeRect (int xpos, int ypos, int xlen, int ylen)
{
Rect rect = {{xpos, ypos}, {xlen, ylen}};
return rect;
}
However, it turned out that nested initializer blocks for local
variables did not work at all in that the relocations were lost because
fake defs were being created for the generated instructions.
Thus, instead of creating fake defs, simply record the offset relative
to the base def, the type, and the basic type initializer expression,
then generate instructions that all refer to the correct def but with a
relative offset.
Other than using the new element system, static initializers are largely
unaffected.
2020-03-05 02:05:13 +00:00
|
|
|
|
2020-03-11 10:42:38 +00:00
|
|
|
free_element_chain (&element_chain);
|
2011-02-15 00:30:37 +00:00
|
|
|
}
|
|
|
|
|
2022-02-06 11:13:59 +00:00
|
|
|
void
|
2022-01-24 03:48:02 +00:00
|
|
|
init_vector_components (symbol_t *vector_sym, int is_field, symtab_t *symtab)
|
2011-03-07 01:21:40 +00:00
|
|
|
{
|
|
|
|
expr_t *vector_expr;
|
|
|
|
int i;
|
|
|
|
static const char *fields[] = { "x", "y", "z" };
|
|
|
|
|
|
|
|
vector_expr = new_symbol_expr (vector_sym);
|
|
|
|
for (i = 0; i < 3; i++) {
|
2011-03-22 04:05:42 +00:00
|
|
|
expr_t *expr = 0;
|
|
|
|
symbol_t *sym;
|
|
|
|
const char *name;
|
|
|
|
|
2021-01-31 07:01:20 +00:00
|
|
|
name = va (0, "%s_%s", vector_sym->name, fields[i]);
|
2022-01-24 03:48:02 +00:00
|
|
|
sym = symtab_lookup (symtab, name);
|
2011-03-07 08:23:52 +00:00
|
|
|
if (sym) {
|
2022-01-24 03:48:02 +00:00
|
|
|
if (sym->table == symtab) {
|
2011-03-07 08:23:52 +00:00
|
|
|
if (sym->sy_type != sy_expr) {
|
|
|
|
error (0, "%s redefined", name);
|
|
|
|
sym = 0;
|
|
|
|
} else {
|
|
|
|
expr = sym->s.expr;
|
|
|
|
if (is_field) {
|
|
|
|
if (expr->type != ex_value
|
2018-10-12 13:05:17 +00:00
|
|
|
|| expr->e.value->lltype != ev_field) {
|
2011-03-07 08:23:52 +00:00
|
|
|
error (0, "%s redefined", name);
|
|
|
|
sym = 0;
|
|
|
|
} else {
|
2012-07-18 14:01:09 +00:00
|
|
|
expr->e.value->v.pointer.def = vector_sym->s.def;
|
|
|
|
expr->e.value->v.pointer.val = i;
|
2011-03-07 08:23:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
sym = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!sym)
|
|
|
|
sym = new_symbol (name);
|
|
|
|
if (!expr) {
|
|
|
|
if (is_field) {
|
|
|
|
expr = new_field_expr (i, &type_float, vector_sym->s.def);
|
|
|
|
} else {
|
2013-09-27 08:43:33 +00:00
|
|
|
expr = field_expr (vector_expr,
|
|
|
|
new_symbol_expr (new_symbol (fields[i])));
|
2011-03-07 08:23:52 +00:00
|
|
|
}
|
2011-03-07 01:21:40 +00:00
|
|
|
}
|
|
|
|
sym->sy_type = sy_expr;
|
|
|
|
sym->s.expr = expr;
|
2011-03-07 08:23:52 +00:00
|
|
|
if (!sym->table)
|
2022-01-24 03:48:02 +00:00
|
|
|
symtab_addsymbol (symtab, sym);
|
2011-03-07 01:21:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-22 01:43:35 +00:00
|
|
|
static void
|
2022-01-24 03:48:02 +00:00
|
|
|
init_field_def (def_t *def, expr_t *init, storage_class_t storage,
|
|
|
|
symtab_t *symtab)
|
2011-02-22 01:43:35 +00:00
|
|
|
{
|
2021-07-24 09:09:54 +00:00
|
|
|
type_t *type = (type_t *) dereference_type (def->type);//FIXME cast
|
2011-02-22 06:43:15 +00:00
|
|
|
def_t *field_def;
|
2011-03-06 06:38:19 +00:00
|
|
|
symbol_t *field_sym;
|
2011-03-09 01:52:29 +00:00
|
|
|
reloc_t *relocs = 0;
|
2011-02-22 06:43:15 +00:00
|
|
|
|
2011-03-07 08:23:52 +00:00
|
|
|
if (!init) {
|
2011-03-30 00:33:47 +00:00
|
|
|
field_sym = symtab_lookup (pr.entity_fields, def->name);
|
|
|
|
if (!field_sym)
|
|
|
|
field_sym = new_symbol_type (def->name, type);
|
|
|
|
if (field_sym->s.def && field_sym->s.def->external) {
|
|
|
|
//FIXME this really is not the right way
|
|
|
|
relocs = field_sym->s.def->relocs;
|
|
|
|
free_def (field_sym->s.def);
|
|
|
|
field_sym->s.def = 0;
|
|
|
|
}
|
|
|
|
if (!field_sym->s.def) {
|
|
|
|
field_sym->s.def = new_def (def->name, type, pr.entity_data, storage);
|
2012-11-12 07:14:09 +00:00
|
|
|
reloc_attach_relocs (relocs, &field_sym->s.def->relocs);
|
2011-03-30 00:33:47 +00:00
|
|
|
field_sym->s.def->nosave = 1;
|
|
|
|
}
|
|
|
|
field_def = field_sym->s.def;
|
|
|
|
if (!field_sym->table)
|
|
|
|
symtab_addsymbol (pr.entity_fields, field_sym);
|
2012-12-02 01:11:30 +00:00
|
|
|
if (storage != sc_extern) {
|
2011-03-07 08:23:52 +00:00
|
|
|
D_INT (def) = field_def->offset;
|
2011-03-30 00:33:47 +00:00
|
|
|
reloc_def_field (field_def, def);
|
2011-03-07 08:23:52 +00:00
|
|
|
def->constant = 1;
|
|
|
|
def->nosave = 1;
|
|
|
|
}
|
|
|
|
// no support for initialized field vector componets (yet?)
|
2020-03-27 06:16:41 +00:00
|
|
|
if (is_vector(type) && options.code.vector_components)
|
2022-01-24 03:48:02 +00:00
|
|
|
init_vector_components (field_sym, 1, symtab);
|
2011-03-30 00:33:47 +00:00
|
|
|
} else if (init->type == ex_symbol) {
|
|
|
|
symbol_t *sym = init->e.symbol;
|
|
|
|
symbol_t *field = symtab_lookup (pr.entity_fields, sym->name);
|
|
|
|
if (field) {
|
|
|
|
expr_t *new = new_field_expr (0, field->type, field->s.def);
|
|
|
|
init->type = new->type;
|
|
|
|
init->e = new->e;
|
|
|
|
}
|
2011-03-07 08:23:52 +00:00
|
|
|
}
|
2011-02-22 01:43:35 +00:00
|
|
|
}
|
|
|
|
|
2019-06-09 14:11:38 +00:00
|
|
|
static int
|
|
|
|
num_elements (expr_t *e)
|
|
|
|
{
|
|
|
|
int count = 0;
|
|
|
|
for (e = e->e.block.head; e; e = e->next) {
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2011-01-25 03:07:02 +00:00
|
|
|
void
|
2018-10-15 13:11:20 +00:00
|
|
|
initialize_def (symbol_t *sym, expr_t *init, defspace_t *space,
|
2022-01-24 03:48:02 +00:00
|
|
|
storage_class_t storage, symtab_t *symtab)
|
2011-01-25 03:07:02 +00:00
|
|
|
{
|
2022-01-24 03:48:02 +00:00
|
|
|
symbol_t *check = symtab_lookup (symtab, sym->name);
|
2011-03-09 01:52:29 +00:00
|
|
|
reloc_t *relocs = 0;
|
|
|
|
|
2023-02-11 05:44:55 +00:00
|
|
|
if (check && symtab->parent && check->table == symtab->parent->parent
|
|
|
|
&& symtab->parent->parent->type == stab_param) {
|
|
|
|
error (0, "%s shadows a parameter", sym->name);
|
|
|
|
}
|
2022-01-24 03:48:02 +00:00
|
|
|
if (check && check->table == symtab) {
|
2021-12-21 15:19:36 +00:00
|
|
|
if (check->sy_type != sy_var || !type_same (check->type, sym->type)) {
|
2011-01-25 03:07:02 +00:00
|
|
|
error (0, "%s redefined", sym->name);
|
|
|
|
} else {
|
|
|
|
// is var and same type
|
2011-02-14 12:25:08 +00:00
|
|
|
if (!check->s.def)
|
2011-01-25 03:07:02 +00:00
|
|
|
internal_error (0, "half defined var");
|
2012-12-02 01:11:30 +00:00
|
|
|
if (storage == sc_extern) {
|
2011-01-25 03:07:02 +00:00
|
|
|
if (init)
|
2020-03-03 08:32:48 +00:00
|
|
|
error (0, "initializing external variable");
|
2011-01-25 03:07:02 +00:00
|
|
|
return;
|
|
|
|
}
|
2011-02-14 12:25:08 +00:00
|
|
|
if (init && check->s.def->initialized) {
|
2011-01-25 03:07:02 +00:00
|
|
|
error (0, "%s redefined", sym->name);
|
|
|
|
return;
|
|
|
|
}
|
2011-02-14 12:25:08 +00:00
|
|
|
sym = check;
|
2011-01-25 03:07:02 +00:00
|
|
|
}
|
|
|
|
}
|
2018-10-15 13:11:20 +00:00
|
|
|
sym->sy_type = sy_var;
|
2011-02-14 12:25:08 +00:00
|
|
|
if (!sym->table)
|
2022-01-24 03:48:02 +00:00
|
|
|
symtab_addsymbol (symtab, sym);
|
2018-10-15 13:12:40 +00:00
|
|
|
|
2011-01-25 03:07:02 +00:00
|
|
|
if (sym->s.def && sym->s.def->external) {
|
2011-03-09 01:52:29 +00:00
|
|
|
//FIXME this really is not the right way
|
|
|
|
relocs = sym->s.def->relocs;
|
2011-01-25 03:07:02 +00:00
|
|
|
free_def (sym->s.def);
|
|
|
|
sym->s.def = 0;
|
|
|
|
}
|
2011-03-09 01:52:29 +00:00
|
|
|
if (!sym->s.def) {
|
2019-06-09 14:11:38 +00:00
|
|
|
if (is_array (sym->type) && !type_size (sym->type)
|
2021-09-24 10:44:14 +00:00
|
|
|
&& init && init->type == ex_compound) {
|
2019-06-09 14:11:38 +00:00
|
|
|
sym->type = array_type (sym->type->t.array.type,
|
|
|
|
num_elements (init));
|
|
|
|
}
|
2023-08-18 07:05:54 +00:00
|
|
|
if (sym->type == &type_auto) {
|
|
|
|
if (init) {
|
|
|
|
if (!(sym->type = get_type (init))) {
|
|
|
|
sym->type = type_default;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
error (0, "'auto' requires an initialized data declaration");
|
|
|
|
sym->type = type_default;
|
|
|
|
}
|
|
|
|
}
|
2018-10-15 13:11:20 +00:00
|
|
|
sym->s.def = new_def (sym->name, sym->type, space, storage);
|
2012-11-12 07:14:09 +00:00
|
|
|
reloc_attach_relocs (relocs, &sym->s.def->relocs);
|
2011-03-09 01:52:29 +00:00
|
|
|
}
|
2020-03-27 06:16:41 +00:00
|
|
|
if (is_vector(sym->type) && options.code.vector_components)
|
2022-01-24 03:48:02 +00:00
|
|
|
init_vector_components (sym, 0, symtab);
|
2018-10-15 13:11:20 +00:00
|
|
|
if (sym->type->type == ev_field && storage != sc_local
|
|
|
|
&& storage != sc_param)
|
2022-01-24 03:48:02 +00:00
|
|
|
init_field_def (sym->s.def, init, storage, symtab);
|
2012-12-02 01:11:30 +00:00
|
|
|
if (storage == sc_extern) {
|
2011-01-25 03:07:02 +00:00
|
|
|
if (init)
|
2020-03-03 08:32:48 +00:00
|
|
|
error (0, "initializing external variable");
|
2011-01-25 03:07:02 +00:00
|
|
|
return;
|
|
|
|
}
|
2011-03-07 08:23:52 +00:00
|
|
|
if (!init)
|
2011-01-25 03:07:02 +00:00
|
|
|
return;
|
2011-02-14 06:45:31 +00:00
|
|
|
convert_name (init);
|
|
|
|
if (init->type == ex_error)
|
|
|
|
return;
|
2023-05-25 12:22:50 +00:00
|
|
|
if ((is_structural (sym->type) || is_nonscalar (sym->type))
|
|
|
|
&& (init->type == ex_compound || init->type == ex_nil)) {
|
2011-02-15 00:30:37 +00:00
|
|
|
init_elements (sym->s.def, init);
|
2012-11-24 06:26:27 +00:00
|
|
|
sym->s.def->initialized = 1;
|
2011-01-25 03:07:02 +00:00
|
|
|
} else {
|
2020-02-27 11:30:07 +00:00
|
|
|
type_t *init_type;
|
|
|
|
if (init->type == ex_nil) {
|
|
|
|
convert_nil (init, sym->type);
|
|
|
|
}
|
|
|
|
init_type = get_type (init);
|
2020-02-15 08:42:46 +00:00
|
|
|
if (!type_assignable (sym->type, init_type)) {
|
2022-04-26 10:57:43 +00:00
|
|
|
error (init, "type mismatch in initializer: %s = %s",
|
|
|
|
get_type_string (sym->type), get_type_string (init_type));
|
2011-01-25 03:07:02 +00:00
|
|
|
return;
|
|
|
|
}
|
2021-01-13 09:08:30 +00:00
|
|
|
if (storage == sc_local && local_expr) {
|
2012-11-24 06:26:27 +00:00
|
|
|
sym->s.def->initialized = 1;
|
2011-03-05 08:23:22 +00:00
|
|
|
init = assign_expr (new_symbol_expr (sym), init);
|
|
|
|
// fold_constants takes care of int/float conversions
|
|
|
|
append_expr (local_expr, fold_constants (init));
|
2011-02-15 00:30:37 +00:00
|
|
|
} else {
|
2020-02-15 06:37:16 +00:00
|
|
|
if (!is_constant (init)) {
|
|
|
|
error (init, "non-constant initializier");
|
|
|
|
return;
|
|
|
|
}
|
2022-01-08 03:06:52 +00:00
|
|
|
while (init->type == ex_alias) {
|
|
|
|
init = init->e.alias.expr;
|
2020-02-15 06:37:16 +00:00
|
|
|
}
|
2011-02-15 00:30:37 +00:00
|
|
|
if (init->type != ex_value) { //FIXME enum etc
|
2020-02-15 06:37:16 +00:00
|
|
|
internal_error (0, "initializier not a value");
|
2011-02-15 00:30:37 +00:00
|
|
|
return;
|
|
|
|
}
|
2022-01-18 05:36:06 +00:00
|
|
|
if (init->e.value->lltype == ev_ptr
|
2018-10-12 13:05:17 +00:00
|
|
|
|| init->e.value->lltype == ev_field) {
|
2011-02-22 01:43:35 +00:00
|
|
|
// FIXME offset pointers
|
2012-07-18 14:01:09 +00:00
|
|
|
D_INT (sym->s.def) = init->e.value->v.pointer.val;
|
|
|
|
if (init->e.value->v.pointer.def)
|
|
|
|
reloc_def_field (init->e.value->v.pointer.def, sym->s.def);
|
2011-02-22 01:43:35 +00:00
|
|
|
} else {
|
2012-12-05 13:16:08 +00:00
|
|
|
ex_value_t *v = init->e.value;
|
2020-02-23 13:28:54 +00:00
|
|
|
if (!init->implicit
|
|
|
|
&& is_double (init_type)
|
2020-02-15 08:42:46 +00:00
|
|
|
&& (is_integral (sym->type) || is_float (sym->type))) {
|
|
|
|
warning (init, "assigning double to %s in initializer "
|
|
|
|
"(use a cast)", sym->type->name);
|
|
|
|
}
|
2022-11-16 08:55:56 +00:00
|
|
|
if (!type_same (sym->type, init_type))
|
2012-12-05 13:16:08 +00:00
|
|
|
v = convert_value (v, sym->type);
|
2018-10-12 13:05:17 +00:00
|
|
|
if (v->lltype == ev_string) {
|
2012-11-03 09:11:45 +00:00
|
|
|
EMIT_STRING (sym->s.def->space, D_STRING (sym->s.def),
|
2012-12-05 13:16:08 +00:00
|
|
|
v->v.string_val);
|
2012-11-03 09:11:45 +00:00
|
|
|
} else {
|
2022-04-26 06:10:00 +00:00
|
|
|
memcpy (D_POINTER (pr_type_t, sym->s.def), &v->v,
|
2018-10-15 13:11:20 +00:00
|
|
|
type_size (sym->type) * sizeof (pr_type_t));
|
2012-11-03 09:11:45 +00:00
|
|
|
}
|
2011-02-22 01:43:35 +00:00
|
|
|
}
|
2019-06-09 10:23:23 +00:00
|
|
|
sym->s.def->initialized = 1;
|
2020-02-23 13:51:00 +00:00
|
|
|
if (options.code.const_initializers) {
|
2019-06-09 10:23:23 +00:00
|
|
|
sym->s.def->constant = 1;
|
|
|
|
sym->s.def->nosave = 1;
|
|
|
|
}
|
2011-02-15 00:30:37 +00:00
|
|
|
}
|
2011-01-25 03:07:02 +00:00
|
|
|
}
|
2012-11-03 09:12:44 +00:00
|
|
|
sym->s.def->initializer = init;
|
2011-01-25 03:07:02 +00:00
|
|
|
}
|
2012-12-10 04:23:45 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
def_overlap (def_t *d1, def_t *d2)
|
|
|
|
{
|
|
|
|
int offs1, size1;
|
|
|
|
int offs2, size2;
|
2012-12-11 10:51:34 +00:00
|
|
|
defspace_t *s1 = d1->space;
|
|
|
|
defspace_t *s2 = d2->space;
|
|
|
|
|
|
|
|
if (d1->alias)
|
|
|
|
s1 = d1->alias->space;
|
|
|
|
if (d2->alias)
|
|
|
|
s2 = d2->alias->space;
|
2012-12-10 04:23:45 +00:00
|
|
|
/// Defs in different spaces never overlap.
|
2012-12-11 10:51:34 +00:00
|
|
|
if (s1 != s2)
|
2012-12-10 04:23:45 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
offs1 = d1->offset;
|
|
|
|
if (d1->alias)
|
|
|
|
offs1 += d1->alias->offset;
|
|
|
|
size1 = type_size (d1->type);
|
|
|
|
|
|
|
|
offs2 = d2->offset;
|
|
|
|
if (d2->alias)
|
|
|
|
offs2 += d2->alias->offset;
|
|
|
|
size2 = type_size (d2->type);
|
|
|
|
|
2012-12-13 05:42:51 +00:00
|
|
|
if (offs1 <= offs2 && offs1 + size1 >= offs2 + size2)
|
|
|
|
return 2; // d1 fully overlaps d2
|
2012-12-10 04:23:45 +00:00
|
|
|
if (offs1 < offs2 + size2 && offs2 < offs1 + size1)
|
2012-12-13 05:42:51 +00:00
|
|
|
return 1; // d1 and d2 at least partially overlap
|
2012-12-10 04:23:45 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2012-12-10 05:40:43 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
def_offset (def_t *def)
|
|
|
|
{
|
|
|
|
int offset = def->offset;
|
|
|
|
if (def->alias)
|
|
|
|
offset += def->alias->offset;
|
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
def_size (def_t *def)
|
|
|
|
{
|
|
|
|
return type_size (def->type);
|
|
|
|
}
|
2012-12-12 02:46:33 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
def_visit_all (def_t *def, int overlap,
|
|
|
|
int (*visit) (def_t *, void *), void *data)
|
|
|
|
{
|
|
|
|
def_t *start_def = def;
|
2012-12-13 00:47:00 +00:00
|
|
|
int ret;
|
2012-12-12 02:46:33 +00:00
|
|
|
|
2012-12-13 00:47:00 +00:00
|
|
|
if ((ret = visit (def, data)))
|
|
|
|
return ret;
|
2012-12-12 02:46:33 +00:00
|
|
|
if (def->alias) {
|
|
|
|
def = def->alias;
|
2023-05-19 07:42:13 +00:00
|
|
|
if (!(overlap & 4) && (ret = visit (def, data)))
|
2012-12-13 00:47:00 +00:00
|
|
|
return ret;
|
2023-05-19 07:42:13 +00:00
|
|
|
overlap &= ~4;
|
2020-03-08 07:53:28 +00:00
|
|
|
} else {
|
|
|
|
overlap = 0;
|
2012-12-12 02:46:33 +00:00
|
|
|
}
|
|
|
|
for (def = def->alias_defs; def; def = def->next) {
|
|
|
|
if (def == start_def)
|
|
|
|
continue;
|
2012-12-13 05:42:51 +00:00
|
|
|
if (overlap && def_overlap (def, start_def) < overlap)
|
2012-12-12 02:46:33 +00:00
|
|
|
continue;
|
2012-12-13 00:47:00 +00:00
|
|
|
if ((ret = visit (def, data)))
|
|
|
|
return ret;
|
2012-12-12 02:46:33 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|