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

266 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.
#pragma once
#include <map>
#include <string>
#include <vector>
#include "paddle/cinn/ir/buffer.h"
#include "paddle/cinn/ir/ir_base.h"
#include "paddle/cinn/ir/stmt.h"
namespace cinn {
namespace ir {
class _LoweredFunc_;
/**
* A struct representing an argument to a lowered function. Used for specifying
* the function signature of generated code.
*/
struct Argument {
//! kInput: arg is input
//! kOutput: arg is output
//! kUnknown: arg maybe input or output
enum class IO { kInput = 0, kOutput = 1, kUnknown = 2 };
IO io{IO::kInput};
Argument() = default;
explicit Argument(const ir::Buffer& buffer, IO io = IO::kInput);
explicit Argument(const ir::Var& var, IO io = IO::kInput);
//! Set the buffer argument, all the buffer information are stored in
//! ir::Buffer.
void set_buffer(const ir::Buffer& x);
//! Set the var argument.
void set_var(const ir::Var& x);
bool is_input() const { return io == IO::kInput; }
bool is_output() const { return io == IO::kOutput; }
bool is_var() const { return var_arg_.defined(); }
bool is_buffer() const { return buffer_arg_.defined(); }
bool defined() const { return is_var() || is_buffer(); }
ir::Buffer buffer_arg() const;
ir::Var var_arg() const;
//! The type of the buffer or scalar.
Type type() const;
std::string name() const;
std::string human_readable() const;
private:
//! The buffer field.
ir::Buffer buffer_arg_;
//! The scalar field.
ir::Var var_arg_;
};
//! Wrapper for _LoweredFunc_
class LoweredFunc : public IrNodeRef {
public:
LoweredFunc() = default;
explicit LoweredFunc(IrNode* n) : IrNodeRef(n) {}
const _LoweredFunc_* operator->() const;
_LoweredFunc_* operator->();
};
using symbolic_dim3_t = std::array<ir::Expr, 3>;
struct CudaAxisInfo {
CudaAxisInfo() {
for (ir::Expr& v : grid_dims_) v = ir::Expr(static_cast<int64_t>(1));
for (ir::Expr& v : block_dims_) v = ir::Expr(static_cast<int64_t>(1));
set_valid(false);
max_threads_per_block_ = -1;
min_blocks_per_sm_ = -1;
}
void set_grid_dim(int offset, int64_t x);
void set_block_dim(int offset, int64_t x);
void set_grid_dim(int offset, ir::Expr x);
void set_block_dim(int offset, ir::Expr x);
ir::Expr grid_dim(int offset) const;
ir::Expr block_dim(int offset) const;
inline void set_valid(bool x = false) { valid_ = x; }
inline bool valid() const { return valid_; }
void set_max_threads_per_block(int x) { max_threads_per_block_ = x; }
int max_threads_per_block() const { return max_threads_per_block_; }
void set_min_blocks_per_sm(int x) { min_blocks_per_sm_ = x; }
int min_blocks_per_sm() const { return min_blocks_per_sm_; }
private:
// the three dimensions represents x, y, z
symbolic_dim3_t grid_dims_;
// the three dimensions represents x, y, z
symbolic_dim3_t block_dims_;
bool valid_{false};
int max_threads_per_block_{-1};
int min_blocks_per_sm_{-1};
};
std::ostream& operator<<(std::ostream& os, const CudaAxisInfo& x);
/**
* A struct representing a temporary global buffer (allocated on the heap) that
* is used as staging space during kernel execution.
*/
struct TempSpaceInfo {
TempSpaceInfo() = default;
TempSpaceInfo(const Expr& size, int arg_idx, bool need_zero_init = false)
: size_(size), arg_idx_(arg_idx), need_zero_init_(need_zero_init) {}
Expr size() const { return size_; }
int arg_idx() const { return arg_idx_; }
bool need_zero_init() const { return need_zero_init_; }
private:
// size of the space in bytes
Expr size_;
// index in the function's argument list
int arg_idx_;
// whether this space need to be zero-initialized
bool need_zero_init_;
};
/**
* Definition of a lowered function. Note that, it should be functional.
*
* Arguments of the function:
*
* both the input and output arguments, the output arguments are in the tail.
*/
struct _LoweredFunc_ : public IrNode {
//! The name of this function.
std::string name;
//! The Arguments used in the body of the function.
std::vector<Argument> args;
//! Temporary buffers(as output), these buffers will not appear in the
//! function's argument list, but will be used in the body.
std::vector<Buffer> temp_bufs;
//! Temporary global buffers. These buffers will appear in the function's
//! argument list.
std::vector<TempSpaceInfo> temp_spaces;
//! Number of output tensors that appear in the function's argument list.
//! This number doesn't include temp_spaces.
int num_output_tensors;
// TODO(Hongqing-work): remove expr body after update all the backend passes.
//! Body of this function.
Expr body;
stmt::BlockRef body_block;
DeviceAPI device_api{DeviceAPI::UNK};
CudaAxisInfo cuda_axis_info;
/**
* The output buffer will be resized to the size required, we leave all the
* expression here. The allocation and deallocation expressions will insert
* into the head and tail of the function's body. It supports lazy
* allocation/deallocation if the corresponding intrinsic methods support.
*
* Currently, we assume that all the input and output buffers should locate in
* heap, no other memory type is allowed.
*/
// @{
std::vector<Expr> alloc_output_buffer_exprs;
std::vector<Expr> dealloc_output_buffer_exprs;
// @}
//! something like: float* A_data = (float*)(A->memory);
std::vector<Expr> buffer_data_cast_exprs;
std::vector<Expr> argument_prepare_exprs;
static LoweredFunc Make(const std::string& name,
const std::vector<Argument>& args,
const Expr& body,
const std::vector<ir::Buffer>& temp_bufs);
static LoweredFunc Make(const std::string& name,
const std::vector<Argument>& args,
const stmt::BlockRef& body,
const std::vector<ir::Buffer>& temp_bufs);
// A simple version of the make function method,
// regardless of the argument buffer information and IO information of
// Argument, after building the function to optimize the buffer through pass
static LoweredFunc Make(const std::string& name,
const std::vector<Argument>& args,
const Expr& body);
static LoweredFunc Make(const std::string& name,
const std::vector<Argument>& args,
const stmt::BlockRef& body);
bool is_gpu_host() const { return cuda_axis_info.valid(); }
void Verify() const override {}
IrNodeTy node_type() const override { return _node_type_; }
std::vector<Expr*> expr_fields() override;
std::vector<const Expr*> expr_fields() const override;
static const IrNodeTy _node_type_ = IrNodeTy::LoweredFunc;
//! Prepare the assumptions that a gpu axis should be less than its
//! corresponding dim size, e.g. threadIdx.x < blockDim.x.
std::vector<ir::stmt::StmtRef> PrepareAxisRangeAssumptionStmts() const;
std::vector<Expr> PrepareCreateTempBufferExprs() const;
//! Prepare the expressions for `alloc_tmp_buffer_exprs`.
std::vector<Expr> PrepareAllocTempBufferExprs() const;
std::vector<ir::stmt::StmtRef> PrepareAllocTempBufferStmts() const;
std::vector<Expr> PrepareDeallocTempBufferExprs() const;
std::vector<ir::stmt::StmtRef> PrepareDeallocTempBufferStmts() const;
std::vector<Expr> CudaPrepareAllocTempBufferExprs() const;
std::vector<ir::stmt::StmtRef> CudaAliasVarStmts() const;
void PrepareBufferCastExprs(bool with_expr_gen_tensor = true);
void PrepareCudaAxisInfoFromBody();
private:
void CheckValid() const;
//! Prepare the expressions for `alloc_output_buffer_exprs`.
void PrepareAllocOutputBufferExprs();
//! Prepare the expressions for `dealloc_output_buffer_exprs`.
void PrepareDeallocOutputBufferExprs();
//! Insert the allocation expr for temporary variables.
void AllocTempBuffer();
void PrepareArgumentExprs();
//! Get all the Buffers the function body references.
//! NOTE it will return the buffers with duplicates removed(by comparing their
//! name).
std::vector<Tensor> CollectAllTensorReference(
bool with_expr_gen_tensor = true) const;
};
} // namespace ir
} // namespace cinn