xref: /llvm-project/llvm/unittests/FuzzMutate/RandomIRBuilderTest.cpp (revision 97d691b4b3f5ba446d6827fc29fbe15e44a7adac)
1 //===- RandomIRBuilderTest.cpp - Tests for injector strategy --------------===//
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 #include "llvm/FuzzMutate/RandomIRBuilder.h"
10 #include "llvm/ADT/StringRef.h"
11 #include "llvm/AsmParser/Parser.h"
12 #include "llvm/AsmParser/SlotMapping.h"
13 #include "llvm/FuzzMutate/IRMutator.h"
14 #include "llvm/FuzzMutate/OpDescriptor.h"
15 #include "llvm/FuzzMutate/Operations.h"
16 #include "llvm/FuzzMutate/Random.h"
17 #include "llvm/IR/Constants.h"
18 #include "llvm/IR/Dominators.h"
19 #include "llvm/IR/Instructions.h"
20 #include "llvm/IR/LLVMContext.h"
21 #include "llvm/IR/Module.h"
22 #include "llvm/IR/Verifier.h"
23 #include "llvm/Support/SourceMgr.h"
24 
25 #include "gtest/gtest.h"
26 
27 using namespace llvm;
28 
29 static constexpr int Seed = 5;
30 
31 namespace {
32 
33 std::unique_ptr<Module> parseAssembly(const char *Assembly,
34                                       LLVMContext &Context) {
35 
36   SMDiagnostic Error;
37   std::unique_ptr<Module> M = parseAssemblyString(Assembly, Error, Context);
38 
39   std::string ErrMsg;
40   raw_string_ostream OS(ErrMsg);
41   Error.print("", OS);
42 
43   assert(M && !verifyModule(*M, &errs()));
44   return M;
45 }
46 
47 TEST(RandomIRBuilderTest, ShuffleVectorIncorrectOperands) {
48   // Test that we don't create load instruction as a source for the shuffle
49   // vector operation.
50 
51   LLVMContext Ctx;
52   const char *Source =
53       "define <2 x i32> @test(<2 x i1> %cond, <2 x i32> %a) {\n"
54       "  %A = alloca <2 x i32>\n"
55       "  %I = insertelement <2 x i32> %a, i32 1, i32 1\n"
56       "  ret <2 x i32> undef\n"
57       "}";
58   auto M = parseAssembly(Source, Ctx);
59 
60   fuzzerop::OpDescriptor Descr = fuzzerop::shuffleVectorDescriptor(1);
61 
62   // Empty known types since we ShuffleVector descriptor doesn't care about them
63   RandomIRBuilder IB(Seed, {});
64 
65   // Get first basic block of the first function
66   Function &F = *M->begin();
67   BasicBlock &BB = *F.begin();
68 
69   SmallVector<Instruction *, 32> Insts;
70   for (auto I = BB.getFirstInsertionPt(), E = BB.end(); I != E; ++I)
71     Insts.push_back(&*I);
72 
73   // Pick first and second sources
74   SmallVector<Value *, 2> Srcs;
75   ASSERT_TRUE(Descr.SourcePreds[0].matches(Srcs, Insts[1]));
76   Srcs.push_back(Insts[1]);
77   ASSERT_TRUE(Descr.SourcePreds[1].matches(Srcs, Insts[1]));
78   Srcs.push_back(Insts[1]);
79 
80   // Create new source. Check that it always matches with the descriptor.
81   // Run some iterations to account for random decisions.
82   for (int i = 0; i < 10; ++i) {
83     Value *LastSrc = IB.newSource(BB, Insts, Srcs, Descr.SourcePreds[2]);
84     ASSERT_TRUE(Descr.SourcePreds[2].matches(Srcs, LastSrc));
85   }
86 }
87 
88 TEST(RandomIRBuilderTest, InsertValueIndexes) {
89   // Check that we will generate correct indexes for the insertvalue operation
90 
91   LLVMContext Ctx;
92   const char *Source = "%T = type {i8, i32, i64}\n"
93                        "define void @test() {\n"
94                        "  %A = alloca %T\n"
95                        "  %L = load %T, ptr %A"
96                        "  ret void\n"
97                        "}";
98   auto M = parseAssembly(Source, Ctx);
99 
100   fuzzerop::OpDescriptor IVDescr = fuzzerop::insertValueDescriptor(1);
101 
102   std::array<Type *, 3> Types = {Type::getInt8Ty(Ctx), Type::getInt32Ty(Ctx),
103                                  Type::getInt64Ty(Ctx)};
104   RandomIRBuilder IB(Seed, Types);
105 
106   // Get first basic block of the first function
107   Function &F = *M->begin();
108   BasicBlock &BB = *F.begin();
109 
110   // Pick first source
111   Instruction *Src = &*std::next(BB.begin());
112 
113   SmallVector<Value *, 2> Srcs(2);
114   ASSERT_TRUE(IVDescr.SourcePreds[0].matches({}, Src));
115   Srcs[0] = Src;
116 
117   // Generate constants for each of the types and check that we pick correct
118   // index for the given type
119   for (auto *T : Types) {
120     // Loop to account for possible random decisions
121     for (int i = 0; i < 10; ++i) {
122       // Create value we want to insert. Only it's type matters.
123       Srcs[1] = ConstantInt::get(T, 5);
124 
125       // Try to pick correct index
126       Value *Src =
127           IB.findOrCreateSource(BB, &*BB.begin(), Srcs, IVDescr.SourcePreds[2]);
128       ASSERT_TRUE(IVDescr.SourcePreds[2].matches(Srcs, Src));
129     }
130   }
131 }
132 
133 TEST(RandomIRBuilderTest, ShuffleVectorSink) {
134   // Check that we will never use shuffle vector mask as a sink from the
135   // unrelated operation.
136 
137   LLVMContext Ctx;
138   const char *SourceCode =
139       "define void @test(<4 x i32> %a) {\n"
140       "  %S1 = shufflevector <4 x i32> %a, <4 x i32> %a, <4 x i32> undef\n"
141       "  %S2 = shufflevector <4 x i32> %a, <4 x i32> %a, <4 x i32> undef\n"
142       "  ret void\n"
143       "}";
144   auto M = parseAssembly(SourceCode, Ctx);
145 
146   fuzzerop::OpDescriptor IVDescr = fuzzerop::insertValueDescriptor(1);
147 
148   RandomIRBuilder IB(Seed, {});
149 
150   // Get first basic block of the first function
151   Function &F = *M->begin();
152   BasicBlock &BB = *F.begin();
153 
154   // Source is %S1
155   Instruction *Source = &*BB.begin();
156   // Sink is %S2
157   SmallVector<Instruction *, 1> Sinks = {&*std::next(BB.begin())};
158 
159   // Loop to account for random decisions
160   for (int i = 0; i < 10; ++i) {
161     // Try to connect S1 to S2. We should always create new sink.
162     IB.connectToSink(BB, Sinks, Source);
163     ASSERT_TRUE(!verifyModule(*M, &errs()));
164   }
165 }
166 
167 TEST(RandomIRBuilderTest, InsertValueArray) {
168   // Check that we can generate insertvalue for the vector operations
169 
170   LLVMContext Ctx;
171   const char *SourceCode = "define void @test() {\n"
172                            "  %A = alloca [8 x i32]\n"
173                            "  %L = load [8 x i32], ptr %A"
174                            "  ret void\n"
175                            "}";
176   auto M = parseAssembly(SourceCode, Ctx);
177 
178   fuzzerop::OpDescriptor Descr = fuzzerop::insertValueDescriptor(1);
179 
180   std::array<Type *, 3> Types = {Type::getInt8Ty(Ctx), Type::getInt32Ty(Ctx),
181                                  Type::getInt64Ty(Ctx)};
182   RandomIRBuilder IB(Seed, Types);
183 
184   // Get first basic block of the first function
185   Function &F = *M->begin();
186   BasicBlock &BB = *F.begin();
187 
188   // Pick first source
189   Instruction *Source = &*std::next(BB.begin());
190   ASSERT_TRUE(Descr.SourcePreds[0].matches({}, Source));
191 
192   SmallVector<Value *, 2> Srcs(2);
193 
194   // Check that we can always pick the last two operands.
195   for (int i = 0; i < 10; ++i) {
196     Srcs[0] = Source;
197     Srcs[1] = IB.findOrCreateSource(BB, {Source}, Srcs, Descr.SourcePreds[1]);
198     IB.findOrCreateSource(BB, {}, Srcs, Descr.SourcePreds[2]);
199   }
200 }
201 
202 TEST(RandomIRBuilderTest, Invokes) {
203   // Check that we never generate load or store after invoke instruction
204 
205   LLVMContext Ctx;
206   const char *SourceCode =
207       "declare ptr @f()"
208       "declare i32 @personality_function()"
209       "define ptr @test() personality ptr @personality_function {\n"
210       "entry:\n"
211       "  %val = invoke ptr @f()\n"
212       "          to label %normal unwind label %exceptional\n"
213       "normal:\n"
214       "  ret ptr %val\n"
215       "exceptional:\n"
216       "  %landing_pad4 = landingpad token cleanup\n"
217       "  ret ptr undef\n"
218       "}";
219   auto M = parseAssembly(SourceCode, Ctx);
220 
221   std::array<Type *, 1> Types = {Type::getInt8Ty(Ctx)};
222   RandomIRBuilder IB(Seed, Types);
223 
224   // Get first basic block of the test function
225   Function &F = *M->getFunction("test");
226   BasicBlock &BB = *F.begin();
227 
228   Instruction *Invoke = &*BB.begin();
229 
230   // Find source but never insert new load after invoke
231   for (int i = 0; i < 10; ++i) {
232     (void)IB.findOrCreateSource(BB, {Invoke}, {}, fuzzerop::anyIntType());
233     ASSERT_TRUE(!verifyModule(*M, &errs()));
234   }
235 }
236 
237 TEST(RandomIRBuilderTest, SwiftError) {
238   // Check that we never pick swifterror value as a source for operation
239   // other than load, store and call.
240 
241   LLVMContext Ctx;
242   const char *SourceCode = "declare void @use(ptr swifterror %err)"
243                            "define void @test() {\n"
244                            "entry:\n"
245                            "  %err = alloca swifterror ptr, align 8\n"
246                            "  call void @use(ptr swifterror %err)\n"
247                            "  ret void\n"
248                            "}";
249   auto M = parseAssembly(SourceCode, Ctx);
250 
251   std::array<Type *, 1> Types = {Type::getInt8Ty(Ctx)};
252   RandomIRBuilder IB(Seed, Types);
253 
254   // Get first basic block of the test function
255   Function &F = *M->getFunction("test");
256   BasicBlock &BB = *F.begin();
257   Instruction *Alloca = &*BB.begin();
258 
259   fuzzerop::OpDescriptor Descr = fuzzerop::gepDescriptor(1);
260 
261   for (int i = 0; i < 10; ++i) {
262     Value *V = IB.findOrCreateSource(BB, {Alloca}, {}, Descr.SourcePreds[0]);
263     ASSERT_FALSE(isa<AllocaInst>(V));
264   }
265 }
266 
267 TEST(RandomIRBuilderTest, dontConnectToSwitch) {
268   // Check that we never put anything into switch's case branch
269   // If we accidently put a variable, the module is invalid.
270   LLVMContext Ctx;
271   const char *SourceCode = "\n\
272     define void @test(i1 %C1, i1 %C2, i32 %I, i32 %J) { \n\
273     Entry:  \n\
274       %I.1 = add i32 %I, 42 \n\
275       %J.1 = add i32 %J, 42 \n\
276       %IJ = add i32 %I, %J \n\
277       switch i32 %I, label %Default [ \n\
278         i32 1, label %OnOne  \n\
279       ] \n\
280     Default:  \n\
281       %CIEqJ = icmp eq i32 %I.1, %J.1 \n\
282       %CISltJ = icmp slt i32 %I.1, %J.1 \n\
283       %CAnd = and i1 %C1, %C2 \n\
284       br i1 %CIEqJ, label %Default, label %Exit \n\
285     OnOne:  \n\
286       br i1 %C1, label %OnOne, label %Exit \n\
287     Exit:  \n\
288       ret void \n\
289     }";
290 
291   std::array<Type *, 2> Types = {Type::getInt32Ty(Ctx), Type::getInt1Ty(Ctx)};
292   RandomIRBuilder IB(Seed, Types);
293   for (int i = 0; i < 20; i++) {
294     std::unique_ptr<Module> M = parseAssembly(SourceCode, Ctx);
295     Function &F = *M->getFunction("test");
296     auto RS = makeSampler(IB.Rand, make_pointer_range(F));
297     BasicBlock *BB = RS.getSelection();
298     SmallVector<Instruction *, 32> Insts;
299     for (auto I = BB->getFirstInsertionPt(), E = BB->end(); I != E; ++I)
300       Insts.push_back(&*I);
301     if (Insts.size() < 2)
302       continue;
303     // Choose an instruction and connect to later operations.
304     size_t IP = uniform<size_t>(IB.Rand, 1, Insts.size() - 1);
305     Instruction *Inst = Insts[IP - 1];
306     auto ConnectAfter = ArrayRef(Insts).slice(IP);
307     IB.connectToSink(*BB, ConnectAfter, Inst);
308     ASSERT_FALSE(verifyModule(*M, &errs()));
309   }
310 }
311 
312 TEST(RandomIRBuilderTest, createStackMemory) {
313   LLVMContext Ctx;
314   const char *SourceCode = "\n\
315     define void @test(i1 %C1, i1 %C2, i32 %I, i32 %J) { \n\
316     Entry:  \n\
317       ret void \n\
318     }";
319   Type *Int32Ty = Type::getInt32Ty(Ctx);
320   Constant *Int32_1 = ConstantInt::get(Int32Ty, APInt(32, 1));
321   Type *Int64Ty = Type::getInt64Ty(Ctx);
322   Constant *Int64_42 = ConstantInt::get(Int64Ty, APInt(64, 42));
323   Type *DoubleTy = Type::getDoubleTy(Ctx);
324   Constant *Double_0 =
325       ConstantFP::get(Ctx, APFloat::getZero(DoubleTy->getFltSemantics()));
326   std::array<Type *, 7> Types = {
327       Int32Ty,
328       Int64Ty,
329       DoubleTy,
330       PointerType::get(Ctx, 0),
331       VectorType::get(Int32Ty, 4, false),
332       StructType::create({Int32Ty, DoubleTy, Int64Ty}),
333       ArrayType::get(Int64Ty, 4),
334   };
335   std::array<Value *, 7> Inits = {
336       Int32_1,
337       Int64_42,
338       Double_0,
339       UndefValue::get(Types[3]),
340       ConstantVector::get({Int32_1, Int32_1, Int32_1, Int32_1}),
341       ConstantStruct::get(cast<StructType>(Types[5]),
342                           {Int32_1, Double_0, Int64_42}),
343       ConstantArray::get(cast<ArrayType>(Types[6]),
344                          {Int64_42, Int64_42, Int64_42, Int64_42}),
345   };
346   ASSERT_EQ(Types.size(), Inits.size());
347   unsigned NumTests = Types.size();
348   RandomIRBuilder IB(Seed, Types);
349   auto CreateStackMemoryAndVerify = [&Ctx, &SourceCode, &IB](Type *Ty,
350                                                              Value *Init) {
351     std::unique_ptr<Module> M = parseAssembly(SourceCode, Ctx);
352     Function &F = *M->getFunction("test");
353     // Create stack memory without initializer.
354     IB.createStackMemory(&F, Ty, nullptr);
355     // Create stack memory with initializer.
356     IB.createStackMemory(&F, Ty, Init);
357     EXPECT_FALSE(verifyModule(*M, &errs()));
358   };
359   for (unsigned i = 0; i < NumTests; i++) {
360     CreateStackMemoryAndVerify(Types[i], Inits[i]);
361   }
362 }
363 
364 TEST(RandomIRBuilderTest, findOrCreateGlobalVariable) {
365   LLVMContext Ctx;
366   const char *SourceCode = "\n\
367     @G0 = external global i16 \n\
368     @G1 = global i32 1 \n\
369   ";
370   std::array<Type *, 3> Types = {Type::getInt16Ty(Ctx), Type::getInt32Ty(Ctx),
371                                  Type::getInt64Ty(Ctx)};
372   RandomIRBuilder IB(Seed, Types);
373 
374   // Find external global
375   std::unique_ptr<Module> M0 = parseAssembly(SourceCode, Ctx);
376   Type *ExternalTy = M0->globals().begin()->getValueType();
377   ASSERT_TRUE(ExternalTy->isIntegerTy(16));
378   IB.findOrCreateGlobalVariable(&*M0, {}, fuzzerop::onlyType(Types[0]));
379   ASSERT_FALSE(verifyModule(*M0, &errs()));
380   unsigned NumGV0 = M0->getNumNamedValues();
381   auto [GV0, DidCreate0] =
382       IB.findOrCreateGlobalVariable(&*M0, {}, fuzzerop::onlyType(Types[0]));
383   ASSERT_FALSE(verifyModule(*M0, &errs()));
384   ASSERT_EQ(M0->getNumNamedValues(), NumGV0 + DidCreate0);
385 
386   // Find existing global
387   std::unique_ptr<Module> M1 = parseAssembly(SourceCode, Ctx);
388   IB.findOrCreateGlobalVariable(&*M1, {}, fuzzerop::onlyType(Types[1]));
389   ASSERT_FALSE(verifyModule(*M1, &errs()));
390   unsigned NumGV1 = M1->getNumNamedValues();
391   auto [GV1, DidCreate1] =
392       IB.findOrCreateGlobalVariable(&*M1, {}, fuzzerop::onlyType(Types[1]));
393   ASSERT_FALSE(verifyModule(*M1, &errs()));
394   ASSERT_EQ(M1->getNumNamedValues(), NumGV1 + DidCreate1);
395 
396   // Create new global
397   std::unique_ptr<Module> M2 = parseAssembly(SourceCode, Ctx);
398   auto [GV2, DidCreate2] =
399       IB.findOrCreateGlobalVariable(&*M2, {}, fuzzerop::onlyType(Types[2]));
400   ASSERT_FALSE(verifyModule(*M2, &errs()));
401   ASSERT_TRUE(DidCreate2);
402 }
403 
404 /// Checks if the source and sink we find for an instruction has correct
405 /// domination relation.
406 TEST(RandomIRBuilderTest, findSourceAndSink) {
407   const char *Source = "\n\
408         define i64 @test(i1 %0, i1 %1, i1 %2, i32 %3, i32 %4) { \n\
409         Entry:  \n\
410           %A = alloca i32, i32 8, align 4 \n\
411           %E.1 = and i32 %3, %4 \n\
412           %E.2 = add i32 %4 , 1 \n\
413           %A.GEP.1 = getelementptr i32, ptr %A, i32 0 \n\
414           %A.GEP.2 = getelementptr i32, ptr %A.GEP.1, i32 1 \n\
415           %L.2 = load i32, ptr %A.GEP.2 \n\
416           %L.1 = load i32, ptr %A.GEP.1 \n\
417           %E.3 = sub i32 %E.2, %L.1 \n\
418           %Cond.1 = icmp eq i32 %E.3, %E.2 \n\
419           %Cond.2 = and i1 %0, %1 \n\
420           %Cond = or i1 %Cond.1, %Cond.2 \n\
421           br i1 %Cond, label %BB0, label %BB1  \n\
422         BB0:  \n\
423           %Add = add i32 %L.1, %L.2 \n\
424           %Sub = sub i32 %L.1, %L.2 \n\
425           %Sub.1 = sub i32 %Sub, 12 \n\
426           %Cast.1 = bitcast i32 %4 to float \n\
427           %Add.2 = add i32 %3, 1 \n\
428           %Cast.2 = bitcast i32 %Add.2 to float \n\
429           %FAdd = fadd float %Cast.1, %Cast.2 \n\
430           %Add.3 = add i32 %L.2, %L.1 \n\
431           %Cast.3 = bitcast float %FAdd to i32 \n\
432           %Sub.2 = sub i32 %Cast.3, %Sub.1 \n\
433           %SExt = sext i32 %Cast.3 to i64 \n\
434           %A.GEP.3 = getelementptr i64, ptr %A, i32 1 \n\
435           store i64 %SExt, ptr %A.GEP.3 \n\
436           br label %Exit  \n\
437         BB1:  \n\
438           %PHI.1 = phi i32 [0, %Entry] \n\
439           %SExt.1 = sext i1 %Cond.2 to i32 \n\
440           %SExt.2 = sext i1 %Cond.1 to i32 \n\
441           %E.164 = zext i32 %E.1 to i64 \n\
442           %E.264 = zext i32 %E.2 to i64 \n\
443           %E.1264 = mul i64 %E.164, %E.264 \n\
444           %E.12 = trunc i64 %E.1264 to i32 \n\
445           %A.GEP.4 = getelementptr i32, ptr %A, i32 2 \n\
446           %A.GEP.5 = getelementptr i32, ptr %A.GEP.4, i32 2 \n\
447           store i32 %E.12, ptr %A.GEP.5 \n\
448           br label %Exit  \n\
449         Exit:  \n\
450           %PHI.2 = phi i32 [%Add, %BB0], [%E.3, %BB1] \n\
451           %PHI.3 = phi i64 [%SExt, %BB0], [%E.1264, %BB1] \n\
452           %ZExt = zext i32 %PHI.2 to i64 \n\
453           %Add.5 = add i64 %PHI.3, 3 \n\
454           ret i64 %Add.5  \n\
455       }";
456   LLVMContext Ctx;
457   std::array<Type *, 3> Types = {Type::getInt1Ty(Ctx), Type::getInt32Ty(Ctx),
458                                  Type::getInt64Ty(Ctx)};
459   std::mt19937 mt(Seed);
460   std::uniform_int_distribution<int> RandInt(INT_MIN, INT_MAX);
461 
462   // Get a random instruction, try to find source and sink, make sure it is
463   // dominated.
464   for (int i = 0; i < 100; i++) {
465     RandomIRBuilder IB(RandInt(mt), Types);
466     std::unique_ptr<Module> M = parseAssembly(Source, Ctx);
467     Function &F = *M->getFunction("test");
468     DominatorTree DT(F);
469     BasicBlock *BB = makeSampler(IB.Rand, make_pointer_range(F)).getSelection();
470     SmallVector<Instruction *, 32> Insts;
471     for (auto I = BB->getFirstInsertionPt(), E = BB->end(); I != E; ++I)
472       Insts.push_back(&*I);
473     // Choose an insertion point for our new instruction.
474     size_t IP = uniform<size_t>(IB.Rand, 1, Insts.size() - 2);
475 
476     auto InstsBefore = ArrayRef(Insts).slice(0, IP);
477     auto InstsAfter = ArrayRef(Insts).slice(IP);
478     Value *Src = IB.findOrCreateSource(
479         *BB, InstsBefore, {}, fuzzerop::onlyType(Types[i % Types.size()]));
480     ASSERT_TRUE(DT.dominates(Src, Insts[IP + 1]));
481     Instruction *Sink = IB.connectToSink(*BB, InstsAfter, Insts[IP - 1]);
482     if (!DT.dominates(Insts[IP - 1], Sink)) {
483       errs() << *Insts[IP - 1] << "\n" << *Sink << "\n ";
484     }
485     ASSERT_TRUE(DT.dominates(Insts[IP - 1], Sink));
486   }
487 }
488 TEST(RandomIRBuilderTest, sinkToIntrinsic) {
489   const char *Source = "\n\
490         declare double @llvm.sqrt.f64(double %Val)  \n\
491         declare void   @llvm.ubsantrap(i8 immarg) cold noreturn nounwind  \n\
492         \n\
493         define double @test(double %0, double %1, i64 %2, i64 %3, i64 %4, i8 %5) {  \n\
494         Entry:   \n\
495             %sqrt = call double @llvm.sqrt.f64(double %0)  \n\
496             call void @llvm.ubsantrap(i8 1)  \n\
497             ret double %sqrt \n\
498         }";
499   LLVMContext Ctx;
500   std::array<Type *, 3> Types = {Type::getInt8Ty(Ctx), Type::getInt64Ty(Ctx),
501                                  Type::getDoubleTy(Ctx)};
502   std::mt19937 mt(Seed);
503   std::uniform_int_distribution<int> RandInt(INT_MIN, INT_MAX);
504 
505   RandomIRBuilder IB(RandInt(mt), Types);
506   std::unique_ptr<Module> M = parseAssembly(Source, Ctx);
507   Function &F = *M->getFunction("test");
508   BasicBlock &BB = F.getEntryBlock();
509   bool Modified = false;
510 
511   Instruction *I = &*BB.begin();
512   for (int i = 0; i < 20; i++) {
513     Value *OldOperand = I->getOperand(0);
514     Value *Src = F.getArg(1);
515     IB.connectToSink(BB, {I}, Src);
516     Value *NewOperand = I->getOperand(0);
517     Modified |= (OldOperand != NewOperand);
518     ASSERT_FALSE(verifyModule(*M, &errs()));
519   }
520   ASSERT_TRUE(Modified);
521 
522   Modified = false;
523   I = I->getNextNonDebugInstruction();
524   for (int i = 0; i < 20; i++) {
525     Value *OldOperand = I->getOperand(0);
526     Value *Src = F.getArg(5);
527     IB.connectToSink(BB, {I}, Src);
528     Value *NewOperand = I->getOperand(0);
529     Modified |= (OldOperand != NewOperand);
530     ASSERT_FALSE(verifyModule(*M, &errs()));
531   }
532   ASSERT_FALSE(Modified);
533 }
534 
535 TEST(RandomIRBuilderTest, DoNotCallPointerWhenSink) {
536   const char *Source = "\n\
537         declare void @g()  \n\
538         define void @f(ptr %ptr) {  \n\
539         Entry:   \n\
540             call void @g()  \n\
541             ret void \n\
542         }";
543   LLVMContext Ctx;
544   std::mt19937 mt(Seed);
545   std::uniform_int_distribution<int> RandInt(INT_MIN, INT_MAX);
546 
547   RandomIRBuilder IB(RandInt(mt), {});
548   std::unique_ptr<Module> M = parseAssembly(Source, Ctx);
549   Function &F = *M->getFunction("f");
550   BasicBlock &BB = F.getEntryBlock();
551   bool Modified = false;
552 
553   Instruction *I = &*BB.begin();
554   for (int i = 0; i < 20; i++) {
555     Value *OldOperand = I->getOperand(0);
556     Value *Src = F.getArg(0);
557     IB.connectToSink(BB, {I}, Src);
558     Value *NewOperand = I->getOperand(0);
559     Modified |= (OldOperand != NewOperand);
560     ASSERT_FALSE(verifyModule(*M, &errs()));
561   }
562   ASSERT_FALSE(Modified);
563 }
564 
565 TEST(RandomIRBuilderTest, SrcAndSinkWOrphanBlock) {
566   const char *Source = "\n\
567         define i1 @test(i1 %Bool, i32 %Int, i64 %Long) {   \n\
568         Entry:    \n\
569             %Eq0 = icmp eq i64 %Long, 0 \n\
570             br i1 %Eq0, label %True, label %False \n\
571         True: \n\
572             %Or = or i1 %Bool, %Eq0 \n\
573             ret i1 %Or \n\
574         False: \n\
575             %And = and i1 %Bool, %Eq0 \n\
576             ret i1 %And \n\
577         Orphan_1:  \n\
578             %NotBool = sub i1 1, %Bool \n\
579             ret i1 %NotBool \n\
580         Orphan_2:  \n\
581             %Le42 = icmp sle i32 %Int, 42 \n\
582             ret i1 %Le42 \n\
583         }";
584   LLVMContext Ctx;
585   std::mt19937 mt(Seed);
586   std::uniform_int_distribution<int> RandInt(INT_MIN, INT_MAX);
587   std::array<Type *, 3> IntTys(
588       {Type::getInt64Ty(Ctx), Type::getInt32Ty(Ctx), Type::getInt1Ty(Ctx)});
589   std::vector<Value *> Constants;
590   for (Type *IntTy : IntTys) {
591     for (size_t v : {1, 42}) {
592       Constants.push_back(ConstantInt::get(IntTy, v));
593     }
594   }
595   for (int i = 0; i < 10; i++) {
596     RandomIRBuilder IB(RandInt(mt), IntTys);
597     std::unique_ptr<Module> M = parseAssembly(Source, Ctx);
598     Function &F = *M->getFunction("test");
599     for (BasicBlock &BB : F) {
600       SmallVector<Instruction *, 4> Insts;
601       for (Instruction &I : BB) {
602         Insts.push_back(&I);
603       }
604       for (int j = 0; j < 10; j++) {
605         IB.findOrCreateSource(BB, Insts);
606       }
607       for (Value *V : Constants) {
608         IB.connectToSink(BB, Insts, V);
609       }
610     }
611   }
612 }
613 } // namespace
614