<commit_before>#include "io.h"

#include <list>
#include <boost/program_options.hpp>
#include <boost/any.hpp>
#include <boost/scoped_ptr.hpp>
#include <iostream>
#include <string>
#include <sys/time.h>
#include <execinfo.h>

#include "printing.h"

#define BASH_RED "\033[0;31m"
#define BASH_GREEN "\033[0;32m"
#define BASH_YELLOW "\033[0;33m"
#define BASH_CYAN "\033[0;36m"
#define BASH_CLEAR "\033[0m"

using namespace mlpack;
using namespace mlpack::io;

IO* IO::singleton = NULL;

#ifdef DEBUG
PrefixedOutStream IO::Debug = PrefixedOutStream(std::cout,
    BASH_CYAN "[DEBUG] " BASH_CLEAR);
#else
NullOutStream IO::Debug = NullOutStream();
#endif
PrefixedOutStream IO::Info = PrefixedOutStream(std::cout,
    BASH_GREEN "[INFO ] " BASH_CLEAR);
PrefixedOutStream IO::Warn = PrefixedOutStream(std::cout,
    BASH_YELLOW "[WARN ] " BASH_CLEAR);
PrefixedOutStream IO::Fatal = PrefixedOutStream(std::cerr,
    BASH_RED "[FATAL] " BASH_CLEAR);

/* For clarity, we will alias boost's namespace */
namespace po = boost::program_options;

/* Constructors, Destructors, Copy */
IO::IO() : desc("Allowed Options") , hierarchy("Allowed Options") {

  return;
}

IO::IO(std::string& optionsName) :
    desc(optionsName.c_str()), hierarchy(optionsName.c_str()) {
  return;
}

IO::IO(const IO::IO& other) : desc(other.desc){
  return;
}

IO::~IO() {
  return;
}

/* Methods */
void IO::Add(const char* identifier,
             const char* description,
             const char* parent,
             bool required) {

  po::options_description& desc = IO::GetSingleton().desc;

  //Generate the full pathname and insert the node into the hierarchy
  std::string tmp = TYPENAME(bool);
  std::string path =
    IO::GetSingleton().ManageHierarchy(identifier, parent, tmp, description);

  //Add the option to boost program_options
  desc.add_options()
    (path.c_str(), description);

  //If the option is required, add it to the required options list
  if (required)
    GetSingleton().requiredOptions.push_front(path);

  return;
}

//Returns true if the specified value has been flagged by the user
bool IO::CheckValue(const char* identifier) {
  int isInVmap = GetSingleton().vmap.count(identifier);
  int isInGmap = GetSingleton().globalValues.count(identifier);

  //Return true if we have a defined value for identifier
  return (isInVmap || isInGmap);
}

//Returns the sole instance of this class
IO& IO::GetSingleton() {
  if (singleton == NULL)
    singleton = new IO();
  return *singleton;
}

//Generates a full pathname, and places it in the hierarchy
std::string IO::ManageHierarchy(const char* id,
                                const char* parent,
                                std::string& tname,
                                const char* description) {

  std::string path(id), desc(description);

  path = SanitizeString(parent)+id;

  //Add the sanity checked string to the hierarchy
  if (desc.length() == 0)
    hierarchy.AppendNode(path, tname);
  else
    hierarchy.AppendNode(path, tname, desc);
  return path;
}

//Parses the command line for options
void IO::ParseCommandLine(int argc, char** line) {
  po::variables_map& vmap = GetSingleton().vmap;
  po::options_description& desc = GetSingleton().desc;
  std::list<std::string> rOpt = GetSingleton().requiredOptions;

  //Parse the command line, place the options & values into vmap
  try{
    po::store(po::parse_command_line(argc, line, desc), vmap);
  }catch(std::exception& ex) {
    IO::Fatal << ex.what() << std::endl;
  }
  //Flush the buffer, make sure changes are propogated to vmap
  po::notify(vmap);

  //Default help message
  if (CheckValue("help")) {
    GetSingleton().hierarchy.PrintAllHelp();
    exit(0);  //The user doesn't want to run the program, he wants help.
  }
  else if (CheckValue("info")) {
    std::string str = GetValue<std::string>("info");
    GetSingleton().hierarchy.FindNode(str);
    exit(0);
  }

  //Now, warn the user if they missed any required options
  std::list<std::string>::iterator iter;
  for (iter = rOpt.begin(); iter != rOpt.end(); iter++)
    if (!CheckValue((*iter).c_str())) // If a required option isn't there...
      IO::Fatal << "Required option --" << iter->c_str() << " is undefined..."
          << std::endl;
}

void IO::ParseStream(std::istream& stream) {
  IO::Debug << "Compiled with debug checks." << std::endl;

  po::variables_map& vmap = GetSingleton().vmap;
  po::options_description& desc = GetSingleton().desc;
  std::list<std::string> rOpt = GetSingleton().requiredOptions;

  //Parse the stream, place options & values into vmap
  try{
  po::store(po::parse_config_file(stream, desc), vmap);
  }catch(std::exception& ex) {
    IO::Fatal << ex.what() << std::endl;
  }
  //Flush the buffer, make s ure changes are propgated to vmap
  po::notify(vmap);

  //Now, warn the user if they missed any required options
  std::list<std::string>::iterator iter;
  for (iter = rOpt.begin(); iter != rOpt.end(); iter++)
    if (!CheckValue((*iter).c_str())) //If a required option isn't there...
      IO::Fatal << "Required option --" << iter->c_str() << " is undefined..."
          << std::endl;
}

//Prints the current state, right now just for debugging purposes
void IO::Print() {
  IO::GetSingleton().hierarchy.PrintAll();
}

/* Print whatever data we can */
void IO::PrintData() {
}

/* Initializes a timer, available like a normal value specified on the command
   line.  Timers are of type timval, as defined in sys/time.h*/
void IO::StartTimer(const char* timerName) {
  //Don't want to actually document the timer, the user can do that if he wants
  timeval tmp;

  tmp.tv_sec = 0;
  tmp.tv_usec = 0;

  gettimeofday(&tmp, NULL);
  GetValue<timeval>(timerName) = tmp;
}

/* Halts the timer, and replaces it's value with the delta time from it's start
*/
void IO::StopTimer(const char* timerName) {
  timeval delta, b, &a = GetValue<timeval>(timerName);
  gettimeofday(&b, NULL);

  //Calculate the delta time
  timersub(&b, &a, &delta);
  a = delta;
}

//Sanitizes strings, rendering input such as /foo/bar and foo/bar equal
std::string IO::SanitizeString(const char* str) {
  if (str != NULL) {
    std::string p(str);
    //Lets sanity check string, remove superfluous '/' prefixes
    if (p.find_first_of("/") == 0)
      p = p.substr(1,p.length()-1);
    //Add necessary '/' suffixes to parent
    if (p.find_last_of("/") != p.length()-1)
      p = p+"/";
    return p;
  }

  return std::string("");
}

PARAM_MODULE("help", "default help info");
<commit_msg>Commit the change that I think r7929 was supposed to be: fix compatibility with gcc 4.6.<commit_after>#include "io.h"

#include <list>
#include <boost/program_options.hpp>
#include <boost/any.hpp>
#include <boost/scoped_ptr.hpp>
#include <iostream>
#include <string>
#include <sys/time.h>
#include <execinfo.h>

#include "printing.h"

#define BASH_RED "\033[0;31m"
#define BASH_GREEN "\033[0;32m"
#define BASH_YELLOW "\033[0;33m"
#define BASH_CYAN "\033[0;36m"
#define BASH_CLEAR "\033[0m"

using namespace mlpack;
using namespace mlpack::io;

IO* IO::singleton = NULL;

#ifdef DEBUG
PrefixedOutStream IO::Debug = PrefixedOutStream(std::cout,
    BASH_CYAN "[DEBUG] " BASH_CLEAR);
#else
NullOutStream IO::Debug = NullOutStream();
#endif
PrefixedOutStream IO::Info = PrefixedOutStream(std::cout,
    BASH_GREEN "[INFO ] " BASH_CLEAR);
PrefixedOutStream IO::Warn = PrefixedOutStream(std::cout,
    BASH_YELLOW "[WARN ] " BASH_CLEAR);
PrefixedOutStream IO::Fatal = PrefixedOutStream(std::cerr,
    BASH_RED "[FATAL] " BASH_CLEAR);

/* For clarity, we will alias boost's namespace */
namespace po = boost::program_options;

/* Constructors, Destructors, Copy */
IO::IO() : desc("Allowed Options") , hierarchy("Allowed Options") {

  return;
}

IO::IO(std::string& optionsName) :
    desc(optionsName.c_str()), hierarchy(optionsName.c_str()) {
  return;
}

IO::IO(const IO& other) : desc(other.desc){
  return;
}

IO::~IO() {
  return;
}

/* Methods */
void IO::Add(const char* identifier,
             const char* description,
             const char* parent,
             bool required) {

  po::options_description& desc = IO::GetSingleton().desc;

  //Generate the full pathname and insert the node into the hierarchy
  std::string tmp = TYPENAME(bool);
  std::string path =
    IO::GetSingleton().ManageHierarchy(identifier, parent, tmp, description);

  //Add the option to boost program_options
  desc.add_options()
    (path.c_str(), description);

  //If the option is required, add it to the required options list
  if (required)
    GetSingleton().requiredOptions.push_front(path);

  return;
}

//Returns true if the specified value has been flagged by the user
bool IO::CheckValue(const char* identifier) {
  int isInVmap = GetSingleton().vmap.count(identifier);
  int isInGmap = GetSingleton().globalValues.count(identifier);

  //Return true if we have a defined value for identifier
  return (isInVmap || isInGmap);
}

//Returns the sole instance of this class
IO& IO::GetSingleton() {
  if (singleton == NULL)
    singleton = new IO();
  return *singleton;
}

//Generates a full pathname, and places it in the hierarchy
std::string IO::ManageHierarchy(const char* id,
                                const char* parent,
                                std::string& tname,
                                const char* description) {

  std::string path(id), desc(description);

  path = SanitizeString(parent)+id;

  //Add the sanity checked string to the hierarchy
  if (desc.length() == 0)
    hierarchy.AppendNode(path, tname);
  else
    hierarchy.AppendNode(path, tname, desc);
  return path;
}

//Parses the command line for options
void IO::ParseCommandLine(int argc, char** line) {
  po::variables_map& vmap = GetSingleton().vmap;
  po::options_description& desc = GetSingleton().desc;
  std::list<std::string> rOpt = GetSingleton().requiredOptions;

  //Parse the command line, place the options & values into vmap
  try{
    po::store(po::parse_command_line(argc, line, desc), vmap);
  }catch(std::exception& ex) {
    IO::Fatal << ex.what() << std::endl;
  }
  //Flush the buffer, make sure changes are propogated to vmap
  po::notify(vmap);

  //Default help message
  if (CheckValue("help")) {
    GetSingleton().hierarchy.PrintAllHelp();
    exit(0);  //The user doesn't want to run the program, he wants help.
  }
  else if (CheckValue("info")) {
    std::string str = GetValue<std::string>("info");
    GetSingleton().hierarchy.FindNode(str);
    exit(0);
  }

  //Now, warn the user if they missed any required options
  std::list<std::string>::iterator iter;
  for (iter = rOpt.begin(); iter != rOpt.end(); iter++)
    if (!CheckValue((*iter).c_str())) // If a required option isn't there...
      IO::Fatal << "Required option --" << iter->c_str() << " is undefined..."
          << std::endl;
}

void IO::ParseStream(std::istream& stream) {
  IO::Debug << "Compiled with debug checks." << std::endl;

  po::variables_map& vmap = GetSingleton().vmap;
  po::options_description& desc = GetSingleton().desc;
  std::list<std::string> rOpt = GetSingleton().requiredOptions;

  //Parse the stream, place options & values into vmap
  try{
  po::store(po::parse_config_file(stream, desc), vmap);
  }catch(std::exception& ex) {
    IO::Fatal << ex.what() << std::endl;
  }
  //Flush the buffer, make s ure changes are propgated to vmap
  po::notify(vmap);

  //Now, warn the user if they missed any required options
  std::list<std::string>::iterator iter;
  for (iter = rOpt.begin(); iter != rOpt.end(); iter++)
    if (!CheckValue((*iter).c_str())) //If a required option isn't there...
      IO::Fatal << "Required option --" << iter->c_str() << " is undefined..."
          << std::endl;
}

//Prints the current state, right now just for debugging purposes
void IO::Print() {
  IO::GetSingleton().hierarchy.PrintAll();
}

/* Print whatever data we can */
void IO::PrintData() {
}

/* Initializes a timer, available like a normal value specified on the command
   line.  Timers are of type timval, as defined in sys/time.h*/
void IO::StartTimer(const char* timerName) {
  //Don't want to actually document the timer, the user can do that if he wants
  timeval tmp;

  tmp.tv_sec = 0;
  tmp.tv_usec = 0;

  gettimeofday(&tmp, NULL);
  GetValue<timeval>(timerName) = tmp;
}

/* Halts the timer, and replaces it's value with the delta time from it's start
*/
void IO::StopTimer(const char* timerName) {
  timeval delta, b, &a = GetValue<timeval>(timerName);
  gettimeofday(&b, NULL);

  //Calculate the delta time
  timersub(&b, &a, &delta);
  a = delta;
}

//Sanitizes strings, rendering input such as /foo/bar and foo/bar equal
std::string IO::SanitizeString(const char* str) {
  if (str != NULL) {
    std::string p(str);
    //Lets sanity check string, remove superfluous '/' prefixes
    if (p.find_first_of("/") == 0)
      p = p.substr(1,p.length()-1);
    //Add necessary '/' suffixes to parent
    if (p.find_last_of("/") != p.length()-1)
      p = p+"/";
    return p;
  }

  return std::string("");
}

PARAM_MODULE("help", "default help info");
<|endoftext|>


<commit_before>//===--- ModuleDependencyCollector.cpp - Collect module dependencies ------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Collect the dependencies of a set of modules.
//
//===----------------------------------------------------------------------===//

#include "clang/Frontend/Utils.h"
#include "clang/Serialization/ASTReader.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Config/config.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"

using namespace clang;

namespace {
/// Private implementation for ModuleDependencyCollector
class ModuleDependencyListener : public ASTReaderListener {
  ModuleDependencyCollector &Collector;
  llvm::StringMap<std::string> SymLinkMap;

  bool getRealPath(StringRef SrcPath, SmallVectorImpl<char> &Result);
  std::error_code copyToRoot(StringRef Src);
public:
  ModuleDependencyListener(ModuleDependencyCollector &Collector)
      : Collector(Collector) {}
  bool needsInputFileVisitation() override { return true; }
  bool needsSystemInputFileVisitation() override { return true; }
  bool visitInputFile(StringRef Filename, bool IsSystem, bool IsOverridden,
                      bool IsExplicitModule) override;
};
}

void ModuleDependencyCollector::attachToASTReader(ASTReader &R) {
  R.addListener(llvm::make_unique<ModuleDependencyListener>(*this));
}

void ModuleDependencyCollector::writeFileMap() {
  if (Seen.empty())
    return;

  SmallString<256> Dest = getDest();
  llvm::sys::path::append(Dest, "vfs.yaml");

  std::error_code EC;
  llvm::raw_fd_ostream OS(Dest, EC, llvm::sys::fs::F_Text);
  if (EC) {
    setHasErrors();
    return;
  }
  VFSWriter.write(OS);
}

// TODO: move this to Support/Path.h and check for HAVE_REALPATH?
static bool real_path(StringRef SrcPath, SmallVectorImpl<char> &RealPath) {
#ifdef LLVM_ON_UNIX
  char CanonicalPath[PATH_MAX];

  // TODO: emit a warning in case this fails...?
  if (!realpath(SrcPath.str().c_str(), CanonicalPath))
    return false;

  SmallString<256> RPath(CanonicalPath);
  RealPath.swap(RPath);
  return true;
#else
  // FIXME: Add support for systems without realpath.
  return false;
#endif
}

bool ModuleDependencyListener::getRealPath(StringRef SrcPath,
                                           SmallVectorImpl<char> &Result) {
  using namespace llvm::sys;
  SmallString<256> RealPath;
  StringRef FileName = path::filename(SrcPath);
  std::string Dir = path::parent_path(SrcPath).str();
  auto DirWithSymLink = SymLinkMap.find(Dir);

  // Use real_path to fix any symbolic link component present in a path.
  // Computing the real path is expensive, cache the search through the
  // parent path directory.
  if (DirWithSymLink == SymLinkMap.end()) {
    if (!real_path(Dir, RealPath))
      return false;
    SymLinkMap[Dir] = RealPath.str();
  } else {
    RealPath = DirWithSymLink->second;
  }

  path::append(RealPath, FileName);
  Result.swap(RealPath);
  return true;
}

std::error_code ModuleDependencyListener::copyToRoot(StringRef Src) {
  using namespace llvm::sys;

  // We need an absolute path to append to the root.
  SmallString<256> AbsoluteSrc = Src;
  fs::make_absolute(AbsoluteSrc);
  // Canonicalize to a native path to avoid mixed separator styles.
  path::native(AbsoluteSrc);
  // Remove redundant leading "./" pieces and consecutive separators.
  AbsoluteSrc = path::remove_leading_dotslash(AbsoluteSrc);

  // Canonicalize path by removing "..", "." components.
  SmallString<256> CanonicalPath = AbsoluteSrc;
  path::remove_dots(CanonicalPath, /*remove_dot_dot=*/true);

  // If a ".." component is present after a symlink component, remove_dots may
  // lead to the wrong real destination path. Let the source be canonicalized
  // like that but make sure the destination uses the real path.
  bool HasDotDotInPath =
      std::count(path::begin(AbsoluteSrc), path::end(AbsoluteSrc), "..") > 0;
  SmallString<256> RealPath;
  bool HasRemovedSymlinkComponent = HasDotDotInPath &&
                             getRealPath(AbsoluteSrc, RealPath) &&
                             !StringRef(CanonicalPath).equals(RealPath);

  // Build the destination path.
  SmallString<256> Dest = Collector.getDest();
  path::append(Dest, path::relative_path(HasRemovedSymlinkComponent ? RealPath
                                                             : CanonicalPath));

  // Copy the file into place.
  if (std::error_code EC = fs::create_directories(path::parent_path(Dest),
                                                   /*IgnoreExisting=*/true))
    return EC;
  if (std::error_code EC = fs::copy_file(
          HasRemovedSymlinkComponent ? RealPath : CanonicalPath, Dest))
    return EC;

  // Use the canonical path under the root for the file mapping. Also create
  // an additional entry for the real path.
  Collector.addFileMapping(CanonicalPath, Dest);
  if (HasRemovedSymlinkComponent)
    Collector.addFileMapping(RealPath, Dest);

  return std::error_code();
}

bool ModuleDependencyListener::visitInputFile(StringRef Filename, bool IsSystem,
                                              bool IsOverridden,
                                              bool IsExplicitModule) {
  if (Collector.insertSeen(Filename))
    if (copyToRoot(Filename))
      Collector.setHasErrors();
  return true;
}
<commit_msg>[VFS] Remove wrong header include<commit_after>//===--- ModuleDependencyCollector.cpp - Collect module dependencies ------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Collect the dependencies of a set of modules.
//
//===----------------------------------------------------------------------===//

#include "clang/Frontend/Utils.h"
#include "clang/Serialization/ASTReader.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"

using namespace clang;

namespace {
/// Private implementation for ModuleDependencyCollector
class ModuleDependencyListener : public ASTReaderListener {
  ModuleDependencyCollector &Collector;
  llvm::StringMap<std::string> SymLinkMap;

  bool getRealPath(StringRef SrcPath, SmallVectorImpl<char> &Result);
  std::error_code copyToRoot(StringRef Src);
public:
  ModuleDependencyListener(ModuleDependencyCollector &Collector)
      : Collector(Collector) {}
  bool needsInputFileVisitation() override { return true; }
  bool needsSystemInputFileVisitation() override { return true; }
  bool visitInputFile(StringRef Filename, bool IsSystem, bool IsOverridden,
                      bool IsExplicitModule) override;
};
}

void ModuleDependencyCollector::attachToASTReader(ASTReader &R) {
  R.addListener(llvm::make_unique<ModuleDependencyListener>(*this));
}

void ModuleDependencyCollector::writeFileMap() {
  if (Seen.empty())
    return;

  SmallString<256> Dest = getDest();
  llvm::sys::path::append(Dest, "vfs.yaml");

  std::error_code EC;
  llvm::raw_fd_ostream OS(Dest, EC, llvm::sys::fs::F_Text);
  if (EC) {
    setHasErrors();
    return;
  }
  VFSWriter.write(OS);
}

// TODO: move this to Support/Path.h and check for HAVE_REALPATH?
static bool real_path(StringRef SrcPath, SmallVectorImpl<char> &RealPath) {
#ifdef LLVM_ON_UNIX
  char CanonicalPath[PATH_MAX];

  // TODO: emit a warning in case this fails...?
  if (!realpath(SrcPath.str().c_str(), CanonicalPath))
    return false;

  SmallString<256> RPath(CanonicalPath);
  RealPath.swap(RPath);
  return true;
#else
  // FIXME: Add support for systems without realpath.
  return false;
#endif
}

bool ModuleDependencyListener::getRealPath(StringRef SrcPath,
                                           SmallVectorImpl<char> &Result) {
  using namespace llvm::sys;
  SmallString<256> RealPath;
  StringRef FileName = path::filename(SrcPath);
  std::string Dir = path::parent_path(SrcPath).str();
  auto DirWithSymLink = SymLinkMap.find(Dir);

  // Use real_path to fix any symbolic link component present in a path.
  // Computing the real path is expensive, cache the search through the
  // parent path directory.
  if (DirWithSymLink == SymLinkMap.end()) {
    if (!real_path(Dir, RealPath))
      return false;
    SymLinkMap[Dir] = RealPath.str();
  } else {
    RealPath = DirWithSymLink->second;
  }

  path::append(RealPath, FileName);
  Result.swap(RealPath);
  return true;
}

std::error_code ModuleDependencyListener::copyToRoot(StringRef Src) {
  using namespace llvm::sys;

  // We need an absolute path to append to the root.
  SmallString<256> AbsoluteSrc = Src;
  fs::make_absolute(AbsoluteSrc);
  // Canonicalize to a native path to avoid mixed separator styles.
  path::native(AbsoluteSrc);
  // Remove redundant leading "./" pieces and consecutive separators.
  AbsoluteSrc = path::remove_leading_dotslash(AbsoluteSrc);

  // Canonicalize path by removing "..", "." components.
  SmallString<256> CanonicalPath = AbsoluteSrc;
  path::remove_dots(CanonicalPath, /*remove_dot_dot=*/true);

  // If a ".." component is present after a symlink component, remove_dots may
  // lead to the wrong real destination path. Let the source be canonicalized
  // like that but make sure the destination uses the real path.
  bool HasDotDotInPath =
      std::count(path::begin(AbsoluteSrc), path::end(AbsoluteSrc), "..") > 0;
  SmallString<256> RealPath;
  bool HasRemovedSymlinkComponent = HasDotDotInPath &&
                             getRealPath(AbsoluteSrc, RealPath) &&
                             !StringRef(CanonicalPath).equals(RealPath);

  // Build the destination path.
  SmallString<256> Dest = Collector.getDest();
  path::append(Dest, path::relative_path(HasRemovedSymlinkComponent ? RealPath
                                                             : CanonicalPath));

  // Copy the file into place.
  if (std::error_code EC = fs::create_directories(path::parent_path(Dest),
                                                   /*IgnoreExisting=*/true))
    return EC;
  if (std::error_code EC = fs::copy_file(
          HasRemovedSymlinkComponent ? RealPath : CanonicalPath, Dest))
    return EC;

  // Use the canonical path under the root for the file mapping. Also create
  // an additional entry for the real path.
  Collector.addFileMapping(CanonicalPath, Dest);
  if (HasRemovedSymlinkComponent)
    Collector.addFileMapping(RealPath, Dest);

  return std::error_code();
}

bool ModuleDependencyListener::visitInputFile(StringRef Filename, bool IsSystem,
                                              bool IsOverridden,
                                              bool IsExplicitModule) {
  if (Collector.insertSeen(Filename))
    if (copyToRoot(Filename))
      Collector.setHasErrors();
  return true;
}
<|endoftext|>


<commit_before>#ifndef PCL_FEATURES_IMPL_PPFRGB_H_
#define PCL_FEATURES_IMPL_PPFRGB_H_

#include "pcl/features/ppfrgb.h"
#include "pcl/features/pfhrgb.h"

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT, typename PointNT, typename PointOutT>
pcl::PPFRGBEstimation<PointInT, PointNT, PointOutT>::PPFRGBEstimation ()
: FeatureFromNormals <PointInT, PointNT, PointOutT> ()
{
  feature_name_ = "PPFRGBEstimation";
  // Slight hack in order to pass the check for the presence of a search method in Feature::initCompute ()
  Feature<PointInT, PointOutT>::tree_.reset (new KdTreeFLANN <PointInT> ());
  Feature<PointInT, PointOutT>::search_radius_ = 1.0f;
};

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT, typename PointNT, typename PointOutT> void
pcl::PPFRGBEstimation<PointInT, PointNT, PointOutT>::computeFeature (PointCloudOut &output)
{
  // Initialize output container - overwrite the sizes done by Feature::initCompute ()
  output.points.resize (indices_->size () * input_->points.size ());
  output.height = 1;
  output.width = output.points.size ();

  // Compute point pair features for every pair of points in the cloud
  for (size_t index_i = 0; index_i < indices_->size (); ++index_i)
  {
    size_t i = (*indices_)[index_i];
    for (size_t j = 0 ; j < input_->points.size (); ++j)
    {
      PointOutT p;
      if (i != j)
      {
        if (pcl::computeRGBPairFeatures
            (input_->points[i].getVector4fMap (), normals_->points[i].getNormalVector4fMap (), input_->points[i].getRGBVector4i (),
             input_->points[j].getVector4fMap (), normals_->points[j].getNormalVector4fMap (), input_->points[j].getRGBVector4i (),
             p.f1, p.f2, p.f3, p.f4, p.r_ratio, p.g_ratio, p.b_ratio))
        {
          // Calculate alpha_m angle
          Eigen::Vector3f model_reference_point = input_->points[i].getVector3fMap (),
              model_reference_normal = normals_->points[i].getNormalVector3fMap (),
              model_point = input_->points[j].getVector3fMap ();
          Eigen::AngleAxisf rotation_mg (acos (model_reference_normal.dot (Eigen::Vector3f::UnitX ())),
                                         model_reference_normal.cross (Eigen::Vector3f::UnitX ()).normalized ());
          Eigen::Affine3f transform_mg = Eigen::Translation3f ( rotation_mg * ((-1) * model_reference_point)) * rotation_mg;

          Eigen::Vector3f model_point_transformed = transform_mg * model_point;
          float angle = atan2f ( -model_point_transformed(2), model_point_transformed(1));
          if (sin (angle) * model_point_transformed(2) < 0.0f)
            angle *= (-1);
          p.alpha_m = -angle;
        }
        else
        {
          PCL_ERROR ("[pcl::%s::computeFeature] Computing pair feature vector between points %zu and %zu went wrong.\n", getClassName ().c_str (), i, j);
          p.f1 = p.f2 = p.f3 = p.f4 = p.alpha_m = 0.0;
        }
      }
      // Do not calculate the feature for identity pairs (i, i) as they are not used
      // in the following computations
      else
        p.f1 = p.f2 = p.f3 = p.f4 = p.alpha_m = 0.0;

      output.points[index_i*input_->points.size () + j] = p;
    }
  }
}

//////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT, typename PointNT, typename PointOutT>
pcl::PPFRGBRegionEstimation<PointInT, PointNT, PointOutT>::PPFRGBRegionEstimation ()
: FeatureFromNormals <PointInT, PointNT, PointOutT> ()
{
  feature_name_ = "PPFRGBEstimation";
};

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT, typename PointNT, typename PointOutT> void
pcl::PPFRGBRegionEstimation<PointInT, PointNT, PointOutT>::computeFeature (PointCloudOut &output)
{
  PCL_INFO ("before computing output size: %u\n", output.size ());
  output.resize (indices_->size ());
  for (size_t index_i = 0; index_i < indices_->size (); ++index_i)
  {
    size_t i = (*indices_)[index_i];
    std::vector<int> nn_indices;
    std::vector<float> nn_distances;
    tree_->radiusSearch (i, search_radius_, nn_indices, nn_distances);

    PointOutT average_feature_nn;
    average_feature_nn.f1 = average_feature_nn.f2 = average_feature_nn.f3 = average_feature_nn.f4 =
        average_feature_nn.r_ratio = average_feature_nn.g_ratio = average_feature_nn.b_ratio = 0.0f;

    for (std::vector<int>::iterator nn_it = nn_indices.begin (); nn_it != nn_indices.end (); ++nn_it)
    {
      size_t j = *nn_it;
      if (i != j)
      {
        float f1, f2, f3, f4, r_ratio, g_ratio, b_ratio;
        if (pcl::computeRGBPairFeatures
            (input_->points[i].getVector4fMap (), normals_->points[i].getNormalVector4fMap (), input_->points[i].getRGBVector4i (),
             input_->points[j].getVector4fMap (), normals_->points[j].getNormalVector4fMap (), input_->points[j].getRGBVector4i (),
             f1, f2, f3, f4, r_ratio, g_ratio, b_ratio))
        {
          average_feature_nn.f1 += f1;
          average_feature_nn.f2 += f2;
          average_feature_nn.f3 += f3;
          average_feature_nn.f4 += f4;
          average_feature_nn.r_ratio += r_ratio;
          average_feature_nn.g_ratio += g_ratio;
          average_feature_nn.b_ratio += b_ratio;
        }
        else
        {
          PCL_ERROR ("[pcl::%s::computeFeature] Computing pair feature vector between points %zu and %zu went wrong.\n", getClassName ().c_str (), i, j);
        }
      }
    }

    float normalization_factor = nn_indices.size ();
    average_feature_nn.f1 /= normalization_factor;
    average_feature_nn.f2 /= normalization_factor;
    average_feature_nn.f3 /= normalization_factor;
    average_feature_nn.f4 /= normalization_factor;
    average_feature_nn.r_ratio /= normalization_factor;
    average_feature_nn.g_ratio /= normalization_factor;
    average_feature_nn.b_ratio /= normalization_factor;
    output.points[index_i] = average_feature_nn;
  }
  PCL_INFO ("Output size: %u\n", output.points.size ());
}

#define PCL_INSTANTIATE_PPFRGBEstimation(T,NT,OutT) template class PCL_EXPORTS pcl::PPFRGBEstimation<T,NT,OutT>;
#define PCL_INSTANTIATE_PPFRGBRegionEstimation(T,NT,OutT) template class PCL_EXPORTS pcl::PPFRGBRegionEstimation<T,NT,OutT>;

#endif // PCL_FEATURES_IMPL_PPFRGB_H_
<commit_msg>removed a warning for pathcc<commit_after>#ifndef PCL_FEATURES_IMPL_PPFRGB_H_
#define PCL_FEATURES_IMPL_PPFRGB_H_

#include "pcl/features/ppfrgb.h"
#include "pcl/features/pfhrgb.h"

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT, typename PointNT, typename PointOutT>
pcl::PPFRGBEstimation<PointInT, PointNT, PointOutT>::PPFRGBEstimation ()
: FeatureFromNormals <PointInT, PointNT, PointOutT> ()
{
  feature_name_ = "PPFRGBEstimation";
  // Slight hack in order to pass the check for the presence of a search method in Feature::initCompute ()
  Feature<PointInT, PointOutT>::tree_.reset (new KdTreeFLANN <PointInT> ());
  Feature<PointInT, PointOutT>::search_radius_ = 1.0f;
};

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT, typename PointNT, typename PointOutT> void
pcl::PPFRGBEstimation<PointInT, PointNT, PointOutT>::computeFeature (PointCloudOut &output)
{
  // Initialize output container - overwrite the sizes done by Feature::initCompute ()
  output.points.resize (indices_->size () * input_->points.size ());
  output.height = 1;
  output.width = output.points.size ();

  // Compute point pair features for every pair of points in the cloud
  for (size_t index_i = 0; index_i < indices_->size (); ++index_i)
  {
    size_t i = (*indices_)[index_i];
    for (size_t j = 0 ; j < input_->points.size (); ++j)
    {
      PointOutT p;
      if (i != j)
      {
        if (pcl::computeRGBPairFeatures
            (input_->points[i].getVector4fMap (), normals_->points[i].getNormalVector4fMap (), input_->points[i].getRGBVector4i (),
             input_->points[j].getVector4fMap (), normals_->points[j].getNormalVector4fMap (), input_->points[j].getRGBVector4i (),
             p.f1, p.f2, p.f3, p.f4, p.r_ratio, p.g_ratio, p.b_ratio))
        {
          // Calculate alpha_m angle
          Eigen::Vector3f model_reference_point = input_->points[i].getVector3fMap (),
              model_reference_normal = normals_->points[i].getNormalVector3fMap (),
              model_point = input_->points[j].getVector3fMap ();
          Eigen::AngleAxisf rotation_mg (acos (model_reference_normal.dot (Eigen::Vector3f::UnitX ())),
                                         model_reference_normal.cross (Eigen::Vector3f::UnitX ()).normalized ());
          Eigen::Affine3f transform_mg = Eigen::Translation3f ( rotation_mg * ((-1) * model_reference_point)) * rotation_mg;

          Eigen::Vector3f model_point_transformed = transform_mg * model_point;
          float angle = atan2f ( -model_point_transformed(2), model_point_transformed(1));
          if (sin (angle) * model_point_transformed(2) < 0.0f)
            angle *= (-1);
          p.alpha_m = -angle;
        }
        else
        {
          PCL_ERROR ("[pcl::%s::computeFeature] Computing pair feature vector between points %zu and %zu went wrong.\n", getClassName ().c_str (), i, j);
          p.f1 = p.f2 = p.f3 = p.f4 = p.alpha_m = 0.0;
        }
      }
      // Do not calculate the feature for identity pairs (i, i) as they are not used
      // in the following computations
      else
        p.f1 = p.f2 = p.f3 = p.f4 = p.alpha_m = 0.0;

      output.points[index_i*input_->points.size () + j] = p;
    }
  }
}

//////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT, typename PointNT, typename PointOutT>
pcl::PPFRGBRegionEstimation<PointInT, PointNT, PointOutT>::PPFRGBRegionEstimation ()
: FeatureFromNormals <PointInT, PointNT, PointOutT> ()
{
  feature_name_ = "PPFRGBEstimation";
};

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT, typename PointNT, typename PointOutT> void
pcl::PPFRGBRegionEstimation<PointInT, PointNT, PointOutT>::computeFeature (PointCloudOut &output)
{
  PCL_INFO ("before computing output size: %u\n", output.size ());
  output.resize (indices_->size ());
  for (size_t index_i = 0; index_i < indices_->size (); ++index_i)
  {
    size_t i = (*indices_)[index_i];
    std::vector<int> nn_indices;
    std::vector<float> nn_distances;
    tree_->radiusSearch (i, search_radius_, nn_indices, nn_distances);

    PointOutT average_feature_nn;
    average_feature_nn.alpha_m = 0;
    average_feature_nn.f1 = average_feature_nn.f2 = average_feature_nn.f3 = average_feature_nn.f4 =
        average_feature_nn.r_ratio = average_feature_nn.g_ratio = average_feature_nn.b_ratio = 0.0f;

    for (std::vector<int>::iterator nn_it = nn_indices.begin (); nn_it != nn_indices.end (); ++nn_it)
    {
      size_t j = *nn_it;
      if (i != j)
      {
        float f1, f2, f3, f4, r_ratio, g_ratio, b_ratio;
        if (pcl::computeRGBPairFeatures
            (input_->points[i].getVector4fMap (), normals_->points[i].getNormalVector4fMap (), input_->points[i].getRGBVector4i (),
             input_->points[j].getVector4fMap (), normals_->points[j].getNormalVector4fMap (), input_->points[j].getRGBVector4i (),
             f1, f2, f3, f4, r_ratio, g_ratio, b_ratio))
        {
          average_feature_nn.f1 += f1;
          average_feature_nn.f2 += f2;
          average_feature_nn.f3 += f3;
          average_feature_nn.f4 += f4;
          average_feature_nn.r_ratio += r_ratio;
          average_feature_nn.g_ratio += g_ratio;
          average_feature_nn.b_ratio += b_ratio;
        }
        else
        {
          PCL_ERROR ("[pcl::%s::computeFeature] Computing pair feature vector between points %zu and %zu went wrong.\n", getClassName ().c_str (), i, j);
        }
      }
    }

    float normalization_factor = nn_indices.size ();
    average_feature_nn.f1 /= normalization_factor;
    average_feature_nn.f2 /= normalization_factor;
    average_feature_nn.f3 /= normalization_factor;
    average_feature_nn.f4 /= normalization_factor;
    average_feature_nn.r_ratio /= normalization_factor;
    average_feature_nn.g_ratio /= normalization_factor;
    average_feature_nn.b_ratio /= normalization_factor;
    output.points[index_i] = average_feature_nn;
  }
  PCL_INFO ("Output size: %u\n", output.points.size ());
}

#define PCL_INSTANTIATE_PPFRGBEstimation(T,NT,OutT) template class PCL_EXPORTS pcl::PPFRGBEstimation<T,NT,OutT>;
#define PCL_INSTANTIATE_PPFRGBRegionEstimation(T,NT,OutT) template class PCL_EXPORTS pcl::PPFRGBRegionEstimation<T,NT,OutT>;

#endif // PCL_FEATURES_IMPL_PPFRGB_H_
<|endoftext|>


<commit_before>#include "raytracing.h"
#include "misc/omputil.h"
#include "renderer/nonphotoreal.h"

namespace aten
{
    vec3 RayTracing::radiance(
        const context& ctxt,
        const ray& inRay,
        scene* scene)
    {
        uint32_t depth = 0;

        aten::ray ray = inRay;

        vec3 contribution = vec3(0, 0, 0);
        vec3 throughput = vec3(1, 1, 1);

        while (depth < m_maxDepth) {
            hitrecord rec;
            Intersection isect;

            if (scene->hit(ctxt, ray, AT_MATH_EPSILON, AT_MATH_INF, rec, isect)) {
                auto mtrl = ctxt.getMaterial(rec.mtrlid);

                if (mtrl->isEmissive()) {
                    auto emit = mtrl->color();
                    contribution += throughput * emit;
                    return std::move(contribution);
                }

                // 交差位置の法線.
                // 物体からのレイの入出を考慮.
                const vec3 orienting_normal = dot(rec.normal, ray.dir) < 0.0 ? rec.normal : -rec.normal;

                if (mtrl->isSingular() || mtrl->isTranslucent()) {
                    auto sampling = mtrl->sample(ray, orienting_normal, rec.normal, nullptr, rec.u, rec.v);

                    auto nextDir = normalize(sampling.dir);
                    auto bsdf = sampling.bsdf;

                    throughput *= bsdf;

                    // Make next ray.
                    ray = aten::ray(rec.p, nextDir, orienting_normal);
                }
                else if (mtrl->isNPR()) {
                    // Non-Photo-Real.
                    contribution = shadeNPR(ctxt, mtrl, rec.p, orienting_normal, rec.u, rec.v, scene, nullptr);
                    return std::move(contribution);
                }
                else {
                    auto lightNum = scene->lightNum();

                    for (int i = 0; i < lightNum; i++) {
                        auto light = scene->getLight(i);

                        if (light->isIBL()) {
                            continue;
                        }

                        auto sampleres = light->sample(ctxt, rec.p, nullptr);

                        vec3 dirToLight = sampleres.dir;
                        auto len = length(dirToLight);

                        dirToLight = normalize(dirToLight);

                        auto lightobj = sampleres.obj;

                        auto albedo = mtrl->color();

                        aten::ray shadowRay(rec.p, dirToLight, orienting_normal);

                        hitrecord tmpRec;

                        if (scene->hitLight(ctxt, light, sampleres.pos, shadowRay, AT_MATH_EPSILON, AT_MATH_INF, tmpRec)) {
                            auto lightColor = sampleres.finalColor;

                            if (light->isInfinite()) {
                                len = real(1);
                            }

                            const auto c0 = std::max(real(0.0), dot(orienting_normal, dirToLight));
                            real c1 = real(1);

                            if (!light->isSingular()) {
                                c1 = std::max(real(0.0), dot(sampleres.nml, -dirToLight));
                            }

                            auto G = c0 * c1 / (len * len);

                            contribution += throughput * (albedo * lightColor) * G;
                        }
                    }

                    break;
                }
            }
            else {
                auto ibl = scene->getIBL();

                if (ibl) {
                    auto bg = ibl->getEnvMap()->sample(ray);
                    contribution += throughput * bg;
                }
                else {
                    auto bg = sampleBG(ray);
                    contribution += throughput * bg;
                }

                return std::move(contribution);
            }

            depth++;
        }

        return contribution;
    }

    void RayTracing::onRender(
        const context& ctxt,
        Destination& dst,
        scene* scene,
        camera* camera)
    {
        int width = dst.width;
        int height = dst.height;

        m_maxDepth = dst.maxDepth;

        uint32_t sample = 1;

#ifdef ENABLE_OMP
#pragma omp parallel
#endif
        {
#ifdef ENABLE_OMP
#pragma omp for
#endif
            for (int y = 0; y < height; y++) {
                for (int x = 0; x < width; x++) {
                    //if (x == 419 && y == 107) {
                    //if (x == 408 && y == 112) {
                    if (x == 378 && y == 480 - 355) {
                        int xxx = 0;
                    }
                    int pos = y * width + x;

                    real u = (real(x) + real(0.5)) / real(width - 1);
                    real v = (real(y) + real(0.5)) / real(height - 1);

                    auto camsample = camera->sample(u, v, nullptr);

                    auto col = radiance(ctxt, camsample.r, scene);

                    dst.buffer->put(x, y, vec4(col, 1));
                }
            }
        }
    }
}
<commit_msg>Modify to pass normal to ray to compute offset<commit_after>#include "raytracing.h"
#include "misc/omputil.h"
#include "renderer/nonphotoreal.h"

namespace aten
{
    vec3 RayTracing::radiance(
        const context& ctxt,
        const ray& inRay,
        scene* scene)
    {
        uint32_t depth = 0;

        aten::ray ray = inRay;

        vec3 contribution = vec3(0, 0, 0);
        vec3 throughput = vec3(1, 1, 1);

        while (depth < m_maxDepth) {
            hitrecord rec;
            Intersection isect;

            if (scene->hit(ctxt, ray, AT_MATH_EPSILON, AT_MATH_INF, rec, isect)) {
                auto mtrl = ctxt.getMaterial(rec.mtrlid);

                if (mtrl->isEmissive()) {
                    auto emit = mtrl->color();
                    contribution += throughput * emit;
                    return std::move(contribution);
                }

                auto isBackfacing = dot(rec.normal, -ray.dir) < real(0.0);

                // 交差位置の法線.
                // 物体からのレイの入出を考慮.
                vec3 orienting_normal = rec.normal;
                if (!mtrl->isTranslucent() && isBackfacing) {
                    orienting_normal = -orienting_normal;
                }

                // Get normal to add ray offset.
                // In refraction material case, new ray direction might be computed with inverted normal.
                // For example, when a ray go into the refraction surface, inverted normal is used to compute new ray direction.
                auto rayBasedNormal = (!isBackfacing && mtrl->isTranslucent())
                    ? -orienting_normal
                    : orienting_normal;

                if (mtrl->isSingular() || mtrl->isTranslucent()) {
                    auto sampling = mtrl->sample(ray, orienting_normal, rec.normal, nullptr, rec.u, rec.v);

                    auto nextDir = normalize(sampling.dir);
                    auto bsdf = sampling.bsdf;

                    throughput *= bsdf;

                    // Make next ray.
                    ray = aten::ray(rec.p, nextDir, rayBasedNormal);
                }
                else if (mtrl->isNPR()) {
                    // Non-Photo-Real.
                    contribution = shadeNPR(ctxt, mtrl, rec.p, orienting_normal, rec.u, rec.v, scene, nullptr);
                    return std::move(contribution);
                }
                else {
                    auto lightNum = scene->lightNum();

                    for (int i = 0; i < lightNum; i++) {
                        auto light = scene->getLight(i);

                        if (light->isIBL()) {
                            continue;
                        }

                        // TODO
                        // In area light case, we don't specify sampler.
                        // So, in area light sampler, center of light is choosed
                        // as the position which ray try to reach to the light.
                        // But, if the light is square angle and it is composed of 2 triangles,
                        // center of the light might be edge of border of 2 triangles.
                        // Therefore, the ray might not hit any tirangles of the light.
                        // エリアライトの場合に、samplerがnullptrのときはライトのAABBの中心が
                        // レイの向かう先として選択される。
                        // その場合に、もしエリアライトが正方形で二つの三角形から構成されていたときに
                        // 中心位置は三角形の境目に位置していることになり、誤差等によりヒットしない可能性がある.
                        auto sampleres = light->sample(ctxt, rec.p, nullptr);

                        if (!light->isSingular() && !sampleres.obj) {
                            continue;
                        }

                        vec3 dirToLight = sampleres.dir;
                        auto len = length(dirToLight);

                        dirToLight = normalize(dirToLight);

                        if (dot(orienting_normal, dirToLight) < real(0)) {
                            continue;
                        }

                        auto albedo = mtrl->color();

                        aten::ray shadowRay(rec.p, dirToLight, orienting_normal);

                        hitrecord tmpRec;

                        if (scene->hitLight(ctxt, light, sampleres.pos, shadowRay, AT_MATH_EPSILON, AT_MATH_INF, tmpRec)) {
                            auto lightColor = sampleres.finalColor;

                            if (light->isInfinite()) {
                                len = real(1);
                            }

                            const auto c0 = std::max(real(0.0), dot(orienting_normal, dirToLight));
                            real c1 = real(1);

                            if (!light->isSingular()) {
                                c1 = std::max(real(0.0), dot(sampleres.nml, -dirToLight));
                            }

                            auto G = c0 * c1 / (len * len);

                            contribution += throughput * (albedo * lightColor) * G;
                        }
                    }

                    break;
                }
            }
            else {
                auto ibl = scene->getIBL();

                if (ibl) {
                    auto bg = ibl->getEnvMap()->sample(ray);
                    contribution += throughput * bg;
                }
                else {
                    auto bg = sampleBG(ray);
                    contribution += throughput * bg;
                }

                return std::move(contribution);
            }

            depth++;
        }

        return contribution;
    }

    void RayTracing::onRender(
        const context& ctxt,
        Destination& dst,
        scene* scene,
        camera* camera)
    {
        int width = dst.width;
        int height = dst.height;

        m_maxDepth = dst.maxDepth;

        uint32_t sample = 1;

#ifdef ENABLE_OMP
#pragma omp parallel
#endif
        {
#ifdef ENABLE_OMP
#pragma omp for
#endif
            for (int y = 0; y < height; y++) {
                for (int x = 0; x < width; x++) {
                    //if (x == 419 && y == 107) {
                    //if (x == 408 && y == 112) {
                    if (x == 259 && y == 0) {
                        int xxx = 0;
                    }
                    int pos = y * width + x;

                    real u = (real(x) + real(0.5)) / real(width - 1);
                    real v = (real(y) + real(0.5)) / real(height - 1);

                    auto camsample = camera->sample(u, v, nullptr);

                    auto col = radiance(ctxt, camsample.r, scene);

                    dst.buffer->put(x, y, vec4(col, 1));
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>#include "taskexecutor.h"
#include "../log/logger.h"
#include "../measurement/measurementfactory.h"
#include "../network/networkmanager.h"
#include "client.h"
#include "controller/ntpcontroller.h"
#include "localinformation.h"
#include "settings.h"

#include <QThread>
#include <QPointer>
#include <QElapsedTimer>

LOGGER(TaskExecutor);

class InternalTaskExecutor : public QObject
{
    Q_OBJECT

public:
    MeasurementFactory factory;
    QPointer<NetworkManager> networkManager;

    ScheduleDefinition currentTest;
    MeasurementPtr measurement;
    QElapsedTimer timer;

private:
    LocalInformation localInformation;

public slots:
    void execute(const ScheduleDefinition &test, MeasurementObserver *observer)
    {
        LOG_INFO(QString("Starting execution of %1").arg(test.name()));

        emit started(test);

        currentTest = test;
        measurement = factory.createMeasurement(test.name(), test.taskId());

        if (!measurement.isNull())
        {
            // get local information
            measurement->setPreInfo(localInformation.getVariables());

            connect(measurement.data(), SIGNAL(finished()), this, SLOT(measurementFinished()));
            connect(measurement.data(), SIGNAL(error(const QString &)), this, SLOT(measurementError(const QString &)));

            if (observer)
            {
                observer->created(measurement);
                delete observer;
            }

            if (networkManager->allInterfacesDown())
            {
                LOG_ERROR(QString("Unable to execute measurement, no interface is up: %1").arg(test.name()));
                measurementError("No interface is up");
                return;
            }

            MeasurementDefinitionPtr definition = factory.createMeasurementDefinition(test.name(), test.measurementDefinition());

            if (measurement->prepare(networkManager, definition))
            {
                // in case of no error this is the local information we want
                // because it is right before the actual measurement
                measurement->setPreInfo(localInformation.getVariables());
                measurement->setStartDateTime(Client::instance()->ntpController()->currentDateTime());
                timer.start();

                if (measurement->start())
                {
                    return;
                }
            }

            // the result should at least contain the errorString, as all the other
            // fields will be empty
            LOG_ERROR(QString("Finished execution of %1 (failed): %2").arg(test.name()).arg(measurement->errorString()));

            Result result;
            result.setStartDateTime(measurement->startDateTime());
            result.setEndDateTime(measurement->startDateTime().addMSecs(timer.elapsed()));
            result.setPreInfo(measurement->preInfo());
            result.setPostInfo(localInformation.getVariables());
            result.setErrorString(measurement->errorString());
            emit finished(test, result);

            measurement.clear();
        }
        else
        {
            LOG_ERROR(QString("Unable to create measurement: %1").arg(test.name()));
            emit finished(test, Result("Unable to create measurement"));
        }
    }

    void measurementFinished()
    {
        measurement->disconnect(this, SLOT(measurementFinished()));
        measurement->disconnect(this, SLOT(measurementError(const QString &)));

        LOG_INFO(QString("Finished execution of %1 (success)").arg(currentTest.name()));

        Result result = measurement->result();
        result.setStartDateTime(measurement->startDateTime());
        result.setEndDateTime(measurement->startDateTime().addMSecs(timer.elapsed()));
        result.setPreInfo(measurement->preInfo());
        result.setPostInfo(localInformation.getVariables());
        result.setErrorString(measurement->errorString()); // should be null

        emit finished(currentTest, result);
        measurement->stop();
        measurement.clear();
    }

    void measurementError(const QString &errorMsg)
    {
        measurement->disconnect(this, SLOT(measurementFinished()));
        measurement->disconnect(this, SLOT(measurementError(const QString &)));

        LOG_ERROR(QString("Finished execution of %1 (failed): %2").arg(currentTest.name()).arg(errorMsg));

        Result result;
        result.setStartDateTime(measurement->startDateTime());
        result.setEndDateTime(measurement->startDateTime().addMSecs(timer.elapsed()));
        result.setPreInfo(measurement->preInfo());
        result.setPostInfo(localInformation.getVariables());
        result.setErrorString(errorMsg);
        emit finished(currentTest, result);

        measurement->stop();
        measurement.clear();
    }

signals:
    void started(const ScheduleDefinition &test);
    void finished(const ScheduleDefinition &test, const Result &result);
};

class TaskExecutor::Private : public QObject
{
    Q_OBJECT

public:
    Private(TaskExecutor *q)
    : q(q)
    , running(false)
    {
        // Should we really have a background thread running
        // all the time?
        executor.moveToThread(&taskThread);
        taskThread.setObjectName("TaskExecutorThread");
        taskThread.start();

        connect(&executor, SIGNAL(started(ScheduleDefinition)), this, SLOT(onStarted()));
        connect(&executor, SIGNAL(finished(ScheduleDefinition, Result)), this, SLOT(onFinished()));

        connect(&executor, SIGNAL(started(ScheduleDefinition)), q, SIGNAL(started(ScheduleDefinition)));
        connect(&executor, SIGNAL(finished(ScheduleDefinition, Result)), q, SIGNAL(finished(ScheduleDefinition, Result)));
    }

    ~Private()
    {
        taskThread.quit();
        taskThread.wait();
    }

    struct QueueEntry
    {
        ScheduleDefinition definition;
        MeasurementObserver *observer;
    };

    TaskExecutor *q;

    // Properties
    bool running;
    QThread taskThread;
    InternalTaskExecutor executor;

    QList<QueueEntry> queue;

    // Functions

public slots:
    void onStarted();
    void onFinished();
};

void TaskExecutor::Private::onStarted()
{
    if (!running)
    {
        running = true;
        emit q->runningChanged(running);
    }
}

Q_DECLARE_METATYPE(MeasurementObserver *);

void TaskExecutor::Private::onFinished()
{
    if (queue.isEmpty())
    {
        running = false;
        emit q->runningChanged(running);
    }
    else
    {
        QueueEntry entry = queue.takeFirst();
        QMetaObject::invokeMethod(&executor, "execute", Qt::QueuedConnection, Q_ARG(ScheduleDefinition, entry.definition),
                                  Q_ARG(MeasurementObserver *, entry.observer));
    }
}

TaskExecutor::TaskExecutor()
: d(new Private(this))
{
    qRegisterMetaType<MeasurementObserver *>();
}

TaskExecutor::~TaskExecutor()
{
    delete d;
}

void TaskExecutor::setNetworkManager(NetworkManager *networkManager)
{
    d->executor.networkManager = networkManager;
}

NetworkManager *TaskExecutor::networkManager() const
{
    return d->executor.networkManager;
}

bool TaskExecutor::isRunning() const
{
    return d->running;
}

void TaskExecutor::execute(const ScheduleDefinition &test, MeasurementObserver *observer)
{
    // Check preconditions
    if (!test.precondition().check())
    {
        LOG_INFO(QString("Measurement not executed, preconditions not met: %1").arg(test.name()));
        return;
    }

    // Abort if mobile measurements are disallowed and we are on a mobile connection
    if (!Client::instance()->settings()->mobileMeasurementsActive() && d->executor.networkManager->onMobileConnection())
    {
        LOG_ERROR(QString("Unable to execute measurement, we are on a mobile connection or no interface is up: %1").arg(test.name()));
        return;
    }

    if (d->running == false)
    {
        d->running = true;
        emit runningChanged(d->running);

        QMetaObject::invokeMethod(&d->executor, "execute", Qt::QueuedConnection, Q_ARG(ScheduleDefinition, test),
                                  Q_ARG(MeasurementObserver *, observer));
    }
    else
    {
        TaskExecutor::Private::QueueEntry entry;
        entry.definition = test;
        entry.observer = observer;

        d->queue.append(entry);
    }
}

#include "taskexecutor.moc"
<commit_msg>change debug string<commit_after>#include "taskexecutor.h"
#include "../log/logger.h"
#include "../measurement/measurementfactory.h"
#include "../network/networkmanager.h"
#include "client.h"
#include "controller/ntpcontroller.h"
#include "localinformation.h"
#include "settings.h"

#include <QThread>
#include <QPointer>
#include <QElapsedTimer>

LOGGER(TaskExecutor);

class InternalTaskExecutor : public QObject
{
    Q_OBJECT

public:
    MeasurementFactory factory;
    QPointer<NetworkManager> networkManager;

    ScheduleDefinition currentTest;
    MeasurementPtr measurement;
    QElapsedTimer timer;

private:
    LocalInformation localInformation;

public slots:
    void execute(const ScheduleDefinition &test, MeasurementObserver *observer)
    {
        LOG_INFO(QString("Starting execution of %1").arg(test.name()));

        emit started(test);

        currentTest = test;
        measurement = factory.createMeasurement(test.name(), test.taskId());

        if (!measurement.isNull())
        {
            // get local information
            measurement->setPreInfo(localInformation.getVariables());

            connect(measurement.data(), SIGNAL(finished()), this, SLOT(measurementFinished()));
            connect(measurement.data(), SIGNAL(error(const QString &)), this, SLOT(measurementError(const QString &)));

            if (observer)
            {
                observer->created(measurement);
                delete observer;
            }

            if (networkManager->allInterfacesDown())
            {
                LOG_ERROR(QString("Unable to execute measurement, no interface is up: %1").arg(test.name()));
                measurementError("No interface is up");
                return;
            }

            MeasurementDefinitionPtr definition = factory.createMeasurementDefinition(test.name(), test.measurementDefinition());

            if (measurement->prepare(networkManager, definition))
            {
                // in case of no error this is the local information we want
                // because it is right before the actual measurement
                measurement->setPreInfo(localInformation.getVariables());
                measurement->setStartDateTime(Client::instance()->ntpController()->currentDateTime());
                timer.start();

                if (measurement->start())
                {
                    return;
                }
            }

            // the result should at least contain the errorString, as all the other
            // fields will be empty
            LOG_ERROR(QString("Finished execution of %1 (failed): %2").arg(test.name()).arg(measurement->errorString()));

            Result result;
            result.setStartDateTime(measurement->startDateTime());
            result.setEndDateTime(measurement->startDateTime().addMSecs(timer.elapsed()));
            result.setPreInfo(measurement->preInfo());
            result.setPostInfo(localInformation.getVariables());
            result.setErrorString(measurement->errorString());
            emit finished(test, result);

            measurement.clear();
        }
        else
        {
            LOG_ERROR(QString("Unable to create measurement: %1").arg(test.name()));
            emit finished(test, Result("Unable to create measurement"));
        }
    }

    void measurementFinished()
    {
        measurement->disconnect(this, SLOT(measurementFinished()));
        measurement->disconnect(this, SLOT(measurementError(const QString &)));

        LOG_INFO(QString("Finished execution of %1 (success)").arg(currentTest.name()));

        Result result = measurement->result();
        result.setStartDateTime(measurement->startDateTime());
        result.setEndDateTime(measurement->startDateTime().addMSecs(timer.elapsed()));
        result.setPreInfo(measurement->preInfo());
        result.setPostInfo(localInformation.getVariables());
        result.setErrorString(measurement->errorString()); // should be null

        emit finished(currentTest, result);
        measurement->stop();
        measurement.clear();
    }

    void measurementError(const QString &errorMsg)
    {
        measurement->disconnect(this, SLOT(measurementFinished()));
        measurement->disconnect(this, SLOT(measurementError(const QString &)));

        LOG_ERROR(QString("Finished execution of %1 (failed): %2").arg(currentTest.name()).arg(errorMsg));

        Result result;
        result.setStartDateTime(measurement->startDateTime());
        result.setEndDateTime(measurement->startDateTime().addMSecs(timer.elapsed()));
        result.setPreInfo(measurement->preInfo());
        result.setPostInfo(localInformation.getVariables());
        result.setErrorString(errorMsg);
        emit finished(currentTest, result);

        measurement->stop();
        measurement.clear();
    }

signals:
    void started(const ScheduleDefinition &test);
    void finished(const ScheduleDefinition &test, const Result &result);
};

class TaskExecutor::Private : public QObject
{
    Q_OBJECT

public:
    Private(TaskExecutor *q)
    : q(q)
    , running(false)
    {
        // Should we really have a background thread running
        // all the time?
        executor.moveToThread(&taskThread);
        taskThread.setObjectName("TaskExecutorThread");
        taskThread.start();

        connect(&executor, SIGNAL(started(ScheduleDefinition)), this, SLOT(onStarted()));
        connect(&executor, SIGNAL(finished(ScheduleDefinition, Result)), this, SLOT(onFinished()));

        connect(&executor, SIGNAL(started(ScheduleDefinition)), q, SIGNAL(started(ScheduleDefinition)));
        connect(&executor, SIGNAL(finished(ScheduleDefinition, Result)), q, SIGNAL(finished(ScheduleDefinition, Result)));
    }

    ~Private()
    {
        taskThread.quit();
        taskThread.wait();
    }

    struct QueueEntry
    {
        ScheduleDefinition definition;
        MeasurementObserver *observer;
    };

    TaskExecutor *q;

    // Properties
    bool running;
    QThread taskThread;
    InternalTaskExecutor executor;

    QList<QueueEntry> queue;

    // Functions

public slots:
    void onStarted();
    void onFinished();
};

void TaskExecutor::Private::onStarted()
{
    if (!running)
    {
        running = true;
        emit q->runningChanged(running);
    }
}

Q_DECLARE_METATYPE(MeasurementObserver *);

void TaskExecutor::Private::onFinished()
{
    if (queue.isEmpty())
    {
        running = false;
        emit q->runningChanged(running);
    }
    else
    {
        QueueEntry entry = queue.takeFirst();
        QMetaObject::invokeMethod(&executor, "execute", Qt::QueuedConnection, Q_ARG(ScheduleDefinition, entry.definition),
                                  Q_ARG(MeasurementObserver *, entry.observer));
    }
}

TaskExecutor::TaskExecutor()
: d(new Private(this))
{
    qRegisterMetaType<MeasurementObserver *>();
}

TaskExecutor::~TaskExecutor()
{
    delete d;
}

void TaskExecutor::setNetworkManager(NetworkManager *networkManager)
{
    d->executor.networkManager = networkManager;
}

NetworkManager *TaskExecutor::networkManager() const
{
    return d->executor.networkManager;
}

bool TaskExecutor::isRunning() const
{
    return d->running;
}

void TaskExecutor::execute(const ScheduleDefinition &test, MeasurementObserver *observer)
{
    // Check preconditions
    if (!test.precondition().check())
    {
        LOG_INFO(QString("Measurement not executed, preconditions not met: %1").arg(test.name()));
        return;
    }

    // Abort if mobile measurements are disallowed and we are on a mobile connection
    if (!Client::instance()->settings()->mobileMeasurementsActive() && d->executor.networkManager->onMobileConnection())
    {
        LOG_DEBUG(QString("Mobile measurements prohibited by settings: %1").arg(test.name()));
        return;
    }

    if (d->running == false)
    {
        d->running = true;
        emit runningChanged(d->running);

        QMetaObject::invokeMethod(&d->executor, "execute", Qt::QueuedConnection, Q_ARG(ScheduleDefinition, test),
                                  Q_ARG(MeasurementObserver *, observer));
    }
    else
    {
        TaskExecutor::Private::QueueEntry entry;
        entry.definition = test;
        entry.observer = observer;

        d->queue.append(entry);
    }
}

#include "taskexecutor.moc"
<|endoftext|>


<commit_before>//===- PreSelection.cpp - Specialize LLVM code for target machine ---------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the PreSelection pass which specializes LLVM code for a
// target machine, while remaining in legal portable LLVM form and
// preserving type information and type safety.  This is meant to enable
// dataflow optimizations on target-specific operations such as accesses to
// constants, globals, and array indexing.
//
//===----------------------------------------------------------------------===//

#include "SparcInternals.h"
#include "llvm/Constants.h"
#include "llvm/iMemory.h"
#include "llvm/iPHINode.h"
#include "llvm/iOther.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/InstVisitor.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/Scalar.h"
#include <algorithm>

namespace {

  //===--------------------------------------------------------------------===//
  // PreSelection Pass - Specialize LLVM code for the current target machine.
  //
  class PreSelection : public Pass, public InstVisitor<PreSelection> {
    const TargetInstrInfo &instrInfo;
    Module *TheModule;

    std::map<const Constant*, GlobalVariable*> gvars;

    GlobalVariable* getGlobalForConstant(Constant* CV) {
      std::map<const Constant*, GlobalVariable*>::iterator I = gvars.find(CV);
      if (I != gvars.end()) return I->second;    // global exists so return it

      return I->second = new GlobalVariable(CV->getType(), true,
                                            GlobalValue::InternalLinkage, CV,
                                            "immcst", TheModule);
    }

  public:
    PreSelection(const TargetMachine &T)
      : instrInfo(T.getInstrInfo()), TheModule(0) {}

    // run - apply this pass to the entire Module
    bool run(Module &M) {
      TheModule = &M;

      // Build reverse map for pre-existing global constants so we can find them
      for (Module::giterator I = M.gbegin(), E = M.gend(); I != E; ++I)
        if (I->hasInitializer() && I->isConstant())
          gvars[I->getInitializer()] = I;

      for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
        visit(*I);

      gvars.clear();
      return true;
    }

    // These methods do the actual work of specializing code
    void visitInstruction(Instruction &I);   // common work for every instr.
    void visitGetElementPtrInst(GetElementPtrInst &I);
    void visitCallInst(CallInst &I);
    void visitPHINode(PHINode &PN);

    // Helper functions for visiting operands of every instruction
    //
    // visitOperands() works on every operand in [firstOp, lastOp-1].
    // If lastOp==0, lastOp defaults to #operands or #incoming Phi values.
    //
    // visitOneOperand() does all the work for one operand.
    //
    void visitOperands(Instruction &I, int firstOp=0);
    void visitOneOperand(Instruction &I, Value* Op, unsigned opNum,
                         Instruction& insertBefore);
  };

  // Register the pass...
  RegisterOpt<PreSelection> X("preselect",
                              "Specialize LLVM code for a target machine",
                              createPreSelectionPass);
}  // end anonymous namespace

//------------------------------------------------------------------------------
// Helper functions used by methods of class PreSelection
//------------------------------------------------------------------------------

// getGlobalAddr(): Put address of a global into a v. register.
static GetElementPtrInst* getGlobalAddr(Value* ptr, Instruction& insertBefore) {
  if (isa<ConstantPointerRef>(ptr))
    ptr = cast<ConstantPointerRef>(ptr)->getValue();

  return (isa<GlobalVariable>(ptr))
    ? new GetElementPtrInst(ptr,
                    std::vector<Value*>(1, ConstantSInt::get(Type::LongTy, 0U)),
                    "addrOfGlobal", &insertBefore)
    : NULL;
}

// Wrapper on Constant::classof to use in find_if :-(
inline static bool nonConstant(const Use& U) {
  return ! isa<Constant>(U);
}

static Instruction* DecomposeConstantExpr(ConstantExpr* CE,
                                          Instruction& insertBefore)
{
  Value *getArg1, *getArg2;

  switch(CE->getOpcode())
    {
    case Instruction::Cast:
      getArg1 = CE->getOperand(0);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg1))
        getArg1 = DecomposeConstantExpr(CEarg, insertBefore);
      return new CastInst(getArg1, CE->getType(), "constantCast",&insertBefore);

    case Instruction::GetElementPtr:
      assert(find_if(CE->op_begin()+1, CE->op_end(),nonConstant) == CE->op_end()
             && "All indices in ConstantExpr getelementptr must be constant!");
      getArg1 = CE->getOperand(0);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg1))
        getArg1 = DecomposeConstantExpr(CEarg, insertBefore);
      else if (GetElementPtrInst* gep = getGlobalAddr(getArg1, insertBefore))
        getArg1 = gep;
      return new GetElementPtrInst(getArg1,
                          std::vector<Value*>(CE->op_begin()+1, CE->op_end()),
                          "constantGEP", &insertBefore);

    default:                            // must be a binary operator
      assert(CE->getOpcode() >= Instruction::BinaryOpsBegin &&
             CE->getOpcode() <  Instruction::BinaryOpsEnd &&
             "Unrecognized opcode in ConstantExpr");
      getArg1 = CE->getOperand(0);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg1))
        getArg1 = DecomposeConstantExpr(CEarg, insertBefore);
      getArg2 = CE->getOperand(1);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg2))
        getArg2 = DecomposeConstantExpr(CEarg, insertBefore);
      return BinaryOperator::create((Instruction::BinaryOps) CE->getOpcode(),
                                    getArg1, getArg2,
                                    "constantBinaryOp", &insertBefore);
    }
}

//------------------------------------------------------------------------------
// Instruction visitor methods to perform instruction-specific operations
//------------------------------------------------------------------------------
inline void
PreSelection::visitOneOperand(Instruction &I, Value* Op, unsigned opNum,
                              Instruction& insertBefore)
{
  assert(&insertBefore != NULL && "Must have instruction to insert before.");

  if (GetElementPtrInst* gep = getGlobalAddr(Op, insertBefore)) {
    I.setOperand(opNum, gep);           // replace global operand
    return;                             // nothing more to do for this op.
  }

  Constant* CV  = dyn_cast<Constant>(Op);
  if (CV == NULL)
    return;

  if (ConstantExpr* CE = dyn_cast<ConstantExpr>(CV)) {
    // load-time constant: factor it out so we optimize as best we can
    Instruction* computeConst = DecomposeConstantExpr(CE, insertBefore);
    I.setOperand(opNum, computeConst); // replace expr operand with result
  } else if (instrInfo.ConstantTypeMustBeLoaded(CV)) {
    // load address of constant into a register, then load the constant
    GetElementPtrInst* gep = getGlobalAddr(getGlobalForConstant(CV),
                                           insertBefore);
    LoadInst* ldI = new LoadInst(gep, "loadConst", &insertBefore);
    I.setOperand(opNum, ldI);        // replace operand with copy in v.reg.
  } else if (instrInfo.ConstantMayNotFitInImmedField(CV, &I)) {
    // put the constant into a virtual register using a cast
    CastInst* castI = new CastInst(CV, CV->getType(), "copyConst",
                                   &insertBefore);
    I.setOperand(opNum, castI);      // replace operand with copy in v.reg.
  }
}

// visitOperands() transforms individual operands of all instructions:
// -- Load "large" int constants into a virtual register.  What is large
//    depends on the type of instruction and on the target architecture.
// -- For any constants that cannot be put in an immediate field,
//    load address into virtual register first, and then load the constant.
//
// firstOp and lastOp can be used to skip leading and trailing operands.
// If lastOp is 0, it defaults to #operands or #incoming Phi values.
//
inline void PreSelection::visitOperands(Instruction &I, int firstOp) {
  // For any instruction other than PHI, copies go just before the instr.
  for (unsigned i = firstOp, e = I.getNumOperands(); i != e; ++i)
    visitOneOperand(I, I.getOperand(i), i, I);
}

void PreSelection::visitPHINode(PHINode &PN) {
  // For a PHI, operand copies must be before the terminator of the
  // appropriate predecessor basic block.  Remaining logic is simple
  // so just handle PHIs and other instructions separately.
  //
  for (unsigned i = 0, e = PN.getNumIncomingValues(); i != e; ++i)
    visitOneOperand(PN, PN.getIncomingValue(i),
                    PN.getOperandNumForIncomingValue(i),
                    *PN.getIncomingBlock(i)->getTerminator());
  // do not call visitOperands!
}

// Common work for *all* instructions.  This needs to be called explicitly
// by other visit<InstructionType> functions.
inline void PreSelection::visitInstruction(Instruction &I) {
  visitOperands(I);              // Perform operand transformations
}

// GetElementPtr instructions: check if pointer is a global
void PreSelection::visitGetElementPtrInst(GetElementPtrInst &I) {
  Instruction* curI = &I;

  // Decompose multidimensional array references
  if (I.getNumIndices() >= 2) {
    // DecomposeArrayRef() replaces I and deletes it, if successful,
    // so remember predecessor in order to find the replacement instruction.
    // Also remember the basic block in case there is no predecessor.
    Instruction* prevI = I.getPrev();
    BasicBlock* bb = I.getParent();
    if (DecomposeArrayRef(&I))
      // first instr. replacing I
      curI = cast<GetElementPtrInst>(prevI? prevI->getNext() : &bb->front());
  }

  // Perform other transformations common to all instructions
  visitInstruction(*curI);
}

void PreSelection::visitCallInst(CallInst &I) {
  // Tell visitOperands to ignore the function name if this is a direct call.
  visitOperands(I, (/*firstOp=*/ I.getCalledFunction()? 1 : 0));
}

//===----------------------------------------------------------------------===//
// createPreSelectionPass - Public entrypoint for pre-selection pass
// and this file as a whole...
//
Pass* createPreSelectionPass(TargetMachine &T) {
  return new PreSelection(T);
}
<commit_msg>No, really, order the #includes correctly.<commit_after>//===- PreSelection.cpp - Specialize LLVM code for target machine ---------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the PreSelection pass which specializes LLVM code for a
// target machine, while remaining in legal portable LLVM form and
// preserving type information and type safety.  This is meant to enable
// dataflow optimizations on target-specific operations such as accesses to
// constants, globals, and array indexing.
//
//===----------------------------------------------------------------------===//

#include "SparcInternals.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/iMemory.h"
#include "llvm/iPHINode.h"
#include "llvm/iOther.h"
#include "llvm/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/InstVisitor.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/Scalar.h"
#include <algorithm>

namespace {

  //===--------------------------------------------------------------------===//
  // PreSelection Pass - Specialize LLVM code for the current target machine.
  //
  class PreSelection : public Pass, public InstVisitor<PreSelection> {
    const TargetInstrInfo &instrInfo;
    Module *TheModule;

    std::map<const Constant*, GlobalVariable*> gvars;

    GlobalVariable* getGlobalForConstant(Constant* CV) {
      std::map<const Constant*, GlobalVariable*>::iterator I = gvars.find(CV);
      if (I != gvars.end()) return I->second;    // global exists so return it

      return I->second = new GlobalVariable(CV->getType(), true,
                                            GlobalValue::InternalLinkage, CV,
                                            "immcst", TheModule);
    }

  public:
    PreSelection(const TargetMachine &T)
      : instrInfo(T.getInstrInfo()), TheModule(0) {}

    // run - apply this pass to the entire Module
    bool run(Module &M) {
      TheModule = &M;

      // Build reverse map for pre-existing global constants so we can find them
      for (Module::giterator I = M.gbegin(), E = M.gend(); I != E; ++I)
        if (I->hasInitializer() && I->isConstant())
          gvars[I->getInitializer()] = I;

      for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
        visit(*I);

      gvars.clear();
      return true;
    }

    // These methods do the actual work of specializing code
    void visitInstruction(Instruction &I);   // common work for every instr.
    void visitGetElementPtrInst(GetElementPtrInst &I);
    void visitCallInst(CallInst &I);
    void visitPHINode(PHINode &PN);

    // Helper functions for visiting operands of every instruction
    //
    // visitOperands() works on every operand in [firstOp, lastOp-1].
    // If lastOp==0, lastOp defaults to #operands or #incoming Phi values.
    //
    // visitOneOperand() does all the work for one operand.
    //
    void visitOperands(Instruction &I, int firstOp=0);
    void visitOneOperand(Instruction &I, Value* Op, unsigned opNum,
                         Instruction& insertBefore);
  };

  // Register the pass...
  RegisterOpt<PreSelection> X("preselect",
                              "Specialize LLVM code for a target machine",
                              createPreSelectionPass);
}  // end anonymous namespace

//------------------------------------------------------------------------------
// Helper functions used by methods of class PreSelection
//------------------------------------------------------------------------------

// getGlobalAddr(): Put address of a global into a v. register.
static GetElementPtrInst* getGlobalAddr(Value* ptr, Instruction& insertBefore) {
  if (isa<ConstantPointerRef>(ptr))
    ptr = cast<ConstantPointerRef>(ptr)->getValue();

  return (isa<GlobalVariable>(ptr))
    ? new GetElementPtrInst(ptr,
                    std::vector<Value*>(1, ConstantSInt::get(Type::LongTy, 0U)),
                    "addrOfGlobal", &insertBefore)
    : NULL;
}

// Wrapper on Constant::classof to use in find_if :-(
inline static bool nonConstant(const Use& U) {
  return ! isa<Constant>(U);
}

static Instruction* DecomposeConstantExpr(ConstantExpr* CE,
                                          Instruction& insertBefore)
{
  Value *getArg1, *getArg2;

  switch(CE->getOpcode())
    {
    case Instruction::Cast:
      getArg1 = CE->getOperand(0);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg1))
        getArg1 = DecomposeConstantExpr(CEarg, insertBefore);
      return new CastInst(getArg1, CE->getType(), "constantCast",&insertBefore);

    case Instruction::GetElementPtr:
      assert(find_if(CE->op_begin()+1, CE->op_end(),nonConstant) == CE->op_end()
             && "All indices in ConstantExpr getelementptr must be constant!");
      getArg1 = CE->getOperand(0);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg1))
        getArg1 = DecomposeConstantExpr(CEarg, insertBefore);
      else if (GetElementPtrInst* gep = getGlobalAddr(getArg1, insertBefore))
        getArg1 = gep;
      return new GetElementPtrInst(getArg1,
                          std::vector<Value*>(CE->op_begin()+1, CE->op_end()),
                          "constantGEP", &insertBefore);

    default:                            // must be a binary operator
      assert(CE->getOpcode() >= Instruction::BinaryOpsBegin &&
             CE->getOpcode() <  Instruction::BinaryOpsEnd &&
             "Unrecognized opcode in ConstantExpr");
      getArg1 = CE->getOperand(0);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg1))
        getArg1 = DecomposeConstantExpr(CEarg, insertBefore);
      getArg2 = CE->getOperand(1);
      if (ConstantExpr* CEarg = dyn_cast<ConstantExpr>(getArg2))
        getArg2 = DecomposeConstantExpr(CEarg, insertBefore);
      return BinaryOperator::create((Instruction::BinaryOps) CE->getOpcode(),
                                    getArg1, getArg2,
                                    "constantBinaryOp", &insertBefore);
    }
}

//------------------------------------------------------------------------------
// Instruction visitor methods to perform instruction-specific operations
//------------------------------------------------------------------------------
inline void
PreSelection::visitOneOperand(Instruction &I, Value* Op, unsigned opNum,
                              Instruction& insertBefore)
{
  assert(&insertBefore != NULL && "Must have instruction to insert before.");

  if (GetElementPtrInst* gep = getGlobalAddr(Op, insertBefore)) {
    I.setOperand(opNum, gep);           // replace global operand
    return;                             // nothing more to do for this op.
  }

  Constant* CV  = dyn_cast<Constant>(Op);
  if (CV == NULL)
    return;

  if (ConstantExpr* CE = dyn_cast<ConstantExpr>(CV)) {
    // load-time constant: factor it out so we optimize as best we can
    Instruction* computeConst = DecomposeConstantExpr(CE, insertBefore);
    I.setOperand(opNum, computeConst); // replace expr operand with result
  } else if (instrInfo.ConstantTypeMustBeLoaded(CV)) {
    // load address of constant into a register, then load the constant
    GetElementPtrInst* gep = getGlobalAddr(getGlobalForConstant(CV),
                                           insertBefore);
    LoadInst* ldI = new LoadInst(gep, "loadConst", &insertBefore);
    I.setOperand(opNum, ldI);        // replace operand with copy in v.reg.
  } else if (instrInfo.ConstantMayNotFitInImmedField(CV, &I)) {
    // put the constant into a virtual register using a cast
    CastInst* castI = new CastInst(CV, CV->getType(), "copyConst",
                                   &insertBefore);
    I.setOperand(opNum, castI);      // replace operand with copy in v.reg.
  }
}

// visitOperands() transforms individual operands of all instructions:
// -- Load "large" int constants into a virtual register.  What is large
//    depends on the type of instruction and on the target architecture.
// -- For any constants that cannot be put in an immediate field,
//    load address into virtual register first, and then load the constant.
//
// firstOp and lastOp can be used to skip leading and trailing operands.
// If lastOp is 0, it defaults to #operands or #incoming Phi values.
//
inline void PreSelection::visitOperands(Instruction &I, int firstOp) {
  // For any instruction other than PHI, copies go just before the instr.
  for (unsigned i = firstOp, e = I.getNumOperands(); i != e; ++i)
    visitOneOperand(I, I.getOperand(i), i, I);
}

void PreSelection::visitPHINode(PHINode &PN) {
  // For a PHI, operand copies must be before the terminator of the
  // appropriate predecessor basic block.  Remaining logic is simple
  // so just handle PHIs and other instructions separately.
  //
  for (unsigned i = 0, e = PN.getNumIncomingValues(); i != e; ++i)
    visitOneOperand(PN, PN.getIncomingValue(i),
                    PN.getOperandNumForIncomingValue(i),
                    *PN.getIncomingBlock(i)->getTerminator());
  // do not call visitOperands!
}

// Common work for *all* instructions.  This needs to be called explicitly
// by other visit<InstructionType> functions.
inline void PreSelection::visitInstruction(Instruction &I) {
  visitOperands(I);              // Perform operand transformations
}

// GetElementPtr instructions: check if pointer is a global
void PreSelection::visitGetElementPtrInst(GetElementPtrInst &I) {
  Instruction* curI = &I;

  // Decompose multidimensional array references
  if (I.getNumIndices() >= 2) {
    // DecomposeArrayRef() replaces I and deletes it, if successful,
    // so remember predecessor in order to find the replacement instruction.
    // Also remember the basic block in case there is no predecessor.
    Instruction* prevI = I.getPrev();
    BasicBlock* bb = I.getParent();
    if (DecomposeArrayRef(&I))
      // first instr. replacing I
      curI = cast<GetElementPtrInst>(prevI? prevI->getNext() : &bb->front());
  }

  // Perform other transformations common to all instructions
  visitInstruction(*curI);
}

void PreSelection::visitCallInst(CallInst &I) {
  // Tell visitOperands to ignore the function name if this is a direct call.
  visitOperands(I, (/*firstOp=*/ I.getCalledFunction()? 1 : 0));
}

//===----------------------------------------------------------------------===//
// createPreSelectionPass - Public entrypoint for pre-selection pass
// and this file as a whole...
//
Pass* createPreSelectionPass(TargetMachine &T) {
  return new PreSelection(T);
}
<|endoftext|>