1 //===- RandomIRBuilderTest.cpp - Tests for injector strategy --------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "llvm/FuzzMutate/RandomIRBuilder.h"
11 #include "llvm/ADT/StringRef.h"
12 #include "llvm/AsmParser/Parser.h"
13 #include "llvm/AsmParser/SlotMapping.h"
14 #include "llvm/FuzzMutate/IRMutator.h"
15 #include "llvm/FuzzMutate/OpDescriptor.h"
16 #include "llvm/FuzzMutate/Operations.h"
17 #include "llvm/IR/Constants.h"
18 #include "llvm/IR/Instructions.h"
19 #include "llvm/IR/LLVMContext.h"
20 #include "llvm/IR/Module.h"
21 #include "llvm/IR/Verifier.h"
22 #include "llvm/Support/SourceMgr.h"
24 #include "gtest/gtest.h"
28 static constexpr int Seed
= 5;
32 std::unique_ptr
<Module
> parseAssembly(
33 const char *Assembly
, LLVMContext
&Context
) {
36 std::unique_ptr
<Module
> M
= parseAssemblyString(Assembly
, Error
, Context
);
39 raw_string_ostream
OS(ErrMsg
);
42 assert(M
&& !verifyModule(*M
, &errs()));
46 TEST(RandomIRBuilderTest
, ShuffleVectorIncorrectOperands
) {
47 // Test that we don't create load instruction as a source for the shuffle
52 "define <2 x i32> @test(<2 x i1> %cond, <2 x i32> %a) {\n"
53 " %A = alloca <2 x i32>\n"
54 " %I = insertelement <2 x i32> %a, i32 1, i32 1\n"
55 " ret <2 x i32> undef\n"
57 auto M
= parseAssembly(Source
, Ctx
);
59 fuzzerop::OpDescriptor Descr
= fuzzerop::shuffleVectorDescriptor(1);
61 // Empty known types since we ShuffleVector descriptor doesn't care about them
62 RandomIRBuilder
IB(Seed
, {});
64 // Get first basic block of the first function
65 Function
&F
= *M
->begin();
66 BasicBlock
&BB
= *F
.begin();
68 SmallVector
<Instruction
*, 32> Insts
;
69 for (auto I
= BB
.getFirstInsertionPt(), E
= BB
.end(); I
!= E
; ++I
)
72 // Pick first and second sources
73 SmallVector
<Value
*, 2> Srcs
;
74 ASSERT_TRUE(Descr
.SourcePreds
[0].matches(Srcs
, Insts
[1]));
75 Srcs
.push_back(Insts
[1]);
76 ASSERT_TRUE(Descr
.SourcePreds
[1].matches(Srcs
, Insts
[1]));
77 Srcs
.push_back(Insts
[1]);
79 // Create new source. Check that it always matches with the descriptor.
80 // Run some iterations to account for random decisions.
81 for (int i
= 0; i
< 10; ++i
) {
82 Value
*LastSrc
= IB
.newSource(BB
, Insts
, Srcs
, Descr
.SourcePreds
[2]);
83 ASSERT_TRUE(Descr
.SourcePreds
[2].matches(Srcs
, LastSrc
));
87 TEST(RandomIRBuilderTest
, InsertValueIndexes
) {
88 // Check that we will generate correct indexes for the insertvalue operation
92 "%T = type {i8, i32, i64}\n"
93 "define void @test() {\n"
95 " %L = load %T, %T* %A"
98 auto M
= parseAssembly(Source
, Ctx
);
100 fuzzerop::OpDescriptor IVDescr
= fuzzerop::insertValueDescriptor(1);
102 std::vector
<Type
*> Types
=
103 {Type::getInt8Ty(Ctx
), Type::getInt32Ty(Ctx
), Type::getInt64Ty(Ctx
)};
104 RandomIRBuilder
IB(Seed
, Types
);
106 // Get first basic block of the first function
107 Function
&F
= *M
->begin();
108 BasicBlock
&BB
= *F
.begin();
111 Instruction
*Src
= &*std::next(BB
.begin());
113 SmallVector
<Value
*, 2> Srcs(2);
114 ASSERT_TRUE(IVDescr
.SourcePreds
[0].matches({}, Src
));
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);
125 // Try to pick correct index
126 Value
*Src
= IB
.findOrCreateSource(
127 BB
, &*BB
.begin(), Srcs
, IVDescr
.SourcePreds
[2]);
128 ASSERT_TRUE(IVDescr
.SourcePreds
[2].matches(Srcs
, Src
));
133 TEST(RandomIRBuilderTest
, ShuffleVectorSink
) {
134 // Check that we will never use shuffle vector mask as a sink form the
135 // unrelated operation.
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"
144 auto M
= parseAssembly(SourceCode
, Ctx
);
146 fuzzerop::OpDescriptor IVDescr
= fuzzerop::insertValueDescriptor(1);
148 RandomIRBuilder
IB(Seed
, {});
150 // Get first basic block of the first function
151 Function
&F
= *M
->begin();
152 BasicBlock
&BB
= *F
.begin();
155 Instruction
*Source
= &*BB
.begin();
157 SmallVector
<Instruction
*, 1> Sinks
= {&*std::next(BB
.begin())};
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()));
167 TEST(RandomIRBuilderTest
, InsertValueArray
) {
168 // Check that we can generate insertvalue for the vector operations
171 const char *SourceCode
=
172 "define void @test() {\n"
173 " %A = alloca [8 x i32]\n"
174 " %L = load [8 x i32], [8 x i32]* %A"
177 auto M
= parseAssembly(SourceCode
, Ctx
);
179 fuzzerop::OpDescriptor Descr
= fuzzerop::insertValueDescriptor(1);
181 std::vector
<Type
*> Types
=
182 {Type::getInt8Ty(Ctx
), Type::getInt32Ty(Ctx
), Type::getInt64Ty(Ctx
)};
183 RandomIRBuilder
IB(Seed
, Types
);
185 // Get first basic block of the first function
186 Function
&F
= *M
->begin();
187 BasicBlock
&BB
= *F
.begin();
190 Instruction
*Source
= &*std::next(BB
.begin());
191 ASSERT_TRUE(Descr
.SourcePreds
[0].matches({}, Source
));
193 SmallVector
<Value
*, 2> Srcs(2);
195 // Check that we can always pick the last two operands.
196 for (int i
= 0; i
< 10; ++i
) {
198 Srcs
[1] = IB
.findOrCreateSource(BB
, {Source
}, Srcs
, Descr
.SourcePreds
[1]);
199 IB
.findOrCreateSource(BB
, {}, Srcs
, Descr
.SourcePreds
[2]);
203 TEST(RandomIRBuilderTest
, Invokes
) {
204 // Check that we never generate load or store after invoke instruction
207 const char *SourceCode
=
209 "declare i32 @personality_function()"
210 "define i32* @test() personality i32 ()* @personality_function {\n"
212 " %val = invoke i32* @f()\n"
213 " to label %normal unwind label %exceptional\n"
217 " %landing_pad4 = landingpad token cleanup\n"
220 auto M
= parseAssembly(SourceCode
, Ctx
);
223 std::vector
<Type
*> Types
= {Type::getInt8Ty(Ctx
)};
224 RandomIRBuilder
IB(Seed
, Types
);
226 // Get first basic block of the test function
227 Function
&F
= *M
->getFunction("test");
228 BasicBlock
&BB
= *F
.begin();
230 Instruction
*Invoke
= &*BB
.begin();
232 // Find source but never insert new load after invoke
233 for (int i
= 0; i
< 10; ++i
) {
234 (void)IB
.findOrCreateSource(BB
, {Invoke
}, {}, fuzzerop::anyIntType());
235 ASSERT_TRUE(!verifyModule(*M
, &errs()));
239 TEST(RandomIRBuilderTest
, FirstClassTypes
) {
240 // Check that we never insert new source as a load from non first class
244 const char *SourceCode
= "%Opaque = type opaque\n"
245 "define void @test(i8* %ptr) {\n"
247 " %tmp = bitcast i8* %ptr to i32* (i32*)*\n"
248 " %tmp1 = bitcast i8* %ptr to %Opaque*\n"
251 auto M
= parseAssembly(SourceCode
, Ctx
);
253 std::vector
<Type
*> Types
= {Type::getInt8Ty(Ctx
)};
254 RandomIRBuilder
IB(Seed
, Types
);
256 Function
&F
= *M
->getFunction("test");
257 BasicBlock
&BB
= *F
.begin();
258 // Non first class type
259 Instruction
*FuncPtr
= &*BB
.begin();
261 Instruction
*OpaquePtr
= &*std::next(BB
.begin());
263 for (int i
= 0; i
< 10; ++i
) {
264 Value
*V
= IB
.findOrCreateSource(BB
, {FuncPtr
, OpaquePtr
});
265 ASSERT_FALSE(isa
<LoadInst
>(V
));
269 TEST(RandomIRBuilderTest
, SwiftError
) {
270 // Check that we never pick swifterror value as a source for operation
271 // other than load, store and call.
274 const char *SourceCode
= "declare void @use(i8** swifterror %err)"
275 "define void @test() {\n"
277 " %err = alloca swifterror i8*, align 8\n"
278 " call void @use(i8** swifterror %err)\n"
281 auto M
= parseAssembly(SourceCode
, Ctx
);
283 std::vector
<Type
*> Types
= {Type::getInt8Ty(Ctx
)};
284 RandomIRBuilder
IB(Seed
, Types
);
286 // Get first basic block of the test function
287 Function
&F
= *M
->getFunction("test");
288 BasicBlock
&BB
= *F
.begin();
289 Instruction
*Alloca
= &*BB
.begin();
291 fuzzerop::OpDescriptor Descr
= fuzzerop::gepDescriptor(1);
293 for (int i
= 0; i
< 10; ++i
) {
294 Value
*V
= IB
.findOrCreateSource(BB
, {Alloca
}, {}, Descr
.SourcePreds
[0]);
295 ASSERT_FALSE(isa
<AllocaInst
>(V
));