chore: import upstream snapshot with attribution
This commit is contained in:
@@ -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
Reference in New Issue
Block a user