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