1 | //===- OperationsTest.cpp - Tests for fuzzer operations -------------------===// |
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/Operations.h" |
10 | #include "llvm/AsmParser/Parser.h" |
11 | #include "llvm/FuzzMutate/OpDescriptor.h" |
12 | #include "llvm/IR/Constants.h" |
13 | #include "llvm/IR/Instructions.h" |
14 | #include "llvm/IR/Module.h" |
15 | #include "llvm/IR/Verifier.h" |
16 | #include "llvm/Support/SourceMgr.h" |
17 | #include "gmock/gmock.h" |
18 | #include "gtest/gtest.h" |
19 | #include <iostream> |
20 | |
21 | // Define some pretty printers to help with debugging failures. |
22 | namespace llvm { |
23 | void PrintTo(Type *T, ::std::ostream *OS) { |
24 | raw_os_ostream ROS(*OS); |
25 | T->print(O&: ROS); |
26 | } |
27 | |
28 | void PrintTo(BasicBlock *BB, ::std::ostream *OS) { |
29 | raw_os_ostream ROS(*OS); |
30 | ROS << BB << " (" << BB->getName() << ")" ; |
31 | } |
32 | |
33 | void PrintTo(Value *V, ::std::ostream *OS) { |
34 | raw_os_ostream ROS(*OS); |
35 | ROS << V << " (" ; |
36 | V->print(O&: ROS); |
37 | ROS << ")" ; |
38 | } |
39 | void PrintTo(Constant *C, ::std::ostream *OS) { PrintTo(V: cast<Value>(Val: C), OS); } |
40 | |
41 | } // namespace llvm |
42 | |
43 | using namespace llvm; |
44 | |
45 | using testing::AllOf; |
46 | using testing::AnyOf; |
47 | using testing::Each; |
48 | using testing::ElementsAre; |
49 | using testing::Eq; |
50 | using testing::Ge; |
51 | using testing::PrintToString; |
52 | using testing::SizeIs; |
53 | using testing::Truly; |
54 | |
55 | namespace { |
56 | std::unique_ptr<Module> parseAssembly(const char *Assembly, |
57 | LLVMContext &Context) { |
58 | |
59 | SMDiagnostic Error; |
60 | std::unique_ptr<Module> M = parseAssemblyString(AsmString: Assembly, Err&: Error, Context); |
61 | |
62 | std::string ErrMsg; |
63 | raw_string_ostream OS(ErrMsg); |
64 | Error.print(ProgName: "" , S&: OS); |
65 | |
66 | assert(M && !verifyModule(*M, &errs())); |
67 | return M; |
68 | } |
69 | |
70 | MATCHER_P(TypesMatch, V, "has type " + PrintToString(V->getType())) { |
71 | return arg->getType() == V->getType(); |
72 | } |
73 | |
74 | MATCHER_P(HasType, T, "" ) { return arg->getType() == T; } |
75 | |
76 | TEST(OperationsTest, SourcePreds) { |
77 | using namespace llvm::fuzzerop; |
78 | |
79 | LLVMContext Ctx; |
80 | |
81 | Constant *i1 = ConstantInt::getFalse(Context&: Ctx); |
82 | Constant *i8 = ConstantInt::get(Ty: Type::getInt8Ty(C&: Ctx), V: 3); |
83 | Constant *i16 = ConstantInt::get(Ty: Type::getInt16Ty(C&: Ctx), V: 1 << 15); |
84 | Constant *i32 = ConstantInt::get(Ty: Type::getInt32Ty(C&: Ctx), V: 0); |
85 | Constant *i64 = ConstantInt::get(Ty: Type::getInt64Ty(C&: Ctx), |
86 | V: std::numeric_limits<uint64_t>::max()); |
87 | Constant *f16 = ConstantFP::getInfinity(Ty: Type::getHalfTy(C&: Ctx)); |
88 | Constant *f32 = ConstantFP::get(Ty: Type::getFloatTy(C&: Ctx), V: 0.0); |
89 | Constant *f64 = ConstantFP::get(Ty: Type::getDoubleTy(C&: Ctx), V: 123.45); |
90 | Constant *s = ConstantStruct::get(T: StructType::create(Context&: Ctx, Name: "OpaqueStruct" )); |
91 | Constant *a = |
92 | ConstantArray::get(T: ArrayType::get(ElementType: i32->getType(), NumElements: 2), V: {i32, i32}); |
93 | Constant *v8i1 = ConstantVector::getSplat(EC: ElementCount::getFixed(MinVal: 8), Elt: i1); |
94 | Constant *v8i8 = ConstantVector::getSplat(EC: ElementCount::getFixed(MinVal: 8), Elt: i8); |
95 | Constant *v4f16 = ConstantVector::getSplat(EC: ElementCount::getFixed(MinVal: 4), Elt: f16); |
96 | Constant *p0i32 = |
97 | ConstantPointerNull::get(T: PointerType::get(ElementType: i32->getType(), AddressSpace: 0)); |
98 | Constant *v8p0i32 = |
99 | ConstantVector::getSplat(EC: ElementCount::getFixed(MinVal: 8), Elt: p0i32); |
100 | Constant *vni32 = ConstantVector::getSplat(EC: ElementCount::getScalable(MinVal: 8), Elt: i32); |
101 | Constant *vnf64 = ConstantVector::getSplat(EC: ElementCount::getScalable(MinVal: 8), Elt: f64); |
102 | Constant *vnp0i32 = |
103 | ConstantVector::getSplat(EC: ElementCount::getScalable(MinVal: 8), Elt: p0i32); |
104 | |
105 | auto OnlyI32 = onlyType(Only: i32->getType()); |
106 | EXPECT_TRUE(OnlyI32.matches({}, i32)); |
107 | EXPECT_FALSE(OnlyI32.matches({}, i64)); |
108 | EXPECT_FALSE(OnlyI32.matches({}, p0i32)); |
109 | EXPECT_FALSE(OnlyI32.matches({}, a)); |
110 | |
111 | EXPECT_THAT(OnlyI32.generate({}, {}), |
112 | AllOf(SizeIs(Ge(1u)), Each(TypesMatch(i32)))); |
113 | |
114 | auto AnyType = anyType(); |
115 | EXPECT_TRUE(AnyType.matches({}, i1)); |
116 | EXPECT_TRUE(AnyType.matches({}, f64)); |
117 | EXPECT_TRUE(AnyType.matches({}, s)); |
118 | EXPECT_TRUE(AnyType.matches({}, v8i8)); |
119 | EXPECT_TRUE(AnyType.matches({}, p0i32)); |
120 | |
121 | EXPECT_THAT( |
122 | AnyType.generate({}, {i32->getType(), f16->getType(), v8i8->getType()}), |
123 | Each(AnyOf(TypesMatch(i32), TypesMatch(f16), TypesMatch(v8i8)))); |
124 | |
125 | auto AnyInt = anyIntType(); |
126 | EXPECT_TRUE(AnyInt.matches({}, i1)); |
127 | EXPECT_TRUE(AnyInt.matches({}, i64)); |
128 | EXPECT_FALSE(AnyInt.matches({}, f32)); |
129 | EXPECT_FALSE(AnyInt.matches({}, v4f16)); |
130 | |
131 | EXPECT_THAT( |
132 | AnyInt.generate({}, {i32->getType(), f16->getType(), v8i8->getType()}), |
133 | AllOf(SizeIs(Ge(1u)), Each(TypesMatch(i32)))); |
134 | |
135 | auto AnyIntOrVecInt = anyIntOrVecIntType(); |
136 | EXPECT_TRUE(AnyIntOrVecInt.matches({}, i1)); |
137 | EXPECT_TRUE(AnyIntOrVecInt.matches({}, i64)); |
138 | EXPECT_FALSE(AnyIntOrVecInt.matches({}, f32)); |
139 | EXPECT_FALSE(AnyIntOrVecInt.matches({}, v4f16)); |
140 | EXPECT_TRUE(AnyIntOrVecInt.matches({}, v8i8)); |
141 | EXPECT_FALSE(AnyIntOrVecInt.matches({}, v4f16)); |
142 | EXPECT_FALSE(AnyIntOrVecInt.matches({}, v8p0i32)); |
143 | EXPECT_TRUE(AnyIntOrVecInt.matches({}, vni32)); |
144 | EXPECT_FALSE(AnyIntOrVecInt.matches({}, vnf64)); |
145 | EXPECT_FALSE(AnyIntOrVecInt.matches({}, vnp0i32)); |
146 | |
147 | EXPECT_THAT(AnyIntOrVecInt.generate({}, {v8i8->getType()}), |
148 | AllOf(Each(TypesMatch(v8i8)))); |
149 | |
150 | auto BoolOrVecBool = boolOrVecBoolType(); |
151 | EXPECT_TRUE(BoolOrVecBool.matches({}, i1)); |
152 | EXPECT_FALSE(BoolOrVecBool.matches({}, i64)); |
153 | EXPECT_FALSE(BoolOrVecBool.matches({}, f32)); |
154 | EXPECT_FALSE(BoolOrVecBool.matches({}, v4f16)); |
155 | EXPECT_TRUE(BoolOrVecBool.matches({}, v8i1)); |
156 | EXPECT_FALSE(BoolOrVecBool.matches({}, v4f16)); |
157 | EXPECT_FALSE(BoolOrVecBool.matches({}, v8p0i32)); |
158 | EXPECT_FALSE(BoolOrVecBool.matches({}, vni32)); |
159 | EXPECT_FALSE(BoolOrVecBool.matches({}, vnf64)); |
160 | EXPECT_FALSE(BoolOrVecBool.matches({}, vnp0i32)); |
161 | |
162 | EXPECT_THAT(BoolOrVecBool.generate({}, {v8i8->getType(), v8i1->getType()}), |
163 | AllOf(Each(TypesMatch(v8i1)))); |
164 | |
165 | auto AnyFP = anyFloatType(); |
166 | EXPECT_TRUE(AnyFP.matches({}, f16)); |
167 | EXPECT_TRUE(AnyFP.matches({}, f32)); |
168 | EXPECT_FALSE(AnyFP.matches({}, i16)); |
169 | EXPECT_FALSE(AnyFP.matches({}, p0i32)); |
170 | EXPECT_FALSE(AnyFP.matches({}, v4f16)); |
171 | |
172 | EXPECT_THAT( |
173 | AnyFP.generate({}, {i32->getType(), f16->getType(), v8i8->getType()}), |
174 | AllOf(SizeIs(Ge(1u)), Each(TypesMatch(f16)))); |
175 | |
176 | auto AnyFPOrVecFP = anyFloatOrVecFloatType(); |
177 | EXPECT_TRUE(AnyFPOrVecFP.matches({}, f16)); |
178 | EXPECT_TRUE(AnyFPOrVecFP.matches({}, f32)); |
179 | EXPECT_FALSE(AnyFPOrVecFP.matches({}, i16)); |
180 | EXPECT_FALSE(AnyFPOrVecFP.matches({}, p0i32)); |
181 | EXPECT_TRUE(AnyFPOrVecFP.matches({}, v4f16)); |
182 | EXPECT_FALSE(AnyFPOrVecFP.matches({}, v8p0i32)); |
183 | EXPECT_FALSE(AnyFPOrVecFP.matches({}, vni32)); |
184 | EXPECT_TRUE(AnyFPOrVecFP.matches({}, vnf64)); |
185 | EXPECT_FALSE(AnyFPOrVecFP.matches({}, vnp0i32)); |
186 | |
187 | EXPECT_THAT(AnyFPOrVecFP.generate( |
188 | {}, {i32->getType(), f16->getType(), v8i8->getType()}), |
189 | AllOf(SizeIs(Ge(1u)), Each(TypesMatch(f16)))); |
190 | EXPECT_THAT(AnyFPOrVecFP.generate({}, {v4f16->getType()}), |
191 | AllOf(SizeIs(Ge(1u)), Each(TypesMatch(v4f16)))); |
192 | |
193 | auto AnyPtr = anyPtrType(); |
194 | EXPECT_TRUE(AnyPtr.matches({}, p0i32)); |
195 | EXPECT_FALSE(AnyPtr.matches({}, i8)); |
196 | EXPECT_FALSE(AnyPtr.matches({}, a)); |
197 | EXPECT_FALSE(AnyPtr.matches({}, v8i8)); |
198 | EXPECT_FALSE(AnyPtr.matches({}, v8p0i32)); |
199 | EXPECT_FALSE(AnyPtr.matches({}, vni32)); |
200 | |
201 | auto isPointer = [](Value *V) { return V->getType()->isPointerTy(); }; |
202 | EXPECT_THAT( |
203 | AnyPtr.generate({}, {i32->getType(), f16->getType(), v8i8->getType()}), |
204 | AllOf(SizeIs(Ge(3u)), Each(Truly(isPointer)))); |
205 | |
206 | auto AnyVec = anyVectorType(); |
207 | EXPECT_TRUE(AnyVec.matches({}, v8i8)); |
208 | EXPECT_TRUE(AnyVec.matches({}, v4f16)); |
209 | EXPECT_FALSE(AnyVec.matches({}, i8)); |
210 | EXPECT_FALSE(AnyVec.matches({}, a)); |
211 | EXPECT_FALSE(AnyVec.matches({}, s)); |
212 | EXPECT_TRUE(AnyVec.matches({}, v8p0i32)); |
213 | EXPECT_TRUE(AnyVec.matches({}, vni32)); |
214 | EXPECT_TRUE(AnyVec.matches({}, vnf64)); |
215 | EXPECT_TRUE(AnyVec.matches({}, vnp0i32)); |
216 | |
217 | EXPECT_THAT(AnyVec.generate({}, {v8i8->getType()}), Each(TypesMatch(v8i8))); |
218 | |
219 | auto First = matchFirstType(); |
220 | EXPECT_TRUE(First.matches({i8}, i8)); |
221 | EXPECT_TRUE(First.matches({s, a}, s)); |
222 | EXPECT_FALSE(First.matches({f16}, f32)); |
223 | EXPECT_FALSE(First.matches({v4f16, f64}, f64)); |
224 | |
225 | EXPECT_THAT(First.generate({i8}, {}), Each(TypesMatch(i8))); |
226 | EXPECT_THAT(First.generate({f16}, {i8->getType()}), Each(TypesMatch(f16))); |
227 | EXPECT_THAT(First.generate({v8i8, i32}, {}), Each(TypesMatch(v8i8))); |
228 | |
229 | auto FirstLength = matchFirstLengthWAnyType(); |
230 | EXPECT_TRUE(FirstLength.matches({v8i8}, v8i1)); |
231 | |
232 | EXPECT_THAT(FirstLength.generate({v8i1}, {i8->getType()}), |
233 | Each(TypesMatch(v8i8))); |
234 | |
235 | auto Second = matchSecondType(); |
236 | EXPECT_TRUE(Second.matches({i32, i8}, i8)); |
237 | EXPECT_TRUE(Second.matches({i8, f16}, f16)); |
238 | |
239 | EXPECT_THAT(Second.generate({v8i8, i32}, {}), Each(TypesMatch(i32))); |
240 | EXPECT_THAT(Second.generate({f32, f16}, {f16->getType()}), |
241 | Each(TypesMatch(f16))); |
242 | |
243 | auto FirstScalar = matchScalarOfFirstType(); |
244 | EXPECT_TRUE(FirstScalar.matches({v8i8}, i8)); |
245 | EXPECT_TRUE(FirstScalar.matches({i8}, i8)); |
246 | EXPECT_TRUE(FirstScalar.matches({v4f16}, f16)); |
247 | |
248 | EXPECT_THAT(FirstScalar.generate({v8i8}, {i8->getType()}), |
249 | Each(TypesMatch(i8))); |
250 | } |
251 | |
252 | TEST(OperationsTest, SplitBlock) { |
253 | LLVMContext Ctx; |
254 | |
255 | Module M("M" , Ctx); |
256 | Function *F = Function::Create(Ty: FunctionType::get(Result: Type::getVoidTy(C&: Ctx), Params: {}, |
257 | /*isVarArg=*/false), |
258 | Linkage: GlobalValue::ExternalLinkage, N: "f" , M: &M); |
259 | auto SBOp = fuzzerop::splitBlockDescriptor(Weight: 1); |
260 | |
261 | // Create a block with only a return and split it on the return. |
262 | auto *BB = BasicBlock::Create(Context&: Ctx, Name: "BB" , Parent: F); |
263 | auto *RI = ReturnInst::Create(C&: Ctx, InsertAtEnd: BB); |
264 | SBOp.BuilderFunc({UndefValue::get(T: Type::getInt1Ty(C&: Ctx))}, RI); |
265 | |
266 | // We should end up with an unconditional branch from BB to BB1, and the |
267 | // return ends up in BB1. |
268 | auto *UncondBr = cast<BranchInst>(Val: BB->getTerminator()); |
269 | ASSERT_TRUE(UncondBr->isUnconditional()); |
270 | auto *BB1 = UncondBr->getSuccessor(i: 0); |
271 | ASSERT_THAT(RI->getParent(), Eq(BB1)); |
272 | |
273 | // Now add an instruction to BB1 and split on that. |
274 | auto *AI = new AllocaInst(Type::getInt8Ty(C&: Ctx), 0, "a" , RI); |
275 | Value *Cond = ConstantInt::getFalse(Context&: Ctx); |
276 | SBOp.BuilderFunc({Cond}, AI); |
277 | |
278 | // We should end up with a loop back on BB1 and the instruction we split on |
279 | // moves to BB2. |
280 | auto *CondBr = cast<BranchInst>(Val: BB1->getTerminator()); |
281 | EXPECT_THAT(CondBr->getCondition(), Eq(Cond)); |
282 | ASSERT_THAT(CondBr->getNumSuccessors(), Eq(2u)); |
283 | ASSERT_THAT(CondBr->getSuccessor(0), Eq(BB1)); |
284 | auto *BB2 = CondBr->getSuccessor(i: 1); |
285 | EXPECT_THAT(AI->getParent(), Eq(BB2)); |
286 | EXPECT_THAT(RI->getParent(), Eq(BB2)); |
287 | |
288 | EXPECT_FALSE(verifyModule(M, &errs())); |
289 | } |
290 | |
291 | TEST(OperationsTest, SplitEHBlock) { |
292 | // Check that we will not try to branch back to the landingpad block using |
293 | // regular branch instruction |
294 | |
295 | LLVMContext Ctx; |
296 | const char *SourceCode = |
297 | "declare ptr @f()" |
298 | "declare i32 @personality_function()" |
299 | "define ptr @test() personality ptr @personality_function {\n" |
300 | "entry:\n" |
301 | " %val = invoke ptr @f()\n" |
302 | " to label %normal unwind label %exceptional\n" |
303 | "normal:\n" |
304 | " ret ptr %val\n" |
305 | "exceptional:\n" |
306 | " %landing_pad4 = landingpad token cleanup\n" |
307 | " ret ptr undef\n" |
308 | "}" ; |
309 | auto M = parseAssembly(Assembly: SourceCode, Context&: Ctx); |
310 | |
311 | // Get the landingpad block |
312 | BasicBlock &BB = *std::next(x: M->getFunction(Name: "test" )->begin(), n: 2); |
313 | |
314 | fuzzerop::OpDescriptor Descr = fuzzerop::splitBlockDescriptor(Weight: 1); |
315 | |
316 | Descr.BuilderFunc({ConstantInt::getTrue(Context&: Ctx)}, &*BB.getFirstInsertionPt()); |
317 | ASSERT_TRUE(!verifyModule(*M, &errs())); |
318 | } |
319 | |
320 | TEST(OperationsTest, SplitBlockWithPhis) { |
321 | LLVMContext Ctx; |
322 | |
323 | Type *Int8Ty = Type::getInt8Ty(C&: Ctx); |
324 | |
325 | Module M("M" , Ctx); |
326 | Function *F = Function::Create(Ty: FunctionType::get(Result: Type::getVoidTy(C&: Ctx), Params: {}, |
327 | /*isVarArg=*/false), |
328 | Linkage: GlobalValue::ExternalLinkage, N: "f" , M: &M); |
329 | auto SBOp = fuzzerop::splitBlockDescriptor(Weight: 1); |
330 | |
331 | // Create 3 blocks with an if-then branch. |
332 | auto *BB1 = BasicBlock::Create(Context&: Ctx, Name: "BB1" , Parent: F); |
333 | auto *BB2 = BasicBlock::Create(Context&: Ctx, Name: "BB2" , Parent: F); |
334 | auto *BB3 = BasicBlock::Create(Context&: Ctx, Name: "BB3" , Parent: F); |
335 | BranchInst::Create(IfTrue: BB2, IfFalse: BB3, Cond: ConstantInt::getFalse(Context&: Ctx), InsertAtEnd: BB1); |
336 | BranchInst::Create(IfTrue: BB3, InsertAtEnd: BB2); |
337 | |
338 | // Set up phi nodes selecting values for the incoming edges. |
339 | auto *PHI1 = PHINode::Create(Ty: Int8Ty, /*NumReservedValues=*/2, NameStr: "p1" , InsertAtEnd: BB3); |
340 | PHI1->addIncoming(V: ConstantInt::get(Ty: Int8Ty, V: 0), BB: BB1); |
341 | PHI1->addIncoming(V: ConstantInt::get(Ty: Int8Ty, V: 1), BB: BB2); |
342 | auto *PHI2 = PHINode::Create(Ty: Int8Ty, /*NumReservedValues=*/2, NameStr: "p2" , InsertAtEnd: BB3); |
343 | PHI2->addIncoming(V: ConstantInt::get(Ty: Int8Ty, V: 1), BB: BB1); |
344 | PHI2->addIncoming(V: ConstantInt::get(Ty: Int8Ty, V: 0), BB: BB2); |
345 | auto *RI = ReturnInst::Create(C&: Ctx, InsertAtEnd: BB3); |
346 | |
347 | // Now we split the block with PHI nodes, making sure they're all updated. |
348 | Value *Cond = ConstantInt::getFalse(Context&: Ctx); |
349 | SBOp.BuilderFunc({Cond}, RI); |
350 | |
351 | // Make sure the PHIs are updated with a value for the third incoming edge. |
352 | EXPECT_THAT(PHI1->getNumIncomingValues(), Eq(3u)); |
353 | EXPECT_THAT(PHI2->getNumIncomingValues(), Eq(3u)); |
354 | EXPECT_FALSE(verifyModule(M, &errs())); |
355 | } |
356 | |
357 | TEST(OperationsTest, GEP) { |
358 | LLVMContext Ctx; |
359 | |
360 | Type *Int8PtrTy = PointerType::getUnqual(C&: Ctx); |
361 | Type *Int32Ty = Type::getInt32Ty(C&: Ctx); |
362 | |
363 | Module M("M" , Ctx); |
364 | Function *F = Function::Create(Ty: FunctionType::get(Result: Type::getVoidTy(C&: Ctx), Params: {}, |
365 | /*isVarArg=*/false), |
366 | Linkage: GlobalValue::ExternalLinkage, N: "f" , M: &M); |
367 | auto *BB = BasicBlock::Create(Context&: Ctx, Name: "BB" , Parent: F); |
368 | auto *RI = ReturnInst::Create(C&: Ctx, InsertAtEnd: BB); |
369 | |
370 | auto GEPOp = fuzzerop::gepDescriptor(Weight: 1); |
371 | EXPECT_TRUE(GEPOp.SourcePreds[0].matches({}, UndefValue::get(Int8PtrTy))); |
372 | EXPECT_TRUE(GEPOp.SourcePreds[1].matches({UndefValue::get(Int8PtrTy)}, |
373 | ConstantInt::get(Int32Ty, 0))); |
374 | |
375 | GEPOp.BuilderFunc({UndefValue::get(T: Int8PtrTy), ConstantInt::get(Ty: Int32Ty, V: 0)}, |
376 | RI); |
377 | EXPECT_FALSE(verifyModule(M, &errs())); |
378 | } |
379 | |
380 | TEST(OperationsTest, GEPPointerOperand) { |
381 | // Check that we only pick sized pointers for the GEP instructions |
382 | |
383 | LLVMContext Ctx; |
384 | const char *SourceCode = "%opaque = type opaque\n" |
385 | "declare void @f()\n" |
386 | "define void @test(%opaque %o) {\n" |
387 | " %a = alloca i64, i32 10\n" |
388 | " ret void\n" |
389 | "}" ; |
390 | auto M = parseAssembly(Assembly: SourceCode, Context&: Ctx); |
391 | |
392 | fuzzerop::OpDescriptor Descr = fuzzerop::gepDescriptor(Weight: 1); |
393 | |
394 | // Get first basic block of the test function |
395 | Function &F = *M->getFunction(Name: "test" ); |
396 | BasicBlock &BB = *F.begin(); |
397 | |
398 | // Don't match %o |
399 | ASSERT_FALSE(Descr.SourcePreds[0].matches({}, &*F.arg_begin())); |
400 | |
401 | // Match %a |
402 | ASSERT_TRUE(Descr.SourcePreds[0].matches({}, &*BB.begin())); |
403 | } |
404 | |
405 | TEST(OperationsTest, ExtractAndInsertValue) { |
406 | LLVMContext Ctx; |
407 | |
408 | Type *Int8PtrTy = PointerType::getUnqual(C&: Ctx); |
409 | Type *Int32Ty = Type::getInt32Ty(C&: Ctx); |
410 | Type *Int64Ty = Type::getInt64Ty(C&: Ctx); |
411 | |
412 | Type *StructTy = StructType::create(Context&: Ctx, Elements: {Int8PtrTy, Int32Ty}); |
413 | Type *OpaqueTy = StructType::create(Context&: Ctx, Name: "OpaqueStruct" ); |
414 | Type *ZeroSizedArrayTy = ArrayType::get(ElementType: Int64Ty, NumElements: 0); |
415 | Type *ArrayTy = ArrayType::get(ElementType: Int64Ty, NumElements: 4); |
416 | Type *VectorTy = FixedVectorType::get(ElementType: Int32Ty, NumElts: 2); |
417 | |
418 | auto EVOp = fuzzerop::extractValueDescriptor(Weight: 1); |
419 | auto IVOp = fuzzerop::insertValueDescriptor(Weight: 1); |
420 | |
421 | // Sanity check the source preds. |
422 | Constant *SVal = UndefValue::get(T: StructTy); |
423 | Constant *OVal = UndefValue::get(T: OpaqueTy); |
424 | Constant *AVal = UndefValue::get(T: ArrayTy); |
425 | Constant *ZAVal = UndefValue::get(T: ZeroSizedArrayTy); |
426 | Constant *VVal = UndefValue::get(T: VectorTy); |
427 | |
428 | EXPECT_TRUE(EVOp.SourcePreds[0].matches({}, SVal)); |
429 | EXPECT_FALSE(EVOp.SourcePreds[0].matches({}, OVal)); |
430 | EXPECT_TRUE(EVOp.SourcePreds[0].matches({}, AVal)); |
431 | EXPECT_FALSE(EVOp.SourcePreds[0].matches({}, VVal)); |
432 | EXPECT_TRUE(IVOp.SourcePreds[0].matches({}, SVal)); |
433 | EXPECT_FALSE(IVOp.SourcePreds[0].matches({}, OVal)); |
434 | EXPECT_TRUE(IVOp.SourcePreds[0].matches({}, AVal)); |
435 | EXPECT_FALSE(IVOp.SourcePreds[0].matches({}, VVal)); |
436 | |
437 | // Don't consider zero sized arrays as viable sources |
438 | EXPECT_FALSE(EVOp.SourcePreds[0].matches({}, ZAVal)); |
439 | EXPECT_FALSE(IVOp.SourcePreds[0].matches({}, ZAVal)); |
440 | |
441 | // Make sure we're range checking appropriately. |
442 | EXPECT_TRUE( |
443 | EVOp.SourcePreds[1].matches({SVal}, ConstantInt::get(Int32Ty, 0))); |
444 | EXPECT_TRUE( |
445 | EVOp.SourcePreds[1].matches({SVal}, ConstantInt::get(Int32Ty, 1))); |
446 | EXPECT_FALSE( |
447 | EVOp.SourcePreds[1].matches({SVal}, ConstantInt::get(Int32Ty, 2))); |
448 | EXPECT_FALSE( |
449 | EVOp.SourcePreds[1].matches({OVal}, ConstantInt::get(Int32Ty, 0))); |
450 | EXPECT_FALSE( |
451 | EVOp.SourcePreds[1].matches({OVal}, ConstantInt::get(Int32Ty, 65536))); |
452 | EXPECT_TRUE( |
453 | EVOp.SourcePreds[1].matches({AVal}, ConstantInt::get(Int32Ty, 0))); |
454 | EXPECT_TRUE( |
455 | EVOp.SourcePreds[1].matches({AVal}, ConstantInt::get(Int32Ty, 3))); |
456 | EXPECT_FALSE( |
457 | EVOp.SourcePreds[1].matches({AVal}, ConstantInt::get(Int32Ty, 4))); |
458 | |
459 | EXPECT_THAT( |
460 | EVOp.SourcePreds[1].generate({SVal}, {}), |
461 | ElementsAre(ConstantInt::get(Int32Ty, 0), ConstantInt::get(Int32Ty, 1))); |
462 | |
463 | // InsertValue should accept any type in the struct, but only in positions |
464 | // where it makes sense. |
465 | EXPECT_TRUE(IVOp.SourcePreds[1].matches({SVal}, UndefValue::get(Int8PtrTy))); |
466 | EXPECT_TRUE(IVOp.SourcePreds[1].matches({SVal}, UndefValue::get(Int32Ty))); |
467 | EXPECT_FALSE(IVOp.SourcePreds[1].matches({SVal}, UndefValue::get(Int64Ty))); |
468 | EXPECT_FALSE(IVOp.SourcePreds[2].matches({SVal, UndefValue::get(Int32Ty)}, |
469 | ConstantInt::get(Int32Ty, 0))); |
470 | EXPECT_TRUE(IVOp.SourcePreds[2].matches({SVal, UndefValue::get(Int32Ty)}, |
471 | ConstantInt::get(Int32Ty, 1))); |
472 | |
473 | EXPECT_THAT(IVOp.SourcePreds[1].generate({SVal}, {}), |
474 | Each(AnyOf(HasType(Int32Ty), HasType(Int8PtrTy)))); |
475 | EXPECT_THAT( |
476 | IVOp.SourcePreds[2].generate({SVal, ConstantInt::get(Int32Ty, 0)}, {}), |
477 | ElementsAre(ConstantInt::get(Int32Ty, 1))); |
478 | } |
479 | |
480 | } // namespace |
481 | |