1//===- llvm/unittests/Transforms/Vectorize/VPlanTest.cpp - VPlan tests ----===//
2//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10#include "../lib/Transforms/Vectorize/VPlan.h"
11#include "../lib/Transforms/Vectorize/VPlanCFG.h"
12#include "llvm/ADT/DepthFirstIterator.h"
13#include "llvm/ADT/PostOrderIterator.h"
14#include "llvm/Analysis/VectorUtils.h"
15#include "llvm/IR/Instruction.h"
16#include "llvm/IR/Instructions.h"
17#include "gtest/gtest.h"
18#include <string>
19
20namespace llvm {
21namespace {
22
23#define CHECK_ITERATOR(Range1, ...) \
24 do { \
25 std::vector<VPInstruction *> Tmp = {__VA_ARGS__}; \
26 EXPECT_EQ((size_t)std::distance(Range1.begin(), Range1.end()), \
27 Tmp.size()); \
28 for (auto Pair : zip(Range1, make_range(Tmp.begin(), Tmp.end()))) \
29 EXPECT_EQ(&std::get<0>(Pair), std::get<1>(Pair)); \
30 } while (0)
31
32TEST(VPInstructionTest, insertBefore) {
33 VPInstruction *I1 = new VPInstruction(0, {});
34 VPInstruction *I2 = new VPInstruction(1, {});
35 VPInstruction *I3 = new VPInstruction(2, {});
36
37 VPBasicBlock VPBB1;
38 VPBB1.appendRecipe(Recipe: I1);
39
40 I2->insertBefore(InsertPos: I1);
41 CHECK_ITERATOR(VPBB1, I2, I1);
42
43 I3->insertBefore(InsertPos: I2);
44 CHECK_ITERATOR(VPBB1, I3, I2, I1);
45}
46
47TEST(VPInstructionTest, eraseFromParent) {
48 VPInstruction *I1 = new VPInstruction(0, {});
49 VPInstruction *I2 = new VPInstruction(1, {});
50 VPInstruction *I3 = new VPInstruction(2, {});
51
52 VPBasicBlock VPBB1;
53 VPBB1.appendRecipe(Recipe: I1);
54 VPBB1.appendRecipe(Recipe: I2);
55 VPBB1.appendRecipe(Recipe: I3);
56
57 I2->eraseFromParent();
58 CHECK_ITERATOR(VPBB1, I1, I3);
59
60 I1->eraseFromParent();
61 CHECK_ITERATOR(VPBB1, I3);
62
63 I3->eraseFromParent();
64 EXPECT_TRUE(VPBB1.empty());
65}
66
67TEST(VPInstructionTest, moveAfter) {
68 VPInstruction *I1 = new VPInstruction(0, {});
69 VPInstruction *I2 = new VPInstruction(1, {});
70 VPInstruction *I3 = new VPInstruction(2, {});
71
72 VPBasicBlock VPBB1;
73 VPBB1.appendRecipe(Recipe: I1);
74 VPBB1.appendRecipe(Recipe: I2);
75 VPBB1.appendRecipe(Recipe: I3);
76
77 I1->moveAfter(MovePos: I2);
78
79 CHECK_ITERATOR(VPBB1, I2, I1, I3);
80
81 VPInstruction *I4 = new VPInstruction(4, {});
82 VPInstruction *I5 = new VPInstruction(5, {});
83 VPBasicBlock VPBB2;
84 VPBB2.appendRecipe(Recipe: I4);
85 VPBB2.appendRecipe(Recipe: I5);
86
87 I3->moveAfter(MovePos: I4);
88
89 CHECK_ITERATOR(VPBB1, I2, I1);
90 CHECK_ITERATOR(VPBB2, I4, I3, I5);
91 EXPECT_EQ(I3->getParent(), I4->getParent());
92}
93
94TEST(VPInstructionTest, moveBefore) {
95 VPInstruction *I1 = new VPInstruction(0, {});
96 VPInstruction *I2 = new VPInstruction(1, {});
97 VPInstruction *I3 = new VPInstruction(2, {});
98
99 VPBasicBlock VPBB1;
100 VPBB1.appendRecipe(Recipe: I1);
101 VPBB1.appendRecipe(Recipe: I2);
102 VPBB1.appendRecipe(Recipe: I3);
103
104 I1->moveBefore(BB&: VPBB1, I: I3->getIterator());
105
106 CHECK_ITERATOR(VPBB1, I2, I1, I3);
107
108 VPInstruction *I4 = new VPInstruction(4, {});
109 VPInstruction *I5 = new VPInstruction(5, {});
110 VPBasicBlock VPBB2;
111 VPBB2.appendRecipe(Recipe: I4);
112 VPBB2.appendRecipe(Recipe: I5);
113
114 I3->moveBefore(BB&: VPBB2, I: I4->getIterator());
115
116 CHECK_ITERATOR(VPBB1, I2, I1);
117 CHECK_ITERATOR(VPBB2, I3, I4, I5);
118 EXPECT_EQ(I3->getParent(), I4->getParent());
119
120 VPBasicBlock VPBB3;
121
122 I4->moveBefore(BB&: VPBB3, I: VPBB3.end());
123
124 CHECK_ITERATOR(VPBB1, I2, I1);
125 CHECK_ITERATOR(VPBB2, I3, I5);
126 CHECK_ITERATOR(VPBB3, I4);
127 EXPECT_EQ(&VPBB3, I4->getParent());
128}
129
130TEST(VPInstructionTest, setOperand) {
131 VPValue *VPV1 = new VPValue();
132 VPValue *VPV2 = new VPValue();
133 VPInstruction *I1 = new VPInstruction(0, {VPV1, VPV2});
134 EXPECT_EQ(1u, VPV1->getNumUsers());
135 EXPECT_EQ(I1, *VPV1->user_begin());
136 EXPECT_EQ(1u, VPV2->getNumUsers());
137 EXPECT_EQ(I1, *VPV2->user_begin());
138
139 // Replace operand 0 (VPV1) with VPV3.
140 VPValue *VPV3 = new VPValue();
141 I1->setOperand(I: 0, New: VPV3);
142 EXPECT_EQ(0u, VPV1->getNumUsers());
143 EXPECT_EQ(1u, VPV2->getNumUsers());
144 EXPECT_EQ(I1, *VPV2->user_begin());
145 EXPECT_EQ(1u, VPV3->getNumUsers());
146 EXPECT_EQ(I1, *VPV3->user_begin());
147
148 // Replace operand 1 (VPV2) with VPV3.
149 I1->setOperand(I: 1, New: VPV3);
150 EXPECT_EQ(0u, VPV1->getNumUsers());
151 EXPECT_EQ(0u, VPV2->getNumUsers());
152 EXPECT_EQ(2u, VPV3->getNumUsers());
153 EXPECT_EQ(I1, *VPV3->user_begin());
154 EXPECT_EQ(I1, *std::next(VPV3->user_begin()));
155
156 // Replace operand 0 (VPV3) with VPV4.
157 VPValue *VPV4 = new VPValue();
158 I1->setOperand(I: 0, New: VPV4);
159 EXPECT_EQ(1u, VPV3->getNumUsers());
160 EXPECT_EQ(I1, *VPV3->user_begin());
161 EXPECT_EQ(I1, *VPV4->user_begin());
162
163 // Replace operand 1 (VPV3) with VPV4.
164 I1->setOperand(I: 1, New: VPV4);
165 EXPECT_EQ(0u, VPV3->getNumUsers());
166 EXPECT_EQ(I1, *VPV4->user_begin());
167 EXPECT_EQ(I1, *std::next(VPV4->user_begin()));
168
169 delete I1;
170 delete VPV1;
171 delete VPV2;
172 delete VPV3;
173 delete VPV4;
174}
175
176TEST(VPInstructionTest, replaceAllUsesWith) {
177 VPValue *VPV1 = new VPValue();
178 VPValue *VPV2 = new VPValue();
179 VPInstruction *I1 = new VPInstruction(0, {VPV1, VPV2});
180
181 // Replace all uses of VPV1 with VPV3.
182 VPValue *VPV3 = new VPValue();
183 VPV1->replaceAllUsesWith(New: VPV3);
184 EXPECT_EQ(VPV3, I1->getOperand(0));
185 EXPECT_EQ(VPV2, I1->getOperand(1));
186 EXPECT_EQ(0u, VPV1->getNumUsers());
187 EXPECT_EQ(1u, VPV2->getNumUsers());
188 EXPECT_EQ(I1, *VPV2->user_begin());
189 EXPECT_EQ(1u, VPV3->getNumUsers());
190 EXPECT_EQ(I1, *VPV3->user_begin());
191
192 // Replace all uses of VPV2 with VPV3.
193 VPV2->replaceAllUsesWith(New: VPV3);
194 EXPECT_EQ(VPV3, I1->getOperand(0));
195 EXPECT_EQ(VPV3, I1->getOperand(1));
196 EXPECT_EQ(0u, VPV1->getNumUsers());
197 EXPECT_EQ(0u, VPV2->getNumUsers());
198 EXPECT_EQ(2u, VPV3->getNumUsers());
199 EXPECT_EQ(I1, *VPV3->user_begin());
200
201 // Replace all uses of VPV3 with VPV1.
202 VPV3->replaceAllUsesWith(New: VPV1);
203 EXPECT_EQ(VPV1, I1->getOperand(0));
204 EXPECT_EQ(VPV1, I1->getOperand(1));
205 EXPECT_EQ(2u, VPV1->getNumUsers());
206 EXPECT_EQ(I1, *VPV1->user_begin());
207 EXPECT_EQ(0u, VPV2->getNumUsers());
208 EXPECT_EQ(0u, VPV3->getNumUsers());
209
210 VPInstruction *I2 = new VPInstruction(0, {VPV1, VPV2});
211 EXPECT_EQ(3u, VPV1->getNumUsers());
212 VPV1->replaceAllUsesWith(New: VPV3);
213 EXPECT_EQ(3u, VPV3->getNumUsers());
214
215 delete I1;
216 delete I2;
217 delete VPV1;
218 delete VPV2;
219 delete VPV3;
220}
221
222TEST(VPInstructionTest, releaseOperandsAtDeletion) {
223 VPValue *VPV1 = new VPValue();
224 VPValue *VPV2 = new VPValue();
225 VPInstruction *I1 = new VPInstruction(0, {VPV1, VPV2});
226
227 EXPECT_EQ(1u, VPV1->getNumUsers());
228 EXPECT_EQ(I1, *VPV1->user_begin());
229 EXPECT_EQ(1u, VPV2->getNumUsers());
230 EXPECT_EQ(I1, *VPV2->user_begin());
231
232 delete I1;
233
234 EXPECT_EQ(0u, VPV1->getNumUsers());
235 EXPECT_EQ(0u, VPV2->getNumUsers());
236
237 delete VPV1;
238 delete VPV2;
239}
240TEST(VPBasicBlockTest, getPlan) {
241 {
242 VPBasicBlock *VPPH = new VPBasicBlock("ph");
243 VPBasicBlock *VPBB1 = new VPBasicBlock();
244 VPBasicBlock *VPBB2 = new VPBasicBlock();
245 VPBasicBlock *VPBB3 = new VPBasicBlock();
246 VPBasicBlock *VPBB4 = new VPBasicBlock();
247
248 // VPBB1
249 // / \
250 // VPBB2 VPBB3
251 // \ /
252 // VPBB4
253 VPBlockUtils::connectBlocks(From: VPBB1, To: VPBB2);
254 VPBlockUtils::connectBlocks(From: VPBB1, To: VPBB3);
255 VPBlockUtils::connectBlocks(From: VPBB2, To: VPBB4);
256 VPBlockUtils::connectBlocks(From: VPBB3, To: VPBB4);
257
258 auto TC = std::make_unique<VPValue>();
259 VPlan Plan(VPPH, &*TC, VPBB1);
260
261 EXPECT_EQ(&Plan, VPBB1->getPlan());
262 EXPECT_EQ(&Plan, VPBB2->getPlan());
263 EXPECT_EQ(&Plan, VPBB3->getPlan());
264 EXPECT_EQ(&Plan, VPBB4->getPlan());
265 }
266
267 {
268 VPBasicBlock *VPPH = new VPBasicBlock("ph");
269 // VPBasicBlock is the entry into the VPlan, followed by a region.
270 VPBasicBlock *R1BB1 = new VPBasicBlock();
271 VPBasicBlock *R1BB2 = new VPBasicBlock();
272 VPRegionBlock *R1 = new VPRegionBlock(R1BB1, R1BB2, "R1");
273 VPBlockUtils::connectBlocks(From: R1BB1, To: R1BB2);
274
275 VPBasicBlock *VPBB1 = new VPBasicBlock();
276 VPBlockUtils::connectBlocks(From: VPBB1, To: R1);
277
278 auto TC = std::make_unique<VPValue>();
279 VPlan Plan(VPPH, &*TC, VPBB1);
280
281 EXPECT_EQ(&Plan, VPBB1->getPlan());
282 EXPECT_EQ(&Plan, R1->getPlan());
283 EXPECT_EQ(&Plan, R1BB1->getPlan());
284 EXPECT_EQ(&Plan, R1BB2->getPlan());
285 }
286
287 {
288 VPBasicBlock *VPPH = new VPBasicBlock("ph");
289
290 VPBasicBlock *R1BB1 = new VPBasicBlock();
291 VPBasicBlock *R1BB2 = new VPBasicBlock();
292 VPRegionBlock *R1 = new VPRegionBlock(R1BB1, R1BB2, "R1");
293 VPBlockUtils::connectBlocks(From: R1BB1, To: R1BB2);
294
295 VPBasicBlock *R2BB1 = new VPBasicBlock();
296 VPBasicBlock *R2BB2 = new VPBasicBlock();
297 VPRegionBlock *R2 = new VPRegionBlock(R2BB1, R2BB2, "R2");
298 VPBlockUtils::connectBlocks(From: R2BB1, To: R2BB2);
299
300 VPBasicBlock *VPBB1 = new VPBasicBlock();
301 VPBlockUtils::connectBlocks(From: VPBB1, To: R1);
302 VPBlockUtils::connectBlocks(From: VPBB1, To: R2);
303
304 VPBasicBlock *VPBB2 = new VPBasicBlock();
305 VPBlockUtils::connectBlocks(From: R1, To: VPBB2);
306 VPBlockUtils::connectBlocks(From: R2, To: VPBB2);
307
308 auto TC = std::make_unique<VPValue>();
309 VPlan Plan(VPPH, &*TC, VPBB1);
310
311 EXPECT_EQ(&Plan, VPBB1->getPlan());
312 EXPECT_EQ(&Plan, R1->getPlan());
313 EXPECT_EQ(&Plan, R1BB1->getPlan());
314 EXPECT_EQ(&Plan, R1BB2->getPlan());
315 EXPECT_EQ(&Plan, R2->getPlan());
316 EXPECT_EQ(&Plan, R2BB1->getPlan());
317 EXPECT_EQ(&Plan, R2BB2->getPlan());
318 EXPECT_EQ(&Plan, VPBB2->getPlan());
319 }
320}
321
322TEST(VPBasicBlockTest, TraversingIteratorTest) {
323 {
324 // VPBasicBlocks only
325 // VPBB1
326 // / \
327 // VPBB2 VPBB3
328 // \ /
329 // VPBB4
330 //
331 VPBasicBlock *VPPH = new VPBasicBlock("ph");
332 VPBasicBlock *VPBB1 = new VPBasicBlock();
333 VPBasicBlock *VPBB2 = new VPBasicBlock();
334 VPBasicBlock *VPBB3 = new VPBasicBlock();
335 VPBasicBlock *VPBB4 = new VPBasicBlock();
336
337 VPBlockUtils::connectBlocks(From: VPBB1, To: VPBB2);
338 VPBlockUtils::connectBlocks(From: VPBB1, To: VPBB3);
339 VPBlockUtils::connectBlocks(From: VPBB2, To: VPBB4);
340 VPBlockUtils::connectBlocks(From: VPBB3, To: VPBB4);
341
342 VPBlockDeepTraversalWrapper<const VPBlockBase *> Start(VPBB1);
343 SmallVector<const VPBlockBase *> FromIterator(depth_first(G: Start));
344 EXPECT_EQ(4u, FromIterator.size());
345 EXPECT_EQ(VPBB1, FromIterator[0]);
346 EXPECT_EQ(VPBB2, FromIterator[1]);
347
348 // Use Plan to properly clean up created blocks.
349 auto TC = std::make_unique<VPValue>();
350 VPlan Plan(VPPH, &*TC, VPBB1);
351 }
352
353 {
354 // 2 consecutive regions.
355 // VPBB0
356 // |
357 // R1 {
358 // \
359 // R1BB1
360 // / \ |--|
361 // R1BB2 R1BB3 -|
362 // \ /
363 // R1BB4
364 // }
365 // |
366 // R2 {
367 // \
368 // R2BB1
369 // |
370 // R2BB2
371 //
372 VPBasicBlock *VPPH = new VPBasicBlock("ph");
373 VPBasicBlock *VPBB0 = new VPBasicBlock("VPBB0");
374 VPBasicBlock *R1BB1 = new VPBasicBlock();
375 VPBasicBlock *R1BB2 = new VPBasicBlock();
376 VPBasicBlock *R1BB3 = new VPBasicBlock();
377 VPBasicBlock *R1BB4 = new VPBasicBlock();
378 VPRegionBlock *R1 = new VPRegionBlock(R1BB1, R1BB4, "R1");
379 R1BB2->setParent(R1);
380 R1BB3->setParent(R1);
381 VPBlockUtils::connectBlocks(From: VPBB0, To: R1);
382 VPBlockUtils::connectBlocks(From: R1BB1, To: R1BB2);
383 VPBlockUtils::connectBlocks(From: R1BB1, To: R1BB3);
384 VPBlockUtils::connectBlocks(From: R1BB2, To: R1BB4);
385 VPBlockUtils::connectBlocks(From: R1BB3, To: R1BB4);
386 // Cycle.
387 VPBlockUtils::connectBlocks(From: R1BB3, To: R1BB3);
388
389 VPBasicBlock *R2BB1 = new VPBasicBlock();
390 VPBasicBlock *R2BB2 = new VPBasicBlock();
391 VPRegionBlock *R2 = new VPRegionBlock(R2BB1, R2BB2, "R2");
392 VPBlockUtils::connectBlocks(From: R2BB1, To: R2BB2);
393 VPBlockUtils::connectBlocks(From: R1, To: R2);
394
395 // Successors of R1.
396 SmallVector<const VPBlockBase *> FromIterator(
397 VPAllSuccessorsIterator<VPBlockBase *>(R1),
398 VPAllSuccessorsIterator<VPBlockBase *>::end(Block: R1));
399 EXPECT_EQ(1u, FromIterator.size());
400 EXPECT_EQ(R1BB1, FromIterator[0]);
401
402 // Depth-first.
403 VPBlockDeepTraversalWrapper<VPBlockBase *> Start(R1);
404 FromIterator.clear();
405 copy(first: df_begin(G: Start), last: df_end(G: Start), result: std::back_inserter(x&: FromIterator));
406 EXPECT_EQ(8u, FromIterator.size());
407 EXPECT_EQ(R1, FromIterator[0]);
408 EXPECT_EQ(R1BB1, FromIterator[1]);
409 EXPECT_EQ(R1BB2, FromIterator[2]);
410 EXPECT_EQ(R1BB4, FromIterator[3]);
411 EXPECT_EQ(R2, FromIterator[4]);
412 EXPECT_EQ(R2BB1, FromIterator[5]);
413 EXPECT_EQ(R2BB2, FromIterator[6]);
414 EXPECT_EQ(R1BB3, FromIterator[7]);
415
416 // const VPBasicBlocks only.
417 FromIterator.clear();
418 copy(Range: VPBlockUtils::blocksOnly<const VPBasicBlock>(Range: depth_first(G: Start)),
419 Out: std::back_inserter(x&: FromIterator));
420 EXPECT_EQ(6u, FromIterator.size());
421 EXPECT_EQ(R1BB1, FromIterator[0]);
422 EXPECT_EQ(R1BB2, FromIterator[1]);
423 EXPECT_EQ(R1BB4, FromIterator[2]);
424 EXPECT_EQ(R2BB1, FromIterator[3]);
425 EXPECT_EQ(R2BB2, FromIterator[4]);
426 EXPECT_EQ(R1BB3, FromIterator[5]);
427
428 // VPRegionBlocks only.
429 SmallVector<VPRegionBlock *> FromIteratorVPRegion(
430 VPBlockUtils::blocksOnly<VPRegionBlock>(Range: depth_first(G: Start)));
431 EXPECT_EQ(2u, FromIteratorVPRegion.size());
432 EXPECT_EQ(R1, FromIteratorVPRegion[0]);
433 EXPECT_EQ(R2, FromIteratorVPRegion[1]);
434
435 // Post-order.
436 FromIterator.clear();
437 copy(Range: post_order(G: Start), Out: std::back_inserter(x&: FromIterator));
438 EXPECT_EQ(8u, FromIterator.size());
439 EXPECT_EQ(R2BB2, FromIterator[0]);
440 EXPECT_EQ(R2BB1, FromIterator[1]);
441 EXPECT_EQ(R2, FromIterator[2]);
442 EXPECT_EQ(R1BB4, FromIterator[3]);
443 EXPECT_EQ(R1BB2, FromIterator[4]);
444 EXPECT_EQ(R1BB3, FromIterator[5]);
445 EXPECT_EQ(R1BB1, FromIterator[6]);
446 EXPECT_EQ(R1, FromIterator[7]);
447
448 // Use Plan to properly clean up created blocks.
449 auto TC = std::make_unique<VPValue>();
450 VPlan Plan(VPPH, &*TC, VPBB0);
451 }
452
453 {
454 // 2 nested regions.
455 // VPBB1
456 // |
457 // R1 {
458 // R1BB1
459 // / \
460 // R2 { |
461 // \ |
462 // R2BB1 |
463 // | \ R1BB2
464 // R2BB2-| |
465 // \ |
466 // R2BB3 |
467 // } /
468 // \ /
469 // R1BB3
470 // }
471 // |
472 // VPBB2
473 //
474 VPBasicBlock *VPPH = new VPBasicBlock("ph");
475 VPBasicBlock *R1BB1 = new VPBasicBlock("R1BB1");
476 VPBasicBlock *R1BB2 = new VPBasicBlock("R1BB2");
477 VPBasicBlock *R1BB3 = new VPBasicBlock("R1BB3");
478 VPRegionBlock *R1 = new VPRegionBlock(R1BB1, R1BB3, "R1");
479
480 VPBasicBlock *R2BB1 = new VPBasicBlock("R2BB1");
481 VPBasicBlock *R2BB2 = new VPBasicBlock("R2BB2");
482 VPBasicBlock *R2BB3 = new VPBasicBlock("R2BB3");
483 VPRegionBlock *R2 = new VPRegionBlock(R2BB1, R2BB3, "R2");
484 R2BB2->setParent(R2);
485 VPBlockUtils::connectBlocks(From: R2BB1, To: R2BB2);
486 VPBlockUtils::connectBlocks(From: R2BB2, To: R2BB1);
487 VPBlockUtils::connectBlocks(From: R2BB2, To: R2BB3);
488
489 R2->setParent(R1);
490 VPBlockUtils::connectBlocks(From: R1BB1, To: R2);
491 R1BB2->setParent(R1);
492 VPBlockUtils::connectBlocks(From: R1BB1, To: R1BB2);
493 VPBlockUtils::connectBlocks(From: R1BB2, To: R1BB3);
494 VPBlockUtils::connectBlocks(From: R2, To: R1BB3);
495
496 VPBasicBlock *VPBB1 = new VPBasicBlock("VPBB1");
497 VPBlockUtils::connectBlocks(From: VPBB1, To: R1);
498 VPBasicBlock *VPBB2 = new VPBasicBlock("VPBB2");
499 VPBlockUtils::connectBlocks(From: R1, To: VPBB2);
500
501 // Depth-first.
502 VPBlockDeepTraversalWrapper<VPBlockBase *> Start(VPBB1);
503 SmallVector<VPBlockBase *> FromIterator(depth_first(G: Start));
504 EXPECT_EQ(10u, FromIterator.size());
505 EXPECT_EQ(VPBB1, FromIterator[0]);
506 EXPECT_EQ(R1, FromIterator[1]);
507 EXPECT_EQ(R1BB1, FromIterator[2]);
508 EXPECT_EQ(R2, FromIterator[3]);
509 EXPECT_EQ(R2BB1, FromIterator[4]);
510 EXPECT_EQ(R2BB2, FromIterator[5]);
511 EXPECT_EQ(R2BB3, FromIterator[6]);
512 EXPECT_EQ(R1BB3, FromIterator[7]);
513 EXPECT_EQ(VPBB2, FromIterator[8]);
514 EXPECT_EQ(R1BB2, FromIterator[9]);
515
516 // Post-order.
517 FromIterator.clear();
518 FromIterator.append(in_start: po_begin(G: Start), in_end: po_end(G: Start));
519 EXPECT_EQ(10u, FromIterator.size());
520 EXPECT_EQ(VPBB2, FromIterator[0]);
521 EXPECT_EQ(R1BB3, FromIterator[1]);
522 EXPECT_EQ(R2BB3, FromIterator[2]);
523 EXPECT_EQ(R2BB2, FromIterator[3]);
524 EXPECT_EQ(R2BB1, FromIterator[4]);
525 EXPECT_EQ(R2, FromIterator[5]);
526 EXPECT_EQ(R1BB2, FromIterator[6]);
527 EXPECT_EQ(R1BB1, FromIterator[7]);
528 EXPECT_EQ(R1, FromIterator[8]);
529 EXPECT_EQ(VPBB1, FromIterator[9]);
530
531 // Use Plan to properly clean up created blocks.
532 auto TC = std::make_unique<VPValue>();
533 VPlan Plan(VPPH, &*TC, VPBB1);
534 }
535
536 {
537 // VPBB1
538 // |
539 // R1 {
540 // \
541 // R2 {
542 // R2BB1
543 // |
544 // R2BB2
545 // }
546 //
547 VPBasicBlock *VPPH = new VPBasicBlock("ph");
548 VPBasicBlock *R2BB1 = new VPBasicBlock("R2BB1");
549 VPBasicBlock *R2BB2 = new VPBasicBlock("R2BB2");
550 VPRegionBlock *R2 = new VPRegionBlock(R2BB1, R2BB2, "R2");
551 VPBlockUtils::connectBlocks(From: R2BB1, To: R2BB2);
552
553 VPRegionBlock *R1 = new VPRegionBlock(R2, R2, "R1");
554 R2->setParent(R1);
555
556 VPBasicBlock *VPBB1 = new VPBasicBlock("VPBB1");
557 VPBlockUtils::connectBlocks(From: VPBB1, To: R1);
558
559 // Depth-first.
560 VPBlockDeepTraversalWrapper<VPBlockBase *> Start(VPBB1);
561 SmallVector<VPBlockBase *> FromIterator(depth_first(G: Start));
562 EXPECT_EQ(5u, FromIterator.size());
563 EXPECT_EQ(VPBB1, FromIterator[0]);
564 EXPECT_EQ(R1, FromIterator[1]);
565 EXPECT_EQ(R2, FromIterator[2]);
566 EXPECT_EQ(R2BB1, FromIterator[3]);
567 EXPECT_EQ(R2BB2, FromIterator[4]);
568
569 // Post-order.
570 FromIterator.clear();
571 FromIterator.append(in_start: po_begin(G: Start), in_end: po_end(G: Start));
572 EXPECT_EQ(5u, FromIterator.size());
573 EXPECT_EQ(R2BB2, FromIterator[0]);
574 EXPECT_EQ(R2BB1, FromIterator[1]);
575 EXPECT_EQ(R2, FromIterator[2]);
576 EXPECT_EQ(R1, FromIterator[3]);
577 EXPECT_EQ(VPBB1, FromIterator[4]);
578
579 // Use Plan to properly clean up created blocks.
580 auto TC = std::make_unique<VPValue>();
581 VPlan Plan(VPPH, &*TC, VPBB1);
582 }
583
584 {
585 // Nested regions with both R3 and R2 being exit nodes without successors.
586 // The successors of R1 should be used.
587 //
588 // VPBB1
589 // |
590 // R1 {
591 // \
592 // R2 {
593 // \
594 // R2BB1
595 // |
596 // R3 {
597 // R3BB1
598 // }
599 // }
600 // |
601 // VPBB2
602 //
603 VPBasicBlock *VPPH = new VPBasicBlock("ph");
604 VPBasicBlock *R3BB1 = new VPBasicBlock("R3BB1");
605 VPRegionBlock *R3 = new VPRegionBlock(R3BB1, R3BB1, "R3");
606
607 VPBasicBlock *R2BB1 = new VPBasicBlock("R2BB1");
608 VPRegionBlock *R2 = new VPRegionBlock(R2BB1, R3, "R2");
609 R3->setParent(R2);
610 VPBlockUtils::connectBlocks(From: R2BB1, To: R3);
611
612 VPRegionBlock *R1 = new VPRegionBlock(R2, R2, "R1");
613 R2->setParent(R1);
614
615 VPBasicBlock *VPBB1 = new VPBasicBlock("VPBB1");
616 VPBasicBlock *VPBB2 = new VPBasicBlock("VPBB2");
617 VPBlockUtils::connectBlocks(From: VPBB1, To: R1);
618 VPBlockUtils::connectBlocks(From: R1, To: VPBB2);
619
620 // Depth-first.
621 VPBlockDeepTraversalWrapper<VPBlockBase *> Start(VPBB1);
622 SmallVector<VPBlockBase *> FromIterator(depth_first(G: Start));
623 EXPECT_EQ(7u, FromIterator.size());
624 EXPECT_EQ(VPBB1, FromIterator[0]);
625 EXPECT_EQ(R1, FromIterator[1]);
626 EXPECT_EQ(R2, FromIterator[2]);
627 EXPECT_EQ(R2BB1, FromIterator[3]);
628 EXPECT_EQ(R3, FromIterator[4]);
629 EXPECT_EQ(R3BB1, FromIterator[5]);
630 EXPECT_EQ(VPBB2, FromIterator[6]);
631
632 SmallVector<VPBlockBase *> FromIteratorVPBB;
633 copy(Range: VPBlockUtils::blocksOnly<VPBasicBlock>(Range: depth_first(G: Start)),
634 Out: std::back_inserter(x&: FromIteratorVPBB));
635 EXPECT_EQ(VPBB1, FromIteratorVPBB[0]);
636 EXPECT_EQ(R2BB1, FromIteratorVPBB[1]);
637 EXPECT_EQ(R3BB1, FromIteratorVPBB[2]);
638 EXPECT_EQ(VPBB2, FromIteratorVPBB[3]);
639
640 // Post-order.
641 FromIterator.clear();
642 copy(Range: post_order(G: Start), Out: std::back_inserter(x&: FromIterator));
643 EXPECT_EQ(7u, FromIterator.size());
644 EXPECT_EQ(VPBB2, FromIterator[0]);
645 EXPECT_EQ(R3BB1, FromIterator[1]);
646 EXPECT_EQ(R3, FromIterator[2]);
647 EXPECT_EQ(R2BB1, FromIterator[3]);
648 EXPECT_EQ(R2, FromIterator[4]);
649 EXPECT_EQ(R1, FromIterator[5]);
650 EXPECT_EQ(VPBB1, FromIterator[6]);
651
652 // Post-order, const VPRegionBlocks only.
653 VPBlockDeepTraversalWrapper<const VPBlockBase *> StartConst(VPBB1);
654 SmallVector<const VPRegionBlock *> FromIteratorVPRegion(
655 VPBlockUtils::blocksOnly<const VPRegionBlock>(Range: post_order(G: StartConst)));
656 EXPECT_EQ(3u, FromIteratorVPRegion.size());
657 EXPECT_EQ(R3, FromIteratorVPRegion[0]);
658 EXPECT_EQ(R2, FromIteratorVPRegion[1]);
659 EXPECT_EQ(R1, FromIteratorVPRegion[2]);
660
661 // Post-order, VPBasicBlocks only.
662 FromIterator.clear();
663 copy(Range: VPBlockUtils::blocksOnly<VPBasicBlock>(Range: post_order(G: Start)),
664 Out: std::back_inserter(x&: FromIterator));
665 EXPECT_EQ(FromIterator.size(), 4u);
666 EXPECT_EQ(VPBB2, FromIterator[0]);
667 EXPECT_EQ(R3BB1, FromIterator[1]);
668 EXPECT_EQ(R2BB1, FromIterator[2]);
669 EXPECT_EQ(VPBB1, FromIterator[3]);
670
671 // Use Plan to properly clean up created blocks.
672 auto TC = std::make_unique<VPValue>();
673 VPlan Plan(VPPH, &*TC, VPBB1);
674 }
675}
676
677#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
678TEST(VPBasicBlockTest, print) {
679 VPInstruction *TC = new VPInstruction(Instruction::Add, {});
680 VPBasicBlock *VPBB0 = new VPBasicBlock("preheader");
681 VPBB0->appendRecipe(Recipe: TC);
682
683 VPInstruction *I1 = new VPInstruction(Instruction::Add, {});
684 VPInstruction *I2 = new VPInstruction(Instruction::Sub, {I1});
685 VPInstruction *I3 = new VPInstruction(Instruction::Br, {I1, I2});
686
687 VPBasicBlock *VPBB1 = new VPBasicBlock();
688 VPBB1->appendRecipe(Recipe: I1);
689 VPBB1->appendRecipe(Recipe: I2);
690 VPBB1->appendRecipe(Recipe: I3);
691 VPBB1->setName("bb1");
692
693 VPInstruction *I4 = new VPInstruction(Instruction::Mul, {I2, I1});
694 VPInstruction *I5 = new VPInstruction(Instruction::Ret, {I4});
695 VPBasicBlock *VPBB2 = new VPBasicBlock();
696 VPBB2->appendRecipe(Recipe: I4);
697 VPBB2->appendRecipe(Recipe: I5);
698 VPBB2->setName("bb2");
699
700 VPBlockUtils::connectBlocks(From: VPBB1, To: VPBB2);
701
702 // Check printing an instruction without associated VPlan.
703 {
704 std::string I3Dump;
705 raw_string_ostream OS(I3Dump);
706 VPSlotTracker SlotTracker;
707 I3->print(O&: OS, Indent: "", SlotTracker);
708 OS.flush();
709 EXPECT_EQ("EMIT br <badref>, <badref>", I3Dump);
710 }
711
712 VPlan Plan(VPBB0, TC, VPBB1);
713 std::string FullDump;
714 raw_string_ostream OS(FullDump);
715 Plan.printDOT(O&: OS);
716
717 const char *ExpectedStr = R"(digraph VPlan {
718graph [labelloc=t, fontsize=30; label="Vectorization Plan\n for UF\>=1\nvp\<%1\> = original trip-count\n"]
719node [shape=rect, fontname=Courier, fontsize=30]
720edge [fontname=Courier, fontsize=30]
721compound=true
722 N0 [label =
723 "preheader:\l" +
724 " EMIT vp\<%1\> = add\l" +
725 "No successors\l"
726 ]
727 N1 [label =
728 "bb1:\l" +
729 " EMIT vp\<%2\> = add\l" +
730 " EMIT vp\<%3\> = sub vp\<%2\>\l" +
731 " EMIT br vp\<%2\>, vp\<%3\>\l" +
732 "Successor(s): bb2\l"
733 ]
734 N1 -> N2 [ label=""]
735 N2 [label =
736 "bb2:\l" +
737 " EMIT vp\<%5\> = mul vp\<%3\>, vp\<%2\>\l" +
738 " EMIT ret vp\<%5\>\l" +
739 "No successors\l"
740 ]
741}
742)";
743 EXPECT_EQ(ExpectedStr, FullDump);
744
745 const char *ExpectedBlock1Str = R"(bb1:
746 EMIT vp<%2> = add
747 EMIT vp<%3> = sub vp<%2>
748 EMIT br vp<%2>, vp<%3>
749Successor(s): bb2
750)";
751 std::string Block1Dump;
752 raw_string_ostream OS1(Block1Dump);
753 VPBB1->print(O&: OS1);
754 EXPECT_EQ(ExpectedBlock1Str, Block1Dump);
755
756 // Ensure that numbering is good when dumping the second block in isolation.
757 const char *ExpectedBlock2Str = R"(bb2:
758 EMIT vp<%5> = mul vp<%3>, vp<%2>
759 EMIT ret vp<%5>
760No successors
761)";
762 std::string Block2Dump;
763 raw_string_ostream OS2(Block2Dump);
764 VPBB2->print(O&: OS2);
765 EXPECT_EQ(ExpectedBlock2Str, Block2Dump);
766
767 {
768 std::string I3Dump;
769 raw_string_ostream OS(I3Dump);
770 VPSlotTracker SlotTracker(&Plan);
771 I3->print(O&: OS, Indent: "", SlotTracker);
772 OS.flush();
773 EXPECT_EQ("EMIT br vp<%2>, vp<%3>", I3Dump);
774 }
775
776 {
777 std::string I4Dump;
778 raw_string_ostream OS(I4Dump);
779 OS << *I4;
780 OS.flush();
781 EXPECT_EQ("EMIT vp<%5> = mul vp<%3>, vp<%2>", I4Dump);
782 }
783}
784
785TEST(VPBasicBlockTest, printPlanWithVFsAndUFs) {
786
787 VPInstruction *TC = new VPInstruction(Instruction::Sub, {});
788 VPBasicBlock *VPBB0 = new VPBasicBlock("preheader");
789 VPBB0->appendRecipe(Recipe: TC);
790
791 VPInstruction *I1 = new VPInstruction(Instruction::Add, {});
792 VPBasicBlock *VPBB1 = new VPBasicBlock();
793 VPBB1->appendRecipe(Recipe: I1);
794 VPBB1->setName("bb1");
795
796 VPlan Plan(VPBB0, TC, VPBB1);
797 Plan.setName("TestPlan");
798 Plan.addVF(VF: ElementCount::getFixed(MinVal: 4));
799
800 {
801 std::string FullDump;
802 raw_string_ostream OS(FullDump);
803 Plan.print(O&: OS);
804
805 const char *ExpectedStr = R"(VPlan 'TestPlan for VF={4},UF>=1' {
806vp<%1> = original trip-count
807
808preheader:
809 EMIT vp<%1> = sub
810No successors
811
812bb1:
813 EMIT vp<%2> = add
814No successors
815}
816)";
817 EXPECT_EQ(ExpectedStr, FullDump);
818 }
819
820 {
821 Plan.addVF(VF: ElementCount::getScalable(MinVal: 8));
822 std::string FullDump;
823 raw_string_ostream OS(FullDump);
824 Plan.print(O&: OS);
825
826 const char *ExpectedStr = R"(VPlan 'TestPlan for VF={4,vscale x 8},UF>=1' {
827vp<%1> = original trip-count
828
829preheader:
830 EMIT vp<%1> = sub
831No successors
832
833bb1:
834 EMIT vp<%2> = add
835No successors
836}
837)";
838 EXPECT_EQ(ExpectedStr, FullDump);
839 }
840
841 {
842 Plan.setUF(4);
843 std::string FullDump;
844 raw_string_ostream OS(FullDump);
845 Plan.print(O&: OS);
846
847 const char *ExpectedStr = R"(VPlan 'TestPlan for VF={4,vscale x 8},UF={4}' {
848vp<%1> = original trip-count
849
850preheader:
851 EMIT vp<%1> = sub
852No successors
853
854bb1:
855 EMIT vp<%2> = add
856No successors
857}
858)";
859 EXPECT_EQ(ExpectedStr, FullDump);
860 }
861}
862#endif
863
864TEST(VPRecipeTest, CastVPInstructionToVPUser) {
865 VPValue Op1;
866 VPValue Op2;
867 VPInstruction Recipe(Instruction::Add, {&Op1, &Op2});
868 EXPECT_TRUE(isa<VPUser>(&Recipe));
869 VPRecipeBase *BaseR = &Recipe;
870 EXPECT_TRUE(isa<VPUser>(BaseR));
871 EXPECT_EQ(&Recipe, BaseR);
872}
873
874TEST(VPRecipeTest, CastVPWidenRecipeToVPUser) {
875 LLVMContext C;
876
877 IntegerType *Int32 = IntegerType::get(C, NumBits: 32);
878 auto *AI =
879 BinaryOperator::CreateAdd(V1: UndefValue::get(T: Int32), V2: UndefValue::get(T: Int32));
880 VPValue Op1;
881 VPValue Op2;
882 SmallVector<VPValue *, 2> Args;
883 Args.push_back(Elt: &Op1);
884 Args.push_back(Elt: &Op1);
885 VPWidenRecipe WidenR(*AI, make_range(x: Args.begin(), y: Args.end()));
886 EXPECT_TRUE(isa<VPUser>(&WidenR));
887 VPRecipeBase *WidenRBase = &WidenR;
888 EXPECT_TRUE(isa<VPUser>(WidenRBase));
889 EXPECT_EQ(&WidenR, WidenRBase);
890 delete AI;
891}
892
893TEST(VPRecipeTest, CastVPWidenCallRecipeToVPUserAndVPDef) {
894 LLVMContext C;
895
896 IntegerType *Int32 = IntegerType::get(C, NumBits: 32);
897 FunctionType *FTy = FunctionType::get(Result: Int32, isVarArg: false);
898 auto *Call = CallInst::Create(Ty: FTy, F: UndefValue::get(T: FTy));
899 VPValue Op1;
900 VPValue Op2;
901 SmallVector<VPValue *, 2> Args;
902 Args.push_back(Elt: &Op1);
903 Args.push_back(Elt: &Op2);
904 VPWidenCallRecipe Recipe(*Call, make_range(x: Args.begin(), y: Args.end()), false);
905 EXPECT_TRUE(isa<VPUser>(&Recipe));
906 VPRecipeBase *BaseR = &Recipe;
907 EXPECT_TRUE(isa<VPUser>(BaseR));
908 EXPECT_EQ(&Recipe, BaseR);
909
910 VPValue *VPV = &Recipe;
911 EXPECT_TRUE(VPV->getDefiningRecipe());
912 EXPECT_EQ(&Recipe, VPV->getDefiningRecipe());
913
914 delete Call;
915}
916
917TEST(VPRecipeTest, CastVPWidenSelectRecipeToVPUserAndVPDef) {
918 LLVMContext C;
919
920 IntegerType *Int1 = IntegerType::get(C, NumBits: 1);
921 IntegerType *Int32 = IntegerType::get(C, NumBits: 32);
922 auto *SelectI = SelectInst::Create(
923 C: UndefValue::get(T: Int1), S1: UndefValue::get(T: Int32), S2: UndefValue::get(T: Int32));
924 VPValue Op1;
925 VPValue Op2;
926 VPValue Op3;
927 SmallVector<VPValue *, 4> Args;
928 Args.push_back(Elt: &Op1);
929 Args.push_back(Elt: &Op2);
930 Args.push_back(Elt: &Op3);
931 VPWidenSelectRecipe WidenSelectR(*SelectI,
932 make_range(x: Args.begin(), y: Args.end()));
933 EXPECT_TRUE(isa<VPUser>(&WidenSelectR));
934 VPRecipeBase *BaseR = &WidenSelectR;
935 EXPECT_TRUE(isa<VPUser>(BaseR));
936 EXPECT_EQ(&WidenSelectR, BaseR);
937
938 VPValue *VPV = &WidenSelectR;
939 EXPECT_TRUE(isa<VPRecipeBase>(VPV->getDefiningRecipe()));
940 EXPECT_EQ(&WidenSelectR, VPV->getDefiningRecipe());
941
942 delete SelectI;
943}
944
945TEST(VPRecipeTest, CastVPWidenGEPRecipeToVPUserAndVPDef) {
946 LLVMContext C;
947
948 IntegerType *Int32 = IntegerType::get(C, NumBits: 32);
949 PointerType *Int32Ptr = PointerType::get(ElementType: Int32, AddressSpace: 0);
950 auto *GEP = GetElementPtrInst::Create(PointeeType: Int32, Ptr: UndefValue::get(T: Int32Ptr),
951 IdxList: UndefValue::get(T: Int32));
952 VPValue Op1;
953 VPValue Op2;
954 SmallVector<VPValue *, 4> Args;
955 Args.push_back(Elt: &Op1);
956 Args.push_back(Elt: &Op2);
957 VPWidenGEPRecipe Recipe(GEP, make_range(x: Args.begin(), y: Args.end()));
958 EXPECT_TRUE(isa<VPUser>(&Recipe));
959 VPRecipeBase *BaseR = &Recipe;
960 EXPECT_TRUE(isa<VPUser>(BaseR));
961 EXPECT_EQ(&Recipe, BaseR);
962
963 VPValue *VPV = &Recipe;
964 EXPECT_TRUE(isa<VPRecipeBase>(VPV->getDefiningRecipe()));
965 EXPECT_EQ(&Recipe, VPV->getDefiningRecipe());
966
967 delete GEP;
968}
969
970TEST(VPRecipeTest, CastVPBlendRecipeToVPUser) {
971 LLVMContext C;
972
973 IntegerType *Int32 = IntegerType::get(C, NumBits: 32);
974 auto *Phi = PHINode::Create(Ty: Int32, NumReservedValues: 1);
975 VPValue I1;
976 VPValue I2;
977 VPValue M2;
978 SmallVector<VPValue *, 4> Args;
979 Args.push_back(Elt: &I1);
980 Args.push_back(Elt: &I2);
981 Args.push_back(Elt: &M2);
982 VPBlendRecipe Recipe(Phi, Args);
983 EXPECT_TRUE(isa<VPUser>(&Recipe));
984 VPRecipeBase *BaseR = &Recipe;
985 EXPECT_TRUE(isa<VPUser>(BaseR));
986 delete Phi;
987}
988
989TEST(VPRecipeTest, CastVPInterleaveRecipeToVPUser) {
990 LLVMContext C;
991
992 VPValue Addr;
993 VPValue Mask;
994 InterleaveGroup<Instruction> IG(4, false, Align(4));
995 VPInterleaveRecipe Recipe(&IG, &Addr, {}, &Mask, false);
996 EXPECT_TRUE(isa<VPUser>(&Recipe));
997 VPRecipeBase *BaseR = &Recipe;
998 EXPECT_TRUE(isa<VPUser>(BaseR));
999 EXPECT_EQ(&Recipe, BaseR);
1000}
1001
1002TEST(VPRecipeTest, CastVPReplicateRecipeToVPUser) {
1003 LLVMContext C;
1004
1005 VPValue Op1;
1006 VPValue Op2;
1007 SmallVector<VPValue *, 4> Args;
1008 Args.push_back(Elt: &Op1);
1009 Args.push_back(Elt: &Op2);
1010
1011 IntegerType *Int32 = IntegerType::get(C, NumBits: 32);
1012 FunctionType *FTy = FunctionType::get(Result: Int32, isVarArg: false);
1013 auto *Call = CallInst::Create(Ty: FTy, F: UndefValue::get(T: FTy));
1014 VPReplicateRecipe Recipe(Call, make_range(x: Args.begin(), y: Args.end()), true);
1015 EXPECT_TRUE(isa<VPUser>(&Recipe));
1016 VPRecipeBase *BaseR = &Recipe;
1017 EXPECT_TRUE(isa<VPUser>(BaseR));
1018 delete Call;
1019}
1020
1021TEST(VPRecipeTest, CastVPBranchOnMaskRecipeToVPUser) {
1022 LLVMContext C;
1023
1024 VPValue Mask;
1025 VPBranchOnMaskRecipe Recipe(&Mask);
1026 EXPECT_TRUE(isa<VPUser>(&Recipe));
1027 VPRecipeBase *BaseR = &Recipe;
1028 EXPECT_TRUE(isa<VPUser>(BaseR));
1029 EXPECT_EQ(&Recipe, BaseR);
1030}
1031
1032TEST(VPRecipeTest, CastVPWidenMemoryRecipeToVPUserAndVPDef) {
1033 LLVMContext C;
1034
1035 IntegerType *Int32 = IntegerType::get(C, NumBits: 32);
1036 PointerType *Int32Ptr = PointerType::get(ElementType: Int32, AddressSpace: 0);
1037 auto *Load =
1038 new LoadInst(Int32, UndefValue::get(T: Int32Ptr), "", false, Align(1));
1039 VPValue Addr;
1040 VPValue Mask;
1041 VPWidenLoadRecipe Recipe(*Load, &Addr, &Mask, true, false, {});
1042 EXPECT_TRUE(isa<VPUser>(&Recipe));
1043 VPRecipeBase *BaseR = &Recipe;
1044 EXPECT_TRUE(isa<VPUser>(BaseR));
1045 EXPECT_EQ(&Recipe, BaseR);
1046
1047 VPValue *VPV = Recipe.getVPSingleValue();
1048 EXPECT_TRUE(isa<VPRecipeBase>(VPV->getDefiningRecipe()));
1049 EXPECT_EQ(&Recipe, VPV->getDefiningRecipe());
1050
1051 delete Load;
1052}
1053
1054TEST(VPRecipeTest, MayHaveSideEffectsAndMayReadWriteMemory) {
1055 LLVMContext C;
1056 IntegerType *Int1 = IntegerType::get(C, NumBits: 1);
1057 IntegerType *Int32 = IntegerType::get(C, NumBits: 32);
1058 PointerType *Int32Ptr = PointerType::get(ElementType: Int32, AddressSpace: 0);
1059
1060 {
1061 auto *AI = BinaryOperator::CreateAdd(V1: UndefValue::get(T: Int32),
1062 V2: UndefValue::get(T: Int32));
1063 VPValue Op1;
1064 VPValue Op2;
1065 SmallVector<VPValue *, 2> Args;
1066 Args.push_back(Elt: &Op1);
1067 Args.push_back(Elt: &Op1);
1068 VPWidenRecipe Recipe(*AI, make_range(x: Args.begin(), y: Args.end()));
1069 EXPECT_FALSE(Recipe.mayHaveSideEffects());
1070 EXPECT_FALSE(Recipe.mayReadFromMemory());
1071 EXPECT_FALSE(Recipe.mayWriteToMemory());
1072 EXPECT_FALSE(Recipe.mayReadOrWriteMemory());
1073 delete AI;
1074 }
1075
1076 {
1077 auto *SelectI = SelectInst::Create(
1078 C: UndefValue::get(T: Int1), S1: UndefValue::get(T: Int32), S2: UndefValue::get(T: Int32));
1079 VPValue Op1;
1080 VPValue Op2;
1081 VPValue Op3;
1082 SmallVector<VPValue *, 4> Args;
1083 Args.push_back(Elt: &Op1);
1084 Args.push_back(Elt: &Op2);
1085 Args.push_back(Elt: &Op3);
1086 VPWidenSelectRecipe Recipe(*SelectI, make_range(x: Args.begin(), y: Args.end()));
1087 EXPECT_FALSE(Recipe.mayHaveSideEffects());
1088 EXPECT_FALSE(Recipe.mayReadFromMemory());
1089 EXPECT_FALSE(Recipe.mayWriteToMemory());
1090 EXPECT_FALSE(Recipe.mayReadOrWriteMemory());
1091 delete SelectI;
1092 }
1093
1094 {
1095 auto *GEP = GetElementPtrInst::Create(PointeeType: Int32, Ptr: UndefValue::get(T: Int32Ptr),
1096 IdxList: UndefValue::get(T: Int32));
1097 VPValue Op1;
1098 VPValue Op2;
1099 SmallVector<VPValue *, 4> Args;
1100 Args.push_back(Elt: &Op1);
1101 Args.push_back(Elt: &Op2);
1102 VPWidenGEPRecipe Recipe(GEP, make_range(x: Args.begin(), y: Args.end()));
1103 EXPECT_FALSE(Recipe.mayHaveSideEffects());
1104 EXPECT_FALSE(Recipe.mayReadFromMemory());
1105 EXPECT_FALSE(Recipe.mayWriteToMemory());
1106 EXPECT_FALSE(Recipe.mayReadOrWriteMemory());
1107 delete GEP;
1108 }
1109
1110 {
1111 VPValue Mask;
1112 VPBranchOnMaskRecipe Recipe(&Mask);
1113 EXPECT_TRUE(Recipe.mayHaveSideEffects());
1114 EXPECT_FALSE(Recipe.mayReadFromMemory());
1115 EXPECT_FALSE(Recipe.mayWriteToMemory());
1116 EXPECT_FALSE(Recipe.mayReadOrWriteMemory());
1117 }
1118
1119 {
1120 VPValue ChainOp;
1121 VPValue VecOp;
1122 VPValue CondOp;
1123 VPReductionRecipe Recipe(RecurrenceDescriptor(), nullptr, &ChainOp, &CondOp,
1124 &VecOp, false);
1125 EXPECT_FALSE(Recipe.mayHaveSideEffects());
1126 EXPECT_FALSE(Recipe.mayReadFromMemory());
1127 EXPECT_FALSE(Recipe.mayWriteToMemory());
1128 EXPECT_FALSE(Recipe.mayReadOrWriteMemory());
1129 }
1130
1131 {
1132 auto *Load =
1133 new LoadInst(Int32, UndefValue::get(T: Int32Ptr), "", false, Align(1));
1134 VPValue Addr;
1135 VPValue Mask;
1136 VPWidenLoadRecipe Recipe(*Load, &Addr, &Mask, true, false, {});
1137 EXPECT_FALSE(Recipe.mayHaveSideEffects());
1138 EXPECT_TRUE(Recipe.mayReadFromMemory());
1139 EXPECT_FALSE(Recipe.mayWriteToMemory());
1140 EXPECT_TRUE(Recipe.mayReadOrWriteMemory());
1141 delete Load;
1142 }
1143
1144 {
1145 auto *Store = new StoreInst(UndefValue::get(T: Int32),
1146 UndefValue::get(T: Int32Ptr), false, Align(1));
1147 VPValue Addr;
1148 VPValue Mask;
1149 VPValue StoredV;
1150 VPWidenStoreRecipe Recipe(*Store, &Addr, &StoredV, &Mask, false, false, {});
1151 EXPECT_TRUE(Recipe.mayHaveSideEffects());
1152 EXPECT_FALSE(Recipe.mayReadFromMemory());
1153 EXPECT_TRUE(Recipe.mayWriteToMemory());
1154 EXPECT_TRUE(Recipe.mayReadOrWriteMemory());
1155 delete Store;
1156 }
1157
1158 {
1159 FunctionType *FTy = FunctionType::get(Result: Int32, isVarArg: false);
1160 auto *Call = CallInst::Create(Ty: FTy, F: UndefValue::get(T: FTy));
1161 VPValue Op1;
1162 VPValue Op2;
1163 SmallVector<VPValue *, 2> Args;
1164 Args.push_back(Elt: &Op1);
1165 Args.push_back(Elt: &Op2);
1166 VPWidenCallRecipe Recipe(*Call, make_range(x: Args.begin(), y: Args.end()),
1167 false);
1168 EXPECT_TRUE(Recipe.mayHaveSideEffects());
1169 EXPECT_TRUE(Recipe.mayReadFromMemory());
1170 EXPECT_TRUE(Recipe.mayWriteToMemory());
1171 EXPECT_TRUE(Recipe.mayReadOrWriteMemory());
1172 delete Call;
1173 }
1174
1175 {
1176 // Test for a call to a function without side-effects.
1177 LLVMContext C;
1178 Module M("", C);
1179 Function *TheFn = Intrinsic::getDeclaration(M: &M, Intrinsic::id: thread_pointer);
1180
1181 auto *Call = CallInst::Create(Ty: TheFn->getFunctionType(), F: TheFn);
1182 VPValue Op1;
1183 VPValue Op2;
1184 SmallVector<VPValue *, 2> Args;
1185 Args.push_back(Elt: &Op1);
1186 Args.push_back(Elt: &Op2);
1187 VPWidenCallRecipe Recipe(*Call, make_range(x: Args.begin(), y: Args.end()),
1188 false);
1189 EXPECT_FALSE(Recipe.mayHaveSideEffects());
1190 EXPECT_FALSE(Recipe.mayReadFromMemory());
1191 EXPECT_FALSE(Recipe.mayWriteToMemory());
1192 EXPECT_FALSE(Recipe.mayReadOrWriteMemory());
1193 delete Call;
1194 }
1195
1196 {
1197 VPValue Op1;
1198 VPValue Op2;
1199 InductionDescriptor IndDesc;
1200 VPScalarIVStepsRecipe Recipe(IndDesc, &Op1, &Op2);
1201 EXPECT_FALSE(Recipe.mayHaveSideEffects());
1202 EXPECT_FALSE(Recipe.mayReadFromMemory());
1203 EXPECT_FALSE(Recipe.mayWriteToMemory());
1204 EXPECT_FALSE(Recipe.mayReadOrWriteMemory());
1205 }
1206
1207 // The initial implementation is conservative with respect to VPInstructions.
1208 {
1209 VPValue Op1;
1210 VPValue Op2;
1211 VPInstruction VPInst(Instruction::Add, {&Op1, &Op2});
1212 VPRecipeBase &Recipe = VPInst;
1213 EXPECT_TRUE(Recipe.mayHaveSideEffects());
1214 EXPECT_TRUE(Recipe.mayReadFromMemory());
1215 EXPECT_TRUE(Recipe.mayWriteToMemory());
1216 EXPECT_TRUE(Recipe.mayReadOrWriteMemory());
1217 }
1218 {
1219 VPValue Op1;
1220 VPPredInstPHIRecipe Recipe(&Op1);
1221 EXPECT_FALSE(Recipe.mayHaveSideEffects());
1222 EXPECT_FALSE(Recipe.mayReadFromMemory());
1223 EXPECT_FALSE(Recipe.mayWriteToMemory());
1224 EXPECT_FALSE(Recipe.mayReadOrWriteMemory());
1225 }
1226}
1227
1228#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1229TEST(VPRecipeTest, dumpRecipeInPlan) {
1230 VPBasicBlock *VPBB0 = new VPBasicBlock("preheader");
1231 VPBasicBlock *VPBB1 = new VPBasicBlock();
1232 VPlan Plan(VPBB0, VPBB1);
1233
1234 LLVMContext C;
1235
1236 IntegerType *Int32 = IntegerType::get(C, NumBits: 32);
1237 auto *AI =
1238 BinaryOperator::CreateAdd(V1: UndefValue::get(T: Int32), V2: UndefValue::get(T: Int32));
1239 AI->setName("a");
1240 SmallVector<VPValue *, 2> Args;
1241 VPValue *ExtVPV1 = Plan.getOrAddLiveIn(V: ConstantInt::get(Ty: Int32, V: 1));
1242 VPValue *ExtVPV2 = Plan.getOrAddLiveIn(V: ConstantInt::get(Ty: Int32, V: 2));
1243 Args.push_back(Elt: ExtVPV1);
1244 Args.push_back(Elt: ExtVPV2);
1245 VPWidenRecipe *WidenR =
1246 new VPWidenRecipe(*AI, make_range(x: Args.begin(), y: Args.end()));
1247 VPBB1->appendRecipe(Recipe: WidenR);
1248
1249 {
1250 // Use EXPECT_EXIT to capture stderr and compare against expected output.
1251 //
1252 // Test VPValue::dump().
1253 VPValue *VPV = WidenR;
1254 EXPECT_EXIT(
1255 {
1256 VPV->dump();
1257 exit(0);
1258 },
1259 testing::ExitedWithCode(0), "WIDEN ir<%a> = add ir<1>, ir<2>");
1260
1261 // Test VPRecipeBase::dump().
1262 VPRecipeBase *R = WidenR;
1263 EXPECT_EXIT(
1264 {
1265 R->dump();
1266 exit(0);
1267 },
1268 testing::ExitedWithCode(0), "WIDEN ir<%a> = add ir<1>, ir<2>");
1269
1270 // Test VPDef::dump().
1271 VPDef *D = WidenR;
1272 EXPECT_EXIT(
1273 {
1274 D->dump();
1275 exit(0);
1276 },
1277 testing::ExitedWithCode(0), "WIDEN ir<%a> = add ir<1>, ir<2>");
1278 }
1279
1280 delete AI;
1281}
1282
1283TEST(VPRecipeTest, dumpRecipeUnnamedVPValuesInPlan) {
1284 VPBasicBlock *VPBB0 = new VPBasicBlock("preheader");
1285 VPBasicBlock *VPBB1 = new VPBasicBlock();
1286 VPlan Plan(VPBB0, VPBB1);
1287
1288 LLVMContext C;
1289
1290 IntegerType *Int32 = IntegerType::get(C, NumBits: 32);
1291 auto *AI =
1292 BinaryOperator::CreateAdd(V1: UndefValue::get(T: Int32), V2: UndefValue::get(T: Int32));
1293 AI->setName("a");
1294 SmallVector<VPValue *, 2> Args;
1295 VPValue *ExtVPV1 = Plan.getOrAddLiveIn(V: ConstantInt::get(Ty: Int32, V: 1));
1296 VPValue *ExtVPV2 = Plan.getOrAddLiveIn(V: AI);
1297 Args.push_back(Elt: ExtVPV1);
1298 Args.push_back(Elt: ExtVPV2);
1299 VPInstruction *I1 = new VPInstruction(Instruction::Add, {ExtVPV1, ExtVPV2});
1300 VPInstruction *I2 = new VPInstruction(Instruction::Mul, {I1, I1});
1301 VPBB1->appendRecipe(Recipe: I1);
1302 VPBB1->appendRecipe(Recipe: I2);
1303
1304 // Check printing I1.
1305 {
1306 // Use EXPECT_EXIT to capture stderr and compare against expected output.
1307 //
1308 // Test VPValue::dump().
1309 VPValue *VPV = I1;
1310 EXPECT_EXIT(
1311 {
1312 VPV->dump();
1313 exit(0);
1314 },
1315 testing::ExitedWithCode(0), "EMIT vp<%1> = add ir<1>, ir<%a>");
1316
1317 // Test VPRecipeBase::dump().
1318 VPRecipeBase *R = I1;
1319 EXPECT_EXIT(
1320 {
1321 R->dump();
1322 exit(0);
1323 },
1324 testing::ExitedWithCode(0), "EMIT vp<%1> = add ir<1>, ir<%a>");
1325
1326 // Test VPDef::dump().
1327 VPDef *D = I1;
1328 EXPECT_EXIT(
1329 {
1330 D->dump();
1331 exit(0);
1332 },
1333 testing::ExitedWithCode(0), "EMIT vp<%1> = add ir<1>, ir<%a>");
1334 }
1335 // Check printing I2.
1336 {
1337 // Use EXPECT_EXIT to capture stderr and compare against expected output.
1338 //
1339 // Test VPValue::dump().
1340 VPValue *VPV = I2;
1341 EXPECT_EXIT(
1342 {
1343 VPV->dump();
1344 exit(0);
1345 },
1346 testing::ExitedWithCode(0), "EMIT vp<%2> = mul vp<%1>, vp<%1>");
1347
1348 // Test VPRecipeBase::dump().
1349 VPRecipeBase *R = I2;
1350 EXPECT_EXIT(
1351 {
1352 R->dump();
1353 exit(0);
1354 },
1355 testing::ExitedWithCode(0), "EMIT vp<%2> = mul vp<%1>, vp<%1>");
1356
1357 // Test VPDef::dump().
1358 VPDef *D = I2;
1359 EXPECT_EXIT(
1360 {
1361 D->dump();
1362 exit(0);
1363 },
1364 testing::ExitedWithCode(0), "EMIT vp<%2> = mul vp<%1>, vp<%1>");
1365 }
1366 delete AI;
1367}
1368
1369TEST(VPRecipeTest, dumpRecipeUnnamedVPValuesNotInPlanOrBlock) {
1370 LLVMContext C;
1371 IntegerType *Int32 = IntegerType::get(C, NumBits: 32);
1372 auto *AI =
1373 BinaryOperator::CreateAdd(V1: UndefValue::get(T: Int32), V2: UndefValue::get(T: Int32));
1374 AI->setName("a");
1375 VPValue *ExtVPV1 = new VPValue(ConstantInt::get(Ty: Int32, V: 1));
1376 VPValue *ExtVPV2 = new VPValue(AI);
1377
1378 VPInstruction *I1 = new VPInstruction(Instruction::Add, {ExtVPV1, ExtVPV2});
1379 VPInstruction *I2 = new VPInstruction(Instruction::Mul, {I1, I1});
1380
1381 // Check printing I1.
1382 {
1383 // Use EXPECT_EXIT to capture stderr and compare against expected output.
1384 //
1385 // Test VPValue::dump().
1386 VPValue *VPV = I1;
1387 EXPECT_EXIT(
1388 {
1389 VPV->dump();
1390 exit(0);
1391 },
1392 testing::ExitedWithCode(0), "EMIT <badref> = add ir<1>, ir<%a>");
1393
1394 // Test VPRecipeBase::dump().
1395 VPRecipeBase *R = I1;
1396 EXPECT_EXIT(
1397 {
1398 R->dump();
1399 exit(0);
1400 },
1401 testing::ExitedWithCode(0), "EMIT <badref> = add ir<1>, ir<%a>");
1402
1403 // Test VPDef::dump().
1404 VPDef *D = I1;
1405 EXPECT_EXIT(
1406 {
1407 D->dump();
1408 exit(0);
1409 },
1410 testing::ExitedWithCode(0), "EMIT <badref> = add ir<1>, ir<%a>");
1411 }
1412 // Check printing I2.
1413 {
1414 // Use EXPECT_EXIT to capture stderr and compare against expected output.
1415 //
1416 // Test VPValue::dump().
1417 VPValue *VPV = I2;
1418 EXPECT_EXIT(
1419 {
1420 VPV->dump();
1421 exit(0);
1422 },
1423 testing::ExitedWithCode(0), "EMIT <badref> = mul <badref>, <badref>");
1424
1425 // Test VPRecipeBase::dump().
1426 VPRecipeBase *R = I2;
1427 EXPECT_EXIT(
1428 {
1429 R->dump();
1430 exit(0);
1431 },
1432 testing::ExitedWithCode(0), "EMIT <badref> = mul <badref>, <badref>");
1433
1434 // Test VPDef::dump().
1435 VPDef *D = I2;
1436 EXPECT_EXIT(
1437 {
1438 D->dump();
1439 exit(0);
1440 },
1441 testing::ExitedWithCode(0), "EMIT <badref> = mul <badref>, <badref>");
1442 }
1443
1444 delete I2;
1445 delete I1;
1446 delete ExtVPV2;
1447 delete ExtVPV1;
1448 delete AI;
1449}
1450
1451#endif
1452
1453TEST(VPRecipeTest, CastVPReductionRecipeToVPUser) {
1454 LLVMContext C;
1455
1456 VPValue ChainOp;
1457 VPValue VecOp;
1458 VPValue CondOp;
1459 VPReductionRecipe Recipe(RecurrenceDescriptor(), nullptr, &ChainOp, &CondOp,
1460 &VecOp, false);
1461 EXPECT_TRUE(isa<VPUser>(&Recipe));
1462 VPRecipeBase *BaseR = &Recipe;
1463 EXPECT_TRUE(isa<VPUser>(BaseR));
1464}
1465
1466struct VPDoubleValueDef : public VPRecipeBase {
1467 VPDoubleValueDef(ArrayRef<VPValue *> Operands) : VPRecipeBase(99, Operands) {
1468 new VPValue(nullptr, this);
1469 new VPValue(nullptr, this);
1470 }
1471
1472 VPRecipeBase *clone() override { return nullptr; }
1473
1474 void execute(struct VPTransformState &State) override {}
1475#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1476 void print(raw_ostream &O, const Twine &Indent,
1477 VPSlotTracker &SlotTracker) const override {}
1478#endif
1479};
1480
1481TEST(VPDoubleValueDefTest, traverseUseLists) {
1482 // Check that the def-use chains of a multi-def can be traversed in both
1483 // directions.
1484
1485 // Create a new VPDef which defines 2 values and has 2 operands.
1486 VPInstruction Op0(20, {});
1487 VPInstruction Op1(30, {});
1488 VPDoubleValueDef DoubleValueDef({&Op0, &Op1});
1489
1490 // Create a new users of the defined values.
1491 VPInstruction I1(
1492 1, {DoubleValueDef.getVPValue(I: 0), DoubleValueDef.getVPValue(I: 1)});
1493 VPInstruction I2(2, {DoubleValueDef.getVPValue(I: 0)});
1494 VPInstruction I3(3, {DoubleValueDef.getVPValue(I: 1)});
1495
1496 // Check operands of the VPDef (traversing upwards).
1497 SmallVector<VPValue *, 4> DoubleOperands(DoubleValueDef.op_begin(),
1498 DoubleValueDef.op_end());
1499 EXPECT_EQ(2u, DoubleOperands.size());
1500 EXPECT_EQ(&Op0, DoubleOperands[0]);
1501 EXPECT_EQ(&Op1, DoubleOperands[1]);
1502
1503 // Check users of the defined values (traversing downwards).
1504 SmallVector<VPUser *, 4> DoubleValueDefV0Users(
1505 DoubleValueDef.getVPValue(I: 0)->user_begin(),
1506 DoubleValueDef.getVPValue(I: 0)->user_end());
1507 EXPECT_EQ(2u, DoubleValueDefV0Users.size());
1508 EXPECT_EQ(&I1, DoubleValueDefV0Users[0]);
1509 EXPECT_EQ(&I2, DoubleValueDefV0Users[1]);
1510
1511 SmallVector<VPUser *, 4> DoubleValueDefV1Users(
1512 DoubleValueDef.getVPValue(I: 1)->user_begin(),
1513 DoubleValueDef.getVPValue(I: 1)->user_end());
1514 EXPECT_EQ(2u, DoubleValueDefV1Users.size());
1515 EXPECT_EQ(&I1, DoubleValueDefV1Users[0]);
1516 EXPECT_EQ(&I3, DoubleValueDefV1Users[1]);
1517
1518 // Now check that we can get the right VPDef for each defined value.
1519 EXPECT_EQ(&DoubleValueDef, I1.getOperand(0)->getDefiningRecipe());
1520 EXPECT_EQ(&DoubleValueDef, I1.getOperand(1)->getDefiningRecipe());
1521 EXPECT_EQ(&DoubleValueDef, I2.getOperand(0)->getDefiningRecipe());
1522 EXPECT_EQ(&DoubleValueDef, I3.getOperand(0)->getDefiningRecipe());
1523}
1524
1525} // namespace
1526} // namespace llvm
1527

source code of llvm/unittests/Transforms/Vectorize/VPlanTest.cpp