chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:40:42 +08:00
commit e25996e7db
15472 changed files with 3536181 additions and 0 deletions
@@ -0,0 +1,20 @@
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <c10/util/Optional.h>
#include <torch/cuda.h>
#include <torch/sparse.h>
#include <torch/types.h>
@@ -0,0 +1,60 @@
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <c10/cuda/CUDAFunctions.h>
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
#include <c10/cuda/CUDAGuard.h>
#endif
#include <c10/util/Exception.h>
#include <torch/cuda.h>
#include "paddle/phi/backends/gpu/gpu_info.h"
#include "paddle/phi/core/platform/device/gpu/gpu_info.h"
#include "paddle/phi/core/platform/device_event_base.h"
namespace torch::cuda {
c10::DeviceIndex device_count() {
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
return phi::backends::gpu::GetGPUDeviceCount();
#else
// Match PyTorch c10::cuda::device_count(): return 0 in CPU-only builds so
// that is_available() and the pre-checks of synchronize() degrade gracefully
// through a single, consistent "No CUDA GPUs are available" error path.
return 0;
#endif
}
bool is_available() { return cuda::device_count() > 0; }
void synchronize(int64_t device_index) {
TORCH_CHECK(is_available(), "No CUDA GPUs are available");
auto num_gpus = cuda::device_count();
TORCH_CHECK(
device_index == -1 || (device_index >= 0 && device_index < num_gpus),
"Device index out of range: ",
device_index);
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
// Match PyTorch semantics:
// 1. `device_index == -1` means "current CUDA device".
// 2. Explicit device synchronization must not leak a changed current device
// to the caller after returning.
const c10::cuda::CUDAGuard device_guard(c10::Device(
c10::DeviceType::CUDA, static_cast<c10::DeviceIndex>(device_index)));
c10::cuda::device_synchronize();
#endif
// CPU-only builds are already rejected above by the is_available() check.
}
} // namespace torch::cuda
@@ -0,0 +1,32 @@
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <c10/core/Device.h>
#include <cstdint>
#include "paddle/common/macros.h"
namespace torch::cuda {
PADDLE_API c10::DeviceIndex device_count();
PADDLE_API bool is_available();
PADDLE_API void synchronize(int64_t device_index = -1);
} // namespace torch::cuda
namespace at::cuda {
using torch::cuda::synchronize;
} // namespace at::cuda
@@ -0,0 +1,19 @@
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// The file has been adapted from pytorch project
// Licensed under BSD-style license -
// https://github.com/pytorch/pytorch/blob/main/LICENSE
#pragma once
@@ -0,0 +1,50 @@
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// The file has been adapted from pytorch project
// Licensed under BSD-style license -
// https://github.com/pytorch/pytorch/blob/main/LICENSE
#pragma once
#include <ATen/Device.h>
#include <ATen/ops/arange.h>
#include <ATen/ops/empty_strided.h>
#include <c10/util/Exception.h>
#include <torch/types.h>
#include <utils/scalar_type_conversion.h>
#if !defined(PADDLE_ON_INFERENCE) && !defined(PADDLE_NO_PYTHON)
// Python bindings for the C++ frontend (includes Python.h)
#include "paddle/utils/pybind.h"
#endif
namespace torch::python {
namespace detail {
inline Dtype py_object_to_dtype(py::object object) {
PyObject* obj = object.ptr();
return *reinterpret_cast<Dtype*>(obj);
}
inline PyObject* getTHPDtype(c10::ScalarType dtype) {
return paddle::pybind::ToPyObject(
compat::_PD_AtenScalarTypeToPhiDataType(dtype));
}
} // namespace detail
} // namespace torch::python
namespace torch {
using torch::python::detail::getTHPDtype;
} // namespace torch
@@ -0,0 +1,17 @@
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <ATen/ATen.h>
@@ -0,0 +1,22 @@
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// The file has been adapted from pytorch project
// Licensed under BSD-style license -
// https://github.com/pytorch/pytorch/blob/main/LICENSE
#pragma once
#include <torch/all.h>
#include <torch/extension.h>
@@ -0,0 +1,60 @@
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// The file has been adapted from pytorch project
// Licensed under BSD-style license -
// https://github.com/pytorch/pytorch/blob/main/LICENSE
#pragma once
#include <ATen/ATen.h>
#include <ATen/Functions.h>
#include <ATen/core/TensorBody.h>
#include <c10/core/ScalarType.h>
#include <c10/util/OptionalArrayRef.h>
namespace torch {
using namespace at; // NOLINT
using std::nullopt; // NOLINT
using std::optional; // NOLINT
using Dtype = at::ScalarType;
constexpr auto kUInt8 = at::kByte;
constexpr auto kInt8 = at::kChar;
constexpr auto kInt16 = at::kShort;
constexpr auto kInt32 = at::kInt;
constexpr auto kInt64 = at::kLong;
constexpr auto kUInt16 = at::kUInt16;
constexpr auto kUInt32 = at::kUInt32;
constexpr auto kFloat16 = at::kHalf;
constexpr auto kFloat32 = at::kFloat;
constexpr auto kFloat64 = at::kDouble;
constexpr auto kBFloat16 = at::kBFloat16;
constexpr auto kU8 = kUInt8;
constexpr auto kU16 = kUInt16;
constexpr auto kU32 = kUInt32;
constexpr auto kI8 = kInt8;
constexpr auto kI16 = kInt16;
constexpr auto kI32 = kInt32;
constexpr auto kI64 = kInt64;
constexpr auto kF16 = kFloat16;
constexpr auto kF32 = kFloat32;
constexpr auto kF64 = kFloat64;
} // namespace torch
@@ -0,0 +1,39 @@
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
/// Indicates the major version of LibTorch.
#define TORCH_VERSION_MAJOR 2
/// Indicates the minor version of LibTorch.
#define TORCH_VERSION_MINOR 10
/// Indicates the patch version of LibTorch.
#define TORCH_VERSION_PATCH 0
/// Indicates the ABI version tag of LibTorch.
#define TORCH_VERSION_ABI_TAG 0
/// Indicates the version of LibTorch as a string literal.
#define TORCH_VERSION "2.10.0"
/// Indicates the ABI version of LibTorch as a single uint64.
/// [ byte ][ byte ][ byte ][ byte ][ byte ][ byte ][ byte ][ byte ]
/// [ MAJ ][ MIN ][ PATCH][ ABI TAG ]
#define TORCH_ABI_VERSION \
(((0ULL + TORCH_VERSION_MAJOR) << 56) | \
((0ULL + TORCH_VERSION_MINOR) << 48) | /* NOLINT(whitespace/indent) */ \
((0ULL + TORCH_VERSION_PATCH) << 40) | /* NOLINT(whitespace/indent) */ \
((0ULL + TORCH_VERSION_ABI_TAG) << 0)) /* NOLINT(whitespace/indent) */
@@ -0,0 +1,583 @@
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// The file has been adapted from pytorch project
// Licensed under BSD-style license -
// https://github.com/pytorch/pytorch/blob/main/LICENSE
#include "torch/csrc/jit/function_schema_parser.h"
#include "glog/logging.h"
#include "torch/csrc/jit/schema_parser_defs.h"
#include "torch/csrc/jit/schema_type_parser.h"
namespace torch::jit {
namespace {
std::string parsedDeclarationToDebugString(
const std::variant<std::string, c10::FunctionSchema>& parsed) {
// Used only in parser debug logs so we can see whether we parsed
// an operator name or a full function schema.
std::ostringstream os;
if (std::holds_alternative<std::string>(parsed)) {
os << "name(" << std::get<std::string>(parsed) << ")";
} else {
os << "schema" << std::get<c10::FunctionSchema>(parsed);
}
return os.str();
}
std::string schemaTypeRuntimeClassName(const c10::Type& type) {
if (dynamic_cast<const c10::detail::SchemaAtomicType*>(&type)) {
return "c10::detail::SchemaAtomicType";
}
if (dynamic_cast<const c10::detail::SchemaOptionalType*>(&type)) {
return "c10::detail::SchemaOptionalType";
}
if (dynamic_cast<const c10::detail::SchemaTupleType*>(&type)) {
return "c10::detail::SchemaTupleType";
}
return typeid(type).name();
}
const char* schemaTypeKindName(c10::TypeKind kind) {
switch (kind) {
#define TORCH_SCHEMA_KIND_CASE(T) \
case c10::TypeKind::T: \
return #T;
C10_FORALL_TYPES(TORCH_SCHEMA_KIND_CASE)
#undef TORCH_SCHEMA_KIND_CASE
default:
return "UnknownTypeKind";
}
}
void appendTypeTree(std::ostringstream& os,
const c10::TypePtr& type,
int depth) {
// Recursively dump the parsed type tree (e.g. Optional[Tuple[...]])
// for verbose parser tracing.
const std::string indent(static_cast<size_t>(depth) * 2, ' ');
if (!type) {
os << "\n" << indent << "- <null type>";
return;
}
os << "\n"
<< indent << "- str=`" << type->str()
<< "`, kind=" << schemaTypeKindName(type->kind())
<< ", class=" << schemaTypeRuntimeClassName(*type);
const auto children = type->containedTypes();
for (const auto& child : children) {
appendTypeTree(os, child, depth + 1);
}
}
std::string buildFunctionSchemaTypeTreeDebugString(
const c10::FunctionSchema& schema) {
std::ostringstream os;
os << "schema_type_tree";
for (size_t i = 0; i < schema.arguments().size(); ++i) {
const auto& arg = schema.arguments()[i];
os << "\narg[" << i << "] `" << arg.name() << "`";
appendTypeTree(os, arg.type(), 1);
}
for (size_t i = 0; i < schema.returns().size(); ++i) {
const auto& ret = schema.returns()[i];
os << "\nret[" << i << "] `" << ret.name() << "`";
appendTypeTree(os, ret.type(), 1);
}
return os.str();
}
class SchemaParser final {
public:
explicit SchemaParser(const std::string& schema) : schema_(schema) {}
std::variant<std::string, c10::FunctionSchema> parseExactlyOneDeclaration() {
// Parse exactly one declaration and reject trailing characters so callers
// can treat a successful parse as fully validated schema text.
skipWhitespace();
if (atEnd()) {
return std::string();
}
auto result = parseDeclaration();
skipWhitespace();
TORCH_CHECK(atEnd(), "Unexpected trailing content", posInfo());
return result;
}
private:
std::variant<std::string, c10::FunctionSchema> parseDeclaration() {
// Declarations are either:
// 1) operator name only
// 2) full schema: name(args) -> returns
const std::string name = parseOperatorName();
skipWhitespace();
if (atEnd() || peek() != TORCH_SCHEMA_CH_LPAREN) {
return name;
}
std::vector<c10::Argument> arguments;
std::vector<c10::Argument> returns;
bool kwarg_only = false;
bool is_vararg = false;
bool is_varret = false;
size_t idx = 0;
parseDelimitedList(TORCH_SCHEMA_CH_LPAREN, TORCH_SCHEMA_CH_RPAREN, [&] {
skipWhitespace();
if (consumeLiteral(TORCH_SCHEMA_LIT_VARARG)) {
TORCH_CHECK(
!is_vararg, "Duplicate vararg (...) declaration", posInfo());
is_vararg = true;
return;
}
if (consumeChar(TORCH_SCHEMA_CH_STAR)) {
kwarg_only = true;
return;
}
TORCH_CHECK(!is_vararg,
"... must be the last element of the argument list",
posInfo());
arguments.push_back(
parseArgument(idx++, /*is_return=*/false, /*kwarg_only=*/kwarg_only));
});
if (is_vararg) {
for (const auto& arg : arguments) {
TORCH_CHECK(!arg.default_value().has_value(),
"Schemas with vararg (...) cannot have default arguments");
}
}
skipWhitespace();
expectLiteral(TORCH_SCHEMA_LIT_ARROW);
skipWhitespace();
// In FunctionSchema, `-> (T1, T2)` means two return slots. It is not a
// single Tuple type return unless the schema explicitly encodes that type.
if (consumeLiteral(TORCH_SCHEMA_LIT_VARARG)) {
is_varret = true;
} else if (consumeChar(TORCH_SCHEMA_CH_LPAREN)) {
skipWhitespace();
if (!consumeChar(TORCH_SCHEMA_CH_RPAREN)) {
size_t return_idx = 0;
while (true) {
skipWhitespace();
if (consumeLiteral(TORCH_SCHEMA_LIT_VARARG)) {
TORCH_CHECK(
!is_varret, "Duplicate varret (...) declaration", posInfo());
is_varret = true;
skipWhitespace();
TORCH_CHECK(peek() == TORCH_SCHEMA_CH_RPAREN,
"... must be the last element of the return list",
posInfo());
} else {
TORCH_CHECK(!is_varret,
"... must be the last element of the return list",
posInfo());
returns.push_back(parseArgument(
return_idx++, /*is_return=*/true, /*kwarg_only=*/false));
}
skipWhitespace();
if (consumeChar(TORCH_SCHEMA_CH_COMMA)) {
continue;
}
expectChar(TORCH_SCHEMA_CH_RPAREN);
break;
}
}
} else {
returns.push_back(
parseArgument(0, /*is_return=*/true, /*kwarg_only=*/false));
}
return c10::FunctionSchema(
std::move(arguments), std::move(returns), is_vararg, is_varret);
}
c10::Argument parseArgument(size_t /*idx*/, bool is_return, bool kwarg_only) {
// Type and alias syntax is parsed by SchemaTypeParser. This method handles
// argument-level decorations such as fixed-size list suffixes, names and
// defaults.
SchemaTypeParser type_parser(schema_, &pos_, &next_fresh_alias_id_);
ParsedType parsed = type_parser.parseType();
std::optional<int32_t> N;
std::optional<torch::IValue> default_value;
std::string name;
skipWhitespace();
if (!is_return && consumeChar(TORCH_SCHEMA_CH_LBRACKET)) {
skipWhitespace();
const std::string n_str = parseUnsignedNumber();
int64_t n64 = 0;
try {
n64 = std::stoll(n_str);
} catch (const std::exception&) {
TORCH_CHECK(false, "Invalid fixed-size list length", posInfo());
}
TORCH_CHECK(n64 >= 0 && n64 <= std::numeric_limits<int32_t>::max(),
"Fixed-size list length out of range",
posInfo());
N = static_cast<int32_t>(n64);
skipWhitespace();
expectChar(TORCH_SCHEMA_CH_RBRACKET);
skipWhitespace();
if (consumeChar(TORCH_SCHEMA_CH_QMARK)) {
parsed.type = c10::makeSchemaOptionalType(parsed.type);
}
// Container alias annotation belongs to the outer list-like container.
// Element alias information is kept as contained type alias metadata.
auto container_alias = type_parser.parseAliasAnnotation();
if (container_alias.has_value() && parsed.alias_info.has_value()) {
container_alias->addContainedType(std::move(*parsed.alias_info));
}
if (container_alias.has_value()) {
parsed.alias_info = std::move(container_alias);
}
}
if (is_return) {
skipWhitespace();
if (!atEnd() && isIdentifierStart(peek())) {
name = parseIdentifier("return field name");
} else {
name = "";
}
} else {
name = parseIdentifier("argument name");
skipWhitespace();
if (consumeChar(TORCH_SCHEMA_CH_EQUAL)) {
default_value = parseDefaultValue(*parsed.type);
}
}
return c10::Argument(std::move(name),
parsed.type,
parsed.type,
N,
std::move(default_value),
!is_return && kwarg_only,
std::move(parsed.alias_info));
}
torch::IValue parseDefaultValue(const c10::Type& arg_type) {
skipWhitespace();
TORCH_CHECK(!atEnd(), "Missing default value", posInfo());
if (consumeKeyword(TORCH_SCHEMA_KW_NONE)) {
return torch::IValue();
}
if (consumeKeyword(TORCH_SCHEMA_KW_TRUE)) {
return torch::IValue(true);
}
if (consumeKeyword(TORCH_SCHEMA_KW_FALSE)) {
return torch::IValue(false);
}
if (peek() == TORCH_SCHEMA_CH_DQUOTE || peek() == TORCH_SCHEMA_CH_SQUOTE) {
return torch::IValue(parseStringLiteral());
}
if (peek() == TORCH_SCHEMA_CH_PLUS || peek() == TORCH_SCHEMA_CH_MINUS ||
std::isdigit(peekAsUnsigned())) {
return parseNumericLiteral();
}
if (isIdentifierStart(peek())) {
const std::string ident = parseIdentifier("default value");
TORCH_CHECK(arg_type.kind() == c10::TypeKind::StringType,
"Unsupported identifier default value `",
ident,
"`",
posInfo());
return torch::IValue(ident);
}
TORCH_CHECK(false, "Unsupported default value", posInfo());
}
torch::IValue parseNumericLiteral() {
skipWhitespace();
const size_t start = pos_;
bool seen_digit = false;
bool is_float = false;
if (peek() == TORCH_SCHEMA_CH_PLUS || peek() == TORCH_SCHEMA_CH_MINUS) {
++pos_;
}
while (!atEnd() && std::isdigit(peekAsUnsigned())) {
++pos_;
seen_digit = true;
}
if (!atEnd() && peek() == TORCH_SCHEMA_CH_DOT) {
is_float = true;
++pos_;
while (!atEnd() && std::isdigit(peekAsUnsigned())) {
++pos_;
seen_digit = true;
}
}
if (!atEnd() && (peek() == TORCH_SCHEMA_CH_EXP_LOWER ||
peek() == TORCH_SCHEMA_CH_EXP_UPPER)) {
is_float = true;
++pos_;
if (!atEnd() &&
(peek() == TORCH_SCHEMA_CH_PLUS || peek() == TORCH_SCHEMA_CH_MINUS)) {
++pos_;
}
bool has_exp_digit = false;
while (!atEnd() && std::isdigit(peekAsUnsigned())) {
++pos_;
has_exp_digit = true;
}
TORCH_CHECK(has_exp_digit, "Malformed numeric literal", posInfo());
}
TORCH_CHECK(seen_digit, "Malformed numeric literal", posInfo());
const std::string literal = schema_.substr(start, pos_ - start);
try {
if (is_float) {
return torch::IValue(std::stod(literal));
}
return torch::IValue(static_cast<int64_t>(std::stoll(literal)));
} catch (const std::exception&) {
TORCH_CHECK(
false, "Failed to parse numeric literal `", literal, "`", posInfo());
}
}
std::string parseStringLiteral() {
skipWhitespace();
TORCH_CHECK(!atEnd() && (peek() == TORCH_SCHEMA_CH_DQUOTE ||
peek() == TORCH_SCHEMA_CH_SQUOTE),
"Expected string literal",
posInfo());
const char quote = peek();
++pos_;
std::string out;
while (!atEnd()) {
char c = schema_[pos_++];
if (c == quote) {
return out;
}
if (c == TORCH_SCHEMA_CH_BACKSLASH) {
TORCH_CHECK(!atEnd(), "Unterminated escape sequence", posInfo());
const char escaped = schema_[pos_++];
switch (escaped) {
case TORCH_SCHEMA_CH_N:
out.push_back('\n');
break;
case TORCH_SCHEMA_CH_T:
out.push_back('\t');
break;
case TORCH_SCHEMA_CH_R:
out.push_back('\r');
break;
case TORCH_SCHEMA_CH_BACKSLASH:
out.push_back('\\');
break;
case TORCH_SCHEMA_CH_SQUOTE:
out.push_back('\'');
break;
case TORCH_SCHEMA_CH_DQUOTE:
out.push_back('"');
break;
default:
out.push_back(escaped);
break;
}
} else {
out.push_back(c);
}
}
TORCH_CHECK(false, "Unterminated string literal", posInfo());
}
template <typename Callback>
void parseDelimitedList(char begin, char end, Callback&& callback) {
// Shared list parser for "(...)" sections with comma-separated elements.
skipWhitespace();
expectChar(begin);
skipWhitespace();
if (consumeChar(end)) {
return;
}
while (true) {
callback();
skipWhitespace();
if (consumeChar(TORCH_SCHEMA_CH_COMMA)) {
continue;
}
expectChar(end);
return;
}
}
std::string parseOperatorName() {
skipWhitespace();
const size_t start = pos_;
while (!atEnd()) {
const char c = peek();
if (std::isspace(peekAsUnsigned()) || c == TORCH_SCHEMA_CH_LPAREN) {
break;
}
++pos_;
}
TORCH_CHECK(start != pos_, "Expected operator name", posInfo());
return schema_.substr(start, pos_ - start);
}
std::string parseIdentifier(const char* desc) {
skipWhitespace();
TORCH_CHECK(
!atEnd() && isIdentifierStart(peek()), "Expected ", desc, posInfo());
const size_t start = pos_++;
while (!atEnd() && isIdentifierChar(peek())) {
++pos_;
}
return schema_.substr(start, pos_ - start);
}
std::string parseUnsignedNumber() {
skipWhitespace();
TORCH_CHECK(!atEnd() && std::isdigit(peekAsUnsigned()),
"Expected an unsigned number",
posInfo());
const size_t start = pos_++;
while (!atEnd() && std::isdigit(peekAsUnsigned())) {
++pos_;
}
return schema_.substr(start, pos_ - start);
}
bool consumeKeyword(const char* kw) {
skipWhitespace();
const size_t len = std::char_traits<char>::length(kw);
if (schema_.compare(pos_, len, kw) != 0) {
return false;
}
const size_t next = pos_ + len;
if (next < schema_.size() && isIdentifierChar(schema_[next])) {
return false;
}
pos_ = next;
return true;
}
bool consumeLiteral(const char* literal) {
const size_t len = std::char_traits<char>::length(literal);
if (schema_.compare(pos_, len, literal) == 0) {
pos_ += len;
return true;
}
return false;
}
void expectLiteral(const char* literal) {
TORCH_CHECK(consumeLiteral(literal), "Expected `", literal, "`", posInfo());
}
bool consumeChar(char c) {
if (!atEnd() && schema_[pos_] == c) {
++pos_;
return true;
}
return false;
}
void expectChar(char c) {
TORCH_CHECK(
!atEnd() && schema_[pos_] == c, "Expected `", c, "`", posInfo());
++pos_;
}
char peek() const {
TORCH_INTERNAL_ASSERT(!atEnd());
return schema_[pos_];
}
unsigned char peekAsUnsigned() const {
return static_cast<unsigned char>(peek());
}
bool atEnd() const { return pos_ >= schema_.size(); }
void skipWhitespace() {
while (!atEnd() && std::isspace(peekAsUnsigned())) {
++pos_;
}
}
static bool isIdentifierStart(char c) {
const auto uc = static_cast<unsigned char>(c);
return std::isalpha(uc) || c == '_';
}
static bool isIdentifierChar(char c) {
const auto uc = static_cast<unsigned char>(c);
return std::isalnum(uc) || c == '_';
}
std::string posInfo() const {
std::ostringstream os;
os << " at position " << pos_ << " in schema `" << schema_ << "`";
return os.str();
}
const std::string& schema_;
size_t pos_{0};
size_t next_fresh_alias_id_{0};
};
} // namespace
std::variant<std::string, c10::FunctionSchema> parseSchemaOrName(
const std::string& schemaOrName) {
auto parsed = SchemaParser(schemaOrName).parseExactlyOneDeclaration();
VLOG(3) << "parseSchemaOrName input=`" << schemaOrName
<< "` parsed=" << parsedDeclarationToDebugString(parsed);
if (VLOG_IS_ON(4) && std::holds_alternative<c10::FunctionSchema>(parsed)) {
VLOG(4) << buildFunctionSchemaTypeTreeDebugString(
std::get<c10::FunctionSchema>(parsed));
}
return parsed;
}
c10::FunctionSchema parseSchema(const std::string& schema) {
auto parsed = parseSchemaOrName(schema);
TORCH_CHECK(
std::holds_alternative<c10::FunctionSchema>(parsed),
"Tried to parse a function schema but only the operator name was given");
VLOG(3) << "parseSchema input=`" << schema
<< "` output=" << std::get<c10::FunctionSchema>(parsed);
return std::get<c10::FunctionSchema>(std::move(parsed));
}
std::string parseName(const std::string& name) {
auto parsed = parseSchemaOrName(name);
TORCH_CHECK(
std::holds_alternative<std::string>(parsed),
"Tried to parse an operator name but a function schema was given");
VLOG(3) << "parseName input=`" << name
<< "` output=" << std::get<std::string>(parsed);
return std::get<std::string>(std::move(parsed));
}
std::string schemaTypeTreeToDebugString(const c10::FunctionSchema& schema) {
return buildFunctionSchemaTypeTreeDebugString(schema);
}
} // namespace torch::jit
@@ -0,0 +1,39 @@
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// The file has been adapted from pytorch project
// Licensed under BSD-style license -
// https://github.com/pytorch/pytorch/blob/main/LICENSE
#pragma once
#include <ATen/core/function_schema.h>
#include <c10/macros/Macros.h>
#include <string>
#include <variant>
namespace torch::jit {
// allow_typevars: If true, we assume that lowercase types that we don't
// understand are type variables. This is only needed for TorchScript (and not
// not needed for custom ops).
// If false, we disallow typevars, except in certain cases for BC reason (i.e.
// your op is in the aten or prim namespace).
PADDLE_API std::variant<std::string, c10::FunctionSchema> parseSchemaOrName(
const std::string& schemaOrName);
PADDLE_API c10::FunctionSchema parseSchema(const std::string& schema);
PADDLE_API std::string parseName(const std::string& name);
PADDLE_API std::string schemaTypeTreeToDebugString(
const c10::FunctionSchema& schema);
} // namespace torch::jit
@@ -0,0 +1,86 @@
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
// Common literals
#define TORCH_SCHEMA_LIT_VARARG "..."
#define TORCH_SCHEMA_LIT_ARROW "->"
// Common keywords
#define TORCH_SCHEMA_KW_NONE "None"
#define TORCH_SCHEMA_KW_TRUE "true"
#define TORCH_SCHEMA_KW_FALSE "false"
// Common characters
#define TORCH_SCHEMA_CH_LPAREN '('
#define TORCH_SCHEMA_CH_RPAREN ')'
#define TORCH_SCHEMA_CH_LBRACKET '['
#define TORCH_SCHEMA_CH_RBRACKET ']'
#define TORCH_SCHEMA_CH_COMMA ','
#define TORCH_SCHEMA_CH_STAR '*'
#define TORCH_SCHEMA_CH_BANG '!'
#define TORCH_SCHEMA_CH_PIPE '|'
#define TORCH_SCHEMA_CH_QMARK '?'
#define TORCH_SCHEMA_CH_EQUAL '='
#define TORCH_SCHEMA_CH_DOT '.'
#define TORCH_SCHEMA_CH_PLUS '+'
#define TORCH_SCHEMA_CH_MINUS '-'
#define TORCH_SCHEMA_CH_EXP_LOWER 'e'
#define TORCH_SCHEMA_CH_EXP_UPPER 'E'
#define TORCH_SCHEMA_CH_DQUOTE '"'
#define TORCH_SCHEMA_CH_SQUOTE '\''
#define TORCH_SCHEMA_CH_BACKSLASH '\\'
#define TORCH_SCHEMA_CH_N 'n'
#define TORCH_SCHEMA_CH_T 't'
#define TORCH_SCHEMA_CH_R 'r'
// Alias syntax literals
#define TORCH_SCHEMA_ALIAS_WILDCARD "*"
#define TORCH_SCHEMA_ALIAS_FRESH_PREFIX "$"
// Type spellings in schema text
#define TORCH_SCHEMA_TYPE_CPP_DOUBLE "double"
#define TORCH_SCHEMA_TYPE_CPP_INT64_T "int64_t"
#define TORCH_SCHEMA_TYPE_TENSOR "Tensor"
#define TORCH_SCHEMA_TYPE_STR "str"
#define TORCH_SCHEMA_TYPE_STRING "string"
#define TORCH_SCHEMA_TYPE_INT "int"
#define TORCH_SCHEMA_TYPE_FLOAT "float"
#define TORCH_SCHEMA_TYPE_BOOL "bool"
#define TORCH_SCHEMA_TYPE_NONE "None"
#define TORCH_SCHEMA_TYPE_NONE_TYPE "NoneType"
#define TORCH_SCHEMA_TYPE_DEVICE "Device"
#define TORCH_SCHEMA_TYPE_SCALAR "Scalar"
#define TORCH_SCHEMA_TYPE_NUMBER "number"
// Base type conversion table for schema text -> TypeKind + canonical repr.
// Entry shape:
// _(input_text_literal, type_kind_enum_member, canonical_repr_literal)
// Notes:
// - Some entries intentionally map aliases to the same canonical repr.
// - This table only covers atomic/base types; tuple/optional are parsed
// structurally in SchemaTypeParser::parseType().
#define TORCH_SCHEMA_BASE_TYPE_CONVERSION_TABLE(_) \
_(TORCH_SCHEMA_TYPE_TENSOR, TensorType, TORCH_SCHEMA_TYPE_TENSOR) \
_(TORCH_SCHEMA_TYPE_STR, StringType, TORCH_SCHEMA_TYPE_STR) \
_(TORCH_SCHEMA_TYPE_STRING, StringType, TORCH_SCHEMA_TYPE_STR) \
_(TORCH_SCHEMA_TYPE_INT, IntType, TORCH_SCHEMA_TYPE_INT) \
_(TORCH_SCHEMA_TYPE_FLOAT, FloatType, TORCH_SCHEMA_TYPE_FLOAT) \
_(TORCH_SCHEMA_TYPE_BOOL, BoolType, TORCH_SCHEMA_TYPE_BOOL) \
_(TORCH_SCHEMA_TYPE_NONE, NoneType, TORCH_SCHEMA_TYPE_NONE_TYPE) \
_(TORCH_SCHEMA_TYPE_NONE_TYPE, NoneType, TORCH_SCHEMA_TYPE_NONE_TYPE) \
_(TORCH_SCHEMA_TYPE_DEVICE, DeviceObjType, TORCH_SCHEMA_TYPE_DEVICE) \
_(TORCH_SCHEMA_TYPE_SCALAR, NumberType, TORCH_SCHEMA_TYPE_SCALAR) \
_(TORCH_SCHEMA_TYPE_NUMBER, NumberType, TORCH_SCHEMA_TYPE_SCALAR)
@@ -0,0 +1,240 @@
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "torch/csrc/jit/schema_type_parser.h"
#include "torch/csrc/jit/schema_parser_defs.h"
#include <cctype>
#include <set>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
namespace torch::jit {
size_t& SchemaTypeParser::refFromPtr(size_t* ptr, const char* name) {
TORCH_CHECK(ptr != nullptr, name, " must not be null");
return *ptr;
}
c10::TypePtr SchemaTypeParser::parseBaseType() {
// Map textual schema type names to compat lightweight type objects.
std::string type_name = parseDottedIdentifier("type");
if (type_name == TORCH_SCHEMA_TYPE_CPP_DOUBLE) {
TORCH_CHECK(false,
"Use `float` instead of `double` in schema declarations",
posInfo());
}
if (type_name == TORCH_SCHEMA_TYPE_CPP_INT64_T) {
TORCH_CHECK(false,
"Use `int` instead of `int64_t` in schema declarations",
posInfo());
}
#define TORCH_SCHEMA_BASE_TYPE_CASE(TEXT, KIND, REPR) \
if (type_name == TEXT) { \
return c10::makeSchemaAtomicType(c10::TypeKind::KIND, (REPR)); \
}
TORCH_SCHEMA_BASE_TYPE_CONVERSION_TABLE(TORCH_SCHEMA_BASE_TYPE_CASE)
#undef TORCH_SCHEMA_BASE_TYPE_CASE
TORCH_CHECK(false, "Unsupported type specifier `", type_name, "`", posInfo());
}
std::optional<c10::AliasInfo> SchemaTypeParser::parseAliasAnnotation() {
// Supported alias forms:
// (a), (a!), (a! -> b|c), !
// where bare '!' creates a fresh write alias set.
skipWhitespace();
if (consumeChar(TORCH_SCHEMA_CH_LPAREN)) {
std::set<std::string> before_sets;
parseAliasSetList(&before_sets);
skipWhitespace();
const bool is_write = consumeChar(TORCH_SCHEMA_CH_BANG);
std::set<std::string> after_sets = before_sets;
skipWhitespace();
if (consumeLiteral(TORCH_SCHEMA_LIT_ARROW)) {
after_sets.clear();
parseAliasSetList(&after_sets);
}
skipWhitespace();
TORCH_CHECK(!atEnd() && peek() == TORCH_SCHEMA_CH_RPAREN,
"Expected `)`",
posInfo());
consumeChar(TORCH_SCHEMA_CH_RPAREN);
return c10::AliasInfo(is_write, before_sets, after_sets);
}
if (consumeChar(TORCH_SCHEMA_CH_BANG)) {
std::set<std::string> fresh_set{
std::string(TORCH_SCHEMA_ALIAS_FRESH_PREFIX) +
std::to_string(next_fresh_alias_id_++)};
return c10::AliasInfo(true, fresh_set, fresh_set);
}
return std::nullopt;
}
ParsedType SchemaTypeParser::parseType() {
// Parse a full type expression including:
// - tuple forms: (T1, T2, ...)
// - alias suffixes
// - optional suffix '?'
skipWhitespace();
ParsedType out;
if (consumeChar(TORCH_SCHEMA_CH_LPAREN)) {
std::vector<c10::TypePtr> elements;
std::vector<std::optional<c10::AliasInfo>> element_aliases;
skipWhitespace();
if (!consumeChar(TORCH_SCHEMA_CH_RPAREN)) {
while (true) {
ParsedType elem = parseType();
elements.push_back(elem.type);
element_aliases.push_back(std::move(elem.alias_info));
skipWhitespace();
if (consumeChar(TORCH_SCHEMA_CH_COMMA)) {
continue;
}
TORCH_CHECK(!atEnd() && peek() == TORCH_SCHEMA_CH_RPAREN,
"Expected `)`",
posInfo());
consumeChar(TORCH_SCHEMA_CH_RPAREN);
break;
}
}
out.type = c10::makeSchemaTupleType(std::move(elements));
out.alias_info = parseAliasAnnotation();
// If tuple elements carry alias info, attach them as contained aliases
// of the tuple-level alias metadata.
bool has_contained_alias = false;
for (const auto& alias : element_aliases) {
if (alias.has_value()) {
has_contained_alias = true;
break;
}
}
if (has_contained_alias) {
if (!out.alias_info.has_value()) {
out.alias_info.emplace();
}
for (auto& alias : element_aliases) {
if (alias.has_value()) {
out.alias_info->addContainedType(std::move(*alias));
}
}
}
} else {
out.type = parseBaseType();
out.alias_info = parseAliasAnnotation();
}
skipWhitespace();
if (consumeChar(TORCH_SCHEMA_CH_QMARK)) {
out.type = c10::makeSchemaOptionalType(out.type);
}
return out;
}
void SchemaTypeParser::parseAliasSetList(std::set<std::string>* sets) {
TORCH_CHECK(sets != nullptr, "Alias set output must not be null");
// Parse alias set unions: a|b|*.
skipWhitespace();
while (true) {
if (consumeChar(TORCH_SCHEMA_CH_STAR)) {
sets->insert(TORCH_SCHEMA_ALIAS_WILDCARD);
} else {
sets->insert(parseIdentifier("alias set"));
}
skipWhitespace();
if (!consumeChar(TORCH_SCHEMA_CH_PIPE)) {
break;
}
skipWhitespace();
}
TORCH_CHECK(!sets->empty(), "Empty alias set annotation", posInfo());
}
std::string SchemaTypeParser::parseIdentifier(const char* desc) {
skipWhitespace();
TORCH_CHECK(
!atEnd() && isIdentifierStart(peek()), "Expected ", desc, posInfo());
const size_t start = pos_++;
while (!atEnd() && isIdentifierChar(peek())) {
++pos_;
}
return schema_.substr(start, pos_ - start);
}
std::string SchemaTypeParser::parseDottedIdentifier(const char* desc) {
std::string ident = parseIdentifier(desc);
skipWhitespace();
while (consumeChar(TORCH_SCHEMA_CH_DOT)) {
ident.push_back(TORCH_SCHEMA_CH_DOT);
ident += parseIdentifier(desc);
skipWhitespace();
}
return ident;
}
void SchemaTypeParser::skipWhitespace() {
while (!atEnd() && std::isspace(peekAsUnsigned())) {
++pos_;
}
}
bool SchemaTypeParser::consumeLiteral(const char* literal) {
const size_t len = std::char_traits<char>::length(literal);
if (schema_.compare(pos_, len, literal) == 0) {
pos_ += len;
return true;
}
return false;
}
bool SchemaTypeParser::consumeChar(char c) {
if (!atEnd() && schema_[pos_] == c) {
++pos_;
return true;
}
return false;
}
char SchemaTypeParser::peek() const {
TORCH_INTERNAL_ASSERT(!atEnd());
return schema_[pos_];
}
unsigned char SchemaTypeParser::peekAsUnsigned() const {
return static_cast<unsigned char>(peek());
}
bool SchemaTypeParser::atEnd() const { return pos_ >= schema_.size(); }
std::string SchemaTypeParser::posInfo() const {
std::ostringstream os;
os << " at position " << pos_ << " in schema `" << schema_ << "`";
return os.str();
}
bool SchemaTypeParser::isIdentifierStart(char c) {
const auto uc = static_cast<unsigned char>(c);
return std::isalpha(uc) || c == '_';
}
bool SchemaTypeParser::isIdentifierChar(char c) {
const auto uc = static_cast<unsigned char>(c);
return std::isalnum(uc) || c == '_';
}
} // namespace torch::jit
@@ -0,0 +1,67 @@
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <ATen/core/alias_info.h>
#include <ATen/core/jit_type.h>
#include <c10/macros/Macros.h>
#include <cstddef>
#include <optional>
#include <set>
#include <string>
namespace torch::jit {
struct ParsedType {
c10::TypePtr type;
std::optional<c10::AliasInfo> alias_info;
};
class PADDLE_API SchemaTypeParser {
public:
SchemaTypeParser(const std::string& schema,
size_t* pos,
size_t* next_fresh_alias_id)
: schema_(schema),
pos_(refFromPtr(pos, "pos")),
next_fresh_alias_id_(
refFromPtr(next_fresh_alias_id, "next_fresh_alias_id")) {}
c10::TypePtr parseBaseType();
std::optional<c10::AliasInfo> parseAliasAnnotation();
ParsedType parseType();
private:
void parseAliasSetList(std::set<std::string>* sets);
std::string parseIdentifier(const char* desc);
std::string parseDottedIdentifier(const char* desc);
void skipWhitespace();
bool consumeLiteral(const char* literal);
bool consumeChar(char c);
char peek() const;
unsigned char peekAsUnsigned() const;
bool atEnd() const;
std::string posInfo() const;
static bool isIdentifierStart(char c);
static bool isIdentifierChar(char c);
static size_t& refFromPtr(size_t* ptr, const char* name);
const std::string& schema_;
size_t& pos_;
size_t& next_fresh_alias_id_;
};
} // namespace torch::jit
@@ -0,0 +1,22 @@
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// The file has been adapted from pytorch project
// Licensed under BSD-style license -
// https://github.com/pytorch/pytorch/blob/main/LICENSE
#pragma once
#include <torch/all.h>
#include <torch/python.h>
@@ -0,0 +1,58 @@
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <cstddef>
#include <cstdint>
#include <functional>
namespace c10 {
enum class DeviceType : int8_t {
CPU = 0,
CUDA = 1,
XPU = 12,
IPU = 18,
CUSTOM = 20,
PrivateUse1 = CUSTOM,
};
constexpr DeviceType kCUDA = DeviceType::CUDA;
constexpr DeviceType kCPU = DeviceType::CPU;
constexpr DeviceType kCUSTOM = DeviceType::CUSTOM;
constexpr DeviceType kXPU = DeviceType::XPU;
constexpr DeviceType kIPU = DeviceType::IPU;
constexpr DeviceType kPrivateUse1 = DeviceType::PrivateUse1;
} // namespace c10
namespace std {
template <>
struct hash<c10::DeviceType> {
std::size_t operator()(c10::DeviceType k) const noexcept {
return std::hash<int>()(static_cast<int>(k));
}
};
} // namespace std
namespace at {
using c10::DeviceType;
using c10::kCPU;
using c10::kCUDA;
using c10::kCUSTOM;
using c10::kIPU;
using c10::kPrivateUse1;
using c10::kXPU;
} // namespace at
@@ -0,0 +1,337 @@
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// The file has been adapted from pytorch project
// Licensed under BSD-style license -
// https://github.com/pytorch/pytorch/blob/main/LICENSE
#pragma once
#include <c10/util/BFloat16.h>
#include <c10/util/Float4_e2m1fn_x2.h>
#include <c10/util/Float8_e4m3fn.h>
#include <c10/util/Float8_e4m3fnuz.h>
#include <c10/util/Float8_e5m2.h>
#include <c10/util/Float8_e5m2fnuz.h>
#include <c10/util/Float8_e8m0fnu.h>
#include <c10/util/Half.h>
#include <c10/util/bits.h>
#include <c10/util/complex.h>
#include <c10/util/qint32.h>
#include <c10/util/qint8.h>
#include <c10/util/quint2x4.h>
#include <c10/util/quint4x2.h>
#include <c10/util/quint8.h>
#include <cstdint>
#include <ostream>
#include <type_traits>
#include "paddle/common/macros.h"
namespace c10 {
// dummy struct for uint1 to uint7, actual functionality
// of these dtypes will be implemented in python with Tensor subclass
template <unsigned int N>
struct dummy_uint1_7_t {};
// dummy struct for int1 to int7, actual functionality
// of these dtypes will be implemented in python with Tensor subclass
template <unsigned int N>
struct dummy_int1_7_t {};
#define AT_FORALL_SCALAR_TYPES_WITH_COMPLEX_AND_QINTS(_) \
_(uint8_t, UINT8, Byte) /* 0 */ \
_(int8_t, INT8, Char) /* 1 */ \
_(int16_t, INT16, Short) /* 2 */ \
_(int, INT32, Int) /* 3 */ \
_(int64_t, INT64, Long) /* 4 */ \
_(at::Half, FLOAT16, Half) /* 5 */ \
_(float, FLOAT32, Float) /* 6 */ \
_(double, FLOAT64, Double) /* 7 */ \
_(c10::complex<at::Half>, ComplexHalf, ComplexHalf) /* 8 */ \
_(c10::complex<float>, COMPLEX64, ComplexFloat) /* 9 */ \
_(c10::complex<double>, COMPLEX128, ComplexDouble) /* 10 */ \
_(bool, BOOL, Bool) /* 11 */ \
_(c10::qint8, QInt8, QInt8) /* 12 */ \
_(c10::quint8, QUInt8, QUInt8) /* 13 */ \
_(c10::qint32, QInt32, QInt32) /* 14 */ \
_(at::BFloat16, BFLOAT16, BFloat16) /* 15 */ \
_(c10::quint4x2, QUInt4x2, QUInt4x2) /* 16 */ \
_(c10::quint2x4, QUInt2x4, QUInt2x4) /* 17 */ \
_(c10::bits1x8, Bits1x8, Bits1x8) /* 18 */ \
_(c10::bits2x4, Bits2x4, Bits2x4) /* 19 */ \
_(c10::bits4x2, Bits4x2, Bits4x2) /* 20 */ \
_(c10::bits8, Bits8, Bits8) /* 21 */ \
_(c10::bits16, Bits16, Bits16) /* 22 */ \
_(c10::Float8_e5m2, FLOAT8_E5M2, Float8_e5m2) /* 23 */ \
_(c10::Float8_e4m3fn, FLOAT8_E4M3FN, Float8_e4m3fn) /* 24 */ \
_(c10::Float8_e5m2fnuz, Float8_e5m2fnuz, Float8_e5m2fnuz) /* 25 */ \
_(c10::Float8_e4m3fnuz, Float8_e4m3fnuz, Float8_e4m3fnuz) /* 26 */ \
_(uint16_t, UINT16, UInt16) /* 27 */ \
_(uint32_t, UINT32, UInt32) /* 28 */ \
_(uint64_t, UINT64, UInt64) /* 29 */ \
_(c10::dummy_uint1_7_t<1>, UInt1, UInt1) /* 30 */ \
_(c10::dummy_uint1_7_t<2>, UInt2, UInt2) /* 31 */ \
_(c10::dummy_uint1_7_t<3>, UInt3, UInt3) /* 32 */ \
_(c10::dummy_uint1_7_t<4>, UInt4, UInt4) /* 33 */ \
_(c10::dummy_uint1_7_t<5>, UInt5, UInt5) /* 34 */ \
_(c10::dummy_uint1_7_t<6>, UInt6, UInt6) /* 35 */ \
_(c10::dummy_uint1_7_t<7>, UInt7, UInt7) /* 36 */ \
_(c10::dummy_int1_7_t<1>, Int1, Int1) /* 37 */ \
_(c10::dummy_int1_7_t<2>, Int2, Int2) /* 38 */ \
_(c10::dummy_int1_7_t<3>, Int3, Int3) /* 39 */ \
_(c10::dummy_int1_7_t<4>, Int4, Int4) /* 40 */ \
_(c10::dummy_int1_7_t<5>, Int5, Int5) /* 41 */ \
_(c10::dummy_int1_7_t<6>, Int6, Int6) /* 42 */ \
_(c10::dummy_int1_7_t<7>, Int7, Int7) /* 43 */ \
_(c10::Float8_e8m0fnu, Float8_e8m0fnu, Float8_e8m0fnu) /* 44 */ \
_(c10::Float4_e2m1fn_x2, Float4_e2m1fn_x2, Float4_e2m1fn_x2) /* 45 */
#define AT_FORALL_SCALAR_TYPES_WITH_COMPLEX_EXCEPT_COMPLEX_HALF_F8NZ(_) \
_(uint8_t, Byte) \
_(int8_t, Char) \
_(int16_t, Short) \
_(int, Int) \
_(int64_t, Long) \
_(at::Half, Half) \
_(float, Float) \
_(double, Double) \
_(c10::complex<float>, ComplexFloat) \
_(c10::complex<double>, ComplexDouble) \
_(bool, Bool) \
_(at::BFloat16, BFloat16) \
_(c10::Float8_e5m2, Float8_e5m2) \
_(c10::Float8_e4m3fn, Float8_e4m3fn)
#define AT_FORALL_SCALAR_TYPES_WITH_COMPLEX(_) \
_(uint8_t, Byte) \
_(int8_t, Char) \
_(int16_t, Short) \
_(int, Int) \
_(int64_t, Long) \
_(float, Float) \
_(double, Double) \
_(c10::complex<float>, ComplexFloat) \
_(c10::complex<double>, ComplexDouble) \
_(bool, Bool) \
_(at::BFloat16, BFloat16) \
_(c10::Float8_e5m2, Float8_e5m2) \
_(c10::Float8_e4m3fn, Float8_e4m3fn)
#define AT_FORALL_QINT_TYPES(_) \
_(c10::qint8, QInt8) \
_(c10::quint8, QUInt8) \
_(c10::qint32, QInt32) \
_(c10::quint4x2, QUInt4x2) \
_(c10::quint2x4, QUInt2x4)
#define FOREACH_PADDLE_AND_TORCH_DTYPES(_) \
_(uint8_t, UINT8, Byte) \
_(int8_t, INT8, Char) \
_(int16_t, INT16, Short) \
_(int32_t, INT32, Int) \
_(int64_t, INT64, Long) \
_(at::Half, FLOAT16, Half) \
_(float, FLOAT32, Float) \
_(double, FLOAT64, Double) \
_(c10::complex<float>, COMPLEX64, ComplexFloat) \
_(c10::complex<double>, COMPLEX128, ComplexDouble) \
_(bool, BOOL, Bool) \
_(at::BFloat16, BFLOAT16, BFloat16) \
_(c10::Float8_e5m2, FLOAT8_E5M2, Float8_e5m2) \
_(c10::Float8_e4m3fn, FLOAT8_E4M3FN, Float8_e4m3fn) \
_(uint16_t, UINT16, UInt16) \
_(uint32_t, UINT32, UInt32)
enum class PADDLE_API ScalarType : int8_t {
Byte = 0,
Char = 1,
Short = 2,
Int = 3,
Long = 4,
Half = 5,
Float = 6,
Double = 7,
ComplexHalf = 8,
ComplexFloat = 9,
ComplexDouble = 10,
Bool = 11,
QInt8 = 12,
QUInt8 = 13,
QInt32 = 14,
BFloat16 = 15,
QUInt4x2 = 16,
QUInt2x4 = 17,
Bits1x8 = 18,
Bits2x4 = 19,
Bits4x2 = 20,
Bits8 = 21,
Bits16 = 22,
Float8_e5m2 = 23,
Float8_e4m3fn = 24,
Float8_e5m2fnuz = 25,
Float8_e4m3fnuz = 26,
UInt16 = 27,
UInt32 = 28,
UInt64 = 29,
UInt1 = 30,
UInt2 = 31,
UInt3 = 32,
UInt4 = 33,
UInt5 = 34,
UInt6 = 35,
UInt7 = 36,
Int1 = 37,
Int2 = 38,
Int3 = 39,
Int4 = 40,
Int5 = 41,
Int6 = 42,
Int7 = 43,
Float8_e8m0fnu = 44,
Float4_e2m1fn_x2 = 45,
Undefined = 46,
NumOptions = 47
};
constexpr uint16_t NumScalarTypes =
static_cast<uint16_t>(ScalarType::NumOptions);
namespace impl {
template <c10::ScalarType N>
struct ScalarTypeToCPPType;
#define SPECIALIZE_ScalarTypeToCPPType(cpp_type, _2, scalar_type) \
template <> \
struct ScalarTypeToCPPType<c10::ScalarType::scalar_type> { \
using type = cpp_type; \
\
static type t; \
};
AT_FORALL_SCALAR_TYPES_WITH_COMPLEX_AND_QINTS(SPECIALIZE_ScalarTypeToCPPType)
#undef SPECIALIZE_ScalarTypeToCPPType
template <c10::ScalarType N>
using ScalarTypeToCPPTypeT = typename ScalarTypeToCPPType<N>::type;
} // namespace impl
template <typename T>
struct CppTypeToScalarType;
#define SPECIALIZE_CppTypeToScalarType(cpp_type, _2, scalar_type) \
template <> \
struct CppTypeToScalarType<cpp_type> \
: std::integral_constant<c10::ScalarType, \
c10::ScalarType::scalar_type> {};
AT_FORALL_SCALAR_TYPES_WITH_COMPLEX_AND_QINTS(SPECIALIZE_CppTypeToScalarType)
#undef SPECIALIZE_CppTypeToScalarType
#define AT_FORALL_SCALAR_TYPES_AND(SCALARTYPE, _) \
_(uint8_t, Byte) \
_(int8_t, Char) \
_(int16_t, Short) \
_(int, Int) \
_(int64_t, Long) \
_(float, Float) \
_(double, Double) \
_(decltype(::c10::impl::ScalarTypeToCPPType< \
::c10::ScalarType::SCALARTYPE>::t), \
SCALARTYPE)
#define AT_FORALL_SCALAR_TYPES_AND2(SCALARTYPE1, SCALARTYPE2, _) \
_(uint8_t, Byte) \
_(int8_t, Char) \
_(int16_t, Short) \
_(int, Int) \
_(int64_t, Long) \
_(float, Float) \
_(double, Double) \
_(decltype(::c10::impl::ScalarTypeToCPPType< \
::c10::ScalarType::SCALARTYPE1>::t), \
SCALARTYPE1) \
_(decltype(::c10::impl::ScalarTypeToCPPType< \
::c10::ScalarType::SCALARTYPE2>::t), \
SCALARTYPE2)
#define AT_FORALL_SCALAR_TYPES_AND3(SCALARTYPE1, SCALARTYPE2, SCALARTYPE3, _) \
_(uint8_t, Byte) \
_(int8_t, Char) \
_(int16_t, Short) \
_(int, Int) \
_(int64_t, Long) \
_(float, Float) \
_(double, Double) \
_(decltype(::c10::impl::ScalarTypeToCPPType< \
::c10::ScalarType::SCALARTYPE1>::t), \
SCALARTYPE1) \
_(decltype(::c10::impl::ScalarTypeToCPPType< \
::c10::ScalarType::SCALARTYPE2>::t), \
SCALARTYPE2) \
_(decltype(::c10::impl::ScalarTypeToCPPType< \
::c10::ScalarType::SCALARTYPE3>::t), \
SCALARTYPE3)
#define AT_FORALL_COMPLEX_TYPES(_) \
_(c10::complex<float>, ComplexFloat) \
_(c10::complex<double>, ComplexDouble)
inline const char* toString(ScalarType t) {
#define DEFINE_CASE(_1, _2, name) \
case ScalarType::name: \
return #name;
switch (t) {
AT_FORALL_SCALAR_TYPES_WITH_COMPLEX_AND_QINTS(DEFINE_CASE)
case ScalarType::Undefined:
return "Undefined";
default:
return "UNKNOWN_SCALAR";
}
#undef DEFINE_CASE
}
inline std::ostream& operator<<(std::ostream& stream, ScalarType scalar_type) {
return stream << toString(scalar_type);
}
inline bool isQIntType(ScalarType t) {
return t == ScalarType::QInt8 || t == ScalarType::QUInt8 ||
t == ScalarType::QInt32 || t == ScalarType::QUInt4x2 ||
t == ScalarType::QUInt2x4;
}
inline ScalarType toUnderlying(ScalarType t) {
switch (t) {
case ScalarType::QUInt8:
case ScalarType::QUInt4x2:
case ScalarType::QUInt2x4:
return ScalarType::Byte;
case ScalarType::QInt8:
return ScalarType::Char;
case ScalarType::QInt32:
return ScalarType::Int;
default:
return t;
}
}
} // namespace c10
@@ -0,0 +1,399 @@
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// The file has been adapted from pytorch project
// Licensed under BSD-style license -
// https://github.com/pytorch/pytorch/blob/main/LICENSE
#pragma once
#include <c10/macros/Macros.h>
#include <c10/util/ArrayRef.h>
#include <torch/headeronly/util/Exception.h>
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <iterator>
#include <type_traits>
#include <utility>
namespace torch::headeronly {
// The PtrTraits argument to the TensorAccessor/GenericPackedTensorAccessor
// is used to enable the __restrict__ keyword/modifier for the data
// passed to cuda.
template <typename T>
struct DefaultPtrTraits {
typedef T* PtrType;
};
#if defined(__CUDACC__) || defined(__HIPCC__)
template <typename T>
struct RestrictPtrTraits {
typedef T* __restrict__ PtrType;
};
#endif
namespace detail {
// TensorAccessorBase and TensorAccessor are used for both CPU and CUDA tensors.
// For CUDA tensors it is used in device code (only). This means that we
// restrict ourselves to functions and types available there (e.g. IntArrayRef
// isn't).
// The PtrTraits argument is only relevant to cuda to support `__restrict__`
// pointers.
template <class ArrayRefCls,
typename T,
size_t N,
template <typename U> class PtrTraits = DefaultPtrTraits,
typename index_t = int64_t>
class TensorAccessorBase {
public:
typedef typename PtrTraits<T>::PtrType PtrType;
C10_HOST_DEVICE TensorAccessorBase(PtrType data,
const index_t* sizes,
const index_t* strides)
: data_(data), sizes_(sizes), strides_(strides) {}
C10_HOST ArrayRefCls sizes() const { return ArrayRefCls(sizes_, N); }
C10_HOST ArrayRefCls strides() const { return ArrayRefCls(strides_, N); }
C10_HOST_DEVICE index_t stride(index_t i) const { return strides_[i]; }
C10_HOST_DEVICE index_t size(index_t i) const { return sizes_[i]; }
C10_HOST_DEVICE PtrType data() { return data_; }
C10_HOST_DEVICE const PtrType data() const { return data_; }
protected:
PtrType data_;
const index_t* sizes_;
const index_t* strides_;
};
// The `TensorAccessor` is typically instantiated for CPU `Tensor`s using
// `Tensor.accessor<T, N>()`.
// For CUDA `Tensor`s, `GenericPackedTensorAccessor` is used on the host and
// only indexing on the device uses `TensorAccessor`s.
template <class ArrayRefCls,
typename T,
size_t N,
template <typename U> class PtrTraits = DefaultPtrTraits,
typename index_t = int64_t>
class TensorAccessor
: public TensorAccessorBase<ArrayRefCls, T, N, PtrTraits, index_t> {
public:
typedef typename PtrTraits<T>::PtrType PtrType;
C10_HOST_DEVICE TensorAccessor(PtrType data,
const index_t* sizes,
const index_t* strides)
: TensorAccessorBase<ArrayRefCls, T, N, PtrTraits, index_t>(
data, sizes, strides) {}
C10_HOST_DEVICE TensorAccessor<ArrayRefCls, T, N - 1, PtrTraits, index_t>
operator[](index_t i) {
return TensorAccessor<ArrayRefCls, T, N - 1, PtrTraits, index_t>(
this->data_ + this->strides_[0] * i,
this->sizes_ + 1,
this->strides_ + 1);
}
C10_HOST_DEVICE const
TensorAccessor<ArrayRefCls, T, N - 1, PtrTraits, index_t>
operator[](index_t i) const {
return TensorAccessor<ArrayRefCls, T, N - 1, PtrTraits, index_t>(
this->data_ + this->strides_[0] * i,
this->sizes_ + 1,
this->strides_ + 1);
}
};
template <class ArrayRefCls,
typename T,
template <typename U>
class PtrTraits,
typename index_t>
class TensorAccessor<ArrayRefCls, T, 1, PtrTraits, index_t>
: public TensorAccessorBase<ArrayRefCls, T, 1, PtrTraits, index_t> {
public:
typedef typename PtrTraits<T>::PtrType PtrType;
C10_HOST_DEVICE TensorAccessor(PtrType data,
const index_t* sizes,
const index_t* strides)
: TensorAccessorBase<ArrayRefCls, T, 1, PtrTraits, index_t>(
data, sizes, strides) {}
C10_HOST_DEVICE T& operator[](index_t i) {
return this->data_[this->strides_[0] * i];
}
C10_HOST_DEVICE const T& operator[](index_t i) const {
return this->data_[this->strides_[0] * i];
}
};
// GenericPackedTensorAccessorBase and GenericPackedTensorAccessor are used on
// for CUDA `Tensor`s on the host and as in contrast to `TensorAccessor`s, they
// copy the strides and sizes on instantiation (on the host) in order to
// transfer them on the device when calling kernels. On the device, indexing of
// multidimensional tensors gives to `TensorAccessor`s. Use RestrictPtrTraits as
// PtrTraits if you want the tensor's data pointer to be marked as __restrict__.
// Instantiation from data, sizes, strides is only needed on the host and
// std::copy isn't available on the device, so those functions are host only.
template <typename IndexBoundsCheck,
typename T,
size_t N,
template <typename U> class PtrTraits = DefaultPtrTraits,
typename index_t = int64_t>
class GenericPackedTensorAccessorBase {
public:
typedef typename PtrTraits<T>::PtrType PtrType;
C10_HOST GenericPackedTensorAccessorBase(PtrType data,
const index_t* sizes,
const index_t* strides)
: data_(data) {
std::copy(sizes, sizes + N, std::begin(this->sizes_));
std::copy(strides, strides + N, std::begin(this->strides_));
}
// if index_t is not int64_t, we want to have an int64_t constructor
template <typename source_index_t,
class = std::enable_if_t<std::is_same_v<source_index_t, int64_t>>>
C10_HOST GenericPackedTensorAccessorBase(PtrType data,
const source_index_t* sizes,
const source_index_t* strides)
: data_(data) {
for (size_t i = 0; i < N; ++i) {
this->sizes_[i] = sizes[i];
this->strides_[i] = strides[i];
}
}
C10_HOST_DEVICE index_t stride(index_t i) const { return strides_[i]; }
C10_HOST_DEVICE index_t size(index_t i) const { return sizes_[i]; }
C10_HOST_DEVICE PtrType data() { return data_; }
C10_HOST_DEVICE const PtrType data() const { return data_; }
protected:
PtrType data_;
// NOLINTNEXTLINE(runtime/arrays)
index_t sizes_[N];
// NOLINTNEXTLINE(runtime/arrays)
index_t strides_[N];
C10_HOST void bounds_check_(index_t i) const { IndexBoundsCheck _(i); }
};
template <typename ItemAccessor,
typename IndexBoundsCheck,
typename T,
size_t N,
template <typename U> class PtrTraits = DefaultPtrTraits,
typename index_t = int64_t>
class GenericPackedTensorAccessor
: public GenericPackedTensorAccessorBase<IndexBoundsCheck,
T,
N,
PtrTraits,
index_t> {
public:
typedef typename PtrTraits<T>::PtrType PtrType;
C10_HOST GenericPackedTensorAccessor(PtrType data,
const index_t* sizes,
const index_t* strides)
: GenericPackedTensorAccessorBase<IndexBoundsCheck,
T,
N,
PtrTraits,
index_t>(data, sizes, strides) {}
// if index_t is not int64_t, we want to have an int64_t constructor
template <typename source_index_t,
class = std::enable_if_t<std::is_same_v<source_index_t, int64_t>>>
C10_HOST GenericPackedTensorAccessor(PtrType data,
const source_index_t* sizes,
const source_index_t* strides)
: GenericPackedTensorAccessorBase<IndexBoundsCheck,
T,
N,
PtrTraits,
index_t>(data, sizes, strides) {}
C10_DEVICE ItemAccessor operator[](index_t i) {
index_t* new_sizes = this->sizes_ + 1;
index_t* new_strides = this->strides_ + 1;
return ItemAccessor(
this->data_ + this->strides_[0] * i, new_sizes, new_strides);
}
C10_DEVICE const ItemAccessor operator[](index_t i) const {
const index_t* new_sizes = this->sizes_ + 1;
const index_t* new_strides = this->strides_ + 1;
return ItemAccessor(
this->data_ + this->strides_[0] * i, new_sizes, new_strides);
}
/// Returns a PackedTensorAccessor of the same dimension after transposing the
/// two dimensions given. Does not actually move elements; transposition is
/// made by permuting the size/stride arrays. If the dimensions are not valid,
/// asserts.
C10_HOST GenericPackedTensorAccessor<ItemAccessor,
IndexBoundsCheck,
T,
N,
PtrTraits,
index_t>
transpose(index_t dim1, index_t dim2) const {
this->bounds_check_(dim1);
this->bounds_check_(dim2);
GenericPackedTensorAccessor<ItemAccessor,
IndexBoundsCheck,
T,
N,
PtrTraits,
index_t>
result(this->data_, this->sizes_, this->strides_);
std::swap(result.strides_[dim1], result.strides_[dim2]);
std::swap(result.sizes_[dim1], result.sizes_[dim2]);
return result;
}
};
template <typename ItemAccessor,
typename IndexBoundsCheck,
typename T,
template <typename U>
class PtrTraits,
typename index_t>
class GenericPackedTensorAccessor<ItemAccessor,
IndexBoundsCheck,
T,
1,
PtrTraits,
index_t>
: public GenericPackedTensorAccessorBase<IndexBoundsCheck,
T,
1,
PtrTraits,
index_t> {
public:
typedef typename PtrTraits<T>::PtrType PtrType;
C10_HOST GenericPackedTensorAccessor(PtrType data,
const index_t* sizes,
const index_t* strides)
: GenericPackedTensorAccessorBase<IndexBoundsCheck,
T,
1,
PtrTraits,
index_t>(data, sizes, strides) {}
// if index_t is not int64_t, we want to have an int64_t constructor
template <typename source_index_t,
class = std::enable_if_t<std::is_same_v<source_index_t, int64_t>>>
C10_HOST GenericPackedTensorAccessor(PtrType data,
const source_index_t* sizes,
const source_index_t* strides)
: GenericPackedTensorAccessorBase<IndexBoundsCheck,
T,
1,
PtrTraits,
index_t>(data, sizes, strides) {}
C10_DEVICE T& operator[](index_t i) {
return this->data_[this->strides_[0] * i];
}
C10_DEVICE const T& operator[](index_t i) const {
return this->data_[this->strides_[0] * i];
}
// Same as in the general N-dimensional case, but note that in the
// 1-dimensional case the returned PackedTensorAccessor will always be an
// identical copy of the original
C10_HOST GenericPackedTensorAccessor<ItemAccessor,
IndexBoundsCheck,
T,
1,
PtrTraits,
index_t>
transpose(index_t dim1, index_t dim2) const {
this->bounds_check_(dim1);
this->bounds_check_(dim2);
return GenericPackedTensorAccessor<ItemAccessor,
IndexBoundsCheck,
T,
1,
PtrTraits,
index_t>(
this->data_, this->sizes_, this->strides_);
}
};
template <size_t N, typename index_t>
struct HeaderOnlyIndexBoundsCheck {
explicit HeaderOnlyIndexBoundsCheck(index_t i) {
TORCH_CHECK(0 <= i && i < index_t{N},
"Index ",
i,
" is not within bounds of a tensor of dimension ",
N);
}
};
} // namespace detail
// HeaderOnlyTensorAccessorBase is same as at::TensorAccessorBase.
template <typename T,
size_t N,
template <typename U> class PtrTraits = DefaultPtrTraits,
typename index_t = int64_t>
using HeaderOnlyTensorAccessorBase =
detail::TensorAccessorBase<c10::IntArrayRef, T, N, PtrTraits, index_t>;
// HeaderOnlyTensorAccessor is same as at::TensorAccessor.
template <typename T,
size_t N,
template <typename U> class PtrTraits = DefaultPtrTraits,
typename index_t = int64_t>
using HeaderOnlyTensorAccessor =
detail::TensorAccessor<c10::IntArrayRef, T, N, PtrTraits, index_t>;
// HeaderOnlyGenericPackedTensorAccessorBase is same as
// at::GenericPackedTensorAccessorBase.
template <typename T,
size_t N,
template <typename U> class PtrTraits = DefaultPtrTraits,
typename index_t = int64_t>
using HeaderOnlyGenericPackedTensorAccessorBase =
detail::GenericPackedTensorAccessorBase<
detail::HeaderOnlyIndexBoundsCheck<N, index_t>,
T,
N,
PtrTraits,
index_t>;
// HeaderOnlyGenericPackedTensorAccessor is same as
// at::GenericPackedTensorAccessor.
template <typename T,
size_t N,
template <typename U> class PtrTraits = DefaultPtrTraits,
typename index_t = int64_t>
using HeaderOnlyGenericPackedTensorAccessor =
detail::GenericPackedTensorAccessor<
HeaderOnlyTensorAccessor<T, N - 1, PtrTraits, index_t>,
detail::HeaderOnlyIndexBoundsCheck<N, index_t>,
T,
N,
PtrTraits,
index_t>;
} // namespace torch::headeronly
@@ -0,0 +1,85 @@
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <c10/macros/Macros.h>
#include <sstream>
#include <stdexcept>
#include <string>
#ifndef C10_UNLIKELY
#if defined(__GNUC__) || defined(__clang__)
#define C10_UNLIKELY(expr) (__builtin_expect(static_cast<bool>(expr), 0))
#else
#define C10_UNLIKELY(expr) (expr)
#endif
#endif
namespace c10 {
// Keep constexpr-friendly control flow when the check condition is constant
// under nvcc/hipcc, matching upstream headeronly behavior.
#if defined(__CUDACC__) || defined(__HIPCC__)
#define C10_UNLIKELY_OR_CONST(e) e
#else
#define C10_UNLIKELY_OR_CONST(e) C10_UNLIKELY(e)
#endif
} // namespace c10
#ifdef STRIP_ERROR_MESSAGES
#define STD_TORCH_CHECK_MSG(cond, type, ...) \
(#cond #type " CHECK FAILED at " C10_STRINGIZE(__FILE__))
#else
namespace torch::headeronly::detail {
template <typename... Args>
inline std::string stdTorchCheckMsgImpl(const char* /*msg*/,
const Args&... args) {
std::ostringstream oss;
((oss << args), ...);
return oss.str();
}
inline const char* stdTorchCheckMsgImpl(const char* msg) { return msg; }
inline const char* stdTorchCheckMsgImpl(const char* /*msg*/, const char* args) {
return args;
}
} // namespace torch::headeronly::detail
#define STD_TORCH_CHECK_MSG(cond, type, ...) \
(torch::headeronly::detail::stdTorchCheckMsgImpl( \
"Expected " #cond \
" to be true, but got false. " \
"(Could this error message be improved? If so, " \
"please report an enhancement request to PyTorch.)", \
##__VA_ARGS__))
#endif
#define STD_TORCH_CHECK(cond, ...) \
if (C10_UNLIKELY_OR_CONST(!(cond))) { \
throw std::runtime_error(STD_TORCH_CHECK_MSG(cond, \
"", \
__func__, \
", ", \
__FILE__, \
":", \
__LINE__, \
", ", \
##__VA_ARGS__)); \
}
@@ -0,0 +1,343 @@
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <torch/library.h>
#include "glog/logging.h"
#include "paddle/common/exception.h"
namespace torch {
// ClassRegistry
ClassRegistry& ClassRegistry::instance() {
static ClassRegistry registry;
return registry;
}
void ClassRegistry::register_class(const std::string& namespace_name,
const std::string& class_name) {
std::string qualified_name = namespace_name + "::" + class_name;
classes_[qualified_name] =
std::make_unique<ClassRegistration>(namespace_name, class_name);
VLOG(3) << "Registered class: " << qualified_name;
}
void ClassRegistry::register_constructor(const std::string& qualified_name,
CppFunction&& func) {
auto it = classes_.find(qualified_name);
if (it == classes_.end()) {
PADDLE_THROW(common::errors::NotFound("Class %s not found in registry!",
qualified_name.c_str()));
}
it->second->constructors.push_back(
std::make_shared<CppFunction>(std::move(func)));
VLOG(3) << "Registered constructor for: " << qualified_name
<< " (total: " << it->second->constructors.size() << ")";
}
void ClassRegistry::register_method(const std::string& qualified_name,
const std::string& method_name,
CppFunction&& func) {
auto it = classes_.find(qualified_name);
if (it == classes_.end()) {
PADDLE_THROW(common::errors::NotFound("Class %s not found in registry!",
qualified_name.c_str()));
}
it->second->methods[method_name] =
std::make_shared<CppFunction>(std::move(func));
VLOG(3) << "Registered method: " << qualified_name << "::" << method_name;
}
void ClassRegistry::register_static_method(const std::string& qualified_name,
const std::string& method_name,
CppFunction&& func) {
auto it = classes_.find(qualified_name);
if (it == classes_.end()) {
PADDLE_THROW(common::errors::NotFound("Class %s not found in registry!",
qualified_name.c_str()));
}
it->second->static_methods[method_name] =
std::make_shared<CppFunction>(std::move(func));
VLOG(3) << "Registered static method: " << qualified_name
<< "::" << method_name;
}
FunctionResult ClassRegistry::call_method_with_args(
const std::string& qualified_name,
const std::string& method_name,
const FunctionArgs& args) const {
auto it = classes_.find(qualified_name);
if (it == classes_.end()) {
PADDLE_THROW(common::errors::NotFound("Class %s not found in registry!",
qualified_name.c_str()));
}
auto& class_reg = it->second;
auto method_it = class_reg->methods.find(method_name);
if (method_it == class_reg->methods.end()) {
PADDLE_THROW(common::errors::NotFound("Method %s not found in class %s!",
method_name.c_str(),
qualified_name.c_str()));
}
try {
VLOG(3) << "Executing " << qualified_name << "::" << method_name
<< " (instance) with " << args.size() << " args";
auto result = method_it->second->call_with_args(args);
if (result.has_value()) {
VLOG(3) << "Instance method executed successfully with return value";
} else {
VLOG(3) << "Instance method executed successfully (void)";
}
return result;
} catch (const std::exception& e) {
VLOG(3) << "Instance method execution failed: " << e.what();
throw;
}
}
FunctionResult ClassRegistry::call_method_with_args(
const std::string& qualified_name,
const std::string& method_name,
const IValue& instance,
const FunctionArgs& args) const {
FunctionArgs full_args;
full_args.add_arg(instance);
for (size_t i = 0; i < args.size(); ++i) {
full_args.add_arg(args.get_value(i));
}
for (const auto& [name, value] : args.named_args()) {
torch::arg keyword(name);
keyword = value;
full_args.add_arg(std::move(keyword));
}
return call_method_with_args(qualified_name, method_name, full_args);
}
FunctionResult ClassRegistry::call_constructor_with_args(
const std::string& qualified_name, const FunctionArgs& args) const {
auto it = classes_.find(qualified_name);
if (it == classes_.end()) {
PADDLE_THROW(common::errors::NotFound("Class %s not found in registry!",
qualified_name.c_str()));
}
auto& class_reg = it->second;
if (class_reg->constructors.empty()) {
PADDLE_THROW(common::errors::NotFound(
"No constructor registered for class %s!", qualified_name.c_str()));
}
VLOG(3) << "Creating instance of " << qualified_name << " with "
<< args.size() << " args";
VLOG(3) << "Available constructors: " << class_reg->constructors.size();
for (size_t i = 0; i < class_reg->constructors.size(); ++i) {
try {
VLOG(3) << "Trying constructor " << (i + 1) << "...";
auto result = class_reg->constructors[i]->call_with_args(args);
VLOG(3) << "Constructor " << (i + 1) << " executed successfully";
return result;
} catch (const std::exception& e) {
VLOG(3) << "Constructor " << (i + 1) << " failed: " << e.what();
}
}
PADDLE_THROW(common::errors::InvalidArgument(
"No suitable constructor found for class %s!", qualified_name.c_str()));
}
FunctionResult ClassRegistry::call_static_method_with_args(
const std::string& qualified_name,
const std::string& method_name,
const FunctionArgs& args) const {
auto it = classes_.find(qualified_name);
if (it == classes_.end()) {
PADDLE_THROW(common::errors::NotFound("Class %s not found in registry!",
qualified_name.c_str()));
}
auto& class_reg = it->second;
auto method_it = class_reg->static_methods.find(method_name);
if (method_it == class_reg->static_methods.end()) {
PADDLE_THROW(
common::errors::NotFound("Static method %s not found in class %s!",
method_name.c_str(),
qualified_name.c_str()));
}
try {
VLOG(3) << "Executing " << qualified_name << "::" << method_name
<< " (static) with " << args.size() << " args";
auto result = method_it->second->call_with_args(args);
if (result.has_value()) {
VLOG(3) << "Static method executed successfully with return value";
} else {
VLOG(3) << "Static method executed successfully (void return)";
}
return result;
} catch (const std::exception& e) {
VLOG(3) << "Error executing static method: " << e.what();
throw;
}
}
void ClassRegistry::print_all_classes() const {
std::ostringstream oss;
oss << "\n=== Registered Classes ===" << std::endl;
for (const auto& [qualified_name, registration] : classes_) {
oss << "Class: " << qualified_name << std::endl;
if (!registration->constructors.empty()) {
oss << " Constructors: " << registration->constructors.size()
<< " available" << std::endl;
}
if (!registration->methods.empty()) {
oss << " Methods: ";
for (const auto& [method_name, _] : registration->methods) {
oss << method_name << " ";
}
oss << std::endl;
}
if (!registration->static_methods.empty()) {
oss << " Static Methods: ";
for (const auto& [method_name, _] : registration->static_methods) {
oss << method_name << " ";
}
oss << std::endl;
}
}
oss << "==========================" << std::endl;
std::cout << oss.str();
}
// OperatorRegistry
OperatorRegistry& OperatorRegistry::instance() {
static OperatorRegistry registry;
return registry;
}
void OperatorRegistry::register_schema(const std::string& qualified_name,
const std::string& schema) {
auto& op = get_or_create_operator(qualified_name);
op.schemaOrName_ = torch::jit::parseSchemaOrName(schema);
if (std::holds_alternative<c10::FunctionSchema>(op.schemaOrName_.value())) {
const auto& parsed_schema =
std::get<c10::FunctionSchema>(op.schemaOrName_.value());
for (auto& [dispatch_key, impl] : op.implementations) {
(void)dispatch_key;
impl.bind_schema(parsed_schema);
}
}
VLOG(3) << "Registered schema: " << qualified_name << " -> " << schema;
}
void OperatorRegistry::register_implementation(
const std::string& qualified_name,
c10::DispatchKey key,
CppFunction&& func) {
auto& op = get_or_create_operator(qualified_name);
if (op.schemaOrName_.has_value() &&
std::holds_alternative<c10::FunctionSchema>(op.schemaOrName_.value())) {
func.bind_schema(std::get<c10::FunctionSchema>(op.schemaOrName_.value()));
}
op.implementations[key] = std::move(func);
VLOG(3) << "Registered implementation: " << qualified_name << " for "
<< c10::toString(key);
}
OperatorRegistration* OperatorRegistry::find_operator(
const std::string& qualified_name) {
auto it = operators_.find(qualified_name);
return (it != operators_.end()) ? &it->second : nullptr;
}
void OperatorRegistry::print_all_operators() const {
std::stringstream oss;
oss << "\n=== Registered Operators ===" << std::endl;
for (const auto& [name, op] : operators_) {
oss << "Operator: " << name << std::endl;
if (op.schemaOrName_.has_value()) {
const auto& schema_or_name = op.schemaOrName_.value();
oss << " Schema: ";
if (std::holds_alternative<std::string>(schema_or_name)) {
oss << std::get<std::string>(schema_or_name);
} else {
oss << std::get<c10::FunctionSchema>(schema_or_name);
}
oss << std::endl;
}
oss << " Implementations: ";
for (const auto& [key, impl] : op.implementations) {
oss << c10::toString(key) << " ";
}
oss << std::endl;
}
oss << "=========================" << std::endl;
std::cout << oss.str();
}
// Library
Library::Library(Kind kind,
const std::string& ns,
std::optional<c10::DispatchKey> dispatch_key,
const char* file,
uint32_t line)
: kind_(kind),
ns_(ns),
dispatch_key_(dispatch_key),
file_(file),
line_(line) {
std::stringstream oss;
oss << "Created Library: kind=" << kind_to_string(kind)
<< ", namespace=" << ns;
if (dispatch_key) {
oss << ", dispatch_key=" << c10::toString(*dispatch_key);
}
VLOG(3) << oss.str() << std::endl;
}
Library::Library(const std::string& ns) // NOLINT
: kind_(DEF), ns_(ns), file_(nullptr), line_(0) {
VLOG(3) << "Created Library: namespace=" << ns << std::endl;
}
Library& Library::def(const std::string& schema) & {
if (kind_ == IMPL) {
VLOG(3)
<< "Warning: def() should not be called in TORCH_LIBRARY_IMPL block";
return *this;
}
// Simple schema extraction: if it contains '(', extract the part before '('
auto op_name = extract_op_name(schema);
auto qualified_name = ns_ + "::" + op_name;
OperatorRegistry::instance().register_schema(qualified_name, schema);
return *this;
}
void Library::print_info() const {
std::ostringstream oss;
oss << "Library Info: " << kind_to_string(kind_) << ", namespace=" << ns_;
if (dispatch_key_) {
oss << ", dispatch_key=" << c10::toString(*dispatch_key_);
}
std::cout << oss.str() << std::endl;
}
} // namespace torch
File diff suppressed because it is too large Load Diff