1#!/usr/bin/perl 2# Generate fusion.md 3# 4# Copyright (C) 2020-2022 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-2022 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_one 57{ 58 my ($lmode, $result, $ccmode) = @_; 59 60 my $np = "NON_PREFIXED_D"; 61 my $mempred = "non_update_memory_operand"; 62 my $extend; 63 64 # We need to special case lwa. The prefixed_load_p function in rs6000.cc 65 # (which determines if a load instruction is prefixed) uses the fact that the 66 # register mode is different from the memory mode, and that the sign_extend 67 # attribute is set to use DS-form rules for the address instead of D-form. 68 # If the register size is the same, prefixed_load_p assumes we are doing a 69 # lwz. We change to use an lwz and word compare if we don't need to sign 70 # extend the SImode value. Otherwise if we need the value, we need to 71 # make sure the insn is marked as ds-form. 72 my $cmp_size_char = ($lmode eq "SI" 73 && $ccmode eq "CC" 74 && $result !~ /^EXT|^DI$/) ? "w" : "d"; 75 76 if ($ccmode eq "CC") { 77 # ld and lwa are both DS-FORM. 78 ($lmode eq "DI") and $np = "NON_PREFIXED_DS"; 79 ($lmode eq "SI" && $cmp_size_char eq "d") and $np = "NON_PREFIXED_DS"; 80 } else { 81 if ($lmode eq "DI") { 82 # ld is DS-form, but lwz is not. 83 $np = "NON_PREFIXED_DS"; 84 } 85 } 86 87 my $cmpl = ($ccmode eq "CC") ? "" : "l"; 88 my $echr = ($ccmode eq "CC" && $cmp_size_char eq "d") ? "a" : "z"; 89 if ($lmode eq "DI") { $echr = ""; } 90 my $constpred = ($ccmode eq "CC") ? "const_m1_to_1_operand" 91 : "const_0_to_1_operand"; 92 93 # For clobber, we need a SI/DI reg in case we 94 # split because we have to sign/zero extend. 95 my $clobbermode = ($lmode =~ /^[QH]I$/) ? "GPR" : $lmode; 96 if ($result =~ /^EXT/ || $result eq "GPR" || $clobbermode eq "GPR") { 97 # We always need extension if result > lmode. 98 $extend = ($ccmode eq "CC") ? "sign" : "zero"; 99 } else { 100 # Result of SI/DI does not need sign extension. 101 $extend = "none"; 102 } 103 104 my $ldst = mode_to_ldst_char($lmode); 105 106 # DS-form addresses need YZ, and not m. 107 my $constraint = ($np eq "NON_PREFIXED_DS") ? "YZ" : "m"; 108 print <<HERE; 109;; load-cmpi fusion pattern generated by gen_ld_cmpi_p10 110;; load mode is $lmode result mode is $result compare mode is $ccmode extend is $extend 111(define_insn_and_split "*l${ldst}${echr}_cmp${cmpl}${cmp_size_char}i_cr0_${lmode}_${result}_${ccmode}_${extend}" 112 [(set (match_operand:${ccmode} 2 "cc_reg_operand" "=x") 113 (compare:${ccmode} (match_operand:${lmode} 1 "${mempred}" "${constraint}") 114HERE 115 print " " if $ccmode eq "CCUNS"; 116print <<HERE; 117 (match_operand:${lmode} 3 "${constpred}" "n"))) 118HERE 119 120 if ($result eq "clobber") { 121 print <<HERE; 122 (clobber (match_scratch:${clobbermode} 0 "=r"))] 123HERE 124 } elsif ($result eq $lmode) { 125 print <<HERE; 126 (set (match_operand:${result} 0 "gpc_reg_operand" "=r") (match_dup 1))] 127HERE 128 } else { 129 print <<HERE; 130 (set (match_operand:${result} 0 "gpc_reg_operand" "=r") (${extend}_extend:${result} (match_dup 1)))] 131HERE 132 } 133 134 print <<HERE; 135 "(TARGET_P10_FUSION)" 136 "l${ldst}${echr}%X1 %0,%1\\;cmp${cmpl}${cmp_size_char}i %2,%0,%3" 137 "&& reload_completed 138 && (cc_reg_not_cr0_operand (operands[2], CCmode) 139 || !address_is_non_pfx_d_or_x (XEXP (operands[1], 0), 140 ${lmode}mode, ${np}))" 141HERE 142 143 if ($extend eq "none") { 144 print " [(set (match_dup 0) (match_dup 1))\n"; 145 } elsif ($result eq "clobber") { 146 print " [(set (match_dup 0) (${extend}_extend:${clobbermode} (match_dup 1)))\n"; 147 } else { 148 print " [(set (match_dup 0) (${extend}_extend:${result} (match_dup 1)))\n"; 149 } 150 151 print <<HERE; 152 (set (match_dup 2) 153 (compare:${ccmode} (match_dup 0) (match_dup 3)))] 154 "" 155 [(set_attr "type" "fused_load_cmpi") 156 (set_attr "cost" "8") 157HERE 158 159 if ($lmode eq "SI" && $ccmode eq "CC" && $cmp_size_char eq "d") { 160 # prefixed_load_p needs the sign_extend attribute to validate lwa as a 161 # DS-form instruction instead of D-form. 162 print " (set_attr \"sign_extend\" \"yes\")\n"; 163 } 164 165 print <<HERE 166 (set_attr "length" "8")]) 167 168HERE 169} 170 171sub gen_ld_cmpi_p10 172{ 173 foreach my $lmode (qw/DI SI HI QI/) { 174 foreach my $result ("clobber", $lmode, "EXT$lmode") { 175 # EXTDI does not exist, and we cannot directly produce HI/QI results. 176 next if $result =~ /^(QI|HI|EXTDI)$/; 177 178 # Don't allow EXTQI because that would allow HI result which we can't do. 179 $result = "GPR" if $result eq "EXTQI"; 180 181 foreach my $ccmode (qw/CC CCUNS/) { 182 # We do not have signed single-byte loads. 183 next if ($lmode eq "QI" and $ccmode eq "CC"); 184 185 gen_ld_cmpi_p10_one($lmode, $result, $ccmode); 186 } 187 } 188 } 189} 190 191sub gen_logical_addsubf 192{ 193 my @logicals = ( "and", "andc", "eqv", "nand", "nor", "or", "orc", "xor" ); 194 my %logicals_addsub = ( "and"=>1, "nand"=>1, "nor"=>1, "or"=>1 ); 195 my @addsub = ( "add", "subf" ); 196 my %isaddsub = ( "add"=>1, "subf"=>1 ); 197 my %complement = ( "and"=> 0, "andc"=> 1, "eqv"=> 0, "nand"=> 3, 198 "nor"=> 3, "or"=> 0, "orc"=> 1, "xor"=> 0, 199 "add"=> 0, "subf"=> 0 ); 200 my %invert = ( "and"=> 0, "andc"=> 0, "eqv"=> 1, "nand"=> 0, 201 "nor"=> 0, "or"=> 0, "orc"=> 0, "xor"=> 0, 202 "add"=> 0, "subf"=> 0 ); 203 my %commute2 = ( "and"=> 1, "andc"=> 0, "eqv"=> 1, "nand"=> 0, 204 "nor"=> 0, "or"=> 1, "orc"=> 0, "xor"=> 1 ); 205 my %rtlop = ( "and"=>"and", "andc"=>"and", "eqv"=>"xor", "nand"=>"ior", 206 "nor"=>"and", "or"=>"ior", "orc"=>"ior", "xor"=>"xor", 207 "add"=>"plus", "subf"=>"minus" ); 208 209 my ($kind, $vchr, $mode, $pred, $constraint, $cr, $outer, @outer_ops, 210 $outer_op, $outer_comp, $outer_inv, $outer_rtl, $inner, @inner_ops, 211 $inner_comp, $inner_inv, $inner_rtl, $inner_op, $both_commute, $c4, 212 $bc, $inner_arg0, $inner_arg1, $inner_exp, $outer_arg2, $outer_exp, 213 $ftype, $insn, $is_subf, $is_rsubf, $outer_32, $outer_42,$outer_name, 214 $fuse_type); 215 KIND: foreach $kind ('scalar','vector') { 216 @outer_ops = @logicals; 217 if ( $kind eq 'vector' ) { 218 $vchr = "v"; 219 $mode = "VM"; 220 $pred = "altivec_register_operand"; 221 $constraint = "v"; 222 $fuse_type = "fused_vector"; 223 } else { 224 $vchr = ""; 225 $mode = "GPR"; 226 $pred = "gpc_reg_operand"; 227 $constraint = "r"; 228 $fuse_type = "fused_arith_logical"; 229 push (@outer_ops, @addsub); 230 push (@outer_ops, ( "rsubf" )); 231 } 232 $c4 = "${constraint},${constraint},${constraint},${constraint}"; 233 OUTER: foreach $outer ( @outer_ops ) { 234 $outer_name = "${vchr}${outer}"; 235 $is_subf = ( $outer eq "subf" ); 236 $is_rsubf = ( $outer eq "rsubf" ); 237 if ( $is_rsubf ) { 238 $outer = "subf"; 239 } 240 $outer_op = "${vchr}${outer}"; 241 $outer_comp = $complement{$outer}; 242 $outer_inv = $invert{$outer}; 243 $outer_rtl = $rtlop{$outer}; 244 @inner_ops = @logicals; 245 $ftype = "logical-logical"; 246 if ( exists $isaddsub{$outer} ) { 247 @inner_ops = sort keys %logicals_addsub; 248 $ftype = "logical-add"; 249 } elsif ( $kind ne 'vector' && exists $logicals_addsub{$outer} ) { 250 push (@inner_ops, @addsub); 251 } 252 INNER: foreach $inner ( @inner_ops ) { 253 if ( exists $isaddsub{$inner} ) { 254 $ftype = "add-logical"; 255 } 256 $inner_comp = $complement{$inner}; 257 $inner_inv = $invert{$inner}; 258 $inner_rtl = $rtlop{$inner}; 259 $inner_op = "${vchr}${inner}"; 260 # If both ops commute then we can specify % on operand 1 261 # so the pattern will let operands 1 and 2 interchange. 262 $both_commute = ($inner eq $outer) && ($commute2{$inner} == 1); 263 $bc = ""; if ( $both_commute ) { $bc = "%"; } 264 $inner_arg0 = "(match_operand:${mode} 0 \"${pred}\" \"${c4}\")"; 265 $inner_arg1 = "(match_operand:${mode} 1 \"${pred}\" \"${bc}${c4}\")"; 266 if ( ($inner_comp & 1) == 1 ) { 267 $inner_arg0 = "(not:${mode} $inner_arg0)"; 268 } 269 if ( ($inner_comp & 2) == 2 ) { 270 $inner_arg1 = "(not:${mode} $inner_arg1)"; 271 } 272 $inner_exp = "(${inner_rtl}:${mode} ${inner_arg0} 273 ${inner_arg1})"; 274 if ( $inner_inv == 1 ) { 275 $inner_exp = "(not:${mode} $inner_exp)"; 276 } 277 $outer_arg2 = "(match_operand:${mode} 2 \"${pred}\" \"${c4}\")"; 278 if ( ($outer_comp & 1) == 1 ) { 279 $outer_arg2 = "(not:${mode} $outer_arg2)"; 280 } 281 if ( ($outer_comp & 2) == 2 ) { 282 $inner_exp = "(not:${mode} $inner_exp)"; 283 } 284 if ( $is_subf ) { 285 $outer_32 = "%2,%3"; 286 $outer_42 = "%2,%4"; 287 } else { 288 $outer_32 = "%3,%2"; 289 $outer_42 = "%4,%2"; 290 } 291 if ( $is_rsubf == 1 ) { 292 $outer_exp = "(${outer_rtl}:${mode} ${outer_arg2} 293 ${inner_exp})"; 294 } else { 295 $outer_exp = "(${outer_rtl}:${mode} ${inner_exp} 296 ${outer_arg2})"; 297 } 298 if ( $outer_inv == 1 ) { 299 $outer_exp = "(not:${mode} $outer_exp)"; 300 } 301 302 $insn = <<"EOF"; 303 304;; $ftype fusion pattern generated by gen_logical_addsubf 305;; $kind $inner_op -> $outer_name 306(define_insn "*fuse_${inner_op}_${outer_name}" 307 [(set (match_operand:${mode} 3 "${pred}" "=&0,&1,&${constraint},${constraint}") 308 ${outer_exp}) 309 (clobber (match_scratch:${mode} 4 "=X,X,X,&${constraint}"))] 310 "(TARGET_P10_FUSION)" 311 "@ 312 ${inner_op} %3,%1,%0\\;${outer_op} %3,${outer_32} 313 ${inner_op} %3,%1,%0\\;${outer_op} %3,${outer_32} 314 ${inner_op} %3,%1,%0\\;${outer_op} %3,${outer_32} 315 ${inner_op} %4,%1,%0\\;${outer_op} %3,${outer_42}" 316 [(set_attr "type" "$fuse_type") 317 (set_attr "cost" "6") 318 (set_attr "length" "8")]) 319EOF 320 321 print $insn; 322 } 323 } 324 } 325} 326 327sub gen_addadd 328{ 329 my ($kind, $vchr, $op, $type, $mode, $pred, $constraint); 330 foreach $kind ('scalar','vector') { 331 if ( $kind eq 'vector' ) { 332 $vchr = "v"; 333 $op = "vaddudm"; 334 $type = "fused_vector"; 335 $mode = "V2DI"; 336 $pred = "altivec_register_operand"; 337 $constraint = "v"; 338 } else { 339 $vchr = ""; 340 $op = "add"; 341 $type = "fused_arith_logical"; 342 $mode = "GPR"; 343 $pred = "gpc_reg_operand"; 344 $constraint = "r"; 345 } 346 my $c4 = "${constraint},${constraint},${constraint},${constraint}"; 347 print <<"EOF"; 348 349;; ${op}-${op} fusion pattern generated by gen_addadd 350(define_insn "*fuse_${op}_${op}" 351 [(set (match_operand:${mode} 3 "${pred}" "=&0,&1,&${constraint},${constraint}") 352 (plus:${mode} 353 (plus:${mode} (match_operand:${mode} 0 "${pred}" "${c4}") 354 (match_operand:${mode} 1 "${pred}" "%${c4}")) 355 (match_operand:${mode} 2 "${pred}" "${c4}"))) 356 (clobber (match_scratch:${mode} 4 "=X,X,X,&${constraint}"))] 357 "(TARGET_P10_FUSION)" 358 "@ 359 ${op} %3,%1,%0\\;${op} %3,%3,%2 360 ${op} %3,%1,%0\\;${op} %3,%3,%2 361 ${op} %3,%1,%0\\;${op} %3,%3,%2 362 ${op} %4,%1,%0\\;${op} %3,%4,%2" 363 [(set_attr "type" "${type}") 364 (set_attr "cost" "6") 365 (set_attr "length" "8")]) 366EOF 367 } 368} 369 370gen_ld_cmpi_p10(); 371gen_logical_addsubf(); 372gen_addadd; 373 374exit(0); 375 376