diff options
author | jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-04-09 17:19:58 +0000 |
---|---|---|
committer | jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-04-09 17:19:58 +0000 |
commit | a6c787e5b7ad773092038330079c7c62122ae7f7 (patch) | |
tree | 61752d61b3fcec7c9f45123820661900d12f5e36 /gcc/config/alpha | |
parent | 55fcc6a4251261bf1b1683c720e9a9fe1d977422 (diff) | |
download | gcc-a6c787e5b7ad773092038330079c7c62122ae7f7.tar.gz |
* tree.h (enum tree_index): Add TI_VA_LIST_GPR_COUNTER_FIELD
and TI_VA_LIST_FPR_COUNTER_FIELD.
(va_list_gpr_counter_field, va_list_fpr_counter_field): Define.
* tree-pass.h (pass_stdarg): Add.
* tree-optimize.c (init_tree_optimization_passes): Add pass_stdarg.
* tree-stdarg.c: New file.
* tree-stdarg.h: New file.
* Makefile.in (OBJS-common): Add tree-stdarg.o.
(tree-stdarg.o): Add dependencies.
* function.h (struct function): Add va_list_gpr_size and
va_list_fpr_size fields.
* function.c (allocate_struct_function): Initialize them.
* target.h (struct gcc_target): Add stdarg_optimize_hook.
* target-def.h (TARGET_STDARG_OPTIMIZE_HOOK): Define.
(TARGET_INITIALIZER): Add it.
* config/i386/i386.c (ix86_build_builtin_va_list): Initialize
va_list_{g,f}pr_counter_field.
(ix86_setup_incoming_varargs): Don't do anything if reg_save
area will not be used. Only save registers that tree-stdarg.c
detected they need saving.
(ix86_va_start): Don't set up fields that won't be used.
* config/rs6000/rs6000.c (rs6000_build_builtin_va_list): Initialize
va_list_{g,f}pr_counter_field.
(setup_incoming_varargs): Don't do anything if reg_save
area will not be used. Only save registers that tree-stdarg.c
detected they need saving.
(rs6000_va_start): Don't set up fields that won't be used.
* config/alpha/alpha.c: Include tree-flow.h and tree-stdarg.h.
(alpha_build_builtin_va_list): Initialize va_list_gpr_counter_field.
(va_list_skip_additions, alpha_stdarg_optimize_hook): New functions.
(TARGET_STDARG_OPTIMIZE_HOOK): Define.
* gcc.dg/tree-ssa/stdarg-1.c: New test.
* gcc.dg/tree-ssa/stdarg-2.c: New test.
* gcc.dg/tree-ssa/stdarg-3.c: New test.
* gcc.dg/tree-ssa/stdarg-4.c: New test.
* gcc.dg/tree-ssa/stdarg-5.c: New test.
* gcc.c-torture/execute/stdarg-4.c: New test.
* gcc.dg/vmx/varargs-1.c (f1, f2, f3): Add missing va_end.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@97916 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/alpha')
-rw-r--r-- | gcc/config/alpha/alpha.c | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c index 777e62e85e5..39ad4a7aaa8 100644 --- a/gcc/config/alpha/alpha.c +++ b/gcc/config/alpha/alpha.c @@ -53,6 +53,8 @@ Boston, MA 02111-1307, USA. */ #include <splay-tree.h> #include "cfglayout.h" #include "tree-gimple.h" +#include "tree-flow.h" +#include "tree-stdarg.h" /* Specify which cpu to schedule for. */ enum processor_type alpha_tune; @@ -5576,9 +5578,156 @@ alpha_build_builtin_va_list (void) TYPE_FIELDS (record) = base; layout_type (record); + va_list_gpr_counter_field = ofs; return record; } +/* Helper function for alpha_stdarg_optimize_hook. Skip over casts + and constant additions. */ + +static tree +va_list_skip_additions (tree lhs) +{ + tree rhs, stmt; + + if (TREE_CODE (lhs) != SSA_NAME) + return lhs; + + for (;;) + { + stmt = SSA_NAME_DEF_STMT (lhs); + + if (TREE_CODE (stmt) == PHI_NODE) + return stmt; + + if (TREE_CODE (stmt) != MODIFY_EXPR + || TREE_OPERAND (stmt, 0) != lhs) + return lhs; + + rhs = TREE_OPERAND (stmt, 1); + if (TREE_CODE (rhs) == WITH_SIZE_EXPR) + rhs = TREE_OPERAND (rhs, 0); + + if ((TREE_CODE (rhs) != NOP_EXPR + && TREE_CODE (rhs) != CONVERT_EXPR + && (TREE_CODE (rhs) != PLUS_EXPR + || TREE_CODE (TREE_OPERAND (rhs, 1)) != INTEGER_CST + || !host_integerp (TREE_OPERAND (rhs, 1), 1))) + || TREE_CODE (TREE_OPERAND (rhs, 0)) != SSA_NAME) + return rhs; + + lhs = TREE_OPERAND (rhs, 0); + } +} + +/* Check if LHS = RHS statement is + LHS = *(ap.__base + ap.__offset + cst) + or + LHS = *(ap.__base + + ((ap.__offset + cst <= 47) + ? ap.__offset + cst - 48 : ap.__offset + cst) + cst2). + If the former, indicate that GPR registers are needed, + if the latter, indicate that FPR registers are needed. + On alpha, cfun->va_list_gpr_size is used as size of the needed + regs and cfun->va_list_fpr_size is a bitmask, bit 0 set if + GPR registers are needed and bit 1 set if FPR registers are needed. + Return true if va_list references should not be scanned for the current + statement. */ + +static bool +alpha_stdarg_optimize_hook (struct stdarg_info *si, tree lhs, tree rhs) +{ + tree base, offset, arg1, arg2; + int offset_arg = 1; + + if (TREE_CODE (rhs) != INDIRECT_REF + || TREE_CODE (TREE_OPERAND (rhs, 0)) != SSA_NAME) + return false; + + lhs = va_list_skip_additions (TREE_OPERAND (rhs, 0)); + if (lhs == NULL_TREE + || TREE_CODE (lhs) != PLUS_EXPR) + return false; + + base = TREE_OPERAND (lhs, 0); + if (TREE_CODE (base) == SSA_NAME) + base = va_list_skip_additions (base); + + if (TREE_CODE (base) != COMPONENT_REF + || TREE_OPERAND (base, 1) != TYPE_FIELDS (va_list_type_node)) + { + base = TREE_OPERAND (lhs, 0); + if (TREE_CODE (base) == SSA_NAME) + base = va_list_skip_additions (base); + + if (TREE_CODE (base) != COMPONENT_REF + || TREE_OPERAND (base, 1) != TYPE_FIELDS (va_list_type_node)) + return false; + + offset_arg = 0; + } + + base = get_base_address (base); + if (TREE_CODE (base) != VAR_DECL + || !bitmap_bit_p (si->va_list_vars, var_ann (base)->uid)) + return false; + + offset = TREE_OPERAND (lhs, offset_arg); + if (TREE_CODE (offset) == SSA_NAME) + offset = va_list_skip_additions (offset); + + if (TREE_CODE (offset) == PHI_NODE) + { + HOST_WIDE_INT sub; + + if (PHI_NUM_ARGS (offset) != 2) + goto escapes; + + arg1 = va_list_skip_additions (PHI_ARG_DEF (offset, 0)); + arg2 = va_list_skip_additions (PHI_ARG_DEF (offset, 1)); + if (TREE_CODE (arg1) != COMPONENT_REF) + { + tree tem = arg1; + + arg1 = arg2; + arg2 = tem; + } + + if ((TREE_CODE (arg2) != MINUS_EXPR + && TREE_CODE (arg2) != PLUS_EXPR) + || !host_integerp (TREE_OPERAND (arg2, 1), 0)) + goto escapes; + + sub = tree_low_cst (TREE_OPERAND (arg2, 1), 0); + if (TREE_CODE (arg2) == MINUS_EXPR) + sub = -sub; + if (sub < -48 || sub > -32) + goto escapes; + + arg2 = va_list_skip_additions (TREE_OPERAND (arg2, 0)); + if (arg1 != arg2 + || TREE_CODE (arg1) != COMPONENT_REF + || TREE_OPERAND (arg1, 1) != va_list_gpr_counter_field + || get_base_address (arg1) != base) + goto escapes; + + /* Need floating point regs. */ + cfun->va_list_fpr_size |= 2; + } + else if (TREE_CODE (offset) != COMPONENT_REF + || TREE_OPERAND (offset, 1) != va_list_gpr_counter_field + || get_base_address (offset) != base) + goto escapes; + else + /* Need general regs. */ + cfun->va_list_fpr_size |= 1; + return false; + +escapes: + si->va_list_escapes = true; + return false; +} + /* Perform any needed actions needed for a function that is receiving a variable number of arguments. */ @@ -10205,6 +10354,9 @@ alpha_init_libfuncs (void) #undef TARGET_HANDLE_OPTION #define TARGET_HANDLE_OPTION alpha_handle_option +#undef TARGET_STDARG_OPTIMIZE_HOOK +#define TARGET_STDARG_OPTIMIZE_HOOK alpha_stdarg_optimize_hook + struct gcc_target targetm = TARGET_INITIALIZER; |