From patchwork Sun May 6 10:49:12 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Botcazou X-Patchwork-Id: 157061 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 72A24B6FA4 for ; Sun, 6 May 2012 20:52:05 +1000 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1336906326; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: Received:From:To:Subject:Date:User-Agent:MIME-Version: Content-Type:Message-Id:Mailing-List:Precedence:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:Sender: Delivered-To; bh=G8Ejz57VQtub+qw/cvwENZSSRZk=; b=KDdWf5k328NqA60 9Rqhbc9mkO83ajvXH///g+xDXYp+MxEf/enj47NMx8wA53QlK1hjiIevhphCXdB1 V4oNxIaPJQJ1hBEZtzb+cvJzL9ibyxQeNjVTT40s/EEf4tnr6NhGCELb9KpJgV0m CJrESYR1nvmekc44+4SxrPwN864s= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:Received:Received:From:To:Subject:Date:User-Agent:MIME-Version:Content-Type:Message-Id:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=wvcE2qjIEAWL3Sl0GYPny3AYA1+qY+HPuis+rSes3QjkCqhY+G/TeqKtXjX8bG ix1lu1JsveX5XwTlRWfbttk9pUUTMLN4lu3bNMNUoxqWKDidlKMhmRYrmgAziOh/ /n+NjzEKMag3fW8DLKvcU5OpOYp1i4ev2abjAh4yyzec8=; Received: (qmail 32621 invoked by alias); 6 May 2012 10:52:02 -0000 Received: (qmail 32607 invoked by uid 22791); 6 May 2012 10:52:00 -0000 X-SWARE-Spam-Status: No, hits=-1.9 required=5.0 tests=AWL, BAYES_00, TW_NR, TW_TM X-Spam-Check-By: sourceware.org Received: from mel.act-europe.fr (HELO mel.act-europe.fr) (194.98.77.210) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sun, 06 May 2012 10:51:47 +0000 Received: from localhost (localhost [127.0.0.1]) by filtered-smtp.eu.adacore.com (Postfix) with ESMTP id C27F7290022 for ; Sun, 6 May 2012 12:51:51 +0200 (CEST) Received: from mel.act-europe.fr ([127.0.0.1]) by localhost (smtp.eu.adacore.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id NsoIVtMF+lUQ for ; Sun, 6 May 2012 12:51:51 +0200 (CEST) Received: from [192.168.1.2] (bon31-6-88-161-99-133.fbx.proxad.net [88.161.99.133]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mel.act-europe.fr (Postfix) with ESMTP id 66ED829000A for ; Sun, 6 May 2012 12:51:51 +0200 (CEST) From: Eric Botcazou To: gcc-patches@gcc.gnu.org Subject: [Ada] Missed vectorization opportunity for assignment loop Date: Sun, 6 May 2012 12:49:12 +0200 User-Agent: KMail/1.9.9 MIME-Version: 1.0 Message-Id: <201205061249.12278.ebotcazou@adacore.com> 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 In Ada, we have issues with vectorization when full checks are enabled, most notably -gnato. This patch makes it possible to vectorize more loops at -O3. Tested on i586-suse-linux, applied on the mainline. 2012-05-06 Eric Botcazou * gcc-interface/trans.c (Loop_Statement_to_gnu): Also handle invariant conditions with only one bound. (Raise_Error_to_gnu): Likewise. New function extracted from... (gnat_to_gnu) : ...here. Call above function in regular mode only. Index: gcc-interface/trans.c =================================================================== --- gcc-interface/trans.c (revision 187206) +++ gcc-interface/trans.c (working copy) @@ -2563,13 +2563,19 @@ Loop_Statement_to_gnu (Node_Id gnat_node i++) { tree low_ok - = build_binary_op (GE_EXPR, boolean_type_node, - convert (rci->type, gnu_low), - rci->low_bound); + = rci->low_bound + ? build_binary_op (GE_EXPR, boolean_type_node, + convert (rci->type, gnu_low), + rci->low_bound) + : boolean_true_node; + tree high_ok - = build_binary_op (LE_EXPR, boolean_type_node, - convert (rci->type, gnu_high), - rci->high_bound); + = rci->high_bound + ? build_binary_op (LE_EXPR, boolean_type_node, + convert (rci->type, gnu_high), + rci->high_bound) + : boolean_true_node; + tree range_ok = build_binary_op (TRUTH_ANDIF_EXPR, boolean_type_node, low_ok, high_ok); @@ -2794,7 +2800,7 @@ finalize_nrv_r (tree *tp, int *walk_subt tree ret_val = TREE_OPERAND (TREE_OPERAND (t, 0), 1), init_expr; /* If this is the temporary created for a return value with variable - size in call_to_gnu, we replace the RHS with the init expression. */ + size in Call_to_gnu, we replace the RHS with the init expression. */ if (TREE_CODE (ret_val) == COMPOUND_EXPR && TREE_CODE (TREE_OPERAND (ret_val, 0)) == INIT_EXPR && TREE_OPERAND (TREE_OPERAND (ret_val, 0), 0) @@ -3122,7 +3128,7 @@ build_return_expr (tree ret_obj, tree re && aggregate_value_p (operation_type, current_function_decl)) { /* Recognize the temporary created for a return value with variable - size in call_to_gnu. We want to eliminate it if possible. */ + size in Call_to_gnu. We want to eliminate it if possible. */ if (TREE_CODE (ret_val) == COMPOUND_EXPR && TREE_CODE (TREE_OPERAND (ret_val, 0)) == INIT_EXPR && TREE_OPERAND (TREE_OPERAND (ret_val, 0), 0) @@ -3583,7 +3589,7 @@ create_init_temporary (const char *prefi requires atomic synchronization. */ static tree -call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target, +Call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target, bool atomic_sync) { const bool function_call = (Nkind (gnat_node) == N_Function_Call); @@ -4751,6 +4757,134 @@ Compilation_Unit_to_gnu (Node_Id gnat_no invalidate_global_renaming_pointers (); } +/* Subroutine of gnat_to_gnu to translate gnat_node, an N_Raise_xxx_Error, + to a GCC tree, which is returned. GNU_RESULT_TYPE_P is a pointer to where + we should place the result type. LABEL_P is true if there is a label to + branch to for the exception. */ + +static tree +Raise_Error_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p) +{ + const Node_Kind kind = Nkind (gnat_node); + const int reason = UI_To_Int (Reason (gnat_node)); + const Node_Id gnat_cond = Condition (gnat_node); + const bool with_extra_info + = Exception_Extra_Info + && !No_Exception_Handlers_Set () + && !get_exception_label (kind); + tree gnu_result = NULL_TREE, gnu_cond = NULL_TREE; + + *gnu_result_type_p = get_unpadded_type (Etype (gnat_node)); + + switch (reason) + { + case CE_Access_Check_Failed: + if (with_extra_info) + gnu_result = build_call_raise_column (reason, gnat_node); + break; + + case CE_Index_Check_Failed: + case CE_Range_Check_Failed: + case CE_Invalid_Data: + if (Present (gnat_cond) && Nkind (gnat_cond) == N_Op_Not) + { + Node_Id gnat_range, gnat_index, gnat_type; + tree gnu_index, gnu_low_bound, gnu_high_bound; + struct range_check_info_d *rci; + + switch (Nkind (Right_Opnd (gnat_cond))) + { + case N_In: + gnat_range = Right_Opnd (Right_Opnd (gnat_cond)); + gcc_assert (Nkind (gnat_range) == N_Range); + gnu_low_bound = gnat_to_gnu (Low_Bound (gnat_range)); + gnu_high_bound = gnat_to_gnu (High_Bound (gnat_range)); + break; + + case N_Op_Ge: + gnu_low_bound = gnat_to_gnu (Right_Opnd (Right_Opnd (gnat_cond))); + gnu_high_bound = NULL_TREE; + break; + + case N_Op_Le: + gnu_low_bound = NULL_TREE; + gnu_high_bound = gnat_to_gnu (Right_Opnd (Right_Opnd (gnat_cond))); + break; + + default: + goto common; + } + + gnat_index = Left_Opnd (Right_Opnd (gnat_cond)); + gnat_type = Etype (gnat_index); + gnu_index = gnat_to_gnu (gnat_index); + + if (with_extra_info + && gnu_low_bound + && gnu_high_bound + && Known_Esize (gnat_type) + && UI_To_Int (Esize (gnat_type)) <= 32) + gnu_result + = build_call_raise_range (reason, gnat_node, gnu_index, + gnu_low_bound, gnu_high_bound); + + /* If loop unswitching is enabled, we try to compute invariant + conditions for checks applied to iteration variables, i.e. + conditions that are both independent of the variable and + necessary in order for the check to fail in the course of + some iteration, and prepend them to the original condition + of the checks. This will make it possible later for the + loop unswitching pass to replace the loop with two loops, + one of which has the checks eliminated and the other has + the original checks reinstated, and a run time selection. + The former loop will be suitable for vectorization. */ + if (flag_unswitch_loops + && (!gnu_low_bound + || (gnu_low_bound = gnat_invariant_expr (gnu_low_bound))) + && (!gnu_high_bound + || (gnu_high_bound = gnat_invariant_expr (gnu_high_bound))) + && (rci = push_range_check_info (gnu_index))) + { + rci->low_bound = gnu_low_bound; + rci->high_bound = gnu_high_bound; + rci->type = gnat_to_gnu_type (gnat_type); + rci->invariant_cond = build1 (SAVE_EXPR, boolean_type_node, + boolean_true_node); + gnu_cond = build_binary_op (TRUTH_ANDIF_EXPR, + boolean_type_node, + rci->invariant_cond, + gnat_to_gnu (gnat_cond)); + } + } + break; + + default: + break; + } + +common: + if (!gnu_result) + gnu_result = build_call_raise (reason, gnat_node, kind); + set_expr_location_from_node (gnu_result, gnat_node); + + /* If the type is VOID, this is a statement, so we need to generate the code + for the call. Handle a condition, if there is one. */ + if (VOID_TYPE_P (*gnu_result_type_p)) + { + if (Present (gnat_cond)) + { + if (!gnu_cond) + gnu_cond = gnat_to_gnu (gnat_cond); + gnu_result = build3 (COND_EXPR, void_type_node, gnu_cond, gnu_result, + alloc_stmt_list ()); + } + } + else + gnu_result = build1 (NULL_EXPR, *gnu_result_type_p, gnu_result); + + return gnu_result; +} + /* Return true if GNAT_NODE is on the LHS of an assignment or an actual parameter of a call. */ @@ -5949,7 +6083,7 @@ gnat_to_gnu (Node_Id gnat_node) N_Raise_Storage_Error); else if (Nkind (Expression (gnat_node)) == N_Function_Call) gnu_result - = call_to_gnu (Expression (gnat_node), &gnu_result_type, gnu_lhs, + = Call_to_gnu (Expression (gnat_node), &gnu_result_type, gnu_lhs, atomic_sync_required_p (Name (gnat_node))); else { @@ -6238,7 +6372,7 @@ gnat_to_gnu (Node_Id gnat_node) case N_Function_Call: case N_Procedure_Call_Statement: - gnu_result = call_to_gnu (gnat_node, &gnu_result_type, NULL_TREE, false); + gnu_result = Call_to_gnu (gnat_node, &gnu_result_type, NULL_TREE, false); break; /************************/ @@ -6661,105 +6795,10 @@ gnat_to_gnu (Node_Id gnat_node) case N_Raise_Constraint_Error: case N_Raise_Program_Error: case N_Raise_Storage_Error: - { - const int reason = UI_To_Int (Reason (gnat_node)); - const Node_Id gnat_cond = Condition (gnat_node); - const bool with_extra_info = Exception_Extra_Info - && !No_Exception_Handlers_Set () - && !get_exception_label (kind); - tree gnu_cond = NULL_TREE; - - if (type_annotate_only) - { - gnu_result = alloc_stmt_list (); - break; - } - - gnu_result_type = get_unpadded_type (Etype (gnat_node)); - - switch (reason) - { - case CE_Access_Check_Failed: - if (with_extra_info) - gnu_result = build_call_raise_column (reason, gnat_node); - break; - - case CE_Index_Check_Failed: - case CE_Range_Check_Failed: - case CE_Invalid_Data: - if (Present (gnat_cond) - && Nkind (gnat_cond) == N_Op_Not - && Nkind (Right_Opnd (gnat_cond)) == N_In - && Nkind (Right_Opnd (Right_Opnd (gnat_cond))) == N_Range) - { - Node_Id gnat_index = Left_Opnd (Right_Opnd (gnat_cond)); - Node_Id gnat_type = Etype (gnat_index); - Node_Id gnat_range = Right_Opnd (Right_Opnd (gnat_cond)); - tree gnu_index = gnat_to_gnu (gnat_index); - tree gnu_low_bound = gnat_to_gnu (Low_Bound (gnat_range)); - tree gnu_high_bound = gnat_to_gnu (High_Bound (gnat_range)); - struct range_check_info_d *rci; - - if (with_extra_info - && Known_Esize (gnat_type) - && UI_To_Int (Esize (gnat_type)) <= 32) - gnu_result - = build_call_raise_range (reason, gnat_node, gnu_index, - gnu_low_bound, gnu_high_bound); - - /* If loop unswitching is enabled, we try to compute invariant - conditions for checks applied to iteration variables, i.e. - conditions that are both independent of the variable and - necessary in order for the check to fail in the course of - some iteration, and prepend them to the original condition - of the checks. This will make it possible later for the - loop unswitching pass to replace the loop with two loops, - one of which has the checks eliminated and the other has - the original checks reinstated, and a run time selection. - The former loop will be suitable for vectorization. */ - if (flag_unswitch_loops - && (gnu_low_bound = gnat_invariant_expr (gnu_low_bound)) - && (gnu_high_bound = gnat_invariant_expr (gnu_high_bound)) - && (rci = push_range_check_info (gnu_index))) - { - rci->low_bound = gnu_low_bound; - rci->high_bound = gnu_high_bound; - rci->type = gnat_to_gnu_type (gnat_type); - rci->invariant_cond = build1 (SAVE_EXPR, boolean_type_node, - boolean_true_node); - gnu_cond = build_binary_op (TRUTH_ANDIF_EXPR, - boolean_type_node, - rci->invariant_cond, - gnat_to_gnu (gnat_cond)); - } - } - break; - - default: - break; - } - - if (gnu_result == error_mark_node) - gnu_result = build_call_raise (reason, gnat_node, kind); - - set_expr_location_from_node (gnu_result, gnat_node); - - /* If the type is VOID, this is a statement, so we need to generate - the code for the call. Handle a condition, if there is one. */ - if (VOID_TYPE_P (gnu_result_type)) - { - if (Present (gnat_cond)) - { - if (!gnu_cond) - gnu_cond = gnat_to_gnu (gnat_cond); - gnu_result - = build3 (COND_EXPR, void_type_node, gnu_cond, gnu_result, - alloc_stmt_list ()); - } - } - else - gnu_result = build1 (NULL_EXPR, gnu_result_type, gnu_result); - } + if (type_annotate_only) + gnu_result = alloc_stmt_list (); + else + gnu_result = Raise_Error_to_gnu (gnat_node, &gnu_result_type); break; case N_Validate_Unchecked_Conversion: