diff --git a/mlir/include/mlir/Conversion/OpenACCToLLVM/ConvertOpenACCToLLVM.h b/mlir/include/mlir/Conversion/OpenACCToLLVM/ConvertOpenACCToLLVM.h new file mode 100644 --- /dev/null +++ b/mlir/include/mlir/Conversion/OpenACCToLLVM/ConvertOpenACCToLLVM.h @@ -0,0 +1,29 @@ +//===- ConvertOpenACCToLLVM.h - OpenACC conversion pass entrypoint --------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#ifndef MLIR_CONVERSION_OPENACCTOLLVM_CONVERTOPENACCTOLLVMPASS_H_ +#define MLIR_CONVERSION_OPENACCTOLLVM_CONVERTOPENACCTOLLVMPASS_H_ + +#include + +namespace mlir { +class LLVMTypeConverter; +class ModuleOp; +template +class OperationPass; +class RewritePatternSet; + +/// Collect the patterns to convert from the OpenACC dialect LLVMIR dialect. +void populateOpenACCToLLVMConversionPatterns(LLVMTypeConverter &converter, + RewritePatternSet &patterns); + +/// Create a pass to convert the OpenACC dialect into the LLVMIR dialect. +std::unique_ptr> createConvertOpenACCToLLVMPass(); + +} // namespace mlir + +#endif // MLIR_CONVERSION_OPENACCTOLLVM_CONVERTOPENACCTOLLVMPASS_H_ diff --git a/mlir/include/mlir/Conversion/Passes.h b/mlir/include/mlir/Conversion/Passes.h --- a/mlir/include/mlir/Conversion/Passes.h +++ b/mlir/include/mlir/Conversion/Passes.h @@ -20,6 +20,7 @@ #include "mlir/Conversion/LinalgToLLVM/LinalgToLLVM.h" #include "mlir/Conversion/LinalgToSPIRV/LinalgToSPIRVPass.h" #include "mlir/Conversion/LinalgToStandard/LinalgToStandard.h" +#include "mlir/Conversion/OpenACCToLLVM/ConvertOpenACCToLLVM.h" #include "mlir/Conversion/OpenMPToLLVM/ConvertOpenMPToLLVM.h" #include "mlir/Conversion/PDLToPDLInterp/PDLToPDLInterp.h" #include "mlir/Conversion/SCFToGPU/SCFToGPUPass.h" diff --git a/mlir/include/mlir/Conversion/Passes.td b/mlir/include/mlir/Conversion/Passes.td --- a/mlir/include/mlir/Conversion/Passes.td +++ b/mlir/include/mlir/Conversion/Passes.td @@ -228,6 +228,16 @@ let dependentDialects = ["spirv::SPIRVDialect"]; } +//===----------------------------------------------------------------------===// +// OpenACCToLLVM +//===----------------------------------------------------------------------===// + +def ConvertOpenACCToLLVM : Pass<"convert-openacc-to-llvm", "ModuleOp"> { + let summary = "Convert the OpenACC ops to LLVM dialect"; + let constructor = "mlir::createConvertOpenACCToLLVMPass()"; + let dependentDialects = ["LLVM::LLVMDialect"]; +} + //===----------------------------------------------------------------------===// // OpenMPToLLVM //===----------------------------------------------------------------------===// diff --git a/mlir/lib/Conversion/CMakeLists.txt b/mlir/lib/Conversion/CMakeLists.txt --- a/mlir/lib/Conversion/CMakeLists.txt +++ b/mlir/lib/Conversion/CMakeLists.txt @@ -9,6 +9,7 @@ add_subdirectory(LinalgToLLVM) add_subdirectory(LinalgToSPIRV) add_subdirectory(LinalgToStandard) +add_subdirectory(OpenACCToLLVM) add_subdirectory(OpenMPToLLVM) add_subdirectory(PDLToPDLInterp) add_subdirectory(SCFToGPU) diff --git a/mlir/lib/Conversion/OpenACCToLLVM/CMakeLists.txt b/mlir/lib/Conversion/OpenACCToLLVM/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/mlir/lib/Conversion/OpenACCToLLVM/CMakeLists.txt @@ -0,0 +1,20 @@ +add_mlir_conversion_library(MLIROpenACCToLLVM + OpenACCToLLVM.cpp + + ADDITIONAL_HEADER_DIRS + ${MLIR_MAIN_INCLUDE_DIR}/mlir/Conversion/OpenACCToLLVM + + DEPENDS + MLIRConversionPassIncGen + intrinsics_gen + + LINK_COMPONENTS + Core + + LINK_LIBS PUBLIC + MLIRIR + MLIRLLVMIR + MLIROpenACC + MLIRStandardToLLVM + MLIRTransforms + ) diff --git a/mlir/lib/Conversion/OpenACCToLLVM/OpenACCToLLVM.cpp b/mlir/lib/Conversion/OpenACCToLLVM/OpenACCToLLVM.cpp new file mode 100644 --- /dev/null +++ b/mlir/lib/Conversion/OpenACCToLLVM/OpenACCToLLVM.cpp @@ -0,0 +1,419 @@ +//===- OpenACCToLLVM.cpp - conversion from OpenACC to LLVM dialect --------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "../PassDetail.h" +#include "mlir/Conversion/OpenACCToLLVM/ConvertOpenACCToLLVM.h" +#include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h" +#include "mlir/Dialect/LLVMIR/LLVMDialect.h" +#include "mlir/Dialect/OpenACC/OpenACC.h" + +#include "llvm/IR/GlobalValue.h" +#include "llvm/Support/FormatVariadic.h" + +using namespace mlir; +using namespace mlir::acc; + +//===----------------------------------------------------------------------===// +// Utility functions +//===----------------------------------------------------------------------===// + +static constexpr StringRef kmpIdentTypeName = "struct.ident_t"; +static constexpr StringRef globalOffloadMaptypesName = ".offload_maptypes"; +static constexpr StringRef globalOffloadMapnamesName = ".offload_mapnames"; +static constexpr StringRef tgtTargetDataBeginMapperName = + "__tgt_target_data_begin_mapper"; +static constexpr int64_t defaultDeviceId = -1; + +/// 0 = alloc +static constexpr int64_t createFlag = 0; + +static LLVM::LLVMStructType getKmpIdentType(MLIRContext *ctx) { + // Struct defined in openmp/libomptarget/include/SourceInfo.h + // Create a struct type corresponding to the C struct below. + // struct ident_t { + // // Ident_t flags described in kmp.h. + // int32_t reserved_1; + // int32_t flags; + // int32_t reserved_2; + // int32_t reserved_3; + // char const *psource; + // }; + auto i32Ty = IntegerType::get(ctx, 32); + auto i8Ty = IntegerType::get(ctx, 8); + auto i8Ptr = LLVM::LLVMPointerType::get(i8Ty); + auto type = LLVM::LLVMStructType::getIdentified(ctx, kmpIdentTypeName); + type.setBody({i32Ty, i32Ty, i32Ty, i32Ty, i8Ptr}, /*isPacked=*/false); + return type; +} + +/// Function defined in openmp/libomptarget/include/omptarget.h +/// void __tgt_target_data_begin_mapper(ident_t *loc, int64_t device_id, +/// int32_t arg_num, void **args_base, +/// void **args, int64_t *arg_sizes, +/// int64_t *arg_types, +/// map_var_info_t *arg_names, +/// void **arg_mappers); +static LLVM::LLVMFunctionType +getTgtTargetDataBeginMapperType(MLIRContext *ctx) { + auto llvmVoidType = LLVM::LLVMVoidType::get(ctx); + auto identType = getKmpIdentType(ctx); + auto identTypePtr = LLVM::LLVMPointerType::get(identType); + + auto i32Ty = IntegerType::get(ctx, 32); // i32 + auto i8Ty = IntegerType::get(ctx, 8); + auto i8PtrTy = LLVM::LLVMPointerType::get(i8Ty); + auto i8PtrPtrTy = LLVM::LLVMPointerType::get(i8PtrTy); // i8** + auto i64Ty = IntegerType::get(ctx, 64); + auto i64PtrTy = LLVM::LLVMPointerType::get(i64Ty); // i64* + + return LLVM::LLVMFunctionType::get( + llvmVoidType, {identTypePtr, i64Ty, i32Ty, i8PtrPtrTy, i8PtrPtrTy, + i64PtrTy, i64PtrTy, i8PtrPtrTy, i8PtrPtrTy}); +} + +static LLVM::GlobalOp createLocationInfoGlobalOp(Location loc, EnterDataOp &op, + OpBuilder &builder) { + MLIRContext *ctx = builder.getContext(); + std::string locStr; + llvm::raw_string_ostream locOS(locStr); + if (auto fileLoc = loc.dyn_cast()) { + auto funcOp = op.getOperation()->getParentOfType(); + StringRef funcName = funcOp ? funcOp.getName() : "unknown"; + locOS << ";" << fileLoc.getFilename() << ";" << funcName << ";" + << fileLoc.getLine() << ";" << fileLoc.getColumn() << ";;"; + } else { + locOS << ";unknown;unknown;0;0;;"; + } + auto globalStringType = + LLVM::LLVMArrayType::get(IntegerType::get(ctx, 8), locOS.str().size()); + auto globalStr = builder.create( + loc, globalStringType, + /*isConstant=*/true, LLVM::Linkage::Private, "0", + builder.getStringAttr(locOS.str())); + globalStr.unnamed_addrAttr( + LLVM::UnnamedAddrAttr::get(ctx, LLVM::UnnamedAddr::Global)); + + auto structType = getKmpIdentType(ctx); + + // Create a ident_t struct + auto llvmI32Type = IntegerType::get(ctx, 32); + auto i8Ty = IntegerType::get(ctx, 8); + auto i8PtrTy = LLVM::LLVMPointerType::get(i8Ty); + auto global = builder.create( + loc, structType, + /*isConstant=*/true, LLVM::Linkage::Private, "1", Attribute()); + global.unnamed_addrAttr( + LLVM::UnnamedAddrAttr::get(ctx, LLVM::UnnamedAddr::Global)); + + Location globalLoc = global.getLoc(); + Region ®ion = global.getInitializerRegion(); + Block *block = builder.createBlock(®ion); + builder.setInsertionPoint(block, block->begin()); + + Value structValue = builder.create(globalLoc, structType); + Value zero = builder.create(globalLoc, llvmI32Type, + builder.getI64IntegerAttr(0)); + Value two = builder.create(globalLoc, llvmI32Type, + builder.getI64IntegerAttr(2)); + structValue = builder.create( + globalLoc, structType, structValue, zero, + ArrayAttr::get(ctx, {builder.getIntegerAttr(builder.getI32Type(), 0)})); + structValue = builder.create( + globalLoc, structType, structValue, two, + ArrayAttr::get(ctx, {builder.getIntegerAttr(builder.getI32Type(), 1)})); + structValue = builder.create( + globalLoc, structType, structValue, zero, + ArrayAttr::get(ctx, {builder.getIntegerAttr(builder.getI32Type(), 2)})); + structValue = builder.create( + globalLoc, structType, structValue, zero, + ArrayAttr::get(ctx, {builder.getIntegerAttr(builder.getI32Type(), 3)})); + Value addrOfGlobalStr = + builder.create(globalLoc, globalStr); + auto globalStrGep = builder.create( + globalLoc, i8PtrTy, addrOfGlobalStr, ArrayRef{zero, zero}); + structValue = builder.create( + globalLoc, structType, structValue, globalStrGep, + ArrayAttr::get(ctx, {builder.getIntegerAttr(builder.getI32Type(), 4)})); + builder.create(globalLoc, ArrayRef({structValue})); + builder.setInsertionPointAfter(global); + return global; +} + +/// Create offload maptypes global constant +static LLVM::GlobalOp createOffloadMaptypesGlobal(Location loc, + OpBuilder &builder, + unsigned nbArg, + ArrayRef flags) { + MLIRContext *ctx = builder.getContext(); + auto offloadMaptypesType = + LLVM::LLVMArrayType::get(IntegerType::get(ctx, 64), nbArg); + auto offloadMaptypes = builder.create( + loc, offloadMaptypesType, /*isConstant=*/true, LLVM::Linkage::Private, + globalOffloadMaptypesName, builder.getI64VectorAttr(flags)); + offloadMaptypes.unnamed_addrAttr( + LLVM::UnnamedAddrAttr::get(ctx, LLVM::UnnamedAddr::Global)); + return offloadMaptypes; +} + +static LLVM::GlobalOp +createOffloadMapnamesGlobal(Location loc, OpBuilder &builder, unsigned nbArg, + SmallVector &names) { + MLIRContext *ctx = builder.getContext(); + SmallVector globals; + unsigned index = 0; + for (StringRef name : names) { + std::string locStr; + llvm::raw_string_ostream locOS(locStr); + if (auto fileLoc = loc.dyn_cast()) { + locOS << ";" << name << ";" << fileLoc.getFilename() << ";0;" + << name.size() << ";;"; + } else { + locOS << ";" << name << ";unknown;0;0;;"; + } + auto globalStringType = + LLVM::LLVMArrayType::get(IntegerType::get(ctx, 8), locOS.str().size()); + std::string globalName = std::string(llvm::formatv("{0}_mapname", index)); + auto globalStr = builder.create( + loc, globalStringType, + /*isConstant=*/true, LLVM::Linkage::Private, globalName, + builder.getStringAttr(locOS.str())); + globalStr.unnamed_addrAttr( + LLVM::UnnamedAddrAttr::get(ctx, LLVM::UnnamedAddr::Global)); + globals.push_back(globalStr); + ++index; + } + + auto llvmI32Type = IntegerType::get(ctx, 32); + auto i8Ty = IntegerType::get(ctx, 8); + auto i8PtrTy = LLVM::LLVMPointerType::get(i8Ty); + + auto offloadMapnamesType = + LLVM::LLVMArrayType::get(LLVM::LLVMPointerType::get(i8Ty), nbArg); + + auto offloadMapnames = builder.create( + loc, offloadMapnamesType, /*isConstant=*/true, LLVM::Linkage::Private, + globalOffloadMapnamesName, Attribute()); + + // Initialize the global with global string created above. + Location globalLoc = offloadMapnames.getLoc(); + Region ®ion = offloadMapnames.getInitializerRegion(); + Block *block = builder.createBlock(®ion); + builder.setInsertionPoint(block, block->begin()); + + Value mapValue = + builder.create(globalLoc, offloadMapnamesType); + Value zero = builder.create(globalLoc, llvmI32Type, + builder.getI64IntegerAttr(0)); + index = 0; + for (LLVM::GlobalOp global : globals) { + Value addrOfGlobal = builder.create(globalLoc, global); + auto globalGep = builder.create( + globalLoc, i8PtrTy, addrOfGlobal, ArrayRef{zero, zero}); + mapValue = builder.create( + globalLoc, offloadMapnamesType, mapValue, globalGep, + ArrayAttr::get(ctx, + {builder.getIntegerAttr(builder.getI32Type(), index)})); + ++index; + } + builder.create(globalLoc, ArrayRef({mapValue})); + builder.setInsertionPointAfter(offloadMapnames); + return offloadMapnames; +} + +static LLVM::LLVMFuncOp getTgtTargetDataBeginMapperFuncOp(ModuleOp &module, + OpBuilder &builder) { + MLIRContext *ctx = module.getContext(); + auto mapperFunc = + module.lookupSymbol(tgtTargetDataBeginMapperName); + if (!mapperFunc) { + OpBuilder::InsertionGuard guard(builder); + builder.setInsertionPointToStart(module.getBody()); + auto mapperFuncTy = getTgtTargetDataBeginMapperType(ctx); + mapperFunc = builder.create( + builder.getUnknownLoc(), tgtTargetDataBeginMapperName, mapperFuncTy); + } + return mapperFunc; +} + +//===----------------------------------------------------------------------===// +// Conversion patterns +//===----------------------------------------------------------------------===// + +struct EnterDataOpConversion : public ConvertOpToLLVMPattern { + using ConvertOpToLLVMPattern::ConvertOpToLLVMPattern; + + LogicalResult + matchAndRewrite(EnterDataOp enterDataOp, ArrayRef operands, + ConversionPatternRewriter &rewriter) const override { + // acc.enter_data operation is lowered to a call to + // __tgt_target_data_begin_mapper function from the libomptarget runtime. + + // TODO + // - handle copyin operands + // - handle create_zero operands + // - handle attach operands + // - handle async + // - wait + + auto loc = enterDataOp->getLoc(); + auto module = enterDataOp->getParentOfType(); + MLIRContext *ctx = module.getContext(); + + OpBuilder moduleBuilder(module.getBodyRegion(), rewriter.getListener()); + auto globalLocationInfo = + createLocationInfoGlobalOp(loc, enterDataOp, moduleBuilder); + + auto deviceId = rewriter.create( + enterDataOp->getLoc(), rewriter.getI64Type(), + rewriter.getI64IntegerAttr(defaultDeviceId)); + + // Number of arguments in the enter_data operation. + // TODO include copyin, create_zero and attach operands. + unsigned nbArg = enterDataOp.createOperands().size(); + + auto argNumCstOp = rewriter.create( + enterDataOp->getLoc(), rewriter.getI32Type(), + rewriter.getI32IntegerAttr(nbArg)); + + auto i8Ty = IntegerType::get(ctx, 8); // i8 + auto i8PtrTy = LLVM::LLVMPointerType::get(i8Ty); // i8* + auto i8PtrPtrTy = LLVM::LLVMPointerType::get(i8PtrTy); // i8** + auto i8PtrArrTy = LLVM::LLVMArrayType::get(i8PtrTy, nbArg); // [nbArg x i8*] + auto i8PtrArrPtrTy = + LLVM::LLVMPointerType::get(i8PtrArrTy); // [nbArg x i8*]* + auto i64Ty = IntegerType::get(ctx, 64); // i64 + auto i64PtrTy = LLVM::LLVMPointerType::get(i64Ty); // i64* + auto i64ArrTy = LLVM::LLVMArrayType::get(i64Ty, nbArg); // [nbArg x i64*] + auto i64ArrTyPtr = LLVM::LLVMPointerType::get(i64ArrTy); // [nbArg x i64*]* + + // %4 = alloca [nbArg x i8*], align 8 + auto argsBasePtr = rewriter.create( + loc, i8PtrArrPtrTy, argNumCstOp, /*alignment=*/0); + // %5 = alloca [nbArg x i8*], align 8 + auto argsPtr = rewriter.create( + loc, i8PtrArrPtrTy, argNumCstOp, /*alignment=*/0); + // %7 = alloca [nbArg x i64], align 8 + auto argSizesPtr = rewriter.create( + loc, i64ArrTyPtr, argNumCstOp, /*alignment=*/0); + + auto zero = rewriter.create( + loc, IntegerType::get(ctx, 32), rewriter.getI32IntegerAttr(0)); + + SmallVector flags; + SmallVector names; + unsigned index = 0; + // create operands are handled as alloc call. + for (auto data : enterDataOp.createOperands()) { + Value crtIndex = rewriter.create( + loc, IntegerType::get(ctx, 32), rewriter.getI32IntegerAttr(index)); + + // Handle operands that were converted to MemRefDescriptors. + if (auto structType = data.getType().dyn_cast()) { + // Calculate the size of the memref and store it for the fct call. + Value sizeBytes = getSizeInBytes(loc, structType, rewriter); + auto sizesPtr = rewriter.create( + loc, i64PtrTy, argSizesPtr, ArrayRef{zero, zero}); + rewriter.create(loc, sizeBytes, sizesPtr); + + MemRefDescriptor descriptor(data); + Value allocatedPtr = descriptor.allocatedPtr(rewriter, loc); + + auto basePtr = rewriter.create( + loc, i8PtrTy, argsBasePtr, ArrayRef{zero, crtIndex}); + Value basePtrCast = rewriter.create( + loc, LLVM::LLVMPointerType::get(descriptor.getElementPtrType()), + basePtr); + rewriter.create(loc, allocatedPtr, basePtrCast); + + auto ptr = rewriter.create( + loc, i8PtrTy, argsPtr, ArrayRef{zero, crtIndex}); + Value ptrCast = rewriter.create( + loc, LLVM::LLVMPointerType::get(descriptor.getElementPtrType()), + ptr); + rewriter.create(loc, allocatedPtr, ptrCast); + + flags.push_back(createFlag); + + // TODO: pass more information about line location and name of memref. + names.push_back(std::string(llvm::formatv("memref_{0}", index))); + } else { + // Not supported types for now. + enterDataOp.emitOpError("Unsupported type ") << data.getType(); + return failure(); + } + ++index; + } + + auto offloadMaptypes = + createOffloadMaptypesGlobal(loc, moduleBuilder, nbArg, flags); + + auto offloadMapnames = + createOffloadMapnamesGlobal(loc, moduleBuilder, nbArg, names); + + Value addrLocInfo = + rewriter.create(loc, globalLocationInfo); + auto argsBasePtrArg = rewriter.create( + loc, i8PtrPtrTy, argsBasePtr, ArrayRef{zero, zero}); + auto argsPtrArg = rewriter.create(loc, i8PtrPtrTy, argsPtr, + ArrayRef{zero, zero}); + auto argSizesPtrArg = rewriter.create( + loc, i64PtrTy, argSizesPtr, ArrayRef{zero, zero}); + Value addrOffloadMaptypes = + rewriter.create(loc, offloadMaptypes); + auto offloadMaptypesArg = rewriter.create( + loc, i64PtrTy, addrOffloadMaptypes, ArrayRef{zero, zero}); + Value addrOffloadMapnames = + rewriter.create(loc, offloadMapnames); + auto offloadMapnamesArg = rewriter.create( + loc, i8PtrPtrTy, addrOffloadMapnames, ArrayRef{zero, zero}); + auto nullPtr = rewriter.create(loc, i8PtrPtrTy); + + auto mapperFuncOp = getTgtTargetDataBeginMapperFuncOp(module, rewriter); + rewriter.replaceOpWithNewOp( + enterDataOp, mapperFuncOp, + ValueRange{addrLocInfo, deviceId, argNumCstOp, argsBasePtrArg, + argsPtrArg, argSizesPtrArg, offloadMaptypesArg, + offloadMapnamesArg, nullPtr}); + + return success(); + } +}; + +void mlir::populateOpenACCToLLVMConversionPatterns( + LLVMTypeConverter &converter, OwningRewritePatternList &patterns) { + patterns.add(converter); +} + +namespace { +struct ConvertOpenACCToLLVMPass + : public ConvertOpenACCToLLVMBase { + void runOnOperation() override; +}; +} // namespace + +void ConvertOpenACCToLLVMPass::runOnOperation() { + auto op = getOperation(); + auto *context = op.getContext(); + + // Convert to OpenACC operations with LLVM IR dialect + RewritePatternSet patterns(context); + LLVMTypeConverter converter(context); + populateStdToLLVMConversionPatterns(converter, patterns); + populateOpenACCToLLVMConversionPatterns(converter, patterns); + + ConversionTarget target(*context); + target.addLegalDialect(); + + if (failed(applyPartialConversion(op, target, std::move(patterns)))) + signalPassFailure(); +} + +std::unique_ptr> +mlir::createConvertOpenACCToLLVMPass() { + return std::make_unique(); +} diff --git a/mlir/test/Conversion/OpenACCToLLVM/convert-standalone-data-to-llvmir.mlir b/mlir/test/Conversion/OpenACCToLLVM/convert-standalone-data-to-llvmir.mlir new file mode 100644 --- /dev/null +++ b/mlir/test/Conversion/OpenACCToLLVM/convert-standalone-data-to-llvmir.mlir @@ -0,0 +1,48 @@ +// RUN: mlir-opt -convert-std-to-llvm -convert-openacc-to-llvm %s | FileCheck %s + +func @testenterdataop(%a: memref<10xf32>, %b: memref<10xf32>) -> () { + acc.enter_data create(%a, %b : memref<10xf32>, memref<10xf32>) + return +} + +// CHECK: llvm.func @__tgt_target_data_begin_mapper(!llvm.ptr)>>, i64, i32, !llvm.ptr>, !llvm.ptr>, !llvm.ptr, !llvm.ptr, !llvm.ptr>, !llvm.ptr>) +// CHECK: llvm.mlir.global private constant [[LOCSTR:@.*]](";{{.*}};{{.*}};4;3;;") {unnamed_addr = 2 : i64} +// CHECK: llvm.mlir.global private constant [[IDENT_T:@.*]]() {unnamed_addr = 2 : i64} : !llvm.struct<"struct.ident_t", (i32, i32, i32, i32, ptr)> { +// CHECK-NEXT: %{{.*}} = llvm.mlir.undef : !llvm.struct<"struct.ident_t", (i32, i32, i32, i32, ptr)> +// CHECK-NEXT: [[ZERO:%.*]] = llvm.mlir.constant(0 : i64) : i32 +// CHECK-NEXT: [[TWO:%.*]] = llvm.mlir.constant(2 : i64) : i32 +// CHECK-NEXT: %{{.*}} = llvm.insertvalue [[ZERO]], %{{.*}}[0 : i32] : !llvm.struct<"struct.ident_t", (i32, i32, i32, i32, ptr)> +// CHECK-NEXT: %{{.*}} = llvm.insertvalue [[TWO]], %{{.*}}[1 : i32] : !llvm.struct<"struct.ident_t", (i32, i32, i32, i32, ptr)> +// CHECK-NEXT: %{{.*}} = llvm.insertvalue [[ZERO]], %{{.*}}[2 : i32] : !llvm.struct<"struct.ident_t", (i32, i32, i32, i32, ptr)> +// CHECK-NEXT: %{{.*}} = llvm.insertvalue [[ZERO]], %{{.*}}[3 : i32] : !llvm.struct<"struct.ident_t", (i32, i32, i32, i32, ptr)> +// CHECK-NEXT: %{{.*}} = llvm.mlir.addressof [[LOCSTR]] : !llvm.ptr> +// CHECK-NEXT: %{{.*}} = llvm.getelementptr %{{.*}}[%{{.*}}, %{{.*}}] : (!llvm.ptr>, i32, i32) -> !llvm.ptr +// CHECK-NEXT: %{{.*}} = llvm.insertvalue %{{.*}}, %{{.*}}[4 : i32] : !llvm.struct<"struct.ident_t", (i32, i32, i32, i32, ptr)> +// CHECK-NEXT: llvm.return %{{.*}} : !llvm.struct<"struct.ident_t", (i32, i32, i32, i32, ptr)> +// CHECK-NEXT: } +// CHECK: llvm.mlir.global private constant @".offload_maptypes"(dense<0> : vector<{{.*}}xi64>) {unnamed_addr = 2 : i64} : !llvm.array<{{.*}} x i64> +// CHECK: llvm.mlir.global private constant [[MAPNAME0:@.*]](";memref_0;{{.*}};0;8;;") {unnamed_addr = 2 : i64} +// CHECK: llvm.mlir.global private constant [[MAPNAME1:@.*]](";memref_1;{{.*}};0;8;;") {unnamed_addr = 2 : i64} +// CHECK: llvm.mlir.global private constant @".offload_mapnames"() : !llvm.array<2 x ptr> { +// CHECK-NEXT: %{{.*}} = llvm.mlir.undef : !llvm.array<2 x ptr> +// CHECK-NEXT: %{{.*}} = llvm.mlir.constant(0 : i64) : i32 +// CHECK-NEXT: %{{.*}} = llvm.mlir.addressof [[MAPNAME0]] : !llvm.ptr> +// CHECK-NEXT: %{{.*}} = llvm.getelementptr %{{.*}}[%{{.*}}, %{{.*}}] : (!llvm.ptr>, i32, i32) -> !llvm.ptr +// CHECK-NEXT: %{{.*}} = llvm.insertvalue %{{.*}}, %{{.*}}[0 : i32] : !llvm.array<2 x ptr> +// CHECK-NEXT: %{{.*}} = llvm.mlir.addressof [[MAPNAME1]] : !llvm.ptr> +// CHECK-NEXT: %{{.*}} = llvm.getelementptr %{{.*}}[%1, %1] : (!llvm.ptr>, i32, i32) -> !llvm.ptr +// CHECK-NEXT: %{{.*}} = llvm.insertvalue %{{.*}}, %{{.*}}[1 : i32] : !llvm.array<2 x ptr> +// CHECK-NEXT: llvm.return %7 : !llvm.array<2 x ptr> +// CHECK-NEXT: } + +// CHECK: llvm.func @testenterdataop + +// CHECK: [[DEVICEID:%.*]] = llvm.mlir.constant(-1 : i64) : i64 +// CHECK: [[ARGNUM:%.*]] = llvm.mlir.constant(2 : i32) : i32 + +// CHECK: [[ARGS_BASE:%.*]] = llvm.alloca %{{.*}} x !llvm.array<{{.*}} x ptr> : (i32) -> !llvm.ptr>> +// CHECK: [[ARGS:%.*]] = llvm.alloca %{{.*}} x !llvm.array<{{.*}} x ptr> : (i32) -> !llvm.ptr>> +// CHECK: [[SIZES:%.*]] = llvm.alloca %{{.*}} x !llvm.array<{{.*}} x i64> : (i32) -> !llvm.ptr> + +// CHECK: llvm.call @__tgt_target_data_begin_mapper(%{{.*}}, [[DEVICEID]], [[ARGNUM]], %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) : (!llvm.ptr)>>, i64, i32, !llvm.ptr>, !llvm.ptr>, !llvm.ptr, !llvm.ptr, !llvm.ptr>, !llvm.ptr>) -> () +// CHECK-NOT: acc.enter_data