1 /**
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <algorithm>
17 #include <vector>
18 #include "unit_test.h"
19
20 namespace panda::compiler {
21 class IteratorsTest : public GraphTest {
22 public:
23 static constexpr size_t INST_COUNT = 10;
24
25 public:
Check(std::vector<Inst * > & tested_instructions)26 void Check(std::vector<Inst *> &tested_instructions)
27 {
28 auto block = &BB(0);
29 PopulateBlock(block, tested_instructions);
30 InitExpectData(tested_instructions);
31
32 // Check InstForwardIterator
33 std::vector<Inst *> result;
34 for (auto inst : block->PhiInsts()) {
35 result.push_back(inst);
36 }
37 EXPECT_EQ(result, expect_phis_);
38
39 result.clear();
40 for (auto inst : block->Insts()) {
41 result.push_back(inst);
42 }
43 EXPECT_EQ(result, expect_insts_);
44
45 result.clear();
46 for (auto inst : block->AllInsts()) {
47 result.push_back(inst);
48 }
49 EXPECT_EQ(result, expect_all_);
50
51 // Check InstForwardValidIterator
52 result.clear();
53 for (auto inst : block->PhiInstsSafe()) {
54 result.push_back(inst);
55 }
56 EXPECT_EQ(result, expect_phis_);
57
58 result.clear();
59 for (auto inst : block->InstsSafe()) {
60 result.push_back(inst);
61 }
62 EXPECT_EQ(result, expect_insts_);
63
64 result.clear();
65 for (auto inst : block->AllInstsSafe()) {
66 result.push_back(inst);
67 }
68 EXPECT_EQ(result, expect_all_);
69
70 // Check InstBackwardValidIterator
71 result.clear();
72 for (auto inst : block->PhiInstsSafeReverse()) {
73 result.push_back(inst);
74 }
75 std::reverse(result.begin(), result.end());
76 EXPECT_EQ(result, expect_phis_);
77
78 result.clear();
79 for (auto inst : block->InstsSafeReverse()) {
80 result.push_back(inst);
81 }
82 std::reverse(result.begin(), result.end());
83 EXPECT_EQ(result, expect_insts_);
84
85 result.clear();
86 for (auto inst : block->AllInstsSafeReverse()) {
87 result.push_back(inst);
88 }
89 std::reverse(result.begin(), result.end());
90 EXPECT_EQ(result, expect_all_);
91
92 // Check InstForwardValidIterator with erasing instructions
93 result.clear();
94 for (auto inst : block->PhiInstsSafe()) {
95 result.push_back(inst);
96 block->EraseInst(inst);
97 }
98 EXPECT_EQ(result, expect_phis_);
99
100 result.clear();
101 for (auto inst : block->InstsSafe()) {
102 result.push_back(inst);
103 block->EraseInst(inst);
104 }
105 EXPECT_EQ(result, expect_insts_);
106
107 result.clear();
108 for (auto inst : block->AllInstsSafe()) {
109 result.push_back(inst);
110 }
111 EXPECT_EQ(result.size(), 0U);
112
113 PopulateBlock(block, tested_instructions);
114 for (auto inst : block->AllInstsSafe()) {
115 result.push_back(inst);
116 block->EraseInst(inst);
117 }
118 EXPECT_EQ(result, expect_all_);
119
120 // Check InstBackwardValidIterator with erasing instructions
121 PopulateBlock(block, tested_instructions);
122 result.clear();
123 for (auto inst : block->PhiInstsSafeReverse()) {
124 result.push_back(inst);
125 block->EraseInst(inst);
126 }
127 std::reverse(result.begin(), result.end());
128 EXPECT_EQ(result, expect_phis_);
129
130 result.clear();
131 for (auto inst : block->InstsSafeReverse()) {
132 result.push_back(inst);
133 block->EraseInst(inst);
134 }
135 std::reverse(result.begin(), result.end());
136 EXPECT_EQ(result, expect_insts_);
137
138 result.clear();
139 for (auto inst : block->AllInstsSafeReverse()) {
140 result.push_back(inst);
141 }
142 EXPECT_EQ(result.size(), 0U);
143
144 PopulateBlock(block, tested_instructions);
145 for (auto inst : block->AllInstsSafeReverse()) {
146 result.push_back(inst);
147 block->EraseInst(inst);
148 }
149 std::reverse(result.begin(), result.end());
150 EXPECT_EQ(result, expect_all_);
151 }
152
153 private:
InitExpectData(std::vector<Inst * > & instructions)154 void InitExpectData(std::vector<Inst *> &instructions)
155 {
156 expect_phis_.clear();
157 expect_insts_.clear();
158 expect_all_.clear();
159
160 for (auto inst : instructions) {
161 if (inst->IsPhi()) {
162 expect_phis_.push_back(inst);
163 } else {
164 expect_insts_.push_back(inst);
165 }
166 }
167 expect_all_.insert(expect_all_.end(), expect_phis_.begin(), expect_phis_.end());
168 expect_all_.insert(expect_all_.end(), expect_insts_.begin(), expect_insts_.end());
169 }
170
PopulateBlock(BasicBlock * block,std::vector<Inst * > & instructions)171 void PopulateBlock(BasicBlock *block, std::vector<Inst *> &instructions)
172 {
173 for (auto inst : instructions) {
174 if (inst->IsPhi()) {
175 block->AppendPhi(inst);
176 } else {
177 block->AppendInst(inst);
178 }
179 }
180 }
181
182 private:
183 std::vector<Inst *> expect_phis_;
184 std::vector<Inst *> expect_insts_;
185 std::vector<Inst *> expect_all_;
186 };
187
TEST_F(IteratorsTest,EmptyBlock)188 TEST_F(IteratorsTest, EmptyBlock)
189 {
190 GRAPH(GetGraph())
191 {
192 BASIC_BLOCK(2, -1)
193 {
194 INST(0, Opcode::ReturnVoid);
195 }
196 }
197 std::vector<Inst *> instructions;
198 Check(instructions);
199 }
200
TEST_F(IteratorsTest,BlockPhisInstructions)201 TEST_F(IteratorsTest, BlockPhisInstructions)
202 {
203 GRAPH(GetGraph())
204 {
205 BASIC_BLOCK(2, -1)
206 {
207 INST(0, Opcode::ReturnVoid);
208 }
209 }
210 std::vector<Inst *> instructions(IteratorsTest::INST_COUNT);
211 for (auto &inst : instructions) {
212 inst = GetGraph()->CreateInst(Opcode::Phi);
213 }
214 Check(instructions);
215 }
216
TEST_F(IteratorsTest,BlockNotPhisInstructions)217 TEST_F(IteratorsTest, BlockNotPhisInstructions)
218 {
219 GRAPH(GetGraph())
220 {
221 BASIC_BLOCK(2, -1)
222 {
223 INST(0, Opcode::ReturnVoid);
224 }
225 }
226 std::vector<Inst *> instructions(IteratorsTest::INST_COUNT);
227 for (auto &inst : instructions) {
228 inst = GetGraph()->CreateInst(Opcode::Add);
229 }
230 Check(instructions);
231 }
232
TEST_F(IteratorsTest,BlockAllInstructions)233 TEST_F(IteratorsTest, BlockAllInstructions)
234 {
235 GRAPH(GetGraph())
236 {
237 BASIC_BLOCK(2, -1)
238 {
239 INST(0, Opcode::ReturnVoid);
240 }
241 }
242 std::vector<Inst *> instructions(IteratorsTest::INST_COUNT);
243
244 // first instruction is phi
245 size_t i = 0;
246 for (auto &inst : instructions) {
247 if (++i % 2) {
248 inst = GetGraph()->CreateInst(Opcode::Phi);
249 } else {
250 inst = GetGraph()->CreateInst(Opcode::Add);
251 }
252 }
253 Check(instructions);
254 // first instruction is not phi
255 i = 1;
256 for (auto &inst : instructions) {
257 if (++i % 2) {
258 inst = GetGraph()->CreateInst(Opcode::Phi);
259 } else {
260 inst = GetGraph()->CreateInst(Opcode::Add);
261 }
262 }
263 Check(instructions);
264
265 // first instructions are phi
266 i = 0;
267 for (auto &inst : instructions) {
268 if (i < IteratorsTest::INST_COUNT / 2) {
269 inst = GetGraph()->CreateInst(Opcode::Phi);
270 } else {
271 inst = GetGraph()->CreateInst(Opcode::Add);
272 }
273 }
274 Check(instructions);
275
276 // first instructions are not phi
277 i = 0;
278 for (auto &inst : instructions) {
279 if (i >= IteratorsTest::INST_COUNT / 2) {
280 inst = GetGraph()->CreateInst(Opcode::Phi);
281 } else {
282 inst = GetGraph()->CreateInst(Opcode::Add);
283 }
284 }
285 Check(instructions);
286 }
287 } // namespace panda::compiler
288