diff options
author | Dan Albert <danalbert@google.com> | 2015-06-17 11:09:54 -0700 |
---|---|---|
committer | Dan Albert <danalbert@google.com> | 2015-06-17 14:15:22 -0700 |
commit | f378ebf14df0952eae870c9865bab8326aa8f137 (patch) | |
tree | 31794503eb2a8c64ea5f313b93100f1163afcffb /gcc-4.4.3/gcc/auto-inc-dec.c | |
parent | 2c58169824949d3a597d9fa81931e001ef9b1bd0 (diff) | |
download | toolchain_gcc-f378ebf14df0952eae870c9865bab8326aa8f137.tar.gz toolchain_gcc-f378ebf14df0952eae870c9865bab8326aa8f137.tar.bz2 toolchain_gcc-f378ebf14df0952eae870c9865bab8326aa8f137.zip |
Delete old versions of GCC.
Change-Id: I710f125d905290e1024cbd67f48299861790c66c
Diffstat (limited to 'gcc-4.4.3/gcc/auto-inc-dec.c')
-rw-r--r-- | gcc-4.4.3/gcc/auto-inc-dec.c | 1562 |
1 files changed, 0 insertions, 1562 deletions
diff --git a/gcc-4.4.3/gcc/auto-inc-dec.c b/gcc-4.4.3/gcc/auto-inc-dec.c deleted file mode 100644 index 86b5a2c6f..000000000 --- a/gcc-4.4.3/gcc/auto-inc-dec.c +++ /dev/null @@ -1,1562 +0,0 @@ -/* Discovery of auto-inc and auto-dec instructions. - Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc. - Contributed by Kenneth Zadeck <zadeck@naturalbridge.com> - -This file is part of GCC. - -GCC is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 3, or (at your option) any later -version. - -GCC is distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" -#include "tree.h" -#include "rtl.h" -#include "tm_p.h" -#include "hard-reg-set.h" -#include "basic-block.h" -#include "insn-config.h" -#include "regs.h" -#include "flags.h" -#include "output.h" -#include "function.h" -#include "except.h" -#include "toplev.h" -#include "recog.h" -#include "expr.h" -#include "timevar.h" -#include "tree-pass.h" -#include "df.h" -#include "dbgcnt.h" - -/* This pass was originally removed from flow.c. However there is - almost nothing that remains of that code. - - There are (4) basic forms that are matched: - - a <- b + c - ... - *a - - becomes - - a <- b - ... - *(a += c) pre - a += c - ... - *a - - becomes - - *(a += c) pre - *a - ... - b <- a + c - - for this case to be true, b must not be assigned or used between - the *a and the assignment to b. B must also be a Pmode reg. - - becomes - - b <- a - ... - *(b += c) post - *a - ... - a <- a + c - - becomes - - *(a += c) post - - There are three types of values of c. - - 1) c is a constant equal to the width of the value being accessed by - the pointer. This is useful for machines that have - HAVE_PRE_INCREMENT, HAVE_POST_INCREMENT, HAVE_PRE_DECREMENT or - HAVE_POST_DECREMENT defined. - - 2) c is a constant not equal to the width of the value being accessed - by the pointer. This is useful for machines that have - HAVE_PRE_MODIFY_DISP, HAVE_POST_MODIFY_DISP defined. - - 3) c is a register. This is useful for machines that have - HAVE_PRE_MODIFY_REG, HAVE_POST_MODIFY_REG - - The is one special case: if a already had an offset equal to it +- - its width and that offset is equal to -c when the increment was - before the ref or +c if the increment was after the ref, then if we - can do the combination but switch the pre/post bit. - - (1) FORM_PRE_ADD - - a <- b + c - ... - *(a - c) - - becomes - - a <- b - ... - *(a += c) post - - (2) FORM_PRE_INC - - a += c - ... - *(a - c) - - becomes - - *(a += c) post - - (3) FORM_POST_ADD - - *(a + c) - ... - b <- a + c - - for this case to be true, b must not be assigned or used between - the *a and the assignment to b. B must also be a Pmode reg. - - becomes - - b <- a - ... - *(b += c) pre - - - (4) FORM_POST_INC - - *(a + c) - ... - a <- a + c - - becomes - - *(a += c) pre -*/ -#ifdef AUTO_INC_DEC - -enum form -{ - FORM_PRE_ADD, - FORM_PRE_INC, - FORM_POST_ADD, - FORM_POST_INC, - FORM_last -}; - -/* The states of the second operands of mem refs and inc insns. If no - second operand of the mem_ref was found, it is assumed to just be - ZERO. SIZE is the size of the mode accessed in the memref. The - ANY is used for constants that are not +-size or 0. REG is used if - the forms are reg1 + reg2. */ - -enum inc_state -{ - INC_ZERO, /* == 0 */ - INC_NEG_SIZE, /* == +size */ - INC_POS_SIZE, /* == -size */ - INC_NEG_ANY, /* == some -constant */ - INC_POS_ANY, /* == some +constant */ - INC_REG, /* == some register */ - INC_last -}; - -/* The eight forms that pre/post inc/dec can take. */ -enum gen_form -{ - NOTHING, - SIMPLE_PRE_INC, /* ++size */ - SIMPLE_POST_INC, /* size++ */ - SIMPLE_PRE_DEC, /* --size */ - SIMPLE_POST_DEC, /* size-- */ - DISP_PRE, /* ++con */ - DISP_POST, /* con++ */ - REG_PRE, /* ++reg */ - REG_POST /* reg++ */ -}; - -/* Tmp mem rtx for use in cost modeling. */ -static rtx mem_tmp; - -static enum inc_state -set_inc_state (HOST_WIDE_INT val, int size) -{ - if (val == 0) - return INC_ZERO; - if (val < 0) - return (val == -size) ? INC_NEG_SIZE : INC_NEG_ANY; - else - return (val == size) ? INC_POS_SIZE : INC_POS_ANY; -} - -/* The DECISION_TABLE that describes what form, if any, the increment - or decrement will take. It is a three dimensional table. The first - index is the type of constant or register found as the second - operand of the inc insn. The second index is the type of constant - or register found as the second operand of the memory reference (if - no second operand exists, 0 is used). The third index is the form - and location (relative to the mem reference) of inc insn. */ - -static bool initialized = false; -static enum gen_form decision_table[INC_last][INC_last][FORM_last]; - -static void -init_decision_table (void) -{ - enum gen_form value; - - if (HAVE_PRE_INCREMENT || HAVE_PRE_MODIFY_DISP) - { - /* Prefer the simple form if both are available. */ - value = (HAVE_PRE_INCREMENT) ? SIMPLE_PRE_INC : DISP_PRE; - - decision_table[INC_POS_SIZE][INC_ZERO][FORM_PRE_ADD] = value; - decision_table[INC_POS_SIZE][INC_ZERO][FORM_PRE_INC] = value; - - decision_table[INC_POS_SIZE][INC_POS_SIZE][FORM_POST_ADD] = value; - decision_table[INC_POS_SIZE][INC_POS_SIZE][FORM_POST_INC] = value; - } - - if (HAVE_POST_INCREMENT || HAVE_POST_MODIFY_DISP) - { - /* Prefer the simple form if both are available. */ - value = (HAVE_POST_INCREMENT) ? SIMPLE_POST_INC : DISP_POST; - - decision_table[INC_POS_SIZE][INC_ZERO][FORM_POST_ADD] = value; - decision_table[INC_POS_SIZE][INC_ZERO][FORM_POST_INC] = value; - - decision_table[INC_POS_SIZE][INC_NEG_SIZE][FORM_PRE_ADD] = value; - decision_table[INC_POS_SIZE][INC_NEG_SIZE][FORM_PRE_INC] = value; - } - - if (HAVE_PRE_DECREMENT || HAVE_PRE_MODIFY_DISP) - { - /* Prefer the simple form if both are available. */ - value = (HAVE_PRE_DECREMENT) ? SIMPLE_PRE_DEC : DISP_PRE; - - decision_table[INC_NEG_SIZE][INC_ZERO][FORM_PRE_ADD] = value; - decision_table[INC_NEG_SIZE][INC_ZERO][FORM_PRE_INC] = value; - - decision_table[INC_NEG_SIZE][INC_NEG_SIZE][FORM_POST_ADD] = value; - decision_table[INC_NEG_SIZE][INC_NEG_SIZE][FORM_POST_INC] = value; - } - - if (HAVE_POST_DECREMENT || HAVE_POST_MODIFY_DISP) - { - /* Prefer the simple form if both are available. */ - value = (HAVE_POST_DECREMENT) ? SIMPLE_POST_DEC : DISP_POST; - - decision_table[INC_NEG_SIZE][INC_ZERO][FORM_POST_ADD] = value; - decision_table[INC_NEG_SIZE][INC_ZERO][FORM_POST_INC] = value; - - decision_table[INC_NEG_SIZE][INC_POS_SIZE][FORM_PRE_ADD] = value; - decision_table[INC_NEG_SIZE][INC_POS_SIZE][FORM_PRE_INC] = value; - } - - if (HAVE_PRE_MODIFY_DISP) - { - decision_table[INC_POS_ANY][INC_ZERO][FORM_PRE_ADD] = DISP_PRE; - decision_table[INC_POS_ANY][INC_ZERO][FORM_PRE_INC] = DISP_PRE; - - decision_table[INC_POS_ANY][INC_POS_ANY][FORM_POST_ADD] = DISP_PRE; - decision_table[INC_POS_ANY][INC_POS_ANY][FORM_POST_INC] = DISP_PRE; - - decision_table[INC_NEG_ANY][INC_ZERO][FORM_PRE_ADD] = DISP_PRE; - decision_table[INC_NEG_ANY][INC_ZERO][FORM_PRE_INC] = DISP_PRE; - - decision_table[INC_NEG_ANY][INC_NEG_ANY][FORM_POST_ADD] = DISP_PRE; - decision_table[INC_NEG_ANY][INC_NEG_ANY][FORM_POST_INC] = DISP_PRE; - } - - if (HAVE_POST_MODIFY_DISP) - { - decision_table[INC_POS_ANY][INC_ZERO][FORM_POST_ADD] = DISP_POST; - decision_table[INC_POS_ANY][INC_ZERO][FORM_POST_INC] = DISP_POST; - - decision_table[INC_POS_ANY][INC_NEG_ANY][FORM_PRE_ADD] = DISP_POST; - decision_table[INC_POS_ANY][INC_NEG_ANY][FORM_PRE_INC] = DISP_POST; - - decision_table[INC_NEG_ANY][INC_ZERO][FORM_POST_ADD] = DISP_POST; - decision_table[INC_NEG_ANY][INC_ZERO][FORM_POST_INC] = DISP_POST; - - decision_table[INC_NEG_ANY][INC_POS_ANY][FORM_PRE_ADD] = DISP_POST; - decision_table[INC_NEG_ANY][INC_POS_ANY][FORM_PRE_INC] = DISP_POST; - } - - /* This is much simpler than the other cases because we do not look - for the reg1-reg2 case. Note that we do not have a INC_POS_REG - and INC_NEG_REG states. Most of the use of such states would be - on a target that had an R1 - R2 update address form. - - There is the remote possibility that you could also catch a = a + - b; *(a - b) as a postdecrement of (a + b). However, it is - unclear if *(a - b) would ever be generated on a machine that did - not have that kind of addressing mode. The IA-64 and RS6000 will - not do this, and I cannot speak for any other. If any - architecture does have an a-b update for, these cases should be - added. */ - if (HAVE_PRE_MODIFY_REG) - { - decision_table[INC_REG][INC_ZERO][FORM_PRE_ADD] = REG_PRE; - decision_table[INC_REG][INC_ZERO][FORM_PRE_INC] = REG_PRE; - - decision_table[INC_REG][INC_REG][FORM_POST_ADD] = REG_PRE; - decision_table[INC_REG][INC_REG][FORM_POST_INC] = REG_PRE; - } - - if (HAVE_POST_MODIFY_REG) - { - decision_table[INC_REG][INC_ZERO][FORM_POST_ADD] = REG_POST; - decision_table[INC_REG][INC_ZERO][FORM_POST_INC] = REG_POST; - } - - initialized = true; -} - -/* Parsed fields of an inc insn of the form "reg_res = reg0+reg1" or - "reg_res = reg0+c". */ - -static struct inc_insn -{ - rtx insn; /* The insn being parsed. */ - rtx pat; /* The pattern of the insn. */ - bool reg1_is_const; /* True if reg1 is const, false if reg1 is a reg. */ - enum form form; - rtx reg_res; - rtx reg0; - rtx reg1; - enum inc_state reg1_state;/* The form of the const if reg1 is a const. */ - HOST_WIDE_INT reg1_val;/* Value if reg1 is const. */ -} inc_insn; - - -/* Dump the parsed inc insn to FILE. */ - -static void -dump_inc_insn (FILE *file) -{ - const char *f = ((inc_insn.form == FORM_PRE_ADD) - || (inc_insn.form == FORM_PRE_INC)) ? "pre" : "post"; - - dump_insn_slim (file, inc_insn.insn); - - switch (inc_insn.form) - { - case FORM_PRE_ADD: - case FORM_POST_ADD: - if (inc_insn.reg1_is_const) - fprintf (file, "found %s add(%d) r[%d]=r[%d]+%d\n", - f, INSN_UID (inc_insn.insn), - REGNO (inc_insn.reg_res), - REGNO (inc_insn.reg0), (int) inc_insn.reg1_val); - else - fprintf (file, "found %s add(%d) r[%d]=r[%d]+r[%d]\n", - f, INSN_UID (inc_insn.insn), - REGNO (inc_insn.reg_res), - REGNO (inc_insn.reg0), REGNO (inc_insn.reg1)); - break; - - case FORM_PRE_INC: - case FORM_POST_INC: - if (inc_insn.reg1_is_const) - fprintf (file, "found %s inc(%d) r[%d]+=%d\n", - f, INSN_UID (inc_insn.insn), - REGNO (inc_insn.reg_res), (int) inc_insn.reg1_val); - else - fprintf (file, "found %s inc(%d) r[%d]+=r[%d]\n", - f, INSN_UID (inc_insn.insn), - REGNO (inc_insn.reg_res), REGNO (inc_insn.reg1)); - break; - - default: - break; - } -} - - -/* Parsed fields of a mem ref of the form "*(reg0+reg1)" or "*(reg0+c)". */ - -static struct mem_insn -{ - rtx insn; /* The insn being parsed. */ - rtx pat; /* The pattern of the insn. */ - rtx *mem_loc; /* The address of the field that holds the mem */ - /* that is to be replaced. */ - bool reg1_is_const; /* True if reg1 is const, false if reg1 is a reg. */ - rtx reg0; - rtx reg1; /* This is either a reg or a const depending on - reg1_is_const. */ - enum inc_state reg1_state;/* The form of the const if reg1 is a const. */ - HOST_WIDE_INT reg1_val;/* Value if reg1 is const. */ -} mem_insn; - - -/* Dump the parsed mem insn to FILE. */ - -static void -dump_mem_insn (FILE *file) -{ - dump_insn_slim (file, mem_insn.insn); - - if (mem_insn.reg1_is_const) - fprintf (file, "found mem(%d) *(r[%d]+%d)\n", - INSN_UID (mem_insn.insn), - REGNO (mem_insn.reg0), (int) mem_insn.reg1_val); - else - fprintf (file, "found mem(%d) *(r[%d]+r[%d])\n", - INSN_UID (mem_insn.insn), - REGNO (mem_insn.reg0), REGNO (mem_insn.reg1)); -} - - -/* The following three arrays contain pointers to instructions. They - are indexed by REGNO. At any point in the basic block where we are - looking these three arrays contain, respectively, the next insn - that uses REGNO, the next inc or add insn that uses REGNO and the - next insn that sets REGNO. - - The arrays are not cleared when we move from block to block so - whenever an insn is retrieved from these arrays, it's block number - must be compared with the current block. -*/ - -static rtx *reg_next_use = NULL; -static rtx *reg_next_inc_use = NULL; -static rtx *reg_next_def = NULL; - - -/* Move dead note that match PATTERN to TO_INSN from FROM_INSN. We do - not really care about moving any other notes from the inc or add - insn. Moving the REG_EQUAL and REG_EQUIV is clearly wrong and it - does not appear that there are any other kinds of relevant notes. */ - -static void -move_dead_notes (rtx to_insn, rtx from_insn, rtx pattern) -{ - rtx note; - rtx next_note; - rtx prev_note = NULL; - - for (note = REG_NOTES (from_insn); note; note = next_note) - { - next_note = XEXP (note, 1); - - if ((REG_NOTE_KIND (note) == REG_DEAD) - && pattern == XEXP (note, 0)) - { - XEXP (note, 1) = REG_NOTES (to_insn); - REG_NOTES (to_insn) = note; - if (prev_note) - XEXP (prev_note, 1) = next_note; - else - REG_NOTES (from_insn) = next_note; - } - else prev_note = note; - } -} - - -/* Create a mov insn DEST_REG <- SRC_REG and insert it before - NEXT_INSN. */ - -static rtx -insert_move_insn_before (rtx next_insn, rtx dest_reg, rtx src_reg) -{ - rtx insns; - - start_sequence (); - emit_move_insn (dest_reg, src_reg); - insns = get_insns (); - end_sequence (); - emit_insn_before (insns, next_insn); - return insns; -} - - -/* Change mem_insn.mem_loc so that uses NEW_ADDR which has an - increment of INC_REG. To have reached this point, the change is a - legitimate one from a dataflow point of view. The only questions - are is this a valid change to the instruction and is this a - profitable change to the instruction. */ - -static bool -attempt_change (rtx new_addr, rtx inc_reg) -{ - /* There are four cases: For the two cases that involve an add - instruction, we are going to have to delete the add and insert a - mov. We are going to assume that the mov is free. This is - fairly early in the backend and there are a lot of opportunities - for removing that move later. In particular, there is the case - where the move may be dead, this is what dead code elimination - passes are for. The two cases where we have an inc insn will be - handled mov free. */ - - basic_block bb = BASIC_BLOCK (BLOCK_NUM (mem_insn.insn)); - rtx mov_insn = NULL; - int regno; - rtx mem = *mem_insn.mem_loc; - enum machine_mode mode = GET_MODE (mem); - rtx new_mem; - int old_cost = 0; - int new_cost = 0; - bool speed = optimize_bb_for_speed_p (bb); - - PUT_MODE (mem_tmp, mode); - XEXP (mem_tmp, 0) = new_addr; - - old_cost = rtx_cost (mem, 0, speed) - + rtx_cost (PATTERN (inc_insn.insn), 0, speed); - new_cost = rtx_cost (mem_tmp, 0, speed); - - /* The first item of business is to see if this is profitable. */ - if (old_cost < new_cost) - { - if (dump_file) - fprintf (dump_file, "cost failure old=%d new=%d\n", old_cost, new_cost); - return false; - } - - /* Jump thru a lot of hoops to keep the attributes up to date. We - do not want to call one of the change address variants that take - an offset even though we know the offset in many cases. These - assume you are changing where the address is pointing by the - offset. */ - new_mem = replace_equiv_address_nv (mem, new_addr); - if (! validate_change (mem_insn.insn, mem_insn.mem_loc, new_mem, 0)) - { - if (dump_file) - fprintf (dump_file, "validation failure\n"); - return false; - } - - /* From here to the end of the function we are committed to the - change, i.e. nothing fails. Generate any necessary movs, move - any regnotes, and fix up the reg_next_{use,inc_use,def}. */ - switch (inc_insn.form) - { - case FORM_PRE_ADD: - /* Replace the addition with a move. Do it at the location of - the addition since the operand of the addition may change - before the memory reference. */ - mov_insn = insert_move_insn_before (inc_insn.insn, - inc_insn.reg_res, inc_insn.reg0); - move_dead_notes (mov_insn, inc_insn.insn, inc_insn.reg0); - - regno = REGNO (inc_insn.reg_res); - reg_next_def[regno] = mov_insn; - reg_next_use[regno] = NULL; - regno = REGNO (inc_insn.reg0); - reg_next_use[regno] = mov_insn; - df_recompute_luids (bb); - break; - - case FORM_POST_INC: - regno = REGNO (inc_insn.reg_res); - if (reg_next_use[regno] == reg_next_inc_use[regno]) - reg_next_inc_use[regno] = NULL; - - /* Fallthru. */ - case FORM_PRE_INC: - regno = REGNO (inc_insn.reg_res); - reg_next_def[regno] = mem_insn.insn; - reg_next_use[regno] = NULL; - - break; - - case FORM_POST_ADD: - mov_insn = insert_move_insn_before (mem_insn.insn, - inc_insn.reg_res, inc_insn.reg0); - move_dead_notes (mov_insn, inc_insn.insn, inc_insn.reg0); - - /* Do not move anything to the mov insn because the instruction - pointer for the main iteration has not yet hit that. It is - still pointing to the mem insn. */ - regno = REGNO (inc_insn.reg_res); - reg_next_def[regno] = mem_insn.insn; - reg_next_use[regno] = NULL; - - regno = REGNO (inc_insn.reg0); - reg_next_use[regno] = mem_insn.insn; - if ((reg_next_use[regno] == reg_next_inc_use[regno]) - || (reg_next_inc_use[regno] == inc_insn.insn)) - reg_next_inc_use[regno] = NULL; - df_recompute_luids (bb); - break; - - case FORM_last: - default: - gcc_unreachable (); - } - - if (!inc_insn.reg1_is_const) - { - regno = REGNO (inc_insn.reg1); - reg_next_use[regno] = mem_insn.insn; - if ((reg_next_use[regno] == reg_next_inc_use[regno]) - || (reg_next_inc_use[regno] == inc_insn.insn)) - reg_next_inc_use[regno] = NULL; - } - - delete_insn (inc_insn.insn); - - if (dump_file && mov_insn) - { - fprintf (dump_file, "inserting mov "); - dump_insn_slim (dump_file, mov_insn); - } - - /* Record that this insn has an implicit side effect. */ - add_reg_note (mem_insn.insn, REG_INC, inc_reg); - - if (dump_file) - { - fprintf (dump_file, "****success "); - dump_insn_slim (dump_file, mem_insn.insn); - } - - return true; -} - - -/* Try to combine the instruction in INC_INSN with the instruction in - MEM_INSN. First the form is determined using the DECISION_TABLE - and the results of parsing the INC_INSN and the MEM_INSN. - Assuming the form is ok, a prototype new address is built which is - passed to ATTEMPT_CHANGE for final processing. */ - -static bool -try_merge (void) -{ - enum gen_form gen_form; - rtx mem = *mem_insn.mem_loc; - rtx inc_reg = inc_insn.form == FORM_POST_ADD ? - inc_insn.reg_res : mem_insn.reg0; - - /* The width of the mem being accessed. */ - int size = GET_MODE_SIZE (GET_MODE (mem)); - rtx last_insn = NULL; - - switch (inc_insn.form) - { - case FORM_PRE_ADD: - case FORM_PRE_INC: - last_insn = mem_insn.insn; - break; - case FORM_POST_INC: - case FORM_POST_ADD: - last_insn = inc_insn.insn; - break; - case FORM_last: - default: - gcc_unreachable (); - } - - /* Cannot handle auto inc of the stack. */ - if (inc_reg == stack_pointer_rtx) - { - if (dump_file) - fprintf (dump_file, "cannot inc stack %d failure\n", REGNO (inc_reg)); - return false; - } - - /* Look to see if the inc register is dead after the memory - reference. If it is, do not do the combination. */ - if (find_regno_note (last_insn, REG_DEAD, REGNO (inc_reg))) - { - if (dump_file) - fprintf (dump_file, "dead failure %d\n", REGNO (inc_reg)); - return false; - } - - mem_insn.reg1_state = (mem_insn.reg1_is_const) - ? set_inc_state (mem_insn.reg1_val, size) : INC_REG; - inc_insn.reg1_state = (inc_insn.reg1_is_const) - ? set_inc_state (inc_insn.reg1_val, size) : INC_REG; - - /* Now get the form that we are generating. */ - gen_form = decision_table - [inc_insn.reg1_state][mem_insn.reg1_state][inc_insn.form]; - - if (dbg_cnt (auto_inc_dec) == false) - return false; - - switch (gen_form) - { - default: - case NOTHING: - return false; - - case SIMPLE_PRE_INC: /* ++size */ - if (dump_file) - fprintf (dump_file, "trying SIMPLE_PRE_INC\n"); - return attempt_change (gen_rtx_PRE_INC (Pmode, inc_reg), inc_reg); - break; - - case SIMPLE_POST_INC: /* size++ */ - if (dump_file) - fprintf (dump_file, "trying SIMPLE_POST_INC\n"); - return attempt_change (gen_rtx_POST_INC (Pmode, inc_reg), inc_reg); - break; - - case SIMPLE_PRE_DEC: /* --size */ - if (dump_file) - fprintf (dump_file, "trying SIMPLE_PRE_DEC\n"); - return attempt_change (gen_rtx_PRE_DEC (Pmode, inc_reg), inc_reg); - break; - - case SIMPLE_POST_DEC: /* size-- */ - if (dump_file) - fprintf (dump_file, "trying SIMPLE_POST_DEC\n"); - return attempt_change (gen_rtx_POST_DEC (Pmode, inc_reg), inc_reg); - break; - - case DISP_PRE: /* ++con */ - if (dump_file) - fprintf (dump_file, "trying DISP_PRE\n"); - return attempt_change (gen_rtx_PRE_MODIFY (Pmode, - inc_reg, - gen_rtx_PLUS (Pmode, - inc_reg, - inc_insn.reg1)), - inc_reg); - break; - - case DISP_POST: /* con++ */ - if (dump_file) - fprintf (dump_file, "trying POST_DISP\n"); - return attempt_change (gen_rtx_POST_MODIFY (Pmode, - inc_reg, - gen_rtx_PLUS (Pmode, - inc_reg, - inc_insn.reg1)), - inc_reg); - break; - - case REG_PRE: /* ++reg */ - if (dump_file) - fprintf (dump_file, "trying PRE_REG\n"); - return attempt_change (gen_rtx_PRE_MODIFY (Pmode, - inc_reg, - gen_rtx_PLUS (Pmode, - inc_reg, - inc_insn.reg1)), - inc_reg); - break; - - case REG_POST: /* reg++ */ - if (dump_file) - fprintf (dump_file, "trying POST_REG\n"); - return attempt_change (gen_rtx_POST_MODIFY (Pmode, - inc_reg, - gen_rtx_PLUS (Pmode, - inc_reg, - inc_insn.reg1)), - inc_reg); - break; - } -} - -/* Return the next insn that uses (if reg_next_use is passed in - NEXT_ARRAY) or defines (if reg_next_def is passed in NEXT_ARRAY) - REGNO in BB. */ - -static rtx -get_next_ref (int regno, basic_block bb, rtx *next_array) -{ - rtx insn = next_array[regno]; - - /* Lazy about cleaning out the next_arrays. */ - if (insn && BASIC_BLOCK (BLOCK_NUM (insn)) != bb) - { - next_array[regno] = NULL; - insn = NULL; - } - - return insn; -} - - -/* Reverse the operands in a mem insn. */ - -static void -reverse_mem (void) -{ - rtx tmp = mem_insn.reg1; - mem_insn.reg1 = mem_insn.reg0; - mem_insn.reg0 = tmp; -} - - -/* Reverse the operands in a inc insn. */ - -static void -reverse_inc (void) -{ - rtx tmp = inc_insn.reg1; - inc_insn.reg1 = inc_insn.reg0; - inc_insn.reg0 = tmp; -} - - -/* Return true if INSN is of a form "a = b op c" where a and b are - regs. op is + if c is a reg and +|- if c is a const. Fill in - INC_INSN with what is found. - - This function is called in two contexts, if BEFORE_MEM is true, - this is called for each insn in the basic block. If BEFORE_MEM is - false, it is called for the instruction in the block that uses the - index register for some memory reference that is currently being - processed. */ - -static bool -parse_add_or_inc (rtx insn, bool before_mem) -{ - rtx pat = single_set (insn); - if (!pat) - return false; - - /* Result must be single reg. */ - if (!REG_P (SET_DEST (pat))) - return false; - - if ((GET_CODE (SET_SRC (pat)) != PLUS) - && (GET_CODE (SET_SRC (pat)) != MINUS)) - return false; - - if (!REG_P (XEXP (SET_SRC (pat), 0))) - return false; - - inc_insn.insn = insn; - inc_insn.pat = pat; - inc_insn.reg_res = SET_DEST (pat); - inc_insn.reg0 = XEXP (SET_SRC (pat), 0); - if (rtx_equal_p (inc_insn.reg_res, inc_insn.reg0)) - inc_insn.form = before_mem ? FORM_PRE_INC : FORM_POST_INC; - else - inc_insn.form = before_mem ? FORM_PRE_ADD : FORM_POST_ADD; - - if (GET_CODE (XEXP (SET_SRC (pat), 1)) == CONST_INT) - { - /* Process a = b + c where c is a const. */ - inc_insn.reg1_is_const = true; - if (GET_CODE (SET_SRC (pat)) == PLUS) - { - inc_insn.reg1 = XEXP (SET_SRC (pat), 1); - inc_insn.reg1_val = INTVAL (inc_insn.reg1); - } - else - { - inc_insn.reg1_val = -INTVAL (XEXP (SET_SRC (pat), 1)); - inc_insn.reg1 = GEN_INT (inc_insn.reg1_val); - } - return true; - } - else if ((HAVE_PRE_MODIFY_REG || HAVE_POST_MODIFY_REG) - && (REG_P (XEXP (SET_SRC (pat), 1))) - && GET_CODE (SET_SRC (pat)) == PLUS) - { - /* Process a = b + c where c is a reg. */ - inc_insn.reg1 = XEXP (SET_SRC (pat), 1); - inc_insn.reg1_is_const = false; - - if (inc_insn.form == FORM_PRE_INC - || inc_insn.form == FORM_POST_INC) - return true; - else if (rtx_equal_p (inc_insn.reg_res, inc_insn.reg1)) - { - /* Reverse the two operands and turn *_ADD into *_INC since - a = c + a. */ - reverse_inc (); - inc_insn.form = before_mem ? FORM_PRE_INC : FORM_POST_INC; - return true; - } - else - return true; - } - - return false; -} - - -/* A recursive function that checks all of the mem uses in - ADDRESS_OF_X to see if any single one of them is compatible with - what has been found in inc_insn. - - -1 is returned for success. 0 is returned if nothing was found and - 1 is returned for failure. */ - -static int -find_address (rtx *address_of_x) -{ - rtx x = *address_of_x; - enum rtx_code code = GET_CODE (x); - const char *const fmt = GET_RTX_FORMAT (code); - int i; - int value = 0; - int tem; - - if (code == MEM && rtx_equal_p (XEXP (x, 0), inc_insn.reg_res)) - { - /* Match with *reg0. */ - mem_insn.mem_loc = address_of_x; - mem_insn.reg0 = inc_insn.reg_res; - mem_insn.reg1_is_const = true; - mem_insn.reg1_val = 0; - mem_insn.reg1 = GEN_INT (0); - return -1; - } - if (code == MEM && GET_CODE (XEXP (x, 0)) == PLUS - && rtx_equal_p (XEXP (XEXP (x, 0), 0), inc_insn.reg_res)) - { - rtx b = XEXP (XEXP (x, 0), 1); - mem_insn.mem_loc = address_of_x; - mem_insn.reg0 = inc_insn.reg_res; - mem_insn.reg1 = b; - mem_insn.reg1_is_const = inc_insn.reg1_is_const; - if (GET_CODE (b) == CONST_INT) - { - /* Match with *(reg0 + reg1) where reg1 is a const. */ - HOST_WIDE_INT val = INTVAL (b); - if (inc_insn.reg1_is_const - && (inc_insn.reg1_val == val || inc_insn.reg1_val == -val)) - { - mem_insn.reg1_val = val; - return -1; - } - } - else if (!inc_insn.reg1_is_const - && rtx_equal_p (inc_insn.reg1, b)) - /* Match with *(reg0 + reg1). */ - return -1; - } - - if (code == SIGN_EXTRACT || code == ZERO_EXTRACT) - { - /* If REG occurs inside a MEM used in a bit-field reference, - that is unacceptable. */ - if (find_address (&XEXP (x, 0))) - return 1; - } - - if (x == inc_insn.reg_res) - return 1; - - /* Time for some deep diving. */ - for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) - { - if (fmt[i] == 'e') - { - tem = find_address (&XEXP (x, i)); - /* If this is the first use, let it go so the rest of the - insn can be checked. */ - if (value == 0) - value = tem; - else if (tem != 0) - /* More than one match was found. */ - return 1; - } - else if (fmt[i] == 'E') - { - int j; - for (j = XVECLEN (x, i) - 1; j >= 0; j--) - { - tem = find_address (&XVECEXP (x, i, j)); - /* If this is the first use, let it go so the rest of - the insn can be checked. */ - if (value == 0) - value = tem; - else if (tem != 0) - /* More than one match was found. */ - return 1; - } - } - } - return value; -} - -/* Once a suitable mem reference has been found and the MEM_INSN - structure has been filled in, FIND_INC is called to see if there is - a suitable add or inc insn that follows the mem reference and - determine if it is suitable to merge. - - In the case where the MEM_INSN has two registers in the reference, - this function may be called recursively. The first time looking - for an add of the first register, and if that fails, looking for an - add of the second register. The FIRST_TRY parameter is used to - only allow the parameters to be reversed once. */ - -static bool -find_inc (bool first_try) -{ - rtx insn; - basic_block bb = BASIC_BLOCK (BLOCK_NUM (mem_insn.insn)); - rtx other_insn; - df_ref *def_rec; - - /* Make sure this reg appears only once in this insn. */ - if (count_occurrences (PATTERN (mem_insn.insn), mem_insn.reg0, 1) != 1) - { - if (dump_file) - fprintf (dump_file, "mem count failure\n"); - return false; - } - - if (dump_file) - dump_mem_insn (dump_file); - - /* Find the next use that is an inc. */ - insn = get_next_ref (REGNO (mem_insn.reg0), - BASIC_BLOCK (BLOCK_NUM (mem_insn.insn)), - reg_next_inc_use); - if (!insn) - return false; - - /* Even though we know the next use is an add or inc because it came - from the reg_next_inc_use, we must still reparse. */ - if (!parse_add_or_inc (insn, false)) - { - /* Next use was not an add. Look for one extra case. It could be - that we have: - - *(a + b) - ...= a; - ...= b + a - - if we reverse the operands in the mem ref we would - find this. Only try it once though. */ - if (first_try && !mem_insn.reg1_is_const) - { - reverse_mem (); - return find_inc (false); - } - else - return false; - } - - /* Need to assure that none of the operands of the inc instruction are - assigned to by the mem insn. */ - for (def_rec = DF_INSN_DEFS (mem_insn.insn); *def_rec; def_rec++) - { - df_ref def = *def_rec; - unsigned int regno = DF_REF_REGNO (def); - if ((regno == REGNO (inc_insn.reg0)) - || (regno == REGNO (inc_insn.reg_res))) - { - if (dump_file) - fprintf (dump_file, "inc conflicts with store failure.\n"); - return false; - } - if (!inc_insn.reg1_is_const && (regno == REGNO (inc_insn.reg1))) - { - if (dump_file) - fprintf (dump_file, "inc conflicts with store failure.\n"); - return false; - } - } - - if (dump_file) - dump_inc_insn (dump_file); - - if (inc_insn.form == FORM_POST_ADD) - { - /* Make sure that there is no insn that assigns to inc_insn.res - between the mem_insn and the inc_insn. */ - rtx other_insn = get_next_ref (REGNO (inc_insn.reg_res), - BASIC_BLOCK (BLOCK_NUM (mem_insn.insn)), - reg_next_def); - if (other_insn != inc_insn.insn) - { - if (dump_file) - fprintf (dump_file, - "result of add is assigned to between mem and inc insns.\n"); - return false; - } - - other_insn = get_next_ref (REGNO (inc_insn.reg_res), - BASIC_BLOCK (BLOCK_NUM (mem_insn.insn)), - reg_next_use); - if (other_insn - && (other_insn != inc_insn.insn) - && (DF_INSN_LUID (inc_insn.insn) > DF_INSN_LUID (other_insn))) - { - if (dump_file) - fprintf (dump_file, - "result of add is used between mem and inc insns.\n"); - return false; - } - - /* For the post_add to work, the result_reg of the inc must not be - used in the mem insn since this will become the new index - register. */ - if (count_occurrences (PATTERN (mem_insn.insn), inc_insn.reg_res, 1) != 0) - { - if (dump_file) - fprintf (dump_file, "base reg replacement failure.\n"); - return false; - } - } - - if (mem_insn.reg1_is_const) - { - if (mem_insn.reg1_val == 0) - { - if (!inc_insn.reg1_is_const) - { - /* The mem looks like *r0 and the rhs of the add has two - registers. */ - int luid = DF_INSN_LUID (inc_insn.insn); - if (inc_insn.form == FORM_POST_ADD) - { - /* The trick is that we are not going to increment r0, - we are going to increment the result of the add insn. - For this trick to be correct, the result reg of - the inc must be a valid addressing reg. */ - if (GET_MODE (inc_insn.reg_res) != Pmode) - { - if (dump_file) - fprintf (dump_file, "base reg mode failure.\n"); - return false; - } - - /* We also need to make sure that the next use of - inc result is after the inc. */ - other_insn - = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_use); - if (other_insn && luid > DF_INSN_LUID (other_insn)) - return false; - - if (!rtx_equal_p (mem_insn.reg0, inc_insn.reg0)) - reverse_inc (); - } - - other_insn - = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_def); - if (other_insn && luid > DF_INSN_LUID (other_insn)) - return false; - } - } - /* Both the inc/add and the mem have a constant. Need to check - that the constants are ok. */ - else if ((mem_insn.reg1_val != inc_insn.reg1_val) - && (mem_insn.reg1_val != -inc_insn.reg1_val)) - return false; - } - else - { - /* The mem insn is of the form *(a + b) where a and b are both - regs. It may be that in order to match the add or inc we - need to treat it as if it was *(b + a). It may also be that - the add is of the form a + c where c does not match b and - then we just abandon this. */ - - int luid = DF_INSN_LUID (inc_insn.insn); - rtx other_insn; - - /* Make sure this reg appears only once in this insn. */ - if (count_occurrences (PATTERN (mem_insn.insn), mem_insn.reg1, 1) != 1) - return false; - - if (inc_insn.form == FORM_POST_ADD) - { - /* For this trick to be correct, the result reg of the inc - must be a valid addressing reg. */ - if (GET_MODE (inc_insn.reg_res) != Pmode) - { - if (dump_file) - fprintf (dump_file, "base reg mode failure.\n"); - return false; - } - - if (rtx_equal_p (mem_insn.reg0, inc_insn.reg0)) - { - if (!rtx_equal_p (mem_insn.reg1, inc_insn.reg1)) - { - /* See comment above on find_inc (false) call. */ - if (first_try) - { - reverse_mem (); - return find_inc (false); - } - else - return false; - } - - /* Need to check that there are no assignments to b - before the add insn. */ - other_insn - = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_def); - if (other_insn && luid > DF_INSN_LUID (other_insn)) - return false; - /* All ok for the next step. */ - } - else - { - /* We know that mem_insn.reg0 must equal inc_insn.reg1 - or else we would not have found the inc insn. */ - reverse_mem (); - if (!rtx_equal_p (mem_insn.reg0, inc_insn.reg0)) - { - /* See comment above on find_inc (false) call. */ - if (first_try) - return find_inc (false); - else - return false; - } - /* To have gotten here know that. - *(b + a) - - ... = (b + a) - - We also know that the lhs of the inc is not b or a. We - need to make sure that there are no assignments to b - between the mem ref and the inc. */ - - other_insn - = get_next_ref (REGNO (inc_insn.reg0), bb, reg_next_def); - if (other_insn && luid > DF_INSN_LUID (other_insn)) - return false; - } - - /* Need to check that the next use of the add result is later than - add insn since this will be the reg incremented. */ - other_insn - = get_next_ref (REGNO (inc_insn.reg_res), bb, reg_next_use); - if (other_insn && luid > DF_INSN_LUID (other_insn)) - return false; - } - else /* FORM_POST_INC. There is less to check here because we - know that operands must line up. */ - { - if (!rtx_equal_p (mem_insn.reg1, inc_insn.reg1)) - /* See comment above on find_inc (false) call. */ - { - if (first_try) - { - reverse_mem (); - return find_inc (false); - } - else - return false; - } - - /* To have gotten here know that. - *(a + b) - - ... = (a + b) - - We also know that the lhs of the inc is not b. We need to make - sure that there are no assignments to b between the mem ref and - the inc. */ - other_insn - = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_def); - if (other_insn && luid > DF_INSN_LUID (other_insn)) - return false; - } - } - - if (inc_insn.form == FORM_POST_INC) - { - other_insn - = get_next_ref (REGNO (inc_insn.reg0), bb, reg_next_use); - /* When we found inc_insn, we were looking for the - next add or inc, not the next insn that used the - reg. Because we are going to increment the reg - in this form, we need to make sure that there - were no intervening uses of reg. */ - if (inc_insn.insn != other_insn) - return false; - } - - return try_merge (); -} - - -/* A recursive function that walks ADDRESS_OF_X to find all of the mem - uses in pat that could be used as an auto inc or dec. It then - calls FIND_INC for each one. */ - -static bool -find_mem (rtx *address_of_x) -{ - rtx x = *address_of_x; - enum rtx_code code = GET_CODE (x); - const char *const fmt = GET_RTX_FORMAT (code); - int i; - - if (code == MEM && REG_P (XEXP (x, 0))) - { - /* Match with *reg0. */ - mem_insn.mem_loc = address_of_x; - mem_insn.reg0 = XEXP (x, 0); - mem_insn.reg1_is_const = true; - mem_insn.reg1_val = 0; - mem_insn.reg1 = GEN_INT (0); - if (find_inc (true)) - return true; - } - if (code == MEM && GET_CODE (XEXP (x, 0)) == PLUS - && REG_P (XEXP (XEXP (x, 0), 0))) - { - rtx reg1 = XEXP (XEXP (x, 0), 1); - mem_insn.mem_loc = address_of_x; - mem_insn.reg0 = XEXP (XEXP (x, 0), 0); - mem_insn.reg1 = reg1; - if (GET_CODE (reg1) == CONST_INT) - { - mem_insn.reg1_is_const = true; - /* Match with *(reg0 + c) where c is a const. */ - mem_insn.reg1_val = INTVAL (reg1); - if (find_inc (true)) - return true; - } - else if (REG_P (reg1)) - { - /* Match with *(reg0 + reg1). */ - mem_insn.reg1_is_const = false; - if (find_inc (true)) - return true; - } - } - - if (code == SIGN_EXTRACT || code == ZERO_EXTRACT) - { - /* If REG occurs inside a MEM used in a bit-field reference, - that is unacceptable. */ - return false; - } - - /* Time for some deep diving. */ - for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) - { - if (fmt[i] == 'e') - { - if (find_mem (&XEXP (x, i))) - return true; - } - else if (fmt[i] == 'E') - { - int j; - for (j = XVECLEN (x, i) - 1; j >= 0; j--) - if (find_mem (&XVECEXP (x, i, j))) - return true; - } - } - return false; -} - - -/* Try to combine all incs and decs by constant values with memory - references in BB. */ - -static void -merge_in_block (int max_reg, basic_block bb) -{ - rtx insn; - rtx curr; - int success_in_block = 0; - - if (dump_file) - fprintf (dump_file, "\n\nstarting bb %d\n", bb->index); - - FOR_BB_INSNS_REVERSE_SAFE (bb, insn, curr) - { - unsigned int uid = INSN_UID (insn); - bool insn_is_add_or_inc = true; - - if (!INSN_P (insn)) - continue; - - /* This continue is deliberate. We do not want the uses of the - jump put into reg_next_use because it is not considered safe to - combine a preincrement with a jump. */ - if (JUMP_P (insn)) - continue; - - if (dump_file) - dump_insn_slim (dump_file, insn); - - /* Does this instruction increment or decrement a register? */ - if (parse_add_or_inc (insn, true)) - { - int regno = REGNO (inc_insn.reg_res); - /* Cannot handle case where there are three separate regs - before a mem ref. Too many moves would be needed to be - profitable. */ - if ((inc_insn.form == FORM_PRE_INC) || inc_insn.reg1_is_const) - { - mem_insn.insn = get_next_ref (regno, bb, reg_next_use); - if (mem_insn.insn) - { - bool ok = true; - if (!inc_insn.reg1_is_const) - { - /* We are only here if we are going to try a - HAVE_*_MODIFY_REG type transformation. c is a - reg and we must sure that the path from the - inc_insn to the mem_insn.insn is both def and use - clear of c because the inc insn is going to move - into the mem_insn.insn. */ - int luid = DF_INSN_LUID (mem_insn.insn); - rtx other_insn - = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_use); - - if (other_insn && luid > DF_INSN_LUID (other_insn)) - ok = false; - - other_insn - = get_next_ref (REGNO (inc_insn.reg1), bb, reg_next_def); - - if (other_insn && luid > DF_INSN_LUID (other_insn)) - ok = false; - } - - if (dump_file) - dump_inc_insn (dump_file); - - if (ok && find_address (&PATTERN (mem_insn.insn)) == -1) - { - if (dump_file) - dump_mem_insn (dump_file); - if (try_merge ()) - { - success_in_block++; - insn_is_add_or_inc = false; - } - } - } - } - } - else - { - insn_is_add_or_inc = false; - mem_insn.insn = insn; - if (find_mem (&PATTERN (insn))) - success_in_block++; - } - - /* If the inc insn was merged with a mem, the inc insn is gone - and there is noting to update. */ - if (DF_INSN_UID_GET(uid)) - { - df_ref *def_rec; - df_ref *use_rec; - /* Need to update next use. */ - for (def_rec = DF_INSN_UID_DEFS (uid); *def_rec; def_rec++) - { - df_ref def = *def_rec; - reg_next_use[DF_REF_REGNO (def)] = NULL; - reg_next_inc_use[DF_REF_REGNO (def)] = NULL; - reg_next_def[DF_REF_REGNO (def)] = insn; - } - - for (use_rec = DF_INSN_UID_USES (uid); *use_rec; use_rec++) - { - df_ref use = *use_rec; - reg_next_use[DF_REF_REGNO (use)] = insn; - if (insn_is_add_or_inc) - reg_next_inc_use[DF_REF_REGNO (use)] = insn; - else - reg_next_inc_use[DF_REF_REGNO (use)] = NULL; - } - } - else if (dump_file) - fprintf (dump_file, "skipping update of deleted insn %d\n", uid); - } - - /* If we were successful, try again. There may have been several - opportunities that were interleaved. This is rare but - gcc.c-torture/compile/pr17273.c actually exhibits this. */ - if (success_in_block) - { - /* In this case, we must clear these vectors since the trick of - testing if the stale insn in the block will not work. */ - memset (reg_next_use, 0, max_reg * sizeof(rtx)); - memset (reg_next_inc_use, 0, max_reg * sizeof(rtx)); - memset (reg_next_def, 0, max_reg * sizeof(rtx)); - df_recompute_luids (bb); - merge_in_block (max_reg, bb); - } -} - -#endif - -static unsigned int -rest_of_handle_auto_inc_dec (void) -{ -#ifdef AUTO_INC_DEC - basic_block bb; - int max_reg = max_reg_num (); - - if (!initialized) - init_decision_table (); - - mem_tmp = gen_rtx_MEM (Pmode, NULL_RTX); - - df_note_add_problem (); - df_analyze (); - - reg_next_use = XCNEWVEC (rtx, max_reg); - reg_next_inc_use = XCNEWVEC (rtx, max_reg); - reg_next_def = XCNEWVEC (rtx, max_reg); - FOR_EACH_BB (bb) - merge_in_block (max_reg, bb); - - free (reg_next_use); - free (reg_next_inc_use); - free (reg_next_def); - - mem_tmp = NULL; -#endif - return 0; -} - - -/* Discover auto-inc auto-dec instructions. */ - -static bool -gate_auto_inc_dec (void) -{ -#ifdef AUTO_INC_DEC - return (optimize > 0 && flag_auto_inc_dec); -#else - return false; -#endif -} - - -struct rtl_opt_pass pass_inc_dec = -{ - { - RTL_PASS, - "auto_inc_dec", /* name */ - gate_auto_inc_dec, /* gate */ - rest_of_handle_auto_inc_dec, /* execute */ - NULL, /* sub */ - NULL, /* next */ - 0, /* static_pass_number */ - TV_AUTO_INC_DEC, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - TODO_dump_func | - TODO_df_finish, /* todo_flags_finish */ - } -}; - |