/* mem.c - Global memory accesses with acks (get, put, read and write) */
/* see copyright.txt for usage terms */

#define TI_NO_SRCPOS
#include <tic.h>

ti_hsl_t	GetPut_mutex;

void memory_init(void) {
  if (MYBOXPROC == 0) {
    ti_hsl_init(&GetPut_mutex);
  }
}

/* .......................................
 *
 * Keep track of outstanding GETs and PUTs
 *
 * .......................................
 */

Counter numGetOuts = 0;
Counter numPutOuts = 0;

/* ------------------------------------------------------------------------------------ */
TI_INLINE(decr_put_ctr_reply)
void decr_put_ctr_reply(tic_amtoken_t token) { 
  ti_hsl_lock(&GetPut_mutex);
  numPutOuts--; 
  ti_hsl_unlock(&GetPut_mutex);
}
TIC_AMSHORT(decr_put_ctr_reply, 0, 0,
  (token),
  (token));
/* ------------------------------------------------------------------------------------ */
TI_INLINE(decr_ctr_reply)
void decr_ctr_reply(tic_amtoken_t token, Counter *ctr) {
  __decr_ctr(ctr);
}
TIC_AMSHORT(decr_ctr_reply, 1, 2,
  (token, (Counter *)TIC_AMRECV_PTR32(a0)    ),
  (token, (Counter *)TIC_AMRECV_PTR64(a0, a1)));
/* ------------------------------------------------------------------------------------ */
	
/* ..........................
 *
 * GETs with explicit counter
 *
 * ..........................
 */

#ifdef COMM_AM2

/* ------------------------------------------------------------------------------------ */
/* get requests */
/* ------------------------------------------------------------------------------------ */
#define _TIC_GET_HANDLER(shorttype, type)                                                                         \
TI_INLINE(get_ ## shorttype ## _request)                                                                         \
void get_ ## shorttype ## _request(tic_amtoken_t token, type *addr,                                               \
                                      void *retAddr, Counter *ctr) {                                              \
  tic_AMReply(3,5,(token, TIC_AMIDX(get_ ## shorttype ## _reply),                                                 \
               TIC_AMSEND_PTR(retAddr), (tic_handlerarg_t)*addr, TIC_AMSEND_PTR(ctr)));                           \
}                                                                                                                 \
TIC_AMSHORT(get_ ## shorttype ## _request, 3, 6,                                                                  \
  (token, (type *)TIC_AMRECV_PTR32(a0),     TIC_AMRECV_PTR32(a1),     (Counter *)TIC_AMRECV_PTR32(a2)    ), \
  (token, (type *)TIC_AMRECV_PTR64(a0, a1), TIC_AMRECV_PTR64(a2, a3), (Counter *)TIC_AMRECV_PTR64(a4, a5)))

_TIC_GET_HANDLER(b, jbyte);
_TIC_GET_HANDLER(sh, jshort);
_TIC_GET_HANDLER(i, jint);
/* ------------------------------------------------------------------------------------ */
TI_INLINE(get_f_request)
void get_f_request(tic_amtoken_t token, jfloat *addr, void *retAddr, Counter *ctr) {
  const jfloat val = *addr;
  tic_AMReply(3,5,(token, TIC_AMIDX(get_f_reply),
               TIC_AMSEND_PTR(retAddr), TIC_AMSEND_JFLOAT(val), TIC_AMSEND_PTR(ctr)));
}
TIC_AMSHORT(get_f_request, 3, 6,
  (token, (jfloat *)TIC_AMRECV_PTR32(a0),     TIC_AMRECV_PTR32(a1),     (Counter *)TIC_AMRECV_PTR32(a2)    ),
  (token, (jfloat *)TIC_AMRECV_PTR64(a0, a1), TIC_AMRECV_PTR64(a2, a3), (Counter *)TIC_AMRECV_PTR64(a4, a5)));
/* ------------------------------------------------------------------------------------ */
TI_INLINE(get_d_request)
void get_d_request(tic_amtoken_t token, jdouble *addr, void *retAddr, Counter *ctr) {
  const jdouble val = *addr;
  tic_AMReply(4,6,(token, TIC_AMIDX(get_d_reply),
               TIC_AMSEND_PTR(retAddr), TIC_AMSEND_JDOUBLE(val), TIC_AMSEND_PTR(ctr)));
}
TIC_AMSHORT(get_d_request, 3, 6,
  (token, (jdouble *)TIC_AMRECV_PTR32(a0),     TIC_AMRECV_PTR32(a1),     (Counter *)TIC_AMRECV_PTR32(a2)    ),
  (token, (jdouble *)TIC_AMRECV_PTR64(a0, a1), TIC_AMRECV_PTR64(a2, a3), (Counter *)TIC_AMRECV_PTR64(a4, a5)));
/* ------------------------------------------------------------------------------------ */
TI_INLINE(get_l_request)
void get_l_request(tic_amtoken_t token, jlong *addr, void *retAddr, Counter *ctr) {
  const jlong val = *addr;
  tic_AMReply(4,6,(token, TIC_AMIDX(get_l_reply),
               TIC_AMSEND_PTR(retAddr), TIC_AMSEND_JLONG(val), TIC_AMSEND_PTR(ctr)));
}
TIC_AMSHORT(get_l_request, 3, 6,
  (token, (jlong *)TIC_AMRECV_PTR32(a0),     TIC_AMRECV_PTR32(a1),     (Counter *)TIC_AMRECV_PTR32(a2)    ),
  (token, (jlong *)TIC_AMRECV_PTR64(a0, a1), TIC_AMRECV_PTR64(a2, a3), (Counter *)TIC_AMRECV_PTR64(a4, a5)));
/* ------------------------------------------------------------------------------------ */
TI_INLINE(get_lp_request)
void get_lp_request(tic_amtoken_t token, void **addr, void *retAddr, Counter *ctr) {
  void *dataPtr = *addr;

  #if defined(USE_DISTRIBUTED_GC) && !defined(USE_GC_NONE)
    dgc_ptr_esc_all(&dataPtr, sizeof(void *), 1); /* inform distributed GC that a pointer is escaping */
  #endif

  tic_AMReply(3,6,(token, TIC_AMIDX(get_lp_reply),
               TIC_AMSEND_PTR(retAddr), TIC_AMSEND_PTR(dataPtr), TIC_AMSEND_PTR(ctr)));
}
TIC_AMSHORT(get_lp_request, 3, 6,
  (token, (void **)TIC_AMRECV_PTR32(a0),     TIC_AMRECV_PTR32(a1),     (Counter *)TIC_AMRECV_PTR32(a2)    ),
  (token, (void **)TIC_AMRECV_PTR64(a0, a1), TIC_AMRECV_PTR64(a2, a3), (Counter *)TIC_AMRECV_PTR64(a4, a5)));
/* ------------------------------------------------------------------------------------ */
TI_INLINE(get_gp_request)
void get_gp_request(tic_amtoken_t token, jGPointer *addr, void *retAddr, Counter *ctr) {
  jGPointer data = *addr;
  void *dataAddr = tolocal(data);
  Box dataBox = tobox(data);

  #if defined(USE_DISTRIBUTED_GC) && !defined(USE_GC_NONE)
    dgc_ptr_esc(&data, 1, 1); /* inform distributed GC that a gp is escaping */
  #endif

  tic_AMReply(4,7,(token, TIC_AMIDX(get_gp_reply),
               TIC_AMSEND_PTR(retAddr), (tic_handlerarg_t)dataBox, 
               TIC_AMSEND_PTR(dataAddr), TIC_AMSEND_PTR(ctr)));
}
TIC_AMSHORT(get_gp_request, 3, 6,
  (token, (jGPointer *)TIC_AMRECV_PTR32(a0),     TIC_AMRECV_PTR32(a1),     (Counter *)TIC_AMRECV_PTR32(a2)    ),
  (token, (jGPointer *)TIC_AMRECV_PTR64(a0, a1), TIC_AMRECV_PTR64(a2, a3), (Counter *)TIC_AMRECV_PTR64(a4, a5)));
/* ------------------------------------------------------------------------------------ */


/* ------------------------------------------------------------------------------------ */
/* get replies */
/* ------------------------------------------------------------------------------------ */
#define _TIC_GET_REPLYHANDLER(shorttype, type)                                          \
TI_INLINE(get_ ## shorttype ## _reply)                                                 \
void get_ ## shorttype ## _reply(tic_amtoken_t token, type *addr,                       \
                                      type data, Counter *ctr) {                        \
  *addr = data;                                                                         \
  __decr_ctr(ctr);                                                                      \
}                                                                                       \
TIC_AMSHORT(get_ ## shorttype ## _reply, 3, 5,                                          \
  (token, (type *)TIC_AMRECV_PTR32(a0),     (type)a1, (Counter *)TIC_AMRECV_PTR32(a2)    ), \
  (token, (type *)TIC_AMRECV_PTR64(a0, a1), (type)a2, (Counter *)TIC_AMRECV_PTR64(a3, a4)))

_TIC_GET_REPLYHANDLER(b, jbyte);
_TIC_GET_REPLYHANDLER(sh, jshort);
_TIC_GET_REPLYHANDLER(i, jint);
/* ------------------------------------------------------------------------------------ */
TI_INLINE(get_f_reply)
void get_f_reply(tic_amtoken_t token, jfloat *addr, jfloat data, Counter *ctr) {
  *addr = data;
  __decr_ctr(ctr);
}
TIC_AMSHORT(get_f_reply, 3, 5,
  (token, (jfloat *)TIC_AMRECV_PTR32(a0),     TIC_AMRECV_JFLOAT(a1), (Counter *)TIC_AMRECV_PTR32(a2)    ),
  (token, (jfloat *)TIC_AMRECV_PTR64(a0, a1), TIC_AMRECV_JFLOAT(a2), (Counter *)TIC_AMRECV_PTR64(a3, a4)));
/* ------------------------------------------------------------------------------------ */
TI_INLINE(get_d_reply)
void get_d_reply(tic_amtoken_t token, jdouble *addr, jdouble data, Counter *ctr) {
  *addr = data;
  __decr_ctr(ctr);
}
TIC_AMSHORT(get_d_reply, 4, 6,
  (token, (jdouble *)TIC_AMRECV_PTR32(a0),     TIC_AMRECV_JDOUBLE(a1, a2), (Counter *)TIC_AMRECV_PTR32(a3)    ),
  (token, (jdouble *)TIC_AMRECV_PTR64(a0, a1), TIC_AMRECV_JDOUBLE(a2, a3), (Counter *)TIC_AMRECV_PTR64(a4, a5)));
/* ------------------------------------------------------------------------------------ */
TI_INLINE(get_l_reply)
void get_l_reply(tic_amtoken_t token, jlong *addr, jlong data, Counter *ctr) {
  *addr = data;
  __decr_ctr(ctr);
}
TIC_AMSHORT(get_l_reply, 4, 6,
  (token, (jlong *)TIC_AMRECV_PTR32(a0),     TIC_AMRECV_JLONG(a1, a2), (Counter *)TIC_AMRECV_PTR32(a3)    ),
  (token, (jlong *)TIC_AMRECV_PTR64(a0, a1), TIC_AMRECV_JLONG(a2, a3), (Counter *)TIC_AMRECV_PTR64(a4, a5)));
/* ------------------------------------------------------------------------------------ */
TI_INLINE(get_lp_reply)
void get_lp_reply(tic_amtoken_t token, void **addr, void *data, Counter *ctr) {
  *addr = data;
  __decr_ctr(ctr);
}
TIC_AMSHORT(get_lp_reply, 3, 6,
  (token, (void **)TIC_AMRECV_PTR32(a0),     TIC_AMRECV_PTR32(a1),     (Counter *)TIC_AMRECV_PTR32(a2)    ),
  (token, (void **)TIC_AMRECV_PTR64(a0, a1), TIC_AMRECV_PTR64(a2, a3), (Counter *)TIC_AMRECV_PTR64(a4, a5)));
/* ------------------------------------------------------------------------------------ */
TI_INLINE(get_gp_reply)
void get_gp_reply(tic_amtoken_t token, jGPointer *addr, Box dataBox, void *dataAddr, Counter *ctr) {
  *addr = toglobalb(dataBox, dataAddr);
  __decr_ctr(ctr);
}
TIC_AMSHORT(get_gp_reply, 4, 7,
  (token, (jGPointer *)TIC_AMRECV_PTR32(a0),     (Box)a1, TIC_AMRECV_PTR32(a2),     (Counter *)TIC_AMRECV_PTR32(a3)    ),
  (token, (jGPointer *)TIC_AMRECV_PTR64(a0, a1), (Box)a2, TIC_AMRECV_PTR64(a3, a4), (Counter *)TIC_AMRECV_PTR64(a5, a6)));
/* ------------------------------------------------------------------------------------ */

/* ..........................
 *
 * PUTs with explicit counter
 *
 * ..........................
 */
/* ------------------------------------------------------------------------------------ */
#define _TIC_PUT_HANDLER(shorttype, type)                                               \
TI_INLINE(put_ ## shorttype ## _request)                                               \
void put_ ## shorttype ## _request(tic_amtoken_t token, type *addr,                     \
                                      type data, Counter *ctr) {                        \
  *addr = data;                                                                         \
  tic_AMReply(1,2,(token, TIC_AMIDX(decr_ctr_reply), TIC_AMSEND_PTR(ctr)));             \
}                                                                                       \
TIC_AMSHORT(put_ ## shorttype ## _request, 3, 5,                                        \
  (token, (type *)TIC_AMRECV_PTR32(a0),     (type)a1, (Counter *)TIC_AMRECV_PTR32(a2)    ), \
  (token, (type *)TIC_AMRECV_PTR64(a0, a1), (type)a2, (Counter *)TIC_AMRECV_PTR64(a3, a4)))

_TIC_PUT_HANDLER(b, jbyte);
_TIC_PUT_HANDLER(sh, jshort);
_TIC_PUT_HANDLER(i, jint);
/* ------------------------------------------------------------------------------------ */
TI_INLINE(put_f_request)
void put_f_request(tic_amtoken_t token, jfloat *addr, jfloat data, Counter *ctr) {
  *addr = data;
  tic_AMReply(1,2,(token, TIC_AMIDX(decr_ctr_reply), TIC_AMSEND_PTR(ctr)));
}
TIC_AMSHORT(put_f_request, 3, 5,
  (token, (jfloat *)TIC_AMRECV_PTR32(a0),     TIC_AMRECV_JFLOAT(a1), (Counter *)TIC_AMRECV_PTR32(a2)    ),
  (token, (jfloat *)TIC_AMRECV_PTR64(a0, a1), TIC_AMRECV_JFLOAT(a2), (Counter *)TIC_AMRECV_PTR64(a3, a4)));
/* ------------------------------------------------------------------------------------ */
TI_INLINE(put_d_request)
void put_d_request(tic_amtoken_t token, jdouble *addr, jdouble data, Counter *ctr) {
  *addr = data;
  tic_AMReply(1,2,(token, TIC_AMIDX(decr_ctr_reply), TIC_AMSEND_PTR(ctr)));
}
TIC_AMSHORT(put_d_request, 4, 6,
  (token, (jdouble *)TIC_AMRECV_PTR32(a0),     TIC_AMRECV_JDOUBLE(a1, a2), (Counter *)TIC_AMRECV_PTR32(a3)    ),
  (token, (jdouble *)TIC_AMRECV_PTR64(a0, a1), TIC_AMRECV_JDOUBLE(a2, a3), (Counter *)TIC_AMRECV_PTR64(a4, a5)));
/* ------------------------------------------------------------------------------------ */
TI_INLINE(put_l_request)
void put_l_request(tic_amtoken_t token, jlong *addr, jlong data, Counter *ctr) {
  *addr = data;
  tic_AMReply(1,2,(token, TIC_AMIDX(decr_ctr_reply), TIC_AMSEND_PTR(ctr)));
}
TIC_AMSHORT(put_l_request, 4, 6,
  (token, (jlong *)TIC_AMRECV_PTR32(a0),     TIC_AMRECV_JLONG(a1, a2), (Counter *)TIC_AMRECV_PTR32(a3)    ),
  (token, (jlong *)TIC_AMRECV_PTR64(a0, a1), TIC_AMRECV_JLONG(a2, a3), (Counter *)TIC_AMRECV_PTR64(a4, a5)));
/* ------------------------------------------------------------------------------------ */
TI_INLINE(put_lp_request)
void put_lp_request(tic_amtoken_t token, void **addr, void *data, Counter *ctr) {
  *addr = data;
  tic_AMReply(1,2,(token, TIC_AMIDX(decr_ctr_reply), TIC_AMSEND_PTR(ctr)));
}
TIC_AMSHORT(put_lp_request, 3, 6,
  (token, (void **)TIC_AMRECV_PTR32(a0),     TIC_AMRECV_PTR32(a1),     (Counter *)TIC_AMRECV_PTR32(a2)    ),
  (token, (void **)TIC_AMRECV_PTR64(a0, a1), TIC_AMRECV_PTR64(a2, a3), (Counter *)TIC_AMRECV_PTR64(a4, a5)));
/* ------------------------------------------------------------------------------------ */
TI_INLINE(put_gp_request)
void put_gp_request(tic_amtoken_t token, jGPointer *addr, Box dataBox, void *dataAddr, Counter *ctr) {
  *addr = toglobalb(dataBox, dataAddr);
  tic_AMReply(1,2,(token, TIC_AMIDX(decr_ctr_reply), TIC_AMSEND_PTR(ctr)));
}
TIC_AMSHORT(put_gp_request, 4, 7,
  (token, (jGPointer *)TIC_AMRECV_PTR32(a0),     (Box)a1, TIC_AMRECV_PTR32(a2),     (Counter *)TIC_AMRECV_PTR32(a3)    ),
  (token, (jGPointer *)TIC_AMRECV_PTR64(a0, a1), (Box)a2, TIC_AMRECV_PTR64(a3, a4), (Counter *)TIC_AMRECV_PTR64(a5, a6)));
/* ------------------------------------------------------------------------------------ */
#endif /* AMII */