| 96 | } |
| 97 | |
| 98 | SubTensorSpec Slice::apply(TensorLayout layout, int axis) const { |
| 99 | mgb_assert(layout.ndim > 0 && layout.dtype.valid()); |
| 100 | if (axis == megdnn::param::OptionalAxisV1::INVALID_AXIS) { |
| 101 | axis = 0; |
| 102 | layout = layout.collapse_contiguous(); |
| 103 | mgb_assert( |
| 104 | layout.ndim == 1, |
| 105 | "apply Slice with axis==INVALID_AXIS on non-contig layout"); |
| 106 | } |
| 107 | // axis in [-ndim, ndim) is available |
| 108 | if (axis < 0) |
| 109 | axis += layout.ndim; |
| 110 | mgb_assert( |
| 111 | axis >= 0 && static_cast<size_t>(axis) < layout.ndim, |
| 112 | "invalid axis: %d; ndim=%zu", axis, layout.ndim); |
| 113 | |
| 114 | ptrdiff_t size_ax = layout.shape[axis]; |
| 115 | ptrdiff_t begin, end, step = m_step.val_with_default(1); |
| 116 | mgb_assert(step, "Slice step can not be zero"); |
| 117 | |
| 118 | auto tostr = [](const Maybe<ptrdiff_t>& v) -> std::string { |
| 119 | if (!v.valid()) |
| 120 | return "None"; |
| 121 | return std::to_string(v.val()); |
| 122 | }; |
| 123 | auto mod_size = [size_ax](ptrdiff_t v) -> ptrdiff_t { |
| 124 | if (size_ax == 0) |
| 125 | return 0; |
| 126 | return v < 0 ? v + size_ax : v; |
| 127 | }; |
| 128 | MGB_MARK_USED_VAR(tostr); |
| 129 | |
| 130 | #define CHECK(cond) \ |
| 131 | if (m_is_scalar_idx) { \ |
| 132 | mgb_assert( \ |
| 133 | cond, "index out of bound: layout=%s; request index=%s, axis=%d", \ |
| 134 | layout.to_string().c_str(), tostr(m_begin).c_str(), axis); \ |
| 135 | } else { \ |
| 136 | mgb_assert( \ |
| 137 | cond, \ |
| 138 | "index out of bound: layout=%s; request begin=%s end=%s step=%s " \ |
| 139 | "axis=%d", \ |
| 140 | layout.to_string().c_str(), tostr(m_begin).c_str(), \ |
| 141 | tostr(m_end).c_str(), tostr(m_step).c_str(), axis); \ |
| 142 | } |
| 143 | |
| 144 | if (step > 0) { |
| 145 | begin = mod_size(m_begin.val_with_default(0)); |
| 146 | end = mod_size(m_end.val_with_default(size_ax)); |
| 147 | if (!m_is_scalar_idx) { |
| 148 | end = std::min(end, size_ax); |
| 149 | begin = std::min(begin, end); |
| 150 | } |
| 151 | CHECK(begin >= 0 && end >= begin && end <= size_ax) |
| 152 | } else { |
| 153 | begin = mod_size(m_begin.val_with_default(size_ax - 1)); |
| 154 | end = m_end.valid() ? mod_size(m_end.val()) : -1; |
| 155 | if (!m_is_scalar_idx) { |