This is the mail archive of the gcc-patches@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]

[PATCH] Optimize strlen comparisons against zero



Whilst fixing some style issues in some local code, it occurred to
me that the problem could also be fixed by the compiler.

The following patch optimizes comparisons of the return value from
strlen against zero.  This optimization transforms the expression
"strlen(ptr) > 0" into the equivalent "*((const char*)ptr) != 0",
where the call is actually to the GCC builtin.  Checking whether
the first character of the string is NUL is more efficient than
calculating the entire string length, only to ignore the actual result.

I believe that this is always safe, as IIRC the behaviour of operations
on objects larger than size_t are implementation defined, hence the
return value of strlen should not be expected to overflow for suitably
large strings.  Someone more familiar with multi-byte character standards
should also confirm that there are no potential problems there.

For those not familiar with this part of fold-const.c, by this point
all comparisons of unsigned types against zero (including the size_t
returned by strlen) have been reduced to either inequality or
equality tests.  Hence, "strlen(ptr) > 0" and "strlen(ptr) >= 1" have
been transformed to "strlen(ptr) != 0", and "strlen(ptr) < 1" into
"strlen(ptr) == 0".  The simplifies the code, since arg0 of the
comparison just needs to be replace strlen(ptr) with *ptr.

Tested by "make bootstrap" and "make check-gcc" on i686-pc-linux-gnu
with no new regressions.  A test case is also included to check that
the transformation is being applied and that it doesn't change program
behaviour.

Finally, I'm also willing, if necessary, to submit a follow up patch to
remove the few example uses of this strlen-comparison-against-zero idiom
from the GCC source tree.



*** fold-const.c	2001/10/21 21:31:59	1.172
--- fold-const.c	2001/11/03 18:49:54
*************** fold (expr)
*** 6858,6863 ****
--- 6858,6892 ----
  			      fold (build (code, type, imag0, imag1))));
  	}

+         /* Optimize "strlen(ptr) == 0" to "*((const char*)ptr) == 0"
+            and "strlen(ptr) != 0" to "*((const char*)ptr) != 0".  */
+         if (integer_zerop (arg1)
+             && TREE_CODE (arg0) == CALL_EXPR
+             && TREE_CODE (TREE_OPERAND (arg0, 0)) == ADDR_EXPR)
+           {
+             tree fndecl = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
+             tree arglist;
+
+             if (TREE_CODE (fndecl) == FUNCTION_DECL
+                 && DECL_BUILT_IN (fndecl)
+                 && DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_MD
+                 && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_STRLEN
+                 && (arglist = TREE_OPERAND (arg0, 1))
+                 && TREE_CODE (TREE_TYPE (TREE_VALUE (arglist)))
+                    == POINTER_TYPE
+                 && ! TREE_CHAIN (arglist))
+             {
+               tree cst_char_node = build_type_variant (char_type_node, 1, 0);
+               tree cst_char_ptr_node = build_pointer_type (cst_char_node);
+               return fold (build (code, type,
+                                   build1 (INDIRECT_REF, cst_char_node,
+                                           build1 (NOP_EXPR,
+                                                   cst_char_ptr_node,
+                                                   TREE_VALUE(arglist))),
+                                   integer_zero_node));
+             }
+           }
+
        /* From here on, the only cases we handle are when the result is
  	 known to be a constant.

*** /dev/null
--- gcc.c-torture/execute/string-opt-13.c	Sat Nov  3 11:53:33 2001
***************
*** 0 ****
--- 1,58 ----
+ /* Copyright (C) 2001  Free Software Foundation.
+
+    Ensure all builtin strlen comparisons against zero are optimized
+    and perform correctly. The calls to strcpy are to prevent the strlen
+    calls from being removed by CSE.
+
+    Written by Roger Sayle, 11/02/2001.  */
+
+ extern void abort (void);
+ typedef __SIZE_TYPE__ size_t;
+ extern size_t strlen (const char *);
+ extern char *strcpy (char *, const char *);
+
+ int
+ main ()
+ {
+   char str[8];
+   char *ptr;
+
+   ptr = str;
+   strcpy (ptr, "nts");
+   if (strlen (ptr) == 0)
+     abort ();
+
+   strcpy (ptr, "nts");
+   if (strlen (ptr) < 1)
+     abort ();
+
+   strcpy (ptr, "nts");
+   if (strlen (ptr) <= 0)
+     abort ();
+
+   strcpy (ptr, "nts");
+   if (strlen (ptr+3) != 0)
+     abort ();
+
+   strcpy (ptr, "nts");
+   if (strlen (ptr+3) > 0)
+     abort ();
+
+   strcpy (ptr, "nts");
+   if (strlen (str+3) >= 1)
+     abort ();
+
+   return 0;
+ }
+
+ #ifdef __OPTIMIZE__
+ /* When optimizing, all the above cases should be transformed into
+    something else.  So any remaining calls to the original function
+    should abort.  */
+ static size_t
+ strlen (const char *s)
+ {
+   abort ();
+ }
+ #endif
+


--
Roger Sayle,                         E-mail: roger@eyesopen.com
OpenEye Scientific Software,         WWW: http://www.eyesopen.com/
Suite 1107, 3600 Cerrillos Road,     Tel: (+1) 505-473-7385
Santa Fe, New Mexico, 87507.         Fax: (+1) 505-438-3470



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