From ddef6bc7a3c885433f0b8a611cdbb4bef0ce4bc3 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 3 Apr 2001 17:06:12 +0200 Subject: [PATCH] Use byte offsets in SUBREGs instead of words. 2001-04-03 Jakub Jelinek David S. Miller Andrew MacLeod 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 Co-Authored-By: David S. Miller From-SVN: r41058 --- gcc/ChangeLog | 212 ++++++++++++ gcc/alias.c | 2 +- gcc/caller-save.c | 26 +- gcc/calls.c | 25 +- gcc/combine.c | 165 ++++++---- gcc/config/a29k/a29k.c | 12 +- gcc/config/alpha/alpha.c | 3 +- gcc/config/arm/arm.c | 12 +- gcc/config/d30v/d30v.c | 19 +- gcc/config/dsp16xx/dsp16xx.md | 4 +- gcc/config/h8300/h8300.md | 4 +- gcc/config/i370/i370.md | 21 +- gcc/config/i860/i860.c | 2 +- gcc/config/i860/i860.md | 16 +- gcc/config/i960/i960.md | 62 ++-- gcc/config/m68hc11/m68hc11.c | 8 +- gcc/config/m68k/m68k.md | 20 +- gcc/config/m88k/m88k.md | 4 +- gcc/config/mips/mips.c | 45 ++- gcc/config/mips/mips.md | 134 ++++---- gcc/config/mn10200/mn10200.c | 9 +- gcc/config/mn10300/mn10300.c | 9 +- gcc/config/ns32k/ns32k.md | 4 +- gcc/config/pa/pa.c | 8 +- gcc/config/pa/pa.md | 8 +- gcc/config/pdp11/pdp11.md | 14 +- gcc/config/romp/romp.c | 7 +- gcc/config/sh/sh.c | 19 +- gcc/config/sh/sh.h | 2 +- gcc/config/sh/sh.md | 8 +- gcc/config/sparc/sparc.c | 4 +- gcc/config/sparc/sparc.h | 37 ++- gcc/config/sparc/sparc.md | 86 +++-- gcc/config/v850/v850.c | 4 +- gcc/cse.c | 41 +-- gcc/dbxout.c | 13 +- gcc/dwarf2out.c | 6 +- gcc/dwarfout.c | 6 +- gcc/emit-rtl.c | 600 +++++++++++++++++++++------------- gcc/expmed.c | 33 +- gcc/expr.c | 8 +- gcc/final.c | 25 +- gcc/flow.c | 11 +- gcc/function.c | 47 ++- gcc/gengenrtl.c | 1 + gcc/global.c | 33 +- gcc/ifcvt.c | 5 +- gcc/integrate.c | 37 ++- gcc/jump.c | 28 +- gcc/local-alloc.c | 38 ++- gcc/recog.c | 150 ++++++--- gcc/reg-stack.c | 6 +- gcc/regmove.c | 4 +- gcc/regs.h | 20 +- gcc/reload.c | 165 +++++++--- gcc/reload1.c | 51 +-- gcc/resource.c | 6 +- gcc/rtl.h | 17 +- gcc/rtl.texi | 21 +- gcc/rtlanal.c | 84 ++++- gcc/sched-vis.c | 2 +- gcc/sdbout.c | 12 +- gcc/stmt.c | 2 +- gcc/tm.texi | 24 +- 64 files changed, 1639 insertions(+), 872 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e42b63a675b9..a63667af04c9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,215 @@ +2001-04-03 Jakub Jelinek + David S. Miller + Andrew MacLeod + + 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. + 2001-04-03 Alexandre Oliva * configure.in (target_subdir): Use target_alias, not target. diff --git a/gcc/alias.c b/gcc/alias.c index a1f2e0b785cd..d69b38392fe6 100644 --- a/gcc/alias.c +++ b/gcc/alias.c @@ -1880,7 +1880,7 @@ nonlocal_mentioned_p (x) { /* Global registers are not local. */ if (REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER - && global_regs[REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)]) + && global_regs[subreg_regno (x)]) return 1; return 0; } diff --git a/gcc/caller-save.c b/gcc/caller-save.c index 787d45c818ef..602159d5eb07 100644 --- a/gcc/caller-save.c +++ b/gcc/caller-save.c @@ -487,18 +487,21 @@ mark_set_regs (reg, setter, data) { register int regno, endregno, i; enum machine_mode mode = GET_MODE (reg); - int word = 0; if (GET_CODE (reg) == SUBREG) { - word = SUBREG_WORD (reg); - reg = SUBREG_REG (reg); - } + rtx inner = SUBREG_REG (reg); + if (GET_CODE (inner) != REG || REGNO (inner) >= FIRST_PSEUDO_REGISTER) + return; - if (GET_CODE (reg) != REG || REGNO (reg) >= FIRST_PSEUDO_REGISTER) + regno = subreg_hard_regno (reg, 1); + } + else if (GET_CODE (reg) == REG + && REGNO (reg) < FIRST_PSEUDO_REGISTER) + regno = REGNO (reg); + else return; - regno = REGNO (reg) + word; endregno = regno + HARD_REGNO_NREGS (regno, mode); for (i = regno; i < endregno; i++) @@ -517,21 +520,24 @@ add_stored_regs (reg, setter, data) { register int regno, endregno, i; enum machine_mode mode = GET_MODE (reg); - int word = 0; + int offset = 0; if (GET_CODE (setter) == CLOBBER) return; - while (GET_CODE (reg) == SUBREG) + if (GET_CODE (reg) == SUBREG && GET_CODE (SUBREG_REG (reg)) == REG) { - word += SUBREG_WORD (reg); + offset = subreg_regno_offset (REGNO (SUBREG_REG (reg)), + GET_MODE (SUBREG_REG (reg)), + SUBREG_BYTE (reg), + GET_MODE (reg)); reg = SUBREG_REG (reg); } if (GET_CODE (reg) != REG || REGNO (reg) >= FIRST_PSEUDO_REGISTER) return; - regno = REGNO (reg) + word; + regno = REGNO (reg) + offset; endregno = regno + HARD_REGNO_NREGS (regno, mode); for (i = regno; i < endregno; i++) diff --git a/gcc/calls.c b/gcc/calls.c index 228d9b8e112f..694eeeee4e60 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -1462,6 +1462,8 @@ precompute_arguments (flags, num_actuals, args) if ((flags & (ECF_CONST | ECF_PURE)) || calls_function (args[i].tree_value, !ACCUMULATE_OUTGOING_ARGS)) { + enum machine_mode mode; + /* If this is an addressable type, we cannot pre-evaluate it. */ if (TREE_ADDRESSABLE (TREE_TYPE (args[i].tree_value))) abort (); @@ -1481,11 +1483,11 @@ precompute_arguments (flags, num_actuals, args) args[i].initial_value = args[i].value = protect_from_queue (args[i].value, 0); - if (TYPE_MODE (TREE_TYPE (args[i].tree_value)) != args[i].mode) + mode = TYPE_MODE (TREE_TYPE (args[i].tree_value)); + if (mode != args[i].mode) { args[i].value - = convert_modes (args[i].mode, - TYPE_MODE (TREE_TYPE (args[i].tree_value)), + = convert_modes (args[i].mode, mode, args[i].value, args[i].unsignedp); #ifdef PROMOTE_FOR_CALL_ONLY /* CSE will replace this only if it contains args[i].value @@ -1495,8 +1497,7 @@ precompute_arguments (flags, num_actuals, args) && GET_MODE_CLASS (args[i].mode) == MODE_INT) { args[i].initial_value - = gen_rtx_SUBREG (TYPE_MODE (TREE_TYPE (args[i].tree_value)), - args[i].value, 0); + = gen_lowpart_SUBREG (mode, args[i].value); SUBREG_PROMOTED_VAR_P (args[i].initial_value) = 1; SUBREG_PROMOTED_UNSIGNED_P (args[i].initial_value) = args[i].unsignedp; @@ -3272,13 +3273,25 @@ expand_call (exp, target, ignore) { tree type = TREE_TYPE (exp); int unsignedp = TREE_UNSIGNED (type); + int offset = 0; /* If we don't promote as expected, something is wrong. */ if (GET_MODE (target) != promote_mode (type, TYPE_MODE (type), &unsignedp, 1)) abort (); - target = gen_rtx_SUBREG (TYPE_MODE (type), target, 0); + if ((WORDS_BIG_ENDIAN || BYTES_BIG_ENDIAN) + && GET_MODE_SIZE (GET_MODE (target)) + > GET_MODE_SIZE (TYPE_MODE (type))) + { + offset = GET_MODE_SIZE (GET_MODE (target)) + - GET_MODE_SIZE (TYPE_MODE (type)); + if (! BYTES_BIG_ENDIAN) + offset = (offset / UNITS_PER_WORD) * UNITS_PER_WORD; + else if (! WORDS_BIG_ENDIAN) + offset %= UNITS_PER_WORD; + } + target = gen_rtx_SUBREG (TYPE_MODE (type), target, offset); SUBREG_PROMOTED_VAR_P (target) = 1; SUBREG_PROMOTED_UNSIGNED_P (target) = unsignedp; } diff --git a/gcc/combine.c b/gcc/combine.c index 4aa7721e8807..ee5631c82636 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 diff --git a/gcc/config/a29k/a29k.c b/gcc/config/a29k/a29k.c index c6d7ba28e4a4..65c6240a3bc6 100644 --- a/gcc/config/a29k/a29k.c +++ b/gcc/config/a29k/a29k.c @@ -262,9 +262,10 @@ gpc_reg_operand (op, mode) regno = REGNO (op); else if (GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == REG) { - regno = REGNO (SUBREG_REG (op)); - if (regno < FIRST_PSEUDO_REGISTER) - regno += SUBREG_WORD (op); + if (REGNO (SUBREG_REG (op)) < FIRST_PSEUDO_REGISTER) + regno = subreg_regno (op); + else + regno = REGNO (SUBREG_REG (op)); } else return 0; @@ -467,7 +468,7 @@ a29k_get_reloaded_address (op) { if (GET_CODE (op) == SUBREG) { - if (SUBREG_WORD (op) != 0) + if (SUBREG_BYTE (op) != 0) abort (); op = SUBREG_REG (op); @@ -1187,7 +1188,8 @@ print_operand (file, x, code) if (GET_MODE (SUBREG_REG (XEXP (x, 0))) == SFmode) fprintf (file, "$float"); else - fprintf (file, "$double%d", SUBREG_WORD (XEXP (x, 0))); + fprintf (file, "$double%d", + (SUBREG_BYTE (XEXP (x, 0)) / GET_MODE_SIZE (GET_MODE (x)))); memcpy ((char *) &u, (char *) &CONST_DOUBLE_LOW (SUBREG_REG (XEXP (x, 0))), sizeof u); fprintf (file, "(%.20e)", u.d); diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c index 18a61d6c7f6e..c6aa2eec7fac 100644 --- a/gcc/config/alpha/alpha.c +++ b/gcc/config/alpha/alpha.c @@ -4098,7 +4098,8 @@ print_operand_address (file, addr) basereg = REGNO (addr); else if (GET_CODE (addr) == SUBREG && GET_CODE (SUBREG_REG (addr)) == REG) - basereg = REGNO (SUBREG_REG (addr)) + SUBREG_WORD (addr); + basereg = REGNO (SUBREG_REG (addr)) + + SUBREG_BYTE (addr) / GET_MODE_SIZE (GET_MODE (addr)); else if (GET_CODE (addr) == CONST_INT) offset = INTVAL (addr); else diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 0f0c5e9d9a31..b89392efad26 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -4748,11 +4748,7 @@ arm_reload_in_hi (operands) if (GET_CODE (ref) == SUBREG) { - offset = SUBREG_WORD (ref) * UNITS_PER_WORD; - if (BYTES_BIG_ENDIAN) - offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (ref))) - - MIN (UNITS_PER_WORD, - GET_MODE_SIZE (GET_MODE (SUBREG_REG (ref))))); + offset = SUBREG_BYTE (ref); ref = SUBREG_REG (ref); } @@ -4865,11 +4861,7 @@ arm_reload_out_hi (operands) if (GET_CODE (ref) == SUBREG) { - offset = SUBREG_WORD (ref) * UNITS_PER_WORD; - if (BYTES_BIG_ENDIAN) - offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (ref))) - - MIN (UNITS_PER_WORD, - GET_MODE_SIZE (GET_MODE (SUBREG_REG (ref))))); + offset = SUBREG_BYTE (ref); ref = SUBREG_REG (ref); } diff --git a/gcc/config/d30v/d30v.c b/gcc/config/d30v/d30v.c index a4f5e8d84737..b8f30aa7c5fc 100644 --- a/gcc/config/d30v/d30v.c +++ b/gcc/config/d30v/d30v.c @@ -2667,10 +2667,13 @@ d30v_split_double (value, p_high, p_low) switch (GET_CODE (value)) { case SUBREG: - offset = SUBREG_WORD (value); - value = SUBREG_REG (value); - if (GET_CODE (value) != REG) + if (GET_CODE (SUBREG_REG (value)) != REG) abort (); + offset = subreg_regno_offset (REGNO (SUBREG_REG (value)), + GET_MODE (SUBREG_REG (value)), + SUBREG_BYTE (value), + GET_MODE (value)); + value = SUBREG_REG (value); /* fall through */ @@ -2795,7 +2798,10 @@ d30v_print_operand_memory_reference (stream, x) if (GET_CODE (x0) == SUBREG) { - offset0 = SUBREG_WORD (x0); + offset0 = subreg_regno_offset (REGNO (SUBREG_REG (x0)), + GET_MODE (SUBREG_REG (x0)), + SUBREG_BYTE (x0), + GET_MODE (x0)); x0 = SUBREG_REG (x0); } @@ -2828,7 +2834,10 @@ d30v_print_operand_memory_reference (stream, x) switch (GET_CODE (x1)) { case SUBREG: - offset1 = SUBREG_WORD (x1); + offset1 = subreg_regno_offset (REGNO (SUBREG_REG (x1)), + GET_MODE (SUBREG_REG (x1)), + SUBREG_BYTE (x1), + GET_MODE (x1)); x1 = SUBREG_REG (x1); if (GET_CODE (x1) != REG) fatal_insn ("Bad insn to d30v_print_operand_memory_reference:", x); diff --git a/gcc/config/dsp16xx/dsp16xx.md b/gcc/config/dsp16xx/dsp16xx.md index ce7fb96b8500..4c65a89bfbe3 100644 --- a/gcc/config/dsp16xx/dsp16xx.md +++ b/gcc/config/dsp16xx/dsp16xx.md @@ -1258,7 +1258,7 @@ " { operands[2] = gen_reg_rtx (HImode); - operands[3] = gen_rtx_SUBREG (QImode, operands[2], 1); + operands[3] = gen_rtx_SUBREG (QImode, operands[2], GET_MODE_SIZE (QImode)); }") ;;(define_insn "extendqihi2" @@ -1308,7 +1308,7 @@ " { operands[2] = gen_reg_rtx (HImode); - operands[3] = gen_rtx_SUBREG (QImode, operands[2], 1); + operands[3] = gen_rtx_SUBREG (QImode, operands[2], GET_MODE_SIZE (QImode)); }") diff --git a/gcc/config/h8300/h8300.md b/gcc/config/h8300/h8300.md index 2ea2463f91b7..d79750aeb23d 100644 --- a/gcc/config/h8300/h8300.md +++ b/gcc/config/h8300/h8300.md @@ -1925,7 +1925,7 @@ (subreg:HI (zero_extract:SI (match_operand:HI 1 "register_operand" "r") (const_int 1) - (match_operand:HI 2 "immediate_operand" "n")) 1))] + (match_operand:HI 2 "immediate_operand" "n")) 2))] "" "sub.w %0,%0\;bld %Z2,%Y1\;bst #0,%X0" [(set_attr "cc" "clobber") @@ -1966,7 +1966,7 @@ (subreg:HI (lshiftrt:SI (match_operand:SI 1 "register_operand" "Ur") - (match_operand:SI 2 "const_int_operand" "n")) 1)) + (match_operand:SI 2 "const_int_operand" "n")) 2)) (const_int 1)))] "INTVAL (operands[2]) < 16" "sub.w %0,%0\;bild %Z2,%Y1\;bst #0,%X0" diff --git a/gcc/config/i370/i370.md b/gcc/config/i370/i370.md index 614e3d6fb6ba..5de8931d21bf 100644 --- a/gcc/config/i370/i370.md +++ b/gcc/config/i370/i370.md @@ -537,12 +537,12 @@ check_label_emit (); emit_insn (gen_rtx_CLOBBER (VOIDmode, reg1)); emit_move_insn (gen_rtx_SUBREG (SImode, reg1, 0), force_operand (XEXP (mem1, 0), NULL_RTX)); - emit_move_insn (gen_rtx_SUBREG (SImode, reg1, 1), len); + emit_move_insn (gen_rtx_SUBREG (SImode, reg1, GET_MODE_SIZE (SImode)), len); emit_insn (gen_rtx_CLOBBER (VOIDmode, reg2)); emit_move_insn (gen_rtx_SUBREG (SImode, reg2, 0), force_operand (XEXP (mem2, 0), NULL_RTX)); - emit_move_insn (gen_rtx_SUBREG (SImode, reg2, 1), len); + emit_move_insn (gen_rtx_SUBREG (SImode, reg2, GET_MODE_SIZE (SImode)), len); /* Compare! */ emit_insn (gen_cmpstrsi_1 (result, reg1, reg2)); @@ -1409,11 +1409,11 @@ check_label_emit (); emit_insn (gen_rtx_CLOBBER (VOIDmode, reg1)); emit_move_insn (gen_rtx_SUBREG (SImode, reg1, 0), force_operand (XEXP (mem1, 0), NULL_RTX)); - emit_move_insn (gen_rtx_SUBREG (SImode, reg1, 1), len); + emit_move_insn (gen_rtx_SUBREG (SImode, reg1, GET_MODE_SIZE (SImode)), len); emit_insn (gen_rtx_CLOBBER (VOIDmode, reg2)); emit_move_insn (gen_rtx_SUBREG (SImode, reg2, 0), zippo); - emit_move_insn (gen_rtx_SUBREG (SImode, reg2, 1), zippo); + emit_move_insn (gen_rtx_SUBREG (SImode, reg2, GET_MODE_SIZE (SImode)), zippo); /* Copy! */ emit_insn (gen_movstrsi_1 (reg1, reg2)); @@ -1476,12 +1476,12 @@ check_label_emit (); emit_insn (gen_rtx_CLOBBER (VOIDmode, reg1)); emit_move_insn (gen_rtx_SUBREG (SImode, reg1, 0), force_operand (XEXP (mem1, 0), NULL_RTX)); - emit_move_insn (gen_rtx_SUBREG (SImode, reg1, 1), len); + emit_move_insn (gen_rtx_SUBREG (SImode, reg1, GET_MODE_SIZE (SImode)), len); emit_insn (gen_rtx_CLOBBER (VOIDmode, reg2)); emit_move_insn (gen_rtx_SUBREG (SImode, reg2, 0), force_operand (XEXP (mem2, 0), NULL_RTX)); - emit_move_insn (gen_rtx_SUBREG (SImode, reg2, 1), len); + emit_move_insn (gen_rtx_SUBREG (SImode, reg2, GET_MODE_SIZE (SImode)), len); /* Copy! */ emit_insn (gen_movstrsi_1 (reg1, reg2)); @@ -2425,11 +2425,12 @@ check_label_emit (); * Dunno how to untwist it elegantly; but it seems to work for now. */ emit_insn (gen_rtx_SET (VOIDmode, - gen_rtx_SUBREG (SImode, r, 1), operands[1])); + gen_rtx_SUBREG (SImode, r, GET_MODE_SIZE (SImode)), + operands[1])); emit_insn (gen_rtx_SET (VOIDmode, r, gen_rtx_MULT (DImode, r, operands[2]))); emit_insn (gen_rtx_SET (VOIDmode, operands[0], - gen_rtx_SUBREG (SImode, r, 1))); + gen_rtx_SUBREG (SImode, r, GET_MODE_SIZE (SImode)))); } DONE; }") @@ -2534,7 +2535,7 @@ check_label_emit (); emit_insn (gen_rtx_SET (VOIDmode, r, gen_rtx_DIV (DImode, r, operands[2]))); emit_insn (gen_rtx_SET (VOIDmode, operands[0], - gen_rtx_SUBREG (SImode, r, 1))); + gen_rtx_SUBREG (SImode, r, GET_MODE_SIZE (SImode)))); DONE; }") @@ -2552,7 +2553,7 @@ check_label_emit (); { rtx dr = gen_reg_rtx (DImode); rtx dr_0 = gen_rtx_SUBREG (SImode, dr, 0); - rtx dr_1 = gen_rtx_SUBREG (SImode, dr, 1); + rtx dr_1 = gen_rtx_SUBREG (SImode, dr, GET_MODE_SIZE (SImode)); if (GET_CODE (operands[2]) == CONST_INT) diff --git a/gcc/config/i860/i860.c b/gcc/config/i860/i860.c index 7cc9d51e22ee..4789f70fe000 100644 --- a/gcc/config/i860/i860.c +++ b/gcc/config/i860/i860.c @@ -340,7 +340,7 @@ single_insn_src_p (op, mode) return 1; case SUBREG: - if (SUBREG_WORD (op) != 0) + if (SUBREG_BYTE (op) != 0) return 0; return single_insn_src_p (SUBREG_REG (op), mode); diff --git a/gcc/config/i860/i860.md b/gcc/config/i860/i860.md index 8cc1fd883f7f..5778964f5bee 100644 --- a/gcc/config/i860/i860.md +++ b/gcc/config/i860/i860.md @@ -1730,12 +1730,12 @@ }") (define_expand "mulsi3_big" - [(set (subreg:SI (match_dup 4) 1) (match_operand:SI 1 "general_operand" "")) - (set (subreg:SI (match_dup 5) 1) (match_operand:SI 2 "general_operand" "")) + [(set (subreg:SI (match_dup 4) 4) (match_operand:SI 1 "general_operand" "")) + (set (subreg:SI (match_dup 5) 4) (match_operand:SI 2 "general_operand" "")) (clobber (match_dup 3)) - (set (subreg:SI (match_dup 3) 1) - (mult:SI (subreg:SI (match_dup 4) 1) (subreg:SI (match_dup 5) 1))) - (set (match_operand:SI 0 "register_operand" "") (subreg:SI (match_dup 3) 1))] + (set (subreg:SI (match_dup 3) 4) + (mult:SI (subreg:SI (match_dup 4) 4) (subreg:SI (match_dup 5) 4))) + (set (match_operand:SI 0 "register_operand" "") (subreg:SI (match_dup 3) 4))] "WORDS_BIG_ENDIAN" " { @@ -1752,9 +1752,9 @@ "fmlow.dd %2,%1,%0") (define_insn "" - [(set (subreg:SI (match_operand:DI 0 "register_operand" "=f") 1) - (mult:SI (subreg:SI (match_operand:DI 1 "register_operand" "f") 1) - (subreg:SI (match_operand:DI 2 "register_operand" "f") 1)))] + [(set (subreg:SI (match_operand:DI 0 "register_operand" "=f") 4) + (mult:SI (subreg:SI (match_operand:DI 1 "register_operand" "f") 4) + (subreg:SI (match_operand:DI 2 "register_operand" "f") 4)))] "WORDS_BIG_ENDIAN" "fmlow.dd %2,%1,%0") diff --git a/gcc/config/i960/i960.md b/gcc/config/i960/i960.md index b7680e103617..424fb87056e4 100644 --- a/gcc/config/i960/i960.md +++ b/gcc/config/i960/i960.md @@ -1211,15 +1211,17 @@ { rtx temp = gen_reg_rtx (SImode); rtx shift_16 = GEN_INT (16); - int op1_subreg_word = 0; + int op1_subreg_byte = 0; if (GET_CODE (operand1) == SUBREG) { - op1_subreg_word = SUBREG_WORD (operand1); + op1_subreg_byte = SUBREG_BYTE (operand1); + op1_subreg_byte /= GET_MODE_SIZE (SImode); + op1_subreg_byte *= GET_MODE_SIZE (SImode); operand1 = SUBREG_REG (operand1); } if (GET_MODE (operand1) != SImode) - operand1 = gen_rtx (SUBREG, SImode, operand1, op1_subreg_word); + operand1 = gen_rtx (SUBREG, SImode, operand1, op1_subreg_byte); emit_insn (gen_ashlsi3 (temp, operand1, shift_16)); emit_insn (gen_ashrsi3 (operand0, temp, shift_16)); @@ -1246,15 +1248,17 @@ { rtx temp = gen_reg_rtx (SImode); rtx shift_24 = GEN_INT (24); - int op1_subreg_word = 0; + int op1_subreg_byte = 0; if (GET_CODE (operand1) == SUBREG) { - op1_subreg_word = SUBREG_WORD (operand1); + op1_subreg_byte = SUBREG_BYTE (operand1); + op1_subreg_byte /= GET_MODE_SIZE (SImode); + op1_subreg_byte *= GET_MODE_SIZE (SImode); operand1 = SUBREG_REG (operand1); } if (GET_MODE (operand1) != SImode) - operand1 = gen_rtx (SUBREG, SImode, operand1, op1_subreg_word); + operand1 = gen_rtx (SUBREG, SImode, operand1, op1_subreg_byte); emit_insn (gen_ashlsi3 (temp, operand1, shift_24)); emit_insn (gen_ashrsi3 (operand0, temp, shift_24)); @@ -1282,24 +1286,28 @@ { rtx temp = gen_reg_rtx (SImode); rtx shift_24 = GEN_INT (24); - int op0_subreg_word = 0; - int op1_subreg_word = 0; + int op0_subreg_byte = 0; + int op1_subreg_byte = 0; if (GET_CODE (operand1) == SUBREG) { - op1_subreg_word = SUBREG_WORD (operand1); + op1_subreg_byte = SUBREG_BYTE (operand1); + op1_subreg_byte /= GET_MODE_SIZE (SImode); + op1_subreg_byte *= GET_MODE_SIZE (SImode); operand1 = SUBREG_REG (operand1); } if (GET_MODE (operand1) != SImode) - operand1 = gen_rtx (SUBREG, SImode, operand1, op1_subreg_word); + operand1 = gen_rtx (SUBREG, SImode, operand1, op1_subreg_byte); if (GET_CODE (operand0) == SUBREG) { - op0_subreg_word = SUBREG_WORD (operand0); + op0_subreg_byte = SUBREG_BYTE (operand0); + op0_subreg_byte /= GET_MODE_SIZE (SImode); + op0_subreg_byte *= GET_MODE_SIZE (SImode); operand0 = SUBREG_REG (operand0); } if (GET_MODE (operand0) != SImode) - operand0 = gen_rtx_SUBREG (SImode, operand0, op0_subreg_word); + operand0 = gen_rtx_SUBREG (SImode, operand0, op0_subreg_byte); emit_insn (gen_ashlsi3 (temp, operand1, shift_24)); emit_insn (gen_ashrsi3 (operand0, temp, shift_24)); @@ -1327,15 +1335,17 @@ { rtx temp = gen_reg_rtx (SImode); rtx shift_16 = GEN_INT (16); - int op1_subreg_word = 0; + int op1_subreg_byte = 0; if (GET_CODE (operand1) == SUBREG) { - op1_subreg_word = SUBREG_WORD (operand1); + op1_subreg_byte = SUBREG_BYTE (operand1); + op1_subreg_byte /= GET_MODE_SIZE (SImode); + op1_subreg_byte *= GET_MODE_SIZE (SImode); operand1 = SUBREG_REG (operand1); } if (GET_MODE (operand1) != SImode) - operand1 = gen_rtx (SUBREG, SImode, operand1, op1_subreg_word); + operand1 = gen_rtx (SUBREG, SImode, operand1, op1_subreg_byte); emit_insn (gen_ashlsi3 (temp, operand1, shift_16)); emit_insn (gen_lshrsi3 (operand0, temp, shift_16)); @@ -1367,15 +1377,17 @@ { rtx temp = gen_reg_rtx (SImode); rtx shift_24 = GEN_INT (24); - int op1_subreg_word = 0; + int op1_subreg_byte = 0; if (GET_CODE (operand1) == SUBREG) { - op1_subreg_word = SUBREG_WORD (operand1); - operand1 = SUBREG_REG (operand1); + op1_subreg_byte = SUBREG_BYTE (operand1); + op1_subreg_byte /= GET_MODE_SIZE (SImode); + op1_subreg_byte *= GET_MODE_SIZE (SImode); + operand1 = SUBREG_REG (operand1); } if (GET_MODE (operand1) != SImode) - operand1 = gen_rtx (SUBREG, SImode, operand1, op1_subreg_word); + operand1 = gen_rtx (SUBREG, SImode, operand1, op1_subreg_byte); emit_insn (gen_ashlsi3 (temp, operand1, shift_24)); emit_insn (gen_lshrsi3 (operand0, temp, shift_24)); @@ -1403,24 +1415,24 @@ { rtx temp = gen_reg_rtx (SImode); rtx shift_24 = GEN_INT (24); - int op0_subreg_word = 0; - int op1_subreg_word = 0; + int op0_subreg_byte = 0; + int op1_subreg_byte = 0; if (GET_CODE (operand1) == SUBREG) { - op1_subreg_word = SUBREG_WORD (operand1); + op1_subreg_byte = SUBREG_BYTE (operand1); operand1 = SUBREG_REG (operand1); } if (GET_MODE (operand1) != SImode) - operand1 = gen_rtx (SUBREG, SImode, operand1, op1_subreg_word); + operand1 = gen_rtx (SUBREG, SImode, operand1, op1_subreg_byte); if (GET_CODE (operand0) == SUBREG) { - op0_subreg_word = SUBREG_WORD (operand0); + op0_subreg_byte = SUBREG_BYTE (operand0); operand0 = SUBREG_REG (operand0); } if (GET_MODE (operand0) != SImode) - operand0 = gen_rtx_SUBREG (SImode, operand0, op0_subreg_word); + operand0 = gen_rtx_SUBREG (SImode, operand0, op0_subreg_byte); emit_insn (gen_ashlsi3 (temp, operand1, shift_24)); emit_insn (gen_lshrsi3 (operand0, temp, shift_24)); diff --git a/gcc/config/m68hc11/m68hc11.c b/gcc/config/m68hc11/m68hc11.c index b1cf541b4c2e..0075c39abc65 100644 --- a/gcc/config/m68hc11/m68hc11.c +++ b/gcc/config/m68hc11/m68hc11.c @@ -1739,12 +1739,12 @@ m68hc11_gen_lowpart (mode, x) return gen_rtx (REG, mode, HARD_B_REGNUM); /* gen_lowpart crashes when it is called with a SUBREG. */ - if (GET_CODE (x) == SUBREG && SUBREG_WORD (x) != 0) + if (GET_CODE (x) == SUBREG && SUBREG_BYTE (x) != 0) { if (mode == SImode) - return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_WORD (x) + 2); + return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 2); else if (mode == HImode) - return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_WORD (x) + 1); + return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 1); else abort (); } @@ -1844,7 +1844,7 @@ m68hc11_gen_highpart (mode, x) } /* gen_highpart crashes when it is called with a SUBREG. */ - if (GET_CODE (x) == SUBREG && SUBREG_WORD (x) != 0) + if (GET_CODE (x) == SUBREG && SUBREG_BYTE (x) != 0) { return gen_rtx (SUBREG, mode, XEXP (x, 0), XEXP (x, 1)); } diff --git a/gcc/config/m68k/m68k.md b/gcc/config/m68k/m68k.md index 1eff7f437234..c74b1424e57f 100644 --- a/gcc/config/m68k/m68k.md +++ b/gcc/config/m68k/m68k.md @@ -1554,7 +1554,7 @@ operands[1] = make_safe_from (operands[1], operands[0]); if (GET_CODE (operands[0]) == SUBREG) operands[2] = gen_rtx_SUBREG (HImode, SUBREG_REG (operands[0]), - SUBREG_WORD (operands[0])); + SUBREG_BYTE (operands[0])); else operands[2] = gen_rtx_SUBREG (HImode, operands[0], 0); }") @@ -1570,7 +1570,7 @@ operands[1] = make_safe_from (operands[1], operands[0]); if (GET_CODE (operands[0]) == SUBREG) operands[2] = gen_rtx_SUBREG (QImode, SUBREG_REG (operands[0]), - SUBREG_WORD (operands[0])); + SUBREG_BYTE (operands[0])); else operands[2] = gen_rtx_SUBREG (QImode, operands[0], 0); }") @@ -1586,7 +1586,7 @@ operands[1] = make_safe_from (operands[1], operands[0]); if (GET_CODE (operands[0]) == SUBREG) operands[2] = gen_rtx_SUBREG (QImode, SUBREG_REG (operands[0]), - SUBREG_WORD (operands[0])); + SUBREG_BYTE (operands[0])); else operands[2] = gen_rtx_SUBREG (QImode, operands[0], 0); }") @@ -3096,7 +3096,7 @@ ;; the high-numbered word of the DImode operand[0] and operand[1]. (define_expand "umulsidi3" [(parallel - [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 1) + [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 4) (mult:SI (match_operand:SI 1 "register_operand" "") (match_operand:SI 2 "nonimmediate_operand" ""))) (set (subreg:SI (match_dup 0) 0) @@ -3135,7 +3135,7 @@ (define_expand "mulsidi3" [(parallel - [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 1) + [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 4) (mult:SI (match_operand:SI 1 "register_operand" "") (match_operand:SI 2 "nonimmediate_operand" ""))) (set (subreg:SI (match_dup 0) 0) @@ -4731,7 +4731,7 @@ (define_insn "subreghi1ashrdi_const32" [(set (match_operand:HI 0 "general_operand" "=rm") (subreg:HI (ashiftrt:DI (match_operand:DI 1 "general_operand" "ro") - (const_int 32)) 1))] + (const_int 32)) 4))] "" "* { @@ -4743,7 +4743,7 @@ (define_insn "subregsi1ashrdi_const32" [(set (match_operand:SI 0 "general_operand" "=rm") (subreg:SI (ashiftrt:DI (match_operand:DI 1 "general_operand" "ro") - (const_int 32)) 1))] + (const_int 32)) 4))] "" "* { @@ -4894,10 +4894,10 @@ ;;(define_insn "" ;; [(set (cc0) ;; (subreg:SI (lshiftrt:DI (match_operand:DI 0 "general_operand" "ro") -;; (const_int 32)) 1)) +;; (const_int 32)) 4)) ;; (set (match_operand:SI 1 "general_operand" "=dm") ;; (subreg:SI (lshiftrt:DI (match_dup 0) -;; (const_int 32)) 1))] +;; (const_int 32)) 4))] ;; "" ;; "* ;;{ @@ -4924,7 +4924,7 @@ (define_insn "subreg1lshrdi_const32" [(set (match_operand:SI 0 "general_operand" "=rm") (subreg:SI (lshiftrt:DI (match_operand:DI 1 "general_operand" "ro") - (const_int 32)) 1))] + (const_int 32)) 4))] "" "* { diff --git a/gcc/config/m88k/m88k.md b/gcc/config/m88k/m88k.md index d8e7a738bcff..7a1ac64ed183 100644 --- a/gcc/config/m88k/m88k.md +++ b/gcc/config/m88k/m88k.md @@ -2295,10 +2295,10 @@ ;;- sign extension instructions (define_expand "extendsidi2" - [(set (subreg:SI (match_operand:DI 0 "register_operand" "=r") 1) + [(set (subreg:SI (match_operand:DI 0 "register_operand" "=r") 4) (match_operand:SI 1 "general_operand" "g")) (set (subreg:SI (match_dup 0) 0) - (ashiftrt:SI (subreg:SI (match_dup 0) 1) + (ashiftrt:SI (subreg:SI (match_dup 0) 4) (const_int 31)))] "" "") diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index e33cb9b65a36..aeccb3fae20e 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -1833,20 +1833,26 @@ mips_move_1word (operands, insn, unsignedp) enum rtx_code code0 = GET_CODE (op0); enum rtx_code code1 = GET_CODE (op1); enum machine_mode mode = GET_MODE (op0); - int subreg_word0 = 0; - int subreg_word1 = 0; + int subreg_offset0 = 0; + int subreg_offset1 = 0; enum delay_type delay = DELAY_NONE; while (code0 == SUBREG) { - subreg_word0 += SUBREG_WORD (op0); + subreg_offset0 += subreg_regno_offset (REGNO (SUBREG_REG (op0)), + GET_MODE (SUBREG_REG (op0)), + SUBREG_BYTE (op0), + GET_MODE (op0)); op0 = SUBREG_REG (op0); code0 = GET_CODE (op0); } while (code1 == SUBREG) { - subreg_word1 += SUBREG_WORD (op1); + subreg_offset1 += subreg_regno_offset (REGNO (SUBREG_REG (op1)), + GET_MODE (SUBREG_REG (op1)), + SUBREG_BYTE (op1), + GET_MODE (op1)); op1 = SUBREG_REG (op1); code1 = GET_CODE (op1); } @@ -1857,11 +1863,11 @@ mips_move_1word (operands, insn, unsignedp) if (code0 == REG) { - int regno0 = REGNO (op0) + subreg_word0; + int regno0 = REGNO (op0) + subreg_offset0; if (code1 == REG) { - int regno1 = REGNO (op1) + subreg_word1; + int regno1 = REGNO (op1) + subreg_offset1; /* Just in case, don't do anything for assigning a register to itself, unless we are filling a delay slot. */ @@ -2146,7 +2152,7 @@ mips_move_1word (operands, insn, unsignedp) if (code1 == REG) { - int regno1 = REGNO (op1) + subreg_word1; + int regno1 = REGNO (op1) + subreg_offset1; if (GP_REG_P (regno1)) { @@ -2225,13 +2231,16 @@ mips_move_2words (operands, insn) rtx op1 = operands[1]; enum rtx_code code0 = GET_CODE (operands[0]); enum rtx_code code1 = GET_CODE (operands[1]); - int subreg_word0 = 0; - int subreg_word1 = 0; + int subreg_offset0 = 0; + int subreg_offset1 = 0; enum delay_type delay = DELAY_NONE; while (code0 == SUBREG) { - subreg_word0 += SUBREG_WORD (op0); + subreg_offset0 += subreg_regno_offset (REGNO (SUBREG_REG (op0)), + GET_MODE (SUBREG_REG (op0)), + SUBREG_BYTE (op0), + GET_MODE (op0)); op0 = SUBREG_REG (op0); code0 = GET_CODE (op0); } @@ -2244,7 +2253,10 @@ mips_move_2words (operands, insn) while (code1 == SUBREG) { - subreg_word1 += SUBREG_WORD (op1); + subreg_offset1 += subreg_regno_offset (REGNO (SUBREG_REG (op1)), + GET_MODE (SUBREG_REG (op1)), + SUBREG_BYTE (op1), + GET_MODE (op1)); op1 = SUBREG_REG (op1); code1 = GET_CODE (op1); } @@ -2262,11 +2274,11 @@ mips_move_2words (operands, insn) if (code0 == REG) { - int regno0 = REGNO (op0) + subreg_word0; + int regno0 = REGNO (op0) + subreg_offset0; if (code1 == REG) { - int regno1 = REGNO (op1) + subreg_word1; + int regno1 = REGNO (op1) + subreg_offset1; /* Just in case, don't do anything for assigning a register to itself, unless we are filling a delay slot. */ @@ -2603,7 +2615,7 @@ mips_move_2words (operands, insn) { if (code1 == REG) { - int regno1 = REGNO (op1) + subreg_word1; + int regno1 = REGNO (op1) + subreg_offset1; if (FP_REG_P (regno1)) ret = "s.d\t%1,%0"; @@ -7888,7 +7900,10 @@ mips_secondary_reload_class (class, mode, x, in_p) { while (GET_CODE (x) == SUBREG) { - off += SUBREG_WORD (x); + off += subreg_regno_offset (REGNO (SUBREG_REG (x)), + GET_MODE (SUBREG_REG (x)), + SUBREG_BYTE (x), + GET_MODE (x)); x = SUBREG_REG (x); } diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md index ceb4f6a2b11a..d7c421327d6b 100644 --- a/gcc/config/mips/mips.md +++ b/gcc/config/mips/mips.md @@ -790,12 +790,12 @@ (ltu:SI (subreg:SI (match_dup 0) 0) (subreg:SI (match_dup 2) 0))) - (set (subreg:SI (match_dup 0) 1) - (plus:SI (subreg:SI (match_dup 1) 1) - (subreg:SI (match_dup 2) 1))) + (set (subreg:SI (match_dup 0) 4) + (plus:SI (subreg:SI (match_dup 1) 4) + (subreg:SI (match_dup 2) 4))) - (set (subreg:SI (match_dup 0) 1) - (plus:SI (subreg:SI (match_dup 0) 1) + (set (subreg:SI (match_dup 0) 4) + (plus:SI (subreg:SI (match_dup 0) 4) (match_dup 3)))] "") @@ -812,13 +812,13 @@ && (REGNO (operands[0]) != REGNO (operands[1]) || REGNO (operands[0]) != REGNO (operands[2]))" - [(set (subreg:SI (match_dup 0) 1) - (plus:SI (subreg:SI (match_dup 1) 1) - (subreg:SI (match_dup 2) 1))) + [(set (subreg:SI (match_dup 0) 4) + (plus:SI (subreg:SI (match_dup 1) 4) + (subreg:SI (match_dup 2) 4))) (set (match_dup 3) - (ltu:SI (subreg:SI (match_dup 0) 1) - (subreg:SI (match_dup 2) 1))) + (ltu:SI (subreg:SI (match_dup 0) 4) + (subreg:SI (match_dup 2) 4))) (set (subreg:SI (match_dup 0) 0) (plus:SI (subreg:SI (match_dup 1) 0) @@ -865,8 +865,8 @@ (ltu:SI (subreg:SI (match_dup 0) 0) (match_dup 2))) - (set (subreg:SI (match_dup 0) 1) - (plus:SI (subreg:SI (match_dup 1) 1) + (set (subreg:SI (match_dup 0) 4) + (plus:SI (subreg:SI (match_dup 1) 4) (match_dup 3)))] "") @@ -881,12 +881,12 @@ && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1])) && INTVAL (operands[2]) > 0" - [(set (subreg:SI (match_dup 0) 1) - (plus:SI (subreg:SI (match_dup 1) 1) + [(set (subreg:SI (match_dup 0) 4) + (plus:SI (subreg:SI (match_dup 1) 4) (match_dup 2))) (set (match_dup 3) - (ltu:SI (subreg:SI (match_dup 0) 1) + (ltu:SI (subreg:SI (match_dup 0) 4) (match_dup 2))) (set (subreg:SI (match_dup 0) 0) @@ -1307,12 +1307,12 @@ (minus:SI (subreg:SI (match_dup 1) 0) (subreg:SI (match_dup 2) 0))) - (set (subreg:SI (match_dup 0) 1) - (minus:SI (subreg:SI (match_dup 1) 1) - (subreg:SI (match_dup 2) 1))) + (set (subreg:SI (match_dup 0) 4) + (minus:SI (subreg:SI (match_dup 1) 4) + (subreg:SI (match_dup 2) 4))) - (set (subreg:SI (match_dup 0) 1) - (minus:SI (subreg:SI (match_dup 0) 1) + (set (subreg:SI (match_dup 0) 4) + (minus:SI (subreg:SI (match_dup 0) 4) (match_dup 3)))] "") @@ -1328,12 +1328,12 @@ && GET_CODE (operands[2]) == REG && GP_REG_P (REGNO (operands[2]))" [(set (match_dup 3) - (ltu:SI (subreg:SI (match_dup 1) 1) - (subreg:SI (match_dup 2) 1))) + (ltu:SI (subreg:SI (match_dup 1) 4) + (subreg:SI (match_dup 2) 4))) - (set (subreg:SI (match_dup 0) 1) - (minus:SI (subreg:SI (match_dup 1) 1) - (subreg:SI (match_dup 2) 1))) + (set (subreg:SI (match_dup 0) 4) + (minus:SI (subreg:SI (match_dup 1) 4) + (subreg:SI (match_dup 2) 4))) (set (subreg:SI (match_dup 0) 0) (minus:SI (subreg:SI (match_dup 1) 0) @@ -1378,8 +1378,8 @@ (minus:SI (subreg:SI (match_dup 1) 0) (match_dup 2))) - (set (subreg:SI (match_dup 0) 1) - (minus:SI (subreg:SI (match_dup 1) 1) + (set (subreg:SI (match_dup 0) 4) + (minus:SI (subreg:SI (match_dup 1) 4) (match_dup 3)))] "") @@ -1395,11 +1395,11 @@ && INTVAL (operands[2]) > 0" [(set (match_dup 3) - (ltu:SI (subreg:SI (match_dup 1) 1) + (ltu:SI (subreg:SI (match_dup 1) 4) (match_dup 2))) - (set (subreg:SI (match_dup 0) 1) - (minus:SI (subreg:SI (match_dup 1) 1) + (set (subreg:SI (match_dup 0) 4) + (minus:SI (subreg:SI (match_dup 1) 4) (match_dup 2))) (set (subreg:SI (match_dup 0) 0) @@ -3121,7 +3121,7 @@ move\\t%0,%z4\\n\\ && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))" [(set (subreg:SI (match_dup 0) 0) (not:SI (subreg:SI (match_dup 1) 0))) - (set (subreg:SI (match_dup 0) 1) (not:SI (subreg:SI (match_dup 1) 1)))] + (set (subreg:SI (match_dup 0) 4) (not:SI (subreg:SI (match_dup 1) 4)))] "") @@ -3224,7 +3224,7 @@ move\\t%0,%z4\\n\\ && GET_CODE (operands[2]) == REG && GP_REG_P (REGNO (operands[2]))" [(set (subreg:SI (match_dup 0) 0) (and:SI (subreg:SI (match_dup 1) 0) (subreg:SI (match_dup 2) 0))) - (set (subreg:SI (match_dup 0) 1) (and:SI (subreg:SI (match_dup 1) 1) (subreg:SI (match_dup 2) 1)))] + (set (subreg:SI (match_dup 0) 4) (and:SI (subreg:SI (match_dup 1) 4) (subreg:SI (match_dup 2) 4)))] "") (define_insn "anddi3_internal1" @@ -3325,7 +3325,7 @@ move\\t%0,%z4\\n\\ && GET_CODE (operands[2]) == REG && GP_REG_P (REGNO (operands[2]))" [(set (subreg:SI (match_dup 0) 0) (ior:SI (subreg:SI (match_dup 1) 0) (subreg:SI (match_dup 2) 0))) - (set (subreg:SI (match_dup 0) 1) (ior:SI (subreg:SI (match_dup 1) 1) (subreg:SI (match_dup 2) 1)))] + (set (subreg:SI (match_dup 0) 4) (ior:SI (subreg:SI (match_dup 1) 4) (subreg:SI (match_dup 2) 4)))] "") (define_expand "xorsi3" @@ -3429,7 +3429,7 @@ move\\t%0,%z4\\n\\ && GET_CODE (operands[2]) == REG && GP_REG_P (REGNO (operands[2]))" [(set (subreg:SI (match_dup 0) 0) (xor:SI (subreg:SI (match_dup 1) 0) (subreg:SI (match_dup 2) 0))) - (set (subreg:SI (match_dup 0) 1) (xor:SI (subreg:SI (match_dup 1) 1) (subreg:SI (match_dup 2) 1)))] + (set (subreg:SI (match_dup 0) 4) (xor:SI (subreg:SI (match_dup 1) 4) (subreg:SI (match_dup 2) 4)))] "") (define_insn "xordi3_immed" @@ -3478,7 +3478,7 @@ move\\t%0,%z4\\n\\ && GET_CODE (operands[2]) == REG && GP_REG_P (REGNO (operands[2]))" [(set (subreg:SI (match_dup 0) 0) (and:SI (not:SI (subreg:SI (match_dup 1) 0)) (not:SI (subreg:SI (match_dup 2) 0)))) - (set (subreg:SI (match_dup 0) 1) (and:SI (not:SI (subreg:SI (match_dup 1) 1)) (not:SI (subreg:SI (match_dup 2) 1))))] + (set (subreg:SI (match_dup 0) 4) (and:SI (not:SI (subreg:SI (match_dup 1) 4)) (not:SI (subreg:SI (match_dup 2) 4))))] "") ;; @@ -4917,7 +4917,7 @@ move\\t%0,%z4\\n\\ && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))" [(set (subreg:SI (match_dup 0) 0) (subreg:SI (match_dup 1) 0)) - (set (subreg:SI (match_dup 0) 1) (subreg:SI (match_dup 1) 1))] + (set (subreg:SI (match_dup 0) 4) (subreg:SI (match_dup 1) 4))] "") (define_insn "movdi_internal2" @@ -6147,7 +6147,7 @@ move\\t%0,%z4\\n\\ && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0])) && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))" [(set (subreg:SI (match_dup 0) 0) (subreg:SI (match_dup 1) 0)) - (set (subreg:SI (match_dup 0) 1) (subreg:SI (match_dup 1) 1))] + (set (subreg:SI (match_dup 0) 4) (subreg:SI (match_dup 1) 4))] "") ;; Instructions to load the global pointer register. @@ -6516,7 +6516,7 @@ move\\t%0,%z4\\n\\ && GET_CODE (operands[1]) == REG && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER && (INTVAL (operands[2]) & 32) != 0" - [(set (subreg:SI (match_dup 0) 1) (ashift:SI (subreg:SI (match_dup 1) 0) (match_dup 2))) + [(set (subreg:SI (match_dup 0) 4) (ashift:SI (subreg:SI (match_dup 1) 0) (match_dup 2))) (set (subreg:SI (match_dup 0) 0) (const_int 0))] "operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);") @@ -6533,8 +6533,8 @@ move\\t%0,%z4\\n\\ && GET_CODE (operands[1]) == REG && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER && (INTVAL (operands[2]) & 32) != 0" - [(set (subreg:SI (match_dup 0) 0) (ashift:SI (subreg:SI (match_dup 1) 1) (match_dup 2))) - (set (subreg:SI (match_dup 0) 1) (const_int 0))] + [(set (subreg:SI (match_dup 0) 0) (ashift:SI (subreg:SI (match_dup 1) 4) (match_dup 2))) + (set (subreg:SI (match_dup 0) 4) (const_int 0))] "operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);") @@ -6574,16 +6574,16 @@ move\\t%0,%z4\\n\\ && (INTVAL (operands[2]) & 63) < 32 && (INTVAL (operands[2]) & 63) != 0" - [(set (subreg:SI (match_dup 0) 1) - (ashift:SI (subreg:SI (match_dup 1) 1) + [(set (subreg:SI (match_dup 0) 4) + (ashift:SI (subreg:SI (match_dup 1) 4) (match_dup 2))) (set (match_dup 3) (lshiftrt:SI (subreg:SI (match_dup 1) 0) (match_dup 4))) - (set (subreg:SI (match_dup 0) 1) - (ior:SI (subreg:SI (match_dup 0) 1) + (set (subreg:SI (match_dup 0) 4) + (ior:SI (subreg:SI (match_dup 0) 4) (match_dup 3))) (set (subreg:SI (match_dup 0) 0) @@ -6614,15 +6614,15 @@ move\\t%0,%z4\\n\\ (match_dup 2))) (set (match_dup 3) - (lshiftrt:SI (subreg:SI (match_dup 1) 1) + (lshiftrt:SI (subreg:SI (match_dup 1) 4) (match_dup 4))) (set (subreg:SI (match_dup 0) 0) (ior:SI (subreg:SI (match_dup 0) 0) (match_dup 3))) - (set (subreg:SI (match_dup 0) 1) - (ashift:SI (subreg:SI (match_dup 1) 1) + (set (subreg:SI (match_dup 0) 4) + (ashift:SI (subreg:SI (match_dup 1) 4) (match_dup 2)))] " { @@ -6871,8 +6871,8 @@ move\\t%0,%z4\\n\\ && GET_CODE (operands[1]) == REG && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER && (INTVAL (operands[2]) & 32) != 0" - [(set (subreg:SI (match_dup 0) 0) (ashiftrt:SI (subreg:SI (match_dup 1) 1) (match_dup 2))) - (set (subreg:SI (match_dup 0) 1) (ashiftrt:SI (subreg:SI (match_dup 1) 1) (const_int 31)))] + [(set (subreg:SI (match_dup 0) 0) (ashiftrt:SI (subreg:SI (match_dup 1) 4) (match_dup 2))) + (set (subreg:SI (match_dup 0) 4) (ashiftrt:SI (subreg:SI (match_dup 1) 4) (const_int 31)))] "operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);") @@ -6887,7 +6887,7 @@ move\\t%0,%z4\\n\\ && GET_CODE (operands[1]) == REG && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER && (INTVAL (operands[2]) & 32) != 0" - [(set (subreg:SI (match_dup 0) 1) (ashiftrt:SI (subreg:SI (match_dup 1) 0) (match_dup 2))) + [(set (subreg:SI (match_dup 0) 4) (ashiftrt:SI (subreg:SI (match_dup 1) 0) (match_dup 2))) (set (subreg:SI (match_dup 0) 0) (ashiftrt:SI (subreg:SI (match_dup 1) 0) (const_int 31)))] "operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);") @@ -6932,15 +6932,15 @@ move\\t%0,%z4\\n\\ (match_dup 2))) (set (match_dup 3) - (ashift:SI (subreg:SI (match_dup 1) 1) + (ashift:SI (subreg:SI (match_dup 1) 4) (match_dup 4))) (set (subreg:SI (match_dup 0) 0) (ior:SI (subreg:SI (match_dup 0) 0) (match_dup 3))) - (set (subreg:SI (match_dup 0) 1) - (ashiftrt:SI (subreg:SI (match_dup 1) 1) + (set (subreg:SI (match_dup 0) 4) + (ashiftrt:SI (subreg:SI (match_dup 1) 4) (match_dup 2)))] " { @@ -6962,16 +6962,16 @@ move\\t%0,%z4\\n\\ && (INTVAL (operands[2]) & 63) < 32 && (INTVAL (operands[2]) & 63) != 0" - [(set (subreg:SI (match_dup 0) 1) - (lshiftrt:SI (subreg:SI (match_dup 1) 1) + [(set (subreg:SI (match_dup 0) 4) + (lshiftrt:SI (subreg:SI (match_dup 1) 4) (match_dup 2))) (set (match_dup 3) (ashift:SI (subreg:SI (match_dup 1) 0) (match_dup 4))) - (set (subreg:SI (match_dup 0) 1) - (ior:SI (subreg:SI (match_dup 0) 1) + (set (subreg:SI (match_dup 0) 4) + (ior:SI (subreg:SI (match_dup 0) 4) (match_dup 3))) (set (subreg:SI (match_dup 0) 0) @@ -7255,8 +7255,8 @@ move\\t%0,%z4\\n\\ && GET_CODE (operands[1]) == REG && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER && (INTVAL (operands[2]) & 32) != 0" - [(set (subreg:SI (match_dup 0) 0) (lshiftrt:SI (subreg:SI (match_dup 1) 1) (match_dup 2))) - (set (subreg:SI (match_dup 0) 1) (const_int 0))] + [(set (subreg:SI (match_dup 0) 0) (lshiftrt:SI (subreg:SI (match_dup 1) 4) (match_dup 2))) + (set (subreg:SI (match_dup 0) 4) (const_int 0))] "operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);") @@ -7272,7 +7272,7 @@ move\\t%0,%z4\\n\\ && GET_CODE (operands[1]) == REG && REGNO (operands[1]) < FIRST_PSEUDO_REGISTER && (INTVAL (operands[2]) & 32) != 0" - [(set (subreg:SI (match_dup 0) 1) (lshiftrt:SI (subreg:SI (match_dup 1) 0) (match_dup 2))) + [(set (subreg:SI (match_dup 0) 4) (lshiftrt:SI (subreg:SI (match_dup 1) 0) (match_dup 2))) (set (subreg:SI (match_dup 0) 0) (const_int 0))] "operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);") @@ -7317,15 +7317,15 @@ move\\t%0,%z4\\n\\ (match_dup 2))) (set (match_dup 3) - (ashift:SI (subreg:SI (match_dup 1) 1) + (ashift:SI (subreg:SI (match_dup 1) 4) (match_dup 4))) (set (subreg:SI (match_dup 0) 0) (ior:SI (subreg:SI (match_dup 0) 0) (match_dup 3))) - (set (subreg:SI (match_dup 0) 1) - (lshiftrt:SI (subreg:SI (match_dup 1) 1) + (set (subreg:SI (match_dup 0) 4) + (lshiftrt:SI (subreg:SI (match_dup 1) 4) (match_dup 2)))] " { @@ -7347,16 +7347,16 @@ move\\t%0,%z4\\n\\ && (INTVAL (operands[2]) & 63) < 32 && (INTVAL (operands[2]) & 63) != 0" - [(set (subreg:SI (match_dup 0) 1) - (lshiftrt:SI (subreg:SI (match_dup 1) 1) + [(set (subreg:SI (match_dup 0) 4) + (lshiftrt:SI (subreg:SI (match_dup 1) 4) (match_dup 2))) (set (match_dup 3) (ashift:SI (subreg:SI (match_dup 1) 0) (match_dup 4))) - (set (subreg:SI (match_dup 0) 1) - (ior:SI (subreg:SI (match_dup 0) 1) + (set (subreg:SI (match_dup 0) 4) + (ior:SI (subreg:SI (match_dup 0) 4) (match_dup 3))) (set (subreg:SI (match_dup 0) 0) diff --git a/gcc/config/mn10200/mn10200.c b/gcc/config/mn10200/mn10200.c index 1e520a84c605..1a4f9dd0f030 100644 --- a/gcc/config/mn10200/mn10200.c +++ b/gcc/config/mn10200/mn10200.c @@ -162,8 +162,7 @@ print_operand (file, x, code) break; case SUBREG: - fprintf (file, "%s", - reg_names[REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)]); + fprintf (file, "%s", reg_names[subreg_regno (x)]); break; case CONST_DOUBLE: @@ -222,8 +221,7 @@ print_operand (file, x, code) break; case SUBREG: - fprintf (file, "%s", - reg_names[REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)] + 1); + fprintf (file, "%s", reg_names[subreg_regno (x) + 1]); break; case CONST_DOUBLE: @@ -322,8 +320,7 @@ print_operand (file, x, code) break; case SUBREG: - fprintf (file, "%s", - reg_names[REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)]); + fprintf (file, "%s", reg_names[subreg_regno (x)]); break; case CONST_INT: diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c index 225c8789994a..7f1c0363587b 100644 --- a/gcc/config/mn10300/mn10300.c +++ b/gcc/config/mn10300/mn10300.c @@ -143,8 +143,7 @@ print_operand (file, x, code) break; case SUBREG: - fprintf (file, "%s", - reg_names[REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)]); + fprintf (file, "%s", reg_names[subreg_regno (x)]); break; case CONST_DOUBLE: @@ -204,8 +203,7 @@ print_operand (file, x, code) break; case SUBREG: - fprintf (file, "%s", - reg_names[REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)] + 1); + fprintf (file, "%s", reg_names[subreg_regno (x) + 1]); break; case CONST_DOUBLE: @@ -289,8 +287,7 @@ print_operand (file, x, code) break; case SUBREG: - fprintf (file, "%s", - reg_names[REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)]); + fprintf (file, "%s", reg_names[subreg_regno (x)]); break; /* This will only be single precision.... */ diff --git a/gcc/config/ns32k/ns32k.md b/gcc/config/ns32k/ns32k.md index 2b811621be73..f7646d391d61 100644 --- a/gcc/config/ns32k/ns32k.md +++ b/gcc/config/ns32k/ns32k.md @@ -1275,7 +1275,7 @@ ;; Retain this insn which *does* have a pattern indicating what it does, ;; just in case the compiler is smart enough to recognize a substitution. (define_insn "udivmoddisi4" - [(set (subreg:SI (match_operand:DI 0 "nonimmediate_operand" "=rm") 1) + [(set (subreg:SI (match_operand:DI 0 "nonimmediate_operand" "=rm") 4) (truncate:SI (udiv:DI (match_operand:DI 1 "nonimmediate_operand" "0") (zero_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm"))))) (set (subreg:SI (match_operand:DI 3 "nonimmediate_operand" "=0") 0) @@ -1338,7 +1338,7 @@ "deiw %2,%0") (define_insn "udivmoddihi4" - [(set (subreg:HI (match_operand:DI 0 "register_operand" "=r") 1) + [(set (subreg:HI (match_operand:DI 0 "register_operand" "=r") 2) (truncate:HI (udiv:DI (match_operand:DI 1 "register_operand" "0") (zero_extend:DI (match_operand:HI 2 "nonimmediate_operand" "rm"))))) (set (subreg:HI (match_operand:DI 3 "register_operand" "=0") 0) diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c index 26e80966c95c..502d204e74da 100644 --- a/gcc/config/pa/pa.c +++ b/gcc/config/pa/pa.c @@ -1192,11 +1192,11 @@ emit_move_sequence (operands, mode, scratch_reg) && GET_CODE (SUBREG_REG (operand0)) == REG && REGNO (SUBREG_REG (operand0)) >= FIRST_PSEUDO_REGISTER) { - /* We must not alter SUBREG_WORD (operand0) since that would confuse + /* We must not alter SUBREG_BYTE (operand0) since that would confuse the code which tracks sets/uses for delete_output_reload. */ rtx temp = gen_rtx_SUBREG (GET_MODE (operand0), reg_equiv_mem [REGNO (SUBREG_REG (operand0))], - SUBREG_WORD (operand0)); + SUBREG_BYTE (operand0)); operand0 = alter_subreg (temp); } @@ -1209,11 +1209,11 @@ emit_move_sequence (operands, mode, scratch_reg) && GET_CODE (SUBREG_REG (operand1)) == REG && REGNO (SUBREG_REG (operand1)) >= FIRST_PSEUDO_REGISTER) { - /* We must not alter SUBREG_WORD (operand0) since that would confuse + /* We must not alter SUBREG_BYTE (operand0) since that would confuse the code which tracks sets/uses for delete_output_reload. */ rtx temp = gen_rtx_SUBREG (GET_MODE (operand1), reg_equiv_mem [REGNO (SUBREG_REG (operand1))], - SUBREG_WORD (operand1)); + SUBREG_BYTE (operand1)); operand1 = alter_subreg (temp); } diff --git a/gcc/config/pa/pa.md b/gcc/config/pa/pa.md index ceea64cfa82f..baeef934243f 100644 --- a/gcc/config/pa/pa.md +++ b/gcc/config/pa/pa.md @@ -3505,9 +3505,9 @@ (set_attr "length" "4")]) (define_expand "floatunssisf2" - [(set (subreg:SI (match_dup 2) 1) + [(set (subreg:SI (match_dup 2) 4) (match_operand:SI 1 "register_operand" "")) - (set (subreg:SI (match_dup 2) 0) + (set (subreg:SI (match_dup 2) 4) (const_int 0)) (set (match_operand:SF 0 "register_operand" "") (float:SF (match_dup 2)))] @@ -3523,7 +3523,7 @@ }") (define_expand "floatunssidf2" - [(set (subreg:SI (match_dup 2) 1) + [(set (subreg:SI (match_dup 2) 4) (match_operand:SI 1 "register_operand" "")) (set (subreg:SI (match_dup 2) 0) (const_int 0)) @@ -3891,7 +3891,7 @@ } emit_insn (gen_rtx_SET (VOIDmode, operands[0], - gen_rtx_SUBREG (SImode, scratch, 1))); + gen_rtx_SUBREG (SImode, scratch, GET_MODE_SIZE (SImode)))); DONE; } operands[3] = gen_reg_rtx (SImode); diff --git a/gcc/config/pdp11/pdp11.md b/gcc/config/pdp11/pdp11.md index 9171a773386f..7fc7f8dc2818 100644 --- a/gcc/config/pdp11/pdp11.md +++ b/gcc/config/pdp11/pdp11.md @@ -766,7 +766,7 @@ (define_expand "zero_extendhisi2" [(set (subreg:HI (match_dup 0) - 1) + 2) (match_operand:HI 1 "register_operand" "r")) (set (subreg:HI (match_operand:SI 0 "register_operand" "=r") @@ -1782,16 +1782,16 @@ [(set_attr "length" "2")]) (define_expand "modhi3" - [(set (subreg:HI (match_dup 1) 1) + [(set (subreg:HI (match_dup 1) 2) (mod:HI (match_operand:SI 1 "general_operand" "0") (match_operand:HI 2 "general_operand" "g"))) (set (match_operand:HI 0 "general_operand" "=r") - (subreg:HI (match_dup 1) 1))] + (subreg:HI (match_dup 1) 2))] "TARGET_45" "") (define_insn "" - [(set (subreg:HI (match_operand:SI 0 "general_operand" "=r") 1) + [(set (subreg:HI (match_operand:SI 0 "general_operand" "=r") 4) (mod:HI (match_operand:SI 1 "general_operand" "0") (match_operand:HI 2 "general_operand" "g")))] "TARGET_45" @@ -1802,11 +1802,11 @@ ; [(parallel [(set (subreg:HI (match_dup 1) 0) ; (div:HI (match_operand:SI 1 "general_operand" "0") ; (match_operand:HI 2 "general_operand" "g"))) -; (set (subreg:HI (match_dup 1) 1) +; (set (subreg:HI (match_dup 1) 2) ; (mod:HI (match_dup 1) ; (match_dup 2)))]) ; (set (match_operand:HI 3 "general_operand" "=r") -; (subreg:HI (match_dup 1) 1)) +; (subreg:HI (match_dup 1) 2)) ; (set (match_operand:HI 0 "general_operand" "=r") ; (subreg:HI (match_dup 1) 0))] ; "TARGET_45" @@ -1816,7 +1816,7 @@ ; [(set (subreg:HI (match_operand:SI 0 "general_operand" "=r") 0) ; (div:HI (match_operand:SI 1 "general_operand" "0") ; (match_operand:HI 2 "general_operand" "g"))) -; (set (subreg:HI (match_dup 0) 1) +; (set (subreg:HI (match_dup 0) 2) ; (mod:HI (match_dup 1) ; (match_dup 2)))] ; "TARGET_45" diff --git a/gcc/config/romp/romp.c b/gcc/config/romp/romp.c index 7aedeb600241..8cabb46e825c 100644 --- a/gcc/config/romp/romp.c +++ b/gcc/config/romp/romp.c @@ -269,12 +269,7 @@ memory_offset_in_range_p (op, mode, low, high) while (GET_CODE (op) == SUBREG) { - offset += SUBREG_WORD (op) * UNITS_PER_WORD; -#if BYTES_BIG_ENDIAN - offset -= (min (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (op))) - - min (UNITS_PER_WORD, - GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))))); -#endif + offset += SUBREG_BYTE (op); op = SUBREG_REG (op); } diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index 4cb5cf27fb0b..d8d4ef3581b4 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -666,7 +666,7 @@ output_movedouble (insn, operands, mode) if (GET_CODE (inside) == REG) ptrreg = REGNO (inside); else if (GET_CODE (inside) == SUBREG) - ptrreg = REGNO (SUBREG_REG (inside)) + SUBREG_WORD (inside); + ptrreg = subreg_regno (inside); else if (GET_CODE (inside) == PLUS) { ptrreg = REGNO (XEXP (inside, 0)); @@ -1143,13 +1143,13 @@ gen_ashift_hi (type, n, reg) gen_ashift_hi is only called in contexts where we know that the sign extension works out correctly. */ { - int word = 0; + int offset = 0; if (GET_CODE (reg) == SUBREG) { - word = SUBREG_WORD (reg); + offset = SUBREG_BYTE (reg); reg = SUBREG_REG (reg); } - gen_ashift (type, n, gen_rtx_SUBREG (SImode, reg, word)); + gen_ashift (type, n, gen_rtx_SUBREG (SImode, reg, offset)); break; } case ASHIFT: @@ -2516,7 +2516,11 @@ regs_used (x, is_dest) break; if (REGNO (y) < 16) return (((1 << HARD_REGNO_NREGS (0, GET_MODE (x))) - 1) - << (REGNO (y) + SUBREG_WORD (x) + is_dest)); + << (REGNO (y) + + subreg_regno_offset (REGNO (y), + GET_MODE (y), + SUBREG_BYTE (x), + GET_MODE (x)) + is_dest)); return 0; } case SET: @@ -3260,7 +3264,10 @@ machine_dependent_reorg (first) mode = HImode; while (GET_CODE (dst) == SUBREG) { - offset += SUBREG_WORD (dst); + offset += subreg_regno_offset (REGNO (SUBREG_REG (dst)), + GET_MODE (SUBREG_REG (dst)), + SUBREG_BYTE (dst), + GET_MODE (dst)); dst = SUBREG_REG (dst); } dst = gen_rtx_REG (HImode, REGNO (dst) + offset); diff --git a/gcc/config/sh/sh.h b/gcc/config/sh/sh.h index 7045148ae291..a71ba3cc7964 100644 --- a/gcc/config/sh/sh.h +++ b/gcc/config/sh/sh.h @@ -1401,7 +1401,7 @@ extern int current_function_anonymous_args; ((GET_CODE (X) == REG && REG_OK_FOR_INDEX_P (X)) \ || (GET_CODE (X) == SUBREG \ && GET_CODE (SUBREG_REG (X)) == REG \ - && SUBREG_OK_FOR_INDEX_P (SUBREG_REG (X), SUBREG_WORD (X)))) + && SUBREG_OK_FOR_INDEX_P (SUBREG_REG (X), SUBREG_BYTE (X)))) /* Jump to LABEL if X is a valid address RTX. This must also take REG_OK_STRICT into account when deciding about valid registers, but it uses diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md index 3a03c2d7b41d..420c33630a8c 100644 --- a/gcc/config/sh/sh.md +++ b/gcc/config/sh/sh.md @@ -2591,7 +2591,7 @@ if (GET_CODE (operands[0]) == REG) regno = REGNO (operands[0]); else if (GET_CODE (operands[0]) == SUBREG) - regno = REGNO (SUBREG_REG (operands[0])) + SUBREG_WORD (operands[0]); + regno = subreg_regno (operands[0]); else if (GET_CODE (operands[0]) == MEM) regno = -1; @@ -2729,7 +2729,7 @@ mem = operands[1]; store_p = 0; } - if (GET_CODE (mem) == SUBREG && SUBREG_WORD (mem) == 0) + if (GET_CODE (mem) == SUBREG && SUBREG_BYTE (mem) == 0) mem = SUBREG_REG (mem); if (GET_CODE (mem) == MEM) { @@ -2751,7 +2751,7 @@ mem = copy_rtx (mem); PUT_MODE (mem, SImode); word0 = alter_subreg (gen_rtx (SUBREG, SImode, regop, 0)); - word1 = alter_subreg (gen_rtx (SUBREG, SImode, regop, 1)); + word1 = alter_subreg (gen_rtx (SUBREG, SImode, regop, 4)); if (store_p || ! refers_to_regno_p (REGNO (word0), REGNO (word0) + 1, addr, 0)) { @@ -2963,7 +2963,7 @@ if (GET_CODE (operands[0]) == REG) regno = REGNO (operands[0]); else if (GET_CODE (operands[0]) == SUBREG) - regno = REGNO (SUBREG_REG (operands[0])) + SUBREG_WORD (operands[0]); + regno = subreg_regno (operands[0]); else if (GET_CODE (operands[0]) == MEM) regno = -1; diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index 9cb4c5ccf09f..782d2a725d34 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -7494,8 +7494,8 @@ ultra_find_type (type_mask, list, start) && GET_CODE (SET_SRC (pat)) == SUBREG && REGNO (SUBREG_REG (SET_DEST (slot_pat))) == REGNO (SUBREG_REG (SET_SRC (pat))) - && SUBREG_WORD (SET_DEST (slot_pat)) == - SUBREG_WORD (SET_SRC (pat))))) + && SUBREG_BYTE (SET_DEST (slot_pat)) == + SUBREG_BYTE (SET_SRC (pat))))) || (check_fpmode_conflict == 1 && GET_CODE (slot_insn) == INSN && GET_CODE (slot_pat) == SET diff --git a/gcc/config/sparc/sparc.h b/gcc/config/sparc/sparc.h index 9e49eadb02da..d65908eb3537 100644 --- a/gcc/config/sparc/sparc.h +++ b/gcc/config/sparc/sparc.h @@ -1146,25 +1146,34 @@ while (0) : (GET_MODE_SIZE (MODE) + 3) / 4) \ : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) -/* A subreg in 64 bit mode will have the wrong offset for a floating point - register. The least significant part is at offset 1, compared to 0 for - integer registers. This only applies when FMODE is a larger mode. - We also need to handle a special case of TF-->DF conversions. */ -#define ALTER_HARD_SUBREG(TMODE, WORD, FMODE, REGNO) \ - (TARGET_ARCH64 \ - && (REGNO) >= SPARC_FIRST_FP_REG \ - && (REGNO) <= SPARC_LAST_V9_FP_REG \ - && (TMODE) == SImode \ - && !((FMODE) == QImode || (FMODE) == HImode) \ - ? ((REGNO) + 1) \ - : ((TMODE) == DFmode && (FMODE) == TFmode) \ - ? ((REGNO) + ((WORD) * 2)) \ - : ((REGNO) + (WORD))) +/* Due to the ARCH64 descrepancy above we must override these + next two macros too. */ +#define REG_SIZE(R) \ + (TARGET_ARCH64 \ + && ((GET_CODE (R) == REG \ + && ((REGNO (R) >= FIRST_PSEUDO_REGISTER \ + && FLOAT_MODE_P (GET_MODE (R))) \ + || (REGNO (R) < FIRST_PSEUDO_REGISTER \ + && REGNO (R) >= 32))) \ + || (GET_CODE (R) == SUBREG \ + && ((REGNO (SUBREG_REG (R)) >= FIRST_PSEUDO_REGISTER \ + && FLOAT_MODE_P (GET_MODE (SUBREG_REG (R)))) \ + || (REGNO (SUBREG_REG (R)) < FIRST_PSEUDO_REGISTER \ + && REGNO (SUBREG_REG (R)) >= 32)))) \ + ? (GET_MODE_SIZE (GET_MODE (R)) + 3) / 4 \ + : (GET_MODE_SIZE (GET_MODE (R)) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + +#define REGMODE_NATURAL_SIZE(MODE) \ + ((TARGET_ARCH64 && FLOAT_MODE_P (MODE)) ? 4 : UNITS_PER_WORD) /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. See sparc.c for how we initialize this. */ extern int *hard_regno_mode_classes; extern int sparc_mode_class[]; + +/* ??? Because of the funny way we pass parameters we should allow certain + ??? types of float/complex values to be in integer registers during + ??? RTL generation. This only matters on arch32. */ #define HARD_REGNO_MODE_OK(REGNO, MODE) \ ((hard_regno_mode_classes[REGNO] & sparc_mode_class[MODE]) != 0) diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md index 8167af887ecd..cf7ae0981965 100644 --- a/gcc/config/sparc/sparc.md +++ b/gcc/config/sparc/sparc.md @@ -4546,15 +4546,17 @@ { rtx temp = gen_reg_rtx (SImode); rtx shift_16 = GEN_INT (16); - int op1_subword = 0; + int op1_subbyte = 0; if (GET_CODE (operand1) == SUBREG) { - op1_subword = SUBREG_WORD (operand1); + op1_subbyte = SUBREG_BYTE (operand1); + op1_subbyte /= GET_MODE_SIZE (SImode); + op1_subbyte *= GET_MODE_SIZE (SImode); operand1 = XEXP (operand1, 0); } - emit_insn (gen_ashlsi3 (temp, gen_rtx_SUBREG (SImode, operand1, op1_subword), + emit_insn (gen_ashlsi3 (temp, gen_rtx_SUBREG (SImode, operand1, op1_subbyte), shift_16)); emit_insn (gen_lshrsi3 (operand0, temp, shift_16)); DONE; @@ -4624,15 +4626,17 @@ { rtx temp = gen_reg_rtx (DImode); rtx shift_48 = GEN_INT (48); - int op1_subword = 0; + int op1_subbyte = 0; if (GET_CODE (operand1) == SUBREG) { - op1_subword = SUBREG_WORD (operand1); + op1_subbyte = SUBREG_BYTE (operand1); + op1_subbyte /= GET_MODE_SIZE (DImode); + op1_subbyte *= GET_MODE_SIZE (DImode); operand1 = XEXP (operand1, 0); } - emit_insn (gen_ashldi3 (temp, gen_rtx_SUBREG (DImode, operand1, op1_subword), + emit_insn (gen_ashldi3 (temp, gen_rtx_SUBREG (DImode, operand1, op1_subbyte), shift_48)); emit_insn (gen_lshrdi3 (operand0, temp, shift_48)); DONE; @@ -4794,7 +4798,7 @@ (define_insn "*cmp_siqi_trunc" [(set (reg:CC 100) - (compare:CC (subreg:QI (match_operand:SI 0 "register_operand" "r") 0) + (compare:CC (subreg:QI (match_operand:SI 0 "register_operand" "r") 3) (const_int 0)))] "" "andcc\\t%0, 0xff, %%g0" @@ -4803,10 +4807,10 @@ (define_insn "*cmp_siqi_trunc_set" [(set (reg:CC 100) - (compare:CC (subreg:QI (match_operand:SI 1 "register_operand" "r") 0) + (compare:CC (subreg:QI (match_operand:SI 1 "register_operand" "r") 3) (const_int 0))) (set (match_operand:QI 0 "register_operand" "=r") - (subreg:QI (match_dup 1) 0))] + (subreg:QI (match_dup 1) 3))] "" "andcc\\t%1, 0xff, %0" [(set_attr "type" "compare") @@ -4814,7 +4818,7 @@ (define_insn "*cmp_diqi_trunc" [(set (reg:CC 100) - (compare:CC (subreg:QI (match_operand:DI 0 "register_operand" "r") 0) + (compare:CC (subreg:QI (match_operand:DI 0 "register_operand" "r") 7) (const_int 0)))] "TARGET_ARCH64" "andcc\\t%0, 0xff, %%g0" @@ -4823,10 +4827,10 @@ (define_insn "*cmp_diqi_trunc_set" [(set (reg:CC 100) - (compare:CC (subreg:QI (match_operand:DI 1 "register_operand" "r") 0) + (compare:CC (subreg:QI (match_operand:DI 1 "register_operand" "r") 7) (const_int 0))) (set (match_operand:QI 0 "register_operand" "=r") - (subreg:QI (match_dup 1) 0))] + (subreg:QI (match_dup 1) 7))] "TARGET_ARCH64" "andcc\\t%1, 0xff, %0" [(set_attr "type" "compare") @@ -4846,15 +4850,17 @@ { rtx temp = gen_reg_rtx (SImode); rtx shift_16 = GEN_INT (16); - int op1_subword = 0; + int op1_subbyte = 0; if (GET_CODE (operand1) == SUBREG) { - op1_subword = SUBREG_WORD (operand1); + op1_subbyte = SUBREG_BYTE (operand1); + op1_subbyte /= GET_MODE_SIZE (SImode); + op1_subbyte *= GET_MODE_SIZE (SImode); operand1 = XEXP (operand1, 0); } - emit_insn (gen_ashlsi3 (temp, gen_rtx_SUBREG (SImode, operand1, op1_subword), + emit_insn (gen_ashlsi3 (temp, gen_rtx_SUBREG (SImode, operand1, op1_subbyte), shift_16)); emit_insn (gen_ashrsi3 (operand0, temp, shift_16)); DONE; @@ -4876,23 +4882,27 @@ { rtx temp = gen_reg_rtx (SImode); rtx shift_24 = GEN_INT (24); - int op1_subword = 0; - int op0_subword = 0; + int op1_subbyte = 0; + int op0_subbyte = 0; if (GET_CODE (operand1) == SUBREG) { - op1_subword = SUBREG_WORD (operand1); + op1_subbyte = SUBREG_BYTE (operand1); + op1_subbyte /= GET_MODE_SIZE (SImode); + op1_subbyte *= GET_MODE_SIZE (SImode); operand1 = XEXP (operand1, 0); } if (GET_CODE (operand0) == SUBREG) { - op0_subword = SUBREG_WORD (operand0); + op0_subbyte = SUBREG_BYTE (operand0); + op0_subbyte /= GET_MODE_SIZE (SImode); + op0_subbyte *= GET_MODE_SIZE (SImode); operand0 = XEXP (operand0, 0); } - emit_insn (gen_ashlsi3 (temp, gen_rtx_SUBREG (SImode, operand1, op1_subword), + emit_insn (gen_ashlsi3 (temp, gen_rtx_SUBREG (SImode, operand1, op1_subbyte), shift_24)); if (GET_MODE (operand0) != SImode) - operand0 = gen_rtx_SUBREG (SImode, operand0, op0_subword); + operand0 = gen_rtx_SUBREG (SImode, operand0, op0_subbyte); emit_insn (gen_ashrsi3 (operand0, temp, shift_24)); DONE; }") @@ -4913,15 +4923,17 @@ { rtx temp = gen_reg_rtx (SImode); rtx shift_24 = GEN_INT (24); - int op1_subword = 0; + int op1_subbyte = 0; if (GET_CODE (operand1) == SUBREG) { - op1_subword = SUBREG_WORD (operand1); + op1_subbyte = SUBREG_BYTE (operand1); + op1_subbyte /= GET_MODE_SIZE (SImode); + op1_subbyte *= GET_MODE_SIZE (SImode); operand1 = XEXP (operand1, 0); } - emit_insn (gen_ashlsi3 (temp, gen_rtx_SUBREG (SImode, operand1, op1_subword), + emit_insn (gen_ashlsi3 (temp, gen_rtx_SUBREG (SImode, operand1, op1_subbyte), shift_24)); emit_insn (gen_ashrsi3 (operand0, temp, shift_24)); DONE; @@ -4943,15 +4955,17 @@ { rtx temp = gen_reg_rtx (DImode); rtx shift_56 = GEN_INT (56); - int op1_subword = 0; + int op1_subbyte = 0; if (GET_CODE (operand1) == SUBREG) { - op1_subword = SUBREG_WORD (operand1); + op1_subbyte = SUBREG_BYTE (operand1); + op1_subbyte /= GET_MODE_SIZE (DImode); + op1_subbyte *= GET_MODE_SIZE (DImode); operand1 = XEXP (operand1, 0); } - emit_insn (gen_ashldi3 (temp, gen_rtx_SUBREG (DImode, operand1, op1_subword), + emit_insn (gen_ashldi3 (temp, gen_rtx_SUBREG (DImode, operand1, op1_subbyte), shift_56)); emit_insn (gen_ashrdi3 (operand0, temp, shift_56)); DONE; @@ -4973,15 +4987,17 @@ { rtx temp = gen_reg_rtx (DImode); rtx shift_48 = GEN_INT (48); - int op1_subword = 0; + int op1_subbyte = 0; if (GET_CODE (operand1) == SUBREG) { - op1_subword = SUBREG_WORD (operand1); + op1_subbyte = SUBREG_BYTE (operand1); + op1_subbyte /= GET_MODE_SIZE (DImode); + op1_subbyte *= GET_MODE_SIZE (DImode); operand1 = XEXP (operand1, 0); } - emit_insn (gen_ashldi3 (temp, gen_rtx_SUBREG (DImode, operand1, op1_subword), + emit_insn (gen_ashldi3 (temp, gen_rtx_SUBREG (DImode, operand1, op1_subbyte), shift_48)); emit_insn (gen_ashrdi3 (operand0, temp, shift_48)); DONE; @@ -6275,7 +6291,7 @@ (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r,r")) (sign_extend:DI (match_operand:SI 2 "register_operand" "r,r"))) (match_operand:SI 3 "const_int_operand" "i,i")) - 1)) + 4)) (clobber (match_scratch:SI 4 "=X,&h"))] "TARGET_V8PLUS" "@ @@ -8346,7 +8362,7 @@ (define_insn "" [(set (match_operand:SI 0 "register_operand" "=r") (ashiftrt:SI (subreg:SI (lshiftrt:DI (match_operand:DI 1 "register_operand" "r") - (const_int 32)) 0) + (const_int 32)) 4) (match_operand:SI 2 "small_int_or_double" "n")))] "TARGET_ARCH64 && ((GET_CODE (operands[2]) == CONST_INT @@ -8366,7 +8382,7 @@ (define_insn "" [(set (match_operand:SI 0 "register_operand" "=r") (lshiftrt:SI (subreg:SI (ashiftrt:DI (match_operand:DI 1 "register_operand" "r") - (const_int 32)) 0) + (const_int 32)) 4) (match_operand:SI 2 "small_int_or_double" "n")))] "TARGET_ARCH64 && ((GET_CODE (operands[2]) == CONST_INT @@ -8386,7 +8402,7 @@ (define_insn "" [(set (match_operand:SI 0 "register_operand" "=r") (ashiftrt:SI (subreg:SI (ashiftrt:DI (match_operand:DI 1 "register_operand" "r") - (match_operand:SI 2 "small_int_or_double" "n")) 0) + (match_operand:SI 2 "small_int_or_double" "n")) 4) (match_operand:SI 3 "small_int_or_double" "n")))] "TARGET_ARCH64 && GET_CODE (operands[2]) == CONST_INT && GET_CODE (operands[3]) == CONST_INT @@ -8405,7 +8421,7 @@ (define_insn "" [(set (match_operand:SI 0 "register_operand" "=r") (lshiftrt:SI (subreg:SI (lshiftrt:DI (match_operand:DI 1 "register_operand" "r") - (match_operand:SI 2 "small_int_or_double" "n")) 0) + (match_operand:SI 2 "small_int_or_double" "n")) 4) (match_operand:SI 3 "small_int_or_double" "n")))] "TARGET_ARCH64 && GET_CODE (operands[2]) == CONST_INT && GET_CODE (operands[3]) == CONST_INT diff --git a/gcc/config/v850/v850.c b/gcc/config/v850/v850.c index 34369d46325d..a074d953604c 100644 --- a/gcc/config/v850/v850.c +++ b/gcc/config/v850/v850.c @@ -541,7 +541,7 @@ print_operand (file, x, code) fputs (reg_names[REGNO (x)], file); break; case SUBREG: - fputs (reg_names[REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)], file); + fputs (reg_names[subreg_regno (x)], file); break; case CONST_INT: case SYMBOL_REF: @@ -823,7 +823,7 @@ output_move_double (operands) if (GET_CODE (inside) == REG) ptrreg = REGNO (inside); else if (GET_CODE (inside) == SUBREG) - ptrreg = REGNO (SUBREG_REG (inside)) + SUBREG_WORD (inside); + ptrreg = subreg_regno (inside); else if (GET_CODE (inside) == PLUS) ptrreg = REGNO (XEXP (inside, 0)); else if (GET_CODE (inside) == LO_SUM) diff --git a/gcc/cse.c b/gcc/cse.c index 38ba919f115a..2b487510eae6 100644 --- a/gcc/cse.c +++ b/gcc/cse.c @@ -1220,11 +1220,11 @@ mention_regs (x) /* If reg_tick has been incremented more than once since reg_in_table was last set, that means that the entire register has been set before, so discard anything memorized - for the entrire register, including all SUBREG expressions. */ + for the entire register, including all SUBREG expressions. */ if (REG_IN_TABLE (i) != REG_TICK (i) - 1) remove_invalid_refs (i); else - remove_invalid_subreg_refs (i, SUBREG_WORD (x), GET_MODE (x)); + remove_invalid_subreg_refs (i, SUBREG_BYTE (x), GET_MODE (x)); } REG_IN_TABLE (i) = REG_TICK (i); @@ -2004,32 +2004,31 @@ remove_invalid_refs (regno) } } -/* Likewise for a subreg with subreg_reg WORD and mode MODE. */ +/* Likewise for a subreg with subreg_reg REGNO, subreg_byte OFFSET, + and mode MODE. */ static void -remove_invalid_subreg_refs (regno, word, mode) +remove_invalid_subreg_refs (regno, offset, mode) unsigned int regno; - unsigned int word; + unsigned int offset; enum machine_mode mode; { unsigned int i; struct table_elt *p, *next; - unsigned int end = word + (GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD; + unsigned int end = offset + (GET_MODE_SIZE (mode) - 1); for (i = 0; i < HASH_SIZE; i++) for (p = table[i]; p; p = next) { - rtx exp; + rtx exp = p->exp; next = p->next_same_hash; - exp = p->exp; - if (GET_CODE (p->exp) != REG + if (GET_CODE (exp) != REG && (GET_CODE (exp) != SUBREG || GET_CODE (SUBREG_REG (exp)) != REG || REGNO (SUBREG_REG (exp)) != regno - || (((SUBREG_WORD (exp) - + (GET_MODE_SIZE (GET_MODE (exp)) - 1) / UNITS_PER_WORD) - >= word) - && SUBREG_WORD (exp) <= end)) + || (((SUBREG_BYTE (exp) + + (GET_MODE_SIZE (GET_MODE (exp)) - 1)) >= offset) + && SUBREG_BYTE (exp) <= end)) && refers_to_regno_p (regno, regno + 1, p->exp, NULL_PTR)) remove_from_table (p, i); } @@ -2302,7 +2301,8 @@ canon_hash (x, mode) if (GET_CODE (SUBREG_REG (x)) == REG) { hash += (((unsigned) SUBREG << 7) - + REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)); + + REGNO (SUBREG_REG (x)) + + (SUBREG_BYTE (x) / UNITS_PER_WORD)); return hash; } break; @@ -3413,7 +3413,8 @@ fold_rtx (x, insn) if (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE_SIZE (mode) == UNITS_PER_WORD && GET_MODE (SUBREG_REG (x)) != VOIDmode) - new = operand_subword (folded_arg0, SUBREG_WORD (x), 0, + new = operand_subword (folded_arg0, + (SUBREG_BYTE (x) / UNITS_PER_WORD), 0, GET_MODE (SUBREG_REG (x))); if (new == 0 && subreg_lowpart_p (x)) new = gen_lowpart_if_possible (mode, folded_arg0); @@ -4393,10 +4394,12 @@ gen_lowpart_if_possible (mode, x) offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD) - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD)); if (BYTES_BIG_ENDIAN) - /* Adjust the address so that the address-after-the-data is - unchanged. */ - offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)) - - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x)))); + { + /* Adjust the address so that the address-after-the-data is + unchanged. */ + offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)) + - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x)))); + } new = gen_rtx_MEM (mode, plus_constant (XEXP (x, 0), offset)); if (! memory_address_p (mode, XEXP (new, 0))) return 0; diff --git a/gcc/dbxout.c b/gcc/dbxout.c index fd9fc0c0284a..207ba2a155dd 100644 --- a/gcc/dbxout.c +++ b/gcc/dbxout.c @@ -2024,20 +2024,15 @@ dbxout_symbol_location (decl, type, suffix, home) else if (GET_CODE (home) == SUBREG) { rtx value = home; - int offset = 0; + while (GET_CODE (value) == SUBREG) - { - offset += SUBREG_WORD (value); - value = SUBREG_REG (value); - } + value = SUBREG_REG (value); if (GET_CODE (value) == REG) { - regno = REGNO (value); - if (regno >= FIRST_PSEUDO_REGISTER) + if (REGNO (value) >= FIRST_PSEUDO_REGISTER) return 0; - regno += offset; } - alter_subreg (home); + regno = REGNO (alter_subreg (home)); } /* The kind-of-variable letter depends on where diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 2e71518fa805..873d0b6d97e2 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -3494,7 +3494,7 @@ is_pseudo_reg (rtl) { return ((GET_CODE (rtl) == REG && REGNO (rtl) >= FIRST_PSEUDO_REGISTER) || (GET_CODE (rtl) == SUBREG - && REGNO (XEXP (rtl, 0)) >= FIRST_PSEUDO_REGISTER)); + && REGNO (SUBREG_REG (rtl)) >= FIRST_PSEUDO_REGISTER)); } /* Return a reference to a type, with its const and volatile qualifiers @@ -7038,7 +7038,7 @@ mem_loc_descriptor (rtl, mode) up an entire register. For now, just assume that it is legitimate to make the Dwarf info refer to the whole register which contains the given subreg. */ - rtl = XEXP (rtl, 0); + rtl = SUBREG_REG (rtl); /* Fall through. */ @@ -7182,7 +7182,7 @@ loc_descriptor (rtl) up an entire register. For now, just assume that it is legitimate to make the Dwarf info refer to the whole register which contains the given subreg. */ - rtl = XEXP (rtl, 0); + rtl = SUBREG_REG (rtl); /* Fall through. */ diff --git a/gcc/dwarfout.c b/gcc/dwarfout.c index 370d14f4d88c..80b06ae17540 100644 --- a/gcc/dwarfout.c +++ b/gcc/dwarfout.c @@ -817,7 +817,7 @@ is_pseudo_reg (rtl) { return (((GET_CODE (rtl) == REG) && (REGNO (rtl) >= FIRST_PSEUDO_REGISTER)) || ((GET_CODE (rtl) == SUBREG) - && (REGNO (XEXP (rtl, 0)) >= FIRST_PSEUDO_REGISTER))); + && (REGNO (SUBREG_REG (rtl)) >= FIRST_PSEUDO_REGISTER))); } inline static tree @@ -1630,7 +1630,7 @@ output_mem_loc_descriptor (rtl) legitimate to make the Dwarf info refer to the whole register which contains the given subreg. */ - rtl = XEXP (rtl, 0); + rtl = SUBREG_REG (rtl); /* Drop thru. */ case REG: @@ -1714,7 +1714,7 @@ output_loc_descriptor (rtl) legitimate to make the Dwarf info refer to the whole register which contains the given subreg. */ - rtl = XEXP (rtl, 0); + rtl = SUBREG_REG (rtl); /* Drop thru. */ case REG: diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index 93f11f43de9d..7b715c6f69dd 100644 --- a/gcc/emit-rtl.c +++ b/gcc/emit-rtl.c @@ -348,6 +348,55 @@ gen_rtx_MEM (mode, addr) return rt; } + +rtx +gen_rtx_SUBREG (mode, reg, offset) + enum machine_mode mode; + rtx reg; + int offset; +{ + /* This is the most common failure type. + Catch it early so we can see who does it. */ + if ((offset % GET_MODE_SIZE (mode)) != 0) + abort (); + + /* This check isn't usable right now because combine will + throw arbitrary crap like a CALL into a SUBREG in + gen_lowpart_for_combine so we must just eat it. */ +#if 0 + /* Check for this too. */ + if (offset >= GET_MODE_SIZE (GET_MODE (reg))) + abort (); +#endif + return gen_rtx_fmt_ei (SUBREG, mode, reg, offset); +} + +/* Generate a SUBREG representing the least-significant part + * of REG if MODE is smaller than mode of REG, otherwise + * paradoxical SUBREG. */ +rtx +gen_lowpart_SUBREG (mode, reg) + enum machine_mode mode; + rtx reg; +{ + enum machine_mode inmode; + int offset; + + inmode = GET_MODE (reg); + if (inmode == VOIDmode) + inmode = mode; + offset = 0; + if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (inmode) + && (WORDS_BIG_ENDIAN || BYTES_BIG_ENDIAN)) + { + offset = GET_MODE_SIZE (inmode) - GET_MODE_SIZE (mode); + if (! BYTES_BIG_ENDIAN) + offset = (offset / UNITS_PER_WORD) * UNITS_PER_WORD; + else if (! WORDS_BIG_ENDIAN) + offset %= UNITS_PER_WORD; + } + return gen_rtx_SUBREG (mode, reg, offset); +} /* rtx gen_rtx (code, mode, [element1, ..., elementn]) ** @@ -650,6 +699,38 @@ get_first_label_num () return first_label_num; } +/* Return the final regno of X, which is a SUBREG of a hard + register. */ +int +subreg_hard_regno (x, check_mode) + register rtx x; + int check_mode; +{ + enum machine_mode mode = GET_MODE (x); + unsigned int byte_offset, base_regno, final_regno; + rtx reg = SUBREG_REG (x); + + /* This is where we attempt to catch illegal subregs + created by the compiler. */ + if (GET_CODE (x) != SUBREG + || GET_CODE (reg) != REG) + abort (); + base_regno = REGNO (reg); + if (base_regno >= FIRST_PSEUDO_REGISTER) + abort (); + if (! HARD_REGNO_MODE_OK (base_regno, GET_MODE (reg))) + abort (); + + /* Catch non-congruent offsets too. */ + byte_offset = SUBREG_BYTE (x); + if ((byte_offset % GET_MODE_SIZE (mode)) != 0) + abort (); + + final_regno = subreg_regno (x); + + return final_regno; +} + /* Return a value representing some low-order bits of X, where the number of low-order bits is given by MODE. Note that no conversion is done between floating-point and fixed-point values, rather, the bit @@ -666,22 +747,29 @@ gen_lowpart_common (mode, x) enum machine_mode mode; register rtx x; { - int word = 0; + int msize = GET_MODE_SIZE (mode); + int xsize = GET_MODE_SIZE (GET_MODE (x)); + int offset = 0; if (GET_MODE (x) == mode) return x; /* MODE must occupy no more words than the mode of X. */ if (GET_MODE (x) != VOIDmode - && ((GET_MODE_SIZE (mode) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD - > ((GET_MODE_SIZE (GET_MODE (x)) + (UNITS_PER_WORD - 1)) - / UNITS_PER_WORD))) + && ((msize + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD + > ((xsize + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD))) return 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); + if ((WORDS_BIG_ENDIAN || BYTES_BIG_ENDIAN) + && xsize > msize) + { + int difference = xsize - msize; + + if (WORDS_BIG_ENDIAN) + offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD; + if (BYTES_BIG_ENDIAN) + offset += difference % UNITS_PER_WORD; + } if ((GET_CODE (x) == ZERO_EXTEND || GET_CODE (x) == SIGN_EXTEND) && (GET_MODE_CLASS (mode) == MODE_INT @@ -703,39 +791,40 @@ gen_lowpart_common (mode, x) return gen_rtx_fmt_e (GET_CODE (x), mode, XEXP (x, 0)); } else if (GET_CODE (x) == SUBREG - && (GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) - || GET_MODE_SIZE (mode) <= UNITS_PER_WORD + && (GET_MODE_SIZE (mode) <= UNITS_PER_WORD || GET_MODE_SIZE (mode) == GET_MODE_UNIT_SIZE (GET_MODE (x)))) - return (GET_MODE (SUBREG_REG (x)) == mode && SUBREG_WORD (x) == 0 - ? SUBREG_REG (x) - : gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_WORD (x) + word)); + { + int final_offset; + + if (GET_MODE (SUBREG_REG (x)) == mode && subreg_lowpart_p (x)) + return SUBREG_REG (x); + + /* When working with SUBREGs the rule is that the byte + offset must be a multiple of the SUBREG's mode. */ + final_offset = SUBREG_BYTE (x) + offset; + final_offset = (final_offset / GET_MODE_SIZE (mode)); + final_offset = (final_offset * GET_MODE_SIZE (mode)); + return gen_rtx_SUBREG (mode, SUBREG_REG (x), final_offset); + } else if (GET_CODE (x) == REG) { - /* Let the backend decide how many registers to skip. This is needed - in particular for Sparc64 where fp regs are smaller than a word. */ - /* ??? Note that subregs are now ambiguous, in that those against - pseudos are sized by the Word Size, while those against hard - regs are sized by the underlying register size. Better would be - to always interpret the subreg offset parameter as bytes or bits. */ - - if (WORDS_BIG_ENDIAN && REGNO (x) < FIRST_PSEUDO_REGISTER - && GET_MODE_SIZE (GET_MODE (x)) > GET_MODE_SIZE (mode)) - word = (HARD_REGNO_NREGS (REGNO (x), GET_MODE (x)) - - HARD_REGNO_NREGS (REGNO (x), mode)); - - /* If the register is not valid for MODE, return 0. If we don't - do this, there is no way to fix up the resulting REG later. - But we do do this if the current REG is not valid for its - mode. This latter is a kludge, but is required due to the - way that parameters are passed on some machines, most - notably Sparc. */ - if (REGNO (x) < FIRST_PSEUDO_REGISTER - && ! HARD_REGNO_MODE_OK (REGNO (x) + word, mode) - && HARD_REGNO_MODE_OK (REGNO (x), GET_MODE (x))) - return 0; - else if (REGNO (x) < FIRST_PSEUDO_REGISTER + /* Hard registers are done specially in certain cases. */ + if (REGNO (x) < FIRST_PSEUDO_REGISTER) + { + int final_regno = REGNO (x) + + subreg_regno_offset (REGNO (x), GET_MODE (x), + offset, mode); + + /* If the final regno is not valid for MODE, punt. */ + /* ??? We do allow it if the current REG is not valid for + ??? it's mode. It is a kludge to work around how float/complex + ??? arguments are passed on 32-bit Sparc and should be fixed. */ + if (! HARD_REGNO_MODE_OK (final_regno, mode) + && HARD_REGNO_MODE_OK (REGNO (x), GET_MODE (x))) + return 0; + /* integrate.c can't handle parts of a return value register. */ - && (! REG_FUNCTION_VALUE_P (x) + if ((! REG_FUNCTION_VALUE_P (x) || ! rtx_equal_function_value_matters) #ifdef CLASS_CANNOT_CHANGE_MODE && ! (CLASS_CANNOT_CHANGE_MODE_P (mode, GET_MODE (x)) @@ -752,9 +841,9 @@ gen_lowpart_common (mode, x) && x != arg_pointer_rtx #endif && x != stack_pointer_rtx) - return gen_rtx_REG (mode, REGNO (x) + word); - else - return gen_rtx_SUBREG (mode, x, word); + return gen_rtx_REG (mode, final_regno); + } + return gen_rtx_SUBREG (mode, x, offset); } /* If X is a CONST_INT or a CONST_DOUBLE, extract the appropriate bits from the low-order part of the constant. */ @@ -847,7 +936,7 @@ gen_lowpart_common (mode, x) && GET_CODE (x) == CONST_DOUBLE && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT && GET_MODE_BITSIZE (mode) == BITS_PER_WORD) - return operand_subword (x, word, 0, GET_MODE (x)); + return constant_subword (x, (offset / UNITS_PER_WORD), GET_MODE (x)); /* Similarly, if this is converting a floating-point value into a two-word integer, we can do this one word at a time and make an @@ -863,11 +952,14 @@ gen_lowpart_common (mode, x) && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT && GET_MODE_BITSIZE (mode) == 2 * BITS_PER_WORD) { - rtx lowpart - = operand_subword (x, word + WORDS_BIG_ENDIAN, 0, GET_MODE (x)); - rtx highpart - = operand_subword (x, word + ! WORDS_BIG_ENDIAN, 0, GET_MODE (x)); - + rtx lowpart, highpart; + + lowpart = constant_subword (x, + (offset / UNITS_PER_WORD) + WORDS_BIG_ENDIAN, + GET_MODE (x)); + highpart = constant_subword (x, + (offset / UNITS_PER_WORD) + (! WORDS_BIG_ENDIAN), + GET_MODE (x)); if (lowpart && GET_CODE (lowpart) == CONST_INT && highpart && GET_CODE (highpart) == CONST_INT) return immed_double_const (INTVAL (lowpart), INTVAL (highpart), mode); @@ -1021,7 +1113,7 @@ gen_imagpart (mode, x) return XEXP (x, 1); else if (WORDS_BIG_ENDIAN) return gen_lowpart (mode, x); - else if (!WORDS_BIG_ENDIAN + else if (! WORDS_BIG_ENDIAN && GET_MODE_BITSIZE (mode) < BITS_PER_WORD && REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER) @@ -1043,7 +1135,7 @@ subreg_realpart_p (x) if (GET_CODE (x) != SUBREG) abort (); - return ((unsigned int) SUBREG_WORD (x) * UNITS_PER_WORD + return ((unsigned int) SUBREG_BYTE (x) < GET_MODE_UNIT_SIZE (GET_MODE (SUBREG_REG (x)))); } @@ -1101,10 +1193,13 @@ gen_highpart (mode, x) enum machine_mode mode; register rtx x; { + unsigned int msize = GET_MODE_SIZE (mode); + unsigned int xsize = GET_MODE_SIZE (GET_MODE (x)); + /* This case loses if X is a subreg. To catch bugs early, complain if an invalid MODE is used even in other cases. */ - if (GET_MODE_SIZE (mode) > UNITS_PER_WORD - && GET_MODE_SIZE (mode) != GET_MODE_UNIT_SIZE (GET_MODE (x))) + if (msize > UNITS_PER_WORD + && msize != GET_MODE_UNIT_SIZE (GET_MODE (x))) abort (); if (GET_CODE (x) == CONST_DOUBLE #if !(TARGET_FLOAT_FORMAT != HOST_FLOAT_FORMAT || defined (REAL_IS_NOT_DOUBLE)) @@ -1121,15 +1216,14 @@ gen_highpart (mode, x) else if (GET_CODE (x) == MEM) { register int offset = 0; + if (! WORDS_BIG_ENDIAN) - offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD) - - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD)); + offset = (MAX (xsize, UNITS_PER_WORD) + - MAX (msize, UNITS_PER_WORD)); if (! BYTES_BIG_ENDIAN - && GET_MODE_SIZE (mode) < UNITS_PER_WORD) - offset -= (GET_MODE_SIZE (mode) - - MIN (UNITS_PER_WORD, - GET_MODE_SIZE (GET_MODE (x)))); + && msize < UNITS_PER_WORD) + offset -= (msize - MIN (UNITS_PER_WORD, xsize)); return change_address (x, mode, plus_constant (XEXP (x, 0), offset)); } @@ -1138,46 +1232,47 @@ gen_highpart (mode, x) /* The only time this should occur is when we are looking at a multi-word item with a SUBREG whose mode is the same as that of the item. It isn't clear what we would do if it wasn't. */ - if (SUBREG_WORD (x) != 0) + if (SUBREG_BYTE (x) != 0) abort (); return gen_highpart (mode, SUBREG_REG (x)); } else if (GET_CODE (x) == REG) { - int word; - - /* Let the backend decide how many registers to skip. This is needed - in particular for sparc64 where fp regs are smaller than a word. */ - /* ??? Note that subregs are now ambiguous, in that those against - pseudos are sized by the word size, while those against hard - regs are sized by the underlying register size. Better would be - to always interpret the subreg offset parameter as bytes or bits. */ + int offset = 0; if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (mode)) abort (); - else if (WORDS_BIG_ENDIAN) - word = 0; - else if (REGNO (x) < FIRST_PSEUDO_REGISTER) - word = (HARD_REGNO_NREGS (REGNO (x), GET_MODE (x)) - - HARD_REGNO_NREGS (REGNO (x), mode)); - else - word = ((GET_MODE_SIZE (GET_MODE (x)) - - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD)) - / UNITS_PER_WORD); - - if (REGNO (x) < FIRST_PSEUDO_REGISTER - /* integrate.c can't handle parts of a return value register. */ - && (! REG_FUNCTION_VALUE_P (x) - || ! rtx_equal_function_value_matters) + + if ((! WORDS_BIG_ENDIAN || ! BYTES_BIG_ENDIAN) + && xsize > msize) + { + int difference = xsize - msize; + + if (! WORDS_BIG_ENDIAN) + offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD; + if (! BYTES_BIG_ENDIAN) + offset += difference % UNITS_PER_WORD; + } + if (REGNO (x) < FIRST_PSEUDO_REGISTER) + { + int final_regno = REGNO (x) + + subreg_regno_offset (REGNO (x), GET_MODE (x), offset, mode); + + /* integrate.c can't handle parts of a return value register. + ??? Then integrate.c should be fixed! + ??? What about CLASS_CANNOT_CHANGE_SIZE? */ + if ((! REG_FUNCTION_VALUE_P (x) + || ! rtx_equal_function_value_matters) /* We want to keep the stack, frame, and arg pointers special. */ - && x != frame_pointer_rtx -#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM - && x != arg_pointer_rtx + && x != frame_pointer_rtx +#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM + && x != arg_pointer_rtx #endif - && x != stack_pointer_rtx) - return gen_rtx_REG (mode, REGNO (x) + word); - else - return gen_rtx_SUBREG (mode, x, word); + && x != stack_pointer_rtx) + return gen_rtx_REG (mode, final_regno); + } + /* Just generate a normal SUBREG. */ + return gen_rtx_SUBREG (mode, x, offset); } else abort (); @@ -1191,154 +1286,44 @@ int subreg_lowpart_p (x) rtx x; { + unsigned int offset = 0; + int difference = (GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) + - GET_MODE_SIZE (GET_MODE (x))); + if (GET_CODE (x) != SUBREG) return 1; else if (GET_MODE (SUBREG_REG (x)) == VOIDmode) return 0; - if (WORDS_BIG_ENDIAN - && GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) > UNITS_PER_WORD) - return (SUBREG_WORD (x) - == ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) - - MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD)) - / UNITS_PER_WORD)); + if (difference > 0) + { + if (WORDS_BIG_ENDIAN) + offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD; + if (BYTES_BIG_ENDIAN) + offset += difference % UNITS_PER_WORD; + } - return SUBREG_WORD (x) == 0; + return SUBREG_BYTE (x) == offset; } -/* Return subword I of operand OP. - The word number, I, is interpreted as the word number starting at the - low-order address. Word 0 is the low-order word if not WORDS_BIG_ENDIAN, - otherwise it is the high-order word. - - If we cannot extract the required word, we return zero. Otherwise, an - rtx corresponding to the requested word will be returned. - VALIDATE_ADDRESS is nonzero if the address should be validated. Before - reload has completed, a valid address will always be returned. After - reload, if a valid address cannot be returned, we return zero. - - If VALIDATE_ADDRESS is zero, we simply form the required address; validating - it is the responsibility of the caller. - - MODE is the mode of OP in case it is a CONST_INT. */ +/* Helper routine for all the constant cases of operand_subword. + Some places invoke this directly. */ rtx -operand_subword (op, i, validate_address, mode) +constant_subword (op, offset, mode) rtx op; - unsigned int i; - int validate_address; + int offset; enum machine_mode mode; { - HOST_WIDE_INT val; int size_ratio = HOST_BITS_PER_WIDE_INT / BITS_PER_WORD; - - if (mode == VOIDmode) - mode = GET_MODE (op); - - if (mode == VOIDmode) - abort (); - - /* If OP is narrower than a word, fail. */ - if (mode != BLKmode - && (GET_MODE_SIZE (mode) < UNITS_PER_WORD)) - return 0; - - /* If we want a word outside OP, return zero. */ - if (mode != BLKmode - && (i + 1) * UNITS_PER_WORD > GET_MODE_SIZE (mode)) - return const0_rtx; + HOST_WIDE_INT val; /* If OP is already an integer word, return it. */ if (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE_SIZE (mode) == UNITS_PER_WORD) return op; - /* If OP is a REG or SUBREG, we can handle it very simply. */ - if (GET_CODE (op) == REG) - { - /* ??? There is a potential problem with this code. It does not - properly handle extractions of a subword from a hard register - that is larger than word_mode. Presumably the check for - HARD_REGNO_MODE_OK catches these most of these cases. */ - - /* If OP is a hard register, but OP + I is not a hard register, - then extracting a subword is impossible. - - For example, consider if OP is the last hard register and it is - larger than word_mode. If we wanted word N (for N > 0) because a - part of that hard register was known to contain a useful value, - then OP + I would refer to a pseudo, not the hard register we - actually wanted. */ - if (REGNO (op) < FIRST_PSEUDO_REGISTER - && REGNO (op) + i >= FIRST_PSEUDO_REGISTER) - return 0; - - /* If the register is not valid for MODE, return 0. Note we - have to check both OP and OP + I since they may refer to - different parts of the register file. - - Consider if OP refers to the last 96bit FP register and we want - subword 3 because that subword is known to contain a value we - needed. */ - if (REGNO (op) < FIRST_PSEUDO_REGISTER - && (! HARD_REGNO_MODE_OK (REGNO (op), word_mode) - || ! HARD_REGNO_MODE_OK (REGNO (op) + i, word_mode))) - return 0; - else if (REGNO (op) >= FIRST_PSEUDO_REGISTER - || (REG_FUNCTION_VALUE_P (op) - && rtx_equal_function_value_matters) - /* We want to keep the stack, frame, and arg pointers - special. */ - || op == frame_pointer_rtx -#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM - || op == arg_pointer_rtx -#endif - || op == stack_pointer_rtx) - return gen_rtx_SUBREG (word_mode, op, i); - else - return gen_rtx_REG (word_mode, REGNO (op) + i); - } - else if (GET_CODE (op) == SUBREG) - return gen_rtx_SUBREG (word_mode, SUBREG_REG (op), i + SUBREG_WORD (op)); - else if (GET_CODE (op) == CONCAT) - { - unsigned int partwords - = GET_MODE_UNIT_SIZE (GET_MODE (op)) / UNITS_PER_WORD; - - if (i < partwords) - return operand_subword (XEXP (op, 0), i, validate_address, mode); - return operand_subword (XEXP (op, 1), i - partwords, - validate_address, mode); - } - - /* Form a new MEM at the requested address. */ - if (GET_CODE (op) == MEM) - { - rtx addr = plus_constant (XEXP (op, 0), i * UNITS_PER_WORD); - rtx new; - - if (validate_address) - { - if (reload_completed) - { - if (! strict_memory_address_p (word_mode, addr)) - return 0; - } - else - addr = memory_address (word_mode, addr); - } - - new = gen_rtx_MEM (word_mode, addr); - MEM_COPY_ATTRIBUTES (new, op); - return new; - } - - /* The only remaining cases are when OP is a constant. If the host and - target floating formats are the same, handling two-word floating - constants are easy. Note that REAL_VALUE_TO_TARGET_{SINGLE,DOUBLE} - are defined as returning one or two 32 bit values, respectively, - and not values of BITS_PER_WORD bits. */ #ifdef REAL_ARITHMETIC /* The output is some bits, the width of the target machine's word. A wider-word host can surely hold them in a CONST_INT. A narrower-word @@ -1365,12 +1350,12 @@ operand_subword (op, i, validate_address, mode) So we explicitly mask and sign-extend as necessary. */ if (BITS_PER_WORD == 32) { - val = k[i]; + val = k[offset]; val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000; return GEN_INT (val); } #if HOST_BITS_PER_WIDE_INT >= 64 - else if (BITS_PER_WORD >= 64 && i == 0) + else if (BITS_PER_WORD >= 64 && offset == 0) { val = k[! WORDS_BIG_ENDIAN]; val = (((val & 0xffffffff) ^ 0x80000000) - 0x80000000) << 32; @@ -1380,8 +1365,8 @@ operand_subword (op, i, validate_address, mode) #endif else if (BITS_PER_WORD == 16) { - val = k[i >> 1]; - if ((i & 1) == !WORDS_BIG_ENDIAN) + val = k[offset >> 1]; + if ((offset & 1) == ! WORDS_BIG_ENDIAN) val >>= 16; val &= 0xffff; return GEN_INT (val); @@ -1402,16 +1387,16 @@ operand_subword (op, i, validate_address, mode) if (BITS_PER_WORD == 32) { - val = k[i]; + val = k[offset]; val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000; return GEN_INT (val); } #if HOST_BITS_PER_WIDE_INT >= 64 - else if (BITS_PER_WORD >= 64 && i <= 1) + else if (BITS_PER_WORD >= 64 && offset <= 1) { - val = k[i*2 + ! WORDS_BIG_ENDIAN]; + val = k[offset * 2 + ! WORDS_BIG_ENDIAN]; val = (((val & 0xffffffff) ^ 0x80000000) - 0x80000000) << 32; - val |= (HOST_WIDE_INT) k[i*2 + WORDS_BIG_ENDIAN] & 0xffffffff; + val |= (HOST_WIDE_INT) k[offset * 2 + WORDS_BIG_ENDIAN] & 0xffffffff; return GEN_INT (val); } #endif @@ -1431,10 +1416,10 @@ operand_subword (op, i, validate_address, mode) compilers don't like a conditional inside macro args, so we have two copies of the return. */ #ifdef HOST_WORDS_BIG_ENDIAN - return GEN_INT (i == WORDS_BIG_ENDIAN + return GEN_INT (offset == WORDS_BIG_ENDIAN ? CONST_DOUBLE_HIGH (op) : CONST_DOUBLE_LOW (op)); #else - return GEN_INT (i != WORDS_BIG_ENDIAN + return GEN_INT (offset != WORDS_BIG_ENDIAN ? CONST_DOUBLE_HIGH (op) : CONST_DOUBLE_LOW (op)); #endif } @@ -1460,7 +1445,7 @@ operand_subword (op, i, validate_address, mode) if (BITS_PER_WORD == 16) { - if ((i & 1) == !WORDS_BIG_ENDIAN) + if ((offset & 1) == ! WORDS_BIG_ENDIAN) val >>= 16; val &= 0xffff; } @@ -1504,7 +1489,7 @@ operand_subword (op, i, validate_address, mode) /* The only remaining cases that we can handle are integers. Convert to proper endianness now since these cases need it. - At this point, i == 0 means the low-order word. + At this point, offset == 0 means the low-order word. We do not want to handle the case when BITS_PER_WORD <= HOST_BITS_PER_INT in general. However, if OP is (const_int 0), we can just return @@ -1519,39 +1504,184 @@ operand_subword (op, i, validate_address, mode) return 0; if (WORDS_BIG_ENDIAN) - i = GET_MODE_SIZE (mode) / UNITS_PER_WORD - 1 - i; + offset = GET_MODE_SIZE (mode) / UNITS_PER_WORD - 1 - offset; /* Find out which word on the host machine this value is in and get it from the constant. */ - val = (i / size_ratio == 0 + val = (offset / size_ratio == 0 ? (GET_CODE (op) == CONST_INT ? INTVAL (op) : CONST_DOUBLE_LOW (op)) : (GET_CODE (op) == CONST_INT ? (INTVAL (op) < 0 ? ~0 : 0) : CONST_DOUBLE_HIGH (op))); /* Get the value we want into the low bits of val. */ if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT) - val = ((val >> ((i % size_ratio) * BITS_PER_WORD))); + val = ((val >> ((offset % size_ratio) * BITS_PER_WORD))); val = trunc_int_for_mode (val, word_mode); return GEN_INT (val); } +/* Return subword OFFSET of operand OP. + The word number, OFFSET, is interpreted as the word number starting + at the low-order address. OFFSET 0 is the low-order word if not + WORDS_BIG_ENDIAN, otherwise it is the high-order word. + + If we cannot extract the required word, we return zero. Otherwise, + an rtx corresponding to the requested word will be returned. + + VALIDATE_ADDRESS is nonzero if the address should be validated. Before + reload has completed, a valid address will always be returned. After + reload, if a valid address cannot be returned, we return zero. + + If VALIDATE_ADDRESS is zero, we simply form the required address; validating + it is the responsibility of the caller. + + MODE is the mode of OP in case it is a CONST_INT. + + ??? This is still rather broken for some cases. The problem for the + moment is that all callers of this thing provide no 'goal mode' to + tell us to work with. This exists because all callers were written + in a word based SUBREG world. */ + +rtx +operand_subword (op, offset, validate_address, mode) + rtx op; + unsigned int offset; + int validate_address; + enum machine_mode mode; +{ + if (mode == VOIDmode) + mode = GET_MODE (op); + + if (mode == VOIDmode) + abort (); + + /* If OP is narrower than a word, fail. */ + if (mode != BLKmode + && (GET_MODE_SIZE (mode) < UNITS_PER_WORD)) + return 0; + + /* If we want a word outside OP, return zero. */ + if (mode != BLKmode + && (offset + 1) * UNITS_PER_WORD > GET_MODE_SIZE (mode)) + return const0_rtx; + + switch (GET_CODE (op)) + { + case REG: + case SUBREG: + case CONCAT: + case MEM: + break; + + default: + /* The only remaining cases are when OP is a constant. If the host and + target floating formats are the same, handling two-word floating + constants are easy. Note that REAL_VALUE_TO_TARGET_{SINGLE,DOUBLE} + are defined as returning one or two 32 bit values, respectively, + and not values of BITS_PER_WORD bits. */ + return constant_subword (op, offset, mode); + } + + /* If OP is already an integer word, return it. */ + if (GET_MODE_CLASS (mode) == MODE_INT + && GET_MODE_SIZE (mode) == UNITS_PER_WORD) + return op; + + /* If OP is a REG or SUBREG, we can handle it very simply. */ + if (GET_CODE (op) == REG) + { + if (REGNO (op) < FIRST_PSEUDO_REGISTER) + { + int final_regno = REGNO (op) + + subreg_regno_offset (REGNO (op), GET_MODE (op), + offset * UNITS_PER_WORD, + word_mode); + + /* If the register is not valid for MODE, return 0. If we don't + do this, there is no way to fix up the resulting REG later. */ + if (! HARD_REGNO_MODE_OK (final_regno, word_mode)) + return 0; + + /* integrate.c can't handle parts of a return value register. + ??? Then integrate.c should be fixed! + ??? What about CLASS_CANNOT_CHANGE_SIZE? */ + if ((! REG_FUNCTION_VALUE_P (op) + || ! rtx_equal_function_value_matters) + /* ??? What about CLASS_CANNOT_CHANGE_SIZE? */ + /* We want to keep the stack, frame, and arg pointers + special. */ + && op != frame_pointer_rtx +#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM + && op != arg_pointer_rtx +#endif + && op != stack_pointer_rtx) + return gen_rtx_REG (word_mode, final_regno); + } + + /* Just return a normal SUBREG. */ + return gen_rtx_SUBREG (word_mode, op, + (offset * UNITS_PER_WORD)); + } + else if (GET_CODE (op) == SUBREG) + { + int final_offset = ((offset * UNITS_PER_WORD) + SUBREG_BYTE (op)); + + /* When working with SUBREGs the rule is that the byte + offset must be a multiple of the SUBREG's mode. */ + final_offset = (final_offset / GET_MODE_SIZE (word_mode)); + final_offset = (final_offset * GET_MODE_SIZE (word_mode)); + return gen_rtx_SUBREG (word_mode, SUBREG_REG (op), final_offset); + } + else if (GET_CODE (op) == CONCAT) + { + unsigned int partwords = GET_MODE_UNIT_SIZE (GET_MODE (op)) / UNITS_PER_WORD; + if (offset < partwords) + return operand_subword (XEXP (op, 0), offset, validate_address, mode); + return operand_subword (XEXP (op, 1), offset - partwords, + validate_address, mode); + } + + /* Form a new MEM at the requested address. */ + if (GET_CODE (op) == MEM) + { + rtx addr = plus_constant (XEXP (op, 0), (offset * UNITS_PER_WORD)); + rtx new; + + if (validate_address) + { + if (reload_completed) + { + if (! strict_memory_address_p (word_mode, addr)) + return 0; + } + else + addr = memory_address (word_mode, addr); + } + + new = gen_rtx_MEM (word_mode, addr); + MEM_COPY_ATTRIBUTES (new, op); + return new; + } + + /* Unreachable... (famous last words) */ + abort (); +} + /* Similar to `operand_subword', but never return 0. If we can't extract the required subword, put OP into a register and try again. If that fails, - abort. We always validate the address in this case. It is not valid - to call this function after reload; it is mostly meant for RTL - generation. + abort. We always validate the address in this case. MODE is the mode of OP, in case it is CONST_INT. */ rtx -operand_subword_force (op, i, mode) +operand_subword_force (op, offset, mode) rtx op; - unsigned int i; + unsigned int offset; enum machine_mode mode; { - rtx result = operand_subword (op, i, 1, mode); + rtx result = operand_subword (op, offset, 1, mode); if (result) return result; @@ -1566,7 +1696,7 @@ operand_subword_force (op, i, mode) op = force_reg (mode, op); } - result = operand_subword (op, i, 1, mode); + result = operand_subword (op, offset, 1, mode); if (result == 0) abort (); diff --git a/gcc/expmed.c b/gcc/expmed.c index 7fdbdf5d2bf0..a7684508b5bc 100644 --- a/gcc/expmed.c +++ b/gcc/expmed.c @@ -261,7 +261,7 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size) meaningful at a much higher level; when structures are copied between memory and regs, the higher-numbered regs always get higher addresses. */ - offset += SUBREG_WORD (op0); + offset += (SUBREG_BYTE (op0) / UNITS_PER_WORD); /* We used to adjust BITPOS here, but now we do the whole adjustment right after the loop. */ op0 = SUBREG_REG (op0); @@ -311,7 +311,9 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size) abort (); } if (GET_CODE (op0) == REG) - op0 = gen_rtx_SUBREG (fieldmode, op0, offset); + op0 = gen_rtx_SUBREG (fieldmode, op0, + (bitnum % BITS_PER_WORD) / BITS_PER_UNIT + + (offset * UNITS_PER_WORD)); else op0 = change_address (op0, fieldmode, plus_constant (XEXP (op0, 0), offset)); @@ -373,7 +375,10 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size) } emit_insn (GEN_FCN (icode) - (gen_rtx_SUBREG (fieldmode, op0, offset), value)); + (gen_rtx_SUBREG (fieldmode, op0, + (bitnum % BITS_PER_WORD) / BITS_PER_UNIT + + (offset * UNITS_PER_WORD)), + value)); return value; } @@ -447,7 +452,7 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size) abort (); } op0 = gen_rtx_SUBREG (mode_for_size (BITS_PER_WORD, MODE_INT, 0), - op0, offset); + op0, (offset * UNITS_PER_WORD)); } offset = 0; } @@ -550,7 +555,7 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size) if (GET_CODE (xop0) == SUBREG) /* We can't just change the mode, because this might clobber op0, and we will need the original value of op0 if insv fails. */ - xop0 = gen_rtx_SUBREG (maxmode, SUBREG_REG (xop0), SUBREG_WORD (xop0)); + xop0 = gen_rtx_SUBREG (maxmode, SUBREG_REG (xop0), SUBREG_BYTE (xop0)); if (GET_CODE (xop0) == REG && GET_MODE (xop0) != maxmode) xop0 = gen_rtx_SUBREG (maxmode, xop0, 0); @@ -910,8 +915,8 @@ store_split_bit_field (op0, bitsize, bitpos, value, align) the current word starting from the base register. */ if (GET_CODE (op0) == SUBREG) { - word = operand_subword_force (SUBREG_REG (op0), - SUBREG_WORD (op0) + offset, + int word_offset = (SUBREG_BYTE (op0) / UNITS_PER_WORD) + offset; + word = operand_subword_force (SUBREG_REG (op0), word_offset, GET_MODE (SUBREG_REG (op0))); offset = 0; } @@ -1008,7 +1013,7 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp, int outer_size = GET_MODE_BITSIZE (GET_MODE (op0)); int inner_size = GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0))); - offset += SUBREG_WORD (op0); + offset += SUBREG_BYTE (op0) / UNITS_PER_WORD; inner_size = MIN (inner_size, BITS_PER_WORD); @@ -1104,7 +1109,9 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp, abort (); } if (GET_CODE (op0) == REG) - op0 = gen_rtx_SUBREG (mode1, op0, offset); + op0 = gen_rtx_SUBREG (mode1, op0, + (bitnum % BITS_PER_WORD) / BITS_PER_UNIT + + (offset * UNITS_PER_WORD)); else op0 = change_address (op0, mode1, plus_constant (XEXP (op0, 0), offset)); @@ -1213,7 +1220,7 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp, if (GET_CODE (op0) != REG) op0 = copy_to_reg (op0); op0 = gen_rtx_SUBREG (mode_for_size (BITS_PER_WORD, MODE_INT, 0), - op0, offset); + op0, (offset * UNITS_PER_WORD)); } offset = 0; } @@ -1808,8 +1815,8 @@ extract_split_bit_field (op0, bitsize, bitpos, unsignedp, align) the current word starting from the base register. */ if (GET_CODE (op0) == SUBREG) { - word = operand_subword_force (SUBREG_REG (op0), - SUBREG_WORD (op0) + offset, + int word_offset = (SUBREG_BYTE (op0) / UNITS_PER_WORD) + offset; + word = operand_subword_force (SUBREG_REG (op0), word_offset, GET_MODE (SUBREG_REG (op0))); offset = 0; } @@ -1928,7 +1935,7 @@ expand_shift (code, mode, shifted, amount, target, unsignedp) op1 = GEN_INT ((unsigned HOST_WIDE_INT) INTVAL (op1) % GET_MODE_BITSIZE (mode)); else if (GET_CODE (op1) == SUBREG - && SUBREG_WORD (op1) == 0) + && SUBREG_BYTE (op1) == 0) op1 = SUBREG_REG (op1); } #endif diff --git a/gcc/expr.c b/gcc/expr.c index c2661722cb3a..7d78acd33ae1 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -4134,7 +4134,7 @@ store_expr (exp, target, want_value) if (want_value && GET_MODE (temp) != GET_MODE (target) && GET_MODE (temp) != VOIDmode) { - temp = gen_rtx_SUBREG (GET_MODE (target), temp, 0); + temp = gen_lowpart_SUBREG (GET_MODE (target), temp); SUBREG_PROMOTED_VAR_P (temp) = 1; SUBREG_PROMOTED_UNSIGNED_P (temp) = SUBREG_PROMOTED_UNSIGNED_P (target); @@ -6346,7 +6346,7 @@ expand_expr (exp, target, tmode, modifier) != promote_mode (type, DECL_MODE (exp), &unsignedp, 0)) abort (); - temp = gen_rtx_SUBREG (mode, DECL_RTL (exp), 0); + temp = gen_lowpart_SUBREG (mode, DECL_RTL (exp)); SUBREG_PROMOTED_VAR_P (temp) = 1; SUBREG_PROMOTED_UNSIGNED_P (temp) = unsignedp; return temp; @@ -6466,7 +6466,7 @@ expand_expr (exp, target, tmode, modifier) if (GET_CODE (temp) == REG && GET_MODE (temp) != mode) { - temp = gen_rtx_SUBREG (mode, SAVE_EXPR_RTL (exp), 0); + temp = gen_lowpart_SUBREG (mode, SAVE_EXPR_RTL (exp)); SUBREG_PROMOTED_VAR_P (temp) = 1; SUBREG_PROMOTED_UNSIGNED_P (temp) = unsignedp; } @@ -6489,7 +6489,7 @@ expand_expr (exp, target, tmode, modifier) { /* Compute the signedness and make the proper SUBREG. */ promote_mode (type, mode, &unsignedp, 0); - temp = gen_rtx_SUBREG (mode, SAVE_EXPR_RTL (exp), 0); + temp = gen_lowpart_SUBREG (mode, SAVE_EXPR_RTL (exp)); SUBREG_PROMOTED_VAR_P (temp) = 1; SUBREG_PROMOTED_UNSIGNED_P (temp) = unsignedp; return temp; diff --git a/gcc/final.c b/gcc/final.c index fef6641a3a63..88519bd73bfa 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -3119,20 +3119,8 @@ alter_subreg (x) if (GET_CODE (y) == REG) { - int regno; - /* If the word size is larger than the size of this register, - adjust the register number to compensate. */ - /* ??? Note that this just catches stragglers created by/for - integrate. It would be better if we either caught these - earlier, or kept _all_ subregs until now and eliminate - gen_lowpart and friends. */ - -#ifdef ALTER_HARD_SUBREG - regno = ALTER_HARD_SUBREG (GET_MODE (x), SUBREG_WORD (x), - GET_MODE (y), REGNO (y)); -#else - regno = REGNO (y) + SUBREG_WORD (x); -#endif + int regno = subreg_hard_regno (x, 1); + PUT_CODE (x, REG); REGNO (x) = regno; ORIGINAL_REGNO (x) = ORIGINAL_REGNO (y); @@ -3142,11 +3130,12 @@ alter_subreg (x) } else if (GET_CODE (y) == MEM) { - register int offset = SUBREG_WORD (x) * UNITS_PER_WORD; + register int offset = SUBREG_BYTE (x); + + /* Catch these instead of generating incorrect code. */ + if ((offset % GET_MODE_SIZE (GET_MODE (x))) != 0) + abort (); - if (BYTES_BIG_ENDIAN) - offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))) - - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (y)))); PUT_CODE (x, MEM); MEM_COPY_ATTRIBUTES (x, y); XEXP (x, 0) = plus_constant (XEXP (y, 0), offset); diff --git a/gcc/flow.c b/gcc/flow.c index d057bc5e264b..388bd2a9d8a0 100644 --- a/gcc/flow.c +++ b/gcc/flow.c @@ -3088,7 +3088,7 @@ set_noop_p (set) if (GET_CODE (src) == SUBREG && GET_CODE (dst) == SUBREG) { - if (SUBREG_WORD (src) != SUBREG_WORD (dst)) + if (SUBREG_BYTE (src) != SUBREG_BYTE (dst)) return 0; src = SUBREG_REG (src); dst = SUBREG_REG (dst); @@ -4669,12 +4669,9 @@ mark_set_1 (pbi, code, reg, cond, insn, flags) regno_last = regno_first = REGNO (SUBREG_REG (reg)); if (regno_first < FIRST_PSEUDO_REGISTER) { -#ifdef ALTER_HARD_SUBREG - regno_first = ALTER_HARD_SUBREG (outer_mode, SUBREG_WORD (reg), - inner_mode, regno_first); -#else - regno_first += SUBREG_WORD (reg); -#endif + regno_first += subreg_regno_offset (regno_first, inner_mode, + SUBREG_BYTE (reg), + outer_mode); regno_last = (regno_first + HARD_REGNO_NREGS (regno_first, outer_mode) - 1); diff --git a/gcc/function.c b/gcc/function.c index 6eebf34f2847..c31029bc5668 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -2221,7 +2221,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements) dest = XEXP (dest, 0); if (GET_CODE (src) == SUBREG) - src = XEXP (src, 0); + src = SUBREG_REG (src); /* If VAR does not appear at the top level of the SET just scan the lower levels of the tree. */ @@ -2505,7 +2505,7 @@ fixup_memory_subreg (x, insn, uncritical) rtx insn; int uncritical; { - int offset = SUBREG_WORD (x) * UNITS_PER_WORD; + int offset = SUBREG_BYTE (x); rtx addr = XEXP (SUBREG_REG (x), 0); enum machine_mode mode = GET_MODE (x); rtx result; @@ -2515,9 +2515,6 @@ fixup_memory_subreg (x, insn, uncritical) && ! uncritical) abort (); - if (BYTES_BIG_ENDIAN) - offset += (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))) - - MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode))); addr = plus_constant (addr, offset); if (!flag_force_addr && memory_address_p (mode, addr)) /* Shortcut if no insns need be emitted. */ @@ -2711,7 +2708,8 @@ optimize_bit_field (body, insn, equiv_mem) offset /= BITS_PER_UNIT; if (GET_CODE (XEXP (bitfield, 0)) == SUBREG) { - offset += SUBREG_WORD (XEXP (bitfield, 0)) * UNITS_PER_WORD; + offset += (SUBREG_BYTE (XEXP (bitfield, 0)) + / UNITS_PER_WORD) * UNITS_PER_WORD; if (BYTES_BIG_ENDIAN) offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (XEXP (bitfield, 0)))) @@ -2736,7 +2734,7 @@ optimize_bit_field (body, insn, equiv_mem) { rtx src = SET_SRC (body); while (GET_CODE (src) == SUBREG - && SUBREG_WORD (src) == 0) + && SUBREG_BYTE (src) == 0) src = SUBREG_REG (src); if (GET_MODE (src) != GET_MODE (memref)) src = gen_lowpart (GET_MODE (memref), SET_SRC (body)); @@ -2757,7 +2755,7 @@ optimize_bit_field (body, insn, equiv_mem) rtx dest = SET_DEST (body); while (GET_CODE (dest) == SUBREG - && SUBREG_WORD (dest) == 0 + && SUBREG_BYTE (dest) == 0 && (GET_MODE_CLASS (GET_MODE (dest)) == GET_MODE_CLASS (GET_MODE (SUBREG_REG (dest)))) && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))) @@ -3067,7 +3065,7 @@ purge_addressof_1 (loc, insn, force, store, ht) code did. This is especially true of REG_RETVAL. */ - if (GET_CODE (z) == SUBREG && SUBREG_WORD (z) == 0) + if (GET_CODE (z) == SUBREG && SUBREG_BYTE (z) == 0) z = SUBREG_REG (z); if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD @@ -3443,17 +3441,22 @@ purge_single_hard_subreg_set (pattern) { rtx reg = SET_DEST (pattern); enum machine_mode mode = GET_MODE (SET_DEST (pattern)); - int word = 0; - - while (GET_CODE (reg) == SUBREG) + int offset = 0; + + if (GET_CODE (reg) == SUBREG && GET_CODE (SUBREG_REG (reg)) == REG + && REGNO (SUBREG_REG (reg)) < FIRST_PSEUDO_REGISTER) { - word += SUBREG_WORD (reg); + offset = subreg_regno_offset (REGNO (SUBREG_REG (reg)), + GET_MODE (SUBREG_REG (reg)), + SUBREG_BYTE (reg), + GET_MODE (reg)); reg = SUBREG_REG (reg); } - + + if (REGNO (reg) < FIRST_PSEUDO_REGISTER) { - reg = gen_rtx_REG (mode, REGNO (reg) + word); + reg = gen_rtx_REG (mode, REGNO (reg) + offset); SET_DEST (pattern) = reg; } } @@ -4737,6 +4740,20 @@ assign_parms (fndecl) push_to_sequence (conversion_insns); tempreg = convert_to_mode (nominal_mode, tempreg, unsignedp); + if (GET_CODE (tempreg) == SUBREG + && GET_MODE (tempreg) == nominal_mode + && GET_CODE (SUBREG_REG (tempreg)) == REG + && nominal_mode == passed_mode + && GET_MODE (SUBREG_REG (tempreg)) == GET_MODE (entry_parm) + && GET_MODE_SIZE (GET_MODE (tempreg)) + < GET_MODE_SIZE (GET_MODE (entry_parm))) + { + /* The argument is already sign/zero extended, so note it + into the subreg. */ + SUBREG_PROMOTED_VAR_P (tempreg) = 1; + SUBREG_PROMOTED_UNSIGNED_P (tempreg) = unsignedp; + } + /* TREE_USED gets set erroneously during expand_assignment. */ save_tree_used = TREE_USED (parm); expand_assignment (parm, diff --git a/gcc/gengenrtl.c b/gcc/gengenrtl.c index 21f46df1461a..d41e0d279751 100644 --- a/gcc/gengenrtl.c +++ b/gcc/gengenrtl.c @@ -208,6 +208,7 @@ special_rtx (idx) return (strcmp (defs[idx].enumname, "CONST_INT") == 0 || strcmp (defs[idx].enumname, "CONST_DOUBLE") == 0 || strcmp (defs[idx].enumname, "REG") == 0 + || strcmp (defs[idx].enumname, "SUBREG") == 0 || strcmp (defs[idx].enumname, "MEM") == 0); } diff --git a/gcc/global.c b/gcc/global.c index 8aa172a5e36a..2f757bd9ade7 100644 --- a/gcc/global.c +++ b/gcc/global.c @@ -1422,17 +1422,8 @@ mark_reg_store (reg, setter, data) { register int regno; - /* WORD is which word of a multi-register group is being stored. - For the case where the store is actually into a SUBREG of REG. - Except we don't use it; I believe the entire REG needs to be - made live. */ - int word = 0; - if (GET_CODE (reg) == SUBREG) - { - word = SUBREG_WORD (reg); - reg = SUBREG_REG (reg); - } + reg = SUBREG_REG (reg); if (GET_CODE (reg) != REG) return; @@ -1456,7 +1447,7 @@ mark_reg_store (reg, setter, data) } if (reg_renumber[regno] >= 0) - regno = reg_renumber[regno] /* + word */; + regno = reg_renumber[regno]; /* Handle hardware regs (and pseudos allocated to hard regs). */ if (regno < FIRST_PSEUDO_REGISTER && ! fixed_regs[regno]) @@ -1606,7 +1597,15 @@ set_preference (dest, src) else if (GET_CODE (src) == SUBREG && GET_CODE (SUBREG_REG (src)) == REG) { src_regno = REGNO (SUBREG_REG (src)); - offset += SUBREG_WORD (src); + + if (REGNO (SUBREG_REG (src)) < FIRST_PSEUDO_REGISTER) + offset += subreg_regno_offset (REGNO (SUBREG_REG (src)), + GET_MODE (SUBREG_REG (src)), + SUBREG_BYTE (src), + GET_MODE (src)); + else + offset += (SUBREG_BYTE (src) + / REGMODE_NATURAL_SIZE (GET_MODE (src))); } else return; @@ -1616,7 +1615,15 @@ set_preference (dest, src) else if (GET_CODE (dest) == SUBREG && GET_CODE (SUBREG_REG (dest)) == REG) { dest_regno = REGNO (SUBREG_REG (dest)); - offset -= SUBREG_WORD (dest); + + if (REGNO (SUBREG_REG (dest)) < FIRST_PSEUDO_REGISTER) + offset -= subreg_regno_offset (REGNO (SUBREG_REG (dest)), + GET_MODE (SUBREG_REG (dest)), + SUBREG_BYTE (dest), + GET_MODE (dest)); + else + offset -= (SUBREG_BYTE (dest) + / REGMODE_NATURAL_SIZE (GET_MODE (dest))); } else return; diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c index f0df3da0371e..b642643f3aec 100644 --- a/gcc/ifcvt.c +++ b/gcc/ifcvt.c @@ -557,10 +557,7 @@ noce_emit_move_insn (x, y) inner = XEXP (outer, 0); outmode = GET_MODE (outer); inmode = GET_MODE (inner); - bitpos = SUBREG_WORD (outer) * BITS_PER_WORD; - if (BYTES_BIG_ENDIAN) - bitpos += (GET_MODE_BITSIZE (inmode) - GET_MODE_BITSIZE (outmode)) - % BITS_PER_WORD; + bitpos = SUBREG_BYTE (outer) * BITS_PER_UNIT; store_bit_field (inner, GET_MODE_BITSIZE (outmode), bitpos, outmode, y, GET_MODE_BITSIZE (inmode), GET_MODE_BITSIZE (inmode)); diff --git a/gcc/integrate.c b/gcc/integrate.c index ed6540e4bfd7..327e8fa5f254 100644 --- a/gcc/integrate.c +++ b/gcc/integrate.c @@ -1895,23 +1895,33 @@ copy_rtx_and_substitute (orig, map, for_lhs) copy = copy_rtx_and_substitute (SUBREG_REG (orig), map, for_lhs); /* SUBREG is ordinary, but don't make nested SUBREGs. */ if (GET_CODE (copy) == SUBREG) - return gen_rtx_SUBREG (GET_MODE (orig), SUBREG_REG (copy), - SUBREG_WORD (orig) + SUBREG_WORD (copy)); + { + int final_offset = SUBREG_BYTE (orig) + SUBREG_BYTE (copy); + + /* When working with SUBREGs the rule is that the byte + offset must be a multiple of the SUBREG's mode. */ + final_offset = (final_offset / GET_MODE_SIZE (GET_MODE (orig))); + final_offset = (final_offset * GET_MODE_SIZE (GET_MODE (orig))); + return gen_rtx_SUBREG (GET_MODE (orig), SUBREG_REG (copy), + final_offset); + } else if (GET_CODE (copy) == CONCAT) { rtx retval = subreg_realpart_p (orig) ? XEXP (copy, 0) : XEXP (copy, 1); + int final_offset; if (GET_MODE (retval) == GET_MODE (orig)) return retval; - else - return gen_rtx_SUBREG (GET_MODE (orig), retval, - (SUBREG_WORD (orig) % - (GET_MODE_UNIT_SIZE (GET_MODE (SUBREG_REG (orig))) - / (unsigned) UNITS_PER_WORD))); + + final_offset = SUBREG_BYTE (orig) % + GET_MODE_UNIT_SIZE (GET_MODE (SUBREG_REG (orig))); + final_offset = (final_offset / GET_MODE_SIZE (GET_MODE (orig))); + final_offset = (final_offset * GET_MODE_SIZE (GET_MODE (orig))); + return gen_rtx_SUBREG (GET_MODE (orig), retval, final_offset); } else return gen_rtx_SUBREG (GET_MODE (orig), copy, - SUBREG_WORD (orig)); + SUBREG_BYTE (orig)); case ADDRESSOF: copy = gen_rtx_ADDRESSOF (mode, @@ -2397,8 +2407,8 @@ subst_constants (loc, insn, map, memonly) if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT && GET_MODE_SIZE (GET_MODE (x)) == UNITS_PER_WORD && GET_MODE (SUBREG_REG (x)) != VOIDmode) - new = operand_subword (inner, SUBREG_WORD (x), 0, - GET_MODE (SUBREG_REG (x))); + new = operand_subword (inner, SUBREG_BYTE (x) / UNITS_PER_WORD, + 0, GET_MODE (SUBREG_REG (x))); cancel_changes (num_changes); if (new == 0 && subreg_lowpart_p (x)) @@ -2675,7 +2685,12 @@ mark_stores (dest, x, data) regno = REGNO (dest), mode = GET_MODE (dest); else if (GET_CODE (dest) == SUBREG && GET_CODE (SUBREG_REG (dest)) == REG) { - regno = REGNO (SUBREG_REG (dest)) + SUBREG_WORD (dest); + regno = REGNO (SUBREG_REG (dest)); + if (regno < FIRST_PSEUDO_REGISTER) + regno += subreg_regno_offset (REGNO (SUBREG_REG (dest)), + GET_MODE (SUBREG_REG (dest)), + SUBREG_BYTE (dest), + GET_MODE (dest)); mode = GET_MODE (SUBREG_REG (dest)); } diff --git a/gcc/jump.c b/gcc/jump.c index 2b111d4bd59b..5c5807394dc0 100644 --- a/gcc/jump.c +++ b/gcc/jump.c @@ -3543,7 +3543,7 @@ rtx_renumbered_equal_p (x, y) && GET_CODE (SUBREG_REG (y)) == REG))) { int reg_x = -1, reg_y = -1; - int word_x = 0, word_y = 0; + int byte_x = 0, byte_y = 0; if (GET_MODE (x) != GET_MODE (y)) return 0; @@ -3556,15 +3556,17 @@ rtx_renumbered_equal_p (x, y) if (code == SUBREG) { reg_x = REGNO (SUBREG_REG (x)); - word_x = SUBREG_WORD (x); + byte_x = SUBREG_BYTE (x); if (reg_renumber[reg_x] >= 0) { - reg_x = reg_renumber[reg_x] + word_x; - word_x = 0; + reg_x = subreg_regno_offset (reg_renumber[reg_x], + GET_MODE (SUBREG_REG (x)), + byte_x, + GET_MODE (x)); + byte_x = 0; } } - else { reg_x = REGNO (x); @@ -3575,15 +3577,17 @@ rtx_renumbered_equal_p (x, y) if (GET_CODE (y) == SUBREG) { reg_y = REGNO (SUBREG_REG (y)); - word_y = SUBREG_WORD (y); + byte_y = SUBREG_BYTE (y); if (reg_renumber[reg_y] >= 0) { - reg_y = reg_renumber[reg_y]; - word_y = 0; + reg_y = subreg_regno_offset (reg_renumber[reg_y], + GET_MODE (SUBREG_REG (y)), + byte_y, + GET_MODE (y)); + byte_y = 0; } } - else { reg_y = REGNO (y); @@ -3591,7 +3595,7 @@ rtx_renumbered_equal_p (x, y) reg_y = reg_renumber[reg_y]; } - return reg_x >= 0 && reg_x == reg_y && word_x == word_y; + return reg_x >= 0 && reg_x == reg_y && byte_x == byte_y; } /* Now we have disposed of all the cases @@ -3722,7 +3726,9 @@ true_regnum (x) { int base = true_regnum (SUBREG_REG (x)); if (base >= 0 && base < FIRST_PSEUDO_REGISTER) - return SUBREG_WORD (x) + base; + return base + subreg_regno_offset (REGNO (SUBREG_REG (x)), + GET_MODE (SUBREG_REG (x)), + SUBREG_BYTE (x), GET_MODE (x)); } return -1; } diff --git a/gcc/local-alloc.c b/gcc/local-alloc.c index c743ad63fe83..c83d4f145f58 100644 --- a/gcc/local-alloc.c +++ b/gcc/local-alloc.c @@ -1813,25 +1813,49 @@ combine_regs (usedreg, setreg, may_save_copy, insn_number, insn, already_dead) { if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (usedreg))) > UNITS_PER_WORD) may_save_copy = 0; - offset += SUBREG_WORD (usedreg); + if (REGNO (SUBREG_REG (usedreg)) < FIRST_PSEUDO_REGISTER) + offset += subreg_regno_offset (REGNO (SUBREG_REG (usedreg)), + GET_MODE (SUBREG_REG (usedreg)), + SUBREG_BYTE (usedreg), + GET_MODE (usedreg)); + else + offset += (SUBREG_BYTE (usedreg) + / REGMODE_NATURAL_SIZE (GET_MODE (usedreg))); usedreg = SUBREG_REG (usedreg); } if (GET_CODE (usedreg) != REG) return 0; ureg = REGNO (usedreg); - usize = REG_SIZE (usedreg); + if (ureg < FIRST_PSEUDO_REGISTER) + usize = HARD_REGNO_NREGS (ureg, GET_MODE (usedreg)); + else + usize = ((GET_MODE_SIZE (GET_MODE (usedreg)) + + (REGMODE_NATURAL_SIZE (GET_MODE (usedreg)) - 1)) + / REGMODE_NATURAL_SIZE (GET_MODE (usedreg))); while (GET_CODE (setreg) == SUBREG) { if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (setreg))) > UNITS_PER_WORD) may_save_copy = 0; - offset -= SUBREG_WORD (setreg); + if (REGNO (SUBREG_REG (setreg)) < FIRST_PSEUDO_REGISTER) + offset -= subreg_regno_offset (REGNO (SUBREG_REG (setreg)), + GET_MODE (SUBREG_REG (setreg)), + SUBREG_BYTE (setreg), + GET_MODE (setreg)); + else + offset -= (SUBREG_BYTE (setreg) + / REGMODE_NATURAL_SIZE (GET_MODE (setreg))); setreg = SUBREG_REG (setreg); } if (GET_CODE (setreg) != REG) return 0; sreg = REGNO (setreg); - ssize = REG_SIZE (setreg); + if (sreg < FIRST_PSEUDO_REGISTER) + ssize = HARD_REGNO_NREGS (sreg, GET_MODE (setreg)); + else + ssize = ((GET_MODE_SIZE (GET_MODE (setreg)) + + (REGMODE_NATURAL_SIZE (GET_MODE (setreg)) - 1)) + / REGMODE_NATURAL_SIZE (GET_MODE (setreg))); /* If UREG is a pseudo-register that hasn't already been assigned a quantity number, it means that it is not local to this block or dies @@ -2032,7 +2056,11 @@ reg_is_born (reg, birth) register int regno; if (GET_CODE (reg) == SUBREG) - regno = REGNO (SUBREG_REG (reg)) + SUBREG_WORD (reg); + { + regno = REGNO (SUBREG_REG (reg)); + if (regno < FIRST_PSEUDO_REGISTER) + regno = subreg_hard_regno (reg, 1); + } else regno = REGNO (reg); diff --git a/gcc/recog.c b/gcc/recog.c index 1596a019067a..e278f985529a 100644 --- a/gcc/recog.c +++ b/gcc/recog.c @@ -517,13 +517,15 @@ validate_replace_rtx_1 (loc, from, to, object) if (GET_CODE (XEXP (x, 0)) == SUBREG) { if (GET_MODE_SIZE (GET_MODE (XEXP (x, 0))) <= UNITS_PER_WORD) - to = operand_subword (to, SUBREG_WORD (XEXP (x, 0)), + to = operand_subword (to, + (SUBREG_BYTE (XEXP (x, 0)) + / UNITS_PER_WORD), 0, GET_MODE (from)); else if (GET_MODE_CLASS (GET_MODE (from)) == MODE_INT && (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) <= HOST_BITS_PER_WIDE_INT)) { - int i = SUBREG_WORD (XEXP (x, 0)) * BITS_PER_WORD; + int i = SUBREG_BYTE (XEXP (x, 0)) * BITS_PER_UNIT; HOST_WIDE_INT valh; unsigned HOST_WIDE_INT vall; @@ -569,26 +571,21 @@ validate_replace_rtx_1 (loc, from, to, object) break; case SUBREG: - /* In case we are replacing by constant, attempt to simplify it to non-SUBREG - expression. We can't do this later, since the information about inner mode - may be lost. */ + /* In case we are replacing by constant, attempt to simplify it to + non-SUBREG expression. We can't do this later, since the information + about inner mode may be lost. */ if (CONSTANT_P (to) && rtx_equal_p (SUBREG_REG (x), from)) { - if (GET_MODE_SIZE (GET_MODE (x)) == UNITS_PER_WORD - && GET_MODE_SIZE (GET_MODE (from)) > UNITS_PER_WORD - && GET_MODE_CLASS (GET_MODE (x)) == MODE_INT) - { - rtx temp = operand_subword (to, SUBREG_WORD (x), - 0, GET_MODE (from)); - if (temp) - { - validate_change (object, loc, temp, 1); - return; - } - } - if (subreg_lowpart_p (x)) + int offset, part; + unsigned HOST_WIDE_INT val; + + /* A paradoxical SUBREG of a VOIDmode constant is the same constant, + since we are saying that the high bits don't matter. */ + if (GET_MODE (to) == VOIDmode + && (GET_MODE_SIZE (GET_MODE (x)) + >= GET_MODE_SIZE (GET_MODE (from)))) { - rtx new = gen_lowpart_if_possible (GET_MODE (x), to); + rtx new = gen_lowpart_if_possible (GET_MODE (x), to); if (new) { validate_change (object, loc, new, 1); @@ -596,13 +593,67 @@ validate_replace_rtx_1 (loc, from, to, object) } } - /* A paradoxical SUBREG of a VOIDmode constant is the same constant, - since we are saying that the high bits don't matter. */ - if (GET_MODE (to) == VOIDmode - && GET_MODE_SIZE (GET_MODE (x)) > GET_MODE_SIZE (GET_MODE (from))) + offset = SUBREG_BYTE (x) * BITS_PER_UNIT; + switch (GET_CODE (to)) { - validate_change (object, loc, to, 1); - return; + case CONST_DOUBLE: + if (GET_MODE (to) != VOIDmode) + break; + + part = offset >= HOST_BITS_PER_WIDE_INT; + if ((BITS_PER_WORD > HOST_BITS_PER_WIDE_INT + && BYTES_BIG_ENDIAN) + || (BITS_PER_WORD <= HOST_BITS_PER_WIDE_INT + && WORDS_BIG_ENDIAN)) + part = !part; + val = part ? CONST_DOUBLE_HIGH (to) : CONST_DOUBLE_LOW (to); + offset %= HOST_BITS_PER_WIDE_INT; + + /* FALLTHROUGH */ + case CONST_INT: + if (GET_CODE (to) == CONST_INT) + val = INTVAL (to); + + { + /* Avoid creating bogus SUBREGs */ + enum machine_mode mode = GET_MODE (x); + enum machine_mode inner_mode = GET_MODE (from); + + /* We've already picked the word we want from a double, so + pretend this is actually an integer. */ + if (GET_CODE (to) == CONST_DOUBLE) + inner_mode = SImode; + + if (GET_MODE_CLASS (mode) != MODE_INT) + abort (); + + if (BYTES_BIG_ENDIAN || WORDS_BIG_ENDIAN) + { + if (WORDS_BIG_ENDIAN) + offset = GET_MODE_BITSIZE (inner_mode) + - GET_MODE_BITSIZE (mode) - offset; + if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN + && GET_MODE_SIZE (mode) < UNITS_PER_WORD) + offset = offset + BITS_PER_WORD - GET_MODE_BITSIZE (mode) + - 2 * (offset % BITS_PER_WORD); + } + + if (offset >= HOST_BITS_PER_WIDE_INT) + to = ((HOST_WIDE_INT) val < 0) ? constm1_rtx : const0_rtx; + else + { + val >>= offset; + if (GET_MODE_BITSIZE (mode) < HOST_BITS_PER_WIDE_INT) + val = trunc_int_for_mode (val, mode); + to = GEN_INT (val); + } + + validate_change (object, loc, to, 1); + return; + } + + default: + break; } } @@ -612,15 +663,26 @@ validate_replace_rtx_1 (loc, from, to, object) && rtx_equal_p (SUBREG_REG (x), from)) { if (GET_MODE (x) == GET_MODE (SUBREG_REG (to)) - && SUBREG_WORD (x) == 0 && SUBREG_WORD (to) == 0) + && SUBREG_BYTE (x) == 0 && SUBREG_BYTE (to) == 0) { validate_change (object, loc, SUBREG_REG (to), 1); return; } - validate_change (object, loc, - gen_rtx_SUBREG (GET_MODE (x), SUBREG_REG (to), - SUBREG_WORD (x) + SUBREG_WORD (to)), 1); + /* Make sure the 2 byte counts added together are an even unit + of x's mode, and combine them if so. Otherwise we run + into problems with something like: + (subreg:HI (subreg:QI (SI:55) 3) 0) + we end up with an odd offset into a HI which is invalid. */ + + if (SUBREG_BYTE (to) % GET_MODE_SIZE (GET_MODE (x)) == 0) + validate_change (object, loc, + gen_rtx_SUBREG (GET_MODE (x), SUBREG_REG (to), + SUBREG_BYTE(x) + SUBREG_BYTE (to)), + 1); + else + validate_change (object, loc, to, 1); + return; } @@ -636,15 +698,10 @@ validate_replace_rtx_1 (loc, from, to, object) && ! MEM_VOLATILE_P (to) && GET_MODE_SIZE (GET_MODE (x)) <= GET_MODE_SIZE (GET_MODE (to))) { - int offset = SUBREG_WORD (x) * UNITS_PER_WORD; + int offset = SUBREG_BYTE (x); enum machine_mode mode = GET_MODE (x); rtx new; - if (BYTES_BIG_ENDIAN) - offset += (MIN (UNITS_PER_WORD, - GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))) - - MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode))); - new = gen_rtx_MEM (mode, plus_constant (XEXP (to, 0), offset)); MEM_COPY_ATTRIBUTES (new, to); validate_change (object, loc, new, 1); @@ -694,8 +751,8 @@ validate_replace_rtx_1 (loc, from, to, object) int offset = pos / BITS_PER_UNIT; rtx newmem; - /* If the bytes and bits are counted differently, we - must adjust the offset. */ + /* If the bytes and bits are counted differently, we + must adjust the offset. */ if (BYTES_BIG_ENDIAN != BITS_BIG_ENDIAN) offset = (GET_MODE_SIZE (is_mode) - GET_MODE_SIZE (wanted_mode) - offset); @@ -1040,7 +1097,6 @@ general_operand (op, mode) enum machine_mode mode; { register enum rtx_code code = GET_CODE (op); - int mode_altering_drug = 0; if (mode == VOIDmode) mode = GET_MODE (op); @@ -1078,11 +1134,6 @@ general_operand (op, mode) op = SUBREG_REG (op); code = GET_CODE (op); -#if 0 - /* No longer needed, since (SUBREG (MEM...)) - will load the MEM into a reload reg in the MEM's own mode. */ - mode_altering_drug = 1; -#endif } if (code == REG) @@ -1113,8 +1164,6 @@ general_operand (op, mode) return 0; win: - if (mode_altering_drug) - return ! mode_dependent_address_p (XEXP (op, 0)); return 1; } @@ -1467,13 +1516,9 @@ indirect_operand (op, mode) if (! reload_completed && GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == MEM) { - register int offset = SUBREG_WORD (op) * UNITS_PER_WORD; + register int offset = SUBREG_BYTE (op); rtx inner = SUBREG_REG (op); - if (BYTES_BIG_ENDIAN) - offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (op))) - - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (inner)))); - if (mode != VOIDmode && GET_MODE (op) != mode) return 0; @@ -2482,7 +2527,10 @@ constrain_operands (strict) { if (GET_CODE (SUBREG_REG (op)) == REG && REGNO (SUBREG_REG (op)) < FIRST_PSEUDO_REGISTER) - offset = SUBREG_WORD (op); + offset = subreg_regno_offset (REGNO (SUBREG_REG (op)), + GET_MODE (SUBREG_REG (op)), + SUBREG_BYTE (op), + GET_MODE (op)); op = SUBREG_REG (op); } diff --git a/gcc/reg-stack.c b/gcc/reg-stack.c index 54c3f086a482..6c2044674236 100644 --- a/gcc/reg-stack.c +++ b/gcc/reg-stack.c @@ -557,7 +557,11 @@ get_true_reg (pat) rtx subreg; if (FP_REG_P (subreg = SUBREG_REG (*pat))) { - *pat = FP_MODE_REG (REGNO (subreg) + SUBREG_WORD (*pat), + int regno_off = subreg_regno_offset (REGNO (subreg), + GET_MODE (subreg), + SUBREG_BYTE (*pat), + GET_MODE (*pat)); + *pat = FP_MODE_REG (REGNO (subreg) + regno_off, GET_MODE (subreg)); default: return pat; diff --git a/gcc/regmove.c b/gcc/regmove.c index 26c4546fce36..227c662c5371 100644 --- a/gcc/regmove.c +++ b/gcc/regmove.c @@ -717,7 +717,7 @@ optimize_reg_copy_3 (insn, dest, src) /* Now walk forward making additional replacements. We want to be able to undo all the changes if a later substitution fails. */ - subreg = gen_rtx_SUBREG (old_mode, src_reg, 0); + subreg = gen_lowpart_SUBREG (old_mode, src_reg); while (p = NEXT_INSN (p), p != insn) { if (! INSN_P (p)) @@ -1168,7 +1168,7 @@ regmove_optimize (f, nregs, regmove_dump_file) { src_subreg = gen_rtx_SUBREG (GET_MODE (SUBREG_REG (dst)), - src, SUBREG_WORD (dst)); + src, SUBREG_BYTE (dst)); dst = SUBREG_REG (dst); } if (GET_CODE (dst) != REG diff --git a/gcc/regs.h b/gcc/regs.h index 082296660215..61b9a49ac02d 100644 --- a/gcc/regs.h +++ b/gcc/regs.h @@ -24,12 +24,28 @@ Boston, MA 02111-1307, USA. */ #define REG_BYTES(R) mode_size[(int) GET_MODE (R)] -/* Get the number of consecutive hard regs required to hold the REG rtx R. +/* Get the number of consecutive hard regs required to hold the REG or + SUBREG rtx R. When something may be an explicit hard reg, REG_SIZE is the only - valid way to get this value. You cannot get it from the regno. */ + valid way to get this value. You cannot get it from the regno. + A target may override this definition, the case where you would do + this is where there are registers which are smaller than WORD_SIZE + such as the SFmode registers on sparc64. */ + +#ifndef REG_SIZE #define REG_SIZE(R) \ ((mode_size[(int) GET_MODE (R)] + UNITS_PER_WORD - 1) / UNITS_PER_WORD) +#endif + +/* When you only have the mode of a pseudo register before it has a hard + register chosen for it, this reports the size of each hard register + a pseudo in such a mode would get allocated to. Like REG_SIZE, a + target may override this. */ + +#ifndef REGMODE_NATURAL_SIZE +#define REGMODE_NATURAL_SIZE(MODE) UNITS_PER_WORD +#endif #ifndef SMALL_REGISTER_CLASSES #define SMALL_REGISTER_CLASSES 0 diff --git a/gcc/reload.c b/gcc/reload.c index 9849aed299bb..ea5bea62331a 100644 --- a/gcc/reload.c +++ b/gcc/reload.c @@ -791,7 +791,7 @@ reload_inner_reg_of_subreg (x, mode) return 0; /* If INNER is not ok for MODE, then INNER will need reloading. */ - if (! HARD_REGNO_MODE_OK (REGNO (inner) + SUBREG_WORD (x), mode)) + if (! HARD_REGNO_MODE_OK (subreg_regno (x), mode)) return 1; /* If the outer part is a word or smaller, INNER larger than a @@ -938,13 +938,12 @@ push_reload (in, out, inloc, outloc, class, Finally, reload the inner expression if it is a register that is in the class whose registers cannot be referenced in a different size - and M1 is not the same size as M2. If SUBREG_WORD is nonzero, we + and M1 is not the same size as M2. If SUBREG_BYTE is nonzero, we cannot reload just the inside since we might end up with the wrong register class. But if it is inside a STRICT_LOW_PART, we have no choice, so we hope we do get the right register class there. */ if (in != 0 && GET_CODE (in) == SUBREG - && (SUBREG_WORD (in) == 0 || strict_low) #ifdef CLASS_CANNOT_CHANGE_MODE && (class != CLASS_CANNOT_CHANGE_MODE || ! CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (in)), inmode)) @@ -978,7 +977,7 @@ push_reload (in, out, inloc, outloc, class, && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER /* The case where out is nonzero is handled differently in the following statement. */ - && (out == 0 || SUBREG_WORD (in) == 0) + && (out == 0 || SUBREG_BYTE (in) == 0) && ((GET_MODE_SIZE (inmode) <= UNITS_PER_WORD && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))) > UNITS_PER_WORD) @@ -986,9 +985,7 @@ push_reload (in, out, inloc, outloc, class, / UNITS_PER_WORD) != HARD_REGNO_NREGS (REGNO (SUBREG_REG (in)), GET_MODE (SUBREG_REG (in))))) - || ! HARD_REGNO_MODE_OK ((REGNO (SUBREG_REG (in)) - + SUBREG_WORD (in)), - inmode))) + || ! HARD_REGNO_MODE_OK (subreg_regno (in), inmode))) #ifdef SECONDARY_INPUT_RELOAD_CLASS || (SECONDARY_INPUT_RELOAD_CLASS (class, inmode, in) != NO_REGS && (SECONDARY_INPUT_RELOAD_CLASS (class, @@ -1028,7 +1025,7 @@ push_reload (in, out, inloc, outloc, class, that case. */ /* Similar issue for (SUBREG constant ...) if it was not handled by the - code above. This can happen if SUBREG_WORD != 0. */ + code above. This can happen if SUBREG_BYTE != 0. */ if (in != 0 && reload_inner_reg_of_subreg (in, inmode)) { @@ -1038,7 +1035,11 @@ push_reload (in, out, inloc, outloc, class, RELOAD_OTHER, we are guaranteed that this inner reload will be output before the outer reload. */ push_reload (SUBREG_REG (in), NULL_RTX, &SUBREG_REG (in), NULL_PTR, - find_valid_class (inmode, SUBREG_WORD (in)), + find_valid_class (inmode, + subreg_regno_offset (REGNO (SUBREG_REG (in)), + GET_MODE (SUBREG_REG (in)), + SUBREG_BYTE (in), + GET_MODE (in))), VOIDmode, VOIDmode, 0, 0, opnum, type); dont_remove_subreg = 1; } @@ -1050,7 +1051,7 @@ push_reload (in, out, inloc, outloc, class, (except in the case of STRICT_LOW_PART, and in that case the constraint should label it input-output.) */ if (out != 0 && GET_CODE (out) == SUBREG - && (SUBREG_WORD (out) == 0 || strict_low) + && (SUBREG_BYTE (out) == 0 || strict_low) #ifdef CLASS_CANNOT_CHANGE_MODE && (class != CLASS_CANNOT_CHANGE_MODE || ! CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (out)), @@ -1080,9 +1081,7 @@ push_reload (in, out, inloc, outloc, class, / UNITS_PER_WORD) != HARD_REGNO_NREGS (REGNO (SUBREG_REG (out)), GET_MODE (SUBREG_REG (out))))) - || ! HARD_REGNO_MODE_OK ((REGNO (SUBREG_REG (out)) - + SUBREG_WORD (out)), - outmode))) + || ! HARD_REGNO_MODE_OK (subreg_regno (out), outmode))) #ifdef SECONDARY_OUTPUT_RELOAD_CLASS || (SECONDARY_OUTPUT_RELOAD_CLASS (class, outmode, out) != NO_REGS && (SECONDARY_OUTPUT_RELOAD_CLASS (class, @@ -1129,7 +1128,11 @@ push_reload (in, out, inloc, outloc, class, dont_remove_subreg = 1; push_reload (SUBREG_REG (out), SUBREG_REG (out), &SUBREG_REG (out), &SUBREG_REG (out), - find_valid_class (outmode, SUBREG_WORD (out)), + find_valid_class (outmode, + subreg_regno_offset (REGNO (SUBREG_REG (out)), + GET_MODE (SUBREG_REG (out)), + SUBREG_BYTE (out), + GET_MODE (out))), VOIDmode, VOIDmode, 0, 0, opnum, RELOAD_OTHER); } @@ -1146,16 +1149,14 @@ push_reload (in, out, inloc, outloc, class, if (in != 0 && GET_CODE (in) == SUBREG && GET_CODE (SUBREG_REG (in)) == REG && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER && ! dont_remove_subreg) - in = gen_rtx_REG (GET_MODE (in), - REGNO (SUBREG_REG (in)) + SUBREG_WORD (in)); + in = gen_rtx_REG (GET_MODE (in), subreg_regno (in)); /* Similarly for OUT. */ if (out != 0 && GET_CODE (out) == SUBREG && GET_CODE (SUBREG_REG (out)) == REG && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER && ! dont_remove_subreg) - out = gen_rtx_REG (GET_MODE (out), - REGNO (SUBREG_REG (out)) + SUBREG_WORD (out)); + out = gen_rtx_REG (GET_MODE (out), subreg_regno (out)); /* Narrow down the class of register wanted if that is desirable on this machine for efficiency. */ @@ -1810,15 +1811,28 @@ find_dummy_reload (real_in, real_out, inloc, outloc, || GET_MODE_SIZE (inmode) > UNITS_PER_WORD)) return 0; + /* Note that {in,out}_offset are needed only when 'in' or 'out' + respectively refers to a hard register. */ + /* Find the inside of any subregs. */ while (GET_CODE (out) == SUBREG) { - out_offset = SUBREG_WORD (out); + if (GET_CODE (SUBREG_REG (out)) == REG + && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER) + out_offset += subreg_regno_offset (REGNO (SUBREG_REG (out)), + GET_MODE (SUBREG_REG (out)), + SUBREG_BYTE (out), + GET_MODE (out)); out = SUBREG_REG (out); } while (GET_CODE (in) == SUBREG) { - in_offset = SUBREG_WORD (in); + if (GET_CODE (SUBREG_REG (in)) == REG + && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER) + in_offset += subreg_regno_offset (REGNO (SUBREG_REG (in)), + GET_MODE (SUBREG_REG (in)), + SUBREG_BYTE (in), + GET_MODE (in)); in = SUBREG_REG (in); } @@ -2035,7 +2049,10 @@ operands_match_p (x, y) i = REGNO (SUBREG_REG (x)); if (i >= FIRST_PSEUDO_REGISTER) goto slow; - i += SUBREG_WORD (x); + i += subreg_regno_offset (REGNO (SUBREG_REG (x)), + GET_MODE (SUBREG_REG (x)), + SUBREG_BYTE (x), + GET_MODE (x)); } else i = REGNO (x); @@ -2045,7 +2062,10 @@ operands_match_p (x, y) j = REGNO (SUBREG_REG (y)); if (j >= FIRST_PSEUDO_REGISTER) goto slow; - j += SUBREG_WORD (y); + j += subreg_regno_offset (REGNO (SUBREG_REG (y)), + GET_MODE (SUBREG_REG (y)), + SUBREG_BYTE (y), + GET_MODE (y)); } else j = REGNO (y); @@ -2777,7 +2797,18 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) while (GET_CODE (operand) == SUBREG) { - offset += SUBREG_WORD (operand); + /* Offset only matters when operand is a REG and + it is a hard reg. This is because it is passed + to reg_fits_class_p if it is a REG and all pseudos + return 0 from that function. */ + if (GET_CODE (SUBREG_REG (operand)) == REG + && REGNO (SUBREG_REG (operand)) < FIRST_PSEUDO_REGISTER) + { + offset += subreg_regno_offset (REGNO (SUBREG_REG (operand)), + GET_MODE (SUBREG_REG (operand)), + SUBREG_BYTE (operand), + GET_MODE (operand)); + } operand = SUBREG_REG (operand); /* Force reload if this is a constant or PLUS or if there may be a problem accessing OPERAND in the outer mode. */ @@ -2828,6 +2859,11 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) ) #endif ) + /* This following hunk of code should no longer be + needed at all with SUBREG_BYTE. If you need this + code back, please explain to me why so I can + fix the real problem. -DaveM */ +#if 0 /* Subreg of a hard reg which can't handle the subreg's mode or which would handle that mode in the wrong number of registers for subregging to work. */ @@ -2841,7 +2877,9 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) != HARD_REGNO_NREGS (REGNO (operand), GET_MODE (operand)))) || ! HARD_REGNO_MODE_OK (REGNO (operand) + offset, - operand_mode[i])))) + operand_mode[i]))) +#endif + ) force_reload = 1; } @@ -3716,7 +3754,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) rtx operand = recog_data.operand[i]; while (GET_CODE (operand) == SUBREG) - operand = XEXP (operand, 0); + operand = SUBREG_REG (operand); if ((GET_CODE (operand) == MEM || (GET_CODE (operand) == REG && REGNO (operand) >= FIRST_PSEUDO_REGISTER)) @@ -3766,7 +3804,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) operand = *recog_data.operand_loc[i]; while (GET_CODE (operand) == SUBREG) - operand = XEXP (operand, 0); + operand = SUBREG_REG (operand); if (GET_CODE (operand) == REG) { if (modified[i] != RELOAD_WRITE) @@ -3789,7 +3827,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p) rtx operand = recog_data.operand[i]; while (GET_CODE (operand) == SUBREG) - operand = XEXP (operand, 0); + operand = SUBREG_REG (operand); if ((GET_CODE (operand) == MEM || (GET_CODE (operand) == REG && REGNO (operand) >= FIRST_PSEUDO_REGISTER)) @@ -4303,7 +4341,7 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest, insn, && regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0 && reg_equiv_constant[regno] != 0 && (tem = operand_subword (reg_equiv_constant[regno], - SUBREG_WORD (x), 0, + SUBREG_BYTE (x) / UNITS_PER_WORD, 0, GET_MODE (SUBREG_REG (x)))) != 0) { /* TEM is now a word sized constant for the bits from X that @@ -4329,7 +4367,7 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest, insn, && (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))) { - int shift = SUBREG_WORD (x) * BITS_PER_WORD; + int shift = SUBREG_BYTE (x) * BITS_PER_UNIT; if (WORDS_BIG_ENDIAN) shift = (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) - GET_MODE_BITSIZE (GET_MODE (x)) @@ -4383,13 +4421,18 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest, insn, the meaning of the memory access. */ enum machine_mode subreg_mode = GET_MODE (SUBREG_REG (x)); + /* SUBREG_REG (x) is a MEM, so we cant take the offset, instead we + calculate the register number as : + SUBREG_BYTE (x) / GET_MODE_SIZE (subreg_mode) */ if (is_set_dest) push_reload (NULL_RTX, SUBREG_REG (x), NULL_PTR, &SUBREG_REG (x), - find_valid_class (subreg_mode, SUBREG_WORD (x)), + find_valid_class (subreg_mode, + SUBREG_BYTE (x) / GET_MODE_SIZE (subreg_mode)), VOIDmode, subreg_mode, 0, 0, opnum, type); else push_reload (SUBREG_REG (x), NULL_RTX, &SUBREG_REG (x), NULL_PTR, - find_valid_class (subreg_mode, SUBREG_WORD (x)), + find_valid_class (subreg_mode, + SUBREG_BYTE (x) / GET_MODE_SIZE (subreg_mode)), subreg_mode, VOIDmode, 0, 0, opnum, type); } @@ -5075,7 +5118,11 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn) code0 = GET_CODE (op0); if (code0 == REG && REGNO (op0) < FIRST_PSEUDO_REGISTER) op0 = gen_rtx_REG (word_mode, - REGNO (op0) + SUBREG_WORD (orig_op0)); + (REGNO (op0) + + subreg_regno_offset (REGNO (SUBREG_REG (orig_op0)), + GET_MODE (SUBREG_REG (orig_op0)), + SUBREG_BYTE (orig_op0), + GET_MODE (orig_op0)))); } if (GET_CODE (op1) == SUBREG) @@ -5083,8 +5130,14 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn) op1 = SUBREG_REG (op1); code1 = GET_CODE (op1); if (code1 == REG && REGNO (op1) < FIRST_PSEUDO_REGISTER) + /* ??? Why is this given op1's mode and above for + ??? op0 SUBREGs we use word_mode? */ op1 = gen_rtx_REG (GET_MODE (op1), - REGNO (op1) + SUBREG_WORD (orig_op1)); + (REGNO (op1) + + subreg_regno_offset (REGNO (SUBREG_REG (orig_op1)), + GET_MODE (SUBREG_REG (orig_op1)), + SUBREG_BYTE (orig_op1), + GET_MODE (orig_op1)))); } if (code0 == MULT || code0 == SIGN_EXTEND || code0 == TRUNCATE @@ -5492,7 +5545,7 @@ find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn) needless copies if SUBREG_REG is multi-word. */ if (REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER) { - int regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x); + int regno = subreg_regno (x); if (! (context ? REGNO_OK_FOR_INDEX_P (regno) : REGNO_MODE_OK_FOR_BASE_P (regno, mode))) @@ -5646,15 +5699,10 @@ find_reloads_subreg_address (x, force_replace, opnum, type, if (force_replace || ! rtx_equal_p (tem, reg_equiv_mem[regno])) { - int offset = SUBREG_WORD (x) * UNITS_PER_WORD; + int offset = SUBREG_BYTE (x); unsigned outer_size = GET_MODE_SIZE (GET_MODE (x)); unsigned inner_size = GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))); - if (BYTES_BIG_ENDIAN) - { - offset += MIN (inner_size, UNITS_PER_WORD); - offset -= MIN (outer_size, UNITS_PER_WORD); - } XEXP (tem, 0) = plus_constant (XEXP (tem, 0), offset); PUT_MODE (tem, GET_MODE (x)); @@ -5741,8 +5789,18 @@ subst_reloads (insn) *r->subreg_loc = SUBREG_REG (reloadreg); else { + int final_offset = + SUBREG_BYTE (*r->subreg_loc) + SUBREG_BYTE (reloadreg); + + /* When working with SUBREGs the rule is that the byte + offset must be a multiple of the SUBREG's mode. */ + final_offset = (final_offset / + GET_MODE_SIZE (GET_MODE (*r->subreg_loc))); + final_offset = (final_offset * + GET_MODE_SIZE (GET_MODE (*r->subreg_loc))); + *r->where = SUBREG_REG (reloadreg); - SUBREG_WORD (*r->subreg_loc) += SUBREG_WORD (reloadreg); + SUBREG_BYTE (*r->subreg_loc) = final_offset; } } else @@ -5843,12 +5901,24 @@ find_replacement (loc) if (GET_CODE (reloadreg) == REG) return gen_rtx_REG (GET_MODE (*loc), - REGNO (reloadreg) + SUBREG_WORD (*loc)); + (REGNO (reloadreg) + + subreg_regno_offset (REGNO (SUBREG_REG (*loc)), + GET_MODE (SUBREG_REG (*loc)), + SUBREG_BYTE (*loc), + GET_MODE (*loc)))); else if (GET_MODE (reloadreg) == GET_MODE (*loc)) return reloadreg; else - return gen_rtx_SUBREG (GET_MODE (*loc), SUBREG_REG (reloadreg), - SUBREG_WORD (reloadreg) + SUBREG_WORD (*loc)); + { + int final_offset = SUBREG_BYTE (reloadreg) + SUBREG_BYTE (*loc); + + /* When working with SUBREGs the rule is that the byte + offset must be a multiple of the SUBREG's mode. */ + final_offset = (final_offset / GET_MODE_SIZE (GET_MODE (*loc))); + final_offset = (final_offset * GET_MODE_SIZE (GET_MODE (*loc))); + return gen_rtx_SUBREG (GET_MODE (*loc), SUBREG_REG (reloadreg), + final_offset); + } } } @@ -5925,7 +5995,7 @@ refers_to_regno_for_reload_p (regno, endregno, x, loc) if (GET_CODE (SUBREG_REG (x)) == REG && REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER) { - unsigned int inner_regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x); + unsigned int inner_regno = subreg_regno (x); unsigned int inner_endregno = inner_regno + (inner_regno < FIRST_PSEUDO_REGISTER ? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1); @@ -6020,7 +6090,10 @@ reg_overlap_mentioned_for_reload_p (x, in) { regno = REGNO (SUBREG_REG (x)); if (regno < FIRST_PSEUDO_REGISTER) - regno += SUBREG_WORD (x); + regno += subreg_regno_offset (REGNO (SUBREG_REG (x)), + GET_MODE (SUBREG_REG (x)), + SUBREG_BYTE (x), + GET_MODE (x)); } else if (GET_CODE (x) == REG) { diff --git a/gcc/reload1.c b/gcc/reload1.c index 6194b875244f..16cc3be5d605 100644 --- a/gcc/reload1.c +++ b/gcc/reload1.c @@ -2509,7 +2509,7 @@ eliminate_regs (x, mem_mode, insn) return x; case SUBREG: - /* Similar to above processing, but preserve SUBREG_WORD. + /* Similar to above processing, but preserve SUBREG_BYTE. Convert (subreg (mem)) to (mem) if not paradoxical. Also, if we have a non-paradoxical (subreg (pseudo)) and the pseudo didn't get a hard reg, we must replace this with the @@ -2526,7 +2526,7 @@ eliminate_regs (x, mem_mode, insn) else new = eliminate_regs (SUBREG_REG (x), mem_mode, insn); - if (new != XEXP (x, 0)) + if (new != SUBREG_REG (x)) { int x_size = GET_MODE_SIZE (GET_MODE (x)); int new_size = GET_MODE_SIZE (GET_MODE (new)); @@ -2547,20 +2547,15 @@ eliminate_regs (x, mem_mode, insn) || (x_size == new_size)) ) { - int offset = SUBREG_WORD (x) * UNITS_PER_WORD; + int offset = SUBREG_BYTE (x); enum machine_mode mode = GET_MODE (x); - if (BYTES_BIG_ENDIAN) - offset += (MIN (UNITS_PER_WORD, - GET_MODE_SIZE (GET_MODE (new))) - - MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode))); - PUT_MODE (new, mode); XEXP (new, 0) = plus_constant (XEXP (new, 0), offset); return new; } else - return gen_rtx_SUBREG (GET_MODE (x), new, SUBREG_WORD (x)); + return gen_rtx_SUBREG (GET_MODE (x), new, SUBREG_BYTE (x)); } return x; @@ -4088,10 +4083,14 @@ forget_old_reloads_1 (x, ignored, data) unsigned int nr; int offset = 0; - /* note_stores does give us subregs of hard regs. */ + /* note_stores does give us subregs of hard regs, + subreg_regno_offset will abort if it is not a hard reg. */ while (GET_CODE (x) == SUBREG) { - offset += SUBREG_WORD (x); + offset += subreg_regno_offset (REGNO (SUBREG_REG (x)), + GET_MODE (SUBREG_REG (x)), + SUBREG_BYTE (x), + GET_MODE (x)); x = SUBREG_REG (x); } @@ -5401,7 +5400,7 @@ choose_reload_regs (chain) if (inheritance) { - int word = 0; + int byte = 0; register int regno = -1; enum machine_mode mode = VOIDmode; @@ -5420,10 +5419,10 @@ choose_reload_regs (chain) else if (GET_CODE (rld[r].in_reg) == SUBREG && GET_CODE (SUBREG_REG (rld[r].in_reg)) == REG) { - word = SUBREG_WORD (rld[r].in_reg); + byte = SUBREG_BYTE (rld[r].in_reg); regno = REGNO (SUBREG_REG (rld[r].in_reg)); if (regno < FIRST_PSEUDO_REGISTER) - regno += word; + regno = subreg_regno (rld[r].in_reg); mode = GET_MODE (rld[r].in_reg); } #ifdef AUTO_INC_DEC @@ -5444,7 +5443,7 @@ choose_reload_regs (chain) that can invalidate an inherited reload of part of a pseudoreg. */ else if (GET_CODE (rld[r].in) == SUBREG && GET_CODE (SUBREG_REG (rld[r].in)) == REG) - regno = REGNO (SUBREG_REG (rld[r].in)) + SUBREG_WORD (rld[r].in); + regno = subreg_regno (rld[r].in); #endif if (regno >= 0 && reg_last_reload_reg[regno] != 0) @@ -5453,15 +5452,15 @@ choose_reload_regs (chain) rtx last_reg = reg_last_reload_reg[regno]; enum machine_mode need_mode; - i = REGNO (last_reg) + word; + i = REGNO (last_reg); + i += subreg_regno_offset (i, GET_MODE (last_reg), byte, mode); last_class = REGNO_REG_CLASS (i); - if (word == 0) + if (byte == 0) need_mode = mode; else need_mode - = smallest_mode_for_size (GET_MODE_SIZE (mode) - + word * UNITS_PER_WORD, + = smallest_mode_for_size (GET_MODE_SIZE (mode) + byte, GET_MODE_CLASS (mode)); if ( @@ -5631,7 +5630,7 @@ choose_reload_regs (chain) Make a new REG since this might be used in an address and not all machines support SUBREGs there. */ - regno = REGNO (SUBREG_REG (equiv)) + SUBREG_WORD (equiv); + regno = subreg_regno (equiv); equiv = gen_rtx_REG (rld[r].mode, regno); } else @@ -6261,7 +6260,7 @@ emit_input_reload_insns (chain, rl, old, j) oldequiv = SUBREG_REG (oldequiv); if (GET_MODE (oldequiv) != VOIDmode && mode != GET_MODE (oldequiv)) - oldequiv = gen_rtx_SUBREG (mode, oldequiv, 0); + oldequiv = gen_lowpart_SUBREG (mode, oldequiv); /* Switch to the right place to emit the reload insns. */ switch (rl->when_needed) @@ -8885,7 +8884,10 @@ reload_combine_note_store (dst, set, data) if (GET_CODE (dst) == SUBREG) { - regno = SUBREG_WORD (dst); + regno = subreg_regno_offset (REGNO (SUBREG_REG (dst)), + GET_MODE (SUBREG_REG (dst)), + SUBREG_BYTE (dst), + GET_MODE (dst)); dst = SUBREG_REG (dst); } if (GET_CODE (dst) != REG) @@ -9276,7 +9278,10 @@ move2add_note_store (dst, set, data) if (GET_CODE (dst) == SUBREG) { - regno = SUBREG_WORD (dst); + regno = subreg_regno_offset (REGNO (SUBREG_REG (dst)), + GET_MODE (SUBREG_REG (dst)), + SUBREG_BYTE (dst), + GET_MODE (dst)); dst = SUBREG_REG (dst); } diff --git a/gcc/resource.c b/gcc/resource.c index 0b3a892ce2ca..17f7d034d93d 100644 --- a/gcc/resource.c +++ b/gcc/resource.c @@ -100,7 +100,7 @@ update_live_status (dest, x, data) return; if (GET_CODE (dest) == SUBREG) - first_regno = REGNO (SUBREG_REG (dest)) + SUBREG_WORD (dest); + first_regno = subreg_regno (dest); else first_regno = REGNO (dest); @@ -222,7 +222,7 @@ mark_referenced_resources (x, res, include_delayed_effects) mark_referenced_resources (SUBREG_REG (x), res, 0); else { - unsigned int regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x); + unsigned int regno = subreg_regno (x); unsigned int last_regno = regno + HARD_REGNO_NREGS (regno, GET_MODE (x)); @@ -780,7 +780,7 @@ mark_set_resources (x, res, in_dest, mark_type) mark_set_resources (SUBREG_REG (x), res, in_dest, mark_type); else { - unsigned int regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x); + unsigned int regno = subreg_regno (x); unsigned int last_regno = regno + HARD_REGNO_NREGS (regno, GET_MODE (x)); diff --git a/gcc/rtl.h b/gcc/rtl.h index dbadd70f9583..e4f2ab037141 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -789,10 +789,17 @@ extern const char * const note_insn_name[NOTE_INSN_MAX - NOTE_INSN_BIAS]; #define CONST_DOUBLE_MEM(r) XCEXP (r, 0, CONST_DOUBLE) /* For a SUBREG rtx, SUBREG_REG extracts the value we want a subreg of. - SUBREG_WORD extracts the word-number. */ + SUBREG_BYTE extracts the byte-number. */ #define SUBREG_REG(RTX) XCEXP(RTX, 0, SUBREG) -#define SUBREG_WORD(RTX) XCUINT(RTX, 1, SUBREG) +#define SUBREG_BYTE(RTX) XCUINT(RTX, 1, SUBREG) + +/* in rtlanal.c */ +extern unsigned int subreg_regno_offset PARAMS ((unsigned int, + enum machine_mode, + unsigned int, + enum machine_mode)); +extern unsigned int subreg_regno PARAMS ((rtx)); /* 1 if the REG contained in SUBREG_REG is already known to be sign- or zero-extended from the mode of the SUBREG to the mode of @@ -1179,6 +1186,7 @@ extern int rtx_equal_p PARAMS ((rtx, rtx)); extern rtvec gen_rtvec_v PARAMS ((int, rtx *)); extern rtx gen_reg_rtx PARAMS ((enum machine_mode)); extern rtx gen_label_rtx PARAMS ((void)); +extern int subreg_hard_regno PARAMS ((rtx, int)); extern rtx gen_lowpart_common PARAMS ((enum machine_mode, rtx)); extern rtx gen_lowpart PARAMS ((enum machine_mode, rtx)); @@ -1191,6 +1199,8 @@ extern rtx gen_realpart PARAMS ((enum machine_mode, rtx)); extern rtx gen_imagpart PARAMS ((enum machine_mode, rtx)); extern rtx operand_subword PARAMS ((rtx, unsigned int, int, enum machine_mode)); +extern rtx constant_subword PARAMS ((rtx, int, + enum machine_mode)); /* In emit-rtl.c */ extern rtx operand_subword_force PARAMS ((rtx, unsigned int, @@ -1569,8 +1579,11 @@ extern rtx gen_rtx_CONST_DOUBLE PARAMS ((enum machine_mode, rtx, extern rtx gen_rtx_CONST_INT PARAMS ((enum machine_mode, HOST_WIDE_INT)); extern rtx gen_raw_REG PARAMS ((enum machine_mode, int)); extern rtx gen_rtx_REG PARAMS ((enum machine_mode, int)); +extern rtx gen_rtx_SUBREG PARAMS ((enum machine_mode, rtx, int)); extern rtx gen_rtx_MEM PARAMS ((enum machine_mode, rtx)); +extern rtx gen_lowpart_SUBREG PARAMS ((enum machine_mode, rtx)); + /* We need the cast here to ensure that we get the same result both with and without prototypes. */ #define GEN_INT(N) gen_rtx_CONST_INT (VOIDmode, (HOST_WIDE_INT) (N)) diff --git a/gcc/rtl.texi b/gcc/rtl.texi index cfae3a9b9873..665a40766c7e 100644 --- a/gcc/rtl.texi +++ b/gcc/rtl.texi @@ -1166,16 +1166,16 @@ This virtual register is replaced by the sum of the register given by @end table @findex subreg -@item (subreg:@var{m} @var{reg} @var{wordnum}) +@item (subreg:@var{m} @var{reg} @var{bytenum}) @code{subreg} expressions are used to refer to a register in a machine mode other than its natural one, or to refer to one register of -a multi-word @code{reg} that actually refers to several registers. +a multi-part @code{reg} that actually refers to several registers. Each pseudo-register has a natural mode. If it is necessary to operate on it in a different mode---for example, to perform a fullword move instruction on a pseudo-register that contains a single byte---the pseudo-register must be enclosed in a @code{subreg}. In -such a case, @var{wordnum} is zero. +such a case, @var{bytenum} is zero. Usually @var{m} is at least as narrow as the mode of @var{reg}, in which case it is restricting consideration to only the bits of @var{reg} that @@ -1192,7 +1192,7 @@ a multi-register value. Machine modes such as @code{DImode} and @code{TImode} can indicate values longer than a word, values which usually require two or more consecutive registers. To access one of the registers, use a @code{subreg} with mode @code{SImode} and a -@var{wordnum} that says which register. +@var{bytenum} offset that says which register. Storing in a non-paradoxical @code{subreg} has undefined results for bits belonging to the same word as the @code{subreg}. This laxity makes @@ -1202,8 +1202,13 @@ the @code{subreg}, use @code{strict_low_part} around the @code{subreg}. @cindex @code{WORDS_BIG_ENDIAN}, effect on @code{subreg} The compilation parameter @code{WORDS_BIG_ENDIAN}, if set to 1, says -that word number zero is the most significant part; otherwise, it is -the least significant part. +that byte number zero is part of the most significant word; otherwise, +it is part of the least significant word. + +@cindex @code{BYTES_BIG_ENDIAN}, effect on @code{subreg} +The compilation parameter @code{BYTES_BIG_ENDIAN}, if set to 1, says +that byte number zero is the most significant byte within a word; +otherwise, it is the least significant byte within a word. @cindex @code{FLOAT_WORDS_BIG_ENDIAN}, (lack of) effect on @code{subreg} On a few targets, @code{FLOAT_WORDS_BIG_ENDIAN} disagrees with @@ -1239,10 +1244,10 @@ a single machine register. The reload pass prevents @code{subreg} expressions such as these from being formed. @findex SUBREG_REG -@findex SUBREG_WORD +@findex SUBREG_BYTE The first operand of a @code{subreg} expression is customarily accessed with the @code{SUBREG_REG} macro and the second operand is customarily -accessed with the @code{SUBREG_WORD} macro. +accessed with the @code{SUBREG_BYTE} macro. @findex scratch @cindex scratch operands diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index db8e69680102..36c3c9ff42f2 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -1083,7 +1083,7 @@ refers_to_regno_p (regno, endregno, x, loc) if (GET_CODE (SUBREG_REG (x)) == REG && REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER) { - unsigned int inner_regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x); + unsigned int inner_regno = subreg_regno (x); unsigned int inner_endregno = inner_regno + (inner_regno < FIRST_PSEUDO_REGISTER ? HARD_REGNO_NREGS (regno, GET_MODE (x)) : 1); @@ -1170,7 +1170,7 @@ reg_overlap_mentioned_p (x, in) case SUBREG: regno = REGNO (SUBREG_REG (x)); if (regno < FIRST_PSEUDO_REGISTER) - regno += SUBREG_WORD (x); + regno = subreg_regno (x); goto do_reg; case REG: @@ -2229,18 +2229,32 @@ replace_regs (x, reg_map, nregs, replace_dest) return map_inner; else { + int final_offset = SUBREG_BYTE (x) + SUBREG_BYTE (map_val); + + /* When working with REG SUBREGs the rule is that the byte + offset must be a multiple of the SUBREG's mode. */ + final_offset = (final_offset / GET_MODE_SIZE (GET_MODE (x))); + final_offset = (final_offset * GET_MODE_SIZE (GET_MODE (x))); + /* We cannot call gen_rtx here since we may be linked with genattrtab.c. */ /* Let's try clobbering the incoming SUBREG and see if this is really safe. */ SUBREG_REG (x) = map_inner; - SUBREG_WORD (x) += SUBREG_WORD (map_val); + SUBREG_BYTE (x) = final_offset; return x; #if 0 rtx new = rtx_alloc (SUBREG); + int final_offset = SUBREG_BYTE (x) + SUBREG_BYTE (map_val); + + /* When working with REG SUBREGs the rule is that the byte + offset must be a multiple of the SUBREG's mode. */ + final_offset = (final_offset / GET_MODE_SIZE (GET_MODE (x))); + final_offset = (final_offset * GET_MODE_SIZE (GET_MODE (x))); + PUT_MODE (new, GET_MODE (x)); SUBREG_REG (new) = map_inner; - SUBREG_WORD (new) = SUBREG_WORD (x) + SUBREG_WORD (map_val); + SUBREG_BYTE (new) = final_offset; #endif } } @@ -2613,3 +2627,65 @@ loc_mentioned_in_p (loc, in) } return 0; } + +/* This function returns the regno offset of a subreg expression. + xregno - A regno of an inner hard subreg_reg (or what will become one). + xmode - The mode of xregno. + offset - The byte offset. + ymode - The mode of a top level SUBREG (or what may become one). + RETURN - The regno offset which would be used. + This function can be overridden by defining SUBREG_REGNO_OFFSET, + taking the same parameters. */ +unsigned int +subreg_regno_offset (xregno, xmode, offset, ymode) + unsigned int xregno; + enum machine_mode xmode; + unsigned int offset; + enum machine_mode ymode; +{ + unsigned ret; + int nregs_xmode, nregs_ymode; + int mode_multiple, nregs_multiple; + int y_offset; + +/* Check for an override, and use it instead. */ +#ifdef SUBREG_REGNO_OFFSET + ret = SUBREG_REGNO_OFFSET (xregno, xmode, offset, ymode) +#else + if (xregno >= FIRST_PSEUDO_REGISTER) + abort (); + + nregs_xmode = HARD_REGNO_NREGS (xregno, xmode); + nregs_ymode = HARD_REGNO_NREGS (xregno, ymode); + if (offset == 0 || nregs_xmode == nregs_ymode) + return 0; + + /* size of ymode must not be greater than the size of xmode. */ + mode_multiple = GET_MODE_SIZE (xmode) / GET_MODE_SIZE (ymode); + if (mode_multiple == 0) + abort (); + + y_offset = offset / GET_MODE_SIZE (ymode); + nregs_multiple = nregs_xmode / nregs_ymode; + ret = (y_offset / (mode_multiple / nregs_multiple)) * nregs_ymode; +#endif + + return ret; +} + +/* Return the final regno that a subreg expression refers to. */ +unsigned int +subreg_regno (x) + rtx x; +{ + unsigned int ret; + rtx subreg = SUBREG_REG (x); + int regno = REGNO (subreg); + + ret = regno + subreg_regno_offset (regno, + GET_MODE (subreg), + SUBREG_BYTE (x), + GET_MODE (x)); + return ret; + +} diff --git a/gcc/sched-vis.c b/gcc/sched-vis.c index 4cd07790130a..4aad9f931c1e 100644 --- a/gcc/sched-vis.c +++ b/gcc/sched-vis.c @@ -591,7 +591,7 @@ print_value (buf, x, verbose) case SUBREG: print_value (t, SUBREG_REG (x), verbose); cur = safe_concat (buf, cur, t); - sprintf (t, "#%d", SUBREG_WORD (x)); + sprintf (t, "#%d", SUBREG_BYTE (x)); cur = safe_concat (buf, cur, t); break; case SCRATCH: diff --git a/gcc/sdbout.c b/gcc/sdbout.c index 649bc0aa67d5..dfccee06f796 100644 --- a/gcc/sdbout.c +++ b/gcc/sdbout.c @@ -776,19 +776,15 @@ sdbout_symbol (decl, local) else if (GET_CODE (value) == SUBREG) { int offset = 0; + while (GET_CODE (value) == SUBREG) - { - offset += SUBREG_WORD (value); - value = SUBREG_REG (value); - } + value = SUBREG_REG (value); if (GET_CODE (value) == REG) { - regno = REGNO (value); - if (regno >= FIRST_PSEUDO_REGISTER) + if (REGNO (value) >= FIRST_PSEUDO_REGISTER) return; - regno += offset; } - alter_subreg (DECL_RTL (decl)); + regno = REGNO (alter_subreg (DECL_RTL (decl))); value = DECL_RTL (decl); } /* Don't output anything if an auto variable diff --git a/gcc/stmt.c b/gcc/stmt.c index 12f1562cbf6b..e9c49dcffd41 100644 --- a/gcc/stmt.c +++ b/gcc/stmt.c @@ -4166,7 +4166,7 @@ expand_anon_union_decl (decl, cleanup, decl_elts) if (mode == GET_MODE (x)) SET_DECL_RTL (decl_elt, x); else - SET_DECL_RTL (decl_elt, gen_rtx_SUBREG (mode, x, 0)); + SET_DECL_RTL (decl_elt, gen_lowpart_SUBREG (mode, x)); } else abort (); diff --git a/gcc/tm.texi b/gcc/tm.texi index e3dd5309b20b..1956979f1bde 100644 --- a/gcc/tm.texi +++ b/gcc/tm.texi @@ -1697,17 +1697,6 @@ definition of this macro is / UNITS_PER_WORD) @end smallexample -@findex ALTER_HARD_SUBREG -@item ALTER_HARD_SUBREG (@var{tgt_mode}, @var{word}, @var{src_mode}, @var{regno}) -A C expression that returns an adjusted hard register number for - -@smallexample -(subreg:@var{tgt_mode} (reg:@var{src_mode} @var{regno}) @var{word}) -@end smallexample - -This may be needed if the target machine has mixed sized big-endian -registers, like Sparc v9. - @findex HARD_REGNO_MODE_OK @item HARD_REGNO_MODE_OK (@var{regno}, @var{mode}) A C expression that is nonzero if it is permissible to store a value @@ -1790,6 +1779,19 @@ allocation. Define this macro if the compiler should avoid copies to/from @code{CCmode} registers. You should only define this macro if support for copying to/from @code{CCmode} is incomplete. + +@findex SUBREG_REGNO_OFFSET +@item SUBREG_REGNO_OFFSET +Define this macro if the compiler needs to handle subregs in a non-standard +way. The macro returns the correct regno offset for mode @code{YMODE} given +a subreg of type @code{XMODE}. +This macro takes 4 parameters: +@code{XREGNO} - A regno of an inner hard subreg_reg (or what will become one). +@code{XMODE} - The mode of xregno. +@code{OFFSET} - The byte offset. +@code{YMODE} - The mode of a top level SUBREG (or what may become one). +The default function can be found in rtlanal.c, function +@code{subreg_regno_offset}. Normally this does not need to be defined. @end table @node Leaf Functions -- 2.43.5