message: use llvm optimization to decomplicate generated block iteration
diff: #include <llvm/IR/LegacyPassManager.h>
  #include <llvm/IR/Module.h>
  #include <llvm/Support/DynamicLibrary.h>
  +#include <llvm/Transforms/IPO/PassManagerBuilder.h>
  #include <algorithm>
  #include <deque>
  @@ -130,16 +131,31 @@ Compiler::Compiler() : context_(llvm::getGlobalContext()), builder_{context_} {
  }
  std::unique_ptr<Executable> Compiler::CompileProgram(const stripe::Block& program) {
  - // std::cerr << "Compiler::CompileProgram:" << std::endl;
  - // std::cerr << program << std::endl << "----------------" << std::endl;
  + // Compile each block in this program into a function within a single LLVM module.
  module_ = new llvm::Module("stripe", context_);
  llvm::Function* main = CompileBlock(program);
  + // Generate a stub function we can invoke from the outside, passing the buffers in
  + // as an array of generic pointers.
  GenerateInvoker(program, main);
  + // Improve the simple-minded IR we've just generated by running module-level
  + // optimization passes; among many other things, this will streamline our loops
  + // to eliminate most of the branching and inline most of the block function calls.
  + llvm::PassManagerBuilder pmb;
  + pmb.OptLevel = 3;
  + pmb.SizeLevel = 0;
  + pmb.BBVectorize = true;
  + pmb.SLPVectorize = true;
  + pmb.LoopVectorize = true;
  + pmb.MergeFunctions = true;
  + llvm::legacy::PassManager modopt;
  + pmb.populateModulePassManager(modopt);
  + modopt.run(*module_);
  + // module_->print(llvm::errs(), nullptr);
  + // Wrap the finished module and the buffer names into an executable we can return.
  std::vector<std::string> param_names;
  for (auto& ref : program.refs) {
  param_names.push_back(ref.into);
  }
  - // module_->print(llvm::errs(), nullptr);
  std::unique_ptr<llvm::Module> xfermod(module_);
  module_ = nullptr;
  return std::make_unique<Executable>(std::move(xfermod), param_names);
  