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

337 lines
11 KiB
C++

// Copyright (c) 2025 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/optim/ir_simplify.h"
#include <gtest/gtest.h>
#include "paddle/cinn/cinn.h"
#include "paddle/cinn/ir/ir.h"
#include "paddle/cinn/ir/ir_printer.h"
#include "paddle/cinn/ir/op/ir_operators.h"
#include "paddle/cinn/ir/schedule/ir_schedule.h"
#include "paddle/cinn/ir/utils/ir_nodes_collector.h"
#include "paddle/cinn/ir/utils/stmt_converter.h"
#include "paddle/cinn/utils/string.h"
namespace cinn {
namespace optim {
/*
serial for (i, 0ll, 32768ll) {
serial for (j, 0ll, 16ll) {
serial for (reduce_k_0, 0ll, 128ll) {
var_18[i, j] = select((var_18[i, j] > var_17[i, j, reduce_k_0]),
var_18[i, j], var_17[i, j, reduce_k_0])
}
}
}
}
*/
TEST(IRSimplifySelect, SimplifySelectToMax) {
Context::Global().ResetNameId();
// Create input IR matching the specified pattern
const std::vector<ir::Expr> shape_2d = {ir::Expr(32768), ir::Expr(16)};
const std::vector<ir::Expr> shape_3d = {
ir::Expr(32768), ir::Expr(16), ir::Expr(128)};
ir::Tensor var_17 =
ir::_Tensor_::Make("var_17", ir::Float(32), shape_3d, shape_3d);
var_17->WithBuffer("global", "var_17_buffer");
ir::Tensor var_18 =
ir::_Tensor_::Make("var_18", ir::Float(32), shape_2d, shape_2d);
var_18->WithBuffer("global", "var_18_buffer");
// Define loop variables
ir::Var var_i = ir::Var(ir::Expr(0), ir::Expr(32768), "i");
ir::Var var_j = ir::Var(ir::Expr(0), ir::Expr(16), "j");
ir::Var var_reduce_k_0 = ir::Var(ir::Expr(0), ir::Expr(128), "reduce_k_0");
// Create innermost reduction loop body
ir::Expr reduce_body = ir::Store::Make(
var_18,
ir::Select::Make(
ir::GT::Make(ir::Load::Make(var_18, {var_i, var_j}),
ir::Load::Make(var_17, {var_i, var_j, var_reduce_k_0})),
ir::Load::Make(var_18, {var_i, var_j}),
ir::Load::Make(var_17, {var_i, var_j, var_reduce_k_0})),
{var_i, var_j});
// Create reduction loop
ir::Expr reduce_loop = ir::For::Make(var_reduce_k_0,
ir::Expr(0),
ir::Expr(128),
ir::ForType::Serial,
ir::DeviceAPI::Host,
ir::Block::Make({reduce_body}));
// Create j loop
ir::Expr j_loop = ir::For::Make(var_j,
ir::Expr(0),
ir::Expr(16),
ir::ForType::Serial,
ir::DeviceAPI::Host,
ir::Block::Make({reduce_loop}));
// Create i loop
ir::Expr i_loop = ir::For::Make(var_i,
ir::Expr(0),
ir::Expr(32768),
ir::ForType::Serial,
ir::DeviceAPI::Host,
ir::Block::Make({j_loop}));
// Final expression
ir::Expr expr = ir::Block::Make({i_loop});
VLOG(6) << "Before Simplify: " << expr;
Simplify(&expr);
VLOG(6) << "After Simplify: " << expr;
// Expected output verification
std::string expected_ir = R"ROC({
serial for (i, 0, 32768)
{
serial for (j, 0, 16)
{
serial for (reduce_k_0, 0, 128)
{
var_18[i, j] = cinn_max(var_17[i, j, reduce_k_0], var_18[i, j])
}
}
}
})ROC";
EXPECT_EQ(utils::GetStreamCnt(expr), utils::Trim(expected_ir));
}
/*
serial for (i, 0ll, 32768ll) {
serial for (j, 0ll, 16ll) {
serial for (reduce_k_0, 0ll, 128ll) {
var_18[i, j] = select((var_18[i, j] < var_17[i, j, reduce_k_0]),
var_18[i, j], var_17[i, j, reduce_k_0])
}
}
}
}
*/
TEST(IRSimplifySelect, SimplifySelectToMin) {
Context::Global().ResetNameId();
// Create input IR matching the specified pattern
const std::vector<ir::Expr> shape_2d = {ir::Expr(32768), ir::Expr(16)};
const std::vector<ir::Expr> shape_3d = {
ir::Expr(32768), ir::Expr(16), ir::Expr(128)};
ir::Tensor var_17 =
ir::_Tensor_::Make("var_17", ir::Float(32), shape_3d, shape_3d);
var_17->WithBuffer("global", "var_17_buffer");
ir::Tensor var_18 =
ir::_Tensor_::Make("var_18", ir::Float(32), shape_2d, shape_2d);
var_18->WithBuffer("global", "var_18_buffer");
// Define loop variables
ir::Var var_i = ir::Var(ir::Expr(0), ir::Expr(32768), "i");
ir::Var var_j = ir::Var(ir::Expr(0), ir::Expr(16), "j");
ir::Var var_reduce_k_0 = ir::Var(ir::Expr(0), ir::Expr(128), "reduce_k_0");
// Create innermost reduction loop body
ir::Expr reduce_body = ir::Store::Make(
var_18,
ir::Select::Make(
ir::LT::Make(ir::Load::Make(var_18, {var_i, var_j}),
ir::Load::Make(var_17, {var_i, var_j, var_reduce_k_0})),
ir::Load::Make(var_18, {var_i, var_j}),
ir::Load::Make(var_17, {var_i, var_j, var_reduce_k_0})),
{var_i, var_j});
// Create reduction loop
ir::Expr reduce_loop = ir::For::Make(var_reduce_k_0,
ir::Expr(0),
ir::Expr(128),
ir::ForType::Serial,
ir::DeviceAPI::Host,
ir::Block::Make({reduce_body}));
// Create j loop
ir::Expr j_loop = ir::For::Make(var_j,
ir::Expr(0),
ir::Expr(16),
ir::ForType::Serial,
ir::DeviceAPI::Host,
ir::Block::Make({reduce_loop}));
// Create i loop
ir::Expr i_loop = ir::For::Make(var_i,
ir::Expr(0),
ir::Expr(32768),
ir::ForType::Serial,
ir::DeviceAPI::Host,
ir::Block::Make({j_loop}));
// Final expression
ir::Expr expr = ir::Block::Make({i_loop});
VLOG(6) << "Before Simplify: " << expr;
Simplify(&expr);
VLOG(6) << "After Simplify: " << expr;
// Expected output verification
std::string expected_ir = R"ROC({
serial for (i, 0, 32768)
{
serial for (j, 0, 16)
{
serial for (reduce_k_0, 0, 128)
{
var_18[i, j] = cinn_min(var_18[i, j], var_17[i, j, reduce_k_0])
}
}
}
})ROC";
EXPECT_EQ(utils::GetStreamCnt(expr), utils::Trim(expected_ir));
}
/*
serial for (i, 0ll, 32768ll)
{
serial for (j, 0, 16)
{
serial for (j_0, 0, 128)
{
var_45[i, j, j_0)] = select(
(var_18[i, ((((j * 128ll) + j_0) / 128ll) + 0ll)] <=
float32(3.4028234663852886e+38)),
select(
(var_18[i, ((((j * 128ll) + j_0) / 128ll) + 0ll)] >=
float32(9.9999997473787516e-05)),
var_18[i, ((((j * 128ll) + j_0) / 128ll) + 0ll)],
float32(9.9999997473787516e-05)
),
float32(3.4028234663852886e+38)
)
}
}
}
*/
TEST(IRSimplifySelect, SimplifySelectToMinMax) {
Context::Global().ResetNameId();
// Create input IR matching the specified pattern
const std::vector<ir::Expr> shape_2d = {ir::Expr(32768), ir::Expr(16)};
const std::vector<ir::Expr> shape_3d = {
ir::Expr(32768), ir::Expr(16), ir::Expr(128)};
ir::Tensor var_18 =
ir::_Tensor_::Make("var_18", ir::Float(32), shape_2d, shape_2d);
var_18->WithBuffer("global", "var_18_buffer");
ir::Tensor var_45 =
ir::_Tensor_::Make("var_45", ir::Float(32), shape_3d, shape_3d);
var_45->WithBuffer("global", "var_45_buffer");
// Define loop variables
ir::Var var_i = ir::Var(ir::Expr(0), ir::Expr(32768), "i");
ir::Var var_j = ir::Var(ir::Expr(0), ir::Expr(16), "j");
ir::Var var_j_0 = ir::Var(ir::Expr(0), ir::Expr(128), "j_0");
// Create innermost loop body
ir::Expr body = ir::Store::Make(
var_45,
ir::Select::Make(
ir::LE::Make(
ir::Load::Make(
var_18,
{var_i,
ir::Div::Make(
ir::Add::Make(ir::Mul::Make(var_j, ir::Expr(128)),
var_j_0),
ir::Expr(128))}),
ir::Expr(3.4028234663852886e+38f)),
ir::Select::Make(
ir::GE::Make(
ir::Load::Make(
var_18,
{var_i,
ir::Div::Make(
ir::Add::Make(ir::Mul::Make(var_j, ir::Expr(128)),
var_j_0),
ir::Expr(128))}),
ir::Expr(9.9999997473787516e-05f)),
ir::Load::Make(
var_18,
{var_i,
ir::Div::Make(
ir::Add::Make(ir::Mul::Make(var_j, ir::Expr(128)),
var_j_0),
ir::Expr(128))}),
ir::Expr(9.9999997473787516e-05f)),
ir::Expr(3.4028234663852886e+38f)),
{var_i, var_j, var_j_0});
// Create j_0 loop
ir::Expr j_0_loop = ir::For::Make(var_j_0,
ir::Expr(0),
ir::Expr(128),
ir::ForType::Serial,
ir::DeviceAPI::Host,
ir::Block::Make({body}));
// Create j loop
ir::Expr j_loop = ir::For::Make(var_j,
ir::Expr(0),
ir::Expr(16),
ir::ForType::Serial,
ir::DeviceAPI::Host,
ir::Block::Make({j_0_loop}));
// Create i loop
ir::Expr i_loop = ir::For::Make(var_i,
ir::Expr(0),
ir::Expr(32768),
ir::ForType::Serial,
ir::DeviceAPI::Host,
ir::Block::Make({j_loop}));
// Final expression
ir::Expr expr = ir::Block::Make({i_loop});
VLOG(6) << "Before Simplify: " << expr;
Simplify(&expr);
VLOG(6) << "After Simplify: " << expr;
// Expected output verification
std::string expected_ir = R"ROC({
serial for (i, 0, 32768)
{
serial for (j, 0, 16)
{
serial for (j_0, 0, 128)
{
var_45[i, j, j_0] = cinn_min(cinn_max(var_18[i, (((j * 128) + j_0) / 128)], 9.99999975e-05f), 3.40282347e+38f)
}
}
}
})ROC";
EXPECT_EQ(utils::GetStreamCnt(expr), utils::Trim(expected_ir));
}
} // namespace optim
} // namespace cinn