From 113b807017847f7d9e79db724f09968b51459cf0 Mon Sep 17 00:00:00 2001 From: Valentin Clement Date: Wed, 12 May 2021 11:41:03 -0400 Subject: [PATCH] [mlir][openacc] Add OpenACC translation to LLVM IR (enter_data op create/copyin) This patch begins to translate acc.enter_data operation to call to tgt runtime call. It currently only translate create/copyin operands of memref type. This acts as a basis to add support for FIR types in the Flang/OpenACC support. It follows more or less a similar path than clang with `omp target enter data map` directives. This patch is taking a different approach than D100678 and perform a translation to LLVM IR and make use of the OpenMPIRBuilder instead of doing a conversion to the LLVMIR dialect. OpenACC support in Flang will rely on the current OpenMP runtime where 1:1 lowering can be applied. Some extension will be added where features are not available yet. Big part of this code will be shared for other standalone data operations in the OpenACC dialect such as acc.exit_data and acc.update. It is likely that parts of the lowering can also be shared later with the ops for standalone data directives in the OpenMP dialect when they are introduced. This is an initial translation and it probably needs more work. Reviewed By: ftynse Differential Revision: https://reviews.llvm.org/D101504 --- mlir/include/mlir/Target/LLVMIR/Dialect/All.h | 2 + .../Dialect/OpenACC/OpenACCToLLVMIRTranslation.h | 31 +++ mlir/lib/Target/LLVMIR/CMakeLists.txt | 2 + mlir/lib/Target/LLVMIR/Dialect/CMakeLists.txt | 1 + .../Target/LLVMIR/Dialect/OpenACC/CMakeLists.txt | 14 + .../Dialect/OpenACC/OpenACCToLLVMIRTranslation.cpp | 304 +++++++++++++++++++++ mlir/test/Target/LLVMIR/openacc-llvm.mlir | 65 +++++ 7 files changed, 419 insertions(+) create mode 100644 mlir/include/mlir/Target/LLVMIR/Dialect/OpenACC/OpenACCToLLVMIRTranslation.h create mode 100644 mlir/lib/Target/LLVMIR/Dialect/OpenACC/CMakeLists.txt create mode 100644 mlir/lib/Target/LLVMIR/Dialect/OpenACC/OpenACCToLLVMIRTranslation.cpp create mode 100644 mlir/test/Target/LLVMIR/openacc-llvm.mlir diff --git a/mlir/include/mlir/Target/LLVMIR/Dialect/All.h b/mlir/include/mlir/Target/LLVMIR/Dialect/All.h index 9d0de05..2bbfd7a 100644 --- a/mlir/include/mlir/Target/LLVMIR/Dialect/All.h +++ b/mlir/include/mlir/Target/LLVMIR/Dialect/All.h @@ -19,6 +19,7 @@ #include "mlir/Target/LLVMIR/Dialect/ArmSVE/ArmSVEToLLVMIRTranslation.h" #include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h" #include "mlir/Target/LLVMIR/Dialect/NVVM/NVVMToLLVMIRTranslation.h" +#include "mlir/Target/LLVMIR/Dialect/OpenACC/OpenACCToLLVMIRTranslation.h" #include "mlir/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.h" #include "mlir/Target/LLVMIR/Dialect/ROCDL/ROCDLToLLVMIRTranslation.h" #include "mlir/Target/LLVMIR/Dialect/X86Vector/X86VectorToLLVMIRTranslation.h" @@ -34,6 +35,7 @@ static inline void registerAllToLLVMIRTranslations(DialectRegistry ®istry) { registerArmSVEDialectTranslation(registry); registerLLVMDialectTranslation(registry); registerNVVMDialectTranslation(registry); + registerOpenACCDialectTranslation(registry); registerOpenMPDialectTranslation(registry); registerROCDLDialectTranslation(registry); registerX86VectorDialectTranslation(registry); diff --git a/mlir/include/mlir/Target/LLVMIR/Dialect/OpenACC/OpenACCToLLVMIRTranslation.h b/mlir/include/mlir/Target/LLVMIR/Dialect/OpenACC/OpenACCToLLVMIRTranslation.h new file mode 100644 index 0000000..d7e847f --- /dev/null +++ b/mlir/include/mlir/Target/LLVMIR/Dialect/OpenACC/OpenACCToLLVMIRTranslation.h @@ -0,0 +1,31 @@ +//===- OpenACCToLLVMIRTranslation.h - OpenACC Dialect to LLVM IR -- C++ -*-===// +// +// 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 provides registration calls for OpenACC dialect to LLVM IR translation. +// +//===----------------------------------------------------------------------===// + +#ifndef MLIR_TARGET_LLVMIR_DIALECT_OPENACC_OPENACCTOLLVMIRTRANSLATION_H +#define MLIR_TARGET_LLVMIR_DIALECT_OPENACC_OPENACCTOLLVMIRTRANSLATION_H + +namespace mlir { + +class DialectRegistry; +class MLIRContext; + +/// Register the OpenACC dialect and the translation to the LLVM IR in +/// the given registry; +void registerOpenACCDialectTranslation(DialectRegistry ®istry); + +/// Register the OpenACC dialect and the translation in the registry +/// associated with the given context. +void registerOpenACCDialectTranslation(MLIRContext &context); + +} // namespace mlir + +#endif // MLIR_TARGET_LLVMIR_DIALECT_OPENACC_OPENACCTOLLVMIRTRANSLATION_H diff --git a/mlir/lib/Target/LLVMIR/CMakeLists.txt b/mlir/lib/Target/LLVMIR/CMakeLists.txt index 6d48c999..accd6c6 100644 --- a/mlir/lib/Target/LLVMIR/CMakeLists.txt +++ b/mlir/lib/Target/LLVMIR/CMakeLists.txt @@ -27,6 +27,7 @@ add_mlir_translation_library(MLIRTargetLLVMIRExport LINK_LIBS PUBLIC MLIRLLVMIR + MLIROpenACC MLIROpenMP MLIRLLVMIRTransforms MLIRTranslation @@ -42,6 +43,7 @@ add_mlir_translation_library(MLIRToLLVMIRTranslationRegistration MLIRX86VectorToLLVMIRTranslation MLIRLLVMToLLVMIRTranslation MLIRNVVMToLLVMIRTranslation + MLIROpenACCToLLVMIRTranslation MLIROpenMPToLLVMIRTranslation MLIRROCDLToLLVMIRTranslation ) diff --git a/mlir/lib/Target/LLVMIR/Dialect/CMakeLists.txt b/mlir/lib/Target/LLVMIR/Dialect/CMakeLists.txt index 40bed0b..8df5176 100644 --- a/mlir/lib/Target/LLVMIR/Dialect/CMakeLists.txt +++ b/mlir/lib/Target/LLVMIR/Dialect/CMakeLists.txt @@ -3,6 +3,7 @@ add_subdirectory(ArmSVE) add_subdirectory(AMX) add_subdirectory(LLVMIR) add_subdirectory(NVVM) +add_subdirectory(OpenACC) add_subdirectory(OpenMP) add_subdirectory(ROCDL) add_subdirectory(X86Vector) diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenACC/CMakeLists.txt b/mlir/lib/Target/LLVMIR/Dialect/OpenACC/CMakeLists.txt new file mode 100644 index 0000000..c61aece --- /dev/null +++ b/mlir/lib/Target/LLVMIR/Dialect/OpenACC/CMakeLists.txt @@ -0,0 +1,14 @@ +add_mlir_translation_library(MLIROpenACCToLLVMIRTranslation + OpenACCToLLVMIRTranslation.cpp + + LINK_COMPONENTS + Core + + LINK_LIBS PUBLIC + MLIRIR + MLIRLLVMIR + MLIROpenACC + MLIROpenACCToLLVM + MLIRSupport + MLIRTargetLLVMIRExport + ) diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenACC/OpenACCToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenACC/OpenACCToLLVMIRTranslation.cpp new file mode 100644 index 0000000..490e833 --- /dev/null +++ b/mlir/lib/Target/LLVMIR/Dialect/OpenACC/OpenACCToLLVMIRTranslation.cpp @@ -0,0 +1,304 @@ +//===- OpenACCToLLVMIRTranslation.cpp -------------------------------------===// +// +// 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 implements a translation between the MLIR OpenACC dialect and LLVM +// IR. +// +//===----------------------------------------------------------------------===// + +#include "mlir/Target/LLVMIR/Dialect/OpenACC/OpenACCToLLVMIRTranslation.h" +#include "mlir/Conversion/OpenACCToLLVM/ConvertOpenACCToLLVM.h" +#include "mlir/Dialect/LLVMIR/LLVMDialect.h" +#include "mlir/Dialect/OpenACC/OpenACC.h" +#include "mlir/IR/BuiltinOps.h" +#include "mlir/IR/Operation.h" +#include "mlir/Support/LLVM.h" +#include "mlir/Target/LLVMIR/ModuleTranslation.h" + +#include "llvm/ADT/TypeSwitch.h" +#include "llvm/Frontend/OpenMP/OMPConstants.h" +#include "llvm/Support/FormatVariadic.h" + +using namespace mlir; + +using OpenACCIRBuilder = llvm::OpenMPIRBuilder; + +//===----------------------------------------------------------------------===// +// Utility functions +//===----------------------------------------------------------------------===// + +/// 0 = alloc/create +static constexpr uint64_t createFlag = 0; +/// 1 = to/copyin +static constexpr uint64_t copyinFlag = 1; +/// Default value for the device id +static constexpr int64_t defaultDevice = -1; + +/// Create a constant string location from the MLIR Location information. +static llvm::Constant *createSourceLocStrFromLocation(Location loc, + OpenACCIRBuilder &builder, + StringRef name) { + 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); + } else { + std::string locStr; + llvm::raw_string_ostream locOS(locStr); + locOS << loc; + return builder.getOrCreateSrcLocStr(locOS.str()); + } +} + +/// Create the location struct from the operation location information. +static llvm::Value *createSourceLocationInfo(acc::EnterDataOp &op, + OpenACCIRBuilder &builder) { + auto loc = op.getLoc(); + auto funcOp = op.getOperation()->getParentOfType(); + StringRef funcName = funcOp ? funcOp.getName() : "unknown"; + llvm::Constant *locStr = + createSourceLocStrFromLocation(loc, builder, funcName); + return builder.getOrCreateIdent(locStr); +} + +/// Create a constant string representing the mapping information extracted from +/// the MLIR location information. +static llvm::Constant *createMappingInformation(Location loc, + OpenACCIRBuilder &builder) { + if (auto nameLoc = loc.dyn_cast()) { + StringRef name = nameLoc.getName(); + return createSourceLocStrFromLocation(nameLoc.getChildLoc(), builder, name); + } else { + return createSourceLocStrFromLocation(loc, builder, "unknown"); + } +} + +/// Return the runtime function used to lower the given operation. +static llvm::Function *getAssociatedFunction(OpenACCIRBuilder &builder, + Operation &op) { + if (isa(op)) + return builder.getOrCreateRuntimeFunctionPtr( + llvm::omp::OMPRTL___tgt_target_data_begin_mapper); + 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 +processOperands(llvm::IRBuilderBase &builder, + LLVM::ModuleTranslation &moduleTranslation, Operation &op, + ValueRange operands, unsigned totalNbOperand, + uint64_t operandFlag, SmallVector &flags, + SmallVector &names, unsigned &index, + llvm::AllocaInst *argsBase, llvm::AllocaInst *args, + llvm::AllocaInst *argSizes) { + OpenACCIRBuilder *accBuilder = moduleTranslation.getOpenMPBuilder(); + llvm::LLVMContext &ctx = builder.getContext(); + auto *i8PtrTy = llvm::Type::getInt8PtrTy(ctx); + auto *arrI8PtrTy = llvm::ArrayType::get(i8PtrTy, totalNbOperand); + auto *i64Ty = llvm::Type::getInt64Ty(ctx); + auto *arrI64Ty = llvm::ArrayType::get(i64Ty, totalNbOperand); + + for (Value data : operands) { + llvm::Value *dataValue = moduleTranslation.lookupValue(data); + + llvm::Value *dataPtrBase; + llvm::Value *dataPtr; + llvm::Value *dataSize; + + // Handle operands that were converted to DataDescriptor. + if (DataDescriptor::isValid(data)) { + dataPtrBase = + builder.CreateExtractValue(dataValue, kPtrBasePosInDataDescriptor); + dataPtr = builder.CreateExtractValue(dataValue, kPtrPosInDataDescriptor); + dataSize = + builder.CreateExtractValue(dataValue, kSizePosInDataDescriptor); + } else if (data.getType().isa()) { + dataPtrBase = dataValue; + dataPtr = dataValue; + dataSize = getSizeInBytes(builder, dataValue); + } else { + return op.emitOpError() + << "Data operand must be legalized before translation." + << "Unsupported type: " << data.getType(); + } + + // Store base pointer extracted from operand into the i-th position of + // argBase. + llvm::Value *ptrBaseGEP = builder.CreateInBoundsGEP( + arrI8PtrTy, argsBase, {builder.getInt32(0), builder.getInt32(index)}); + llvm::Value *ptrBaseCast = builder.CreateBitCast( + ptrBaseGEP, dataPtrBase->getType()->getPointerTo()); + builder.CreateStore(dataPtrBase, ptrBaseCast); + + // Store pointer extracted from operand into the i-th position of args. + llvm::Value *ptrGEP = builder.CreateInBoundsGEP( + arrI8PtrTy, args, {builder.getInt32(0), builder.getInt32(index)}); + llvm::Value *ptrCast = + builder.CreateBitCast(ptrGEP, dataPtr->getType()->getPointerTo()); + builder.CreateStore(dataPtr, ptrCast); + + // Store size extracted from operand into the i-th position of argSizes. + llvm::Value *sizeGEP = builder.CreateInBoundsGEP( + arrI64Ty, argSizes, {builder.getInt32(0), builder.getInt32(index)}); + builder.CreateStore(dataSize, sizeGEP); + + flags.push_back(operandFlag); + llvm::Constant *mapName = + createMappingInformation(data.getLoc(), *accBuilder); + names.push_back(mapName); + ++index; + } + return success(); +} + +//===----------------------------------------------------------------------===// +// Conversion functions +//===----------------------------------------------------------------------===// + +/// Converts an OpenACC enter_data operartion into LLVM IR. +static LogicalResult +convertEnterDataOp(Operation &op, llvm::IRBuilderBase &builder, + LLVM::ModuleTranslation &moduleTranslation) { + auto enterDataOp = cast(op); + auto enclosingFuncOp = op.getParentOfType(); + llvm::Function *enclosingFunction = + moduleTranslation.lookupFunction(enclosingFuncOp.getName()); + + OpenACCIRBuilder *accBuilder = moduleTranslation.getOpenMPBuilder(); + + auto *srcLocInfo = createSourceLocationInfo(enterDataOp, *accBuilder); + auto *mapperFunc = getAssociatedFunction(*accBuilder, op); + + // Number of arguments in the enter_data operation. + // TODO include create_zero and attach operands. + unsigned totalNbOperand = + enterDataOp.createOperands().size() + enterDataOp.copyinOperands().size(); + + // TODO could be moved to OpenXXIRBuilder? + llvm::LLVMContext &ctx = builder.getContext(); + auto *i8PtrTy = llvm::Type::getInt8PtrTy(ctx); + auto *arrI8PtrTy = llvm::ArrayType::get(i8PtrTy, totalNbOperand); + auto *i64Ty = llvm::Type::getInt64Ty(ctx); + auto *arrI64Ty = llvm::ArrayType::get(i64Ty, totalNbOperand); + llvm::IRBuilder<>::InsertPoint allocaIP( + &enclosingFunction->getEntryBlock(), + enclosingFunction->getEntryBlock().getFirstInsertionPt()); + llvm::IRBuilder<>::InsertPoint currentIP = builder.saveIP(); + builder.restoreIP(allocaIP); + llvm::AllocaInst *argsBase = builder.CreateAlloca(arrI8PtrTy); + llvm::AllocaInst *args = builder.CreateAlloca(arrI8PtrTy); + llvm::AllocaInst *argSizes = builder.CreateAlloca(arrI64Ty); + builder.restoreIP(currentIP); + + SmallVector flags; + SmallVector names; + unsigned index = 0; + + // Create operands are handled as `alloc` call. + if (failed(processOperands(builder, moduleTranslation, op, + enterDataOp.createOperands(), totalNbOperand, + createFlag, flags, names, index, argsBase, args, + argSizes))) + return failure(); + + // Copyin operands are handled as `to` call. + if (failed(processOperands(builder, moduleTranslation, op, + enterDataOp.copyinOperands(), totalNbOperand, + copyinFlag, flags, names, index, argsBase, args, + argSizes))) + return failure(); + + llvm::GlobalVariable *maptypes = + accBuilder->createOffloadMaptypes(flags, ".offload_maptypes"); + llvm::Value *maptypesArg = builder.CreateConstInBoundsGEP2_32( + llvm::ArrayType::get(llvm::Type::getInt64Ty(ctx), totalNbOperand), + maptypes, /*Idx0=*/0, /*Idx1=*/0); + + llvm::GlobalVariable *mapnames = + accBuilder->createOffloadMapnames(names, ".offload_mapnames"); + llvm::Value *mapnamesArg = builder.CreateConstInBoundsGEP2_32( + llvm::ArrayType::get(llvm::Type::getInt8PtrTy(ctx), totalNbOperand), + mapnames, /*Idx0=*/0, /*Idx1=*/0); + + llvm::Value *argsBaseGEP = builder.CreateInBoundsGEP( + arrI8PtrTy, argsBase, {builder.getInt32(0), builder.getInt32(0)}); + llvm::Value *argsGEP = builder.CreateInBoundsGEP( + arrI8PtrTy, args, {builder.getInt32(0), builder.getInt32(0)}); + llvm::Value *argSizesGEP = builder.CreateInBoundsGEP( + arrI64Ty, argSizes, {builder.getInt32(0), builder.getInt32(0)}); + llvm::Value *nullPtr = llvm::Constant::getNullValue( + llvm::Type::getInt8PtrTy(ctx)->getPointerTo()); + + builder.CreateCall(mapperFunc, + {srcLocInfo, builder.getInt64(defaultDevice), + builder.getInt32(totalNbOperand), argsBaseGEP, argsGEP, + argSizesGEP, maptypesArg, mapnamesArg, nullPtr}); + + return success(); +} + +namespace { + +/// Implementation of the dialect interface that converts operations belonging +/// to the OpenACC dialect to LLVM IR. +class OpenACCDialectLLVMIRTranslationInterface + : public LLVMTranslationDialectInterface { +public: + using LLVMTranslationDialectInterface::LLVMTranslationDialectInterface; + + /// Translates the given operation to LLVM IR using the provided IR builder + /// and saving the state in `moduleTranslation`. + LogicalResult + convertOperation(Operation *op, llvm::IRBuilderBase &builder, + LLVM::ModuleTranslation &moduleTranslation) const final; +}; + +} // end namespace + +/// Given an OpenACC MLIR operation, create the corresponding LLVM IR +/// (including OpenACC runtime calls). +LogicalResult OpenACCDialectLLVMIRTranslationInterface::convertOperation( + Operation *op, llvm::IRBuilderBase &builder, + LLVM::ModuleTranslation &moduleTranslation) const { + + return llvm::TypeSwitch(op) + .Case([&](acc::EnterDataOp) { + return convertEnterDataOp(*op, builder, moduleTranslation); + }) + .Default([&](Operation *op) { + return op->emitError("unsupported OpenACC operation: ") + << op->getName(); + }); +} + +void mlir::registerOpenACCDialectTranslation(DialectRegistry ®istry) { + registry.insert(); + registry.addDialectInterface(); +} + +void mlir::registerOpenACCDialectTranslation(MLIRContext &context) { + DialectRegistry registry; + registerOpenACCDialectTranslation(registry); + context.appendDialectRegistry(registry); +} diff --git a/mlir/test/Target/LLVMIR/openacc-llvm.mlir b/mlir/test/Target/LLVMIR/openacc-llvm.mlir new file mode 100644 index 0000000..c57e502 --- /dev/null +++ b/mlir/test/Target/LLVMIR/openacc-llvm.mlir @@ -0,0 +1,65 @@ +// RUN: mlir-translate -mlir-to-llvmir %s | FileCheck %s + +llvm.func @testenterdataop(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: i64, %arg3: i64, %arg4: i64, %arg5: !llvm.ptr) { + %0 = llvm.mlir.undef : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)> + %1 = llvm.insertvalue %arg0, %0[0] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)> + %2 = llvm.insertvalue %arg1, %1[1] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)> + %3 = llvm.insertvalue %arg2, %2[2] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)> + %4 = llvm.insertvalue %arg3, %3[3, 0] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)> + %5 = llvm.insertvalue %arg4, %4[4, 0] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)> + %6 = llvm.mlir.constant(10 : index) : i64 + %7 = llvm.mlir.constant(1 : index) : i64 + %8 = llvm.mlir.null : !llvm.ptr + %9 = llvm.getelementptr %8[%6] : (!llvm.ptr, i64) -> !llvm.ptr + %10 = llvm.ptrtoint %9 : !llvm.ptr to i64 + %11 = llvm.extractvalue %5[1] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)> + %12 = llvm.mlir.undef : !llvm.struct<"openacc_data", (struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>, ptr, i64)> + %13 = llvm.insertvalue %5, %12[0] : !llvm.struct<"openacc_data", (struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>, ptr, i64)> + %14 = llvm.insertvalue %11, %13[1] : !llvm.struct<"openacc_data", (struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>, ptr, i64)> + %15 = llvm.insertvalue %10, %14[2] : !llvm.struct<"openacc_data", (struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>, ptr, i64)> + acc.enter_data copyin(%arg5 : !llvm.ptr) create(%15 : !llvm.struct<"openacc_data", (struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>, ptr, i64)>) + llvm.return +} + +// CHECK: %struct.ident_t = type { i32, i32, i32, i32, i8* } + +// CHECK: [[LOCSTR:@.*]] = private unnamed_addr constant [{{[0-9]*}} x i8] c";{{.*}};testenterdataop;{{[0-9]*}};{{[0-9]*}};;\00", align 1 +// CHECK: [[LOCGLOBAL:@.*]] = private unnamed_addr constant %struct.ident_t { i32 0, i32 2, i32 0, i32 0, i8* getelementptr inbounds ([{{[0-9]*}} x i8], [{{[0-9]*}} x i8]* [[LOCSTR]], i32 0, i32 0) }, align 8 +// CHECK: [[MAPNAME1:@.*]] = private unnamed_addr constant [{{[0-9]*}} x i8] c";{{.*}};unknown;{{[0-9]*}};{{[0-9]*}};;\00", align 1 +// CHECK: [[MAPNAME2:@.*]] = private unnamed_addr constant [{{[0-9]*}} x i8] c";{{.*}};unknown;{{[0-9]*}};{{[0-9]*}};;\00", align 1 +// CHECK: [[MAPTYPES:@.*]] = private unnamed_addr constant [{{[0-9]*}} x i64] [i64 0, i64 1] +// CHECK: [[MAPNAMES:@.*]] = private constant [{{[0-9]*}} x i8*] [i8* getelementptr inbounds ([{{[0-9]*}} x i8], [{{[0-9]*}} x i8]* [[MAPNAME1]], i32 0, i32 0), i8* getelementptr inbounds ([{{[0-9]*}} x i8], [{{[0-9]*}} x i8]* [[MAPNAME2]], i32 0, i32 0)] + +// CHECK: define void @testenterdataop(float* %{{.*}}, float* %{{.*}}, i64 %{{.*}}, i64 %{{.*}}, i64 %{{.*}}, float* [[SIMPLEPTR:%.*]]) +// CHECK: [[ARGBASE_ALLOCA:%.*]] = alloca [{{[0-9]*}} x i8*], align 8 +// CHECK: [[ARG_ALLOCA:%.*]] = alloca [{{[0-9]*}} x i8*], align 8 +// CHECK: [[SIZE_ALLOCA:%.*]] = alloca [{{[0-9]*}} x i64], align 8 + +// CHECK: [[ARGBASE:%.*]] = extractvalue %openacc_data %{{.*}}, 0 +// CHECK: [[ARG:%.*]] = extractvalue %openacc_data %{{.*}}, 1 +// CHECK: [[ARGSIZE:%.*]] = extractvalue %openacc_data %{{.*}}, 2 +// CHECK: [[ARGBASEGEP:%.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[ARGBASE_ALLOCA]], i32 0, i32 0 +// CHECK: [[ARGBASEGEPCAST:%.*]] = bitcast i8** [[ARGBASEGEP]] to { float*, float*, i64, [1 x i64], [1 x i64] }* +// CHECK: store { float*, float*, i64, [1 x i64], [1 x i64] } [[ARGBASE]], { float*, float*, i64, [1 x i64], [1 x i64] }* [[ARGBASEGEPCAST]], align 8 +// CHECK: [[ARGGEP:%.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[ARG_ALLOCA]], i32 0, i32 0 +// CHECK: [[ARGGEPCAST:%.*]] = bitcast i8** [[ARGGEP]] to float** +// CHECK: store float* [[ARG]], float** [[ARGGEPCAST]], align 8 +// CHECK: [[SIZEGEP:%.*]] = getelementptr inbounds [2 x i64], [2 x i64]* [[SIZE_ALLOCA]], i32 0, i32 0 +// CHECK: store i64 [[ARGSIZE]], i64* [[SIZEGEP]], align 4 + +// CHECK: [[ARGBASEGEP:%.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[ARGBASE_ALLOCA]], i32 0, i32 1 +// CHECK: [[ARGBASEGEPCAST:%.*]] = bitcast i8** [[ARGBASEGEP]] to float** +// CHECK: store float* [[SIMPLEPTR]], float** [[ARGBASEGEPCAST]], align 8 +// CHECK: [[ARGGEP:%.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[ARG_ALLOCA]], i32 0, i32 1 +// CHECK: [[ARGGEPCAST:%.*]] = bitcast i8** [[ARGGEP]] to float** +// CHECK: store float* [[SIMPLEPTR]], float** [[ARGGEPCAST]], align 8 +// CHECK: [[SIZEGEP:%.*]] = getelementptr inbounds [2 x i64], [2 x i64]* [[SIZE_ALLOCA]], i32 0, i32 1 +// CHECK: store i64 ptrtoint (i1** getelementptr (i1*, i1** null, i32 1) to i64), i64* [[SIZEGEP]], align 4 + +// CHECK: [[ARGBASE_ALLOCA_GEP:%.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[ARGBASE_ALLOCA]], i32 0, i32 0 +// CHECK: [[ARG_ALLOCA_GEP:%.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* [[ARG_ALLOCA]], i32 0, i32 0 +// CHECK: [[SIZE_ALLOCA_GEP:%.*]] = getelementptr inbounds [2 x i64], [2 x i64]* [[SIZE_ALLOCA]], i32 0, i32 0 + +// CHECK: call void @__tgt_target_data_begin_mapper(%struct.ident_t* [[LOCGLOBAL]], i64 -1, i32 2, i8** [[ARGBASE_ALLOCA_GEP]], i8** [[ARG_ALLOCA_GEP]], i64* [[SIZE_ALLOCA_GEP]], i64* getelementptr inbounds ([{{[0-9]*}} x i64], [{{[0-9]*}} x i64]* [[MAPTYPES]], i32 0, i32 0), i8** getelementptr inbounds ([{{[0-9]*}} x i8*], [{{[0-9]*}} x i8*]* [[MAPNAMES]], i32 0, i32 0), i8** null) + +// CHECK: declare void @__tgt_target_data_begin_mapper(%struct.ident_t*, i64, i32, i8**, i8**, i64*, i64*, i8**, i8**) #0 -- 2.7.4