From d9df71be907c93848f4ab31b280080da59cf5b5a Mon Sep 17 00:00:00 2001 From: Aaron Sawdey Date: Thu, 17 Nov 2016 18:58:16 +0000 Subject: [PATCH] i386.md (cmpstrnsi): New test to bail out if neither string input is a string constant. 2016-11-17 Aaron Sawdey * 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 | 7 +++++++ gcc/builtins.c | 32 ++++++++++++-------------------- gcc/config/i386/i386.md | 15 +++++++++++++++ 3 files changed, 34 insertions(+), 20 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0967e8dcb82..86c664bf7a9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2016-11-17 Aaron Sawdey + + * 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 PR middle-end/78201 diff --git a/gcc/builtins.c b/gcc/builtins.c index 3ac2d441484..1316c27e9a6 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -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); diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 7db04ce82ae..0645805770b 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -16911,6 +16911,21 @@ 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); -- 2.30.2