| // RUN: %libomptarget-compile-run-and-check-generic |
| // XFAIL: intelgpu |
| #include <assert.h> |
| #include <omp.h> |
| #include <stdio.h> |
| |
| // --------------------------------------------------------------------------- |
| // Various definitions copied from OpenMP RTL |
| |
| typedef struct { |
| uint64_t Reserved; |
| uint16_t Version; |
| uint16_t Kind; // OpenMP==1 |
| uint32_t Flags; |
| void *Address; |
| char *SymbolName; |
| uint64_t Size; |
| uint64_t Data; |
| void *AuxAddr; |
| } __tgt_offload_entry; |
| |
| enum OpenMPOffloadingDeclareTargetFlags { |
| /// Mark the entry global as having a 'link' attribute. |
| OMP_DECLARE_TARGET_LINK = 0x01, |
| /// Mark the entry global as being an indirectly callable function. |
| OMP_DECLARE_TARGET_INDIRECT = 0x08, |
| /// This is an entry corresponding to a requirement to be registered. |
| OMP_REGISTER_REQUIRES = 0x10, |
| /// Mark the entry global as being an indirect vtable. |
| OMP_DECLARE_TARGET_INDIRECT_VTABLE = 0x20, |
| }; |
| |
| #pragma omp begin declare variant match(device = {kind(gpu)}) |
| // Provided by the runtime. |
| void *__llvm_omp_indirect_call_lookup(void *host_ptr); |
| #pragma omp declare target to(__llvm_omp_indirect_call_lookup) \ |
| device_type(nohost) |
| #pragma omp end declare variant |
| |
| #pragma omp begin declare variant match(device = {kind(cpu)}) |
| // We assume unified addressing on the CPU target. |
| void *__llvm_omp_indirect_call_lookup(void *host_ptr) { return host_ptr; } |
| #pragma omp end declare variant |
| |
| #pragma omp begin declare target |
| void foo(int *i) { *i += 1; } |
| void bar(int *i) { *i += 10; } |
| void baz(int *i) { *i += 100; } |
| #pragma omp end declare target |
| |
| typedef void (*fptr_t)(int *i); |
| |
| // Dispatch Table - declare separately on host and device to avoid |
| // registering with the library; this also allows us to use separate |
| // names, which is convenient for debugging. This dispatchTable is |
| // intended to mimic what Clang emits for C++ vtables. |
| fptr_t dispatchTable[] = {foo, bar, baz}; |
| #pragma omp begin declare target device_type(nohost) |
| fptr_t GPUdispatchTable[] = {foo, bar, baz}; |
| fptr_t *GPUdispatchTablePtr = GPUdispatchTable; |
| #pragma omp end declare target |
| |
| // Define "manual" OpenMP offload entries, where we emit Clang |
| // offloading entry structure definitions in the appropriate ELF |
| // section. This allows us to emulate the offloading entries that Clang would |
| // normally emit for us |
| |
| __attribute__((weak, section("llvm_offload_entries"), aligned(8))) |
| const __tgt_offload_entry __offloading_entry[] = {{ |
| 0ULL, // Reserved |
| 1, // Version |
| 1, // Kind |
| OMP_DECLARE_TARGET_INDIRECT_VTABLE, // Flags |
| &dispatchTable, // Address |
| "GPUdispatchTablePtr", // SymbolName |
| (size_t)(sizeof(dispatchTable)), // Size |
| 0ULL, // Data |
| NULL // AuxAddr |
| }}; |
| |
| // Mimic how Clang emits vtable pointers for C++ classes |
| typedef struct { |
| fptr_t *dispatchPtr; |
| } myClass; |
| |
| // --------------------------------------------------------------------------- |
| int main() { |
| myClass obj_foo = {dispatchTable + 0}; |
| myClass obj_bar = {dispatchTable + 1}; |
| myClass obj_baz = {dispatchTable + 2}; |
| int aaa = 0; |
| |
| #pragma omp target map(aaa) map(to : obj_foo, obj_bar, obj_baz) |
| { |
| // Lookup |
| fptr_t *foo_ptr = __llvm_omp_indirect_call_lookup(obj_foo.dispatchPtr); |
| fptr_t *bar_ptr = __llvm_omp_indirect_call_lookup(obj_bar.dispatchPtr); |
| fptr_t *baz_ptr = __llvm_omp_indirect_call_lookup(obj_baz.dispatchPtr); |
| foo_ptr[0](&aaa); |
| bar_ptr[0](&aaa); |
| baz_ptr[0](&aaa); |
| } |
| |
| assert(aaa == 111); |
| // CHECK: PASS |
| printf("PASS\n"); |
| return 0; |
| } |