aboutsummaryrefslogtreecommitdiff
path: root/gcc/combine.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2001-04-03 17:06:12 +0200
committerAndrew Macleod <amacleod@gcc.gnu.org>2001-04-03 15:06:12 +0000
commitddef6bc7a3c885433f0b8a611cdbb4bef0ce4bc3 (patch)
tree28cfaed9a88de9b20638576026f15f0a1d8b06e6 /gcc/combine.c
parent924c96ebc4c736cd20d0a36a3973686854e2a152 (diff)
downloadgcc-ddef6bc7a3c885433f0b8a611cdbb4bef0ce4bc3.zip
gcc-ddef6bc7a3c885433f0b8a611cdbb4bef0ce4bc3.tar.gz
gcc-ddef6bc7a3c885433f0b8a611cdbb4bef0ce4bc3.tar.bz2
Use byte offsets in SUBREGs instead of words.
2001-04-03 Jakub Jelinek <jakub@redhat.com> David S. Miller <davem@pierdol.cobaltmicro.com> Andrew MacLeod <amacleod@redhat.com> Use byte offsets in SUBREGs instead of words. * alias.c (nonlocal_mentioned_p): Use subreg_regno function. * caller-save.c (mark_set_regs): Change callers of subreg_hard_regno to pass new argument. (add_stored_regs): Use subreg_regno_offset function. * calls.c (expand_call): For non-paradoxical SUBREG take endianess into account. (precompute_arguments): Use gen_lowpart_SUBREG. * combine.c (try_combine): Replace explicit XEXP with SUBREG_REG. (combine_simplify_rtx): Rework to use SUBREG_BYTE. (simplify_set): Rework to use SUBREG_BYTE. (expand_field_assignment): Use SUBREG_BYTE. (make_extraction): Use SUBREG_BYTE. (if_then_else_cond): Use SUBREG_BYTE. (apply_distributive_law): Use SUBREG_BYTE and fixup subreg comments. (gen_lowpart_for_combine): Compute full byte offset. * cse.c (mention_regs): Use SUBREG_BYTE. (remove_invalid_subreg_refs): Rework to use SUBREG_BYTE. (canon_hash): Use SUBREG_BYTE. (fold_rtx): Pass SUBREG_BYTE div UNITS_PER_WORD to operand_subword. (gen_lowpart_if_possible): Formatting. * dbxout.c (dbxout_symbol_location): Compute SUBREG hard regnos correctly. * dwarf2out.c (is_pseudo_reg): Fixup explicit XEXP into SUBREG_REG (mem_loc_descriptor): Fixup explicit XEXP into SUBREG_REG (loc_descriptor): Fixup explicit XEXP into SUBREG_REG * dwarfout.c (is_pseudo_reg): Fixup explicit XEXP into SUBREG_REG (output_mem_loc_descriptor): Fixup explicit XEXP into SUBREG_REG (output_loc_descriptor): Fixup explicit XEXP into SUBREG_REG * emit-rtl.c (gen_rtx_SUBREG): New function, used to verify certain invariants about SUBREGs the compiler creates. (gen_lowpart_SUBREG): New function. (subreg_hard_regno): New function to get the final register number. (gen_lowpart_common): Use SUBREG_BYTE. (gen_imagpart): Spacing nits. (subreg_realpart_p): Use SUBREG_BYTE. (gen_highpart): Use SUBREG_BYTE. (subreg_lowpart_p): Always compute endian corrected goal offset, even at the byte level, then compare against that. (constant_subword): New function, pulled out all constant cases from operand_subword and changed second argument name to offset. (operand_subword): Detect non REG/SUBREG/CONCAT/MEM cases early and call constant_subword to do the work. Return const0_rtx if looking for a word outside of OP. (operand_subword_force): Change second arg name to offset. * expmed.c (store_bit_field): Use SUBREG_BYTE. (store_split_bit_field): Use SUBREG_BYTE. (extract_bit_field): Use SUBREG_BYTE. (extract_split_bit_field): Use SUBREG_BYTE. (expand_shift): Use SUBREG_BYTE. * expr.c (store_expr, expand_expr): Use gen_lowpart_SUBREG. * final.c (alter_subreg) Use subreg_hard_regno and SUBREG_BYTE. * flow.c (set_noop_p): Use SUBREG_BYTE. (mark_set_1): Remove ALTER_HARD_SUBREG. Use subreg_regno_offset instead. * function.c (fixup_var_refs_1): Fixup explicit XEXP into a SUBREG_REG. (fixup_memory_subreg): Use SUBREG_BYTE and remove byte endian correction code. (optimize_bit_field): Use SUBREG_BYTE. (purge_addressof_1): Use SUBREG_BYTE. (purge_single_hard_subreg_set): Use subreg_regno_offset function. (assign_params): Mark arguments SUBREG_PROMOTED_VAR_P if they are actually promoted by the caller and PROMOTE_FOR_CALLS_ONLY is true. * gengenrtl.c (special_rtx): Add SUBREG. * global.c (mark_reg_store): Use SUBREG_BYTE. (set_preference): Rework to use subreg_regno_offset and SUBREG_BYTE. * ifcvt (noce_emit_move_insn): Use SUBREG_BYTE. * integrate.c (copy_rtx_and_substitute): Use SUBREG_BYTE and make sure final byte offset is congruent to subreg's mode size. (subst_constants): Use SUBREG_BYTE. (mark_stores): Use subreg_regno_offset function. * jump.c (rtx_renumbered_equal_p, true_regnum): Use subreg_regno_offset function and SUBREG_BYTE. * local-alloc.c (combine_regs): Use subreg_regno_offset function. (reg_is_born): Use subreg_hard_regno. * recog.c (valid_replace_rtx_1): Use SUBREG_BYTE and remove byte endian correction code. Don't combine subregs unless resulting offset aligns with type. Fix subreg constant extraction for DImode. Simplify SUBREG of VOIDmode CONST_DOUBLE. (general_operand): Remove dead mode_altering_drug code. (indirect_operand): Use SUBREG_BYTE. (constrain_operands): Use subreg_regno_offset function. * reg-stack.c (get_true_reg): Use subreg_regno_offset function. * regmove.c (regmove_optimize): Use SUBREG_BYTE. (optimize_reg_copy_3): Use gen_lowpart_SUBREG. * regs.h (REG_SIZE): Allow target to override. (REGMODE_NATURAL_SIZE): New macro which target can override. * reload.c (reload_inner_reg_of_subreg): subreg_regno should be used on the entire subreg rtx. (push_reload): Use SUBREG_BYTE in comments and code. (find_dummy_reload): Use subreg_regno_offset. Only adjust offsets for hard registers inside subregs. (operands_match_p): Use subreg_regno_offset. (find_reloads): Use SUBREG_BYTE and only advance offset for subregs containing hard regs. (find_reload_toplev): Use SUBREG_BYTE. Remove byte endian corrections when fixing up MEM subregs. (find_reloads_address_1): Use SUBREG_BYTE, subreg_regno, and subreg_regno_offset where appropriate. (find_reloads_subreg_address): Use SUBREG_BYTE. Remove byte endian corrections when fixing up MEM subregs. (subst_reloads): When combining two subregs, make sure final offset is congruent to subreg's mode size. (find_replacement): Use SUBREG_BYTE and subreg_regno_offset. (refers_to_regno_for_reload_p): Use subreg_regno. (reg_overlap_mentioned_for_reload_p): Use subreg_regno_offset. * reload1.c (eliminate_regs) Use SUBREG_BYTE. Remove byte endian correction code for memory subreg fixups. (forget_old_reload_1): Use subreg_regno_offset. (choose_reload_regs): Use subreg_regno. (emit_input_reload_insns): Use SUBREG_BYTE. (reload_combine_note_store): Use subreg_regno_offset. (move2add_note_store): Use subreg_regno_offset. * resource.c (update_live_status, mark_referenced_resources): Use subreg_regno function. (mark_set_resources): Use subreg_regno function. * rtl.h (SUBREG_WORD): Rename to SUBREG_BYTE. (subreg_regno_offset, subreg_regno): Define prototypes. (subreg_hard_regno, constant_subword, gen_rtx_SUBREG): Newi functions. (gen_lowpart_SUBREG): Add prototype. * rtl.texi (subreg): Update to reflect new byte offset representation. Add mentioning of the effect that BYTES_BIG_ENDIAN has on subregs now. * rtlanal.c (refers_to_regno_p): Use subreg_regno. (reg_overlap_mentioned_p): Use subreg_regno. (replace_regs); Make sure final offset of combined subreg is congruent to size of subreg's mode. (subreg_regno_offset): New function. (subreg_regno): New function. * sched-vis.c (print_value): Change SUBREG_WORD to SUBREG_BYTE. * sdbout.c (sdbout_symbol): Compute offset using alter_subreg. * stmt.c (expand_anon_union_decl): Use gen_lowpart_SUBREG. * tm.texi (ALTER_HARD_SUBREG): Remove, it is now dead. (SUBREG_REGNO_OFFSET): Describe SUBREG_REGNO_OFFSET overrides. * config/a29k/a29k.c (gpc_reg_operand): Use subreg_regno. (a29k_get_reloaded_address): Use SUBREG_BYTE. (print_operand): Use SUBREG_BYTE. * config/alpha/alpha.c (print_operand_address): Use SUBREG_BYTE. * config/arm/arm.c (arm_reload_in_hi): Use SUBREG_BYTE. (arm_reload_out_hi): Use SUBREG_BYTE. * config/d30v/d30v.c (d30v_split_double): Use subreg_regno_offset instead of SUBREG_WORD. (d30v_print_operand_memory_reference): Use subreg_regno_offset. * config/dsp16xx/dsp16xx.md (extendqihi2, zero_extendqihi2): Fix SUBREG creation to use byte offset. * config/h8300/h8300.md (Unnamed HImode zero extraction and 16bit inverted load insns): Fix explicit rtl subregs to use byte offsets. * config/i370/i370.md (cmpstrsi, movstrsi, mulsi3, divsi3, udivsi3, umodsi3): Generate SUBREGs with byte offsets. * config/i860/i860.c (single_insn_src_p): Use SUBREG_BYTE. * config/i860/i860.md (mulsi3_big): Fixup explicit SUBREGs in rtl to use byte offsets. (unnamed fmlow.dd insn): Fixup SUBREGS to use byte offsets. * config/i960/i960.md (extendhisi2): Generate SUBREGs with byte offsets, also make sure it is congruent to SUBREG's mode size. (extendqisi2, extendqihi2, zero_extendhisi2, zero_extendqisi2, unnamed ldob insn): Generate SUBREGs with byte offset. (zero_extendqihi2): SUBREG's are byte offsets. * config/m68hc11/m68hc11.c (m68hc11_gen_lowpart): Use SUBREG_BYTE. (m68hc11_gen_highpart): Use SUBREG_BYTE. * config/m68k/m68k.md (zero_extendhisi2, zero_extendqihi2, zero-extendqisi2): Generate SUBREGs with byte offset. (umulsidi3, mulsidi3, subreghi1ashrdi_const32, subregsi1ashrdi_const32, subreg1lshrdi_const32): Fixup explicit subregs in rtl to use byte offsets. * config/m88k/m88k.md (extendsidi2): fixup subregs to use byte offset. * config/mips/mips.c (mips_move_1word): Use subreg_regno_offset. (mips_move_2words): Use subreg_regno_offset. (mips_secondary_reload_class): Use subreg_regno_offset. * config/mips/mips.md (DImode plus, minus, move, and logical op splits): Fixup explicit subregs in rtl to use byte offsets. * config/mn10200/mn10200.c (print_operand): Use subreg_regno function. * config/mn10300/mn10300.c (print_operand): Use subreg_regno function. * config/ns32k/ns32k.md (udivmoddisi4): Fix explicit subregs in rtl to use byte offsets. * config/pa/pa.c (emit_move_sequence): Use SUBREG_BYTE. * config/pa/pa.md (floatunssisf2, floatunssidf2, mulsi3): fix explicit subregs to use byte offsets. * config/pdp11/pdp11.md (zero_extendhisi2, modhi3, modhi3+1): Fixup explicit subregs in rtl to use byte offsets. * config/romp/romp.c (memory_offset_in_range_p): Use SUBREG_BYTE and remove byte endian correction code. * config/sh/sh.c (output_movedouble): Use subreg_regno. (gen_ashift_hi): Use SUBREG_BYTE. (regs_used): Use subreg_regno_offset. (machine_dependent_reorg): Use subreg_regno_offset. * config/sh/sh.h (INDEX_REGISTER_RTX_P): Use SUBREG_BYTE. * config/sh/sh.md (DImode and DFmode move splits): Use subreg_regno. (movdf_i4): Subregs are byte offsets now. * config/sparc/sparc.c (ultra_find_type): Use SUBREG_BYTE. * config/sparc/sparc.h (ALTER_HARD_SUBREG): Removed. (REGMODE_NATURAL_SIZE): Override. (REG_SIZE): For SUBREG check float mode on SUBREG_REG's mode. * config/sparc/sparc.md (TFmode move splits): Generate SUBREGs with byte offsets. (zero_extendhisi2, zero_extendqidi2_insn, extendhisi2, extendqihi2, sign_extendqihi2_insn, sign_extendqisi2_insn, extendqidi2): Generate SUBREGs with byte offsets, also make sure it is congruent to SUBREG's mode size. (smulsi3_highpart_v8plus): Fix explicit subregs in rtl to use byte offsets. (cmp_siqi_trunc, cmp_siqi_trunc_set, cmp_diqi_trunc, cmp_diqi_trunc_set, lshrdi3_v8plus+1, lshrdi3_v8plus+2, lshrdi3_v8plus+3, lshrdi3_v8plus+4): Use proper SUBREG_BYTE offset for non-paradoxical subregs in patterns. * config/v850/v850.c (print_operand, output_move_double): Use subreg_regno function. Co-Authored-By: Andrew MacLeod <amacleod@redhat.com> Co-Authored-By: David S. Miller <davem@pierdol.cobaltmicro.com> From-SVN: r41058
Diffstat (limited to 'gcc/combine.c')
-rw-r--r--gcc/combine.c165
1 files changed, 109 insertions, 56 deletions
diff --git a/gcc/combine.c b/gcc/combine.c
index 4aa7721..ee5631c 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -2249,7 +2249,7 @@ try_combine (i3, i2, i1, new_direct_jump_p)
be written as a ZERO_EXTEND. */
if (split_code == SUBREG && GET_CODE (SUBREG_REG (*split)) == MEM)
SUBST (*split, gen_rtx_ZERO_EXTEND (split_mode,
- XEXP (*split, 0)));
+ SUBREG_REG (*split)));
#endif
newi2pat = gen_rtx_SET (VOIDmode, newdest, *split);
@@ -3773,27 +3773,17 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
<= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
{
rtx inner = SUBREG_REG (x);
- int endian_offset = 0;
+ int offset = SUBREG_BYTE (x);
/* Don't change the mode of the MEM
if that would change the meaning of the address. */
if (MEM_VOLATILE_P (SUBREG_REG (x))
|| mode_dependent_address_p (XEXP (inner, 0)))
return gen_rtx_CLOBBER (mode, const0_rtx);
- if (BYTES_BIG_ENDIAN)
- {
- if (GET_MODE_SIZE (mode) < UNITS_PER_WORD)
- endian_offset += UNITS_PER_WORD - GET_MODE_SIZE (mode);
- if (GET_MODE_SIZE (GET_MODE (inner)) < UNITS_PER_WORD)
- endian_offset -= (UNITS_PER_WORD
- - GET_MODE_SIZE (GET_MODE (inner)));
- }
/* Note if the plus_constant doesn't make a valid address
then this combination won't be accepted. */
x = gen_rtx_MEM (mode,
- plus_constant (XEXP (inner, 0),
- (SUBREG_WORD (x) * UNITS_PER_WORD
- + endian_offset)));
+ plus_constant (XEXP (inner, 0), offset));
MEM_COPY_ATTRIBUTES (x, inner);
return x;
}
@@ -3806,12 +3796,58 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
or not at all if changing back to starting mode. */
if (GET_CODE (SUBREG_REG (x)) == SUBREG)
{
- if (mode == GET_MODE (SUBREG_REG (SUBREG_REG (x)))
- && SUBREG_WORD (x) == 0 && SUBREG_WORD (SUBREG_REG (x)) == 0)
- return SUBREG_REG (SUBREG_REG (x));
+ int final_offset;
+ enum machine_mode outer_mode, inner_mode;
+
+ /* If the innermost mode is the same as the goal mode,
+ and the low word is being referenced in both SUBREGs,
+ return the innermost element. */
+ if (mode == GET_MODE (SUBREG_REG (SUBREG_REG (x))))
+ {
+ int inner_word = SUBREG_BYTE (SUBREG_REG (x));
+ int outer_word = SUBREG_BYTE (x);
+
+ inner_word = (inner_word / UNITS_PER_WORD) * UNITS_PER_WORD;
+ outer_word = (outer_word / UNITS_PER_WORD) * UNITS_PER_WORD;
+ if (inner_word == 0
+ && outer_word == 0)
+ return SUBREG_REG (SUBREG_REG (x));
+ }
+
+ outer_mode = GET_MODE (SUBREG_REG (x));
+ inner_mode = GET_MODE (SUBREG_REG (SUBREG_REG (x)));
+ final_offset = SUBREG_BYTE (x) + SUBREG_BYTE (SUBREG_REG(x));
+
+ if ((WORDS_BIG_ENDIAN || BYTES_BIG_ENDIAN)
+ && GET_MODE_SIZE (outer_mode) > GET_MODE_SIZE (mode)
+ && GET_MODE_SIZE (outer_mode) > GET_MODE_SIZE (inner_mode))
+ {
+ /* Inner SUBREG is paradoxical, outer is not. On big endian
+ we have to special case this. */
+ if (SUBREG_BYTE (SUBREG_REG (x)))
+ abort(); /* Can a paradoxical subreg have nonzero offset? */
+ if (WORDS_BIG_ENDIAN && BYTES_BIG_ENDIAN)
+ final_offset = SUBREG_BYTE (x) - GET_MODE_SIZE (outer_mode)
+ + GET_MODE_SIZE (inner_mode);
+ else if (WORDS_BIG_ENDIAN)
+ final_offset = (final_offset % UNITS_PER_WORD)
+ + ((SUBREG_BYTE (x) - GET_MODE_SIZE (outer_mode)
+ + GET_MODE_SIZE (inner_mode))
+ * UNITS_PER_WORD) / UNITS_PER_WORD;
+ else
+ final_offset = ((final_offset * UNITS_PER_WORD)
+ / UNITS_PER_WORD)
+ + ((SUBREG_BYTE (x) - GET_MODE_SIZE (outer_mode)
+ + GET_MODE_SIZE (inner_mode))
+ % UNITS_PER_WORD);
+ }
- SUBST_INT (SUBREG_WORD (x),
- SUBREG_WORD (x) + SUBREG_WORD (SUBREG_REG (x)));
+ /* The SUBREG rules are that the byte offset must be
+ some multiple of the toplevel SUBREG's mode. */
+ final_offset = (final_offset / GET_MODE_SIZE (mode));
+ final_offset = (final_offset * GET_MODE_SIZE (mode));
+
+ SUBST_INT (SUBREG_BYTE (x), final_offset);
SUBST (SUBREG_REG (x), SUBREG_REG (SUBREG_REG (x)));
}
@@ -3831,10 +3867,10 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
#endif
&& REGNO (SUBREG_REG (x)) != STACK_POINTER_REGNUM)
{
- if (HARD_REGNO_MODE_OK (REGNO (SUBREG_REG (x)) + SUBREG_WORD (x),
- mode))
- return gen_rtx_REG (mode,
- REGNO (SUBREG_REG (x)) + SUBREG_WORD (x));
+ int final_regno = subreg_hard_regno (x, 0);
+
+ if (HARD_REGNO_MODE_OK (final_regno, mode))
+ return gen_rtx_REG (mode, final_regno);
else
return gen_rtx_CLOBBER (mode, const0_rtx);
}
@@ -3849,7 +3885,8 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
&& GET_MODE_SIZE (op0_mode) > UNITS_PER_WORD
&& GET_MODE_CLASS (mode) == MODE_INT)
{
- temp = operand_subword (SUBREG_REG (x), SUBREG_WORD (x),
+ temp = operand_subword (SUBREG_REG (x),
+ (SUBREG_BYTE (x) / UNITS_PER_WORD),
0, op0_mode);
if (temp)
return temp;
@@ -3863,11 +3900,9 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
if (CONSTANT_P (SUBREG_REG (x))
&& ((GET_MODE_SIZE (op0_mode) <= UNITS_PER_WORD
|| ! WORDS_BIG_ENDIAN)
- ? SUBREG_WORD (x) == 0
- : (SUBREG_WORD (x)
- == ((GET_MODE_SIZE (op0_mode)
- - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD))
- / UNITS_PER_WORD)))
+ ? SUBREG_BYTE (x) == 0
+ : (SUBREG_BYTE (x)
+ == (GET_MODE_SIZE (op0_mode) - GET_MODE_SIZE (mode))))
&& GET_MODE_SIZE (mode) <= GET_MODE_SIZE (op0_mode)
&& (! WORDS_BIG_ENDIAN
|| GET_MODE_BITSIZE (op0_mode) <= BITS_PER_WORD))
@@ -3879,8 +3914,9 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
&& GET_MODE_SIZE (mode) > GET_MODE_SIZE (op0_mode))
{
if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) > UNITS_PER_WORD
- && (WORDS_BIG_ENDIAN || SUBREG_WORD (x) != 0))
- return operand_subword (SUBREG_REG (x), SUBREG_WORD (x), 0, mode);
+ && (WORDS_BIG_ENDIAN || SUBREG_BYTE (x) != 0))
+ return constant_subword (SUBREG_REG (x),
+ SUBREG_BYTE (x) / UNITS_PER_WORD, mode);
return SUBREG_REG (x);
}
@@ -5157,14 +5193,14 @@ simplify_set (x)
if (GET_CODE (src) == SUBREG && subreg_lowpart_p (src)
&& LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (src))) != NIL
- && SUBREG_WORD (src) == 0
+ && SUBREG_BYTE (src) == 0
&& (GET_MODE_SIZE (GET_MODE (src))
> GET_MODE_SIZE (GET_MODE (SUBREG_REG (src))))
&& GET_CODE (SUBREG_REG (src)) == MEM)
{
SUBST (SET_SRC (x),
gen_rtx (LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (src))),
- GET_MODE (src), XEXP (src, 0)));
+ GET_MODE (src), SUBREG_REG (src)));
src = SET_SRC (x);
}
@@ -5756,9 +5792,11 @@ expand_field_assignment (x)
if (GET_CODE (SET_DEST (x)) == STRICT_LOW_PART
&& GET_CODE (XEXP (SET_DEST (x), 0)) == SUBREG)
{
+ int byte_offset = SUBREG_BYTE (XEXP (SET_DEST (x), 0));
+
inner = SUBREG_REG (XEXP (SET_DEST (x), 0));
len = GET_MODE_BITSIZE (GET_MODE (XEXP (SET_DEST (x), 0)));
- pos = GEN_INT (BITS_PER_WORD * SUBREG_WORD (XEXP (SET_DEST (x), 0)));
+ pos = GEN_INT (BITS_PER_WORD * (byte_offset / UNITS_PER_WORD));
}
else if (GET_CODE (SET_DEST (x)) == ZERO_EXTRACT
&& GET_CODE (XEXP (SET_DEST (x), 1)) == CONST_INT)
@@ -5996,18 +6034,26 @@ make_extraction (mode, inner, pos, pos_rtx, len,
/* We can't call gen_lowpart_for_combine here since we always want
a SUBREG and it would sometimes return a new hard register. */
if (tmode != inner_mode)
- new = gen_rtx_SUBREG (tmode, inner,
- (WORDS_BIG_ENDIAN
- && (GET_MODE_SIZE (inner_mode)
- > UNITS_PER_WORD)
- ? (((GET_MODE_SIZE (inner_mode)
- - GET_MODE_SIZE (tmode))
- / UNITS_PER_WORD)
- - pos / BITS_PER_WORD)
- : pos / BITS_PER_WORD));
- else
- new = inner;
- }
+ {
+ int final_word = pos / BITS_PER_WORD;
+
+ if (WORDS_BIG_ENDIAN
+ && GET_MODE_SIZE (inner_mode) > UNITS_PER_WORD)
+ final_word = ((GET_MODE_SIZE (inner_mode)
+ - GET_MODE_SIZE (tmode))
+ / UNITS_PER_WORD) - final_word;
+
+ final_word *= UNITS_PER_WORD;
+ if (BYTES_BIG_ENDIAN &&
+ GET_MODE_SIZE (inner_mode) > GET_MODE_SIZE (tmode))
+ final_word += (GET_MODE_SIZE (inner_mode)
+ - GET_MODE_SIZE (tmode)) % UNITS_PER_WORD;
+
+ new = gen_rtx_SUBREG (tmode, inner, final_word);
+ }
+ else
+ new = inner;
+ }
else
new = force_to_mode (inner, tmode,
len >= HOST_BITS_PER_WIDE_INT
@@ -7395,11 +7441,11 @@ if_then_else_cond (x, ptrue, pfalse)
|| GET_CODE (SUBREG_REG (x)) == MEM
|| CONSTANT_P (SUBREG_REG (x)))
&& GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) > UNITS_PER_WORD
- && (WORDS_BIG_ENDIAN || SUBREG_WORD (x) != 0))
+ && (WORDS_BIG_ENDIAN || SUBREG_BYTE (x) >= UNITS_PER_WORD))
{
- true0 = operand_subword (true0, SUBREG_WORD (x), 0,
+ true0 = operand_subword (true0, SUBREG_BYTE (x) / UNITS_PER_WORD, 0,
GET_MODE (SUBREG_REG (x)));
- false0 = operand_subword (false0, SUBREG_WORD (x), 0,
+ false0 = operand_subword (false0, SUBREG_BYTE (x) / UNITS_PER_WORD, 0,
GET_MODE (SUBREG_REG (x)));
}
*ptrue = force_to_mode (true0, mode, ~(HOST_WIDE_INT) 0, NULL_RTX, 0);
@@ -7772,7 +7818,7 @@ apply_distributive_law (x)
case SUBREG:
/* Non-paradoxical SUBREGs distributes over all operations, provided
- the inner modes and word numbers are the same, this is an extraction
+ the inner modes and byte offsets are the same, this is an extraction
of a low-order part, we don't convert an fp operation to int or
vice versa, and we would not be converting a single-word
operation into a multi-word operation. The latter test is not
@@ -7783,7 +7829,7 @@ apply_distributive_law (x)
We produce the result slightly differently in this case. */
if (GET_MODE (SUBREG_REG (lhs)) != GET_MODE (SUBREG_REG (rhs))
- || SUBREG_WORD (lhs) != SUBREG_WORD (rhs)
+ || SUBREG_BYTE (lhs) != SUBREG_BYTE (rhs)
|| ! subreg_lowpart_p (lhs)
|| (GET_MODE_CLASS (GET_MODE (lhs))
!= GET_MODE_CLASS (GET_MODE (SUBREG_REG (lhs))))
@@ -9853,13 +9899,19 @@ gen_lowpart_for_combine (mode, x)
include an explicit SUBREG or we may simplify it further in combine. */
else
{
- int word = 0;
+ int offset = 0;
- if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
- word = ((GET_MODE_SIZE (GET_MODE (x))
- - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD))
- / UNITS_PER_WORD);
- return gen_rtx_SUBREG (mode, x, word);
+ if ((WORDS_BIG_ENDIAN || BYTES_BIG_ENDIAN)
+ && GET_MODE_SIZE (GET_MODE (x)) > GET_MODE_SIZE (mode))
+ {
+ int difference = (GET_MODE_SIZE (GET_MODE (x))
+ - GET_MODE_SIZE (mode));
+ if (WORDS_BIG_ENDIAN)
+ offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
+ if (BYTES_BIG_ENDIAN)
+ offset += difference % UNITS_PER_WORD;
+ }
+ return gen_rtx_SUBREG (mode, x, offset);
}
}
@@ -11927,6 +11979,7 @@ move_deaths (x, maybe_kill_insn, from_cuid, to_insn, pnotes)
that accesses one word of a multi-word item, some
piece of everything register in the expression is used by
this insn, so remove any old death. */
+ /* ??? So why do we test for equality of the sizes? */
if (GET_CODE (dest) == ZERO_EXTRACT
|| GET_CODE (dest) == STRICT_LOW_PART