This commit fixes a bug in the Mem2Reg operation erasure order. Replacing the use-def based topological order with a dominance-based weak order ensures that no operation is removed before all its uses have been replaced. The order relation uses the topological order of blocks and block internal ordering to determine a deterministic operation order. Additionally, the reliance on the `DenseMap` key order was eliminated by switching to a `MapVector`, that gives a deterministic iteration order. Example: ``` %ptr = alloca ... ... %val0 = %load %ptr ... // LOAD0 store %val0 %ptr ... %val1 = load %ptr ... // LOAD1 ```` When promoting the slot backing %ptr, it can happen that the LOAD0 was cleaned before LOAD1. This results in all uses of LOAD0 being replaced by its reaching definition, before LOAD1's result is replaced by LOAD0's result. The subsequent erasure of LOAD0 can thus not succeed, as it has remaining usages.
549 lines
22 KiB
C++
549 lines
22 KiB
C++
//===- 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/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/Dialect/OpenMPCommon.h"
|
|
#include "mlir/Target/LLVMIR/ModuleTranslation.h"
|
|
#include "mlir/Transforms/RegionUtils.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
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// Flag values are extracted from openmp/libomptarget/include/omptarget.h and
|
|
/// mapped to corresponding OpenACC flags.
|
|
static constexpr uint64_t kCreateFlag = 0x000;
|
|
static constexpr uint64_t kDeviceCopyinFlag = 0x001;
|
|
static constexpr uint64_t kHostCopyoutFlag = 0x002;
|
|
static constexpr uint64_t kPresentFlag = 0x1000;
|
|
static constexpr uint64_t kDeleteFlag = 0x008;
|
|
// Runtime extension to implement the OpenACC second reference counter.
|
|
static constexpr uint64_t kHoldFlag = 0x2000;
|
|
|
|
/// Default value for the device id
|
|
static constexpr int64_t kDefaultDevice = -1;
|
|
|
|
/// Create the location struct from the operation location information.
|
|
static llvm::Value *createSourceLocationInfo(OpenACCIRBuilder &builder,
|
|
Operation *op) {
|
|
auto loc = op->getLoc();
|
|
auto funcOp = op->getParentOfType<LLVM::LLVMFuncOp>();
|
|
StringRef funcName = funcOp ? funcOp.getName() : "unknown";
|
|
uint32_t strLen;
|
|
llvm::Constant *locStr = mlir::LLVM::createSourceLocStrFromLocation(
|
|
loc, builder, funcName, strLen);
|
|
return builder.getOrCreateIdent(locStr, strLen);
|
|
}
|
|
|
|
/// Return the runtime function used to lower the given operation.
|
|
static llvm::Function *getAssociatedFunction(OpenACCIRBuilder &builder,
|
|
Operation *op) {
|
|
return llvm::TypeSwitch<Operation *, llvm::Function *>(op)
|
|
.Case([&](acc::EnterDataOp) {
|
|
return builder.getOrCreateRuntimeFunctionPtr(
|
|
llvm::omp::OMPRTL___tgt_target_data_begin_mapper);
|
|
})
|
|
.Case([&](acc::ExitDataOp) {
|
|
return builder.getOrCreateRuntimeFunctionPtr(
|
|
llvm::omp::OMPRTL___tgt_target_data_end_mapper);
|
|
})
|
|
.Case([&](acc::UpdateOp) {
|
|
return builder.getOrCreateRuntimeFunctionPtr(
|
|
llvm::omp::OMPRTL___tgt_target_data_update_mapper);
|
|
});
|
|
llvm_unreachable("Unknown OpenACC operation");
|
|
}
|
|
|
|
/// 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<uint64_t> &flags,
|
|
SmallVectorImpl<llvm::Constant *> &names, unsigned &index,
|
|
struct OpenACCIRBuilder::MapperAllocas &mapperAllocas) {
|
|
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;
|
|
|
|
if (isa<LLVM::LLVMPointerType>(data.getType())) {
|
|
dataPtrBase = dataValue;
|
|
dataPtr = dataValue;
|
|
dataSize = accBuilder->getSizeInBytes(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, mapperAllocas.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, mapperAllocas.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, mapperAllocas.ArgSizes,
|
|
{builder.getInt32(0), builder.getInt32(index)});
|
|
builder.CreateStore(dataSize, sizeGEP);
|
|
|
|
flags.push_back(operandFlag);
|
|
llvm::Constant *mapName =
|
|
mlir::LLVM::createMappingInformation(data.getLoc(), *accBuilder);
|
|
names.push_back(mapName);
|
|
++index;
|
|
}
|
|
return success();
|
|
}
|
|
|
|
/// Process data operands from acc::EnterDataOp
|
|
static LogicalResult
|
|
processDataOperands(llvm::IRBuilderBase &builder,
|
|
LLVM::ModuleTranslation &moduleTranslation,
|
|
acc::EnterDataOp op, SmallVector<uint64_t> &flags,
|
|
SmallVectorImpl<llvm::Constant *> &names,
|
|
struct OpenACCIRBuilder::MapperAllocas &mapperAllocas) {
|
|
// TODO add `create_zero` and `attach` operands
|
|
|
|
unsigned index = 0;
|
|
|
|
// Create operands are handled as `alloc` call.
|
|
// Copyin operands are handled as `to` call.
|
|
llvm::SmallVector<mlir::Value> create, copyin;
|
|
for (mlir::Value dataOp : op.getDataClauseOperands()) {
|
|
if (auto createOp =
|
|
mlir::dyn_cast_or_null<acc::CreateOp>(dataOp.getDefiningOp())) {
|
|
create.push_back(createOp.getVarPtr());
|
|
} else if (auto copyinOp = mlir::dyn_cast_or_null<acc::CopyinOp>(
|
|
dataOp.getDefiningOp())) {
|
|
copyin.push_back(copyinOp.getVarPtr());
|
|
}
|
|
}
|
|
|
|
auto nbTotalOperands = create.size() + copyin.size();
|
|
|
|
// Create operands are handled as `alloc` call.
|
|
if (failed(processOperands(builder, moduleTranslation, op, create,
|
|
nbTotalOperands, kCreateFlag, flags, names, index,
|
|
mapperAllocas)))
|
|
return failure();
|
|
|
|
// Copyin operands are handled as `to` call.
|
|
if (failed(processOperands(builder, moduleTranslation, op, copyin,
|
|
nbTotalOperands, kDeviceCopyinFlag, flags, names,
|
|
index, mapperAllocas)))
|
|
return failure();
|
|
|
|
return success();
|
|
}
|
|
|
|
/// Process data operands from acc::ExitDataOp
|
|
static LogicalResult
|
|
processDataOperands(llvm::IRBuilderBase &builder,
|
|
LLVM::ModuleTranslation &moduleTranslation,
|
|
acc::ExitDataOp op, SmallVector<uint64_t> &flags,
|
|
SmallVectorImpl<llvm::Constant *> &names,
|
|
struct OpenACCIRBuilder::MapperAllocas &mapperAllocas) {
|
|
// TODO add `detach` operands
|
|
|
|
unsigned index = 0;
|
|
|
|
llvm::SmallVector<mlir::Value> deleteOperands, copyoutOperands;
|
|
for (mlir::Value dataOp : op.getDataClauseOperands()) {
|
|
if (auto devicePtrOp = mlir::dyn_cast_or_null<acc::GetDevicePtrOp>(
|
|
dataOp.getDefiningOp())) {
|
|
for (auto &u : devicePtrOp.getAccPtr().getUses()) {
|
|
if (mlir::dyn_cast_or_null<acc::DeleteOp>(u.getOwner()))
|
|
deleteOperands.push_back(devicePtrOp.getVarPtr());
|
|
else if (mlir::dyn_cast_or_null<acc::CopyoutOp>(u.getOwner()))
|
|
copyoutOperands.push_back(devicePtrOp.getVarPtr());
|
|
}
|
|
}
|
|
}
|
|
|
|
auto nbTotalOperands = deleteOperands.size() + copyoutOperands.size();
|
|
|
|
// Delete operands are handled as `delete` call.
|
|
if (failed(processOperands(builder, moduleTranslation, op, deleteOperands,
|
|
nbTotalOperands, kDeleteFlag, flags, names, index,
|
|
mapperAllocas)))
|
|
return failure();
|
|
|
|
// Copyout operands are handled as `from` call.
|
|
if (failed(processOperands(builder, moduleTranslation, op, copyoutOperands,
|
|
nbTotalOperands, kHostCopyoutFlag, flags, names,
|
|
index, mapperAllocas)))
|
|
return failure();
|
|
|
|
return success();
|
|
}
|
|
|
|
/// Process data operands from acc::UpdateOp
|
|
static LogicalResult
|
|
processDataOperands(llvm::IRBuilderBase &builder,
|
|
LLVM::ModuleTranslation &moduleTranslation,
|
|
acc::UpdateOp op, SmallVector<uint64_t> &flags,
|
|
SmallVectorImpl<llvm::Constant *> &names,
|
|
struct OpenACCIRBuilder::MapperAllocas &mapperAllocas) {
|
|
unsigned index = 0;
|
|
|
|
// Host operands are handled as `from` call.
|
|
// Device operands are handled as `to` call.
|
|
llvm::SmallVector<mlir::Value> from, to;
|
|
for (mlir::Value dataOp : op.getDataClauseOperands()) {
|
|
if (auto getDevicePtrOp = mlir::dyn_cast_or_null<acc::GetDevicePtrOp>(
|
|
dataOp.getDefiningOp())) {
|
|
from.push_back(getDevicePtrOp.getVarPtr());
|
|
} else if (auto updateDeviceOp =
|
|
mlir::dyn_cast_or_null<acc::UpdateDeviceOp>(
|
|
dataOp.getDefiningOp())) {
|
|
to.push_back(updateDeviceOp.getVarPtr());
|
|
}
|
|
}
|
|
|
|
if (failed(processOperands(builder, moduleTranslation, op, from, from.size(),
|
|
kHostCopyoutFlag, flags, names, index,
|
|
mapperAllocas)))
|
|
return failure();
|
|
|
|
if (failed(processOperands(builder, moduleTranslation, op, to, to.size(),
|
|
kDeviceCopyinFlag, flags, names, index,
|
|
mapperAllocas)))
|
|
return failure();
|
|
return success();
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Conversion functions
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// Converts an OpenACC data operation into LLVM IR.
|
|
static LogicalResult convertDataOp(acc::DataOp &op,
|
|
llvm::IRBuilderBase &builder,
|
|
LLVM::ModuleTranslation &moduleTranslation) {
|
|
llvm::LLVMContext &ctx = builder.getContext();
|
|
auto enclosingFuncOp = op.getOperation()->getParentOfType<LLVM::LLVMFuncOp>();
|
|
llvm::Function *enclosingFunction =
|
|
moduleTranslation.lookupFunction(enclosingFuncOp.getName());
|
|
|
|
OpenACCIRBuilder *accBuilder = moduleTranslation.getOpenMPBuilder();
|
|
|
|
llvm::Value *srcLocInfo = createSourceLocationInfo(*accBuilder, op);
|
|
|
|
llvm::Function *beginMapperFunc = accBuilder->getOrCreateRuntimeFunctionPtr(
|
|
llvm::omp::OMPRTL___tgt_target_data_begin_mapper);
|
|
|
|
llvm::Function *endMapperFunc = accBuilder->getOrCreateRuntimeFunctionPtr(
|
|
llvm::omp::OMPRTL___tgt_target_data_end_mapper);
|
|
|
|
// Number of arguments in the data operation.
|
|
unsigned totalNbOperand = op.getNumDataOperands();
|
|
|
|
struct OpenACCIRBuilder::MapperAllocas mapperAllocas;
|
|
OpenACCIRBuilder::InsertPointTy allocaIP(
|
|
&enclosingFunction->getEntryBlock(),
|
|
enclosingFunction->getEntryBlock().getFirstInsertionPt());
|
|
accBuilder->createMapperAllocas(builder.saveIP(), allocaIP, totalNbOperand,
|
|
mapperAllocas);
|
|
|
|
SmallVector<uint64_t> flags;
|
|
SmallVector<llvm::Constant *> names;
|
|
unsigned index = 0;
|
|
|
|
// TODO handle no_create, deviceptr and attach operands.
|
|
|
|
llvm::SmallVector<mlir::Value> copyin, copyout, create, present,
|
|
deleteOperands;
|
|
for (mlir::Value dataOp : op.getDataClauseOperands()) {
|
|
if (auto devicePtrOp = mlir::dyn_cast_or_null<acc::GetDevicePtrOp>(
|
|
dataOp.getDefiningOp())) {
|
|
for (auto &u : devicePtrOp.getAccPtr().getUses()) {
|
|
if (mlir::dyn_cast_or_null<acc::DeleteOp>(u.getOwner())) {
|
|
deleteOperands.push_back(devicePtrOp.getVarPtr());
|
|
} else if (mlir::dyn_cast_or_null<acc::CopyoutOp>(u.getOwner())) {
|
|
// TODO copyout zero currenlty handled as copyout. Update when
|
|
// extension available.
|
|
copyout.push_back(devicePtrOp.getVarPtr());
|
|
}
|
|
}
|
|
} else if (auto copyinOp = mlir::dyn_cast_or_null<acc::CopyinOp>(
|
|
dataOp.getDefiningOp())) {
|
|
// TODO copyin readonly currenlty handled as copyin. Update when extension
|
|
// available.
|
|
copyin.push_back(copyinOp.getVarPtr());
|
|
} else if (auto createOp = mlir::dyn_cast_or_null<acc::CreateOp>(
|
|
dataOp.getDefiningOp())) {
|
|
// TODO create zero currenlty handled as create. Update when extension
|
|
// available.
|
|
create.push_back(createOp.getVarPtr());
|
|
} else if (auto presentOp = mlir::dyn_cast_or_null<acc::PresentOp>(
|
|
dataOp.getDefiningOp())) {
|
|
present.push_back(createOp.getVarPtr());
|
|
}
|
|
}
|
|
|
|
auto nbTotalOperands = copyin.size() + copyout.size() + create.size() +
|
|
present.size() + deleteOperands.size();
|
|
|
|
// Copyin operands are handled as `to` call.
|
|
if (failed(processOperands(builder, moduleTranslation, op, copyin,
|
|
nbTotalOperands, kDeviceCopyinFlag | kHoldFlag,
|
|
flags, names, index, mapperAllocas)))
|
|
return failure();
|
|
|
|
// Delete operands are handled as `delete` call.
|
|
if (failed(processOperands(builder, moduleTranslation, op, deleteOperands,
|
|
nbTotalOperands, kDeleteFlag, flags, names, index,
|
|
mapperAllocas)))
|
|
return failure();
|
|
|
|
// Copyout operands are handled as `from` call.
|
|
if (failed(processOperands(builder, moduleTranslation, op, copyout,
|
|
nbTotalOperands, kHostCopyoutFlag | kHoldFlag,
|
|
flags, names, index, mapperAllocas)))
|
|
return failure();
|
|
|
|
// Create operands are handled as `alloc` call.
|
|
if (failed(processOperands(builder, moduleTranslation, op, create,
|
|
nbTotalOperands, kCreateFlag | kHoldFlag, flags,
|
|
names, index, mapperAllocas)))
|
|
return failure();
|
|
|
|
if (failed(processOperands(builder, moduleTranslation, op, present,
|
|
nbTotalOperands, kPresentFlag | kHoldFlag, flags,
|
|
names, index, mapperAllocas)))
|
|
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);
|
|
|
|
// Create call to start the data region.
|
|
accBuilder->emitMapperCall(builder.saveIP(), beginMapperFunc, srcLocInfo,
|
|
maptypesArg, mapnamesArg, mapperAllocas,
|
|
kDefaultDevice, totalNbOperand);
|
|
|
|
// Convert the region.
|
|
llvm::BasicBlock *entryBlock = nullptr;
|
|
|
|
for (Block &bb : op.getRegion()) {
|
|
llvm::BasicBlock *llvmBB = llvm::BasicBlock::Create(
|
|
ctx, "acc.data", builder.GetInsertBlock()->getParent());
|
|
if (entryBlock == nullptr)
|
|
entryBlock = llvmBB;
|
|
moduleTranslation.mapBlock(&bb, llvmBB);
|
|
}
|
|
|
|
auto afterDataRegion = builder.saveIP();
|
|
|
|
llvm::BranchInst *sourceTerminator = builder.CreateBr(entryBlock);
|
|
|
|
builder.restoreIP(afterDataRegion);
|
|
llvm::BasicBlock *endDataBlock = llvm::BasicBlock::Create(
|
|
ctx, "acc.end_data", builder.GetInsertBlock()->getParent());
|
|
|
|
SetVector<Block *> blocks = getTopologicallySortedBlocks(op.getRegion());
|
|
for (Block *bb : blocks) {
|
|
llvm::BasicBlock *llvmBB = moduleTranslation.lookupBlock(bb);
|
|
if (bb->isEntryBlock()) {
|
|
assert(sourceTerminator->getNumSuccessors() == 1 &&
|
|
"provided entry block has multiple successors");
|
|
sourceTerminator->setSuccessor(0, llvmBB);
|
|
}
|
|
|
|
if (failed(
|
|
moduleTranslation.convertBlock(*bb, bb->isEntryBlock(), builder))) {
|
|
return failure();
|
|
}
|
|
|
|
if (isa<acc::TerminatorOp, acc::YieldOp>(bb->getTerminator()))
|
|
builder.CreateBr(endDataBlock);
|
|
}
|
|
|
|
// Create call to end the data region.
|
|
builder.SetInsertPoint(endDataBlock);
|
|
accBuilder->emitMapperCall(builder.saveIP(), endMapperFunc, srcLocInfo,
|
|
maptypesArg, mapnamesArg, mapperAllocas,
|
|
kDefaultDevice, totalNbOperand);
|
|
|
|
return success();
|
|
}
|
|
|
|
/// Converts an OpenACC standalone data operation into LLVM IR.
|
|
template <typename OpTy>
|
|
static LogicalResult
|
|
convertStandaloneDataOp(OpTy &op, llvm::IRBuilderBase &builder,
|
|
LLVM::ModuleTranslation &moduleTranslation) {
|
|
auto enclosingFuncOp =
|
|
op.getOperation()->template getParentOfType<LLVM::LLVMFuncOp>();
|
|
llvm::Function *enclosingFunction =
|
|
moduleTranslation.lookupFunction(enclosingFuncOp.getName());
|
|
|
|
OpenACCIRBuilder *accBuilder = moduleTranslation.getOpenMPBuilder();
|
|
|
|
auto *srcLocInfo = createSourceLocationInfo(*accBuilder, op);
|
|
auto *mapperFunc = getAssociatedFunction(*accBuilder, op);
|
|
|
|
// Number of arguments in the enter_data operation.
|
|
unsigned totalNbOperand = op.getNumDataOperands();
|
|
|
|
llvm::LLVMContext &ctx = builder.getContext();
|
|
|
|
struct OpenACCIRBuilder::MapperAllocas mapperAllocas;
|
|
OpenACCIRBuilder::InsertPointTy allocaIP(
|
|
&enclosingFunction->getEntryBlock(),
|
|
enclosingFunction->getEntryBlock().getFirstInsertionPt());
|
|
accBuilder->createMapperAllocas(builder.saveIP(), allocaIP, totalNbOperand,
|
|
mapperAllocas);
|
|
|
|
SmallVector<uint64_t> flags;
|
|
SmallVector<llvm::Constant *> names;
|
|
|
|
if (failed(processDataOperands(builder, moduleTranslation, op, flags, names,
|
|
mapperAllocas)))
|
|
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);
|
|
|
|
accBuilder->emitMapperCall(builder.saveIP(), mapperFunc, srcLocInfo,
|
|
maptypesArg, mapnamesArg, mapperAllocas,
|
|
kDefaultDevice, totalNbOperand);
|
|
|
|
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;
|
|
};
|
|
|
|
} // 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<Operation *, LogicalResult>(op)
|
|
.Case([&](acc::DataOp dataOp) {
|
|
return convertDataOp(dataOp, builder, moduleTranslation);
|
|
})
|
|
.Case([&](acc::EnterDataOp enterDataOp) {
|
|
return convertStandaloneDataOp<acc::EnterDataOp>(enterDataOp, builder,
|
|
moduleTranslation);
|
|
})
|
|
.Case([&](acc::ExitDataOp exitDataOp) {
|
|
return convertStandaloneDataOp<acc::ExitDataOp>(exitDataOp, builder,
|
|
moduleTranslation);
|
|
})
|
|
.Case([&](acc::UpdateOp updateOp) {
|
|
return convertStandaloneDataOp<acc::UpdateOp>(updateOp, builder,
|
|
moduleTranslation);
|
|
})
|
|
.Case<acc::TerminatorOp, acc::YieldOp>([](auto op) {
|
|
// `yield` and `terminator` can be just omitted. The block structure was
|
|
// created in the function that handles their parent operation.
|
|
assert(op->getNumOperands() == 0 &&
|
|
"unexpected OpenACC terminator with operands");
|
|
return success();
|
|
})
|
|
.Case<acc::CreateOp, acc::CopyinOp, acc::CopyoutOp, acc::DeleteOp,
|
|
acc::UpdateDeviceOp, acc::GetDevicePtrOp>([](auto op) {
|
|
// NOP
|
|
return success();
|
|
})
|
|
.Default([&](Operation *op) {
|
|
return op->emitError("unsupported OpenACC operation: ")
|
|
<< op->getName();
|
|
});
|
|
}
|
|
|
|
void mlir::registerOpenACCDialectTranslation(DialectRegistry ®istry) {
|
|
registry.insert<acc::OpenACCDialect>();
|
|
registry.addExtension(+[](MLIRContext *ctx, acc::OpenACCDialect *dialect) {
|
|
dialect->addInterfaces<OpenACCDialectLLVMIRTranslationInterface>();
|
|
});
|
|
}
|
|
|
|
void mlir::registerOpenACCDialectTranslation(MLIRContext &context) {
|
|
DialectRegistry registry;
|
|
registerOpenACCDialectTranslation(registry);
|
|
context.appendDialectRegistry(registry);
|
|
}
|