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
33 changes: 33 additions & 0 deletions backends/native/runtime/graph/Ids.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// 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 <utility>

namespace ptn {

// Index-arena handles: a NodeId indexes the graph's node arena, a ValueId
// its value arena. Plain int32_t aliases — they index, compare, and hash
// directly, at the cost of no NodeId/ValueId type distinction. kInvalid marks
// "no id".
using NodeId = int32_t;
using ValueId = int32_t;
inline constexpr int32_t kInvalid = -1;

constexpr bool valid(int32_t id) {
return id >= 0;
}

// std::cmp_less compares the signed id against the unsigned size without
// casting either side.
constexpr bool in_bounds(int32_t id, size_t size) {
return valid(id) && std::cmp_less(id, size);
}

} // namespace ptn
37 changes: 37 additions & 0 deletions backends/native/runtime/graph/Value.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// 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/Value.h>

#include <stdexcept>

namespace ptn {

const TensorMeta& Value::tensor_meta() const {
const TensorMeta* m = std::get_if<TensorMeta>(&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<Scalar>(&value_);
if (s == nullptr) {
throw std::runtime_error("Value::scalar: value is not a Scalar");
}
return *s;
}

const std::vector<ValueId>& Value::content_ids() const {
const std::vector<ValueId>* ids = std::get_if<std::vector<ValueId>>(&value_);
if (ids == nullptr) {
throw std::runtime_error("Value::content_ids: value is not a List");
}
return *ids;
}

} // namespace ptn
98 changes: 98 additions & 0 deletions backends/native/runtime/graph/Value.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// 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 <any>
#include <cstdint>
#include <string>
#include <unordered_map>
#include <utility>
#include <variant>
#include <vector>

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

namespace ptn {

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 and an open annotation map. The id fields are plain
// handles; whether one is in range is a property of the owning arena, so
// nothing here validates them.
//
// The variant's alternatives are listed in ValueKind order, so kind() is its
// index. A Tensor carries metadata only, so a weight is an ordinary arena
// value like any other, with its bytes held outside the graph. A List holds
// ValueIds to its elements, so nesting goes through the arena; nothing
// deserialized is a List, it exists for in-memory rewrites such as grouping a
// tuple.
class Value {
private:
std::variant<std::monostate, TensorMeta, Scalar, std::vector<ValueId>> value_;

public:
// SSA name, scoped to the enclosing Graph.
std::string name;
// Defining node; invalid => graph input.
NodeId producer_id = kInvalid;
// Def-use, built by inverting node inputs.
std::vector<NodeId> consumer_ids;
// Shares storage with this value (a view); fresh if invalid.
ValueId alias_id = kInvalid;
// Open annotations for graph passes and engines, like node.meta in FX.
std::unordered_map<std::string, std::any> 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)
: value_(std::move(meta)), name(std::move(name)) {}

// The empty dim_order_hint is what makes the tensor contiguous.
Value(std::string name, ScalarType dtype, std::vector<Dim> sizes)
: value_(TensorMeta{dtype, std::move(sizes), {}}),
name(std::move(name)) {}

Value(std::string name, Scalar value)
: value_(value), name(std::move(name)) {}

Value(std::string name, std::vector<ValueId> elem_ids)
: value_(std::move(elem_ids)), name(std::move(name)) {}

ValueKind kind() const {
return static_cast<ValueKind>(value_.index());
}
bool is_tensor() const {
return std::holds_alternative<TensorMeta>(value_);
}
bool is_scalar() const {
return std::holds_alternative<Scalar>(value_);
}
bool is_list() const {
return std::holds_alternative<std::vector<ValueId>>(value_);
}
bool is_none() const {
return std::holds_alternative<std::monostate>(value_);
}

// Typed payload accessors: throw std::runtime_error unless the kind matches.
const TensorMeta& tensor_meta() const;
const Scalar& scalar() const;
const std::vector<ValueId>& content_ids() const;
};

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

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

runtime.cxx_library(
name = "value",
srcs = ["Value.cpp"],
exported_headers = [
"Value.h",
],
exported_deps = [
":ids",
":scalar",
":tensor_meta",
],
visibility = ["//executorch/backends/native/..."],
)

# utils/ has no BUCK of its own, so the IR printer's target lives here. Kept
# separate from the IR libraries so only a consumer that dumps the IR links
# the formatting code.
Expand Down
Loading