]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/rs6000/genfusion.pl
Update copyright years.
[thirdparty/gcc.git] / gcc / config / rs6000 / genfusion.pl
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
22 use warnings;
23 use strict;
24
25 print <<'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
46 EOF
47
48 sub 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
56 sub 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
147 sub 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,&${constraint}"))]
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")])
278 EOF
279
280 print $insn;
281 }
282 }
283 }
284 }
285
286 sub 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")])
325 EOF
326 }
327 }
328
329 gen_ld_cmpi_p10();
330 gen_logical_addsubf();
331 gen_addadd;
332
333 exit(0);
334