<commit_before>
#include "llvm/ADT/Triple.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/CodeGen/CommandFlags.h"
#include "llvm/CodeGen/LinkAllAsmWriterComponents.h"
#include "llvm/CodeGen/LinkAllCodegenComponents.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/Linker/Linker.h"
#include "llvm/MC/SubtargetFeature.h"
#include "llvm/PassManager.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetSubtargetInfo.h"
#include "llvm/Transforms/Scalar.h"

#include <memory>
#include <string>

#include "DynamicCallCounter.h"
#include "StaticCallCounter.h"

#include "config.h"

using namespace llvm;
using std::string;
using std::unique_ptr;
using std::vector;
using llvm::sys::ExecuteAndWait;
using llvm::sys::findProgramByName;

enum class AnalysisType {
  STATIC, DYNAMIC
};

namespace {

cl::opt<string>
inPath(cl::Positional,
       cl::desc("<Module to analyze>"),
       cl::value_desc("bitcode filename"),
       cl::init(""), cl::Required);

cl::opt<AnalysisType>
analysisType(cl::desc("Select analyis type:"),
  cl::values(
    clEnumValN(AnalysisType::STATIC,  "static",  "Count static direct calls."),
    clEnumValN(AnalysisType::DYNAMIC, "dynamic", "Count dynamic direct calls."),
  clEnumValEnd), cl::Required);

cl::opt<string>
outFile("o",
        cl::desc("Filename of the instrumented program"),
        cl::value_desc("filename"),
        cl::init(""));

static cl::opt<char>
optLevel("O",
        cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
                  "(default = '-O2')"),
        cl::Prefix,
        cl::ZeroOrMore,
        cl::init('2'));

cl::list<string>
libPaths("L", cl::Prefix,
          cl::desc("Specify a library search path"),
          cl::value_desc("directory"));

cl::list<string>
libraries("l", cl::Prefix,
          cl::desc("Specify libraries to link to"),
          cl::value_desc("library prefix"));

}

static void
compile(Module &m, string outputPath) {
  string err;

  Triple triple = Triple(m.getTargetTriple());
  Target const *target = TargetRegistry::lookupTarget(MArch, triple, err);
  if (!target) {
    report_fatal_error("Unable to find target:\n " + err);
  }

  CodeGenOpt::Level level = CodeGenOpt::Default;
  switch (optLevel) {
    default:
      report_fatal_error("Invalid optimization level.\n");
      // No fall through
    case '0': level = CodeGenOpt::None; break;
    case '1': level = CodeGenOpt::Less; break;
    case '2': level = CodeGenOpt::Default; break;
    case '3': level = CodeGenOpt::Aggressive; break;
  }

  string FeaturesStr;
  TargetOptions options = InitTargetOptionsFromCodeGenFlags();
  unique_ptr<TargetMachine>
    machine(target->createTargetMachine(triple.getTriple(),
                                        MCPU, FeaturesStr, options,
                                        RelocModel, CMModel, level));
  assert(machine.get() && "Could not allocate target machine!");

  if (FloatABIForCalls != FloatABI::Default) {
    options.FloatABIType = FloatABIForCalls;
  }

  std::error_code errc;
  auto out = std::make_unique<tool_output_file>(outputPath.c_str(),
                                                errc, sys::fs::F_None);
  if (!out) {
    report_fatal_error("Unable to create file:\n " + errc.message());
  }

  // Build up all of the passes that we want to do to the module.
  legacy::PassManager pm;

  // Add target specific info and transforms
  TargetLibraryInfoImpl tlii(Triple(m.getTargetTriple()));
  pm.add(new TargetLibraryInfoWrapperPass(tlii));

  m.setDataLayout(machine->createDataLayout());

  { // Bound this scope
    raw_pwrite_stream *os(&out->os());

    FileType = TargetMachine::CGFT_ObjectFile;
    std::unique_ptr<buffer_ostream> bos;
    if (!out->os().supportsSeeking()) {
      bos = std::make_unique<buffer_ostream>(*os);
      os = bos.get();
    }

    // Ask the target to add backend passes as necessary.
    if (machine->addPassesToEmitFile(pm, *os, FileType)) {
      report_fatal_error("target does not support generation "
                         "of this file type!\n");
    }

    // Before executing passes, print the final values of the LLVM options.
    cl::PrintOptionValues();

    pm.run(m);
  }

  // Keep the output binary if we've been successful to this point.
  out->keep();
}

static void
link(string const &objectFile, string const &outputFile) {
  auto clang = findProgramByName("clang++");
  string opt("-O");
  opt += optLevel;

  if (!clang) {
    report_fatal_error("Unable to find clang.");
  }
  vector<string> args{clang.get(), opt, "-o", outputFile, objectFile};

  for (auto &libPath : libPaths) {
    args.push_back("-L" + libPath);
  }

  for (auto &library : libraries) {
    args.push_back("-l" + library);
  }

  vector<char const *> charArgs;
  for (auto &arg : args) {
    charArgs.push_back(arg.c_str());
  }
  charArgs.push_back(nullptr);

  for (auto &arg : args) {
    outs() << arg.c_str() << " ";
  }
  outs() << "\n";

  string err;
  if (-1 == ExecuteAndWait(clang.get(), &charArgs[0],
                           nullptr, nullptr, 0, 0, &err)) {
    report_fatal_error("Unable to link output file.");
  }
}

static void
generateBinary(Module &m, string const &outputFilename) {
  // Compiling to native should allow things to keep working even when the
  // version of clang on the system and the version of LLVM used to compile
  // the tool don't quite match up.
  string objectFile = outputFilename + ".o";
  compile(m, objectFile);
  link(objectFile, outputFilename);
}

static void
saveModule(Module &m, StringRef const filename) {
  std::error_code errc;
  raw_fd_ostream out(filename.data(), errc, sys::fs::F_None);

  if (errc) {
    report_fatal_error("error saving llvm module to '" + filename + "': \n"
                       + errc.message());
  }
  WriteBitcodeToFile(&m, out);
}

static void
prepareLinkingPaths(SmallString<32> invocationPath) {
  // First search the directory of the binary for the library, in case it is
  // all bundled together.
  sys::path::remove_filename(invocationPath);
  if (!invocationPath.empty()) {
    libPaths.push_back(invocationPath.str());
  }
  // If the builder doesn't plan on installing it, we still need to get to the
  // runtime library somehow, so just build in the path to the temporary one.
#ifdef CMAKE_INSTALL_PREFIX
  libPaths.push_back(CMAKE_INSTALL_PREFIX "/lib");
#elif defined(CMAKE_TEMP_LIBRARY_PATH)
  libPaths.push_back(CMAKE_TEMP_LIBRARY_PATH);
#elif defined(TEMP_LIBRARY_PATH)
  // This is a bit of a hack
  libPaths.push_back(TEMP_LIBRARY_PATH "/Debug+Asserts/lib/");
  libPaths.push_back(TEMP_LIBRARY_PATH "/Release+Asserts/lib/");
  libPaths.push_back(TEMP_LIBRARY_PATH "/Debug/lib/");
  libPaths.push_back(TEMP_LIBRARY_PATH "/Release/lib/");
#endif
  libraries.push_back(RUNTIME_LIB);
  libraries.push_back("rt");
}

static void
instrumentForDynamicCount(Module &m) {
  InitializeAllTargets();
  InitializeAllTargetMCs();
  InitializeAllAsmPrinters();
  InitializeAllAsmParsers();
  cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);

  if (outFile.getValue() == "") {
    errs() << "-o command line option must be specified.\n";
    exit(-1);
  }

  // Build up all of the passes that we want to run on the module.
  PassManager pm;
  pm.add(new callcounter::DynamicCallCounter());
  pm.add(createVerifierPass());
  pm.run(m);

  generateBinary(m, outFile);
  saveModule(m, outFile + ".callcounter.bc");
}

struct StaticCountPrinter : public ModulePass {
  static char ID;
  raw_ostream &out;

  explicit StaticCountPrinter(raw_ostream &out)
      : ModulePass(ID),
        out(out)
        { }

  bool
  runOnModule(Module &m) override {
    getAnalysis<callcounter::StaticCallCounter>().print(out, &m);
    return false;
  }

  void
  getAnalysisUsage(AnalysisUsage &au) const override {
    au.addRequired<callcounter::StaticCallCounter>();
    au.setPreservesAll();
  }
};

char StaticCountPrinter::ID = 0;

static void
countStaticCalls(Module &m) {
  // Build up all of the passes that we want to run on the module.
  PassManager pm;
  pm.add(new callcounter::StaticCallCounter());
  pm.add(new StaticCountPrinter(outs()));
  pm.run(m);
}

int
main (int argc, char **argv) {
  // This boilerplate provides convenient stack traces and clean LLVM exit
  // handling. It also initializes the built in support for convenient
  // command line option handling.
  sys::PrintStackTraceOnErrorSignal();
  llvm::PrettyStackTraceProgram X(argc, argv);
  llvm_shutdown_obj shutdown;
  cl::ParseCommandLineOptions(argc, argv);

  // Construct an IR file from the filename passed on the command line.
  SMDiagnostic err;
  LLVMContext &context = getGlobalContext();
  unique_ptr<Module> module = parseIRFile(inPath.getValue(), err, context);

  if (!module.get()) {
    errs() << "Error reading bitcode file: " << inPath << "\n";
    err.print(argv[0], errs());
    return -1;
  }

  if (AnalysisType::DYNAMIC == analysisType) {
    prepareLinkingPaths(StringRef(argv[0]));
    instrumentForDynamicCount(*module);
  } else {
    countStaticCalls(*module);
  }

  return 0;
}

<commit_msg>Fix for pass manager header changes (which conflict with the debian package headers....)<commit_after>
#include "llvm/ADT/Triple.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/CodeGen/CommandFlags.h"
#include "llvm/CodeGen/LinkAllAsmWriterComponents.h"
#include "llvm/CodeGen/LinkAllCodegenComponents.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/Linker/Linker.h"
#include "llvm/MC/SubtargetFeature.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetSubtargetInfo.h"
#include "llvm/Transforms/Scalar.h"

#include <memory>
#include <string>

#include "DynamicCallCounter.h"
#include "StaticCallCounter.h"

#include "config.h"

using namespace llvm;
using std::string;
using std::unique_ptr;
using std::vector;
using llvm::sys::ExecuteAndWait;
using llvm::sys::findProgramByName;
using llvm::legacy::PassManager;

enum class AnalysisType {
  STATIC, DYNAMIC
};

namespace {

cl::opt<string>
inPath(cl::Positional,
       cl::desc("<Module to analyze>"),
       cl::value_desc("bitcode filename"),
       cl::init(""), cl::Required);

cl::opt<AnalysisType>
analysisType(cl::desc("Select analyis type:"),
  cl::values(
    clEnumValN(AnalysisType::STATIC,  "static",  "Count static direct calls."),
    clEnumValN(AnalysisType::DYNAMIC, "dynamic", "Count dynamic direct calls."),
  clEnumValEnd), cl::Required);

cl::opt<string>
outFile("o",
        cl::desc("Filename of the instrumented program"),
        cl::value_desc("filename"),
        cl::init(""));

static cl::opt<char>
optLevel("O",
        cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
                  "(default = '-O2')"),
        cl::Prefix,
        cl::ZeroOrMore,
        cl::init('2'));

cl::list<string>
libPaths("L", cl::Prefix,
          cl::desc("Specify a library search path"),
          cl::value_desc("directory"));

cl::list<string>
libraries("l", cl::Prefix,
          cl::desc("Specify libraries to link to"),
          cl::value_desc("library prefix"));

}

static void
compile(Module &m, string outputPath) {
  string err;

  Triple triple = Triple(m.getTargetTriple());
  Target const *target = TargetRegistry::lookupTarget(MArch, triple, err);
  if (!target) {
    report_fatal_error("Unable to find target:\n " + err);
  }

  CodeGenOpt::Level level = CodeGenOpt::Default;
  switch (optLevel) {
    default:
      report_fatal_error("Invalid optimization level.\n");
      // No fall through
    case '0': level = CodeGenOpt::None; break;
    case '1': level = CodeGenOpt::Less; break;
    case '2': level = CodeGenOpt::Default; break;
    case '3': level = CodeGenOpt::Aggressive; break;
  }

  string FeaturesStr;
  TargetOptions options = InitTargetOptionsFromCodeGenFlags();
  unique_ptr<TargetMachine>
    machine(target->createTargetMachine(triple.getTriple(),
                                        MCPU, FeaturesStr, options,
                                        RelocModel, CMModel, level));
  assert(machine.get() && "Could not allocate target machine!");

  if (FloatABIForCalls != FloatABI::Default) {
    options.FloatABIType = FloatABIForCalls;
  }

  std::error_code errc;
  auto out = std::make_unique<tool_output_file>(outputPath.c_str(),
                                                errc, sys::fs::F_None);
  if (!out) {
    report_fatal_error("Unable to create file:\n " + errc.message());
  }

  // Build up all of the passes that we want to do to the module.
  legacy::PassManager pm;

  // Add target specific info and transforms
  TargetLibraryInfoImpl tlii(Triple(m.getTargetTriple()));
  pm.add(new TargetLibraryInfoWrapperPass(tlii));

  m.setDataLayout(machine->createDataLayout());

  { // Bound this scope
    raw_pwrite_stream *os(&out->os());

    FileType = TargetMachine::CGFT_ObjectFile;
    std::unique_ptr<buffer_ostream> bos;
    if (!out->os().supportsSeeking()) {
      bos = std::make_unique<buffer_ostream>(*os);
      os = bos.get();
    }

    // Ask the target to add backend passes as necessary.
    if (machine->addPassesToEmitFile(pm, *os, FileType)) {
      report_fatal_error("target does not support generation "
                         "of this file type!\n");
    }

    // Before executing passes, print the final values of the LLVM options.
    cl::PrintOptionValues();

    pm.run(m);
  }

  // Keep the output binary if we've been successful to this point.
  out->keep();
}

static void
link(string const &objectFile, string const &outputFile) {
  auto clang = findProgramByName("clang++");
  string opt("-O");
  opt += optLevel;

  if (!clang) {
    report_fatal_error("Unable to find clang.");
  }
  vector<string> args{clang.get(), opt, "-o", outputFile, objectFile};

  for (auto &libPath : libPaths) {
    args.push_back("-L" + libPath);
  }

  for (auto &library : libraries) {
    args.push_back("-l" + library);
  }

  vector<char const *> charArgs;
  for (auto &arg : args) {
    charArgs.push_back(arg.c_str());
  }
  charArgs.push_back(nullptr);

  for (auto &arg : args) {
    outs() << arg.c_str() << " ";
  }
  outs() << "\n";

  string err;
  if (-1 == ExecuteAndWait(clang.get(), &charArgs[0],
                           nullptr, nullptr, 0, 0, &err)) {
    report_fatal_error("Unable to link output file.");
  }
}

static void
generateBinary(Module &m, string const &outputFilename) {
  // Compiling to native should allow things to keep working even when the
  // version of clang on the system and the version of LLVM used to compile
  // the tool don't quite match up.
  string objectFile = outputFilename + ".o";
  compile(m, objectFile);
  link(objectFile, outputFilename);
}

static void
saveModule(Module &m, StringRef const filename) {
  std::error_code errc;
  raw_fd_ostream out(filename.data(), errc, sys::fs::F_None);

  if (errc) {
    report_fatal_error("error saving llvm module to '" + filename + "': \n"
                       + errc.message());
  }
  WriteBitcodeToFile(&m, out);
}

static void
prepareLinkingPaths(SmallString<32> invocationPath) {
  // First search the directory of the binary for the library, in case it is
  // all bundled together.
  sys::path::remove_filename(invocationPath);
  if (!invocationPath.empty()) {
    libPaths.push_back(invocationPath.str());
  }
  // If the builder doesn't plan on installing it, we still need to get to the
  // runtime library somehow, so just build in the path to the temporary one.
#ifdef CMAKE_INSTALL_PREFIX
  libPaths.push_back(CMAKE_INSTALL_PREFIX "/lib");
#elif defined(CMAKE_TEMP_LIBRARY_PATH)
  libPaths.push_back(CMAKE_TEMP_LIBRARY_PATH);
#elif defined(TEMP_LIBRARY_PATH)
  // This is a bit of a hack
  libPaths.push_back(TEMP_LIBRARY_PATH "/Debug+Asserts/lib/");
  libPaths.push_back(TEMP_LIBRARY_PATH "/Release+Asserts/lib/");
  libPaths.push_back(TEMP_LIBRARY_PATH "/Debug/lib/");
  libPaths.push_back(TEMP_LIBRARY_PATH "/Release/lib/");
#endif
  libraries.push_back(RUNTIME_LIB);
  libraries.push_back("rt");
}

static void
instrumentForDynamicCount(Module &m) {
  InitializeAllTargets();
  InitializeAllTargetMCs();
  InitializeAllAsmPrinters();
  InitializeAllAsmParsers();
  cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);

  if (outFile.getValue() == "") {
    errs() << "-o command line option must be specified.\n";
    exit(-1);
  }

  // Build up all of the passes that we want to run on the module.
  PassManager pm;
  pm.add(new callcounter::DynamicCallCounter());
  pm.add(createVerifierPass());
  pm.run(m);

  generateBinary(m, outFile);
  saveModule(m, outFile + ".callcounter.bc");
}

struct StaticCountPrinter : public ModulePass {
  static char ID;
  raw_ostream &out;

  explicit StaticCountPrinter(raw_ostream &out)
      : ModulePass(ID),
        out(out)
        { }

  bool
  runOnModule(Module &m) override {
    getAnalysis<callcounter::StaticCallCounter>().print(out, &m);
    return false;
  }

  void
  getAnalysisUsage(AnalysisUsage &au) const override {
    au.addRequired<callcounter::StaticCallCounter>();
    au.setPreservesAll();
  }
};

char StaticCountPrinter::ID = 0;

static void
countStaticCalls(Module &m) {
  // Build up all of the passes that we want to run on the module.
  PassManager pm;
  pm.add(new callcounter::StaticCallCounter());
  pm.add(new StaticCountPrinter(outs()));
  pm.run(m);
}

int
main (int argc, char **argv) {
  // This boilerplate provides convenient stack traces and clean LLVM exit
  // handling. It also initializes the built in support for convenient
  // command line option handling.
  sys::PrintStackTraceOnErrorSignal();
  llvm::PrettyStackTraceProgram X(argc, argv);
  llvm_shutdown_obj shutdown;
  cl::ParseCommandLineOptions(argc, argv);

  // Construct an IR file from the filename passed on the command line.
  SMDiagnostic err;
  LLVMContext &context = getGlobalContext();
  unique_ptr<Module> module = parseIRFile(inPath.getValue(), err, context);

  if (!module.get()) {
    errs() << "Error reading bitcode file: " << inPath << "\n";
    err.print(argv[0], errs());
    return -1;
  }

  if (AnalysisType::DYNAMIC == analysisType) {
    prepareLinkingPaths(StringRef(argv[0]));
    instrumentForDynamicCount(*module);
  } else {
    countStaticCalls(*module);
  }

  return 0;
}

<|endoftext|>


<commit_before>//===--- Backend.cpp - Interface to LLVM backend technologies -------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "ASTConsumers.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Frontend/CompileOptions.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/DeclGroup.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/Module.h"
#include "llvm/ModuleProvider.h"
#include "llvm/PassManager.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/CodeGen/RegAllocRegistry.h"
#include "llvm/CodeGen/SchedulerRegistry.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Timer.h"
#include "llvm/System/Path.h"
#include "llvm/System/Program.h"
#include "llvm/Target/SubtargetFeature.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetMachineRegistry.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/IPO.h"
using namespace clang;
using namespace llvm;

namespace {
  class VISIBILITY_HIDDEN BackendConsumer : public ASTConsumer {
    BackendAction Action;
    CompileOptions CompileOpts;
    const std::string &InputFile;
    std::string OutputFile;
    ASTContext *Context;

    Timer LLVMIRGeneration;
    Timer CodeGenerationTime;

    llvm::OwningPtr<CodeGenerator> Gen;

    llvm::Module *TheModule;
    llvm::TargetData *TheTargetData;
    llvm::raw_ostream *AsmOutStream;

    mutable llvm::ModuleProvider *ModuleProvider;
    mutable FunctionPassManager *CodeGenPasses;
    mutable PassManager *PerModulePasses;
    mutable FunctionPassManager *PerFunctionPasses;

    FunctionPassManager *getCodeGenPasses() const;
    PassManager *getPerModulePasses() const;
    FunctionPassManager *getPerFunctionPasses() const;

    void CreatePasses();

    /// AddEmitPasses - Add passes necessary to emit assembly or LLVM
    /// IR.
    ///
    /// \return True on success. On failure \arg Error will be set to
    /// a user readable error message.
    bool AddEmitPasses(std::string &Error);

    void EmitAssembly();

  public:
    BackendConsumer(BackendAction action, Diagnostic &Diags,
                    const LangOptions &langopts, const CompileOptions &compopts,
                    const std::string &infile, const std::string &outfile) :
      Action(action),
      CompileOpts(compopts),
      InputFile(infile),
      OutputFile(outfile),
      LLVMIRGeneration("LLVM IR Generation Time"),
      CodeGenerationTime("Code Generation Time"),
      Gen(CreateLLVMCodeGen(Diags, InputFile, compopts)),
      TheModule(0), TheTargetData(0), AsmOutStream(0), ModuleProvider(0),
      CodeGenPasses(0), PerModulePasses(0), PerFunctionPasses(0) {

      // Enable -time-passes if -ftime-report is enabled.
      llvm::TimePassesIsEnabled = CompileOpts.TimePasses;
    }

    ~BackendConsumer() {
      delete AsmOutStream;
      delete TheTargetData;
      delete ModuleProvider;
      delete CodeGenPasses;
      delete PerModulePasses;
      delete PerFunctionPasses;
    }

    virtual void Initialize(ASTContext &Ctx) {
      Context = &Ctx;

      if (CompileOpts.TimePasses)
        LLVMIRGeneration.startTimer();

      Gen->Initialize(Ctx);

      TheModule = Gen->GetModule();
      ModuleProvider = new ExistingModuleProvider(TheModule);
      TheTargetData = new llvm::TargetData(Ctx.Target.getTargetDescription());

      if (CompileOpts.TimePasses)
        LLVMIRGeneration.stopTimer();
    }

    virtual void HandleTopLevelDecl(DeclGroupRef D) {
      PrettyStackTraceDecl CrashInfo(*D.begin(), SourceLocation(),
                                     Context->getSourceManager(),
                                     "LLVM IR generation of declaration");

      if (CompileOpts.TimePasses)
        LLVMIRGeneration.startTimer();

      Gen->HandleTopLevelDecl(D);

      if (CompileOpts.TimePasses)
        LLVMIRGeneration.stopTimer();
    }

    virtual void HandleTranslationUnit(ASTContext &C) {
      {
        PrettyStackTraceString CrashInfo("Per-file LLVM IR generation");
        if (CompileOpts.TimePasses)
          LLVMIRGeneration.startTimer();

        Gen->HandleTranslationUnit(C);

        if (CompileOpts.TimePasses)
          LLVMIRGeneration.stopTimer();
      }

      // EmitAssembly times and registers crash info itself.
      EmitAssembly();

      // Force a flush here in case we never get released.
      if (AsmOutStream)
        AsmOutStream->flush();
    }

    virtual void HandleTagDeclDefinition(TagDecl *D) {
      PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
                                     Context->getSourceManager(),
                                     "LLVM IR generation of declaration");
      Gen->HandleTagDeclDefinition(D);
    }
  };
}

FunctionPassManager *BackendConsumer::getCodeGenPasses() const {
  if (!CodeGenPasses) {
    CodeGenPasses = new FunctionPassManager(ModuleProvider);
    CodeGenPasses->add(new TargetData(*TheTargetData));
  }

  return CodeGenPasses;
}

PassManager *BackendConsumer::getPerModulePasses() const {
  if (!PerModulePasses) {
    PerModulePasses = new PassManager();
    PerModulePasses->add(new TargetData(*TheTargetData));
  }

  return PerModulePasses;
}

FunctionPassManager *BackendConsumer::getPerFunctionPasses() const {
  if (!PerFunctionPasses) {
    PerFunctionPasses = new FunctionPassManager(ModuleProvider);
    PerFunctionPasses->add(new TargetData(*TheTargetData));
  }

  return PerFunctionPasses;
}

bool BackendConsumer::AddEmitPasses(std::string &Error) {
  if (Action == Backend_EmitNothing)
    return true;

  if (OutputFile == "-" || (InputFile == "-" && OutputFile.empty())) {
    AsmOutStream = new raw_stdout_ostream();
    sys::Program::ChangeStdoutToBinary();
  } else {
    if (OutputFile.empty()) {
      llvm::sys::Path Path(InputFile);
      Path.eraseSuffix();
      if (Action == Backend_EmitBC) {
        Path.appendSuffix("bc");
      } else if (Action == Backend_EmitLL) {
        Path.appendSuffix("ll");
      } else {
        Path.appendSuffix("s");
      }
      OutputFile = Path.toString();
    }

    AsmOutStream = new raw_fd_ostream(OutputFile.c_str(), true, Error);
    if (!Error.empty())
      return false;
  }

  if (Action == Backend_EmitBC) {
    getPerModulePasses()->add(createBitcodeWriterPass(*AsmOutStream));
  } else if (Action == Backend_EmitLL) {
    getPerModulePasses()->add(createPrintModulePass(AsmOutStream));
  } else {
    bool Fast = CompileOpts.OptimizationLevel == 0;

    // Create the TargetMachine for generating code.
    const TargetMachineRegistry::entry *TME =
      TargetMachineRegistry::getClosestStaticTargetForModule(*TheModule, Error);
    if (!TME) {
      Error = std::string("Unable to get target machine: ") + Error;
      return false;
    }

    std::string FeaturesStr;
    if (CompileOpts.CPU.size() || CompileOpts.Features.size()) {
      SubtargetFeatures Features;
      Features.setCPU(CompileOpts.CPU);
      for (std::vector<std::string>::iterator
             it = CompileOpts.Features.begin(),
             ie = CompileOpts.Features.end(); it != ie; ++it)
        Features.AddFeature(*it);
      FeaturesStr = Features.getString();
    }
    TargetMachine *TM = TME->CtorFn(*TheModule, FeaturesStr);

    // Set register scheduler & allocation policy.
    RegisterScheduler::setDefault(createDefaultScheduler);
    RegisterRegAlloc::setDefault(Fast ? createLocalRegisterAllocator :
                                 createLinearScanRegisterAllocator);

    // From llvm-gcc:
    // If there are passes we have to run on the entire module, we do codegen
    // as a separate "pass" after that happens.
    // FIXME: This is disabled right now until bugs can be worked out.  Reenable
    // this for fast -O0 compiles!
    FunctionPassManager *PM = getCodeGenPasses();

    // Normal mode, emit a .s file by running the code generator.
    // Note, this also adds codegenerator level optimization passes.
    switch (TM->addPassesToEmitFile(*PM, *AsmOutStream,
                                    TargetMachine::AssemblyFile, Fast)) {
    default:
    case FileModel::Error:
      Error = "Unable to interface with target machine!\n";
      return false;
    case FileModel::AsmFile:
      break;
    }

    if (TM->addPassesToEmitFileFinish(*CodeGenPasses, 0, Fast)) {
      Error = "Unable to interface with target machine!\n";
      return false;
    }
  }

  return true;
}

void BackendConsumer::CreatePasses() {
  // In -O0 if checking is disabled, we don't even have per-function passes.
  if (CompileOpts.VerifyModule)
    getPerFunctionPasses()->add(createVerifierPass());

  if (CompileOpts.OptimizationLevel > 0) {
    FunctionPassManager *PM = getPerFunctionPasses();
    PM->add(createCFGSimplificationPass());
    if (CompileOpts.OptimizationLevel == 1)
      PM->add(createPromoteMemoryToRegisterPass());
    else
      PM->add(createScalarReplAggregatesPass());
    PM->add(createInstructionCombiningPass());
  }

  // For now we always create per module passes.
  PassManager *PM = getPerModulePasses();
  if (CompileOpts.OptimizationLevel > 0) {
    if (CompileOpts.UnitAtATime)
      PM->add(createRaiseAllocationsPass());      // call %malloc -> malloc inst
    PM->add(createCFGSimplificationPass());       // Clean up disgusting code
    PM->add(createPromoteMemoryToRegisterPass()); // Kill useless allocas
    if (CompileOpts.UnitAtATime) {
      PM->add(createGlobalOptimizerPass());       // Optimize out global vars
      PM->add(createGlobalDCEPass());             // Remove unused fns and globs
      PM->add(createIPConstantPropagationPass()); // IP Constant Propagation
      PM->add(createDeadArgEliminationPass());    // Dead argument elimination
    }
    PM->add(createInstructionCombiningPass());    // Clean up after IPCP & DAE
    PM->add(createCFGSimplificationPass());       // Clean up after IPCP & DAE
    if (CompileOpts.UnitAtATime) {
      PM->add(createPruneEHPass());               // Remove dead EH info
      PM->add(createFunctionAttrsPass());         // Set readonly/readnone attrs
    }
    if (CompileOpts.InlineFunctions)
      PM->add(createFunctionInliningPass());      // Inline small functions
    else
      PM->add(createAlwaysInlinerPass());         // Respect always_inline
    if (CompileOpts.OptimizationLevel > 2)
      PM->add(createArgumentPromotionPass());     // Scalarize uninlined fn args
    if (CompileOpts.SimplifyLibCalls)
      PM->add(createSimplifyLibCallsPass());      // Library Call Optimizations
    PM->add(createInstructionCombiningPass());    // Cleanup for scalarrepl.
    PM->add(createJumpThreadingPass());           // Thread jumps.
    PM->add(createCFGSimplificationPass());       // Merge & remove BBs
    PM->add(createScalarReplAggregatesPass());    // Break up aggregate allocas
    PM->add(createInstructionCombiningPass());    // Combine silly seq's
    PM->add(createCondPropagationPass());         // Propagate conditionals
    PM->add(createTailCallEliminationPass());     // Eliminate tail calls
    PM->add(createCFGSimplificationPass());       // Merge & remove BBs
    PM->add(createReassociatePass());             // Reassociate expressions
    PM->add(createLoopRotatePass());              // Rotate Loop
    PM->add(createLICMPass());                    // Hoist loop invariants
    PM->add(createLoopUnswitchPass(CompileOpts.OptimizeSize ? true : false));
//    PM->add(createLoopIndexSplitPass());          // Split loop index
    PM->add(createInstructionCombiningPass());
    PM->add(createIndVarSimplifyPass());          // Canonicalize indvars
    PM->add(createLoopDeletionPass());            // Delete dead loops
    if (CompileOpts.UnrollLoops)
      PM->add(createLoopUnrollPass());            // Unroll small loops
    PM->add(createInstructionCombiningPass());    // Clean up after the unroller
    PM->add(createGVNPass());                     // Remove redundancies
    PM->add(createMemCpyOptPass());               // Remove memcpy / form memset
    PM->add(createSCCPPass());                    // Constant prop with SCCP

    // Run instcombine after redundancy elimination to exploit opportunities
    // opened up by them.
    PM->add(createInstructionCombiningPass());
    PM->add(createCondPropagationPass());         // Propagate conditionals
    PM->add(createDeadStoreEliminationPass());    // Delete dead stores
    PM->add(createAggressiveDCEPass());           // Delete dead instructions
    PM->add(createCFGSimplificationPass());       // Merge & remove BBs

    if (CompileOpts.UnitAtATime) {
      PM->add(createStripDeadPrototypesPass());   // Get rid of dead prototypes
      PM->add(createDeadTypeEliminationPass());   // Eliminate dead types
    }

    if (CompileOpts.OptimizationLevel > 1 && CompileOpts.UnitAtATime)
      PM->add(createConstantMergePass());         // Merge dup global constants
  } else {
    PM->add(createAlwaysInlinerPass());
  }
}

/// EmitAssembly - Handle interaction with LLVM backend to generate
/// actual machine code.
void BackendConsumer::EmitAssembly() {
  // Silently ignore if we weren't initialized for some reason.
  if (!TheModule || !TheTargetData)
    return;

  TimeRegion Region(CompileOpts.TimePasses ? &CodeGenerationTime : 0);

  // Make sure IR generation is happy with the module. This is
  // released by the module provider.
  Module *M = Gen->ReleaseModule();
  if (!M) {
    // The module has been released by IR gen on failures, do not
    // double free.
    ModuleProvider->releaseModule();
    TheModule = 0;
    return;
  }

  assert(TheModule == M && "Unexpected module change during IR generation");

  CreatePasses();

  std::string Error;
  if (!AddEmitPasses(Error)) {
    // FIXME: Don't fail this way.
    llvm::cerr << "ERROR: " << Error << "\n";
    ::exit(1);
  }

  // Run passes. For now we do all passes at once, but eventually we
  // would like to have the option of streaming code generation.

  if (PerFunctionPasses) {
    PrettyStackTraceString CrashInfo("Per-function optimization");

    PerFunctionPasses->doInitialization();
    for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
      if (!I->isDeclaration())
        PerFunctionPasses->run(*I);
    PerFunctionPasses->doFinalization();
  }

  if (PerModulePasses) {
    PrettyStackTraceString CrashInfo("Per-module optimization passes");
    PerModulePasses->run(*M);
  }

  if (CodeGenPasses) {
    PrettyStackTraceString CrashInfo("Code generation");
    CodeGenPasses->doInitialization();
    for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
      if (!I->isDeclaration())
        CodeGenPasses->run(*I);
    CodeGenPasses->doFinalization();
  }
}

ASTConsumer *clang::CreateBackendConsumer(BackendAction Action,
                                          Diagnostic &Diags,
                                          const LangOptions &LangOpts,
                                          const CompileOptions &CompileOpts,
                                          const std::string& InFile,
                                          const std::string& OutFile) {
  // FIXME: If optimizing, disable all debug info generation.  The LLVM
  // optimizer and backend is not ready to handle it when optimizations
  // are enabled.
  if (CompileOpts.OptimizationLevel > 0)
    const_cast<CompileOptions&>(CompileOpts).DebugInfo = false;

  return new BackendConsumer(Action, Diags, LangOpts, CompileOpts,
                             InFile, OutFile);
}
<commit_msg>Reapply 68936, turned out to that clang's better debug info exposed a codegenerator bug.<commit_after>//===--- Backend.cpp - Interface to LLVM backend technologies -------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "ASTConsumers.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Frontend/CompileOptions.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/DeclGroup.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/Module.h"
#include "llvm/ModuleProvider.h"
#include "llvm/PassManager.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/CodeGen/RegAllocRegistry.h"
#include "llvm/CodeGen/SchedulerRegistry.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Timer.h"
#include "llvm/System/Path.h"
#include "llvm/System/Program.h"
#include "llvm/Target/SubtargetFeature.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetMachineRegistry.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/IPO.h"
using namespace clang;
using namespace llvm;

namespace {
  class VISIBILITY_HIDDEN BackendConsumer : public ASTConsumer {
    BackendAction Action;
    CompileOptions CompileOpts;
    const std::string &InputFile;
    std::string OutputFile;
    ASTContext *Context;

    Timer LLVMIRGeneration;
    Timer CodeGenerationTime;

    llvm::OwningPtr<CodeGenerator> Gen;

    llvm::Module *TheModule;
    llvm::TargetData *TheTargetData;
    llvm::raw_ostream *AsmOutStream;

    mutable llvm::ModuleProvider *ModuleProvider;
    mutable FunctionPassManager *CodeGenPasses;
    mutable PassManager *PerModulePasses;
    mutable FunctionPassManager *PerFunctionPasses;

    FunctionPassManager *getCodeGenPasses() const;
    PassManager *getPerModulePasses() const;
    FunctionPassManager *getPerFunctionPasses() const;

    void CreatePasses();

    /// AddEmitPasses - Add passes necessary to emit assembly or LLVM
    /// IR.
    ///
    /// \return True on success. On failure \arg Error will be set to
    /// a user readable error message.
    bool AddEmitPasses(std::string &Error);

    void EmitAssembly();

  public:
    BackendConsumer(BackendAction action, Diagnostic &Diags,
                    const LangOptions &langopts, const CompileOptions &compopts,
                    const std::string &infile, const std::string &outfile) :
      Action(action),
      CompileOpts(compopts),
      InputFile(infile),
      OutputFile(outfile),
      LLVMIRGeneration("LLVM IR Generation Time"),
      CodeGenerationTime("Code Generation Time"),
      Gen(CreateLLVMCodeGen(Diags, InputFile, compopts)),
      TheModule(0), TheTargetData(0), AsmOutStream(0), ModuleProvider(0),
      CodeGenPasses(0), PerModulePasses(0), PerFunctionPasses(0) {

      // Enable -time-passes if -ftime-report is enabled.
      llvm::TimePassesIsEnabled = CompileOpts.TimePasses;
    }

    ~BackendConsumer() {
      delete AsmOutStream;
      delete TheTargetData;
      delete ModuleProvider;
      delete CodeGenPasses;
      delete PerModulePasses;
      delete PerFunctionPasses;
    }

    virtual void Initialize(ASTContext &Ctx) {
      Context = &Ctx;

      if (CompileOpts.TimePasses)
        LLVMIRGeneration.startTimer();

      Gen->Initialize(Ctx);

      TheModule = Gen->GetModule();
      ModuleProvider = new ExistingModuleProvider(TheModule);
      TheTargetData = new llvm::TargetData(Ctx.Target.getTargetDescription());

      if (CompileOpts.TimePasses)
        LLVMIRGeneration.stopTimer();
    }

    virtual void HandleTopLevelDecl(DeclGroupRef D) {
      PrettyStackTraceDecl CrashInfo(*D.begin(), SourceLocation(),
                                     Context->getSourceManager(),
                                     "LLVM IR generation of declaration");

      if (CompileOpts.TimePasses)
        LLVMIRGeneration.startTimer();

      Gen->HandleTopLevelDecl(D);

      if (CompileOpts.TimePasses)
        LLVMIRGeneration.stopTimer();
    }

    virtual void HandleTranslationUnit(ASTContext &C) {
      {
        PrettyStackTraceString CrashInfo("Per-file LLVM IR generation");
        if (CompileOpts.TimePasses)
          LLVMIRGeneration.startTimer();

        Gen->HandleTranslationUnit(C);

        if (CompileOpts.TimePasses)
          LLVMIRGeneration.stopTimer();
      }

      // EmitAssembly times and registers crash info itself.
      EmitAssembly();

      // Force a flush here in case we never get released.
      if (AsmOutStream)
        AsmOutStream->flush();
    }

    virtual void HandleTagDeclDefinition(TagDecl *D) {
      PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
                                     Context->getSourceManager(),
                                     "LLVM IR generation of declaration");
      Gen->HandleTagDeclDefinition(D);
    }
  };
}

FunctionPassManager *BackendConsumer::getCodeGenPasses() const {
  if (!CodeGenPasses) {
    CodeGenPasses = new FunctionPassManager(ModuleProvider);
    CodeGenPasses->add(new TargetData(*TheTargetData));
  }

  return CodeGenPasses;
}

PassManager *BackendConsumer::getPerModulePasses() const {
  if (!PerModulePasses) {
    PerModulePasses = new PassManager();
    PerModulePasses->add(new TargetData(*TheTargetData));
  }

  return PerModulePasses;
}

FunctionPassManager *BackendConsumer::getPerFunctionPasses() const {
  if (!PerFunctionPasses) {
    PerFunctionPasses = new FunctionPassManager(ModuleProvider);
    PerFunctionPasses->add(new TargetData(*TheTargetData));
  }

  return PerFunctionPasses;
}

bool BackendConsumer::AddEmitPasses(std::string &Error) {
  if (Action == Backend_EmitNothing)
    return true;

  if (OutputFile == "-" || (InputFile == "-" && OutputFile.empty())) {
    AsmOutStream = new raw_stdout_ostream();
    sys::Program::ChangeStdoutToBinary();
  } else {
    if (OutputFile.empty()) {
      llvm::sys::Path Path(InputFile);
      Path.eraseSuffix();
      if (Action == Backend_EmitBC) {
        Path.appendSuffix("bc");
      } else if (Action == Backend_EmitLL) {
        Path.appendSuffix("ll");
      } else {
        Path.appendSuffix("s");
      }
      OutputFile = Path.toString();
    }

    AsmOutStream = new raw_fd_ostream(OutputFile.c_str(), true, Error);
    if (!Error.empty())
      return false;
  }

  if (Action == Backend_EmitBC) {
    getPerModulePasses()->add(createBitcodeWriterPass(*AsmOutStream));
  } else if (Action == Backend_EmitLL) {
    getPerModulePasses()->add(createPrintModulePass(AsmOutStream));
  } else {
    bool Fast = CompileOpts.OptimizationLevel == 0;

    // Create the TargetMachine for generating code.
    const TargetMachineRegistry::entry *TME =
      TargetMachineRegistry::getClosestStaticTargetForModule(*TheModule, Error);
    if (!TME) {
      Error = std::string("Unable to get target machine: ") + Error;
      return false;
    }

    std::string FeaturesStr;
    if (CompileOpts.CPU.size() || CompileOpts.Features.size()) {
      SubtargetFeatures Features;
      Features.setCPU(CompileOpts.CPU);
      for (std::vector<std::string>::iterator
             it = CompileOpts.Features.begin(),
             ie = CompileOpts.Features.end(); it != ie; ++it)
        Features.AddFeature(*it);
      FeaturesStr = Features.getString();
    }
    TargetMachine *TM = TME->CtorFn(*TheModule, FeaturesStr);

    // Set register scheduler & allocation policy.
    RegisterScheduler::setDefault(createDefaultScheduler);
    RegisterRegAlloc::setDefault(Fast ? createLocalRegisterAllocator :
                                 createLinearScanRegisterAllocator);

    // From llvm-gcc:
    // If there are passes we have to run on the entire module, we do codegen
    // as a separate "pass" after that happens.
    // FIXME: This is disabled right now until bugs can be worked out.  Reenable
    // this for fast -O0 compiles!
    FunctionPassManager *PM = getCodeGenPasses();

    // Normal mode, emit a .s file by running the code generator.
    // Note, this also adds codegenerator level optimization passes.
    switch (TM->addPassesToEmitFile(*PM, *AsmOutStream,
                                    TargetMachine::AssemblyFile, Fast)) {
    default:
    case FileModel::Error:
      Error = "Unable to interface with target machine!\n";
      return false;
    case FileModel::AsmFile:
      break;
    }

    if (TM->addPassesToEmitFileFinish(*CodeGenPasses, 0, Fast)) {
      Error = "Unable to interface with target machine!\n";
      return false;
    }
  }

  return true;
}

void BackendConsumer::CreatePasses() {
  // In -O0 if checking is disabled, we don't even have per-function passes.
  if (CompileOpts.VerifyModule)
    getPerFunctionPasses()->add(createVerifierPass());

  if (CompileOpts.OptimizationLevel > 0) {
    FunctionPassManager *PM = getPerFunctionPasses();
    PM->add(createCFGSimplificationPass());
    if (CompileOpts.OptimizationLevel == 1)
      PM->add(createPromoteMemoryToRegisterPass());
    else
      PM->add(createScalarReplAggregatesPass());
    PM->add(createInstructionCombiningPass());
  }

  // For now we always create per module passes.
  PassManager *PM = getPerModulePasses();
  if (CompileOpts.OptimizationLevel > 0) {
    if (CompileOpts.UnitAtATime)
      PM->add(createRaiseAllocationsPass());      // call %malloc -> malloc inst
    PM->add(createCFGSimplificationPass());       // Clean up disgusting code
    PM->add(createPromoteMemoryToRegisterPass()); // Kill useless allocas
    if (CompileOpts.UnitAtATime) {
      PM->add(createGlobalOptimizerPass());       // Optimize out global vars
      PM->add(createGlobalDCEPass());             // Remove unused fns and globs
      PM->add(createIPConstantPropagationPass()); // IP Constant Propagation
      PM->add(createDeadArgEliminationPass());    // Dead argument elimination
    }
    PM->add(createInstructionCombiningPass());    // Clean up after IPCP & DAE
    PM->add(createCFGSimplificationPass());       // Clean up after IPCP & DAE
    if (CompileOpts.UnitAtATime) {
      PM->add(createPruneEHPass());               // Remove dead EH info
      PM->add(createFunctionAttrsPass());         // Set readonly/readnone attrs
    }
    if (CompileOpts.InlineFunctions)
      PM->add(createFunctionInliningPass());      // Inline small functions
    else
      PM->add(createAlwaysInlinerPass());         // Respect always_inline
    if (CompileOpts.OptimizationLevel > 2)
      PM->add(createArgumentPromotionPass());     // Scalarize uninlined fn args
    if (CompileOpts.SimplifyLibCalls)
      PM->add(createSimplifyLibCallsPass());      // Library Call Optimizations
    PM->add(createInstructionCombiningPass());    // Cleanup for scalarrepl.
    PM->add(createJumpThreadingPass());           // Thread jumps.
    PM->add(createCFGSimplificationPass());       // Merge & remove BBs
    PM->add(createScalarReplAggregatesPass());    // Break up aggregate allocas
    PM->add(createInstructionCombiningPass());    // Combine silly seq's
    PM->add(createCondPropagationPass());         // Propagate conditionals
    PM->add(createTailCallEliminationPass());     // Eliminate tail calls
    PM->add(createCFGSimplificationPass());       // Merge & remove BBs
    PM->add(createReassociatePass());             // Reassociate expressions
    PM->add(createLoopRotatePass());              // Rotate Loop
    PM->add(createLICMPass());                    // Hoist loop invariants
    PM->add(createLoopUnswitchPass(CompileOpts.OptimizeSize ? true : false));
//    PM->add(createLoopIndexSplitPass());          // Split loop index
    PM->add(createInstructionCombiningPass());
    PM->add(createIndVarSimplifyPass());          // Canonicalize indvars
    PM->add(createLoopDeletionPass());            // Delete dead loops
    if (CompileOpts.UnrollLoops)
      PM->add(createLoopUnrollPass());            // Unroll small loops
    PM->add(createInstructionCombiningPass());    // Clean up after the unroller
    PM->add(createGVNPass());                     // Remove redundancies
    PM->add(createMemCpyOptPass());               // Remove memcpy / form memset
    PM->add(createSCCPPass());                    // Constant prop with SCCP

    // Run instcombine after redundancy elimination to exploit opportunities
    // opened up by them.
    PM->add(createInstructionCombiningPass());
    PM->add(createCondPropagationPass());         // Propagate conditionals
    PM->add(createDeadStoreEliminationPass());    // Delete dead stores
    PM->add(createAggressiveDCEPass());           // Delete dead instructions
    PM->add(createCFGSimplificationPass());       // Merge & remove BBs

    if (CompileOpts.UnitAtATime) {
      PM->add(createStripDeadPrototypesPass());   // Get rid of dead prototypes
      PM->add(createDeadTypeEliminationPass());   // Eliminate dead types
    }

    if (CompileOpts.OptimizationLevel > 1 && CompileOpts.UnitAtATime)
      PM->add(createConstantMergePass());         // Merge dup global constants
  } else {
    PM->add(createAlwaysInlinerPass());
  }
}

/// EmitAssembly - Handle interaction with LLVM backend to generate
/// actual machine code.
void BackendConsumer::EmitAssembly() {
  // Silently ignore if we weren't initialized for some reason.
  if (!TheModule || !TheTargetData)
    return;

  TimeRegion Region(CompileOpts.TimePasses ? &CodeGenerationTime : 0);

  // Make sure IR generation is happy with the module. This is
  // released by the module provider.
  Module *M = Gen->ReleaseModule();
  if (!M) {
    // The module has been released by IR gen on failures, do not
    // double free.
    ModuleProvider->releaseModule();
    TheModule = 0;
    return;
  }

  assert(TheModule == M && "Unexpected module change during IR generation");

  CreatePasses();

  std::string Error;
  if (!AddEmitPasses(Error)) {
    // FIXME: Don't fail this way.
    llvm::cerr << "ERROR: " << Error << "\n";
    ::exit(1);
  }

  // Run passes. For now we do all passes at once, but eventually we
  // would like to have the option of streaming code generation.

  if (PerFunctionPasses) {
    PrettyStackTraceString CrashInfo("Per-function optimization");

    PerFunctionPasses->doInitialization();
    for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
      if (!I->isDeclaration())
        PerFunctionPasses->run(*I);
    PerFunctionPasses->doFinalization();
  }

  if (PerModulePasses) {
    PrettyStackTraceString CrashInfo("Per-module optimization passes");
    PerModulePasses->run(*M);
  }

  if (CodeGenPasses) {
    PrettyStackTraceString CrashInfo("Code generation");
    CodeGenPasses->doInitialization();
    for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
      if (!I->isDeclaration())
        CodeGenPasses->run(*I);
    CodeGenPasses->doFinalization();
  }
}

ASTConsumer *clang::CreateBackendConsumer(BackendAction Action,
                                          Diagnostic &Diags,
                                          const LangOptions &LangOpts,
                                          const CompileOptions &CompileOpts,
                                          const std::string& InFile,
                                          const std::string& OutFile) {
  return new BackendConsumer(Action, Diags, LangOpts, CompileOpts,
                             InFile, OutFile);
}
<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <getopt.h>
#include <algorithm>
#include <memory>

#include <zcm/zcm-cpp.hpp>

#include "zcm/json/json.h"

#include "zcm/util/TypeDb.hpp"

#include "IndexerPluginDb.hpp"

using namespace std;

struct Args
{
    string logfile     = "";
    string output      = "";
    string plugin_path = "";
    string type_path   = "";
    bool readable      = false;
    bool debug         = false;

    bool parse(int argc, char *argv[])
    {
        // set some defaults
        const char *optstring = "l:o:p:t:rdh";
        struct option long_opts[] = {
            { "log",         required_argument, 0, 'l' },
            { "output",      required_argument, 0, 'o' },
            { "plugin-path", required_argument, 0, 'p' },
            { "type-path",   required_argument, 0, 't' },
            { "readable",    no_argument,       0, 'r' },
            { "debug",       no_argument,       0, 'd' },
            { "help",        no_argument,       0, 'h' },
            { 0, 0, 0, 0 }
        };

        int c;
        while ((c = getopt_long (argc, argv, optstring, long_opts, 0)) >= 0) {
            switch (c) {
                case 'l': logfile     = string(optarg); break;
                case 'o': output      = string(optarg); break;
                case 'p': plugin_path = string(optarg); break;
                case 't': type_path   = string(optarg); break;
                case 'r': readable    = true;           break;
                case 'd': debug       = true;           break;
                case 'h': default: return false;
            };
        }

        if (logfile == "") {
            cerr << "Please specify logfile input" << endl;
            return false;
        }

        if (output  == "") {
            cerr << "Please specify index file output" << endl;
            return false;
        }

        const char* type_path_env = getenv("ZCM_LOG_INDEXER_ZCMTYPES_PATH");
        if (type_path == "" && type_path_env) type_path = type_path_env;
        if (type_path == "") {
            cerr << "Please specify a zcmtypes.so path either through -t TYPE_PATH "
                    "or through the env var ZCM_LOG_INDEXER_ZCMTYPES_PATH" << endl;
            return false;
        }

        const char* plugin_path_env = getenv("ZCM_LOG_INDEXER_PLUGINS_PATH");
        if (plugin_path == "" && plugin_path_env) plugin_path = plugin_path_env;
        if (plugin_path == "") cerr << "Running with default timestamp indexer plugin" << endl;

        return true;
    }

    void usage()
    {
        cerr << "usage: zcm-log-indexer [options]" << endl
             << "" << endl
             << "    Load in a log file and write an index json file that" << endl
             << "    allows for faster log indexing." << endl
             << "" << endl
             << "Example:" << endl
             << "    zcm-log-indexer -l zcm.log -o index.dbz -t path/to/zcmtypes.so" << endl
             << "" << endl
             << "Options:" << endl
             << "" << endl
             << "  -h, --help              Shows this help text and exits" << endl
             << "  -l, --log=logfile       Input log to index for fast querying" << endl
             << "  -o, --output=indexfile  Output index file to be used with log" << endl
             << "  -p, --plugin-path=path  Path to shared library containing indexer plugins" << endl
             << "                          Can also be specified via the environment variable" << endl
             << "                          ZCM_LOG_INDEXER_ZCMTYPES_PATH" << endl
             << "  -t, --type-path=path    Path to shared library containing the zcmtypes" << endl
             << "                          Can also be specified via the environment variable" << endl
             << "                          ZCM_LOG_INDEXER_PLUGINS_PATH" << endl
             << "  -r, --readable          Don't minify the output index file. " << endl
             << "                          Leave it human readable" << endl
             << "  -d, --debug             Run a dry run to ensure proper indexer setup" << endl
             << endl << endl;
    }
};

int main(int argc, char* argv[])
{
    Args args;
    if (!args.parse(argc, argv)) {
        args.usage();
        return 1;
    }

    zcm::LogFile log(args.logfile, "r");
    if (!log.good()) {
        cerr << "Unable to open logfile: " << args.logfile << endl;
        return 1;
    }
    fseeko(log.getFilePtr(), 0, SEEK_END);
    // XXX Look into handling large logfiles
    off_t logSize = ftello(log.getFilePtr());

    ofstream output;
    output.open(args.output);
    if (!output.is_open()) {
        cerr << "Unable to open output file: " << args.output << endl;
        log.close();
        return 1;
    }

    vector<zcm::IndexerPlugin*> plugins;

    zcm::IndexerPlugin* defaultPlugin = new zcm::IndexerPlugin();
    plugins.push_back(defaultPlugin);

    IndexerPluginDb pluginDb(args.plugin_path, args.debug);
    // Load plugins from path if specified
    if (args.plugin_path != "") {
        vector<const zcm::IndexerPlugin*> dbPlugins = pluginDb.getPlugins();
        // casting away constness. Don't mess up.
        for (auto dbp : dbPlugins) plugins.push_back((zcm::IndexerPlugin*) dbp);
    }

    for (size_t i = 0; i < plugins.size(); ++i) {
        for (size_t j = i + 1; j < plugins.size(); ++j) {
            if (args.debug)
                cout << plugins.data()[i] << "->name() == "
                     << plugins.data()[j] << "->name()" << endl;

            if (plugins[i]->name() == plugins[j]->name()) {
                cerr << "Plugins must have unique names. Collision: "
                     << plugins[i]->name() << endl;
                return 1;
            }
        }
    }

    TypeDb types(args.type_path, args.debug);

    if (args.debug) return 0;

    struct PluginRuntimeInfo {
        zcm::IndexerPlugin* plugin;
        bool runThroughLog;
    };

    auto buildPluginGroups = [] (vector<zcm::IndexerPlugin*> plugins) {
        vector<vector<PluginRuntimeInfo>> groups;
        vector<zcm::IndexerPlugin*> lastLoop = plugins;
        while (!plugins.empty()) {
            groups.resize(groups.size() + 1);
            for (auto p = plugins.begin(); p != plugins.end();) {
                auto deps = (*p)->dependsOn();

                bool skipUntilLater = false;
                for (auto* dep : plugins) {
                    if (find(deps.begin(), deps.end(), dep->name()) != deps.end()) {
                        skipUntilLater = true;
                        break;
                    }
                }
                for (auto dep : groups.back()) {
                    if (find(deps.begin(), deps.end(), dep.plugin->name()) != deps.end()) {
                        skipUntilLater = true;
                        break;
                    }
                }
                if (!skipUntilLater) {
                    groups.back().push_back({*p, false});
                    p = plugins.erase(p);
                } else {
                    ++p;
                }
            }

            // Check for dependency resolution failure
            if (plugins == lastLoop) {
                cerr << "Unable to resolve all plugin dependencies. "
                        "Plugins left to resolve:" << endl << endl;
                for (auto* p : plugins) {
                    cerr << p->name() << endl
                         << "  Depends on:" << endl;
                    for (auto d : p->dependsOn())
                         cerr << "    " << d << endl;
                    cerr << endl;
                }
                exit(1);
            }
            lastLoop = plugins;
        }
        return groups;
    };

    // We do not own all the memory in here. We only own the default prorgam
    vector<vector<PluginRuntimeInfo>> pluginGroups;
    pluginGroups = buildPluginGroups(plugins);
    if (pluginGroups.size() > 1) {
        cout << "Identified " << pluginGroups.size() << " indexer plugin groups" << endl
             << "Running through log " << pluginGroups.size()
             << " times to satisfy dependencies" << endl;
    }

    zcm::Json::Value index;

    size_t numEvents = 0;
    const zcm::LogEvent* evt;
    for (size_t i = 0; i < pluginGroups.size(); ++i) {
        if (pluginGroups.size() != 1) cout << "Plugin group " << (i + 1) << endl;
        off_t offset = 0;
        fseeko(log.getFilePtr(), 0, SEEK_SET);

        for (auto p : pluginGroups[i])
            p.runThroughLog = p.plugin->setUp(index, index[p.plugin->name()], log);

        while (1) {
            offset = ftello(log.getFilePtr());

            static int lastPrintPercent = 0;
            int percent = (100.0 * offset / logSize) * 100;
            if (percent != lastPrintPercent) {
                cout << "\r" << "Percent Complete: " << (percent / 100) << flush;
                lastPrintPercent = percent;
            }

            evt = log.readNextEvent();
            if (evt == nullptr) break;

            int64_t msg_hash;
            __int64_t_decode_array(evt->data, 0, 8, &msg_hash, 1);
            const TypeMetadata* md = types.getByHash(msg_hash);
            if (!md) continue;

            for (auto p : pluginGroups[i]) {
                assert(p.plugin);

                if (!p.runThroughLog) continue;

                p.plugin->indexEvent(index, index[p.plugin->name()],
                                     evt->channel, md->name,
                                     offset, evt->timestamp,
                                     (uint64_t) msg_hash,
                                     evt->data, evt->datalen);

                numEvents++;
            }
        }

        cout << endl;

        for (auto p : pluginGroups[i])
            p.plugin->tearDown(index, index[p.plugin->name()], log);
    }

    delete defaultPlugin;
    defaultPlugin = nullptr;

    zcm::Json::StreamWriterBuilder builder;
    builder["indentation"] = args.readable ? "    " : "";
    std::unique_ptr<zcm::Json::StreamWriter> writer(builder.newStreamWriter());
    writer->write(index, &output);
    output << endl;
    output.close();

    cout << "Indexed " << numEvents << " events" << endl;
    return 0;
}
<commit_msg>By reference<commit_after>#include <iostream>
#include <fstream>
#include <getopt.h>
#include <algorithm>
#include <memory>

#include <zcm/zcm-cpp.hpp>

#include "zcm/json/json.h"

#include "zcm/util/TypeDb.hpp"

#include "IndexerPluginDb.hpp"

using namespace std;

struct Args
{
    string logfile     = "";
    string output      = "";
    string plugin_path = "";
    string type_path   = "";
    bool readable      = false;
    bool debug         = false;

    bool parse(int argc, char *argv[])
    {
        // set some defaults
        const char *optstring = "l:o:p:t:rdh";
        struct option long_opts[] = {
            { "log",         required_argument, 0, 'l' },
            { "output",      required_argument, 0, 'o' },
            { "plugin-path", required_argument, 0, 'p' },
            { "type-path",   required_argument, 0, 't' },
            { "readable",    no_argument,       0, 'r' },
            { "debug",       no_argument,       0, 'd' },
            { "help",        no_argument,       0, 'h' },
            { 0, 0, 0, 0 }
        };

        int c;
        while ((c = getopt_long (argc, argv, optstring, long_opts, 0)) >= 0) {
            switch (c) {
                case 'l': logfile     = string(optarg); break;
                case 'o': output      = string(optarg); break;
                case 'p': plugin_path = string(optarg); break;
                case 't': type_path   = string(optarg); break;
                case 'r': readable    = true;           break;
                case 'd': debug       = true;           break;
                case 'h': default: return false;
            };
        }

        if (logfile == "") {
            cerr << "Please specify logfile input" << endl;
            return false;
        }

        if (output  == "") {
            cerr << "Please specify index file output" << endl;
            return false;
        }

        const char* type_path_env = getenv("ZCM_LOG_INDEXER_ZCMTYPES_PATH");
        if (type_path == "" && type_path_env) type_path = type_path_env;
        if (type_path == "") {
            cerr << "Please specify a zcmtypes.so path either through -t TYPE_PATH "
                    "or through the env var ZCM_LOG_INDEXER_ZCMTYPES_PATH" << endl;
            return false;
        }

        const char* plugin_path_env = getenv("ZCM_LOG_INDEXER_PLUGINS_PATH");
        if (plugin_path == "" && plugin_path_env) plugin_path = plugin_path_env;
        if (plugin_path == "") cerr << "Running with default timestamp indexer plugin" << endl;

        return true;
    }

    void usage()
    {
        cerr << "usage: zcm-log-indexer [options]" << endl
             << "" << endl
             << "    Load in a log file and write an index json file that" << endl
             << "    allows for faster log indexing." << endl
             << "" << endl
             << "Example:" << endl
             << "    zcm-log-indexer -l zcm.log -o index.dbz -t path/to/zcmtypes.so" << endl
             << "" << endl
             << "Options:" << endl
             << "" << endl
             << "  -h, --help              Shows this help text and exits" << endl
             << "  -l, --log=logfile       Input log to index for fast querying" << endl
             << "  -o, --output=indexfile  Output index file to be used with log" << endl
             << "  -p, --plugin-path=path  Path to shared library containing indexer plugins" << endl
             << "                          Can also be specified via the environment variable" << endl
             << "                          ZCM_LOG_INDEXER_ZCMTYPES_PATH" << endl
             << "  -t, --type-path=path    Path to shared library containing the zcmtypes" << endl
             << "                          Can also be specified via the environment variable" << endl
             << "                          ZCM_LOG_INDEXER_PLUGINS_PATH" << endl
             << "  -r, --readable          Don't minify the output index file. " << endl
             << "                          Leave it human readable" << endl
             << "  -d, --debug             Run a dry run to ensure proper indexer setup" << endl
             << endl << endl;
    }
};

int main(int argc, char* argv[])
{
    Args args;
    if (!args.parse(argc, argv)) {
        args.usage();
        return 1;
    }

    zcm::LogFile log(args.logfile, "r");
    if (!log.good()) {
        cerr << "Unable to open logfile: " << args.logfile << endl;
        return 1;
    }
    fseeko(log.getFilePtr(), 0, SEEK_END);
    // XXX Look into handling large logfiles
    off_t logSize = ftello(log.getFilePtr());

    ofstream output;
    output.open(args.output);
    if (!output.is_open()) {
        cerr << "Unable to open output file: " << args.output << endl;
        log.close();
        return 1;
    }

    vector<zcm::IndexerPlugin*> plugins;

    zcm::IndexerPlugin* defaultPlugin = new zcm::IndexerPlugin();
    plugins.push_back(defaultPlugin);

    IndexerPluginDb pluginDb(args.plugin_path, args.debug);
    // Load plugins from path if specified
    if (args.plugin_path != "") {
        vector<const zcm::IndexerPlugin*> dbPlugins = pluginDb.getPlugins();
        // casting away constness. Don't mess up.
        for (auto dbp : dbPlugins) plugins.push_back((zcm::IndexerPlugin*) dbp);
    }

    for (size_t i = 0; i < plugins.size(); ++i) {
        for (size_t j = i + 1; j < plugins.size(); ++j) {
            if (args.debug)
                cout << plugins.data()[i] << "->name() == "
                     << plugins.data()[j] << "->name()" << endl;

            if (plugins[i]->name() == plugins[j]->name()) {
                cerr << "Plugins must have unique names. Collision: "
                     << plugins[i]->name() << endl;
                return 1;
            }
        }
    }

    TypeDb types(args.type_path, args.debug);

    if (args.debug) return 0;

    struct PluginRuntimeInfo {
        zcm::IndexerPlugin* plugin;
        bool runThroughLog;
    };

    auto buildPluginGroups = [] (vector<zcm::IndexerPlugin*> plugins) {
        vector<vector<PluginRuntimeInfo>> groups;
        vector<zcm::IndexerPlugin*> lastLoop = plugins;
        while (!plugins.empty()) {
            groups.resize(groups.size() + 1);
            for (auto p = plugins.begin(); p != plugins.end();) {
                auto deps = (*p)->dependsOn();

                bool skipUntilLater = false;
                for (auto* dep : plugins) {
                    if (find(deps.begin(), deps.end(), dep->name()) != deps.end()) {
                        skipUntilLater = true;
                        break;
                    }
                }
                for (auto dep : groups.back()) {
                    if (find(deps.begin(), deps.end(), dep.plugin->name()) != deps.end()) {
                        skipUntilLater = true;
                        break;
                    }
                }
                if (!skipUntilLater) {
                    groups.back().push_back({*p, false});
                    p = plugins.erase(p);
                } else {
                    ++p;
                }
            }

            // Check for dependency resolution failure
            if (plugins == lastLoop) {
                cerr << "Unable to resolve all plugin dependencies. "
                        "Plugins left to resolve:" << endl << endl;
                for (auto* p : plugins) {
                    cerr << p->name() << endl
                         << "  Depends on:" << endl;
                    for (auto d : p->dependsOn())
                         cerr << "    " << d << endl;
                    cerr << endl;
                }
                exit(1);
            }
            lastLoop = plugins;
        }
        return groups;
    };

    // We do not own all the memory in here. We only own the default prorgam
    vector<vector<PluginRuntimeInfo>> pluginGroups;
    pluginGroups = buildPluginGroups(plugins);
    if (pluginGroups.size() > 1) {
        cout << "Identified " << pluginGroups.size() << " indexer plugin groups" << endl
             << "Running through log " << pluginGroups.size()
             << " times to satisfy dependencies" << endl;
    }

    zcm::Json::Value index;

    size_t numEvents = 0;
    const zcm::LogEvent* evt;
    for (size_t i = 0; i < pluginGroups.size(); ++i) {
        if (pluginGroups.size() != 1) cout << "Plugin group " << (i + 1) << endl;
        off_t offset = 0;
        fseeko(log.getFilePtr(), 0, SEEK_SET);

        for (auto& p : pluginGroups[i])
            p.runThroughLog = p.plugin->setUp(index, index[p.plugin->name()], log);

        while (1) {
            offset = ftello(log.getFilePtr());

            static int lastPrintPercent = 0;
            int percent = (100.0 * offset / logSize) * 100;
            if (percent != lastPrintPercent) {
                cout << "\r" << "Percent Complete: " << (percent / 100) << flush;
                lastPrintPercent = percent;
            }

            evt = log.readNextEvent();
            if (evt == nullptr) break;

            int64_t msg_hash;
            __int64_t_decode_array(evt->data, 0, 8, &msg_hash, 1);
            const TypeMetadata* md = types.getByHash(msg_hash);
            if (!md) continue;

            for (auto& p : pluginGroups[i]) {
                assert(p.plugin);

                if (!p.runThroughLog) continue;

                p.plugin->indexEvent(index, index[p.plugin->name()],
                                     evt->channel, md->name,
                                     offset, evt->timestamp,
                                     (uint64_t) msg_hash,
                                     evt->data, evt->datalen);

                numEvents++;
            }
        }

        cout << endl;

        for (auto& p : pluginGroups[i])
            p.plugin->tearDown(index, index[p.plugin->name()], log);
    }

    delete defaultPlugin;
    defaultPlugin = nullptr;

    zcm::Json::StreamWriterBuilder builder;
    builder["indentation"] = args.readable ? "    " : "";
    std::unique_ptr<zcm::Json::StreamWriter> writer(builder.newStreamWriter());
    writer->write(index, &output);
    output << endl;
    output.close();

    cout << "Indexed " << numEvents << " events" << endl;
    return 0;
}
<|endoftext|>


<commit_before>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/fastos/fastos.h>
#include <vespa/log/log.h>
LOG_SETUP(".features.agefeature");

#include <vespa/searchlib/fef/featurenamebuilder.h>
#include <vespa/searchlib/fef/matchdata.h>
#include "agefeature.h"
#include "valuefeature.h"

using search::attribute::IAttributeVector;

namespace search {

typedef fef::FeatureNameBuilder FNB;

namespace features {

AgeExecutor::AgeExecutor(const IAttributeVector *attribute) :
    search::fef::FeatureExecutor(),
    _attribute(attribute),
    _buf()
{
    if (_attribute != NULL) {
        _buf.allocate(attribute->getMaxValueCount());
    }
}

void
AgeExecutor::execute(search::fef::MatchData &data)
{
    feature_t age = 10000000000.0;
    if (_attribute != NULL) {
        _buf.fill(*_attribute, data.getDocId());
        int64_t docTime = _buf[0];
        feature_t currTime = *data.resolveFeature(inputs()[0]);
        age = currTime - docTime;
        if (age < 0) {
            age = 0;
        }
    }
    *data.resolveFeature(outputs()[0]) = age;
}

void
AgeBlueprint::visitDumpFeatures(const search::fef::IIndexEnvironment &,
                                search::fef::IDumpFeatureVisitor &) const
{
    // empty
}

bool
AgeBlueprint::setup(const search::fef::IIndexEnvironment &env,
                    const search::fef::ParameterList &params)
{
    _attribute = params[0].getValue();
    defineInput("now");

    describeOutput("out", "The age of the document, in seconds.");
    env.hintAttributeAccess(_attribute);
    return true;
}

search::fef::Blueprint::UP
AgeBlueprint::createInstance() const
{
    return search::fef::Blueprint::UP(new AgeBlueprint());
}

search::fef::FeatureExecutor &
AgeBlueprint::createExecutor(const search::fef::IQueryEnvironment &env, vespalib::Stash &stash) const
{
    // Get docdate attribute vector
    const IAttributeVector * attribute = env.getAttributeContext().getAttribute(_attribute);
    return stash.create<AgeExecutor>(attribute);
}

}
}
<commit_msg>Use new API for getting inputs and setting outputs in age feature executor.<commit_after>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/fastos/fastos.h>
#include <vespa/log/log.h>
LOG_SETUP(".features.agefeature");

#include <vespa/searchlib/fef/featurenamebuilder.h>
#include <vespa/searchlib/fef/matchdata.h>
#include "agefeature.h"
#include "valuefeature.h"

using search::attribute::IAttributeVector;

namespace search {

typedef fef::FeatureNameBuilder FNB;

namespace features {

AgeExecutor::AgeExecutor(const IAttributeVector *attribute) :
    search::fef::FeatureExecutor(),
    _attribute(attribute),
    _buf()
{
    if (_attribute != NULL) {
        _buf.allocate(attribute->getMaxValueCount());
    }
}

void
AgeExecutor::execute(search::fef::MatchData &data)
{
    feature_t age = 10000000000.0;
    if (_attribute != NULL) {
        _buf.fill(*_attribute, data.getDocId());
        int64_t docTime = _buf[0];
        feature_t currTime = inputs().get_number(0);
        age = currTime - docTime;
        if (age < 0) {
            age = 0;
        }
    }
    outputs().set_number(0, age);
}

void
AgeBlueprint::visitDumpFeatures(const search::fef::IIndexEnvironment &,
                                search::fef::IDumpFeatureVisitor &) const
{
    // empty
}

bool
AgeBlueprint::setup(const search::fef::IIndexEnvironment &env,
                    const search::fef::ParameterList &params)
{
    _attribute = params[0].getValue();
    defineInput("now");

    describeOutput("out", "The age of the document, in seconds.");
    env.hintAttributeAccess(_attribute);
    return true;
}

search::fef::Blueprint::UP
AgeBlueprint::createInstance() const
{
    return search::fef::Blueprint::UP(new AgeBlueprint());
}

search::fef::FeatureExecutor &
AgeBlueprint::createExecutor(const search::fef::IQueryEnvironment &env, vespalib::Stash &stash) const
{
    // Get docdate attribute vector
    const IAttributeVector * attribute = env.getAttributeContext().getAttribute(_attribute);
    return stash.create<AgeExecutor>(attribute);
}

}
}
<|endoftext|>


<commit_before>#include <fstream>
#include <iostream>
#include <vector>

#include "yaml-cpp/eventhandler.h"
#include "yaml-cpp/yaml.h"  // IWYU pragma: keep

struct Params {
  bool hasFile;
  std::string fileName;
};

Params ParseArgs(int argc, char** argv) {
  Params p;

  std::vector<std::string> args(argv + 1, argv + argc);

  return p;
}

class NullEventHandler : public YAML::EventHandler {
 public:
  virtual void OnDocumentStart(const YAML::Mark&) {}
  virtual void OnDocumentEnd() {}

  virtual void OnNull(const YAML::Mark&, YAML::anchor_t) {}
  virtual void OnAlias(const YAML::Mark&, YAML::anchor_t) {}
  virtual void OnScalar(const YAML::Mark&, const std::string&, YAML::anchor_t,
                        const std::string&) {}

  virtual void OnSequenceStart(const YAML::Mark&, const std::string&,
                               YAML::anchor_t) {}
  virtual void OnSequenceEnd() {}

  virtual void OnMapStart(const YAML::Mark&, const std::string&,
                          YAML::anchor_t) {}
  virtual void OnMapEnd() {}
};

void parse(std::istream& input) {
  try {
    YAML::Node doc = YAML::Load(input);
    std::cout << doc << "\n";
  } catch (const YAML::Exception& e) {
    std::cerr << e.what() << "\n";
  }
}

int main(int argc, char** argv) {
  Params p = ParseArgs(argc, argv);

  if (argc > 1) {
    std::ifstream fin;
    fin.open(argv[1]);
    parse(fin);
  } else {
    parse(std::cin);
  }

  return 0;
}
<commit_msg>Fix NullEventHandler overloads<commit_after>#include <fstream>
#include <iostream>
#include <vector>

#include "yaml-cpp/eventhandler.h"
#include "yaml-cpp/yaml.h"  // IWYU pragma: keep

struct Params {
  bool hasFile;
  std::string fileName;
};

Params ParseArgs(int argc, char** argv) {
  Params p;

  std::vector<std::string> args(argv + 1, argv + argc);

  return p;
}

class NullEventHandler : public YAML::EventHandler {
 public:
  void OnDocumentStart(const YAML::Mark&) override {}
  void OnDocumentEnd() override {}

  void OnNull(const YAML::Mark&, YAML::anchor_t) override {}
  void OnAlias(const YAML::Mark&, YAML::anchor_t) override {}
  void OnScalar(const YAML::Mark&, const std::string&, YAML::anchor_t,
                const std::string&) override {}

  void OnSequenceStart(const YAML::Mark&, const std::string&, YAML::anchor_t,
                       YAML::EmitterStyle::value) override {}
  void OnSequenceEnd() override {}

  void OnMapStart(const YAML::Mark&, const std::string&, YAML::anchor_t,
                  YAML::EmitterStyle::value) override {}
  void OnMapEnd() override {}
};

void parse(std::istream& input) {
  try {
    YAML::Node doc = YAML::Load(input);
    std::cout << doc << "\n";
  } catch (const YAML::Exception& e) {
    std::cerr << e.what() << "\n";
  }
}

int main(int argc, char** argv) {
  Params p = ParseArgs(argc, argv);

  if (argc > 1) {
    std::ifstream fin;
    fin.open(argv[1]);
    parse(fin);
  } else {
    parse(std::cin);
  }

  return 0;
}
<|endoftext|>