[flang] Update CommandTest for AIX (NFC) (#118403)
[llvm-project.git] / llvm / unittests / Analysis / IRSimilarityIdentifierTest.cpp
blob24f4f11db9a8b9c8b379635f7c0033fde2a86262
1 //===- IRSimilarityIdentifierTest.cpp - IRSimilarityIdentifier unit tests -===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Tests for components for finding similarity such as the instruction mapper,
10 // suffix tree usage, and structural analysis.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/Analysis/IRSimilarityIdentifier.h"
15 #include "llvm/ADT/ScopeExit.h"
16 #include "llvm/AsmParser/Parser.h"
17 #include "llvm/IR/LLVMContext.h"
18 #include "llvm/IR/Module.h"
19 #include "llvm/Support/Allocator.h"
20 #include "llvm/Support/SourceMgr.h"
21 #include "gtest/gtest.h"
23 using namespace llvm;
24 using namespace IRSimilarity;
26 extern llvm::cl::opt<bool> UseNewDbgInfoFormat;
27 extern cl::opt<cl::boolOrDefault> PreserveInputDbgFormat;
28 extern bool WriteNewDbgInfoFormatToBitcode;
29 extern cl::opt<bool> WriteNewDbgInfoFormat;
31 static std::unique_ptr<Module> makeLLVMModule(LLVMContext &Context,
32 StringRef ModuleStr) {
33 SMDiagnostic Err;
34 std::unique_ptr<Module> M = parseAssemblyString(ModuleStr, Err, Context);
35 assert(M && "Bad LLVM IR?");
36 return M;
39 void getVectors(Module &M, IRInstructionMapper &Mapper,
40 std::vector<IRInstructionData *> &InstrList,
41 std::vector<unsigned> &UnsignedVec) {
42 for (Function &F : M)
43 for (BasicBlock &BB : F)
44 Mapper.convertToUnsignedVec(BB, InstrList, UnsignedVec);
47 void getSimilarities(
48 Module &M,
49 std::vector<std::vector<IRSimilarityCandidate>> &SimilarityCandidates) {
50 // In order to keep the size of the tests from becoming too large, we do not
51 // recognize similarity for branches unless explicitly needed.
52 IRSimilarityIdentifier Identifier(/*EnableBranchMatching = */false);
53 SimilarityCandidates = Identifier.findSimilarity(M);
56 // Checks that different opcodes are mapped to different values
57 TEST(IRInstructionMapper, OpcodeDifferentiation) {
58 StringRef ModuleString = R"(
59 define i32 @f(i32 %a, i32 %b) {
60 bb0:
61 %0 = add i32 %a, %b
62 %1 = mul i32 %a, %b
63 ret i32 0
64 })";
65 LLVMContext Context;
66 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
68 std::vector<IRInstructionData *> InstrList;
69 std::vector<unsigned> UnsignedVec;
71 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
72 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
73 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
74 getVectors(*M, Mapper, InstrList, UnsignedVec);
76 // Check that the size of the unsigned vector and the instruction list are the
77 // same as a safety check.
78 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
80 // Make sure that the unsigned vector is the expected size.
81 ASSERT_TRUE(UnsignedVec.size() == 3);
83 // Check whether the instructions are not mapped to the same value.
84 ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]);
87 // Checks that the same opcodes and types are mapped to the same values.
88 TEST(IRInstructionMapper, OpcodeTypeSimilarity) {
89 StringRef ModuleString = R"(
90 define i32 @f(i32 %a, i32 %b) {
91 bb0:
92 %0 = add i32 %a, %b
93 %1 = add i32 %b, %a
94 ret i32 0
95 })";
96 LLVMContext Context;
97 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
99 std::vector<IRInstructionData *> InstrList;
100 std::vector<unsigned> UnsignedVec;
102 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
103 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
104 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
105 getVectors(*M, Mapper, InstrList, UnsignedVec);
107 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
108 ASSERT_TRUE(UnsignedVec.size() == 3);
110 // Check whether the instructions are mapped to the same value.
111 ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]);
114 // Checks that the same opcode and different types are mapped to different
115 // values.
116 TEST(IRInstructionMapper, TypeDifferentiation) {
117 StringRef ModuleString = R"(
118 define i32 @f(i32 %a, i32 %b, i64 %c, i64 %d) {
119 bb0:
120 %0 = add i32 %a, %b
121 %1 = add i64 %c, %d
122 ret i32 0
123 })";
124 LLVMContext Context;
125 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
127 std::vector<IRInstructionData *> InstrList;
128 std::vector<unsigned> UnsignedVec;
130 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
131 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
132 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
133 getVectors(*M, Mapper, InstrList, UnsignedVec);
135 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
136 ASSERT_TRUE(UnsignedVec.size() == 3);
137 ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]);
140 // Checks that different predicates map to different values.
141 TEST(IRInstructionMapper, PredicateDifferentiation) {
142 StringRef ModuleString = R"(
143 define i32 @f(i32 %a, i32 %b) {
144 bb0:
145 %0 = icmp sge i32 %b, %a
146 %1 = icmp slt i32 %a, %b
147 ret i32 0
148 })";
149 LLVMContext Context;
150 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
152 std::vector<IRInstructionData *> InstrList;
153 std::vector<unsigned> UnsignedVec;
155 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
156 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
157 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
158 getVectors(*M, Mapper, InstrList, UnsignedVec);
160 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
161 ASSERT_TRUE(UnsignedVec.size() == 3);
162 ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]);
165 // Checks that predicates where that can be considered the same when the
166 // operands are swapped, i.e. greater than to less than are mapped to the same
167 // unsigned integer.
168 TEST(IRInstructionMapper, PredicateIsomorphism) {
169 StringRef ModuleString = R"(
170 define i32 @f(i32 %a, i32 %b) {
171 bb0:
172 %0 = icmp sgt i32 %a, %b
173 %1 = icmp slt i32 %b, %a
174 ret i32 0
175 })";
176 LLVMContext Context;
177 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
179 std::vector<IRInstructionData *> InstrList;
180 std::vector<unsigned> UnsignedVec;
182 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
183 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
184 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
185 getVectors(*M, Mapper, InstrList, UnsignedVec);
187 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
188 ASSERT_TRUE(UnsignedVec.size() == 3);
189 ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]);
192 // Checks that the same predicate maps to the same value.
193 TEST(IRInstructionMapper, PredicateSimilarity) {
194 StringRef ModuleString = R"(
195 define i32 @f(i32 %a, i32 %b) {
196 bb0:
197 %0 = icmp slt i32 %a, %b
198 %1 = icmp slt i32 %b, %a
199 ret i32 0
200 })";
201 LLVMContext Context;
202 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
204 std::vector<IRInstructionData *> InstrList;
205 std::vector<unsigned> UnsignedVec;
207 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
208 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
209 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
210 getVectors(*M, Mapper, InstrList, UnsignedVec);
212 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
213 ASSERT_TRUE(UnsignedVec.size() == 3);
214 ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]);
217 // Checks that the same predicate maps to the same value for floating point
218 // CmpInsts.
219 TEST(IRInstructionMapper, FPPredicateSimilarity) {
220 StringRef ModuleString = R"(
221 define i32 @f(double %a, double %b) {
222 bb0:
223 %0 = fcmp olt double %a, %b
224 %1 = fcmp olt double %b, %a
225 ret i32 0
226 })";
227 LLVMContext Context;
228 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
230 std::vector<IRInstructionData *> InstrList;
231 std::vector<unsigned> UnsignedVec;
233 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
234 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
235 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
236 getVectors(*M, Mapper, InstrList, UnsignedVec);
238 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
239 ASSERT_TRUE(UnsignedVec.size() == 3);
240 ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]);
243 // Checks that the different predicate maps to a different value for floating
244 // point CmpInsts.
245 TEST(IRInstructionMapper, FPPredicatDifference) {
246 StringRef ModuleString = R"(
247 define i32 @f(double %a, double %b) {
248 bb0:
249 %0 = fcmp olt double %a, %b
250 %1 = fcmp oge double %b, %a
251 ret i32 0
252 })";
253 LLVMContext Context;
254 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
256 std::vector<IRInstructionData *> InstrList;
257 std::vector<unsigned> UnsignedVec;
259 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
260 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
261 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
262 getVectors(*M, Mapper, InstrList, UnsignedVec);
264 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
265 ASSERT_TRUE(UnsignedVec.size() == 3);
266 ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]);
269 // Checks that the zexts that have the same type parameters map to the same
270 // unsigned integer.
271 TEST(IRInstructionMapper, ZextTypeSimilarity) {
272 StringRef ModuleString = R"(
273 define i32 @f(i32 %a) {
274 bb0:
275 %0 = zext i32 %a to i64
276 %1 = zext i32 %a to i64
277 ret i32 0
278 })";
279 LLVMContext Context;
280 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
282 std::vector<IRInstructionData *> InstrList;
283 std::vector<unsigned> UnsignedVec;
285 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
286 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
287 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
288 getVectors(*M, Mapper, InstrList, UnsignedVec);
290 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
291 ASSERT_TRUE(UnsignedVec.size() == 3);
292 ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]);
295 // Checks that the sexts that have the same type parameters map to the same
296 // unsigned integer.
297 TEST(IRInstructionMapper, SextTypeSimilarity) {
298 StringRef ModuleString = R"(
299 define i32 @f(i32 %a) {
300 bb0:
301 %0 = sext i32 %a to i64
302 %1 = sext i32 %a to i64
303 ret i32 0
304 })";
305 LLVMContext Context;
306 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
308 std::vector<IRInstructionData *> InstrList;
309 std::vector<unsigned> UnsignedVec;
311 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
312 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
313 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
314 getVectors(*M, Mapper, InstrList, UnsignedVec);
316 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
317 ASSERT_TRUE(UnsignedVec.size() == 3);
318 ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]);
321 // Checks that the zexts that have the different type parameters map to the
322 // different unsigned integers.
323 TEST(IRInstructionMapper, ZextTypeDifference) {
324 StringRef ModuleString = R"(
325 define i32 @f(i32 %a, i8 %b) {
326 bb0:
327 %0 = zext i32 %a to i64
328 %1 = zext i8 %b to i32
329 ret i32 0
330 })";
331 LLVMContext Context;
332 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
334 std::vector<IRInstructionData *> InstrList;
335 std::vector<unsigned> UnsignedVec;
337 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
338 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
339 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
340 getVectors(*M, Mapper, InstrList, UnsignedVec);
342 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
343 ASSERT_TRUE(UnsignedVec.size() == 3);
344 ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]);
347 // Checks that the sexts that have the different type parameters map to the
348 // different unsigned integers.
349 TEST(IRInstructionMapper, SextTypeDifference) {
350 StringRef ModuleString = R"(
351 define i32 @f(i32 %a, i8 %b) {
352 bb0:
353 %0 = sext i32 %a to i64
354 %1 = sext i8 %b to i32
355 ret i32 0
356 })";
357 LLVMContext Context;
358 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
360 std::vector<IRInstructionData *> InstrList;
361 std::vector<unsigned> UnsignedVec;
363 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
364 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
365 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
366 getVectors(*M, Mapper, InstrList, UnsignedVec);
368 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
369 ASSERT_TRUE(UnsignedVec.size() == 3);
370 ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]);
373 // Checks that loads that have the same type are mapped to the same unsigned
374 // integer.
375 TEST(IRInstructionMapper, LoadSimilarType) {
376 StringRef ModuleString = R"(
377 define i32 @f(i32* %a, i32* %b) {
378 bb0:
379 %0 = load i32, i32* %a
380 %1 = load i32, i32* %b
381 ret i32 0
382 })";
383 LLVMContext Context;
384 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
386 std::vector<IRInstructionData *> InstrList;
387 std::vector<unsigned> UnsignedVec;
389 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
390 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
391 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
392 getVectors(*M, Mapper, InstrList, UnsignedVec);
394 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
395 ASSERT_TRUE(UnsignedVec.size() == 3);
396 ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]);
399 // Checks that loads that have the different types are mapped to
400 // different unsigned integers.
401 TEST(IRInstructionMapper, LoadDifferentType) {
402 StringRef ModuleString = R"(
403 define i32 @f(i32* %a, i64* %b) {
404 bb0:
405 %0 = load i32, i32* %a
406 %1 = load i64, i64* %b
407 ret i32 0
408 })";
409 LLVMContext Context;
410 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
412 std::vector<IRInstructionData *> InstrList;
413 std::vector<unsigned> UnsignedVec;
415 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
416 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
417 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
418 getVectors(*M, Mapper, InstrList, UnsignedVec);
420 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
421 ASSERT_TRUE(UnsignedVec.size() == 3);
422 ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]);
425 // Checks that loads that have the different aligns are mapped to different
426 // unsigned integers.
427 TEST(IRInstructionMapper, LoadDifferentAlign) {
428 StringRef ModuleString = R"(
429 define i32 @f(i32* %a, i32* %b) {
430 bb0:
431 %0 = load i32, i32* %a, align 4
432 %1 = load i32, i32* %b, align 8
433 ret i32 0
434 })";
435 LLVMContext Context;
436 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
438 std::vector<IRInstructionData *> InstrList;
439 std::vector<unsigned> UnsignedVec;
441 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
442 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
443 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
444 getVectors(*M, Mapper, InstrList, UnsignedVec);
446 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
447 ASSERT_TRUE(UnsignedVec.size() == 3);
448 ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]);
451 // Checks that loads that have the different volatile settings are mapped to
452 // different unsigned integers.
453 TEST(IRInstructionMapper, LoadDifferentVolatile) {
454 StringRef ModuleString = R"(
455 define i32 @f(i32* %a, i32* %b) {
456 bb0:
457 %0 = load volatile i32, i32* %a
458 %1 = load i32, i32* %b
459 ret i32 0
460 })";
461 LLVMContext Context;
462 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
464 std::vector<IRInstructionData *> InstrList;
465 std::vector<unsigned> UnsignedVec;
467 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
468 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
469 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
470 getVectors(*M, Mapper, InstrList, UnsignedVec);
472 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
473 ASSERT_TRUE(UnsignedVec.size() == 3);
474 ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]);
477 // Checks that loads that have the same volatile settings are mapped to
478 // different unsigned integers.
479 TEST(IRInstructionMapper, LoadSameVolatile) {
480 StringRef ModuleString = R"(
481 define i32 @f(i32* %a, i32* %b) {
482 bb0:
483 %0 = load volatile i32, i32* %a
484 %1 = load volatile i32, i32* %b
485 ret i32 0
486 })";
487 LLVMContext Context;
488 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
490 std::vector<IRInstructionData *> InstrList;
491 std::vector<unsigned> UnsignedVec;
493 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
494 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
495 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
496 getVectors(*M, Mapper, InstrList, UnsignedVec);
498 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
499 ASSERT_TRUE(UnsignedVec.size() == 3);
500 ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]);
503 // Checks that loads that have the different atomicity settings are mapped to
504 // different unsigned integers.
505 TEST(IRInstructionMapper, LoadDifferentAtomic) {
506 StringRef ModuleString = R"(
507 define i32 @f(i32* %a, i32* %b) {
508 bb0:
509 %0 = load atomic i32, i32* %a unordered, align 4
510 %1 = load atomic i32, i32* %b monotonic, align 4
511 ret i32 0
512 })";
513 LLVMContext Context;
514 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
516 std::vector<IRInstructionData *> InstrList;
517 std::vector<unsigned> UnsignedVec;
519 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
520 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
521 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
522 getVectors(*M, Mapper, InstrList, UnsignedVec);
524 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
525 ASSERT_TRUE(UnsignedVec.size() == 3);
526 ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]);
529 // Checks that loads that have the same atomicity settings are mapped to
530 // different unsigned integers.
531 TEST(IRInstructionMapper, LoadSameAtomic) {
532 StringRef ModuleString = R"(
533 define i32 @f(i32* %a, i32* %b) {
534 bb0:
535 %0 = load atomic i32, i32* %a unordered, align 4
536 %1 = load atomic i32, i32* %b unordered, align 4
537 ret i32 0
538 })";
539 LLVMContext Context;
540 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
542 std::vector<IRInstructionData *> InstrList;
543 std::vector<unsigned> UnsignedVec;
545 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
546 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
547 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
548 getVectors(*M, Mapper, InstrList, UnsignedVec);
550 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
551 ASSERT_TRUE(UnsignedVec.size() == 3);
552 ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]);
555 // Checks that stores that have the same type are mapped to the same unsigned
556 // integer.
557 TEST(IRInstructionMapper, StoreSimilarType) {
558 StringRef ModuleString = R"(
559 define i32 @f(i32* %a, i32* %b) {
560 bb0:
561 store i32 1, i32* %a
562 store i32 2, i32* %a
563 ret i32 0
564 })";
565 LLVMContext Context;
566 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
568 std::vector<IRInstructionData *> InstrList;
569 std::vector<unsigned> UnsignedVec;
571 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
572 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
573 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
574 getVectors(*M, Mapper, InstrList, UnsignedVec);
576 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
577 ASSERT_TRUE(UnsignedVec.size() == 3);
578 ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]);
581 // Checks that stores that have the different types are mapped to
582 // different unsigned integers.
583 TEST(IRInstructionMapper, StoreDifferentType) {
584 StringRef ModuleString = R"(
585 define i32 @f(i32* %a, i64* %b) {
586 bb0:
587 store i32 1, i32* %a
588 store i64 1, i64* %b
589 ret i32 0
590 })";
591 LLVMContext Context;
592 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
594 std::vector<IRInstructionData *> InstrList;
595 std::vector<unsigned> UnsignedVec;
597 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
598 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
599 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
600 getVectors(*M, Mapper, InstrList, UnsignedVec);
602 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
603 ASSERT_TRUE(UnsignedVec.size() == 3);
604 ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]);
607 // Checks that stores that have the different aligns are mapped to different
608 // unsigned integers.
609 TEST(IRInstructionMapper, StoreDifferentAlign) {
610 StringRef ModuleString = R"(
611 define i32 @f(i32* %a, i32* %b) {
612 bb0:
613 store i32 1, i32* %a, align 4
614 store i32 1, i32* %b, align 8
615 ret i32 0
616 })";
617 LLVMContext Context;
618 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
620 std::vector<IRInstructionData *> InstrList;
621 std::vector<unsigned> UnsignedVec;
623 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
624 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
625 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
626 getVectors(*M, Mapper, InstrList, UnsignedVec);
628 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
629 ASSERT_TRUE(UnsignedVec.size() == 3);
630 ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]);
633 // Checks that stores that have the different volatile settings are mapped to
634 // different unsigned integers.
635 TEST(IRInstructionMapper, StoreDifferentVolatile) {
636 StringRef ModuleString = R"(
637 define i32 @f(i32* %a, i32* %b) {
638 bb0:
639 store volatile i32 1, i32* %a
640 store i32 1, i32* %b
641 ret i32 0
642 })";
643 LLVMContext Context;
644 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
646 std::vector<IRInstructionData *> InstrList;
647 std::vector<unsigned> UnsignedVec;
649 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
650 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
651 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
652 getVectors(*M, Mapper, InstrList, UnsignedVec);
654 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
655 ASSERT_TRUE(UnsignedVec.size() == 3);
656 ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]);
659 // Checks that stores that have the same volatile settings are mapped to
660 // different unsigned integers.
661 TEST(IRInstructionMapper, StoreSameVolatile) {
662 StringRef ModuleString = R"(
663 define i32 @f(i32* %a, i32* %b) {
664 bb0:
665 store volatile i32 1, i32* %a
666 store volatile i32 1, i32* %b
667 ret i32 0
668 })";
669 LLVMContext Context;
670 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
672 std::vector<IRInstructionData *> InstrList;
673 std::vector<unsigned> UnsignedVec;
675 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
676 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
677 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
678 getVectors(*M, Mapper, InstrList, UnsignedVec);
680 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
681 ASSERT_TRUE(UnsignedVec.size() == 3);
682 ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]);
685 // Checks that loads that have the same atomicity settings are mapped to
686 // different unsigned integers.
687 TEST(IRInstructionMapper, StoreSameAtomic) {
688 StringRef ModuleString = R"(
689 define i32 @f(i32* %a, i32* %b) {
690 bb0:
691 store atomic i32 1, i32* %a unordered, align 4
692 store atomic i32 1, i32* %b unordered, align 4
693 ret i32 0
694 })";
695 LLVMContext Context;
696 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
698 std::vector<IRInstructionData *> InstrList;
699 std::vector<unsigned> UnsignedVec;
701 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
702 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
703 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
704 getVectors(*M, Mapper, InstrList, UnsignedVec);
706 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
707 ASSERT_TRUE(UnsignedVec.size() == 3);
708 ASSERT_TRUE(UnsignedVec[0] == UnsignedVec[1]);
711 // Checks that loads that have the different atomicity settings are mapped to
712 // different unsigned integers.
713 TEST(IRInstructionMapper, StoreDifferentAtomic) {
714 StringRef ModuleString = R"(
715 define i32 @f(i32* %a, i32* %b) {
716 bb0:
717 store atomic i32 1, i32* %a unordered, align 4
718 store atomic i32 1, i32* %b monotonic, align 4
719 ret i32 0
720 })";
721 LLVMContext Context;
722 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
724 std::vector<IRInstructionData *> InstrList;
725 std::vector<unsigned> UnsignedVec;
727 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
728 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
729 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
730 getVectors(*M, Mapper, InstrList, UnsignedVec);
732 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
733 ASSERT_TRUE(UnsignedVec.size() == 3);
734 ASSERT_TRUE(UnsignedVec[0] != UnsignedVec[1]);
737 // Checks that the branch is mapped to legal when the option is set.
738 TEST(IRInstructionMapper, BranchLegal) {
739 StringRef ModuleString = R"(
740 define i32 @f(i32 %a, i32 %b) {
741 bb0:
742 %0 = icmp slt i32 %a, %b
743 br i1 %0, label %bb0, label %bb1
744 bb1:
745 ret i32 0
746 })";
747 LLVMContext Context;
748 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
750 std::vector<IRInstructionData *> InstrList;
751 std::vector<unsigned> UnsignedVec;
753 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
754 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
755 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
756 Mapper.InstClassifier.EnableBranches = true;
757 Mapper.initializeForBBs(*M);
758 getVectors(*M, Mapper, InstrList, UnsignedVec);
760 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
761 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
762 ASSERT_TRUE(UnsignedVec[1] > UnsignedVec[0]);
763 ASSERT_TRUE(UnsignedVec[1] < UnsignedVec[2]);
766 // Checks that a PHINode is mapped to be legal.
767 TEST(IRInstructionMapper, PhiLegal) {
768 StringRef ModuleString = R"(
769 define i32 @f(i32 %a, i32 %b) {
770 bb0:
771 %0 = phi i1 [ 0, %bb0 ], [ %0, %bb1 ]
772 %1 = add i32 %a, %b
773 ret i32 0
774 bb1:
775 ret i32 1
776 })";
777 LLVMContext Context;
778 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
780 std::vector<IRInstructionData *> InstrList;
781 std::vector<unsigned> UnsignedVec;
783 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
784 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
785 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
786 Mapper.InstClassifier.EnableBranches = true;
787 Mapper.initializeForBBs(*M);
788 getVectors(*M, Mapper, InstrList, UnsignedVec);
790 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
791 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
794 // Checks that a PHINode is mapped to be legal.
795 TEST(IRInstructionMapper, PhiIllegal) {
796 StringRef ModuleString = R"(
797 define i32 @f(i32 %a, i32 %b) {
798 bb0:
799 %0 = phi i1 [ 0, %bb0 ], [ %0, %bb1 ]
800 %1 = add i32 %a, %b
801 ret i32 0
802 bb1:
803 ret i32 1
804 })";
805 LLVMContext Context;
806 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
808 std::vector<IRInstructionData *> InstrList;
809 std::vector<unsigned> UnsignedVec;
811 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
812 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
813 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
814 Mapper.initializeForBBs(*M);
815 getVectors(*M, Mapper, InstrList, UnsignedVec);
817 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
818 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
819 ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
822 // In most cases, the illegal instructions we are collecting don't require any
823 // sort of setup. In these cases, we can just only have illegal instructions,
824 // and the mapper will create 0 length vectors, and we can check that.
826 // In cases where we have legal instructions needed to set up the illegal
827 // instruction, to check illegal instructions are assigned unsigned integers
828 // from the maximum value decreasing to 0, it will be greater than a legal
829 // instruction that comes after. So to check that we have an illegal
830 // instruction, we place a legal instruction after an illegal instruction, and
831 // check that the illegal unsigned integer is greater than the unsigned integer
832 // of the legal instruction.
834 // Checks that an alloca instruction is mapped to be illegal.
835 TEST(IRInstructionMapper, AllocaIllegal) {
836 StringRef ModuleString = R"(
837 define i32 @f(i32 %a, i32 %b) {
838 bb0:
839 %0 = alloca i32
840 ret i32 0
841 })";
842 LLVMContext Context;
843 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
845 std::vector<IRInstructionData *> InstrList;
846 std::vector<unsigned> UnsignedVec;
848 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
849 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
850 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
851 getVectors(*M, Mapper, InstrList, UnsignedVec);
853 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
854 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(1));
855 ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
858 // Checks that an getelementptr instruction is mapped to be legal. And that
859 // the operands in getelementpointer instructions are the exact same after the
860 // first element operand, which only requires the same type.
861 TEST(IRInstructionMapper, GetElementPtrSameEndOperands) {
862 StringRef ModuleString = R"(
863 %struct.RT = type { i8, [10 x [20 x i32]], i8 }
864 %struct.ST = type { i32, double, %struct.RT }
865 define i32 @f(%struct.ST* %s, i64 %a, i64 %b) {
866 bb0:
867 %0 = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 %a, i32 0
868 %1 = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 %b, i32 0
869 ret i32 0
870 })";
871 LLVMContext Context;
872 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
874 std::vector<IRInstructionData *> InstrList;
875 std::vector<unsigned> UnsignedVec;
877 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
878 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
879 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
880 getVectors(*M, Mapper, InstrList, UnsignedVec);
882 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
883 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
884 ASSERT_EQ(UnsignedVec[0], UnsignedVec[1]);
887 // Check that when the operands in getelementpointer instructions are not the
888 // exact same after the first element operand, the instructions are mapped to
889 // different values.
890 TEST(IRInstructionMapper, GetElementPtrDifferentEndOperands) {
891 StringRef ModuleString = R"(
892 %struct.RT = type { i8, [10 x [20 x i32]], i8 }
893 %struct.ST = type { i32, double, %struct.RT }
894 define i32 @f(%struct.ST* %s, i64 %a, i64 %b) {
895 bb0:
896 %0 = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 %a, i32 0
897 %1 = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 %b, i32 2
898 ret i32 0
899 })";
900 LLVMContext Context;
901 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
903 std::vector<IRInstructionData *> InstrList;
904 std::vector<unsigned> UnsignedVec;
906 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
907 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
908 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
909 getVectors(*M, Mapper, InstrList, UnsignedVec);
911 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
912 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
913 ASSERT_NE(UnsignedVec[0], UnsignedVec[1]);
916 // Check that when the operands in getelementpointer instructions are not the
917 // same initial base type, each instruction is mapped to a different value.
918 TEST(IRInstructionMapper, GetElementPtrDifferentBaseType) {
919 StringRef ModuleString = R"(
920 %struct.RT = type { i8, [10 x [20 x i32]], i8 }
921 %struct.ST = type { i32, double, %struct.RT }
922 define i32 @f(%struct.ST* %s, %struct.RT* %r, i64 %a, i64 %b) {
923 bb0:
924 %0 = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 %a
925 %1 = getelementptr inbounds %struct.RT, %struct.RT* %r, i64 %b
926 ret i32 0
927 })";
928 LLVMContext Context;
929 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
931 std::vector<IRInstructionData *> InstrList;
932 std::vector<unsigned> UnsignedVec;
934 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
935 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
936 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
937 getVectors(*M, Mapper, InstrList, UnsignedVec);
939 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
940 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
941 ASSERT_NE(UnsignedVec[0], UnsignedVec[1]);
944 // Check that when the operands in getelementpointer instructions do not have
945 // the same inbounds modifier, they are not counted as the same.
946 TEST(IRInstructionMapper, GetElementPtrDifferentInBounds) {
947 StringRef ModuleString = R"(
948 %struct.RT = type { i8, [10 x [20 x i32]], i8 }
949 %struct.ST = type { i32, double, %struct.RT }
950 define i32 @f(%struct.ST* %s, %struct.RT* %r, i64 %a, i64 %b) {
951 bb0:
952 %0 = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 %a, i32 0
953 %1 = getelementptr %struct.ST, %struct.ST* %s, i64 %b, i32 0
954 ret i32 0
955 })";
956 LLVMContext Context;
957 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
959 std::vector<IRInstructionData *> InstrList;
960 std::vector<unsigned> UnsignedVec;
962 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
963 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
964 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
965 getVectors(*M, Mapper, InstrList, UnsignedVec);
967 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
968 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
969 ASSERT_NE(UnsignedVec[0], UnsignedVec[1]);
972 // Checks that indirect call instructions are mapped to be illegal when it is
973 // specified to disallow them.
974 TEST(IRInstructionMapper, CallsIllegalIndirect) {
975 StringRef ModuleString = R"(
976 define i32 @f(void()* %func) {
977 bb0:
978 call void %func()
979 ret i32 0
980 })";
981 LLVMContext Context;
982 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
984 std::vector<IRInstructionData *> InstrList;
985 std::vector<unsigned> UnsignedVec;
987 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
988 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
989 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
990 Mapper.InstClassifier.EnableIndirectCalls = false;
991 getVectors(*M, Mapper, InstrList, UnsignedVec);
993 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
994 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(1));
995 ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
998 // Checks that indirect call instructions are mapped to be legal when it is not
999 // specified to disallow them.
1000 TEST(IRInstructionMapper, CallsLegalIndirect) {
1001 StringRef ModuleString = R"(
1002 define i32 @f(void()* %func) {
1003 bb0:
1004 call void %func()
1005 call void %func()
1006 ret i32 0
1007 })";
1008 LLVMContext Context;
1009 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1011 std::vector<IRInstructionData *> InstrList;
1012 std::vector<unsigned> UnsignedVec;
1014 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1015 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1016 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1017 Mapper.InstClassifier.EnableIndirectCalls = true;
1018 getVectors(*M, Mapper, InstrList, UnsignedVec);
1020 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1021 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
1024 // Checks that a call instruction is mapped to be legal. Here we check that
1025 // a call with the same name, and same types are mapped to the same
1026 // value.
1027 TEST(IRInstructionMapper, CallsSameTypeSameName) {
1028 StringRef ModuleString = R"(
1029 declare i32 @f1(i32, i32)
1030 define i32 @f(i32 %a, i32 %b) {
1031 bb0:
1032 %0 = call i32 @f1(i32 %a, i32 %b)
1033 %1 = call i32 @f1(i32 %a, i32 %b)
1034 ret i32 0
1035 })";
1036 LLVMContext Context;
1037 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1039 std::vector<IRInstructionData *> InstrList;
1040 std::vector<unsigned> UnsignedVec;
1042 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1043 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1044 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1045 getVectors(*M, Mapper, InstrList, UnsignedVec);
1047 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1048 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
1049 ASSERT_EQ(UnsignedVec[0], UnsignedVec[1]);
1052 // Here we check that a calls with different names, but the same arguments types
1053 // are mapped to different value when specified that the name must match.
1054 TEST(IRInstructionMapper, CallsSameArgTypeDifferentNameDisallowed) {
1055 StringRef ModuleString = R"(
1056 declare i32 @f1(i32, i32)
1057 declare i32 @f2(i32, i32)
1058 define i32 @f(i32 %a, i32 %b) {
1059 bb0:
1060 %0 = call i32 @f1(i32 %a, i32 %b)
1061 %1 = call i32 @f2(i32 %a, i32 %b)
1062 ret i32 0
1063 })";
1064 LLVMContext Context;
1065 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1067 std::vector<IRInstructionData *> InstrList;
1068 std::vector<unsigned> UnsignedVec;
1070 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1071 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1072 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1073 Mapper.EnableMatchCallsByName = true;
1074 getVectors(*M, Mapper, InstrList, UnsignedVec);
1076 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1077 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
1078 ASSERT_NE(UnsignedVec[0], UnsignedVec[1]);
1081 // Here we check that a calls with different names, but the same arguments types
1082 // are mapped to the same value when it is not specifed that they must match.
1083 TEST(IRInstructionMapper, CallsSameArgTypeDifferentName) {
1084 StringRef ModuleString = R"(
1085 declare i32 @f1(i32, i32)
1086 declare i32 @f2(i32, i32)
1087 define i32 @f(i32 %a, i32 %b) {
1088 bb0:
1089 %0 = call i32 @f1(i32 %a, i32 %b)
1090 %1 = call i32 @f2(i32 %a, i32 %b)
1091 ret i32 0
1092 })";
1093 LLVMContext Context;
1094 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1096 std::vector<IRInstructionData *> InstrList;
1097 std::vector<unsigned> UnsignedVec;
1099 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1100 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1101 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1102 Mapper.EnableMatchCallsByName = false;
1103 getVectors(*M, Mapper, InstrList, UnsignedVec);
1105 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1106 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
1107 ASSERT_EQ(UnsignedVec[0], UnsignedVec[1]);
1110 // Here we check that a calls with different names, and different arguments
1111 // types are mapped to different value.
1112 TEST(IRInstructionMapper, CallsDifferentArgTypeDifferentName) {
1113 StringRef ModuleString = R"(
1114 declare i32 @f1(i32, i32)
1115 declare i32 @f2(i32)
1116 define i32 @f(i32 %a, i32 %b) {
1117 bb0:
1118 %0 = call i32 @f1(i32 %a, i32 %b)
1119 %1 = call i32 @f2(i32 %a)
1120 ret i32 0
1121 })";
1122 LLVMContext Context;
1123 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1125 std::vector<IRInstructionData *> InstrList;
1126 std::vector<unsigned> UnsignedVec;
1128 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1129 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1130 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1131 getVectors(*M, Mapper, InstrList, UnsignedVec);
1133 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1134 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
1135 ASSERT_NE(UnsignedVec[0], UnsignedVec[1]);
1138 // Here we check that calls with different names, and different return
1139 // types are mapped to different value.
1140 TEST(IRInstructionMapper, CallsDifferentReturnTypeDifferentName) {
1141 StringRef ModuleString = R"(
1142 declare i64 @f1(i32, i32)
1143 declare i32 @f2(i32, i32)
1144 define i32 @f(i32 %a, i32 %b) {
1145 bb0:
1146 %0 = call i64 @f1(i32 %a, i32 %b)
1147 %1 = call i32 @f2(i32 %a, i32 %b)
1148 ret i32 0
1149 })";
1150 LLVMContext Context;
1151 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1153 std::vector<IRInstructionData *> InstrList;
1154 std::vector<unsigned> UnsignedVec;
1156 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1157 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1158 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1159 getVectors(*M, Mapper, InstrList, UnsignedVec);
1161 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1162 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
1163 ASSERT_NE(UnsignedVec[0], UnsignedVec[1]);
1166 // Here we check that calls with the same name, types, and parameters map to the
1167 // same unsigned integer.
1168 TEST(IRInstructionMapper, CallsSameParameters) {
1169 StringRef ModuleString = R"(
1170 declare i32 @f1(i32, i32)
1171 define i32 @f(i32 %a, i32 %b) {
1172 bb0:
1173 %0 = tail call fastcc i32 @f1(i32 %a, i32 %b)
1174 %1 = tail call fastcc i32 @f1(i32 %a, i32 %b)
1175 ret i32 0
1176 })";
1177 LLVMContext Context;
1178 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1180 std::vector<IRInstructionData *> InstrList;
1181 std::vector<unsigned> UnsignedVec;
1183 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1184 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1185 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1186 getVectors(*M, Mapper, InstrList, UnsignedVec);
1188 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1189 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
1190 ASSERT_EQ(UnsignedVec[0], UnsignedVec[1]);
1193 // Here we check that calls with different tail call settings are mapped to
1194 // different values.
1195 TEST(IRInstructionMapper, CallsDifferentTails) {
1196 StringRef ModuleString = R"(
1197 declare i32 @f1(i32, i32)
1198 define i32 @f(i32 %a, i32 %b) {
1199 bb0:
1200 %0 = tail call i32 @f1(i32 %a, i32 %b)
1201 %1 = call i32 @f1(i32 %a, i32 %b)
1202 ret i32 0
1203 })";
1204 LLVMContext Context;
1205 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1207 std::vector<IRInstructionData *> InstrList;
1208 std::vector<unsigned> UnsignedVec;
1210 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1211 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1212 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1213 getVectors(*M, Mapper, InstrList, UnsignedVec);
1215 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1216 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
1217 ASSERT_NE(UnsignedVec[0], UnsignedVec[1]);
1220 // Here we check that calls with different calling convention settings are
1221 // mapped to different values.
1222 TEST(IRInstructionMapper, CallsDifferentCallingConventions) {
1223 StringRef ModuleString = R"(
1224 declare i32 @f1(i32, i32)
1225 define i32 @f(i32 %a, i32 %b) {
1226 bb0:
1227 %0 = call fastcc i32 @f1(i32 %a, i32 %b)
1228 %1 = call i32 @f1(i32 %a, i32 %b)
1229 ret i32 0
1230 })";
1231 LLVMContext Context;
1232 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1234 std::vector<IRInstructionData *> InstrList;
1235 std::vector<unsigned> UnsignedVec;
1237 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1238 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1239 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1240 getVectors(*M, Mapper, InstrList, UnsignedVec);
1242 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1243 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
1244 ASSERT_NE(UnsignedVec[0], UnsignedVec[1]);
1247 // Checks that an invoke instruction is mapped to be illegal. Invoke
1248 // instructions are considered to be illegal because of the change in the
1249 // control flow that is currently not recognized.
1250 TEST(IRInstructionMapper, InvokeIllegal) {
1251 StringRef ModuleString = R"(
1252 define i32 @f(i8 *%gep1, i32 %b) {
1253 then:
1254 invoke i32 undef(i8* undef)
1255 to label %invoke unwind label %lpad
1257 invoke:
1258 unreachable
1260 lpad:
1261 landingpad { i8*, i32 }
1262 catch i8* null
1263 unreachable
1264 })";
1265 LLVMContext Context;
1266 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1268 std::vector<IRInstructionData *> InstrList;
1269 std::vector<unsigned> UnsignedVec;
1271 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1272 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1273 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1274 getVectors(*M, Mapper, InstrList, UnsignedVec);
1276 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1277 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(1));
1278 ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
1281 // Checks that an callbr instructions are considered to be illegal. Callbr
1282 // instructions are considered to be illegal because of the change in the
1283 // control flow that is currently not recognized.
1284 TEST(IRInstructionMapper, CallBrInstIllegal) {
1285 StringRef ModuleString = R"(
1286 define void @test() {
1287 fail:
1288 ret void
1291 define i32 @f(i32 %a, i32 %b) {
1292 bb0:
1293 callbr void asm "xorl $0, $0; jmp ${1:l}", "r,X,~{dirflag},~{fpsr},~{flags}"(i32 %a, i8* blockaddress(@test, %fail)) to label %normal [label %fail]
1294 fail:
1295 ret i32 0
1296 normal:
1297 ret i32 0
1298 })";
1299 LLVMContext Context;
1300 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1302 std::vector<IRInstructionData *> InstrList;
1303 std::vector<unsigned> UnsignedVec;
1305 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1306 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1307 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1308 getVectors(*M, Mapper, InstrList, UnsignedVec);
1310 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1311 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(1));
1312 ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
1315 // Checks that an debuginfo records are mapped to be invisible. Since they
1316 // do not semantically change the program, they can be recognized as similar.
1317 TEST(IRInstructionMapper, DebugInfoInvisible) {
1318 StringRef ModuleString = R"(
1319 define i32 @f(i32 %a, i32 %b) {
1320 then:
1321 %0 = add i32 %a, %b
1322 #dbg_value(i32 0, !0, !0, !0)
1323 %1 = add i32 %a, %b
1324 ret i32 0
1327 !0 = distinct !{!"test\00", i32 10})";
1328 LLVMContext Context;
1329 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1331 std::vector<IRInstructionData *> InstrList;
1332 std::vector<unsigned> UnsignedVec;
1334 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1335 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1336 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1337 getVectors(*M, Mapper, InstrList, UnsignedVec);
1339 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1340 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(3));
1343 // The following are all exception handling intrinsics. We do not currently
1344 // handle these instruction because they are very context dependent.
1346 // Checks that an eh.typeid.for intrinsic is mapped to be illegal.
1347 TEST(IRInstructionMapper, ExceptionHandlingTypeIdIllegal) {
1348 StringRef ModuleString = R"(
1349 @_ZTIi = external constant i8*
1350 define i32 @f() {
1351 then:
1352 %0 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
1353 ret i32 0
1356 declare i32 @llvm.eh.typeid.for(i8*))";
1357 LLVMContext Context;
1358 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1360 std::vector<IRInstructionData *> InstrList;
1361 std::vector<unsigned> UnsignedVec;
1363 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1364 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1365 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1366 getVectors(*M, Mapper, InstrList, UnsignedVec);
1368 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1369 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(1));
1370 ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
1373 // Checks that an eh.exceptioncode intrinsic is mapped to be illegal.
1374 TEST(IRInstructionMapper, ExceptionHandlingExceptionCodeIllegal) {
1375 StringRef ModuleString = R"(
1376 define i32 @f(i32 %a, i32 %b) {
1377 entry:
1378 %0 = catchswitch within none [label %__except] unwind to caller
1380 __except:
1381 %1 = catchpad within %0 [i8* null]
1382 catchret from %1 to label %__except
1384 then:
1385 %2 = call i32 @llvm.eh.exceptioncode(token %1)
1386 ret i32 0
1389 declare i32 @llvm.eh.exceptioncode(token))";
1390 LLVMContext Context;
1391 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1393 std::vector<IRInstructionData *> InstrList;
1394 std::vector<unsigned> UnsignedVec;
1396 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1397 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1398 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1399 getVectors(*M, Mapper, InstrList, UnsignedVec);
1401 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1402 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(1));
1403 ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
1406 // Checks that an eh.unwind intrinsic is mapped to be illegal.
1407 TEST(IRInstructionMapper, ExceptionHandlingUnwindIllegal) {
1408 StringRef ModuleString = R"(
1409 define i32 @f(i32 %a, i32 %b) {
1410 entry:
1411 call void @llvm.eh.unwind.init()
1412 ret i32 0
1415 declare void @llvm.eh.unwind.init())";
1416 LLVMContext Context;
1417 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1419 std::vector<IRInstructionData *> InstrList;
1420 std::vector<unsigned> UnsignedVec;
1422 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1423 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1424 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1425 getVectors(*M, Mapper, InstrList, UnsignedVec);
1427 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1428 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(1));
1429 ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
1432 // Checks that an eh.exceptionpointer intrinsic is mapped to be illegal.
1433 TEST(IRInstructionMapper, ExceptionHandlingExceptionPointerIllegal) {
1434 StringRef ModuleString = R"(
1435 define i32 @f(i32 %a, i32 %b) {
1436 entry:
1437 %0 = call i8* @llvm.eh.exceptionpointer.p0i8(i32 0)
1438 ret i32 0
1441 declare i8* @llvm.eh.exceptionpointer.p0i8(i32))";
1442 LLVMContext Context;
1443 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1445 std::vector<IRInstructionData *> InstrList;
1446 std::vector<unsigned> UnsignedVec;
1448 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1449 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1450 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1451 getVectors(*M, Mapper, InstrList, UnsignedVec);
1453 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1454 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(1));
1455 ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
1458 // Checks that a catchpad instruction is mapped to an illegal value.
1459 TEST(IRInstructionMapper, CatchpadIllegal) {
1460 StringRef ModuleString = R"(
1461 declare void @llvm.donothing() nounwind readnone
1463 define void @function() personality i8 3 {
1464 entry:
1465 invoke void @llvm.donothing() to label %normal unwind label %exception
1466 exception:
1467 %cs1 = catchswitch within none [label %catchpad1] unwind to caller
1468 catchpad1:
1469 catchpad within %cs1 []
1470 br label %normal
1471 normal:
1472 ret void
1473 })";
1474 LLVMContext Context;
1475 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1477 std::vector<IRInstructionData *> InstrList;
1478 std::vector<unsigned> UnsignedVec;
1480 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1481 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1482 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1483 getVectors(*M, Mapper, InstrList, UnsignedVec);
1485 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1486 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(1));
1487 ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
1490 // Checks that a cleanuppad instruction is mapped to an illegal value.
1491 TEST(IRInstructionMapper, CleanuppadIllegal) {
1492 StringRef ModuleString = R"(
1493 declare void @llvm.donothing() nounwind readnone
1495 define void @function() personality i8 3 {
1496 entry:
1497 invoke void @llvm.donothing() to label %normal unwind label %exception
1498 exception:
1499 %cs1 = catchswitch within none [label %catchpad1] unwind to caller
1500 catchpad1:
1501 %clean = cleanuppad within none []
1502 br label %normal
1503 normal:
1504 ret void
1505 })";
1506 LLVMContext Context;
1507 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1509 std::vector<IRInstructionData *> InstrList;
1510 std::vector<unsigned> UnsignedVec;
1512 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1513 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1514 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1515 getVectors(*M, Mapper, InstrList, UnsignedVec);
1517 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1518 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(1));
1519 ASSERT_GT(UnsignedVec[0], Mapper.IllegalInstrNumber);
1522 // The following three instructions are memory transfer and setting based, which
1523 // are considered illegal since is extra checking needed to handle the address
1524 // space checking.
1526 // Checks that a memset instruction is mapped to an illegal value when
1527 // specified.
1528 TEST(IRInstructionMapper, MemSetIllegal) {
1529 StringRef ModuleString = R"(
1530 declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1)
1532 define i64 @function(i64 %x, i64 %z, i64 %n) {
1533 entry:
1534 %pool = alloca [59 x i64], align 4
1535 %tmp = bitcast [59 x i64]* %pool to i8*
1536 call void @llvm.memset.p0i8.i64(i8* nonnull %tmp, i8 0, i64 236, i32 4, i1 false)
1537 %cmp3 = icmp eq i64 %n, 0
1538 %a = add i64 %x, %z
1539 %c = add i64 %x, %z
1540 ret i64 0
1541 })";
1542 LLVMContext Context;
1543 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1545 std::vector<IRInstructionData *> InstrList;
1546 std::vector<unsigned> UnsignedVec;
1548 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1549 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1550 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1551 Mapper.InstClassifier.EnableIntrinsics = false;
1552 getVectors(*M, Mapper, InstrList, UnsignedVec);
1554 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1555 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(7));
1556 ASSERT_TRUE(UnsignedVec[2] < UnsignedVec[0]);
1559 // Checks that a memcpy instruction is mapped to an illegal value when
1560 // specified.
1561 TEST(IRInstructionMapper, MemCpyIllegal) {
1562 StringRef ModuleString = R"(
1563 declare void @llvm.memcpy.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1)
1565 define i64 @function(i64 %x, i64 %z, i64 %n) {
1566 entry:
1567 %pool = alloca [59 x i64], align 4
1568 %tmp = bitcast [59 x i64]* %pool to i8*
1569 call void @llvm.memcpy.p0i8.i64(i8* nonnull %tmp, i8 0, i64 236, i32 4, i1 false)
1570 %cmp3 = icmp eq i64 %n, 0
1571 %a = add i64 %x, %z
1572 %c = add i64 %x, %z
1573 ret i64 0
1574 })";
1575 LLVMContext Context;
1576 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1578 std::vector<IRInstructionData *> InstrList;
1579 std::vector<unsigned> UnsignedVec;
1581 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1582 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1583 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1584 Mapper.InstClassifier.EnableIntrinsics = false;
1585 getVectors(*M, Mapper, InstrList, UnsignedVec);
1587 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1588 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(7));
1589 ASSERT_GT(UnsignedVec[2], UnsignedVec[3]);
1590 ASSERT_LT(UnsignedVec[2], UnsignedVec[0]);
1593 // Checks that a memmove instruction is mapped to an illegal value when
1594 // specified.
1595 TEST(IRInstructionMapper, MemMoveIllegal) {
1596 StringRef ModuleString = R"(
1597 declare void @llvm.memmove.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1)
1599 define i64 @function(i64 %x, i64 %z, i64 %n) {
1600 entry:
1601 %pool = alloca [59 x i64], align 4
1602 %tmp = bitcast [59 x i64]* %pool to i8*
1603 call void @llvm.memmove.p0i8.i64(i8* nonnull %tmp, i8 0, i64 236, i32 4, i1 false)
1604 %cmp3 = icmp eq i64 %n, 0
1605 %a = add i64 %x, %z
1606 %c = add i64 %x, %z
1607 ret i64 0
1608 })";
1609 LLVMContext Context;
1610 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1612 std::vector<IRInstructionData *> InstrList;
1613 std::vector<unsigned> UnsignedVec;
1615 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1616 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1617 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1618 Mapper.InstClassifier.EnableIntrinsics = false;
1619 getVectors(*M, Mapper, InstrList, UnsignedVec);
1621 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1622 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(7));
1623 ASSERT_LT(UnsignedVec[2], UnsignedVec[0]);
1626 // Checks that mem* instructions are mapped to an legal value when not
1627 // specified, and that all the intrinsics are marked differently.
1628 TEST(IRInstructionMapper, MemOpsLegal) {
1629 StringRef ModuleString = R"(
1630 declare void @llvm.memmove.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1)
1631 declare void @llvm.memcpy.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1)
1632 declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i32, i1)
1634 define i64 @function(i64 %x, i64 %z, i64 %n) {
1635 entry:
1636 %pool = alloca [59 x i64], align 4
1637 %tmp = bitcast [59 x i64]* %pool to i8*
1638 call void @llvm.memmove.p0i8.i64(i8* nonnull %tmp, i8 0, i64 236, i32 4, i1 false)
1639 call void @llvm.memcpy.p0i8.i64(i8* nonnull %tmp, i8 0, i64 236, i32 4, i1 false)
1640 call void @llvm.memset.p0i8.i64(i8* nonnull %tmp, i8 0, i64 236, i32 4, i1 false)
1641 %cmp3 = icmp eq i64 %n, 0
1642 %a = add i64 %x, %z
1643 %c = add i64 %x, %z
1644 ret i64 0
1645 })";
1646 LLVMContext Context;
1647 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1649 std::vector<IRInstructionData *> InstrList;
1650 std::vector<unsigned> UnsignedVec;
1652 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1653 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1654 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1655 Mapper.InstClassifier.EnableIntrinsics = true;
1656 getVectors(*M, Mapper, InstrList, UnsignedVec);
1658 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1659 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(9));
1660 ASSERT_LT(UnsignedVec[2], UnsignedVec[3]);
1661 ASSERT_LT(UnsignedVec[3], UnsignedVec[4]);
1662 ASSERT_LT(UnsignedVec[4], UnsignedVec[5]);
1665 // Checks that a variable argument instructions are mapped to an illegal value.
1666 // We exclude variable argument instructions since variable arguments
1667 // requires extra checking of the argument list.
1668 TEST(IRInstructionMapper, VarArgsIllegal) {
1669 StringRef ModuleString = R"(
1670 declare void @llvm.va_start(i8*)
1671 declare void @llvm.va_copy(i8*, i8*)
1672 declare void @llvm.va_end(i8*)
1674 define i32 @func1(i32 %a, double %b, i8* %v, ...) nounwind {
1675 entry:
1676 %a.addr = alloca i32, align 4
1677 %b.addr = alloca double, align 8
1678 %ap = alloca i8*, align 4
1679 %c = alloca i32, align 4
1680 store i32 %a, i32* %a.addr, align 4
1681 store double %b, double* %b.addr, align 8
1682 %ap1 = bitcast i8** %ap to i8*
1683 call void @llvm.va_start(i8* %ap1)
1684 store double %b, double* %b.addr, align 8
1685 store double %b, double* %b.addr, align 8
1686 %0 = va_arg i8** %ap, i32
1687 store double %b, double* %b.addr, align 8
1688 store double %b, double* %b.addr, align 8
1689 call void @llvm.va_copy(i8* %v, i8* %ap1)
1690 store double %b, double* %b.addr, align 8
1691 store double %b, double* %b.addr, align 8
1692 call void @llvm.va_end(i8* %ap1)
1693 store i32 %0, i32* %c, align 4
1694 %tmp = load i32, i32* %c, align 4
1695 ret i32 %tmp
1696 })";
1697 LLVMContext Context;
1698 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1700 std::vector<IRInstructionData *> InstrList;
1701 std::vector<unsigned> UnsignedVec;
1703 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1704 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1705 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1706 Mapper.InstClassifier.EnableIntrinsics = false;
1707 getVectors(*M, Mapper, InstrList, UnsignedVec);
1709 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
1710 ASSERT_EQ(UnsignedVec.size(), static_cast<unsigned>(17));
1711 ASSERT_TRUE(UnsignedVec[7] < UnsignedVec[0]);
1712 ASSERT_TRUE(UnsignedVec[13] < UnsignedVec[10]);
1713 ASSERT_TRUE(UnsignedVec[16] < UnsignedVec[13]);
1716 // Check the length of adding two illegal instructions one after th other. We
1717 // should find that only one element is added for each illegal range.
1718 TEST(IRInstructionMapper, RepeatedIllegalLength) {
1719 StringRef ModuleString = R"(
1720 define i32 @f(i32 %a, i32 %b) {
1721 bb0:
1722 %0 = add i32 %a, %b
1723 %1 = mul i32 %a, %b
1724 %2 = alloca i32
1725 %3 = alloca i32
1726 %4 = add i32 %a, %b
1727 %5 = mul i32 %a, %b
1728 ret i32 0
1729 })";
1730 LLVMContext Context;
1731 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1733 std::vector<IRInstructionData *> InstrList;
1734 std::vector<unsigned> UnsignedVec;
1736 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1737 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1738 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1739 getVectors(*M, Mapper, InstrList, UnsignedVec);
1741 // Check that the size of the unsigned vector and the instruction list are the
1742 // same as a safety check.
1743 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
1745 // Make sure that the unsigned vector is the expected size.
1746 ASSERT_TRUE(UnsignedVec.size() == 6);
1749 // A helper function that accepts an instruction list from a module made up of
1750 // two blocks of two legal instructions and terminator, and checks them for
1751 // instruction similarity.
1752 static bool longSimCandCompare(std::vector<IRInstructionData *> &InstrList,
1753 bool Structure = false, unsigned Length = 2,
1754 unsigned StartIdxOne = 0,
1755 unsigned StartIdxTwo = 3) {
1756 std::vector<IRInstructionData *>::iterator Start, End;
1758 Start = InstrList.begin();
1759 End = InstrList.begin();
1761 std::advance(End, StartIdxOne + Length - 1);
1762 IRSimilarityCandidate Cand1(StartIdxOne, Length, *Start, *End);
1764 Start = InstrList.begin();
1765 End = InstrList.begin();
1767 std::advance(Start, StartIdxTwo);
1768 std::advance(End, StartIdxTwo + Length - 1);
1769 IRSimilarityCandidate Cand2(StartIdxTwo, Length, *Start, *End);
1770 if (Structure)
1771 return IRSimilarityCandidate::compareStructure(Cand1, Cand2);
1772 return IRSimilarityCandidate::isSimilar(Cand1, Cand2);
1775 // Checks that two adds with commuted operands are considered to be the same
1776 // instructions.
1777 TEST(IRSimilarityCandidate, CheckIdenticalInstructions) {
1778 StringRef ModuleString = R"(
1779 define i32 @f(i32 %a, i32 %b) {
1780 bb0:
1781 %0 = add i32 %a, %b
1782 %1 = add i32 %b, %a
1783 ret i32 0
1784 })";
1785 LLVMContext Context;
1786 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1788 std::vector<IRInstructionData *> InstrList;
1789 std::vector<unsigned> UnsignedVec;
1791 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1792 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1793 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1794 getVectors(*M, Mapper, InstrList, UnsignedVec);
1796 // Check to make sure that we have a long enough region.
1797 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(3));
1798 // Check that the instructions were added correctly to both vectors.
1799 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
1801 std::vector<IRInstructionData *>::iterator Start, End;
1802 Start = InstrList.begin();
1803 End = InstrList.begin();
1804 std::advance(End, 1);
1805 IRSimilarityCandidate Cand1(0, 2, *Start, *End);
1806 IRSimilarityCandidate Cand2(0, 2, *Start, *End);
1808 ASSERT_TRUE(IRSimilarityCandidate::isSimilar(Cand1, Cand2));
1811 // Checks that comparison instructions are found to be similar instructions
1812 // when the operands are flipped and the predicate is also swapped.
1813 TEST(IRSimilarityCandidate, PredicateIsomorphism) {
1814 StringRef ModuleString = R"(
1815 define i32 @f(i32 %a, i32 %b) {
1816 bb0:
1817 %0 = icmp sgt i32 %a, %b
1818 %1 = add i32 %b, %a
1819 br label %bb1
1820 bb1:
1821 %2 = icmp slt i32 %a, %b
1822 %3 = add i32 %a, %b
1823 ret i32 0
1824 })";
1825 LLVMContext Context;
1826 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1828 std::vector<IRInstructionData *> InstrList;
1829 std::vector<unsigned> UnsignedVec;
1831 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1832 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1833 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1834 getVectors(*M, Mapper, InstrList, UnsignedVec);
1836 ASSERT_TRUE(InstrList.size() > 5);
1837 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
1839 std::vector<IRInstructionData *>::iterator Start, End;
1840 Start = InstrList.begin();
1841 End = InstrList.begin();
1843 std::advance(End, 1);
1844 IRSimilarityCandidate Cand1(0, 2, *Start, *End);
1846 Start = InstrList.begin();
1847 End = InstrList.begin();
1849 std::advance(Start, 3);
1850 std::advance(End, 4);
1851 IRSimilarityCandidate Cand2(3, 2, *Start, *End);
1853 ASSERT_TRUE(IRSimilarityCandidate::isSimilar(Cand1, Cand2));
1856 // Checks that IRSimilarityCandidates wrapping these two regions of instructions
1857 // are able to differentiate between instructions that have different opcodes.
1858 TEST(IRSimilarityCandidate, CheckRegionsDifferentInstruction) {
1859 StringRef ModuleString = R"(
1860 define i32 @f(i32 %a, i32 %b) {
1861 bb0:
1862 %0 = add i32 %a, %b
1863 %1 = add i32 %b, %a
1864 ret i32 0
1865 bb1:
1866 %2 = sub i32 %a, %b
1867 %3 = add i32 %b, %a
1868 ret i32 0
1869 })";
1870 LLVMContext Context;
1871 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1873 std::vector<IRInstructionData *> InstrList;
1874 std::vector<unsigned> UnsignedVec;
1876 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1877 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1878 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1879 getVectors(*M, Mapper, InstrList, UnsignedVec);
1881 // Check to make sure that we have a long enough region.
1882 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(6));
1883 // Check that the instructions were added correctly to both vectors.
1884 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
1886 ASSERT_FALSE(longSimCandCompare(InstrList));
1889 // Checks that IRSimilarityCandidates wrapping these two regions of instructions
1890 // are able to differentiate between instructions that have different types.
1891 TEST(IRSimilarityCandidate, CheckRegionsDifferentTypes) {
1892 StringRef ModuleString = R"(
1893 define i32 @f(i32 %a, i32 %b, i64 %c, i64 %d) {
1894 bb0:
1895 %0 = add i32 %a, %b
1896 %1 = add i32 %b, %a
1897 ret i32 0
1898 bb1:
1899 %2 = add i64 %c, %d
1900 %3 = add i64 %d, %c
1901 ret i32 0
1902 })";
1903 LLVMContext Context;
1904 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1906 std::vector<IRInstructionData *> InstrList;
1907 std::vector<unsigned> UnsignedVec;
1909 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1910 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1911 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1912 getVectors(*M, Mapper, InstrList, UnsignedVec);
1914 // Check to make sure that we have a long enough region.
1915 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(6));
1916 // Check that the instructions were added correctly to both vectors.
1917 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
1919 ASSERT_FALSE(longSimCandCompare(InstrList));
1922 // Check that debug records do not impact similarity. They are marked as
1923 // invisible.
1924 TEST(IRSimilarityCandidate, IdenticalWithDebug) {
1925 StringRef ModuleString = R"(
1926 define i32 @f(i32 %a, i32 %b) {
1927 bb0:
1928 %0 = add i32 %a, %b
1929 #dbg_value(i32 0, !0, !0, !0)
1930 %1 = add i32 %b, %a
1931 ret i32 0
1932 bb1:
1933 %2 = add i32 %a, %b
1934 #dbg_value(i32 1, !1, !1, !1)
1935 %3 = add i32 %b, %a
1936 ret i32 0
1937 bb2:
1938 %4 = add i32 %a, %b
1939 %5 = add i32 %b, %a
1940 ret i32 0
1943 !0 = distinct !{!"test\00", i32 10}
1944 !1 = distinct !{!"test\00", i32 11})";
1945 LLVMContext Context;
1946 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1948 std::vector<IRInstructionData *> InstrList;
1949 std::vector<unsigned> UnsignedVec;
1951 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1952 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1953 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1954 getVectors(*M, Mapper, InstrList, UnsignedVec);
1956 // Check to make sure that we have a long enough region.
1957 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(9));
1958 // Check that the instructions were added correctly to both vectors.
1959 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
1961 ASSERT_TRUE(longSimCandCompare(InstrList));
1964 // Checks that IRSimilarityCandidates that include illegal instructions, are not
1965 // considered to be the same set of instructions. In these sets of instructions
1966 // the allocas are illegal.
1967 TEST(IRSimilarityCandidate, IllegalInCandidate) {
1968 StringRef ModuleString = R"(
1969 define i32 @f(i32 %a, i32 %b) {
1970 bb0:
1971 %0 = add i32 %a, %b
1972 %1 = add i32 %a, %b
1973 %2 = alloca i32
1974 ret i32 0
1975 bb1:
1976 %3 = add i32 %a, %b
1977 %4 = add i32 %a, %b
1978 %5 = alloca i32
1979 ret i32 0
1980 })";
1981 LLVMContext Context;
1982 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
1984 std::vector<IRInstructionData *> InstrList;
1985 std::vector<unsigned> UnsignedVec;
1987 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
1988 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
1989 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
1990 getVectors(*M, Mapper, InstrList, UnsignedVec);
1992 // Check to make sure that we have a long enough region.
1993 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(6));
1994 // Check that the instructions were added correctly to both vectors.
1995 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
1997 std::vector<IRInstructionData *>::iterator Start, End;
1999 Start = InstrList.begin();
2000 End = InstrList.begin();
2002 std::advance(End, 2);
2003 IRSimilarityCandidate Cand1(0, 3, *Start, *End);
2005 Start = InstrList.begin();
2006 End = InstrList.begin();
2008 std::advance(Start, 3);
2009 std::advance(End, 5);
2010 IRSimilarityCandidate Cand2(3, 3, *Start, *End);
2011 ASSERT_FALSE(IRSimilarityCandidate::isSimilar(Cand1, Cand2));
2014 // Checks that different structure, in this case, where we introduce a new
2015 // needed input in one region, is recognized as different.
2016 TEST(IRSimilarityCandidate, DifferentStructure) {
2017 StringRef ModuleString = R"(
2018 define i32 @f(i32 %a, i32 %b) {
2019 bb0:
2020 %0 = add i32 %a, %b
2021 %1 = add i32 %b, %a
2022 ret i32 0
2023 bb1:
2024 %2 = add i32 %a, %b
2025 %3 = add i32 %b, %0
2026 ret i32 0
2027 })";
2028 LLVMContext Context;
2029 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2031 std::vector<IRInstructionData *> InstrList;
2032 std::vector<unsigned> UnsignedVec;
2034 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
2035 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
2036 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
2037 getVectors(*M, Mapper, InstrList, UnsignedVec);
2039 // Check to make sure that we have a long enough region.
2040 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(6));
2041 // Check that the instructions were added correctly to both vectors.
2042 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
2044 ASSERT_FALSE(longSimCandCompare(InstrList, true));
2047 // Checks that comparison instructions are found to have the same structure
2048 // when the operands are flipped and the predicate is also swapped.
2049 TEST(IRSimilarityCandidate, PredicateIsomorphismStructure) {
2050 StringRef ModuleString = R"(
2051 define i32 @f(i32 %a, i32 %b) {
2052 bb0:
2053 %0 = icmp sgt i32 %a, %b
2054 %1 = add i32 %a, %b
2055 br label %bb1
2056 bb1:
2057 %2 = icmp slt i32 %b, %a
2058 %3 = add i32 %a, %b
2059 ret i32 0
2060 })";
2061 LLVMContext Context;
2062 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2064 std::vector<IRInstructionData *> InstrList;
2065 std::vector<unsigned> UnsignedVec;
2067 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
2068 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
2069 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
2070 getVectors(*M, Mapper, InstrList, UnsignedVec);
2072 ASSERT_TRUE(InstrList.size() > 5);
2073 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
2075 ASSERT_TRUE(longSimCandCompare(InstrList, true));
2078 // Checks that different predicates are counted as diferent.
2079 TEST(IRSimilarityCandidate, PredicateDifference) {
2080 StringRef ModuleString = R"(
2081 define i32 @f(i32 %a, i32 %b) {
2082 bb0:
2083 %0 = icmp sge i32 %a, %b
2084 %1 = add i32 %b, %a
2085 br label %bb1
2086 bb1:
2087 %2 = icmp slt i32 %b, %a
2088 %3 = add i32 %a, %b
2089 ret i32 0
2090 })";
2091 LLVMContext Context;
2092 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2094 std::vector<IRInstructionData *> InstrList;
2095 std::vector<unsigned> UnsignedVec;
2097 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
2098 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
2099 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
2100 getVectors(*M, Mapper, InstrList, UnsignedVec);
2102 ASSERT_TRUE(InstrList.size() > 5);
2103 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
2105 ASSERT_FALSE(longSimCandCompare(InstrList));
2108 // Checks that the same structure is recognized between two candidates. The
2109 // items %a and %b are used in the same way in both sets of instructions.
2110 TEST(IRSimilarityCandidate, SameStructure) {
2111 StringRef ModuleString = R"(
2112 define i32 @f(i32 %a, i32 %b) {
2113 bb0:
2114 %0 = add i32 %a, %b
2115 %1 = sub i32 %b, %a
2116 ret i32 0
2117 bb1:
2118 %2 = add i32 %a, %b
2119 %3 = sub i32 %b, %a
2120 ret i32 0
2121 })";
2122 LLVMContext Context;
2123 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2125 std::vector<IRInstructionData *> InstrList;
2126 std::vector<unsigned> UnsignedVec;
2128 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
2129 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
2130 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
2131 getVectors(*M, Mapper, InstrList, UnsignedVec);
2133 // Check to make sure that we have a long enough region.
2134 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(6));
2135 // Check that the instructions were added correctly to both vectors.
2136 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
2138 ASSERT_TRUE(longSimCandCompare(InstrList, true));
2141 // Checks that the canonical numbering between two candidates matches the found
2142 // mapping between two candidates.
2143 TEST(IRSimilarityCandidate, CanonicalNumbering) {
2144 StringRef ModuleString = R"(
2145 define i32 @f(i32 %a, i32 %b) {
2146 bb0:
2147 %0 = add i32 %a, %b
2148 %1 = sub i32 %b, %a
2149 ret i32 0
2150 bb1:
2151 %2 = add i32 %a, %b
2152 %3 = sub i32 %b, %a
2153 ret i32 0
2154 })";
2155 LLVMContext Context;
2156 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2158 std::vector<IRInstructionData *> InstrList;
2159 std::vector<unsigned> UnsignedVec;
2161 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
2162 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
2163 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
2164 getVectors(*M, Mapper, InstrList, UnsignedVec);
2166 // Check to make sure that we have a long enough region.
2167 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(6));
2168 // Check that the instructions were added correctly to both vectors.
2169 ASSERT_EQ(InstrList.size(), UnsignedVec.size());
2171 std::vector<IRInstructionData *>::iterator Start, End;
2173 Start = InstrList.begin();
2174 End = InstrList.begin();
2176 std::advance(End, 1);
2177 IRSimilarityCandidate Cand1(0, 2, *Start, *End);
2179 Start = InstrList.begin();
2180 End = InstrList.begin();
2182 std::advance(Start, 3);
2183 std::advance(End, 4);
2184 IRSimilarityCandidate Cand2(3, 2, *Start, *End);
2185 DenseMap<unsigned, DenseSet<unsigned>> Mapping1;
2186 DenseMap<unsigned, DenseSet<unsigned>> Mapping2;
2187 ASSERT_TRUE(IRSimilarityCandidate::compareStructure(Cand1, Cand2, Mapping1,
2188 Mapping2));
2189 IRSimilarityCandidate::createCanonicalMappingFor(Cand1);
2190 Cand2.createCanonicalRelationFrom(Cand1, Mapping1, Mapping2);
2192 for (std::pair<unsigned, DenseSet<unsigned>> &P : Mapping2) {
2193 unsigned Source = P.first;
2195 ASSERT_TRUE(Cand2.getCanonicalNum(Source).has_value());
2196 unsigned Canon = *Cand2.getCanonicalNum(Source);
2197 ASSERT_TRUE(Cand1.fromCanonicalNum(Canon).has_value());
2198 unsigned Dest = *Cand1.fromCanonicalNum(Canon);
2200 DenseSet<unsigned>::iterator It = P.second.find(Dest);
2201 ASSERT_NE(It, P.second.end());
2205 // Checks that the same structure is recognized between two candidates. While
2206 // the input names are reversed, they still perform the same overall operation.
2207 TEST(IRSimilarityCandidate, DifferentNameSameStructure) {
2208 StringRef ModuleString = R"(
2209 define i32 @f(i32 %a, i32 %b) {
2210 bb0:
2211 %0 = add i32 %a, %b
2212 %1 = add i32 %b, %a
2213 ret i32 0
2214 bb1:
2215 %2 = add i32 %b, %a
2216 %3 = add i32 %a, %b
2217 ret i32 0
2218 })";
2219 LLVMContext Context;
2220 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2222 std::vector<IRInstructionData *> InstrList;
2223 std::vector<unsigned> UnsignedVec;
2225 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
2226 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
2227 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
2228 getVectors(*M, Mapper, InstrList, UnsignedVec);
2230 // Check to make sure that we have a long enough region.
2231 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(6));
2232 // Check that the instructions were added correctly to both vectors.
2233 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
2235 ASSERT_TRUE(longSimCandCompare(InstrList, true));
2238 // Checks that the same structure is recognized between two candidates when
2239 // the branches target other blocks inside the same region, the relative
2240 // distance between the blocks must be the same.
2241 TEST(IRSimilarityCandidate, SameBranchStructureInternal) {
2242 StringRef ModuleString = R"(
2243 define i32 @f(i32 %a, i32 %b) {
2244 bb0:
2245 %0 = add i32 %a, %b
2246 %1 = add i32 %b, %a
2247 br label %bb1
2248 bb1:
2249 %2 = add i32 %b, %a
2250 %3 = add i32 %a, %b
2251 ret i32 0
2254 define i32 @f2(i32 %a, i32 %b) {
2255 bb0:
2256 %0 = add i32 %a, %b
2257 %1 = add i32 %b, %a
2258 br label %bb1
2259 bb1:
2260 %2 = add i32 %b, %a
2261 %3 = add i32 %a, %b
2262 ret i32 0
2263 })";
2264 LLVMContext Context;
2265 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2267 std::vector<IRInstructionData *> InstrList;
2268 std::vector<unsigned> UnsignedVec;
2270 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
2271 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
2272 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
2273 Mapper.InstClassifier.EnableBranches = true;
2274 Mapper.initializeForBBs(*M);
2275 getVectors(*M, Mapper, InstrList, UnsignedVec);
2277 // Check to make sure that we have a long enough region.
2278 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(12));
2279 // Check that the instructions were added correctly to both vectors.
2280 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
2282 ASSERT_TRUE(longSimCandCompare(InstrList, true, 5, 0, 6));
2285 // Checks that the different structure is recognized between two candidates,
2286 // when the branches target other blocks inside the same region, the relative
2287 // distance between the blocks must be the same.
2288 TEST(IRSimilarityCandidate, DifferentBranchStructureInternal) {
2289 StringRef ModuleString = R"(
2290 define i32 @f(i32 %a, i32 %b) {
2291 bb0:
2292 %0 = add i32 %a, %b
2293 %1 = add i32 %b, %a
2294 br label %bb2
2295 bb1:
2296 %2 = add i32 %b, %a
2297 %3 = add i32 %a, %b
2298 br label %bb2
2299 bb2:
2300 %4 = add i32 %b, %a
2301 %5 = add i32 %a, %b
2302 ret i32 0
2305 define i32 @f2(i32 %a, i32 %b) {
2306 bb0:
2307 %0 = add i32 %a, %b
2308 %1 = add i32 %b, %a
2309 br label %bb1
2310 bb1:
2311 %2 = add i32 %b, %a
2312 %3 = add i32 %a, %b
2313 br label %bb2
2314 bb2:
2315 %4 = add i32 %b, %a
2316 %5 = add i32 %a, %b
2317 ret i32 0
2318 })";
2319 LLVMContext Context;
2320 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2322 std::vector<IRInstructionData *> InstrList;
2323 std::vector<unsigned> UnsignedVec;
2325 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
2326 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
2327 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
2328 Mapper.InstClassifier.EnableBranches = true;
2329 Mapper.initializeForBBs(*M);
2330 getVectors(*M, Mapper, InstrList, UnsignedVec);
2332 // Check to make sure that we have a long enough region.
2333 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(18));
2334 // Check that the instructions were added correctly to both vectors.
2335 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
2337 ASSERT_FALSE(longSimCandCompare(InstrList, true, 6, 0, 9));
2340 // Checks that the same structure is recognized between two candidates, when
2341 // the branches target other blocks outside region, the relative distance
2342 // does not need to be the same.
2343 TEST(IRSimilarityCandidate, SameBranchStructureOutside) {
2344 StringRef ModuleString = R"(
2345 define i32 @f(i32 %a, i32 %b) {
2346 bb0:
2347 %0 = add i32 %a, %b
2348 %1 = add i32 %b, %a
2349 br label %bb1
2350 bb1:
2351 %2 = add i32 %b, %a
2352 %3 = add i32 %a, %b
2353 ret i32 0
2356 define i32 @f2(i32 %a, i32 %b) {
2357 bb0:
2358 %0 = add i32 %a, %b
2359 %1 = add i32 %b, %a
2360 br label %bb1
2361 bb1:
2362 %2 = add i32 %b, %a
2363 %3 = add i32 %a, %b
2364 ret i32 0
2365 })";
2366 LLVMContext Context;
2367 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2369 std::vector<IRInstructionData *> InstrList;
2370 std::vector<unsigned> UnsignedVec;
2372 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
2373 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
2374 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
2375 Mapper.InstClassifier.EnableBranches = true;
2376 Mapper.initializeForBBs(*M);
2377 getVectors(*M, Mapper, InstrList, UnsignedVec);
2379 // Check to make sure that we have a long enough region.
2380 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(12));
2381 // Check that the instructions were added correctly to both vectors.
2382 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
2384 ASSERT_TRUE(longSimCandCompare(InstrList, true, 3, 0, 6));
2387 // Checks that the same structure is recognized between two candidates, when
2388 // the branches target other blocks outside region, the relative distance
2389 // does not need to be the same.
2390 TEST(IRSimilarityCandidate, DifferentBranchStructureOutside) {
2391 StringRef ModuleString = R"(
2392 define i32 @f(i32 %a, i32 %b) {
2393 bb0:
2394 %0 = add i32 %a, %b
2395 %1 = add i32 %b, %a
2396 br label %bb1
2397 bb1:
2398 %2 = add i32 %b, %a
2399 %3 = add i32 %a, %b
2400 ret i32 0
2403 define i32 @f2(i32 %a, i32 %b) {
2404 bb0:
2405 %0 = add i32 %a, %b
2406 %1 = add i32 %b, %a
2407 br label %bb2
2408 bb1:
2409 %2 = add i32 %b, %a
2410 %3 = add i32 %a, %b
2411 br label %bb2
2412 bb2:
2413 %4 = add i32 %b, %a
2414 %5 = add i32 %a, %b
2415 ret i32 0
2416 })";
2417 LLVMContext Context;
2418 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2420 std::vector<IRInstructionData *> InstrList;
2421 std::vector<unsigned> UnsignedVec;
2423 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
2424 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
2425 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
2426 Mapper.InstClassifier.EnableBranches = true;
2427 Mapper.initializeForBBs(*M);
2428 getVectors(*M, Mapper, InstrList, UnsignedVec);
2430 // Check to make sure that we have a long enough region.
2431 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(15));
2432 // Check that the instructions were added correctly to both vectors.
2433 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
2435 ASSERT_TRUE(longSimCandCompare(InstrList, true, 3, 0, 6));
2438 // Checks that the same structure is recognized between two candidates,
2439 // when the phi predecessor are other blocks inside the same region,
2440 // the relative distance between the blocks must be the same.
2441 TEST(IRSimilarityCandidate, SamePHIStructureInternal) {
2442 StringRef ModuleString = R"(
2443 define i32 @f(i32 %a, i32 %b) {
2444 bb0:
2445 br label %bb2
2446 bb1:
2447 br label %bb2
2448 bb2:
2449 %0 = phi i32 [ %a, %bb0 ], [ %b, %bb1 ]
2450 %1 = add i32 %b, %a
2451 %2 = add i32 %a, %b
2452 ret i32 0
2455 define i32 @f2(i32 %a, i32 %b) {
2456 bb0:
2457 br label %bb2
2458 bb1:
2459 br label %bb2
2460 bb2:
2461 %0 = phi i32 [ %a, %bb0 ], [ %b, %bb1 ]
2462 %1 = add i32 %b, %a
2463 %2 = add i32 %a, %b
2464 ret i32 0
2465 })";
2466 LLVMContext Context;
2467 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2469 std::vector<IRInstructionData *> InstrList;
2470 std::vector<unsigned> UnsignedVec;
2472 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
2473 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
2474 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
2475 Mapper.InstClassifier.EnableBranches = true;
2476 Mapper.initializeForBBs(*M);
2477 getVectors(*M, Mapper, InstrList, UnsignedVec);
2479 // Check to make sure that we have a long enough region.
2480 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(12));
2481 // Check that the instructions were added correctly to both vectors.
2482 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
2484 ASSERT_TRUE(longSimCandCompare(InstrList, true, 4, 0, 6));
2487 // Checks that the different structure is recognized between two candidates,
2488 // when the phi predecessor are other blocks inside the same region,
2489 // the relative distance between the blocks must be the same.
2490 TEST(IRSimilarityCandidate, DifferentPHIStructureInternal) {
2491 StringRef ModuleString = R"(
2492 define i32 @f(i32 %a, i32 %b) {
2493 bb0:
2494 br label %bb2
2495 bb1:
2496 br label %bb2
2497 bb3:
2498 br label %bb2
2499 bb2:
2500 %0 = phi i32 [ %a, %bb0 ], [ %b, %bb1 ]
2501 %1 = add i32 %b, %a
2502 %2 = add i32 %a, %b
2503 ret i32 0
2506 define i32 @f2(i32 %a, i32 %b) {
2507 bb0:
2508 br label %bb2
2509 bb1:
2510 br label %bb2
2511 bb3:
2512 br label %bb2
2513 bb2:
2514 %0 = phi i32 [ %a, %bb0 ], [ %b, %bb3 ]
2515 %1 = add i32 %b, %a
2516 %2 = add i32 %a, %b
2517 ret i32 0
2518 })";
2519 LLVMContext Context;
2520 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2522 std::vector<IRInstructionData *> InstrList;
2523 std::vector<unsigned> UnsignedVec;
2525 SpecificBumpPtrAllocator<IRInstructionData> InstDataAllocator;
2526 SpecificBumpPtrAllocator<IRInstructionDataList> IDLAllocator;
2527 IRInstructionMapper Mapper(&InstDataAllocator, &IDLAllocator);
2528 Mapper.InstClassifier.EnableBranches = true;
2529 Mapper.initializeForBBs(*M);
2530 getVectors(*M, Mapper, InstrList, UnsignedVec);
2532 // Check to make sure that we have a long enough region.
2533 ASSERT_EQ(InstrList.size(), static_cast<unsigned>(14));
2534 // Check that the instructions were added correctly to both vectors.
2535 ASSERT_TRUE(InstrList.size() == UnsignedVec.size());
2537 ASSERT_FALSE(longSimCandCompare(InstrList, true, 5, 0, 7));
2540 // Checks that two sets of identical instructions are found to be the same.
2541 // Both sequences of adds have the same operand ordering, and the same
2542 // instructions, making them strcturally equivalent.
2543 TEST(IRSimilarityIdentifier, IdentitySimilarity) {
2544 StringRef ModuleString = R"(
2545 define i32 @f(i32 %a, i32 %b) {
2546 bb0:
2547 %0 = add i32 %a, %b
2548 %1 = sub i32 %b, %a
2549 br label %bb1
2550 bb1:
2551 %2 = add i32 %a, %b
2552 %3 = sub i32 %b, %a
2553 ret i32 0
2554 })";
2555 LLVMContext Context;
2556 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2558 std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates;
2559 getSimilarities(*M, SimilarityCandidates);
2561 ASSERT_TRUE(SimilarityCandidates.size() == 1);
2562 for (std::vector<IRSimilarityCandidate> &Cands : SimilarityCandidates) {
2563 ASSERT_TRUE(Cands.size() == 2);
2564 unsigned InstIdx = 0;
2565 for (IRSimilarityCandidate &Cand : Cands) {
2566 ASSERT_TRUE(Cand.getStartIdx() == InstIdx);
2567 InstIdx += 3;
2572 // Checks that incorrect sequences are not found as similar. In this case,
2573 // we have different sequences of instructions.
2574 TEST(IRSimilarityIdentifier, InstructionDifference) {
2575 StringRef ModuleString = R"(
2576 define i32 @f(i32 %a, i32 %b, i32 %c, i32 %d) {
2577 bb0:
2578 %0 = sub i32 %a, %b
2579 %1 = add i32 %b, %a
2580 br label %bb1
2581 bb1:
2582 %2 = add i32 %c, %d
2583 %3 = sub i32 %d, %c
2584 ret i32 0
2585 })";
2586 LLVMContext Context;
2587 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2589 std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates;
2590 getSimilarities(*M, SimilarityCandidates);
2592 ASSERT_TRUE(SimilarityCandidates.empty());
2595 // This test checks to see whether we can detect similarity for commutative
2596 // instructions where the operands have been reversed.
2597 TEST(IRSimilarityIdentifier, CommutativeSimilarity) {
2598 StringRef ModuleString = R"(
2599 define i32 @f(i32 %a, i32 %b) {
2600 bb0:
2601 %0 = add i32 %a, %b
2602 %1 = add i32 %b, %a
2603 br label %bb1
2604 bb1:
2605 %2 = add i32 %a, %b
2606 %3 = add i32 %a, %b
2607 ret i32 0
2608 })";
2609 LLVMContext Context;
2610 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2612 std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates;
2613 getSimilarities(*M, SimilarityCandidates);
2615 ASSERT_TRUE(SimilarityCandidates.size() == 1);
2616 for (std::vector<IRSimilarityCandidate> &Cands : SimilarityCandidates) {
2617 ASSERT_TRUE(Cands.size() == 2);
2618 unsigned InstIdx = 0;
2619 for (IRSimilarityCandidate &Cand : Cands) {
2620 ASSERT_TRUE(Cand.getStartIdx() == InstIdx);
2621 InstIdx += 3;
2626 // This test ensures that when the first instruction in a sequence is
2627 // a commutative instruction with the same value (mcomm_inst_same_val), but the
2628 // corresponding instruction (comm_inst_diff_val) is not, we mark the regions
2629 // and not similar.
2630 TEST(IRSimilarityIdentifier, CommutativeSameValueFirstMisMatch) {
2631 StringRef ModuleString = R"(
2632 define void @v_1_0(i64 %v_33) {
2633 entry:
2634 %comm_inst_same_val = mul i64 undef, undef
2635 %add = add i64 %comm_inst_same_val, %v_33
2636 %comm_inst_diff_val = mul i64 0, undef
2637 %mul.i = add i64 %comm_inst_diff_val, %comm_inst_diff_val
2638 unreachable
2639 })";
2640 LLVMContext Context;
2641 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2643 std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates;
2644 getSimilarities(*M, SimilarityCandidates);
2646 ASSERT_TRUE(SimilarityCandidates.size() == 0);
2649 // This test makes sure that intrinsic functions that are marked commutative
2650 // are still treated as non-commutative since they are function calls.
2651 TEST(IRSimilarityIdentifier, IntrinsicCommutative) {
2652 // If treated as commutative, we will fail to find a valid mapping, causing
2653 // an assertion error.
2654 StringRef ModuleString = R"(
2655 define void @foo() {
2656 entry:
2657 %0 = call i16 @llvm.smul.fix.i16(i16 16384, i16 16384, i32 15)
2658 store i16 %0, i16* undef, align 1
2659 %1 = icmp eq i16 undef, 8192
2660 call void @bar()
2661 %2 = call i16 @llvm.smul.fix.i16(i16 -16384, i16 16384, i32 15)
2662 store i16 %2, i16* undef, align 1
2663 %3 = icmp eq i16 undef, -8192
2664 call void @bar()
2665 %4 = call i16 @llvm.smul.fix.i16(i16 -16384, i16 -16384, i32 15)
2666 ret void
2669 declare void @bar()
2671 ; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
2672 declare i16 @llvm.smul.fix.i16(i16, i16, i32 immarg))";
2673 LLVMContext Context;
2674 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2676 std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates;
2677 getSimilarities(*M, SimilarityCandidates);
2679 ASSERT_TRUE(SimilarityCandidates.size() == 0);
2682 // This test checks to see whether we can detect different structure in
2683 // commutative instructions. In this case, the second operand in the second
2684 // add is different.
2685 TEST(IRSimilarityIdentifier, NoCommutativeSimilarity) {
2686 StringRef ModuleString = R"(
2687 define i32 @f(i32 %a, i32 %b) {
2688 bb0:
2689 %0 = add i32 %a, %b
2690 %1 = add i32 %1, %b
2691 br label %bb1
2692 bb1:
2693 %2 = add i32 %a, %b
2694 %3 = add i32 %2, %a
2695 ret i32 0
2696 })";
2697 LLVMContext Context;
2698 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2700 std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates;
2701 getSimilarities(*M, SimilarityCandidates);
2703 ASSERT_TRUE(SimilarityCandidates.size() == 0);
2706 // Check that we are not finding similarity in non commutative
2707 // instructions. That is, while the instruction and operands used are the same
2708 // in the two subtraction sequences, they are in a different order, and cannot
2709 // be counted as the same since a subtraction is not commutative.
2710 TEST(IRSimilarityIdentifier, NonCommutativeDifference) {
2711 StringRef ModuleString = R"(
2712 define i32 @f(i32 %a, i32 %b) {
2713 bb0:
2714 %0 = sub i32 %a, %b
2715 %1 = sub i32 %b, %a
2716 br label %bb1
2717 bb1:
2718 %2 = sub i32 %a, %b
2719 %3 = sub i32 %a, %b
2720 ret i32 0
2721 })";
2722 LLVMContext Context;
2723 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2725 std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates;
2726 getSimilarities(*M, SimilarityCandidates);
2728 ASSERT_TRUE(SimilarityCandidates.empty());
2731 // Check that we find similarity despite changing the register names.
2732 TEST(IRSimilarityIdentifier, MappingSimilarity) {
2733 StringRef ModuleString = R"(
2734 define i32 @f(i32 %a, i32 %b, i32 %c, i32 %d) {
2735 bb0:
2736 %0 = add i32 %a, %b
2737 %1 = sub i32 %b, %a
2738 br label %bb1
2739 bb1:
2740 %2 = add i32 %c, %d
2741 %3 = sub i32 %d, %c
2742 ret i32 0
2743 })";
2744 LLVMContext Context;
2745 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2747 std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates;
2748 getSimilarities(*M, SimilarityCandidates);
2750 ASSERT_TRUE(SimilarityCandidates.size() == 1);
2751 for (std::vector<IRSimilarityCandidate> &Cands : SimilarityCandidates) {
2752 ASSERT_TRUE(Cands.size() == 2);
2753 unsigned InstIdx = 0;
2754 for (IRSimilarityCandidate &Cand : Cands) {
2755 ASSERT_TRUE(Cand.getStartIdx() == InstIdx);
2756 InstIdx += 3;
2761 // Check that we find instances of swapped predicate isomorphism. That is,
2762 // for predicates that can be flipped, e.g. greater than to less than,
2763 // we can identify that instances of these different literal predicates, but are
2764 // the same within a single swap can be found.
2765 TEST(IRSimilarityIdentifier, PredicateIsomorphism) {
2766 StringRef ModuleString = R"(
2767 define i32 @f(i32 %a, i32 %b) {
2768 bb0:
2769 %0 = add i32 %a, %b
2770 %1 = icmp sgt i32 %b, %a
2771 br label %bb1
2772 bb1:
2773 %2 = add i32 %a, %b
2774 %3 = icmp slt i32 %a, %b
2775 ret i32 0
2776 })";
2777 LLVMContext Context;
2778 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2780 std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates;
2781 getSimilarities(*M, SimilarityCandidates);
2783 ASSERT_TRUE(SimilarityCandidates.size() == 1);
2784 for (std::vector<IRSimilarityCandidate> &Cands : SimilarityCandidates) {
2785 ASSERT_TRUE(Cands.size() == 2);
2786 unsigned InstIdx = 0;
2787 for (IRSimilarityCandidate &Cand : Cands) {
2788 ASSERT_TRUE(Cand.getStartIdx() == InstIdx);
2789 InstIdx += 3;
2794 // Checks that constants are detected as the same operand in each use in the
2795 // sequences of instructions. Also checks that we can find structural
2796 // equivalence using constants. In this case the 1 has the same use pattern as
2797 // %a.
2798 TEST(IRSimilarityIdentifier, ConstantMappingSimilarity) {
2799 StringRef ModuleString = R"(
2800 define i32 @f(i32 %a, i32 %b) {
2801 bb0:
2802 %0 = add i32 1, %b
2803 %1 = icmp sgt i32 %b, 1
2804 br label %bb1
2805 bb1:
2806 %2 = add i32 %a, %b
2807 %3 = icmp sgt i32 %b, %a
2808 ret i32 0
2809 })";
2810 LLVMContext Context;
2811 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2813 std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates;
2814 getSimilarities(*M, SimilarityCandidates);
2816 ASSERT_TRUE(SimilarityCandidates.size() == 1);
2817 for (std::vector<IRSimilarityCandidate> &Cands : SimilarityCandidates) {
2818 ASSERT_TRUE(Cands.size() == 2);
2819 unsigned InstIdx = 0;
2820 for (IRSimilarityCandidate &Cand : Cands) {
2821 ASSERT_TRUE(Cand.getStartIdx() == InstIdx);
2822 InstIdx += 3;
2827 // Check that constants are uniquely identified. i.e. two different constants
2828 // are not considered the same. This means that this should not find any
2829 // structural similarity.
2830 TEST(IRSimilarityIdentifier, ConstantMappingDifference) {
2831 StringRef ModuleString = R"(
2832 define i32 @f(i32 %a, i32 %b) {
2833 bb0:
2834 %0 = add i32 1, %b
2835 %1 = icmp sgt i32 %b, 2
2836 br label %bb1
2837 bb1:
2838 %2 = add i32 %a, %b
2839 %3 = icmp slt i32 %a, %b
2840 ret i32 0
2841 })";
2842 LLVMContext Context;
2843 std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
2845 std::vector<std::vector<IRSimilarityCandidate>> SimilarityCandidates;
2846 getSimilarities(*M, SimilarityCandidates);
2848 ASSERT_TRUE(SimilarityCandidates.empty());