#pragma once
#include <algorithm>
#include <functional>
#include <memory>
#include <vector>
#include <c10/macros/Macros.h>
#include <c10/util/safe_numerics.h>
#include <executorch/runtime/core/error.h>
#include <executorch/runtime/core/exec_aten/exec_aten.h>
#include <executorch/runtime/core/exec_aten/util/scalar_type_util.h>
C10_DIAGNOSTIC_PUSH_AND_IGNORED_IF_DEFINED("-Wswitch-enum")
namespace executorch {
namespace extension {
using TensorPtr = std::shared_ptr<executorch::aten::Tensor>;
TensorPtr make_tensor_ptr(
std::vector<executorch::aten::SizesType> sizes,
void* data,
std::vector<executorch::aten::DimOrderType> dim_order,
std::vector<executorch::aten::StridesType> strides,
const executorch::aten::ScalarType type =
executorch::aten::ScalarType::Float,
executorch::aten::Device device =
executorch::aten::Device(executorch::aten::DeviceType::CPU),
const executorch::aten::TensorShapeDynamism dynamism =
executorch::aten::TensorShapeDynamism::DYNAMIC_BOUND,
std::function<void(void*)> deleter = nullptr);
inline TensorPtr make_tensor_ptr(
std::vector<executorch::aten::SizesType> sizes,
void* data,
const executorch::aten::ScalarType type =
executorch::aten::ScalarType::Float,
executorch::aten::Device device =
executorch::aten::Device(executorch::aten::DeviceType::CPU),
const executorch::aten::TensorShapeDynamism dynamism =
executorch::aten::TensorShapeDynamism::DYNAMIC_BOUND,
std::function<void(void*)> deleter = nullptr) {
return make_tensor_ptr(
std::move(sizes),
data,
{},
{},
type,
device,
dynamism,
std::move(deleter));
}
template <
typename T = float,
executorch::aten::ScalarType deduced_type =
runtime::CppTypeToScalarType<T>::value>
inline TensorPtr make_tensor_ptr(
std::vector<executorch::aten::SizesType> sizes,
std::vector<T> data,
std::vector<executorch::aten::DimOrderType> dim_order = {},
std::vector<executorch::aten::StridesType> strides = {},
executorch::aten::ScalarType type = deduced_type,
executorch::aten::TensorShapeDynamism dynamism =
executorch::aten::TensorShapeDynamism::DYNAMIC_BOUND) {
auto numel_result = executorch::aten::safe_numel(sizes.data(), sizes.size());
ET_CHECK_MSG(
numel_result.ok(),
"safe_numel failed: %d",
static_cast<int>(numel_result.error()));
ET_CHECK_MSG(
data.size() == static_cast<size_t>(numel_result.get()),
"Data size does not match tensor size.");
if (type != deduced_type) {
ET_CHECK_MSG(
runtime::canCast(deduced_type, type),
"Cannot cast deduced type to specified type.");
size_t casted_bytes = 0;
ET_CHECK_MSG(
!c10::mul_overflows(
data.size(),
static_cast<size_t>(aten::elementSize(type)),
&casted_bytes),
"casted_data size overflow: %zu elements * %zu bytes/element",
data.size(),
static_cast<size_t>(aten::elementSize(type)));
std::vector<uint8_t> casted_data(casted_bytes);
struct {
[[noreturn]] void fail(torch::executor::Error ) {
ET_CHECK_MSG(false, "Unsupported dtype in make_tensor_ptr");
}
} ctx;
ET_SWITCH_REALHBBF16_AND_UINT_TYPES(
type, ctx, "make_tensor_ptr", CTYPE, [&] {
std::transform(
data.begin(),
data.end(),
reinterpret_cast<CTYPE*>(casted_data.data()),
[](const T& val) { return static_cast<CTYPE>(val); });
});
const auto raw_data_ptr = casted_data.data();
auto data_ptr =
std::make_shared<std::vector<uint8_t>>(std::move(casted_data));
return make_tensor_ptr(
std::move(sizes),
raw_data_ptr,
std::move(dim_order),
std::move(strides),
type,
executorch::aten::Device(executorch::aten::DeviceType::CPU),
dynamism,
[data_ptr = std::move(data_ptr)](void*) {});
}
const auto raw_data_ptr = data.data();
auto data_ptr = std::make_shared<std::vector<T>>(std::move(data));
return make_tensor_ptr(
std::move(sizes),
raw_data_ptr,
std::move(dim_order),
std::move(strides),
type,
executorch::aten::Device(executorch::aten::DeviceType::CPU),
dynamism,
[data_ptr = std::move(data_ptr)](void*) {});
}
template <
typename T = float,
executorch::aten::ScalarType deduced_type =
runtime::CppTypeToScalarType<T>::value>
inline TensorPtr make_tensor_ptr(
std::vector<T> data,
executorch::aten::ScalarType type = deduced_type,
executorch::aten::TensorShapeDynamism dynamism =
executorch::aten::TensorShapeDynamism::DYNAMIC_BOUND) {
std::vector<executorch::aten::SizesType> sizes{
executorch::aten::SizesType(data.size())};
return make_tensor_ptr(
std::move(sizes), std::move(data), {0}, {1}, type, dynamism);
}
template <
typename T = float,
executorch::aten::ScalarType deduced_type =
runtime::CppTypeToScalarType<T>::value>
inline TensorPtr make_tensor_ptr(
std::vector<executorch::aten::SizesType> sizes,
std::initializer_list<T> list,
std::vector<executorch::aten::DimOrderType> dim_order = {},
std::vector<executorch::aten::StridesType> strides = {},
executorch::aten::ScalarType type = deduced_type,
executorch::aten::TensorShapeDynamism dynamism =
executorch::aten::TensorShapeDynamism::DYNAMIC_BOUND) {
return make_tensor_ptr(
std::move(sizes),
std::vector<T>(std::move(list)),
std::move(dim_order),
std::move(strides),
type,
dynamism);
}
template <
typename T = float,
executorch::aten::ScalarType deduced_type =
runtime::CppTypeToScalarType<T>::value>
inline TensorPtr make_tensor_ptr(
std::initializer_list<T> list,
executorch::aten::ScalarType type = deduced_type,
executorch::aten::TensorShapeDynamism dynamism =
executorch::aten::TensorShapeDynamism::DYNAMIC_BOUND) {
std::vector<executorch::aten::SizesType> sizes{
executorch::aten::SizesType(list.size())};
return make_tensor_ptr(
std::move(sizes), std::move(list), {0}, {1}, type, dynamism);
}
template <typename T>
inline TensorPtr make_tensor_ptr(T value) {
return make_tensor_ptr(
std::vector<executorch::aten::SizesType>{}, std::vector<T>{value});
}
TensorPtr make_tensor_ptr(
std::vector<executorch::aten::SizesType> sizes,
std::vector<uint8_t> data,
std::vector<executorch::aten::DimOrderType> dim_order,
std::vector<executorch::aten::StridesType> strides,
executorch::aten::ScalarType type = executorch::aten::ScalarType::Float,
executorch::aten::TensorShapeDynamism dynamism =
executorch::aten::TensorShapeDynamism::DYNAMIC_BOUND);
inline TensorPtr make_tensor_ptr(
std::vector<executorch::aten::SizesType> sizes,
std::vector<uint8_t> data,
executorch::aten::ScalarType type = executorch::aten::ScalarType::Float,
executorch::aten::TensorShapeDynamism dynamism =
executorch::aten::TensorShapeDynamism::DYNAMIC_BOUND) {
return make_tensor_ptr(
std::move(sizes), std::move(data), {}, {}, type, dynamism);
}
inline TensorPtr make_tensor_ptr(
const executorch::aten::Tensor& tensor,
std::vector<executorch::aten::SizesType> sizes = {},
std::vector<executorch::aten::DimOrderType> dim_order = {},
std::vector<executorch::aten::StridesType> strides = {},
std::function<void(void*)> deleter = nullptr) {
if (sizes.empty()) {
sizes.assign(tensor.sizes().begin(), tensor.sizes().end());
}
const auto same_rank = sizes.size() == static_cast<size_t>(tensor.dim());
const auto same_shape = same_rank &&
std::equal(sizes.begin(), sizes.end(), tensor.sizes().begin());
auto element_count_result =
executorch::aten::safe_numel(sizes.data(), sizes.size());
ET_CHECK_MSG(
element_count_result.ok(),
"safe_numel failed: %d",
static_cast<int>(element_count_result.error()));
const auto element_count = element_count_result.get();
const auto parent_element_count = tensor.numel();
ET_CHECK_MSG(
element_count <= parent_element_count,
"Requested view has %zd elements, but source tensor only has %zd.",
static_cast<ssize_t>(element_count),
static_cast<ssize_t>(parent_element_count));
#ifndef USE_ATEN_LIB
if (dim_order.empty() && strides.empty() && same_rank) {
dim_order.assign(tensor.dim_order().begin(), tensor.dim_order().end());
}
#endif if (strides.empty() && dim_order.empty() && same_shape) {
strides.assign(tensor.strides().begin(), tensor.strides().end());
}
return make_tensor_ptr(
std::move(sizes),
tensor.mutable_data_ptr(),
std::move(dim_order),
std::move(strides),
tensor.scalar_type(),
#ifndef USE_ATEN_LIB
executorch::aten::Device(tensor.device_type(), tensor.device_index()),
tensor.shape_dynamism(),
std::move(deleter));
#else
tensor.device(),
executorch::aten::TensorShapeDynamism::DYNAMIC_BOUND,
std::move(deleter));
#endif }
inline TensorPtr make_tensor_ptr(
const TensorPtr& tensor_ptr,
std::vector<executorch::aten::SizesType> sizes = {},
std::vector<executorch::aten::DimOrderType> dim_order = {},
std::vector<executorch::aten::StridesType> strides = {}) {
return make_tensor_ptr(
*tensor_ptr,
std::move(sizes),
std::move(dim_order),
std::move(strides),
[tensor_ptr](void*) {});
}
TensorPtr clone_tensor_ptr(
const executorch::aten::Tensor& tensor,
executorch::aten::ScalarType type);
inline TensorPtr clone_tensor_ptr(const executorch::aten::Tensor& tensor) {
return clone_tensor_ptr(tensor, tensor.scalar_type());
}
inline TensorPtr clone_tensor_ptr(
const TensorPtr& tensor,
executorch::aten::ScalarType type) {
return clone_tensor_ptr(*tensor, type);
}
inline TensorPtr clone_tensor_ptr(const TensorPtr& tensor) {
return clone_tensor_ptr(*tensor, tensor->scalar_type());
}
ET_NODISCARD
runtime::Error resize_tensor_ptr(
TensorPtr& tensor,
const std::vector<executorch::aten::SizesType>& sizes);
#ifndef USE_ATEN_LIB
TensorPtr clone_tensor_ptr_to(
const TensorPtr& tensor,
executorch::aten::Device target);
#endif
} }
C10_DIAGNOSTIC_POP()