diff --git a/llvm/lib/FuzzMutate/IRMutator.cpp b/llvm/lib/FuzzMutate/IRMutator.cpp --- a/llvm/lib/FuzzMutate/IRMutator.cpp +++ b/llvm/lib/FuzzMutate/IRMutator.cpp @@ -218,8 +218,8 @@ case Instruction::Mul: case Instruction::Sub: case Instruction::Shl: - Modifications.push_back([&Inst]() { Inst.setHasNoSignedWrap(true); }), - Modifications.push_back([&Inst]() { Inst.setHasNoSignedWrap(false); }); + Modifications.push_back([&Inst]() { Inst.setHasNoSignedWrap(true); }); + Modifications.push_back([&Inst]() { Inst.setHasNoSignedWrap(false); }); Modifications.push_back([&Inst]() { Inst.setHasNoUnsignedWrap(true); }); Modifications.push_back([&Inst]() { Inst.setHasNoUnsignedWrap(false); }); @@ -244,6 +244,54 @@ break; } + // Randomly switch operands of instructions + std::pair NoneItem({-1, -1}), ShuffleItems(NoneItem); + switch (Inst.getOpcode()) { + case Instruction::SDiv: + case Instruction::UDiv: + case Instruction::SRem: + case Instruction::URem: + case Instruction::FDiv: + case Instruction::FRem: { + // Verify that the after shuffle the second operand is not + // constant 0. + Value *Operand = Inst.getOperand(0); + if (Constant *C = dyn_cast(Operand)) { + if (!C->isZeroValue()) { + ShuffleItems = {0, 1}; + } + } + break; + } + case Instruction::Select: + ShuffleItems = {1, 2}; + break; + case Instruction::Add: + case Instruction::Sub: + case Instruction::Mul: + case Instruction::Shl: + case Instruction::LShr: + case Instruction::AShr: + case Instruction::And: + case Instruction::Or: + case Instruction::Xor: + case Instruction::FAdd: + case Instruction::FSub: + case Instruction::FMul: + case Instruction::ICmp: + case Instruction::FCmp: + case Instruction::ShuffleVector: + ShuffleItems = {0, 1}; + break; + } + if (ShuffleItems != NoneItem) { + Modifications.push_back([&Inst, &ShuffleItems]() { + Value *Op0 = Inst.getOperand(ShuffleItems.first); + Inst.setOperand(ShuffleItems.first, Inst.getOperand(ShuffleItems.second)); + Inst.setOperand(ShuffleItems.second, Op0); + }); + } + auto RS = makeSampler(IB.Rand, Modifications); if (RS) RS.getSelection()(); diff --git a/llvm/unittests/FuzzMutate/StrategiesTest.cpp b/llvm/unittests/FuzzMutate/StrategiesTest.cpp --- a/llvm/unittests/FuzzMutate/StrategiesTest.cpp +++ b/llvm/unittests/FuzzMutate/StrategiesTest.cpp @@ -37,24 +37,13 @@ return std::make_unique(std::move(Types), std::move(Strategies)); } -std::unique_ptr createDeleterMutator() { +template std::unique_ptr createMutator() { std::vector Types{ Type::getInt1Ty, Type::getInt8Ty, Type::getInt16Ty, Type::getInt32Ty, Type::getInt64Ty, Type::getFloatTy, Type::getDoubleTy}; std::vector> Strategies; - Strategies.push_back(std::make_unique()); - - return std::make_unique(std::move(Types), std::move(Strategies)); -} - -std::unique_ptr createInstModifierMutator() { - std::vector Types{ - Type::getInt1Ty, Type::getInt8Ty, Type::getInt16Ty, Type::getInt32Ty, - Type::getInt64Ty, Type::getFloatTy, Type::getDoubleTy}; - - std::vector> Strategies; - Strategies.push_back(std::make_unique()); + Strategies.push_back(std::make_unique()); return std::make_unique(std::move(Types), std::move(Strategies)); } @@ -113,7 +102,7 @@ "ret i32 %L6\n" "}\n"; - auto Mutator = createDeleterMutator(); + auto Mutator = createMutator(); ASSERT_TRUE(Mutator); IterateOnSource(Source, *Mutator); @@ -139,7 +128,7 @@ ret i32 %a.0\n\ }"; - auto Mutator = createDeleterMutator(); + auto Mutator = createMutator(); ASSERT_TRUE(Mutator); IterateOnSource(Source, *Mutator); @@ -154,7 +143,7 @@ ret i32 %a\n\ }"); - auto Mutator = createInstModifierMutator(); + auto Mutator = createMutator(); ASSERT_TRUE(Mutator); auto M = parseAssembly(Source.data(), Ctx); @@ -198,7 +187,7 @@ ret i1 %a\n\ }"; - auto Mutator = createInstModifierMutator(); + auto Mutator = createMutator(); ASSERT_TRUE(Mutator); auto M = parseAssembly(Source.data(), Ctx); @@ -223,7 +212,7 @@ ret i32* %gep\n\ }"; - auto Mutator = createInstModifierMutator(); + auto Mutator = createMutator(); ASSERT_TRUE(Mutator); auto M = parseAssembly(Source.data(), Ctx); @@ -239,4 +228,83 @@ EXPECT_TRUE(FoundInbounds); } + +/// The caller has to guarantee that function argument are used in the SAME +/// place as the operand. +void VerfyOperandShuffled(StringRef Source, std::pair ShuffleItems) { + LLVMContext Ctx; + auto Mutator = createMutator(); + ASSERT_TRUE(Mutator); + + auto M = parseAssembly(Source.data(), Ctx); + auto &F = *M->begin(); + Instruction *Inst = &*F.begin()->begin(); + ASSERT_TRUE(M && !verifyModule(*M, &errs())); + ASSERT_TRUE(Inst->getOperand(ShuffleItems.first) == + dyn_cast(F.getArg(ShuffleItems.first))); + ASSERT_TRUE(Inst->getOperand(ShuffleItems.second) == + dyn_cast(F.getArg(ShuffleItems.second))); + + Mutator->mutateModule(*M, 0, Source.size(), Source.size() + 100); + EXPECT_TRUE(!verifyModule(*M, &errs())); + + EXPECT_TRUE(Inst->getOperand(ShuffleItems.first) == + dyn_cast(F.getArg(ShuffleItems.second))); + EXPECT_TRUE(Inst->getOperand(ShuffleItems.second) == + dyn_cast(F.getArg(ShuffleItems.first))); +} + +TEST(InstModificationIRStrategyTest, ShuffleFAdd) { + StringRef Source = "\n\ + define float @test(float %0, float %1) {\n\ + %add = fadd float %0, %1\n\ + ret float %add\n\ + }"; + VerfyOperandShuffled(Source, {0, 1}); +} +TEST(InstModificationIRStrategyTest, ShuffleSelect) { + StringRef Source = "\n\ + define float @test(i1 %0, float %1, float %2) {\n\ + %select = select i1 %0, float %1, float %2\n\ + ret float %select\n\ + }"; + VerfyOperandShuffled(Source, {1, 2}); +} + +void VerfyDivDidntShuffle(StringRef Source) { + LLVMContext Ctx; + auto Mutator = createMutator(); + ASSERT_TRUE(Mutator); + + auto M = parseAssembly(Source.data(), Ctx); + auto &F = *M->begin(); + Instruction *Inst = &*F.begin()->begin(); + ASSERT_TRUE(M && !verifyModule(*M, &errs())); + + EXPECT_TRUE(isa(Inst->getOperand(0))); + EXPECT_TRUE(Inst->getOperand(1) == dyn_cast(F.getArg(0))); + + Mutator->mutateModule(*M, Seed, Source.size(), Source.size() + 100); + EXPECT_TRUE(!verifyModule(*M, &errs())); + + // Didn't shuffle. + EXPECT_TRUE(isa(Inst->getOperand(0))); + EXPECT_TRUE(Inst->getOperand(1) == dyn_cast(F.getArg(0))); +} +TEST(InstModificationIRStrategyTest, DidntShuffleSDiv) { + StringRef Source = "\n\ + define i32 @test(i32 %0) {\n\ + %div = sdiv i32 0, %0\n\ + ret i32 %div\n\ + }"; + VerfyDivDidntShuffle(Source); +} +TEST(InstModificationIRStrategyTest, DidntShuffleFRem) { + StringRef Source = "\n\ + define <2 x double> @test(<2 x double> %0) {\n\ + %div = frem <2 x double> , %0\n\ + ret <2 x double> %div\n\ + }"; + VerfyDivDidntShuffle(Source); +} } // namespace