Skip to content

Commit c7c68f1

Browse files
authored
[Libomptarget] Allow the CPU targets to be built without libffi (#77495)
Summary: The CPU targets currently rely on `libffi` to invoke the "kernel" functions. Previously we would not build these if this dependency was not found. This patch copies th eapproach used for things like CUDA and HSA to dynamically load this if it is not found. The one sketchy thing this does is hard-code the default ABI for the target. These are normally defined on a per-file basis in the FFI source, so I had to fish out the expected values. We only use two types, so ideally we will always be able to use the default ABI. It's possible we could remove this dependency entirely in the future as well.
1 parent b6d1577 commit c7c68f1

File tree

5 files changed

+209
-102
lines changed

5 files changed

+209
-102
lines changed

openmp/libomptarget/cmake/Modules/LibomptargetGetDependencies.cmake

Lines changed: 2 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -50,52 +50,8 @@ endif()
5050
################################################################################
5151
# Looking for libffi...
5252
################################################################################
53-
find_package(PkgConfig)
54-
55-
pkg_check_modules(LIBOMPTARGET_SEARCH_LIBFFI QUIET libffi)
56-
57-
find_path (
58-
LIBOMPTARGET_DEP_LIBFFI_INCLUDE_DIR
59-
NAMES
60-
ffi.h
61-
HINTS
62-
${LIBOMPTARGET_SEARCH_LIBFFI_INCLUDEDIR}
63-
${LIBOMPTARGET_SEARCH_LIBFFI_INCLUDE_DIRS}
64-
PATHS
65-
/usr/include
66-
/usr/local/include
67-
/opt/local/include
68-
/sw/include
69-
ENV CPATH)
70-
71-
# Don't bother look for the library if the header files were not found.
72-
if (LIBOMPTARGET_DEP_LIBFFI_INCLUDE_DIR)
73-
find_library (
74-
LIBOMPTARGET_DEP_LIBFFI_LIBRARIES
75-
NAMES
76-
ffi
77-
HINTS
78-
${LIBOMPTARGET_SEARCH_LIBFFI_LIBDIR}
79-
${LIBOMPTARGET_SEARCH_LIBFFI_LIBRARY_DIRS}
80-
PATHS
81-
/usr/lib
82-
/usr/local/lib
83-
/opt/local/lib
84-
/sw/lib
85-
ENV LIBRARY_PATH
86-
ENV LD_LIBRARY_PATH)
87-
endif()
88-
89-
set(LIBOMPTARGET_DEP_LIBFFI_INCLUDE_DIRS ${LIBOMPTARGET_DEP_LIBFFI_INCLUDE_DIR})
90-
find_package_handle_standard_args(
91-
LIBOMPTARGET_DEP_LIBFFI
92-
DEFAULT_MSG
93-
LIBOMPTARGET_DEP_LIBFFI_LIBRARIES
94-
LIBOMPTARGET_DEP_LIBFFI_INCLUDE_DIRS)
95-
96-
mark_as_advanced(
97-
LIBOMPTARGET_DEP_LIBFFI_INCLUDE_DIRS
98-
LIBOMPTARGET_DEP_LIBFFI_LIBRARIES)
53+
find_package(FFI QUIET)
54+
set(LIBOMPTARGET_DEP_LIBFFI_FOUND ${FFI_FOUND})
9955

10056
################################################################################
10157
# Looking for CUDA...

openmp/libomptarget/plugins-nextgen/CMakeLists.txt

Lines changed: 59 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -19,71 +19,74 @@ add_subdirectory(common)
1919
# - tmachine_libname: machine name to be appended to the plugin library name.
2020
macro(build_generic_elf64 tmachine tmachine_name tmachine_libname tmachine_triple elf_machine_id)
2121
if(CMAKE_SYSTEM_PROCESSOR MATCHES "${tmachine}$")
22-
if(LIBOMPTARGET_DEP_LIBFFI_FOUND)
23-
24-
libomptarget_say("Building ${tmachine_name} NextGen offloading plugin.")
25-
26-
# Define macro to be used as prefix of the runtime messages for this target.
27-
add_definitions("-DTARGET_NAME=${tmachine_name}")
22+
# Define macro to be used as prefix of the runtime messages for this target.
23+
add_definitions("-DTARGET_NAME=${tmachine_name}")
2824

29-
# Define debug prefix. TODO: This should be automatized in the Debug.h but
30-
# it requires changing the original plugins.
31-
add_definitions(-DDEBUG_PREFIX="TARGET ${tmachine_name} RTL")
25+
# Define debug prefix. TODO: This should be automatized in the Debug.h but
26+
# it requires changing the original plugins.
27+
add_definitions(-DDEBUG_PREFIX="TARGET ${tmachine_name} RTL")
3228

33-
# Define macro with the ELF ID for this target.
34-
add_definitions("-DTARGET_ELF_ID=${elf_machine_id}")
29+
# Define the macro with the ELF e_machine for this target.
30+
add_definitions("-DTARGET_ELF_ID=${elf_machine_id}")
3531

36-
# Define target regiple
37-
add_definitions("-DLIBOMPTARGET_NEXTGEN_GENERIC_PLUGIN_TRIPLE=${tmachine}")
32+
# Define target triple
33+
add_definitions("-DLIBOMPTARGET_NEXTGEN_GENERIC_PLUGIN_TRIPLE=${tmachine}")
3834

39-
add_llvm_library("omptarget.rtl.${tmachine_libname}"
40-
SHARED
35+
add_llvm_library("omptarget.rtl.${tmachine_libname}"
36+
SHARED
4137

42-
${CMAKE_CURRENT_SOURCE_DIR}/../generic-elf-64bit/src/rtl.cpp
38+
${CMAKE_CURRENT_SOURCE_DIR}/../generic-elf-64bit/src/rtl.cpp
4339

44-
ADDITIONAL_HEADER_DIRS
40+
ADDITIONAL_HEADER_DIRS
4541
${LIBOMPTARGET_INCLUDE_DIR}
46-
${LIBOMPTARGET_DEP_LIBFFI_INCLUDE_DIR}
47-
48-
LINK_LIBS
49-
PRIVATE
50-
PluginCommon
51-
${LIBOMPTARGET_DEP_LIBFFI_LIBRARIES}
52-
${OPENMP_PTHREAD_LIB}
53-
54-
NO_INSTALL_RPATH
55-
)
56-
57-
if ((OMPT_TARGET_DEFAULT) AND (LIBOMPTARGET_OMPT_SUPPORT))
58-
target_link_libraries("omptarget.rtl.${tmachine_libname}" PRIVATE OMPT)
59-
endif()
60-
61-
if (LIBOMP_HAVE_VERSION_SCRIPT_FLAG)
62-
target_link_libraries("omptarget.rtl.${tmachine_libname}" PRIVATE
63-
"-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/../exports")
64-
endif()
65-
66-
# Install plugin under the lib destination folder.
67-
install(TARGETS "omptarget.rtl.${tmachine_libname}"
68-
LIBRARY DESTINATION "${OPENMP_INSTALL_LIBDIR}")
69-
set_target_properties("omptarget.rtl.${tmachine_libname}" PROPERTIES
70-
INSTALL_RPATH "$ORIGIN" BUILD_RPATH "$ORIGIN:${CMAKE_CURRENT_BINARY_DIR}/.."
71-
POSITION_INDEPENDENT_CODE ON
72-
CXX_VISIBILITY_PRESET protected)
73-
74-
target_include_directories( "omptarget.rtl.${tmachine_libname}" PRIVATE
75-
${LIBOMPTARGET_INCLUDE_DIR}
76-
${LIBOMPTARGET_DEP_LIBFFI_INCLUDE_DIR})
7742

78-
list(APPEND LIBOMPTARGET_TESTED_PLUGINS "omptarget.rtl.${tmachine_libname}")
79-
set(LIBOMPTARGET_TESTED_PLUGINS
80-
"${LIBOMPTARGET_TESTED_PLUGINS}" PARENT_SCOPE)
81-
set(LIBOMPTARGET_SYSTEM_TARGETS
82-
"${LIBOMPTARGET_SYSTEM_TARGETS} ${tmachine_triple} ${tmachine_triple}-LTO" PARENT_SCOPE)
43+
LINK_LIBS
44+
PRIVATE
45+
PluginCommon
46+
${OPENMP_PTHREAD_LIB}
47+
48+
NO_INSTALL_RPATH
49+
)
8350

84-
else(LIBOMPTARGET_DEP_LIBFFI_FOUND)
85-
libomptarget_say("Not building ${tmachine_name} NextGen offloading plugin: libffi dependency not found.")
86-
endif(LIBOMPTARGET_DEP_LIBFFI_FOUND)
51+
if(LIBOMPTARGET_DEP_LIBFFI_FOUND)
52+
libomptarget_say("Building ${tmachine_libname} plugin linked with libffi")
53+
target_link_libraries("omptarget.rtl.${tmachine_libname}" PRIVATE
54+
${FFI_LIBRARIES})
55+
target_include_directories("omptarget.rtl.${tmachine_libname}" PRIVATE
56+
${FFI_INCLUDE_DIRS})
57+
else()
58+
libomptarget_say("Building ${tmachine_libname} plugie for dlopened libffi")
59+
target_sources("omptarget.rtl.${tmachine_libname}" PRIVATE
60+
${CMAKE_CURRENT_SOURCE_DIR}/../generic-elf-64bit/dynamic_ffi/ffi.cpp)
61+
target_include_directories("omptarget.rtl.${tmachine_libname}" PRIVATE
62+
${CMAKE_CURRENT_SOURCE_DIR}/../generic-elf-64bit/dynamic_ffi)
63+
endif()
64+
65+
if(OMPT_TARGET_DEFAULT AND LIBOMPTARGET_OMPT_SUPPORT)
66+
target_link_libraries("omptarget.rtl.${tmachine_libname}" PRIVATE OMPT)
67+
endif()
68+
69+
if(LIBOMP_HAVE_VERSION_SCRIPT_FLAG)
70+
target_link_libraries("omptarget.rtl.${tmachine_libname}" PRIVATE
71+
"-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/../exports")
72+
endif()
73+
74+
# Install plugin under the lib destination folder.
75+
install(TARGETS "omptarget.rtl.${tmachine_libname}"
76+
LIBRARY DESTINATION "${OPENMP_INSTALL_LIBDIR}")
77+
set_target_properties("omptarget.rtl.${tmachine_libname}" PROPERTIES
78+
INSTALL_RPATH "$ORIGIN" BUILD_RPATH "$ORIGIN:${CMAKE_CURRENT_BINARY_DIR}/.."
79+
POSITION_INDEPENDENT_CODE ON
80+
CXX_VISIBILITY_PRESET protected)
81+
82+
target_include_directories("omptarget.rtl.${tmachine_libname}" PRIVATE
83+
${LIBOMPTARGET_INCLUDE_DIR})
84+
85+
list(APPEND LIBOMPTARGET_TESTED_PLUGINS "omptarget.rtl.${tmachine_libname}")
86+
set(LIBOMPTARGET_TESTED_PLUGINS
87+
"${LIBOMPTARGET_TESTED_PLUGINS}" PARENT_SCOPE)
88+
set(LIBOMPTARGET_SYSTEM_TARGETS
89+
"${LIBOMPTARGET_SYSTEM_TARGETS} ${tmachine_triple} ${tmachine_triple}-LTO" PARENT_SCOPE)
8790
else()
8891
libomptarget_say("Not building ${tmachine_name} NextGen offloading plugin: machine not found in the system.")
8992
endif()
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
//===--- generic-elf-64bit/dynamic_ffi/ffi.cpp -------------------- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Implement subset of the FFI api by calling into the FFI library via dlopen
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "llvm/Support/DynamicLibrary.h"
14+
#include <memory>
15+
16+
#include "DLWrap.h"
17+
#include "ffi.h"
18+
19+
DLWRAP_INITIALIZE()
20+
21+
DLWRAP(ffi_call, 4);
22+
DLWRAP(ffi_prep_cif, 5);
23+
24+
DLWRAP_FINALIZE()
25+
26+
ffi_type ffi_type_void;
27+
ffi_type ffi_type_pointer;
28+
29+
// Name of the FFI shared library.
30+
constexpr const char *FFI_PATH = "libffi.so";
31+
32+
#define DYNAMIC_FFI_SUCCESS 0
33+
#define DYNAMIC_FFI_FAIL 1
34+
35+
// Initializes the dynamic FFI wrapper.
36+
uint32_t ffi_init() {
37+
std::string ErrMsg;
38+
auto DynlibHandle = std::make_unique<llvm::sys::DynamicLibrary>(
39+
llvm::sys::DynamicLibrary::getPermanentLibrary(FFI_PATH, &ErrMsg));
40+
if (!DynlibHandle->isValid())
41+
return DYNAMIC_FFI_FAIL;
42+
43+
for (size_t I = 0; I < dlwrap::size(); I++) {
44+
const char *Sym = dlwrap::symbol(I);
45+
46+
void *P = DynlibHandle->getAddressOfSymbol(Sym);
47+
if (P == nullptr)
48+
return DYNAMIC_FFI_FAIL;
49+
50+
*dlwrap::pointer(I) = P;
51+
}
52+
53+
#define DYNAMIC_INIT(SYMBOL) \
54+
{ \
55+
void *SymbolPtr = DynlibHandle->getAddressOfSymbol(#SYMBOL); \
56+
if (!SymbolPtr) \
57+
return DYNAMIC_FFI_FAIL; \
58+
SYMBOL = *reinterpret_cast<decltype(SYMBOL) *>(SymbolPtr); \
59+
}
60+
DYNAMIC_INIT(ffi_type_void);
61+
DYNAMIC_INIT(ffi_type_pointer);
62+
#undef DYNAMIC_INIT
63+
64+
return DYNAMIC_FFI_SUCCESS;
65+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
//===--- generic-elf-64bit/dynamic_ffi/ffi.cpp -------------------- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Provides a mirror to the parts of the FFI interface that the plugins require.
10+
//
11+
// libffi
12+
// - Copyright (c) 2011, 2014, 2019, 2021, 2022 Anthony Green
13+
// - Copyright (c) 1996-2003, 2007, 2008 Red Hat, Inc.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef DYNAMIC_FFI_FFI_H
18+
#define DYNAMIC_FFI_FFI_H
19+
20+
#include <stddef.h>
21+
#include <stdint.h>
22+
23+
#define USES_DYNAMIC_FFI
24+
25+
uint32_t ffi_init();
26+
27+
typedef struct _ffi_type {
28+
size_t size;
29+
unsigned short alignment;
30+
unsigned short type;
31+
struct _ffi_type **elements;
32+
} ffi_type;
33+
34+
typedef enum {
35+
FFI_OK = 0,
36+
FFI_BAD_TYPEDEF,
37+
FFI_BAD_ABI,
38+
FFI_BAD_ARGTYPE
39+
} ffi_status;
40+
41+
// These are target depenent so we set them manually for each ABI by referencing
42+
// the FFI source.
43+
typedef enum ffi_abi {
44+
#if (defined(_M_X64) || defined(__x86_64__))
45+
FFI_DEFAULT_ABI = 2, // FFI_UNIX64.
46+
#elif defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64)
47+
FFI_DEFAULT_ABI = 1, // FFI_SYSV.
48+
#elif defined(__powerpc64__)
49+
FFI_DEFAULT_ABI = 8, // FFI_LINUX.
50+
#elif defined(__s390x__)
51+
FFI_DEFAULT_ABI = 1, // FFI_SYSV.
52+
#else
53+
#error "Unknown ABI"
54+
#endif
55+
} ffi_cif;
56+
57+
#ifdef __cplusplus
58+
extern "C" {
59+
#endif
60+
61+
#define FFI_EXTERN extern
62+
#define FFI_API
63+
64+
FFI_EXTERN ffi_type ffi_type_void;
65+
FFI_EXTERN ffi_type ffi_type_pointer;
66+
67+
FFI_API
68+
void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue);
69+
70+
FFI_API
71+
ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs,
72+
ffi_type *rtype, ffi_type **atypes);
73+
74+
#ifdef __cplusplus
75+
}
76+
#endif
77+
78+
#endif // DYNAMIC_FFI_FFI_H

openmp/libomptarget/plugins-nextgen/generic-elf-64bit/src/rtl.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,11 @@ struct GenELF64PluginTy final : public GenericPluginTy {
383383
ompt::connectLibrary();
384384
#endif
385385

386+
#ifdef USES_DYNAMIC_FFI
387+
if (auto Err = Plugin::check(ffi_init(), "Failed to initialize libffi"))
388+
return std::move(Err);
389+
#endif
390+
386391
return NUM_DEVICES;
387392
}
388393

0 commit comments

Comments
 (0)