Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions paddle/phi/api/include/compat/ATen/core/TensorBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,16 @@
#include <c10/core/MemoryFormat.h>
#include <c10/core/Scalar.h>
#include <c10/core/ScalarType.h>
#include <c10/core/Storage.h>
#include <c10/core/SymInt.h>
#include <c10/core/TensorOptions.h>
#include <utils/int_array_ref_conversion.h>
#include <utils/scalar_type_conversion.h>
#include "paddle/common/layout.h"
#include "paddle/phi/api/include/api.h"
#include "paddle/phi/api/include/tensor.h"
#include "paddle/phi/common/place.h"
#include "paddle/phi/core/dense_tensor.h"

namespace at {
using PaddleTensor = paddle::Tensor;
Expand Down Expand Up @@ -208,6 +211,35 @@ class PADDLE_API TensorBase {

bool defined() const { return tensor_.defined(); }

int64_t storage_offset() const {
// Paddle DenseTensor stores offset in meta_.offset (in bytes)
// We need to convert to element offset
auto dense_tensor =
std::dynamic_pointer_cast<phi::DenseTensor>(tensor_.impl());
if (dense_tensor) {
size_t byte_offset = dense_tensor->meta().offset;
size_t element_size = SizeOf(tensor_.dtype());
return element_size > 0 ? static_cast<int64_t>(byte_offset / element_size)
: 0;
}
return 0;
}
Comment on lines +214 to +226
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The storage_offset() method doesn't validate if the dynamic_pointer_cast to DenseTensor succeeds. If the tensor's impl is not a DenseTensor, the method will crash when trying to access dense_tensor->meta(). Add a check and return 0 if the cast fails.

Copilot uses AI. Check for mistakes.

c10::SymInt sym_storage_offset() const {
return c10::SymInt(storage_offset());
}

bool has_storage() const { return tensor_.defined(); }

const Storage storage() const {
return Storage(
std::dynamic_pointer_cast<phi::DenseTensor>(tensor_.impl())->Holder());
Comment on lines +235 to +236
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The storage() method returns a Storage by value constructed from the tensor's Holder. However, it doesn't check if the tensor is defined or if the dynamic_pointer_cast succeeds. If the tensor is not a DenseTensor or is undefined, this will result in undefined behavior or a crash when trying to access a nullptr. Add validation before accessing the DenseTensor.

Suggested change
return Storage(
std::dynamic_pointer_cast<phi::DenseTensor>(tensor_.impl())->Holder());
if (!tensor_.defined()) {
// Undefined tensor: return an empty Storage
return Storage();
}
auto impl = tensor_.impl();
if (!impl) {
// No underlying implementation: return an empty Storage
return Storage();
}
auto dense_tensor =
std::dynamic_pointer_cast<phi::DenseTensor>(impl);
if (!dense_tensor) {
// Not backed by a DenseTensor: return an empty Storage
return Storage();
}
auto holder = dense_tensor->Holder();
if (!holder) {
// No allocation holder: return an empty Storage
return Storage();
}
return Storage(holder);

Copilot uses AI. Check for mistakes.
}

bool is_alias_of(const at::TensorBase& other) const {
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The is_alias_of method doesn't check if the tensors are defined before accessing their storage. If either tensor is undefined, calling storage() will likely crash. Add validation to check if both tensors are defined before comparing their storage allocations.

Suggested change
bool is_alias_of(const at::TensorBase& other) const {
bool is_alias_of(const at::TensorBase& other) const {
if (!this->defined() || !other.defined()) {
// Undefined tensors cannot be aliases of each other.
return false;
}

Copilot uses AI. Check for mistakes.
return this->storage().allocation() == other.storage().allocation();
}
Comment on lines +214 to +241
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing test coverage for TensorBase storage-related methods. The new methods storage_offset(), sym_storage_offset(), has_storage(), storage(), and is_alias_of() added to TensorBase lack dedicated test coverage that validates edge cases like undefined tensors, non-DenseTensor implementations, and error conditions. Consider adding specific tests for these methods.

Copilot uses AI. Check for mistakes.

Layout layout() const {
switch (tensor_.layout()) {
case common::DataLayout::STRIDED:
Expand Down
110 changes: 110 additions & 0 deletions paddle/phi/api/include/compat/c10/core/Allocator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// 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.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

同下,添加下声明

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已添加

// #The file has been adapted from pytorch project
// #Licensed under BSD-style license -
// https://github.com/pytorch/pytorch/blob/main/LICENSE

#pragma once

#include <cstddef>
#include <functional>
#include <memory>
#include <utility>

#include "paddle/phi/common/place.h"
#include "paddle/phi/core/allocator.h"

namespace c10 {

// Deleter function pointer type (compatible with LibTorch)
using DeleterFnPtr = void (*)(void*);

// DataPtr class compatible with LibTorch's c10::DataPtr
// Wraps a pointer with associated device and deleter
class DataPtr {
public:
DataPtr() : ptr_(nullptr), device_(phi::CPUPlace()) {}

explicit DataPtr(void* data, phi::Place device = phi::CPUPlace())
: ptr_(data), device_(device) {}

DataPtr(void* data,
void* ctx,
DeleterFnPtr ctx_deleter,
phi::Place device = phi::CPUPlace())
: ptr_(data), ctx_(ctx), deleter_(ctx_deleter), device_(device) {}

// Construct from phi::Allocation
explicit DataPtr(const std::shared_ptr<phi::Allocation>& alloc)
: ptr_(alloc ? alloc->ptr() : nullptr),
device_(alloc ? alloc->place() : phi::CPUPlace()),
allocation_(alloc) {}

DataPtr(const DataPtr&) = default;
DataPtr& operator=(const DataPtr&) = default;
DataPtr(DataPtr&&) = default;
DataPtr& operator=(DataPtr&&) = default;

void* get() const { return ptr_; }

void* operator->() const { return ptr_; }

explicit operator bool() const { return ptr_ != nullptr; }

phi::Place device() const { return device_; }

DeleterFnPtr get_deleter() const { return deleter_; }

void* get_context() const { return ctx_; }

void clear() {
ptr_ = nullptr;
ctx_ = nullptr;
deleter_ = nullptr;
allocation_.reset();
}
Comment on lines +72 to +77
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The clear() method resets the raw pointer and allocation but doesn't call the deleter if one is set. If a custom deleter was provided via the constructor, clearing without calling it could leak resources or leave cleanup incomplete. Consider calling the deleter before clearing if it's non-null.

Copilot uses AI. Check for mistakes.

// Get the underlying allocation (if available)
std::shared_ptr<phi::Allocation> allocation() const { return allocation_; }

private:
void* ptr_ = nullptr;
void* ctx_ = nullptr;
DeleterFnPtr deleter_ = nullptr;
phi::Place device_;
std::shared_ptr<phi::Allocation> allocation_;
};
Comment on lines +34 to +88
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing documentation for DataPtr class. This is a key compatibility wrapper that manages memory pointers with device information and custom deleters. Add a class-level comment explaining its purpose, relationship to LibTorch's DataPtr, and usage patterns.

Copilot uses AI. Check for mistakes.

inline bool operator==(const DataPtr& dp, std::nullptr_t) noexcept {
return !dp;
}

inline bool operator==(std::nullptr_t, const DataPtr& dp) noexcept {
return !dp;
}

inline bool operator!=(const DataPtr& dp, std::nullptr_t) noexcept {
return static_cast<bool>(dp);
}

inline bool operator!=(std::nullptr_t, const DataPtr& dp) noexcept {
return static_cast<bool>(dp);
}

} // namespace c10

namespace at {
using DataPtr = c10::DataPtr;
} // namespace at
Comment on lines +34 to +110
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing test coverage for the DataPtr class. The new DataPtr class in Allocator.h has no dedicated test coverage. Tests should verify construction with different parameters, the clear() method, operator bool(), comparison operators, and the allocation() method. Consider adding tests for DataPtr functionality.

Copilot uses AI. Check for mistakes.
Loading
Loading