From fdc309cc4e95778d7615f3829917c4fe42086e1e Mon Sep 17 00:00:00 2001 From: Nadav Rotem Date: Sun, 26 Feb 2012 08:35:53 +0000 Subject: Add a random .LL file generator to stress-test different llvm components. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@151479 91177308-0d34-0410-b5e6-96231b3b80d8 --- tools/llvm-stress/CMakeLists.txt | 5 + tools/llvm-stress/LLVMBuild.txt | 22 ++ tools/llvm-stress/Makefile | 18 ++ tools/llvm-stress/llvm-stress.cpp | 623 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 668 insertions(+) create mode 100644 tools/llvm-stress/CMakeLists.txt create mode 100644 tools/llvm-stress/LLVMBuild.txt create mode 100644 tools/llvm-stress/Makefile create mode 100644 tools/llvm-stress/llvm-stress.cpp (limited to 'tools/llvm-stress') diff --git a/tools/llvm-stress/CMakeLists.txt b/tools/llvm-stress/CMakeLists.txt new file mode 100644 index 00000000000..e2d07a5dda2 --- /dev/null +++ b/tools/llvm-stress/CMakeLists.txt @@ -0,0 +1,5 @@ +set(LLVM_LINK_COMPONENTS bitreader asmparser bitwriter instrumentation scalaropts ipo) + +add_llvm_tool(llvm-stress + llvm-stress.cpp + ) diff --git a/tools/llvm-stress/LLVMBuild.txt b/tools/llvm-stress/LLVMBuild.txt new file mode 100644 index 00000000000..f383d351dd3 --- /dev/null +++ b/tools/llvm-stress/LLVMBuild.txt @@ -0,0 +1,22 @@ +;===- ./tools/llvm-stress/LLVMBuild.txt -------------------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Tool +name = llvm-stress +parent = Tools +required_libraries = AsmParser BitReader BitWriter IPO Instrumentation Scalar diff --git a/tools/llvm-stress/Makefile b/tools/llvm-stress/Makefile new file mode 100644 index 00000000000..90d57c3fa98 --- /dev/null +++ b/tools/llvm-stress/Makefile @@ -0,0 +1,18 @@ +##===- tools/llvm-stress/Makefile --------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL := ../.. +TOOLNAME := llvm-stress +LINK_COMPONENTS := object +LINK_COMPONENTS := bitreader bitwriter asmparser instrumentation scalaropts ipo + +# This tool has no plugins, optimize startup time. +TOOL_NO_EXPORTS = 1 + +include $(LEVEL)/Makefile.common diff --git a/tools/llvm-stress/llvm-stress.cpp b/tools/llvm-stress/llvm-stress.cpp new file mode 100644 index 00000000000..e24e76679ac --- /dev/null +++ b/tools/llvm-stress/llvm-stress.cpp @@ -0,0 +1,623 @@ +//===-- llvm-stress.cpp - Print the size of each object section ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This program is a utility that generates random .ll files to stress-test +// different components in LLVM. +// +//===----------------------------------------------------------------------===// +#include "llvm/LLVMContext.h" +#include "llvm/Module.h" +#include "llvm/PassManager.h" +#include "llvm/Constants.h" +#include "llvm/Instruction.h" +#include "llvm/CallGraphSCCPass.h" +#include "llvm/Assembly/PrintModulePass.h" +#include "llvm/Analysis/Verifier.h" +#include "llvm/Support/PassNameParser.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/PluginLoader.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/ToolOutputFile.h" +#include +#include +#include +#include +#include +using namespace llvm; + +static cl::opt SeedCL("seed", + cl::desc("Seed used for randomness"), cl::init(0)); +static cl::opt SizeCL("size", + cl::desc("The estimated size of the generated function (# of instrs)"), + cl::init(100)); +static cl::opt +OutputFilename("o", cl::desc("Override output filename"), + cl::value_desc("filename")); + +/// A utility class to provide a pseudo-random number generator which is +/// the same across all platforms. This is somewhat close to the libc +/// implementation. Note: This is not a cryptographically secure pseudorandom +/// number generator. +class Random { +public: + /// C'tor + Random(unsigned _seed):Seed(_seed) {} + /// Return the next random value. + unsigned Rand() { + unsigned Val = Seed + 0x000b07a1; + Seed = (Val * 0x3c7c0ac1); + // Only lowest 19 bits are random-ish. + return Seed & 0x7ffff; + } + +private: + unsigned Seed; +}; + +/// Generate an empty function with a default argument list. +Function *GenEmptyFunction(Module *M) { + // Type Definitions + std::vector ArgsTy; + // Define a few arguments + LLVMContext &Context = M->getContext(); + ArgsTy.push_back(PointerType::get(IntegerType::getInt8Ty(Context), 0)); + ArgsTy.push_back(PointerType::get(IntegerType::getInt32Ty(Context), 0)); + ArgsTy.push_back(PointerType::get(IntegerType::getInt64Ty(Context), 0)); + ArgsTy.push_back(IntegerType::getInt32Ty(Context)); + ArgsTy.push_back(IntegerType::getInt64Ty(Context)); + ArgsTy.push_back(IntegerType::getInt8Ty(Context)); + + FunctionType *FuncTy = FunctionType::get(Type::getVoidTy(Context), ArgsTy, 0); + // Pick a unique name to describe the input parameters + std::stringstream ss; + ss<<"autogen_SD"<setCallingConv(CallingConv::C); + return Func; +} + +/// A base class, implementing utilities needed for +/// modifying and adding new random instructions. +struct Modifier { + /// Used to store the randomly generated values. + typedef std::vector PieceTable; + +public: + /// C'tor + Modifier(BasicBlock *_BB, PieceTable *PT, Random *R): + BB(_BB),PT(PT),Ran(R),Context(BB->getContext()) {}; + /// Add a new instruction. + virtual void Act() = 0; + /// Add N new instructions, + virtual void ActN(unsigned n) { + for (unsigned i=0; isize()); + return PT->at(Ran->Rand() % PT->size()); + } + + /// Return a random value with a known type. + Value *getRandomValue(Type *Tp) { + unsigned index = Ran->Rand(); + for (unsigned i=0; isize(); ++i) { + Value *V = PT->at((index + i) % PT->size()); + if (V->getType() == Tp) + return V; + } + + // If the requested type was not found, generate a constant value. + if (Tp->isIntegerTy()) { + if (Ran->Rand() & 1) + return ConstantInt::getAllOnesValue(Tp); + return ConstantInt::getNullValue(Tp); + } else if (Tp->isFloatingPointTy()) { + if (Ran->Rand() & 1) + return ConstantFP::getAllOnesValue(Tp); + return ConstantFP::getNullValue(Tp); + } + + // TODO: return values for vector types. + return UndefValue::get(Tp); + } + + /// Return a random value of any pointer type. + Value *getRandomPointerValue() { + unsigned index = Ran->Rand(); + for (unsigned i=0; isize(); ++i) { + Value *V = PT->at((index + i) % PT->size()); + if (V->getType()->isPointerTy()) + return V; + } + return UndefValue::get(pickPointerType()); + } + + /// Return a random value of any vector type. + Value *getRandomVectorValue() { + unsigned index = Ran->Rand(); + for (unsigned i=0; isize(); ++i) { + Value *V = PT->at((index + i) % PT->size()); + if (V->getType()->isVectorTy()) + return V; + } + return UndefValue::get(pickVectorType()); + } + + /// Pick a random type. + Type *pickType() { + return (Ran->Rand() & 1 ? pickVectorType() : pickScalarType()); + } + + /// Pick a random pointer type. + Type *pickPointerType() { + Type *Ty = pickType(); + return PointerType::get(Ty, 0); + } + + /// Pick a random vector type. + Type *pickVectorType(unsigned len = (unsigned)-1) { + Type *Ty = pickScalarType(); + // Pick a random vector width in the range 2**0 to 2**4. + // by adding two randoms we are generating a normal-like distribution + // around 2**3. + unsigned width = 1<<((Ran->Rand() % 3) + (Ran->Rand() % 3)); + if (len != (unsigned)-1) + width = len; + return VectorType::get(Ty, width); + } + + /// Pick a random scalar type. + Type *pickScalarType() { + switch (Ran->Rand() % 15) { + case 0: return Type::getInt1Ty(Context); + case 1: return Type::getInt8Ty(Context); + case 2: return Type::getInt16Ty(Context); + case 3: case 4: + case 5: return Type::getFloatTy(Context); + case 6: case 7: + case 8: return Type::getDoubleTy(Context); + case 9: case 10: + case 11: return Type::getInt32Ty(Context); + case 12: case 13: + case 14: return Type::getInt64Ty(Context); + } + llvm_unreachable("Invalid scalar value"); + } + + /// Basic block to populate + BasicBlock *BB; + /// Value table + PieceTable *PT; + /// Random number generator + Random *Ran; + /// Context + LLVMContext &Context; +}; + +struct LoadModifier: public Modifier { + LoadModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R) {}; + virtual void Act() { + // Try to use predefined pointers. If non exist, use undef pointer value; + Value *Ptr = getRandomPointerValue(); + Value *V = new LoadInst(Ptr, "L", BB->getTerminator()); + PT->push_back(V); + } +}; + +struct StoreModifier: public Modifier { + StoreModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R) {} + virtual void Act() { + // Try to use predefined pointers. If non exist, use undef pointer value; + Value *Ptr = getRandomPointerValue(); + Type *Tp = Ptr->getType(); + Value *Val = getRandomValue(Tp->getContainedType(0)); + + // Do not store vectors of i1s because they are unsupported + //by the codegen. + if (Tp->isVectorTy() && Tp->getScalarSizeInBits() == 1) + return; + + new StoreInst(Val, Ptr, BB->getTerminator()); + } +}; + +struct BinModifier: public Modifier { + BinModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R) {} + + virtual void Act() { + Value *Val0 = getRandomVal(); + Value *Val1 = getRandomValue(Val0->getType()); + + // Don't handle pointer types. + if (Val0->getType()->isPointerTy() || + Val1->getType()->isPointerTy()) + return; + + // Don't handle i1 types. + if (Val0->getType()->getScalarSizeInBits() == 1) + return; + + + bool isFloat = Val0->getType()->getScalarType()->isFloatingPointTy(); + Instruction* Term = BB->getTerminator(); + unsigned R = Ran->Rand() % (isFloat ? 7 : 13); + Instruction::BinaryOps Op; + + switch (R) { + default: llvm_unreachable("Invalid BinOp"); + case 0:{Op = (isFloat?Instruction::FAdd : Instruction::Add); break; } + case 1:{Op = (isFloat?Instruction::FSub : Instruction::Sub); break; } + case 2:{Op = (isFloat?Instruction::FMul : Instruction::Mul); break; } + case 3:{Op = (isFloat?Instruction::FDiv : Instruction::SDiv); break; } + case 4:{Op = (isFloat?Instruction::FDiv : Instruction::UDiv); break; } + case 5:{Op = (isFloat?Instruction::FRem : Instruction::SRem); break; } + case 6:{Op = (isFloat?Instruction::FRem : Instruction::URem); break; } + case 7: {Op = Instruction::Shl; break; } + case 8: {Op = Instruction::LShr; break; } + case 9: {Op = Instruction::AShr; break; } + case 10:{Op = Instruction::And; break; } + case 11:{Op = Instruction::Or; break; } + case 12:{Op = Instruction::Xor; break; } + } + + PT->push_back(BinaryOperator::Create(Op, Val0, Val1, "B", Term)); + } +}; + +/// Generate constant values. +struct ConstModifier: public Modifier { + ConstModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R) {} + virtual void Act() { + Type *Ty = pickType(); + + if (Ty->isVectorTy()) { + switch (Ran->Rand() % 2) { + case 0: if (Ty->getScalarType()->isIntegerTy()) + return PT->push_back(ConstantVector::getAllOnesValue(Ty)); + case 1: if (Ty->getScalarType()->isIntegerTy()) + return PT->push_back(ConstantVector::getNullValue(Ty)); + } + } + + if (Ty->isFloatingPointTy()) { + if (Ran->Rand() & 1) + return PT->push_back(ConstantFP::getNullValue(Ty)); + return PT->push_back(ConstantFP::get(Ty, + static_cast(1)/Ran->Rand())); + } + + if (Ty->isIntegerTy()) { + switch (Ran->Rand() % 7) { + case 0: if (Ty->isIntegerTy()) + return PT->push_back(ConstantInt::get(Ty, + APInt::getAllOnesValue(Ty->getPrimitiveSizeInBits()))); + case 1: if (Ty->isIntegerTy()) + return PT->push_back(ConstantInt::get(Ty, + APInt::getNullValue(Ty->getPrimitiveSizeInBits()))); + case 2: case 3: case 4: case 5: + case 6: if (Ty->isIntegerTy()) + PT->push_back(ConstantInt::get(Ty, Ran->Rand())); + } + } + + } +}; + +struct AllocaModifier: public Modifier { + AllocaModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R){} + + virtual void Act() { + Type *Tp = pickType(); + PT->push_back(new AllocaInst(Tp, "A", BB->getFirstNonPHI())); + } +}; + +struct ExtractElementModifier: public Modifier { + ExtractElementModifier(BasicBlock *BB, PieceTable *PT, Random *R): + Modifier(BB, PT, R) {} + + virtual void Act() { + Value *Val0 = getRandomVectorValue(); + Value *V = ExtractElementInst::Create(Val0, + ConstantInt::get(Type::getInt32Ty(BB->getContext()), + Ran->Rand() % cast(Val0->getType())->getNumElements()), + "E", BB->getTerminator()); + return PT->push_back(V); + } +}; + +struct ShuffModifier: public Modifier { + ShuffModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R) {} + virtual void Act() { + + Value *Val0 = getRandomVectorValue(); + Value *Val1 = getRandomValue(Val0->getType()); + + unsigned Width = cast(Val0->getType())->getNumElements(); + std::vector Idxs; + + Type *I32 = Type::getInt32Ty(BB->getContext()); + for (unsigned i=0; iRand() % (Width*2)); + // Pick some undef values. + if (!(Ran->Rand() % 5)) + CI = UndefValue::get(I32); + Idxs.push_back(CI); + } + + Constant *Mask = ConstantVector::get(Idxs); + + Value *V = new ShuffleVectorInst(Val0, Val1, Mask, "Shuff", + BB->getTerminator()); + PT->push_back(V); + } +}; + +struct InsertElementModifier: public Modifier { + InsertElementModifier(BasicBlock *BB, PieceTable *PT, Random *R): + Modifier(BB, PT, R) {} + + virtual void Act() { + Value *Val0 = getRandomVectorValue(); + Value *Val1 = getRandomValue(Val0->getType()->getScalarType()); + + Value *V = InsertElementInst::Create(Val0, Val1, + ConstantInt::get(Type::getInt32Ty(BB->getContext()), + Ran->Rand() % cast(Val0->getType())->getNumElements()), + "I", BB->getTerminator()); + return PT->push_back(V); + } + +}; + +struct CastModifier: public Modifier { + CastModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R) {} + virtual void Act() { + + Value *V = getRandomVal(); + Type *VTy = V->getType(); + Type *DestTy = pickScalarType(); + + // Handle vector casts vectors. + if (VTy->isVectorTy()) { + VectorType *VecTy = cast(VTy); + DestTy = pickVectorType(VecTy->getNumElements()); + } + + // no need to casr. + if (VTy == DestTy) return; + + // Pointers: + if (VTy->isPointerTy()) { + if (!DestTy->isPointerTy()) + DestTy = PointerType::get(DestTy, 0); + return PT->push_back( + new BitCastInst(V, DestTy, "PC", BB->getTerminator())); + } + + // Generate lots of bitcasts. + if ((Ran->Rand() & 1) && + VTy->getPrimitiveSizeInBits() == DestTy->getPrimitiveSizeInBits()) { + return PT->push_back( + new BitCastInst(V, DestTy, "BC", BB->getTerminator())); + } + + // Both types are integers: + if (VTy->getScalarType()->isIntegerTy() && + DestTy->getScalarType()->isIntegerTy()) { + if (VTy->getScalarType()->getPrimitiveSizeInBits() > + DestTy->getScalarType()->getPrimitiveSizeInBits()) { + return PT->push_back( + new TruncInst(V, DestTy, "Tr", BB->getTerminator())); + } else { + if (Ran->Rand() & 1) + return PT->push_back( + new ZExtInst(V, DestTy, "ZE", BB->getTerminator())); + return PT->push_back(new SExtInst(V, DestTy, "Se", BB->getTerminator())); + } + } + + // Fp to int. + if (VTy->getScalarType()->isFloatingPointTy() && + DestTy->getScalarType()->isIntegerTy()) { + if (Ran->Rand() & 1) + return PT->push_back( + new FPToSIInst(V, DestTy, "FC", BB->getTerminator())); + return PT->push_back(new FPToUIInst(V, DestTy, "FC", BB->getTerminator())); + } + + // Int to fp. + if (VTy->getScalarType()->isIntegerTy() && + DestTy->getScalarType()->isFloatingPointTy()) { + if (Ran->Rand() & 1) + return PT->push_back( + new SIToFPInst(V, DestTy, "FC", BB->getTerminator())); + return PT->push_back(new UIToFPInst(V, DestTy, "FC", BB->getTerminator())); + + } + + // Both floats. + if (VTy->getScalarType()->isFloatingPointTy() && + DestTy->getScalarType()->isFloatingPointTy()) { + if (VTy->getScalarType()->getPrimitiveSizeInBits() > + DestTy->getScalarType()->getPrimitiveSizeInBits()) { + return PT->push_back( + new FPTruncInst(V, DestTy, "Tr", BB->getTerminator())); + } else { + return PT->push_back( + new FPExtInst(V, DestTy, "ZE", BB->getTerminator())); + } + } + } + +}; + +struct SelectModifier: public Modifier { + SelectModifier(BasicBlock *BB, PieceTable *PT, Random *R): + Modifier(BB, PT, R) {} + + virtual void Act() { + // Try a bunch of different select configuration until a valid one is found. + Value *Val0 = getRandomVal(); + Value *Val1 = getRandomValue(Val0->getType()); + + Type *CondTy = Type::getInt1Ty(Context); + + // If the value type is a vector, and we allow vector select, then in 50% + // of the cases generate a vector select. + if (Val0->getType()->isVectorTy() && (Ran->Rand() % 1)) { + unsigned NumElem = cast(Val0->getType())->getNumElements(); + CondTy = VectorType::get(CondTy, NumElem); + } + + Value *Cond = getRandomValue(CondTy); + Value *V = SelectInst::Create(Cond, Val0, Val1, "Sl", BB->getTerminator()); + return PT->push_back(V); + } +}; + + +struct CmpModifier: public Modifier { + CmpModifier(BasicBlock *BB, PieceTable *PT, Random *R):Modifier(BB, PT, R) {} + virtual void Act() { + + Value *Val0 = getRandomVal(); + Value *Val1 = getRandomValue(Val0->getType()); + + if (Val0->getType()->isPointerTy()) return; + bool fp = Val0->getType()->getScalarType()->isFloatingPointTy(); + + int op; + if (fp) { + op = Ran->Rand() % + (CmpInst::LAST_FCMP_PREDICATE - CmpInst::FIRST_FCMP_PREDICATE) + + CmpInst::FIRST_FCMP_PREDICATE; + } else { + op = Ran->Rand() % + (CmpInst::LAST_ICMP_PREDICATE - CmpInst::FIRST_ICMP_PREDICATE) + + CmpInst::FIRST_ICMP_PREDICATE; + } + + Value *V = CmpInst::Create(fp ? Instruction::FCmp : Instruction::ICmp, + op, Val0, Val1, "Cmp", BB->getTerminator()); + return PT->push_back(V); + } +}; + +void FillFunction(Function *F) { + // Create a legal entry block. + BasicBlock *BB = BasicBlock::Create(F->getContext(), "BB", F); + ReturnInst::Create(F->getContext(), BB); + + // Create the value table. + Modifier::PieceTable PT; + // Pick an initial seed value + Random R(SeedCL); + + // Consider arguments as legal values. + for (Function::arg_iterator it = F->arg_begin(), e = F->arg_end(); + it != e; ++it) + PT.push_back(it); + + // List of modifiers which add new random instructions. + std::vector Modifiers; + std::auto_ptr LM(new LoadModifier(BB, &PT, &R)); + std::auto_ptr SM(new StoreModifier(BB, &PT, &R)); + std::auto_ptr EE(new ExtractElementModifier(BB, &PT, &R)); + std::auto_ptr SHM(new ShuffModifier(BB, &PT, &R)); + std::auto_ptr IE(new InsertElementModifier(BB, &PT, &R)); + std::auto_ptr BM(new BinModifier(BB, &PT, &R)); + std::auto_ptr CM(new CastModifier(BB, &PT, &R)); + std::auto_ptr SLM(new SelectModifier(BB, &PT, &R)); + std::auto_ptr PM(new CmpModifier(BB, &PT, &R)); + Modifiers.push_back(LM.get()); + Modifiers.push_back(SM.get()); + Modifiers.push_back(EE.get()); + Modifiers.push_back(SHM.get()); + Modifiers.push_back(IE.get()); + Modifiers.push_back(BM.get()); + Modifiers.push_back(CM.get()); + Modifiers.push_back(SLM.get()); + Modifiers.push_back(PM.get()); + + // Generate the random instructions + AllocaModifier AM(BB, &PT, &R); AM.ActN(5); // Throw in a few allocas + ConstModifier COM(BB, &PT, &R); COM.ActN(40); // Throw in a few constants + + for (unsigned i=0; i< SizeCL / Modifiers.size(); ++i) + for (std::vector::iterator it = Modifiers.begin(), + e = Modifiers.end(); it != e; ++it) { + (*it)->Act(); + } + + SM->ActN(5); // Throw in a few stores. +} + +void IntroduceControlFlow(Function *F) { + std::set BoolInst; + for (BasicBlock::iterator it = F->begin()->begin(), + e = F->begin()->end(); it != e; ++it) { + if (it->getType() == IntegerType::getInt1Ty(F->getContext())) + BoolInst.insert(it); + } + + for (std::set::iterator it = BoolInst.begin(), + e = BoolInst.end(); it != e; ++it) { + Instruction *Instr = *it; + BasicBlock *Curr = Instr->getParent(); + BasicBlock::iterator Loc= Instr; + BasicBlock *Next = Curr->splitBasicBlock(Loc, "CF"); + Instr->moveBefore(Curr->getTerminator()); + if (Curr != &F->getEntryBlock()) { + BranchInst::Create(Curr, Next, Instr, Curr->getTerminator()); + Curr->getTerminator()->eraseFromParent(); + } + } +} + +int main(int argc, char **argv) { + // Init LLVM, call llvm_shutdown() on exit, parse args, etc. + llvm::PrettyStackTraceProgram X(argc, argv); + cl::ParseCommandLineOptions(argc, argv, "llvm codegen stress-tester\n"); + llvm_shutdown_obj Y; + + std::auto_ptr M(new Module("/tmp/autogen.bc", getGlobalContext())); + Function *F = GenEmptyFunction(M.get()); + FillFunction(F); + IntroduceControlFlow(F); + + // Figure out what stream we are supposed to write to... + OwningPtr Out; + // Default to standard output. + if (OutputFilename.empty()) + OutputFilename = "-"; + + std::string ErrorInfo; + Out.reset(new tool_output_file(OutputFilename.c_str(), ErrorInfo, + raw_fd_ostream::F_Binary)); + if (!ErrorInfo.empty()) { + errs() << ErrorInfo << '\n'; + return 1; + } + + PassManager Passes; + Passes.add(createVerifierPass()); + Passes.add(createPrintModulePass(&Out->os())); + Passes.run(*M.get()); + Out->keep(); + + return 0; +} -- cgit v1.2.3