1function codegen_binop_method (binop, op, xtype) 2%CODEGEN_BINOP_METHOD create a function to compute C=binop(A,B) 3% 4% codegen_binop_method (binop, op, xtype) 5 6% SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2021, All Rights Reserved. 7% SPDX-License-Identifier: Apache-2.0 8 9f = fopen ('control.m4', 'w') ; 10 11% no code is generated for the ANY operator (SECOND is used in its place) 12assert (~isequal (binop, 'any')) ; 13 14[fname, unsigned, bits] = codegen_type (xtype) ; 15 16name = sprintf ('%s_%s', binop, fname) ; 17 18% function names 19fprintf (f, 'define(`_AaddB'', `_AaddB__%s'')\n', name) ; 20fprintf (f, 'define(`_AemultB_01'', `_AemultB_01__%s'')\n', name) ; 21fprintf (f, 'define(`_AemultB_02'', `_AemultB_02__%s'')\n', name) ; 22fprintf (f, 'define(`_AemultB_03'', `_AemultB_03__%s'')\n', name) ; 23fprintf (f, 'define(`_AemultB_bitmap'', `_AemultB_bitmap__%s'')\n', name) ; 24fprintf (f, 'define(`_Cdense_accumB'', `_Cdense_accumB__%s'')\n', name) ; 25fprintf (f, 'define(`_Cdense_accumb'', `_Cdense_accumb__%s'')\n', name) ; 26fprintf (f, 'define(`_Cdense_ewise3_noaccum'', `_Cdense_ewise3_noaccum__%s'')\n', name) ; 27 28% subset of operators for GB_dense_ewise3_accum 29switch (binop) 30 case { 'min', 'max', 'plus', 'minus', 'rminus', 'times', 'div', 'rdiv' } 31 % these operators are used in ewise3_accum 32 fprintf (f, 'define(`_Cdense_ewise3_accum'', `_Cdense_ewise3_accum__%s'')\n', name) ; 33 fprintf (f, 'define(`if_is_binop_subset'', `'')\n') ; 34 fprintf (f, 'define(`endif_is_binop_subset'', `'')\n') ; 35 otherwise 36 fprintf (f, 'define(`_Cdense_ewise3_accum'', `(none)'')\n') ; 37 fprintf (f, 'define(`if_is_binop_subset'', `#if 0'')\n') ; 38 fprintf (f, 'define(`endif_is_binop_subset'', `#endif'')\n') ; 39end 40 41% subset of operators for GB_AxB_rowscale and GB_AxB_colscale 42switch (binop) 43 case { 'min', 'max', 'plus', 'minus', 'rminus', 'times', 'div', 'rdiv', ... 44 'first', 'second', 'pair', 'isgt', 'islt', 'isge', 'isle', ... 45 'gt', 'lt', 'ge', 'le', 'lor', 'land', 'lxor' } 46 % these operators are used in GB_AxB_*scale 47 binop_is_semiring_multiplier = true ; 48 case { 'eq', 'iseq', 'ne', 'isne' } 49 % these do not appear in complex semirings 50 binop_is_semiring_multiplier = (~contains (xtype, 'FC')) ; 51 case { 'bor', 'band', 'bxor', 'bxnor' } 52 % these operators are used in GB_AxB_*scale for uint* only 53 binop_is_semiring_multiplier = contains (xtype, 'uint') ; 54 otherwise 55 % these operators are not used in GB_AxB_*scale by any builtin semiring 56 binop_is_semiring_multiplier = false ; 57end 58if (binop_is_semiring_multiplier) 59 fprintf (f, 'define(`_AxD'', `_AxD__%s'')\n', name) ; 60 fprintf (f, 'define(`_DxB'', `_DxB__%s'')\n', name) ; 61 fprintf (f, 'define(`if_binop_is_semiring_multiplier'', `'')\n') ; 62 fprintf (f, 'define(`endif_binop_is_semiring_multiplier'', `'')\n') ; 63else 64 fprintf (f, 'define(`_AxD'', `(none)'')\n') ; 65 fprintf (f, 'define(`_DxB'', `(node)'')\n') ; 66 fprintf (f, 'define(`if_binop_is_semiring_multiplier'', `#if 0'')\n') ; 67 fprintf (f, 'define(`endif_binop_is_semiring_multiplier'', `#endif'')\n') ; 68end 69 70% subset of operators for GB_apply 71switch (binop) 72 case { 'first', 'any', 'pair' } 73 % no bind2nd for these operators 74 fprintf (f, 'define(`_bind2nd'', `(none)'')\n', name) ; 75 fprintf (f, 'define(`_bind2nd_tran'', `(none)'')\n', name) ; 76 fprintf (f, 'define(`if_binop_bind2nd_is_enabled'', `#if 0'')\n') ; 77 fprintf (f, 'define(`endif_binop_bind2nd_is_enabled'', `#endif'')\n') ; 78 otherwise 79 fprintf (f, 'define(`_bind2nd'', `_bind2nd__%s'')\n', name) ; 80 fprintf (f, 'define(`_bind2nd_tran'', `_bind2nd_tran__%s'')\n', name) ; 81 fprintf (f, 'define(`if_binop_bind2nd_is_enabled'', `'')\n') ; 82 fprintf (f, 'define(`endif_binop_bind2nd_is_enabled'', `'')\n') ; 83end 84switch (binop) 85 case { 'second', 'any', 'pair' } 86 % no bind1st for these operators 87 fprintf (f, 'define(`_bind1st'', `(none)'')\n', name) ; 88 fprintf (f, 'define(`_bind1st_tran'', `(none)'')\n', name) ; 89 fprintf (f, 'define(`if_binop_bind1st_is_enabled'', `#if 0'')\n') ; 90 fprintf (f, 'define(`endif_binop_bind1st_is_enabled'', `#endif'')\n') ; 91 otherwise 92 fprintf (f, 'define(`_bind1st'', `_bind1st__%s'')\n', name) ; 93 fprintf (f, 'define(`_bind1st_tran'', `_bind1st_tran__%s'')\n', name) ; 94 fprintf (f, 'define(`if_binop_bind1st_is_enabled'', `'')\n') ; 95 fprintf (f, 'define(`endif_binop_bind1st_is_enabled'', `'')\n') ; 96end 97 98if (isequal (binop, 'second')) 99 fprintf (f, 'define(`GB_op_is_second'', `1'')\n') ; 100else 101 fprintf (f, 'define(`GB_op_is_second'', `0'')\n') ; 102end 103 104% determine type of z, x, and y from xtype and binop 105switch (binop) 106 case { 'eq', 'ne', 'gt', 'lt', 'ge', 'le' } 107 % GrB_LT_* and related operators are TxT -> bool 108 ztype = 'bool' ; 109 ytype = xtype ; 110 case { 'cmplx' } 111 % GxB_CMPLX_* are TxT -> (complex T) 112 if (isequal (xtype, 'float')) 113 ztype = 'GxB_FC32_t' ; 114 else 115 ztype = 'GxB_FC64_t' ; 116 end 117 ytype = xtype ; 118 case { 'bshift' } 119 % z = bitshift (x,y): y is always int8 120 ztype = xtype ; 121 ytype = 'int8_t' ; 122 otherwise 123 % all other operators: z, x, and y have the same type 124 ztype = xtype ; 125 ytype = xtype ; 126end 127 128fprintf (f, 'define(`GB_ctype'', `%s'')\n', ztype) ; 129fprintf (f, 'define(`GB_atype'', `%s'')\n', xtype) ; 130fprintf (f, 'define(`GB_btype'', `%s'')\n', ytype) ; 131 132fprintf (f, 'define(`GB_atype_is_btype'', `%d'')\n', isequal (xtype, ytype)) ; 133fprintf (f, 'define(`GB_ctype_is_atype'', `%d'')\n', isequal (ztype, xtype)) ; 134fprintf (f, 'define(`GB_ctype_is_btype'', `%d'')\n', isequal (ztype, ytype)) ; 135 136% C_dense_update: operators z=f(x,y) where ztype and xtype match, and op is not 'first' 137if (isequal (xtype, ztype) && ~isequal (binop, 'first')) 138 fprintf (f, 'define(`GB_C_dense_update'', `1'')\n') ; 139 fprintf (f, 'define(`if_C_dense_update'', `'')\n') ; 140 fprintf (f, 'define(`endif_C_dense_update'', `'')\n') ; 141else 142 fprintf (f, 'define(`GB_C_dense_update'', `0'')\n') ; 143 fprintf (f, 'define(`if_C_dense_update'', `#if 0'')\n') ; 144 fprintf (f, 'define(`endif_C_dense_update'', `#endif'')\n') ; 145end 146 147% to get an entry from A 148if (isequal (binop, 'second') || isequal (binop, 'pair')) 149 % the value of A is ignored 150 fprintf (f, 'define(`GB_geta'', `;'')\n') ; 151else 152 fprintf (f, 'define(`GB_geta'', `%s $1 = $2 [$3]'')\n', xtype) ; 153end 154 155% to get an entry from B 156if (isequal (binop, 'first') || isequal (binop, 'pair')) 157 % the value of B is ignored 158 fprintf (f, 'define(`GB_getb'', `;'')\n') ; 159else 160 fprintf (f, 'define(`GB_getb'', `%s $1 = $2 [$3]'')\n', ytype) ; 161end 162 163% to copy an entry from A to C 164if (isequal (xtype, 'GxB_FC32_t') && isequal (ztype, 'bool')) 165 fprintf (f, 'define(`GB_copy_a_to_c'', `$1 = (crealf ($2 [$3]) != 0) || (cimagf ($2 [$3]) != 0)'')\n') ; 166elseif (isequal (xtype, 'GxB_FC64_t') && isequal (ztype, 'bool')) 167 fprintf (f, 'define(`GB_copy_a_to_c'', `$1 = (creal ($2 [$3]) != 0) || (cimag ($2 [$3]) != 0)'')\n') ; 168elseif (isequal (xtype, 'float') && isequal (ztype, 'GxB_FC32_t')) 169 fprintf (f, 'define(`GB_copy_a_to_c'', `$1 = GxB_CMPLXF ($2 [$3], 0)'')\n') ; 170elseif (isequal (xtype, 'double') && isequal (ztype, 'GxB_FC64_t')) 171 fprintf (f, 'define(`GB_copy_a_to_c'', `$1 = GxB_CMPLX ($2 [$3], 0)'')\n') ; 172else 173 fprintf (f, 'define(`GB_copy_a_to_c'', `$1 = $2 [$3]'')\n') ; 174end 175 176% to copy an entry from B to C 177if (isequal (ytype, 'GxB_FC32_t') && isequal (ztype, 'bool')) 178 fprintf (f, 'define(`GB_copy_b_to_c'', `$1 = (crealf ($2 [$3]) != 0) || (cimagf ($2 [$3]) != 0)'')\n') ; 179elseif (isequal (ytype, 'GxB_FC64_t') && isequal (ztype, 'bool')) 180 fprintf (f, 'define(`GB_copy_b_to_c'', `$1 = (creal ($2 [$3]) != 0) || (cimag ($2 [$3]) != 0)'')\n') ; 181elseif (isequal (ytype, 'float') && isequal (ztype, 'GxB_FC32_t')) 182 fprintf (f, 'define(`GB_copy_b_to_c'', `$1 = GxB_CMPLXF ($2 [$3], 0)'')\n') ; 183elseif (isequal (ytype, 'double') && isequal (ztype, 'GxB_FC64_t')) 184 fprintf (f, 'define(`GB_copy_b_to_c'', `$1 = GxB_CMPLX ($2 [$3], 0)'')\n') ; 185else 186 fprintf (f, 'define(`GB_copy_b_to_c'', `$1 = $2 [$3]'')\n') ; 187end 188 189% type-specific IDIV 190if (~isempty (strfind (op, 'IDIV'))) 191 if (unsigned) 192 op = strrep (op, 'IDIV', 'IDIV_UNSIGNED') ; 193 else 194 op = strrep (op, 'IDIV', 'IDIV_SIGNED') ; 195 end 196 op = strrep (op, ')', sprintf (', %d)', bits)) ; 197end 198 199% create the binary operator 200op = strrep (op, 'xarg', '`$2''') ; 201op = strrep (op, 'yarg', '`$3''') ; 202fprintf (f, 'define(`GB_binaryop'', `$1 = %s'')\n', op) ; 203 204% handle the flip 205switch (binop) 206 case { 'pow', 'bget', 'bset', 'bclr', 'bshift', 'atan2', 'fmod', ... 207 'remainder', 'copysign', 'ldexp', 'cmplx' } 208 fprintf (f, 'define(`GB_binaryop_flip'', `1'')\n') ; 209 otherwise 210 fprintf (f, 'define(`GB_binaryop_flip'', `0'')\n') ; 211end 212 213% create the disable flag 214disable = sprintf ('GxB_NO_%s', upper (binop)) ; 215disable = [disable (sprintf (' || GxB_NO_%s', upper (fname)))] ; 216disable = [disable (sprintf (' || GxB_NO_%s_%s', upper (binop), upper (fname)))] ; 217fprintf (f, 'define(`GB_disable'', `(%s)'')\n', disable) ; 218 219% ff = fopen ('temp.h', 'a') ; 220% fprintf (ff, '// #define GxB_NO_%s_%s\n', upper (binop), upper (fname)) ; 221% fclose (ff) ; 222 223fclose (f) ; 224 225trim = 41 ; 226 227% construct the *.c file 228cmd = sprintf (... 229'cat control.m4 Generator/GB_binop.c | m4 | tail -n +%d > Generated/GB_binop__%s.c', ... 230trim, name) ; 231fprintf ('.') ; 232system (cmd) ; 233 234% append to the *.h file 235cmd = sprintf (... 236'cat control.m4 Generator/GB_binop.h | m4 | tail -n +%d >> Generated/GB_binop__include.h', trim) ; 237system (cmd) ; 238 239delete ('control.m4') ; 240 241