diff --git a/tools/qfcc/include/def.h b/tools/qfcc/include/def.h index 6892b5d8a..a00758bdf 100644 --- a/tools/qfcc/include/def.h +++ b/tools/qfcc/include/def.h @@ -97,6 +97,7 @@ typedef struct def_s { unsigned external:1; ///< externally declared def unsigned local:1; ///< function local def unsigned param:1; ///< function param def + unsigned argument:1; ///< function argument def unsigned system:1; ///< system def unsigned nosave:1; ///< don't set DEF_SAVEGLOBAL @@ -117,7 +118,8 @@ typedef enum storage_class_e { sc_extern, ///< def is externally allocated sc_static, ///< def is private to the current unit sc_param, ///< def is an incoming function parameter - sc_local ///< def is local to the current function + sc_local, ///< def is local to the current function + sc_argument, ///< def is a function argument } storage_class_t; /** Create a new def. diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index f87803f2c..b745f2da3 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -76,30 +76,42 @@ set_storage_bits (def_t *def, storage_class_t storage) def->external = 0; def->local = 0; def->param = 0; + def->argument = 0; break; case sc_extern: def->global = 1; def->external = 1; def->local = 0; def->param = 0; + def->argument = 0; break; case sc_static: def->external = 0; def->global = 0; def->local = 0; def->param = 0; + def->argument = 0; break; case sc_local: def->external = 0; def->global = 0; def->local = 1; def->param = 0; + def->argument = 0; break; case sc_param: def->external = 0; def->global = 0; def->local = 1; def->param = 1; + def->argument = 0; + break; + case sc_argument: + def->external = 0; + def->global = 0; + def->local = 1; + def->param = 0; + def->argument = 1; break; } def->initialized = 0; diff --git a/tools/qfcc/source/flow.c b/tools/qfcc/source/flow.c index 4e86fc0c3..43768096a 100644 --- a/tools/qfcc/source/flow.c +++ b/tools/qfcc/source/flow.c @@ -227,7 +227,8 @@ flowvar_is_global (flowvar_t *var) * * For the flowvar to refer to a function parameter, the flowvar's operand * must be a def operand (but the def itself may be an alias of the real def) - * and the rel def must have both its def_t::local and def_t::param flags set. + * and the real def must have both its def_t::local and def_t::param flags + * set. * * Temp vars are are not represented by op_def, so no mistake can be made. */ @@ -248,16 +249,43 @@ flowvar_is_param (flowvar_t *var) return 1; } +/** Check if the flowvar refers to a function argument. + * + * For the flowvar to refer to a function argument, the flowvar's operand + * must be a def operand (but the def itself may be an alias of the real def) + * and the real def must have both its def_t::local and def_t::argument flags + * set. + * + * Temp vars are are not represented by op_def, so no mistake can be made. + */ +static int +flowvar_is_argument (flowvar_t *var) +{ + def_t *def; + + if (var->op->op_type != op_def) + return 0; + def = var->op->def; + if (def->alias) + def = def->alias; + if (!def->local) + return 0; + if (!def->argument) + return 0; + return 1; +} + /** Check if the flowvar refers to a local variable. * - * As this is simply "neither global nor pamam", all other flowvars are - * considered local, in particular actual non-staic function scope variables - * and temp vars. + * As this is simply "neither global nor pamam nor argument", all other + * flowvars are considered local, in particular actual non-staic function + * scope variables and temp vars. */ static int flowvar_is_local (flowvar_t *var) { - return !(flowvar_is_global (var) || flowvar_is_param (var)); + return !(flowvar_is_global (var) || flowvar_is_param (var) + || flowvar_is_argument (var)); } ///@} @@ -443,6 +471,13 @@ add_operand (function_t *func, operand_t *op) var->flowaddr = get_pseudo_address (func, 1); } else if (op->op_type == op_temp) { var->flowaddr = get_temp_address (func, op); + } else if (flowvar_is_param (var)) { + var->flowaddr = func->num_statements + def_offset (var->op->def); + var->flowaddr += func->locals->space->size; + } else if (flowvar_is_argument (var)) { + var->flowaddr = func->num_statements + def_offset (var->op->def); + var->flowaddr += func->locals->space->size; + var->flowaddr += func->parameters->space->size; } else if (flowvar_is_local (var)) { var->flowaddr = func->num_statements + def_offset (var->op->def); } @@ -609,7 +644,12 @@ flow_build_vars (function_t *func) // set up pseudo address space for temp vars so accessing tmp vars // though aliases analyses correctly - func->pseudo_addr = func->num_statements + func->locals->space->size; + func->pseudo_addr = func->num_statements; + func->pseudo_addr += func->locals->space->size; + func->pseudo_addr += func->parameters->space->size; + if (func->arguments) { + func->pseudo_addr += func->arguments->size; + } func->num_vars = 0; // incremented by add_operand // first, add .return and .param_[0-7] as they are always needed diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 3da2e12a5..a3b0a64fb 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -1097,7 +1097,7 @@ expr_call (sblock_t *sblock, expr_t *call, operand_t **op) expr_t *a = args[i]; const char *arg_name = va (0, ".arg%d", arg_num++); def_t *def = new_def (arg_name, 0, current_func->arguments, - sc_local); + sc_argument); type_t *arg_type = get_type (a); int size = type_size (arg_type); int alignment = arg_type->alignment;