1 //------------------------------------------------------------------------------
2 // GB_ewise_generic: generic methods for eWiseMult and eWiseAdd
3 //------------------------------------------------------------------------------
4
5 // SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2021, All Rights Reserved.
6 // SPDX-License-Identifier: Apache-2.0
7
8 //------------------------------------------------------------------------------
9
10 // GB_ewise_generic handles the generic case for ewise operations, when no
11 // built-in worker in the switch factory can handle this case. This occurs
12 // for user-defined operators, when typecasting occurs, or for FIRST[IJ]* and
13 // SECOND[IJ]* positional operators.
14
15 #include "GB_ewise.h"
16 #include "GB_emult.h"
17 #include "GB_binop.h"
18 #include "GB_unused.h"
19 #include "GB_ek_slice.h"
20
21 #undef GB_FREE_ALL
22 #define GB_FREE_ALL \
23 { \
24 GB_phbix_free (C) ; \
25 }
26
GB_ewise_generic(GrB_Matrix C,const GrB_BinaryOp op,const GB_task_struct * restrict TaskList,const int C_ntasks,const int C_nthreads,const int64_t * restrict C_to_M,const int64_t * restrict C_to_A,const int64_t * restrict C_to_B,const int C_sparsity,const int ewise_method,const int64_t * restrict Cp_kfirst,const int64_t * M_ek_slicing,const int M_ntasks,const int M_nthreads,const int64_t * A_ek_slicing,const int A_ntasks,const int A_nthreads,const int64_t * B_ek_slicing,const int B_ntasks,const int B_nthreads,const GrB_Matrix M,const bool Mask_struct,const bool Mask_comp,const GrB_Matrix A,const GrB_Matrix B,GB_Context Context)27 void GB_ewise_generic // generic ewise
28 (
29 // input/output:
30 GrB_Matrix C, // output matrix, static header
31 // input:
32 const GrB_BinaryOp op, // op to perform C = op (A,B)
33 // tasks from phase1a:
34 const GB_task_struct *restrict TaskList, // array of structs
35 const int C_ntasks, // # of tasks
36 const int C_nthreads, // # of threads to use
37 // analysis from phase0:
38 const int64_t *restrict C_to_M,
39 const int64_t *restrict C_to_A,
40 const int64_t *restrict C_to_B,
41 const int C_sparsity,
42 // from GB_emult_sparsity or GB_add_sparsity:
43 const int ewise_method,
44 // from GB_emult_03 and GB_emult_02:
45 const int64_t *restrict Cp_kfirst,
46 // to slice M, A, and/or B,
47 const int64_t *M_ek_slicing, const int M_ntasks, const int M_nthreads,
48 const int64_t *A_ek_slicing, const int A_ntasks, const int A_nthreads,
49 const int64_t *B_ek_slicing, const int B_ntasks, const int B_nthreads,
50 // original input:
51 const GrB_Matrix M, // optional mask, may be NULL
52 const bool Mask_struct, // if true, use the only structure of M
53 const bool Mask_comp, // if true, use !M
54 const GrB_Matrix A,
55 const GrB_Matrix B,
56 GB_Context Context
57 )
58 {
59
60 //--------------------------------------------------------------------------
61 // check inputs
62 //--------------------------------------------------------------------------
63
64 ASSERT (C != NULL && C->static_header) ;
65 ASSERT_MATRIX_OK_OR_NULL (M, "M for ewise generic", GB0) ;
66 ASSERT_MATRIX_OK (A, "A for ewise generic", GB0) ;
67 ASSERT_MATRIX_OK (B, "B for ewise generic", GB0) ;
68 ASSERT_BINARYOP_OK (op, "op for ewise generic", GB0) ;
69
70 //--------------------------------------------------------------------------
71 // get C
72 //--------------------------------------------------------------------------
73
74 const GrB_Type ctype = C->type ;
75 const GB_Type_code ccode = ctype->code ;
76
77 //--------------------------------------------------------------------------
78 // get the opcode and define the typecasting functions
79 //--------------------------------------------------------------------------
80
81 GB_Opcode opcode = op->opcode ;
82
83 // the following booleans are all false if flipxy is true, since flipxy has
84 // already been handled in the caller, in this case.
85 const bool op_is_positional = GB_OPCODE_IS_POSITIONAL (opcode) ;
86 const bool op_is_first = (opcode == GB_FIRST_opcode) ;
87 const bool op_is_second = (opcode == GB_SECOND_opcode) ;
88 const bool op_is_pair = (opcode == GB_PAIR_opcode) ;
89 const bool A_is_pattern = (op_is_second || op_is_pair || op_is_positional) ;
90 const bool B_is_pattern = (op_is_first || op_is_pair || op_is_positional) ;
91
92 // if flipxy true use fop(y,x) else fop(x,y)
93 // const bool flipxy = (ewise_method < 0) ; TODO
94 const bool flipxy = (ewise_method == GB_EMULT_METHOD_02B) ;
95
96 const GxB_binary_function fop = op->function ; // NULL if op positional
97 const size_t csize = ctype->size ;
98 const size_t asize = A->type->size ;
99 const size_t bsize = B->type->size ;
100 const GrB_Type xtype = flipxy ? op->ytype : op->xtype ;
101 const GrB_Type ytype = flipxy ? op->xtype : op->ytype ;
102
103 const size_t xsize = (A_is_pattern) ? 1 : xtype->size ;
104 const size_t ysize = (B_is_pattern) ? 1 : ytype->size ;
105 const size_t zsize = op->ztype->size ;
106
107 const GB_cast_function cast_A_to_X =
108 (A_is_pattern) ? NULL : GB_cast_factory (xtype->code, A->type->code) ;
109
110 const GB_cast_function cast_B_to_Y =
111 (B_is_pattern) ? NULL : GB_cast_factory (ytype->code, B->type->code) ;
112
113 const GB_cast_function cast_Z_to_C =
114 GB_cast_factory (ccode, op->ztype->code) ;
115
116 // aij = (xtype) A(i,j), located in Ax [pA]
117 #define GB_GETA(aij,Ax,pA) \
118 GB_void aij [GB_VLA(xsize)] ; \
119 if (cast_A_to_X != NULL) \
120 { \
121 cast_A_to_X (aij, Ax +((pA)*asize), asize) ; \
122 }
123
124 // bij = (ytype) B(i,j), located in Bx [pB]
125 #define GB_GETB(bij,Bx,pB) \
126 GB_void bij [GB_VLA(ysize)] ; \
127 if (cast_B_to_Y != NULL) \
128 { \
129 cast_B_to_Y (bij, Bx +((pB)*bsize), bsize) ; \
130 }
131
132 // address of Cx [p]
133 #define GB_CX(p) Cx +((p)*csize)
134
135 #define GB_ATYPE GB_void
136 #define GB_BTYPE GB_void
137 #define GB_CTYPE GB_void
138
139 #define GB_PHASE_2_OF_2
140
141 // loops cannot be vectorized
142 #define GB_PRAGMA_SIMD_VECTORIZE ;
143
144 // flipxy is handled in the definition of GB_BINOP, not in the tempate
145 #define GB_FLIPPED 0
146
147 //--------------------------------------------------------------------------
148 // do the ewise operation
149 //--------------------------------------------------------------------------
150
151 if (op_is_positional)
152 {
153
154 //----------------------------------------------------------------------
155 // C(i,j) = positional_op (aij, bij)
156 //----------------------------------------------------------------------
157
158 const int64_t offset = GB_positional_offset (opcode) ;
159 const bool index_is_i =
160 (opcode == GB_FIRSTI_opcode ) || (opcode == GB_FIRSTI1_opcode ) ||
161 (opcode == GB_SECONDI_opcode ) || (opcode == GB_SECONDI1_opcode) ;
162
163 if (op->ztype == GrB_INT64)
164 {
165 #undef GB_BINOP
166 #define GB_BINOP(cij, aij, bij, i, j) \
167 int64_t z = ((index_is_i) ? i : j) + offset ; \
168 cast_Z_to_C (cij, &z, csize) ;
169 if (ewise_method == GB_EMULT_METHOD_02A ||
170 ewise_method == GB_EMULT_METHOD_02B)
171 {
172 #include "GB_emult_02_template.c"
173 }
174 else if (ewise_method == GB_EMULT_METHOD_03)
175 {
176 #include "GB_emult_03_template.c"
177 }
178 else if (C_sparsity == GxB_BITMAP)
179 {
180 #include "GB_bitmap_emult_template.c"
181 }
182 else
183 {
184 #include "GB_emult_01_meta.c"
185 }
186 }
187 else
188 {
189 #undef GB_BINOP
190 #define GB_BINOP(cij, aij, bij, i, j) \
191 int32_t z = (int32_t) (((index_is_i) ? i : j) + offset) ; \
192 cast_Z_to_C (cij, &z, csize) ;
193 if (ewise_method == GB_EMULT_METHOD_02A ||
194 ewise_method == GB_EMULT_METHOD_02B)
195 {
196 #include "GB_emult_02_template.c"
197 }
198 else if (ewise_method == GB_EMULT_METHOD_03)
199 {
200 #include "GB_emult_03_template.c"
201 }
202 else if (C_sparsity == GxB_BITMAP)
203 {
204 #include "GB_bitmap_emult_template.c"
205 }
206 else
207 {
208 #include "GB_emult_01_meta.c"
209 }
210 }
211
212 }
213 else
214 {
215
216 //----------------------------------------------------------------------
217 // standard binary operator
218 //----------------------------------------------------------------------
219
220 // C(i,j) = (ctype) (A(i,j) + B(i,j))
221 if (ewise_method == GB_EMULT_METHOD_02A ||
222 ewise_method == GB_EMULT_METHOD_02B)
223 {
224 // handle flipxy
225 #undef GB_BINOP
226 #define GB_BINOP(cij, aij, bij, i, j) \
227 GB_void z [GB_VLA(zsize)] ; \
228 if (flipxy) \
229 { \
230 fop (z, bij, aij) ; \
231 } \
232 else \
233 { \
234 fop (z, aij, bij) ; \
235 } \
236 cast_Z_to_C (cij, z, csize) ;
237 #include "GB_emult_02_template.c"
238 }
239 else if (ewise_method == GB_EMULT_METHOD_03)
240 {
241 #undef GB_BINOP
242 #define GB_BINOP(cij, aij, bij, i, j) \
243 GB_void z [GB_VLA(zsize)] ; \
244 fop (z, aij, bij) ; \
245 cast_Z_to_C (cij, z, csize) ;
246 #include "GB_emult_03_template.c"
247 }
248 else if (C_sparsity == GxB_BITMAP)
249 {
250 #include "GB_bitmap_emult_template.c"
251 }
252 else
253 {
254 #include "GB_emult_01_meta.c"
255 }
256 }
257
258 ASSERT_MATRIX_OK (C, "C from ewise generic", GB0) ;
259 }
260
261