brintos

brintos / llvm-project-archived public Read only

0
0
Text · 21.0 KiB · 9bef774 Raw
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