shape.hpp 10.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015-2022 Advanced Micro Devices, Inc. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
Paul's avatar
Paul committed
24
25
#ifndef MIGRAPHX_GUARD_MIGRAPHLIB_SHAPE_HPP
#define MIGRAPHX_GUARD_MIGRAPHLIB_SHAPE_HPP
Paul's avatar
Paul committed
26
27
28

#include <vector>
#include <cassert>
Paul's avatar
Paul committed
29
#include <ostream>
Paul's avatar
Paul committed
30
#include <numeric>
Paul's avatar
Paul committed
31
#include <memory>
Paul's avatar
Paul committed
32

Paul's avatar
Paul committed
33
34
35
#include <migraphx/errors.hpp>
#include <migraphx/half.hpp>
#include <migraphx/config.hpp>
Paul's avatar
Paul committed
36

Paul's avatar
Paul committed
37
namespace migraphx {
Paul's avatar
Paul committed
38
inline namespace MIGRAPHX_INLINE_NS {
Paul's avatar
Paul committed
39

40
struct value;
Paul's avatar
Paul committed
41
42
struct shape_impl;

Paul's avatar
Paul committed
43
44
struct shape
{
Paul's avatar
Paul committed
45
46

// Add new types here
Paul's avatar
Paul committed
47
// clang-format off
Paul's avatar
Paul committed
48
#define MIGRAPHX_SHAPE_VISIT_TYPES(m) \
49
    m(bool_type, bool) \
Paul's avatar
Paul committed
50
    m(half_type, half) \
Paul's avatar
Paul committed
51
    m(float_type, float) \
Paul's avatar
Paul committed
52
53
54
55
56
57
58
59
    m(double_type, double) \
    m(uint8_type, uint8_t) \
    m(int8_type, int8_t) \
    m(uint16_type, uint16_t) \
    m(int16_type, int16_t) \
    m(int32_type, int32_t) \
    m(int64_type, int64_t) \
    m(uint32_type, uint32_t) \
Paul's avatar
Paul committed
60
    m(uint64_type, uint64_t)
bpickrel's avatar
bpickrel committed
61
    // clang-format on
Paul's avatar
Paul committed
62

Paul's avatar
Paul committed
63
#define MIGRAPHX_SHAPE_GENERATE_ENUM_TYPES(x, t) x,
Paul's avatar
Paul committed
64
65
    enum type_t
    {
Paul Fultz II's avatar
Paul Fultz II committed
66
        MIGRAPHX_SHAPE_VISIT_TYPES(MIGRAPHX_SHAPE_GENERATE_ENUM_TYPES) tuple_type
Paul's avatar
Paul committed
67
    };
Paul's avatar
Paul committed
68
#undef MIGRAPHX_SHAPE_GENERATE_ENUM_TYPES
Paul's avatar
Paul committed
69

Paul's avatar
Paul committed
70
    template <class T, class = void>
Paul's avatar
Paul committed
71
    struct get_type;
Paul's avatar
Paul committed
72
#define MIGRAPHX_SHAPE_GENERATE_GET_TYPE(x, t)                \
Paul's avatar
Paul committed
73
    template <class T>                                        \
Paul's avatar
Paul committed
74
    struct get_type<t, T> : std::integral_constant<type_t, x> \
Paul's avatar
Paul committed
75
76
    {                                                         \
    };
Paul's avatar
Paul committed
77
78
    MIGRAPHX_SHAPE_VISIT_TYPES(MIGRAPHX_SHAPE_GENERATE_GET_TYPE)
#undef MIGRAPHX_SHAPE_GENERATE_GET_TYPE
Paul's avatar
Paul committed
79

wsttiger's avatar
wsttiger committed
80
81
82
83
84
    template <class T>
    struct get_type<const T> : get_type<T>
    {
    };

Charlie Lin's avatar
Charlie Lin committed
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
    struct dynamic_dimension
    {
        std::size_t min = 0;
        std::size_t max = 0;
        std::size_t opt = 0;

        template <class Self, class F>
        static auto reflect(Self& self, F f);

        bool is_fixed() const;
        bool has_optimal() const;

        friend bool operator==(const dynamic_dimension& x, const dynamic_dimension& y);
        friend bool operator!=(const dynamic_dimension& x, const dynamic_dimension& y);
        friend std::ostream& operator<<(std::ostream& os, const dynamic_dimension& x);
    };

102
103
    static const std::vector<type_t>& types();

104
105
106
    static std::string name(type_t t);
    static std::string cpp_type(type_t t);

Paul's avatar
Paul committed
107
108
109
110
    shape();
    shape(type_t t);
    shape(type_t t, std::vector<std::size_t> l);
    shape(type_t t, std::vector<std::size_t> l, std::vector<std::size_t> s);
Paul's avatar
Paul committed
111

Charlie Lin's avatar
Charlie Lin committed
112
113
114
115
116
117
    // Force all calls of the format `shape( type_t, { size_t compatibles } )` to map to
    // shape(type_t, std::vector<std::size_t> l)
    shape(type_t t, std::initializer_list<std::size_t> d);

    shape(type_t t, std::vector<dynamic_dimension> dims);

Paul's avatar
Paul committed
118
119
120
121
122
123
    template <class Range>
    shape(type_t t, const Range& l) : shape(t, std::vector<std::size_t>(l.begin(), l.end()))
    {
    }

    template <class Range1, class Range2>
Paul's avatar
Paul committed
124
    shape(type_t t, const Range1& l, const Range2& s)
Paul's avatar
Paul committed
125
126
127
128
129
        : shape(t,
                std::vector<std::size_t>(l.begin(), l.end()),
                std::vector<std::size_t>(s.begin(), s.end()))
    {
    }
Paul's avatar
Paul committed
130

Paul Fultz II's avatar
Paul Fultz II committed
131
132
    shape(const std::vector<shape>& subs);

133
134
    static shape
    from_permutation(type_t t, const std::vector<std::size_t>& l, const std::vector<int64_t>& perm);
Paul's avatar
Paul committed
135
    type_t type() const;
Paul's avatar
Paul committed
136
137
    const std::vector<std::size_t>& lens() const;
    const std::vector<std::size_t>& strides() const;
Charlie Lin's avatar
Charlie Lin committed
138
139
140
141

    /*!
     * Return the number of elements in the tensor.
     */
Paul's avatar
Paul committed
142
    std::size_t elements() const;
Charlie Lin's avatar
Charlie Lin committed
143
144
145
146
147

    /*!
     * Return the number of total bytes used for storage of the tensor data; includes subshapes.
     * For dynamic shape, returns the maximum number of bytes presuming a packed shape.
     */
Paul's avatar
Paul committed
148
    std::size_t bytes() const;
Charlie Lin's avatar
Charlie Lin committed
149
150
151
152
153

    /*!
     * Return the size of the type of the main shape.
     * Returns 0 if there are subshapes.
     */
Scott Thornton's avatar
Scott Thornton committed
154
    std::size_t type_size() const;
Paul's avatar
Paul committed
155

Charlie Lin's avatar
Charlie Lin committed
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
    const std::vector<dynamic_dimension>& dyn_dims() const;

    /*!
     * Minimum lengths for dynamic shape.
     * lens() for fixed shape.
     */
    std::vector<std::size_t> min_lens() const;

    /*!
     * Maximum lengths for dynamic shape.
     * lens() for fixed shape.
     */
    std::vector<std::size_t> max_lens() const;

    /*!
     * Optimum lengths for dynamic shape.
     * lens() for fixed shape.
     */
    std::vector<std::size_t> opt_lens() const;

Paul's avatar
Paul committed
176
    /// Map multiple indices to space index
Paul's avatar
Paul committed
177
    std::size_t index(std::initializer_list<std::size_t> l) const;
Paul's avatar
Paul committed
178
    /// Map multiple indices to space index
Paul's avatar
Paul committed
179
    std::size_t index(const std::vector<std::size_t>& l) const;
Paul's avatar
Paul committed
180

Paul's avatar
Paul committed
181
    /// Map multiple indices from a range of iterator to a space index
Paul's avatar
Paul committed
182
    template <class Iterator>
Paul's avatar
Paul committed
183
184
185
186
    std::size_t index(Iterator start, Iterator last) const
    {
        assert(std::distance(start, last) <= this->lens().size());
        assert(this->lens().size() == this->strides().size());
Paul Fultz II's avatar
Paul Fultz II committed
187
        return std::inner_product(start, last, this->strides().begin(), std::size_t{0}); // NOLINT
Paul's avatar
Paul committed
188
    }
Paul's avatar
Paul committed
189

Paul's avatar
Paul committed
190
    /// Map element index to space index
Paul's avatar
Paul committed
191
192
    std::size_t index(std::size_t i) const;

193
    std::vector<std::size_t> multi(std::size_t i) const;
194
    void multi_copy(std::size_t i, std::size_t* start, const std::size_t* end) const;
195

Charlie Lin's avatar
Charlie Lin committed
196
197
    /// Returns true if the shape is packed (number of elements and buffer size the same) with no
    /// padding
Paul's avatar
Paul committed
198
    bool packed() const;
Charlie Lin's avatar
Charlie Lin committed
199

Paul's avatar
Paul committed
200
201
    /// Returns true is the shape has been transposed. That is the strides are not in descending
    /// order
Paul's avatar
Paul committed
202
    bool transposed() const;
Charlie Lin's avatar
Charlie Lin committed
203

Paul's avatar
Paul committed
204
    /// Returns true if the shape is broadcasting a dimension. That is, one of the strides are zero
Paul's avatar
Paul committed
205
    bool broadcasted() const;
Charlie Lin's avatar
Charlie Lin committed
206

Paul's avatar
Paul committed
207
208
    /// Returns true if the shape is in its standard format. That is, the shape is both packed and
    /// not transposed.
Paul's avatar
Paul committed
209
    bool standard() const;
Charlie Lin's avatar
Charlie Lin committed
210

Khalique's avatar
Khalique committed
211
212
    /// Returns true if all strides are equal to 0 (scalar tensor)
    bool scalar() const;
Paul's avatar
Paul committed
213

Charlie Lin's avatar
Charlie Lin committed
214
215
216
    /// Return true if the shape is dynamic
    bool dynamic() const;

217
218
    shape normalize_standard() const;

219
220
221
    shape with_lens(type_t t, const std::vector<std::size_t>& l) const;
    shape with_lens(const std::vector<std::size_t>& l) const;

222
223
    shape with_type(type_t t) const;

Paul's avatar
Paul committed
224
225
    friend bool operator==(const shape& x, const shape& y);
    friend bool operator!=(const shape& x, const shape& y);
Paul's avatar
Paul committed
226
    friend std::ostream& operator<<(std::ostream& os, const shape& x);
Paul's avatar
Paul committed
227

Paul's avatar
Paul committed
228
    template <class T>
Paul's avatar
Paul committed
229
230
    struct as
    {
231
        using type = std::conditional_t<std::is_same<T, bool>{}, int8_t, T>;
Paul's avatar
Paul committed
232

233
234
235
236
        type max() const { return std::numeric_limits<type>::max(); }

        type min() const { return std::numeric_limits<type>::lowest(); }

Paul's avatar
Paul committed
237
        template <class U>
238
        type operator()(U u) const
Paul's avatar
Paul committed
239
        {
240
            return type(u);
Paul's avatar
Paul committed
241
242
        }

Paul's avatar
Paul committed
243
        template <class U>
244
        type* operator()(U* u) const
Paul's avatar
Paul committed
245
        {
246
            return static_cast<type*>(u);
Paul's avatar
Paul committed
247
248
        }

Paul's avatar
Paul committed
249
        template <class U>
250
        const type* operator()(const U* u) const
Paul's avatar
Paul committed
251
        {
252
            return static_cast<type*>(u);
Paul's avatar
Paul committed
253
254
        }

255
        type operator()() const { return {}; }
Paul's avatar
Paul committed
256

257
        std::size_t size(std::size_t n = 1) const { return sizeof(type) * n; }
Paul's avatar
Paul committed
258

Paul Fultz II's avatar
Paul Fultz II committed
259
260
261
262
        auto is_integral() const { return std::is_integral<type>{}; }
        auto is_signed() const { return std::is_signed<type>{}; }
        auto is_unsigned() const { return std::is_unsigned<type>{}; }

Paul's avatar
Paul committed
263
        template <class U>
264
        type* from(U* buffer, std::size_t n = 0) const
Paul's avatar
Paul committed
265
        {
266
            return reinterpret_cast<type*>(buffer) + n;
Paul's avatar
Paul committed
267
        }
Paul's avatar
Paul committed
268

Paul's avatar
Paul committed
269
        template <class U>
270
        const type* from(const U* buffer, std::size_t n = 0) const
Paul's avatar
Paul committed
271
        {
272
            return reinterpret_cast<const type*>(buffer) + n;
Paul's avatar
Paul committed
273
        }
Paul's avatar
Paul committed
274

275
        type_t type_enum() const { return get_type<type>{}; }
Paul's avatar
Paul committed
276
277
    };

Paul Fultz II's avatar
Paul Fultz II committed
278
279
    template <class Visitor, class TupleVisitor>
    static void visit(type_t t, Visitor v, TupleVisitor tv)
Paul's avatar
Paul committed
280
    {
281
        switch(t)
Paul's avatar
Paul committed
282
        {
bpickrel's avatar
bpickrel committed
283
        case tuple_type: {
Paul Fultz II's avatar
Paul Fultz II committed
284
285
286
            tv();
            return;
        }
Paul's avatar
Paul committed
287
#define MIGRAPHX_SHAPE_GENERATE_VISITOR_CASE(x, t) \
Paul's avatar
Paul committed
288
    case x: v(as<t>()); return;
Paul's avatar
Paul committed
289
290
            MIGRAPHX_SHAPE_VISIT_TYPES(MIGRAPHX_SHAPE_GENERATE_VISITOR_CASE)
#undef MIGRAPHX_SHAPE_GENERATE_VISITOR_CASE
Paul's avatar
Paul committed
291
        }
Paul's avatar
Paul committed
292
        MIGRAPHX_THROW("Unknown type");
Paul's avatar
Paul committed
293
    }
Paul's avatar
Paul committed
294

295
    template <class Visitor>
Paul Fultz II's avatar
Paul Fultz II committed
296
    static void visit(type_t t, Visitor v)
297
    {
Paul Fultz II's avatar
Paul Fultz II committed
298
299
300
301
302
303
304
        return visit(t, v, [] { MIGRAPHX_THROW("Tuple cannot be visited."); });
    }

    template <class... Visitors>
    void visit_type(Visitors... vs) const
    {
        visit(this->type(), vs...);
305
306
    }

Paul's avatar
Paul committed
307
308
309
    template <class Visitor>
    static void visit_types(Visitor v)
    {
Paul's avatar
Paul committed
310
#define MIGRAPHX_SHAPE_GENERATE_VISITOR_ALL(x, t) v(as<t>());
Paul's avatar
Paul committed
311
312
313
314
        MIGRAPHX_SHAPE_VISIT_TYPES(MIGRAPHX_SHAPE_GENERATE_VISITOR_ALL)
#undef MIGRAPHX_SHAPE_GENERATE_VISITOR_ALL
    }

315
    std::string type_string() const;
316
    static type_t parse_type(const std::string& s);
317

Paul Fultz II's avatar
Paul Fultz II committed
318
319
    const std::vector<shape>& sub_shapes() const;

Charlie Lin's avatar
Charlie Lin committed
320
321
322
323
324
    /*!
     * Returns the number of elements in the data buffer.
     * For a dynamic shape, returns the maximum number of elements of the data buffer and assumes it
     * is packed.
     */
325
326
    std::size_t element_space() const;

Paul's avatar
Paul committed
327
    private:
328
    shape(std::shared_ptr<shape_impl> pimpl);
Paul's avatar
Paul committed
329
    std::shared_ptr<const shape_impl> impl;
Paul's avatar
Paul committed
330
331
};

332
333
334
void migraphx_to_value(value& v, const shape& s);
void migraphx_from_value(const value& v, shape& s);

Paul's avatar
Paul committed
335
} // namespace MIGRAPHX_INLINE_NS
Paul's avatar
Paul committed
336
} // namespace migraphx
Paul's avatar
Paul committed
337
338

#endif