@@ -22,7 +22,9 @@
use warnings;
use strict;
-print <<'EOF';
+sub gen_copyright_and_top_comments
+{
+ print << "EOF";
;; Generated automatically by genfusion.pl
;; Copyright (C) 2020-2023 Free Software Foundation, Inc.
@@ -44,255 +46,369 @@ print <<'EOF';
;; <http://www.gnu.org/licenses/>.
EOF
+}
+# Map any mode of DI/SI/HI/QI to single char d/w/h/b,
+# die if the given mode in arg 0 isn't expected.
sub mode_to_ldst_char
{
- my ($mode) = @_;
- my %x = (DI => 'd', SI => 'w', HI => 'h', QI => 'b');
- return $x{$mode} if exists $x{$mode};
- return '?';
+ my $mode = $_[0];
+ die "Unexpected mode: $mode" unless $mode =~ /[QHSD]I/;
+ my %map = (DI => 'd', SI => 'w', HI => 'h', QI => 'b');
+ return $map{$mode};
}
-sub gen_ld_cmpi_p10
+# Emit define_insn_and_split for load-cmpi fusion type based
+# on the below given arguments:
+# arg 0: mode of load.
+# arg 1: mode of result.
+# arg 2: mode of comparison.
+# arg 3: extension type.
+sub ld_cmpi_p10_emit_define
{
- my ($lmode, $ldst, $clobbermode, $result, $cmpl, $echr, $constpred,
- $mempred, $ccmode, $np, $extend, $resultmode);
- LMODE: foreach $lmode ('DI','SI','HI','QI') {
- $ldst = mode_to_ldst_char($lmode);
- $clobbermode = $lmode;
- # For clobber, we need a SI/DI reg in case we
- # split because we have to sign/zero extend.
- if ($lmode eq 'HI' || $lmode eq 'QI') { $clobbermode = "GPR"; }
- RESULT: foreach $result ('clobber', $lmode, "EXT".$lmode) {
- # EXTDI does not exist, and we cannot directly produce HI/QI results.
- next RESULT if $result eq "EXTDI" || $result eq "HI" || $result eq "QI";
- # Don't allow EXTQI because that would allow HI result which we can't do.
- $result = "GPR" if $result eq "EXTQI";
- CCMODE: foreach $ccmode ('CC','CCUNS') {
- $np = "NON_PREFIXED_D";
- $mempred = "non_update_memory_operand";
- if ( $ccmode eq 'CC' ) {
- next CCMODE if $lmode eq 'QI';
- if ( $lmode eq 'DI' || $lmode eq 'SI' ) {
- # ld and lwa are both DS-FORM.
- $np = "NON_PREFIXED_DS";
- $mempred = "ds_form_mem_operand";
- }
- $cmpl = "";
- $echr = "a";
- $constpred = "const_m1_to_1_operand";
- } else {
- if ( $lmode eq 'DI' ) {
- # ld is DS-form, but lwz is not.
- $np = "NON_PREFIXED_DS";
- $mempred = "ds_form_mem_operand";
- }
- $cmpl = "l";
- $echr = "z";
- $constpred = "const_0_to_1_operand";
- }
- if ($lmode eq 'DI') { $echr = ""; }
- if ($result =~ m/^EXT/ || $result eq 'GPR' || $clobbermode eq 'GPR') {
- # We always need extension if result > lmode.
- if ( $ccmode eq 'CC' ) {
- $extend = "sign";
- } else {
- $extend = "zero";
- }
- } else {
- # Result of SI/DI does not need sign extension.
- $extend = "none";
- }
- print ";; load-cmpi fusion pattern generated by gen_ld_cmpi_p10\n";
- print ";; load mode is $lmode result mode is $result compare mode is $ccmode extend is $extend\n";
-
- print "(define_insn_and_split \"*l${ldst}${echr}_cmp${cmpl}di_cr0_${lmode}_${result}_${ccmode}_${extend}\"\n";
- print " [(set (match_operand:${ccmode} 2 \"cc_reg_operand\" \"=x\")\n";
- print " (compare:${ccmode} (match_operand:${lmode} 1 \"${mempred}\" \"m\")\n";
- if ($ccmode eq 'CCUNS') { print " "; }
- print " (match_operand:${lmode} 3 \"${constpred}\" \"n\")))\n";
- if ($result eq 'clobber') {
- print " (clobber (match_scratch:${clobbermode} 0 \"=r\"))]\n";
- } elsif ($result eq $lmode) {
- print " (set (match_operand:${result} 0 \"gpc_reg_operand\" \"=r\") (match_dup 1))]\n";
- } else {
- print " (set (match_operand:${result} 0 \"gpc_reg_operand\" \"=r\") (${extend}_extend:${result} (match_dup 1)))]\n";
- }
- print " \"(TARGET_P10_FUSION)\"\n";
- print " \"l${ldst}${echr}%X1 %0,%1\\;cmp${cmpl}di %2,%0,%3\"\n";
- print " \"&& reload_completed\n";
- print " && (cc_reg_not_cr0_operand (operands[2], CCmode)\n";
- print " || !address_is_non_pfx_d_or_x (XEXP (operands[1], 0),\n";
- print " ${lmode}mode, ${np}))\"\n";
-
- if ($extend eq "none") {
- print " [(set (match_dup 0) (match_dup 1))\n";
- } else {
- $resultmode = $result;
- if ( $result eq 'clobber' ) { $resultmode = $clobbermode }
- print " [(set (match_dup 0) (${extend}_extend:${resultmode} (match_dup 1)))\n";
- }
- print " (set (match_dup 2)\n";
- print " (compare:${ccmode} (match_dup 0) (match_dup 3)))]\n";
- print " \"\"\n";
- print " [(set_attr \"type\" \"fused_load_cmpi\")\n";
- print " (set_attr \"cost\" \"8\")\n";
- print " (set_attr \"length\" \"8\")])\n";
- print "\n";
- }
- }
+ my $lmode = $_[0];
+ my $result = $_[1];
+ my $ccmode = $_[2];
+ my $extend = $_[3];
+
+ # For clobber, we need a SI/DI reg in case we
+ # split because we have to sign/zero extend.
+ my $clobbermode = ($lmode eq 'HI' || $lmode eq 'QI') ? 'GPR' : $lmode;
+
+ my $np = 'NON_PREFIXED_D';
+ my $mempred = 'non_update_memory_operand';
+
+ # ld and lwa are both DS-FORM.
+ if ( $lmode eq 'DI'
+ || ($lmode eq 'SI' && $ccmode eq 'CC') ) {
+ $np = 'NON_PREFIXED_DS';
+ $mempred = 'ds_form_mem_operand';
+ }
+
+ my $cmpl = '';
+ my $echr = 'a';
+ my $constpred = 'const_m1_to_1_operand';
+
+ # Logical comparison has 'l', zero extended load has 'z'.
+ if ($ccmode eq 'CCUNS') {
+ $cmpl = 'l';
+ $echr = 'z';
+ $constpred = 'const_0_to_1_operand';
}
+
+ # DI load doesn't have suffix for zero or sign.
+ $echr = '' if $lmode eq 'DI';
+
+ my $ldst = mode_to_ldst_char ($lmode);
+
+ # define_insn_and_split comments.
+ print ";; load-cmpi fusion pattern generated by gen_ld_cmpi_p10\n";
+ print ";; load mode is $lmode result mode is $result compare mode is $ccmode extend is $extend\n";
+
+ # main set pattern.
+ print "(define_insn_and_split \"*l${ldst}${echr}_cmp${cmpl}di_cr0_${lmode}_${result}_${ccmode}_${extend}\"\n";
+ print " [(set (match_operand:${ccmode} 2 \"cc_reg_operand\" \"=x\")\n";
+ print " (compare:${ccmode} (match_operand:${lmode} 1 \"${mempred}\" \"m\")\n";
+ print " " if ($ccmode eq 'CCUNS');
+ print " (match_operand:${lmode} 3 \"${constpred}\" \"n\")))\n";
+
+ # clobber or another set pattern.
+ if ($result eq 'clobber') {
+ print " (clobber (match_scratch:${clobbermode} 0 \"=r\"))]\n";
+ } elsif ($result eq $lmode) {
+ print " (set (match_operand:${result} 0 \"gpc_reg_operand\" \"=r\") (match_dup 1))]\n";
+ } else {
+ print " (set (match_operand:${result} 0 \"gpc_reg_operand\" \"=r\") (${extend}_extend:${result} (match_dup 1)))]\n";
+ }
+
+ # insn condition and output template.
+ print " \"(TARGET_P10_FUSION)\"\n";
+ print " \"l${ldst}${echr}%X1 %0,%1\\;cmp${cmpl}di %2,%0,%3\"\n";
+
+ # split condition.
+ print " \"&& reload_completed\n";
+ print " && (cc_reg_not_cr0_operand (operands[2], CCmode)\n";
+ print " || !address_is_non_pfx_d_or_x (XEXP (operands[1], 0),\n";
+ print " ${lmode}mode, ${np}))\"\n";
+
+ # new insn patterns.
+ if ($extend eq 'none') {
+ print " [(set (match_dup 0) (match_dup 1))\n";
+ } else {
+ my $resultmode = ( $result eq 'clobber' ) ? $clobbermode : $result;
+ print " [(set (match_dup 0) (${extend}_extend:${resultmode} (match_dup 1)))\n";
+ }
+ print " (set (match_dup 2)\n";
+ print " (compare:${ccmode} (match_dup 0) (match_dup 3)))]\n";
+ print " \"\"\n";
+
+ # insn attributes.
+ print " [(set_attr \"type\" \"fused_load_cmpi\")\n";
+ print " (set_attr \"cost\" \"8\")\n";
+ print " (set_attr \"length\" \"8\")])\n";
+ print "\n";
}
-sub gen_logical_addsubf
+# Main subroutine to generate load-cmpi fusion type.
+sub gen_ld_cmpi_p10
{
- my @logicals = ( "and", "andc", "eqv", "nand", "nor", "or", "orc", "xor" );
- my %logicals_addsub = ( "and"=>1, "nand"=>1, "nor"=>1, "or"=>1 );
- my @addsub = ( "add", "subf" );
- my %isaddsub = ( "add"=>1, "subf"=>1 );
- my %complement = ( "and"=> 0, "andc"=> 1, "eqv"=> 0, "nand"=> 3,
- "nor"=> 3, "or"=> 0, "orc"=> 1, "xor"=> 0,
- "add"=> 0, "subf"=> 0 );
- my %invert = ( "and"=> 0, "andc"=> 0, "eqv"=> 1, "nand"=> 0,
- "nor"=> 0, "or"=> 0, "orc"=> 0, "xor"=> 0,
- "add"=> 0, "subf"=> 0 );
- my %commute2 = ( "and"=> 1, "andc"=> 0, "eqv"=> 1, "nand"=> 0,
- "nor"=> 0, "or"=> 1, "orc"=> 0, "xor"=> 1 );
- my %rtlop = ( "and"=>"and", "andc"=>"and", "eqv"=>"xor", "nand"=>"ior",
- "nor"=>"and", "or"=>"ior", "orc"=>"ior", "xor"=>"xor",
- "add"=>"plus", "subf"=>"minus" );
-
- my ($kind, $vchr, $mode, $pred, $constraint, $cr, $outer, @outer_ops,
- $outer_op, $outer_comp, $outer_inv, $outer_rtl, $inner, @inner_ops,
- $inner_comp, $inner_inv, $inner_rtl, $inner_op, $both_commute, $c4,
- $bc, $inner_arg0, $inner_arg1, $inner_exp, $outer_arg2, $outer_exp,
- $ftype, $insn, $is_subf, $is_rsubf, $outer_32, $outer_42,$outer_name,
- $fuse_type);
- KIND: foreach $kind ('scalar','vector') {
- @outer_ops = @logicals;
- if ( $kind eq 'vector' ) {
- $vchr = "v";
- $mode = "VM";
- $pred = "altivec_register_operand";
- $constraint = "v";
- $fuse_type = "fused_vector";
- } else {
- $vchr = "";
- $mode = "GPR";
- $pred = "gpc_reg_operand";
- $constraint = "r";
- $fuse_type = "fused_arith_logical";
- push (@outer_ops, @addsub);
- push (@outer_ops, ( "rsubf" ));
- }
- $c4 = "${constraint},${constraint},${constraint},${constraint}";
- OUTER: foreach $outer ( @outer_ops ) {
- $outer_name = "${vchr}${outer}";
- $is_subf = ( $outer eq "subf" );
- $is_rsubf = ( $outer eq "rsubf" );
- if ( $is_rsubf ) {
- $outer = "subf";
- }
- $outer_op = "${vchr}${outer}";
- $outer_comp = $complement{$outer};
- $outer_inv = $invert{$outer};
- $outer_rtl = $rtlop{$outer};
- @inner_ops = @logicals;
- $ftype = "logical-logical";
- if ( exists $isaddsub{$outer} ) {
- @inner_ops = sort keys %logicals_addsub;
- $ftype = "logical-add";
- } elsif ( $kind ne 'vector' && exists $logicals_addsub{$outer} ) {
- push (@inner_ops, @addsub);
- }
- INNER: foreach $inner ( @inner_ops ) {
- if ( exists $isaddsub{$inner} ) {
- $ftype = "add-logical";
- }
- $inner_comp = $complement{$inner};
- $inner_inv = $invert{$inner};
- $inner_rtl = $rtlop{$inner};
- $inner_op = "${vchr}${inner}";
- # If both ops commute then we can specify % on operand 1
- # so the pattern will let operands 1 and 2 interchange.
- $both_commute = ($inner eq $outer) && ($commute2{$inner} == 1);
- $bc = ""; if ( $both_commute ) { $bc = "%"; }
- $inner_arg0 = "(match_operand:${mode} 0 \"${pred}\" \"${c4}\")";
- $inner_arg1 = "(match_operand:${mode} 1 \"${pred}\" \"${bc}${c4}\")";
- if ( ($inner_comp & 1) == 1 ) {
- $inner_arg0 = "(not:${mode} $inner_arg0)";
- }
- if ( ($inner_comp & 2) == 2 ) {
- $inner_arg1 = "(not:${mode} $inner_arg1)";
- }
- $inner_exp = "(${inner_rtl}:${mode} ${inner_arg0}
- ${inner_arg1})";
- if ( $inner_inv == 1 ) {
- $inner_exp = "(not:${mode} $inner_exp)";
- }
- $outer_arg2 = "(match_operand:${mode} 2 \"${pred}\" \"${c4}\")";
- if ( ($outer_comp & 1) == 1 ) {
- $outer_arg2 = "(not:${mode} $outer_arg2)";
- }
- if ( ($outer_comp & 2) == 2 ) {
- $inner_exp = "(not:${mode} $inner_exp)";
- }
- if ( $is_subf ) {
- $outer_32 = "%2,%3";
- $outer_42 = "%2,%4";
- } else {
- $outer_32 = "%3,%2";
- $outer_42 = "%4,%2";
- }
- if ( $is_rsubf == 1 ) {
- $outer_exp = "(${outer_rtl}:${mode} ${outer_arg2}
- ${inner_exp})";
- } else {
- $outer_exp = "(${outer_rtl}:${mode} ${inner_exp}
- ${outer_arg2})";
- }
- if ( $outer_inv == 1 ) {
- $outer_exp = "(not:${mode} $outer_exp)";
- }
+ # For load mode is DI, there is no EXTDI, the result of
+ # DI doesn't need extension.
+ ld_cmpi_p10_emit_define ('DI', 'clobber', 'CC', 'none');
+ ld_cmpi_p10_emit_define ('DI', 'clobber', 'CCUNS', 'none');
+ ld_cmpi_p10_emit_define ('DI', 'DI', 'CC', 'none');
+ ld_cmpi_p10_emit_define ('DI', 'DI', 'CCUNS', 'none');
+
+ # For load mode is SI, only EXTSI need extension.
+ ld_cmpi_p10_emit_define ('SI', 'clobber', 'CC', 'none');
+ ld_cmpi_p10_emit_define ('SI', 'clobber', 'CCUNS', 'none');
+ ld_cmpi_p10_emit_define ('SI', 'SI', 'CC', 'none');
+ ld_cmpi_p10_emit_define ('SI', 'SI', 'CCUNS', 'none');
+ ld_cmpi_p10_emit_define ('SI', 'EXTSI', 'CC', 'sign');
+ ld_cmpi_p10_emit_define ('SI', 'EXTSI', 'CCUNS', 'zero');
- $insn = <<"EOF";
+ # For load mode is HI, we can't produce HI result directly.
+ # We always need extension if result is wider than load
+ # mode.
+ ld_cmpi_p10_emit_define ('HI', 'clobber', 'CC', 'sign');
+ ld_cmpi_p10_emit_define ('HI', 'clobber', 'CCUNS', 'zero');
+ ld_cmpi_p10_emit_define ('HI', 'EXTHI', 'CC', 'sign');
+ ld_cmpi_p10_emit_define ('HI', 'EXTHI', 'CCUNS', 'zero');
+
+ # For load mode is QI, we can't produce QI result directly,
+ # also ignore CC here. We always need extension if result
+ # is wider than load mode.
+ ld_cmpi_p10_emit_define ('QI', 'clobber', 'CCUNS', 'zero');
+ # Don't allow EXTQI because that would allow HI result
+ # which we can't do.
+ ld_cmpi_p10_emit_define ('QI', 'GPR', 'CCUNS', 'zero');
+}
+
+# Emit define_insn_and_split for logical/addsubf fusion type
+# based the below given arguments:
+# arg 0: string for fusion type in comments, can only be
+# "logical-logical", "logical-add" or "add-logical".
+# arg 1: "scalar" or "vector".
+# arg 2: outer operator.
+# arg 3: inner operator.
+# arg 4: machine mode.
+# arg 5: predicate.
+# arg 6: constraint.
+# arg 7: expression pattern made by logical_addsubf_make_exp.
+# arg 8: fusion type for insn type attribute.
+sub logical_addsubf_emit_define
+{
+ my ($ftype, $kind, $outer_op, $inner_op, $mode, $pred, $cstr,
+ $exp, $fuse_type) = @_;
+
+ # Make some adjustments for subf and rsubf.
+ my $outer_name = $outer_op;
+ $outer_op = 'subf' if $outer_op eq 'rsubf';
+
+ my $ops32 = '%3,%2';
+ my $ops42 = '%4,%2';
+ if ( $outer_name eq 'subf' ) {
+ $ops32 = '%2,%3';
+ $ops42 = '%2,%4';
+ }
+
+ print << "EOF";
;; $ftype fusion pattern generated by gen_logical_addsubf
;; $kind $inner_op -> $outer_name
(define_insn "*fuse_${inner_op}_${outer_name}"
- [(set (match_operand:${mode} 3 "${pred}" "=&0,&1,&${constraint},${constraint}")
- ${outer_exp})
- (clobber (match_scratch:${mode} 4 "=X,X,X,&${constraint}"))]
+ [(set (match_operand:${mode} 3 "${pred}" "=&0,&1,&${cstr},${cstr}")
+ ${exp})
+ (clobber (match_scratch:${mode} 4 "=X,X,X,&${cstr}"))]
"(TARGET_P10_FUSION)"
"@
- ${inner_op} %3,%1,%0\\;${outer_op} %3,${outer_32}
- ${inner_op} %3,%1,%0\\;${outer_op} %3,${outer_32}
- ${inner_op} %3,%1,%0\\;${outer_op} %3,${outer_32}
- ${inner_op} %4,%1,%0\\;${outer_op} %3,${outer_42}"
+ ${inner_op} %3,%1,%0\\;${outer_op} %3,${ops32}
+ ${inner_op} %3,%1,%0\\;${outer_op} %3,${ops32}
+ ${inner_op} %3,%1,%0\\;${outer_op} %3,${ops32}
+ ${inner_op} %4,%1,%0\\;${outer_op} %3,${ops42}"
[(set_attr "type" "$fuse_type")
(set_attr "cost" "6")
(set_attr "length" "8")])
EOF
+}
- print $insn;
+# For the given operator in arg 0, return an array holding the
+# information on complementing, inverting, commuting and rtl
+# operator name, die if the given operator isn't expected.
+sub logical_addsub_get_op_info
+{
+ my $op = $_[0];
+
+ # Checking the given OP is valid
+ my @valid_ops = ( 'and', 'andc', 'eqv', 'nand', 'nor', 'or', 'orc', 'xor',
+ 'add', 'subf', 'rsubf' );
+ die "Unexpected op:$op" unless grep (/^$op$/, @valid_ops);
+
+ my %complement = ( 'and'=> 0, 'andc'=> 1, 'eqv'=> 0, 'nand'=> 3,
+ 'nor'=> 3, 'or'=> 0, 'orc'=> 1, 'xor'=> 0,
+ 'add'=> 0, 'subf'=> 0 );
+ my %invert = ( 'and'=> 0, 'andc'=> 0, 'eqv'=> 1, 'nand'=> 0,
+ 'nor'=> 0, 'or'=> 0, 'orc'=> 0, 'xor'=> 0,
+ 'add'=> 0, 'subf'=> 0 );
+ my %commute2 = ( 'and'=> 1, 'andc'=> 0, 'eqv'=> 1, 'nand'=> 0,
+ 'nor'=> 0, 'or'=> 1, 'orc'=> 0, 'xor'=> 1 );
+ my %rtl_ops = ( 'and'=>'and', 'andc'=>'and', 'eqv'=>'xor', 'nand'=>'ior',
+ 'nor'=>'and', 'or'=>'ior', 'orc'=>'ior', 'xor'=>'xor',
+ 'add'=>'plus', 'subf'=>'minus' );
+
+ return ($complement{$op}, $invert{$op}, $commute2{$op}, $rtl_ops{$op});
+}
+
+# For logical/addsubf fusion type, make up an expression based on
+# the below given arguments:
+# arg 1: outer operator.
+# arg 2: inner operator.
+# arg 3: machine mode.
+# arg 4: predicate.
+# arg 5: constraint.
+sub logical_addsubf_make_exp
+{
+ my ($outer_op, $inner_op, $mode, $pred, $cstr) = @_;
+
+ my $outer_is_rsubf_p = 0;
+ if ($outer_op eq 'rsubf') {
+ $outer_op = 'subf';
+ $outer_is_rsubf_p = 1;
+ }
+
+ my ($outer_comp, $outer_invert_p, $outer_comm_p,
+ $outer_rtl_op) = logical_addsub_get_op_info ($outer_op);
+ my ($inner_comp, $inner_invert_p, $inner_comm_p,
+ $inner_rtl_op) = logical_addsub_get_op_info ($inner_op);
+
+ # If both ops commute then we can specify % on operand 1
+ # so the pattern will let operands 1 and 2 interchange.
+ my $bc = '';
+ $bc = '%' if ($inner_op eq $outer_op) && $inner_comm_p;
+
+ my $cstr4 = "${cstr},${cstr},${cstr},${cstr}";
+
+ # Make up arg0 (inner).
+ my $arg0 = "(match_operand:${mode} 0 \"${pred}\" \"${cstr4}\")";
+ $arg0 = "(not:${mode} $arg0)" if ($inner_comp & 1) == 1;
+
+ # Make up arg1 (inner).
+ my $arg1 = "(match_operand:${mode} 1 \"${pred}\" \"${bc}${cstr4}\")";
+ $arg1 = "(not:${mode} $arg1)" if ($inner_comp & 2) == 2;
+
+ # Make up inner_exp.
+ my $inner_exp = "(${inner_rtl_op}:${mode} ${arg0}
+ ${arg1})";
+
+ # Invert inner_exp if needed.
+ $inner_exp = "(not:${mode} $inner_exp)" if ( $inner_invert_p );
+
+ # Make up outer arg2.
+ my $arg2 = "(match_operand:${mode} 2 \"${pred}\" \"${cstr4}\")";
+ $arg2 = "(not:${mode} $arg2)" if ($outer_comp & 1) == 1;
+
+ # Complement inner_exp if needed.
+ $inner_exp = "(not:${mode} $inner_exp)" if ($outer_comp & 2) == 2;
+
+ my $outer_exp;
+ # Make up outer_exp and special casing rsubf.
+ if ($outer_is_rsubf_p) {
+ $outer_exp = "(${outer_rtl_op}:${mode} ${arg2}
+ ${inner_exp})";
+ } else {
+ $outer_exp = "(${outer_rtl_op}:${mode} ${inner_exp}
+ ${arg2})";
+ }
+
+ # Invert outer_exp if needed.
+ $outer_exp = "(not:${mode} $outer_exp)" if $outer_invert_p;
+
+ return $outer_exp;
+}
+
+# Generate logical/addsubf fusion type for scalar.
+sub gen_logical_addsubf_scalar
+{
+ my $mode = 'GPR';
+ my $pred = 'gpc_reg_operand';
+ my $fuse_type = 'fused_arith_logical';
+ my $constraint = 'r';
+
+ my @logicals = ( 'and', 'andc', 'eqv', 'nand', 'nor', 'or', 'orc', 'xor' );
+ # logical ops which can fuse with add/subf/rsubf
+ my @logicals2 = ( 'and', 'nand', 'nor', 'or' );
+ my @add_subf = ( 'add', 'subf' );
+
+ # {logical, add}-logical
+ foreach my $outer_op ( @logicals ) {
+ foreach my $inner_op ( @logicals, @add_subf ) {
+ my $ftype = 'logical-logical';
+ if (grep (/^$inner_op$/, @add_subf)) {
+ next unless grep (/^$outer_op$/, @logicals2);
+ $ftype = 'add-logical';
}
+ my $exp = logical_addsubf_make_exp ($outer_op, $inner_op, $mode,
+ $pred, $constraint);
+ logical_addsubf_emit_define ($ftype, 'scalar', $outer_op, $inner_op,
+ $mode, $pred, $constraint, $exp, $fuse_type);
+ }
+ }
+
+ my @add_subf_rsubf = ( 'add', 'subf', 'rsubf' );
+
+ # logical-add
+ foreach my $outer_op ( @add_subf_rsubf ) {
+ foreach my $inner_op ( @logicals2 ) {
+ my $exp = logical_addsubf_make_exp ($outer_op, $inner_op, $mode,
+ $pred, $constraint);
+ logical_addsubf_emit_define ('logical-add', 'scalar', $outer_op,
+ $inner_op, $mode, $pred, $constraint,
+ $exp, $fuse_type);
+ }
+ }
+}
+
+# Generate logical/addsubf fusion type for vector.
+sub gen_logical_addsubf_vector
+{
+ my $mode = "VM";
+ my $pred = "altivec_register_operand";
+ my $fuse_type = "fused_vector";
+ my $constraint = "v";
+
+ my @logicals = ( 'and', 'andc', 'eqv', 'nand', 'nor', 'or', 'orc', 'xor' );
+
+ # logical-logical
+ foreach my $outer_op ( @logicals ) {
+ foreach my $inner_op ( @logicals ) {
+ my $exp = logical_addsubf_make_exp ($outer_op, $inner_op, $mode,
+ $pred, $constraint);
+ logical_addsubf_emit_define ('logical-logical', 'vector', "v${outer_op}",
+ "v${inner_op}", $mode, $pred, $constraint,
+ $exp, $fuse_type);
}
}
}
+# Main subroutine to generate logical/addsubf fusion type.
+sub gen_logical_addsubf
+{
+ gen_logical_addsubf_scalar ();
+ gen_logical_addsubf_vector ();
+}
+
+# Main subroutine to generate add-add fusion type.
sub gen_addadd
{
- my ($kind, $vchr, $op, $type, $mode, $pred, $constraint);
+ my ($kind, $op, $type, $mode, $pred, $constraint);
foreach $kind ('scalar','vector') {
if ( $kind eq 'vector' ) {
- $vchr = "v";
$op = "vaddudm";
$type = "fused_vector";
$mode = "V2DI";
$pred = "altivec_register_operand";
$constraint = "v";
} else {
- $vchr = "";
$op = "add";
$type = "fused_arith_logical";
$mode = "GPR";
@@ -323,9 +439,13 @@ EOF
}
}
-gen_ld_cmpi_p10();
-gen_logical_addsubf();
-gen_addadd;
+sub main {
+ gen_copyright_and_top_comments ();
+ gen_ld_cmpi_p10 ();
+ gen_logical_addsubf ();
+ gen_addadd ();
+ return 0;
+}
-exit(0);
+exit main ();