i386.md (cmpstrnsi): New test to bail out if neither string input is a string constant.
authorAaron Sawdey <acsawdey@linux.vnet.ibm.com>
Thu, 17 Nov 2016 18:58:16 +0000 (18:58 +0000)
committerAaron Sawdey <acsawdey@gcc.gnu.org>
Thu, 17 Nov 2016 18:58:16 +0000 (12:58 -0600)
2016-11-17  Aaron Sawdey  <acsawdey@linux.vnet.ibm.com>

* config/i386/i386.md (cmpstrnsi): New test to bail out if neither
string input is a string constant.
* builtins.c (expand_builtin_strncmp): Attempt expansion of strncmp
via cmpstrnsi even if neither string is constant.

From-SVN: r242556

gcc/ChangeLog
gcc/builtins.c
gcc/config/i386/i386.md

index 0967e8dcb828e11f04c7da420dfb8eaeb4eb95ce..86c664bf7a99931a741de4373511c459a4534c01 100644 (file)
@@ -1,3 +1,10 @@
+2016-11-17  Aaron Sawdey  <acsawdey@linux.vnet.ibm.com>
+
+       * config/i386/i386.md (cmpstrnsi): New test to bail out if neither
+       string input is a string constant.
+       * builtins.c (expand_builtin_strncmp): Attempt expansion of strncmp
+       via cmpstrnsi even if neither string is constant.
+
 2016-11-17  Jakub Jelinek  <jakub@redhat.com>
 
        PR middle-end/78201
index 3ac2d44148440b124559ba7cd3de483b7a74b72d..1316c27e9a6c6eead2768275bae77fb7018de56a 100644 (file)
@@ -3918,7 +3918,7 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
   insn_code cmpstrn_icode = direct_optab_handler (cmpstrn_optab, SImode);
   if (cmpstrn_icode != CODE_FOR_nothing)
   {
-    tree len, len1, len2;
+    tree len, len1, len2, len3;
     rtx arg1_rtx, arg2_rtx, arg3_rtx;
     rtx result;
     tree fndecl, fn;
@@ -3937,14 +3937,19 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
     if (len2)
       len2 = size_binop_loc (loc, PLUS_EXPR, ssize_int (1), len2);
 
+    len3 = fold_convert_loc (loc, sizetype, arg3);
+
     /* If we don't have a constant length for the first, use the length
-       of the second, if we know it.  We don't require a constant for
+       of the second, if we know it.  If neither string is constant length,
+       use the given length argument.  We don't require a constant for
        this case; some cost analysis could be done if both are available
        but neither is constant.  For now, assume they're equally cheap,
        unless one has side effects.  If both strings have constant lengths,
        use the smaller.  */
 
-    if (!len1)
+    if (!len1 && !len2)
+      len = len3;
+    else if (!len1)
       len = len2;
     else if (!len2)
       len = len1;
@@ -3961,23 +3966,10 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
     else
       len = len2;
 
-    /* If both arguments have side effects, we cannot optimize.  */
-    if (!len || TREE_SIDE_EFFECTS (len))
-      return NULL_RTX;
-
-    /* The actual new length parameter is MIN(len,arg3).  */
-    len = fold_build2_loc (loc, MIN_EXPR, TREE_TYPE (len), len,
-                      fold_convert_loc (loc, TREE_TYPE (len), arg3));
-
-    /* If we don't have POINTER_TYPE, call the function.  */
-    if (arg1_align == 0 || arg2_align == 0)
-      return NULL_RTX;
-
-    /* Stabilize the arguments in case gen_cmpstrnsi fails.  */
-    arg1 = builtin_save_expr (arg1);
-    arg2 = builtin_save_expr (arg2);
-    len = builtin_save_expr (len);
-
+    /* If we are not using the given length, we must incorporate it here.
+       The actual new length parameter will be MIN(len,arg3) in this case.  */
+    if (len != len3)
+      len = fold_build2_loc (loc, MIN_EXPR, TREE_TYPE (len), len, len3);
     arg1_rtx = get_memory_rtx (arg1, len);
     arg2_rtx = get_memory_rtx (arg2, len);
     arg3_rtx = expand_normal (len);
index 7db04ce82ae5655635cd61f3a615d272789e77fe..0645805770b04dcf706356ef23ab6e43d1633f9e 100644 (file)
   if (fixed_regs[CX_REG] || fixed_regs[SI_REG] || fixed_regs[DI_REG])
     FAIL;
 
+  /* One of the strings must be a constant.  If so, expand_builtin_strncmp()
+     will have rewritten the length arg to be the minimum of the const string
+     length and the actual length arg.  If both strings are the same and
+     shorter than the length arg, repz cmpsb will not stop at the 0 byte and
+     will incorrectly base the results on chars past the 0 byte.  */
+  tree t1 = MEM_EXPR (operands[1]);
+  tree t2 = MEM_EXPR (operands[2]);
+  if (!((t1 && TREE_CODE (t1) == MEM_REF
+         && TREE_CODE (TREE_OPERAND (t1, 0)) == ADDR_EXPR
+         && TREE_CODE (TREE_OPERAND (TREE_OPERAND (t1, 0), 0)) == STRING_CST)
+      || (t2 && TREE_CODE (t2) == MEM_REF
+          && TREE_CODE (TREE_OPERAND (t2, 0)) == ADDR_EXPR
+          && TREE_CODE (TREE_OPERAND (TREE_OPERAND (t2, 0), 0)) == STRING_CST)))
+    FAIL;
+
   out = operands[0];
   if (!REG_P (out))
     out = gen_reg_rtx (SImode);