Files
2026-07-13 12:40:42 +08:00

361 lines
14 KiB
C++

// Copyright (c) 2024 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 "paddle/ap/include/adt/adt.h"
#include "paddle/ap/include/axpr/anf_expr_builder.h"
#include "paddle/ap/include/axpr/core_expr.h"
#include "paddle/ap/include/axpr/function.h"
#include "paddle/ap/include/axpr/lambda_expr_builder.h"
#include "paddle/ap/include/axpr/serializable_value.h"
#include "paddle/ap/include/code_gen/arg_source_ctx.h"
#include "paddle/ap/include/code_gen/kernel_arg_id.h"
namespace ap::code_gen {
template <typename BirNode>
struct ArgSourceHelper {
const ArgSourceCtx<BirNode>& arg_source_ctx;
adt::Result<axpr::Function<axpr::SerializableValue>>
MakeRuntimeKerneArgsGetter(
const std::list<KernelArgId<BirNode>>& kernel_arg_ids) const {
auto GetBody =
[&](axpr::LetVar* dispatch_ctx) -> adt::Result<axpr::LetVar*> {
std::vector<axpr::LetVar> items;
items.reserve(kernel_arg_ids.size());
for (const auto& kernel_arg_id : kernel_arg_ids) {
ADT_LET_CONST_REF(elt, MakeRuntimeGetter(dispatch_ctx, kernel_arg_id));
items.emplace_back(*elt);
}
auto* ctx = dispatch_ctx->ctx();
auto* ret_ptr = &ctx->Var(ctx->NewTmpVarName());
*ret_ptr = ctx->Var(axpr::kBuiltinList()).Call(items);
return ret_ptr;
};
ADT_LET_CONST_REF(lambda, CreateLambda("ctx", GetBody));
return axpr::Function<axpr::SerializableValue>{lambda, std::nullopt};
}
adt::Result<axpr::Function<axpr::SerializableValue>>
MakeRuntimeKerneArgGetter(const KernelArgId<BirNode>& kernel_arg_id) const {
auto GetBody =
[&](axpr::LetVar* dispatch_ctx) -> adt::Result<axpr::LetVar*> {
return MakeRuntimeGetter(dispatch_ctx, kernel_arg_id);
};
ADT_LET_CONST_REF(lambda, CreateLambda("ctx", GetBody));
return axpr::Function<axpr::SerializableValue>{lambda, std::nullopt};
}
private:
adt::Result<axpr::LetVar*> MakeRuntimeGetter(
axpr::LetVar* dispatch_ctx,
const KernelArgId<BirNode>& kernel_arg_id) const {
return kernel_arg_id.Match([&](const auto& impl) {
return MakeRuntimeGetterImpl(dispatch_ctx, impl);
});
}
adt::Result<axpr::LetVar*> MakeRuntimeGetterImpl(
axpr::LetVar* dispatch_ctx,
const InTensorDataPtrKernelArgId<BirNode>& kernel_arg_id) const {
const auto& opt_in_tensor_source =
arg_source_ctx->GetInputTensorSource(kernel_arg_id->ir_value);
ADT_CHECK(opt_in_tensor_source.has_value());
const auto* in_tensor_source = opt_in_tensor_source.value();
ADT_LET_CONST_REF(
tensor_var_ptr,
MakeGetterAnfExprByInTensorSource(dispatch_ctx, *in_tensor_source));
return &tensor_var_ptr->Attr("data_ptr");
}
adt::Result<axpr::LetVar*> MakeRuntimeGetterImpl(
axpr::LetVar* dispatch_ctx,
const OutTensorDataPtrKernelArgId<BirNode>& kernel_arg_id) const {
const auto& opt_out_tensor_source =
arg_source_ctx->GetOutputTensorSource(kernel_arg_id->ir_value);
ADT_CHECK(opt_out_tensor_source.has_value());
const auto* out_tensor_source = opt_out_tensor_source.value();
ADT_LET_CONST_REF(
tensor_var_ptr,
MakeGetterAnfExprByOutTensorSource(dispatch_ctx, *out_tensor_source));
return &tensor_var_ptr->Attr("data_ptr");
}
template <typename GetVarPtrT>
adt::Result<axpr::Lambda<axpr::CoreExpr>> CreateLambda(
const std::string& dispatch_ctx_name, const GetVarPtrT& GetVarPtr) const {
axpr::LambdaExprBuilder lmbd;
auto GetBody =
[&](axpr::LetContext& ctx) -> adt::Result<axpr::AnfExpr> { // NOLINT
ADT_LET_CONST_REF(var_ptr, GetVarPtr(&ctx.Var(dispatch_ctx_name)));
return static_cast<axpr::AnfExpr>(*var_ptr);
};
ADT_LET_CONST_REF(anf_expr, lmbd.TryLambda({dispatch_ctx_name}, GetBody));
const auto& core_expr = ConvertAnfExprToCoreExpr(anf_expr);
ADT_LET_CONST_REF(
atomic, core_expr.template TryGet<axpr::Atomic<axpr::CoreExpr>>());
ADT_LET_CONST_REF(lambda,
atomic.template TryGet<axpr::Lambda<axpr::CoreExpr>>());
return lambda;
}
adt::Result<axpr::LetVar*> MakeGetterAnfExprByInTensorSource(
axpr::LetVar* dispatch_ctx,
const InTensorSource& in_tensor_source) const {
auto& inputs_var = dispatch_ctx->Attr("inputs");
return MakeGetterAnfExprByTensorSource(&inputs_var,
in_tensor_source.tensor_source);
}
adt::Result<axpr::LetVar*> MakeGetterAnfExprByOutTensorSource(
axpr::LetVar* dispatch_ctx,
const OutTensorSource& out_tensor_source) const {
auto& outputs_var = dispatch_ctx->Attr("outputs");
return MakeGetterAnfExprByTensorSource(&outputs_var,
out_tensor_source.tensor_source);
}
adt::Result<axpr::LetVar*> MakeGetterAnfExprByTensorSource(
axpr::LetVar* in_out_tensors, const TensorSource& tensor_source) const {
using RetT = adt::Result<axpr::LetVar*>;
return tensor_source.Match(
[&](const NativeIrValueSource& native) -> RetT {
return &in_out_tensors->At(native.native_ir_value_index);
},
[&](const PackedIrValueSource& packed) -> RetT {
return &in_out_tensors->At(packed.packed_ir_value_index)
.At(packed.tensor_member_index);
});
}
adt::Result<axpr::LetVar*> MakeRuntimeGetterImpl(
axpr::LetVar* dispatch_ctx,
const DimExprKernelArgId<BirNode>& kernel_arg_id) const {
ADT_CHECK(arg_source_ctx->HasDirectOrIndirectDimExprSource(
kernel_arg_id->dim_expr));
return MakeGetterAnfExprByDimExpr(dispatch_ctx, kernel_arg_id->dim_expr);
}
adt::Result<axpr::LetVar*> MakeGetterAnfExprByDimSource(
axpr::LetVar* dispatch_ctx, const DimSource& dim_source) const {
using RetT = adt::Result<axpr::LetVar*>;
return dim_source.Match(
[&](const ShapeDimSource& shape_dim_source) -> RetT {
ADT_LET_CONST_REF(tensor_var_ptr,
MakeGetterAnfExprByInOutTensorSource(
dispatch_ctx, shape_dim_source.tensor_source));
auto* ctx = dispatch_ctx->ctx();
auto* dim_expr =
&tensor_var_ptr->Attr("shape").At(shape_dim_source.dim_axis);
auto* data_value = &ctx->Var("DataValue").Call(*dim_expr);
auto* ret = &ctx->Var(ctx->NewTmpVarName());
*ret = data_value->Attr("cast").Call(
ctx->Var("DataType").Attr("const_int64"));
return ret;
},
[&](const DataDimSource& data_dim_source) -> RetT {
return adt::errors::TypeError{"DataDimSource is not supported yet."};
});
}
adt::Result<axpr::LetVar*> MakeGetterAnfExprByInOutTensorSource(
axpr::LetVar* dispatch_ctx,
const InOutTensorSource& in_out_tensor_source) const {
using RetT = adt::Result<axpr::LetVar*>;
return in_out_tensor_source.Match(
[&](const InTensorSource& in_tensor_source) -> RetT {
return MakeGetterAnfExprByInTensorSource(dispatch_ctx,
in_tensor_source);
},
[&](const OutTensorSource& out_tensor_source) -> RetT {
return MakeGetterAnfExprByOutTensorSource(dispatch_ctx,
out_tensor_source);
});
}
adt::Result<axpr::LetVar*> MakeGetterAnfExprByDimExpr(
axpr::LetVar* dispatch_ctx, const symbol::DimExpr& dim_expr) const {
const auto& opt_dim_source = arg_source_ctx->GetDimExprSource(dim_expr);
if (opt_dim_source.has_value()) {
return MakeGetterAnfExprByDimSource(dispatch_ctx,
*opt_dim_source.value());
}
return dim_expr.Match([&](const auto& impl) {
return MakeGetterAnfExprByDimExprImpl(dispatch_ctx, impl);
});
}
adt::Result<axpr::LetVar*> MakeGetterAnfExprByDimExprImpl(
axpr::LetVar* dispatch_ctx, int64_t c) const {
auto* ctx = dispatch_ctx->ctx();
auto* ret_var = &ctx->Var(ctx->NewTmpVarName());
*ret_var = ctx->Int64(c);
return ret_var;
}
adt::Result<axpr::LetVar*> MakeGetterAnfExprByDimExprImpl(
axpr::LetVar* dispatch_ctx, const std::string& symbol) const {
return adt::errors::NotImplementedError{
"Dead code. Symbols have been handled in MakeGetterAnfExprByDimExpr()"};
}
adt::Result<axpr::LetVar*> MakeGetterAnfExprByDimExprImpl(
axpr::LetVar* dispatch_ctx,
const symbol::Negative<symbol::DimExpr>& dim_expr) const {
return adt::errors::NotImplementedError{
"Dead code. Negative dim_exprs have been handled in "
"MakeGetterAnfExprByDimExprImpl(dispatch_ctx, const "
"symbol::Add<symbol::DimExpr>&)"};
}
adt::Result<axpr::LetVar*> MakeGetterAnfExprByDimExprImpl(
axpr::LetVar* dispatch_ctx,
const symbol::Add<symbol::DimExpr>& dim_expr) const {
const auto& [operands] = dim_expr;
ADT_CHECK(operands->size() > 0);
auto* ctx = dispatch_ctx->ctx();
ADT_LET_CONST_REF(
init_var_ptr,
MakeGetterAnfExprByDimExpr(dispatch_ctx, operands->at(0)));
axpr::LetVar* ret_var_ptr = init_var_ptr;
for (int i = 1; i < operands->size(); ++i) {
const auto& operand = operands->at(i);
auto* tmp_var_ptr = &ctx->Var(ctx->NewTmpVarName());
if (operand.template Has<symbol::Negative<symbol::DimExpr>>()) {
const auto& [operand_operand] =
*operand.template Get<symbol::Negative<symbol::DimExpr>>();
ADT_LET_CONST_REF(
operand_operand_var_ptr,
MakeGetterAnfExprByDimExpr(dispatch_ctx, operand_operand));
*tmp_var_ptr = ctx->Call(
axpr::kBuiltinSub(), *ret_var_ptr, *operand_operand_var_ptr);
} else {
ADT_LET_CONST_REF(operand_var_ptr,
MakeGetterAnfExprByDimExpr(dispatch_ctx, operand));
*tmp_var_ptr =
ctx->Call(axpr::kBuiltinAdd(), *ret_var_ptr, *operand_var_ptr);
}
ret_var_ptr = tmp_var_ptr;
}
return ret_var_ptr;
}
adt::Result<axpr::LetVar*> MakeGetterAnfExprByDimExprImpl(
axpr::LetVar* dispatch_ctx,
const symbol::Mul<symbol::DimExpr>& dim_expr) const {
const auto& [operands] = dim_expr;
ADT_CHECK(operands->size() > 0);
auto* ctx = dispatch_ctx->ctx();
ADT_LET_CONST_REF(
init_var_ptr,
MakeGetterAnfExprByDimExpr(dispatch_ctx, operands->at(0)));
axpr::LetVar* ret_var_ptr = init_var_ptr;
for (int i = 1; i < operands->size(); ++i) {
const auto& operand = operands->at(i);
auto* tmp_var_ptr = &ctx->Var(ctx->NewTmpVarName());
ADT_LET_CONST_REF(operand_var_ptr,
MakeGetterAnfExprByDimExpr(dispatch_ctx, operand));
*tmp_var_ptr =
ctx->Call(axpr::kBuiltinMul(), *ret_var_ptr, *operand_var_ptr);
ret_var_ptr = tmp_var_ptr;
}
return ret_var_ptr;
}
adt::Result<axpr::LetVar*> MakeGetterAnfExprByDimExprImpl(
axpr::LetVar* dispatch_ctx,
const symbol::Div<symbol::DimExpr>& dim_expr) const {
const auto& operand_lhs = (*dim_expr).lhs;
const auto& operand_rhs = (*dim_expr).rhs;
auto* ctx = dispatch_ctx->ctx();
ADT_LET_CONST_REF(init_var_ptr,
MakeGetterAnfExprByDimExpr(dispatch_ctx, operand_lhs));
axpr::LetVar* ret_var_ptr = init_var_ptr;
auto* tmp_var_ptr = &ctx->Var(ctx->NewTmpVarName());
ADT_LET_CONST_REF(operand_var_ptr,
MakeGetterAnfExprByDimExpr(dispatch_ctx, operand_rhs));
*tmp_var_ptr =
ctx->Call(axpr::kBuiltinDiv(), *ret_var_ptr, *operand_var_ptr);
ret_var_ptr = tmp_var_ptr;
return ret_var_ptr;
}
adt::Result<axpr::LetVar*> MakeGetterAnfExprByDimExprImpl(
axpr::LetVar* dispatch_ctx,
const symbol::Max<symbol::DimExpr>& dim_expr) const {
const auto& [operands] = dim_expr;
ADT_CHECK(operands->size() > 0);
auto* ctx = dispatch_ctx->ctx();
ADT_LET_CONST_REF(
init_var_ptr,
MakeGetterAnfExprByDimExpr(dispatch_ctx, operands->at(0)));
axpr::LetVar* ret_var_ptr = init_var_ptr;
for (int i = 1; i < operands->size(); ++i) {
const auto& operand = operands->at(i);
auto* tmp_var_ptr = &ctx->Var(ctx->NewTmpVarName());
ADT_LET_CONST_REF(operand_var_ptr,
MakeGetterAnfExprByDimExpr(dispatch_ctx, operand));
*tmp_var_ptr = ctx->Call("max", *ret_var_ptr, *operand_var_ptr);
ret_var_ptr = tmp_var_ptr;
}
return ret_var_ptr;
}
adt::Result<axpr::LetVar*> MakeGetterAnfExprByDimExprImpl(
axpr::LetVar* dispatch_ctx,
const symbol::Min<symbol::DimExpr>& dim_expr) const {
const auto& [operands] = dim_expr;
ADT_CHECK(operands->size() > 0);
auto* ctx = dispatch_ctx->ctx();
ADT_LET_CONST_REF(
init_var_ptr,
MakeGetterAnfExprByDimExpr(dispatch_ctx, operands->at(0)));
axpr::LetVar* ret_var_ptr = init_var_ptr;
for (int i = 1; i < operands->size(); ++i) {
const auto& operand = operands->at(i);
auto* tmp_var_ptr = &ctx->Var(ctx->NewTmpVarName());
ADT_LET_CONST_REF(operand_var_ptr,
MakeGetterAnfExprByDimExpr(dispatch_ctx, operand));
*tmp_var_ptr = ctx->Call("min", *ret_var_ptr, *operand_var_ptr);
ret_var_ptr = tmp_var_ptr;
}
return ret_var_ptr;
}
adt::Result<axpr::LetVar*> MakeGetterAnfExprByDimExprImpl(
axpr::LetVar* dispatch_ctx,
const symbol::Broadcast<symbol::DimExpr>& dim_expr) const {
const auto& [operands] = dim_expr;
ADT_CHECK(operands->size() > 0);
auto* ctx = dispatch_ctx->ctx();
ADT_LET_CONST_REF(
init_var_ptr,
MakeGetterAnfExprByDimExpr(dispatch_ctx, operands->at(0)));
axpr::LetVar* ret_var_ptr = init_var_ptr;
for (int i = 1; i < operands->size(); ++i) {
const auto& operand = operands->at(i);
auto* tmp_var_ptr = &ctx->Var(ctx->NewTmpVarName());
ADT_LET_CONST_REF(operand_var_ptr,
MakeGetterAnfExprByDimExpr(dispatch_ctx, operand));
*tmp_var_ptr = ctx->Call("broadcast", *ret_var_ptr, *operand_var_ptr);
ret_var_ptr = tmp_var_ptr;
}
return ret_var_ptr;
}
};
} // namespace ap::code_gen