diff options
author | Jakub Jelinek <jakub@redhat.com> | 2001-04-03 17:06:12 +0200 |
---|---|---|
committer | Andrew Macleod <amacleod@gcc.gnu.org> | 2001-04-03 15:06:12 +0000 |
commit | ddef6bc7a3c885433f0b8a611cdbb4bef0ce4bc3 (patch) | |
tree | 28cfaed9a88de9b20638576026f15f0a1d8b06e6 /gcc/combine.c | |
parent | 924c96ebc4c736cd20d0a36a3973686854e2a152 (diff) | |
download | gcc-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.c | 165 |
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 |