| 337 | } |
| 338 | |
| 339 | bool mul_q8_sme_possible(const ITensorInfo *src0, const ITensorInfo *src1, const ITensorInfo *dst, float scale) |
| 340 | { |
| 341 | ARM_COMPUTE_UNUSED(src0, src1, dst, scale); |
| 342 | #ifdef ARM_COMPUTE_ENABLE_SME2 |
| 343 | const auto &in0_shape = src0->tensor_shape(); |
| 344 | const auto &in1_shape = src1->tensor_shape(); |
| 345 | const unsigned int dst_dims = dst->num_dimensions(); |
| 346 | |
| 347 | // Calculate Scale |
| 348 | const auto iq0 = src0->quantization_info().uniform(); |
| 349 | const auto iq1 = src1->quantization_info().uniform(); |
| 350 | const auto oq = dst->quantization_info().uniform(); |
| 351 | const auto multiplier = ((iq0.scale * iq1.scale) / oq.scale) * scale; |
| 352 | const auto max_result = multiplier * (127) * (127) + static_cast<float>(oq.offset); |
| 353 | const auto min_result = multiplier * (-128) * (-128) + static_cast<float>(oq.offset); |
| 354 | |
| 355 | // Does not support broadcasting on x |
| 356 | // Does not support dims > 4D output, unless input shapes are identical (therefore collapsible) |
| 357 | // Checks whether CPU has SME2 Available |
| 358 | if (in0_shape.x() == in1_shape.x() && CPUInfo::get().has_sme2() && (in0_shape == in1_shape || dst_dims <= 4)) |
| 359 | { |
| 360 | // Check if multiplier cannot be stored as a 14.18 signed fixed-point number |
| 361 | if (multiplier < -8191.f || multiplier > 8191.f) |
| 362 | { |
| 363 | return false; |
| 364 | } |
| 365 | // It might not be possible to store the result as a 14.18 signed fixed-point number. |
| 366 | if (max_result > 8191.f || min_result < -8191.f) |
| 367 | { |
| 368 | return false; |
| 369 | } |
| 370 | // Passed all checks |
| 371 | return true; |
| 372 | } |
| 373 | #endif // ARM_COMPUTE_ENABLE_SME2 |
| 374 | return false; |
| 375 | } |
| 376 | |
| 377 | bool mul_q8_neon_fixedpoint_possible(const ITensorInfo *src0, |
| 378 | const ITensorInfo *src1, |
no test coverage detected