ir_program_test.cc 11.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// Copyright (c) 2023 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 <gtest/gtest.h>

17 18 19
#include "paddle/fluid/ir/dialect/pd_dialect.h"
#include "paddle/fluid/ir/dialect/pd_type.h"
#include "paddle/fluid/ir/dialect/utils.h"
20
#include "paddle/fluid/ir/interface/op_yaml_info.h"
21
#include "paddle/ir/core/block.h"
22 23 24 25 26 27
#include "paddle/ir/core/builtin_attribute.h"
#include "paddle/ir/core/builtin_dialect.h"
#include "paddle/ir/core/builtin_op.h"
#include "paddle/ir/core/ir_context.h"
#include "paddle/ir/core/program.h"
#include "paddle/ir/core/utils.h"
28 29 30
#include "paddle/phi/core/meta_tensor.h"
#include "paddle/phi/infermeta/binary.h"
#include "paddle/phi/kernels/elementwise_add_kernel.h"
31 32 33
// NOTE(zhangbo9674): File pd_op.h is generated by op_gen.py, see details in
// paddle/fluid/ir/dialect/CMakeLists.txt.
#include "paddle/fluid/ir/dialect/pd_op.h"
34 35 36 37

class AddOp : public ir::Op<AddOp> {
 public:
  using Op::Op;
38 39 40
  static const char *name() { return "test.add"; }
  static constexpr const char **attributes_name = nullptr;
  static constexpr uint32_t attributes_num = 0;
41
  void Verify();
42 43 44 45 46
  static void Build(ir::Builder &builder,             // NOLINT
                    ir::OperationArgument &argument,  // NOLINT
                    ir::OpResult l_operand,
                    ir::OpResult r_operand,
                    ir::Type sum_type);
47
};
48 49 50 51 52 53 54 55
void AddOp::Verify() {
  if (num_operands() != 2) {
    throw("The size of inputs must be equal to 2.");
  }
  if (num_results() != 1) {
    throw("The size of outputs must be equal to 1.");
  }
}
56 57 58 59 60 61 62 63 64
void AddOp::Build(ir::Builder &,
                  ir::OperationArgument &argument,
                  ir::OpResult l_operand,
                  ir::OpResult r_operand,
                  ir::Type sum_type) {
  argument.AddOperand(l_operand);
  argument.AddOperand(r_operand);
  argument.AddOutput(sum_type);
}
65 66
IR_DECLARE_EXPLICIT_TYPE_ID(AddOp)
IR_DEFINE_EXPLICIT_TYPE_ID(AddOp)
67 68 69 70 71 72 73 74 75 76 77

TEST(program_test, program) {
  // (1) Init environment.
  ir::IrContext *ctx = ir::IrContext::Instance();
  ir::Dialect *builtin_dialect =
      ctx->GetOrRegisterDialect<ir::BuiltinDialect>();
  builtin_dialect->RegisterOp<AddOp>();
  ir::Dialect *paddle_dialect =
      ctx->GetOrRegisterDialect<paddle::dialect::PaddleDialect>();

  // (2) Create an empty program object
78
  ir::Program program(ctx);
79 80 81

  // (3) Create a float32 DenseTensor Parameter and save into Program
  ir::Type fp32_dtype = ir::Float32Type::get(ctx);
82 83 84
  phi::DDim dims = {2, 2};
  phi::DataLayout data_layout = phi::DataLayout::NCHW;
  phi::LoD lod = {{0, 1, 2}};
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
  size_t offset = 0;
  ir::Type dense_tensor_dtype = paddle::dialect::DenseTensorType::get(
      ctx, fp32_dtype, dims, data_layout, lod, offset);

  std::vector<float> data_a = {1, 2, 3, 4};
  std::unique_ptr<ir::Parameter> parameter_a =
      std::make_unique<ir::Parameter>(reinterpret_cast<void *>(data_a.data()),
                                      4 * sizeof(float),
                                      dense_tensor_dtype);
  program.SetParameter("a", std::move(parameter_a));
  EXPECT_EQ(program.parameters_num() == 1, true);

  std::vector<float> data_b = {5, 6, 7, 8};
  std::unique_ptr<ir::Parameter> parameter_b =
      std::make_unique<ir::Parameter>(reinterpret_cast<void *>(data_b.data()),
                                      4 * sizeof(float),
                                      dense_tensor_dtype);
  program.SetParameter("b", std::move(parameter_b));
  EXPECT_EQ(program.parameters_num() == 2, true);

  // (4) Def a = GetParameterOp("a"), and create DenseTensor for a.
106 107
  ir::Builder builder(ctx, program.block());
  auto op1 = builder.Build<ir::GetParameterOp>("a", dense_tensor_dtype);
108 109

  EXPECT_EQ(&program, op1->GetParentProgram());
110
  EXPECT_EQ(op1->result(0).type().dialect().id(), paddle_dialect->id());
111
  using Interface = paddle::dialect::ParameterConvertInterface;
112 113
  Interface *a_interface =
      op1->result(0).type().dialect().GetRegisteredInterface<Interface>();
114 115 116 117
  std::shared_ptr<paddle::framework::Variable> a_var =
      a_interface->ParameterToVariable(program.GetParameter("a"));
  const phi::DenseTensor &a_tensor = a_var->Get<phi::DenseTensor>();
  EXPECT_EQ(a_tensor.numel(), 4);
118
  EXPECT_EQ(a_tensor.dims(), dims);
119
  EXPECT_EQ(a_tensor.dtype(), paddle::dialect::TransToPhiDataType(fp32_dtype));
120
  EXPECT_EQ(a_tensor.layout(), data_layout);
121 122 123 124 125 126 127
  EXPECT_EQ(a_tensor.lod(), lod);
  EXPECT_EQ(a_tensor.offset(), offset);
  for (int64_t i = 0; i < a_tensor.numel(); i++) {
    EXPECT_EQ(*(a_tensor.data<float>() + i), data_a[i]);
  }

  // (5) Def b = GetParameterOp("b"), and create DenseTensor for b.
128
  auto op2 = builder.Build<ir::GetParameterOp>("b", dense_tensor_dtype);
129

130 131 132
  EXPECT_EQ(op2->result(0).type().dialect().id(), paddle_dialect->id());
  Interface *b_interface =
      op2->result(0).type().dialect().GetRegisteredInterface<Interface>();
133 134 135 136
  std::shared_ptr<paddle::framework::Variable> b_var =
      b_interface->ParameterToVariable(program.GetParameter("b"));
  const phi::DenseTensor &b_tensor = b_var->Get<phi::DenseTensor>();
  EXPECT_EQ(b_tensor.numel(), 4);
137
  EXPECT_EQ(b_tensor.dims(), dims);
138
  EXPECT_EQ(b_tensor.dtype(), paddle::dialect::TransToPhiDataType(fp32_dtype));
139
  EXPECT_EQ(b_tensor.layout(), data_layout);
140 141 142 143 144 145 146
  EXPECT_EQ(b_tensor.lod(), lod);
  EXPECT_EQ(b_tensor.offset(), offset);
  for (int64_t i = 0; i < b_tensor.numel(); i++) {
    EXPECT_EQ(*(b_tensor.data<float>() + i), data_b[i]);
  }

  // (6) Def c = AddOp(a, b), execute this op.
147 148
  auto op3 =
      builder.Build<AddOp>(op1->result(0), op2->result(0), dense_tensor_dtype);
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
  phi::CPUContext *dev_ctx = static_cast<phi::CPUContext *>(
      paddle::platform::DeviceContextPool::Instance().Get(
          paddle::platform::CPUPlace()));
  phi::DenseTensor c_tensor =
      phi::Add<float, phi::CPUContext>(*dev_ctx, a_tensor, b_tensor);
  std::shared_ptr<paddle::framework::Variable> variable_c =
      std::make_shared<paddle::framework::Variable>();
  auto *dst_tensor = variable_c->GetMutable<phi::DenseTensor>();
  *dst_tensor = c_tensor;
  EXPECT_EQ(dst_tensor->numel(), b_tensor.numel());
  EXPECT_EQ(dst_tensor->dims(), b_tensor.dims());
  EXPECT_EQ(dst_tensor->dtype(), b_tensor.dtype());
  EXPECT_EQ(dst_tensor->layout(), b_tensor.layout());
  EXPECT_EQ(dst_tensor->lod(), b_tensor.lod());
  EXPECT_EQ(dst_tensor->offset(), b_tensor.offset());
  for (int64_t i = 0; i < dst_tensor->numel(); i++) {
    EXPECT_EQ(*(dst_tensor->data<float>() + i), data_a[i] + data_b[i]);
  }

168
  // (7) Def AbsOp(b)
169
  auto abs_op = builder.Build<paddle::dialect::AbsOp>(op1->result(0));
170 171
  paddle::dialect::OpYamlInfoInterface interface =
      abs_op->dyn_cast<paddle::dialect::OpYamlInfoInterface>();
172 173 174
  EXPECT_EQ(std::get<0>(interface.GetOpInfo())[0].name == "x", true);

  // (8) Def SetParameterOp(c, "c")
175 176
  auto op4 = builder.Build<ir::SetParameterOp>(op3->result(0), "c");

177
  EXPECT_EQ(op4->op_operand(0).type().dialect().id(), paddle_dialect->id());
178
  Interface *c_interface =
179
      op4->op_operand(0).type().dialect().GetRegisteredInterface<Interface>();
180 181 182 183 184 185 186 187 188 189 190 191
  //   ir::Parameter *parameter_c =
  //       c_interface->VariableToParameter(variable_c.get());
  std::unique_ptr<ir::Parameter> parameter_c =
      c_interface->VariableToParameter(variable_c.get());
  EXPECT_EQ(parameter_c->type(), dense_tensor_dtype);
  for (int64_t i = 0; i < dst_tensor->numel(); i++) {
    EXPECT_EQ(*(dst_tensor->data<float>() + i),
              *(static_cast<float *>(parameter_c->data()) + i));
  }
  program.SetParameter("c", std::move(parameter_c));

  // (8) Traverse Program
192
  EXPECT_EQ(program.block()->size() == 5, true);
193
  EXPECT_EQ(program.parameters_num() == 3, true);
194

Y
Yuanle Liu 已提交
195
  program.Print(std::cout);
196
}
197 198 199 200 201 202 203

TEST(program_test, slice_combine_test) {
  // (1) Init environment.
  ir::IrContext *ctx = ir::IrContext::Instance();
  ctx->GetOrRegisterDialect<ir::BuiltinDialect>();

  // (2) Create an empty program object
204
  ir::Program program(ctx);
205
  //   ir::Program *program = new ir::Program();
206
  EXPECT_EQ(program.block()->empty(), true);
207 208 209 210 211 212 213 214 215 216

  // (3) Create a float32 DenseTensor Parameter and save into Program
  ir::Type fp32_dtype = ir::Float32Type::get(ctx);

  // (4) Def a = GetParameterOp("a")
  std::string op1_name = ir::GetParameterOp::name();
  ir::OpInfo op1_info = ctx->GetRegisteredOpInfo(op1_name);
  std::unordered_map<std::string, ir::Attribute> op1_attribute{
      {"parameter_name", ir::StrAttribute::get(ctx, "a")}};
  ir::Operation *op1 =
217
      ir::Operation::Create({}, op1_attribute, {fp32_dtype}, op1_info);
218
  program.block()->push_back(op1);
219

K
kangguangli 已提交
220 221
  // (5) Def b = Constant("b")
  std::string op2_name = std::string(ir::ConstantOp::name());
222
  ir::OpInfo op2_info = ctx->GetRegisteredOpInfo(op2_name);
223 224 225 226
  ir::AttributeMap attr_map;
  attr_map.insert(std::pair<std::string, ir::Attribute>(
      "value", ir::FloatAttribute::get(ctx, 2.0)));
  ir::Operation *op2 =
227
      ir::Operation::Create({}, attr_map, {fp32_dtype}, op2_info);
228
  program.block()->push_back(op2);
229 230 231 232 233 234

  // (6) Def combine_op = CombineOp("a", "b")
  std::string combine_op_name = std::string(ir::CombineOp::name());
  ir::OpInfo combine_op_info = ctx->GetRegisteredOpInfo(combine_op_name);
  ir::Type output_type =
      ir::VectorType::get(ctx, std::vector<ir::Type>({fp32_dtype, fp32_dtype}));
235
  ir::Operation *combine_op = ir::Operation::Create(
236
      {op1->result(0), op2->result(0)}, {}, {output_type}, combine_op_info);
237 238
  ir::CombineOp combine_op_type = combine_op->dyn_cast<ir::CombineOp>();
  EXPECT_TRUE(combine_op_type.out());
239
  program.block()->push_back(combine_op);
240 241 242 243

  // (7) Def slice_op = SliceOp(combine_op, 0)
  std::string slice_op_name = std::string(ir::SliceOp::name());
  ir::OpInfo slice_op_info = ctx->GetRegisteredOpInfo(slice_op_name);
Z
zhangbo9674 已提交
244
  ir::Attribute index_attr = ir::Int32Attribute::get(ctx, 0);
245 246 247 248
  ir::Operation *slice_op = ir::Operation::Create({combine_op->result(0)},
                                                  {{"index", index_attr}},
                                                  {fp32_dtype},
                                                  slice_op_info);
249
  program.block()->push_back(slice_op);
250 251

  // (8) Traverse Program
Z
zhangbo9674 已提交
252
  EXPECT_EQ(program.block()->size() == 4, true);
253
}
254 255 256 257 258

TEST(program_test, builder) {
  ir::IrContext *ctx = ir::IrContext::Instance();
  ctx->GetOrRegisterDialect<paddle::dialect::PaddleDialect>();
  ir::Program program(ctx);
259
  ir::Builder builder = ir::Builder(ctx, program.block());
260

261
  paddle::dialect::FullOp full_op = builder.Build<paddle::dialect::FullOp>(
262
      std::vector<int64_t>{2, 2}, 1.5, phi::DataType::FLOAT32, phi::CPUPlace());
263
  ir::Type full_op_output = full_op->result(0).type();
264
  EXPECT_EQ(program.block()->size(), 1u);
265
  EXPECT_EQ(program.block()->back(), full_op.operation());
266 267 268
  EXPECT_EQ(full_op.num_operands(), 0u);
  EXPECT_EQ(full_op.num_results(), 1u);
  EXPECT_EQ(full_op.attributes().size(), 4u);
269 270 271 272 273 274 275 276 277
  EXPECT_EQ(
      full_op_output.dyn_cast<paddle::dialect::DenseTensorType>().offset() == 0,
      true);
  for (auto dim : phi::vectorize(
           full_op_output.dyn_cast<paddle::dialect::DenseTensorType>()
               .dims())) {
    EXPECT_EQ(dim == 2, true);
  }

278
  ir::ConstantOp constant = builder.Build<ir::ConstantOp>(
Z
zhangbo9674 已提交
279
      ir::Int32Attribute::get(ctx, 2), ir::Int32Type::get(ctx));
280
  EXPECT_EQ(program.block()->size() == 2, true);
Z
zhangbo9674 已提交
281
  EXPECT_EQ(constant.value().dyn_cast<ir::Int32Attribute>().data() == 2, true);
282
}