Index: llvm/tools/llvm-stress/CMakeLists.txt =================================================================== --- llvm/tools/llvm-stress/CMakeLists.txt +++ llvm/tools/llvm-stress/CMakeLists.txt @@ -1,6 +1,7 @@ set(LLVM_LINK_COMPONENTS Analysis Core + FuzzMutate Support ) Index: llvm/tools/llvm-stress/llvm-stress.cpp =================================================================== --- llvm/tools/llvm-stress/llvm-stress.cpp +++ llvm/tools/llvm-stress/llvm-stress.cpp @@ -17,6 +17,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" +#include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/Constants.h" @@ -32,11 +33,16 @@ #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" #include "llvm/IR/Verifier.h" +#include "llvm/FuzzMutate/FuzzerCLI.h" +#include "llvm/FuzzMutate/IRMutator.h" +#include "llvm/FuzzMutate/Operations.h" +#include "llvm/IRReader/IRReader.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/InitLLVM.h" +#include "llvm/Support/SourceMgr.h" #include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" @@ -53,28 +59,41 @@ static cl::OptionCategory StressCategory("Stress Options"); +namespace subopts { +static cl::SubCommand + Generate("generate", + "Generate a new random IR file (default if no subcommand provided)"); +static cl::SubCommand + Mutate("mutate", + "Randomly mutates user provided IR provided on standard in"); +} // namespace subopts + + static cl::opt SeedCL("seed", cl::desc("Seed used for randomness"), - cl::init(0), cl::cat(StressCategory)); + cl::init(0), cl::cat(StressCategory), + cl::sub(*cl::AllSubCommands)); static cl::opt SizeCL( "size", cl::desc("The estimated size of the generated function (# of instrs)"), - cl::init(100), cl::cat(StressCategory)); + cl::init(100), cl::cat(StressCategory), cl::sub(subopts::Generate)); static cl::opt OutputFilename("o", cl::desc("Override output filename"), cl::value_desc("filename"), - cl::cat(StressCategory)); + cl::cat(StressCategory), + cl::sub(*cl::AllSubCommands)); static cl::list AdditionalScalarTypes( - "types", cl::CommaSeparated, + "types", cl::CommaSeparated, cl::cat(StressCategory), + cl::sub(subopts::Generate), cl::desc("Additional IR scalar types " "(always includes i1, i8, i16, i32, i64, float and double)")); static cl::opt EnableScalableVectors( "enable-scalable-vectors", cl::desc("Generate IR involving scalable vector types"), - cl::init(false), cl::cat(StressCategory)); + cl::init(false), cl::cat(StressCategory), cl::sub(subopts::Generate)); namespace { @@ -730,24 +749,9 @@ } // end namespace llvm -int main(int argc, char **argv) { - using namespace llvm; - - InitLLVM X(argc, argv); - cl::HideUnrelatedOptions({&StressCategory, &getColorCategory()}); - cl::ParseCommandLineOptions(argc, argv, "llvm codegen stress-tester\n"); - - LLVMContext Context; - auto M = std::make_unique("/tmp/autogen.bc", Context); - Function *F = GenEmptyFunction(M.get()); - - // Pick an initial seed value - Random R(SeedCL); - // Generate lots of random instructions inside a single basic block. - FillFunction(F, R); - // Break the basic block into many loops. - IntroduceControlFlow(F, R); +using namespace llvm; +static int WriteModule(Module &M) { // Figure out what stream we are supposed to write to... std::unique_ptr Out; // Default to standard output. @@ -762,13 +766,79 @@ } // Check that the generated module is accepted by the verifier. - if (verifyModule(*M.get(), &Out->os())) + if (verifyModule(M, &Out->os())) report_fatal_error("Broken module found, compilation aborted!"); // Output textual IR. - M->print(Out->os(), nullptr); + M.print(Out->os(), nullptr); Out->keep(); - return 0; } + +static int Generate() { + LLVMContext Context; + auto M = std::make_unique("/tmp/autogen.bc", Context); + Function *F = GenEmptyFunction(M.get()); + + // Pick an initial seed value + Random R(SeedCL); + // Generate lots of random instructions inside a single basic block. + FillFunction(F, R); + // Break the basic block into many loops. + IntroduceControlFlow(F, R); + + return WriteModule(*M); +} + +static int GetBitcodeSizeInBytes(Module &M) { + std::string Buf; + raw_string_ostream OS(Buf); + WriteBitcodeToFile(M, OS); + return Buf.size(); +} + +static int Mutate() { + // TODO: Refactor to share this with Generate command, and generalize option + // to apply here too. + std::vector Types{ + Type::getInt1Ty, Type::getInt8Ty, Type::getInt16Ty, Type::getInt32Ty, + Type::getInt64Ty, Type::getFloatTy, Type::getDoubleTy}; + + std::vector> Strategies; + Strategies.emplace_back( + new InjectorIRStrategy(InjectorIRStrategy::getDefaultOps())); + Strategies.emplace_back(new InstDeleterIRStrategy()); + Strategies.emplace_back(new InstModificationIRStrategy()); + + std::unique_ptr Mutator = + std::make_unique(std::move(Types), std::move(Strategies)); + + LLVMContext Context; + SMDiagnostic SM; + std::unique_ptr M = parseIRFile("-", SM, Context); + + if (verifyModule(*M, &errs())) { + errs() << "Input module does not verify\n"; + return 1; + } + + // TODO: If the input was bitcode already, there is a really + // inefficient size check. + const int CurSize = GetBitcodeSizeInBytes(*M); + const int MaxSize = 1024; + Mutator->mutateModule(*M, SeedCL, CurSize, MaxSize); + + // Output textual IR. + return WriteModule(*M); +} + +int main(int argc, char **argv) { + InitLLVM X(argc, argv); + cl::HideUnrelatedOptions({&StressCategory, &getColorCategory()}); + cl::ParseCommandLineOptions(argc, argv, "llvm codegen stress-tester\n"); + + if (subopts::Mutate) + return Mutate(); + return Generate(); +}