166900b3eSAlex Zinenko //===- OpenMPToLLVMIRTranslation.cpp - Translate OpenMP dialect to LLVM IR-===//
266900b3eSAlex Zinenko //
366900b3eSAlex Zinenko // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
466900b3eSAlex Zinenko // See https://llvm.org/LICENSE.txt for license information.
566900b3eSAlex Zinenko // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
666900b3eSAlex Zinenko //
766900b3eSAlex Zinenko //===----------------------------------------------------------------------===//
866900b3eSAlex Zinenko //
966900b3eSAlex Zinenko // This file implements a translation between the MLIR OpenMP dialect and LLVM
1066900b3eSAlex Zinenko // IR.
1166900b3eSAlex Zinenko //
1266900b3eSAlex Zinenko //===----------------------------------------------------------------------===//
1366900b3eSAlex Zinenko #include "mlir/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.h"
1466900b3eSAlex Zinenko #include "mlir/Dialect/OpenMP/OpenMPDialect.h"
158647e4c3SAlex Zinenko #include "mlir/IR/BlockAndValueMapping.h"
1666900b3eSAlex Zinenko #include "mlir/IR/Operation.h"
1766900b3eSAlex Zinenko #include "mlir/Support/LLVM.h"
1866900b3eSAlex Zinenko #include "mlir/Target/LLVMIR/ModuleTranslation.h"
1966900b3eSAlex Zinenko
2066900b3eSAlex Zinenko #include "llvm/ADT/SetVector.h"
2166900b3eSAlex Zinenko #include "llvm/ADT/TypeSwitch.h"
2266900b3eSAlex Zinenko #include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
23ffe8720aSserge-sans-paille #include "llvm/IR/DebugInfoMetadata.h"
2466900b3eSAlex Zinenko #include "llvm/IR/IRBuilder.h"
2566900b3eSAlex Zinenko
2666900b3eSAlex Zinenko using namespace mlir;
2766900b3eSAlex Zinenko
2872d013ddSAlex Zinenko namespace {
292d92ee97SMichael Kruse static llvm::omp::ScheduleKind
convertToScheduleKind(Optional<omp::ClauseScheduleKind> schedKind)302d92ee97SMichael Kruse convertToScheduleKind(Optional<omp::ClauseScheduleKind> schedKind) {
31491d2701SKazu Hirata if (!schedKind.has_value())
322d92ee97SMichael Kruse return llvm::omp::OMP_SCHEDULE_Default;
33*c27d8152SKazu Hirata switch (schedKind.value()) {
342d92ee97SMichael Kruse case omp::ClauseScheduleKind::Static:
352d92ee97SMichael Kruse return llvm::omp::OMP_SCHEDULE_Static;
362d92ee97SMichael Kruse case omp::ClauseScheduleKind::Dynamic:
372d92ee97SMichael Kruse return llvm::omp::OMP_SCHEDULE_Dynamic;
382d92ee97SMichael Kruse case omp::ClauseScheduleKind::Guided:
392d92ee97SMichael Kruse return llvm::omp::OMP_SCHEDULE_Guided;
402d92ee97SMichael Kruse case omp::ClauseScheduleKind::Auto:
412d92ee97SMichael Kruse return llvm::omp::OMP_SCHEDULE_Auto;
422d92ee97SMichael Kruse case omp::ClauseScheduleKind::Runtime:
432d92ee97SMichael Kruse return llvm::omp::OMP_SCHEDULE_Runtime;
442d92ee97SMichael Kruse }
452d92ee97SMichael Kruse llvm_unreachable("unhandled schedule clause argument");
462d92ee97SMichael Kruse }
472d92ee97SMichael Kruse
4872d013ddSAlex Zinenko /// ModuleTranslation stack frame for OpenMP operations. This keeps track of the
4972d013ddSAlex Zinenko /// insertion points for allocas.
5072d013ddSAlex Zinenko class OpenMPAllocaStackFrame
5172d013ddSAlex Zinenko : public LLVM::ModuleTranslation::StackFrameBase<OpenMPAllocaStackFrame> {
5272d013ddSAlex Zinenko public:
535e50dd04SRiver Riddle MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(OpenMPAllocaStackFrame)
545e50dd04SRiver Riddle
OpenMPAllocaStackFrame(llvm::OpenMPIRBuilder::InsertPointTy allocaIP)5572d013ddSAlex Zinenko explicit OpenMPAllocaStackFrame(llvm::OpenMPIRBuilder::InsertPointTy allocaIP)
5672d013ddSAlex Zinenko : allocaInsertPoint(allocaIP) {}
5772d013ddSAlex Zinenko llvm::OpenMPIRBuilder::InsertPointTy allocaInsertPoint;
5872d013ddSAlex Zinenko };
598647e4c3SAlex Zinenko
608647e4c3SAlex Zinenko /// ModuleTranslation stack frame containing the partial mapping between MLIR
618647e4c3SAlex Zinenko /// values and their LLVM IR equivalents.
628647e4c3SAlex Zinenko class OpenMPVarMappingStackFrame
638647e4c3SAlex Zinenko : public LLVM::ModuleTranslation::StackFrameBase<
648647e4c3SAlex Zinenko OpenMPVarMappingStackFrame> {
658647e4c3SAlex Zinenko public:
665e50dd04SRiver Riddle MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(OpenMPVarMappingStackFrame)
675e50dd04SRiver Riddle
OpenMPVarMappingStackFrame(const DenseMap<Value,llvm::Value * > & mapping)688647e4c3SAlex Zinenko explicit OpenMPVarMappingStackFrame(
698647e4c3SAlex Zinenko const DenseMap<Value, llvm::Value *> &mapping)
708647e4c3SAlex Zinenko : mapping(mapping) {}
718647e4c3SAlex Zinenko
728647e4c3SAlex Zinenko DenseMap<Value, llvm::Value *> mapping;
738647e4c3SAlex Zinenko };
7472d013ddSAlex Zinenko } // namespace
7572d013ddSAlex Zinenko
7672d013ddSAlex Zinenko /// Find the insertion point for allocas given the current insertion point for
7772d013ddSAlex Zinenko /// normal operations in the builder.
7872d013ddSAlex Zinenko static llvm::OpenMPIRBuilder::InsertPointTy
findAllocaInsertPoint(llvm::IRBuilderBase & builder,const LLVM::ModuleTranslation & moduleTranslation)7972d013ddSAlex Zinenko findAllocaInsertPoint(llvm::IRBuilderBase &builder,
8072d013ddSAlex Zinenko const LLVM::ModuleTranslation &moduleTranslation) {
8172d013ddSAlex Zinenko // If there is an alloca insertion point on stack, i.e. we are in a nested
8272d013ddSAlex Zinenko // operation and a specific point was provided by some surrounding operation,
8372d013ddSAlex Zinenko // use it.
8472d013ddSAlex Zinenko llvm::OpenMPIRBuilder::InsertPointTy allocaInsertPoint;
8572d013ddSAlex Zinenko WalkResult walkResult = moduleTranslation.stackWalk<OpenMPAllocaStackFrame>(
8672d013ddSAlex Zinenko [&](const OpenMPAllocaStackFrame &frame) {
8772d013ddSAlex Zinenko allocaInsertPoint = frame.allocaInsertPoint;
8872d013ddSAlex Zinenko return WalkResult::interrupt();
8972d013ddSAlex Zinenko });
9072d013ddSAlex Zinenko if (walkResult.wasInterrupted())
9172d013ddSAlex Zinenko return allocaInsertPoint;
9272d013ddSAlex Zinenko
9372d013ddSAlex Zinenko // Otherwise, insert to the entry block of the surrounding function.
94c082ca16SMichael Kruse // If the current IRBuilder InsertPoint is the function's entry, it cannot
95c082ca16SMichael Kruse // also be used for alloca insertion which would result in insertion order
96c082ca16SMichael Kruse // confusion. Create a new BasicBlock for the Builder and use the entry block
97c082ca16SMichael Kruse // for the allocs.
98ff289feeSMichael Kruse // TODO: Create a dedicated alloca BasicBlock at function creation such that
99ff289feeSMichael Kruse // we do not need to move the current InertPoint here.
100c082ca16SMichael Kruse if (builder.GetInsertBlock() ==
101c082ca16SMichael Kruse &builder.GetInsertBlock()->getParent()->getEntryBlock()) {
102c082ca16SMichael Kruse assert(builder.GetInsertPoint() == builder.GetInsertBlock()->end() &&
103c082ca16SMichael Kruse "Assuming end of basic block");
104c082ca16SMichael Kruse llvm::BasicBlock *entryBB = llvm::BasicBlock::Create(
105c082ca16SMichael Kruse builder.getContext(), "entry", builder.GetInsertBlock()->getParent(),
106c082ca16SMichael Kruse builder.GetInsertBlock()->getNextNode());
107c082ca16SMichael Kruse builder.CreateBr(entryBB);
108c082ca16SMichael Kruse builder.SetInsertPoint(entryBB);
109c082ca16SMichael Kruse }
110c082ca16SMichael Kruse
11172d013ddSAlex Zinenko llvm::BasicBlock &funcEntryBlock =
11272d013ddSAlex Zinenko builder.GetInsertBlock()->getParent()->getEntryBlock();
11372d013ddSAlex Zinenko return llvm::OpenMPIRBuilder::InsertPointTy(
11472d013ddSAlex Zinenko &funcEntryBlock, funcEntryBlock.getFirstInsertionPt());
11572d013ddSAlex Zinenko }
11672d013ddSAlex Zinenko
11766900b3eSAlex Zinenko /// Converts the given region that appears within an OpenMP dialect operation to
11866900b3eSAlex Zinenko /// LLVM IR, creating a branch from the `sourceBlock` to the entry block of the
11966900b3eSAlex Zinenko /// region, and a branch from any block with an successor-less OpenMP terminator
1208647e4c3SAlex Zinenko /// to `continuationBlock`. Populates `continuationBlockPHIs` with the PHI nodes
1218647e4c3SAlex Zinenko /// of the continuation block if provided.
convertOmpOpRegions(Region & region,StringRef blockName,llvm::IRBuilderBase & builder,LLVM::ModuleTranslation & moduleTranslation,LogicalResult & bodyGenStatus,SmallVectorImpl<llvm::PHINode * > * continuationBlockPHIs=nullptr)122ff289feeSMichael Kruse static llvm::BasicBlock *convertOmpOpRegions(
123ff289feeSMichael Kruse Region ®ion, StringRef blockName, llvm::IRBuilderBase &builder,
1248647e4c3SAlex Zinenko LLVM::ModuleTranslation &moduleTranslation, LogicalResult &bodyGenStatus,
1258647e4c3SAlex Zinenko SmallVectorImpl<llvm::PHINode *> *continuationBlockPHIs = nullptr) {
126ff289feeSMichael Kruse llvm::BasicBlock *continuationBlock =
127ff289feeSMichael Kruse splitBB(builder, true, "omp.region.cont");
128ff289feeSMichael Kruse llvm::BasicBlock *sourceBlock = builder.GetInsertBlock();
129ff289feeSMichael Kruse
13066900b3eSAlex Zinenko llvm::LLVMContext &llvmContext = builder.getContext();
13166900b3eSAlex Zinenko for (Block &bb : region) {
13266900b3eSAlex Zinenko llvm::BasicBlock *llvmBB = llvm::BasicBlock::Create(
1338647e4c3SAlex Zinenko llvmContext, blockName, builder.GetInsertBlock()->getParent(),
1348647e4c3SAlex Zinenko builder.GetInsertBlock()->getNextNode());
13566900b3eSAlex Zinenko moduleTranslation.mapBlock(&bb, llvmBB);
13666900b3eSAlex Zinenko }
13766900b3eSAlex Zinenko
138ff289feeSMichael Kruse llvm::Instruction *sourceTerminator = sourceBlock->getTerminator();
13966900b3eSAlex Zinenko
1408647e4c3SAlex Zinenko // Terminators (namely YieldOp) may be forwarding values to the region that
1418647e4c3SAlex Zinenko // need to be available in the continuation block. Collect the types of these
1428647e4c3SAlex Zinenko // operands in preparation of creating PHI nodes.
1438647e4c3SAlex Zinenko SmallVector<llvm::Type *> continuationBlockPHITypes;
1448647e4c3SAlex Zinenko bool operandsProcessed = false;
1458647e4c3SAlex Zinenko unsigned numYields = 0;
1468647e4c3SAlex Zinenko for (Block &bb : region.getBlocks()) {
1478647e4c3SAlex Zinenko if (omp::YieldOp yield = dyn_cast<omp::YieldOp>(bb.getTerminator())) {
1488647e4c3SAlex Zinenko if (!operandsProcessed) {
1498647e4c3SAlex Zinenko for (unsigned i = 0, e = yield->getNumOperands(); i < e; ++i) {
1508647e4c3SAlex Zinenko continuationBlockPHITypes.push_back(
1518647e4c3SAlex Zinenko moduleTranslation.convertType(yield->getOperand(i).getType()));
1528647e4c3SAlex Zinenko }
1538647e4c3SAlex Zinenko operandsProcessed = true;
1548647e4c3SAlex Zinenko } else {
1558647e4c3SAlex Zinenko assert(continuationBlockPHITypes.size() == yield->getNumOperands() &&
1568647e4c3SAlex Zinenko "mismatching number of values yielded from the region");
1578647e4c3SAlex Zinenko for (unsigned i = 0, e = yield->getNumOperands(); i < e; ++i) {
1588647e4c3SAlex Zinenko llvm::Type *operandType =
1598647e4c3SAlex Zinenko moduleTranslation.convertType(yield->getOperand(i).getType());
1608647e4c3SAlex Zinenko (void)operandType;
1618647e4c3SAlex Zinenko assert(continuationBlockPHITypes[i] == operandType &&
1628647e4c3SAlex Zinenko "values of mismatching types yielded from the region");
1638647e4c3SAlex Zinenko }
1648647e4c3SAlex Zinenko }
1658647e4c3SAlex Zinenko numYields++;
1668647e4c3SAlex Zinenko }
1678647e4c3SAlex Zinenko }
1688647e4c3SAlex Zinenko
1698647e4c3SAlex Zinenko // Insert PHI nodes in the continuation block for any values forwarded by the
1708647e4c3SAlex Zinenko // terminators in this region.
1718647e4c3SAlex Zinenko if (!continuationBlockPHITypes.empty())
1728647e4c3SAlex Zinenko assert(
1738647e4c3SAlex Zinenko continuationBlockPHIs &&
1748647e4c3SAlex Zinenko "expected continuation block PHIs if converted regions yield values");
1758647e4c3SAlex Zinenko if (continuationBlockPHIs) {
1768647e4c3SAlex Zinenko llvm::IRBuilderBase::InsertPointGuard guard(builder);
1778647e4c3SAlex Zinenko continuationBlockPHIs->reserve(continuationBlockPHITypes.size());
178ff289feeSMichael Kruse builder.SetInsertPoint(continuationBlock, continuationBlock->begin());
1798647e4c3SAlex Zinenko for (llvm::Type *ty : continuationBlockPHITypes)
1808647e4c3SAlex Zinenko continuationBlockPHIs->push_back(builder.CreatePHI(ty, numYields));
1818647e4c3SAlex Zinenko }
1828647e4c3SAlex Zinenko
18366900b3eSAlex Zinenko // Convert blocks one by one in topological order to ensure
18466900b3eSAlex Zinenko // defs are converted before uses.
1854efb7754SRiver Riddle SetVector<Block *> blocks =
18666900b3eSAlex Zinenko LLVM::detail::getTopologicallySortedBlocks(region);
18766900b3eSAlex Zinenko for (Block *bb : blocks) {
18866900b3eSAlex Zinenko llvm::BasicBlock *llvmBB = moduleTranslation.lookupBlock(bb);
18966900b3eSAlex Zinenko // Retarget the branch of the entry block to the entry block of the
19066900b3eSAlex Zinenko // converted region (regions are single-entry).
19166900b3eSAlex Zinenko if (bb->isEntryBlock()) {
19266900b3eSAlex Zinenko assert(sourceTerminator->getNumSuccessors() == 1 &&
19366900b3eSAlex Zinenko "provided entry block has multiple successors");
194ff289feeSMichael Kruse assert(sourceTerminator->getSuccessor(0) == continuationBlock &&
19566900b3eSAlex Zinenko "ContinuationBlock is not the successor of the entry block");
19666900b3eSAlex Zinenko sourceTerminator->setSuccessor(0, llvmBB);
19766900b3eSAlex Zinenko }
19866900b3eSAlex Zinenko
199ce8f10d6SAlex Zinenko llvm::IRBuilderBase::InsertPointGuard guard(builder);
200ce8f10d6SAlex Zinenko if (failed(
201ce8f10d6SAlex Zinenko moduleTranslation.convertBlock(*bb, bb->isEntryBlock(), builder))) {
20266900b3eSAlex Zinenko bodyGenStatus = failure();
203ff289feeSMichael Kruse return continuationBlock;
20466900b3eSAlex Zinenko }
20566900b3eSAlex Zinenko
20666900b3eSAlex Zinenko // Special handling for `omp.yield` and `omp.terminator` (we may have more
20766900b3eSAlex Zinenko // than one): they return the control to the parent OpenMP dialect operation
20866900b3eSAlex Zinenko // so replace them with the branch to the continuation block. We handle this
20966900b3eSAlex Zinenko // here to avoid relying inter-function communication through the
21066900b3eSAlex Zinenko // ModuleTranslation class to set up the correct insertion point. This is
21166900b3eSAlex Zinenko // also consistent with MLIR's idiom of handling special region terminators
21266900b3eSAlex Zinenko // in the same code that handles the region-owning operation.
2138647e4c3SAlex Zinenko Operation *terminator = bb->getTerminator();
2148647e4c3SAlex Zinenko if (isa<omp::TerminatorOp, omp::YieldOp>(terminator)) {
215ff289feeSMichael Kruse builder.CreateBr(continuationBlock);
2168647e4c3SAlex Zinenko
2178647e4c3SAlex Zinenko for (unsigned i = 0, e = terminator->getNumOperands(); i < e; ++i)
2188647e4c3SAlex Zinenko (*continuationBlockPHIs)[i]->addIncoming(
2198647e4c3SAlex Zinenko moduleTranslation.lookupValue(terminator->getOperand(i)), llvmBB);
22066900b3eSAlex Zinenko }
2218647e4c3SAlex Zinenko }
2228647e4c3SAlex Zinenko // After all blocks have been traversed and values mapped, connect the PHI
2238647e4c3SAlex Zinenko // nodes to the results of preceding blocks.
22466900b3eSAlex Zinenko LLVM::detail::connectPHINodes(region, moduleTranslation);
2258647e4c3SAlex Zinenko
2268647e4c3SAlex Zinenko // Remove the blocks and values defined in this region from the mapping since
2278647e4c3SAlex Zinenko // they are not visible outside of this region. This allows the same region to
2288647e4c3SAlex Zinenko // be converted several times, that is cloned, without clashes, and slightly
2298647e4c3SAlex Zinenko // speeds up the lookups.
2308647e4c3SAlex Zinenko moduleTranslation.forgetMapping(region);
231ff289feeSMichael Kruse
232ff289feeSMichael Kruse return continuationBlock;
23366900b3eSAlex Zinenko }
23466900b3eSAlex Zinenko
235aae51255SMogball /// Convert ProcBindKind from MLIR-generated enum to LLVM enum.
getProcBindKind(omp::ClauseProcBindKind kind)236aae51255SMogball static llvm::omp::ProcBindKind getProcBindKind(omp::ClauseProcBindKind kind) {
237aae51255SMogball switch (kind) {
2387c385c4bSShraiysh Vaishay case omp::ClauseProcBindKind::Close:
239aae51255SMogball return llvm::omp::ProcBindKind::OMP_PROC_BIND_close;
2407c385c4bSShraiysh Vaishay case omp::ClauseProcBindKind::Master:
241aae51255SMogball return llvm::omp::ProcBindKind::OMP_PROC_BIND_master;
2427c385c4bSShraiysh Vaishay case omp::ClauseProcBindKind::Primary:
243aae51255SMogball return llvm::omp::ProcBindKind::OMP_PROC_BIND_primary;
2447c385c4bSShraiysh Vaishay case omp::ClauseProcBindKind::Spread:
245aae51255SMogball return llvm::omp::ProcBindKind::OMP_PROC_BIND_spread;
246aae51255SMogball }
247217570b0SLorenzo Chelini llvm_unreachable("Unknown ClauseProcBindKind kind");
248aae51255SMogball }
249aae51255SMogball
25066900b3eSAlex Zinenko /// Converts the OpenMP parallel operation to LLVM IR.
25166900b3eSAlex Zinenko static LogicalResult
convertOmpParallel(omp::ParallelOp opInst,llvm::IRBuilderBase & builder,LLVM::ModuleTranslation & moduleTranslation)252aae51255SMogball convertOmpParallel(omp::ParallelOp opInst, llvm::IRBuilderBase &builder,
25366900b3eSAlex Zinenko LLVM::ModuleTranslation &moduleTranslation) {
25466900b3eSAlex Zinenko using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
25566900b3eSAlex Zinenko // TODO: support error propagation in OpenMPIRBuilder and use it instead of
25666900b3eSAlex Zinenko // relying on captured variables.
25766900b3eSAlex Zinenko LogicalResult bodyGenStatus = success();
25866900b3eSAlex Zinenko
259ff289feeSMichael Kruse auto bodyGenCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP) {
26072d013ddSAlex Zinenko // Save the alloca insertion point on ModuleTranslation stack for use in
26172d013ddSAlex Zinenko // nested regions.
26272d013ddSAlex Zinenko LLVM::ModuleTranslation::SaveStack<OpenMPAllocaStackFrame> frame(
26372d013ddSAlex Zinenko moduleTranslation, allocaIP);
26472d013ddSAlex Zinenko
26566900b3eSAlex Zinenko // ParallelOp has only one region associated with it.
266ff289feeSMichael Kruse builder.restoreIP(codeGenIP);
267ff289feeSMichael Kruse convertOmpOpRegions(opInst.getRegion(), "omp.par.region", builder,
268aae51255SMogball moduleTranslation, bodyGenStatus);
26966900b3eSAlex Zinenko };
27066900b3eSAlex Zinenko
27166900b3eSAlex Zinenko // TODO: Perform appropriate actions according to the data-sharing
27266900b3eSAlex Zinenko // attribute (shared, private, firstprivate, ...) of variables.
27366900b3eSAlex Zinenko // Currently defaults to shared.
27466900b3eSAlex Zinenko auto privCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP,
27566900b3eSAlex Zinenko llvm::Value &, llvm::Value &vPtr,
27666900b3eSAlex Zinenko llvm::Value *&replacementValue) -> InsertPointTy {
27766900b3eSAlex Zinenko replacementValue = &vPtr;
27866900b3eSAlex Zinenko
27966900b3eSAlex Zinenko return codeGenIP;
28066900b3eSAlex Zinenko };
28166900b3eSAlex Zinenko
28266900b3eSAlex Zinenko // TODO: Perform finalization actions for variables. This has to be
28366900b3eSAlex Zinenko // called for variables which have destructors/finalizers.
28466900b3eSAlex Zinenko auto finiCB = [&](InsertPointTy codeGenIP) {};
28566900b3eSAlex Zinenko
28666900b3eSAlex Zinenko llvm::Value *ifCond = nullptr;
287aae51255SMogball if (auto ifExprVar = opInst.if_expr_var())
28866900b3eSAlex Zinenko ifCond = moduleTranslation.lookupValue(ifExprVar);
28966900b3eSAlex Zinenko llvm::Value *numThreads = nullptr;
290aae51255SMogball if (auto numThreadsVar = opInst.num_threads_var())
29166900b3eSAlex Zinenko numThreads = moduleTranslation.lookupValue(numThreadsVar);
292aae51255SMogball auto pbKind = llvm::omp::OMP_PROC_BIND_default;
293aae51255SMogball if (auto bind = opInst.proc_bind_val())
294aae51255SMogball pbKind = getProcBindKind(*bind);
29566900b3eSAlex Zinenko // TODO: Is the Parallel construct cancellable?
29666900b3eSAlex Zinenko bool isCancellable = false;
29772d013ddSAlex Zinenko
298c082ca16SMichael Kruse llvm::OpenMPIRBuilder::InsertPointTy allocaIP =
299c082ca16SMichael Kruse findAllocaInsertPoint(builder, moduleTranslation);
300b85cfe20SShraiysh Vaishay llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
30166900b3eSAlex Zinenko builder.restoreIP(moduleTranslation.getOpenMPBuilder()->createParallel(
302c082ca16SMichael Kruse ompLoc, allocaIP, bodyGenCB, privCB, finiCB, ifCond, numThreads, pbKind,
303c082ca16SMichael Kruse isCancellable));
30472d013ddSAlex Zinenko
30572d013ddSAlex Zinenko return bodyGenStatus;
30666900b3eSAlex Zinenko }
30766900b3eSAlex Zinenko
30866900b3eSAlex Zinenko /// Converts an OpenMP 'master' operation into LLVM IR using OpenMPIRBuilder.
30966900b3eSAlex Zinenko static LogicalResult
convertOmpMaster(Operation & opInst,llvm::IRBuilderBase & builder,LLVM::ModuleTranslation & moduleTranslation)31066900b3eSAlex Zinenko convertOmpMaster(Operation &opInst, llvm::IRBuilderBase &builder,
31166900b3eSAlex Zinenko LLVM::ModuleTranslation &moduleTranslation) {
31266900b3eSAlex Zinenko using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
31366900b3eSAlex Zinenko // TODO: support error propagation in OpenMPIRBuilder and use it instead of
31466900b3eSAlex Zinenko // relying on captured variables.
31566900b3eSAlex Zinenko LogicalResult bodyGenStatus = success();
31666900b3eSAlex Zinenko
317ff289feeSMichael Kruse auto bodyGenCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP) {
31866900b3eSAlex Zinenko // MasterOp has only one region associated with it.
31966900b3eSAlex Zinenko auto ®ion = cast<omp::MasterOp>(opInst).getRegion();
320ff289feeSMichael Kruse builder.restoreIP(codeGenIP);
321ff289feeSMichael Kruse convertOmpOpRegions(region, "omp.master.region", builder, moduleTranslation,
32266900b3eSAlex Zinenko bodyGenStatus);
32366900b3eSAlex Zinenko };
32466900b3eSAlex Zinenko
32566900b3eSAlex Zinenko // TODO: Perform finalization actions for variables. This has to be
32666900b3eSAlex Zinenko // called for variables which have destructors/finalizers.
32766900b3eSAlex Zinenko auto finiCB = [&](InsertPointTy codeGenIP) {};
32866900b3eSAlex Zinenko
329b85cfe20SShraiysh Vaishay llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
33066900b3eSAlex Zinenko builder.restoreIP(moduleTranslation.getOpenMPBuilder()->createMaster(
33166900b3eSAlex Zinenko ompLoc, bodyGenCB, finiCB));
33266900b3eSAlex Zinenko return success();
33366900b3eSAlex Zinenko }
33466900b3eSAlex Zinenko
33559989d68SKiran Chandramohan /// Converts an OpenMP 'critical' operation into LLVM IR using OpenMPIRBuilder.
33659989d68SKiran Chandramohan static LogicalResult
convertOmpCritical(Operation & opInst,llvm::IRBuilderBase & builder,LLVM::ModuleTranslation & moduleTranslation)33759989d68SKiran Chandramohan convertOmpCritical(Operation &opInst, llvm::IRBuilderBase &builder,
33859989d68SKiran Chandramohan LLVM::ModuleTranslation &moduleTranslation) {
33959989d68SKiran Chandramohan using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
34059989d68SKiran Chandramohan auto criticalOp = cast<omp::CriticalOp>(opInst);
34159989d68SKiran Chandramohan // TODO: support error propagation in OpenMPIRBuilder and use it instead of
34259989d68SKiran Chandramohan // relying on captured variables.
34359989d68SKiran Chandramohan LogicalResult bodyGenStatus = success();
34459989d68SKiran Chandramohan
345ff289feeSMichael Kruse auto bodyGenCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP) {
34659989d68SKiran Chandramohan // CriticalOp has only one region associated with it.
34759989d68SKiran Chandramohan auto ®ion = cast<omp::CriticalOp>(opInst).getRegion();
348ff289feeSMichael Kruse builder.restoreIP(codeGenIP);
349ff289feeSMichael Kruse convertOmpOpRegions(region, "omp.critical.region", builder,
350ff289feeSMichael Kruse moduleTranslation, bodyGenStatus);
35159989d68SKiran Chandramohan };
35259989d68SKiran Chandramohan
35359989d68SKiran Chandramohan // TODO: Perform finalization actions for variables. This has to be
35459989d68SKiran Chandramohan // called for variables which have destructors/finalizers.
35559989d68SKiran Chandramohan auto finiCB = [&](InsertPointTy codeGenIP) {};
35659989d68SKiran Chandramohan
357b85cfe20SShraiysh Vaishay llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
35859989d68SKiran Chandramohan llvm::LLVMContext &llvmContext = moduleTranslation.getLLVMContext();
359c4c7e06bSShraiysh Vaishay llvm::Constant *hint = nullptr;
360c4c7e06bSShraiysh Vaishay
361c4c7e06bSShraiysh Vaishay // If it has a name, it probably has a hint too.
362c4c7e06bSShraiysh Vaishay if (criticalOp.nameAttr()) {
363c4c7e06bSShraiysh Vaishay // The verifiers in OpenMP Dialect guarentee that all the pointers are
364c4c7e06bSShraiysh Vaishay // non-null
365c4c7e06bSShraiysh Vaishay auto symbolRef = criticalOp.nameAttr().cast<SymbolRefAttr>();
366c4c7e06bSShraiysh Vaishay auto criticalDeclareOp =
367c4c7e06bSShraiysh Vaishay SymbolTable::lookupNearestSymbolFrom<omp::CriticalDeclareOp>(criticalOp,
368c4c7e06bSShraiysh Vaishay symbolRef);
369d2f0fe23SShraiysh Vaishay hint =
370d2f0fe23SShraiysh Vaishay llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvmContext),
371d2f0fe23SShraiysh Vaishay static_cast<int>(criticalDeclareOp.hint_val()));
372c4c7e06bSShraiysh Vaishay }
37359989d68SKiran Chandramohan builder.restoreIP(moduleTranslation.getOpenMPBuilder()->createCritical(
37430c67587SKazu Hirata ompLoc, bodyGenCB, finiCB, criticalOp.name().value_or(""), hint));
37559989d68SKiran Chandramohan return success();
37659989d68SKiran Chandramohan }
37759989d68SKiran Chandramohan
3788647e4c3SAlex Zinenko /// Returns a reduction declaration that corresponds to the given reduction
3798647e4c3SAlex Zinenko /// operation in the given container. Currently only supports reductions inside
3808647e4c3SAlex Zinenko /// WsLoopOp but can be easily extended.
findReductionDecl(omp::WsLoopOp container,omp::ReductionOp reduction)3818647e4c3SAlex Zinenko static omp::ReductionDeclareOp findReductionDecl(omp::WsLoopOp container,
3828647e4c3SAlex Zinenko omp::ReductionOp reduction) {
3838647e4c3SAlex Zinenko SymbolRefAttr reductionSymbol;
3848647e4c3SAlex Zinenko for (unsigned i = 0, e = container.getNumReductionVars(); i < e; ++i) {
3858647e4c3SAlex Zinenko if (container.reduction_vars()[i] != reduction.accumulator())
3868647e4c3SAlex Zinenko continue;
3878647e4c3SAlex Zinenko reductionSymbol = (*container.reductions())[i].cast<SymbolRefAttr>();
3888647e4c3SAlex Zinenko break;
3898647e4c3SAlex Zinenko }
3908647e4c3SAlex Zinenko assert(reductionSymbol &&
3918647e4c3SAlex Zinenko "reduction operation must be associated with a declaration");
3928647e4c3SAlex Zinenko
3938647e4c3SAlex Zinenko return SymbolTable::lookupNearestSymbolFrom<omp::ReductionDeclareOp>(
3948647e4c3SAlex Zinenko container, reductionSymbol);
3958647e4c3SAlex Zinenko }
3968647e4c3SAlex Zinenko
3978647e4c3SAlex Zinenko /// Populates `reductions` with reduction declarations used in the given loop.
3988647e4c3SAlex Zinenko static void
collectReductionDecls(omp::WsLoopOp loop,SmallVectorImpl<omp::ReductionDeclareOp> & reductions)3998647e4c3SAlex Zinenko collectReductionDecls(omp::WsLoopOp loop,
4008647e4c3SAlex Zinenko SmallVectorImpl<omp::ReductionDeclareOp> &reductions) {
4018647e4c3SAlex Zinenko Optional<ArrayAttr> attr = loop.reductions();
4028647e4c3SAlex Zinenko if (!attr)
4038647e4c3SAlex Zinenko return;
4048647e4c3SAlex Zinenko
4058647e4c3SAlex Zinenko reductions.reserve(reductions.size() + loop.getNumReductionVars());
4068647e4c3SAlex Zinenko for (auto symbolRef : attr->getAsRange<SymbolRefAttr>()) {
4078647e4c3SAlex Zinenko reductions.push_back(
4088647e4c3SAlex Zinenko SymbolTable::lookupNearestSymbolFrom<omp::ReductionDeclareOp>(
4098647e4c3SAlex Zinenko loop, symbolRef));
4108647e4c3SAlex Zinenko }
4118647e4c3SAlex Zinenko }
4128647e4c3SAlex Zinenko
4138647e4c3SAlex Zinenko /// Translates the blocks contained in the given region and appends them to at
4148647e4c3SAlex Zinenko /// the current insertion point of `builder`. The operations of the entry block
4158647e4c3SAlex Zinenko /// are appended to the current insertion block, which is not expected to have a
4168647e4c3SAlex Zinenko /// terminator. If set, `continuationBlockArgs` is populated with translated
4178647e4c3SAlex Zinenko /// values that correspond to the values omp.yield'ed from the region.
inlineConvertOmpRegions(Region & region,StringRef blockName,llvm::IRBuilderBase & builder,LLVM::ModuleTranslation & moduleTranslation,SmallVectorImpl<llvm::Value * > * continuationBlockArgs=nullptr)4188647e4c3SAlex Zinenko static LogicalResult inlineConvertOmpRegions(
4198647e4c3SAlex Zinenko Region ®ion, StringRef blockName, llvm::IRBuilderBase &builder,
4208647e4c3SAlex Zinenko LLVM::ModuleTranslation &moduleTranslation,
4218647e4c3SAlex Zinenko SmallVectorImpl<llvm::Value *> *continuationBlockArgs = nullptr) {
4228647e4c3SAlex Zinenko if (region.empty())
4238647e4c3SAlex Zinenko return success();
4248647e4c3SAlex Zinenko
4258647e4c3SAlex Zinenko // Special case for single-block regions that don't create additional blocks:
4268647e4c3SAlex Zinenko // insert operations without creating additional blocks.
4278647e4c3SAlex Zinenko if (llvm::hasSingleElement(region)) {
4288647e4c3SAlex Zinenko moduleTranslation.mapBlock(®ion.front(), builder.GetInsertBlock());
4298647e4c3SAlex Zinenko if (failed(moduleTranslation.convertBlock(
4308647e4c3SAlex Zinenko region.front(), /*ignoreArguments=*/true, builder)))
4318647e4c3SAlex Zinenko return failure();
4328647e4c3SAlex Zinenko
4338647e4c3SAlex Zinenko // The continuation arguments are simply the translated terminator operands.
4348647e4c3SAlex Zinenko if (continuationBlockArgs)
4358647e4c3SAlex Zinenko llvm::append_range(
4368647e4c3SAlex Zinenko *continuationBlockArgs,
4378647e4c3SAlex Zinenko moduleTranslation.lookupValues(region.front().back().getOperands()));
4388647e4c3SAlex Zinenko
4398647e4c3SAlex Zinenko // Drop the mapping that is no longer necessary so that the same region can
4408647e4c3SAlex Zinenko // be processed multiple times.
4418647e4c3SAlex Zinenko moduleTranslation.forgetMapping(region);
4428647e4c3SAlex Zinenko return success();
4438647e4c3SAlex Zinenko }
4448647e4c3SAlex Zinenko
4458647e4c3SAlex Zinenko LogicalResult bodyGenStatus = success();
4468647e4c3SAlex Zinenko SmallVector<llvm::PHINode *> phis;
447ff289feeSMichael Kruse llvm::BasicBlock *continuationBlock = convertOmpOpRegions(
448ff289feeSMichael Kruse region, blockName, builder, moduleTranslation, bodyGenStatus, &phis);
4498647e4c3SAlex Zinenko if (failed(bodyGenStatus))
4508647e4c3SAlex Zinenko return failure();
4518647e4c3SAlex Zinenko if (continuationBlockArgs)
4528647e4c3SAlex Zinenko llvm::append_range(*continuationBlockArgs, phis);
4538647e4c3SAlex Zinenko builder.SetInsertPoint(continuationBlock,
4548647e4c3SAlex Zinenko continuationBlock->getFirstInsertionPt());
4558647e4c3SAlex Zinenko return success();
4568647e4c3SAlex Zinenko }
4578647e4c3SAlex Zinenko
4588647e4c3SAlex Zinenko namespace {
4598647e4c3SAlex Zinenko /// Owning equivalents of OpenMPIRBuilder::(Atomic)ReductionGen that are used to
4608647e4c3SAlex Zinenko /// store lambdas with capture.
4618647e4c3SAlex Zinenko using OwningReductionGen = std::function<llvm::OpenMPIRBuilder::InsertPointTy(
4628647e4c3SAlex Zinenko llvm::OpenMPIRBuilder::InsertPointTy, llvm::Value *, llvm::Value *,
4638647e4c3SAlex Zinenko llvm::Value *&)>;
4648647e4c3SAlex Zinenko using OwningAtomicReductionGen =
4658647e4c3SAlex Zinenko std::function<llvm::OpenMPIRBuilder::InsertPointTy(
466d733f2c6SNikita Popov llvm::OpenMPIRBuilder::InsertPointTy, llvm::Type *, llvm::Value *,
467d733f2c6SNikita Popov llvm::Value *)>;
4688647e4c3SAlex Zinenko } // namespace
4698647e4c3SAlex Zinenko
4708647e4c3SAlex Zinenko /// Create an OpenMPIRBuilder-compatible reduction generator for the given
4718647e4c3SAlex Zinenko /// reduction declaration. The generator uses `builder` but ignores its
4728647e4c3SAlex Zinenko /// insertion point.
4738647e4c3SAlex Zinenko static OwningReductionGen
makeReductionGen(omp::ReductionDeclareOp decl,llvm::IRBuilderBase & builder,LLVM::ModuleTranslation & moduleTranslation)4748647e4c3SAlex Zinenko makeReductionGen(omp::ReductionDeclareOp decl, llvm::IRBuilderBase &builder,
4758647e4c3SAlex Zinenko LLVM::ModuleTranslation &moduleTranslation) {
4768647e4c3SAlex Zinenko // The lambda is mutable because we need access to non-const methods of decl
4778647e4c3SAlex Zinenko // (which aren't actually mutating it), and we must capture decl by-value to
4788647e4c3SAlex Zinenko // avoid the dangling reference after the parent function returns.
4798647e4c3SAlex Zinenko OwningReductionGen gen =
4808647e4c3SAlex Zinenko [&, decl](llvm::OpenMPIRBuilder::InsertPointTy insertPoint,
4818647e4c3SAlex Zinenko llvm::Value *lhs, llvm::Value *rhs,
4828647e4c3SAlex Zinenko llvm::Value *&result) mutable {
4838647e4c3SAlex Zinenko Region &reductionRegion = decl.reductionRegion();
4848647e4c3SAlex Zinenko moduleTranslation.mapValue(reductionRegion.front().getArgument(0), lhs);
4858647e4c3SAlex Zinenko moduleTranslation.mapValue(reductionRegion.front().getArgument(1), rhs);
4868647e4c3SAlex Zinenko builder.restoreIP(insertPoint);
4878647e4c3SAlex Zinenko SmallVector<llvm::Value *> phis;
4888647e4c3SAlex Zinenko if (failed(inlineConvertOmpRegions(reductionRegion,
4898647e4c3SAlex Zinenko "omp.reduction.nonatomic.body",
4908647e4c3SAlex Zinenko builder, moduleTranslation, &phis)))
4918647e4c3SAlex Zinenko return llvm::OpenMPIRBuilder::InsertPointTy();
4928647e4c3SAlex Zinenko assert(phis.size() == 1);
4938647e4c3SAlex Zinenko result = phis[0];
4948647e4c3SAlex Zinenko return builder.saveIP();
4958647e4c3SAlex Zinenko };
4968647e4c3SAlex Zinenko return gen;
4978647e4c3SAlex Zinenko }
4988647e4c3SAlex Zinenko
4998647e4c3SAlex Zinenko /// Create an OpenMPIRBuilder-compatible atomic reduction generator for the
5008647e4c3SAlex Zinenko /// given reduction declaration. The generator uses `builder` but ignores its
5018647e4c3SAlex Zinenko /// insertion point. Returns null if there is no atomic region available in the
5028647e4c3SAlex Zinenko /// reduction declaration.
5038647e4c3SAlex Zinenko static OwningAtomicReductionGen
makeAtomicReductionGen(omp::ReductionDeclareOp decl,llvm::IRBuilderBase & builder,LLVM::ModuleTranslation & moduleTranslation)5048647e4c3SAlex Zinenko makeAtomicReductionGen(omp::ReductionDeclareOp decl,
5058647e4c3SAlex Zinenko llvm::IRBuilderBase &builder,
5068647e4c3SAlex Zinenko LLVM::ModuleTranslation &moduleTranslation) {
5078647e4c3SAlex Zinenko if (decl.atomicReductionRegion().empty())
5088647e4c3SAlex Zinenko return OwningAtomicReductionGen();
5098647e4c3SAlex Zinenko
5108647e4c3SAlex Zinenko // The lambda is mutable because we need access to non-const methods of decl
5118647e4c3SAlex Zinenko // (which aren't actually mutating it), and we must capture decl by-value to
5128647e4c3SAlex Zinenko // avoid the dangling reference after the parent function returns.
5138647e4c3SAlex Zinenko OwningAtomicReductionGen atomicGen =
514d733f2c6SNikita Popov [&, decl](llvm::OpenMPIRBuilder::InsertPointTy insertPoint, llvm::Type *,
5158647e4c3SAlex Zinenko llvm::Value *lhs, llvm::Value *rhs) mutable {
5168647e4c3SAlex Zinenko Region &atomicRegion = decl.atomicReductionRegion();
5178647e4c3SAlex Zinenko moduleTranslation.mapValue(atomicRegion.front().getArgument(0), lhs);
5188647e4c3SAlex Zinenko moduleTranslation.mapValue(atomicRegion.front().getArgument(1), rhs);
5198647e4c3SAlex Zinenko builder.restoreIP(insertPoint);
5208647e4c3SAlex Zinenko SmallVector<llvm::Value *> phis;
5218647e4c3SAlex Zinenko if (failed(inlineConvertOmpRegions(atomicRegion,
5228647e4c3SAlex Zinenko "omp.reduction.atomic.body", builder,
5238647e4c3SAlex Zinenko moduleTranslation, &phis)))
5248647e4c3SAlex Zinenko return llvm::OpenMPIRBuilder::InsertPointTy();
5258647e4c3SAlex Zinenko assert(phis.empty());
5268647e4c3SAlex Zinenko return builder.saveIP();
5278647e4c3SAlex Zinenko };
5288647e4c3SAlex Zinenko return atomicGen;
5298647e4c3SAlex Zinenko }
5308647e4c3SAlex Zinenko
531b37e5187SPeixin-Qiao /// Converts an OpenMP 'ordered' operation into LLVM IR using OpenMPIRBuilder.
532b37e5187SPeixin-Qiao static LogicalResult
convertOmpOrdered(Operation & opInst,llvm::IRBuilderBase & builder,LLVM::ModuleTranslation & moduleTranslation)533b37e5187SPeixin-Qiao convertOmpOrdered(Operation &opInst, llvm::IRBuilderBase &builder,
534b37e5187SPeixin-Qiao LLVM::ModuleTranslation &moduleTranslation) {
535b37e5187SPeixin-Qiao auto orderedOp = cast<omp::OrderedOp>(opInst);
536b37e5187SPeixin-Qiao
537aae51255SMogball omp::ClauseDepend dependType = *orderedOp.depend_type_val();
538b37e5187SPeixin-Qiao bool isDependSource = dependType == omp::ClauseDepend::dependsource;
5396d5fc1e3SKazu Hirata unsigned numLoops = *orderedOp.num_loops_val();
540b37e5187SPeixin-Qiao SmallVector<llvm::Value *> vecValues =
541b37e5187SPeixin-Qiao moduleTranslation.lookupValues(orderedOp.depend_vec_vars());
542b37e5187SPeixin-Qiao
543b37e5187SPeixin-Qiao size_t indexVecValues = 0;
544b37e5187SPeixin-Qiao while (indexVecValues < vecValues.size()) {
545b37e5187SPeixin-Qiao SmallVector<llvm::Value *> storeValues;
546b37e5187SPeixin-Qiao storeValues.reserve(numLoops);
547b37e5187SPeixin-Qiao for (unsigned i = 0; i < numLoops; i++) {
548b37e5187SPeixin-Qiao storeValues.push_back(vecValues[indexVecValues]);
549b37e5187SPeixin-Qiao indexVecValues++;
550b37e5187SPeixin-Qiao }
551c082ca16SMichael Kruse llvm::OpenMPIRBuilder::InsertPointTy allocaIP =
552c082ca16SMichael Kruse findAllocaInsertPoint(builder, moduleTranslation);
553c082ca16SMichael Kruse llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
554b37e5187SPeixin-Qiao builder.restoreIP(moduleTranslation.getOpenMPBuilder()->createOrderedDepend(
555c082ca16SMichael Kruse ompLoc, allocaIP, numLoops, storeValues, ".cnt.addr", isDependSource));
556b37e5187SPeixin-Qiao }
557b37e5187SPeixin-Qiao return success();
558b37e5187SPeixin-Qiao }
559b37e5187SPeixin-Qiao
560b37e5187SPeixin-Qiao /// Converts an OpenMP 'ordered_region' operation into LLVM IR using
561b37e5187SPeixin-Qiao /// OpenMPIRBuilder.
562b37e5187SPeixin-Qiao static LogicalResult
convertOmpOrderedRegion(Operation & opInst,llvm::IRBuilderBase & builder,LLVM::ModuleTranslation & moduleTranslation)563b37e5187SPeixin-Qiao convertOmpOrderedRegion(Operation &opInst, llvm::IRBuilderBase &builder,
564b37e5187SPeixin-Qiao LLVM::ModuleTranslation &moduleTranslation) {
565b37e5187SPeixin-Qiao using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
566b37e5187SPeixin-Qiao auto orderedRegionOp = cast<omp::OrderedRegionOp>(opInst);
567b37e5187SPeixin-Qiao
568b37e5187SPeixin-Qiao // TODO: The code generation for ordered simd directive is not supported yet.
569b37e5187SPeixin-Qiao if (orderedRegionOp.simd())
570b37e5187SPeixin-Qiao return failure();
571b37e5187SPeixin-Qiao
572b37e5187SPeixin-Qiao // TODO: support error propagation in OpenMPIRBuilder and use it instead of
573b37e5187SPeixin-Qiao // relying on captured variables.
574b37e5187SPeixin-Qiao LogicalResult bodyGenStatus = success();
575b37e5187SPeixin-Qiao
576ff289feeSMichael Kruse auto bodyGenCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP) {
577b37e5187SPeixin-Qiao // OrderedOp has only one region associated with it.
578b37e5187SPeixin-Qiao auto ®ion = cast<omp::OrderedRegionOp>(opInst).getRegion();
579ff289feeSMichael Kruse builder.restoreIP(codeGenIP);
580ff289feeSMichael Kruse convertOmpOpRegions(region, "omp.ordered.region", builder,
581ff289feeSMichael Kruse moduleTranslation, bodyGenStatus);
582b37e5187SPeixin-Qiao };
583b37e5187SPeixin-Qiao
584b37e5187SPeixin-Qiao // TODO: Perform finalization actions for variables. This has to be
585b37e5187SPeixin-Qiao // called for variables which have destructors/finalizers.
586b37e5187SPeixin-Qiao auto finiCB = [&](InsertPointTy codeGenIP) {};
587b37e5187SPeixin-Qiao
588b85cfe20SShraiysh Vaishay llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
589b37e5187SPeixin-Qiao builder.restoreIP(
590b37e5187SPeixin-Qiao moduleTranslation.getOpenMPBuilder()->createOrderedThreadsSimd(
591b37e5187SPeixin-Qiao ompLoc, bodyGenCB, finiCB, !orderedRegionOp.simd()));
592b37e5187SPeixin-Qiao return bodyGenStatus;
593b37e5187SPeixin-Qiao }
594b37e5187SPeixin-Qiao
5953425b1bcSShraiysh Vaishay static LogicalResult
convertOmpSections(Operation & opInst,llvm::IRBuilderBase & builder,LLVM::ModuleTranslation & moduleTranslation)5963425b1bcSShraiysh Vaishay convertOmpSections(Operation &opInst, llvm::IRBuilderBase &builder,
5973425b1bcSShraiysh Vaishay LLVM::ModuleTranslation &moduleTranslation) {
5983425b1bcSShraiysh Vaishay using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
5993425b1bcSShraiysh Vaishay using StorableBodyGenCallbackTy =
6003425b1bcSShraiysh Vaishay llvm::OpenMPIRBuilder::StorableBodyGenCallbackTy;
6013425b1bcSShraiysh Vaishay
6023425b1bcSShraiysh Vaishay auto sectionsOp = cast<omp::SectionsOp>(opInst);
6033425b1bcSShraiysh Vaishay
6043425b1bcSShraiysh Vaishay // TODO: Support the following clauses: private, firstprivate, lastprivate,
6053425b1bcSShraiysh Vaishay // reduction, allocate
6065ee500acSShraiysh Vaishay if (!sectionsOp.reduction_vars().empty() || sectionsOp.reductions() ||
6073425b1bcSShraiysh Vaishay !sectionsOp.allocate_vars().empty() ||
6083425b1bcSShraiysh Vaishay !sectionsOp.allocators_vars().empty())
6093425b1bcSShraiysh Vaishay return emitError(sectionsOp.getLoc())
6105ee500acSShraiysh Vaishay << "reduction and allocate clauses are not supported for sections "
6115ee500acSShraiysh Vaishay "construct";
6123425b1bcSShraiysh Vaishay
6133425b1bcSShraiysh Vaishay LogicalResult bodyGenStatus = success();
6143425b1bcSShraiysh Vaishay SmallVector<StorableBodyGenCallbackTy> sectionCBs;
6153425b1bcSShraiysh Vaishay
6163425b1bcSShraiysh Vaishay for (Operation &op : *sectionsOp.region().begin()) {
6173425b1bcSShraiysh Vaishay auto sectionOp = dyn_cast<omp::SectionOp>(op);
6183425b1bcSShraiysh Vaishay if (!sectionOp) // omp.terminator
6193425b1bcSShraiysh Vaishay continue;
6203425b1bcSShraiysh Vaishay
6213425b1bcSShraiysh Vaishay Region ®ion = sectionOp.region();
6223425b1bcSShraiysh Vaishay auto sectionCB = [®ion, &builder, &moduleTranslation, &bodyGenStatus](
623ff289feeSMichael Kruse InsertPointTy allocaIP, InsertPointTy codeGenIP) {
6243425b1bcSShraiysh Vaishay builder.restoreIP(codeGenIP);
625ff289feeSMichael Kruse convertOmpOpRegions(region, "omp.section.region", builder,
626ff289feeSMichael Kruse moduleTranslation, bodyGenStatus);
6273425b1bcSShraiysh Vaishay };
6283425b1bcSShraiysh Vaishay sectionCBs.push_back(sectionCB);
6293425b1bcSShraiysh Vaishay }
6303425b1bcSShraiysh Vaishay
6313425b1bcSShraiysh Vaishay // No sections within omp.sections operation - skip generation. This situation
6323425b1bcSShraiysh Vaishay // is only possible if there is only a terminator operation inside the
6333425b1bcSShraiysh Vaishay // sections operation
6345a1f6077SMehdi Amini if (sectionCBs.empty())
6353425b1bcSShraiysh Vaishay return success();
6363425b1bcSShraiysh Vaishay
6373425b1bcSShraiysh Vaishay assert(isa<omp::SectionOp>(*sectionsOp.region().op_begin()));
6383425b1bcSShraiysh Vaishay
6393425b1bcSShraiysh Vaishay // TODO: Perform appropriate actions according to the data-sharing
6403425b1bcSShraiysh Vaishay // attribute (shared, private, firstprivate, ...) of variables.
6413425b1bcSShraiysh Vaishay // Currently defaults to shared.
6423425b1bcSShraiysh Vaishay auto privCB = [&](InsertPointTy, InsertPointTy codeGenIP, llvm::Value &,
6433425b1bcSShraiysh Vaishay llvm::Value &vPtr,
6443425b1bcSShraiysh Vaishay llvm::Value *&replacementValue) -> InsertPointTy {
6453425b1bcSShraiysh Vaishay replacementValue = &vPtr;
6463425b1bcSShraiysh Vaishay return codeGenIP;
6473425b1bcSShraiysh Vaishay };
6483425b1bcSShraiysh Vaishay
6493425b1bcSShraiysh Vaishay // TODO: Perform finalization actions for variables. This has to be
6503425b1bcSShraiysh Vaishay // called for variables which have destructors/finalizers.
6513425b1bcSShraiysh Vaishay auto finiCB = [&](InsertPointTy codeGenIP) {};
6523425b1bcSShraiysh Vaishay
653c082ca16SMichael Kruse llvm::OpenMPIRBuilder::InsertPointTy allocaIP =
654c082ca16SMichael Kruse findAllocaInsertPoint(builder, moduleTranslation);
655b85cfe20SShraiysh Vaishay llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
6563425b1bcSShraiysh Vaishay builder.restoreIP(moduleTranslation.getOpenMPBuilder()->createSections(
657c082ca16SMichael Kruse ompLoc, allocaIP, sectionCBs, privCB, finiCB, false,
658c082ca16SMichael Kruse sectionsOp.nowait()));
6593425b1bcSShraiysh Vaishay return bodyGenStatus;
6603425b1bcSShraiysh Vaishay }
6613425b1bcSShraiysh Vaishay
6623c0d4708SShraiysh Vaishay /// Converts an OpenMP single construct into LLVM IR using OpenMPIRBuilder.
6633c0d4708SShraiysh Vaishay static LogicalResult
convertOmpSingle(omp::SingleOp & singleOp,llvm::IRBuilderBase & builder,LLVM::ModuleTranslation & moduleTranslation)6643c0d4708SShraiysh Vaishay convertOmpSingle(omp::SingleOp &singleOp, llvm::IRBuilderBase &builder,
6653c0d4708SShraiysh Vaishay LLVM::ModuleTranslation &moduleTranslation) {
6663c0d4708SShraiysh Vaishay using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
6673c0d4708SShraiysh Vaishay llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
6683c0d4708SShraiysh Vaishay LogicalResult bodyGenStatus = success();
669ff289feeSMichael Kruse auto bodyCB = [&](InsertPointTy allocaIP, InsertPointTy codegenIP) {
670ff289feeSMichael Kruse builder.restoreIP(codegenIP);
671ff289feeSMichael Kruse convertOmpOpRegions(singleOp.region(), "omp.single.region", builder,
6723c0d4708SShraiysh Vaishay moduleTranslation, bodyGenStatus);
6733c0d4708SShraiysh Vaishay };
6743c0d4708SShraiysh Vaishay auto finiCB = [&](InsertPointTy codeGenIP) {};
6753c0d4708SShraiysh Vaishay builder.restoreIP(moduleTranslation.getOpenMPBuilder()->createSingle(
6768722c12cSShraiysh Vaishay ompLoc, bodyCB, finiCB, singleOp.nowait(), /*DidIt=*/nullptr));
6773c0d4708SShraiysh Vaishay return bodyGenStatus;
6783c0d4708SShraiysh Vaishay }
6793c0d4708SShraiysh Vaishay
680fdf505f3SShraiysh Vaishay /// Converts an OpenMP task construct into LLVM IR using OpenMPIRBuilder.
681fdf505f3SShraiysh Vaishay static LogicalResult
convertOmpTaskOp(omp::TaskOp taskOp,llvm::IRBuilderBase & builder,LLVM::ModuleTranslation & moduleTranslation)682fdf505f3SShraiysh Vaishay convertOmpTaskOp(omp::TaskOp taskOp, llvm::IRBuilderBase &builder,
683fdf505f3SShraiysh Vaishay LLVM::ModuleTranslation &moduleTranslation) {
684fdf505f3SShraiysh Vaishay using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
685fdf505f3SShraiysh Vaishay LogicalResult bodyGenStatus = success();
686fdf505f3SShraiysh Vaishay if (taskOp.if_expr() || taskOp.final_expr() || taskOp.untiedAttr() ||
687fdf505f3SShraiysh Vaishay taskOp.mergeableAttr() || taskOp.in_reductions() || taskOp.priority() ||
688fdf505f3SShraiysh Vaishay !taskOp.allocate_vars().empty()) {
689fdf505f3SShraiysh Vaishay return taskOp.emitError("unhandled clauses for translation to LLVM IR");
690fdf505f3SShraiysh Vaishay }
691fdf505f3SShraiysh Vaishay auto bodyCB = [&](InsertPointTy allocaIP, InsertPointTy codegenIP) {
692fdf505f3SShraiysh Vaishay builder.restoreIP(codegenIP);
693fdf505f3SShraiysh Vaishay convertOmpOpRegions(taskOp.region(), "omp.task.region", builder,
694fdf505f3SShraiysh Vaishay moduleTranslation, bodyGenStatus);
695fdf505f3SShraiysh Vaishay };
696fdf505f3SShraiysh Vaishay llvm::OpenMPIRBuilder::InsertPointTy allocaIP =
697fdf505f3SShraiysh Vaishay findAllocaInsertPoint(builder, moduleTranslation);
698fdf505f3SShraiysh Vaishay llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
699fdf505f3SShraiysh Vaishay builder.restoreIP(moduleTranslation.getOpenMPBuilder()->createTask(
700fdf505f3SShraiysh Vaishay ompLoc, allocaIP, bodyCB, !taskOp.untied()));
701fdf505f3SShraiysh Vaishay return bodyGenStatus;
702fdf505f3SShraiysh Vaishay }
703fdf505f3SShraiysh Vaishay
70466900b3eSAlex Zinenko /// Converts an OpenMP workshare loop into LLVM IR using OpenMPIRBuilder.
70519db802eSAlex Zinenko static LogicalResult
convertOmpWsLoop(Operation & opInst,llvm::IRBuilderBase & builder,LLVM::ModuleTranslation & moduleTranslation)70619db802eSAlex Zinenko convertOmpWsLoop(Operation &opInst, llvm::IRBuilderBase &builder,
70766900b3eSAlex Zinenko LLVM::ModuleTranslation &moduleTranslation) {
70866900b3eSAlex Zinenko auto loop = cast<omp::WsLoopOp>(opInst);
70966900b3eSAlex Zinenko // TODO: this should be in the op verifier instead.
71066900b3eSAlex Zinenko if (loop.lowerBound().empty())
71166900b3eSAlex Zinenko return failure();
71266900b3eSAlex Zinenko
7137280f4b2SMats Petersson // Static is the default.
71430c67587SKazu Hirata auto schedule = loop.schedule_val().value_or(omp::ClauseScheduleKind::Static);
71566900b3eSAlex Zinenko
7168647e4c3SAlex Zinenko // Find the loop configuration.
7178647e4c3SAlex Zinenko llvm::Value *step = moduleTranslation.lookupValue(loop.step()[0]);
7188647e4c3SAlex Zinenko llvm::Type *ivType = step->getType();
719a56a7d99SPeixin-Qiao llvm::Value *chunk = nullptr;
720a56a7d99SPeixin-Qiao if (loop.schedule_chunk_var()) {
721a56a7d99SPeixin-Qiao llvm::Value *chunkVar =
722a56a7d99SPeixin-Qiao moduleTranslation.lookupValue(loop.schedule_chunk_var());
7231795f8cdSPeixin-Qiao chunk = builder.CreateSExtOrTrunc(chunkVar, ivType);
724a56a7d99SPeixin-Qiao }
7258647e4c3SAlex Zinenko
7268647e4c3SAlex Zinenko SmallVector<omp::ReductionDeclareOp> reductionDecls;
7278647e4c3SAlex Zinenko collectReductionDecls(loop, reductionDecls);
7288647e4c3SAlex Zinenko llvm::OpenMPIRBuilder::InsertPointTy allocaIP =
7298647e4c3SAlex Zinenko findAllocaInsertPoint(builder, moduleTranslation);
7308647e4c3SAlex Zinenko
7318647e4c3SAlex Zinenko // Allocate space for privatized reduction variables.
7328647e4c3SAlex Zinenko SmallVector<llvm::Value *> privateReductionVariables;
7338647e4c3SAlex Zinenko DenseMap<Value, llvm::Value *> reductionVariableMap;
7348647e4c3SAlex Zinenko unsigned numReductions = loop.getNumReductionVars();
7358647e4c3SAlex Zinenko privateReductionVariables.reserve(numReductions);
7368647e4c3SAlex Zinenko if (numReductions != 0) {
7378647e4c3SAlex Zinenko llvm::IRBuilderBase::InsertPointGuard guard(builder);
7388647e4c3SAlex Zinenko builder.restoreIP(allocaIP);
7398647e4c3SAlex Zinenko for (unsigned i = 0; i < numReductions; ++i) {
7408647e4c3SAlex Zinenko auto reductionType =
7418647e4c3SAlex Zinenko loop.reduction_vars()[i].getType().cast<LLVM::LLVMPointerType>();
7428647e4c3SAlex Zinenko llvm::Value *var = builder.CreateAlloca(
7438647e4c3SAlex Zinenko moduleTranslation.convertType(reductionType.getElementType()));
7448647e4c3SAlex Zinenko privateReductionVariables.push_back(var);
7458647e4c3SAlex Zinenko reductionVariableMap.try_emplace(loop.reduction_vars()[i], var);
7468647e4c3SAlex Zinenko }
7478647e4c3SAlex Zinenko }
7488647e4c3SAlex Zinenko
7498647e4c3SAlex Zinenko // Store the mapping between reduction variables and their private copies on
7508647e4c3SAlex Zinenko // ModuleTranslation stack. It can be then recovered when translating
7518647e4c3SAlex Zinenko // omp.reduce operations in a separate call.
7528647e4c3SAlex Zinenko LLVM::ModuleTranslation::SaveStack<OpenMPVarMappingStackFrame> mappingGuard(
7538647e4c3SAlex Zinenko moduleTranslation, reductionVariableMap);
7548647e4c3SAlex Zinenko
7558647e4c3SAlex Zinenko // Before the loop, store the initial values of reductions into reduction
7568647e4c3SAlex Zinenko // variables. Although this could be done after allocas, we don't want to mess
7578647e4c3SAlex Zinenko // up with the alloca insertion point.
7588647e4c3SAlex Zinenko for (unsigned i = 0; i < numReductions; ++i) {
7598647e4c3SAlex Zinenko SmallVector<llvm::Value *> phis;
7608647e4c3SAlex Zinenko if (failed(inlineConvertOmpRegions(reductionDecls[i].initializerRegion(),
7618647e4c3SAlex Zinenko "omp.reduction.neutral", builder,
7628647e4c3SAlex Zinenko moduleTranslation, &phis)))
7638647e4c3SAlex Zinenko return failure();
7648647e4c3SAlex Zinenko assert(phis.size() == 1 && "expected one value to be yielded from the "
7658647e4c3SAlex Zinenko "reduction neutral element declaration region");
7668647e4c3SAlex Zinenko builder.CreateStore(phis[0], privateReductionVariables[i]);
7678647e4c3SAlex Zinenko }
7688647e4c3SAlex Zinenko
76966900b3eSAlex Zinenko // Set up the source location value for OpenMP runtime.
770b85cfe20SShraiysh Vaishay llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
77166900b3eSAlex Zinenko
772c4c10309SAlex Zinenko // Generator of the canonical loop body.
77366900b3eSAlex Zinenko // TODO: support error propagation in OpenMPIRBuilder and use it instead of
77466900b3eSAlex Zinenko // relying on captured variables.
775c4c10309SAlex Zinenko SmallVector<llvm::CanonicalLoopInfo *> loopInfos;
776c4c10309SAlex Zinenko SmallVector<llvm::OpenMPIRBuilder::InsertPointTy> bodyInsertPoints;
77766900b3eSAlex Zinenko LogicalResult bodyGenStatus = success();
77866900b3eSAlex Zinenko auto bodyGen = [&](llvm::OpenMPIRBuilder::InsertPointTy ip, llvm::Value *iv) {
77966900b3eSAlex Zinenko // Make sure further conversions know about the induction variable.
780c4c10309SAlex Zinenko moduleTranslation.mapValue(
781c4c10309SAlex Zinenko loop.getRegion().front().getArgument(loopInfos.size()), iv);
78266900b3eSAlex Zinenko
783c4c10309SAlex Zinenko // Capture the body insertion point for use in nested loops. BodyIP of the
784c4c10309SAlex Zinenko // CanonicalLoopInfo always points to the beginning of the entry block of
785c4c10309SAlex Zinenko // the body.
786c4c10309SAlex Zinenko bodyInsertPoints.push_back(ip);
787c4c10309SAlex Zinenko
788c4c10309SAlex Zinenko if (loopInfos.size() != loop.getNumLoops() - 1)
789c4c10309SAlex Zinenko return;
790c4c10309SAlex Zinenko
791c4c10309SAlex Zinenko // Convert the body of the loop.
792ff289feeSMichael Kruse builder.restoreIP(ip);
793ff289feeSMichael Kruse convertOmpOpRegions(loop.region(), "omp.wsloop.region", builder,
794ff289feeSMichael Kruse moduleTranslation, bodyGenStatus);
79566900b3eSAlex Zinenko };
79666900b3eSAlex Zinenko
79766900b3eSAlex Zinenko // Delegate actual loop construction to the OpenMP IRBuilder.
79866900b3eSAlex Zinenko // TODO: this currently assumes WsLoop is semantically similar to SCF loop,
79966900b3eSAlex Zinenko // i.e. it has a positive step, uses signed integer semantics. Reconsider
80066900b3eSAlex Zinenko // this code when WsLoop clearly supports more cases.
801c4c10309SAlex Zinenko llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder();
802c4c10309SAlex Zinenko for (unsigned i = 0, e = loop.getNumLoops(); i < e; ++i) {
803c4c10309SAlex Zinenko llvm::Value *lowerBound =
804c4c10309SAlex Zinenko moduleTranslation.lookupValue(loop.lowerBound()[i]);
805c4c10309SAlex Zinenko llvm::Value *upperBound =
806c4c10309SAlex Zinenko moduleTranslation.lookupValue(loop.upperBound()[i]);
807c4c10309SAlex Zinenko llvm::Value *step = moduleTranslation.lookupValue(loop.step()[i]);
808c4c10309SAlex Zinenko
809c4c10309SAlex Zinenko // Make sure loop trip count are emitted in the preheader of the outermost
810c4c10309SAlex Zinenko // loop at the latest so that they are all available for the new collapsed
811c4c10309SAlex Zinenko // loop will be created below.
812c4c10309SAlex Zinenko llvm::OpenMPIRBuilder::LocationDescription loc = ompLoc;
813c4c10309SAlex Zinenko llvm::OpenMPIRBuilder::InsertPointTy computeIP = ompLoc.IP;
814c4c10309SAlex Zinenko if (i != 0) {
815b85cfe20SShraiysh Vaishay loc = llvm::OpenMPIRBuilder::LocationDescription(bodyInsertPoints.back());
816c4c10309SAlex Zinenko computeIP = loopInfos.front()->getPreheaderIP();
817c4c10309SAlex Zinenko }
818c4c10309SAlex Zinenko loopInfos.push_back(ompBuilder->createCanonicalLoop(
819c4c10309SAlex Zinenko loc, bodyGen, lowerBound, upperBound, step,
820c4c10309SAlex Zinenko /*IsSigned=*/true, loop.inclusive(), computeIP));
821c4c10309SAlex Zinenko
82266900b3eSAlex Zinenko if (failed(bodyGenStatus))
82366900b3eSAlex Zinenko return failure();
824c4c10309SAlex Zinenko }
82566900b3eSAlex Zinenko
826c4c10309SAlex Zinenko // Collapse loops. Store the insertion point because LoopInfos may get
827c4c10309SAlex Zinenko // invalidated.
828c4c10309SAlex Zinenko llvm::IRBuilderBase::InsertPoint afterIP = loopInfos.front()->getAfterIP();
829c4c10309SAlex Zinenko llvm::CanonicalLoopInfo *loopInfo =
830b85cfe20SShraiysh Vaishay ompBuilder->collapseLoops(ompLoc.DL, loopInfos, {});
831c4c10309SAlex Zinenko
8328647e4c3SAlex Zinenko allocaIP = findAllocaInsertPoint(builder, moduleTranslation);
83330238c36SMats Petersson
8342d92ee97SMichael Kruse // TODO: Handle doacross loops when the ordered clause has a parameter.
8350916d96dSKazu Hirata bool isOrdered = loop.ordered_val().has_value();
8362d92ee97SMichael Kruse Optional<omp::ScheduleModifier> scheduleModifier = loop.schedule_modifier();
83730238c36SMats Petersson bool isSimd = loop.simd_modifier();
83830238c36SMats Petersson
8392d92ee97SMichael Kruse ompBuilder->applyWorkshareLoop(
8402d92ee97SMichael Kruse ompLoc.DL, loopInfo, allocaIP, !loop.nowait(),
8412d92ee97SMichael Kruse convertToScheduleKind(schedule), chunk, isSimd,
8422d92ee97SMichael Kruse scheduleModifier == omp::ScheduleModifier::monotonic,
8432d92ee97SMichael Kruse scheduleModifier == omp::ScheduleModifier::nonmonotonic, isOrdered);
84466900b3eSAlex Zinenko
845c4c10309SAlex Zinenko // Continue building IR after the loop. Note that the LoopInfo returned by
846c4c10309SAlex Zinenko // `collapseLoops` points inside the outermost loop and is intended for
847c4c10309SAlex Zinenko // potential further loop transformations. Use the insertion point stored
848c4c10309SAlex Zinenko // before collapsing loops instead.
849517c3aeeSMats Petersson builder.restoreIP(afterIP);
8508647e4c3SAlex Zinenko
8518647e4c3SAlex Zinenko // Process the reductions if required.
8528647e4c3SAlex Zinenko if (numReductions == 0)
8538647e4c3SAlex Zinenko return success();
8548647e4c3SAlex Zinenko
8558647e4c3SAlex Zinenko // Create the reduction generators. We need to own them here because
8568647e4c3SAlex Zinenko // ReductionInfo only accepts references to the generators.
8578647e4c3SAlex Zinenko SmallVector<OwningReductionGen> owningReductionGens;
8588647e4c3SAlex Zinenko SmallVector<OwningAtomicReductionGen> owningAtomicReductionGens;
8598647e4c3SAlex Zinenko for (unsigned i = 0; i < numReductions; ++i) {
8608647e4c3SAlex Zinenko owningReductionGens.push_back(
8618647e4c3SAlex Zinenko makeReductionGen(reductionDecls[i], builder, moduleTranslation));
8628647e4c3SAlex Zinenko owningAtomicReductionGens.push_back(
8638647e4c3SAlex Zinenko makeAtomicReductionGen(reductionDecls[i], builder, moduleTranslation));
8648647e4c3SAlex Zinenko }
8658647e4c3SAlex Zinenko
8668647e4c3SAlex Zinenko // Collect the reduction information.
8678647e4c3SAlex Zinenko SmallVector<llvm::OpenMPIRBuilder::ReductionInfo> reductionInfos;
8688647e4c3SAlex Zinenko reductionInfos.reserve(numReductions);
8698647e4c3SAlex Zinenko for (unsigned i = 0; i < numReductions; ++i) {
8708647e4c3SAlex Zinenko llvm::OpenMPIRBuilder::AtomicReductionGenTy atomicGen = nullptr;
8718647e4c3SAlex Zinenko if (owningAtomicReductionGens[i])
8728647e4c3SAlex Zinenko atomicGen = owningAtomicReductionGens[i];
873ea043ea1SNikita Popov auto reductionType =
874ea043ea1SNikita Popov loop.reduction_vars()[i].getType().cast<LLVM::LLVMPointerType>();
875d733f2c6SNikita Popov llvm::Value *variable =
876d733f2c6SNikita Popov moduleTranslation.lookupValue(loop.reduction_vars()[i]);
877ea043ea1SNikita Popov reductionInfos.push_back(
878ea043ea1SNikita Popov {moduleTranslation.convertType(reductionType.getElementType()),
879ea043ea1SNikita Popov variable, privateReductionVariables[i], owningReductionGens[i],
880ea043ea1SNikita Popov atomicGen});
8818647e4c3SAlex Zinenko }
8828647e4c3SAlex Zinenko
8838647e4c3SAlex Zinenko // The call to createReductions below expects the block to have a
8848647e4c3SAlex Zinenko // terminator. Create an unreachable instruction to serve as terminator
8858647e4c3SAlex Zinenko // and remove it later.
8868647e4c3SAlex Zinenko llvm::UnreachableInst *tempTerminator = builder.CreateUnreachable();
8878647e4c3SAlex Zinenko builder.SetInsertPoint(tempTerminator);
8888647e4c3SAlex Zinenko llvm::OpenMPIRBuilder::InsertPointTy contInsertPoint =
8898647e4c3SAlex Zinenko ompBuilder->createReductions(builder.saveIP(), allocaIP, reductionInfos,
8908647e4c3SAlex Zinenko loop.nowait());
8918647e4c3SAlex Zinenko if (!contInsertPoint.getBlock())
8928647e4c3SAlex Zinenko return loop->emitOpError() << "failed to convert reductions";
8938647e4c3SAlex Zinenko auto nextInsertionPoint =
8948647e4c3SAlex Zinenko ompBuilder->createBarrier(contInsertPoint, llvm::omp::OMPD_for);
8958647e4c3SAlex Zinenko tempTerminator->eraseFromParent();
8968647e4c3SAlex Zinenko builder.restoreIP(nextInsertionPoint);
8978647e4c3SAlex Zinenko
8988647e4c3SAlex Zinenko return success();
8998647e4c3SAlex Zinenko }
9008647e4c3SAlex Zinenko
9010e9198c3SArnamoy Bhattacharyya /// Converts an OpenMP simd loop into LLVM IR using OpenMPIRBuilder.
9020e9198c3SArnamoy Bhattacharyya static LogicalResult
convertOmpSimdLoop(Operation & opInst,llvm::IRBuilderBase & builder,LLVM::ModuleTranslation & moduleTranslation)9030e9198c3SArnamoy Bhattacharyya convertOmpSimdLoop(Operation &opInst, llvm::IRBuilderBase &builder,
9040e9198c3SArnamoy Bhattacharyya LLVM::ModuleTranslation &moduleTranslation) {
9050e9198c3SArnamoy Bhattacharyya auto loop = cast<omp::SimdLoopOp>(opInst);
9060e9198c3SArnamoy Bhattacharyya
9070e9198c3SArnamoy Bhattacharyya llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
9080e9198c3SArnamoy Bhattacharyya
9090e9198c3SArnamoy Bhattacharyya // Generator of the canonical loop body.
9100e9198c3SArnamoy Bhattacharyya // TODO: support error propagation in OpenMPIRBuilder and use it instead of
9110e9198c3SArnamoy Bhattacharyya // relying on captured variables.
9120e9198c3SArnamoy Bhattacharyya SmallVector<llvm::CanonicalLoopInfo *> loopInfos;
9130e9198c3SArnamoy Bhattacharyya SmallVector<llvm::OpenMPIRBuilder::InsertPointTy> bodyInsertPoints;
9140e9198c3SArnamoy Bhattacharyya LogicalResult bodyGenStatus = success();
9152c915e3bSDominik Adamski
9162c915e3bSDominik Adamski // TODO: The code generation for if clause is not supported yet.
9172c915e3bSDominik Adamski if (loop.if_expr())
9182c915e3bSDominik Adamski return failure();
9192c915e3bSDominik Adamski
9200e9198c3SArnamoy Bhattacharyya auto bodyGen = [&](llvm::OpenMPIRBuilder::InsertPointTy ip, llvm::Value *iv) {
9210e9198c3SArnamoy Bhattacharyya // Make sure further conversions know about the induction variable.
9220e9198c3SArnamoy Bhattacharyya moduleTranslation.mapValue(
9230e9198c3SArnamoy Bhattacharyya loop.getRegion().front().getArgument(loopInfos.size()), iv);
9240e9198c3SArnamoy Bhattacharyya
9250e9198c3SArnamoy Bhattacharyya // Capture the body insertion point for use in nested loops. BodyIP of the
9260e9198c3SArnamoy Bhattacharyya // CanonicalLoopInfo always points to the beginning of the entry block of
9270e9198c3SArnamoy Bhattacharyya // the body.
9280e9198c3SArnamoy Bhattacharyya bodyInsertPoints.push_back(ip);
9290e9198c3SArnamoy Bhattacharyya
9300e9198c3SArnamoy Bhattacharyya if (loopInfos.size() != loop.getNumLoops() - 1)
9310e9198c3SArnamoy Bhattacharyya return;
9320e9198c3SArnamoy Bhattacharyya
9330e9198c3SArnamoy Bhattacharyya // Convert the body of the loop.
934ff289feeSMichael Kruse builder.restoreIP(ip);
935ff289feeSMichael Kruse convertOmpOpRegions(loop.region(), "omp.simdloop.region", builder,
936ff289feeSMichael Kruse moduleTranslation, bodyGenStatus);
9370e9198c3SArnamoy Bhattacharyya };
9380e9198c3SArnamoy Bhattacharyya
9390e9198c3SArnamoy Bhattacharyya // Delegate actual loop construction to the OpenMP IRBuilder.
9400e9198c3SArnamoy Bhattacharyya // TODO: this currently assumes SimdLoop is semantically similar to SCF loop,
9410e9198c3SArnamoy Bhattacharyya // i.e. it has a positive step, uses signed integer semantics. Reconsider
9420e9198c3SArnamoy Bhattacharyya // this code when SimdLoop clearly supports more cases.
9430e9198c3SArnamoy Bhattacharyya llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder();
9440e9198c3SArnamoy Bhattacharyya for (unsigned i = 0, e = loop.getNumLoops(); i < e; ++i) {
9450e9198c3SArnamoy Bhattacharyya llvm::Value *lowerBound =
9460e9198c3SArnamoy Bhattacharyya moduleTranslation.lookupValue(loop.lowerBound()[i]);
9470e9198c3SArnamoy Bhattacharyya llvm::Value *upperBound =
9480e9198c3SArnamoy Bhattacharyya moduleTranslation.lookupValue(loop.upperBound()[i]);
9490e9198c3SArnamoy Bhattacharyya llvm::Value *step = moduleTranslation.lookupValue(loop.step()[i]);
9500e9198c3SArnamoy Bhattacharyya
9510e9198c3SArnamoy Bhattacharyya // Make sure loop trip count are emitted in the preheader of the outermost
9520e9198c3SArnamoy Bhattacharyya // loop at the latest so that they are all available for the new collapsed
9530e9198c3SArnamoy Bhattacharyya // loop will be created below.
9540e9198c3SArnamoy Bhattacharyya llvm::OpenMPIRBuilder::LocationDescription loc = ompLoc;
9550e9198c3SArnamoy Bhattacharyya llvm::OpenMPIRBuilder::InsertPointTy computeIP = ompLoc.IP;
9560e9198c3SArnamoy Bhattacharyya if (i != 0) {
9570e9198c3SArnamoy Bhattacharyya loc = llvm::OpenMPIRBuilder::LocationDescription(bodyInsertPoints.back(),
9580e9198c3SArnamoy Bhattacharyya ompLoc.DL);
9590e9198c3SArnamoy Bhattacharyya computeIP = loopInfos.front()->getPreheaderIP();
9600e9198c3SArnamoy Bhattacharyya }
9610e9198c3SArnamoy Bhattacharyya loopInfos.push_back(ompBuilder->createCanonicalLoop(
9620e9198c3SArnamoy Bhattacharyya loc, bodyGen, lowerBound, upperBound, step,
9630e9198c3SArnamoy Bhattacharyya /*IsSigned=*/true, /*Inclusive=*/true, computeIP));
9640e9198c3SArnamoy Bhattacharyya
9650e9198c3SArnamoy Bhattacharyya if (failed(bodyGenStatus))
9660e9198c3SArnamoy Bhattacharyya return failure();
9670e9198c3SArnamoy Bhattacharyya }
9680e9198c3SArnamoy Bhattacharyya
9690e9198c3SArnamoy Bhattacharyya // Collapse loops.
9700e9198c3SArnamoy Bhattacharyya llvm::IRBuilderBase::InsertPoint afterIP = loopInfos.front()->getAfterIP();
9710e9198c3SArnamoy Bhattacharyya llvm::CanonicalLoopInfo *loopInfo =
9720e9198c3SArnamoy Bhattacharyya ompBuilder->collapseLoops(ompLoc.DL, loopInfos, {});
9730e9198c3SArnamoy Bhattacharyya
974ac892c70SPrabhdeep Singh Soni ompBuilder->applySimd(loopInfo, nullptr);
9750e9198c3SArnamoy Bhattacharyya
9760e9198c3SArnamoy Bhattacharyya builder.restoreIP(afterIP);
9770e9198c3SArnamoy Bhattacharyya return success();
9780e9198c3SArnamoy Bhattacharyya }
9790e9198c3SArnamoy Bhattacharyya
980217570b0SLorenzo Chelini /// Convert an Atomic Ordering attribute to llvm::AtomicOrdering.
981aae51255SMogball llvm::AtomicOrdering
convertAtomicOrdering(Optional<omp::ClauseMemoryOrderKind> ao)982aae51255SMogball convertAtomicOrdering(Optional<omp::ClauseMemoryOrderKind> ao) {
983aae51255SMogball if (!ao)
98431cf42bdSShraiysh Vaishay return llvm::AtomicOrdering::Monotonic; // Default Memory Ordering
98531cf42bdSShraiysh Vaishay
986aae51255SMogball switch (*ao) {
9877c385c4bSShraiysh Vaishay case omp::ClauseMemoryOrderKind::Seq_cst:
988aae51255SMogball return llvm::AtomicOrdering::SequentiallyConsistent;
9897c385c4bSShraiysh Vaishay case omp::ClauseMemoryOrderKind::Acq_rel:
990aae51255SMogball return llvm::AtomicOrdering::AcquireRelease;
9917c385c4bSShraiysh Vaishay case omp::ClauseMemoryOrderKind::Acquire:
992aae51255SMogball return llvm::AtomicOrdering::Acquire;
9937c385c4bSShraiysh Vaishay case omp::ClauseMemoryOrderKind::Release:
994aae51255SMogball return llvm::AtomicOrdering::Release;
9957c385c4bSShraiysh Vaishay case omp::ClauseMemoryOrderKind::Relaxed:
996aae51255SMogball return llvm::AtomicOrdering::Monotonic;
997aae51255SMogball }
998217570b0SLorenzo Chelini llvm_unreachable("Unknown ClauseMemoryOrderKind kind");
99931cf42bdSShraiysh Vaishay }
100031cf42bdSShraiysh Vaishay
1001217570b0SLorenzo Chelini /// Convert omp.atomic.read operation to LLVM IR.
100231cf42bdSShraiysh Vaishay static LogicalResult
convertOmpAtomicRead(Operation & opInst,llvm::IRBuilderBase & builder,LLVM::ModuleTranslation & moduleTranslation)100331cf42bdSShraiysh Vaishay convertOmpAtomicRead(Operation &opInst, llvm::IRBuilderBase &builder,
100431cf42bdSShraiysh Vaishay LLVM::ModuleTranslation &moduleTranslation) {
100531cf42bdSShraiysh Vaishay
100631cf42bdSShraiysh Vaishay auto readOp = cast<omp::AtomicReadOp>(opInst);
100731cf42bdSShraiysh Vaishay llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder();
100831cf42bdSShraiysh Vaishay
1009b85cfe20SShraiysh Vaishay llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
1010b85cfe20SShraiysh Vaishay
1011d2f0fe23SShraiysh Vaishay llvm::AtomicOrdering AO = convertAtomicOrdering(readOp.memory_order_val());
1012a8586b57SShraiysh Vaishay llvm::Value *x = moduleTranslation.lookupValue(readOp.x());
1013f2c2a31dSNikita Popov Type xTy = readOp.x().getType().cast<omp::PointerLikeType>().getElementType();
1014a8586b57SShraiysh Vaishay llvm::Value *v = moduleTranslation.lookupValue(readOp.v());
1015f2c2a31dSNikita Popov Type vTy = readOp.v().getType().cast<omp::PointerLikeType>().getElementType();
1016f2c2a31dSNikita Popov llvm::OpenMPIRBuilder::AtomicOpValue V = {
1017f2c2a31dSNikita Popov v, moduleTranslation.convertType(vTy), false, false};
1018f2c2a31dSNikita Popov llvm::OpenMPIRBuilder::AtomicOpValue X = {
1019f2c2a31dSNikita Popov x, moduleTranslation.convertType(xTy), false, false};
1020a8586b57SShraiysh Vaishay builder.restoreIP(ompBuilder->createAtomicRead(ompLoc, X, V, AO));
102131cf42bdSShraiysh Vaishay return success();
102231cf42bdSShraiysh Vaishay }
102331cf42bdSShraiysh Vaishay
10246bcb4c44SShraiysh Vaishay /// Converts an omp.atomic.write operation to LLVM IR.
10256bcb4c44SShraiysh Vaishay static LogicalResult
convertOmpAtomicWrite(Operation & opInst,llvm::IRBuilderBase & builder,LLVM::ModuleTranslation & moduleTranslation)10266bcb4c44SShraiysh Vaishay convertOmpAtomicWrite(Operation &opInst, llvm::IRBuilderBase &builder,
10276bcb4c44SShraiysh Vaishay LLVM::ModuleTranslation &moduleTranslation) {
10286bcb4c44SShraiysh Vaishay auto writeOp = cast<omp::AtomicWriteOp>(opInst);
10296bcb4c44SShraiysh Vaishay llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder();
10306bcb4c44SShraiysh Vaishay
1031b85cfe20SShraiysh Vaishay llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
1032d2f0fe23SShraiysh Vaishay llvm::AtomicOrdering ao = convertAtomicOrdering(writeOp.memory_order_val());
10336bcb4c44SShraiysh Vaishay llvm::Value *expr = moduleTranslation.lookupValue(writeOp.value());
10346bcb4c44SShraiysh Vaishay llvm::Value *dest = moduleTranslation.lookupValue(writeOp.address());
1035f2c2a31dSNikita Popov llvm::Type *ty = moduleTranslation.convertType(writeOp.value().getType());
1036f2c2a31dSNikita Popov llvm::OpenMPIRBuilder::AtomicOpValue x = {dest, ty, /*isSigned=*/false,
10376bcb4c44SShraiysh Vaishay /*isVolatile=*/false};
10386bcb4c44SShraiysh Vaishay builder.restoreIP(ompBuilder->createAtomicWrite(ompLoc, x, expr, ao));
10396bcb4c44SShraiysh Vaishay return success();
10406bcb4c44SShraiysh Vaishay }
10416bcb4c44SShraiysh Vaishay
10426dd54da5SShraiysh Vaishay /// Converts an LLVM dialect binary operation to the corresponding enum value
10436dd54da5SShraiysh Vaishay /// for `atomicrmw` supported binary operation.
convertBinOpToAtomic(Operation & op)10446dd54da5SShraiysh Vaishay llvm::AtomicRMWInst::BinOp convertBinOpToAtomic(Operation &op) {
10456dd54da5SShraiysh Vaishay return llvm::TypeSwitch<Operation *, llvm::AtomicRMWInst::BinOp>(&op)
10466dd54da5SShraiysh Vaishay .Case([&](LLVM::AddOp) { return llvm::AtomicRMWInst::BinOp::Add; })
10476dd54da5SShraiysh Vaishay .Case([&](LLVM::SubOp) { return llvm::AtomicRMWInst::BinOp::Sub; })
10486dd54da5SShraiysh Vaishay .Case([&](LLVM::AndOp) { return llvm::AtomicRMWInst::BinOp::And; })
10496dd54da5SShraiysh Vaishay .Case([&](LLVM::OrOp) { return llvm::AtomicRMWInst::BinOp::Or; })
10506dd54da5SShraiysh Vaishay .Case([&](LLVM::XOrOp) { return llvm::AtomicRMWInst::BinOp::Xor; })
10516dd54da5SShraiysh Vaishay .Case([&](LLVM::UMaxOp) { return llvm::AtomicRMWInst::BinOp::UMax; })
10526dd54da5SShraiysh Vaishay .Case([&](LLVM::UMinOp) { return llvm::AtomicRMWInst::BinOp::UMin; })
10536dd54da5SShraiysh Vaishay .Case([&](LLVM::FAddOp) { return llvm::AtomicRMWInst::BinOp::FAdd; })
10546dd54da5SShraiysh Vaishay .Case([&](LLVM::FSubOp) { return llvm::AtomicRMWInst::BinOp::FSub; })
10556dd54da5SShraiysh Vaishay .Default(llvm::AtomicRMWInst::BinOp::BAD_BINOP);
10566dd54da5SShraiysh Vaishay }
10576dd54da5SShraiysh Vaishay
10586dd54da5SShraiysh Vaishay /// Converts an OpenMP atomic update operation using OpenMPIRBuilder.
10596dd54da5SShraiysh Vaishay static LogicalResult
convertOmpAtomicUpdate(omp::AtomicUpdateOp & opInst,llvm::IRBuilderBase & builder,LLVM::ModuleTranslation & moduleTranslation)10606dd54da5SShraiysh Vaishay convertOmpAtomicUpdate(omp::AtomicUpdateOp &opInst,
10616dd54da5SShraiysh Vaishay llvm::IRBuilderBase &builder,
10626dd54da5SShraiysh Vaishay LLVM::ModuleTranslation &moduleTranslation) {
10636dd54da5SShraiysh Vaishay llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder();
10646dd54da5SShraiysh Vaishay
10656dd54da5SShraiysh Vaishay // Convert values and types.
10666dd54da5SShraiysh Vaishay auto &innerOpList = opInst.region().front().getOperations();
10676dd54da5SShraiysh Vaishay if (innerOpList.size() != 2)
10686dd54da5SShraiysh Vaishay return opInst.emitError("exactly two operations are allowed inside an "
10696dd54da5SShraiysh Vaishay "atomic update region while lowering to LLVM IR");
10706dd54da5SShraiysh Vaishay
10716dd54da5SShraiysh Vaishay Operation &innerUpdateOp = innerOpList.front();
10726dd54da5SShraiysh Vaishay
10736dd54da5SShraiysh Vaishay if (innerUpdateOp.getNumOperands() != 2 ||
10746dd54da5SShraiysh Vaishay !llvm::is_contained(innerUpdateOp.getOperands(),
10756dd54da5SShraiysh Vaishay opInst.getRegion().getArgument(0)))
10766dd54da5SShraiysh Vaishay return opInst.emitError(
10776dd54da5SShraiysh Vaishay "the update operation inside the region must be a binary operation and "
10786dd54da5SShraiysh Vaishay "that update operation must have the region argument as an operand");
10796dd54da5SShraiysh Vaishay
10806dd54da5SShraiysh Vaishay llvm::AtomicRMWInst::BinOp binop = convertBinOpToAtomic(innerUpdateOp);
10816dd54da5SShraiysh Vaishay
10826dd54da5SShraiysh Vaishay bool isXBinopExpr =
10836dd54da5SShraiysh Vaishay innerUpdateOp.getNumOperands() > 0 &&
10846dd54da5SShraiysh Vaishay innerUpdateOp.getOperand(0) == opInst.getRegion().getArgument(0);
10856dd54da5SShraiysh Vaishay
10866dd54da5SShraiysh Vaishay mlir::Value mlirExpr = (isXBinopExpr ? innerUpdateOp.getOperand(1)
10876dd54da5SShraiysh Vaishay : innerUpdateOp.getOperand(0));
10886dd54da5SShraiysh Vaishay llvm::Value *llvmExpr = moduleTranslation.lookupValue(mlirExpr);
10896dd54da5SShraiysh Vaishay llvm::Value *llvmX = moduleTranslation.lookupValue(opInst.x());
10906dd54da5SShraiysh Vaishay LLVM::LLVMPointerType mlirXType =
10916dd54da5SShraiysh Vaishay opInst.x().getType().cast<LLVM::LLVMPointerType>();
10926dd54da5SShraiysh Vaishay llvm::Type *llvmXElementType =
10936dd54da5SShraiysh Vaishay moduleTranslation.convertType(mlirXType.getElementType());
10946dd54da5SShraiysh Vaishay llvm::OpenMPIRBuilder::AtomicOpValue llvmAtomicX = {llvmX, llvmXElementType,
10956dd54da5SShraiysh Vaishay /*isSigned=*/false,
10966dd54da5SShraiysh Vaishay /*isVolatile=*/false};
10976dd54da5SShraiysh Vaishay
10986dd54da5SShraiysh Vaishay llvm::AtomicOrdering atomicOrdering =
10996dd54da5SShraiysh Vaishay convertAtomicOrdering(opInst.memory_order_val());
11006dd54da5SShraiysh Vaishay
11016dd54da5SShraiysh Vaishay // Generate update code.
11026dd54da5SShraiysh Vaishay LogicalResult updateGenStatus = success();
11036dd54da5SShraiysh Vaishay auto updateFn = [&opInst, &moduleTranslation, &updateGenStatus](
11046dd54da5SShraiysh Vaishay llvm::Value *atomicx,
11056dd54da5SShraiysh Vaishay llvm::IRBuilder<> &builder) -> llvm::Value * {
11066dd54da5SShraiysh Vaishay Block &bb = *opInst.region().begin();
11076dd54da5SShraiysh Vaishay moduleTranslation.mapValue(*opInst.region().args_begin(), atomicx);
11086dd54da5SShraiysh Vaishay moduleTranslation.mapBlock(&bb, builder.GetInsertBlock());
11096dd54da5SShraiysh Vaishay if (failed(moduleTranslation.convertBlock(bb, true, builder))) {
11106dd54da5SShraiysh Vaishay updateGenStatus = (opInst.emitError()
11116dd54da5SShraiysh Vaishay << "unable to convert update operation to llvm IR");
11126dd54da5SShraiysh Vaishay return nullptr;
11136dd54da5SShraiysh Vaishay }
11146dd54da5SShraiysh Vaishay omp::YieldOp yieldop = dyn_cast<omp::YieldOp>(bb.getTerminator());
11156dd54da5SShraiysh Vaishay assert(yieldop && yieldop.results().size() == 1 &&
11166dd54da5SShraiysh Vaishay "terminator must be omp.yield op and it must have exactly one "
11176dd54da5SShraiysh Vaishay "argument");
11186dd54da5SShraiysh Vaishay return moduleTranslation.lookupValue(yieldop.results()[0]);
11196dd54da5SShraiysh Vaishay };
11206dd54da5SShraiysh Vaishay
11216dd54da5SShraiysh Vaishay // Handle ambiguous alloca, if any.
11226dd54da5SShraiysh Vaishay auto allocaIP = findAllocaInsertPoint(builder, moduleTranslation);
1123c082ca16SMichael Kruse llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
11246dd54da5SShraiysh Vaishay builder.restoreIP(ompBuilder->createAtomicUpdate(
1125c082ca16SMichael Kruse ompLoc, allocaIP, llvmAtomicX, llvmExpr, atomicOrdering, binop, updateFn,
1126c082ca16SMichael Kruse isXBinopExpr));
11276dd54da5SShraiysh Vaishay return updateGenStatus;
11286dd54da5SShraiysh Vaishay }
11296dd54da5SShraiysh Vaishay
113031486a9fSShraiysh Vaishay static LogicalResult
convertOmpAtomicCapture(omp::AtomicCaptureOp atomicCaptureOp,llvm::IRBuilderBase & builder,LLVM::ModuleTranslation & moduleTranslation)113131486a9fSShraiysh Vaishay convertOmpAtomicCapture(omp::AtomicCaptureOp atomicCaptureOp,
113231486a9fSShraiysh Vaishay llvm::IRBuilderBase &builder,
113331486a9fSShraiysh Vaishay LLVM::ModuleTranslation &moduleTranslation) {
113431486a9fSShraiysh Vaishay llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder();
113531486a9fSShraiysh Vaishay mlir::Value mlirExpr;
113631486a9fSShraiysh Vaishay bool isXBinopExpr = false, isPostfixUpdate = false;
113731486a9fSShraiysh Vaishay llvm::AtomicRMWInst::BinOp binop = llvm::AtomicRMWInst::BinOp::BAD_BINOP;
113831486a9fSShraiysh Vaishay
113931486a9fSShraiysh Vaishay omp::AtomicUpdateOp atomicUpdateOp = atomicCaptureOp.getAtomicUpdateOp();
114031486a9fSShraiysh Vaishay omp::AtomicWriteOp atomicWriteOp = atomicCaptureOp.getAtomicWriteOp();
114131486a9fSShraiysh Vaishay
114231486a9fSShraiysh Vaishay assert((atomicUpdateOp || atomicWriteOp) &&
114331486a9fSShraiysh Vaishay "internal op must be an atomic.update or atomic.write op");
114431486a9fSShraiysh Vaishay
114531486a9fSShraiysh Vaishay if (atomicWriteOp) {
114631486a9fSShraiysh Vaishay isPostfixUpdate = true;
114731486a9fSShraiysh Vaishay mlirExpr = atomicWriteOp.value();
114831486a9fSShraiysh Vaishay } else {
114931486a9fSShraiysh Vaishay isPostfixUpdate = atomicCaptureOp.getSecondOp() ==
115031486a9fSShraiysh Vaishay atomicCaptureOp.getAtomicUpdateOp().getOperation();
115131486a9fSShraiysh Vaishay auto &innerOpList = atomicUpdateOp.region().front().getOperations();
115231486a9fSShraiysh Vaishay if (innerOpList.size() != 2)
115331486a9fSShraiysh Vaishay return atomicUpdateOp.emitError(
115431486a9fSShraiysh Vaishay "exactly two operations are allowed inside an "
115531486a9fSShraiysh Vaishay "atomic update region while lowering to LLVM IR");
115631486a9fSShraiysh Vaishay Operation *innerUpdateOp = atomicUpdateOp.getFirstOp();
115731486a9fSShraiysh Vaishay if (innerUpdateOp->getNumOperands() != 2 ||
115831486a9fSShraiysh Vaishay !llvm::is_contained(innerUpdateOp->getOperands(),
115931486a9fSShraiysh Vaishay atomicUpdateOp.getRegion().getArgument(0)))
116031486a9fSShraiysh Vaishay return atomicUpdateOp.emitError(
116131486a9fSShraiysh Vaishay "the update operation inside the region must be a binary operation "
116231486a9fSShraiysh Vaishay "and that update operation must have the region argument as an "
116331486a9fSShraiysh Vaishay "operand");
116431486a9fSShraiysh Vaishay binop = convertBinOpToAtomic(*innerUpdateOp);
116531486a9fSShraiysh Vaishay
116631486a9fSShraiysh Vaishay isXBinopExpr = innerUpdateOp->getOperand(0) ==
116731486a9fSShraiysh Vaishay atomicUpdateOp.getRegion().getArgument(0);
116831486a9fSShraiysh Vaishay
116931486a9fSShraiysh Vaishay mlirExpr = (isXBinopExpr ? innerUpdateOp->getOperand(1)
117031486a9fSShraiysh Vaishay : innerUpdateOp->getOperand(0));
117131486a9fSShraiysh Vaishay }
117231486a9fSShraiysh Vaishay
117331486a9fSShraiysh Vaishay llvm::Value *llvmExpr = moduleTranslation.lookupValue(mlirExpr);
117431486a9fSShraiysh Vaishay llvm::Value *llvmX =
117531486a9fSShraiysh Vaishay moduleTranslation.lookupValue(atomicCaptureOp.getAtomicReadOp().x());
117631486a9fSShraiysh Vaishay llvm::Value *llvmV =
117731486a9fSShraiysh Vaishay moduleTranslation.lookupValue(atomicCaptureOp.getAtomicReadOp().v());
117831486a9fSShraiysh Vaishay auto mlirXType = atomicCaptureOp.getAtomicReadOp()
117931486a9fSShraiysh Vaishay .x()
118031486a9fSShraiysh Vaishay .getType()
118131486a9fSShraiysh Vaishay .cast<LLVM::LLVMPointerType>();
118231486a9fSShraiysh Vaishay llvm::Type *llvmXElementType =
118331486a9fSShraiysh Vaishay moduleTranslation.convertType(mlirXType.getElementType());
118431486a9fSShraiysh Vaishay llvm::OpenMPIRBuilder::AtomicOpValue llvmAtomicX = {llvmX, llvmXElementType,
118531486a9fSShraiysh Vaishay /*isSigned=*/false,
118631486a9fSShraiysh Vaishay /*isVolatile=*/false};
118731486a9fSShraiysh Vaishay llvm::OpenMPIRBuilder::AtomicOpValue llvmAtomicV = {llvmV, llvmXElementType,
118831486a9fSShraiysh Vaishay /*isSigned=*/false,
118931486a9fSShraiysh Vaishay /*isVolatile=*/false};
119031486a9fSShraiysh Vaishay
119131486a9fSShraiysh Vaishay llvm::AtomicOrdering atomicOrdering =
119231486a9fSShraiysh Vaishay convertAtomicOrdering(atomicCaptureOp.memory_order_val());
119331486a9fSShraiysh Vaishay
119431486a9fSShraiysh Vaishay LogicalResult updateGenStatus = success();
119531486a9fSShraiysh Vaishay auto updateFn = [&](llvm::Value *atomicx,
119631486a9fSShraiysh Vaishay llvm::IRBuilder<> &builder) -> llvm::Value * {
119731486a9fSShraiysh Vaishay if (atomicWriteOp)
119831486a9fSShraiysh Vaishay return moduleTranslation.lookupValue(atomicWriteOp.value());
119931486a9fSShraiysh Vaishay Block &bb = *atomicUpdateOp.region().begin();
120031486a9fSShraiysh Vaishay moduleTranslation.mapValue(*atomicUpdateOp.region().args_begin(), atomicx);
120131486a9fSShraiysh Vaishay moduleTranslation.mapBlock(&bb, builder.GetInsertBlock());
120231486a9fSShraiysh Vaishay if (failed(moduleTranslation.convertBlock(bb, true, builder))) {
120331486a9fSShraiysh Vaishay updateGenStatus = (atomicUpdateOp.emitError()
120431486a9fSShraiysh Vaishay << "unable to convert update operation to llvm IR");
120531486a9fSShraiysh Vaishay return nullptr;
120631486a9fSShraiysh Vaishay }
120731486a9fSShraiysh Vaishay omp::YieldOp yieldop = dyn_cast<omp::YieldOp>(bb.getTerminator());
120831486a9fSShraiysh Vaishay assert(yieldop && yieldop.results().size() == 1 &&
120931486a9fSShraiysh Vaishay "terminator must be omp.yield op and it must have exactly one "
121031486a9fSShraiysh Vaishay "argument");
121131486a9fSShraiysh Vaishay return moduleTranslation.lookupValue(yieldop.results()[0]);
121231486a9fSShraiysh Vaishay };
1213c082ca16SMichael Kruse
121431486a9fSShraiysh Vaishay // Handle ambiguous alloca, if any.
121531486a9fSShraiysh Vaishay auto allocaIP = findAllocaInsertPoint(builder, moduleTranslation);
1216c082ca16SMichael Kruse llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
121731486a9fSShraiysh Vaishay builder.restoreIP(ompBuilder->createAtomicCapture(
1218c082ca16SMichael Kruse ompLoc, allocaIP, llvmAtomicX, llvmAtomicV, llvmExpr, atomicOrdering,
1219c082ca16SMichael Kruse binop, updateFn, atomicUpdateOp, isPostfixUpdate, isXBinopExpr));
122031486a9fSShraiysh Vaishay return updateGenStatus;
122131486a9fSShraiysh Vaishay }
122231486a9fSShraiysh Vaishay
12238647e4c3SAlex Zinenko /// Converts an OpenMP reduction operation using OpenMPIRBuilder. Expects the
12248647e4c3SAlex Zinenko /// mapping between reduction variables and their private equivalents to have
12258647e4c3SAlex Zinenko /// been stored on the ModuleTranslation stack. Currently only supports
12268647e4c3SAlex Zinenko /// reduction within WsLoopOp, but can be easily extended.
12278647e4c3SAlex Zinenko static LogicalResult
convertOmpReductionOp(omp::ReductionOp reductionOp,llvm::IRBuilderBase & builder,LLVM::ModuleTranslation & moduleTranslation)12288647e4c3SAlex Zinenko convertOmpReductionOp(omp::ReductionOp reductionOp,
12298647e4c3SAlex Zinenko llvm::IRBuilderBase &builder,
12308647e4c3SAlex Zinenko LLVM::ModuleTranslation &moduleTranslation) {
12318647e4c3SAlex Zinenko // Find the declaration that corresponds to the reduction op.
12328647e4c3SAlex Zinenko auto reductionContainer = reductionOp->getParentOfType<omp::WsLoopOp>();
12338647e4c3SAlex Zinenko omp::ReductionDeclareOp declaration =
12348647e4c3SAlex Zinenko findReductionDecl(reductionContainer, reductionOp);
12358647e4c3SAlex Zinenko assert(declaration && "could not find reduction declaration");
12368647e4c3SAlex Zinenko
12378647e4c3SAlex Zinenko // Retrieve the mapping between reduction variables and their private
12388647e4c3SAlex Zinenko // equivalents.
12398647e4c3SAlex Zinenko const DenseMap<Value, llvm::Value *> *reductionVariableMap = nullptr;
12408647e4c3SAlex Zinenko moduleTranslation.stackWalk<OpenMPVarMappingStackFrame>(
12418647e4c3SAlex Zinenko [&](const OpenMPVarMappingStackFrame &frame) {
12428647e4c3SAlex Zinenko reductionVariableMap = &frame.mapping;
12438647e4c3SAlex Zinenko return WalkResult::interrupt();
12448647e4c3SAlex Zinenko });
12458647e4c3SAlex Zinenko assert(reductionVariableMap && "couldn't find private reduction variables");
12468647e4c3SAlex Zinenko
12478647e4c3SAlex Zinenko // Translate the reduction operation by emitting the body of the corresponding
12488647e4c3SAlex Zinenko // reduction declaration.
12498647e4c3SAlex Zinenko Region &reductionRegion = declaration.reductionRegion();
12508647e4c3SAlex Zinenko llvm::Value *privateReductionVar =
12518647e4c3SAlex Zinenko reductionVariableMap->lookup(reductionOp.accumulator());
12528647e4c3SAlex Zinenko llvm::Value *reductionVal = builder.CreateLoad(
12538647e4c3SAlex Zinenko moduleTranslation.convertType(reductionOp.operand().getType()),
12548647e4c3SAlex Zinenko privateReductionVar);
12558647e4c3SAlex Zinenko
12568647e4c3SAlex Zinenko moduleTranslation.mapValue(reductionRegion.front().getArgument(0),
12578647e4c3SAlex Zinenko reductionVal);
12588647e4c3SAlex Zinenko moduleTranslation.mapValue(
12598647e4c3SAlex Zinenko reductionRegion.front().getArgument(1),
12608647e4c3SAlex Zinenko moduleTranslation.lookupValue(reductionOp.operand()));
12618647e4c3SAlex Zinenko
12628647e4c3SAlex Zinenko SmallVector<llvm::Value *> phis;
12638647e4c3SAlex Zinenko if (failed(inlineConvertOmpRegions(reductionRegion, "omp.reduction.body",
12648647e4c3SAlex Zinenko builder, moduleTranslation, &phis)))
12658647e4c3SAlex Zinenko return failure();
12668647e4c3SAlex Zinenko assert(phis.size() == 1 && "expected one value to be yielded from "
12678647e4c3SAlex Zinenko "the reduction body declaration region");
12688647e4c3SAlex Zinenko builder.CreateStore(phis[0], privateReductionVar);
126966900b3eSAlex Zinenko return success();
127066900b3eSAlex Zinenko }
127166900b3eSAlex Zinenko
1272139c5b8aSPeixin-Qiao /// Converts an OpenMP Threadprivate operation into LLVM IR using
1273139c5b8aSPeixin-Qiao /// OpenMPIRBuilder.
1274139c5b8aSPeixin-Qiao static LogicalResult
convertOmpThreadprivate(Operation & opInst,llvm::IRBuilderBase & builder,LLVM::ModuleTranslation & moduleTranslation)1275139c5b8aSPeixin-Qiao convertOmpThreadprivate(Operation &opInst, llvm::IRBuilderBase &builder,
1276139c5b8aSPeixin-Qiao LLVM::ModuleTranslation &moduleTranslation) {
1277139c5b8aSPeixin-Qiao llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
1278139c5b8aSPeixin-Qiao auto threadprivateOp = cast<omp::ThreadprivateOp>(opInst);
1279139c5b8aSPeixin-Qiao
1280139c5b8aSPeixin-Qiao Value symAddr = threadprivateOp.sym_addr();
12812d633542SMehdi Amini auto *symOp = symAddr.getDefiningOp();
1282139c5b8aSPeixin-Qiao if (!isa<LLVM::AddressOfOp>(symOp))
1283139c5b8aSPeixin-Qiao return opInst.emitError("Addressing symbol not found");
1284139c5b8aSPeixin-Qiao LLVM::AddressOfOp addressOfOp = dyn_cast<LLVM::AddressOfOp>(symOp);
1285139c5b8aSPeixin-Qiao
1286139c5b8aSPeixin-Qiao LLVM::GlobalOp global = addressOfOp.getGlobal();
1287139c5b8aSPeixin-Qiao llvm::GlobalValue *globalValue = moduleTranslation.lookupGlobal(global);
1288139c5b8aSPeixin-Qiao llvm::Value *data =
1289139c5b8aSPeixin-Qiao builder.CreateBitCast(globalValue, builder.getInt8PtrTy());
1290139c5b8aSPeixin-Qiao llvm::Type *type = globalValue->getValueType();
1291139c5b8aSPeixin-Qiao llvm::TypeSize typeSize =
1292139c5b8aSPeixin-Qiao builder.GetInsertBlock()->getModule()->getDataLayout().getTypeStoreSize(
1293139c5b8aSPeixin-Qiao type);
1294139c5b8aSPeixin-Qiao llvm::ConstantInt *size = builder.getInt64(typeSize.getFixedSize());
1295139c5b8aSPeixin-Qiao llvm::StringRef suffix = llvm::StringRef(".cache", 6);
12968608ed14SMehdi Amini std::string cacheName = (Twine(global.getSymName()).concat(suffix)).str();
1297139c5b8aSPeixin-Qiao // Emit runtime function and bitcast its type (i8*) to real data type.
1298139c5b8aSPeixin-Qiao llvm::Value *callInst =
1299139c5b8aSPeixin-Qiao moduleTranslation.getOpenMPBuilder()->createCachedThreadPrivate(
1300139c5b8aSPeixin-Qiao ompLoc, data, size, cacheName);
1301139c5b8aSPeixin-Qiao llvm::Value *result = builder.CreateBitCast(callInst, globalValue->getType());
1302139c5b8aSPeixin-Qiao moduleTranslation.mapValue(opInst.getResult(0), result);
1303139c5b8aSPeixin-Qiao return success();
1304139c5b8aSPeixin-Qiao }
1305139c5b8aSPeixin-Qiao
130619db802eSAlex Zinenko namespace {
130719db802eSAlex Zinenko
130819db802eSAlex Zinenko /// Implementation of the dialect interface that converts operations belonging
130919db802eSAlex Zinenko /// to the OpenMP dialect to LLVM IR.
131019db802eSAlex Zinenko class OpenMPDialectLLVMIRTranslationInterface
131119db802eSAlex Zinenko : public LLVMTranslationDialectInterface {
131219db802eSAlex Zinenko public:
131319db802eSAlex Zinenko using LLVMTranslationDialectInterface::LLVMTranslationDialectInterface;
131419db802eSAlex Zinenko
131519db802eSAlex Zinenko /// Translates the given operation to LLVM IR using the provided IR builder
131619db802eSAlex Zinenko /// and saving the state in `moduleTranslation`.
131719db802eSAlex Zinenko LogicalResult
131819db802eSAlex Zinenko convertOperation(Operation *op, llvm::IRBuilderBase &builder,
131919db802eSAlex Zinenko LLVM::ModuleTranslation &moduleTranslation) const final;
132019db802eSAlex Zinenko };
132119db802eSAlex Zinenko
1322be0a7e9fSMehdi Amini } // namespace
132319db802eSAlex Zinenko
132466900b3eSAlex Zinenko /// Given an OpenMP MLIR operation, create the corresponding LLVM IR
132566900b3eSAlex Zinenko /// (including OpenMP runtime calls).
convertOperation(Operation * op,llvm::IRBuilderBase & builder,LLVM::ModuleTranslation & moduleTranslation) const132619db802eSAlex Zinenko LogicalResult OpenMPDialectLLVMIRTranslationInterface::convertOperation(
132766900b3eSAlex Zinenko Operation *op, llvm::IRBuilderBase &builder,
132866900b3eSAlex Zinenko LLVM::ModuleTranslation &moduleTranslation) const {
132966900b3eSAlex Zinenko
133066900b3eSAlex Zinenko llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder();
133166900b3eSAlex Zinenko
133266900b3eSAlex Zinenko return llvm::TypeSwitch<Operation *, LogicalResult>(op)
133366900b3eSAlex Zinenko .Case([&](omp::BarrierOp) {
133466900b3eSAlex Zinenko ompBuilder->createBarrier(builder.saveIP(), llvm::omp::OMPD_barrier);
133566900b3eSAlex Zinenko return success();
133666900b3eSAlex Zinenko })
133766900b3eSAlex Zinenko .Case([&](omp::TaskwaitOp) {
133866900b3eSAlex Zinenko ompBuilder->createTaskwait(builder.saveIP());
133966900b3eSAlex Zinenko return success();
134066900b3eSAlex Zinenko })
134166900b3eSAlex Zinenko .Case([&](omp::TaskyieldOp) {
134266900b3eSAlex Zinenko ompBuilder->createTaskyield(builder.saveIP());
134366900b3eSAlex Zinenko return success();
134466900b3eSAlex Zinenko })
134566900b3eSAlex Zinenko .Case([&](omp::FlushOp) {
134666900b3eSAlex Zinenko // No support in Openmp runtime function (__kmpc_flush) to accept
134766900b3eSAlex Zinenko // the argument list.
134866900b3eSAlex Zinenko // OpenMP standard states the following:
134966900b3eSAlex Zinenko // "An implementation may implement a flush with a list by ignoring
135066900b3eSAlex Zinenko // the list, and treating it the same as a flush without a list."
135166900b3eSAlex Zinenko //
135266900b3eSAlex Zinenko // The argument list is discarded so that, flush with a list is treated
135366900b3eSAlex Zinenko // same as a flush without a list.
135466900b3eSAlex Zinenko ompBuilder->createFlush(builder.saveIP());
135566900b3eSAlex Zinenko return success();
135666900b3eSAlex Zinenko })
1357aae51255SMogball .Case([&](omp::ParallelOp op) {
1358aae51255SMogball return convertOmpParallel(op, builder, moduleTranslation);
135966900b3eSAlex Zinenko })
13608647e4c3SAlex Zinenko .Case([&](omp::ReductionOp reductionOp) {
13618647e4c3SAlex Zinenko return convertOmpReductionOp(reductionOp, builder, moduleTranslation);
13628647e4c3SAlex Zinenko })
136366900b3eSAlex Zinenko .Case([&](omp::MasterOp) {
136466900b3eSAlex Zinenko return convertOmpMaster(*op, builder, moduleTranslation);
136566900b3eSAlex Zinenko })
136659989d68SKiran Chandramohan .Case([&](omp::CriticalOp) {
136759989d68SKiran Chandramohan return convertOmpCritical(*op, builder, moduleTranslation);
136859989d68SKiran Chandramohan })
1369b37e5187SPeixin-Qiao .Case([&](omp::OrderedRegionOp) {
1370b37e5187SPeixin-Qiao return convertOmpOrderedRegion(*op, builder, moduleTranslation);
1371b37e5187SPeixin-Qiao })
1372b37e5187SPeixin-Qiao .Case([&](omp::OrderedOp) {
1373b37e5187SPeixin-Qiao return convertOmpOrdered(*op, builder, moduleTranslation);
1374b37e5187SPeixin-Qiao })
137566900b3eSAlex Zinenko .Case([&](omp::WsLoopOp) {
137666900b3eSAlex Zinenko return convertOmpWsLoop(*op, builder, moduleTranslation);
137766900b3eSAlex Zinenko })
13780e9198c3SArnamoy Bhattacharyya .Case([&](omp::SimdLoopOp) {
13790e9198c3SArnamoy Bhattacharyya return convertOmpSimdLoop(*op, builder, moduleTranslation);
13800e9198c3SArnamoy Bhattacharyya })
138131cf42bdSShraiysh Vaishay .Case([&](omp::AtomicReadOp) {
138231cf42bdSShraiysh Vaishay return convertOmpAtomicRead(*op, builder, moduleTranslation);
138331cf42bdSShraiysh Vaishay })
13846bcb4c44SShraiysh Vaishay .Case([&](omp::AtomicWriteOp) {
13856bcb4c44SShraiysh Vaishay return convertOmpAtomicWrite(*op, builder, moduleTranslation);
13866bcb4c44SShraiysh Vaishay })
13876dd54da5SShraiysh Vaishay .Case([&](omp::AtomicUpdateOp op) {
13886dd54da5SShraiysh Vaishay return convertOmpAtomicUpdate(op, builder, moduleTranslation);
13896dd54da5SShraiysh Vaishay })
139031486a9fSShraiysh Vaishay .Case([&](omp::AtomicCaptureOp op) {
139131486a9fSShraiysh Vaishay return convertOmpAtomicCapture(op, builder, moduleTranslation);
139231486a9fSShraiysh Vaishay })
13933425b1bcSShraiysh Vaishay .Case([&](omp::SectionsOp) {
13943425b1bcSShraiysh Vaishay return convertOmpSections(*op, builder, moduleTranslation);
13953425b1bcSShraiysh Vaishay })
13963c0d4708SShraiysh Vaishay .Case([&](omp::SingleOp op) {
13973c0d4708SShraiysh Vaishay return convertOmpSingle(op, builder, moduleTranslation);
13983c0d4708SShraiysh Vaishay })
1399fdf505f3SShraiysh Vaishay .Case([&](omp::TaskOp op) {
1400fdf505f3SShraiysh Vaishay return convertOmpTaskOp(op, builder, moduleTranslation);
1401fdf505f3SShraiysh Vaishay })
1402711aa357SKiran Chandramohan .Case<omp::YieldOp, omp::TerminatorOp, omp::ReductionDeclareOp,
1403711aa357SKiran Chandramohan omp::CriticalDeclareOp>([](auto op) {
14048647e4c3SAlex Zinenko // `yield` and `terminator` can be just omitted. The block structure
14058647e4c3SAlex Zinenko // was created in the region that handles their parent operation.
14068647e4c3SAlex Zinenko // `reduction.declare` will be used by reductions and is not
14078647e4c3SAlex Zinenko // converted directly, skip it.
1408711aa357SKiran Chandramohan // `critical.declare` is only used to declare names of critical
1409711aa357SKiran Chandramohan // sections which will be used by `critical` ops and hence can be
1410711aa357SKiran Chandramohan // ignored for lowering. The OpenMP IRBuilder will create unique
1411711aa357SKiran Chandramohan // name for critical section names.
141266900b3eSAlex Zinenko return success();
141366900b3eSAlex Zinenko })
1414139c5b8aSPeixin-Qiao .Case([&](omp::ThreadprivateOp) {
1415139c5b8aSPeixin-Qiao return convertOmpThreadprivate(*op, builder, moduleTranslation);
1416139c5b8aSPeixin-Qiao })
141766900b3eSAlex Zinenko .Default([&](Operation *inst) {
141866900b3eSAlex Zinenko return inst->emitError("unsupported OpenMP operation: ")
141966900b3eSAlex Zinenko << inst->getName();
142066900b3eSAlex Zinenko });
142166900b3eSAlex Zinenko }
142219db802eSAlex Zinenko
registerOpenMPDialectTranslation(DialectRegistry & registry)142319db802eSAlex Zinenko void mlir::registerOpenMPDialectTranslation(DialectRegistry ®istry) {
142419db802eSAlex Zinenko registry.insert<omp::OpenMPDialect>();
142577eee579SRiver Riddle registry.addExtension(+[](MLIRContext *ctx, omp::OpenMPDialect *dialect) {
142677eee579SRiver Riddle dialect->addInterfaces<OpenMPDialectLLVMIRTranslationInterface>();
142777eee579SRiver Riddle });
142819db802eSAlex Zinenko }
142919db802eSAlex Zinenko
registerOpenMPDialectTranslation(MLIRContext & context)143019db802eSAlex Zinenko void mlir::registerOpenMPDialectTranslation(MLIRContext &context) {
143119db802eSAlex Zinenko DialectRegistry registry;
143219db802eSAlex Zinenko registerOpenMPDialectTranslation(registry);
143319db802eSAlex Zinenko context.appendDialectRegistry(registry);
143419db802eSAlex Zinenko }
1435