| 172 | |
| 173 | template<typename T> |
| 174 | void gemm(Array<T> &out, af_mat_prop optLhs, af_mat_prop optRhs, const T *alpha, |
| 175 | const Array<T> &lhs, const Array<T> &rhs, const T *beta) { |
| 176 | using BT = typename blas_base<T>::type; |
| 177 | using CBT = const typename blas_base<T>::type; |
| 178 | |
| 179 | const CBLAS_TRANSPOSE lOpts = toCblasTranspose(optLhs); |
| 180 | const CBLAS_TRANSPOSE rOpts = toCblasTranspose(optRhs); |
| 181 | |
| 182 | const int aRowDim = (lOpts == CblasNoTrans) ? 0 : 1; |
| 183 | const int aColDim = (lOpts == CblasNoTrans) ? 1 : 0; |
| 184 | const int bColDim = (rOpts == CblasNoTrans) ? 1 : 0; |
| 185 | |
| 186 | const dim4 &lDims = lhs.dims(); |
| 187 | const dim4 &rDims = rhs.dims(); |
| 188 | const int M = lDims[aRowDim]; |
| 189 | const int N = rDims[bColDim]; |
| 190 | const int K = lDims[aColDim]; |
| 191 | const dim4 &oDims = out.dims(); |
| 192 | |
| 193 | dim4 lStrides = lhs.strides(); |
| 194 | dim4 rStrides = rhs.strides(); |
| 195 | dim4 oStrides = out.strides(); |
| 196 | |
| 197 | int batchSize = oDims[2] * oDims[3]; |
| 198 | |
| 199 | bool is_l_d2_batched = (oDims[2] == lDims[2]); |
| 200 | bool is_l_d3_batched = (oDims[3] == lDims[3]); |
| 201 | bool is_r_d2_batched = (oDims[2] == rDims[2]); |
| 202 | bool is_r_d3_batched = (oDims[3] == rDims[3]); |
| 203 | |
| 204 | // get host pointers from mapped memory |
| 205 | mapped_ptr<T> lPtr = lhs.getMappedPtr(CL_MAP_READ); |
| 206 | mapped_ptr<T> rPtr = rhs.getMappedPtr(CL_MAP_READ); |
| 207 | mapped_ptr<T> oPtr = out.getMappedPtr(CL_MAP_READ | CL_MAP_WRITE); |
| 208 | |
| 209 | for (int n = 0; n < batchSize; ++n) { |
| 210 | int w = n / oDims[2]; |
| 211 | int z = n - w * oDims[2]; |
| 212 | |
| 213 | int loff = z * (is_l_d2_batched * lStrides[2]) + |
| 214 | w * (is_l_d3_batched * lStrides[3]); |
| 215 | int roff = z * (is_r_d2_batched * rStrides[2]) + |
| 216 | w * (is_r_d3_batched * rStrides[3]); |
| 217 | |
| 218 | CBT *lptr = reinterpret_cast<CBT *>(lPtr.get() + loff); |
| 219 | CBT *rptr = reinterpret_cast<CBT *>(rPtr.get() + roff); |
| 220 | BT *optr = reinterpret_cast<BT *>(oPtr.get() + z * oStrides[2] + |
| 221 | w * oStrides[3]); |
| 222 | |
| 223 | if (rDims[bColDim] == 1) { |
| 224 | dim_t incr = (rOpts == CblasNoTrans) ? rStrides[0] : rStrides[1]; |
| 225 | gemv_func<T>()(CblasColMajor, lOpts, lDims[0], lDims[1], |
| 226 | getOneScalar<T>(alpha), lptr, lStrides[1], rptr, |
| 227 | incr, getOneScalar<T>(beta), optr, 1); |
| 228 | } else { |
| 229 | gemm_func<T>()(CblasColMajor, lOpts, rOpts, M, N, K, |
| 230 | getOneScalar<T>(alpha), lptr, lStrides[1], rptr, |
| 231 | rStrides[1], getOneScalar<T>(beta), optr, |
nothing calls this directly
no test coverage detected