// SPDX-License-Identifier: 0BSD /*! * @file * @license{ * BSD Zero Clause License * * Copyright (c) 2022 by Raphael Bach * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. * } */ /*============================================================================== INCLUDE ==============================================================================*/ // Own header #include "internal/fmpi_futhark.h" // C Standard Library #include <assert.h> #include <stdbool.h> #include <stdlib.h> // NULL, size_t, free(), malloc() // Internal #include "internal/fmpi_common.h" #include "internal/fmpi_error.h" #include "internal/fmpi_futhark_entry.h" #include "internal/fmpi_type.h" #include "internal/generic/fmpi_generic.h" /*============================================================================== STATIC ==============================================================================*/ typedef void * (*fmpi_futhark_new_data_func)( const struct fmpi_futhark_ctx * ctx, const void * data, size_t x, size_t y, size_t z ); static const fmpi_futhark_new_data_func fmpi_futhark_new_data_func_list[] = { FMPI_FUTHARK_FUNC_ENTRY_LIST(new, 1), FMPI_FUTHARK_FUNC_ENTRY_LIST(new, 2), FMPI_FUTHARK_FUNC_ENTRY_LIST(new, 3) }; typedef int (*fmpi_futhark_free_data_func)( const struct fmpi_futhark_ctx * ctx, void * data ); static const fmpi_futhark_free_data_func fmpi_futhark_free_data_func_list[] = { FMPI_FUTHARK_FUNC_ENTRY_LIST(free, 1), FMPI_FUTHARK_FUNC_ENTRY_LIST(free, 2), FMPI_FUTHARK_FUNC_ENTRY_LIST(free, 3) }; typedef int (*fmpi_futhark_get_data_func)( const struct fmpi_futhark_ctx * ctx, void * in, void * out ); static const fmpi_futhark_get_data_func fmpi_futhark_get_data_func_list[] = { FMPI_FUTHARK_FUNC_ENTRY_LIST(values, 1), FMPI_FUTHARK_FUNC_ENTRY_LIST(values, 2), FMPI_FUTHARK_FUNC_ENTRY_LIST(values, 3) }; /*============================================================================== MACRO ==============================================================================*/ #define FMPI_RAISE_FUTHARK_ERROR(ctx, ...) \ do { \ if((ctx)->err_handler.func != NULL) { \ FMPI_RAISE_ERROR((ctx)->err_handler, "FUTHARK", __VA_ARGS__); \ } \ } while(0) /*============================================================================== PUBLIC FUNCTION DEFINITION ==============================================================================*/ /*------------------------------------------------------------------------------ fmpi_futhark_init() ------------------------------------------------------------------------------*/ struct fmpi_futhark_ctx * fmpi_futhark_init( const struct fmpi_error_handler err_handler ){ struct fmpi_futhark_ctx * ctx = malloc(sizeof(*ctx)); if(ctx == NULL) { FMPI_RAISE_ERROR(err_handler, "FMPI", "malloc(fmpi_futhark_ctx) failed!"); return NULL; } ctx->err_handler = err_handler; ctx->cfg = futhark_context_config_new(); if(ctx->cfg == NULL) { FMPI_RAISE_FUTHARK_ERROR(ctx, "futhark_context_config_new() failed!"); free(ctx); return NULL; } ctx->ctx = futhark_context_new(ctx->cfg); // The doc says in case of error futhark_context_free() should be called // anyway, implying that futhark_context_new() returns a non-null pointer // even on error. // The code generated by futhark 0.22 says otherwise by clearly returning // NULL if malloc() fails. if(ctx->ctx == NULL) { FMPI_RAISE_FUTHARK_ERROR(ctx, "futhark_context_new() failed!"); futhark_context_config_free(ctx->cfg); free(ctx); return NULL; } if(fmpi_futhark_check_error(ctx, "futhark_context_new") != FMPI_SUCCESS) { if(fmpi_futhark_exit(&ctx) != FMPI_SUCCESS) { FMPI_RAISE_ERROR(err_handler, "FMPI", "fmpi_futhark_exit() failed!"); } return NULL; } return ctx; } /*------------------------------------------------------------------------------ fmpi_futhark_exit() ------------------------------------------------------------------------------*/ int fmpi_futhark_exit(struct fmpi_futhark_ctx ** const ctx) { assert(ctx != NULL); assert(*ctx != NULL); const int err = futhark_context_sync((*ctx)->ctx); futhark_context_free((*ctx)->ctx); futhark_context_config_free((*ctx)->cfg); free(*ctx); *ctx = NULL; if(err != FUTHARK_SUCCESS) { return FMPI_ERR_FUTHARK; } return FMPI_SUCCESS; } /*------------------------------------------------------------------------------ fmpi_futhark_sync() ------------------------------------------------------------------------------*/ int fmpi_futhark_sync(const struct fmpi_futhark_ctx * const ctx) { assert(ctx != NULL); if(futhark_context_sync(ctx->ctx) != FUTHARK_SUCCESS) { return fmpi_futhark_check_error(ctx, "futhark_context_sync"); } return FMPI_SUCCESS; } /*------------------------------------------------------------------------------ fmpi_futhark_check_error() ------------------------------------------------------------------------------*/ int fmpi_futhark_check_error( const struct fmpi_futhark_ctx * const ctx, const char * const func ){ assert(ctx != NULL); assert(func != NULL); char * err_str = futhark_context_get_error(ctx->ctx); if(err_str != NULL) { FMPI_RAISE_FUTHARK_ERROR(ctx, "%s() failed! %s", func, err_str); free(err_str); return FMPI_ERR_FUTHARK; } return FMPI_SUCCESS; } /*------------------------------------------------------------------------------ fmpi_futhark_new_data_sync() ------------------------------------------------------------------------------*/ void * fmpi_futhark_new_data_sync( const struct fmpi_futhark_ctx * const ctx, const void * const data, const enum fmpi_type_base type, const size_t dim_cnt, const size_t x, const size_t y, const size_t z ){ assert(ctx != NULL); assert(data != NULL); assert(dim_cnt <= FMPI_DIM_MAX); const size_t idx = FMPI_PRIV_FUTHARK_FUNC_IDX(dim_cnt, type); void * new_data = fmpi_futhark_new_data_func_list[idx](ctx, data, x, y, z); fmpi_futhark_sync(ctx); //! @todo Construct a proper string with dimension and type const int err = fmpi_futhark_check_error(ctx, "futhark_new_##T##_##D##"); if(new_data == NULL || err != FMPI_SUCCESS) { return NULL; } return new_data; } /*------------------------------------------------------------------------------ fmpi_futhark_new_data_async() ------------------------------------------------------------------------------*/ void * fmpi_futhark_new_data_async( const struct fmpi_futhark_ctx * const ctx, const void * const data, const enum fmpi_type_base type, const size_t dim_cnt, const size_t x, const size_t y, const size_t z ){ assert(ctx != NULL); assert(data != NULL); assert(dim_cnt <= FMPI_DIM_MAX); const size_t idx = FMPI_PRIV_FUTHARK_FUNC_IDX(dim_cnt, type); return fmpi_futhark_new_data_func_list[idx](ctx, data, x, y, z); } /*------------------------------------------------------------------------------ fmpi_futhark_free_data_sync() ------------------------------------------------------------------------------*/ int fmpi_futhark_free_data_sync( const struct fmpi_futhark_ctx * const ctx, void * const data, const enum fmpi_type_base type, const size_t dim_cnt ){ assert(ctx != NULL); assert(data != NULL); const size_t idx = FMPI_PRIV_FUTHARK_FUNC_IDX(dim_cnt, type); fmpi_futhark_free_data_func_list[idx](ctx, data); fmpi_futhark_sync(ctx); //! @todo Construct a proper string with dimension and type return fmpi_futhark_check_error(ctx, "futhark_free_##T##_##D##"); } /*------------------------------------------------------------------------------ fmpi_futhark_free_data_async() ------------------------------------------------------------------------------*/ int fmpi_futhark_free_data_async( const struct fmpi_futhark_ctx * const ctx, void * const data, const enum fmpi_type_base type, const size_t dim_cnt ){ assert(ctx != NULL); assert(data != NULL); const size_t idx = FMPI_PRIV_FUTHARK_FUNC_IDX(dim_cnt, type); return fmpi_futhark_free_data_func_list[idx](ctx, data); } /*------------------------------------------------------------------------------ fmpi_futhark_get_data_sync() ------------------------------------------------------------------------------*/ void * fmpi_futhark_get_data_sync( const struct fmpi_futhark_ctx * const ctx, void * const in, void * const out, const enum fmpi_type_base type, const size_t dim_cnt ){ assert(ctx != NULL); assert(in != NULL); assert(out != NULL); assert(dim_cnt <= FMPI_DIM_MAX); const size_t idx = FMPI_PRIV_FUTHARK_FUNC_IDX(dim_cnt, type); fmpi_futhark_get_data_func_list[idx](ctx, in, out); fmpi_futhark_sync(ctx); if(fmpi_futhark_check_error(ctx, "futhark_values_##T##_##D##d") != FMPI_SUCCESS) { return NULL; } return out; } /*------------------------------------------------------------------------------ fmpi_futhark_get_data_async() ------------------------------------------------------------------------------*/ void * fmpi_futhark_get_data_async( const struct fmpi_futhark_ctx * const ctx, void * const in, void * const out, const enum fmpi_type_base type, const size_t dim_cnt ){ assert(ctx != NULL); assert(in != NULL); assert(out != NULL); assert(dim_cnt <= FMPI_DIM_MAX); const size_t idx = FMPI_PRIV_FUTHARK_FUNC_IDX(dim_cnt, type); if(fmpi_futhark_get_data_func_list[idx](ctx, in, out) != FMPI_SUCCESS) { return NULL; } return out; } #define FMPI_FUTHARK_DEFINITION(D, T) \ _Static_assert((D) > 0 && (D) <= FMPI_DIM_MAX, ""); \ void * fmpi_futhark_new_##D##d_##T( \ const struct fmpi_futhark_ctx * const ctx, const void * const data, \ const size_t x, const size_t y, const size_t z \ ){ \ assert(ctx != NULL); \ assert(data != NULL); \ struct futhark_##T##_##D##d * new_data = FMPI_FUTHARK_NEW_##D(T, ctx->ctx, data, x, y, z); \ if(new_data == NULL) { \ FMPI_RAISE_FUTHARK_ERROR(ctx, CPL_STRINGIFY(futhark_new_##T##_##D##d)"() failed!"); \ } \ return new_data; \ } \ int fmpi_futhark_free_##D##d_##T( \ const struct fmpi_futhark_ctx * const ctx, void * const data \ ){ \ assert(ctx != NULL); \ assert(data != NULL); \ if(futhark_free_##T##_##D##d(ctx->ctx, data) != FUTHARK_SUCCESS) { \ FMPI_RAISE_FUTHARK_ERROR(ctx, CPL_STRINGIFY(futhark_free_##T##_##D##d)"() failed!"); \ return FMPI_ERR_FUTHARK; \ } \ return FMPI_SUCCESS; \ } \ int fmpi_futhark_values_##D##d_##T( \ const struct fmpi_futhark_ctx * const ctx, void * const in, void * const out \ ){ \ assert(ctx != NULL); \ assert(in != NULL); \ assert(out != NULL); \ if(futhark_values_##T##_##D##d(ctx->ctx, in, out) != FUTHARK_SUCCESS) { \ FMPI_RAISE_FUTHARK_ERROR(ctx, CPL_STRINGIFY(fmpi_futhark_values_##T##_##D##d)"() failed!"); \ return FMPI_ERR_FUTHARK; \ } \ return FMPI_SUCCESS; \ } FMPI_DEFINE_FUNCS_DT(FMPI_FUTHARK_DEFINITION, 1, FMPI_FUTHARK_TYPES) FMPI_DEFINE_FUNCS_DT(FMPI_FUTHARK_DEFINITION, 2, FMPI_FUTHARK_TYPES) FMPI_DEFINE_FUNCS_DT(FMPI_FUTHARK_DEFINITION, 3, FMPI_FUTHARK_TYPES)