diff options
-rw-r--r-- | gcc/ChangeLog | 49 | ||||
-rw-r--r-- | gcc/combine.c | 6 | ||||
-rw-r--r-- | gcc/config/ia64/ia64.c | 3 | ||||
-rw-r--r-- | gcc/emit-rtl.c | 213 | ||||
-rw-r--r-- | gcc/final.c | 11 | ||||
-rw-r--r-- | gcc/regclass.c | 5 | ||||
-rw-r--r-- | gcc/reload.c | 2 | ||||
-rw-r--r-- | gcc/rtl.def | 10 | ||||
-rw-r--r-- | gcc/rtl.h | 10 | ||||
-rw-r--r-- | gcc/var-tracking.c | 141 |
10 files changed, 240 insertions, 210 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 94ff58e..b8ae7de 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,52 @@ +2007-12-19 Richard Sandiford <rsandifo@nildram.co.uk> + + * rtl.def (SUBREG): Update comments. + * rtl.h (reg_attrs): Be explicit about the type of offset used. + (set_reg_attrs_from_mem): Rename to... + (set_reg_attrs_from_value): ...this. + (adjust_reg_mode, byte_lowpart_offset): Declare. + * emit-rtl.c (byte_lowpart_offset): New function. + (update_reg_offset): Remove special offset handling for big-endian + targets. + (gen_rtx_REG_offset, gen_reg_rtx_offset): Explicitly say that the + offset parameter is added to REG_OFFSET. + (adjust_reg_mode): New function. + (set_reg_attrs_for_mem): Rename to... + (set_reg_attrs_for_value): ...this and generalize to all values. + If the register is a lowpart of the value, adjust the offset + accordingly. + (set_reg_attrs_for_parm): Update after the above renaming. + (set_reg_attrs_for_decl_rtl): New function, split out from + set_decl_incoming_rtl. Set the offset of plain REGs to the + offset of the REG's mode from the decl's. Assert that all + subregs are lowparts and handle their inner registers in the + same way as plain REGs. + (set_decl_rtl, set_incoming_decl_rtl): Use reg_attrs_for_decl_rtl. + (subreg_lowpart_offset): Explicitly say that the returned offset + is a SUBREG_BYTE. + * combine.c (do_SUBST_MODE, try_combine, undo_all): Use adjust_reg_mode + instead of PUT_MODE. + * final.c (alter_subreg): Fix/update argument to gen_rtx_REG_offset. + * config/ia64/ia64.c (ia64_expand_load_address): Likewise. + * regclass.c (reg_scan_mark_refs): Use set_reg_attrs_from_value. + * reload.c (find_reloads_subreg_address): Call set_mem_offset + when offseting a MEM. + * var-tracking.c (offset_valid_for_tracked_p): Delete. + (mode_for_reg_attrs): Replace with... + (track_loc_p): ...this new function. Return the mode and offset + to the caller, checking that the latter is valid. If the rtx is + a paradoxical lowpart of the decl, use the decl's mode instead. + Do the same when storing to a register that contains the entire decl. + (var_lowpart): Use byte_lowpart_offset rather than + subreg_lowpart_offset when adjusting the offset attribute. + (count_uses, add_uses, add_stores): Use track_reg_p instead of + REG_EXPR, MEM_EXPR, REG_OFFSET, INT_MEM_OFFSET, track_expr_p, + offset_valid_for_tracked_p and mode_for_reg_attrs. Generate + lowparts for MEMs as well as REGs. + (vt_add_function_parameters): When obtaining the information from + the decl_rtl, adjust the offset to match incoming. Use track_loc_p + and var_lowpart. + 2007-12-18 Sebastian Pop <sebastian.pop@amd.com> PR tree-optimization/34123 diff --git a/gcc/combine.c b/gcc/combine.c index 4e7086f..b3d064d 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -751,7 +751,7 @@ do_SUBST_MODE (rtx *into, enum machine_mode newval) buf->kind = UNDO_MODE; buf->where.r = into; buf->old_contents.m = oldval; - PUT_MODE (*into, newval); + adjust_reg_mode (*into, newval); buf->next = undobuf.undos, undobuf.undos = buf; } @@ -2984,7 +2984,7 @@ try_combine (rtx i3, rtx i2, rtx i1, int *new_direct_jump_p) { struct undo *buf; - PUT_MODE (regno_reg_rtx[REGNO (i2dest)], old_mode); + adjust_reg_mode (regno_reg_rtx[REGNO (i2dest)], old_mode); buf = undobuf.undos; undobuf.undos = buf->next; buf->next = undobuf.frees; @@ -3826,7 +3826,7 @@ undo_all (void) *undo->where.i = undo->old_contents.i; break; case UNDO_MODE: - PUT_MODE (*undo->where.r, undo->old_contents.m); + adjust_reg_mode (*undo->where.r, undo->old_contents.m); break; default: gcc_unreachable (); diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c index a75e68e..f2d00cf 100644 --- a/gcc/config/ia64/ia64.c +++ b/gcc/config/ia64/ia64.c @@ -796,7 +796,8 @@ ia64_expand_load_address (rtx dest, rtx src) computation below are also more natural to compute as 64-bit quantities. If we've been given an SImode destination register, change it. */ if (GET_MODE (dest) != Pmode) - dest = gen_rtx_REG_offset (dest, Pmode, REGNO (dest), 0); + dest = gen_rtx_REG_offset (dest, Pmode, REGNO (dest), + byte_lowpart_offset (Pmode, GET_MODE (dest))); if (TARGET_NO_PIC) return false; diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index f9b1347..ae8970c 100644 --- a/gcc/emit-rtl.c +++ b/gcc/emit-rtl.c @@ -837,6 +837,22 @@ gen_rtvec_v (int n, rtx *argp) return rt_val; } +/* Return the number of bytes between the start of an OUTER_MODE + in-memory value and the start of an INNER_MODE in-memory value, + given that the former is a lowpart of the latter. It may be a + paradoxical lowpart, in which case the offset will be negative + on big-endian targets. */ + +int +byte_lowpart_offset (enum machine_mode outer_mode, + enum machine_mode inner_mode) +{ + if (GET_MODE_SIZE (outer_mode) < GET_MODE_SIZE (inner_mode)) + return subreg_lowpart_offset (outer_mode, inner_mode); + else + return -subreg_lowpart_offset (inner_mode, outer_mode); +} + /* Generate a REG rtx for a new pseudo register of mode MODE. This pseudo is assigned the next sequential register number. */ @@ -891,101 +907,18 @@ gen_reg_rtx (enum machine_mode mode) return val; } -/* Update NEW with the same attributes as REG, but offsetted by OFFSET. - Do the big endian correction if needed. */ +/* Update NEW with the same attributes as REG, but with OFFSET added + to the REG_OFFSET. */ static void update_reg_offset (rtx new, rtx reg, int offset) { - tree decl; - HOST_WIDE_INT var_size; - - /* PR middle-end/14084 - The problem appears when a variable is stored in a larger register - and later it is used in the original mode or some mode in between - or some part of variable is accessed. - - On little endian machines there is no problem because - the REG_OFFSET of the start of the variable is the same when - accessed in any mode (it is 0). - - However, this is not true on big endian machines. - The offset of the start of the variable is different when accessed - in different modes. - When we are taking a part of the REG we have to change the OFFSET - from offset WRT size of mode of REG to offset WRT size of variable. - - If we would not do the big endian correction the resulting REG_OFFSET - would be larger than the size of the DECL. - - Examples of correction, for BYTES_BIG_ENDIAN WORDS_BIG_ENDIAN machine: - - REG.mode MODE DECL size old offset new offset description - DI SI 4 4 0 int32 in SImode - DI SI 1 4 0 char in SImode - DI QI 1 7 0 char in QImode - DI QI 4 5 1 1st element in QImode - of char[4] - DI HI 4 6 2 1st element in HImode - of int16[2] - - If the size of DECL is equal or greater than the size of REG - we can't do this correction because the register holds the - whole variable or a part of the variable and thus the REG_OFFSET - is already correct. */ - - decl = REG_EXPR (reg); - if ((BYTES_BIG_ENDIAN || WORDS_BIG_ENDIAN) - && decl != NULL - && offset > 0 - && GET_MODE_SIZE (GET_MODE (reg)) > GET_MODE_SIZE (GET_MODE (new)) - && ((var_size = int_size_in_bytes (TREE_TYPE (decl))) > 0 - && var_size < GET_MODE_SIZE (GET_MODE (reg)))) - { - int offset_le; - - /* Convert machine endian to little endian WRT size of mode of REG. */ - if (WORDS_BIG_ENDIAN) - offset_le = ((GET_MODE_SIZE (GET_MODE (reg)) - 1 - offset) - / UNITS_PER_WORD) * UNITS_PER_WORD; - else - offset_le = (offset / UNITS_PER_WORD) * UNITS_PER_WORD; - - if (BYTES_BIG_ENDIAN) - offset_le += ((GET_MODE_SIZE (GET_MODE (reg)) - 1 - offset) - % UNITS_PER_WORD); - else - offset_le += offset % UNITS_PER_WORD; - - if (offset_le >= var_size) - { - /* MODE is wider than the variable so the new reg will cover - the whole variable so the resulting OFFSET should be 0. */ - offset = 0; - } - else - { - /* Convert little endian to machine endian WRT size of variable. */ - if (WORDS_BIG_ENDIAN) - offset = ((var_size - 1 - offset_le) - / UNITS_PER_WORD) * UNITS_PER_WORD; - else - offset = (offset_le / UNITS_PER_WORD) * UNITS_PER_WORD; - - if (BYTES_BIG_ENDIAN) - offset += ((var_size - 1 - offset_le) - % UNITS_PER_WORD); - else - offset += offset_le % UNITS_PER_WORD; - } - } - REG_ATTRS (new) = get_reg_attrs (REG_EXPR (reg), REG_OFFSET (reg) + offset); } -/* Generate a register with same attributes as REG, but offsetted by - OFFSET. */ +/* Generate a register with same attributes as REG, but with OFFSET + added to the REG_OFFSET. */ rtx gen_rtx_REG_offset (rtx reg, enum machine_mode mode, unsigned int regno, @@ -998,7 +931,7 @@ gen_rtx_REG_offset (rtx reg, enum machine_mode mode, unsigned int regno, } /* Generate a new pseudo-register with the same attributes as REG, but - offsetted by OFFSET. */ + with OFFSET added to the REG_OFFSET. */ rtx gen_reg_rtx_offset (rtx reg, enum machine_mode mode, int offset) @@ -1009,14 +942,30 @@ gen_reg_rtx_offset (rtx reg, enum machine_mode mode, int offset) return new; } -/* Set REG to the decl that MEM refers to. */ +/* Adjust REG in-place so that it has mode MODE. It is assumed that the + new register is a (possibly paradoxical) lowpart of the old one. */ + +void +adjust_reg_mode (rtx reg, enum machine_mode mode) +{ + update_reg_offset (reg, reg, byte_lowpart_offset (mode, GET_MODE (reg))); + PUT_MODE (reg, mode); +} + +/* Copy REG's attributes from X, if X has any attributes. If REG and X + have different modes, REG is a (possibly paradoxical) lowpart of X. */ void -set_reg_attrs_from_mem (rtx reg, rtx mem) +set_reg_attrs_from_value (rtx reg, rtx x) { - if (MEM_OFFSET (mem) && GET_CODE (MEM_OFFSET (mem)) == CONST_INT) + int offset; + + offset = byte_lowpart_offset (GET_MODE (reg), GET_MODE (x)); + if (MEM_P (x) && MEM_OFFSET (x) && GET_CODE (MEM_OFFSET (x)) == CONST_INT) REG_ATTRS (reg) - = get_reg_attrs (MEM_EXPR (mem), INTVAL (MEM_OFFSET (mem))); + = get_reg_attrs (MEM_EXPR (x), INTVAL (MEM_OFFSET (x)) + offset); + if (REG_P (x) && REG_ATTRS (x)) + update_reg_offset (reg, x, offset); } /* Set the register attributes for registers contained in PARM_RTX. @@ -1026,7 +975,7 @@ void set_reg_attrs_for_parm (rtx parm_rtx, rtx mem) { if (REG_P (parm_rtx)) - set_reg_attrs_from_mem (parm_rtx, mem); + set_reg_attrs_from_value (parm_rtx, mem); else if (GET_CODE (parm_rtx) == PARALLEL) { /* Check for a NULL entry in the first slot, used to indicate that the @@ -1043,54 +992,21 @@ set_reg_attrs_for_parm (rtx parm_rtx, rtx mem) } } -/* Assign the RTX X to declaration T. */ -void -set_decl_rtl (tree t, rtx x) -{ - DECL_WRTL_CHECK (t)->decl_with_rtl.rtl = x; +/* Set the REG_ATTRS for registers in value X, given that X represents + decl T. */ - if (!x) - return; - /* For register, we maintain the reverse information too. */ - if (REG_P (x)) - REG_ATTRS (x) = get_reg_attrs (t, 0); - else if (GET_CODE (x) == SUBREG) - REG_ATTRS (SUBREG_REG (x)) - = get_reg_attrs (t, -SUBREG_BYTE (x)); - if (GET_CODE (x) == CONCAT) - { - if (REG_P (XEXP (x, 0))) - REG_ATTRS (XEXP (x, 0)) = get_reg_attrs (t, 0); - if (REG_P (XEXP (x, 1))) - REG_ATTRS (XEXP (x, 1)) - = get_reg_attrs (t, GET_MODE_UNIT_SIZE (GET_MODE (XEXP (x, 0)))); - } - if (GET_CODE (x) == PARALLEL) +static void +set_reg_attrs_for_decl_rtl (tree t, rtx x) +{ + if (GET_CODE (x) == SUBREG) { - int i; - for (i = 0; i < XVECLEN (x, 0); i++) - { - rtx y = XVECEXP (x, 0, i); - if (REG_P (XEXP (y, 0))) - REG_ATTRS (XEXP (y, 0)) = get_reg_attrs (t, INTVAL (XEXP (y, 1))); - } + gcc_assert (subreg_lowpart_p (x)); + x = SUBREG_REG (x); } -} - -/* Assign the RTX X to parameter declaration T. */ -void -set_decl_incoming_rtl (tree t, rtx x) -{ - DECL_INCOMING_RTL (t) = x; - - if (!x) - return; - /* For register, we maintain the reverse information too. */ if (REG_P (x)) - REG_ATTRS (x) = get_reg_attrs (t, 0); - else if (GET_CODE (x) == SUBREG) - REG_ATTRS (SUBREG_REG (x)) - = get_reg_attrs (t, -SUBREG_BYTE (x)); + REG_ATTRS (x) + = get_reg_attrs (t, byte_lowpart_offset (GET_MODE (x), + TYPE_MODE (TREE_TYPE (t)))); if (GET_CODE (x) == CONCAT) { if (REG_P (XEXP (x, 0))) @@ -1119,6 +1035,26 @@ set_decl_incoming_rtl (tree t, rtx x) } } +/* Assign the RTX X to declaration T. */ + +void +set_decl_rtl (tree t, rtx x) +{ + DECL_WRTL_CHECK (t)->decl_with_rtl.rtl = x; + if (x) + set_reg_attrs_for_decl_rtl (t, x); +} + +/* Assign the RTX X to parameter declaration T. */ + +void +set_decl_incoming_rtl (tree t, rtx x) +{ + DECL_INCOMING_RTL (t) = x; + if (x) + set_reg_attrs_for_decl_rtl (t, x); +} + /* Identify REG (which may be a CONCAT) as a user register. */ void @@ -1304,8 +1240,7 @@ gen_highpart_mode (enum machine_mode outermode, enum machine_mode innermode, rtx subreg_highpart_offset (outermode, innermode)); } -/* Return offset in bytes to get OUTERMODE low part - of the value in mode INNERMODE stored in memory in target format. */ +/* Return the SUBREG_BYTE for an OUTERMODE lowpart of an INNERMODE value. */ unsigned int subreg_lowpart_offset (enum machine_mode outermode, enum machine_mode innermode) diff --git a/gcc/final.c b/gcc/final.c index 654f847..72edbc0 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -2763,8 +2763,15 @@ alter_subreg (rtx *xp) else if (REG_P (y)) { /* Simplify_subreg can't handle some REG cases, but we have to. */ - unsigned int regno = subreg_regno (x); - *xp = gen_rtx_REG_offset (y, GET_MODE (x), regno, SUBREG_BYTE (x)); + unsigned int regno; + HOST_WIDE_INT offset; + + regno = subreg_regno (x); + if (subreg_lowpart_p (x)) + offset = byte_lowpart_offset (GET_MODE (x), GET_MODE (y)); + else + offset = SUBREG_BYTE (x); + *xp = gen_rtx_REG_offset (y, GET_MODE (x), regno, offset); } } diff --git a/gcc/regclass.c b/gcc/regclass.c index d292519..a4734f2 100644 --- a/gcc/regclass.c +++ b/gcc/regclass.c @@ -2435,10 +2435,7 @@ reg_scan_mark_refs (rtx x, rtx insn) || (GET_CODE (src) == SUBREG && subreg_lowpart_p (src))) src = XEXP (src, 0); - if (REG_P (src)) - REG_ATTRS (dest) = REG_ATTRS (src); - if (MEM_P (src)) - set_reg_attrs_from_mem (dest, src); + set_reg_attrs_from_value (dest, src); } /* ... fall through ... */ diff --git a/gcc/reload.c b/gcc/reload.c index 64c0119..8f84546 100644 --- a/gcc/reload.c +++ b/gcc/reload.c @@ -6025,6 +6025,8 @@ find_reloads_subreg_address (rtx x, int force_replace, int opnum, XEXP (tem, 0) = plus_constant (XEXP (tem, 0), offset); PUT_MODE (tem, GET_MODE (x)); + if (MEM_OFFSET (tem)) + set_mem_offset (tem, plus_constant (MEM_OFFSET (tem), offset)); /* If this was a paradoxical subreg that we replaced, the resulting memory must be sufficiently aligned to allow diff --git a/gcc/rtl.def b/gcc/rtl.def index 9dee200..fa2238c 100644 --- a/gcc/rtl.def +++ b/gcc/rtl.def @@ -371,14 +371,8 @@ DEF_RTL_EXPR(REG, "reg", "i00", RTX_OBJ) marked as having one operand so it can be turned into a REG. */ DEF_RTL_EXPR(SCRATCH, "scratch", "0", RTX_OBJ) -/* One word of a multi-word value. - The first operand is the complete value; the second says which word. - The WORDS_BIG_ENDIAN flag controls whether word number 0 - (as numbered in a SUBREG) is the most or least significant word. - - This is also used to refer to a value in a different machine mode. - For example, it can be used to refer to a SImode value as if it were - Qimode, or vice versa. Then the word number is always 0. */ +/* A reference to a part of another value. The first operand is the + complete value and the second is the byte offset of the selected part. */ DEF_RTL_EXPR(SUBREG, "subreg", "ei", RTX_EXTRA) /* This one-argument rtx is used for move instructions @@ -149,7 +149,11 @@ typedef struct mem_attrs GTY(()) } mem_attrs; /* Structure used to describe the attributes of a REG in similar way as - mem_attrs does for MEM above. */ + mem_attrs does for MEM above. Note that the OFFSET field is calculated + in the same way as for mem_attrs, rather than in the same way as a + SUBREG_BYTE. For example, if a big-endian target stores a byte + object in the low part of a 4-byte register, the OFFSET field + will be -3 rather than 0. */ typedef struct reg_attrs GTY(()) { @@ -1476,9 +1480,10 @@ extern rtx copy_insn_1 (rtx); extern rtx copy_insn (rtx); extern rtx gen_int_mode (HOST_WIDE_INT, enum machine_mode); extern rtx emit_copy_of_insn_after (rtx, rtx); -extern void set_reg_attrs_from_mem (rtx, rtx); +extern void set_reg_attrs_from_value (rtx, rtx); extern void set_mem_attrs_from_reg (rtx, rtx); extern void set_reg_attrs_for_parm (rtx, rtx); +extern void adjust_reg_mode (rtx, enum machine_mode); extern int mem_expr_equal_p (const_tree, const_tree); /* In rtl.c */ @@ -1522,6 +1527,7 @@ extern unsigned int subreg_lowpart_offset (enum machine_mode, enum machine_mode); extern unsigned int subreg_highpart_offset (enum machine_mode, enum machine_mode); +extern int byte_lowpart_offset (enum machine_mode, enum machine_mode); extern rtx make_safe_from (rtx, rtx); extern rtx convert_memory_address (enum machine_mode, rtx); extern rtx get_insns (void); diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c index 46752fa..eb7e3b9 100644 --- a/gcc/var-tracking.c +++ b/gcc/var-tracking.c @@ -1645,18 +1645,6 @@ track_expr_p (tree expr) return 1; } -/* Return true if OFFSET is a valid offset for a register or memory - access we want to track. This is used to reject out-of-bounds - accesses that can cause assertions to fail later. Note that we - don't reject negative offsets because they can be generated for - paradoxical subregs on big-endian architectures. */ - -static inline bool -offset_valid_for_tracked_p (HOST_WIDE_INT offset) -{ - return (-MAX_VAR_PARTS < offset) && (offset < MAX_VAR_PARTS); -} - /* Determine whether a given LOC refers to the same variable part as EXPR+OFFSET. */ @@ -1691,28 +1679,65 @@ same_variable_part_p (rtx loc, tree expr, HOST_WIDE_INT offset) return (expr == expr2 && offset == offset2); } -/* REG is a register we want to track. If not all of REG contains useful - information, return the mode of the lowpart that does contain useful - information, otherwise return the mode of REG. +/* LOC is a REG or MEM that we would like to track if possible. + If EXPR is null, we don't know what expression LOC refers to, + otherwise it refers to EXPR + OFFSET. STORE_REG_P is true if + LOC is an lvalue register. - If REG was a paradoxical subreg, its REG_ATTRS will describe the - whole subreg, but only the old inner part is really relevant. */ + Return true if EXPR is nonnull and if LOC, or some lowpart of it, + is something we can track. When returning true, store the mode of + the lowpart we can track in *MODE_OUT (if nonnull) and its offset + from EXPR in *OFFSET_OUT (if nonnull). */ -static enum machine_mode -mode_for_reg_attrs (rtx reg) +static bool +track_loc_p (rtx loc, tree expr, HOST_WIDE_INT offset, bool store_reg_p, + enum machine_mode *mode_out, HOST_WIDE_INT *offset_out) { enum machine_mode mode; - mode = GET_MODE (reg); - if (!HARD_REGISTER_NUM_P (ORIGINAL_REGNO (reg))) + if (expr == NULL || !track_expr_p (expr)) + return false; + + /* If REG was a paradoxical subreg, its REG_ATTRS will describe the + whole subreg, but only the old inner part is really relevant. */ + mode = GET_MODE (loc); + if (REG_P (loc) && !HARD_REGISTER_NUM_P (ORIGINAL_REGNO (loc))) { enum machine_mode pseudo_mode; - pseudo_mode = PSEUDO_REGNO_MODE (ORIGINAL_REGNO (reg)); + pseudo_mode = PSEUDO_REGNO_MODE (ORIGINAL_REGNO (loc)); if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (pseudo_mode)) - mode = pseudo_mode; + { + offset += byte_lowpart_offset (pseudo_mode, mode); + mode = pseudo_mode; + } + } + + /* If LOC is a paradoxical lowpart of EXPR, refer to EXPR itself. + Do the same if we are storing to a register and EXPR occupies + the whole of register LOC; in that case, the whole of EXPR is + being changed. We exclude complex modes from the second case + because the real and imaginary parts are represented as separate + pseudo registers, even if the whole complex value fits into one + hard register. */ + if ((GET_MODE_SIZE (mode) > GET_MODE_SIZE (DECL_MODE (expr)) + || (store_reg_p + && !COMPLEX_MODE_P (DECL_MODE (expr)) + && hard_regno_nregs[REGNO (loc)][DECL_MODE (expr)] == 1)) + && offset + byte_lowpart_offset (DECL_MODE (expr), mode) == 0) + { + mode = DECL_MODE (expr); + offset = 0; } - return mode; + + if (offset < 0 || offset >= MAX_VAR_PARTS) + return false; + + if (mode_out) + *mode_out = mode; + if (offset_out) + *offset_out = offset; + return true; } /* Return the MODE lowpart of LOC, or null if LOC is not something we @@ -1722,7 +1747,7 @@ mode_for_reg_attrs (rtx reg) static rtx var_lowpart (enum machine_mode mode, rtx loc) { - unsigned int offset, regno; + unsigned int offset, reg_offset, regno; if (!REG_P (loc) && !MEM_P (loc)) return NULL; @@ -1730,13 +1755,14 @@ var_lowpart (enum machine_mode mode, rtx loc) if (GET_MODE (loc) == mode) return loc; - offset = subreg_lowpart_offset (mode, GET_MODE (loc)); + offset = byte_lowpart_offset (mode, GET_MODE (loc)); if (MEM_P (loc)) return adjust_address_nv (loc, mode, offset); + reg_offset = subreg_lowpart_offset (mode, GET_MODE (loc)); regno = REGNO (loc) + subreg_regno_offset (REGNO (loc), GET_MODE (loc), - offset, mode); + reg_offset, mode); return gen_rtx_REG_offset (loc, mode, regno, offset); } @@ -1754,9 +1780,8 @@ count_uses (rtx *loc, void *insn) VTI (bb)->n_mos++; } else if (MEM_P (*loc) - && MEM_EXPR (*loc) - && track_expr_p (MEM_EXPR (*loc)) - && offset_valid_for_tracked_p (INT_MEM_OFFSET (*loc))) + && track_loc_p (*loc, MEM_EXPR (*loc), INT_MEM_OFFSET (*loc), + false, NULL, NULL)) { VTI (bb)->n_mos++; } @@ -1787,17 +1812,18 @@ count_stores (rtx loc, const_rtx expr ATTRIBUTE_UNUSED, void *insn) static int add_uses (rtx *loc, void *insn) { + enum machine_mode mode; + if (REG_P (*loc)) { basic_block bb = BLOCK_FOR_INSN ((rtx) insn); micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++; - if (REG_EXPR (*loc) - && track_expr_p (REG_EXPR (*loc)) - && offset_valid_for_tracked_p (REG_OFFSET (*loc))) + if (track_loc_p (*loc, REG_EXPR (*loc), REG_OFFSET (*loc), + false, &mode, NULL)) { mo->type = MO_USE; - mo->u.loc = var_lowpart (mode_for_reg_attrs (*loc), *loc); + mo->u.loc = var_lowpart (mode, *loc); } else { @@ -1807,15 +1833,14 @@ add_uses (rtx *loc, void *insn) mo->insn = (rtx) insn; } else if (MEM_P (*loc) - && MEM_EXPR (*loc) - && track_expr_p (MEM_EXPR (*loc)) - && offset_valid_for_tracked_p (INT_MEM_OFFSET (*loc))) + && track_loc_p (*loc, MEM_EXPR (*loc), INT_MEM_OFFSET (*loc), + false, &mode, NULL)) { basic_block bb = BLOCK_FOR_INSN ((rtx) insn); micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++; mo->type = MO_USE; - mo->u.loc = *loc; + mo->u.loc = var_lowpart (mode, *loc); mo->insn = (rtx) insn; } @@ -1837,22 +1862,22 @@ add_uses_1 (rtx *x, void *insn) static void add_stores (rtx loc, const_rtx expr, void *insn) { + enum machine_mode mode; + if (REG_P (loc)) { basic_block bb = BLOCK_FOR_INSN ((rtx) insn); micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++; if (GET_CODE (expr) == CLOBBER - || !(REG_EXPR (loc) - && track_expr_p (REG_EXPR (loc)) - && offset_valid_for_tracked_p (REG_OFFSET (loc)))) + || !track_loc_p (loc, REG_EXPR (loc), REG_OFFSET (loc), + true, &mode, NULL)) { mo->type = MO_CLOBBER; mo->u.loc = loc; } else { - enum machine_mode mode = mode_for_reg_attrs (loc); rtx src = NULL; if (GET_CODE (expr) == SET && SET_DEST (expr) == loc) @@ -1878,9 +1903,8 @@ add_stores (rtx loc, const_rtx expr, void *insn) mo->insn = (rtx) insn; } else if (MEM_P (loc) - && MEM_EXPR (loc) - && track_expr_p (MEM_EXPR (loc)) - && offset_valid_for_tracked_p (INT_MEM_OFFSET (loc))) + && track_loc_p (loc, MEM_EXPR (loc), INT_MEM_OFFSET (loc), + false, &mode, NULL)) { basic_block bb = BLOCK_FOR_INSN ((rtx) insn); micro_operation *mo = VTI (bb)->mos + VTI (bb)->n_mos++; @@ -1888,14 +1912,15 @@ add_stores (rtx loc, const_rtx expr, void *insn) if (GET_CODE (expr) == CLOBBER) { mo->type = MO_CLOBBER; - mo->u.loc = loc; + mo->u.loc = var_lowpart (mode, loc); } else { rtx src = NULL; if (GET_CODE (expr) == SET && SET_DEST (expr) == loc) - src = var_lowpart (GET_MODE (loc), SET_SRC (expr)); + src = var_lowpart (mode, SET_SRC (expr)); + loc = var_lowpart (mode, loc); if (src == NULL) { @@ -1904,6 +1929,8 @@ add_stores (rtx loc, const_rtx expr, void *insn) } else { + if (SET_SRC (expr) != src) + expr = gen_rtx_SET (VOIDmode, loc, src); if (same_variable_part_p (SET_SRC (expr), MEM_EXPR (loc), INT_MEM_OFFSET (loc))) @@ -3115,6 +3142,7 @@ vt_add_function_parameters (void) rtx decl_rtl = DECL_RTL_IF_SET (parm); rtx incoming = DECL_INCOMING_RTL (parm); tree decl; + enum machine_mode mode; HOST_WIDE_INT offset; dataflow_set *out; @@ -3131,18 +3159,26 @@ vt_add_function_parameters (void) continue; if (!vt_get_decl_and_offset (incoming, &decl, &offset)) - if (!vt_get_decl_and_offset (decl_rtl, &decl, &offset)) - continue; + { + if (!vt_get_decl_and_offset (decl_rtl, &decl, &offset)) + continue; + offset += byte_lowpart_offset (GET_MODE (incoming), + GET_MODE (decl_rtl)); + } if (!decl) continue; gcc_assert (parm == decl); + if (!track_loc_p (incoming, parm, offset, false, &mode, &offset)) + continue; + out = &VTI (ENTRY_BLOCK_PTR)->out; if (REG_P (incoming)) { + incoming = var_lowpart (mode, incoming); gcc_assert (REGNO (incoming) < FIRST_PSEUDO_REGISTER); attrs_list_insert (&out->regs[REGNO (incoming)], parm, offset, incoming); @@ -3150,8 +3186,11 @@ vt_add_function_parameters (void) NULL); } else if (MEM_P (incoming)) - set_variable_part (out, incoming, parm, offset, VAR_INIT_STATUS_INITIALIZED, - NULL); + { + incoming = var_lowpart (mode, incoming); + set_variable_part (out, incoming, parm, offset, + VAR_INIT_STATUS_INITIALIZED, NULL); + } } } |