2000-04-30 13:01:53 +02:00
|
|
|
|
/* If-conversion support.
|
2001-07-28 05:13:34 +02:00
|
|
|
|
Copyright (C) 2000, 2001 Free Software Foundation, Inc.
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
Makefile.in, [...]: replace "GNU CC" with "GCC".
* Makefile.in, alias.c, basic-block.h, bb-reorder.c, bitmap.c,
bitmap.h, builtin-types.def, builtins.c, builtins.def,
c-aux-info.c, c-common.c, c-common.def, c-common.h,
c-convert.c, c-decl.c, c-dump.c, c-dump.h, c-errors.c,
c-format.c, c-lang.c, c-lex.c, c-lex.h, c-parse.in,
c-pragma.c, c-pragma.h, c-semantics.c, c-tree.h, c-typeck.c,
caller-save.c, calls.c, collect2.c, collect2.h, combine.c,
conditions.h, config.gcc, configure.frag, configure.in,
conflict.c, convert.c, convert.h, cppspec.c, crtstuff.c,
cse.c, cselib.c, cselib.h, dbxout.c, dbxout.h, defaults.h,
dependence.c, df.c, df.h, diagnostic.c, diagnostic.h,
doloop.c, dominance.c, dwarf.h, dwarf2.h, dwarf2asm.c,
dwarf2asm.h, dwarf2out.c, dwarf2out.h, dwarfout.c,
emit-rtl.c, errors.c, errors.h, except.c, except.h,
exgettext, explow.c, expmed.c, expr.c, expr.h, final.c,
fixproto, flags.h, flow.c, fold-const.c, fp-test.c,
function.c, function.h, gbl-ctors.h, gcc.c, gcc.h, gcc.hlp,
gccspec.c, gcov-io.h, gcse.c, genattr.c, genattrtab.c,
gencheck.c, gencodes.c, genconfig.c, genemit.c,
genextract.c, genflags.c, gengenrtl.c, genmultilib,
genopinit.c, genoutput.c, genpeep.c, genrecog.c,
gensupport.c, gensupport.h, ggc-callbacks.c, ggc-common.c,
ggc-none.c, ggc-page.c, ggc-simple.c, ggc.h, global.c,
graph.c, graph.h, gthr-aix.h, gthr-dce.h, gthr-posix.h,
gthr-rtems.h, gthr-single.h, gthr-solaris.h, gthr-vxworks.h,
gthr-win32.h, gthr.h, haifa-sched.c, halfpic.c, halfpic.h,
hard-reg-set.h, hwint.h, ifcvt.c, input.h, insn-addr.h,
integrate.c, integrate.h, jump.c, lcm.c, libgcc2.c,
libgcc2.h, lists.c, local-alloc.c, loop.c, loop.h,
machmode.def, machmode.h, main.c, mbchar.c, mbchar.h,
mips-tdump.c, mips-tfile.c, mklibgcc.in, mkmap-flat.awk,
mkmap-symver.awk, optabs.c, output.h, params.c, params.def,
params.h, predict.c, predict.def, predict.h, prefix.c,
prefix.h, print-rtl.c, print-tree.c, profile.c, protoize.c,
read-rtl.c, real.c, real.h, recog.c, recog.h, reg-stack.c,
regclass.c, regmove.c, regrename.c, regs.h, reload.c,
reload.h, reload1.c, reorg.c, resource.c, resource.h, rtl.c,
rtl.def, rtl.h, rtlanal.c, sbitmap.c, sbitmap.h,
sched-deps.c, sched-ebb.c, sched-int.h, sched-rgn.c,
sched-vis.c, sdbout.c, sdbout.h, sibcall.c, simplify-rtx.c,
ssa-ccp.c, ssa-dce.c, ssa.c, ssa.h, stmt.c, stor-layout.c,
stringpool.c, system.h, timevar.c, timevar.def, timevar.h,
tlink.c, toplev.c, toplev.h, tree.c, tree.def, tree.h,
tsystem.h, unroll.c, unwind-dw2-fde.c, unwind-dw2-fde.h,
unwind-dw2.c, unwind-pe.h, unwind-sjlj.c, unwind.h,
unwind.inc, varasm.c, varray.c, varray.h, xcoffout.c,
xcoffout.h: replace "GNU CC" with "GCC".
From-SVN: r45105
2001-08-22 16:35:51 +02:00
|
|
|
|
This file is part of GCC.
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
Makefile.in, [...]: replace "GNU CC" with "GCC".
* Makefile.in, alias.c, basic-block.h, bb-reorder.c, bitmap.c,
bitmap.h, builtin-types.def, builtins.c, builtins.def,
c-aux-info.c, c-common.c, c-common.def, c-common.h,
c-convert.c, c-decl.c, c-dump.c, c-dump.h, c-errors.c,
c-format.c, c-lang.c, c-lex.c, c-lex.h, c-parse.in,
c-pragma.c, c-pragma.h, c-semantics.c, c-tree.h, c-typeck.c,
caller-save.c, calls.c, collect2.c, collect2.h, combine.c,
conditions.h, config.gcc, configure.frag, configure.in,
conflict.c, convert.c, convert.h, cppspec.c, crtstuff.c,
cse.c, cselib.c, cselib.h, dbxout.c, dbxout.h, defaults.h,
dependence.c, df.c, df.h, diagnostic.c, diagnostic.h,
doloop.c, dominance.c, dwarf.h, dwarf2.h, dwarf2asm.c,
dwarf2asm.h, dwarf2out.c, dwarf2out.h, dwarfout.c,
emit-rtl.c, errors.c, errors.h, except.c, except.h,
exgettext, explow.c, expmed.c, expr.c, expr.h, final.c,
fixproto, flags.h, flow.c, fold-const.c, fp-test.c,
function.c, function.h, gbl-ctors.h, gcc.c, gcc.h, gcc.hlp,
gccspec.c, gcov-io.h, gcse.c, genattr.c, genattrtab.c,
gencheck.c, gencodes.c, genconfig.c, genemit.c,
genextract.c, genflags.c, gengenrtl.c, genmultilib,
genopinit.c, genoutput.c, genpeep.c, genrecog.c,
gensupport.c, gensupport.h, ggc-callbacks.c, ggc-common.c,
ggc-none.c, ggc-page.c, ggc-simple.c, ggc.h, global.c,
graph.c, graph.h, gthr-aix.h, gthr-dce.h, gthr-posix.h,
gthr-rtems.h, gthr-single.h, gthr-solaris.h, gthr-vxworks.h,
gthr-win32.h, gthr.h, haifa-sched.c, halfpic.c, halfpic.h,
hard-reg-set.h, hwint.h, ifcvt.c, input.h, insn-addr.h,
integrate.c, integrate.h, jump.c, lcm.c, libgcc2.c,
libgcc2.h, lists.c, local-alloc.c, loop.c, loop.h,
machmode.def, machmode.h, main.c, mbchar.c, mbchar.h,
mips-tdump.c, mips-tfile.c, mklibgcc.in, mkmap-flat.awk,
mkmap-symver.awk, optabs.c, output.h, params.c, params.def,
params.h, predict.c, predict.def, predict.h, prefix.c,
prefix.h, print-rtl.c, print-tree.c, profile.c, protoize.c,
read-rtl.c, real.c, real.h, recog.c, recog.h, reg-stack.c,
regclass.c, regmove.c, regrename.c, regs.h, reload.c,
reload.h, reload1.c, reorg.c, resource.c, resource.h, rtl.c,
rtl.def, rtl.h, rtlanal.c, sbitmap.c, sbitmap.h,
sched-deps.c, sched-ebb.c, sched-int.h, sched-rgn.c,
sched-vis.c, sdbout.c, sdbout.h, sibcall.c, simplify-rtx.c,
ssa-ccp.c, ssa-dce.c, ssa.c, ssa.h, stmt.c, stor-layout.c,
stringpool.c, system.h, timevar.c, timevar.def, timevar.h,
tlink.c, toplev.c, toplev.h, tree.c, tree.def, tree.h,
tsystem.h, unroll.c, unwind-dw2-fde.c, unwind-dw2-fde.h,
unwind-dw2.c, unwind-pe.h, unwind-sjlj.c, unwind.h,
unwind.inc, varasm.c, varray.c, varray.h, xcoffout.c,
xcoffout.h: replace "GNU CC" with "GCC".
From-SVN: r45105
2001-08-22 16:35:51 +02:00
|
|
|
|
GCC is free software; you can redistribute it and/or modify it
|
|
|
|
|
under the terms of the GNU General Public License as published by
|
2000-04-30 13:01:53 +02:00
|
|
|
|
the Free Software Foundation; either version 2, or (at your option)
|
|
|
|
|
any later version.
|
|
|
|
|
|
Makefile.in, [...]: replace "GNU CC" with "GCC".
* Makefile.in, alias.c, basic-block.h, bb-reorder.c, bitmap.c,
bitmap.h, builtin-types.def, builtins.c, builtins.def,
c-aux-info.c, c-common.c, c-common.def, c-common.h,
c-convert.c, c-decl.c, c-dump.c, c-dump.h, c-errors.c,
c-format.c, c-lang.c, c-lex.c, c-lex.h, c-parse.in,
c-pragma.c, c-pragma.h, c-semantics.c, c-tree.h, c-typeck.c,
caller-save.c, calls.c, collect2.c, collect2.h, combine.c,
conditions.h, config.gcc, configure.frag, configure.in,
conflict.c, convert.c, convert.h, cppspec.c, crtstuff.c,
cse.c, cselib.c, cselib.h, dbxout.c, dbxout.h, defaults.h,
dependence.c, df.c, df.h, diagnostic.c, diagnostic.h,
doloop.c, dominance.c, dwarf.h, dwarf2.h, dwarf2asm.c,
dwarf2asm.h, dwarf2out.c, dwarf2out.h, dwarfout.c,
emit-rtl.c, errors.c, errors.h, except.c, except.h,
exgettext, explow.c, expmed.c, expr.c, expr.h, final.c,
fixproto, flags.h, flow.c, fold-const.c, fp-test.c,
function.c, function.h, gbl-ctors.h, gcc.c, gcc.h, gcc.hlp,
gccspec.c, gcov-io.h, gcse.c, genattr.c, genattrtab.c,
gencheck.c, gencodes.c, genconfig.c, genemit.c,
genextract.c, genflags.c, gengenrtl.c, genmultilib,
genopinit.c, genoutput.c, genpeep.c, genrecog.c,
gensupport.c, gensupport.h, ggc-callbacks.c, ggc-common.c,
ggc-none.c, ggc-page.c, ggc-simple.c, ggc.h, global.c,
graph.c, graph.h, gthr-aix.h, gthr-dce.h, gthr-posix.h,
gthr-rtems.h, gthr-single.h, gthr-solaris.h, gthr-vxworks.h,
gthr-win32.h, gthr.h, haifa-sched.c, halfpic.c, halfpic.h,
hard-reg-set.h, hwint.h, ifcvt.c, input.h, insn-addr.h,
integrate.c, integrate.h, jump.c, lcm.c, libgcc2.c,
libgcc2.h, lists.c, local-alloc.c, loop.c, loop.h,
machmode.def, machmode.h, main.c, mbchar.c, mbchar.h,
mips-tdump.c, mips-tfile.c, mklibgcc.in, mkmap-flat.awk,
mkmap-symver.awk, optabs.c, output.h, params.c, params.def,
params.h, predict.c, predict.def, predict.h, prefix.c,
prefix.h, print-rtl.c, print-tree.c, profile.c, protoize.c,
read-rtl.c, real.c, real.h, recog.c, recog.h, reg-stack.c,
regclass.c, regmove.c, regrename.c, regs.h, reload.c,
reload.h, reload1.c, reorg.c, resource.c, resource.h, rtl.c,
rtl.def, rtl.h, rtlanal.c, sbitmap.c, sbitmap.h,
sched-deps.c, sched-ebb.c, sched-int.h, sched-rgn.c,
sched-vis.c, sdbout.c, sdbout.h, sibcall.c, simplify-rtx.c,
ssa-ccp.c, ssa-dce.c, ssa.c, ssa.h, stmt.c, stor-layout.c,
stringpool.c, system.h, timevar.c, timevar.def, timevar.h,
tlink.c, toplev.c, toplev.h, tree.c, tree.def, tree.h,
tsystem.h, unroll.c, unwind-dw2-fde.c, unwind-dw2-fde.h,
unwind-dw2.c, unwind-pe.h, unwind-sjlj.c, unwind.h,
unwind.inc, varasm.c, varray.c, varray.h, xcoffout.c,
xcoffout.h: replace "GNU CC" with "GCC".
From-SVN: r45105
2001-08-22 16:35:51 +02:00
|
|
|
|
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.
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
Makefile.in, [...]: replace "GNU CC" with "GCC".
* Makefile.in, alias.c, basic-block.h, bb-reorder.c, bitmap.c,
bitmap.h, builtin-types.def, builtins.c, builtins.def,
c-aux-info.c, c-common.c, c-common.def, c-common.h,
c-convert.c, c-decl.c, c-dump.c, c-dump.h, c-errors.c,
c-format.c, c-lang.c, c-lex.c, c-lex.h, c-parse.in,
c-pragma.c, c-pragma.h, c-semantics.c, c-tree.h, c-typeck.c,
caller-save.c, calls.c, collect2.c, collect2.h, combine.c,
conditions.h, config.gcc, configure.frag, configure.in,
conflict.c, convert.c, convert.h, cppspec.c, crtstuff.c,
cse.c, cselib.c, cselib.h, dbxout.c, dbxout.h, defaults.h,
dependence.c, df.c, df.h, diagnostic.c, diagnostic.h,
doloop.c, dominance.c, dwarf.h, dwarf2.h, dwarf2asm.c,
dwarf2asm.h, dwarf2out.c, dwarf2out.h, dwarfout.c,
emit-rtl.c, errors.c, errors.h, except.c, except.h,
exgettext, explow.c, expmed.c, expr.c, expr.h, final.c,
fixproto, flags.h, flow.c, fold-const.c, fp-test.c,
function.c, function.h, gbl-ctors.h, gcc.c, gcc.h, gcc.hlp,
gccspec.c, gcov-io.h, gcse.c, genattr.c, genattrtab.c,
gencheck.c, gencodes.c, genconfig.c, genemit.c,
genextract.c, genflags.c, gengenrtl.c, genmultilib,
genopinit.c, genoutput.c, genpeep.c, genrecog.c,
gensupport.c, gensupport.h, ggc-callbacks.c, ggc-common.c,
ggc-none.c, ggc-page.c, ggc-simple.c, ggc.h, global.c,
graph.c, graph.h, gthr-aix.h, gthr-dce.h, gthr-posix.h,
gthr-rtems.h, gthr-single.h, gthr-solaris.h, gthr-vxworks.h,
gthr-win32.h, gthr.h, haifa-sched.c, halfpic.c, halfpic.h,
hard-reg-set.h, hwint.h, ifcvt.c, input.h, insn-addr.h,
integrate.c, integrate.h, jump.c, lcm.c, libgcc2.c,
libgcc2.h, lists.c, local-alloc.c, loop.c, loop.h,
machmode.def, machmode.h, main.c, mbchar.c, mbchar.h,
mips-tdump.c, mips-tfile.c, mklibgcc.in, mkmap-flat.awk,
mkmap-symver.awk, optabs.c, output.h, params.c, params.def,
params.h, predict.c, predict.def, predict.h, prefix.c,
prefix.h, print-rtl.c, print-tree.c, profile.c, protoize.c,
read-rtl.c, real.c, real.h, recog.c, recog.h, reg-stack.c,
regclass.c, regmove.c, regrename.c, regs.h, reload.c,
reload.h, reload1.c, reorg.c, resource.c, resource.h, rtl.c,
rtl.def, rtl.h, rtlanal.c, sbitmap.c, sbitmap.h,
sched-deps.c, sched-ebb.c, sched-int.h, sched-rgn.c,
sched-vis.c, sdbout.c, sdbout.h, sibcall.c, simplify-rtx.c,
ssa-ccp.c, ssa-dce.c, ssa.c, ssa.h, stmt.c, stor-layout.c,
stringpool.c, system.h, timevar.c, timevar.def, timevar.h,
tlink.c, toplev.c, toplev.h, tree.c, tree.def, tree.h,
tsystem.h, unroll.c, unwind-dw2-fde.c, unwind-dw2-fde.h,
unwind-dw2.c, unwind-pe.h, unwind-sjlj.c, unwind.h,
unwind.inc, varasm.c, varray.c, varray.h, xcoffout.c,
xcoffout.h: replace "GNU CC" with "GCC".
From-SVN: r45105
2001-08-22 16:35:51 +02:00
|
|
|
|
along with GCC; see the file COPYING. If not, write to the Free
|
|
|
|
|
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
|
|
|
|
02111-1307, USA. */
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
#include "system.h"
|
|
|
|
|
|
|
|
|
|
#include "rtl.h"
|
|
|
|
|
#include "regs.h"
|
|
|
|
|
#include "function.h"
|
|
|
|
|
#include "flags.h"
|
|
|
|
|
#include "insn-config.h"
|
|
|
|
|
#include "recog.h"
|
2000-05-20 00:27:28 +02:00
|
|
|
|
#include "hard-reg-set.h"
|
2000-04-30 13:01:53 +02:00
|
|
|
|
#include "basic-block.h"
|
|
|
|
|
#include "expr.h"
|
2001-02-25 20:34:06 +01:00
|
|
|
|
#include "real.h"
|
2000-04-30 13:01:53 +02:00
|
|
|
|
#include "output.h"
|
Makefile.in (ifcvt.o): Depend on toplev.h.
* Makefile.in (ifcvt.o): Depend on toplev.h.
* c-semantics.c: Include expr.h.
* ifcvt.c: Include toplev.h.
* expr.h (rtx_equal_p): Delete prototype.
* rtl.h (exact_log2_wide, floor_log2_wide, permalloc,
protect_from_queue, gen_jump, gen_beq, gen_bge, gen_ble,
eliminate_constant_term, expand_complex_abs, find_single_use,
make_tree, init_expr_once, init_optabs, supports_one_only):
Likewise.
* tree.h (exact_log2_wide, floor_log2_wide, expand_null_return,
rest_of_type_compilation, emit_queue, do_pending_stack_adjust,
expand_assignment, store_expr, emit_line_note_after,
emit_line_note_force, split_specs_attrs, label_rtx): Likewise.
* toplev.h (exact_log2_wide, floor_log2_wide): Add prototype.
cp:
* Make-lang.in (cp/semantics.o): Depend on $(EXPR_H).
* semantics.c: Include expr.h.
java:
* Make-lang.in (java/boehm.o): Depend on toplev.h.
* boehm.c: Include toplev.h.
From-SVN: r41256
2001-04-11 17:51:55 +02:00
|
|
|
|
#include "toplev.h"
|
2000-04-30 13:01:53 +02:00
|
|
|
|
#include "tm_p.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef HAVE_conditional_execution
|
|
|
|
|
#define HAVE_conditional_execution 0
|
|
|
|
|
#endif
|
|
|
|
|
#ifndef HAVE_conditional_move
|
|
|
|
|
#define HAVE_conditional_move 0
|
|
|
|
|
#endif
|
|
|
|
|
#ifndef HAVE_incscc
|
|
|
|
|
#define HAVE_incscc 0
|
|
|
|
|
#endif
|
|
|
|
|
#ifndef HAVE_decscc
|
|
|
|
|
#define HAVE_decscc 0
|
|
|
|
|
#endif
|
2001-07-14 20:39:16 +02:00
|
|
|
|
#ifndef HAVE_trap
|
|
|
|
|
#define HAVE_trap 0
|
|
|
|
|
#endif
|
|
|
|
|
#ifndef HAVE_conditional_trap
|
|
|
|
|
#define HAVE_conditional_trap 0
|
|
|
|
|
#endif
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
#ifndef MAX_CONDITIONAL_EXECUTE
|
|
|
|
|
#define MAX_CONDITIONAL_EXECUTE (BRANCH_COST + 1)
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#define NULL_EDGE ((struct edge_def *)NULL)
|
|
|
|
|
#define NULL_BLOCK ((struct basic_block_def *)NULL)
|
|
|
|
|
|
|
|
|
|
/* # of IF-THEN or IF-THEN-ELSE blocks we looked at */
|
|
|
|
|
static int num_possible_if_blocks;
|
|
|
|
|
|
|
|
|
|
/* # of IF-THEN or IF-THEN-ELSE blocks were converted to conditional
|
|
|
|
|
execution. */
|
|
|
|
|
static int num_updated_if_blocks;
|
|
|
|
|
|
|
|
|
|
/* # of basic blocks that were removed. */
|
|
|
|
|
static int num_removed_blocks;
|
|
|
|
|
|
2001-06-11 07:16:10 +02:00
|
|
|
|
/* True if life data ok at present. */
|
|
|
|
|
static bool life_data_ok;
|
|
|
|
|
|
2000-04-30 13:01:53 +02:00
|
|
|
|
/* The post-dominator relation on the original block numbers. */
|
|
|
|
|
static sbitmap *post_dominators;
|
|
|
|
|
|
|
|
|
|
/* Forward references. */
|
|
|
|
|
static int count_bb_insns PARAMS ((basic_block));
|
|
|
|
|
static rtx first_active_insn PARAMS ((basic_block));
|
|
|
|
|
static int last_active_insn_p PARAMS ((basic_block, rtx));
|
2000-05-26 01:53:23 +02:00
|
|
|
|
static int seq_contains_jump PARAMS ((rtx));
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
2000-05-09 08:12:51 +02:00
|
|
|
|
static int cond_exec_process_insns PARAMS ((rtx, rtx, rtx, rtx, int));
|
2000-04-30 13:01:53 +02:00
|
|
|
|
static rtx cond_exec_get_condition PARAMS ((rtx));
|
|
|
|
|
static int cond_exec_process_if_block PARAMS ((basic_block, basic_block,
|
|
|
|
|
basic_block, basic_block));
|
|
|
|
|
|
|
|
|
|
static rtx noce_get_condition PARAMS ((rtx, rtx *));
|
2001-02-25 20:34:06 +01:00
|
|
|
|
static int noce_operand_ok PARAMS ((rtx));
|
2000-04-30 13:01:53 +02:00
|
|
|
|
static int noce_process_if_block PARAMS ((basic_block, basic_block,
|
|
|
|
|
basic_block, basic_block));
|
|
|
|
|
|
|
|
|
|
static int process_if_block PARAMS ((basic_block, basic_block,
|
|
|
|
|
basic_block, basic_block));
|
|
|
|
|
static void merge_if_block PARAMS ((basic_block, basic_block,
|
|
|
|
|
basic_block, basic_block));
|
|
|
|
|
|
|
|
|
|
static int find_if_header PARAMS ((basic_block));
|
|
|
|
|
static int find_if_block PARAMS ((basic_block, edge, edge));
|
|
|
|
|
static int find_if_case_1 PARAMS ((basic_block, edge, edge));
|
|
|
|
|
static int find_if_case_2 PARAMS ((basic_block, edge, edge));
|
2001-07-14 20:39:16 +02:00
|
|
|
|
static int find_cond_trap PARAMS ((basic_block, edge, edge));
|
2000-04-30 13:01:53 +02:00
|
|
|
|
static int find_memory PARAMS ((rtx *, void *));
|
|
|
|
|
static int dead_or_predicable PARAMS ((basic_block, basic_block,
|
2001-07-22 23:42:35 +02:00
|
|
|
|
basic_block, basic_block, int));
|
2001-04-02 10:17:15 +02:00
|
|
|
|
static void noce_emit_move_insn PARAMS ((rtx, rtx));
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
/* Abuse the basic_block AUX field to store the original block index,
|
|
|
|
|
as well as a flag indicating that the block should be rescaned for
|
|
|
|
|
life analysis. */
|
|
|
|
|
|
basic-block.h (BB_REACHABLE): Renumber.
* basic-block.h (BB_REACHABLE): Renumber.
(BB_DIRTY, BB_NEW): New flags.
(clear_bb_flags): Declare.
(update_life_info_in_dirty_blocks): Declare.
* cfg.c (clear_bb_flags): New function.
* cfgrtl.c (create_basic_block_structure): Set flags to BB_NEW.
* emit-rtl.c (add_insn_after, add_insn_before, remove_insn,
reorder_insns, emit_insn_after): Mark block as dirty.
* flow.c (update_life_info): Fix clearing of PROP_LOG_LINKS.
(update_life_info_in_dirty_blocks): New function.
* recog.c (apply_change_group): Dirtify block.
* cse.c (cse_insn): Reorder emitting of jump insn to keep
cfg consistent.
* gcse.c (delete_null_pointer_checks): Likewise.
* toplev.c (dump_file_index): Move cse2 after bp,
add DFI_null
(dump_file_info): Similary.
(rest_of_compilation): Avoid most of CFG rebuilds;
do first if converision after null pointer checks, do cse2
after branch prediction; avoid full liveness rebuild after
initializing subregs.
* invoke.texi (-d options): Document -du, renumber.
* cfgcleanup.c (bb_flags): Remove BB_UPDATE_LIFE.
(notice_new_block): Do not set BB_UPDATE_LIFE.
(try_forward_edges, merge_blocks_move_predecessor_nojumps,
merge_blocks_move_successor_nojumps, merge_blocks,
try_crossjump_to_edge): Likewise.
(try_optimize_cfg): Likewise; use update_life_info_in_dirty_blocks.
* cfgrtl.c (merge_blocks_nomove): Copy b's flags to a.
* ifcvt.c (SET_UPDATE_LIFE, UPDATE_LIFE): Kill.
(merge_of_block): Do not use life_data_ok.
(find_if_case_1): Do not use SET_UPDATE_LIFE.
(if_convert): Use BB_DIRTY mechanizm to update life.
* lcm.c (optimize_mode_switching): Update
update_life_info_in_dirty_blocks
From-SVN: r50127
2002-02-28 11:11:01 +01:00
|
|
|
|
#define SET_ORIG_INDEX(BB,I) ((BB)->aux = (void *)((size_t)(I)))
|
|
|
|
|
#define ORIG_INDEX(BB) ((size_t)(BB)->aux)
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Count the number of non-jump active insns in BB. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
count_bb_insns (bb)
|
|
|
|
|
basic_block bb;
|
|
|
|
|
{
|
|
|
|
|
int count = 0;
|
|
|
|
|
rtx insn = bb->head;
|
|
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
|
{
|
|
|
|
|
if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == INSN)
|
|
|
|
|
count++;
|
|
|
|
|
|
|
|
|
|
if (insn == bb->end)
|
|
|
|
|
break;
|
|
|
|
|
insn = NEXT_INSN (insn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return the first non-jump active insn in the basic block. */
|
|
|
|
|
|
|
|
|
|
static rtx
|
|
|
|
|
first_active_insn (bb)
|
|
|
|
|
basic_block bb;
|
|
|
|
|
{
|
|
|
|
|
rtx insn = bb->head;
|
|
|
|
|
|
|
|
|
|
if (GET_CODE (insn) == CODE_LABEL)
|
|
|
|
|
{
|
|
|
|
|
if (insn == bb->end)
|
|
|
|
|
return NULL_RTX;
|
|
|
|
|
insn = NEXT_INSN (insn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (GET_CODE (insn) == NOTE)
|
|
|
|
|
{
|
|
|
|
|
if (insn == bb->end)
|
|
|
|
|
return NULL_RTX;
|
|
|
|
|
insn = NEXT_INSN (insn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (GET_CODE (insn) == JUMP_INSN)
|
|
|
|
|
return NULL_RTX;
|
|
|
|
|
|
|
|
|
|
return insn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return true if INSN is the last active non-jump insn in BB. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
last_active_insn_p (bb, insn)
|
|
|
|
|
basic_block bb;
|
|
|
|
|
rtx insn;
|
|
|
|
|
{
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
if (insn == bb->end)
|
|
|
|
|
return TRUE;
|
|
|
|
|
insn = NEXT_INSN (insn);
|
|
|
|
|
}
|
|
|
|
|
while (GET_CODE (insn) == NOTE);
|
|
|
|
|
|
|
|
|
|
return GET_CODE (insn) == JUMP_INSN;
|
|
|
|
|
}
|
2000-05-26 01:53:23 +02:00
|
|
|
|
|
|
|
|
|
/* It is possible, especially when having dealt with multi-word
|
|
|
|
|
arithmetic, for the expanders to have emitted jumps. Search
|
|
|
|
|
through the sequence and return TRUE if a jump exists so that
|
|
|
|
|
we can abort the conversion. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
seq_contains_jump (insn)
|
|
|
|
|
rtx insn;
|
|
|
|
|
{
|
|
|
|
|
while (insn)
|
|
|
|
|
{
|
|
|
|
|
if (GET_CODE (insn) == JUMP_INSN)
|
|
|
|
|
return 1;
|
|
|
|
|
insn = NEXT_INSN (insn);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
/* Go through a bunch of insns, converting them to conditional
|
|
|
|
|
execution format if possible. Return TRUE if all of the non-note
|
|
|
|
|
insns were processed. */
|
|
|
|
|
|
|
|
|
|
static int
|
2000-05-09 08:12:51 +02:00
|
|
|
|
cond_exec_process_insns (start, end, test, prob_val, mod_ok)
|
2000-04-30 13:01:53 +02:00
|
|
|
|
rtx start; /* first insn to look at */
|
|
|
|
|
rtx end; /* last insn to look at */
|
|
|
|
|
rtx test; /* conditional execution test */
|
2000-05-09 08:12:51 +02:00
|
|
|
|
rtx prob_val; /* probability of branch taken. */
|
2000-04-30 13:01:53 +02:00
|
|
|
|
int mod_ok; /* true if modifications ok last insn. */
|
|
|
|
|
{
|
|
|
|
|
int must_be_last = FALSE;
|
|
|
|
|
rtx insn;
|
2000-06-04 04:03:03 +02:00
|
|
|
|
rtx pattern;
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
for (insn = start; ; insn = NEXT_INSN (insn))
|
|
|
|
|
{
|
|
|
|
|
if (GET_CODE (insn) == NOTE)
|
|
|
|
|
goto insn_done;
|
|
|
|
|
|
|
|
|
|
if (GET_CODE (insn) != INSN && GET_CODE (insn) != CALL_INSN)
|
|
|
|
|
abort ();
|
|
|
|
|
|
2000-06-01 01:58:46 +02:00
|
|
|
|
/* Remove USE insns that get in the way. */
|
|
|
|
|
if (reload_completed && GET_CODE (PATTERN (insn)) == USE)
|
2000-05-16 08:21:04 +02:00
|
|
|
|
{
|
|
|
|
|
/* ??? Ug. Actually unlinking the thing is problematic,
|
|
|
|
|
given what we'd have to coordinate with our callers. */
|
|
|
|
|
PUT_CODE (insn, NOTE);
|
|
|
|
|
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
|
|
|
|
|
NOTE_SOURCE_FILE (insn) = 0;
|
|
|
|
|
goto insn_done;
|
|
|
|
|
}
|
|
|
|
|
|
2000-04-30 13:01:53 +02:00
|
|
|
|
/* Last insn wasn't last? */
|
|
|
|
|
if (must_be_last)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (modified_in_p (test, insn))
|
|
|
|
|
{
|
|
|
|
|
if (!mod_ok)
|
|
|
|
|
return FALSE;
|
|
|
|
|
must_be_last = TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now build the conditional form of the instruction. */
|
2000-06-04 04:03:03 +02:00
|
|
|
|
pattern = PATTERN (insn);
|
|
|
|
|
|
|
|
|
|
/* If the machine needs to modify the insn being conditionally executed,
|
|
|
|
|
say for example to force a constant integer operand into a temp
|
|
|
|
|
register, do so here. */
|
|
|
|
|
#ifdef IFCVT_MODIFY_INSN
|
|
|
|
|
IFCVT_MODIFY_INSN (pattern, insn);
|
|
|
|
|
if (! pattern)
|
|
|
|
|
return FALSE;
|
|
|
|
|
#endif
|
|
|
|
|
|
2000-04-30 13:01:53 +02:00
|
|
|
|
validate_change (insn, &PATTERN (insn),
|
|
|
|
|
gen_rtx_COND_EXEC (VOIDmode, copy_rtx (test),
|
2000-06-04 04:03:03 +02:00
|
|
|
|
pattern), 1);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
2000-05-09 08:12:51 +02:00
|
|
|
|
if (GET_CODE (insn) == CALL_INSN && prob_val)
|
|
|
|
|
validate_change (insn, ®_NOTES (insn),
|
|
|
|
|
alloc_EXPR_LIST (REG_BR_PROB, prob_val,
|
|
|
|
|
REG_NOTES (insn)), 1);
|
|
|
|
|
|
2000-04-30 13:01:53 +02:00
|
|
|
|
insn_done:
|
|
|
|
|
if (insn == end)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return the condition for a jump. Do not do any special processing. */
|
|
|
|
|
|
|
|
|
|
static rtx
|
|
|
|
|
cond_exec_get_condition (jump)
|
|
|
|
|
rtx jump;
|
|
|
|
|
{
|
|
|
|
|
rtx test_if, cond;
|
|
|
|
|
|
combine.c (try_combine): Use any_condjump_p...
* combine.c (try_combine): Use any_condjump_p, any_uncondjump_p
and pc_set at the place of simplejump_p and condjump_p.
* cse.c (record_jump_equiv): Likewise.
* emit-rtl.c (emit): Likewise.
* explow.c (find_next_ref): Likewise.
* flow.c (tidy_fallthru_edge): Likewise.
(init_propagate_block_info): Likewise.
* gcse.c (delete_null_pointer_checks): Likewise.
* ifcvt.c (cond_exec_get_condition, noce_get_condition,
dead_or_predicable): Likewise.
* integrate.c (copy_insn_list): Likewise.
* loop.c (scan_loop, verify_dominator, find_and_verify_loops,
for_each_insn_in_loop, check_dbra_loop, get_condition,
insert_bct, load_mems): Likewise.
* resource.c (find_dead_or_set_registers): Likewise.
* sibcalls.c (simplejump_p): Likewise.
* unroll.c (copy_loop_body, reg_dead_after_loop): Likewise.
From-SVN: r34175
2000-05-25 23:38:49 +02:00
|
|
|
|
if (any_condjump_p (jump))
|
2000-05-26 11:51:00 +02:00
|
|
|
|
test_if = SET_SRC (pc_set (jump));
|
2000-04-30 13:01:53 +02:00
|
|
|
|
else
|
|
|
|
|
return NULL_RTX;
|
|
|
|
|
cond = XEXP (test_if, 0);
|
|
|
|
|
|
|
|
|
|
/* If this branches to JUMP_LABEL when the condition is false,
|
|
|
|
|
reverse the condition. */
|
|
|
|
|
if (GET_CODE (XEXP (test_if, 2)) == LABEL_REF
|
|
|
|
|
&& XEXP (XEXP (test_if, 2), 0) == JUMP_LABEL (jump))
|
2001-06-13 20:16:31 +02:00
|
|
|
|
{
|
|
|
|
|
enum rtx_code rev = reversed_comparison_code (cond, jump);
|
|
|
|
|
if (rev == UNKNOWN)
|
|
|
|
|
return NULL_RTX;
|
|
|
|
|
|
|
|
|
|
cond = gen_rtx_fmt_ee (rev, GET_MODE (cond), XEXP (cond, 0),
|
|
|
|
|
XEXP (cond, 1));
|
|
|
|
|
}
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
return cond;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Given a simple IF-THEN or IF-THEN-ELSE block, attempt to convert it
|
|
|
|
|
to conditional execution. Return TRUE if we were successful at
|
|
|
|
|
converting the the block. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb)
|
|
|
|
|
basic_block test_bb; /* Basic block test is in */
|
|
|
|
|
basic_block then_bb; /* Basic block for THEN block */
|
|
|
|
|
basic_block else_bb; /* Basic block for ELSE block */
|
|
|
|
|
basic_block join_bb; /* Basic block the join label is in */
|
|
|
|
|
{
|
|
|
|
|
rtx test_expr; /* expression in IF_THEN_ELSE that is tested */
|
|
|
|
|
rtx then_start; /* first insn in THEN block */
|
|
|
|
|
rtx then_end; /* last insn + 1 in THEN block */
|
2000-06-11 06:29:49 +02:00
|
|
|
|
rtx else_start = NULL_RTX; /* first insn in ELSE block or NULL */
|
|
|
|
|
rtx else_end = NULL_RTX; /* last insn + 1 in ELSE block */
|
2001-08-13 01:40:53 +02:00
|
|
|
|
int max; /* max # of insns to convert. */
|
2000-04-30 13:01:53 +02:00
|
|
|
|
int then_mod_ok; /* whether conditional mods are ok in THEN */
|
|
|
|
|
rtx true_expr; /* test for else block insns */
|
|
|
|
|
rtx false_expr; /* test for then block insns */
|
2000-05-09 08:12:51 +02:00
|
|
|
|
rtx true_prob_val; /* probability of else block */
|
|
|
|
|
rtx false_prob_val; /* probability of then block */
|
2000-04-30 13:01:53 +02:00
|
|
|
|
int n_insns;
|
2001-06-13 20:16:31 +02:00
|
|
|
|
enum rtx_code false_code;
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
/* Find the conditional jump to the ELSE or JOIN part, and isolate
|
|
|
|
|
the test. */
|
|
|
|
|
test_expr = cond_exec_get_condition (test_bb->end);
|
|
|
|
|
if (! test_expr)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2000-05-31 09:33:02 +02:00
|
|
|
|
/* If the conditional jump is more than just a conditional jump,
|
|
|
|
|
then we can not do conditional execution conversion on this block. */
|
|
|
|
|
if (!onlyjump_p (test_bb->end))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2000-04-30 13:01:53 +02:00
|
|
|
|
/* Collect the bounds of where we're to search. */
|
|
|
|
|
|
|
|
|
|
then_start = then_bb->head;
|
|
|
|
|
then_end = then_bb->end;
|
|
|
|
|
|
2000-05-16 08:21:04 +02:00
|
|
|
|
/* Skip a label heading THEN block. */
|
|
|
|
|
if (GET_CODE (then_start) == CODE_LABEL)
|
|
|
|
|
then_start = NEXT_INSN (then_start);
|
|
|
|
|
|
2000-04-30 13:01:53 +02:00
|
|
|
|
/* Skip a (use (const_int 0)) or branch as the final insn. */
|
|
|
|
|
if (GET_CODE (then_end) == INSN
|
|
|
|
|
&& GET_CODE (PATTERN (then_end)) == USE
|
|
|
|
|
&& GET_CODE (XEXP (PATTERN (then_end), 0)) == CONST_INT)
|
|
|
|
|
then_end = PREV_INSN (then_end);
|
|
|
|
|
else if (GET_CODE (then_end) == JUMP_INSN)
|
|
|
|
|
then_end = PREV_INSN (then_end);
|
|
|
|
|
|
|
|
|
|
if (else_bb)
|
|
|
|
|
{
|
|
|
|
|
/* Skip the ELSE block's label. */
|
|
|
|
|
else_start = NEXT_INSN (else_bb->head);
|
|
|
|
|
else_end = else_bb->end;
|
|
|
|
|
|
|
|
|
|
/* Skip a (use (const_int 0)) or branch as the final insn. */
|
|
|
|
|
if (GET_CODE (else_end) == INSN
|
|
|
|
|
&& GET_CODE (PATTERN (else_end)) == USE
|
|
|
|
|
&& GET_CODE (XEXP (PATTERN (else_end), 0)) == CONST_INT)
|
|
|
|
|
else_end = PREV_INSN (else_end);
|
|
|
|
|
else if (GET_CODE (else_end) == JUMP_INSN)
|
|
|
|
|
else_end = PREV_INSN (else_end);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* How many instructions should we convert in total? */
|
|
|
|
|
n_insns = 0;
|
|
|
|
|
if (else_bb)
|
|
|
|
|
{
|
|
|
|
|
max = 2 * MAX_CONDITIONAL_EXECUTE;
|
|
|
|
|
n_insns = count_bb_insns (else_bb);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
max = MAX_CONDITIONAL_EXECUTE;
|
|
|
|
|
n_insns += count_bb_insns (then_bb);
|
|
|
|
|
if (n_insns > max)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* Map test_expr/test_jump into the appropriate MD tests to use on
|
|
|
|
|
the conditionally executed code. */
|
|
|
|
|
|
|
|
|
|
true_expr = test_expr;
|
2001-06-13 20:16:31 +02:00
|
|
|
|
|
|
|
|
|
false_code = reversed_comparison_code (true_expr, test_bb->end);
|
|
|
|
|
if (false_code != UNKNOWN)
|
|
|
|
|
false_expr = gen_rtx_fmt_ee (false_code, GET_MODE (true_expr),
|
|
|
|
|
XEXP (true_expr, 0), XEXP (true_expr, 1));
|
|
|
|
|
else
|
|
|
|
|
false_expr = NULL_RTX;
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
2000-06-04 04:03:03 +02:00
|
|
|
|
#ifdef IFCVT_MODIFY_TESTS
|
|
|
|
|
/* If the machine description needs to modify the tests, such as setting a
|
|
|
|
|
conditional execution register from a comparison, it can do so here. */
|
|
|
|
|
IFCVT_MODIFY_TESTS (true_expr, false_expr, test_bb, then_bb, else_bb,
|
|
|
|
|
join_bb);
|
|
|
|
|
|
|
|
|
|
/* See if the conversion failed */
|
|
|
|
|
if (!true_expr || !false_expr)
|
|
|
|
|
goto fail;
|
|
|
|
|
#endif
|
|
|
|
|
|
2000-05-09 08:12:51 +02:00
|
|
|
|
true_prob_val = find_reg_note (test_bb->end, REG_BR_PROB, NULL_RTX);
|
|
|
|
|
if (true_prob_val)
|
|
|
|
|
{
|
|
|
|
|
true_prob_val = XEXP (true_prob_val, 0);
|
|
|
|
|
false_prob_val = GEN_INT (REG_BR_PROB_BASE - INTVAL (true_prob_val));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
false_prob_val = NULL_RTX;
|
|
|
|
|
|
2000-04-30 13:01:53 +02:00
|
|
|
|
/* For IF-THEN-ELSE blocks, we don't allow modifications of the test
|
|
|
|
|
on then THEN block. */
|
|
|
|
|
then_mod_ok = (else_bb == NULL_BLOCK);
|
|
|
|
|
|
|
|
|
|
/* Go through the THEN and ELSE blocks converting the insns if possible
|
|
|
|
|
to conditional execution. */
|
|
|
|
|
|
|
|
|
|
if (then_end
|
2001-06-13 20:16:31 +02:00
|
|
|
|
&& (! false_expr
|
|
|
|
|
|| ! cond_exec_process_insns (then_start, then_end, false_expr,
|
|
|
|
|
false_prob_val, then_mod_ok)))
|
2000-04-30 13:01:53 +02:00
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
|
|
if (else_bb
|
|
|
|
|
&& ! cond_exec_process_insns (else_start, else_end,
|
2000-05-09 08:12:51 +02:00
|
|
|
|
true_expr, true_prob_val, TRUE))
|
2000-04-30 13:01:53 +02:00
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
|
|
if (! apply_change_group ())
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2000-06-04 04:03:03 +02:00
|
|
|
|
#ifdef IFCVT_MODIFY_FINAL
|
|
|
|
|
/* Do any machine dependent final modifications */
|
|
|
|
|
IFCVT_MODIFY_FINAL (test_bb, then_bb, else_bb, join_bb);
|
|
|
|
|
#endif
|
|
|
|
|
|
2000-04-30 13:01:53 +02:00
|
|
|
|
/* Conversion succeeded. */
|
|
|
|
|
if (rtl_dump_file)
|
|
|
|
|
fprintf (rtl_dump_file, "%d insn%s converted to conditional execution.\n",
|
|
|
|
|
n_insns, (n_insns == 1) ? " was" : "s were");
|
|
|
|
|
|
|
|
|
|
/* Merge the blocks! */
|
|
|
|
|
merge_if_block (test_bb, then_bb, else_bb, join_bb);
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
fail:
|
2000-06-04 04:03:03 +02:00
|
|
|
|
#ifdef IFCVT_MODIFY_CANCEL
|
|
|
|
|
/* Cancel any machine dependent changes. */
|
|
|
|
|
IFCVT_MODIFY_CANCEL (test_bb, then_bb, else_bb, join_bb);
|
|
|
|
|
#endif
|
|
|
|
|
|
2000-04-30 13:01:53 +02:00
|
|
|
|
cancel_changes (0);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Used by noce_process_if_block to communicate with its subroutines.
|
|
|
|
|
|
|
|
|
|
The subroutines know that A and B may be evaluated freely. They
|
|
|
|
|
know that X is a register. They should insert new instructions
|
|
|
|
|
before cond_earliest. */
|
|
|
|
|
|
|
|
|
|
struct noce_if_info
|
|
|
|
|
{
|
2001-02-25 20:34:06 +01:00
|
|
|
|
basic_block test_bb;
|
2000-04-30 13:01:53 +02:00
|
|
|
|
rtx insn_a, insn_b;
|
|
|
|
|
rtx x, a, b;
|
|
|
|
|
rtx jump, cond, cond_earliest;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static rtx noce_emit_store_flag PARAMS ((struct noce_if_info *,
|
|
|
|
|
rtx, int, int));
|
|
|
|
|
static int noce_try_store_flag PARAMS ((struct noce_if_info *));
|
|
|
|
|
static int noce_try_store_flag_inc PARAMS ((struct noce_if_info *));
|
|
|
|
|
static int noce_try_store_flag_constants PARAMS ((struct noce_if_info *));
|
|
|
|
|
static int noce_try_store_flag_mask PARAMS ((struct noce_if_info *));
|
|
|
|
|
static rtx noce_emit_cmove PARAMS ((struct noce_if_info *,
|
|
|
|
|
rtx, enum rtx_code, rtx,
|
|
|
|
|
rtx, rtx, rtx));
|
|
|
|
|
static int noce_try_cmove PARAMS ((struct noce_if_info *));
|
|
|
|
|
static int noce_try_cmove_arith PARAMS ((struct noce_if_info *));
|
2001-02-25 20:34:06 +01:00
|
|
|
|
static rtx noce_get_alt_condition PARAMS ((struct noce_if_info *,
|
|
|
|
|
rtx, rtx *));
|
|
|
|
|
static int noce_try_minmax PARAMS ((struct noce_if_info *));
|
|
|
|
|
static int noce_try_abs PARAMS ((struct noce_if_info *));
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
/* Helper function for noce_try_store_flag*. */
|
|
|
|
|
|
|
|
|
|
static rtx
|
|
|
|
|
noce_emit_store_flag (if_info, x, reversep, normalize)
|
|
|
|
|
struct noce_if_info *if_info;
|
|
|
|
|
rtx x;
|
|
|
|
|
int reversep, normalize;
|
|
|
|
|
{
|
|
|
|
|
rtx cond = if_info->cond;
|
|
|
|
|
int cond_complex;
|
|
|
|
|
enum rtx_code code;
|
|
|
|
|
|
|
|
|
|
cond_complex = (! general_operand (XEXP (cond, 0), VOIDmode)
|
|
|
|
|
|| ! general_operand (XEXP (cond, 1), VOIDmode));
|
|
|
|
|
|
|
|
|
|
/* If earliest == jump, or when the condition is complex, try to
|
|
|
|
|
build the store_flag insn directly. */
|
|
|
|
|
|
|
|
|
|
if (cond_complex)
|
2000-12-27 19:22:51 +01:00
|
|
|
|
cond = XEXP (SET_SRC (pc_set (if_info->jump)), 0);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
2001-02-28 17:20:43 +01:00
|
|
|
|
if (reversep)
|
|
|
|
|
code = reversed_comparison_code (cond, if_info->jump);
|
|
|
|
|
else
|
|
|
|
|
code = GET_CODE (cond);
|
|
|
|
|
|
2000-04-30 13:01:53 +02:00
|
|
|
|
if ((if_info->cond_earliest == if_info->jump || cond_complex)
|
|
|
|
|
&& (normalize == 0 || STORE_FLAG_VALUE == normalize))
|
|
|
|
|
{
|
|
|
|
|
rtx tmp;
|
|
|
|
|
|
|
|
|
|
tmp = gen_rtx_fmt_ee (code, GET_MODE (x), XEXP (cond, 0),
|
|
|
|
|
XEXP (cond, 1));
|
|
|
|
|
tmp = gen_rtx_SET (VOIDmode, x, tmp);
|
|
|
|
|
|
|
|
|
|
start_sequence ();
|
|
|
|
|
tmp = emit_insn (tmp);
|
|
|
|
|
|
|
|
|
|
if (recog_memoized (tmp) >= 0)
|
|
|
|
|
{
|
|
|
|
|
tmp = get_insns ();
|
|
|
|
|
end_sequence ();
|
|
|
|
|
emit_insns (tmp);
|
|
|
|
|
|
|
|
|
|
if_info->cond_earliest = if_info->jump;
|
|
|
|
|
|
|
|
|
|
return x;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
end_sequence ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Don't even try if the comparison operands are weird. */
|
|
|
|
|
if (cond_complex)
|
|
|
|
|
return NULL_RTX;
|
|
|
|
|
|
|
|
|
|
return emit_store_flag (x, code, XEXP (cond, 0),
|
|
|
|
|
XEXP (cond, 1), VOIDmode,
|
|
|
|
|
(code == LTU || code == LEU
|
|
|
|
|
|| code == GEU || code == GTU), normalize);
|
|
|
|
|
}
|
|
|
|
|
|
2001-10-09 08:03:16 +02:00
|
|
|
|
/* Emit instruction to move an rtx into STRICT_LOW_PART. */
|
2001-04-02 10:17:15 +02:00
|
|
|
|
static void
|
|
|
|
|
noce_emit_move_insn (x, y)
|
|
|
|
|
rtx x, y;
|
|
|
|
|
{
|
|
|
|
|
enum machine_mode outmode, inmode;
|
|
|
|
|
rtx outer, inner;
|
|
|
|
|
int bitpos;
|
|
|
|
|
|
|
|
|
|
if (GET_CODE (x) != STRICT_LOW_PART)
|
|
|
|
|
{
|
|
|
|
|
emit_move_insn (x, y);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
outer = XEXP (x, 0);
|
|
|
|
|
inner = XEXP (outer, 0);
|
|
|
|
|
outmode = GET_MODE (outer);
|
|
|
|
|
inmode = GET_MODE (inner);
|
Use byte offsets in SUBREGs instead of words.
2001-04-03 Jakub Jelinek <jakub@redhat.com>
David S. Miller <davem@pierdol.cobaltmicro.com>
Andrew MacLeod <amacleod@redhat.com>
Use byte offsets in SUBREGs instead of words.
* alias.c (nonlocal_mentioned_p): Use subreg_regno function.
* caller-save.c (mark_set_regs): Change callers of subreg_hard_regno
to pass new argument.
(add_stored_regs): Use subreg_regno_offset function.
* calls.c (expand_call): For non-paradoxical SUBREG take endianess
into account.
(precompute_arguments): Use gen_lowpart_SUBREG.
* combine.c (try_combine): Replace explicit XEXP with SUBREG_REG.
(combine_simplify_rtx): Rework to use SUBREG_BYTE.
(simplify_set): Rework to use SUBREG_BYTE.
(expand_field_assignment): Use SUBREG_BYTE.
(make_extraction): Use SUBREG_BYTE.
(if_then_else_cond): Use SUBREG_BYTE.
(apply_distributive_law): Use SUBREG_BYTE and fixup subreg comments.
(gen_lowpart_for_combine): Compute full byte offset.
* cse.c (mention_regs): Use SUBREG_BYTE.
(remove_invalid_subreg_refs): Rework to use SUBREG_BYTE.
(canon_hash): Use SUBREG_BYTE.
(fold_rtx): Pass SUBREG_BYTE div UNITS_PER_WORD to operand_subword.
(gen_lowpart_if_possible): Formatting.
* dbxout.c (dbxout_symbol_location): Compute SUBREG hard regnos
correctly.
* dwarf2out.c (is_pseudo_reg): Fixup explicit XEXP into SUBREG_REG
(mem_loc_descriptor): Fixup explicit XEXP into SUBREG_REG
(loc_descriptor): Fixup explicit XEXP into SUBREG_REG
* dwarfout.c (is_pseudo_reg): Fixup explicit XEXP into SUBREG_REG
(output_mem_loc_descriptor): Fixup explicit XEXP into SUBREG_REG
(output_loc_descriptor): Fixup explicit XEXP into SUBREG_REG
* emit-rtl.c (gen_rtx_SUBREG): New function, used to verify
certain invariants about SUBREGs the compiler creates.
(gen_lowpart_SUBREG): New function.
(subreg_hard_regno): New function to get the final register number.
(gen_lowpart_common): Use SUBREG_BYTE.
(gen_imagpart): Spacing nits.
(subreg_realpart_p): Use SUBREG_BYTE.
(gen_highpart): Use SUBREG_BYTE.
(subreg_lowpart_p): Always compute endian corrected goal offset,
even at the byte level, then compare against that.
(constant_subword): New function, pulled out all constant cases
from operand_subword and changed second argument name to offset.
(operand_subword): Detect non REG/SUBREG/CONCAT/MEM cases early
and call constant_subword to do the work. Return const0_rtx if
looking for a word outside of OP.
(operand_subword_force): Change second arg name to offset.
* expmed.c (store_bit_field): Use SUBREG_BYTE.
(store_split_bit_field): Use SUBREG_BYTE.
(extract_bit_field): Use SUBREG_BYTE.
(extract_split_bit_field): Use SUBREG_BYTE.
(expand_shift): Use SUBREG_BYTE.
* expr.c (store_expr, expand_expr): Use gen_lowpart_SUBREG.
* final.c (alter_subreg) Use subreg_hard_regno and SUBREG_BYTE.
* flow.c (set_noop_p): Use SUBREG_BYTE.
(mark_set_1): Remove ALTER_HARD_SUBREG. Use subreg_regno_offset instead.
* function.c (fixup_var_refs_1): Fixup explicit XEXP into a SUBREG_REG.
(fixup_memory_subreg): Use SUBREG_BYTE and remove byte endian
correction code.
(optimize_bit_field): Use SUBREG_BYTE.
(purge_addressof_1): Use SUBREG_BYTE.
(purge_single_hard_subreg_set): Use subreg_regno_offset function.
(assign_params): Mark arguments SUBREG_PROMOTED_VAR_P if they are
actually promoted by the caller and PROMOTE_FOR_CALLS_ONLY is true.
* gengenrtl.c (special_rtx): Add SUBREG.
* global.c (mark_reg_store): Use SUBREG_BYTE.
(set_preference): Rework to use subreg_regno_offset and SUBREG_BYTE.
* ifcvt (noce_emit_move_insn): Use SUBREG_BYTE.
* integrate.c (copy_rtx_and_substitute): Use SUBREG_BYTE and make sure
final byte offset is congruent to subreg's mode size.
(subst_constants): Use SUBREG_BYTE.
(mark_stores): Use subreg_regno_offset function.
* jump.c (rtx_renumbered_equal_p, true_regnum): Use subreg_regno_offset
function and SUBREG_BYTE.
* local-alloc.c (combine_regs): Use subreg_regno_offset function.
(reg_is_born): Use subreg_hard_regno.
* recog.c (valid_replace_rtx_1): Use SUBREG_BYTE and remove byte
endian correction code. Don't combine subregs unless resulting
offset aligns with type. Fix subreg constant extraction for DImode.
Simplify SUBREG of VOIDmode CONST_DOUBLE.
(general_operand): Remove dead mode_altering_drug code.
(indirect_operand): Use SUBREG_BYTE.
(constrain_operands): Use subreg_regno_offset function.
* reg-stack.c (get_true_reg): Use subreg_regno_offset function.
* regmove.c (regmove_optimize): Use SUBREG_BYTE.
(optimize_reg_copy_3): Use gen_lowpart_SUBREG.
* regs.h (REG_SIZE): Allow target to override.
(REGMODE_NATURAL_SIZE): New macro which target can override.
* reload.c (reload_inner_reg_of_subreg): subreg_regno should be used
on the entire subreg rtx.
(push_reload): Use SUBREG_BYTE in comments and code.
(find_dummy_reload): Use subreg_regno_offset. Only adjust offsets
for hard registers inside subregs.
(operands_match_p): Use subreg_regno_offset.
(find_reloads): Use SUBREG_BYTE and only advance offset for subregs
containing hard regs.
(find_reload_toplev): Use SUBREG_BYTE. Remove byte endian
corrections when fixing up MEM subregs.
(find_reloads_address_1): Use SUBREG_BYTE, subreg_regno, and
subreg_regno_offset where appropriate.
(find_reloads_subreg_address): Use SUBREG_BYTE. Remove
byte endian corrections when fixing up MEM subregs.
(subst_reloads): When combining two subregs, make sure final
offset is congruent to subreg's mode size.
(find_replacement): Use SUBREG_BYTE and subreg_regno_offset.
(refers_to_regno_for_reload_p): Use subreg_regno.
(reg_overlap_mentioned_for_reload_p): Use subreg_regno_offset.
* reload1.c (eliminate_regs) Use SUBREG_BYTE. Remove byte endian
correction code for memory subreg fixups.
(forget_old_reload_1): Use subreg_regno_offset.
(choose_reload_regs): Use subreg_regno.
(emit_input_reload_insns): Use SUBREG_BYTE.
(reload_combine_note_store): Use subreg_regno_offset.
(move2add_note_store): Use subreg_regno_offset.
* resource.c (update_live_status, mark_referenced_resources): Use
subreg_regno function.
(mark_set_resources): Use subreg_regno function.
* rtl.h (SUBREG_WORD): Rename to SUBREG_BYTE.
(subreg_regno_offset, subreg_regno): Define prototypes.
(subreg_hard_regno, constant_subword, gen_rtx_SUBREG): Newi functions.
(gen_lowpart_SUBREG): Add prototype.
* rtl.texi (subreg): Update to reflect new byte offset representation.
Add mentioning of the effect that BYTES_BIG_ENDIAN has on subregs now.
* rtlanal.c (refers_to_regno_p): Use subreg_regno.
(reg_overlap_mentioned_p): Use subreg_regno.
(replace_regs); Make sure final offset of combined subreg is
congruent to size of subreg's mode.
(subreg_regno_offset): New function.
(subreg_regno): New function.
* sched-vis.c (print_value): Change SUBREG_WORD to SUBREG_BYTE.
* sdbout.c (sdbout_symbol): Compute offset using alter_subreg.
* stmt.c (expand_anon_union_decl): Use gen_lowpart_SUBREG.
* tm.texi (ALTER_HARD_SUBREG): Remove, it is now dead.
(SUBREG_REGNO_OFFSET): Describe SUBREG_REGNO_OFFSET overrides.
* config/a29k/a29k.c (gpc_reg_operand): Use subreg_regno.
(a29k_get_reloaded_address): Use SUBREG_BYTE.
(print_operand): Use SUBREG_BYTE.
* config/alpha/alpha.c (print_operand_address): Use SUBREG_BYTE.
* config/arm/arm.c (arm_reload_in_hi): Use SUBREG_BYTE.
(arm_reload_out_hi): Use SUBREG_BYTE.
* config/d30v/d30v.c (d30v_split_double): Use subreg_regno_offset
instead of SUBREG_WORD.
(d30v_print_operand_memory_reference): Use subreg_regno_offset.
* config/dsp16xx/dsp16xx.md (extendqihi2, zero_extendqihi2): Fix
SUBREG creation to use byte offset.
* config/h8300/h8300.md (Unnamed HImode zero extraction and 16bit
inverted load insns): Fix explicit rtl subregs to use byte
offsets.
* config/i370/i370.md (cmpstrsi, movstrsi, mulsi3, divsi3,
udivsi3, umodsi3): Generate SUBREGs with byte offsets.
* config/i860/i860.c (single_insn_src_p): Use SUBREG_BYTE.
* config/i860/i860.md (mulsi3_big): Fixup explicit SUBREGs in rtl
to use byte offsets.
(unnamed fmlow.dd insn): Fixup SUBREGS to use byte offsets.
* config/i960/i960.md (extendhisi2): Generate SUBREGs with byte
offsets, also make sure it is congruent to SUBREG's mode size.
(extendqisi2, extendqihi2, zero_extendhisi2, zero_extendqisi2,
unnamed ldob insn): Generate SUBREGs with byte offset.
(zero_extendqihi2): SUBREG's are byte offsets.
* config/m68hc11/m68hc11.c (m68hc11_gen_lowpart): Use SUBREG_BYTE.
(m68hc11_gen_highpart): Use SUBREG_BYTE.
* config/m68k/m68k.md (zero_extendhisi2, zero_extendqihi2,
zero-extendqisi2): Generate SUBREGs with byte offset.
(umulsidi3, mulsidi3, subreghi1ashrdi_const32,
subregsi1ashrdi_const32, subreg1lshrdi_const32): Fixup explicit
subregs in rtl to use byte offsets.
* config/m88k/m88k.md (extendsidi2): fixup subregs to use byte offset.
* config/mips/mips.c (mips_move_1word): Use subreg_regno_offset.
(mips_move_2words): Use subreg_regno_offset.
(mips_secondary_reload_class): Use subreg_regno_offset.
* config/mips/mips.md (DImode plus, minus, move, and logical op
splits): Fixup explicit subregs in rtl to use byte offsets.
* config/mn10200/mn10200.c (print_operand): Use subreg_regno function.
* config/mn10300/mn10300.c (print_operand): Use subreg_regno function.
* config/ns32k/ns32k.md (udivmoddisi4): Fix explicit subregs in
rtl to use byte offsets.
* config/pa/pa.c (emit_move_sequence): Use SUBREG_BYTE.
* config/pa/pa.md (floatunssisf2, floatunssidf2, mulsi3): fix explicit
subregs to use byte offsets.
* config/pdp11/pdp11.md (zero_extendhisi2, modhi3, modhi3+1):
Fixup explicit subregs in rtl to use byte offsets.
* config/romp/romp.c (memory_offset_in_range_p): Use SUBREG_BYTE
and remove byte endian correction code.
* config/sh/sh.c (output_movedouble): Use subreg_regno.
(gen_ashift_hi): Use SUBREG_BYTE.
(regs_used): Use subreg_regno_offset.
(machine_dependent_reorg): Use subreg_regno_offset.
* config/sh/sh.h (INDEX_REGISTER_RTX_P): Use SUBREG_BYTE.
* config/sh/sh.md (DImode and DFmode move splits): Use subreg_regno.
(movdf_i4): Subregs are byte offsets now.
* config/sparc/sparc.c (ultra_find_type): Use SUBREG_BYTE.
* config/sparc/sparc.h (ALTER_HARD_SUBREG): Removed.
(REGMODE_NATURAL_SIZE): Override.
(REG_SIZE): For SUBREG check float mode on SUBREG_REG's mode.
* config/sparc/sparc.md (TFmode move splits): Generate SUBREGs
with byte offsets.
(zero_extendhisi2, zero_extendqidi2_insn, extendhisi2,
extendqihi2, sign_extendqihi2_insn, sign_extendqisi2_insn,
extendqidi2): Generate SUBREGs with byte offsets, also make sure
it is congruent to SUBREG's mode size.
(smulsi3_highpart_v8plus): Fix explicit subregs in rtl to use byte
offsets.
(cmp_siqi_trunc, cmp_siqi_trunc_set, cmp_diqi_trunc,
cmp_diqi_trunc_set, lshrdi3_v8plus+1, lshrdi3_v8plus+2,
lshrdi3_v8plus+3, lshrdi3_v8plus+4): Use proper
SUBREG_BYTE offset for non-paradoxical subregs in patterns.
* config/v850/v850.c (print_operand, output_move_double): Use
subreg_regno function.
Co-Authored-By: Andrew MacLeod <amacleod@redhat.com>
Co-Authored-By: David S. Miller <davem@pierdol.cobaltmicro.com>
From-SVN: r41058
2001-04-03 17:06:12 +02:00
|
|
|
|
bitpos = SUBREG_BYTE (outer) * BITS_PER_UNIT;
|
expmed.c (extract_bit_field): No longer pass in alignment.
* expmed.c (extract_bit_field): No longer pass in alignment.
(extract_fixed_bit_field, extract_split_bit_field): Likewise.
(store_bit_field, store_fixed_bit_field, store_split_bit_field):
Likewise.
* expr.c (store_constructor, store_constructor_field): Likewise.
(store_field, emit_group_load, emit_group_store): Likewise.
* expr.h (emit_group_load, emit_group_store): Delete ALIGN parm.
(store_bit_field, extract_bit_field): Likewise.
* calls.c, expr.c, function.c: Change calls to above functions.
* ifcvt.c, stmt.c: Likewise.
From-SVN: r46926
2001-11-11 12:02:26 +01:00
|
|
|
|
store_bit_field (inner, GET_MODE_BITSIZE (outmode), bitpos, outmode, y,
|
2001-04-02 10:17:15 +02:00
|
|
|
|
GET_MODE_BITSIZE (inmode));
|
|
|
|
|
}
|
|
|
|
|
|
2000-04-30 13:01:53 +02:00
|
|
|
|
/* Convert "if (test) x = 1; else x = 0".
|
|
|
|
|
|
|
|
|
|
Only try 0 and STORE_FLAG_VALUE here. Other combinations will be
|
|
|
|
|
tried in noce_try_store_flag_constants after noce_try_cmove has had
|
|
|
|
|
a go at the conversion. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
noce_try_store_flag (if_info)
|
|
|
|
|
struct noce_if_info *if_info;
|
|
|
|
|
{
|
|
|
|
|
int reversep;
|
|
|
|
|
rtx target, seq;
|
|
|
|
|
|
|
|
|
|
if (GET_CODE (if_info->b) == CONST_INT
|
|
|
|
|
&& INTVAL (if_info->b) == STORE_FLAG_VALUE
|
|
|
|
|
&& if_info->a == const0_rtx)
|
|
|
|
|
reversep = 0;
|
|
|
|
|
else if (if_info->b == const0_rtx
|
|
|
|
|
&& GET_CODE (if_info->a) == CONST_INT
|
|
|
|
|
&& INTVAL (if_info->a) == STORE_FLAG_VALUE
|
2001-02-28 17:20:43 +01:00
|
|
|
|
&& (reversed_comparison_code (if_info->cond, if_info->jump)
|
|
|
|
|
!= UNKNOWN))
|
2000-04-30 13:01:53 +02:00
|
|
|
|
reversep = 1;
|
|
|
|
|
else
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
start_sequence ();
|
|
|
|
|
|
|
|
|
|
target = noce_emit_store_flag (if_info, if_info->x, reversep, 0);
|
|
|
|
|
if (target)
|
|
|
|
|
{
|
|
|
|
|
if (target != if_info->x)
|
2001-04-02 10:17:15 +02:00
|
|
|
|
noce_emit_move_insn (if_info->x, target);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
seq = get_insns ();
|
|
|
|
|
end_sequence ();
|
|
|
|
|
emit_insns_before (seq, if_info->cond_earliest);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
end_sequence ();
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Convert "if (test) x = a; else x = b", for A and B constant. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
noce_try_store_flag_constants (if_info)
|
|
|
|
|
struct noce_if_info *if_info;
|
|
|
|
|
{
|
|
|
|
|
rtx target, seq;
|
|
|
|
|
int reversep;
|
|
|
|
|
HOST_WIDE_INT itrue, ifalse, diff, tmp;
|
|
|
|
|
int normalize, can_reverse;
|
2001-07-19 21:43:44 +02:00
|
|
|
|
enum machine_mode mode;
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
if (! no_new_pseudos
|
|
|
|
|
&& GET_CODE (if_info->a) == CONST_INT
|
|
|
|
|
&& GET_CODE (if_info->b) == CONST_INT)
|
|
|
|
|
{
|
2001-07-19 21:43:44 +02:00
|
|
|
|
mode = GET_MODE (if_info->x);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
ifalse = INTVAL (if_info->a);
|
|
|
|
|
itrue = INTVAL (if_info->b);
|
2001-11-27 10:07:59 +01:00
|
|
|
|
|
|
|
|
|
/* Make sure we can represent the difference between the two values. */
|
|
|
|
|
if ((itrue - ifalse > 0)
|
|
|
|
|
!= ((ifalse < 0) != (itrue < 0) ? ifalse < 0 : ifalse < itrue))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2001-07-20 05:59:19 +02:00
|
|
|
|
diff = trunc_int_for_mode (itrue - ifalse, mode);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
2001-02-28 17:20:43 +01:00
|
|
|
|
can_reverse = (reversed_comparison_code (if_info->cond, if_info->jump)
|
|
|
|
|
!= UNKNOWN);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
reversep = 0;
|
|
|
|
|
if (diff == STORE_FLAG_VALUE || diff == -STORE_FLAG_VALUE)
|
|
|
|
|
normalize = 0;
|
|
|
|
|
else if (ifalse == 0 && exact_log2 (itrue) >= 0
|
|
|
|
|
&& (STORE_FLAG_VALUE == 1
|
|
|
|
|
|| BRANCH_COST >= 2))
|
|
|
|
|
normalize = 1;
|
|
|
|
|
else if (itrue == 0 && exact_log2 (ifalse) >= 0 && can_reverse
|
|
|
|
|
&& (STORE_FLAG_VALUE == 1 || BRANCH_COST >= 2))
|
|
|
|
|
normalize = 1, reversep = 1;
|
|
|
|
|
else if (itrue == -1
|
|
|
|
|
&& (STORE_FLAG_VALUE == -1
|
|
|
|
|
|| BRANCH_COST >= 2))
|
|
|
|
|
normalize = -1;
|
|
|
|
|
else if (ifalse == -1 && can_reverse
|
|
|
|
|
&& (STORE_FLAG_VALUE == -1 || BRANCH_COST >= 2))
|
|
|
|
|
normalize = -1, reversep = 1;
|
|
|
|
|
else if ((BRANCH_COST >= 2 && STORE_FLAG_VALUE == -1)
|
|
|
|
|
|| BRANCH_COST >= 3)
|
|
|
|
|
normalize = -1;
|
|
|
|
|
else
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (reversep)
|
|
|
|
|
{
|
|
|
|
|
tmp = itrue; itrue = ifalse; ifalse = tmp;
|
2001-07-20 05:59:19 +02:00
|
|
|
|
diff = trunc_int_for_mode (-diff, mode);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
start_sequence ();
|
|
|
|
|
target = noce_emit_store_flag (if_info, if_info->x, reversep, normalize);
|
|
|
|
|
if (! target)
|
|
|
|
|
{
|
|
|
|
|
end_sequence ();
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* if (test) x = 3; else x = 4;
|
|
|
|
|
=> x = 3 + (test == 0); */
|
|
|
|
|
if (diff == STORE_FLAG_VALUE || diff == -STORE_FLAG_VALUE)
|
|
|
|
|
{
|
optabs.h (OTI_flodiv, [...]): Kill.
* optabs.h (OTI_flodiv, flodiv_optab): Kill.
* genopinit.c: Put floating point divide insns in sdiv_optab.
* expr.c (expand_expr): Use sdiv_optab, not flodiv_optab.
* config/gofast.h, config/c4x/c4x.h,
config/ia64/hpux_longdouble.h, config/mips/mips.h,
config/pa/long_double.h, config/rs6000/sysv4.h,
config/sparc/sparc.h: Put floating point divide libcalls in sdiv_optab.
* optabs.c (init_optab): Break into new_optab, init_optab, init_optabv.
(init_optabs): Use init_optabv for overflow-trapping optabs.
Don't init flodiv_optab. Give mov_optab, movstrict_optab, and
cmp_optab RTX codes so have_insn_for can find them.
* optabs.c (expand_simple_binop, expand_simple_unop,
have_insn_for, gen_sub3_insn): New interfaces.
* expr.h: Prototype new functions.
(enum optab_methods): Move here from optabs.h.
* builtins.c, combine.c, doloop.c, function.c, ifcvt.c,
loop.c, profile.c, simplify-rtx.c, stmt.c, unroll.c:
Use new functions instead of working directly with optabs.
* doloop.c, ifcvt.c, loop.c, profile.c, simplify-rtx.c,
unroll.c: Don't include optabs.h.
* caller-save.c, combine.c, function.c, stmt.c: Just include
insn-codes.h, not optabs.h.
* Makefile.in: Update dependencies.
* combine.c (make_compound_operation, simplify_comparison):
Fix typos testing for this or that instruction.
From-SVN: r45008
2001-08-18 21:59:46 +02:00
|
|
|
|
target = expand_simple_binop (mode,
|
|
|
|
|
(diff == STORE_FLAG_VALUE
|
|
|
|
|
? PLUS : MINUS),
|
|
|
|
|
GEN_INT (ifalse), target, if_info->x, 0,
|
|
|
|
|
OPTAB_WIDEN);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* if (test) x = 8; else x = 0;
|
|
|
|
|
=> x = (test != 0) << 3; */
|
|
|
|
|
else if (ifalse == 0 && (tmp = exact_log2 (itrue)) >= 0)
|
|
|
|
|
{
|
optabs.h (OTI_flodiv, [...]): Kill.
* optabs.h (OTI_flodiv, flodiv_optab): Kill.
* genopinit.c: Put floating point divide insns in sdiv_optab.
* expr.c (expand_expr): Use sdiv_optab, not flodiv_optab.
* config/gofast.h, config/c4x/c4x.h,
config/ia64/hpux_longdouble.h, config/mips/mips.h,
config/pa/long_double.h, config/rs6000/sysv4.h,
config/sparc/sparc.h: Put floating point divide libcalls in sdiv_optab.
* optabs.c (init_optab): Break into new_optab, init_optab, init_optabv.
(init_optabs): Use init_optabv for overflow-trapping optabs.
Don't init flodiv_optab. Give mov_optab, movstrict_optab, and
cmp_optab RTX codes so have_insn_for can find them.
* optabs.c (expand_simple_binop, expand_simple_unop,
have_insn_for, gen_sub3_insn): New interfaces.
* expr.h: Prototype new functions.
(enum optab_methods): Move here from optabs.h.
* builtins.c, combine.c, doloop.c, function.c, ifcvt.c,
loop.c, profile.c, simplify-rtx.c, stmt.c, unroll.c:
Use new functions instead of working directly with optabs.
* doloop.c, ifcvt.c, loop.c, profile.c, simplify-rtx.c,
unroll.c: Don't include optabs.h.
* caller-save.c, combine.c, function.c, stmt.c: Just include
insn-codes.h, not optabs.h.
* Makefile.in: Update dependencies.
* combine.c (make_compound_operation, simplify_comparison):
Fix typos testing for this or that instruction.
From-SVN: r45008
2001-08-18 21:59:46 +02:00
|
|
|
|
target = expand_simple_binop (mode, ASHIFT,
|
|
|
|
|
target, GEN_INT (tmp), if_info->x, 0,
|
|
|
|
|
OPTAB_WIDEN);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* if (test) x = -1; else x = b;
|
|
|
|
|
=> x = -(test != 0) | b; */
|
|
|
|
|
else if (itrue == -1)
|
|
|
|
|
{
|
optabs.h (OTI_flodiv, [...]): Kill.
* optabs.h (OTI_flodiv, flodiv_optab): Kill.
* genopinit.c: Put floating point divide insns in sdiv_optab.
* expr.c (expand_expr): Use sdiv_optab, not flodiv_optab.
* config/gofast.h, config/c4x/c4x.h,
config/ia64/hpux_longdouble.h, config/mips/mips.h,
config/pa/long_double.h, config/rs6000/sysv4.h,
config/sparc/sparc.h: Put floating point divide libcalls in sdiv_optab.
* optabs.c (init_optab): Break into new_optab, init_optab, init_optabv.
(init_optabs): Use init_optabv for overflow-trapping optabs.
Don't init flodiv_optab. Give mov_optab, movstrict_optab, and
cmp_optab RTX codes so have_insn_for can find them.
* optabs.c (expand_simple_binop, expand_simple_unop,
have_insn_for, gen_sub3_insn): New interfaces.
* expr.h: Prototype new functions.
(enum optab_methods): Move here from optabs.h.
* builtins.c, combine.c, doloop.c, function.c, ifcvt.c,
loop.c, profile.c, simplify-rtx.c, stmt.c, unroll.c:
Use new functions instead of working directly with optabs.
* doloop.c, ifcvt.c, loop.c, profile.c, simplify-rtx.c,
unroll.c: Don't include optabs.h.
* caller-save.c, combine.c, function.c, stmt.c: Just include
insn-codes.h, not optabs.h.
* Makefile.in: Update dependencies.
* combine.c (make_compound_operation, simplify_comparison):
Fix typos testing for this or that instruction.
From-SVN: r45008
2001-08-18 21:59:46 +02:00
|
|
|
|
target = expand_simple_binop (mode, IOR,
|
|
|
|
|
target, GEN_INT (ifalse), if_info->x, 0,
|
|
|
|
|
OPTAB_WIDEN);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* if (test) x = a; else x = b;
|
|
|
|
|
=> x = (-(test != 0) & (b - a)) + a; */
|
|
|
|
|
else
|
|
|
|
|
{
|
optabs.h (OTI_flodiv, [...]): Kill.
* optabs.h (OTI_flodiv, flodiv_optab): Kill.
* genopinit.c: Put floating point divide insns in sdiv_optab.
* expr.c (expand_expr): Use sdiv_optab, not flodiv_optab.
* config/gofast.h, config/c4x/c4x.h,
config/ia64/hpux_longdouble.h, config/mips/mips.h,
config/pa/long_double.h, config/rs6000/sysv4.h,
config/sparc/sparc.h: Put floating point divide libcalls in sdiv_optab.
* optabs.c (init_optab): Break into new_optab, init_optab, init_optabv.
(init_optabs): Use init_optabv for overflow-trapping optabs.
Don't init flodiv_optab. Give mov_optab, movstrict_optab, and
cmp_optab RTX codes so have_insn_for can find them.
* optabs.c (expand_simple_binop, expand_simple_unop,
have_insn_for, gen_sub3_insn): New interfaces.
* expr.h: Prototype new functions.
(enum optab_methods): Move here from optabs.h.
* builtins.c, combine.c, doloop.c, function.c, ifcvt.c,
loop.c, profile.c, simplify-rtx.c, stmt.c, unroll.c:
Use new functions instead of working directly with optabs.
* doloop.c, ifcvt.c, loop.c, profile.c, simplify-rtx.c,
unroll.c: Don't include optabs.h.
* caller-save.c, combine.c, function.c, stmt.c: Just include
insn-codes.h, not optabs.h.
* Makefile.in: Update dependencies.
* combine.c (make_compound_operation, simplify_comparison):
Fix typos testing for this or that instruction.
From-SVN: r45008
2001-08-18 21:59:46 +02:00
|
|
|
|
target = expand_simple_binop (mode, AND,
|
|
|
|
|
target, GEN_INT (diff), if_info->x, 0,
|
|
|
|
|
OPTAB_WIDEN);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
if (target)
|
optabs.h (OTI_flodiv, [...]): Kill.
* optabs.h (OTI_flodiv, flodiv_optab): Kill.
* genopinit.c: Put floating point divide insns in sdiv_optab.
* expr.c (expand_expr): Use sdiv_optab, not flodiv_optab.
* config/gofast.h, config/c4x/c4x.h,
config/ia64/hpux_longdouble.h, config/mips/mips.h,
config/pa/long_double.h, config/rs6000/sysv4.h,
config/sparc/sparc.h: Put floating point divide libcalls in sdiv_optab.
* optabs.c (init_optab): Break into new_optab, init_optab, init_optabv.
(init_optabs): Use init_optabv for overflow-trapping optabs.
Don't init flodiv_optab. Give mov_optab, movstrict_optab, and
cmp_optab RTX codes so have_insn_for can find them.
* optabs.c (expand_simple_binop, expand_simple_unop,
have_insn_for, gen_sub3_insn): New interfaces.
* expr.h: Prototype new functions.
(enum optab_methods): Move here from optabs.h.
* builtins.c, combine.c, doloop.c, function.c, ifcvt.c,
loop.c, profile.c, simplify-rtx.c, stmt.c, unroll.c:
Use new functions instead of working directly with optabs.
* doloop.c, ifcvt.c, loop.c, profile.c, simplify-rtx.c,
unroll.c: Don't include optabs.h.
* caller-save.c, combine.c, function.c, stmt.c: Just include
insn-codes.h, not optabs.h.
* Makefile.in: Update dependencies.
* combine.c (make_compound_operation, simplify_comparison):
Fix typos testing for this or that instruction.
From-SVN: r45008
2001-08-18 21:59:46 +02:00
|
|
|
|
target = expand_simple_binop (mode, PLUS,
|
|
|
|
|
target, GEN_INT (ifalse),
|
|
|
|
|
if_info->x, 0, OPTAB_WIDEN);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (! target)
|
|
|
|
|
{
|
|
|
|
|
end_sequence ();
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (target != if_info->x)
|
2001-04-02 10:17:15 +02:00
|
|
|
|
noce_emit_move_insn (if_info->x, target);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
seq = get_insns ();
|
|
|
|
|
end_sequence ();
|
2000-05-26 01:53:23 +02:00
|
|
|
|
|
|
|
|
|
if (seq_contains_jump (seq))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2000-04-30 13:01:53 +02:00
|
|
|
|
emit_insns_before (seq, if_info->cond_earliest);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Convert "if (test) foo++" into "foo += (test != 0)", and
|
|
|
|
|
similarly for "foo--". */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
noce_try_store_flag_inc (if_info)
|
|
|
|
|
struct noce_if_info *if_info;
|
|
|
|
|
{
|
|
|
|
|
rtx target, seq;
|
|
|
|
|
int subtract, normalize;
|
|
|
|
|
|
|
|
|
|
if (! no_new_pseudos
|
|
|
|
|
&& (BRANCH_COST >= 2
|
|
|
|
|
|| HAVE_incscc
|
|
|
|
|
|| HAVE_decscc)
|
|
|
|
|
/* Should be no `else' case to worry about. */
|
|
|
|
|
&& if_info->b == if_info->x
|
|
|
|
|
&& GET_CODE (if_info->a) == PLUS
|
|
|
|
|
&& (XEXP (if_info->a, 1) == const1_rtx
|
|
|
|
|
|| XEXP (if_info->a, 1) == constm1_rtx)
|
|
|
|
|
&& rtx_equal_p (XEXP (if_info->a, 0), if_info->x)
|
2001-02-28 17:20:43 +01:00
|
|
|
|
&& (reversed_comparison_code (if_info->cond, if_info->jump)
|
|
|
|
|
!= UNKNOWN))
|
2000-04-30 13:01:53 +02:00
|
|
|
|
{
|
|
|
|
|
if (STORE_FLAG_VALUE == INTVAL (XEXP (if_info->a, 1)))
|
|
|
|
|
subtract = 0, normalize = 0;
|
|
|
|
|
else if (-STORE_FLAG_VALUE == INTVAL (XEXP (if_info->a, 1)))
|
|
|
|
|
subtract = 1, normalize = 0;
|
|
|
|
|
else
|
|
|
|
|
subtract = 0, normalize = INTVAL (XEXP (if_info->a, 1));
|
|
|
|
|
|
|
|
|
|
start_sequence ();
|
|
|
|
|
|
|
|
|
|
target = noce_emit_store_flag (if_info,
|
|
|
|
|
gen_reg_rtx (GET_MODE (if_info->x)),
|
|
|
|
|
1, normalize);
|
|
|
|
|
|
|
|
|
|
if (target)
|
optabs.h (OTI_flodiv, [...]): Kill.
* optabs.h (OTI_flodiv, flodiv_optab): Kill.
* genopinit.c: Put floating point divide insns in sdiv_optab.
* expr.c (expand_expr): Use sdiv_optab, not flodiv_optab.
* config/gofast.h, config/c4x/c4x.h,
config/ia64/hpux_longdouble.h, config/mips/mips.h,
config/pa/long_double.h, config/rs6000/sysv4.h,
config/sparc/sparc.h: Put floating point divide libcalls in sdiv_optab.
* optabs.c (init_optab): Break into new_optab, init_optab, init_optabv.
(init_optabs): Use init_optabv for overflow-trapping optabs.
Don't init flodiv_optab. Give mov_optab, movstrict_optab, and
cmp_optab RTX codes so have_insn_for can find them.
* optabs.c (expand_simple_binop, expand_simple_unop,
have_insn_for, gen_sub3_insn): New interfaces.
* expr.h: Prototype new functions.
(enum optab_methods): Move here from optabs.h.
* builtins.c, combine.c, doloop.c, function.c, ifcvt.c,
loop.c, profile.c, simplify-rtx.c, stmt.c, unroll.c:
Use new functions instead of working directly with optabs.
* doloop.c, ifcvt.c, loop.c, profile.c, simplify-rtx.c,
unroll.c: Don't include optabs.h.
* caller-save.c, combine.c, function.c, stmt.c: Just include
insn-codes.h, not optabs.h.
* Makefile.in: Update dependencies.
* combine.c (make_compound_operation, simplify_comparison):
Fix typos testing for this or that instruction.
From-SVN: r45008
2001-08-18 21:59:46 +02:00
|
|
|
|
target = expand_simple_binop (GET_MODE (if_info->x),
|
|
|
|
|
subtract ? MINUS : PLUS,
|
|
|
|
|
if_info->x, target, if_info->x,
|
|
|
|
|
0, OPTAB_WIDEN);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
if (target)
|
|
|
|
|
{
|
|
|
|
|
if (target != if_info->x)
|
2001-04-02 10:17:15 +02:00
|
|
|
|
noce_emit_move_insn (if_info->x, target);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
seq = get_insns ();
|
|
|
|
|
end_sequence ();
|
2000-05-26 01:53:23 +02:00
|
|
|
|
|
|
|
|
|
if (seq_contains_jump (seq))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2000-04-30 13:01:53 +02:00
|
|
|
|
emit_insns_before (seq, if_info->cond_earliest);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
end_sequence ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Convert "if (test) x = 0;" to "x &= -(test == 0);" */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
noce_try_store_flag_mask (if_info)
|
|
|
|
|
struct noce_if_info *if_info;
|
|
|
|
|
{
|
|
|
|
|
rtx target, seq;
|
|
|
|
|
int reversep;
|
|
|
|
|
|
|
|
|
|
reversep = 0;
|
|
|
|
|
if (! no_new_pseudos
|
|
|
|
|
&& (BRANCH_COST >= 2
|
|
|
|
|
|| STORE_FLAG_VALUE == -1)
|
|
|
|
|
&& ((if_info->a == const0_rtx
|
|
|
|
|
&& rtx_equal_p (if_info->b, if_info->x))
|
2001-02-28 17:20:43 +01:00
|
|
|
|
|| ((reversep = (reversed_comparison_code (if_info->cond,
|
|
|
|
|
if_info->jump)
|
|
|
|
|
!= UNKNOWN))
|
2000-04-30 13:01:53 +02:00
|
|
|
|
&& if_info->b == const0_rtx
|
|
|
|
|
&& rtx_equal_p (if_info->a, if_info->x))))
|
|
|
|
|
{
|
|
|
|
|
start_sequence ();
|
|
|
|
|
target = noce_emit_store_flag (if_info,
|
|
|
|
|
gen_reg_rtx (GET_MODE (if_info->x)),
|
|
|
|
|
reversep, -1);
|
|
|
|
|
if (target)
|
optabs.h (OTI_flodiv, [...]): Kill.
* optabs.h (OTI_flodiv, flodiv_optab): Kill.
* genopinit.c: Put floating point divide insns in sdiv_optab.
* expr.c (expand_expr): Use sdiv_optab, not flodiv_optab.
* config/gofast.h, config/c4x/c4x.h,
config/ia64/hpux_longdouble.h, config/mips/mips.h,
config/pa/long_double.h, config/rs6000/sysv4.h,
config/sparc/sparc.h: Put floating point divide libcalls in sdiv_optab.
* optabs.c (init_optab): Break into new_optab, init_optab, init_optabv.
(init_optabs): Use init_optabv for overflow-trapping optabs.
Don't init flodiv_optab. Give mov_optab, movstrict_optab, and
cmp_optab RTX codes so have_insn_for can find them.
* optabs.c (expand_simple_binop, expand_simple_unop,
have_insn_for, gen_sub3_insn): New interfaces.
* expr.h: Prototype new functions.
(enum optab_methods): Move here from optabs.h.
* builtins.c, combine.c, doloop.c, function.c, ifcvt.c,
loop.c, profile.c, simplify-rtx.c, stmt.c, unroll.c:
Use new functions instead of working directly with optabs.
* doloop.c, ifcvt.c, loop.c, profile.c, simplify-rtx.c,
unroll.c: Don't include optabs.h.
* caller-save.c, combine.c, function.c, stmt.c: Just include
insn-codes.h, not optabs.h.
* Makefile.in: Update dependencies.
* combine.c (make_compound_operation, simplify_comparison):
Fix typos testing for this or that instruction.
From-SVN: r45008
2001-08-18 21:59:46 +02:00
|
|
|
|
target = expand_simple_binop (GET_MODE (if_info->x), AND,
|
|
|
|
|
if_info->x, target, if_info->x, 0,
|
|
|
|
|
OPTAB_WIDEN);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
if (target)
|
|
|
|
|
{
|
|
|
|
|
if (target != if_info->x)
|
2001-04-02 10:17:15 +02:00
|
|
|
|
noce_emit_move_insn (if_info->x, target);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
seq = get_insns ();
|
|
|
|
|
end_sequence ();
|
2000-05-26 01:53:23 +02:00
|
|
|
|
|
|
|
|
|
if (seq_contains_jump (seq))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2000-04-30 13:01:53 +02:00
|
|
|
|
emit_insns_before (seq, if_info->cond_earliest);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
end_sequence ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Helper function for noce_try_cmove and noce_try_cmove_arith. */
|
|
|
|
|
|
|
|
|
|
static rtx
|
|
|
|
|
noce_emit_cmove (if_info, x, code, cmp_a, cmp_b, vfalse, vtrue)
|
|
|
|
|
struct noce_if_info *if_info;
|
|
|
|
|
rtx x, cmp_a, cmp_b, vfalse, vtrue;
|
|
|
|
|
enum rtx_code code;
|
|
|
|
|
{
|
|
|
|
|
/* If earliest == jump, try to build the cmove insn directly.
|
|
|
|
|
This is helpful when combine has created some complex condition
|
|
|
|
|
(like for alpha's cmovlbs) that we can't hope to regenerate
|
|
|
|
|
through the normal interface. */
|
|
|
|
|
|
|
|
|
|
if (if_info->cond_earliest == if_info->jump)
|
|
|
|
|
{
|
|
|
|
|
rtx tmp;
|
|
|
|
|
|
|
|
|
|
tmp = gen_rtx_fmt_ee (code, GET_MODE (if_info->cond), cmp_a, cmp_b);
|
|
|
|
|
tmp = gen_rtx_IF_THEN_ELSE (GET_MODE (x), tmp, vtrue, vfalse);
|
|
|
|
|
tmp = gen_rtx_SET (VOIDmode, x, tmp);
|
|
|
|
|
|
|
|
|
|
start_sequence ();
|
|
|
|
|
tmp = emit_insn (tmp);
|
|
|
|
|
|
|
|
|
|
if (recog_memoized (tmp) >= 0)
|
|
|
|
|
{
|
|
|
|
|
tmp = get_insns ();
|
|
|
|
|
end_sequence ();
|
|
|
|
|
emit_insns (tmp);
|
|
|
|
|
|
|
|
|
|
return x;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
end_sequence ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Don't even try if the comparison operands are weird. */
|
|
|
|
|
if (! general_operand (cmp_a, GET_MODE (cmp_a))
|
|
|
|
|
|| ! general_operand (cmp_b, GET_MODE (cmp_b)))
|
|
|
|
|
return NULL_RTX;
|
|
|
|
|
|
2000-05-01 23:21:44 +02:00
|
|
|
|
#if HAVE_conditional_move
|
2000-04-30 13:01:53 +02:00
|
|
|
|
return emit_conditional_move (x, code, cmp_a, cmp_b, VOIDmode,
|
|
|
|
|
vtrue, vfalse, GET_MODE (x),
|
|
|
|
|
(code == LTU || code == GEU
|
|
|
|
|
|| code == LEU || code == GTU));
|
2000-05-01 23:21:44 +02:00
|
|
|
|
#else
|
|
|
|
|
/* We'll never get here, as noce_process_if_block doesn't call the
|
|
|
|
|
functions involved. Ifdef code, however, should be discouraged
|
|
|
|
|
because it leads to typos in the code not selected. However,
|
|
|
|
|
emit_conditional_move won't exist either. */
|
|
|
|
|
return NULL_RTX;
|
|
|
|
|
#endif
|
2000-04-30 13:01:53 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Try only simple constants and registers here. More complex cases
|
|
|
|
|
are handled in noce_try_cmove_arith after noce_try_store_flag_arith
|
|
|
|
|
has had a go at it. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
noce_try_cmove (if_info)
|
|
|
|
|
struct noce_if_info *if_info;
|
|
|
|
|
{
|
|
|
|
|
enum rtx_code code;
|
|
|
|
|
rtx target, seq;
|
|
|
|
|
|
|
|
|
|
if ((CONSTANT_P (if_info->a) || register_operand (if_info->a, VOIDmode))
|
|
|
|
|
&& (CONSTANT_P (if_info->b) || register_operand (if_info->b, VOIDmode)))
|
|
|
|
|
{
|
|
|
|
|
start_sequence ();
|
|
|
|
|
|
|
|
|
|
code = GET_CODE (if_info->cond);
|
|
|
|
|
target = noce_emit_cmove (if_info, if_info->x, code,
|
|
|
|
|
XEXP (if_info->cond, 0),
|
|
|
|
|
XEXP (if_info->cond, 1),
|
|
|
|
|
if_info->a, if_info->b);
|
|
|
|
|
|
|
|
|
|
if (target)
|
|
|
|
|
{
|
|
|
|
|
if (target != if_info->x)
|
2001-04-02 10:17:15 +02:00
|
|
|
|
noce_emit_move_insn (if_info->x, target);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
seq = get_insns ();
|
|
|
|
|
end_sequence ();
|
|
|
|
|
emit_insns_before (seq, if_info->cond_earliest);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
end_sequence ();
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Try more complex cases involving conditional_move. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
noce_try_cmove_arith (if_info)
|
|
|
|
|
struct noce_if_info *if_info;
|
|
|
|
|
{
|
|
|
|
|
rtx a = if_info->a;
|
|
|
|
|
rtx b = if_info->b;
|
|
|
|
|
rtx x = if_info->x;
|
|
|
|
|
rtx insn_a, insn_b;
|
|
|
|
|
rtx tmp, target;
|
|
|
|
|
int is_mem = 0;
|
|
|
|
|
enum rtx_code code;
|
|
|
|
|
|
|
|
|
|
/* A conditional move from two memory sources is equivalent to a
|
|
|
|
|
conditional on their addresses followed by a load. Don't do this
|
|
|
|
|
early because it'll screw alias analysis. Note that we've
|
|
|
|
|
already checked for no side effects. */
|
|
|
|
|
if (! no_new_pseudos && cse_not_expected
|
|
|
|
|
&& GET_CODE (a) == MEM && GET_CODE (b) == MEM
|
|
|
|
|
&& BRANCH_COST >= 5)
|
|
|
|
|
{
|
|
|
|
|
a = XEXP (a, 0);
|
|
|
|
|
b = XEXP (b, 0);
|
|
|
|
|
x = gen_reg_rtx (Pmode);
|
|
|
|
|
is_mem = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ??? We could handle this if we knew that a load from A or B could
|
2000-05-03 13:16:35 +02:00
|
|
|
|
not fault. This is also true if we've already loaded
|
2000-04-30 13:01:53 +02:00
|
|
|
|
from the address along the path from ENTRY. */
|
2000-05-03 13:16:35 +02:00
|
|
|
|
else if (may_trap_p (a) || may_trap_p (b))
|
2000-04-30 13:01:53 +02:00
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* if (test) x = a + b; else x = c - d;
|
|
|
|
|
=> y = a + b;
|
|
|
|
|
x = c - d;
|
|
|
|
|
if (test)
|
|
|
|
|
x = y;
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
code = GET_CODE (if_info->cond);
|
|
|
|
|
insn_a = if_info->insn_a;
|
|
|
|
|
insn_b = if_info->insn_b;
|
|
|
|
|
|
|
|
|
|
/* Possibly rearrange operands to make things come out more natural. */
|
2001-02-28 17:20:43 +01:00
|
|
|
|
if (reversed_comparison_code (if_info->cond, if_info->jump) != UNKNOWN)
|
2000-04-30 13:01:53 +02:00
|
|
|
|
{
|
|
|
|
|
int reversep = 0;
|
|
|
|
|
if (rtx_equal_p (b, x))
|
|
|
|
|
reversep = 1;
|
|
|
|
|
else if (general_operand (b, GET_MODE (b)))
|
|
|
|
|
reversep = 1;
|
|
|
|
|
|
|
|
|
|
if (reversep)
|
|
|
|
|
{
|
2001-02-28 17:20:43 +01:00
|
|
|
|
code = reversed_comparison_code (if_info->cond, if_info->jump);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
tmp = a, a = b, b = tmp;
|
|
|
|
|
tmp = insn_a, insn_a = insn_b, insn_b = tmp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
start_sequence ();
|
|
|
|
|
|
|
|
|
|
/* If either operand is complex, load it into a register first.
|
|
|
|
|
The best way to do this is to copy the original insn. In this
|
|
|
|
|
way we preserve any clobbers etc that the insn may have had.
|
|
|
|
|
This is of course not possible in the IS_MEM case. */
|
|
|
|
|
if (! general_operand (a, GET_MODE (a)))
|
|
|
|
|
{
|
|
|
|
|
rtx set;
|
|
|
|
|
|
|
|
|
|
if (no_new_pseudos)
|
|
|
|
|
goto end_seq_and_fail;
|
|
|
|
|
|
|
|
|
|
if (is_mem)
|
|
|
|
|
{
|
|
|
|
|
tmp = gen_reg_rtx (GET_MODE (a));
|
|
|
|
|
tmp = emit_insn (gen_rtx_SET (VOIDmode, tmp, a));
|
|
|
|
|
}
|
|
|
|
|
else if (! insn_a)
|
|
|
|
|
goto end_seq_and_fail;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
a = gen_reg_rtx (GET_MODE (a));
|
|
|
|
|
tmp = copy_rtx (insn_a);
|
|
|
|
|
set = single_set (tmp);
|
|
|
|
|
SET_DEST (set) = a;
|
|
|
|
|
tmp = emit_insn (PATTERN (tmp));
|
|
|
|
|
}
|
|
|
|
|
if (recog_memoized (tmp) < 0)
|
|
|
|
|
goto end_seq_and_fail;
|
|
|
|
|
}
|
|
|
|
|
if (! general_operand (b, GET_MODE (b)))
|
|
|
|
|
{
|
|
|
|
|
rtx set;
|
|
|
|
|
|
|
|
|
|
if (no_new_pseudos)
|
|
|
|
|
goto end_seq_and_fail;
|
|
|
|
|
|
|
|
|
|
if (is_mem)
|
|
|
|
|
{
|
|
|
|
|
tmp = gen_reg_rtx (GET_MODE (b));
|
|
|
|
|
tmp = emit_insn (gen_rtx_SET (VOIDmode, tmp, b));
|
|
|
|
|
}
|
|
|
|
|
else if (! insn_b)
|
|
|
|
|
goto end_seq_and_fail;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
b = gen_reg_rtx (GET_MODE (b));
|
|
|
|
|
tmp = copy_rtx (insn_b);
|
|
|
|
|
set = single_set (tmp);
|
|
|
|
|
SET_DEST (set) = b;
|
|
|
|
|
tmp = emit_insn (PATTERN (tmp));
|
|
|
|
|
}
|
|
|
|
|
if (recog_memoized (tmp) < 0)
|
|
|
|
|
goto end_seq_and_fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
target = noce_emit_cmove (if_info, x, code, XEXP (if_info->cond, 0),
|
|
|
|
|
XEXP (if_info->cond, 1), a, b);
|
|
|
|
|
|
|
|
|
|
if (! target)
|
|
|
|
|
goto end_seq_and_fail;
|
|
|
|
|
|
|
|
|
|
/* If we're handling a memory for above, emit the load now. */
|
|
|
|
|
if (is_mem)
|
|
|
|
|
{
|
|
|
|
|
tmp = gen_rtx_MEM (GET_MODE (if_info->x), target);
|
|
|
|
|
|
|
|
|
|
/* Copy over flags as appropriate. */
|
|
|
|
|
if (MEM_VOLATILE_P (if_info->a) || MEM_VOLATILE_P (if_info->b))
|
|
|
|
|
MEM_VOLATILE_P (tmp) = 1;
|
|
|
|
|
if (MEM_IN_STRUCT_P (if_info->a) && MEM_IN_STRUCT_P (if_info->b))
|
|
|
|
|
MEM_IN_STRUCT_P (tmp) = 1;
|
|
|
|
|
if (MEM_SCALAR_P (if_info->a) && MEM_SCALAR_P (if_info->b))
|
|
|
|
|
MEM_SCALAR_P (tmp) = 1;
|
|
|
|
|
if (MEM_ALIAS_SET (if_info->a) == MEM_ALIAS_SET (if_info->b))
|
alias.c (set_mem_alias_set): New function.
* alias.c (set_mem_alias_set): New function.
* rtl.h (set_mem_alias_set): Declare it.
* builtins.c (expand_builtin_return_addr): Call it instead of
using MEM_ALIAS_SET accessor.
(expand_builtin_setjmp_setup, expand_builtin_longjmp): Likewise.
(get_memory_rtx, expand_builtin_va_arg): Likewise.
(expand_builtin_va_copy):Likewise.
* caller-save.c (setup_save_areas): Likewise.
* calls.c (compute_argument_addresses): Likewise.
* explow.c (set_mem_attributes): Likewise.
* expr.c (emit_single_push_insn, emit_push_insn): Likewise.
(expand_assignment, store_constructor_field, store_field): Likewise.
(expand_expr_unaligned): Likewise.
* function.c (assign_stack_temp_for_type): Likewise.
(put_reg_into_stack, gen_mem_addressof): Likewise.
* ifcvt.c (noce_try_cmove_arith): Likewise.
* reload1.c (reload, alter_reg): Likewise.
* config/alpha/alpha.c (get_aligned_mem): Likewise.
(alpha_set_memflags_1, alpha_expand_unaligned_load): Likewise.
(alpha_expand_unaligned_store): Likewise
(alpha_expand_unaligned_load_words): Likewise.
(alpha_expand_unaligned_store_words): Likewise.
(alpha_expand_block_clear, alpha_expand_prologue): Likewise.
(alpha_expand_epilogue): Likewise.
* config/arc/arc.c (arc_setup_incoming_varargs): Likewise.
* config/clipper/clipper.c (clipper_builtin_saveregs): Likewise.
* config/i386/i386.c (legitimize_pic_address): Likewise.
* config/i960/i960.c (setup_incoming_varargs): Likewise.
* config/ia64/ia64.c (spill_restore_mem): Likewise.
* config/m32r/m32r.c (m32r_setup_incoming_varargs): Likewise.
* config/m8k/m88k.c (m88k_builtin_saveregs): Likewise.
* config/mips/mips.c (mips_va_arg): Likewise.
* config/mn10300/mn10300.c (mn10300_builtin_saveregs): Likewise.
* config/pa/pa.c (hppa_builtin_saveregs): Likewise.
* config/rs6000/rs6000.c (rs6000_emit_move): Likewise.
(setup_incoming_varargs, rs6000_va_arg): Likewise.
(rs6000_emit_eh_toc_restore, rs6000_emit_prologue): Likewise.
(rs6000_emit_epilogue): Likewise.
* config/sh/sh.c (sh_builtin_saveregs): Likewise.
* config/sparc/sparc.c (sparc_va_arg): Likewise.
* config/v850/v850.c (v850_va_arg): Likewise.
From-SVN: r43951
2001-07-11 22:35:55 +02:00
|
|
|
|
set_mem_alias_set (tmp, MEM_ALIAS_SET (if_info->a));
|
alias.c (can_address_p): Compnonents are not addressable if the containing type has alias set 0.
* alias.c (can_address_p): Compnonents are not addressable if
the containing type has alias set 0.
(get_alias_set): Rework to use STRIP_NOPS.
Only call front-end routine on object, type, or object with
NOPs stripped, not inner values.
Use language hook to call front-end routine.
* builtins.c (get_memory_rtx): Always call set_mem_attributes.
(expand_builtin_apply): Call set_mem_align on MEMs we make.
Don't pass alignment to emit_block_move.
(expand_builtin_memcpy, expand_builtin_va_copy): Likewise.
(expand_builtin_memset): Likewise, but for clear_storage.
* c-common.c (lang_get_alias_set): Renamed to c_common_alias_set
and remove C++ specific parts.
* c-common.h (c_common_get_alias_set): Add declaration.
* c-lang.c (LANG_HOOKS_GET_ALIAS_SET): New macro.
* calls.c (emit_call_1): Fix typo in sibcall_pop case.
(save_fixed_argument_area): Call set_mem_align.
Remove alignment in call to emit_block_move.
(emit_library_call_value_1, store_one_arg): Likewise.
(target_for_arg): Remove; disabled long ago.
* emit-rtl.c (set_mem_attributes): Rework to only call get_mem_attrs
once and similar cleanups.
(offset_address): Use proper introductory comment.
* expr.c (emit_block_move): Use alignment from that of MEM args, not
from explicit operand; all callers changed.
(clear_storage): Likewise.
(expand_assignment): Don't call set_mem_alias_set on to_rtx.
(store_field): Remove kludge on alias set used for to_rtx.
(highest_pow2_factor, case *_DIV_EXPR): Never return 0.
(expand_expr_unaligned): Call set_mem_attributes instead of
set_mem_alias_set.
* expr.h (emit_block_move, clear_storage): Remove ALIGN argument.
* function.c (assign_stack_temp_for_type): Set MEM alignment.
(expand_function_end): Track MEM attributes of trampolines.
* ifcvt.c (noce_try_cmove_arith): Set alignment of new MEM.
* integrate.c (copy_rtx_and_substitute, case CALL): Copy memory
attributes from original.
* langhooks.c (lang_hook_default_get_alias_set): New function.
(hook_get_alias_set_0): New function.
* langhooks.h (hook_get_alias_set_0): New declaration.
(lang_hook_default_get_alias_set): Likewise.
(LANG_HOOKS_GET_ALIAS_SET): New macro; add to initializer.
* reload1.c (alter_reg): Use adjust_address_nv.
* rtl.c (get_mode_alignment): Moved to here.
* rtl.h (MEM_ALIGN): Take default from mode, if not BLKmode, and
change default if unknown from 1 to BITS_PER_UNIT.
* stor-layout.c (get_mode_alignment): Remove from here.
* toplev.h (struct lang_hoks): Add get_alias_set field.
* tree.h (lang_get_alias_set): Delete declaration.
* config/arc/arc.c (arc_setup_incoming_varags): Set MEM alignment.
* config/i386/i386.c (ix86_setup_incoming_varargs): Likewise.
(ix86_va_arg): Likewise.
* config/i960/i960.c (i960_setup_incoming_varargs): Likewise.
* config/pa/pa.c (hppa_builtin_saveregs): Likewise.
* config/sparc/sparc.c (sparc_va_arg): Likewise.
* config/rs6000/rs6000.c (setup_incoming_varargs): Likewise.
(expand_block_move_mem): Remove dead code.
* cp/cp-lang.c (cxx_get_alias_set): New function.
Point LANG_HOOKS_GET_ALIAS_SET to it.
* f/com.c (LANG_HOOKS_GET_ALIAS_SET): New macro.
(lang_get_alias_set): Delete.
* java/lang.c (lang_get_alias_set): Deleted.
From-SVN: r46440
2001-10-23 20:51:18 +02:00
|
|
|
|
set_mem_align (tmp,
|
|
|
|
|
MIN (MEM_ALIGN (if_info->a), MEM_ALIGN (if_info->b)));
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
2001-04-02 10:17:15 +02:00
|
|
|
|
noce_emit_move_insn (if_info->x, tmp);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
}
|
|
|
|
|
else if (target != x)
|
2001-04-02 10:17:15 +02:00
|
|
|
|
noce_emit_move_insn (x, target);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
tmp = get_insns ();
|
|
|
|
|
end_sequence ();
|
|
|
|
|
emit_insns_before (tmp, if_info->cond_earliest);
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
end_seq_and_fail:
|
|
|
|
|
end_sequence ();
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2001-02-25 20:34:06 +01:00
|
|
|
|
/* For most cases, the simplified condition we found is the best
|
|
|
|
|
choice, but this is not the case for the min/max/abs transforms.
|
|
|
|
|
For these we wish to know that it is A or B in the condition. */
|
|
|
|
|
|
|
|
|
|
static rtx
|
|
|
|
|
noce_get_alt_condition (if_info, target, earliest)
|
|
|
|
|
struct noce_if_info *if_info;
|
|
|
|
|
rtx target;
|
|
|
|
|
rtx *earliest;
|
|
|
|
|
{
|
|
|
|
|
rtx cond, set, insn;
|
|
|
|
|
int reverse;
|
|
|
|
|
|
|
|
|
|
/* If target is already mentioned in the known condition, return it. */
|
|
|
|
|
if (reg_mentioned_p (target, if_info->cond))
|
|
|
|
|
{
|
|
|
|
|
*earliest = if_info->cond_earliest;
|
|
|
|
|
return if_info->cond;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
set = pc_set (if_info->jump);
|
|
|
|
|
cond = XEXP (SET_SRC (set), 0);
|
|
|
|
|
reverse
|
|
|
|
|
= GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF
|
|
|
|
|
&& XEXP (XEXP (SET_SRC (set), 2), 0) == JUMP_LABEL (if_info->jump);
|
|
|
|
|
|
2001-07-28 05:13:34 +02:00
|
|
|
|
/* If we're looking for a constant, try to make the conditional
|
|
|
|
|
have that constant in it. There are two reasons why it may
|
|
|
|
|
not have the constant we want:
|
|
|
|
|
|
|
|
|
|
1. GCC may have needed to put the constant in a register, because
|
|
|
|
|
the target can't compare directly against that constant. For
|
|
|
|
|
this case, we look for a SET immediately before the comparison
|
|
|
|
|
that puts a constant in that register.
|
|
|
|
|
|
|
|
|
|
2. GCC may have canonicalized the conditional, for example
|
|
|
|
|
replacing "if x < 4" with "if x <= 3". We can undo that (or
|
|
|
|
|
make equivalent types of changes) to get the constants we need
|
|
|
|
|
if they're off by one in the right direction. */
|
|
|
|
|
|
|
|
|
|
if (GET_CODE (target) == CONST_INT)
|
|
|
|
|
{
|
|
|
|
|
enum rtx_code code = GET_CODE (if_info->cond);
|
|
|
|
|
rtx op_a = XEXP (if_info->cond, 0);
|
|
|
|
|
rtx op_b = XEXP (if_info->cond, 1);
|
|
|
|
|
rtx prev_insn;
|
|
|
|
|
|
|
|
|
|
/* First, look to see if we put a constant in a register. */
|
|
|
|
|
prev_insn = PREV_INSN (if_info->cond_earliest);
|
|
|
|
|
if (prev_insn
|
|
|
|
|
&& INSN_P (prev_insn)
|
|
|
|
|
&& GET_CODE (PATTERN (prev_insn)) == SET)
|
|
|
|
|
{
|
|
|
|
|
rtx src = find_reg_equal_equiv_note (prev_insn);
|
|
|
|
|
if (!src)
|
|
|
|
|
src = SET_SRC (PATTERN (prev_insn));
|
|
|
|
|
if (GET_CODE (src) == CONST_INT)
|
|
|
|
|
{
|
|
|
|
|
if (rtx_equal_p (op_a, SET_DEST (PATTERN (prev_insn))))
|
2001-08-03 18:31:44 +02:00
|
|
|
|
op_a = src;
|
2001-07-28 05:13:34 +02:00
|
|
|
|
else if (rtx_equal_p (op_b, SET_DEST (PATTERN (prev_insn))))
|
2001-08-03 18:31:44 +02:00
|
|
|
|
op_b = src;
|
2001-07-28 05:13:34 +02:00
|
|
|
|
|
|
|
|
|
if (GET_CODE (op_a) == CONST_INT)
|
|
|
|
|
{
|
|
|
|
|
rtx tmp = op_a;
|
|
|
|
|
op_a = op_b;
|
|
|
|
|
op_b = tmp;
|
|
|
|
|
code = swap_condition (code);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Now, look to see if we can get the right constant by
|
|
|
|
|
adjusting the conditional. */
|
|
|
|
|
if (GET_CODE (op_b) == CONST_INT)
|
|
|
|
|
{
|
|
|
|
|
HOST_WIDE_INT desired_val = INTVAL (target);
|
|
|
|
|
HOST_WIDE_INT actual_val = INTVAL (op_b);
|
|
|
|
|
|
|
|
|
|
switch (code)
|
|
|
|
|
{
|
|
|
|
|
case LT:
|
|
|
|
|
if (actual_val == desired_val + 1)
|
|
|
|
|
{
|
|
|
|
|
code = LE;
|
|
|
|
|
op_b = GEN_INT (desired_val);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case LE:
|
|
|
|
|
if (actual_val == desired_val - 1)
|
|
|
|
|
{
|
|
|
|
|
code = LT;
|
|
|
|
|
op_b = GEN_INT (desired_val);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case GT:
|
|
|
|
|
if (actual_val == desired_val - 1)
|
|
|
|
|
{
|
|
|
|
|
code = GE;
|
|
|
|
|
op_b = GEN_INT (desired_val);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case GE:
|
|
|
|
|
if (actual_val == desired_val + 1)
|
|
|
|
|
{
|
|
|
|
|
code = GT;
|
|
|
|
|
op_b = GEN_INT (desired_val);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If we made any changes, generate a new conditional that is
|
|
|
|
|
equivalent to what we started with, but has the right
|
|
|
|
|
constants in it. */
|
|
|
|
|
if (code != GET_CODE (if_info->cond)
|
|
|
|
|
|| op_a != XEXP (if_info->cond, 0)
|
|
|
|
|
|| op_b != XEXP (if_info->cond, 1))
|
|
|
|
|
{
|
|
|
|
|
cond = gen_rtx_fmt_ee (code, GET_MODE (cond), op_a, op_b);
|
|
|
|
|
*earliest = if_info->cond_earliest;
|
|
|
|
|
return cond;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-02-25 20:34:06 +01:00
|
|
|
|
cond = canonicalize_condition (if_info->jump, cond, reverse,
|
|
|
|
|
earliest, target);
|
|
|
|
|
if (! cond || ! reg_mentioned_p (target, cond))
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
/* We almost certainly searched back to a different place.
|
|
|
|
|
Need to re-verify correct lifetimes. */
|
|
|
|
|
|
|
|
|
|
/* X may not be mentioned in the range (cond_earliest, jump]. */
|
|
|
|
|
for (insn = if_info->jump; insn != *earliest; insn = PREV_INSN (insn))
|
|
|
|
|
if (INSN_P (insn) && reg_mentioned_p (if_info->x, insn))
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
/* A and B may not be modified in the range [cond_earliest, jump). */
|
|
|
|
|
for (insn = *earliest; insn != if_info->jump; insn = NEXT_INSN (insn))
|
|
|
|
|
if (INSN_P (insn)
|
|
|
|
|
&& (modified_in_p (if_info->a, insn)
|
|
|
|
|
|| modified_in_p (if_info->b, insn)))
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
return cond;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Convert "if (a < b) x = a; else x = b;" to "x = min(a, b);", etc. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
noce_try_minmax (if_info)
|
|
|
|
|
struct noce_if_info *if_info;
|
|
|
|
|
{
|
|
|
|
|
rtx cond, earliest, target, seq;
|
optabs.h (OTI_flodiv, [...]): Kill.
* optabs.h (OTI_flodiv, flodiv_optab): Kill.
* genopinit.c: Put floating point divide insns in sdiv_optab.
* expr.c (expand_expr): Use sdiv_optab, not flodiv_optab.
* config/gofast.h, config/c4x/c4x.h,
config/ia64/hpux_longdouble.h, config/mips/mips.h,
config/pa/long_double.h, config/rs6000/sysv4.h,
config/sparc/sparc.h: Put floating point divide libcalls in sdiv_optab.
* optabs.c (init_optab): Break into new_optab, init_optab, init_optabv.
(init_optabs): Use init_optabv for overflow-trapping optabs.
Don't init flodiv_optab. Give mov_optab, movstrict_optab, and
cmp_optab RTX codes so have_insn_for can find them.
* optabs.c (expand_simple_binop, expand_simple_unop,
have_insn_for, gen_sub3_insn): New interfaces.
* expr.h: Prototype new functions.
(enum optab_methods): Move here from optabs.h.
* builtins.c, combine.c, doloop.c, function.c, ifcvt.c,
loop.c, profile.c, simplify-rtx.c, stmt.c, unroll.c:
Use new functions instead of working directly with optabs.
* doloop.c, ifcvt.c, loop.c, profile.c, simplify-rtx.c,
unroll.c: Don't include optabs.h.
* caller-save.c, combine.c, function.c, stmt.c: Just include
insn-codes.h, not optabs.h.
* Makefile.in: Update dependencies.
* combine.c (make_compound_operation, simplify_comparison):
Fix typos testing for this or that instruction.
From-SVN: r45008
2001-08-18 21:59:46 +02:00
|
|
|
|
enum rtx_code code, op;
|
2001-02-25 20:34:06 +01:00
|
|
|
|
int unsignedp;
|
|
|
|
|
|
|
|
|
|
/* ??? Can't guarantee that expand_binop won't create pseudos. */
|
|
|
|
|
if (no_new_pseudos)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* ??? Reject FP modes since we don't know how 0 vs -0 or NaNs
|
|
|
|
|
will be resolved with an SMIN/SMAX. It wouldn't be too hard
|
|
|
|
|
to get the target to tell us... */
|
|
|
|
|
if (FLOAT_MODE_P (GET_MODE (if_info->x))
|
|
|
|
|
&& TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
|
2001-03-07 20:29:41 +01:00
|
|
|
|
&& ! flag_unsafe_math_optimizations)
|
2001-02-25 20:34:06 +01:00
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
cond = noce_get_alt_condition (if_info, if_info->a, &earliest);
|
|
|
|
|
if (!cond)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* Verify the condition is of the form we expect, and canonicalize
|
|
|
|
|
the comparison code. */
|
|
|
|
|
code = GET_CODE (cond);
|
|
|
|
|
if (rtx_equal_p (XEXP (cond, 0), if_info->a))
|
|
|
|
|
{
|
|
|
|
|
if (! rtx_equal_p (XEXP (cond, 1), if_info->b))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
else if (rtx_equal_p (XEXP (cond, 1), if_info->a))
|
|
|
|
|
{
|
|
|
|
|
if (! rtx_equal_p (XEXP (cond, 0), if_info->b))
|
|
|
|
|
return FALSE;
|
|
|
|
|
code = swap_condition (code);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* Determine what sort of operation this is. Note that the code is for
|
|
|
|
|
a taken branch, so the code->operation mapping appears backwards. */
|
|
|
|
|
switch (code)
|
|
|
|
|
{
|
|
|
|
|
case LT:
|
|
|
|
|
case LE:
|
|
|
|
|
case UNLT:
|
|
|
|
|
case UNLE:
|
optabs.h (OTI_flodiv, [...]): Kill.
* optabs.h (OTI_flodiv, flodiv_optab): Kill.
* genopinit.c: Put floating point divide insns in sdiv_optab.
* expr.c (expand_expr): Use sdiv_optab, not flodiv_optab.
* config/gofast.h, config/c4x/c4x.h,
config/ia64/hpux_longdouble.h, config/mips/mips.h,
config/pa/long_double.h, config/rs6000/sysv4.h,
config/sparc/sparc.h: Put floating point divide libcalls in sdiv_optab.
* optabs.c (init_optab): Break into new_optab, init_optab, init_optabv.
(init_optabs): Use init_optabv for overflow-trapping optabs.
Don't init flodiv_optab. Give mov_optab, movstrict_optab, and
cmp_optab RTX codes so have_insn_for can find them.
* optabs.c (expand_simple_binop, expand_simple_unop,
have_insn_for, gen_sub3_insn): New interfaces.
* expr.h: Prototype new functions.
(enum optab_methods): Move here from optabs.h.
* builtins.c, combine.c, doloop.c, function.c, ifcvt.c,
loop.c, profile.c, simplify-rtx.c, stmt.c, unroll.c:
Use new functions instead of working directly with optabs.
* doloop.c, ifcvt.c, loop.c, profile.c, simplify-rtx.c,
unroll.c: Don't include optabs.h.
* caller-save.c, combine.c, function.c, stmt.c: Just include
insn-codes.h, not optabs.h.
* Makefile.in: Update dependencies.
* combine.c (make_compound_operation, simplify_comparison):
Fix typos testing for this or that instruction.
From-SVN: r45008
2001-08-18 21:59:46 +02:00
|
|
|
|
op = SMAX;
|
2001-02-25 20:34:06 +01:00
|
|
|
|
unsignedp = 0;
|
|
|
|
|
break;
|
|
|
|
|
case GT:
|
|
|
|
|
case GE:
|
|
|
|
|
case UNGT:
|
|
|
|
|
case UNGE:
|
optabs.h (OTI_flodiv, [...]): Kill.
* optabs.h (OTI_flodiv, flodiv_optab): Kill.
* genopinit.c: Put floating point divide insns in sdiv_optab.
* expr.c (expand_expr): Use sdiv_optab, not flodiv_optab.
* config/gofast.h, config/c4x/c4x.h,
config/ia64/hpux_longdouble.h, config/mips/mips.h,
config/pa/long_double.h, config/rs6000/sysv4.h,
config/sparc/sparc.h: Put floating point divide libcalls in sdiv_optab.
* optabs.c (init_optab): Break into new_optab, init_optab, init_optabv.
(init_optabs): Use init_optabv for overflow-trapping optabs.
Don't init flodiv_optab. Give mov_optab, movstrict_optab, and
cmp_optab RTX codes so have_insn_for can find them.
* optabs.c (expand_simple_binop, expand_simple_unop,
have_insn_for, gen_sub3_insn): New interfaces.
* expr.h: Prototype new functions.
(enum optab_methods): Move here from optabs.h.
* builtins.c, combine.c, doloop.c, function.c, ifcvt.c,
loop.c, profile.c, simplify-rtx.c, stmt.c, unroll.c:
Use new functions instead of working directly with optabs.
* doloop.c, ifcvt.c, loop.c, profile.c, simplify-rtx.c,
unroll.c: Don't include optabs.h.
* caller-save.c, combine.c, function.c, stmt.c: Just include
insn-codes.h, not optabs.h.
* Makefile.in: Update dependencies.
* combine.c (make_compound_operation, simplify_comparison):
Fix typos testing for this or that instruction.
From-SVN: r45008
2001-08-18 21:59:46 +02:00
|
|
|
|
op = SMIN;
|
2001-02-25 20:34:06 +01:00
|
|
|
|
unsignedp = 0;
|
|
|
|
|
break;
|
|
|
|
|
case LTU:
|
|
|
|
|
case LEU:
|
optabs.h (OTI_flodiv, [...]): Kill.
* optabs.h (OTI_flodiv, flodiv_optab): Kill.
* genopinit.c: Put floating point divide insns in sdiv_optab.
* expr.c (expand_expr): Use sdiv_optab, not flodiv_optab.
* config/gofast.h, config/c4x/c4x.h,
config/ia64/hpux_longdouble.h, config/mips/mips.h,
config/pa/long_double.h, config/rs6000/sysv4.h,
config/sparc/sparc.h: Put floating point divide libcalls in sdiv_optab.
* optabs.c (init_optab): Break into new_optab, init_optab, init_optabv.
(init_optabs): Use init_optabv for overflow-trapping optabs.
Don't init flodiv_optab. Give mov_optab, movstrict_optab, and
cmp_optab RTX codes so have_insn_for can find them.
* optabs.c (expand_simple_binop, expand_simple_unop,
have_insn_for, gen_sub3_insn): New interfaces.
* expr.h: Prototype new functions.
(enum optab_methods): Move here from optabs.h.
* builtins.c, combine.c, doloop.c, function.c, ifcvt.c,
loop.c, profile.c, simplify-rtx.c, stmt.c, unroll.c:
Use new functions instead of working directly with optabs.
* doloop.c, ifcvt.c, loop.c, profile.c, simplify-rtx.c,
unroll.c: Don't include optabs.h.
* caller-save.c, combine.c, function.c, stmt.c: Just include
insn-codes.h, not optabs.h.
* Makefile.in: Update dependencies.
* combine.c (make_compound_operation, simplify_comparison):
Fix typos testing for this or that instruction.
From-SVN: r45008
2001-08-18 21:59:46 +02:00
|
|
|
|
op = UMAX;
|
2001-02-25 20:34:06 +01:00
|
|
|
|
unsignedp = 1;
|
|
|
|
|
break;
|
|
|
|
|
case GTU:
|
|
|
|
|
case GEU:
|
optabs.h (OTI_flodiv, [...]): Kill.
* optabs.h (OTI_flodiv, flodiv_optab): Kill.
* genopinit.c: Put floating point divide insns in sdiv_optab.
* expr.c (expand_expr): Use sdiv_optab, not flodiv_optab.
* config/gofast.h, config/c4x/c4x.h,
config/ia64/hpux_longdouble.h, config/mips/mips.h,
config/pa/long_double.h, config/rs6000/sysv4.h,
config/sparc/sparc.h: Put floating point divide libcalls in sdiv_optab.
* optabs.c (init_optab): Break into new_optab, init_optab, init_optabv.
(init_optabs): Use init_optabv for overflow-trapping optabs.
Don't init flodiv_optab. Give mov_optab, movstrict_optab, and
cmp_optab RTX codes so have_insn_for can find them.
* optabs.c (expand_simple_binop, expand_simple_unop,
have_insn_for, gen_sub3_insn): New interfaces.
* expr.h: Prototype new functions.
(enum optab_methods): Move here from optabs.h.
* builtins.c, combine.c, doloop.c, function.c, ifcvt.c,
loop.c, profile.c, simplify-rtx.c, stmt.c, unroll.c:
Use new functions instead of working directly with optabs.
* doloop.c, ifcvt.c, loop.c, profile.c, simplify-rtx.c,
unroll.c: Don't include optabs.h.
* caller-save.c, combine.c, function.c, stmt.c: Just include
insn-codes.h, not optabs.h.
* Makefile.in: Update dependencies.
* combine.c (make_compound_operation, simplify_comparison):
Fix typos testing for this or that instruction.
From-SVN: r45008
2001-08-18 21:59:46 +02:00
|
|
|
|
op = UMIN;
|
2001-02-25 20:34:06 +01:00
|
|
|
|
unsignedp = 1;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
start_sequence ();
|
|
|
|
|
|
optabs.h (OTI_flodiv, [...]): Kill.
* optabs.h (OTI_flodiv, flodiv_optab): Kill.
* genopinit.c: Put floating point divide insns in sdiv_optab.
* expr.c (expand_expr): Use sdiv_optab, not flodiv_optab.
* config/gofast.h, config/c4x/c4x.h,
config/ia64/hpux_longdouble.h, config/mips/mips.h,
config/pa/long_double.h, config/rs6000/sysv4.h,
config/sparc/sparc.h: Put floating point divide libcalls in sdiv_optab.
* optabs.c (init_optab): Break into new_optab, init_optab, init_optabv.
(init_optabs): Use init_optabv for overflow-trapping optabs.
Don't init flodiv_optab. Give mov_optab, movstrict_optab, and
cmp_optab RTX codes so have_insn_for can find them.
* optabs.c (expand_simple_binop, expand_simple_unop,
have_insn_for, gen_sub3_insn): New interfaces.
* expr.h: Prototype new functions.
(enum optab_methods): Move here from optabs.h.
* builtins.c, combine.c, doloop.c, function.c, ifcvt.c,
loop.c, profile.c, simplify-rtx.c, stmt.c, unroll.c:
Use new functions instead of working directly with optabs.
* doloop.c, ifcvt.c, loop.c, profile.c, simplify-rtx.c,
unroll.c: Don't include optabs.h.
* caller-save.c, combine.c, function.c, stmt.c: Just include
insn-codes.h, not optabs.h.
* Makefile.in: Update dependencies.
* combine.c (make_compound_operation, simplify_comparison):
Fix typos testing for this or that instruction.
From-SVN: r45008
2001-08-18 21:59:46 +02:00
|
|
|
|
target = expand_simple_binop (GET_MODE (if_info->x), op,
|
|
|
|
|
if_info->a, if_info->b,
|
|
|
|
|
if_info->x, unsignedp, OPTAB_WIDEN);
|
2001-02-25 20:34:06 +01:00
|
|
|
|
if (! target)
|
|
|
|
|
{
|
|
|
|
|
end_sequence ();
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
if (target != if_info->x)
|
2001-04-02 10:17:15 +02:00
|
|
|
|
noce_emit_move_insn (if_info->x, target);
|
2001-02-25 20:34:06 +01:00
|
|
|
|
|
|
|
|
|
seq = get_insns ();
|
|
|
|
|
end_sequence ();
|
|
|
|
|
|
|
|
|
|
if (seq_contains_jump (seq))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
emit_insns_before (seq, earliest);
|
|
|
|
|
if_info->cond = cond;
|
|
|
|
|
if_info->cond_earliest = earliest;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Convert "if (a < 0) x = -a; else x = a;" to "x = abs(a);", etc. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
noce_try_abs (if_info)
|
|
|
|
|
struct noce_if_info *if_info;
|
|
|
|
|
{
|
|
|
|
|
rtx cond, earliest, target, seq, a, b, c;
|
|
|
|
|
int negate;
|
|
|
|
|
|
|
|
|
|
/* ??? Can't guarantee that expand_binop won't create pseudos. */
|
|
|
|
|
if (no_new_pseudos)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* Recognize A and B as constituting an ABS or NABS. */
|
|
|
|
|
a = if_info->a;
|
|
|
|
|
b = if_info->b;
|
|
|
|
|
if (GET_CODE (a) == NEG && rtx_equal_p (XEXP (a, 0), b))
|
|
|
|
|
negate = 0;
|
|
|
|
|
else if (GET_CODE (b) == NEG && rtx_equal_p (XEXP (b, 0), a))
|
|
|
|
|
{
|
|
|
|
|
c = a; a = b; b = c;
|
|
|
|
|
negate = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
cond = noce_get_alt_condition (if_info, b, &earliest);
|
|
|
|
|
if (!cond)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* Verify the condition is of the form we expect. */
|
|
|
|
|
if (rtx_equal_p (XEXP (cond, 0), b))
|
|
|
|
|
c = XEXP (cond, 1);
|
|
|
|
|
else if (rtx_equal_p (XEXP (cond, 1), b))
|
|
|
|
|
c = XEXP (cond, 0);
|
|
|
|
|
else
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* Verify that C is zero. Search backward through the block for
|
|
|
|
|
a REG_EQUAL note if necessary. */
|
|
|
|
|
if (REG_P (c))
|
|
|
|
|
{
|
|
|
|
|
rtx insn, note = NULL;
|
|
|
|
|
for (insn = earliest;
|
|
|
|
|
insn != if_info->test_bb->head;
|
|
|
|
|
insn = PREV_INSN (insn))
|
|
|
|
|
if (INSN_P (insn)
|
|
|
|
|
&& ((note = find_reg_note (insn, REG_EQUAL, c))
|
|
|
|
|
|| (note = find_reg_note (insn, REG_EQUIV, c))))
|
|
|
|
|
break;
|
|
|
|
|
if (! note)
|
|
|
|
|
return FALSE;
|
|
|
|
|
c = XEXP (note, 0);
|
|
|
|
|
}
|
|
|
|
|
if (GET_CODE (c) == MEM
|
|
|
|
|
&& GET_CODE (XEXP (c, 0)) == SYMBOL_REF
|
|
|
|
|
&& CONSTANT_POOL_ADDRESS_P (XEXP (c, 0)))
|
|
|
|
|
c = get_pool_constant (XEXP (c, 0));
|
|
|
|
|
|
|
|
|
|
/* Work around funny ideas get_condition has wrt canonicalization.
|
|
|
|
|
Note that these rtx constants are known to be CONST_INT, and
|
|
|
|
|
therefore imply integer comparisons. */
|
|
|
|
|
if (c == constm1_rtx && GET_CODE (cond) == GT)
|
|
|
|
|
;
|
|
|
|
|
else if (c == const1_rtx && GET_CODE (cond) == LT)
|
|
|
|
|
;
|
|
|
|
|
else if (c != CONST0_RTX (GET_MODE (b)))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* Determine what sort of operation this is. */
|
|
|
|
|
switch (GET_CODE (cond))
|
|
|
|
|
{
|
|
|
|
|
case LT:
|
|
|
|
|
case LE:
|
|
|
|
|
case UNLT:
|
|
|
|
|
case UNLE:
|
|
|
|
|
negate = !negate;
|
|
|
|
|
break;
|
|
|
|
|
case GT:
|
|
|
|
|
case GE:
|
|
|
|
|
case UNGT:
|
|
|
|
|
case UNGE:
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
start_sequence ();
|
|
|
|
|
|
optabs.h (OTI_flodiv, [...]): Kill.
* optabs.h (OTI_flodiv, flodiv_optab): Kill.
* genopinit.c: Put floating point divide insns in sdiv_optab.
* expr.c (expand_expr): Use sdiv_optab, not flodiv_optab.
* config/gofast.h, config/c4x/c4x.h,
config/ia64/hpux_longdouble.h, config/mips/mips.h,
config/pa/long_double.h, config/rs6000/sysv4.h,
config/sparc/sparc.h: Put floating point divide libcalls in sdiv_optab.
* optabs.c (init_optab): Break into new_optab, init_optab, init_optabv.
(init_optabs): Use init_optabv for overflow-trapping optabs.
Don't init flodiv_optab. Give mov_optab, movstrict_optab, and
cmp_optab RTX codes so have_insn_for can find them.
* optabs.c (expand_simple_binop, expand_simple_unop,
have_insn_for, gen_sub3_insn): New interfaces.
* expr.h: Prototype new functions.
(enum optab_methods): Move here from optabs.h.
* builtins.c, combine.c, doloop.c, function.c, ifcvt.c,
loop.c, profile.c, simplify-rtx.c, stmt.c, unroll.c:
Use new functions instead of working directly with optabs.
* doloop.c, ifcvt.c, loop.c, profile.c, simplify-rtx.c,
unroll.c: Don't include optabs.h.
* caller-save.c, combine.c, function.c, stmt.c: Just include
insn-codes.h, not optabs.h.
* Makefile.in: Update dependencies.
* combine.c (make_compound_operation, simplify_comparison):
Fix typos testing for this or that instruction.
From-SVN: r45008
2001-08-18 21:59:46 +02:00
|
|
|
|
target = expand_simple_unop (GET_MODE (if_info->x), ABS, b, if_info->x, 0);
|
2001-02-25 20:34:06 +01:00
|
|
|
|
|
|
|
|
|
/* ??? It's a quandry whether cmove would be better here, especially
|
|
|
|
|
for integers. Perhaps combine will clean things up. */
|
|
|
|
|
if (target && negate)
|
optabs.h (OTI_flodiv, [...]): Kill.
* optabs.h (OTI_flodiv, flodiv_optab): Kill.
* genopinit.c: Put floating point divide insns in sdiv_optab.
* expr.c (expand_expr): Use sdiv_optab, not flodiv_optab.
* config/gofast.h, config/c4x/c4x.h,
config/ia64/hpux_longdouble.h, config/mips/mips.h,
config/pa/long_double.h, config/rs6000/sysv4.h,
config/sparc/sparc.h: Put floating point divide libcalls in sdiv_optab.
* optabs.c (init_optab): Break into new_optab, init_optab, init_optabv.
(init_optabs): Use init_optabv for overflow-trapping optabs.
Don't init flodiv_optab. Give mov_optab, movstrict_optab, and
cmp_optab RTX codes so have_insn_for can find them.
* optabs.c (expand_simple_binop, expand_simple_unop,
have_insn_for, gen_sub3_insn): New interfaces.
* expr.h: Prototype new functions.
(enum optab_methods): Move here from optabs.h.
* builtins.c, combine.c, doloop.c, function.c, ifcvt.c,
loop.c, profile.c, simplify-rtx.c, stmt.c, unroll.c:
Use new functions instead of working directly with optabs.
* doloop.c, ifcvt.c, loop.c, profile.c, simplify-rtx.c,
unroll.c: Don't include optabs.h.
* caller-save.c, combine.c, function.c, stmt.c: Just include
insn-codes.h, not optabs.h.
* Makefile.in: Update dependencies.
* combine.c (make_compound_operation, simplify_comparison):
Fix typos testing for this or that instruction.
From-SVN: r45008
2001-08-18 21:59:46 +02:00
|
|
|
|
target = expand_simple_unop (GET_MODE (target), NEG, target, if_info->x, 0);
|
2001-02-25 20:34:06 +01:00
|
|
|
|
|
|
|
|
|
if (! target)
|
|
|
|
|
{
|
|
|
|
|
end_sequence ();
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (target != if_info->x)
|
2001-04-02 10:17:15 +02:00
|
|
|
|
noce_emit_move_insn (if_info->x, target);
|
2001-02-25 20:34:06 +01:00
|
|
|
|
|
|
|
|
|
seq = get_insns ();
|
|
|
|
|
end_sequence ();
|
|
|
|
|
|
|
|
|
|
if (seq_contains_jump (seq))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
emit_insns_before (seq, earliest);
|
|
|
|
|
if_info->cond = cond;
|
|
|
|
|
if_info->cond_earliest = earliest;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2000-04-30 13:01:53 +02:00
|
|
|
|
/* Look for the condition for the jump first. We'd prefer to avoid
|
|
|
|
|
get_condition if we can -- it tries to look back for the contents
|
|
|
|
|
of an original compare. On targets that use normal integers for
|
|
|
|
|
comparisons, e.g. alpha, this is wasteful. */
|
|
|
|
|
|
|
|
|
|
static rtx
|
|
|
|
|
noce_get_condition (jump, earliest)
|
|
|
|
|
rtx jump;
|
|
|
|
|
rtx *earliest;
|
|
|
|
|
{
|
|
|
|
|
rtx cond;
|
combine.c (try_combine): Use any_condjump_p...
* combine.c (try_combine): Use any_condjump_p, any_uncondjump_p
and pc_set at the place of simplejump_p and condjump_p.
* cse.c (record_jump_equiv): Likewise.
* emit-rtl.c (emit): Likewise.
* explow.c (find_next_ref): Likewise.
* flow.c (tidy_fallthru_edge): Likewise.
(init_propagate_block_info): Likewise.
* gcse.c (delete_null_pointer_checks): Likewise.
* ifcvt.c (cond_exec_get_condition, noce_get_condition,
dead_or_predicable): Likewise.
* integrate.c (copy_insn_list): Likewise.
* loop.c (scan_loop, verify_dominator, find_and_verify_loops,
for_each_insn_in_loop, check_dbra_loop, get_condition,
insert_bct, load_mems): Likewise.
* resource.c (find_dead_or_set_registers): Likewise.
* sibcalls.c (simplejump_p): Likewise.
* unroll.c (copy_loop_body, reg_dead_after_loop): Likewise.
From-SVN: r34175
2000-05-25 23:38:49 +02:00
|
|
|
|
rtx set;
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
/* If the condition variable is a register and is MODE_INT, accept it.
|
|
|
|
|
Otherwise, fall back on get_condition. */
|
|
|
|
|
|
combine.c (try_combine): Use any_condjump_p...
* combine.c (try_combine): Use any_condjump_p, any_uncondjump_p
and pc_set at the place of simplejump_p and condjump_p.
* cse.c (record_jump_equiv): Likewise.
* emit-rtl.c (emit): Likewise.
* explow.c (find_next_ref): Likewise.
* flow.c (tidy_fallthru_edge): Likewise.
(init_propagate_block_info): Likewise.
* gcse.c (delete_null_pointer_checks): Likewise.
* ifcvt.c (cond_exec_get_condition, noce_get_condition,
dead_or_predicable): Likewise.
* integrate.c (copy_insn_list): Likewise.
* loop.c (scan_loop, verify_dominator, find_and_verify_loops,
for_each_insn_in_loop, check_dbra_loop, get_condition,
insert_bct, load_mems): Likewise.
* resource.c (find_dead_or_set_registers): Likewise.
* sibcalls.c (simplejump_p): Likewise.
* unroll.c (copy_loop_body, reg_dead_after_loop): Likewise.
From-SVN: r34175
2000-05-25 23:38:49 +02:00
|
|
|
|
if (! any_condjump_p (jump))
|
2000-04-30 13:01:53 +02:00
|
|
|
|
return NULL_RTX;
|
|
|
|
|
|
combine.c (try_combine): Use any_condjump_p...
* combine.c (try_combine): Use any_condjump_p, any_uncondjump_p
and pc_set at the place of simplejump_p and condjump_p.
* cse.c (record_jump_equiv): Likewise.
* emit-rtl.c (emit): Likewise.
* explow.c (find_next_ref): Likewise.
* flow.c (tidy_fallthru_edge): Likewise.
(init_propagate_block_info): Likewise.
* gcse.c (delete_null_pointer_checks): Likewise.
* ifcvt.c (cond_exec_get_condition, noce_get_condition,
dead_or_predicable): Likewise.
* integrate.c (copy_insn_list): Likewise.
* loop.c (scan_loop, verify_dominator, find_and_verify_loops,
for_each_insn_in_loop, check_dbra_loop, get_condition,
insert_bct, load_mems): Likewise.
* resource.c (find_dead_or_set_registers): Likewise.
* sibcalls.c (simplejump_p): Likewise.
* unroll.c (copy_loop_body, reg_dead_after_loop): Likewise.
From-SVN: r34175
2000-05-25 23:38:49 +02:00
|
|
|
|
set = pc_set (jump);
|
|
|
|
|
|
|
|
|
|
cond = XEXP (SET_SRC (set), 0);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
if (GET_CODE (XEXP (cond, 0)) == REG
|
|
|
|
|
&& GET_MODE_CLASS (GET_MODE (XEXP (cond, 0))) == MODE_INT)
|
|
|
|
|
{
|
|
|
|
|
*earliest = jump;
|
|
|
|
|
|
|
|
|
|
/* If this branches to JUMP_LABEL when the condition is false,
|
|
|
|
|
reverse the condition. */
|
combine.c (try_combine): Use any_condjump_p...
* combine.c (try_combine): Use any_condjump_p, any_uncondjump_p
and pc_set at the place of simplejump_p and condjump_p.
* cse.c (record_jump_equiv): Likewise.
* emit-rtl.c (emit): Likewise.
* explow.c (find_next_ref): Likewise.
* flow.c (tidy_fallthru_edge): Likewise.
(init_propagate_block_info): Likewise.
* gcse.c (delete_null_pointer_checks): Likewise.
* ifcvt.c (cond_exec_get_condition, noce_get_condition,
dead_or_predicable): Likewise.
* integrate.c (copy_insn_list): Likewise.
* loop.c (scan_loop, verify_dominator, find_and_verify_loops,
for_each_insn_in_loop, check_dbra_loop, get_condition,
insert_bct, load_mems): Likewise.
* resource.c (find_dead_or_set_registers): Likewise.
* sibcalls.c (simplejump_p): Likewise.
* unroll.c (copy_loop_body, reg_dead_after_loop): Likewise.
From-SVN: r34175
2000-05-25 23:38:49 +02:00
|
|
|
|
if (GET_CODE (XEXP (SET_SRC (set), 2)) == LABEL_REF
|
|
|
|
|
&& XEXP (XEXP (SET_SRC (set), 2), 0) == JUMP_LABEL (jump))
|
2000-04-30 13:01:53 +02:00
|
|
|
|
cond = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond)),
|
|
|
|
|
GET_MODE (cond), XEXP (cond, 0),
|
|
|
|
|
XEXP (cond, 1));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
cond = get_condition (jump, earliest);
|
|
|
|
|
|
|
|
|
|
return cond;
|
|
|
|
|
}
|
|
|
|
|
|
2001-02-25 20:34:06 +01:00
|
|
|
|
/* Return true if OP is ok for if-then-else processing. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
noce_operand_ok (op)
|
|
|
|
|
rtx op;
|
|
|
|
|
{
|
|
|
|
|
/* We special-case memories, so handle any of them with
|
|
|
|
|
no address side effects. */
|
|
|
|
|
if (GET_CODE (op) == MEM)
|
|
|
|
|
return ! side_effects_p (XEXP (op, 0));
|
|
|
|
|
|
|
|
|
|
if (side_effects_p (op))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2001-03-07 20:29:41 +01:00
|
|
|
|
/* ??? Unfortuantely may_trap_p can't look at flag_trapping_math, due to
|
2001-02-25 20:34:06 +01:00
|
|
|
|
being linked into the genfoo programs. This is probably a mistake.
|
|
|
|
|
With finite operands, most fp operations don't trap. */
|
2001-03-07 20:29:41 +01:00
|
|
|
|
if (!flag_trapping_math && FLOAT_MODE_P (GET_MODE (op)))
|
2001-02-25 20:34:06 +01:00
|
|
|
|
switch (GET_CODE (op))
|
|
|
|
|
{
|
|
|
|
|
case DIV:
|
|
|
|
|
case MOD:
|
|
|
|
|
case UDIV:
|
|
|
|
|
case UMOD:
|
|
|
|
|
/* ??? This is kinda lame -- almost every target will have forced
|
|
|
|
|
the constant into a register first. But given the expense of
|
|
|
|
|
division, this is probably for the best. */
|
|
|
|
|
return (CONSTANT_P (XEXP (op, 1))
|
|
|
|
|
&& XEXP (op, 1) != CONST0_RTX (GET_MODE (op))
|
|
|
|
|
&& ! may_trap_p (XEXP (op, 0)));
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
switch (GET_RTX_CLASS (GET_CODE (op)))
|
|
|
|
|
{
|
|
|
|
|
case '1':
|
2001-03-02 12:00:29 +01:00
|
|
|
|
return ! may_trap_p (XEXP (op, 0));
|
|
|
|
|
case 'c':
|
2001-02-25 20:34:06 +01:00
|
|
|
|
case '2':
|
|
|
|
|
return ! may_trap_p (XEXP (op, 0)) && ! may_trap_p (XEXP (op, 1));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ! may_trap_p (op);
|
|
|
|
|
}
|
|
|
|
|
|
2000-04-30 13:01:53 +02:00
|
|
|
|
/* Given a simple IF-THEN or IF-THEN-ELSE block, attempt to convert it
|
|
|
|
|
without using conditional execution. Return TRUE if we were
|
|
|
|
|
successful at converting the the block. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
noce_process_if_block (test_bb, then_bb, else_bb, join_bb)
|
|
|
|
|
basic_block test_bb; /* Basic block test is in */
|
|
|
|
|
basic_block then_bb; /* Basic block for THEN block */
|
|
|
|
|
basic_block else_bb; /* Basic block for ELSE block */
|
|
|
|
|
basic_block join_bb; /* Basic block the join label is in */
|
|
|
|
|
{
|
|
|
|
|
/* We're looking for patterns of the form
|
|
|
|
|
|
|
|
|
|
(1) if (...) x = a; else x = b;
|
|
|
|
|
(2) x = b; if (...) x = a;
|
|
|
|
|
(3) if (...) x = a; // as if with an initial x = x.
|
|
|
|
|
|
|
|
|
|
The later patterns require jumps to be more expensive.
|
|
|
|
|
|
|
|
|
|
??? For future expansion, look for multiple X in such patterns. */
|
|
|
|
|
|
|
|
|
|
struct noce_if_info if_info;
|
|
|
|
|
rtx insn_a, insn_b;
|
|
|
|
|
rtx set_a, set_b;
|
|
|
|
|
rtx orig_x, x, a, b;
|
2000-05-01 08:55:44 +02:00
|
|
|
|
rtx jump, cond, insn;
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
/* If this is not a standard conditional jump, we can't parse it. */
|
|
|
|
|
jump = test_bb->end;
|
|
|
|
|
cond = noce_get_condition (jump, &if_info.cond_earliest);
|
|
|
|
|
if (! cond)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2000-05-31 09:33:02 +02:00
|
|
|
|
/* If the conditional jump is more than just a conditional jump,
|
|
|
|
|
then we can not do if-conversion on this block. */
|
|
|
|
|
if (! onlyjump_p (jump))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2000-04-30 13:01:53 +02:00
|
|
|
|
/* We must be comparing objects whose modes imply the size. */
|
|
|
|
|
if (GET_MODE (XEXP (cond, 0)) == BLKmode)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* Look for one of the potential sets. */
|
|
|
|
|
insn_a = first_active_insn (then_bb);
|
|
|
|
|
if (! insn_a
|
|
|
|
|
|| ! last_active_insn_p (then_bb, insn_a)
|
|
|
|
|
|| (set_a = single_set (insn_a)) == NULL_RTX)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
x = SET_DEST (set_a);
|
|
|
|
|
a = SET_SRC (set_a);
|
|
|
|
|
|
|
|
|
|
/* Look for the other potential set. Make sure we've got equivalent
|
|
|
|
|
destinations. */
|
|
|
|
|
/* ??? This is overconservative. Storing to two different mems is
|
|
|
|
|
as easy as conditionally computing the address. Storing to a
|
|
|
|
|
single mem merely requires a scratch memory to use as one of the
|
|
|
|
|
destination addresses; often the memory immediately below the
|
|
|
|
|
stack pointer is available for this. */
|
|
|
|
|
set_b = NULL_RTX;
|
|
|
|
|
if (else_bb)
|
|
|
|
|
{
|
|
|
|
|
insn_b = first_active_insn (else_bb);
|
|
|
|
|
if (! insn_b
|
|
|
|
|
|| ! last_active_insn_p (else_bb, insn_b)
|
|
|
|
|
|| (set_b = single_set (insn_b)) == NULL_RTX
|
|
|
|
|
|| ! rtx_equal_p (x, SET_DEST (set_b)))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
insn_b = prev_nonnote_insn (if_info.cond_earliest);
|
|
|
|
|
if (! insn_b
|
|
|
|
|
|| GET_CODE (insn_b) != INSN
|
|
|
|
|
|| (set_b = single_set (insn_b)) == NULL_RTX
|
|
|
|
|
|| ! rtx_equal_p (x, SET_DEST (set_b))
|
2000-05-06 23:41:10 +02:00
|
|
|
|
|| reg_mentioned_p (x, cond)
|
2000-05-06 23:50:03 +02:00
|
|
|
|
|| reg_mentioned_p (x, a)
|
|
|
|
|
|| reg_mentioned_p (x, SET_SRC (set_b)))
|
2000-04-30 13:01:53 +02:00
|
|
|
|
insn_b = set_b = NULL_RTX;
|
|
|
|
|
}
|
|
|
|
|
b = (set_b ? SET_SRC (set_b) : x);
|
|
|
|
|
|
2000-05-05 01:22:26 +02:00
|
|
|
|
/* X may not be mentioned in the range (cond_earliest, jump]. */
|
|
|
|
|
for (insn = jump; insn != if_info.cond_earliest; insn = PREV_INSN (insn))
|
|
|
|
|
if (INSN_P (insn) && reg_mentioned_p (x, insn))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* A and B may not be modified in the range [cond_earliest, jump). */
|
|
|
|
|
for (insn = if_info.cond_earliest; insn != jump; insn = NEXT_INSN (insn))
|
|
|
|
|
if (INSN_P (insn)
|
|
|
|
|
&& (modified_in_p (a, insn) || modified_in_p (b, insn)))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2000-04-30 13:01:53 +02:00
|
|
|
|
/* Only operate on register destinations, and even then avoid extending
|
|
|
|
|
the lifetime of hard registers on small register class machines. */
|
|
|
|
|
orig_x = x;
|
|
|
|
|
if (GET_CODE (x) != REG
|
|
|
|
|
|| (SMALL_REGISTER_CLASSES
|
|
|
|
|
&& REGNO (x) < FIRST_PSEUDO_REGISTER))
|
|
|
|
|
{
|
|
|
|
|
if (no_new_pseudos)
|
|
|
|
|
return FALSE;
|
2001-04-02 10:17:15 +02:00
|
|
|
|
x = gen_reg_rtx (GET_MODE (GET_CODE (x) == STRICT_LOW_PART
|
|
|
|
|
? XEXP (x, 0) : x));
|
2000-04-30 13:01:53 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Don't operate on sources that may trap or are volatile. */
|
2001-02-25 20:34:06 +01:00
|
|
|
|
if (! noce_operand_ok (a) || ! noce_operand_ok (b))
|
2000-04-30 13:01:53 +02:00
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* Set up the info block for our subroutines. */
|
2001-02-25 20:34:06 +01:00
|
|
|
|
if_info.test_bb = test_bb;
|
2000-04-30 13:01:53 +02:00
|
|
|
|
if_info.cond = cond;
|
|
|
|
|
if_info.jump = jump;
|
|
|
|
|
if_info.insn_a = insn_a;
|
|
|
|
|
if_info.insn_b = insn_b;
|
|
|
|
|
if_info.x = x;
|
|
|
|
|
if_info.a = a;
|
|
|
|
|
if_info.b = b;
|
|
|
|
|
|
|
|
|
|
/* Try optimizations in some approximation of a useful order. */
|
|
|
|
|
/* ??? Should first look to see if X is live incoming at all. If it
|
|
|
|
|
isn't, we don't need anything but an unconditional set. */
|
|
|
|
|
|
|
|
|
|
/* Look and see if A and B are really the same. Avoid creating silly
|
|
|
|
|
cmove constructs that no one will fix up later. */
|
|
|
|
|
if (rtx_equal_p (a, b))
|
|
|
|
|
{
|
|
|
|
|
/* If we have an INSN_B, we don't have to create any new rtl. Just
|
|
|
|
|
move the instruction that we already have. If we don't have an
|
|
|
|
|
INSN_B, that means that A == X, and we've got a noop move. In
|
|
|
|
|
that case don't do anything and let the code below delete INSN_A. */
|
|
|
|
|
if (insn_b && else_bb)
|
|
|
|
|
{
|
2001-03-21 21:19:21 +01:00
|
|
|
|
rtx note;
|
|
|
|
|
|
2000-04-30 13:01:53 +02:00
|
|
|
|
if (else_bb && insn_b == else_bb->end)
|
|
|
|
|
else_bb->end = PREV_INSN (insn_b);
|
|
|
|
|
reorder_insns (insn_b, insn_b, PREV_INSN (if_info.cond_earliest));
|
2001-03-21 21:19:21 +01:00
|
|
|
|
|
|
|
|
|
/* If there was a REG_EQUAL note, delete it since it may have been
|
|
|
|
|
true due to this insn being after a jump. */
|
|
|
|
|
if ((note = find_reg_note (insn_b, REG_EQUAL, NULL_RTX)) != 0)
|
|
|
|
|
remove_note (insn_b, note);
|
|
|
|
|
|
2000-04-30 13:01:53 +02:00
|
|
|
|
insn_b = NULL_RTX;
|
|
|
|
|
}
|
2000-09-12 21:06:05 +02:00
|
|
|
|
/* If we have "x = b; if (...) x = a;", and x has side-effects, then
|
|
|
|
|
x must be executed twice. */
|
|
|
|
|
else if (insn_b && side_effects_p (orig_x))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2000-05-05 01:23:45 +02:00
|
|
|
|
x = orig_x;
|
2000-04-30 13:01:53 +02:00
|
|
|
|
goto success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (noce_try_store_flag (&if_info))
|
|
|
|
|
goto success;
|
2001-02-25 20:34:06 +01:00
|
|
|
|
if (noce_try_minmax (&if_info))
|
|
|
|
|
goto success;
|
|
|
|
|
if (noce_try_abs (&if_info))
|
|
|
|
|
goto success;
|
2000-04-30 13:01:53 +02:00
|
|
|
|
if (HAVE_conditional_move
|
|
|
|
|
&& noce_try_cmove (&if_info))
|
|
|
|
|
goto success;
|
|
|
|
|
if (! HAVE_conditional_execution)
|
|
|
|
|
{
|
|
|
|
|
if (noce_try_store_flag_constants (&if_info))
|
|
|
|
|
goto success;
|
|
|
|
|
if (noce_try_store_flag_inc (&if_info))
|
|
|
|
|
goto success;
|
|
|
|
|
if (noce_try_store_flag_mask (&if_info))
|
|
|
|
|
goto success;
|
|
|
|
|
if (HAVE_conditional_move
|
|
|
|
|
&& noce_try_cmove_arith (&if_info))
|
|
|
|
|
goto success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
success:
|
|
|
|
|
/* The original sets may now be killed. */
|
basic-block.h (flow_delete_insn, [...]): Kill.
* basic-block.h (flow_delete_insn, flow_delete_insn_chain): Kill.
* cfg.c (delete_insn): Rename from ....; use remove_insn; do not
remove some labels.
(flow_delete_insn): This one.
(delete_insn_chain): Rename from ...; do not care labels.
(flow_delete_insn_chain): ... this one.
(flow_delete_block): Remove the insns one BB has been expunged.
(merge_blocks_nomove): Likewise.
(try_redirect_by_replacing_jump): Use delete_insn[_chain]; do not care
updating BB boundaries.
(tidy_fallthru_edge): Likewise.
(commit_one_edge_insertion): Likewise.
* cfgbuild.c (find_basic_block): Likewise.
(find_basic_blocks_1): Likewise.
* cfgcleanup.c (merge_blocks_move_predecessor_nojumps): Likewise.
(try_crossjump_to_edge): Likewise.
(try_optimize_cfg): Likewise.
* cse.c (delete_trivially_dead_insns): Likewise.
* df.c (df_insn_delete): Likewise.
* doloop.c (doloop_modify): Use delete_related_insns.
* emit-rtl.c (try_split): Likewise.
(remove_insn): Update BB boundaries.
* expect.c (connect_post_landing_pads): Use delete_related_insns.
* flow.c (delete_dead_jumptables): Use delete_insn[_chain]; do not care
updating BB boundaries.
(propagate_block_delete_insn): Likewise.
(propagate_block_delete_libcall): Likewise.
* function.c (delete_handlers): Use delete_related_insns.
(thread_prologue_and_epilogue_insns): Likewise.
* gcse.c (delete_null_pointer_checks): Use delete_related_insns.
* genpeep.c (gen_peephole): Use delete_related_insns.
* ifcvt.c (noce_process_if_block): Use delete_insn; do not care updating
BB boundaries.
(find_cond_trap): Likewise.
* integrate.c (save_for_inline): Use delete_related_insns.
(copy_insn_list): Likewise.
* jump.c (pruge_linie_number_notes): Likewise.
(duplicate_loop_exit_test): Likewise.
(delete_computation): Likewise.
(delete_related_insn): Rename from ...; use delete_insn
(delete_insn): ... this one.
(redirect_jump): Use delete_related_insns.
* loop.c (scan_loop): Likewise.
(move_movables): Likewise.
(find_and_verify_loops): Likewise.
(check_dbra_loop): Likewise.
* recog.c (peephole2_optimize): Likewise.
* reg-stack.c (delete_insn_for_stacker): Remove.
(move_for_stack_reg): Use delete_insn.
* regmove.c (combine_stack_adjustments_for_block): Likewise.
* reload1.c (delete_address_reloads): Use delete_related_insns.
(fixup_abnormal_edges): Use delete_insn.
* recog.c (emit_delay_sequence): Use delete_related_insns.
(delete_from-delay_slot): Likewise.
(delete_scheduled_jump): likewise.
(optimize_skip): Likewise.
(try_merge_delay_insns): Likewise.
(full_simple_delay_slots): Likewise.
(fill_slots_from_thread): Likewise.
(relax_delay_slots): Likewise.
(make_return_insns): Likewise.
(dbr_schedule): Likewise.
* rtl.h (delete_insn): Rename to delete_related_insns.
(delete_insn, delete_insn_chain): New prototypes.
* ssa-ccp (sse_fast_dce): Remove deleting of DEF, as it is done
by df_insn_delete already.
* ssa-dce.c (delete_insn_bb): Use delete_insn.
* ssa.c (convert_from_ssa): Use delete_related_insns.
* unroll.c (unroll_loop): Likewise.
(calculate_giv_inc): Likewise.
(copy_loop_body): Likewise.
* i386-protos.h (ix86_libcall_value, ix86_function_value,
ix86_function_arg_regno_p, ix86_function_arg_boundary,
ix86_return_in_memory, ix86_function_value): Declare.
* i386.c (x86_64_int_parameter_registers, x86_64_int_return_registers):
new static valurables.
(x86_64_reg_class): New enum
(x86_64_reg_class_name): New array.
(classify_argument, examine_argument, construct_container,
merge_classes): New static functions.
(optimization_options): Enable flag_omit_frame_pointer and disable
flag_pcc_struct_return on 64bit.
(ix86_libcall_value, ix86_function_value,
ix86_function_arg_regno_p, ix86_function_arg_boundary,
ix86_return_in_memory, ix86_function_value): New global functions.
(init_cumulative_args): Refuse regparm on x86_64, set maybe_vaarg.
(function_arg_advance): Handle x86_64 passing conventions.
(function_arg): Likewise.
* i386.h (FUNCTION_ARG_BOUNDARY): New macro.
(RETURN_IN_MEMORY): Move offline.
(FUNCTION_VALUE, LIBCALL_VALUE): Likewise.
(FUNCTION_VALUE_REGNO_P): New macro.
(FUNCTION_ARG_REGNO_P): Move offline.
(struct ix86_args): Add maybe_vaarg.
* next.h (FUNCTION_VALUE_REGNO_P): Delete.
* unix.h (FUNCTION_VALUE_REGNO_P): Delete.
From-SVN: r45726
2001-09-21 14:55:18 +02:00
|
|
|
|
delete_insn (insn_a);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
/* Several special cases here: First, we may have reused insn_b above,
|
|
|
|
|
in which case insn_b is now NULL. Second, we want to delete insn_b
|
|
|
|
|
if it came from the ELSE block, because follows the now correct
|
|
|
|
|
write that appears in the TEST block. However, if we got insn_b from
|
|
|
|
|
the TEST block, it may in fact be loading data needed for the comparison.
|
|
|
|
|
We'll let life_analysis remove the insn if it's really dead. */
|
|
|
|
|
if (insn_b && else_bb)
|
basic-block.h (flow_delete_insn, [...]): Kill.
* basic-block.h (flow_delete_insn, flow_delete_insn_chain): Kill.
* cfg.c (delete_insn): Rename from ....; use remove_insn; do not
remove some labels.
(flow_delete_insn): This one.
(delete_insn_chain): Rename from ...; do not care labels.
(flow_delete_insn_chain): ... this one.
(flow_delete_block): Remove the insns one BB has been expunged.
(merge_blocks_nomove): Likewise.
(try_redirect_by_replacing_jump): Use delete_insn[_chain]; do not care
updating BB boundaries.
(tidy_fallthru_edge): Likewise.
(commit_one_edge_insertion): Likewise.
* cfgbuild.c (find_basic_block): Likewise.
(find_basic_blocks_1): Likewise.
* cfgcleanup.c (merge_blocks_move_predecessor_nojumps): Likewise.
(try_crossjump_to_edge): Likewise.
(try_optimize_cfg): Likewise.
* cse.c (delete_trivially_dead_insns): Likewise.
* df.c (df_insn_delete): Likewise.
* doloop.c (doloop_modify): Use delete_related_insns.
* emit-rtl.c (try_split): Likewise.
(remove_insn): Update BB boundaries.
* expect.c (connect_post_landing_pads): Use delete_related_insns.
* flow.c (delete_dead_jumptables): Use delete_insn[_chain]; do not care
updating BB boundaries.
(propagate_block_delete_insn): Likewise.
(propagate_block_delete_libcall): Likewise.
* function.c (delete_handlers): Use delete_related_insns.
(thread_prologue_and_epilogue_insns): Likewise.
* gcse.c (delete_null_pointer_checks): Use delete_related_insns.
* genpeep.c (gen_peephole): Use delete_related_insns.
* ifcvt.c (noce_process_if_block): Use delete_insn; do not care updating
BB boundaries.
(find_cond_trap): Likewise.
* integrate.c (save_for_inline): Use delete_related_insns.
(copy_insn_list): Likewise.
* jump.c (pruge_linie_number_notes): Likewise.
(duplicate_loop_exit_test): Likewise.
(delete_computation): Likewise.
(delete_related_insn): Rename from ...; use delete_insn
(delete_insn): ... this one.
(redirect_jump): Use delete_related_insns.
* loop.c (scan_loop): Likewise.
(move_movables): Likewise.
(find_and_verify_loops): Likewise.
(check_dbra_loop): Likewise.
* recog.c (peephole2_optimize): Likewise.
* reg-stack.c (delete_insn_for_stacker): Remove.
(move_for_stack_reg): Use delete_insn.
* regmove.c (combine_stack_adjustments_for_block): Likewise.
* reload1.c (delete_address_reloads): Use delete_related_insns.
(fixup_abnormal_edges): Use delete_insn.
* recog.c (emit_delay_sequence): Use delete_related_insns.
(delete_from-delay_slot): Likewise.
(delete_scheduled_jump): likewise.
(optimize_skip): Likewise.
(try_merge_delay_insns): Likewise.
(full_simple_delay_slots): Likewise.
(fill_slots_from_thread): Likewise.
(relax_delay_slots): Likewise.
(make_return_insns): Likewise.
(dbr_schedule): Likewise.
* rtl.h (delete_insn): Rename to delete_related_insns.
(delete_insn, delete_insn_chain): New prototypes.
* ssa-ccp (sse_fast_dce): Remove deleting of DEF, as it is done
by df_insn_delete already.
* ssa-dce.c (delete_insn_bb): Use delete_insn.
* ssa.c (convert_from_ssa): Use delete_related_insns.
* unroll.c (unroll_loop): Likewise.
(calculate_giv_inc): Likewise.
(copy_loop_body): Likewise.
* i386-protos.h (ix86_libcall_value, ix86_function_value,
ix86_function_arg_regno_p, ix86_function_arg_boundary,
ix86_return_in_memory, ix86_function_value): Declare.
* i386.c (x86_64_int_parameter_registers, x86_64_int_return_registers):
new static valurables.
(x86_64_reg_class): New enum
(x86_64_reg_class_name): New array.
(classify_argument, examine_argument, construct_container,
merge_classes): New static functions.
(optimization_options): Enable flag_omit_frame_pointer and disable
flag_pcc_struct_return on 64bit.
(ix86_libcall_value, ix86_function_value,
ix86_function_arg_regno_p, ix86_function_arg_boundary,
ix86_return_in_memory, ix86_function_value): New global functions.
(init_cumulative_args): Refuse regparm on x86_64, set maybe_vaarg.
(function_arg_advance): Handle x86_64 passing conventions.
(function_arg): Likewise.
* i386.h (FUNCTION_ARG_BOUNDARY): New macro.
(RETURN_IN_MEMORY): Move offline.
(FUNCTION_VALUE, LIBCALL_VALUE): Likewise.
(FUNCTION_VALUE_REGNO_P): New macro.
(FUNCTION_ARG_REGNO_P): Move offline.
(struct ix86_args): Add maybe_vaarg.
* next.h (FUNCTION_VALUE_REGNO_P): Delete.
* unix.h (FUNCTION_VALUE_REGNO_P): Delete.
From-SVN: r45726
2001-09-21 14:55:18 +02:00
|
|
|
|
delete_insn (insn_b);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
/* The new insns will have been inserted before cond_earliest. We should
|
2000-05-01 08:55:44 +02:00
|
|
|
|
be able to remove the jump with impunity, but the condition itself may
|
|
|
|
|
have been modified by gcse to be shared across basic blocks. */
|
basic-block.h (flow_delete_insn, [...]): Kill.
* basic-block.h (flow_delete_insn, flow_delete_insn_chain): Kill.
* cfg.c (delete_insn): Rename from ....; use remove_insn; do not
remove some labels.
(flow_delete_insn): This one.
(delete_insn_chain): Rename from ...; do not care labels.
(flow_delete_insn_chain): ... this one.
(flow_delete_block): Remove the insns one BB has been expunged.
(merge_blocks_nomove): Likewise.
(try_redirect_by_replacing_jump): Use delete_insn[_chain]; do not care
updating BB boundaries.
(tidy_fallthru_edge): Likewise.
(commit_one_edge_insertion): Likewise.
* cfgbuild.c (find_basic_block): Likewise.
(find_basic_blocks_1): Likewise.
* cfgcleanup.c (merge_blocks_move_predecessor_nojumps): Likewise.
(try_crossjump_to_edge): Likewise.
(try_optimize_cfg): Likewise.
* cse.c (delete_trivially_dead_insns): Likewise.
* df.c (df_insn_delete): Likewise.
* doloop.c (doloop_modify): Use delete_related_insns.
* emit-rtl.c (try_split): Likewise.
(remove_insn): Update BB boundaries.
* expect.c (connect_post_landing_pads): Use delete_related_insns.
* flow.c (delete_dead_jumptables): Use delete_insn[_chain]; do not care
updating BB boundaries.
(propagate_block_delete_insn): Likewise.
(propagate_block_delete_libcall): Likewise.
* function.c (delete_handlers): Use delete_related_insns.
(thread_prologue_and_epilogue_insns): Likewise.
* gcse.c (delete_null_pointer_checks): Use delete_related_insns.
* genpeep.c (gen_peephole): Use delete_related_insns.
* ifcvt.c (noce_process_if_block): Use delete_insn; do not care updating
BB boundaries.
(find_cond_trap): Likewise.
* integrate.c (save_for_inline): Use delete_related_insns.
(copy_insn_list): Likewise.
* jump.c (pruge_linie_number_notes): Likewise.
(duplicate_loop_exit_test): Likewise.
(delete_computation): Likewise.
(delete_related_insn): Rename from ...; use delete_insn
(delete_insn): ... this one.
(redirect_jump): Use delete_related_insns.
* loop.c (scan_loop): Likewise.
(move_movables): Likewise.
(find_and_verify_loops): Likewise.
(check_dbra_loop): Likewise.
* recog.c (peephole2_optimize): Likewise.
* reg-stack.c (delete_insn_for_stacker): Remove.
(move_for_stack_reg): Use delete_insn.
* regmove.c (combine_stack_adjustments_for_block): Likewise.
* reload1.c (delete_address_reloads): Use delete_related_insns.
(fixup_abnormal_edges): Use delete_insn.
* recog.c (emit_delay_sequence): Use delete_related_insns.
(delete_from-delay_slot): Likewise.
(delete_scheduled_jump): likewise.
(optimize_skip): Likewise.
(try_merge_delay_insns): Likewise.
(full_simple_delay_slots): Likewise.
(fill_slots_from_thread): Likewise.
(relax_delay_slots): Likewise.
(make_return_insns): Likewise.
(dbr_schedule): Likewise.
* rtl.h (delete_insn): Rename to delete_related_insns.
(delete_insn, delete_insn_chain): New prototypes.
* ssa-ccp (sse_fast_dce): Remove deleting of DEF, as it is done
by df_insn_delete already.
* ssa-dce.c (delete_insn_bb): Use delete_insn.
* ssa.c (convert_from_ssa): Use delete_related_insns.
* unroll.c (unroll_loop): Likewise.
(calculate_giv_inc): Likewise.
(copy_loop_body): Likewise.
* i386-protos.h (ix86_libcall_value, ix86_function_value,
ix86_function_arg_regno_p, ix86_function_arg_boundary,
ix86_return_in_memory, ix86_function_value): Declare.
* i386.c (x86_64_int_parameter_registers, x86_64_int_return_registers):
new static valurables.
(x86_64_reg_class): New enum
(x86_64_reg_class_name): New array.
(classify_argument, examine_argument, construct_container,
merge_classes): New static functions.
(optimization_options): Enable flag_omit_frame_pointer and disable
flag_pcc_struct_return on 64bit.
(ix86_libcall_value, ix86_function_value,
ix86_function_arg_regno_p, ix86_function_arg_boundary,
ix86_return_in_memory, ix86_function_value): New global functions.
(init_cumulative_args): Refuse regparm on x86_64, set maybe_vaarg.
(function_arg_advance): Handle x86_64 passing conventions.
(function_arg): Likewise.
* i386.h (FUNCTION_ARG_BOUNDARY): New macro.
(RETURN_IN_MEMORY): Move offline.
(FUNCTION_VALUE, LIBCALL_VALUE): Likewise.
(FUNCTION_VALUE_REGNO_P): New macro.
(FUNCTION_ARG_REGNO_P): Move offline.
(struct ix86_args): Add maybe_vaarg.
* next.h (FUNCTION_VALUE_REGNO_P): Delete.
* unix.h (FUNCTION_VALUE_REGNO_P): Delete.
From-SVN: r45726
2001-09-21 14:55:18 +02:00
|
|
|
|
delete_insn (jump);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
/* If we used a temporary, fix it up now. */
|
|
|
|
|
if (orig_x != x)
|
|
|
|
|
{
|
|
|
|
|
start_sequence ();
|
2002-01-31 12:07:14 +01:00
|
|
|
|
noce_emit_move_insn (copy_rtx (orig_x), x);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
insn_b = gen_sequence ();
|
|
|
|
|
end_sequence ();
|
|
|
|
|
|
2001-09-16 22:21:30 +02:00
|
|
|
|
emit_insn_after (insn_b, test_bb->end);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Merge the blocks! */
|
|
|
|
|
merge_if_block (test_bb, then_bb, else_bb, join_bb);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Attempt to convert an IF-THEN or IF-THEN-ELSE block into
|
|
|
|
|
straight line code. Return true if successful. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
process_if_block (test_bb, then_bb, else_bb, join_bb)
|
|
|
|
|
basic_block test_bb; /* Basic block test is in */
|
|
|
|
|
basic_block then_bb; /* Basic block for THEN block */
|
|
|
|
|
basic_block else_bb; /* Basic block for ELSE block */
|
|
|
|
|
basic_block join_bb; /* Basic block the join label is in */
|
|
|
|
|
{
|
|
|
|
|
if (! reload_completed
|
|
|
|
|
&& noce_process_if_block (test_bb, then_bb, else_bb, join_bb))
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
if (HAVE_conditional_execution
|
|
|
|
|
&& reload_completed
|
|
|
|
|
&& cond_exec_process_if_block (test_bb, then_bb, else_bb, join_bb))
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Merge the blocks and mark for local life update. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
merge_if_block (test_bb, then_bb, else_bb, join_bb)
|
|
|
|
|
basic_block test_bb; /* Basic block test is in */
|
|
|
|
|
basic_block then_bb; /* Basic block for THEN block */
|
|
|
|
|
basic_block else_bb; /* Basic block for ELSE block */
|
|
|
|
|
basic_block join_bb; /* Basic block the join label is in */
|
|
|
|
|
{
|
|
|
|
|
basic_block combo_bb;
|
|
|
|
|
|
|
|
|
|
/* All block merging is done into the lower block numbers. */
|
|
|
|
|
|
|
|
|
|
combo_bb = test_bb;
|
|
|
|
|
|
|
|
|
|
/* First merge TEST block into THEN block. This is a no-brainer since
|
|
|
|
|
the THEN block did not have a code label to begin with. */
|
|
|
|
|
|
basic-block.h (BB_REACHABLE): Renumber.
* basic-block.h (BB_REACHABLE): Renumber.
(BB_DIRTY, BB_NEW): New flags.
(clear_bb_flags): Declare.
(update_life_info_in_dirty_blocks): Declare.
* cfg.c (clear_bb_flags): New function.
* cfgrtl.c (create_basic_block_structure): Set flags to BB_NEW.
* emit-rtl.c (add_insn_after, add_insn_before, remove_insn,
reorder_insns, emit_insn_after): Mark block as dirty.
* flow.c (update_life_info): Fix clearing of PROP_LOG_LINKS.
(update_life_info_in_dirty_blocks): New function.
* recog.c (apply_change_group): Dirtify block.
* cse.c (cse_insn): Reorder emitting of jump insn to keep
cfg consistent.
* gcse.c (delete_null_pointer_checks): Likewise.
* toplev.c (dump_file_index): Move cse2 after bp,
add DFI_null
(dump_file_info): Similary.
(rest_of_compilation): Avoid most of CFG rebuilds;
do first if converision after null pointer checks, do cse2
after branch prediction; avoid full liveness rebuild after
initializing subregs.
* invoke.texi (-d options): Document -du, renumber.
* cfgcleanup.c (bb_flags): Remove BB_UPDATE_LIFE.
(notice_new_block): Do not set BB_UPDATE_LIFE.
(try_forward_edges, merge_blocks_move_predecessor_nojumps,
merge_blocks_move_successor_nojumps, merge_blocks,
try_crossjump_to_edge): Likewise.
(try_optimize_cfg): Likewise; use update_life_info_in_dirty_blocks.
* cfgrtl.c (merge_blocks_nomove): Copy b's flags to a.
* ifcvt.c (SET_UPDATE_LIFE, UPDATE_LIFE): Kill.
(merge_of_block): Do not use life_data_ok.
(find_if_case_1): Do not use SET_UPDATE_LIFE.
(if_convert): Use BB_DIRTY mechanizm to update life.
* lcm.c (optimize_mode_switching): Update
update_life_info_in_dirty_blocks
From-SVN: r50127
2002-02-28 11:11:01 +01:00
|
|
|
|
if (combo_bb->global_live_at_end)
|
2000-04-30 13:01:53 +02:00
|
|
|
|
COPY_REG_SET (combo_bb->global_live_at_end, then_bb->global_live_at_end);
|
|
|
|
|
merge_blocks_nomove (combo_bb, then_bb);
|
|
|
|
|
num_removed_blocks++;
|
|
|
|
|
|
|
|
|
|
/* The ELSE block, if it existed, had a label. That label count
|
|
|
|
|
will almost always be zero, but odd things can happen when labels
|
|
|
|
|
get their addresses taken. */
|
|
|
|
|
if (else_bb)
|
|
|
|
|
{
|
2000-05-12 18:26:15 +02:00
|
|
|
|
merge_blocks_nomove (combo_bb, else_bb);
|
|
|
|
|
num_removed_blocks++;
|
2000-04-30 13:01:53 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If there was no join block reported, that means it was not adjacent
|
|
|
|
|
to the others, and so we cannot merge them. */
|
|
|
|
|
|
|
|
|
|
if (! join_bb)
|
|
|
|
|
{
|
|
|
|
|
/* The outgoing edge for the current COMBO block should already
|
|
|
|
|
be correct. Verify this. */
|
|
|
|
|
if (combo_bb->succ == NULL_EDGE)
|
|
|
|
|
abort ();
|
|
|
|
|
|
2001-07-14 20:39:16 +02:00
|
|
|
|
/* There should still be a branch at the end of the THEN or ELSE
|
2000-04-30 13:01:53 +02:00
|
|
|
|
blocks taking us to our final destination. */
|
2001-07-14 20:39:16 +02:00
|
|
|
|
if (GET_CODE (combo_bb->end) != JUMP_INSN)
|
2000-04-30 13:01:53 +02:00
|
|
|
|
abort ();
|
|
|
|
|
}
|
|
|
|
|
|
2000-05-12 18:26:15 +02:00
|
|
|
|
/* The JOIN block may have had quite a number of other predecessors too.
|
|
|
|
|
Since we've already merged the TEST, THEN and ELSE blocks, we should
|
|
|
|
|
have only one remaining edge from our if-then-else diamond. If there
|
2000-06-01 02:03:36 +02:00
|
|
|
|
is more than one remaining edge, it must come from elsewhere. There
|
|
|
|
|
may be zero incoming edges if the THEN block didn't actually join
|
|
|
|
|
back up (as with a call to abort). */
|
2001-08-22 07:21:10 +02:00
|
|
|
|
else if ((join_bb->pred == NULL
|
|
|
|
|
|| join_bb->pred->pred_next == NULL)
|
|
|
|
|
&& join_bb != EXIT_BLOCK_PTR)
|
2000-04-30 13:01:53 +02:00
|
|
|
|
{
|
|
|
|
|
/* We can merge the JOIN. */
|
basic-block.h (BB_REACHABLE): Renumber.
* basic-block.h (BB_REACHABLE): Renumber.
(BB_DIRTY, BB_NEW): New flags.
(clear_bb_flags): Declare.
(update_life_info_in_dirty_blocks): Declare.
* cfg.c (clear_bb_flags): New function.
* cfgrtl.c (create_basic_block_structure): Set flags to BB_NEW.
* emit-rtl.c (add_insn_after, add_insn_before, remove_insn,
reorder_insns, emit_insn_after): Mark block as dirty.
* flow.c (update_life_info): Fix clearing of PROP_LOG_LINKS.
(update_life_info_in_dirty_blocks): New function.
* recog.c (apply_change_group): Dirtify block.
* cse.c (cse_insn): Reorder emitting of jump insn to keep
cfg consistent.
* gcse.c (delete_null_pointer_checks): Likewise.
* toplev.c (dump_file_index): Move cse2 after bp,
add DFI_null
(dump_file_info): Similary.
(rest_of_compilation): Avoid most of CFG rebuilds;
do first if converision after null pointer checks, do cse2
after branch prediction; avoid full liveness rebuild after
initializing subregs.
* invoke.texi (-d options): Document -du, renumber.
* cfgcleanup.c (bb_flags): Remove BB_UPDATE_LIFE.
(notice_new_block): Do not set BB_UPDATE_LIFE.
(try_forward_edges, merge_blocks_move_predecessor_nojumps,
merge_blocks_move_successor_nojumps, merge_blocks,
try_crossjump_to_edge): Likewise.
(try_optimize_cfg): Likewise; use update_life_info_in_dirty_blocks.
* cfgrtl.c (merge_blocks_nomove): Copy b's flags to a.
* ifcvt.c (SET_UPDATE_LIFE, UPDATE_LIFE): Kill.
(merge_of_block): Do not use life_data_ok.
(find_if_case_1): Do not use SET_UPDATE_LIFE.
(if_convert): Use BB_DIRTY mechanizm to update life.
* lcm.c (optimize_mode_switching): Update
update_life_info_in_dirty_blocks
From-SVN: r50127
2002-02-28 11:11:01 +01:00
|
|
|
|
if (combo_bb->global_live_at_end)
|
2000-04-30 13:01:53 +02:00
|
|
|
|
COPY_REG_SET (combo_bb->global_live_at_end,
|
|
|
|
|
join_bb->global_live_at_end);
|
|
|
|
|
merge_blocks_nomove (combo_bb, join_bb);
|
|
|
|
|
num_removed_blocks++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* We cannot merge the JOIN. */
|
|
|
|
|
|
|
|
|
|
/* The outgoing edge for the current COMBO block should already
|
|
|
|
|
be correct. Verify this. */
|
|
|
|
|
if (combo_bb->succ->succ_next != NULL_EDGE
|
|
|
|
|
|| combo_bb->succ->dest != join_bb)
|
|
|
|
|
abort ();
|
|
|
|
|
|
|
|
|
|
/* Remove the jump and cruft from the end of the COMBO block. */
|
2001-08-22 07:21:10 +02:00
|
|
|
|
if (join_bb != EXIT_BLOCK_PTR)
|
|
|
|
|
tidy_fallthru_edge (combo_bb->succ, combo_bb, join_bb);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
num_updated_if_blocks++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Find a block ending in a simple IF condition. Return TRUE if
|
|
|
|
|
we were able to transform it in some way. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
find_if_header (test_bb)
|
|
|
|
|
basic_block test_bb;
|
|
|
|
|
{
|
|
|
|
|
edge then_edge;
|
|
|
|
|
edge else_edge;
|
|
|
|
|
|
|
|
|
|
/* The kind of block we're looking for has exactly two successors. */
|
|
|
|
|
if ((then_edge = test_bb->succ) == NULL_EDGE
|
|
|
|
|
|| (else_edge = then_edge->succ_next) == NULL_EDGE
|
|
|
|
|
|| else_edge->succ_next != NULL_EDGE)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* Neither edge should be abnormal. */
|
|
|
|
|
if ((then_edge->flags & EDGE_COMPLEX)
|
|
|
|
|
|| (else_edge->flags & EDGE_COMPLEX))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* The THEN edge is canonically the one that falls through. */
|
|
|
|
|
if (then_edge->flags & EDGE_FALLTHRU)
|
|
|
|
|
;
|
|
|
|
|
else if (else_edge->flags & EDGE_FALLTHRU)
|
|
|
|
|
{
|
|
|
|
|
edge e = else_edge;
|
|
|
|
|
else_edge = then_edge;
|
|
|
|
|
then_edge = e;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
/* Otherwise this must be a multiway branch of some sort. */
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (find_if_block (test_bb, then_edge, else_edge))
|
|
|
|
|
goto success;
|
2001-07-14 20:39:16 +02:00
|
|
|
|
if (HAVE_trap && HAVE_conditional_trap
|
|
|
|
|
&& find_cond_trap (test_bb, then_edge, else_edge))
|
|
|
|
|
goto success;
|
2000-04-30 13:01:53 +02:00
|
|
|
|
if (post_dominators
|
|
|
|
|
&& (! HAVE_conditional_execution || reload_completed))
|
|
|
|
|
{
|
|
|
|
|
if (find_if_case_1 (test_bb, then_edge, else_edge))
|
|
|
|
|
goto success;
|
|
|
|
|
if (find_if_case_2 (test_bb, then_edge, else_edge))
|
|
|
|
|
goto success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
success:
|
|
|
|
|
if (rtl_dump_file)
|
|
|
|
|
fprintf (rtl_dump_file, "Conversion succeeded.\n");
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Determine if a given basic block heads a simple IF-THEN or IF-THEN-ELSE
|
|
|
|
|
block. If so, we'll try to convert the insns to not require the branch.
|
|
|
|
|
Return TRUE if we were successful at converting the the block. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
find_if_block (test_bb, then_edge, else_edge)
|
|
|
|
|
basic_block test_bb;
|
|
|
|
|
edge then_edge, else_edge;
|
|
|
|
|
{
|
|
|
|
|
basic_block then_bb = then_edge->dest;
|
|
|
|
|
basic_block else_bb = else_edge->dest;
|
|
|
|
|
basic_block join_bb = NULL_BLOCK;
|
|
|
|
|
edge then_succ = then_bb->succ;
|
|
|
|
|
edge else_succ = else_bb->succ;
|
|
|
|
|
int next_index;
|
|
|
|
|
|
|
|
|
|
/* The THEN block of an IF-THEN combo must have exactly one predecessor. */
|
|
|
|
|
if (then_bb->pred->pred_next != NULL_EDGE)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2000-06-01 02:03:36 +02:00
|
|
|
|
/* The THEN block of an IF-THEN combo must have zero or one successors. */
|
|
|
|
|
if (then_succ != NULL_EDGE
|
|
|
|
|
&& (then_succ->succ_next != NULL_EDGE
|
|
|
|
|
|| (then_succ->flags & EDGE_COMPLEX)))
|
2000-04-30 13:01:53 +02:00
|
|
|
|
return FALSE;
|
|
|
|
|
|
2000-06-01 02:03:36 +02:00
|
|
|
|
/* If the THEN block has no successors, conditional execution can still
|
|
|
|
|
make a conditional call. Don't do this unless the ELSE block has
|
2000-08-20 00:32:11 +02:00
|
|
|
|
only one incoming edge -- the CFG manipulation is too ugly otherwise.
|
|
|
|
|
Check for the last insn of the THEN block being an indirect jump, which
|
|
|
|
|
is listed as not having any successors, but confuses the rest of the CE
|
|
|
|
|
code processing. XXX we should fix this in the future. */
|
2000-06-01 02:03:36 +02:00
|
|
|
|
if (then_succ == NULL)
|
|
|
|
|
{
|
|
|
|
|
if (else_bb->pred->pred_next == NULL_EDGE)
|
|
|
|
|
{
|
2000-08-20 00:32:11 +02:00
|
|
|
|
rtx last_insn = then_bb->end;
|
|
|
|
|
|
2000-08-20 03:32:44 +02:00
|
|
|
|
while (last_insn
|
|
|
|
|
&& GET_CODE (last_insn) == NOTE
|
|
|
|
|
&& last_insn != then_bb->head)
|
|
|
|
|
last_insn = PREV_INSN (last_insn);
|
2000-08-20 00:32:11 +02:00
|
|
|
|
|
2000-08-20 03:32:44 +02:00
|
|
|
|
if (last_insn
|
|
|
|
|
&& GET_CODE (last_insn) == JUMP_INSN
|
2000-08-20 00:32:11 +02:00
|
|
|
|
&& ! simplejump_p (last_insn))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2000-06-01 02:03:36 +02:00
|
|
|
|
join_bb = else_bb;
|
|
|
|
|
else_bb = NULL_BLOCK;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2000-04-30 13:01:53 +02:00
|
|
|
|
/* If the THEN block's successor is the other edge out of the TEST block,
|
|
|
|
|
then we have an IF-THEN combo without an ELSE. */
|
2000-06-01 02:03:36 +02:00
|
|
|
|
else if (then_succ->dest == else_bb)
|
2000-04-30 13:01:53 +02:00
|
|
|
|
{
|
|
|
|
|
join_bb = else_bb;
|
|
|
|
|
else_bb = NULL_BLOCK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If the THEN and ELSE block meet in a subsequent block, and the ELSE
|
|
|
|
|
has exactly one predecessor and one successor, and the outgoing edge
|
|
|
|
|
is not complex, then we have an IF-THEN-ELSE combo. */
|
|
|
|
|
else if (else_succ != NULL_EDGE
|
|
|
|
|
&& then_succ->dest == else_succ->dest
|
|
|
|
|
&& else_bb->pred->pred_next == NULL_EDGE
|
|
|
|
|
&& else_succ->succ_next == NULL_EDGE
|
|
|
|
|
&& ! (else_succ->flags & EDGE_COMPLEX))
|
|
|
|
|
join_bb = else_succ->dest;
|
|
|
|
|
|
|
|
|
|
/* Otherwise it is not an IF-THEN or IF-THEN-ELSE combination. */
|
|
|
|
|
else
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
num_possible_if_blocks++;
|
|
|
|
|
|
|
|
|
|
if (rtl_dump_file)
|
|
|
|
|
{
|
|
|
|
|
if (else_bb)
|
|
|
|
|
fprintf (rtl_dump_file,
|
|
|
|
|
"\nIF-THEN-ELSE block found, start %d, then %d, else %d, join %d\n",
|
|
|
|
|
test_bb->index, then_bb->index, else_bb->index,
|
|
|
|
|
join_bb->index);
|
|
|
|
|
else
|
|
|
|
|
fprintf (rtl_dump_file,
|
|
|
|
|
"\nIF-THEN block found, start %d, then %d, join %d\n",
|
|
|
|
|
test_bb->index, then_bb->index, join_bb->index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Make sure IF, THEN, and ELSE, blocks are adjacent. Actually, we
|
|
|
|
|
get the first condition for free, since we've already asserted that
|
|
|
|
|
there's a fallthru edge from IF to THEN. */
|
2001-03-28 13:04:51 +02:00
|
|
|
|
/* ??? As an enhancement, move the ELSE block. Have to deal with
|
2000-04-30 13:01:53 +02:00
|
|
|
|
BLOCK notes, if by no other means than aborting the merge if they
|
|
|
|
|
exist. Sticky enough I don't want to think about it now. */
|
|
|
|
|
next_index = then_bb->index;
|
|
|
|
|
if (else_bb && ++next_index != else_bb->index)
|
|
|
|
|
return FALSE;
|
2001-08-22 07:21:10 +02:00
|
|
|
|
if (++next_index != join_bb->index && join_bb->index != EXIT_BLOCK)
|
2000-04-30 13:01:53 +02:00
|
|
|
|
{
|
|
|
|
|
if (else_bb)
|
|
|
|
|
join_bb = NULL;
|
|
|
|
|
else
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Do the real work. */
|
|
|
|
|
return process_if_block (test_bb, then_bb, else_bb, join_bb);
|
|
|
|
|
}
|
|
|
|
|
|
2001-07-14 20:39:16 +02:00
|
|
|
|
/* Convert a branch over a trap, or a branch to a trap,
|
|
|
|
|
into a conditional trap. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
find_cond_trap (test_bb, then_edge, else_edge)
|
|
|
|
|
basic_block test_bb;
|
|
|
|
|
edge then_edge, else_edge;
|
|
|
|
|
{
|
|
|
|
|
basic_block then_bb, else_bb, join_bb, trap_bb;
|
|
|
|
|
rtx trap, jump, cond, cond_earliest, seq;
|
|
|
|
|
enum rtx_code code;
|
|
|
|
|
|
|
|
|
|
then_bb = then_edge->dest;
|
|
|
|
|
else_bb = else_edge->dest;
|
|
|
|
|
join_bb = NULL;
|
|
|
|
|
|
|
|
|
|
/* Locate the block with the trap instruction. */
|
|
|
|
|
/* ??? While we look for no successors, we really ought to allow
|
|
|
|
|
EH successors. Need to fix merge_if_block for that to work. */
|
|
|
|
|
/* ??? We can't currently handle merging the blocks if they are not
|
|
|
|
|
already adjacent. Prevent losage in merge_if_block by detecting
|
|
|
|
|
this now. */
|
|
|
|
|
if (then_bb->succ == NULL)
|
|
|
|
|
{
|
|
|
|
|
trap_bb = then_bb;
|
|
|
|
|
if (else_bb->index != then_bb->index + 1)
|
|
|
|
|
return FALSE;
|
|
|
|
|
join_bb = else_bb;
|
|
|
|
|
else_bb = NULL;
|
|
|
|
|
}
|
|
|
|
|
else if (else_bb->succ == NULL)
|
|
|
|
|
{
|
|
|
|
|
trap_bb = else_bb;
|
|
|
|
|
if (else_bb->index != then_bb->index + 1)
|
|
|
|
|
else_bb = NULL;
|
|
|
|
|
else if (then_bb->succ
|
|
|
|
|
&& ! then_bb->succ->succ_next
|
|
|
|
|
&& ! (then_bb->succ->flags & EDGE_COMPLEX)
|
|
|
|
|
&& then_bb->succ->dest->index == else_bb->index + 1)
|
|
|
|
|
join_bb = then_bb->succ->dest;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2001-07-15 02:00:56 +02:00
|
|
|
|
/* Don't confuse a conditional return with something we want to
|
|
|
|
|
optimize here. */
|
|
|
|
|
if (trap_bb == EXIT_BLOCK_PTR)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2001-07-14 20:39:16 +02:00
|
|
|
|
/* The only instruction in the THEN block must be the trap. */
|
|
|
|
|
trap = first_active_insn (trap_bb);
|
|
|
|
|
if (! (trap == trap_bb->end
|
|
|
|
|
&& GET_CODE (PATTERN (trap)) == TRAP_IF
|
|
|
|
|
&& TRAP_CONDITION (PATTERN (trap)) == const_true_rtx))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (rtl_dump_file)
|
|
|
|
|
{
|
|
|
|
|
if (trap_bb == then_bb)
|
|
|
|
|
fprintf (rtl_dump_file,
|
|
|
|
|
"\nTRAP-IF block found, start %d, trap %d",
|
|
|
|
|
test_bb->index, then_bb->index);
|
|
|
|
|
else
|
|
|
|
|
fprintf (rtl_dump_file,
|
|
|
|
|
"\nTRAP-IF block found, start %d, then %d, trap %d",
|
|
|
|
|
test_bb->index, then_bb->index, trap_bb->index);
|
|
|
|
|
if (join_bb)
|
|
|
|
|
fprintf (rtl_dump_file, ", join %d\n", join_bb->index);
|
|
|
|
|
else
|
|
|
|
|
fputc ('\n', rtl_dump_file);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If this is not a standard conditional jump, we can't parse it. */
|
|
|
|
|
jump = test_bb->end;
|
|
|
|
|
cond = noce_get_condition (jump, &cond_earliest);
|
|
|
|
|
if (! cond)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* If the conditional jump is more than just a conditional jump,
|
|
|
|
|
then we can not do if-conversion on this block. */
|
|
|
|
|
if (! onlyjump_p (jump))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* We must be comparing objects whose modes imply the size. */
|
|
|
|
|
if (GET_MODE (XEXP (cond, 0)) == BLKmode)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* Reverse the comparison code, if necessary. */
|
|
|
|
|
code = GET_CODE (cond);
|
|
|
|
|
if (then_bb == trap_bb)
|
|
|
|
|
{
|
|
|
|
|
code = reversed_comparison_code (cond, jump);
|
|
|
|
|
if (code == UNKNOWN)
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Attempt to generate the conditional trap. */
|
|
|
|
|
seq = gen_cond_trap (code, XEXP (cond, 0), XEXP (cond, 1),
|
|
|
|
|
TRAP_CODE (PATTERN (trap)));
|
|
|
|
|
if (seq == NULL)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* Emit the new insns before cond_earliest; delete the old jump
|
|
|
|
|
and trap insns. */
|
|
|
|
|
|
|
|
|
|
emit_insn_before (seq, cond_earliest);
|
|
|
|
|
|
basic-block.h (flow_delete_insn, [...]): Kill.
* basic-block.h (flow_delete_insn, flow_delete_insn_chain): Kill.
* cfg.c (delete_insn): Rename from ....; use remove_insn; do not
remove some labels.
(flow_delete_insn): This one.
(delete_insn_chain): Rename from ...; do not care labels.
(flow_delete_insn_chain): ... this one.
(flow_delete_block): Remove the insns one BB has been expunged.
(merge_blocks_nomove): Likewise.
(try_redirect_by_replacing_jump): Use delete_insn[_chain]; do not care
updating BB boundaries.
(tidy_fallthru_edge): Likewise.
(commit_one_edge_insertion): Likewise.
* cfgbuild.c (find_basic_block): Likewise.
(find_basic_blocks_1): Likewise.
* cfgcleanup.c (merge_blocks_move_predecessor_nojumps): Likewise.
(try_crossjump_to_edge): Likewise.
(try_optimize_cfg): Likewise.
* cse.c (delete_trivially_dead_insns): Likewise.
* df.c (df_insn_delete): Likewise.
* doloop.c (doloop_modify): Use delete_related_insns.
* emit-rtl.c (try_split): Likewise.
(remove_insn): Update BB boundaries.
* expect.c (connect_post_landing_pads): Use delete_related_insns.
* flow.c (delete_dead_jumptables): Use delete_insn[_chain]; do not care
updating BB boundaries.
(propagate_block_delete_insn): Likewise.
(propagate_block_delete_libcall): Likewise.
* function.c (delete_handlers): Use delete_related_insns.
(thread_prologue_and_epilogue_insns): Likewise.
* gcse.c (delete_null_pointer_checks): Use delete_related_insns.
* genpeep.c (gen_peephole): Use delete_related_insns.
* ifcvt.c (noce_process_if_block): Use delete_insn; do not care updating
BB boundaries.
(find_cond_trap): Likewise.
* integrate.c (save_for_inline): Use delete_related_insns.
(copy_insn_list): Likewise.
* jump.c (pruge_linie_number_notes): Likewise.
(duplicate_loop_exit_test): Likewise.
(delete_computation): Likewise.
(delete_related_insn): Rename from ...; use delete_insn
(delete_insn): ... this one.
(redirect_jump): Use delete_related_insns.
* loop.c (scan_loop): Likewise.
(move_movables): Likewise.
(find_and_verify_loops): Likewise.
(check_dbra_loop): Likewise.
* recog.c (peephole2_optimize): Likewise.
* reg-stack.c (delete_insn_for_stacker): Remove.
(move_for_stack_reg): Use delete_insn.
* regmove.c (combine_stack_adjustments_for_block): Likewise.
* reload1.c (delete_address_reloads): Use delete_related_insns.
(fixup_abnormal_edges): Use delete_insn.
* recog.c (emit_delay_sequence): Use delete_related_insns.
(delete_from-delay_slot): Likewise.
(delete_scheduled_jump): likewise.
(optimize_skip): Likewise.
(try_merge_delay_insns): Likewise.
(full_simple_delay_slots): Likewise.
(fill_slots_from_thread): Likewise.
(relax_delay_slots): Likewise.
(make_return_insns): Likewise.
(dbr_schedule): Likewise.
* rtl.h (delete_insn): Rename to delete_related_insns.
(delete_insn, delete_insn_chain): New prototypes.
* ssa-ccp (sse_fast_dce): Remove deleting of DEF, as it is done
by df_insn_delete already.
* ssa-dce.c (delete_insn_bb): Use delete_insn.
* ssa.c (convert_from_ssa): Use delete_related_insns.
* unroll.c (unroll_loop): Likewise.
(calculate_giv_inc): Likewise.
(copy_loop_body): Likewise.
* i386-protos.h (ix86_libcall_value, ix86_function_value,
ix86_function_arg_regno_p, ix86_function_arg_boundary,
ix86_return_in_memory, ix86_function_value): Declare.
* i386.c (x86_64_int_parameter_registers, x86_64_int_return_registers):
new static valurables.
(x86_64_reg_class): New enum
(x86_64_reg_class_name): New array.
(classify_argument, examine_argument, construct_container,
merge_classes): New static functions.
(optimization_options): Enable flag_omit_frame_pointer and disable
flag_pcc_struct_return on 64bit.
(ix86_libcall_value, ix86_function_value,
ix86_function_arg_regno_p, ix86_function_arg_boundary,
ix86_return_in_memory, ix86_function_value): New global functions.
(init_cumulative_args): Refuse regparm on x86_64, set maybe_vaarg.
(function_arg_advance): Handle x86_64 passing conventions.
(function_arg): Likewise.
* i386.h (FUNCTION_ARG_BOUNDARY): New macro.
(RETURN_IN_MEMORY): Move offline.
(FUNCTION_VALUE, LIBCALL_VALUE): Likewise.
(FUNCTION_VALUE_REGNO_P): New macro.
(FUNCTION_ARG_REGNO_P): Move offline.
(struct ix86_args): Add maybe_vaarg.
* next.h (FUNCTION_VALUE_REGNO_P): Delete.
* unix.h (FUNCTION_VALUE_REGNO_P): Delete.
From-SVN: r45726
2001-09-21 14:55:18 +02:00
|
|
|
|
delete_insn (jump);
|
2001-07-14 20:39:16 +02:00
|
|
|
|
|
basic-block.h (flow_delete_insn, [...]): Kill.
* basic-block.h (flow_delete_insn, flow_delete_insn_chain): Kill.
* cfg.c (delete_insn): Rename from ....; use remove_insn; do not
remove some labels.
(flow_delete_insn): This one.
(delete_insn_chain): Rename from ...; do not care labels.
(flow_delete_insn_chain): ... this one.
(flow_delete_block): Remove the insns one BB has been expunged.
(merge_blocks_nomove): Likewise.
(try_redirect_by_replacing_jump): Use delete_insn[_chain]; do not care
updating BB boundaries.
(tidy_fallthru_edge): Likewise.
(commit_one_edge_insertion): Likewise.
* cfgbuild.c (find_basic_block): Likewise.
(find_basic_blocks_1): Likewise.
* cfgcleanup.c (merge_blocks_move_predecessor_nojumps): Likewise.
(try_crossjump_to_edge): Likewise.
(try_optimize_cfg): Likewise.
* cse.c (delete_trivially_dead_insns): Likewise.
* df.c (df_insn_delete): Likewise.
* doloop.c (doloop_modify): Use delete_related_insns.
* emit-rtl.c (try_split): Likewise.
(remove_insn): Update BB boundaries.
* expect.c (connect_post_landing_pads): Use delete_related_insns.
* flow.c (delete_dead_jumptables): Use delete_insn[_chain]; do not care
updating BB boundaries.
(propagate_block_delete_insn): Likewise.
(propagate_block_delete_libcall): Likewise.
* function.c (delete_handlers): Use delete_related_insns.
(thread_prologue_and_epilogue_insns): Likewise.
* gcse.c (delete_null_pointer_checks): Use delete_related_insns.
* genpeep.c (gen_peephole): Use delete_related_insns.
* ifcvt.c (noce_process_if_block): Use delete_insn; do not care updating
BB boundaries.
(find_cond_trap): Likewise.
* integrate.c (save_for_inline): Use delete_related_insns.
(copy_insn_list): Likewise.
* jump.c (pruge_linie_number_notes): Likewise.
(duplicate_loop_exit_test): Likewise.
(delete_computation): Likewise.
(delete_related_insn): Rename from ...; use delete_insn
(delete_insn): ... this one.
(redirect_jump): Use delete_related_insns.
* loop.c (scan_loop): Likewise.
(move_movables): Likewise.
(find_and_verify_loops): Likewise.
(check_dbra_loop): Likewise.
* recog.c (peephole2_optimize): Likewise.
* reg-stack.c (delete_insn_for_stacker): Remove.
(move_for_stack_reg): Use delete_insn.
* regmove.c (combine_stack_adjustments_for_block): Likewise.
* reload1.c (delete_address_reloads): Use delete_related_insns.
(fixup_abnormal_edges): Use delete_insn.
* recog.c (emit_delay_sequence): Use delete_related_insns.
(delete_from-delay_slot): Likewise.
(delete_scheduled_jump): likewise.
(optimize_skip): Likewise.
(try_merge_delay_insns): Likewise.
(full_simple_delay_slots): Likewise.
(fill_slots_from_thread): Likewise.
(relax_delay_slots): Likewise.
(make_return_insns): Likewise.
(dbr_schedule): Likewise.
* rtl.h (delete_insn): Rename to delete_related_insns.
(delete_insn, delete_insn_chain): New prototypes.
* ssa-ccp (sse_fast_dce): Remove deleting of DEF, as it is done
by df_insn_delete already.
* ssa-dce.c (delete_insn_bb): Use delete_insn.
* ssa.c (convert_from_ssa): Use delete_related_insns.
* unroll.c (unroll_loop): Likewise.
(calculate_giv_inc): Likewise.
(copy_loop_body): Likewise.
* i386-protos.h (ix86_libcall_value, ix86_function_value,
ix86_function_arg_regno_p, ix86_function_arg_boundary,
ix86_return_in_memory, ix86_function_value): Declare.
* i386.c (x86_64_int_parameter_registers, x86_64_int_return_registers):
new static valurables.
(x86_64_reg_class): New enum
(x86_64_reg_class_name): New array.
(classify_argument, examine_argument, construct_container,
merge_classes): New static functions.
(optimization_options): Enable flag_omit_frame_pointer and disable
flag_pcc_struct_return on 64bit.
(ix86_libcall_value, ix86_function_value,
ix86_function_arg_regno_p, ix86_function_arg_boundary,
ix86_return_in_memory, ix86_function_value): New global functions.
(init_cumulative_args): Refuse regparm on x86_64, set maybe_vaarg.
(function_arg_advance): Handle x86_64 passing conventions.
(function_arg): Likewise.
* i386.h (FUNCTION_ARG_BOUNDARY): New macro.
(RETURN_IN_MEMORY): Move offline.
(FUNCTION_VALUE, LIBCALL_VALUE): Likewise.
(FUNCTION_VALUE_REGNO_P): New macro.
(FUNCTION_ARG_REGNO_P): Move offline.
(struct ix86_args): Add maybe_vaarg.
* next.h (FUNCTION_VALUE_REGNO_P): Delete.
* unix.h (FUNCTION_VALUE_REGNO_P): Delete.
From-SVN: r45726
2001-09-21 14:55:18 +02:00
|
|
|
|
delete_insn (trap);
|
2001-07-14 20:39:16 +02:00
|
|
|
|
|
|
|
|
|
/* Merge the blocks! */
|
|
|
|
|
if (trap_bb != then_bb && ! else_bb)
|
|
|
|
|
{
|
|
|
|
|
flow_delete_block (trap_bb);
|
|
|
|
|
num_removed_blocks++;
|
|
|
|
|
}
|
|
|
|
|
merge_if_block (test_bb, then_bb, else_bb, join_bb);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2000-04-30 13:01:53 +02:00
|
|
|
|
/* Look for IF-THEN-ELSE cases in which one of THEN or ELSE is
|
|
|
|
|
transformable, but not necessarily the other. There need be no
|
|
|
|
|
JOIN block.
|
|
|
|
|
|
|
|
|
|
Return TRUE if we were successful at converting the the block.
|
|
|
|
|
|
|
|
|
|
Cases we'd like to look at:
|
|
|
|
|
|
|
|
|
|
(1)
|
|
|
|
|
if (test) goto over; // x not live
|
|
|
|
|
x = a;
|
|
|
|
|
goto label;
|
|
|
|
|
over:
|
|
|
|
|
|
|
|
|
|
becomes
|
|
|
|
|
|
|
|
|
|
x = a;
|
|
|
|
|
if (! test) goto label;
|
|
|
|
|
|
|
|
|
|
(2)
|
|
|
|
|
if (test) goto E; // x not live
|
|
|
|
|
x = big();
|
|
|
|
|
goto L;
|
|
|
|
|
E:
|
|
|
|
|
x = b;
|
|
|
|
|
goto M;
|
|
|
|
|
|
|
|
|
|
becomes
|
|
|
|
|
|
|
|
|
|
x = b;
|
|
|
|
|
if (test) goto M;
|
|
|
|
|
x = big();
|
|
|
|
|
goto L;
|
|
|
|
|
|
|
|
|
|
(3) // This one's really only interesting for targets that can do
|
|
|
|
|
// multiway branching, e.g. IA-64 BBB bundles. For other targets
|
|
|
|
|
// it results in multiple branches on a cache line, which often
|
|
|
|
|
// does not sit well with predictors.
|
|
|
|
|
|
|
|
|
|
if (test1) goto E; // predicted not taken
|
|
|
|
|
x = a;
|
|
|
|
|
if (test2) goto F;
|
|
|
|
|
...
|
|
|
|
|
E:
|
|
|
|
|
x = b;
|
|
|
|
|
J:
|
|
|
|
|
|
|
|
|
|
becomes
|
|
|
|
|
|
|
|
|
|
x = a;
|
|
|
|
|
if (test1) goto E;
|
|
|
|
|
if (test2) goto F;
|
|
|
|
|
|
|
|
|
|
Notes:
|
|
|
|
|
|
|
|
|
|
(A) Don't do (2) if the branch is predicted against the block we're
|
|
|
|
|
eliminating. Do it anyway if we can eliminate a branch; this requires
|
|
|
|
|
that the sole successor of the eliminated block postdominate the other
|
|
|
|
|
side of the if.
|
|
|
|
|
|
|
|
|
|
(B) With CE, on (3) we can steal from both sides of the if, creating
|
|
|
|
|
|
|
|
|
|
if (test1) x = a;
|
|
|
|
|
if (!test1) x = b;
|
|
|
|
|
if (test1) goto J;
|
|
|
|
|
if (test2) goto F;
|
|
|
|
|
...
|
|
|
|
|
J:
|
|
|
|
|
|
|
|
|
|
Again, this is most useful if J postdominates.
|
|
|
|
|
|
|
|
|
|
(C) CE substitutes for helpful life information.
|
|
|
|
|
|
|
|
|
|
(D) These heuristics need a lot of work. */
|
|
|
|
|
|
|
|
|
|
/* Tests for case 1 above. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
find_if_case_1 (test_bb, then_edge, else_edge)
|
|
|
|
|
basic_block test_bb;
|
|
|
|
|
edge then_edge, else_edge;
|
|
|
|
|
{
|
|
|
|
|
basic_block then_bb = then_edge->dest;
|
2001-07-22 23:42:35 +02:00
|
|
|
|
basic_block else_bb = else_edge->dest, new_bb;
|
2000-04-30 13:01:53 +02:00
|
|
|
|
edge then_succ = then_bb->succ;
|
|
|
|
|
|
|
|
|
|
/* THEN has one successor. */
|
|
|
|
|
if (!then_succ || then_succ->succ_next != NULL)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* THEN does not fall through, but is not strange either. */
|
|
|
|
|
if (then_succ->flags & (EDGE_COMPLEX | EDGE_FALLTHRU))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* THEN has one predecessor. */
|
|
|
|
|
if (then_bb->pred->pred_next != NULL)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2001-07-22 23:42:35 +02:00
|
|
|
|
/* THEN must do something. */
|
|
|
|
|
if (forwarder_block_p (then_bb))
|
2000-04-30 13:01:53 +02:00
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
num_possible_if_blocks++;
|
|
|
|
|
if (rtl_dump_file)
|
|
|
|
|
fprintf (rtl_dump_file,
|
|
|
|
|
"\nIF-CASE-1 found, start %d, then %d\n",
|
|
|
|
|
test_bb->index, then_bb->index);
|
|
|
|
|
|
|
|
|
|
/* THEN is small. */
|
|
|
|
|
if (count_bb_insns (then_bb) > BRANCH_COST)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* Registers set are dead, or are predicable. */
|
2001-07-22 23:42:35 +02:00
|
|
|
|
if (! dead_or_predicable (test_bb, then_bb, else_bb,
|
|
|
|
|
then_bb->succ->dest, 1))
|
2000-04-30 13:01:53 +02:00
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* Conversion went ok, including moving the insns and fixing up the
|
|
|
|
|
jump. Adjust the CFG to match. */
|
|
|
|
|
|
|
|
|
|
bitmap_operation (test_bb->global_live_at_end,
|
|
|
|
|
else_bb->global_live_at_start,
|
|
|
|
|
then_bb->global_live_at_end, BITMAP_IOR);
|
|
|
|
|
|
2001-07-22 23:42:35 +02:00
|
|
|
|
new_bb = redirect_edge_and_branch_force (FALLTHRU_EDGE (test_bb), else_bb);
|
|
|
|
|
/* Make rest of code believe that the newly created block is the THEN_BB
|
|
|
|
|
block we are going to remove. */
|
|
|
|
|
if (new_bb)
|
basic-block.h (BB_REACHABLE): Renumber.
* basic-block.h (BB_REACHABLE): Renumber.
(BB_DIRTY, BB_NEW): New flags.
(clear_bb_flags): Declare.
(update_life_info_in_dirty_blocks): Declare.
* cfg.c (clear_bb_flags): New function.
* cfgrtl.c (create_basic_block_structure): Set flags to BB_NEW.
* emit-rtl.c (add_insn_after, add_insn_before, remove_insn,
reorder_insns, emit_insn_after): Mark block as dirty.
* flow.c (update_life_info): Fix clearing of PROP_LOG_LINKS.
(update_life_info_in_dirty_blocks): New function.
* recog.c (apply_change_group): Dirtify block.
* cse.c (cse_insn): Reorder emitting of jump insn to keep
cfg consistent.
* gcse.c (delete_null_pointer_checks): Likewise.
* toplev.c (dump_file_index): Move cse2 after bp,
add DFI_null
(dump_file_info): Similary.
(rest_of_compilation): Avoid most of CFG rebuilds;
do first if converision after null pointer checks, do cse2
after branch prediction; avoid full liveness rebuild after
initializing subregs.
* invoke.texi (-d options): Document -du, renumber.
* cfgcleanup.c (bb_flags): Remove BB_UPDATE_LIFE.
(notice_new_block): Do not set BB_UPDATE_LIFE.
(try_forward_edges, merge_blocks_move_predecessor_nojumps,
merge_blocks_move_successor_nojumps, merge_blocks,
try_crossjump_to_edge): Likewise.
(try_optimize_cfg): Likewise; use update_life_info_in_dirty_blocks.
* cfgrtl.c (merge_blocks_nomove): Copy b's flags to a.
* ifcvt.c (SET_UPDATE_LIFE, UPDATE_LIFE): Kill.
(merge_of_block): Do not use life_data_ok.
(find_if_case_1): Do not use SET_UPDATE_LIFE.
(if_convert): Use BB_DIRTY mechanizm to update life.
* lcm.c (optimize_mode_switching): Update
update_life_info_in_dirty_blocks
From-SVN: r50127
2002-02-28 11:11:01 +01:00
|
|
|
|
new_bb->aux = then_bb->aux;
|
2000-04-30 13:01:53 +02:00
|
|
|
|
flow_delete_block (then_bb);
|
2001-07-22 23:42:35 +02:00
|
|
|
|
/* We've possibly created jump to next insn, cleanup_cfg will solve that
|
|
|
|
|
later. */
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
num_removed_blocks++;
|
|
|
|
|
num_updated_if_blocks++;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Test for case 2 above. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
find_if_case_2 (test_bb, then_edge, else_edge)
|
|
|
|
|
basic_block test_bb;
|
|
|
|
|
edge then_edge, else_edge;
|
|
|
|
|
{
|
|
|
|
|
basic_block then_bb = then_edge->dest;
|
|
|
|
|
basic_block else_bb = else_edge->dest;
|
|
|
|
|
edge else_succ = else_bb->succ;
|
2001-07-22 23:42:35 +02:00
|
|
|
|
rtx note;
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
/* ELSE has one successor. */
|
|
|
|
|
if (!else_succ || else_succ->succ_next != NULL)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* ELSE outgoing edge is not complex. */
|
|
|
|
|
if (else_succ->flags & EDGE_COMPLEX)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* ELSE has one predecessor. */
|
|
|
|
|
if (else_bb->pred->pred_next != NULL)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2000-05-19 22:07:18 +02:00
|
|
|
|
/* THEN is not EXIT. */
|
|
|
|
|
if (then_bb->index < 0)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2000-04-30 13:01:53 +02:00
|
|
|
|
/* ELSE is predicted or SUCC(ELSE) postdominates THEN. */
|
|
|
|
|
note = find_reg_note (test_bb->end, REG_BR_PROB, NULL_RTX);
|
|
|
|
|
if (note && INTVAL (XEXP (note, 0)) >= REG_BR_PROB_BASE / 2)
|
|
|
|
|
;
|
|
|
|
|
else if (else_succ->dest->index < 0
|
2000-05-19 22:07:18 +02:00
|
|
|
|
|| TEST_BIT (post_dominators[ORIG_INDEX (then_bb)],
|
|
|
|
|
ORIG_INDEX (else_succ->dest)))
|
2000-04-30 13:01:53 +02:00
|
|
|
|
;
|
|
|
|
|
else
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
num_possible_if_blocks++;
|
|
|
|
|
if (rtl_dump_file)
|
|
|
|
|
fprintf (rtl_dump_file,
|
|
|
|
|
"\nIF-CASE-2 found, start %d, else %d\n",
|
|
|
|
|
test_bb->index, else_bb->index);
|
|
|
|
|
|
|
|
|
|
/* ELSE is small. */
|
|
|
|
|
if (count_bb_insns (then_bb) > BRANCH_COST)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* Registers set are dead, or are predicable. */
|
2001-07-22 23:42:35 +02:00
|
|
|
|
if (! dead_or_predicable (test_bb, else_bb, then_bb, else_succ->dest, 0))
|
2000-04-30 13:01:53 +02:00
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* Conversion went ok, including moving the insns and fixing up the
|
|
|
|
|
jump. Adjust the CFG to match. */
|
|
|
|
|
|
|
|
|
|
bitmap_operation (test_bb->global_live_at_end,
|
|
|
|
|
then_bb->global_live_at_start,
|
|
|
|
|
else_bb->global_live_at_end, BITMAP_IOR);
|
|
|
|
|
|
|
|
|
|
flow_delete_block (else_bb);
|
|
|
|
|
|
|
|
|
|
num_removed_blocks++;
|
|
|
|
|
num_updated_if_blocks++;
|
|
|
|
|
|
|
|
|
|
/* ??? We may now fallthru from one of THEN's successors into a join
|
|
|
|
|
block. Rerun cleanup_cfg? Examine things manually? Wait? */
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* A subroutine of dead_or_predicable called through for_each_rtx.
|
|
|
|
|
Return 1 if a memory is found. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
find_memory (px, data)
|
|
|
|
|
rtx *px;
|
|
|
|
|
void *data ATTRIBUTE_UNUSED;
|
|
|
|
|
{
|
|
|
|
|
return GET_CODE (*px) == MEM;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Used by the code above to perform the actual rtl transformations.
|
|
|
|
|
Return TRUE if successful.
|
|
|
|
|
|
|
|
|
|
TEST_BB is the block containing the conditional branch. MERGE_BB
|
|
|
|
|
is the block containing the code to manipulate. NEW_DEST is the
|
|
|
|
|
label TEST_BB should be branching to after the conversion.
|
|
|
|
|
REVERSEP is true if the sense of the branch should be reversed. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
dead_or_predicable (test_bb, merge_bb, other_bb, new_dest, reversep)
|
|
|
|
|
basic_block test_bb, merge_bb, other_bb;
|
2001-07-22 23:42:35 +02:00
|
|
|
|
basic_block new_dest;
|
2000-04-30 13:01:53 +02:00
|
|
|
|
int reversep;
|
|
|
|
|
{
|
2001-07-22 23:42:35 +02:00
|
|
|
|
rtx head, end, jump, earliest, old_dest, new_label;
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
jump = test_bb->end;
|
|
|
|
|
|
|
|
|
|
/* Find the extent of the real code in the merge block. */
|
|
|
|
|
head = merge_bb->head;
|
|
|
|
|
end = merge_bb->end;
|
|
|
|
|
|
|
|
|
|
if (GET_CODE (head) == CODE_LABEL)
|
|
|
|
|
head = NEXT_INSN (head);
|
|
|
|
|
if (GET_CODE (head) == NOTE)
|
|
|
|
|
{
|
|
|
|
|
if (head == end)
|
|
|
|
|
{
|
|
|
|
|
head = end = NULL_RTX;
|
|
|
|
|
goto no_body;
|
|
|
|
|
}
|
|
|
|
|
head = NEXT_INSN (head);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (GET_CODE (end) == JUMP_INSN)
|
|
|
|
|
{
|
|
|
|
|
if (head == end)
|
|
|
|
|
{
|
|
|
|
|
head = end = NULL_RTX;
|
|
|
|
|
goto no_body;
|
|
|
|
|
}
|
|
|
|
|
end = PREV_INSN (end);
|
|
|
|
|
}
|
|
|
|
|
|
2000-06-13 04:23:56 +02:00
|
|
|
|
/* Disable handling dead code by conditional execution if the machine needs
|
|
|
|
|
to do anything funny with the tests, etc. */
|
|
|
|
|
#ifndef IFCVT_MODIFY_TESTS
|
2000-04-30 13:01:53 +02:00
|
|
|
|
if (HAVE_conditional_execution)
|
|
|
|
|
{
|
|
|
|
|
/* In the conditional execution case, we have things easy. We know
|
|
|
|
|
the condition is reversable. We don't have to check life info,
|
|
|
|
|
becase we're going to conditionally execute the code anyway.
|
|
|
|
|
All that's left is making sure the insns involved can actually
|
|
|
|
|
be predicated. */
|
|
|
|
|
|
2000-05-09 08:12:51 +02:00
|
|
|
|
rtx cond, prob_val;
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
cond = cond_exec_get_condition (jump);
|
2001-06-13 20:16:31 +02:00
|
|
|
|
if (! cond)
|
|
|
|
|
return FALSE;
|
2000-05-09 08:12:51 +02:00
|
|
|
|
|
|
|
|
|
prob_val = find_reg_note (jump, REG_BR_PROB, NULL_RTX);
|
|
|
|
|
if (prob_val)
|
|
|
|
|
prob_val = XEXP (prob_val, 0);
|
|
|
|
|
|
2000-04-30 13:01:53 +02:00
|
|
|
|
if (reversep)
|
2000-05-09 08:12:51 +02:00
|
|
|
|
{
|
2001-06-13 20:16:31 +02:00
|
|
|
|
enum rtx_code rev = reversed_comparison_code (cond, jump);
|
|
|
|
|
if (rev == UNKNOWN)
|
2001-06-14 02:40:44 +02:00
|
|
|
|
return FALSE;
|
2001-06-13 20:16:31 +02:00
|
|
|
|
cond = gen_rtx_fmt_ee (rev, GET_MODE (cond), XEXP (cond, 0),
|
2000-05-09 08:12:51 +02:00
|
|
|
|
XEXP (cond, 1));
|
|
|
|
|
if (prob_val)
|
|
|
|
|
prob_val = GEN_INT (REG_BR_PROB_BASE - INTVAL (prob_val));
|
|
|
|
|
}
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
2000-05-09 08:12:51 +02:00
|
|
|
|
if (! cond_exec_process_insns (head, end, cond, prob_val, 0))
|
2000-04-30 13:01:53 +02:00
|
|
|
|
goto cancel;
|
|
|
|
|
|
|
|
|
|
earliest = jump;
|
|
|
|
|
}
|
|
|
|
|
else
|
2000-06-13 04:23:56 +02:00
|
|
|
|
#endif
|
2000-04-30 13:01:53 +02:00
|
|
|
|
{
|
|
|
|
|
/* In the non-conditional execution case, we have to verify that there
|
|
|
|
|
are no trapping operations, no calls, no references to memory, and
|
|
|
|
|
that any registers modified are dead at the branch site. */
|
|
|
|
|
|
|
|
|
|
rtx insn, cond, prev;
|
|
|
|
|
regset_head merge_set_head, tmp_head, test_live_head, test_set_head;
|
|
|
|
|
regset merge_set, tmp, test_live, test_set;
|
|
|
|
|
struct propagate_block_info *pbi;
|
|
|
|
|
int i, fail = 0;
|
|
|
|
|
|
|
|
|
|
/* Check for no calls or trapping operations. */
|
|
|
|
|
for (insn = head; ; insn = NEXT_INSN (insn))
|
|
|
|
|
{
|
|
|
|
|
if (GET_CODE (insn) == CALL_INSN)
|
|
|
|
|
return FALSE;
|
|
|
|
|
if (INSN_P (insn))
|
|
|
|
|
{
|
|
|
|
|
if (may_trap_p (PATTERN (insn)))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* ??? Even non-trapping memories such as stack frame
|
|
|
|
|
references must be avoided. For stores, we collect
|
|
|
|
|
no lifetime info; for reads, we'd have to assert
|
ChangeLog.2, [...]: Fix spelling errors.
* ChangeLog.2, ChangeLog.4, ChangeLog.5, ChangeLog,
FSFChangeLog.10, FSFChangeLog.11, alias.c, attribs.c,
caller-save.c, calls.c, cfg.c, cfganal.c, cfgcleanup.c, cfgrtl.c,
cppmacro.c, fold-const.c, ifcvt.c, local-alloc.c, profile.c,
sched-int.h, toplev.c, config/alpha/alpha.c,
config/alpha/alpha.md, config/c4x/c4x.h, config/cris/cris.h,
config/cris/cris.md, config/i370/i370.md, config/i386/i386.c,
config/i386/i386.h, config/i386/i386.md, config/i386/xm-djgpp.h,
config/ia64/ia64.c, config/m68hc11/m68hc11.c, config/m68k/m68k.md,
config/mcore/mcore.h, config/mmix/mmix.c, config/ns32k/ns32k.h,
config/ns32k/ns32k.md, config/rs6000/rs6000.c,
config/rs6000/sysv4.h, config/sh/sh.md: Fix spelling errors.
From-SVN: r46760
2001-11-04 03:51:28 +01:00
|
|
|
|
true_dependence false against every store in the
|
2000-04-30 13:01:53 +02:00
|
|
|
|
TEST range. */
|
|
|
|
|
if (for_each_rtx (&PATTERN (insn), find_memory, NULL))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
if (insn == end)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
combine.c (try_combine): Use any_condjump_p...
* combine.c (try_combine): Use any_condjump_p, any_uncondjump_p
and pc_set at the place of simplejump_p and condjump_p.
* cse.c (record_jump_equiv): Likewise.
* emit-rtl.c (emit): Likewise.
* explow.c (find_next_ref): Likewise.
* flow.c (tidy_fallthru_edge): Likewise.
(init_propagate_block_info): Likewise.
* gcse.c (delete_null_pointer_checks): Likewise.
* ifcvt.c (cond_exec_get_condition, noce_get_condition,
dead_or_predicable): Likewise.
* integrate.c (copy_insn_list): Likewise.
* loop.c (scan_loop, verify_dominator, find_and_verify_loops,
for_each_insn_in_loop, check_dbra_loop, get_condition,
insert_bct, load_mems): Likewise.
* resource.c (find_dead_or_set_registers): Likewise.
* sibcalls.c (simplejump_p): Likewise.
* unroll.c (copy_loop_body, reg_dead_after_loop): Likewise.
From-SVN: r34175
2000-05-25 23:38:49 +02:00
|
|
|
|
if (! any_condjump_p (jump))
|
2000-04-30 13:01:53 +02:00
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* Find the extent of the conditional. */
|
|
|
|
|
cond = noce_get_condition (jump, &earliest);
|
|
|
|
|
if (! cond)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* Collect:
|
|
|
|
|
MERGE_SET = set of registers set in MERGE_BB
|
|
|
|
|
TEST_LIVE = set of registers live at EARLIEST
|
|
|
|
|
TEST_SET = set of registers set between EARLIEST and the
|
|
|
|
|
end of the block. */
|
|
|
|
|
|
|
|
|
|
tmp = INITIALIZE_REG_SET (tmp_head);
|
|
|
|
|
merge_set = INITIALIZE_REG_SET (merge_set_head);
|
|
|
|
|
test_live = INITIALIZE_REG_SET (test_live_head);
|
|
|
|
|
test_set = INITIALIZE_REG_SET (test_set_head);
|
|
|
|
|
|
|
|
|
|
/* ??? bb->local_set is only valid during calculate_global_regs_live,
|
|
|
|
|
so we must recompute usage for MERGE_BB. Not so bad, I suppose,
|
|
|
|
|
since we've already asserted that MERGE_BB is small. */
|
2000-11-27 18:50:11 +01:00
|
|
|
|
propagate_block (merge_bb, tmp, merge_set, merge_set, 0);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
/* For small register class machines, don't lengthen lifetimes of
|
|
|
|
|
hard registers before reload. */
|
|
|
|
|
if (SMALL_REGISTER_CLASSES && ! reload_completed)
|
|
|
|
|
{
|
|
|
|
|
EXECUTE_IF_SET_IN_BITMAP
|
|
|
|
|
(merge_set, 0, i,
|
|
|
|
|
{
|
|
|
|
|
if (i < FIRST_PSEUDO_REGISTER
|
|
|
|
|
&& ! fixed_regs[i]
|
|
|
|
|
&& ! global_regs[i])
|
|
|
|
|
fail = 1;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* For TEST, we're interested in a range of insns, not a whole block.
|
|
|
|
|
Moreover, we're interested in the insns live from OTHER_BB. */
|
|
|
|
|
|
|
|
|
|
COPY_REG_SET (test_live, other_bb->global_live_at_start);
|
2000-11-27 18:50:11 +01:00
|
|
|
|
pbi = init_propagate_block_info (test_bb, test_live, test_set, test_set,
|
|
|
|
|
0);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
for (insn = jump; ; insn = prev)
|
|
|
|
|
{
|
|
|
|
|
prev = propagate_one_insn (pbi, insn);
|
|
|
|
|
if (insn == earliest)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free_propagate_block_info (pbi);
|
|
|
|
|
|
|
|
|
|
/* We can perform the transformation if
|
|
|
|
|
MERGE_SET & (TEST_SET | TEST_LIVE)
|
|
|
|
|
and
|
|
|
|
|
TEST_SET & merge_bb->global_live_at_start
|
|
|
|
|
are empty. */
|
|
|
|
|
|
|
|
|
|
bitmap_operation (tmp, test_set, test_live, BITMAP_IOR);
|
|
|
|
|
bitmap_operation (tmp, tmp, merge_set, BITMAP_AND);
|
|
|
|
|
EXECUTE_IF_SET_IN_BITMAP(tmp, 0, i, fail = 1);
|
|
|
|
|
|
|
|
|
|
bitmap_operation (tmp, test_set, merge_bb->global_live_at_start,
|
|
|
|
|
BITMAP_AND);
|
|
|
|
|
EXECUTE_IF_SET_IN_BITMAP(tmp, 0, i, fail = 1);
|
|
|
|
|
|
|
|
|
|
FREE_REG_SET (tmp);
|
|
|
|
|
FREE_REG_SET (merge_set);
|
|
|
|
|
FREE_REG_SET (test_live);
|
|
|
|
|
FREE_REG_SET (test_set);
|
|
|
|
|
|
|
|
|
|
if (fail)
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
no_body:
|
|
|
|
|
/* We don't want to use normal invert_jump or redirect_jump because
|
|
|
|
|
we don't want to delete_insn called. Also, we want to do our own
|
|
|
|
|
change group management. */
|
|
|
|
|
|
|
|
|
|
old_dest = JUMP_LABEL (jump);
|
2002-01-31 08:10:49 +01:00
|
|
|
|
if (other_bb != new_dest)
|
|
|
|
|
{
|
|
|
|
|
new_label = block_label (new_dest);
|
|
|
|
|
if (reversep
|
|
|
|
|
? ! invert_jump_1 (jump, new_label)
|
|
|
|
|
: ! redirect_jump_1 (jump, new_label))
|
|
|
|
|
goto cancel;
|
|
|
|
|
}
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
if (! apply_change_group ())
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2002-01-31 08:10:49 +01:00
|
|
|
|
if (other_bb != new_dest)
|
2001-07-22 23:42:35 +02:00
|
|
|
|
{
|
2002-01-31 08:10:49 +01:00
|
|
|
|
if (old_dest)
|
|
|
|
|
LABEL_NUSES (old_dest) -= 1;
|
|
|
|
|
if (new_label)
|
|
|
|
|
LABEL_NUSES (new_label) += 1;
|
|
|
|
|
JUMP_LABEL (jump) = new_label;
|
|
|
|
|
if (reversep)
|
|
|
|
|
invert_br_probabilities (jump);
|
|
|
|
|
|
|
|
|
|
redirect_edge_succ (BRANCH_EDGE (test_bb), new_dest);
|
|
|
|
|
if (reversep)
|
|
|
|
|
{
|
|
|
|
|
gcov_type count, probability;
|
|
|
|
|
count = BRANCH_EDGE (test_bb)->count;
|
|
|
|
|
BRANCH_EDGE (test_bb)->count = FALLTHRU_EDGE (test_bb)->count;
|
|
|
|
|
FALLTHRU_EDGE (test_bb)->count = count;
|
|
|
|
|
probability = BRANCH_EDGE (test_bb)->probability;
|
|
|
|
|
BRANCH_EDGE (test_bb)->probability
|
|
|
|
|
= FALLTHRU_EDGE (test_bb)->probability;
|
|
|
|
|
FALLTHRU_EDGE (test_bb)->probability = probability;
|
|
|
|
|
update_br_prob_note (test_bb);
|
|
|
|
|
}
|
2001-07-22 23:42:35 +02:00
|
|
|
|
}
|
|
|
|
|
|
2000-04-30 13:01:53 +02:00
|
|
|
|
/* Move the insns out of MERGE_BB to before the branch. */
|
|
|
|
|
if (head != NULL)
|
|
|
|
|
{
|
2000-05-02 08:35:22 +02:00
|
|
|
|
if (end == merge_bb->end)
|
|
|
|
|
merge_bb->end = PREV_INSN (head);
|
|
|
|
|
|
2001-11-15 11:28:52 +01:00
|
|
|
|
if (squeeze_notes (&head, &end))
|
|
|
|
|
return TRUE;
|
2000-04-30 20:41:37 +02:00
|
|
|
|
|
2000-04-30 13:01:53 +02:00
|
|
|
|
reorder_insns (head, end, PREV_INSN (earliest));
|
|
|
|
|
}
|
2002-01-31 08:10:49 +01:00
|
|
|
|
|
|
|
|
|
/* Remove the jump and edge if we can. */
|
|
|
|
|
if (other_bb == new_dest)
|
|
|
|
|
{
|
|
|
|
|
delete_insn (jump);
|
|
|
|
|
remove_edge (BRANCH_EDGE (test_bb));
|
|
|
|
|
/* ??? Can't merge blocks here, as then_bb is still in use.
|
|
|
|
|
At minimum, the merge will get done just before bb-reorder. */
|
|
|
|
|
}
|
|
|
|
|
|
2000-04-30 13:01:53 +02:00
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
cancel:
|
|
|
|
|
cancel_changes (0);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Main entry point for all if-conversion. */
|
|
|
|
|
|
|
|
|
|
void
|
2001-06-11 07:16:10 +02:00
|
|
|
|
if_convert (x_life_data_ok)
|
|
|
|
|
int x_life_data_ok;
|
2000-04-30 13:01:53 +02:00
|
|
|
|
{
|
|
|
|
|
int block_num;
|
|
|
|
|
|
|
|
|
|
num_possible_if_blocks = 0;
|
|
|
|
|
num_updated_if_blocks = 0;
|
|
|
|
|
num_removed_blocks = 0;
|
2001-06-11 07:16:10 +02:00
|
|
|
|
life_data_ok = (x_life_data_ok != 0);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
/* Free up basic_block_for_insn so that we don't have to keep it
|
|
|
|
|
up to date, either here or in merge_blocks_nomove. */
|
|
|
|
|
free_basic_block_vars (1);
|
|
|
|
|
|
|
|
|
|
/* Compute postdominators if we think we'll use them. */
|
|
|
|
|
post_dominators = NULL;
|
|
|
|
|
if (HAVE_conditional_execution || life_data_ok)
|
|
|
|
|
{
|
|
|
|
|
post_dominators = sbitmap_vector_alloc (n_basic_blocks, n_basic_blocks);
|
2000-11-14 10:58:40 +01:00
|
|
|
|
calculate_dominance_info (NULL, post_dominators, CDI_POST_DOMINATORS);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
}
|
basic-block.h (BB_REACHABLE): Renumber.
* basic-block.h (BB_REACHABLE): Renumber.
(BB_DIRTY, BB_NEW): New flags.
(clear_bb_flags): Declare.
(update_life_info_in_dirty_blocks): Declare.
* cfg.c (clear_bb_flags): New function.
* cfgrtl.c (create_basic_block_structure): Set flags to BB_NEW.
* emit-rtl.c (add_insn_after, add_insn_before, remove_insn,
reorder_insns, emit_insn_after): Mark block as dirty.
* flow.c (update_life_info): Fix clearing of PROP_LOG_LINKS.
(update_life_info_in_dirty_blocks): New function.
* recog.c (apply_change_group): Dirtify block.
* cse.c (cse_insn): Reorder emitting of jump insn to keep
cfg consistent.
* gcse.c (delete_null_pointer_checks): Likewise.
* toplev.c (dump_file_index): Move cse2 after bp,
add DFI_null
(dump_file_info): Similary.
(rest_of_compilation): Avoid most of CFG rebuilds;
do first if converision after null pointer checks, do cse2
after branch prediction; avoid full liveness rebuild after
initializing subregs.
* invoke.texi (-d options): Document -du, renumber.
* cfgcleanup.c (bb_flags): Remove BB_UPDATE_LIFE.
(notice_new_block): Do not set BB_UPDATE_LIFE.
(try_forward_edges, merge_blocks_move_predecessor_nojumps,
merge_blocks_move_successor_nojumps, merge_blocks,
try_crossjump_to_edge): Likewise.
(try_optimize_cfg): Likewise; use update_life_info_in_dirty_blocks.
* cfgrtl.c (merge_blocks_nomove): Copy b's flags to a.
* ifcvt.c (SET_UPDATE_LIFE, UPDATE_LIFE): Kill.
(merge_of_block): Do not use life_data_ok.
(find_if_case_1): Do not use SET_UPDATE_LIFE.
(if_convert): Use BB_DIRTY mechanizm to update life.
* lcm.c (optimize_mode_switching): Update
update_life_info_in_dirty_blocks
From-SVN: r50127
2002-02-28 11:11:01 +01:00
|
|
|
|
if (life_data_ok)
|
|
|
|
|
clear_bb_flags ();
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
/* Record initial block numbers. */
|
|
|
|
|
for (block_num = 0; block_num < n_basic_blocks; block_num++)
|
|
|
|
|
SET_ORIG_INDEX (BASIC_BLOCK (block_num), block_num);
|
|
|
|
|
|
|
|
|
|
/* Go through each of the basic blocks looking for things to convert. */
|
|
|
|
|
for (block_num = 0; block_num < n_basic_blocks; )
|
|
|
|
|
{
|
|
|
|
|
basic_block bb = BASIC_BLOCK (block_num);
|
|
|
|
|
if (find_if_header (bb))
|
|
|
|
|
block_num = bb->index;
|
|
|
|
|
else
|
|
|
|
|
block_num++;
|
|
|
|
|
}
|
|
|
|
|
|
2000-05-13 19:08:28 +02:00
|
|
|
|
if (post_dominators)
|
|
|
|
|
sbitmap_vector_free (post_dominators);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
if (rtl_dump_file)
|
|
|
|
|
fflush (rtl_dump_file);
|
|
|
|
|
|
|
|
|
|
/* Rebuild life info for basic blocks that require it. */
|
|
|
|
|
if (num_removed_blocks && life_data_ok)
|
|
|
|
|
{
|
|
|
|
|
/* If we allocated new pseudos, we must resize the array for sched1. */
|
|
|
|
|
if (max_regno < max_reg_num ())
|
|
|
|
|
{
|
|
|
|
|
max_regno = max_reg_num ();
|
|
|
|
|
allocate_reg_info (max_regno, FALSE, FALSE);
|
|
|
|
|
}
|
basic-block.h (BB_REACHABLE): Renumber.
* basic-block.h (BB_REACHABLE): Renumber.
(BB_DIRTY, BB_NEW): New flags.
(clear_bb_flags): Declare.
(update_life_info_in_dirty_blocks): Declare.
* cfg.c (clear_bb_flags): New function.
* cfgrtl.c (create_basic_block_structure): Set flags to BB_NEW.
* emit-rtl.c (add_insn_after, add_insn_before, remove_insn,
reorder_insns, emit_insn_after): Mark block as dirty.
* flow.c (update_life_info): Fix clearing of PROP_LOG_LINKS.
(update_life_info_in_dirty_blocks): New function.
* recog.c (apply_change_group): Dirtify block.
* cse.c (cse_insn): Reorder emitting of jump insn to keep
cfg consistent.
* gcse.c (delete_null_pointer_checks): Likewise.
* toplev.c (dump_file_index): Move cse2 after bp,
add DFI_null
(dump_file_info): Similary.
(rest_of_compilation): Avoid most of CFG rebuilds;
do first if converision after null pointer checks, do cse2
after branch prediction; avoid full liveness rebuild after
initializing subregs.
* invoke.texi (-d options): Document -du, renumber.
* cfgcleanup.c (bb_flags): Remove BB_UPDATE_LIFE.
(notice_new_block): Do not set BB_UPDATE_LIFE.
(try_forward_edges, merge_blocks_move_predecessor_nojumps,
merge_blocks_move_successor_nojumps, merge_blocks,
try_crossjump_to_edge): Likewise.
(try_optimize_cfg): Likewise; use update_life_info_in_dirty_blocks.
* cfgrtl.c (merge_blocks_nomove): Copy b's flags to a.
* ifcvt.c (SET_UPDATE_LIFE, UPDATE_LIFE): Kill.
(merge_of_block): Do not use life_data_ok.
(find_if_case_1): Do not use SET_UPDATE_LIFE.
(if_convert): Use BB_DIRTY mechanizm to update life.
* lcm.c (optimize_mode_switching): Update
update_life_info_in_dirty_blocks
From-SVN: r50127
2002-02-28 11:11:01 +01:00
|
|
|
|
update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL_RM_NOTES,
|
|
|
|
|
PROP_DEATH_NOTES | PROP_SCAN_DEAD_CODE
|
|
|
|
|
| PROP_KILL_DEAD_CODE);
|
2000-04-30 13:01:53 +02:00
|
|
|
|
}
|
2001-10-27 16:33:12 +02:00
|
|
|
|
clear_aux_for_blocks ();
|
2000-04-30 13:01:53 +02:00
|
|
|
|
|
|
|
|
|
/* Write the final stats. */
|
|
|
|
|
if (rtl_dump_file && num_possible_if_blocks > 0)
|
|
|
|
|
{
|
|
|
|
|
fprintf (rtl_dump_file,
|
|
|
|
|
"\n%d possible IF blocks searched.\n",
|
|
|
|
|
num_possible_if_blocks);
|
|
|
|
|
fprintf (rtl_dump_file,
|
|
|
|
|
"%d IF blocks converted.\n",
|
|
|
|
|
num_updated_if_blocks);
|
|
|
|
|
fprintf (rtl_dump_file,
|
|
|
|
|
"%d basic blocks deleted.\n\n\n",
|
|
|
|
|
num_removed_blocks);
|
|
|
|
|
}
|
|
|
|
|
|
2000-05-02 00:25:54 +02:00
|
|
|
|
#ifdef ENABLE_CHECKING
|
2000-05-21 01:16:18 +02:00
|
|
|
|
verify_flow_info ();
|
2000-05-02 00:25:54 +02:00
|
|
|
|
#endif
|
2000-04-30 13:01:53 +02:00
|
|
|
|
}
|