Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions backends/native/runtime/graph/ScalarType.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree.

#pragma once

#include <cstddef>
#include <cstdint>
#include <stdexcept>

namespace ptn {

// X-macro table of scalar types: (CPP_TYPE, NAME, ID).
//
// The ids are the serialized ScalarType values, so a deserializer maps a
// serialized byte straight to this enum. They are not sequential: the gaps are
// ids reserved for element types this header does not carry.
//
// Half and BFloat16 have no 16-bit float type in this dependency-free header;
// they map to uint16_t as a raw storage stand-in, correct for size and layout.
#define PTN_FORALL_SCALAR_TYPES(_) \
_(uint8_t, Byte, 0) \
_(int8_t, Char, 1) \
_(int16_t, Short, 2) \
_(int32_t, Int, 3) \
_(int64_t, Long, 4) \
_(uint16_t, Half, 5) \
_(float, Float, 6) \
_(double, Double, 7) \
_(bool, Bool, 11) \
_(uint16_t, BFloat16, 15) \
_(uint16_t, UInt16, 16) \
_(uint32_t, UInt32, 17) \
_(uint64_t, UInt64, 18)

enum class ScalarType : int8_t {
#define PTN_DEFINE_ENUM(cpp_type, name, id) name = id,
PTN_FORALL_SCALAR_TYPES(PTN_DEFINE_ENUM)
#undef PTN_DEFINE_ENUM
};

#define PTN_DEFINE_CONSTANT(cpp_type, name, id) \
inline constexpr ScalarType k##name = ScalarType::name;
PTN_FORALL_SCALAR_TYPES(PTN_DEFINE_CONSTANT)
#undef PTN_DEFINE_CONSTANT

// Forward mapping only: a reverse C++-type -> ScalarType trait is omitted,
// since uint16_t would collide across Half / BFloat16 / UInt16.
template <ScalarType N>
struct ScalarTypeToCppType;
#define PTN_SPECIALIZE_S2C(cpp_type, name, id) \
template <> \
struct ScalarTypeToCppType<ScalarType::name> { \
using type = cpp_type; \
};
PTN_FORALL_SCALAR_TYPES(PTN_SPECIALIZE_S2C)
#undef PTN_SPECIALIZE_S2C

template <ScalarType N>
using cpp_type_t = typename ScalarTypeToCppType<N>::type;

// Throws std::runtime_error on a value outside the table, e.g. a bad cast from
// an out-of-range serialized byte.
constexpr size_t element_size(ScalarType t) {
switch (t) {
#define PTN_CASE_ELEMSIZE(cpp_type, name, id) \
case ScalarType::name: \
return sizeof(cpp_type);
PTN_FORALL_SCALAR_TYPES(PTN_CASE_ELEMSIZE)
#undef PTN_CASE_ELEMSIZE
}
throw std::runtime_error("element_size: unrecognized ScalarType");
}

// Enumerator name, e.g. "Float". Throws on a value outside the table.
constexpr const char* scalar_type_name(ScalarType t) {
switch (t) {
#define PTN_CASE_NAME(cpp_type, name, id) \
case ScalarType::name: \
return #name;
PTN_FORALL_SCALAR_TYPES(PTN_CASE_NAME)
#undef PTN_CASE_NAME
}
throw std::runtime_error("scalar_type_name: unrecognized ScalarType");
}

} // namespace ptn
74 changes: 74 additions & 0 deletions backends/native/runtime/graph/TensorMeta.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree.

#include <executorch/backends/native/runtime/graph/TensorMeta.h>

#include <algorithm>
#include <limits>
#include <ranges>
#include <stdexcept>

namespace ptn {

Dim::Dim(int64_t min_v, int64_t max_v) : min(min_v), max(max_v) {
if (min_v < 0 || (max_v >= 0 && max_v < min_v)) {
throw std::runtime_error(
"Dim: no shape has the range " + std::to_string(min_v) + ".." +
std::to_string(max_v));
}
}

bool TensorMeta::is_static() const {
return std::ranges::all_of(sizes, &Dim::is_static);
}

bool TensorMeta::is_contiguous() const {
if (dim_order_hint.empty()) {
return true;
}
// A length mismatch already makes this unequal.
return std::ranges::equal(
dim_order_hint,
std::views::iota(int32_t{0}, static_cast<int32_t>(sizes.size())));
}

int64_t TensorMeta::numel() const {
int64_t n = 1;
for (const Dim& d : sizes) {
const int64_t extent = d.is_static() ? d.min : d.max;
if (extent < 0) {
throw std::runtime_error("TensorMeta::numel: unbounded dynamic dim");
}
// Signed overflow is UB, so the product must be checked before it happens.
if (extent != 0 && n > std::numeric_limits<int64_t>::max() / extent) {
throw std::runtime_error("TensorMeta::numel: element count overflows");
}
n *= extent;
}
return n;
}

std::string TensorMeta::to_string() const {
std::string s = scalar_type_name(dtype);
s += "[";
for (size_t i = 0; i < sizes.size(); ++i) {
if (i != 0) {
s += ",";
}
const Dim& d = sizes[i];
if (d.is_static()) {
s += std::to_string(d.min);
} else if (d.max < 0) {
s += std::to_string(d.min) + "..?";
} else {
s += std::to_string(d.min) + ".." + std::to_string(d.max);
}
}
s += "]";
return s;
}

} // namespace ptn
76 changes: 76 additions & 0 deletions backends/native/runtime/graph/TensorMeta.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.
// All rights reserved.
//
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree.

#pragma once

#include <cstddef>
#include <cstdint>
#include <string>
#include <vector>

#include <executorch/backends/native/runtime/graph/ScalarType.h>

namespace ptn {

// One tensor dimension as an inclusive range. Static: min == max. Dynamic:
// min < max, or max < 0 for unbounded.
struct Dim {
int64_t min = 0;
int64_t max = -1;

Dim() = default;
// Implicit so a shape can be written as a plain int list, e.g. {16, 8}.
// cppcheck-suppress noExplicitConstructor
/* implicit */ Dim(int64_t extent) : Dim(extent, extent) {}
// Throws std::runtime_error on a range no shape can have: a negative lower
// bound, or a bounded upper bound below it. A funnel, not an invariant --
// min / max stay public and assignable.
Dim(int64_t min_v, int64_t max_v);

bool is_static() const {
return min == max;
}

bool operator==(const Dim&) const = default;
};

// Logical tensor metadata: element type and per-dim size ranges. No storage, no
// quant scheme.
//
// dim_order_hint is a permutation of dim indices, outermost first; empty means
// contiguous ([0, 1, ..., n-1]). It is a hint only for a tensor with no stored
// content — an activation — where an engine is free to pick its own physical
// layout. For a tensor whose bytes are serialized it instead describes the
// layout those bytes are actually in, and an engine that ignores it reads the
// weight wrong.
struct TensorMeta {
ScalarType dtype = ScalarType::Float;
std::vector<Dim> sizes;
std::vector<int32_t> dim_order_hint;

size_t ndim() const {
return sizes.size();
}

bool is_static() const;

// True if dim_order_hint is empty or the identity permutation.
bool is_contiguous() const;

// Element count from each dim's upper bound. Throws std::runtime_error on an
// unbounded dynamic dim (max < 0), which has no finite count.
int64_t numel() const;

// e.g. "Float[16,16]", "Float[1..8,16]" (bounded dynamic), "Float[0..?,16]"
// (unbounded).
std::string to_string() const;

// Exact on dim_order_hint: an empty hint and a spelled-out identity
// permutation compare unequal though they mean the same layout.
bool operator==(const TensorMeta&) const = default;
};

} // namespace ptn
20 changes: 20 additions & 0 deletions backends/native/runtime/graph/targets.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,23 @@ def define_common_targets():
],
visibility = ["//executorch/backends/native/..."],
)

runtime.cxx_library(
name = "scalar_type",
exported_headers = [
"ScalarType.h",
],
visibility = ["//executorch/backends/native/..."],
)

runtime.cxx_library(
name = "tensor_meta",
srcs = ["TensorMeta.cpp"],
exported_headers = [
"TensorMeta.h",
],
exported_deps = [
":scalar_type",
],
visibility = ["//executorch/backends/native/..."],
)
Loading