From patchwork Wed May 21 14:13:11 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Biener X-Patchwork-Id: 351202 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 29632140080 for ; Thu, 22 May 2014 00:15:29 +1000 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=JpGAM1qZiKAKk0rTRhPTwyi+wTd+SAw4c/ngBHT3Eez624FxDfZNm NbcHGcHmjxCsSYYfsWd6/1ptOVWyGeAYm9mYRja7Hf+U9cU8Xa5w6qEKpFTQC6Nv L6eHpjxDuCln6FviBzx8I09x0S6bWF5gKqJvp4jyXqkSuaAUjwUWs8= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=29cFaZmBcY0NC9PRYrSoEni4E7o=; b=oPBso9dIbCLn90S6kB89 Gsx9wLAGByTvcJrjUm0QFFGtStzMWHQTXfgaAIRY/UcqNPgoSQq4ESEEssqzc4Ta zxo6wXZ0qkvNbkhKY/K5JZkJf2aIBUnO+O4ldQA3K4d4jg+GseCgXlevS/ORKVZO hdZ/9RyR7oPErPV2AaT3QXo= Received: (qmail 11234 invoked by alias); 21 May 2014 14:15:23 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 11222 invoked by uid 89); 21 May 2014 14:15:22 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-3.6 required=5.0 tests=AWL, BAYES_00, RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: mx2.suse.de Received: from cantor2.suse.de (HELO mx2.suse.de) (195.135.220.15) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (CAMELLIA256-SHA encrypted) ESMTPS; Wed, 21 May 2014 14:15:20 +0000 Received: from relay1.suse.de (charybdis-ext.suse.de [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id C7FD0AD21 for ; Wed, 21 May 2014 14:15:17 +0000 (UTC) Date: Wed, 21 May 2014 16:13:11 +0200 (CEST) From: Richard Biener To: gcc-patches@gcc.gnu.org Subject: [PATCH][match-and-simplify] Fix missed constant folding / operand canonicalization Message-ID: User-Agent: Alpine 2.11 (LSU 23 2013-08-11) MIME-Version: 1.0 I noticed we fail to do $subject for the outermost stmt. I did so when trying to implement the basic constant folding patterns required to make gimple_fold_stmt_to_constant replaceable by gimple_match_and_simplify, thus patterns like (match_and_simplify (plus @0 integer_zerop) @0) Built on x86_64-unknown-linux-gnu, applied to branch. Note this makes a few cases of the match-1.c and match-2.c testcases fail because operands are swapped and we only have one variant of commutative patterns (yeah, points to we need a solution for that). Richard. 2014-05-21 Richard Biener * gimple-match-head.c (constant_for_folding): New function. (gimple_resimplify1, gimple_resimplify2, gimple_resimplify3): Use it. Strip NOPs from call stmt constant folding results and return whether we re-simplified anything. (maybe_push_res_to_seq): Allow is_gimple_val ADDR_EXPRs as simple. (gimple_match_and_simplify): Use constant_for_folding, Strip NOPs from call stmt constant folding results. (gimple_match_and_simplify): Use gimple_resimplify1 for the stmt overload to get constant folding and argument canonicalization. Simplify SSA name copies. (gimple_match_and_simplify): Valueize from a copy or constant assignment for the SSA name overload. Index: gcc/gimple-match-head.c =================================================================== --- gcc/gimple-match-head.c (revision 210637) +++ gcc/gimple-match-head.c (working copy) @@ -35,6 +35,8 @@ along with GCC; see the file COPYING3. #include "tree-ssanames.h" #include "gimple-fold.h" #include "gimple-iterator.h" +#include "expr.h" +#include "tree-dfa.h" #define INTEGER_CST_P(node) (TREE_CODE(node) == INTEGER_CST) #define integral_op_p(node) INTEGRAL_TYPE_P(TREE_TYPE(node)) @@ -57,7 +59,9 @@ private: int rep; }; -/* Forward declarations of the private auto-generated matchers. */ +/* Forward declarations of the private auto-generated matchers. They + expect valueized operands in canonical order and they do not + perform simplification of all-constant operands. */ static bool gimple_match_and_simplify (code_helper, tree, tree, code_helper *, tree *, gimple_seq *, tree (*)(tree)); @@ -69,18 +73,31 @@ static bool gimple_match_and_simplify (c gimple_seq *, tree (*)(tree)); +/* Return whether T is a constant that we'll dispatch to fold to + evaluate fully constant expressions. */ + +static inline bool +constant_for_folding (tree t) +{ + return (CONSTANT_CLASS_P (t) + /* The following is only interesting to string builtins. */ + || (TREE_CODE (t) == ADDR_EXPR + && TREE_CODE (TREE_OPERAND (t, 0)) == STRING_CST)); +} + + /* Helper that matches and simplifies the toplevel result from a gimple_match_and_simplify run (where we don't want to build a stmt in case it's used in in-place folding). Replaces *RES_CODE and *RES_OPS with a simplified and/or canonicalized - result. */ + result and returns whether any change was made. */ -static void +static bool gimple_resimplify1 (gimple_seq *seq, code_helper *res_code, tree type, tree *res_ops, tree (*valueize)(tree)) { - if (CONSTANT_CLASS_P (res_ops[0])) + if (constant_for_folding (res_ops[0])) { tree tem; if (res_code->is_tree_code ()) @@ -89,13 +106,19 @@ gimple_resimplify1 (gimple_seq *seq, { tree decl = builtin_decl_implicit (*res_code); tem = fold_builtin_n (UNKNOWN_LOCATION, decl, res_ops, 1, false); + if (tem) + { + /* fold_builtin_n wraps the result inside a NOP_EXPR. */ + STRIP_NOPS (tem); + tem = fold_convert (type, tem); + } } if (tem != NULL_TREE && CONSTANT_CLASS_P (tem)) { res_ops[0] = tem; *res_code = TREE_CODE (res_ops[0]); - return; + return true; } } @@ -108,21 +131,24 @@ gimple_resimplify1 (gimple_seq *seq, res_ops[0] = res_ops2[0]; res_ops[1] = res_ops2[1]; res_ops[2] = res_ops2[2]; + return true; } + + return false; } /* Helper that matches and simplifies the toplevel result from a gimple_match_and_simplify run (where we don't want to build a stmt in case it's used in in-place folding). Replaces *RES_CODE and *RES_OPS with a simplified and/or canonicalized - result. */ + result and returns whether any change was made. */ -static void +static bool gimple_resimplify2 (gimple_seq *seq, code_helper *res_code, tree type, tree *res_ops, tree (*valueize)(tree)) { - if (CONSTANT_CLASS_P (res_ops[0]) && CONSTANT_CLASS_P (res_ops[1])) + if (constant_for_folding (res_ops[0]) && constant_for_folding (res_ops[1])) { tree tem; if (res_code->is_tree_code ()) @@ -132,23 +158,31 @@ gimple_resimplify2 (gimple_seq *seq, { tree decl = builtin_decl_implicit (*res_code); tem = fold_builtin_n (UNKNOWN_LOCATION, decl, res_ops, 2, false); + if (tem) + { + /* fold_builtin_n wraps the result inside a NOP_EXPR. */ + STRIP_NOPS (tem); + tem = fold_convert (type, tem); + } } if (tem != NULL_TREE) { res_ops[0] = tem; *res_code = TREE_CODE (res_ops[0]); - return; + return true; } } /* Canonicalize operand order. */ + bool canonicalized = false; if (res_code->is_tree_code () && commutative_tree_code (*res_code) && tree_swap_operands_p (res_ops[0], res_ops[1], false)) { tree tem = res_ops[0]; res_ops[0] = res_ops[1]; - res_ops[1]= tem; + res_ops[1] = tem; + canonicalized = true; } code_helper res_code2; @@ -160,22 +194,25 @@ gimple_resimplify2 (gimple_seq *seq, res_ops[0] = res_ops2[0]; res_ops[1] = res_ops2[1]; res_ops[2] = res_ops2[2]; + return true; } + + return canonicalized; } /* Helper that matches and simplifies the toplevel result from a gimple_match_and_simplify run (where we don't want to build a stmt in case it's used in in-place folding). Replaces *RES_CODE and *RES_OPS with a simplified and/or canonicalized - result. */ + result and returns whether any change was made. */ -static void +static bool gimple_resimplify3 (gimple_seq *seq, code_helper *res_code, tree type, tree *res_ops, tree (*valueize)(tree)) { - if (CONSTANT_CLASS_P (res_ops[0]) && CONSTANT_CLASS_P (res_ops[1]) - && CONSTANT_CLASS_P (res_ops[2])) + if (constant_for_folding (res_ops[0]) && constant_for_folding (res_ops[1]) + && constant_for_folding (res_ops[2])) { tree tem; if (res_code->is_tree_code ()) @@ -185,24 +222,32 @@ gimple_resimplify3 (gimple_seq *seq, { tree decl = builtin_decl_implicit (*res_code); tem = fold_builtin_n (UNKNOWN_LOCATION, decl, res_ops, 3, false); + if (tem) + { + /* fold_builtin_n wraps the result inside a NOP_EXPR. */ + STRIP_NOPS (tem); + tem = fold_convert (type, tem); + } } if (tem != NULL_TREE && CONSTANT_CLASS_P (tem)) { res_ops[0] = tem; *res_code = TREE_CODE (res_ops[0]); - return; + return true; } } /* Canonicalize operand order. */ + bool canonicalized = false; if (res_code->is_tree_code () && commutative_ternary_tree_code (*res_code) && tree_swap_operands_p (res_ops[0], res_ops[1], false)) { tree tem = res_ops[0]; res_ops[0] = res_ops[1]; - res_ops[1]= tem; + res_ops[1] = tem; + canonicalized = true; } code_helper res_code2; @@ -215,7 +260,10 @@ gimple_resimplify3 (gimple_seq *seq, res_ops[0] = res_ops2[0]; res_ops[1] = res_ops2[1]; res_ops[2] = res_ops2[2]; + return true; } + + return canonicalized; } @@ -232,7 +280,8 @@ maybe_push_res_to_seq (code_helper rcode if (rcode.is_tree_code ()) { if (!res - && TREE_CODE_LENGTH ((tree_code) rcode) == 0 + && (TREE_CODE_LENGTH ((tree_code) rcode) == 0 + || ((tree_code) rcode) == ADDR_EXPR) && is_gimple_val (ops[0])) return ops[0]; if (!seq) @@ -265,7 +314,7 @@ gimple_match_and_simplify (enum tree_cod tree op0, gimple_seq *seq, tree (*valueize)(tree)) { - if (CONSTANT_CLASS_P (op0)) + if (constant_for_folding (op0)) { tree res = fold_unary_to_constant (code, type, op0); if (res != NULL_TREE) @@ -285,7 +334,7 @@ gimple_match_and_simplify (enum tree_cod tree op0, tree op1, gimple_seq *seq, tree (*valueize)(tree)) { - if (CONSTANT_CLASS_P (op0) && CONSTANT_CLASS_P (op1)) + if (constant_for_folding (op0) && constant_for_folding (op1)) { tree res = fold_binary_to_constant (code, type, op0, op1); /* ??? We can't assert that we fold this to a constant as @@ -317,8 +366,8 @@ gimple_match_and_simplify (enum tree_cod tree op0, tree op1, tree op2, gimple_seq *seq, tree (*valueize)(tree)) { - if (CONSTANT_CLASS_P (op0) && CONSTANT_CLASS_P (op1) - && CONSTANT_CLASS_P (op2)) + if (constant_for_folding (op0) && constant_for_folding (op1) + && constant_for_folding (op2)) { tree res = fold_ternary/*_to_constant */ (code, type, op0, op1, op2); if (res != NULL_TREE @@ -349,13 +398,18 @@ gimple_match_and_simplify (enum built_in tree arg0, gimple_seq *seq, tree (*valueize)(tree)) { - if (CONSTANT_CLASS_P (arg0)) + if (constant_for_folding (arg0)) { tree decl = builtin_decl_implicit (fn); tree res = fold_builtin_n (UNKNOWN_LOCATION, decl, &arg0, 1, false); - if (res != NULL_TREE - && CONSTANT_CLASS_P (res)) - return res; + if (res) + { + /* fold_builtin_n wraps the result inside a NOP_EXPR. */ + STRIP_NOPS (res); + res = fold_convert (type, res); + if (CONSTANT_CLASS_P (res)) + return res; + } } code_helper rcode; @@ -389,9 +443,9 @@ gimple_match_and_simplify (gimple stmt, if (!op0) return false; } - return gimple_match_and_simplify (code, type, op0, - rcode, ops, - seq, valueize); + *rcode = code; + ops[0] = op0; + return gimple_resimplify1 (seq, rcode, type, ops, valueize); } else if (code == BIT_FIELD_REF) { @@ -403,11 +457,22 @@ gimple_match_and_simplify (gimple stmt, if (!op0) return false; } - return gimple_match_and_simplify (code, type, op0, - TREE_OPERAND (rhs1, 1), - TREE_OPERAND (rhs1, 2), - rcode, ops, - seq, valueize); + *rcode = code; + ops[0] = op0; + ops[1] = TREE_OPERAND (rhs1, 1); + ops[2] = TREE_OPERAND (rhs1, 2); + return gimple_resimplify3 (seq, rcode, type, ops, valueize); + } + else if (code == SSA_NAME + && valueize) + { + tree op0 = gimple_assign_rhs1 (stmt); + tree valueized = valueize (op0); + if (!valueized || op0 == valueized) + return false; + ops[0] = valueized; + *rcode = TREE_CODE (op0); + return true; } break; case GIMPLE_UNARY_RHS: @@ -419,9 +484,9 @@ gimple_match_and_simplify (gimple stmt, if (!rhs1) return false; } - return gimple_match_and_simplify (code, type, rhs1, - rcode, ops, - seq, valueize); + *rcode = code; + ops[0] = rhs1; + return gimple_resimplify1 (seq, rcode, type, ops, valueize); } case GIMPLE_BINARY_RHS: { @@ -439,9 +504,10 @@ gimple_match_and_simplify (gimple stmt, if (!rhs2) return false; } - return gimple_match_and_simplify (code, type, rhs1, rhs2, - rcode, ops, - seq, valueize); + *rcode = code; + ops[0] = rhs1; + ops[1] = rhs2; + return gimple_resimplify2 (seq, rcode, type, ops, valueize); } case GIMPLE_TERNARY_RHS: { @@ -466,19 +532,32 @@ gimple_match_and_simplify (gimple stmt, if (!rhs3) return false; } - return gimple_match_and_simplify (code, type, rhs1, rhs2, rhs3, - rcode, ops, - seq, valueize); + *rcode = code; + ops[0] = rhs1; + ops[1] = rhs2; + ops[2] = rhs3; + return gimple_resimplify3 (seq, rcode, type, ops, valueize); } default: gcc_unreachable (); } } else if (is_gimple_call (stmt) - && gimple_call_builtin_p (stmt, BUILT_IN_NORMAL) && gimple_call_lhs (stmt) != NULL_TREE) { - tree decl = gimple_call_fndecl (stmt); + tree fn = gimple_call_fn (stmt); + if (TREE_CODE (fn) == SSA_NAME + && valueize) + fn = valueize (fn); + if (!fn + || TREE_CODE (fn) != ADDR_EXPR + || TREE_CODE (TREE_OPERAND (fn, 0)) != FUNCTION_DECL + || DECL_BUILT_IN_CLASS (TREE_OPERAND (fn, 0)) != BUILT_IN_NORMAL + || !gimple_builtin_call_types_compatible_p (stmt, + TREE_OPERAND (fn, 0))) + return false; + + tree decl = TREE_OPERAND (fn, 0); tree type = TREE_TYPE (gimple_call_lhs (stmt)); switch (gimple_call_num_args (stmt)) { @@ -491,10 +570,9 @@ gimple_match_and_simplify (gimple stmt, if (!arg1) return false; } - return gimple_match_and_simplify (DECL_FUNCTION_CODE (decl), - type, arg1, - rcode, ops, - seq, valueize); + *rcode = DECL_FUNCTION_CODE (decl); + ops[0] = arg1; + return gimple_resimplify1 (seq, rcode, type, ops, valueize); } case 2: { @@ -512,10 +590,10 @@ gimple_match_and_simplify (gimple stmt, if (!arg2) return false; } - return gimple_match_and_simplify (DECL_FUNCTION_CODE (decl), - type, arg1, arg2, - rcode, ops, - seq, valueize); + *rcode = DECL_FUNCTION_CODE (decl); + ops[0] = arg1; + ops[1] = arg2; + return gimple_resimplify2 (seq, rcode, type, ops, valueize); } default: return false; @@ -539,7 +617,23 @@ gimple_match_and_simplify (tree name, gi if (TREE_CODE (name) != SSA_NAME) return NULL_TREE; + /* This function is supposed to return a valueization of name, thus + also allow simply returning an unsimplified RHS of its definition + statement. */ gimple stmt = SSA_NAME_DEF_STMT (name); + if (gimple_assign_single_p (stmt)) + { + tree rhs = gimple_assign_rhs1 (stmt); + if (TREE_CODE (rhs) == SSA_NAME) + { + if (valueize) + rhs = valueize (rhs); + return rhs; + } + else if (is_gimple_min_invariant (rhs)) + return rhs; + } + code_helper rcode; tree ops[3] = {}; if (!gimple_match_and_simplify (stmt, &rcode, ops, seq, valueize))