🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: gnu.gcc.bug
Article #6316

patch for faster version of strlen

#6316
From: Wolfgang Formann
Date: Mon, 18 Dec 1995 00:00
491 lines
21448 bytes
Hello!

I want to send you a little patch which makes the inlined function strlen(3)
much faster on i[45]86.  Since the the fastest version on i486 and on i586
differ a little I have also added the new options -m[no-]586, -m[no-]pentium
to get optimal code for each processor.  Still code generated for one of
Intel's processors runs on each other.  I have tried hard, but on an i386
I did not find a faster way than the good old repne scasb.

Here is a little table that shows the speedup.  The string I took the length
from was 500 bytes long.
+-------------------+-------------+---------------+---------------+
+ processor\pattern | repne scasb | 486-optimized | 586-optimized |
+                   |            clock  cycles  used              |
+-------------------+-------------+---------------+---------------+
+ i386-33           |       11311 |         11613 |         12284 |
+ i486DX2/50 (AMD)  |        4572 |          2873 |          3105 |
+ i486DX2/50 (Intel)|        4573 |          2874 |          3107 |
+ i586-90           |        2026 |           772 |           658 |
+-------------------+-------------+---------------+---------------+
The difference between Intel's and AMD's i486 depend on the moon ;-)

The differences on shorter strings are similar.  So as you can see the
optimized code is not so bad on i386, but it gives a nice speedup on
the others.

Well I have added the new switch -m586 / -mpentium.  I implemented theese in
the way that no old code is affected.  -mno-pentium is the same as
-mno-486, which is the same as -m386.  -mpentium also turns on -m486.
The macro TARGET_386 is true when none of the bits for i[45]86 are set.
The macro TARGET_486 is not modified.
The new macro TARGET_586 is true when the bits for i486 *AND* i586 are set.

( also included is a little typo in md.texi [ if instead of iff ])

I hope I have explained enough ;->

The patch is based on gcc.2.7.2.


Sun Dec 17 11:14:29 1995  Wolfgang Formann <wolfi@exner.tgm.ac.at>

	* Added flags -m586, -mpentium

	* New inlined versions for strlen(), optimized for i486 and i586

	* Fixed typo in md.texi, added new flags to invoke.texi


diff -rcp -x TAGS -x c-parse.y -x c-parse.c -x c-parse.h -x c-gperf.h -x cexp.c -x bi-parser.c -x objc-parse.y -x objc-parse.c -x gcc.?? -x gcc.??s -x gcc.aux -x gcc.info* -x cpp.?? -x cpp.??s -x cpp.aux -x cpp.info* -x */cp/parse.c -x */cp/parse.h -x Makefile gcc-2.7.2/config/i386/i386.c gcc-2.7.2-new/config/i386/i386.c
*** gcc-2.7.2/config/i386/i386.c	Sun Oct 22 12:13:21 1995
--- gcc-2.7.2-new/config/i386/i386.c	Sun Dec 17 12:42:19 1995
*************** assign_386_stack_local (mode, n)
*** 3243,3245 ****
--- 3243,3433 ----
  
    return i386_stack_locals[(int) mode][n];
  }
+ 
+ /* Output the approprate insns for doing strlen if not just doing repnz; scasb
+ 
+    operands[0] = result, initialized with the startaddress
+    operands[1] = alignment of the address.
+    operands[2] = scratch register, initialized with the startaddress when
+    		 not aligned, otherwise undefined
+ 
+    This is just the body. It needs the initialisations mentioned above and
+    some adress computing at the end.  These things are done in i386.md.  */
+ 
+ char *
+ output_strlen_unroll (operands)
+      rtx operands[];
+ {
+   rtx xops[18];
+ 
+   xops[0] = operands[0];		/* Result */
+   /*        operands[1];                 * Alignment */
+   xops[1] = operands[2];		/* Scratch */
+   xops[2] = GEN_INT (0);
+   xops[3] = GEN_INT (2);
+   xops[4] = GEN_INT (3);
+   xops[5] = GEN_INT (4);
+   /* xops[6] = gen_label_rtx ();	 * label when aligned to 3-byte */
+   /* xops[7] = gen_label_rtx ();	 * label when aligned to 2-byte */
+   xops[8] = gen_label_rtx ();		/* label of main loop */
+   if(TARGET_586 && QI_REG_P (xops[1]))
+     xops[9] = gen_label_rtx ();		/* pentium optimisation */
+   xops[10] = gen_label_rtx ();		/* end label 2 */
+   xops[11] = gen_label_rtx ();		/* end label 1 */
+   xops[12] = gen_label_rtx ();		/* end label */
+   /* xops[13]				 * Temporary used */
+   xops[14] = GEN_INT (0xff);
+   xops[15] = GEN_INT (0xff00);
+   xops[16] = GEN_INT (0xff0000);
+   xops[17] = GEN_INT (0xff000000);
+ 
+     /* maybe you do not want this ?? */
+   fprintf (asm_out_file, "\n%s start of strlen\n", ASM_COMMENT_START);
+ 
+     /* Loop to check 1..3 bytes for null to get an aligned pointer */
+ 
+     /* is there a known alignment and is it less then 4 */
+   if (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) < 4)
+     {
+ 	/* is there a known alignment and is it not 2 */
+       if (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 2)
+ 	{
+ 	  xops[6] = gen_label_rtx ();	/* label when aligned to 3-byte */
+ 	  xops[7] = gen_label_rtx ();	/* label when aligned to 2-byte */
+ 
+ 	    /* leave just the 3 lower bits */
+ 	    /* if this is a q-register, then the high part is used later */
+ 	    /* therefore user andl rather than andb */
+ 	  output_asm_insn (AS2 (and%L1,%4,%1), xops);
+ 	    /* is aligned to 4-byte adress when zero */
+ 	  output_asm_insn (AS1 (je,%l8), xops);
+ 	    /* side-effect even Parity when %eax == 3 */
+ 	  output_asm_insn (AS1 (jp,%6), xops);
+ 
+ 	    /* is it aligned to 2 bytes ? */
+ 	  if (QI_REG_P (xops[1]))
+ 	    output_asm_insn (AS2 (cmp%B1,%3,%1), xops);
+ 	  else
+ 	    output_asm_insn (AS2 (cmp%L1,%3,%1), xops);
+ 	  output_asm_insn (AS1 (je,%7), xops);
+ 	}
+       else
+         {
+             /* since the alignment is 2, we have to check 2 or 0 bytes */
+ 
+ 	    /* check if is aligned to 4 - byte */
+ 	  output_asm_insn (AS2 (and%L1,%3,%1), xops);
+ 	    /* is aligned to 4-byte adress when zero */
+ 	  output_asm_insn (AS1 (je,%l8), xops);
+         }
+ 
+       xops[13] = gen_rtx (MEM, QImode, xops[0]);
+ 	/* now, compare the bytes */
+ 	/* compare with the high part of a q-reg gives shorter code */
+       if (QI_REG_P (xops[1]))
+         {
+             /* compare the first n unaligned byte on a byte per byte basis */
+           output_asm_insn (AS2 (cmp%B1,%h1,%13), xops);
+             /* when zero we reached the end */
+           output_asm_insn (AS1 (je,%l12), xops);
+             /* increment the address */
+           output_asm_insn (AS1 (inc%L0,%0), xops);
+ 
+ 	    /* not needed with an alignment of 2 */
+ 	  if (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 2)
+ 	    {
+ 	      ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[7]));
+ 	      output_asm_insn (AS2 (cmp%B1,%h1,%13), xops);
+ 	      output_asm_insn (AS1 (je,%l12), xops);
+ 	      output_asm_insn (AS1 (inc%L0,%0), xops);
+ 
+ 	      ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[6]));
+ 	    }
+           output_asm_insn (AS2 (cmp%B1,%h1,%13), xops);
+         }
+       else
+         {
+           output_asm_insn (AS2 (cmp%B13,%2,%13), xops);
+           output_asm_insn (AS1 (je,%l12), xops);
+           output_asm_insn (AS1 (inc%L0,%0), xops);
+ 
+ 	  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[7]));
+           output_asm_insn (AS2 (cmp%B13,%2,%13), xops);
+           output_asm_insn (AS1 (je,%l12), xops);
+           output_asm_insn (AS1 (inc%L0,%0), xops);
+ 
+ 	  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[6]));
+           output_asm_insn (AS2 (cmp%B13,%2,%13), xops);
+         }
+       output_asm_insn (AS1 (je,%l12), xops);
+       output_asm_insn (AS1 (inc%L0,%0), xops);
+     }
+ 
+     /* Generate loop to check 4 bytes at a time */
+     /* IMHO it is not a good idea to align this loop.  It gives only */
+     /* huge programms, but does not help to speed up */
+   /* ASM_OUTPUT_LOOP_ALIGN (asm_out_file); */
+   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[8]));
+ 
+   xops[13] = gen_rtx (MEM, SImode, xops[0]);
+   output_asm_insn (AS2 (mov%L1,%13,%1), xops);
+ 
+   if (QI_REG_P (xops[1]))
+     {
+ 	/* on i586 it is faster to compare the hi- and lo- part */
+ 	/* as a kind of lookahead.  If xoring both is zero, then one */
+ 	/* of both *could* be zero, otherwith none of both is zero */
+ 	/* this saves one instruction, on i486 this is slower */
+ 	/* testet with P-90, i486DX2-66, AMD486DX2-66 */
+       if(TARGET_586)
+         {
+ 	  output_asm_insn (AS2 (test%B1,%h1,%b1), xops);
+ 	  output_asm_insn (AS1 (jne,%l9), xops);
+         }
+ 
+ 	/* check first byte */
+       output_asm_insn (AS2 (test%B1,%b1,%b1), xops);
+       output_asm_insn (AS1 (je,%l12), xops);
+ 
+ 	/* check second byte */
+       output_asm_insn (AS2 (test%B1,%h1,%h1), xops);
+       output_asm_insn (AS1 (je,%l11), xops);
+ 
+       if(TARGET_586)
+           ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[9]));
+     }
+   else
+     {
+ 	/* check first byte */
+       output_asm_insn (AS2 (test%L1,%14,%1), xops);
+       output_asm_insn (AS1 (je,%l12), xops);
+ 
+ 	/* check second byte */
+       output_asm_insn (AS2 (test%L1,%15,%1), xops);
+       output_asm_insn (AS1 (je,%l11), xops);
+     }
+ 
+     /* check third byte */
+   output_asm_insn (AS2 (test%L1,%16,%1), xops);
+   output_asm_insn (AS1 (je,%l10), xops);
+   
+     /* check fourth byte and increment address */
+   output_asm_insn (AS2 (add%L0,%5,%0), xops);
+   output_asm_insn (AS2 (test%L1,%17,%1), xops);
+   output_asm_insn (AS1 (jne,%l8), xops);
+ 
+     /* now generate fixups when the compare stops within a 4-byte word */
+   output_asm_insn (AS2 (sub%L0,%4,%0), xops);
+ 
+   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[10]));
+   output_asm_insn (AS1 (inc%L0,%0), xops);
+ 
+   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[11]));
+   output_asm_insn (AS1 (inc%L0,%0), xops);
+ 
+   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[12]));
+ 
+     /* maybe you do not want this ?? */
+   fprintf (asm_out_file, "%s end of strlen\n", ASM_COMMENT_START);
+   RET;
+ }
diff -rcp -x TAGS -x c-parse.y -x c-parse.c -x c-parse.h -x c-gperf.h -x cexp.c -x bi-parser.c -x objc-parse.y -x objc-parse.c -x gcc.?? -x gcc.??s -x gcc.aux -x gcc.info* -x cpp.?? -x cpp.??s -x cpp.aux -x cpp.info* -x */cp/parse.c -x */cp/parse.h -x Makefile gcc-2.7.2/config/i386/i386.h gcc-2.7.2-new/config/i386/i386.h
*** gcc-2.7.2/config/i386/i386.h	Fri Sep 22 23:42:57 1995
--- gcc-2.7.2-new/config/i386/i386.h	Sun Dec 17 10:23:34 1995
*************** extern int target_flags;
*** 67,73 ****
  /* Masks for the -m switches */
  #define MASK_80387		000000000001	/* Hardware floating point */
  #define MASK_486		000000000002	/* 80486 specific */
! #define MASK_NOTUSED1		000000000004	/* bit not currently used */
  #define MASK_RTD		000000000010	/* Use ret that pops args */
  #define MASK_ALIGN_DOUBLE	000000000020	/* align doubles to 2 word boundary */
  #define MASK_SVR3_SHLIB		000000000040	/* Uninit locals into bss */
--- 67,73 ----
  /* Masks for the -m switches */
  #define MASK_80387		000000000001	/* Hardware floating point */
  #define MASK_486		000000000002	/* 80486 specific */
! #define MASK_586		000000000006	/* pentium specific (implies 80486) */
  #define MASK_RTD		000000000010	/* Use ret that pops args */
  #define MASK_ALIGN_DOUBLE	000000000020	/* align doubles to 2 word boundary */
  #define MASK_SVR3_SHLIB		000000000040	/* Uninit locals into bss */
*************** extern int target_flags;
*** 129,136 ****
  #define TARGET_MOVE	((target_flags & MASK_NO_MOVE) == 0)	/* Don't generate memory->memory */
  
  /* Specific hardware switches */
  #define TARGET_486	(target_flags & MASK_486)	/* 80486DX, 80486SX, 80486DX[24] */
! #define TARGET_386	(!TARGET_486) 			/* 80386 */
  
  #define TARGET_SWITCHES							\
  { { "80387",			 MASK_80387 },				\
--- 129,137 ----
  #define TARGET_MOVE	((target_flags & MASK_NO_MOVE) == 0)	/* Don't generate memory->memory */
  
  /* Specific hardware switches */
+ #define TARGET_586	((target_flags & MASK_586) == MASK_586)	/* pentium */
  #define TARGET_486	(target_flags & MASK_486)	/* 80486DX, 80486SX, 80486DX[24] */
! #define TARGET_386	(!(target_flags & MASK_586))	/* 80386 */
  
  #define TARGET_SWITCHES							\
  { { "80387",			 MASK_80387 },				\
*************** extern int target_flags;
*** 142,147 ****
--- 143,152 ----
    { "no-386",			 MASK_486 },				\
    { "486",			 MASK_486 },				\
    { "no-486",			-MASK_486 },				\
+   { "586",			 MASK_586 },				\
+   { "no-586",			-MASK_586 },				\
+   { "pentium",			 MASK_586 },				\
+   { "no-pentium",		-MASK_586 },				\
    { "rtd",			 MASK_RTD },				\
    { "no-rtd",			-MASK_RTD },				\
    { "align-double",		 MASK_ALIGN_DOUBLE },			\
*************** extern void init_cumulative_args ();
*** 1868,1873 ****
--- 1873,1879 ----
  extern void function_arg_advance ();
  extern struct rtx_def *function_arg ();
  extern int function_arg_partial_nregs ();
+ extern char *output_strlen_unroll ();
  extern void output_op_from_reg ();
  extern void output_to_reg ();
  extern char *singlemove_string ();
diff -rcp -x TAGS -x c-parse.y -x c-parse.c -x c-parse.h -x c-gperf.h -x cexp.c -x bi-parser.c -x objc-parse.y -x objc-parse.c -x gcc.?? -x gcc.??s -x gcc.aux -x gcc.info* -x cpp.?? -x cpp.??s -x cpp.aux -x cpp.info* -x */cp/parse.c -x */cp/parse.h -x Makefile gcc-2.7.2/config/i386/i386.md gcc-2.7.2-new/config/i386/i386.md
*** gcc-2.7.2/config/i386/i386.md	Mon Aug 21 18:27:58 1995
--- gcc-2.7.2-new/config/i386/i386.md	Sun Dec 17 17:11:51 1995
***************
*** 5736,5742 ****
  (define_expand "strlensi"
    [(parallel [(set (match_dup 4)
  		   (unspec:SI [(mem:BLK (match_operand:BLK 1 "general_operand" ""))
! 			       (match_operand:QI 2 "register_operand" "")
  			       (match_operand:SI 3 "immediate_operand" "")] 0))
  	      (clobber (match_dup 1))])
     (set (match_dup 5)
--- 5736,5742 ----
  (define_expand "strlensi"
    [(parallel [(set (match_dup 4)
  		   (unspec:SI [(mem:BLK (match_operand:BLK 1 "general_operand" ""))
! 			       (match_operand:QI 2 "immediate_operand" "")
  			       (match_operand:SI 3 "immediate_operand" "")] 0))
  	      (clobber (match_dup 1))])
     (set (match_dup 5)
***************
*** 5747,5752 ****
--- 5747,5793 ----
    ""
    "
  {
+   if (!TARGET_386 && operands[2] == const0_rtx && optimize > 1)
+     {
+       rtx address;
+       rtx scratch;
+ 
+ 	/* well it seems that some optimizer does not combine a call like
+ 	     foo(strlen(bar), strlen(bar));
+ 	   when the move and the subtraction is done here.  It does calculate
+ 	   the length just once when these instructions are done inside of
+ 	   output_strlen_unroll().  But I think since &bar[strlen(bar)] is
+ 	   often used and I use one fewer register for the lifetime of
+ 	   output_strlen_unroll() this is better.  */
+       scratch = gen_reg_rtx (SImode);
+       address = force_reg (SImode, XEXP (operands[1], 0));
+ 
+ 	/* move address to scratch-register
+ 	   this is done here because the i586 can do the following and
+ 	   in the same cycle with the following move.  */
+       if (GET_CODE (operands[3]) != CONST_INT || INTVAL (operands[3]) < 4)
+ 	  emit_insn (gen_movsi (scratch, address));
+ 
+       emit_insn (gen_movsi (operands[0], address));
+ 
+       if(TARGET_586)
+ 	emit_insn (gen_strlensi_unroll5 (operands[0],
+ 					operands[3],
+ 					scratch,
+ 					operands[0]));
+       else
+ 	emit_insn (gen_strlensi_unroll4 (operands[0],
+ 					operands[3],
+ 					scratch,
+ 					operands[0]));
+ 
+         /* gen_strlensi_unroll[45] returns the address of the zero
+            at the end of the string, like memchr(), so compute the
+            length by subtracting the startaddress.  */
+       emit_insn (gen_subsi3 (operands[0], operands[0], address));
+       DONE;
+     }
+ 
    operands[1] = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
    operands[4] = gen_reg_rtx (SImode);
    operands[5] = gen_reg_rtx (SImode);
***************
*** 5759,5765 ****
  (define_insn ""
    [(set (match_operand:SI 0 "register_operand" "=&c")
  	(unspec:SI [(mem:BLK (match_operand:SI 1 "address_operand" "D"))
! 		    (match_operand:QI 2 "register_operand" "a")
  		    (match_operand:SI 3 "immediate_operand" "i")] 0))
     (clobber (match_dup 1))]
    ""
--- 5800,5806 ----
  (define_insn ""
    [(set (match_operand:SI 0 "register_operand" "=&c")
  	(unspec:SI [(mem:BLK (match_operand:SI 1 "address_operand" "D"))
! 		    (match_operand:QI 2 "immediate_operand" "a")
  		    (match_operand:SI 3 "immediate_operand" "i")] 0))
     (clobber (match_dup 1))]
    ""
***************
*** 5773,5775 ****
--- 5814,5837 ----
    output_asm_insn (AS2 (mov%L0,%1,%0), xops);
    return \"repnz\;scas%B2\";
  }")
+ 
+ ;; the only difference between the following patterns is the register preference
+ ;; on a pentium using a q-register saves one clock cycle per 4 characters
+ 
+ (define_insn "strlensi_unroll4"
+   [(set (match_operand:SI 0 "register_operand" "=r,r")
+ 		   (unspec:SI [(mem:BLK (match_operand:SI 3 "register_operand" "0,0"))
+ 			       (match_operand:SI 1 "immediate_operand" "i,i")
+ 			       (match_operand:SI 2 "register_operand" "=&q,&!r")] 0))
+    (clobber (match_dup 2))]
+   "(TARGET_486 && !TARGET_586 && optimize > 1)"
+   "* return output_strlen_unroll (operands);")
+ 
+ (define_insn "strlensi_unroll5"
+   [(set (match_operand:SI 0 "register_operand" "=r")
+ 		   (unspec:SI [(mem:BLK (match_operand:SI 3 "register_operand" "0"))
+ 			       (match_operand:SI 1 "immediate_operand" "i")
+ 			       (match_operand:SI 2 "register_operand" "=&q")] 0))
+    (clobber (match_dup 2))]
+   "(TARGET_586 && optimize > 1)"
+   "* return output_strlen_unroll (operands);")
diff -rcp -x TAGS -x c-parse.y -x c-parse.c -x c-parse.h -x c-gperf.h -x cexp.c -x bi-parser.c -x objc-parse.y -x objc-parse.c -x gcc.?? -x gcc.??s -x gcc.aux -x gcc.info* -x cpp.?? -x cpp.??s -x cpp.aux -x cpp.info* -x */cp/parse.c -x */cp/parse.h -x Makefile gcc-2.7.2/invoke.texi gcc-2.7.2-new/invoke.texi
*** gcc-2.7.2/invoke.texi	Tue Oct  3 16:40:43 1995
--- gcc-2.7.2-new/invoke.texi	Sun Dec 17 11:07:56 1995
*************** in addition to the above:
*** 281,288 ****
  -mstats  -EL  -EB  -G @var{num}  -nocpp
  
  @emph{i386 Options}
! -m486  -m386 -mieee-fp  -mno-fancy-math-387
! -mno-fp-ret-in-387  -msoft-float  -msvr3-shlib  
  -mno-wide-multiply -mrtd -malign-double
  -mreg-alloc=@var{list} -mregparm=@var{num}
  -malign-jumps=@var{num} -malign-loops=@var{num}
--- 281,288 ----
  -mstats  -EL  -EB  -G @var{num}  -nocpp
  
  @emph{i386 Options}
! -m586 -mpentium -m486 -m386 -mieee-fp -mno-fancy-math-387
! -mno-fp-ret-in-387 -msoft-float -msvr3-shlib  
  -mno-wide-multiply -mrtd -malign-double
  -mreg-alloc=@var{list} -mregparm=@var{num}
  -malign-jumps=@var{num} -malign-loops=@var{num}
*************** These @samp{-m} options are defined for 
*** 3666,3673 ****
  @table @code
  @item -m486
  @itemx -m386
! Control whether or not code is optimized for a 486 instead of an
! 386.  Code generated for an 486 will run on a 386 and vice versa.
  
  @item -mieee-fp
  @itemx -mno-ieee-fp
--- 3666,3676 ----
  @table @code
  @item -m486
  @itemx -m386
! @itemx -m586
! @itemx -mpentium
! Control whether or not code is optimized for a 486 or a pentium instead of an
! 386.  Code generated for any of these processors will run on any i386 family
! processor.
  
  @item -mieee-fp
  @itemx -mno-ieee-fp
diff -rcp -x TAGS -x c-parse.y -x c-parse.c -x c-parse.h -x c-gperf.h -x cexp.c -x bi-parser.c -x objc-parse.y -x objc-parse.c -x gcc.?? -x gcc.??s -x gcc.aux -x gcc.info* -x cpp.?? -x cpp.??s -x cpp.aux -x cpp.info* -x */cp/parse.c -x */cp/parse.h -x Makefile gcc-2.7.2/md.texi gcc-2.7.2-new/md.texi
*** gcc-2.7.2/md.texi	Sun Nov 26 20:05:33 1995
--- gcc-2.7.2-new/md.texi	Mon Dec 11 09:37:22 1995
*************** define these patterns.
*** 2046,2052 ****
  @cindex @code{s@var{cond}} instruction pattern
  @item @samp{s@var{cond}}
  Store zero or nonzero in the operand according to the condition codes.
! Value stored is nonzero iff the condition @var{cond} is true.
  @var{cond} is the name of a comparison operation expression code, such
  as @code{eq}, @code{lt} or @code{leu}.
  
--- 2046,2052 ----
  @cindex @code{s@var{cond}} instruction pattern
  @item @samp{s@var{cond}}
  Store zero or nonzero in the operand according to the condition codes.
! Value stored is nonzero if the condition @var{cond} is true.
  @var{cond} is the name of a comparison operation expression code, such
  as @code{eq}, @code{lt} or @code{leu}.
  


-
Wolfgang Formann        (wolfi@exner.tgm.ac.at)
Technical Details
Message-ID: <199512180948.KAA24900@asus1.fw.com>
Path: arc1-ca.pugleaf.net!unknown!not-for-mail

Show Full Headers
Complete Article Headers
X-Google-Language: ENGLISH,ASCII-7-bit
X-Google-Thread: 113d02,ef0c82b2c9aaf016,start
X-Google-Attributes: gid113d02,public
From: wolfi@asus1.fw.COM (Wolfgang Formann)
Subject: patch for faster version of strlen
Date: 1995/12/18
Message-ID: <199512180948.KAA24900@asus1.fw.com>
X-Deja-AN: 122223930
distribution: gnu
sender: daemon@cis.ohio-state.edu
organization: GNUs Not Usenet
newsgroups: gnu.gcc.bug