SPIRV-Tools/test/opt/iterator_test.cpp
Victor Lomuller 0ec08c28c1 Add register liveness analysis.
For each function, the analysis determine which SSA registers are live
at the beginning of each basic block and which one are killed at
the end of the basic block.

It also includes utilities to simulate the register pressure for loop
fusion and fission.

The implementation is based on the paper "A non-iterative data-flow
algorithm for computing liveness sets in strict ssa programs" from
Boissinot et al.
2018-04-20 09:45:15 -04:00

267 lines
7.4 KiB
C++

// Copyright (c) 2016 Google Inc.
//
// 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 <memory>
#include <vector>
#include "gmock/gmock.h"
#include "opt/iterator.h"
#include "opt/make_unique.h"
namespace {
using namespace spvtools;
using ::testing::ContainerEq;
TEST(Iterator, IncrementDeref) {
const int count = 100;
std::vector<std::unique_ptr<int>> data;
for (int i = 0; i < count; ++i) {
data.emplace_back(new int(i));
}
ir::UptrVectorIterator<int> it(&data, data.begin());
ir::UptrVectorIterator<int> end(&data, data.end());
EXPECT_EQ(*data[0], *it);
for (int i = 1; i < count; ++i) {
EXPECT_NE(end, it);
EXPECT_EQ(*data[i], *(++it));
}
EXPECT_EQ(end, ++it);
}
TEST(Iterator, DecrementDeref) {
const int count = 100;
std::vector<std::unique_ptr<int>> data;
for (int i = 0; i < count; ++i) {
data.emplace_back(new int(i));
}
ir::UptrVectorIterator<int> begin(&data, data.begin());
ir::UptrVectorIterator<int> it(&data, data.end());
for (int i = count - 1; i >= 0; --i) {
EXPECT_NE(begin, it);
EXPECT_EQ(*data[i], *(--it));
}
EXPECT_EQ(begin, it);
}
TEST(Iterator, PostIncrementDeref) {
const int count = 100;
std::vector<std::unique_ptr<int>> data;
for (int i = 0; i < count; ++i) {
data.emplace_back(new int(i));
}
ir::UptrVectorIterator<int> it(&data, data.begin());
ir::UptrVectorIterator<int> end(&data, data.end());
for (int i = 0; i < count; ++i) {
EXPECT_NE(end, it);
EXPECT_EQ(*data[i], *(it++));
}
EXPECT_EQ(end, it);
}
TEST(Iterator, PostDecrementDeref) {
const int count = 100;
std::vector<std::unique_ptr<int>> data;
for (int i = 0; i < count; ++i) {
data.emplace_back(new int(i));
}
ir::UptrVectorIterator<int> begin(&data, data.begin());
ir::UptrVectorIterator<int> end(&data, data.end());
ir::UptrVectorIterator<int> it(&data, data.end());
EXPECT_EQ(end, it--);
for (int i = count - 1; i >= 1; --i) {
EXPECT_EQ(*data[i], *(it--));
}
// Decrementing .begin() is undefined behavior.
EXPECT_EQ(*data[0], *it);
}
TEST(Iterator, Access) {
const int count = 100;
std::vector<std::unique_ptr<int>> data;
for (int i = 0; i < count; ++i) {
data.emplace_back(new int(i));
}
ir::UptrVectorIterator<int> it(&data, data.begin());
for (int i = 0; i < count; ++i) EXPECT_EQ(*data[i], it[i]);
}
TEST(Iterator, Comparison) {
const int count = 100;
std::vector<std::unique_ptr<int>> data;
for (int i = 0; i < count; ++i) {
data.emplace_back(new int(i));
}
ir::UptrVectorIterator<int> it(&data, data.begin());
ir::UptrVectorIterator<int> end(&data, data.end());
for (int i = 0; i < count; ++i, ++it) EXPECT_TRUE(it < end);
EXPECT_EQ(end, it);
}
TEST(Iterator, InsertBeginEnd) {
const int count = 100;
std::vector<std::unique_ptr<int>> data;
std::vector<int> expected;
std::vector<int> actual;
for (int i = 0; i < count; ++i) {
data.emplace_back(new int(i));
expected.push_back(i);
}
// Insert at the beginning
expected.insert(expected.begin(), -100);
ir::UptrVectorIterator<int> begin(&data, data.begin());
auto insert_point = begin.InsertBefore(MakeUnique<int>(-100));
for (int i = 0; i < count + 1; ++i) {
actual.push_back(*(insert_point++));
}
EXPECT_THAT(actual, ContainerEq(expected));
// Insert at the end
expected.push_back(-42);
expected.push_back(-36);
expected.push_back(-77);
ir::UptrVectorIterator<int> end(&data, data.end());
end = end.InsertBefore(MakeUnique<int>(-77));
end = end.InsertBefore(MakeUnique<int>(-36));
end = end.InsertBefore(MakeUnique<int>(-42));
actual.clear();
begin = ir::UptrVectorIterator<int>(&data, data.begin());
for (int i = 0; i < count + 4; ++i) {
actual.push_back(*(begin++));
}
EXPECT_THAT(actual, ContainerEq(expected));
}
TEST(Iterator, InsertMiddle) {
const int count = 100;
std::vector<std::unique_ptr<int>> data;
std::vector<int> expected;
std::vector<int> actual;
for (int i = 0; i < count; ++i) {
data.emplace_back(new int(i));
expected.push_back(i);
}
const int insert_pos = 42;
expected.insert(expected.begin() + insert_pos, -100);
expected.insert(expected.begin() + insert_pos, -42);
ir::UptrVectorIterator<int> it(&data, data.begin());
for (int i = 0; i < insert_pos; ++i) ++it;
it = it.InsertBefore(MakeUnique<int>(-100));
it = it.InsertBefore(MakeUnique<int>(-42));
auto begin = ir::UptrVectorIterator<int>(&data, data.begin());
for (int i = 0; i < count + 2; ++i) {
actual.push_back(*(begin++));
}
EXPECT_THAT(actual, ContainerEq(expected));
}
TEST(IteratorRange, Interface) {
const uint32_t count = 100;
std::vector<std::unique_ptr<uint32_t>> data;
for (uint32_t i = 0; i < count; ++i) {
data.emplace_back(new uint32_t(i));
}
auto b = ir::UptrVectorIterator<uint32_t>(&data, data.begin());
auto e = ir::UptrVectorIterator<uint32_t>(&data, data.end());
auto range = ir::IteratorRange<decltype(b)>(b, e);
EXPECT_EQ(b, range.begin());
EXPECT_EQ(e, range.end());
EXPECT_FALSE(range.empty());
EXPECT_EQ(count, range.size());
EXPECT_EQ(0u, *range.begin());
EXPECT_EQ(99u, *(--range.end()));
// IteratorRange itself is immutable.
++b, --e;
EXPECT_EQ(count, range.size());
++range.begin(), --range.end();
EXPECT_EQ(count, range.size());
}
TEST(Iterator, FilterIterator) {
struct Placeholder {
int val;
};
std::vector<Placeholder> data = {{1}, {2}, {3}, {4}, {5},
{6}, {7}, {8}, {9}, {10}};
// Predicate to only consider odd values.
struct Predicate {
bool operator()(const Placeholder& data) { return data.val % 2; }
};
Predicate pred;
auto filter_range =
ir::MakeFilterIteratorRange(data.begin(), data.end(), pred);
EXPECT_EQ(filter_range.begin().Get(), data.begin());
EXPECT_EQ(filter_range.end(), filter_range.begin().GetEnd());
for (Placeholder& data : filter_range) {
EXPECT_EQ(data.val % 2, 1);
}
for (auto it = filter_range.begin(); it != filter_range.end(); it++) {
EXPECT_EQ(it->val % 2, 1);
EXPECT_EQ((*it).val % 2, 1);
}
for (auto it = filter_range.begin(); it != filter_range.end(); ++it) {
EXPECT_EQ(it->val % 2, 1);
EXPECT_EQ((*it).val % 2, 1);
}
EXPECT_EQ(ir::MakeFilterIterator(data.begin(), data.end(), pred).Get(),
data.begin());
EXPECT_EQ(ir::MakeFilterIterator(data.end(), data.end(), pred).Get(),
data.end());
EXPECT_EQ(ir::MakeFilterIterator(data.begin(), data.end(), pred).GetEnd(),
ir::MakeFilterIterator(data.end(), data.end(), pred));
EXPECT_NE(ir::MakeFilterIterator(data.begin(), data.end(), pred),
ir::MakeFilterIterator(data.end(), data.end(), pred));
// Empty range: no values satisfies the predicate.
auto empty_range = ir::MakeFilterIteratorRange(
data.begin(), data.end(),
[](const Placeholder& data) { return data.val > 10; });
EXPECT_EQ(empty_range.begin(), empty_range.end());
}
} // anonymous namespace