diff --git a/llvm/lib/FuzzMutate/RandomIRBuilder.cpp b/llvm/lib/FuzzMutate/RandomIRBuilder.cpp --- a/llvm/lib/FuzzMutate/RandomIRBuilder.cpp +++ b/llvm/lib/FuzzMutate/RandomIRBuilder.cpp @@ -72,6 +72,7 @@ static bool isCompatibleReplacement(const Instruction *I, const Use &Operand, const Value *Replacement) { + unsigned int OperandNo = Operand.getOperandNo(); if (Operand->getType() != Replacement->getType()) return false; switch (I->getOpcode()) { @@ -80,13 +81,21 @@ case Instruction::ExtractValue: // TODO: We could potentially validate these, but for now just leave indices // alone. - if (Operand.getOperandNo() >= 1) + if (OperandNo >= 1) return false; break; case Instruction::InsertValue: case Instruction::InsertElement: case Instruction::ShuffleVector: - if (Operand.getOperandNo() >= 2) + if (OperandNo >= 2) + return false; + break; + // For Br/Switch, we only try to modify the 1st Operand (condition). + // Modify other operands, like switch case may accidently change case from + // ConstnatInt to a register, which is illegal. + case Instruction::Switch: + case Instruction::Br: + if (OperandNo >= 1) return false; break; default: diff --git a/llvm/unittests/FuzzMutate/RandomIRBuilderTest.cpp b/llvm/unittests/FuzzMutate/RandomIRBuilderTest.cpp --- a/llvm/unittests/FuzzMutate/RandomIRBuilderTest.cpp +++ b/llvm/unittests/FuzzMutate/RandomIRBuilderTest.cpp @@ -13,6 +13,7 @@ #include "llvm/FuzzMutate/IRMutator.h" #include "llvm/FuzzMutate/OpDescriptor.h" #include "llvm/FuzzMutate/Operations.h" +#include "llvm/FuzzMutate/Random.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/LLVMContext.h" @@ -292,4 +293,49 @@ } } +TEST(RandomIRBuilderTest, dontConnectToSwitch) { + // Check that we never put anything into switch's case branch + // If we accidently put a variable, the module is invalid. + LLVMContext Ctx; + const char *SourceCode = "\n\ + define void @test(i1 %C1, i1 %C2, i32 %I, i32 %J) { \n\ + Entry: \n\ + %I.1 = add i32 %I, 42 \n\ + %J.1 = add i32 %J, 42 \n\ + %IJ = add i32 %I, %J \n\ + switch i32 %I, label %Default [ \n\ + i32 1, label %OnOne \n\ + ] \n\ + Default: \n\ + %CIEqJ = icmp eq i32 %I.1, %J.1 \n\ + %CISltJ = icmp slt i32 %I.1, %J.1 \n\ + %CAnd = and i1 %C1, %C2 \n\ + br i1 %CIEqJ, label %Default, label %Exit \n\ + OnOne: \n\ + br i1 %C1, label %OnOne, label %Exit \n\ + Exit: \n\ + ret void \n\ + }"; + + std::vector Types = {Type::getInt32Ty(Ctx), Type::getInt1Ty(Ctx)}; + RandomIRBuilder IB(Seed, Types); + for (int i = 0; i < 20; i++) { + std::unique_ptr M = parseAssembly(SourceCode, Ctx); + Function &F = *M->getFunction("test"); + auto RS = makeSampler(IB.Rand, make_pointer_range(F)); + BasicBlock *BB = RS.getSelection(); + SmallVector Insts; + for (auto I = BB->getFirstInsertionPt(), E = BB->end(); I != E; ++I) + Insts.push_back(&*I); + if (Insts.size() < 2) + continue; + // Choose an instruction and connect to later operations. + size_t IP = uniform(IB.Rand, 1, Insts.size() - 1); + Instruction *Inst = Insts[IP - 1]; + auto ConnectAfter = makeArrayRef(Insts).slice(IP); + IB.connectToSink(*BB, ConnectAfter, Inst); + ASSERT_TRUE(!verifyModule(*M, &errs())); + } +} + } // namespace