1fd4e5da5Sopenharmony_ci// Copyright (c) 2017 Google Inc.
2fd4e5da5Sopenharmony_ci//
3fd4e5da5Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License");
4fd4e5da5Sopenharmony_ci// you may not use this file except in compliance with the License.
5fd4e5da5Sopenharmony_ci// You may obtain a copy of the License at
6fd4e5da5Sopenharmony_ci//
7fd4e5da5Sopenharmony_ci//     http://www.apache.org/licenses/LICENSE-2.0
8fd4e5da5Sopenharmony_ci//
9fd4e5da5Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software
10fd4e5da5Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS,
11fd4e5da5Sopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12fd4e5da5Sopenharmony_ci// See the License for the specific language governing permissions and
13fd4e5da5Sopenharmony_ci// limitations under the License.
14fd4e5da5Sopenharmony_ci
15fd4e5da5Sopenharmony_ci#include <algorithm>
16fd4e5da5Sopenharmony_ci#include <memory>
17fd4e5da5Sopenharmony_ci#include <utility>
18fd4e5da5Sopenharmony_ci#include <vector>
19fd4e5da5Sopenharmony_ci
20fd4e5da5Sopenharmony_ci#include "gmock/gmock.h"
21fd4e5da5Sopenharmony_ci#include "gtest/gtest.h"
22fd4e5da5Sopenharmony_ci#include "source/opt/instruction.h"
23fd4e5da5Sopenharmony_ci#include "source/opt/instruction_list.h"
24fd4e5da5Sopenharmony_ci
25fd4e5da5Sopenharmony_cinamespace spvtools {
26fd4e5da5Sopenharmony_cinamespace opt {
27fd4e5da5Sopenharmony_cinamespace {
28fd4e5da5Sopenharmony_ci
29fd4e5da5Sopenharmony_ciusing ::testing::ContainerEq;
30fd4e5da5Sopenharmony_ciusing ::testing::ElementsAre;
31fd4e5da5Sopenharmony_ciusing InstructionListTest = ::testing::Test;
32fd4e5da5Sopenharmony_ci
33fd4e5da5Sopenharmony_ci// A class that overrides the destructor, so we can trace it.
34fd4e5da5Sopenharmony_ciclass TestInstruction : public Instruction {
35fd4e5da5Sopenharmony_ci public:
36fd4e5da5Sopenharmony_ci  TestInstruction() : Instruction() { created_instructions_.push_back(this); }
37fd4e5da5Sopenharmony_ci
38fd4e5da5Sopenharmony_ci  ~TestInstruction() override{ deleted_instructions_.push_back(this); }
39fd4e5da5Sopenharmony_ci
40fd4e5da5Sopenharmony_ci  static std::vector<TestInstruction*> created_instructions_;
41fd4e5da5Sopenharmony_ci  static std::vector<TestInstruction*> deleted_instructions_;
42fd4e5da5Sopenharmony_ci};
43fd4e5da5Sopenharmony_ci
44fd4e5da5Sopenharmony_cistd::vector<TestInstruction*> TestInstruction::created_instructions_;
45fd4e5da5Sopenharmony_cistd::vector<TestInstruction*> TestInstruction::deleted_instructions_;
46fd4e5da5Sopenharmony_ci
47fd4e5da5Sopenharmony_ci// Test that the destructor for InstructionList is calling the destructor
48fd4e5da5Sopenharmony_ci// for every element that is in the list.
49fd4e5da5Sopenharmony_ciTEST(InstructionListTest, Destructor) {
50fd4e5da5Sopenharmony_ci  InstructionList* list = new InstructionList();
51fd4e5da5Sopenharmony_ci  list->push_back(std::unique_ptr<Instruction>(new Instruction()));
52fd4e5da5Sopenharmony_ci  list->push_back(std::unique_ptr<Instruction>(new Instruction()));
53fd4e5da5Sopenharmony_ci  delete list;
54fd4e5da5Sopenharmony_ci
55fd4e5da5Sopenharmony_ci  // Sorting because we do not care if the order of create and destruction is
56fd4e5da5Sopenharmony_ci  // the same.  Using generic sort just incase things are changed above.
57fd4e5da5Sopenharmony_ci  std::sort(TestInstruction::created_instructions_.begin(),
58fd4e5da5Sopenharmony_ci            TestInstruction::created_instructions_.end());
59fd4e5da5Sopenharmony_ci  std::sort(TestInstruction::deleted_instructions_.begin(),
60fd4e5da5Sopenharmony_ci            TestInstruction::deleted_instructions_.end());
61fd4e5da5Sopenharmony_ci  EXPECT_THAT(TestInstruction::created_instructions_,
62fd4e5da5Sopenharmony_ci              ContainerEq(TestInstruction::deleted_instructions_));
63fd4e5da5Sopenharmony_ci}
64fd4e5da5Sopenharmony_ci
65fd4e5da5Sopenharmony_ci// Test the |InsertBefore| with a single instruction in the iterator class.
66fd4e5da5Sopenharmony_ci// Need to make sure the elements are inserted in the correct order, and the
67fd4e5da5Sopenharmony_ci// return value points to the correct location.
68fd4e5da5Sopenharmony_ci//
69fd4e5da5Sopenharmony_ci// Comparing addresses to make sure they remain stable, so other data structures
70fd4e5da5Sopenharmony_ci// can have pointers to instructions in InstructionList.
71fd4e5da5Sopenharmony_ciTEST(InstructionListTest, InsertBefore1) {
72fd4e5da5Sopenharmony_ci  InstructionList list;
73fd4e5da5Sopenharmony_ci  std::vector<Instruction*> inserted_instructions;
74fd4e5da5Sopenharmony_ci  for (int i = 0; i < 4; i++) {
75fd4e5da5Sopenharmony_ci    std::unique_ptr<Instruction> inst(new Instruction());
76fd4e5da5Sopenharmony_ci    inserted_instructions.push_back(inst.get());
77fd4e5da5Sopenharmony_ci    auto new_element = list.end().InsertBefore(std::move(inst));
78fd4e5da5Sopenharmony_ci    EXPECT_EQ(&*new_element, inserted_instructions.back());
79fd4e5da5Sopenharmony_ci  }
80fd4e5da5Sopenharmony_ci
81fd4e5da5Sopenharmony_ci  std::vector<Instruction*> output;
82fd4e5da5Sopenharmony_ci  for (auto& i : list) {
83fd4e5da5Sopenharmony_ci    output.push_back(&i);
84fd4e5da5Sopenharmony_ci  }
85fd4e5da5Sopenharmony_ci  EXPECT_THAT(output, ContainerEq(inserted_instructions));
86fd4e5da5Sopenharmony_ci}
87fd4e5da5Sopenharmony_ci
88fd4e5da5Sopenharmony_ci// Test inserting an entire vector of instructions using InsertBefore.  Checking
89fd4e5da5Sopenharmony_ci// the order of insertion and the return value.
90fd4e5da5Sopenharmony_ci//
91fd4e5da5Sopenharmony_ci// Comparing addresses to make sure they remain stable, so other data structures
92fd4e5da5Sopenharmony_ci// can have pointers to instructions in InstructionList.
93fd4e5da5Sopenharmony_ciTEST(InstructionListTest, InsertBefore2) {
94fd4e5da5Sopenharmony_ci  InstructionList list;
95fd4e5da5Sopenharmony_ci  std::vector<std::unique_ptr<Instruction>> new_instructions;
96fd4e5da5Sopenharmony_ci  std::vector<Instruction*> created_instructions;
97fd4e5da5Sopenharmony_ci  for (int i = 0; i < 4; i++) {
98fd4e5da5Sopenharmony_ci    std::unique_ptr<Instruction> inst(new Instruction());
99fd4e5da5Sopenharmony_ci    created_instructions.push_back(inst.get());
100fd4e5da5Sopenharmony_ci    new_instructions.push_back(std::move(inst));
101fd4e5da5Sopenharmony_ci  }
102fd4e5da5Sopenharmony_ci  auto new_element = list.begin().InsertBefore(std::move(new_instructions));
103fd4e5da5Sopenharmony_ci  EXPECT_TRUE(new_instructions.empty());
104fd4e5da5Sopenharmony_ci  EXPECT_EQ(&*new_element, created_instructions.front());
105fd4e5da5Sopenharmony_ci
106fd4e5da5Sopenharmony_ci  std::vector<Instruction*> output;
107fd4e5da5Sopenharmony_ci  for (auto& i : list) {
108fd4e5da5Sopenharmony_ci    output.push_back(&i);
109fd4e5da5Sopenharmony_ci  }
110fd4e5da5Sopenharmony_ci  EXPECT_THAT(output, ContainerEq(created_instructions));
111fd4e5da5Sopenharmony_ci}
112fd4e5da5Sopenharmony_ci
113fd4e5da5Sopenharmony_ci}  // namespace
114fd4e5da5Sopenharmony_ci}  // namespace opt
115fd4e5da5Sopenharmony_ci}  // namespace spvtools
116