mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
* Adding @transpose attr deserialization support * Turning on the transpose serialization test * Adding the autodiff unittests
329 lines
13 KiB
C++
329 lines
13 KiB
C++
//===--------------------- IndexSubsetTests.cpp ---------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2019 - 2020 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/AST/IndexSubset.h"
|
|
#include "TestContext.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
using namespace swift;
|
|
using namespace swift::unittest;
|
|
|
|
TEST(IndexSubset, NumBitWordsNeeded) {
|
|
EXPECT_EQ(IndexSubset::getNumBitWordsNeededForCapacity(0), 0u);
|
|
EXPECT_EQ(IndexSubset::getNumBitWordsNeededForCapacity(1), 1u);
|
|
EXPECT_EQ(IndexSubset::getNumBitWordsNeededForCapacity(5), 1u);
|
|
EXPECT_EQ(IndexSubset::getNumBitWordsNeededForCapacity(
|
|
IndexSubset::numBitsPerBitWord - 1), 1u);
|
|
EXPECT_EQ(IndexSubset::getNumBitWordsNeededForCapacity(
|
|
IndexSubset::numBitsPerBitWord), 2u);
|
|
EXPECT_EQ(IndexSubset::getNumBitWordsNeededForCapacity(
|
|
IndexSubset::numBitsPerBitWord * 2 - 1), 2u);
|
|
EXPECT_EQ(IndexSubset::getNumBitWordsNeededForCapacity(
|
|
IndexSubset::numBitsPerBitWord * 2), 3u);
|
|
}
|
|
|
|
TEST(IndexSubset, BitWordIndexAndOffset) {
|
|
EXPECT_EQ(IndexSubset::getBitWordIndexAndOffset(0),
|
|
std::make_pair(0u, 0u));
|
|
EXPECT_EQ(IndexSubset::getBitWordIndexAndOffset(5),
|
|
std::make_pair(0u, 5u));
|
|
EXPECT_EQ(IndexSubset::getBitWordIndexAndOffset(8),
|
|
std::make_pair(0u, 8u));
|
|
EXPECT_EQ(IndexSubset::getBitWordIndexAndOffset(
|
|
IndexSubset::numBitsPerBitWord - 1),
|
|
std::make_pair(0u, IndexSubset::numBitsPerBitWord - 1));
|
|
EXPECT_EQ(IndexSubset::getBitWordIndexAndOffset(
|
|
IndexSubset::numBitsPerBitWord),
|
|
std::make_pair(1u, 0u));
|
|
}
|
|
|
|
TEST(IndexSubset, Equality) {
|
|
TestContext ctx;
|
|
EXPECT_EQ(IndexSubset::get(ctx.Ctx, /*capacity*/ 5, /*indices*/ {0}),
|
|
IndexSubset::get(ctx.Ctx, /*capacity*/ 5, /*indices*/ {0}));
|
|
EXPECT_EQ(IndexSubset::get(ctx.Ctx, /*capacity*/ 5, /*indices*/ {0, 2, 4}),
|
|
IndexSubset::get(ctx.Ctx, /*capacity*/ 5, /*indices*/ {0, 2, 4}));
|
|
EXPECT_EQ(IndexSubset::get(ctx.Ctx, /*capacity*/ 5, /*indices*/ {}),
|
|
IndexSubset::get(ctx.Ctx, /*capacity*/ 5, /*indices*/ {}));
|
|
EXPECT_NE(IndexSubset::get(ctx.Ctx, /*capacity*/ 1, /*indices*/ {}),
|
|
IndexSubset::get(ctx.Ctx, /*capacity*/ 0, /*indices*/ {}));
|
|
EXPECT_NE(IndexSubset::get(ctx.Ctx, /*capacity*/ 5, /*indices*/ {0}),
|
|
IndexSubset::get(ctx.Ctx, /*capacity*/ 5, /*indices*/ {}));
|
|
}
|
|
|
|
TEST(IndexSubset, Initializers) {
|
|
TestContext ctx;
|
|
// Default init.
|
|
EXPECT_EQ(IndexSubset::getDefault(ctx.Ctx, /*capacity*/ 5,
|
|
/*includeAll*/ true),
|
|
IndexSubset::get(ctx.Ctx, /*capacity*/ 5,
|
|
/*indices*/ {0, 1, 2, 3, 4}));
|
|
EXPECT_EQ(IndexSubset::getDefault(ctx.Ctx, /*capacity*/ 5,
|
|
/*includeAll*/ false),
|
|
IndexSubset::get(ctx.Ctx, /*capacity*/ 5, /*indices*/ {}));
|
|
EXPECT_EQ(IndexSubset::getDefault(ctx.Ctx, /*capacity*/ 0,
|
|
/*includeAll*/ true),
|
|
IndexSubset::get(ctx.Ctx, /*capacity*/ 0, /*indices*/ {}));
|
|
EXPECT_EQ(IndexSubset::getDefault(ctx.Ctx, /*capacity*/ 0,
|
|
/*includeAll*/ false),
|
|
IndexSubset::get(ctx.Ctx, /*capacity*/ 0, /*indices*/ {}));
|
|
// Bit vector init.
|
|
{
|
|
llvm::SmallBitVector bitVec(6);
|
|
bitVec.set(1, 4);
|
|
EXPECT_EQ(IndexSubset::get(ctx.Ctx, bitVec),
|
|
IndexSubset::get(ctx.Ctx, /*capacity*/ 6, /*indices*/ {1, 2, 3}));
|
|
}
|
|
{
|
|
llvm::SmallBitVector bitVec(0);
|
|
EXPECT_EQ(IndexSubset::get(ctx.Ctx, bitVec),
|
|
IndexSubset::get(ctx.Ctx, /*capacity*/ 0, /*indices*/ {}));
|
|
}
|
|
// String init.
|
|
EXPECT_EQ(IndexSubset::getFromString(ctx.Ctx, "SSSSS"),
|
|
IndexSubset::get(ctx.Ctx, /*capacity*/ 5,
|
|
/*indices*/ {0, 1, 2, 3, 4}));
|
|
EXPECT_EQ(IndexSubset::getFromString(ctx.Ctx, "UUUUU"),
|
|
IndexSubset::get(ctx.Ctx, /*capacity*/ 5, /*indices*/ {}));
|
|
EXPECT_EQ(IndexSubset::getFromString(ctx.Ctx, "SUSUS"),
|
|
IndexSubset::get(ctx.Ctx, /*capacity*/ 5,
|
|
/*indices*/ {0, 2, 4}));
|
|
EXPECT_EQ(IndexSubset::getFromString(ctx.Ctx, ""),
|
|
IndexSubset::get(ctx.Ctx, /*capacity*/ 0, /*indices*/ {}));
|
|
}
|
|
|
|
TEST(IndexSubset, Bits) {
|
|
TestContext ctx;
|
|
auto *indices1 = IndexSubset::get(ctx.Ctx, /*capacity*/ 5,
|
|
/*indices*/ {0, 2, 4});
|
|
EXPECT_EQ(indices1->getNumBitWords(), 1u);
|
|
EXPECT_EQ(indices1->getCapacity(), 5u);
|
|
EXPECT_TRUE(indices1->contains(0));
|
|
EXPECT_FALSE(indices1->contains(1));
|
|
EXPECT_TRUE(indices1->contains(2));
|
|
EXPECT_FALSE(indices1->contains(3));
|
|
EXPECT_TRUE(indices1->contains(4));
|
|
|
|
auto *indices2 = IndexSubset::get(ctx.Ctx, /*capacity*/ 5,
|
|
/*indices*/ {1, 3});
|
|
EXPECT_EQ(indices2->getNumBitWords(), 1u);
|
|
EXPECT_EQ(indices2->getCapacity(), 5u);
|
|
EXPECT_FALSE(indices2->contains(0));
|
|
EXPECT_TRUE(indices2->contains(1));
|
|
EXPECT_FALSE(indices2->contains(2));
|
|
EXPECT_TRUE(indices2->contains(3));
|
|
EXPECT_FALSE(indices2->contains(4));
|
|
}
|
|
|
|
TEST(IndexSubset, Iteration) {
|
|
TestContext ctx;
|
|
// Test 1
|
|
{
|
|
auto *indices1 = IndexSubset::get(ctx.Ctx, /*capacity*/ 5,
|
|
/*indices*/ {0, 2, 4});
|
|
// Check forward iteration.
|
|
EXPECT_EQ(indices1->findFirst(), 0);
|
|
EXPECT_EQ(indices1->findNext(0), 2);
|
|
EXPECT_EQ(indices1->findNext(2), 4);
|
|
EXPECT_EQ(indices1->findNext(4), (int)indices1->getCapacity());
|
|
// Check reverse iteration.
|
|
EXPECT_EQ(indices1->findLast(), 4);
|
|
EXPECT_EQ(indices1->findPrevious(4), 2);
|
|
EXPECT_EQ(indices1->findPrevious(2), 0);
|
|
EXPECT_EQ(indices1->findPrevious(0), -1);
|
|
// Check range.
|
|
unsigned indices1Elements[3] = {0, 2, 4};
|
|
EXPECT_TRUE(std::equal(indices1->begin(), indices1->end(),
|
|
indices1Elements));
|
|
}
|
|
// Test 2
|
|
{
|
|
auto *indices2 = IndexSubset::get(ctx.Ctx, /*capacity*/ 5,
|
|
/*indices*/ {1, 3});
|
|
// Check forward iteration.
|
|
EXPECT_EQ(indices2->findFirst(), 1);
|
|
EXPECT_EQ(indices2->findNext(1), 3);
|
|
EXPECT_EQ(indices2->findNext(3), (int)indices2->getCapacity());
|
|
// Check reverse iteration.
|
|
EXPECT_EQ(indices2->findLast(), 3);
|
|
EXPECT_EQ(indices2->findPrevious(3), 1);
|
|
EXPECT_EQ(indices2->findPrevious(1), -1);
|
|
// Check range.
|
|
unsigned indices2Elements[2] = {1, 3};
|
|
EXPECT_TRUE(std::equal(indices2->begin(), indices2->end(),
|
|
indices2Elements));
|
|
}
|
|
}
|
|
|
|
TEST(IndexSubset, SupersetAndSubset) {
|
|
TestContext ctx;
|
|
auto *indices1 = IndexSubset::get(ctx.Ctx, /*capacity*/ 5,
|
|
/*indices*/ {0, 2, 4});
|
|
EXPECT_TRUE(indices1->isSupersetOf(indices1));
|
|
EXPECT_TRUE(indices1->isSubsetOf(indices1));
|
|
auto *indices2 = IndexSubset::get(ctx.Ctx, /*capacity*/ 5, /*indices*/ {2});
|
|
EXPECT_TRUE(indices2->isSupersetOf(indices2));
|
|
EXPECT_TRUE(indices2->isSubsetOf(indices2));
|
|
|
|
EXPECT_TRUE(indices1->isSupersetOf(indices2));
|
|
EXPECT_TRUE(indices2->isSubsetOf(indices1));
|
|
}
|
|
|
|
TEST(IndexSubset, Insertion) {
|
|
TestContext ctx;
|
|
auto *indices1 = IndexSubset::get(ctx.Ctx, 5, {0, 2, 4});
|
|
EXPECT_EQ(indices1->adding(0, ctx.Ctx), indices1);
|
|
EXPECT_EQ(indices1->adding(1, ctx.Ctx),
|
|
IndexSubset::get(ctx.Ctx, 5, {0, 1, 2, 4}));
|
|
EXPECT_EQ(indices1->adding(3, ctx.Ctx),
|
|
IndexSubset::get(ctx.Ctx, 5, {0, 2, 3, 4}));
|
|
}
|
|
|
|
TEST(IndexSubset, FindNext) {
|
|
TestContext ctx;
|
|
auto *indices1 = IndexSubset::get(ctx.Ctx, 5, {1, 2, 4});
|
|
EXPECT_EQ(indices1->findFirst(), 1);
|
|
EXPECT_EQ(indices1->findNext(/*startIndex*/ -1), 1);
|
|
EXPECT_EQ(indices1->findNext(/*startIndex*/ 0), 1);
|
|
EXPECT_EQ(indices1->findNext(/*startIndex*/ 1), 2);
|
|
EXPECT_EQ(indices1->findNext(/*startIndex*/ 2), 4);
|
|
EXPECT_EQ(indices1->findNext(/*startIndex*/ 3), 4);
|
|
}
|
|
|
|
TEST(IndexSubset, FindPrevious) {
|
|
TestContext ctx;
|
|
auto *indices1 = IndexSubset::get(ctx.Ctx, 5, {0, 2, 4});
|
|
EXPECT_EQ(indices1->findLast(), 4);
|
|
EXPECT_EQ(indices1->findPrevious(/*endIndex*/ 5), 4);
|
|
EXPECT_EQ(indices1->findPrevious(/*endIndex*/ 4), 2);
|
|
EXPECT_EQ(indices1->findPrevious(/*endIndex*/ 3), 2);
|
|
EXPECT_EQ(indices1->findPrevious(/*endIndex*/ 2), 0);
|
|
EXPECT_EQ(indices1->findPrevious(/*endIndex*/ 1), 0);
|
|
EXPECT_EQ(indices1->findPrevious(/*endIndex*/ 0), -1);
|
|
}
|
|
|
|
TEST(IndexSubset, Lowering) {
|
|
TestContext testCtx;
|
|
auto &C = testCtx.Ctx;
|
|
// ((T, T)) -> ()
|
|
EXPECT_EQ(
|
|
autodiff::getLoweredParameterIndices(
|
|
IndexSubset::get(C, 1, {0}),
|
|
FunctionType::get({
|
|
FunctionType::Param(
|
|
TupleType::get({C.TheAnyType, C.TheAnyType}, C))},
|
|
C.TheEmptyTupleType)),
|
|
IndexSubset::get(C, 2, {0, 1}));
|
|
// ((), (T, T)) -> ()
|
|
EXPECT_EQ(
|
|
autodiff::getLoweredParameterIndices(
|
|
IndexSubset::get(C, 2, {1}),
|
|
FunctionType::get({
|
|
FunctionType::Param(C.TheEmptyTupleType),
|
|
FunctionType::Param(
|
|
TupleType::get({C.TheAnyType, C.TheAnyType}, C))},
|
|
C.TheEmptyTupleType)),
|
|
IndexSubset::get(C, 2, {0, 1}));
|
|
// (T, (T, T)) -> ()
|
|
EXPECT_EQ(
|
|
autodiff::getLoweredParameterIndices(
|
|
IndexSubset::get(C, 2, {1}),
|
|
FunctionType::get({
|
|
FunctionType::Param(C.TheAnyType),
|
|
FunctionType::Param(
|
|
TupleType::get({C.TheAnyType, C.TheAnyType}, C))},
|
|
C.TheEmptyTupleType)),
|
|
IndexSubset::get(C, 3, {1, 2}));
|
|
// (T, (T, T)) -> ()
|
|
EXPECT_EQ(
|
|
autodiff::getLoweredParameterIndices(
|
|
IndexSubset::get(C, 2, {0, 1}),
|
|
FunctionType::get({
|
|
FunctionType::Param(C.TheAnyType),
|
|
FunctionType::Param(
|
|
TupleType::get({C.TheAnyType, C.TheAnyType}, C))},
|
|
C.TheEmptyTupleType)),
|
|
IndexSubset::get(C, 3, {0, 1, 2}));
|
|
// (T, ((T, T)), (T, T), T) -> ()
|
|
EXPECT_EQ(
|
|
autodiff::getLoweredParameterIndices(
|
|
IndexSubset::get(C, 4, {0, 1, 3}),
|
|
FunctionType::get({
|
|
FunctionType::Param(C.TheAnyType),
|
|
FunctionType::Param(
|
|
TupleType::get({
|
|
TupleType::get({C.TheAnyType, C.TheAnyType}, C)}, C)),
|
|
FunctionType::Param(
|
|
TupleType::get({C.TheAnyType, C.TheAnyType}, C)),
|
|
FunctionType::Param(C.TheAnyType)},
|
|
C.TheEmptyTupleType)),
|
|
IndexSubset::get(C, 6, {0, 1, 2, 5}));
|
|
// Method (T) -> ((T, T), (T, T), T) -> ()
|
|
// TODO(TF-874): Fix this unit test.
|
|
// The current actual result is:
|
|
// `(autodiff_index_subset capacity=6 indices=(0, 1, 4))`.
|
|
#if 0
|
|
EXPECT_EQ(
|
|
autodiff::getLoweredParameterIndices(
|
|
IndexSubset::get(C, 4, {0, 1, 3}),
|
|
FunctionType::get(
|
|
{FunctionType::Param(C.TheAnyType)},
|
|
FunctionType::get({
|
|
FunctionType::Param(
|
|
TupleType::get({C.TheAnyType, C.TheAnyType}, C)),
|
|
FunctionType::Param(
|
|
TupleType::get({C.TheAnyType, C.TheAnyType}, C)),
|
|
FunctionType::Param(C.TheAnyType)},
|
|
C.TheEmptyTupleType)->withExtInfo(
|
|
FunctionType::ExtInfo().withSILRepresentation(
|
|
SILFunctionTypeRepresentation::Method)))),
|
|
IndexSubset::get(C, 6, {0, 1, 4, 5}));
|
|
#endif
|
|
}
|
|
|
|
TEST(IndexSubset, GetSubsetParameterTypes) {
|
|
TestContext testCtx;
|
|
auto &C = testCtx.Ctx;
|
|
// (T, T) -> ()
|
|
{
|
|
SmallVector<AnyFunctionType::Param, 8> params;
|
|
auto *functionType = FunctionType::get({FunctionType::Param(C.TheAnyType),
|
|
FunctionType::Param(C.TheAnyType)},
|
|
C.TheEmptyTupleType);
|
|
functionType->getSubsetParameters(IndexSubset::get(C, 1, {0}), params);
|
|
AnyFunctionType::Param expected[] = {AnyFunctionType::Param(C.TheAnyType)};
|
|
EXPECT_TRUE(std::equal(params.begin(), params.end(), expected,
|
|
[](auto param1, auto param2) {
|
|
return param1.getPlainType()->isEqual(param2.getPlainType());
|
|
}));
|
|
}
|
|
// (T) -> (T, T) -> ()
|
|
{
|
|
SmallVector<AnyFunctionType::Param, 8> params;
|
|
auto *functionType =
|
|
FunctionType::get({FunctionType::Param(C.TheIEEE16Type)},
|
|
FunctionType::get({FunctionType::Param(C.TheAnyType),
|
|
FunctionType::Param(C.TheAnyType)},
|
|
C.TheEmptyTupleType));
|
|
functionType->getSubsetParameters(IndexSubset::get(C, 3, {0, 1, 2}),
|
|
params);
|
|
AnyFunctionType::Param expected[] = {
|
|
AnyFunctionType::Param(C.TheIEEE16Type),
|
|
AnyFunctionType::Param(C.TheAnyType),
|
|
AnyFunctionType::Param(C.TheAnyType)};
|
|
EXPECT_TRUE(std::equal(
|
|
params.begin(), params.end(), expected, [](auto param1, auto param2) {
|
|
return param1.getPlainType()->isEqual(param2.getPlainType());
|
|
}));
|
|
}
|
|
}
|