diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -381,7 +381,7 @@ cast(*S)); break; case Stmt::OMPInteropDirectiveClass: - llvm_unreachable("Interop directive not supported yet."); + EmitOMPInteropDirective(cast(*S)); break; case Stmt::OMPDispatchDirectiveClass: llvm_unreachable("Dispatch directive not supported yet."); diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -6300,6 +6300,58 @@ [](CodeGenFunction &) { return nullptr; }); } +void CodeGenFunction::EmitOMPInteropDirective(const OMPInteropDirective &S) { + llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder(); + llvm::Value *Device = nullptr; + if (const auto *C = S.getSingleClause()) + Device = EmitScalarExpr(C->getDevice()); + + llvm::Value *NumDependences = nullptr; + llvm::Value *DependenceAddress = nullptr; + if (const auto *DC = S.getSingleClause()) { + OMPTaskDataTy::DependData Dependencies(DC->getDependencyKind(), + DC->getModifier()); + Dependencies.DepExprs.append(DC->varlist_begin(), DC->varlist_end()); + std::pair DependencePair = + CGM.getOpenMPRuntime().emitDependClause(*this, Dependencies, + DC->getBeginLoc()); + NumDependences = DependencePair.first; + DependenceAddress = Builder.CreatePointerCast( + DependencePair.second.getPointer(), CGM.Int8PtrTy); + } + + assert (!(S.hasClausesOfKind() && + !(S.getSingleClause() || + S.getSingleClause() || + S.getSingleClause())) && + "OMPNowaitClause clause is used separately in OMPInteropDirective."); + + if (const auto *C = S.getSingleClause()) { + llvm::Value *InteropvarPtr = + EmitLValue(C->getInteropVar()).getPointer(*this); + llvm::omp::OMPInteropType InteropType = llvm::omp::OMPInteropType::Unknown; + if (C->getIsTarget()) + InteropType = llvm::omp::OMPInteropType::Target; + else if (C->getIsTargetSync()) + InteropType = llvm::omp::OMPInteropType::TargetSync; + OMPBuilder.createOMPInteropInit(Builder, InteropvarPtr, InteropType, Device, + NumDependences, DependenceAddress, + S.hasClausesOfKind()); + } else if (const auto *C = S.getSingleClause()) { + llvm::Value *InteropvarPtr = + EmitLValue(C->getInteropVar()).getPointer(*this); + OMPBuilder.createOMPInteropDestroy(Builder, InteropvarPtr, Device, + NumDependences, DependenceAddress, + S.hasClausesOfKind()); + } else if (const auto *C = S.getSingleClause()) { + llvm::Value *InteropvarPtr = + EmitLValue(C->getInteropVar()).getPointer(*this); + OMPBuilder.createOMPInteropUse(Builder, InteropvarPtr, Device, + NumDependences, DependenceAddress, + S.hasClausesOfKind()); + } +} + static void emitTargetTeamsDistributeParallelForRegion( CodeGenFunction &CGF, const OMPTargetTeamsDistributeParallelForDirective &S, PrePostActionTy &Action) { diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -3511,6 +3511,7 @@ const OMPTargetTeamsDistributeParallelForSimdDirective &S); void EmitOMPTargetTeamsDistributeSimdDirective( const OMPTargetTeamsDistributeSimdDirective &S); + void EmitOMPInteropDirective(const OMPInteropDirective &S); /// Emit device code for the target directive. static void EmitOMPTargetDeviceFunction(CodeGenModule &CGM, diff --git a/clang/test/OpenMP/interop_irbuilder.cpp b/clang/test/OpenMP/interop_irbuilder.cpp new file mode 100644 --- /dev/null +++ b/clang/test/OpenMP/interop_irbuilder.cpp @@ -0,0 +1,219 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --include-generated-funcs +// RUN: %clang_cc1 -verify -fopenmp -x c++ -emit-llvm %s -o - | FileCheck %s + +// expected-no-diagnostics +typedef void *omp_interop_t; + +void test1() { + + int device_id = 4; + int D0, D1; + omp_interop_t interop; + + #pragma omp interop init(target: interop) + + #pragma omp interop init(targetsync: interop) + + #pragma omp interop init(target: interop) device(device_id) + + #pragma omp interop init(targetsync: interop) device(device_id) + + #pragma omp interop use(interop) depend(in:D0, D1) nowait + + #pragma omp interop destroy(interop) depend(in:D0, D1) +} + +// ###: %clang_cc1 -verify -fopenmp -emit-llvm -o -| FileCheck %s +// CHECK-64-LABEL: @_Z5test1v( +// CHECK-64-NEXT: entry: +// CHECK-64-NEXT: [[DEVICE_ID:%.*]] = alloca i32, align 4 +// CHECK-64-NEXT: [[D0:%.*]] = alloca i32, align 4 +// CHECK-64-NEXT: [[D1:%.*]] = alloca i32, align 4 +// CHECK-64-NEXT: [[INTEROP:%.*]] = alloca i8*, align 8 +// CHECK-64-NEXT: [[DOTDEP_ARR_ADDR:%.*]] = alloca [2 x %struct.kmp_depend_info], align 8 +// CHECK-64-NEXT: [[DEP_COUNTER_ADDR:%.*]] = alloca i64, align 8 +// CHECK-64-NEXT: [[DOTDEP_ARR_ADDR5:%.*]] = alloca [2 x %struct.kmp_depend_info], align 8 +// CHECK-64-NEXT: [[DEP_COUNTER_ADDR6:%.*]] = alloca i64, align 8 +// CHECK-64-NEXT: store i32 4, i32* [[DEVICE_ID]], align 4 +// CHECK-64-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1:[0-9]+]]) +// CHECK-64-NEXT: call void @__kmpc_interop_init(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM]], i8** [[INTEROP]], i64 1, i32 -1, i32 0, i8* null, i32 0) +// CHECK-64-NEXT: [[OMP_GLOBAL_THREAD_NUM1:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1]]) +// CHECK-64-NEXT: call void @__kmpc_interop_init(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM1]], i8** [[INTEROP]], i64 2, i32 -1, i32 0, i8* null, i32 0) +// CHECK-64-NEXT: [[TMP0:%.*]] = load i32, i32* [[DEVICE_ID]], align 4 +// CHECK-64-NEXT: [[OMP_GLOBAL_THREAD_NUM2:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1]]) +// CHECK-64-NEXT: call void @__kmpc_interop_init(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM2]], i8** [[INTEROP]], i64 1, i32 [[TMP0]], i32 0, i8* null, i32 0) +// CHECK-64-NEXT: [[TMP1:%.*]] = load i32, i32* [[DEVICE_ID]], align 4 +// CHECK-64-NEXT: [[OMP_GLOBAL_THREAD_NUM3:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1]]) +// CHECK-64-NEXT: call void @__kmpc_interop_init(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM3]], i8** [[INTEROP]], i64 2, i32 [[TMP1]], i32 0, i8* null, i32 0) +// CHECK-64-NEXT: [[TMP2:%.*]] = getelementptr inbounds [2 x %struct.kmp_depend_info], [2 x %struct.kmp_depend_info]* [[DOTDEP_ARR_ADDR]], i64 0, i64 0 +// CHECK-64-NEXT: [[TMP3:%.*]] = getelementptr [[STRUCT_KMP_DEPEND_INFO:%.*]], %struct.kmp_depend_info* [[TMP2]], i64 0 +// CHECK-64-NEXT: [[TMP4:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP3]], i32 0, i32 0 +// CHECK-64-NEXT: [[TMP5:%.*]] = ptrtoint i32* [[D0]] to i64 +// CHECK-64-NEXT: store i64 [[TMP5]], i64* [[TMP4]], align 8 +// CHECK-64-NEXT: [[TMP6:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP3]], i32 0, i32 1 +// CHECK-64-NEXT: store i64 4, i64* [[TMP6]], align 8 +// CHECK-64-NEXT: [[TMP7:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP3]], i32 0, i32 2 +// CHECK-64-NEXT: store i8 1, i8* [[TMP7]], align 8 +// CHECK-64-NEXT: [[TMP8:%.*]] = getelementptr [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP2]], i64 1 +// CHECK-64-NEXT: [[TMP9:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP8]], i32 0, i32 0 +// CHECK-64-NEXT: [[TMP10:%.*]] = ptrtoint i32* [[D1]] to i64 +// CHECK-64-NEXT: store i64 [[TMP10]], i64* [[TMP9]], align 8 +// CHECK-64-NEXT: [[TMP11:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP8]], i32 0, i32 1 +// CHECK-64-NEXT: store i64 4, i64* [[TMP11]], align 8 +// CHECK-64-NEXT: [[TMP12:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP8]], i32 0, i32 2 +// CHECK-64-NEXT: store i8 1, i8* [[TMP12]], align 8 +// CHECK-64-NEXT: store i64 2, i64* [[DEP_COUNTER_ADDR]], align 8 +// CHECK-64-NEXT: [[TMP13:%.*]] = bitcast %struct.kmp_depend_info* [[TMP2]] to i8* +// CHECK-64-NEXT: [[OMP_GLOBAL_THREAD_NUM4:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1]]) +// CHECK-64-NEXT: call void @__kmpc_interop_use(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM4]], i8** [[INTEROP]], i32 -1, i32 2, i8* [[TMP13]], i32 1) +// CHECK-64-NEXT: [[TMP14:%.*]] = getelementptr inbounds [2 x %struct.kmp_depend_info], [2 x %struct.kmp_depend_info]* [[DOTDEP_ARR_ADDR5]], i64 0, i64 0 +// CHECK-64-NEXT: [[TMP15:%.*]] = getelementptr [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP14]], i64 0 +// CHECK-64-NEXT: [[TMP16:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP15]], i32 0, i32 0 +// CHECK-64-NEXT: [[TMP17:%.*]] = ptrtoint i32* [[D0]] to i64 +// CHECK-64-NEXT: store i64 [[TMP17]], i64* [[TMP16]], align 8 +// CHECK-64-NEXT: [[TMP18:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP15]], i32 0, i32 1 +// CHECK-64-NEXT: store i64 4, i64* [[TMP18]], align 8 +// CHECK-64-NEXT: [[TMP19:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP15]], i32 0, i32 2 +// CHECK-64-NEXT: store i8 1, i8* [[TMP19]], align 8 +// CHECK-64-NEXT: [[TMP20:%.*]] = getelementptr [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP14]], i64 1 +// CHECK-64-NEXT: [[TMP21:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP20]], i32 0, i32 0 +// CHECK-64-NEXT: [[TMP22:%.*]] = ptrtoint i32* [[D1]] to i64 +// CHECK-64-NEXT: store i64 [[TMP22]], i64* [[TMP21]], align 8 +// CHECK-64-NEXT: [[TMP23:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP20]], i32 0, i32 1 +// CHECK-64-NEXT: store i64 4, i64* [[TMP23]], align 8 +// CHECK-64-NEXT: [[TMP24:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP20]], i32 0, i32 2 +// CHECK-64-NEXT: store i8 1, i8* [[TMP24]], align 8 +// CHECK-64-NEXT: store i64 2, i64* [[DEP_COUNTER_ADDR6]], align 8 +// CHECK-64-NEXT: [[TMP25:%.*]] = bitcast %struct.kmp_depend_info* [[TMP14]] to i8* +// CHECK-64-NEXT: [[OMP_GLOBAL_THREAD_NUM7:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1]]) +// CHECK-64-NEXT: call void @__kmpc_interop_destroy(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM7]], i8** [[INTEROP]], i32 -1, i32 2, i8* [[TMP25]], i32 0) +// CHECK-64-NEXT: ret void +// OMP45-LABEL: @_Z5test1v( +// OMP45-NEXT: entry: +// OMP45-NEXT: [[DEVICE_ID:%.*]] = alloca i32, align 4 +// OMP45-NEXT: [[D0:%.*]] = alloca i32, align 4 +// OMP45-NEXT: [[D1:%.*]] = alloca i32, align 4 +// OMP45-NEXT: [[INTEROP:%.*]] = alloca i8*, align 8 +// OMP45-NEXT: [[DOTDEP_ARR_ADDR:%.*]] = alloca [2 x %struct.kmp_depend_info], align 8 +// OMP45-NEXT: [[DEP_COUNTER_ADDR:%.*]] = alloca i64, align 8 +// OMP45-NEXT: [[DOTDEP_ARR_ADDR5:%.*]] = alloca [2 x %struct.kmp_depend_info], align 8 +// OMP45-NEXT: [[DEP_COUNTER_ADDR6:%.*]] = alloca i64, align 8 +// OMP45-NEXT: store i32 4, i32* [[DEVICE_ID]], align 4 +// OMP45-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1:[0-9]+]]) +// OMP45-NEXT: call void @__kmpc_interop_init(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM]], i8** [[INTEROP]], i64 1, i32 -1, i32 0, i8* null, i32 0) +// OMP45-NEXT: [[OMP_GLOBAL_THREAD_NUM1:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1]]) +// OMP45-NEXT: call void @__kmpc_interop_init(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM1]], i8** [[INTEROP]], i64 2, i32 -1, i32 0, i8* null, i32 0) +// OMP45-NEXT: [[TMP0:%.*]] = load i32, i32* [[DEVICE_ID]], align 4 +// OMP45-NEXT: [[OMP_GLOBAL_THREAD_NUM2:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1]]) +// OMP45-NEXT: call void @__kmpc_interop_init(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM2]], i8** [[INTEROP]], i64 1, i32 [[TMP0]], i32 0, i8* null, i32 0) +// OMP45-NEXT: [[TMP1:%.*]] = load i32, i32* [[DEVICE_ID]], align 4 +// OMP45-NEXT: [[OMP_GLOBAL_THREAD_NUM3:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1]]) +// OMP45-NEXT: call void @__kmpc_interop_init(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM3]], i8** [[INTEROP]], i64 2, i32 [[TMP1]], i32 0, i8* null, i32 0) +// OMP45-NEXT: [[TMP2:%.*]] = getelementptr inbounds [2 x %struct.kmp_depend_info], [2 x %struct.kmp_depend_info]* [[DOTDEP_ARR_ADDR]], i64 0, i64 0 +// OMP45-NEXT: [[TMP3:%.*]] = getelementptr [[STRUCT_KMP_DEPEND_INFO:%.*]], %struct.kmp_depend_info* [[TMP2]], i64 0 +// OMP45-NEXT: [[TMP4:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP3]], i32 0, i32 0 +// OMP45-NEXT: [[TMP5:%.*]] = ptrtoint i32* [[D0]] to i64 +// OMP45-NEXT: store i64 [[TMP5]], i64* [[TMP4]], align 8 +// OMP45-NEXT: [[TMP6:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP3]], i32 0, i32 1 +// OMP45-NEXT: store i64 4, i64* [[TMP6]], align 8 +// OMP45-NEXT: [[TMP7:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP3]], i32 0, i32 2 +// OMP45-NEXT: store i8 1, i8* [[TMP7]], align 8 +// OMP45-NEXT: [[TMP8:%.*]] = getelementptr [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP2]], i64 1 +// OMP45-NEXT: [[TMP9:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP8]], i32 0, i32 0 +// OMP45-NEXT: [[TMP10:%.*]] = ptrtoint i32* [[D1]] to i64 +// OMP45-NEXT: store i64 [[TMP10]], i64* [[TMP9]], align 8 +// OMP45-NEXT: [[TMP11:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP8]], i32 0, i32 1 +// OMP45-NEXT: store i64 4, i64* [[TMP11]], align 8 +// OMP45-NEXT: [[TMP12:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP8]], i32 0, i32 2 +// OMP45-NEXT: store i8 1, i8* [[TMP12]], align 8 +// OMP45-NEXT: store i64 2, i64* [[DEP_COUNTER_ADDR]], align 8 +// OMP45-NEXT: [[TMP13:%.*]] = bitcast %struct.kmp_depend_info* [[TMP2]] to i8* +// OMP45-NEXT: [[OMP_GLOBAL_THREAD_NUM4:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1]]) +// OMP45-NEXT: call void @__kmpc_interop_use(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM4]], i8** [[INTEROP]], i32 -1, i32 2, i8* [[TMP13]], i32 1) +// OMP45-NEXT: [[TMP14:%.*]] = getelementptr inbounds [2 x %struct.kmp_depend_info], [2 x %struct.kmp_depend_info]* [[DOTDEP_ARR_ADDR5]], i64 0, i64 0 +// OMP45-NEXT: [[TMP15:%.*]] = getelementptr [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP14]], i64 0 +// OMP45-NEXT: [[TMP16:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP15]], i32 0, i32 0 +// OMP45-NEXT: [[TMP17:%.*]] = ptrtoint i32* [[D0]] to i64 +// OMP45-NEXT: store i64 [[TMP17]], i64* [[TMP16]], align 8 +// OMP45-NEXT: [[TMP18:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP15]], i32 0, i32 1 +// OMP45-NEXT: store i64 4, i64* [[TMP18]], align 8 +// OMP45-NEXT: [[TMP19:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP15]], i32 0, i32 2 +// OMP45-NEXT: store i8 1, i8* [[TMP19]], align 8 +// OMP45-NEXT: [[TMP20:%.*]] = getelementptr [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP14]], i64 1 +// OMP45-NEXT: [[TMP21:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP20]], i32 0, i32 0 +// OMP45-NEXT: [[TMP22:%.*]] = ptrtoint i32* [[D1]] to i64 +// OMP45-NEXT: store i64 [[TMP22]], i64* [[TMP21]], align 8 +// OMP45-NEXT: [[TMP23:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP20]], i32 0, i32 1 +// OMP45-NEXT: store i64 4, i64* [[TMP23]], align 8 +// OMP45-NEXT: [[TMP24:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP20]], i32 0, i32 2 +// OMP45-NEXT: store i8 1, i8* [[TMP24]], align 8 +// OMP45-NEXT: store i64 2, i64* [[DEP_COUNTER_ADDR6]], align 8 +// OMP45-NEXT: [[TMP25:%.*]] = bitcast %struct.kmp_depend_info* [[TMP14]] to i8* +// OMP45-NEXT: [[OMP_GLOBAL_THREAD_NUM7:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1]]) +// OMP45-NEXT: call void @__kmpc_interop_destroy(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM7]], i8** [[INTEROP]], i32 -1, i32 2, i8* [[TMP25]], i32 0) +// OMP45-NEXT: ret void +// CHECK-LABEL: @_Z5test1v( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[DEVICE_ID:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[D0:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[D1:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[INTEROP:%.*]] = alloca i8*, align 8 +// CHECK-NEXT: [[DOTDEP_ARR_ADDR:%.*]] = alloca [2 x %struct.kmp_depend_info], align 8 +// CHECK-NEXT: [[DEP_COUNTER_ADDR:%.*]] = alloca i64, align 8 +// CHECK-NEXT: [[DOTDEP_ARR_ADDR5:%.*]] = alloca [2 x %struct.kmp_depend_info], align 8 +// CHECK-NEXT: [[DEP_COUNTER_ADDR6:%.*]] = alloca i64, align 8 +// CHECK-NEXT: store i32 4, i32* [[DEVICE_ID]], align 4 +// CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1:[0-9]+]]) +// CHECK-NEXT: call void @__kmpc_interop_init(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM]], i8** [[INTEROP]], i64 1, i32 -1, i32 0, i8* null, i32 0) +// CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM1:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1]]) +// CHECK-NEXT: call void @__kmpc_interop_init(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM1]], i8** [[INTEROP]], i64 2, i32 -1, i32 0, i8* null, i32 0) +// CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[DEVICE_ID]], align 4 +// CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM2:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1]]) +// CHECK-NEXT: call void @__kmpc_interop_init(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM2]], i8** [[INTEROP]], i64 1, i32 [[TMP0]], i32 0, i8* null, i32 0) +// CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[DEVICE_ID]], align 4 +// CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM3:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1]]) +// CHECK-NEXT: call void @__kmpc_interop_init(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM3]], i8** [[INTEROP]], i64 2, i32 [[TMP1]], i32 0, i8* null, i32 0) +// CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds [2 x %struct.kmp_depend_info], [2 x %struct.kmp_depend_info]* [[DOTDEP_ARR_ADDR]], i64 0, i64 0 +// CHECK-NEXT: [[TMP3:%.*]] = getelementptr [[STRUCT_KMP_DEPEND_INFO:%.*]], %struct.kmp_depend_info* [[TMP2]], i64 0 +// CHECK-NEXT: [[TMP4:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP3]], i32 0, i32 0 +// CHECK-NEXT: [[TMP5:%.*]] = ptrtoint i32* [[D0]] to i64 +// CHECK-NEXT: store i64 [[TMP5]], i64* [[TMP4]], align 8 +// CHECK-NEXT: [[TMP6:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP3]], i32 0, i32 1 +// CHECK-NEXT: store i64 4, i64* [[TMP6]], align 8 +// CHECK-NEXT: [[TMP7:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP3]], i32 0, i32 2 +// CHECK-NEXT: store i8 1, i8* [[TMP7]], align 8 +// CHECK-NEXT: [[TMP8:%.*]] = getelementptr [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP2]], i64 1 +// CHECK-NEXT: [[TMP9:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP8]], i32 0, i32 0 +// CHECK-NEXT: [[TMP10:%.*]] = ptrtoint i32* [[D1]] to i64 +// CHECK-NEXT: store i64 [[TMP10]], i64* [[TMP9]], align 8 +// CHECK-NEXT: [[TMP11:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP8]], i32 0, i32 1 +// CHECK-NEXT: store i64 4, i64* [[TMP11]], align 8 +// CHECK-NEXT: [[TMP12:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP8]], i32 0, i32 2 +// CHECK-NEXT: store i8 1, i8* [[TMP12]], align 8 +// CHECK-NEXT: store i64 2, i64* [[DEP_COUNTER_ADDR]], align 8 +// CHECK-NEXT: [[TMP13:%.*]] = bitcast %struct.kmp_depend_info* [[TMP2]] to i8* +// CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM4:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1]]) +// CHECK-NEXT: call void @__kmpc_interop_use(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM4]], i8** [[INTEROP]], i32 -1, i32 2, i8* [[TMP13]], i32 1) +// CHECK-NEXT: [[TMP14:%.*]] = getelementptr inbounds [2 x %struct.kmp_depend_info], [2 x %struct.kmp_depend_info]* [[DOTDEP_ARR_ADDR5]], i64 0, i64 0 +// CHECK-NEXT: [[TMP15:%.*]] = getelementptr [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP14]], i64 0 +// CHECK-NEXT: [[TMP16:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP15]], i32 0, i32 0 +// CHECK-NEXT: [[TMP17:%.*]] = ptrtoint i32* [[D0]] to i64 +// CHECK-NEXT: store i64 [[TMP17]], i64* [[TMP16]], align 8 +// CHECK-NEXT: [[TMP18:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP15]], i32 0, i32 1 +// CHECK-NEXT: store i64 4, i64* [[TMP18]], align 8 +// CHECK-NEXT: [[TMP19:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP15]], i32 0, i32 2 +// CHECK-NEXT: store i8 1, i8* [[TMP19]], align 8 +// CHECK-NEXT: [[TMP20:%.*]] = getelementptr [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP14]], i64 1 +// CHECK-NEXT: [[TMP21:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP20]], i32 0, i32 0 +// CHECK-NEXT: [[TMP22:%.*]] = ptrtoint i32* [[D1]] to i64 +// CHECK-NEXT: store i64 [[TMP22]], i64* [[TMP21]], align 8 +// CHECK-NEXT: [[TMP23:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP20]], i32 0, i32 1 +// CHECK-NEXT: store i64 4, i64* [[TMP23]], align 8 +// CHECK-NEXT: [[TMP24:%.*]] = getelementptr inbounds [[STRUCT_KMP_DEPEND_INFO]], %struct.kmp_depend_info* [[TMP20]], i32 0, i32 2 +// CHECK-NEXT: store i8 1, i8* [[TMP24]], align 8 +// CHECK-NEXT: store i64 2, i64* [[DEP_COUNTER_ADDR6]], align 8 +// CHECK-NEXT: [[TMP25:%.*]] = bitcast %struct.kmp_depend_info* [[TMP14]] to i8* +// CHECK-NEXT: [[OMP_GLOBAL_THREAD_NUM7:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* @[[GLOB1]]) +// CHECK-NEXT: call void @__kmpc_interop_destroy(%struct.ident_t* @[[GLOB1]], i32 [[OMP_GLOBAL_THREAD_NUM7]], i8** [[INTEROP]], i32 -1, i32 2, i8* [[TMP25]], i32 0) +// CHECK-NEXT: ret void +// diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPConstants.h b/llvm/include/llvm/Frontend/OpenMP/OMPConstants.h --- a/llvm/include/llvm/Frontend/OpenMP/OMPConstants.h +++ b/llvm/include/llvm/Frontend/OpenMP/OMPConstants.h @@ -128,6 +128,9 @@ LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue */ ModifierMask) }; +/// \note This needs to be kept in sync with interop.h enum kmp_interop_type_t.: +enum class OMPInteropType { Unknown, Target, TargetSync }; + } // end namespace omp } // end namespace llvm diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h --- a/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h +++ b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h @@ -779,6 +779,57 @@ llvm::ConstantInt *Size, const llvm::Twine &Name = Twine("")); + /// Create a runtime call for kmpc_interop_init + /// + /// \param Loc The insert and source location description. + /// \param InteropVar variable to be allocated + /// \param InteropType type of interop operation + /// \param Device devide to which offloading will occur + /// \param NumDependences number of dependence variables + /// \param DependenceAddress pointer to dependence variables + /// \param HaveNowaitClause does nowait clause exist + /// + /// \returns CallInst to the kmpc_interop_init call + CallInst * + createOMPInteropInit(const LocationDescription &Loc, Value *InteropVar, + omp::OMPInteropType InteropType, Value *Device, + Value *NumDependences, + Value *DependenceAddress, bool HaveNowaitClause); + + /// Create a runtime call for kmpc_interop_destroy + /// + /// \param Loc The insert and source location description. + /// \param InteropVar variable to be allocated + /// \param Device devide to which offloading will occur + /// \param NumDependences number of dependence variables + /// \param DependenceAddress pointer to dependence variables + /// \param HaveNowaitClause does nowait clause exist + /// + /// \returns CallInst to the kmpc_interop_destroy call + CallInst *createOMPInteropDestroy(const LocationDescription &Loc, + Value *InteropVar, + Value *Device, + Value *NumDependences, + Value *DependenceAddress, + bool HaveNowaitClause); + + /// Create a runtime call for kmpc_interop_use + /// + /// \param Loc The insert and source location description. + /// \param InteropVar variable to be allocated + /// \param Device devide to which offloading will occur + /// \param NumDependences number of dependence variables + /// \param DependenceAddress pointer to dependence variables + /// \param HaveNowaitClause does nowait clause exist + /// + /// \returns CallInst to the kmpc_interop_use call + CallInst *createOMPInteropUse(const LocationDescription &Loc, + Value *InteropVar, Value *Device, + Value *NumDependences, + Value *DependenceAddress, + bool HaveNowaitClause); + + /// Declarations for LLVM-IR types (simple, array, function and structure) are /// The `omp target` interface /// /// For more information about the usage of this interface, diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def b/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def --- a/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def +++ b/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def @@ -371,6 +371,15 @@ __OMP_RTL(__kmpc_alloc, false, VoidPtr, /* Int */ Int32, SizeTy, VoidPtr) __OMP_RTL(__kmpc_free, false, Void, /* Int */ Int32, VoidPtr, VoidPtr) +__OMP_RTL(__kmpc_interop_init, false, Void, IdentPtr, Int32, VoidPtrPtr, + Int64, Int32, Int32, VoidPtr, Int32) + +__OMP_RTL(__kmpc_interop_destroy, false, Void, IdentPtr, Int32, VoidPtrPtr, + Int32, Int32, VoidPtr, Int32) + +__OMP_RTL(__kmpc_interop_use, false, Void, IdentPtr, Int32, VoidPtrPtr, + Int32, Int32, VoidPtr, Int32) + __OMP_RTL(__kmpc_init_allocator, false, /* omp_allocator_handle_t */ VoidPtr, /* Int */ Int32, /* omp_memespace_handle_t */ VoidPtr, /* Int */ Int32, /* omp_alloctrait_t */ VoidPtr) diff --git a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp --- a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp +++ b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp @@ -2173,6 +2173,96 @@ return Builder.CreateCall(Fn, Args, Name); } +CallInst *OpenMPIRBuilder::createOMPInteropInit(const LocationDescription &Loc, + Value *InteropVar, + omp::OMPInteropType InteropType, + Value *Device, + Value *NumDependences, + Value *DependenceAddress, + bool HaveNowaitClause) { + IRBuilder<>::InsertPointGuard IPG(Builder); + Builder.restoreIP(Loc.IP); + + Constant *SrcLocStr = getOrCreateSrcLocStr(Loc); + Value *Ident = getOrCreateIdent(SrcLocStr); + Value *ThreadId = getOrCreateThreadID(Ident); + if (Device == NULL) + Device = ConstantInt::get(M.getContext(), APInt(32, -1, true)); + Constant *InteropTypeVal = + ConstantInt::get(Int64, (int)InteropType); + if (NumDependences == nullptr) { + NumDependences = ConstantInt::get(Int32, 0); + PointerType *PointerTypeVar = Type::getInt8PtrTy(M.getContext()); + DependenceAddress = ConstantPointerNull::get(PointerTypeVar); + } + Value *HaveNowaitClauseVal = + ConstantInt::get(M.getContext(), APInt(32, HaveNowaitClause, true)); + Value *Args[] = { + Ident, ThreadId, InteropVar, InteropTypeVal, + Device, NumDependences, DependenceAddress, HaveNowaitClauseVal}; + + Function *Fn = getOrCreateRuntimeFunctionPtr(OMPRTL___kmpc_interop_init); + + return Builder.CreateCall(Fn, Args); +} + +CallInst *OpenMPIRBuilder::createOMPInteropDestroy( + const LocationDescription &Loc, Value *InteropVar, Value *Device, + Value *NumDependences, Value *DependenceAddress, + bool HaveNowaitClause) { + IRBuilder<>::InsertPointGuard IPG(Builder); + Builder.restoreIP(Loc.IP); + + Constant *SrcLocStr = getOrCreateSrcLocStr(Loc); + Value *Ident = getOrCreateIdent(SrcLocStr); + Value *ThreadId = getOrCreateThreadID(Ident); + if (Device == NULL) + Device = ConstantInt::get(M.getContext(), APInt(32, -1, true)); + if (NumDependences == nullptr) { + NumDependences = ConstantInt::get(Int32, 0); + PointerType *PointerTypeVar = Type::getInt8PtrTy(M.getContext()); + DependenceAddress = ConstantPointerNull::get(PointerTypeVar); + } + Value *HaveNowaitClauseVal = + ConstantInt::get(M.getContext(), APInt(32, HaveNowaitClause, true)); + Value *Args[] = { + Ident, ThreadId, InteropVar, Device, + NumDependences, DependenceAddress, HaveNowaitClauseVal}; + + Function *Fn = getOrCreateRuntimeFunctionPtr(OMPRTL___kmpc_interop_destroy); + + return Builder.CreateCall(Fn, Args); +} + +CallInst *OpenMPIRBuilder::createOMPInteropUse(const LocationDescription &Loc, + Value *InteropVar, + Value *Device, + Value *NumDependences, + Value *DependenceAddress, + bool HaveNowaitClause) { + IRBuilder<>::InsertPointGuard IPG(Builder); + Builder.restoreIP(Loc.IP); + Constant *SrcLocStr = getOrCreateSrcLocStr(Loc); + Value *Ident = getOrCreateIdent(SrcLocStr); + Value *ThreadId = getOrCreateThreadID(Ident); + if (Device == NULL) + Device = ConstantInt::get(M.getContext(), APInt(32, -1, true)); + if (NumDependences == nullptr) { + NumDependences = ConstantInt::get(Int32, 0); + PointerType *PointerTypeVar = Type::getInt8PtrTy(M.getContext()); + DependenceAddress = ConstantPointerNull::get(PointerTypeVar); + } + Value *HaveNowaitClauseVal = + ConstantInt::get(M.getContext(), APInt(32, HaveNowaitClause, true)); + Value *Args[] = { + Ident, ThreadId, InteropVar, Device, + NumDependences, DependenceAddress, HaveNowaitClauseVal}; + + Function *Fn = getOrCreateRuntimeFunctionPtr(OMPRTL___kmpc_interop_use); + + return Builder.CreateCall(Fn, Args); +} + CallInst *OpenMPIRBuilder::createCachedThreadPrivate( const LocationDescription &Loc, llvm::Value *Pointer, llvm::ConstantInt *Size, const llvm::Twine &Name) { diff --git a/openmp/libomptarget/include/interop.h b/openmp/libomptarget/include/interop.h new file mode 100644 --- /dev/null +++ b/openmp/libomptarget/include/interop.h @@ -0,0 +1,172 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _INTEROP_H_ +#define _INTEROP_H_ + +#include "omptarget.h" +#include + +#if defined(_WIN32) +#define __KAI_KMPC_CONVENTION __cdecl +#ifndef __KMP_IMP +#define __KMP_IMP __declspec(dllimport) +#endif +#else +#define __KAI_KMPC_CONVENTION +#ifndef __KMP_IMP +#define __KMP_IMP +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/// TODO: Include the `omp.h` of the current build +/* OpenMP 5.1 interop */ +typedef intptr_t omp_intptr_t; + +/* 0..omp_get_num_interop_properties()-1 are reserved for implementation-defined + * properties */ +typedef enum omp_interop_property { + omp_ipr_fr_id = -1, + omp_ipr_fr_name = -2, + omp_ipr_vendor = -3, + omp_ipr_vendor_name = -4, + omp_ipr_device_num = -5, + omp_ipr_platform = -6, + omp_ipr_device = -7, + omp_ipr_device_context = -8, + omp_ipr_targetsync = -9, + omp_ipr_first = -9 +} omp_interop_property_t; + +#define omp_interop_none 0 + +typedef enum omp_interop_rc { + omp_irc_no_value = 1, + omp_irc_success = 0, + omp_irc_empty = -1, + omp_irc_out_of_range = -2, + omp_irc_type_int = -3, + omp_irc_type_ptr = -4, + omp_irc_type_str = -5, + omp_irc_other = -6 +} omp_interop_rc_t; + +typedef enum omp_interop_fr { + omp_ifr_cuda = 1, + omp_ifr_cuda_driver = 2, + omp_ifr_opencl = 3, + omp_ifr_sycl = 4, + omp_ifr_hip = 5, + omp_ifr_level_zero = 6, + omp_ifr_last = 7 +} omp_interop_fr_t; + +typedef void *omp_interop_t; + +/*! + * The `omp_get_num_interop_properties` routine retrieves the number of + * implementation-defined properties available for an `omp_interop_t` object. + */ +int __KAI_KMPC_CONVENTION omp_get_num_interop_properties(const omp_interop_t); +/*! + * The `omp_get_interop_int` routine retrieves an integer property from an + * `omp_interop_t` object. + */ +omp_intptr_t __KAI_KMPC_CONVENTION omp_get_interop_int(const omp_interop_t, + omp_interop_property_t, + int *); +/*! + * The `omp_get_interop_ptr` routine retrieves a pointer property from an + * `omp_interop_t` object. + */ +void *__KAI_KMPC_CONVENTION omp_get_interop_ptr(const omp_interop_t, + omp_interop_property_t, int *); +/*! + * The `omp_get_interop_str` routine retrieves a string property from an + * `omp_interop_t` object. + */ +const char *__KAI_KMPC_CONVENTION omp_get_interop_str(const omp_interop_t, + omp_interop_property_t, + int *); +/*! + * The `omp_get_interop_name` routine retrieves a property name from an + * `omp_interop_t` object. + */ +const char *__KAI_KMPC_CONVENTION omp_get_interop_name(const omp_interop_t, + omp_interop_property_t); +/*! + * The `omp_get_interop_type_desc` routine retrieves a description of the type + * of a property associated with an `omp_interop_t` object. + */ +const char *__KAI_KMPC_CONVENTION +omp_get_interop_type_desc(const omp_interop_t, omp_interop_property_t); +/*! + * The `omp_get_interop_rc_desc` routine retrieves a description of the return + * code associated with an `omp_interop_t` object. + */ +extern const char *__KAI_KMPC_CONVENTION +omp_get_interop_rc_desc(const omp_interop_t, omp_interop_rc_t); + +typedef struct kmp_tasking_flags { /* Total struct must be exactly 32 bits */ + /* Compiler flags */ /* Total compiler flags must be 16 bits */ + unsigned tiedness : 1; /* task is either tied (1) or untied (0) */ + unsigned final : 1; /* task is final(1) so execute immediately */ + unsigned merged_if0 : 1; // no __kmpc_task_{begin/complete}_if0 calls in if0 + unsigned destructors_thunk : 1; // set if the compiler creates a thunk to + unsigned proxy : 1; // task is a proxy task (it will be executed outside the + unsigned priority_specified : 1; // set if the compiler provides priority + unsigned detachable : 1; // 1 == can detach */ + unsigned unshackled : 1; /* 1 == unshackled task */ + unsigned target : 1; /* 1 == target task */ + unsigned reserved : 7; /* reserved for compiler use */ + unsigned tasktype : 1; /* task is either explicit(1) or implicit (0) */ + unsigned task_serial : 1; // task is executed immediately (1) or deferred (0) + unsigned tasking_ser : 1; // all tasks in team are either executed immediately + unsigned team_serial : 1; // entire team is serial (1) [1 thread] or parallel + unsigned started : 1; /* 1==started, 0==not started */ + unsigned executing : 1; /* 1==executing, 0==not executing */ + unsigned complete : 1; /* 1==complete, 0==not complete */ + unsigned freed : 1; /* 1==freed, 0==allocated */ + unsigned native : 1; /* 1==gcc-compiled task, 0==intel */ + unsigned reserved31 : 7; /* reserved for library use */ +} kmp_tasking_flags_t; + +typedef enum omp_interop_backend_type_t { + // reserve 0 + omp_interop_backend_type_cuda_1 = 1, +} omp_interop_backend_type_t; + +typedef enum kmp_interop_type_t { + kmp_interop_type_unknown = -1, + kmp_interop_type_platform, + kmp_interop_type_device, + kmp_interop_type_tasksync, +} kmp_interop_type_t; + +/// The interop value type, aka. the interop object. +typedef struct omp_interop_val_t { + /// Device and interop-type are determined at construction time and fix. + omp_interop_val_t(intptr_t device_id, kmp_interop_type_t interop_type) + : interop_type(interop_type), device_id(device_id) {} + const char *err_str = nullptr; + __tgt_async_info *async_info = nullptr; + __tgt_device_info device_info; + const kmp_interop_type_t interop_type; + const intptr_t device_id; + const intptr_t vendor_id = 1; // LLVM? + const intptr_t backend_type_id = omp_interop_backend_type_cuda_1; +} omp_interop_val_t; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/openmp/libomptarget/include/omptarget.h b/openmp/libomptarget/include/omptarget.h --- a/openmp/libomptarget/include/omptarget.h +++ b/openmp/libomptarget/include/omptarget.h @@ -176,6 +176,11 @@ uint64_t Stride; }; +struct __tgt_device_info { + void *Context = nullptr; + void *Device = nullptr; +}; + #ifdef __cplusplus extern "C" { #endif diff --git a/openmp/libomptarget/include/omptargetplugin.h b/openmp/libomptarget/include/omptargetplugin.h --- a/openmp/libomptarget/include/omptargetplugin.h +++ b/openmp/libomptarget/include/omptargetplugin.h @@ -142,6 +142,10 @@ // Set plugin's internal information flag externally. void __tgt_rtl_set_info_flag(uint32_t); +int32_t __tgt_rtl_init_async_info(int32_t ID, __tgt_async_info **AsyncInfoPtr); +int32_t __tgt_rtl_init_device_info(int32_t ID, __tgt_device_info *DeviceInfoPtr, + const char **errStr); + #ifdef __cplusplus } #endif diff --git a/openmp/libomptarget/plugins/cuda/src/rtl.cpp b/openmp/libomptarget/plugins/cuda/src/rtl.cpp --- a/openmp/libomptarget/plugins/cuda/src/rtl.cpp +++ b/openmp/libomptarget/plugins/cuda/src/rtl.cpp @@ -421,6 +421,7 @@ E.Table.EntriesBegin = E.Table.EntriesEnd = nullptr; } +public: CUstream getStream(const int DeviceId, __tgt_async_info *AsyncInfo) const { assert(AsyncInfo && "AsyncInfo is nullptr"); @@ -430,7 +431,6 @@ return reinterpret_cast(AsyncInfo->Queue); } -public: // This class should not be copied DeviceRTLTy(const DeviceRTLTy &) = delete; DeviceRTLTy(DeviceRTLTy &&) = delete; @@ -1118,6 +1118,45 @@ } return (Err == CUDA_SUCCESS) ? OFFLOAD_SUCCESS : OFFLOAD_FAIL; } + + int releaseAsyncInfo(int DeviceId, __tgt_async_info *AsyncInfo) const { + if (AsyncInfo->Queue) { + StreamManager->returnStream(DeviceId, + reinterpret_cast(AsyncInfo->Queue)); + AsyncInfo->Queue = nullptr; + } + + return OFFLOAD_SUCCESS; + } + + int initAsyncInfo(int DeviceId, __tgt_async_info **AsyncInfo) const { + CUresult Err = cuCtxSetCurrent(DeviceData[DeviceId].Context); + if (!checkResult(Err, "error returned from cuCtxSetCurrent")) + return OFFLOAD_FAIL; + + *AsyncInfo = new __tgt_async_info; + getStream(DeviceId, *AsyncInfo); + return OFFLOAD_SUCCESS; + } + + int initDeviceInfo(const int DeviceId, __tgt_device_info *DeviceInfo, + const char **errStr) const { + assert(DeviceInfo && "DeviceInfo is nullptr"); + + if (!DeviceInfo->Context) + DeviceInfo->Context = DeviceData[DeviceId].Context; + if (!DeviceInfo->Device) { + CUdevice Dev; + CUresult Err = cuDeviceGet(&Dev, DeviceId); + if (Err == CUDA_SUCCESS) { + DeviceInfo->Device = reinterpret_cast(Dev); + } else { + cuGetErrorString(Err, errStr); + return OFFLOAD_FAIL; + } + } + return OFFLOAD_SUCCESS; + } }; DeviceRTLTy DeviceRTL; @@ -1313,11 +1352,36 @@ return DeviceRTL.synchronize(device_id, async_info_ptr); } +int32_t __tgt_rtl_release_async_info(int32_t device_id, + __tgt_async_info *async_info) { + assert(DeviceRTL.isValidDeviceId(device_id) && "device_id is invalid"); + assert(async_info && "async_info is nullptr"); + + return DeviceRTL.releaseAsyncInfo(device_id, async_info); +} + +int32_t __tgt_rtl_init_async_info(int32_t device_id, + __tgt_async_info **async_info) { + assert(DeviceRTL.isValidDeviceId(device_id) && "device_id is invalid"); + assert(async_info && "async_info is nullptr"); + + return DeviceRTL.initAsyncInfo(device_id, async_info); +} + void __tgt_rtl_set_info_flag(uint32_t NewInfoLevel) { std::atomic &InfoLevel = getInfoLevelInternal(); InfoLevel.store(NewInfoLevel); } +int32_t __tgt_rtl_init_device_info(int32_t device_id, + __tgt_device_info *device_info_ptr, + const char **errStr) { + assert(DeviceRTL.isValidDeviceId(device_id) && "device_id is invalid"); + assert(device_info_ptr && "device_info_ptr is nullptr"); + + return DeviceRTL.initDeviceInfo(device_id, device_info_ptr, errStr); +} + #ifdef __cplusplus } #endif diff --git a/openmp/libomptarget/plugins/exports b/openmp/libomptarget/plugins/exports --- a/openmp/libomptarget/plugins/exports +++ b/openmp/libomptarget/plugins/exports @@ -23,6 +23,8 @@ __tgt_rtl_unregister_lib; __tgt_rtl_supports_empty_images; __tgt_rtl_set_info_flag; + __tgt_rtl_init_device_info; + __tgt_rtl_init_async_info; local: *; }; diff --git a/openmp/libomptarget/src/CMakeLists.txt b/openmp/libomptarget/src/CMakeLists.txt --- a/openmp/libomptarget/src/CMakeLists.txt +++ b/openmp/libomptarget/src/CMakeLists.txt @@ -16,8 +16,9 @@ ${CMAKE_CURRENT_SOURCE_DIR}/api.cpp ${CMAKE_CURRENT_SOURCE_DIR}/device.cpp ${CMAKE_CURRENT_SOURCE_DIR}/interface.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/rtl.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/interop.cpp ${CMAKE_CURRENT_SOURCE_DIR}/omptarget.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rtl.cpp ) set(LIBOMPTARGET_SRC_FILES ${LIBOMPTARGET_SRC_FILES} PARENT_SCOPE) diff --git a/openmp/libomptarget/src/exports b/openmp/libomptarget/src/exports --- a/openmp/libomptarget/src/exports +++ b/openmp/libomptarget/src/exports @@ -40,6 +40,15 @@ llvm_omp_target_alloc_shared; llvm_omp_target_alloc_device; __tgt_set_info_flag; + omp_get_interop_ptr; + omp_get_interop_str; + omp_get_interop_int; + omp_get_interop_name; + omp_get_interop_type_desc; + omp_get_interop_rc_desc; + __tgt_interop_init; + __tgt_interop_use; + __tgt_interop_destroy; local: *; }; diff --git a/openmp/libomptarget/src/interop.cpp b/openmp/libomptarget/src/interop.cpp new file mode 100644 --- /dev/null +++ b/openmp/libomptarget/src/interop.cpp @@ -0,0 +1,276 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "interop.h" +#include "private.h" + +namespace { +omp_interop_rc_t +__tgt_interop_get_property_err_type(omp_interop_property_t property) { + switch (property) { + case omp_ipr_fr_id: + return omp_irc_type_int; + case omp_ipr_fr_name: + return omp_irc_type_str; + case omp_ipr_vendor: + return omp_irc_type_int; + case omp_ipr_vendor_name: + return omp_irc_type_str; + case omp_ipr_device_num: + return omp_irc_type_int; + case omp_ipr_platform: + return omp_irc_type_int; + case omp_ipr_device: + return omp_irc_type_ptr; + case omp_ipr_device_context: + return omp_irc_type_ptr; + case omp_ipr_targetsync: + return omp_irc_type_ptr; + }; + return omp_irc_no_value; +} + +void __tgt_interop_type_mismatch(omp_interop_property_t property, int *err) { + if (err) + *err = __tgt_interop_get_property_err_type(property); +} + +const char *__tgt_interop_vendor_id_to_str(intptr_t vendor_id) { + switch (vendor_id) { + case 1: + return ("cuda"); + case 2: + return ("cuda_driver"); + case 3: + return ("opencl"); + case 4: + return ("sycl"); + case 5: + return ("hip"); + case 6: + return ("level_zero"); + default: + return ("unknown"); + } +} + +template +PropertyTy __tgt_interop_get_property(omp_interop_val_t &interop_val, + omp_interop_property_t property, + int *err); + +template <> +intptr_t __tgt_interop_get_property(omp_interop_val_t &interop_val, + omp_interop_property_t property, + int *err) { + switch (property) { + case omp_ipr_fr_id: + return interop_val.backend_type_id; + case omp_ipr_vendor: + return interop_val.vendor_id; + case omp_ipr_device_num: + return interop_val.device_id; + default:; + } + __tgt_interop_type_mismatch(property, err); + return 0; +} + +template <> +const char *__tgt_interop_get_property( + omp_interop_val_t &interop_val, omp_interop_property_t property, int *err) { + switch (property) { + case omp_ipr_fr_id: + return interop_val.interop_type == kmp_interop_type_tasksync + ? "tasksync" + : "device+context"; + case omp_ipr_vendor_name: + return __tgt_interop_vendor_id_to_str(interop_val.vendor_id); + default: + __tgt_interop_type_mismatch(property, err); + return nullptr; + } +} + +template <> +void *__tgt_interop_get_property(omp_interop_val_t &interop_val, + omp_interop_property_t property, + int *err) { + switch (property) { + case omp_ipr_device: + if (interop_val.device_info.Device) + return interop_val.device_info.Device; + *err = omp_irc_no_value; + return const_cast(interop_val.err_str); + case omp_ipr_device_context: + return interop_val.device_info.Context; + case omp_ipr_targetsync: + return interop_val.async_info->Queue; + default:; + } + __tgt_interop_type_mismatch(property, err); + return nullptr; +} + +bool __tgt_interop_get_property_check(omp_interop_val_t **interop_ptr, + omp_interop_property_t property, + int *err) { + if (err) + *err = omp_irc_success; + if (!interop_ptr) { + if (err) + *err = omp_irc_empty; + return false; + } + if (property >= 0 || property < omp_ipr_first) { + if (err) + *err = omp_irc_out_of_range; + return false; + } + if (property == omp_ipr_targetsync && + (*interop_ptr)->interop_type != kmp_interop_type_tasksync) { + if (err) + *err = omp_irc_other; + return false; + } + if ((property == omp_ipr_device || property == omp_ipr_device_context) && + (*interop_ptr)->interop_type == kmp_interop_type_tasksync) { + if (err) + *err = omp_irc_other; + return false; + } + return true; +} + +} // namespace + +#define __OMP_GET_INTEROP_TY(RETURN_TYPE, SUFFIX) \ + RETURN_TYPE omp_get_interop_##SUFFIX(const omp_interop_t interop, \ + omp_interop_property_t property_id, \ + int *err) { \ + omp_interop_val_t *interop_val = (omp_interop_val_t *)interop; \ + assert((interop_val)->interop_type == kmp_interop_type_tasksync); \ + if (!__tgt_interop_get_property_check(&interop_val, property_id, err)) { \ + return (RETURN_TYPE)(0); \ + } \ + return __tgt_interop_get_property(*interop_val, property_id, \ + err); \ + } +__OMP_GET_INTEROP_TY(intptr_t, int) +__OMP_GET_INTEROP_TY(void *, ptr) +__OMP_GET_INTEROP_TY(const char *, str) +#undef __OMP_GET_INTEROP_TY + +#define __OMP_GET_INTEROP_TY3(RETURN_TYPE, SUFFIX) \ + RETURN_TYPE omp_get_interop_##SUFFIX(const omp_interop_t interop, \ + omp_interop_property_t property_id) { \ + int err; \ + omp_interop_val_t *interop_val = (omp_interop_val_t *)interop; \ + if (!__tgt_interop_get_property_check(&interop_val, property_id, &err)) { \ + return (RETURN_TYPE)(0); \ + } \ + return nullptr; \ + return __tgt_interop_get_property(*interop_val, property_id, \ + &err); \ + } +__OMP_GET_INTEROP_TY3(const char *, name) +__OMP_GET_INTEROP_TY3(const char *, type_desc) +__OMP_GET_INTEROP_TY3(const char *, rc_desc) +#undef __OMP_GET_INTEROP_TY3 + +typedef int64_t kmp_int64; + +#ifdef __cplusplus +extern "C" { +#endif +void __tgt_interop_init(ident_t *loc_ref, kmp_int32 gtid, + omp_interop_val_t *&interop_ptr, + kmp_interop_type_t interop_type, kmp_int32 device_id, + kmp_int64 ndeps, kmp_depend_info_t *dep_list, + kmp_int32 have_nowait) { + kmp_int32 ndeps_noalias = 0; + kmp_depend_info_t *noalias_dep_list = NULL; + assert(interop_type != kmp_interop_type_unknown && + "Cannot initialize with unknown interop_type!"); + if (device_id == -1) { + device_id = omp_get_default_device(); + } + + if (interop_type == kmp_interop_type_tasksync) { + __kmpc_omp_wait_deps(loc_ref, gtid, ndeps, dep_list, ndeps_noalias, + noalias_dep_list); + } + + interop_ptr = new omp_interop_val_t(device_id, interop_type); + if (!device_is_ready(device_id)) { + interop_ptr->err_str = "Device not ready!"; + return; + } + + DeviceTy &Device = PM->Devices[device_id]; + if (interop_type == kmp_interop_type_tasksync) { + if (!Device.RTL || !Device.RTL->init_async_info || + Device.RTL->init_async_info(device_id, &(interop_ptr)->async_info)) { + delete interop_ptr; + interop_ptr = omp_interop_none; + } + } else { + if (!Device.RTL || !Device.RTL->init_device_info || + Device.RTL->init_device_info(device_id, &(interop_ptr)->device_info, + &(interop_ptr)->err_str)) { + delete interop_ptr; + interop_ptr = omp_interop_none; + } + } +} + +void __tgt_interop_use(ident_t *loc_ref, kmp_int32 gtid, + omp_interop_val_t *interop_ptr, kmp_int32 device_id, + kmp_int32 ndeps, kmp_depend_info_t *dep_list, + kmp_int32 have_nowait) { + kmp_int32 ndeps_noalias = 0; + kmp_depend_info_t *noalias_dep_list = NULL; + assert(interop_ptr && "Cannot use nullptr!"); + omp_interop_val_t *interop_val = interop_ptr; + assert(interop_val != omp_interop_none && + "Cannot use uninitialized interop_ptr!"); + assert((device_id == -1 || interop_val->device_id == device_id) && + "Inconsistent device-id usage!"); + + if (interop_val->interop_type == kmp_interop_type_tasksync) { + __kmpc_omp_wait_deps(loc_ref, gtid, ndeps, dep_list, ndeps_noalias, + noalias_dep_list); + } +} + +void __tgt_interop_destroy(ident_t *loc_ref, kmp_int32 gtid, + omp_interop_val_t *&interop_ptr, kmp_int32 device_id, + kmp_int32 ndeps, kmp_depend_info_t *dep_list, + kmp_int32 have_nowait) { + kmp_int32 ndeps_noalias = 0; + kmp_depend_info_t *noalias_dep_list = NULL; + assert(interop_ptr && "Cannot use nullptr!"); + omp_interop_val_t *interop_val = interop_ptr; + + if (interop_val == omp_interop_none) + return; + + assert((device_id == -1 || interop_val->device_id == device_id) && + "Inconsistent device-id usage!"); + + if (interop_val->interop_type == kmp_interop_type_tasksync) { + __kmpc_omp_wait_deps(loc_ref, gtid, ndeps, dep_list, ndeps_noalias, + noalias_dep_list); + } + + delete interop_ptr; + interop_ptr = omp_interop_none; +} +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/openmp/libomptarget/src/private.h b/openmp/libomptarget/src/private.h --- a/openmp/libomptarget/src/private.h +++ b/openmp/libomptarget/src/private.h @@ -89,11 +89,35 @@ #ifdef __cplusplus extern "C" { #endif + +/*! + * The ident structure that describes a source location. + * The struct is identical to the one in the kmp.h file. + * We maintain the same data structure for compatibility. + */ +typedef int kmp_int32; +typedef intptr_t kmp_intptr_t; + +// Compiler sends us this info: +typedef struct kmp_depend_info { + kmp_intptr_t base_addr; + size_t len; + struct { + bool in : 1; + bool out : 1; + bool mtx : 1; + } flags; +} kmp_depend_info_t; + // functions that extract info from libomp; keep in sync int omp_get_default_device(void) __attribute__((weak)); int32_t __kmpc_omp_taskwait(void *loc_ref, int32_t gtid) __attribute__((weak)); int32_t __kmpc_global_thread_num(void *) __attribute__((weak)); int __kmpc_get_target_offload(void) __attribute__((weak)); +void __kmpc_omp_wait_deps(ident_t *loc_ref, kmp_int32 gtid, kmp_int32 ndeps, + kmp_depend_info_t *dep_list, kmp_int32 ndeps_noalias, + kmp_depend_info_t *noalias_dep_list) + __attribute__((weak)); #ifdef __cplusplus } #endif diff --git a/openmp/libomptarget/src/rtl.h b/openmp/libomptarget/src/rtl.h --- a/openmp/libomptarget/src/rtl.h +++ b/openmp/libomptarget/src/rtl.h @@ -56,6 +56,10 @@ typedef int32_t (*register_lib_ty)(__tgt_bin_desc *); typedef int32_t(supports_empty_images_ty)(); typedef void(set_info_flag_ty)(uint32_t); + typedef int32_t(release_async_info_ty)(int32_t, __tgt_async_info *); + typedef int32_t(init_async_info_ty)(int32_t, __tgt_async_info **); + typedef int64_t(init_device_into_ty)(int64_t, __tgt_device_info *, + const char **); int32_t Idx = -1; // RTL index, index is the number of devices // of other RTLs that were registered before, @@ -93,6 +97,9 @@ register_lib_ty unregister_lib = nullptr; supports_empty_images_ty *supports_empty_images = nullptr; set_info_flag_ty *set_info_flag = nullptr; + init_async_info_ty *init_async_info = nullptr; + init_device_into_ty *init_device_info = nullptr; + release_async_info_ty *release_async_info = nullptr; // Are there images associated with this RTL. bool isUsed = false; diff --git a/openmp/libomptarget/src/rtl.cpp b/openmp/libomptarget/src/rtl.cpp --- a/openmp/libomptarget/src/rtl.cpp +++ b/openmp/libomptarget/src/rtl.cpp @@ -177,6 +177,12 @@ dlsym(dynlib_handle, "__tgt_rtl_supports_empty_images"); *((void **)&R.set_info_flag) = dlsym(dynlib_handle, "__tgt_rtl_set_info_flag"); + *((void **)&R.release_async_info) = + dlsym(dynlib_handle, "__tgt_rtl_release_async_info"); + *((void **)&R.init_async_info) = + dlsym(dynlib_handle, "__tgt_rtl_init_async_info"); + *((void **)&R.init_device_info) = + dlsym(dynlib_handle, "__tgt_rtl_init_device_info"); } DP("RTLs loaded!\n"); diff --git a/openmp/runtime/src/dllexports b/openmp/runtime/src/dllexports --- a/openmp/runtime/src/dllexports +++ b/openmp/runtime/src/dllexports @@ -548,6 +548,9 @@ omp_display_env 733 omp_calloc 776 omp_realloc 777 + omp_get_interop_int 2514 + omp_get_interop_ptr 2515 + omp_get_interop_str 2516 omp_null_allocator DATA omp_default_mem_alloc DATA diff --git a/openmp/runtime/src/kmp_ftn_entry.h b/openmp/runtime/src/kmp_ftn_entry.h --- a/openmp/runtime/src/kmp_ftn_entry.h +++ b/openmp/runtime/src/kmp_ftn_entry.h @@ -1446,6 +1446,135 @@ #endif } +/// TODO: Include the `omp.h` of the current build +/* OpenMP 5.1 interop */ +typedef intptr_t omp_intptr_t; + +/* 0..omp_get_num_interop_properties()-1 are reserved for implementation-defined + * properties */ +typedef enum omp_interop_property { + omp_ipr_fr_id = -1, + omp_ipr_fr_name = -2, + omp_ipr_vendor = -3, + omp_ipr_vendor_name = -4, + omp_ipr_device_num = -5, + omp_ipr_platform = -6, + omp_ipr_device = -7, + omp_ipr_device_context = -8, + omp_ipr_targetsync = -9, + omp_ipr_first = -9 +} omp_interop_property_t; + +#define omp_interop_none 0 + +typedef enum omp_interop_rc { + omp_irc_no_value = 1, + omp_irc_success = 0, + omp_irc_empty = -1, + omp_irc_out_of_range = -2, + omp_irc_type_int = -3, + omp_irc_type_ptr = -4, + omp_irc_type_str = -5, + omp_irc_other = -6 +} omp_interop_rc_t; + +typedef enum omp_interop_fr { + omp_ifr_cuda = 1, + omp_ifr_cuda_driver = 2, + omp_ifr_opencl = 3, + omp_ifr_sycl = 4, + omp_ifr_hip = 5, + omp_ifr_level_zero = 6, + omp_ifr_last = 7 +} omp_interop_fr_t; + +typedef void *omp_interop_t; + +// libomptarget, if loaded, provides this function +int FTN_STDCALL FTN_GET_NUM_INTEROP_PROPERTIES(const omp_interop_t interop) { + assert(0); +#if KMP_MIC || KMP_OS_DARWIN || defined(KMP_STUB) + return 0; +#else + int (*fptr)(const omp_interop_t); + if ((*(void **)(&fptr) = KMP_DLSYM_NEXT("omp_get_num_interop_properties"))) { + return (*fptr)(interop); + } else { // liboffload & libomptarget don't exist + return 0; + } +#endif // KMP_MIC || KMP_OS_DARWIN || KMP_OS_WINDOWS || defined(KMP_STUB) +} + +/// TODO Convert FTN_GET_INTEROP_XXX functions into a macro like interop.cpp +// libomptarget, if loaded, provides this function +intptr_t FTN_STDCALL FTN_GET_INTEROP_INT(const omp_interop_t interop, + omp_interop_property_t property_id, + int *err) { + intptr_t (*fptr)(const omp_interop_t, omp_interop_property_t, int *); + if ((*(void **)(&fptr) = KMP_DLSYM_NEXT("omp_get_interop_int"))) { + return (*fptr)(interop, property_id, err); + } else { // liboffload & libomptarget don't exist + return 0; + } +} + +// libomptarget, if loaded, provides this function +void *FTN_STDCALL FTN_GET_INTEROP_PTR(const omp_interop_t interop, + omp_interop_property_t property_id, + int *err) { + void *(*fptr)(const omp_interop_t, omp_interop_property_t, int *); + if ((*(void **)(&fptr) = KMP_DLSYM_NEXT("omp_get_interop_ptr"))) { + return (*fptr)(interop, property_id, err); + } else { // liboffload & libomptarget don't exist + return (void *)0; + } +} + +// libomptarget, if loaded, provides this function +const char *FTN_STDCALL FTN_GET_INTEROP_STR(const omp_interop_t interop, + omp_interop_property_t property_id, + int *err) { + const char *(*fptr)(const omp_interop_t, omp_interop_property_t, int *); + if ((*(void **)(&fptr) = KMP_DLSYM_NEXT("omp_get_interop_str"))) { + return (*fptr)(interop, property_id, err); + } else { // liboffload & libomptarget don't exist + return (const char *)0; + } +} + +// libomptarget, if loaded, provides this function +const char *FTN_STDCALL FTN_GET_INTEROP_NAME( + const omp_interop_t interop, omp_interop_property_t property_id) { + const char *(*fptr)(const omp_interop_t, omp_interop_property_t); + if ((*(void **)(&fptr) = KMP_DLSYM_NEXT("omp_get_interop_name"))) { + return (*fptr)(interop, property_id); + } else { // liboffload & libomptarget don't exist + return (const char *)0; + } +} + +// libomptarget, if loaded, provides this function +const char *FTN_STDCALL FTN_GET_INTEROP_TYPE_DESC( + const omp_interop_t interop, omp_interop_property_t property_id) { + const char *(*fptr)(const omp_interop_t, omp_interop_property_t); + if ((*(void **)(&fptr) = KMP_DLSYM_NEXT("omp_get_interop_type_desc"))) { + return (*fptr)(interop, property_id); + } else { // liboffload & libomptarget don't exist + return (const char *)0; + } +} + +// libomptarget, if loaded, provides this function +const char *FTN_STDCALL FTN_GET_INTEROP_RC_DESC( + const omp_interop_t interop, omp_interop_property_t property_id) { + const char *(*fptr)(const omp_interop_t, omp_interop_property_t); + if ((*(void **)(&fptr) = KMP_DLSYM_NEXT("omp_get_interop_rec_desc"))) { + return (*fptr)(interop, property_id); + } else { // liboffload & libomptarget don't exist + return (const char *)0; + } +} + // display environment variables when requested void FTN_STDCALL FTN_DISPLAY_ENV(int verbose) { #ifndef KMP_STUB diff --git a/openmp/runtime/src/kmp_ftn_os.h b/openmp/runtime/src/kmp_ftn_os.h --- a/openmp/runtime/src/kmp_ftn_os.h +++ b/openmp/runtime/src/kmp_ftn_os.h @@ -140,6 +140,14 @@ #define FTN_SET_TEAMS_THREAD_LIMIT omp_set_teams_thread_limit #define FTN_GET_TEAMS_THREAD_LIMIT omp_get_teams_thread_limit +#define FTN_GET_NUM_INTEROP_PROPERTIES omp_get_num_interop_properties +#define FTN_GET_INTEROP_INT omp_get_interop_int +#define FTN_GET_INTEROP_PTR omp_get_interop_ptr +#define FTN_GET_INTEROP_STR omp_get_interop_str +#define FTN_GET_INTEROP_NAME omp_get_interop_name +#define FTN_GET_INTEROP_TYPE_DESC omp_get_interop_type_desc +#define FTN_GET_INTEROP_RC_DESC omp_get_interop_rc_desc + #endif /* KMP_FTN_PLAIN */ /* ------------------------------------------------------------------------ */