From 3dce09649d93c3465754c0b027574823607964ab Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 13 Oct 2014 13:20:44 -0700 Subject: [PATCH] Handle cfa adjustments in csa pass * combine-stack-adj.c (no_unhandled_cfa): New. (maybe_merge_cfa_adjust): New. (combine_stack_adjustments_for_block): Use them. From-SVN: r216161 --- gcc/ChangeLog | 6 + gcc/combine-stack-adj.c | 97 ++++++++- gcc/testsuite/ChangeLog | 4 + gcc/testsuite/g++.dg/torture/20141013.C | 267 ++++++++++++++++++++++++ 4 files changed, 367 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/g++.dg/torture/20141013.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a60aae0c352..8829dfeec20 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2014-10-13 Richard Henderson + + * combine-stack-adj.c (no_unhandled_cfa): New. + (maybe_merge_cfa_adjust): New. + (combine_stack_adjustments_for_block): Use them. + 2014-10-13 Aldy Hernandez * Makefile.in (TAGS): Tag ../include files. diff --git a/gcc/combine-stack-adj.c b/gcc/combine-stack-adj.c index aebdf87d807..844873c574d 100644 --- a/gcc/combine-stack-adj.c +++ b/gcc/combine-stack-adj.c @@ -190,6 +190,44 @@ record_one_stack_ref (rtx_insn *insn, rtx *ref, struct csa_reflist *next_reflist return ml; } +/* We only know how to adjust the CFA; no other frame-related changes + may appear in any insn to be deleted. */ + +static bool +no_unhandled_cfa (rtx_insn *insn) +{ + if (!RTX_FRAME_RELATED_P (insn)) + return true; + + /* No CFA notes at all is a legacy interpretation like + FRAME_RELATED_EXPR, and is context sensitive within + the prologue state machine. We can't handle that here. */ + bool has_cfa_adjust = false; + + for (rtx link = REG_NOTES (insn); link; link = XEXP (link, 1)) + switch (REG_NOTE_KIND (link)) + { + default: + break; + case REG_CFA_ADJUST_CFA: + has_cfa_adjust = true; + break; + + case REG_FRAME_RELATED_EXPR: + case REG_CFA_DEF_CFA: + case REG_CFA_OFFSET: + case REG_CFA_REGISTER: + case REG_CFA_EXPRESSION: + case REG_CFA_RESTORE: + case REG_CFA_SET_VDRAP: + case REG_CFA_WINDOW_SAVE: + case REG_CFA_FLUSH_QUEUE: + return false; + } + + return has_cfa_adjust; +} + /* Attempt to apply ADJUST to the stack adjusting insn INSN, as well as each of the memories and stack references in REFLIST. Return true on success. */ @@ -320,6 +358,44 @@ maybe_move_args_size_note (rtx_insn *last, rtx_insn *insn, bool after) add_reg_note (last, REG_ARGS_SIZE, XEXP (note, 0)); } +/* Merge any REG_CFA_ADJUST_CFA note from SRC into DST. + AFTER is true iff DST follows SRC in the instruction stream. */ + +static void +maybe_merge_cfa_adjust (rtx_insn *dst, rtx_insn *src, bool after) +{ + rtx snote = NULL, dnote = NULL; + rtx sexp, dexp; + rtx exp1, exp2; + + if (RTX_FRAME_RELATED_P (src)) + snote = find_reg_note (src, REG_CFA_ADJUST_CFA, NULL_RTX); + if (snote == NULL) + return; + sexp = XEXP (snote, 0); + + if (RTX_FRAME_RELATED_P (dst)) + dnote = find_reg_note (dst, REG_CFA_ADJUST_CFA, NULL_RTX); + if (dnote == NULL) + { + add_reg_note (dst, REG_CFA_ADJUST_CFA, sexp); + return; + } + dexp = XEXP (dnote, 0); + + gcc_assert (GET_CODE (sexp) == SET); + gcc_assert (GET_CODE (dexp) == SET); + + if (after) + exp1 = dexp, exp2 = sexp; + else + exp1 = sexp, exp2 = dexp; + + SET_SRC (exp1) = simplify_replace_rtx (SET_SRC (exp1), SET_DEST (exp2), + SET_SRC (exp2)); + XEXP (dnote, 0) = exp1; +} + /* Return the next (or previous) active insn within BB. */ static rtx_insn * @@ -491,12 +567,15 @@ combine_stack_adjustments_for_block (basic_block bb) /* Combine an allocation into the first instruction. */ if (STACK_GROWS_DOWNWARD ? this_adjust <= 0 : this_adjust >= 0) { - if (try_apply_stack_adjustment (last_sp_set, reflist, - last_sp_adjust + this_adjust, - this_adjust)) + if (no_unhandled_cfa (insn) + && try_apply_stack_adjustment (last_sp_set, reflist, + last_sp_adjust + + this_adjust, + this_adjust)) { /* It worked! */ maybe_move_args_size_note (last_sp_set, insn, false); + maybe_merge_cfa_adjust (last_sp_set, insn, false); delete_insn (insn); last_sp_adjust += this_adjust; continue; @@ -508,12 +587,15 @@ combine_stack_adjustments_for_block (basic_block bb) else if (STACK_GROWS_DOWNWARD ? last_sp_adjust >= 0 : last_sp_adjust <= 0) { - if (try_apply_stack_adjustment (insn, reflist, - last_sp_adjust + this_adjust, - -last_sp_adjust)) + if (no_unhandled_cfa (last_sp_set) + && try_apply_stack_adjustment (insn, reflist, + last_sp_adjust + + this_adjust, + -last_sp_adjust)) { /* It worked! */ maybe_move_args_size_note (insn, last_sp_set, true); + maybe_merge_cfa_adjust (insn, last_sp_set, true); delete_insn (last_sp_set); last_sp_set = insn; last_sp_adjust += this_adjust; @@ -528,9 +610,10 @@ combine_stack_adjustments_for_block (basic_block bb) delete the old deallocation insn. */ if (last_sp_set) { - if (last_sp_adjust == 0) + if (last_sp_adjust == 0 && no_unhandled_cfa (last_sp_set)) { maybe_move_args_size_note (insn, last_sp_set, true); + maybe_merge_cfa_adjust (insn, last_sp_set, true); delete_insn (last_sp_set); } else diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 139ea44dfcb..b052a704106 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2014-10-13 Richard Henderson + + * g++.dg/torture/20141013.C: New. + 2014-10-13 Evgeny Stupachenko PR target/8340 diff --git a/gcc/testsuite/g++.dg/torture/20141013.C b/gcc/testsuite/g++.dg/torture/20141013.C new file mode 100644 index 00000000000..529ef0965e4 --- /dev/null +++ b/gcc/testsuite/g++.dg/torture/20141013.C @@ -0,0 +1,267 @@ +enum +{ + _sch_isdigit = 0x0004, + _sch_ispunct = 0x0020, + _sch_isxdigit = 0x0100, + _sch_isidst = 0x0200, + _sch_isvsp = 0x0400, + _sch_isnvsp = 0x0800, + _sch_isalnum = _sch_isidst | _sch_isdigit, + _sch_iscppsp = _sch_isvsp | _sch_isnvsp, +}; +extern const unsigned short _sch_istable[256]; +typedef union tree_node *tree; +typedef const union tree_node *const_tree; +enum opt_code +{ + OPT_Warray_bounds = 240, + OPT_Wformat_ = 245, + OPT_Wintf_annotation = 368, + OPT_std_gnu__14 = 1311, +}; +enum tree_code +{ + TREE_LIST, + CONST_DECL, + ADDR_EXPR, + MAX_TREE_CODES +}; +enum tree_code_class +{ + tcc_type, +}; +enum tree_node_structure_enum +{ + TS_TYPED, + TS_COMMON, +}; +enum integer_type_kind +{ + itk_char, + itk_none +}; +struct tree_base +{ + enum tree_code code:16; +}; +struct tree_typed +{ + tree type; +}; +struct tree_common +{ + tree chain; +}; +struct tree_list +{ + tree purpose; +}; +struct tree_type_common +{ + tree main_variant; +}; +union tree_node +{ + struct tree_base base; + struct tree_typed typed; + struct tree_common common; + struct tree_type_common type_common; + struct tree_list list; +}; +extern unsigned char tree_contains_struct[MAX_TREE_CODES][64]; +extern tree integer_types[itk_none]; +extern void tree_contains_struct_check_failed (const_tree, + tree_node_structure_enum, + const char *, int, + const char *) + __attribute__ ((__noreturn__)); +inline tree +tree_check (tree __t, const char *__f, int __l, const char *__g, + tree_code __c) +{ +} + +inline const_tree +contains_struct_check (const_tree __t, + const enum tree_node_structure_enum __s, + const char *__f, int __l, const char *__g) +{ + if (tree_contains_struct[((enum tree_code) (__t)->base.code)][__s] != 1) + tree_contains_struct_check_failed (__t, __s, __f, __l, __g); +} + +inline const_tree +tree_class_check (const_tree __t, const enum tree_code_class __class, + const char *__f, int __l, const char *__g) +{ +} + +static inline bool +is_attribute_p (const char *attr_name, const_tree ident) +{ +} + +extern int integer_zerop (const_tree); +extern bool warning (int, const char *, ...) + __attribute__ ((__nonnull__ (2))); +extern void +check_function_arguments_recurse (void (*)(void *, tree, unsigned long long), + void *, tree, unsigned long long); +extern bool objc_string_ref_type_p (tree); +enum +{ + FMT_FLAG_SCANF_A_KLUDGE = 2, + FMT_FLAG_PARSE_ARG_CONVERT_EXTERNAL = 256 +}; +typedef struct +{ +} +format_flag_spec; +typedef struct +{ + int flags; + tree *width_type; +} +format_kind_info; +typedef struct alloc_pool_list_def +{ +} + *alloc_pool; +struct gcc_targetcm +{ + bool (*string_object_ref_type_p) (const_tree stringref); +} + ; +extern struct gcc_targetcm targetcm; +enum format_type +{ + gcc_objc_string_format_type, +}; +typedef struct function_format_info +{ + int format_type; +} +function_format_info; +static const format_kind_info format_types_orig[] = { }; +struct format_check_context { }; + +static const format_kind_info *format_types = format_types_orig; +static void check_format_info (function_format_info *, tree); +void check_format_arg (void *, tree, unsigned long long); + +void +check_function_format (tree attrs, int nargs, tree * argarray) +{ + tree a; + for (a = attrs; + a; + ((contains_struct_check + ((a), (TS_COMMON), "../../git-master/gcc/c-family/c-format.c", 1002, + __FUNCTION__))->common.chain)) + { + if (is_attribute_p + ("format", + ((tree_check + ((a), "../../git-master/gcc/c-family/c-format.c", 1004, + __FUNCTION__, (TREE_LIST)))->list.purpose))) + { + function_format_info info; + { + tree params = (tree) __null; + check_format_info (&info, params); + } + } + } +} + +static bool +avoid_dollar_number (const char *format) +{ + while ((_sch_istable[(*format) & 0xff] & (unsigned short) (_sch_isdigit))) + format++; + if (*format == '$') + { + warning (OPT_Wformat_, + "$ operand number used after format without operand number"); + } +} + +static void +check_format_info (function_format_info * info, tree params) +{ + format_check_context format_ctx; + unsigned long long arg_num; + tree format_tree; + check_function_arguments_recurse (check_format_arg, &format_ctx, + format_tree, arg_num); + const char *format_chars; + if (integer_zerop (format_tree)) + { + { + ((contains_struct_check + ((params), (TS_COMMON), + "../../git-master/gcc/c-family/c-format.c", 1444, + __FUNCTION__))->common.chain); + } + return; + } + if (((enum tree_code) (format_tree)->base.code) != ADDR_EXPR) + { + return; + } + if (format_types[info->format_type].flags & (int) + FMT_FLAG_PARSE_ARG_CONVERT_EXTERNAL) + { + bool objc_str = (info->format_type == gcc_objc_string_format_type); + if (((enum tree_code) (format_tree)->base.code) != CONST_DECL + || + !((objc_str + && + objc_string_ref_type_p (((contains_struct_check + ((format_tree), (TS_TYPED), + "../../git-master/gcc/c-family/c-format.c", + 1498, __FUNCTION__))->typed.type))) + || + (*targetcm.string_object_ref_type_p) ((const_tree) + ((contains_struct_check + ((format_tree), + (TS_TYPED), + "../../git-master/gcc/c-family/c-format.c", + 1500, + __FUNCTION__))->typed. + type)))) + { + } + } + { + } + if (((tree_class_check + ((((contains_struct_check + ((((contains_struct_check + ((format_tree), (TS_TYPED), + "../../git-master/gcc/c-family/c-format.c", 1549, + __FUNCTION__))->typed.type)), (TS_TYPED), + "../../git-master/gcc/c-family/c-format.c", 1549, + __FUNCTION__))->typed.type)), (tcc_type), + "../../git-master/gcc/c-family/c-format.c", 1549, + __FUNCTION__))->type_common.main_variant) != integer_types[itk_char]) + { + return; + } + { + } + const format_kind_info *fki = &format_types[info->format_type]; + while (*format_chars != 0) + { + { + if (fki->width_type != __null && *format_chars == '*') + { + { + if (avoid_dollar_number (format_chars)) + if (avoid_dollar_number (format_chars)) + return; + } + } + } + } +} -- 2.30.2