1 //------------------------------------------------------------------------------
2 // GB_stringify_terminal: convert terminal condition into a string or enum
3 //------------------------------------------------------------------------------
4 
5 // SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2021, All Rights Reserved.
6 // SPDX-License-Identifier: Apache-2.0
7 
8 //------------------------------------------------------------------------------
9 
10 // The terminal_expression_macro(cij) should return true if the value of
11 // cij has reached its terminal value, or false otherwise.  If the monoid is
12 // not terminal, then the macro should always return false.  The ANY monoid
13 // should always return true.
14 
15 // The terminal_statement_macro is a macro containing a full statement.  If the
16 // monoid is never terminal, it becomes the empty statement.  Otherwise,
17 // it checks the terminal condition and does a "break" if true.  The statement
18 // has no trailing semicolon.
19 
20 #include "GB.h"
21 #include "GB_stringify.h"
22 
23 //------------------------------------------------------------------------------
24 // GB_stringify_terminal: macros for terminal value and condition
25 //------------------------------------------------------------------------------
26 
GB_stringify_terminal(bool * is_monoid_terminal,char * terminal_expression_macro,char * terminal_statement_macro,const char * terminal_expression_macro_name,const char * terminal_statement_macro_name,GB_Opcode opcode,GB_Type_code zcode)27 void GB_stringify_terminal         // return strings to check terminal
28 (
29     // outputs:
30     bool *is_monoid_terminal,           // true if monoid is terminal
31     char *terminal_expression_macro,    // #define for terminal expression macro
32     char *terminal_statement_macro,     // #define for terminal statement macro
33     // inputs:
34     const char *terminal_expression_macro_name,     // name of expression macro
35     const char *terminal_statement_macro_name,      // name of statement macro
36     GB_Opcode opcode,    // must be a built-in binary operator from a monoid
37     GB_Type_code zcode   // type code of the binary operator
38 )
39 {
40 
41     char *terminal_value ;
42     char terminal_expression [GB_CUDA_STRLEN+1] ;
43     char terminal_statement  [GB_CUDA_STRLEN+1] ;
44     int ecode ;
45 
46     // get ecode and bool (is_monoid_terminal) from the opcode and zcode
47     GB_enumify_terminal (&ecode, opcode, zcode) ;
48     (*is_monoid_terminal) = (ecode <= 29) ;
49 
50     // convert ecode and is_monoid_terminal to strings
51     GB_charify_identity_or_terminal (&terminal_value, ecode) ;
52     GB_charify_terminal_expression (terminal_expression,
53         terminal_value, is_monoid_terminal, ecode) ;
54     GB_charify_terminal_statement (terminal_statement,
55         terminal_value, is_monoid_terminal, ecode) ;
56 
57     // convert strings to macros
58     GB_macrofy_terminal_expression (terminal_expression_macro,
59         terminal_expression_macro_name, terminal_expression) ;
60     GB_macrofy_terminal_statement (terminal_statement_macro,
61         terminal_statement_macro_name, terminal_statement) ;
62 }
63 
64 //------------------------------------------------------------------------------
65 // GB_enumify_terminal: return enum of terminal value
66 //------------------------------------------------------------------------------
67 
GB_enumify_terminal(int * ecode,GB_Opcode opcode,GB_Type_code zcode)68 void GB_enumify_terminal       // return enum of terminal value
69 (
70     // output:
71     int *ecode,                 // enumerated terminal, 0 to 31 (-1 if fail)
72     // input:
73     GB_Opcode opcode,           // built-in binary opcode of a monoid
74     GB_Type_code zcode          // type code used in the opcode we want
75 )
76 {
77 
78     int e = -1 ;
79 
80     switch (opcode)
81     {
82 
83         case GB_PLUS_opcode :
84 
85             if (zcode == GB_BOOL_code)
86             {
87                 e = 2 ;                 // true (boolean OR)
88             }
89             else
90             {
91                 e = 31 ;                // builtin with no terminal value
92             }
93             break ;
94 
95         case GB_TIMES_opcode :
96 
97             switch (zcode)
98             {
99                 case GB_BOOL_code   :
100                     e = 3 ;             // false (boolean AND)
101                     break ;
102                 case GB_INT8_code   :
103                 case GB_INT16_code  :
104                 case GB_INT32_code  :
105                 case GB_INT64_code  :
106                 case GB_UINT8_code  :
107                 case GB_UINT16_code :
108                 case GB_UINT32_code :
109                 case GB_UINT64_code :
110                     e = 0 ;             // 0
111                     break ;
112                 default :
113                     e = 31 ;            // builtin with no terminal value
114                     break ;
115             }
116             break ;
117 
118         case GB_LOR_opcode      :
119 
120                 e = 2 ;                 // true
121                 break ;
122 
123         case GB_LAND_opcode     :
124 
125                 e = 3 ;                 // false
126                 break ;
127 
128         case GB_MIN_opcode :
129 
130             switch (zcode)
131             {
132                 case GB_BOOL_code   : e =  3 ; break ; // false
133                 case GB_INT8_code   : e = 13 ; break ; // INT8_MIN
134                 case GB_INT16_code  : e = 14 ; break ; // INT16_MIN
135                 case GB_INT32_code  : e = 15 ; break ; // INT32_MIN
136                 case GB_INT64_code  : e = 16 ; break ; // INT64_MIN
137                 case GB_UINT8_code  :
138                 case GB_UINT16_code :
139                 case GB_UINT32_code :
140                 case GB_UINT64_code : e =  0 ; break ; // 0
141                 case GB_FP32_code   :
142                 case GB_FP64_code   : e = 17 ; break ; // -INFINITY
143                 default             : e = -1 ; break ;
144             }
145             break ;
146 
147         case GB_MAX_opcode :
148 
149             switch (zcode)
150             {
151                 case GB_BOOL_code   : e =  2 ; break ; // true
152                 case GB_INT8_code   : e =  4 ; break ; // INT8_MAX
153                 case GB_INT16_code  : e =  5 ; break ; // INT16_MAX
154                 case GB_INT32_code  : e =  6 ; break ; // INT32_MAX
155                 case GB_INT64_code  : e =  7 ; break ; // INT64_MAX
156                 case GB_UINT8_code  : e =  8 ; break ; // UINT8_MAX
157                 case GB_UINT16_code : e =  9 ; break ; // UINT16_MAX
158                 case GB_UINT32_code : e = 10 ; break ; // UINT32_MAX
159                 case GB_UINT64_code : e = 11 ; break ; // UINT64_MAX
160                 case GB_FP32_code   :
161                 case GB_FP64_code   : e = 12 ; break ; // INFINITY
162                 default             : e = -1 ; break ;
163             }
164             break ;
165 
166         case GB_ANY_opcode :
167 
168             e = 18 ;                    // no specific terminal value
169             break ;
170 
171         case GB_LXOR_opcode     :
172         // case GB_LXNOR_opcode :
173         case GB_EQ_opcode       :
174         default                 :
175 
176             e = 31 ;                    // builtin with no terminal value
177             break ;
178 
179         case GB_USER_opcode :
180 
181     }
182 
183     (*ecode) = e ;
184 }
185 
186 //------------------------------------------------------------------------------
187 // GB_charify_terminal_expression: string to evaluate terminal expression
188 //------------------------------------------------------------------------------
189 
GB_charify_terminal_expression(char * terminal_expression,char * terminal_string,bool is_monoid_terminal,int ecode)190 void GB_charify_terminal_expression    // string for terminal expression
191 (
192     // output:
193     char *terminal_expression,          // string with terminal expression
194     // input:
195     char *terminal_string,              // string with terminal value
196     bool is_monoid_terminal,            // true if monoid is terminal
197     int ecode                           // ecode of monoid operator
198 )
199 {
200 
201     if (is_monoid_terminal)
202     {
203         // the monoid is terminal
204         if (ecode == 18)
205         {
206             // ANY monoid: terminal expression is always true
207             snprintf (terminal_expression, GB_CUDA_STRLEN, "(true)") ;
208         }
209         else
210         {
211             // typical terminal monoids: check if C(i,j) has reached its
212             // terminal value
213             snprintf (terminal_expression, GB_CUDA_STRLEN,
214                 "((cij) == %s)", terminal_string) ;
215         }
216     }
217     else
218     {
219         // the monoid is not terminal: the expression is always false
220         snprintf (terminal_expression, GB_CUDA_STRLEN, "(false)") ;
221     }
222 }
223 
224 //------------------------------------------------------------------------------
225 // GB_charify_terminal_statement: string for terminal statement
226 //------------------------------------------------------------------------------
227 
GB_charify_terminal_statement(char * terminal_statement,char * terminal_string,bool is_monoid_terminal,int ecode)228 void GB_charify_terminal_statement // string for terminal statement
229 (
230     // output:
231     char *terminal_statement,           // string with terminal statement
232     // input:
233     char *terminal_string,              // string with terminal value
234     bool is_monoid_terminal,            // true if monoid is terminal
235     int ecode                           // ecode of monoid operator
236 )
237 {
238 
239     if (is_monoid_terminal)
240     {
241         // the monoid is terminal
242         if (ecode == 18)
243         {
244             // ANY monoid: always break
245             snprintf (terminal_statement, GB_CUDA_STRLEN, "break") ;
246         }
247         else
248         {
249             // typical terminal monoids: break if C(i,j) has reached its
250             // terminal value
251             snprintf (terminal_statement, GB_CUDA_STRLEN,
252                 "if ((cij) == %s) break", terminal_string) ;
253         }
254     }
255     else
256     {
257         // the monoid is not terminal: the terminal statement is empty
258         snprintf (terminal_statement, GB_CUDA_STRLEN, "") ;
259     }
260 }
261 
262 //------------------------------------------------------------------------------
263 // GB_macrofy_terminal_expression: macro for terminal expression
264 //------------------------------------------------------------------------------
265 
GB_macrofy_terminal_expression(char * terminal_expression_macro,const char * terminal_expression_macro_name,const char * terminal_expression)266 void GB_macrofy_terminal_expression    // macro for terminal expression
267 (
268     // output:
269     char *terminal_expression_macro,
270     // intput:
271     const char *terminal_expression_macro_name,
272     const char *terminal_expression
273 )
274 {
275 
276     snprintf (terminal_expression_macro, GB_CUDA_STRLEN,
277         "#define %s(cij) %s",
278         terminal_expression_macro_name, terminal_expression) ;
279 }
280 
281 //------------------------------------------------------------------------------
282 // GB_macrofy_terminal_statement: macro for terminal statement
283 //------------------------------------------------------------------------------
284 
GB_macrofy_terminal_statement(char * terminal_statement_macro,const char * terminal_statement_macro_name,const char * terminal_statement)285 void GB_macrofy_terminal_statement     // macro for terminal statement
286 (
287     // output:
288     char *terminal_statement_macro,
289     // intput:
290     const char *terminal_statement_macro_name,
291     const char *terminal_statement
292 )
293 {
294 
295     snprintf (terminal_statement_macro, GB_CUDA_STRLEN,
296         "#define %s %s",
297         terminal_statement_macro_name, terminal_statement) ;
298 }
299 
300