From patchwork Sat Sep 4 21:13:13 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Hubicka X-Patchwork-Id: 63807 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]) by ozlabs.org (Postfix) with SMTP id 4B47FB7140 for ; Sun, 5 Sep 2010 07:13:24 +1000 (EST) Received: (qmail 31187 invoked by alias); 4 Sep 2010 21:13:22 -0000 Received: (qmail 31178 invoked by uid 22791); 4 Sep 2010 21:13:21 -0000 X-SWARE-Spam-Status: No, hits=-1.7 required=5.0 tests=AWL, BAYES_00, TW_CF, TW_CV, TW_TM, T_FRT_BELOW2, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from nikam-dmz.ms.mff.cuni.cz (HELO nikam.ms.mff.cuni.cz) (195.113.20.16) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sat, 04 Sep 2010 21:13:15 +0000 Received: by nikam.ms.mff.cuni.cz (Postfix, from userid 16202) id 71F3A9ACB11; Sat, 4 Sep 2010 23:13:13 +0200 (CEST) Date: Sat, 4 Sep 2010 23:13:13 +0200 From: Jan Hubicka To: gcc-patches@gcc.gnu.org, rguenther@suse.de Subject: Teach sccvn about constant vars Message-ID: <20100904211313.GE31380@kam.mff.cuni.cz> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.18 (2008-05-17) 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 Hi, this patch adds folding of constant vars accesses into fully_constant_vn_reference_p. I tested that both main code paths (vars alone and array refs) are tripped during bootstrap, the testcase bellow shows fragment where we otherwise fail to fold until cfgexpand time. It is my first attempt to add something into tree-ssa-sccvn, so I am not quite sure I got everything right. We should probably also fold component ref though producing a testcase might be tricky (because in array ref one can arrange the offset to be known only at VN time, but I am not sure I can think of component ref testcase) Bootstrapped/regtested x86_64-linux, seems sane? Honza /* { dg-do compile } */ /* { dg-options "-O2 -fdump-tree-optimized" } */ enum { ERROR_OK, ERROR_UNKNOWN, ERROR_NUM }; enum { __LC_CTYPE = 0, __LC_NUMERIC = 1, __LC_TIME = 2, __LC_COLLATE = 3, __LC_MONETARY = 4, __LC_MESSAGES = 5, __LC_ALL = 6, __LC_PAPER = 10, __LC_MEASUREMENT = 11, __LC_IDENTIFICATION = 12 }; static const char *const _messages[] = { "no error", "unknown error", "Internal error: unknown reason", }; elf_errmsg (int err) { if (err < 0 || err >= ERROR_NUM || _messages[err] == ((void *) 0)) { err = ERROR_UNKNOWN; } return _messages[err]; } /* We should fold _messages[1]. */ /* { dg-final { scan-tree-dump "unknown error" "optimized"} } */ /* { dg-final { cleanup-tree-dump "optimized" } } */ * gimple.h (fold_const_array_ref): Declare. * tree-ssa-sccvn.c (fully_constant_vn_reference_p): Fold initialized readonly static vars and array references into them. * tree-ssa-ccp.c (fold_const_array_ref): Break out from ... (fold_const_aggregate_ref): ... here. Index: gimple.h =================================================================== --- gimple.h (revision 163862) +++ gimple.h (working copy) @@ -4870,6 +4870,7 @@ extern void dump_gimple_statistics (void /* In gimple-fold.c. */ void gimplify_and_update_call_from_tree (gimple_stmt_iterator *, tree); tree gimple_fold_builtin (gimple); +tree fold_const_array_ref (tree, tree, tree); bool fold_stmt (gimple_stmt_iterator *); bool fold_stmt_inplace (gimple); tree maybe_fold_offset_to_address (location_t, tree, tree, tree); Index: tree-ssa-sccvn.c =================================================================== --- tree-ssa-sccvn.c (revision 163862) +++ tree-ssa-sccvn.c (working copy) @@ -1109,24 +1109,56 @@ fully_constant_vn_reference_p (vn_refere return folded; } } - - /* Simplify reads from constant strings. */ + else if (op->opcode == VAR_DECL + || op->opcode == CONST_DECL) + return get_symbol_constant_value (op->op0); else if (op->opcode == ARRAY_REF - && TREE_CODE (op->op0) == INTEGER_CST - && integer_zerop (op->op1) && VEC_length (vn_reference_op_s, operands) == 2) { vn_reference_op_t arg0; + tree ctor = NULL_TREE; + tree op0; + arg0 = VEC_index (vn_reference_op_s, operands, 1); - if (arg0->opcode == STRING_CST - && (TYPE_MODE (op->type) - == TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0->op0)))) - && GET_MODE_CLASS (TYPE_MODE (op->type)) == MODE_INT - && GET_MODE_SIZE (TYPE_MODE (op->type)) == 1 - && compare_tree_int (op->op0, TREE_STRING_LENGTH (arg0->op0)) < 0) - return build_int_cst_type (op->type, - (TREE_STRING_POINTER (arg0->op0) - [TREE_INT_CST_LOW (op->op0)])); + op0 = arg0->op0; + + switch (arg0->opcode) + { + case MEM_REF: + /* ??? We could handle this case. */ + if (!integer_zerop (TREE_OPERAND (op0, 1))) + return NULL_TREE; + op0 = get_base_address (op0); + if (!op0 + || TREE_CODE (op0) != VAR_DECL) + return NULL_TREE; + + /* Fallthru. */ + case VAR_DECL: + if (!TREE_READONLY (op0) + || TREE_CODE (TREE_TYPE (op0)) != ARRAY_TYPE + || ((TREE_STATIC (op0) || DECL_EXTERNAL (op0)) + && !varpool_get_node (op0)->const_value_known)) + return NULL_TREE; + + ctor = DECL_INITIAL (op0); + break; + + case ARRAY_REF: + case COMPONENT_REF: + gcc_unreachable (); + break; + + case STRING_CST: + case CONSTRUCTOR: + ctor = op0; + break; + + default: + break; + } + if (ctor) + return fold_const_array_ref (op->type, ctor, op->op0); } return NULL_TREE; Index: tree-ssa-ccp.c =================================================================== --- tree-ssa-ccp.c (revision 163862) +++ tree-ssa-ccp.c (working copy) @@ -1310,6 +1310,62 @@ ccp_fold (gimple stmt) } } +/* Fold array reference of TYPE into a variable with known value CTOR + with known index IDX. */ +tree +fold_const_array_ref (tree type, tree ctor, tree idx) +{ + unsigned HOST_WIDE_INT cnt; + tree cfield, cval; + tree tem; + + if (ctor == NULL_TREE + || (TREE_CODE (ctor) != CONSTRUCTOR + && TREE_CODE (ctor) != STRING_CST) + || !TREE_STATIC (ctor)) + return NULL_TREE; + + /* Get the index. If we have an SSA_NAME, try to resolve it + with the current lattice value for the SSA_NAME. */ + switch (TREE_CODE (idx)) + { + case SSA_NAME: + if ((tem = get_constant_value (idx)) + && TREE_CODE (tem) == INTEGER_CST) + idx = tem; + else + return NULL_TREE; + break; + + case INTEGER_CST: + break; + + default: + return NULL_TREE; + } + + /* Fold read from constant string. */ + if (TREE_CODE (ctor) == STRING_CST) + { + if ((TYPE_MODE (type) + == TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor)))) + && (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor)))) + == MODE_INT) + && GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor)))) == 1 + && compare_tree_int (idx, TREE_STRING_LENGTH (ctor)) < 0) + return build_int_cst_type (type, + (TREE_STRING_POINTER (ctor) + [TREE_INT_CST_LOW (idx)])); + return NULL_TREE; + } + + /* Whoo-hoo! I'll fold ya baby. Yeah! */ + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), cnt, cfield, cval) + if (tree_int_cst_equal (cfield, idx)) + return canonicalize_constructor_val (cval); + return NULL_TREE; +} + /* Return the tree representing the element referenced by T if T is an ARRAY_REF or COMPONENT_REF into constant aggregates. Return NULL_TREE otherwise. */ @@ -1332,11 +1388,11 @@ fold_const_aggregate_ref (tree t) switch (TREE_CODE (t)) { case ARRAY_REF: + base = TREE_OPERAND (t, 0); /* Get a CONSTRUCTOR. If BASE is a VAR_DECL, get its DECL_INITIAL. If BASE is a nested reference into another ARRAY_REF or COMPONENT_REF, make a recursive call to resolve the inner reference. */ - base = TREE_OPERAND (t, 0); switch (TREE_CODE (base)) { case MEM_REF: @@ -1373,51 +1429,9 @@ fold_const_aggregate_ref (tree t) return NULL_TREE; } - if (ctor == NULL_TREE - || (TREE_CODE (ctor) != CONSTRUCTOR - && TREE_CODE (ctor) != STRING_CST) - || !TREE_STATIC (ctor)) - return NULL_TREE; - - /* Get the index. If we have an SSA_NAME, try to resolve it - with the current lattice value for the SSA_NAME. */ - idx = TREE_OPERAND (t, 1); - switch (TREE_CODE (idx)) - { - case SSA_NAME: - if ((tem = get_constant_value (idx)) - && TREE_CODE (tem) == INTEGER_CST) - idx = tem; - else - return NULL_TREE; - break; - - case INTEGER_CST: - break; - - default: - return NULL_TREE; - } - - /* Fold read from constant string. */ - if (TREE_CODE (ctor) == STRING_CST) - { - if ((TYPE_MODE (TREE_TYPE (t)) - == TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor)))) - && (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor)))) - == MODE_INT) - && GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor)))) == 1 - && compare_tree_int (idx, TREE_STRING_LENGTH (ctor)) < 0) - return build_int_cst_type (TREE_TYPE (t), - (TREE_STRING_POINTER (ctor) - [TREE_INT_CST_LOW (idx)])); - return NULL_TREE; - } - - /* Whoo-hoo! I'll fold ya baby. Yeah! */ - FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), cnt, cfield, cval) - if (tree_int_cst_equal (cfield, idx)) - return canonicalize_constructor_val (cval); + return fold_const_array_ref (TREE_TYPE (t), + ctor, + TREE_OPERAND (t, 1)); break; case COMPONENT_REF: