| //===- IslTest.cpp ----------------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "polly/Support/GICHelper.h" |
| #include "polly/Support/ISLOperators.h" |
| #include "polly/Support/ISLTools.h" |
| #include "gtest/gtest.h" |
| #include "isl/stream.h" |
| #include "isl/val.h" |
| |
| using namespace llvm; |
| using namespace polly; |
| |
| static isl::space parseSpace(isl_ctx *Ctx, const char *Str) { |
| isl_stream *Stream = isl_stream_new_str(Ctx, Str); |
| auto Obj = isl_stream_read_obj(Stream); |
| |
| isl::space Result; |
| if (Obj.type == isl_obj_set) |
| Result = isl::manage(isl_set_get_space(static_cast<isl_set *>(Obj.v))); |
| else if (Obj.type == isl_obj_map) |
| Result = isl::manage(isl_map_get_space(static_cast<isl_map *>(Obj.v))); |
| |
| isl_stream_free(Stream); |
| if (Obj.type) |
| Obj.type->free(Obj.v); |
| return Result; |
| } |
| |
| #define SPACE(Str) parseSpace(Ctx.get(), Str) |
| |
| #define SET(Str) isl::set(Ctx.get(), Str) |
| #define MAP(Str) isl::map(Ctx.get(), Str) |
| |
| #define USET(Str) isl::union_set(Ctx.get(), Str) |
| #define UMAP(Str) isl::union_map(Ctx.get(), Str) |
| |
| namespace isl { |
| inline namespace noexceptions { |
| |
| static bool operator==(const isl::space &LHS, const isl::space &RHS) { |
| return bool(LHS.is_equal(RHS)); |
| } |
| |
| static bool operator==(const isl::set &LHS, const isl::set &RHS) { |
| return bool(LHS.is_equal(RHS)); |
| } |
| |
| static bool operator==(const isl::map &LHS, const isl::map &RHS) { |
| return bool(LHS.is_equal(RHS)); |
| } |
| |
| static bool operator==(const isl::union_set &LHS, const isl::union_set &RHS) { |
| return bool(LHS.is_equal(RHS)); |
| } |
| |
| static bool operator==(const isl::union_map &LHS, const isl::union_map &RHS) { |
| return bool(LHS.is_equal(RHS)); |
| } |
| |
| static bool operator==(const isl::val &LHS, const isl::val &RHS) { |
| return bool(LHS.eq(RHS)); |
| } |
| |
| static bool operator==(const isl::pw_aff &LHS, const isl::pw_aff &RHS) { |
| return bool(LHS.is_equal(RHS)); |
| } |
| } // namespace noexceptions |
| } // namespace isl |
| |
| namespace { |
| |
| TEST(Isl, APIntToIslVal) { |
| isl_ctx *IslCtx = isl_ctx_alloc(); |
| |
| { |
| APInt APZero(1, 0, true); |
| auto IslZero = valFromAPInt(IslCtx, APZero, true); |
| EXPECT_TRUE(IslZero.is_zero()); |
| } |
| |
| { |
| APInt APNOne(1, -1, true); |
| auto IslNOne = valFromAPInt(IslCtx, APNOne, true); |
| EXPECT_TRUE(IslNOne.is_negone()); |
| } |
| |
| { |
| APInt APZero(1, 0, false); |
| auto IslZero = valFromAPInt(IslCtx, APZero, false); |
| EXPECT_TRUE(IslZero.is_zero()); |
| } |
| |
| { |
| APInt APOne(1, 1, false); |
| auto IslOne = valFromAPInt(IslCtx, APOne, false); |
| EXPECT_TRUE(IslOne.is_one()); |
| } |
| |
| { |
| APInt APNTwo(2, -2, true); |
| auto IslNTwo = valFromAPInt(IslCtx, APNTwo, true); |
| auto IslNTwoCmp = isl::val(IslCtx, -2); |
| EXPECT_EQ(IslNTwo, IslNTwoCmp); |
| } |
| |
| { |
| APInt APNOne(32, -1, true); |
| auto IslNOne = valFromAPInt(IslCtx, APNOne, true); |
| EXPECT_TRUE(IslNOne.is_negone()); |
| } |
| |
| { |
| APInt APZero(32, 0, false); |
| auto IslZero = valFromAPInt(IslCtx, APZero, false); |
| EXPECT_TRUE(IslZero.is_zero()); |
| } |
| |
| { |
| APInt APOne(32, 1, false); |
| auto IslOne = valFromAPInt(IslCtx, APOne, false); |
| EXPECT_TRUE(IslOne.is_one()); |
| } |
| |
| { |
| APInt APTwo(32, 2, false); |
| auto IslTwo = valFromAPInt(IslCtx, APTwo, false); |
| EXPECT_EQ(0, IslTwo.cmp_si(2)); |
| } |
| |
| { |
| APInt APNOne(32, (1ull << 32) - 1, false); |
| auto IslNOne = valFromAPInt(IslCtx, APNOne, false); |
| auto IslRef = isl::val(IslCtx, 32).pow2().sub(1); |
| EXPECT_EQ(IslNOne, IslRef); |
| } |
| |
| { |
| APInt APLarge(130, 2, false); |
| APLarge = APLarge.shl(70); |
| auto IslLarge = valFromAPInt(IslCtx, APLarge, false); |
| auto IslRef = isl::val(IslCtx, 71); |
| IslRef = IslRef.pow2(); |
| EXPECT_EQ(IslLarge, IslRef); |
| } |
| |
| isl_ctx_free(IslCtx); |
| } |
| |
| TEST(Isl, IslValToAPInt) { |
| isl_ctx *IslCtx = isl_ctx_alloc(); |
| |
| { |
| auto IslNOne = isl::val(IslCtx, -1); |
| auto APNOne = APIntFromVal(IslNOne); |
| // Compare with the two's complement of -1 in a 1-bit integer. |
| EXPECT_EQ(1, APNOne); |
| EXPECT_EQ(1u, APNOne.getBitWidth()); |
| } |
| |
| { |
| auto IslNTwo = isl::val(IslCtx, -2); |
| auto APNTwo = APIntFromVal(IslNTwo); |
| // Compare with the two's complement of -2 in a 2-bit integer. |
| EXPECT_EQ(2, APNTwo); |
| EXPECT_EQ(2u, APNTwo.getBitWidth()); |
| } |
| |
| { |
| auto IslNThree = isl::val(IslCtx, -3); |
| auto APNThree = APIntFromVal(IslNThree); |
| // Compare with the two's complement of -3 in a 3-bit integer. |
| EXPECT_EQ(5, APNThree); |
| EXPECT_EQ(3u, APNThree.getBitWidth()); |
| } |
| |
| { |
| auto IslNFour = isl::val(IslCtx, -4); |
| auto APNFour = APIntFromVal(IslNFour); |
| // Compare with the two's complement of -4 in a 3-bit integer. |
| EXPECT_EQ(4, APNFour); |
| EXPECT_EQ(3u, APNFour.getBitWidth()); |
| } |
| |
| { |
| auto IslZero = isl::val(IslCtx, 0); |
| auto APZero = APIntFromVal(IslZero); |
| EXPECT_EQ(0, APZero); |
| EXPECT_EQ(1u, APZero.getBitWidth()); |
| } |
| |
| { |
| auto IslOne = isl::val(IslCtx, 1); |
| auto APOne = APIntFromVal(IslOne); |
| EXPECT_EQ(1, APOne); |
| EXPECT_EQ(2u, APOne.getBitWidth()); |
| } |
| |
| { |
| auto IslTwo = isl::val(IslCtx, 2); |
| auto APTwo = APIntFromVal(IslTwo); |
| EXPECT_EQ(2, APTwo); |
| EXPECT_EQ(3u, APTwo.getBitWidth()); |
| } |
| |
| { |
| auto IslThree = isl::val(IslCtx, 3); |
| auto APThree = APIntFromVal(IslThree); |
| EXPECT_EQ(3, APThree); |
| EXPECT_EQ(3u, APThree.getBitWidth()); |
| } |
| |
| { |
| auto IslFour = isl::val(IslCtx, 4); |
| auto APFour = APIntFromVal(IslFour); |
| EXPECT_EQ(4, APFour); |
| EXPECT_EQ(4u, APFour.getBitWidth()); |
| } |
| |
| { |
| auto IslNOne = isl::val(IslCtx, 32).pow2().sub(1); |
| auto APNOne = APIntFromVal(IslNOne); |
| EXPECT_EQ((1ull << 32) - 1, APNOne); |
| EXPECT_EQ(33u, APNOne.getBitWidth()); |
| } |
| |
| { |
| auto IslLargeNum = isl::val(IslCtx, 60); |
| IslLargeNum = IslLargeNum.pow2(); |
| IslLargeNum = IslLargeNum.sub(1); |
| auto APLargeNum = APIntFromVal(IslLargeNum); |
| EXPECT_EQ((1ull << 60) - 1, APLargeNum); |
| EXPECT_EQ(61u, APLargeNum.getBitWidth()); |
| } |
| |
| { |
| auto IslExp = isl::val(IslCtx, 500); |
| auto IslLargePow2 = IslExp.pow2(); |
| auto APLargePow2 = APIntFromVal(IslLargePow2); |
| EXPECT_TRUE(APLargePow2.isPowerOf2()); |
| EXPECT_EQ(502u, APLargePow2.getBitWidth()); |
| EXPECT_EQ(502u, APLargePow2.getMinSignedBits()); |
| } |
| |
| { |
| auto IslExp = isl::val(IslCtx, 500); |
| auto IslLargeNPow2 = IslExp.pow2().neg(); |
| auto APLargeNPow2 = APIntFromVal(IslLargeNPow2); |
| EXPECT_EQ(501u, APLargeNPow2.getBitWidth()); |
| EXPECT_EQ(501u, APLargeNPow2.getMinSignedBits()); |
| EXPECT_EQ(500, (-APLargeNPow2).exactLogBase2()); |
| } |
| |
| { |
| auto IslExp = isl::val(IslCtx, 512); |
| auto IslLargePow2 = IslExp.pow2(); |
| auto APLargePow2 = APIntFromVal(IslLargePow2); |
| EXPECT_TRUE(APLargePow2.isPowerOf2()); |
| EXPECT_EQ(514u, APLargePow2.getBitWidth()); |
| EXPECT_EQ(514u, APLargePow2.getMinSignedBits()); |
| } |
| |
| { |
| auto IslExp = isl::val(IslCtx, 512); |
| auto IslLargeNPow2 = IslExp.pow2().neg(); |
| auto APLargeNPow2 = APIntFromVal(IslLargeNPow2); |
| EXPECT_EQ(513u, APLargeNPow2.getBitWidth()); |
| EXPECT_EQ(513u, APLargeNPow2.getMinSignedBits()); |
| EXPECT_EQ(512, (-APLargeNPow2).exactLogBase2()); |
| } |
| |
| isl_ctx_free(IslCtx); |
| } |
| |
| TEST(Isl, Operators) { |
| std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> IslCtx(isl_ctx_alloc(), |
| &isl_ctx_free); |
| |
| isl::val ValOne = isl::val(IslCtx.get(), 1); |
| isl::val ValTwo = isl::val(IslCtx.get(), 2); |
| isl::val ValThree = isl::val(IslCtx.get(), 3); |
| isl::val ValFour = isl::val(IslCtx.get(), 4); |
| isl::val ValNegOne = isl::val(IslCtx.get(), -1); |
| isl::val ValNegTwo = isl::val(IslCtx.get(), -2); |
| isl::val ValNegThree = isl::val(IslCtx.get(), -3); |
| isl::val ValNegFour = isl::val(IslCtx.get(), -4); |
| |
| isl::space Space = isl::space(IslCtx.get(), 0, 0); |
| isl::local_space LS = isl::local_space(Space); |
| |
| isl::pw_aff AffOne = isl::aff(LS, ValOne); |
| isl::pw_aff AffTwo = isl::aff(LS, ValTwo); |
| isl::pw_aff AffThree = isl::aff(LS, ValThree); |
| isl::pw_aff AffFour = isl::aff(LS, ValFour); |
| isl::pw_aff AffNegOne = isl::aff(LS, ValNegOne); |
| isl::pw_aff AffNegTwo = isl::aff(LS, ValNegTwo); |
| isl::pw_aff AffNegThree = isl::aff(LS, ValNegThree); |
| isl::pw_aff AffNegFour = isl::aff(LS, ValNegFour); |
| |
| // Addition |
| { |
| EXPECT_EQ(AffOne + AffOne, AffTwo); |
| EXPECT_EQ(AffOne + 1, AffTwo); |
| EXPECT_EQ(1 + AffOne, AffTwo); |
| EXPECT_EQ(AffOne + ValOne, AffTwo); |
| EXPECT_EQ(ValOne + AffOne, AffTwo); |
| } |
| |
| // Multiplication |
| { |
| EXPECT_EQ(AffTwo * AffTwo, AffFour); |
| EXPECT_EQ(AffTwo * 2, AffFour); |
| EXPECT_EQ(2 * AffTwo, AffFour); |
| EXPECT_EQ(AffTwo * ValTwo, AffFour); |
| EXPECT_EQ(ValTwo * AffTwo, AffFour); |
| } |
| |
| // Subtraction |
| { |
| EXPECT_EQ(AffTwo - AffOne, AffOne); |
| EXPECT_EQ(AffTwo - 1, AffOne); |
| EXPECT_EQ(2 - AffOne, AffOne); |
| EXPECT_EQ(AffTwo - ValOne, AffOne); |
| EXPECT_EQ(ValTwo - AffOne, AffOne); |
| } |
| |
| // Division |
| { |
| EXPECT_EQ(AffFour / AffTwo, AffTwo); |
| EXPECT_EQ(AffFour / 2, AffTwo); |
| EXPECT_EQ(4 / AffTwo, AffTwo); |
| EXPECT_EQ(AffFour / ValTwo, AffTwo); |
| EXPECT_EQ(AffFour / 2, AffTwo); |
| |
| // Dividend is negative (should be rounded towards zero) |
| EXPECT_EQ(AffNegFour / AffThree, AffNegOne); |
| EXPECT_EQ(AffNegFour / 3, AffNegOne); |
| EXPECT_EQ((-4) / AffThree, AffNegOne); |
| EXPECT_EQ(AffNegFour / ValThree, AffNegOne); |
| EXPECT_EQ(AffNegFour / 3, AffNegOne); |
| |
| // Divisor is negative (should be rounded towards zero) |
| EXPECT_EQ(AffFour / AffNegThree, AffNegOne); |
| EXPECT_EQ(AffFour / -3, AffNegOne); |
| EXPECT_EQ(4 / AffNegThree, AffNegOne); |
| EXPECT_EQ(AffFour / ValNegThree, AffNegOne); |
| EXPECT_EQ(AffFour / -3, AffNegOne); |
| } |
| |
| // Remainder |
| { |
| EXPECT_EQ(AffThree % AffTwo, AffOne); |
| EXPECT_EQ(AffThree % 2, AffOne); |
| EXPECT_EQ(3 % AffTwo, AffOne); |
| EXPECT_EQ(AffThree % ValTwo, AffOne); |
| EXPECT_EQ(ValThree % AffTwo, AffOne); |
| |
| // Dividend is negative (should be rounded towards zero) |
| EXPECT_EQ(AffNegFour % AffThree, AffNegOne); |
| EXPECT_EQ(AffNegFour % 3, AffNegOne); |
| EXPECT_EQ((-4) % AffThree, AffNegOne); |
| EXPECT_EQ(AffNegFour % ValThree, AffNegOne); |
| EXPECT_EQ(AffNegFour % 3, AffNegOne); |
| |
| // Divisor is negative (should be rounded towards zero) |
| EXPECT_EQ(AffFour % AffNegThree, AffOne); |
| EXPECT_EQ(AffFour % -3, AffOne); |
| EXPECT_EQ(4 % AffNegThree, AffOne); |
| EXPECT_EQ(AffFour % ValNegThree, AffOne); |
| EXPECT_EQ(AffFour % -3, AffOne); |
| } |
| } |
| |
| TEST(Isl, Foreach) { |
| std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(), |
| &isl_ctx_free); |
| |
| isl::map TestMap{Ctx.get(), "{ [2] -> [7]; [5] -> [7] }"}; |
| isl::union_map TestUMap{Ctx.get(), "{ A[i] -> [7]; B[i] -> [7] }"}; |
| |
| isl::set TestSet{Ctx.get(), "{ [0,7]; [i,7]: i >= 2 }"}; |
| isl::union_set TestUSet{Ctx.get(), "{ A[0,7]; B[i,7] }"}; |
| |
| isl::set Seven{Ctx.get(), "{ [7] }"}; |
| |
| { |
| auto NumBMaps = 0; |
| isl::stat Stat = |
| TestMap.foreach_basic_map([&](isl::basic_map BMap) -> isl::stat { |
| EXPECT_EQ(BMap.range(), Seven); |
| NumBMaps++; |
| return isl::stat::ok(); |
| }); |
| |
| EXPECT_TRUE(Stat.is_ok()); |
| EXPECT_EQ(2, NumBMaps); |
| } |
| |
| { |
| auto NumBSets = 0; |
| isl::stat Stat = |
| TestSet.foreach_basic_set([&](isl::basic_set BSet) -> isl::stat { |
| EXPECT_EQ(BSet.project_out(isl::dim::set, 0, 1), Seven); |
| NumBSets++; |
| return isl::stat::ok(); |
| }); |
| EXPECT_TRUE(Stat.is_ok()); |
| EXPECT_EQ(2, NumBSets); |
| } |
| |
| { |
| auto NumMaps = 0; |
| isl::stat Stat = TestUMap.foreach_map([&](isl::map Map) -> isl::stat { |
| EXPECT_EQ(Map.range(), Seven); |
| NumMaps++; |
| return isl::stat::ok(); |
| }); |
| EXPECT_TRUE(Stat.is_ok()); |
| EXPECT_EQ(2, NumMaps); |
| } |
| |
| { |
| auto NumSets = 0; |
| isl::stat Stat = TestUSet.foreach_set([&](isl::set Set) -> isl::stat { |
| EXPECT_EQ(Set.project_out(isl::dim::set, 0, 1), Seven); |
| NumSets++; |
| return isl::stat::ok(); |
| }); |
| EXPECT_TRUE(Stat.is_ok()); |
| EXPECT_EQ(2, NumSets); |
| } |
| |
| { |
| auto UPwAff = isl::union_pw_aff(TestUSet, isl::val::zero(Ctx.get())); |
| auto NumPwAffs = 0; |
| isl::stat Stat = UPwAff.foreach_pw_aff([&](isl::pw_aff PwAff) -> isl::stat { |
| EXPECT_TRUE(PwAff.is_cst()); |
| NumPwAffs++; |
| return isl::stat::ok(); |
| }); |
| EXPECT_TRUE(Stat.is_ok()); |
| EXPECT_EQ(2, NumPwAffs); |
| } |
| |
| { |
| auto NumBMaps = 0; |
| EXPECT_TRUE(TestMap |
| .foreach_basic_map([&](isl::basic_map BMap) -> isl::stat { |
| EXPECT_EQ(BMap.range(), Seven); |
| NumBMaps++; |
| return isl::stat::error(); |
| }) |
| .is_error()); |
| EXPECT_EQ(1, NumBMaps); |
| } |
| |
| { |
| auto NumMaps = 0; |
| EXPECT_TRUE(TestUMap |
| .foreach_map([&](isl::map Map) -> isl::stat { |
| EXPECT_EQ(Map.range(), Seven); |
| NumMaps++; |
| return isl::stat::error(); |
| }) |
| .is_error()); |
| EXPECT_EQ(1, NumMaps); |
| } |
| |
| { |
| auto TestPwAff = isl::pw_aff(TestSet, isl::val::zero(Ctx.get())); |
| auto NumPieces = 0; |
| isl::stat Stat = TestPwAff.foreach_piece( |
| [&](isl::set Domain, isl::aff Aff) -> isl::stat { |
| EXPECT_EQ(Domain, TestSet); |
| EXPECT_TRUE(Aff.is_cst()); |
| NumPieces++; |
| return isl::stat::error(); |
| }); |
| EXPECT_TRUE(Stat.is_error()); |
| EXPECT_EQ(1, NumPieces); |
| } |
| } |
| |
| TEST(ISLTools, beforeScatter) { |
| std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(), |
| &isl_ctx_free); |
| |
| // Basic usage with isl_map |
| EXPECT_EQ(MAP("{ [] -> [i] : i <= 0 }"), |
| beforeScatter(MAP("{ [] -> [0] }"), false)); |
| EXPECT_EQ(MAP("{ [] -> [i] : i < 0 }"), |
| beforeScatter(MAP("{ [] -> [0] }"), true)); |
| |
| // Basic usage with isl_union_map |
| EXPECT_EQ(UMAP("{ A[] -> [i] : i <= 0; B[] -> [i] : i <= 0 }"), |
| beforeScatter(UMAP("{ A[] -> [0]; B[] -> [0] }"), false)); |
| EXPECT_EQ(UMAP("{ A[] -> [i] : i < 0; B[] -> [i] : i < 0 }"), |
| beforeScatter(UMAP("{ A[] -> [0]; B[] -> [0] }"), true)); |
| |
| // More than one dimension |
| EXPECT_EQ(UMAP("{ [] -> [i, j] : i < 0; [] -> [i, j] : i = 0 and j <= 0 }"), |
| beforeScatter(UMAP("{ [] -> [0, 0] }"), false)); |
| EXPECT_EQ(UMAP("{ [] -> [i, j] : i < 0; [] -> [i, j] : i = 0 and j < 0 }"), |
| beforeScatter(UMAP("{ [] -> [0, 0] }"), true)); |
| |
| // Functional |
| EXPECT_EQ(UMAP("{ [i] -> [j] : j <= i }"), |
| beforeScatter(UMAP("{ [i] -> [i] }"), false)); |
| EXPECT_EQ(UMAP("{ [i] -> [j] : j < i }"), |
| beforeScatter(UMAP("{ [i] -> [i] }"), true)); |
| |
| // Parametrized |
| EXPECT_EQ(UMAP("[i] -> { [] -> [j] : j <= i }"), |
| beforeScatter(UMAP("[i] -> { [] -> [i] }"), false)); |
| EXPECT_EQ(UMAP("[i] -> { [] -> [j] : j < i }"), |
| beforeScatter(UMAP("[i] -> { [] -> [i] }"), true)); |
| |
| // More than one range |
| EXPECT_EQ(UMAP("{ [] -> [i] : i <= 10 }"), |
| beforeScatter(UMAP("{ [] -> [0]; [] -> [10] }"), false)); |
| EXPECT_EQ(UMAP("{ [] -> [i] : i < 10 }"), |
| beforeScatter(UMAP("{ [] -> [0]; [] -> [10] }"), true)); |
| |
| // Edge case: empty |
| EXPECT_EQ(UMAP("{ [] -> [i] : 1 = 0 }"), |
| beforeScatter(UMAP("{ [] -> [i] : 1 = 0 }"), false)); |
| EXPECT_EQ(UMAP("{ [] -> [i] : 1 = 0 }"), |
| beforeScatter(UMAP("{ [] -> [i] : 1 = 0 }"), true)); |
| } |
| |
| TEST(ISLTools, afterScatter) { |
| std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(), |
| &isl_ctx_free); |
| |
| // Basic usage with isl_map |
| EXPECT_EQ(MAP("{ [] -> [i] : i >= 0 }"), |
| afterScatter(MAP("{ [] -> [0] }"), false)); |
| EXPECT_EQ(MAP("{ [] -> [i] : i > 0 }"), |
| afterScatter(MAP("{ [] -> [0] }"), true)); |
| |
| // Basic usage with isl_union_map |
| EXPECT_EQ(UMAP("{ A[] -> [i] : i >= 0; B[] -> [i] : i >= 0 }"), |
| afterScatter(UMAP("{ A[] -> [0]; B[] -> [0] }"), false)); |
| EXPECT_EQ(UMAP("{ A[] -> [i] : i > 0; B[] -> [i] : i > 0 }"), |
| afterScatter(UMAP("{ A[] -> [0]; B[] -> [0] }"), true)); |
| |
| // More than one dimension |
| EXPECT_EQ(UMAP("{ [] -> [i, j] : i > 0; [] -> [i, j] : i = 0 and j >= 0 }"), |
| afterScatter(UMAP("{ [] -> [0, 0] }"), false)); |
| EXPECT_EQ(UMAP("{ [] -> [i, j] : i > 0; [] -> [i, j] : i = 0 and j > 0 }"), |
| afterScatter(UMAP("{ [] -> [0, 0] }"), true)); |
| |
| // Functional |
| EXPECT_EQ(UMAP("{ [i] -> [j] : j >= i }"), |
| afterScatter(UMAP("{ [i] -> [i] }"), false)); |
| EXPECT_EQ(UMAP("{ [i] -> [j] : j > i }"), |
| afterScatter(UMAP("{ [i] -> [i] }"), true)); |
| |
| // Parametrized |
| EXPECT_EQ(UMAP("[i] -> { [] -> [j] : j >= i }"), |
| afterScatter(UMAP("[i] -> { [] -> [i] }"), false)); |
| EXPECT_EQ(UMAP("[i] -> { [] -> [j] : j > i }"), |
| afterScatter(UMAP("[i] -> { [] -> [i] }"), true)); |
| |
| // More than one range |
| EXPECT_EQ(UMAP("{ [] -> [i] : i >= 0 }"), |
| afterScatter(UMAP("{ [] -> [0]; [] -> [10] }"), false)); |
| EXPECT_EQ(UMAP("{ [] -> [i] : i > 0 }"), |
| afterScatter(UMAP("{ [] -> [0]; [] -> [10] }"), true)); |
| |
| // Edge case: empty |
| EXPECT_EQ(UMAP("{ }"), afterScatter(UMAP("{ }"), false)); |
| EXPECT_EQ(UMAP("{ }"), afterScatter(UMAP("{ }"), true)); |
| } |
| |
| TEST(ISLTools, betweenScatter) { |
| std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(), |
| &isl_ctx_free); |
| |
| // Basic usage with isl_map |
| EXPECT_EQ(MAP("{ [] -> [i] : 0 < i < 10 }"), |
| betweenScatter(MAP("{ [] -> [0] }"), MAP("{ [] -> [10] }"), false, |
| false)); |
| EXPECT_EQ( |
| MAP("{ [] -> [i] : 0 <= i < 10 }"), |
| betweenScatter(MAP("{ [] -> [0] }"), MAP("{ [] -> [10] }"), true, false)); |
| EXPECT_EQ( |
| MAP("{ [] -> [i] : 0 < i <= 10 }"), |
| betweenScatter(MAP("{ [] -> [0] }"), MAP("{ [] -> [10] }"), false, true)); |
| EXPECT_EQ( |
| MAP("{ [] -> [i] : 0 <= i <= 10 }"), |
| betweenScatter(MAP("{ [] -> [0] }"), MAP("{ [] -> [10] }"), true, true)); |
| |
| // Basic usage with isl_union_map |
| EXPECT_EQ(UMAP("{ A[] -> [i] : 0 < i < 10; B[] -> [i] : 0 < i < 10 }"), |
| betweenScatter(UMAP("{ A[] -> [0]; B[] -> [0] }"), |
| UMAP("{ A[] -> [10]; B[] -> [10] }"), false, false)); |
| EXPECT_EQ(UMAP("{ A[] -> [i] : 0 <= i < 10; B[] -> [i] : 0 <= i < 10 }"), |
| betweenScatter(UMAP("{ A[] -> [0]; B[] -> [0] }"), |
| UMAP("{ A[] -> [10]; B[] -> [10] }"), true, false)); |
| EXPECT_EQ(UMAP("{ A[] -> [i] : 0 < i <= 10; B[] -> [i] : 0 < i <= 10 }"), |
| betweenScatter(UMAP("{ A[] -> [0]; B[] -> [0] }"), |
| UMAP("{ A[] -> [10]; B[] -> [10] }"), false, true)); |
| EXPECT_EQ(UMAP("{ A[] -> [i] : 0 <= i <= 10; B[] -> [i] : 0 <= i <= 10 }"), |
| betweenScatter(UMAP("{ A[] -> [0]; B[] -> [0] }"), |
| UMAP("{ A[] -> [10]; B[] -> [10] }"), true, true)); |
| } |
| |
| TEST(ISLTools, singleton) { |
| std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(), |
| &isl_ctx_free); |
| |
| // No element found |
| EXPECT_EQ(SET("{ [] : 1 = 0 }"), singleton(USET("{ }"), SPACE("{ [] }"))); |
| EXPECT_EQ(MAP("{ [] -> [] : 1 = 0 }"), |
| singleton(UMAP("{ }"), SPACE("{ [] -> [] }"))); |
| |
| // One element found |
| EXPECT_EQ(SET("{ [] }"), singleton(USET("{ [] }"), SPACE("{ [] }"))); |
| EXPECT_EQ(MAP("{ [] -> [] }"), |
| singleton(UMAP("{ [] -> [] }"), SPACE("{ [] -> [] }"))); |
| |
| // Many elements found |
| EXPECT_EQ(SET("{ [i] : 0 <= i < 10 }"), |
| singleton(USET("{ [i] : 0 <= i < 10 }"), SPACE("{ [i] }"))); |
| EXPECT_EQ( |
| MAP("{ [i] -> [i] : 0 <= i < 10 }"), |
| singleton(UMAP("{ [i] -> [i] : 0 <= i < 10 }"), SPACE("{ [i] -> [j] }"))); |
| |
| // Different parameters |
| EXPECT_EQ(SET("[i] -> { [i] }"), |
| singleton(USET("[i] -> { [i] }"), SPACE("{ [i] }"))); |
| EXPECT_EQ(MAP("[i] -> { [i] -> [i] }"), |
| singleton(UMAP("[i] -> { [i] -> [i] }"), SPACE("{ [i] -> [j] }"))); |
| } |
| |
| TEST(ISLTools, getNumScatterDims) { |
| std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(), |
| &isl_ctx_free); |
| |
| // Basic usage |
| EXPECT_EQ(0u, getNumScatterDims(UMAP("{ [] -> [] }"))); |
| EXPECT_EQ(1u, getNumScatterDims(UMAP("{ [] -> [i] }"))); |
| EXPECT_EQ(2u, getNumScatterDims(UMAP("{ [] -> [i,j] }"))); |
| EXPECT_EQ(3u, getNumScatterDims(UMAP("{ [] -> [i,j,k] }"))); |
| |
| // Different scatter spaces |
| EXPECT_EQ(0u, getNumScatterDims(UMAP("{ A[] -> []; [] -> []}"))); |
| EXPECT_EQ(1u, getNumScatterDims(UMAP("{ A[] -> []; [] -> [i] }"))); |
| EXPECT_EQ(2u, getNumScatterDims(UMAP("{ A[] -> [i]; [] -> [i,j] }"))); |
| EXPECT_EQ(3u, getNumScatterDims(UMAP("{ A[] -> [i]; [] -> [i,j,k] }"))); |
| } |
| |
| TEST(ISLTools, getScatterSpace) { |
| std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(), |
| &isl_ctx_free); |
| |
| // Basic usage |
| EXPECT_EQ(SPACE("{ [] }"), getScatterSpace(UMAP("{ [] -> [] }"))); |
| EXPECT_EQ(SPACE("{ [i] }"), getScatterSpace(UMAP("{ [] -> [i] }"))); |
| EXPECT_EQ(SPACE("{ [i,j] }"), getScatterSpace(UMAP("{ [] -> [i,j] }"))); |
| EXPECT_EQ(SPACE("{ [i,j,k] }"), getScatterSpace(UMAP("{ [] -> [i,j,k] }"))); |
| |
| // Different scatter spaces |
| EXPECT_EQ(SPACE("{ [] }"), getScatterSpace(UMAP("{ A[] -> []; [] -> [] }"))); |
| EXPECT_EQ(SPACE("{ [i] }"), |
| getScatterSpace(UMAP("{ A[] -> []; [] -> [i] }"))); |
| EXPECT_EQ(SPACE("{ [i,j] }"), |
| getScatterSpace(UMAP("{ A[] -> [i]; [] -> [i,j] }"))); |
| EXPECT_EQ(SPACE("{ [i,j,k] }"), |
| getScatterSpace(UMAP("{ A[] -> [i]; [] -> [i,j,k] }"))); |
| } |
| |
| TEST(ISLTools, makeIdentityMap) { |
| std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(), |
| &isl_ctx_free); |
| |
| // Basic usage |
| EXPECT_EQ(UMAP("{ [i] -> [i] }"), makeIdentityMap(USET("{ [0] }"), false)); |
| EXPECT_EQ(UMAP("{ [0] -> [0] }"), makeIdentityMap(USET("{ [0] }"), true)); |
| |
| // Multiple spaces |
| EXPECT_EQ(UMAP("{ [] -> []; [i] -> [i] }"), |
| makeIdentityMap(USET("{ []; [0] }"), false)); |
| EXPECT_EQ(UMAP("{ [] -> []; [0] -> [0] }"), |
| makeIdentityMap(USET("{ []; [0] }"), true)); |
| |
| // Edge case: empty |
| EXPECT_EQ(UMAP("{ }"), makeIdentityMap(USET("{ }"), false)); |
| EXPECT_EQ(UMAP("{ }"), makeIdentityMap(USET("{ }"), true)); |
| } |
| |
| TEST(ISLTools, reverseDomain) { |
| std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(), |
| &isl_ctx_free); |
| |
| // Basic usage |
| EXPECT_EQ(MAP("{ [B[] -> A[]] -> [] }"), |
| reverseDomain(MAP("{ [A[] -> B[]] -> [] }"))); |
| EXPECT_EQ(UMAP("{ [B[] -> A[]] -> [] }"), |
| reverseDomain(UMAP("{ [A[] -> B[]] -> [] }"))); |
| } |
| |
| TEST(ISLTools, shiftDim) { |
| std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(), |
| &isl_ctx_free); |
| |
| // Basic usage |
| EXPECT_EQ(SET("{ [1] }"), shiftDim(SET("{ [0] }"), 0, 1)); |
| EXPECT_EQ(USET("{ [1] }"), shiftDim(USET("{ [0] }"), 0, 1)); |
| |
| // From-end indexing |
| EXPECT_EQ(USET("{ [0,0,1] }"), shiftDim(USET("{ [0,0,0] }"), -1, 1)); |
| EXPECT_EQ(USET("{ [0,1,0] }"), shiftDim(USET("{ [0,0,0] }"), -2, 1)); |
| EXPECT_EQ(USET("{ [1,0,0] }"), shiftDim(USET("{ [0,0,0] }"), -3, 1)); |
| |
| // Parametrized |
| EXPECT_EQ(USET("[n] -> { [n+1] }"), shiftDim(USET("[n] -> { [n] }"), 0, 1)); |
| |
| // Union maps |
| EXPECT_EQ(MAP("{ [1] -> [] }"), |
| shiftDim(MAP("{ [0] -> [] }"), isl::dim::in, 0, 1)); |
| EXPECT_EQ(UMAP("{ [1] -> [] }"), |
| shiftDim(UMAP("{ [0] -> [] }"), isl::dim::in, 0, 1)); |
| EXPECT_EQ(MAP("{ [] -> [1] }"), |
| shiftDim(MAP("{ [] -> [0] }"), isl::dim::out, 0, 1)); |
| EXPECT_EQ(UMAP("{ [] -> [1] }"), |
| shiftDim(UMAP("{ [] -> [0] }"), isl::dim::out, 0, 1)); |
| } |
| |
| TEST(DeLICM, computeReachingWrite) { |
| std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(), |
| &isl_ctx_free); |
| |
| // Basic usage |
| EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom[] : 0 < i }"), |
| computeReachingWrite(UMAP("{ Dom[] -> [0] }"), |
| UMAP("{ Dom[] -> Elt[] }"), false, false, |
| false)); |
| EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom[] : 0 < i }"), |
| computeReachingWrite(UMAP("{ Dom[] -> [0] }"), |
| UMAP("{ Dom[] -> Elt[] }"), false, false, |
| true)); |
| EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom[] : 0 <= i }"), |
| computeReachingWrite(UMAP("{ Dom[] -> [0] }"), |
| UMAP("{ Dom[] -> Elt[] }"), false, true, |
| false)); |
| EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom[] : 0 <= i }"), |
| computeReachingWrite(UMAP("{ Dom[] -> [0] }"), |
| UMAP("{ Dom[] -> Elt[] }"), false, true, |
| false)); |
| |
| EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom[] : i < 0 }"), |
| computeReachingWrite(UMAP("{ Dom[] -> [0] }"), |
| UMAP("{ Dom[] -> Elt[] }"), true, false, |
| false)); |
| EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom[] : i <= 0 }"), |
| computeReachingWrite(UMAP("{ Dom[] -> [0] }"), |
| UMAP("{ Dom[] -> Elt[] }"), true, false, |
| true)); |
| EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom[] : i < 0 }"), |
| computeReachingWrite(UMAP("{ Dom[] -> [0] }"), |
| UMAP("{ Dom[] -> Elt[] }"), true, true, |
| false)); |
| EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom[] : i <= 0 }"), |
| computeReachingWrite(UMAP("{ Dom[] -> [0] }"), |
| UMAP("{ Dom[] -> Elt[] }"), true, true, true)); |
| |
| // Two writes |
| EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom1[] : 0 < i < 10; [Elt[] -> [i]] -> " |
| "Dom2[] : 10 < i }"), |
| computeReachingWrite(UMAP("{ Dom1[] -> [0]; Dom2[] -> [10] }"), |
| UMAP("{ Dom1[] -> Elt[]; Dom2[] -> Elt[] }"), |
| false, false, false)); |
| EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom1[] : 0 <= i < 10; [Elt[] -> [i]] -> " |
| "Dom2[] : 10 <= i }"), |
| computeReachingWrite(UMAP("{ Dom1[] -> [0]; Dom2[] -> [10] }"), |
| UMAP("{ Dom1[] -> Elt[]; Dom2[] -> Elt[] }"), |
| false, true, false)); |
| EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom1[] : 0 < i <= 10; [Elt[] -> [i]] -> " |
| "Dom2[] : 10 < i }"), |
| computeReachingWrite(UMAP("{ Dom1[] -> [0]; Dom2[] -> [10] }"), |
| UMAP("{ Dom1[] -> Elt[]; Dom2[] -> Elt[] }"), |
| false, false, true)); |
| EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom1[] : 0 <= i <= 10; [Elt[] -> [i]] -> " |
| "Dom2[] : 10 <= i }"), |
| computeReachingWrite(UMAP("{ Dom1[] -> [0]; Dom2[] -> [10] }"), |
| UMAP("{ Dom1[] -> Elt[]; Dom2[] -> Elt[] }"), |
| false, true, true)); |
| |
| EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom2[] : 0 < i < 10; [Elt[] -> [i]] -> " |
| "Dom1[] : i < 0 }"), |
| computeReachingWrite(UMAP("{ Dom1[] -> [0]; Dom2[] -> [10] }"), |
| UMAP("{ Dom1[] -> Elt[]; Dom2[] -> Elt[] }"), |
| true, false, false)); |
| EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom2[] : 0 <= i < 10; [Elt[] -> [i]] -> " |
| "Dom1[] : i < 0 }"), |
| computeReachingWrite(UMAP("{ Dom1[] -> [0]; Dom2[] -> [10] }"), |
| UMAP("{ Dom1[] -> Elt[]; Dom2[] -> Elt[] }"), |
| true, true, false)); |
| EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom2[] : 0 < i <= 10; [Elt[] -> [i]] -> " |
| "Dom1[] : i <= 0 }"), |
| computeReachingWrite(UMAP("{ Dom1[] -> [0]; Dom2[] -> [10] }"), |
| UMAP("{ Dom1[] -> Elt[]; Dom2[] -> Elt[] }"), |
| true, false, true)); |
| EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom2[] : 0 <= i <= 10; [Elt[] -> [i]] -> " |
| "Dom1[] : i <= 0 }"), |
| computeReachingWrite(UMAP("{ Dom1[] -> [0]; Dom2[] -> [10] }"), |
| UMAP("{ Dom1[] -> Elt[]; Dom2[] -> Elt[] }"), |
| true, true, true)); |
| |
| // Domain in same space |
| EXPECT_EQ(UMAP("{ [Elt[] -> [i]] -> Dom[1] : 0 < i <= 10; [Elt[] -> [i]] -> " |
| "Dom[2] : 10 < i }"), |
| computeReachingWrite(UMAP("{ Dom[i] -> [10i - 10] }"), |
| UMAP("{ Dom[1] -> Elt[]; Dom[2] -> Elt[] }"), |
| false, false, true)); |
| |
| // Parametric |
| EXPECT_EQ(UMAP("[p] -> { [Elt[] -> [i]] -> Dom[] : p < i }"), |
| computeReachingWrite(UMAP("[p] -> { Dom[] -> [p] }"), |
| UMAP("{ Dom[] -> Elt[] }"), false, false, |
| false)); |
| |
| // More realistic example (from reduction_embedded.ll) |
| EXPECT_EQ( |
| UMAP("{ [Elt[] -> [i]] -> Dom[0] : 0 < i <= 3; [Elt[] -> [i]] -> Dom[1] " |
| ": 3 < i <= 6; [Elt[] -> [i]] -> Dom[2] : 6 < i <= 9; [Elt[] -> " |
| "[i]] -> Dom[3] : 9 < i <= 12; [Elt[] -> [i]] -> Dom[4] : 12 < i }"), |
| computeReachingWrite(UMAP("{ Dom[i] -> [3i] : 0 <= i <= 4 }"), |
| UMAP("{ Dom[i] -> Elt[] : 0 <= i <= 4 }"), false, |
| false, true)); |
| } |
| |
| TEST(DeLICM, computeArrayUnused) { |
| std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(), |
| &isl_ctx_free); |
| |
| // The ReadEltInSameInst parameter doesn't matter in simple cases. To also |
| // cover the parameter without duplicating the tests, this loops runs over |
| // other in both settings. |
| for (bool ReadEltInSameInst = false, Done = false; !Done; |
| Done = ReadEltInSameInst, ReadEltInSameInst = true) { |
| // Basic usage: one read, one write |
| EXPECT_EQ(UMAP("{ Elt[] -> [i] : 0 < i < 10 }"), |
| computeArrayUnused(UMAP("{ Read[] -> [0]; Write[] -> [10] }"), |
| UMAP("{ Write[] -> Elt[] }"), |
| UMAP("{ Read[] -> Elt[] }"), ReadEltInSameInst, |
| false, false)); |
| EXPECT_EQ(UMAP("{ Elt[] -> [i] : 0 < i <= 10 }"), |
| computeArrayUnused(UMAP("{ Read[] -> [0]; Write[] -> [10] }"), |
| UMAP("{ Write[] -> Elt[] }"), |
| UMAP("{ Read[] -> Elt[] }"), ReadEltInSameInst, |
| false, true)); |
| EXPECT_EQ(UMAP("{ Elt[] -> [i] : 0 <= i < 10 }"), |
| computeArrayUnused(UMAP("{ Read[] -> [0]; Write[] -> [10] }"), |
| UMAP("{ Write[] -> Elt[] }"), |
| UMAP("{ Read[] -> Elt[] }"), ReadEltInSameInst, |
| true, false)); |
| EXPECT_EQ(UMAP("{ Elt[] -> [i] : 0 <= i <= 10 }"), |
| computeArrayUnused(UMAP("{ Read[] -> [0]; Write[] -> [10] }"), |
| UMAP("{ Write[] -> Elt[] }"), |
| UMAP("{ Read[] -> Elt[] }"), ReadEltInSameInst, |
| true, true)); |
| |
| // Two reads |
| EXPECT_EQ(UMAP("{ Elt[] -> [i] : 0 < i <= 10 }"), |
| computeArrayUnused( |
| UMAP("{ Read[0] -> [-10]; Read[1] -> [0]; Write[] -> [10] }"), |
| UMAP("{ Write[] -> Elt[] }"), UMAP("{ Read[i] -> Elt[] }"), |
| ReadEltInSameInst, false, true)); |
| |
| // Corner case: no writes |
| EXPECT_EQ(UMAP("{}"), |
| computeArrayUnused(UMAP("{ Read[] -> [0] }"), UMAP("{}"), |
| UMAP("{ Read[] -> Elt[] }"), ReadEltInSameInst, |
| false, false)); |
| |
| // Corner case: no reads |
| EXPECT_EQ(UMAP("{ Elt[] -> [i] : i <= 0 }"), |
| computeArrayUnused(UMAP("{ Write[] -> [0] }"), |
| UMAP("{ Write[] -> Elt[] }"), UMAP("{}"), |
| ReadEltInSameInst, false, true)); |
| |
| // Two writes |
| EXPECT_EQ( |
| UMAP("{ Elt[] -> [i] : i <= 10 }"), |
| computeArrayUnused(UMAP("{ WriteA[] -> [0]; WriteB[] -> [10] }"), |
| UMAP("{ WriteA[] -> Elt[]; WriteB[] -> Elt[] }"), |
| UMAP("{}"), ReadEltInSameInst, false, true)); |
| |
| // Two unused zones |
| // read,write,read,write |
| EXPECT_EQ( |
| UMAP("{ Elt[] -> [i] : 0 < i <= 10; Elt[] -> [i] : 20 < i <= 30 }"), |
| computeArrayUnused(UMAP("{ ReadA[] -> [0]; WriteA[] -> [10]; ReadB[] " |
| "-> [20]; WriteB[] -> [30] }"), |
| UMAP("{ WriteA[] -> Elt[]; WriteB[] -> Elt[] }"), |
| UMAP("{ ReadA[] -> Elt[]; ReadB[] -> Elt[] }"), |
| ReadEltInSameInst, false, true)); |
| |
| // write, write |
| EXPECT_EQ( |
| UMAP("{ Elt[] -> [i] : i <= 10 }"), |
| computeArrayUnused( |
| UMAP("{ WriteA[] -> [0]; WriteB[] -> [10]; Read[] -> [20] }"), |
| UMAP("{ WriteA[] -> Elt[]; WriteB[] -> Elt[] }"), |
| UMAP("{ Read[] -> Elt[] }"), ReadEltInSameInst, false, true)); |
| |
| // write, read |
| EXPECT_EQ(UMAP("{ Elt[] -> [i] : i <= 0 }"), |
| computeArrayUnused(UMAP("{ Write[] -> [0]; Read[] -> [10] }"), |
| UMAP("{ Write[] -> Elt[] }"), |
| UMAP("{ Read[] -> Elt[] }"), ReadEltInSameInst, |
| false, true)); |
| |
| // read, write, read |
| EXPECT_EQ(UMAP("{ Elt[] -> [i] : 0 < i <= 10 }"), |
| computeArrayUnused( |
| UMAP("{ ReadA[] -> [0]; Write[] -> [10]; ReadB[] -> [20] }"), |
| UMAP("{ Write[] -> Elt[] }"), |
| UMAP("{ ReadA[] -> Elt[]; ReadB[] -> Elt[] }"), |
| ReadEltInSameInst, false, true)); |
| |
| // read, write, write |
| EXPECT_EQ( |
| UMAP("{ Elt[] -> [i] : 0 < i <= 20 }"), |
| computeArrayUnused( |
| UMAP("{ Read[] -> [0]; WriteA[] -> [10]; WriteB[] -> [20] }"), |
| UMAP("{ WriteA[] -> Elt[]; WriteB[] -> Elt[] }"), |
| UMAP("{ Read[] -> Elt[] }"), ReadEltInSameInst, false, true)); |
| |
| // read, write, write, read |
| EXPECT_EQ( |
| UMAP("{ Elt[] -> [i] : 0 < i <= 20 }"), |
| computeArrayUnused(UMAP("{ ReadA[] -> [0]; WriteA[] -> [10]; WriteB[] " |
| "-> [20]; ReadB[] -> [30] }"), |
| UMAP("{ WriteA[] -> Elt[]; WriteB[] -> Elt[] }"), |
| UMAP("{ ReadA[] -> Elt[]; ReadB[] -> Elt[] }"), |
| ReadEltInSameInst, false, true)); |
| } |
| |
| // Read and write in same statement |
| EXPECT_EQ(UMAP("{ Elt[] -> [i] : i < 0 }"), |
| computeArrayUnused(UMAP("{ RW[] -> [0] }"), |
| UMAP("{ RW[] -> Elt[] }"), |
| UMAP("{ RW[] -> Elt[] }"), true, false, false)); |
| EXPECT_EQ(UMAP("{ Elt[] -> [i] : i <= 0 }"), |
| computeArrayUnused(UMAP("{ RW[] -> [0] }"), |
| UMAP("{ RW[] -> Elt[] }"), |
| UMAP("{ RW[] -> Elt[] }"), true, false, true)); |
| EXPECT_EQ(UMAP("{ Elt[] -> [0] }"), |
| computeArrayUnused(UMAP("{ RW[] -> [0] }"), |
| UMAP("{ RW[] -> Elt[] }"), |
| UMAP("{ RW[] -> Elt[] }"), false, true, true)); |
| } |
| |
| TEST(DeLICM, convertZoneToTimepoints) { |
| std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(), |
| &isl_ctx_free); |
| |
| // Corner case: empty set |
| EXPECT_EQ(USET("{}"), convertZoneToTimepoints(USET("{}"), false, false)); |
| EXPECT_EQ(USET("{}"), convertZoneToTimepoints(USET("{}"), true, false)); |
| EXPECT_EQ(USET("{}"), convertZoneToTimepoints(USET("{}"), false, true)); |
| EXPECT_EQ(USET("{}"), convertZoneToTimepoints(USET("{}"), true, true)); |
| |
| // Basic usage |
| EXPECT_EQ(USET("{}"), convertZoneToTimepoints(USET("{ [1] }"), false, false)); |
| EXPECT_EQ(USET("{ [0] }"), |
| convertZoneToTimepoints(USET("{ [1] }"), true, false)); |
| EXPECT_EQ(USET("{ [1] }"), |
| convertZoneToTimepoints(USET("{ [1] }"), false, true)); |
| EXPECT_EQ(USET("{ [0]; [1] }"), |
| convertZoneToTimepoints(USET("{ [1] }"), true, true)); |
| |
| // Non-adjacent ranges |
| EXPECT_EQ(USET("{}"), |
| convertZoneToTimepoints(USET("{ [1]; [11] }"), false, false)); |
| EXPECT_EQ(USET("{ [0]; [10] }"), |
| convertZoneToTimepoints(USET("{ [1]; [11] }"), true, false)); |
| EXPECT_EQ(USET("{ [1]; [11] }"), |
| convertZoneToTimepoints(USET("{ [1]; [11] }"), false, true)); |
| EXPECT_EQ(USET("{ [0]; [1]; [10]; [11] }"), |
| convertZoneToTimepoints(USET("{ [1]; [11] }"), true, true)); |
| |
| // Adjacent unit ranges |
| EXPECT_EQ( |
| USET("{ [i] : 0 < i < 10 }"), |
| convertZoneToTimepoints(USET("{ [i] : 0 < i <= 10 }"), false, false)); |
| EXPECT_EQ( |
| USET("{ [i] : 0 <= i < 10 }"), |
| convertZoneToTimepoints(USET("{ [i] : 0 < i <= 10 }"), true, false)); |
| EXPECT_EQ( |
| USET("{ [i] : 0 < i <= 10 }"), |
| convertZoneToTimepoints(USET("{ [i] : 0 < i <= 10 }"), false, true)); |
| EXPECT_EQ(USET("{ [i] : 0 <= i <= 10 }"), |
| convertZoneToTimepoints(USET("{ [i] : 0 < i <= 10 }"), true, true)); |
| |
| // More than one dimension |
| EXPECT_EQ(USET("{}"), |
| convertZoneToTimepoints(USET("{ [0,1] }"), false, false)); |
| EXPECT_EQ(USET("{ [0,0] }"), |
| convertZoneToTimepoints(USET("{ [0,1] }"), true, false)); |
| EXPECT_EQ(USET("{ [0,1] }"), |
| convertZoneToTimepoints(USET("{ [0,1] }"), false, true)); |
| EXPECT_EQ(USET("{ [0,0]; [0,1] }"), |
| convertZoneToTimepoints(USET("{ [0,1] }"), true, true)); |
| |
| // Map domains |
| EXPECT_EQ(UMAP("{}"), convertZoneToTimepoints(UMAP("{ [1] -> [] }"), |
| isl::dim::in, false, false)); |
| EXPECT_EQ(UMAP("{ [0] -> [] }"), |
| convertZoneToTimepoints(UMAP("{ [1] -> [] }"), isl::dim::in, true, |
| false)); |
| EXPECT_EQ(UMAP("{ [1] -> [] }"), |
| convertZoneToTimepoints(UMAP("{ [1] -> [] }"), isl::dim::in, false, |
| true)); |
| EXPECT_EQ( |
| UMAP("{ [0] -> []; [1] -> [] }"), |
| convertZoneToTimepoints(UMAP("{ [1] -> [] }"), isl::dim::in, true, true)); |
| |
| // Map ranges |
| EXPECT_EQ(UMAP("{}"), convertZoneToTimepoints(UMAP("{ [] -> [1] }"), |
| isl::dim::out, false, false)); |
| EXPECT_EQ(UMAP("{ [] -> [0] }"), |
| convertZoneToTimepoints(UMAP("{ [] -> [1] }"), isl::dim::out, true, |
| false)); |
| EXPECT_EQ(UMAP("{ [] -> [1] }"), |
| convertZoneToTimepoints(UMAP("{ [] -> [1] }"), isl::dim::out, false, |
| true)); |
| EXPECT_EQ(UMAP("{ [] -> [0]; [] -> [1] }"), |
| convertZoneToTimepoints(UMAP("{ [] -> [1] }"), isl::dim::out, true, |
| true)); |
| } |
| |
| TEST(DeLICM, distribute) { |
| std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(), |
| &isl_ctx_free); |
| |
| // Basic usage |
| EXPECT_EQ(MAP("{ [Domain[] -> Range1[]] -> [Domain[] -> Range2[]] }"), |
| distributeDomain(MAP("{ Domain[] -> [Range1[] -> Range2[]] }"))); |
| EXPECT_EQ( |
| MAP("{ [Domain[i,j] -> Range1[i,k]] -> [Domain[i,j] -> Range2[j,k]] }"), |
| distributeDomain(MAP("{ Domain[i,j] -> [Range1[i,k] -> Range2[j,k]] }"))); |
| |
| // Union maps |
| EXPECT_EQ( |
| UMAP( |
| "{ [DomainA[i,j] -> RangeA1[i,k]] -> [DomainA[i,j] -> RangeA2[j,k]];" |
| "[DomainB[i,j] -> RangeB1[i,k]] -> [DomainB[i,j] -> RangeB2[j,k]] }"), |
| distributeDomain( |
| UMAP("{ DomainA[i,j] -> [RangeA1[i,k] -> RangeA2[j,k]];" |
| "DomainB[i,j] -> [RangeB1[i,k] -> RangeB2[j,k]] }"))); |
| } |
| |
| TEST(DeLICM, lift) { |
| std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(), |
| &isl_ctx_free); |
| |
| // Basic usage |
| EXPECT_EQ(UMAP("{ [Factor[] -> Domain[]] -> [Factor[] -> Range[]] }"), |
| liftDomains(UMAP("{ Domain[] -> Range[] }"), USET("{ Factor[] }"))); |
| EXPECT_EQ(UMAP("{ [Factor[l] -> Domain[i,k]] -> [Factor[l] -> Range[j,k]] }"), |
| liftDomains(UMAP("{ Domain[i,k] -> Range[j,k] }"), |
| USET("{ Factor[l] }"))); |
| |
| // Multiple maps in union |
| EXPECT_EQ( |
| UMAP("{ [FactorA[] -> DomainA[]] -> [FactorA[] -> RangeA[]];" |
| "[FactorB[] -> DomainA[]] -> [FactorB[] -> RangeA[]];" |
| "[FactorA[] -> DomainB[]] -> [FactorA[] -> RangeB[]];" |
| "[FactorB[] -> DomainB[]] -> [FactorB[] -> RangeB[]] }"), |
| liftDomains(UMAP("{ DomainA[] -> RangeA[]; DomainB[] -> RangeB[] }"), |
| USET("{ FactorA[]; FactorB[] }"))); |
| } |
| |
| TEST(DeLICM, apply) { |
| std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(), |
| &isl_ctx_free); |
| |
| // Basic usage |
| EXPECT_EQ( |
| UMAP("{ [DomainDomain[] -> NewDomainRange[]] -> Range[] }"), |
| applyDomainRange(UMAP("{ [DomainDomain[] -> DomainRange[]] -> Range[] }"), |
| UMAP("{ DomainRange[] -> NewDomainRange[] }"))); |
| EXPECT_EQ( |
| UMAP("{ [DomainDomain[i,k] -> NewDomainRange[j,k,l]] -> Range[i,j] }"), |
| applyDomainRange( |
| UMAP("{ [DomainDomain[i,k] -> DomainRange[j,k]] -> Range[i,j] }"), |
| UMAP("{ DomainRange[j,k] -> NewDomainRange[j,k,l] }"))); |
| |
| // Multiple maps in union |
| EXPECT_EQ(UMAP("{ [DomainDomainA[] -> NewDomainRangeA[]] -> RangeA[];" |
| "[DomainDomainB[] -> NewDomainRangeB[]] -> RangeB[] }"), |
| applyDomainRange( |
| UMAP("{ [DomainDomainA[] -> DomainRangeA[]] -> RangeA[];" |
| "[DomainDomainB[] -> DomainRangeB[]] -> RangeB[] }"), |
| UMAP("{ DomainRangeA[] -> NewDomainRangeA[];" |
| "DomainRangeB[] -> NewDomainRangeB[] }"))); |
| } |
| |
| TEST(Isl, Quota) { |
| std::unique_ptr<isl_ctx, decltype(&isl_ctx_free)> Ctx(isl_ctx_alloc(), |
| &isl_ctx_free); |
| |
| isl::set TestSet1{Ctx.get(), "{ [0] }"}; |
| isl::set TestSet2{Ctx.get(), "{ [i] : i > 0 }"}; |
| |
| { |
| IslMaxOperationsGuard MaxOpGuard(Ctx.get(), 1); |
| ASSERT_EQ(isl_options_get_on_error(Ctx.get()), ISL_ON_ERROR_CONTINUE); |
| ASSERT_EQ(isl_ctx_get_max_operations(Ctx.get()), 1ul); |
| ASSERT_FALSE(MaxOpGuard.hasQuotaExceeded()); |
| |
| // Intentionally exceed the quota. Each allocation will use at least one |
| // operation, guaranteed to exceed the max_operations of 1. |
| isl::id::alloc(Ctx.get(), "A", nullptr); |
| isl::id::alloc(Ctx.get(), "B", nullptr); |
| ASSERT_TRUE(MaxOpGuard.hasQuotaExceeded()); |
| |
| // Check returned object after exceeded quota. |
| isl::set Union = TestSet1.unite(TestSet2); |
| EXPECT_TRUE(Union.is_null()); |
| |
| // Check isl::boolean result after exceeded quota. |
| isl::boolean BoolResult = TestSet1.is_empty(); |
| EXPECT_TRUE(BoolResult.is_error()); |
| EXPECT_FALSE(BoolResult.is_false()); |
| EXPECT_FALSE(BoolResult.is_true()); |
| EXPECT_DEATH((void)(bool)BoolResult, |
| "IMPLEMENTATION ERROR: Unhandled error state"); |
| EXPECT_DEATH((void)(bool)!BoolResult, |
| "IMPLEMENTATION ERROR: Unhandled error state"); |
| EXPECT_DEATH( |
| { |
| if (BoolResult) { |
| } |
| }, |
| "IMPLEMENTATION ERROR: Unhandled error state"); |
| EXPECT_DEATH((void)(BoolResult == false), |
| "IMPLEMENTATION ERROR: Unhandled error state"); |
| EXPECT_DEATH((void)(BoolResult == true), |
| "IMPLEMENTATION ERROR: Unhandled error state"); |
| |
| // Check isl::stat result after exceeded quota. |
| isl::stat StatResult = |
| TestSet1.foreach_point([](isl::point) { return isl::stat::ok(); }); |
| EXPECT_TRUE(StatResult.is_error()); |
| EXPECT_FALSE(StatResult.is_ok()); |
| } |
| ASSERT_EQ(isl_ctx_last_error(Ctx.get()), isl_error_quota); |
| ASSERT_EQ(isl_options_get_on_error(Ctx.get()), ISL_ON_ERROR_WARN); |
| ASSERT_EQ(isl_ctx_get_max_operations(Ctx.get()), 0ul); |
| |
| // Operations must work again after leaving the quota scope. |
| { |
| isl::set Union = TestSet1.unite(TestSet2); |
| EXPECT_FALSE(Union.is_null()); |
| |
| isl::boolean BoolResult = TestSet1.is_empty(); |
| EXPECT_FALSE(BoolResult.is_error()); |
| EXPECT_TRUE(BoolResult.is_false()); |
| EXPECT_FALSE(BoolResult.is_true()); |
| EXPECT_FALSE(BoolResult); |
| EXPECT_TRUE(!BoolResult); |
| |
| isl::stat StatResult = |
| TestSet1.foreach_point([](isl::point) { return isl::stat::ok(); }); |
| EXPECT_FALSE(StatResult.is_error()); |
| EXPECT_TRUE(StatResult.is_ok()); |
| } |
| } |
| |
| } // anonymous namespace |