Skip to content
Closed
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
62 changes: 62 additions & 0 deletions backends/native/runtime/Method.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// 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 <string>
#include <vector>

#include <executorch/backends/native/runtime/graph/Graph.h>
#include <executorch/backends/native/runtime/graph/Ids.h>
#include <executorch/backends/native/runtime/graph/Value.h>

namespace ptn {

// Classifies a graph-level output position; pinned to the schema OutputKind
// ids. Orthogonal to ValueRole, which classifies a value's storage: the value
// produced at a mutation output is an ordinary Intermediate, and the Buffer or
// UserInput role sits on its target.
enum class OutputKind : int8_t {
UserOutput = 0,
BufferMutation = 1,
UserInputMutation = 2,
};

// Binds a method-graph placeholder to its external storage, unifying the
// schema's NamedTensorRef (data shipped under `key`) and MutableBufferSpec (no
// data, zero-initialized at load, e.g. a KV cache). Tensor metadata is not
// duplicated — it lives on the bound Value, which also mirrors `role`.
struct DataBinding {
ValueId value_id = kInvalid;
ValueRole role = ValueRole::Parameter; // Parameter / Buffer / ConstantTensor
// Fully-qualified name: the constant-file key if has_data, else the buffer's
// cross-method identity.
std::string key;
bool has_data = true; // false only for a non-persistent Buffer
bool mutated = false; // written in place; state persists across executions
};

// Classifies one graph output. `target_id` is the placeholder value the output
// writes back into — a user input or a buffer, both lifted to placeholders
// here; kInvalid for UserOutput. It replaces the schema's dual-namespace target
// string, whose contents are recoverable from that Value.
struct OutputSpec {
OutputKind kind = OutputKind::UserOutput;
ValueId target_id = kInvalid;
};

// A named method: one top-level pure Graph plus the stateful signature bindings
// that Graph deliberately lacks. HOP subgraphs (inside graph.subgraphs) carry
// no bindings of their own — their params are lifted here and passed as
// operands, which is why Method wraps Graph rather than folding into it.
struct Method {
std::string name;
Graph graph;
std::vector<DataBinding> data_bindings;
std::vector<OutputSpec> output_specs; // aligned to graph.output_ids by index
};

} // namespace ptn
15 changes: 15 additions & 0 deletions backends/native/runtime/graph/Value.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,18 @@ enum class ValueKind : int8_t {
List = 3,
};

// How a Value's storage is owned / sourced. The placeholder roles are pinned to
// the schema InputKind ids; Intermediate extends them for a value a node
// produces. Parameter / ConstantTensor are frozen external data; a Buffer is
// persistent state when its binding ships data, else zero-initialized at load.
enum class ValueRole : int8_t {
UserInput = 0,
Parameter = 1,
Buffer = 2,
ConstantTensor = 3,
Intermediate = 4,
};

// 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
Expand All @@ -53,6 +65,9 @@ class Value {
std::vector<NodeId> consumer_ids;
// Shares storage with this value (a view); fresh if invalid.
ValueId alias_id = kInvalid;
// Stamped from the Method's data bindings, so a value can be classified
// without searching them; the storage itself is located through the binding.
ValueRole role = ValueRole::Intermediate;
// Open annotations for graph passes and engines, like node.meta in FX.
std::unordered_map<std::string, std::any> attrs;

Expand Down
33 changes: 33 additions & 0 deletions backends/native/runtime/targets.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,36 @@ def define_common_targets():
],
visibility = ["PUBLIC"],
)

# A named method: one top-level Graph plus its stateful signature bindings
# (data bindings + output specs). Sits at the Program level (peer to the reader),
# above the graph/ arena package.
runtime.cxx_library(
name = "method",
exported_headers = [
"Method.h",
],
exported_deps = [
"//executorch/backends/native/runtime/graph:graph",
"//executorch/backends/native/runtime/graph:ids",
"//executorch/backends/native/runtime/graph:value",
],
visibility = ["//executorch/backends/native/..."],
)

# The graph/ printer stops at Graph, since Method sits above that package;
# this adds the method layer on top of it.
runtime.cxx_library(
name = "print",
srcs = [
"utils/Print.cpp",
],
exported_headers = [
"utils/Print.h",
],
exported_deps = [
":method",
"//executorch/backends/native/runtime/graph:print",
],
visibility = ["//executorch/backends/native/..."],
)
78 changes: 78 additions & 0 deletions backends/native/runtime/utils/Print.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// 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/utils/Print.h>

#include <cstddef>
#include <string>

namespace ptn {

namespace {

const char* output_kind_name(OutputKind kind) {
switch (kind) {
case OutputKind::UserOutput:
return "UserOutput";
case OutputKind::BufferMutation:
return "BufferMutation";
case OutputKind::UserInputMutation:
return "UserInputMutation";
}
return "?";
}

const char* value_role_name(ValueRole role) {
switch (role) {
case ValueRole::Intermediate:
return "Intermediate";
case ValueRole::UserInput:
return "UserInput";
case ValueRole::Parameter:
return "Parameter";
case ValueRole::Buffer:
return "Buffer";
case ValueRole::ConstantTensor:
return "ConstantTensor";
}
return "?";
}

} // namespace

std::string to_string(const Method& method) {
std::string s = "method " + method.name + "\n";
s += to_string(method.graph);

s += "data_bindings: [";
for (size_t i = 0; i < method.data_bindings.size(); ++i) {
if (i) {
s += ", ";
}
const DataBinding& b = method.data_bindings[i];
s += "%" + std::to_string(b.value_id) + "=" + b.key + "(" +
value_role_name(b.role) + (b.has_data ? "" : ",zero_init") +
(b.mutated ? ",mutated" : "") + ")";
}
s += "]\n";

s += "output_specs: [";
for (size_t i = 0; i < method.output_specs.size(); ++i) {
if (i) {
s += ", ";
}
const OutputSpec& o = method.output_specs[i];
s += output_kind_name(o.kind);
if (valid(o.target_id)) {
s += "(%" + std::to_string(o.target_id) + ")";
}
}
s += "]\n";

return s;
}

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

#include <executorch/backends/native/runtime/Method.h>
#include <executorch/backends/native/runtime/graph/utils/Print.h>

namespace ptn {

// The method layer of the IR printer, split out only because Method sits above
// the graph/ package. Same contract: debug-only, for humans, not parsed back.

// Multi-line: the method name, its graph, then the binding tables.
std::string to_string(const Method& method);

} // namespace ptn
Loading