aboutsummaryrefslogtreecommitdiff
path: root/src/core/NEON/kernels/NEMinMaxLocationKernel.cpp
diff options
context:
space:
mode:
authorMichele Di Giorgio <michele.digiorgio@arm.com>2017-07-04 17:19:43 +0100
committerAnthony Barbier <anthony.barbier@arm.com>2018-09-17 14:16:42 +0100
commitef4b4ae784f7533ed6d9e7b51827a894c32ed48e (patch)
tree6f4268044be18c003f5136b8ef7c7c07e219f2bd /src/core/NEON/kernels/NEMinMaxLocationKernel.cpp
parentf87cc7f6fef95f9b022725304118796a6a764a7c (diff)
downloadComputeLibrary-ef4b4ae784f7533ed6d9e7b51827a894c32ed48e.tar.gz
COMPMID-438: Add support for floating point Min-Max Location layer.
Change-Id: I84ae564a40fc7320a6f94a84d53906ba51404f51 Reviewed-on: http://mpd-gerrit.cambridge.arm.com/79797 Reviewed-by: Anthony Barbier <anthony.barbier@arm.com> Tested-by: Kaizen <jeremy.johnson+kaizengerrit@arm.com>
Diffstat (limited to 'src/core/NEON/kernels/NEMinMaxLocationKernel.cpp')
-rw-r--r--src/core/NEON/kernels/NEMinMaxLocationKernel.cpp141
1 files changed, 114 insertions, 27 deletions
diff --git a/src/core/NEON/kernels/NEMinMaxLocationKernel.cpp b/src/core/NEON/kernels/NEMinMaxLocationKernel.cpp
index 1e41ddcf80..a6da7f415d 100644
--- a/src/core/NEON/kernels/NEMinMaxLocationKernel.cpp
+++ b/src/core/NEON/kernels/NEMinMaxLocationKernel.cpp
@@ -41,14 +41,14 @@
namespace arm_compute
{
NEMinMaxKernel::NEMinMaxKernel()
- : _func(), _input(nullptr), _min(), _max(), _min_init(), _max_init(), _mtx()
+ : _func(), _input(nullptr), _min(), _max(), _mtx()
{
}
-void NEMinMaxKernel::configure(const IImage *input, int32_t *min, int32_t *max)
+void NEMinMaxKernel::configure(const IImage *input, void *min, void *max)
{
ARM_COMPUTE_ERROR_ON_TENSOR_NOT_2D(input);
- ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::U8, DataType::S16);
+ ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::U8, DataType::S16, DataType::F32);
ARM_COMPUTE_ERROR_ON(nullptr == min);
ARM_COMPUTE_ERROR_ON(nullptr == max);
@@ -56,20 +56,19 @@ void NEMinMaxKernel::configure(const IImage *input, int32_t *min, int32_t *max)
_min = min;
_max = max;
- switch(input->info()->format())
+ switch(_input->info()->data_type())
{
- case Format::U8:
- _min_init = UCHAR_MAX;
- _max_init = 0;
- _func = &NEMinMaxKernel::minmax_U8;
+ case DataType::U8:
+ _func = &NEMinMaxKernel::minmax_U8;
break;
- case Format::S16:
- _min_init = SHRT_MAX;
- _max_init = SHRT_MIN;
- _func = &NEMinMaxKernel::minmax_S16;
+ case DataType::S16:
+ _func = &NEMinMaxKernel::minmax_S16;
+ break;
+ case DataType::F32:
+ _func = &NEMinMaxKernel::minmax_F32;
break;
default:
- ARM_COMPUTE_ERROR("You called with the wrong img formats");
+ ARM_COMPUTE_ERROR("Unsupported data type");
break;
}
@@ -93,8 +92,24 @@ void NEMinMaxKernel::run(const Window &window)
void NEMinMaxKernel::reset()
{
ARM_COMPUTE_ERROR_ON_UNCONFIGURED_KERNEL(this);
- *_min = _min_init;
- *_max = _max_init;
+ switch(_input->info()->data_type())
+ {
+ case DataType::U8:
+ *static_cast<int32_t *>(_min) = UCHAR_MAX;
+ *static_cast<int32_t *>(_max) = 0;
+ break;
+ case DataType::S16:
+ *static_cast<int32_t *>(_min) = SHRT_MAX;
+ *static_cast<int32_t *>(_max) = SHRT_MIN;
+ break;
+ case DataType::F32:
+ *static_cast<float *>(_min) = std::numeric_limits<float>::max();
+ *static_cast<float *>(_max) = std::numeric_limits<float>::lowest();
+ break;
+ default:
+ ARM_COMPUTE_ERROR("Unsupported data type");
+ break;
+ }
}
template <typename T>
@@ -102,14 +117,19 @@ void NEMinMaxKernel::update_min_max(const T min, const T max)
{
std::lock_guard<std::mutex> lock(_mtx);
- if(min < *_min)
+ using type = typename std::conditional<std::is_same<T, float>::value, float, int32_t>::type;
+
+ auto min_ptr = static_cast<type *>(_min);
+ auto max_ptr = static_cast<type *>(_max);
+
+ if(min < *min_ptr)
{
- *_min = min;
+ *min_ptr = min;
}
- if(max > *_max)
+ if(max > *max_ptr)
{
- *_max = max;
+ *max_ptr = max;
}
}
@@ -229,6 +249,65 @@ void NEMinMaxKernel::minmax_S16(Window win)
update_min_max(min_i, max_i);
}
+void NEMinMaxKernel::minmax_F32(Window win)
+{
+ float32x2_t carry_min = vdup_n_f32(std::numeric_limits<float>::max());
+ float32x2_t carry_max = vdup_n_f32(std::numeric_limits<float>::lowest());
+
+ float carry_min_scalar = std::numeric_limits<float>::max();
+ float carry_max_scalar = std::numeric_limits<float>::lowest();
+
+ const int x_start = win.x().start();
+ const int x_end = win.x().end();
+
+ // Handle X dimension manually to split into two loops
+ // First one will use vector operations, second one processes the left over pixels
+ win.set(Window::DimX, Window::Dimension(0, 1, 1));
+
+ Iterator input(_input, win);
+
+ execute_window_loop(win, [&](const Coordinates & id)
+ {
+ int x = x_start;
+ const auto in_ptr = reinterpret_cast<const float *const>(input.ptr());
+
+ // Vector loop
+ for(; x <= x_end - 8; x += 8)
+ {
+ const float32x4x2_t pixels = vld2q_f32(in_ptr + x);
+ const float32x4_t tmp_min1 = vminq_f32(pixels.val[0], pixels.val[1]);
+ const float32x4_t tmp_max1 = vmaxq_f32(pixels.val[0], pixels.val[1]);
+ const float32x2_t tmp_min2 = vmin_f32(vget_high_f32(tmp_min1), vget_low_f32(tmp_min1));
+ const float32x2_t tmp_max2 = vmax_f32(vget_high_f32(tmp_max1), vget_low_f32(tmp_max1));
+ carry_min = vmin_f32(tmp_min2, carry_min);
+ carry_max = vmax_f32(tmp_max2, carry_max);
+ }
+
+ // Process leftover pixels
+ for(; x < x_end; ++x)
+ {
+ const float pixel = in_ptr[x];
+ carry_min_scalar = std::min(pixel, carry_min_scalar);
+ carry_max_scalar = std::max(pixel, carry_max_scalar);
+ }
+
+ },
+ input);
+
+ // Reduce result
+ carry_min = vpmin_f32(carry_min, carry_min);
+ carry_max = vpmax_f32(carry_max, carry_max);
+ carry_min = vpmin_f32(carry_min, carry_min);
+ carry_max = vpmax_f32(carry_max, carry_max);
+
+ // Extract max/min values
+ const float min_i = std::min(vget_lane_f32(carry_min, 0), carry_min_scalar);
+ const float max_i = std::max(vget_lane_f32(carry_max, 0), carry_max_scalar);
+
+ // Perform reduction of local min/max values
+ update_min_max(min_i, max_i);
+}
+
NEMinMaxLocationKernel::NEMinMaxLocationKernel()
: _func(nullptr), _input(nullptr), _min(nullptr), _max(nullptr), _min_count(nullptr), _max_count(nullptr), _min_loc(nullptr), _max_loc(nullptr)
{
@@ -271,12 +350,12 @@ const NEMinMaxLocationKernel::MinMaxLocFunction NEMinMaxLocationKernel::create_f
&NEMinMaxLocationKernel::minmax_loc<T, bool(N & 8), bool(N & 4), bool(N & 2), bool(N & 1)>...
};
-void NEMinMaxLocationKernel::configure(const IImage *input, int32_t *min, int32_t *max,
+void NEMinMaxLocationKernel::configure(const IImage *input, void *min, void *max,
ICoordinates2DArray *min_loc, ICoordinates2DArray *max_loc,
uint32_t *min_count, uint32_t *max_count)
{
ARM_COMPUTE_ERROR_ON_TENSOR_NOT_2D(input);
- ARM_COMPUTE_ERROR_ON_FORMAT_NOT_IN(input, Format::U8, Format::S16);
+ ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::U8, DataType::S16, DataType::F32);
ARM_COMPUTE_ERROR_ON(nullptr == min);
ARM_COMPUTE_ERROR_ON(nullptr == max);
@@ -295,16 +374,19 @@ void NEMinMaxLocationKernel::configure(const IImage *input, int32_t *min, int32_
unsigned int table_idx = (count_min << 3) | (count_max << 2) | (loc_min << 1) | loc_max;
- switch(input->info()->format())
+ switch(input->info()->data_type())
{
- case Format::U8:
+ case DataType::U8:
_func = create_func_table<uint8_t, gen_index_seq<16>::type>::func_table[table_idx];
break;
- case Format::S16:
+ case DataType::S16:
_func = create_func_table<int16_t, gen_index_seq<16>::type>::func_table[table_idx];
break;
+ case DataType::F32:
+ _func = create_func_table<float, gen_index_seq<16>::type>::func_table[table_idx];
+ break;
default:
- ARM_COMPUTE_ERROR("You called with the wrong img formats");
+ ARM_COMPUTE_ERROR("Unsupported data type");
break;
}
@@ -349,6 +431,11 @@ void NEMinMaxLocationKernel::minmax_loc(const Window &win)
_max_loc->clear();
}
+ using type = typename std::conditional<std::is_same<T, float>::value, float, int32_t>::type;
+
+ auto min_ptr = static_cast<type *>(_min);
+ auto max_ptr = static_cast<type *>(_max);
+
execute_window_loop(win, [&](const Coordinates & id)
{
auto in_ptr = reinterpret_cast<const T *>(input.ptr());
@@ -360,7 +447,7 @@ void NEMinMaxLocationKernel::minmax_loc(const Window &win)
if(count_min || loc_min)
{
- if(*_min == pixel)
+ if(*min_ptr == pixel)
{
if(count_min)
{
@@ -376,7 +463,7 @@ void NEMinMaxLocationKernel::minmax_loc(const Window &win)
if(count_max || loc_max)
{
- if(*_max == pixel)
+ if(*max_ptr == pixel)
{
if(count_max)
{