Index: gcc/rtl.def =================================================================== --- gcc/rtl.def 2007-12-18 07:39:35.000000000 +0000 +++ gcc/rtl.def 2007-12-18 07:48:07.000000000 +0000 @@ -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 Index: gcc/rtl.h =================================================================== --- gcc/rtl.h 2007-12-18 07:48:06.000000000 +0000 +++ gcc/rtl.h 2007-12-18 07:48:07.000000000 +0000 @@ -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_offse 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); Index: gcc/emit-rtl.c =================================================================== --- gcc/emit-rtl.c 2007-12-18 07:48:06.000000000 +0000 +++ gcc/emit-rtl.c 2007-12-18 09:25:48.000000000 +0000 @@ -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 machin } /* 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 machin 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 @@ set_reg_attrs_from_mem (rtx reg, rtx mem 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, rt } } -/* 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 out 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) Index: gcc/combine.c =================================================================== --- gcc/combine.c 2007-12-18 07:48:06.000000000 +0000 +++ gcc/combine.c 2007-12-18 07:48:07.000000000 +0000 @@ -751,7 +751,7 @@ do_SUBST_MODE (rtx *into, enum machine_m 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 { 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 (); Index: gcc/final.c =================================================================== --- gcc/final.c 2007-12-18 07:39:35.000000000 +0000 +++ gcc/final.c 2007-12-18 07:48:07.000000000 +0000 @@ -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); } } Index: gcc/config/ia64/ia64.c =================================================================== --- gcc/config/ia64/ia64.c 2007-12-18 09:26:01.000000000 +0000 +++ gcc/config/ia64/ia64.c 2007-12-18 09:26:22.000000000 +0000 @@ -796,7 +796,8 @@ ia64_expand_load_address (rtx dest, rtx 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; Index: gcc/regclass.c =================================================================== --- gcc/regclass.c 2007-12-18 07:48:06.000000000 +0000 +++ gcc/regclass.c 2007-12-18 07:48:07.000000000 +0000 @@ -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 ... */ Index: gcc/reload.c =================================================================== --- gcc/reload.c 2007-12-18 07:48:06.000000000 +0000 +++ gcc/reload.c 2007-12-18 07:48:07.000000000 +0000 @@ -6025,6 +6025,8 @@ find_reloads_subreg_address (rtx x, int 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 Index: gcc/var-tracking.c =================================================================== --- gcc/var-tracking.c 2007-12-18 07:48:06.000000000 +0000 +++ gcc/var-tracking.c 2007-12-18 07:48:07.000000000 +0000 @@ -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 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. + + 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). */ - If REG was a paradoxical subreg, its REG_ATTRS will describe the - whole subreg, but only the old inner part is really relevant. */ - -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 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 AT 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, voi 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, voi 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, voi } 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); + } } }