/* 
 * $Id: ompsm.h,v 1.56 2002/10/08 13:44:38 a-hasega Exp $
 * $RWC_Release: Omni-1.6 $
 * $RWC_Copyright:
 *  Omni Compiler Software Version 1.5-1.6
 *  Copyright (C) 2002 PC Cluster Consortium
 *  
 *  This software is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License version
 *  2.1 published by the Free Software Foundation.
 *  
 *  Omni Compiler Software Version 1.0-1.4
 *  Copyright (C) 1999, 2000, 2001.
 *   Tsukuba Research Center, Real World Computing Partnership, Japan.
 *  
 *  Please check the Copyright and License information in the files named
 *  COPYRIGHT and LICENSE under the top  directory of the Omni Compiler
 *  Software release kit.
 *  
 *  
 *  $
 */

/* RWC Omni OpenMP C compiler runtime lib.
 *  for shmem model 
 */

#ifndef _OMPSH_H
#define _OMPSH_H

#define TRUE 1
#define FALSE 0

#include "exc_platform.h"
#include "ompc_reduction.h"

#ifndef OMNI_CPU_ALPHA
#ifndef __GNUC__
#ifndef __PGI
# define asm(X) __asm(X)
#endif /* __PGI */
#else /* __GNUC__ */
# define asm(X) __asm volatile (X)
#endif /* __GNUC__ */
#endif

#ifdef USE_SCASH
#include <scash.h>
#include <scashcrt.h>
#endif /* USE_SCASH */

#define N_PROC_DEFAULT	4 	/* default */
#define MAX_PROC	64
#define MAX_DIM		16
#define OMPSM_DEFAULT_FREE_MEM_SIZE  4096 /*(1024*1024*32)*/

#ifdef USE_UNIX_SHMEM
typedef int _ompc_lock_t;	/* spin lock value */
typedef int _ompc_nest_lock_t;  /* dummy */
#endif

#ifdef USE_SCASH
typedef struct __ompc_lock_t {
  int			locknum1;
#ifndef SCASH_SUPPORT_TESTLOCK
  int			locknum2;
#endif
  int			owner;
  int			count;
  struct __ompc_lock_t	* next;
} *_ompc_lock_t, *_ompc_nest_lock_t;
#endif

#define PARALLEL_MAX_ARG 32

enum sched_kind {
    SCHED_NONE = 0, 
    SCHED_STATIC, 
    SCHED_DYNAMIC, 
    SCHED_GUIDED 
};

struct critical_lock_list {
    struct critical_lock_list *next;
    _ompc_lock_t **addr;
    _ompc_lock_t lock;
};

typedef void (*cfunc)();

/* global shared data */
struct _global_ {
    /* initial constant */
    int debug_flag;
    int runtime_chunk_size;
    enum sched_kind runtime_sched_kind;
#ifdef USE_UNIX_SHMEM
    _ompc_lock_t *atomic_lock;
    _ompc_lock_t *ordered_lock;
#endif
    
    struct critical_lock_list *critical_locks;

    /* for function invocation */
    cfunc thd_func;
    int thd_narg;
    void *thd_args[PARALLEL_MAX_ARG];

    /* global shared data */
    int gdata_n;
    void ***gdata_pp;
    void **gdata_p;

    /* for loop dynamic scheduling */
    int dynamic_index;
    int ordered_id, ordered_step;

    /* for reduction */
    any_type reduction_vals[MAX_PROC];

#ifdef USE_SCASH
    int			_ompsm_scash_locknum;
    _ompc_lock_t	free_locks;

    char		*heap_top;
    char		*heap_tail;
#endif
};

struct ompsm_thread {
  int	ompc_last_flag;
  int	ompc_loop_sched_index;
  int   ompc_loop_start;
  int	ompc_loop_end;
  int   ompc_loop_step;
  int	ompc_loop_chunk_size;
  int	ompc_loop_stride;
  int	ompc_loop_id;
  int	ompc_section_indx;
  int	ompc_last_section_indx;
};

extern struct _global_		*__G__;

extern struct ompsm_thread	*_ompsm_thread;

extern int _ompsm_gdata_size;
extern int _ompsm_gdata_count;
extern int _ompsm_free_shmem_size;
#ifdef USE_SCASH
extern int _scash_args_size;
#endif


/*
 * non-nested thread management
 */
extern int _ompc_n_node;
extern int _ompc_node_id;
#define IS_MASTER_NODE (_ompc_node_id == 0)
#define IS_MASTER_THREAD (IS_MASTER_NODE || (IN_NESTED_PARALLEL))

extern int _ompc_debug_flag;
extern int _ompc_in_parallel;		/* parallel nest level */
extern int _ompc_serialized_count;	/* parallel_if(false) count */
#define NESTING_COUNT		(_ompc_in_parallel + _ompc_serialized_count)
#define IN_PARALLEL		(_ompc_in_parallel != 0)
#define NOT_IN_PARALLEL		(_ompc_in_parallel == 0)
#define IN_NESTED_PARALLEL	(1<(NESTING_COUNT))

extern volatile int _ompc_nested;	/* nested enable/disable */
extern volatile int _ompc_dynamic;	/* dynamic enable/disable */
extern volatile int _ompc_max_threads;	/* max number of thread */
extern int _ompc_num_threads;
extern int _ompc_n_proc;

extern enum sched_kind	_ompc_runtime_sched_kind;
extern int		_ompc_runtime_chunk_size; /* default */
extern _ompc_lock_t	*_ompc_atomic_lock_p;
extern _ompc_lock_t	*_ompc_ordered_lock_p;

/* distribution, only on SCASH */
#define MAP_NONE	0	/* default mapping */
#define MAP_EXPR	1
#define MAP_BLOCK	2
#define MAP_CYCLIC	3

struct data_map_entry {
    void **p;
    int offset;
    int size;
    int n_dim;
    int dim_size[MAX_DIM];
    int dist_dim,dist_mode,dist_blk_size,dist_scale,dist_offset;
};

void _ompc_fatal(char *msg);
void _ompc_init(int argc,char *argv[]);

void _ompsm_slave_main(void);
void _ompsm_init(int argc,char *argv[]);
void _ompsm_allocate_global_data (void);
void _ompc_do_parallel(cfunc, void **, int);
void _ompc_terminate (int);

#ifdef USE_UNIX_SHMEM   /* for unix shmem */
void _ompsm_shmem_init_lock(_ompc_lock_t *lp);

#define OMPSM_INIT(argc,argv)		_ompsm_shmem_init(argc,argv)
#define OMPSM_TERMINATE(exitcode)	exit(exitcode)
#define OMPSM_BARRIER() 		_ompsm_shmem_barrier()
#define OMPSM_MASTER_BEGIN()		_ompsm_shmem_master_begin()
#define OMPSM_MASTER_END()  		_ompsm_shmem_master_end()
#define OMPSM_SLAVE_BEGIN()		_ompsm_shmem_slave_begin()
#define OMPSM_SLAVE_END()		_ompsm_shmem_slave_end()
#define OMPSM_FINALIZE()		_ompsm_shmem_finalize()
#define OMPSM_ALLOC(size)		_ompsm_shmem_alloc(size)
#define OMPSM_GALLOC(size,mode,arg)	_ompsm_shmem_alloc(size)
#define OMPSM_ALIGN_SIZE(size)		_ompsm_shmem_align_size(size)
#define OMPSM_ALIGN_ADDR(size)		_ompsm_shmem_align_addr(addr)
#define OMPSM_ALLOCA(size)		_ompsm_shmem_alloca(size)
#define OMPSM_FREEA(p,size)		_ompsm_shmem_freea(p,size)
#define OMPSM_IS_SHARED(p)  		_ompsm_shmem_is_shared(p)
#define OMPSM_LOOP_IN_LOCK0() 		_ompsm_shmem_loop_in_lock0()
#define OMPSM_LOOP_OUT() 		_ompsm_shmem_loop_out()
#define OMPSM_COUNT_LOCK0() 		_ompsm_shmem_count_lock0()
#define OMPSM_LOCK0() 			_ompsm_shmem_lock0()
#define OMPSM_UNLOCK0() 		_ompsm_shmem_unlock0()
#define OMPSM_LOCK(lp)			_ompsm_shmem_lock(lp)
#define OMPSM_UNLOCK(lp)		_ompsm_shmem_unlock(lp)
#define OMPSM_WAIT(cond) while(cond)	/**/
#define OMPSM_ALLOC_LOCK()		((_ompc_lock_t *)_ompsm_shmem_alloc(sizeof(int)))
#define OMPSM_FLUSH(addr,sz)		_ompsm_shmem_flush()
#define OMPSM_FLUSH_VAR(addr,sz)	_ompsm_shmem_flush()
#define OMPSM_FLUSH_ALL()		_ompsm_shmem_flush()
#define OMPSM_REFRESH_VAR(addr,sz)	/**/
#define OMPSM_REFRESH_ALL()		/**/
#define OMPSM_BCAST_THDPRV(src,dst,sz)	_ompsm_shmem_bcast_thdprv((src),(dst),(sz))

#define OMPSM_INIT_SLOCK(lp)		_ompsm_shmem_init_lock(lp)
#define OMPSM_DESTROY_SLOCK(lp)		_ompsm_shmem_destroy_lock(lp)
#define OMPSM_LOCK_SLOCK(lp)		_ompsm_shmem_lock(lp)
#define OMPSM_UNLOCK_SLOCK(lp)		_ompsm_shmem_unlock(lp)
#define OMPSM_TEST_SLOCK(lp)		_ompsm_shmem_test_lock(lp)

#define OMPSM_INIT_NLOCK(lp)		_ompsm_shmem_init_nlock(lp)
#define OMPSM_DESTROY_NLOCK(lp)		_ompsm_shmem_destroy_nlock(lp)
#define OMPSM_LOCK_NLOCK(lp)		_ompsm_shmem_lock_nlock(lp)
#define OMPSM_UNLOCK_NLOCK(lp)		_ompsm_shmem_unlock_nlock(lp)
#define OMPSM_TESTLOCK_NLOCK(lp)	_ompsm_shmem_testlock_nlock(lp)

#define OMPSM_LIB_IN()			/**/
#define OMPSM_LIB_OUT()			/**/
#define OMPSM_FLUSH_LOCK()		/**/
#define OMPSM_FLUSH_UNLOCK()		/**/

void _ompsm_estimate_shmem_size(void);
void _ompsm_init_global_data(void);
void _ompsm_shmem_init(int argc,char **argv);
void _ompsm_shmem_barrier(void);
void _ompsm_shmem_master_begin(void);
void _ompsm_shmem_master_end(void);
void _ompsm_shmem_slave_begin(void);
void _ompsm_shmem_slave_end(void);
void _ompsm_shmem_finalize(void);
char *_ompsm_shmem_alloc(int size);
int  _ompsm_shmem_is_shared(char *addr);
char *_ompsm_shmem_align_addr(char *addr);
int _ompsm_shmem_align_size(int size);
char *_ompsm_shmem_alloca(int size);
void _ompsm_shmem_freea(char *p,int size);
int _ompsm_shmem_loop_in_lock0(void);
void _ompsm_shmem_loop_out(void);
int _ompsm_shmem_count_lock0(void);
void _ompsm_shmem_lock0(void);
void _ompsm_shmem_unlock0(void);
void _ompsm_shmem_lock(volatile _ompc_lock_t *lp);
void _ompsm_shmem_unlock(volatile _ompc_lock_t *lp);
void _ompsm_shmem_flush(void);

void	_ompsm_scash_bcast_thdprv(void *dst, void *src, int size);

void	_ompsm_shmem_init_nlock (volatile _ompc_nest_lock_t *);
void	_ompsm_shmem_destroy_nlock (volatile _ompc_nest_lock_t *);
void	_ompsm_shmem_lock_nlock (volatile _ompc_nest_lock_t *);
void	_ompsm_shmem_unlock_nlock (volatile _ompc_nest_lock_t *);
int	_ompsm_shmem_testlock_nlock (volatile _ompc_nest_lock_t *);
int 	_ompsm_shmem_test_lock(volatile _ompc_lock_t *lp);
void 	_ompsm_shmem_destroy_lock(volatile _ompc_lock_t *lp);
#endif

#ifdef USE_SCASH   /* for SCASH distributed shared memory */
enum OMPSM_LOCK_TBL {
  LOCK0 = 1,
  LOCK1,
  LOCK_ATOMIC,
  LOCK_ORDERED,
  LOCK_LOCKINIT,
  LOCK_TAIL
};

enum OMPSM_BARRIER_TYPE {
  BARRIER_SYSTEM = 1,
  BARRIER_SLAVE_START,
  BARRIER_THREAD_BEGIN,
  BARRIER_THREAD_END,
  BARRIER_RUNTIME,
  BARRIER_THDPRV
};

enum OMPSM_DEST_MODE {
  DEST_NONE = 0,
  DEST_BLOCK,
  DEST_DIRECT
};

#define OMPSM_INIT(argc,argv)  		_ompsm_scash_init(argc,argv)
#define OMPSM_TERMINATE(exitcode)	_ompsm_scash_terminate (exitcode)
#define OMPSM_BARRIER() 		scash_barrier(BARRIER_RUNTIME)
#define OMPSM_MASTER_BEGIN() 		_ompsm_scash_master_begin()
#define OMPSM_MASTER_END()  		_ompsm_scash_master_end()
#define OMPSM_SLAVE_BEGIN() 		_ompsm_scash_slave_begin()
#define OMPSM_SLAVE_END() 		_ompsm_scash_slave_end()
#define OMPSM_FINALIZE() 		_ompsm_scash_finalize()
#define OMPSM_ALLOC(size)		_ompsm_scash_alloc(size, DEST_NONE, 0)
#define OMPSM_GALLOC(size,mode,arg)	_ompsm_scash_alloc(size, mode, arg)
#define OMPSM_ALIGN_SIZE(size) 		_ompsm_scash_align_size(size)
#define OMPSM_ALIGN_ADDR(size) 		_ompsm_scash_align_addr(addr)
#define OMPSM_ALLOCA(size) 		_ompsm_scash_alloca(size)
#define OMPSM_FREEA(p,size) 		_ompsm_scash_freea(p,size)
#define OMPSM_IS_SHARED(p)  	 	_ompsm_scash_is_shared(p)
#define OMPSM_LOOP_IN_LOCK0() 		_ompsm_scash_loop_in_lock0()
#define OMPSM_LOOP_OUT() 		_ompsm_scash_loop_out()
#define OMPSM_COUNT_LOCK0() 		_ompsm_scash_count_lock0()
#define OMPSM_LOCK0() 			scash_lock(LOCK0)
#define OMPSM_UNLOCK0() 		scash_unlock(LOCK0)
#define OMPSM_LOCK(lp)			scash_lock(lp)
#define OMPSM_UNLOCK(lp)		scash_unlock(lp)
#define OMPSM_LOCK_ORDERED()		scash_lock(LOCK_ORDERED)
#define OMPSM_UNLOCK_ORDERED()		scash_unlock(LOCK_ORDERED)
#define OMPSM_LOCK_ATOMIC()		scash_lock(LOCK_ATOMIC)
#define OMPSM_UNLOCK_ATOMIC()		scash_unlock(LOCK_ATOMIC)
#define OMPSM_WAIT(cond)		while(cond){ scash_poll(); }
#define OMPSM_ALLOC_LOCK()		((_ompc_lock_t *)_ompsm_scash_alloc(sizeof(int),DEST_NONE,0))
#define OMPSM_FLUSH(addr,sz)		_ompsm_scash_flush(addr,sz)
#define OMPSM_FLUSH_VAR(addr,sz)	scash_omp_flush((caddr_t)(addr),(int)(sz))
#define OMPSM_FLUSH_ALL()		_ompsm_scash_flush(_ompsm_scash_data_top, ((int)__G__->heap_tail - (int)_ompsm_scash_data_top))
#define OMPSM_REFRESH_VAR(addr,sz)	scash_refresh((caddr_t)(addr),(sz))
#define OMPSM_REFRESH_ALL()		_ompsm_scash_flush(_ompsm_scash_data_top, ((int)__G__->heap_tail - (int)_ompsm_scash_data_top))
#define OMPSM_BCAST_THDPRV(src,dst,sz)	_ompsm_scash_bcast_thdprv((src),(dst),(sz))

#define OMPSM_INIT_SLOCK(lp)		_ompsm_scash_init_lock(lp)
#define OMPSM_DESTROY_SLOCK(lp)		_ompsm_scash_destroy_lock(lp)
#define OMPSM_LOCK_SLOCK(lp)		_ompsm_scash_lock(lp)
#define OMPSM_UNLOCK_SLOCK(lp)		_ompsm_scash_unlock(lp)
#define OMPSM_TEST_SLOCK(lp)		_ompsm_scash_test_lock(lp)

#define OMPSM_INIT_NLOCK(lp)		_ompsm_scash_init_lock(lp)
#define OMPSM_DESTROY_NLOCK(lp)		_ompsm_scash_destroy_lock(lp)
#define OMPSM_LOCK_NLOCK(lp)		_ompsm_scash_lock_nlock(lp)
#define OMPSM_UNLOCK_NLOCK(lp)		_ompsm_scash_unlock_nlock(lp)
#define OMPSM_TESTLOCK_NLOCK(lp)	_ompsm_scash_testlock_nlock(lp)

#define OMPSM_LIB_IN()			_ompsm_scash_lib_in ()
#define OMPSM_LIB_OUT()			_ompsm_scash_lib_out ()
#define OMPSM_FLUSH_LOCK()		_ompsm_scash_flush_lock ()
#define OMPSM_FLUSH_UNLOCK()		_ompsm_scash_flush_unlock ()


void	_ompsm_scash_init(int argc,char **argv);
void	_ompsm_scash_terminate(int);
/* void	_ompsm_scash_barrier(void); */
void	_ompsm_scash_master_begin(void);
void	_ompsm_scash_master_end(void);
void	_ompsm_scash_slave_begin(void);
void	_ompsm_scash_slave_end(void);
void	_ompsm_scash_start_slaves(void);
void	_ompsm_scash_finalize(void);
char *	_ompsm_scash_alloc(int size, int mode, int args);
int 	_ompsm_scash_is_shared(char *addr);
char *	_ompsm_scash_align_addr(char *addr);
int	_ompsm_scash_align_size(int size);
char *	_ompsm_scash_alloca(int size);
void	_ompsm_scash_freea(char *p,int size);
int	_ompsm_scash_loop_in_lock0(void);
void	_ompsm_scash_loop_out(void);
int	_ompsm_scash_count_lock0(void);
void	_ompsm_scash_flush (void *addr, int sz);
void	_ompsm_scash_init_lock(volatile _ompc_lock_t *lp);
void	_ompsm_scash_destroy_lock(volatile _ompc_lock_t *lp);
void	_ompsm_scash_lock(volatile _ompc_lock_t *lp);
void	_ompsm_scash_unlock(volatile _ompc_lock_t *lp);


int	_ompsm_scash_test_lock(volatile _ompc_lock_t *lp);
void	_ompsm_scash_bcast_thdprv(void *dst, void *src, int size);
/* void _ompsm_scash_lock0(void); */
/* void _ompsm_scash_unlock0(void); */

void	_ompsm_scash_lock_nlock (volatile _ompc_nest_lock_t *);
void	_ompsm_scash_unlock_nlock (volatile _ompc_nest_lock_t *);
int	_ompsm_scash_testlock_nlock (volatile _ompc_nest_lock_t *);

void	_ompsm_scash_default_block_dist (char *, int);
void 	_ompsm_scash_default_block_dist2 (char *, int, int);
void	_ompsm_scash_data_dist(struct data_map_entry *);

int	_ompsm_scash_is_shared (char *);

void	_ompsm_scash_lib_in (void);
void	_ompsm_scash_lib_out (void);
void	_ompsm_scash_flush_lock (void);
void	_ompsm_scash_flush_unlock (void);

void	_ompsm_scash_fatal (char *);

extern int	_ompc_scash_dist_flag;
extern char	*_ompsm_scash_data_top;


#endif

#endif /* _OMPSH_H */
