mirror of
https://github.com/saymrwulf/onnxruntime.git
synced 2026-07-12 17:57:38 +00:00
### Description - make `MakeString` force inline - refactor ORT_FORCEINLINE macro - move to one place to avoid macro redefinition error - ~~add a `StringJoin` utility~~ ### Motivation and Context <!-- - Why is this change required? What problem does it solve? - If it fixes an open issue, please link to the issue here. -->
470 lines
12 KiB
C++
470 lines
12 KiB
C++
/**
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the MIT License.
|
|
*
|
|
* Module Name:
|
|
* matrix_layout.h
|
|
*
|
|
* Abstract:
|
|
* Utils for simplifying positioning and striding in tensors. Inspired
|
|
* by CUTLASS, striving for 0 runtime cost while promote safety.
|
|
*
|
|
* Only supports 2D tensors (matrix) for now.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <gsl/gsl>
|
|
|
|
#include "core/util/force_inline.h"
|
|
|
|
namespace onnxruntime {
|
|
|
|
//
|
|
// Clang-format doesn't handle force inline decorator well, it insists on
|
|
// adding extra indentation to the next line, making it very confusing
|
|
// to read. So we turn it off for this file.
|
|
// clang-format off
|
|
//
|
|
|
|
/**
|
|
* @brief A tuple of integers to represent tensor coordinates
|
|
*/
|
|
template <
|
|
int Rank_, ///< Logical rank of coordinate
|
|
typename Index_ = int, ///< Index type used for each dimension
|
|
typename LongIndex_ = int64_t ///< Long index type used for linear offsets
|
|
>
|
|
struct Position {
|
|
public:
|
|
/// Number of elements in Position
|
|
static int const kRank = Rank_;
|
|
|
|
/// Index type used to store elements
|
|
using Index = Index_;
|
|
|
|
/// Type used to represent linear offsets
|
|
using LongIndex = LongIndex_;
|
|
|
|
private:
|
|
Index idx[kRank];
|
|
|
|
public:
|
|
ORT_FORCEINLINE explicit Position(Index value = Index(0)) {
|
|
for (int i = 0; i < kRank; ++i) {
|
|
idx[i] = value;
|
|
}
|
|
}
|
|
|
|
/// Constructs from an array of integers
|
|
ORT_FORCEINLINE
|
|
Position(Index const (&_idx)[kRank]) {
|
|
for (int i = 0; i < kRank; ++i) {
|
|
idx[i] = _idx[i];
|
|
}
|
|
}
|
|
|
|
template <int R, typename I, typename L>
|
|
ORT_FORCEINLINE
|
|
Position(Position<R, I, L> other) {
|
|
for (int i = 0; i < kRank; ++i) {
|
|
idx[i] = other[i];
|
|
}
|
|
}
|
|
|
|
ORT_FORCEINLINE
|
|
Position operator+(Position const& b) const {
|
|
Position c;
|
|
for (int i = 0; i < kRank; ++i) {
|
|
c.idx[i] = idx[i] + b.idx[i];
|
|
}
|
|
return c;
|
|
}
|
|
|
|
ORT_FORCEINLINE
|
|
Position operator-(Position const& b) const {
|
|
Position c;
|
|
for (int i = 0; i < kRank; ++i) {
|
|
c.idx[i] = idx[i] - b.idx[i];
|
|
}
|
|
return c;
|
|
}
|
|
|
|
ORT_FORCEINLINE
|
|
Position operator*(Position const& b) const {
|
|
Position c;
|
|
for (int i = 0; i < kRank; ++i) {
|
|
c.idx[i] = idx[i] * b.idx[i];
|
|
}
|
|
return c;
|
|
}
|
|
|
|
ORT_FORCEINLINE
|
|
Position operator/(Position const& b) const {
|
|
Position c;
|
|
for (int i = 0; i < kRank; ++i) {
|
|
c.idx[i] = idx[i] / b.idx[i];
|
|
}
|
|
return c;
|
|
}
|
|
|
|
ORT_FORCEINLINE
|
|
Position& operator+=(Position const& b) {
|
|
for (int i = 0; i < kRank; ++i) {
|
|
idx[i] += b.idx[i];
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
ORT_FORCEINLINE
|
|
Position& operator-=(Position const& b) {
|
|
for (int i = 0; i < kRank; ++i) {
|
|
idx[i] -= b.idx[i];
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
ORT_FORCEINLINE
|
|
Position& operator*=(Position const& b) {
|
|
for (int i = 0; i < kRank; ++i) {
|
|
idx[i] *= b.idx[i];
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
ORT_FORCEINLINE
|
|
Position& operator/=(Position const& b) {
|
|
for (int i = 0; i < kRank; ++i) {
|
|
idx[i] /= b.idx[i];
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
ORT_FORCEINLINE Index& operator[](int dim) { return idx[dim]; }
|
|
|
|
ORT_FORCEINLINE Index const& operator[](int dim) const { return idx[dim]; }
|
|
|
|
ORT_FORCEINLINE bool operator==(Position const& b) const {
|
|
bool equal = true;
|
|
for (int i = 0; equal && i < kRank; ++i) {
|
|
equal = (idx[i] == b.idx[i]);
|
|
}
|
|
return equal;
|
|
}
|
|
|
|
ORT_FORCEINLINE bool operator!=(Position const& b) const { return !(*this == b); }
|
|
|
|
ORT_FORCEINLINE
|
|
Position& clamp(Position const& max, Position const& min = Position()) {
|
|
for (int i = 0; i < kRank; ++i) {
|
|
idx[i] = std::max(std::min(idx[i], max.idx[i]), min.idx[i]);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
ORT_FORCEINLINE
|
|
Index sum() const {
|
|
Index sum_(idx[0]);
|
|
for (int i = 1; i < kRank; ++i) {
|
|
sum_ += idx[i];
|
|
}
|
|
return sum_;
|
|
}
|
|
|
|
ORT_FORCEINLINE
|
|
LongIndex product() const {
|
|
LongIndex product_(idx[0]);
|
|
for (int i = 1; i < kRank; ++i) {
|
|
product_ *= idx[i];
|
|
}
|
|
return product_;
|
|
}
|
|
};
|
|
|
|
template <typename T, typename L = int64_t>
|
|
Position<2, T, L> make_Position(T _0, T _1) {
|
|
T values[2] = {_0, _1};
|
|
return Position<2, T, L>(values);
|
|
}
|
|
|
|
template <typename T, typename L = int64_t>
|
|
Position<3, T, L> make_Position(T _0, T _1, T _2) {
|
|
T values[3] = {_0, _1, _2};
|
|
return Position<2, T, L>(values);
|
|
}
|
|
|
|
/// Describes the size of a matrix tile
|
|
template <
|
|
int Row_, ///< rows of a matrix
|
|
int Column_ ///< columns of a matrix
|
|
>
|
|
struct MatrixShape {
|
|
static int const kRow = Row_; ///< rows of a matrix
|
|
static int const kColumn = Column_; ///< columns of a matrix
|
|
static int const kCount = Row_ * Column_; ///< total number of elements in a matrix
|
|
|
|
ORT_FORCEINLINE static Position<2> toCoord() {
|
|
return make_Position(kRow, kColumn);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Defines a mapping from logical coordinate to linear memory
|
|
* offsets in a row major layout matrix
|
|
*/
|
|
class RowMajorLayout {
|
|
public:
|
|
/// Index type used for coordinates
|
|
using Index = int;
|
|
|
|
/// Long index type used for offsets
|
|
using LongIndex = int64_t;
|
|
|
|
/// Logical coordinate
|
|
using MatCoord = Position<2, Index, LongIndex>;
|
|
|
|
private:
|
|
Index stride_;
|
|
|
|
public:
|
|
ORT_FORCEINLINE
|
|
RowMajorLayout(Index ldm = 0) : stride_(ldm) {}
|
|
|
|
ORT_FORCEINLINE static RowMajorLayout packed(MatCoord const& extent) {
|
|
return RowMajorLayout(extent[1]);
|
|
}
|
|
|
|
/// Returns the offset of a coordinate in linear memory.
|
|
/// Assumes coordinate has convention (row, column)
|
|
ORT_FORCEINLINE
|
|
LongIndex operator()(MatCoord const& coord) const {
|
|
return LongIndex(coord[0]) * stride_ + coord[1];
|
|
}
|
|
|
|
/// Inverse of layout function, mapping linear offset to logical coordinate
|
|
ORT_FORCEINLINE
|
|
MatCoord inverse(LongIndex offset) const {
|
|
return make_Position(Index(offset / stride_), Index(offset % stride_));
|
|
}
|
|
|
|
ORT_FORCEINLINE
|
|
Index stride() const {
|
|
return stride_;
|
|
}
|
|
};
|
|
|
|
class ColumnMajorLayout {
|
|
public:
|
|
/// Index type used for coordinates
|
|
using Index = int;
|
|
|
|
/// Long index type used for offsets
|
|
using LongIndex = int64_t;
|
|
|
|
/// Logical coordinate
|
|
using MatCoord = Position<2, Index, LongIndex>;
|
|
|
|
private:
|
|
Index stride_;
|
|
|
|
public:
|
|
ORT_FORCEINLINE
|
|
ColumnMajorLayout(Index ldm = 0) : stride_(ldm) {}
|
|
|
|
ORT_FORCEINLINE static ColumnMajorLayout packed(MatCoord const& extent) {
|
|
return ColumnMajorLayout(extent[0]);
|
|
}
|
|
|
|
/// Returns the offset of a coordinate in linear memory.
|
|
/// Assumes coordinate has convention (row, column)
|
|
ORT_FORCEINLINE
|
|
LongIndex operator()(MatCoord const& coord) const {
|
|
return LongIndex(coord[1]) * LongIndex(stride_) + coord[0];
|
|
}
|
|
|
|
/// Inverse of layout function, mapping linear offset to logical coordinate
|
|
ORT_FORCEINLINE
|
|
MatCoord inverse(LongIndex offset) const {
|
|
return make_Position(Index(offset % stride_), Index(offset / stride_));
|
|
}
|
|
|
|
ORT_FORCEINLINE
|
|
Index stride() const {
|
|
return stride_;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief A reference to a tensor, with a layout object to map logical
|
|
* coordinates to linear offsets.
|
|
*/
|
|
template <
|
|
/// Data type of element stored within tensor, must be numerical types
|
|
typename Element_,
|
|
/// Defines a mapping from logical coordinate to linear memory offsets
|
|
typename Layout_,
|
|
/// If true, extra bounds checking is performed on all accesses
|
|
bool ExtraBoundsCheck_ = false>
|
|
class MatrixRef {
|
|
public:
|
|
/// Data type of individual access
|
|
using Element = Element_;
|
|
|
|
using Reference = Element&;
|
|
|
|
/// Mapping function from logical coordinate to linear memory
|
|
using Layout = Layout_;
|
|
|
|
/// Index type
|
|
using Index = typename Layout::Index;
|
|
|
|
/// Long index used for pointer offsets
|
|
using LongIndex = typename Layout::LongIndex;
|
|
|
|
/// Coordinate in logical tensor space
|
|
using MatCoord = typename Layout::MatCoord;
|
|
|
|
/// MatrixRef to constant data
|
|
using ConstMatrixRef = MatrixRef<
|
|
typename std::remove_const<Element>::type const,
|
|
Layout, ExtraBoundsCheck_>;
|
|
|
|
/// MatrixRef to non-constant data
|
|
using NonConstMatrixRef = MatrixRef<
|
|
typename std::remove_const<Element>::type,
|
|
Layout, ExtraBoundsCheck_>;
|
|
|
|
static constexpr bool IsNonConstRef = std::is_same<NonConstMatrixRef, MatrixRef<Element_, Layout_>>::value;
|
|
|
|
private:
|
|
/// Pointer to data
|
|
gsl::span<Element> data_;
|
|
|
|
/// Shape of matrix
|
|
MatCoord shape_;
|
|
|
|
/// Layout object maps logical coordinates to linear offsets
|
|
Layout layout_;
|
|
|
|
public:
|
|
ORT_FORCEINLINE
|
|
MatrixRef() : data_() {}
|
|
|
|
ORT_FORCEINLINE
|
|
MatrixRef(
|
|
gsl::span<Element> const& data, ///< pointer to start of tensor
|
|
MatCoord const& shape ///< shape of tensor
|
|
) : data_(data), shape_(shape), layout_(Layout::packed(shape)) {
|
|
Expects(data_.size() >= size_t(shape_.product()));
|
|
}
|
|
|
|
ORT_FORCEINLINE
|
|
MatrixRef(
|
|
Element* ptr, ///< pointer to start of tensor
|
|
LongIndex size, ///< size of tensor in elements
|
|
MatCoord const& shape ///< shape of tensor
|
|
) : data_(ptr, size), shape_(shape), layout_(Layout::packed(shape)) {
|
|
Expects(data_.size() >= shape_.product());
|
|
}
|
|
|
|
/// Converting constructor from MatrixRef to non-constant data.
|
|
template <typename _Magic = int>
|
|
ORT_FORCEINLINE
|
|
MatrixRef(
|
|
NonConstMatrixRef const& ref, ///< MatrixRef to non-const data
|
|
/// SFINAE trick to avoid creating a copy-constructor when Element_ is already non-const
|
|
[[maybe_unused]] _Magic magic = (typename std::enable_if<!IsNonConstRef, _Magic>::type)0
|
|
) : data_(ref.data()), shape_(ref.shape()), layout_(Layout::packed(ref.shape())) {}
|
|
|
|
ORT_FORCEINLINE
|
|
ConstMatrixRef const_ref() const {
|
|
return ConstMatrixRef(data_, shape_);
|
|
}
|
|
|
|
ORT_FORCEINLINE
|
|
NonConstMatrixRef non_const_ref() {
|
|
return NonConstMatrixRef(
|
|
const_cast<typename std::remove_const<Element>::type*>(data_.data()),
|
|
data_.size(), shape_);
|
|
}
|
|
|
|
/// Returns true if the MatrixRef is non-null
|
|
ORT_FORCEINLINE
|
|
bool good() const { return !data_.empty(); }
|
|
|
|
ORT_FORCEINLINE
|
|
gsl::span<Element> const& data() const { return data_; }
|
|
|
|
ORT_FORCEINLINE
|
|
MatCoord const& shape() const { return shape_; }
|
|
|
|
ORT_FORCEINLINE
|
|
Layout& layout() { return layout_; }
|
|
|
|
ORT_FORCEINLINE
|
|
Layout layout() const { return layout_; }
|
|
|
|
ORT_FORCEINLINE
|
|
Index stride() const { return layout_.stride(); }
|
|
|
|
ORT_FORCEINLINE
|
|
Index& stride() { return layout_.stride(); }
|
|
|
|
/// Computes the offset of an index from the origin of the tensor
|
|
ORT_FORCEINLINE
|
|
LongIndex offset(MatCoord const& coord) const {
|
|
if constexpr (ExtraBoundsCheck_) {
|
|
Expects(coord[0] >= 0 && coord[0] < shape_[0]);
|
|
Expects(coord[1] >= 0 && coord[1] < shape_[1]);
|
|
}
|
|
return layout_(coord);
|
|
}
|
|
|
|
/// Returns a reference to the element at a given Coord
|
|
ORT_FORCEINLINE
|
|
Reference at(MatCoord const& coord) const {
|
|
return data_[offset(coord)];
|
|
}
|
|
|
|
ORT_FORCEINLINE
|
|
Reference at(int row, int col) const {
|
|
return data_[offset(make_Position(row, col))];
|
|
}
|
|
|
|
/// Returns a reference to the element at a given Coord
|
|
ORT_FORCEINLINE
|
|
Reference operator[](MatCoord const& coord) const {
|
|
return data_[offset(coord)];
|
|
}
|
|
};
|
|
|
|
/// Constructs a MatrixRef, deducing types from arguments.
|
|
template <
|
|
typename Element,
|
|
typename Layout = RowMajorLayout,
|
|
bool ExtraBoundsCheck = false>
|
|
ORT_FORCEINLINE
|
|
MatrixRef<Element, Layout, ExtraBoundsCheck>
|
|
make_MatrixRef(
|
|
Element* ptr,
|
|
int64_t size,
|
|
typename Layout::MatCoord const& shape) {
|
|
return MatrixRef<Element, Layout, ExtraBoundsCheck>(ptr, size, shape);
|
|
}
|
|
|
|
template <
|
|
typename Element,
|
|
typename Layout = RowMajorLayout,
|
|
bool ExtraBoundsCheck = false>
|
|
ORT_FORCEINLINE
|
|
MatrixRef<Element, Layout, ExtraBoundsCheck>
|
|
make_MatrixRef(
|
|
const gsl::span<Element>& span,
|
|
typename Layout::MatCoord const& shape) {
|
|
return MatrixRef<Element, Layout, ExtraBoundsCheck>(span, shape);
|
|
}
|
|
|
|
// clang-format off
|
|
|
|
} // namespace onnxruntime
|