1#!/usr/bin/perl 2# Generate fusion.md 3# 4# Copyright (C) 2020,2021 Free Software Foundation, Inc. 5# 6# This file is part of GCC. 7# 8# GCC is free software; you can redistribute it and/or modify 9# it under the terms of the GNU General Public License as published by 10# the Free Software Foundation; either version 3, or (at your option) 11# any later version. 12# 13# GCC is distributed in the hope that it will be useful, 14# but WITHOUT ANY WARRANTY; without even the implied warranty of 15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16# GNU General Public License for more details. 17# 18# You should have received a copy of the GNU General Public License 19# along with GCC; see the file COPYING3. If not see 20# <http://www.gnu.org/licenses/>. 21 22use warnings; 23use strict; 24 25print <<'EOF'; 26;; Generated automatically by genfusion.pl 27 28;; Copyright (C) 2020,2021 Free Software Foundation, Inc. 29;; 30;; This file is part of GCC. 31;; 32;; GCC is free software; you can redistribute it and/or modify it under 33;; the terms of the GNU General Public License as published by the Free 34;; Software Foundation; either version 3, or (at your option) any later 35;; version. 36;; 37;; GCC is distributed in the hope that it will be useful, but WITHOUT ANY 38;; WARRANTY; without even the implied warranty of MERCHANTABILITY or 39;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 40;; for more details. 41;; 42;; You should have received a copy of the GNU General Public License 43;; along with GCC; see the file COPYING3. If not see 44;; <http://www.gnu.org/licenses/>. 45 46EOF 47 48sub mode_to_ldst_char 49{ 50 my ($mode) = @_; 51 my %x = (DI => 'd', SI => 'w', HI => 'h', QI => 'b'); 52 return $x{$mode} if exists $x{$mode}; 53 return '?'; 54} 55 56sub gen_ld_cmpi_p10 57{ 58 my ($lmode, $ldst, $clobbermode, $result, $cmpl, $echr, $constpred, 59 $mempred, $ccmode, $np, $extend, $resultmode); 60 LMODE: foreach $lmode ('DI','SI','HI','QI') { 61 $ldst = mode_to_ldst_char($lmode); 62 $clobbermode = $lmode; 63 # For clobber, we need a SI/DI reg in case we 64 # split because we have to sign/zero extend. 65 if ($lmode eq 'HI' || $lmode eq 'QI') { $clobbermode = "GPR"; } 66 RESULT: foreach $result ('clobber', $lmode, "EXT".$lmode) { 67 # EXTDI does not exist, and we cannot directly produce HI/QI results. 68 next RESULT if $result eq "EXTDI" || $result eq "HI" || $result eq "QI"; 69 # Don't allow EXTQI because that would allow HI result which we can't do. 70 $result = "GPR" if $result eq "EXTQI"; 71 CCMODE: foreach $ccmode ('CC','CCUNS') { 72 $np = "NON_PREFIXED_D"; 73 $mempred = "non_update_memory_operand"; 74 if ( $ccmode eq 'CC' ) { 75 next CCMODE if $lmode eq 'QI'; 76 if ( $lmode eq 'DI' || $lmode eq 'SI' ) { 77 # ld and lwa are both DS-FORM. 78 $np = "NON_PREFIXED_DS"; 79 $mempred = "ds_form_mem_operand"; 80 } 81 $cmpl = ""; 82 $echr = "a"; 83 $constpred = "const_m1_to_1_operand"; 84 } else { 85 if ( $lmode eq 'DI' ) { 86 # ld is DS-form, but lwz is not. 87 $np = "NON_PREFIXED_DS"; 88 $mempred = "ds_form_mem_operand"; 89 } 90 $cmpl = "l"; 91 $echr = "z"; 92 $constpred = "const_0_to_1_operand"; 93 } 94 if ($lmode eq 'DI') { $echr = ""; } 95 if ($result =~ m/^EXT/ || $result eq 'GPR' || $clobbermode eq 'GPR') { 96 # We always need extension if result > lmode. 97 if ( $ccmode eq 'CC' ) { 98 $extend = "sign"; 99 } else { 100 $extend = "zero"; 101 } 102 } else { 103 # Result of SI/DI does not need sign extension. 104 $extend = "none"; 105 } 106 print ";; load-cmpi fusion pattern generated by gen_ld_cmpi_p10\n"; 107 print ";; load mode is $lmode result mode is $result compare mode is $ccmode extend is $extend\n"; 108 109 print "(define_insn_and_split \"*l${ldst}${echr}_cmp${cmpl}di_cr0_${lmode}_${result}_${ccmode}_${extend}\"\n"; 110 print " [(set (match_operand:${ccmode} 2 \"cc_reg_operand\" \"=x\")\n"; 111 print " (compare:${ccmode} (match_operand:${lmode} 1 \"${mempred}\" \"m\")\n"; 112 if ($ccmode eq 'CCUNS') { print " "; } 113 print " (match_operand:${lmode} 3 \"${constpred}\" \"n\")))\n"; 114 if ($result eq 'clobber') { 115 print " (clobber (match_scratch:${clobbermode} 0 \"=r\"))]\n"; 116 } elsif ($result eq $lmode) { 117 print " (set (match_operand:${result} 0 \"gpc_reg_operand\" \"=r\") (match_dup 1))]\n"; 118 } else { 119 print " (set (match_operand:${result} 0 \"gpc_reg_operand\" \"=r\") (${extend}_extend:${result} (match_dup 1)))]\n"; 120 } 121 print " \"(TARGET_P10_FUSION && TARGET_P10_FUSION_LD_CMPI)\"\n"; 122 print " \"l${ldst}${echr}%X1 %0,%1\\;cmp${cmpl}di %2,%0,%3\"\n"; 123 print " \"&& reload_completed\n"; 124 print " && (cc_reg_not_cr0_operand (operands[2], CCmode)\n"; 125 print " || !address_is_non_pfx_d_or_x (XEXP (operands[1], 0),\n"; 126 print " ${lmode}mode, ${np}))\"\n"; 127 128 if ($extend eq "none") { 129 print " [(set (match_dup 0) (match_dup 1))\n"; 130 } else { 131 $resultmode = $result; 132 if ( $result eq 'clobber' ) { $resultmode = $clobbermode } 133 print " [(set (match_dup 0) (${extend}_extend:${resultmode} (match_dup 1)))\n"; 134 } 135 print " (set (match_dup 2)\n"; 136 print " (compare:${ccmode} (match_dup 0) (match_dup 3)))]\n"; 137 print " \"\"\n"; 138 print " [(set_attr \"type\" \"fused_load_cmpi\")\n"; 139 print " (set_attr \"cost\" \"8\")\n"; 140 print " (set_attr \"length\" \"8\")])\n"; 141 print "\n"; 142 } 143 } 144 } 145} 146 147sub gen_logical_addsubf 148{ 149 my @logicals = ( "and", "andc", "eqv", "nand", "nor", "or", "orc", "xor" ); 150 my %logicals_addsub = ( "and"=>1, "nand"=>1, "nor"=>1, "or"=>1 ); 151 my @addsub = ( "add", "subf" ); 152 my %isaddsub = ( "add"=>1, "subf"=>1 ); 153 my %complement = ( "and"=> 0, "andc"=> 1, "eqv"=> 0, "nand"=> 3, 154 "nor"=> 3, "or"=> 0, "orc"=> 1, "xor"=> 0, 155 "add"=> 0, "subf"=> 0 ); 156 my %invert = ( "and"=> 0, "andc"=> 0, "eqv"=> 1, "nand"=> 0, 157 "nor"=> 0, "or"=> 0, "orc"=> 0, "xor"=> 0, 158 "add"=> 0, "subf"=> 0 ); 159 my %commute2 = ( "and"=> 1, "andc"=> 0, "eqv"=> 1, "nand"=> 0, 160 "nor"=> 0, "or"=> 1, "orc"=> 0, "xor"=> 1 ); 161 my %rtlop = ( "and"=>"and", "andc"=>"and", "eqv"=>"xor", "nand"=>"ior", 162 "nor"=>"and", "or"=>"ior", "orc"=>"ior", "xor"=>"xor", 163 "add"=>"plus", "subf"=>"minus" ); 164 165 my ($kind, $vchr, $mode, $pred, $constraint, $cr, $outer, @outer_ops, 166 $outer_op, $outer_comp, $outer_inv, $outer_rtl, $inner, @inner_ops, 167 $inner_comp, $inner_inv, $inner_rtl, $inner_op, $both_commute, $c4, 168 $bc, $inner_arg0, $inner_arg1, $inner_exp, $outer_arg2, $outer_exp, 169 $target_flag, $ftype, $insn, $is_subf, $is_rsubf, $outer_32, $outer_42, 170 $outer_name, $fuse_type); 171 KIND: foreach $kind ('scalar','vector') { 172 @outer_ops = @logicals; 173 if ( $kind eq 'vector' ) { 174 $vchr = "v"; 175 $mode = "VM"; 176 $pred = "altivec_register_operand"; 177 $constraint = "v"; 178 $fuse_type = "fused_vector"; 179 } else { 180 $vchr = ""; 181 $mode = "GPR"; 182 $pred = "gpc_reg_operand"; 183 $constraint = "r"; 184 $fuse_type = "fused_arith_logical"; 185 push (@outer_ops, @addsub); 186 push (@outer_ops, ( "rsubf" )); 187 } 188 $c4 = "${constraint},${constraint},${constraint},${constraint}"; 189 OUTER: foreach $outer ( @outer_ops ) { 190 $outer_name = "${vchr}${outer}"; 191 $is_subf = ( $outer eq "subf" ); 192 $is_rsubf = ( $outer eq "rsubf" ); 193 if ( $is_rsubf ) { 194 $outer = "subf"; 195 } 196 $outer_op = "${vchr}${outer}"; 197 $outer_comp = $complement{$outer}; 198 $outer_inv = $invert{$outer}; 199 $outer_rtl = $rtlop{$outer}; 200 @inner_ops = @logicals; 201 $ftype = "logical-logical"; 202 $target_flag = "TARGET_P10_FUSION_2LOGICAL"; 203 if ( exists $isaddsub{$outer} ) { 204 @inner_ops = sort keys %logicals_addsub; 205 $ftype = "logical-add"; 206 $target_flag = "TARGET_P10_FUSION_LOGADD"; 207 } elsif ( $kind ne 'vector' && exists $logicals_addsub{$outer} ) { 208 push (@inner_ops, @addsub); 209 } 210 INNER: foreach $inner ( @inner_ops ) { 211 if ( exists $isaddsub{$inner} ) { 212 $ftype = "add-logical"; 213 $target_flag = "TARGET_P10_FUSION_ADDLOG"; 214 } 215 $inner_comp = $complement{$inner}; 216 $inner_inv = $invert{$inner}; 217 $inner_rtl = $rtlop{$inner}; 218 $inner_op = "${vchr}${inner}"; 219 # If both ops commute then we can specify % on operand 1 220 # so the pattern will let operands 1 and 2 interchange. 221 $both_commute = ($inner eq $outer) && ($commute2{$inner} == 1); 222 $bc = ""; if ( $both_commute ) { $bc = "%"; } 223 $inner_arg0 = "(match_operand:${mode} 0 \"${pred}\" \"${c4}\")"; 224 $inner_arg1 = "(match_operand:${mode} 1 \"${pred}\" \"${bc}${c4}\")"; 225 if ( ($inner_comp & 1) == 1 ) { 226 $inner_arg0 = "(not:${mode} $inner_arg0)"; 227 } 228 if ( ($inner_comp & 2) == 2 ) { 229 $inner_arg1 = "(not:${mode} $inner_arg1)"; 230 } 231 $inner_exp = "(${inner_rtl}:${mode} ${inner_arg0} 232 ${inner_arg1})"; 233 if ( $inner_inv == 1 ) { 234 $inner_exp = "(not:${mode} $inner_exp)"; 235 } 236 $outer_arg2 = "(match_operand:${mode} 2 \"${pred}\" \"${c4}\")"; 237 if ( ($outer_comp & 1) == 1 ) { 238 $outer_arg2 = "(not:${mode} $outer_arg2)"; 239 } 240 if ( ($outer_comp & 2) == 2 ) { 241 $inner_exp = "(not:${mode} $inner_exp)"; 242 } 243 if ( $is_subf ) { 244 $outer_32 = "%2,%3"; 245 $outer_42 = "%2,%4"; 246 } else { 247 $outer_32 = "%3,%2"; 248 $outer_42 = "%4,%2"; 249 } 250 if ( $is_rsubf == 1 ) { 251 $outer_exp = "(${outer_rtl}:${mode} ${outer_arg2} 252 ${inner_exp})"; 253 } else { 254 $outer_exp = "(${outer_rtl}:${mode} ${inner_exp} 255 ${outer_arg2})"; 256 } 257 if ( $outer_inv == 1 ) { 258 $outer_exp = "(not:${mode} $outer_exp)"; 259 } 260 261 $insn = <<"EOF"; 262 263;; $ftype fusion pattern generated by gen_logical_addsubf 264;; $kind $inner_op -> $outer_name 265(define_insn "*fuse_${inner_op}_${outer_name}" 266 [(set (match_operand:${mode} 3 "${pred}" "=&0,&1,&${constraint},${constraint}") 267 ${outer_exp}) 268 (clobber (match_scratch:${mode} 4 "=X,X,X,&r"))] 269 "(TARGET_P10_FUSION && $target_flag)" 270 "@ 271 ${inner_op} %3,%1,%0\\;${outer_op} %3,${outer_32} 272 ${inner_op} %3,%1,%0\\;${outer_op} %3,${outer_32} 273 ${inner_op} %3,%1,%0\\;${outer_op} %3,${outer_32} 274 ${inner_op} %4,%1,%0\\;${outer_op} %3,${outer_42}" 275 [(set_attr "type" "$fuse_type") 276 (set_attr "cost" "6") 277 (set_attr "length" "8")]) 278EOF 279 280 print $insn; 281 } 282 } 283 } 284} 285 286sub gen_addadd 287{ 288 my ($kind, $vchr, $op, $type, $mode, $pred, $constraint); 289 foreach $kind ('scalar','vector') { 290 if ( $kind eq 'vector' ) { 291 $vchr = "v"; 292 $op = "vaddudm"; 293 $type = "fused_vector"; 294 $mode = "V2DI"; 295 $pred = "altivec_register_operand"; 296 $constraint = "v"; 297 } else { 298 $vchr = ""; 299 $op = "add"; 300 $type = "fused_arith_logical"; 301 $mode = "GPR"; 302 $pred = "gpc_reg_operand"; 303 $constraint = "r"; 304 } 305 my $c4 = "${constraint},${constraint},${constraint},${constraint}"; 306 print <<"EOF"; 307 308;; ${op}-${op} fusion pattern generated by gen_addadd 309(define_insn "*fuse_${op}_${op}" 310 [(set (match_operand:${mode} 3 "${pred}" "=&0,&1,&${constraint},${constraint}") 311 (plus:${mode} 312 (plus:${mode} (match_operand:${mode} 0 "${pred}" "${c4}") 313 (match_operand:${mode} 1 "${pred}" "%${c4}")) 314 (match_operand:${mode} 2 "${pred}" "${c4}"))) 315 (clobber (match_scratch:${mode} 4 "=X,X,X,&${constraint}"))] 316 "(TARGET_P10_FUSION && TARGET_P10_FUSION_2ADD)" 317 "@ 318 ${op} %3,%1,%0\\;${op} %3,%3,%2 319 ${op} %3,%1,%0\\;${op} %3,%3,%2 320 ${op} %3,%1,%0\\;${op} %3,%3,%2 321 ${op} %4,%1,%0\\;${op} %3,%4,%2" 322 [(set_attr "type" "${type}") 323 (set_attr "cost" "6") 324 (set_attr "length" "8")]) 325EOF 326 } 327} 328 329gen_ld_cmpi_p10(); 330gen_logical_addsubf(); 331gen_addadd; 332 333exit(0); 334 335