gcc/liboffloadmic/include/myo/myoimpl.h

620 lines
25 KiB
C

/*
* Copyright 2010-2015 Intel Corporation.
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, version 2.1.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*
* Disclaimer: The codes contained in these modules may be specific
* to the Intel Software Development Platform codenamed Knights Ferry,
* and the Intel product codenamed Knights Corner, and are not backward
* compatible with other Intel products. Additionally, Intel will NOT
* support the codes or instruction set in future products.
*
* Intel offers no warranty of any kind regarding the code. This code is
* licensed on an "AS IS" basis and Intel is not obligated to provide
* any support, assistance, installation, training, or other services
* of any kind. Intel is also not obligated to provide any updates,
* enhancements or extensions. Intel specifically disclaims any warranty
* of merchantability, non-infringement, fitness for any particular
* purpose, and any other warranty.
*
* Further, Intel disclaims all liability of any kind, including but
* not limited to liability for infringement of any proprietary rights,
* relating to the use of the code, even if Intel is notified of the
* possibility of such liability. Except as expressly stated in an Intel
* license agreement provided with this code and agreed upon with Intel,
* no license, express or implied, by estoppel or otherwise, to any
* intellectual property rights is granted herein.
*/
/**
Description:
Define APIs of MYO for compiler or pre-processor to transfer original programs.
*/
#ifndef _MYO_IMPL_H_
#define _MYO_IMPL_H_
/** @ingroup MYO
* @addtogroup MYOIMPL_API
@{
* @file myoimpl.h
*/
#ifdef __cplusplus
extern "C" {
#define EXTERN_C extern "C"
#else
#define EXTERN_C /* nothing */
#endif
# define MYOACCESSAPI /* nothing */
#ifdef DEFINE_ARENA_API_CILK_SHARED
#define CILK_SHARED _Cilk_shared
#else
#define CILK_SHARED /* nothing */
#endif
/* **************************************************************************** *\
APIs to enable functions being remotely called
\* **************************************************************************** */
typedef void *(*MyoiRemoteFuncType)(void *);
/** @fn extern MyoError myoiRemoteFuncRegister(MyoiRemoteFuncType in_pFuncAddr,
* const char *in_pFuncName)
* @brief Register a function so that it can be remotely called. This should be
* done in myoiUserInit or before calling myoiLibInit. After myoiLibInit,
* there will be a table on all peers, which contains the information for
* all remotely callable functions.
*
* @param in_pWrapFuncAddr address of the wrapper function.
* @param in_pFuncName name of the function.
* @return
* MYO_SUCCESS; or
* an error number to indicate the error.
**/
MYOACCESSAPI
MyoError myoiRemoteFuncRegister(MyoiRemoteFuncType in_pFuncAddr,
const char *in_pFuncName);
/** @fn extern MyoError myoiRemoteFuncLookupByName(char *in_pFuncName,
* MyoiRemoteFuncType *out_pWrapFuncAddr)
* @brief Get the address of the wrapper function by looking up the table
* by name. This API can be used when assigning a function pointer to
* remotely callable functions.
*
* @param in_pFuncName name of the function.
* @param out_pWrapFuncAddr address of the wrapper function.
* @return
* MYO_SUCCESS; or
* an error number to indicate the error.
**/
MYOACCESSAPI MyoError myoiRemoteFuncLookupByName(char *in_pFuncName,
MyoiRemoteFuncType *out_pWrapFuncAddr);
/** @fn extern MyoError myoiRemoteFuncLookupByAddr(MyoiRemoteFuncType
* in_pWrapFuncAddr,char **out_pFuncName)
* @brief Get the name of a remote function by looking up the table by
* the address. This API can be used when calling a remotely callable
* function by a function pointer.
*
* @param in_pWrapFuncAddr address of the function.
* @param out_pFuncName name of the function.
* @return
* MYO_SUCCESS; or
* an error number to indicate the error.
**/
MYOACCESSAPI MyoError myoiRemoteFuncLookupByAddr(MyoiRemoteFuncType in_pWrapFuncAddr,
char **out_pFuncName);
//! Host Side Shared Function Pointer Entry Struct
typedef struct {
//! Function Name
const char *funcName;
//! Function Address
void *funcAddr;
//! Local Thunk Address
void *localThunkAddr;
} MyoiHostSharedFptrEntry;
//! Target Side Shared Function Pointer Entry Struct
typedef struct {
//! Function Name
const char *funcName;
//! Function Address
void *funcAddr;
//! Wrap Function Address
void *wrapFuncAddr;
//! Locak Thunk Address
void *localThunkAddr;
} MyoiTargetSharedFptrEntry;
/**
* @cond INCLUDE_MYO_INTERNAL_DOCUMENTATION
* @fn extern MyoError myoiHostFptrTableRegister(void *in_pAddrOfFptrTable,
* int in_NumEntry, int in_Ordered)
* @brief Register shared functions on host side. A 16 byte thunk will be
* allocated for each function entry in non-coherent shared memory. The
* thunk will contain a jump instruction to the local version of the
* shared function, which is provided by the second item of the function
* entry. Also, the address of the thunk will be stored to the 3rd item
* of the function entry for Compiler usage.
*
* @param in_pAddrOfFptrTable start address of the shared function
* table, assuming it follows the format of MyoiHostSharedFptrEntry.
* @param in_NumEntry number of entry in the table.
* @param in_Ordered whether the table is ordered by function name.
* @return
* MYO_SUCCESS; or
* an error number to indicate the error.
**/
MYOACCESSAPI
MyoError myoiHostFptrTableRegister(
void *in_pAddrOfFptrTable, int in_NumEntry, int in_Ordered);
/** @fn extern MyoError myoiTargetFptrTableRegister(void *in_pAddrOfFptrTable,
* int in_NumEntry, int in_Ordered)
* @brief Register shared functions on target side. This function is the
* same as myoiHostFptrTableRegister, except it does not need to allocate
* thunks from non-coherent shared memory for each function entry, but
* instead looks up this information from a table retrieved from the
* Host side.
*
* @param in_pAddrOfFptrTable start address of the shared function
* table, assuming it follows the format of MyoiTargetSharedFptrEntry.
* @param in_NumEntry number of entry in the table.
* @param in_Ordered whether the table is ordered by function name.
* @return
* MYO_SUCCESS; or
* an error number to indicate the error.
**/
extern MyoError myoiTargetFptrTableRegister(
void *in_pAddrOfFptrTable, int in_NumEntry, int in_Ordered);
/**
* @endcond
**/
/* *************************************************************************** *\
APIs for remote function calls
\* *************************************************************************** */
typedef void * MyoiRFuncCallHandle;
/** @fn extern MyoiRFuncCallHandle myoiRemoteCall(char *in_pFuncName,
* void *in_pArgs, int in_deviceNum)
* @brief Call a remote callable function. If there are multiple arguments
* for the function, pack them to a shared buffer beforehand and take the
* address of the shared buffer as this function. After receiving the call
* requests from other peers, the arguments should be unpacked from the
* shared buffer before calling the target function. The shared buffer
* can also be used to store the return value of the function.
*
* @param in_pFuncName name of the function.
* @param in_pArgs address of the shared buffer.
* @return
* Handle used to check the result.
**/
MYOACCESSAPI
MyoiRFuncCallHandle myoiRemoteCall(const char *in_pFuncName, void *in_pArgs, int in_deviceNum);
/**
* @cond INCLUDE_MYO_INTERNAL_DOCUMENTATION
* @fn extern MyoError myoiRemoteThunkCall(void *in_funcThunkAddr, void *in_pArgs, int in_deviceNum)
* @brief Call a remote callable function. If there are multiple arguments for
* the function, pack them to a shared buffer beforehand and take the address
* of the shared buffer as this function. After receiving the call requests
* from other peers, the arguments should be unpacked from the shared buffer
* before calling the target function. The shared buffer can also be used to
* store the return value of the function.
*
* @param in_funcThunkAddr pointer to function thunk in the non-coherent
* shared memory.
* @param in_pArgs address of the shared buffer.
* @PARAM in_deviceNum: device ID (0-N-1) for the MIC device to run
* function call. -1 request causes MYO to schedule an available device.
* For RPC from device to host, in_deviceNum should always be -1.
* @return
* MYO_SUCCESS; or
* an error number to indicate the error.
**/
MYOACCESSAPI
MyoError myoiRemoteThunkCall(void *in_funcThunkAddr, void *in_pArgs, int in_deviceNum);
/**
* @endcond
**/
/** @fn extern MyoError myoiCheckResult(MyoiRFuncCallHandle in_Handle)
* @brief Check whether the remote call is done.
*
* @param in_Handle handle of the remote call.
* @return
* MYO_SUCCESS (done); or
* an error number to indicate the error.
**/
extern MyoError myoiCheckResult(MyoiRFuncCallHandle in_Handle);
/** @fn extern MyoError myoiGetResult(MyoiRFuncCallHandle in_Handle)
* @brief Wait till the remote call is done.
*
* @param in_Handle handle of the remote call.
* @return
* MYO_SUCCESS; or
* an error number to indicate the error.
**/
MYOACCESSAPI
MyoError myoiGetResult(MyoiRFuncCallHandle in_Handle);
/* **************************************************************************** *\
APIs related with shared variables.
\* **************************************************************************** */
/*
* It is Compiler's responsibility to make sure all shared variables
* located in shared memory space and have the same address in all sides.
* However, it is hard for Compiler to do this. So we propose a solution
* which is changing the definition of all shared variables and accessing
* them indirectly, and making sure all shared variables pointing
* to the same shared space on all sides. For example,
*
* "shared int a;" is changed to "shared int *a";
* Also all the accesses to "a" is change to "*a".
*
* We suppose the shared memory for each shared variable is allocated on
* host side by Compiler. For the upper example, Compiler can call:
*
* a = (shared int *) myoSharedMalloc(sizeof(shared int));
*
* Now the issue is how to make "a" on other sides also pointing to the
* same shared memory on other sides. We provide two methods to do this.
* They can be used in a hybrid way.
*/
/*
* The first method is calling myoiVarRegister for each shared variable
* on all sides in myoiUserInit. On host side, we will get a table containing
* a table containing the shared address and name of each shared variable.
* After calling myoiUserInit, we will propagate the table to other sides.
* On card side, after getting the table from host, myoiUserInit is called.
* When calling myoiVarRegister in myoiUserInit, we will make local pointer
* of each shared variable pointing to the same shared memory with the local
* pointer on host side of the same shared variable pointing to.
*/
/*
* The second method suppose that Compiler already have a table on all sides.
* On host side, the table contains the name and the shared address of each
* shared variable. On card side, the table contains the name of each shared
* variable and the address of the local pointer which will pointing to shared
* memory space.
*
* On host side, Compiler generates a call to myoiHostVarTablePropagate
* after initializing MYO runtime and making the host side table ready.
* On card side, Compiler uses myoiMicVarTableRegister to tell
* the runtime where the card side table is.
*
* Since there may be multiple libraries on card side for the same application,
* myoiHostVarTablePropagate and myoiMicVarTableRegister can be called multiple
* times and called simultaneously.
*
* Inside runtime, the local pointer of the same shared variable on all sides
* will be make sure pointing to the same shared space by using the information
* of the Compiler provided tables.
*/
/*
* Comipler knows the following two structures to make sure the var table
* has the following format.
*/
/*
* This is structure of the Shared var table entry. This table contains
* the shared address and name of each shared variable
*/
/** @fn extern MyoError myoiVarRegister(void *in_pAddrOfLocalPtrToShared, char *in_pSVarName)
* @brief Register shared variables. Call it on all sides in myoiUserInit.
* On host side, make sure calling it after allocating shared memory for
* the shared variables by calling myoSharedMalloc.
*
* @param in_pAddrOfLocalPtrToShared the address assigned by the compiler
* for the shared variable, which is the address of a local pointer,
* pointing to shared memory space.
* @param in_pSVarName name of shared variable.
* @return
* MYO_SUCCESS; or
* an error number to indicate the error.
**/
MYOACCESSAPI
MyoError myoiVarRegister(
void *in_pAddrOfLocalPtrToShared, const char *in_pSVarName);
/*
* Compiler knows the following two structures to make sure the var table
* has the following format.
*/
/**
* This is structure of the Shared var table entry. This table contains
* the shared address and name of each shared variable
**/
typedef struct {
//! Variable Name
const char *varName;
//! Shared Address
void *sharedAddr;
} MyoiSharedVarEntry;
//! Structure of the var table entry on host
typedef struct {
//! Variable Name
const char *varName;
//! Variable Size
int size;
//! Local pointer to Shared var
void *ptrToLocalPtrToShared;
} MyoiHostSharedVarEntry;
//! Structure of the var table entry on card
typedef struct {
//! Variable Name
const char *varName;
//! Local pointer to Shared var
void *ptrToLocalPtrToShared;
} MyoiMicSharedVarEntry;
/** @fn extern MyoError myoiHostVarTablePropagate(void *in_pAddrOfSVarTable, int in_NumEntry)
* @brief Send the host side var table to the card side. Card side will also
* have a copy of the host side var table after this propagation, although it
* is in an internal format different than the original host side var table,
* due to implementation convenience.
*
* @param in_pAddrOfSVarTable start address of the host side var table,
* assuming it follows the format of MyoiSharedVarEntry.
* @param in_NumEntry number of entry in the table.
* @return
* MYO_SUCCESS; or
* an error number to indicate the error.
**/
MYOACCESSAPI MyoError myoiHostVarTablePropagate(
void *in_pAddrOfSVarTable, int in_NumEntry);
/**
* @cond INCLUDE_MYO_INTERNAL_DOCUMENTATION
* @fn extern MyoError myoiMicVarTableRegister(void *in_pAddrOfSVarTable, int in_NumEntry)
* @brief Tell the runtime where the card side table is.
*
* @param in_pAddrOfSVarTable start address of the card side var
* table, assuming it follows the format of MyoiMicSharedVarEntry.
* @param in_NumEntry number of entry in the table.
* @return
* MYO_SUCCESS; or
* an error number to indicate the error.
**/
extern MyoError myoiMicVarTableRegister(
void *in_pAddrOfSVarTable, int in_NumEntry);
/**
* @endcond
**/
/** @fn MyoError myoiHostSharedMallocTableRegister(void *in_pAddrOfSVarTable, int in_NumEntry, int in_Ordered)
* @brief Allocate shared memory for all shared variables in the table.
* Also update local address of the shared variable with new shared address.
*
* @param in_pAddrOfSVarTable start address of the shared variable table,
* assuming it follows the format of MyoiHostSharedVarEntry.
* @param in_NumEntry number of entry in the table.
* @param in_Ordered whether the table ordered by name.
* @return
* MYO_SUCCESS; or
* an error number to indicate the error.
**/
MYOACCESSAPI
MyoError myoiHostSharedMallocTableRegister(
void *in_pAddrOfSVarTable, int in_NumEntry, int in_Ordered);
/** @fn extern MyoError myoiTargetSharedMallocTableRegister(void *in_pAddrOfSVarTable, int in_NumEntry, int in_Ordered)
* @brief Register the shared variables on the target side.
*
* @param in_pAddrOfSVarTable start address of the shared varaible table,
* assuming it follows the format of MyoiMicSharedVarEntry.
* @param in_NumEntry number of entry in the table.
* @param in_Ordered whether the table ordered by name.
* @return
* MYO_SUCCESS; or
* an error number to indicate the error.
**/
extern MyoError myoiTargetSharedMallocTableRegister(
void *in_pAddrOfSVarTable, int in_NumEntry, int in_Ordered);
/** @fn MyoError myoiLibInit(void * in_args, void (*userInitFunc))
* @brief Init entry of the MYO library responsible for initializing
* the runtime.
*
* @param in_args mechanism to pass arguments to the Initialization
* routine. The default value of NULL would mean the host is blocked
* on the completion of myoiLibInit() on all nodes. A subset of the
* installed cards can be intialized by passing an array of
* MyoiUserParams. For example, in a system with two cards, to run a
* MYO application only on the second card, intialize the array as
* follows:
* @code
* MyoiUserParams UserParas[64];
* UserParas[0].type = MYOI_USERPARAMS_DEVID;
* UserParas[0].nodeid = 2;
* UserParas[1].type = MYOI_USERPARAMS_LAST_MSG;
* if(MYO_SUCCESS != myoiLibInit(&UserParas, (void*)&myoiUserInit)) {
* printf("Failed to initialize MYO runtime\n");
* return -1;
* }
* @endcode
* This intialization is required only in the client/host side
* of the application. The server/card side executable should be
* executed only on the second card in this case.
*
* Another capability for the MyoiUserParams structure in MYO is specifying
* a remote procedure call to be executed on the host or card, immediately after
* myoiLibInit() completes. This capability is useful because some calls in
* MYO return immediately, but do not actually complete until after the MYO
* library is completely initialized on all peers. An example follows,
* showing how to cause MYO to execute the registered function named
* "PostMyoLibInitFunction" on the first card only:
* @code
* MyoiUserParams UserParas[64];
* UserParas[0].type = MYOI_USERPARAMS_POST_MYO_LIB_INIT_FUNC;
* UserParas[0].nodeid = 1;
* SetPostLibInitFuncName(UserParas[1], "PostMyoLibInitFunction");
* UserParas[2].type = MYOI_USERPARAMS_LAST_MSG;
* if(MYO_SUCCESS != myoiLibInit(&UserParas, (void*)&myoiUserInit)) {
* printf("Failed to initialize MYO runtime\n");
* return -1;
* }
* @endcode
*
* Note, to cause PostMyoLibInitFunction to be executed on ALL cards,
* specify: MYOI_USERPARAMS_POST_MYO_LIB_INIT_FUNC_ALL_NODES for the nodeid.
* That is:
* @code
* UserParas[0].nodeid = MYOI_USERPARAMS_POST_MYO_LIB_INIT_FUNC_ALL_NODES;
* @endcode
*
* @param userInitFunc Shared variables and remote functions are
* registered in this routine, which is called by the runtime during
* library initialization.
* @return
* MYO_SUCCESS;
* MYO_ERROR;
**/
MYOACCESSAPI
MyoError myoiLibInit(void * in_args, void *userInitFunc /*userInitFunc must be: MyoError (*userInitFunc)(void) */);
/** @fn extern MyoError myoiSupportsFeature(MyoFeatureType myoFeature)
* @brief Supports runtime query to determine whether a feature is supported
* by the myo that is installed on the system. This function is intended to
* support client code to query the myo library to determine whether its set
* of capabilities are able to support the client's needs.
*
* @param myoFeature The feature that is to be inquired about.
* @return
* MYO_SUCCESS; if the feature is supported.
* MYO_FEATURE_NOT_IMPLEMENTED if the feature is not supported.
*
* (For more information, please also see the declaration of the MyoFeatureType enum declaration.)
**/
MYOACCESSAPI
MyoError myoiSupportsFeature(MyoFeatureType myoFeature);
/** @fn void myoiLibFini()
* @brief Finalize the MYO library, all resources held by the runtime are
* released by this routine.
*
* @return
**/
MYOACCESSAPI
void myoiLibFini();
/* *************************************************************************** *\
APIs to set shared memory space consistent/non-consistent.
\* *************************************************************************** */
/** @fn extern MyoError myoiSetMemNonConsistent(void *in_pAddr, size_t in_Size)
* @brief Set part of the shared memory space to be non-consistent, which
* means that the consistency of this part of shared memory space does not
* need to be maintained between HOST and cards.
*
* @param in_pAddr The start address of the specified shared memory space;
* @param in_Size The size of the specified shared memory space;
* @return
* MYO_SUCCESS; or
* an error number to indicate the error.
**/
MYOACCESSAPI
MyoError myoiSetMemNonConsistent(void *in_pAddr, size_t in_Size);
/** @fn extern MyoError myoiSetMemConsistent(void *in_pAddr, size_t in_Size)
* @brief Set part of the shared memory space to be consistent, which
* means that the consistency of this part of shared memory space needs
* to be maintained between HOST and cards.
*
* @param in_pAddr The start address of the specified shared
* memory space.
* @param in_size The size of the specified shared memory space.
* @return
* MYO_SUCCESS; or
* an error number to indicate the error.
**/
MYOACCESSAPI
MyoError myoiSetMemConsistent(void *in_pAddr, size_t in_Size);
/* A collection of external data symbols */
EXTERN_C MYOACCESSAPI unsigned int myoiMyId; /* MYO_MYID if on accelerators */
EXTERN_C MYOACCESSAPI volatile int myoiInitFlag;
//! Structure of the array element that is passed to myoiLibInit() to initialize a subset of the available cards, or
//! to specify a remote call function to be called after successful myo library initialization:
typedef struct {
//!type = MYOI_USERPARAMS_DEVID or MYOI_USERPARAMS_POST_MYO_LIB_INIT_FUNC for each element in the array except
//!the last element, type should be: MYOI_USERPARAMS_LAST_MSG.
int type;
//! nodeid refers to the 'one-based' card index. Specifying, 1 represents the first card, mic0, 2 represents the
// second card, mic1, 3 represents the third card, mic2, ....).
// NOTE: for type == MYOI_USERPARAMS_POST_MYO_LIB_INIT_FUNC, specifying MYOI_USERPARAMS_POST_MYO_LIB_INIT_FUNC_ALL_NODES
// for nodeid, will execute the named function, on each card in the system, mic0, mic1, mic2, .... micn.
int nodeid;
} MyoiUserParams;
//!The following two types are dealt with entirely with just one MyoiUserParams structure:
//!MYOI_USERPARAMS_DEVID maps node ids.
#define MYOI_USERPARAMS_DEVID 1
//!MYOI_USERPARAMS_LAST_MSG terminates the array of MyoiUserParams.
#define MYOI_USERPARAMS_LAST_MSG -1
//!The following type requires setting the node id in a MyoiUserParams structure, and then following the struct
//!with a MyoiUserParamsPostLibInit union:
#define MYOI_USERPARAMS_POST_MYO_LIB_INIT_FUNC 2
//!nodeid can be one of the following macros, or a number >=1, corresponding to the card number (1 == mic0,
//!2 == mic1, 3 == mic2, ....)
//!Setting nodeid to MYOI_USERPARAMS_POST_MYO_LIB_INIT_FUNC_ALL_NODES causes the function to be called on all
//!cards:
#define MYOI_USERPARAMS_POST_MYO_LIB_INIT_FUNC_ALL_NODES 0
//!Setting nodeid to MYOI_USERPARAMS_POST_MYO_LIB_INIT_FUNC_HOST_NODE causes the function to be called on the
//!host instead of the card:
#define MYOI_USERPARAMS_POST_MYO_LIB_INIT_FUNC_HOST_NODE -1
//!The postLibInit union contains two members that serves two different purposes:
//!1. It can be used to stipulate the name of the function to be remotely called from host to card, on successful
//!myo library initialization, (member postLibInitRemoveFuncName) using the type:
//!MYOI_USERPARAMS_POST_MYO_LIB_INIT_FUNC. OR
//!2. It can be an actual function pointer (member name: postLibInitHostFuncAddress) that will be called on the host,
//!on successful myo library initialization, using the type: MYOI_USERPARAMS_POST_MYO_LIB_INIT_FUNC, with nodeid:
//!MYOI_USERPARAMS_POST_MYO_LIB_INIT_FUNC_HOST_NODE
typedef union {
const char *postLibInitRemoveFuncName;
void (*postLibInitHostFuncAddress)(void);
} MyoiUserParamsPostLibInit;
/* These are two macros to help get the information in a MyoiUserParamsPostLibInit union from a MyoiUserParams struct; */
#define GetPostLibInitFuncName(USERPARAMS) ((MyoiUserParamsPostLibInit *) (& (USERPARAMS)))->postLibInitRemoveFuncName
#define GetPostLibInitFuncAddr(USERPARAMS) ((MyoiUserParamsPostLibInit *) (& (USERPARAMS)))->postLibInitHostFuncAddress
/* These are two macros to help set the information in a MyoiUserParamsPostLibInit union from a MyoiUserParams struct; */
#define SetPostLibInitFuncName(USERPARAMS,FUNC_NAME) GetPostLibInitFuncName(USERPARAMS) = FUNC_NAME
#define SetPostLibInitFuncAddr(USERPARAMS,FUNC_ADDR) GetPostLibInitFuncAddr(USERPARAMS) = FUNC_ADDR
#ifdef __cplusplus
}
#endif
#endif // _MYO_IMPL_H_
/*! @} */