Commit 9ae8ffe7 by Jeffrey A Law Committed by Jeff Law

* Integrate alias analysis changes from jfc@mit.edu

        * Makefile.in (OBJS): Add alias.o
        (alias.o): Add dependencies.
        * alias.c: New file.
        * sched.c: Remove alias analysis code.  It lives in alias.c now.
        (reg_last_uses_size): Declare.
        (sched_analyze_2): Add new arguments to true_dependence.
        (sched_analyze_insn): Use reg_last_uses_size instead of max_reg.
        (schedule_block): Initialize reg_last_uses_size.
        (schedule_insns): Always call init_alias_analysis.
        * calls.c (expand_call): Note calls to malloc, calloc, and realloc;
        mark return value from such functions as a pointer and keep track of
        them for alias analysis.  If a return value from a function is a
        pointer, mark it as such.
        * combine.c (distribute_notes): Handle REG_NOALIAS.
        * cse.c (struct write_data): Delete.  No longer needed.
        (invalidate): Don't call set_nonvarying_address_components anymore.
        Use true_dependence to decide if an entry should be removed from
        the hash table.
        (invalidate_memory): Remove WRITES argument, simplify appropriately.
        Fix all callers.
        (note_mem_written): Similarly for WRITE_PTR argument.
        (invalidate_from_clobbers): Similarly for W argument.
        (invalidate_for_call): Remove memory elements from the hash table.
        (refers_to_mem_p, cse_rtx_addr_varies_p): Deleted.
        (cse_rtx_varies_p): New function.  Derived from old
        cse_rtx_addr_varies_p.
        (cse_insn): Remove WRITES_MEMORY and INIT variables and all references.
        Don't call note_mem_written anymore.  Stack pushes invalidate the stack
        pointer if PUSH_ROUNDING is defined.  No longer need to call
        cse_rtx_addr_varies_p to decide if a MEM should be invalidated.
        (skipped_writes_memory): Remove variable.
        (invalidate_skipped_set): Simplify and wewrite to use invalidate_memory.
        (invalidate_skipped_block): Simplify for new alias analysis code.
        (cse_set_around_loop): Likewise.
        (cse_main): Call init_alias_analysis.
        * flags.h (flag_alias_check, flag_argument_noalias): Declare.
        * toplev.c (flag_alias_check, flag_argument_noalias): Define.
        (f_options): Add new alias checking arguments.
        (main): Set flag_alias_check when optimizing.
        * local_alloc (validate_equiv_mem_from_store): Add new arguments
        to true_dependence.
        (memref_referenced_p): Likewise.
        * loop.c (NUM_STORES): Increase to 30.
        (prescan_loop): Only non-constant calls set unknown_address_altered.
        (invariant_p): Add new arguments to true_dependence.
        (record_giv): Initialize unrolled and shared fields.
        (emit_iv_add_mult): Call record_base_value as needed.
        * loop.h (struct induction): Add unrolled and shared fields.
        * unroll.c  (unroll_loop): Call record_base_value as needed.
        (copy_loop_body): Likewise.
        (final_biv_value): Likewise.
        (final_giv_value): Likewise.
        (find_splittable_regs): Likewise.  Only create one new pseudo
        if we have multiple address GIVs that were combined with the same
        dst_reg GIV.  Note when a new register is created due to unrolling.
        * rtl.c (reg_note_name): Add REG_NOALIAS.
        * rtl.h (enum reg_note): Similarly.
        (rtx_varies_p, may_trap_p, side_effects_p): Declare.
        (volatile_refs_p, volatile_insn_p, remove_note): Likewise.
        (note_stores, refers_to_regno_p, reg_overlap_mentioned_p): Likewise.
        (true_dependence, read_dependence, anti_dependence): Likewise.
        (output_dependence, init_alias_analysis, end_alias_analysis): Likewise.
        (mark_user_reg, mark_reg_pointer): Likewise.
jfc's alias analysis code.

From-SVN: r14768
parent 5fa39bfe
Mon Aug 11 10:04:49 1997 Jeffrey A Law (law@cygnus.com)
* Integrate reload bugfix from Wilson which enables the PA port
* Integrate alias analysis changes from jfc@mit.edu
* Makefile.in (OBJS): Add alias.o
(alias.o): Add dependencies.
* alias.c: New file.
* sched.c: Remove alias analysis code. It lives in alias.c now.
(reg_last_uses_size): Declare.
(sched_analyze_2): Add new arguments to true_dependence.
(sched_analyze_insn): Use reg_last_uses_size instead of max_reg.
(schedule_block): Initialize reg_last_uses_size.
(schedule_insns): Always call init_alias_analysis.
* calls.c (expand_call): Note calls to malloc, calloc, and realloc;
mark return value from such functions as a pointer and keep track of
them for alias analysis. If a return value from a function is a
pointer, mark it as such.
* combine.c (distribute_notes): Handle REG_NOALIAS.
* cse.c (struct write_data): Delete. No longer needed.
(invalidate): Don't call set_nonvarying_address_components anymore.
Use true_dependence to decide if an entry should be removed from
the hash table.
(invalidate_memory): Remove WRITES argument, simplify appropriately.
Fix all callers.
(note_mem_written): Similarly for WRITE_PTR argument.
(invalidate_from_clobbers): Similarly for W argument.
(invalidate_for_call): Remove memory elements from the hash table.
(refers_to_mem_p, cse_rtx_addr_varies_p): Deleted.
(cse_rtx_varies_p): New function. Derived from old
cse_rtx_addr_varies_p.
(cse_insn): Remove WRITES_MEMORY and INIT variables and all references.
Don't call note_mem_written anymore. Stack pushes invalidate the stack
pointer if PUSH_ROUNDING is defined. No longer need to call
cse_rtx_addr_varies_p to decide if a MEM should be invalidated.
(skipped_writes_memory): Remove variable.
(invalidate_skipped_set): Simplify and wewrite to use invalidate_memory.
(invalidate_skipped_block): Simplify for new alias analysis code.
(cse_set_around_loop): Likewise.
(cse_main): Call init_alias_analysis.
* flags.h (flag_alias_check, flag_argument_noalias): Declare.
* toplev.c (flag_alias_check, flag_argument_noalias): Define.
(f_options): Add new alias checking arguments.
(main): Set flag_alias_check when optimizing.
* local_alloc (validate_equiv_mem_from_store): Add new arguments
to true_dependence.
(memref_referenced_p): Likewise.
* loop.c (NUM_STORES): Increase to 30.
(prescan_loop): Only non-constant calls set unknown_address_altered.
(invariant_p): Add new arguments to true_dependence.
(record_giv): Initialize unrolled and shared fields.
(emit_iv_add_mult): Call record_base_value as needed.
* loop.h (struct induction): Add unrolled and shared fields.
* unroll.c (unroll_loop): Call record_base_value as needed.
(copy_loop_body): Likewise.
(final_biv_value): Likewise.
(final_giv_value): Likewise.
(find_splittable_regs): Likewise. Only create one new pseudo
if we have multiple address GIVs that were combined with the same
dst_reg GIV. Note when a new register is created due to unrolling.
* rtl.c (reg_note_name): Add REG_NOALIAS.
* rtl.h (enum reg_note): Similarly.
(rtx_varies_p, may_trap_p, side_effects_p): Declare.
(volatile_refs_p, volatile_insn_p, remove_note): Likewise.
(note_stores, refers_to_regno_p, reg_overlap_mentioned_p): Likewise.
(true_dependence, read_dependence, anti_dependence): Likewise.
(output_dependence, init_alias_analysis, end_alias_analysis): Likewise.
(mark_user_reg, mark_reg_pointer): Likewise.
* Integrate reload bugfix from Wilon which enables the PA port
to bootstrap again.
* reload1.c (reload): Sum needs for both OPADDR_ADDR and and
OPERAND_ADDRESS when computing how many registers an insn needs.
......
......@@ -554,7 +554,7 @@ OBJS = toplev.o version.o tree.o print-tree.o stor-layout.o fold-const.o \
dbxout.o sdbout.o dwarfout.o dwarf2out.o xcoffout.o bitmap.o \
integrate.o jump.o cse.o loop.o unroll.o flow.o stupid.o combine.o \
regclass.o local-alloc.o global.o reload.o reload1.o caller-save.o \
insn-peep.o reorg.o sched.o final.o recog.o reg-stack.o \
insn-peep.o reorg.o alias.o sched.o final.o recog.o reg-stack.o \
insn-opinit.o insn-recog.o insn-extract.o insn-output.o insn-emit.o \
profile.o insn-attrtab.o $(out_object_file) getpwd.o convert.o $(EXTRA_OBJS)
......@@ -1321,6 +1321,8 @@ caller-save.o : caller-save.c $(CONFIG_H) $(RTL_H) flags.h \
reorg.o : reorg.c $(CONFIG_H) $(RTL_H) conditions.h hard-reg-set.h \
$(BASIC_BLOCK_H) regs.h insn-config.h insn-attr.h insn-flags.h recog.h \
flags.h output.h
alias.o : alias.c $(CONFIG_H) $(RTL_H) flags.h hard-reg-set.h regs.h \
insn-codes.h
sched.o : $(SCHED_PREFIX)sched.c $(CONFIG_H) $(RTL_H) $(BASIC_BLOCK_H) regs.h hard-reg-set.h \
flags.h insn-config.h insn-attr.h
final.o : final.c $(CONFIG_H) $(RTL_H) $(TREE_H) flags.h regs.h \
......
This diff is collapsed. Click to expand it.
......@@ -563,6 +563,8 @@ expand_call (exp, target, ignore)
/* Nonzero if it is plausible that this is a call to alloca. */
int may_be_alloca;
/* Nonzero if this is a call to malloc or a related function. */
int is_malloc;
/* Nonzero if this is a call to setjmp or a related function. */
int returns_twice;
/* Nonzero if this is a call to `longjmp'. */
......@@ -841,6 +843,7 @@ expand_call (exp, target, ignore)
returns_twice = 0;
is_longjmp = 0;
is_malloc = 0;
if (name != 0 && IDENTIFIER_LENGTH (DECL_NAME (fndecl)) <= 15)
{
......@@ -880,6 +883,12 @@ expand_call (exp, target, ignore)
else if (tname[0] == 'l' && tname[1] == 'o'
&& ! strcmp (tname, "longjmp"))
is_longjmp = 1;
/* Only recognize malloc when alias analysis is enabled. */
else if (flag_alias_check
&& ((tname[0] == 'm' && ! strcmp(tname + 1, "alloc"))
|| (tname[0] == 'c' && ! strcmp(tname + 1, "alloc"))
|| (tname[0] == 'r' && ! strcmp(tname + 1, "ealloc"))))
is_malloc = 1;
}
if (may_be_alloca)
......@@ -1366,7 +1375,7 @@ expand_call (exp, target, ignore)
/* Now we are about to start emitting insns that can be deleted
if a libcall is deleted. */
if (is_const)
if (is_const || is_malloc)
start_sequence ();
/* If we have no actual push instructions, or shouldn't use them,
......@@ -1948,6 +1957,13 @@ expand_call (exp, target, ignore)
rtx temp = gen_reg_rtx (GET_MODE (valreg));
rtx insns;
/* Mark the return value as a pointer if needed. */
if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
{
tree pointed_to = TREE_TYPE (TREE_TYPE (exp));
mark_reg_pointer (temp, TYPE_ALIGN (pointed_to) / BITS_PER_UNIT);
}
/* Construct an "equal form" for the value which mentions all the
arguments in order as well as the function name. */
#ifdef PUSH_ARGS_REVERSED
......@@ -1974,6 +1990,29 @@ expand_call (exp, target, ignore)
end_sequence ();
emit_insns (insns);
}
else if (is_malloc)
{
rtx temp = gen_reg_rtx (GET_MODE (valreg));
rtx last, insns;
/* The return value from a malloc-like function is a pointer. */
if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
mark_reg_pointer (temp, BIGGEST_ALIGNMENT / BITS_PER_UNIT);
emit_move_insn (temp, valreg);
/* The return value from a malloc-like function can not alias
anything else. */
last = get_last_insn ();
REG_NOTES (last) =
gen_rtx (EXPR_LIST, REG_NOALIAS, temp, REG_NOTES (last));
/* Write out the sequence. */
insns = get_insns ();
end_sequence ();
emit_insns (insns);
valreg = temp;
}
/* For calls to `setjmp', etc., inform flow.c it should complain
if nonvolatile values are live. */
......
......@@ -11058,6 +11058,7 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
case REG_EQUAL:
case REG_EQUIV:
case REG_NONNEG:
case REG_NOALIAS:
/* These notes say something about results of an insn. We can
only support them if they used to be on I3 in which case they
remain on I3. Otherwise they are ignored.
......
......@@ -370,6 +370,19 @@ extern int flag_gnu_linker;
/* Tag all structures with __attribute__(packed) */
extern int flag_pack_struct;
/* 1 if alias checking is enabled: symbols do not alias each other
and parameters do not alias the current stack frame. */
extern int flag_alias_check;
/* This flag is only tested if alias checking is enabled.
0 if pointer arguments may alias each other. True in C.
1 if pointer arguments may not alias each other but may alias
global variables.
2 if pointer arguments may not alias each other and may not
alias global variables. True in Fortran.
The value is ignored if flag_alias_check is 0. */
extern int flag_argument_noalias;
/* Emit code to check for stack overflow; also may cause large objects
to be allocated dynamically. */
extern int flag_stack_check;
......
......@@ -543,7 +543,7 @@ validate_equiv_mem_from_store (dest, set)
if ((GET_CODE (dest) == REG
&& reg_overlap_mentioned_p (dest, equiv_mem))
|| (GET_CODE (dest) == MEM
&& true_dependence (dest, equiv_mem)))
&& true_dependence (dest, VOIDmode, equiv_mem, rtx_varies_p)))
equiv_mem_modified = 1;
}
......@@ -632,7 +632,7 @@ memref_referenced_p (memref, x)
reg_equiv_replacement[REGNO (x)]));
case MEM:
if (true_dependence (memref, x))
if (true_dependence (memref, VOIDmode, x, rtx_varies_p))
return 1;
break;
......
......@@ -111,8 +111,7 @@ int *loop_number_exit_count;
unsigned HOST_WIDE_INT loop_n_iterations;
/* Nonzero if there is a subroutine call in the current loop.
(unknown_address_altered is also nonzero in this case.) */
/* Nonzero if there is a subroutine call in the current loop. */
static int loop_has_call;
......@@ -160,7 +159,7 @@ static char *moved_once;
/* Array of MEMs that are stored in this loop. If there are too many to fit
here, we just turn on unknown_address_altered. */
#define NUM_STORES 20
#define NUM_STORES 30
static rtx loop_store_mems[NUM_STORES];
/* Index of first available slot in above array. */
......@@ -2199,7 +2198,8 @@ prescan_loop (start, end)
}
else if (GET_CODE (insn) == CALL_INSN)
{
unknown_address_altered = 1;
if (! CONST_CALL_P (insn))
unknown_address_altered = 1;
loop_has_call = 1;
}
else
......@@ -2795,7 +2795,7 @@ invariant_p (x)
/* See if there is any dependence between a store and this load. */
for (i = loop_store_mems_idx - 1; i >= 0; i--)
if (true_dependence (loop_store_mems[i], x))
if (true_dependence (loop_store_mems[i], VOIDmode, x, rtx_varies_p))
return 0;
/* It's not invalidated by a store in memory
......@@ -4523,6 +4523,8 @@ record_giv (v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
v->final_value = 0;
v->same_insn = 0;
v->auto_inc_opt = 0;
v->unrolled = 0;
v->shared = 0;
/* The v->always_computable field is used in update_giv_derive, to
determine whether a giv can be used to derive another giv. For a
......@@ -5771,6 +5773,8 @@ emit_iv_add_mult (b, m, a, reg, insert_before)
end_sequence ();
emit_insn_before (seq, insert_before);
record_base_value (REGNO (reg), b);
}
/* Test whether A * B can be computed without
......
......@@ -92,6 +92,9 @@ struct induction
would probably lose. */
unsigned auto_inc_opt : 1; /* 1 if this giv had its increment output next
to it to try to form an auto-inc address. */
unsigned unrolled : 1; /* 1 if new register has been allocated in
unrolled loop. */
unsigned shared : 1;
int lifetime; /* Length of life of this giv */
int times_used; /* # times this giv is used. */
rtx derive_adjustment; /* If nonzero, is an adjustment to be
......
......@@ -181,7 +181,7 @@ char *reg_note_name[] = { "", "REG_DEAD", "REG_INC", "REG_EQUIV", "REG_WAS_0",
"REG_NONNEG", "REG_NO_CONFLICT", "REG_UNUSED",
"REG_CC_SETTER", "REG_CC_USER", "REG_LABEL",
"REG_DEP_ANTI", "REG_DEP_OUTPUT", "REG_BR_PROB",
"REG_EXEC_COUNT" };
"REG_EXEC_COUNT", "REG_NOALIAS" };
/* Allocate an rtx vector of N elements.
Store the length, and initialize all elements to zero. */
......
......@@ -317,7 +317,7 @@ enum reg_note { REG_DEAD = 1, REG_INC = 2, REG_EQUIV = 3, REG_WAS_0 = 4,
REG_NONNEG = 8, REG_NO_CONFLICT = 9, REG_UNUSED = 10,
REG_CC_SETTER = 11, REG_CC_USER = 12, REG_LABEL = 13,
REG_DEP_ANTI = 14, REG_DEP_OUTPUT = 15, REG_BR_PROB = 16,
REG_EXEC_COUNT = 17 };
REG_EXEC_COUNT = 17, REG_NOALIAS = 18 };
/* The base value for branch probability notes. */
#define REG_BR_PROB_BASE 10000
......@@ -803,6 +803,16 @@ extern rtx gen_ble PROTO((rtx));
extern rtx eliminate_constant_term PROTO((rtx, rtx *));
extern rtx expand_complex_abs PROTO((enum machine_mode, rtx, rtx, int));
extern enum machine_mode choose_hard_reg_mode PROTO((int, int));
extern int rtx_varies_p PROTO((rtx));
extern int may_trap_p PROTO((rtx));
extern int side_effects_p PROTO((rtx));
extern int volatile_refs_p PROTO((rtx));
extern int volatile_insn_p PROTO((rtx));
extern void remove_note PROTO((rtx, rtx));
extern void note_stores PROTO((rtx, void (*)()));
extern int refers_to_regno_p PROTO((int, int, rtx, rtx *));
extern int reg_overlap_mentioned_p PROTO((rtx, rtx));
/* Maximum number of parallel sets and clobbers in any insn in this fn.
Always at least 3, since the combiner could put that many togetherm
......@@ -959,3 +969,12 @@ extern char *regno_pointer_align;
know what `enum tree_code' means. */
extern int rtx_to_tree_code PROTO((enum rtx_code));
extern int true_dependence PROTO((rtx, enum machine_mode, rtx, int (*)()));
extern int read_dependence PROTO((rtx, rtx));
extern int anti_dependence PROTO((rtx, rtx));
extern int output_dependence PROTO((rtx, rtx));
extern void init_alias_analysis PROTO((void));
extern void end_alias_analysis PROTO((void));
extern void mark_user_reg PROTO((rtx));
extern void mark_reg_pointer PROTO((rtx, int));
......@@ -616,6 +616,17 @@ int flag_check_memory_usage = 0;
-fcheck-memory-usage. */
int flag_prefix_function_name = 0;
/* 1 if alias checking is on (by default, when -O). */
int flag_alias_check = 0;
/* 0 if pointer arguments may alias each other. True in C.
1 if pointer arguments may not alias each other but may alias
global variables.
2 if pointer arguments may not alias each other and may not
alias global variables. True in Fortran.
This defaults to 0 for C. */
int flag_argument_noalias = 0;
/* Table of language-independent -f options.
STRING is the option name. VARIABLE is the address of the variable.
ON_VALUE is the value to store in VARIABLE
......@@ -672,6 +683,10 @@ struct { char *string; int *variable; int on_value;} f_options[] =
{"pack-struct", &flag_pack_struct, 1},
{"stack-check", &flag_stack_check, 1},
{"bytecode", &output_bytecode, 1},
{"alias-check", &flag_alias_check, 1},
{"argument-alias", &flag_argument_noalias, 0},
{"argument-noalias", &flag_argument_noalias, 1},
{"argument-noalias-global", &flag_argument_noalias, 2},
{"check-memory-usage", &flag_check_memory_usage, 1},
{"prefix-function-name", &flag_prefix_function_name, 1}
};
......@@ -3672,6 +3687,7 @@ main (argc, argv, envp)
#ifdef CAN_DEBUG_WITHOUT_FP
flag_omit_frame_pointer = 1;
#endif
flag_alias_check = 1;
}
if (optimize >= 2)
......
......@@ -1046,8 +1046,11 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
for (j = FIRST_PSEUDO_REGISTER; j < max_reg_before_loop; j++)
if (local_regno[j])
map->reg_map[j] = gen_reg_rtx (GET_MODE (regno_reg_rtx[j]));
{
map->reg_map[j] = gen_reg_rtx (GET_MODE (regno_reg_rtx[j]));
record_base_value (REGNO (map->reg_map[j]),
regno_reg_rtx[j]);
}
/* The last copy needs the compare/branch insns at the end,
so reset copy_end here if the loop ends with a conditional
branch. */
......@@ -1191,7 +1194,11 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
for (j = FIRST_PSEUDO_REGISTER; j < max_reg_before_loop; j++)
if (local_regno[j])
map->reg_map[j] = gen_reg_rtx (GET_MODE (regno_reg_rtx[j]));
{
map->reg_map[j] = gen_reg_rtx (GET_MODE (regno_reg_rtx[j]));
record_base_value (REGNO (map->reg_map[j]),
regno_reg_rtx[j]);
}
/* If loop starts with a branch to the test, then fix it so that
it points to the test of the first unrolled copy of the loop. */
......@@ -1691,7 +1698,7 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
/* Check for shared address givs, and avoid
incrementing the shared pseudo reg more than
once. */
if (! tv->same_insn)
if (! tv->same_insn && ! tv->shared)
{
/* tv->dest_reg may actually be a (PLUS (REG)
(CONST)) here, so we must call plus_constant
......@@ -1817,6 +1824,7 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
tem = gen_reg_rtx (GET_MODE (giv_src_reg));
giv_dest_reg = tem;
map->reg_map[regno] = tem;
record_base_value (REGNO (tem), giv_src_reg);
}
else
map->reg_map[regno] = giv_src_reg;
......@@ -2505,7 +2513,8 @@ find_splittable_regs (unroll_type, loop_start, loop_end, end_insert_before,
|| ! invariant_p (bl->initial_value)))
{
rtx tem = gen_reg_rtx (bl->biv->mode);
record_base_value (REGNO (tem), bl->biv->add_val);
emit_insn_before (gen_move_insn (tem, bl->biv->src_reg),
loop_start);
......@@ -2562,6 +2571,8 @@ find_splittable_regs (unroll_type, loop_start, loop_end, end_insert_before,
this insn will always be executed, no matter how the loop
exits. */
rtx tem = gen_reg_rtx (bl->biv->mode);
record_base_value (REGNO (tem), bl->biv->add_val);
emit_insn_before (gen_move_insn (tem, bl->biv->src_reg),
loop_start);
emit_insn_before (gen_move_insn (bl->biv->src_reg,
......@@ -2737,6 +2748,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
{
rtx tem = gen_reg_rtx (bl->biv->mode);
record_base_value (REGNO (tem), bl->biv->add_val);
emit_insn_before (gen_move_insn (tem, bl->biv->src_reg),
loop_start);
biv_initial_value = tem;
......@@ -2778,6 +2790,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
|| GET_CODE (XEXP (value, 1)) != CONST_INT))
{
rtx tem = gen_reg_rtx (v->mode);
record_base_value (REGNO (tem), v->add_val);
emit_iv_add_mult (bl->initial_value, v->mult_val,
v->add_val, tem, loop_start);
value = tem;
......@@ -2796,16 +2809,9 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
what we want for split addr regs. We always create a new
register for the split addr giv, just to be safe. */
/* ??? If there are multiple address givs which have been
combined with the same dest_reg giv, then we may only need
one new register for them. Pulling out constants below will
catch some of the common cases of this. Currently, I leave
the work of simplifying multiple address givs to the
following cse pass. */
/* As a special case, if we have multiple identical address givs
within a single instruction, then we do use a single pseudo
reg for both. This is necessary in case one is a match_dup
/* If we have multiple identical address givs within a
single instruction, then use a single pseudo reg for
both. This is necessary in case one is a match_dup
of the other. */
v->const_adjust = 0;
......@@ -2818,12 +2824,26 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
"Sharing address givs in insn %d\n",
INSN_UID (v->insn));
}
/* If multiple address GIVs have been combined with the
same dest_reg GIV, do not create a new register for
each. */
else if (unroll_type != UNROLL_COMPLETELY
&& v->giv_type == DEST_ADDR
&& v->same && v->same->giv_type == DEST_ADDR
&& v->same->unrolled)
{
v->dest_reg = v->same->dest_reg;
v->shared = 1;
}
else if (unroll_type != UNROLL_COMPLETELY)
{
/* If not completely unrolling the loop, then create a new
register to hold the split value of the DEST_ADDR giv.
Emit insn to initialize its value before loop start. */
tem = gen_reg_rtx (v->mode);
rtx tem = gen_reg_rtx (v->mode);
record_base_value (REGNO (tem), v->add_val);
v->unrolled = 1;
/* If the address giv has a constant in its new_reg value,
then this constant can be pulled out and put in value,
......@@ -2834,7 +2854,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
{
v->dest_reg
= plus_constant (tem, INTVAL (XEXP (v->new_reg,1)));
/* Only succeed if this will give valid addresses.
Try to validate both the first and the last
address resulting from loop unrolling, if
......@@ -3130,6 +3150,7 @@ final_biv_value (bl, loop_start, loop_end)
case it is needed later. */
tem = gen_reg_rtx (bl->biv->mode);
record_base_value (REGNO (tem), bl->biv->add_val);
/* Make sure loop_end is not the last insn. */
if (NEXT_INSN (loop_end) == 0)
emit_note_after (NOTE_INSN_DELETED, loop_end);
......@@ -3228,6 +3249,7 @@ final_giv_value (v, loop_start, loop_end)
/* Put the final biv value in tem. */
tem = gen_reg_rtx (bl->biv->mode);
record_base_value (REGNO (tem), bl->biv->add_val);
emit_iv_add_mult (increment, GEN_INT (loop_n_iterations),
bl->initial_value, tem, insert_before);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment