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