blob: 8a7b23fa3fd8ac2baa30710a58d41a4cc7350bc6 [file] [log] [blame] [edit]
// 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;
}