genfusion.pl revision 1.1 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