ONE - On-device Neural Engine
Loading...
Searching...
No Matches
luci::sinf Namespace Reference

Data Structures

class  Algorithm
 
struct  Rule
 
struct  StridedSliceContext
 
struct  StridedSliceParams
 
class  TensorShapeExpander
 Create a higher-rank TensorShape following NumPy broadcasting semantics. More...
 

Functions

loco::TensorShape circle_shape (const luci::CircleNode *node)
 
loco::TensorShape broadcast_shape (const loco::TensorShape &x, const loco::TensorShape &y)
 
loco::TensorShape pad_shape (const loco::TensorShape &input_shape, const luci::CircleNode *paddings)
 
int Clamp (const int32_t v, const int32_t lo, const int32_t hi)
 
int64_t StartForAxis (const StridedSliceParams &params, const loco::TensorShape &input_shape, int64_t axis)
 
int64_t StopForAxis (const StridedSliceParams &params, const loco::TensorShape &input_shape, int64_t axis, int64_t start_for_axis)
 
StridedSliceParams BuildStridedSliceParams (StridedSliceContext *op_context)
 

Variables

const int kMaxDim = 5
 
const loco::DataType S32 = loco::DataType::S32
 

Function Documentation

◆ broadcast_shape()

loco::TensorShape luci::sinf::broadcast_shape ( const loco::TensorShape x,
const loco::TensorShape y 
)

Definition at line 152 of file CircleShapeInferenceHelper.cpp.

153{
154 auto x_match = x;
155 auto y_match = y;
156
157 expand_rank(x_match, y_match);
158
159 auto output_shape = expand_dimension(x_match, y_match);
160
161 return output_shape;
162}
const luci_interpreter::RuntimeShape output_shape

References output_shape.

Referenced by luci::sinf::Algorithm::visit(), luci::sinf::Algorithm::visit(), luci::sinf::Algorithm::visit(), and luci::sinf::Algorithm::visit().

◆ BuildStridedSliceParams()

StridedSliceParams luci::sinf::BuildStridedSliceParams ( StridedSliceContext op_context)

Definition at line 251 of file CircleStridedSlice.cpp.

252{
253 StridedSliceParams op_params;
254
255 // The ellipsis_mask and new_axis_mask in op_params are not used. Those masks
256 // are processed here to update begin_mask, end_mask and the index range.
257 op_params.begin_mask = 0;
258 op_params.ellipsis_mask = 0;
259 op_params.end_mask = 0;
260 op_params.new_axis_mask = 0;
261 op_params.shrink_axis_mask = 0;
262
263 // Count indexes where the new_axis_mask is set but the ellipsis_mask is not.
264 loco::TensorShape begin_shape = circle_shape(op_context->begin);
265 const int64_t begin_count = static_cast<int64_t>(begin_shape.dim(0).value());
266 int64_t num_add_axis = 0;
267 for (int64_t i = 0; i < begin_count; ++i)
268 {
269 if (!((1LL << i) & op_context->params.ellipsis_mask) &&
270 ((1LL << i) & op_context->params.new_axis_mask))
271 {
272 num_add_axis++;
273 }
274 }
275
276 // Calculate the dims of input after adding new axises.
277 const int64_t effective_dims = op_context->input_dims + num_add_axis;
278
279 // If begin, end and strides are not fully provided, it means Ellipsis should
280 // be expanded to multiple dimensions (Ex: for spec [Ellipsis, 2] on a 3D
281 // input, the Ellipsis should be applied for the first 2 dimensions). Besides,
282 // If the new_axis_mask and the ellipsis_mask are set at the same index, the
283 // new_axis_mask will have no effect.
284 int64_t effective_ellipsis_mask = 0, effective_new_axis_mask = 0;
285 int64_t ellipsis_start_idx = effective_dims, expanded_ellipsis = 0;
286 for (int64_t i = 0; i < effective_dims;)
287 {
288 if ((1LL << i) & op_context->params.ellipsis_mask)
289 {
290 ellipsis_start_idx = i;
291 int64_t ellipsis_end_idx =
292 std::max(i + 1, std::min(i + 1 + num_add_axis + op_context->input_dims - begin_count,
293 effective_dims));
294 expanded_ellipsis = ellipsis_end_idx - ellipsis_start_idx - 1;
295
296 // Set bit for effective_ellipsis_mask.
297 for (; i < ellipsis_end_idx; ++i)
298 {
299 effective_ellipsis_mask |= (1LL << i);
300 }
301 continue;
302 }
303
304 if ((1LL << (i - expanded_ellipsis)) & op_context->params.new_axis_mask)
305 {
306 effective_new_axis_mask |= (1LL << i);
307 }
308 ++i;
309 }
310
311 // Calculate effective_input_shape and its corresponding begin, end, strides.
312 loco::TensorShape input_shape = circle_shape(op_context->input);
313 int64_t added_ellipsis = 0, added_axises = 0;
314 // make sure no overflow
315 assert(static_cast<uint32_t>(effective_dims) == effective_dims);
316 op_context->effective_input_shape.rank(effective_dims);
317
318 for (int64_t i = 0; i < effective_dims; ++i)
319 {
320 if ((1LL << i) & effective_ellipsis_mask)
321 {
322 // If ellipsis_mask, set the begin_mask and end_mask at that index.
323 added_ellipsis = std::max(int64_t(0), i - ellipsis_start_idx);
324 assert(i < 16);
325 op_params.begin_mask |= (1LL << i);
326 op_params.end_mask |= (1LL << i);
327 op_params.strides[i] = 1;
328 op_context->effective_input_shape.dim(i) = input_shape.dim(i - added_axises);
329 }
330 else if ((1LL << i) & effective_new_axis_mask)
331 {
332 // If new_axis_mask is set, it is equivalent to adding a new dim of 1 to
333 // input tensor. Store added shape to effective_input_shape.
334 op_params.start_indices[i] = 0;
335 op_params.stop_indices[i] = 1;
336 op_params.strides[i] = 1;
337 op_context->effective_input_shape.dim(i) = loco::Dimension(1);
338 added_axises++;
339 }
340 else if (i >= begin_count + expanded_ellipsis)
341 {
342 op_params.start_indices[i] = 0;
343 op_params.stop_indices[i] = 0;
344 op_params.strides[i] = 1;
345 assert(i < 16);
346 op_params.begin_mask |= (1LL << i);
347 op_params.end_mask |= (1LL << i);
348 op_context->effective_input_shape.dim(i) = input_shape.dim(i - added_axises);
349 }
350 else
351 {
352 const int64_t orig_idx = i - added_ellipsis;
353 op_params.start_indices[i] = op_context->begin->at<S32>(orig_idx);
354 op_params.stop_indices[i] = op_context->end->at<S32>(orig_idx);
355 op_params.strides[i] = op_context->strides->at<S32>(orig_idx);
356 if (op_context->params.begin_mask & (1LL << orig_idx))
357 {
358 assert(i < 16);
359 op_params.begin_mask |= (1LL << i);
360 }
361 if (op_context->params.end_mask & (1LL << orig_idx))
362 {
363 assert(i < 16);
364 op_params.end_mask |= (1LL << i);
365 }
366 if (op_context->params.shrink_axis_mask & (1LL << orig_idx))
367 {
368 assert(i < 16);
369 op_params.shrink_axis_mask |= (1LL << i);
370 }
371 op_context->effective_input_shape.dim(i) = input_shape.dim(i - added_axises);
372 }
373 }
374
375 // make sure no overflow
376 assert(static_cast<int8_t>(effective_dims) == static_cast<int32_t>(effective_dims));
377
378 op_params.start_indices_count = effective_dims;
379 op_params.stop_indices_count = effective_dims;
380 op_params.strides_count = effective_dims;
381
382 return op_params;
383}
The value of one dimension in a tensor shape.
Definition Dimension.h:30
uint32_t value(void) const
Return the value.
Definition Dimension.h:51
const Dimension & dim(uint32_t axis) const
Definition TensorShape.h:38
uint32_t rank(void) const
Definition TensorShape.h:35
const loco::DataTypeImpl< DT >::Type & at(uint32_t n) const
const loco::DataType S32
loco::TensorShape circle_shape(const luci::CircleNode *node)
int8_t begin_count
Definition Slice.cpp:32

References luci::CircleConst::at(), luci::sinf::StridedSliceContext::begin, begin_count, luci::sinf::StridedSliceParams::begin_mask, circle_shape(), loco::TensorShape::dim(), luci::sinf::StridedSliceContext::effective_input_shape, luci::sinf::StridedSliceParams::ellipsis_mask, luci::sinf::StridedSliceContext::end, luci::sinf::StridedSliceParams::end_mask, luci::sinf::StridedSliceContext::input, luci::sinf::StridedSliceContext::input_dims, luci::sinf::StridedSliceParams::new_axis_mask, luci::sinf::StridedSliceContext::params, loco::TensorShape::rank(), S32, luci::sinf::StridedSliceParams::shrink_axis_mask, luci::sinf::StridedSliceParams::start_indices, luci::sinf::StridedSliceParams::start_indices_count, luci::sinf::StridedSliceParams::stop_indices, luci::sinf::StridedSliceParams::stop_indices_count, luci::sinf::StridedSliceParams::strides, luci::sinf::StridedSliceContext::strides, luci::sinf::StridedSliceParams::strides_count, and loco::Dimension::value().

Referenced by luci::sinf::Algorithm::visit().

◆ circle_shape()

◆ Clamp()

int luci::sinf::Clamp ( const int32_t  v,
const int32_t  lo,
const int32_t  hi 
)
inline

Definition at line 116 of file CircleStridedSlice.cpp.

117{
118 LUCI_ASSERT(!(hi < lo), "Clamp hi < lo");
119 if (hi < v)
120 return hi;
121 if (v < lo)
122 return lo;
123 return v;
124}
#define LUCI_ASSERT(condition, msg)
Definition Check.h:26

References LUCI_ASSERT.

Referenced by StartForAxis(), and StopForAxis().

◆ pad_shape()

loco::TensorShape luci::sinf::pad_shape ( const loco::TensorShape input_shape,
const luci::CircleNode paddings 
)

Definition at line 164 of file CircleShapeInferenceHelper.cpp.

165{
166 const loco::DataType S32 = loco::DataType::S32;
167 const loco::DataType S64 = loco::DataType::S64;
168
169 // TODO support other data type
170 LUCI_ASSERT(paddings->dtype() == S32 || paddings->dtype() == S64, "Support int 32/64 for now");
171 if (paddings->rank() != 2)
172 INTERNAL_EXN("paddings should be rank 2");
173
174 int32_t n = paddings->dim(0).value();
175 int32_t v = paddings->dim(1).value();
176
177 if (v != 2)
178 INTERNAL_EXN("paddings should be [n, 2]");
179
180 if (n != int32_t(input_shape.rank()))
181 INTERNAL_EXN("paddings [n, 2] should have same value of input rank");
182
184
185 output_shape.rank(input_shape.rank());
186
187 auto const_padding = dynamic_cast<const luci::CircleConst *>(paddings);
188 if (const_padding == nullptr)
189 return output_shape;
190
191 for (int32_t ni = 0; ni < n; ++ni)
192 {
193 if (not input_shape.dim(ni).known())
194 {
195 output_shape.dim(ni).unset();
196 continue;
197 }
198 int32_t idx = ni * 2;
199 int value = input_shape.dim(ni).value();
200 if (const_padding->dtype() == S32)
201 {
202 value += const_padding->at<S32>(idx + 0); // left
203 value += const_padding->at<S32>(idx + 1); // right
204 }
205 else
206 {
207 auto pl = const_padding->at<S64>(idx + 0);
208 auto pr = const_padding->at<S64>(idx + 1);
209 auto max = static_cast<int64_t>(std::numeric_limits<int32_t>::max());
210 auto low = static_cast<int64_t>(std::numeric_limits<int32_t>::lowest());
211 LUCI_ASSERT(pl <= max, "paddings is over 32 bit limit");
212 LUCI_ASSERT(pl >= low, "paddings is over 32 bit limit");
213 LUCI_ASSERT(pr <= max, "paddings is over 32 bit limit");
214 LUCI_ASSERT(pr >= low, "paddings is over 32 bit limit");
215 value += static_cast<int32_t>(pl); // left
216 value += static_cast<int32_t>(pr); // right
217 }
218 output_shape.dim(ni) = value;
219 }
220
221 return output_shape;
222}
#define INTERNAL_EXN(msg)
@ brief throw internal exception with message
Definition InternalExn.h:25
bool known(void) const
Return whether the value is known (or not)
Definition Dimension.h:47
Class to build tensor data.
Definition CircleConst.h:35
DataType
"scalar" value type
Definition DataType.h:27

References loco::TensorShape::dim(), INTERNAL_EXN, loco::Dimension::known(), LUCI_ASSERT, output_shape, loco::TensorShape::rank(), S32, and loco::Dimension::value().

Referenced by luci::sinf::Algorithm::visit().

◆ StartForAxis()

int64_t luci::sinf::StartForAxis ( const StridedSliceParams params,
const loco::TensorShape input_shape,
int64_t  axis 
)
inline

Definition at line 129 of file CircleStridedSlice.cpp.

131{
132 const auto begin_mask = params.begin_mask;
133 const auto *start_indices = params.start_indices;
134 const auto *strides = params.strides;
135 const int64_t axis_size = static_cast<int64_t>(input_shape.dim(axis).value());
136 if (axis_size == 0)
137 {
138 return 0;
139 }
140 // Begin with the specified index.
141 int64_t start = start_indices[axis];
142
143 // begin_mask override
144 if (begin_mask & (1LL << axis))
145 {
146 if (strides[axis] > 0)
147 {
148 // Forward iteration - use the first element. These values will get
149 // clamped below (Note: We could have set them to 0 and axis_size-1, but
150 // use lowest() and max() to maintain symmetry with StopForAxis())
151 start = std::numeric_limits<int32_t>::lowest();
152 }
153 else
154 {
155 // Backward iteration - use the last element.
156 start = std::numeric_limits<int32_t>::max();
157 }
158 }
159
160 // Handle negative indices
161 if (start < 0)
162 {
163 start += axis_size;
164 }
165
166 // Clamping
167 if (strides[axis] > 0)
168 {
169 // Forward iteration
170 start = Clamp(start, 0, axis_size);
171 }
172 else
173 {
174 // Backward iteration
175 start = Clamp(start, -1, axis_size - 1);
176 }
177
178 return start;
179}
int Clamp(const int v, const int lo, const int hi)

References luci::sinf::StridedSliceParams::begin_mask, Clamp(), loco::TensorShape::dim(), luci::sinf::StridedSliceParams::start_indices, luci::sinf::StridedSliceParams::strides, and loco::Dimension::value().

Referenced by luci::sinf::Algorithm::visit().

◆ StopForAxis()

int64_t luci::sinf::StopForAxis ( const StridedSliceParams params,
const loco::TensorShape input_shape,
int64_t  axis,
int64_t  start_for_axis 
)
inline

Definition at line 186 of file CircleStridedSlice.cpp.

188{
189 const auto end_mask = params.end_mask;
190 const auto shrink_axis_mask = params.shrink_axis_mask;
191 const auto *stop_indices = params.stop_indices;
192 const auto *strides = params.strides;
193 const int64_t axis_size = static_cast<int64_t>(input_shape.dim(axis).value());
194 if (axis_size == 0)
195 {
196 return 0;
197 }
198
199 // Begin with the specified index
200 const bool shrink_axis = shrink_axis_mask & (1LL << axis);
201 int64_t stop = stop_indices[axis];
202
203 // When shrinking an axis, the end position does not matter (and can be
204 // incorrect when negative indexing is used, see Issue #19260). Always use
205 // start_for_axis + 1 to generate a length 1 slice, since start_for_axis has
206 // already been adjusted for negative indices.
207 if (shrink_axis)
208 {
209 return start_for_axis + 1;
210 }
211
212 // end_mask override
213 if (end_mask & (1LL << axis))
214 {
215 if (strides[axis] > 0)
216 {
217 // Forward iteration - use the last element. These values will get
218 // clamped below
219 stop = std::numeric_limits<int32_t>::max();
220 }
221 else
222 {
223 // Backward iteration - use the first element.
224 stop = std::numeric_limits<int32_t>::lowest();
225 }
226 }
227
228 // Handle negative indices
229 if (stop < 0)
230 {
231 stop += axis_size;
232 }
233
234 // Clamping
235 // Because the end index points one past the last element, we need slightly
236 // different clamping ranges depending on the direction.
237 if (strides[axis] > 0)
238 {
239 // Forward iteration
240 stop = Clamp(stop, 0, axis_size);
241 }
242 else
243 {
244 // Backward iteration
245 stop = Clamp(stop, -1, axis_size - 1);
246 }
247
248 return stop;
249}

References Clamp(), loco::TensorShape::dim(), luci::sinf::StridedSliceParams::end_mask, luci::sinf::StridedSliceParams::shrink_axis_mask, luci::sinf::StridedSliceParams::stop_indices, luci::sinf::StridedSliceParams::strides, and loco::Dimension::value().

Referenced by luci::sinf::Algorithm::visit().

Variable Documentation

◆ kMaxDim

const int luci::sinf::kMaxDim = 5

Definition at line 59 of file CircleStridedSlice.cpp.

◆ S32

const loco::DataType luci::sinf::S32 = loco::DataType::S32