mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-28 07:46:07 +00:00
[FuzzMutate] introduce vector operations, select and fneg into InstInjectorStrategy
Reviewed By: arsenm Differential Revision: https://reviews.llvm.org/D139894
This commit is contained in:
parent
4d7e5163d9
commit
c06adaeba6
@ -18,6 +18,7 @@
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/DerivedTypes.h"
|
||||
#include "llvm/IR/InstrTypes.h"
|
||||
#include "llvm/IR/Type.h"
|
||||
#include "llvm/IR/Value.h"
|
||||
#include <functional>
|
||||
@ -117,6 +118,20 @@ static inline SourcePred anyIntType() {
|
||||
return {Pred, Make};
|
||||
}
|
||||
|
||||
static inline SourcePred anyIntOrVecIntType() {
|
||||
auto Pred = [](ArrayRef<Value *>, const Value *V) {
|
||||
return V->getType()->isIntOrIntVectorTy();
|
||||
};
|
||||
return {Pred, std::nullopt};
|
||||
}
|
||||
|
||||
static inline SourcePred boolOrVecBoolType() {
|
||||
auto Pred = [](ArrayRef<Value *>, const Value *V) {
|
||||
return V->getType()->isIntOrIntVectorTy(1);
|
||||
};
|
||||
return {Pred, std::nullopt};
|
||||
}
|
||||
|
||||
static inline SourcePred anyFloatType() {
|
||||
auto Pred = [](ArrayRef<Value *>, const Value *V) {
|
||||
return V->getType()->isFloatingPointTy();
|
||||
@ -125,6 +140,13 @@ static inline SourcePred anyFloatType() {
|
||||
return {Pred, Make};
|
||||
}
|
||||
|
||||
static inline SourcePred anyFloatOrVecFloatType() {
|
||||
auto Pred = [](ArrayRef<Value *>, const Value *V) {
|
||||
return V->getType()->isFPOrFPVectorTy();
|
||||
};
|
||||
return {Pred, std::nullopt};
|
||||
}
|
||||
|
||||
static inline SourcePred anyPtrType() {
|
||||
auto Pred = [](ArrayRef<Value *>, const Value *V) {
|
||||
return V->getType()->isPointerTy() && !V->isSwiftError();
|
||||
@ -161,6 +183,54 @@ static inline SourcePred sizedPtrType() {
|
||||
return {Pred, Make};
|
||||
}
|
||||
|
||||
static inline SourcePred matchFirstLengthWAnyType() {
|
||||
auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
|
||||
assert(!Cur.empty() && "No first source yet");
|
||||
Type *This = V->getType(), *First = Cur[0]->getType();
|
||||
VectorType *ThisVec = dyn_cast<VectorType>(This);
|
||||
VectorType *FirstVec = dyn_cast<VectorType>(First);
|
||||
if (ThisVec && FirstVec) {
|
||||
return ThisVec->getElementCount() == FirstVec->getElementCount();
|
||||
}
|
||||
return (ThisVec == nullptr) && (FirstVec == nullptr) && (!This->isVoidTy());
|
||||
};
|
||||
auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *> BaseTypes) {
|
||||
assert(!Cur.empty() && "No first source yet");
|
||||
std::vector<Constant *> Result;
|
||||
ElementCount EC;
|
||||
bool isVec = false;
|
||||
if (VectorType *VecTy = dyn_cast<VectorType>(Cur[0]->getType())) {
|
||||
EC = VecTy->getElementCount();
|
||||
isVec = true;
|
||||
}
|
||||
for (Type *T : BaseTypes) {
|
||||
if (VectorType::isValidElementType(T)) {
|
||||
if (isVec)
|
||||
// If the first pred is <i1 x N>, make the result <T x N>
|
||||
makeConstantsWithType(VectorType::get(T, EC), Result);
|
||||
else
|
||||
makeConstantsWithType(T, Result);
|
||||
}
|
||||
}
|
||||
assert(!Result.empty() && "No potential constants.");
|
||||
return Result;
|
||||
};
|
||||
return {Pred, Make};
|
||||
}
|
||||
|
||||
/// Match values that have the same type as the first source.
|
||||
static inline SourcePred matchSecondType() {
|
||||
auto Pred = [](ArrayRef<Value *> Cur, const Value *V) {
|
||||
assert((Cur.size() > 1) && "No second source yet");
|
||||
return V->getType() == Cur[1]->getType();
|
||||
};
|
||||
auto Make = [](ArrayRef<Value *> Cur, ArrayRef<Type *>) {
|
||||
assert((Cur.size() > 1) && "No second source yet");
|
||||
return makeConstantsWithType(Cur[1]->getType());
|
||||
};
|
||||
return {Pred, Make};
|
||||
}
|
||||
|
||||
static inline SourcePred anyAggregateType() {
|
||||
auto Pred = [](ArrayRef<Value *>, const Value *V) {
|
||||
// We can't index zero sized arrays.
|
||||
|
@ -28,12 +28,16 @@ void describeFuzzerControlFlowOps(std::vector<fuzzerop::OpDescriptor> &Ops);
|
||||
void describeFuzzerPointerOps(std::vector<fuzzerop::OpDescriptor> &Ops);
|
||||
void describeFuzzerAggregateOps(std::vector<fuzzerop::OpDescriptor> &Ops);
|
||||
void describeFuzzerVectorOps(std::vector<fuzzerop::OpDescriptor> &Ops);
|
||||
void describeFuzzerUnaryOperations(std::vector<fuzzerop::OpDescriptor> &Ops);
|
||||
void describeFuzzerOtherOps(std::vector<fuzzerop::OpDescriptor> &Ops);
|
||||
/// @}
|
||||
|
||||
namespace fuzzerop {
|
||||
|
||||
/// Descriptors for individual operations.
|
||||
/// @{
|
||||
OpDescriptor selectDescriptor(unsigned Weight);
|
||||
OpDescriptor fnegDescriptor(unsigned Weight);
|
||||
OpDescriptor binOpDescriptor(unsigned Weight, Instruction::BinaryOps Op);
|
||||
OpDescriptor cmpOpDescriptor(unsigned Weight, Instruction::OtherOps CmpOp,
|
||||
CmpInst::Predicate Pred);
|
||||
@ -44,6 +48,7 @@ OpDescriptor insertValueDescriptor(unsigned Weight);
|
||||
OpDescriptor extractElementDescriptor(unsigned Weight);
|
||||
OpDescriptor insertElementDescriptor(unsigned Weight);
|
||||
OpDescriptor shuffleVectorDescriptor(unsigned Weight);
|
||||
|
||||
/// @}
|
||||
|
||||
} // namespace fuzzerop
|
||||
|
@ -15,6 +15,9 @@ using namespace fuzzerop;
|
||||
void fuzzerop::makeConstantsWithType(Type *T, std::vector<Constant *> &Cs) {
|
||||
if (auto *IntTy = dyn_cast<IntegerType>(T)) {
|
||||
uint64_t W = IntTy->getBitWidth();
|
||||
Cs.push_back(ConstantInt::get(IntTy, 0));
|
||||
Cs.push_back(ConstantInt::get(IntTy, 1));
|
||||
Cs.push_back(ConstantInt::get(IntTy, 42));
|
||||
Cs.push_back(ConstantInt::get(IntTy, APInt::getMaxValue(W)));
|
||||
Cs.push_back(ConstantInt::get(IntTy, APInt::getMinValue(W)));
|
||||
Cs.push_back(ConstantInt::get(IntTy, APInt::getSignedMaxValue(W)));
|
||||
@ -24,10 +27,24 @@ void fuzzerop::makeConstantsWithType(Type *T, std::vector<Constant *> &Cs) {
|
||||
auto &Ctx = T->getContext();
|
||||
auto &Sem = T->getFltSemantics();
|
||||
Cs.push_back(ConstantFP::get(Ctx, APFloat::getZero(Sem)));
|
||||
Cs.push_back(ConstantFP::get(Ctx, APFloat(Sem, 1)));
|
||||
Cs.push_back(ConstantFP::get(Ctx, APFloat(Sem, 42)));
|
||||
Cs.push_back(ConstantFP::get(Ctx, APFloat::getLargest(Sem)));
|
||||
Cs.push_back(ConstantFP::get(Ctx, APFloat::getSmallest(Sem)));
|
||||
} else
|
||||
Cs.push_back(ConstantFP::get(Ctx, APFloat::getInf(Sem)));
|
||||
Cs.push_back(ConstantFP::get(Ctx, APFloat::getNaN(Sem)));
|
||||
} else if (VectorType *VecTy = dyn_cast<VectorType>(T)) {
|
||||
std::vector<Constant *> EleCs;
|
||||
Type *EltTy = VecTy->getElementType();
|
||||
makeConstantsWithType(EltTy, EleCs);
|
||||
ElementCount EC = VecTy->getElementCount();
|
||||
for (Constant *Elt : EleCs) {
|
||||
Cs.push_back(ConstantVector::getSplat(EC, Elt));
|
||||
}
|
||||
} else {
|
||||
Cs.push_back(UndefValue::get(T));
|
||||
Cs.push_back(PoisonValue::get(T));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Constant *> fuzzerop::makeConstantsWithType(Type *T) {
|
||||
|
@ -67,11 +67,20 @@ void llvm::describeFuzzerFloatOps(std::vector<fuzzerop::OpDescriptor> &Ops) {
|
||||
Ops.push_back(cmpOpDescriptor(1, Instruction::FCmp, CmpInst::FCMP_TRUE));
|
||||
}
|
||||
|
||||
void llvm::describeFuzzerUnaryOperations(
|
||||
std::vector<fuzzerop::OpDescriptor> &Ops) {
|
||||
Ops.push_back(fnegDescriptor(1));
|
||||
}
|
||||
|
||||
void llvm::describeFuzzerControlFlowOps(
|
||||
std::vector<fuzzerop::OpDescriptor> &Ops) {
|
||||
Ops.push_back(splitBlockDescriptor(1));
|
||||
}
|
||||
|
||||
void llvm::describeFuzzerOtherOps(std::vector<fuzzerop::OpDescriptor> &Ops) {
|
||||
Ops.push_back(selectDescriptor(1));
|
||||
}
|
||||
|
||||
void llvm::describeFuzzerPointerOps(std::vector<fuzzerop::OpDescriptor> &Ops) {
|
||||
Ops.push_back(gepDescriptor(1));
|
||||
}
|
||||
@ -88,6 +97,22 @@ void llvm::describeFuzzerVectorOps(std::vector<fuzzerop::OpDescriptor> &Ops) {
|
||||
Ops.push_back(shuffleVectorDescriptor(1));
|
||||
}
|
||||
|
||||
OpDescriptor llvm::fuzzerop::selectDescriptor(unsigned Weight) {
|
||||
auto buildOp = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
|
||||
return SelectInst::Create(Srcs[0], Srcs[1], Srcs[2], "S", Inst);
|
||||
};
|
||||
return {Weight,
|
||||
{boolOrVecBoolType(), matchFirstLengthWAnyType(), matchSecondType()},
|
||||
buildOp};
|
||||
}
|
||||
|
||||
OpDescriptor llvm::fuzzerop::fnegDescriptor(unsigned Weight) {
|
||||
auto buildOp = [](ArrayRef<Value *> Srcs, Instruction *Inst) {
|
||||
return UnaryOperator::Create(Instruction::FNeg, Srcs[0], "F", Inst);
|
||||
};
|
||||
return {Weight, {anyFloatOrVecFloatType()}, buildOp};
|
||||
}
|
||||
|
||||
OpDescriptor llvm::fuzzerop::binOpDescriptor(unsigned Weight,
|
||||
Instruction::BinaryOps Op) {
|
||||
auto buildOp = [Op](ArrayRef<Value *> Srcs, Instruction *Inst) {
|
||||
@ -107,13 +132,13 @@ OpDescriptor llvm::fuzzerop::binOpDescriptor(unsigned Weight,
|
||||
case Instruction::And:
|
||||
case Instruction::Or:
|
||||
case Instruction::Xor:
|
||||
return {Weight, {anyIntType(), matchFirstType()}, buildOp};
|
||||
return {Weight, {anyIntOrVecIntType(), matchFirstType()}, buildOp};
|
||||
case Instruction::FAdd:
|
||||
case Instruction::FSub:
|
||||
case Instruction::FMul:
|
||||
case Instruction::FDiv:
|
||||
case Instruction::FRem:
|
||||
return {Weight, {anyFloatType(), matchFirstType()}, buildOp};
|
||||
return {Weight, {anyFloatOrVecFloatType(), matchFirstType()}, buildOp};
|
||||
case Instruction::BinaryOpsEnd:
|
||||
llvm_unreachable("Value out of range of enum");
|
||||
}
|
||||
@ -129,9 +154,9 @@ OpDescriptor llvm::fuzzerop::cmpOpDescriptor(unsigned Weight,
|
||||
|
||||
switch (CmpOp) {
|
||||
case Instruction::ICmp:
|
||||
return {Weight, {anyIntType(), matchFirstType()}, buildOp};
|
||||
return {Weight, {anyIntOrVecIntType(), matchFirstType()}, buildOp};
|
||||
case Instruction::FCmp:
|
||||
return {Weight, {anyFloatType(), matchFirstType()}, buildOp};
|
||||
return {Weight, {anyFloatOrVecFloatType(), matchFirstType()}, buildOp};
|
||||
default:
|
||||
llvm_unreachable("CmpOp must be ICmp or FCmp");
|
||||
}
|
||||
|
@ -91,10 +91,17 @@ TEST(OperationsTest, SourcePreds) {
|
||||
Constant *s = ConstantStruct::get(StructType::create(Ctx, "OpaqueStruct"));
|
||||
Constant *a =
|
||||
ConstantArray::get(ArrayType::get(i32->getType(), 2), {i32, i32});
|
||||
Constant *v8i1 = ConstantVector::getSplat(ElementCount::getFixed(8), i1);
|
||||
Constant *v8i8 = ConstantVector::getSplat(ElementCount::getFixed(8), i8);
|
||||
Constant *v4f16 = ConstantVector::getSplat(ElementCount::getFixed(4), f16);
|
||||
Constant *p0i32 =
|
||||
ConstantPointerNull::get(PointerType::get(i32->getType(), 0));
|
||||
Constant *v8p0i32 =
|
||||
ConstantVector::getSplat(ElementCount::getFixed(8), p0i32);
|
||||
Constant *vni32 = ConstantVector::getSplat(ElementCount::getScalable(8), i32);
|
||||
Constant *vnf64 = ConstantVector::getSplat(ElementCount::getScalable(8), f64);
|
||||
Constant *vnp0i32 =
|
||||
ConstantVector::getSplat(ElementCount::getScalable(8), p0i32);
|
||||
|
||||
auto OnlyI32 = onlyType(i32->getType());
|
||||
EXPECT_TRUE(OnlyI32.matches({}, i32));
|
||||
@ -126,6 +133,36 @@ TEST(OperationsTest, SourcePreds) {
|
||||
AnyInt.generate({}, {i32->getType(), f16->getType(), v8i8->getType()}),
|
||||
AllOf(SizeIs(Ge(1u)), Each(TypesMatch(i32))));
|
||||
|
||||
auto AnyIntOrVecInt = anyIntOrVecIntType();
|
||||
EXPECT_TRUE(AnyIntOrVecInt.matches({}, i1));
|
||||
EXPECT_TRUE(AnyIntOrVecInt.matches({}, i64));
|
||||
EXPECT_FALSE(AnyIntOrVecInt.matches({}, f32));
|
||||
EXPECT_FALSE(AnyIntOrVecInt.matches({}, v4f16));
|
||||
EXPECT_TRUE(AnyIntOrVecInt.matches({}, v8i8));
|
||||
EXPECT_FALSE(AnyIntOrVecInt.matches({}, v4f16));
|
||||
EXPECT_FALSE(AnyIntOrVecInt.matches({}, v8p0i32));
|
||||
EXPECT_TRUE(AnyIntOrVecInt.matches({}, vni32));
|
||||
EXPECT_FALSE(AnyIntOrVecInt.matches({}, vnf64));
|
||||
EXPECT_FALSE(AnyIntOrVecInt.matches({}, vnp0i32));
|
||||
|
||||
EXPECT_THAT(AnyIntOrVecInt.generate({}, {v8i8->getType()}),
|
||||
AllOf(Each(TypesMatch(v8i8))));
|
||||
|
||||
auto BoolOrVecBool = boolOrVecBoolType();
|
||||
EXPECT_TRUE(BoolOrVecBool.matches({}, i1));
|
||||
EXPECT_FALSE(BoolOrVecBool.matches({}, i64));
|
||||
EXPECT_FALSE(BoolOrVecBool.matches({}, f32));
|
||||
EXPECT_FALSE(BoolOrVecBool.matches({}, v4f16));
|
||||
EXPECT_TRUE(BoolOrVecBool.matches({}, v8i1));
|
||||
EXPECT_FALSE(BoolOrVecBool.matches({}, v4f16));
|
||||
EXPECT_FALSE(BoolOrVecBool.matches({}, v8p0i32));
|
||||
EXPECT_FALSE(BoolOrVecBool.matches({}, vni32));
|
||||
EXPECT_FALSE(BoolOrVecBool.matches({}, vnf64));
|
||||
EXPECT_FALSE(BoolOrVecBool.matches({}, vnp0i32));
|
||||
|
||||
EXPECT_THAT(BoolOrVecBool.generate({}, {v8i8->getType(), v8i1->getType()}),
|
||||
AllOf(Each(TypesMatch(v8i1))));
|
||||
|
||||
auto AnyFP = anyFloatType();
|
||||
EXPECT_TRUE(AnyFP.matches({}, f16));
|
||||
EXPECT_TRUE(AnyFP.matches({}, f32));
|
||||
@ -137,11 +174,30 @@ TEST(OperationsTest, SourcePreds) {
|
||||
AnyFP.generate({}, {i32->getType(), f16->getType(), v8i8->getType()}),
|
||||
AllOf(SizeIs(Ge(1u)), Each(TypesMatch(f16))));
|
||||
|
||||
auto AnyFPOrVecFP = anyFloatOrVecFloatType();
|
||||
EXPECT_TRUE(AnyFPOrVecFP.matches({}, f16));
|
||||
EXPECT_TRUE(AnyFPOrVecFP.matches({}, f32));
|
||||
EXPECT_FALSE(AnyFPOrVecFP.matches({}, i16));
|
||||
EXPECT_FALSE(AnyFPOrVecFP.matches({}, p0i32));
|
||||
EXPECT_TRUE(AnyFPOrVecFP.matches({}, v4f16));
|
||||
EXPECT_FALSE(AnyFPOrVecFP.matches({}, v8p0i32));
|
||||
EXPECT_FALSE(AnyFPOrVecFP.matches({}, vni32));
|
||||
EXPECT_TRUE(AnyFPOrVecFP.matches({}, vnf64));
|
||||
EXPECT_FALSE(AnyFPOrVecFP.matches({}, vnp0i32));
|
||||
|
||||
EXPECT_THAT(AnyFPOrVecFP.generate(
|
||||
{}, {i32->getType(), f16->getType(), v8i8->getType()}),
|
||||
AllOf(SizeIs(Ge(1u)), Each(TypesMatch(f16))));
|
||||
EXPECT_THAT(AnyFPOrVecFP.generate({}, {v4f16->getType()}),
|
||||
AllOf(SizeIs(Ge(1u)), Each(TypesMatch(v4f16))));
|
||||
|
||||
auto AnyPtr = anyPtrType();
|
||||
EXPECT_TRUE(AnyPtr.matches({}, p0i32));
|
||||
EXPECT_FALSE(AnyPtr.matches({}, i8));
|
||||
EXPECT_FALSE(AnyPtr.matches({}, a));
|
||||
EXPECT_FALSE(AnyPtr.matches({}, v8i8));
|
||||
EXPECT_FALSE(AnyPtr.matches({}, v8p0i32));
|
||||
EXPECT_FALSE(AnyPtr.matches({}, vni32));
|
||||
|
||||
auto isPointer = [](Value *V) { return V->getType()->isPointerTy(); };
|
||||
EXPECT_THAT(
|
||||
@ -154,9 +210,12 @@ TEST(OperationsTest, SourcePreds) {
|
||||
EXPECT_FALSE(AnyVec.matches({}, i8));
|
||||
EXPECT_FALSE(AnyVec.matches({}, a));
|
||||
EXPECT_FALSE(AnyVec.matches({}, s));
|
||||
EXPECT_TRUE(AnyVec.matches({}, v8p0i32));
|
||||
EXPECT_TRUE(AnyVec.matches({}, vni32));
|
||||
EXPECT_TRUE(AnyVec.matches({}, vnf64));
|
||||
EXPECT_TRUE(AnyVec.matches({}, vnp0i32));
|
||||
|
||||
EXPECT_THAT(AnyVec.generate({}, {v8i8->getType()}),
|
||||
ElementsAre(TypesMatch(v8i8)));
|
||||
EXPECT_THAT(AnyVec.generate({}, {v8i8->getType()}), Each(TypesMatch(v8i8)));
|
||||
|
||||
auto First = matchFirstType();
|
||||
EXPECT_TRUE(First.matches({i8}, i8));
|
||||
@ -167,6 +226,28 @@ TEST(OperationsTest, SourcePreds) {
|
||||
EXPECT_THAT(First.generate({i8}, {}), Each(TypesMatch(i8)));
|
||||
EXPECT_THAT(First.generate({f16}, {i8->getType()}), Each(TypesMatch(f16)));
|
||||
EXPECT_THAT(First.generate({v8i8, i32}, {}), Each(TypesMatch(v8i8)));
|
||||
|
||||
auto FirstLength = matchFirstLengthWAnyType();
|
||||
EXPECT_TRUE(FirstLength.matches({v8i8}, v8i1));
|
||||
|
||||
EXPECT_THAT(FirstLength.generate({v8i1}, {i8->getType()}),
|
||||
Each(TypesMatch(v8i8)));
|
||||
|
||||
auto Second = matchSecondType();
|
||||
EXPECT_TRUE(Second.matches({i32, i8}, i8));
|
||||
EXPECT_TRUE(Second.matches({i8, f16}, f16));
|
||||
|
||||
EXPECT_THAT(Second.generate({v8i8, i32}, {}), Each(TypesMatch(i32)));
|
||||
EXPECT_THAT(Second.generate({f32, f16}, {f16->getType()}),
|
||||
Each(TypesMatch(f16)));
|
||||
|
||||
auto FirstScalar = matchScalarOfFirstType();
|
||||
EXPECT_TRUE(FirstScalar.matches({v8i8}, i8));
|
||||
EXPECT_TRUE(FirstScalar.matches({i8}, i8));
|
||||
EXPECT_TRUE(FirstScalar.matches({v4f16}, f16));
|
||||
|
||||
EXPECT_THAT(FirstScalar.generate({v8i8}, {i8->getType()}),
|
||||
Each(TypesMatch(i8)));
|
||||
}
|
||||
|
||||
TEST(OperationsTest, SplitBlock) {
|
||||
@ -301,13 +382,12 @@ TEST(OperationsTest, GEPPointerOperand) {
|
||||
// Check that we only pick sized pointers for the GEP instructions
|
||||
|
||||
LLVMContext Ctx;
|
||||
const char *SourceCode =
|
||||
"%opaque = type opaque\n"
|
||||
"declare void @f()\n"
|
||||
"define void @test(%opaque %o) {\n"
|
||||
" %a = alloca i64, i32 10\n"
|
||||
" ret void\n"
|
||||
"}";
|
||||
const char *SourceCode = "%opaque = type opaque\n"
|
||||
"declare void @f()\n"
|
||||
"define void @test(%opaque %o) {\n"
|
||||
" %a = alloca i64, i32 10\n"
|
||||
" ret void\n"
|
||||
"}";
|
||||
auto M = parseAssembly(SourceCode, Ctx);
|
||||
|
||||
fuzzerop::OpDescriptor Descr = fuzzerop::gepDescriptor(1);
|
||||
|
@ -34,6 +34,17 @@ std::unique_ptr<IRMutator> createInjectorMutator() {
|
||||
Type::getInt1Ty, Type::getInt8Ty, Type::getInt16Ty, Type::getInt32Ty,
|
||||
Type::getInt64Ty, Type::getFloatTy, Type::getDoubleTy};
|
||||
|
||||
// Add vector 1, 2, 3, 4, and 8.
|
||||
int VectorLength[] = {1, 2, 3, 4, 8};
|
||||
std::vector<TypeGetter> BasicTypeGetters(Types);
|
||||
for (auto typeGetter : BasicTypeGetters) {
|
||||
for (int length : VectorLength) {
|
||||
Types.push_back([typeGetter, length](LLVMContext &C) {
|
||||
return VectorType::get(typeGetter(C), length, false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<IRMutationStrategy>> Strategies;
|
||||
Strategies.push_back(std::make_unique<InjectorIRStrategy>(
|
||||
InjectorIRStrategy::getDefaultOps()));
|
||||
@ -78,6 +89,25 @@ void IterateOnSource(StringRef Source, IRMutator &Mutator) {
|
||||
}
|
||||
}
|
||||
|
||||
static void mutateAndVerifyModule(StringRef Source,
|
||||
std::unique_ptr<IRMutator> &Mutator,
|
||||
int repeat = 100) {
|
||||
LLVMContext Ctx;
|
||||
auto M = parseAssembly(Source.data(), Ctx);
|
||||
std::mt19937 mt(Seed);
|
||||
std::uniform_int_distribution<int> RandInt(INT_MIN, INT_MAX);
|
||||
for (int i = 0; i < repeat; i++) {
|
||||
Mutator->mutateModule(*M, RandInt(mt), Source.size(), Source.size() + 1024);
|
||||
ASSERT_FALSE(verifyModule(*M, &errs()));
|
||||
}
|
||||
}
|
||||
template <class Strategy>
|
||||
static void mutateAndVerifyModule(StringRef Source, int repeat = 100) {
|
||||
auto Mutator = createMutator<Strategy>();
|
||||
ASSERT_TRUE(Mutator);
|
||||
mutateAndVerifyModule(Source, Mutator, repeat);
|
||||
}
|
||||
|
||||
TEST(InjectorIRStrategyTest, EmptyModule) {
|
||||
// Test that we can inject into empty module
|
||||
|
||||
@ -92,6 +122,13 @@ TEST(InjectorIRStrategyTest, EmptyModule) {
|
||||
EXPECT_TRUE(!verifyModule(*M, &errs()));
|
||||
}
|
||||
|
||||
TEST(InjectorIRStrategyTest, LargeInsertion) {
|
||||
StringRef Source = "";
|
||||
auto Mutator = createInjectorMutator();
|
||||
ASSERT_TRUE(Mutator);
|
||||
mutateAndVerifyModule(Source, Mutator, 100);
|
||||
}
|
||||
|
||||
TEST(InstDeleterIRStrategyTest, EmptyFunction) {
|
||||
// Test that we don't crash even if we can't remove from one of the functions.
|
||||
|
||||
@ -385,21 +422,6 @@ TEST(InstModificationIRStrategy, FastMath) {
|
||||
ASSERT_TRUE(p.second);
|
||||
}
|
||||
|
||||
template <class Strategy>
|
||||
static void mutateAndVerifyModule(StringRef Source, int repeat = 100) {
|
||||
LLVMContext Ctx;
|
||||
auto Mutator = createMutator<Strategy>();
|
||||
ASSERT_TRUE(Mutator);
|
||||
|
||||
auto M = parseAssembly(Source.data(), Ctx);
|
||||
std::mt19937 mt(Seed);
|
||||
std::uniform_int_distribution<int> RandInt(INT_MIN, INT_MAX);
|
||||
for (int i = 0; i < repeat; i++) {
|
||||
Mutator->mutateModule(*M, RandInt(mt), Source.size(), Source.size() + 1024);
|
||||
ASSERT_FALSE(verifyModule(*M, &errs()));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(InsertCFGStrategy, CFG) {
|
||||
StringRef Source = "\n\
|
||||
define i32 @test(i1 %C1, i1 %C2, i1 %C3, i16 %S1, i16 %S2, i32 %I1) { \n\
|
||||
|
Loading…
x
Reference in New Issue
Block a user