Skip to content
Snippets Groups Projects
fmpi_futhark.c 11.71 KiB
// 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)