Compute Library
 23.11
IAccessWindow.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017-2018 Arm Limited.
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
25 
29 
30 using namespace arm_compute;
31 
33  const ValidRegion &input_valid_region) const
34 {
35  return compute_valid_region(window, input_valid_region, false, BorderSize(0));
36 }
37 
39  ValidRegion input_valid_region,
40  bool border_undefined,
41  BorderSize border_size) const
42 {
43  if (_info == nullptr)
44  {
45  return input_valid_region;
46  }
47 
48  Coordinates &anchor = input_valid_region.anchor;
49  Coordinates old_anchor(anchor);
50  TensorShape &shape = input_valid_region.shape;
51 
52  if (!border_undefined)
53  {
54  border_size = BorderSize(0);
55  }
56 
57  // Start of the valid region is equal to the start of the window. But it
58  // cannot be less than the start of the input's valid region plus the border
59  // size required by this kernel (if undefined).
60  // Additionally the valid region is shifted by the offset that is used by
61  // the kernel to write back output values.
62  anchor.set(0, std::max<int>(window.x().start() * _scale_x, anchor[0] + border_size.left) + _x);
63  if (_info->num_dimensions() > 1)
64  {
65  anchor.set(1, std::max<int>(window.y().start() * _scale_y, anchor[1] + border_size.top) + _y);
66  }
67 
68  // End of the valid region is equal to the start of the last write of the
69  // kernel plus the number of written elements. (This assumes that all
70  // written elements are valid). Nevertheless the end cannot be larger than
71  // the end of the input's valid region minus the border size.
72  // Note: not the end points of the region are stored but its size. Thus the
73  // old size is first converted into end points to compared against the
74  // execution window. Afterwards the new end points are converted back into
75  // a size of the region.
76  shape.set(0, std::min<int>(old_anchor[0] + shape[0] - border_size.right,
77  (window.x().end() - window.x().step()) * _scale_x + _width) -
78  anchor[0]);
79  if (_info->num_dimensions() > 1)
80  {
81  shape.set(1, std::min<int>(old_anchor[1] + shape[1] - border_size.bottom,
82  (window.y().end() - window.y().step()) * _scale_y + _height) -
83  anchor[1]);
84  }
85 
86  // For higher dimensions use the intersection of the window size and the
87  // valid region of the input
88  for (size_t d = 2; d < _info->num_dimensions(); ++d)
89  {
90  anchor.set(d, std::max(window[d].start(), input_valid_region.anchor[d]));
91  shape.set(d, std::min<int>(window[d].end(), input_valid_region.shape[d]) - anchor[d]);
92  }
93 
94  return input_valid_region;
95 }
96 
98  const ValidRegion &input_valid_region,
99  bool border_undefined,
100  const BorderSize &border_size)
101 {
102  if (_info != nullptr)
103  {
104  _info->set_valid_region(compute_valid_region(window, input_valid_region, border_undefined, border_size));
105  }
106 }
107 
109 {
110  // Only update the window size if we can't use padding
111  if (_info == nullptr || _info->is_resizable())
112  {
113  return false;
114  }
115 
116  PaddingSize needed = get_needed_padding(window);
117  PaddingSize available = _info->padding();
118 
119  if (needed.top <= available.top && needed.right <= available.right && needed.bottom <= available.bottom &&
120  needed.left <= available.left)
121  {
122  return false;
123  }
124 
125  const TensorShape &shape = _info->tensor_shape();
126  const Strides &strides = _info->strides_in_bytes();
127  const size_t offset_first_element = _info->offset_first_element_in_bytes();
128 
129  bool window_modified = false;
130 
131  int front_pad_y = 0;
132 
133  const int min_y = window.y().start() * _scale_y + _y;
134  const int max_y = (window.y().end() - window.y().step()) * _scale_y + _y + _height;
135 
136  // Adjust window start for Y dimension
137  if (min_y < 0)
138  {
139  // Calculate rows available above the tensor
140  const int front_pad_y_available = -static_cast<int>(offset_first_element / strides[1]);
141 
142  if (min_y < front_pad_y_available)
143  {
144  // Not enough padding available, need to shrink the window
145  int start = adjust_up(min_y, front_pad_y_available, window.y().step() * _scale_y) - _y;
146  start = std::min<int>(start / _scale_y, window.y().end());
147 
148  window.set(1, Window::Dimension(start, window.y().end(), window.y().step()));
149  window_modified = true;
150  }
151 
152  // Update front padding with reconstructed value
153  front_pad_y = std::max(0, static_cast<int>(std::floor(-window.y().start() * _scale_y)) - _y);
154  }
155 
156  // Adjust window end for Y dimension
157  if (max_y > static_cast<int>(shape[1]))
158  {
159  const int stride_z = _info->num_dimensions() > 2 ? strides[2] : _info->total_size();
160 
161  // Calculate rows available below the tensor
162  const int tail_pad_y_available = (stride_z / strides[1]) - shape[1] - front_pad_y;
163 
164  if (static_cast<int>(shape[1]) + tail_pad_y_available < max_y)
165  {
166  // Not enough padding available, need to shrink the window
167  int end = adjust_down(max_y, shape[1] + tail_pad_y_available, window.y().step() * _scale_y) +
168  window.y().step() * _scale_y - _y - _height;
169  end = std::max<int>(window.y().start(), end / _scale_y);
170 
171  window.set(1, Window::Dimension(window.y().start(), end, window.y().step()));
172  window_modified = true;
173  }
174  }
175 
176  int front_pad_x = 0;
177 
178  const int min_x = window.x().start() * _scale_x + _x;
179  const int max_x = (window.x().end() - window.x().step()) * _scale_x + _x + _width;
180 
181  const int stride_y = _info->num_dimensions() > 1 ? strides[1] : _info->total_size();
182 
183  // Adjust window start for X dimension
184  if (min_x < 0)
185  {
186  const int front_pad_x_available =
187  -std::min<int>(static_cast<int>(offset_first_element) - front_pad_y * strides[1],
188  stride_y - shape[0] * strides[0]) /
189  static_cast<int>(strides[0]);
190 
191  if (min_x < front_pad_x_available)
192  {
193  // Not enough padding available, need to shrink the window
194  int start = adjust_up(min_x, front_pad_x_available, window.x().step() * _scale_x) - _x;
195  start = std::min<int>(start / _scale_x, window.x().end());
196 
197  window.set(0, Window::Dimension(start, window.x().end(), window.x().step()));
198  window_modified = true;
199  }
200 
201  // Update front padding with reconstructed value
202  front_pad_x = std::max(0, static_cast<int>(std::floor(-window.x().start() * _scale_x)) - _x);
203  }
204 
205  // Adjust window end for X dimension
206  if (max_x > static_cast<int>(shape[0]))
207  {
208  const int tail_pad_x_available = (stride_y / strides[0]) - shape[0] - front_pad_x;
209 
210  if (static_cast<int>(shape[0]) + tail_pad_x_available < max_x)
211  {
212  // Not enough padding available, need to shrink the window
213  int end = adjust_down(max_x, shape[0] + tail_pad_x_available, window.x().step() * _scale_x) +
214  window.x().step() * _scale_x - _x - _width;
215  end = std::max<int>(window.x().start(), end / _scale_x);
216 
217  window.set(0, Window::Dimension(window.x().start(), end, window.x().step()));
218  window_modified = true;
219  }
220  }
221 
222  window.validate();
223 
224  return window_modified;
225 }
226 
228 {
229  // Only update the padding if the tensor allows it
230  if (_info == nullptr || !_info->is_resizable())
231  {
232  return false;
233  }
234  // Update strides in tensor info
235  return _info->extend_padding(get_needed_padding(window));
236 }
237 
238 PaddingSize AccessWindowRectangle::get_needed_padding(const Window &window) const
239 {
240  ARM_COMPUTE_ERROR_ON(_scale_x == 0);
241  ARM_COMPUTE_ERROR_ON(_scale_y == 0);
242 
243  const int min_x = window.x().start() * _scale_x + _x;
244  const int max_x = (window.x().end() - window.x().step()) * _scale_x + _x + _width;
245  const int min_y = window.y().start() * _scale_y + _y;
246  const int max_y = (window.y().end() - window.y().step()) * _scale_y + _y + _height;
247 
248  const TensorShape &shape = _info->tensor_shape();
249 
250  PaddingSize padding;
251  padding.left = std::max(0, -min_x);
252  padding.right = std::max<int>(0, max_x - shape[0]);
253  padding.top = std::max(0, -min_y);
254  padding.bottom = std::max<int>(0, max_y - shape[1]);
255 
256  return padding;
257 }
arm_compute::BorderSize::right
unsigned int right
right of the border
Definition: Types.h:340
arm_compute::Window::Dimension::start
constexpr int start() const
Return the start of the dimension.
Definition: Window.h:96
arm_compute::ITensorInfo::tensor_shape
virtual const TensorShape & tensor_shape() const =0
Size for each dimension of the tensor.
arm_compute::Dimensions::set
void set(size_t dimension, T value, bool increase_dim_unit=true)
Accessor to set the value of one of the dimensions.
Definition: Dimensions.h:75
Helpers.h
arm_compute::BorderSize
Container for 2D border size.
Definition: Types.h:239
arm_compute::Window::Dimension::step
constexpr int step() const
Return the step of the dimension.
Definition: Window.h:106
arm_compute::TensorShape
Shape of a tensor.
Definition: TensorShape.h:39
arm_compute::ITensorInfo::extend_padding
virtual bool extend_padding(const PaddingSize &padding)=0
Update the offset to the first element, the strides and the total size.
arm_compute::AccessWindowRectangle::compute_valid_region
ValidRegion compute_valid_region(const Window &window, const ValidRegion &input_valid_region) const
Compute the valid region based on access pattern, valid region of the inputs and border mode.
Definition: IAccessWindow.cpp:32
Window.h
arm_compute::BorderSize::top
unsigned int top
top of the border
Definition: Types.h:339
TensorInfo.h
arm_compute::Strides
Strides of an item in bytes.
Definition: Strides.h:38
arm_compute::test::validation::shape
shape
Definition: DFT.cpp:115
ARM_COMPUTE_ERROR_ON
#define ARM_COMPUTE_ERROR_ON(cond)
If the condition is true then an error message is printed and an exception thrown.
Definition: Error.h:466
arm_compute::BorderSize::bottom
unsigned int bottom
bottom of the border
Definition: Types.h:341
arm_compute::ValidRegion
Container for valid region of a window.
Definition: Types.h:143
arm_compute::Window::y
constexpr const Dimension & y() const
Alias to access the second dimension of the window.
Definition: Window.h:167
arm_compute::Window::validate
void validate() const
Will validate all the window's dimensions' values when asserts are enabled.
Definition: Window.inl:187
arm_compute::adjust_up
int adjust_up(int required, int available, int step)
Increase required in steps of step until it's greater than available.
Definition: IAccessWindow.h:63
arm_compute::AccessWindowRectangle::update_window_if_needed
bool update_window_if_needed(Window &window) const override
Shrink the window if padding is not large enough.
Definition: IAccessWindow.cpp:108
arm_compute::Coordinates
Coordinates of an item.
Definition: Coordinates.h:37
arm_compute::Window::Dimension
Describe one of the image's dimensions with a start, end and step.
Definition: Window.h:79
arm_compute::Window::set
void set(size_t dimension, const Dimension &dim)
Set the values of a given dimension.
Definition: Window.inl:53
arm_compute::AccessWindowRectangle::update_padding_if_needed
bool update_padding_if_needed(const Window &window) override
Increase the padding to be large enough for the window.
Definition: IAccessWindow.cpp:227
arm_compute::ITensorInfo::is_resizable
virtual bool is_resizable() const =0
Flag indicating whether the size of the tensor can be changed.
arm_compute::Window
Describe a multidimensional execution window.
Definition: Window.h:39
arm_compute::ValidRegion::shape
TensorShape shape
Shape of the valid region.
Definition: Types.h:223
arm_compute
Copyright (c) 2017-2023 Arm Limited.
Definition: introduction.dox:24
arm_compute::ITensorInfo::set_valid_region
virtual void set_valid_region(const ValidRegion &valid_region)=0
Set the valid region of the tensor.
arm_compute::adjust_down
int adjust_down(int required, int available, int step)
Decrease required in steps of step until it's less than available.
Definition: IAccessWindow.h:47
arm_compute::BorderSize::left
unsigned int left
left of the border
Definition: Types.h:342
arm_compute::ITensorInfo::offset_first_element_in_bytes
virtual size_t offset_first_element_in_bytes() const =0
The offset from the beginning of the memory allocation to the first element of the tensor.
arm_compute::ITensorInfo::strides_in_bytes
virtual const Strides & strides_in_bytes() const =0
The strides in bytes for accessing each dimension of the tensor.
arm_compute::mlgo::parser::end
void end(TokenStream &in, bool &valid)
Definition: MLGOParser.cpp:283
arm_compute::Window::Dimension::end
constexpr int end() const
Return the end of the dimension.
Definition: Window.h:101
IAccessWindow.h
arm_compute::AccessWindowRectangle::set_valid_region
void set_valid_region(const Window &window, const ValidRegion &input_valid_region, bool border_undefined=false, const BorderSize &border_size=BorderSize(0))
Set the valid region based on access pattern, valid region of the inputs and border mode.
Definition: IAccessWindow.cpp:97
arm_compute::Window::x
constexpr const Dimension & x() const
Alias to access the first dimension of the window.
Definition: Window.h:158
arm_compute::ITensorInfo::total_size
virtual size_t total_size() const =0
Returns the total size of the tensor in bytes.
arm_compute::ITensorInfo::num_dimensions
virtual size_t num_dimensions() const =0
The number of dimensions of the tensor (rank)
arm_compute::ValidRegion::anchor
Coordinates anchor
Anchor for the start of the valid region.
Definition: Types.h:222
arm_compute::ITensorInfo::padding
virtual PaddingSize padding() const =0
Padding of tensor.