chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:40:42 +08:00
commit e25996e7db
15472 changed files with 3536181 additions and 0 deletions
+23
View File
@@ -0,0 +1,23 @@
cinn_cc_test(test_dfs_walker SRCS dfs_walker_test.cc DEPS gtest glog)
cinn_cc_test(test_dfs_topo_walker SRCS dfs_topo_walker_test.cc DEPS gtest glog)
cinn_cc_test(test_cinn_value SRCS cinn_value_test.cc DEPS cinncore)
cinn_cc_test(test_axis SRCS axis_test.cc DEPS cinncore)
cinn_cc_test(dim_expr_converter_test SRCS dim_expr_converter_test.cc DEPS
cinncore)
cinn_cc_test(broadcast_tree_test SRCS broadcast_tree_test.cc DEPS cinncore)
cinn_cc_test(test_equation_graph_topo_walker SRCS
equation_graph_topo_walker_test.cc DEPS gtest glog)
cinn_cc_test(test_type SRCS type_test.cc DEPS cinncore)
cinn_cc_test(test_topo_walker SRCS topo_walker_test.cc DEPS gtest glog)
cinn_cc_test(test_shared SRCS shared_test.cc DEPS cinncore)
cinn_cc_test(test_is_reachable_predicator SRCS is_reachable_predicator_test.cc
DEPS gtest glog)
cinn_cc_test(test_integer_set SRCS integer_set_test.cc DEPS cinncore)
if(WITH_CUDA)
cinn_nv_test(test_fp16_bf16_cuda SRCS float16_bfloat16_cuda_test.cu DEPS
gtest glog)
endif()
cinn_cc_test(test_fp16_bf16_host SRCS float16_bfloat16_host_test.cc DEPS gtest
glog)
+45
View File
@@ -0,0 +1,45 @@
// Copyright (c) 2023 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/common/axis.h"
#include <glog/logging.h>
#include <gtest/gtest.h>
#include <string>
#include "paddle/cinn/utils/string.h"
namespace cinn {
namespace common {
TEST(AXISNAME, BASE) {
ASSERT_EQ(axis_name(0), std::string("i"));
ASSERT_EQ(axis_name(1), std::string("j"));
ASSERT_EQ(axis_name(22), std::string("ii"));
ASSERT_EQ(axis_name(44), std::string("iii"));
}
TEST(AXISNAME, CHECK_RESERVED) {
ASSERT_TRUE(IsAxisNameReserved("i"));
ASSERT_TRUE(IsAxisNameReserved("j"));
ASSERT_TRUE(IsAxisNameReserved("ii"));
ASSERT_TRUE(IsAxisNameReserved("iiiiiiiiii"));
ASSERT_FALSE(IsAxisNameReserved("ijk"));
ASSERT_FALSE(IsAxisNameReserved("iiiiiiiiiij"));
ASSERT_FALSE(IsAxisNameReserved("x"));
}
} // namespace common
} // namespace cinn
+118
View File
@@ -0,0 +1,118 @@
// 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.
#include "paddle/cinn/common/broadcast_tree.h"
#include "gtest/gtest.h"
namespace cinn::common {
using namespace symbol; // NOLINT
namespace {
DimExpr MakeBroadcastDimExpr(const DimExpr& expr1, const DimExpr& expr2) {
List<DimExpr> operands{expr1, expr2};
return Broadcast<DimExpr>{operands};
}
bool DimExprNonBroadcast(const DimExpr& dim_expr) {
if (dim_expr.Has<Broadcast<DimExpr>>()) {
return false;
} else {
return true;
}
}
void CheckLeafNonBroadcast(const BroadcastLeaf& leaf) {
for (const auto& operands : *leaf) {
for (const auto& operand : operands) {
ASSERT_TRUE(DimExprNonBroadcast(operand));
}
}
}
void CheckInnerBranchNonBroadcast(
const BroadcastBranch<BroadcastTree>& branch) {
const auto& [_, lhs_eq_rhs_tree, lhs_eq_one_tree, rhs_eq_one_tree] =
branch.tuple();
ASSERT_TRUE(lhs_eq_rhs_tree.Has<BroadcastLeaf>());
ASSERT_TRUE(lhs_eq_one_tree.Has<BroadcastLeaf>());
ASSERT_TRUE(rhs_eq_one_tree.Has<BroadcastLeaf>());
CheckLeafNonBroadcast(lhs_eq_rhs_tree.Get<BroadcastLeaf>());
CheckLeafNonBroadcast(lhs_eq_one_tree.Get<BroadcastLeaf>());
CheckLeafNonBroadcast(rhs_eq_one_tree.Get<BroadcastLeaf>());
}
} // namespace
TEST(BroadcastTree, Naive) {
DimExpr expr1("S1");
DimExpr expr2("S2");
DimExpr expr3("S3");
DimExpr expr4("S4");
std::vector<DimExpr> tensor_shape{expr1,
expr2,
MakeBroadcastDimExpr(expr1, expr2),
MakeBroadcastDimExpr(expr3, expr4)};
BroadcastLeaf leaf = adt::List<std::vector<DimExpr>>{tensor_shape};
int num_of_leaves = 0;
BroadcastTree tree = ConstructBroadcastTree(leaf, &num_of_leaves);
ASSERT_TRUE(tree.Has<BroadcastBranch<BroadcastTree>>());
const auto& branch = tree.Get<BroadcastBranch<BroadcastTree>>();
const auto& [cstr_broadcastable,
lhs_eq_rhs_tree,
lhs_eq_one_tree,
rhs_eq_one_tree] = branch.tuple();
ASSERT_EQ(cstr_broadcastable->lhs, DimExpr("S1"));
ASSERT_EQ(cstr_broadcastable->rhs, DimExpr("S2"));
ASSERT_TRUE(lhs_eq_rhs_tree.Has<BroadcastBranch<BroadcastTree>>());
ASSERT_TRUE(lhs_eq_one_tree.Has<BroadcastBranch<BroadcastTree>>());
ASSERT_TRUE(rhs_eq_one_tree.Has<BroadcastBranch<BroadcastTree>>());
CheckInnerBranchNonBroadcast(
lhs_eq_rhs_tree.Get<BroadcastBranch<BroadcastTree>>());
CheckInnerBranchNonBroadcast(
lhs_eq_one_tree.Get<BroadcastBranch<BroadcastTree>>());
CheckInnerBranchNonBroadcast(
rhs_eq_one_tree.Get<BroadcastBranch<BroadcastTree>>());
}
TEST(BroadcastTree, SimplifyConstantBroadcast) {
DimExpr expr1("S1");
DimExpr expr2("S2");
DimExpr expr3("S3");
DimExpr expr4(4);
std::vector<DimExpr> tensor_shape{expr1,
expr2,
MakeBroadcastDimExpr(expr1, expr2),
MakeBroadcastDimExpr(expr3, expr4)};
BroadcastLeaf leaf = adt::List<std::vector<DimExpr>>{tensor_shape};
int num_of_leaves = 0;
BroadcastTree tree = ConstructBroadcastTree(leaf, &num_of_leaves);
ASSERT_TRUE(tree.Has<BroadcastBranch<BroadcastTree>>());
const auto& branch = tree.Get<BroadcastBranch<BroadcastTree>>();
const auto& [cstr_broadcastable,
lhs_eq_rhs_tree,
lhs_eq_one_tree,
rhs_eq_one_tree] = branch.tuple();
ASSERT_EQ(cstr_broadcastable->lhs, DimExpr("S1"));
ASSERT_EQ(cstr_broadcastable->rhs, DimExpr("S2"));
ASSERT_TRUE(lhs_eq_rhs_tree.Has<BroadcastLeaf>());
ASSERT_TRUE(lhs_eq_one_tree.Has<BroadcastLeaf>());
ASSERT_TRUE(rhs_eq_one_tree.Has<BroadcastLeaf>());
CheckLeafNonBroadcast(lhs_eq_rhs_tree.Get<BroadcastLeaf>());
CheckLeafNonBroadcast(lhs_eq_one_tree.Get<BroadcastLeaf>());
CheckLeafNonBroadcast(rhs_eq_one_tree.Get<BroadcastLeaf>());
}
} // namespace cinn::common
+59
View File
@@ -0,0 +1,59 @@
// 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/common/cinn_value.h"
#include <gtest/gtest.h>
#include "paddle/cinn/common/common.h"
#include "paddle/cinn/common/ir_util.h"
#include "paddle/cinn/ir/ir.h"
#include "paddle/cinn/ir/ir_printer.h"
namespace cinn {
namespace common {
TEST(CINNValue, test) {
{
CINNValue value(32);
ASSERT_EQ(int(value), 32); // NOLINT
}
{
CINNValue value(32.f);
ASSERT_NEAR(float(value), 32.f, 1e-6); // NOLINT
}
}
TEST(CINNValue, buffer) {
cinn_buffer_t* v = nullptr;
CINNValue value(v);
ASSERT_EQ((cinn_buffer_t*)value, nullptr);
}
TEST(CINNValue, Expr) {
Expr a(1);
{
CINNValue value(a);
ASSERT_TRUE(a == value);
}
{
CINNValue copied = CINNValue(a);
ASSERT_TRUE(copied == cinn::common::make_const(1));
}
}
} // namespace common
} // namespace cinn
@@ -0,0 +1,54 @@
// Copyright (c) 2023 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 <glog/logging.h>
#include <gtest/gtest.h>
#include "paddle/cinn/common/dfs_topo_walker.h"
namespace cinn {
namespace common {
TEST(DfsTopoWalker, simple) {
std::vector<std::pair<int, int>> edges{
{0, 1}, {2, 3}, {1, 3}, {0, 3}, {3, 4}};
DfsTopoWalker<int> walker(
[&](int node, const std::function<void(int)>& NodeHandler) {
for (const auto& pair : edges) {
if (pair.second == node) {
NodeHandler(pair.first);
}
}
},
[&](int node, const std::function<void(int)>& NodeHandler) {
for (const auto& pair : edges) {
if (pair.first == node) {
NodeHandler(pair.second);
}
}
});
std::vector<int> sources{0, 2};
std::vector<int> outputs;
walker(sources.begin(), sources.end(), [&](int node) {
outputs.push_back(node);
});
for (auto output : outputs) {
LOG(INFO) << output;
}
std::vector<int> expected{0, 1, 2, 3, 4};
EXPECT_TRUE((outputs == expected));
}
} // namespace common
} // namespace cinn
+72
View File
@@ -0,0 +1,72 @@
// Copyright (c) 2023 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/common/dfs_walker.h"
#include <glog/logging.h>
#include <gtest/gtest.h>
namespace cinn {
namespace common {
TEST(DfsWalker, simple_on_push) {
DfsWalker<int> visitor(
[](int node, const std::function<void(int)>& NodeHandler) {
if (node == 0) {
NodeHandler(3);
} else if (node == 1) {
NodeHandler(2);
NodeHandler(3);
} else if (node == 2 || node == 3) {
NodeHandler(4);
}
});
std::vector<int> sources{0, 1};
std::vector<int> outputs;
visitor(sources.begin(), sources.end(), [&](int node) {
LOG(ERROR) << node;
outputs.push_back(node);
});
std::vector<int> expected{0, 3, 4, 1, 2};
EXPECT_TRUE((outputs == expected));
}
TEST(DfsWalker, simple_on_pop) {
DfsWalker<int> visitor(
[](int node, const std::function<void(int)>& NodeHandler) {
if (node == 0) {
NodeHandler(3);
} else if (node == 1) {
NodeHandler(2);
NodeHandler(3);
} else if (node == 2 || node == 3) {
NodeHandler(4);
}
});
std::vector<int> sources{0, 1};
std::vector<int> outputs;
visitor(
sources.begin(),
sources.end(),
[](int) {},
[&](int node) {
LOG(ERROR) << node;
outputs.push_back(node);
});
std::vector<int> expected{4, 3, 0, 2, 1};
EXPECT_TRUE((outputs == expected));
}
} // namespace common
} // namespace cinn
@@ -0,0 +1,96 @@
// 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 <sstream>
#include "gtest/gtest.h"
#include "paddle/cinn/common/dim_expr_converter.h"
#include "paddle/cinn/common/ir_util.h"
#include "paddle/cinn/ir/ir_printer.h"
namespace cinn::common::test {
using namespace symbol; // NOLINT
TEST(Convert, AddExpr) {
List<DimExpr> num_lists{DimExpr(4), DimExpr(5), DimExpr("sym_0")};
DimExpr dim_expr{Add<DimExpr>{num_lists}};
ir::Expr src_expr = DimExprConverter().ConvertToIrExpr(dim_expr);
ir::Expr expr1 =
ir::Add::Make(ir::Expr(std::int64_t(4)), ir::Expr(std::int64_t(5)));
ir::Expr dst_expr =
ir::Add::Make(expr1,
ir::_Var_::Make(ir::Expr(static_cast<int64_t>(1)),
ir::Expr(INT32_MAX),
"sym_0",
/* is_reduce = */ false,
/* is_symbolic_constant = */ true));
ASSERT_TRUE(MathEqual(src_expr, dst_expr));
}
TEST(Convert, SubExpr) {
DimExpr dim_expr = DimExpr(4) - DimExpr("sym_0");
ir::Expr src_expr = DimExprConverter().ConvertToIrExpr(dim_expr);
ir::Expr expr1 =
ir::Sub::Make(ir::Expr(std::int64_t(0)),
ir::_Var_::Make(ir::Expr(static_cast<int64_t>(1)),
ir::Expr(INT32_MAX),
"sym_0",
/* is_reduce = */ false,
/* is_symbolic_constant = */ true));
ir::Expr dst_expr = ir::Add::Make(ir::Expr(std::int64_t(4)), expr1);
ASSERT_TRUE(MathEqual(src_expr, dst_expr));
}
TEST(Convert, MulExpr) {
List<DimExpr> num_lists{DimExpr(4), DimExpr(5), DimExpr("sym_0")};
DimExpr dim_expr{Mul<DimExpr>{num_lists}};
ir::Expr src_expr = DimExprConverter().ConvertToIrExpr(dim_expr);
ir::Expr expr1 =
ir::Mul::Make(ir::Expr(std::int64_t(4)), ir::Expr(std::int64_t(5)));
ir::Expr dst_expr =
ir::Mul::Make(expr1,
ir::_Var_::Make(ir::Expr(static_cast<int64_t>(1)),
ir::Expr(INT32_MAX),
"sym_0",
/* is_reduce = */ false,
/* is_symbolic_constant = */ true));
ASSERT_TRUE(MathEqual(src_expr, dst_expr));
}
TEST(Convert, MaxExpr) {
List<DimExpr> num_lists{DimExpr(4), DimExpr(5), DimExpr("sym_0")};
DimExpr dim_expr{Max<DimExpr>{num_lists}};
ir::Expr src_expr = DimExprConverter().ConvertToIrExpr(dim_expr);
std::ostringstream stream;
stream << src_expr;
ASSERT_EQ(stream.str(), "cinn_max(cinn_max(4ll, 5ll), sym_0)");
}
TEST(Convert, MinExpr) {
List<DimExpr> num_lists{DimExpr(4), DimExpr(5), DimExpr("sym_0")};
DimExpr dim_expr{Min<DimExpr>{num_lists}};
ir::Expr src_expr = DimExprConverter().ConvertToIrExpr(dim_expr);
std::ostringstream stream;
stream << src_expr;
ASSERT_EQ(stream.str(), "cinn_min(cinn_min(4ll, 5ll), sym_0)");
}
} // namespace cinn::common::test
@@ -0,0 +1,116 @@
// 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.
// TODO(yifan): Add unittest here
#include "paddle/cinn/common/equation_graph_topo_walker.h"
#include <glog/logging.h>
#include <gtest/gtest.h>
namespace adt {
namespace common {
using VT = int;
using FT = std::string;
/*
Graph ex:
1-> "1->10" -> 10
2-> "2->20" -> 20
*/
TEST(EquationGraphTopoWalker, simple1) {
auto F4V = [](VT variable, const std::function<void(FT)>& visitor) {
if (variable == 1) {
visitor("1->10");
} else if (variable == 2) {
visitor("2->20");
}
};
auto InV4F = [](FT function, const std::function<void(VT)>& visitor) {
if (function == "1->10") {
visitor(1);
} else if (function == "2->20") {
visitor(2);
}
};
auto OutV4F = [](FT function, const std::function<void(VT)>& visitor) {
if (function == "1->10") {
visitor(10);
} else if (function == "2->20") {
visitor(20);
}
};
cinn::EquationGraphTopoWalker<VT, FT> walker(F4V, InV4F, OutV4F);
std::vector<FT> outputs;
std::function<void(FT)> FunctionVisitor = [&](FT function) {
outputs.push_back(function);
};
walker.WalkFunction(1, FunctionVisitor);
std::vector<FT> expected{"1->10"};
EXPECT_TRUE((outputs == expected));
}
/*
Graph ex:
1 -> "1->10, 1->11" -> 10
-> 11
2 -> "2->20" -> 20
3 -> "3->30, 3->31" -> 30
-> 31
*/
TEST(EquationGraphTopoWalker, simple2) {
auto F4V = [](VT variable, const std::function<void(FT)>& visitor) {
if (variable == 1) {
visitor("1->10, 1->11");
} else if (variable == 2) {
visitor("2->20");
} else if (variable == 3) {
visitor("3->30, 3->31");
}
};
auto InV4F = [](FT function, const std::function<void(VT)>& visitor) {
if (function == "1->10, 1->11") {
visitor(1);
} else if (function == "2->20") {
visitor(2);
} else if (function == "3->30, 3->31") {
visitor(3);
}
};
auto OutV4F = [](FT function, const std::function<void(VT)>& visitor) {
if (function == "1->10, 1->11") {
visitor(10);
visitor(11);
} else if (function == "2->20") {
visitor(20);
} else if (function == "3->30, 3->31") {
visitor(30);
visitor(31);
}
};
cinn::EquationGraphTopoWalker<VT, FT> walker(F4V, InV4F, OutV4F);
std::vector<VT> outputs;
std::function<void(VT)> VariableVisitor = [&](VT variable) {
outputs.push_back(variable);
};
walker.WalkVariable(1, VariableVisitor);
std::vector<VT> expected{1, 10, 11};
EXPECT_TRUE((outputs == expected));
}
} // namespace common
} // namespace adt
@@ -0,0 +1,286 @@
// 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 <glog/logging.h>
#include <gtest/gtest.h>
#include <random>
#include <vector>
#include "paddle/cinn/common/bfloat16.h"
#include "paddle/cinn/common/float16.h"
#include "paddle/common/enforce.h"
namespace cinn {
namespace common {
#define CUDA_CALL(func) \
{ \
auto status = func; \
if (status != cudaSuccess) { \
std::stringstream ss; \
ss << "CUDA Error : " << cudaGetErrorString(status); \
PADDLE_THROW(::common::errors::Fatal(ss.str())); \
} \
}
class CudaMem {
public:
CudaMem() = default;
void* mutable_data(size_t bytes) {
PADDLE_ENFORCE_GT(
bytes,
0,
::common::errors::InvalidArgument("Cannot allocate empty memory!"));
if (ptr) {
PADDLE_ENFORCE_EQ(
bytes,
bytes_,
::common::errors::InvalidArgument("Try allocate memory twice!"));
return ptr;
}
CUDA_CALL(cudaMalloc(&ptr, bytes));
bytes_ = bytes;
return ptr;
}
template <typename T>
T* mutable_data(size_t num) {
return reinterpret_cast<T*>(mutable_data(num * sizeof(T)));
}
void* data() const {
PADDLE_ENFORCE_NOT_NULL(ptr,
::common::errors::InvalidArgument(
"Pointer is null; please ensure it is properly "
"initialized before use."));
return ptr;
}
template <typename T>
T* data() const {
return reinterpret_cast<T*>(data());
}
void MemcpyFromHost(const void* src,
size_t bytes,
cudaStream_t stream = nullptr) {
PADDLE_ENFORCE_LE(
bytes,
bytes_,
::common::errors::InvalidArgument("Too many data need copy"));
CUDA_CALL(cudaMemcpyAsync(ptr, src, bytes, cudaMemcpyHostToDevice, stream));
}
void MemcpyToHost(void* dst, size_t bytes, cudaStream_t stream = nullptr) {
PADDLE_ENFORCE_LE(
bytes,
bytes_,
::common::errors::InvalidArgument("Too many data need copy"));
CUDA_CALL(cudaMemcpyAsync(dst, ptr, bytes, cudaMemcpyDeviceToHost, stream));
}
~CudaMem() {
if (ptr) {
cudaFree(ptr);
}
bytes_ = 0;
}
private:
void* ptr{nullptr};
size_t bytes_{0};
};
__global__ void cast_fp32_to_fp16_cuda_kernel(const float* input,
const int num,
float16* out) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < num) {
out[idx] = float16(input[idx]);
}
}
__global__ void cast_fp16_to_fp32_cuda_kernel(const float16* input,
const int num,
float* out) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < num) {
out[idx] = static_cast<float>(input[idx]);
}
}
__global__ void test_fp16_cuda_kernel(const float16* x,
const float16* y,
const int num,
float16* out) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < num) {
float16 x_i = x[idx], y_i = y[idx];
x_i += float16(1);
out[idx] = (x_i + y_i) * (x_i - y_i);
}
}
__global__ void cast_fp32_to_bf16_cuda_kernel(const float* input,
const int num,
bfloat16* out) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < num) {
out[idx] = bfloat16(input[idx]);
}
}
__global__ void cast_bf16_to_fp32_cuda_kernel(const bfloat16* input,
const int num,
float* out) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < num) {
out[idx] = static_cast<float>(input[idx]);
}
}
__global__ void test_bf16_cuda_kernel(const bfloat16* x,
const bfloat16* y,
const int num,
bfloat16* out) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < num) {
bfloat16 x_i = x[idx], y_i = y[idx];
x_i += bfloat16(1);
out[idx] = (x_i + y_i) * (x_i - y_i);
}
}
__global__ void test_fp32_cuda_kernel(const float* x,
const float* y,
const int num,
float* out) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < num) {
float x_i = x[idx], y_i = y[idx];
x_i += 1.0f;
out[idx] = (x_i + y_i) * (x_i - y_i);
}
}
TEST(FP16_BF16, basic_cuda) {
#ifdef CUDA_VERSION
LOG(INFO) << "CUDA version: " << CUDA_VERSION;
#endif
int num = 2048;
cudaStream_t stream;
CUDA_CALL(cudaStreamCreate(&stream));
dim3 block = 1024;
dim3 grid = (num + block.x - 1) / block.x;
std::vector<float> x_fp32_host(num), y_fp32_host(num);
{ // step1 : generate input data
std::random_device r;
std::default_random_engine eng(r());
std::uniform_real_distribution<float> dis(1e-5f, 1.0f);
for (int i = 0; i < num; ++i) {
x_fp32_host[i] = dis(eng);
y_fp32_host[i] = dis(eng);
}
}
CudaMem x_fp32_device, y_fp32_device, out_fp32_device;
{ // step2 : compute fp32 result
auto x_fp32_ptr = x_fp32_device.mutable_data<float>(num);
auto y_fp32_ptr = y_fp32_device.mutable_data<float>(num);
auto out_fp32_ptr = out_fp32_device.mutable_data<float>(num);
x_fp32_device.MemcpyFromHost(
x_fp32_host.data(), num * sizeof(float), stream);
y_fp32_device.MemcpyFromHost(
y_fp32_host.data(), num * sizeof(float), stream);
test_fp32_cuda_kernel<<<grid, block, 0, stream>>>(
x_fp32_ptr, y_fp32_ptr, num, out_fp32_ptr);
}
CudaMem x_fp16_device, y_fp16_device, out_fp16_device;
CudaMem x_bf16_device, y_bf16_device, out_bf16_device;
{ // step3 : compute fp16/bf16 result
// step3.1 : compute fp16 result
auto x_fp16_ptr = x_fp16_device.mutable_data<float16>(num);
auto y_fp16_ptr = y_fp16_device.mutable_data<float16>(num);
auto out_fp16_ptr = out_fp16_device.mutable_data<float16>(num);
cast_fp32_to_fp16_cuda_kernel<<<grid, block, 0, stream>>>(
x_fp32_device.data<float>(), num, x_fp16_ptr);
cast_fp32_to_fp16_cuda_kernel<<<grid, block, 0, stream>>>(
y_fp32_device.data<float>(), num, y_fp16_ptr);
test_fp16_cuda_kernel<<<grid, block, 0, stream>>>(
x_fp16_ptr, y_fp16_ptr, num, out_fp16_ptr);
// step3.2 : compute bf16 result
auto x_bf16_ptr = x_bf16_device.mutable_data<bfloat16>(num);
auto y_bf16_ptr = y_bf16_device.mutable_data<bfloat16>(num);
auto out_bf16_ptr = out_bf16_device.mutable_data<bfloat16>(num);
cast_fp32_to_bf16_cuda_kernel<<<grid, block, 0, stream>>>(
x_fp32_device.data<float>(), num, x_bf16_ptr);
cast_fp32_to_bf16_cuda_kernel<<<grid, block, 0, stream>>>(
y_fp32_device.data<float>(), num, y_bf16_ptr);
test_bf16_cuda_kernel<<<grid, block, 0, stream>>>(
x_bf16_ptr, y_bf16_ptr, num, out_bf16_ptr);
}
CudaMem fp32res_fp16_device;
CudaMem fp32res_bf16_device;
{ // step4 : cast fp16/bf16 result to fp32 result
// step4.1 : cast fp16 result to fp32 result
auto fp32res_fp16_ptr = fp32res_fp16_device.mutable_data<float>(num);
cast_fp16_to_fp32_cuda_kernel<<<grid, block, 0, stream>>>(
out_fp16_device.data<float16>(), num, fp32res_fp16_ptr);
// step4.2 : cast bf16 result to fp32 result
auto fp32res_bf16_ptr = fp32res_bf16_device.mutable_data<float>(num);
cast_bf16_to_fp32_cuda_kernel<<<grid, block, 0, stream>>>(
out_bf16_device.data<bfloat16>(), num, fp32res_bf16_ptr);
}
std::vector<float> out_fp32_host(num), out_fp16_host(num), out_bf16_host(num);
{ // step5 : copy result from device to host
out_fp32_device.MemcpyToHost(
out_fp32_host.data(), num * sizeof(float), stream);
fp32res_fp16_device.MemcpyToHost(
out_fp16_host.data(), num * sizeof(float), stream);
fp32res_bf16_device.MemcpyToHost(
out_bf16_host.data(), num * sizeof(float), stream);
}
CUDA_CALL(cudaStreamSynchronize(stream));
for (int i = 0; i < num; ++i) {
ASSERT_NEAR(out_fp32_host[i], out_fp16_host[i], 1e-2f);
ASSERT_NEAR(out_fp32_host[i], out_bf16_host[i], 1e-1f);
}
CUDA_CALL(cudaStreamDestroy(stream));
}
} // namespace common
} // namespace cinn
@@ -0,0 +1,104 @@
// 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 <glog/logging.h>
#include <gtest/gtest.h>
#include <random>
#include <vector>
#include "paddle/cinn/common/bfloat16.h"
#include "paddle/cinn/common/float16.h"
namespace cinn {
namespace common {
std::vector<float16> test_fp16_host_kernel(const float16* x,
const float16* y,
const int num) {
std::vector<float16> out(num);
for (int idx = 0; idx < num; ++idx) {
float16 x_i = x[idx], y_i = y[idx];
x_i += float16(1);
out[idx] = (x_i + y_i) * (x_i - y_i);
}
return out;
}
std::vector<bfloat16> test_bf16_host_kernel(const bfloat16* x,
const bfloat16* y,
const int num) {
std::vector<bfloat16> out(num);
for (int idx = 0; idx < num; ++idx) {
bfloat16 x_i = x[idx], y_i = y[idx];
x_i += bfloat16(1);
out[idx] = (x_i + y_i) * (x_i - y_i);
}
return out;
}
std::vector<float> test_fp32_host_kernel(const float* x,
const float* y,
const int num) {
std::vector<float> out(num);
for (int idx = 0; idx < num; ++idx) {
float x_i = x[idx], y_i = y[idx];
x_i += 1.0f;
out[idx] = (x_i + y_i) * (x_i - y_i);
}
return out;
}
TEST(FP16_BF16, basic_host) {
int num = 2048;
// int num = 2;
std::vector<float16> x_fp16(num), y_fp16(num);
std::vector<bfloat16> x_bf16(num), y_bf16(num);
std::vector<float> x_fp32(num), y_fp32(num);
std::random_device r;
std::default_random_engine eng(r());
std::uniform_real_distribution<float> dis(1e-5f, 1.0f);
for (int i = 0; i < num; ++i) {
x_fp16[i] = x_fp32[i] = dis(eng);
y_fp16[i] = y_fp32[i] = dis(eng);
x_fp16[i] = x_fp32[i];
y_fp16[i] = y_fp32[i];
x_bf16[i] = x_fp32[i];
y_bf16[i] = y_fp32[i];
}
auto out_fp16 = test_fp16_host_kernel(x_fp16.data(), y_fp16.data(), num);
ASSERT_EQ(out_fp16.size(), num);
auto out_bf16 = test_bf16_host_kernel(x_bf16.data(), y_bf16.data(), num);
ASSERT_EQ(out_bf16.size(), num);
auto out_fp32 = test_fp32_host_kernel(x_fp32.data(), y_fp32.data(), num);
ASSERT_EQ(out_fp32.size(), num);
for (int i = 0; i < num; ++i) {
ASSERT_NEAR(static_cast<float>(out_fp16[i]), out_fp32[i], 1e-2f);
ASSERT_NEAR(static_cast<float>(out_bf16[i]), out_fp32[i], 1e-1f);
}
}
} // namespace common
} // namespace cinn
+341
View File
@@ -0,0 +1,341 @@
// Copyright (c) 2023 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/common/integer_set.h"
#include <glog/logging.h>
#include <gtest/gtest.h>
#include "paddle/cinn/ir/op/ir_operators.h"
namespace cinn {
namespace common {
class TestSymbolicExprAnalyzer : public ::testing::Test {
public:
void SetUp() override {
// Var is [lower_bound, upper_bound)
i = ir::Var(ir::Expr(0), ir::Expr(7), "i"); // i ∈ [0, 7)
j = ir::Var(ir::Expr(0), ir::Expr(15), "j"); // j ∈ [0, 15)
// CasInterval is [lower_bound, upper_bound]
var_intervals = {
{"i", CasInterval(i->lower_bound, i->upper_bound - 1)}, // i ∈ [0, 6]
{"j", CasInterval(j->lower_bound, j->upper_bound - 1)}, // j ∈ [0, 14]
};
}
ir::Var i;
ir::Var j;
cas_intervals_t var_intervals;
SymbolicExprAnalyzer analyzer{var_intervals};
};
TEST_F(TestSymbolicExprAnalyzer, bound) {
ir::Expr e1 = i + j;
EXPECT_EQ(analyzer.LowerBound(e1), ir::Expr(0));
EXPECT_EQ(analyzer.UpperBound(e1), ir::Expr(20)); // 6 + 14 = 20
ir::Expr e2 = 16 * i + j;
EXPECT_EQ(analyzer.LowerBound(e2), ir::Expr(0));
EXPECT_EQ(analyzer.UpperBound(e2), ir::Expr(110)); // 16 * 6 + 14 = 110
ir::Expr e3 = 16 * i + j + 1;
EXPECT_EQ(analyzer.LowerBound(e3), ir::Expr(1));
EXPECT_EQ(analyzer.UpperBound(e3), ir::Expr(111)); // 16 * 6 + 15 = 111
ir::Expr e4 = (16 * i + j) / 16;
EXPECT_EQ(analyzer.LowerBound(e4), ir::Expr(0));
EXPECT_EQ(analyzer.UpperBound(e4), ir::Expr(6)); // 110 / 16 = 6
ir::Expr e5 = (16 * i + j) % 16;
EXPECT_EQ(analyzer.LowerBound(e5), ir::Expr(0));
EXPECT_EQ(analyzer.UpperBound(e5), ir::Expr(14)); // 110 % 16
ir::Expr e6 = i - j;
EXPECT_EQ(analyzer.LowerBound(e6), ir::Expr(-14)); // 0 - 14
EXPECT_EQ(analyzer.UpperBound(e6), ir::Expr(6)); // 6 - 0
ir::Expr e7 = 0 - i - j;
EXPECT_EQ(analyzer.LowerBound(e7), ir::Expr(-20)); // 0 - 6 - 14
EXPECT_EQ(analyzer.UpperBound(e7), ir::Expr(0)); // 0 - 0 - 0
ir::Expr e8 = -1 * i - j;
EXPECT_EQ(analyzer.LowerBound(e8), ir::Expr(-20)); // -1 * 6 - 14
EXPECT_EQ(analyzer.UpperBound(e8), ir::Expr(0)); // -1 * 0 - 0
}
TEST_F(TestSymbolicExprAnalyzer, compare) {
// case 1
ir::Expr e1 = 4 * i + 2 * j;
ir::Expr e2 = 2 * i + j;
EXPECT_TRUE(analyzer.ProveEQ(e1, e1).value() &&
analyzer.Prove(ir::EQ::Make(e1, e1)).value());
EXPECT_FALSE(analyzer.ProveEQ(e1, e2).has_value() ||
analyzer.Prove(ir::EQ::Make(e1, e2)).has_value());
EXPECT_FALSE(analyzer.ProveNE(e1, e1).value() &&
analyzer.Prove(ir::NE::Make(e1, e1)).value());
EXPECT_FALSE(analyzer.ProveNE(e1, e2).has_value() ||
analyzer.Prove(ir::NE::Make(e1, e2)).has_value());
EXPECT_TRUE(analyzer.ProveGE(e1, e2).value() &&
analyzer.Prove(e1 >= e2).value());
EXPECT_FALSE(analyzer.ProveGE(e2, e1).has_value() ||
analyzer.Prove(e2 >= e1).has_value());
EXPECT_TRUE(analyzer.ProveLE(e2, e1).value() &&
analyzer.Prove(e2 <= e1).value());
EXPECT_FALSE(analyzer.ProveLE(e1, e2).has_value() ||
analyzer.Prove(e1 <= e2).has_value());
EXPECT_FALSE(analyzer.ProveGT(e1, e2).has_value() ||
analyzer.Prove(e1 > e2).has_value());
EXPECT_FALSE(analyzer.ProveGT(e2, e1).value() &&
analyzer.Prove(e2 > e1).value());
EXPECT_FALSE(analyzer.ProveLT(e2, e1).has_value() ||
analyzer.Prove(e2 < e1).has_value());
EXPECT_FALSE(analyzer.ProveLT(e1, e2).value() &&
analyzer.Prove(e1 < e2).value());
// case 2
ir::Expr e3 = i + j + 1;
ir::Expr e4 = i + j;
EXPECT_TRUE(analyzer.ProveEQ(e3, e3).value() &&
analyzer.Prove(ir::EQ::Make(e3, e3)).value());
EXPECT_FALSE(analyzer.ProveEQ(e3, e4).value() &&
analyzer.Prove(ir::EQ::Make(e3, e4)).value());
EXPECT_TRUE(analyzer.ProveNE(e3, e4).value() &&
analyzer.Prove(ir::NE::Make(e3, e4)).value());
EXPECT_FALSE(analyzer.ProveNE(e4, e4).value() &&
analyzer.Prove(ir::NE::Make(e4, e4)).value());
EXPECT_TRUE(analyzer.ProveGE(e3, e4).value() &&
analyzer.Prove(e3 >= e4).value());
EXPECT_FALSE(analyzer.ProveGE(e4, e3).value() &&
analyzer.Prove(e4 >= e3).value());
EXPECT_TRUE(analyzer.ProveLE(e4, e3).value() &&
analyzer.Prove(e4 <= e3).value());
EXPECT_FALSE(analyzer.ProveLE(e3, e4).value() &&
analyzer.Prove(e3 <= e4).value());
EXPECT_TRUE(analyzer.ProveGT(e3, e4).value() &&
analyzer.Prove(e3 > e4).value());
EXPECT_FALSE(analyzer.ProveGT(e4, e3).value() &&
analyzer.Prove(e4 > e3).value());
EXPECT_TRUE(analyzer.ProveLT(e4, e3).value() &&
analyzer.Prove(e4 < e3).value());
EXPECT_FALSE(analyzer.ProveLT(e3, e4).value() &&
analyzer.Prove(e3 < e4).value());
}
TEST_F(TestSymbolicExprAnalyzer, Divisible) {
auto x = ir::Var(ir::Expr(1), ir::Expr(7), "x");
auto y = ir::Var(ir::Expr(1), ir::Expr(15), "y");
auto S = ir::Var(ir::Expr(16), ir::Expr(256), "S");
cas_intervals_t divisible_var_intervals = {
{"x", CasInterval(x->lower_bound, x->upper_bound - ir::Expr(1))},
{"y", CasInterval(y->lower_bound, y->upper_bound - ir::Expr(1))},
{"S", CasInterval(S->lower_bound, S->upper_bound - ir::Expr(1))},
};
SymbolicExprAnalyzer divisible_analyzer{divisible_var_intervals};
// case 1
ir::Expr e1 = 4 * x + 2 * y * x;
ir::Expr e2 = x;
ir::Expr e3 = y;
EXPECT_TRUE(divisible_analyzer.ProveDivisible(e1, e2).value_or(false));
EXPECT_FALSE(divisible_analyzer.ProveDivisible(e1, e3).value_or(false));
// case 2
ir::Expr e4 = y + y * x + 4 * y - x * y;
EXPECT_TRUE(divisible_analyzer.ProveDivisible(e4, e3).value_or(false));
EXPECT_FALSE(divisible_analyzer.ProveDivisible(e4, e2).value_or(false));
// case 3
ir::Expr e5 = x / y + x + y;
EXPECT_FALSE(divisible_analyzer.ProveDivisible(e5, e3).value_or(false));
EXPECT_FALSE(divisible_analyzer.ProveDivisible(e5, e2).value_or(false));
// case 4
ir::Expr e6 = S * x / 4 + x * y;
EXPECT_FALSE(divisible_analyzer.ProveDivisible(e6, e2).value_or(false));
EXPECT_FALSE(divisible_analyzer.ProveDivisible(e6, e3).value_or(false));
ir::Expr e7 = 16 * x / 4 + x * y;
EXPECT_TRUE(divisible_analyzer.ProveDivisible(e7, e2).value_or(false));
EXPECT_FALSE(divisible_analyzer.ProveDivisible(e7, e3).value_or(false));
}
TEST(SingleIntervalIntSet, constant) {
SingleIntervalIntSet empty_set(ir::Expr(0), ir::Expr(-1));
SingleIntervalIntSet all_set(SymbolicExprLimit::negative_inf,
SymbolicExprLimit::positive_inf);
SingleIntervalIntSet single_point(ir::Expr(0), ir::Expr(0));
SingleIntervalIntSet interval_0_2_set(ir::Expr(0), ir::Expr(2));
SingleIntervalIntSet interval_0_4_set(ir::Expr(0), ir::Expr(4));
SingleIntervalIntSet interval_2_6_set(ir::Expr(2), ir::Expr(6));
SingleIntervalIntSet interval_8_9_set(ir::Expr(8), ir::Expr(9));
EXPECT_TRUE(empty_set.ProveEmpty().value());
EXPECT_FALSE(empty_set.ProveAll().value());
EXPECT_FALSE(all_set.ProveEmpty().value());
EXPECT_TRUE(all_set.ProveAll().value());
EXPECT_TRUE(single_point.ProvePoint().value());
EXPECT_FALSE(interval_0_2_set.ProvePoint().value());
EXPECT_TRUE(interval_0_2_set.ProveSubSet(interval_0_4_set).value());
EXPECT_FALSE(interval_0_4_set.ProveSubSet(interval_0_2_set).value());
EXPECT_FALSE(interval_0_2_set.ProveSuperSet(interval_0_4_set).value());
EXPECT_TRUE(interval_0_4_set.ProveSuperSet(interval_0_2_set).value());
EXPECT_TRUE(ProveEQ(interval_0_2_set, interval_0_2_set).value());
EXPECT_FALSE(ProveEQ(interval_0_2_set, interval_0_4_set).value());
SingleIntervalIntSet union_0_6_set =
ProvedUnion(interval_0_2_set, interval_2_6_set).value();
EXPECT_EQ(union_0_6_set.Min(), ir::Expr(0));
EXPECT_EQ(union_0_6_set.Max(), ir::Expr(6));
union_0_6_set = ProvedUnion(interval_2_6_set, interval_0_2_set).value();
EXPECT_EQ(union_0_6_set.Min(), ir::Expr(0));
EXPECT_EQ(union_0_6_set.Max(), ir::Expr(6));
SingleIntervalIntSet union_0_4_set =
ProvedUnion(interval_0_2_set, interval_0_4_set).value();
EXPECT_EQ(union_0_4_set.Min(), ir::Expr(0));
EXPECT_EQ(union_0_4_set.Max(), ir::Expr(4));
union_0_4_set = ProvedUnion(interval_0_4_set, interval_0_2_set).value();
EXPECT_EQ(union_0_4_set.Min(), ir::Expr(0));
EXPECT_EQ(union_0_4_set.Max(), ir::Expr(4));
SingleIntervalIntSet union_0_9_set =
ProvedUnion(interval_0_4_set, interval_8_9_set).value();
EXPECT_EQ(union_0_9_set.Min(), ir::Expr(0));
EXPECT_EQ(union_0_9_set.Max(), ir::Expr(9));
union_0_9_set = ProvedUnion(interval_8_9_set, interval_0_4_set).value();
EXPECT_EQ(union_0_9_set.Min(), ir::Expr(0));
EXPECT_EQ(union_0_9_set.Max(), ir::Expr(9));
SingleIntervalIntSet intersect_0_2_set =
ProvedIntersect(interval_0_2_set, interval_0_4_set).value();
EXPECT_EQ(intersect_0_2_set.Min(), ir::Expr(0));
EXPECT_EQ(intersect_0_2_set.Max(), ir::Expr(2));
intersect_0_2_set =
ProvedIntersect(interval_0_4_set, interval_0_2_set).value();
EXPECT_EQ(intersect_0_2_set.Min(), ir::Expr(0));
EXPECT_EQ(intersect_0_2_set.Max(), ir::Expr(2));
SingleIntervalIntSet intersect_2_2_set =
ProvedIntersect(interval_0_2_set, interval_2_6_set).value();
EXPECT_EQ(intersect_2_2_set.Min(), ir::Expr(2));
EXPECT_EQ(intersect_2_2_set.Max(), ir::Expr(2));
intersect_2_2_set =
ProvedIntersect(interval_2_6_set, interval_0_2_set).value();
EXPECT_EQ(intersect_2_2_set.Min(), ir::Expr(2));
EXPECT_EQ(intersect_2_2_set.Max(), ir::Expr(2));
SingleIntervalIntSet intersect_empty_set =
ProvedIntersect(interval_0_4_set, interval_8_9_set).value();
EXPECT_TRUE(intersect_empty_set.ProveEmpty().value());
intersect_empty_set =
ProvedIntersect(interval_8_9_set, interval_0_4_set).value();
EXPECT_TRUE(intersect_empty_set.ProveEmpty().value());
}
TEST(SingleIntervalIntSet, case_0) {
ir::Var S0 = ir::Var(ir::Expr(0), ir::Expr(7), "S0");
ir::Expr e1 = S0 * 16;
ir::Expr e2 = S0 * 16 + 7;
ir::Expr e3 = S0 * 16 + 15;
SingleIntervalIntSet empty_set(e2, e1);
SingleIntervalIntSet single_point(e3, e3);
SingleIntervalIntSet set_0(e1, e2);
SingleIntervalIntSet set_1(e1, e3);
EXPECT_TRUE(empty_set.ProveEmpty().value());
EXPECT_FALSE(empty_set.ProveAll().value());
EXPECT_TRUE(single_point.ProvePoint().value());
EXPECT_FALSE(set_0.ProvePoint().value());
EXPECT_TRUE(ProveEQ(set_0, set_0).value());
EXPECT_FALSE(ProveEQ(set_0, set_1).value());
EXPECT_TRUE(set_0.ProveSubSet(set_1).value());
EXPECT_FALSE(set_1.ProveSubSet(set_0).value());
EXPECT_FALSE(set_0.ProveSuperSet(set_1).value());
EXPECT_TRUE(set_1.ProveSuperSet(set_0).value());
EXPECT_TRUE(ProveEQ(ProvedUnion(set_0, set_1).value(), set_1).value());
EXPECT_TRUE(ProveEQ(ProvedIntersect(set_0, set_1).value(), set_0).value());
EXPECT_TRUE(ProveEQ(ProvedUnion(set_1, single_point).value(), set_1).value());
EXPECT_TRUE(
ProveEQ(ProvedIntersect(set_1, single_point).value(), single_point)
.value());
EXPECT_TRUE(ProveEQ(ProvedUnion(set_0, empty_set).value(), set_0).value());
EXPECT_TRUE(
ProveEQ(ProvedIntersect(set_0, empty_set).value(), empty_set).value());
EXPECT_TRUE(ProveEQ(ProvedUnion(set_0, single_point).value(), set_1).value());
EXPECT_TRUE(ProvedIntersect(set_0, single_point).value().ProveEmpty());
}
TEST(SingleIntervalIntSet, case_1) {
ir::Var S0 = ir::Var(ir::Expr(0), ir::Expr(7), "S0");
ir::Var S1 = ir::Var(ir::Expr(0), ir::Expr(15), "S1");
ir::Expr e1 = S0 * 16;
ir::Expr e2 = S0 * 16 + S1;
ir::Expr e3 = S0 * 16 + S1 * 2 + 1;
SingleIntervalIntSet empty_set(e3, e1);
SingleIntervalIntSet single_point(e3, e3);
SingleIntervalIntSet set_0(e1, e2);
SingleIntervalIntSet set_1(e1, e3);
EXPECT_TRUE(empty_set.ProveEmpty().value());
EXPECT_FALSE(empty_set.ProveAll().value());
EXPECT_TRUE(single_point.ProvePoint().value());
EXPECT_FALSE(set_0.ProvePoint().has_value());
EXPECT_TRUE(ProveEQ(set_0, set_0).value());
EXPECT_FALSE(ProveEQ(set_0, set_1).value());
EXPECT_TRUE(set_0.ProveSubSet(set_1).value());
EXPECT_FALSE(set_1.ProveSubSet(set_0).value());
EXPECT_FALSE(set_0.ProveSuperSet(set_1).value());
EXPECT_TRUE(set_1.ProveSuperSet(set_0).value());
EXPECT_TRUE(ProveEQ(ProvedUnion(set_0, set_1).value(), set_1).value());
EXPECT_TRUE(ProveEQ(ProvedIntersect(set_0, set_1).value(), set_0).value());
EXPECT_TRUE(ProveEQ(ProvedUnion(set_1, single_point).value(), set_1).value());
EXPECT_TRUE(
ProveEQ(ProvedIntersect(set_1, single_point).value(), single_point)
.value());
EXPECT_TRUE(ProveEQ(ProvedUnion(set_0, empty_set).value(), set_0).value());
EXPECT_TRUE(
ProveEQ(ProvedIntersect(set_0, empty_set).value(), empty_set).value());
EXPECT_TRUE(ProveEQ(ProvedUnion(set_0, single_point).value(), set_1).value());
EXPECT_TRUE(
ProvedIntersect(set_0, single_point).value().ProveEmpty().value());
}
TEST(SingleIntervalIntSet, case_2) {
ir::Var S = ir::Var(ir::Expr(0), ir::Expr(1), "S"); // S ∈ [0, 1)
SingleIntervalIntSet set_0{S, S + Expr(1)}; // [0, 1]
SingleIntervalIntSet set_1{Expr(0), Expr(1)}; // [0, 1]
SingleIntervalIntSet set_2{Expr(0), Expr(2)}; // [0, 2]
EXPECT_TRUE(ProveEQ(set_0, set_1).value());
EXPECT_FALSE(ProveEQ(set_0, set_2).value());
EXPECT_TRUE(set_0.ProveSubSet(set_2).value());
EXPECT_TRUE(set_2.ProveSuperSet(set_0).value());
}
} // namespace common
} // namespace cinn
@@ -0,0 +1,38 @@
// Copyright (c) 2023 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/common/is_reachable_predicator.h"
#include <glog/logging.h>
#include <gtest/gtest.h>
namespace cinn {
namespace common {
TEST(IsReachablePredicator, simple) {
IsReachablePredicator<int> IsReachable(
// Get min depth
[](int x) { return std::abs(x); },
// Get max depth
[](int x) { return std::abs(x); },
// visit next node
[](int x, const std::function<void(int)>& Handler) {
Handler(x + (x / std::abs(x)));
});
EXPECT_TRUE(IsReachable(33, 99, [](int) {}));
EXPECT_FALSE(IsReachable(33, -99, [](int) {}));
}
} // namespace common
} // namespace cinn
+55
View File
@@ -0,0 +1,55 @@
// 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/common/shared.h"
#include <glog/logging.h>
#include <gtest/gtest.h>
#include "paddle/cinn/common/object.h"
namespace cinn {
namespace common {
struct A : public Object {
const char *type_info() const override { return "A"; }
Shared<A> other;
};
class B : public Object {};
TEST(Shared, test) {
Shared<A> a_ref(make_shared<A>());
ASSERT_EQ(ref_count(a_ref.get()).val(), 1);
{ // local copy
Shared<A> b = a_ref;
EXPECT_EQ(ref_count(a_ref.get()).val(), 2);
ASSERT_EQ(ref_count(b.get()).val(), 2);
}
ASSERT_EQ(ref_count(a_ref.get()).val(), 1);
}
TEST(Shared, cycle_share) {
{
Shared<A> a_ref(make_shared<A>());
a_ref->other = a_ref;
ASSERT_EQ(a_ref->__ref_count__.val(), 2);
}
}
} // namespace common
} // namespace cinn
+51
View File
@@ -0,0 +1,51 @@
// Copyright (c) 2023 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/common/topo_walker.h"
#include <glog/logging.h>
#include <gtest/gtest.h>
namespace cinn {
namespace common {
TEST(TopoWalker, simple) {
std::vector<std::pair<int, int>> edges{
{0, 3}, {1, 2}, {1, 3}, {2, 3}, {3, 4}};
TopoWalker<int> visitor(
[&](int node, const std::function<void(int)>& NodeHandler) {
for (const auto& pair : edges) {
if (pair.second == node) {
NodeHandler(pair.first);
}
}
},
[&](int node, const std::function<void(int)>& NodeHandler) {
for (const auto& pair : edges) {
if (pair.first == node) {
NodeHandler(pair.second);
}
}
});
std::vector<int> sources{0, 1};
std::vector<int> outputs;
visitor(sources.begin(), sources.end(), [&](int node) {
outputs.push_back(node);
});
std::vector<int> expected{0, 1, 2, 3, 4};
EXPECT_TRUE((outputs == expected));
}
} // namespace common
} // namespace cinn
+31
View File
@@ -0,0 +1,31 @@
// 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/common/type.h"
#include <gtest/gtest.h>
namespace cinn::common {
TEST(Type, basic) {
LOG(INFO) << I32();
auto i32 = I32();
LOG(INFO) << I32();
LOG(INFO) << F32();
LOG(INFO) << type_of<float>();
}
} // namespace cinn::common