<commit_before>#include "StudentTRand.h"
#include "NormalRand.h"
#include "CauchyRand.h"

StudentTRand::StudentTRand(double degree, double location, double scale)
{
    SetDegree(degree);
    SetLocation(location);
    SetScale(scale);
}

std::string StudentTRand::Name() const
{
    if (mu == 0.0 && sigma == 1.0)
        return "Student's t(" + toStringWithPrecision(GetDegree()) + ")";
    return "Student's t(" + toStringWithPrecision(GetDegree()) + ", "
                          + toStringWithPrecision(GetLocation()) + ", "
                          + toStringWithPrecision(GetScale()) + ")";
}

void StudentTRand::SetDegree(double degree)
{
    nu = degree > 0 ? degree : 1;
    Y.SetParameters(0.5 * nu, 1.0);

    nup1Half = 0.5 * (nu + 1);
    pdfCoef = std::lgamma(nup1Half);
    pdfCoef -= 0.5 * M_LNPI;
    pdfCoef -= Y.GetLogGammaFunction();
    logBetaFun = -pdfCoef;
    pdfCoef -= 0.5 * std::log(nu);
}

void StudentTRand::SetLocation(double location)
{
    mu = location;
}

void StudentTRand::SetScale(double scale)
{
    sigma = scale > 0 ? scale : 1.0;
    logSigma = std::log(sigma);
}

double StudentTRand::f(const double & x) const
{
    /// adjustment
    double x0 = x - mu;
    x0 /= sigma;
    double xSq = x0 * x0;
    if (nu == 1) /// Cauchy distribution
        return M_1_PI / (sigma * (1 + xSq));
    if (nu == 2)
        return 1.0 / (sigma * std::pow(2.0 + xSq, 1.5));
    if (nu == 3) {
        double y = 3 + xSq;
        return 6 * M_SQRT3 * M_1_PI / (sigma * y * y);
    }
    return std::exp(logf(x));
}

double StudentTRand::logf(const double & x) const
{
    /// adjustment
    double x0 = x - mu;
    x0 /= sigma;
    double xSq = x0 * x0;
    if (nu == 1) /// Cauchy distribution
        return std::log(M_1_PI / (sigma * (1 + xSq)));
    if (nu == 2) {
        return -logSigma - 1.5 * std::log(2.0 + xSq);
    }
    if (nu == 3) {
        double y = 3 + xSq;
        y = 6 * M_SQRT3 * M_1_PI / (sigma * y * y);
        return std::log(y);
    }
    double y = -nup1Half * std::log1p(xSq / nu);
    return pdfCoef + y - logSigma;
}

double StudentTRand::F(const double & x) const
{
    double x0 = x - mu;
    x0 /= sigma;
    if (x0 == 0.0)
        return 0.5;
    if (nu == 1) {
        /// Cauchy distribution
        return 0.5 + M_1_PI * RandMath::atan(x0);
    }
    if (nu == 2) {
        return 0.5 + 0.5 * x0 / std::sqrt(2 + x0 * x0);
    }
    if (nu == 3) {
        double y = M_SQRT3 * x0 / (x0 * x0 + 3);
        y += RandMath::atan(x0 / M_SQRT3);
        return 0.5 + M_1_PI * y;
    }
    double t = nu / (x0 * x0 + nu);
    double y = 0.5 * RandMath::ibeta(t, 0.5 * nu, 0.5, logBetaFun, std::log(t), std::log1p(-t));
    return (x0 > 0.0) ? (1.0 - y) : y;
}

double StudentTRand::S(const double & x) const
{
    double x0 = x - mu;
    x0 /= sigma;
    if (x0 == 0.0)
        return 0.5;
    if (nu == 1) {
        /// Cauchy distribution
        return 0.5 + M_1_PI * RandMath::atan(-x0);
    }
    if (nu == 2) {
        return 0.5 - 0.5 * x0 / std::sqrt(2 + x0 * x0);
    }
    if (nu == 3) {
        double y = M_SQRT3 * x0 / (x0 * x0 + 3);
        y += RandMath::atan(x0 / M_SQRT3);
        return 0.5 - M_1_PI * y;
    }
    double t = nu / (x0 * x0 + nu);
    double y = 0.5 * RandMath::ibeta(t, 0.5 * nu, 0.5, logBetaFun, std::log(t), std::log1p(-t));
    return (x0 > 0.0) ? y : 1.0 - y;
}

double StudentTRand::Variate() const
{
    if (nu == 1)
        return CauchyRand::Variate(mu, sigma);
    return mu + sigma * NormalRand::StandardVariate() / Y.Variate();
}

void StudentTRand::Sample(std::vector<double> &outputData) const
{
    if (nu == 1) {
        for (double &var : outputData)
            var = CauchyRand::Variate(mu, sigma);
    }
    else {
        Y.Sample(outputData);
        for (double &var : outputData)
            var = mu + sigma * NormalRand::StandardVariate() / var;
    }
}

double StudentTRand::Mean() const
{
    return (nu > 1) ? mu : NAN;
}

double StudentTRand::Variance() const
{
    if (nu > 2)
        return sigma * sigma * nu / (nu - 2);
    return (nu > 1) ? INFINITY : NAN;
}

std::complex<double> StudentTRand::CFImpl(double t) const
{
    double x = std::sqrt(nu) * std::fabs(t * sigma); // value of sqrt(nu) can be hashed
    double vHalf = 0.5 * nu;
    double y = vHalf * std::log(x);
    y -= Y.GetLogGammaFunction();
    y -= (vHalf - 1) * M_LN2;
    y += RandMath::logModifiedBesselSecondKind(x, vHalf);
    double costmu = std::cos(t * mu), sintmu = std::sin(t * mu);
    std::complex<double> cf(costmu, sintmu);
    return std::exp(y) * cf;
}

double StudentTRand::quantileImpl(double p) const
{
    double temp = p - 0.5;
    if (nu == 1)
        return std::tan(M_PI * temp) * sigma + mu;
    double pq = p * (1.0 - p);
    if (nu == 2)
        return sigma * 2.0 * temp * std::sqrt(0.5 / pq) + mu;
    if (nu == 4)
    {
        double alpha = 2 * std::sqrt(pq);
        double beta = std::cos(std::acos(alpha) / 3.0) / alpha - 1;
        return mu + sigma * 2 * RandMath::sign(temp) * std::sqrt(beta);
    }
    return ContinuousDistribution::quantileImpl(p);
}

double StudentTRand::quantileImpl1m(double p) const
{
    double temp = 0.5 - p;
    if (nu == 1)
        return std::tan(M_PI * temp) * sigma + mu;
    double pq = p * (1.0 - p);
    if (nu == 2)
        return sigma * 2 * temp * std::sqrt(0.5 / pq) + mu;
    if (nu == 4)
    {
        double alpha = 2 * std::sqrt(pq);
        double beta = std::cos(std::acos(alpha) / 3.0) / alpha - 1;
        return mu + sigma * 2 * RandMath::sign(temp) * std::sqrt(beta);
    }
    return ContinuousDistribution::quantileImpl1m(p);
}

double StudentTRand::Median() const
{
    return mu;
}

double StudentTRand::Mode() const
{
    return mu;
}

double StudentTRand::Skewness() const
{
    return (nu > 3) ? 0.0 : NAN;
}

double StudentTRand::ExcessKurtosis() const
{
    if (nu > 4)
        return 6 / (nu - 4);
    return (nu > 2) ? INFINITY : NAN;
}
<commit_msg>Update StudentTRand.cpp<commit_after>#include "StudentTRand.h"
#include "NormalRand.h"
#include "CauchyRand.h"

StudentTRand::StudentTRand(double degree, double location, double scale)
{
    SetDegree(degree);
    SetLocation(location);
    SetScale(scale);
}

std::string StudentTRand::Name() const
{
    if (mu == 0.0 && sigma == 1.0)
        return "Student's t(" + toStringWithPrecision(GetDegree()) + ")";
    return "Student's t(" + toStringWithPrecision(GetDegree()) + ", "
                          + toStringWithPrecision(GetLocation()) + ", "
                          + toStringWithPrecision(GetScale()) + ")";
}

void StudentTRand::SetDegree(double degree)
{
    nu = degree > 0 ? degree : 1;
    Y.SetParameters(0.5 * nu, 1.0);

    nup1Half = 0.5 * (nu + 1);
    pdfCoef = std::lgamma(nup1Half);
    pdfCoef -= 0.5 * M_LNPI;
    pdfCoef -= Y.GetLogGammaFunction();
    logBetaFun = -pdfCoef;
    pdfCoef -= 0.5 * std::log(nu);
}

void StudentTRand::SetLocation(double location)
{
    mu = location;
}

void StudentTRand::SetScale(double scale)
{
    sigma = scale > 0 ? scale : 1.0;
    logSigma = std::log(sigma);
}

double StudentTRand::f(const double & x) const
{
    /// adjustment
    double x0 = x - mu;
    x0 /= sigma;
    double xSq = x0 * x0;
    if (nu == 1) /// Cauchy distribution
        return M_1_PI / (sigma * (1 + xSq));
    if (nu == 2)
        return 1.0 / (sigma * std::pow(2.0 + xSq, 1.5));
    if (nu == 3) {
        double y = 3 + xSq;
        return 6 * M_SQRT3 * M_1_PI / (sigma * y * y);
    }
    return std::exp(logf(x));
}

double StudentTRand::logf(const double & x) const
{
    /// adjustment
    double x0 = x - mu;
    x0 /= sigma;
    double xSq = x0 * x0;
    if (nu == 1) /// Cauchy distribution
        return -std::log1p(xSq) - logSigma - M_LNPI;
    if (nu == 2)
        return -logSigma - 1.5 * std::log(2.0 + xSq);
    if (nu == 3) {
        double y = 3 + xSq;
        y = 6 * M_SQRT3 * M_1_PI / (sigma * y * y);
        return std::log(y);
    }
    double y = -nup1Half * std::log1p(xSq / nu);
    return pdfCoef + y - logSigma;
}

double StudentTRand::F(const double & x) const
{
    double x0 = x - mu;
    x0 /= sigma;
    if (x0 == 0.0)
        return 0.5;
    if (nu == 1) {
        /// Cauchy distribution
        return 0.5 + M_1_PI * RandMath::atan(x0);
    }
    if (nu == 2) {
        return 0.5 + 0.5 * x0 / std::sqrt(2 + x0 * x0);
    }
    if (nu == 3) {
        double y = M_SQRT3 * x0 / (x0 * x0 + 3);
        y += RandMath::atan(x0 / M_SQRT3);
        return 0.5 + M_1_PI * y;
    }
    double t = nu / (x0 * x0 + nu);
    double y = 0.5 * RandMath::ibeta(t, 0.5 * nu, 0.5, logBetaFun, std::log(t), std::log1p(-t));
    return (x0 > 0.0) ? (1.0 - y) : y;
}

double StudentTRand::S(const double & x) const
{
    double x0 = x - mu;
    x0 /= sigma;
    if (x0 == 0.0)
        return 0.5;
    if (nu == 1) {
        /// Cauchy distribution
        return 0.5 + M_1_PI * RandMath::atan(-x0);
    }
    if (nu == 2) {
        return 0.5 - 0.5 * x0 / std::sqrt(2 + x0 * x0);
    }
    if (nu == 3) {
        double y = M_SQRT3 * x0 / (x0 * x0 + 3);
        y += RandMath::atan(x0 / M_SQRT3);
        return 0.5 - M_1_PI * y;
    }
    double t = nu / (x0 * x0 + nu);
    double y = 0.5 * RandMath::ibeta(t, 0.5 * nu, 0.5, logBetaFun, std::log(t), std::log1p(-t));
    return (x0 > 0.0) ? y : 1.0 - y;
}

double StudentTRand::Variate() const
{
    if (nu == 1)
        return CauchyRand::Variate(mu, sigma);
    return mu + sigma * NormalRand::StandardVariate() / Y.Variate();
}

void StudentTRand::Sample(std::vector<double> &outputData) const
{
    if (nu == 1) {
        for (double &var : outputData)
            var = CauchyRand::Variate(mu, sigma);
    }
    else {
        Y.Sample(outputData);
        for (double &var : outputData)
            var = mu + sigma * NormalRand::StandardVariate() / var;
    }
}

double StudentTRand::Mean() const
{
    return (nu > 1) ? mu : NAN;
}

double StudentTRand::Variance() const
{
    if (nu > 2)
        return sigma * sigma * nu / (nu - 2);
    return (nu > 1) ? INFINITY : NAN;
}

std::complex<double> StudentTRand::CFImpl(double t) const
{
    double x = std::sqrt(nu) * std::fabs(t * sigma); // value of sqrt(nu) can be hashed
    double vHalf = 0.5 * nu;
    double y = vHalf * std::log(x);
    y -= Y.GetLogGammaFunction();
    y -= (vHalf - 1) * M_LN2;
    y += RandMath::logModifiedBesselSecondKind(x, vHalf);
    double costmu = std::cos(t * mu), sintmu = std::sin(t * mu);
    std::complex<double> cf(costmu, sintmu);
    return std::exp(y) * cf;
}

double StudentTRand::quantileImpl(double p) const
{
    double temp = p - 0.5;
    if (nu == 1)
        return std::tan(M_PI * temp) * sigma + mu;
    double pq = p * (1.0 - p);
    if (nu == 2)
        return sigma * 2.0 * temp * std::sqrt(0.5 / pq) + mu;
    if (nu == 4)
    {
        double alpha = 2 * std::sqrt(pq);
        double beta = std::cos(std::acos(alpha) / 3.0) / alpha - 1;
        return mu + sigma * 2 * RandMath::sign(temp) * std::sqrt(beta);
    }
    return ContinuousDistribution::quantileImpl(p);
}

double StudentTRand::quantileImpl1m(double p) const
{
    double temp = 0.5 - p;
    if (nu == 1)
        return std::tan(M_PI * temp) * sigma + mu;
    double pq = p * (1.0 - p);
    if (nu == 2)
        return sigma * 2 * temp * std::sqrt(0.5 / pq) + mu;
    if (nu == 4)
    {
        double alpha = 2 * std::sqrt(pq);
        double beta = std::cos(std::acos(alpha) / 3.0) / alpha - 1;
        return mu + sigma * 2 * RandMath::sign(temp) * std::sqrt(beta);
    }
    return ContinuousDistribution::quantileImpl1m(p);
}

double StudentTRand::Median() const
{
    return mu;
}

double StudentTRand::Mode() const
{
    return mu;
}

double StudentTRand::Skewness() const
{
    return (nu > 3) ? 0.0 : NAN;
}

double StudentTRand::ExcessKurtosis() const
{
    if (nu > 4)
        return 6 / (nu - 4);
    return (nu > 2) ? INFINITY : NAN;
}
<|endoftext|>


<commit_before>#pragma once

#include <type_traits>
#include <tuple>
#include <agency/detail/integer_sequence.hpp>

#define __DEFINE_HAS_NESTED_TYPE(trait_name, nested_type_name) \
template<typename T> \
  struct trait_name  \
{                    \
  typedef char yes_type; \
  typedef int  no_type;  \
  template<typename S> static yes_type test(typename S::nested_type_name *); \
  template<typename S> static no_type  test(...); \
  static bool const value = sizeof(test<T>(0)) == sizeof(yes_type);\
  typedef std::integral_constant<bool, value> type;\
};

#define __DEFINE_HAS_NESTED_CLASS_TEMPLATE(trait_name, nested_class_template_name) \
template<typename T, typename... Types> \
  struct trait_name         \
{                           \
  typedef char yes_type;    \
  typedef int  no_type;     \
  template<typename S> static yes_type test(typename S::template nested_class_template_name<Types...> *); \
  template<typename S> static no_type  test(...); \
  static bool const value = sizeof(test<T>(0)) == sizeof(yes_type);\
  typedef std::integral_constant<bool, value> type;\
};

#ifdef __NVCC__
#define __DEFINE_HAS_NESTED_MEMBER(trait_name, nested_member_name) \
template<typename T> \
  struct trait_name  \
{                    \
  typedef char yes_type; \
  typedef int  no_type;  \
  template<int i> struct swallow_int {}; \
  template<typename S> static yes_type test(swallow_int<sizeof(S::nested_member_name)>*); \
  template<typename S> static no_type  test(...); \
  static bool const value = sizeof(test<T>(0)) == sizeof(yes_type);\
  typedef std::integral_constant<bool, value> type;\
};
#else
#define __DEFINE_HAS_NESTED_MEMBER(trait_name, nested_member_name) \
template<typename T> \
  struct trait_name  \
{                    \
  typedef char yes_type; \
  typedef int  no_type;  \
  template<typename S> static yes_type test(decltype(S::nested_member_name)*); \
  template<typename S> static no_type  test(...); \
  static bool const value = sizeof(test<T>(0)) == sizeof(yes_type);\
  typedef std::integral_constant<bool, value> type;\
};
#endif

namespace agency
{
namespace detail
{

template<bool b, typename T, typename F>
struct lazy_conditional
{
  using type = typename T::type;
};

template<typename T, typename F>
struct lazy_conditional<false,T,F>
{
  using type = typename F::type;
};

template<typename T>
struct identity
{
  typedef T type;
};

template<class T>
using decay_t = typename std::decay<T>::type;

template<class T>
using result_of_t = typename std::result_of<T>::type;

template<class... Types> struct type_list {};

template<class TypeList> struct type_list_size;

template<class... Types>
struct type_list_size<type_list<Types...>> : std::integral_constant<size_t, sizeof...(Types)> {};

template<size_t i, class TypeList>
struct type_list_element_impl;

template<class T0, class... Types>
struct type_list_element_impl<0,type_list<T0,Types...>>
{
  using type = T0;
};

template<size_t i, class T0, class... Types>
struct type_list_element_impl<i,type_list<T0,Types...>>
{
  using type = typename type_list_element_impl<i-1,type_list<Types...>>::type;
};

template<size_t i, class TypeList>
using type_list_element = typename type_list_element_impl<i,TypeList>::type;

template<class TypeList, class IndexSequence>
struct type_list_take_impl_impl;

template<class TypeList, size_t... I>
struct type_list_take_impl_impl<TypeList, index_sequence<I...>>
{
  using type = type_list<
    type_list_element<I,TypeList>...
  >;
};

template<size_t n, class TypeList>
struct type_list_take_impl;

template<size_t n, class... Types>
struct type_list_take_impl<n,type_list<Types...>>
{
  using type = typename type_list_take_impl_impl<
    type_list<Types...>,
    make_index_sequence<n>
  >::type;
};

template<size_t n, class TypeList>
using type_list_take = typename type_list_take_impl<n,TypeList>::type;

namespace type_list_detail
{

template<int a, int b>
struct max : std::integral_constant<
  int,
  (a < b ? b : a)
>
{};

} // end type_list_detail

template<size_t n, class TypeList>
using type_list_drop = type_list_take<
  type_list_detail::max<
    0,
    type_list_size<TypeList>::value - n
  >::value,
  TypeList
>;

template<class TypeList>
using type_list_drop_last = type_list_drop<1,TypeList>;

template<class T, class TypeList>
struct is_constructible_from_type_list;

template<class T, class... Types>
struct is_constructible_from_type_list<T,type_list<Types...>>
  : std::is_constructible<T,Types...>
{};

template<class T0, class TypeList>
struct type_list_prepend;

template<class T0, class... Types>
struct type_list_prepend<T0, type_list<Types...>>
{
  using type = type_list<T0, Types...>;
};

template<class T, size_t n>
struct repeat_type_impl
{
  using rest = typename repeat_type_impl<T,n-1>::type;
  using type = typename type_list_prepend<
    T,
    rest
  >::type;
};

template<class T>
struct repeat_type_impl<T,0>
{
  using type = type_list<>;
};

template<class T, size_t n>
using repeat_type = typename repeat_type_impl<T,n>::type;

template<class... Conditions>
struct static_and;

template<>
struct static_and<> : std::true_type {};

template<class Condition, class... Conditions>
struct static_and<Condition, Conditions...>
  : std::integral_constant<
      bool,
      Condition::value && static_and<Conditions...>::value
    >
{};

template<class... Conditions>
struct static_or;

template<>
struct static_or<> : std::false_type {};

template<class Condition, class... Conditions>
struct static_or<Condition, Conditions...>
  : std::integral_constant<
      bool,
      Condition::value || static_or<Conditions...>::value
    >
{};

__DEFINE_HAS_NESTED_MEMBER(has_value, value);

template<class T>
struct is_tuple : has_value<std::tuple_size<T>> {};

template<class Indices, class Tuple>
struct tuple_type_list_impl;

template<size_t... Indices, class Tuple>
struct tuple_type_list_impl<index_sequence<Indices...>, Tuple>
{
  using type = type_list<
    typename std::tuple_element<Indices,Tuple>::type...
  >;
};

template<class T, class Enable = void>
struct tuple_type_list;

template<class Tuple>
struct tuple_type_list<Tuple, typename std::enable_if<is_tuple<Tuple>::value>::type>
{
  using type = typename tuple_type_list_impl<
    make_index_sequence<std::tuple_size<Tuple>::value>,
    Tuple
  >::type;
};

template<class>
struct is_empty_tuple;

template<class T>
struct is_empty_tuple_impl_impl;

template<class... Types>
struct is_empty_tuple_impl_impl<type_list<Types...>>
{
  using type = static_and<
    static_or<
      std::is_empty<Types>,
      is_empty_tuple<Types>
    >...
  >;
};

template<class T, class Enable = void>
struct is_empty_tuple_impl : std::false_type {};

template<class Tuple>
struct is_empty_tuple_impl<Tuple, typename std::enable_if<is_tuple<Tuple>::value>::type>
{
  using type = typename is_empty_tuple_impl_impl<
    typename tuple_type_list<Tuple>::type
  >::type;
};

template<class Tuple>
struct is_empty_tuple : is_empty_tuple_impl<Tuple>::type {};

template<class T>
struct lazy_add_lvalue_reference
{
  using type = typename std::add_lvalue_reference<typename T::type>::type;
};

template<class T, template<class...> class Template>
struct is_instance_of : std::false_type {};

template<class... Types, template<class...> class Template>
struct is_instance_of<Template<Types...>,Template> : std::true_type {};

} // end detail
} // end agency

<commit_msg>Put type_list in its own header<commit_after>#pragma once

#include <type_traits>
#include <tuple>
#include <agency/detail/integer_sequence.hpp>
#include <agency/detail/type_list.hpp>

#define __DEFINE_HAS_NESTED_TYPE(trait_name, nested_type_name) \
template<typename T> \
  struct trait_name  \
{                    \
  typedef char yes_type; \
  typedef int  no_type;  \
  template<typename S> static yes_type test(typename S::nested_type_name *); \
  template<typename S> static no_type  test(...); \
  static bool const value = sizeof(test<T>(0)) == sizeof(yes_type);\
  typedef std::integral_constant<bool, value> type;\
};

#define __DEFINE_HAS_NESTED_CLASS_TEMPLATE(trait_name, nested_class_template_name) \
template<typename T, typename... Types> \
  struct trait_name         \
{                           \
  typedef char yes_type;    \
  typedef int  no_type;     \
  template<typename S> static yes_type test(typename S::template nested_class_template_name<Types...> *); \
  template<typename S> static no_type  test(...); \
  static bool const value = sizeof(test<T>(0)) == sizeof(yes_type);\
  typedef std::integral_constant<bool, value> type;\
};

#ifdef __NVCC__
#define __DEFINE_HAS_NESTED_MEMBER(trait_name, nested_member_name) \
template<typename T> \
  struct trait_name  \
{                    \
  typedef char yes_type; \
  typedef int  no_type;  \
  template<int i> struct swallow_int {}; \
  template<typename S> static yes_type test(swallow_int<sizeof(S::nested_member_name)>*); \
  template<typename S> static no_type  test(...); \
  static bool const value = sizeof(test<T>(0)) == sizeof(yes_type);\
  typedef std::integral_constant<bool, value> type;\
};
#else
#define __DEFINE_HAS_NESTED_MEMBER(trait_name, nested_member_name) \
template<typename T> \
  struct trait_name  \
{                    \
  typedef char yes_type; \
  typedef int  no_type;  \
  template<typename S> static yes_type test(decltype(S::nested_member_name)*); \
  template<typename S> static no_type  test(...); \
  static bool const value = sizeof(test<T>(0)) == sizeof(yes_type);\
  typedef std::integral_constant<bool, value> type;\
};
#endif

namespace agency
{
namespace detail
{

template<bool b, typename T, typename F>
struct lazy_conditional
{
  using type = typename T::type;
};

template<typename T, typename F>
struct lazy_conditional<false,T,F>
{
  using type = typename F::type;
};

template<typename T>
struct identity
{
  typedef T type;
};

template<class T>
using decay_t = typename std::decay<T>::type;

template<class T>
using result_of_t = typename std::result_of<T>::type;

template<class T, size_t n>
struct repeat_type_impl
{
  using rest = typename repeat_type_impl<T,n-1>::type;
  using type = typename type_list_prepend<
    T,
    rest
  >::type;
};

template<class T>
struct repeat_type_impl<T,0>
{
  using type = type_list<>;
};

template<class T, size_t n>
using repeat_type = typename repeat_type_impl<T,n>::type;

template<class... Conditions>
struct static_and;

template<>
struct static_and<> : std::true_type {};

template<class Condition, class... Conditions>
struct static_and<Condition, Conditions...>
  : std::integral_constant<
      bool,
      Condition::value && static_and<Conditions...>::value
    >
{};

template<class... Conditions>
struct static_or;

template<>
struct static_or<> : std::false_type {};

template<class Condition, class... Conditions>
struct static_or<Condition, Conditions...>
  : std::integral_constant<
      bool,
      Condition::value || static_or<Conditions...>::value
    >
{};

__DEFINE_HAS_NESTED_MEMBER(has_value, value);

template<class T>
struct is_tuple : has_value<std::tuple_size<T>> {};

template<class Indices, class Tuple>
struct tuple_type_list_impl;

template<size_t... Indices, class Tuple>
struct tuple_type_list_impl<index_sequence<Indices...>, Tuple>
{
  using type = type_list<
    typename std::tuple_element<Indices,Tuple>::type...
  >;
};

template<class T, class Enable = void>
struct tuple_type_list;

template<class Tuple>
struct tuple_type_list<Tuple, typename std::enable_if<is_tuple<Tuple>::value>::type>
{
  using type = typename tuple_type_list_impl<
    make_index_sequence<std::tuple_size<Tuple>::value>,
    Tuple
  >::type;
};

template<class>
struct is_empty_tuple;

template<class T>
struct is_empty_tuple_impl_impl;

template<class... Types>
struct is_empty_tuple_impl_impl<type_list<Types...>>
{
  using type = static_and<
    static_or<
      std::is_empty<Types>,
      is_empty_tuple<Types>
    >...
  >;
};

template<class T, class Enable = void>
struct is_empty_tuple_impl : std::false_type {};

template<class Tuple>
struct is_empty_tuple_impl<Tuple, typename std::enable_if<is_tuple<Tuple>::value>::type>
{
  using type = typename is_empty_tuple_impl_impl<
    typename tuple_type_list<Tuple>::type
  >::type;
};

template<class Tuple>
struct is_empty_tuple : is_empty_tuple_impl<Tuple>::type {};

template<class T>
struct lazy_add_lvalue_reference
{
  using type = typename std::add_lvalue_reference<typename T::type>::type;
};

template<class T, template<class...> class Template>
struct is_instance_of : std::false_type {};

template<class... Types, template<class...> class Template>
struct is_instance_of<Template<Types...>,Template> : std::true_type {};

} // end detail
} // end agency

<|endoftext|>


<commit_before>/*
 * StreamServerManager.cpp
 *
 *  Created on: Sep 10, 2015
 *      Author: alarrosa14
 */
#include <chrono>

#include "lz4.h"
#include "lz4frame.h"

#include "StreamServerManager.h"

StreamServerManager::StreamServerManager(void) {
	waitForNewFrameMutex.lock();
}

StreamServerManager::~StreamServerManager(void) {}

void StreamServerManager::setEnabled(const bool &isEnabled) {
	this->enabled = isEnabled;
}

void StreamServerManager::setCompressionEnabled(const bool &compression) {
	this->compressionEnabled = compression;
}

void StreamServerManager::setAddress(const string &address) {
	this->address = address;
}

void StreamServerManager::setPixelQuantity(const int &pixelQty){
	this->pixelQuantity = pixelQty;
}

void StreamServerManager::setPort(const int &port){
	this->port = port;
}

bool StreamServerManager::getEnabled() {
	return this->enabled;
}

bool StreamServerManager::getCompressionEnabled() {
	return this->compressionEnabled;
}

string StreamServerManager::getAddress() {
	return this->address;
}

int StreamServerManager::getPixelQuantity() {
	return this->pixelQuantity;
}

int StreamServerManager::getPort(){
	return this->port;
}

void StreamServerManager::setupStreamingSender() {
	cout << "Server config: " << this->address << endl << this->port << endl;
	cout << "Compression enabled? " << (this->compressionEnabled ? "True" : "False") << endl;
	string url = "http://" + this->address + ":" + to_string(this->port);
	cout << "Setting up Streaming Server: " << url << endl;

	udpManager.Create();
	cout << this->address.c_str() << this->port << endl;
	if (!udpManager.Connect(this->address.c_str(), this->port));
		cout << endl << endl << "Error connecting socket!" << endl << endl;
	udpManager.SetNonBlocking(true);

}

void StreamServerManager::addFrameToSendBuffer(DTFrame* newFrame) {
	lock();
	this->sendBuffer.push_back(newFrame);
	unlock();
	waitForNewFrameMutex.unlock();
}

void convertToArrayOfBytes(void* data, int length, unsigned char *buffer) {
	char* ptr = (char*)data;
	for (int i = 0; i < length; i++)
		buffer[i] = *ptr++;
};

uint64_t htonll(uint64_t n) {
#if __BYTE_ORDER == __BIG_ENDIAN
    return n;
#else
    return (((uint64_t)htonl(n)) << 32) + htonl(n >> 32);
#endif
}

uint64_t ntohll(uint64_t n) {
	return htonll(n);
}

void StreamServerManager::threadedFunction() {

	const int frameSize = this->pixelQuantity*3;

	size_t compressedBufferMaxSize;
	unsigned char *compressedBuffer = NULL;
	if (compressionEnabled) {
		compressedBufferMaxSize = LZ4F_compressFrameBound(frameSize, NULL);
		compressedBuffer = new unsigned char[compressedBufferMaxSize];
	}

	const int bufferSize = ((compressionEnabled && compressedBufferMaxSize > frameSize) ? compressedBufferMaxSize : frameSize) + sizeof(uint64_t);
	unsigned char *buffer = new unsigned char[bufferSize];

	while(isThreadRunning()) {

		waitForNewFrameMutex.lock();
		lock();
		if(this->sendBuffer.size()>0){
	        vector<DTFrame*>::iterator it = this->sendBuffer.begin();
	        this->sendBuffer.erase(it);
	        unlock();

	        uint8_t* raw_frame = (*it)->getRawFrameData();
			int raw_frame_length = (*it)->getPixelQuantity()*3;

			assert(raw_frame_length == this->pixelQuantity*3);

			using namespace std::chrono;
			uint64_t ms = htonll(duration_cast< milliseconds >(
			    system_clock::now().time_since_epoch()
			).count());

			convertToArrayOfBytes(&ms, sizeof(ms), buffer);

			if (compressionEnabled) {
				size_t compressedBufferSize = LZ4F_compressFrame(compressedBuffer, compressedBufferMaxSize, raw_frame, raw_frame_length, NULL);
				convertToArrayOfBytes(compressedBuffer, compressedBufferSize, buffer + sizeof(ms));
				this->udpManager.Send((char*) buffer, sizeof(ms) + compressedBufferSize);
			} else {
				convertToArrayOfBytes(raw_frame, raw_frame_length, buffer + sizeof(ms));
				this->udpManager.Send((char*) buffer, bufferSize);
			}

		} else {
	    	unlock();
	    }
	}
	this->udpManager.Close();
	delete[]buffer;
	delete[]compressedBuffer;
}
<commit_msg>Now sending a 1 byte long timestamp in each frame to Sendero Streaming Server<commit_after>/*
 * StreamServerManager.cpp
 *
 *  Created on: Sep 10, 2015
 *      Author: alarrosa14
 */
#include <chrono>

#include "lz4.h"
#include "lz4frame.h"

#include "StreamServerManager.h"

StreamServerManager::StreamServerManager(void) {
	waitForNewFrameMutex.lock();
}

StreamServerManager::~StreamServerManager(void) {}

void StreamServerManager::setEnabled(const bool &isEnabled) {
	this->enabled = isEnabled;
}

void StreamServerManager::setCompressionEnabled(const bool &compression) {
	this->compressionEnabled = compression;
}

void StreamServerManager::setAddress(const string &address) {
	this->address = address;
}

void StreamServerManager::setPixelQuantity(const int &pixelQty){
	this->pixelQuantity = pixelQty;
}

void StreamServerManager::setPort(const int &port){
	this->port = port;
}

bool StreamServerManager::getEnabled() {
	return this->enabled;
}

bool StreamServerManager::getCompressionEnabled() {
	return this->compressionEnabled;
}

string StreamServerManager::getAddress() {
	return this->address;
}

int StreamServerManager::getPixelQuantity() {
	return this->pixelQuantity;
}

int StreamServerManager::getPort(){
	return this->port;
}

void StreamServerManager::setupStreamingSender() {
	cout << "Server config: " << this->address << endl << this->port << endl;
	cout << "Compression enabled? " << (this->compressionEnabled ? "True" : "False") << endl;
	string url = "http://" + this->address + ":" + to_string(this->port);
	cout << "Setting up Streaming Server: " << url << endl;

	udpManager.Create();
	cout << this->address.c_str() << this->port << endl;
	if (!udpManager.Connect(this->address.c_str(), this->port));
		cout << endl << endl << "Error connecting socket!" << endl << endl;
	udpManager.SetNonBlocking(true);

}

void StreamServerManager::addFrameToSendBuffer(DTFrame* newFrame) {
	lock();
	this->sendBuffer.push_back(newFrame);
	unlock();
	waitForNewFrameMutex.unlock();
}

void convertToArrayOfBytes(void* data, int length, unsigned char *buffer) {
	char* ptr = (char*)data;
	for (int i = 0; i < length; i++)
		buffer[i] = *ptr++;
};

uint64_t htonll(uint64_t n) {
#if __BYTE_ORDER == __BIG_ENDIAN
    return n;
#else
    return (((uint64_t)htonl(n)) << 32) + htonl(n >> 32);
#endif
}

uint64_t ntohll(uint64_t n) {
	return htonll(n);
}

void StreamServerManager::threadedFunction() {

	uint8_t currentSeqNmb = 0;

	const int frameSize = this->pixelQuantity*3;

	size_t compressedBufferMaxSize;
	unsigned char *compressedBuffer = NULL;
	if (compressionEnabled) {
		compressedBufferMaxSize = LZ4F_compressFrameBound(frameSize, NULL);
		compressedBuffer = new unsigned char[compressedBufferMaxSize];
	}

	const int bufferSize = ((compressionEnabled && compressedBufferMaxSize > frameSize) ? compressedBufferMaxSize : frameSize) + sizeof(uint64_t) + sizeof(uint8_t);
	unsigned char *buffer = new unsigned char[bufferSize];

	using namespace std::chrono;
	while(isThreadRunning()) {

		waitForNewFrameMutex.lock();
		lock();
		if(this->sendBuffer.size()>0){
	        vector<DTFrame*>::iterator it = this->sendBuffer.begin();
	        this->sendBuffer.erase(it);
	        unlock();

	        uint8_t* raw_frame = (*it)->getRawFrameData();
			int raw_frame_length = (*it)->getPixelQuantity()*3;

			assert(raw_frame_length == this->pixelQuantity*3);

			uint64_t ms = htonll(duration_cast< milliseconds >(
			    system_clock::now().time_since_epoch()
			).count());

			convertToArrayOfBytes(&ms, sizeof(ms), buffer);
			convertToArrayOfBytes(&currentSeqNmb, sizeof(currentSeqNmb), buffer + sizeof(ms));

			if (compressionEnabled) {
				size_t compressedBufferSize = LZ4F_compressFrame(compressedBuffer, compressedBufferMaxSize, raw_frame, raw_frame_length, NULL);
				convertToArrayOfBytes(compressedBuffer, compressedBufferSize, buffer + sizeof(ms) + sizeof(currentSeqNmb));
				this->udpManager.Send((char*) buffer, sizeof(ms) + sizeof(currentSeqNmb) + compressedBufferSize);
			} else {
				convertToArrayOfBytes(raw_frame, raw_frame_length, buffer + sizeof(ms));
				this->udpManager.Send((char*) buffer, bufferSize);
			}

			currentSeqNmb = (currentSeqNmb + 1) % 256;

		} else {
	    	unlock();
	    }
	}
	this->udpManager.Close();
	delete[]buffer;
	delete[]compressedBuffer;
}
<|endoftext|>


<commit_before>#include "details/pass/build-ast-to-ir/scope.h"
#include "details/grammar/nany.h"
#include "details/ast/ast.h"
#include <limits>

using namespace Yuni;

namespace Nany
{
namespace IR
{
namespace Producer
{

	namespace // anonymous
	{

		struct NumberDef final
		{
			// Is the number signed or unsigned ?
			bool isUnsigned = false;
			// Is the number a floating-point number ?
			bool isFloat = false;
			// how many bits used by the number ? (32 by default)
			uint bits = 32;
			// Sign of the number: ' ', '+', '-'
			char sign = ' ';

			//! The first part of the number
			uint64_t part1 = 0;
			//! Second part of the number
			AnyString part2; // the second part may have additional zero
		};

		static constexpr inline bool validNumberOfBits(uint32_t bits)
		{
			return bits == 32 or bits == 64 or bits == 16 or bits == 8;
		}

		static bool convertASTNumberToDouble(double& value, uint64 part1, const AnyString& part2, char sign)
		{
			if (part1 == 0 and part2.empty()) // obvious zero value
			{
				value = 0.;
			}
			else
			{
				ShortString128 tmp;
				if (sign == '-') // append the sign of the number
					tmp += '-';

				tmp << part1;
				if (not part2.empty())
					tmp << '.' << part2;

				if (unlikely(not tmp.to<double>(value)))
				{
					value = 0.;
					return false;
				}
			}
			return true;
		}

	} // anonymous namespace

	template<bool BuiltinT, class DefT>
	inline bool Scope::generateNumberCode(uint32_t& localvar, const DefT& numdef, const AST::Node& node)
	{
		// checking for invalid float values
		nytype_t type = nyt_void;
		// class name
		AnyString cn;
		uint32_t hardcodedlvid;

		if (not numdef.isFloat)
		{
			if (not numdef.isUnsigned)
			{
				switch (numdef.bits)
				{
					case 64: type = nyt_i64; if (not BuiltinT) cn = "i64"; break;
					case 32: type = nyt_i32; if (not BuiltinT) cn = "i32"; break;
					case 16: type = nyt_i16; if (not BuiltinT) cn = "i16"; break;
					case  8: type = nyt_i8;  if (not BuiltinT) cn = "i8";  break;
				}
			}
			else
			{
				switch (numdef.bits)
				{
					case 64: type = nyt_u64; if (not BuiltinT) cn = "u64"; break;
					case 32: type = nyt_u32; if (not BuiltinT) cn = "u32"; break;
					case 16: type = nyt_u16; if (not BuiltinT) cn = "u16"; break;
					case  8: type = nyt_u8;  if (not BuiltinT) cn = "u8";  break;
				}
			}

			if (numdef.part1 != 0)
			{
				bool invalidcast = false;

				if (numdef.sign == ' ' or numdef.sign == '+')
				{
					if (not numdef.isUnsigned)
					{
						switch (numdef.bits)
						{
							case 64: invalidcast = (numdef.part1 > std::numeric_limits<int32_t>::max()); break;
							case 32: invalidcast = (numdef.part1 > std::numeric_limits<int32_t>::max()); break;
							case 16: invalidcast = (numdef.part1 > std::numeric_limits<int16_t>::max()); break;
							case  8: invalidcast = (numdef.part1 > std::numeric_limits< int8_t>::max()); break;
						}
					}
					else
					{
						switch (numdef.bits)
						{
							case 64: break;
							case 32: invalidcast = (numdef.part1 > std::numeric_limits<uint32_t>::max()); break;
							case 16: invalidcast = (numdef.part1 > std::numeric_limits<uint16_t>::max()); break;
							case  8: invalidcast = (numdef.part1 > std::numeric_limits< uint8_t>::max()); break;
						}
					}
				}
				else
				{
					if (not numdef.isUnsigned)
					{
						if (numdef.part1 < static_cast<uint64_t>(std::numeric_limits<int64_t>::max()))
						{
							int64_t sv = static_cast<int64_t>(numdef.part1);
							switch (numdef.bits)
							{
								case 64: invalidcast = (sv < std::numeric_limits<int32_t>::min()); break;
								case 32: invalidcast = (sv < std::numeric_limits<int32_t>::min()); break;
								case 16: invalidcast = (sv < std::numeric_limits<int16_t>::min()); break;
								case  8: invalidcast = (sv < std::numeric_limits< int8_t>::min()); break;
							}
						}
						else
							invalidcast = true;
					}
					else
						invalidcast = true;
				}

				if (unlikely(invalidcast))
				{
					error(node) << "invalid " << ((numdef.isUnsigned) ? "unsigned " : "signed ")
						<< numdef.bits << "bits integer";
					return false;
				}
			}

			hardcodedlvid = createLocalBuiltinInt(node, type, numdef.part1);
		}
		else
		{
			// converting the number into a double
			double value;
			if (unlikely(not convertASTNumberToDouble(value, numdef.part1, numdef.part2, numdef.sign)))
				return (error(node) << "invalid floating point number");

			type = (numdef.bits == 32) ? nyt_f32 : nyt_f64;
			if (not BuiltinT)
				cn.adapt((numdef.bits == 32) ? "f32" : "f64", 3);
			hardcodedlvid = createLocalBuiltinFloat(node, type, value);
		}

		if (BuiltinT)
		{
			localvar = hardcodedlvid;
			return true;
		}
		else
		{
			if (!context.reuse.literal.node)
				context.prepareReuseForLiterals();

			assert(not cn.empty());
			context.reuse.literal.classname->text = cn;
			ShortString16 lvidstr;
			lvidstr = hardcodedlvid;
			context.reuse.literal.lvidnode->text = lvidstr;

			bool success = visitASTExprNew(*(context.reuse.literal.node), localvar);

			// avoid crap in the debugger
			context.reuse.literal.classname->text.clear();
			context.reuse.literal.lvidnode->text.clear();
			return success;
		}
	}

	bool Scope::visitASTExprNumber(const AST::Node& node, yuint32& localvar)
	{
		assert(node.rule == AST::rgNumber);
		assert(not node.children.empty());

		// Number definition
		NumberDef numdef;
		// is a builtin ? (__i32, __f64...)
		// (always generate builtin types when not importing the NSL)
		bool builtin = (not Config::importNSL);

		emitDebugpos(node);

		for (auto& childptr: node.children)
		{
			switch (childptr->rule)
			{
				case AST::rgNumberValue: // standard number definition
				{
					bool firstPart = true;
					for (auto& subnodeptr: childptr->children)
					{
						switch (subnodeptr->rule)
						{
							case AST::rgInteger:
							{
								if (likely(firstPart))
								{
									if (not subnodeptr->text.to<uint64>(numdef.part1))
									{
										error(*subnodeptr) << "invalid integer value";
										return false;
									}
									firstPart = false;
								}
								else
								{
									numdef.part2 = subnodeptr->text;
									numdef.part2.trimRight('0'); // remove useless zeros
									// as far as we know, it is a float64 by default
									numdef.isFloat = true;
								}
								break;
							}

							default:
							{
								ice(*subnodeptr) << "[expr-number]";
								return false;
							}
						}
					}
					break;
				}

				case AST::rgNumberSign: // + -
				{
					assert(not childptr->text.empty() and "invalid ast");
					numdef.sign = childptr->text[0];
					assert(numdef.sign == '+' or numdef.sign == '-');
					break;
				}

				case AST::rgNumberQualifier: // unsigned / signed / float
				{
					for (auto& subnodeptr: childptr->children)
					{
						auto& subnode = *(subnodeptr);
						switch (subnode.rule)
						{
							case AST::rgNumberQualifierType:
							{
								assert(not subnode.text.empty());
								uint offset = 0;
								if (subnode.text.first() == '_' and subnode.text[1] == '_')
								{
									offset = 2;
									builtin = true;
								}
								for (uint i = offset; i < subnode.text.size(); ++i)
								{
									switch (subnode.text[i])
									{
										case 'i': numdef.isUnsigned = false; break;
										case 'u': numdef.isUnsigned = true; break;
										case 'f': numdef.isFloat = true; break;
										default: error(node) << "invalid number qualifier. Got '"
											<< subnode.text.first() << "', expected 'i', 'u' or 'f'";
									}
								}
								break;
							}
							case AST::rgInteger:
							{
								if (likely(subnode.text.size() < 10))
								{
									numdef.bits = subnode.text.to<uint>();
									if (unlikely(not validNumberOfBits(numdef.bits)))
										return (error(subnode) << "invalid integer size");
								}
								else
								{
									error(subnode) << "integer too large";
									return false;
								}
								break;
							}
							default:
							{
								ice(subnode) << "[expr-number]";
								return false;
							}
						}
					}

					break;
				}

				default:
				{
					ice(*childptr) << "[expr-number]";
					return false;
				}
			}
		}

		assert(numdef.bits == 64 or numdef.bits == 32 or numdef.bits == 16 or numdef.bits == 8);

		return (not builtin)
			? generateNumberCode<false>(localvar, numdef, node)
			: generateNumberCode<true> (localvar, numdef, node);
	}

} // namespace Producer
} // namespace IR
} // namespace Nany
<commit_msg>fixed invalid interpretation of negative numbers<commit_after>#include "details/pass/build-ast-to-ir/scope.h"
#include "details/grammar/nany.h"
#include "details/ast/ast.h"
#include <limits>

using namespace Yuni;

namespace Nany
{
namespace IR
{
namespace Producer
{

	namespace // anonymous
	{

		struct NumberDef final
		{
			// Is the number signed or unsigned ?
			bool isUnsigned = false;
			// Is the number a floating-point number ?
			bool isFloat = false;
			// how many bits used by the number ? (32 by default)
			uint bits = 32;
			// Sign of the number: ' ', '+', '-'
			char sign = ' ';

			//! The first part of the number
			uint64_t part1 = 0;
			//! Second part of the number
			AnyString part2; // the second part may have additional zero
		};

		static constexpr inline bool validNumberOfBits(uint32_t bits)
		{
			return bits == 32 or bits == 64 or bits == 16 or bits == 8;
		}

		static bool convertASTNumberToDouble(double& value, uint64 part1, const AnyString& part2, char sign)
		{
			if (part1 == 0 and part2.empty()) // obvious zero value
			{
				value = 0.;
			}
			else
			{
				ShortString128 tmp;
				if (sign == '-') // append the sign of the number
					tmp += '-';

				tmp << part1;
				if (not part2.empty())
					tmp << '.' << part2;

				if (unlikely(not tmp.to<double>(value)))
				{
					value = 0.;
					return false;
				}
			}
			return true;
		}

	} // anonymous namespace

	template<bool BuiltinT, class DefT>
	inline bool Scope::generateNumberCode(uint32_t& localvar, const DefT& numdef, const AST::Node& node)
	{
		// checking for invalid float values
		nytype_t type = nyt_void;
		// class name
		AnyString cn;
		uint32_t hardcodedlvid;
		bool negate = false;

		if (not numdef.isFloat)
		{
			if (not numdef.isUnsigned)
			{
				switch (numdef.bits)
				{
					case 64: type = nyt_i64; if (not BuiltinT) cn = "i64"; break;
					case 32: type = nyt_i32; if (not BuiltinT) cn = "i32"; break;
					case 16: type = nyt_i16; if (not BuiltinT) cn = "i16"; break;
					case  8: type = nyt_i8;  if (not BuiltinT) cn = "i8";  break;
				}
			}
			else
			{
				switch (numdef.bits)
				{
					case 64: type = nyt_u64; if (not BuiltinT) cn = "u64"; break;
					case 32: type = nyt_u32; if (not BuiltinT) cn = "u32"; break;
					case 16: type = nyt_u16; if (not BuiltinT) cn = "u16"; break;
					case  8: type = nyt_u8;  if (not BuiltinT) cn = "u8";  break;
				}
			}

			if (numdef.part1 != 0)
			{
				bool invalidcast = false;

				negate = (numdef.sign == '-');
				if (not negate)
				{
					if (not numdef.isUnsigned)
					{
						switch (numdef.bits)
						{
							case 64: invalidcast = (numdef.part1 > std::numeric_limits<int32_t>::max()); break;
							case 32: invalidcast = (numdef.part1 > std::numeric_limits<int32_t>::max()); break;
							case 16: invalidcast = (numdef.part1 > std::numeric_limits<int16_t>::max()); break;
							case  8: invalidcast = (numdef.part1 > std::numeric_limits< int8_t>::max()); break;
						}
					}
					else
					{
						switch (numdef.bits)
						{
							case 64: break;
							case 32: invalidcast = (numdef.part1 > std::numeric_limits<uint32_t>::max()); break;
							case 16: invalidcast = (numdef.part1 > std::numeric_limits<uint16_t>::max()); break;
							case  8: invalidcast = (numdef.part1 > std::numeric_limits< uint8_t>::max()); break;
						}
					}
				}
				else
				{
					if (not numdef.isUnsigned)
					{
						if (numdef.part1 < static_cast<uint64_t>(std::numeric_limits<int64_t>::max()))
						{
							int64_t sv = static_cast<int64_t>(numdef.part1);
							switch (numdef.bits)
							{
								case 64: invalidcast = (sv < std::numeric_limits<int32_t>::min()); break;
								case 32: invalidcast = (sv < std::numeric_limits<int32_t>::min()); break;
								case 16: invalidcast = (sv < std::numeric_limits<int16_t>::min()); break;
								case  8: invalidcast = (sv < std::numeric_limits< int8_t>::min()); break;
							}
						}
						else
							invalidcast = true;
					}
					else
						invalidcast = true;
				}

				if (unlikely(invalidcast))
				{
					error(node) << "invalid " << ((numdef.isUnsigned) ? "unsigned " : "signed ")
						<< numdef.bits << "bits integer";
					return false;
				}
			}

			uint64_t number = (not negate)
				? numdef.part1
				: (uint64_t)( - static_cast<int64_t>(numdef.part1)); // reinterpret to avoid unwanted type promotion
			hardcodedlvid = createLocalBuiltinInt(node, type, number);
		}
		else
		{
			// converting the number into a double
			double value;
			if (unlikely(not convertASTNumberToDouble(value, numdef.part1, numdef.part2, numdef.sign)))
				return (error(node) << "invalid floating point number");

			type = (numdef.bits == 32) ? nyt_f32 : nyt_f64;
			if (not BuiltinT)
				cn.adapt((numdef.bits == 32) ? "f32" : "f64", 3);
			hardcodedlvid = createLocalBuiltinFloat(node, type, value);
		}

		if (BuiltinT)
		{
			localvar = hardcodedlvid;
			return true;
		}
		else
		{
			if (!context.reuse.literal.node)
				context.prepareReuseForLiterals();

			assert(not cn.empty());
			context.reuse.literal.classname->text = cn;
			ShortString16 lvidstr;
			lvidstr = hardcodedlvid;
			context.reuse.literal.lvidnode->text = lvidstr;

			bool success = visitASTExprNew(*(context.reuse.literal.node), localvar);

			// avoid crap in the debugger
			context.reuse.literal.classname->text.clear();
			context.reuse.literal.lvidnode->text.clear();
			return success;
		}
	}

	bool Scope::visitASTExprNumber(const AST::Node& node, yuint32& localvar)
	{
		assert(node.rule == AST::rgNumber);
		assert(not node.children.empty());

		// Number definition
		NumberDef numdef;
		// is a builtin ? (__i32, __f64...)
		// (always generate builtin types when not importing the NSL)
		bool builtin = (not Config::importNSL);

		emitDebugpos(node);

		for (auto& childptr: node.children)
		{
			switch (childptr->rule)
			{
				case AST::rgNumberValue: // standard number definition
				{
					bool firstPart = true;
					for (auto& subnodeptr: childptr->children)
					{
						switch (subnodeptr->rule)
						{
							case AST::rgInteger:
							{
								if (likely(firstPart))
								{
									if (not subnodeptr->text.to<uint64>(numdef.part1))
									{
										error(*subnodeptr) << "invalid integer value";
										return false;
									}
									firstPart = false;
								}
								else
								{
									numdef.part2 = subnodeptr->text;
									numdef.part2.trimRight('0'); // remove useless zeros
									// as far as we know, it is a float64 by default
									numdef.isFloat = true;
								}
								break;
							}

							default:
							{
								ice(*subnodeptr) << "[expr-number]";
								return false;
							}
						}
					}
					break;
				}

				case AST::rgNumberSign: // + -
				{
					assert(not childptr->text.empty() and "invalid ast");
					numdef.sign = childptr->text[0];
					assert(numdef.sign == '+' or numdef.sign == '-');
					break;
				}

				case AST::rgNumberQualifier: // unsigned / signed / float
				{
					for (auto& subnodeptr: childptr->children)
					{
						auto& subnode = *(subnodeptr);
						switch (subnode.rule)
						{
							case AST::rgNumberQualifierType:
							{
								assert(not subnode.text.empty());
								uint offset = 0;
								if (subnode.text.first() == '_' and subnode.text[1] == '_')
								{
									offset = 2;
									builtin = true;
								}
								for (uint i = offset; i < subnode.text.size(); ++i)
								{
									switch (subnode.text[i])
									{
										case 'i': numdef.isUnsigned = false; break;
										case 'u': numdef.isUnsigned = true; break;
										case 'f': numdef.isFloat = true; break;
										default: error(node) << "invalid number qualifier. Got '"
											<< subnode.text.first() << "', expected 'i', 'u' or 'f'";
									}
								}
								break;
							}
							case AST::rgInteger:
							{
								if (likely(subnode.text.size() < 10))
								{
									numdef.bits = subnode.text.to<uint>();
									if (unlikely(not validNumberOfBits(numdef.bits)))
										return (error(subnode) << "invalid integer size");
								}
								else
								{
									error(subnode) << "integer too large";
									return false;
								}
								break;
							}
							default:
							{
								ice(subnode) << "[expr-number]";
								return false;
							}
						}
					}

					break;
				}

				default:
				{
					ice(*childptr) << "[expr-number]";
					return false;
				}
			}
		}

		assert(numdef.bits == 64 or numdef.bits == 32 or numdef.bits == 16 or numdef.bits == 8);

		return (not builtin)
			? generateNumberCode<false>(localvar, numdef, node)
			: generateNumberCode<true> (localvar, numdef, node);
	}

} // namespace Producer
} // namespace IR
} // namespace Nany
<|endoftext|>


<commit_before>//===-------------------------- SILCombine --------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// A port of LLVM's InstCombine pass to SIL. Its main purpose is for performing
// small combining operations/peepholes at the SIL level. It additionally
// performs dead code elimination when it initially adds instructions to the
// work queue in order to reduce compile time by not visiting trivially dead
// instructions.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "sil-combine"
#include "swift/SILPasses/Passes.h"
#include "SILCombiner.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILVisitor.h"
#include "swift/SILAnalysis/AliasAnalysis.h"
#include "swift/SILAnalysis/SimplifyInstruction.h"
#include "swift/SILPasses/Transforms.h"
#include "swift/SILPasses/Utils/Local.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Debug.h"

using namespace swift;

STATISTIC(NumSimplified, "Number of instructions simplified");
STATISTIC(NumCombined, "Number of instructions combined");
STATISTIC(NumDeadInst, "Number of dead insts eliminated");

//===----------------------------------------------------------------------===//
//                              Utility Methods
//===----------------------------------------------------------------------===//

/// addReachableCodeToWorklist - Walk the function in depth-first order, adding
/// all reachable code to the worklist.
///
/// This has a couple of tricks to make the code faster and more powerful.  In
/// particular, we DCE instructions as we go, to avoid adding them to the
/// worklist (this significantly speeds up SILCombine on code where many
/// instructions are dead or constant).
void SILCombiner::addReachableCodeToWorklist(SILBasicBlock *BB) {
  llvm::SmallVector<SILBasicBlock*, 256> Worklist;
  llvm::SmallVector<SILInstruction*, 128> InstrsForSILCombineWorklist;
  llvm::SmallPtrSet<SILBasicBlock*, 64> Visited;

  Worklist.push_back(BB);
  do {
    BB = Worklist.pop_back_val();

    // We have now visited this block!  If we've already been here, ignore it.
    if (!Visited.insert(BB).second) continue;

    for (SILBasicBlock::iterator BBI = BB->begin(), E = BB->end(); BBI != E; ) {
      SILInstruction *Inst = BBI++;

      // DCE instruction if trivially dead.
      if (isInstructionTriviallyDead(Inst)) {
        ++NumDeadInst;
        DEBUG(llvm::dbgs() << "SC: DCE: " << *Inst << '\n');

        // We pass in false here since we need to signal to
        // eraseInstFromFunction to not add this instruction's operands to the
        // worklist since we have not initialized the worklist yet.
        //
        // The reason to just use a default argument here is that it allows us
        // to centralize all instruction removal in SILCombine into this one
        // function. This is important if we want to be able to update analyses
        // in a clean manner.
        eraseInstFromFunction(*Inst, false /*Don't add operands to worklist*/);
        continue;
      }

      InstrsForSILCombineWorklist.push_back(Inst);
    }

    // Recursively visit successors.
    for (auto SI = BB->succ_begin(), SE = BB->succ_end(); SI != SE; ++SI)
      Worklist.push_back(*SI);
  } while (!Worklist.empty());

  // Once we've found all of the instructions to add to the worklist, add them
  // in reverse order. This way SILCombine will visit from the top of the
  // function down. This jives well with the way that it adds all uses of
  // instructions to the worklist after doing a transformation, thus avoiding
  // some N^2 behavior in pathological cases.
  addInitialGroup(InstrsForSILCombineWorklist);
}

//===----------------------------------------------------------------------===//
//                               Implementation
//===----------------------------------------------------------------------===//

void SILCombineWorklist::add(SILInstruction *I) {
  if (!WorklistMap.insert(std::make_pair(I, Worklist.size())).second)
    return;

  DEBUG(llvm::dbgs() << "SC: ADD: " << *I << '\n');
  Worklist.push_back(I);
}

bool SILCombiner::doOneIteration(SILFunction &F, unsigned Iteration) {
  MadeChange = false;

  DEBUG(llvm::dbgs() << "\n\nSILCOMBINE ITERATION #" << Iteration << " on "
                     << F.getName() << "\n");

  // Add reachable instructions to our worklist.
  addReachableCodeToWorklist(F.begin());

  // Process until we run out of items in our worklist.
  while (!Worklist.isEmpty()) {
    SILInstruction *I = Worklist.removeOne();

    // When we erase an instruction, we use the map in the worklist to check if
    // the instruction is in the worklist. If it is, we replace it with null
    // instead of shifting all members of the worklist towards the front. This
    // check makes sure that if we run into any such residual null pointers, we
    // skip them.
    if (I == 0)
      continue;

    // Check to see if we can DCE the instruction.
    if (isInstructionTriviallyDead(I)) {
      DEBUG(llvm::dbgs() << "SC: DCE: " << *I << '\n');
      eraseInstFromFunction(*I);
      ++NumDeadInst;
      MadeChange = true;
      continue;
    }

    // Check to see if we can instsimplify the instruction.
    if (SILValue Result = simplifyInstruction(I)) {
      ++NumSimplified;

      DEBUG(llvm::dbgs() << "SC: Simplify Old = " << *I << '\n'
                         << "    New = " << *Result.getDef() << '\n');

      // Everything uses the new instruction now.
      replaceInstUsesWith(*I, Result.getDef(), 0, Result.getResultNumber());

      // Push the new instruction and any users onto the worklist.
      Worklist.addUsersToWorklist(Result.getDef());

      eraseInstFromFunction(*I);
      MadeChange = true;
      continue;
    }

    // If we have reached this point, all attempts to do simple simplifications
    // have failed. Prepare to SILCombine.
    Builder->setInsertionPoint(I->getParent(), I);

#ifndef NDEBUG
    std::string OrigI;
#endif
    DEBUG(llvm::raw_string_ostream SS(OrigI); I->print(SS); OrigI = SS.str(););
    DEBUG(llvm::dbgs() << "SC: Visiting: " << OrigI << '\n');

    if (SILInstruction *Result = visit(I)) {
      ++NumCombined;
      // Should we replace the old instruction with a new one?
      if (Result != I) {
        // Insert the new instruction into the basic block.
        I->getParent()->getInstList().insert(I, Result);

        DEBUG(llvm::dbgs() << "SC: Old = " << *I << '\n'
                           << "    New = " << *Result << '\n');

        // Everything uses the new instruction now.
        replaceInstUsesWith(*I, Result);

        // Push the new instruction and any users onto the worklist.
        Worklist.add(Result);
        Worklist.addUsersToWorklist(Result);

        eraseInstFromFunction(*I);
      } else {
        DEBUG(llvm::dbgs() << "SC: Mod = " << OrigI << '\n'
                     << "    New = " << *I << '\n');

        // If the instruction was modified, it's possible that it is now dead.
        // if so, remove it.
        if (isInstructionTriviallyDead(I)) {
          eraseInstFromFunction(*I);
        } else {
          Worklist.add(I);
          Worklist.addUsersToWorklist(I);
        }
      }
      MadeChange = true;
    }

    // Our tracking list has been accumulating instructions created by the
    // SILBuilder during this iteration. Go through the tracking list and add
    // its contents to the worklist and then clear said list in preparation for
    // the next iteration.
    for (SILInstruction *I : TrackingList)
      Worklist.add(I);
    TrackingList.clear();
  }

  Worklist.zap();
  return MadeChange;
}

void SILCombineWorklist::addInitialGroup(ArrayRef<SILInstruction *> List) {
  assert(Worklist.empty() && "Worklist must be empty to add initial group");
  Worklist.reserve(List.size()+16);
  WorklistMap.resize(List.size());
  DEBUG(llvm::dbgs() << "SC: ADDING: " << List.size()
        << " instrs to worklist\n");
  while (!List.empty()) {
    SILInstruction *I = List.back();
    List = List.slice(0, List.size()-1);
    WorklistMap.insert(std::make_pair(I, Worklist.size()));
    Worklist.push_back(I);
    }
}

bool SILCombiner::runOnFunction(SILFunction &F) {
  clear();

  // Create a SILBuilder for F and initialize the tracking list.
  SILBuilder B(F);
  B.setTrackingList(&TrackingList);
  Builder = &B;

  bool Changed = false;
  // Perform iterations until we do not make any changes.
  while (doOneIteration(F, Iteration)) {
    Changed = true;
    Iteration++;
  }

  // Cleanup the builder and return whether or not we made any changes.
  Builder = nullptr;
  return Changed;
}

// Insert the instruction New before instruction Old in Old's parent BB. Add
// New to the worklist.
SILInstruction *SILCombiner::insertNewInstBefore(SILInstruction *New,
                                                 SILInstruction &Old) {
  assert(New && New->getParent() == 0 &&
         "New instruction already inserted into a basic block!");
  SILBasicBlock *BB = Old.getParent();
  BB->getInstList().insert(&Old, New);  // Insert inst
  Worklist.add(New);
  return New;
}

// This method is to be used when an instruction is found to be dead,
// replacable with another preexisting expression. Here we add all uses of I
// to the worklist, replace all uses of I with the new value, then return I,
// so that the combiner will know that I was modified.
SILInstruction *SILCombiner::replaceInstUsesWith(SILInstruction &I,
                                                 ValueBase *V) {
  Worklist.addUsersToWorklist(&I);   // Add all modified instrs to worklist.

  DEBUG(llvm::dbgs() << "SC: Replacing " << I << "\n"
        "    with " << *V << '\n');

  I.replaceAllUsesWith(V);

  return &I;
}

/// This is meant to be used when one is attempting to replace only one of the
/// results of I with a result of V.
SILInstruction *
SILCombiner::
replaceInstUsesWith(SILInstruction &I, ValueBase *V, unsigned IIndex,
                    unsigned VIndex) {
  assert(IIndex < I.getNumTypes() && "Can not have more results than "
         "types.");
  assert(VIndex < V->getNumTypes() && "Can not have more results than "
         "types.");

  // Add all modified instrs to worklist.
  Worklist.addUsersToWorklist(&I, IIndex);

  DEBUG(llvm::dbgs() << "SC: Replacing " << I << "\n"
        "    with " << *V << '\n');

  SILValue(&I, IIndex).replaceAllUsesWith(SILValue(V, VIndex));

  return &I;
}

// Some instructions can never be "trivially dead" due to side effects or
// producing a void value. In those cases, since we can not rely on
// SILCombines trivially dead instruction DCE in order to delete the
// instruction, visit methods should use this method to delete the given
// instruction and upon completion of their peephole return the value returned
// by this method.
SILInstruction *SILCombiner::eraseInstFromFunction(SILInstruction &I,
                                                   bool AddOperandsToWorklist) {
  DEBUG(llvm::dbgs() << "SC: ERASE " << I << '\n');

  assert(I.use_empty() && "Cannot erase instruction that is used!");
  // Make sure that we reprocess all operands now that we reduced their
  // use counts.
  if (I.getNumOperands() < 8 && AddOperandsToWorklist)
    for (auto &OpI : I.getAllOperands())
      if (SILInstruction *Op = llvm::dyn_cast<SILInstruction>(&*OpI.get()))
        Worklist.add(Op);

  // If we have a call graph and we've removing an apply, remove the
  // associated edges from the call graph.
  if (CG)
    if (auto *AI = dyn_cast<ApplyInst>(&I))
      CG->removeEdgesForApply(AI, true /*Ignore Missing*/);

  Worklist.remove(&I);
  I.eraseFromParent();
  MadeChange = true;
  return nullptr;  // Don't do anything with I
}

//===----------------------------------------------------------------------===//
//                                Entry Points
//===----------------------------------------------------------------------===//

namespace {

class SILCombine : public SILFunctionTransform {

  /// The entry point to the transformation.
  void run() override {
    auto *AA = PM->getAnalysis<AliasAnalysis>();

    // Call Graph Analysis in case we need to perform Call Graph updates.
    auto *CGA = PM->getAnalysis<CallGraphAnalysis>();
    SILCombiner Combiner(AA, CGA->getCallGraphOrNull(),
                         getOptions().RemoveRuntimeAsserts);
    bool Changed = Combiner.runOnFunction(*getFunction());

    if (Changed) {
      // Ignore invalidation messages for all analyses that we keep up to date
      // manually.
      CGA->lock();

      // Invalidate everything else.
      invalidateAnalysis(SILAnalysis::PreserveKind::Nothing);

      // Unlock all of the analyses that we locked.
      CGA->unlock();
    }
  }

  StringRef getName() override { return "SIL Combine"; }
};

} // end anonymous namespace

SILTransform *swift::createSILCombine() {
  return new SILCombine();
}
<commit_msg>Use correct method name. NFC.<commit_after>//===-------------------------- SILCombine --------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// A port of LLVM's InstCombine pass to SIL. Its main purpose is for performing
// small combining operations/peepholes at the SIL level. It additionally
// performs dead code elimination when it initially adds instructions to the
// work queue in order to reduce compile time by not visiting trivially dead
// instructions.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "sil-combine"
#include "swift/SILPasses/Passes.h"
#include "SILCombiner.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILVisitor.h"
#include "swift/SILAnalysis/AliasAnalysis.h"
#include "swift/SILAnalysis/SimplifyInstruction.h"
#include "swift/SILPasses/Transforms.h"
#include "swift/SILPasses/Utils/Local.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Debug.h"

using namespace swift;

STATISTIC(NumSimplified, "Number of instructions simplified");
STATISTIC(NumCombined, "Number of instructions combined");
STATISTIC(NumDeadInst, "Number of dead insts eliminated");

//===----------------------------------------------------------------------===//
//                              Utility Methods
//===----------------------------------------------------------------------===//

/// addReachableCodeToWorklist - Walk the function in depth-first order, adding
/// all reachable code to the worklist.
///
/// This has a couple of tricks to make the code faster and more powerful.  In
/// particular, we DCE instructions as we go, to avoid adding them to the
/// worklist (this significantly speeds up SILCombine on code where many
/// instructions are dead or constant).
void SILCombiner::addReachableCodeToWorklist(SILBasicBlock *BB) {
  llvm::SmallVector<SILBasicBlock*, 256> Worklist;
  llvm::SmallVector<SILInstruction*, 128> InstrsForSILCombineWorklist;
  llvm::SmallPtrSet<SILBasicBlock*, 64> Visited;

  Worklist.push_back(BB);
  do {
    BB = Worklist.pop_back_val();

    // We have now visited this block!  If we've already been here, ignore it.
    if (!Visited.insert(BB).second) continue;

    for (SILBasicBlock::iterator BBI = BB->begin(), E = BB->end(); BBI != E; ) {
      SILInstruction *Inst = BBI++;

      // DCE instruction if trivially dead.
      if (isInstructionTriviallyDead(Inst)) {
        ++NumDeadInst;
        DEBUG(llvm::dbgs() << "SC: DCE: " << *Inst << '\n');

        // We pass in false here since we need to signal to
        // eraseInstFromFunction to not add this instruction's operands to the
        // worklist since we have not initialized the worklist yet.
        //
        // The reason to just use a default argument here is that it allows us
        // to centralize all instruction removal in SILCombine into this one
        // function. This is important if we want to be able to update analyses
        // in a clean manner.
        eraseInstFromFunction(*Inst, false /*Don't add operands to worklist*/);
        continue;
      }

      InstrsForSILCombineWorklist.push_back(Inst);
    }

    // Recursively visit successors.
    for (auto SI = BB->succ_begin(), SE = BB->succ_end(); SI != SE; ++SI)
      Worklist.push_back(*SI);
  } while (!Worklist.empty());

  // Once we've found all of the instructions to add to the worklist, add them
  // in reverse order. This way SILCombine will visit from the top of the
  // function down. This jives well with the way that it adds all uses of
  // instructions to the worklist after doing a transformation, thus avoiding
  // some N^2 behavior in pathological cases.
  addInitialGroup(InstrsForSILCombineWorklist);
}

//===----------------------------------------------------------------------===//
//                               Implementation
//===----------------------------------------------------------------------===//

void SILCombineWorklist::add(SILInstruction *I) {
  if (!WorklistMap.insert(std::make_pair(I, Worklist.size())).second)
    return;

  DEBUG(llvm::dbgs() << "SC: ADD: " << *I << '\n');
  Worklist.push_back(I);
}

bool SILCombiner::doOneIteration(SILFunction &F, unsigned Iteration) {
  MadeChange = false;

  DEBUG(llvm::dbgs() << "\n\nSILCOMBINE ITERATION #" << Iteration << " on "
                     << F.getName() << "\n");

  // Add reachable instructions to our worklist.
  addReachableCodeToWorklist(F.begin());

  // Process until we run out of items in our worklist.
  while (!Worklist.isEmpty()) {
    SILInstruction *I = Worklist.removeOne();

    // When we erase an instruction, we use the map in the worklist to check if
    // the instruction is in the worklist. If it is, we replace it with null
    // instead of shifting all members of the worklist towards the front. This
    // check makes sure that if we run into any such residual null pointers, we
    // skip them.
    if (I == 0)
      continue;

    // Check to see if we can DCE the instruction.
    if (isInstructionTriviallyDead(I)) {
      DEBUG(llvm::dbgs() << "SC: DCE: " << *I << '\n');
      eraseInstFromFunction(*I);
      ++NumDeadInst;
      MadeChange = true;
      continue;
    }

    // Check to see if we can instsimplify the instruction.
    if (SILValue Result = simplifyInstruction(I)) {
      ++NumSimplified;

      DEBUG(llvm::dbgs() << "SC: Simplify Old = " << *I << '\n'
                         << "    New = " << *Result.getDef() << '\n');

      // Everything uses the new instruction now.
      replaceInstUsesWith(*I, Result.getDef(), 0, Result.getResultNumber());

      // Push the new instruction and any users onto the worklist.
      Worklist.addUsersToWorklist(Result.getDef());

      eraseInstFromFunction(*I);
      MadeChange = true;
      continue;
    }

    // If we have reached this point, all attempts to do simple simplifications
    // have failed. Prepare to SILCombine.
    Builder->setInsertionPoint(I->getParent(), I);

#ifndef NDEBUG
    std::string OrigI;
#endif
    DEBUG(llvm::raw_string_ostream SS(OrigI); I->print(SS); OrigI = SS.str(););
    DEBUG(llvm::dbgs() << "SC: Visiting: " << OrigI << '\n');

    if (SILInstruction *Result = visit(I)) {
      ++NumCombined;
      // Should we replace the old instruction with a new one?
      if (Result != I) {
        // Insert the new instruction into the basic block.
        I->getParent()->getInstList().insert(I, Result);

        DEBUG(llvm::dbgs() << "SC: Old = " << *I << '\n'
                           << "    New = " << *Result << '\n');

        // Everything uses the new instruction now.
        replaceInstUsesWith(*I, Result);

        // Push the new instruction and any users onto the worklist.
        Worklist.add(Result);
        Worklist.addUsersToWorklist(Result);

        eraseInstFromFunction(*I);
      } else {
        DEBUG(llvm::dbgs() << "SC: Mod = " << OrigI << '\n'
                     << "    New = " << *I << '\n');

        // If the instruction was modified, it's possible that it is now dead.
        // if so, remove it.
        if (isInstructionTriviallyDead(I)) {
          eraseInstFromFunction(*I);
        } else {
          Worklist.add(I);
          Worklist.addUsersToWorklist(I);
        }
      }
      MadeChange = true;
    }

    // Our tracking list has been accumulating instructions created by the
    // SILBuilder during this iteration. Go through the tracking list and add
    // its contents to the worklist and then clear said list in preparation for
    // the next iteration.
    for (SILInstruction *I : TrackingList)
      Worklist.add(I);
    TrackingList.clear();
  }

  Worklist.zap();
  return MadeChange;
}

void SILCombineWorklist::addInitialGroup(ArrayRef<SILInstruction *> List) {
  assert(Worklist.empty() && "Worklist must be empty to add initial group");
  Worklist.reserve(List.size()+16);
  WorklistMap.resize(List.size());
  DEBUG(llvm::dbgs() << "SC: ADDING: " << List.size()
        << " instrs to worklist\n");
  while (!List.empty()) {
    SILInstruction *I = List.back();
    List = List.slice(0, List.size()-1);
    WorklistMap.insert(std::make_pair(I, Worklist.size()));
    Worklist.push_back(I);
    }
}

bool SILCombiner::runOnFunction(SILFunction &F) {
  clear();

  // Create a SILBuilder for F and initialize the tracking list.
  SILBuilder B(F);
  B.setTrackingList(&TrackingList);
  Builder = &B;

  bool Changed = false;
  // Perform iterations until we do not make any changes.
  while (doOneIteration(F, Iteration)) {
    Changed = true;
    Iteration++;
  }

  // Cleanup the builder and return whether or not we made any changes.
  Builder = nullptr;
  return Changed;
}

// Insert the instruction New before instruction Old in Old's parent BB. Add
// New to the worklist.
SILInstruction *SILCombiner::insertNewInstBefore(SILInstruction *New,
                                                 SILInstruction &Old) {
  assert(New && New->getParent() == 0 &&
         "New instruction already inserted into a basic block!");
  SILBasicBlock *BB = Old.getParent();
  BB->getInstList().insert(&Old, New);  // Insert inst
  Worklist.add(New);
  return New;
}

// This method is to be used when an instruction is found to be dead,
// replacable with another preexisting expression. Here we add all uses of I
// to the worklist, replace all uses of I with the new value, then return I,
// so that the combiner will know that I was modified.
SILInstruction *SILCombiner::replaceInstUsesWith(SILInstruction &I,
                                                 ValueBase *V) {
  Worklist.addUsersToWorklist(&I);   // Add all modified instrs to worklist.

  DEBUG(llvm::dbgs() << "SC: Replacing " << I << "\n"
        "    with " << *V << '\n');

  I.replaceAllUsesWith(V);

  return &I;
}

/// This is meant to be used when one is attempting to replace only one of the
/// results of I with a result of V.
SILInstruction *
SILCombiner::
replaceInstUsesWith(SILInstruction &I, ValueBase *V, unsigned IIndex,
                    unsigned VIndex) {
  assert(IIndex < I.getNumTypes() && "Can not have more results than "
         "types.");
  assert(VIndex < V->getNumTypes() && "Can not have more results than "
         "types.");

  // Add all modified instrs to worklist.
  Worklist.addUsersToWorklist(&I, IIndex);

  DEBUG(llvm::dbgs() << "SC: Replacing " << I << "\n"
        "    with " << *V << '\n');

  SILValue(&I, IIndex).replaceAllUsesWith(SILValue(V, VIndex));

  return &I;
}

// Some instructions can never be "trivially dead" due to side effects or
// producing a void value. In those cases, since we can not rely on
// SILCombines trivially dead instruction DCE in order to delete the
// instruction, visit methods should use this method to delete the given
// instruction and upon completion of their peephole return the value returned
// by this method.
SILInstruction *SILCombiner::eraseInstFromFunction(SILInstruction &I,
                                                   bool AddOperandsToWorklist) {
  DEBUG(llvm::dbgs() << "SC: ERASE " << I << '\n');

  assert(I.use_empty() && "Cannot erase instruction that is used!");
  // Make sure that we reprocess all operands now that we reduced their
  // use counts.
  if (I.getNumOperands() < 8 && AddOperandsToWorklist)
    for (auto &OpI : I.getAllOperands())
      if (SILInstruction *Op = llvm::dyn_cast<SILInstruction>(&*OpI.get()))
        Worklist.add(Op);

  // If we have a call graph and we've removing an apply, remove the
  // associated edges from the call graph.
  if (CG)
    if (auto *AI = dyn_cast<ApplyInst>(&I))
      CG->removeEdgesForApply(AI, true /*Ignore Missing*/);

  Worklist.remove(&I);
  I.eraseFromParent();
  MadeChange = true;
  return nullptr;  // Don't do anything with I
}

//===----------------------------------------------------------------------===//
//                                Entry Points
//===----------------------------------------------------------------------===//

namespace {

class SILCombine : public SILFunctionTransform {

  /// The entry point to the transformation.
  void run() override {
    auto *AA = PM->getAnalysis<AliasAnalysis>();

    // Call Graph Analysis in case we need to perform Call Graph updates.
    auto *CGA = PM->getAnalysis<CallGraphAnalysis>();
    SILCombiner Combiner(AA, CGA->getCallGraphOrNull(),
                         getOptions().RemoveRuntimeAsserts);
    bool Changed = Combiner.runOnFunction(*getFunction());

    if (Changed) {
      // Ignore invalidation messages for all analyses that we keep up to date
      // manually.
      CGA->lockInvalidation();

      // Invalidate everything else.
      invalidateAnalysis(SILAnalysis::PreserveKind::Nothing);

      // Unlock all of the analyses that we locked.
      CGA->unlockInvalidation();
    }
  }

  StringRef getName() override { return "SIL Combine"; }
};

} // end anonymous namespace

SILTransform *swift::createSILCombine() {
  return new SILCombine();
}
<|endoftext|>


<commit_before>/**
 * @file   macro_legalize.cpp
 * @author Yibo Lin
 * @date   Jun 2018
 */
#include "utility/src/torch.h"
#include "utility/src/LegalizationDB.h"
#include "utility/src/LegalizationDBUtils.h"
#include "macro_legalize/src/hannan_legalize.h"
#include "macro_legalize/src/lp_legalize.h"

DREAMPLACE_BEGIN_NAMESPACE

/// @brief The macro legalization follows the way of floorplanning,
/// because macros have quite different sizes.
/// @return true if legal
template <typename T>
bool macroLegalizationLauncher(LegalizationDB<T> db);

#define CHECK_FLAT(x) AT_ASSERTM(!x.is_cuda() && x.ndimension() == 1, #x "must be a flat tensor on CPU")
#define CHECK_EVEN(x) AT_ASSERTM((x.numel()&1) == 0, #x "must have even number of elements")
#define CHECK_CONTIGUOUS(x) AT_ASSERTM(x.is_contiguous(), #x "must be contiguous")

/// @brief legalize layout with greedy legalization.
/// Only movable nodes will be moved. Fixed nodes and filler nodes are fixed.
///
/// @param init_pos initial locations of nodes, including movable nodes, fixed nodes, and filler nodes, [0, num_movable_nodes) are movable nodes, [num_movable_nodes, num_nodes-num_filler_nodes) are fixed nodes, [num_nodes-num_filler_nodes, num_nodes) are filler nodes
/// @param node_size_x width of nodes, including movable nodes, fixed nodes, and filler nodes, [0, num_movable_nodes) are movable nodes, [num_movable_nodes, num_nodes-num_filler_nodes) are fixed nodes, [num_nodes-num_filler_nodes, num_nodes) are filler nodes
/// @param node_size_y height of nodes, including movable nodes, fixed nodes, and filler nodes, same as node_size_x
/// @param xl left edge of bounding box of layout area
/// @param yl bottom edge of bounding box of layout area
/// @param xh right edge of bounding box of layout area
/// @param yh top edge of bounding box of layout area
/// @param site_width width of a placement site
/// @param row_height height of a placement row
/// @param num_bins_x number of bins in horizontal direction
/// @param num_bins_y number of bins in vertical direction
/// @param num_nodes total number of nodes, including movable nodes, fixed nodes, and filler nodes; fixed nodes are in the range of [num_movable_nodes, num_nodes-num_filler_nodes)
/// @param num_movable_nodes number of movable nodes, movable nodes are in the range of [0, num_movable_nodes)
/// @param number of filler nodes, filler nodes are in the range of [num_nodes-num_filler_nodes, num_nodes)
at::Tensor macro_legalization_forward(
        at::Tensor init_pos,
        at::Tensor pos,
        at::Tensor node_size_x,
        at::Tensor node_size_y,
        at::Tensor flat_region_boxes,
        at::Tensor flat_region_boxes_start,
        at::Tensor node2fence_region_map,
        double xl,
        double yl,
        double xh,
        double yh,
        double site_width, double row_height,
        int num_bins_x,
        int num_bins_y,
        int num_movable_nodes,
        int num_terminal_NIs,
        int num_filler_nodes
        )
{
    CHECK_FLAT(init_pos);
    CHECK_EVEN(init_pos);
    CHECK_CONTIGUOUS(init_pos);

    auto pos_copy = pos.clone();

    hr_clock_rep timer_start, timer_stop;
    timer_start = get_globaltime();
    // Call the cuda kernel launcher
    DREAMPLACE_DISPATCH_FLOATING_TYPES(pos.type(), "macroLegalizationLauncher", [&] {
            auto db = make_placedb<scalar_t>(
                    init_pos,
                    pos_copy,
                    node_size_x,
                    node_size_y,
                    flat_region_boxes, flat_region_boxes_start, node2fence_region_map,
                    xl, yl, xh, yh,
                    site_width, row_height,
                    num_bins_x,
                    num_bins_y,
                    num_movable_nodes,
                    num_terminal_NIs,
                    num_filler_nodes
                    );
            macroLegalizationLauncher<scalar_t>(db);
            });
    timer_stop = get_globaltime();
    dreamplacePrint(kINFO, "Macro legalization takes %g ms\n", (timer_stop-timer_start)*get_timer_period());

    return pos_copy;
}

template <typename T>
bool check_macro_legality(LegalizationDB<T> db, const std::vector<int>& macros, bool fast_check)
{
    // check legality between movable and fixed macros
    // for debug only, so it is slow
    auto checkOverlap2Nodes = [&](int i, int node_id1, T xl1, T yl1, T width1, T height1, int j, int node_id2, T xl2, T yl2, T width2, T height2) {
        T xh1 = xl1 + width1;
        T yh1 = yl1 + height1;
        T xh2 = xl2 + width2;
        T yh2 = yl2 + height2;
        if (std::min(xh1, xh2) > std::max(xl1, xl2) && std::min(yh1, yh2) > std::max(yl1, yl2))
        {
            dreamplacePrint((fast_check)? kWARN : kERROR, "macro %d (%g, %g, %g, %g) var %d overlaps with macro %d (%g, %g, %g, %g) var %d, fixed: %d\n",
                    node_id1, xl1, yl1, xh1, yh1, i,
                    node_id2, xl2, yl2, xh2, yh2, j,
                    (int)(node_id2 >= db.num_movable_nodes)
                    );
            return true;
        }
        return false;
    };

    bool legal = true;
    for (unsigned int i = 0, ie = macros.size(); i < ie; ++i)
    {
        int node_id1 = macros[i];
        T xl1 = db.x[node_id1];
        T yl1 = db.y[node_id1];
        T width1 = db.node_size_x[node_id1];
        T height1 = db.node_size_y[node_id1];
        // constraints with other macros
        for (unsigned int j = i+1; j < ie; ++j)
        {
            int node_id2 = macros[j];
            T xl2 = db.x[node_id2];
            T yl2 = db.y[node_id2];
            T width2 = db.node_size_x[node_id2];
            T height2 = db.node_size_y[node_id2];

            bool overlap = checkOverlap2Nodes(i, node_id1, xl1, yl1, width1, height1, j, node_id2, xl2, yl2, width2, height2);
            if (overlap)
            {
                legal = false;
                if (fast_check)
                {
                    return legal;
                }
            }
        }
        // constraints with fixed macros
        // when considering fixed macros, there is no guarantee to find legal solution
        // with current ad-hoc constraint graphs
        for (int j = db.num_movable_nodes; j < db.num_nodes; ++j)
        {
            int node_id2 = j;
            T xl2 = db.init_x[node_id2];
            T yl2 = db.init_y[node_id2];
            T width2 = db.node_size_x[node_id2];
            T height2 = db.node_size_y[node_id2];

            bool overlap = checkOverlap2Nodes(i, node_id1, xl1, yl1, width1, height1, j, node_id2, xl2, yl2, width2, height2);
            if (overlap)
            {
                legal = false;
                if (fast_check)
                {
                    return legal;
                }
            }
        }
    }
    if (legal)
    {
        dreamplacePrint(kDEBUG, "Macro legality check PASSED\n");
    }
    else
    {
        dreamplacePrint(kERROR, "Macro legality check FAILED\n");
    }

    return legal;
}

template <typename T>
T compute_displace(const LegalizationDB<T>& db, const std::vector<int>& macros)
{
    T displace = 0;
    for (auto node_id : macros)
    {
        displace += std::abs(db.init_x[node_id]-db.x[node_id]) + std::abs(db.init_y[node_id]-db.y[node_id]);
    }
    return displace;
}

template <typename T>
bool macroLegalizationLauncher(LegalizationDB<T> db)
{
    // collect macros
    std::vector<int> macros;
    for (int i = 0; i < db.num_movable_nodes; ++i)
    {
        if (db.is_dummy_fixed(i))
        {
            macros.push_back(i);
#ifdef DEBUG
            dreamplacePrint(kDEBUG, "macro %d %gx%g\n", i, db.node_size_x[i], db.node_size_y[i]);
#endif
        }
    }
    dreamplacePrint(kINFO, "Macro legalization: regard %lu cells as dummy fixed (movable macros)\n", macros.size());

    // in case there is no movable macros
    if (macros.empty())
    {
        return true;
    }

    // first round with LP
    lpLegalizeLauncher(db, macros);
    dreamplacePrint(kINFO, "Macro displacement %g\n", compute_displace(db, macros));
    bool legal = check_macro_legality(db, macros, true);

    // try Hannan grid legalization if still not legal
    if (!legal)
    {
        legal = hannanLegalizeLauncher(db, macros);
        dreamplacePrint(kINFO, "Macro displacement %g\n", compute_displace(db, macros));
        legal = check_macro_legality(db, macros, false);

        // refine with LP if legal
        if (legal)
        {
            lpLegalizeLauncher(db, macros);
            dreamplacePrint(kINFO, "Macro displacement %g\n", compute_displace(db, macros));
        }
    }

    dreamplacePrint(kINFO, "Align macros to site and rows\n");
    // align the lower left corner to row and site
    for (unsigned int i = 0, ie = macros.size(); i < ie; ++i)
    {
        int node_id = macros[i];
        db.x[node_id] = db.align2site(db.x[node_id], db.node_size_x[node_id]);
        db.y[node_id] = db.align2row(db.y[node_id], db.node_size_y[node_id]);
    }

    legal = check_macro_legality(db, macros, false);

    return legal;
}

DREAMPLACE_END_NAMESPACE

PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
  m.def("forward", &DREAMPLACE_NAMESPACE::macro_legalization_forward, "Macro legalization forward");
}
<commit_msg>add try and error scheme to macro legalization<commit_after>/**
 * @file   macro_legalize.cpp
 * @author Yibo Lin
 * @date   Jun 2018
 */
#include "utility/src/torch.h"
#include "utility/src/LegalizationDB.h"
#include "utility/src/LegalizationDBUtils.h"
#include "macro_legalize/src/hannan_legalize.h"
#include "macro_legalize/src/lp_legalize.h"

DREAMPLACE_BEGIN_NAMESPACE

/// @brief The macro legalization follows the way of floorplanning,
/// because macros have quite different sizes.
/// @return true if legal
template <typename T>
bool macroLegalizationLauncher(LegalizationDB<T> db);

#define CHECK_FLAT(x) AT_ASSERTM(!x.is_cuda() && x.ndimension() == 1, #x "must be a flat tensor on CPU")
#define CHECK_EVEN(x) AT_ASSERTM((x.numel()&1) == 0, #x "must have even number of elements")
#define CHECK_CONTIGUOUS(x) AT_ASSERTM(x.is_contiguous(), #x "must be contiguous")

/// @brief legalize layout with greedy legalization.
/// Only movable nodes will be moved. Fixed nodes and filler nodes are fixed.
///
/// @param init_pos initial locations of nodes, including movable nodes, fixed nodes, and filler nodes, [0, num_movable_nodes) are movable nodes, [num_movable_nodes, num_nodes-num_filler_nodes) are fixed nodes, [num_nodes-num_filler_nodes, num_nodes) are filler nodes
/// @param node_size_x width of nodes, including movable nodes, fixed nodes, and filler nodes, [0, num_movable_nodes) are movable nodes, [num_movable_nodes, num_nodes-num_filler_nodes) are fixed nodes, [num_nodes-num_filler_nodes, num_nodes) are filler nodes
/// @param node_size_y height of nodes, including movable nodes, fixed nodes, and filler nodes, same as node_size_x
/// @param xl left edge of bounding box of layout area
/// @param yl bottom edge of bounding box of layout area
/// @param xh right edge of bounding box of layout area
/// @param yh top edge of bounding box of layout area
/// @param site_width width of a placement site
/// @param row_height height of a placement row
/// @param num_bins_x number of bins in horizontal direction
/// @param num_bins_y number of bins in vertical direction
/// @param num_nodes total number of nodes, including movable nodes, fixed nodes, and filler nodes; fixed nodes are in the range of [num_movable_nodes, num_nodes-num_filler_nodes)
/// @param num_movable_nodes number of movable nodes, movable nodes are in the range of [0, num_movable_nodes)
/// @param number of filler nodes, filler nodes are in the range of [num_nodes-num_filler_nodes, num_nodes)
at::Tensor macro_legalization_forward(
        at::Tensor init_pos,
        at::Tensor pos,
        at::Tensor node_size_x,
        at::Tensor node_size_y,
        at::Tensor flat_region_boxes,
        at::Tensor flat_region_boxes_start,
        at::Tensor node2fence_region_map,
        double xl,
        double yl,
        double xh,
        double yh,
        double site_width, double row_height,
        int num_bins_x,
        int num_bins_y,
        int num_movable_nodes,
        int num_terminal_NIs,
        int num_filler_nodes
        )
{
    CHECK_FLAT(init_pos);
    CHECK_EVEN(init_pos);
    CHECK_CONTIGUOUS(init_pos);

    auto pos_copy = pos.clone();

    hr_clock_rep timer_start, timer_stop;
    timer_start = get_globaltime();
    // Call the cuda kernel launcher
    DREAMPLACE_DISPATCH_FLOATING_TYPES(pos.type(), "macroLegalizationLauncher", [&] {
            auto db = make_placedb<scalar_t>(
                    init_pos,
                    pos_copy,
                    node_size_x,
                    node_size_y,
                    flat_region_boxes, flat_region_boxes_start, node2fence_region_map,
                    xl, yl, xh, yh,
                    site_width, row_height,
                    num_bins_x,
                    num_bins_y,
                    num_movable_nodes,
                    num_terminal_NIs,
                    num_filler_nodes
                    );
            macroLegalizationLauncher<scalar_t>(db);
            });
    timer_stop = get_globaltime();
    dreamplacePrint(kINFO, "Macro legalization takes %g ms\n", (timer_stop-timer_start)*get_timer_period());

    return pos_copy;
}

template <typename T>
bool check_macro_legality(LegalizationDB<T> db, const std::vector<int>& macros, bool fast_check)
{
    // check legality between movable and fixed macros
    // for debug only, so it is slow
    auto checkOverlap2Nodes = [&](int i, int node_id1, T xl1, T yl1, T width1, T height1, int j, int node_id2, T xl2, T yl2, T width2, T height2) {
        T xh1 = xl1 + width1;
        T yh1 = yl1 + height1;
        T xh2 = xl2 + width2;
        T yh2 = yl2 + height2;
        if (std::min(xh1, xh2) > std::max(xl1, xl2) && std::min(yh1, yh2) > std::max(yl1, yl2))
        {
            dreamplacePrint((fast_check)? kWARN : kERROR, "macro %d (%g, %g, %g, %g) var %d overlaps with macro %d (%g, %g, %g, %g) var %d, fixed: %d\n",
                    node_id1, xl1, yl1, xh1, yh1, i,
                    node_id2, xl2, yl2, xh2, yh2, j,
                    (int)(node_id2 >= db.num_movable_nodes)
                    );
            return true;
        }
        return false;
    };

    bool legal = true;
    for (unsigned int i = 0, ie = macros.size(); i < ie; ++i)
    {
        int node_id1 = macros[i];
        T xl1 = db.x[node_id1];
        T yl1 = db.y[node_id1];
        T width1 = db.node_size_x[node_id1];
        T height1 = db.node_size_y[node_id1];
        // constraints with other macros
        for (unsigned int j = i+1; j < ie; ++j)
        {
            int node_id2 = macros[j];
            T xl2 = db.x[node_id2];
            T yl2 = db.y[node_id2];
            T width2 = db.node_size_x[node_id2];
            T height2 = db.node_size_y[node_id2];

            bool overlap = checkOverlap2Nodes(i, node_id1, xl1, yl1, width1, height1, j, node_id2, xl2, yl2, width2, height2);
            if (overlap)
            {
                legal = false;
                if (fast_check)
                {
                    return legal;
                }
            }
        }
        // constraints with fixed macros
        // when considering fixed macros, there is no guarantee to find legal solution
        // with current ad-hoc constraint graphs
        for (int j = db.num_movable_nodes; j < db.num_nodes; ++j)
        {
            int node_id2 = j;
            T xl2 = db.init_x[node_id2];
            T yl2 = db.init_y[node_id2];
            T width2 = db.node_size_x[node_id2];
            T height2 = db.node_size_y[node_id2];

            bool overlap = checkOverlap2Nodes(i, node_id1, xl1, yl1, width1, height1, j, node_id2, xl2, yl2, width2, height2);
            if (overlap)
            {
                legal = false;
                if (fast_check)
                {
                    return legal;
                }
            }
        }
    }
    if (legal)
    {
        dreamplacePrint(kDEBUG, "Macro legality check PASSED\n");
    }
    else
    {
        dreamplacePrint(kERROR, "Macro legality check FAILED\n");
    }

    return legal;
}

template <typename T>
T compute_displace(const LegalizationDB<T>& db, const std::vector<int>& macros)
{
    T displace = 0;
    for (auto node_id : macros)
    {
        displace += std::abs(db.init_x[node_id]-db.x[node_id]) + std::abs(db.init_y[node_id]-db.y[node_id]);
    }
    return displace;
}

template <typename T>
bool macroLegalizationLauncher(LegalizationDB<T> db)
{
    // collect macros
    std::vector<int> macros;
    for (int i = 0; i < db.num_movable_nodes; ++i)
    {
        if (db.is_dummy_fixed(i))
        {
            macros.push_back(i);
#ifdef DEBUG
            dreamplacePrint(kDEBUG, "macro %d %gx%g\n", i, db.node_size_x[i], db.node_size_y[i]);
#endif
        }
    }
    dreamplacePrint(kINFO, "Macro legalization: regard %lu cells as dummy fixed (movable macros)\n", macros.size());

    // in case there is no movable macros
    if (macros.empty())
    {
        return true;
    }

    // store the best legalization solution found
    std::vector<T> best_x (macros.size());
    std::vector<T> best_y (macros.size());
    T best_displace = std::numeric_limits<T>::max();

    // update current best solution
    auto update_best = [&](bool legal, T displace){
        if (legal && displace < best_displace)
        {
            for (unsigned int i = 0, ie = macros.size(); i < ie; ++i)
            {
                int macro_id = macros[i];
                best_x[i] = db.x[macro_id];
                best_y[i] = db.y[macro_id];
            }
            best_displace = displace;
        }
    };

    // first round with LP
    lpLegalizeLauncher(db, macros);
    dreamplacePrint(kINFO, "Macro displacement %g\n", compute_displace(db, macros));
    bool legal = check_macro_legality(db, macros, true);

    // try Hannan grid legalization if still not legal
    if (!legal)
    {
        legal = hannanLegalizeLauncher(db, macros);
        T displace = compute_displace(db, macros);
        dreamplacePrint(kINFO, "Macro displacement %g\n", displace);
        legal = check_macro_legality(db, macros, true);
        update_best(legal, displace);

        // refine with LP if legal
        if (legal)
        {
            lpLegalizeLauncher(db, macros);
            displace = compute_displace(db, macros);
            dreamplacePrint(kINFO, "Macro displacement %g\n", displace);
            legal = check_macro_legality(db, macros, true);
            update_best(legal, displace);
        }
    }

    // apply best solution
    if (best_displace < std::numeric_limits<T>::max())
    {
        dreamplacePrint(kINFO, "use best macro displacement %g\n", best_displace);
        for (unsigned int i = 0, ie = macros.size(); i < ie; ++i)
        {
            int macro_id = macros[i];
            db.x[macro_id] = best_x[i];
            db.y[macro_id] = best_y[i];
        }
    }

    dreamplacePrint(kINFO, "Align macros to site and rows\n");
    // align the lower left corner to row and site
    for (unsigned int i = 0, ie = macros.size(); i < ie; ++i)
    {
        int node_id = macros[i];
        db.x[node_id] = db.align2site(db.x[node_id], db.node_size_x[node_id]);
        db.y[node_id] = db.align2row(db.y[node_id], db.node_size_y[node_id]);
    }

    legal = check_macro_legality(db, macros, false);

    return legal;
}

DREAMPLACE_END_NAMESPACE

PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
  m.def("forward", &DREAMPLACE_NAMESPACE::macro_legalization_forward, "Macro legalization forward");
}
<|endoftext|>