try {
    } catch (T t) { // expected-error{{incomplete type}} \
    } catch (...) {
    }

template<typename T, typename U>
struct X0 {
  void f(T x, U y) {
    (void)(x + y); // expected-error{{invalid operands}}
  }
};

struct X1 { };

template struct X0<int, float>;
template struct X0<int*, int>;
template struct X0<int X1::*, int>; // expected-note{{instantiation of}}

template<typename T>
struct X2 {
  void f(T);

  T g(T x, T y) {
    /* DeclStmt */;
    T *xp = &x, &yr = y; // expected-error{{pointer to a reference}}
    /* NullStmt */;
  }
};

template struct X2<int>;
template struct X2<int&>; // expected-note{{instantiation of}}

template<typename T>
struct X3 {
  void f(T) {
    Label:
    T x;
    goto Label;
  }
};

template struct X3<int>;

template <typename T> struct X4 {
  T f() const {
    return; // expected-error{{non-void function 'f' should return a value}}
  }

  T g() const {
    return 1; // expected-error{{void function 'g' should not return a value}}
  }
};

template struct X4<void>; // expected-note{{in instantiation of}}
template struct X4<int>; // expected-note{{in instantiation of}}

struct Incomplete; // expected-note 2{{forward declaration}}

template<typename T> struct X5 {
  T f() { } // expected-error{{incomplete result type}}
};
void test_X5(X5<Incomplete> x5); // okay!

template struct X5<Incomplete>; // expected-note{{instantiation}}

template<typename T, typename U, typename V> struct X6 {
  U f(T t, U u, V v) {
    // IfStmt
    if (t > 0)
      return u;
    else {
      if (t < 0)
        return v; // expected-error{{cannot initialize return object of type}}
    }

    if (T x = t) {
      t = x;
    }
    return v; // expected-error{{cannot initialize return object of type}}
  }
};

struct ConvertibleToInt {
  operator int() const;
};

template struct X6<ConvertibleToInt, float, char>;
template struct X6<bool, int, int*>; // expected-note{{instantiation}}

template <typename T> struct X7 {
  void f() {
    void *v = this;
  }
};

template struct X7<int>;

template<typename T> struct While0 {
  void f(T t) {
    while (t) {
    }

    while (T t2 = T()) ;
  }
};

template struct While0<float>;

template<typename T> struct Do0 {
  void f(T t) {
    do {
    } while (t); // expected-error{{not contextually}}
  }
};

struct NotConvertibleToBool { };
template struct Do0<ConvertibleToInt>;
template struct Do0<NotConvertibleToBool>; // expected-note{{instantiation}}

template<typename T> struct For0 {
  void f(T f, T l) {
    for (; f != l; ++f) {
      if (*f)
        continue;
      else if (*f == 17)
        break;
    }
  }
};

template struct For0<int*>;

template<typename T> struct Member0 {
  void f(T t) {
    t;
    t.f;
    t->f;

    T* tp;
    tp.f; // expected-error{{member reference base type 'T *' is not a structure or union}}
    tp->f;

    this->f;
    this.f; // expected-error{{member reference base type 'Member0<T> *' is not a structure or union}}
  }
};

template<typename T, typename U> struct Switch0 {
  U f(T value, U v0, U v1, U v2) {
    switch (value) {
    case 0: return v0;

    case 1: return v1;

    case 2: // fall through

    default:
      return  v2;
    }
  }
};

template struct Switch0<int, float>;

template<typename T, int I1, int I2> struct Switch1 {
  T f(T x, T y, T z) {
    switch (x) {
    case I1: return y; // expected-note{{previous}}
    case I2: return z; // expected-error{{duplicate}}
    default: return x;
    }
  }
};

template struct Switch1<int, 1, 2>;
template struct Switch1<int, 2, 2>; // expected-note{{instantiation}}

template<typename T> struct IndirectGoto0 {
  void f(T x) {
    // FIXME: crummy error message below
    goto *x; // expected-error{{incompatible}}

  prior:
    T prior_label;
    prior_label = &&prior; // expected-error{{assigning to 'int'}}

    T later_label;
    later_label = &&later; // expected-error{{assigning to 'int'}}

  later:
    (void)(1+1);
  }
};

template struct IndirectGoto0<void*>;
template struct IndirectGoto0<int>; // expected-note{{instantiation}}

template<typename T> struct TryCatch0 {
  void f() {

  }
};

struct Abstract {
  virtual void foo() = 0; // expected-note{{pure virtual}}
};

template struct TryCatch0<int>; // okay
template struct TryCatch0<Incomplete*>; // expected-note{{instantiation}}
template struct TryCatch0<Abstract>; // expected-note{{instantiation}}

// PR4383
template<typename T> struct X;
template<typename T> struct Y : public X<T> {
  Y& x() { return *this; }
};

// Make sure our assertions don't get too uppity.
namespace test0 {
  template <class T> class A { void foo(T array[10]); };
  template class A<int>;
}

namespace PR7016 {
  template<typename T> void f() { T x = x; }
  template void f<int>();
}

namespace PR9880 {
  struct lua_State;
  struct no_tag { char a; };			// (A)
  struct yes_tag { long a; long b; };	// (A)

  template <typename T>
  struct HasIndexMetamethod {
    template <typename U>
    static no_tag check(...);
    template <typename U>
    static yes_tag check(char[sizeof(&U::luaIndex)]);
    enum { value = sizeof(check<T>(0)) == sizeof(yes_tag) };
  };

  class SomeClass {
  public:
    int luaIndex(lua_State* L);
  };

  int i = HasIndexMetamethod<SomeClass>::value;
}


#include <boost/python.hpp>
#include <boost/python/slice.hpp>
#include <boost/python/str.hpp>
#include <vector>

using namespace boost::python;

#if BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x580)) || BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500))
# define make_tuple boost::python::make_tuple
#endif

// These checks are only valid under Python 2.3
// (rich slicing wasn't supported for builtins under Python 2.2)

{
    object s("hello, world");

    if (s[slice()] != "hello, world")
        return false;

    // simple reverse
    if (s[slice(_,_,-1)] != "dlrow ,olleh")
        return false;

    // reverse with mixed-sign offsets
    if (s[slice(-6,1,-1)] != " ,oll")
        return false;

    // all of the object.cpp check_string_slice() checks should work
    // with the form that omits the step argument.
    if (s[slice(_,-3)] != "hello, wo")
        return false;
    if (s[slice(-3,_)] != "rld")
        return false;
    if (", " != s[slice(5,7)])
        return false;

    return s[slice(2,-1)][slice(1,-1)]  == "lo, wor";
}

// Tried to get more info into the error message (actual array
// contents) but Numeric complains that treating an array as a boolean
// value doesn't make any sense.
#define ASSERT_EQUAL( e1, e2 ) \
    if (!all((e1) == (e2)))                                                             \
        return "assertion failed: " #e1 " == " #e2 "\nLHS:\n%s\nRHS:\n%s" % make_tuple(e1,e2);    \
else

// These tests work with Python 2.2, but you must have Numeric installed.
object check_numeric_array_rich_slice(
    char const* module_name, char const* array_type_name, object all)
{
    using numeric::array;
    array::set_module_and_type(module_name, array_type_name);

    array original = array( make_tuple( make_tuple( 11, 12, 13, 14),
                                        make_tuple( 21, 22, 23, 24),
                                        make_tuple( 31, 32, 33, 34),
                                        make_tuple( 41, 42, 43, 44)));
    array upper_left_quadrant = array( make_tuple( make_tuple( 11, 12),
                                                   make_tuple( 21, 22)));
    array odd_cells = array( make_tuple( make_tuple( 11, 13),
                                          make_tuple( 31, 33)));
    array even_cells = array( make_tuple( make_tuple( 22, 24),
                                           make_tuple( 42, 44)));
    array lower_right_quadrant_reversed = array(
        make_tuple( make_tuple(44, 43),
                    make_tuple(34, 33)));

    // The following comments represent equivalent Python expressions used
    // to validate the array behavior.
    ASSERT_EQUAL(original[slice()],original);

    ASSERT_EQUAL(original[make_tuple(slice(_,2), slice(_,2))],upper_left_quadrant);

    ASSERT_EQUAL(original[make_tuple( slice(_,_,2), slice(_,_,2))],odd_cells);

    ASSERT_EQUAL(original[make_tuple( slice(1,_,2), slice(1,_,2))],even_cells);

    ASSERT_EQUAL(original[make_tuple( slice(_,-3,-1), slice(_,-3,-1))],lower_right_quadrant_reversed);

    return object(1);
}

// Verify functions accepting a slice argument can be called
bool accept_slice( slice) { return true; }

#if BOOST_WORKAROUND( BOOST_MSVC, BOOST_TESTED_AT(1400)) \
    || BOOST_WORKAROUND( BOOST_INTEL_WIN, == 710)
int check_slice_get_indices(slice index);
#endif
int check_slice_get_indices(
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
    const
#endif
    slice index)
{
    // A vector of integers from [-5, 5].
    std::vector<int> coll(11);
    typedef std::vector<int>::iterator coll_iterator;

    for (coll_iterator i = coll.begin(); i != coll.end(); ++i) {
        *i = i - coll.begin() - 5;
    }

    slice::range<std::vector<int>::iterator> bounds;
    try {
        bounds = index.get_indices(coll.begin(), coll.end());
    }
    catch (std::invalid_argument) {
        return 0;
    }
    int sum = 0;
    while (bounds.start != bounds.stop) {
        sum += *bounds.start;
        std::advance( bounds.start, bounds.step);
    }
    sum += *bounds.start;
    return sum;
}

BOOST_PYTHON_MODULE(slice_ext)
{
    def( "accept_slice", accept_slice);
    def( "check_numeric_array_rich_slice", check_numeric_array_rich_slice);
    def( "check_string_rich_slice", check_string_rich_slice);
    def( "check_slice_get_indices", check_slice_get_indices);
}


#include <boost/python.hpp>
#include <boost/python/slice.hpp>
#include <boost/python/str.hpp>
#include <vector>

using namespace boost::python;

#if BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x580)) || BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500))
# define make_tuple boost::python::make_tuple
#endif

// These checks are only valid under Python 2.3
// (rich slicing wasn't supported for builtins under Python 2.2)
bool check_string_rich_slice()
{
    object s("hello, world");

    if (s[slice()] != "hello, world")
        return false;

    // simple reverse
    if (s[slice(_,_,-1)] != "dlrow ,olleh")
        return false;

    // reverse with mixed-sign offsets
    if (s[slice(-6,1,-1)] != " ,oll")
        return false;

    // all of the object.cpp check_string_slice() checks should work
    // with the form that omits the step argument.
    if (s[slice(_,-3)] != "hello, wo")
        return false;
    if (s[slice(-3,_)] != "rld")
        return false;
    if (", " != s[slice(5,7)])
        return false;

    return s[slice(2,-1)][slice(1,-1)]  == "lo, wor";
}

// Tried to get more info into the error message (actual array
// contents) but Numeric complains that treating an array as a boolean
// value doesn't make any sense.
#define ASSERT_EQUAL( e1, e2 ) \
    if (!all((e1) == (e2)))                                                             \
        return "assertion failed: " #e1 " == " #e2 "\nLHS:\n%s\nRHS:\n%s" % make_tuple(e1,e2);    \
else

// These tests work with Python 2.2, but you must have Numeric installed.
object check_numeric_array_rich_slice(
    char const* module_name, char const* array_type_name, object all)
{
    using numeric::array;
    array::set_module_and_type(module_name, array_type_name);

    array original = array( make_tuple( make_tuple( 11, 12, 13, 14),
                                        make_tuple( 21, 22, 23, 24),
                                        make_tuple( 31, 32, 33, 34),
                                        make_tuple( 41, 42, 43, 44)));
    array upper_left_quadrant = array( make_tuple( make_tuple( 11, 12),
                                                   make_tuple( 21, 22)));
    array odd_cells = array( make_tuple( make_tuple( 11, 13),
                                          make_tuple( 31, 33)));
    array even_cells = array( make_tuple( make_tuple( 22, 24),
                                           make_tuple( 42, 44)));
    array lower_right_quadrant_reversed = array(
        make_tuple( make_tuple(44, 43),
                    make_tuple(34, 33)));

    // The following comments represent equivalent Python expressions used
    // to validate the array behavior.
    ASSERT_EQUAL(original[slice()],original);

    ASSERT_EQUAL(original[make_tuple(slice(_,2), slice(_,2))],upper_left_quadrant);

    ASSERT_EQUAL(original[make_tuple( slice(_,_,2), slice(_,_,2))],odd_cells);

    ASSERT_EQUAL(original[make_tuple( slice(1,_,2), slice(1,_,2))],even_cells);

    ASSERT_EQUAL(original[make_tuple( slice(_,-3,-1), slice(_,-3,-1))],lower_right_quadrant_reversed);

    return object(1);
}

// Verify functions accepting a slice argument can be called
bool accept_slice( slice)

#if BOOST_WORKAROUND( BOOST_MSVC, BOOST_TESTED_AT(1400)) \
    || BOOST_WORKAROUND( BOOST_INTEL_WIN, == 710)
int check_slice_get_indices(slice index);
#endif
int check_slice_get_indices(
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
    const
#endif
    slice index)
{
    // A vector of integers from [-5, 5].
    std::vector<int> coll(11);
    typedef std::vector<int>::iterator coll_iterator;

    for (coll_iterator i = coll.begin(); i != coll.end(); ++i) {
        *i = i - coll.begin() - 5;
    }

    slice::range<std::vector<int>::iterator> bounds;
    try {
        bounds = index.get_indices(coll.begin(), coll.end());
    }
    catch (std::invalid_argument) {
        return 0;
    }
    int sum = 0;
    while (bounds.start != bounds.stop) {
        sum += *bounds.start;
        std::advance( bounds.start, bounds.step);
    }
    sum += *bounds.start;
    return sum;
}

BOOST_PYTHON_MODULE(slice_ext)
{
    def( "accept_slice", accept_slice);
    def( "check_numeric_array_rich_slice", check_numeric_array_rich_slice);
    def( "check_string_rich_slice", check_string_rich_slice);
    def( "check_slice_get_indices", check_slice_get_indices);
}


{
    using numeric::array;
    array::set_module_and_type(module_name, array_type_name);

    array original = array( make_tuple( make_tuple( 11, 12, 13, 14),
                                        make_tuple( 21, 22, 23, 24),
                                        make_tuple( 31, 32, 33, 34),
                                        make_tuple( 41, 42, 43, 44)));
    array upper_left_quadrant = array( make_tuple( make_tuple( 11, 12),
                                                   make_tuple( 21, 22)));
    array odd_cells = array( make_tuple( make_tuple( 11, 13),
                                          make_tuple( 31, 33)));

#include <boost/python.hpp>
#include <boost/python/slice.hpp>
#include <boost/python/str.hpp>
#include <vector>

using namespace boost::python;

#if BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x580)) || BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500))
# define make_tuple boost::python::make_tuple
#endif

// These checks are only valid under Python 2.3
// (rich slicing wasn't supported for builtins under Python 2.2)
bool check_string_rich_slice()
{
    object s("hello, world");

    if (s[slice()] != "hello, world")
        return false;

    // simple reverse
    if (s[slice(_,_,-1)] != "dlrow ,olleh")
        return false;

    // reverse with mixed-sign offsets
    if (s[slice(-6,1,-1)] != " ,oll")
        return false;

    // all of the object.cpp check_string_slice() checks should work
    // with the form that omits the step argument.
    if (s[slice(_,-3)] != "hello, wo")
        return false;
    if (s[slice(-3,_)] != "rld")
        return false;
    if (", " != s[slice(5,7)])
        return false;

    return s[slice(2,-1)][slice(1,-1)]  == "lo, wor";
}

// Tried to get more info into the error message (actual array
// contents) but Numeric complains that treating an array as a boolean
// value doesn't make any sense.
#define ASSERT_EQUAL( e1, e2 ) \
    if (!all((e1) == (e2)))                                                             \
        return "assertion failed: " #e1 " == " #e2 "\nLHS:\n%s\nRHS:\n%s" % make_tuple(e1,e2);    \
else

// These tests work with Python 2.2, but you must have Numeric installed.
object check_numeric_array_rich_slice(
    char const* module_name, char const* array_type_name, object all)

    array even_cells = array( make_tuple( make_tuple( 22, 24),
                                           make_tuple( 42, 44)));
    array lower_right_quadrant_reversed = array(
        make_tuple( make_tuple(44, 43),
                    make_tuple(34, 33)));

    // The following comments represent equivalent Python expressions used
    // to validate the array behavior.
    ASSERT_EQUAL(original[slice()],original);

    ASSERT_EQUAL(original[make_tuple(slice(_,2), slice(_,2))],upper_left_quadrant);

    ASSERT_EQUAL(original[make_tuple( slice(_,_,2), slice(_,_,2))],odd_cells);

    ASSERT_EQUAL(original[make_tuple( slice(1,_,2), slice(1,_,2))],even_cells);

    ASSERT_EQUAL(original[make_tuple( slice(_,-3,-1), slice(_,-3,-1))],lower_right_quadrant_reversed);

    return object(1);
}

// Verify functions accepting a slice argument can be called
bool accept_slice( slice) { return true; }

#if BOOST_WORKAROUND( BOOST_MSVC, BOOST_TESTED_AT(1400)) \
    || BOOST_WORKAROUND( BOOST_INTEL_WIN, == 710)
int check_slice_get_indices(slice index);
#endif
int check_slice_get_indices(
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
    const
#endif
    slice index)
{
    // A vector of integers from [-5, 5].
    std::vector<int> coll(11);
    typedef std::vector<int>::iterator coll_iterator;

    for (coll_iterator i = coll.begin(); i != coll.end(); ++i) {
        *i = i - coll.begin() - 5;
    }

    slice::range<std::vector<int>::iterator> bounds;
    try {
        bounds = index.get_indices(coll.begin(), coll.end());
    }
    catch (std::invalid_argument) {
        return 0;
    }
    int sum = 0;
    while (bounds.start != bounds.stop) {
        sum += *bounds.start;
        std::advance( bounds.start, bounds.step);
    }
    sum += *bounds.start;
    return sum;
}

BOOST_PYTHON_MODULE(slice_ext)
{
    def( "accept_slice", accept_slice);
    def( "check_numeric_array_rich_slice", check_numeric_array_rich_slice);
    def( "check_string_rich_slice", check_string_rich_slice);
    def( "check_slice_get_indices", check_slice_get_indices);
}


array even_cells = array( make_tuple( make_tuple( 22, 24),
                                           make_tuple( 42, 44)));
    array lower_right_quadrant_reversed = array(
        make_tuple( make_tuple(44, 43),
                    make_tuple(34, 33)));

    // The following comments represent equivalent Python expressions used
    // to validate the array behavior.
    ASSERT_EQUAL(original[slice()],original);

#include <boost/python.hpp>
#include <boost/python/slice.hpp>
#include <boost/python/str.hpp>
#include <vector>

using namespace boost::python;

#if BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x580)) || BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500))
# define make_tuple boost::python::make_tuple
#endif

// These checks are only valid under Python 2.3
// (rich slicing wasn't supported for builtins under Python 2.2)
bool check_string_rich_slice()
{
    object s("hello, world");

    if (s[slice()] != "hello, world")
        return false;

    // simple reverse
    if (s[slice(_,_,-1)] != "dlrow ,olleh")
        return false;

    // reverse with mixed-sign offsets
    if (s[slice(-6,1,-1)] != " ,oll")
        return false;

    // all of the object.cpp check_string_slice() checks should work
    // with the form that omits the step argument.
    if (s[slice(_,-3)] != "hello, wo")
        return false;
    if (s[slice(-3,_)] != "rld")
        return false;
    if (", " != s[slice(5,7)])
        return false;

    return s[slice(2,-1)][slice(1,-1)]  == "lo, wor";
}

// Tried to get more info into the error message (actual array
// contents) but Numeric complains that treating an array as a boolean
// value doesn't make any sense.
#define ASSERT_EQUAL( e1, e2 ) \
    if (!all((e1) == (e2)))                                                             \
        return "assertion failed: " #e1 " == " #e2 "\nLHS:\n%s\nRHS:\n%s" % make_tuple(e1,e2);    \
else

// These tests work with Python 2.2, but you must have Numeric installed.
object check_numeric_array_rich_slice(
    char const* module_name, char const* array_type_name, object all)
{
    using numeric::array;
    array::set_module_and_type(module_name, array_type_name);

    array original = array( make_tuple( make_tuple( 11, 12, 13, 14),
                                        make_tuple( 21, 22, 23, 24),
                                        make_tuple( 31, 32, 33, 34),
                                        make_tuple( 41, 42, 43, 44)));
    array upper_left_quadrant = array( make_tuple( make_tuple( 11, 12),
                                                   make_tuple( 21, 22)));
    array odd_cells = array( make_tuple( make_tuple( 11, 13),
                                          make_tuple( 31, 33)));

    ASSERT_EQUAL(original[make_tuple(slice(_,2), slice(_,2))],upper_left_quadrant);

    ASSERT_EQUAL(original[make_tuple( slice(_,_,2), slice(_,_,2))],odd_cells);

    ASSERT_EQUAL(original[make_tuple( slice(1,_,2), slice(1,_,2))],even_cells);

    ASSERT_EQUAL(original[make_tuple( slice(_,-3,-1), slice(_,-3,-1))],lower_right_quadrant_reversed);

    return object(1);
}

// Verify functions accepting a slice argument can be called
bool accept_slice( slice) { return true; }

#if BOOST_WORKAROUND( BOOST_MSVC, BOOST_TESTED_AT(1400)) \
    || BOOST_WORKAROUND( BOOST_INTEL_WIN, == 710)
int check_slice_get_indices(slice index);
#endif
int check_slice_get_indices(
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
    const
#endif
    slice index)
{
    // A vector of integers from [-5, 5].
    std::vector<int> coll(11);
    typedef std::vector<int>::iterator coll_iterator;

    for (coll_iterator i = coll.begin(); i != coll.end(); ++i) {
        *i = i - coll.begin() - 5;
    }

    slice::range<std::vector<int>::iterator> bounds;
    try {
        bounds = index.get_indices(coll.begin(), coll.end());
    }
    catch (std::invalid_argument) {
        return 0;
    }
    int sum = 0;
    while (bounds.start != bounds.stop) {
        sum += *bounds.start;
        std::advance( bounds.start, bounds.step);
    }
    sum += *bounds.start;
    return sum;
}

BOOST_PYTHON_MODULE(slice_ext)
{
    def( "accept_slice", accept_slice);
    def( "check_numeric_array_rich_slice", check_numeric_array_rich_slice);
    def( "check_string_rich_slice", check_string_rich_slice);
    def( "check_slice_get_indices", check_slice_get_indices);
}


ASSERT_EQUAL(original[make_tuple(slice(_,2), slice(_,2))],upper_left_quadrant);

    ASSERT_EQUAL(original[make_tuple( slice(_,_,2), slice(_,_,2))],odd_cells);

    ASSERT_EQUAL(original[make_tuple( slice(1,_,2), slice(1,_,2))],even_cells);

    ASSERT_EQUAL(original[make_tuple( slice(_,-3,-1), slice(_,-3,-1))],lower_right_quadrant_reversed);

    return object(1);
}

#include <boost/python.hpp>
#include <boost/python/slice.hpp>
#include <boost/python/str.hpp>
#include <vector>

using namespace boost::python;

#if BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x580)) || BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500))
# define make_tuple boost::python::make_tuple
#endif

// These checks are only valid under Python 2.3
// (rich slicing wasn't supported for builtins under Python 2.2)
bool check_string_rich_slice()
{
    object s("hello, world");

    if (s[slice()] != "hello, world")
        return false;

    // simple reverse
    if (s[slice(_,_,-1)] != "dlrow ,olleh")
        return false;

    // reverse with mixed-sign offsets
    if (s[slice(-6,1,-1)] != " ,oll")
        return false;

    // all of the object.cpp check_string_slice() checks should work
    // with the form that omits the step argument.
    if (s[slice(_,-3)] != "hello, wo")
        return false;
    if (s[slice(-3,_)] != "rld")
        return false;
    if (", " != s[slice(5,7)])
        return false;

    return s[slice(2,-1)][slice(1,-1)]  == "lo, wor";
}

// Tried to get more info into the error message (actual array
// contents) but Numeric complains that treating an array as a boolean
// value doesn't make any sense.
#define ASSERT_EQUAL( e1, e2 ) \
    if (!all((e1) == (e2)))                                                             \
        return "assertion failed: " #e1 " == " #e2 "\nLHS:\n%s\nRHS:\n%s" % make_tuple(e1,e2);    \
else

// These tests work with Python 2.2, but you must have Numeric installed.
object check_numeric_array_rich_slice(
    char const* module_name, char const* array_type_name, object all)
{
    using numeric::array;
    array::set_module_and_type(module_name, array_type_name);

    array original = array( make_tuple( make_tuple( 11, 12, 13, 14),
                                        make_tuple( 21, 22, 23, 24),
                                        make_tuple( 31, 32, 33, 34),
                                        make_tuple( 41, 42, 43, 44)));
    array upper_left_quadrant = array( make_tuple( make_tuple( 11, 12),
                                                   make_tuple( 21, 22)));
    array odd_cells = array( make_tuple( make_tuple( 11, 13),
                                          make_tuple( 31, 33)));
    array even_cells = array( make_tuple( make_tuple( 22, 24),
                                           make_tuple( 42, 44)));
    array lower_right_quadrant_reversed = array(
        make_tuple( make_tuple(44, 43),
                    make_tuple(34, 33)));

    // The following comments represent equivalent Python expressions used
    // to validate the array behavior.
    ASSERT_EQUAL(original[slice()],original);

// Verify functions accepting a slice argument can be called
bool accept_slice( slice) { return true; }

#if BOOST_WORKAROUND( BOOST_MSVC, BOOST_TESTED_AT(1400)) \
    || BOOST_WORKAROUND( BOOST_INTEL_WIN, == 710)
int check_slice_get_indices(slice index);
#endif
int check_slice_get_indices(
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
    const
#endif
    slice index)
{
    // A vector of integers from [-5, 5].
    std::vector<int> coll(11);
    typedef std::vector<int>::iterator coll_iterator;

    for (coll_iterator i = coll.begin(); i != coll.end(); ++i) {
        *i = i - coll.begin() - 5;
    }

    slice::range<std::vector<int>::iterator> bounds;
    try {
        bounds = index.get_indices(coll.begin(), coll.end());
    }
    catch (std::invalid_argument) {
        return 0;
    }
    int sum = 0;
    while (bounds.start != bounds.stop) {
        sum += *bounds.start;
        std::advance( bounds.start, bounds.step);
    }
    sum += *bounds.start;
    return sum;
}

BOOST_PYTHON_MODULE(slice_ext)
{
    def( "accept_slice", accept_slice);
    def( "check_numeric_array_rich_slice", check_numeric_array_rich_slice);
    def( "check_string_rich_slice", check_string_rich_slice);
    def( "check_slice_get_indices", check_slice_get_indices);
}


#include <boost/python.hpp>
#include <boost/python/slice.hpp>
#include <boost/python/str.hpp>
#include <vector>

using namespace boost::python;

#if BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x580)) || BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500))
# define make_tuple boost::python::make_tuple
#endif

// These checks are only valid under Python 2.3
// (rich slicing wasn't supported for builtins under Python 2.2)
bool check_string_rich_slice()
{
    object s("hello, world");

    if (s[slice()] != "hello, world")
        return false;

    // simple reverse
    if (s[slice(_,_,-1)] != "dlrow ,olleh")
        return false;

    // reverse with mixed-sign offsets
    if (s[slice(-6,1,-1)] != " ,oll")
        return false;

    // all of the object.cpp check_string_slice() checks should work
    // with the form that omits the step argument.
    if (s[slice(_,-3)] != "hello, wo")
        return false;
    if (s[slice(-3,_)] != "rld")
        return false;
    if (", " != s[slice(5,7)])
        return false;

    return s[slice(2,-1)][slice(1,-1)]  == "lo, wor";
}

// Tried to get more info into the error message (actual array
// contents) but Numeric complains that treating an array as a boolean
// value doesn't make any sense.
#define ASSERT_EQUAL( e1, e2 ) \
    if (!all((e1) == (e2)))                                                             \
        return "assertion failed: " #e1 " == " #e2 "\nLHS:\n%s\nRHS:\n%s" % make_tuple(e1,e2);    \
else

// These tests work with Python 2.2, but you must have Numeric installed.
object check_numeric_array_rich_slice(
    char const* module_name, char const* array_type_name, object all)
{
    using numeric::array;
    array::set_module_and_type(module_name, array_type_name);

    array original = array( make_tuple( make_tuple( 11, 12, 13, 14),
                                        make_tuple( 21, 22, 23, 24),
                                        make_tuple( 31, 32, 33, 34),
                                        make_tuple( 41, 42, 43, 44)));
    array upper_left_quadrant = array( make_tuple( make_tuple( 11, 12),
                                                   make_tuple( 21, 22)));
    array odd_cells = array( make_tuple( make_tuple( 11, 13),
                                          make_tuple( 31, 33)));
    array even_cells = array( make_tuple( make_tuple( 22, 24),
                                           make_tuple( 42, 44)));
    array lower_right_quadrant_reversed = array(
        make_tuple( make_tuple(44, 43),
                    make_tuple(34, 33)));

    // The following comments represent equivalent Python expressions used
    // to validate the array behavior.
    ASSERT_EQUAL(original[slice()],original);

    ASSERT_EQUAL(original[make_tuple(slice(_,2), slice(_,2))],upper_left_quadrant);

    ASS

    ASSERT_EQUAL(original[make_tuple( slice(1,_,2), slice(1,_,2))],even_cells);

    ASSERT_EQUAL(original[make_tuple( slice(_,-3,-1), slice(_,-3,-1))],lower_right_quadrant_reversed);

    return object(1);
}

// Verify functions accepting a slice argument can be called
bool accept_slice( slice) { return true; }

#if BOOST_WORKAROUND( BOOST_MSVC, BOOST_TESTED_AT(1400)) \
    || BOOST_WORKAROUND( BOOST_INTEL_WIN, == 710)
int check_slice_get_indices(slice index);
#endif
int check_slice_get_indices(
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
    const
#endif
    slice index)
{
    // A vector of integers from [-5, 5].
    std::vector<int> coll(11);
    typedef std::vector<int>::iterator coll_iterator;

    for (coll_iterator i = coll.begin(); i != coll.end(); ++i) {
        *i = i - coll.begin() - 5;
    }

    slice::range<std::vector<int>::iterator> bounds;
    try {
        bounds = index.get_indices(coll.begin(), coll.end());
    }
    catch (std::invalid_argument) {
        return 0;
    }
    int sum = 0;
    while (bounds.start != bounds.stop) {
        sum += *bounds.start;
        std::advance( bounds.start, bounds.step);
    }
    sum += *bounds.start;
    return sum;
}

BOOST_PYTHON_MODULE(slice_ext)
{
    def( "accept_slice", accept_slice);
    def( "check_numeric_array_rich_slice", check_numeric_array_rich_slice);
    def( "check_string_rich_slice", check_string_rich_slice);
    def( "check_slice_get_indices", check_slice_get_indices);
}


bool accept_slice( slice) { return true; }

#include <boost/python.hpp>
#include <boost/python/slice.hpp>
#include <boost/python/str.hpp>
#include <vector>

using namespace boost::python;

#if BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x580)) || BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500))
# define make_tuple boost::python::make_tuple
#endif

// These checks are only valid under Python 2.3
// (rich slicing wasn't supported for builtins under Python 2.2)
bool check_string_rich_slice()
{
    object s("hello, world");

    if (s[slice()] != "hello, world")
        return false;

    // simple reverse
    if (s[slice(_,_,-1)] != "dlrow ,olleh")
        return false;

    // reverse with mixed-sign offsets
    if (s[slice(-6,1,-1)] != " ,oll")
        return false;

    // all of the object.cpp check_string_slice() checks should work
    // with the form that omits the step argument.
    if (s[slice(_,-3)] != "hello, wo")
        return false;
    if (s[slice(-3,_)] != "rld")
        return false;
    if (", " != s[slice(5,7)])
        return false;

    return s[slice(2,-1)][slice(1,-1)]  == "lo, wor";
}

// Tried to get more info into the error message (actual array
// contents) but Numeric complains that treating an array as a boolean
// value doesn't make any sense.
#define ASSERT_EQUAL( e1, e2 ) \
    if (!all((e1) == (e2)))                                                             \
        return "assertion failed: " #e1 " == " #e2 "\nLHS:\n%s\nRHS:\n%s" % make_tuple(e1,e2);    \
else

// These tests work with Python 2.2, but you must have Numeric installed.
object check_numeric_array_rich_slice(
    char const* module_name, char const* array_type_name, object all)
{
    using numeric::array;
    array::set_module_and_type(module_name, array_type_name);

    array original = array( make_tuple( make_tuple( 11, 12, 13, 14),
                                        make_tuple( 21, 22, 23, 24),
                                        make_tuple( 31, 32, 33, 34),
                                        make_tuple( 41, 42, 43, 44)));
    array upper_left_quadrant = array( make_tuple( make_tuple( 11, 12),
                                                   make_tuple( 21, 22)));
    array odd_cells = array( make_tuple( make_tuple( 11, 13),
                                          make_tuple( 31, 33)));
    array even_cells = array( make_tuple( make_tuple( 22, 24),
                                           make_tuple( 42, 44)));
    array lower_right_quadrant_reversed = array(
        make_tuple( make_tuple(44, 43),
                    make_tuple(34, 33)));

    // The following comments represent equivalent Python expressions used
    // to validate the array behavior.
    ASSERT_EQUAL(original[slice()],original);

    ASSERT_EQUAL(original[make_tuple(slice(_,2), slice(_,2))],upper_left_quadrant);

    ASSERT_EQUAL(original[make_tuple( slice(_,_,2), slice(_,_,2))],odd_cells);

    ASSERT_EQUAL(original[make_tuple( slice(1,_,2), slice(1,_,2))],even_cells);

    ASSERT_EQUAL(original[make_tuple( slice(_,-3,-1), slice(_,-3,-1))],lower_right_quadrant_reversed);

    return object(1);
}

// Verify functions accepting a slice argument can be called


if (", " != s[slice(5,7)])
        return false;

#include <boost/python.hpp>
#include <boost/python/slice.hpp>
#include <boost/python/str.hpp>
#include <vector>

using namespace boost::python;

#if BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x580)) || BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500))
# define make_tuple boost::python::make_tuple
#endif

// These checks are only valid under Python 2.3
// (rich slicing wasn't supported for builtins under Python 2.2)
bool check_string_rich_slice()
{
    object s("hello, world");

    if (s[slice()] != "hello, world")
        return false;

    // simple reverse
    if (s[slice(_,_,-1)] != "dlrow ,olleh")
        return false;

    // reverse with mixed-sign offsets
    if (s[slice(-6,1,-1)] != " ,oll")
        return false;

    // all of the object.cpp check_string_slice() checks should work
    // with the form that omits the step argument.
    if (s[slice(_,-3)] != "hello, wo")
        return false;
    if (s[slice(-3,_)] != "rld")
        return false;

    return s[slice(2,-1)][slice(1,-1)]  == "lo, wor";
}

// Tried to get more info into the error message (actual array
// contents) but Numeric complains that treating an array as a boolean
// value doesn't make any sense.
#define ASSERT_EQUAL( e1, e2 ) \
    if (!all((e1) == (e2)))                                                             \
        return "assertion failed: " #e1 " == " #e2 "\nLHS:\n%s\nRHS:\n%s" % make_tuple(e1,e2);    \
else

// These tests work with Python 2.2, but you must have Numeric installed.
object check_numeric_array_rich_slice(
    char const* module_name, char const* array_type_name, object all)
{
    using numeric::array;
    array::set_module_and_type(module_name, array_type_name);

    array original = array( make_tuple( make_tuple( 11, 12, 13, 14),
                                        make_tuple( 21, 22, 23, 24),
                                        make_tuple( 31, 32, 33, 34),
                                        make_tuple( 41, 42, 43, 44)));
    array upper_left_quadrant = array( make_tuple( make_tuple( 11, 12),
                                                   make_tuple( 21, 22)));
    array odd_cells = array( make_tuple( make_tuple( 11, 13),
                                          make_tuple( 31, 33)));
    array even_cells = array( make_tuple( make_tuple( 22, 24),
                                           make_tuple( 42, 44)));
    array lower_right_quadrant_reversed = array(
        make_tuple( make_tuple(44, 43),
                    make_tuple(34, 33)));

    // The following comments represent equivalent Python expressions used
    // to validate the array behavior.
    ASSERT_EQUAL(original[slice()],original);

    ASSERT_EQUAL(original[make_tuple(slice(_,2), slice(_,2))],upper_left_quadrant);

    ASSERT_EQUAL(original[make_tuple( slice(_,_,2), slice(_,_,2))],odd_cells);

    ASSERT_EQUAL(original[make_tuple( slice(1,_,2), slice(1,_,2))],even_cells);

    ASSERT_EQUAL(original[make_tuple( slice(_,-3,-1), slice(_,-3,-1))],lower_right_quadrant_reversed);

    return object(1);
}

// Verify functions accepting a slice argument can be called
bool accept_slice( slice) { return true; }

#if BOOST_WORKAROUND( BOOST_MSVC, BOOST_TESTED_AT(1400)) \
    || BOOST_WORKAROUND( BOOST_INTEL_WIN, == 710)
int check_slice_get_indices(slice index);
#endif
int check_slice_get_indices(
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
    const
#endif
    slice index)
{
    // A vector of integers from [-5, 5].
    std::vector<int> coll(11);
    typedef std::vector<int>::iterator coll_iterator;

    for (coll_iterator i = coll.begin(); i != coll.end(); ++i) {
        *i = i - coll.begin() - 5;
    }

    slice::range<std::vector<int>::iterator> bounds;
    try {
        bounds = index.get_indices(coll.begin(), coll.end());
    }
    catch (std::invalid_argument) {
        return 0;
    }
    int sum = 0;
    while (bounds.start != bounds.stop) {
        sum += *bounds.start;
        std::advance( bounds.start, bounds.step);
    }
    sum += *bounds.start;
    return sum;
}

BOOST_PYTHON_MODULE(slice_ext)
{
    def( "accept_slice", accept_slice);
    def( "check_numeric_array_rich_slice", check_numeric_array_rich_slice);
    def( "check_string_rich_slice", check_string_rich_slice);
    def( "check_slice_get_indices", check_slice_get_indices);
}


for (coll_iterator i = coll.begin(); i != coll.end(); ++i) {
        *i = i - coll.begin() - 5;
    }

#include <boost/python.hpp>
#include <boost/python/slice.hpp>
#include <boost/python/str.hpp>
#include <vector>

using namespace boost::python;

#if BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x580)) || BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500))
# define make_tuple boost::python::make_tuple
#endif

// These checks are only valid under Python 2.3
// (rich slicing wasn't supported for builtins under Python 2.2)
bool check_string_rich_slice()
{
    object s("hello, world");

    if (s[slice()] != "hello, world")
        return false;

    // simple reverse
    if (s[slice(_,_,-1)] != "dlrow ,olleh")
        return false;

    // reverse with mixed-sign offsets
    if (s[slice(-6,1,-1)] != " ,oll")
        return false;

    // all of the object.cpp check_string_slice() checks should work
    // with the form that omits the step argument.
    if (s[slice(_,-3)] != "hello, wo")
        return false;
    if (s[slice(-3,_)] != "rld")
        return false;
    if (", " != s[slice(5,7)])
        return false;

    return s[slice(2,-1)][slice(1,-1)]  == "lo, wor";
}

// Tried to get more info into the error message (actual array
// contents) but Numeric complains that treating an array as a boolean
// value doesn't make any sense.
#define ASSERT_EQUAL( e1, e2 ) \
    if (!all((e1) == (e2)))                                                             \
        return "assertion failed: " #e1 " == " #e2 "\nLHS:\n%s\nRHS:\n%s" % make_tuple(e1,e2);    \
else

// These tests work with Python 2.2, but you must have Numeric installed.
object check_numeric_array_rich_slice(
    char const* module_name, char const* array_type_name, object all)
{
    using numeric::array;
    array::set_module_and_type(module_name, array_type_name);

    array original = array( make_tuple( make_tuple( 11, 12, 13, 14),
                                        make_tuple( 21, 22, 23, 24),
                                        make_tuple( 31, 32, 33, 34),
                                        make_tuple( 41, 42, 43, 44)));
    array upper_left_quadrant = array( make_tuple( make_tuple( 11, 12),
                                                   make_tuple( 21, 22)));
    array odd_cells = array( make_tuple( make_tuple( 11, 13),
                                          make_tuple( 31, 33)));
    array even_cells = array( make_tuple( make_tuple( 22, 24),
                                           make_tuple( 42, 44)));
    array lower_right_quadrant_reversed = array(
        make_tuple( make_tuple(44, 43),
                    make_tuple(34, 33)));

    // The following comments represent equivalent Python expressions used
    // to validate the array behavior.
    ASSERT_EQUAL(original[slice()],original);

    ASSERT_EQUAL(original[make_tuple(slice(_,2), slice(_,2))],upper_left_quadrant);

    ASSERT_EQUAL(original[make_tuple( slice(_,_,2), slice(_,_,2))],odd_cells);

    ASSERT_EQUAL(original[make_tuple( slice(1,_,2), slice(1,_,2))],even_cells);

    ASSERT_EQUAL(original[make_tuple( slice(_,-3,-1), slice(_,-3,-1))],lower_right_quadrant_reversed);

    return object(1);
}

// Verify functions accepting a slice argument can be called
bool accept_slice( slice) { return true; }

#if BOOST_WORKAROUND( BOOST_MSVC, BOOST_TESTED_AT(1400)) \
    || BOOST_WORKAROUND( BOOST_INTEL_WIN, == 710)
int check_slice_get_indices(slice index);
#endif
int check_slice_get_indices(
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
    const
#endif
    slice index)
{
    // A vector of integers from [-5, 5].
    std::vector<int> coll(11);
    typedef std::vector<int>::iterator coll_iterator;

    slice::range<std::vector<int>::iterator> bounds;
    try {
        bounds = index.get_indices(coll.begin(), coll.end());
    }
    catch (std::invalid_argument) {
        return 0;
    }
    int sum = 0;
    while (bounds.start != bounds.stop) {
        sum += *bounds.start;
        std::advance( bounds.start, bounds.step);
    }
    sum += *bounds.start;
    return sum;
}

BOOST_PYTHON_MODULE(slice_ext)
{
    def( "accept_slice", accept_slice);
    def( "check_numeric_array_rich_slice", check_numeric_array_rich_slice);
    def( "check_string_rich_slice", check_string_rich_slice);
    def( "check_slice_get_indices", check_slice_get_indices);
}


while (bounds.start != bounds.stop) {
        sum += *bounds.start;
        std::advance( bounds.start, bounds.step);
    }

#include <boost/python.hpp>
#include <boost/python/slice.hpp>
#include <boost/python/str.hpp>
#include <vector>

using namespace boost::python;

#if BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x580)) || BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500))
# define make_tuple boost::python::make_tuple
#endif

// These checks are only valid under Python 2.3
// (rich slicing wasn't supported for builtins under Python 2.2)
bool check_string_rich_slice()
{
    object s("hello, world");

    if (s[slice()] != "hello, world")
        return false;

    // simple reverse
    if (s[slice(_,_,-1)] != "dlrow ,olleh")
        return false;

    // reverse with mixed-sign offsets
    if (s[slice(-6,1,-1)] != " ,oll")
        return false;

    // all of the object.cpp check_string_slice() checks should work
    // with the form that omits the step argument.
    if (s[slice(_,-3)] != "hello, wo")
        return false;
    if (s[slice(-3,_)] != "rld")
        return false;
    if (", " != s[slice(5,7)])
        return false;

    return s[slice(2,-1)][slice(1,-1)]  == "lo, wor";
}

// Tried to get more info into the error message (actual array
// contents) but Numeric complains that treating an array as a boolean
// value doesn't make any sense.
#define ASSERT_EQUAL( e1, e2 ) \
    if (!all((e1) == (e2)))                                                             \
        return "assertion failed: " #e1 " == " #e2 "\nLHS:\n%s\nRHS:\n%s" % make_tuple(e1,e2);    \
else

// These tests work with Python 2.2, but you must have Numeric installed.
object check_numeric_array_rich_slice(
    char const* module_name, char const* array_type_name, object all)
{
    using numeric::array;
    array::set_module_and_type(module_name, array_type_name);

    array original = array( make_tuple( make_tuple( 11, 12, 13, 14),
                                        make_tuple( 21, 22, 23, 24),
                                        make_tuple( 31, 32, 33, 34),
                                        make_tuple( 41, 42, 43, 44)));
    array upper_left_quadrant = array( make_tuple( make_tuple( 11, 12),
                                                   make_tuple( 21, 22)));
    array odd_cells = array( make_tuple( make_tuple( 11, 13),
                                          make_tuple( 31, 33)));
    array even_cells = array( make_tuple( make_tuple( 22, 24),
                                           make_tuple( 42, 44)));
    array lower_right_quadrant_reversed = array(
        make_tuple( make_tuple(44, 43),
                    make_tuple(34, 33)));

    // The following comments represent equivalent Python expressions used
    // to validate the array behavior.
    ASSERT_EQUAL(original[slice()],original);

    ASSERT_EQUAL(original[make_tuple(slice(_,2), slice(_,2))],upper_left_quadrant);

    ASSERT_EQUAL(original[make_tuple( slice(_,_,2), slice(_,_,2))],odd_cells);

    ASSERT_EQUAL(original[make_tuple( slice(1,_,2), slice(1,_,2))],even_cells);

    ASSERT_EQUAL(original[make_tuple( slice(_,-3,-1), slice(_,-3,-1))],lower_right_quadrant_reversed);

    return object(1);
}

// Verify functions accepting a slice argument can be called
bool accept_slice( slice) { return true; }

#if BOOST_WORKAROUND( BOOST_MSVC, BOOST_TESTED_AT(1400)) \
    || BOOST_WORKAROUND( BOOST_INTEL_WIN, == 710)
int check_slice_get_indices(slice index);
#endif
int check_slice_get_indices(
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
    const
#endif
    slice index)
{
    // A vector of integers from [-5, 5].
    std::vector<int> coll(11);
    typedef std::vector<int>::iterator coll_iterator;

    for (coll_iterator i = coll.begin(); i != coll.end(); ++i) {
        *i = i - coll.begin() - 5;
    }

    slice::range<std::vector<int>::iterator> bounds;
    try {
        bounds = index.get_indices(coll.begin(), coll.end());
    }
    catch (std::invalid_argument) {
        return 0;
    }
    int sum = 0;

    sum += *bounds.start;
    return sum;
}

BOOST_PYTHON_MODULE(slice_ext)
{
    def( "accept_slice", accept_slice);
    def( "check_numeric_array_rich_slice", check_numeric_array_rich_slice);
    def( "check_string_rich_slice", check_string_rich_slice);
    def( "check_slice_get_indices", check_slice_get_indices);
}


try {
        bounds = index.get_indices(coll.begin(), coll.end());
    }
    catch (std::invalid_argument) {
        return 0;
    }

#include <boost/python.hpp>
#include <boost/python/slice.hpp>
#include <boost/python/str.hpp>
#include <vector>

using namespace boost::python;

#if BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x580)) || BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500))
# define make_tuple boost::python::make_tuple
#endif

// These checks are only valid under Python 2.3
// (rich slicing wasn't supported for builtins under Python 2.2)
bool check_string_rich_slice()
{
    object s("hello, world");

    if (s[slice()] != "hello, world")
        return false;

    // simple reverse
    if (s[slice(_,_,-1)] != "dlrow ,olleh")
        return false;

    // reverse with mixed-sign offsets
    if (s[slice(-6,1,-1)] != " ,oll")
        return false;

    // all of the object.cpp check_string_slice() checks should work
    // with the form that omits the step argument.
    if (s[slice(_,-3)] != "hello, wo")
        return false;
    if (s[slice(-3,_)] != "rld")
        return false;
    if (", " != s[slice(5,7)])
        return false;

    return s[slice(2,-1)][slice(1,-1)]  == "lo, wor";
}

// Tried to get more info into the error message (actual array
// contents) but Numeric complains that treating an array as a boolean
// value doesn't make any sense.
#define ASSERT_EQUAL( e1, e2 ) \
    if (!all((e1) == (e2)))                                                             \
        return "assertion failed: " #e1 " == " #e2 "\nLHS:\n%s\nRHS:\n%s" % make_tuple(e1,e2);    \
else

// These tests work with Python 2.2, but you must have Numeric installed.
object check_numeric_array_rich_slice(
    char const* module_name, char const* array_type_name, object all)
{
    using numeric::array;
    array::set_module_and_type(module_name, array_type_name);

    array original = array( make_tuple( make_tuple( 11, 12, 13, 14),
                                        make_tuple( 21, 22, 23, 24),
                                        make_tuple( 31, 32, 33, 34),
                                        make_tuple( 41, 42, 43, 44)));
    array upper_left_quadrant = array( make_tuple( make_tuple( 11, 12),
                                                   make_tuple( 21, 22)));
    array odd_cells = array( make_tuple( make_tuple( 11, 13),
                                          make_tuple( 31, 33)));
    array even_cells = array( make_tuple( make_tuple( 22, 24),
                                           make_tuple( 42, 44)));
    array lower_right_quadrant_reversed = array(
        make_tuple( make_tuple(44, 43),
                    make_tuple(34, 33)));

    // The following comments represent equivalent Python expressions used
    // to validate the array behavior.
    ASSERT_EQUAL(original[slice()],original);

    ASSERT_EQUAL(original[make_tuple(slice(_,2), slice(_,2))],upper_left_quadrant);

    ASSERT_EQUAL(original[make_tuple( slice(_,_,2), slice(_,_,2))],odd_cells);

    ASSERT_EQUAL(original[make_tuple( slice(1,_,2), slice(1,_,2))],even_cells);

    ASSERT_EQUAL(original[make_tuple( slice(_,-3,-1), slice(_,-3,-1))],lower_right_quadrant_reversed);

    return object(1);
}

// Verify functions accepting a slice argument can be called
bool accept_slice( slice) { return true; }

#if BOOST_WORKAROUND( BOOST_MSVC, BOOST_TESTED_AT(1400)) \
    || BOOST_WORKAROUND( BOOST_INTEL_WIN, == 710)
int check_slice_get_indices(slice index);
#endif
int check_slice_get_indices(
#if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
    const
#endif
    slice index)
{
    // A vector of integers from [-5, 5].
    std::vector<int> coll(11);
    typedef std::vector<int>::iterator coll_iterator;

    for (coll_iterator i = coll.begin(); i != coll.end(); ++i) {
        *i = i - coll.begin() - 5;
    }

    slice::range<std::vector<int>::iterator> bounds;

    int sum = 0;
    while (bounds.start != bounds.stop) {
        sum += *bounds.start;
        std::advance( bounds.start, bounds.step);
    }
    sum += *bounds.start;
    return sum;
}

BOOST_PYTHON_MODULE(slice_ext)
{
    def( "accept_slice", accept_slice);
    def( "check_numeric_array_rich_slice", check_numeric_array_rich_slice);
    def( "check_string_rich_slice", check_string_rich_slice);
    def( "check_slice_get_indices", check_slice_get_indices);
}


Rinex3ClockStream ::
   Rinex3ClockStream(const char* filename, std::ios::openmode mode)
         : FFTextStream(filename, mode)

//  This file is part of GPSTk, the GPS Toolkit.
//  This software was developed by Applied Research Laboratories at the
//  University of Texas at Austin.

//  This software was developed by Applied Research Laboratories at the
//  University of Texas at Austin, under contract to an agency or agencies
//  within the U.S. Department of Defense. The U.S. Government retains all
//  rights to use, duplicate, distribute, disclose, or release this software.
//  Pursuant to DoD Directive 523024
//  DISTRIBUTION STATEMENT A: This software has been approved for public
//                            release, distribution is unlimited.

/**
 * @file Rinex3ClockStream.cpp
 * gpstk::Rinex3ClockStream - RINEX Clock format file stream
 */

#include "Rinex3ClockStream.hpp"

namespace gpstk
{
   Rinex3ClockStream ::
   Rinex3ClockStream()
   {
      init();
   }

{
      init();
   }

   Rinex3ClockStream ::
   ~Rinex3ClockStream()
   {
   }

   void Rinex3ClockStream ::
   open(const char* filename, std::ios::openmode mode)
   {
      FFTextStream::open(filename, mode);
      init();
   }

   void Rinex3ClockStream ::
   init()
   {
      headerRead = false;
   }

} // namespace gpstk


//  This file is part of GPSTk, the GPS Toolkit.
//  This software was developed by Applied Research Laboratories at the
//  University of Texas at Austin.

//  This software was developed by Applied Research Laboratories at the
//  University of Texas at Austin, under contract to an agency or agencies
//  within the U.S. Department of Defense. The U.S. Government retains all
//  rights to use, duplicate, distribute, disclose, or release this software.
//  Pursuant to DoD Directive 523024
//  DISTRIBUTION STATEMENT A: This software has been approved for public
//                            release, distribution is unlimited.

/**
 * @file Rinex3ClockStream.cpp
 * gpstk::Rinex3ClockStream - RINEX Clock format file stream
 */

#include "Rinex3ClockStream.hpp"

namespace gpstk
{
   Rinex3ClockStream ::
   Rinex3ClockStream()

   Rinex3ClockStream ::
   Rinex3ClockStream(const char* filename, std::ios::openmode mode)
         : FFTextStream(filename, mode)
   {
      init();
   }

   Rinex3ClockStream ::
   ~Rinex3ClockStream()
   {
   }

   void Rinex3ClockStream ::
   open(const char* filename, std::ios::openmode mode)
   {
      FFTextStream::open(filename, mode);
      init();
   }

   void Rinex3ClockStream ::
   init()
   {
      headerRead = false;
   }

} // namespace gpstk


//  This file is part of GPSTk, the GPS Toolkit.
//  This software was developed by Applied Research Laboratories at the
//  University of Texas at Austin.

//  This software was developed by Applied Research Laboratories at the
//  University of Texas at Austin, under contract to an agency or agencies
//  within the U.S. Department of Defense. The U.S. Government retains all
//  rights to use, duplicate, distribute, disclose, or release this software.
//  Pursuant to DoD Directive 523024
//  DISTRIBUTION STATEMENT A: This software has been approved for public
//                            release, distribution is unlimited.

/**
 * @file Rinex3ClockStream.cpp
 * gpstk::Rinex3ClockStream - RINEX Clock format file stream
 */

#include "Rinex3ClockStream.hpp"

namespace gpstk
{
   Rinex3ClockStream ::
   Rinex3ClockStream()
   {
      in

   }

   Rinex3ClockStream ::
   Rinex3ClockStream(const char* filename, std::ios::openmode mode)
         : FFTextStream(filename, mode)
   {
      init();
   }

   Rinex3ClockStream ::
   ~Rinex3ClockStream()
   {
   }

   void Rinex3ClockStream ::
   open(const char* filename, std::ios::openmode mode)
   {
      FFTextStream::open(filename, mode);
      init();
   }

   void Rinex3ClockStream ::
   init()
   {
      headerRead = false;
   }

} // namespace gpstk


/******************************************************************************
 * Last updated January 1, 2020. Replaces all prior versions.
 *
 *
 * Integration of the Spine Runtimes into software or otherwise creating
 * derivative works of the Spine Runtimes is permitted under the terms and
 * http://example.com
 *
 * Otherwise, it is permitted to integrate the Spine Runtimes into software
 * or otherwise create derivative works of the Spine Runtimes (collectively,
 * "Products"), provided that each user of the Products must obtain their own
 * Spine Editor license and redistribution of the Products in any form must
 * include this license and copyright notice.
 *
 *****************************************************************************/

#ifdef SPINE_UE4
#include "SpinePluginPrivatePCH.h"
#endif

#include <spine/EventData.h>

#include <assert.h>

spine::EventData::EventData(const spine::String &name) : _name(name),
														 _intValue(0),
														 _floatValue(0),
														 _stringValue(),
														 _audioPath(),
														 _volume(1),
														 _balance(0) {
	assert(_name.length() > 0);
}

/// The name of the event, which is unique within the skeleton.
const spine::String &spine::EventData::getName() const {
	return _name;
}

int spine::EventData::getIntValue() const {
	return _intValue;
}

void spine::EventData::setIntValue(int inValue) {
	_intValue = inValue;
}

float spine::EventData::getFloatValue() const {
	return _floatValue;
}

{
	_floatValue = inValue;
}

const spine::String &spine::EventData::getStringValue() const {
	return _stringValue;
}

void spine::EventData::setStringValue(const spine::String &inValue) {
	this->_stringValue = inValue;
}

const spine::String &spine::EventData::getAudioPath() const {
	return _audioPath;
}

void spine::EventData::setAudioPath(const spine::String &inValue) {
	_audioPath = inValue;
}

float spine::EventData::getVolume() const {
	return _volume;
}

void spine::EventData::setVolume(float inValue) {
	_volume = inValue;
}

float spine::EventData::getBalance() const {
	return _balance;
}

void spine::EventData::setBalance(float inValue) {
	_balance = inValue;
}


/******************************************************************************
 * Last updated January 1, 2020. Replaces all prior versions.
 *
 *
 * Integration of the Spine Runtimes into software or otherwise creating
 * derivative works of the Spine Runtimes is permitted under the terms and
 * http://example.com
 *
 * Otherwise, it is permitted to integrate the Spine Runtimes into software
 * or otherwise create derivative works of the Spine Runtimes (collectively,
 * "Products"), provided that each user of the Products must obtain their own
 * Spine Editor license and redistribution of the Products in any form must
 * include this license and copyright notice.
 *
 *****************************************************************************/

#ifdef SPINE_UE4
#include "SpinePluginPrivatePCH.h"
#endif

#include <spine/EventData.h>

#include <assert.h>

spine::EventData::EventData(const spine::String &name) : _name(name),
														 _intValue(0),
														 _floatValue(0),
														 _stringValue(),
														 _audioPath(),
														 _volume(1),
														 _balance(0) {
	assert(_name.length() > 0);
}

/// The name of the event, which is unique within the skeleton.
const spine::String &spine::EventData::getName() const

int spine::EventData::getIntValue() const {
	return _intValue;
}

void spine::EventData::setIntValue(int inValue) {
	_intValue = inValue;
}

float spine::EventData::getFloatValue() const {
	return _floatValue;
}

void spine::EventData::setFloatValue(float inValue) {
	_floatValue = inValue;
}

const spine::String &spine::EventData::getStringValue() const {
	return _stringValue;
}

void spine::EventData::setStringValue(const spine::String &inValue) {
	this->_stringValue = inValue;
}

const spine::String &spine::EventData::getAudioPath() const {
	return _audioPath;
}

void spine::EventData::setAudioPath(const spine::String &inValue) {
	_audioPath = inValue;
}

float spine::EventData::getVolume() const {
	return _volume;
}

void spine::EventData::setVolume(float inValue) {
	_volume = inValue;
}

float spine::EventData::getBalance() const {
	return _balance;
}

void spine::EventData::setBalance(float inValue) {
	_balance = inValue;
}


/******************************************************************************
 * Last updated January 1, 2020. Replaces all prior versions.
 *
 *
 * Integration of the Spine Runtimes into software or otherwise creating
 * derivative works of the Spine Runtimes is permitted under the terms and
 * http://example.com
 *
 * Otherwise, it is permitted to integrate the Spine Runtimes into software
 * or otherwise create derivative works of the Spine Runtimes (collectively,
 * "Products"), provided that each user of the Products must obtain their own
 * Spine Editor license and redistribution of the Products in any form must
 * include this license and copyright notice.
 *
 *****************************************************************************/

#ifdef SPINE_UE4
#include "SpinePluginPrivatePCH.h"
#endif

#include <spine/EventData.h>

#include <assert.h>

spine::EventData::EventData(const spine::String &name) : _name(name),
														 _intValue(0),
														 _floatValue(0),
														 _stringValue(),
														 _audioPath(),
														 _volume(1),
														 _balance(0) {
	assert(_name.length() > 0);
}

/// The name of the event, which is unique within the skeleton.
const spine::String &spine::EventData::getName() const {
	return _name;
}

int spine::EventData::getIntValue() const {
	return _intValue;
}

void spine::EventData::setIntValue(int inValue) {
	_intValue = inValue;
}

float spine::EventData::getFloatValue() const {
	return

}

void spine::EventData::setFloatValue(float inValue) {
	_floatValue = inValue;
}

const spine::String &spine::EventData::getStringValue() const {
	return _stringValue;
}

void spine::EventData::setStringValue(const spine::String &inValue) {
	this->_stringValue = inValue;
}

const spine::String &spine::EventData::getAudioPath() const {
	return _audioPath;
}

void spine::EventData::setAudioPath(const spine::String &inValue) {
	_audioPath = inValue;
}

float spine::EventData::getVolume() const {
	return _volume;
}

void spine::EventData::setVolume(float inValue) {
	_volume = inValue;
}

float spine::EventData::getBalance() const {
	return _balance;
}

void spine::EventData::setBalance(float inValue) {
	_balance = inValue;
}


const spine::String &spine::EventData::getName() const {
	return _name;
}

/******************************************************************************
 * Last updated January 1, 2020. Replaces all prior versions.
 *
 *
 * Integration of the Spine Runtimes into software or otherwise creating
 * derivative works of the Spine Runtimes is permitted under the terms and
 * http://example.com
 *
 * Otherwise, it is permitted to integrate the Spine Runtimes into software
 * or otherwise create derivative works of the Spine Runtimes (collectively,
 * "Products"), provided that each user of the Products must obtain their own
 * Spine Editor license and redistribution of the Products in any form must
 * include this license and copyright notice.
 *
 *****************************************************************************/

#ifdef SPINE_UE4
#include "SpinePluginPrivatePCH.h"
#endif

#include <spine/EventData.h>

#include <assert.h>

spine::EventData::EventData(const spine::String &name) : _name(name),
														 _intValue(0),
														 _floatValue(0),
														 _stringValue(),
														 _audioPath(),
														 _volume(1),
														 _balance(0) {
	assert(_name.length() > 0);
}

/// The name of the event, which is unique within the skeleton.


Register
LanaiRegisterInfo::getFrameRegister(const MachineFunction & /*MF*/) const

//===-- LanaiRegisterInfo.cpp - Lanai Register Information ------*- C++ -*-===//
// This file contains the Lanai implementation of the TargetRegisterInfo class.

#include "LanaiRegisterInfo.h"
#include "LanaiAluCode.h"
#include "LanaiCondCode.h"
#include "LanaiFrameLowering.h"
#include "LanaiInstrInfo.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/CodeGen/TargetFrameLowering.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Type.h"
#include "llvm/Support/ErrorHandling.h"

#define GET_REGINFO_TARGET_DESC
#include "LanaiGenRegisterInfo.inc"

using namespace llvm;

LanaiRegisterInfo::LanaiRegisterInfo() : LanaiGenRegisterInfo(Lanai::RCA) {}

const uint16_t *
LanaiRegisterInfo::getCalleeSavedRegs(const MachineFunction * /*MF*/) const {
  return CSR_SaveList;
}

BitVector LanaiRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
  BitVector Reserved(getNumRegs());

  Reserved.set(Lanai::R0);
  Reserved.set(Lanai::R1);
  Reserved.set(Lanai::PC);
  Reserved.set(Lanai::R2);
  Reserved.set(Lanai::SP);
  Reserved.set(Lanai::R4);
  Reserved.set(Lanai::FP);
  Reserved.set(Lanai::R5);
  Reserved.set(Lanai::RR1);
  Reserved.set(Lanai::R10);
  Reserved.set(Lanai::RR2);
  Reserved.set(Lanai::R11);
  Reserved.set(Lanai::RCA);
  Reserved.set(Lanai::R15);
  if (hasBasePointer(MF))
    Reserved.set(getBaseRegister());
  return Reserved;
}

bool LanaiRegisterInfo::requiresRegisterScavenging(
    const MachineFunction & /*MF*/) const {
  return true;
}

bool LanaiRegisterInfo::trackLivenessAfterRegAlloc(
    const MachineFunction & /*MF*/) const {
  return true;
}

static bool isALUArithLoOpcode(unsigned Opcode) {
  switch (Opcode) {
  case Lanai::ADD_I_LO:
  case Lanai::SUB_I_LO:
  case Lanai::ADD_F_I_LO:
  case Lanai::SUB_F_I_LO:
  case Lanai::ADDC_I_LO:
  case Lanai::SUBB_I_LO:
  case Lanai::ADDC_F_I_LO:
  case Lanai::SUBB_F_I_LO:
    return true;
  default:
    return false;
  }
}

static unsigned getOppositeALULoOpcode(unsigned Opcode) {
  switch (Opcode) {
  case Lanai::ADD_I_LO:
    return Lanai::SUB_I_LO;
  case Lanai::SUB_I_LO:
    return Lanai::ADD_I_LO;
  case Lanai::ADD_F_I_LO:
    return Lanai::SUB_F_I_LO;
  case Lanai::SUB_F_I_LO:
    return Lanai::ADD_F_I_LO;
  case Lanai::ADDC_I_LO:
    return Lanai::SUBB_I_LO;
  case Lanai::SUBB_I_LO:
    return Lanai::ADDC_I_LO;
  case Lanai::ADDC_F_I_LO:
    return Lanai::SUBB_F_I_LO;
  case Lanai::SUBB_F_I_LO:
    return Lanai::ADDC_F_I_LO;
  default:
    llvm_unreachable("Invalid ALU lo opcode");
  }
}

static unsigned getRRMOpcodeVariant(unsigned Opcode) {
  switch (Opcode) {
  case Lanai::LDBs_RI:
    return Lanai::LDBs_RR;
  case Lanai::LDBz_RI:
    return Lanai::LDBz_RR;
  case Lanai::LDHs_RI:
    return Lanai::LDHs_RR;
  case Lanai::LDHz_RI:
    return Lanai::LDHz_RR;
  case Lanai::LDW_RI:
    return Lanai::LDW_RR;
  case Lanai::STB_RI:
    return Lanai::STB_RR;
  case Lanai::STH_RI:
    return Lanai::STH_RR;
  case Lanai::SW_RI:
    return Lanai::SW_RR;
  default:
    llvm_unreachable("Opcode has no RRM variant");
  }
}

void LanaiRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
                                            int SPAdj, unsigned FIOperandNum,
                                            RegScavenger *RS) const {
  assert(SPAdj == 0 && "Unexpected");

  MachineInstr &MI = *II;
  MachineFunction &MF = *MI.getParent()->getParent();
  const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
  const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
  bool HasFP = TFI->hasFP(MF);
  DebugLoc DL = MI.getDebugLoc();

  int FrameIndex = MI.getOperand(FIOperandNum).getIndex();

  int Offset = MF.getFrameInfo().getObjectOffset(FrameIndex) +
               MI.getOperand(FIOperandNum + 1).getImm();

  // Addressable stack objects are addressed using neg. offsets from fp
  // or pos. offsets from sp/basepointer
  if (!HasFP || (needsStackRealignment(MF) && FrameIndex >= 0))
    Offset += MF.getFrameInfo().getStackSize();

  unsigned FrameReg = getFrameRegister(MF);
  if (FrameIndex >= 0) {
    if (hasBasePointer(MF))
      FrameReg = getBaseRegister();
    else if (needsStackRealignment(MF))
      FrameReg = Lanai::SP;
  }

  // Replace frame index with a frame pointer reference.
  // If the offset is small enough to fit in the immediate field, directly
  // encode it.
  // Otherwise scavenge a register and encode it into a MOVHI, OR_I_LO sequence.
  if ((isSPLSOpcode(MI.getOpcode()) && !isInt<10>(Offset)) ||
      !isInt<16>(Offset)) {
    assert(RS && "Register scavenging must be on");
    unsigned Reg = RS->FindUnusedReg(&Lanai::GPRRegClass);
    if (!Reg)
      Reg = RS->scavengeRegister(&Lanai::GPRRegClass, II, SPAdj);
    assert(Reg && "Register scavenger failed");

    bool HasNegOffset = false;
    // ALU ops have unsigned immediate values. If the Offset is negative, we
    // negate it here and reverse the opcode later.
    if (Offset < 0) {
      HasNegOffset = true;
      Offset = -Offset;
    }

    if (!isInt<16>(Offset)) {
      BuildMI(*MI.getParent(), II, DL, TII->get(Lanai::MOVHI), Reg)
          .addImm(static_cast<uint32_t>(Offset) >> 16);
      BuildMI(*MI.getParent(), II, DL, TII->get(Lanai::OR_I_LO), Reg)
          .addReg(Reg)
          .addImm(Offset & 0xffffU);
    } else {
      BuildMI(*MI.getParent(), II, DL, TII->get(Lanai::ADD_I_LO), Reg)
          .addImm(0)
          .addImm(Offset);
    }
    // Reg = FrameReg OP Reg
    if (MI.getOpcode() == Lanai::ADD_I_LO) {
      BuildMI(*MI.getParent(), II, DL,
              HasNegOffset ? TII->get(Lanai::SUB_R) : TII->get(Lanai::ADD_R),
              MI.getOperand(0).getReg())
          .addReg(FrameReg)
          .addReg(Reg)
          .addImm(LPCC::ICC_T);
      MI.eraseFromParent();
      return;
    }
    if (isSPLSOpcode(MI.getOpcode()) || isRMOpcode(MI.getOpcode())) {
      MI.setDesc(TII->get(getRRMOpcodeVariant(MI.getOpcode())));
      if (HasNegOffset) {
        // Change the ALU op (operand 3) from LPAC::ADD (the default) to
        // LPAC::SUB with the already negated offset.
        assert((MI.getOperand(3).getImm() == LPAC::ADD) &&
               "Unexpected ALU op in RRM instruction");
        MI.getOperand(3).setImm(LPAC::SUB);
      }
    } else
      llvm_unreachable("Unexpected opcode in frame index operation");

    MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, /*isDef=*/false);
    MI.getOperand(FIOperandNum + 1)
        .ChangeToRegister(Reg, /*isDef=*/false, /*isImp=*/false,
                          /*isKill=*/true);
    return;
  }

  // ALU arithmetic ops take unsigned immediates. If the offset is negative,
  // we replace the instruction with one that inverts the opcode and negates
  // the immediate.
  if ((Offset < 0) && isALUArithLoOpcode(MI.getOpcode())) {
    unsigned NewOpcode = getOppositeALULoOpcode(MI.getOpcode());
    // We know this is an ALU op, so we know the operands are as follows:
    BuildMI(*MI.getParent(), II, DL, TII->get(NewOpcode),
            MI.getOperand(0).getReg())
        .addReg(FrameReg)
        .addImm(-Offset);
    MI.eraseFromParent();
  } else {
    MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, /*isDef=*/false);
    MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset);
  }
}

bool LanaiRegisterInfo::hasBasePointer(const MachineFunction &MF) const {
  const MachineFrameInfo &MFI = MF.getFrameInfo();
  // When we need stack realignment and there are dynamic allocas, we can't
  // reference off of the stack pointer, so we reserve a base pointer.
  if (needsStackRealignment(MF) && MFI.hasVarSizedObjects())
    return true;

  return false;
}

unsigned LanaiRegisterInfo::getRARegister() const { return Lanai::RCA; }

{
  return Lanai::FP;
}

Register LanaiRegisterInfo::getBaseRegister() const { return Lanai::R14; }

const uint32_t *
LanaiRegisterInfo::getCallPreservedMask(const MachineFunction & /*MF*/,
                                        CallingConv::ID /*CC*/) const {
  return CSR_RegMask;
}


//===-- LanaiRegisterInfo.cpp - Lanai Register Information ------*- C++ -*-===//
// This file contains the Lanai implementation of the TargetRegisterInfo class.

#include "LanaiRegisterInfo.h"
#include "LanaiAluCode.h"
#include "LanaiCondCode.h"
#include "LanaiFrameLowering.h"
#include "LanaiInstrInfo.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/CodeGen/TargetFrameLowering.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Type.h"
#include "llvm/Support/ErrorHandling.h"

#define GET_REGINFO_TARGET_DESC
#include "LanaiGenRegisterInfo.inc"

using namespace llvm;

LanaiRegisterInfo::LanaiRegisterInfo() : LanaiGenRegisterInfo(Lanai::RCA) {}

const uint16_t *
LanaiRegisterInfo::getCalleeSavedRegs(const MachineFunction * /*MF*/) const {
  return CSR_SaveList;
}

BitVector LanaiRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
  BitVector Reserved(getNumRegs());

  Reserved.set(Lanai::R0);
  Reserved.set(Lanai::R1);
  Reserved.set(Lanai::PC);
  Reserved.set(Lanai::R2);
  Reserved.set(Lanai::SP);
  Reserved.set(Lanai::R4);
  Reserved.set(Lanai::FP);
  Reserved.set(Lanai::R5);
  Reserved.set(Lanai::RR1);
  Reserved.set(Lanai::R10);
  Reserved.set(Lanai::RR2);
  Reserved.set(Lanai::R11);
  Reserved.set(Lanai::RCA);
  Reserved.set(Lanai::R15);
  if (hasBasePointer(MF))
    Reserved.set(getBaseRegister());
  return Reserved;
}

bool LanaiRegisterInfo::requiresRegisterScavenging(
    const MachineFunction & /*MF*/) const {
  return true;
}

bool LanaiRegisterInfo::trackLivenessAfterRegAlloc(
    const MachineFunction & /*MF*/) const {
  return true;
}

static bool isALUArithLoOpcode(unsigned Opcode) {
  switch (Opcode) {
  case Lanai::ADD_I_LO:
  case Lanai::SUB_I_LO:
  case Lanai::ADD_F_I_LO:
  case Lanai::SUB_F_I_LO:
  case Lanai::ADDC_I_LO:
  case Lanai::SUBB_I_LO:
  case Lanai::ADDC_F_I_LO:
  case Lanai::SUBB_F_I_LO:
    return true;
  default:
    return false;
  }
}

static unsigned getOppositeALULoOpcode(unsigned Opcode) {
  switch (Opcode) {
  case Lanai::ADD_I_LO:
    return Lanai::SUB_I_LO;
  case Lanai::SUB_I_LO:
    return Lanai::ADD_I_LO;
  case Lanai::ADD_F_I_LO:
    return Lanai::SUB_F_I_LO;
  case Lanai::SUB_F_I_LO:
    return Lanai::ADD_F_I_LO;
  case Lanai::ADDC_I_LO:
    return Lanai::SUBB_I_LO;
  case Lanai::SUBB_I_LO:
    return Lanai::ADDC_I_LO;
  case Lanai::ADDC_F_I_LO:
    return Lanai::SUBB_F_I_LO;
  case Lanai::SUBB_F_I_LO:
    return Lanai::ADDC_F_I_LO;
  default:
    llvm_unreachable("Invalid ALU lo opcode");
  }
}

static unsigned getRRMOpcodeVariant(unsigned Opcode) {
  switch (Opcode) {
  case Lanai::LDBs_RI:
    return Lanai::LDBs_RR;
  case Lanai::LDBz_RI:
    return Lanai::LDBz_RR;
  case Lanai::LDHs_RI:
    return Lanai::LDHs_RR;
  case Lanai::LDHz_RI:
    return Lanai::LDHz_RR;
  case Lanai::LDW_RI:
    return Lanai::LDW_RR;
  case Lanai::STB_RI:
    return Lanai::STB_RR;
  case Lanai::STH_RI:
    return Lanai::STH_RR;
  case Lanai::SW_RI:
    return Lanai::SW_RR;
  default:
    llvm_unreachable("Opcode has no RRM variant");
  }
}

void LanaiRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
                                            int SPAdj, unsigned FIOperandNum,
                                            RegScavenger *RS) const {
  assert(SPAdj == 0 && "Unexpected");

  MachineInstr &MI = *II;
  MachineFunction &MF = *MI.getParent()->getParent();
  const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
  const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
  bool HasFP = TFI->hasFP(MF);
  DebugLoc DL = MI.getDebugLoc();

  int FrameIndex = MI.getOperand(FIOperandNum).getIndex();

  int Offset = MF.getFrameInfo().getObjectOffset(FrameIndex) +
               MI.getOperand(FIOperandNum + 1).getImm();

  // Addressable stack objects are addressed using neg. offsets from fp
  // or pos. offsets from sp/basepointer
  if (!HasFP || (needsStackRealignment(MF) && FrameIndex >= 0))
    Offset += MF.getFrameInfo().getStackSize();

  unsigned FrameReg = getFrameRegister(MF);
  if (FrameIndex >= 0) {
    if (hasBasePointer(MF))
      FrameReg = getBaseRegister();
    else if (needsStackRealignment(MF))
      FrameReg = Lanai::SP;
  }

  // Replace frame index with a frame pointer reference.
  // If the offset is small enough to fit in the immediate field, directly
  // encode it.
  // Otherwise scavenge a register and encode it into a MOVHI, OR_I_LO sequence.
  if ((isSPLSOpcode(MI.getOpcode()) && !isInt<10>(Offset)) ||
      !isInt<16>(Offset)) {
    assert(RS && "Register scavenging must be on");
    unsigned Reg = RS->FindUnusedReg(&Lanai::GPRRegClass);
    if (!Reg)
      Reg = RS->scavengeRegister(&Lanai::GPRRegClass, II, SPAdj);
    assert(Reg && "Register scavenger failed");

    bool HasNegOffset = false;
    // ALU ops have unsigned immediate values. If the Offset is negative, we
    // negate it here and reverse the opcode later.
    if (Offset < 0) {
      HasNegOffset = true;
      Offset = -Offset;
    }

    if (!isInt<16>(Offset)) {
      BuildMI(*MI.getParent(), II, DL, TII->get(Lanai::MOVHI), Reg)
          .addImm(static_cast<uint32_t>(Offset) >> 16);
      BuildMI(*MI.getParent(), II, DL, TII->get(Lanai::OR_I_LO), Reg)
          .addReg(Reg)
          .addImm(Offset & 0xffffU);
    } else {
      BuildMI(*MI.getParent(), II, DL, TII->get(Lanai::ADD_I_LO), Reg)
          .addImm(0)
          .addImm(Offset);
    }
    // Reg = FrameReg OP Reg
    if (MI.getOpcode() == Lanai::ADD_I_LO) {
      BuildMI(*MI.getParent(), II, DL,
              HasNegOffset ? TII->get(Lanai::SUB_R) : TII->get(Lanai::ADD_R),
              MI.getOperand(0).getReg())
          .addReg(FrameReg)
          .addReg(Reg)
          .addImm(LPCC::ICC_T);
      MI.eraseFromParent();
      return;
    }
    if (isSPLSOpcode(MI.getOpcode()) || isRMOpcode(MI.getOpcode())) {
      MI.setDesc(TII->get(getRRMOpcodeVariant(MI.getOpcode())));
      if (HasNegOffset) {
        // Change the ALU op (operand 3) from LPAC::ADD (the default) to
        // LPAC::SUB with the already negated offset.
        assert((MI.getOperand(3).getImm() == LPAC::ADD) &&
               "Unexpected ALU op in RRM instruction");
        MI.getOperand(3).setImm(LPAC::SUB);
      }
    } else
      llvm_unreachable("Unexpected opcode in frame index operation");

    MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, /*isDef=*/false);
    MI.getOperand(FIOperandNum + 1)
        .ChangeToRegister(Reg, /*isDef=*/false, /*isImp=*/false,
                          /*isKill=*/true);
    return;
  }

  // ALU arithmetic ops take unsigned immediates. If the offset is negative,
  // we replace the instruction with one that inverts the opcode and negates
  // the immediate.
  if ((Offset < 0) && isALUArithLoOpcode(MI.getOpcode())) {
    unsigned NewOpcode = getOppositeALULoOpcode(MI.getOpcode());
    // We know this is an ALU op, so we know the operands are as follows:
    BuildMI(*MI.getParent(), II, DL, TII->get(NewOpcode),
            MI.getOperand(0).getReg())
        .addReg(FrameReg)
        .addImm(-Offset);
    MI.eraseFromParent();
  } else {
    MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, /*isDef=*/false);
    MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset);
  }
}

bool LanaiRegisterInfo::hasBasePointer(const MachineFunction &MF) const {
  const MachineFrameInfo &MFI = MF.getFrameInfo();
  // When we need stack realignment and there are dynamic allocas, we can't
  // reference off of the stack pointer, so we reserve a base pointer.
  if (needsStackRealignment(MF) && MFI.hasVarSizedObjects())
    return true;

  return false;
}

unsigned LanaiRegisterInfo::getRARegister() const { return Lanai::RCA; }

Register
LanaiRegisterInfo::getFrameRegister(const MachineFunction & /*MF*/) const

Register LanaiRegisterInfo::getBaseRegister() const { return Lanai::R14; }

const uint32_t *
LanaiRegisterInfo::getCallPreservedMask(const MachineFunction & /*MF*/,
                                        CallingConv::ID /*CC*/) const {
  return CSR_RegMask;
}


//===-- LanaiRegisterInfo.cpp - Lanai Register Information ------*- C++ -*-===//
// This file contains the Lanai implementation of the TargetRegisterInfo class.

#include "LanaiRegisterInfo.h"
#include "LanaiAluCode.h"
#include "LanaiCondCode.h"
#include "LanaiFrameLowering.h"
#include "LanaiInstrInfo.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/CodeGen/TargetFrameLowering.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Type.h"
#include "llvm/Support/ErrorHandling.h"

#define GET_REGINFO_TARGET_DESC
#include "LanaiGenRegisterInfo.inc"

using namespace llvm;

LanaiRegisterInfo::LanaiRegisterInfo() : LanaiGenRegisterInfo(Lanai::RCA) {}

const uint16_t *
LanaiRegisterInfo::getCalleeSavedRegs(const MachineFunction * /*MF*/) const {
  return CSR_SaveList;
}

BitVector LanaiRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
  BitVector Reserved(getNumRegs());

  Reserved.set(Lanai::R0);
  Reserved.set(Lanai::R1);
  Reserved.set(Lanai::PC);
  Reserved.set(Lanai::R2);
  Reserved.set(Lanai::SP);
  Reserved.set(Lanai::R4);
  Reserved.set(Lanai::FP);
  Reserved.set(Lanai::R5);
  Reserved.set(Lanai::RR1);
  Reserved.set(Lanai::R10);
  Reserved.set(Lanai::RR2);
  Reserved.set(Lanai::R11);
  Reserved.set(Lanai::RCA);
  Reserved.set(Lanai::R15);
  if (hasBasePointer(MF))
    Reserved.set(getBaseRegister());
  return Reserved;
}

bool LanaiRegisterInfo::requiresRegisterScavenging(
    const MachineFunction & /*MF*/) const {
  return true;
}

bool LanaiRegisterInfo::trackLivenessAfterRegAlloc(
    const MachineFunction & /*MF*/) const {
  return true;
}

static bool isALUArithLoOpcode(unsigned Opcode)

  switch (Opcode) {
  case Lanai::ADD_I_LO:
  case Lanai::SUB_I_LO:
  case Lanai::ADD_F_I_LO:
  case Lanai::SUB_F_I_LO:
  case Lanai::ADDC_I_LO:
  case Lanai::SUBB_I_LO:
  case Lanai::ADDC_F_I_LO:
  case Lanai::SUBB_F_I_LO:
    return true;
  default:
    return false;
  }
}

static unsigned getOppositeALULoOpcode(unsigned Opcode) {
  switch (Opcode) {
  case Lanai::ADD_I_LO:
    return Lanai::SUB_I_LO;
  case Lanai::SUB_I_LO:
    return Lanai::ADD_I_LO;
  case Lanai::ADD_F_I_LO:
    return Lanai::SUB_F_I_LO;
  case Lanai::SUB_F_I_LO:
    return Lanai::ADD_F_I_LO;
  case Lanai::ADDC_I_LO:
    return Lanai::SUBB_I_LO;
  case Lanai::SUBB_I_LO:
    return Lanai::ADDC_I_LO;
  case Lanai::ADDC_F_I_LO:
    return Lanai::SUBB_F_I_LO;
  case Lanai::SUBB_F_I_LO:
    return Lanai::ADDC_F_I_LO;
  default:
    llvm_unreachable("Invalid ALU lo opcode");
  }
}

static unsigned getRRMOpcodeVariant(unsigned Opcode) {
  switch (Opcode) {
  case Lanai::LDBs_RI:
    return Lanai::LDBs_RR;
  case Lanai::LDBz_RI:
    return Lanai::LDBz_RR;
  case Lanai::LDHs_RI:
    return Lanai::LDHs_RR;
  case Lanai::LDHz_RI:
    return Lanai::LDHz_RR;
  case Lanai::LDW_RI:
    return Lanai::LDW_RR;
  case Lanai::STB_RI:
    return Lanai::STB_RR;
  case Lanai::STH_RI:
    return Lanai::STH_RR;
  case Lanai::SW_RI:
    return Lanai::SW_RR;
  default:
    llvm_unreachable("Opcode has no RRM variant");
  }
}

void LanaiRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
                                            int SPAdj, unsigned FIOperandNum,
                                            RegScavenger *RS) const {
  assert(SPAdj == 0 && "Unexpected");

  MachineInstr &MI = *II;
  MachineFunction &MF = *MI.getParent()->getParent();
  const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
  const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
  bool HasFP = TFI->hasFP(MF);
  DebugLoc DL = MI.getDebugLoc();

  int FrameIndex = MI.getOperand(FIOperandNum).getIndex();

  int Offset = MF.getFrameInfo().getObjectOffset(FrameIndex) +
               MI.getOperand(FIOperandNum + 1).getImm();

  // Addressable stack objects are addressed using neg. offsets from fp
  // or pos. offsets from sp/basepointer
  if (!HasFP || (needsStackRealignment(MF) && FrameIndex >= 0))
    Offset += MF.getFrameInfo().getStackSize();

  unsigned FrameReg = getFrameRegister(MF);
  if (FrameIndex >= 0) {
    if (hasBasePointer(MF))
      FrameReg = getBaseRegister();
    else if (needsStackRealignment(MF))
      FrameReg = Lanai::SP;
  }

  // Replace frame index with a frame pointer reference.
  // If the offset is small enough to fit in the immediate field, directly
  // encode it.
  // Otherwise scavenge a register and encode it into a MOVHI, OR_I_LO sequence.
  if ((isSPLSOpcode(MI.getOpcode()) && !isInt<10>(Offset)) ||
      !isInt<16>(Offset)) {
    assert(RS && "Register scavenging must be on");
    unsigned Reg = RS->FindUnusedReg(&Lanai::GPRRegClass);
    if (!Reg)
      Reg = RS->scavengeRegister(&Lanai::GPRRegClass, II, SPAdj);
    assert(Reg && "Register scavenger failed");

    bool HasNegOffset = false;
    // ALU ops have unsigned immediate values. If the Offset is negative, we
    // negate it here and reverse the opcode later.
    if (Offset < 0) {
      HasNegOffset = true;
      Offset = -Offset;
    }

    if (!isInt<16>(Offset)) {
      BuildMI(*MI.getParent(), II, DL, TII->get(Lanai::MOVHI), Reg)
          .addImm(static_cast<uint32_t>(Offset) >> 16);
      BuildMI(*MI.getParent(), II, DL, TII->get(Lanai::OR_I_LO), Reg)
          .addReg(Reg)
          .addImm(Offset & 0xffffU);
    } else {
      BuildMI(*MI.getParent(), II, DL, TII->get(Lanai::ADD_I_LO), Reg)
          .addImm(0)
          .addImm(Offset);
    }
    // Reg = FrameReg OP Reg
    if (MI.getOpcode() == Lanai::ADD_I_LO) {
      BuildMI(*MI.getParent(), II, DL,
              HasNegOffset ? TII->get(Lanai::SUB_R) : TII->get(Lanai::ADD_R),
              MI.getOperand(0).getReg())
          .addReg(FrameReg)
          .addReg(Reg)
          .addImm(LPCC::ICC_T);
      MI.eraseFromParent();
      return;
    }
    if (isSPLSOpcode(MI.getOpcode()) || isRMOpcode(MI.getOpcode())) {
      MI.setDesc(TII->get(getRRMOpcodeVariant(MI.getOpcode())));
      if (HasNegOffset) {
        // Change the ALU op (operand 3) from LPAC::ADD (the default) to
        // LPAC::SUB with the already negated offset.
        assert((MI.getOperand(3).getImm() == LPAC::ADD) &&
               "Unexpected ALU op in RRM instruction");
        MI.getOperand(3).setImm(LPAC::SUB);
      }
    } else
      llvm_unreachable("Unexpected opcode in frame index operation");

    MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, /*isDef=*/false);
    MI.getOperand(FIOperandNum + 1)
        .ChangeToRegister(Reg, /*isDef=*/false, /*isImp=*/false,
                          /*isKill=*/true);
    return;
  }

  // ALU arithmetic ops take unsigned immediates. If the offset is negative,
  // we replace the instruction with one that inverts the opcode and negates
  // the immediate.
  if ((Offset < 0) && isALUArithLoOpcode(MI.getOpcode())) {
    unsigned NewOpcode = getOppositeALULoOpcode(MI.getOpcode());
    // We know this is an ALU op, so we know the operands are as follows:
    BuildMI(*MI.getParent(), II, DL, TII->get(NewOpcode),
            MI.getOperand(0).getReg())
        .addReg(FrameReg)
        .addImm(-Offset);
    MI.eraseFromParent();
  } else {
    MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, /*isDef=*/false);
    MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset);
  }
}

bool LanaiRegisterInfo::hasBasePointer(const MachineFunction &MF) const {
  const MachineFrameInfo &MFI = MF.getFrameInfo();
  // When we need stack realignment and there are dynamic allocas, we can't
  // reference off of the stack pointer, so we reserve a base pointer.
  if (needsStackRealignment(MF) && MFI.hasVarSizedObjects())
    return true;

  return false;
}

unsigned LanaiRegisterInfo::getRARegister() const { return Lanai::RCA; }

Register
LanaiRegisterInfo::getFrameRegister(const MachineFunction & /*MF*/) const {
  return Lanai::FP;
}

Register LanaiRegisterInfo::getBaseRegister() const { return Lanai::R14; }

const uint32_t *
LanaiRegisterInfo::getCallPreservedMask(const MachineFunction & /*MF*/,
                                        CallingConv::ID /*CC*/) const {
  return CSR_RegMask;
}


switch (Opcode) {
  case Lanai::ADD_I_LO:
  case Lanai::SUB_I_LO:
  case Lanai::ADD_F_I_LO:
  case Lanai::SUB_F_I_LO:
  case Lanai::ADDC_I_LO:
  case Lanai::SUBB_I_LO:
  case Lanai::ADDC_F_I_LO:
  case Lanai::SUBB_F_I_LO:
    return true;
  default:
    return false;
  }

//===-- LanaiRegisterInfo.cpp - Lanai Register Information ------*- C++ -*-===//
// This file contains the Lanai implementation of the TargetRegisterInfo class.

#include "LanaiRegisterInfo.h"
#include "LanaiAluCode.h"
#include "LanaiCondCode.h"
#include "LanaiFrameLowering.h"
#include "LanaiInstrInfo.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/CodeGen/TargetFrameLowering.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Type.h"
#include "llvm/Support/ErrorHandling.h"

#define GET_REGINFO_TARGET_DESC
#include "LanaiGenRegisterInfo.inc"

using namespace llvm;

LanaiRegisterInfo::LanaiRegisterInfo() : LanaiGenRegisterInfo(Lanai::RCA) {}

const uint16_t *
LanaiRegisterInfo::getCalleeSavedRegs(const MachineFunction * /*MF*/) const {
  return CSR_SaveList;
}

BitVector LanaiRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
  BitVector Reserved(getNumRegs());

  Reserved.set(Lanai::R0);
  Reserved.set(Lanai::R1);
  Reserved.set(Lanai::PC);
  Reserved.set(Lanai::R2);
  Reserved.set(Lanai::SP);
  Reserved.set(Lanai::R4);
  Reserved.set(Lanai::FP);
  Reserved.set(Lanai::R5);
  Reserved.set(Lanai::RR1);
  Reserved.set(Lanai::R10);
  Reserved.set(Lanai::RR2);
  Reserved.set(Lanai::R11);
  Reserved.set(Lanai::RCA);
  Reserved.set(Lanai::R15);
  if (hasBasePointer(MF))
    Reserved.set(getBaseRegister());
  return Reserved;
}

bool LanaiRegisterInfo::requiresRegisterScavenging(
    const MachineFunction & /*MF*/) const {
  return true;
}

bool LanaiRegisterInfo::trackLivenessAfterRegAlloc(
    const MachineFunction & /*MF*/) const {
  return true;
}

static bool isALUArithLoOpcode(unsigned Opcode) {

}

static unsigned getOppositeALULoOpcode(unsigned Opcode) {
  switch (Opcode) {
  case Lanai::ADD_I_LO:
    return Lanai::SUB_I_LO;
  case Lanai::SUB_I_LO:
    return Lanai::ADD_I_LO;
  case Lanai::ADD_F_I_LO:
    return Lanai::SUB_F_I_LO;
  case Lanai::SUB_F_I_LO:
    return Lanai::ADD_F_I_LO;
  case Lanai::ADDC_I_LO:
    return Lanai::SUBB_I_LO;
  case Lanai::SUBB_I_LO:
    return Lanai::ADDC_I_LO;
  case Lanai::ADDC_F_I_LO:
    return Lanai::SUBB_F_I_LO;
  case Lanai::SUBB_F_I_LO:
    return Lanai::ADDC_F_I_LO;
  default:
    llvm_unreachable("Invalid ALU lo opcode");
  }
}

static unsigned getRRMOpcodeVariant(unsigned Opcode) {
  switch (Opcode) {
  case Lanai::LDBs_RI:
    return Lanai::LDBs_RR;
  case Lanai::LDBz_RI:
    return Lanai::LDBz_RR;
  case Lanai::LDHs_RI:
    return Lanai::LDHs_RR;
  case Lanai::LDHz_RI:
    return Lanai::LDHz_RR;
  case Lanai::LDW_RI:
    return Lanai::LDW_RR;
  case Lanai::STB_RI:
    return Lanai::STB_RR;
  case Lanai::STH_RI:
    return Lanai::STH_RR;
  case Lanai::SW_RI:
    return Lanai::SW_RR;
  default:
    llvm_unreachable("Opcode has no RRM variant");
  }
}

void LanaiRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
                                            int SPAdj, unsigned FIOperandNum,
                                            RegScavenger *RS) const {
  assert(SPAdj == 0 && "Unexpected");

  MachineInstr &MI = *II;
  MachineFunction &MF = *MI.getParent()->getParent();
  const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
  const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
  bool HasFP = TFI->hasFP(MF);
  DebugLoc DL = MI.getDebugLoc();

  int FrameIndex = MI.getOperand(FIOperandNum).getIndex();

  int Offset = MF.getFrameInfo().getObjectOffset(FrameIndex) +
               MI.getOperand(FIOperandNum + 1).getImm();

  // Addressable stack objects are addressed using neg. offsets from fp
  // or pos. offsets from sp/basepointer
  if (!HasFP || (needsStackRealignment(MF) && FrameIndex >= 0))
    Offset += MF.getFrameInfo().getStackSize();

  unsigned FrameReg = getFrameRegister(MF);
  if (FrameIndex >= 0) {
    if (hasBasePointer(MF))
      FrameReg = getBaseRegister();
    else if (needsStackRealignment(MF))
      FrameReg = Lanai::SP;
  }

  // Replace frame index with a frame pointer reference.
  // If the offset is small enough to fit in the immediate field, directly
  // encode it.
  // Otherwise scavenge a register and encode it into a MOVHI, OR_I_LO sequence.
  if ((isSPLSOpcode(MI.getOpcode()) && !isInt<10>(Offset)) ||
      !isInt<16>(Offset)) {
    assert(RS && "Register scavenging must be on");
    unsigned Reg = RS->FindUnusedReg(&Lanai::GPRRegClass);
    if (!Reg)
      Reg = RS->scavengeRegister(&Lanai::GPRRegClass, II, SPAdj);
    assert(Reg && "Register scavenger failed");

    bool HasNegOffset = false;
    // ALU ops have unsigned immediate values. If the Offset is negative, we
    // negate it here and reverse the opcode later.
    if (Offset < 0) {
      HasNegOffset = true;
      Offset = -Offset;
    }

    if (!isInt<16>(Offset)) {
      BuildMI(*MI.getParent(), II, DL, TII->get(Lanai::MOVHI), Reg)
          .addImm(static_cast<uint32_t>(Offset) >> 16);
      BuildMI(*MI.getParent(), II, DL, TII->get(Lanai::OR_I_LO), Reg)
          .addReg(Reg)
          .addImm(Offset & 0xffffU);
    } else {
      BuildMI(*MI.getParent(), II, DL, TII->get(Lanai::ADD_I_LO), Reg)
          .addImm(0)
          .addImm(Offset);
    }
    // Reg = FrameReg OP Reg
    if (MI.getOpcode() == Lanai::ADD_I_LO) {
      BuildMI(*MI.getParent(), II, DL,
              HasNegOffset ? TII->get(Lanai::SUB_R) : TII->get(Lanai::ADD_R),
              MI.getOperand(0).getReg())
          .addReg(FrameReg)
          .addReg(Reg)
          .addImm(LPCC::ICC_T);
      MI.eraseFromParent();
      return;
    }
    if (isSPLSOpcode(MI.getOpcode()) || isRMOpcode(MI.getOpcode())) {
      MI.setDesc(TII->get(getRRMOpcodeVariant(MI.getOpcode())));
      if (HasNegOffset) {
        // Change the ALU op (operand 3) from LPAC::ADD (the default) to
        // LPAC::SUB with the already negated offset.
        assert((MI.getOperand(3).getImm() == LPAC::ADD) &&
               "Unexpected ALU op in RRM instruction");
        MI.getOperand(3).setImm(LPAC::SUB);
      }
    } else
      llvm_unreachable("Unexpected opcode in frame index operation");

    MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, /*isDef=*/false);
    MI.getOperand(FIOperandNum + 1)
        .ChangeToRegister(Reg, /*isDef=*/false, /*isImp=*/false,
                          /*isKill=*/true);
    return;
  }

  // ALU arithmetic ops take unsigned immediates. If the offset is negative,
  // we replace the instruction with one that inverts the opcode and negates
  // the immediate.
  if ((Offset < 0) && isALUArithLoOpcode(MI.getOpcode())) {
    unsigned NewOpcode = getOppositeALULoOpcode(MI.getOpcode());
    // We know this is an ALU op, so we know the operands are as follows:
    BuildMI(*MI.getParent(), II, DL, TII->get(NewOpcode),
            MI.getOperand(0).getReg())
        .addReg(FrameReg)
        .addImm(-Offset);
    MI.eraseFromParent();
  } else {
    MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, /*isDef=*/false);
    MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset);
  }
}

bool LanaiRegisterInfo::hasBasePointer(const MachineFunction &MF) const {
  const MachineFrameInfo &MFI = MF.getFrameInfo();
  // When we need stack realignment and there are dynamic allocas, we can't
  // reference off of the stack pointer, so we reserve a base pointer.
  if (needsStackRealignment(MF) && MFI.hasVarSizedObjects())
    return true;

  return false;
}

unsigned LanaiRegisterInfo::getRARegister() const { return Lanai::RCA; }

Register
LanaiRegisterInfo::getFrameRegister(const MachineFunction & /*MF*/) const {
  return Lanai::FP;
}

Register LanaiRegisterInfo::getBaseRegister() const { return Lanai::R14; }

const uint32_t *
LanaiRegisterInfo::getCallPreservedMask(const MachineFunction & /*MF*/,
                                        CallingConv::ID /*CC*/) const {
  return CSR_RegMask;
}