From: Dale Weiler Date: Fri, 26 Jul 2013 13:58:45 +0000 (+0000) Subject: Merge branch 'master' into threading X-Git-Url: https://git.xonotic.org/?a=commitdiff_plain;h=0c7395da1ae45cac8a8a4d6885570b4a44205386;hp=-c;p=xonotic%2Fgmqcc.git Merge branch 'master' into threading Conflicts: Makefile gmqcc.h ir.c ir.h opts.def parser.c --- 0c7395da1ae45cac8a8a4d6885570b4a44205386 diff --combined Makefile index 3a215f2,2e5c1ee..cd26b16 --- a/Makefile +++ b/Makefile @@@ -1,16 -1,20 +1,10 @@@ --DESTDIR := --OPTIONAL:= --PREFIX := /usr/local --BINDIR := $(PREFIX)/bin --DATADIR := $(PREFIX)/share --MANDIR := $(DATADIR)/man ++include include.mk UNAME ?= $(shell uname) CYGWIN = $(findstring CYGWIN, $(UNAME)) MINGW = $(findstring MINGW32, $(UNAME)) - CC ?= clang - CFLAGS += -Wall -Wextra -Werror -I. -fno-strict-aliasing -fsigned-char -pthread $(OPTIONAL) -CC ?= clang -# linker flags and optional additional libraries if required -LDFLAGS += -LIBS += -lm - + CFLAGS += -Wall -Wextra -Werror -fno-strict-aliasing $(OPTIONAL) ifneq ($(shell git describe --always 2>/dev/null),) CFLAGS += -DGMQCC_GITINFO="\"$(shell git describe --always)\"" endif @@@ -25,28 -29,33 +19,29 @@@ ifeq ($(CC), clang -Wno-conversion \ -Wno-missing-prototypes \ -Wno-float-equal \ + -Wno-unknown-warning-option \ + -Wno-cast-align \ - -Wno-missing-variable-declarations \ - -Wno-unknown-warning-option + -Wstrict-prototypes else #Tiny C Compiler doesn't know what -pedantic-errors is # and instead of ignoring .. just errors. ifneq ($(CC), tcc) - CFLAGS +=-pedantic-errors -ffunction-sections -fdata-sections -Wl,-gc-sections - CFLAGS += -Wstrict-prototypes -pedantic-errors ++ CFLAGS += -pedantic-errors else CFLAGS += -Wno-pointer-sign -fno-common endif ++ ++ #-Wstrict-prototypes is not valid in g++ ++ ifneq ($(CC), g++) ++ CFLAGS += -Wstrict-prototypes ++ endif endif --ifeq ($(track), no) -- CFLAGS += -DNOTRACK --endif -- - OBJ_D = util.o code.o ast.o ir.o thread.o conout.o ftepp.o opts.o fs.o utf8.o correct.o - OBJ_P = util.o fs.o conout.o opts.o pak.o - OBJ_T = test.o util.o conout.o fs.o - OBJ_C = main.o lexer.o parser.o fs.o - OBJ_X = exec-standalone.o util.o conout.o fs.o -OBJ_D = util.o code.o ast.o ir.o conout.o ftepp.o opts.o fs.o utf8.o correct.o stat.o -OBJ_P = util.o fs.o conout.o opts.o pak.o stat.o -OBJ_T = test.o util.o conout.o fs.o stat.o -OBJ_C = main.o lexer.o parser.o fs.o stat.o -OBJ_X = exec-standalone.o util.o conout.o fs.o stat.o - + #we have duplicate object files when dealing with creating a simple list + #for dependinces. To combat this we use some clever recrusive-make to + #filter the list and remove duplicates which we use for make depend + RMDUP = $(if $1,$(firstword $1) $(call RMDUP,$(filter-out $(firstword $1),$1))) -DEPS := $(call RMDUP, $(OBJ_D) $(OBJ_P) $(OBJ_T) $(OBJ_C) $(OBJ_X)) ++DEPS := $(call RMDUP, $(OBJ_P) $(OBJ_T) $(OBJ_C) $(OBJ_X)) ifneq ("$(CYGWIN)", "") #nullify the common variables that @@@ -58,7 -67,7 +53,7 @@@ QCVM = qcvm.exe GMQCC = gmqcc.exe TESTSUITE = testsuite.exe -- PAK = pak.exe ++ PAK = gmqpak.exe else ifneq ("$(MINGW)", "") #nullify the common variables that @@@ -70,120 -79,111 +65,33 @@@ QCVM = qcvm.exe GMQCC = gmqcc.exe TESTSUITE = testsuite.exe - PAK = pak.exe + PAK = gmqpak.exe else - #arm support for linux .. we need to allow unaligned accesses - #to memory otherwise we just segfault everywhere - ifneq (, $(findstring arm, $(shell uname -m))) - CFLAGS += -munaligned-access - endif - QCVM = qcvm GMQCC = gmqcc TESTSUITE = testsuite - PAK = pak + PAK = gmqpak endif endif --#gource flags --GOURCEFLAGS= \ -- --date-format "%d %B, %Y" \ -- --seconds-per-day 0.01 \ -- --auto-skip-seconds 1 \ -- --title "GMQCC" \ -- --key \ -- --camera-mode overview \ -- --highlight-all-users \ -- --file-idle-time 0 \ -- --hide progress,mouse \ -- --stop-at-end \ -- --max-files 99999999999 \ -- --max-file-lag 0.000001 \ -- --bloom-multiplier 1.3 \ - --logo doc/html/gmqcc.png \ -- -1280x720 -- --#ffmpeg flags for gource --FFMPEGFLAGS= \ -- -y \ -- -r 60 \ -- -f image2pipe \ -- -vcodec ppm \ -- -i - \ -- -vcodec libx264 \ -- -preset ultrafast \ -- -crf 1 \ -- -threads 0 \ -- -bf 0 -- --#splint flags --SPLINTFLAGS = \ -- -redef \ -- -noeffect \ -- -nullderef \ -- -usedef \ -- -type \ -- -mustfreeonly \ -- -nullstate \ -- -varuse \ -- -mustfreefresh \ -- -compdestroy \ -- -compmempass \ -- -nullpass \ -- -onlytrans \ -- -predboolint \ -- -boolops \ - -exportlocal \ -- -incondefs \ -- -macroredef \ -- -retvalint \ -- -nullret \ -- -predboolothers \ -- -globstate \ -- -dependenttrans \ -- -branchstate \ -- -compdef \ -- -temptrans \ -- -usereleased \ -- -warnposix \ - -shiftimplementation \ -- +charindex \ -- -kepttrans \ -- -unqualifiedtrans \ -- +matchanyintegral \ -- +voidabstract \ -- -nullassign \ -- -unrecog \ -- -casebreak \ -- -retvalbool \ -- -retvalother \ -- -mayaliasunique \ -- -realcompare \ -- -observertrans \ - -shiftnegative \ - -freshtrans \ -- -abstract \ -- -statictrans \ -- -castfcnptr -- #standard rules --default: all %.o: %.c - $(CC) -c $< -o $@ $(CFLAGS) + $(CC) -c $< -o $@ $(CPPFLAGS) $(CFLAGS) exec-standalone.o: exec.c - $(CC) -c $< -o $@ $(CFLAGS) -DQCVM_EXECUTOR=1 + $(CC) -c $< -o $@ $(CPPFLAGS) $(CFLAGS) -DQCVM_EXECUTOR=1 $(QCVM): $(OBJ_X) - $(CC) -o $@ $^ $(CFLAGS) -lm + $(CC) -o $@ $^ $(LDFLAGS) $(LIBS) $(GMQCC): $(OBJ_C) $(OBJ_D) - $(CC) -o $@ $^ $(CFLAGS) -lm -pthread + $(CC) -o $@ $^ $(LDFLAGS) $(LIBS) $(TESTSUITE): $(OBJ_T) - $(CC) -o $@ $^ $(CFLAGS) -lm + $(CC) -o $@ $^ $(LDFLAGS) $(LIBS) $(PAK): $(OBJ_P) - $(CC) -o $@ $^ $(CFLAGS) + $(CC) -o $@ $^ $(LDFLAGS) all: $(GMQCC) $(QCVM) $(TESTSUITE) $(PAK) @@@ -193,7 -193,7 +101,7 @@@ test: al @ ./$(TESTSUITE) clean: - rm -f *.o $(GMQCC) $(QCVM) $(TESTSUITE) $(PAK) *.dat gource.mp4 - rm -f *.o $(GMQCC) $(QCVM) $(TESTSUITE) $(PAK) *.dat gource.mp4 *.exe ++ rm -rf *.o $(GMQCC) $(QCVM) $(TESTSUITE) $(PAK) *.dat gource.mp4 *.exe gm-qcc.tgz ./cov-int splint: @ splint $(SPLINTFLAGS) *.c *.h @@@ -205,65 -205,49 +113,48 @@@ gource-record @ gource $(GOURCEFLAGS) -o - | ffmpeg $(FFMPEGFLAGS) gource.mp4 depend: -- @makedepend -Y -w 65536 2> /dev/null \ - $(subst .o,.c,$(OBJ_D)) - @makedepend -a -Y -w 65536 2> /dev/null \ - $(subst .o,.c,$(OBJ_T)) - @makedepend -a -Y -w 65536 2> /dev/null \ - $(subst .o,.c,$(OBJ_C)) - @makedepend -a -Y -w 65536 2> /dev/null \ - $(subst .o,.c,$(OBJ_X)) - @makedepend -a -Y -w 65536 2> /dev/null \ - $(subst .o,.c,$(OBJ_P)) - $(subst .o,.c,$(DEPS)) ++ @ makedepend -Y -w 65536 2> /dev/null $(subst .o,.c,$(DEPS)) ++ ++ ++coverity: ++ @cov-build --dir cov-int $(MAKE) ++ @tar czf gm-qcc.tgz cov-int ++ @rm -rf cov-int ++ @echo gm-qcc.tgz generated, submit for analysis #install rules - install: install-gmqcc install-qcvm install-doc + install: install-gmqcc install-qcvm install-gmqpak install-doc install-gmqcc: $(GMQCC) install -d -m755 $(DESTDIR)$(BINDIR) - install -m755 $(GMQCC) $(DESTDIR)$(BINDIR)/gmqcc + install -m755 $(GMQCC) $(DESTDIR)$(BINDIR)/$(GMQCC) install-qcvm: $(QCVM) install -d -m755 $(DESTDIR)$(BINDIR) - install -m755 $(QCVM) $(DESTDIR)$(BINDIR)/qcvm + install -m755 $(QCVM) $(DESTDIR)$(BINDIR)/$(QCVM) + install-gmqpak: $(PAK) + install -d -m755 $(DESTDIR)$(BINDIR) + install -m755 $(PAK) $(DESTDIR)$(BINDIR)/$(PAK) install-doc: install -d -m755 $(DESTDIR)$(MANDIR)/man1 install -m644 doc/gmqcc.1 $(DESTDIR)$(MANDIR)/man1/ install -m644 doc/qcvm.1 $(DESTDIR)$(MANDIR)/man1/ - - uninstall: - rm $(DESTDIR)$(BINDIR)/gmqcc - rm $(DESTDIR)$(BINDIR)/qcvm - rm $(DESTDIR)$(MANDIR)/man1/doc/gmqcc.1 - rm $(DESTDIR)$(MANDIR)/man1/doc/qcvm.1 + install -m644 doc/gmqpak.1 $(DESTDIR)$(MANDIR)/man1/ -uninstall: - rm -f $(DESTDIR)$(BINDIR)/gmqcc - rm -f $(DESTDIR)$(BINDIR)/qcvm - rm -f $(DESTDIR)$(BINDIR)/gmqpak - rm -f $(DESTDIR)$(MANDIR)/man1/doc/gmqcc.1 - rm -f $(DESTDIR)$(MANDIR)/man1/doc/qcvm.1 - rm -f $(DESTDIR)$(MANDIR)/man1/doc/gmqpak.1 - # DO NOT DELETE util.o: gmqcc.h opts.def --code.o: gmqcc.h opts.def --ast.o: gmqcc.h opts.def ast.h ir.h --ir.o: gmqcc.h opts.def ir.h ++fs.o: gmqcc.h opts.def conout.o: gmqcc.h opts.def --ftepp.o: gmqcc.h opts.def lexer.h opts.o: gmqcc.h opts.def --fs.o: gmqcc.h opts.def --utf8.o: gmqcc.h opts.def --correct.o: gmqcc.h opts.def - -stat.o: gmqcc.h opts.def + pak.o: gmqcc.h opts.def ++stat.o: gmqcc.h opts.def test.o: gmqcc.h opts.def - util.o: gmqcc.h opts.def - conout.o: gmqcc.h opts.def - fs.o: gmqcc.h opts.def - main.o: gmqcc.h opts.def lexer.h lexer.o: gmqcc.h opts.def lexer.h parser.o: gmqcc.h opts.def lexer.h ast.h ir.h intrin.h - fs.o: gmqcc.h opts.def - - util.o: gmqcc.h opts.def - conout.o: gmqcc.h opts.def - fs.o: gmqcc.h opts.def - - util.o: gmqcc.h opts.def - fs.o: gmqcc.h opts.def - conout.o: gmqcc.h opts.def - opts.o: gmqcc.h opts.def - pak.o: gmqcc.h opts.def ++code.o: gmqcc.h opts.def ++ast.o: gmqcc.h opts.def ast.h ir.h ++ir.o: gmqcc.h opts.def ir.h ++ftepp.o: gmqcc.h opts.def lexer.h ++utf8.o: gmqcc.h opts.def ++correct.o: gmqcc.h opts.def ++thread.o: gmqcc.h opts.def diff --combined gmqcc.h index a9599ac,d6055db..9a3e432 --- a/gmqcc.h +++ b/gmqcc.h @@@ -23,12 -23,8 +23,8 @@@ */ #ifndef GMQCC_HDR #define GMQCC_HDR - #include - #include - #include #include - #include - #include + #include /* TODO: remove this */ /* * Disable some over protective warnings in visual studio because fixing them is a waste @@@ -36,7 -32,6 +32,6 @@@ */ #ifdef _MSC_VER # pragma warning(disable : 4244 ) /* conversion from 'int' to 'float', possible loss of data */ - # pragma warning(disable : 4018 ) /* signed/unsigned mismatch */ #endif /*! _MSC_VER */ #define GMQCC_VERSION_MAJOR 0 @@@ -49,13 -44,17 +44,17 @@@ #define GMQCC_VERSION_TYPE_DEVEL /* Full version string in case we need it */ - #ifdef GMQCC_GITINFO - # define GMQCC_DEV_VERSION_STRING "git build: " GMQCC_GITINFO "\n" - #elif defined(GMQCC_VERSION_TYPE_DEVEL) - # define GMQCC_DEV_VERSION_STRING "development build\n" + #ifdef GMQCC_VERSION_TYPE_DEVEL + # ifdef GMQCC_GITINFO + # define GMQCC_DEV_VERSION_STRING "git build: " GMQCC_GITINFO "\n" + # elif defined(GMQCC_VERSION_TYPE_DEVEL) + # define GMQCC_DEV_VERSION_STRING "development build\n" + # else + # define GMQCC_DEV_VERSION_STRING + # endif /*! GMQCC_GITINGO */ #else # define GMQCC_DEV_VERSION_STRING - #endif /*! GMQCC_GITINGO */ + #endif #define GMQCC_STRINGIFY(x) #x #define GMQCC_IND_STRING(x) GMQCC_STRINGIFY(x) @@@ -168,17 -167,6 +167,6 @@@ GMQCC_IND_STRING(GMQCC_VERSION_PATCH) typedef __int64 int64_t; #endif /*! _MSC_VER */ - /* - *windows makes these prefixed because they're C99 - * TODO: utility versions that are type-safe and not - * just plain textual subsitution. - */ - #ifdef _MSC_VER - # define snprintf(X, Y, Z, ...) _snprintf(X, Y, Z, __VA_ARGS__) - /* strtof doesn't exist -> strtod does though :) */ - # define strtof(X, Y) (float)(strtod(X, Y)) - #endif /*! _MSC_VER */ - /* * Very roboust way at determining endianess at compile time: this handles * almost every possible situation. Otherwise a runtime check has to be @@@ -263,7 -251,7 +251,7 @@@ * On windows systems where we're not compiling with MING32 we need a * little extra help on dependinces for implementing our own dirent.h * in fs.c. - */ + */ #if defined(_WIN32) && !defined(__MINGW32__) # define _WIN32_LEAN_AND_MEAN # include @@@ -275,7 -263,7 +263,7 @@@ unsigned short d_reclen; unsigned short d_namlen; char d_name[FILENAME_MAX]; - } + }; typedef struct { struct _finddata_t dd_dta; @@@ -284,24 -272,42 +272,42 @@@ int dd_stat; char dd_name[1]; } DIR; + /* + * Visual studio also lacks S_ISDIR for sys/stat.h, so we emulate this as well + * which is not hard at all. + */ + # ifdef S_ISDIR + # undef S_ISDIR + # endif /*! S_ISDIR */ + # define S_ISDIR(X) ((X)&_S_IFDIR) #else # include #endif /*! _WIN32 && !defined(__MINGW32__) */ + /*===================================================================*/ + /*=========================== stat.c ================================*/ + /*===================================================================*/ + void stat_info (void); + char *stat_mem_strdup (const char *, size_t, const char *, bool); + void *stat_mem_reallocate(void *, size_t, size_t, const char *); + void stat_mem_deallocate(void *); + void *stat_mem_allocate (size_t, size_t, const char *); + + #define mem_a(SIZE) stat_mem_allocate ((SIZE), __LINE__, __FILE__) + #define mem_d(PTRN) stat_mem_deallocate((void*)(PTRN)) + #define mem_r(PTRN, SIZE) stat_mem_reallocate((void*)(PTRN), (SIZE), __LINE__, __FILE__) + #define mem_af(SIZE, FILE, LINE) stat_mem_allocate ((SIZE), (LINE), (FILE)) + + /* TODO: rename to mem variations */ + #define util_strdup(SRC) stat_mem_strdup((char*)(SRC), __LINE__, __FILE__, false) + #define util_strdupe(SRC) stat_mem_strdup((char*)(SRC), __LINE__, __FILE__, true) /*===================================================================*/ /*=========================== util.c ================================*/ /*===================================================================*/ - void *util_memory_a (size_t, /*****/ unsigned int, const char *); - void *util_memory_r (void *, size_t, unsigned int, const char *); - void util_memory_d (void *); - void util_meminfo (); - bool util_filexists (const char *); bool util_strupper (const char *); bool util_strdigit (const char *); - char *_util_Estrdup (const char *, const char *, size_t); - char *_util_Estrdup_empty(const char *, const char *, size_t); void util_debug (const char *, const char *, ...); void util_endianswap (void *, size_t, unsigned int); @@@ -311,26 -317,20 +317,20 @@@ size_t util_strtononcmd (const char *, uint16_t util_crc16(uint16_t crc, const char *data, size_t len); void util_seed(uint32_t); - uint32_t util_rand(); - - int util_vasprintf(char **ret, const char *fmt, va_list); - int util_asprintf (char **ret, const char *fmt, ...); + uint32_t util_rand(void); - - #ifdef NOTRACK - # define mem_a(x) malloc (x) - # define mem_d(x) free ((void*)x) - # define mem_r(x, n) realloc((void*)x, n) - # define mem_af(x,f,l) malloc (x) - #else - # define mem_a(x) util_memory_a((x), __LINE__, __FILE__) - # define mem_d(x) util_memory_d((void*)(x)) - # define mem_r(x, n) util_memory_r((void*)(x), (n), __LINE__, __FILE__) - # define mem_af(x,f,l) util_memory_a((x), __LINE__, __FILE__) - #endif /*! NOTRACK */ - - #define util_strdup(X) _util_Estrdup((X), __FILE__, __LINE__) - #define util_strdupe(X) _util_Estrdup_empty((X), __FILE__, __LINE__) + /* + * String functions (formatting, copying, concatenating, errors). These are wrapped + * to use the MSVC _safe_ versions when using MSVC, plus some implementations of + * these are non-conformant or don't exist such as asprintf and snprintf, which are + * not supported in C90, but do exist in C99. + */ + int util_vasprintf(char **ret, const char *fmt, va_list); + int util_asprintf (char **ret, const char *fmt, ...); + int util_snprintf (char *src, size_t bytes, const char *format, ...); + char *util_strcat (char *dest, const char *src); + char *util_strncpy (char *dest, const char *src, size_t num); + const char *util_strerror (int num); /* * A flexible vector implementation: all vector pointers contain some @@@ -355,7 -355,7 +355,7 @@@ void _util_vec_grow(void **a, size_t i ) /* exposed interface */ - #define vec_meta(A) (((vector_t*)(A)) - 1) + #define vec_meta(A) (((vector_t*)((void*)A)) - 1) #define vec_free(A) ((void)((A) ? (mem_d((void*)vec_meta(A)), (A) = NULL) : 0)) #define vec_push(A,V) (GMQCC_VEC_WILLGROW((A),1), (A)[vec_meta(A)->used++] = (V)) #define vec_size(A) ((A) ? vec_meta(A)->used : 0) @@@ -373,21 -373,13 +373,13 @@@ typedef struct trie_s struct trie_s *entries; } correct_trie_t; - correct_trie_t* correct_trie_new(); + correct_trie_t* correct_trie_new(void); typedef struct hash_table_t { size_t size; struct hash_node_t **table; } hash_table_t, *ht; - typedef struct hash_set_t { - size_t bits; - size_t mask; - size_t capacity; - size_t *items; - size_t total; - } hash_set_t, *hs; - /* * hashtable implementation: * @@@ -430,49 -422,6 +422,11 @@@ void util_htrm (hash_table_t void *util_htget (hash_table_t *ht, const char *key); void *util_htgeth(hash_table_t *ht, const char *key, size_t hash); - /* - * hashset implementation: - * This was designed for pointers: you manage the life of the object yourself - * if you do use this for non-pointers please be warned that the object may not - * be valid if the duration of it exceeds (i.e on stack). So you need to allocate - * yourself, or put those in global scope to ensure duration is for the whole - * runtime. - * - * util_hsnew() -- to make a new hashset - * util_hsadd(set, key) -- to add something in the set - * util_hshas(set, key) -- to check if something is in the set - * util_hsrem(set, key) -- to remove something in the set - * util_hsdel(set) -- to delete the set - * - * example of use: - * - * hs foo = util_hsnew(); - * char *bar = "hello blub\n"; - * char *baz = "hello dale\n"; - * - * util_hsadd(foo, bar); - * util_hsadd(foo, baz); - * util_hsrem(foo, baz); - * - * printf("bar %d | baz %d\n", - * util_hshas(foo, bar), - * util_hshad(foo, baz) - * ); - * - * util_hsdel(foo); - */ - - hash_set_t *util_hsnew(void); - int util_hsadd(hash_set_t *, void *); - int util_hshas(hash_set_t *, void *); - int util_hsrem(hash_set_t *, void *); - void util_hsdel(hash_set_t *); - +/*===================================================================*/ +/*=========================== thread.c ==============================*/ +/*===================================================================*/ +GMQCC_INLINE uint32_t util_atomic_xadd32(volatile uint32_t *x, uint32_t v); + /*===================================================================*/ /*============================ file.c ===============================*/ /*===================================================================*/ @@@ -483,7 -432,7 +437,7 @@@ int fs_file_getc (FILE *) int fs_file_printf (FILE *, const char *, ...); int fs_file_puts (FILE *, const char *); int fs_file_seek (FILE *, long int, int); - long int fs_file_tell (FILE *); + long int fs_file_tell (FILE *); size_t fs_file_read (void *, size_t, size_t, FILE *); size_t fs_file_write (const void *, size_t, size_t, FILE *); @@@ -545,9 -494,9 +499,9 @@@ enum #define CV_VAR -1 #define CV_WRONG 0x8000 /* magic number to help parsing */ - extern const char *type_name [TYPE_COUNT]; - extern uint16_t type_store_instr [TYPE_COUNT]; - extern uint16_t field_store_instr[TYPE_COUNT]; + extern const char *type_name [TYPE_COUNT]; + extern const uint16_t type_store_instr [TYPE_COUNT]; + extern const uint16_t field_store_instr[TYPE_COUNT]; /* * could use type_store_instr + INSTR_STOREP_F - INSTR_STORE_F @@@ -555,10 -504,10 +509,10 @@@ * instruction set, the old ones are left untouched, thus the _I instructions * are at a seperate place. */ - extern uint16_t type_storep_instr[TYPE_COUNT]; - extern uint16_t type_eq_instr [TYPE_COUNT]; - extern uint16_t type_ne_instr [TYPE_COUNT]; - extern uint16_t type_not_instr [TYPE_COUNT]; + extern const uint16_t type_storep_instr[TYPE_COUNT]; + extern const uint16_t type_eq_instr [TYPE_COUNT]; + extern const uint16_t type_ne_instr [TYPE_COUNT]; + extern const uint16_t type_not_instr [TYPE_COUNT]; typedef struct { uint32_t offset; /* Offset in file of where data begins */ @@@ -748,32 -697,40 +702,40 @@@ enum VINSTR_NRCALL }; - /* TODO: cleanup this mess */ - extern prog_section_statement *code_statements; - extern int *code_linenums; - extern prog_section_def *code_defs; - extern prog_section_field *code_fields; - extern prog_section_function *code_functions; - extern int *code_globals; - extern char *code_chars; - extern uint16_t code_crc; - /* uhh? */ typedef float qcfloat; typedef int32_t qcint; + typedef struct { + prog_section_statement *statements; + int *linenums; + prog_section_def *defs; + prog_section_field *fields; + prog_section_function *functions; + int *globals; + char *chars; + uint16_t crc; + uint32_t entfields; + ht string_cache; + qcint string_cached_empty; + } code_t; + /* - * code_write -- writes out the compiled file - * code_init -- prepares the code file + * code_write -- writes out the compiled file + * code_init -- prepares the code file + * code_genstrin -- generates string for code + * code_alloc_field -- allocated a field + * code_push_statement -- keeps statements and linenumbers together + * code_pop_statement -- keeps statements and linenumbers together */ - bool code_write (const char *filename, const char *lno); - void code_init (); - uint32_t code_genstring (const char *string); - qcint code_alloc_field (size_t qcsize); - - /* this function is used to keep statements and linenumbers together */ - void code_push_statement(prog_section_statement *stmt, int linenum); - void code_pop_statement(); + bool code_write (code_t *, const char *filename, const char *lno); + GMQCC_WARN + code_t *code_init (void); + void code_cleanup (code_t *); + uint32_t code_genstring (code_t *, const char *string); + qcint code_alloc_field (code_t *, size_t qcsize); + void code_push_statement(code_t *, prog_section_statement *stmt, int linenum); + void code_pop_statement (code_t *); /* * A shallow copy of a lex_file to remember where which ast node @@@ -782,6 -739,7 +744,7 @@@ typedef struct { const char *file; size_t line; + size_t column; } lex_ctx; /*===================================================================*/ @@@ -805,17 -763,17 +768,17 @@@ enum LVL_ERROR }; - FILE *con_default_out(); - FILE *con_default_err(); + FILE *con_default_out(void); + FILE *con_default_err(void); - void con_vprintmsg (int level, const char *name, size_t line, const char *msgtype, const char *msg, va_list ap); - void con_printmsg (int level, const char *name, size_t line, const char *msgtype, const char *msg, ...); + void con_vprintmsg (int level, const char *name, size_t line, size_t column, const char *msgtype, const char *msg, va_list ap); + void con_printmsg (int level, const char *name, size_t line, size_t column, const char *msgtype, const char *msg, ...); void con_cvprintmsg(void *ctx, int lvl, const char *msgtype, const char *msg, va_list ap); void con_cprintmsg (void *ctx, int lvl, const char *msgtype, const char *msg, ...); - void con_close (); - void con_init (); - void con_reset (); + void con_close (void); + void con_init (void); + void con_reset (void); void con_color (int); int con_change(const char *, const char *); int con_verr (const char *, va_list); @@@ -832,7 -790,7 +795,7 @@@ void /********/ compile_error (lex_ct void /********/ vcompile_error (lex_ctx ctx, /*LVL_ERROR*/ const char *msg, va_list ap); bool GMQCC_WARN compile_warning (lex_ctx ctx, int warntype, const char *fmt, ...); bool GMQCC_WARN vcompile_warning(lex_ctx ctx, int warntype, const char *fmt, va_list ap); - void compile_show_werrors(); + void compile_show_werrors(void); /*===================================================================*/ /*========================= assembler.c =============================*/ @@@ -1026,7 -984,7 +989,7 @@@ void prog_delete(qc_program *pro bool prog_exec(qc_program *prog, prog_section_function *func, size_t flags, long maxjumps); - char* prog_getstring (qc_program *prog, qcint str); + const char* prog_getstring (qc_program *prog, qcint str); prog_section_def* prog_entfield (qc_program *prog, qcint off); prog_section_def* prog_getdef (qc_program *prog, qcint off); qcany* prog_getedict (qc_program *prog, qcint e); @@@ -1037,8 -995,7 +1000,7 @@@ qcint prog_tempstring(qc_pr /*===================== parser.c commandline ========================*/ /*===================================================================*/ struct parser_s; - - struct parser_s *parser_create (); + struct parser_s *parser_create (void); bool parser_compile_file (struct parser_s *parser, const char *); bool parser_compile_string(struct parser_s *parser, const char *, const char *, size_t); bool parser_finish (struct parser_s *parser, const char *); @@@ -1047,21 -1004,8 +1009,8 @@@ void parser_cleanup ( /*===================================================================*/ /*====================== ftepp.c commandline ========================*/ /*===================================================================*/ - struct lex_file_s; struct ftepp_s; - - typedef struct { - const char *name; - char *(*func)(struct lex_file_s *); - } ftepp_predef_t; - - /* - * line, file, counter, counter_last, random, random_last, date, time - * increment when items are added - */ - #define FTEPP_PREDEF_COUNT 8 - - struct ftepp_s *ftepp_create (); + struct ftepp_s *ftepp_create (void); bool ftepp_preprocess_file (struct ftepp_s *ftepp, const char *filename); bool ftepp_preprocess_string(struct ftepp_s *ftepp, const char *name, const char *str); void ftepp_finish (struct ftepp_s *ftepp); @@@ -1070,8 -1014,6 +1019,6 @@@ void ftepp_flush void ftepp_add_define (struct ftepp_s *ftepp, const char *source, const char *name); void ftepp_add_macro (struct ftepp_s *ftepp, const char *name, const char *value); - extern const ftepp_predef_t ftepp_predefs[FTEPP_PREDEF_COUNT]; - /*===================================================================*/ /*======================= main.c commandline ========================*/ /*===================================================================*/ @@@ -1123,10 -1065,10 +1070,10 @@@ void opts_setoptimlevel(unsigned int) void opts_ini_init (const char *); /* Saner flag handling */ - void opts_backup_non_Wall(); - void opts_restore_non_Wall(); - void opts_backup_non_Werror_all(); - void opts_restore_non_Werror_all(); + void opts_backup_non_Wall(void); + void opts_restore_non_Wall(void); + void opts_backup_non_Werror_all(void); + void opts_restore_non_Werror_all(void); enum { # define GMQCC_TYPE_FLAGS @@@ -1211,7 -1153,7 +1158,7 @@@ typedef struct extern opts_cmd_t opts; - #define OPTS_GENERIC(f,i) (!! (((f)[(i)/32]) & (1<< ((i)%32)))) + #define OPTS_GENERIC(f,i) (!! (((f)[(i)/32]) & (1<< (unsigned)((i)%32)))) #define OPTS_FLAG(i) OPTS_GENERIC(opts.flags, (i)) #define OPTS_WARN(i) OPTS_GENERIC(opts.warn, (i)) #define OPTS_WERROR(i) OPTS_GENERIC(opts.werror, (i)) diff --combined ir.c index a65b015,fcf4caa..5e88587 --- a/ir.c +++ b/ir.c @@@ -1,6 -1,7 +1,7 @@@ /* * Copyright (C) 2012, 2013 * Wolfgang Bumiller + * Dale Weiler * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in @@@ -22,6 -23,7 +23,7 @@@ */ #include #include + #include "gmqcc.h" #include "ir.h" @@@ -48,7 -50,7 +50,7 @@@ const char *type_name[TYPE_COUNT] = "" }; - size_t type_sizeof_[TYPE_COUNT] = { + static size_t type_sizeof_[TYPE_COUNT] = { 1, /* TYPE_VOID */ 1, /* TYPE_STRING */ 1, /* TYPE_FLOAT */ @@@ -66,7 -68,7 +68,7 @@@ 0, /* TYPE_NOESPR */ }; - uint16_t type_store_instr[TYPE_COUNT] = { + const uint16_t type_store_instr[TYPE_COUNT] = { INSTR_STORE_F, /* should use I when having integer support */ INSTR_STORE_S, INSTR_STORE_F, @@@ -90,7 -92,7 +92,7 @@@ VINSTR_END, /* noexpr */ }; - uint16_t field_store_instr[TYPE_COUNT] = { + const uint16_t field_store_instr[TYPE_COUNT] = { INSTR_STORE_FLD, INSTR_STORE_FLD, INSTR_STORE_FLD, @@@ -114,7 -116,7 +116,7 @@@ VINSTR_END, /* noexpr */ }; - uint16_t type_storep_instr[TYPE_COUNT] = { + const uint16_t type_storep_instr[TYPE_COUNT] = { INSTR_STOREP_F, /* should use I when having integer support */ INSTR_STOREP_S, INSTR_STOREP_F, @@@ -138,7 -140,7 +140,7 @@@ VINSTR_END, /* noexpr */ }; - uint16_t type_eq_instr[TYPE_COUNT] = { + const uint16_t type_eq_instr[TYPE_COUNT] = { INSTR_EQ_F, /* should use I when having integer support */ INSTR_EQ_S, INSTR_EQ_F, @@@ -162,7 -164,7 +164,7 @@@ VINSTR_END, /* noexpr */ }; - uint16_t type_ne_instr[TYPE_COUNT] = { + const uint16_t type_ne_instr[TYPE_COUNT] = { INSTR_NE_F, /* should use I when having integer support */ INSTR_NE_S, INSTR_NE_F, @@@ -186,9 -188,9 +188,9 @@@ VINSTR_END, /* noexpr */ }; - uint16_t type_not_instr[TYPE_COUNT] = { + const uint16_t type_not_instr[TYPE_COUNT] = { INSTR_NOT_F, /* should use I when having integer support */ - INSTR_NOT_S, + VINSTR_END, /* not to be used, depends on string related -f flags */ INSTR_NOT_F, INSTR_NOT_V, INSTR_NOT_ENT, @@@ -211,8 -213,31 +213,31 @@@ }; /* protos */ - static void ir_gen_extparam (ir_builder *ir); - + static ir_value* ir_value_var(const char *name, int st, int vtype); + static bool ir_value_set_name(ir_value*, const char *name); + static void ir_value_dump(ir_value*, int (*oprintf)(const char*,...)); + + static ir_value* ir_gen_extparam_proto(ir_builder *ir); -static void ir_gen_extparam (code_t *, ir_builder *ir); ++static void ir_gen_extparam (ir_builder *ir); + + static bool ir_builder_set_name(ir_builder *self, const char *name); + + static ir_function* ir_function_new(struct ir_builder_s *owner, int returntype); + static bool ir_function_set_name(ir_function*, const char *name); + static void ir_function_delete(ir_function*); + static void ir_function_dump(ir_function*, char *ind, int (*oprintf)(const char*,...)); + + static ir_value* ir_block_create_general_instr(ir_block *self, lex_ctx, const char *label, + int op, ir_value *a, ir_value *b, int outype); + static void ir_block_delete(ir_block*); + static ir_block* ir_block_new(struct ir_function_s *owner, const char *label); + static bool GMQCC_WARN ir_block_create_store(ir_block*, lex_ctx, ir_value *target, ir_value *what); + static bool ir_block_set_label(ir_block*, const char *label); + static void ir_block_dump(ir_block*, char *ind, int (*oprintf)(const char*,...)); + + static bool ir_instr_op(ir_instr*, int op, ir_value *value, bool writing); + static void ir_instr_delete(ir_instr*); + static void ir_instr_dump(ir_instr* in, char *ind, int (*oprintf)(const char*,...)); /* error functions */ static void irerror(lex_ctx ctx, const char *msg, ...) @@@ -237,7 -262,7 +262,7 @@@ static bool irwarning(lex_ctx ctx, int * Vector utility functions */ - bool GMQCC_WARN vec_ir_value_find(ir_value **vec, const ir_value *what, size_t *idx) + static bool GMQCC_WARN vec_ir_value_find(ir_value **vec, const ir_value *what, size_t *idx) { size_t i; size_t len = vec_size(vec); @@@ -250,7 -275,7 +275,7 @@@ return false; } - bool GMQCC_WARN vec_ir_block_find(ir_block **vec, ir_block *what, size_t *idx) + static bool GMQCC_WARN vec_ir_block_find(ir_block **vec, ir_block *what, size_t *idx) { size_t i; size_t len = vec_size(vec); @@@ -263,7 -288,7 +288,7 @@@ return false; } - bool GMQCC_WARN vec_ir_instr_find(ir_instr **vec, ir_instr *what, size_t *idx) + static bool GMQCC_WARN vec_ir_instr_find(ir_instr **vec, ir_instr *what, size_t *idx) { size_t i; size_t len = vec_size(vec); @@@ -308,7 -333,6 +333,6 @@@ ir_builder* ir_builder_new(const char * self->max_globaltemps = 0; self->first_common_local = 0; self->max_locals = 0; - self->max_used_params = 0; self->str_immediate = 0; self->name = NULL; @@@ -317,11 -341,10 +341,11 @@@ return NULL; } - self->nil = ir_value_var("nil", store_global, TYPE_NIL); + self->nil = ir_value_var("nil", store_value, TYPE_NIL); self->nil->cvq = CV_CONST; - self->nil->untracked = true; self->reserved_va_count = NULL; ++ self->code = code_init(); return self; } @@@ -341,6 -364,7 +365,7 @@@ void ir_builder_delete(ir_builder* self ir_value_delete(self->extparams[i]); } vec_free(self->extparams); + vec_free(self->extparam_protos); for (i = 0; i != vec_size(self->globals); ++i) { ir_value_delete(self->globals[i]); } @@@ -352,6 -376,6 +377,8 @@@ vec_free(self->fields); vec_free(self->filenames); vec_free(self->filestrings); ++ ++ code_cleanup(self->code); mem_d(self); } @@@ -363,7 -387,7 +390,7 @@@ bool ir_builder_set_name(ir_builder *se return !!self->name; } - ir_function* ir_builder_get_function(ir_builder *self, const char *name) + static ir_function* ir_builder_get_function(ir_builder *self, const char *name) { return (ir_function*)util_htget(self->htfunctions, name); } @@@ -398,7 -422,7 +425,7 @@@ ir_function* ir_builder_create_function return fn; } - ir_value* ir_builder_get_global(ir_builder *self, const char *name) + static ir_value* ir_builder_get_global(ir_builder *self, const char *name) { return (ir_value*)util_htget(self->htglobals, name); } @@@ -423,14 -447,12 +450,12 @@@ ir_value* ir_builder_create_global(ir_b ir_value* ir_builder_get_va_count(ir_builder *self) { - if (!self->reserved_va_count) { - self->reserved_va_count = ir_builder_create_global(self, "reserved:va_count", TYPE_FLOAT); - self->reserved_va_count->untracked = true; - } - return self->reserved_va_count; + if (self->reserved_va_count) + return self->reserved_va_count; + return (self->reserved_va_count = ir_builder_create_global(self, "reserved:va_count", TYPE_FLOAT)); } - ir_value* ir_builder_get_field(ir_builder *self, const char *name) + static ir_value* ir_builder_get_field(ir_builder *self, const char *name) { return (ir_value*)util_htget(self->htfields, name); } @@@ -454,10 -476,10 +479,10 @@@ ir_value* ir_builder_create_field(ir_bu *IR Function */ - bool ir_function_naive_phi(ir_function*); - void ir_function_enumerate(ir_function*); - bool ir_function_calculate_liferanges(ir_function*); - bool ir_function_allocate_locals(ir_function*); + static bool ir_function_naive_phi(ir_function*); + static void ir_function_enumerate(ir_function*); + static bool ir_function_calculate_liferanges(ir_function*); + static bool ir_function_allocate_locals(ir_function*); ir_function* ir_function_new(ir_builder* owner, int outtype) { @@@ -554,7 -576,7 +579,7 @@@ void ir_function_delete(ir_function *se mem_d(self); } - void ir_function_collect_value(ir_function *self, ir_value *v) + static void ir_function_collect_value(ir_function *self, ir_value *v) { vec_push(self->values, v); } @@@ -577,7 -599,7 +602,7 @@@ static bool instr_is_operation(uint16_ (op >= INSTR_CALL0 && op <= INSTR_CALL8) ); } - bool ir_function_pass_peephole(ir_function *self) + static bool ir_function_pass_peephole(ir_function *self) { size_t b; @@@ -693,7 -715,7 +718,7 @@@ return true; } - bool ir_function_pass_tailrecursion(ir_function *self) + static bool ir_function_pass_tailrecursion(ir_function *self) { size_t b, p; @@@ -780,8 -802,10 +805,10 @@@ return true; } - bool ir_function_optimize(ir_function *self) + bool ir_function_finalize(ir_function *self) { + size_t i; + if (self->builtin) return true; @@@ -803,15 -827,6 +830,6 @@@ irerror(self->context, "internal error: ir_function_naive_phi failed"); return false; } - return true; - } - - bool ir_function_finalize(ir_function *self) - { - size_t i; - - if (self->builtin) - return true; for (i = 0; i < vec_size(self->locals); ++i) { ir_value *v = self->locals[i]; @@@ -936,7 -951,7 +954,7 @@@ bool ir_block_set_label(ir_block *self *IR Instructions */ - ir_instr* ir_instr_new(lex_ctx ctx, ir_block* owner, int op) + static ir_instr* ir_instr_new(lex_ctx ctx, ir_block* owner, int op) { ir_instr *self; self = (ir_instr*)mem_a(sizeof(*self)); @@@ -968,7 -983,7 +986,7 @@@ static void ir_instr_delete_quick(ir_in mem_d(self); } - void ir_instr_delete(ir_instr *self) + static void ir_instr_delete(ir_instr *self) { size_t i; /* The following calls can only delete from @@@ -979,8 -994,6 +997,6 @@@ */ for (i = 0; i < vec_size(self->phi); ++i) { size_t idx; - if (self->phi[i].value->untracked) - continue; if (vec_ir_instr_find(self->phi[i].value->writes, self, &idx)) vec_remove(self->phi[i].value->writes, idx, 1); if (vec_ir_instr_find(self->phi[i].value->reads, self, &idx)) @@@ -989,8 -1002,6 +1005,6 @@@ vec_free(self->phi); for (i = 0; i < vec_size(self->params); ++i) { size_t idx; - if (self->params[i]->untracked) - continue; if (vec_ir_instr_find(self->params[i]->writes, self, &idx)) vec_remove(self->params[i]->writes, idx, 1); if (vec_ir_instr_find(self->params[i]->reads, self, &idx)) @@@ -1003,17 -1014,16 +1017,16 @@@ mem_d(self); } - bool ir_instr_op(ir_instr *self, int op, ir_value *v, bool writing) + static bool ir_instr_op(ir_instr *self, int op, ir_value *v, bool writing) { - ir_value *old = self->_ops[op]; - if (old && !old->untracked) { + if (self->_ops[op]) { size_t idx; - if (writing && vec_ir_instr_find(old->writes, self, &idx)) - vec_remove(old->writes, idx, 1); - else if (vec_ir_instr_find(old->reads, self, &idx)) - vec_remove(old->reads, idx, 1); + if (writing && vec_ir_instr_find(self->_ops[op]->writes, self, &idx)) + vec_remove(self->_ops[op]->writes, idx, 1); + else if (vec_ir_instr_find(self->_ops[op]->reads, self, &idx)) + vec_remove(self->_ops[op]->reads, idx, 1); } - if (v && !v->untracked) { + if (v) { if (writing) vec_push(v->writes, self); else @@@ -1027,7 -1037,7 +1040,7 @@@ *IR Value */ - void ir_value_code_setaddr(ir_value *self, int32_t gaddr) + static void ir_value_code_setaddr(ir_value *self, int32_t gaddr) { self->code.globaladdr = gaddr; if (self->members[0]) self->members[0]->code.globaladdr = gaddr; @@@ -1035,7 -1045,7 +1048,7 @@@ if (self->members[2]) self->members[2]->code.globaladdr = gaddr; } - int32_t ir_value_code_addr(const ir_value *self) + static int32_t ir_value_code_addr(const ir_value *self) { if (self->store == store_return) return OFS_RETURN + self->code.addroffset; @@@ -1052,9 -1062,8 +1065,8 @@@ ir_value* ir_value_var(const char *name self->store = storetype; self->flags = 0; - self->reads = NULL; - self->writes = NULL; - self->untracked = false; + self->reads = NULL; + self->writes = NULL; self->cvq = CV_NONE; self->hasvalue = false; @@@ -1149,7 -1158,7 +1161,7 @@@ static GMQCC_INLINE size_t ir_value_siz return type_sizeof_[self->vtype]; } - ir_value* ir_value_out(ir_function *owner, const char *name, int storetype, int vtype) + static ir_value* ir_value_out(ir_function *owner, const char *name, int storetype, int vtype) { ir_value *v = ir_value_var(name, storetype, vtype); if (!v) @@@ -1256,7 -1265,7 +1268,7 @@@ bool ir_value_lives(ir_value *self, siz return false; } - bool ir_value_life_insert(ir_value *self, size_t idx, ir_life_entry_t e) + static bool ir_value_life_insert(ir_value *self, size_t idx, ir_life_entry_t e) { size_t k; vec_push(self->life, e); @@@ -1266,7 -1275,7 +1278,7 @@@ return true; } - bool ir_value_life_merge(ir_value *self, size_t s) + static bool ir_value_life_merge(ir_value *self, size_t s) { size_t i; const size_t vs = vec_size(self->life); @@@ -1329,7 -1338,7 +1341,7 @@@ return ir_value_life_insert(self, i, new_entry); } - bool ir_value_life_merge_into(ir_value *self, const ir_value *other) + static bool ir_value_life_merge_into(ir_value *self, const ir_value *other) { size_t i, myi; @@@ -1403,7 -1412,7 +1415,7 @@@ return true; } - bool ir_values_overlap(const ir_value *a, const ir_value *b) + static bool ir_values_overlap(const ir_value *a, const ir_value *b) { /* For any life entry in A see if it overlaps with * any life entry in B. @@@ -1499,7 -1508,7 +1511,7 @@@ bool ir_block_create_store_op(ir_block return true; } - bool ir_block_create_store(ir_block *self, lex_ctx ctx, ir_value *target, ir_value *what) + static bool ir_block_create_store(ir_block *self, lex_ctx ctx, ir_value *target, ir_value *what) { int op = 0; int vtype; @@@ -1661,8 -1670,7 +1673,7 @@@ void ir_phi_add(ir_instr* self, ir_bloc pe.value = v; pe.from = b; - if (!v->untracked) - vec_push(v->reads, self); + vec_push(v->reads, self); vec_push(self->phi, pe); } @@@ -1712,15 -1720,8 +1723,8 @@@ ir_value* ir_call_value(ir_instr *self void ir_call_param(ir_instr* self, ir_value *v) { - size_t *maxparams, param; vec_push(self->params, v); - if (!v->untracked) - vec_push(v->reads, self); - - param = vec_size(self->params); - maxparams = &self->owner->owner->owner->max_used_params; - if (param > *maxparams) - *maxparams = param; + vec_push(v->reads, self); } /* binary op related code */ @@@ -1796,14 -1797,14 +1800,33 @@@ ir_value* ir_block_create_binop(ir_bloc ot = TYPE_POINTER; break; #endif ++ /* ++ * after the following default case, the value of opcode can never ++ * be 1, 2, 3, 4, 5, 6, 7, 8, 9, 62, 63, 64, 65 ++ */ default: /* ranges: */ /* boolean operations result in floats */ ++ ++ /* ++ * opcode >= 10 takes true branch opcode is at least 10 ++ * opcode <= 23 takes false branch opcode is at least 24 ++ */ if (opcode >= INSTR_EQ_F && opcode <= INSTR_GT) ot = TYPE_FLOAT; ++ ++ /* ++ * At condition "opcode <= 23", the value of "opcode" must be ++ * at least 24. ++ * At condition "opcode <= 23", the value of "opcode" cannot be ++ * equal to any of {1, 2, 3, 4, 5, 6, 7, 8, 9, 62, 63, 64, 65}. ++ * The condition "opcode <= 23" cannot be true. ++ * ++ * Thus ot=2 (TYPE_FLOAT) can never be true ++ */ ++#if 0 else if (opcode >= INSTR_LE && opcode <= INSTR_GT) ot = TYPE_FLOAT; --#if 0 else if (opcode >= INSTR_LE_I && opcode <= INSTR_EQ_FI) ot = TYPE_FLOAT; #endif @@@ -1850,7 -1851,7 +1873,7 @@@ ir_value* ir_block_create_unary(ir_bloc return ir_block_create_general_instr(self, ctx, label, opcode, operand, NULL, ot); } - ir_value* ir_block_create_general_instr(ir_block *self, lex_ctx ctx, const char *label, + static ir_value* ir_block_create_general_instr(ir_block *self, lex_ctx ctx, const char *label, int op, ir_value *a, ir_value *b, int outype) { ir_instr *instr; @@@ -2195,7 -2196,17 +2218,17 @@@ bool ir_function_allocate_locals(ir_fun if (param < 8) ir_value_code_setaddr(v, OFS_PARM0 + 3*param); else { - ir_value *ep = self->owner->extparam_protos[param-=8]; + size_t nprotos = vec_size(self->owner->extparam_protos); + ir_value *ep; + param -= 8; + if (nprotos > param) + ep = self->owner->extparam_protos[param]; + else + { + ep = ir_gen_extparam_proto(self->owner); + while (++nprotos <= param) + ep = ir_gen_extparam_proto(self->owner); + } ir_instr_op(v->writes[0], 0, ep, true); call->params[param+8] = ep; } @@@ -2453,30 -2464,20 +2486,20 @@@ static bool ir_block_life_propagate(ir_ if (instr->opcode == INSTR_MUL_VF) { value = instr->_ops[2]; - if (value->store == store_value || - value->store == store_local || - value->store == store_param) - { - /* the float source will get an additional lifetime */ - if (ir_value_life_merge(value, instr->eid+1)) - *changed = true; - if (value->memberof && ir_value_life_merge(value->memberof, instr->eid+1)) - *changed = true; - } + /* the float source will get an additional lifetime */ + if (ir_value_life_merge(value, instr->eid+1)) + *changed = true; + if (value->memberof && ir_value_life_merge(value->memberof, instr->eid+1)) + *changed = true; } else if (instr->opcode == INSTR_MUL_FV || instr->opcode == INSTR_LOAD_V) { value = instr->_ops[1]; - if (value->store == store_value || - value->store == store_local || - value->store == store_param) - { - /* the float source will get an additional lifetime */ - if (ir_value_life_merge(value, instr->eid+1)) - *changed = true; - if (value->memberof && ir_value_life_merge(value->memberof, instr->eid+1)) - *changed = true; - } + /* the float source will get an additional lifetime */ + if (ir_value_life_merge(value, instr->eid+1)) + *changed = true; + if (value->memberof && ir_value_life_merge(value->memberof, instr->eid+1)) + *changed = true; } for (o = 0; o < 3; ++o) @@@ -2512,10 -2513,6 +2535,6 @@@ for (p = 0; p < vec_size(instr->phi); ++p) { value = instr->phi[p].value; - if (value->store != store_value && - value->store != store_local && - value->store != store_param) - continue; if (!vec_ir_value_find(self->living, value, NULL)) vec_push(self->living, value); /* reading adds the full vector */ @@@ -2536,10 -2533,6 +2555,6 @@@ for (p = 0; p < vec_size(instr->params); ++p) { value = instr->params[p]; - if (value->store != store_value && - value->store != store_local && - value->store != store_param) - continue; if (!vec_ir_value_find(self->living, value, NULL)) vec_push(self->living, value); /* reading adds the full vector */ @@@ -2569,7 -2562,7 +2584,8 @@@ bool ir_function_calculate_liferanges(i /* parameters live at 0 */ for (i = 0; i < vec_size(self->params); ++i) -- ir_value_life_merge(self->locals[i], 0); ++ if (!ir_value_life_merge(self->locals[i], 0)) ++ compile_error(self->context, "internal error: failed value-life merging"); do { self->run_id++; @@@ -2650,9 -2643,9 +2666,9 @@@ * * Breaking conventions is annoying... */ -static bool ir_builder_gen_global(code_t *, ir_builder *self, ir_value *global, bool islocal); +static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool islocal); - static bool gen_global_field(ir_value *global) + static bool gen_global_field(code_t *code, ir_value *global) { if (global->hasvalue) { @@@ -2663,20 -2656,20 +2679,20 @@@ } /* copy the field's value */ - ir_value_code_setaddr(global, vec_size(code_globals)); - vec_push(code_globals, fld->code.fieldaddr); + ir_value_code_setaddr(global, vec_size(code->globals)); + vec_push(code->globals, fld->code.fieldaddr); if (global->fieldtype == TYPE_VECTOR) { - vec_push(code_globals, fld->code.fieldaddr+1); - vec_push(code_globals, fld->code.fieldaddr+2); + vec_push(code->globals, fld->code.fieldaddr+1); + vec_push(code->globals, fld->code.fieldaddr+2); } } else { - ir_value_code_setaddr(global, vec_size(code_globals)); - vec_push(code_globals, 0); + ir_value_code_setaddr(global, vec_size(code->globals)); + vec_push(code->globals, 0); if (global->fieldtype == TYPE_VECTOR) { - vec_push(code_globals, 0); - vec_push(code_globals, 0); + vec_push(code->globals, 0); + vec_push(code->globals, 0); } } if (global->code.globaladdr < 0) @@@ -2684,7 -2677,7 +2700,7 @@@ return true; } - static bool gen_global_pointer(ir_value *global) + static bool gen_global_pointer(code_t *code, ir_value *global) { if (global->hasvalue) { @@@ -2710,20 -2703,20 +2726,20 @@@ return false; } - ir_value_code_setaddr(global, vec_size(code_globals)); - vec_push(code_globals, target->code.globaladdr); + ir_value_code_setaddr(global, vec_size(code->globals)); + vec_push(code->globals, target->code.globaladdr); } else { - ir_value_code_setaddr(global, vec_size(code_globals)); - vec_push(code_globals, 0); + ir_value_code_setaddr(global, vec_size(code->globals)); + vec_push(code->globals, 0); } if (global->code.globaladdr < 0) return false; return true; } - static bool gen_blocks_recursive(ir_function *func, ir_block *block) + static bool gen_blocks_recursive(code_t *code, ir_function *func, ir_block *block) { prog_section_statement stmt; ir_instr *instr; @@@ -2734,7 -2727,7 +2750,7 @@@ size_t i; block->generated = true; - block->code_start = vec_size(code_statements); + block->code_start = vec_size(code->statements); for (i = 0; i < vec_size(block->instr); ++i) { instr = block->instr[i]; @@@ -2750,15 -2743,15 +2766,15 @@@ * yet, we generate them right here. */ if (!target->generated) - return gen_blocks_recursive(func, target); + return gen_blocks_recursive(code, func, target); /* otherwise we generate a jump instruction */ stmt.opcode = INSTR_GOTO; - stmt.o1.s1 = (target->code_start) - vec_size(code_statements); + stmt.o1.s1 = (target->code_start) - vec_size(code->statements); stmt.o2.s1 = 0; stmt.o3.s1 = 0; if (stmt.o1.s1 != 1) - code_push_statement(&stmt, instr->context.line); + code_push_statement(code, &stmt, instr->context.line); /* no further instructions can be in this block */ return true; @@@ -2777,23 -2770,23 +2793,23 @@@ if (ontrue->generated) { stmt.opcode = INSTR_IF; - stmt.o2.s1 = (ontrue->code_start) - vec_size(code_statements); + stmt.o2.s1 = (ontrue->code_start) - vec_size(code->statements); if (stmt.o2.s1 != 1) - code_push_statement(&stmt, instr->context.line); + code_push_statement(code, &stmt, instr->context.line); } if (onfalse->generated) { stmt.opcode = INSTR_IFNOT; - stmt.o2.s1 = (onfalse->code_start) - vec_size(code_statements); + stmt.o2.s1 = (onfalse->code_start) - vec_size(code->statements); if (stmt.o2.s1 != 1) - code_push_statement(&stmt, instr->context.line); + code_push_statement(code, &stmt, instr->context.line); } if (!ontrue->generated) { if (onfalse->generated) - return gen_blocks_recursive(func, ontrue); + return gen_blocks_recursive(code, func, ontrue); } if (!onfalse->generated) { if (ontrue->generated) - return gen_blocks_recursive(func, onfalse); + return gen_blocks_recursive(code, func, onfalse); } /* neither ontrue nor onfalse exist */ stmt.opcode = INSTR_IFNOT; @@@ -2804,24 -2797,24 +2820,24 @@@ onfalse = ontrue; ontrue = tmp; } - stidx = vec_size(code_statements); - code_push_statement(&stmt, instr->context.line); + stidx = vec_size(code->statements); + code_push_statement(code, &stmt, instr->context.line); /* on false we jump, so add ontrue-path */ - if (!gen_blocks_recursive(func, ontrue)) + if (!gen_blocks_recursive(code, func, ontrue)) return false; /* fixup the jump address */ - code_statements[stidx].o2.s1 = vec_size(code_statements) - stidx; + code->statements[stidx].o2.s1 = vec_size(code->statements) - stidx; /* generate onfalse path */ if (onfalse->generated) { /* fixup the jump address */ - code_statements[stidx].o2.s1 = (onfalse->code_start) - (stidx); - if (stidx+2 == vec_size(code_statements) && code_statements[stidx].o2.s1 == 1) { - code_statements[stidx] = code_statements[stidx+1]; - if (code_statements[stidx].o1.s1 < 0) - code_statements[stidx].o1.s1++; - code_pop_statement(); + code->statements[stidx].o2.s1 = (onfalse->code_start) - (stidx); + if (stidx+2 == vec_size(code->statements) && code->statements[stidx].o2.s1 == 1) { + code->statements[stidx] = code->statements[stidx+1]; + if (code->statements[stidx].o1.s1 < 0) + code->statements[stidx].o1.s1++; + code_pop_statement(code); } - stmt.opcode = vec_last(code_statements).opcode; + stmt.opcode = vec_last(code->statements).opcode; if (stmt.opcode == INSTR_GOTO || stmt.opcode == INSTR_IF || stmt.opcode == INSTR_IFNOT || @@@ -2833,21 -2826,21 +2849,21 @@@ } /* may have been generated in the previous recursive call */ stmt.opcode = INSTR_GOTO; - stmt.o1.s1 = (onfalse->code_start) - vec_size(code_statements); + stmt.o1.s1 = (onfalse->code_start) - vec_size(code->statements); stmt.o2.s1 = 0; stmt.o3.s1 = 0; if (stmt.o1.s1 != 1) - code_push_statement(&stmt, instr->context.line); + code_push_statement(code, &stmt, instr->context.line); return true; } - else if (stidx+2 == vec_size(code_statements) && code_statements[stidx].o2.s1 == 1) { - code_statements[stidx] = code_statements[stidx+1]; - if (code_statements[stidx].o1.s1 < 0) - code_statements[stidx].o1.s1++; - code_pop_statement(); + else if (stidx+2 == vec_size(code->statements) && code->statements[stidx].o2.s1 == 1) { + code->statements[stidx] = code->statements[stidx+1]; + if (code->statements[stidx].o1.s1 < 0) + code->statements[stidx].o1.s1++; + code_pop_statement(code); } /* if not, generate now */ - return gen_blocks_recursive(func, onfalse); + return gen_blocks_recursive(code, func, onfalse); } if ( (instr->opcode >= INSTR_CALL0 && instr->opcode <= INSTR_CALL8) @@@ -2876,7 -2869,7 +2892,7 @@@ stmt.opcode = type_store_instr[param->vtype]; stmt.o1.u1 = ir_value_code_addr(param); stmt.o2.u1 = OFS_PARM0 + 3 * p; - code_push_statement(&stmt, instr->context.line); + code_push_statement(code, &stmt, instr->context.line); } /* Now handle extparams */ first = vec_size(instr->params); @@@ -2890,7 -2883,7 +2906,7 @@@ continue; if (p-8 >= vec_size(ir->extparams)) - ir_gen_extparam(code, ir); + ir_gen_extparam(ir); targetparam = ir->extparams[p-8]; @@@ -2905,7 -2898,7 +2921,7 @@@ stmt.opcode = type_store_instr[param->vtype]; stmt.o1.u1 = ir_value_code_addr(param); stmt.o2.u1 = ir_value_code_addr(targetparam); - code_push_statement(&stmt, instr->context.line); + code_push_statement(code, &stmt, instr->context.line); } stmt.opcode = INSTR_CALL0 + vec_size(instr->params); @@@ -2914,7 -2907,7 +2930,7 @@@ stmt.o1.u1 = ir_value_code_addr(instr->_ops[1]); stmt.o2.u1 = 0; stmt.o3.u1 = 0; - code_push_statement(&stmt, instr->context.line); + code_push_statement(code, &stmt, instr->context.line); retvalue = instr->_ops[0]; if (retvalue && retvalue->store != store_return && @@@ -2928,7 -2921,7 +2944,7 @@@ stmt.o1.u1 = OFS_RETURN; stmt.o2.u1 = ir_value_code_addr(retvalue); stmt.o3.u1 = 0; - code_push_statement(&stmt, instr->context.line); + code_push_statement(code, &stmt, instr->context.line); } continue; } @@@ -2978,12 -2971,12 +2994,12 @@@ } } - code_push_statement(&stmt, instr->context.line); + code_push_statement(code, &stmt, instr->context.line); } return true; } - static bool gen_function_code(ir_function *self) + static bool gen_function_code(code_t *code, ir_function *self) { ir_block *block; prog_section_statement stmt, *retst; @@@ -3000,13 -2993,13 +3016,13 @@@ if (block->generated) return true; - if (!gen_blocks_recursive(self, block)) { + if (!gen_blocks_recursive(code, self, block)) { irerror(self->context, "failed to generate blocks for '%s'", self->name); return false; } /* code_write and qcvm -disasm need to know that the function ends here */ - retst = &vec_last(code_statements); + retst = &vec_last(code->statements); if (OPTS_OPTIMIZATION(OPTIM_VOID_RETURN) && self->outtype == TYPE_VOID && retst->opcode == INSTR_RETURN && @@@ -3019,12 -3012,12 +3035,12 @@@ stmt.o1.u1 = 0; stmt.o2.u1 = 0; stmt.o3.u1 = 0; - code_push_statement(&stmt, vec_last(code_linenums)); + code_push_statement(code, &stmt, vec_last(code->linenums)); } return true; } -static qcint ir_builder_filestring(code_t *code, ir_builder *ir, const char *filename) +static qcint ir_builder_filestring(ir_builder *ir, const char *filename) { /* NOTE: filename pointers are copied, we never strdup them, * thus we can use pointer-comparison to find the string. @@@ -3037,13 -3030,13 +3053,13 @@@ return ir->filestrings[i]; } - str = code_genstring(filename); - str = code_genstring(code, filename); ++ str = code_genstring(ir->code, filename); vec_push(ir->filenames, filename); vec_push(ir->filestrings, str); return str; } -static bool gen_global_function(code_t *code, ir_builder *ir, ir_value *global) +static bool gen_global_function(ir_builder *ir, ir_value *global) { prog_section_function fun; ir_function *irfun; @@@ -3059,7 -3052,7 +3075,7 @@@ irfun = global->constval.vfunc; fun.name = global->code.name; - fun.file = ir_builder_filestring(code, ir, global->context.file); + fun.file = ir_builder_filestring(ir, global->context.file); fun.profile = 0; /* always 0 */ fun.nargs = vec_size(irfun->params); if (fun.nargs > 8) @@@ -3078,11 -3071,11 +3094,11 @@@ if (irfun->builtin) fun.entry = irfun->builtin+1; else { - irfun->code_function_def = vec_size(code_functions); - fun.entry = vec_size(code_statements); - irfun->code_function_def = vec_size(code->functions); - fun.entry = vec_size(code->statements); ++ irfun->code_function_def = vec_size(ir->code->functions); ++ fun.entry = vec_size(ir->code->statements); } - vec_push(code_functions, fun); - vec_push(code->functions, fun); ++ vec_push(ir->code->functions, fun); return true; } @@@ -3091,15 -3084,14 +3107,14 @@@ static ir_value* ir_gen_extparam_proto( ir_value *global; char name[128]; - snprintf(name, sizeof(name), "EXTPARM#%i", (int)(vec_size(ir->extparam_protos))); + util_snprintf(name, sizeof(name), "EXTPARM#%i", (int)(vec_size(ir->extparam_protos))); global = ir_value_var(name, store_global, TYPE_VECTOR); - global->untracked = true; vec_push(ir->extparam_protos, global); return global; } -static void ir_gen_extparam(code_t *code, ir_builder *ir) +static void ir_gen_extparam(ir_builder *ir) { prog_section_def def; ir_value *global; @@@ -3109,20 -3101,22 +3124,22 @@@ else global = ir->extparam_protos[vec_size(ir->extparams)]; - def.name = code_genstring(global->name); - def.type = TYPE_VECTOR; - def.offset = vec_size(code_globals); - def.name = code_genstring(code, global->name); ++ def.name = code_genstring(ir->code, global->name); + def.type = TYPE_VECTOR; - def.offset = vec_size(code->globals); ++ def.offset = vec_size(ir->code->globals); + - vec_push(code->defs, def); ++ vec_push(ir->code->defs, def); - vec_push(code_defs, def); ir_value_code_setaddr(global, def.offset); - vec_push(code_globals, 0); - vec_push(code_globals, 0); - vec_push(code_globals, 0); + - vec_push(code->globals, 0); - vec_push(code->globals, 0); - vec_push(code->globals, 0); ++ vec_push(ir->code->globals, 0); ++ vec_push(ir->code->globals, 0); ++ vec_push(ir->code->globals, 0); vec_push(ir->extparams, global); } - static bool gen_function_extparam_copy(ir_function *self) + static bool gen_function_extparam_copy(code_t *code, ir_function *self) { size_t i, ext, numparams; @@@ -3139,7 -3133,7 +3156,7 @@@ for (i = 8; i < numparams; ++i) { ext = i - 8; if (ext >= vec_size(ir->extparams)) - ir_gen_extparam(code, ir); + ir_gen_extparam(ir); ep = ir->extparams[ext]; @@@ -3151,13 -3145,13 +3168,13 @@@ } stmt.o1.u1 = ir_value_code_addr(ep); stmt.o2.u1 = ir_value_code_addr(self->locals[i]); - code_push_statement(&stmt, self->context.line); + code_push_statement(code, &stmt, self->context.line); } return true; } - static bool gen_function_varargs_copy(ir_function *self) + static bool gen_function_varargs_copy(code_t *code, ir_function *self) { size_t i, ext, numparams, maxparams; @@@ -3176,24 -3170,24 +3193,24 @@@ if (i < 8) { stmt.o1.u1 = OFS_PARM0 + 3*i; stmt.o2.u1 = ir_value_code_addr(self->locals[i]); - code_push_statement(&stmt, self->context.line); + code_push_statement(code, &stmt, self->context.line); continue; } ext = i - 8; while (ext >= vec_size(ir->extparams)) - ir_gen_extparam(code, ir); + ir_gen_extparam(ir); ep = ir->extparams[ext]; stmt.o1.u1 = ir_value_code_addr(ep); stmt.o2.u1 = ir_value_code_addr(self->locals[i]); - code_push_statement(&stmt, self->context.line); + code_push_statement(code, &stmt, self->context.line); } return true; } -static bool gen_function_locals(code_t *code, ir_builder *ir, ir_value *global) +static bool gen_function_locals(ir_builder *ir, ir_value *global) { prog_section_function *def; ir_function *irfun; @@@ -3201,13 -3195,13 +3218,13 @@@ uint32_t firstlocal, firstglobal; irfun = global->constval.vfunc; - def = code_functions + irfun->code_function_def; - def = code->functions + irfun->code_function_def; ++ def = ir->code->functions + irfun->code_function_def; if (OPTS_OPTION_BOOL(OPTION_G) || !OPTS_OPTIMIZATION(OPTIM_OVERLAP_LOCALS) || (irfun->flags & IR_FLAG_MASK_NO_OVERLAP)) { - firstlocal = def->firstlocal = vec_size(code_globals); - firstlocal = def->firstlocal = vec_size(code->globals); ++ firstlocal = def->firstlocal = vec_size(ir->code->globals); } else { firstlocal = def->firstlocal = ir->first_common_local; ++opts_optimizationcount[OPTIM_OVERLAP_LOCALS]; @@@ -3215,13 -3209,13 +3232,13 @@@ firstglobal = (OPTS_OPTIMIZATION(OPTIM_GLOBAL_TEMPS) ? ir->first_common_globaltemp : firstlocal); - for (i = vec_size(code_globals); i < firstlocal + irfun->allocated_locals; ++i) - vec_push(code_globals, 0); - for (i = vec_size(code->globals); i < firstlocal + irfun->allocated_locals; ++i) - vec_push(code->globals, 0); ++ for (i = vec_size(ir->code->globals); i < firstlocal + irfun->allocated_locals; ++i) ++ vec_push(ir->code->globals, 0); for (i = 0; i < vec_size(irfun->locals); ++i) { ir_value *v = irfun->locals[i]; if (v->locked || !OPTS_OPTIMIZATION(OPTIM_GLOBAL_TEMPS)) { ir_value_code_setaddr(v, firstlocal + v->code.local); - if (!ir_builder_gen_global(code, ir, irfun->locals[i], true)) { + if (!ir_builder_gen_global(ir, irfun->locals[i], true)) { irerror(irfun->locals[i]->context, "failed to generate local %s", irfun->locals[i]->name); return false; } @@@ -3242,7 -3236,7 +3259,7 @@@ return true; } -static bool gen_global_function_code(code_t *code, ir_builder *ir, ir_value *global) +static bool gen_global_function_code(ir_builder *ir, ir_value *global) { prog_section_function *fundef; ir_function *irfun; @@@ -3266,29 -3260,29 +3283,29 @@@ irerror(irfun->context, "`%s`: IR global wasn't generated, failed to access function-def", irfun->name); return false; } - fundef = &code_functions[irfun->code_function_def]; - fundef = &code->functions[irfun->code_function_def]; ++ fundef = &ir->code->functions[irfun->code_function_def]; - fundef->entry = vec_size(code_statements); - fundef->entry = vec_size(code->statements); - if (!gen_function_locals(code, ir, global)) { ++ fundef->entry = vec_size(ir->code->statements); + if (!gen_function_locals(ir, global)) { irerror(irfun->context, "Failed to generate locals for function %s", irfun->name); return false; } - if (!gen_function_extparam_copy(irfun)) { - if (!gen_function_extparam_copy(code, irfun)) { ++ if (!gen_function_extparam_copy(ir->code, irfun)) { irerror(irfun->context, "Failed to generate extparam-copy code for function %s", irfun->name); return false; } - if (irfun->max_varargs && !gen_function_varargs_copy(irfun)) { - if (irfun->max_varargs && !gen_function_varargs_copy(code, irfun)) { ++ if (irfun->max_varargs && !gen_function_varargs_copy(ir->code, irfun)) { irerror(irfun->context, "Failed to generate vararg-copy code for function %s", irfun->name); return false; } - if (!gen_function_code(irfun)) { - if (!gen_function_code(code, irfun)) { ++ if (!gen_function_code(ir->code, irfun)) { irerror(irfun->context, "Failed to generate code for function %s", irfun->name); return false; } return true; } - static void gen_vector_defs(prog_section_def def, const char *name) + static void gen_vector_defs(code_t *code, prog_section_def def, const char *name) { char *component; size_t len, i; @@@ -3309,8 -3303,8 +3326,8 @@@ component[len-1] = 'x'; for (i = 0; i < 3; ++i) { - def.name = code_genstring(component); - vec_push(code_defs, def); + def.name = code_genstring(code, component); + vec_push(code->defs, def); def.offset++; component[len-1]++; } @@@ -3318,7 -3312,7 +3335,7 @@@ mem_d(component); } - static void gen_vector_fields(prog_section_field fld, const char *name) + static void gen_vector_fields(code_t *code, prog_section_field fld, const char *name) { char *component; size_t len, i; @@@ -3339,8 -3333,8 +3356,8 @@@ component[len-1] = 'x'; for (i = 0; i < 3; ++i) { - fld.name = code_genstring(component); - vec_push(code_fields, fld); + fld.name = code_genstring(code, component); + vec_push(code->fields, fld); fld.offset++; component[len-1]++; } @@@ -3348,7 -3342,7 +3365,7 @@@ mem_d(component); } -static bool ir_builder_gen_global(code_t *code, ir_builder *self, ir_value *global, bool islocal) +static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool islocal) { size_t i; int32_t *iptr; @@@ -3356,7 -3350,7 +3373,7 @@@ bool pushdef = opts.optimizeoff; def.type = global->vtype; - def.offset = vec_size(code_globals); - def.offset = vec_size(code->globals); ++ def.offset = vec_size(self->code->globals); def.name = 0; if (OPTS_OPTION_BOOL(OPTION_G) || !islocal) { @@@ -3372,21 -3366,21 +3389,21 @@@ if (pushdef && global->name) { if (global->name[0] == '#') { if (!self->str_immediate) - self->str_immediate = code_genstring("IMMEDIATE"); - self->str_immediate = code_genstring(code, "IMMEDIATE"); ++ self->str_immediate = code_genstring(self->code, "IMMEDIATE"); def.name = global->code.name = self->str_immediate; } else - def.name = global->code.name = code_genstring(global->name); - def.name = global->code.name = code_genstring(code, global->name); ++ def.name = global->code.name = code_genstring(self->code, global->name); } else def.name = 0; if (islocal) { def.offset = ir_value_code_addr(global); - vec_push(code_defs, def); - vec_push(code->defs, def); ++ vec_push(self->code->defs, def); if (global->vtype == TYPE_VECTOR) - gen_vector_defs(def, global->name); - gen_vector_defs(code, def, global->name); ++ gen_vector_defs(self->code, def, global->name); else if (global->vtype == TYPE_FIELD && global->fieldtype == TYPE_VECTOR) - gen_vector_defs(def, global->name); - gen_vector_defs(code, def, global->name); ++ gen_vector_defs(self->code, def, global->name); return true; } } @@@ -3413,102 -3407,103 +3430,103 @@@ * Maybe this could be an -foption * fteqcc creates data for end_sys_* - of size 1, so let's do the same */ - ir_value_code_setaddr(global, vec_size(code_globals)); - vec_push(code_globals, 0); - ir_value_code_setaddr(global, vec_size(code->globals)); - vec_push(code->globals, 0); ++ ir_value_code_setaddr(global, vec_size(self->code->globals)); ++ vec_push(self->code->globals, 0); /* Add the def */ - if (pushdef) vec_push(code_defs, def); - if (pushdef) vec_push(code->defs, def); ++ if (pushdef) vec_push(self->code->defs, def); return true; case TYPE_POINTER: - if (pushdef) vec_push(code_defs, def); - return gen_global_pointer(global); - if (pushdef) vec_push(code->defs, def); - return gen_global_pointer(code, global); ++ if (pushdef) vec_push(self->code->defs, def); ++ return gen_global_pointer(self->code, global); case TYPE_FIELD: if (pushdef) { - vec_push(code_defs, def); - vec_push(code->defs, def); ++ vec_push(self->code->defs, def); if (global->fieldtype == TYPE_VECTOR) - gen_vector_defs(def, global->name); - gen_vector_defs(code, def, global->name); ++ gen_vector_defs(self->code, def, global->name); } - return gen_global_field(global); - return gen_global_field(code, global); ++ return gen_global_field(self->code, global); case TYPE_ENTITY: /* fall through */ case TYPE_FLOAT: { - ir_value_code_setaddr(global, vec_size(code_globals)); - ir_value_code_setaddr(global, vec_size(code->globals)); ++ ir_value_code_setaddr(global, vec_size(self->code->globals)); if (global->hasvalue) { iptr = (int32_t*)&global->constval.ivec[0]; - vec_push(code_globals, *iptr); - vec_push(code->globals, *iptr); ++ vec_push(self->code->globals, *iptr); } else { - vec_push(code_globals, 0); - vec_push(code->globals, 0); ++ vec_push(self->code->globals, 0); } if (!islocal && global->cvq != CV_CONST) def.type |= DEF_SAVEGLOBAL; - if (pushdef) vec_push(code_defs, def); - if (pushdef) vec_push(code->defs, def); ++ if (pushdef) vec_push(self->code->defs, def); return global->code.globaladdr >= 0; } case TYPE_STRING: { - ir_value_code_setaddr(global, vec_size(code_globals)); - ir_value_code_setaddr(global, vec_size(code->globals)); ++ ir_value_code_setaddr(global, vec_size(self->code->globals)); if (global->hasvalue) { - vec_push(code_globals, code_genstring(global->constval.vstring)); - uint32_t load = code_genstring(code, global->constval.vstring); - vec_push(code->globals, load); ++ uint32_t load = code_genstring(self->code, global->constval.vstring); ++ vec_push(self->code->globals, load); } else { - vec_push(code_globals, 0); - vec_push(code->globals, 0); ++ vec_push(self->code->globals, 0); } if (!islocal && global->cvq != CV_CONST) def.type |= DEF_SAVEGLOBAL; - if (pushdef) vec_push(code_defs, def); - if (pushdef) vec_push(code->defs, def); ++ if (pushdef) vec_push(self->code->defs, def); return global->code.globaladdr >= 0; } case TYPE_VECTOR: { size_t d; - ir_value_code_setaddr(global, vec_size(code_globals)); - ir_value_code_setaddr(global, vec_size(code->globals)); ++ ir_value_code_setaddr(global, vec_size(self->code->globals)); if (global->hasvalue) { iptr = (int32_t*)&global->constval.ivec[0]; - vec_push(code_globals, iptr[0]); - vec_push(code->globals, iptr[0]); ++ vec_push(self->code->globals, iptr[0]); if (global->code.globaladdr < 0) return false; for (d = 1; d < type_sizeof_[global->vtype]; ++d) { - vec_push(code_globals, iptr[d]); - vec_push(code->globals, iptr[d]); ++ vec_push(self->code->globals, iptr[d]); } } else { - vec_push(code_globals, 0); - vec_push(code->globals, 0); ++ vec_push(self->code->globals, 0); if (global->code.globaladdr < 0) return false; for (d = 1; d < type_sizeof_[global->vtype]; ++d) { - vec_push(code_globals, 0); - vec_push(code->globals, 0); ++ vec_push(self->code->globals, 0); } } if (!islocal && global->cvq != CV_CONST) def.type |= DEF_SAVEGLOBAL; if (pushdef) { - vec_push(code_defs, def); - vec_push(code->defs, def); ++ vec_push(self->code->defs, def); def.type &= ~DEF_SAVEGLOBAL; - gen_vector_defs(def, global->name); - gen_vector_defs(code, def, global->name); ++ gen_vector_defs(self->code, def, global->name); } return global->code.globaladdr >= 0; } case TYPE_FUNCTION: - ir_value_code_setaddr(global, vec_size(code_globals)); - ir_value_code_setaddr(global, vec_size(code->globals)); ++ ir_value_code_setaddr(global, vec_size(self->code->globals)); if (!global->hasvalue) { - vec_push(code_globals, 0); - vec_push(code->globals, 0); ++ vec_push(self->code->globals, 0); if (global->code.globaladdr < 0) return false; } else { - vec_push(code_globals, vec_size(code_functions)); - vec_push(code->globals, vec_size(code->functions)); - if (!gen_global_function(code, self, global)) ++ vec_push(self->code->globals, vec_size(self->code->functions)); + if (!gen_global_function(self, global)) return false; } if (!islocal && global->cvq != CV_CONST) def.type |= DEF_SAVEGLOBAL; - if (pushdef) vec_push(code_defs, def); - if (pushdef) vec_push(code->defs, def); ++ if (pushdef) vec_push(self->code->defs, def); return true; case TYPE_VARIANT: /* assume biggest type */ - ir_value_code_setaddr(global, vec_size(code_globals)); - vec_push(code_globals, 0); - ir_value_code_setaddr(global, vec_size(code->globals)); - vec_push(code->globals, 0); ++ ir_value_code_setaddr(global, vec_size(self->code->globals)); ++ vec_push(self->code->globals, 0); for (i = 1; i < type_sizeof_[TYPE_VARIANT]; ++i) - vec_push(code_globals, 0); - vec_push(code->globals, 0); ++ vec_push(self->code->globals, 0); return true; default: /* refuse to create 'void' type or any other fancy business. */ @@@ -3518,12 -3513,12 +3536,12 @@@ } } - static void ir_builder_prepare_field(ir_value *field) + static GMQCC_INLINE void ir_builder_prepare_field(code_t *code, ir_value *field) { - field->code.fieldaddr = code_alloc_field(type_sizeof_[field->fieldtype]); + field->code.fieldaddr = code_alloc_field(code, type_sizeof_[field->fieldtype]); } -static bool ir_builder_gen_field(code_t *code, ir_builder *self, ir_value *field) +static bool ir_builder_gen_field(ir_builder *self, ir_value *field) { prog_section_def def; prog_section_field fld; @@@ -3531,7 -3526,7 +3549,7 @@@ (void)self; def.type = (uint16_t)field->vtype; - def.offset = (uint16_t)vec_size(code_globals); - def.offset = (uint16_t)vec_size(code->globals); ++ def.offset = (uint16_t)vec_size(self->code->globals); /* create a global named the same as the field */ if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_GMQCC) { @@@ -3551,7 -3546,7 +3569,7 @@@ memcpy(name+1, field->name, len); /* no strncpy - we used strlen above */ name[len+1] = 0; - def.name = code_genstring(name); - def.name = code_genstring(code, name); ++ def.name = code_genstring(self->code, name); fld.name = def.name + 1; /* we reuse that string table entry */ } else { /* in plain QC, there cannot be a global with the same name, @@@ -3559,13 -3554,13 +3577,13 @@@ * FIXME: fteqcc should create a global as well * check if it actually uses the same name. Probably does */ - def.name = code_genstring(field->name); - def.name = code_genstring(code, field->name); ++ def.name = code_genstring(self->code, field->name); fld.name = def.name; } field->code.name = def.name; - vec_push(code_defs, def); - vec_push(code->defs, def); ++ vec_push(self->code->defs, def); fld.type = field->fieldtype; @@@ -3576,49 -3571,37 +3594,37 @@@ fld.offset = field->code.fieldaddr; - vec_push(code_fields, fld); - vec_push(code->fields, fld); ++ vec_push(self->code->fields, fld); - ir_value_code_setaddr(field, vec_size(code_globals)); - vec_push(code_globals, fld.offset); - ir_value_code_setaddr(field, vec_size(code->globals)); - vec_push(code->globals, fld.offset); ++ ir_value_code_setaddr(field, vec_size(self->code->globals)); ++ vec_push(self->code->globals, fld.offset); if (fld.type == TYPE_VECTOR) { - vec_push(code_globals, fld.offset+1); - vec_push(code_globals, fld.offset+2); - vec_push(code->globals, fld.offset+1); - vec_push(code->globals, fld.offset+2); ++ vec_push(self->code->globals, fld.offset+1); ++ vec_push(self->code->globals, fld.offset+2); } if (field->fieldtype == TYPE_VECTOR) { - gen_vector_defs(def, field->name); - gen_vector_fields(fld, field->name); - gen_vector_defs (code, def, field->name); - gen_vector_fields(code, fld, field->name); ++ gen_vector_defs (self->code, def, field->name); ++ gen_vector_fields(self->code, fld, field->name); } return field->code.globaladdr >= 0; } - bool ir_builder_prepare(ir_builder *self) - { - size_t extparams = self->max_used_params; - if (extparams > 8) { - for (extparams -= 8; extparams; --extparams) - ir_gen_extparam_proto(self); - } - return true; - } - -bool ir_builder_generate(code_t *code, ir_builder *self, const char *filename) +bool ir_builder_generate(ir_builder *self, const char *filename) { prog_section_statement stmt; size_t i; char *lnofile = NULL; - code_init(); - for (i = 0; i < vec_size(self->fields); ++i) { - ir_builder_prepare_field(self->fields[i]); - ir_builder_prepare_field(code, self->fields[i]); ++ ir_builder_prepare_field(self->code, self->fields[i]); } for (i = 0; i < vec_size(self->globals); ++i) { - if (!ir_builder_gen_global(code, self, self->globals[i], false)) { + if (!ir_builder_gen_global(self, self->globals[i], false)) { return false; } if (self->globals[i]->vtype == TYPE_FUNCTION) { @@@ -3635,62 -3618,62 +3641,62 @@@ for (i = 0; i < vec_size(self->fields); ++i) { - if (!ir_builder_gen_field(code, self, self->fields[i])) { + if (!ir_builder_gen_field(self, self->fields[i])) { return false; } } /* generate nil */ - ir_value_code_setaddr(self->nil, vec_size(code_globals)); - vec_push(code_globals, 0); - vec_push(code_globals, 0); - vec_push(code_globals, 0); - ir_value_code_setaddr(self->nil, vec_size(code->globals)); - vec_push(code->globals, 0); - vec_push(code->globals, 0); - vec_push(code->globals, 0); ++ ir_value_code_setaddr(self->nil, vec_size(self->code->globals)); ++ vec_push(self->code->globals, 0); ++ vec_push(self->code->globals, 0); ++ vec_push(self->code->globals, 0); /* generate global temps */ - self->first_common_globaltemp = vec_size(code_globals); - self->first_common_globaltemp = vec_size(code->globals); ++ self->first_common_globaltemp = vec_size(self->code->globals); for (i = 0; i < self->max_globaltemps; ++i) { - vec_push(code_globals, 0); - vec_push(code->globals, 0); ++ vec_push(self->code->globals, 0); } /* generate common locals */ - self->first_common_local = vec_size(code_globals); - self->first_common_local = vec_size(code->globals); ++ self->first_common_local = vec_size(self->code->globals); for (i = 0; i < self->max_locals; ++i) { - vec_push(code_globals, 0); - vec_push(code->globals, 0); ++ vec_push(self->code->globals, 0); } /* generate function code */ for (i = 0; i < vec_size(self->globals); ++i) { if (self->globals[i]->vtype == TYPE_FUNCTION) { - if (!gen_global_function_code(code, self, self->globals[i])) { + if (!gen_global_function_code(self, self->globals[i])) { return false; } } } - if (vec_size(code_globals) >= 65536) { - if (vec_size(code->globals) >= 65536) { ++ if (vec_size(self->code->globals) >= 65536) { irerror(vec_last(self->globals)->context, "This progs file would require more globals than the metadata can handle. Bailing out."); return false; } /* DP errors if the last instruction is not an INSTR_DONE. */ - if (vec_last(code_statements).opcode != INSTR_DONE) - if (vec_last(code->statements).opcode != INSTR_DONE) ++ if (vec_last(self->code->statements).opcode != INSTR_DONE) { stmt.opcode = INSTR_DONE; stmt.o1.u1 = 0; stmt.o2.u1 = 0; stmt.o3.u1 = 0; - code_push_statement(&stmt, vec_last(code_linenums)); - code_push_statement(code, &stmt, vec_last(code->linenums)); ++ code_push_statement(self->code, &stmt, vec_last(self->code->linenums)); } if (OPTS_OPTION_BOOL(OPTION_PP_ONLY)) return true; - if (vec_size(code_statements) != vec_size(code_linenums)) { - if (vec_size(code->statements) != vec_size(code->linenums)) { ++ if (vec_size(self->code->statements) != vec_size(self->code->linenums)) { con_err("Linecounter wrong: %lu != %lu\n", - (unsigned long)vec_size(code_statements), - (unsigned long)vec_size(code_linenums)); - (unsigned long)vec_size(code->statements), - (unsigned long)vec_size(code->linenums)); ++ (unsigned long)vec_size(self->code->statements), ++ (unsigned long)vec_size(self->code->linenums)); } else if (OPTS_FLAG(LNO)) { - char *dot; + char *dot; size_t filelen = strlen(filename); memcpy(vec_add(lnofile, filelen+1), filename, filelen+1); @@@ -3709,7 -3692,7 +3715,7 @@@ else con_out("writing '%s'\n", filename); } - if (!code_write(filename, lnofile)) { - if (!code_write(code, filename, lnofile)) { ++ if (!code_write(self->code, filename, lnofile)) { vec_free(lnofile); return false; } @@@ -3727,7 -3710,7 +3733,7 @@@ # define strncat(dst, src, sz) strncat_s(dst, sz, src, _TRUNCATE) #endif - const char *qc_opname(int op) + static const char *qc_opname(int op) { if (op < 0) return ""; if (op < (int)( sizeof(asm_instr) / sizeof(asm_instr[0]) )) @@@ -3774,7 -3757,7 +3780,7 @@@ void ir_function_dump(ir_function *f, c return; } oprintf("%sfunction %s\n", ind, f->name); -- strncat(ind, "\t", IND_BUFSZ); ++ strncat(ind, "\t", IND_BUFSZ-1); if (vec_size(f->locals)) { oprintf("%s%i locals:\n", ind, (int)vec_size(f->locals)); @@@ -3855,7 -3838,7 +3861,7 @@@ } if (vec_size(f->blocks)) { - oprintf("%slife passes: %i\n", ind, (int)f->run_id); + oprintf("%slife passes: %i\n", ind, (int)f->run_id); for (i = 0; i < vec_size(f->blocks); ++i) { ir_block_dump(f->blocks[i], ind, oprintf); } @@@ -3870,7 -3853,7 +3876,7 @@@ void ir_block_dump(ir_block* b, char *i { size_t i; oprintf("%s:%s\n", ind, b->label); -- strncat(ind, "\t", IND_BUFSZ); ++ strncat(ind, "\t", IND_BUFSZ-1); if (b->instr && b->instr[0]) oprintf("%s (%i) [entry]\n", ind, (int)(b->instr[0]->eid-1)); @@@ -3879,7 -3862,7 +3885,7 @@@ ind[strlen(ind)-1] = 0; } - void dump_phi(ir_instr *in, int (*oprintf)(const char*, ...)) + static void dump_phi(ir_instr *in, int (*oprintf)(const char*, ...)) { size_t i; oprintf("%s <- phi ", in->_ops[0]->name); @@@ -3904,7 -3887,7 +3910,7 @@@ void ir_instr_dump(ir_instr *in, char * return; } -- strncat(ind, "\t", IND_BUFSZ); ++ strncat(ind, "\t", IND_BUFSZ-1); if (in->_ops[0] && (in->_ops[1] || in->_ops[2])) { ir_value_dump(in->_ops[0], oprintf); @@@ -3949,7 -3932,7 +3955,7 @@@ ind[strlen(ind)-1] = 0; } - void ir_value_dump_string(const char *str, int (*oprintf)(const char*, ...)) + static void ir_value_dump_string(const char *str, int (*oprintf)(const char*, ...)) { oprintf("\""); for (; *str; ++str) { diff --combined ir.h index 50fd0d9,cd38295..f5b47da --- a/ir.h +++ b/ir.h @@@ -23,7 -23,6 +23,6 @@@ #ifndef GMQCC_IR_HDR #define GMQCC_IR_HDR #include "gmqcc.h" - /* ir_value */ typedef struct { @@@ -46,7 -45,6 +45,6 @@@ typedef struct ir_value_s int cvq; uint32_t flags; - bool untracked; struct ir_instr_s **reads; struct ir_instr_s **writes; @@@ -87,42 -85,19 +85,19 @@@ ir_life_entry_t *life; } ir_value; - int32_t ir_value_code_addr(const ir_value*); - /* ir_value can be a variable, or created by an operation */ - ir_value* ir_value_var(const char *name, int st, int vtype); /* if a result of an operation: the function should store * it to remember to delete it / garbage collect it */ - ir_value* ir_value_out(struct ir_function_s *owner, const char *name, int st, int vtype); - void ir_value_delete(ir_value*); - bool ir_value_set_name(ir_value*, const char *name); - ir_value* ir_value_vector_member(ir_value*, unsigned int member); - - bool GMQCC_WARN vec_ir_value_find(ir_value **vec, const ir_value *what, size_t *idx); - + void ir_value_delete(ir_value*); + ir_value* ir_value_vector_member(ir_value*, unsigned int member); bool GMQCC_WARN ir_value_set_float(ir_value*, float f); bool GMQCC_WARN ir_value_set_func(ir_value*, int f); - #if 0 - bool GMQCC_WARN ir_value_set_int(ir_value*, int i); - #endif bool GMQCC_WARN ir_value_set_string(ir_value*, const char *s); bool GMQCC_WARN ir_value_set_vector(ir_value*, vector v); bool GMQCC_WARN ir_value_set_field(ir_value*, ir_value *fld); - /*bool ir_value_set_pointer_v(ir_value*, ir_value* p); */ - /*bool ir_value_set_pointer_i(ir_value*, int i); */ - - /* merge an instruction into the life-range */ - /* returns false if the lifepoint was already known */ - bool ir_value_life_merge(ir_value*, size_t); - bool ir_value_life_merge_into(ir_value*, const ir_value*); - /* check if a value lives at a specific point */ - bool ir_value_lives(ir_value*, size_t); - /* check if the life-range of 2 values overlaps */ - bool ir_values_overlap(const ir_value*, const ir_value*); - - void ir_value_dump(ir_value*, int (*oprintf)(const char*,...)); - void ir_value_dump_life(const ir_value *self, int (*oprintf)(const char*,...)); + bool ir_value_lives(ir_value*, size_t); + void ir_value_dump_life(const ir_value *self, int (*oprintf)(const char*,...)); /* PHI data */ typedef struct ir_phi_entry_s @@@ -151,15 -126,6 +126,6 @@@ typedef struct ir_instr_ struct ir_block_s *owner; } ir_instr; - ir_instr* ir_instr_new(lex_ctx ctx, struct ir_block_s *owner, int opcode); - void ir_instr_delete(ir_instr*); - - bool GMQCC_WARN vec_ir_instr_find(ir_instr **vec, ir_instr *what, size_t *idx); - - bool ir_instr_op(ir_instr*, int op, ir_value *value, bool writing); - - void ir_instr_dump(ir_instr* in, char *ind, int (*oprintf)(const char*,...)); - /* block */ typedef struct ir_block_s { @@@ -183,30 -149,16 +149,16 @@@ size_t code_start; } ir_block; - ir_block* ir_block_new(struct ir_function_s *owner, const char *label); - void ir_block_delete(ir_block*); - - bool ir_block_set_label(ir_block*, const char *label); - - ir_value* ir_block_create_binop(ir_block*, lex_ctx, const char *label, int op, - ir_value *left, ir_value *right); - ir_value* ir_block_create_unary(ir_block*, lex_ctx, const char *label, int op, - ir_value *operand); + ir_value* ir_block_create_binop(ir_block*, lex_ctx, const char *label, int op, ir_value *left, ir_value *right); + ir_value* ir_block_create_unary(ir_block*, lex_ctx, const char *label, int op, ir_value *operand); bool GMQCC_WARN ir_block_create_store_op(ir_block*, lex_ctx, int op, ir_value *target, ir_value *what); - bool GMQCC_WARN ir_block_create_store(ir_block*, lex_ctx, ir_value *target, ir_value *what); bool GMQCC_WARN ir_block_create_storep(ir_block*, lex_ctx, ir_value *target, ir_value *what); - - /* field must be of TYPE_FIELD */ - ir_value* ir_block_create_load_from_ent(ir_block*, lex_ctx, const char *label, ir_value *ent, ir_value *field, int outype); - - ir_value* ir_block_create_fieldaddress(ir_block*, lex_ctx, const char *label, ir_value *entity, ir_value *field); + ir_value* ir_block_create_load_from_ent(ir_block*, lex_ctx, const char *label, ir_value *ent, ir_value *field, int outype); + ir_value* ir_block_create_fieldaddress(ir_block*, lex_ctx, const char *label, ir_value *entity, ir_value *field); /* This is to create an instruction of the form * %label := opcode a, b */ - ir_value* ir_block_create_general_instr(ir_block *self, lex_ctx, const char *label, - int op, ir_value *a, ir_value *b, int outype); - ir_instr* ir_block_create_phi(ir_block*, lex_ctx, const char *label, int vtype); ir_value* ir_phi_value(ir_instr*); void ir_phi_add(ir_instr*, ir_block *b, ir_value *v); @@@ -227,10 -179,7 +179,7 @@@ bool GMQCC_WARN ir_block_create_if(ir_b bool GMQCC_WARN ir_block_create_jump(ir_block*, lex_ctx, ir_block *to); bool GMQCC_WARN ir_block_create_goto(ir_block*, lex_ctx, ir_block *to); - void ir_block_dump(ir_block*, char *ind, int (*oprintf)(const char*,...)); - /* function */ - typedef struct ir_function_s { char *name; @@@ -277,6 -226,7 +226,7 @@@ /* vararg support: */ size_t max_varargs; } ir_function; + #define IR_FLAG_HAS_ARRAYS (1<<1) #define IR_FLAG_HAS_UNINITIALIZED (1<<2) #define IR_FLAG_HAS_GOTO (1<<3) @@@ -284,26 -234,9 +234,9 @@@ #define IR_FLAG_MASK_NO_OVERLAP (IR_FLAG_HAS_ARRAYS | IR_FLAG_HAS_UNINITIALIZED) #define IR_FLAG_MASK_NO_LOCAL_TEMPS (IR_FLAG_HAS_ARRAYS | IR_FLAG_HAS_UNINITIALIZED) - ir_function* ir_function_new(struct ir_builder_s *owner, int returntype); - void ir_function_delete(ir_function*); - - void ir_function_collect_value(ir_function*, ir_value *value); - - bool ir_function_set_name(ir_function*, const char *name); - - ir_value* ir_function_create_local(ir_function *self, const char *name, int vtype, bool param); - - bool GMQCC_WARN ir_function_optimize(ir_function*); + ir_value* ir_function_create_local(ir_function *self, const char *name, int vtype, bool param); bool GMQCC_WARN ir_function_finalize(ir_function*); - /* - bool ir_function_naive_phi(ir_function*); - bool ir_function_enumerate(ir_function*); - bool ir_function_calculate_liferanges(ir_function*); - */ - - ir_block* ir_function_create_block(lex_ctx ctx, ir_function*, const char *label); - - void ir_function_dump(ir_function*, char *ind, int (*oprintf)(const char*,...)); + ir_block* ir_function_create_block(lex_ctx ctx, ir_function*, const char *label); /* builder */ #define IR_HT_SIZE 1024 @@@ -327,9 -260,6 +260,6 @@@ typedef struct ir_builder_ uint32_t first_common_local; uint32_t first_common_globaltemp; - /* highest number of parameters */ - size_t max_used_params; - const char **filenames; qcint *filestrings; /* we cache the #IMMEDIATE string here */ @@@ -337,30 -267,23 +267,26 @@@ /* there should just be this one nil */ ir_value *nil; ir_value *reserved_va_count; ++ ++ /* code generator */ ++ code_t *code; } ir_builder; - ir_builder* ir_builder_new(const char *modulename); - void ir_builder_delete(ir_builder*); - - bool ir_builder_set_name(ir_builder *self, const char *name); - - ir_function* ir_builder_get_function(ir_builder*, const char *fun); + ir_builder* ir_builder_new(const char *modulename); + void ir_builder_delete(ir_builder*); ir_function* ir_builder_create_function(ir_builder*, const char *name, int outtype); + ir_value* ir_builder_create_global(ir_builder*, const char *name, int vtype); + ir_value* ir_builder_create_field(ir_builder*, const char *name, int vtype); + ir_value* ir_builder_get_va_count(ir_builder*); -bool ir_builder_generate(code_t *, ir_builder *self, const char *filename); ++bool ir_builder_generate(ir_builder *self, const char *filename); + void ir_builder_dump(ir_builder*, int (*oprintf)(const char*, ...)); - ir_value* ir_builder_get_global(ir_builder*, const char *fun); - ir_value* ir_builder_create_global(ir_builder*, const char *name, int vtype); - ir_value* ir_builder_get_field(ir_builder*, const char *fun); - ir_value* ir_builder_create_field(ir_builder*, const char *name, int vtype); - - ir_value* ir_builder_get_va_count(ir_builder*); - - bool ir_builder_prepare(ir_builder *self); - bool ir_builder_generate(ir_builder *self, const char *filename); - - void ir_builder_dump(ir_builder*, int (*oprintf)(const char*, ...)); - - /* This code assumes 32 bit floats while generating binary */ - extern int check_int_and_float_size - [ (sizeof(int32_t) == sizeof(qcfloat)) ? 1 : -1 ]; + /* + * This code assumes 32 bit floats while generating binary + * Blub: don't use extern here, it's annoying and shows up in nm - * for some reason :P ++ * for some reason :P + */ + typedef int static_assert_is_32bit_float [(sizeof(int32_t) == 4)?1:-1]; + typedef int static_assert_is_32bit_integer[(sizeof(qcfloat) == 4)?1:-1]; #endif diff --combined main.c index be4eaef,98de0e9..03da18f --- a/main.c +++ b/main.c @@@ -21,9 -21,15 +21,15 @@@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + #include + #include + #include + #include + #include + + #include "gmqcc.h" #include "lexer.h" - #include /* TODO: cleanup this whole file .. it's a fuckign mess */ @@@ -41,24 -47,20 +47,20 @@@ static ppitem *ppems = NULL #define TYPE_ASM 1 #define TYPE_SRC 2 + static const char *app_name; - static void version() { - con_out("GMQCC %d.%d.%d Built %s %s\n", + static void version(void) { + con_out("GMQCC %d.%d.%d Built %s %s\n" GMQCC_DEV_VERSION_STRING, GMQCC_VERSION_MAJOR, GMQCC_VERSION_MINOR, GMQCC_VERSION_PATCH, __DATE__, __TIME__ ); - #ifdef GMQCC_GITINFO - con_out("git build: %s\n", GMQCC_GITINFO); - #elif defined(GMQCC_VERION_TYPE_DEVEL) - con_out("development build\n"); - #endif } - static int usage() { + static int usage(void) { con_out("usage: %s [options] [files...]", app_name); con_out("options:\n" " -h, --help show this help message\n" @@@ -173,9 -175,12 +175,12 @@@ static bool options_parse(int argc, cha opts_set(opts.flags, INITIALIZED_NONCONSTANTS, true); opts_set(opts.werror, WARN_INVALID_PARAMETER_COUNT, true); opts_set(opts.werror, WARN_MISSING_RETURN_VALUES, true); + opts_set(opts.flags, EXPRESSIONS_FOR_BUILTINS, true); + opts_set(opts.warn, WARN_BREAKDEF, true); OPTS_OPTION_U32(OPTION_STANDARD) = COMPILER_GMQCC; + OPTS_OPTION_BOOL(OPTION_STATISTICS) = true; } else if (!strcmp(argarg, "qcc")) { @@@ -192,6 -197,7 +197,7 @@@ opts_set(opts.flags, ASSIGN_FUNCTION_TYPES, true); opts_set(opts.flags, CORRECT_TERNARY, false); opts_set(opts.warn, WARN_TERNARY_PRECEDENCE, true); + opts_set(opts.warn, WARN_BREAKDEF, true); OPTS_OPTION_U32(OPTION_STANDARD) = COMPILER_FTEQCC; @@@ -212,11 -218,6 +218,11 @@@ OPTS_OPTION_U16 (OPTION_FORCED_CRC) = strtol(argarg, NULL, 0); continue; } + if (options_long_gcc("jobs", &argc, &argv, &argarg)) { + + OPTS_OPTION_U32 (OPTION_J) = strtol(argarg, NULL, 0); + continue; + } if (options_long_gcc("redirout", &argc, &argv, &redirout)) { con_change(redirout, redirerr); continue; @@@ -464,14 -465,6 +470,14 @@@ vec_push(items, item); break; + case 'j': + if (!options_witharg(&argc, &argv, &argarg)) { + con_out("option -j requires a parameter\n"); + return false; + } + OPTS_OPTION_U32 (OPTION_J) = strtol(argarg, NULL, 0); + break; + case '-': if (!argv[0][2]) { /* anything following -- is considered a non-option argument */ @@@ -656,9 -649,6 +662,6 @@@ int main(int argc, char **argv) } } - if (OPTS_FLAG(TRUE_EMPTY_STRINGS)) - type_not_instr[TYPE_STRING] = INSTR_NOT_F; - util_debug("COM", "starting ...\n"); /* add macros */ @@@ -674,9 -664,10 +677,10 @@@ } if (!vec_size(items)) { - FILE *src; - char *line; + FILE *src; + char *line = NULL; size_t linelen = 0; + bool hasline = false; progs_src = true; @@@ -687,28 -678,23 +691,23 @@@ goto cleanup; } - line = NULL; - if (!progs_nextline(&line, &linelen, src) || !line[0]) { - con_err("illformatted progs.src file: expected output filename in first line\n"); - retval = 1; - goto srcdone; - } - - if (!opts_output_wasset) { - OPTS_OPTION_STR(OPTION_OUTPUT) = util_strdup(line); - opts_output_free = true; - } - while (progs_nextline(&line, &linelen, src)) { argitem item; + if (!line[0] || (line[0] == '/' && line[1] == '/')) continue; - item.filename = util_strdup(line); - item.type = TYPE_QC; - vec_push(items, item); + + if (hasline) { + item.filename = util_strdup(line); + item.type = TYPE_QC; + vec_push(items, item); + } else if (!opts_output_wasset) { + OPTS_OPTION_STR(OPTION_OUTPUT) = util_strdup(line); + opts_output_free = true; + hasline = true; + } } - srcdone: fs_file_close(src); mem_d(line); } @@@ -814,6 -800,7 +813,7 @@@ cleanup mem_d((void*)operators); lex_cleanup(); - util_meminfo(); + stat_info(); + return retval; } diff --combined opts.c index c3d69aa,e6ca420..97a3597 --- a/opts.c +++ b/opts.c @@@ -1,7 -1,7 +1,7 @@@ /* * Copyright (C) 2012, 2013 * Wolfgang Bumiller - * Dale Weiler + * Dale Weiler * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in @@@ -21,11 -21,16 +21,16 @@@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + #include + #include + #include + #include "gmqcc.h" + unsigned int opts_optimizationcount[COUNT_OPTIMIZATIONS]; opts_cmd_t opts; /* command lien options */ - static void opts_setdefault() { + static void opts_setdefault(void) { memset(&opts, 0, sizeof(opts_cmd_t)); OPTS_OPTION_BOOL(OPTION_CORRECTION) = true; @@@ -98,7 -103,6 +103,7 @@@ void opts_init(const char *output, int OPTS_OPTION_U32(OPTION_STANDARD) = standard; OPTS_OPTION_U32(OPTION_MAX_ARRAY_SIZE) = arraysize; OPTS_OPTION_U16(OPTION_MEMDUMPCOLS) = 16; + OPTS_OPTION_U32(OPTION_J) = 2; } static bool opts_setflag_all(const char *name, bool on, uint32_t *flags, const opts_flag_def *list, size_t listsize) { @@@ -217,7 -221,7 +222,7 @@@ static size_t opts_ini_parse /* section found */ if (*(parse_end = opts_ini_next(parse_beg + 1, ']')) == ']') { * parse_end = '\0'; /* terminate bro */ - strncpy(section_data, parse_beg + 1, sizeof(section_data)); + util_strncpy(section_data, parse_beg + 1, sizeof(section_data)); section_data[sizeof(section_data) - 1] = '\0'; *oldname_data = '\0'; } else if (!error) { @@@ -238,7 -242,7 +243,7 @@@ opts_ini_rstrip(read_value); /* valid name value pair, lets call down to handler */ - strncpy(oldname_data, read_name, sizeof(oldname_data)); + util_strncpy(oldname_data, read_name, sizeof(oldname_data)); oldname_data[sizeof(oldname_data) - 1] ='\0'; if ((*errorhandle = loadhandle(section_data, read_name, read_value)) && !error) @@@ -270,7 -274,7 +275,7 @@@ static char *opts_ini_load(const char * /* * undef all of these because they may still be defined like in my * case they where. - */ + */ #undef GMQCC_TYPE_FLAGS #undef GMQCC_TYPE_OPTIMIZATIONS #undef GMQCC_TYPE_WARNS @@@ -348,7 -352,7 +353,7 @@@ void opts_ini_init(const char *file) size_t line; FILE *ini; - + if (!file) { /* try ini */ if (!(ini = fs_file_open((file = "gmqcc.ini"), "r"))) @@@ -362,9 -366,9 +367,9 @@@ if ((line = opts_ini_parse(ini, &opts_ini_load, &error)) != 0) { /* there was a parse error with the ini file */ - con_printmsg(LVL_ERROR, file, line, "error", error); + con_printmsg(LVL_ERROR, file, line, 0 /*TODO: column for ini error*/, "error", error); vec_free(error); } fs_file_close(ini); - } + } diff --combined opts.def index 47f82ee,071b11a..7efe531 --- a/opts.def +++ b/opts.def @@@ -50,6 -50,8 +50,8 @@@ GMQCC_DEFINE_FLAG(PERMISSIVE) GMQCC_DEFINE_FLAG(VARIADIC_ARGS) GMQCC_DEFINE_FLAG(LEGACY_VECTOR_MATHS) + GMQCC_DEFINE_FLAG(EXPRESSIONS_FOR_BUILTINS) + GMQCC_DEFINE_FLAG(RETURN_ASSIGNMENTS) #endif /* warning flags */ @@@ -87,6 -89,7 +89,7 @@@ GMQCC_DEFINE_FLAG(DIFFERENT_ATTRIBUTES) GMQCC_DEFINE_FLAG(DEPRECATED) GMQCC_DEFINE_FLAG(PARENTHESIS) + GMQCC_DEFINE_FLAG(BREAKDEF) #endif #ifdef GMQCC_TYPE_OPTIMIZATIONS @@@ -119,7 -122,7 +122,8 @@@ GMQCC_DEFINE_FLAG(MAX_ARRAY_SIZE) GMQCC_DEFINE_FLAG(ADD_INFO) GMQCC_DEFINE_FLAG(CORRECTION) + GMQCC_DEFINE_FLAG(J) + GMQCC_DEFINE_FLAG(STATISTICS) #endif /* some cleanup so we don't have to */ diff --combined parser.c index 325a030,8a7cf87..8bf4086 --- a/parser.c +++ b/parser.c @@@ -2,7 -2,7 +2,7 @@@ * Copyright (C) 2012, 2013 * Wolfgang Bumiller * Dale Weiler - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to @@@ -21,10 -21,8 +21,9 @@@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - #include - #include + #include #include +#include #include "gmqcc.h" #include "lexer.h" @@@ -40,6 -38,8 +39,8 @@@ typedef struct parser_s lex_file *lex; int tok; + bool ast_cleaned; + ast_expression **globals; ast_expression **fields; ast_function **functions; @@@ -104,6 -104,9 +105,9 @@@ /* collected information */ size_t max_param_count; + + /* code generator */ + code_t *code; } parser_t; static ast_expression * const intrinsic_debug_typestring = (ast_expression*)0x1; @@@ -183,7 -186,7 +187,7 @@@ vector vec3_mulvf(vector a, float b * parsing */ - bool parser_next(parser_t *parser) + static bool parser_next(parser_t *parser) { /* lex_do kills the previous token */ parser->tok = lex_do(parser->lex); @@@ -218,6 -221,7 +222,7 @@@ static ast_value* parser_const_float(pa out = ast_value_new(ctx, "#IMMEDIATE", TYPE_FLOAT); out->cvq = CV_CONST; out->hasvalue = true; + out->isimm = true; out->constval.vfloat = d; vec_push(parser->imm_float, out); return out; @@@ -258,11 -262,12 +263,12 @@@ static ast_value* parser_const_string(p { size_t hash = util_hthash(parser->ht_imm_string, str); ast_value *out; - if ( (out = util_htgeth(parser->ht_imm_string, str, hash)) ) { + if ( (out = (ast_value*)util_htgeth(parser->ht_imm_string, str, hash)) ) { if (dotranslate && out->name[0] == '#') { char name[32]; - snprintf(name, sizeof(name), "dotranslate_%lu", (unsigned long)(parser->translated++)); + util_snprintf(name, sizeof(name), "dotranslate_%lu", (unsigned long)(parser->translated++)); ast_value_set_name(out, name); + out->expression.flags |= AST_FLAG_INCLUDE_DEF; } return out; } @@@ -274,12 -279,14 +280,14 @@@ */ if (dotranslate) { char name[32]; - snprintf(name, sizeof(name), "dotranslate_%lu", (unsigned long)(parser->translated++)); + util_snprintf(name, sizeof(name), "dotranslate_%lu", (unsigned long)(parser->translated++)); out = ast_value_new(parser_ctx(parser), name, TYPE_STRING); + out->expression.flags |= AST_FLAG_INCLUDE_DEF; } else out = ast_value_new(parser_ctx(parser), "#IMMEDIATE", TYPE_STRING); out->cvq = CV_CONST; out->hasvalue = true; + out->isimm = true; out->constval.vstring = parser_strdup(str); vec_push(parser->imm_string, out); util_htseth(parser->ht_imm_string, str, hash, out); @@@ -297,6 -304,7 +305,7 @@@ static ast_value* parser_const_vector(p out = ast_value_new(parser_ctx(parser), "#IMMEDIATE", TYPE_VECTOR); out->cvq = CV_CONST; out->hasvalue = true; + out->isimm = true; out->constval.vvec = v; vec_push(parser->imm_vector, out); return out; @@@ -580,7 -588,7 +589,7 @@@ static bool parser_sy_apply_operator(pa blocks[i] = sy->out[vec_size(sy->out)+i].block; asvalue[i] = (ast_value*)exprs[i]; - if (exprs[i]->expression.vtype == TYPE_NOEXPR && + if (exprs[i]->vtype == TYPE_NOEXPR && !(i != 0 && op->id == opid2('?',':')) && !(i == 1 && op->id == opid1('.'))) { @@@ -598,11 -606,11 +607,11 @@@ } #define NotSameType(T) \ - (exprs[0]->expression.vtype != exprs[1]->expression.vtype || \ - exprs[0]->expression.vtype != T) + (exprs[0]->vtype != exprs[1]->vtype || \ + exprs[0]->vtype != T) #define CanConstFold1(A) \ (ast_istype((A), ast_value) && ((ast_value*)(A))->hasvalue && (((ast_value*)(A))->cvq == CV_CONST) &&\ - (A)->expression.vtype != TYPE_FUNCTION) + (A)->vtype != TYPE_FUNCTION) #define CanConstFold(A, B) \ (CanConstFold1(A) && CanConstFold1(B)) #define ConstV(i) (asvalue[(i)]->constval.vvec) @@@ -615,8 -623,8 +624,8 @@@ return false; case opid1('.'): - if (exprs[0]->expression.vtype == TYPE_VECTOR && - exprs[1]->expression.vtype == TYPE_NOEXPR) + if (exprs[0]->vtype == TYPE_VECTOR && + exprs[1]->vtype == TYPE_NOEXPR) { if (exprs[1] == (ast_expression*)parser->const_vec[0]) out = (ast_expression*)ast_member_new(ctx, exprs[0], 0, NULL); @@@ -629,14 -637,14 +638,14 @@@ return false; } } - else if (exprs[0]->expression.vtype == TYPE_ENTITY) { - if (exprs[1]->expression.vtype != TYPE_FIELD) { + else if (exprs[0]->vtype == TYPE_ENTITY) { + if (exprs[1]->vtype != TYPE_FIELD) { compile_error(ast_ctx(exprs[1]), "type error: right hand of member-operand should be an entity-field"); return false; } out = (ast_expression*)ast_entfield_new(ctx, exprs[0], exprs[1]); } - else if (exprs[0]->expression.vtype == TYPE_VECTOR) { + else if (exprs[0]->vtype == TYPE_VECTOR) { compile_error(ast_ctx(exprs[1]), "vectors cannot be accessed this way"); return false; } @@@ -647,15 -655,15 +656,15 @@@ break; case opid1('['): - if (exprs[0]->expression.vtype != TYPE_ARRAY && - !(exprs[0]->expression.vtype == TYPE_FIELD && - exprs[0]->expression.next->expression.vtype == TYPE_ARRAY)) + if (exprs[0]->vtype != TYPE_ARRAY && + !(exprs[0]->vtype == TYPE_FIELD && + exprs[0]->next->vtype == TYPE_ARRAY)) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); compile_error(ast_ctx(exprs[0]), "cannot index value of type %s", ty1); return false; } - if (exprs[1]->expression.vtype != TYPE_FLOAT) { + if (exprs[1]->vtype != TYPE_FLOAT) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); compile_error(ast_ctx(exprs[1]), "index must be of type float, not %s", ty1); return false; @@@ -702,7 -710,7 +711,7 @@@ out = exprs[0]; break; case opid2('-','P'): - switch (exprs[0]->expression.vtype) { + switch (exprs[0]->vtype) { case TYPE_FLOAT: if (CanConstFold1(exprs[0])) out = (ast_expression*)parser_const_float(parser, -ConstF(0)); @@@ -722,13 -730,13 +731,13 @@@ break; default: compile_error(ctx, "invalid types used in expression: cannot negate type %s", - type_name[exprs[0]->expression.vtype]); + type_name[exprs[0]->vtype]); return false; } break; case opid2('!','P'): - switch (exprs[0]->expression.vtype) { + switch (exprs[0]->vtype) { case TYPE_FLOAT: if (CanConstFold1(exprs[0])) out = (ast_expression*)parser_const_float(parser, !ConstF(0)); @@@ -764,21 -772,21 +773,21 @@@ break; default: compile_error(ctx, "invalid types used in expression: cannot logically negate type %s", - type_name[exprs[0]->expression.vtype]); + type_name[exprs[0]->vtype]); return false; } break; case opid1('+'): - if (exprs[0]->expression.vtype != exprs[1]->expression.vtype || - (exprs[0]->expression.vtype != TYPE_VECTOR && exprs[0]->expression.vtype != TYPE_FLOAT) ) + if (exprs[0]->vtype != exprs[1]->vtype || + (exprs[0]->vtype != TYPE_VECTOR && exprs[0]->vtype != TYPE_FLOAT) ) { compile_error(ctx, "invalid types used in expression: cannot add type %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; } - switch (exprs[0]->expression.vtype) { + switch (exprs[0]->vtype) { case TYPE_FLOAT: if (CanConstFold(exprs[0], exprs[1])) { @@@ -795,21 -803,21 +804,21 @@@ break; default: compile_error(ctx, "invalid types used in expression: cannot add type %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; }; break; case opid1('-'): - if (exprs[0]->expression.vtype != exprs[1]->expression.vtype || - (exprs[0]->expression.vtype != TYPE_VECTOR && exprs[0]->expression.vtype != TYPE_FLOAT) ) + if (exprs[0]->vtype != exprs[1]->vtype || + (exprs[0]->vtype != TYPE_VECTOR && exprs[0]->vtype != TYPE_FLOAT) ) { compile_error(ctx, "invalid types used in expression: cannot subtract type %s from %s", - type_name[exprs[1]->expression.vtype], - type_name[exprs[0]->expression.vtype]); + type_name[exprs[1]->vtype], + type_name[exprs[0]->vtype]); return false; } - switch (exprs[0]->expression.vtype) { + switch (exprs[0]->vtype) { case TYPE_FLOAT: if (CanConstFold(exprs[0], exprs[1])) out = (ast_expression*)parser_const_float(parser, ConstF(0) - ConstF(1)); @@@ -824,27 -832,27 +833,27 @@@ break; default: compile_error(ctx, "invalid types used in expression: cannot subtract type %s from %s", - type_name[exprs[1]->expression.vtype], - type_name[exprs[0]->expression.vtype]); + type_name[exprs[1]->vtype], + type_name[exprs[0]->vtype]); return false; }; break; case opid1('*'): - if (exprs[0]->expression.vtype != exprs[1]->expression.vtype && - !(exprs[0]->expression.vtype == TYPE_VECTOR && - exprs[1]->expression.vtype == TYPE_FLOAT) && - !(exprs[1]->expression.vtype == TYPE_VECTOR && - exprs[0]->expression.vtype == TYPE_FLOAT) + if (exprs[0]->vtype != exprs[1]->vtype && + !(exprs[0]->vtype == TYPE_VECTOR && + exprs[1]->vtype == TYPE_FLOAT) && + !(exprs[1]->vtype == TYPE_VECTOR && + exprs[0]->vtype == TYPE_FLOAT) ) { compile_error(ctx, "invalid types used in expression: cannot multiply types %s and %s", - type_name[exprs[1]->expression.vtype], - type_name[exprs[0]->expression.vtype]); + type_name[exprs[1]->vtype], + type_name[exprs[0]->vtype]); return false; } - switch (exprs[0]->expression.vtype) { + switch (exprs[0]->vtype) { case TYPE_FLOAT: - if (exprs[1]->expression.vtype == TYPE_VECTOR) + if (exprs[1]->vtype == TYPE_VECTOR) { if (CanConstFold(exprs[0], exprs[1])) out = (ast_expression*)parser_const_vector(parser, vec3_mulvf(ConstV(1), ConstF(0))); @@@ -860,7 -868,7 +869,7 @@@ } break; case TYPE_VECTOR: - if (exprs[1]->expression.vtype == TYPE_FLOAT) + if (exprs[1]->vtype == TYPE_FLOAT) { if (CanConstFold(exprs[0], exprs[1])) out = (ast_expression*)parser_const_vector(parser, vec3_mulvf(ConstV(0), ConstF(1))); @@@ -876,7 -884,7 +885,7 @@@ if (!vec.y && !vec.z) { /* 'n 0 0' * v */ ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS]; out = (ast_expression*)ast_member_new(ctx, exprs[1], 0, NULL); - out->expression.node.keep = false; + out->node.keep = false; ((ast_member*)out)->rvalue = true; if (vec.x != 1) out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, (ast_expression*)parser_const_float(parser, vec.x), out); @@@ -884,7 -892,7 +893,7 @@@ else if (!vec.x && !vec.z) { /* '0 n 0' * v */ ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS]; out = (ast_expression*)ast_member_new(ctx, exprs[1], 1, NULL); - out->expression.node.keep = false; + out->node.keep = false; ((ast_member*)out)->rvalue = true; if (vec.y != 1) out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, (ast_expression*)parser_const_float(parser, vec.y), out); @@@ -892,7 -900,7 +901,7 @@@ else if (!vec.x && !vec.y) { /* '0 n 0' * v */ ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS]; out = (ast_expression*)ast_member_new(ctx, exprs[1], 2, NULL); - out->expression.node.keep = false; + out->node.keep = false; ((ast_member*)out)->rvalue = true; if (vec.z != 1) out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, (ast_expression*)parser_const_float(parser, vec.z), out); @@@ -905,7 -913,7 +914,7 @@@ if (!vec.y && !vec.z) { /* v * 'n 0 0' */ ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS]; out = (ast_expression*)ast_member_new(ctx, exprs[0], 0, NULL); - out->expression.node.keep = false; + out->node.keep = false; ((ast_member*)out)->rvalue = true; if (vec.x != 1) out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, out, (ast_expression*)parser_const_float(parser, vec.x)); @@@ -913,7 -921,7 +922,7 @@@ else if (!vec.x && !vec.z) { /* v * '0 n 0' */ ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS]; out = (ast_expression*)ast_member_new(ctx, exprs[0], 1, NULL); - out->expression.node.keep = false; + out->node.keep = false; ((ast_member*)out)->rvalue = true; if (vec.y != 1) out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, out, (ast_expression*)parser_const_float(parser, vec.y)); @@@ -921,7 -929,7 +930,7 @@@ else if (!vec.x && !vec.y) { /* v * '0 n 0' */ ++opts_optimizationcount[OPTIM_VECTOR_COMPONENTS]; out = (ast_expression*)ast_member_new(ctx, exprs[0], 2, NULL); - out->expression.node.keep = false; + out->node.keep = false; ((ast_member*)out)->rvalue = true; if (vec.z != 1) out = (ast_expression*)ast_binary_new(ctx, INSTR_MUL_F, out, (ast_expression*)parser_const_float(parser, vec.z)); @@@ -935,25 -943,25 +944,25 @@@ break; default: compile_error(ctx, "invalid types used in expression: cannot multiply types %s and %s", - type_name[exprs[1]->expression.vtype], - type_name[exprs[0]->expression.vtype]); + type_name[exprs[1]->vtype], + type_name[exprs[0]->vtype]); return false; }; break; case opid1('/'): - if (exprs[1]->expression.vtype != TYPE_FLOAT) { + if (exprs[1]->vtype != TYPE_FLOAT) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); ast_type_to_string(exprs[1], ty2, sizeof(ty2)); compile_error(ctx, "invalid types used in expression: cannot divide tyeps %s and %s", ty1, ty2); return false; } - if (exprs[0]->expression.vtype == TYPE_FLOAT) { + if (exprs[0]->vtype == TYPE_FLOAT) { if (CanConstFold(exprs[0], exprs[1])) out = (ast_expression*)parser_const_float(parser, ConstF(0) / ConstF(1)); else out = (ast_expression*)ast_binary_new(ctx, INSTR_DIV_F, exprs[0], exprs[1]); } - else if (exprs[0]->expression.vtype == TYPE_VECTOR) { + else if (exprs[0]->vtype == TYPE_VECTOR) { if (CanConstFold(exprs[0], exprs[1])) out = (ast_expression*)parser_const_vector(parser, vec3_mulvf(ConstV(0), 1.0/ConstF(1))); else { @@@ -983,8 -991,8 +992,8 @@@ case opid1('%'): if (NotSameType(TYPE_FLOAT)) { compile_error(ctx, "invalid types used in expression: cannot perform modulo operation between types %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; } if (CanConstFold(exprs[0], exprs[1])) { @@@ -1012,8 -1020,8 +1021,8 @@@ case opid1('&'): if (NotSameType(TYPE_FLOAT)) { compile_error(ctx, "invalid types used in expression: cannot perform bit operations between types %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; } if (CanConstFold(exprs[0], exprs[1])) @@@ -1033,9 -1041,9 +1042,9 @@@ case opid2('>','>'): if (CanConstFold(exprs[0], exprs[1]) && ! NotSameType(TYPE_FLOAT)) { if (op->id == opid2('<','<')) - out = (ast_expression*)parser_const_float(parser, (double)((int)(ConstF(0)) << (int)(ConstF(1)))); + out = (ast_expression*)parser_const_float(parser, (double)((unsigned int)(ConstF(0)) << (unsigned int)(ConstF(1)))); else - out = (ast_expression*)parser_const_float(parser, (double)((int)(ConstF(0)) >> (int)(ConstF(1)))); + out = (ast_expression*)parser_const_float(parser, (double)((unsigned int)(ConstF(0)) >> (unsigned int)(ConstF(1)))); break; } case opid3('<','<','='): @@@ -1069,7 -1077,7 +1078,7 @@@ return false; } for (i = 0; i < 2; ++i) { - if (OPTS_FLAG(CORRECT_LOGIC) && exprs[i]->expression.vtype == TYPE_VECTOR) { + if (OPTS_FLAG(CORRECT_LOGIC) && exprs[i]->vtype == TYPE_VECTOR) { out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_V, exprs[i]); if (!out) break; out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_F, out); @@@ -1080,7 -1088,7 +1089,7 @@@ break; } } - else if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && exprs[i]->expression.vtype == TYPE_STRING) { + else if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && exprs[i]->vtype == TYPE_STRING) { out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_S, exprs[i]); if (!out) break; out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_F, out); @@@ -1187,49 -1195,49 +1196,49 @@@ generated_op += INSTR_LE; if (NotSameType(TYPE_FLOAT)) { compile_error(ctx, "invalid types used in expression: cannot perform comparison between types %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; } out = (ast_expression*)ast_binary_new(ctx, generated_op, exprs[0], exprs[1]); break; case opid2('!', '='): - if (exprs[0]->expression.vtype != exprs[1]->expression.vtype) { + if (exprs[0]->vtype != exprs[1]->vtype) { compile_error(ctx, "invalid types used in expression: cannot perform comparison between types %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; } - out = (ast_expression*)ast_binary_new(ctx, type_ne_instr[exprs[0]->expression.vtype], exprs[0], exprs[1]); + out = (ast_expression*)ast_binary_new(ctx, type_ne_instr[exprs[0]->vtype], exprs[0], exprs[1]); break; case opid2('=', '='): - if (exprs[0]->expression.vtype != exprs[1]->expression.vtype) { + if (exprs[0]->vtype != exprs[1]->vtype) { compile_error(ctx, "invalid types used in expression: cannot perform comparison between types %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; } - out = (ast_expression*)ast_binary_new(ctx, type_eq_instr[exprs[0]->expression.vtype], exprs[0], exprs[1]); + out = (ast_expression*)ast_binary_new(ctx, type_eq_instr[exprs[0]->vtype], exprs[0], exprs[1]); break; case opid1('='): if (ast_istype(exprs[0], ast_entfield)) { ast_expression *field = ((ast_entfield*)exprs[0])->field; if (OPTS_FLAG(ADJUST_VECTOR_FIELDS) && - exprs[0]->expression.vtype == TYPE_FIELD && - exprs[0]->expression.next->expression.vtype == TYPE_VECTOR) + exprs[0]->vtype == TYPE_FIELD && + exprs[0]->next->vtype == TYPE_VECTOR) { assignop = type_storep_instr[TYPE_VECTOR]; } else - assignop = type_storep_instr[exprs[0]->expression.vtype]; - if (assignop == VINSTR_END || !ast_compare_type(field->expression.next, exprs[1])) + assignop = type_storep_instr[exprs[0]->vtype]; + if (assignop == VINSTR_END || !ast_compare_type(field->next, exprs[1])) { - ast_type_to_string(field->expression.next, ty1, sizeof(ty1)); + ast_type_to_string(field->next, ty1, sizeof(ty1)); ast_type_to_string(exprs[1], ty2, sizeof(ty2)); if (OPTS_FLAG(ASSIGN_FUNCTION_TYPES) && - field->expression.next->expression.vtype == TYPE_FUNCTION && - exprs[1]->expression.vtype == TYPE_FUNCTION) + field->next->vtype == TYPE_FUNCTION && + exprs[1]->vtype == TYPE_FUNCTION) { (void)!compile_warning(ctx, WARN_ASSIGN_FUNCTION_TYPES, "invalid types in assignment: cannot assign %s to %s", ty2, ty1); @@@ -1241,13 -1249,13 +1250,13 @@@ else { if (OPTS_FLAG(ADJUST_VECTOR_FIELDS) && - exprs[0]->expression.vtype == TYPE_FIELD && - exprs[0]->expression.next->expression.vtype == TYPE_VECTOR) + exprs[0]->vtype == TYPE_FIELD && + exprs[0]->next->vtype == TYPE_VECTOR) { assignop = type_store_instr[TYPE_VECTOR]; } else { - assignop = type_store_instr[exprs[0]->expression.vtype]; + assignop = type_store_instr[exprs[0]->vtype]; } if (assignop == VINSTR_END) { @@@ -1260,8 -1268,8 +1269,8 @@@ ast_type_to_string(exprs[0], ty1, sizeof(ty1)); ast_type_to_string(exprs[1], ty2, sizeof(ty2)); if (OPTS_FLAG(ASSIGN_FUNCTION_TYPES) && - exprs[0]->expression.vtype == TYPE_FUNCTION && - exprs[1]->expression.vtype == TYPE_FUNCTION) + exprs[0]->vtype == TYPE_FUNCTION && + exprs[1]->vtype == TYPE_FUNCTION) { (void)!compile_warning(ctx, WARN_ASSIGN_FUNCTION_TYPES, "invalid types in assignment: cannot assign %s to %s", ty2, ty1); @@@ -1278,7 -1286,7 +1287,7 @@@ case opid3('+','+','P'): case opid3('-','-','P'): /* prefix ++ */ - if (exprs[0]->expression.vtype != TYPE_FLOAT) { + if (exprs[0]->vtype != TYPE_FLOAT) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); compile_error(ast_ctx(exprs[0]), "invalid type for prefix increment: %s", ty1); return false; @@@ -1303,7 -1311,7 +1312,7 @@@ case opid3('S','+','+'): case opid3('S','-','-'): /* prefix ++ */ - if (exprs[0]->expression.vtype != TYPE_FLOAT) { + if (exprs[0]->vtype != TYPE_FLOAT) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); compile_error(ast_ctx(exprs[0]), "invalid type for suffix increment: %s", ty1); return false; @@@ -1335,8 -1343,8 +1344,8 @@@ break; case opid2('+','='): case opid2('-','='): - if (exprs[0]->expression.vtype != exprs[1]->expression.vtype || - (exprs[0]->expression.vtype != TYPE_VECTOR && exprs[0]->expression.vtype != TYPE_FLOAT) ) + if (exprs[0]->vtype != exprs[1]->vtype || + (exprs[0]->vtype != TYPE_VECTOR && exprs[0]->vtype != TYPE_FLOAT) ) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); ast_type_to_string(exprs[1], ty2, sizeof(ty2)); @@@ -1348,10 -1356,10 +1357,10 @@@ compile_error(ctx, "assignment to constant `%s`", asvalue[0]->name); } if (ast_istype(exprs[0], ast_entfield)) - assignop = type_storep_instr[exprs[0]->expression.vtype]; + assignop = type_storep_instr[exprs[0]->vtype]; else - assignop = type_store_instr[exprs[0]->expression.vtype]; - switch (exprs[0]->expression.vtype) { + assignop = type_store_instr[exprs[0]->vtype]; + switch (exprs[0]->vtype) { case TYPE_FLOAT: out = (ast_expression*)ast_binstore_new(ctx, assignop, (op->id == opid2('+','=') ? INSTR_ADD_F : INSTR_SUB_F), @@@ -1364,16 -1372,16 +1373,16 @@@ break; default: compile_error(ctx, "invalid types used in expression: cannot add or subtract type %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; }; break; case opid2('*','='): case opid2('/','='): - if (exprs[1]->expression.vtype != TYPE_FLOAT || - !(exprs[0]->expression.vtype == TYPE_FLOAT || - exprs[0]->expression.vtype == TYPE_VECTOR)) + if (exprs[1]->vtype != TYPE_FLOAT || + !(exprs[0]->vtype == TYPE_FLOAT || + exprs[0]->vtype == TYPE_VECTOR)) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); ast_type_to_string(exprs[1], ty2, sizeof(ty2)); @@@ -1385,10 -1393,10 +1394,10 @@@ compile_error(ctx, "assignment to constant `%s`", asvalue[0]->name); } if (ast_istype(exprs[0], ast_entfield)) - assignop = type_storep_instr[exprs[0]->expression.vtype]; + assignop = type_storep_instr[exprs[0]->vtype]; else - assignop = type_store_instr[exprs[0]->expression.vtype]; - switch (exprs[0]->expression.vtype) { + assignop = type_store_instr[exprs[0]->vtype]; + switch (exprs[0]->vtype) { case TYPE_FLOAT: out = (ast_expression*)ast_binstore_new(ctx, assignop, (op->id == opid2('*','=') ? INSTR_MUL_F : INSTR_DIV_F), @@@ -1417,8 -1425,8 +1426,8 @@@ break; default: compile_error(ctx, "invalid types used in expression: cannot add or subtract type %s and %s", - type_name[exprs[0]->expression.vtype], - type_name[exprs[1]->expression.vtype]); + type_name[exprs[0]->vtype], + type_name[exprs[1]->vtype]); return false; }; break; @@@ -1435,9 -1443,9 +1444,9 @@@ compile_error(ctx, "assignment to constant `%s`", asvalue[0]->name); } if (ast_istype(exprs[0], ast_entfield)) - assignop = type_storep_instr[exprs[0]->expression.vtype]; + assignop = type_storep_instr[exprs[0]->vtype]; else - assignop = type_store_instr[exprs[0]->expression.vtype]; + assignop = type_store_instr[exprs[0]->vtype]; out = (ast_expression*)ast_binstore_new(ctx, assignop, (op->id == opid2('&','=') ? INSTR_BITAND : INSTR_BITOR), exprs[0], exprs[1]); @@@ -1455,9 -1463,9 +1464,9 @@@ return false; } if (ast_istype(exprs[0], ast_entfield)) - assignop = type_storep_instr[exprs[0]->expression.vtype]; + assignop = type_storep_instr[exprs[0]->vtype]; else - assignop = type_store_instr[exprs[0]->expression.vtype]; + assignop = type_store_instr[exprs[0]->vtype]; out = (ast_expression*)ast_binary_new(ctx, INSTR_BITAND, exprs[0], exprs[1]); if (!out) return false; @@@ -1470,7 -1478,7 +1479,7 @@@ break; case opid2('~', 'P'): - if (exprs[0]->expression.vtype != TYPE_FLOAT) { + if (exprs[0]->vtype != TYPE_FLOAT) { ast_type_to_string(exprs[0], ty1, sizeof(ty1)); compile_error(ast_ctx(exprs[0]), "invalid type for bit not: %s", ty1); return false; @@@ -1566,7 -1574,7 +1575,7 @@@ static bool parser_close_call(parser_t if (ast_istype(fun, ast_value)) { funval = (ast_value*)fun; - if ((fun->expression.flags & AST_FLAG_VARIADIC) && + if ((fun->flags & AST_FLAG_VARIADIC) && !(/*funval->cvq == CV_CONST && */ funval->hasvalue && funval->constval.vfunc->builtin)) { call->va_count = (ast_expression*)parser_const_float(parser, (double)paramcount); @@@ -1576,18 -1584,18 +1585,18 @@@ /* overwrite fid, the function, with a call */ sy->out[fid] = syexp(call->expression.node.context, (ast_expression*)call); - if (fun->expression.vtype != TYPE_FUNCTION) { - parseerror(parser, "not a function (%s)", type_name[fun->expression.vtype]); + if (fun->vtype != TYPE_FUNCTION) { + parseerror(parser, "not a function (%s)", type_name[fun->vtype]); return false; } - if (!fun->expression.next) { + if (!fun->next) { parseerror(parser, "could not determine function return type"); return false; } else { ast_value *fval = (ast_istype(fun, ast_value) ? ((ast_value*)fun) : NULL); - if (fun->expression.flags & AST_FLAG_DEPRECATED) { + if (fun->flags & AST_FLAG_DEPRECATED) { if (!fval) { return !parsewarning(parser, WARN_DEPRECATED, "call to function (which is marked deprecated)\n", @@@ -1607,22 -1615,22 +1616,22 @@@ ast_ctx(fun).line); } - if (vec_size(fun->expression.params) != paramcount && - !((fun->expression.flags & AST_FLAG_VARIADIC) && - vec_size(fun->expression.params) < paramcount)) + if (vec_size(fun->params) != paramcount && + !((fun->flags & AST_FLAG_VARIADIC) && + vec_size(fun->params) < paramcount)) { - const char *fewmany = (vec_size(fun->expression.params) > paramcount) ? "few" : "many"; + const char *fewmany = (vec_size(fun->params) > paramcount) ? "few" : "many"; if (fval) return !parsewarning(parser, WARN_INVALID_PARAMETER_COUNT, "too %s parameters for call to %s: expected %i, got %i\n" " -> `%s` has been declared here: %s:%i", - fewmany, fval->name, (int)vec_size(fun->expression.params), (int)paramcount, + fewmany, fval->name, (int)vec_size(fun->params), (int)paramcount, fval->name, ast_ctx(fun).file, (int)ast_ctx(fun).line); else return !parsewarning(parser, WARN_INVALID_PARAMETER_COUNT, "too %s parameters for function call: expected %i, got %i\n" " -> it has been declared here: %s:%i", - fewmany, (int)vec_size(fun->expression.params), (int)paramcount, + fewmany, (int)vec_size(fun->params), (int)paramcount, ast_ctx(fun).file, (int)ast_ctx(fun).line); } } @@@ -1682,6 -1690,8 +1691,8 @@@ static bool parser_close_paren(parser_ static void parser_reclassify_token(parser_t *parser) { size_t i; + if (parser->tok >= TOKEN_START) + return; for (i = 0; i < operator_count; ++i) { if (!strcmp(parser_tokval(parser), operators[i].op)) { parser->tok = TOKEN_OPERATOR; @@@ -1783,6 -1793,9 +1794,9 @@@ static ast_expression* parse_vararg(par return out; } + /* not to be exposed */ + extern bool ftepp_predef_exists(const char *name); + static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels) { if (OPTS_FLAG(TRANSLATABLE_STRINGS) && @@@ -1873,7 -1886,7 +1887,7 @@@ /* When adding more intrinsics, fix the above condition */ prev = NULL; } - if (prev && prev->expression.vtype == TYPE_VECTOR && ctoken[0] >= 'x' && ctoken[0] <= 'z' && !ctoken[1]) + if (prev && prev->vtype == TYPE_VECTOR && ctoken[0] >= 'x' && ctoken[0] <= 'z' && !ctoken[1]) { var = (ast_expression*)parser->const_vec[ctoken[0]-'x']; } else { @@@ -1889,6 -1902,8 +1903,8 @@@ vec_push(parser->labels, lbl); } } + if (!var && !strcmp(parser_tokval(parser), "__FUNC__")) + var = (ast_expression*)parser_const_string(parser, parser->function->name, false); if (!var) { /* intrinsics */ if (!strcmp(parser_tokval(parser), "__builtin_debug_typestring")) { @@@ -1900,10 -1915,8 +1916,8 @@@ */ else if (!strncmp(parser_tokval(parser), "__builtin_", 10)) { var = intrin_func(parser, parser_tokval(parser) + 10 /* skip __builtin */); - } else { - var = intrin_func(parser, parser_tokval(parser)); } - + if (!var) { char *correct = NULL; size_t i; @@@ -1913,13 -1926,9 +1927,9 @@@ * i've done this thousands of times already myself. Lets check for * it in the predef table. And diagnose it better :) */ - if (!OPTS_FLAG(FTEPP_PREDEFS)) { - for (i = 0; i < sizeof(ftepp_predefs)/sizeof(*ftepp_predefs); i++) { - if (!strcmp(ftepp_predefs[i].name, parser_tokval(parser))) { - parseerror(parser, "unexpected ident: %s (use -fftepp-predef to enable pre-defined macros)", parser_tokval(parser)); - return false; - } - } + if (!OPTS_FLAG(FTEPP_PREDEFS) && ftepp_predef_exists(parser_tokval(parser))) { + parseerror(parser, "unexpected ident: %s (use -fftepp-predef to enable pre-defined macros)", parser_tokval(parser)); + return false; } /* @@@ -1929,7 -1938,7 +1939,7 @@@ * We should also consider adding correction tables for * other things as well. */ - if (OPTS_OPTION_BOOL(OPTION_CORRECTION)) { + if (OPTS_OPTION_BOOL(OPTION_CORRECTION) && strlen(parser_tokval(parser)) <= 16) { correction_t corr; correct_init(&corr); @@@ -2183,8 -2192,27 +2193,27 @@@ static ast_expression* parse_expression wantop = true; } else { - parseerror(parser, "expected operator or end of statement"); - goto onerr; + /* in this case we might want to allow constant string concatenation */ + bool concatenated = false; + if (parser->tok == TOKEN_STRINGCONST && vec_size(sy.out)) { + ast_expression *lexpr = vec_last(sy.out).out; + if (ast_istype(lexpr, ast_value)) { + ast_value *last = (ast_value*)lexpr; + if (last->isimm == true && last->cvq == CV_CONST && + last->hasvalue && last->expression.vtype == TYPE_STRING) + { + char *newstr = NULL; + util_asprintf(&newstr, "%s%s", last->constval.vstring, parser_tokval(parser)); + vec_last(sy.out).out = (ast_expression*)parser_const_string(parser, newstr, false); + mem_d(newstr); + concatenated = true; + } + } + } + if (!concatenated) { + parseerror(parser, "expected operator or end of statement"); + goto onerr; + } } if (!parser_next(parser)) { @@@ -2204,8 -2232,8 +2233,8 @@@ } parser->lex->flags.noops = true; - if (!vec_size(sy.out)) { - parseerror(parser, "empty expression"); + if (vec_size(sy.out) != 1) { + parseerror(parser, "expression with not 1 but %lu output values...", (unsigned long) vec_size(sy.out)); expr = NULL; } else expr = sy.out[0].out; @@@ -2340,13 -2368,13 +2369,13 @@@ static ast_expression* process_conditio ast_unary *unary; ast_expression *prev; - if (cond->expression.vtype == TYPE_VOID || cond->expression.vtype >= TYPE_VARIANT) { + if (cond->vtype == TYPE_VOID || cond->vtype >= TYPE_VARIANT) { char ty[1024]; ast_type_to_string(cond, ty, sizeof(ty)); compile_error(ast_ctx(cond), "invalid type for if() condition: %s", ty); } - if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && cond->expression.vtype == TYPE_STRING) + if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && cond->vtype == TYPE_STRING) { prev = cond; cond = (ast_expression*)ast_unary_new(ast_ctx(cond), INSTR_NOT_S, cond); @@@ -2357,7 -2385,7 +2386,7 @@@ } ifnot = !ifnot; } - else if (OPTS_FLAG(CORRECT_LOGIC) && cond->expression.vtype == TYPE_VECTOR) + else if (OPTS_FLAG(CORRECT_LOGIC) && cond->vtype == TYPE_VECTOR) { /* vector types need to be cast to true booleans */ ast_binary *bin = (ast_binary*)cond; @@@ -2430,17 -2458,17 +2459,17 @@@ static bool parse_if(parser_t *parser, /* closing paren */ if (parser->tok != ')') { parseerror(parser, "expected closing paren after 'if' condition"); - ast_delete(cond); + ast_unref(cond); return false; } /* parse into the 'then' branch */ if (!parser_next(parser)) { parseerror(parser, "expected statement for on-true branch of 'if'"); - ast_delete(cond); + ast_unref(cond); return false; } if (!parse_statement_or_block(parser, &ontrue)) { - ast_delete(cond); + ast_unref(cond); return false; } if (!ontrue) @@@ -2451,12 -2479,12 +2480,12 @@@ if (!parser_next(parser)) { parseerror(parser, "expected on-false branch after 'else'"); ast_delete(ontrue); - ast_delete(cond); + ast_unref(cond); return false; } if (!parse_statement_or_block(parser, &onfalse)) { ast_delete(ontrue); - ast_delete(cond); + ast_unref(cond); return false; } } @@@ -2553,23 -2581,23 +2582,23 @@@ static bool parse_while_go(parser_t *pa /* closing paren */ if (parser->tok != ')') { parseerror(parser, "expected closing paren after 'while' condition"); - ast_delete(cond); + ast_unref(cond); return false; } /* parse into the 'then' branch */ if (!parser_next(parser)) { parseerror(parser, "expected while-loop body"); - ast_delete(cond); + ast_unref(cond); return false; } if (!parse_statement_or_block(parser, &ontrue)) { - ast_delete(cond); + ast_unref(cond); return false; } cond = process_condition(parser, cond, &ifnot); if (!cond) { - ast_delete(ontrue); + ast_unref(ontrue); return false; } aloop = ast_loop_new(ctx, NULL, cond, ifnot, NULL, false, NULL, ontrue); @@@ -2669,21 -2697,21 +2698,21 @@@ static bool parse_dowhile_go(parser_t * if (parser->tok != ')') { parseerror(parser, "expected closing paren after 'while' condition"); ast_delete(ontrue); - ast_delete(cond); + ast_unref(cond); return false; } /* parse on */ if (!parser_next(parser) || parser->tok != ';') { parseerror(parser, "expected semicolon after condition"); ast_delete(ontrue); - ast_delete(cond); + ast_unref(cond); return false; } if (!parser_next(parser)) { parseerror(parser, "parse error"); ast_delete(ontrue); - ast_delete(cond); + ast_unref(cond); return false; } @@@ -2756,7 -2784,6 +2785,6 @@@ static bool parse_for_go(parser_t *pars ast_expression *initexpr, *cond, *increment, *ontrue; ast_value *typevar; - bool retval = true; bool ifnot = false; lex_ctx ctx = parser_ctx(parser); @@@ -2856,21 -2883,25 +2884,25 @@@ aloop = ast_loop_new(ctx, initexpr, cond, ifnot, NULL, false, increment, ontrue); *out = (ast_expression*)aloop; - if (!parser_leaveblock(parser)) - retval = false; - return retval; + if (!parser_leaveblock(parser)) { + ast_delete(aloop); + return false; + } + return true; onerr: - if (initexpr) ast_delete(initexpr); - if (cond) ast_delete(cond); - if (increment) ast_delete(increment); + if (initexpr) ast_unref(initexpr); + if (cond) ast_unref(cond); + if (increment) ast_unref(increment); (void)!parser_leaveblock(parser); return false; } static bool parse_return(parser_t *parser, ast_block *block, ast_expression **out) { - ast_expression *exp = NULL; - ast_return *ret = NULL; + ast_expression *exp = NULL; + ast_expression *var = NULL; + ast_return *ret = NULL; + ast_value *retval = parser->function->return_value; ast_value *expected = parser->function->vtype; lex_ctx ctx = parser_ctx(parser); @@@ -2882,29 -2913,87 +2914,87 @@@ return false; } + /* return assignments */ + if (parser->tok == '=') { + if (!OPTS_FLAG(RETURN_ASSIGNMENTS)) { + parseerror(parser, "return assignments not activated, try using -freturn-assigments"); + return false; + } + + if (type_store_instr[expected->expression.next->vtype] == VINSTR_END) { + char ty1[1024]; + ast_type_to_string(expected->expression.next, ty1, sizeof(ty1)); + parseerror(parser, "invalid return type: `%s'", ty1); + return false; + } + + if (!parser_next(parser)) { + parseerror(parser, "expected return assignment expression"); + return false; + } + + if (!(exp = parse_expression_leave(parser, false, false, false))) + return false; + + /* prepare the return value */ + if (!retval) { + retval = ast_value_new(ctx, "#LOCAL_RETURN", TYPE_VOID); + ast_type_adopt(retval, expected->expression.next); + parser->function->return_value = retval; + } + + if (!ast_compare_type(exp, (ast_expression*)retval)) { + char ty1[1024], ty2[1024]; + ast_type_to_string(exp, ty1, sizeof(ty1)); + ast_type_to_string(&retval->expression, ty2, sizeof(ty2)); + parseerror(parser, "invalid type for return value: `%s', expected `%s'", ty1, ty2); + } + + /* store to 'return' local variable */ + var = (ast_expression*)ast_store_new( + ctx, + type_store_instr[expected->expression.next->vtype], + (ast_expression*)retval, exp); + + if (!var) { + ast_unref(exp); + return false; + } + + if (parser->tok != ';') + parseerror(parser, "missing semicolon after return assignment"); + else if (!parser_next(parser)) + parseerror(parser, "parse error after return assignment"); + + *out = var; + return true; + } + if (parser->tok != ';') { exp = parse_expression(parser, false, false); if (!exp) return false; - if (exp->expression.vtype != TYPE_NIL && - exp->expression.vtype != expected->expression.next->expression.vtype) + if (exp->vtype != TYPE_NIL && + exp->vtype != ((ast_expression*)expected)->next->vtype) { parseerror(parser, "return with invalid expression"); } ret = ast_return_new(ctx, exp); if (!ret) { - ast_delete(exp); + ast_unref(exp); return false; } } else { if (!parser_next(parser)) parseerror(parser, "parse error"); - if (expected->expression.next->expression.vtype != TYPE_VOID) { + + if (!retval && expected->expression.next->vtype != TYPE_VOID) + { (void)!parsewarning(parser, WARN_MISSING_RETURN_VALUES, "return without value"); } - ret = ast_return_new(ctx, NULL); + ret = ast_return_new(ctx, (ast_expression*)retval); } *out = (ast_expression*)ret; return true; @@@ -3652,7 -3741,7 +3742,7 @@@ static bool parse_statement(parser_t *p } return parse_typedef(parser); } - parseerror(parser, "Unexpected keyword"); + parseerror(parser, "Unexpected keyword: `%s'", parser_tokval(parser)); return false; } else if (parser->tok == '{') @@@ -4043,9 -4132,9 +4133,9 @@@ static bool parse_function_body(parser_ /* qc allows the use of not-yet-declared functions here * - this automatically creates a prototype */ ast_value *thinkfunc; - ast_expression *functype = fld_think->expression.next; + ast_expression *functype = fld_think->next; - thinkfunc = ast_value_new(parser_ctx(parser), parser_tokval(parser), functype->expression.vtype); + thinkfunc = ast_value_new(parser_ctx(parser), parser_tokval(parser), functype->vtype); if (!thinkfunc) { /* || !ast_type_adopt(thinkfunc, functype)*/ ast_unref(framenum); parseerror(parser, "failed to create implicit prototype for `%s`", parser_tokval(parser)); @@@ -4200,7 -4289,7 +4290,7 @@@ if (param->expression.vtype != TYPE_VECTOR && (param->expression.vtype != TYPE_FIELD || - param->expression.next->expression.vtype != TYPE_VECTOR)) + param->expression.next->vtype != TYPE_VECTOR)) { continue; } @@@ -4228,13 -4317,13 +4318,13 @@@ varargs->expression.flags |= AST_FLAG_IS_VARARG; varargs->expression.next = (ast_expression*)ast_value_new(ast_ctx(var), NULL, TYPE_VECTOR); varargs->expression.count = 0; - snprintf(name, sizeof(name), "%s##va##SET", var->name); + util_snprintf(name, sizeof(name), "%s##va##SET", var->name); if (!parser_create_array_setter_proto(parser, varargs, name)) { ast_delete(varargs); ast_block_delete(block); goto enderrfn; } - snprintf(name, sizeof(name), "%s##va##GET", var->name); + util_snprintf(name, sizeof(name), "%s##va##GET", var->name); if (!parser_create_array_getter_proto(parser, varargs, varargs->expression.next, name)) { ast_delete(varargs); ast_block_delete(block); @@@ -4252,6 -4341,7 +4342,7 @@@ } vec_push(func->blocks, block); + parser->function = old; if (!parser_leaveblock(parser)) @@@ -4330,7 -4420,7 +4421,7 @@@ static ast_expression *array_setter_nod ast_store *st; int assignop = type_store_instr[value->expression.vtype]; - if (value->expression.vtype == TYPE_FIELD && value->expression.next->expression.vtype == TYPE_VECTOR) + if (value->expression.vtype == TYPE_FIELD && value->expression.next->vtype == TYPE_VECTOR) assignop = INSTR_STORE_V; subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)parser_const_float(parser, from)); @@@ -4396,7 -4486,7 +4487,7 @@@ static ast_expression *array_field_sett ast_store *st; int assignop = type_storep_instr[value->expression.vtype]; - if (value->expression.vtype == TYPE_FIELD && value->expression.next->expression.vtype == TYPE_VECTOR) + if (value->expression.vtype == TYPE_FIELD && value->expression.next->vtype == TYPE_VECTOR) assignop = INSTR_STOREP_V; subscript = ast_array_index_new(ctx, (ast_expression*)array, (ast_expression*)parser_const_float(parser, from)); @@@ -4706,6 -4796,7 +4797,7 @@@ static ast_value *parse_parameter_list( /* for the sake of less code we parse-in in this function */ if (!parser_next(parser)) { + ast_delete(var); parseerror(parser, "expected parameter list"); return NULL; } @@@ -4973,6 -5064,7 +5065,7 @@@ static ast_value *parse_typename(parser /* parse on */ if (!parser_next(parser)) { ast_delete(var); + mem_d(name); parseerror(parser, "error after variable or field declaration"); return NULL; } @@@ -4982,8 -5074,10 +5075,10 @@@ if (parser->tok == '[') { wasarray = true; var = parse_arraysize(parser, var); - if (!var) + if (!var) { + if (name) mem_d(name); return NULL; + } } /* This is the point where we can turn it into a field */ @@@ -5002,8 -5096,7 +5097,7 @@@ while (parser->tok == '(') { var = parse_parameter_list(parser, var); if (!var) { - if (name) - mem_d((void*)name); + if (name) mem_d(name); return NULL; } } @@@ -5012,11 -5105,12 +5106,12 @@@ if (name) { if (!ast_value_set_name(var, name)) { ast_delete(var); + mem_d(name); parseerror(parser, "internal error: failed to set name"); return NULL; } /* free the name, ast_value_set_name duplicates */ - mem_d((void*)name); + mem_d(name); } return var; @@@ -5115,7 -5209,7 +5210,7 @@@ static bool parse_variable(parser_t *pa bool cleanvar = true; bool wasarray = false; - ast_member *me[3]; + ast_member *me[3] = { NULL, NULL, NULL }; if (!localblock && is_static) parseerror(parser, "`static` qualifier is not supported in global scope"); @@@ -5172,7 -5266,7 +5267,7 @@@ /* * store the vstring back to var for alias and * deprecation messages. - */ + */ if (var->expression.flags & AST_FLAG_DEPRECATED || var->expression.flags & AST_FLAG_ALIAS) var->desc = vstring; @@@ -5247,7 -5341,7 +5342,7 @@@ { /* deal with other globals */ old = parser_find_global(parser, var->name); - if (old && var->expression.vtype == TYPE_FUNCTION && old->expression.vtype == TYPE_FUNCTION) + if (old && var->expression.vtype == TYPE_FUNCTION && old->vtype == TYPE_FUNCTION) { /* This is a function which had a prototype */ if (!ast_istype(old, ast_value)) { @@@ -5269,7 -5363,7 +5364,7 @@@ ast_value_set_name(proto->expression.params[i], var->expression.params[i]->name); if (!parser_check_qualifiers(parser, var, proto)) { retval = false; - if (proto->desc) + if (proto->desc) mem_d(proto->desc); proto = NULL; goto cleanup; @@@ -5355,7 -5449,7 +5450,7 @@@ if (var->expression.vtype == TYPE_VECTOR) isvector = true; else if (var->expression.vtype == TYPE_FIELD && - var->expression.next->expression.vtype == TYPE_VECTOR) + var->expression.next->vtype == TYPE_VECTOR) isvector = true; if (isvector) { @@@ -5394,7 -5488,7 +5489,7 @@@ return false; } - if (var->expression.vtype != find->expression.vtype) { + if (var->expression.vtype != find->vtype) { char ty1[1024]; char ty2[1024]; @@@ -5410,13 -5504,13 +5505,13 @@@ /* * add alias to aliases table and to corrector * so corrections can apply for aliases as well. - */ + */ util_htset(parser->aliases, var->name, find); /* * add to corrector so corrections can work * even for aliases too. - */ + */ correct_add ( vec_last(parser->correct_variables), &vec_last(parser->correct_variables_score), @@@ -5442,7 -5536,7 +5537,7 @@@ /* * add to corrector so corrections can work * even for aliases too. - */ + */ correct_add ( vec_last(parser->correct_variables), &vec_last(parser->correct_variables_score), @@@ -5534,16 -5628,16 +5629,16 @@@ */ if (var->expression.vtype == TYPE_ARRAY) { char name[1024]; - snprintf(name, sizeof(name), "%s##SET", var->name); + util_snprintf(name, sizeof(name), "%s##SET", var->name); if (!parser_create_array_setter(parser, var, name)) goto cleanup; - snprintf(name, sizeof(name), "%s##GET", var->name); + util_snprintf(name, sizeof(name), "%s##GET", var->name); if (!parser_create_array_getter(parser, var, var->expression.next, name)) goto cleanup; } else if (!localblock && !nofields && var->expression.vtype == TYPE_FIELD && - var->expression.next->expression.vtype == TYPE_ARRAY) + var->expression.next->vtype == TYPE_ARRAY) { char name[1024]; ast_expression *telem; @@@ -5555,14 -5649,14 +5650,14 @@@ goto cleanup; } - snprintf(name, sizeof(name), "%s##SETF", var->name); + util_snprintf(name, sizeof(name), "%s##SETF", var->name); if (!parser_create_array_field_setter(parser, array, name)) goto cleanup; telem = ast_type_copy(ast_ctx(var), array->expression.next); tfield = ast_value_new(ast_ctx(var), "<.type>", TYPE_FIELD); tfield->expression.next = telem; - snprintf(name, sizeof(name), "%s##GETFP", var->name); + util_snprintf(name, sizeof(name), "%s##GETFP", var->name); if (!parser_create_array_getter(parser, array, (ast_expression*)tfield, name)) { ast_delete(tfield); goto cleanup; @@@ -5600,10 -5694,18 +5695,18 @@@ skipvar } } - if (parser->tok != '{') { + if (parser->tok != '{' || var->expression.vtype != TYPE_FUNCTION) { if (parser->tok != '=') { - parseerror(parser, "missing semicolon or initializer, got: `%s`", parser_tokval(parser)); - break; + if (!strcmp(parser_tokval(parser), "break")) { + if (!parser_next(parser)) { + parseerror(parser, "error parsing break definition"); + break; + } + (void)!!parsewarning(parser, WARN_BREAKDEF, "break definition ignored (suggest removing it)"); + } else { + parseerror(parser, "missing semicolon or initializer, got: `%s`", parser_tokval(parser)); + break; + } } if (!parser_next(parser)) { @@@ -5616,7 -5718,11 +5719,11 @@@ } if (parser->tok == '#') { - ast_function *func = NULL; + ast_function *func = NULL; + ast_value *number = NULL; + float fractional; + float integral; + int builtin_num; if (localblock) { parseerror(parser, "cannot declare builtins within functions"); @@@ -5630,12 -5736,42 +5737,42 @@@ parseerror(parser, "expected builtin number"); break; } - if (parser->tok != TOKEN_INTCONST) { - parseerror(parser, "builtin number must be an integer constant"); - break; - } - if (parser_token(parser)->constval.i < 0) { - parseerror(parser, "builtin number must be an integer greater than zero"); + + if (OPTS_FLAG(EXPRESSIONS_FOR_BUILTINS)) { + number = (ast_value*)parse_expression_leave(parser, true, false, false); + if (!number) { + parseerror(parser, "builtin number expected"); + break; + } + if (!ast_istype(number, ast_value) || !number->hasvalue || number->cvq != CV_CONST) + { + ast_unref(number); + parseerror(parser, "builtin number must be a compile time constant"); + break; + } + if (number->expression.vtype == TYPE_INTEGER) + builtin_num = number->constval.vint; + else if (number->expression.vtype == TYPE_FLOAT) + builtin_num = number->constval.vfloat; + else { + ast_unref(number); + parseerror(parser, "builtin number must be an integer constant"); + break; + } + ast_unref(number); + + fractional = modff(builtin_num, &integral); + if (builtin_num < 0 || fractional != 0) { + parseerror(parser, "builtin number must be an integer greater than zero"); + break; + } + + /* we only want the integral part anyways */ + builtin_num = integral; + } else if (parser->tok == TOKEN_INTCONST) { + builtin_num = parser_token(parser)->constval.i; + } else { + parseerror(parser, "builtin number must be a compile time constant"); break; } @@@ -5654,10 -5790,13 +5791,13 @@@ } vec_push(parser->functions, func); - func->builtin = -parser_token(parser)->constval.i-1; + func->builtin = -builtin_num-1; } - if (!parser_next(parser)) { + if (OPTS_FLAG(EXPRESSIONS_FOR_BUILTINS) + ? (parser->tok != ',' && parser->tok != ';') + : (!parser_next(parser))) + { parseerror(parser, "expected comma or semicolon"); if (func) ast_function_delete(func); @@@ -5665,7 -5804,22 +5805,22 @@@ break; } } - else if (parser->tok == '{' || parser->tok == '[') + else if (var->expression.vtype == TYPE_ARRAY && parser->tok == '{') + { + if (localblock) { + /* Note that fteqcc and most others don't even *have* + * local arrays, so this is not a high priority. + */ + parseerror(parser, "TODO: initializers for local arrays"); + break; + } + /* + static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma, bool truthvalue, bool with_labels); + */ + parseerror(parser, "TODO: initializing global arrays is not supported yet!"); + break; + } + else if (var->expression.vtype == TYPE_FUNCTION && (parser->tok == '{' || parser->tok == '[')) { if (localblock) { parseerror(parser, "cannot declare functions within functions"); @@@ -5738,6 -5892,7 +5893,7 @@@ } vec_free(sy.out); vec_free(sy.ops); + vec_free(sy.argc); var->cvq = cvq; } } @@@ -5908,7 -6063,7 +6064,7 @@@ static void generate_checksum(parser_t if (!ast_istype(parser->fields[i], ast_value)) continue; value = (ast_value*)(parser->fields[i]); - switch (value->expression.next->expression.vtype) { + switch (value->expression.next->vtype) { case TYPE_FLOAT: crc = progdefs_crc_both(crc, "\tfloat\t"); break; case TYPE_VECTOR: crc = progdefs_crc_both(crc, "\tvec3_t\t"); break; case TYPE_STRING: crc = progdefs_crc_both(crc, "\tstring_t\t"); break; @@@ -5922,7 -6077,7 +6078,7 @@@ } crc = progdefs_crc_both(crc, "} entvars_t;\n\n"); - code_crc = crc; + parser->code->crc = crc; } parser_t *parser_create() @@@ -5937,6 -6092,11 +6093,11 @@@ memset(parser, 0, sizeof(*parser)); + if (!(parser->code = code_init())) { + mem_d(parser); + return NULL; + } + for (i = 0; i < operator_count; ++i) { if (operators[i].id == opid1('=')) { parser->assign_op = operators+i; @@@ -5988,7 -6148,7 +6149,7 @@@ return parser; } - bool parser_compile(parser_t *parser) + static bool parser_compile(parser_t *parser) { /* initial lexer/parser state */ parser->lex->flags.noops = true; @@@ -6040,9 -6200,12 +6201,12 @@@ bool parser_compile_string(parser_t *pa return parser_compile(parser); } - void parser_cleanup(parser_t *parser) + static void parser_remove_ast(parser_t *parser) { size_t i; + if (parser->ast_cleaned) + return; + parser->ast_cleaned = true; for (i = 0; i < vec_size(parser->accessors); ++i) { ast_delete(parser->accessors[i]->constval.vfunc); parser->accessors[i]->constval.vfunc = NULL; @@@ -6111,96 -6274,17 +6275,96 @@@ ast_value_delete(parser->const_vec[2]); util_htdel(parser->aliases); - intrin_intrinsics_destroy(parser); + } + + void parser_cleanup(parser_t *parser) + { + parser_remove_ast(parser); + code_cleanup(parser->code); mem_d(parser); } +static void function_finalize_worker_do(ast_function **list, size_t count, volatile uint32_t *counter, bool *failure) +{ + do { + uint32_t idx = util_atomic_xadd32(counter, 1); + if (idx >= count) { + *counter = count; + return; + } + if (!ir_function_finalize(list[idx]->ir_func)) { + con_out("failed to finalize function %s\n", list[idx]->name); + *failure = true; + return; + } + } while (true); +} + +typedef struct { + ast_function **list; + size_t count; + volatile uint32_t *counter; + bool *failure; +} function_finalize_worker_data; +static void* function_finalize_worker(void *_d) { + function_finalize_worker_data *d = (function_finalize_worker_data*)_d; + function_finalize_worker_do(d->list, d->count, d->counter, d->failure); + return NULL; +} + +static bool function_finalize_all_threaded(ast_function **list, size_t count) +{ + volatile uint32_t counter = 0; + function_finalize_worker_data wd; + + size_t poolsize = OPTS_OPTION_U32(OPTION_J); + bool failure = false; + size_t i, j; + + pthread_t *threads; + + if (!list || !count) + return true; + + wd.list = list; + wd.count = count; + wd.counter = &counter; + wd.failure = &failure; + - threads = (pthread_t*)alloca(poolsize*sizeof(pthread_t)); ++ threads = (pthread_t*)mem_a(poolsize*sizeof(pthread_t)); + + for (i = 0; i < poolsize; ++i) { + if (pthread_create(threads+i, NULL, &function_finalize_worker, &wd) != 0) + break; + } + if (i < poolsize) { + con_out("failed to spawn worker threads\n"); + for (j = 0; j <= i; ++j) + pthread_join(threads[j], NULL); + return false; + } + for (i = 0; i < poolsize; ++i) + pthread_join(threads[i], NULL); + return !failure; +} + +bool function_finalize_all(ast_function **list, size_t count) +{ + size_t i; - for (i = 0; i < count; ++i) { - if (!ir_function_optimize(list[i]->ir_func)) { - con_out("failed to optimize function %s\n", list[i]->name); - return false; - } - } + if (OPTS_OPTION_U32(OPTION_J) > 1) + return function_finalize_all_threaded(list, count); ++ + for (i = 0; i < count; ++i) { + if (!ir_function_finalize(list[i]->ir_func)) { + con_out("failed to finalize function %s\n", list[i]->name); + return false; + } + } + return true; +} + bool parser_finish(parser_t *parser, const char *output) { size_t i; @@@ -6236,11 -6320,11 +6400,11 @@@ ast_expression *subtype; field->hasvalue = true; subtype = field->expression.next; - ifld = ir_builder_create_field(ir, field->name, subtype->expression.vtype); - if (subtype->expression.vtype == TYPE_FIELD) - ifld->fieldtype = subtype->expression.next->expression.vtype; - else if (subtype->expression.vtype == TYPE_FUNCTION) - ifld->outtype = subtype->expression.next->expression.vtype; + ifld = ir_builder_create_field(ir, field->name, subtype->vtype); + if (subtype->vtype == TYPE_FIELD) + ifld->fieldtype = subtype->next->vtype; + else if (subtype->vtype == TYPE_FUNCTION) + ifld->outtype = subtype->next->vtype; (void)!ir_value_set_field(field->ir_v, ifld); } } @@@ -6328,7 -6412,7 +6492,7 @@@ } for (i = 0; i < vec_size(parser->fields); ++i) { ast_value *asvalue; - asvalue = (ast_value*)(parser->fields[i]->expression.next); + asvalue = (ast_value*)(parser->fields[i]->next); if (!ast_istype((ast_expression*)asvalue, ast_value)) continue; @@@ -6354,15 -6438,10 +6518,12 @@@ return false; } } + + generate_checksum(parser); if (OPTS_OPTION_BOOL(OPTION_DUMP)) ir_builder_dump(ir, con_out); + - if (!ir_builder_prepare(ir)) { - con_out("failed to prepare builder for output\n"); - ir_builder_delete(ir); - return false; - } +#if 0 for (i = 0; i < vec_size(parser->functions); ++i) { if (!ir_function_finalize(parser->functions[i]->ir_func)) { con_out("failed to finalize function %s\n", parser->functions[i]->name); @@@ -6370,13 -6449,8 +6531,16 @@@ return false; } } ++ +#else + if (!function_finalize_all(parser->functions, vec_size(parser->functions))) { + ir_builder_delete(ir); + return false; + } +#endif + + parser_remove_ast(parser); + if (compile_Werrors) { con_out("*** there were warnings treated as errors\n"); compile_show_werrors(); @@@ -6387,15 -6461,12 +6551,12 @@@ if (OPTS_OPTION_BOOL(OPTION_DUMPFIN)) ir_builder_dump(ir, con_out); - generate_checksum(parser); - - if (!ir_builder_generate(parser->code, ir, output)) { + if (!ir_builder_generate(ir, output)) { con_out("*** failed to generate output file\n"); ir_builder_delete(ir); return false; } } - ir_builder_delete(ir); return retval; }