summaryrefslogtreecommitdiff
path: root/gcc/config/alpha
diff options
context:
space:
mode:
authorjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2005-04-09 17:19:58 +0000
committerjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2005-04-09 17:19:58 +0000
commita6c787e5b7ad773092038330079c7c62122ae7f7 (patch)
tree61752d61b3fcec7c9f45123820661900d12f5e36 /gcc/config/alpha
parent55fcc6a4251261bf1b1683c720e9a9fe1d977422 (diff)
downloadgcc-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.c152
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;