From patchwork Sun Jul 18 12:03:25 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Sandiford X-Patchwork-Id: 59163 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 DBA42B70A5 for ; Sun, 18 Jul 2010 22:03:40 +1000 (EST) Received: (qmail 27416 invoked by alias); 18 Jul 2010 12:03:39 -0000 Received: (qmail 27061 invoked by uid 22791); 18 Jul 2010 12:03:37 -0000 X-SWARE-Spam-Status: No, hits=-1.7 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, TW_TM, T_TO_NO_BRKTS_FREEMAIL X-Spam-Check-By: sourceware.org Received: from mail-wy0-f175.google.com (HELO mail-wy0-f175.google.com) (74.125.82.175) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sun, 18 Jul 2010 12:03:31 +0000 Received: by wye20 with SMTP id 20so4182911wye.20 for ; Sun, 18 Jul 2010 05:03:29 -0700 (PDT) Received: by 10.227.155.139 with SMTP id s11mr2809633wbw.221.1279454608844; Sun, 18 Jul 2010 05:03:28 -0700 (PDT) Received: from localhost (rsandifo.gotadsl.co.uk [82.133.89.107]) by mx.google.com with ESMTPS id i25sm31710527wbi.4.2010.07.18.05.03.27 (version=TLSv1/SSLv3 cipher=RC4-MD5); Sun, 18 Jul 2010 05:03:27 -0700 (PDT) From: Richard Sandiford To: gcc-patches@gcc.gnu.org Mail-Followup-To: gcc-patches@gcc.gnu.org, rdsandiford@googlemail.com Subject: Extend widening_mul pass to handle fixed-point types Date: Sun, 18 Jul 2010 13:03:25 +0100 Message-ID: <87fwzhro8i.fsf@firetop.home> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux) MIME-Version: 1.0 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 This patch makes the widening_mul pass handle fixed-point types, thus fixing gcc.target/dpaq_sa_l_w.c. WIDEN_MULT_PLUS_EXPR and WIDEN_MULT_MINUS_EXPR already handle the types correctly, it's just that we never generate them. The current multiply-accumulate code (quite reasonably) converts the multiplication to a WIDEN_MULT first, then uses the operands of that WIDEN_MULT in the WIDEN_MULT_PLUS_EXPR and WIDEN_MULT_MINUS_EXPR. The main gotcha with fixed-point types is that WIDEN_MULT_EXPR _doesn't_ support fixed-point types. Indeed MIPS -- the only fixed-point target AFAIK -- doesn't have a pure fixed-point widening multiplication instruction, just a multiply-accumulate one[*]. So there isn't any use for a fixed-point WIDEN_MULT_EXPR right now. Even if I tried to implement it, it would just be dead code, and there's no easy way of telling whether I got right. This patch therefore separates out the processes of getting the unwidened operands and of generating the WIDEN_MULT, so that we can still use the operands in cases where converting to a WIDEN_MULT isn't possible or worthwhile. I realise this is a bit of a strange case, but it does mean that the generation of WIDEN_MULT_{PLUS,MINUS}_EXPR depends only on whether the associated multiply-accumulate optab exists, not on whether other optabs (like the pure multiplication ones) exist too. Note that expand_debug_expr doesn't handle fixed-point types at the moment. That goes for these codes and for much simpler ones. I think adding that is a separate change. Tested on mipsisa64-elfoabi, where it fixes the testsuite failure. Also bootstrapped & regression-tested on x86_64-linux-gnu. OK to instal? Richard [*] It may well be that MIPS should use multiply-accumulate patterns to implement plain multiplication, but I don't have appropriate hardware to test that performance-wise. gcc/ * tree-ssa-math-opts.c (convert_mult_to_widen): Add an RHS_OUT parameter. Handle fixed-point types as well as integer ones, but continue to only generate WIDEN_MULT_EXPR for the latter. Use RHS_OUT to return the unwidened operands to the caller. (convert_plusminus_to_widen): Handle fixed-point types as well as integer ones. Update the call to convert_mult_to_widen. (execute_optimize_widening_mul): Update the call to convert_mult_to_widen. Index: gcc/tree-ssa-math-opts.c =================================================================== --- gcc/tree-ssa-math-opts.c 2010-07-18 08:36:48.000000000 +0100 +++ gcc/tree-ssa-math-opts.c 2010-07-18 12:35:42.000000000 +0100 @@ -1260,22 +1260,30 @@ struct gimple_opt_pass pass_optimize_bsw } }; -/* Process a single gimple statement STMT, which has a MULT_EXPR as - its rhs, and try to convert it into a WIDEN_MULT_EXPR. The return - value is true iff we converted the statement. */ +/* Process a single gimple statement STMT, which has a MULT_EXPR as its + rhs, and see if it is a widening multiplication. If so: + + - store the two unextended operands in RHS_OUT[0] and RHS_OUT[1], + if RHS_OUT is nonnull; and + - try to convert the statement into a WIDEN_MULT_EXPR. + + Return true if the statement could be converted or if operands + were stored in RHS_OUT. */ static bool -convert_mult_to_widen (gimple stmt) +convert_mult_to_widen (gimple stmt, tree *rhs_out) { gimple rhs1_stmt = NULL, rhs2_stmt = NULL; tree type1 = NULL, type2 = NULL; - tree rhs1, rhs2, rhs1_convop = NULL, rhs2_convop = NULL; + tree rhs1, rhs2, unwidened_rhs1 = NULL, unwidened_rhs2 = NULL; enum tree_code rhs1_code, rhs2_code; tree type; + bool use_widen_mult_p; type = TREE_TYPE (gimple_assign_lhs (stmt)); - if (TREE_CODE (type) != INTEGER_TYPE) + if (TREE_CODE (type) != INTEGER_TYPE + && TREE_CODE (type) != FIXED_POINT_TYPE) return false; rhs1 = gimple_assign_rhs1 (stmt); @@ -1287,14 +1295,17 @@ convert_mult_to_widen (gimple stmt) if (!is_gimple_assign (rhs1_stmt)) return false; rhs1_code = gimple_assign_rhs_code (rhs1_stmt); - if (!CONVERT_EXPR_CODE_P (rhs1_code)) + if (TREE_CODE (type) == INTEGER_TYPE + ? !CONVERT_EXPR_CODE_P (rhs1_code) + : rhs1_code != FIXED_CONVERT_EXPR) return false; - rhs1_convop = gimple_assign_rhs1 (rhs1_stmt); - type1 = TREE_TYPE (rhs1_convop); + unwidened_rhs1 = gimple_assign_rhs1 (rhs1_stmt); + type1 = TREE_TYPE (unwidened_rhs1); if (TYPE_PRECISION (type1) * 2 != TYPE_PRECISION (type)) return false; } - else if (TREE_CODE (rhs1) != INTEGER_CST) + else if (TREE_CODE (rhs1) != INTEGER_CST + && TREE_CODE (rhs1) != FIXED_CST) return false; if (TREE_CODE (rhs2) == SSA_NAME) @@ -1303,52 +1314,73 @@ convert_mult_to_widen (gimple stmt) if (!is_gimple_assign (rhs2_stmt)) return false; rhs2_code = gimple_assign_rhs_code (rhs2_stmt); - if (!CONVERT_EXPR_CODE_P (rhs2_code)) + if (TREE_CODE (type) == INTEGER_TYPE + ? !CONVERT_EXPR_CODE_P (rhs2_code) + : rhs2_code != FIXED_CONVERT_EXPR) return false; - rhs2_convop = gimple_assign_rhs1 (rhs2_stmt); - type2 = TREE_TYPE (rhs2_convop); + unwidened_rhs2 = gimple_assign_rhs1 (rhs2_stmt); + type2 = TREE_TYPE (unwidened_rhs2); if (TYPE_PRECISION (type2) * 2 != TYPE_PRECISION (type)) return false; } - else if (TREE_CODE (rhs2) != INTEGER_CST) + else if (TREE_CODE (rhs2) != INTEGER_CST + && TREE_CODE (rhs2) != FIXED_CST) return false; if (rhs1_stmt == NULL && rhs2_stmt == NULL) return false; + /* At present, WIDEN_MULT_EXPR only supports integer types, + not fixed-point ones. Processing fixed-point types is only + useful if the caller wants the unextended operands. */ + if (TREE_CODE (type) == FIXED_POINT_TYPE) + use_widen_mult_p = false; /* Verify that the machine can perform a widening multiply in this mode/signedness combination, otherwise this transformation is likely to pessimize code. */ - if ((rhs1_stmt == NULL || TYPE_UNSIGNED (type1)) - && (rhs2_stmt == NULL || TYPE_UNSIGNED (type2)) - && (optab_handler (umul_widen_optab, TYPE_MODE (type)) - == CODE_FOR_nothing)) - return false; + else if ((rhs1_stmt == NULL || TYPE_UNSIGNED (type1)) + && (rhs2_stmt == NULL || TYPE_UNSIGNED (type2)) + && (optab_handler (umul_widen_optab, TYPE_MODE (type)) + == CODE_FOR_nothing)) + use_widen_mult_p = false; else if ((rhs1_stmt == NULL || !TYPE_UNSIGNED (type1)) && (rhs2_stmt == NULL || !TYPE_UNSIGNED (type2)) && (optab_handler (smul_widen_optab, TYPE_MODE (type)) == CODE_FOR_nothing)) - return false; + use_widen_mult_p = false; else if (rhs1_stmt != NULL && rhs2_stmt != NULL && (TYPE_UNSIGNED (type1) != TYPE_UNSIGNED (type2)) && (optab_handler (usmul_widen_optab, TYPE_MODE (type)) == CODE_FOR_nothing)) + use_widen_mult_p = false; + else + use_widen_mult_p = true; + + if (!use_widen_mult_p && rhs_out == NULL) return false; if ((rhs1_stmt == NULL && !int_fits_type_p (rhs1, type2)) || (rhs2_stmt == NULL && !int_fits_type_p (rhs2, type1))) return false; - if (rhs1_stmt == NULL) - gimple_assign_set_rhs1 (stmt, fold_convert (type2, rhs1)); - else - gimple_assign_set_rhs1 (stmt, rhs1_convop); - if (rhs2_stmt == NULL) - gimple_assign_set_rhs2 (stmt, fold_convert (type1, rhs2)); - else - gimple_assign_set_rhs2 (stmt, rhs2_convop); - gimple_assign_set_rhs_code (stmt, WIDEN_MULT_EXPR); - update_stmt (stmt); + if (unwidened_rhs1 == NULL) + unwidened_rhs1 = fold_convert (type2, rhs1); + if (unwidened_rhs2 == NULL) + unwidened_rhs2 = fold_convert (type1, rhs2); + + if (rhs_out) + { + rhs_out[0] = unwidened_rhs1; + rhs_out[1] = unwidened_rhs2; + } + + if (use_widen_mult_p) + { + gimple_assign_set_rhs1 (stmt, unwidened_rhs1); + gimple_assign_set_rhs2 (stmt, unwidened_rhs2); + gimple_assign_set_rhs_code (stmt, WIDEN_MULT_EXPR); + update_stmt (stmt); + } return true; } @@ -1364,14 +1396,15 @@ convert_plusminus_to_widen (gimple_stmt_ { gimple rhs1_stmt = NULL, rhs2_stmt = NULL; tree type; - tree lhs, rhs1, rhs2, mult_rhs1, mult_rhs2, add_rhs; + tree lhs, rhs1, rhs2, mult_rhs[2], add_rhs; enum tree_code rhs1_code = ERROR_MARK, rhs2_code = ERROR_MARK; optab this_optab; enum tree_code wmult_code; lhs = gimple_assign_lhs (stmt); type = TREE_TYPE (lhs); - if (TREE_CODE (type) != INTEGER_TYPE) + if (TREE_CODE (type) != INTEGER_TYPE + && TREE_CODE (type) != FIXED_POINT_TYPE) return false; if (code == MINUS_EXPR) @@ -1407,29 +1440,28 @@ convert_plusminus_to_widen (gimple_stmt_ else return false; - if (rhs1_code == MULT_EXPR) + if (code == PLUS_EXPR && rhs1_code == MULT_EXPR) { - if (!convert_mult_to_widen (rhs1_stmt)) + if (!convert_mult_to_widen (rhs1_stmt, mult_rhs)) return false; - rhs1_code = gimple_assign_rhs_code (rhs1_stmt); + add_rhs = rhs2; } - if (rhs2_code == MULT_EXPR) + else if (rhs2_code == MULT_EXPR) { - if (!convert_mult_to_widen (rhs2_stmt)) + if (!convert_mult_to_widen (rhs2_stmt, mult_rhs)) return false; - rhs2_code = gimple_assign_rhs_code (rhs2_stmt); + add_rhs = rhs1; } - - if (code == PLUS_EXPR && rhs1_code == WIDEN_MULT_EXPR) + else if (code == PLUS_EXPR && rhs1_code == WIDEN_MULT_EXPR) { - mult_rhs1 = gimple_assign_rhs1 (rhs1_stmt); - mult_rhs2 = gimple_assign_rhs2 (rhs1_stmt); + mult_rhs[0] = gimple_assign_rhs1 (rhs1_stmt); + mult_rhs[1] = gimple_assign_rhs2 (rhs1_stmt); add_rhs = rhs2; } else if (rhs2_code == WIDEN_MULT_EXPR) { - mult_rhs1 = gimple_assign_rhs1 (rhs2_stmt); - mult_rhs2 = gimple_assign_rhs2 (rhs2_stmt); + mult_rhs[0] = gimple_assign_rhs1 (rhs2_stmt); + mult_rhs[1] = gimple_assign_rhs2 (rhs2_stmt); add_rhs = rhs1; } else @@ -1437,7 +1469,7 @@ convert_plusminus_to_widen (gimple_stmt_ /* ??? May need some type verification here? */ - gimple_assign_set_rhs_with_ops_1 (gsi, wmult_code, mult_rhs1, mult_rhs2, + gimple_assign_set_rhs_with_ops_1 (gsi, wmult_code, mult_rhs[0], mult_rhs[1], add_rhs); update_stmt (gsi_stmt (*gsi)); return true; @@ -1467,7 +1499,7 @@ execute_optimize_widening_mul (void) code = gimple_assign_rhs_code (stmt); if (code == MULT_EXPR) - changed |= convert_mult_to_widen (stmt); + changed |= convert_mult_to_widen (stmt, NULL); else if (code == PLUS_EXPR || code == MINUS_EXPR) changed |= convert_plusminus_to_widen (&gsi, stmt, code); }