parent
2aa8f23fc1
commit
8b3686ed86
152
gcc/cse.c
152
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;
|
||||
|
@ -6810,7 +6876,7 @@ cse_end_of_basic_block (insn, data, follow_jumps, after_loop)
|
|||
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)
|
||||
{
|
||||
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
|
||||
|
|
12
gcc/flags.h
12
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. */
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue