1 //===- RandomIRBuilderTest.cpp - Tests for injector strategy --------------===//
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
7 //===----------------------------------------------------------------------===//
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/IR/Constants.h"
17 #include "llvm/IR/Instructions.h"
18 #include "llvm/IR/LLVMContext.h"
19 #include "llvm/IR/Module.h"
20 #include "llvm/IR/Verifier.h"
21 #include "llvm/Support/SourceMgr.h"
23 #include "gtest/gtest.h"
27 static constexpr int Seed
= 5;
31 std::unique_ptr
<Module
> parseAssembly(
32 const char *Assembly
, LLVMContext
&Context
) {
35 std::unique_ptr
<Module
> M
= parseAssemblyString(Assembly
, Error
, Context
);
38 raw_string_ostream
OS(ErrMsg
);
41 assert(M
&& !verifyModule(*M
, &errs()));
45 TEST(RandomIRBuilderTest
, ShuffleVectorIncorrectOperands
) {
46 // Test that we don't create load instruction as a source for the shuffle
51 "define <2 x i32> @test(<2 x i1> %cond, <2 x i32> %a) {\n"
52 " %A = alloca <2 x i32>\n"
53 " %I = insertelement <2 x i32> %a, i32 1, i32 1\n"
54 " ret <2 x i32> undef\n"
56 auto M
= parseAssembly(Source
, Ctx
);
58 fuzzerop::OpDescriptor Descr
= fuzzerop::shuffleVectorDescriptor(1);
60 // Empty known types since we ShuffleVector descriptor doesn't care about them
61 RandomIRBuilder
IB(Seed
, {});
63 // Get first basic block of the first function
64 Function
&F
= *M
->begin();
65 BasicBlock
&BB
= *F
.begin();
67 SmallVector
<Instruction
*, 32> Insts
;
68 for (auto I
= BB
.getFirstInsertionPt(), E
= BB
.end(); I
!= E
; ++I
)
71 // Pick first and second sources
72 SmallVector
<Value
*, 2> Srcs
;
73 ASSERT_TRUE(Descr
.SourcePreds
[0].matches(Srcs
, Insts
[1]));
74 Srcs
.push_back(Insts
[1]);
75 ASSERT_TRUE(Descr
.SourcePreds
[1].matches(Srcs
, Insts
[1]));
76 Srcs
.push_back(Insts
[1]);
78 // Create new source. Check that it always matches with the descriptor.
79 // Run some iterations to account for random decisions.
80 for (int i
= 0; i
< 10; ++i
) {
81 Value
*LastSrc
= IB
.newSource(BB
, Insts
, Srcs
, Descr
.SourcePreds
[2]);
82 ASSERT_TRUE(Descr
.SourcePreds
[2].matches(Srcs
, LastSrc
));
86 TEST(RandomIRBuilderTest
, InsertValueIndexes
) {
87 // Check that we will generate correct indexes for the insertvalue operation
91 "%T = type {i8, i32, i64}\n"
92 "define void @test() {\n"
94 " %L = load %T, %T* %A"
97 auto M
= parseAssembly(Source
, Ctx
);
99 fuzzerop::OpDescriptor IVDescr
= fuzzerop::insertValueDescriptor(1);
101 std::vector
<Type
*> Types
=
102 {Type::getInt8Ty(Ctx
), Type::getInt32Ty(Ctx
), Type::getInt64Ty(Ctx
)};
103 RandomIRBuilder
IB(Seed
, Types
);
105 // Get first basic block of the first function
106 Function
&F
= *M
->begin();
107 BasicBlock
&BB
= *F
.begin();
110 Instruction
*Src
= &*std::next(BB
.begin());
112 SmallVector
<Value
*, 2> Srcs(2);
113 ASSERT_TRUE(IVDescr
.SourcePreds
[0].matches({}, Src
));
116 // Generate constants for each of the types and check that we pick correct
117 // index for the given type
118 for (auto *T
: Types
) {
119 // Loop to account for possible random decisions
120 for (int i
= 0; i
< 10; ++i
) {
121 // Create value we want to insert. Only it's type matters.
122 Srcs
[1] = ConstantInt::get(T
, 5);
124 // Try to pick correct index
125 Value
*Src
= IB
.findOrCreateSource(
126 BB
, &*BB
.begin(), Srcs
, IVDescr
.SourcePreds
[2]);
127 ASSERT_TRUE(IVDescr
.SourcePreds
[2].matches(Srcs
, Src
));
132 TEST(RandomIRBuilderTest
, ShuffleVectorSink
) {
133 // Check that we will never use shuffle vector mask as a sink form the
134 // unrelated operation.
137 const char *SourceCode
=
138 "define void @test(<4 x i32> %a) {\n"
139 " %S1 = shufflevector <4 x i32> %a, <4 x i32> %a, <4 x i32> undef\n"
140 " %S2 = shufflevector <4 x i32> %a, <4 x i32> %a, <4 x i32> undef\n"
143 auto M
= parseAssembly(SourceCode
, Ctx
);
145 fuzzerop::OpDescriptor IVDescr
= fuzzerop::insertValueDescriptor(1);
147 RandomIRBuilder
IB(Seed
, {});
149 // Get first basic block of the first function
150 Function
&F
= *M
->begin();
151 BasicBlock
&BB
= *F
.begin();
154 Instruction
*Source
= &*BB
.begin();
156 SmallVector
<Instruction
*, 1> Sinks
= {&*std::next(BB
.begin())};
158 // Loop to account for random decisions
159 for (int i
= 0; i
< 10; ++i
) {
160 // Try to connect S1 to S2. We should always create new sink.
161 IB
.connectToSink(BB
, Sinks
, Source
);
162 ASSERT_TRUE(!verifyModule(*M
, &errs()));
166 TEST(RandomIRBuilderTest
, InsertValueArray
) {
167 // Check that we can generate insertvalue for the vector operations
170 const char *SourceCode
=
171 "define void @test() {\n"
172 " %A = alloca [8 x i32]\n"
173 " %L = load [8 x i32], [8 x i32]* %A"
176 auto M
= parseAssembly(SourceCode
, Ctx
);
178 fuzzerop::OpDescriptor Descr
= fuzzerop::insertValueDescriptor(1);
180 std::vector
<Type
*> Types
=
181 {Type::getInt8Ty(Ctx
), Type::getInt32Ty(Ctx
), Type::getInt64Ty(Ctx
)};
182 RandomIRBuilder
IB(Seed
, Types
);
184 // Get first basic block of the first function
185 Function
&F
= *M
->begin();
186 BasicBlock
&BB
= *F
.begin();
189 Instruction
*Source
= &*std::next(BB
.begin());
190 ASSERT_TRUE(Descr
.SourcePreds
[0].matches({}, Source
));
192 SmallVector
<Value
*, 2> Srcs(2);
194 // Check that we can always pick the last two operands.
195 for (int i
= 0; i
< 10; ++i
) {
197 Srcs
[1] = IB
.findOrCreateSource(BB
, {Source
}, Srcs
, Descr
.SourcePreds
[1]);
198 IB
.findOrCreateSource(BB
, {}, Srcs
, Descr
.SourcePreds
[2]);
202 TEST(RandomIRBuilderTest
, Invokes
) {
203 // Check that we never generate load or store after invoke instruction
206 const char *SourceCode
=
208 "declare i32 @personality_function()"
209 "define i32* @test() personality i32 ()* @personality_function {\n"
211 " %val = invoke i32* @f()\n"
212 " to label %normal unwind label %exceptional\n"
216 " %landing_pad4 = landingpad token cleanup\n"
219 auto M
= parseAssembly(SourceCode
, Ctx
);
222 std::vector
<Type
*> Types
= {Type::getInt8Ty(Ctx
)};
223 RandomIRBuilder
IB(Seed
, Types
);
225 // Get first basic block of the test function
226 Function
&F
= *M
->getFunction("test");
227 BasicBlock
&BB
= *F
.begin();
229 Instruction
*Invoke
= &*BB
.begin();
231 // Find source but never insert new load after invoke
232 for (int i
= 0; i
< 10; ++i
) {
233 (void)IB
.findOrCreateSource(BB
, {Invoke
}, {}, fuzzerop::anyIntType());
234 ASSERT_TRUE(!verifyModule(*M
, &errs()));
238 TEST(RandomIRBuilderTest
, FirstClassTypes
) {
239 // Check that we never insert new source as a load from non first class
243 const char *SourceCode
= "%Opaque = type opaque\n"
244 "define void @test(i8* %ptr) {\n"
246 " %tmp = bitcast i8* %ptr to i32* (i32*)*\n"
247 " %tmp1 = bitcast i8* %ptr to %Opaque*\n"
250 auto M
= parseAssembly(SourceCode
, Ctx
);
252 std::vector
<Type
*> Types
= {Type::getInt8Ty(Ctx
)};
253 RandomIRBuilder
IB(Seed
, Types
);
255 Function
&F
= *M
->getFunction("test");
256 BasicBlock
&BB
= *F
.begin();
257 // Non first class type
258 Instruction
*FuncPtr
= &*BB
.begin();
260 Instruction
*OpaquePtr
= &*std::next(BB
.begin());
262 for (int i
= 0; i
< 10; ++i
) {
263 Value
*V
= IB
.findOrCreateSource(BB
, {FuncPtr
, OpaquePtr
});
264 ASSERT_FALSE(isa
<LoadInst
>(V
));
268 TEST(RandomIRBuilderTest
, SwiftError
) {
269 // Check that we never pick swifterror value as a source for operation
270 // other than load, store and call.
273 const char *SourceCode
= "declare void @use(i8** swifterror %err)"
274 "define void @test() {\n"
276 " %err = alloca swifterror i8*, align 8\n"
277 " call void @use(i8** swifterror %err)\n"
280 auto M
= parseAssembly(SourceCode
, Ctx
);
282 std::vector
<Type
*> Types
= {Type::getInt8Ty(Ctx
)};
283 RandomIRBuilder
IB(Seed
, Types
);
285 // Get first basic block of the test function
286 Function
&F
= *M
->getFunction("test");
287 BasicBlock
&BB
= *F
.begin();
288 Instruction
*Alloca
= &*BB
.begin();
290 fuzzerop::OpDescriptor Descr
= fuzzerop::gepDescriptor(1);
292 for (int i
= 0; i
< 10; ++i
) {
293 Value
*V
= IB
.findOrCreateSource(BB
, {Alloca
}, {}, Descr
.SourcePreds
[0]);
294 ASSERT_FALSE(isa
<AllocaInst
>(V
));