This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

subreg byte



A bit over a week ago, I submitted an updated version of the subreg-byte 
patch. Here's a new copy of it incorporating a couple of minor 
changes that have happened to the tree since then.

I have also verified that it bootstraps on both 
  ia64-linux
  mips-sgi-irix6.3
in addition to the previous list with no additional changes.


-- MacLeod

--------------------------

Perhaps its time we attempted to integrate the subreg-byte work into
the mainline gcc tree. The initial work was done a few years ago, then Jakub
maintained it for quite some time. I did some work on it last summer,
and rth created a branch off of gcc last fall (subreg-byte-branch), and
applied to patch to it. 

And thats as far as it progressed. Over the past few weeks I've been 
working with it again, building and running it on as many targets as
I can. I've also gone through all the changelogs and merged them together
into one sensible organized entry. 

- This patch bootstraps on
  alpha-linux, 
  x86-linux,
  sparc-solaris,
  ia64-linux,
  mips-sgi-irix6.3

- This also runs with no extra failures on a number of other targets, including 
  ppc-elf
  sh-elf
and a couple of others I dont remember.

- I have also attempted to at least build the compiler on every target
  which the patch touches plus a few others. I think I built it on about 16 
  additional targets to the ones listed above. Some targets I couldnt 
  successfully build on out of the source tree, but the patched branch 
  built to the same point that the original did.

For those that aren't familiar with this, it changes the behaviour of a 
SUBREG. A SUBREG specifies the word offset that we take the subreg from. 
With all the odd combinations of bytes and words we now run across, and
64 bit targets, a word offset is no longer sufficient. (I beleive Jakub 
has been diligently maintaining this for a long time for sparc64 since it 
needs it to work correctly). This patch changes it such that a SUBREG now 
specifies a BYTE offset instead. Of course it touches most parts of the 
compiler, and I suspect the sheer breadth of its coverage is the main reason 
it hasnt been integrated yet... its just no fun dealing with it :-)

The vast majority of the patch has been reviewed by rth already, and his
comments integrated.
 
The patch is big........


-- MacLeod


2001-03-07  Jakub Jelinek  <jakub@redhat.com>
	    David S. Miller  <davem@pierdol.cobaltmicro.com>
            Andrew MacLeod  <amacleod@redhat.com>

	Use byte offsets in SUBREGs instead of words.

	* alias.c (nonlocal_mentioned_p): Use subreg_regno function.
	* caller-save.c (mark_set_regs): Change callers of subreg_hard_regno
	to pass new argument.
	(add_stored_regs): Use subreg_regno_offset function.
	* calls.c (expand_call): For non-paradoxical SUBREG take endianess
	into account.
	(precompute_arguments): Use gen_lowpart_SUBREG.
	* combine.c (try_combine): Replace explicit XEXP with SUBREG_REG.
	(combine_simplify_rtx): Rework to use SUBREG_BYTE.
	(simplify_set): Rework to use SUBREG_BYTE.
	(expand_field_assignment): Use SUBREG_BYTE.
	(make_extraction): Use SUBREG_BYTE.
	(if_then_else_cond): Use SUBREG_BYTE.
	(apply_distributive_law): Use SUBREG_BYTE and fixup subreg comments.
	(gen_lowpart_for_combine): Compute full byte offset.
	* cse.c (mention_regs): Use SUBREG_BYTE.
	(remove_invalid_subreg_refs): Rework to use SUBREG_BYTE.
	(canon_hash): Use SUBREG_BYTE.
	(fold_rtx): Pass SUBREG_BYTE div UNITS_PER_WORD to operand_subword.
	(gen_lowpart_if_possible): Formatting.
	* dbxout.c (dbxout_symbol_location): Compute SUBREG hard regnos
	correctly.
	* dwarf2out.c (is_pseudo_reg): Fixup explicit XEXP into SUBREG_REG
	(mem_loc_descriptor): Fixup explicit XEXP into SUBREG_REG
	(loc_descriptor): Fixup explicit XEXP into SUBREG_REG
	* dwarfout.c (is_pseudo_reg): Fixup explicit XEXP into SUBREG_REG
	(output_mem_loc_descriptor): Fixup explicit XEXP into SUBREG_REG
	(output_loc_descriptor): Fixup explicit XEXP into SUBREG_REG
	* emit-rtl.c (gen_rtx_SUBREG): New function, used to verify
	certain invariants about SUBREGs the compiler creates.
	(gen_lowpart_SUBREG): New function.
	(subreg_hard_regno): New function to get the final register number.
	(gen_lowpart_common): Use SUBREG_BYTE.
	(gen_imagpart): Spacing nits.
	(subreg_realpart_p): Use SUBREG_BYTE.
	(gen_highpart): Use SUBREG_BYTE.
	(subreg_lowpart_p): Always compute endian corrected goal offset,
	even at the byte level, then compare against that.
	(constant_subword): New function, pulled out all constant cases
	from operand_subword and changed second argument name to offset.
	(operand_subword): Detect non REG/SUBREG/CONCAT/MEM cases early
	and call constant_subword to do the work.  Return const0_rtx if 
	looking for a word outside of OP.
	(operand_subword_force): Change second arg name to offset.
	* expmed.c (store_bit_field): Use SUBREG_BYTE.
	(store_split_bit_field): Use SUBREG_BYTE.
	(extract_bit_field): Use SUBREG_BYTE.
	(extract_split_bit_field): Use SUBREG_BYTE.
	(expand_shift): Use SUBREG_BYTE.
	* expr.c (store_expr, expand_expr): Use gen_lowpart_SUBREG. 
	* final.c (alter_subreg) Use subreg_hard_regno and SUBREG_BYTE.
	* flow.c (set_noop_p): Use SUBREG_BYTE.
	(mark_set_1): Remove ALTER_HARD_SUBREG. Use subreg_regno_offset instead.
	* function.c (fixup_var_refs_1): Fixup explicit XEXP into a SUBREG_REG.
	(fixup_memory_subreg): Use SUBREG_BYTE and remove byte endian
	correction code.
	(optimize_bit_field): Use SUBREG_BYTE.
	(purge_addressof_1): Use SUBREG_BYTE.
	(purge_single_hard_subreg_set): Use subreg_regno_offset function.
	(assign_params): Mark arguments SUBREG_PROMOTED_VAR_P if they are 
	actually promoted by the caller and PROMOTE_FOR_CALLS_ONLY is true.
	* gengenrtl.c (special_rtx): Add SUBREG.
	* global.c (mark_reg_store): Use SUBREG_BYTE.
	(set_preference): Rework to use subreg_regno_offset and SUBREG_BYTE.
	* 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.



Index: gcc/alias.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/alias.c,v
retrieving revision 1.118
diff -c -p -r1.118 alias.c
*** gcc/alias.c	2001/03/14 03:21:43	1.118
--- gcc/alias.c	2001/03/16 02:08:19
*************** nonlocal_mentioned_p (x)
*** 1881,1887 ****
  	{
  	  /* Global registers are not local.  */
  	  if (REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER
! 	      && global_regs[REGNO (SUBREG_REG (x)) + SUBREG_WORD (x)])
  	    return 1;
  	  return 0;
  	}
--- 1881,1887 ----
  	{
  	  /* Global registers are not local.  */
  	  if (REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER
! 	      && global_regs[subreg_regno (x)])
  	    return 1;
  	  return 0;
  	}
Index: gcc/caller-save.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/caller-save.c,v
retrieving revision 1.35
diff -c -p -r1.35 caller-save.c
*** gcc/caller-save.c	2001/02/28 21:32:54	1.35
--- gcc/caller-save.c	2001/03/16 02:08:19
*************** mark_set_regs (reg, setter, data)
*** 487,504 ****
  {
    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);
!     }
  
!   if (GET_CODE (reg) != REG || REGNO (reg) >= FIRST_PSEUDO_REGISTER)
      return;
  
-   regno = REGNO (reg) + word;
    endregno = regno + HARD_REGNO_NREGS (regno, mode);
  
    for (i = regno; i < endregno; i++)
--- 487,507 ----
  {
    register int regno, endregno, i;
    enum machine_mode mode = GET_MODE (reg);
  
    if (GET_CODE (reg) == SUBREG)
      {
!       rtx inner = SUBREG_REG (reg);
!       if (GET_CODE (inner) != REG || REGNO (inner) >= FIRST_PSEUDO_REGISTER)
! 	return;
  
!       regno = subreg_hard_regno (reg, 1);
!     }
!   else if (GET_CODE (reg) == REG
! 	   && REGNO (reg) < FIRST_PSEUDO_REGISTER)
!     regno = REGNO (reg);
!   else
      return;
  
    endregno = regno + HARD_REGNO_NREGS (regno, mode);
  
    for (i = regno; i < endregno; i++)
*************** add_stored_regs (reg, setter, data)
*** 517,537 ****
  {
    register int regno, endregno, i;
    enum machine_mode mode = GET_MODE (reg);
!   int word = 0;
  
    if (GET_CODE (setter) == CLOBBER)
      return;
  
!   while (GET_CODE (reg) == SUBREG)
      {
!       word += SUBREG_WORD (reg);
        reg = SUBREG_REG (reg);
      }
  
    if (GET_CODE (reg) != REG || REGNO (reg) >= FIRST_PSEUDO_REGISTER)
      return;
  
!   regno = REGNO (reg) + word;
    endregno = regno + HARD_REGNO_NREGS (regno, mode);
  
    for (i = regno; i < endregno; i++)
--- 520,543 ----
  {
    register int regno, endregno, i;
    enum machine_mode mode = GET_MODE (reg);
!   int offset = 0;
  
    if (GET_CODE (setter) == CLOBBER)
      return;
  
!   if (GET_CODE (reg) == SUBREG && GET_CODE (SUBREG_REG (reg)) == 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) + offset;
    endregno = regno + HARD_REGNO_NREGS (regno, mode);
  
    for (i = regno; i < endregno; i++)
Index: gcc/calls.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/calls.c,v
retrieving revision 1.176
diff -c -p -r1.176 calls.c
*** gcc/calls.c	2001/03/15 02:50:48	1.176
--- gcc/calls.c	2001/03/16 02:08:19
*************** precompute_arguments (flags, num_actuals
*** 1477,1482 ****
--- 1477,1484 ----
      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 ();
*************** precompute_arguments (flags, num_actuals
*** 1496,1506 ****
  	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)
  	  {
  	    args[i].value
! 	      = convert_modes (args[i].mode,
! 			       TYPE_MODE (TREE_TYPE (args[i].tree_value)),
  			       args[i].value, args[i].unsignedp);
  #ifdef PROMOTE_FOR_CALL_ONLY
  	    /* CSE will replace this only if it contains args[i].value
--- 1498,1508 ----
  	args[i].initial_value = args[i].value
  	  = protect_from_queue (args[i].value, 0);
  
! 	mode = TYPE_MODE (TREE_TYPE (args[i].tree_value));
! 	if (mode != args[i].mode)
  	  {
  	    args[i].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
*************** precompute_arguments (flags, num_actuals
*** 1510,1517 ****
  		&& 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);
  		SUBREG_PROMOTED_VAR_P (args[i].initial_value) = 1;
  		SUBREG_PROMOTED_UNSIGNED_P (args[i].initial_value)
  		  = args[i].unsignedp;
--- 1512,1518 ----
  		&& GET_MODE_CLASS (args[i].mode) == MODE_INT)
  	      {
  		args[i].initial_value
! 		  = 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;
*************** expand_call (exp, target, ignore)
*** 3287,3299 ****
  	{
  	  tree type = TREE_TYPE (exp);
  	  int unsignedp = TREE_UNSIGNED (type);
  
  	  /* 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);
  	  SUBREG_PROMOTED_VAR_P (target) = 1;
  	  SUBREG_PROMOTED_UNSIGNED_P (target) = unsignedp;
  	}
--- 3288,3312 ----
  	{
  	  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 ();
  
! 	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;
  	}
Index: gcc/combine.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/combine.c,v
retrieving revision 1.190
diff -c -p -r1.190 combine.c
*** gcc/combine.c	2001/03/11 22:08:12	1.190
--- gcc/combine.c	2001/03/16 02:08:20
*************** try_combine (i3, i2, i1, new_direct_jump
*** 2279,2285 ****
  	     be written as a ZERO_EXTEND.  */
  	  if (split_code == SUBREG && GET_CODE (SUBREG_REG (*split)) == MEM)
  	    SUBST (*split, gen_rtx_combine (ZERO_EXTEND, split_mode,
! 					    XEXP (*split, 0)));
  #endif
  
  	  newi2pat = gen_rtx_combine (SET, VOIDmode, newdest, *split);
--- 2279,2285 ----
  	     be written as a ZERO_EXTEND.  */
  	  if (split_code == SUBREG && GET_CODE (SUBREG_REG (*split)) == MEM)
  	    SUBST (*split, gen_rtx_combine (ZERO_EXTEND, split_mode,
! 					    SUBREG_REG (*split)));
  #endif
  
  	  newi2pat = gen_rtx_combine (SET, VOIDmode, newdest, *split);
*************** combine_simplify_rtx (x, op0_mode, last,
*** 3800,3826 ****
  	      <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
  	{
  	  rtx inner = SUBREG_REG (x);
! 	  int endian_offset = 0;
  	  /* 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)));
  	  MEM_COPY_ATTRIBUTES (x, inner);
  	  return x;
  	}
--- 3800,3816 ----
  	      <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
  	{
  	  rtx inner = SUBREG_REG (x);
! 	  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);
  
  	  /* 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), offset));
  	  MEM_COPY_ATTRIBUTES (x, inner);
  	  return x;
  	}
*************** combine_simplify_rtx (x, op0_mode, last,
*** 3833,3844 ****
  	 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));
  
! 	  SUBST_INT (SUBREG_WORD (x),
! 		     SUBREG_WORD (x) + SUBREG_WORD (SUBREG_REG (x)));
  	  SUBST (SUBREG_REG (x), SUBREG_REG (SUBREG_REG (x)));
  	}
  
--- 3823,3880 ----
  	 or not at all if changing back to starting mode.  */
        if (GET_CODE (SUBREG_REG (x)) == SUBREG)
  	{
! 	  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);
! 	    }
! 
! 	  /* 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)));
  	}
  
*************** combine_simplify_rtx (x, op0_mode, last,
*** 3858,3867 ****
  #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));
  	  else
  	    return gen_rtx_CLOBBER (mode, const0_rtx);
  	}
--- 3894,3903 ----
  #endif
  	  && REGNO (SUBREG_REG (x)) != STACK_POINTER_REGNUM)
  	{
! 	  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);
  	}
*************** combine_simplify_rtx (x, op0_mode, last,
*** 3876,3882 ****
  	  && GET_MODE_SIZE (op0_mode) > UNITS_PER_WORD
  	  && GET_MODE_CLASS (mode) == MODE_INT)
  	{
! 	  temp = operand_subword (SUBREG_REG (x), SUBREG_WORD (x),
  				  0, op0_mode);
  	  if (temp)
  	    return temp;
--- 3912,3919 ----
  	  && GET_MODE_SIZE (op0_mode) > UNITS_PER_WORD
  	  && GET_MODE_CLASS (mode) == MODE_INT)
  	{
! 	  temp = operand_subword (SUBREG_REG (x),
! 				  (SUBREG_BYTE (x) / UNITS_PER_WORD),
  				  0, op0_mode);
  	  if (temp)
  	    return temp;
*************** combine_simplify_rtx (x, op0_mode, last,
*** 3890,3900 ****
        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)))
  	  && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (op0_mode)
  	  && (! WORDS_BIG_ENDIAN
  	      || GET_MODE_BITSIZE (op0_mode) <= BITS_PER_WORD))
--- 3927,3935 ----
        if (CONSTANT_P (SUBREG_REG (x))
  	  && ((GET_MODE_SIZE (op0_mode) <= UNITS_PER_WORD
  	      || ! WORDS_BIG_ENDIAN)
! 	      ? 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))
*************** combine_simplify_rtx (x, op0_mode, last,
*** 3906,3913 ****
  	  && 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);
  	  return SUBREG_REG (x);
  	}
  
--- 3941,3949 ----
  	  && 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_BYTE (x) != 0))
! 	    return constant_subword (SUBREG_REG (x), 
! 				     SUBREG_BYTE (x) / UNITS_PER_WORD, mode);
  	  return SUBREG_REG (x);
  	}
  
*************** simplify_set (x)
*** 5181,5194 ****
  
    if (GET_CODE (src) == SUBREG && subreg_lowpart_p (src)
        && LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (src))) != NIL
!       && SUBREG_WORD (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_combine (LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (src))),
! 			      GET_MODE (src), XEXP (src, 0)));
  
        src = SET_SRC (x);
      }
--- 5217,5230 ----
  
    if (GET_CODE (src) == SUBREG && subreg_lowpart_p (src)
        && LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (src))) != NIL
!       && 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_combine (LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (src))),
! 			      GET_MODE (src), SUBREG_REG (src)));
  
        src = SET_SRC (x);
      }
*************** expand_field_assignment (x)
*** 5775,5783 ****
        if (GET_CODE (SET_DEST (x)) == STRICT_LOW_PART
  	  && GET_CODE (XEXP (SET_DEST (x), 0)) == SUBREG)
  	{
  	  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)));
  	}
        else if (GET_CODE (SET_DEST (x)) == ZERO_EXTRACT
  	       && GET_CODE (XEXP (SET_DEST (x), 1)) == CONST_INT)
--- 5811,5821 ----
        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 * (byte_offset / UNITS_PER_WORD));
  	}
        else if (GET_CODE (SET_DEST (x)) == ZERO_EXTRACT
  	       && GET_CODE (XEXP (SET_DEST (x), 1)) == CONST_INT)
*************** make_extraction (mode, inner, pos, pos_r
*** 6015,6032 ****
  	  /* 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;
! 	}
        else
  	new = force_to_mode (inner, tmode,
  			     len >= HOST_BITS_PER_WIDE_INT
--- 6053,6078 ----
  	  /* 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)
! 	    {
! 	      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
*************** if_then_else_cond (x, ptrue, pfalse)
*** 7410,7420 ****
  	   || 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))
  	{
! 	  true0 = operand_subword (true0, SUBREG_WORD (x), 0,
  				   GET_MODE (SUBREG_REG (x)));
! 	  false0 = operand_subword (false0, SUBREG_WORD (x), 0,
  				    GET_MODE (SUBREG_REG (x)));
  	}
        *ptrue = force_to_mode (true0, mode, ~(HOST_WIDE_INT) 0, NULL_RTX, 0);
--- 7456,7466 ----
  	   || 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_BYTE (x) >= UNITS_PER_WORD))
  	{
! 	  true0 = operand_subword (true0, SUBREG_BYTE (x) / UNITS_PER_WORD, 0,
  				   GET_MODE (SUBREG_REG (x)));
! 	  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);
*************** apply_distributive_law (x)
*** 7786,7792 ****
  
      case SUBREG:
        /* Non-paradoxical SUBREGs distributes over all operations, provided
! 	 the inner modes and word numbers 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
--- 7832,7838 ----
  
      case SUBREG:
        /* Non-paradoxical SUBREGs distributes over all operations, provided
! 	 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
*************** apply_distributive_law (x)
*** 7797,7803 ****
  	 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_lowpart_p (lhs)
  	  || (GET_MODE_CLASS (GET_MODE (lhs))
  	      != GET_MODE_CLASS (GET_MODE (SUBREG_REG (lhs))))
--- 7843,7849 ----
  	 We produce the result slightly differently in this case.  */
  
        if (GET_MODE (SUBREG_REG (lhs)) != GET_MODE (SUBREG_REG (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))))
*************** gen_lowpart_for_combine (mode, x)
*** 9868,9880 ****
       include an explicit SUBREG or we may simplify it further in combine.  */
    else
      {
!       int word = 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);
      }
  }
  
--- 9914,9932 ----
       include an explicit SUBREG or we may simplify it further in combine.  */
    else
      {
!       int offset = 0;
  
!       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);
      }
  }
  
*************** move_deaths (x, maybe_kill_insn, from_cu
*** 12017,12022 ****
--- 12069,12075 ----
  	 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
Index: gcc/configure
===================================================================
RCS file: /cvs/gcc/egcs/gcc/configure,v
retrieving revision 1.507
diff -c -p -r1.507 configure
*** gcc/configure	2001/03/15 00:13:34	1.507
--- gcc/configure	2001/03/16 02:08:20
*************** EOF
*** 2098,2104 ****
  fi
  
  # Find some useful tools
! for ac_prog in mawk gawk nawk awk
  do
  # Extract the first word of "$ac_prog", so it can be a program name with args.
  set dummy $ac_prog; ac_word=$2
--- 2098,2104 ----
  fi
  
  # Find some useful tools
! for ac_prog in gawk mawk nawk awk
  do
  # Extract the first word of "$ac_prog", so it can be a program name with args.
  set dummy $ac_prog; ac_word=$2
Index: gcc/cse.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cse.c,v
retrieving revision 1.178
diff -c -p -r1.178 cse.c
*** gcc/cse.c	2001/03/07 19:29:35	1.178
--- gcc/cse.c	2001/03/16 02:08:21
*************** mention_regs (x)
*** 1220,1230 ****
  	  /* 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.  */
  	  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));
  	}
  
        REG_IN_TABLE (i) = REG_TICK (i);
--- 1220,1230 ----
  	  /* 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 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_BYTE (x), GET_MODE (x));
  	}
  
        REG_IN_TABLE (i) = REG_TICK (i);
*************** remove_invalid_refs (regno)
*** 2004,2035 ****
        }
  }
  
! /* Likewise for a subreg with subreg_reg WORD and mode MODE.  */
  static void
! remove_invalid_subreg_refs (regno, word, mode)
       unsigned int regno;
!      unsigned int word;
       enum machine_mode mode;
  {
    unsigned int i;
    struct table_elt *p, *next;
!   unsigned int end = word + (GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD;
  
    for (i = 0; i < HASH_SIZE; i++)
      for (p = table[i]; p; p = next)
        {
! 	rtx exp;
  	next = p->next_same_hash;
  
! 	exp = p->exp;
! 	if (GET_CODE (p->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))
  	    && refers_to_regno_p (regno, regno + 1, p->exp, NULL_PTR))
  	  remove_from_table (p, i);
        }
--- 2004,2034 ----
        }
  }
  
! /* Likewise for a subreg with subreg_reg REGNO, subreg_byte OFFSET,
!    and mode MODE.  */
  static void
! remove_invalid_subreg_refs (regno, offset, mode)
       unsigned int regno;
!      unsigned int offset;
       enum machine_mode mode;
  {
    unsigned int i;
    struct table_elt *p, *next;
!   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 = p->exp;
  	next = p->next_same_hash;
  
! 	if (GET_CODE (exp) != REG
  	    && (GET_CODE (exp) != SUBREG
  		|| GET_CODE (SUBREG_REG (exp)) != REG
  		|| REGNO (SUBREG_REG (exp)) != regno
! 		|| (((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);
        }
*************** canon_hash (x, mode)
*** 2302,2308 ****
  	if (GET_CODE (SUBREG_REG (x)) == REG)
  	  {
  	    hash += (((unsigned) SUBREG << 7)
! 		     + REGNO (SUBREG_REG (x)) + SUBREG_WORD (x));
  	    return hash;
  	  }
  	break;
--- 2301,2308 ----
  	if (GET_CODE (SUBREG_REG (x)) == REG)
  	  {
  	    hash += (((unsigned) SUBREG << 7)
! 		     + REGNO (SUBREG_REG (x))
! 		     + (SUBREG_BYTE (x) / UNITS_PER_WORD));
  	    return hash;
  	  }
  	break;
*************** fold_rtx (x, insn)
*** 3413,3419 ****
  	  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,
  				   GET_MODE (SUBREG_REG (x)));
  	  if (new == 0 && subreg_lowpart_p (x))
  	    new = gen_lowpart_if_possible (mode, folded_arg0);
--- 3413,3420 ----
  	  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_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);
*************** gen_lowpart_if_possible (mode, x)
*** 4393,4402 ****
  	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))));
        new = gen_rtx_MEM (mode, plus_constant (XEXP (x, 0), offset));
        if (! memory_address_p (mode, XEXP (new, 0)))
  	return 0;
--- 4394,4405 ----
  	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))));
! 	}
        new = gen_rtx_MEM (mode, plus_constant (XEXP (x, 0), offset));
        if (! memory_address_p (mode, XEXP (new, 0)))
  	return 0;
Index: gcc/dbxout.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/dbxout.c,v
retrieving revision 1.74
diff -c -p -r1.74 dbxout.c
*** gcc/dbxout.c	2001/03/15 02:50:48	1.74
--- gcc/dbxout.c	2001/03/16 02:08:21
*************** dbxout_symbol_location (decl, type, suff
*** 2016,2035 ****
    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);
! 	}
        if (GET_CODE (value) == REG)
  	{
! 	  regno = REGNO (value);
! 	  if (regno >= FIRST_PSEUDO_REGISTER)
  	    return 0;
- 	  regno += offset;
  	}
!       alter_subreg (home);
      }
  
    /* The kind-of-variable letter depends on where
--- 2016,2030 ----
    else if (GET_CODE (home) == SUBREG)
      {
        rtx value = home;
! 
        while (GET_CODE (value) == SUBREG)
! 	value = SUBREG_REG (value);
        if (GET_CODE (value) == REG)
  	{
! 	  if (REGNO (value) >= FIRST_PSEUDO_REGISTER)
  	    return 0;
  	}
!       regno = REGNO (alter_subreg (home));
      }
  
    /* The kind-of-variable letter depends on where
Index: gcc/dwarf2out.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/dwarf2out.c,v
retrieving revision 1.249
diff -c -p -r1.249 dwarf2out.c
*** gcc/dwarf2out.c	2001/03/10 16:33:56	1.249
--- gcc/dwarf2out.c	2001/03/16 02:08:22
*************** is_pseudo_reg (rtl)
*** 3417,3423 ****
  {
    return ((GET_CODE (rtl) == REG && REGNO (rtl) >= FIRST_PSEUDO_REGISTER)
  	  || (GET_CODE (rtl) == SUBREG
! 	      && REGNO (XEXP (rtl, 0)) >= FIRST_PSEUDO_REGISTER));
  }
  
  /* Return a reference to a type, with its const and volatile qualifiers
--- 3417,3423 ----
  {
    return ((GET_CODE (rtl) == REG && REGNO (rtl) >= FIRST_PSEUDO_REGISTER)
  	  || (GET_CODE (rtl) == SUBREG
! 	      && REGNO (SUBREG_REG (rtl)) >= FIRST_PSEUDO_REGISTER));
  }
  
  /* Return a reference to a type, with its const and volatile qualifiers
*************** mem_loc_descriptor (rtl, mode)
*** 7064,7070 ****
           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);
  
        /* Fall through.  */
  
--- 7064,7070 ----
           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 = SUBREG_REG (rtl);
  
        /* Fall through.  */
  
*************** loc_descriptor (rtl)
*** 7208,7214 ****
           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);
  
        /* Fall through.  */
  
--- 7208,7214 ----
           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 = SUBREG_REG (rtl);
  
        /* Fall through.  */
  
Index: gcc/dwarfout.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/dwarfout.c,v
retrieving revision 1.80
diff -c -p -r1.80 dwarfout.c
*** gcc/dwarfout.c	2001/02/21 14:42:18	1.80
--- gcc/dwarfout.c	2001/03/16 02:08:22
*************** is_pseudo_reg (rtl)
*** 817,823 ****
  {
    return (((GET_CODE (rtl) == REG) && (REGNO (rtl) >= FIRST_PSEUDO_REGISTER))
            || ((GET_CODE (rtl) == SUBREG)
! 	      && (REGNO (XEXP (rtl, 0)) >= FIRST_PSEUDO_REGISTER)));
  }
  
  inline static tree
--- 817,823 ----
  {
    return (((GET_CODE (rtl) == REG) && (REGNO (rtl) >= FIRST_PSEUDO_REGISTER))
            || ((GET_CODE (rtl) == SUBREG)
! 	      && (REGNO (SUBREG_REG (rtl)) >= FIRST_PSEUDO_REGISTER)));
  }
  
  inline static tree
*************** output_mem_loc_descriptor (rtl)
*** 1630,1636 ****
  	   legitimate to make the Dwarf info refer to the whole register
  	   which contains the given subreg.  */
  
! 	rtl = XEXP (rtl, 0);
  	/* Drop thru.  */
  
        case REG:
--- 1630,1636 ----
  	   legitimate to make the Dwarf info refer to the whole register
  	   which contains the given subreg.  */
  
! 	rtl = SUBREG_REG (rtl);
  	/* Drop thru.  */
  
        case REG:
*************** output_loc_descriptor (rtl)
*** 1714,1720 ****
  	   legitimate to make the Dwarf info refer to the whole register
  	   which contains the given subreg.  */
  
! 	rtl = XEXP (rtl, 0);
  	/* Drop thru.  */
  
      case REG:
--- 1714,1720 ----
  	   legitimate to make the Dwarf info refer to the whole register
  	   which contains the given subreg.  */
  
! 	rtl = SUBREG_REG (rtl);
  	/* Drop thru.  */
  
      case REG:
Index: gcc/emit-rtl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/emit-rtl.c,v
retrieving revision 1.168
diff -c -p -r1.168 emit-rtl.c
*** gcc/emit-rtl.c	2001/03/15 02:50:49	1.168
--- gcc/emit-rtl.c	2001/03/16 02:08:22
*************** gen_rtx_MEM (mode, addr)
*** 348,353 ****
--- 348,402 ----
  
    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])
  **
*************** get_first_label_num ()
*** 650,655 ****
--- 699,736 ----
    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 
*************** gen_lowpart_common (mode, x)
*** 666,687 ****
       enum machine_mode mode;
       register rtx x;
  {
!   int word = 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)))
      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 ((GET_CODE (x) == ZERO_EXTEND || GET_CODE (x) == SIGN_EXTEND)
        && (GET_MODE_CLASS (mode) == MODE_INT
--- 747,775 ----
       enum machine_mode mode;
       register rtx x;
  {
!   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
!       && ((msize + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD
! 	  > ((xsize + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)))
      return 0;
  
!   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
*************** gen_lowpart_common (mode, x)
*** 703,741 ****
  	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) == 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));
    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
  	       /* integrate.c can't handle parts of a return value register. */
! 	       && (! REG_FUNCTION_VALUE_P (x)
  		   || ! rtx_equal_function_value_matters)
  #ifdef CLASS_CANNOT_CHANGE_MODE
  	       && ! (CLASS_CANNOT_CHANGE_MODE_P (mode, GET_MODE (x))
--- 791,830 ----
  	return gen_rtx_fmt_e (GET_CODE (x), mode, XEXP (x, 0));
      }
    else if (GET_CODE (x) == SUBREG
! 	   && (GET_MODE_SIZE (mode) <= UNITS_PER_WORD
  	       || GET_MODE_SIZE (mode) == GET_MODE_UNIT_SIZE (GET_MODE (x))))
!     {
!       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)
      {
!       /* 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. */
! 	  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))
*************** gen_lowpart_common (mode, x)
*** 752,760 ****
  	       && 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);
      }
    /* If X is a CONST_INT or a CONST_DOUBLE, extract the appropriate bits
       from the low-order part of the constant.  */
--- 841,849 ----
  	       && x != arg_pointer_rtx
  #endif
  	       && x != stack_pointer_rtx)
! 	    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.  */
*************** gen_lowpart_common (mode, x)
*** 847,853 ****
  	   && 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));
  
    /* 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
--- 936,942 ----
  	   && GET_CODE (x) == CONST_DOUBLE
  	   && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT
  	   && GET_MODE_BITSIZE (mode) == BITS_PER_WORD)
!     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
*************** gen_lowpart_common (mode, x)
*** 863,873 ****
  	   && 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));
  
        if (lowpart && GET_CODE (lowpart) == CONST_INT
  	  && highpart && GET_CODE (highpart) == CONST_INT)
  	return immed_double_const (INTVAL (lowpart), INTVAL (highpart), mode);
--- 952,965 ----
  	   && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT
  	   && GET_MODE_BITSIZE (mode) == 2 * BITS_PER_WORD)
      {
!       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);
*************** gen_imagpart (mode, x)
*** 1021,1027 ****
      return XEXP (x, 1);
    else if (WORDS_BIG_ENDIAN)
      return gen_lowpart (mode, x);
!   else if (!WORDS_BIG_ENDIAN
  	   && GET_MODE_BITSIZE (mode) < BITS_PER_WORD
  	   && REG_P (x)
  	   && REGNO (x) < FIRST_PSEUDO_REGISTER)
--- 1113,1119 ----
      return XEXP (x, 1);
    else if (WORDS_BIG_ENDIAN)
      return gen_lowpart (mode, x);
!   else if (! WORDS_BIG_ENDIAN
  	   && GET_MODE_BITSIZE (mode) < BITS_PER_WORD
  	   && REG_P (x)
  	   && REGNO (x) < FIRST_PSEUDO_REGISTER)
*************** subreg_realpart_p (x)
*** 1043,1049 ****
    if (GET_CODE (x) != SUBREG)
      abort ();
  
!   return ((unsigned int) SUBREG_WORD (x) * UNITS_PER_WORD
  	  < GET_MODE_UNIT_SIZE (GET_MODE (SUBREG_REG (x))));
  }
  
--- 1135,1141 ----
    if (GET_CODE (x) != SUBREG)
      abort ();
  
!   return ((unsigned int) SUBREG_BYTE (x)
  	  < GET_MODE_UNIT_SIZE (GET_MODE (SUBREG_REG (x))));
  }
  
*************** gen_highpart (mode, x)
*** 1101,1110 ****
       enum machine_mode mode;
       register rtx 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)))
      abort ();
    if (GET_CODE (x) == CONST_DOUBLE
  #if !(TARGET_FLOAT_FORMAT != HOST_FLOAT_FORMAT || defined (REAL_IS_NOT_DOUBLE))
--- 1193,1205 ----
       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 (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))
*************** gen_highpart (mode, x)
*** 1121,1135 ****
    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));
  
        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))));
  
        return change_address (x, mode, plus_constant (XEXP (x, 0), offset));
      }
--- 1216,1229 ----
    else if (GET_CODE (x) == MEM)
      {
        register int offset = 0;
+ 
        if (! WORDS_BIG_ENDIAN)
! 	offset = (MAX (xsize, UNITS_PER_WORD)
! 		  - MAX (msize, UNITS_PER_WORD));
  
        if (! BYTES_BIG_ENDIAN
! 	  && msize < UNITS_PER_WORD)
! 	offset -= (msize - MIN (UNITS_PER_WORD, xsize));
  
        return change_address (x, mode, plus_constant (XEXP (x, 0), offset));
      }
*************** gen_highpart (mode, x)
*** 1138,1183 ****
        /* 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)
  	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.  */
  
        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)
  	  /* 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
  #endif
! 	  && x != stack_pointer_rtx)
! 	return gen_rtx_REG (mode, REGNO (x) + word);
!       else
! 	return gen_rtx_SUBREG (mode, x, word);
      }
    else
      abort ();
--- 1232,1278 ----
        /* 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_BYTE (x) != 0)
  	abort ();
        return gen_highpart (mode, SUBREG_REG (x));
      }
    else if (GET_CODE (x) == REG)
      {
!       int offset = 0;
  
        if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (mode))
  	abort ();
! 
!       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
  #endif
! 	      && 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 ();
*************** int
*** 1191,1344 ****
  subreg_lowpart_p (x)
       rtx 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));
  
!   return SUBREG_WORD (x) == 0;
  }
  
- /* 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.  */
- 
  rtx
! operand_subword (op, i, validate_address, mode)
       rtx op;
!      unsigned int i;
!      int validate_address;
       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;
  
    /* 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
--- 1286,1329 ----
  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 (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_BYTE (x) == offset;
  }
  
  
! /* Helper routine for all the constant cases of operand_subword.
!    Some places invoke this directly.  */
  
  rtx
! constant_subword (op, offset, mode)
       rtx op;
!      int offset;
       enum machine_mode mode;
  {
    int size_ratio = HOST_BITS_PER_WIDE_INT / BITS_PER_WORD;
!   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;
  
  #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
*************** operand_subword (op, i, validate_address
*** 1365,1376 ****
  	 So we explicitly mask and sign-extend as necessary.  */
        if (BITS_PER_WORD == 32)
  	{
! 	  val = k[i];
  	  val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000;
  	  return GEN_INT (val);
  	}
  #if HOST_BITS_PER_WIDE_INT >= 64
!       else if (BITS_PER_WORD >= 64 && i == 0)
  	{
  	  val = k[! WORDS_BIG_ENDIAN];
  	  val = (((val & 0xffffffff) ^ 0x80000000) - 0x80000000) << 32;
--- 1350,1361 ----
  	 So we explicitly mask and sign-extend as necessary.  */
        if (BITS_PER_WORD == 32)
  	{
! 	  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 && offset == 0)
  	{
  	  val = k[! WORDS_BIG_ENDIAN];
  	  val = (((val & 0xffffffff) ^ 0x80000000) - 0x80000000) << 32;
*************** operand_subword (op, i, validate_address
*** 1380,1387 ****
  #endif
        else if (BITS_PER_WORD == 16)
  	{
! 	  val = k[i >> 1];
! 	  if ((i & 1) == !WORDS_BIG_ENDIAN)
  	    val >>= 16;
  	  val &= 0xffff;
  	  return GEN_INT (val);
--- 1365,1372 ----
  #endif
        else if (BITS_PER_WORD == 16)
  	{
! 	  val = k[offset >> 1];
! 	  if ((offset & 1) == ! WORDS_BIG_ENDIAN)
  	    val >>= 16;
  	  val &= 0xffff;
  	  return GEN_INT (val);
*************** operand_subword (op, i, validate_address
*** 1402,1417 ****
  
        if (BITS_PER_WORD == 32)
  	{
! 	  val = k[i];
  	  val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000;
  	  return GEN_INT (val);
  	}
  #if HOST_BITS_PER_WIDE_INT >= 64
!       else if (BITS_PER_WORD >= 64 && i <= 1)
  	{
! 	  val = k[i*2 + ! WORDS_BIG_ENDIAN];
  	  val = (((val & 0xffffffff) ^ 0x80000000) - 0x80000000) << 32;
! 	  val |= (HOST_WIDE_INT) k[i*2 + WORDS_BIG_ENDIAN] & 0xffffffff;
  	  return GEN_INT (val);
  	}
  #endif
--- 1387,1402 ----
  
        if (BITS_PER_WORD == 32)
  	{
! 	  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 && offset <= 1)
  	{
! 	  val = k[offset * 2 + ! WORDS_BIG_ENDIAN];
  	  val = (((val & 0xffffffff) ^ 0x80000000) - 0x80000000) << 32;
! 	  val |= (HOST_WIDE_INT) k[offset * 2 + WORDS_BIG_ENDIAN] & 0xffffffff;
  	  return GEN_INT (val);
  	}
  #endif
*************** operand_subword (op, i, validate_address
*** 1431,1440 ****
  	 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
  		      ? CONST_DOUBLE_HIGH (op) : CONST_DOUBLE_LOW (op));
  #else
!       return GEN_INT (i != WORDS_BIG_ENDIAN
  		      ? CONST_DOUBLE_HIGH (op) : CONST_DOUBLE_LOW (op));
  #endif
      }
--- 1416,1425 ----
  	 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 (offset == WORDS_BIG_ENDIAN
  		      ? CONST_DOUBLE_HIGH (op) : CONST_DOUBLE_LOW (op));
  #else
!       return GEN_INT (offset != WORDS_BIG_ENDIAN
  		      ? CONST_DOUBLE_HIGH (op) : CONST_DOUBLE_LOW (op));
  #endif
      }
*************** operand_subword (op, i, validate_address
*** 1460,1466 ****
  
        if (BITS_PER_WORD == 16)
  	{
! 	  if ((i & 1) == !WORDS_BIG_ENDIAN)
  	    val >>= 16;
  	  val &= 0xffff;
  	}
--- 1445,1451 ----
  
        if (BITS_PER_WORD == 16)
  	{
! 	  if ((offset & 1) == ! WORDS_BIG_ENDIAN)
  	    val >>= 16;
  	  val &= 0xffff;
  	}
*************** operand_subword (op, i, validate_address
*** 1504,1510 ****
        
    /* 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.  
  
       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
--- 1489,1495 ----
        
    /* The only remaining cases that we can handle are integers.
       Convert to proper endianness now since these cases need it.
!      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
*************** operand_subword (op, i, validate_address
*** 1519,1557 ****
      return 0;
  
    if (WORDS_BIG_ENDIAN)
!     i = GET_MODE_SIZE (mode) / UNITS_PER_WORD - 1 - i;
  
    /* Find out which word on the host machine this value is in and get
       it from the constant.  */
!   val = (i / 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 = trunc_int_for_mode (val, word_mode);
  
    return GEN_INT (val);
  }
  
  /* 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. 
  
     MODE is the mode of OP, in case it is CONST_INT.  */
  
  rtx
! operand_subword_force (op, i, mode)
       rtx op;
!      unsigned int i;
       enum machine_mode mode;
  {
!   rtx result = operand_subword (op, i, 1, mode);
  
    if (result)
      return result;
--- 1504,1687 ----
      return 0;
  
    if (WORDS_BIG_ENDIAN)
!     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 = (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 >> ((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.  
  
     MODE is the mode of OP, in case it is CONST_INT.  */
  
  rtx
! operand_subword_force (op, offset, mode)
       rtx op;
!      unsigned int offset;
       enum machine_mode mode;
  {
!   rtx result = operand_subword (op, offset, 1, mode);
  
    if (result)
      return result;
*************** operand_subword_force (op, i, mode)
*** 1566,1572 ****
  	op = force_reg (mode, op);
      }
  
!   result = operand_subword (op, i, 1, mode);
    if (result == 0)
      abort ();
  
--- 1696,1702 ----
  	op = force_reg (mode, op);
      }
  
!   result = operand_subword (op, offset, 1, mode);
    if (result == 0)
      abort ();
  
Index: gcc/expmed.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/expmed.c,v
retrieving revision 1.76
diff -c -p -r1.76 expmed.c
*** gcc/expmed.c	2001/01/31 19:05:49	1.76
--- gcc/expmed.c	2001/03/16 02:08:23
*************** store_bit_field (str_rtx, bitsize, bitnu
*** 263,269 ****
  	 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);
        /* We used to adjust BITPOS here, but now we do the whole adjustment
  	 right after the loop.  */
        op0 = SUBREG_REG (op0);
--- 263,269 ----
  	 meaningful at a much higher level; when structures are copied
  	 between memory and regs, the higher-numbered regs
  	 always get higher addresses.  */
!       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);
*************** store_bit_field (str_rtx, bitsize, bitnu
*** 313,319 ****
  		abort ();
  	    }
  	  if (GET_CODE (op0) == REG)
! 	    op0 = gen_rtx_SUBREG (fieldmode, op0, offset);
  	  else
  	    op0 = change_address (op0, fieldmode,
  				  plus_constant (XEXP (op0, 0), offset));
--- 313,321 ----
  		abort ();
  	    }
  	  if (GET_CODE (op0) == REG)
! 	    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));
*************** store_bit_field (str_rtx, bitsize, bitnu
*** 375,381 ****
  	}
  
        emit_insn (GEN_FCN (icode)
! 		 (gen_rtx_SUBREG (fieldmode, op0, offset), value));
  
        return value;
      }
--- 377,386 ----
  	}
  
        emit_insn (GEN_FCN (icode)
! 		 (gen_rtx_SUBREG (fieldmode, op0,
! 				  (bitnum % BITS_PER_WORD) / BITS_PER_UNIT
! 				  + (offset * UNITS_PER_WORD)),
! 				  value));
  
        return value;
      }
*************** store_bit_field (str_rtx, bitsize, bitnu
*** 449,455 ****
  		abort ();
  	    }
  	  op0 = gen_rtx_SUBREG (mode_for_size (BITS_PER_WORD, MODE_INT, 0),
! 		                op0, offset);
  	}
        offset = 0;
      }
--- 454,460 ----
  		abort ();
  	    }
  	  op0 = gen_rtx_SUBREG (mode_for_size (BITS_PER_WORD, MODE_INT, 0),
! 		                op0, (offset * UNITS_PER_WORD));
  	}
        offset = 0;
      }
*************** store_bit_field (str_rtx, bitsize, bitnu
*** 552,558 ****
        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));
        if (GET_CODE (xop0) == REG && GET_MODE (xop0) != maxmode)
  	xop0 = gen_rtx_SUBREG (maxmode, xop0, 0);
  
--- 557,563 ----
        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_BYTE (xop0));
        if (GET_CODE (xop0) == REG && GET_MODE (xop0) != maxmode)
  	xop0 = gen_rtx_SUBREG (maxmode, xop0, 0);
  
*************** store_split_bit_field (op0, bitsize, bit
*** 912,919 ****
  	 the current word starting from the base register.  */
        if (GET_CODE (op0) == SUBREG)
  	{
! 	  word = operand_subword_force (SUBREG_REG (op0),
! 					SUBREG_WORD (op0) + offset,
  					GET_MODE (SUBREG_REG (op0)));
  	  offset = 0;
  	}
--- 917,924 ----
  	 the current word starting from the base register.  */
        if (GET_CODE (op0) == SUBREG)
  	{
! 	  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;
  	}
*************** extract_bit_field (str_rtx, bitsize, bit
*** 1010,1016 ****
        int outer_size = GET_MODE_BITSIZE (GET_MODE (op0));
        int inner_size = GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0)));
  
!       offset += SUBREG_WORD (op0);
  
        inner_size = MIN (inner_size, BITS_PER_WORD);
  
--- 1015,1021 ----
        int outer_size = GET_MODE_BITSIZE (GET_MODE (op0));
        int inner_size = GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0)));
  
!       offset += SUBREG_BYTE (op0) / UNITS_PER_WORD;
  
        inner_size = MIN (inner_size, BITS_PER_WORD);
  
*************** extract_bit_field (str_rtx, bitsize, bit
*** 1106,1112 ****
  		abort ();
  	    }
  	  if (GET_CODE (op0) == REG)
! 	    op0 = gen_rtx_SUBREG (mode1, op0, offset);
  	  else
  	    op0 = change_address (op0, mode1,
  				  plus_constant (XEXP (op0, 0), offset));
--- 1111,1119 ----
  		abort ();
  	    }
  	  if (GET_CODE (op0) == REG)
! 	    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));
*************** extract_bit_field (str_rtx, bitsize, bit
*** 1215,1221 ****
  	  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);
  	}
        offset = 0;
      }
--- 1222,1228 ----
  	  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 * UNITS_PER_WORD));
  	}
        offset = 0;
      }
*************** extract_split_bit_field (op0, bitsize, b
*** 1810,1817 ****
  	 the current word starting from the base register.  */
        if (GET_CODE (op0) == SUBREG)
  	{
! 	  word = operand_subword_force (SUBREG_REG (op0),
! 					SUBREG_WORD (op0) + offset,
  					GET_MODE (SUBREG_REG (op0)));
  	  offset = 0;
  	}
--- 1817,1824 ----
  	 the current word starting from the base register.  */
        if (GET_CODE (op0) == SUBREG)
  	{
! 	  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;
  	}
*************** expand_shift (code, mode, shifted, amoun
*** 1930,1936 ****
          op1 = GEN_INT ((unsigned HOST_WIDE_INT) INTVAL (op1)
  		       % GET_MODE_BITSIZE (mode));
        else if (GET_CODE (op1) == SUBREG
! 	       && SUBREG_WORD (op1) == 0)
  	op1 = SUBREG_REG (op1);
      }
  #endif
--- 1937,1943 ----
          op1 = GEN_INT ((unsigned HOST_WIDE_INT) INTVAL (op1)
  		       % GET_MODE_BITSIZE (mode));
        else if (GET_CODE (op1) == SUBREG
! 	       && SUBREG_BYTE (op1) == 0)
  	op1 = SUBREG_REG (op1);
      }
  #endif
Index: gcc/expr.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/expr.c,v
retrieving revision 1.303
diff -c -p -r1.303 expr.c
*** gcc/expr.c	2001/03/15 02:50:49	1.303
--- gcc/expr.c	2001/03/16 02:08:23
*************** store_expr (exp, target, want_value)
*** 4088,4094 ****
        if (want_value && GET_MODE (temp) != GET_MODE (target)
  	  && GET_MODE (temp) != VOIDmode)
  	{
! 	  temp = gen_rtx_SUBREG (GET_MODE (target), temp, 0);
  	  SUBREG_PROMOTED_VAR_P (temp) = 1;
  	  SUBREG_PROMOTED_UNSIGNED_P (temp)
  	    = SUBREG_PROMOTED_UNSIGNED_P (target);
--- 4088,4094 ----
        if (want_value && GET_MODE (temp) != GET_MODE (target)
  	  && GET_MODE (temp) != VOIDmode)
  	{
! 	  temp = gen_lowpart_SUBREG (GET_MODE (target), temp);
  	  SUBREG_PROMOTED_VAR_P (temp) = 1;
  	  SUBREG_PROMOTED_UNSIGNED_P (temp)
  	    = SUBREG_PROMOTED_UNSIGNED_P (target);
*************** expand_expr (exp, target, tmode, modifie
*** 6300,6306 ****
  	      != promote_mode (type, DECL_MODE (exp), &unsignedp, 0))
  	    abort ();
  
! 	  temp = gen_rtx_SUBREG (mode, DECL_RTL (exp), 0);
  	  SUBREG_PROMOTED_VAR_P (temp) = 1;
  	  SUBREG_PROMOTED_UNSIGNED_P (temp) = unsignedp;
  	  return temp;
--- 6300,6306 ----
  	      != promote_mode (type, DECL_MODE (exp), &unsignedp, 0))
  	    abort ();
  
! 	  temp = gen_lowpart_SUBREG (mode, DECL_RTL (exp));
  	  SUBREG_PROMOTED_VAR_P (temp) = 1;
  	  SUBREG_PROMOTED_UNSIGNED_P (temp) = unsignedp;
  	  return temp;
*************** expand_expr (exp, target, tmode, modifie
*** 6420,6426 ****
  
  	  if (GET_CODE (temp) == REG && GET_MODE (temp) != mode)
  	    {
! 	      temp = gen_rtx_SUBREG (mode, SAVE_EXPR_RTL (exp), 0);
  	      SUBREG_PROMOTED_VAR_P (temp) = 1;
  	      SUBREG_PROMOTED_UNSIGNED_P (temp) = unsignedp;
  	    }
--- 6420,6426 ----
  
  	  if (GET_CODE (temp) == REG && GET_MODE (temp) != mode)
  	    {
! 	      temp = gen_lowpart_SUBREG (mode, SAVE_EXPR_RTL (exp));
  	      SUBREG_PROMOTED_VAR_P (temp) = 1;
  	      SUBREG_PROMOTED_UNSIGNED_P (temp) = unsignedp;
  	    }
*************** expand_expr (exp, target, tmode, modifie
*** 6443,6449 ****
  	{
  	  /* Compute the signedness and make the proper SUBREG.  */
  	  promote_mode (type, mode, &unsignedp, 0);
! 	  temp = gen_rtx_SUBREG (mode, SAVE_EXPR_RTL (exp), 0);
  	  SUBREG_PROMOTED_VAR_P (temp) = 1;
  	  SUBREG_PROMOTED_UNSIGNED_P (temp) = unsignedp;
  	  return temp;
--- 6443,6449 ----
  	{
  	  /* Compute the signedness and make the proper SUBREG.  */
  	  promote_mode (type, mode, &unsignedp, 0);
! 	  temp = gen_lowpart_SUBREG (mode, SAVE_EXPR_RTL (exp));
  	  SUBREG_PROMOTED_VAR_P (temp) = 1;
  	  SUBREG_PROMOTED_UNSIGNED_P (temp) = unsignedp;
  	  return temp;
Index: gcc/final.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/final.c,v
retrieving revision 1.161
diff -c -p -r1.161 final.c
*** gcc/final.c	2001/02/28 17:53:35	1.161
--- gcc/final.c	2001/03/16 02:08:23
*************** alter_subreg (x)
*** 3154,3173 ****
  
    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
        PUT_CODE (x, REG);
        REGNO (x) = regno;
        ORIGINAL_REGNO (x) = ORIGINAL_REGNO (y);
--- 3154,3161 ----
  
    if (GET_CODE (y) == REG)
      {
!       int regno = subreg_hard_regno (x, 1);
  
        PUT_CODE (x, REG);
        REGNO (x) = regno;
        ORIGINAL_REGNO (x) = ORIGINAL_REGNO (y);
*************** alter_subreg (x)
*** 3177,3187 ****
      }
    else if (GET_CODE (y) == MEM)
      {
!       register int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
  
!       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);
--- 3165,3176 ----
      }
    else if (GET_CODE (y) == MEM)
      {
!       register int offset = SUBREG_BYTE (x);
  
!       /* Catch these instead of generating incorrect code.  */
!       if ((offset % GET_MODE_SIZE (GET_MODE (x))) != 0)
! 	abort ();
! 
        PUT_CODE (x, MEM);
        MEM_COPY_ATTRIBUTES (x, y);
        XEXP (x, 0) = plus_constant (XEXP (y, 0), offset);
Index: gcc/flow.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/flow.c,v
retrieving revision 1.382
diff -c -p -r1.382 flow.c
*** gcc/flow.c	2001/03/12 19:09:56	1.382
--- gcc/flow.c	2001/03/16 02:08:24
*************** set_noop_p (set)
*** 3313,3319 ****
  
    if (GET_CODE (src) == SUBREG && GET_CODE (dst) == SUBREG)
      {
!       if (SUBREG_WORD (src) != SUBREG_WORD (dst))
  	return 0;
        src = SUBREG_REG (src);
        dst = SUBREG_REG (dst);
--- 3313,3319 ----
  
    if (GET_CODE (src) == SUBREG && GET_CODE (dst) == SUBREG)
      {
!       if (SUBREG_BYTE (src) != SUBREG_BYTE (dst))
  	return 0;
        src = SUBREG_REG (src);
        dst = SUBREG_REG (dst);
*************** mark_set_1 (pbi, code, reg, cond, insn, 
*** 4843,4854 ****
  	  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_last = (regno_first
  			    + HARD_REGNO_NREGS (regno_first, outer_mode) - 1);
  
--- 4843,4851 ----
  	  regno_last = regno_first = REGNO (SUBREG_REG (reg));
  	  if (regno_first < FIRST_PSEUDO_REGISTER)
  	    {
! 	      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);
  
Index: gcc/function.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/function.c,v
retrieving revision 1.256
diff -c -p -r1.256 function.c
*** gcc/function.c	2001/03/15 02:50:49	1.256
--- gcc/function.c	2001/03/16 02:08:24
*************** fixup_var_refs_1 (var, promoted_mode, lo
*** 2232,2238 ****
  	  dest = XEXP (dest, 0);
  
  	if (GET_CODE (src) == SUBREG)
! 	  src = XEXP (src, 0);
  
  	/* If VAR does not appear at the top level of the SET
  	   just scan the lower levels of the tree.  */
--- 2232,2238 ----
  	  dest = XEXP (dest, 0);
  
  	if (GET_CODE (src) == SUBREG)
! 	  src = SUBREG_REG (src);
  
  	/* If VAR does not appear at the top level of the SET
  	   just scan the lower levels of the tree.  */
*************** fixup_memory_subreg (x, insn, uncritical
*** 2516,2522 ****
       rtx insn;
       int uncritical;
  {
!   int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
    rtx addr = XEXP (SUBREG_REG (x), 0);
    enum machine_mode mode = GET_MODE (x);
    rtx result;
--- 2516,2522 ----
       rtx insn;
       int uncritical;
  {
!   int offset = SUBREG_BYTE (x);
    rtx addr = XEXP (SUBREG_REG (x), 0);
    enum machine_mode mode = GET_MODE (x);
    rtx result;
*************** fixup_memory_subreg (x, insn, uncritical
*** 2526,2534 ****
        && ! 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.  */
--- 2526,2531 ----
*************** optimize_bit_field (body, insn, equiv_me
*** 2722,2728 ****
  	  offset /= BITS_PER_UNIT;
  	  if (GET_CODE (XEXP (bitfield, 0)) == SUBREG)
  	    {
! 	      offset += SUBREG_WORD (XEXP (bitfield, 0)) * UNITS_PER_WORD;
  	      if (BYTES_BIG_ENDIAN)
  		offset -= (MIN (UNITS_PER_WORD,
  				GET_MODE_SIZE (GET_MODE (XEXP (bitfield, 0))))
--- 2719,2726 ----
  	  offset /= BITS_PER_UNIT;
  	  if (GET_CODE (XEXP (bitfield, 0)) == SUBREG)
  	    {
! 	      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))))
*************** optimize_bit_field (body, insn, equiv_me
*** 2747,2753 ****
  		{
  		  rtx src = SET_SRC (body);
  		  while (GET_CODE (src) == SUBREG
! 			 && SUBREG_WORD (src) == 0)
  		    src = SUBREG_REG (src);
  		  if (GET_MODE (src) != GET_MODE (memref))
  		    src = gen_lowpart (GET_MODE (memref), SET_SRC (body));
--- 2745,2751 ----
  		{
  		  rtx src = SET_SRC (body);
  		  while (GET_CODE (src) == SUBREG
! 			 && SUBREG_BYTE (src) == 0)
  		    src = SUBREG_REG (src);
  		  if (GET_MODE (src) != GET_MODE (memref))
  		    src = gen_lowpart (GET_MODE (memref), SET_SRC (body));
*************** optimize_bit_field (body, insn, equiv_me
*** 2768,2774 ****
  	      rtx dest = SET_DEST (body);
  
  	      while (GET_CODE (dest) == SUBREG
! 		     && SUBREG_WORD (dest) == 0
  		     && (GET_MODE_CLASS (GET_MODE (dest))
  			 == GET_MODE_CLASS (GET_MODE (SUBREG_REG (dest))))
  		     && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest)))
--- 2766,2772 ----
  	      rtx dest = SET_DEST (body);
  
  	      while (GET_CODE (dest) == SUBREG
! 		     && 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)))
*************** purge_addressof_1 (loc, insn, force, sto
*** 3078,3084 ****
  		       code did.  This is especially true of
  		       REG_RETVAL.  */
  
! 		    if (GET_CODE (z) == SUBREG && SUBREG_WORD (z) == 0)
  		      z = SUBREG_REG (z);
  
  		    if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD
--- 3076,3082 ----
  		       code did.  This is especially true of
  		       REG_RETVAL.  */
  
! 		    if (GET_CODE (z) == SUBREG && SUBREG_BYTE (z) == 0)
  		      z = SUBREG_REG (z);
  
  		    if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD
*************** purge_single_hard_subreg_set (pattern)
*** 3454,3470 ****
  {
    rtx reg = SET_DEST (pattern);
    enum machine_mode mode = GET_MODE (SET_DEST (pattern));
!   int word = 0;
! 		  
!   while (GET_CODE (reg) == SUBREG)
      {
!       word += SUBREG_WORD (reg);
        reg = SUBREG_REG (reg);
      }
! 	      
    if (REGNO (reg) < FIRST_PSEUDO_REGISTER)
      {
!       reg = gen_rtx_REG (mode, REGNO (reg) + word);
        SET_DEST (pattern) = reg;
      }
  }
--- 3452,3473 ----
  {
    rtx reg = SET_DEST (pattern);
    enum machine_mode mode = GET_MODE (SET_DEST (pattern));
!   int offset = 0;
! 
!   if (GET_CODE (reg) == SUBREG && GET_CODE (SUBREG_REG (reg)) == REG
!       && REGNO (SUBREG_REG (reg)) < FIRST_PSEUDO_REGISTER)
      {
!       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) + offset);
        SET_DEST (pattern) = reg;
      }
  }
*************** assign_parms (fndecl)
*** 4747,4752 ****
--- 4750,4769 ----
  
  	      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);
Index: gcc/gengenrtl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/gengenrtl.c,v
retrieving revision 1.40
diff -c -p -r1.40 gengenrtl.c
*** gcc/gengenrtl.c	2001/03/10 04:20:02	1.40
--- gcc/gengenrtl.c	2001/03/16 02:08:24
*************** special_rtx (idx)
*** 208,213 ****
--- 208,214 ----
    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);
  }
  
Index: gcc/global.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/global.c,v
retrieving revision 1.65
diff -c -p -r1.65 global.c
*** gcc/global.c	2000/12/05 19:12:19	1.65
--- gcc/global.c	2001/03/16 02:08:24
*************** mark_reg_store (reg, setter, data)
*** 1422,1438 ****
  {
    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);
!     }
  
    if (GET_CODE (reg) != REG)
      return;
--- 1422,1429 ----
  {
    register int regno;
  
    if (GET_CODE (reg) == SUBREG)
!     reg = SUBREG_REG (reg);
  
    if (GET_CODE (reg) != REG)
      return;
*************** mark_reg_store (reg, setter, data)
*** 1456,1462 ****
      }
  
    if (reg_renumber[regno] >= 0)
!     regno = reg_renumber[regno] /* + word */;
  
    /* Handle hardware regs (and pseudos allocated to hard regs).  */
    if (regno < FIRST_PSEUDO_REGISTER && ! fixed_regs[regno])
--- 1447,1453 ----
      }
  
    if (reg_renumber[regno] >= 0)
!     regno = reg_renumber[regno];
  
    /* Handle hardware regs (and pseudos allocated to hard regs).  */
    if (regno < FIRST_PSEUDO_REGISTER && ! fixed_regs[regno])
*************** set_preference (dest, src)
*** 1606,1612 ****
    else if (GET_CODE (src) == SUBREG && GET_CODE (SUBREG_REG (src)) == REG)
      {
        src_regno = REGNO (SUBREG_REG (src));
!       offset += SUBREG_WORD (src);
      }
    else
      return;
--- 1597,1611 ----
    else if (GET_CODE (src) == SUBREG && GET_CODE (SUBREG_REG (src)) == REG)
      {
        src_regno = REGNO (SUBREG_REG (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;
*************** set_preference (dest, src)
*** 1616,1622 ****
    else if (GET_CODE (dest) == SUBREG && GET_CODE (SUBREG_REG (dest)) == REG)
      {
        dest_regno = REGNO (SUBREG_REG (dest));
!       offset -= SUBREG_WORD (dest);
      }
    else
      return;
--- 1615,1629 ----
    else if (GET_CODE (dest) == SUBREG && GET_CODE (SUBREG_REG (dest)) == REG)
      {
        dest_regno = REGNO (SUBREG_REG (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;
Index: gcc/integrate.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/integrate.c,v
retrieving revision 1.132
diff -c -p -r1.132 integrate.c
*** gcc/integrate.c	2001/03/15 02:50:49	1.132
--- gcc/integrate.c	2001/03/16 02:08:25
*************** copy_rtx_and_substitute (orig, map, for_
*** 1905,1927 ****
        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));
        else if (GET_CODE (copy) == CONCAT)
  	{
  	  rtx retval = subreg_realpart_p (orig) ? XEXP (copy, 0) : XEXP (copy, 1);
  
  	  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)));
  	}
        else
  	return gen_rtx_SUBREG (GET_MODE (orig), copy,
! 			       SUBREG_WORD (orig));
  
      case ADDRESSOF:
        copy = gen_rtx_ADDRESSOF (mode,
--- 1905,1937 ----
        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)
! 	{
! 	  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;
! 	  
! 	  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_BYTE (orig));
  
      case ADDRESSOF:
        copy = gen_rtx_ADDRESSOF (mode,
*************** subst_constants (loc, insn, map, memonly
*** 2413,2420 ****
  	  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)));
  
  	  cancel_changes (num_changes);
  	  if (new == 0 && subreg_lowpart_p (x))
--- 2423,2430 ----
  	  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_BYTE (x) / UNITS_PER_WORD,
! 				   0, GET_MODE (SUBREG_REG (x)));
  
  	  cancel_changes (num_changes);
  	  if (new == 0 && subreg_lowpart_p (x))
*************** mark_stores (dest, x, data)
*** 2691,2697 ****
      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);
        mode = GET_MODE (SUBREG_REG (dest));
      }
  
--- 2701,2712 ----
      regno = REGNO (dest), mode = GET_MODE (dest);
    else if (GET_CODE (dest) == SUBREG && GET_CODE (SUBREG_REG (dest)) == REG)
      {
!       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));
      }
  
Index: gcc/jump.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/jump.c,v
retrieving revision 1.159
diff -c -p -r1.159 jump.c
*** gcc/jump.c	2001/03/12 19:11:39	1.159
--- gcc/jump.c	2001/03/16 02:08:25
*************** rtx_renumbered_equal_p (x, y)
*** 3562,3568 ****
  				  && GET_CODE (SUBREG_REG (y)) == REG)))
      {
        int reg_x = -1, reg_y = -1;
!       int word_x = 0, word_y = 0;
  
        if (GET_MODE (x) != GET_MODE (y))
  	return 0;
--- 3562,3568 ----
  				  && GET_CODE (SUBREG_REG (y)) == REG)))
      {
        int reg_x = -1, reg_y = -1;
!       int byte_x = 0, byte_y = 0;
  
        if (GET_MODE (x) != GET_MODE (y))
  	return 0;
*************** rtx_renumbered_equal_p (x, y)
*** 3575,3589 ****
        if (code == SUBREG)
  	{
  	  reg_x = REGNO (SUBREG_REG (x));
! 	  word_x = SUBREG_WORD (x);
  
  	  if (reg_renumber[reg_x] >= 0)
  	    {
! 	      reg_x = reg_renumber[reg_x] + word_x;
! 	      word_x = 0;
  	    }
  	}
- 
        else
  	{
  	  reg_x = REGNO (x);
--- 3575,3591 ----
        if (code == SUBREG)
  	{
  	  reg_x = REGNO (SUBREG_REG (x));
! 	  byte_x = SUBREG_BYTE (x);
  
  	  if (reg_renumber[reg_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);
*************** rtx_renumbered_equal_p (x, y)
*** 3594,3608 ****
        if (GET_CODE (y) == SUBREG)
  	{
  	  reg_y = REGNO (SUBREG_REG (y));
! 	  word_y = SUBREG_WORD (y);
  
  	  if (reg_renumber[reg_y] >= 0)
  	    {
! 	      reg_y = reg_renumber[reg_y];
! 	      word_y = 0;
  	    }
  	}
- 
        else
  	{
  	  reg_y = REGNO (y);
--- 3596,3612 ----
        if (GET_CODE (y) == SUBREG)
  	{
  	  reg_y = REGNO (SUBREG_REG (y));
! 	  byte_y = SUBREG_BYTE (y);
  
  	  if (reg_renumber[reg_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);
*************** rtx_renumbered_equal_p (x, y)
*** 3610,3616 ****
  	    reg_y = reg_renumber[reg_y];
  	}
  
!       return reg_x >= 0 && reg_x == reg_y && word_x == word_y;
      }
  
    /* Now we have disposed of all the cases
--- 3614,3620 ----
  	    reg_y = reg_renumber[reg_y];
  	}
  
!       return reg_x >= 0 && reg_x == reg_y && byte_x == byte_y;
      }
  
    /* Now we have disposed of all the cases
*************** true_regnum (x)
*** 3741,3747 ****
      {
        int base = true_regnum (SUBREG_REG (x));
        if (base >= 0 && base < FIRST_PSEUDO_REGISTER)
! 	return SUBREG_WORD (x) + base;
      }
    return -1;
  }
--- 3745,3753 ----
      {
        int base = true_regnum (SUBREG_REG (x));
        if (base >= 0 && base < FIRST_PSEUDO_REGISTER)
! 	return base + subreg_regno_offset (REGNO (SUBREG_REG (x)),
! 					   GET_MODE (SUBREG_REG (x)),
! 					   SUBREG_BYTE (x), GET_MODE (x));
      }
    return -1;
  }
Index: gcc/local-alloc.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/local-alloc.c,v
retrieving revision 1.78
diff -c -p -r1.78 local-alloc.c
*** gcc/local-alloc.c	2001/02/02 01:03:47	1.78
--- gcc/local-alloc.c	2001/03/16 02:08:25
*************** combine_regs (usedreg, setreg, may_save_
*** 1813,1837 ****
      {
        if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (usedreg))) > UNITS_PER_WORD)
  	may_save_copy = 0;
!       offset += SUBREG_WORD (usedreg);
        usedreg = SUBREG_REG (usedreg);
      }
    if (GET_CODE (usedreg) != REG)
      return 0;
    ureg = REGNO (usedreg);
!   usize = REG_SIZE (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);
        setreg = SUBREG_REG (setreg);
      }
    if (GET_CODE (setreg) != REG)
      return 0;
    sreg = REGNO (setreg);
!   ssize = REG_SIZE (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
--- 1813,1861 ----
      {
        if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (usedreg))) > UNITS_PER_WORD)
  	may_save_copy = 0;
!       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);
!   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;
!       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);
!   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
*************** reg_is_born (reg, birth)
*** 2032,2038 ****
    register int regno;
  
    if (GET_CODE (reg) == SUBREG)
!     regno = REGNO (SUBREG_REG (reg)) + SUBREG_WORD (reg);
    else
      regno = REGNO (reg);
  
--- 2056,2066 ----
    register int regno;
  
    if (GET_CODE (reg) == SUBREG)
!     {
!       regno = REGNO (SUBREG_REG (reg));
!       if (regno < FIRST_PSEUDO_REGISTER)
! 	regno = subreg_hard_regno (reg, 1);
!     }
    else
      regno = REGNO (reg);
  
Index: gcc/recog.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/recog.c,v
retrieving revision 1.90
diff -c -p -r1.90 recog.c
*** gcc/recog.c	2001/02/18 23:56:34	1.90
--- gcc/recog.c	2001/03/16 02:08:25
*************** validate_replace_rtx_1 (loc, from, to, o
*** 519,531 ****
  	  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)),
  				      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;
  		  HOST_WIDE_INT valh;
  		  unsigned HOST_WIDE_INT vall;
  
--- 519,533 ----
  	  if (GET_CODE (XEXP (x, 0)) == SUBREG)
  	    {
  	      if (GET_MODE_SIZE (GET_MODE (XEXP (x, 0))) <= UNITS_PER_WORD)
! 		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_BYTE (XEXP (x, 0)) * BITS_PER_UNIT;
  		  HOST_WIDE_INT valh;
  		  unsigned HOST_WIDE_INT vall;
  
*************** validate_replace_rtx_1 (loc, from, to, o
*** 571,596 ****
        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.  */
        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))
  	    {
! 	      rtx new =  gen_lowpart_if_possible (GET_MODE (x), to);
  	      if (new)
  		{
  		  validate_change (object, loc, new, 1);
--- 573,593 ----
        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.  */
        if (CONSTANT_P (to) && rtx_equal_p (SUBREG_REG (x), from))
          {
! 	  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);
  	      if (new)
  		{
  		  validate_change (object, loc, new, 1);
*************** validate_replace_rtx_1 (loc, from, to, o
*** 598,610 ****
  		}
  	    }
  
! 	  /* 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)))
  	    {
! 	      validate_change (object, loc, to, 1);
! 	      return;
  	    }
          }
  
--- 595,661 ----
  		}
  	    }
  
! 	  offset = SUBREG_BYTE (x) * BITS_PER_UNIT;
! 	  switch (GET_CODE (to))
  	    {
! 	    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;
  	    }
          }
  
*************** validate_replace_rtx_1 (loc, from, to, o
*** 614,628 ****
  	  && rtx_equal_p (SUBREG_REG (x), from))
  	{
  	  if (GET_MODE (x) == GET_MODE (SUBREG_REG (to))
! 	      && SUBREG_WORD (x) == 0 && SUBREG_WORD (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);
  	  return;
  	}
  
--- 665,690 ----
  	  && rtx_equal_p (SUBREG_REG (x), from))
  	{
  	  if (GET_MODE (x) == GET_MODE (SUBREG_REG (to))
! 	      && SUBREG_BYTE (x) == 0 && SUBREG_BYTE (to) == 0)
  	    {
  	      validate_change (object, loc, SUBREG_REG (to), 1);
  	      return;
  	    }
  
! 	  /* 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;
  	}
  
*************** validate_replace_rtx_1 (loc, from, to, o
*** 638,652 ****
  	  && ! MEM_VOLATILE_P (to)
  	  && GET_MODE_SIZE (GET_MODE (x)) <= GET_MODE_SIZE (GET_MODE (to)))
  	{
! 	  int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
  	  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);
--- 700,709 ----
  	  && ! MEM_VOLATILE_P (to)
  	  && GET_MODE_SIZE (GET_MODE (x)) <= GET_MODE_SIZE (GET_MODE (to)))
  	{
! 	  int offset = SUBREG_BYTE (x);
  	  enum machine_mode mode = GET_MODE (x);
  	  rtx new;
  
  	  new = gen_rtx_MEM (mode, plus_constant (XEXP (to, 0), offset));
  	  MEM_COPY_ATTRIBUTES (new, to);
  	  validate_change (object, loc, new, 1);
*************** validate_replace_rtx_1 (loc, from, to, o
*** 696,703 ****
  	      int offset = pos / BITS_PER_UNIT;
  	      rtx newmem;
  
! 		  /* 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);
--- 753,760 ----
  	      int offset = pos / BITS_PER_UNIT;
  	      rtx newmem;
  
! 	      /* 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);
*************** general_operand (op, mode)
*** 1042,1048 ****
       enum machine_mode mode;
  {
    register enum rtx_code code = GET_CODE (op);
-   int mode_altering_drug = 0;
  
    if (mode == VOIDmode)
      mode = GET_MODE (op);
--- 1099,1104 ----
*************** general_operand (op, mode)
*** 1080,1090 ****
  
        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.  */
-