/* 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()); }