https://github.com/chichunchen updated https://github.com/llvm/llvm-project/pull/199101
>From d27400783bebaa4330d951e9792765191293c1c1 Mon Sep 17 00:00:00 2001 From: "Chi Chun, Chen" <[email protected]> Date: Tue, 12 May 2026 22:52:37 -0500 Subject: [PATCH] [OpenMP][mlir] Support iterator modifier LLVM lowering for map/motion Lower iterator modifiers on map and motion (target_data/target_data_begin/target_data_end/target_update) by building dynamic offload map arrays in OpenMPIRBuilder and populating them from iterator-expanded map entries during MLIR OpenMP to LLVM IR translation. Hoist runtime-sized offload map array allocation for target data with iterator modifiers so the dynamic count and arrays dominate runtime calls. This patch is part of feature work for #188061. Assisted with copilot. --- .../llvm/Frontend/OpenMP/OMPIRBuilder.h | 38 ++- llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp | 257 ++++++++++++++- .../Frontend/OpenMPIRBuilderTest.cpp | 126 +++++++ .../OpenMP/OpenMPToLLVMIRTranslation.cpp | 165 +++++++++- mlir/test/Target/LLVMIR/openmp-iterator.mlir | 308 ++++++++++++++++++ mlir/test/Target/LLVMIR/openmp-todo.mlir | 82 +---- .../fortran/map-motion-iterator.f90 | 119 +++++++ 7 files changed, 1000 insertions(+), 95 deletions(-) create mode 100644 offload/test/offloading/fortran/map-motion-iterator.f90 diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h index 128fb7af7152a..5b7e7cf8e5203 100644 --- a/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h +++ b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h @@ -2824,6 +2824,9 @@ class OpenMPIRBuilder { /// Whether the `target ... data` directive has a `nowait` clause. bool HasNoWait = false; + /// Total number of map entries when the number is computed at runtime. + Value *TotalMapCount = nullptr; + explicit TargetDataInfo() = default; explicit TargetDataInfo(bool RequiresDevicePointerInfo, bool SeparateBeginEndCalls) @@ -2839,7 +2842,8 @@ class OpenMPIRBuilder { bool isValid() { return RTArgs.BasePointersArray && RTArgs.PointersArray && RTArgs.SizesArray && RTArgs.MapTypesArray && - (!HasMapper || RTArgs.MappersArray) && NumberOfPtrs; + (!HasMapper || RTArgs.MappersArray) && + (NumberOfPtrs || TotalMapCount); } bool requiresDevicePointerInfo() { return RequiresDevicePointerInfo; } bool separateBeginEndCalls() { return SeparateBeginEndCalls; } @@ -2906,6 +2910,27 @@ class OpenMPIRBuilder { using CustomMapperCallbackTy = function_ref<Expected<Function *>(unsigned int)>; + /// Callback for filling dynamic map entries after static entries have been + /// emitted into the offloading arrays. + using DynMapEntriesCallbackTy = + function_ref<Error(InsertPointTy CodeGenIP, TargetDataRTArgs &RTArgs, + unsigned int StaticCount)>; + + /// Store a single map entry into the offloading arrays at \p Index. + LLVM_ABI void emitOffloadingArraysMapEntry( + IRBuilderBase &Builder, TargetDataRTArgs &RTArgs, TargetDataInfo &Info, + Value *Index, Value *BasePtr, Value *Ptr, Value *Size, Value *MapType, + Value *MapTypeEnd = nullptr, Value *MapperFunc = nullptr, + Value *MapName = nullptr, DeviceInfoTy DevPtrType = DeviceInfoTy::None, + InsertPointTy AllocaIP = {}, unsigned DeviceAddrCBIndex = 0, + function_ref<void(unsigned int, Value *)> DeviceAddrCB = nullptr); + + /// Allocate runtime-sized offloading arrays using \p Info.TotalMapCount. + LLVM_ABI void emitDynamicOffloadingArraysAllocas(InsertPointTy AllocaIP, + InsertPointTy CodeGenIP, + TargetDataInfo &Info, + bool EmitDebug); + /// Generate a target region entry call and host fallback call. /// /// \param Loc The location at which the request originated and is fulfilled. @@ -2973,7 +2998,8 @@ class OpenMPIRBuilder { InsertPointTy AllocaIP, InsertPointTy CodeGenIP, MapInfosTy &CombinedInfo, TargetDataInfo &Info, CustomMapperCallbackTy CustomMapperCB, bool IsNonContiguous = false, - function_ref<void(unsigned int, Value *)> DeviceAddrCB = nullptr); + function_ref<void(unsigned int, Value *)> DeviceAddrCB = nullptr, + DynMapEntriesCallbackTy DynMapEntriesCB = nullptr); /// Allocates memory for and populates the arrays required for offloading /// (offload_{baseptrs|ptrs|mappers|sizes|maptypes|mapnames}). Then, it @@ -2986,7 +3012,8 @@ class OpenMPIRBuilder { TargetDataRTArgs &RTArgs, MapInfosTy &CombinedInfo, CustomMapperCallbackTy CustomMapperCB, bool IsNonContiguous = false, bool ForEndCall = false, - function_ref<void(unsigned int, Value *)> DeviceAddrCB = nullptr); + function_ref<void(unsigned int, Value *)> DeviceAddrCB = nullptr, + DynMapEntriesCallbackTy DynMapEntriesCB = nullptr); /// Creates offloading entry for the provided entry ID \a ID, address \a /// Addr, size \a Size, and flags \a Flags. @@ -3609,6 +3636,8 @@ class OpenMPIRBuilder { /// \param BodyGenCB Optional Callback to generate the region code. /// \param DeviceAddrCB Optional callback to generate code related to /// use_device_ptr and use_device_addr. + /// \param SrcLocInfo Optional source location information. + /// \param DynMapEntriesCB Optional callback to fill dynamic map entries. LLVM_ABI InsertPointOrErrorTy createTargetData( const LocationDescription &Loc, InsertPointTy AllocaIP, InsertPointTy CodeGenIP, ArrayRef<BasicBlock *> DeallocBlocks, @@ -3619,7 +3648,8 @@ class OpenMPIRBuilder { BodyGenTy BodyGenType)> BodyGenCB = nullptr, function_ref<void(unsigned int, Value *)> DeviceAddrCB = nullptr, - Value *SrcLocInfo = nullptr); + Value *SrcLocInfo = nullptr, + DynMapEntriesCallbackTy DynMapEntriesCB = nullptr); using TargetBodyGenCallbackTy = function_ref<InsertPointOrErrorTy( InsertPointTy AllocaIP, InsertPointTy CodeGenIP, diff --git a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp index 92eb7de0d882f..1b6dd7b05313b 100644 --- a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp +++ b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp @@ -8489,30 +8489,45 @@ OpenMPIRBuilder::InsertPointOrErrorTy OpenMPIRBuilder::createTargetData( function_ref<InsertPointOrErrorTy(InsertPointTy CodeGenIP, BodyGenTy BodyGenType)> BodyGenCB, - function_ref<void(unsigned int, Value *)> DeviceAddrCB, Value *SrcLocInfo) { + function_ref<void(unsigned int, Value *)> DeviceAddrCB, Value *SrcLocInfo, + DynMapEntriesCallbackTy DynMapEntriesCB) { if (!updateToLocation(Loc)) return InsertPointTy(); Builder.restoreIP(CodeGenIP); bool IsStandAlone = !BodyGenCB; - MapInfosTy *MapInfo; + MapInfosTy *MapInfo = nullptr; + + if (!IsStandAlone && DynMapEntriesCB) { + MapInfo = &GenMapInfoCB(Builder.saveIP()); + if (Info.TotalMapCount) + emitDynamicOffloadingArraysAllocas(AllocaIP, Builder.saveIP(), Info, + DynMapEntriesCB || + !MapInfo->Names.empty()); + } + // Generate the code for the opening of the data environment. Capture all the // arguments of the runtime call by reference because they are used in the // closing of the region. auto BeginThenGen = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, ArrayRef<BasicBlock *> DeallocBlocks) -> Error { - MapInfo = &GenMapInfoCB(Builder.saveIP()); + if (!MapInfo) + MapInfo = &GenMapInfoCB(Builder.saveIP()); if (Error Err = emitOffloadingArrays( AllocaIP, Builder.saveIP(), *MapInfo, Info, CustomMapperCB, - /*IsNonContiguous=*/true, DeviceAddrCB)) + /*IsNonContiguous=*/true, DeviceAddrCB, DynMapEntriesCB)) return Err; TargetDataRTArgs RTArgs; emitOffloadingArraysArgument(Builder, RTArgs, Info); // Emit the number of elements in the offloading arrays. - Value *PointerNum = Builder.getInt32(Info.NumberOfPtrs); + Value *PointerNum = + Info.TotalMapCount + ? Builder.CreateIntCast(Info.TotalMapCount, Builder.getInt32Ty(), + /*isSigned=*/false, "map.count") + : Builder.getInt32(Info.NumberOfPtrs); // Source location for the ident struct if (!SrcLocInfo) { @@ -8603,11 +8618,15 @@ OpenMPIRBuilder::InsertPointOrErrorTy OpenMPIRBuilder::createTargetData( auto EndThenGen = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, ArrayRef<BasicBlock *> DeallocBlocks) { TargetDataRTArgs RTArgs; - Info.EmitDebug = !MapInfo->Names.empty(); + Info.EmitDebug = Info.EmitDebug || !MapInfo->Names.empty(); emitOffloadingArraysArgument(Builder, RTArgs, Info, /*ForEndCall=*/true); // Emit the number of elements in the offloading arrays. - Value *PointerNum = Builder.getInt32(Info.NumberOfPtrs); + Value *PointerNum = + Info.TotalMapCount + ? Builder.CreateIntCast(Info.TotalMapCount, Builder.getInt32Ty(), + /*isSigned=*/false, "map.count") + : Builder.getInt32(Info.NumberOfPtrs); // Source location for the ident struct if (!SrcLocInfo) { @@ -9621,10 +9640,11 @@ Error OpenMPIRBuilder::emitOffloadingArraysAndArgs( InsertPointTy AllocaIP, InsertPointTy CodeGenIP, TargetDataInfo &Info, TargetDataRTArgs &RTArgs, MapInfosTy &CombinedInfo, CustomMapperCallbackTy CustomMapperCB, bool IsNonContiguous, - bool ForEndCall, function_ref<void(unsigned int, Value *)> DeviceAddrCB) { - if (Error Err = - emitOffloadingArrays(AllocaIP, CodeGenIP, CombinedInfo, Info, - CustomMapperCB, IsNonContiguous, DeviceAddrCB)) + bool ForEndCall, function_ref<void(unsigned int, Value *)> DeviceAddrCB, + DynMapEntriesCallbackTy DynMapEntriesCB) { + if (Error Err = emitOffloadingArrays(AllocaIP, CodeGenIP, CombinedInfo, Info, + CustomMapperCB, IsNonContiguous, + DeviceAddrCB, DynMapEntriesCB)) return Err; emitOffloadingArraysArgument(Builder, RTArgs, Info, ForEndCall); return Error::success(); @@ -10012,7 +10032,7 @@ void OpenMPIRBuilder::emitOffloadingArraysArgument(IRBuilderBase &Builder, auto Int64Ty = Type::getInt64Ty(M.getContext()); auto Int64PtrTy = UnqualPtrTy; - if (!Info.NumberOfPtrs) { + if (!Info.NumberOfPtrs && !Info.TotalMapCount) { RTArgs.BasePointersArray = ConstantPointerNull::get(VoidPtrPtrTy); RTArgs.PointersArray = ConstantPointerNull::get(VoidPtrPtrTy); RTArgs.SizesArray = ConstantPointerNull::get(Int64PtrTy); @@ -10022,6 +10042,29 @@ void OpenMPIRBuilder::emitOffloadingArraysArgument(IRBuilderBase &Builder, return; } + if (Info.TotalMapCount) { + RTArgs.BasePointersArray = + Builder.CreatePointerCast(Info.RTArgs.BasePointersArray, VoidPtrPtrTy); + RTArgs.PointersArray = + Builder.CreatePointerCast(Info.RTArgs.PointersArray, VoidPtrPtrTy); + RTArgs.SizesArray = + Builder.CreatePointerCast(Info.RTArgs.SizesArray, Int64PtrTy); + RTArgs.MapTypesArray = + Builder.CreatePointerCast(ForEndCall && Info.RTArgs.MapTypesArrayEnd + ? Info.RTArgs.MapTypesArrayEnd + : Info.RTArgs.MapTypesArray, + Int64PtrTy); + RTArgs.MapNamesArray = + Info.EmitDebug + ? Builder.CreatePointerCast(Info.RTArgs.MapNamesArray, VoidPtrPtrTy) + : ConstantPointerNull::get(VoidPtrPtrTy); + RTArgs.MappersArray = + Info.HasMapper + ? Builder.CreatePointerCast(Info.RTArgs.MappersArray, VoidPtrPtrTy) + : ConstantPointerNull::get(VoidPtrPtrTy); + return; + } + RTArgs.BasePointersArray = Builder.CreateConstInBoundsGEP2_32( ArrayType::get(VoidPtrTy, Info.NumberOfPtrs), Info.RTArgs.BasePointersArray, @@ -10116,9 +10159,13 @@ void OpenMPIRBuilder::emitNonContiguousDescriptor(InsertPointTy AllocaIP, Builder.restoreIP(CodeGenIP); Value *DAddr = Builder.CreatePointerBitCastOrAddrSpaceCast( DimsAddr, Builder.getPtrTy()); - Value *P = Builder.CreateConstInBoundsGEP2_32( - ArrayType::get(Builder.getPtrTy(), Info.NumberOfPtrs), - Info.RTArgs.PointersArray, 0, I); + Value *P = Info.TotalMapCount + ? Builder.CreateInBoundsGEP(Builder.getPtrTy(), + Info.RTArgs.PointersArray, + Builder.getInt64(I)) + : Builder.CreateConstInBoundsGEP2_32( + ArrayType::get(Builder.getPtrTy(), Info.NumberOfPtrs), + Info.RTArgs.PointersArray, 0, I); Builder.CreateAlignedStore( DAddr, P, M.getDataLayout().getPrefTypeAlign(Builder.getPtrTy())); ++L; @@ -10423,19 +10470,195 @@ Expected<Function *> OpenMPIRBuilder::emitUserDefinedMapper( return MapperFn; } +void OpenMPIRBuilder::emitOffloadingArraysMapEntry( + IRBuilderBase &Builder, TargetDataRTArgs &RTArgs, TargetDataInfo &Info, + Value *Index, Value *BasePtr, Value *Ptr, Value *Size, Value *MapType, + Value *MapTypeEnd, Value *MapperFunc, Value *MapName, + DeviceInfoTy DevPtrType, InsertPointTy AllocaIP, unsigned DeviceAddrCBIndex, + function_ref<void(unsigned int, Value *)> DeviceAddrCB) { + Type *PtrTy = Builder.getPtrTy(); + Type *Int64Ty = Builder.getInt64Ty(); + bool IsDynamic = Info.TotalMapCount != nullptr; + + auto getArrayElementAddress = [&](Value *Array, Type *ElemTy) -> Value * { + if (IsDynamic) + return Builder.CreateInBoundsGEP(ElemTy, Array, Index); + return Builder.CreateInBoundsGEP(ArrayType::get(ElemTy, Info.NumberOfPtrs), + Array, {Builder.getInt32(0), Index}); + }; + + Align PtrAlign = M.getDataLayout().getPrefTypeAlign(PtrTy); + Align Int64Align = M.getDataLayout().getPrefTypeAlign(Int64Ty); + + Value *BPSlot = getArrayElementAddress(RTArgs.BasePointersArray, PtrTy); + Builder.CreateAlignedStore(BasePtr, BPSlot, PtrAlign); + Builder.CreateAlignedStore( + Ptr, getArrayElementAddress(RTArgs.PointersArray, PtrTy), PtrAlign); + + if (Size) + Builder.CreateAlignedStore( + Builder.CreateIntCast(Size, Int64Ty, /*isSigned=*/true), + getArrayElementAddress(RTArgs.SizesArray, Int64Ty), Int64Align); + + if (MapType) + Builder.CreateAlignedStore( + Builder.CreateIntCast(MapType, Int64Ty, /*isSigned=*/false), + getArrayElementAddress(RTArgs.MapTypesArray, Int64Ty), Int64Align); + + if (RTArgs.MapTypesArrayEnd && MapType) + Builder.CreateAlignedStore( + Builder.CreateIntCast(MapTypeEnd ? MapTypeEnd : MapType, Int64Ty, + /*isSigned=*/false), + getArrayElementAddress(RTArgs.MapTypesArrayEnd, Int64Ty), Int64Align); + + Value *Mapper = MapperFunc ? MapperFunc : ConstantPointerNull::get(PtrTy); + if (MapperFunc) + Info.HasMapper = true; + Builder.CreateAlignedStore( + Mapper, getArrayElementAddress(RTArgs.MappersArray, PtrTy), PtrAlign); + + if (RTArgs.MapNamesArray && !isa<ConstantPointerNull>(RTArgs.MapNamesArray)) { + Value *Name = MapName ? MapName : ConstantPointerNull::get(PtrTy); + Builder.CreateAlignedStore( + Name, getArrayElementAddress(RTArgs.MapNamesArray, PtrTy), PtrAlign); + } + + if (Info.requiresDevicePointerInfo()) { + if (DevPtrType == DeviceInfoTy::Pointer) { + auto SavedIP = Builder.saveIP(); + Builder.restoreIP(AllocaIP); + Info.DevicePtrInfoMap[BasePtr] = {BPSlot, Builder.CreateAlloca(PtrTy)}; + Builder.restoreIP(SavedIP); + if (DeviceAddrCB) + DeviceAddrCB(DeviceAddrCBIndex, Info.DevicePtrInfoMap[BasePtr].second); + } else if (DevPtrType == DeviceInfoTy::Address) { + Info.DevicePtrInfoMap[BasePtr] = {BPSlot, BPSlot}; + if (DeviceAddrCB) + DeviceAddrCB(DeviceAddrCBIndex, BPSlot); + } + } +} + +void OpenMPIRBuilder::emitDynamicOffloadingArraysAllocas( + InsertPointTy AllocaIP, InsertPointTy CodeGenIP, TargetDataInfo &Info, + bool EmitDebug) { + assert(Info.TotalMapCount && "expected runtime map entry count"); + + Builder.restoreIP( + (isa<Constant>(Info.TotalMapCount) || isa<Argument>(Info.TotalMapCount)) + ? AllocaIP + : CodeGenIP); + Type *PtrTy = Builder.getPtrTy(); + Type *Int64Ty = Builder.getInt64Ty(); + Info.RTArgs.BasePointersArray = + Builder.CreateAlloca(PtrTy, Info.TotalMapCount, ".offload_baseptrs"); + Info.RTArgs.PointersArray = + Builder.CreateAlloca(PtrTy, Info.TotalMapCount, ".offload_ptrs"); + Info.RTArgs.SizesArray = + Builder.CreateAlloca(Int64Ty, Info.TotalMapCount, ".offload_sizes"); + Info.RTArgs.MapTypesArray = + Builder.CreateAlloca(Int64Ty, Info.TotalMapCount, ".offload_maptypes"); + Info.RTArgs.MappersArray = + Builder.CreateAlloca(PtrTy, Info.TotalMapCount, ".offload_mappers"); + + Info.EmitDebug = Info.EmitDebug || EmitDebug; + if (Info.EmitDebug) + Info.RTArgs.MapNamesArray = + Builder.CreateAlloca(PtrTy, Info.TotalMapCount, ".offload_mapnames"); + else + Info.RTArgs.MapNamesArray = + Constant::getNullValue(PointerType::getUnqual(Builder.getContext())); + + if (Info.separateBeginEndCalls()) + Info.RTArgs.MapTypesArrayEnd = Builder.CreateAlloca( + Int64Ty, Info.TotalMapCount, ".offload_maptypes_end"); + + restoreIPandDebugLoc(Builder, CodeGenIP); +} + Error OpenMPIRBuilder::emitOffloadingArrays( InsertPointTy AllocaIP, InsertPointTy CodeGenIP, MapInfosTy &CombinedInfo, TargetDataInfo &Info, CustomMapperCallbackTy CustomMapperCB, bool IsNonContiguous, - function_ref<void(unsigned int, Value *)> DeviceAddrCB) { + function_ref<void(unsigned int, Value *)> DeviceAddrCB, + DynMapEntriesCallbackTy DynMapEntriesCB) { + + TargetDataRTArgs PreallocatedRTArgs = Info.RTArgs; + bool HasPreallocatedDynamicStorage = + Info.TotalMapCount && Info.RTArgs.BasePointersArray; // Reset the array information. Info.clearArrayInfo(); Info.NumberOfPtrs = CombinedInfo.BasePointers.size(); - if (Info.NumberOfPtrs == 0) + if (Info.NumberOfPtrs == 0 && !Info.TotalMapCount) return Error::success(); + if (Info.TotalMapCount) { + auto mapTypeValue = [&](OpenMPOffloadMappingFlags Flags) { + return Builder.getInt64( + static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>( + Flags)); + }; + auto endMapTypeValue = [&](OpenMPOffloadMappingFlags Flags) { + uint64_t Mapping = + static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(Flags); + Mapping &= + ~static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>( + OpenMPOffloadMappingFlags::OMP_MAP_PRESENT); + return Builder.getInt64(Mapping); + }; + + Type *PtrTy = Builder.getPtrTy(); + if (HasPreallocatedDynamicStorage) + Info.RTArgs = PreallocatedRTArgs; + else + emitDynamicOffloadingArraysAllocas(AllocaIP, CodeGenIP, Info, + DynMapEntriesCB || + !CombinedInfo.Names.empty()); + + for (unsigned I = 0; I < Info.NumberOfPtrs; ++I) { + bool IsNonContigEntry = + IsNonContiguous && + (static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>( + CombinedInfo.Types[I] & + OpenMPOffloadMappingFlags::OMP_MAP_NON_CONTIG) != 0); + Value *Size = CombinedInfo.Sizes[I]; + if (IsNonContigEntry) { + assert(I < CombinedInfo.NonContigInfo.Dims.size() && + "Index must be in-bounds for NON_CONTIG Dims array"); + const uint64_t DimCount = CombinedInfo.NonContigInfo.Dims[I]; + assert(DimCount > 0 && "NON_CONTIG DimCount must be > 0"); + Size = Builder.getInt64(DimCount); + } + + Value *MapperFunc = nullptr; + auto CustomMFunc = CustomMapperCB(I); + if (!CustomMFunc) + return CustomMFunc.takeError(); + if (*CustomMFunc) + MapperFunc = Builder.CreatePointerCast(*CustomMFunc, PtrTy); + + Value *MapName = + I < CombinedInfo.Names.size() ? CombinedInfo.Names[I] : nullptr; + emitOffloadingArraysMapEntry( + Builder, Info.RTArgs, Info, Builder.getInt64(I), + CombinedInfo.BasePointers[I], CombinedInfo.Pointers[I], Size, + mapTypeValue(CombinedInfo.Types[I]), + endMapTypeValue(CombinedInfo.Types[I]), MapperFunc, MapName, + CombinedInfo.DevicePointers[I], AllocaIP, I, DeviceAddrCB); + } + + if (IsNonContiguous && !CombinedInfo.NonContigInfo.Offsets.empty() && + Info.NumberOfPtrs != 0) + emitNonContiguousDescriptor(AllocaIP, CodeGenIP, CombinedInfo, Info); + + if (DynMapEntriesCB) + return DynMapEntriesCB(Builder.saveIP(), Info.RTArgs, Info.NumberOfPtrs); + + return Error::success(); + } + Builder.restoreIP(AllocaIP); // Detect if we have any capture size requiring runtime evaluation of the // size so that a constant array could be eventually used. diff --git a/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp b/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp index 23432e2de2287..690d49b4e8c22 100644 --- a/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp +++ b/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp @@ -8127,6 +8127,132 @@ TEST_F(OpenMPIRBuilderTest, EmitOffloadingArraysArguments) { EXPECT_EQ(RTArgs.MapNamesArray->getType(), VoidPtrPtrTy); } +TEST_F(OpenMPIRBuilderTest, EmitDynamicOffloadingArraysMapEntries) { + OpenMPIRBuilder OMPBuilder(*M); + OMPBuilder.Config.setIsGPU(true); + OMPBuilder.initialize(); + IRBuilder<> Builder(BB); + + AllocaInst *StaticPtr = + Builder.CreateAlloca(Builder.getInt32Ty(), nullptr, "static.ptr"); + AllocaInst *DynamicPtr0 = + Builder.CreateAlloca(Builder.getInt64Ty(), nullptr, "dynamic.ptr.0"); + AllocaInst *DynamicPtr1 = + Builder.CreateAlloca(Builder.getInt8Ty(), nullptr, "dynamic.ptr.1"); + + OpenMPIRBuilder::MapInfosTy CombinedInfo; + CombinedInfo.BasePointers.push_back(StaticPtr); + CombinedInfo.Pointers.push_back(StaticPtr); + CombinedInfo.DevicePointers.push_back(OpenMPIRBuilder::DeviceInfoTy::None); + CombinedInfo.Sizes.push_back(Builder.getInt64(4)); + CombinedInfo.Types.push_back(omp::OpenMPOffloadMappingFlags::OMP_MAP_TO); + CombinedInfo.Names.push_back( + Builder.CreateGlobalString("static", "static_name", 0, M.get())); + + OpenMPIRBuilder::TargetDataInfo Info(false, false); + Info.TotalMapCount = Builder.getInt64(3); + OpenMPIRBuilder::TargetDataRTArgs RTArgs; + using InsertPointTy = OpenMPIRBuilder::InsertPointTy; + + auto mapTypeValue = [&](omp::OpenMPOffloadMappingFlags Flags) { + return Builder.getInt64( + static_cast<std::underlying_type_t<omp::OpenMPOffloadMappingFlags>>( + Flags)); + }; + omp::OpenMPOffloadMappingFlags ToFromMapType = + static_cast<omp::OpenMPOffloadMappingFlags>( + omp::OpenMPOffloadMappingFlags::OMP_MAP_TO | + omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM); + + bool DynamicCBWasCalled = false; + auto DynamicMapEntriesCB = + [&](InsertPointTy CodeGenIP, + OpenMPIRBuilder::TargetDataRTArgs &DynamicRTArgs, + unsigned StaticCount) -> Error { + DynamicCBWasCalled = true; + EXPECT_EQ(StaticCount, 1U); + Builder.restoreIP(CodeGenIP); + OMPBuilder.emitOffloadingArraysMapEntry( + Builder, DynamicRTArgs, Info, Builder.getInt64(StaticCount), + DynamicPtr0, DynamicPtr0, Builder.getInt64(8), + mapTypeValue(omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM)); + OMPBuilder.emitOffloadingArraysMapEntry( + Builder, DynamicRTArgs, Info, Builder.getInt64(StaticCount + 1), + DynamicPtr1, DynamicPtr1, Builder.getInt64(1), + mapTypeValue(ToFromMapType)); + return Error::success(); + }; + + EXPECT_FALSE(OMPBuilder.emitOffloadingArraysAndArgs( + InsertPointTy(Builder.saveIP()), InsertPointTy(Builder.saveIP()), Info, + RTArgs, CombinedInfo, + [](unsigned) -> Expected<Function *> { + return static_cast<Function *>(nullptr); + }, + /*IsNonContiguous=*/false, /*ForEndCall=*/false, + /*DeviceAddrCB=*/nullptr, DynamicMapEntriesCB)); + + EXPECT_TRUE(DynamicCBWasCalled); + EXPECT_EQ(Info.NumberOfPtrs, 1U); + EXPECT_TRUE(Info.isValid()); + + auto expectDynamicAlloca = [](Value *V, Type *AllocatedTy) { + auto *AI = dyn_cast<AllocaInst>(V); + EXPECT_NE(AI, nullptr); + if (!AI) + return AI; + EXPECT_EQ(AI->getAllocatedType(), AllocatedTy); + auto *Size = dyn_cast<ConstantInt>(AI->getArraySize()); + EXPECT_NE(Size, nullptr); + if (!Size) + return AI; + EXPECT_EQ(Size->getZExtValue(), 3U); + return AI; + }; + + AllocaInst *BasePtrsAlloca = + expectDynamicAlloca(Info.RTArgs.BasePointersArray, Builder.getPtrTy()); + ASSERT_NE(BasePtrsAlloca, nullptr); + EXPECT_EQ(RTArgs.BasePointersArray->stripPointerCasts(), BasePtrsAlloca); + expectDynamicAlloca(Info.RTArgs.PointersArray, Builder.getPtrTy()); + expectDynamicAlloca(Info.RTArgs.SizesArray, Builder.getInt64Ty()); + AllocaInst *MapTypesAlloca = + expectDynamicAlloca(Info.RTArgs.MapTypesArray, Builder.getInt64Ty()); + ASSERT_NE(MapTypesAlloca, nullptr); + expectDynamicAlloca(Info.RTArgs.MapNamesArray, Builder.getPtrTy()); + expectDynamicAlloca(Info.RTArgs.MappersArray, Builder.getPtrTy()); + + SmallVector<uint64_t, 4> MapTypeStoreValues; + SmallVector<uint64_t, 4> MapTypeStoreIndices; + for (Instruction &I : instructions(F)) { + auto *SI = dyn_cast<StoreInst>(&I); + if (!SI) + continue; + auto *GEP = dyn_cast<GetElementPtrInst>(SI->getPointerOperand()); + if (!GEP || GEP->getPointerOperand()->stripPointerCasts() != MapTypesAlloca) + continue; + auto *StoredValue = dyn_cast<ConstantInt>(SI->getValueOperand()); + ASSERT_NE(StoredValue, nullptr); + MapTypeStoreValues.push_back(StoredValue->getZExtValue()); + Value *IndexValue = *GEP->idx_begin(); + auto *Index = dyn_cast<ConstantInt>(IndexValue); + ASSERT_NE(Index, nullptr); + MapTypeStoreIndices.push_back(Index->getZExtValue()); + } + + EXPECT_THAT( + MapTypeStoreValues, + testing::UnorderedElementsAre( + static_cast<uint64_t>(omp::OpenMPOffloadMappingFlags::OMP_MAP_TO), + static_cast<uint64_t>(omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM), + static_cast<uint64_t>(ToFromMapType))); + EXPECT_THAT(MapTypeStoreIndices, testing::UnorderedElementsAre(0, 1, 2)); + + Builder.restoreIP(OMPBuilder.Builder.saveIP()); + Builder.CreateRetVoid(); + EXPECT_FALSE(verifyModule(*M, &errs())); +} + TEST_F(OpenMPIRBuilderTest, OffloadEntriesInfoManager) { OpenMPIRBuilder OMPBuilder(*M); OMPBuilder.setConfig( diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp index d35e8612e158b..5d053d7c32340 100644 --- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp @@ -493,14 +493,9 @@ static LogicalResult checkImplementationStatus(Operation &op) { if (totalBits > 128) result = todo("compare for complex types wider than 128 bits"); }) - .Case<omp::TargetEnterDataOp, omp::TargetExitDataOp>([&](auto op) { - checkDepend(op, result); - checkMap(op, result); - }) - .Case([&](omp::TargetUpdateOp op) { - checkDepend(op, result); - checkMap(op, result); - }) + .Case<omp::TargetEnterDataOp, omp::TargetExitDataOp>( + [&](auto op) { checkDepend(op, result); }) + .Case([&](omp::TargetUpdateOp op) { checkDepend(op, result); }) .Case([&](omp::TargetOp op) { checkAllocate(op, result); checkBare(op, result); @@ -508,7 +503,7 @@ static LogicalResult checkImplementationStatus(Operation &op) { checkMap(op, result); checkThreadLimit(op, result); }) - .Case([&](omp::TargetDataOp op) { checkMap(op, result); }) + .Case([&](omp::TargetDataOp) {}) .Case([&](omp::DeclareMapperInfoOp op) { checkMap(op, result); }) .Default([](Operation &) { // Assume all clauses for an operation can be translated unless they are @@ -6757,6 +6752,7 @@ convertOmpTargetData(Operation *op, llvm::IRBuilderBase &builder, llvm::Value *ifCond = nullptr; llvm::Value *deviceID = builder.getInt64(llvm::omp::OMP_DEVICEID_UNDEF); SmallVector<Value> mapVars; + SmallVector<Value> mapIterated; SmallVector<Value> useDevicePtrVars; SmallVector<Value> useDeviceAddrVars; llvm::omp::RuntimeFunction RTLFn; @@ -6789,6 +6785,7 @@ convertOmpTargetData(Operation *op, llvm::IRBuilderBase &builder, deviceID = getDeviceID(devId); mapVars = dataOp.getMapVars(); + mapIterated = dataOp.getMapIterated(); useDevicePtrVars = dataOp.getUseDevicePtrVars(); useDeviceAddrVars = dataOp.getUseDeviceAddrVars(); return success(); @@ -6808,6 +6805,7 @@ convertOmpTargetData(Operation *op, llvm::IRBuilderBase &builder, ? llvm::omp::OMPRTL___tgt_target_data_begin_nowait_mapper : llvm::omp::OMPRTL___tgt_target_data_begin_mapper; mapVars = enterDataOp.getMapVars(); + mapIterated = enterDataOp.getMapIterated(); info.HasNoWait = enterDataOp.getNowait(); return success(); }) @@ -6825,6 +6823,7 @@ convertOmpTargetData(Operation *op, llvm::IRBuilderBase &builder, ? llvm::omp::OMPRTL___tgt_target_data_end_nowait_mapper : llvm::omp::OMPRTL___tgt_target_data_end_mapper; mapVars = exitDataOp.getMapVars(); + mapIterated = exitDataOp.getMapIterated(); info.HasNoWait = exitDataOp.getNowait(); return success(); }) @@ -6843,6 +6842,7 @@ convertOmpTargetData(Operation *op, llvm::IRBuilderBase &builder, ? llvm::omp::OMPRTL___tgt_target_data_update_nowait_mapper : llvm::omp::OMPRTL___tgt_target_data_update_mapper; mapVars = updateDataOp.getMapVars(); + mapIterated = updateDataOp.getMapIterated(); info.HasNoWait = updateDataOp.getNowait(); return success(); }) @@ -6859,15 +6859,145 @@ convertOmpTargetData(Operation *op, llvm::IRBuilderBase &builder, collectMapDataFromMapOperands(mapData, mapVars, moduleTranslation, DL, builder, useDevicePtrVars, useDeviceAddrVars); + llvm::SmallVector<IteratorInfo, 2> iterInfos; + for (Value iter : mapIterated) { + auto itersOp = iter.getDefiningOp<omp::IteratorOp>(); + assert(itersOp && "map_iterated value must be defined by omp.iterator"); + auto yield = + dyn_cast<omp::YieldOp>(itersOp.getRegion().front().getTerminator()); + assert(yield && yield.getResults().size() == 1 && + "expect omp.yield in iterator region to have one result"); + auto mapInfoOp = yield.getResults()[0].getDefiningOp<omp::MapInfoOp>(); + assert(mapInfoOp && "expect iterator to yield omp.map.info"); + + if (!mapInfoOp.getMembers().empty()) { + mapInfoOp.emitError() + << "not yet implemented: map/motion clause with iterator modifier " + "that expands to member maps"; + return failure(); + } + + iterInfos.emplace_back(itersOp, moduleTranslation, builder); + } + // Fill up the arrays with all the mapped variables. MapInfosTy combinedInfo; auto genMapInfoCB = [&](InsertPointTy codeGenIP) -> MapInfosTy & { builder.restoreIP(codeGenIP); genMapInfos(builder, moduleTranslation, DL, combinedInfo, mapData, targetDirective); + if (!iterInfos.empty()) { + info.TotalMapCount = builder.getInt64(combinedInfo.BasePointers.size()); + for (IteratorInfo &iterInfo : iterInfos) + info.TotalMapCount = + builder.CreateAdd(info.TotalMapCount, iterInfo.getTotalTrips()); + } return combinedInfo; }; + auto dynMapEntriesCB = [&](InsertPointTy codeGenIP, + llvm::OpenMPIRBuilder::TargetDataRTArgs &rtArgs, + unsigned staticCount) -> llvm::Error { + builder.restoreIP(codeGenIP); + llvm::Value *offset = builder.getInt64(staticCount); + llvm::Error dynError = llvm::Error::success(); + + auto mapTypeValue = + [&](llvm::omp::OpenMPOffloadMappingFlags flags) -> llvm::Value * { + return builder.getInt64( + static_cast< + std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>( + flags)); + }; + auto endMapTypeValue = + [&](llvm::omp::OpenMPOffloadMappingFlags flags) -> llvm::Value * { + uint64_t mapping = static_cast< + std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>(flags); + mapping &= ~static_cast< + std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>( + llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_PRESENT); + return builder.getInt64(mapping); + }; + + for (auto [i, iterInfo] : llvm::enumerate(iterInfos)) { + auto itersOp = mapIterated[i].getDefiningOp<omp::IteratorOp>(); + if (failed(fillIteratorLoop( + itersOp, builder, moduleTranslation, iterInfo, "map_iterator", + [&](llvm::Value *linearIV, omp::YieldOp yield) { + if (dynError) + return; + + Value yieldedMap = yield.getResults()[0]; + SmallVector<Value> iterMapVars{yieldedMap}; + MapInfoData iterMapData; + collectMapDataFromMapOperands(iterMapData, iterMapVars, + moduleTranslation, DL, builder); + + MapInfosTy iterCombinedInfo; + genMapInfos(builder, moduleTranslation, DL, iterCombinedInfo, + iterMapData, targetDirective); + + if (!iterCombinedInfo.NonContigInfo.Offsets.empty()) { + yield.emitError() + << "not yet implemented: map/motion clause with iterator " + "modifier and non-contiguous map bounds"; + dynError = llvm::make_error<PreviouslyReportedError>(); + return; + } + if (iterCombinedInfo.BasePointers.size() != 1) { + yield.emitError() + << "not yet implemented: map/motion clause with iterator " + "modifier that expands to multiple map entries"; + dynError = llvm::make_error<PreviouslyReportedError>(); + return; + } + + llvm::Value *mapperFunc = nullptr; + if (iterCombinedInfo.Mappers[0]) { + llvm::Function *mapperFn = nullptr; + { + llvm::IRBuilderBase::InsertPointGuard guard(builder); + llvm::Expected<llvm::Function *> mapper = + getOrCreateUserDefinedMapperFunc( + iterCombinedInfo.Mappers[0], builder, + moduleTranslation, targetDirective); + if (!mapper) { + dynError = mapper.takeError(); + return; + } + mapperFn = *mapper; + } + mapperFunc = + builder.CreatePointerCast(mapperFn, builder.getPtrTy()); + } + + llvm::Value *idx = builder.CreateAdd(offset, linearIV); + llvm::Value *mapName = iterCombinedInfo.Names.empty() + ? nullptr + : iterCombinedInfo.Names[0]; + ompBuilder->emitOffloadingArraysMapEntry( + builder, rtArgs, info, idx, + iterCombinedInfo.BasePointers[0], + iterCombinedInfo.Pointers[0], iterCombinedInfo.Sizes[0], + mapTypeValue(iterCombinedInfo.Types[0]), + endMapTypeValue(iterCombinedInfo.Types[0]), mapperFunc, + mapName); + }))) { + if (dynError) + return dynError; + return llvm::make_error<PreviouslyReportedError>(); + } + if (dynError) + return dynError; + + offset = builder.CreateAdd(offset, iterInfo.getTotalTrips()); + } + + ompBuilder->updateToLocation( + llvm::OpenMPIRBuilder::LocationDescription(builder)); + return llvm::Error::success(); + }; + // Define a lambda to apply mappings between use_device_addr and // use_device_ptr base pointers, and their associated block arguments. auto mapUseDevice = @@ -6975,12 +7105,27 @@ convertOmpTargetData(Operation *op, llvm::IRBuilderBase &builder, llvm::OpenMPIRBuilder::InsertPointTy allocaIP = findAllocInsertPoints(builder, moduleTranslation, &deallocBlocks); llvm::OpenMPIRBuilder::InsertPointOrErrorTy afterIP = [&]() { - if (isa<omp::TargetDataOp>(op)) + if (isa<omp::TargetDataOp>(op)) { + if (!mapIterated.empty()) + return ompBuilder->createTargetData( + ompLoc, allocaIP, builder.saveIP(), deallocBlocks, deviceID, ifCond, + info, genMapInfoCB, customMapperCB, + /*MapperFunc=*/nullptr, bodyGenCB, + /*DeviceAddrCB=*/nullptr, + /*SrcLocInfo=*/nullptr, dynMapEntriesCB); return ompBuilder->createTargetData(ompLoc, allocaIP, builder.saveIP(), deallocBlocks, deviceID, ifCond, info, genMapInfoCB, customMapperCB, /*MapperFunc=*/nullptr, bodyGenCB, /*DeviceAddrCB=*/nullptr); + } + if (!mapIterated.empty()) + return ompBuilder->createTargetData( + ompLoc, allocaIP, builder.saveIP(), deallocBlocks, deviceID, ifCond, + info, genMapInfoCB, customMapperCB, &RTLFn, + /*BodyGenCB=*/nullptr, + /*DeviceAddrCB=*/nullptr, + /*SrcLocInfo=*/nullptr, dynMapEntriesCB); return ompBuilder->createTargetData(ompLoc, allocaIP, builder.saveIP(), deallocBlocks, deviceID, ifCond, info, genMapInfoCB, customMapperCB, &RTLFn); diff --git a/mlir/test/Target/LLVMIR/openmp-iterator.mlir b/mlir/test/Target/LLVMIR/openmp-iterator.mlir index 50afb68c4ce99..59aee4165bb74 100644 --- a/mlir/test/Target/LLVMIR/openmp-iterator.mlir +++ b/mlir/test/Target/LLVMIR/openmp-iterator.mlir @@ -478,6 +478,174 @@ module attributes {omp.is_target_device = false, omp.target_triples = ["amdgcn-a } llvm.return } + + omp.declare_mapper @simple_mapper : !llvm.struct<"SimpleMapperTy", (i32)> { + ^bb0(%arg0: !llvm.ptr): + %field = llvm.getelementptr %arg0[0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"SimpleMapperTy", (i32)> + %map = omp.map.info var_ptr(%field : !llvm.ptr, i32) + map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = "field"} + omp.declare_mapper.info map_entries(%map : !llvm.ptr) + } + + // ------------------------------------------------------------------ + // Map/motion clause with iterator modifier + // ------------------------------------------------------------------ + + llvm.func @target_update_map_iterator(%arr: !llvm.ptr) { + %c0 = llvm.mlir.constant(0 : i64) : i64 + %c10 = llvm.mlir.constant(10 : i64) : i64 + %c1 = llvm.mlir.constant(1 : i64) : i64 + + %it = omp.iterator(%iv: i64) = (%c0 to %c10 step %c1) { + %elem = llvm.getelementptr %arr[%iv] : (!llvm.ptr, i64) -> !llvm.ptr, i32 + %map = omp.map.info var_ptr(%elem : !llvm.ptr, i32) + map_clauses(to) capture(ByRef) -> !llvm.ptr {name = ""} + omp.yield(%map : !llvm.ptr) + } -> !omp.iterated<!llvm.ptr> + + omp.target_update map_iterated(%it : !omp.iterated<!llvm.ptr>) + llvm.return + } + + llvm.func @target_update_multiple_map_iterators(%a: !llvm.ptr, %b: !llvm.ptr) { + %c0 = llvm.mlir.constant(0 : i64) : i64 + %c1 = llvm.mlir.constant(1 : i64) : i64 + %c2 = llvm.mlir.constant(2 : i64) : i64 + + %ita = omp.iterator(%iv: i64) = (%c0 to %c2 step %c1) { + %elem = llvm.getelementptr %a[%iv] : (!llvm.ptr, i64) -> !llvm.ptr, i32 + %map = omp.map.info var_ptr(%elem : !llvm.ptr, i32) + map_clauses(to) capture(ByRef) -> !llvm.ptr {name = ""} + omp.yield(%map : !llvm.ptr) + } -> !omp.iterated<!llvm.ptr> + + %itb = omp.iterator(%iv: i64) = (%c0 to %c1 step %c1) { + %elem = llvm.getelementptr %b[%iv] : (!llvm.ptr, i64) -> !llvm.ptr, i64 + %map = omp.map.info var_ptr(%elem : !llvm.ptr, i64) + map_clauses(from) capture(ByRef) -> !llvm.ptr {name = ""} + omp.yield(%map : !llvm.ptr) + } -> !omp.iterated<!llvm.ptr> + + omp.target_update map_iterated(%ita, %itb : !omp.iterated<!llvm.ptr>, !omp.iterated<!llvm.ptr>) + llvm.return + } + + llvm.func @target_enter_data_map_iterator_mixed(%arr: !llvm.ptr, %scalar: !llvm.ptr) { + %c0 = llvm.mlir.constant(0 : i64) : i64 + %c10 = llvm.mlir.constant(10 : i64) : i64 + %c1 = llvm.mlir.constant(1 : i64) : i64 + + %static_map = omp.map.info var_ptr(%scalar : !llvm.ptr, f64) + map_clauses(to) capture(ByRef) -> !llvm.ptr {name = "scalar"} + + %it = omp.iterator(%iv: i64) = (%c0 to %c10 step %c1) { + %elem = llvm.getelementptr %arr[%iv] : (!llvm.ptr, i64) -> !llvm.ptr, i32 + %map = omp.map.info var_ptr(%elem : !llvm.ptr, i32) + map_clauses(to) capture(ByRef) -> !llvm.ptr {name = ""} + omp.yield(%map : !llvm.ptr) + } -> !omp.iterated<!llvm.ptr> + + omp.target_enter_data map_entries(%static_map : !llvm.ptr) map_iterated(%it : !omp.iterated<!llvm.ptr>) {} + llvm.return + } + + llvm.func @target_exit_data_map_iterator(%arr: !llvm.ptr) { + %c0 = llvm.mlir.constant(0 : i64) : i64 + %c5 = llvm.mlir.constant(5 : i64) : i64 + %c1 = llvm.mlir.constant(1 : i64) : i64 + + %it = omp.iterator(%iv: i64) = (%c0 to %c5 step %c1) { + %elem = llvm.getelementptr %arr[%iv] : (!llvm.ptr, i64) -> !llvm.ptr, i32 + %map = omp.map.info var_ptr(%elem : !llvm.ptr, i32) + map_clauses(from) capture(ByRef) -> !llvm.ptr {name = ""} + omp.yield(%map : !llvm.ptr) + } -> !omp.iterated<!llvm.ptr> + + omp.target_exit_data map_iterated(%it : !omp.iterated<!llvm.ptr>) {} + llvm.return + } + + llvm.func @target_data_map_iterator(%arr: !llvm.ptr) { + %c0 = llvm.mlir.constant(0 : i64) : i64 + %c2 = llvm.mlir.constant(2 : i64) : i64 + %c1 = llvm.mlir.constant(1 : i64) : i64 + + %it = omp.iterator(%iv: i64) = (%c0 to %c2 step %c1) { + %elem = llvm.getelementptr %arr[%iv] : (!llvm.ptr, i64) -> !llvm.ptr, i32 + %map = omp.map.info var_ptr(%elem : !llvm.ptr, i32) + map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""} + omp.yield(%map : !llvm.ptr) + } -> !omp.iterated<!llvm.ptr> + + omp.target_data map_iterated(%it : !omp.iterated<!llvm.ptr>) { + omp.terminator + } + llvm.return + } + + llvm.func @target_data_if_map_iterator_dynamic( + %arr: !llvm.ptr, %lb: i64, %ub: i64, %step: i64, %cond: i1) { + %it = omp.iterator(%iv: i64) = (%lb to %ub step %step) { + %elem = llvm.getelementptr %arr[%iv] : (!llvm.ptr, i64) -> !llvm.ptr, i32 + %map = omp.map.info var_ptr(%elem : !llvm.ptr, i32) + map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""} + omp.yield(%map : !llvm.ptr) + } -> !omp.iterated<!llvm.ptr> + + omp.target_data if(%cond) map_iterated(%it : !omp.iterated<!llvm.ptr>) { + omp.terminator + } + llvm.return + } + + llvm.func @target_enter_data_map_iterator_dynamic( + %arr: !llvm.ptr, %lb: i64, %ub: i64, %step: i64) { + %it = omp.iterator(%iv: i64) = (%lb to %ub step %step) { + %elem = llvm.getelementptr %arr[%iv] : (!llvm.ptr, i64) -> !llvm.ptr, i32 + %map = omp.map.info var_ptr(%elem : !llvm.ptr, i32) + map_clauses(to) capture(ByRef) -> !llvm.ptr {name = ""} + omp.yield(%map : !llvm.ptr) + } -> !omp.iterated<!llvm.ptr> + + omp.target_enter_data map_iterated(%it : !omp.iterated<!llvm.ptr>) {} + llvm.return + } + + llvm.func @target_enter_data_map_iterator_2d(%arr: !llvm.ptr) { + %c0 = llvm.mlir.constant(0 : i64) : i64 + %c1 = llvm.mlir.constant(1 : i64) : i64 + %c2 = llvm.mlir.constant(2 : i64) : i64 + %c3 = llvm.mlir.constant(3 : i64) : i64 + + %it = omp.iterator(%i: i64, %j: i64) = + (%c0 to %c1 step %c1, %c0 to %c2 step %c1) { + %row = llvm.mul %i, %c3 : i64 + %linear = llvm.add %row, %j : i64 + %elem = llvm.getelementptr %arr[%linear] : (!llvm.ptr, i64) -> !llvm.ptr, i32 + %map = omp.map.info var_ptr(%elem : !llvm.ptr, i32) + map_clauses(to) capture(ByRef) -> !llvm.ptr {name = ""} + omp.yield(%map : !llvm.ptr) + } -> !omp.iterated<!llvm.ptr> + + omp.target_enter_data map_iterated(%it : !omp.iterated<!llvm.ptr>) {} + llvm.return + } + + llvm.func @target_enter_data_map_iterator_mapper(%arr: !llvm.ptr) { + %c0 = llvm.mlir.constant(0 : i64) : i64 + %c2 = llvm.mlir.constant(2 : i64) : i64 + %c1 = llvm.mlir.constant(1 : i64) : i64 + + %it = omp.iterator(%iv: i64) = (%c0 to %c2 step %c1) { + %elem = llvm.getelementptr %arr[%iv] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<"SimpleMapperTy", (i32)> + %map = omp.map.info var_ptr(%elem : !llvm.ptr, !llvm.struct<"SimpleMapperTy", (i32)>) + map_clauses(to) capture(ByRef) mapper(@simple_mapper) -> !llvm.ptr {name = ""} + omp.yield(%map : !llvm.ptr) + } -> !omp.iterated<!llvm.ptr> + + omp.target_enter_data map_iterated(%it : !omp.iterated<!llvm.ptr>) {} + llvm.return + } } // TARGET-LABEL: define void @omp_target_depend_iterator @@ -513,3 +681,143 @@ module attributes {omp.is_target_device = false, omp.target_triples = ["amdgcn-a // TARGET: call void @.omp_target_task_proxy_func // TARGET: call void @__kmpc_omp_task_complete_if0 // TARGET: tail call void @free(ptr %[[DEP_ARR]]) + +// target_update lowers iterated motion entries into dynamic offload arrays. +// TARGET-LABEL: define void @target_update_map_iterator +// TARGET-SAME: (ptr %[[ARR:[0-9]+]]) +// TARGET-DAG: %[[BASEPTRS:[^ ]*offload_baseptrs]] = alloca ptr, i64 11 +// TARGET-DAG: %[[PTRS:[^ ]*offload_ptrs]] = alloca ptr, i64 11 +// TARGET-DAG: %[[SIZES:[^ ]*offload_sizes]] = alloca i64, i64 11 +// TARGET-DAG: %[[TYPES:[^ ]*offload_maptypes]] = alloca i64, i64 11 +// TARGET: omp_map_iterator.body{{.*}}: +// TARGET: %[[ELEM:.*]] = getelementptr i32, ptr %[[ARR]], i64 %{{.*}} +// TARGET: %[[IDX:.*]] = add i64 0, %{{.*}} +// TARGET: %[[BP_SLOT:.*]] = getelementptr inbounds ptr, ptr %[[BASEPTRS]], i64 %[[IDX]] +// TARGET: store ptr %[[ELEM]], ptr %[[BP_SLOT]] +// TARGET: %[[P_SLOT:.*]] = getelementptr inbounds ptr, ptr %[[PTRS]], i64 %[[IDX]] +// TARGET: store ptr %[[ELEM]], ptr %[[P_SLOT]] +// TARGET: %[[SIZE_SLOT:.*]] = getelementptr inbounds i64, ptr %[[SIZES]], i64 %[[IDX]] +// TARGET: store i64 4, ptr %[[SIZE_SLOT]] +// TARGET: %[[TYPE_SLOT:.*]] = getelementptr inbounds i64, ptr %[[TYPES]], i64 %[[IDX]] +// TARGET: store i64 1, ptr %[[TYPE_SLOT]] +// TARGET: call void @__tgt_target_data_update_mapper(ptr @{{.*}}, i64 -1, i32 11, ptr %[[BASEPTRS]], ptr %[[PTRS]], ptr %[[SIZES]], ptr %[[TYPES]], + +// Multiple map_iterated operands are appended in operand order into one set of +// dynamic offload arrays. +// TARGET-LABEL: define void @target_update_multiple_map_iterators +// TARGET-SAME: (ptr %[[ARRA:[0-9]+]], ptr %[[ARRB:[0-9]+]]) +// TARGET-DAG: %[[BASEPTRSM:[^ ]*offload_baseptrs]] = alloca ptr, i64 5 +// TARGET-DAG: %[[PTRSM:[^ ]*offload_ptrs]] = alloca ptr, i64 5 +// TARGET-DAG: %[[SIZESM:[^ ]*offload_sizes]] = alloca i64, i64 5 +// TARGET-DAG: %[[TYPESM:[^ ]*offload_maptypes]] = alloca i64, i64 5 +// TARGET: omp_map_iterator.body{{.*}}: +// TARGET: %[[ELEMA:.*]] = getelementptr i32, ptr %[[ARRA]], i64 %{{.*}} +// TARGET: %[[IDXA:.*]] = add i64 0, %{{.*}} +// TARGET: %[[BPSLOTA:.*]] = getelementptr inbounds ptr, ptr %[[BASEPTRSM]], i64 %[[IDXA]] +// TARGET: store ptr %[[ELEMA]], ptr %[[BPSLOTA]] +// TARGET: %[[PSLOTA:.*]] = getelementptr inbounds ptr, ptr %[[PTRSM]], i64 %[[IDXA]] +// TARGET: store ptr %[[ELEMA]], ptr %[[PSLOTA]] +// TARGET: %[[SIZESLOTA:.*]] = getelementptr inbounds i64, ptr %[[SIZESM]], i64 %[[IDXA]] +// TARGET: store i64 4, ptr %[[SIZESLOTA]] +// TARGET: %[[TYPESLOTA:.*]] = getelementptr inbounds i64, ptr %[[TYPESM]], i64 %[[IDXA]] +// TARGET: store i64 1, ptr %[[TYPESLOTA]] +// TARGET: omp_map_iterator.body{{.*}}: +// TARGET: %[[ELEMB:.*]] = getelementptr i64, ptr %[[ARRB]], i64 %{{.*}} +// TARGET: %[[IDXB:.*]] = add i64 3, %{{.*}} +// TARGET: %[[BPSLOTB:.*]] = getelementptr inbounds ptr, ptr %[[BASEPTRSM]], i64 %[[IDXB]] +// TARGET: store ptr %[[ELEMB]], ptr %[[BPSLOTB]] +// TARGET: %[[PSLOTB:.*]] = getelementptr inbounds ptr, ptr %[[PTRSM]], i64 %[[IDXB]] +// TARGET: store ptr %[[ELEMB]], ptr %[[PSLOTB]] +// TARGET: %[[SIZESLOTB:.*]] = getelementptr inbounds i64, ptr %[[SIZESM]], i64 %[[IDXB]] +// TARGET: store i64 8, ptr %[[SIZESLOTB]] +// TARGET: %[[TYPESLOTB:.*]] = getelementptr inbounds i64, ptr %[[TYPESM]], i64 %[[IDXB]] +// TARGET: store i64 2, ptr %[[TYPESLOTB]] +// TARGET: call void @__tgt_target_data_update_mapper(ptr @{{.*}}, i64 -1, i32 5, ptr %[[BASEPTRSM]], ptr %[[PTRSM]], ptr %[[SIZESM]], ptr %[[TYPESM]], + +// Static entries are stored first, followed by the iterator-expanded entries. +// TARGET-LABEL: define void @target_enter_data_map_iterator_mixed +// TARGET-SAME: (ptr %[[ARR2:[0-9]+]], ptr %[[SCALAR:[0-9]+]]) +// TARGET-DAG: %[[BASEPTRS2:[^ ]*offload_baseptrs]] = alloca ptr, i64 12 +// TARGET: %[[STATIC_BP:.*]] = getelementptr inbounds ptr, ptr %[[BASEPTRS2]], i64 0 +// TARGET: store ptr %[[SCALAR]], ptr %[[STATIC_BP]] +// TARGET: omp_map_iterator.body: +// TARGET: %[[ELEM2:.*]] = getelementptr i32, ptr %[[ARR2]], i64 %{{.*}} +// TARGET: %[[IDX2:.*]] = add i64 1, %{{.*}} +// TARGET: %[[ITER_BP:.*]] = getelementptr inbounds ptr, ptr %[[BASEPTRS2]], i64 %[[IDX2]] +// TARGET: store ptr %[[ELEM2]], ptr %[[ITER_BP]] +// TARGET: call void @__tgt_target_data_begin_mapper(ptr @{{.*}}, i64 -1, i32 12, ptr %[[BASEPTRS2]], + +// target_exit_data preserves the iterator-expanded FROM map type. +// TARGET-LABEL: define void @target_exit_data_map_iterator +// TARGET-SAME: (ptr %[[ARR3:[0-9]+]]) +// TARGET-DAG: %[[BASEPTRS3:[^ ]*offload_baseptrs]] = alloca ptr, i64 6 +// TARGET-DAG: %[[TYPES3:[^ ]*offload_maptypes]] = alloca i64, i64 6 +// TARGET: omp_map_iterator.body: +// TARGET: %[[IDX3:.*]] = add i64 0, %omp_map_iterator.iv +// TARGET: %[[TYPE_SLOT3:.*]] = getelementptr inbounds i64, ptr %[[TYPES3]], i64 %[[IDX3]] +// TARGET: store i64 2, ptr %[[TYPE_SLOT3]] +// TARGET: call void @__tgt_target_data_end_mapper(ptr @{{.*}}, i64 -1, i32 6, ptr %[[BASEPTRS3]], + +// target_data uses the same dynamic arrays for begin and end runtime calls. +// TARGET-LABEL: define void @target_data_map_iterator +// TARGET-SAME: (ptr %[[ARR4:[0-9]+]]) +// TARGET-DAG: %[[BASEPTRS4:[^ ]*offload_baseptrs]] = alloca ptr, i64 3 +// TARGET-DAG: %[[TYPES4:[^ ]*offload_maptypes]] = alloca i64, i64 3 +// TARGET-DAG: %[[ENDTYPES4:[^ ]*offload_maptypes_end]] = alloca i64, i64 3 +// TARGET: omp_map_iterator.body: +// TARGET: store i64 3, ptr %{{.*}} +// TARGET: store i64 3, ptr %{{.*}} +// TARGET: call void @__tgt_target_data_begin_mapper(ptr @{{.*}}, i64 -1, i32 3, ptr %[[BASEPTRS4]] +// TARGET: call void @__tgt_target_data_end_mapper(ptr @{{.*}}, i64 -1, i32 3, ptr %[[BASEPTRS4]], ptr %{{.*}}, ptr %{{.*}}, ptr %[[ENDTYPES4]] + +// target_data with an if clause hoists dynamic count and array allocas before +// the begin/end control-flow split. +// TARGET-LABEL: define void @target_data_if_map_iterator_dynamic +// TARGET-SAME: (ptr %[[ARRIF:[0-9]+]], i64 %[[LBIF:[0-9]+]], i64 %[[UBIF:[0-9]+]], i64 %[[STEPIF:[0-9]+]], i1 %[[CONDIF:[0-9]+]]) +// TARGET: %[[DIFFIF:.*]] = sub i64 %[[UBIF]], %[[LBIF]] +// TARGET: %[[DIVIF:.*]] = sdiv i64 %[[DIFFIF]], %[[STEPIF]] +// TARGET: %[[TRIPSIF:.*]] = add i64 %[[DIVIF]], 1 +// TARGET: %[[TOTALIF:.*]] = add i64 0, %{{.*}} +// TARGET: %[[BASEPTRSIF:[^ ]*offload_baseptrs]] = alloca ptr, i64 %[[TOTALIF]] +// TARGET: br i1 %[[CONDIF]], label %omp_if.then +// TARGET: call void @__tgt_target_data_begin_mapper(ptr @{{.*}}, i64 -1, i32 %{{.*}}, ptr %[[BASEPTRSIF]] +// TARGET: call void @__tgt_target_data_end_mapper(ptr @{{.*}}, i64 -1, i32 %{{.*}}, ptr %[[BASEPTRSIF]] + +// Dynamic iterator bounds produce a runtime map count and VLA offload arrays. +// TARGET-LABEL: define void @target_enter_data_map_iterator_dynamic +// TARGET-SAME: (ptr %[[ARR5:[0-9]+]], i64 %[[LB:[0-9]+]], i64 %[[UB:[0-9]+]], i64 %[[STEP:[0-9]+]]) +// TARGET: %[[DIFF:.*]] = sub i64 %[[UB]], %[[LB]] +// TARGET: %[[DIV:.*]] = sdiv i64 %[[DIFF]], %[[STEP]] +// TARGET: %[[TRIPS:.*]] = add i64 %[[DIV]], 1 +// TARGET: %[[SCALED:.*]] = mul i64 1, %[[TRIPS]] +// TARGET: %[[TOTAL:.*]] = add i64 0, %[[SCALED]] +// TARGET-DAG: %[[BASEPTRS5:[^ ]*offload_baseptrs]] = alloca ptr, i64 %[[TOTAL]] +// TARGET-DAG: %[[PTRS5:[^ ]*offload_ptrs]] = alloca ptr, i64 %[[TOTAL]] +// TARGET: omp_map_iterator.body: +// TARGET: getelementptr i32, ptr %[[ARR5]], i64 %{{.*}} +// TARGET: %[[NPTRS:.*]] = trunc i64 %[[TOTAL]] to i32 +// TARGET: call void @__tgt_target_data_begin_mapper(ptr @{{.*}}, i64 -1, i32 %[[NPTRS]], ptr %[[BASEPTRS5]], ptr %[[PTRS5]], + +// Multidimensional iterators reconstruct physical IVs before filling the map +// entry for each linearized iteration. +// TARGET-LABEL: define void @target_enter_data_map_iterator_2d +// TARGET-SAME: (ptr %[[ARR2D:[0-9]+]]) +// TARGET-DAG: %[[BASEPTRS2D:[^ ]*offload_baseptrs]] = alloca ptr, i64 6 +// TARGET-DAG: %[[PTRS2D:[^ ]*offload_ptrs]] = alloca ptr, i64 6 +// TARGET: omp_map_iterator.body: +// TARGET: %[[REMJ:.*]] = urem i64 %{{.*}}, 3 +// TARGET: %[[DIVJ:.*]] = udiv i64 %{{.*}}, 3 +// TARGET: %[[REMI:.*]] = urem i64 %[[DIVJ]], 2 +// TARGET: %[[ROW:.*]] = mul i64 %{{.*}}, 3 +// TARGET: %[[LINEAR:.*]] = add i64 %[[ROW]], %{{.*}} +// TARGET: %[[ELEM2D:.*]] = getelementptr i32, ptr %[[ARR2D]], i64 %[[LINEAR]] +// TARGET: store ptr %[[ELEM2D]], ptr %{{.*}} +// TARGET: call void @__tgt_target_data_begin_mapper(ptr @{{.*}}, i64 -1, i32 6, ptr %[[BASEPTRS2D]], ptr %[[PTRS2D]], + +// Iterated entries preserve explicit mapper IDs in the mapper array. +// TARGET-LABEL: define void @target_enter_data_map_iterator_mapper +// TARGET-DAG: %[[MAPPERS6:[^ ]*offload_mappers]] = alloca ptr, i64 3 +// TARGET: omp_map_iterator.body: +// TARGET: %[[MAPPER_SLOT:.*]] = getelementptr inbounds ptr, ptr %[[MAPPERS6]], i64 %{{.*}} +// TARGET: store ptr @.omp_mapper.simple_mapper, ptr %[[MAPPER_SLOT]] +// TARGET: call void @__tgt_target_data_begin_mapper(ptr @{{.*}}, i64 -1, i32 3, ptr %{{.*}}, ptr %{{.*}}, ptr %{{.*}}, ptr %{{.*}}, ptr %{{.*}}, ptr %[[MAPPERS6]]) diff --git a/mlir/test/Target/LLVMIR/openmp-todo.mlir b/mlir/test/Target/LLVMIR/openmp-todo.mlir index fa08590978f43..084625818f31b 100644 --- a/mlir/test/Target/LLVMIR/openmp-todo.mlir +++ b/mlir/test/Target/LLVMIR/openmp-todo.mlir @@ -496,54 +496,6 @@ llvm.func @wsloop_order(%lb : i32, %ub : i32, %step : i32) { // ----- -llvm.func @target_enter_data_map_iterator(%addr : !llvm.ptr) { - %c0 = llvm.mlir.constant(0 : i64) : i64 - %c10 = llvm.mlir.constant(10 : i64) : i64 - %c1 = llvm.mlir.constant(1 : i64) : i64 - %it = omp.iterator(%iv: i64) = (%c0 to %c10 step %c1) { - %m = omp.map.info var_ptr(%addr : !llvm.ptr, i32) map_clauses(to) capture(ByRef) -> !llvm.ptr {name = ""} - omp.yield(%m : !llvm.ptr) - } -> !omp.iterated<!llvm.ptr> - // expected-error@below {{not yet implemented: Unhandled clause map/motion clause with iterator modifier in omp.target_enter_data operation}} - // expected-error@below {{LLVM Translation failed for operation: omp.target_enter_data}} - omp.target_enter_data map_iterated(%it : !omp.iterated<!llvm.ptr>) {} - llvm.return -} - -// ----- - -llvm.func @target_exit_data_map_iterator(%addr : !llvm.ptr) { - %c0 = llvm.mlir.constant(0 : i64) : i64 - %c10 = llvm.mlir.constant(10 : i64) : i64 - %c1 = llvm.mlir.constant(1 : i64) : i64 - %it = omp.iterator(%iv: i64) = (%c0 to %c10 step %c1) { - %m = omp.map.info var_ptr(%addr : !llvm.ptr, i32) map_clauses(from) capture(ByRef) -> !llvm.ptr {name = ""} - omp.yield(%m : !llvm.ptr) - } -> !omp.iterated<!llvm.ptr> - // expected-error@below {{not yet implemented: Unhandled clause map/motion clause with iterator modifier in omp.target_exit_data operation}} - // expected-error@below {{LLVM Translation failed for operation: omp.target_exit_data}} - omp.target_exit_data map_iterated(%it : !omp.iterated<!llvm.ptr>) {} - llvm.return -} - -// ----- - -llvm.func @target_update_map_iterator(%addr : !llvm.ptr) { - %c0 = llvm.mlir.constant(0 : i64) : i64 - %c10 = llvm.mlir.constant(10 : i64) : i64 - %c1 = llvm.mlir.constant(1 : i64) : i64 - %it = omp.iterator(%iv: i64) = (%c0 to %c10 step %c1) { - %m = omp.map.info var_ptr(%addr : !llvm.ptr, i32) map_clauses(to) capture(ByRef) -> !llvm.ptr {name = ""} - omp.yield(%m : !llvm.ptr) - } -> !omp.iterated<!llvm.ptr> - // expected-error@below {{not yet implemented: Unhandled clause map/motion clause with iterator modifier in omp.target_update operation}} - // expected-error@below {{LLVM Translation failed for operation: omp.target_update}} - omp.target_update map_iterated(%it : !omp.iterated<!llvm.ptr>) - llvm.return -} - -// ----- - llvm.func @target_map_iterated_unsupported(%addr : !llvm.ptr) { %c0 = llvm.mlir.constant(0 : i64) : i64 %c10 = llvm.mlir.constant(10 : i64) : i64 @@ -563,22 +515,6 @@ llvm.func @target_map_iterated_unsupported(%addr : !llvm.ptr) { // ----- -llvm.func @target_data_map_iterator(%addr : !llvm.ptr) { - %c0 = llvm.mlir.constant(0 : i64) : i64 - %c10 = llvm.mlir.constant(10 : i64) : i64 - %c1 = llvm.mlir.constant(1 : i64) : i64 - %it = omp.iterator(%iv: i64) = (%c0 to %c10 step %c1) { - %m = omp.map.info var_ptr(%addr : !llvm.ptr, i32) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""} - omp.yield(%m : !llvm.ptr) - } -> !omp.iterated<!llvm.ptr> - // expected-error@below {{not yet implemented: Unhandled clause map/motion clause with iterator modifier in omp.target_data operation}} - // expected-error@below {{LLVM Translation failed for operation: omp.target_data}} - omp.target_data map_iterated(%it : !omp.iterated<!llvm.ptr>) {} - llvm.return -} - -// ----- - module attributes {omp.target_triples = ["amdgcn-amd-amdhsa"]} { omp.declare_mapper @mapper_with_iterator : !llvm.struct<"mapper_type", (i32)> { ^bb0(%arg: !llvm.ptr): @@ -600,3 +536,21 @@ module attributes {omp.target_triples = ["amdgcn-amd-amdhsa"]} { llvm.return } } + +// ----- + +llvm.func @target_enter_data_map_iterator_members(%addr : !llvm.ptr) { + %c0 = llvm.mlir.constant(0 : i64) : i64 + %c10 = llvm.mlir.constant(10 : i64) : i64 + %c1 = llvm.mlir.constant(1 : i64) : i64 + %it = omp.iterator(%iv: i64) = (%c0 to %c10 step %c1) { + %field = llvm.getelementptr %addr[0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"map_type", (i32)> + %field_map = omp.map.info var_ptr(%field : !llvm.ptr, i32) map_clauses(to) capture(ByRef) -> !llvm.ptr {name = ""} + // expected-error@below {{not yet implemented: map/motion clause with iterator modifier that expands to member maps}} + %map = omp.map.info var_ptr(%addr : !llvm.ptr, !llvm.struct<"map_type", (i32)>) map_clauses(to) capture(ByRef) members(%field_map : [0] : !llvm.ptr) -> !llvm.ptr {name = ""} + omp.yield(%map : !llvm.ptr) + } -> !omp.iterated<!llvm.ptr> + // expected-error@below {{LLVM Translation failed for operation: omp.target_enter_data}} + omp.target_enter_data map_iterated(%it : !omp.iterated<!llvm.ptr>) {} + llvm.return +} diff --git a/offload/test/offloading/fortran/map-motion-iterator.f90 b/offload/test/offloading/fortran/map-motion-iterator.f90 new file mode 100644 index 0000000000000..498d2cf355c20 --- /dev/null +++ b/offload/test/offloading/fortran/map-motion-iterator.f90 @@ -0,0 +1,119 @@ +! Offloading test for iterator modifier on map and motion clauses. + +! REQUIRES: flang, amdgpu + +! RUN: %libomptarget-compile-fortran-run-and-check-generic + +program map_motion_iterator + implicit none + integer, parameter :: n = 8 + integer :: a(n), b(n), c(n), d(n), e(n) + integer :: i, dyn_n, dyn_step + logical :: use_device + + do i = 1, n + a(i) = i + end do + !$omp target enter data map(to: a) + !$omp target + do i = 2, n, 2 + a(i) = 100 + i + end do + !$omp end target + do i = 2, n, 2 + a(i) = -100 + end do + !$omp target update from(iterator(i = 2:n:2): a(i)) + !$omp target exit data map(delete: a) + + ! CHECK: update from: 1 102 3 104 5 106 7 108 + print *, "update from:", a + + do i = 1, n + b(i) = i + end do + !$omp target enter data map(to: b) + do i = 2, n, 2 + b(i) = 200 + i + end do + !$omp target update to(iterator(i = 2:n:2): b(i)) + !$omp target + do i = 2, n, 2 + b(i) = b(i) + 10 + end do + !$omp end target + do i = 2, n, 2 + b(i) = -100 + end do + !$omp target update from(iterator(i = 2:n:2): b(i)) + !$omp target exit data map(delete: b) + + ! CHECK: update tofrom: 1 212 3 214 5 216 7 218 + print *, "update tofrom:", b + + do i = 1, n + c(i) = i + end do + !$omp target enter data map(to: c) + !$omp target + c(1) = 11 + c(3) = 33 + c(5) = 55 + c(7) = 77 + !$omp end target + do i = 1, n, 2 + c(i) = -100 + end do + !$omp target exit data map(iterator(i = 1:n:2), from: c(i)) + !$omp target exit data map(delete: c) + + ! CHECK: exit data: 11 2 33 4 55 6 77 8 + print *, "exit data:", c + + do i = 1, n + d(i) = i + end do + !$omp target data map(iterator(i = 1:n:2), tofrom: d(i)) + !$omp target map(present, alloc: d(1)) + d(1) = 21 + !$omp end target + !$omp target map(present, alloc: d(3)) + d(3) = 43 + !$omp end target + !$omp target map(present, alloc: d(5)) + d(5) = 65 + !$omp end target + !$omp target map(present, alloc: d(7)) + d(7) = 87 + !$omp end target + !$omp end target data + + ! CHECK: target data: 21 2 43 4 65 6 87 8 + print *, "target data:", d + + dyn_n = n + dyn_step = 2 + use_device = .true. + do i = 1, n + e(i) = i + end do + !$omp target data if(use_device) & + !$omp& map(iterator(i = 1:dyn_n:dyn_step), tofrom: e(i)) + !$omp target map(present, alloc: e(1)) + e(1) = 31 + !$omp end target + !$omp target map(present, alloc: e(3)) + e(3) = 53 + !$omp end target + !$omp target map(present, alloc: e(5)) + e(5) = 75 + !$omp end target + !$omp target map(present, alloc: e(7)) + e(7) = 97 + !$omp end target + !$omp end target data + + ! CHECK: target data if: 31 2 53 4 75 6 97 8 + print *, "target data if:", e + +end program map_motion_iterator _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
