Files
paddlepaddle--paddle/paddle/cinn/ir/buffer.cc
T
2026-07-13 12:40:42 +08:00

254 lines
8.6 KiB
C++

// Copyright (c) 2021 CINN 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 "paddle/cinn/ir/buffer.h"
#include "paddle/cinn/common/common.h"
#include "paddle/cinn/common/ir_util.h"
#include "paddle/cinn/ir/ir_visitor.h"
#include "paddle/cinn/ir/op/ir_operators.h"
#include "paddle/cinn/optim/ir_simplify.h"
#include "paddle/cinn/runtime/intrinsic.h"
#include "paddle/cinn/utils/string.h"
namespace cinn {
namespace ir {
std::string TensorGetBufferName(const _Tensor_ *tensor) {
PADDLE_ENFORCE_EQ(
!tensor->name.empty(),
true,
::common::errors::InvalidArgument(
"Tensor name is empty. Ensure that the tensor has a valid name."));
PADDLE_ENFORCE_EQ(utils::StartsWith(tensor->name, "_"),
false,
::common::errors::InvalidArgument(
"The name with prefix '_' is not allowed "
"for tensor. Current tensor's name is: %s",
tensor->name));
return "_" + tensor->name;
}
std::string BufferGetTensorName(const _Buffer_ *buffer) {
PADDLE_ENFORCE_EQ(
!buffer->name.empty(),
true,
::common::errors::InvalidArgument(
"Buffer name is empty. Ensure that the buffer has a valid name."));
PADDLE_ENFORCE_EQ(
utils::StartsWith(buffer->name, "_"),
true,
::common::errors::InvalidArgument(
"Buffer's name should start with '_'. Current buffer's name is: %s",
buffer->name));
return buffer->name.substr(1);
}
const _Buffer_ *Buffer::operator->() const { return IrNodeRef::As<_Buffer_>(); }
_Buffer_ *Buffer::operator->() { return IrNodeRef::As<_Buffer_>(); }
Buffer _Buffer_::Make(Var data,
Type dtype,
const std::vector<Expr> &shape,
const std::vector<Expr> &strides,
Expr elem_offset,
const std::string &name,
const std::string &scope,
int data_alignment,
int offset_factor,
Target target) {
PADDLE_ENFORCE_EQ(dtype.valid(),
true,
::common::errors::InvalidArgument(
"The data type (dtype) is invalid. Ensure that dtype "
"is properly initialized and valid."));
PADDLE_ENFORCE_EQ(dtype.is_unk(),
false,
::common::errors::InvalidArgument(
"The data type (dtype) is unknown. Ensure that dtype "
"is properly initialized and known."));
PADDLE_ENFORCE_EQ(dtype.is_void(),
false,
::common::errors::InvalidArgument(
"The data type (dtype) is void. Ensure that dtype is "
"properly initialized and not void."));
auto *node = cinn::common::make_shared<_Buffer_>();
node->shape = shape;
node->strides = strides;
node->elem_offset = elem_offset;
node->name = name;
node->scope = scope;
node->data_alignment = data_alignment;
node->offset_factor = offset_factor;
node->target = target;
node->dtype = dtype;
return Buffer(node);
}
Buffer _Buffer_::Make(const std::string &name, const std::vector<Expr> &shape) {
auto *node = cinn::common::make_shared<_Buffer_>();
node->name = name;
node->shape = shape;
node->dtype = Void();
return Buffer(node);
}
Buffer _Buffer_::Make() {
auto *node = cinn::common::make_shared<_Buffer_>();
node->dtype = Void();
return Buffer(node);
}
IrNodeTy _Buffer_::node_type() const { return _node_type_; }
void _Buffer_::BindTo(const Tensor &tensor) { BindTo(tensor.As<_Tensor_>()); }
void _Buffer_::BindTo(const _Tensor_ *tensor) {
if (name.empty()) name = TensorGetBufferName(tensor);
if (type().is_unk()) set_type(tensor->type());
PADDLE_ENFORCE_EQ(
!tensor->shape.empty(),
true,
::common::errors::InvalidArgument(
"Tensor should have a shape to bind to a Buffer. Ensure that the "
"tensor's shape is properly initialized and not empty."));
shape = tensor->shape;
binded_tensors_names_.insert(tensor->name);
}
void _Buffer_::Unbind(const _Tensor_ *tensor) {
binded_tensors_names_.erase(tensor->name);
}
Var _Buffer_::buffer_addr() const {
auto thetype = type().ElementOf();
thetype.set_cpp_handle();
return _Var_::Make(name, thetype);
}
int64_t _Buffer_::numel() const {
int64_t res = 1;
for (auto &i : shape) {
PADDLE_ENFORCE_EQ(i.is_constant(),
true,
::common::errors::InvalidArgument(
"The value of 'i' is not constant. Ensure that 'i' "
"is a constant value before proceeding."));
if (i->type() == Int(64)) {
res *= i.as_int64();
} else {
res *= i.as_int32();
}
}
return res;
}
ir::Expr _Buffer_::SymbolicNumel() const {
ir::Expr res{1};
for (auto &i : shape) {
res = res * i;
}
return optim::ArithSimplify(res);
}
void _Buffer_::Verify() const {
PADDLE_ENFORCE_EQ(
!shape.empty(),
true,
::common::errors::InvalidArgument(
"Buffer shape is empty. Ensure that the buffer has a valid shape."));
PADDLE_ENFORCE_EQ(
!name.empty(),
true,
::common::errors::InvalidArgument(
"Buffer name is empty. Ensure that the buffer has a valid name."));
PADDLE_ENFORCE_EQ(dtype.valid(),
true,
::common::errors::InvalidArgument(
"Buffer data type (dtype) is invalid. Ensure that "
"dtype is properly initialized and valid."));
}
Expr Buffer::DestroyExpr() const {
auto *node = operator->();
return runtime::IntrinsicCall(Void(),
runtime::intrinsic::buffer_destroy,
{ir::_Var_::Make(node->name, node->type())});
}
Expr _BufferRange_::Make(const Expr &buffer, const std::vector<Var> &ranges) {
auto node = make_shared<_BufferRange_>();
node->buffer = buffer;
node->ranges = ranges;
return Expr(node);
}
void _BufferRange_::Verify() const {
auto *buffer_ptr = buffer.As<_Buffer_>();
PADDLE_ENFORCE_NOT_NULL(buffer_ptr,
::common::errors::InvalidArgument(
"buffer_ptr is null. Ensure that buffer_ptr "
"is properly initialized and not null."));
}
Expr _BufferRange_::Copy() const {
auto node = make_shared<_BufferRange_>();
node->buffer = buffer;
node->ranges = ranges;
node->set_type(type());
return Expr(node);
}
bool BufferRange::operator==(const BufferRange &x) const {
auto this_buffer = operator->()->buffer.As<_Buffer_>();
auto other_buffer = x->buffer.As<_Buffer_>();
PADDLE_ENFORCE_NOT_NULL(this_buffer,
::common::errors::InvalidArgument(
"this_buffer is null. Ensure that this_buffer is "
"properly initialized and not null."));
PADDLE_ENFORCE_NOT_NULL(other_buffer,
::common::errors::InvalidArgument(
"other_buffer is null. Ensure that other_buffer "
"is properly initialized and not null."));
if (this_buffer != other_buffer) return false;
if (x->ranges.size() != operator->()->ranges.size()) return false;
for (int i = 0; i < x->ranges.size(); i++) {
Var this_range = operator->()->ranges[i];
Var other_range = x->ranges[i];
if (!is_zero(this_range->lower_bound - other_range->lower_bound))
return false;
if (!is_zero(this_range->upper_bound - other_range->upper_bound))
return false;
}
return true;
}
bool BufferRange::operator!=(const BufferRange &x) const {
return !(*this == x);
}
BufferRange &BufferRange::operator=(_BufferRange_ *x) {
*this = BufferRange(x);
return *this;
}
BufferRange &BufferRange::operator=(const _BufferRange_ *x) {
auto node = make_shared<_BufferRange_>();
node->buffer = x->buffer;
node->ranges = x->ranges;
node->set_type(x->type());
*this = BufferRange(node);
return *this;
}
} // namespace ir
} // namespace cinn