diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -498,11 +498,6 @@ LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/OMP_REQ_DYNAMIC_ALLOCATORS) }; -enum OpenMPOffloadingReservedDeviceIDs { - /// Device ID if the device was not defined, runtime should get it - /// from environment variables in the spec. - OMP_DEVICEID_UNDEF = -1, -}; } // anonymous namespace /// Describes ident structure that describes a source location. 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 @@ -241,6 +241,12 @@ LLVM_MARK_AS_BITMASK_ENUM(/* LargestFlag = */ OMP_MAP_MEMBER_OF) }; +enum OpenMPOffloadingReservedDeviceIDs { + /// Device ID if the device was not defined, runtime should get it + /// from environment variables in the spec. + OMP_DEVICEID_UNDEF = -1 +}; + enum class AddressSpace : unsigned { Generic = 0, Global = 1, 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 @@ -1095,6 +1095,9 @@ /// variables. StringMap InternalVars; + /// Computes the size of type in bytes. + Value *getSizeInBytes(Value *BasePtr); + /// Create the global variable holding the offload mappings information. GlobalVariable *createOffloadMaptypes(SmallVectorImpl &Mappings, std::string VarName); @@ -1550,6 +1553,29 @@ StringRef EntryFnIDName, int32_t NumTeams, int32_t NumThreads); + /// Generator for '#omp target data' + /// + /// \param Loc The location where the target data construct was encountered. + /// \param CodeGenIP The insertion point at which the target directive code + /// should be placed. + /// \param HasRegion True if the op has a region associated with it, false + /// otherwise + /// \param MapTypeFlags BitVector storing the mapType flags for the + /// mapOperands + /// \param MapNames Names for the mapOperands + /// \param MapperAllocas Pointers to the AllocInsts for the map clause + /// \param MapperFunc Mapper Fucntion to be called for the Target Data op + /// \param DeviceID Stores the DeviceID from the device clause + /// \param IfCond Value which corresponds to the if clause condition. + /// \param ProcessMapOpCB Callback that will generate the mapOperand code. + /// \param BodyGenCB Callback that will generate the region code. + OpenMPIRBuilder::InsertPointTy createTargetData( + const LocationDescription &Loc, OpenMPIRBuilder::InsertPointTy CodeGenIP, + bool HasRegion, SmallVector &MapTypeFlags, + SmallVector &MapNames, struct MapperAllocas &MapperAllocas, + Function *MapperFunc, int64_t DeviceID, Value *IfCond, + BodyGenCallbackTy ProcessMapOpCB, BodyGenCallbackTy BodyGenCB); + /// Declarations for LLVM-IR types (simple, array, function and structure) are /// generated below. Their names are defined and used in OpenMPKinds.def. Here /// we provide the declarations, the initializeTypes function will provide the 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 @@ -4038,6 +4038,74 @@ return OutlinedFnID; } +OpenMPIRBuilder::InsertPointTy OpenMPIRBuilder::createTargetData( + const LocationDescription &Loc, OpenMPIRBuilder::InsertPointTy CodeGenIP, + bool HasRegion, SmallVector &MapTypeFlags, + SmallVector &MapNames, struct MapperAllocas &MapperAllocas, + Function *MapperFunc, int64_t DeviceID, Value *IfCond, + BodyGenCallbackTy ProcessMapOpCB, BodyGenCallbackTy BodyGenCB) { + if (!updateToLocation(Loc)) + return InsertPointTy(); + + Builder.restoreIP(CodeGenIP); + + // LLVM utilities like blocks with terminators. + auto *UI = Builder.CreateUnreachable(); + Instruction *ThenTI = UI, *ElseTI = nullptr; + if (IfCond) { + SplitBlockAndInsertIfThenElse(IfCond, UI, &ThenTI, &ElseTI); + ThenTI->getParent()->setName("omp_if.then"); + ElseTI->getParent()->setName("omp_if.else"); + } + Builder.SetInsertPoint(ThenTI); + + ProcessMapOpCB(Builder.saveIP(), Builder.saveIP()); + + uint32_t SrcLocStrSize; + Constant *SrcLocStr = getOrCreateSrcLocStr(Loc, SrcLocStrSize); + Value *srcLocInfo = getOrCreateIdent(SrcLocStr, SrcLocStrSize); + + GlobalVariable *MapTypesGV = + createOffloadMaptypes(MapTypeFlags, ".offload_maptypes"); + Value *MapTypesArg = Builder.CreateConstInBoundsGEP2_32( + ArrayType::get(Builder.getInt64Ty(), MapTypeFlags.size()), MapTypesGV, + /*Idx0=*/0, /*Idx1=*/0); + + GlobalVariable *MapNamesGV = + createOffloadMapnames(MapNames, ".offload_mapnames"); + Value *MapNamesArg = Builder.CreateConstInBoundsGEP2_32( + ArrayType::get(Builder.getInt8PtrTy(), MapNames.size()), MapNamesGV, + /*Idx0=*/0, /*Idx1=*/0); + + if (HasRegion) { + Function *beginMapperFunc = getOrCreateRuntimeFunctionPtr( + omp::OMPRTL___tgt_target_data_begin_mapper); + Function *endMapperFunc = + getOrCreateRuntimeFunctionPtr(omp::OMPRTL___tgt_target_data_end_mapper); + + // Create call to start the data region. + emitMapperCall(Builder.saveIP(), beginMapperFunc, srcLocInfo, MapTypesArg, + MapNamesArg, MapperAllocas, DeviceID, MapTypeFlags.size()); + + BodyGenCB(Builder.saveIP(), Builder.saveIP()); + + Builder.SetInsertPoint(UI->getParent()); + // Create call to end the data region. + emitMapperCall(Builder.saveIP(), endMapperFunc, srcLocInfo, MapTypesArg, + MapNamesArg, MapperAllocas, DeviceID, MapTypeFlags.size()); + } else { + emitMapperCall(Builder.saveIP(), MapperFunc, srcLocInfo, MapTypesArg, + MapNamesArg, MapperAllocas, DeviceID, MapTypeFlags.size()); + } + + // Update the insertion point and remove the terminator we introduced. + Builder.SetInsertPoint(UI->getParent()); + if (IfCond) + UI->getParent()->setName("omp_if.end"); + UI->eraseFromParent(); + return Builder.saveIP(); +} + std::string OpenMPIRBuilder::getNameWithSeparators(ArrayRef Parts, StringRef FirstSeparator, StringRef Separator) { @@ -4085,6 +4153,15 @@ return getOrCreateInternalVariable(KmpCriticalNameTy, Name); } +Value *OpenMPIRBuilder::getSizeInBytes(Value *BasePtr) { + LLVMContext &Ctx = Builder.getContext(); + Value *Null = Constant::getNullValue(BasePtr->getType()->getPointerTo()); + Value *SizeGep = + Builder.CreateGEP(BasePtr->getType(), Null, Builder.getInt32(1)); + Value *SizePtrToInt = Builder.CreatePtrToInt(SizeGep, Type::getInt64Ty(Ctx)); + return SizePtrToInt; +} + GlobalVariable * OpenMPIRBuilder::createOffloadMaptypes(SmallVectorImpl &Mappings, std::string VarName) { diff --git a/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp b/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp --- a/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp +++ b/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp @@ -4912,6 +4912,84 @@ EXPECT_TRUE(MapperCall->getOperand(8)->getType()->isPointerTy()); } +TEST_F(OpenMPIRBuilderTest, TargetEnterData) { + OpenMPIRBuilder OMPBuilder(*M); + OMPBuilder.initialize(); + F->setName("func"); + IRBuilder<> Builder(BB); + + OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); + + unsigned NumDataOperands = 1; + int64_t DeviceID = 2; + struct OpenMPIRBuilder::MapperAllocas MapperAllocas; + SmallVector MapTypeflags = {5}; + SmallVector MapNames; + auto *I8PtrTy = Builder.getInt8PtrTy(); + auto *ArrI8PtrTy = ArrayType::get(I8PtrTy, NumDataOperands); + auto *I64Ty = Builder.getInt64Ty(); + auto *ArrI64Ty = ArrayType::get(I64Ty, NumDataOperands); + + AllocaInst *Val1 = + Builder.CreateAlloca(Builder.getInt32Ty(), Builder.getInt64(1)); + ASSERT_NE(Val1, nullptr); + + IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(), + F->getEntryBlock().getFirstInsertionPt()); + OMPBuilder.createMapperAllocas(Builder.saveIP(), AllocaIP, NumDataOperands, + MapperAllocas); + + using InsertPointTy = OpenMPIRBuilder::InsertPointTy; + auto ProcessMapOpCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP) { + Value *DataValue = Val1; + Value *DataPtrBase; + Value *DataPtr; + DataPtrBase = DataValue; + DataPtr = DataValue; + Builder.restoreIP(CodeGenIP); + + Value *Null = Constant::getNullValue(DataValue->getType()->getPointerTo()); + Value *SizeGep = + Builder.CreateGEP(DataValue->getType(), Null, Builder.getInt32(1)); + Value *SizePtrToInt = Builder.CreatePtrToInt(SizeGep, I64Ty); + + Value *PtrBaseGEP = + Builder.CreateInBoundsGEP(ArrI8PtrTy, MapperAllocas.ArgsBase, + {Builder.getInt32(0), Builder.getInt32(0)}); + Value *PtrBaseCast = Builder.CreateBitCast( + PtrBaseGEP, DataPtrBase->getType()->getPointerTo()); + Builder.CreateStore(DataPtrBase, PtrBaseCast); + Value *PtrGEP = + Builder.CreateInBoundsGEP(ArrI8PtrTy, MapperAllocas.Args, + {Builder.getInt32(0), Builder.getInt32(0)}); + Value *PtrCast = + Builder.CreateBitCast(PtrGEP, DataPtr->getType()->getPointerTo()); + Builder.CreateStore(DataPtr, PtrCast); + Value *SizeGEP = + Builder.CreateInBoundsGEP(ArrI64Ty, MapperAllocas.ArgSizes, + {Builder.getInt32(0), Builder.getInt32(0)}); + Builder.CreateStore(SizePtrToInt, SizeGEP); + }; + auto BodyCB = [&](InsertPointTy AllocaIP, InsertPointTy codeGenIP) {}; + + Builder.restoreIP(OMPBuilder.createTargetData( + Loc, Builder.saveIP(), /*hasRegion=*/false, MapTypeflags, MapNames, + MapperAllocas, + OMPBuilder.getOrCreateRuntimeFunctionPtr( + OMPRTL___tgt_target_data_begin_mapper), + DeviceID, /*ifCond=*/nullptr, ProcessMapOpCB, BodyCB)); + + CallInst *TargetDataCall = dyn_cast(&BB->back()); + BB->dump(); + EXPECT_NE(TargetDataCall, nullptr); + EXPECT_EQ(TargetDataCall->arg_size(), 9U); + EXPECT_EQ(TargetDataCall->getCalledFunction()->getName(), + "__tgt_target_data_begin_mapper"); + EXPECT_TRUE(TargetDataCall->getOperand(1)->getType()->isIntegerTy(64)); + EXPECT_TRUE(TargetDataCall->getOperand(2)->getType()->isIntegerTy(32)); + EXPECT_TRUE(TargetDataCall->getOperand(8)->getType()->isPointerTy()); +} + TEST_F(OpenMPIRBuilderTest, CreateTask) { using InsertPointTy = OpenMPIRBuilder::InsertPointTy; OpenMPIRBuilder OMPBuilder(*M); diff --git a/mlir/include/mlir/Target/LLVMIR/Dialect/OpenMPCommon.h b/mlir/include/mlir/Target/LLVMIR/Dialect/OpenMPCommon.h new file mode 100644 --- /dev/null +++ b/mlir/include/mlir/Target/LLVMIR/Dialect/OpenMPCommon.h @@ -0,0 +1,40 @@ +//===- OpenMPCommon.h - Utils for translating MLIR dialect to LLVM IR------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file defines general utilities for MLIR Dialect translations to LLVM IR. +// +//===----------------------------------------------------------------------===// + +#ifndef MLIR_TARGET_LLVMIR_DIALECT_UTILS_H +#define MLIR_TARGET_LLVMIR_DIALECT_UTILS_H + +#include "mlir/IR/BuiltinAttributes.h" +#include "mlir/IR/Location.h" +#include "mlir/Support/LLVM.h" + +#include "llvm/Frontend/OpenMP/OMPIRBuilder.h" +#include "llvm/IR/IRBuilder.h" + +namespace mlir { +namespace LLVM { + +/// Create a constant string location from the MLIR Location information. +llvm::Constant *createSourceLocStrFromLocation(Location loc, + llvm::OpenMPIRBuilder &builder, + StringRef name, + uint32_t &strLen); + +/// Create a constant string representing the mapping information extracted from +/// the MLIR location information. +llvm::Constant *createMappingInformation(Location loc, + llvm::OpenMPIRBuilder &builder); + +} // namespace LLVM +} // namespace mlir + +#endif // MLIR_TARGET_LLVMIR_DIALECT_UTILS_H diff --git a/mlir/lib/Target/LLVMIR/CMakeLists.txt b/mlir/lib/Target/LLVMIR/CMakeLists.txt --- a/mlir/lib/Target/LLVMIR/CMakeLists.txt +++ b/mlir/lib/Target/LLVMIR/CMakeLists.txt @@ -19,6 +19,7 @@ LoopAnnotationTranslation.cpp ModuleTranslation.cpp TypeToLLVM.cpp + Dialect/OpenMPCommon.cpp ADDITIONAL_HEADER_DIRS ${MLIR_MAIN_INCLUDE_DIR}/mlir/Target/LLVMIR diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenACC/OpenACCToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenACC/OpenACCToLLVMIRTranslation.cpp --- a/mlir/lib/Target/LLVMIR/Dialect/OpenACC/OpenACCToLLVMIRTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/Dialect/OpenACC/OpenACCToLLVMIRTranslation.cpp @@ -18,6 +18,7 @@ #include "mlir/IR/BuiltinOps.h" #include "mlir/IR/Operation.h" #include "mlir/Support/LLVM.h" +#include "mlir/Target/LLVMIR/Dialect/OpenMPCommon.h" #include "mlir/Target/LLVMIR/ModuleTranslation.h" #include "llvm/ADT/TypeSwitch.h" @@ -46,23 +47,6 @@ /// Default value for the device id static constexpr int64_t kDefaultDevice = -1; -/// Create a constant string location from the MLIR Location information. -static llvm::Constant *createSourceLocStrFromLocation(Location loc, - OpenACCIRBuilder &builder, - StringRef name, - uint32_t &strLen) { - if (auto fileLoc = loc.dyn_cast()) { - StringRef fileName = fileLoc.getFilename(); - unsigned lineNo = fileLoc.getLine(); - unsigned colNo = fileLoc.getColumn(); - return builder.getOrCreateSrcLocStr(name, fileName, lineNo, colNo, strLen); - } - std::string locStr; - llvm::raw_string_ostream locOS(locStr); - locOS << loc; - return builder.getOrCreateSrcLocStr(locOS.str(), strLen); -} - /// Create the location struct from the operation location information. static llvm::Value *createSourceLocationInfo(OpenACCIRBuilder &builder, Operation *op) { @@ -70,24 +54,11 @@ auto funcOp = op->getParentOfType(); StringRef funcName = funcOp ? funcOp.getName() : "unknown"; uint32_t strLen; - llvm::Constant *locStr = - createSourceLocStrFromLocation(loc, builder, funcName, strLen); + llvm::Constant *locStr = mlir::LLVM::createSourceLocStrFromLocation( + loc, builder, funcName, strLen); return builder.getOrCreateIdent(locStr, strLen); } -/// Create a constant string representing the mapping information extracted from -/// the MLIR location information. -static llvm::Constant *createMappingInformation(Location loc, - OpenACCIRBuilder &builder) { - uint32_t strLen; - if (auto nameLoc = loc.dyn_cast()) { - StringRef name = nameLoc.getName(); - return createSourceLocStrFromLocation(nameLoc.getChildLoc(), builder, name, - strLen); - } - return createSourceLocStrFromLocation(loc, builder, "unknown", strLen); -} - /// Return the runtime function used to lower the given operation. static llvm::Function *getAssociatedFunction(OpenACCIRBuilder &builder, Operation *op) { @@ -107,19 +78,6 @@ llvm_unreachable("Unknown OpenACC operation"); } -/// Computes the size of type in bytes. -static llvm::Value *getSizeInBytes(llvm::IRBuilderBase &builder, - llvm::Value *basePtr) { - llvm::LLVMContext &ctx = builder.getContext(); - llvm::Value *null = - llvm::Constant::getNullValue(basePtr->getType()->getPointerTo()); - llvm::Value *sizeGep = - builder.CreateGEP(basePtr->getType(), null, builder.getInt32(1)); - llvm::Value *sizePtrToInt = - builder.CreatePtrToInt(sizeGep, llvm::Type::getInt64Ty(ctx)); - return sizePtrToInt; -} - /// Extract pointer, size and mapping information from operands /// to populate the future functions arguments. static LogicalResult @@ -153,7 +111,7 @@ } else if (data.getType().isa()) { dataPtrBase = dataValue; dataPtr = dataValue; - dataSize = getSizeInBytes(builder, dataValue); + dataSize = accBuilder->getSizeInBytes(dataValue); } else { return op->emitOpError() << "Data operand must be legalized before translation." @@ -185,7 +143,7 @@ flags.push_back(operandFlag); llvm::Constant *mapName = - createMappingInformation(data.getLoc(), *accBuilder); + mlir::LLVM::createMappingInformation(data.getLoc(), *accBuilder); names.push_back(mapName); ++index; } diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp --- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp @@ -15,10 +15,12 @@ #include "mlir/IR/IRMapping.h" #include "mlir/IR/Operation.h" #include "mlir/Support/LLVM.h" +#include "mlir/Target/LLVMIR/Dialect/OpenMPCommon.h" #include "mlir/Target/LLVMIR/ModuleTranslation.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/TypeSwitch.h" +#include "llvm/Frontend/OpenMP/OMPConstants.h" #include "llvm/Frontend/OpenMP/OMPIRBuilder.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/IRBuilder.h" @@ -1351,6 +1353,191 @@ return success(); } +/// Process MapOperands for Target Data directives. +static LogicalResult processMapOperand( + llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation, + const SmallVector &mapOperands, const ArrayAttr &mapTypes, + SmallVector &mapTypeFlags, + SmallVectorImpl &mapNames, + struct llvm::OpenMPIRBuilder::MapperAllocas &mapperAllocas) { + auto numMapOperands = mapOperands.size(); + llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder(); + llvm::PointerType *i8PtrTy = builder.getInt8PtrTy(); + llvm::ArrayType *arrI8PtrTy = llvm::ArrayType::get(i8PtrTy, numMapOperands); + llvm::IntegerType *i64Ty = builder.getInt64Ty(); + llvm::ArrayType *arrI64Ty = llvm::ArrayType::get(i64Ty, numMapOperands); + + unsigned index = 0; + for (const auto &mapOp : mapOperands) { + const auto &mapTypeOp = mapTypes[index]; + + llvm::Value *mapOpValue = moduleTranslation.lookupValue(mapOp); + llvm::Value *mapOpPtrBase; + llvm::Value *mapOpPtr; + llvm::Value *mapOpSize; + + if (mapOp.getType().isa()) { + mapOpPtrBase = mapOpValue; + mapOpPtr = mapOpValue; + mapOpSize = ompBuilder->getSizeInBytes(mapOpValue); + } else { + return failure(); + } + + // Store base pointer extracted from operand into the i-th position of + // argBase. + llvm::Value *ptrBaseGEP = builder.CreateInBoundsGEP( + arrI8PtrTy, mapperAllocas.ArgsBase, + {builder.getInt32(0), builder.getInt32(index)}); + llvm::Value *ptrBaseCast = builder.CreateBitCast( + ptrBaseGEP, mapOpPtrBase->getType()->getPointerTo()); + builder.CreateStore(mapOpPtrBase, ptrBaseCast); + + // Store pointer extracted from operand into the i-th position of args. + llvm::Value *ptrGEP = builder.CreateInBoundsGEP( + arrI8PtrTy, mapperAllocas.Args, + {builder.getInt32(0), builder.getInt32(index)}); + llvm::Value *ptrCast = + builder.CreateBitCast(ptrGEP, mapOpPtr->getType()->getPointerTo()); + builder.CreateStore(mapOpPtr, ptrCast); + + // Store size extracted from operand into the i-th position of argSizes. + llvm::Value *sizeGEP = builder.CreateInBoundsGEP( + arrI64Ty, mapperAllocas.ArgSizes, + {builder.getInt32(0), builder.getInt32(index)}); + builder.CreateStore(mapOpSize, sizeGEP); + + mapTypeFlags.push_back(mapTypeOp.dyn_cast().getInt()); + llvm::Constant *mapName = + mlir::LLVM::createMappingInformation(mapOp.getLoc(), *ompBuilder); + mapNames.push_back(mapName); + ++index; + } + + return success(); +} + +static LogicalResult +convertOmpTargetData(Operation *op, llvm::IRBuilderBase &builder, + LLVM::ModuleTranslation &moduleTranslation) { + unsigned numMapOperands; + llvm::Function *mapperFunc; + llvm::Value *ifCond = nullptr; + int64_t deviceID = llvm::omp::OMP_DEVICEID_UNDEF; + SmallVector mapOperands; + ArrayAttr mapTypes; + + llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder(); + + LogicalResult result = + llvm::TypeSwitch(op) + .Case([&](omp::DataOp dataOp) { + if (dataOp.getUseDeviceAddr().size() || + dataOp.getUseDevicePtr().size()) + return failure(); + + if (auto ifExprVar = dataOp.getIfExpr()) + ifCond = moduleTranslation.lookupValue(ifExprVar); + + if (auto devId = dataOp.getDevice()) + if (auto constOp = mlir::dyn_cast( + devId.getDefiningOp())) + if (auto intAttr = + constOp.getValue().dyn_cast()) + deviceID = intAttr.getInt(); + + numMapOperands = dataOp.getMapOperands().size(); + mapOperands = dataOp.getMapOperands(); + mapTypes = dataOp.getMapTypes(); + return success(); + }) + .Case([&](omp::EnterDataOp enterDataOp) { + if (enterDataOp.getNowait()) + return failure(); + + if (auto ifExprVar = enterDataOp.getIfExpr()) + ifCond = moduleTranslation.lookupValue(ifExprVar); + + if (auto devId = enterDataOp.getDevice()) + if (auto constOp = mlir::dyn_cast( + devId.getDefiningOp())) + if (auto intAttr = + constOp.getValue().dyn_cast()) + deviceID = intAttr.getInt(); + + numMapOperands = enterDataOp.getMapOperands().size(); + mapOperands = enterDataOp.getMapOperands(); + mapTypes = enterDataOp.getMapTypes(); + mapperFunc = ompBuilder->getOrCreateRuntimeFunctionPtr( + llvm::omp::OMPRTL___tgt_target_data_begin_mapper); + return success(); + }) + .Case([&](omp::ExitDataOp exitDataOp) { + if (exitDataOp.getNowait()) + return failure(); + + if (auto ifExprVar = exitDataOp.getIfExpr()) + ifCond = moduleTranslation.lookupValue(ifExprVar); + + if (auto devId = exitDataOp.getDevice()) + if (auto constOp = mlir::dyn_cast( + devId.getDefiningOp())) + if (auto intAttr = + constOp.getValue().dyn_cast()) + deviceID = intAttr.getInt(); + + numMapOperands = exitDataOp.getMapOperands().size(); + mapOperands = exitDataOp.getMapOperands(); + mapTypes = exitDataOp.getMapTypes(); + mapperFunc = ompBuilder->getOrCreateRuntimeFunctionPtr( + llvm::omp::OMPRTL___tgt_target_data_end_mapper); + return success(); + }) + .Default([&](Operation *op) { + return op->emitError("unsupported OpenMP operation: ") + << op->getName(); + }); + + if (failed(result)) + return failure(); + + llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder); + llvm::OpenMPIRBuilder::InsertPointTy allocaIP = + findAllocaInsertPoint(builder, moduleTranslation); + + struct llvm::OpenMPIRBuilder::MapperAllocas mapperAllocas; + SmallVector mapTypeFlags; + SmallVector mapNames; + ompBuilder->createMapperAllocas(builder.saveIP(), allocaIP, numMapOperands, + mapperAllocas); + + using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy; + LogicalResult processMapOpStatus = success(); + auto processMapOpCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP) { + builder.restoreIP(codeGenIP); + processMapOpStatus = + processMapOperand(builder, moduleTranslation, mapOperands, mapTypes, + mapTypeFlags, mapNames, mapperAllocas); + }; + + LogicalResult bodyGenStatus = success(); + auto bodyCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP) { + // DataOp has only one region associated with it. + auto ®ion = cast(op).getRegion(); + builder.restoreIP(codeGenIP); + convertOmpOpRegions(region, "omp.data.region", builder, moduleTranslation, + bodyGenStatus); + }; + + builder.restoreIP(ompBuilder->createTargetData( + ompLoc, builder.saveIP(), isa(op), mapTypeFlags, mapNames, + mapperAllocas, mapperFunc, deviceID, ifCond, processMapOpCB, bodyCB)); + + if (failed(processMapOpStatus)) + return processMapOpStatus; + return bodyGenStatus; +} + namespace { /// Implementation of the dialect interface that converts operations belonging @@ -1465,6 +1652,9 @@ .Case([&](omp::ThreadprivateOp) { return convertOmpThreadprivate(*op, builder, moduleTranslation); }) + .Case([&](auto op) { + return convertOmpTargetData(op, builder, moduleTranslation); + }) .Default([&](Operation *inst) { return inst->emitError("unsupported OpenMP operation: ") << inst->getName(); diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMPCommon.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMPCommon.cpp new file mode 100644 --- /dev/null +++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMPCommon.cpp @@ -0,0 +1,41 @@ +//===- OpenMPCommon.cpp - Utils for translating MLIR dialect to LLVM IR----===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file defines general utilities for MLIR Dialect translations to LLVM IR. +// +//===----------------------------------------------------------------------===// + +#include "mlir/Target/LLVMIR/Dialect/OpenMPCommon.h" + +llvm::Constant * +mlir::LLVM::createSourceLocStrFromLocation(Location loc, + llvm::OpenMPIRBuilder &builder, + StringRef name, uint32_t &strLen) { + if (auto fileLoc = loc.dyn_cast()) { + StringRef fileName = fileLoc.getFilename(); + unsigned lineNo = fileLoc.getLine(); + unsigned colNo = fileLoc.getColumn(); + return builder.getOrCreateSrcLocStr(name, fileName, lineNo, colNo, strLen); + } + std::string locStr; + llvm::raw_string_ostream locOS(locStr); + locOS << loc; + return builder.getOrCreateSrcLocStr(locOS.str(), strLen); +} + +llvm::Constant * +mlir::LLVM::createMappingInformation(Location loc, + llvm::OpenMPIRBuilder &builder) { + uint32_t strLen; + if (auto nameLoc = loc.dyn_cast()) { + StringRef name = nameLoc.getName(); + return createSourceLocStrFromLocation(nameLoc.getChildLoc(), builder, name, + strLen); + } + return createSourceLocStrFromLocation(loc, builder, "unknown", strLen); +} diff --git a/mlir/test/Target/LLVMIR/omptarget-llvm.mlir b/mlir/test/Target/LLVMIR/omptarget-llvm.mlir new file mode 100644 --- /dev/null +++ b/mlir/test/Target/LLVMIR/omptarget-llvm.mlir @@ -0,0 +1,228 @@ +// RUN: mlir-translate -mlir-to-llvmir -split-input-file %s | FileCheck %s + +llvm.func @_QPopenmp_target_data() { + %0 = llvm.mlir.constant(1 : i64) : i64 + %1 = llvm.alloca %0 x i32 {bindc_name = "i", in_type = i32, operand_segment_sizes = array, uniq_name = "_QFopenmp_target_dataEi"} : (i64) -> !llvm.ptr + omp.target_data map((tofrom -> %1 : !llvm.ptr)) { + %2 = llvm.mlir.constant(99 : i32) : i32 + llvm.store %2, %1 : !llvm.ptr + omp.terminator + } + llvm.return +} + +// CHECK: @.offload_maptypes = private unnamed_addr constant [1 x i64] [i64 3] +// CHECK-LABEL: define void @_QPopenmp_target_data() { +// CHECK: %[[VAL_0:.*]] = alloca [1 x ptr], align 8 +// CHECK: %[[VAL_1:.*]] = alloca [1 x ptr], align 8 +// CHECK: %[[VAL_2:.*]] = alloca [1 x i64], align 8 +// CHECK: %[[VAL_3:.*]] = alloca i32, i64 1, align 4 +// CHECK: br label %[[VAL_4:.*]] +// CHECK: entry: ; preds = %[[VAL_5:.*]] +// CHECK: %[[VAL_6:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_0]], i32 0, i32 0 +// CHECK: store ptr %[[VAL_3]], ptr %[[VAL_6]], align 8 +// CHECK: %[[VAL_7:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_1]], i32 0, i32 0 +// CHECK: store ptr %[[VAL_3]], ptr %[[VAL_7]], align 8 +// CHECK: %[[VAL_8:.*]] = getelementptr inbounds [1 x i64], ptr %[[VAL_2]], i32 0, i32 0 +// CHECK: store i64 ptrtoint (ptr getelementptr (ptr, ptr null, i32 1) to i64), ptr %[[VAL_8]], align 4 +// CHECK: %[[VAL_9:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_0]], i32 0, i32 0 +// CHECK: %[[VAL_10:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_1]], i32 0, i32 0 +// CHECK: %[[VAL_11:.*]] = getelementptr inbounds [1 x i64], ptr %[[VAL_2]], i32 0, i32 0 +// CHECK: call void @__tgt_target_data_begin_mapper(ptr @2, i64 -1, i32 1, ptr %[[VAL_9]], ptr %[[VAL_10]], ptr %[[VAL_11]], ptr @.offload_maptypes, ptr @.offload_mapnames, ptr null) +// CHECK: br label %[[VAL_12:.*]] +// CHECK: omp.data.region: ; preds = %[[VAL_4]] +// CHECK: store i32 99, ptr %[[VAL_3]], align 4 +// CHECK: br label %[[VAL_13:.*]] +// CHECK: omp.region.cont: ; preds = %[[VAL_12]] +// CHECK: %[[VAL_14:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_0]], i32 0, i32 0 +// CHECK: %[[VAL_15:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_1]], i32 0, i32 0 +// CHECK: %[[VAL_16:.*]] = getelementptr inbounds [1 x i64], ptr %[[VAL_2]], i32 0, i32 0 +// CHECK: call void @__tgt_target_data_end_mapper(ptr @2, i64 -1, i32 1, ptr %[[VAL_14]], ptr %[[VAL_15]], ptr %[[VAL_16]], ptr @.offload_maptypes, ptr @.offload_mapnames, ptr null) +// CHECK: ret void + +// ----- + +llvm.func @_QPopenmp_target_data_loop(%1 : !llvm.ptr>) { + %2 = llvm.mlir.constant(1 : i64) : i64 + %3 = llvm.alloca %2 x i32 {bindc_name = "i", in_type = i32, operand_segment_sizes = array, uniq_name = "_QFopenmp_target_data_loopEi"} : (i64) -> !llvm.ptr + omp.target_data map((from -> %1 : !llvm.ptr>)) { + %4 = llvm.mlir.constant(1 : i32) : i32 + %5 = llvm.sext %4 : i32 to i64 + %6 = llvm.mlir.constant(1024 : i32) : i32 + %7 = llvm.sext %6 : i32 to i64 + %8 = llvm.mlir.constant(1 : index) : i64 + %9 = llvm.trunc %5 : i64 to i32 + %10 = llvm.sub %7, %5 : i64 + %11 = llvm.add %10, %8 : i64 + llvm.br ^bb1(%5, %9, %11 : i64, i32, i64) + ^bb1(%12: i64, %13: i32, %14: i64): // 2 preds: ^bb0, ^bb2 + %15 = llvm.mlir.constant(0 : index) : i64 + %16 = llvm.icmp "sgt" %14, %15 : i64 + llvm.cond_br %16, ^bb2, ^bb3 + ^bb2: // pred: ^bb1 + llvm.store %13, %3 : !llvm.ptr + %17 = llvm.load %3 : !llvm.ptr + %18 = llvm.load %3 : !llvm.ptr + %19 = llvm.sext %18 : i32 to i64 + %20 = llvm.mlir.constant(1 : i64) : i64 + %21 = llvm.sub %19, %20 : i64 + %22 = llvm.getelementptr %1[0, %21] : (!llvm.ptr>, i64) -> !llvm.ptr + llvm.store %17, %22 : !llvm.ptr + %23 = llvm.add %12, %8 : i64 + %24 = llvm.trunc %8 : i64 to i32 + %25 = llvm.load %3 : !llvm.ptr + %26 = llvm.add %25, %24 : i32 + %27 = llvm.add %12, %8 : i64 + %28 = llvm.mlir.constant(1 : index) : i64 + %29 = llvm.sub %14, %28 : i64 + llvm.br ^bb1(%27, %26, %29 : i64, i32, i64) + ^bb3: // pred: ^bb1 + llvm.store %13, %3 : !llvm.ptr + omp.terminator + } + llvm.return +} + +// CHECK: @.offload_maptypes = private unnamed_addr constant [1 x i64] [i64 2] +// CHECK-LABEL: define void @_QPopenmp_target_data_loop +// CHECK: (ptr %[[ARG_0:.*]]) { +// CHECK: %[[VAL_0:.*]] = alloca [1 x ptr], align 8 +// CHECK: %[[VAL_1:.*]] = alloca [1 x ptr], align 8 +// CHECK: %[[VAL_2:.*]] = alloca [1 x i64], align 8 +// CHECK: %[[VAL_3:.*]] = alloca i32, i64 1, align 4 +// CHECK: br label %[[VAL_4:.*]] +// CHECK: entry: ; preds = %[[VAL_5:.*]] +// CHECK: %[[VAL_6:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_0]], i32 0, i32 0 +// CHECK: store ptr %[[ARG_0]], ptr %[[VAL_6]], align 8 +// CHECK: %[[VAL_8:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_1]], i32 0, i32 0 +// CHECK: store ptr %[[ARG_0]], ptr %[[VAL_8]], align 8 +// CHECK: %[[VAL_9:.*]] = getelementptr inbounds [1 x i64], ptr %[[VAL_2]], i32 0, i32 0 +// CHECK: store i64 ptrtoint (ptr getelementptr (ptr, ptr null, i32 1) to i64), ptr %[[VAL_9]], align 4 +// CHECK: %[[VAL_10:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_0]], i32 0, i32 0 +// CHECK: %[[VAL_11:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_1]], i32 0, i32 0 +// CHECK: %[[VAL_12:.*]] = getelementptr inbounds [1 x i64], ptr %[[VAL_2]], i32 0, i32 0 +// CHECK: call void @__tgt_target_data_begin_mapper(ptr @2, i64 -1, i32 1, ptr %[[VAL_10]], ptr %[[VAL_11]], ptr %[[VAL_12]], ptr @.offload_maptypes, ptr @.offload_mapnames, ptr null) +// CHECK: br label %[[VAL_13:.*]] +// CHECK: omp.data.region3: ; preds = %[[VAL_14:.*]] +// CHECK: store i32 %[[VAL_15:.*]], ptr %[[VAL_3]], align 4 +// CHECK: br label %[[VAL_16:.*]] +// CHECK: omp.data.region2: ; preds = %[[VAL_14]] +// CHECK: store i32 %[[VAL_15]], ptr %[[VAL_3]], align 4 +// CHECK: %[[VAL_17:.*]] = load i32, ptr %[[VAL_3]], align 4 +// CHECK: %[[VAL_18:.*]] = load i32, ptr %[[VAL_3]], align 4 +// CHECK: %[[VAL_19:.*]] = sext i32 %[[VAL_18]] to i64 +// CHECK: %[[VAL_20:.*]] = sub i64 %[[VAL_19]], 1 +// CHECK: %[[VAL_21:.*]] = getelementptr [1024 x i32], ptr %[[ARG_0]], i32 0, i64 %[[VAL_20]] +// CHECK: store i32 %[[VAL_17]], ptr %[[VAL_21]], align 4 +// CHECK: %[[VAL_22:.*]] = add i64 %[[VAL_23:.*]], 1 +// CHECK: %[[VAL_24:.*]] = load i32, ptr %[[VAL_3]], align 4 +// CHECK: %[[VAL_25:.*]] = add i32 %[[VAL_24]], 1 +// CHECK: %[[VAL_26:.*]] = add i64 %[[VAL_23]], 1 +// CHECK: %[[VAL_27:.*]] = sub i64 %[[VAL_28:.*]], 1 +// CHECK: br label %[[VAL_14]] +// CHECK: omp.data.region1: ; preds = %[[VAL_29:.*]], %[[VAL_13]] +// CHECK: %[[VAL_23]] = phi i64 [ %[[VAL_26]], %[[VAL_29]] ], [ 1, %[[VAL_13]] ] +// CHECK: %[[VAL_15]] = phi i32 [ %[[VAL_25]], %[[VAL_29]] ], [ 1, %[[VAL_13]] ] +// CHECK: %[[VAL_28]] = phi i64 [ %[[VAL_27]], %[[VAL_29]] ], [ 1024, %[[VAL_13]] ] +// CHECK: %[[VAL_30:.*]] = icmp sgt i64 %[[VAL_28]], 0 +// CHECK: br i1 %[[VAL_30]], label %[[VAL_29]], label %[[VAL_31:.*]] +// CHECK: omp.data.region: ; preds = %[[VAL_4]] +// CHECK: br label %[[VAL_14]] +// CHECK: omp.region.cont: ; preds = %[[VAL_31]] +// CHECK: %[[VAL_32:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_0]], i32 0, i32 0 +// CHECK: %[[VAL_33:.*]] = getelementptr inbounds [1 x ptr], ptr %[[VAL_1]], i32 0, i32 0 +// CHECK: %[[VAL_34:.*]] = getelementptr inbounds [1 x i64], ptr %[[VAL_2]], i32 0, i32 0 +// CHECK: call void @__tgt_target_data_end_mapper(ptr @2, i64 -1, i32 1, ptr %[[VAL_32]], ptr %[[VAL_33]], ptr %[[VAL_34]], ptr @.offload_maptypes, ptr @.offload_mapnames, ptr null) +// CHECK: ret void + +// ----- + +llvm.func @_QPomp_target_enter_exit(%1 : !llvm.ptr>, %3 : !llvm.ptr>) { + %4 = llvm.mlir.constant(1 : i64) : i64 + %5 = llvm.alloca %4 x i32 {bindc_name = "dvc", in_type = i32, operand_segment_sizes = array, uniq_name = "_QFomp_target_enter_exitEdvc"} : (i64) -> !llvm.ptr + %6 = llvm.mlir.constant(1 : i64) : i64 + %7 = llvm.alloca %6 x i32 {bindc_name = "i", in_type = i32, operand_segment_sizes = array, uniq_name = "_QFomp_target_enter_exitEi"} : (i64) -> !llvm.ptr + %8 = llvm.mlir.constant(5 : i32) : i32 + llvm.store %8, %7 : !llvm.ptr + %9 = llvm.mlir.constant(2 : i32) : i32 + llvm.store %9, %5 : !llvm.ptr + %10 = llvm.load %7 : !llvm.ptr + %11 = llvm.mlir.constant(10 : i32) : i32 + %12 = llvm.icmp "slt" %10, %11 : i32 + %13 = llvm.load %5 : !llvm.ptr + omp.target_enter_data if(%12 : i1) device(%13 : i32) map((to -> %1 : !llvm.ptr>), (alloc -> %3 : !llvm.ptr>)) + %14 = llvm.load %7 : !llvm.ptr + %15 = llvm.mlir.constant(10 : i32) : i32 + %16 = llvm.icmp "sgt" %14, %15 : i32 + %17 = llvm.load %5 : !llvm.ptr + omp.target_exit_data if(%16 : i1) device(%17 : i32) map((from -> %1 : !llvm.ptr>), (release -> %3 : !llvm.ptr>)) + llvm.return +} + +// CHECK: @.offload_maptypes = private unnamed_addr constant [2 x i64] [i64 1, i64 0] +// CHECK: @.offload_maptypes.1 = private unnamed_addr constant [2 x i64] [i64 2, i64 0] +// CHECK-LABEL: define void @_QPomp_target_enter_exit +// CHECK: (ptr %[[ARG_0:.*]], ptr %[[ARG_1:.*]]) { +// CHECK: %[[VAL_0:.*]] = alloca [2 x ptr], align 8 +// CHECK: %[[VAL_1:.*]] = alloca [2 x ptr], align 8 +// CHECK: %[[VAL_2:.*]] = alloca [2 x i64], align 8 +// CHECK: %[[VAL_3:.*]] = alloca [2 x ptr], align 8 +// CHECK: %[[VAL_4:.*]] = alloca [2 x ptr], align 8 +// CHECK: %[[VAL_5:.*]] = alloca [2 x i64], align 8 +// CHECK: %[[VAL_6:.*]] = alloca i32, i64 1, align 4 +// CHECK: %[[VAL_7:.*]] = alloca i32, i64 1, align 4 +// CHECK: store i32 5, ptr %[[VAL_7]], align 4 +// CHECK: store i32 2, ptr %[[VAL_6]], align 4 +// CHECK: %[[VAL_8:.*]] = load i32, ptr %[[VAL_7]], align 4 +// CHECK: %[[VAL_9:.*]] = icmp slt i32 %[[VAL_8]], 10 +// CHECK: %[[VAL_10:.*]] = load i32, ptr %[[VAL_6]], align 4 +// CHECK: br label %[[VAL_11:.*]] +// CHECK: entry: ; preds = %[[VAL_12:.*]] +// CHECK: br i1 %[[VAL_9]], label %[[VAL_13:.*]], label %[[VAL_14:.*]] +// CHECK: omp_if.then: ; preds = %[[VAL_11]] +// CHECK: %[[VAL_15:.*]] = getelementptr inbounds [2 x ptr], ptr %[[VAL_3]], i32 0, i32 0 +// CHECK: store ptr %[[ARG_0]], ptr %[[VAL_15]], align 8 +// CHECK: %[[VAL_17:.*]] = getelementptr inbounds [2 x ptr], ptr %[[VAL_4]], i32 0, i32 0 +// CHECK: store ptr %[[ARG_0]], ptr %[[VAL_17]], align 8 +// CHECK: %[[VAL_18:.*]] = getelementptr inbounds [2 x i64], ptr %[[VAL_5]], i32 0, i32 0 +// CHECK: store i64 ptrtoint (ptr getelementptr (ptr, ptr null, i32 1) to i64), ptr %[[VAL_18]], align 4 +// CHECK: %[[VAL_19:.*]] = getelementptr inbounds [2 x ptr], ptr %[[VAL_3]], i32 0, i32 1 +// CHECK: store ptr %[[ARG_1]], ptr %[[VAL_19]], align 8 +// CHECK: %[[VAL_21:.*]] = getelementptr inbounds [2 x ptr], ptr %[[VAL_4]], i32 0, i32 1 +// CHECK: store ptr %[[ARG_1]], ptr %[[VAL_21]], align 8 +// CHECK: %[[VAL_22:.*]] = getelementptr inbounds [2 x i64], ptr %[[VAL_5]], i32 0, i32 1 +// CHECK: store i64 ptrtoint (ptr getelementptr (ptr, ptr null, i32 1) to i64), ptr %[[VAL_22]], align 4 +// CHECK: %[[VAL_23:.*]] = getelementptr inbounds [2 x ptr], ptr %[[VAL_3]], i32 0, i32 0 +// CHECK: %[[VAL_24:.*]] = getelementptr inbounds [2 x ptr], ptr %[[VAL_4]], i32 0, i32 0 +// CHECK: %[[VAL_25:.*]] = getelementptr inbounds [2 x i64], ptr %[[VAL_5]], i32 0, i32 0 +// CHECK: call void @__tgt_target_data_begin_mapper(ptr @3, i64 -1, i32 2, ptr %[[VAL_23]], ptr %[[VAL_24]], ptr %[[VAL_25]], ptr @.offload_maptypes, ptr @.offload_mapnames, ptr null) +// CHECK: br label %[[VAL_26:.*]] +// CHECK: omp_if.else: ; preds = %[[VAL_11]] +// CHECK: br label %[[VAL_26]] +// CHECK: omp_if.end: ; preds = %[[VAL_14]], %[[VAL_13]] +// CHECK: %[[VAL_27:.*]] = load i32, ptr %[[VAL_7]], align 4 +// CHECK: %[[VAL_28:.*]] = icmp sgt i32 %[[VAL_27]], 10 +// CHECK: %[[VAL_29:.*]] = load i32, ptr %[[VAL_6]], align 4 +// CHECK: br i1 %[[VAL_28]], label %[[VAL_30:.*]], label %[[VAL_31:.*]] +// CHECK: omp_if.then1: ; preds = %[[VAL_26]] +// CHECK: %[[VAL_32:.*]] = getelementptr inbounds [2 x ptr], ptr %[[VAL_0]], i32 0, i32 0 +// CHECK: store ptr %[[ARG_0]], ptr %[[VAL_32]], align 8 +// CHECK: %[[VAL_33:.*]] = getelementptr inbounds [2 x ptr], ptr %[[VAL_1]], i32 0, i32 0 +// CHECK: store ptr %[[ARG_0]], ptr %[[VAL_33]], align 8 +// CHECK: %[[VAL_34:.*]] = getelementptr inbounds [2 x i64], ptr %[[VAL_2]], i32 0, i32 0 +// CHECK: store i64 ptrtoint (ptr getelementptr (ptr, ptr null, i32 1) to i64), ptr %[[VAL_34]], align 4 +// CHECK: %[[VAL_35:.*]] = getelementptr inbounds [2 x ptr], ptr %[[VAL_0]], i32 0, i32 1 +// CHECK: store ptr %[[ARG_1]], ptr %[[VAL_35]], align 8 +// CHECK: %[[VAL_36:.*]] = getelementptr inbounds [2 x ptr], ptr %[[VAL_1]], i32 0, i32 1 +// CHECK: store ptr %[[ARG_1]], ptr %[[VAL_36]], align 8 +// CHECK: %[[VAL_37:.*]] = getelementptr inbounds [2 x i64], ptr %[[VAL_2]], i32 0, i32 1 +// CHECK: store i64 ptrtoint (ptr getelementptr (ptr, ptr null, i32 1) to i64), ptr %[[VAL_37]], align 4 +// CHECK: %[[VAL_38:.*]] = getelementptr inbounds [2 x ptr], ptr %[[VAL_0]], i32 0, i32 0 +// CHECK: %[[VAL_39:.*]] = getelementptr inbounds [2 x ptr], ptr %[[VAL_1]], i32 0, i32 0 +// CHECK: %[[VAL_40:.*]] = getelementptr inbounds [2 x i64], ptr %[[VAL_2]], i32 0, i32 0 +// CHECK: call void @__tgt_target_data_end_mapper(ptr @3, i64 -1, i32 2, ptr %[[VAL_38]], ptr %[[VAL_39]], ptr %[[VAL_40]], ptr @.offload_maptypes.1, ptr @.offload_mapnames.2, ptr null) +// CHECK: br label %[[VAL_41:.*]] +// CHECK: omp_if.else2: ; preds = %[[VAL_26]] +// CHECK: br label %[[VAL_41]] +// CHECK: omp_if.end3: ; preds = %[[VAL_31]], %[[VAL_30]] +// CHECK: ret void