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]
Other format: [Raw text]

[Bug c/12521] New: C compiler generates wrong code


PLEASE REPLY TO gcc-bugzilla@gcc.gnu.org ONLY, *NOT* gcc-bugs@gcc.gnu.org.

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=12521

           Summary: C compiler generates wrong code
           Product: gcc
           Version: 3.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
        AssignedTo: unassigned at gcc dot gnu dot org
        ReportedBy: jmueller at hanoverdipalys dot com
                CC: gcc-bugs at gcc dot gnu dot org
 GCC build triplet: i686-pc-linux-gnu
  GCC host triplet: i686-pc-linux-gnu
GCC target triplet: h8300-hitachi-hms

	
The postdecrement of unsigned shorts (maybe other types as well) in a compare 
expresion of a while {...} loop generates a predecrement of these unsigned 
shorts.

The following program generates wrong code:

#include <stdio.h>

void bla (unsigned short count)
{
	while (count-- > 0)
	{
		fprintf (stdout, "%d\n", count);
	}
}

The resulting assembler file compiled with options -O2 -fomit-frame-pointer -ms -ms2600 -S looks like this:

;	GCC For the Hitachi H8/300
;	By Hitachi America Ltd and Cygnus Support
; -O2

	.h8300s
	.file	"bla.c"
	.section .rodata
.LC0:
	.ascii "%d\12\0"
	.section .text
	.align 1
	.global _bla
_bla:
	push.l	er4
	mov.w	r0,r4
	subs	#1,er4
	beq	.L7
.L5:
	mov.l	er4,@-er7
	mov.l	#.LC0,er2
	mov.l	er2,@-er7
	mov.l	@__impure_ptr,er2
	mov.l	@(8,er2),er0
	jsr	@_fprintf
	adds	#4,er7
	adds	#4,er7
	mov.w	r4,r2
	subs	#1,er4
	bne	.L5
.L7:
	pop.l	er4
	rts
	.end
	.ident
"GCC: (GNU) 3.1"

Environment:
System: Linux linux 2.2.16 #1 Wed Aug 2 20:22:26 GMT 2000 i686 unknown
Architecture: i686

	
host: i686-pc-linux-gnu
build: i686-pc-linux-gnu
target: h8300-hitachi-hms
configured with: ../configure --prefix=/home/jolli/Hitachi --target=h8300-hms --enable-language=c --with-newlib

How-To-Repeat:
	
When generating the cross compiler you have to apply the patch 
h8300-hms-gcc-3.1-1.patch as described on the website 
http://h8300-hms.sourceforge.net/ (the patch is enclosed next):

diff -rc gcc-3.1-old/gcc/config/h8300/crti.asm gcc-3.1/gcc/config/h8300/crti.asm
*** gcc-3.1-old/gcc/config/h8300/crti.asm	Fri Aug 31 06:24:46 2001
--- gcc-3.1/gcc/config/h8300/crti.asm	Sun May 19 11:05:38 2002
***************
*** 1,4 ****
! /* Copyright (C) 2001 Free Software Foundation, Inc.
  
  This file is part of GNU CC.
  
--- 1,4 ----
! /* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
  
  This file is part of GNU CC.
  
***************
*** 50,53 ****
  __init:
          .section .fini
          .global  __fini
! __fini:  
--- 50,53 ----
  __init:
          .section .fini
          .global  __fini
! __fini:
diff -rc gcc-3.1-old/gcc/config/h8300/h8300-protos.h gcc-3.1/gcc/config/h8300/h8300-protos.h
*** gcc-3.1-old/gcc/config/h8300/h8300-protos.h	Mon Feb 18 17:07:42 2002
--- gcc-3.1/gcc/config/h8300/h8300-protos.h	Sun May 19 11:33:17 2002
***************
*** 1,5 ****
! /* Definitions of target machine for GNU compiler. 
!    Hitachi H8/300 version generating coff 
     Copyright (C) 2000 Free SoftwareFoundation, Inc.
     Contributed by Steve Chamberlain (sac@cygnus.com),
     Jim Wilson (wilson@cygnus.com), and Doug Evans (dje@cygnus.com).
--- 1,5 ----
! /* Definitions of target machine for GNU compiler.
!    Hitachi H8/300 version generating coff
     Copyright (C) 2000 Free SoftwareFoundation, Inc.
     Contributed by Steve Chamberlain (sac@cygnus.com),
     Jim Wilson (wilson@cygnus.com), and Doug Evans (dje@cygnus.com).
***************
*** 26,32 ****
  
  /* Declarations for functions used in insn-output.c.  */
  #ifdef RTX_CODE
! extern const char *output_a_shift PARAMS ((rtx *));
  extern const char *emit_a_rotate PARAMS ((enum rtx_code, rtx *));
  extern const char *output_simode_bld PARAMS ((int, rtx[]));
  extern void print_operand_address PARAMS ((FILE *, rtx));
--- 26,33 ----
  
  /* Declarations for functions used in insn-output.c.  */
  #ifdef RTX_CODE
! extern const char *output_a_shift PARAMS ((rtx, rtx *));
! extern unsigned int compute_a_shift_length PARAMS ((rtx, rtx *));
  extern const char *emit_a_rotate PARAMS ((enum rtx_code, rtx *));
  extern const char *output_simode_bld PARAMS ((int, rtx[]));
  extern void print_operand_address PARAMS ((FILE *, rtx));
***************
*** 35,41 ****
  extern void final_prescan_insn PARAMS ((rtx, rtx *, int));
  extern int do_movsi PARAMS ((rtx[]));
  extern void notice_update_cc PARAMS ((rtx, rtx));
! extern const char *output_logical_op PARAMS ((enum machine_mode, int, rtx *));
  extern int expand_a_shift PARAMS ((enum machine_mode, int, rtx[]));
  extern int expand_a_rotate PARAMS ((enum rtx_code, rtx[]));
  extern int fix_bit_operand PARAMS ((rtx *, int, enum rtx_code));
--- 36,45 ----
  extern void final_prescan_insn PARAMS ((rtx, rtx *, int));
  extern int do_movsi PARAMS ((rtx[]));
  extern void notice_update_cc PARAMS ((rtx, rtx));
! extern const char *output_logical_op PARAMS ((enum machine_mode, rtx *));
! extern unsigned int compute_logical_op_length PARAMS ((enum machine_mode,
! 						       rtx *));
! extern int compute_logical_op_cc PARAMS ((enum machine_mode, rtx *));
  extern int expand_a_shift PARAMS ((enum machine_mode, int, rtx[]));
  extern int expand_a_rotate PARAMS ((enum rtx_code, rtx[]));
  extern int fix_bit_operand PARAMS ((rtx *, int, enum rtx_code));
diff -rc gcc-3.1-old/gcc/config/h8300/h8300.c gcc-3.1/gcc/config/h8300/h8300.c
*** gcc-3.1-old/gcc/config/h8300/h8300.c	Sat Feb 23 09:17:25 2002
--- gcc-3.1/gcc/config/h8300/h8300.c	Sun May 19 11:45:53 2002
***************
*** 54,59 ****
--- 54,60 ----
  static void push PARAMS ((FILE *, int));
  static void pop PARAMS ((FILE *, int));
  static const char *cond_string PARAMS ((enum rtx_code));
+ static unsigned int h8300_asm_insn_count PARAMS ((const char *));
  const struct attribute_spec h8300_attribute_table[];
  static tree h8300_handle_fndecl_attribute PARAMS ((tree *, tree, tree, int, bool *));
  static tree h8300_handle_eightbit_data_attribute PARAMS ((tree *, tree, tree, int, bool *));
***************
*** 270,276 ****
    fprintf (file, "\t%s\t%s\n", h8_pop_op, h8_reg_names[rn]);
  }
  
! /* This is what the stack looks like after the prolog of 
     a function with a frame has been set up:
  
     <args>
--- 271,277 ----
    fprintf (file, "\t%s\t%s\n", h8_pop_op, h8_reg_names[rn]);
  }
  
! /* This is what the stack looks like after the prolog of
     a function with a frame has been set up:
  
     <args>
***************
*** 727,735 ****
       rtx op;
       enum machine_mode mode;
  {
!   /* We can except any general operand, expept that MEM operands must
!      be limited to those that use addresses valid for the 'U' constraint.  */
!   if (!general_operand (op, mode))
      return 0;
  
    /* Accept any mem during RTL generation.  Otherwise, the code that does
--- 728,744 ----
       rtx op;
       enum machine_mode mode;
  {
!   int save_volatile_ok = volatile_ok;
!   int gen_op;
! 
!   /* We can except any general operand, including volatile one, expept
!      that MEM operands must be limited to those that use addresses
!      valid for the 'U' constraint.  */
!   volatile_ok = 1;
!   gen_op = general_operand (op, mode);
!   volatile_ok = save_volatile_ok;
! 
!   if (!gen_op)
      return 0;
  
    /* Accept any mem during RTL generation.  Otherwise, the code that does
***************
*** 1206,1228 ****
  	case MEM:
  	  {
  	    rtx addr = XEXP (x, 0);
  
  	    fprintf (file, "@");
  	    output_address (addr);
  
! 	    /* If this is an 'R' operand (reference into the 8-bit
! 	       area), then specify a symbolic address as "foo:8",
! 	       otherwise if operand is still in eight bit section, use
! 	       "foo:16".  */
! 	    if (GET_CODE (addr) == SYMBOL_REF
! 		&& SYMBOL_REF_FLAG (addr))
! 	      fprintf (file, (code == 'R' ? ":8" : ":16"));
! 	    else if (GET_CODE (addr) == SYMBOL_REF
! 		     && TINY_DATA_NAME_P (XSTR (addr, 0)))
! 	      fprintf (file, ":16");
! 	    else if ((code == 'R')
! 		     && EIGHTBIT_CONSTANT_ADDRESS_P (addr))
! 	      fprintf (file, ":8");
  	  }
  	  break;
  
--- 1215,1256 ----
  	case MEM:
  	  {
  	    rtx addr = XEXP (x, 0);
+ 	    int eightbit_ok = ((GET_CODE (addr) == SYMBOL_REF
+ 				&& SYMBOL_REF_FLAG (addr))
+ 			       || EIGHTBIT_CONSTANT_ADDRESS_P (addr));
+ 	    int tiny_ok = ((GET_CODE (addr) == SYMBOL_REF
+ 			    && TINY_DATA_NAME_P (XSTR (addr, 0)))
+ 			   || TINY_CONSTANT_ADDRESS_P (addr));
  
  	    fprintf (file, "@");
  	    output_address (addr);
  
! 	    /* We fall back from smaller addressing to larger
! 	       addressing in various ways depending on CODE.  */
! 	    switch (code)
! 	      {
! 	      case 'R':
! 		/* Used for mov.b and bit operations.  */
! 		if (eightbit_ok)
! 		  {
! 		    fprintf (file, ":8");
! 		    break;
! 		  }
! 
! 		/* Fall through.  We should not get here if we are
! 		   processing bit operations on H8/300 or H8/300H
! 		   because 'U' constraint does not allow bit
! 		   operations on the tiny area on these machines.  */
! 
! 	      case 'T':
! 	      case 'S':
! 		/* Used for mov.w and mov.l.  */
! 		if (tiny_ok)
! 		  fprintf (file, ":16");
! 		break;
! 	      default:
! 		break;
! 	      }
  	  }
  	  break;
  
***************
*** 1487,1497 ****
  }
  
  const char *
! output_logical_op (mode, code, operands)
       enum machine_mode mode;
-      int code;
       rtx *operands;
  {
    /* Pretend that every byte is affected if both operands are registers.  */
    unsigned HOST_WIDE_INT intval =
      (unsigned HOST_WIDE_INT) ((GET_CODE (operands[2]) == CONST_INT)
--- 1515,1526 ----
  }
  
  const char *
! output_logical_op (mode, operands)
       enum machine_mode mode;
       rtx *operands;
  {
+   /* Figure out the logical op that we need to perform.  */
+   enum rtx_code code = GET_CODE (operands[3]);
    /* Pretend that every byte is affected if both operands are registers.  */
    unsigned HOST_WIDE_INT intval =
      (unsigned HOST_WIDE_INT) ((GET_CODE (operands[2]) == CONST_INT)
***************
*** 1627,1632 ****
--- 1656,1822 ----
      }
    return "";
  }
+ 
+ unsigned int
+ compute_logical_op_length (mode, operands)
+      enum machine_mode mode;
+      rtx *operands;
+ {
+   /* Figure out the logical op that we need to perform.  */
+   enum rtx_code code = GET_CODE (operands[3]);
+   /* Pretend that every byte is affected if both operands are registers.  */
+   unsigned HOST_WIDE_INT intval =
+     (unsigned HOST_WIDE_INT) ((GET_CODE (operands[2]) == CONST_INT)
+ 			      ? INTVAL (operands[2]) : 0x55555555);
+   /* The determinant of the algorithm.  If we perform an AND, 0
+      affects a bit.  Otherwise, 1 affects a bit.  */
+   unsigned HOST_WIDE_INT det = (code != AND) ? intval : ~intval;
+   /* Insn length.  */
+   unsigned int length = 0;
+ 
+   switch (mode)
+     {
+     case HImode:
+       /* First, see if we can finish with one insn.  */
+       if ((TARGET_H8300H || TARGET_H8300S)
+ 	  && ((det & 0x00ff) != 0)
+ 	  && ((det & 0xff00) != 0))
+ 	{
+ 	  if (REG_P (operands[2]))
+ 	    length += 2;
+ 	  else
+ 	    length += 4;
+ 	}
+       else
+ 	{
+ 	  /* Take care of the lower byte.  */
+ 	  if ((det & 0x00ff) != 0)
+ 	    length += 2;
+ 
+ 	  /* Take care of the upper byte.  */
+ 	  if ((det & 0xff00) != 0)
+ 	    length += 2;
+ 	}
+       break;
+     case SImode:
+       /* First, see if we can finish with one insn.
+ 
+ 	 If code is either AND or XOR, we exclude two special cases,
+ 	 0xffffff00 and 0xffff00ff, because insns like sub.w or not.w
+ 	 can do a better job.  */
+       if ((TARGET_H8300H || TARGET_H8300S)
+ 	  && ((det & 0x0000ffff) != 0)
+ 	  && ((det & 0xffff0000) != 0)
+ 	  && (code == IOR || det != 0xffffff00)
+ 	  && (code == IOR || det != 0xffff00ff))
+ 	{
+ 	  if (REG_P (operands[2]))
+ 	    length += 4;
+ 	  else
+ 	    length += 6;
+ 	}
+       else
+ 	{
+ 	  /* Take care of the lower and upper words individually.  For
+ 	     each word, we try different methods in the order of
+ 
+ 	     1) the special insn (in case of AND or XOR),
+ 	     2) the word-wise insn, and
+ 	     3) The byte-wise insn.  */
+ 	  if ((det & 0x0000ffff) == 0x0000ffff
+ 	      && (TARGET_H8300 ? (code == AND) : (code != IOR)))
+ 	    {
+ 	      length += 2;
+ 	    }
+ 	  else if ((TARGET_H8300H || TARGET_H8300S)
+ 		   && ((det & 0x000000ff) != 0)
+ 		   && ((det & 0x0000ff00) != 0))
+ 	    {
+ 	      length += 4;
+ 	    }
+ 	  else
+ 	    {
+ 	      if ((det & 0x000000ff) != 0)
+ 		length += 2;
+ 
+ 	      if ((det & 0x0000ff00) != 0)
+ 		length += 2;
+ 	    }
+ 
+ 	  if ((det & 0xffff0000) == 0xffff0000
+ 	      && (TARGET_H8300 ? (code == AND) : (code != IOR)))
+ 	    {
+ 	      length += 2;
+ 	    }
+ 	  else if (TARGET_H8300H || TARGET_H8300S)
+ 	    {
+ 	      if ((det & 0xffff0000) != 0)
+ 		length += 4;
+ 	    }
+ 	  else
+ 	    {
+ 	      if ((det & 0x00ff0000) != 0)
+ 		length += 2;
+ 
+ 	      if ((det & 0xff000000) != 0)
+ 		length += 2;
+ 	    }
+ 	}
+       break;
+     default:
+       abort ();
+     }
+   return length;
+ }
+ 
+ int
+ compute_logical_op_cc (mode, operands)
+      enum machine_mode mode;
+      rtx *operands;
+ {
+   /* Figure out the logical op that we need to perform.  */
+   enum rtx_code code = GET_CODE (operands[3]);
+   /* Pretend that every byte is affected if both operands are registers.  */
+   unsigned HOST_WIDE_INT intval =
+     (unsigned HOST_WIDE_INT) ((GET_CODE (operands[2]) == CONST_INT)
+ 			      ? INTVAL (operands[2]) : 0x55555555);
+   /* The determinant of the algorithm.  If we perform an AND, 0
+      affects a bit.  Otherwise, 1 affects a bit.  */
+   unsigned HOST_WIDE_INT det = (code != AND) ? intval : ~intval;
+   /* Condition code.  */
+   enum attr_cc cc = CC_CLOBBER;
+ 
+   switch (mode)
+     {
+     case HImode:
+       /* First, see if we can finish with one insn.  */
+       if ((TARGET_H8300H || TARGET_H8300S)
+ 	  && ((det & 0x00ff) != 0)
+ 	  && ((det & 0xff00) != 0))
+ 	{
+ 	  cc = CC_SET_ZNV;
+ 	}
+       break;
+     case SImode:
+       /* First, see if we can finish with one insn.
+ 
+ 	 If code is either AND or XOR, we exclude two special cases,
+ 	 0xffffff00 and 0xffff00ff, because insns like sub.w or not.w
+ 	 can do a better job.  */
+       if ((TARGET_H8300H || TARGET_H8300S)
+ 	  && ((det & 0x0000ffff) != 0)
+ 	  && ((det & 0xffff0000) != 0)
+ 	  && (code == IOR || det != 0xffffff00)
+ 	  && (code == IOR || det != 0xffff00ff))
+ 	{
+ 	  cc = CC_SET_ZNV;
+ 	}
+       break;
+     default:
+       abort ();
+     }
+   return cc;
+ }
  
  /* Shifts.
  
***************
*** 1661,1667 ****
     Below, a trailing '*' after the shift count indicates the "best"
     mode isn't implemented.  We only describe SHIFT_SPECIAL cases to
     simplify the table.  For other cases, refer to shift_alg_[qhs]i.
!    
     H8/300 QImode shifts
     7      - ASHIFTRT: shll, subx (propagate carry bit to all bits)
  
--- 1851,1857 ----
     Below, a trailing '*' after the shift count indicates the "best"
     mode isn't implemented.  We only describe SHIFT_SPECIAL cases to
     simplify the table.  For other cases, refer to shift_alg_[qhs]i.
! 
     H8/300 QImode shifts
     7      - ASHIFTRT: shll, subx (propagate carry bit to all bits)
  
***************
*** 2128,2133 ****
--- 2318,2324 ----
  
  static void get_shift_alg PARAMS ((enum shift_type,
  				   enum shift_mode, unsigned int,
+ 				   int,
  				   struct shift_info *));
  
  /* Given SHIFT_TYPE, SHIFT_MODE, and shift count COUNT, determine the
***************
*** 2144,2153 ****
     1,2,3,4 will be inlined (1,2 for SI).  */
  
  static void
! get_shift_alg (shift_type, shift_mode, count, info)
       enum shift_type shift_type;
       enum shift_mode shift_mode;
       unsigned int count;
       struct shift_info *info;
  {
    int cpu;
--- 2335,2345 ----
     1,2,3,4 will be inlined (1,2 for SI).  */
  
  static void
! get_shift_alg (shift_type, shift_mode, count, into_smaller_mode, info)
       enum shift_type shift_type;
       enum shift_mode shift_mode;
       unsigned int count;
+      int into_smaller_mode;
       struct shift_info *info;
  {
    int cpu;
***************
*** 2378,2384 ****
  		}
  	      goto end;
  	    case SHIFT_LSHIFTRT:
! 	      info->special = "mov.w\t%e0,%f0\n\tsub.w\t%e0,%e0";
  	      if (TARGET_H8300)
  		{
  		  info->shift1 = "shlr\t%x0\n\trotxr\t%w0";
--- 2570,2579 ----
  		}
  	      goto end;
  	    case SHIFT_LSHIFTRT:
! 	      if (into_smaller_mode)
! 		info->special = "mov.w\t%e0,%f0";
! 	      else
! 		info->special = "mov.w\t%e0,%f0\n\tsub.w\t%e0,%e0";
  	      if (TARGET_H8300)
  		{
  		  info->shift1 = "shlr\t%x0\n\trotxr\t%w0";
***************
*** 2397,2403 ****
  		}
  	      else
  		{
! 		  info->special = "mov.w\t%e0,%f0\n\texts.l\t%S0";
  		  info->shift1  = "shar.l\t%S0";
  		  info->shift2  = "shar.l\t#2,%S0";
  		}
--- 2592,2601 ----
  		}
  	      else
  		{
! 		  if (into_smaller_mode)
! 		    info->special = "mov.w\t%e0,%f0";
! 		  else
! 		    info->special = "mov.w\t%e0,%f0\n\texts.l\t%S0";
  		  info->shift1  = "shar.l\t%S0";
  		  info->shift2  = "shar.l\t#2,%S0";
  		}
***************
*** 2407,2413 ****
        else if (TARGET_H8300 && 24 <= count && count <= 28)
  	{
  	  info->remainder = count - 24;
!  
  	  switch (shift_type)
  	    {
  	    case SHIFT_ASHIFT:
--- 2605,2611 ----
        else if (TARGET_H8300 && 24 <= count && count <= 28)
  	{
  	  info->remainder = count - 24;
! 
  	  switch (shift_type)
  	    {
  	    case SHIFT_ASHIFT:
***************
*** 2421,2429 ****
  	    case SHIFT_ASHIFTRT:
  	      info->special = "mov.b\t%z0,%w0\n\tbld\t#7,%w0\n\tsubx\t%x0,%x0\n\tsubx\t%x0,%x0\n\tsubx\t%x0,%x0";
  	      info->shift1  = "shar.b\t%w0";
!  	      goto end;
!  	    }
!  	}
        else if ((TARGET_H8300H && count == 24)
  	       || (TARGET_H8300S && 24 <= count && count <= 25))
  	{
--- 2619,2627 ----
  	    case SHIFT_ASHIFTRT:
  	      info->special = "mov.b\t%z0,%w0\n\tbld\t#7,%w0\n\tsubx\t%x0,%x0\n\tsubx\t%x0,%x0\n\tsubx\t%x0,%x0";
  	      info->shift1  = "shar.b\t%w0";
! 	      goto end;
! 	    }
! 	}
        else if ((TARGET_H8300H && count == 24)
  	       || (TARGET_H8300S && 24 <= count && count <= 25))
  	{
***************
*** 2437,2448 ****
  	      info->shift2  = "shll.l\t#2,%S0";
  	      goto end;
  	    case SHIFT_LSHIFTRT:
! 	      info->special = "mov.w\t%e0,%f0\n\tmov.b\t%t0,%s0\n\textu.w\t%f0\n\textu.l\t%S0";
  	      info->shift1  = "shlr.l\t%S0";
  	      info->shift2  = "shlr.l\t#2,%S0";
  	      goto end;
  	    case SHIFT_ASHIFTRT:
! 	      info->special = "mov.w\t%e0,%f0\n\tmov.b\t%t0,%s0\n\texts.w\t%f0\n\texts.l\t%S0";
  	      info->shift1  = "shar.l\t%S0";
  	      info->shift2  = "shar.l\t#2,%S0";
  	      goto end;
--- 2635,2653 ----
  	      info->shift2  = "shll.l\t#2,%S0";
  	      goto end;
  	    case SHIFT_LSHIFTRT:
! 	      if (into_smaller_mode)
! 		info->special = "mov.w\t%e0,%f0\n\tmov.b\t%t0,%s0\n\textu.w\t%f0";
! 	      else
! 		info->special = "mov.w\t%e0,%f0\n\tmov.b\t%t0,%s0\n\textu.w\t%f0\n\textu.l\t%S0";
! 
  	      info->shift1  = "shlr.l\t%S0";
  	      info->shift2  = "shlr.l\t#2,%S0";
  	      goto end;
  	    case SHIFT_ASHIFTRT:
! 	      if (into_smaller_mode)
! 		info->special = "mov.w\t%e0,%f0\n\tmov.b\t%t0,%s0\n\texts.w\t%f0";
! 	      else
! 		info->special = "mov.w\t%e0,%f0\n\tmov.b\t%t0,%s0\n\texts.w\t%f0\n\texts.l\t%S0";
  	      info->shift1  = "shar.l\t%S0";
  	      info->shift2  = "shar.l\t#2,%S0";
  	      goto end;
***************
*** 2495,2501 ****
  /* Emit the assembler code for doing shifts.  */
  
  const char *
! output_a_shift (operands)
       rtx *operands;
  {
    static int loopend_lab;
--- 2700,2707 ----
  /* Emit the assembler code for doing shifts.  */
  
  const char *
! output_a_shift (insn, operands)
!      rtx insn;
       rtx *operands;
  {
    static int loopend_lab;
***************
*** 2545,2551 ****
        fprintf (asm_out_file, "\tble	.Lle%d\n", loopend_lab);
  
        /* Get the assembler code to do one shift.  */
!       get_shift_alg (shift_type, shift_mode, 1, &info);
  
        fprintf (asm_out_file, ".Llt%d:\n", loopend_lab);
        output_asm_insn (info.shift1, operands);
--- 2751,2757 ----
        fprintf (asm_out_file, "\tble	.Lle%d\n", loopend_lab);
  
        /* Get the assembler code to do one shift.  */
!       get_shift_alg (shift_type, shift_mode, 1, 0, &info);
  
        fprintf (asm_out_file, ".Llt%d:\n", loopend_lab);
        output_asm_insn (info.shift1, operands);
***************
*** 2558,2563 ****
--- 2764,2770 ----
    else
      {
        int n = INTVAL (operands[2]);
+       int into_smaller_mode = 0;
  
        /* If the count is negative, make it 0.  */
        if (n < 0)
***************
*** 2568,2574 ****
        else if ((unsigned int) n > GET_MODE_BITSIZE (mode))
  	n = GET_MODE_BITSIZE (mode);
  
!       get_shift_alg (shift_type, shift_mode, n, &info);
  
        switch (info.alg)
  	{
--- 2775,2797 ----
        else if ((unsigned int) n > GET_MODE_BITSIZE (mode))
  	n = GET_MODE_BITSIZE (mode);
  
!       /* Determine if the destination only uses the smaller mode after
! 	 this shift insn.  We could do more advanced tests, but for
! 	 now, we just check for 'use'.  */
!       if (NEXT_INSN (insn) != NULL
! 	  && GET_CODE (NEXT_INSN (insn)) == INSN
! 	  && GET_CODE (PATTERN (NEXT_INSN (insn))) == USE)
! 	{
! 	  rtx usedrtx = XEXP (PATTERN (NEXT_INSN (insn)), 0);
! 
! 	  if (GET_CODE (usedrtx) == REG
! 	      && REGNO (usedrtx) == REGNO (operands[0])
! 	      && (GET_MODE_BITSIZE (GET_MODE (usedrtx))
! 		  < GET_MODE_BITSIZE (GET_MODE (operands[0]))))
! 	    into_smaller_mode = 1;
! 	}
! 
!       get_shift_alg (shift_type, shift_mode, n, into_smaller_mode, &info);
  
        switch (info.alg)
  	{
***************
*** 2682,2687 ****
--- 2905,3064 ----
  	}
      }
  }
+ 
+ static unsigned int
+ h8300_asm_insn_count (const char *template)
+ {
+   unsigned int count = 1;
+ 
+   for (; *template; template++)
+     if (*template == '\n')
+       count++;
+ 
+   return count;
+ }
+ 
+ unsigned int
+ compute_a_shift_length (insn, operands)
+      rtx insn ATTRIBUTE_UNUSED;
+      rtx *operands;
+ {
+   rtx shift = operands[3];
+   enum machine_mode mode = GET_MODE (shift);
+   enum rtx_code code = GET_CODE (shift);
+   enum shift_type shift_type;
+   enum shift_mode shift_mode;
+   struct shift_info info;
+   unsigned int wlength = 0;
+ 
+   switch (mode)
+     {
+     case QImode:
+       shift_mode = QIshift;
+       break;
+     case HImode:
+       shift_mode = HIshift;
+       break;
+     case SImode:
+       shift_mode = SIshift;
+       break;
+     default:
+       abort ();
+     }
+ 
+   switch (code)
+     {
+     case ASHIFTRT:
+       shift_type = SHIFT_ASHIFTRT;
+       break;
+     case LSHIFTRT:
+       shift_type = SHIFT_LSHIFTRT;
+       break;
+     case ASHIFT:
+       shift_type = SHIFT_ASHIFT;
+       break;
+     default:
+       abort ();
+     }
+ 
+   if (GET_CODE (operands[2]) != CONST_INT)
+     {
+       /* Get the assembler code to do one shift.  */
+       get_shift_alg (shift_type, shift_mode, 1, 0, &info);
+ 
+       return (4 + h8300_asm_insn_count (info.shift1)) * 2;
+     }
+   else
+     {
+       int n = INTVAL (operands[2]);
+ 
+       /* If the count is negative, make it 0.  */
+       if (n < 0)
+ 	n = 0;
+       /* If the count is too big, truncate it.
+          ANSI says shifts of GET_MODE_BITSIZE are undefined - we choose to
+ 	 do the intuitive thing.  */
+       else if ((unsigned int) n > GET_MODE_BITSIZE (mode))
+ 	n = GET_MODE_BITSIZE (mode);
+ 
+       get_shift_alg (shift_type, shift_mode, n, 0, &info);
+ 
+       switch (info.alg)
+ 	{
+ 	case SHIFT_SPECIAL:
+ 	  wlength += h8300_asm_insn_count (info.special);
+ 	  /* Fall through.  */
+ 
+ 	case SHIFT_INLINE:
+ 	  n = info.remainder;
+ 
+ 	  if (info.shift2 != NULL)
+ 	    {
+ 	      wlength += h8300_asm_insn_count (info.shift2) * (n / 2);
+ 	      n = n % 2;
+ 	    }
+ 
+ 	  wlength += h8300_asm_insn_count (info.shift1) * n;
+ 
+ 	  return 2 * wlength;
+ 
+ 	case SHIFT_ROT_AND:
+ 	  {
+ 	    int m = GET_MODE_BITSIZE (mode) - n;
+ 
+ 	    /* Not all possibilities of rotate are supported.  They shouldn't
+ 	       be generated, but let's watch for 'em.  */
+ 	    if (info.shift1 == 0)
+ 	      abort ();
+ 
+ 	    if (info.shift2 != NULL)
+ 	      {
+ 		wlength += h8300_asm_insn_count (info.shift2) * (m / 2);
+ 		m = m % 2;
+ 	      }
+ 
+ 	    wlength += h8300_asm_insn_count (info.shift1) * m;
+ 
+ 	    /* Now mask off the high bits.  */
+ 	    switch (mode)
+ 	      {
+ 	      case QImode:
+ 		wlength += 1;
+ 		break;
+ 	      case HImode:
+ 		wlength += 2;
+ 		break;
+ 	      case SImode:
+ 		if (TARGET_H8300)
+ 		  abort ();
+ 		wlength += 3;
+ 		break;
+ 	      default:
+ 		abort ();
+ 	      }
+ 	    return 2 * wlength;
+ 	  }
+ 
+ 	case SHIFT_LOOP:
+ 	  /* A loop to shift by a "large" constant value.
+ 	     If we have shift-by-2 insns, use them.  */
+ 	  if (info.shift2 != NULL)
+ 	    {
+ 	      wlength += 3 + h8300_asm_insn_count (info.shift2);
+ 	      if (n % 2)
+ 		wlength += h8300_asm_insn_count (info.shift1);
+ 	    }
+ 	  else
+ 	    {
+ 	      wlength += 3 + h8300_asm_insn_count (info.shift1);
+ 	    }
+ 	  return 2 * wlength;
+ 
+ 	default:
+ 	  abort ();
+ 	}
+     }
+ }
  
  /* A rotation by a non-constant will cause a loop to be generated, in
     which a rotation by one bit is used.  A rotation by a constant,
***************
*** 3186,3219 ****
        else
  	addr = XEXP (SET_DEST (pat), 0);
  
!       /* On the H8/300, only one adjustment is necessary; if the
! 	 address mode is register indirect, then this insn is two
! 	 bytes shorter than indicated in the machine description.  */
!       if (TARGET_H8300 && GET_CODE (addr) == REG)
! 	return -2;
! 
!       /* On the H8/300H and H8/S, register indirect is 6 bytes shorter than
! 	 indicated in the machine description.  */
!       if ((TARGET_H8300H || TARGET_H8300S)
!           && GET_CODE (addr) == REG)
! 	return -6;
! 
!       /* On the H8/300H and H8/S, reg + d, for small displacements is
! 	 4 bytes shorter than indicated in the machine description.  */
!       if ((TARGET_H8300H || TARGET_H8300S)
! 	  && GET_CODE (addr) == PLUS
! 	  && GET_CODE (XEXP (addr, 0)) == REG
! 	  && GET_CODE (XEXP (addr, 1)) == CONST_INT
! 	  && INTVAL (XEXP (addr, 1)) > -32768
! 	  && INTVAL (XEXP (addr, 1)) < 32767)
! 	return -4;
  
!       /* On the H8/300H and H8/S, abs:16 is two bytes shorter than the
! 	 more general abs:24.  */
!       if ((TARGET_H8300H || TARGET_H8300S)
! 	  && GET_CODE (addr) == SYMBOL_REF
! 	  && TINY_DATA_NAME_P (XSTR (addr, 0)))
! 	return -2;
      }
  
    /* Loading some constants needs adjustment.  */
--- 3563,3611 ----
        else
  	addr = XEXP (SET_DEST (pat), 0);
  
!       if (TARGET_H8300)
! 	{
! 	  /* On the H8/300, we subtract the difference between the
!              actual length and the longest one, which is @(d:16,ERs).  */
  
! 	  /* @Rs is 2 bytes shorter than the longest.  */
! 	  if (GET_CODE (addr) == REG)
! 	    return -2;
! 	}
!       else
! 	{
! 	  /* On the H8/300H and H8/S, we subtract the difference
!              between the actual length and the longest one, which is
!              @(d:24,ERs).  */
! 
! 	  /* @ERs is 6 bytes shorter than the longest.  */
! 	  if (GET_CODE (addr) == REG)
! 	    return -6;
! 
! 	  /* @(d:16,ERs) is 6 bytes shorter than the longest.  */
! 	  if (GET_CODE (addr) == PLUS
! 	      && GET_CODE (XEXP (addr, 0)) == REG
! 	      && GET_CODE (XEXP (addr, 1)) == CONST_INT
! 	      && INTVAL (XEXP (addr, 1)) > -32768
! 	      && INTVAL (XEXP (addr, 1)) < 32767)
! 	    return -4;
! 
! 	  /* @aa:8 is 6 bytes shorter than the longest.  */
! 	  if (GET_MODE (SET_SRC (pat)) == QImode
! 	      && ((GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_FLAG (addr))
! 		  || EIGHTBIT_CONSTANT_ADDRESS_P (addr)))
! 	    return -6;
! 
! 	  /* @aa:16 is 4 bytes shorter than the longest.  */
! 	  if ((GET_CODE (addr) == SYMBOL_REF
! 	       && TINY_DATA_NAME_P (XSTR (addr, 0)))
! 	      || TINY_CONSTANT_ADDRESS_P (addr))
! 	    return -4;
! 
! 	  /* @aa:24 is 2 bytes shorter than the longest.  */
! 	  if (GET_CODE (addr) == CONST_INT)
! 	    return -2;
! 	}
      }
  
    /* Loading some constants needs adjustment.  */
***************
*** 3251,3300 ****
  	}
      }
  
-   /* Shifts need various adjustments.  */
-   if (GET_CODE (pat) == PARALLEL
-       && GET_CODE (XVECEXP (pat, 0, 0)) == SET
-       && (GET_CODE (SET_SRC (XVECEXP (pat, 0, 0))) == ASHIFTRT
- 	  || GET_CODE (SET_SRC (XVECEXP (pat, 0, 0))) == LSHIFTRT
- 	  || GET_CODE (SET_SRC (XVECEXP (pat, 0, 0))) == ASHIFT))
-     {
-       rtx src = SET_SRC (XVECEXP (pat, 0, 0));
-       enum machine_mode mode = GET_MODE (src);
-       int shift;
- 
-       if (GET_CODE (XEXP (src, 1)) != CONST_INT)
- 	return 0;
- 
-       shift = INTVAL (XEXP (src, 1));
-       /* According to ANSI, negative shift is undefined.  It is
-          considered to be zero in this case (see function
-          output_a_shift above).  */
-       if (shift < 0)
- 	shift = 0;
- 
-       /* QImode shifts by small constants take one insn
- 	 per shift.  So the adjustment is 20 (md length) -
- 	 # shifts * 2.  */
-       if (mode == QImode && shift <= 4)
- 	return -(20 - shift * 2);
- 
-       /* Similarly for HImode and SImode shifts by small constants on
- 	 the H8/300H and H8/S.  */
-       if ((TARGET_H8300H || TARGET_H8300S)
- 	  && (mode == HImode || mode == SImode) && shift <= 4)
- 	return -(20 - shift * 2);
- 
-       /* HImode shifts by small constants for the H8/300.  */
-       if (mode == HImode && shift <= 4)
- 	return -(20 - (shift * (GET_CODE (src) == ASHIFT ? 2 : 4)));
- 
-       /* SImode shifts by small constants for the H8/300.  */
-       if (mode == SImode && shift <= 2)
- 	return -(20 - (shift * (GET_CODE (src) == ASHIFT ? 6 : 8)));
- 
-       /* XXX ??? Could check for more shift/rotate cases here.  */
-     }
- 
    /* Rotations need various adjustments.  */
    if (GET_CODE (pat) == SET
        && (GET_CODE (SET_SRC (pat)) == ROTATE
--- 3643,3648 ----
diff -rc gcc-3.1-old/gcc/config/h8300/h8300.h gcc-3.1/gcc/config/h8300/h8300.h
*** gcc-3.1-old/gcc/config/h8300/h8300.h	Tue Feb 19 02:36:55 2002
--- gcc-3.1/gcc/config/h8300/h8300.h	Sun May 19 11:05:38 2002
***************
*** 1,5 ****
! /* Definitions of target machine for GNU compiler. 
!    Hitachi H8/300 version generating coff 
     Copyright (C) 1992, 1993, 1994, 1995, 1996, 1996, 1997, 1998, 1999,
     2000, 2001, 2002 Free Software Foundation, Inc.
     Contributed by Steve Chamberlain (sac@cygnus.com),
--- 1,5 ----
! /* Definitions of target machine for GNU compiler.
!    Hitachi H8/300 version generating coff
     Copyright (C) 1992, 1993, 1994, 1995, 1996, 1996, 1997, 1998, 1999,
     2000, 2001, 2002 Free Software Foundation, Inc.
     Contributed by Steve Chamberlain (sac@cygnus.com),
***************
*** 171,177 ****
  /* Define this if addresses of constant functions
     shouldn't be put through pseudo regs where they can be cse'd.
     Desirable on machines where ordinary constants are expensive
!    but a CALL with constant address is cheap. 
  
     Calls through a register are cheaper than calls to named
     functions; however, the register pressure this causes makes
--- 171,177 ----
  /* Define this if addresses of constant functions
     shouldn't be put through pseudo regs where they can be cse'd.
     Desirable on machines where ordinary constants are expensive
!    but a CALL with constant address is cheap.
  
     Calls through a register are cheaper than calls to named
     functions; however, the register pressure this causes makes
***************
*** 194,200 ****
  #define BYTES_BIG_ENDIAN 1
  
  /* Define this if most significant word of a multiword number is lowest
!    numbered.  
     This is true on an H8/300 (actually we can make it up, but we choose to
     be consistent).  */
  #define WORDS_BIG_ENDIAN 1
--- 194,200 ----
  #define BYTES_BIG_ENDIAN 1
  
  /* Define this if most significant word of a multiword number is lowest
!    numbered.
     This is true on an H8/300 (actually we can make it up, but we choose to
     be consistent).  */
  #define WORDS_BIG_ENDIAN 1
***************
*** 263,269 ****
     from 0 to just below FIRST_PSEUDO_REGISTER.
  
     All registers that the compiler knows about must be given numbers,
!    even those that are not normally considered general registers.  
  
     Reg 9 does not correspond to any hardware register, but instead
     appears in the RTL as an argument pointer prior to reload, and is
--- 263,269 ----
     from 0 to just below FIRST_PSEUDO_REGISTER.
  
     All registers that the compiler knows about must be given numbers,
!    even those that are not normally considered general registers.
  
     Reg 9 does not correspond to any hardware register, but instead
     appears in the RTL as an argument pointer prior to reload, and is
***************
*** 284,290 ****
     The latter must include the registers where values are returned
     and the register where structure-value addresses are passed.
     Aside from that, you can include as many other registers as you
!    like.  
  
     H8 destroys r0,r1,r2,r3.  */
  
--- 284,290 ----
     The latter must include the registers where values are returned
     and the register where structure-value addresses are passed.
     Aside from that, you can include as many other registers as you
!    like.
  
     H8 destroys r0,r1,r2,r3.  */
  
***************
*** 304,310 ****
     to hold something of mode MODE.
  
     This is ordinarily the length in words of a value of mode MODE
!    but can be less for certain modes in special long registers. 
  
     We pretend the MAC register is 32bits -- we don't have any data
     types on the H8 series to handle more than 32bits.  */
--- 304,310 ----
     to hold something of mode MODE.
  
     This is ordinarily the length in words of a value of mode MODE
!    but can be less for certain modes in special long registers.
  
     We pretend the MAC register is 32bits -- we don't have any data
     types on the H8 series to handle more than 32bits.  */
***************
*** 424,430 ****
  #define INDEX_REG_CLASS NO_REGS
  #define BASE_REG_CLASS  GENERAL_REGS
  
! /* Get reg_class from a letter such as appears in the machine description. 
  
     'a' is the MAC register.  */
  
--- 424,430 ----
  #define INDEX_REG_CLASS NO_REGS
  #define BASE_REG_CLASS  GENERAL_REGS
  
! /* Get reg_class from a letter such as appears in the machine description.
  
     'a' is the MAC register.  */
  
***************
*** 463,470 ****
     0)
  
  /* Similar, but for floating constants, and defining letters G and H.
!    Here VALUE is the CONST_DOUBLE rtx itself. 
!      
    `G' is a floating-point zero.  */
  
  #define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C)	\
--- 463,470 ----
     0)
  
  /* Similar, but for floating constants, and defining letters G and H.
!    Here VALUE is the CONST_DOUBLE rtx itself.
! 
    `G' is a floating-point zero.  */
  
  #define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C)	\
***************
*** 486,492 ****
  #define CLASS_MAX_NREGS(CLASS, MODE)	\
    ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
  
! /* Any SI register-to-register move may need to be reloaded, 
     so define REGISTER_MOVE_COST to be > 2 so that reload never
     shortcuts.  */
  
--- 486,492 ----
  #define CLASS_MAX_NREGS(CLASS, MODE)	\
    ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
  
! /* Any SI register-to-register move may need to be reloaded,
     so define REGISTER_MOVE_COST to be > 2 so that reload never
     shortcuts.  */
  
***************
*** 586,593 ****
  /* Define how to find the value returned by a function.
     VALTYPE is the data type of the value (as a tree).
     If the precise function being called is known, FUNC is its FUNCTION_DECL;
!    otherwise, FUNC is 0. 
!    
     On the H8 the return value is in R0/R1.  */
  
  #define FUNCTION_VALUE(VALTYPE, FUNC) \
--- 586,593 ----
  /* Define how to find the value returned by a function.
     VALTYPE is the data type of the value (as a tree).
     If the precise function being called is known, FUNC is its FUNCTION_DECL;
!    otherwise, FUNC is 0.
! 
     On the H8 the return value is in R0/R1.  */
  
  #define FUNCTION_VALUE(VALTYPE, FUNC) \
***************
*** 728,734 ****
  #define EXIT_IGNORE_STACK 0
  
  /* Output assembler code for a block containing the constant parts
!    of a trampoline, leaving space for the variable parts.  
  
     H8/300
  	      vvvv context
--- 728,734 ----
  #define EXIT_IGNORE_STACK 0
  
  /* Output assembler code for a block containing the constant parts
!    of a trampoline, leaving space for the variable parts.
  
     H8/300
  	      vvvv context
***************
*** 860,865 ****
--- 860,873 ----
    (GET_CODE (X) == CONST_INT && TARGET_H8300H		\
     && 0xffff00 <= INTVAL (X) && INTVAL (X) <= 0xffffff)
  
+ /* Nonzero if X is a constant address suitable as an 16-bit absolute
+    on the H8/300H.  */
+ 
+ #define TINY_CONSTANT_ADDRESS_P(X)				\
+   (GET_CODE (X) == CONST_INT && TARGET_H8300H			\
+    && ((0xff8000 <= INTVAL (X) && INTVAL (X) <= 0xffffff)	\
+        || (0x000000 <= INTVAL (X) && INTVAL (X) <= 0x007fff)))
+ 
  /* 'U' if valid for a bset destination;
     i.e. a register, register indirect, or the eightbit memory region
     (a SYMBOL_REF with an SYMBOL_REF_FLAG set).
***************
*** 892,912 ****
  
     The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS,
     except for CONSTANT_ADDRESS_P which is actually
!    machine-independent.  
  
     On the H8/300, a legitimate address has the form
     REG, REG+CONSTANT_ADDRESS or CONSTANT_ADDRESS.  */
  
  /* Accept either REG or SUBREG where a register is valid.  */
  
! #define RTX_OK_FOR_BASE_P(X)					\
!   ((REG_P (X) && REG_OK_FOR_BASE_P (X))				\
!    || (GET_CODE (X) == SUBREG && REG_P (SUBREG_REG (X))		\
         && REG_OK_FOR_BASE_P (SUBREG_REG (X))))
  
! #define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) 	\
    if (RTX_OK_FOR_BASE_P (X)) goto ADDR;			\
!   if (CONSTANT_ADDRESS_P (X)) goto ADDR; 		\
    if (GET_CODE (X) == PLUS				\
        && CONSTANT_ADDRESS_P (XEXP (X, 1))		\
        && RTX_OK_FOR_BASE_P (XEXP (X, 0))) goto ADDR;
--- 900,920 ----
  
     The other macros defined here are used only in GO_IF_LEGITIMATE_ADDRESS,
     except for CONSTANT_ADDRESS_P which is actually
!    machine-independent.
  
     On the H8/300, a legitimate address has the form
     REG, REG+CONSTANT_ADDRESS or CONSTANT_ADDRESS.  */
  
  /* Accept either REG or SUBREG where a register is valid.  */
  
! #define RTX_OK_FOR_BASE_P(X)				\
!   ((REG_P (X) && REG_OK_FOR_BASE_P (X))			\
!    || (GET_CODE (X) == SUBREG && REG_P (SUBREG_REG (X))	\
         && REG_OK_FOR_BASE_P (SUBREG_REG (X))))
  
! #define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR)		\
    if (RTX_OK_FOR_BASE_P (X)) goto ADDR;			\
!   if (CONSTANT_ADDRESS_P (X)) goto ADDR;		\
    if (GET_CODE (X) == PLUS				\
        && CONSTANT_ADDRESS_P (XEXP (X, 1))		\
        && RTX_OK_FOR_BASE_P (XEXP (X, 0))) goto ADDR;
***************
*** 922,928 ****
     GO_IF_LEGITIMATE_ADDRESS.
  
     It is always safe for this macro to do nothing.  It exists to recognize
!    opportunities to optimize the output. 
  
     For the H8/300, don't do anything.  */
  
--- 930,936 ----
     GO_IF_LEGITIMATE_ADDRESS.
  
     It is always safe for this macro to do nothing.  It exists to recognize
!    opportunities to optimize the output.
  
     For the H8/300, don't do anything.  */
  
diff -rc gcc-3.1-old/gcc/config/h8300/h8300.md gcc-3.1/gcc/config/h8300/h8300.md
*** gcc-3.1-old/gcc/config/h8300/h8300.md	Sat Feb 23 09:17:25 2002
--- gcc-3.1/gcc/config/h8300/h8300.md	Sun May 19 11:06:44 2002
***************
*** 1033,1056 ****
    ""
    "")
  
- (define_insn ""
-   [(set (match_operand:HI 0 "register_operand" "=r")
- 	(and:HI (match_operand:HI 1 "register_operand" "%0")
- 		(match_operand:HI 2 "nonmemory_operand" "rn")))]
-   "TARGET_H8300"
-   "* return output_logical_op (HImode, AND, operands);"
-   [(set_attr "length" "4")
-    (set_attr "cc" "clobber")])
- 
- (define_insn ""
-   [(set (match_operand:HI 0 "register_operand" "=r,r")
- 	(and:HI (match_operand:HI 1 "register_operand" "%0,0")
- 		(match_operand:HI 2 "nonmemory_operand" "r,n")))]
-   "TARGET_H8300H || TARGET_H8300S"
-   "* return output_logical_op (HImode, AND, operands);"
-   [(set_attr "length" "2,4")
-    (set_attr "cc" "set_znv,clobber")])
- 
  (define_insn "*andorhi3"
    [(set (match_operand:HI 0 "register_operand" "=r")
  	(ior:HI (and:HI (match_operand:HI 2 "register_operand" "r")
--- 1033,1038 ----
***************
*** 1077,1100 ****
    ""
    "")
  
- (define_insn ""
-   [(set (match_operand:SI 0 "register_operand" "=r")
- 	(and:SI (match_operand:SI 1 "register_operand" "%0")
- 		(match_operand:SI 2 "nonmemory_operand" "rn")))]
-   "TARGET_H8300"
-   "* return output_logical_op (SImode, AND, operands);"
-   [(set_attr "length" "8")
-    (set_attr "cc" "clobber")])
- 
- (define_insn ""
-   [(set (match_operand:SI 0 "register_operand" "=r,r")
- 	(and:SI (match_operand:SI 1 "register_operand" "%0,0")
- 		(match_operand:SI 2 "nonmemory_operand" "r,n")))]
-   "TARGET_H8300H || TARGET_H8300S"
-   "* return output_logical_op (SImode, AND, operands);"
-   [(set_attr "length" "4,6")
-    (set_attr "cc" "set_znv,clobber")])
- 
  ;; ----------------------------------------------------------------------
  ;; OR INSTRUCTIONS
  ;; ----------------------------------------------------------------------
--- 1059,1064 ----
***************
*** 1141,1164 ****
    ""
    "")
  
- (define_insn ""
-   [(set (match_operand:HI 0 "general_operand" "=r,r")
- 	(ior:HI (match_operand:HI 1 "general_operand" "%0,0")
- 		(match_operand:HI 2 "general_operand" "J,rn")))]
-   "TARGET_H8300"
-   "* return output_logical_op (HImode, IOR, operands);"
-   [(set_attr "length" "2,4")
-    (set_attr "cc" "clobber,clobber")])
- 
- (define_insn ""
-   [(set (match_operand:HI 0 "general_operand" "=r,r,r")
- 	(ior:HI (match_operand:HI 1 "general_operand" "%0,0,0")
- 		(match_operand:HI 2 "general_operand" "J,r,n")))]
-   "TARGET_H8300H || TARGET_H8300S"
-   "* return output_logical_op (HImode, IOR, operands);"
-   [(set_attr "length" "2,2,4")
-    (set_attr "cc" "clobber,set_znv,clobber")])
- 
  (define_expand "iorsi3"
    [(set (match_operand:SI 0 "register_operand" "")
  	(ior:SI (match_operand:SI 1 "register_operand" "")
--- 1105,1110 ----
***************
*** 1166,1189 ****
    ""
    "")
  
- (define_insn ""
-   [(set (match_operand:SI 0 "register_operand" "=r,r")
- 	(ior:SI (match_operand:SI 1 "register_operand" "%0,0")
- 		(match_operand:SI 2 "nonmemory_operand" "J,rn")))]
-   "TARGET_H8300"
-   "* return output_logical_op (SImode, IOR, operands);"
-   [(set_attr "length" "2,8")
-    (set_attr "cc" "clobber,clobber")])
- 
- (define_insn ""
-   [(set (match_operand:SI 0 "register_operand" "=r,r,r")
- 	(ior:SI (match_operand:SI 1 "register_operand" "%0,0,0")
- 		(match_operand:SI 2 "nonmemory_operand" "J,r,n")))]
-   "TARGET_H8300H || TARGET_H8300S"
-   "* return output_logical_op (SImode, IOR, operands);"
-   [(set_attr "length" "2,4,6")
-    (set_attr "cc" "clobber,set_znv,clobber")])
- 
  ;; ----------------------------------------------------------------------
  ;; XOR INSTRUCTIONS
  ;; ----------------------------------------------------------------------
--- 1112,1117 ----
***************
*** 1230,1253 ****
    ""
    "")
  
- (define_insn ""
-   [(set (match_operand:HI 0 "register_operand" "=r,r")
- 	(xor:HI (match_operand:HI 1 "register_operand" "%0,0")
- 		(match_operand:HI 2 "nonmemory_operand" "J,rn")))]
-   "TARGET_H8300"
-   "* return output_logical_op (HImode, XOR, operands);"
-   [(set_attr "length" "2,4")
-    (set_attr "cc" "clobber,clobber")])
- 
- (define_insn ""
-   [(set (match_operand:HI 0 "register_operand" "=r,r,r")
- 	(xor:HI (match_operand:HI 1 "register_operand" "%0,0,0")
- 		(match_operand:HI 2 "nonmemory_operand" "J,r,n")))]
-   "TARGET_H8300H || TARGET_H8300S"
-   "* return output_logical_op (HImode, XOR, operands);"
-   [(set_attr "length" "2,2,4")
-    (set_attr "cc" "clobber,set_znv,clobber")])
- 
  (define_expand "xorsi3"
    [(set (match_operand:SI 0 "register_operand" "")
  	(xor:SI (match_operand:SI 1 "register_operand" "")
--- 1158,1163 ----
***************
*** 1255,1277 ****
    ""
    "")
  
  (define_insn ""
!   [(set (match_operand:SI 0 "register_operand" "=r,r")
! 	(xor:SI (match_operand:SI 1 "register_operand" "%0,0")
! 		(match_operand:SI 2 "nonmemory_operand" "J,rn")))]
!   "TARGET_H8300"
!   "* return output_logical_op (SImode, XOR, operands);"
!   [(set_attr "length" "2,8")
!    (set_attr "cc" "clobber,clobber")])
  
  (define_insn ""
!   [(set (match_operand:SI 0 "register_operand" "=r,r,r")
! 	(xor:SI (match_operand:SI 1 "register_operand" "%0,0,0")
! 		(match_operand:SI 2 "nonmemory_operand" "J,r,n")))]
!   "TARGET_H8300H || TARGET_H8300S"
!   "* return output_logical_op (SImode, XOR, operands);"
!   [(set_attr "length" "2,4,6")
!    (set_attr "cc" "clobber,set_znv,clobber")])
  
  ;; ----------------------------------------------------------------------
  ;; NEGATION INSTRUCTIONS
--- 1165,1197 ----
    ""
    "")
  
+ ;; ----------------------------------------------------------------------
+ ;; {AND,IOR,XOR}{HI3,SI3} PATTERNS
+ ;; ----------------------------------------------------------------------
+ 
  (define_insn ""
!   [(set (match_operand:HI 0 "register_operand" "=r")
! 	(match_operator:HI 3 "bit_operator"
! 	  [(match_operand:HI 1 "register_operand" "%0")
! 	   (match_operand:HI 2 "nonmemory_operand" "rn")]))]
!   ""
!   "* return output_logical_op (HImode, operands);"
!   [(set (attr "length")
! 	(symbol_ref "compute_logical_op_length (HImode, operands)"))
!    (set (attr "cc")
! 	(symbol_ref "compute_logical_op_cc (HImode, operands)"))])
  
  (define_insn ""
!   [(set (match_operand:SI 0 "register_operand" "=r")
! 	(match_operator:SI 3 "bit_operator"
! 	  [(match_operand:SI 1 "register_operand" "%0")
! 	   (match_operand:SI 2 "nonmemory_operand" "rn")]))]
!   ""
!   "* return output_logical_op (SImode, operands);"
!   [(set (attr "length")
! 	(symbol_ref "compute_logical_op_length (SImode, operands)"))
!    (set (attr "cc")
! 	(symbol_ref "compute_logical_op_cc (SImode, operands)"))])
  
  ;; ----------------------------------------------------------------------
  ;; NEGATION INSTRUCTIONS
***************
*** 1848,1855 ****
  			  (match_operand:QI 2 "nonmemory_operand" "KM,rn")]))
     (clobber (match_scratch:QI 4 "=X,&r"))]
    ""
!   "* return output_a_shift (operands);"
!   [(set_attr "length" "20")
     (set_attr "cc" "clobber")])
  
  ;; HI BIT SHIFTS
--- 1768,1776 ----
  			  (match_operand:QI 2 "nonmemory_operand" "KM,rn")]))
     (clobber (match_scratch:QI 4 "=X,&r"))]
    ""
!   "* return output_a_shift (insn, operands);"
!   [(set (attr "length")
! 	(symbol_ref "compute_a_shift_length (insn, operands)"))
     (set_attr "cc" "clobber")])
  
  ;; HI BIT SHIFTS
***************
*** 1882,1889 ****
  			  (match_operand:QI 2 "nonmemory_operand" "KM,rn")]))
     (clobber (match_scratch:QI 4 "=X,&r"))]
    ""
!   "* return output_a_shift (operands);"
!   [(set_attr "length" "20")
     (set_attr "cc" "clobber")])
  
  ;;  SI BIT SHIFTS
--- 1803,1811 ----
  			  (match_operand:QI 2 "nonmemory_operand" "KM,rn")]))
     (clobber (match_scratch:QI 4 "=X,&r"))]
    ""
!   "* return output_a_shift (insn, operands);"
!   [(set (attr "length")
! 	(symbol_ref "compute_a_shift_length (insn, operands)"))
     (set_attr "cc" "clobber")])
  
  ;;  SI BIT SHIFTS
***************
*** 1916,1923 ****
  			  (match_operand:QI 2 "nonmemory_operand" "K,rn")]))
     (clobber (match_scratch:QI 4 "=X,&r"))]
    ""
!   "* return output_a_shift (operands);"
!   [(set_attr "length" "20")
     (set_attr "cc" "clobber")])
  
  ;; ----------------------------------------------------------------------
--- 1838,1846 ----
  			  (match_operand:QI 2 "nonmemory_operand" "K,rn")]))
     (clobber (match_scratch:QI 4 "=X,&r"))]
    ""
!   "* return output_a_shift (insn, operands);"
!   [(set (attr "length")
! 	(symbol_ref "compute_a_shift_length (insn, operands)"))
     (set_attr "cc" "clobber")])
  
  ;; ----------------------------------------------------------------------
diff -rc gcc-3.1-old/gcc/config/h8300/lib1funcs.asm gcc-3.1/gcc/config/h8300/lib1funcs.asm
*** gcc-3.1-old/gcc/config/h8300/lib1funcs.asm	Thu Jan 10 16:30:32 2002
--- gcc-3.1/gcc/config/h8300/lib1funcs.asm	Sun May 19 11:05:38 2002
***************
*** 1,7 ****
  ;; libgcc routines for the Hitachi H8/300 CPU.
  ;; Contributed by Steve Chamberlain <sac@cygnus.com>
  
! /* Copyright (C) 1994, 2000, 2001 Free Software Foundation, Inc.
  
  This file is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public License as published by the
--- 1,8 ----
  ;; libgcc routines for the Hitachi H8/300 CPU.
  ;; Contributed by Steve Chamberlain <sac@cygnus.com>
+ ;; Optimizations by Toshiyasu Morita <toshiyasu.morita@hsa.hitachi.com>
  
! /* Copyright (C) 1994, 2000, 2001, 2002 Free Software Foundation, Inc.
  
  This file is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public License as published by the
***************
*** 108,131 ****
  	.align 2
  	.global ___cmpsi2
  ___cmpsi2:
! 	cmp.w	A2,A0
! 	bne	.L2
! 	cmp.w	A3,A1
  	bne	.L2
  	mov.w	#1,A0
  	rts
  .L2:
! 	cmp.w	A0,A2
! 	bgt	.L4
! 	bne	.L3
! 	cmp.w	A1,A3
! 	bls	.L3
! .L4:
! 	sub.w	A0,A0
! 	rts
  .L3:
  	mov.w	#2,A0
  .L5:
  	rts
  	.end
  #endif
--- 109,129 ----
  	.align 2
  	.global ___cmpsi2
  ___cmpsi2:
! 	cmp.w	A0,A2
  	bne	.L2
+ 	cmp.w	A1,A3
+ 	bne	.L4
  	mov.w	#1,A0
  	rts
  .L2:
! 	bgt	.L5
  .L3:
  	mov.w	#2,A0
+ 	rts
+ .L4:
+ 	bls	.L3
  .L5:
+ 	sub.w	A0,A0
  	rts
  	.end
  #endif
***************
*** 137,160 ****
  	.align 2
  	.global ___ucmpsi2
  ___ucmpsi2:
! 	cmp.w	A2,A0
! 	bne	.L2
! 	cmp.w	A3,A1
  	bne	.L2
  	mov.w	#1,A0
  	rts
  .L2:
! 	cmp.w	A0,A2
! 	bhi	.L4
! 	bne	.L3
! 	cmp.w	A1,A3
! 	bls	.L3
! .L4:
! 	sub.w	A0,A0
! 	rts
  .L3:
  	mov.w	#2,A0
  .L5:
  	rts
  	.end
  #endif
--- 135,155 ----
  	.align 2
  	.global ___ucmpsi2
  ___ucmpsi2:
! 	cmp.w	A0,A2
  	bne	.L2
+ 	cmp.w	A1,A3
+ 	bne	.L4
  	mov.w	#1,A0
  	rts
  .L2:
! 	bhi	.L5
  .L3:
  	mov.w	#2,A0
+ 	rts
+ .L4:
+ 	bls	.L3
  .L5:
+ 	sub.w	A0,A0
  	rts
  	.end
  #endif
***************
*** 167,173 ****
  ;; "supporting routines".
  
  ; general purpose normalize routine
! ; 
  ; divisor in A0
  ; dividend in A1
  ; turns both into +ve numbers, and leaves what the answer sign
--- 162,168 ----
  ;; "supporting routines".
  
  ; general purpose normalize routine
! ;
  ; divisor in A0
  ; dividend in A1
  ; turns both into +ve numbers, and leaves what the answer sign
***************
*** 179,191 ****
  divnorm:
  	mov.b	#0x0,A2L
  	or	A0H,A0H		; is divisor > 0
! 	bge	_lab1			
  	not	A0H		; no - then make it +ve
  	not	A0L
! 	adds	#1,A0			
  	xor	#0x1,A2L	; and remember that in A2L
  _lab1:	or	A1H,A1H	; look at dividend
! 	bge	_lab2		
  	not	A1H		; it is -ve, make it positive
  	not	A1L
  	adds	#1,A1
--- 174,186 ----
  divnorm:
  	mov.b	#0x0,A2L
  	or	A0H,A0H		; is divisor > 0
! 	bge	_lab1
  	not	A0H		; no - then make it +ve
  	not	A0L
! 	adds	#1,A0
  	xor	#0x1,A2L	; and remember that in A2L
  _lab1:	or	A1H,A1H	; look at dividend
! 	bge	_lab2
  	not	A1H		; it is -ve, make it positive
  	not	A1L
  	adds	#1,A1
***************
*** 196,208 ****
  modnorm:
  	mov.b	#0x0,A2L
  	or	A0H,A0H		; is divisor > 0
! 	bge	_lab7			
  	not	A0H		; no - then make it +ve
  	not	A0L
! 	adds	#1,A0			
  	xor	#0x1,A2L	; and remember that in A2L
  _lab7:	or	A1H,A1H	; look at dividend
! 	bge	_lab8		
  	not	A1H		; it is -ve, make it positive
  	not	A1L
  	adds	#1,A1
--- 191,203 ----
  modnorm:
  	mov.b	#0x0,A2L
  	or	A0H,A0H		; is divisor > 0
! 	bge	_lab7
  	not	A0H		; no - then make it +ve
  	not	A0L
! 	adds	#1,A0
  	xor	#0x1,A2L	; and remember that in A2L
  _lab7:	or	A1H,A1H	; look at dividend
! 	bge	_lab8
  	not	A1H		; it is -ve, make it positive
  	not	A1L
  	adds	#1,A1
***************
*** 219,225 ****
  	not	A0H	; yes, so make it so
  	not	A0L
  	adds	#1,A0
! _lab4:	rts	
  
  ; A0=A0%A1 signed
  
--- 214,220 ----
  	not	A0H	; yes, so make it so
  	not	A0L
  	adds	#1,A0
! _lab4:	rts
  
  ; A0=A0%A1 signed
  
***************
*** 256,268 ****
  
  	.global	___udivhi3
  ___udivhi3:
! 				; A0 A1 A2 A3 
  				; Nn Dd       P
! 	sub.w	A3,A3		; Nn Dd xP 00 
! 	or	A1H,A1H		 
  	bne	divlongway
! 	or	A0H,A0H		
! 	beq	_lab6		
  
  ; we know that D == 0 and N is != 0
  	mov.b	A0H,A3L		; Nn Dd xP 0N
--- 251,263 ----
  
  	.global	___udivhi3
  ___udivhi3:
! 				; A0 A1 A2 A3
  				; Nn Dd       P
! 	sub.w	A3,A3		; Nn Dd xP 00
! 	or	A1H,A1H
  	bne	divlongway
! 	or	A0H,A0H
! 	beq	_lab6
  
  ; we know that D == 0 and N is != 0
  	mov.b	A0H,A3L		; Nn Dd xP 0N
***************
*** 274,280 ****
  	mov.b	A3L,A0L		; Qq
  	mov.b	A3H,A3L         ;           m
  	mov.b	#0x0,A3H	; Qq       0m
! 	rts	
  
  ; D != 0 - which means the denominator is
  ;          loop around to get the result.
--- 269,275 ----
  	mov.b	A3L,A0L		; Qq
  	mov.b	A3H,A3L         ;           m
  	mov.b	#0x0,A3H	; Qq       0m
! 	rts
  
  ; D != 0 - which means the denominator is
  ;          loop around to get the result.
***************
*** 285,303 ****
  	mov.b	#0x8,A2H	;       8
  div8:	add.b	A0L,A0L		; n*=2
  	rotxl	A3L		; Make remainder bigger
! 	rotxl	A3H		
  	sub.w	A1,A3		; Q-=N
  	bhs	setbit		; set a bit ?
  	add.w	A1,A3		;  no : too far , Q+=N
  
! 	dec	A2H		
! 	bne	div8		; next bit	
! 	rts	
  
  setbit:	inc	A0L		; do insert bit
! 	dec	A2H		
! 	bne	div8		; next bit	
! 	rts	
  
  #endif /* __H8300__ */
  #endif /* L_divhi3 */
--- 280,298 ----
  	mov.b	#0x8,A2H	;       8
  div8:	add.b	A0L,A0L		; n*=2
  	rotxl	A3L		; Make remainder bigger
! 	rotxl	A3H
  	sub.w	A1,A3		; Q-=N
  	bhs	setbit		; set a bit ?
  	add.w	A1,A3		;  no : too far , Q+=N
  
! 	dec	A2H
! 	bne	div8		; next bit
! 	rts
  
  setbit:	inc	A0L		; do insert bit
! 	dec	A2H
! 	bne	div8		; next bit
! 	rts
  
  #endif /* __H8300__ */
  #endif /* L_divhi3 */
***************
*** 306,312 ****
  
  ;; 4 byte integer divides for the H8/300.
  ;;
! ;; We have one routine which does all the work and lots of 
  ;; little ones which prepare the args and massage the sign.
  ;; We bunch all of this into one object file since there are several
  ;; "supporting routines".
--- 301,307 ----
  
  ;; 4 byte integer divides for the H8/300.
  ;;
! ;; We have one routine which does all the work and lots of
  ;; little ones which prepare the args and massage the sign.
  ;; We bunch all of this into one object file since there are several
  ;; "supporting routines".
***************
*** 339,349 ****
  postive:
  	mov.b	A2H,A2H		; is the denominator -ve
  	bge	postive2
! 	not	A2L		
  	not	A2H
  	not	A3L
  	not	A3H
! 	add.b	#1,A3L	
  	addx	#0,A3H
  	addx	#0,A2L
  	addx	#0,A2H
--- 334,344 ----
  postive:
  	mov.b	A2H,A2H		; is the denominator -ve
  	bge	postive2
! 	not	A2L
  	not	A2H
  	not	A3L
  	not	A3H
! 	add.b	#1,A3L
  	addx	#0,A3H
  	addx	#0,A2L
  	addx	#0,A2H
***************
*** 373,383 ****
  mpostive:
  	mov.b	A2H,A2H		; is the denominator -ve
  	bge	mpostive2
! 	not	A2L		
  	not	A2H
  	not	A3L
  	not	A3H
! 	add.b	#1,A3L	
  	addx	#0,A3H
  	addx	#0,A2L
  	addx	#0,A2H
--- 368,378 ----
  mpostive:
  	mov.b	A2H,A2H		; is the denominator -ve
  	bge	mpostive2
! 	not	A2L
  	not	A2H
  	not	A3L
  	not	A3H
! 	add.b	#1,A3L
  	addx	#0,A3H
  	addx	#0,A2L
  	addx	#0,A2H
***************
*** 429,435 ****
  ; denominator in A2/A3
  	.global	___modsi3
  ___modsi3:
! 	PUSHP	S2P		
  	PUSHP	S0P
  	PUSHP	S1P
  
--- 424,430 ----
  ; denominator in A2/A3
  	.global	___modsi3
  ___modsi3:
! 	PUSHP	S2P
  	PUSHP	S0P
  	PUSHP	S1P
  
***************
*** 466,472 ****
  	mov.l	S0P,A0P
  #endif
  	bra	exitdiv
! 	
  	.global	___divsi3
  ___divsi3:
  	PUSHP	S2P
--- 461,467 ----
  	mov.l	S0P,A0P
  #endif
  	bra	exitdiv
! 
  	.global	___divsi3
  ___divsi3:
  	PUSHP	S2P
***************
*** 482,488 ****
  
  	or	S2L,S2L
  	beq	reti
! 	
  	; should be -ve
  #ifdef __H8300__
  	not	A0H
--- 477,483 ----
  
  	or	S2L,S2L
  	beq	reti
! 
  	; should be -ve
  #ifdef __H8300__
  	not	A0H
***************
*** 500,506 ****
  
  reti:
  	POPP	S2P
! 	rts	
  
  	; takes A0/A1 numerator (A0P for 300H)
  	; A2/A3 denominator (A1P for 300H)
--- 495,501 ----
  
  reti:
  	POPP	S2P
! 	rts
  
  	; takes A0/A1 numerator (A0P for 300H)
  	; A2/A3 denominator (A1P for 300H)
***************
*** 543,549 ****
  
          mov.b	S1H,S1L
          mov.b	#0x0,S1H
!         rts	
  
  ; have to do the divide by shift and test
  DenHighZero:
--- 538,544 ----
  
          mov.b	S1H,S1L
          mov.b	#0x0,S1H
!         rts
  
  ; have to do the divide by shift and test
  DenHighZero:
***************
*** 567,573 ****
          sub.w	A3,S1	; does it all fit
          subx	A2L,S0L
          subx	A2H,S0H
!         bhs	setone	 
  
          add.w	A3,S1	; no, restore mistake
          addx	A2L,S0L
--- 562,568 ----
          sub.w	A3,S1	; does it all fit
          subx	A2L,S0L
          subx	A2H,S0H
!         bhs	setone
  
          add.w	A3,S1	; no, restore mistake
          addx	A2L,S0L
***************
*** 575,587 ****
  
          dec	S2H
          bne	nextbit
!         rts	
! 	
  setone:
  	inc	A1L
          dec	S2H
          bne	nextbit
!         rts	
  
  #else /* __H8300H__ */
  
--- 570,582 ----
  
          dec	S2H
          bne	nextbit
!         rts
! 
  setone:
  	inc	A1L
          dec	S2H
          bne	nextbit
!         rts
  
  #else /* __H8300H__ */
  
***************
*** 636,646 ****
  ;; HImode multiply.
  ; The H8/300 only has an 8*8->16 multiply.
  ; The answer is the same as:
! ; 
  ; product = (srca.l * srcb.l) + ((srca.h * srcb.l) + (srcb.h * srca.l)) * 256
  ; (we can ignore A1.h * A0.h cause that will all off the top)
  ; A0 in
! ; A1 in 
  ; A0 answer
  
  #ifdef __H8300__
--- 631,641 ----
  ;; HImode multiply.
  ; The H8/300 only has an 8*8->16 multiply.
  ; The answer is the same as:
! ;
  ; product = (srca.l * srcb.l) + ((srca.h * srcb.l) + (srcb.h * srca.l)) * 256
  ; (we can ignore A1.h * A0.h cause that will all off the top)
  ; A0 in
! ; A1 in
  ; A0 answer
  
  #ifdef __H8300__
***************
*** 649,655 ****
  	.global	___mulhi3
  ___mulhi3:
  	mov.b	A1L,A2L		; A2l gets srcb.l
! 	mulxu	A0L,A2		; A2 gets first sub product 
  
  	mov.b	A0H,A3L		; prepare for
  	mulxu	A1L,A3		; second sub product
--- 644,650 ----
  	.global	___mulhi3
  ___mulhi3:
  	mov.b	A1L,A2L		; A2l gets srcb.l
! 	mulxu	A0L,A2		; A2 gets first sub product
  
  	mov.b	A0H,A3L		; prepare for
  	mulxu	A1L,A3		; second sub product
***************
*** 657,663 ****
  	add.b	A3L,A2H		; sum first two terms
  
  	mov.b	A1H,A3L		; third sub product
! 	mulxu	A0L,A3		
  
  	add.b	A3L,A2H		; almost there
  	mov.w	A2,A0		; that is
--- 652,658 ----
  	add.b	A3L,A2H		; sum first two terms
  
  	mov.b	A1H,A3L		; third sub product
! 	mulxu	A0L,A3
  
  	add.b	A3L,A2H		; almost there
  	mov.w	A2,A0		; that is
***************
*** 669,675 ****
  #ifdef L_mulsi3
  
  ;; SImode multiply.
! ;; 
  ;; I think that shift and add may be sufficient for this.  Using the
  ;; supplied 8x8->16 would need 10 ops of 14 cycles each + overhead.  This way
  ;; the inner loop uses maybe 20 cycles + overhead, but terminates
--- 664,670 ----
  #ifdef L_mulsi3
  
  ;; SImode multiply.
! ;;
  ;; I think that shift and add may be sufficient for this.  Using the
  ;; supplied 8x8->16 would need 10 ops of 14 cycles each + overhead.  This way
  ;; the inner loop uses maybe 20 cycles + overhead, but terminates
***************
*** 678,684 ****
  ;; A0/A1 src_a
  ;; A2/A3 src_b
  ;;
! ;;  while (a) 
  ;;    {
  ;;      if (a & 1)
  ;;        r += b;
--- 673,679 ----
  ;; A0/A1 src_a
  ;; A2/A3 src_b
  ;;
! ;;  while (a)
  ;;    {
  ;;      if (a & 1)
  ;;        r += b;
***************
*** 696,705 ****
  	PUSHP	S0P
  	PUSHP	S1P
  	PUSHP	S2P
! 	
  	sub.w	S0,S0
  	sub.w	S1,S1
! 	
  	; while (a)
  _top:	mov.w	A0,A0
  	bne	_more
--- 691,700 ----
  	PUSHP	S0P
  	PUSHP	S1P
  	PUSHP	S2P
! 
  	sub.w	S0,S0
  	sub.w	S1,S1
! 
  	; while (a)
  _top:	mov.w	A0,A0
  	bne	_more
***************
*** 718,724 ****
  	rotxr	A0L
  	rotxr	A1H
  	rotxr	A1L
! 	
  	; b <<= 1
  	add.w	A3,A3
  	addx	A2L,A2L
--- 713,719 ----
  	rotxr	A0L
  	rotxr	A1H
  	rotxr	A1L
! 
  	; b <<= 1
  	add.w	A3,A3
  	addx	A2L,A2L
***************
*** 726,732 ****
  	bra 	_top
  
  _done:
! 	mov.w	S0,A0	
  	mov.w	S1,A1
  	POPP	S2P
  	POPP	S1P
--- 721,727 ----
  	bra 	_top
  
  _done:
! 	mov.w	S0,A0
  	mov.w	S1,A1
  	POPP	S2P
  	POPP	S1P
***************
*** 735,766 ****
  
  #else /* __H8300H__ */
  
  	.global	___mulsi3
  ___mulsi3:
! 	sub.l	A2P,A2P
  
! 	; while (a)
! _top:	mov.l	A0P,A0P
! 	beq	_done
! 
! 	; if (a & 1)
! 	bld	#0,A0L
! 	bcc	_nobit
! 
! 	; r += b
! 	add.l	A1P,A2P
! 
! _nobit:
! 	; a >>= 1
! 	shlr.l	A0P
! 
! 	; b <<= 1
! 	shll.l	A1P
! 	bra	_top
! 
! _done:
! 	mov.l	A2P,A0P
! 	rts
  
  #endif
  #endif /* L_mulsi3 */
--- 730,771 ----
  
  #else /* __H8300H__ */
  
+ ;
+ ; mulsi3 for H8/300H - based on Hitachi SH implementation
+ ;
+ ; by Toshiyasu Morita
+ ;
+ ; Old code:
+ ;
+ ; 16b * 16b = 372 states (worst case)
+ ; 32b * 32b = 724 states (worst case)
+ ;
+ ; New code:
+ ;
+ ; 16b * 16b =  48 states
+ ; 16b * 32b =  72 states
+ ; 32b * 32b =  92 states
+ ;
+ 
  	.global	___mulsi3
  ___mulsi3:
! 	mov.w	r1,r2   ; ( 2 states) b * d
! 	mulxu	r0,er2  ; (22 states)
  
! 	mov.w	e0,r3   ; ( 2 states) a * d
! 	beq	L_skip1 ; ( 4 states)
! 	mulxu	r1,er3  ; (22 states)
! 	add.w	r3,e2   ; ( 2 states)
! 
! L_skip1:
! 	mov.w	e1,r3   ; ( 2 states) c * b
! 	beq	L_skip2 ; ( 4 states)
! 	mulxu	r0,er3  ; (22 states)
! 	add.w	r3,e2   ; ( 2 states)
! 
! L_skip2:
! 	mov.l	er2,er0	; ( 2 states)
! 	rts		; (10 states)
  
  #endif
  #endif /* L_mulsi3 */
diff -rc gcc-3.1-old/gcc/flow.c gcc-3.1/gcc/flow.c
*** gcc-3.1-old/gcc/flow.c	Thu Apr 18 16:21:09 2002
--- gcc-3.1/gcc/flow.c	Sun May 19 11:05:30 2002
***************
*** 3955,3963 ****
    if (y != 0
        && SET_DEST (x) != stack_pointer_rtx
        && BLOCK_NUM (y) == BLOCK_NUM (insn)
!       /* Don't do this if the reg dies, or gets set in y; a standard addressing
! 	 mode would be better.  */
!       && ! dead_or_set_p (y, SET_DEST (x))
        && try_pre_increment (y, SET_DEST (x), amount))
      {
        /* We have found a suitable auto-increment and already changed
--- 3955,3964 ----
    if (y != 0
        && SET_DEST (x) != stack_pointer_rtx
        && BLOCK_NUM (y) == BLOCK_NUM (insn)
!       /* We cannot use pre-increment if y clobbers the register REGNO.
!          We can still consider a register that is not used after y,
!          hoping pre-increment is faster than indexed addressing.  */
!       && ! reg_set_p (SET_DEST (x), y)
        && try_pre_increment (y, SET_DEST (x), amount))
      {
        /* We have found a suitable auto-increment and already changed
------- Additional Comments From jmueller at hanoverdipalys dot com  2003-10-06 09:25 -------
Fix:
	
Good question. The problem seems to occure when using unsigned shorts, shorts,
unsigned longs and longs. But for unsigned chars and chars the C compiler
generates the correct code. Try to identify the difference and apply the rules
for unsigned chars and chars to the other data types.


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