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