/*

  This program is part of the TACLeBench benchmark suite.
  Version V 2.0

  Name: bitonic

  Author: Chris Leger

  Function: bitonic implements a recursive sorting network algorithm.

  Source: MiBench
          http://wwweb.eecs.umich.edu/mibench

  Changes: no major functional changes

  License: MIT

*/

/*
  Forward declaration of functions
*/

// Wasm loop bounds




__attribute__((import_module("__pragma"), import_name("loopbound"))) extern void
__pragma_loopbound(unsigned int min_bound, unsigned int max_bound);

__attribute__((always_inline)) static inline void bitonic_init(void);
__attribute__((always_inline)) static inline int bitonic_return(void);
__attribute__((always_inline)) static inline void bitonic_compare(int i, int j,
                                                                  int dir);
__attribute__((always_inline)) static inline void bitonic_merge(int lo, int cnt,
                                                                int dir);
__attribute__((always_inline)) static inline void bitonic_sort(int lo, int cnt,
                                                               int dir);
__attribute__((noinline)) __attribute__((export_name("main")))
__attribute__((noinline)) __attribute__((export_name("main"))) int
main(void);

/*
  Declaration of global variables
*/

int bitonic_numiters = 10;
int bitonic_a[32];   // the array to be sorted
const int bitonic_ASCENDING = 1;
const int bitonic_DESCENDING = 0;

const int bitonic_CHECKSUM = 55;

/*
  Initialization- and return-value-related functions
*/

__attribute__((always_inline)) static inline void
bitonic_init(void) {
    /** Initialize array "a" with data **/
    int i;

    __pragma_loopbound(32, 32);
    for (i = 0; i < 32; i++)
        bitonic_a[i] = (32 - i);
}

__attribute__((always_inline)) static inline int
bitonic_return(void) {
    int checksum = 0;

    checksum += bitonic_a[0] + bitonic_a[21] + bitonic_a[31];

    return ((checksum == bitonic_CHECKSUM) ? 0 : -1);
}

/*
  Algorithm core functions
*/

/** A comparator is modelled by the procedure compare, where the
   parameter dir indicates the sorting direction. If dir is ASCENDING
   and a[i] > a[j] is true or dir is DESCENDING and a[i] > a[j] is
   false then a[i] and a[j] are interchanged.
 **/
__attribute__((always_inline)) static inline void
bitonic_compare(int i, int j, int dir) {
    if (dir == (bitonic_a[i] > bitonic_a[j])) {
        int h = bitonic_a[i];
        bitonic_a[i] = bitonic_a[j];
        bitonic_a[j] = h;
    }
}

/** The procedure bitonicMerge recursively sorts a bitonic sequence in
   ascending order, if dir = ASCENDING, and in descending order
   otherwise. The sequence to be sorted starts at index position lo,
   the number of elements is cnt.
 **/
__attribute__((always_inline)) static inline void
bitonic_merge(int lo, int cnt, int dir) {
    int k = cnt / 2;
    int i;
    __pragma_loopbound(0, 16);
    for (i = lo; i < lo + k; i++)
        bitonic_compare(i, i + k, dir);

    if (k > 1) {
        bitonic_merge(lo, k, dir);
        bitonic_merge(lo + k, k, dir);
    }
}

/** Procedure bitonicSort first produces a bitonic sequence by
   recursively sorting its two halves in opposite directions, and then
   calls bitonicMerge.
 **/
__attribute__((always_inline)) static inline void
bitonic_sort(int lo, int cnt, int dir) {
    int k = cnt;
    k /= 2;
    _Pragma("marker recMerge")

        if (cnt > 1) {
        bitonic_sort(lo, k, bitonic_ASCENDING);
        bitonic_sort(lo + k, k, bitonic_DESCENDING);
    }

    bitonic_merge(lo, cnt, dir);
    _Pragma("flowrestriction 1*bitonicMerge <= 31*recMerge")

        return;
}

/*
  Main functions
*/

__attribute__((noinline)) __attribute__((export_name("entrypoint")))
__attribute__((noinline)) __attribute__((export_name("entrypoint"))) void
bitonic_main(void) {
    int i;

    /** When called with parameters lo = 0, cnt = a.length() and dir =
      ASCENDING, procedure bitonicSort sorts the whole array a. **/
    _Pragma("marker recSort") bitonic_sort(0, 32, bitonic_ASCENDING);
    _Pragma("flowrestriction 1*bitonicSort <= 63*recSort")

        /** Loop through array, printing out each element **/
        __pragma_loopbound(32, 32);
    for (i = 0; i < 32; i++) {
    }
}

__attribute__((noinline)) __attribute__((export_name("main")))
__attribute__((noinline)) __attribute__((export_name("main"))) int
main(void) {
    bitonic_init();
    bitonic_main();

    return (bitonic_return());
}
