611 lines · cpp
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-exception6//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 27using namespace llvm;28 29static constexpr int Seed = 5;30 31namespace {32 33std::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 47TEST(RandomIRBuilderTest, ShuffleVectorIncorrectOperands) {48 // Test that we don't create load instruction as a source for the shuffle49 // 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 them63 RandomIRBuilder IB(Seed, {});64 65 // Get first basic block of the first function66 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 sources74 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 88TEST(RandomIRBuilderTest, InsertValueIndexes) {89 // Check that we will generate correct indexes for the insertvalue operation90 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 function107 Function &F = *M->begin();108 BasicBlock &BB = *F.begin();109 110 // Pick first source111 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 correct118 // index for the given type119 for (auto *T : Types) {120 // Loop to account for possible random decisions121 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 index126 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 133TEST(RandomIRBuilderTest, ShuffleVectorSink) {134 // Check that we will never use shuffle vector mask as a sink from the135 // 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 function151 Function &F = *M->begin();152 BasicBlock &BB = *F.begin();153 154 // Source is %S1155 Instruction *Source = &*BB.begin();156 // Sink is %S2157 SmallVector<Instruction *, 1> Sinks = {&*std::next(BB.begin())};158 159 // Loop to account for random decisions160 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 167TEST(RandomIRBuilderTest, InsertValueArray) {168 // Check that we can generate insertvalue for the vector operations169 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 function185 Function &F = *M->begin();186 BasicBlock &BB = *F.begin();187 188 // Pick first source189 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 202TEST(RandomIRBuilderTest, Invokes) {203 // Check that we never generate load or store after invoke instruction204 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 function225 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 invoke231 for (int i = 0; i < 10; ++i) {232 (void)IB.findOrCreateSource(BB, {Invoke}, {}, fuzzerop::anyIntType());233 ASSERT_TRUE(!verifyModule(*M, &errs()));234 }235}236 237TEST(RandomIRBuilderTest, SwiftError) {238 // Check that we never pick swifterror value as a source for operation239 // 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 function255 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 267TEST(RandomIRBuilderTest, dontConnectToSwitch) {268 // Check that we never put anything into switch's case branch269 // 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 312TEST(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 364TEST(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 global375 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 global387 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 global397 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 correct405/// domination relation.406TEST(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 is463 // 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}488TEST(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->getNextNode();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 535TEST(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 565TEST(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(llvm::make_pointer_range(BB));601 for (int j = 0; j < 10; j++) {602 IB.findOrCreateSource(BB, Insts);603 }604 for (Value *V : Constants) {605 IB.connectToSink(BB, Insts, V);606 }607 }608 }609}610} // namespace611