From 52d178b3bec5f73b6dad386a010c7e7999c1ccb3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 10 Apr 2007 13:00:21 +0000 Subject: [PATCH] Add a code generation option, "local-merging", to control qfcc's merging of local variable blocks into one block. Defaults to on for advanced mode and off for traditional. --- tools/qfcc/doc/man/qfcc.1 | 110 ++++++++++++++++++++++-------- tools/qfcc/include/def.h | 1 + tools/qfcc/include/options.h | 3 +- tools/qfcc/source/def.c | 9 ++- tools/qfcc/source/expr.c | 11 ++- tools/qfcc/source/options.c | 125 +++++++++++++++++++---------------- tools/qfcc/source/qfcc.c | 17 +++-- 7 files changed, 178 insertions(+), 98 deletions(-) diff --git a/tools/qfcc/doc/man/qfcc.1 b/tools/qfcc/doc/man/qfcc.1 index 235c1b0b4..c84f4740d 100644 --- a/tools/qfcc/doc/man/qfcc.1 +++ b/tools/qfcc/doc/man/qfcc.1 @@ -42,24 +42,26 @@ understand. .SH OPTIONS \fBqfcc\fP takes the following arguments: .TP -.B \-\-traditional -Use traditional QuakeC syntax, semantics and \*(lqbugs\*(rq. Also implies the -\fBv6only\fP code generation option. This is the default when using progs.src. -.TP .B \-\-advanced -Use advanced Raumoko features. This is the default when using separate +Use advanced Ruamoko features. This is the default when using separate compilation. .TP .B \-C, \-\-code OPTION,... Set code generation options. See \fBCODE GENERATION OPTIONS\fP for details. .TP .B \-c -Compile only, do not link. Can be used in either progs.src or separate +Compile only, do not link. Can be used in either \fBprogs.src\fP or separate compilation modes. .TP +.B \-\-cpp CPPSPEC +\fBcpp\fP execution command line. See \fBCPP NAME\fP for details. +.TP .B \-D, \-\-define SYMBOL[=VAL] Define a symbol for the preprocessor, if it is in use. .TP +.B \-E +Preprocessor only. No compilation or linking is done. +.TP .B \-F, \-\-files Generate files.dat. This list is created by checking the parameters to the precache_* functions. @@ -75,8 +77,8 @@ Add DIR to the list of directories for the preprocessor to search when looking for include files. .TP .B \-\-include FILE -Process FILE as if \fB#include "FILE"\fP appeared as the first line of -the primary source file. See the cpp man page (\fB\-include\fP) for details. +Process FILE as if \fB#include "FILE"\fP appeared as the first line of the +primary source file. See the \fBcpp\fP man page (\fB\-include\fP) for details. .TP .B \-L DIR Add DIR to the search path used for -l. @@ -86,6 +88,10 @@ Add libLIB.a to the list of libraries to be used for resolving undefined symbols. \fBqfcc\fP's libraries are really \fBpak\fP files of \fBqfcc\fP object files built using the \fBpak\fP utility. .TP +.B \-M, \-MD, \-MMD +Generate dependency info. Dependent on \fBcpp\fP version, so check \fBcpp\fP's +documentation. +.TP .B \-N, \-\-notice OPTION,... Set notice options. See \fBNOTICE OPTIONS\fP for details. .TP @@ -93,11 +99,11 @@ Set notice options. See \fBNOTICE OPTIONS\fP for details. Specify output file name. .TP .B \-P, \-\-progs\-src FILE -File to use instead of progs.src +File to use instead of \fBprogs.src\fP .TP .B \-p, \-\-strip\-path NUM Strip NUM leading path elements from file names. eg. -p 3 will strip the -../../.. from ../../../src/foo.r when embedding the source file name in the +\../../.. from ../../../src/foo.r when embedding the source file name in the output code. .TP .B \-q, \-\-quiet @@ -111,7 +117,12 @@ and libraries. Do not delete temporary files. .TP .B \-s, \-\-source DIR -look for progs.src in DIR instead of the current directory. +look for \fBprogs.src\fP in DIR instead of the current directory. +.TP +.B \-\-traditional +Use traditional QuakeC syntax, semantics and \*(lqbugs\*(rq. Also implies the +\fBv6only\fP, \fBno-short-circuit\fP and \fBno-local-merging\fP code +generation options. This is the default when using \fBprogs.src\fP. .TP .B \-U, \-\-undefine SYMBOL Undefine a preprocessor symbol, if the preprocessor is in use. @@ -129,9 +140,6 @@ Set warning options. See \fBWARNING OPTIONS\fP for details. Compress object files when writing them. This is especially useful when creating libraries, especially if using the object oriented features, but can be quite slow. -.TP -.B \-\-cpp CPPSPEC -\fBcpp\fP execution command line. See \fBCPP NAME\fP for details. .SH "CODE GENERATION OPTIONS" Code generation options are processed in the order of their appearance on the command line. Unsupported options are ignored. The following options are @@ -145,6 +153,10 @@ However, \fBqcc\fP never really enforced this. The \fBcow\fP option allows initialized globals in this manner. (also known as \*(lqcopy on write\*(rq\(emnever mind the bovine connotations) .TP +.B cpp +Preprocess all input files with \fBcpp\fP. This includes the \fBprogs.src\fB +file when used. +.TP .B debug Generate debug code for QuakeForge engines. The QuakeForge engine has the ability to load line number and other debugging information for use in @@ -153,6 +165,17 @@ information. It is written to a secondary file with the extension \*(lqsym\*(rq\(emif your output file is \*(lqprogs.dat\*(rq, the symbol file will be \*(lqprogs.sym\*(rq. .TP +.B fast\-float +Use float values directly in \*(lqif\*(rq statements. Defaults to on. This +option is always enabled when using version 6 progs. +.TP +.B local-merging +Clump the local variables from all functions into one block of data the size +of the largest group of locals, resulting in large savings of global data +space. When off, each function's local variable block is separate from the +others, preserving the behaviour of traditional \fBqcc\fP, but using much more +global data. Defaults to off for traditional mode, and on for advanced mode. +.TP .B short\-circuit Generate short circuit code for logical operators (\fB&&\fP and \fB||\fP). For \fBA && B\fP, if \fBA\fP is false, the expression is known to be false and the @@ -161,22 +184,28 @@ code for \fBB\fP will not be executed. Similar for \fBA || B\fP, but if will not be executed. Defaults to off for traditional mode, and on for advanced mode. .TP -.B fast\-float -Use float values directly in \*(lqif\*(rq statements. Defaults to on. This -option is always enabled when using version 6 progs. +.B single-cpp +In \fBprogs.src\fP mode, when \fBcpp\fP is used, produce an intermediate file +that is a series of \fB#include\fP directives, one for each source file. This +file is then passed to \fBcpp\fP and the resulting output is compiled in one +go. This results in preprocessor directives in early files affecting later +files, as would be expected in \fBprogs.src\fP mode. Without this option, +each source file is independent with respect to the preprocessor. Defaults to +on. .TP .B vector\-calls Where a function is called with just a vector, this causes the function call to store three floats instead of one vector. This can save a good number of pr_globals where those vectors contain many duplicate coordinates but do not -match entirly. However, this will generate slower code for such calls. +match entirely. However, this will generate slower code for such calls. .TP .B v6only Restrict the compiler to only version 6 progs (original Quake/QuakeWorld) features. This means that the compiled data file should be able to run on older servers, as long as you have not used any QuakeForge-specific built-in functions. Also disables some of the compiler's features (like integers and -string manipulation support). +string manipulation support). Defaults to on for traditional mode and off for +advanced mode. .SH "WARNING OPTIONS" Warning options are processed in the order of their appearance on the command line. Unsupported options are ignored. The following options are supported by @@ -184,26 +213,49 @@ line. Unsupported options are ignored. The following options are supported by .TP .B cow Emit a warning when the source assigns a value to a named constant. See the -description of the \fBcow\fP code option above for a description of what this -means. +description of the \fBcow\fP code generation option above for a description +of what this means. +.TP +.B error +Promote warnings to errors. +.TP +.B executable +Emit a warning when non-executable statements (eg, \fB==\fP used for +assignment) are encountered. +.TP +.B initializer +Emit a warning when too many structure/array initializer elements are given. +.TP +.B integer-divide +Emit a warning when both constants in a division operation are integers. .TP .B interface\-check Emit a warning when a method is declared in an implementation but not in the interface for a class. .TP +.B precedence +Emit a warning when potentially ambiguous logic is used without parentheses. +.TP +.B traditional +Emit a warning when code that should be an error is allowed by traditional +\fBqcc\fB. Has effect only in traditional mode. +.TP .B undef\-function Emit a warning when a function is called, but has not yet been defined. .TP +.B unimplemented +Emit a warning when a class method has not been implemented. +.TP +.B unused +Emit a warning for unused local variables. +.TP .B uninited\-var -Emit a warning when a variable is read from that has not been initalized to a +Emit a warning when a variable is read from that has not been initialized to a value. .TP .B vararg\-integer Emit a warning when a function that takes a variable number of arguments is passed a constant of an integer type. -.TP -.B error -Promote warnings to errors. .PP Any of the above can be prefixed with \fBno\-\fP to negate its meaning. There are also two special options: @@ -258,9 +310,9 @@ the Web site at <\fBhttp://maori.com/kmst1.htm\fP>. .B qfcc hangs This is almost always caused by qfcc incorrectly invoking \fBcpp\fP. Using the \fB--cpp\fP option (refer to the \fBCPP NAME\fP section above), the correct -method for invoking cpp can be specified. Once you have found this, please -send the correct \fBcpp\fP command line, preferably along with the output of -\fBconfig.guess\fP, to the team. +method for invoking \fBcpp\fP can be specified. Once you have found this, +please send the correct \fBcpp\fP command line, preferably along with the +output of \fBconfig.guess\fP, to the team. .TP .B qfcc is singing a bad 80s rap song to me. What's going on? \*(lqice ice baby\*(rq is QuakeForge-speak for \*(lqInternal Compiler @@ -275,7 +327,7 @@ while, but you told it not to do that by passing the \fBcow\fP option to \fB\-\-code\fP, so it has its revenge by mooing out a warning. Or something like that. To disable the warning, pass \fBno-cow\fP to \fB\-\-warn\fP. .SH "FILES" -progs.src +\fBprogs.src\fP .SH "SEE ALSO" .BR quakeforge (1), pak (1) .SH AUTHORS diff --git a/tools/qfcc/include/def.h b/tools/qfcc/include/def.h index 75aca5ab0..3136f0035 100644 --- a/tools/qfcc/include/def.h +++ b/tools/qfcc/include/def.h @@ -121,6 +121,7 @@ def_t *get_def (struct type_s *type, const char *name, scope_t *scope, storage_class_t storage); def_t *new_def (struct type_s *type, const char *name, scope_t *scope); void set_storage_bits (def_t *def, storage_class_t storage); +int new_location_size (int size, defspace_t *space); int new_location (struct type_s *type, defspace_t *space); void free_location (def_t *def); def_t *get_tempdef (struct type_s *type, scope_t *scope); diff --git a/tools/qfcc/include/options.h b/tools/qfcc/include/options.h index b4f87d330..db0b578ac 100644 --- a/tools/qfcc/include/options.h +++ b/tools/qfcc/include/options.h @@ -40,7 +40,8 @@ typedef struct { qboolean short_circuit; // short circuit logic for && and || qboolean fast_float; // use floats directly in ifs qboolean vector_calls; // use floats instead of vectors for constant function args - unsigned int progsversion; // Progs version to generate code for + qboolean local_merge; // merge function locals into one block + unsigned progsversion; // Progs version to generate code for } code_options_t; typedef struct { diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index 1057f42d9..80e55c97b 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -341,9 +341,8 @@ new_def (type_t *type, const char *name, scope_t *scope) } int -new_location (type_t *type, defspace_t *space) +new_location_size (int size, defspace_t *space) { - int size = type_size (type); int ofs; locref_t *loc; locref_t **l = &space->free_locs; @@ -372,6 +371,12 @@ new_location (type_t *type, defspace_t *space) return ofs; } +int +new_location (type_t *type, defspace_t *space) +{ + return new_location_size (type_size (type), space); +} + void free_location (def_t *def) { diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index a33257169..7f1374ec4 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -306,10 +306,15 @@ check_initialized (expr_t *e) && !e->e.def->external && !e->e.def->initialized) { name = e->e.def->name; - if (options.warnings.uninited_variable && !e->e.def->suppress) - warning (e, "%s may be used uninitialized", name); + if (options.warnings.uninited_variable && !e->e.def->suppress) { + if (options.code.local_merging) + warning (e, "%s may be used uninitialized", name); + else + notice (e, "%s may be used uninitialized", name); + } e->e.def->suppress = 1; // only warn once - if (options.traditional && !e->e.def->set) { + if (options.traditional && options.code.local_merging + && !e->e.def->set) { def_t *def = e->e.def; e->e.def->set = 1; // only auto-init once e = assign_expr (e, new_nil_expr ()); diff --git a/tools/qfcc/source/options.c b/tools/qfcc/source/options.c index d2284d30d..27c664d88 100644 --- a/tools/qfcc/source/options.c +++ b/tools/qfcc/source/options.c @@ -83,29 +83,29 @@ static struct option const long_options[] = { static const char *short_options = "-" // magic option parsing mode doohicky (must come first) - "l:" // lib file - "L:" // lib path - "o:" // output file - "c" // separate compilation - "r" // partial linking - "s:" // source dir - "P:" // progs.src name - "F" // generate files.dat - "q" // quiet - "v" // verbose - "g" // debug "C:" // code options - "W:" // warning options - "h" // help - "V" // version - "p:" // strip path - "S" // save temps + "c" // separate compilation "D:" // define "E" // preprocess only + "F" // generate files.dat + "g" // debug + "h" // help "I:" // set includes - "U:" // undefine - "N:" // notice options + "l:" // lib file + "L:" // lib path "M::" + "N:" // notice options + "o:" // output file + "P:" // progs.src name + "p:" // strip path + "q" // quiet + "r" // partial linking + "S" // save temps + "s:" // source dir + "U:" // undefine + "V" // version + "v" // verbose + "W:" // warning options "z" // compress qfo files ; @@ -116,37 +116,39 @@ usage (int status) printf ("Usage: %s [options] [files]\n", this_program); printf ( "Options:\n" -" --traditional Traditional QuakeC mode: implies v6only\n" -" default when using progs.src\n" " --advanced Advanced Ruamoko mode\n" " default for separate compilation mode\n" -" -s, --source DIR Look for progs.src in DIR instead of \".\"\n" -" -q, --quiet Inhibit usual output\n" -" -v, --verbose Display more output than usual\n" -" -g Generate debugging info\n" -" -o, --output-file FILE Specify output file name\n" -" -P, --progs-src FILE File to use instead of progs.src\n" -" -F, --files Generate files.dat\n" -" -p, --strip-path NUM Strip NUM leading path elements from file\n" -" names\n" " -C, --code OPTION,... Set code generation options\n" -" -W, --warn OPTION,... Set warning options\n" -" -N, --notice OPTION,... Set notice options\n" -" -h, --help Display this help and exit\n" -" -V, --version Output version information and exit\n\n" -" -S, --save-temps Do not delete temporary files\n" +" -c Compile only, don't link\n" +" --cpp CPPSPEC cpp execution command line\n" " -D, --define SYMBOL[=VAL] Define symbols for the preprocessor\n" +" -E Preprocess only\n" +" -F, --files Generate files.dat\n" +" -g Generate debugging info\n" +" -h, --help Display this help and exit\n" " -I DIR Set directories for the preprocessor\n" " to search for #includes\n" " --include FILE Process file as if `#include \"file\"'\n" " appeared as the first line of the primary\n" " source file.\n" -" -U, --undefine SYMBOL Undefine preprocessor symbols\n" -" --cpp CPPSPEC cpp execution command line\n" " -L DIR Add linker library search path\n" " -l LIB Link with libLIB.a\n" -" -c Compile only, don't link\n" +" -M[flags] Generate depency info. Dependent on cpp\n" +" -N, --notice OPTION,... Set notice options\n" +" -o, --output-file FILE Specify output file name\n" +" -P, --progs-src FILE File to use instead of progs.src\n" +" -p, --strip-path NUM Strip NUM leading path elements from file\n" +" names\n" +" -q, --quiet Inhibit usual output\n" " -r Incremental linking\n" +" -S, --save-temps Do not delete temporary files\n" +" -s, --source DIR Look for progs.src in DIR instead of \".\"\n" +" --traditional Traditional QuakeC mode: implies v6only\n" +" default when using progs.src\n" +" -U, --undefine SYMBOL Undefine preprocessor symbols\n" +" -V, --version Output version information and exit\n" +" -v, --verbose Display more output than usual\n" +" -W, --warn OPTION,... Set warning options\n" " -z Compress object files\n" "\n" "For help on options for --code and --warn, see the qfcc(1) manual page\n" @@ -175,6 +177,7 @@ DecodeArgs (int argc, char **argv) add_cpp_def ("-D__QUAKEC__=1"); options.code.short_circuit = -1; + options.code.local_merging = -1; options.code.fast_float = true; options.warnings.uninited_variable = true; options.warnings.unused = true; @@ -275,14 +278,16 @@ DecodeArgs (int argc, char **argv) options.code.cow = flag; } else if (!(strcasecmp (temp, "cpp"))) { cpp_name = flag ? CPP_NAME : 0; - } else if (!(strcasecmp (temp, "single-cpp"))) { - options.single_cpp = flag; } else if (!(strcasecmp (temp, "debug"))) { options.code.debug = flag; - } else if (!(strcasecmp (temp, "short-circuit"))) { - options.code.short_circuit = flag; } else if (!(strcasecmp (temp, "fast-float"))) { options.code.fast_float = flag; + } else if (!(strcasecmp (temp, "local-merging"))) { + options.code.local_merging = flag; + } else if (!(strcasecmp (temp, "short-circuit"))) { + options.code.short_circuit = flag; + } else if (!(strcasecmp (temp, "single-cpp"))) { + options.single_cpp = flag; } else if (!(strcasecmp (temp, "vector-calls"))) { options.code.vector_calls = flag; } else if (!(strcasecmp (temp, "v6only"))) { @@ -334,32 +339,32 @@ DecodeArgs (int argc, char **argv) flag = false; temp += 3; } - if (!strcasecmp (temp, "error")) { - options.warnings.promote = flag; - } else if (!(strcasecmp (temp, "cow"))) { + if (!(strcasecmp (temp, "cow"))) { options.warnings.cow = flag; - } else if (!strcasecmp (temp, "undef-function")) { - options.warnings.undefined_function = flag; - } else if (!strcasecmp (temp, "uninited-var")) { - options.warnings.uninited_variable = flag; - } else if (!strcasecmp (temp, "vararg-integer")) { - options.warnings.vararg_integer = flag; + } else if (!strcasecmp (temp, "error")) { + options.warnings.promote = flag; + } else if (!strcasecmp (temp, "executable")) { + options.warnings.executable = flag; + } else if (!strcasecmp (temp, "initializer")) { + options.warnings.initializer = flag; } else if (!strcasecmp (temp, "integer-divide")) { options.warnings.integer_divide = flag; } else if (!strcasecmp (temp, "interface-check")) { options.warnings.interface_check = flag; - } else if (!strcasecmp (temp, "unused")) { - options.warnings.unused = flag; - } else if (!strcasecmp (temp, "executable")) { - options.warnings.executable = flag; - } else if (!strcasecmp (temp, "traditional")) { - options.warnings.traditional = flag; } else if (!strcasecmp (temp, "precedence")) { options.warnings.precedence = flag; - } else if (!strcasecmp (temp, "initializer")) { - options.warnings.initializer = flag; + } else if (!strcasecmp (temp, "traditional")) { + options.warnings.traditional = flag; + } else if (!strcasecmp (temp, "undef-function")) { + options.warnings.undefined_function = flag; } else if (!strcasecmp (temp, "unimplemented")) { options.warnings.unimplemented = flag; + } else if (!strcasecmp (temp, "unused")) { + options.warnings.unused = flag; + } else if (!strcasecmp (temp, "uninited-var")) { + options.warnings.uninited_variable = flag; + } else if (!strcasecmp (temp, "vararg-integer")) { + options.warnings.vararg_integer = flag; } } temp = strtok (NULL, ","); @@ -439,6 +444,8 @@ DecodeArgs (int argc, char **argv) options.code.progsversion = PROG_ID_VERSION; if (options.code.short_circuit == (qboolean) -1) options.code.short_circuit = false; + if (options.code.local_merging == (qboolean) -1) + options.code.local_merging = false; } if (!options.code.progsversion) options.code.progsversion = PROG_VERSION; @@ -448,6 +455,8 @@ DecodeArgs (int argc, char **argv) add_cpp_def ("-D__RAUMOKO__=1"); if (options.code.short_circuit == (qboolean) -1) options.code.short_circuit = true; + if (options.code.local_merging == (qboolean) -1) + options.code.local_merging = true; } if (options.code.progsversion == PROG_ID_VERSION) add_cpp_def ("-D__VERSION6__=1"); diff --git a/tools/qfcc/source/qfcc.c b/tools/qfcc/source/qfcc.c index 5324510e4..bb3686cb2 100644 --- a/tools/qfcc/source/qfcc.c +++ b/tools/qfcc/source/qfcc.c @@ -452,17 +452,24 @@ finish_compilation (void) if (!f->code) continue; df->first_statement = f->code; - if (f->scope->space->size > num_localdefs) { - num_localdefs = f->scope->space->size; - big_function = f->def->name; + if (options.code.local_merging) { + if (f->scope->space->size > num_localdefs) { + num_localdefs = f->scope->space->size; + big_function = f->def->name; + } + df->parm_start = pr.near_data->size; + } else { + df->parm_start = new_location_size (f->scope->space->size, + pr.near_data); + num_localdefs += f->scope->space->size; } - df->parm_start = pr.near_data->size; for (def = f->scope->head; def; def = def->def_next) { def->ofs += pr.near_data->size; relocate_refs (def->refs, def->ofs); } } - pr.near_data->size += num_localdefs; + if (options.code.local_merging) + new_location_size (num_localdefs, pr.near_data); for (l = pr.labels; l; l = l->next) relocate_refs (l->refs, l->ofs);