<commit_before>// ///////////////////////////////////////////////////////////////////////////
// tenh/meta/typestringof.hpp by Victor Dods, created 2013/02/16
// Copyright Leap Motion Inc.
// ///////////////////////////////////////////////////////////////////////////
/// @file typestringof.hpp
/// @headerfile typestringof.hpp "tenh/meta/typestringof.hpp"
/// @brief Contains runtime and compile time functions for generating strings associated
/// with type names, and for making pretty versions of the same.
#ifndef TENH_META_TYPESTRINGOF_HPP_
#define TENH_META_TYPESTRINGOF_HPP_

#include <complex>
#include <ostream>
#include <string>

#include "tenh/core.hpp"

namespace Tenh {

/// @def AS_STRING(X)
/// @brief Converts built-in types to `std::string` for ease of building type strings.
#define AS_STRING(x) static_cast<std::ostringstream &>(std::ostringstream().flush() << x).str()

/// @struct TypeStringOf_t typestringof.hpp "tenh/meta/typestringof.hpp"
/// @brief Template Meta Function to obtain a string from a typename.
/// @details TypeStringOf_t requires that any user-defined types that it may be passed have a static member
/// function `type_as_string()` which returns a `std::string` containing the name of that type.
/// @tparam T The type to generate a string for.

// by default we call the type's type_as_string static member.
template <typename T> struct TypeStringOf_t { static std::string eval () { return T::type_as_string(); } };

/// @cond false
// template overloads to accomodate built in types and types in the std namespace.
template <> struct TypeStringOf_t<Sint8> { static std::string eval () { return "Sint8"; } };
template <> struct TypeStringOf_t<Uint8> { static std::string eval () { return "Uint8"; } };
template <> struct TypeStringOf_t<Sint16> { static std::string eval () { return "Sint16"; } };
template <> struct TypeStringOf_t<Uint16> { static std::string eval () { return "Uint16"; } };
template <> struct TypeStringOf_t<Sint32> { static std::string eval () { return "Sint32"; } };
template <> struct TypeStringOf_t<Uint32> { static std::string eval () { return "Uint32"; } };
template <> struct TypeStringOf_t<Sint64> { static std::string eval () { return "Sint64"; } };
template <> struct TypeStringOf_t<Uint64> { static std::string eval () { return "Uint64"; } };
template <> struct TypeStringOf_t<bool> { static std::string eval () { return "bool"; } };
template <> struct TypeStringOf_t<float> { static std::string eval () { return "float"; } };
template <> struct TypeStringOf_t<double> { static std::string eval () { return "double"; } };
template <> struct TypeStringOf_t<long double> { static std::string eval () { return "long double"; } };
template <> struct TypeStringOf_t<std::string> { static std::string eval () { return "std::string"; } };
template <typename T>
struct TypeStringOf_t<std::complex<T> >
{
    static std::string eval () { return "complex<" + TypeStringOf_t<T>::eval() + '>'; }
};

template <typename T_>
struct TypeStringOf_t<Type_t<T_> >
{
    static std::string eval () { return "Type_t<" + TypeStringOf_t<T_>::eval() + '>'; }
};

template <typename T_, T_ VALUE_>
struct TypeStringOf_t<Value_t<T_,VALUE_> >
{
    static std::string eval () { return "Value_t<" + TypeStringOf_t<T_>::eval() + ',' + AS_STRING(VALUE_) + '>'; }
};

template <> struct TypeStringOf_t<NullValue> { static std::string eval () { return "NullValue"; } };
/// @endcond

/// @brief Overload for operator<< to stream objects of type TypeStringOf_t
template <typename T_>
std::ostream &operator << (std::ostream &out, TypeStringOf_t<T_> const &)
{
    return out << TypeStringOf_t<T_>::eval();
}

/// @brief Returns the type string of the given type instance.
template <typename T_>
std::string type_string_of (T_ const &)
{
    return TypeStringOf_t<T_>::eval();
}

/// @brief Returns the type string of the given explicitly specified type T_.
/// @tparam T_ The type for which to generate the type string.
template <typename T_>
std::string type_string_of ()
{
    return TypeStringOf_t<T_>::eval();
}

/// @struct Pretty typestringof.hpp "tenh/meta/typestringof.hpp"
/// @brief Used as a tag for "pretty" printing of type strings.
/// @details Exists in order to allow an overload of operator<< for TypeStringOf_t which uses print_pretty_typestring
///  with a non-default value for shortify_depth.
/// @tparam TypeStringOf_ An instance of the TypeStringOf_t template which we wish to print "prettified"
/// @tparam SHORTIFY_DEPTH How deep should template parameters be allowed to go
template <typename TypeStringOf_, Uint32 SHORTIFY_DEPTH_ = 0>
struct Pretty
{
    /** @brief Acessor typedef for template parameter */
    typedef TypeStringOf_ TypeStringOf;
    /** @brief Acessor for template parameter */
    static Uint32 const SHORTIFY_DEPTH = SHORTIFY_DEPTH_;
};

/// @brief Output a "prettified" version of a typestring.
/// @details This function goes through a typestring and indents the template parameters as one might
///          indent blocks of code, and does folding of template parameters deeper than the `shortify_depth`
///          parameter.
/// @param out is the ostream to output to
/// @param typestring is the typestring to prettify and output
/// @param shortify_depth is the depth at which "template arguments" are replaced with an ellipsis;
///        a shortify_depth of 0 means that no ellipsis-collapsing will be done, and e.g. a
///        shortify_depth of 1 will produce something like FooBar<...>.
/// @param indent_size is the number of spaces to use for indenting.
/// @param indent_level gives the starting indentation level
inline void print_pretty_typestring (std::ostream &out,
                                     std::string const &typestring,
                                     Uint32 shortify_depth = 0,
                                     Uint32 indent_size = 4,
                                     Uint32 indent_level = 0)
{
    Uint32 template_argument_depth = 0;
    for (std::string::const_iterator it = typestring.begin(), it_end = typestring.end(); it != it_end; ++it)
    {
        char const &c = *it;
        switch (c)
        {
            case '<':
                ++template_argument_depth;
                // we're shortified, so print the shortified "template arguments"
                if (shortify_depth > 0 && template_argument_depth == shortify_depth)
                {
                    out << "<...>";
                }
                else if (shortify_depth == 0 || template_argument_depth < shortify_depth)
                {
                    ++indent_level;
                    out << "<\n" << std::string(indent_level*indent_size, ' ');
                }
                break;

            case ',':
                // chomp up all whitespace
                while (true)
                {
                    std::string::const_iterator next_it = it;
                    ++next_it;
                    if (next_it == it_end)
                        break;
                    char const &next_c = *next_it;
                    if (next_c != ' ' && next_c != '\t' && next_c != '\n')
                        break;
                    ++it;
                }
                // if we're not in a template parameter list, just print the ',' as normal
                if (template_argument_depth == 0)
                {
                    out << ',';
                }
                // otherwise only print stuff if we're not shortified
                else if (shortify_depth == 0 || template_argument_depth < shortify_depth)
                {
                    out << ",\n" << std::string(indent_level*indent_size, ' ');
                }
                break;

            case '>':
                // only print stuff if we're not shortified
                if (shortify_depth == 0 || template_argument_depth < shortify_depth)
                {
                    // presumably the < and > brackets will be balanced, but in case they're not...
                    if (indent_level > 0)
                        --indent_level;
                    out << '\n' << std::string(indent_level*indent_size, ' ') << '>';
                }
                if (template_argument_depth)
                    --template_argument_depth;
                break;

            default:
                // only print stuff if we're not shortified
                if (shortify_depth == 0 || template_argument_depth < shortify_depth)
                    out << c;
                break;
        }
    }
}

/// @brief Overload for operator<< to stream objects of type Pretty
template <typename T_, Uint32 SHORTIFY_DEPTH_>
std::ostream &operator << (std::ostream &out, Pretty<TypeStringOf_t<T_>,SHORTIFY_DEPTH_> const &)
{
    print_pretty_typestring(out, TypeStringOf_t<T_>::eval(), SHORTIFY_DEPTH_);
    return out;
}

} // end of namespace Tenh

#endif // TENH_META_TYPESTRINGOF_HPP_
<commit_msg>Added two pretty_type_string_of<...> functions for use in printing prettified type strings for debugging purposes.<commit_after>// ///////////////////////////////////////////////////////////////////////////
// tenh/meta/typestringof.hpp by Victor Dods, created 2013/02/16
// Copyright Leap Motion Inc.
// ///////////////////////////////////////////////////////////////////////////
/// @file typestringof.hpp
/// @headerfile typestringof.hpp "tenh/meta/typestringof.hpp"
/// @brief Contains runtime and compile time functions for generating strings associated
/// with type names, and for making pretty versions of the same.
#ifndef TENH_META_TYPESTRINGOF_HPP_
#define TENH_META_TYPESTRINGOF_HPP_

#include <complex>
#include <ostream>
#include <string>

#include "tenh/core.hpp"

namespace Tenh {

/// @def AS_STRING(X)
/// @brief Converts built-in types to `std::string` for ease of building type strings.
#define AS_STRING(x) static_cast<std::ostringstream &>(std::ostringstream().flush() << x).str()

/// @struct TypeStringOf_t typestringof.hpp "tenh/meta/typestringof.hpp"
/// @brief Template Meta Function to obtain a string from a typename.
/// @details TypeStringOf_t requires that any user-defined types that it may be passed have a static member
/// function `type_as_string()` which returns a `std::string` containing the name of that type.
/// @tparam T The type to generate a string for.

// by default we call the type's type_as_string static member.
template <typename T> struct TypeStringOf_t { static std::string eval () { return T::type_as_string(); } };

/// @cond false
// template overloads to accomodate built in types and types in the std namespace.
template <> struct TypeStringOf_t<Sint8> { static std::string eval () { return "Sint8"; } };
template <> struct TypeStringOf_t<Uint8> { static std::string eval () { return "Uint8"; } };
template <> struct TypeStringOf_t<Sint16> { static std::string eval () { return "Sint16"; } };
template <> struct TypeStringOf_t<Uint16> { static std::string eval () { return "Uint16"; } };
template <> struct TypeStringOf_t<Sint32> { static std::string eval () { return "Sint32"; } };
template <> struct TypeStringOf_t<Uint32> { static std::string eval () { return "Uint32"; } };
template <> struct TypeStringOf_t<Sint64> { static std::string eval () { return "Sint64"; } };
template <> struct TypeStringOf_t<Uint64> { static std::string eval () { return "Uint64"; } };
template <> struct TypeStringOf_t<bool> { static std::string eval () { return "bool"; } };
template <> struct TypeStringOf_t<float> { static std::string eval () { return "float"; } };
template <> struct TypeStringOf_t<double> { static std::string eval () { return "double"; } };
template <> struct TypeStringOf_t<long double> { static std::string eval () { return "long double"; } };
template <> struct TypeStringOf_t<std::string> { static std::string eval () { return "std::string"; } };
template <typename T>
struct TypeStringOf_t<std::complex<T> >
{
    static std::string eval () { return "complex<" + TypeStringOf_t<T>::eval() + '>'; }
};

template <typename T_>
struct TypeStringOf_t<Type_t<T_> >
{
    static std::string eval () { return "Type_t<" + TypeStringOf_t<T_>::eval() + '>'; }
};

template <typename T_, T_ VALUE_>
struct TypeStringOf_t<Value_t<T_,VALUE_> >
{
    static std::string eval () { return "Value_t<" + TypeStringOf_t<T_>::eval() + ',' + AS_STRING(VALUE_) + '>'; }
};

template <> struct TypeStringOf_t<NullValue> { static std::string eval () { return "NullValue"; } };
/// @endcond

/// @brief Overload for operator<< to stream objects of type TypeStringOf_t
template <typename T_>
std::ostream &operator << (std::ostream &out, TypeStringOf_t<T_> const &)
{
    return out << TypeStringOf_t<T_>::eval();
}

/// @brief Returns the type string of the given type instance.
template <typename T_>
std::string type_string_of (T_ const &)
{
    return TypeStringOf_t<T_>::eval();
}

/// @brief Returns the type string of the given explicitly specified type T_.
/// @tparam T_ The type for which to generate the type string.
template <typename T_>
std::string type_string_of ()
{
    return TypeStringOf_t<T_>::eval();
}

/// @struct Pretty typestringof.hpp "tenh/meta/typestringof.hpp"
/// @brief Used as a tag for "pretty" printing of type strings.
/// @details Exists in order to allow an overload of operator<< for TypeStringOf_t which uses print_pretty_typestring
///  with a non-default value for shortify_depth.
/// @tparam TypeStringOf_ An instance of the TypeStringOf_t template which we wish to print "prettified"
/// @tparam SHORTIFY_DEPTH How deep should template parameters be allowed to go
template <typename TypeStringOf_, Uint32 SHORTIFY_DEPTH_ = 0>
struct Pretty
{
    /** @brief Acessor typedef for template parameter */
    typedef TypeStringOf_ TypeStringOf;
    /** @brief Acessor for template parameter */
    static Uint32 const SHORTIFY_DEPTH = SHORTIFY_DEPTH_;
};

/// @brief Output a "prettified" version of a typestring.
/// @details This function goes through a typestring and indents the template parameters as one might
///          indent blocks of code, and does folding of template parameters deeper than the `shortify_depth`
///          parameter.
/// @param out is the ostream to output to
/// @param typestring is the typestring to prettify and output
/// @param shortify_depth is the depth at which "template arguments" are replaced with an ellipsis;
///        a shortify_depth of 0 means that no ellipsis-collapsing will be done, and e.g. a
///        shortify_depth of 1 will produce something like FooBar<...>.
/// @param indent_size is the number of spaces to use for indenting.
/// @param indent_level gives the starting indentation level
inline void print_pretty_typestring (std::ostream &out,
                                     std::string const &typestring,
                                     Uint32 shortify_depth = 0,
                                     Uint32 indent_size = 4,
                                     Uint32 indent_level = 0)
{
    Uint32 template_argument_depth = 0;
    for (std::string::const_iterator it = typestring.begin(), it_end = typestring.end(); it != it_end; ++it)
    {
        char const &c = *it;
        switch (c)
        {
            case '<':
                ++template_argument_depth;
                // we're shortified, so print the shortified "template arguments"
                if (shortify_depth > 0 && template_argument_depth == shortify_depth)
                {
                    out << "<...>";
                }
                else if (shortify_depth == 0 || template_argument_depth < shortify_depth)
                {
                    ++indent_level;
                    out << "<\n" << std::string(indent_level*indent_size, ' ');
                }
                break;

            case ',':
                // chomp up all whitespace
                while (true)
                {
                    std::string::const_iterator next_it = it;
                    ++next_it;
                    if (next_it == it_end)
                        break;
                    char const &next_c = *next_it;
                    if (next_c != ' ' && next_c != '\t' && next_c != '\n')
                        break;
                    ++it;
                }
                // if we're not in a template parameter list, just print the ',' as normal
                if (template_argument_depth == 0)
                {
                    out << ',';
                }
                // otherwise only print stuff if we're not shortified
                else if (shortify_depth == 0 || template_argument_depth < shortify_depth)
                {
                    out << ",\n" << std::string(indent_level*indent_size, ' ');
                }
                break;

            case '>':
                // only print stuff if we're not shortified
                if (shortify_depth == 0 || template_argument_depth < shortify_depth)
                {
                    // presumably the < and > brackets will be balanced, but in case they're not...
                    if (indent_level > 0)
                        --indent_level;
                    out << '\n' << std::string(indent_level*indent_size, ' ') << '>';
                }
                if (template_argument_depth)
                    --template_argument_depth;
                break;

            default:
                // only print stuff if we're not shortified
                if (shortify_depth == 0 || template_argument_depth < shortify_depth)
                    out << c;
                break;
        }
    }
}

/// @brief Overload for operator<< to stream objects of type Pretty
template <typename T_, Uint32 SHORTIFY_DEPTH_>
std::ostream &operator << (std::ostream &out, Pretty<TypeStringOf_t<T_>,SHORTIFY_DEPTH_> const &)
{
    print_pretty_typestring(out, TypeStringOf_t<T_>::eval(), SHORTIFY_DEPTH_);
    return out;
}

/// @brief Returns the prettified type string of the given type instance.
template <Uint32 SHORTIFY_DEPTH_, typename T_>
std::string pretty_type_string_of (T_ const &)
{
    std::ostringstream out;
    print_pretty_typestring(out, TypeStringOf_t<T_>::eval(), SHORTIFY_DEPTH_);
    return out.str();
}

/// @brief Returns the type string of the given explicitly specified type T_.
/// @tparam T_ The type for which to generate the type string.
template <Uint32 SHORTIFY_DEPTH_, typename T_>
std::string pretty_type_string_of ()
{
    std::ostringstream out;
    print_pretty_typestring(out, TypeStringOf_t<T_>::eval(), SHORTIFY_DEPTH_);
    return out.str();
}

} // end of namespace Tenh

#endif // TENH_META_TYPESTRINGOF_HPP_
<|endoftext|>


<commit_before>//===---------------------- SymbolicRangeAnalysis.cpp ---------------------===//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "sra"

#include "SymbolicRangeAnalysis.h"

#include "llvm/IR/Constants.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"

raw_ostream& operator<<(raw_ostream& OS, const SymbolicRangeAnalysis& SRR) {
  SRR.print(OS, nullptr);
  return OS;
}

using namespace llvm;

static RegisterPass<SymbolicRangeAnalysis>
  X("sra", "Symbolic range analysis with SAGE and QEPCAD");
char SymbolicRangeAnalysis::ID = 0;

static cl::opt<bool>
    ShouldUseSymBounds("sra-use-sym-bounds", cl::init(false), cl::Hidden,
        cl::desc("Use symbolic mins & maxes for integer bounds"));

static cl::opt<int>
    MaxPhiEvalSize("sra-max-phi-eval-size", cl::init(-1), cl::Hidden,
        cl::desc("Maximum number of operands on phi nodes, phi nodes which"
            "have more will not be evaluated"));

const unsigned CHANGED_LOWER = 1 << 0;
const unsigned CHANGED_UPPER = 1 << 1;

static SAGERange GetBoundsForTy(Type *Ty, SAGEInterface *SI) {
  unsigned Width = Ty->getIntegerBitWidth();
  if (ShouldUseSymBounds) {
    switch (Width) {
      case 8:
        return SAGERange(SAGEExpr(*SI, "UCHAR_MAX"), SAGEExpr(*SI, "CHAR_MIN"));
      case 16:
        return SAGERange(SAGEExpr(*SI, "USHRT_MAX"), SAGEExpr(*SI, "SHRT_MIN"));
      case 32:
        return SAGERange(SAGEExpr(*SI, "UINT_MAX"), SAGEExpr(*SI, "INT_MIN"));
      case 64:
        return SAGERange(SAGEExpr(*SI, "ULONG_MAX"), SAGEExpr(*SI, "LONG_MIN"));
    }
  }
  uint64_t Upper = APInt::getMaxValue(Width).getZExtValue();
  int64_t Lower = APInt::getSignedMinValue(Width).getSExtValue();
  return SAGERange(SAGEExpr(*SI, Upper), SAGEExpr(*SI, Lower));
}

static SAGERange GetBoundsForValue(Value *V, SAGEInterface *SI) {
  return GetBoundsForTy(V->getType(), SI);
}

static SAGERange BinaryOp(BinaryOperator *BO, SymbolicRangeAnalysis *SRA) {
  DEBUG(dbgs() << "SRA: BinaryOp: " << *BO << "\n");

  auto LHS = SRA->getStateOrInf(BO->getOperand(0)),
       RHS = SRA->getStateOrInf(BO->getOperand(1));

  switch (BO->getOpcode()) {
    case Instruction::Add:
      return LHS + RHS;
    case Instruction::Sub:
      return LHS - RHS;
    case Instruction::Mul:
      return LHS * RHS;
    case Instruction::SDiv:
    case Instruction::UDiv:
      return LHS/RHS;
    default:
      return GetBoundsForValue(BO, &SRA->getSI());
  }
}

static SAGERange Narrow(PHINode *Phi, Value *V, ICmpInst::Predicate Pred,
                        SymbolicRangeAnalysis *SRA) {
  DEBUG(dbgs() << "SRA: Narrow: " << *Phi << ", " << *V << "\n");

  auto Ret   = SRA->getStateOrInf(Phi->getIncomingValue(0)),
       Bound = SRA->getState(V);

  std::set<SAGEExpr> Set;
  switch (Pred) {
    case CmpInst::ICMP_SLT:
    case CmpInst::ICMP_ULT:
      Ret.setUpper(Bound.getUpper() - 1);
      break;
    case CmpInst::ICMP_SLE:
    case CmpInst::ICMP_ULE:
      Ret.setUpper(Bound.getUpper());
      break;
    case CmpInst::ICMP_SGT:
    case CmpInst::ICMP_UGT:
      Ret.setLower(Bound.getLower() + 1);
      break;
    case CmpInst::ICMP_SGE:
    case CmpInst::ICMP_UGE:
      Ret.setLower(Bound.getLower());
      break;
    case CmpInst::ICMP_EQ:
      Ret = Bound;
      break;
    default:
      break;
  }
  return Ret;
}

static SAGERange Meet(PHINode *Phi, SymbolicRangeAnalysis *SRA) {
  DEBUG(dbgs() << "SRA: Meet: " << *Phi << "\n");

  if (MaxPhiEvalSize > 0 && Phi->getNumOperands() > (unsigned) MaxPhiEvalSize) {
    SAGERange Ret =
        GetBoundsForTy(cast<IntegerType>(Phi->getType()), &SRA->getSI());
    Ret.setLower(Ret.getLower());
    Ret.setUpper(Ret.getUpper());
    return Ret;
  }

  SAGERange Ret = SRA->getState(Phi->getIncomingValue(0));
  auto OI = Phi->op_begin(), OE = Phi->op_end();
  for (; Ret == SRA->getBottom() && OI != OE; ++OI)
    Ret = SRA->getState(*OI);

  for (; OI != OE; ++OI) {
    SAGERange Incoming = SRA->getState(*OI);
    if (Incoming == SRA->getBottom())
      continue;
    Ret.setLower(Ret.getLower().min(Incoming.getLower()));
    Ret.setUpper(Ret.getUpper().max(Incoming.getUpper()));
  }
  return Ret;
}

void SymbolicRangeAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.addRequired<SAGEInterface>();
  AU.addRequired<Redefinition>();
  AU.setPreservesAll();
}

bool SymbolicRangeAnalysis::runOnFunction(Function& F) {
  Module_ = F.getParent();
  SI_ = &getAnalysis<SAGEInterface>();

  dbgs() << "SRA: runOnModule: " << F.getName() << "\n";

  RDF_ = &getAnalysis<Redefinition>();

  initialize(&F);
  reset(&F);
  iterate(&F);
  reset(&F);
  iterate(&F);
  reset(&F);
  iterate(&F);
  widen(&F);

  DEBUG(dbgs() << *this << "\n");

  return false;
}

SAGEExpr SymbolicRangeAnalysis::getBottomExpr() const {
  static SAGEExpr BottomExpr(*SI_, "_BOT_");
  return BottomExpr;
}

SAGERange SymbolicRangeAnalysis::getBottom() const {
  static SAGERange BottomRange(getBottomExpr());
  return BottomRange;
}

std::string SymbolicRangeAnalysis::makeName(Function *F, Value *V) {
  static unsigned Temp = 1;
  if (V->hasName()) {
    auto Name = (F->getName() + Twine("_") + V->getName()).str();
    std::replace(Name.begin(), Name.end(), '.', '_');
    return Name;
  } else {
    auto Name = F->getName() + Twine("_") + Twine(Temp++);
    return Name.str();
  }
}

void SymbolicRangeAnalysis::setName(Value *V, std::string Name) {
  Name_[V] = Name;
  Value_[Name] = V;
}

std::string SymbolicRangeAnalysis::getName(Value *V) const {
  auto It = Name_.find(V);
  assert(It != Name_.end() && "Requested value is not in map");
  return It->second;
}

void SymbolicRangeAnalysis::setState(Value *V, SAGERange Range) {
  DEBUG(dbgs() << "SRA: setState(" << *V << "," << Range << ")\n");
  auto It = State_.insert(std::make_pair(V, Range));
  if (!It.second) {
    if (It.first->second != Range)
      setChanged(V, It.first->second, Range);
    It.first->second = Range;
  } else if (isa<Instruction>(V)) {
    Changed_[V] = CHANGED_LOWER | CHANGED_UPPER;
  }
}

void SymbolicRangeAnalysis::setChanged(Value *V, SAGERange &Prev,
                                       SAGERange &New) {
  Changed_[V] = (Prev.getLower().isNE(New.getLower()) ? CHANGED_LOWER : 0) |
                (Prev.getUpper().isNE(New.getUpper()) ? CHANGED_UPPER : 0);
}

SAGERange SymbolicRangeAnalysis::getState(Value *V) const {
  // TODO: Handle ptrtoint.
  if (ConstantInt *CI = dyn_cast<ConstantInt>(V))
    return SAGEExpr(*SI_, CI->getValue().getSExtValue());
  if (isa<UndefValue>(V) || isa<Constant>(V))
    return GetBoundsForValue(V, SI_);
  auto It = State_.find(V);
  assert(It != State_.end() && "Requested value is not in map");
  return It->second;
}

SAGERange SymbolicRangeAnalysis::getStateOrInf(Value *V) const {
  auto State = getState(V);
  return State != getBottom()
      ? State : GetBoundsForTy(cast<IntegerType>(V->getType()), SI_);
}

std::pair<Value*, Value*>
    SymbolicRangeAnalysis::getRangeValuesFor(Value *V, IRBuilder<> IRB) const {
  SAGERange Range = getStateOrInf(V);
  IntegerType *Ty = cast<IntegerType>(V->getType());
  Value *Lower = Range.getLower().toValue(Ty, IRB, Value_, Module_),
        *Upper = Range.getUpper().toValue(Ty, IRB, Value_, Module_);
  return std::make_pair(Lower, Upper);
}

void SymbolicRangeAnalysis::createNarrowingFn(Value *LHS, Value *RHS,
                                      CmpInst::Predicate Pred, BasicBlock *BB) {
  if (auto Redef = RDF_->getRedef(LHS, BB))
    Fn_[Redef] = [Redef, RHS, Pred, this] ()
      { return Narrow(Redef, RHS, Pred, this); };
}

void SymbolicRangeAnalysis::handleBranch(BranchInst *BI, ICmpInst *ICI) {
  Value *LHS = ICI->getOperand(0), *RHS = ICI->getOperand(1);
  BasicBlock *TB = BI->getSuccessor(0), *FB = BI->getSuccessor(1);
  CmpInst::Predicate Pred     = ICI->getPredicate(),
                     SwapPred = ICI->getSwappedPredicate(),
                     InvPred  = ICI->getInversePredicate(), EqPred;

  // For (i < j) branching to cond.true and cond.false, for example:
  // 1) i < j at cond.true;
  createNarrowingFn(LHS, RHS, Pred,     TB);
  // 2) j > i at cond.true;
  createNarrowingFn(RHS, LHS, SwapPred, TB);
  // 3) i >= j at cond.false;
  createNarrowingFn(LHS, RHS, InvPred,  FB);

  if (ICI->isEquality())
    EqPred = Pred;
  else if (ICI->isTrueWhenEqual())
    EqPred = (ICmpInst::Predicate)(Pred - 1);
  else {
    assert(ICI->isFalseWhenEqual());
    EqPred = (ICmpInst::Predicate)(Pred + 1);
  }
  // 4) j <= i at cond.false;
  createNarrowingFn(RHS, LHS, EqPred, FB);
}

void SymbolicRangeAnalysis::handleIntInst(Instruction *I) {
  setName(I,  makeName(I->getParent()->getParent(), I));
  if (isa<LoadInst>(I))
    setState(I, GetBoundsForValue(I, SI_));
  else
    setState(I, getBottom());
  switch (I->getOpcode()) {
    case Instruction::Add:
    case Instruction::Sub:
    case Instruction::Mul:
    case Instruction::SDiv:
    case Instruction::UDiv:
      Fn_[I] = [I, this] ()
        { return BinaryOp(cast<BinaryOperator>(I), this); };
      break;
    case Instruction::PHI:
      if (!Fn_.count(I))
        Fn_[I] = [I, this] ()
          { return Meet(cast<PHINode>(I), this); };
      break;
    case Instruction::Trunc:
    case Instruction::ZExt:
    case Instruction::SExt:
        Fn_[I] = [I, this] ()
          { return this->getState(*I->op_begin()); };
      break;
    default:
      return;
  }
}

void SymbolicRangeAnalysis::initialize(Function *F) {
  // Create symbols for the function's integer arguments.
  for (auto AI = F->arg_begin(), AE = F->arg_end(); AI != AE; ++AI)
    if (AI->getType()->isIntegerTy()) {
      std::string Name = makeName(F, &(*AI));
      setName(&(*AI), Name);
      SAGEExpr Arg(*SI_, Name.c_str());
      // Range is symbolic - [Arg, Arg].
      setState(&(*AI), SAGERange(Arg));
    }

  // Create a closure for each instruction.
  for (auto &BB : *F) {
    // Handle sigma nodes.
    TerminatorInst *TI = BB.getTerminator();
    if (BranchInst *BI = dyn_cast<BranchInst>(TI))
      if (BI->isConditional())
        if (ICmpInst *ICI = dyn_cast<ICmpInst>(BI->getCondition()))
          handleBranch(BI, ICI);

    // Handle everything that's not a sigma node.
    for (auto &I : BB)
      if (I.getType()->isIntegerTy()) {
        Mapping_[&I] = Mapping_.size() + 1;
        handleIntInst(&I);
      }
  }
}

void SymbolicRangeAnalysis::reset(Function *F) {
  for (auto &BB : *F)
    for (auto &I : BB)
      if (Changed_.count(&I) && Changed_[&I])
        Worklist_.insert(std::make_pair(Mapping_[&I], &I));

  Evaled_.clear();
  Changed_.clear();
}

void SymbolicRangeAnalysis::iterate(Function *F) {
  DEBUG(dbgs() << "SRA: Iterate\n");
  while (!Worklist_.empty()) {
    auto Next = Worklist_.begin(); Worklist_.erase(Next);
    Instruction *I = Next->second;
    if (Fn_.count(I) && !Evaled_.count(I)) {
      Evaled_.insert(I);
      setState(I, Fn_[I]());
      for (auto UI = I->use_begin(), UE = I->use_end(); UI != UE; ++UI)
        if (Instruction *Use = dyn_cast<Instruction>(*UI))
          if (!Evaled_.count(Use))
            Worklist_.insert(std::make_pair(Mapping_[Use], Use));
    }
  }
}

void SymbolicRangeAnalysis::widen(Function *F) {
  DEBUG(dbgs() << "SRA: Widen\n");
  for (auto &BB : *F)
    for (auto &I : BB)
      if (I.getType()->isIntegerTy())
        if (Changed_.count(&I) && Changed_[&I]) {
          auto State = getStateOrInf(&I);
          auto Bounds = GetBoundsForValue(&I, SI_);
          if (Changed_[&I] & CHANGED_LOWER)
            State.setLower(Bounds.getLower());
          if (Changed_[&I] & CHANGED_UPPER)
            State.setUpper(Bounds.getUpper());
          setState(&I, State);
        }
}

void SymbolicRangeAnalysis::print(raw_ostream &OS, const Module*) const {
  for (auto P : State_)
    OS << "[[" << getName(P.first) << "]] = " << P.second << "\n";
}

<commit_msg>Fix parameter order in GetBoundsForTy<commit_after>//===---------------------- SymbolicRangeAnalysis.cpp ---------------------===//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "sra"

#include "SymbolicRangeAnalysis.h"

#include "llvm/IR/Constants.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"

raw_ostream& operator<<(raw_ostream& OS, const SymbolicRangeAnalysis& SRR) {
  SRR.print(OS, nullptr);
  return OS;
}

using namespace llvm;

static RegisterPass<SymbolicRangeAnalysis>
  X("sra", "Symbolic range analysis with SAGE and QEPCAD");
char SymbolicRangeAnalysis::ID = 0;

static cl::opt<bool>
    ShouldUseSymBounds("sra-use-sym-bounds", cl::init(false), cl::Hidden,
        cl::desc("Use symbolic mins & maxes for integer bounds"));

static cl::opt<int>
    MaxPhiEvalSize("sra-max-phi-eval-size", cl::init(-1), cl::Hidden,
        cl::desc("Maximum number of operands on phi nodes, phi nodes which"
            "have more will not be evaluated"));

const unsigned CHANGED_LOWER = 1 << 0;
const unsigned CHANGED_UPPER = 1 << 1;

static SAGERange GetBoundsForTy(Type *Ty, SAGEInterface *SI) {
  unsigned Width = Ty->getIntegerBitWidth();
  if (ShouldUseSymBounds) {
    switch (Width) {
      case 8:
        return SAGERange(SAGEExpr(*SI, "UCHAR_MAX"), SAGEExpr(*SI, "CHAR_MIN"));
      case 16:
        return SAGERange(SAGEExpr(*SI, "USHRT_MAX"), SAGEExpr(*SI, "SHRT_MIN"));
      case 32:
        return SAGERange(SAGEExpr(*SI, "UINT_MAX"), SAGEExpr(*SI, "INT_MIN"));
      case 64:
        return SAGERange(SAGEExpr(*SI, "ULONG_MAX"), SAGEExpr(*SI, "LONG_MIN"));
    }
  }
  uint64_t Upper = APInt::getMaxValue(Width).getZExtValue();
  int64_t Lower = APInt::getSignedMinValue(Width).getSExtValue();
  return SAGERange(SAGEExpr(*SI, Lower), SAGEExpr(*SI, Upper));
}

static SAGERange GetBoundsForValue(Value *V, SAGEInterface *SI) {
  return GetBoundsForTy(V->getType(), SI);
}

static SAGERange BinaryOp(BinaryOperator *BO, SymbolicRangeAnalysis *SRA) {
  DEBUG(dbgs() << "SRA: BinaryOp: " << *BO << "\n");

  auto LHS = SRA->getStateOrInf(BO->getOperand(0)),
       RHS = SRA->getStateOrInf(BO->getOperand(1));

  switch (BO->getOpcode()) {
    case Instruction::Add:
      return LHS + RHS;
    case Instruction::Sub:
      return LHS - RHS;
    case Instruction::Mul:
      return LHS * RHS;
    case Instruction::SDiv:
    case Instruction::UDiv:
      return LHS/RHS;
    default:
      return GetBoundsForValue(BO, &SRA->getSI());
  }
}

static SAGERange Narrow(PHINode *Phi, Value *V, ICmpInst::Predicate Pred,
                        SymbolicRangeAnalysis *SRA) {
  DEBUG(dbgs() << "SRA: Narrow: " << *Phi << ", " << *V << "\n");

  auto Ret   = SRA->getStateOrInf(Phi->getIncomingValue(0)),
       Bound = SRA->getState(V);

  std::set<SAGEExpr> Set;
  switch (Pred) {
    case CmpInst::ICMP_SLT:
    case CmpInst::ICMP_ULT:
      Ret.setUpper(Bound.getUpper() - 1);
      break;
    case CmpInst::ICMP_SLE:
    case CmpInst::ICMP_ULE:
      Ret.setUpper(Bound.getUpper());
      break;
    case CmpInst::ICMP_SGT:
    case CmpInst::ICMP_UGT:
      Ret.setLower(Bound.getLower() + 1);
      break;
    case CmpInst::ICMP_SGE:
    case CmpInst::ICMP_UGE:
      Ret.setLower(Bound.getLower());
      break;
    case CmpInst::ICMP_EQ:
      Ret = Bound;
      break;
    default:
      break;
  }
  return Ret;
}

static SAGERange Meet(PHINode *Phi, SymbolicRangeAnalysis *SRA) {
  DEBUG(dbgs() << "SRA: Meet: " << *Phi << "\n");

  if (MaxPhiEvalSize > 0 && Phi->getNumOperands() > (unsigned) MaxPhiEvalSize) {
    SAGERange Ret =
        GetBoundsForTy(cast<IntegerType>(Phi->getType()), &SRA->getSI());
    Ret.setLower(Ret.getLower());
    Ret.setUpper(Ret.getUpper());
    return Ret;
  }

  SAGERange Ret = SRA->getState(Phi->getIncomingValue(0));
  auto OI = Phi->op_begin(), OE = Phi->op_end();
  for (; Ret == SRA->getBottom() && OI != OE; ++OI)
    Ret = SRA->getState(*OI);

  for (; OI != OE; ++OI) {
    SAGERange Incoming = SRA->getState(*OI);
    if (Incoming == SRA->getBottom())
      continue;
    Ret.setLower(Ret.getLower().min(Incoming.getLower()));
    Ret.setUpper(Ret.getUpper().max(Incoming.getUpper()));
  }
  return Ret;
}

void SymbolicRangeAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.addRequired<SAGEInterface>();
  AU.addRequired<Redefinition>();
  AU.setPreservesAll();
}

bool SymbolicRangeAnalysis::runOnFunction(Function& F) {
  Module_ = F.getParent();
  SI_ = &getAnalysis<SAGEInterface>();

  dbgs() << "SRA: runOnModule: " << F.getName() << "\n";

  RDF_ = &getAnalysis<Redefinition>();

  initialize(&F);
  reset(&F);
  iterate(&F);
  reset(&F);
  iterate(&F);
  reset(&F);
  iterate(&F);
  widen(&F);

  DEBUG(dbgs() << *this << "\n");

  return false;
}

SAGEExpr SymbolicRangeAnalysis::getBottomExpr() const {
  static SAGEExpr BottomExpr(*SI_, "_BOT_");
  return BottomExpr;
}

SAGERange SymbolicRangeAnalysis::getBottom() const {
  static SAGERange BottomRange(getBottomExpr());
  return BottomRange;
}

std::string SymbolicRangeAnalysis::makeName(Function *F, Value *V) {
  static unsigned Temp = 1;
  if (V->hasName()) {
    auto Name = (F->getName() + Twine("_") + V->getName()).str();
    std::replace(Name.begin(), Name.end(), '.', '_');
    return Name;
  } else {
    auto Name = F->getName() + Twine("_") + Twine(Temp++);
    return Name.str();
  }
}

void SymbolicRangeAnalysis::setName(Value *V, std::string Name) {
  Name_[V] = Name;
  Value_[Name] = V;
}

std::string SymbolicRangeAnalysis::getName(Value *V) const {
  auto It = Name_.find(V);
  assert(It != Name_.end() && "Requested value is not in map");
  return It->second;
}

void SymbolicRangeAnalysis::setState(Value *V, SAGERange Range) {
  DEBUG(dbgs() << "SRA: setState(" << *V << "," << Range << ")\n");
  auto It = State_.insert(std::make_pair(V, Range));
  if (!It.second) {
    if (It.first->second != Range)
      setChanged(V, It.first->second, Range);
    It.first->second = Range;
  } else if (isa<Instruction>(V)) {
    Changed_[V] = CHANGED_LOWER | CHANGED_UPPER;
  }
}

void SymbolicRangeAnalysis::setChanged(Value *V, SAGERange &Prev,
                                       SAGERange &New) {
  Changed_[V] = (Prev.getLower().isNE(New.getLower()) ? CHANGED_LOWER : 0) |
                (Prev.getUpper().isNE(New.getUpper()) ? CHANGED_UPPER : 0);
}

SAGERange SymbolicRangeAnalysis::getState(Value *V) const {
  // TODO: Handle ptrtoint.
  if (ConstantInt *CI = dyn_cast<ConstantInt>(V))
    return SAGEExpr(*SI_, CI->getValue().getSExtValue());
  if (isa<UndefValue>(V) || isa<Constant>(V))
    return GetBoundsForValue(V, SI_);
  auto It = State_.find(V);
  assert(It != State_.end() && "Requested value is not in map");
  return It->second;
}

SAGERange SymbolicRangeAnalysis::getStateOrInf(Value *V) const {
  auto State = getState(V);
  return State != getBottom()
      ? State : GetBoundsForTy(cast<IntegerType>(V->getType()), SI_);
}

std::pair<Value*, Value*>
    SymbolicRangeAnalysis::getRangeValuesFor(Value *V, IRBuilder<> IRB) const {
  SAGERange Range = getStateOrInf(V);
  IntegerType *Ty = cast<IntegerType>(V->getType());
  Value *Lower = Range.getLower().toValue(Ty, IRB, Value_, Module_),
        *Upper = Range.getUpper().toValue(Ty, IRB, Value_, Module_);
  return std::make_pair(Lower, Upper);
}

void SymbolicRangeAnalysis::createNarrowingFn(Value *LHS, Value *RHS,
                                      CmpInst::Predicate Pred, BasicBlock *BB) {
  if (auto Redef = RDF_->getRedef(LHS, BB))
    Fn_[Redef] = [Redef, RHS, Pred, this] ()
      { return Narrow(Redef, RHS, Pred, this); };
}

void SymbolicRangeAnalysis::handleBranch(BranchInst *BI, ICmpInst *ICI) {
  Value *LHS = ICI->getOperand(0), *RHS = ICI->getOperand(1);
  BasicBlock *TB = BI->getSuccessor(0), *FB = BI->getSuccessor(1);
  CmpInst::Predicate Pred     = ICI->getPredicate(),
                     SwapPred = ICI->getSwappedPredicate(),
                     InvPred  = ICI->getInversePredicate(), EqPred;

  // For (i < j) branching to cond.true and cond.false, for example:
  // 1) i < j at cond.true;
  createNarrowingFn(LHS, RHS, Pred,     TB);
  // 2) j > i at cond.true;
  createNarrowingFn(RHS, LHS, SwapPred, TB);
  // 3) i >= j at cond.false;
  createNarrowingFn(LHS, RHS, InvPred,  FB);

  if (ICI->isEquality())
    EqPred = Pred;
  else if (ICI->isTrueWhenEqual())
    EqPred = (ICmpInst::Predicate)(Pred - 1);
  else {
    assert(ICI->isFalseWhenEqual());
    EqPred = (ICmpInst::Predicate)(Pred + 1);
  }
  // 4) j <= i at cond.false;
  createNarrowingFn(RHS, LHS, EqPred, FB);
}

void SymbolicRangeAnalysis::handleIntInst(Instruction *I) {
  setName(I,  makeName(I->getParent()->getParent(), I));
  if (isa<LoadInst>(I))
    setState(I, GetBoundsForValue(I, SI_));
  else
    setState(I, getBottom());
  switch (I->getOpcode()) {
    case Instruction::Add:
    case Instruction::Sub:
    case Instruction::Mul:
    case Instruction::SDiv:
    case Instruction::UDiv:
      Fn_[I] = [I, this] ()
        { return BinaryOp(cast<BinaryOperator>(I), this); };
      break;
    case Instruction::PHI:
      if (!Fn_.count(I))
        Fn_[I] = [I, this] ()
          { return Meet(cast<PHINode>(I), this); };
      break;
    case Instruction::Trunc:
    case Instruction::ZExt:
    case Instruction::SExt:
        Fn_[I] = [I, this] ()
          { return this->getState(*I->op_begin()); };
      break;
    default:
      return;
  }
}

void SymbolicRangeAnalysis::initialize(Function *F) {
  // Create symbols for the function's integer arguments.
  for (auto AI = F->arg_begin(), AE = F->arg_end(); AI != AE; ++AI)
    if (AI->getType()->isIntegerTy()) {
      std::string Name = makeName(F, &(*AI));
      setName(&(*AI), Name);
      SAGEExpr Arg(*SI_, Name.c_str());
      // Range is symbolic - [Arg, Arg].
      setState(&(*AI), SAGERange(Arg));
    }

  // Create a closure for each instruction.
  for (auto &BB : *F) {
    // Handle sigma nodes.
    TerminatorInst *TI = BB.getTerminator();
    if (BranchInst *BI = dyn_cast<BranchInst>(TI))
      if (BI->isConditional())
        if (ICmpInst *ICI = dyn_cast<ICmpInst>(BI->getCondition()))
          handleBranch(BI, ICI);

    // Handle everything that's not a sigma node.
    for (auto &I : BB)
      if (I.getType()->isIntegerTy()) {
        Mapping_[&I] = Mapping_.size() + 1;
        handleIntInst(&I);
      }
  }
}

void SymbolicRangeAnalysis::reset(Function *F) {
  for (auto &BB : *F)
    for (auto &I : BB)
      if (Changed_.count(&I) && Changed_[&I])
        Worklist_.insert(std::make_pair(Mapping_[&I], &I));

  Evaled_.clear();
  Changed_.clear();
}

void SymbolicRangeAnalysis::iterate(Function *F) {
  DEBUG(dbgs() << "SRA: Iterate\n");
  while (!Worklist_.empty()) {
    auto Next = Worklist_.begin(); Worklist_.erase(Next);
    Instruction *I = Next->second;
    if (Fn_.count(I) && !Evaled_.count(I)) {
      Evaled_.insert(I);
      setState(I, Fn_[I]());
      for (auto UI = I->use_begin(), UE = I->use_end(); UI != UE; ++UI)
        if (Instruction *Use = dyn_cast<Instruction>(*UI))
          if (!Evaled_.count(Use))
            Worklist_.insert(std::make_pair(Mapping_[Use], Use));
    }
  }
}

void SymbolicRangeAnalysis::widen(Function *F) {
  DEBUG(dbgs() << "SRA: Widen\n");
  for (auto &BB : *F)
    for (auto &I : BB)
      if (I.getType()->isIntegerTy())
        if (Changed_.count(&I) && Changed_[&I]) {
          auto State = getStateOrInf(&I);
          auto Bounds = GetBoundsForValue(&I, SI_);
          if (Changed_[&I] & CHANGED_LOWER)
            State.setLower(Bounds.getLower());
          if (Changed_[&I] & CHANGED_UPPER)
            State.setUpper(Bounds.getUpper());
          setState(&I, State);
        }
}

void SymbolicRangeAnalysis::print(raw_ostream &OS, const Module*) const {
  for (auto P : State_)
    OS << "[[" << getName(P.first) << "]] = " << P.second << "\n";
}

<|endoftext|>


<commit_before>#include "Halide.h"
#include <stdio.h>

using namespace Halide;

Var x;

template <class T>
bool test(Expr e, const char *funcname, int vector_width, int N, Image<T> &input, T *result) {
    Func f;
    f(x) = e;
    if (vector_width > 1) {
        f.vectorize(x, vector_width);
    }
    Image<T> im = f.realize(N);

    printf("Testing %s (%s x %d)\n", funcname, type_of<T>() == Float(32) ? "float" : "double", vector_width);
    bool ok = true;
    for (int i = 0; i < N; i++) {
        if (result[i] != im(i)) {
            printf("Error: %s(%.9g)=%.9g, should be %.9g\n", funcname, input(i), im(i), result[i]);
            ok = false;
        }
    }
    return ok;
}

template <class T>
bool test(Expr e, const char *funcname, int N, Image<T> &input, T *result) {
    return test(e, funcname, 1, N, input, result)
        && test(e, funcname, 2, N, input, result)
        && test(e, funcname, 4, N, input, result)
        && test(e, funcname, 8, N, input, result);
}

int main(int argc, char **argv) {
    bool ok = true;
    {
        const int N = 22;
        float inputdata[N] = {
            -2.6f, -2.5f, -2.3f, -1.5f, -1.0f, -0.5f, -0.49999997f, -0.2f, -0.0f,
            +2.6f, +2.5f, +2.3f, +1.5f, +1.0f, +0.5f, 0.49999997f, +0.2f, +0.0f,
            8388609, -8388609, 16777216, -16777218,
        };
        float round_result[N] = {
            -3.0f, -2.0f, -2.0f, -2.0f, -1.0f, -0.0f, -0.0f, -0.0f, -0.0f,
            +3.0f, +2.0f, +2.0f, +2.0f, +1.0f, +0.0f, 0.0f, +0.0f, +0.0f,
            8388609, -8388609, 16777216, -16777218
        };
        float floor_result[N] = {
            -3.0f, -3.0f, -3.0f, -2.0f, -1.0f, -1.0f, -1.0f, -1.0f, -0.0f,
            +2.0f, +2.0f, +2.0f, +1.0f, +1.0f, +0.0f, 0.0f, +0.0f, +0.0f,
            8388609, -8388609, 16777216, -16777218
        };
        float ceil_result[N] = {
            -2.0f, -2.0f, -2.0f, -1.0f, -1.0f, -0.0f, -0.0f, -0.0f, -0.0f,
            +3.0f, +3.0f, +3.0f, +2.0f, +1.0f, +1.0f, 1.0f, +1.0f, +0.0f,
            8388609, -8388609, 16777216, -16777218,
        };
        float trunc_result[N] = {
            -2.0f, -2.0f, -2.0f, -1.0f, -1.0f, -0.0f, -0.0f, -0.0f, -0.0f,
            +2.0f, +2.0f, +2.0f, +1.0f, +1.0f, +0.0f, 0.0f, +0.0f, +0.0f,
            8388609, -8388609, 16777216, -16777218,
        };

        Image<float> input(N);
        for (int i = 0; i < N; i++) {
            input(i) = inputdata[i];
        }
        ok = ok && test(round(input(x)), "round", N, input, round_result);
        ok = ok && test(floor(input(x)), "floor", N, input, floor_result);
        ok = ok && test(ceil(input(x)), "ceil", N, input, ceil_result);
        ok = ok && test(trunc(input(x)), "trunc", N, input, trunc_result);
    }
    {
        const int N = 24;
        double inputdata[N] = {
            -2.6, -2.5, -2.3, -1.5, -1.0, -0.5, -0.49999999999999994, -0.2, -0.0,
            +2.6, +2.5, +2.3, +1.5, +1.0, +0.5, 0.49999999999999994, +0.2, +0.0,
            8388609, -8388610, 16777216, -16777218,
            4503599627370497, -4503599627370497
        };
        double round_result[N] = {
            -3.0, -2.0, -2.0, -2.0, -1.0, -0.0, -0.0, -0.0, -0.0,
            +3.0, +2.0, +2.0, +2.0, +1.0, +0.0, 0.0, +0.0, +0.0,
            8388609, -8388610, 16777216, -16777218,
            4503599627370497, -4503599627370497
        };
        double floor_result[N] = {
            -3.0, -3.0, -3.0, -2.0, -1.0, -1.0, -1.0, -1.0, -0.0,
            +2.0, +2.0, +2.0, +1.0, +1.0, +0.0, 0.0, +0.0, +0.0,
            8388609, -8388610, 16777216, -16777218,
            4503599627370497, -4503599627370497
        };
        double ceil_result[N] = {
            -2.0, -2.0, -2.0, -1.0, -1.0, -0.0, -0.0, -0.0, -0.0,
            +3.0, +3.0, +3.0, +2.0, +1.0, +1.0, 1.0, +1.0, +0.0,
            8388609, -8388610, 16777216, -16777218,
            4503599627370497, -4503599627370497
        };
        double trunc_result[N] = {
            -2.0, -2.0, -2.0, -1.0, -1.0, -0.0, -0.0, -0.0, -0.0,
            +2.0, +2.0, +2.0, +1.0, +1.0, +0.0, 0.0, +0.0, +0.0,
            8388609, -8388610, 16777216, -16777218,
            4503599627370497, -4503599627370497
        };
        Image<double> input(N);
        for (int i = 0; i < N; i++) {
            input(i) = inputdata[i];
        }
        ok = ok && test(round(input(x)), "round", N, input, round_result);
        ok = ok && test(floor(input(x)), "floor", N, input, floor_result);
        ok = ok && test(ceil(input(x)), "ceil", N, input, ceil_result);
        ok = ok && test(trunc(input(x)), "trunc", N, input, trunc_result);
    }
    return ok ? 0 : -1;
}
<commit_msg>Add "Success" message to round test.<commit_after>#include "Halide.h"
#include <stdio.h>

using namespace Halide;

Var x;

template <class T>
bool test(Expr e, const char *funcname, int vector_width, int N, Image<T> &input, T *result) {
    Func f;
    f(x) = e;
    if (vector_width > 1) {
        f.vectorize(x, vector_width);
    }
    Image<T> im = f.realize(N);

    printf("Testing %s (%s x %d)\n", funcname, type_of<T>() == Float(32) ? "float" : "double", vector_width);
    bool ok = true;
    for (int i = 0; i < N; i++) {
        if (result[i] != im(i)) {
            printf("Error: %s(%.9g)=%.9g, should be %.9g\n", funcname, input(i), im(i), result[i]);
            ok = false;
        }
    }
    return ok;
}

template <class T>
bool test(Expr e, const char *funcname, int N, Image<T> &input, T *result) {
    return test(e, funcname, 1, N, input, result)
        && test(e, funcname, 2, N, input, result)
        && test(e, funcname, 4, N, input, result)
        && test(e, funcname, 8, N, input, result);
}

int main(int argc, char **argv) {
    bool ok = true;
    {
        const int N = 22;
        float inputdata[N] = {
            -2.6f, -2.5f, -2.3f, -1.5f, -1.0f, -0.5f, -0.49999997f, -0.2f, -0.0f,
            +2.6f, +2.5f, +2.3f, +1.5f, +1.0f, +0.5f, 0.49999997f, +0.2f, +0.0f,
            8388609, -8388609, 16777216, -16777218,
        };
        float round_result[N] = {
            -3.0f, -2.0f, -2.0f, -2.0f, -1.0f, -0.0f, -0.0f, -0.0f, -0.0f,
            +3.0f, +2.0f, +2.0f, +2.0f, +1.0f, +0.0f, 0.0f, +0.0f, +0.0f,
            8388609, -8388609, 16777216, -16777218
        };
        float floor_result[N] = {
            -3.0f, -3.0f, -3.0f, -2.0f, -1.0f, -1.0f, -1.0f, -1.0f, -0.0f,
            +2.0f, +2.0f, +2.0f, +1.0f, +1.0f, +0.0f, 0.0f, +0.0f, +0.0f,
            8388609, -8388609, 16777216, -16777218
        };
        float ceil_result[N] = {
            -2.0f, -2.0f, -2.0f, -1.0f, -1.0f, -0.0f, -0.0f, -0.0f, -0.0f,
            +3.0f, +3.0f, +3.0f, +2.0f, +1.0f, +1.0f, 1.0f, +1.0f, +0.0f,
            8388609, -8388609, 16777216, -16777218,
        };
        float trunc_result[N] = {
            -2.0f, -2.0f, -2.0f, -1.0f, -1.0f, -0.0f, -0.0f, -0.0f, -0.0f,
            +2.0f, +2.0f, +2.0f, +1.0f, +1.0f, +0.0f, 0.0f, +0.0f, +0.0f,
            8388609, -8388609, 16777216, -16777218,
        };

        Image<float> input(N);
        for (int i = 0; i < N; i++) {
            input(i) = inputdata[i];
        }
        ok = ok && test(round(input(x)), "round", N, input, round_result);
        ok = ok && test(floor(input(x)), "floor", N, input, floor_result);
        ok = ok && test(ceil(input(x)), "ceil", N, input, ceil_result);
        ok = ok && test(trunc(input(x)), "trunc", N, input, trunc_result);
    }
    {
        const int N = 24;
        double inputdata[N] = {
            -2.6, -2.5, -2.3, -1.5, -1.0, -0.5, -0.49999999999999994, -0.2, -0.0,
            +2.6, +2.5, +2.3, +1.5, +1.0, +0.5, 0.49999999999999994, +0.2, +0.0,
            8388609, -8388610, 16777216, -16777218,
            4503599627370497, -4503599627370497
        };
        double round_result[N] = {
            -3.0, -2.0, -2.0, -2.0, -1.0, -0.0, -0.0, -0.0, -0.0,
            +3.0, +2.0, +2.0, +2.0, +1.0, +0.0, 0.0, +0.0, +0.0,
            8388609, -8388610, 16777216, -16777218,
            4503599627370497, -4503599627370497
        };
        double floor_result[N] = {
            -3.0, -3.0, -3.0, -2.0, -1.0, -1.0, -1.0, -1.0, -0.0,
            +2.0, +2.0, +2.0, +1.0, +1.0, +0.0, 0.0, +0.0, +0.0,
            8388609, -8388610, 16777216, -16777218,
            4503599627370497, -4503599627370497
        };
        double ceil_result[N] = {
            -2.0, -2.0, -2.0, -1.0, -1.0, -0.0, -0.0, -0.0, -0.0,
            +3.0, +3.0, +3.0, +2.0, +1.0, +1.0, 1.0, +1.0, +0.0,
            8388609, -8388610, 16777216, -16777218,
            4503599627370497, -4503599627370497
        };
        double trunc_result[N] = {
            -2.0, -2.0, -2.0, -1.0, -1.0, -0.0, -0.0, -0.0, -0.0,
            +2.0, +2.0, +2.0, +1.0, +1.0, +0.0, 0.0, +0.0, +0.0,
            8388609, -8388610, 16777216, -16777218,
            4503599627370497, -4503599627370497
        };
        Image<double> input(N);
        for (int i = 0; i < N; i++) {
            input(i) = inputdata[i];
        }
        ok = ok && test(round(input(x)), "round", N, input, round_result);
        ok = ok && test(floor(input(x)), "floor", N, input, floor_result);
        ok = ok && test(ceil(input(x)), "ceil", N, input, ceil_result);
        ok = ok && test(trunc(input(x)), "trunc", N, input, trunc_result);
    }
    if (ok) {
        printf("Success!\n");
    }
    return ok ? 0 : -1;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
 *
 * This source code is subject to the terms of the BSD 2 Clause License and
 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
 * was not distributed with this source code in the LICENSE file, you can
 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
 * Media Patent License 1.0 was not distributed with this source code in the
 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/

#include "third_party/googletest/src/include/gtest/gtest.h"

#include "test/codec_factory.h"
#include "test/decode_test_driver.h"
#include "test/register_state_check.h"
#include "test/video_source.h"

namespace libaom_test {

const char kVP8Name[] = "WebM Project VP8";
const char kAV1Name[] = "WebM Project AV1";

aom_codec_err_t Decoder::PeekStream(const uint8_t *cxdata, size_t size,
                                    aom_codec_stream_info_t *stream_info) {
  return aom_codec_peek_stream_info(
      CodecInterface(), cxdata, static_cast<unsigned int>(size), stream_info);
}

aom_codec_err_t Decoder::DecodeFrame(const uint8_t *cxdata, size_t size) {
  return DecodeFrame(cxdata, size, NULL);
}

aom_codec_err_t Decoder::DecodeFrame(const uint8_t *cxdata, size_t size,
                                     void *user_priv) {
  aom_codec_err_t res_dec;
  InitOnce();
  API_REGISTER_STATE_CHECK(
      res_dec = aom_codec_decode(
          &decoder_, cxdata, static_cast<unsigned int>(size), user_priv, 0));
  return res_dec;
}

bool Decoder::IsVP8() const {
  const char *codec_name = GetDecoderName();
  return strncmp(kVP8Name, codec_name, sizeof(kVP8Name) - 1) == 0;
}

bool Decoder::IsAV1() const {
  const char *codec_name = GetDecoderName();
  return strncmp(kAV1Name, codec_name, sizeof(kAV1Name) - 1) == 0;
}

void DecoderTest::HandlePeekResult(Decoder *const decoder,
                                   CompressedVideoSource *video,
                                   const aom_codec_err_t res_peek) {
  const bool is_vp8 = decoder->IsVP8();
  if (is_vp8) {
    /* Vp8's implementation of PeekStream returns an error if the frame you
     * pass it is not a keyframe, so we only expect AOM_CODEC_OK on the first
     * frame, which must be a keyframe. */
    if (video->frame_number() == 0)
      ASSERT_EQ(AOM_CODEC_OK, res_peek) << "Peek return failed: "
                                        << aom_codec_err_to_string(res_peek);
  } else {
    /* The Av1 implementation of PeekStream returns an error only if the
     * data passed to it isn't a valid Av1 chunk. */
    ASSERT_EQ(AOM_CODEC_OK, res_peek) << "Peek return failed: "
                                      << aom_codec_err_to_string(res_peek);
  }
}

void DecoderTest::RunLoop(CompressedVideoSource *video,
                          const aom_codec_dec_cfg_t &dec_cfg) {
  Decoder *const decoder = codec_->CreateDecoder(dec_cfg, flags_, 0);
  ASSERT_TRUE(decoder != NULL);
  bool end_of_file = false;

  // Decode frames.
  for (video->Begin(); !::testing::Test::HasFailure() && !end_of_file;
       video->Next()) {
    PreDecodeFrameHook(*video, decoder);

    aom_codec_stream_info_t stream_info;
    stream_info.sz = sizeof(stream_info);

    if (video->cxdata() != NULL) {
      const aom_codec_err_t res_peek = decoder->PeekStream(
          video->cxdata(), video->frame_size(), &stream_info);
      HandlePeekResult(decoder, video, res_peek);
      ASSERT_FALSE(::testing::Test::HasFailure());

      aom_codec_err_t res_dec =
          decoder->DecodeFrame(video->cxdata(), video->frame_size());
      if (!HandleDecodeResult(res_dec, *video, decoder)) break;
    } else {
      // Signal end of the file to the decoder.
      const aom_codec_err_t res_dec = decoder->DecodeFrame(NULL, 0);
      ASSERT_EQ(AOM_CODEC_OK, res_dec) << decoder->DecodeError();
      end_of_file = true;
    }

    DxDataIterator dec_iter = decoder->GetDxData();
    const aom_image_t *img = NULL;

    // Get decompressed data
    while ((img = dec_iter.Next()))
      DecompressedFrameHook(*img, video->frame_number());
  }
  delete decoder;
}

void DecoderTest::RunLoop(CompressedVideoSource *video) {
  aom_codec_dec_cfg_t dec_cfg = aom_codec_dec_cfg_t();
  RunLoop(video, dec_cfg);
}

void DecoderTest::set_cfg(const aom_codec_dec_cfg_t &dec_cfg) {
  memcpy(&cfg_, &dec_cfg, sizeof(cfg_));
}

void DecoderTest::set_flags(const aom_codec_flags_t flags) { flags_ = flags; }

}  // namespace libaom_test
<commit_msg>Update codec name in test enviroment to match decoder<commit_after>/*
 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
 *
 * This source code is subject to the terms of the BSD 2 Clause License and
 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
 * was not distributed with this source code in the LICENSE file, you can
 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
 * Media Patent License 1.0 was not distributed with this source code in the
 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/

#include "third_party/googletest/src/include/gtest/gtest.h"

#include "test/codec_factory.h"
#include "test/decode_test_driver.h"
#include "test/register_state_check.h"
#include "test/video_source.h"

namespace libaom_test {

const char kVP8Name[] = "WebM Project VP8";
const char kAV1Name[] = "AOMedia Project AV1 Decoder";

aom_codec_err_t Decoder::PeekStream(const uint8_t *cxdata, size_t size,
                                    aom_codec_stream_info_t *stream_info) {
  return aom_codec_peek_stream_info(
      CodecInterface(), cxdata, static_cast<unsigned int>(size), stream_info);
}

aom_codec_err_t Decoder::DecodeFrame(const uint8_t *cxdata, size_t size) {
  return DecodeFrame(cxdata, size, NULL);
}

aom_codec_err_t Decoder::DecodeFrame(const uint8_t *cxdata, size_t size,
                                     void *user_priv) {
  aom_codec_err_t res_dec;
  InitOnce();
  API_REGISTER_STATE_CHECK(
      res_dec = aom_codec_decode(
          &decoder_, cxdata, static_cast<unsigned int>(size), user_priv, 0));
  return res_dec;
}

bool Decoder::IsVP8() const {
  const char *codec_name = GetDecoderName();
  return strncmp(kVP8Name, codec_name, sizeof(kVP8Name) - 1) == 0;
}

bool Decoder::IsAV1() const {
  const char *codec_name = GetDecoderName();
  return strncmp(kAV1Name, codec_name, sizeof(kAV1Name) - 1) == 0;
}

void DecoderTest::HandlePeekResult(Decoder *const decoder,
                                   CompressedVideoSource *video,
                                   const aom_codec_err_t res_peek) {
  const bool is_vp8 = decoder->IsVP8();
  if (is_vp8) {
    /* Vp8's implementation of PeekStream returns an error if the frame you
     * pass it is not a keyframe, so we only expect AOM_CODEC_OK on the first
     * frame, which must be a keyframe. */
    if (video->frame_number() == 0)
      ASSERT_EQ(AOM_CODEC_OK, res_peek) << "Peek return failed: "
                                        << aom_codec_err_to_string(res_peek);
  } else {
    /* The Av1 implementation of PeekStream returns an error only if the
     * data passed to it isn't a valid Av1 chunk. */
    ASSERT_EQ(AOM_CODEC_OK, res_peek) << "Peek return failed: "
                                      << aom_codec_err_to_string(res_peek);
  }
}

void DecoderTest::RunLoop(CompressedVideoSource *video,
                          const aom_codec_dec_cfg_t &dec_cfg) {
  Decoder *const decoder = codec_->CreateDecoder(dec_cfg, flags_, 0);
  ASSERT_TRUE(decoder != NULL);
  bool end_of_file = false;

  // Decode frames.
  for (video->Begin(); !::testing::Test::HasFailure() && !end_of_file;
       video->Next()) {
    PreDecodeFrameHook(*video, decoder);

    aom_codec_stream_info_t stream_info;
    stream_info.sz = sizeof(stream_info);

    if (video->cxdata() != NULL) {
      const aom_codec_err_t res_peek = decoder->PeekStream(
          video->cxdata(), video->frame_size(), &stream_info);
      HandlePeekResult(decoder, video, res_peek);
      ASSERT_FALSE(::testing::Test::HasFailure());

      aom_codec_err_t res_dec =
          decoder->DecodeFrame(video->cxdata(), video->frame_size());
      if (!HandleDecodeResult(res_dec, *video, decoder)) break;
    } else {
      // Signal end of the file to the decoder.
      const aom_codec_err_t res_dec = decoder->DecodeFrame(NULL, 0);
      ASSERT_EQ(AOM_CODEC_OK, res_dec) << decoder->DecodeError();
      end_of_file = true;
    }

    DxDataIterator dec_iter = decoder->GetDxData();
    const aom_image_t *img = NULL;

    // Get decompressed data
    while ((img = dec_iter.Next()))
      DecompressedFrameHook(*img, video->frame_number());
  }
  delete decoder;
}

void DecoderTest::RunLoop(CompressedVideoSource *video) {
  aom_codec_dec_cfg_t dec_cfg = aom_codec_dec_cfg_t();
  RunLoop(video, dec_cfg);
}

void DecoderTest::set_cfg(const aom_codec_dec_cfg_t &dec_cfg) {
  memcpy(&cfg_, &dec_cfg, sizeof(cfg_));
}

void DecoderTest::set_flags(const aom_codec_flags_t flags) { flags_ = flags; }

}  // namespace libaom_test
<|endoftext|>


<commit_before>/*
	This file is part of the E_Util library.
	Copyright (C) 2009-2012 Benjamin Eikel <benjamin@eikel.org>
	Copyright (C) 2009-2012 Claudius Jähn <claudius@uni-paderborn.de>
	Copyright (C) 2009-2012 Ralf Petring <ralf@petring.net>

	This library is subject to the terms of the Mozilla Public License, v. 2.0.
	You should have received a copy of the MPL along with this library; see the
	file LICENSE. If not, you can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include "E_BitmapUtils.h"
#include "E_Bitmap.h"
#include <Util/Graphics/Color.h>
#include <Util/Graphics/BitmapUtils.h>
#include <Util/Graphics/PixelAccessor.h>
#include <EScript/EScript.h>

namespace E_Util {
namespace E_BitmapUtils{

using namespace EScript;
using namespace Util;

//!	initMembers
void init(EScript::Namespace & lib) {
	//! BitmapUtil.convertBitmap(Bitmap source,PixelFormat format)
	ES_FUN(&lib,"convertBitmap",2,2,
			EScript::create(BitmapUtils::convertBitmap(
				parameter[0].to<Bitmap &>(rt),
				parameter[1].to<const PixelFormat&>(rt))))

	//! void BitmapUtil._mulScalar(Bitmap source,value)
	ES_FUNCTION(&lib,"_mulScalar",2,2,{
		const float factor = parameter[1].toFloat();
		BitmapUtils::alterBitmap(	parameter[0].to<Bitmap &>(rt),
									[factor](const BitmapUtils::BitmapAlteringContext & ctxt) {
										return ctxt.pixels->readColor4f(ctxt.x, ctxt.y) * factor;
									});
		return EScript::create(nullptr);
	});

	//! Bitmap BitmapUtil.blendTogether(PixelFormat,Array of Bitmaps)
	ES_FUNCTION(&lib, "blendTogether", 2, 2, {
		EScript::Array * arr = parameter[1].to<EScript::Array*>(rt);
		std::vector<Util::Reference<Util::Bitmap>> bitmaps;
		for(auto & element : *arr) {
			bitmaps.push_back(element.to<Reference<Bitmap>>(rt));
		}
		return EScript::create(BitmapUtils::blendTogether(parameter[0].to<const PixelFormat&>(rt), bitmaps));
	})

	//! Bitmap BitmapUtil.combineInterleaved(PixelFormat,Array of Bitmaps)
	ES_FUNCTION(&lib, "combineInterleaved", 2, 2, {
		EScript::Array * arr = parameter[1].to<EScript::Array*>(rt);
		std::vector<Util::Reference<Util::Bitmap>> bitmaps;
		for(auto & element : *arr) {
			bitmaps.push_back(element.to<Reference<Bitmap>>(rt));
		}
		return EScript::create(BitmapUtils::combineInterleaved(parameter[0].to<const PixelFormat&>(rt), bitmaps));
	})
}

}
}
<commit_msg>Bindings for BitmapUtils.normalizeBitmap<commit_after>/*
	This file is part of the E_Util library.
	Copyright (C) 2009-2012 Benjamin Eikel <benjamin@eikel.org>
	Copyright (C) 2009-2012 Claudius Jähn <claudius@uni-paderborn.de>
	Copyright (C) 2009-2012 Ralf Petring <ralf@petring.net>

	This library is subject to the terms of the Mozilla Public License, v. 2.0.
	You should have received a copy of the MPL along with this library; see the
	file LICENSE. If not, you can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include "E_BitmapUtils.h"
#include "E_Bitmap.h"
#include <Util/Graphics/Color.h>
#include <Util/Graphics/BitmapUtils.h>
#include <Util/Graphics/PixelAccessor.h>
#include <EScript/EScript.h>

namespace E_Util {
namespace E_BitmapUtils{

using namespace EScript;
using namespace Util;

//!	initMembers
void init(EScript::Namespace & lib) {
	//! BitmapUtil.convertBitmap(Bitmap source,PixelFormat format)
	ES_FUN(&lib,"convertBitmap",2,2,
			EScript::create(BitmapUtils::convertBitmap(
				parameter[0].to<Bitmap &>(rt),
				parameter[1].to<const PixelFormat&>(rt))))

	//! void BitmapUtil._mulScalar(Bitmap source,value)
	ES_FUNCTION(&lib,"_mulScalar",2,2,{
		const float factor = parameter[1].toFloat();
		BitmapUtils::alterBitmap(	parameter[0].to<Bitmap &>(rt),
									[factor](const BitmapUtils::BitmapAlteringContext & ctxt) {
										return ctxt.pixels->readColor4f(ctxt.x, ctxt.y) * factor;
									});
		return EScript::create(nullptr);
	});

	//! Bitmap BitmapUtil.blendTogether(PixelFormat,Array of Bitmaps)
	ES_FUNCTION(&lib, "blendTogether", 2, 2, {
		EScript::Array * arr = parameter[1].to<EScript::Array*>(rt);
		std::vector<Util::Reference<Util::Bitmap>> bitmaps;
		for(auto & element : *arr) {
			bitmaps.push_back(element.to<Reference<Bitmap>>(rt));
		}
		return EScript::create(BitmapUtils::blendTogether(parameter[0].to<const PixelFormat&>(rt), bitmaps));
	})

	//! Bitmap BitmapUtil.combineInterleaved(PixelFormat,Array of Bitmaps)
	ES_FUNCTION(&lib, "combineInterleaved", 2, 2, {
		EScript::Array * arr = parameter[1].to<EScript::Array*>(rt);
		std::vector<Util::Reference<Util::Bitmap>> bitmaps;
		for(auto & element : *arr) {
			bitmaps.push_back(element.to<Reference<Bitmap>>(rt));
		}
		return EScript::create(BitmapUtils::combineInterleaved(parameter[0].to<const PixelFormat&>(rt), bitmaps));
	})

	//! BitmapUtil.normalizeBitmap(Bitmap bitmap)
	ES_FUN(&lib,"normalizeBitmap",1,1, (BitmapUtils::normalizeBitmap(parameter[0].to<Bitmap &>(rt)), thisEObj))
}

}
}
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// There are three classes involved here.  There's NetworkChangeNotifierMac,
// which is the Mac specific implementation of NetworkChangeNotifier.  It is the
// class with which clients can register themselves as network change
// observers.  There's NetworkChangeNotifierThread, which is a base::Thread
// subclass of MessageLoop::TYPE_UI (since it needs a CFRunLoop) that contains
// the NetworkChangeNotifierImpl.  NetworkChangeNotifierImpl is the object
// that receives the actual OS X notifications and posts them to the
// NetworkChangeNotifierMac's message loop, so that NetworkChangeNotifierMac
// can notify all its observers.
//
// When NetworkChangeNotifierMac is being deleted, it will delete the
// NetworkChangeNotifierThread, which will Stop() it and also delete the
// NetworkChangeNotifierImpl.  Therefore, NetworkChangeNotifierImpl and
// NetworkChangeNotifierThread's lifetimes generally begin after and end before
// NetworkChangeNotifierMac.  There is an edge case where a notification task
// gets posted to the IO thread, thereby maintaining a reference to
// NetworkChangeNotifierImpl beyond the lifetime of NetworkChangeNotifierThread.
// In this case, the notification is cancelled, and NetworkChangeNotifierImpl
// will be deleted once all notification tasks that reference it have been run.

#include "net/base/network_change_notifier_mac.h"
#include <SystemConfiguration/SCDynamicStore.h>
#include <SystemConfiguration/SCDynamicStoreKey.h>
#include <SystemConfiguration/SCSchemaDefinitions.h>
#include <algorithm>
#include "base/logging.h"
#include "base/scoped_cftyperef.h"
#include "base/thread.h"

namespace net {

namespace {

// NetworkChangeNotifierImpl should be created on a thread with a CFRunLoop,
// since it requires one to pump notifications.  However, it also runs some
// methods on |notifier_loop_|, because it cannot post calls to |notifier_|
// since NetworkChangeNotifier is not ref counted in a thread safe manner.
class NetworkChangeNotifierImpl
    : public base::RefCountedThreadSafe<NetworkChangeNotifierImpl> {
 public:
  NetworkChangeNotifierImpl(MessageLoop* notifier_loop,
                            NetworkChangeNotifierMac* notifier);

  void Shutdown();

 private:
  friend class base::RefCountedThreadSafe<NetworkChangeNotifierImpl>;
  ~NetworkChangeNotifierImpl();

  static void DynamicStoreCallback(SCDynamicStoreRef /* store */,
                                   CFArrayRef changed_keys,
                                   void* config);

  void OnNetworkConfigChange(CFArrayRef changed_keys);

  // Runs on |notifier_loop_|.
  void OnIPAddressChanged();

  // Raw pointers.  Note that |notifier_| _must_ outlive the
  // NetworkChangeNotifierImpl.  For lifecycle management details, read the
  // comment at the top of the file.
  MessageLoop* const notifier_loop_;
  NetworkChangeNotifierMac* notifier_;

  scoped_cftyperef<CFRunLoopSourceRef> source_;

  DISALLOW_COPY_AND_ASSIGN(NetworkChangeNotifierImpl);
};

NetworkChangeNotifierImpl::NetworkChangeNotifierImpl(
    MessageLoop* notifier_loop, NetworkChangeNotifierMac* notifier)
    : notifier_loop_(notifier_loop),
      notifier_(notifier) {
  DCHECK_EQ(MessageLoop::TYPE_UI, MessageLoop::current()->type());
  SCDynamicStoreContext context = {
    0,    // Version 0.
    this, // User data.
    NULL, // This is not reference counted.  No retain function.
    NULL, // This is not reference counted.  No release function.
    NULL, // No description for this.
  };

  // Get a reference to the dynamic store.
  scoped_cftyperef<SCDynamicStoreRef> store(
      SCDynamicStoreCreate(NULL /* use default allocator */,
                           CFSTR("org.chromium"),
                           DynamicStoreCallback, &context));

  // Create a run loop source for the dynamic store.
  source_.reset(SCDynamicStoreCreateRunLoopSource(
      NULL /* use default allocator */,
      store.get(),
      0 /* 0 sounds like a fine source order to me! */));

  // Add the run loop source to the current run loop.
  CFRunLoopAddSource(CFRunLoopGetCurrent(),
                     source_.get(),
                     kCFRunLoopCommonModes);

  // Set up the notification keys.
  scoped_cftyperef<CFMutableArrayRef> notification_keys(
      CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks));

  // Monitor interface changes.
  scoped_cftyperef<CFStringRef> key(
      SCDynamicStoreKeyCreateNetworkGlobalEntity(
          NULL /* default allocator */, kSCDynamicStoreDomainState,
          kSCEntNetInterface));
  CFArrayAppendValue(notification_keys.get(), key.get());

  // Monitor IP address changes.

  key.reset(SCDynamicStoreKeyCreateNetworkGlobalEntity(
      NULL /* default allocator */, kSCDynamicStoreDomainState,
      kSCEntNetIPv4));
  CFArrayAppendValue(notification_keys.get(), key.get());

  key.reset(SCDynamicStoreKeyCreateNetworkGlobalEntity(
      NULL /* default allocator */, kSCDynamicStoreDomainState,
      kSCEntNetIPv6));
  CFArrayAppendValue(notification_keys.get(), key.get());

  // Ok, let's ask for notifications!
  // TODO(willchan): Figure out a proper way to handle this rather than crash.
  CHECK(SCDynamicStoreSetNotificationKeys(
      store.get(), notification_keys.get(), NULL));
}

NetworkChangeNotifierImpl::~NetworkChangeNotifierImpl() {
  CFRunLoopRemoveSource(CFRunLoopGetCurrent(),
                        source_.get(),
                        kCFRunLoopCommonModes);
}

void NetworkChangeNotifierImpl::Shutdown() {
  CHECK(notifier_);
  notifier_ = NULL;
}

// static
void NetworkChangeNotifierImpl::DynamicStoreCallback(
    SCDynamicStoreRef /* store */,
    CFArrayRef changed_keys,
    void* config) {
  NetworkChangeNotifierImpl* net_config =
      static_cast<NetworkChangeNotifierImpl*>(config);
  net_config->OnNetworkConfigChange(changed_keys);
}

void NetworkChangeNotifierImpl::OnNetworkConfigChange(CFArrayRef changed_keys) {
  for (CFIndex i = 0; i < CFArrayGetCount(changed_keys); ++i) {
    CFStringRef key = static_cast<CFStringRef>(
        CFArrayGetValueAtIndex(changed_keys, i));
    if (CFStringHasSuffix(key, kSCEntNetIPv4) ||
        CFStringHasSuffix(key, kSCEntNetIPv6)) {
      notifier_loop_->PostTask(
          FROM_HERE,
          NewRunnableMethod(
              this,
              &NetworkChangeNotifierImpl::OnIPAddressChanged));
    } else if (CFStringHasSuffix(key, kSCEntNetInterface)) {
      // TODO(willchan): Does not appear to be working.  Look into this.
      // Perhaps this isn't needed anyway.
    } else {
      NOTREACHED();
    }
  }
}

void NetworkChangeNotifierImpl::OnIPAddressChanged() {
  // If |notifier_| doesn't exist, then that means we're shutting down, so
  // notifications are all cancelled.
  if (notifier_)
    notifier_->OnIPAddressChanged();
}

class NetworkChangeNotifierThread : public base::Thread {
 public:
  NetworkChangeNotifierThread(MessageLoop* notifier_loop,
                              NetworkChangeNotifierMac* notifier);
  ~NetworkChangeNotifierThread();

 protected:
  virtual void Init();

 private:
  MessageLoop* const notifier_loop_;
  NetworkChangeNotifierMac* const notifier_;
  scoped_refptr<NetworkChangeNotifierImpl> notifier_impl_;

  DISALLOW_COPY_AND_ASSIGN(NetworkChangeNotifierThread);
};

NetworkChangeNotifierThread::NetworkChangeNotifierThread(
    MessageLoop* notifier_loop, NetworkChangeNotifierMac* notifier)
    : base::Thread("NetworkChangeNotifier"),
      notifier_loop_(notifier_loop),
      notifier_(notifier) {}

NetworkChangeNotifierThread::~NetworkChangeNotifierThread() {
  notifier_impl_->Shutdown();
}

// Note that |notifier_impl_| is initialized on the network change
// notifier thread, not whatever thread constructs the
// NetworkChangeNotifierThread object.  This is important, because this thread
// is the one that has a CFRunLoop.
void NetworkChangeNotifierThread::Init() {
  notifier_impl_ =
      new NetworkChangeNotifierImpl(notifier_loop_, notifier_);
}

}  // namespace

NetworkChangeNotifierMac::NetworkChangeNotifierMac()
    : notifier_thread_(
          new NetworkChangeNotifierThread(MessageLoop::current(), this)) {
  base::Thread::Options thread_options;
  thread_options.message_loop_type = MessageLoop::TYPE_UI;
  notifier_thread_->StartWithOptions(thread_options);
}

NetworkChangeNotifierMac::~NetworkChangeNotifierMac() {}

}  // namespace net
<commit_msg>Fix benign race on NetworkChangeNotifierThread's vtable pointer. See bug 25385 and http://code.google.com/p/data-race-test/wiki/PopularDataRaces for details.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// There are three classes involved here.  There's NetworkChangeNotifierMac,
// which is the Mac specific implementation of NetworkChangeNotifier.  It is the
// class with which clients can register themselves as network change
// observers.  There's NetworkChangeNotifierThread, which is a base::Thread
// subclass of MessageLoop::TYPE_UI (since it needs a CFRunLoop) that contains
// the NetworkChangeNotifierImpl.  NetworkChangeNotifierImpl is the object
// that receives the actual OS X notifications and posts them to the
// NetworkChangeNotifierMac's message loop, so that NetworkChangeNotifierMac
// can notify all its observers.
//
// When NetworkChangeNotifierMac is being deleted, it will delete the
// NetworkChangeNotifierThread, which will Stop() it and also delete the
// NetworkChangeNotifierImpl.  Therefore, NetworkChangeNotifierImpl and
// NetworkChangeNotifierThread's lifetimes generally begin after and end before
// NetworkChangeNotifierMac.  There is an edge case where a notification task
// gets posted to the IO thread, thereby maintaining a reference to
// NetworkChangeNotifierImpl beyond the lifetime of NetworkChangeNotifierThread.
// In this case, the notification is cancelled, and NetworkChangeNotifierImpl
// will be deleted once all notification tasks that reference it have been run.

#include "net/base/network_change_notifier_mac.h"
#include <SystemConfiguration/SCDynamicStore.h>
#include <SystemConfiguration/SCDynamicStoreKey.h>
#include <SystemConfiguration/SCSchemaDefinitions.h>
#include <algorithm>
#include "base/logging.h"
#include "base/scoped_cftyperef.h"
#include "base/thread.h"

namespace net {

namespace {

// NetworkChangeNotifierImpl should be created on a thread with a CFRunLoop,
// since it requires one to pump notifications.  However, it also runs some
// methods on |notifier_loop_|, because it cannot post calls to |notifier_|
// since NetworkChangeNotifier is not ref counted in a thread safe manner.
class NetworkChangeNotifierImpl
    : public base::RefCountedThreadSafe<NetworkChangeNotifierImpl> {
 public:
  NetworkChangeNotifierImpl(MessageLoop* notifier_loop,
                            NetworkChangeNotifierMac* notifier);

  void Shutdown();

 private:
  friend class base::RefCountedThreadSafe<NetworkChangeNotifierImpl>;
  ~NetworkChangeNotifierImpl();

  static void DynamicStoreCallback(SCDynamicStoreRef /* store */,
                                   CFArrayRef changed_keys,
                                   void* config);

  void OnNetworkConfigChange(CFArrayRef changed_keys);

  // Runs on |notifier_loop_|.
  void OnIPAddressChanged();

  // Raw pointers.  Note that |notifier_| _must_ outlive the
  // NetworkChangeNotifierImpl.  For lifecycle management details, read the
  // comment at the top of the file.
  MessageLoop* const notifier_loop_;
  NetworkChangeNotifierMac* notifier_;

  scoped_cftyperef<CFRunLoopSourceRef> source_;

  DISALLOW_COPY_AND_ASSIGN(NetworkChangeNotifierImpl);
};

NetworkChangeNotifierImpl::NetworkChangeNotifierImpl(
    MessageLoop* notifier_loop, NetworkChangeNotifierMac* notifier)
    : notifier_loop_(notifier_loop),
      notifier_(notifier) {
  DCHECK_EQ(MessageLoop::TYPE_UI, MessageLoop::current()->type());
  SCDynamicStoreContext context = {
    0,    // Version 0.
    this, // User data.
    NULL, // This is not reference counted.  No retain function.
    NULL, // This is not reference counted.  No release function.
    NULL, // No description for this.
  };

  // Get a reference to the dynamic store.
  scoped_cftyperef<SCDynamicStoreRef> store(
      SCDynamicStoreCreate(NULL /* use default allocator */,
                           CFSTR("org.chromium"),
                           DynamicStoreCallback, &context));

  // Create a run loop source for the dynamic store.
  source_.reset(SCDynamicStoreCreateRunLoopSource(
      NULL /* use default allocator */,
      store.get(),
      0 /* 0 sounds like a fine source order to me! */));

  // Add the run loop source to the current run loop.
  CFRunLoopAddSource(CFRunLoopGetCurrent(),
                     source_.get(),
                     kCFRunLoopCommonModes);

  // Set up the notification keys.
  scoped_cftyperef<CFMutableArrayRef> notification_keys(
      CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks));

  // Monitor interface changes.
  scoped_cftyperef<CFStringRef> key(
      SCDynamicStoreKeyCreateNetworkGlobalEntity(
          NULL /* default allocator */, kSCDynamicStoreDomainState,
          kSCEntNetInterface));
  CFArrayAppendValue(notification_keys.get(), key.get());

  // Monitor IP address changes.

  key.reset(SCDynamicStoreKeyCreateNetworkGlobalEntity(
      NULL /* default allocator */, kSCDynamicStoreDomainState,
      kSCEntNetIPv4));
  CFArrayAppendValue(notification_keys.get(), key.get());

  key.reset(SCDynamicStoreKeyCreateNetworkGlobalEntity(
      NULL /* default allocator */, kSCDynamicStoreDomainState,
      kSCEntNetIPv6));
  CFArrayAppendValue(notification_keys.get(), key.get());

  // Ok, let's ask for notifications!
  // TODO(willchan): Figure out a proper way to handle this rather than crash.
  CHECK(SCDynamicStoreSetNotificationKeys(
      store.get(), notification_keys.get(), NULL));
}

NetworkChangeNotifierImpl::~NetworkChangeNotifierImpl() {
  CFRunLoopRemoveSource(CFRunLoopGetCurrent(),
                        source_.get(),
                        kCFRunLoopCommonModes);
}

void NetworkChangeNotifierImpl::Shutdown() {
  CHECK(notifier_);
  notifier_ = NULL;
}

// static
void NetworkChangeNotifierImpl::DynamicStoreCallback(
    SCDynamicStoreRef /* store */,
    CFArrayRef changed_keys,
    void* config) {
  NetworkChangeNotifierImpl* net_config =
      static_cast<NetworkChangeNotifierImpl*>(config);
  net_config->OnNetworkConfigChange(changed_keys);
}

void NetworkChangeNotifierImpl::OnNetworkConfigChange(CFArrayRef changed_keys) {
  for (CFIndex i = 0; i < CFArrayGetCount(changed_keys); ++i) {
    CFStringRef key = static_cast<CFStringRef>(
        CFArrayGetValueAtIndex(changed_keys, i));
    if (CFStringHasSuffix(key, kSCEntNetIPv4) ||
        CFStringHasSuffix(key, kSCEntNetIPv6)) {
      notifier_loop_->PostTask(
          FROM_HERE,
          NewRunnableMethod(
              this,
              &NetworkChangeNotifierImpl::OnIPAddressChanged));
    } else if (CFStringHasSuffix(key, kSCEntNetInterface)) {
      // TODO(willchan): Does not appear to be working.  Look into this.
      // Perhaps this isn't needed anyway.
    } else {
      NOTREACHED();
    }
  }
}

void NetworkChangeNotifierImpl::OnIPAddressChanged() {
  // If |notifier_| doesn't exist, then that means we're shutting down, so
  // notifications are all cancelled.
  if (notifier_)
    notifier_->OnIPAddressChanged();
}

class NetworkChangeNotifierThread : public base::Thread {
 public:
  NetworkChangeNotifierThread(MessageLoop* notifier_loop,
                              NetworkChangeNotifierMac* notifier);
  ~NetworkChangeNotifierThread();

 protected:
  virtual void Init();

 private:
  MessageLoop* const notifier_loop_;
  NetworkChangeNotifierMac* const notifier_;
  scoped_refptr<NetworkChangeNotifierImpl> notifier_impl_;

  DISALLOW_COPY_AND_ASSIGN(NetworkChangeNotifierThread);
};

NetworkChangeNotifierThread::NetworkChangeNotifierThread(
    MessageLoop* notifier_loop, NetworkChangeNotifierMac* notifier)
    : base::Thread("NetworkChangeNotifier"),
      notifier_loop_(notifier_loop),
      notifier_(notifier) {}

NetworkChangeNotifierThread::~NetworkChangeNotifierThread() {
  notifier_impl_->Shutdown();
  Stop();
}

// Note that |notifier_impl_| is initialized on the network change
// notifier thread, not whatever thread constructs the
// NetworkChangeNotifierThread object.  This is important, because this thread
// is the one that has a CFRunLoop.
void NetworkChangeNotifierThread::Init() {
  notifier_impl_ =
      new NetworkChangeNotifierImpl(notifier_loop_, notifier_);
}

}  // namespace

NetworkChangeNotifierMac::NetworkChangeNotifierMac()
    : notifier_thread_(
          new NetworkChangeNotifierThread(MessageLoop::current(), this)) {
  base::Thread::Options thread_options;
  thread_options.message_loop_type = MessageLoop::TYPE_UI;
  notifier_thread_->StartWithOptions(thread_options);
}

NetworkChangeNotifierMac::~NetworkChangeNotifierMac() {}

}  // namespace net
<|endoftext|>


<commit_before>#ifdef _WIN32
#define M_PI 3.14
#endif

#include <cmath>
#include <iostream>
#include <fstream>

#include "Body.hpp"

#define G 9.82 // TODO: Get the right number
#define DENSITY 20 // kg/m^3

using namespace sf;
using namespace std;

Body::Body(Vector2f pos, int m, Vector2f dir)
	: position(pos), direction(dir), mass(m)
{
	if (mass <= 0)
	{
		cout << "FATAL ERROR: MASS <= 0" << endl;
	}

	// Radius
	float volume = mass / DENSITY;
	radius = cbrt((3*volume)/(4*M_PI));

	if (radius <= 1)
	{
		radius = 1;
	}

	shape.setRadius(radius);
	shape.setFillColor(Color::Red);

	cout << "New planet with radius " << radius << " at position (" << pos.x << ';' << pos.y << ")" << endl;
}

void Body::move(float dt)
{
	position += direction * dt;
}

void Body::applyGravityOf(const Body &b, float dt)
{
    float r = getDistanceTo(b);

    if (r <= 0)
    {
    	cout << "FATAL ERROR: distance <= 0" << endl;
    	return;
    }

    float F = (G*mass*b.mass) / (r*r);

    // Make the force proportional to the mass
    F /= mass;

	// Get the unit vector to the other body
	Vector2f to_Body(b.position - position);
	to_Body = to_Body / r;

    // Apply the force in the direction of the other body
    direction += (to_Body * F) * dt;
}

float Body::getDistanceTo(const Body &p)
{
    Vector2f a = position;
	Vector2f b = p.position;
    Vector2f c = b - a;

    return sqrt(c.x*c.x + c.y * c.y);
}

void Body::draw(RenderWindow &window)
{
	shape.setPosition(position);
	window.draw(shape);
}

bool Body::collideWith(const Body &p)
{
	Vector2f a = position;
	Vector2f b = p.position;
	float d = (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y);

	float r1 = shape.getRadius();
	float r2 = p.shape.getRadius();
	if (d > (r1+r2)*(r1+r2))
		return false;
	return true;
}

bool Body::contains(const Vector2f &point)
{
    Vector2f a = position;
    Vector2f b = point;
    Vector2f c = b - a;

    if ((c.x*c.x + c.y * c.y) <= shape.getRadius()*shape.getRadius())
    {
        return true;
    }

    return false;
}
<commit_msg>removed garbage<commit_after>#ifdef _WIN32
#define M_PI 3.14
#endif

#include <cmath>
#include <iostream>
#include <fstream>

#include "Body.hpp"

#define G 9.82 // TODO: Get the right number
#define DENSITY 20 // kg/m^3

using namespace sf;
using namespace std;

Body::Body(Vector2f pos, int m, Vector2f dir)
	: position(pos), direction(dir), mass(m)
{
	if (mass <= 0)
	{
		cout << "FATAL ERROR: MASS <= 0" << endl;
	}

	// Radius
	float volume = mass / DENSITY;
	radius = cbrt((3*volume)/(4*M_PI));

	if (radius <= 1)
	{
		radius = 1;
	}

	shape.setRadius(radius);
	shape.setFillColor(Color::Red);
}

void Body::move(float dt)
{
	position += direction * dt;
}

void Body::applyGravityOf(const Body &b, float dt)
{
    float r = getDistanceTo(b);

    float F = (G*mass*b.mass) / (r*r);

    // Make the force proportional to the mass
    F /= mass;

	// Get the unit vector to the other body
	Vector2f to_Body(b.position - position);
	to_Body = to_Body / r;

    // Apply the force in the direction of the other body
    direction += (to_Body * F) * dt;
}

float Body::getDistanceTo(const Body &p)
{
    Vector2f a = position;
	Vector2f b = p.position;
    Vector2f c = b - a;

    return sqrt(c.x*c.x + c.y * c.y);
}

void Body::draw(RenderWindow &window)
{
	shape.setPosition(position);
	window.draw(shape);
}

bool Body::collideWith(const Body &p)
{
	Vector2f a = position;
	Vector2f b = p.position;
	float d = (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y);

	float r1 = shape.getRadius();
	float r2 = p.shape.getRadius();
	if (d > (r1+r2)*(r1+r2))
		return false;
	return true;
}

bool Body::contains(const Vector2f &point)
{
    Vector2f a = position;
    Vector2f b = point;
    Vector2f c = b - a;

    if ((c.x*c.x + c.y * c.y) <= shape.getRadius()*shape.getRadius())
    {
        return true;
    }

    return false;
}
<|endoftext|>