aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Kenner <kenner@gcc.gnu.org>1992-04-05 12:34:53 -0400
committerRichard Kenner <kenner@gcc.gnu.org>1992-04-05 12:34:53 -0400
commit8b3686ed860ccf729560c6d78fee95c2fa42cea5 (patch)
tree3841e6071bc0a5d9fe9cb6bbcdd1f96b8334d552
parent2aa8f23fc1ac90dcf0ebba82883e17a19022c088 (diff)
downloadgcc-8b3686ed860ccf729560c6d78fee95c2fa42cea5.zip
gcc-8b3686ed860ccf729560c6d78fee95c2fa42cea5.tar.gz
gcc-8b3686ed860ccf729560c6d78fee95c2fa42cea5.tar.bz2
*** empty log message ***
From-SVN: r688
-rw-r--r--gcc/cse.c158
-rw-r--r--gcc/flags.h12
-rw-r--r--gcc/toplev.c6
3 files changed, 152 insertions, 24 deletions
diff --git a/gcc/cse.c b/gcc/cse.c
index 04f638f..4552cac 100644
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -2858,7 +2858,7 @@ simplify_unary_operation (code, mode, op, op_mode)
break;
case ABS:
- if (REAL_VALUES_LESS (d, 0.0))
+ if (REAL_VALUE_NEGATIVE (d))
d = REAL_VALUE_NEGATE (d);
break;
@@ -3860,7 +3860,9 @@ simplify_relational_operation (code, mode, op0, op1)
if (CONSTANT_P (op0) && op1 == const0_rtx)
return const0_rtx;
#endif
- if (NONZERO_BASE_PLUS_P (op0) && op1 == const0_rtx)
+ if (NONZERO_BASE_PLUS_P (op0) && op1 == const0_rtx
+ /* On some machines, the ap reg can be 0 sometimes. */
+ && op0 != arg_pointer_rtx)
return const0_rtx;
break;
}
@@ -3871,7 +3873,9 @@ simplify_relational_operation (code, mode, op0, op1)
if (CONSTANT_P (op0) && op1 == const0_rtx)
return const_true_rtx;
#endif
- if (NONZERO_BASE_PLUS_P (op0) && op1 == const0_rtx)
+ if (NONZERO_BASE_PLUS_P (op0) && op1 == const0_rtx
+ /* On some machines, the ap reg can be 0 sometimes. */
+ && op0 != arg_pointer_rtx)
return const_true_rtx;
break;
@@ -6577,6 +6581,65 @@ cse_around_loop (loop_start)
}
}
+/* Variable used for communications between the next two routines. */
+
+static struct write_data skipped_writes_memory;
+
+/* Process one SET of an insn that was skipped. We ignore CLOBBERs
+ since they are done elsewhere. This function is called via note_stores. */
+
+static void
+invalidate_skipped_set (dest, set)
+ rtx set;
+ rtx dest;
+{
+ if (GET_CODE (set) == CLOBBER
+#ifdef HAVE_cc0
+ || dest == cc0_rtx
+#endif
+ || dest == pc_rtx)
+ return;
+
+ if (GET_CODE (dest) == MEM)
+ note_mem_written (dest, &skipped_writes_memory);
+
+ if (GET_CODE (dest) == REG || GET_CODE (dest) == SUBREG
+ || (! skipped_writes_memory.all && ! cse_rtx_addr_varies_p (dest)))
+ invalidate (dest);
+}
+
+/* Invalidate all insns from START up to the end of the function or the
+ next label. This called when we wish to CSE around a block that is
+ conditionally executed. */
+
+static void
+invalidate_skipped_block (start)
+ rtx start;
+{
+ rtx insn;
+ int i;
+ static struct write_data init = {0, 0, 0, 0};
+ static struct write_data everything = {0, 1, 1, 1};
+
+ for (insn = start; insn && GET_CODE (insn) != CODE_LABEL;
+ insn = NEXT_INSN (insn))
+ {
+ if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+ continue;
+
+ skipped_writes_memory = init;
+
+ if (GET_CODE (insn) == CALL_INSN)
+ {
+ invalidate_for_call ();
+ skipped_writes_memory = everything;
+ }
+
+ note_stores (PATTERN (insn), invalidate_skipped_set);
+ invalidate_from_clobbers (&skipped_writes_memory, PATTERN (insn));
+ }
+}
+
/* Used for communication between the following two routines; contains a
value to be checked for modification. */
@@ -6706,7 +6769,7 @@ cse_set_around_loop (x, insn, loop_start)
The branch path indicates which branches should be followed. If a non-zero
path size is specified, the block should be rescanned and a different set
of branches will be taken. The branch path is only used if
- FLAG_CSE_FOLLOW_JUMPS is non-zero.
+ FLAG_CSE_FOLLOW_JUMPS or FLAG_CSE_SKIP_BLOCKS is non-zero.
DATA is a pointer to a struct cse_basic_block_data, defined below, that is
used to describe the block. It is filled in with the information about
@@ -6732,17 +6795,20 @@ struct cse_basic_block_data {
struct branch_path {
/* The branch insn. */
rtx branch;
- /* Whether it should be taken or not. */
- enum taken {TAKEN, NOT_TAKEN} status;
+ /* Whether it should be taken or not. AROUND is the same as taken
+ except that it is used when the destination label is not preceded
+ by a BARRIER. */
+ enum taken {TAKEN, NOT_TAKEN, AROUND} status;
} path[PATHLENGTH];
};
void
-cse_end_of_basic_block (insn, data, follow_jumps, after_loop)
+cse_end_of_basic_block (insn, data, follow_jumps, after_loop, skip_blocks)
rtx insn;
struct cse_basic_block_data *data;
int follow_jumps;
int after_loop;
+ int skip_blocks;
{
rtx p = insn, q;
int nsets = 0;
@@ -6757,7 +6823,7 @@ cse_end_of_basic_block (insn, data, follow_jumps, after_loop)
at least one branch must have been taken if PATH_SIZE is non-zero. */
while (path_size > 0)
{
- if (data->path[path_size - 1].status == TAKEN)
+ if (data->path[path_size - 1].status != NOT_TAKEN)
{
data->path[path_size - 1].status = NOT_TAKEN;
break;
@@ -6802,15 +6868,15 @@ cse_end_of_basic_block (insn, data, follow_jumps, after_loop)
nsets += 1;
if (INSN_CUID (p) > high_cuid)
- high_cuid = INSN_CUID (p);
+ high_cuid = INSN_CUID (p);
if (INSN_CUID (p) < low_cuid)
- low_cuid = INSN_CUID(p);
+ low_cuid = INSN_CUID(p);
/* See if this insn is in our branch path. If it is and we are to
take it, do so. */
if (path_entry < path_size && data->path[path_entry].branch == p)
{
- if (data->path[path_entry].status == TAKEN)
+ if (data->path[path_entry].status != NOT_TAKEN)
p = JUMP_LABEL (p);
/* Point to next entry in path, if any. */
@@ -6820,8 +6886,14 @@ cse_end_of_basic_block (insn, data, follow_jumps, after_loop)
/* If this is a conditional jump, we can follow it if -fcse-follow-jumps
was specified, we haven't reached our maximum path length, there are
insns following the target of the jump, this is the only use of the
- jump label, and the target label is preceded by a BARRIER. */
- else if (follow_jumps && path_size < PATHLENGTH - 1
+ jump label, and the target label is preceded by a BARRIER.
+
+ Alternatively, we can follow the jump if it branches around a
+ block of code and there are no other branches into the block.
+ In this case invalidate_skipped_block will be called to invalidate any
+ registers set in the block when following the jump. */
+
+ else if ((follow_jumps || skip_blocks) && path_size < PATHLENGTH - 1
&& GET_CODE (p) == JUMP_INSN
&& GET_CODE (PATTERN (p)) == SET
&& GET_CODE (SET_SRC (PATTERN (p))) == IF_THEN_ELSE
@@ -6837,7 +6909,7 @@ cse_end_of_basic_block (insn, data, follow_jumps, after_loop)
/* If we ran into a BARRIER, this code is an extension of the
basic block when the branch is taken. */
- if (q != 0 && GET_CODE (q) == BARRIER)
+ if (follow_jumps && q != 0 && GET_CODE (q) == BARRIER)
{
/* Don't allow ourself to keep walking around an
always-executed loop. */
@@ -6865,8 +6937,40 @@ cse_end_of_basic_block (insn, data, follow_jumps, after_loop)
/* Mark block so we won't scan it again later. */
PUT_MODE (NEXT_INSN (p), QImode);
}
+ /* Detect a branch around a block of code. */
+ else if (skip_blocks && q != 0 && GET_CODE (q) != CODE_LABEL)
+ {
+ register rtx tmp;
+
+ if (next_real_insn (q) == next_real_insn (insn))
+ break;
+
+ for (i = 0; i < path_entry; i++)
+ if (data->path[i].branch == p)
+ break;
+
+ if (i != path_entry)
+ break;
+
+ /* This is no_labels_between_p (p, q) with an added check for
+ reaching the end of a function (in case Q precedes P). */
+ for (tmp = NEXT_INSN (p); tmp && tmp != q; tmp = NEXT_INSN (tmp))
+ if (GET_CODE (tmp) == CODE_LABEL)
+ break;
+
+ if (tmp == q)
+ {
+ data->path[path_entry].branch = p;
+ data->path[path_entry++].status = AROUND;
+
+ path_size = path_entry;
+
+ p = JUMP_LABEL (p);
+ /* Mark block so we won't scan it again later. */
+ PUT_MODE (NEXT_INSN (p), QImode);
+ }
+ }
}
-
p = NEXT_INSN (p);
}
@@ -6878,7 +6982,7 @@ cse_end_of_basic_block (insn, data, follow_jumps, after_loop)
/* If all jumps in the path are not taken, set our path length to zero
so a rescan won't be done. */
for (i = path_size - 1; i >= 0; i--)
- if (data->path[i].status == TAKEN)
+ if (data->path[i].status != NOT_TAKEN)
break;
if (i == -1)
@@ -6998,9 +7102,8 @@ cse_main (f, nregs, after_loop, file)
insn = f;
while (insn)
{
- int tem;
-
- cse_end_of_basic_block (insn, &val, flag_cse_follow_jumps, after_loop);
+ cse_end_of_basic_block (insn, &val, flag_cse_follow_jumps, after_loop,
+ flag_cse_skip_blocks);
/* If this basic block was already processed or has no sets, skip it. */
if (val.nsets == 0 || GET_MODE (insn) == QImode)
@@ -7042,7 +7145,8 @@ cse_main (f, nregs, after_loop, file)
us a new branch path to investigate. */
cse_jumps_altered = 0;
temp = cse_basic_block (insn, val.last, val.path, ! after_loop);
- if (cse_jumps_altered == 0 || flag_cse_follow_jumps == 0)
+ if (cse_jumps_altered == 0
+ || (flag_cse_follow_jumps == 0 && flag_cse_skip_blocks == 0))
insn = temp;
cse_jumps_altered |= old_cse_jumps_altered;
@@ -7116,9 +7220,14 @@ cse_basic_block (from, to, next_branch, around_loop)
to be taken, do so. */
if (next_branch->branch == insn)
{
- if (next_branch++->status == TAKEN)
+ enum taken status = next_branch++->status;
+ if (status != NOT_TAKEN)
{
- record_jump_equiv (insn, 1);
+ if (status == TAKEN)
+ record_jump_equiv (insn, 1);
+ else
+ invalidate_skipped_block (NEXT_INSN (insn));
+
/* Set the last insn as the jump insn; it doesn't affect cc0.
Then follow this branch. */
#ifdef HAVE_cc0
@@ -7200,7 +7309,7 @@ cse_basic_block (from, to, next_branch, around_loop)
to_usage = 0;
val.path_size = 0;
- cse_end_of_basic_block (insn, &val, 0, 0);
+ cse_end_of_basic_block (insn, &val, 0, 0, 0);
/* If the tables we allocated have enough space left
to handle all the SETs in the next basic block,
@@ -7230,7 +7339,8 @@ cse_basic_block (from, to, next_branch, around_loop)
we can cse into the loop. Don't do this if we changed the jump
structure of a loop unless we aren't going to be following jumps. */
- if ((cse_jumps_altered == 0 || flag_cse_follow_jumps == 0)
+ if ((cse_jumps_altered == 0
+ || (flag_cse_follow_jumps == 0 && flag_cse_skip_blocks == 0))
&& around_loop && to != 0
&& GET_CODE (to) == NOTE && NOTE_LINE_NUMBER (to) == NOTE_INSN_LOOP_END
&& GET_CODE (PREV_INSN (to)) == JUMP_INSN
diff --git a/gcc/flags.h b/gcc/flags.h
index 747e7c4..868b3e3 100644
--- a/gcc/flags.h
+++ b/gcc/flags.h
@@ -192,6 +192,11 @@ extern int flag_unroll_all_loops;
extern int flag_cse_follow_jumps;
+/* Nonzero for -fcse-skip-blocks:
+ have cse follow a branch around a block. */
+
+extern int flag_cse_skip_blocks;
+
/* Nonzero for -fexpensive-optimizations:
perform miscellaneous relatively-expensive optimizations. */
extern int flag_expensive_optimizations;
@@ -220,6 +225,13 @@ extern int flag_no_peephole;
extern int flag_volatile;
+/* Nonzero allows GCC to violate some IEEE or ANSI rules regarding math
+ operations in the interest of optimization. For example it allows
+ GCC to assume arguments to sqrt are nonnegative numbers, allowing
+ faster code for sqrt to be generated. */
+
+extern int flag_fast_math;
+
/* Nonzero means make functions that look like good inline candidates
go inline. */
diff --git a/gcc/toplev.c b/gcc/toplev.c
index d7164d8..eb1d278 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -293,6 +293,10 @@ int flag_float_store = 0;
int flag_cse_follow_jumps;
+/* Nonzero for -fcse-skip-blocks:
+ have cse follow a branch around a block. */
+int flag_cse_skip_blocks;
+
/* Nonzero for -fexpensive-optimizations:
perform miscellaneous relatively-expensive optimizations. */
int flag_expensive_optimizations;
@@ -451,6 +455,7 @@ struct { char *string; int *variable; int on_value;} f_options[] =
{"defer-pop", &flag_defer_pop, 1},
{"omit-frame-pointer", &flag_omit_frame_pointer, 1},
{"cse-follow-jumps", &flag_cse_follow_jumps, 1},
+ {"cse-skip-blocks", &flag_cse_skip_blocks, 1},
{"expensive-optimizations", &flag_expensive_optimizations, 1},
{"thread-jumps", &flag_thread_jumps, 1},
{"strength-reduce", &flag_strength_reduce, 1},
@@ -2593,6 +2598,7 @@ main (argc, argv, envp)
if (optimize >= 2)
{
flag_cse_follow_jumps = 1;
+ flag_cse_skip_blocks = 1;
flag_expensive_optimizations = 1;
flag_strength_reduce = 1;
flag_rerun_cse_after_loop = 1;