From patchwork Wed Jan 18 08:50:39 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Kewen.Lin" X-Patchwork-Id: 45099 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp2219282wrn; Wed, 18 Jan 2023 00:51:49 -0800 (PST) X-Google-Smtp-Source: AMrXdXtdosY8VPT/G6OO2CuLCAigJTWkOeTHYYh2YI3Xan/1eGb5jBHX8fphGHdh6JbeWx/L9rbI X-Received: by 2002:a05:6402:3213:b0:49b:62c9:4fd with SMTP id g19-20020a056402321300b0049b62c904fdmr7650206eda.1.1674031909755; Wed, 18 Jan 2023 00:51:49 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1674031909; cv=none; d=google.com; s=arc-20160816; b=BiQ+fwA4yb2uc5syQjRiYZXYF7GLNx8xisZIrk7KUF5GZx3hFP0qahCSeD2SH7EaKk 33ar9YMWakIazM7EfAE2iumHMcQ5VCTKojEnauR4RFi/dpAd0jJVkBW+VuivQKppF8hX kJHFJ5iNkHMbozUtTjeGbE7uotoiNaulrzNRjTnjChQwhe2q6vK/Svmn9XRDsGnit49y VikVdLLxN3exRMzzHrSeQSkTJywsPPPHWdO7FCdvNcdEDBgAcHXSv5+5uMBk7Ct+EBrW GGdHxK0tBahkUCRa2d/b5266pp1ACeV5CkKOrQMxK7TKRADM3t9WkalOJUSwyWt+uzdY IXTw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:from:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence:mime-version :content-transfer-encoding:subject:cc:to:content-language:user-agent :date:message-id:dmarc-filter:delivered-to:dkim-signature :dkim-filter; bh=afx+UlWeEm0DFeBFyHwmQy7K3faPT2tmbUb9fTVtj1A=; b=IDsNxMvks47v9FO8io/oAIzHLVd6+BC+n3L4ZZjdFs9TSsOLGaRKSA3A1cK1xbLzar ghvJ6Uj9T4gZ269EcVAtdfOGJEvPBcSf418Ghmrvn3TI1TFgUoKQFXNOUkdv5fkJ2L6y 7sWpIH8Lv1B7WzCq7+XENdEA0U22eMcaNdkoL/fey8R8zR0gRppvGdU6tFnH/rDJwfy/ pV8KY34bCE1dgCrOpcd/HIV7Xe1ot1dwCiLwzNPSRObjqOgrJDGHWxsb/atGWqHktRO6 27QkjzP9FN7PJNiFH4RSMTev773MuI9WwEgP71C6vPsgUX5cvGv4Skrl3mbEXBE7+muB /u7Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=xMcrY26H; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from sourceware.org (ip-8-43-85-97.sourceware.org. [8.43.85.97]) by mx.google.com with ESMTPS id q18-20020a056402519200b004854e1d2682si338050edd.249.2023.01.18.00.51.49 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 18 Jan 2023 00:51:49 -0800 (PST) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) client-ip=8.43.85.97; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=xMcrY26H; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id AF134385B516 for ; Wed, 18 Jan 2023 08:51:39 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org AF134385B516 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1674031899; bh=afx+UlWeEm0DFeBFyHwmQy7K3faPT2tmbUb9fTVtj1A=; h=Date:To:Cc:Subject:List-Id:List-Unsubscribe:List-Archive: List-Post:List-Help:List-Subscribe:From:Reply-To:From; b=xMcrY26HpS0/Ke+zShzb9Tpga1XhcRTcaLJSj8nVxZVJwzVDcLI530uDFHJHeZo9s OACKMrOKiRPxyBq2B4p7J9GYLe5atg8ZIMfi+kt1pJBL0AVMjbTeQVmV2XiVrGeas8 vURSTdKDYJx56OZgCE9f8rtPwppCC3XM53/c859E= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) by sourceware.org (Postfix) with ESMTPS id 4FF8B3858D28 for ; Wed, 18 Jan 2023 08:50:52 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 4FF8B3858D28 Received: from pps.filterd (m0098396.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 30I8CDuE020713; Wed, 18 Jan 2023 08:50:50 GMT Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3n6d1vrt9n-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 18 Jan 2023 08:50:49 +0000 Received: from m0098396.ppops.net (m0098396.ppops.net [127.0.0.1]) by pps.reinject (8.17.1.5/8.17.1.5) with ESMTP id 30I8Fecg031180; Wed, 18 Jan 2023 08:50:49 GMT Received: from ppma02fra.de.ibm.com (47.49.7a9f.ip4.static.sl-reverse.com [159.122.73.71]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 3n6d1vrt92-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 18 Jan 2023 08:50:48 +0000 Received: from pps.filterd (ppma02fra.de.ibm.com [127.0.0.1]) by ppma02fra.de.ibm.com (8.17.1.19/8.17.1.19) with ESMTP id 30HEkgaQ027150; Wed, 18 Jan 2023 08:50:46 GMT Received: from smtprelay02.fra02v.mail.ibm.com ([9.218.2.226]) by ppma02fra.de.ibm.com (PPS) with ESMTPS id 3n3m16kmqj-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 18 Jan 2023 08:50:46 +0000 Received: from smtpav01.fra02v.mail.ibm.com (smtpav01.fra02v.mail.ibm.com [10.20.54.100]) by smtprelay02.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 30I8ohCQ45416952 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 18 Jan 2023 08:50:44 GMT Received: from smtpav01.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id D1A5820043; Wed, 18 Jan 2023 08:50:43 +0000 (GMT) Received: from smtpav01.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id B798320040; Wed, 18 Jan 2023 08:50:41 +0000 (GMT) Received: from [9.197.238.43] (unknown [9.197.238.43]) by smtpav01.fra02v.mail.ibm.com (Postfix) with ESMTP; Wed, 18 Jan 2023 08:50:41 +0000 (GMT) Message-ID: <55027326-ffe1-87e8-9e4b-08535425afdd@linux.ibm.com> Date: Wed, 18 Jan 2023 16:50:39 +0800 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:91.0) Gecko/20100101 Thunderbird/91.6.1 Content-Language: en-US To: GCC Patches Cc: Segher Boessenkool , David Edelsohn , Peter Bergner Subject: [PATCH 1/2] rs6000: Refactor script genfusion.pl X-TM-AS-GCONF: 00 X-Proofpoint-ORIG-GUID: fqdSjTpy7mBNABqUJTqaD9UQw4G6ufOP X-Proofpoint-GUID: KWF-vopUNas4KbVwRDL5CqNZwaZP0VdE X-Proofpoint-UnRewURL: 0 URL was un-rewritten MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.923,Hydra:6.0.562,FMLib:17.11.122.1 definitions=2023-01-18_03,2023-01-17_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 adultscore=0 bulkscore=0 lowpriorityscore=0 impostorscore=0 priorityscore=1501 phishscore=0 clxscore=1015 spamscore=0 mlxscore=0 mlxlogscore=999 suspectscore=0 malwarescore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2212070000 definitions=main-2301180073 X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: "Kewen.Lin via Gcc-patches" From: "Kewen.Lin" Reply-To: "Kewen.Lin" Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org Sender: "Gcc-patches" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1755349683546865087?= X-GMAIL-MSGID: =?utf-8?q?1755349683546865087?= Hi, As Segher suggested in [1], this patch is to refactor the script genfusion.pl for generating fusion.md. It mainly consists of: 1) Add main subroutine, which calls several backbone subroutines, hope it can show the skeleton clearly. 2) Encapsulate copyright and top comments emission to a separated subroutine gen_copyright_and_top_comments. 3) Remove multiple nested loops in gen_ld_cmpi_p10 by expanding them directly, hope it can be more clear. Also factor out some logics to ld_cmpi_p10_emit_define which aims to focus on define_insn_and_split emission. Refine subroutine mode_to_ldst_char a bit. 4) For gen_logical_addsubf, separate scalar and vector handlings into gen_logical_addsubf_{vector,scalar}, factor out op information querying on complement/invert/ commute2/"rtl op name" to subroutine logical_addsub_get_op_info, factor out some logics on define_insn_and_split emission to subroutine logical_addsubf_emit_define, and factor out some logic to construct inner and outer expression to subroutine logical_addsubf_make_exp. 5) For gen_addadd, it's quite simple so I leave it alone, just removes one useless variable. Note that this patch keeps the fusion.md is exactly the same as before. Any comments are highly appreciated. [1] https://gcc.gnu.org/pipermail/gcc-patches/2022-December/608830.html BR, Kewen ----- gcc/ChangeLog: * config/rs6000/genfusion.pl (gen_copyright_and_top_comments): New subroutine, refactor from some existing code. (mode_to_ldst_char): Adjust with die. (ld_cmpi_p10_emit_define): New subroutine, refactor from gen_ld_cmpi_p10, emit define_insn_and_split for load-cmpi fusion. (gen_ld_cmpi_p10): Adjust with ld_cmpi_p10_emit_define. (logical_addsubf_emit_define): New subroutine, refactor from gen_logical_addsubf, emit define_insn_and_split for logical/addsubf fusion. (logical_addsub_get_op_info): New subroutine, refactor from gen_logical_addsubf, offer some information for the given operator. (logical_addsubf_make_exp): New subroutine, refactor from gen_logical_addsubf, construct the expression used for emission. (gen_logical_addsubf_scalar): New subroutine, refactor from gen_logical_addsubf, focus on scalar kind of logical/addsubf fusion. (gen_logical_addsubf_vector): New subroutine, refactor from gen_logical_addsubf, focus on vector kind of logical/addsubf fusion. (gen_logical_addsubf): Adjust with calling gen_logical_addsubf_scalar and gen_logical_addsubf_vector. (gen_addadd): Remove useless variable. (main): New subroutine, call the corresponding main subroutine for each fusion type. --- gcc/config/rs6000/genfusion.pl | 554 ++++++++++++++++++++------------- 1 file changed, 337 insertions(+), 217 deletions(-) -- 2.37.0 diff --git a/gcc/config/rs6000/genfusion.pl b/gcc/config/rs6000/genfusion.pl index e4db352e0ce..487e662ce05 100755 --- a/gcc/config/rs6000/genfusion.pl +++ b/gcc/config/rs6000/genfusion.pl @@ -22,7 +22,9 @@ use warnings; use strict; -print <<'EOF'; +sub gen_copyright_and_top_comments +{ + print << "EOF"; ;; Generated automatically by genfusion.pl ;; Copyright (C) 2020-2023 Free Software Foundation, Inc. @@ -44,255 +46,369 @@ print <<'EOF'; ;; . EOF +} +# Map any mode of DI/SI/HI/QI to single char d/w/h/b, +# die if the given mode in arg 0 isn't expected. sub mode_to_ldst_char { - my ($mode) = @_; - my %x = (DI => 'd', SI => 'w', HI => 'h', QI => 'b'); - return $x{$mode} if exists $x{$mode}; - return '?'; + my $mode = $_[0]; + die "Unexpected mode: $mode" unless $mode =~ /[QHSD]I/; + my %map = (DI => 'd', SI => 'w', HI => 'h', QI => 'b'); + return $map{$mode}; } -sub gen_ld_cmpi_p10 +# Emit define_insn_and_split for load-cmpi fusion type based +# on the below given arguments: +# arg 0: mode of load. +# arg 1: mode of result. +# arg 2: mode of comparison. +# arg 3: extension type. +sub ld_cmpi_p10_emit_define { - my ($lmode, $ldst, $clobbermode, $result, $cmpl, $echr, $constpred, - $mempred, $ccmode, $np, $extend, $resultmode); - LMODE: foreach $lmode ('DI','SI','HI','QI') { - $ldst = mode_to_ldst_char($lmode); - $clobbermode = $lmode; - # For clobber, we need a SI/DI reg in case we - # split because we have to sign/zero extend. - if ($lmode eq 'HI' || $lmode eq 'QI') { $clobbermode = "GPR"; } - RESULT: foreach $result ('clobber', $lmode, "EXT".$lmode) { - # EXTDI does not exist, and we cannot directly produce HI/QI results. - next RESULT if $result eq "EXTDI" || $result eq "HI" || $result eq "QI"; - # Don't allow EXTQI because that would allow HI result which we can't do. - $result = "GPR" if $result eq "EXTQI"; - CCMODE: foreach $ccmode ('CC','CCUNS') { - $np = "NON_PREFIXED_D"; - $mempred = "non_update_memory_operand"; - if ( $ccmode eq 'CC' ) { - next CCMODE if $lmode eq 'QI'; - if ( $lmode eq 'DI' || $lmode eq 'SI' ) { - # ld and lwa are both DS-FORM. - $np = "NON_PREFIXED_DS"; - $mempred = "ds_form_mem_operand"; - } - $cmpl = ""; - $echr = "a"; - $constpred = "const_m1_to_1_operand"; - } else { - if ( $lmode eq 'DI' ) { - # ld is DS-form, but lwz is not. - $np = "NON_PREFIXED_DS"; - $mempred = "ds_form_mem_operand"; - } - $cmpl = "l"; - $echr = "z"; - $constpred = "const_0_to_1_operand"; - } - if ($lmode eq 'DI') { $echr = ""; } - if ($result =~ m/^EXT/ || $result eq 'GPR' || $clobbermode eq 'GPR') { - # We always need extension if result > lmode. - if ( $ccmode eq 'CC' ) { - $extend = "sign"; - } else { - $extend = "zero"; - } - } else { - # Result of SI/DI does not need sign extension. - $extend = "none"; - } - print ";; load-cmpi fusion pattern generated by gen_ld_cmpi_p10\n"; - print ";; load mode is $lmode result mode is $result compare mode is $ccmode extend is $extend\n"; - - print "(define_insn_and_split \"*l${ldst}${echr}_cmp${cmpl}di_cr0_${lmode}_${result}_${ccmode}_${extend}\"\n"; - print " [(set (match_operand:${ccmode} 2 \"cc_reg_operand\" \"=x\")\n"; - print " (compare:${ccmode} (match_operand:${lmode} 1 \"${mempred}\" \"m\")\n"; - if ($ccmode eq 'CCUNS') { print " "; } - print " (match_operand:${lmode} 3 \"${constpred}\" \"n\")))\n"; - if ($result eq 'clobber') { - print " (clobber (match_scratch:${clobbermode} 0 \"=r\"))]\n"; - } elsif ($result eq $lmode) { - print " (set (match_operand:${result} 0 \"gpc_reg_operand\" \"=r\") (match_dup 1))]\n"; - } else { - print " (set (match_operand:${result} 0 \"gpc_reg_operand\" \"=r\") (${extend}_extend:${result} (match_dup 1)))]\n"; - } - print " \"(TARGET_P10_FUSION)\"\n"; - print " \"l${ldst}${echr}%X1 %0,%1\\;cmp${cmpl}di %2,%0,%3\"\n"; - print " \"&& reload_completed\n"; - print " && (cc_reg_not_cr0_operand (operands[2], CCmode)\n"; - print " || !address_is_non_pfx_d_or_x (XEXP (operands[1], 0),\n"; - print " ${lmode}mode, ${np}))\"\n"; - - if ($extend eq "none") { - print " [(set (match_dup 0) (match_dup 1))\n"; - } else { - $resultmode = $result; - if ( $result eq 'clobber' ) { $resultmode = $clobbermode } - print " [(set (match_dup 0) (${extend}_extend:${resultmode} (match_dup 1)))\n"; - } - print " (set (match_dup 2)\n"; - print " (compare:${ccmode} (match_dup 0) (match_dup 3)))]\n"; - print " \"\"\n"; - print " [(set_attr \"type\" \"fused_load_cmpi\")\n"; - print " (set_attr \"cost\" \"8\")\n"; - print " (set_attr \"length\" \"8\")])\n"; - print "\n"; - } - } + my $lmode = $_[0]; + my $result = $_[1]; + my $ccmode = $_[2]; + my $extend = $_[3]; + + # For clobber, we need a SI/DI reg in case we + # split because we have to sign/zero extend. + my $clobbermode = ($lmode eq 'HI' || $lmode eq 'QI') ? 'GPR' : $lmode; + + my $np = 'NON_PREFIXED_D'; + my $mempred = 'non_update_memory_operand'; + + # ld and lwa are both DS-FORM. + if ( $lmode eq 'DI' + || ($lmode eq 'SI' && $ccmode eq 'CC') ) { + $np = 'NON_PREFIXED_DS'; + $mempred = 'ds_form_mem_operand'; + } + + my $cmpl = ''; + my $echr = 'a'; + my $constpred = 'const_m1_to_1_operand'; + + # Logical comparison has 'l', zero extended load has 'z'. + if ($ccmode eq 'CCUNS') { + $cmpl = 'l'; + $echr = 'z'; + $constpred = 'const_0_to_1_operand'; } + + # DI load doesn't have suffix for zero or sign. + $echr = '' if $lmode eq 'DI'; + + my $ldst = mode_to_ldst_char ($lmode); + + # define_insn_and_split comments. + print ";; load-cmpi fusion pattern generated by gen_ld_cmpi_p10\n"; + print ";; load mode is $lmode result mode is $result compare mode is $ccmode extend is $extend\n"; + + # main set pattern. + print "(define_insn_and_split \"*l${ldst}${echr}_cmp${cmpl}di_cr0_${lmode}_${result}_${ccmode}_${extend}\"\n"; + print " [(set (match_operand:${ccmode} 2 \"cc_reg_operand\" \"=x\")\n"; + print " (compare:${ccmode} (match_operand:${lmode} 1 \"${mempred}\" \"m\")\n"; + print " " if ($ccmode eq 'CCUNS'); + print " (match_operand:${lmode} 3 \"${constpred}\" \"n\")))\n"; + + # clobber or another set pattern. + if ($result eq 'clobber') { + print " (clobber (match_scratch:${clobbermode} 0 \"=r\"))]\n"; + } elsif ($result eq $lmode) { + print " (set (match_operand:${result} 0 \"gpc_reg_operand\" \"=r\") (match_dup 1))]\n"; + } else { + print " (set (match_operand:${result} 0 \"gpc_reg_operand\" \"=r\") (${extend}_extend:${result} (match_dup 1)))]\n"; + } + + # insn condition and output template. + print " \"(TARGET_P10_FUSION)\"\n"; + print " \"l${ldst}${echr}%X1 %0,%1\\;cmp${cmpl}di %2,%0,%3\"\n"; + + # split condition. + print " \"&& reload_completed\n"; + print " && (cc_reg_not_cr0_operand (operands[2], CCmode)\n"; + print " || !address_is_non_pfx_d_or_x (XEXP (operands[1], 0),\n"; + print " ${lmode}mode, ${np}))\"\n"; + + # new insn patterns. + if ($extend eq 'none') { + print " [(set (match_dup 0) (match_dup 1))\n"; + } else { + my $resultmode = ( $result eq 'clobber' ) ? $clobbermode : $result; + print " [(set (match_dup 0) (${extend}_extend:${resultmode} (match_dup 1)))\n"; + } + print " (set (match_dup 2)\n"; + print " (compare:${ccmode} (match_dup 0) (match_dup 3)))]\n"; + print " \"\"\n"; + + # insn attributes. + print " [(set_attr \"type\" \"fused_load_cmpi\")\n"; + print " (set_attr \"cost\" \"8\")\n"; + print " (set_attr \"length\" \"8\")])\n"; + print "\n"; } -sub gen_logical_addsubf +# Main subroutine to generate load-cmpi fusion type. +sub gen_ld_cmpi_p10 { - my @logicals = ( "and", "andc", "eqv", "nand", "nor", "or", "orc", "xor" ); - my %logicals_addsub = ( "and"=>1, "nand"=>1, "nor"=>1, "or"=>1 ); - my @addsub = ( "add", "subf" ); - my %isaddsub = ( "add"=>1, "subf"=>1 ); - my %complement = ( "and"=> 0, "andc"=> 1, "eqv"=> 0, "nand"=> 3, - "nor"=> 3, "or"=> 0, "orc"=> 1, "xor"=> 0, - "add"=> 0, "subf"=> 0 ); - my %invert = ( "and"=> 0, "andc"=> 0, "eqv"=> 1, "nand"=> 0, - "nor"=> 0, "or"=> 0, "orc"=> 0, "xor"=> 0, - "add"=> 0, "subf"=> 0 ); - my %commute2 = ( "and"=> 1, "andc"=> 0, "eqv"=> 1, "nand"=> 0, - "nor"=> 0, "or"=> 1, "orc"=> 0, "xor"=> 1 ); - my %rtlop = ( "and"=>"and", "andc"=>"and", "eqv"=>"xor", "nand"=>"ior", - "nor"=>"and", "or"=>"ior", "orc"=>"ior", "xor"=>"xor", - "add"=>"plus", "subf"=>"minus" ); - - my ($kind, $vchr, $mode, $pred, $constraint, $cr, $outer, @outer_ops, - $outer_op, $outer_comp, $outer_inv, $outer_rtl, $inner, @inner_ops, - $inner_comp, $inner_inv, $inner_rtl, $inner_op, $both_commute, $c4, - $bc, $inner_arg0, $inner_arg1, $inner_exp, $outer_arg2, $outer_exp, - $ftype, $insn, $is_subf, $is_rsubf, $outer_32, $outer_42,$outer_name, - $fuse_type); - KIND: foreach $kind ('scalar','vector') { - @outer_ops = @logicals; - if ( $kind eq 'vector' ) { - $vchr = "v"; - $mode = "VM"; - $pred = "altivec_register_operand"; - $constraint = "v"; - $fuse_type = "fused_vector"; - } else { - $vchr = ""; - $mode = "GPR"; - $pred = "gpc_reg_operand"; - $constraint = "r"; - $fuse_type = "fused_arith_logical"; - push (@outer_ops, @addsub); - push (@outer_ops, ( "rsubf" )); - } - $c4 = "${constraint},${constraint},${constraint},${constraint}"; - OUTER: foreach $outer ( @outer_ops ) { - $outer_name = "${vchr}${outer}"; - $is_subf = ( $outer eq "subf" ); - $is_rsubf = ( $outer eq "rsubf" ); - if ( $is_rsubf ) { - $outer = "subf"; - } - $outer_op = "${vchr}${outer}"; - $outer_comp = $complement{$outer}; - $outer_inv = $invert{$outer}; - $outer_rtl = $rtlop{$outer}; - @inner_ops = @logicals; - $ftype = "logical-logical"; - if ( exists $isaddsub{$outer} ) { - @inner_ops = sort keys %logicals_addsub; - $ftype = "logical-add"; - } elsif ( $kind ne 'vector' && exists $logicals_addsub{$outer} ) { - push (@inner_ops, @addsub); - } - INNER: foreach $inner ( @inner_ops ) { - if ( exists $isaddsub{$inner} ) { - $ftype = "add-logical"; - } - $inner_comp = $complement{$inner}; - $inner_inv = $invert{$inner}; - $inner_rtl = $rtlop{$inner}; - $inner_op = "${vchr}${inner}"; - # If both ops commute then we can specify % on operand 1 - # so the pattern will let operands 1 and 2 interchange. - $both_commute = ($inner eq $outer) && ($commute2{$inner} == 1); - $bc = ""; if ( $both_commute ) { $bc = "%"; } - $inner_arg0 = "(match_operand:${mode} 0 \"${pred}\" \"${c4}\")"; - $inner_arg1 = "(match_operand:${mode} 1 \"${pred}\" \"${bc}${c4}\")"; - if ( ($inner_comp & 1) == 1 ) { - $inner_arg0 = "(not:${mode} $inner_arg0)"; - } - if ( ($inner_comp & 2) == 2 ) { - $inner_arg1 = "(not:${mode} $inner_arg1)"; - } - $inner_exp = "(${inner_rtl}:${mode} ${inner_arg0} - ${inner_arg1})"; - if ( $inner_inv == 1 ) { - $inner_exp = "(not:${mode} $inner_exp)"; - } - $outer_arg2 = "(match_operand:${mode} 2 \"${pred}\" \"${c4}\")"; - if ( ($outer_comp & 1) == 1 ) { - $outer_arg2 = "(not:${mode} $outer_arg2)"; - } - if ( ($outer_comp & 2) == 2 ) { - $inner_exp = "(not:${mode} $inner_exp)"; - } - if ( $is_subf ) { - $outer_32 = "%2,%3"; - $outer_42 = "%2,%4"; - } else { - $outer_32 = "%3,%2"; - $outer_42 = "%4,%2"; - } - if ( $is_rsubf == 1 ) { - $outer_exp = "(${outer_rtl}:${mode} ${outer_arg2} - ${inner_exp})"; - } else { - $outer_exp = "(${outer_rtl}:${mode} ${inner_exp} - ${outer_arg2})"; - } - if ( $outer_inv == 1 ) { - $outer_exp = "(not:${mode} $outer_exp)"; - } + # For load mode is DI, there is no EXTDI, the result of + # DI doesn't need extension. + ld_cmpi_p10_emit_define ('DI', 'clobber', 'CC', 'none'); + ld_cmpi_p10_emit_define ('DI', 'clobber', 'CCUNS', 'none'); + ld_cmpi_p10_emit_define ('DI', 'DI', 'CC', 'none'); + ld_cmpi_p10_emit_define ('DI', 'DI', 'CCUNS', 'none'); + + # For load mode is SI, only EXTSI need extension. + ld_cmpi_p10_emit_define ('SI', 'clobber', 'CC', 'none'); + ld_cmpi_p10_emit_define ('SI', 'clobber', 'CCUNS', 'none'); + ld_cmpi_p10_emit_define ('SI', 'SI', 'CC', 'none'); + ld_cmpi_p10_emit_define ('SI', 'SI', 'CCUNS', 'none'); + ld_cmpi_p10_emit_define ('SI', 'EXTSI', 'CC', 'sign'); + ld_cmpi_p10_emit_define ('SI', 'EXTSI', 'CCUNS', 'zero'); - $insn = <<"EOF"; + # For load mode is HI, we can't produce HI result directly. + # We always need extension if result is wider than load + # mode. + ld_cmpi_p10_emit_define ('HI', 'clobber', 'CC', 'sign'); + ld_cmpi_p10_emit_define ('HI', 'clobber', 'CCUNS', 'zero'); + ld_cmpi_p10_emit_define ('HI', 'EXTHI', 'CC', 'sign'); + ld_cmpi_p10_emit_define ('HI', 'EXTHI', 'CCUNS', 'zero'); + + # For load mode is QI, we can't produce QI result directly, + # also ignore CC here. We always need extension if result + # is wider than load mode. + ld_cmpi_p10_emit_define ('QI', 'clobber', 'CCUNS', 'zero'); + # Don't allow EXTQI because that would allow HI result + # which we can't do. + ld_cmpi_p10_emit_define ('QI', 'GPR', 'CCUNS', 'zero'); +} + +# Emit define_insn_and_split for logical/addsubf fusion type +# based the below given arguments: +# arg 0: string for fusion type in comments, can only be +# "logical-logical", "logical-add" or "add-logical". +# arg 1: "scalar" or "vector". +# arg 2: outer operator. +# arg 3: inner operator. +# arg 4: machine mode. +# arg 5: predicate. +# arg 6: constraint. +# arg 7: expression pattern made by logical_addsubf_make_exp. +# arg 8: fusion type for insn type attribute. +sub logical_addsubf_emit_define +{ + my ($ftype, $kind, $outer_op, $inner_op, $mode, $pred, $cstr, + $exp, $fuse_type) = @_; + + # Make some adjustments for subf and rsubf. + my $outer_name = $outer_op; + $outer_op = 'subf' if $outer_op eq 'rsubf'; + + my $ops32 = '%3,%2'; + my $ops42 = '%4,%2'; + if ( $outer_name eq 'subf' ) { + $ops32 = '%2,%3'; + $ops42 = '%2,%4'; + } + + print << "EOF"; ;; $ftype fusion pattern generated by gen_logical_addsubf ;; $kind $inner_op -> $outer_name (define_insn "*fuse_${inner_op}_${outer_name}" - [(set (match_operand:${mode} 3 "${pred}" "=&0,&1,&${constraint},${constraint}") - ${outer_exp}) - (clobber (match_scratch:${mode} 4 "=X,X,X,&${constraint}"))] + [(set (match_operand:${mode} 3 "${pred}" "=&0,&1,&${cstr},${cstr}") + ${exp}) + (clobber (match_scratch:${mode} 4 "=X,X,X,&${cstr}"))] "(TARGET_P10_FUSION)" "@ - ${inner_op} %3,%1,%0\\;${outer_op} %3,${outer_32} - ${inner_op} %3,%1,%0\\;${outer_op} %3,${outer_32} - ${inner_op} %3,%1,%0\\;${outer_op} %3,${outer_32} - ${inner_op} %4,%1,%0\\;${outer_op} %3,${outer_42}" + ${inner_op} %3,%1,%0\\;${outer_op} %3,${ops32} + ${inner_op} %3,%1,%0\\;${outer_op} %3,${ops32} + ${inner_op} %3,%1,%0\\;${outer_op} %3,${ops32} + ${inner_op} %4,%1,%0\\;${outer_op} %3,${ops42}" [(set_attr "type" "$fuse_type") (set_attr "cost" "6") (set_attr "length" "8")]) EOF +} - print $insn; +# For the given operator in arg 0, return an array holding the +# information on complementing, inverting, commuting and rtl +# operator name, die if the given operator isn't expected. +sub logical_addsub_get_op_info +{ + my $op = $_[0]; + + # Checking the given OP is valid + my @valid_ops = ( 'and', 'andc', 'eqv', 'nand', 'nor', 'or', 'orc', 'xor', + 'add', 'subf', 'rsubf' ); + die "Unexpected op:$op" unless grep (/^$op$/, @valid_ops); + + my %complement = ( 'and'=> 0, 'andc'=> 1, 'eqv'=> 0, 'nand'=> 3, + 'nor'=> 3, 'or'=> 0, 'orc'=> 1, 'xor'=> 0, + 'add'=> 0, 'subf'=> 0 ); + my %invert = ( 'and'=> 0, 'andc'=> 0, 'eqv'=> 1, 'nand'=> 0, + 'nor'=> 0, 'or'=> 0, 'orc'=> 0, 'xor'=> 0, + 'add'=> 0, 'subf'=> 0 ); + my %commute2 = ( 'and'=> 1, 'andc'=> 0, 'eqv'=> 1, 'nand'=> 0, + 'nor'=> 0, 'or'=> 1, 'orc'=> 0, 'xor'=> 1 ); + my %rtl_ops = ( 'and'=>'and', 'andc'=>'and', 'eqv'=>'xor', 'nand'=>'ior', + 'nor'=>'and', 'or'=>'ior', 'orc'=>'ior', 'xor'=>'xor', + 'add'=>'plus', 'subf'=>'minus' ); + + return ($complement{$op}, $invert{$op}, $commute2{$op}, $rtl_ops{$op}); +} + +# For logical/addsubf fusion type, make up an expression based on +# the below given arguments: +# arg 1: outer operator. +# arg 2: inner operator. +# arg 3: machine mode. +# arg 4: predicate. +# arg 5: constraint. +sub logical_addsubf_make_exp +{ + my ($outer_op, $inner_op, $mode, $pred, $cstr) = @_; + + my $outer_is_rsubf_p = 0; + if ($outer_op eq 'rsubf') { + $outer_op = 'subf'; + $outer_is_rsubf_p = 1; + } + + my ($outer_comp, $outer_invert_p, $outer_comm_p, + $outer_rtl_op) = logical_addsub_get_op_info ($outer_op); + my ($inner_comp, $inner_invert_p, $inner_comm_p, + $inner_rtl_op) = logical_addsub_get_op_info ($inner_op); + + # If both ops commute then we can specify % on operand 1 + # so the pattern will let operands 1 and 2 interchange. + my $bc = ''; + $bc = '%' if ($inner_op eq $outer_op) && $inner_comm_p; + + my $cstr4 = "${cstr},${cstr},${cstr},${cstr}"; + + # Make up arg0 (inner). + my $arg0 = "(match_operand:${mode} 0 \"${pred}\" \"${cstr4}\")"; + $arg0 = "(not:${mode} $arg0)" if ($inner_comp & 1) == 1; + + # Make up arg1 (inner). + my $arg1 = "(match_operand:${mode} 1 \"${pred}\" \"${bc}${cstr4}\")"; + $arg1 = "(not:${mode} $arg1)" if ($inner_comp & 2) == 2; + + # Make up inner_exp. + my $inner_exp = "(${inner_rtl_op}:${mode} ${arg0} + ${arg1})"; + + # Invert inner_exp if needed. + $inner_exp = "(not:${mode} $inner_exp)" if ( $inner_invert_p ); + + # Make up outer arg2. + my $arg2 = "(match_operand:${mode} 2 \"${pred}\" \"${cstr4}\")"; + $arg2 = "(not:${mode} $arg2)" if ($outer_comp & 1) == 1; + + # Complement inner_exp if needed. + $inner_exp = "(not:${mode} $inner_exp)" if ($outer_comp & 2) == 2; + + my $outer_exp; + # Make up outer_exp and special casing rsubf. + if ($outer_is_rsubf_p) { + $outer_exp = "(${outer_rtl_op}:${mode} ${arg2} + ${inner_exp})"; + } else { + $outer_exp = "(${outer_rtl_op}:${mode} ${inner_exp} + ${arg2})"; + } + + # Invert outer_exp if needed. + $outer_exp = "(not:${mode} $outer_exp)" if $outer_invert_p; + + return $outer_exp; +} + +# Generate logical/addsubf fusion type for scalar. +sub gen_logical_addsubf_scalar +{ + my $mode = 'GPR'; + my $pred = 'gpc_reg_operand'; + my $fuse_type = 'fused_arith_logical'; + my $constraint = 'r'; + + my @logicals = ( 'and', 'andc', 'eqv', 'nand', 'nor', 'or', 'orc', 'xor' ); + # logical ops which can fuse with add/subf/rsubf + my @logicals2 = ( 'and', 'nand', 'nor', 'or' ); + my @add_subf = ( 'add', 'subf' ); + + # {logical, add}-logical + foreach my $outer_op ( @logicals ) { + foreach my $inner_op ( @logicals, @add_subf ) { + my $ftype = 'logical-logical'; + if (grep (/^$inner_op$/, @add_subf)) { + next unless grep (/^$outer_op$/, @logicals2); + $ftype = 'add-logical'; } + my $exp = logical_addsubf_make_exp ($outer_op, $inner_op, $mode, + $pred, $constraint); + logical_addsubf_emit_define ($ftype, 'scalar', $outer_op, $inner_op, + $mode, $pred, $constraint, $exp, $fuse_type); + } + } + + my @add_subf_rsubf = ( 'add', 'subf', 'rsubf' ); + + # logical-add + foreach my $outer_op ( @add_subf_rsubf ) { + foreach my $inner_op ( @logicals2 ) { + my $exp = logical_addsubf_make_exp ($outer_op, $inner_op, $mode, + $pred, $constraint); + logical_addsubf_emit_define ('logical-add', 'scalar', $outer_op, + $inner_op, $mode, $pred, $constraint, + $exp, $fuse_type); + } + } +} + +# Generate logical/addsubf fusion type for vector. +sub gen_logical_addsubf_vector +{ + my $mode = "VM"; + my $pred = "altivec_register_operand"; + my $fuse_type = "fused_vector"; + my $constraint = "v"; + + my @logicals = ( 'and', 'andc', 'eqv', 'nand', 'nor', 'or', 'orc', 'xor' ); + + # logical-logical + foreach my $outer_op ( @logicals ) { + foreach my $inner_op ( @logicals ) { + my $exp = logical_addsubf_make_exp ($outer_op, $inner_op, $mode, + $pred, $constraint); + logical_addsubf_emit_define ('logical-logical', 'vector', "v${outer_op}", + "v${inner_op}", $mode, $pred, $constraint, + $exp, $fuse_type); } } } +# Main subroutine to generate logical/addsubf fusion type. +sub gen_logical_addsubf +{ + gen_logical_addsubf_scalar (); + gen_logical_addsubf_vector (); +} + +# Main subroutine to generate add-add fusion type. sub gen_addadd { - my ($kind, $vchr, $op, $type, $mode, $pred, $constraint); + my ($kind, $op, $type, $mode, $pred, $constraint); foreach $kind ('scalar','vector') { if ( $kind eq 'vector' ) { - $vchr = "v"; $op = "vaddudm"; $type = "fused_vector"; $mode = "V2DI"; $pred = "altivec_register_operand"; $constraint = "v"; } else { - $vchr = ""; $op = "add"; $type = "fused_arith_logical"; $mode = "GPR"; @@ -323,9 +439,13 @@ EOF } } -gen_ld_cmpi_p10(); -gen_logical_addsubf(); -gen_addadd; +sub main { + gen_copyright_and_top_comments (); + gen_ld_cmpi_p10 (); + gen_logical_addsubf (); + gen_addadd (); + return 0; +} -exit(0); +exit main ();