diff --git a/backends/native/runtime/graph/Ids.h b/backends/native/runtime/graph/Ids.h new file mode 100644 index 00000000000..65295791111 --- /dev/null +++ b/backends/native/runtime/graph/Ids.h @@ -0,0 +1,35 @@ +// 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 +#include +#include + +namespace ptn { + +// Index-arena handles. A NodeRef indexes Graph.nodes; a ValueRef indexes +// Graph.values. Plain int32_t aliases — they index, compare, and hash +// directly, at the cost of no NodeRef/ValueRef type distinction. kInvalid +// marks "no ref" (e.g. a graph input has no producer node; a fresh value has +// no alias). +using NodeRef = int32_t; +using ValueRef = int32_t; +constexpr int32_t kInvalid = -1; + +inline bool valid(int32_t ref) { + return ref >= 0; +} + +// True when `ref` addresses one of `size` elements: valid and in range. The +// signed/unsigned comparison goes through std::cmp_less so neither side has to +// be cast to the other's signedness. +inline bool in_bounds(int32_t ref, size_t size) { + return valid(ref) && std::cmp_less(ref, size); +} + +} // namespace ptn diff --git a/backends/native/runtime/graph/Value.cpp b/backends/native/runtime/graph/Value.cpp new file mode 100644 index 00000000000..ebea426a65b --- /dev/null +++ b/backends/native/runtime/graph/Value.cpp @@ -0,0 +1,38 @@ +// 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 + +#include + +namespace ptn { + +const TensorMeta& Value::tensor_meta() const { + const TensorMeta* m = std::get_if(&value_); + if (m == nullptr) { + throw std::runtime_error("Value::tensor_meta: value is not a Tensor"); + } + return *m; +} + +const Scalar& Value::scalar() const { + const Scalar* s = std::get_if(&value_); + if (s == nullptr) { + throw std::runtime_error("Value::scalar: value is not a Scalar"); + } + return *s; +} + +const std::vector& Value::content_refs() const { + const std::vector* refs = + std::get_if>(&value_); + if (refs == nullptr) { + throw std::runtime_error("Value::content_refs: value is not a List"); + } + return *refs; +} + +} // namespace ptn diff --git a/backends/native/runtime/graph/Value.h b/backends/native/runtime/graph/Value.h new file mode 100644 index 00000000000..d48ac44ec82 --- /dev/null +++ b/backends/native/runtime/graph/Value.h @@ -0,0 +1,102 @@ +// 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace ptn { + +// What a Value holds. +enum class ValueKind : int8_t { + None = 0, + Tensor = 1, + Scalar = 2, + List = 3, +}; + +// A single SSA value (dataflow edge) in a Graph: its contents plus def-use +// wiring, a storage-alias fact, and an open attrs map. +// +// The contents are a std::variant whose alternatives are listed in ValueKind +// order, so kind() is the variant's index. Construct via the constructors (one +// per kind); read the payload via the typed accessors after checking kind() +// (each accessor throws std::runtime_error on a kind mismatch). A List holds +// ValueRefs to its element values (a grouping over arena values, e.g. a tuple +// produced by an in-memory rewrite) — nesting is via the arena, so there is no +// recursive value type. The AOT deserializer builds only Tensor / Scalar / +// None; List is reserved for in-memory construction. +class Value { + private: + std::variant> + value_; + + public: + // SSA name, scoped to the enclosing Graph. + std::string name; + // Defining node; invalid => graph input. + NodeRef producer_ref = kInvalid; + // Def-use, built by inverting node inputs. + std::vector consumer_refs; + // Shares storage with this value (a view); fresh if invalid. + ValueRef alias_ref = kInvalid; + // Scratch + planner annotations. + std::unordered_map attrs; + + Value() = default; // a None value with an empty name + + explicit Value(std::string name) // a named None value + : name(std::move(name)) {} + + Value(std::string name, TensorMeta meta) // Tensor + : value_(std::move(meta)), name(std::move(name)) {} + + // Tensor from dtype + sizes: a contiguous, unquantized TensorMeta. The empty + // dim_order_hint is what makes it contiguous, so it is spelled out. + Value(std::string name, ScalarType dtype, std::vector sizes) + : value_(TensorMeta{dtype, std::move(sizes), {}}), + name(std::move(name)) {} + + Value(std::string name, Scalar value) // Scalar + : value_(value), name(std::move(name)) {} + + Value(std::string name, std::vector elem_refs) // List + : value_(std::move(elem_refs)), name(std::move(name)) {} + + ValueKind kind() const { + return static_cast(value_.index()); + } + bool is_tensor() const { + return std::holds_alternative(value_); + } + bool is_scalar() const { + return std::holds_alternative(value_); + } + bool is_list() const { + return std::holds_alternative>(value_); + } + bool is_none() const { + return std::holds_alternative(value_); + } + + // Typed payload accessors. Each throws std::runtime_error unless kind() + // matches; guard with the is_*() / kind() predicates. + const TensorMeta& tensor_meta() const; + const Scalar& scalar() const; + const std::vector& content_refs() const; +}; + +} // namespace ptn diff --git a/backends/native/runtime/graph/targets.bzl b/backends/native/runtime/graph/targets.bzl index 88f73072fe4..606c9dac305 100644 --- a/backends/native/runtime/graph/targets.bzl +++ b/backends/native/runtime/graph/targets.bzl @@ -42,3 +42,28 @@ def define_common_targets(): ], visibility = ["//executorch/backends/native/..."], ) + + # Index-arena handles (NodeRef / ValueRef); header-only. + runtime.cxx_library( + name = "ids", + exported_headers = [ + "Ids.h", + ], + visibility = ["//executorch/backends/native/..."], + ) + + # A single SSA value: a std::variant (tensor / scalar / list / none) plus + # def-use wiring, storage alias, and an attrs scratch map. + runtime.cxx_library( + name = "value", + srcs = ["Value.cpp"], + exported_headers = [ + "Value.h", + ], + exported_deps = [ + ":ids", + ":scalar", + ":tensor_meta", + ], + visibility = ["//executorch/backends/native/..."], + )