/*   $Source: bitbucket.org:berkeleylab/gasnet.git/gasnet_handler.h $
 * Description: GASNet Helpers for using bit-width-independent AM handlers
 * Copyright 2002, Dan Bonachea <bonachea@cs.berkeley.edu>
 * Terms of use are as specified in license.txt
 */

#ifndef _GASNET_HANDLER_H
#define _GASNET_HANDLER_H

/* argument-list macros */
#define ARGS0
#define ARGS1 , gasnet_handlerarg_t a0
#define ARGS2 , gasnet_handlerarg_t a0, gasnet_handlerarg_t a1
#define ARGS3 , gasnet_handlerarg_t a0, gasnet_handlerarg_t a1, gasnet_handlerarg_t a2
#define ARGS4 , gasnet_handlerarg_t a0, gasnet_handlerarg_t a1, gasnet_handlerarg_t a2, gasnet_handlerarg_t a3

#define ARGS5 , gasnet_handlerarg_t a0, gasnet_handlerarg_t a1, gasnet_handlerarg_t a2, gasnet_handlerarg_t a3, \
                gasnet_handlerarg_t a4
#define ARGS6 , gasnet_handlerarg_t a0, gasnet_handlerarg_t a1, gasnet_handlerarg_t a2, gasnet_handlerarg_t a3, \
                gasnet_handlerarg_t a4, gasnet_handlerarg_t a5
#define ARGS7 , gasnet_handlerarg_t a0, gasnet_handlerarg_t a1, gasnet_handlerarg_t a2, gasnet_handlerarg_t a3, \
                gasnet_handlerarg_t a4, gasnet_handlerarg_t a5, gasnet_handlerarg_t a6
#define ARGS8 , gasnet_handlerarg_t a0, gasnet_handlerarg_t a1, gasnet_handlerarg_t a2, gasnet_handlerarg_t a3, \
                gasnet_handlerarg_t a4, gasnet_handlerarg_t a5, gasnet_handlerarg_t a6, gasnet_handlerarg_t a7

#define ARGS9  , gasnet_handlerarg_t a0,  gasnet_handlerarg_t a1,  gasnet_handlerarg_t a2,  gasnet_handlerarg_t a3,  \
                 gasnet_handlerarg_t a4,  gasnet_handlerarg_t a5,  gasnet_handlerarg_t a6,  gasnet_handlerarg_t a7,  \
                 gasnet_handlerarg_t a8
#define ARGS10 , gasnet_handlerarg_t a0,  gasnet_handlerarg_t a1,  gasnet_handlerarg_t a2,  gasnet_handlerarg_t a3,  \
                 gasnet_handlerarg_t a4,  gasnet_handlerarg_t a5,  gasnet_handlerarg_t a6,  gasnet_handlerarg_t a7,  \
                 gasnet_handlerarg_t a8,  gasnet_handlerarg_t a9
#define ARGS11 , gasnet_handlerarg_t a0,  gasnet_handlerarg_t a1,  gasnet_handlerarg_t a2,  gasnet_handlerarg_t a3,  \
                 gasnet_handlerarg_t a4,  gasnet_handlerarg_t a5,  gasnet_handlerarg_t a6,  gasnet_handlerarg_t a7,  \
                 gasnet_handlerarg_t a8,  gasnet_handlerarg_t a9,  gasnet_handlerarg_t a10
#define ARGS12 , gasnet_handlerarg_t a0,  gasnet_handlerarg_t a1,  gasnet_handlerarg_t a2,  gasnet_handlerarg_t a3,  \
                 gasnet_handlerarg_t a4,  gasnet_handlerarg_t a5,  gasnet_handlerarg_t a6,  gasnet_handlerarg_t a7,  \
                 gasnet_handlerarg_t a8,  gasnet_handlerarg_t a9,  gasnet_handlerarg_t a10, gasnet_handlerarg_t a11


#define ARGS13 , gasnet_handlerarg_t a0,  gasnet_handlerarg_t a1,  gasnet_handlerarg_t a2,  gasnet_handlerarg_t a3,  \
                 gasnet_handlerarg_t a4,  gasnet_handlerarg_t a5,  gasnet_handlerarg_t a6,  gasnet_handlerarg_t a7,  \
                 gasnet_handlerarg_t a8,  gasnet_handlerarg_t a9,  gasnet_handlerarg_t a10, gasnet_handlerarg_t a11, \
                 gasnet_handlerarg_t a12
#define ARGS14 , gasnet_handlerarg_t a0,  gasnet_handlerarg_t a1,  gasnet_handlerarg_t a2,  gasnet_handlerarg_t a3,  \
                 gasnet_handlerarg_t a4,  gasnet_handlerarg_t a5,  gasnet_handlerarg_t a6,  gasnet_handlerarg_t a7,  \
                 gasnet_handlerarg_t a8,  gasnet_handlerarg_t a9,  gasnet_handlerarg_t a10, gasnet_handlerarg_t a11, \
                 gasnet_handlerarg_t a12, gasnet_handlerarg_t a13
#define ARGS15 , gasnet_handlerarg_t a0,  gasnet_handlerarg_t a1,  gasnet_handlerarg_t a2,  gasnet_handlerarg_t a3,  \
                 gasnet_handlerarg_t a4,  gasnet_handlerarg_t a5,  gasnet_handlerarg_t a6,  gasnet_handlerarg_t a7,  \
                 gasnet_handlerarg_t a8,  gasnet_handlerarg_t a9,  gasnet_handlerarg_t a10, gasnet_handlerarg_t a11, \
                 gasnet_handlerarg_t a12, gasnet_handlerarg_t a13, gasnet_handlerarg_t a14
#define ARGS16 , gasnet_handlerarg_t a0,  gasnet_handlerarg_t a1,  gasnet_handlerarg_t a2,  gasnet_handlerarg_t a3,  \
                 gasnet_handlerarg_t a4,  gasnet_handlerarg_t a5,  gasnet_handlerarg_t a6,  gasnet_handlerarg_t a7,  \
                 gasnet_handlerarg_t a8,  gasnet_handlerarg_t a9,  gasnet_handlerarg_t a10, gasnet_handlerarg_t a11, \
                 gasnet_handlerarg_t a12, gasnet_handlerarg_t a13, gasnet_handlerarg_t a14, gasnet_handlerarg_t a15

#define ARGNAMES0
#define ARGNAMES1 , a0
#define ARGNAMES2 , a0, a1
#define ARGNAMES3 , a0, a1, a2
#define ARGNAMES4 , a0, a1, a2, a3

#define ARGNAMES5 , a0, a1, a2, a3, a4
#define ARGNAMES6 , a0, a1, a2, a3, a4, a5
#define ARGNAMES7 , a0, a1, a2, a3, a4, a5, a6
#define ARGNAMES8 , a0, a1, a2, a3, a4, a5, a6, a7

#define ARGNAMES9  , a0, a1, a2, a3, a4, a5, a6, a7, a8
#define ARGNAMES10 , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9
#define ARGNAMES11 , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10
#define ARGNAMES12 , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11

#define ARGNAMES13 , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12
#define ARGNAMES14 , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13
#define ARGNAMES15 , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14
#define ARGNAMES16 , a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15

/* 
  =====================================
    Pointer-width abstraction support
  =====================================
  AM arguments are always 32-bits wide, but PTR64 platforms need the ability to 
   send their 64-bit pointers as arguments. We do this by packing pointers into 
   2 arguments. The macros below support this packing/unpacking so you can write the
   calls and handlers once and generate the packing/unpacking code automatically
   as required for the platform.
*/

/* AM send call macros (use instead of direct calls to e.g. gasnet_AMRequestShort2)
  Usage: cnt32 = the number of args needed for AM call on PTR32 platform
         cnt64 = the number of args needed for AM call on PTR64 platform
         args = parenthesized argument list for AM request/reply call, 
           with any pointer args wrapped in a PACK() macro
 */
#if PLATFORM_ARCH_32
  #define SHORT_REQ(cnt32, cnt64, args) gasnet_AMRequestShort ## cnt32 args
  #define SHORT_REP(cnt32, cnt64, args) gasnet_AMReplyShort ## cnt32 args
  #define MEDIUM_REQ(cnt32, cnt64, args) gasnet_AMRequestMedium ## cnt32 args
  #define MEDIUM_REP(cnt32, cnt64, args) gasnet_AMReplyMedium ## cnt32 args
  #define LONG_REQ(cnt32, cnt64, args) gasnet_AMRequestLong ## cnt32 args
  #define LONG_REP(cnt32, cnt64, args) gasnet_AMReplyLong ## cnt32 args
  #define LONGASYNC_REQ(cnt32, cnt64, args) gasnet_AMRequestLongAsync ## cnt32 args
#elif PLATFORM_ARCH_64
  #define SHORT_REQ(cnt32, cnt64, args) gasnet_AMRequestShort ## cnt64 args
  #define SHORT_REP(cnt32, cnt64, args) gasnet_AMReplyShort ## cnt64 args
  #define MEDIUM_REQ(cnt32, cnt64, args) gasnet_AMRequestMedium ## cnt64 args
  #define MEDIUM_REP(cnt32, cnt64, args) gasnet_AMReplyMedium ## cnt64 args
  #define LONG_REQ(cnt32, cnt64, args) gasnet_AMRequestLong ## cnt64 args
  #define LONG_REP(cnt32, cnt64, args) gasnet_AMReplyLong ## cnt64 args
  #define LONGASYNC_REQ(cnt32, cnt64, args) gasnet_AMRequestLongAsync ## cnt64 args
#endif

/* pointer packing/unpacking helper macros */
#if PLATFORM_ARCH_32
  #define PACK(ptr) ((gasnet_handlerarg_t)(ptr))
  #define UNPACK(a0) ((void *)a0)
#elif PLATFORM_ARCH_64
  #define PACK(ptr) ((gasnet_handlerarg_t)GASNETI_HIWORD(ptr)), ((gasnet_handlerarg_t)GASNETI_LOWORD(ptr))
  #define UNPACK2(a0,a1) ((void *)GASNETI_MAKEWORD(a0,a1))
#endif

#ifndef GASNETI_HANDLER_SCOPE
#define GASNETI_HANDLER_SCOPE extern
#endif

#if PLATFORM_ARCH_32
  #define SHORT_HANDLER_DECL(name, cnt32, cnt64) \
    GASNETI_HANDLER_SCOPE void name ## _32(gasnet_token_t token ARGS ## cnt32)
  #define SHORT_HANDLER(name, cnt32, cnt64, innerargs32, innerargs64)            \
    GASNETI_HANDLER_SCOPE void name ## _32(gasnet_token_t token ARGS ## cnt32) { \
      name ## _inner innerargs32 ;                                               \
    } static int _dummy_##name = sizeof(_dummy_##name)
  #define MEDIUM_HANDLER_DECL(name, cnt32, cnt64)                                          \
    GASNETI_HANDLER_SCOPE void name ## _32(gasnet_token_t token, void *addr, size_t nbytes \
                           ARGS ## cnt32)
  #define MEDIUM_HANDLER(name, cnt32, cnt64, innerargs32, innerargs64)                     \
    GASNETI_HANDLER_SCOPE void name ## _32(gasnet_token_t token, void *addr, size_t nbytes \
                           ARGS ## cnt32) {                                                \
      name ## _inner innerargs32 ;                                                         \
    } static int _dummy_##name = sizeof(_dummy_##name)
#elif PLATFORM_ARCH_64
  #define SHORT_HANDLER_DECL(name, cnt32, cnt64) \
    GASNETI_HANDLER_SCOPE void name ## _64(gasnet_token_t token ARGS ## cnt64)
  #define SHORT_HANDLER(name, cnt32, cnt64, innerargs32, innerargs64)            \
    GASNETI_HANDLER_SCOPE void name ## _64(gasnet_token_t token ARGS ## cnt64) { \
      name ## _inner innerargs64 ;                                               \
    } static int _dummy_##name = sizeof(_dummy_##name)
  #define MEDIUM_HANDLER_DECL(name, cnt32, cnt64)                                          \
    GASNETI_HANDLER_SCOPE void name ## _64(gasnet_token_t token, void *addr, size_t nbytes \
                           ARGS ## cnt64)
  #define MEDIUM_HANDLER(name, cnt32, cnt64, innerargs32, innerargs64)                     \
    GASNETI_HANDLER_SCOPE void name ## _64(gasnet_token_t token, void *addr, size_t nbytes \
                           ARGS ## cnt64) {                                                \
      name ## _inner innerargs64 ;                                                         \
    } static int _dummy_##name = sizeof(_dummy_##name)
#endif

/* convenience declarators for bit-width-independent handlers */
#define SHORT_HANDLER_NOBITS_DECL(name, cnt) \
  GASNETI_HANDLER_SCOPE void name(gasnet_token_t token ARGS ## cnt)
#define MEDIUM_HANDLER_NOBITS_DECL(name, cnt) \
  GASNETI_HANDLER_SCOPE void name(gasnet_token_t token, void *addr, size_t nbytes ARGS ## cnt)

/* long and medium handlers have the same signature */
#define LONG_HANDLER              MEDIUM_HANDLER
#define LONG_HANDLER_DECL         MEDIUM_HANDLER_DECL
#define LONG_HANDLER_NOBITS_DECL  MEDIUM_HANDLER_NOBITS_DECL

typedef void (*gasneti_handler_fn_t)();  /* prototype for generic handler function */

/*  handler table construction */
#define gasneti_handleridx(fnname) _hidx_ ## fnname
#define gasneti_handler_tableentry_no_bits(fnname) \
    { gasneti_handleridx(fnname), (gasneti_handler_fn_t)fnname }

#if PLATFORM_ARCH_32
  #define gasneti_handler_tableentry_with_bits(fnname) \
    { gasneti_handleridx(fnname), (gasneti_handler_fn_t)fnname ## _32 }
#elif PLATFORM_ARCH_64
  #define gasneti_handler_tableentry_with_bits(fnname) \
    { gasneti_handleridx(fnname), (gasneti_handler_fn_t)fnname ## _64 }
#endif


#endif
