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,65 @@ [](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()); + + int DependClauseCount = 0; + for (const auto *DC : S.getClausesOfKind()) + DependClauseCount++; + assert(DependClauseCount <= 1 && "Multiple OMPDependClause not supported."); + + 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); + } + + int HaveNowaitClause = 0; + if (S.getSingleClause()) + HaveNowaitClause = 1; + + if (const auto *C = S.getSingleClause()) { + llvm::Value *InteropvarPtr = + (EmitLValue(C->getInteropVar()).getAddress(*this)).getPointer(); + llvm::OMPInteropType InteropType = llvm::OMPInteropType::Unknown; + if (C->getIsTarget()) + InteropType = llvm::OMPInteropType::Target; + else if (C->getIsTargetSync()) + InteropType = llvm::OMPInteropType::TargetSync; + OMPBuilder.createOMPInteropInit(Builder, InteropvarPtr, InteropType, Device, + NumDependences, DependenceAddress, + HaveNowaitClause); + } else if (const auto *C = S.getSingleClause()) { + llvm::Value *InteropvarPtr = + (EmitLValue(C->getInteropVar()).getAddress(*this)).getPointer(); + OMPBuilder.createOMPInteropDestroy(Builder, InteropvarPtr, Device, + NumDependences, DependenceAddress, + HaveNowaitClause); + } else if (const auto *C = S.getSingleClause()) { + llvm::Value *InteropvarPtr = + (EmitLValue(C->getInteropVar()).getAddress(*this)).getPointer(); + OMPBuilder.createOMPInteropUse(Builder, InteropvarPtr, Device, + NumDependences, DependenceAddress, + HaveNowaitClause); + } else if (HaveNowaitClause == true) { + llvm_unreachable("Nowait clause is used separately in Interop Directive."); + } else { + llvm_unreachable("Missing Interop clauses."); + } +} + 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,24 @@ +// RUN: %clang_cc1 -verify -fopenmp -o - %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) +} + 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 @@ -130,6 +130,8 @@ } // end namespace omp +enum class OMPInteropType { Unknown, Target, TargetSync }; + } // end namespace llvm #endif // LLVM_FRONTEND_OPENMP_OMPCONSTANTS_H 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, llvm::Value *InteropVar, + OMPInteropType InteropType, llvm::Value *Device, + llvm::Value *NumDependences, + llvm::Value *DependenceAddress, int 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, + llvm::Value *InteropVar, + llvm::Value *Device, + llvm::Value *NumDependences, + llvm::Value *DependenceAddress, + int 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, + llvm::Value *InteropVar, llvm::Value *Device, + llvm::Value *NumDependences, + llvm::Value *DependenceAddress, + int 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, + OMPInteropType InteropType, + llvm::Value *Device, + llvm::Value *NumDependences, + llvm::Value *DependenceAddress, + int 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)); + ConstantInt *InteropTypeVal = + ConstantInt::get(M.getContext(), APInt(64, (int)InteropType, true)); + if (NumDependences == nullptr) { + NumDependences = ConstantInt::get(M.getContext(), APInt(32, 0, true)); + PointerType *PointerTy_0 = llvm::Type::getInt8PtrTy(M.getContext()); + DependenceAddress = ConstantPointerNull::get(PointerTy_0); + } + 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, llvm::Value *Device, + llvm::Value *NumDependences, llvm::Value *DependenceAddress, + int 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(M.getContext(), APInt(32, 0, true)); + PointerType *PointerTy_0 = llvm::Type::getInt8PtrTy(M.getContext()); + DependenceAddress = ConstantPointerNull::get(PointerTy_0); + } + 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, + llvm::Value *Device, + llvm::Value *NumDependences, + llvm::Value *DependenceAddress, + int 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(M.getContext(), APInt(32, 0, true)); + PointerType *PointerTy_0 = llvm::Type::getInt8PtrTy(M.getContext()); + DependenceAddress = ConstantPointerNull::get(PointerTy_0); + } + 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) {