Bug Summary

File:build/source/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
Warning:line 223, column 9
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name OpenMPToLLVMIRTranslation.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/source/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-17/lib/clang/17 -D MLIR_CUDA_CONVERSIONS_ENABLED=1 -D MLIR_ROCM_CONVERSIONS_ENABLED=1 -D _DEBUG -D _GLIBCXX_ASSERTIONS -D _GNU_SOURCE -D _LIBCPP_ENABLE_ASSERTIONS -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I tools/mlir/lib/Target/LLVMIR/Dialect/OpenMP -I /build/source/mlir/lib/Target/LLVMIR/Dialect/OpenMP -I include -I /build/source/llvm/include -I /build/source/mlir/include -I tools/mlir/include -D _FORTIFY_SOURCE=2 -D NDEBUG -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-17/lib/clang/17/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/source/= -fcoverage-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/source/= -source-date-epoch 1683717183 -O2 -Wno-unused-command-line-argument -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -Wno-misleading-indentation -std=c++17 -fdeprecated-macro -fdebug-compilation-dir=/build/source/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/source/= -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2023-05-10-133810-16478-1 -x c++ /build/source/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
1//===- OpenMPToLLVMIRTranslation.cpp - Translate OpenMP dialect to LLVM IR-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements a translation between the MLIR OpenMP dialect and LLVM
10// IR.
11//
12//===----------------------------------------------------------------------===//
13#include "mlir/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.h"
14#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
15#include "mlir/Dialect/OpenMP/OpenMPInterfaces.h"
16#include "mlir/IR/IRMapping.h"
17#include "mlir/IR/Operation.h"
18#include "mlir/Support/LLVM.h"
19#include "mlir/Target/LLVMIR/Dialect/OpenMPCommon.h"
20#include "mlir/Target/LLVMIR/ModuleTranslation.h"
21#include "mlir/Transforms/RegionUtils.h"
22
23#include "llvm/ADT/SetVector.h"
24#include "llvm/ADT/TypeSwitch.h"
25#include "llvm/Frontend/OpenMP/OMPConstants.h"
26#include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
27#include "llvm/IR/DebugInfoMetadata.h"
28#include "llvm/IR/IRBuilder.h"
29#include "llvm/Support/FileSystem.h"
30
31using namespace mlir;
32
33namespace {
34static llvm::omp::ScheduleKind
35convertToScheduleKind(std::optional<omp::ClauseScheduleKind> schedKind) {
36 if (!schedKind.has_value())
37 return llvm::omp::OMP_SCHEDULE_Default;
38 switch (schedKind.value()) {
39 case omp::ClauseScheduleKind::Static:
40 return llvm::omp::OMP_SCHEDULE_Static;
41 case omp::ClauseScheduleKind::Dynamic:
42 return llvm::omp::OMP_SCHEDULE_Dynamic;
43 case omp::ClauseScheduleKind::Guided:
44 return llvm::omp::OMP_SCHEDULE_Guided;
45 case omp::ClauseScheduleKind::Auto:
46 return llvm::omp::OMP_SCHEDULE_Auto;
47 case omp::ClauseScheduleKind::Runtime:
48 return llvm::omp::OMP_SCHEDULE_Runtime;
49 }
50 llvm_unreachable("unhandled schedule clause argument")::llvm::llvm_unreachable_internal("unhandled schedule clause argument"
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 50)
;
51}
52
53/// ModuleTranslation stack frame for OpenMP operations. This keeps track of the
54/// insertion points for allocas.
55class OpenMPAllocaStackFrame
56 : public LLVM::ModuleTranslation::StackFrameBase<OpenMPAllocaStackFrame> {
57public:
58 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(OpenMPAllocaStackFrame)static ::mlir::TypeID resolveTypeID() { static ::mlir::SelfOwningTypeID
id; return id; } static_assert( ::mlir::detail::InlineTypeIDResolver
::has_resolve_typeid< OpenMPAllocaStackFrame>::value, "`MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID` must be placed in a "
"public section of `" "OpenMPAllocaStackFrame" "`");
59
60 explicit OpenMPAllocaStackFrame(llvm::OpenMPIRBuilder::InsertPointTy allocaIP)
61 : allocaInsertPoint(allocaIP) {}
62 llvm::OpenMPIRBuilder::InsertPointTy allocaInsertPoint;
63};
64
65/// ModuleTranslation stack frame containing the partial mapping between MLIR
66/// values and their LLVM IR equivalents.
67class OpenMPVarMappingStackFrame
68 : public LLVM::ModuleTranslation::StackFrameBase<
69 OpenMPVarMappingStackFrame> {
70public:
71 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(OpenMPVarMappingStackFrame)static ::mlir::TypeID resolveTypeID() { static ::mlir::SelfOwningTypeID
id; return id; } static_assert( ::mlir::detail::InlineTypeIDResolver
::has_resolve_typeid< OpenMPVarMappingStackFrame>::value
, "`MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID` must be placed in a "
"public section of `" "OpenMPVarMappingStackFrame" "`");
72
73 explicit OpenMPVarMappingStackFrame(
74 const DenseMap<Value, llvm::Value *> &mapping)
75 : mapping(mapping) {}
76
77 DenseMap<Value, llvm::Value *> mapping;
78};
79} // namespace
80
81/// Find the insertion point for allocas given the current insertion point for
82/// normal operations in the builder.
83static llvm::OpenMPIRBuilder::InsertPointTy
84findAllocaInsertPoint(llvm::IRBuilderBase &builder,
85 const LLVM::ModuleTranslation &moduleTranslation) {
86 // If there is an alloca insertion point on stack, i.e. we are in a nested
87 // operation and a specific point was provided by some surrounding operation,
88 // use it.
89 llvm::OpenMPIRBuilder::InsertPointTy allocaInsertPoint;
90 WalkResult walkResult = moduleTranslation.stackWalk<OpenMPAllocaStackFrame>(
91 [&](const OpenMPAllocaStackFrame &frame) {
92 allocaInsertPoint = frame.allocaInsertPoint;
93 return WalkResult::interrupt();
94 });
95 if (walkResult.wasInterrupted())
96 return allocaInsertPoint;
97
98 // Otherwise, insert to the entry block of the surrounding function.
99 // If the current IRBuilder InsertPoint is the function's entry, it cannot
100 // also be used for alloca insertion which would result in insertion order
101 // confusion. Create a new BasicBlock for the Builder and use the entry block
102 // for the allocs.
103 // TODO: Create a dedicated alloca BasicBlock at function creation such that
104 // we do not need to move the current InertPoint here.
105 if (builder.GetInsertBlock() ==
106 &builder.GetInsertBlock()->getParent()->getEntryBlock()) {
107 assert(builder.GetInsertPoint() == builder.GetInsertBlock()->end() &&(static_cast <bool> (builder.GetInsertPoint() == builder
.GetInsertBlock()->end() && "Assuming end of basic block"
) ? void (0) : __assert_fail ("builder.GetInsertPoint() == builder.GetInsertBlock()->end() && \"Assuming end of basic block\""
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 108, __extension__ __PRETTY_FUNCTION__))
108 "Assuming end of basic block")(static_cast <bool> (builder.GetInsertPoint() == builder
.GetInsertBlock()->end() && "Assuming end of basic block"
) ? void (0) : __assert_fail ("builder.GetInsertPoint() == builder.GetInsertBlock()->end() && \"Assuming end of basic block\""
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 108, __extension__ __PRETTY_FUNCTION__))
;
109 llvm::BasicBlock *entryBB = llvm::BasicBlock::Create(
110 builder.getContext(), "entry", builder.GetInsertBlock()->getParent(),
111 builder.GetInsertBlock()->getNextNode());
112 builder.CreateBr(entryBB);
113 builder.SetInsertPoint(entryBB);
114 }
115
116 llvm::BasicBlock &funcEntryBlock =
117 builder.GetInsertBlock()->getParent()->getEntryBlock();
118 return llvm::OpenMPIRBuilder::InsertPointTy(
119 &funcEntryBlock, funcEntryBlock.getFirstInsertionPt());
120}
121
122/// Converts the given region that appears within an OpenMP dialect operation to
123/// LLVM IR, creating a branch from the `sourceBlock` to the entry block of the
124/// region, and a branch from any block with an successor-less OpenMP terminator
125/// to `continuationBlock`. Populates `continuationBlockPHIs` with the PHI nodes
126/// of the continuation block if provided.
127static llvm::BasicBlock *convertOmpOpRegions(
128 Region &region, StringRef blockName, llvm::IRBuilderBase &builder,
129 LLVM::ModuleTranslation &moduleTranslation, LogicalResult &bodyGenStatus,
130 SmallVectorImpl<llvm::PHINode *> *continuationBlockPHIs = nullptr) {
131 llvm::BasicBlock *continuationBlock =
132 splitBB(builder, true, "omp.region.cont");
133 llvm::BasicBlock *sourceBlock = builder.GetInsertBlock();
134
135 llvm::LLVMContext &llvmContext = builder.getContext();
136 for (Block &bb : region) {
137 llvm::BasicBlock *llvmBB = llvm::BasicBlock::Create(
138 llvmContext, blockName, builder.GetInsertBlock()->getParent(),
139 builder.GetInsertBlock()->getNextNode());
140 moduleTranslation.mapBlock(&bb, llvmBB);
141 }
142
143 llvm::Instruction *sourceTerminator = sourceBlock->getTerminator();
144
145 // Terminators (namely YieldOp) may be forwarding values to the region that
146 // need to be available in the continuation block. Collect the types of these
147 // operands in preparation of creating PHI nodes.
148 SmallVector<llvm::Type *> continuationBlockPHITypes;
149 bool operandsProcessed = false;
150 unsigned numYields = 0;
151 for (Block &bb : region.getBlocks()) {
152 if (omp::YieldOp yield = dyn_cast<omp::YieldOp>(bb.getTerminator())) {
153 if (!operandsProcessed) {
154 for (unsigned i = 0, e = yield->getNumOperands(); i < e; ++i) {
155 continuationBlockPHITypes.push_back(
156 moduleTranslation.convertType(yield->getOperand(i).getType()));
157 }
158 operandsProcessed = true;
159 } else {
160 assert(continuationBlockPHITypes.size() == yield->getNumOperands() &&(static_cast <bool> (continuationBlockPHITypes.size() ==
yield->getNumOperands() && "mismatching number of values yielded from the region"
) ? void (0) : __assert_fail ("continuationBlockPHITypes.size() == yield->getNumOperands() && \"mismatching number of values yielded from the region\""
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 161, __extension__ __PRETTY_FUNCTION__))
161 "mismatching number of values yielded from the region")(static_cast <bool> (continuationBlockPHITypes.size() ==
yield->getNumOperands() && "mismatching number of values yielded from the region"
) ? void (0) : __assert_fail ("continuationBlockPHITypes.size() == yield->getNumOperands() && \"mismatching number of values yielded from the region\""
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 161, __extension__ __PRETTY_FUNCTION__))
;
162 for (unsigned i = 0, e = yield->getNumOperands(); i < e; ++i) {
163 llvm::Type *operandType =
164 moduleTranslation.convertType(yield->getOperand(i).getType());
165 (void)operandType;
166 assert(continuationBlockPHITypes[i] == operandType &&(static_cast <bool> (continuationBlockPHITypes[i] == operandType
&& "values of mismatching types yielded from the region"
) ? void (0) : __assert_fail ("continuationBlockPHITypes[i] == operandType && \"values of mismatching types yielded from the region\""
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 167, __extension__ __PRETTY_FUNCTION__))
167 "values of mismatching types yielded from the region")(static_cast <bool> (continuationBlockPHITypes[i] == operandType
&& "values of mismatching types yielded from the region"
) ? void (0) : __assert_fail ("continuationBlockPHITypes[i] == operandType && \"values of mismatching types yielded from the region\""
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 167, __extension__ __PRETTY_FUNCTION__))
;
168 }
169 }
170 numYields++;
171 }
172 }
173
174 // Insert PHI nodes in the continuation block for any values forwarded by the
175 // terminators in this region.
176 if (!continuationBlockPHITypes.empty())
3
Taking false branch
177 assert((static_cast <bool> (continuationBlockPHIs && "expected continuation block PHIs if converted regions yield values"
) ? void (0) : __assert_fail ("continuationBlockPHIs && \"expected continuation block PHIs if converted regions yield values\""
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 179, __extension__ __PRETTY_FUNCTION__))
178 continuationBlockPHIs &&(static_cast <bool> (continuationBlockPHIs && "expected continuation block PHIs if converted regions yield values"
) ? void (0) : __assert_fail ("continuationBlockPHIs && \"expected continuation block PHIs if converted regions yield values\""
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 179, __extension__ __PRETTY_FUNCTION__))
179 "expected continuation block PHIs if converted regions yield values")(static_cast <bool> (continuationBlockPHIs && "expected continuation block PHIs if converted regions yield values"
) ? void (0) : __assert_fail ("continuationBlockPHIs && \"expected continuation block PHIs if converted regions yield values\""
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 179, __extension__ __PRETTY_FUNCTION__))
;
180 if (continuationBlockPHIs
3.1
'continuationBlockPHIs' is null
) {
4
Taking false branch
181 llvm::IRBuilderBase::InsertPointGuard guard(builder);
182 continuationBlockPHIs->reserve(continuationBlockPHITypes.size());
183 builder.SetInsertPoint(continuationBlock, continuationBlock->begin());
184 for (llvm::Type *ty : continuationBlockPHITypes)
185 continuationBlockPHIs->push_back(builder.CreatePHI(ty, numYields));
186 }
187
188 // Convert blocks one by one in topological order to ensure
189 // defs are converted before uses.
190 SetVector<Block *> blocks =
191 LLVM::detail::getTopologicallySortedBlocks(region);
192 for (Block *bb : blocks) {
193 llvm::BasicBlock *llvmBB = moduleTranslation.lookupBlock(bb);
194 // Retarget the branch of the entry block to the entry block of the
195 // converted region (regions are single-entry).
196 if (bb->isEntryBlock()) {
5
Assuming the condition is false
6
Taking false branch
197 assert(sourceTerminator->getNumSuccessors() == 1 &&(static_cast <bool> (sourceTerminator->getNumSuccessors
() == 1 && "provided entry block has multiple successors"
) ? void (0) : __assert_fail ("sourceTerminator->getNumSuccessors() == 1 && \"provided entry block has multiple successors\""
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 198, __extension__ __PRETTY_FUNCTION__))
198 "provided entry block has multiple successors")(static_cast <bool> (sourceTerminator->getNumSuccessors
() == 1 && "provided entry block has multiple successors"
) ? void (0) : __assert_fail ("sourceTerminator->getNumSuccessors() == 1 && \"provided entry block has multiple successors\""
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 198, __extension__ __PRETTY_FUNCTION__))
;
199 assert(sourceTerminator->getSuccessor(0) == continuationBlock &&(static_cast <bool> (sourceTerminator->getSuccessor(
0) == continuationBlock && "ContinuationBlock is not the successor of the entry block"
) ? void (0) : __assert_fail ("sourceTerminator->getSuccessor(0) == continuationBlock && \"ContinuationBlock is not the successor of the entry block\""
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 200, __extension__ __PRETTY_FUNCTION__))
200 "ContinuationBlock is not the successor of the entry block")(static_cast <bool> (sourceTerminator->getSuccessor(
0) == continuationBlock && "ContinuationBlock is not the successor of the entry block"
) ? void (0) : __assert_fail ("sourceTerminator->getSuccessor(0) == continuationBlock && \"ContinuationBlock is not the successor of the entry block\""
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 200, __extension__ __PRETTY_FUNCTION__))
;
201 sourceTerminator->setSuccessor(0, llvmBB);
202 }
203
204 llvm::IRBuilderBase::InsertPointGuard guard(builder);
205 if (failed(
7
Taking false branch
206 moduleTranslation.convertBlock(*bb, bb->isEntryBlock(), builder))) {
207 bodyGenStatus = failure();
208 return continuationBlock;
209 }
210
211 // Special handling for `omp.yield` and `omp.terminator` (we may have more
212 // than one): they return the control to the parent OpenMP dialect operation
213 // so replace them with the branch to the continuation block. We handle this
214 // here to avoid relying inter-function communication through the
215 // ModuleTranslation class to set up the correct insertion point. This is
216 // also consistent with MLIR's idiom of handling special region terminators
217 // in the same code that handles the region-owning operation.
218 Operation *terminator = bb->getTerminator();
219 if (isa<omp::TerminatorOp, omp::YieldOp>(terminator)) {
8
Assuming 'terminator' is a 'class mlir::omp::YieldOp &'
9
Taking true branch
220 builder.CreateBr(continuationBlock);
221
222 for (unsigned i = 0, e = terminator->getNumOperands(); i < e; ++i)
10
Assuming 'i' is < 'e'
11
Loop condition is true. Entering loop body
223 (*continuationBlockPHIs)[i]->addIncoming(
12
Called C++ object pointer is null
224 moduleTranslation.lookupValue(terminator->getOperand(i)), llvmBB);
225 }
226 }
227 // After all blocks have been traversed and values mapped, connect the PHI
228 // nodes to the results of preceding blocks.
229 LLVM::detail::connectPHINodes(region, moduleTranslation);
230
231 // Remove the blocks and values defined in this region from the mapping since
232 // they are not visible outside of this region. This allows the same region to
233 // be converted several times, that is cloned, without clashes, and slightly
234 // speeds up the lookups.
235 moduleTranslation.forgetMapping(region);
236
237 return continuationBlock;
238}
239
240/// Convert ProcBindKind from MLIR-generated enum to LLVM enum.
241static llvm::omp::ProcBindKind getProcBindKind(omp::ClauseProcBindKind kind) {
242 switch (kind) {
243 case omp::ClauseProcBindKind::Close:
244 return llvm::omp::ProcBindKind::OMP_PROC_BIND_close;
245 case omp::ClauseProcBindKind::Master:
246 return llvm::omp::ProcBindKind::OMP_PROC_BIND_master;
247 case omp::ClauseProcBindKind::Primary:
248 return llvm::omp::ProcBindKind::OMP_PROC_BIND_primary;
249 case omp::ClauseProcBindKind::Spread:
250 return llvm::omp::ProcBindKind::OMP_PROC_BIND_spread;
251 }
252 llvm_unreachable("Unknown ClauseProcBindKind kind")::llvm::llvm_unreachable_internal("Unknown ClauseProcBindKind kind"
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 252)
;
253}
254
255/// Converts the OpenMP parallel operation to LLVM IR.
256static LogicalResult
257convertOmpParallel(omp::ParallelOp opInst, llvm::IRBuilderBase &builder,
258 LLVM::ModuleTranslation &moduleTranslation) {
259 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
260 // TODO: support error propagation in OpenMPIRBuilder and use it instead of
261 // relying on captured variables.
262 LogicalResult bodyGenStatus = success();
263
264 auto bodyGenCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP) {
265 // Save the alloca insertion point on ModuleTranslation stack for use in
266 // nested regions.
267 LLVM::ModuleTranslation::SaveStack<OpenMPAllocaStackFrame> frame(
268 moduleTranslation, allocaIP);
269
270 // ParallelOp has only one region associated with it.
271 builder.restoreIP(codeGenIP);
272 convertOmpOpRegions(opInst.getRegion(), "omp.par.region", builder,
273 moduleTranslation, bodyGenStatus);
274 };
275
276 // TODO: Perform appropriate actions according to the data-sharing
277 // attribute (shared, private, firstprivate, ...) of variables.
278 // Currently defaults to shared.
279 auto privCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP,
280 llvm::Value &, llvm::Value &vPtr,
281 llvm::Value *&replacementValue) -> InsertPointTy {
282 replacementValue = &vPtr;
283
284 return codeGenIP;
285 };
286
287 // TODO: Perform finalization actions for variables. This has to be
288 // called for variables which have destructors/finalizers.
289 auto finiCB = [&](InsertPointTy codeGenIP) {};
290
291 llvm::Value *ifCond = nullptr;
292 if (auto ifExprVar = opInst.getIfExprVar())
293 ifCond = moduleTranslation.lookupValue(ifExprVar);
294 llvm::Value *numThreads = nullptr;
295 if (auto numThreadsVar = opInst.getNumThreadsVar())
296 numThreads = moduleTranslation.lookupValue(numThreadsVar);
297 auto pbKind = llvm::omp::OMP_PROC_BIND_default;
298 if (auto bind = opInst.getProcBindVal())
299 pbKind = getProcBindKind(*bind);
300 // TODO: Is the Parallel construct cancellable?
301 bool isCancellable = false;
302
303 llvm::OpenMPIRBuilder::InsertPointTy allocaIP =
304 findAllocaInsertPoint(builder, moduleTranslation);
305 llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
306 builder.restoreIP(moduleTranslation.getOpenMPBuilder()->createParallel(
307 ompLoc, allocaIP, bodyGenCB, privCB, finiCB, ifCond, numThreads, pbKind,
308 isCancellable));
309
310 return bodyGenStatus;
311}
312
313/// Converts an OpenMP 'master' operation into LLVM IR using OpenMPIRBuilder.
314static LogicalResult
315convertOmpMaster(Operation &opInst, llvm::IRBuilderBase &builder,
316 LLVM::ModuleTranslation &moduleTranslation) {
317 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
318 // TODO: support error propagation in OpenMPIRBuilder and use it instead of
319 // relying on captured variables.
320 LogicalResult bodyGenStatus = success();
321
322 auto bodyGenCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP) {
323 // MasterOp has only one region associated with it.
324 auto &region = cast<omp::MasterOp>(opInst).getRegion();
325 builder.restoreIP(codeGenIP);
326 convertOmpOpRegions(region, "omp.master.region", builder, moduleTranslation,
327 bodyGenStatus);
328 };
329
330 // TODO: Perform finalization actions for variables. This has to be
331 // called for variables which have destructors/finalizers.
332 auto finiCB = [&](InsertPointTy codeGenIP) {};
333
334 llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
335 builder.restoreIP(moduleTranslation.getOpenMPBuilder()->createMaster(
336 ompLoc, bodyGenCB, finiCB));
337 return success();
338}
339
340/// Converts an OpenMP 'critical' operation into LLVM IR using OpenMPIRBuilder.
341static LogicalResult
342convertOmpCritical(Operation &opInst, llvm::IRBuilderBase &builder,
343 LLVM::ModuleTranslation &moduleTranslation) {
344 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
345 auto criticalOp = cast<omp::CriticalOp>(opInst);
346 // TODO: support error propagation in OpenMPIRBuilder and use it instead of
347 // relying on captured variables.
348 LogicalResult bodyGenStatus = success();
349
350 auto bodyGenCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP) {
351 // CriticalOp has only one region associated with it.
352 auto &region = cast<omp::CriticalOp>(opInst).getRegion();
353 builder.restoreIP(codeGenIP);
354 convertOmpOpRegions(region, "omp.critical.region", builder,
355 moduleTranslation, bodyGenStatus);
356 };
357
358 // TODO: Perform finalization actions for variables. This has to be
359 // called for variables which have destructors/finalizers.
360 auto finiCB = [&](InsertPointTy codeGenIP) {};
361
362 llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
363 llvm::LLVMContext &llvmContext = moduleTranslation.getLLVMContext();
364 llvm::Constant *hint = nullptr;
365
366 // If it has a name, it probably has a hint too.
367 if (criticalOp.getNameAttr()) {
368 // The verifiers in OpenMP Dialect guarentee that all the pointers are
369 // non-null
370 auto symbolRef = criticalOp.getNameAttr().cast<SymbolRefAttr>();
371 auto criticalDeclareOp =
372 SymbolTable::lookupNearestSymbolFrom<omp::CriticalDeclareOp>(criticalOp,
373 symbolRef);
374 hint = llvm::ConstantInt::get(
375 llvm::Type::getInt32Ty(llvmContext),
376 static_cast<int>(criticalDeclareOp.getHintVal()));
377 }
378 builder.restoreIP(moduleTranslation.getOpenMPBuilder()->createCritical(
379 ompLoc, bodyGenCB, finiCB, criticalOp.getName().value_or(""), hint));
380 return success();
381}
382
383/// Returns a reduction declaration that corresponds to the given reduction
384/// operation in the given container. Currently only supports reductions inside
385/// WsLoopOp but can be easily extended.
386static omp::ReductionDeclareOp findReductionDecl(omp::WsLoopOp container,
387 omp::ReductionOp reduction) {
388 SymbolRefAttr reductionSymbol;
389 for (unsigned i = 0, e = container.getNumReductionVars(); i < e; ++i) {
390 if (container.getReductionVars()[i] != reduction.getAccumulator())
391 continue;
392 reductionSymbol = (*container.getReductions())[i].cast<SymbolRefAttr>();
393 break;
394 }
395 assert(reductionSymbol &&(static_cast <bool> (reductionSymbol && "reduction operation must be associated with a declaration"
) ? void (0) : __assert_fail ("reductionSymbol && \"reduction operation must be associated with a declaration\""
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 396, __extension__ __PRETTY_FUNCTION__))
396 "reduction operation must be associated with a declaration")(static_cast <bool> (reductionSymbol && "reduction operation must be associated with a declaration"
) ? void (0) : __assert_fail ("reductionSymbol && \"reduction operation must be associated with a declaration\""
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 396, __extension__ __PRETTY_FUNCTION__))
;
397
398 return SymbolTable::lookupNearestSymbolFrom<omp::ReductionDeclareOp>(
399 container, reductionSymbol);
400}
401
402/// Populates `reductions` with reduction declarations used in the given loop.
403static void
404collectReductionDecls(omp::WsLoopOp loop,
405 SmallVectorImpl<omp::ReductionDeclareOp> &reductions) {
406 std::optional<ArrayAttr> attr = loop.getReductions();
407 if (!attr)
408 return;
409
410 reductions.reserve(reductions.size() + loop.getNumReductionVars());
411 for (auto symbolRef : attr->getAsRange<SymbolRefAttr>()) {
412 reductions.push_back(
413 SymbolTable::lookupNearestSymbolFrom<omp::ReductionDeclareOp>(
414 loop, symbolRef));
415 }
416}
417
418/// Translates the blocks contained in the given region and appends them to at
419/// the current insertion point of `builder`. The operations of the entry block
420/// are appended to the current insertion block, which is not expected to have a
421/// terminator. If set, `continuationBlockArgs` is populated with translated
422/// values that correspond to the values omp.yield'ed from the region.
423static LogicalResult inlineConvertOmpRegions(
424 Region &region, StringRef blockName, llvm::IRBuilderBase &builder,
425 LLVM::ModuleTranslation &moduleTranslation,
426 SmallVectorImpl<llvm::Value *> *continuationBlockArgs = nullptr) {
427 if (region.empty())
428 return success();
429
430 // Special case for single-block regions that don't create additional blocks:
431 // insert operations without creating additional blocks.
432 if (llvm::hasSingleElement(region)) {
433 moduleTranslation.mapBlock(&region.front(), builder.GetInsertBlock());
434 if (failed(moduleTranslation.convertBlock(
435 region.front(), /*ignoreArguments=*/true, builder)))
436 return failure();
437
438 // The continuation arguments are simply the translated terminator operands.
439 if (continuationBlockArgs)
440 llvm::append_range(
441 *continuationBlockArgs,
442 moduleTranslation.lookupValues(region.front().back().getOperands()));
443
444 // Drop the mapping that is no longer necessary so that the same region can
445 // be processed multiple times.
446 moduleTranslation.forgetMapping(region);
447 return success();
448 }
449
450 LogicalResult bodyGenStatus = success();
451 SmallVector<llvm::PHINode *> phis;
452 llvm::BasicBlock *continuationBlock = convertOmpOpRegions(
453 region, blockName, builder, moduleTranslation, bodyGenStatus, &phis);
454 if (failed(bodyGenStatus))
455 return failure();
456 if (continuationBlockArgs)
457 llvm::append_range(*continuationBlockArgs, phis);
458 builder.SetInsertPoint(continuationBlock,
459 continuationBlock->getFirstInsertionPt());
460 return success();
461}
462
463namespace {
464/// Owning equivalents of OpenMPIRBuilder::(Atomic)ReductionGen that are used to
465/// store lambdas with capture.
466using OwningReductionGen = std::function<llvm::OpenMPIRBuilder::InsertPointTy(
467 llvm::OpenMPIRBuilder::InsertPointTy, llvm::Value *, llvm::Value *,
468 llvm::Value *&)>;
469using OwningAtomicReductionGen =
470 std::function<llvm::OpenMPIRBuilder::InsertPointTy(
471 llvm::OpenMPIRBuilder::InsertPointTy, llvm::Type *, llvm::Value *,
472 llvm::Value *)>;
473} // namespace
474
475/// Create an OpenMPIRBuilder-compatible reduction generator for the given
476/// reduction declaration. The generator uses `builder` but ignores its
477/// insertion point.
478static OwningReductionGen
479makeReductionGen(omp::ReductionDeclareOp decl, llvm::IRBuilderBase &builder,
480 LLVM::ModuleTranslation &moduleTranslation) {
481 // The lambda is mutable because we need access to non-const methods of decl
482 // (which aren't actually mutating it), and we must capture decl by-value to
483 // avoid the dangling reference after the parent function returns.
484 OwningReductionGen gen =
485 [&, decl](llvm::OpenMPIRBuilder::InsertPointTy insertPoint,
486 llvm::Value *lhs, llvm::Value *rhs,
487 llvm::Value *&result) mutable {
488 Region &reductionRegion = decl.getReductionRegion();
489 moduleTranslation.mapValue(reductionRegion.front().getArgument(0), lhs);
490 moduleTranslation.mapValue(reductionRegion.front().getArgument(1), rhs);
491 builder.restoreIP(insertPoint);
492 SmallVector<llvm::Value *> phis;
493 if (failed(inlineConvertOmpRegions(reductionRegion,
494 "omp.reduction.nonatomic.body",
495 builder, moduleTranslation, &phis)))
496 return llvm::OpenMPIRBuilder::InsertPointTy();
497 assert(phis.size() == 1)(static_cast <bool> (phis.size() == 1) ? void (0) : __assert_fail
("phis.size() == 1", "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 497, __extension__ __PRETTY_FUNCTION__))
;
498 result = phis[0];
499 return builder.saveIP();
500 };
501 return gen;
502}
503
504/// Create an OpenMPIRBuilder-compatible atomic reduction generator for the
505/// given reduction declaration. The generator uses `builder` but ignores its
506/// insertion point. Returns null if there is no atomic region available in the
507/// reduction declaration.
508static OwningAtomicReductionGen
509makeAtomicReductionGen(omp::ReductionDeclareOp decl,
510 llvm::IRBuilderBase &builder,
511 LLVM::ModuleTranslation &moduleTranslation) {
512 if (decl.getAtomicReductionRegion().empty())
513 return OwningAtomicReductionGen();
514
515 // The lambda is mutable because we need access to non-const methods of decl
516 // (which aren't actually mutating it), and we must capture decl by-value to
517 // avoid the dangling reference after the parent function returns.
518 OwningAtomicReductionGen atomicGen =
519 [&, decl](llvm::OpenMPIRBuilder::InsertPointTy insertPoint, llvm::Type *,
520 llvm::Value *lhs, llvm::Value *rhs) mutable {
521 Region &atomicRegion = decl.getAtomicReductionRegion();
522 moduleTranslation.mapValue(atomicRegion.front().getArgument(0), lhs);
523 moduleTranslation.mapValue(atomicRegion.front().getArgument(1), rhs);
524 builder.restoreIP(insertPoint);
525 SmallVector<llvm::Value *> phis;
526 if (failed(inlineConvertOmpRegions(atomicRegion,
527 "omp.reduction.atomic.body", builder,
528 moduleTranslation, &phis)))
529 return llvm::OpenMPIRBuilder::InsertPointTy();
530 assert(phis.empty())(static_cast <bool> (phis.empty()) ? void (0) : __assert_fail
("phis.empty()", "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 530, __extension__ __PRETTY_FUNCTION__))
;
531 return builder.saveIP();
532 };
533 return atomicGen;
534}
535
536/// Converts an OpenMP 'ordered' operation into LLVM IR using OpenMPIRBuilder.
537static LogicalResult
538convertOmpOrdered(Operation &opInst, llvm::IRBuilderBase &builder,
539 LLVM::ModuleTranslation &moduleTranslation) {
540 auto orderedOp = cast<omp::OrderedOp>(opInst);
541
542 omp::ClauseDepend dependType = *orderedOp.getDependTypeVal();
543 bool isDependSource = dependType == omp::ClauseDepend::dependsource;
544 unsigned numLoops = *orderedOp.getNumLoopsVal();
545 SmallVector<llvm::Value *> vecValues =
546 moduleTranslation.lookupValues(orderedOp.getDependVecVars());
547
548 size_t indexVecValues = 0;
549 while (indexVecValues < vecValues.size()) {
550 SmallVector<llvm::Value *> storeValues;
551 storeValues.reserve(numLoops);
552 for (unsigned i = 0; i < numLoops; i++) {
553 storeValues.push_back(vecValues[indexVecValues]);
554 indexVecValues++;
555 }
556 llvm::OpenMPIRBuilder::InsertPointTy allocaIP =
557 findAllocaInsertPoint(builder, moduleTranslation);
558 llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
559 builder.restoreIP(moduleTranslation.getOpenMPBuilder()->createOrderedDepend(
560 ompLoc, allocaIP, numLoops, storeValues, ".cnt.addr", isDependSource));
561 }
562 return success();
563}
564
565/// Converts an OpenMP 'ordered_region' operation into LLVM IR using
566/// OpenMPIRBuilder.
567static LogicalResult
568convertOmpOrderedRegion(Operation &opInst, llvm::IRBuilderBase &builder,
569 LLVM::ModuleTranslation &moduleTranslation) {
570 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
571 auto orderedRegionOp = cast<omp::OrderedRegionOp>(opInst);
572
573 // TODO: The code generation for ordered simd directive is not supported yet.
574 if (orderedRegionOp.getSimd())
575 return failure();
576
577 // TODO: support error propagation in OpenMPIRBuilder and use it instead of
578 // relying on captured variables.
579 LogicalResult bodyGenStatus = success();
580
581 auto bodyGenCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP) {
582 // OrderedOp has only one region associated with it.
583 auto &region = cast<omp::OrderedRegionOp>(opInst).getRegion();
584 builder.restoreIP(codeGenIP);
585 convertOmpOpRegions(region, "omp.ordered.region", builder,
586 moduleTranslation, bodyGenStatus);
587 };
588
589 // TODO: Perform finalization actions for variables. This has to be
590 // called for variables which have destructors/finalizers.
591 auto finiCB = [&](InsertPointTy codeGenIP) {};
592
593 llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
594 builder.restoreIP(
595 moduleTranslation.getOpenMPBuilder()->createOrderedThreadsSimd(
596 ompLoc, bodyGenCB, finiCB, !orderedRegionOp.getSimd()));
597 return bodyGenStatus;
598}
599
600static LogicalResult
601convertOmpSections(Operation &opInst, llvm::IRBuilderBase &builder,
602 LLVM::ModuleTranslation &moduleTranslation) {
603 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
604 using StorableBodyGenCallbackTy =
605 llvm::OpenMPIRBuilder::StorableBodyGenCallbackTy;
606
607 auto sectionsOp = cast<omp::SectionsOp>(opInst);
608
609 // TODO: Support the following clauses: private, firstprivate, lastprivate,
610 // reduction, allocate
611 if (!sectionsOp.getReductionVars().empty() || sectionsOp.getReductions() ||
612 !sectionsOp.getAllocateVars().empty() ||
613 !sectionsOp.getAllocatorsVars().empty())
614 return emitError(sectionsOp.getLoc())
615 << "reduction and allocate clauses are not supported for sections "
616 "construct";
617
618 LogicalResult bodyGenStatus = success();
619 SmallVector<StorableBodyGenCallbackTy> sectionCBs;
620
621 for (Operation &op : *sectionsOp.getRegion().begin()) {
622 auto sectionOp = dyn_cast<omp::SectionOp>(op);
623 if (!sectionOp) // omp.terminator
624 continue;
625
626 Region &region = sectionOp.getRegion();
627 auto sectionCB = [&region, &builder, &moduleTranslation, &bodyGenStatus](
628 InsertPointTy allocaIP, InsertPointTy codeGenIP) {
629 builder.restoreIP(codeGenIP);
630 convertOmpOpRegions(region, "omp.section.region", builder,
631 moduleTranslation, bodyGenStatus);
632 };
633 sectionCBs.push_back(sectionCB);
634 }
635
636 // No sections within omp.sections operation - skip generation. This situation
637 // is only possible if there is only a terminator operation inside the
638 // sections operation
639 if (sectionCBs.empty())
640 return success();
641
642 assert(isa<omp::SectionOp>(*sectionsOp.getRegion().op_begin()))(static_cast <bool> (isa<omp::SectionOp>(*sectionsOp
.getRegion().op_begin())) ? void (0) : __assert_fail ("isa<omp::SectionOp>(*sectionsOp.getRegion().op_begin())"
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 642, __extension__ __PRETTY_FUNCTION__))
;
643
644 // TODO: Perform appropriate actions according to the data-sharing
645 // attribute (shared, private, firstprivate, ...) of variables.
646 // Currently defaults to shared.
647 auto privCB = [&](InsertPointTy, InsertPointTy codeGenIP, llvm::Value &,
648 llvm::Value &vPtr,
649 llvm::Value *&replacementValue) -> InsertPointTy {
650 replacementValue = &vPtr;
651 return codeGenIP;
652 };
653
654 // TODO: Perform finalization actions for variables. This has to be
655 // called for variables which have destructors/finalizers.
656 auto finiCB = [&](InsertPointTy codeGenIP) {};
657
658 llvm::OpenMPIRBuilder::InsertPointTy allocaIP =
659 findAllocaInsertPoint(builder, moduleTranslation);
660 llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
661 builder.restoreIP(moduleTranslation.getOpenMPBuilder()->createSections(
662 ompLoc, allocaIP, sectionCBs, privCB, finiCB, false,
663 sectionsOp.getNowait()));
664 return bodyGenStatus;
665}
666
667/// Converts an OpenMP single construct into LLVM IR using OpenMPIRBuilder.
668static LogicalResult
669convertOmpSingle(omp::SingleOp &singleOp, llvm::IRBuilderBase &builder,
670 LLVM::ModuleTranslation &moduleTranslation) {
671 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
672 llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
673 LogicalResult bodyGenStatus = success();
674 auto bodyCB = [&](InsertPointTy allocaIP, InsertPointTy codegenIP) {
675 builder.restoreIP(codegenIP);
676 convertOmpOpRegions(singleOp.getRegion(), "omp.single.region", builder,
677 moduleTranslation, bodyGenStatus);
678 };
679 auto finiCB = [&](InsertPointTy codeGenIP) {};
680 builder.restoreIP(moduleTranslation.getOpenMPBuilder()->createSingle(
681 ompLoc, bodyCB, finiCB, singleOp.getNowait(), /*DidIt=*/nullptr));
682 return bodyGenStatus;
683}
684
685/// Converts an OpenMP task construct into LLVM IR using OpenMPIRBuilder.
686static LogicalResult
687convertOmpTaskOp(omp::TaskOp taskOp, llvm::IRBuilderBase &builder,
688 LLVM::ModuleTranslation &moduleTranslation) {
689 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
690 LogicalResult bodyGenStatus = success();
691 if (taskOp.getIfExpr() || taskOp.getFinalExpr() || taskOp.getUntiedAttr() ||
692 taskOp.getMergeableAttr() || taskOp.getInReductions() ||
693 taskOp.getPriority() || !taskOp.getAllocateVars().empty()) {
694 return taskOp.emitError("unhandled clauses for translation to LLVM IR");
695 }
696 auto bodyCB = [&](InsertPointTy allocaIP, InsertPointTy codegenIP) {
697 builder.restoreIP(codegenIP);
698 convertOmpOpRegions(taskOp.getRegion(), "omp.task.region", builder,
699 moduleTranslation, bodyGenStatus);
700 };
701
702 SmallVector<llvm::OpenMPIRBuilder::DependData> dds;
703 if (!taskOp.getDependVars().empty() && taskOp.getDepends()) {
704 for (auto dep :
705 llvm::zip(taskOp.getDependVars(), taskOp.getDepends()->getValue())) {
706 llvm::omp::RTLDependenceKindTy type;
707 switch (
708 std::get<1>(dep).cast<mlir::omp::ClauseTaskDependAttr>().getValue()) {
709 case mlir::omp::ClauseTaskDepend::taskdependin:
710 type = llvm::omp::RTLDependenceKindTy::DepIn;
711 break;
712 // The OpenMP runtime requires that the codegen for 'depend' clause for
713 // 'out' dependency kind must be the same as codegen for 'depend' clause
714 // with 'inout' dependency.
715 case mlir::omp::ClauseTaskDepend::taskdependout:
716 case mlir::omp::ClauseTaskDepend::taskdependinout:
717 type = llvm::omp::RTLDependenceKindTy::DepInOut;
718 break;
719 };
720 llvm::Value *depVal = moduleTranslation.lookupValue(std::get<0>(dep));
721 llvm::OpenMPIRBuilder::DependData dd(type, depVal->getType(), depVal);
722 dds.emplace_back(dd);
723 }
724 }
725
726 llvm::OpenMPIRBuilder::InsertPointTy allocaIP =
727 findAllocaInsertPoint(builder, moduleTranslation);
728 llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
729 builder.restoreIP(moduleTranslation.getOpenMPBuilder()->createTask(
730 ompLoc, allocaIP, bodyCB, !taskOp.getUntied(), /*Final*/ nullptr,
731 /*IfCondition*/ nullptr, dds));
732 return bodyGenStatus;
733}
734
735/// Converts an OpenMP taskgroup construct into LLVM IR using OpenMPIRBuilder.
736static LogicalResult
737convertOmpTaskgroupOp(omp::TaskGroupOp tgOp, llvm::IRBuilderBase &builder,
738 LLVM::ModuleTranslation &moduleTranslation) {
739 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
740 LogicalResult bodyGenStatus = success();
741 if (!tgOp.getTaskReductionVars().empty() || !tgOp.getAllocateVars().empty()) {
742 return tgOp.emitError("unhandled clauses for translation to LLVM IR");
743 }
744 auto bodyCB = [&](InsertPointTy allocaIP, InsertPointTy codegenIP) {
745 builder.restoreIP(codegenIP);
746 convertOmpOpRegions(tgOp.getRegion(), "omp.taskgroup.region", builder,
747 moduleTranslation, bodyGenStatus);
748 };
749 InsertPointTy allocaIP = findAllocaInsertPoint(builder, moduleTranslation);
750 llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
751 builder.restoreIP(moduleTranslation.getOpenMPBuilder()->createTaskgroup(
752 ompLoc, allocaIP, bodyCB));
753 return bodyGenStatus;
754}
755
756/// Converts an OpenMP workshare loop into LLVM IR using OpenMPIRBuilder.
757static LogicalResult
758convertOmpWsLoop(Operation &opInst, llvm::IRBuilderBase &builder,
759 LLVM::ModuleTranslation &moduleTranslation) {
760 auto loop = cast<omp::WsLoopOp>(opInst);
761 // TODO: this should be in the op verifier instead.
762 if (loop.getLowerBound().empty())
763 return failure();
764
765 // Static is the default.
766 auto schedule =
767 loop.getScheduleVal().value_or(omp::ClauseScheduleKind::Static);
768
769 // Find the loop configuration.
770 llvm::Value *step = moduleTranslation.lookupValue(loop.getStep()[0]);
771 llvm::Type *ivType = step->getType();
772 llvm::Value *chunk = nullptr;
773 if (loop.getScheduleChunkVar()) {
774 llvm::Value *chunkVar =
775 moduleTranslation.lookupValue(loop.getScheduleChunkVar());
776 chunk = builder.CreateSExtOrTrunc(chunkVar, ivType);
777 }
778
779 SmallVector<omp::ReductionDeclareOp> reductionDecls;
780 collectReductionDecls(loop, reductionDecls);
781 llvm::OpenMPIRBuilder::InsertPointTy allocaIP =
782 findAllocaInsertPoint(builder, moduleTranslation);
783
784 // Allocate space for privatized reduction variables.
785 SmallVector<llvm::Value *> privateReductionVariables;
786 DenseMap<Value, llvm::Value *> reductionVariableMap;
787 unsigned numReductions = loop.getNumReductionVars();
788 privateReductionVariables.reserve(numReductions);
789 if (numReductions != 0) {
790 llvm::IRBuilderBase::InsertPointGuard guard(builder);
791 builder.restoreIP(allocaIP);
792 for (unsigned i = 0; i < numReductions; ++i) {
793 llvm::Value *var = builder.CreateAlloca(
794 moduleTranslation.convertType(reductionDecls[i].getType()));
795 privateReductionVariables.push_back(var);
796 reductionVariableMap.try_emplace(loop.getReductionVars()[i], var);
797 }
798 }
799
800 // Store the mapping between reduction variables and their private copies on
801 // ModuleTranslation stack. It can be then recovered when translating
802 // omp.reduce operations in a separate call.
803 LLVM::ModuleTranslation::SaveStack<OpenMPVarMappingStackFrame> mappingGuard(
804 moduleTranslation, reductionVariableMap);
805
806 // Before the loop, store the initial values of reductions into reduction
807 // variables. Although this could be done after allocas, we don't want to mess
808 // up with the alloca insertion point.
809 for (unsigned i = 0; i < numReductions; ++i) {
810 SmallVector<llvm::Value *> phis;
811 if (failed(inlineConvertOmpRegions(reductionDecls[i].getInitializerRegion(),
812 "omp.reduction.neutral", builder,
813 moduleTranslation, &phis)))
814 return failure();
815 assert(phis.size() == 1 && "expected one value to be yielded from the "(static_cast <bool> (phis.size() == 1 && "expected one value to be yielded from the "
"reduction neutral element declaration region") ? void (0) :
__assert_fail ("phis.size() == 1 && \"expected one value to be yielded from the \" \"reduction neutral element declaration region\""
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 816, __extension__ __PRETTY_FUNCTION__))
816 "reduction neutral element declaration region")(static_cast <bool> (phis.size() == 1 && "expected one value to be yielded from the "
"reduction neutral element declaration region") ? void (0) :
__assert_fail ("phis.size() == 1 && \"expected one value to be yielded from the \" \"reduction neutral element declaration region\""
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 816, __extension__ __PRETTY_FUNCTION__))
;
817 builder.CreateStore(phis[0], privateReductionVariables[i]);
818 }
819
820 // Set up the source location value for OpenMP runtime.
821 llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
822
823 // Generator of the canonical loop body.
824 // TODO: support error propagation in OpenMPIRBuilder and use it instead of
825 // relying on captured variables.
826 SmallVector<llvm::CanonicalLoopInfo *> loopInfos;
827 SmallVector<llvm::OpenMPIRBuilder::InsertPointTy> bodyInsertPoints;
828 LogicalResult bodyGenStatus = success();
829 auto bodyGen = [&](llvm::OpenMPIRBuilder::InsertPointTy ip, llvm::Value *iv) {
830 // Make sure further conversions know about the induction variable.
831 moduleTranslation.mapValue(
832 loop.getRegion().front().getArgument(loopInfos.size()), iv);
833
834 // Capture the body insertion point for use in nested loops. BodyIP of the
835 // CanonicalLoopInfo always points to the beginning of the entry block of
836 // the body.
837 bodyInsertPoints.push_back(ip);
838
839 if (loopInfos.size() != loop.getNumLoops() - 1)
840 return;
841
842 // Convert the body of the loop.
843 builder.restoreIP(ip);
844 convertOmpOpRegions(loop.getRegion(), "omp.wsloop.region", builder,
845 moduleTranslation, bodyGenStatus);
846 };
847
848 // Delegate actual loop construction to the OpenMP IRBuilder.
849 // TODO: this currently assumes WsLoop is semantically similar to SCF loop,
850 // i.e. it has a positive step, uses signed integer semantics. Reconsider
851 // this code when WsLoop clearly supports more cases.
852 llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder();
853 for (unsigned i = 0, e = loop.getNumLoops(); i < e; ++i) {
854 llvm::Value *lowerBound =
855 moduleTranslation.lookupValue(loop.getLowerBound()[i]);
856 llvm::Value *upperBound =
857 moduleTranslation.lookupValue(loop.getUpperBound()[i]);
858 llvm::Value *step = moduleTranslation.lookupValue(loop.getStep()[i]);
859
860 // Make sure loop trip count are emitted in the preheader of the outermost
861 // loop at the latest so that they are all available for the new collapsed
862 // loop will be created below.
863 llvm::OpenMPIRBuilder::LocationDescription loc = ompLoc;
864 llvm::OpenMPIRBuilder::InsertPointTy computeIP = ompLoc.IP;
865 if (i != 0) {
866 loc = llvm::OpenMPIRBuilder::LocationDescription(bodyInsertPoints.back());
867 computeIP = loopInfos.front()->getPreheaderIP();
868 }
869 loopInfos.push_back(ompBuilder->createCanonicalLoop(
870 loc, bodyGen, lowerBound, upperBound, step,
871 /*IsSigned=*/true, loop.getInclusive(), computeIP));
872
873 if (failed(bodyGenStatus))
874 return failure();
875 }
876
877 // Collapse loops. Store the insertion point because LoopInfos may get
878 // invalidated.
879 llvm::IRBuilderBase::InsertPoint afterIP = loopInfos.front()->getAfterIP();
880 llvm::CanonicalLoopInfo *loopInfo =
881 ompBuilder->collapseLoops(ompLoc.DL, loopInfos, {});
882
883 allocaIP = findAllocaInsertPoint(builder, moduleTranslation);
884
885 // TODO: Handle doacross loops when the ordered clause has a parameter.
886 bool isOrdered = loop.getOrderedVal().has_value();
887 std::optional<omp::ScheduleModifier> scheduleModifier =
888 loop.getScheduleModifier();
889 bool isSimd = loop.getSimdModifier();
890
891 ompBuilder->applyWorkshareLoop(
892 ompLoc.DL, loopInfo, allocaIP, !loop.getNowait(),
893 convertToScheduleKind(schedule), chunk, isSimd,
894 scheduleModifier == omp::ScheduleModifier::monotonic,
895 scheduleModifier == omp::ScheduleModifier::nonmonotonic, isOrdered);
896
897 // Continue building IR after the loop. Note that the LoopInfo returned by
898 // `collapseLoops` points inside the outermost loop and is intended for
899 // potential further loop transformations. Use the insertion point stored
900 // before collapsing loops instead.
901 builder.restoreIP(afterIP);
902
903 // Process the reductions if required.
904 if (numReductions == 0)
905 return success();
906
907 // Create the reduction generators. We need to own them here because
908 // ReductionInfo only accepts references to the generators.
909 SmallVector<OwningReductionGen> owningReductionGens;
910 SmallVector<OwningAtomicReductionGen> owningAtomicReductionGens;
911 for (unsigned i = 0; i < numReductions; ++i) {
912 owningReductionGens.push_back(
913 makeReductionGen(reductionDecls[i], builder, moduleTranslation));
914 owningAtomicReductionGens.push_back(
915 makeAtomicReductionGen(reductionDecls[i], builder, moduleTranslation));
916 }
917
918 // Collect the reduction information.
919 SmallVector<llvm::OpenMPIRBuilder::ReductionInfo> reductionInfos;
920 reductionInfos.reserve(numReductions);
921 for (unsigned i = 0; i < numReductions; ++i) {
922 llvm::OpenMPIRBuilder::AtomicReductionGenTy atomicGen = nullptr;
923 if (owningAtomicReductionGens[i])
924 atomicGen = owningAtomicReductionGens[i];
925 llvm::Value *variable =
926 moduleTranslation.lookupValue(loop.getReductionVars()[i]);
927 reductionInfos.push_back(
928 {moduleTranslation.convertType(reductionDecls[i].getType()), variable,
929 privateReductionVariables[i], owningReductionGens[i], atomicGen});
930 }
931
932 // The call to createReductions below expects the block to have a
933 // terminator. Create an unreachable instruction to serve as terminator
934 // and remove it later.
935 llvm::UnreachableInst *tempTerminator = builder.CreateUnreachable();
936 builder.SetInsertPoint(tempTerminator);
937 llvm::OpenMPIRBuilder::InsertPointTy contInsertPoint =
938 ompBuilder->createReductions(builder.saveIP(), allocaIP, reductionInfos,
939 loop.getNowait());
940 if (!contInsertPoint.getBlock())
941 return loop->emitOpError() << "failed to convert reductions";
942 auto nextInsertionPoint =
943 ompBuilder->createBarrier(contInsertPoint, llvm::omp::OMPD_for);
944 tempTerminator->eraseFromParent();
945 builder.restoreIP(nextInsertionPoint);
946
947 return success();
948}
949
950/// Converts an OpenMP simd loop into LLVM IR using OpenMPIRBuilder.
951static LogicalResult
952convertOmpSimdLoop(Operation &opInst, llvm::IRBuilderBase &builder,
953 LLVM::ModuleTranslation &moduleTranslation) {
954 auto loop = cast<omp::SimdLoopOp>(opInst);
955
956 llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
957
958 // Generator of the canonical loop body.
959 // TODO: support error propagation in OpenMPIRBuilder and use it instead of
960 // relying on captured variables.
961 SmallVector<llvm::CanonicalLoopInfo *> loopInfos;
962 SmallVector<llvm::OpenMPIRBuilder::InsertPointTy> bodyInsertPoints;
963 LogicalResult bodyGenStatus = success();
964 auto bodyGen = [&](llvm::OpenMPIRBuilder::InsertPointTy ip, llvm::Value *iv) {
965 // Make sure further conversions know about the induction variable.
966 moduleTranslation.mapValue(
967 loop.getRegion().front().getArgument(loopInfos.size()), iv);
968
969 // Capture the body insertion point for use in nested loops. BodyIP of the
970 // CanonicalLoopInfo always points to the beginning of the entry block of
971 // the body.
972 bodyInsertPoints.push_back(ip);
973
974 if (loopInfos.size() != loop.getNumLoops() - 1)
975 return;
976
977 // Convert the body of the loop.
978 builder.restoreIP(ip);
979 convertOmpOpRegions(loop.getRegion(), "omp.simdloop.region", builder,
980 moduleTranslation, bodyGenStatus);
981 };
982
983 // Delegate actual loop construction to the OpenMP IRBuilder.
984 // TODO: this currently assumes SimdLoop is semantically similar to SCF loop,
985 // i.e. it has a positive step, uses signed integer semantics. Reconsider
986 // this code when SimdLoop clearly supports more cases.
987 llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder();
988 for (unsigned i = 0, e = loop.getNumLoops(); i < e; ++i) {
989 llvm::Value *lowerBound =
990 moduleTranslation.lookupValue(loop.getLowerBound()[i]);
991 llvm::Value *upperBound =
992 moduleTranslation.lookupValue(loop.getUpperBound()[i]);
993 llvm::Value *step = moduleTranslation.lookupValue(loop.getStep()[i]);
994
995 // Make sure loop trip count are emitted in the preheader of the outermost
996 // loop at the latest so that they are all available for the new collapsed
997 // loop will be created below.
998 llvm::OpenMPIRBuilder::LocationDescription loc = ompLoc;
999 llvm::OpenMPIRBuilder::InsertPointTy computeIP = ompLoc.IP;
1000 if (i != 0) {
1001 loc = llvm::OpenMPIRBuilder::LocationDescription(bodyInsertPoints.back(),
1002 ompLoc.DL);
1003 computeIP = loopInfos.front()->getPreheaderIP();
1004 }
1005 loopInfos.push_back(ompBuilder->createCanonicalLoop(
1006 loc, bodyGen, lowerBound, upperBound, step,
1007 /*IsSigned=*/true, /*Inclusive=*/true, computeIP));
1008
1009 if (failed(bodyGenStatus))
1010 return failure();
1011 }
1012
1013 // Collapse loops.
1014 llvm::IRBuilderBase::InsertPoint afterIP = loopInfos.front()->getAfterIP();
1015 llvm::CanonicalLoopInfo *loopInfo =
1016 ompBuilder->collapseLoops(ompLoc.DL, loopInfos, {});
1017
1018 llvm::ConstantInt *simdlen = nullptr;
1019 if (std::optional<uint64_t> simdlenVar = loop.getSimdlen())
1020 simdlen = builder.getInt64(simdlenVar.value());
1021
1022 llvm::ConstantInt *safelen = nullptr;
1023 if (std::optional<uint64_t> safelenVar = loop.getSafelen())
1024 safelen = builder.getInt64(safelenVar.value());
1025
1026 llvm::MapVector<llvm::Value *, llvm::Value *> alignedVars;
1027 ompBuilder->applySimd(
1028 loopInfo, alignedVars,
1029 loop.getIfExpr() ? moduleTranslation.lookupValue(loop.getIfExpr())
1030 : nullptr,
1031 llvm::omp::OrderKind::OMP_ORDER_unknown, simdlen, safelen);
1032
1033 builder.restoreIP(afterIP);
1034 return success();
1035}
1036
1037/// Convert an Atomic Ordering attribute to llvm::AtomicOrdering.
1038llvm::AtomicOrdering
1039convertAtomicOrdering(std::optional<omp::ClauseMemoryOrderKind> ao) {
1040 if (!ao)
1041 return llvm::AtomicOrdering::Monotonic; // Default Memory Ordering
1042
1043 switch (*ao) {
1044 case omp::ClauseMemoryOrderKind::Seq_cst:
1045 return llvm::AtomicOrdering::SequentiallyConsistent;
1046 case omp::ClauseMemoryOrderKind::Acq_rel:
1047 return llvm::AtomicOrdering::AcquireRelease;
1048 case omp::ClauseMemoryOrderKind::Acquire:
1049 return llvm::AtomicOrdering::Acquire;
1050 case omp::ClauseMemoryOrderKind::Release:
1051 return llvm::AtomicOrdering::Release;
1052 case omp::ClauseMemoryOrderKind::Relaxed:
1053 return llvm::AtomicOrdering::Monotonic;
1054 }
1055 llvm_unreachable("Unknown ClauseMemoryOrderKind kind")::llvm::llvm_unreachable_internal("Unknown ClauseMemoryOrderKind kind"
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 1055)
;
1056}
1057
1058/// Convert omp.atomic.read operation to LLVM IR.
1059static LogicalResult
1060convertOmpAtomicRead(Operation &opInst, llvm::IRBuilderBase &builder,
1061 LLVM::ModuleTranslation &moduleTranslation) {
1062
1063 auto readOp = cast<omp::AtomicReadOp>(opInst);
1064 llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder();
1065
1066 llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
1067
1068 llvm::AtomicOrdering AO = convertAtomicOrdering(readOp.getMemoryOrderVal());
1069 llvm::Value *x = moduleTranslation.lookupValue(readOp.getX());
1070 llvm::Value *v = moduleTranslation.lookupValue(readOp.getV());
1071
1072 llvm::Type *elementType =
1073 moduleTranslation.convertType(readOp.getElementType());
1074
1075 llvm::OpenMPIRBuilder::AtomicOpValue V = {v, elementType, false, false};
1076 llvm::OpenMPIRBuilder::AtomicOpValue X = {x, elementType, false, false};
1077 builder.restoreIP(ompBuilder->createAtomicRead(ompLoc, X, V, AO));
1078 return success();
1079}
1080
1081/// Converts an omp.atomic.write operation to LLVM IR.
1082static LogicalResult
1083convertOmpAtomicWrite(Operation &opInst, llvm::IRBuilderBase &builder,
1084 LLVM::ModuleTranslation &moduleTranslation) {
1085 auto writeOp = cast<omp::AtomicWriteOp>(opInst);
1086 llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder();
1087
1088 llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
1089 llvm::AtomicOrdering ao = convertAtomicOrdering(writeOp.getMemoryOrderVal());
1090 llvm::Value *expr = moduleTranslation.lookupValue(writeOp.getValue());
1091 llvm::Value *dest = moduleTranslation.lookupValue(writeOp.getAddress());
1092 llvm::Type *ty = moduleTranslation.convertType(writeOp.getValue().getType());
1093 llvm::OpenMPIRBuilder::AtomicOpValue x = {dest, ty, /*isSigned=*/false,
1094 /*isVolatile=*/false};
1095 builder.restoreIP(ompBuilder->createAtomicWrite(ompLoc, x, expr, ao));
1096 return success();
1097}
1098
1099/// Converts an LLVM dialect binary operation to the corresponding enum value
1100/// for `atomicrmw` supported binary operation.
1101llvm::AtomicRMWInst::BinOp convertBinOpToAtomic(Operation &op) {
1102 return llvm::TypeSwitch<Operation *, llvm::AtomicRMWInst::BinOp>(&op)
1103 .Case([&](LLVM::AddOp) { return llvm::AtomicRMWInst::BinOp::Add; })
1104 .Case([&](LLVM::SubOp) { return llvm::AtomicRMWInst::BinOp::Sub; })
1105 .Case([&](LLVM::AndOp) { return llvm::AtomicRMWInst::BinOp::And; })
1106 .Case([&](LLVM::OrOp) { return llvm::AtomicRMWInst::BinOp::Or; })
1107 .Case([&](LLVM::XOrOp) { return llvm::AtomicRMWInst::BinOp::Xor; })
1108 .Case([&](LLVM::UMaxOp) { return llvm::AtomicRMWInst::BinOp::UMax; })
1109 .Case([&](LLVM::UMinOp) { return llvm::AtomicRMWInst::BinOp::UMin; })
1110 .Case([&](LLVM::FAddOp) { return llvm::AtomicRMWInst::BinOp::FAdd; })
1111 .Case([&](LLVM::FSubOp) { return llvm::AtomicRMWInst::BinOp::FSub; })
1112 .Default(llvm::AtomicRMWInst::BinOp::BAD_BINOP);
1113}
1114
1115/// Converts an OpenMP atomic update operation using OpenMPIRBuilder.
1116static LogicalResult
1117convertOmpAtomicUpdate(omp::AtomicUpdateOp &opInst,
1118 llvm::IRBuilderBase &builder,
1119 LLVM::ModuleTranslation &moduleTranslation) {
1120 llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder();
1121
1122 // Convert values and types.
1123 auto &innerOpList = opInst.getRegion().front().getOperations();
1124 if (innerOpList.size() != 2)
1125 return opInst.emitError("exactly two operations are allowed inside an "
1126 "atomic update region while lowering to LLVM IR");
1127
1128 Operation &innerUpdateOp = innerOpList.front();
1129
1130 if (innerUpdateOp.getNumOperands() != 2 ||
1131 !llvm::is_contained(innerUpdateOp.getOperands(),
1132 opInst.getRegion().getArgument(0)))
1133 return opInst.emitError(
1134 "the update operation inside the region must be a binary operation and "
1135 "that update operation must have the region argument as an operand");
1136
1137 llvm::AtomicRMWInst::BinOp binop = convertBinOpToAtomic(innerUpdateOp);
1138
1139 bool isXBinopExpr =
1140 innerUpdateOp.getNumOperands() > 0 &&
1141 innerUpdateOp.getOperand(0) == opInst.getRegion().getArgument(0);
1142
1143 mlir::Value mlirExpr = (isXBinopExpr ? innerUpdateOp.getOperand(1)
1144 : innerUpdateOp.getOperand(0));
1145 llvm::Value *llvmExpr = moduleTranslation.lookupValue(mlirExpr);
1146 llvm::Value *llvmX = moduleTranslation.lookupValue(opInst.getX());
1147 llvm::Type *llvmXElementType = moduleTranslation.convertType(
1148 opInst.getRegion().getArgument(0).getType());
1149 llvm::OpenMPIRBuilder::AtomicOpValue llvmAtomicX = {llvmX, llvmXElementType,
1150 /*isSigned=*/false,
1151 /*isVolatile=*/false};
1152
1153 llvm::AtomicOrdering atomicOrdering =
1154 convertAtomicOrdering(opInst.getMemoryOrderVal());
1155
1156 // Generate update code.
1157 LogicalResult updateGenStatus = success();
1158 auto updateFn = [&opInst, &moduleTranslation, &updateGenStatus](
1159 llvm::Value *atomicx,
1160 llvm::IRBuilder<> &builder) -> llvm::Value * {
1161 Block &bb = *opInst.getRegion().begin();
1162 moduleTranslation.mapValue(*opInst.getRegion().args_begin(), atomicx);
1163 moduleTranslation.mapBlock(&bb, builder.GetInsertBlock());
1164 if (failed(moduleTranslation.convertBlock(bb, true, builder))) {
1165 updateGenStatus = (opInst.emitError()
1166 << "unable to convert update operation to llvm IR");
1167 return nullptr;
1168 }
1169 omp::YieldOp yieldop = dyn_cast<omp::YieldOp>(bb.getTerminator());
1170 assert(yieldop && yieldop.getResults().size() == 1 &&(static_cast <bool> (yieldop && yieldop.getResults
().size() == 1 && "terminator must be omp.yield op and it must have exactly one "
"argument") ? void (0) : __assert_fail ("yieldop && yieldop.getResults().size() == 1 && \"terminator must be omp.yield op and it must have exactly one \" \"argument\""
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 1172, __extension__ __PRETTY_FUNCTION__))
1171 "terminator must be omp.yield op and it must have exactly one "(static_cast <bool> (yieldop && yieldop.getResults
().size() == 1 && "terminator must be omp.yield op and it must have exactly one "
"argument") ? void (0) : __assert_fail ("yieldop && yieldop.getResults().size() == 1 && \"terminator must be omp.yield op and it must have exactly one \" \"argument\""
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 1172, __extension__ __PRETTY_FUNCTION__))
1172 "argument")(static_cast <bool> (yieldop && yieldop.getResults
().size() == 1 && "terminator must be omp.yield op and it must have exactly one "
"argument") ? void (0) : __assert_fail ("yieldop && yieldop.getResults().size() == 1 && \"terminator must be omp.yield op and it must have exactly one \" \"argument\""
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 1172, __extension__ __PRETTY_FUNCTION__))
;
1173 return moduleTranslation.lookupValue(yieldop.getResults()[0]);
1174 };
1175
1176 // Handle ambiguous alloca, if any.
1177 auto allocaIP = findAllocaInsertPoint(builder, moduleTranslation);
1178 llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
1179 builder.restoreIP(ompBuilder->createAtomicUpdate(
1180 ompLoc, allocaIP, llvmAtomicX, llvmExpr, atomicOrdering, binop, updateFn,
1181 isXBinopExpr));
1182 return updateGenStatus;
1183}
1184
1185static LogicalResult
1186convertOmpAtomicCapture(omp::AtomicCaptureOp atomicCaptureOp,
1187 llvm::IRBuilderBase &builder,
1188 LLVM::ModuleTranslation &moduleTranslation) {
1189 llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder();
1190 mlir::Value mlirExpr;
1191 bool isXBinopExpr = false, isPostfixUpdate = false;
1192 llvm::AtomicRMWInst::BinOp binop = llvm::AtomicRMWInst::BinOp::BAD_BINOP;
1193
1194 omp::AtomicUpdateOp atomicUpdateOp = atomicCaptureOp.getAtomicUpdateOp();
1195 omp::AtomicWriteOp atomicWriteOp = atomicCaptureOp.getAtomicWriteOp();
1196
1197 assert((atomicUpdateOp || atomicWriteOp) &&(static_cast <bool> ((atomicUpdateOp || atomicWriteOp) &&
"internal op must be an atomic.update or atomic.write op") ?
void (0) : __assert_fail ("(atomicUpdateOp || atomicWriteOp) && \"internal op must be an atomic.update or atomic.write op\""
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 1198, __extension__ __PRETTY_FUNCTION__))
1198 "internal op must be an atomic.update or atomic.write op")(static_cast <bool> ((atomicUpdateOp || atomicWriteOp) &&
"internal op must be an atomic.update or atomic.write op") ?
void (0) : __assert_fail ("(atomicUpdateOp || atomicWriteOp) && \"internal op must be an atomic.update or atomic.write op\""
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 1198, __extension__ __PRETTY_FUNCTION__))
;
1199
1200 if (atomicWriteOp) {
1201 isPostfixUpdate = true;
1202 mlirExpr = atomicWriteOp.getValue();
1203 } else {
1204 isPostfixUpdate = atomicCaptureOp.getSecondOp() ==
1205 atomicCaptureOp.getAtomicUpdateOp().getOperation();
1206 auto &innerOpList = atomicUpdateOp.getRegion().front().getOperations();
1207 if (innerOpList.size() != 2)
1208 return atomicUpdateOp.emitError(
1209 "exactly two operations are allowed inside an "
1210 "atomic update region while lowering to LLVM IR");
1211 Operation *innerUpdateOp = atomicUpdateOp.getFirstOp();
1212 if (innerUpdateOp->getNumOperands() != 2 ||
1213 !llvm::is_contained(innerUpdateOp->getOperands(),
1214 atomicUpdateOp.getRegion().getArgument(0)))
1215 return atomicUpdateOp.emitError(
1216 "the update operation inside the region must be a binary operation "
1217 "and that update operation must have the region argument as an "
1218 "operand");
1219 binop = convertBinOpToAtomic(*innerUpdateOp);
1220
1221 isXBinopExpr = innerUpdateOp->getOperand(0) ==
1222 atomicUpdateOp.getRegion().getArgument(0);
1223
1224 mlirExpr = (isXBinopExpr ? innerUpdateOp->getOperand(1)
1225 : innerUpdateOp->getOperand(0));
1226 }
1227
1228 llvm::Value *llvmExpr = moduleTranslation.lookupValue(mlirExpr);
1229 llvm::Value *llvmX =
1230 moduleTranslation.lookupValue(atomicCaptureOp.getAtomicReadOp().getX());
1231 llvm::Value *llvmV =
1232 moduleTranslation.lookupValue(atomicCaptureOp.getAtomicReadOp().getV());
1233 llvm::Type *llvmXElementType = moduleTranslation.convertType(
1234 atomicCaptureOp.getAtomicReadOp().getElementType());
1235 llvm::OpenMPIRBuilder::AtomicOpValue llvmAtomicX = {llvmX, llvmXElementType,
1236 /*isSigned=*/false,
1237 /*isVolatile=*/false};
1238 llvm::OpenMPIRBuilder::AtomicOpValue llvmAtomicV = {llvmV, llvmXElementType,
1239 /*isSigned=*/false,
1240 /*isVolatile=*/false};
1241
1242 llvm::AtomicOrdering atomicOrdering =
1243 convertAtomicOrdering(atomicCaptureOp.getMemoryOrderVal());
1244
1245 LogicalResult updateGenStatus = success();
1246 auto updateFn = [&](llvm::Value *atomicx,
1247 llvm::IRBuilder<> &builder) -> llvm::Value * {
1248 if (atomicWriteOp)
1249 return moduleTranslation.lookupValue(atomicWriteOp.getValue());
1250 Block &bb = *atomicUpdateOp.getRegion().begin();
1251 moduleTranslation.mapValue(*atomicUpdateOp.getRegion().args_begin(),
1252 atomicx);
1253 moduleTranslation.mapBlock(&bb, builder.GetInsertBlock());
1254 if (failed(moduleTranslation.convertBlock(bb, true, builder))) {
1255 updateGenStatus = (atomicUpdateOp.emitError()
1256 << "unable to convert update operation to llvm IR");
1257 return nullptr;
1258 }
1259 omp::YieldOp yieldop = dyn_cast<omp::YieldOp>(bb.getTerminator());
1260 assert(yieldop && yieldop.getResults().size() == 1 &&(static_cast <bool> (yieldop && yieldop.getResults
().size() == 1 && "terminator must be omp.yield op and it must have exactly one "
"argument") ? void (0) : __assert_fail ("yieldop && yieldop.getResults().size() == 1 && \"terminator must be omp.yield op and it must have exactly one \" \"argument\""
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 1262, __extension__ __PRETTY_FUNCTION__))
1261 "terminator must be omp.yield op and it must have exactly one "(static_cast <bool> (yieldop && yieldop.getResults
().size() == 1 && "terminator must be omp.yield op and it must have exactly one "
"argument") ? void (0) : __assert_fail ("yieldop && yieldop.getResults().size() == 1 && \"terminator must be omp.yield op and it must have exactly one \" \"argument\""
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 1262, __extension__ __PRETTY_FUNCTION__))
1262 "argument")(static_cast <bool> (yieldop && yieldop.getResults
().size() == 1 && "terminator must be omp.yield op and it must have exactly one "
"argument") ? void (0) : __assert_fail ("yieldop && yieldop.getResults().size() == 1 && \"terminator must be omp.yield op and it must have exactly one \" \"argument\""
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 1262, __extension__ __PRETTY_FUNCTION__))
;
1263 return moduleTranslation.lookupValue(yieldop.getResults()[0]);
1264 };
1265
1266 // Handle ambiguous alloca, if any.
1267 auto allocaIP = findAllocaInsertPoint(builder, moduleTranslation);
1268 llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
1269 builder.restoreIP(ompBuilder->createAtomicCapture(
1270 ompLoc, allocaIP, llvmAtomicX, llvmAtomicV, llvmExpr, atomicOrdering,
1271 binop, updateFn, atomicUpdateOp, isPostfixUpdate, isXBinopExpr));
1272 return updateGenStatus;
1273}
1274
1275/// Converts an OpenMP reduction operation using OpenMPIRBuilder. Expects the
1276/// mapping between reduction variables and their private equivalents to have
1277/// been stored on the ModuleTranslation stack. Currently only supports
1278/// reduction within WsLoopOp, but can be easily extended.
1279static LogicalResult
1280convertOmpReductionOp(omp::ReductionOp reductionOp,
1281 llvm::IRBuilderBase &builder,
1282 LLVM::ModuleTranslation &moduleTranslation) {
1283 // Find the declaration that corresponds to the reduction op.
1284 auto reductionContainer = reductionOp->getParentOfType<omp::WsLoopOp>();
1285 omp::ReductionDeclareOp declaration =
1286 findReductionDecl(reductionContainer, reductionOp);
1287 assert(declaration && "could not find reduction declaration")(static_cast <bool> (declaration && "could not find reduction declaration"
) ? void (0) : __assert_fail ("declaration && \"could not find reduction declaration\""
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 1287, __extension__ __PRETTY_FUNCTION__))
;
1288
1289 // Retrieve the mapping between reduction variables and their private
1290 // equivalents.
1291 const DenseMap<Value, llvm::Value *> *reductionVariableMap = nullptr;
1292 moduleTranslation.stackWalk<OpenMPVarMappingStackFrame>(
1293 [&](const OpenMPVarMappingStackFrame &frame) {
1294 reductionVariableMap = &frame.mapping;
1295 return WalkResult::interrupt();
1296 });
1297 assert(reductionVariableMap && "couldn't find private reduction variables")(static_cast <bool> (reductionVariableMap && "couldn't find private reduction variables"
) ? void (0) : __assert_fail ("reductionVariableMap && \"couldn't find private reduction variables\""
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 1297, __extension__ __PRETTY_FUNCTION__))
;
1298
1299 // Translate the reduction operation by emitting the body of the corresponding
1300 // reduction declaration.
1301 Region &reductionRegion = declaration.getReductionRegion();
1302 llvm::Value *privateReductionVar =
1303 reductionVariableMap->lookup(reductionOp.getAccumulator());
1304 llvm::Value *reductionVal = builder.CreateLoad(
1305 moduleTranslation.convertType(reductionOp.getOperand().getType()),
1306 privateReductionVar);
1307
1308 moduleTranslation.mapValue(reductionRegion.front().getArgument(0),
1309 reductionVal);
1310 moduleTranslation.mapValue(
1311 reductionRegion.front().getArgument(1),
1312 moduleTranslation.lookupValue(reductionOp.getOperand()));
1313
1314 SmallVector<llvm::Value *> phis;
1315 if (failed(inlineConvertOmpRegions(reductionRegion, "omp.reduction.body",
1316 builder, moduleTranslation, &phis)))
1317 return failure();
1318 assert(phis.size() == 1 && "expected one value to be yielded from "(static_cast <bool> (phis.size() == 1 && "expected one value to be yielded from "
"the reduction body declaration region") ? void (0) : __assert_fail
("phis.size() == 1 && \"expected one value to be yielded from \" \"the reduction body declaration region\""
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 1319, __extension__ __PRETTY_FUNCTION__))
1319 "the reduction body declaration region")(static_cast <bool> (phis.size() == 1 && "expected one value to be yielded from "
"the reduction body declaration region") ? void (0) : __assert_fail
("phis.size() == 1 && \"expected one value to be yielded from \" \"the reduction body declaration region\""
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 1319, __extension__ __PRETTY_FUNCTION__))
;
1320 builder.CreateStore(phis[0], privateReductionVar);
1321 return success();
1322}
1323
1324/// Converts an OpenMP Threadprivate operation into LLVM IR using
1325/// OpenMPIRBuilder.
1326static LogicalResult
1327convertOmpThreadprivate(Operation &opInst, llvm::IRBuilderBase &builder,
1328 LLVM::ModuleTranslation &moduleTranslation) {
1329 llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
1330 auto threadprivateOp = cast<omp::ThreadprivateOp>(opInst);
1331
1332 Value symAddr = threadprivateOp.getSymAddr();
1333 auto *symOp = symAddr.getDefiningOp();
1334 if (!isa<LLVM::AddressOfOp>(symOp))
1335 return opInst.emitError("Addressing symbol not found");
1336 LLVM::AddressOfOp addressOfOp = dyn_cast<LLVM::AddressOfOp>(symOp);
1337
1338 LLVM::GlobalOp global =
1339 addressOfOp.getGlobal(moduleTranslation.symbolTable());
1340 llvm::GlobalValue *globalValue = moduleTranslation.lookupGlobal(global);
1341 llvm::Value *data =
1342 builder.CreateBitCast(globalValue, builder.getInt8PtrTy());
1343 llvm::Type *type = globalValue->getValueType();
1344 llvm::TypeSize typeSize =
1345 builder.GetInsertBlock()->getModule()->getDataLayout().getTypeStoreSize(
1346 type);
1347 llvm::ConstantInt *size = builder.getInt64(typeSize.getFixedValue());
1348 llvm::StringRef suffix = llvm::StringRef(".cache", 6);
1349 std::string cacheName = (Twine(global.getSymName()).concat(suffix)).str();
1350 // Emit runtime function and bitcast its type (i8*) to real data type.
1351 llvm::Value *callInst =
1352 moduleTranslation.getOpenMPBuilder()->createCachedThreadPrivate(
1353 ompLoc, data, size, cacheName);
1354 llvm::Value *result = builder.CreateBitCast(callInst, globalValue->getType());
1355 moduleTranslation.mapValue(opInst.getResult(0), result);
1356 return success();
1357}
1358
1359/// Process MapOperands for Target Data directives.
1360static LogicalResult processMapOperand(
1361 llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation,
1362 const SmallVector<Value> &mapOperands, const ArrayAttr &mapTypes,
1363 SmallVector<uint64_t> &mapTypeFlags,
1364 SmallVectorImpl<llvm::Constant *> &mapNames,
1365 struct llvm::OpenMPIRBuilder::MapperAllocas &mapperAllocas) {
1366 auto numMapOperands = mapOperands.size();
1367 llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder();
1368 llvm::PointerType *i8PtrTy = builder.getInt8PtrTy();
1369 llvm::ArrayType *arrI8PtrTy = llvm::ArrayType::get(i8PtrTy, numMapOperands);
1370 llvm::IntegerType *i64Ty = builder.getInt64Ty();
1371 llvm::ArrayType *arrI64Ty = llvm::ArrayType::get(i64Ty, numMapOperands);
1372
1373 unsigned index = 0;
1374 for (const auto &mapOp : mapOperands) {
1375 const auto &mapTypeOp = mapTypes[index];
1376
1377 llvm::Value *mapOpValue = moduleTranslation.lookupValue(mapOp);
1378 llvm::Value *mapOpPtrBase;
1379 llvm::Value *mapOpPtr;
1380 llvm::Value *mapOpSize;
1381
1382 if (mapOp.getType().isa<LLVM::LLVMPointerType>()) {
1383 mapOpPtrBase = mapOpValue;
1384 mapOpPtr = mapOpValue;
1385 mapOpSize = ompBuilder->getSizeInBytes(mapOpValue);
1386 } else {
1387 return failure();
1388 }
1389
1390 // Store base pointer extracted from operand into the i-th position of
1391 // argBase.
1392 llvm::Value *ptrBaseGEP = builder.CreateInBoundsGEP(
1393 arrI8PtrTy, mapperAllocas.ArgsBase,
1394 {builder.getInt32(0), builder.getInt32(index)});
1395 llvm::Value *ptrBaseCast = builder.CreateBitCast(
1396 ptrBaseGEP, mapOpPtrBase->getType()->getPointerTo());
1397 builder.CreateStore(mapOpPtrBase, ptrBaseCast);
1398
1399 // Store pointer extracted from operand into the i-th position of args.
1400 llvm::Value *ptrGEP = builder.CreateInBoundsGEP(
1401 arrI8PtrTy, mapperAllocas.Args,
1402 {builder.getInt32(0), builder.getInt32(index)});
1403 llvm::Value *ptrCast =
1404 builder.CreateBitCast(ptrGEP, mapOpPtr->getType()->getPointerTo());
1405 builder.CreateStore(mapOpPtr, ptrCast);
1406
1407 // Store size extracted from operand into the i-th position of argSizes.
1408 llvm::Value *sizeGEP = builder.CreateInBoundsGEP(
1409 arrI64Ty, mapperAllocas.ArgSizes,
1410 {builder.getInt32(0), builder.getInt32(index)});
1411 builder.CreateStore(mapOpSize, sizeGEP);
1412
1413 mapTypeFlags.push_back(mapTypeOp.dyn_cast<mlir::IntegerAttr>().getInt());
1414 llvm::Constant *mapName =
1415 mlir::LLVM::createMappingInformation(mapOp.getLoc(), *ompBuilder);
1416 mapNames.push_back(mapName);
1417 ++index;
1418 }
1419
1420 return success();
1421}
1422
1423static LogicalResult
1424convertOmpTargetData(Operation *op, llvm::IRBuilderBase &builder,
1425 LLVM::ModuleTranslation &moduleTranslation) {
1426 unsigned numMapOperands;
1427 llvm::Value *ifCond = nullptr;
1428 int64_t deviceID = llvm::omp::OMP_DEVICEID_UNDEF;
1429 SmallVector<Value> mapOperands;
1430 ArrayAttr mapTypes;
1431
1432 llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder();
1433
1434 LogicalResult result =
1435 llvm::TypeSwitch<Operation *, LogicalResult>(op)
1436 .Case([&](omp::DataOp dataOp) {
1437 if (!dataOp.getUseDeviceAddr().empty() ||
1438 !dataOp.getUseDevicePtr().empty())
1439 return failure();
1440
1441 if (auto ifExprVar = dataOp.getIfExpr())
1442 ifCond = moduleTranslation.lookupValue(ifExprVar);
1443
1444 if (auto devId = dataOp.getDevice())
1445 if (auto constOp = mlir::dyn_cast<mlir::LLVM::ConstantOp>(
1446 devId.getDefiningOp()))
1447 if (auto intAttr =
1448 constOp.getValue().dyn_cast<mlir::IntegerAttr>())
1449 deviceID = intAttr.getInt();
1450
1451 numMapOperands = dataOp.getMapOperands().size();
1452 mapOperands = dataOp.getMapOperands();
1453 mapTypes = dataOp.getMapTypes();
1454 return success();
1455 })
1456 .Case([&](omp::EnterDataOp enterDataOp) {
1457 if (enterDataOp.getNowait())
1458 return failure();
1459
1460 if (auto ifExprVar = enterDataOp.getIfExpr())
1461 ifCond = moduleTranslation.lookupValue(ifExprVar);
1462
1463 if (auto devId = enterDataOp.getDevice())
1464 if (auto constOp = mlir::dyn_cast<mlir::LLVM::ConstantOp>(
1465 devId.getDefiningOp()))
1466 if (auto intAttr =
1467 constOp.getValue().dyn_cast<mlir::IntegerAttr>())
1468 deviceID = intAttr.getInt();
1469
1470 numMapOperands = enterDataOp.getMapOperands().size();
1471 mapOperands = enterDataOp.getMapOperands();
1472 mapTypes = enterDataOp.getMapTypes();
1473 return success();
1474 })
1475 .Case([&](omp::ExitDataOp exitDataOp) {
1476 if (exitDataOp.getNowait())
1477 return failure();
1478
1479 if (auto ifExprVar = exitDataOp.getIfExpr())
1480 ifCond = moduleTranslation.lookupValue(ifExprVar);
1481
1482 if (auto devId = exitDataOp.getDevice())
1483 if (auto constOp = mlir::dyn_cast<mlir::LLVM::ConstantOp>(
1484 devId.getDefiningOp()))
1485 if (auto intAttr =
1486 constOp.getValue().dyn_cast<mlir::IntegerAttr>())
1487 deviceID = intAttr.getInt();
1488
1489 numMapOperands = exitDataOp.getMapOperands().size();
1490 mapOperands = exitDataOp.getMapOperands();
1491 mapTypes = exitDataOp.getMapTypes();
1492 return success();
1493 })
1494 .Default([&](Operation *op) {
1495 return op->emitError("unsupported OpenMP operation: ")
1496 << op->getName();
1497 });
1498
1499 if (failed(result))
1500 return failure();
1501
1502 llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
1503 llvm::OpenMPIRBuilder::InsertPointTy allocaIP =
1504 findAllocaInsertPoint(builder, moduleTranslation);
1505
1506 struct llvm::OpenMPIRBuilder::MapperAllocas mapperAllocas;
1507 SmallVector<uint64_t> mapTypeFlags;
1508 SmallVector<llvm::Constant *> mapNames;
1509 ompBuilder->createMapperAllocas(builder.saveIP(), allocaIP, numMapOperands,
1510 mapperAllocas);
1511
1512 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
1513 LogicalResult processMapOpStatus = success();
1514 auto processMapOpCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP) {
1515 builder.restoreIP(codeGenIP);
1516 processMapOpStatus =
1517 processMapOperand(builder, moduleTranslation, mapOperands, mapTypes,
1518 mapTypeFlags, mapNames, mapperAllocas);
1519 };
1520
1521 LogicalResult bodyGenStatus = success();
1522 auto bodyCB = [&](InsertPointTy allocaIP, InsertPointTy codeGenIP) {
1523 // DataOp has only one region associated with it.
1524 auto &region = cast<omp::DataOp>(op).getRegion();
1525 builder.restoreIP(codeGenIP);
1526 bodyGenStatus = inlineConvertOmpRegions(region, "omp.data.region", builder,
1527 moduleTranslation);
1528 };
1529
1530 if (isa<omp::DataOp>(op)) {
1531 builder.restoreIP(ompBuilder->createTargetData(
1532 ompLoc, builder.saveIP(), mapTypeFlags, mapNames, mapperAllocas,
1533 /*IsBegin=*/false, deviceID, ifCond, processMapOpCB, bodyCB));
1534 } else {
1535 builder.restoreIP(ompBuilder->createTargetData(
1536 ompLoc, builder.saveIP(), mapTypeFlags, mapNames, mapperAllocas,
1537 isa<omp::EnterDataOp>(op), deviceID, ifCond, processMapOpCB));
1538 }
1539
1540 if (failed(processMapOpStatus))
1541 return processMapOpStatus;
1542 return bodyGenStatus;
1543}
1544
1545/// Lowers the FlagsAttr which is applied to the module on the device
1546/// pass when offloading, this attribute contains OpenMP RTL globals that can
1547/// be passed as flags to the frontend, otherwise they are set to default
1548LogicalResult convertFlagsAttr(Operation *op, mlir::omp::FlagsAttr attribute,
1549 LLVM::ModuleTranslation &moduleTranslation) {
1550 if (!cast<mlir::ModuleOp>(op))
1551 return failure();
1552
1553 llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder();
1554
1555 ompBuilder->createGlobalFlag(
1556 attribute.getDebugKind() /*LangOpts().OpenMPTargetDebug*/,
1557 "__omp_rtl_debug_kind");
1558 ompBuilder->createGlobalFlag(
1559 attribute
1560 .getAssumeTeamsOversubscription() /*LangOpts().OpenMPTeamSubscription*/
1561 ,
1562 "__omp_rtl_assume_teams_oversubscription");
1563 ompBuilder->createGlobalFlag(
1564 attribute
1565 .getAssumeThreadsOversubscription() /*LangOpts().OpenMPThreadSubscription*/
1566 ,
1567 "__omp_rtl_assume_threads_oversubscription");
1568 ompBuilder->createGlobalFlag(
1569 attribute.getAssumeNoThreadState() /*LangOpts().OpenMPNoThreadState*/,
1570 "__omp_rtl_assume_no_thread_state");
1571 ompBuilder->createGlobalFlag(
1572 attribute
1573 .getAssumeNoNestedParallelism() /*LangOpts().OpenMPNoNestedParallelism*/
1574 ,
1575 "__omp_rtl_assume_no_nested_parallelism");
1576
1577 return success();
1578}
1579
1580static bool getTargetEntryUniqueInfo(llvm::TargetRegionEntryInfo &targetInfo,
1581 omp::TargetOp targetOp,
1582 llvm::StringRef parentName = "") {
1583 auto fileLoc = targetOp.getLoc()->findInstanceOf<FileLineColLoc>();
1584
1585 assert(fileLoc && "No file found from location")(static_cast <bool> (fileLoc && "No file found from location"
) ? void (0) : __assert_fail ("fileLoc && \"No file found from location\""
, "mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp"
, 1585, __extension__ __PRETTY_FUNCTION__))
;
1586 StringRef fileName = fileLoc.getFilename().getValue();
1587
1588 llvm::sys::fs::UniqueID id;
1589 if (auto ec = llvm::sys::fs::getUniqueID(fileName, id)) {
1590 targetOp.emitError("Unable to get unique ID for file");
1591 return false;
1592 }
1593
1594 uint64_t line = fileLoc.getLine();
1595 targetInfo = llvm::TargetRegionEntryInfo(parentName, id.getDevice(),
1596 id.getFile(), line);
1597 return true;
1598}
1599
1600static bool targetOpSupported(Operation &opInst) {
1601 auto targetOp = cast<omp::TargetOp>(opInst);
1602 if (targetOp.getIfExpr()) {
1603 opInst.emitError("If clause not yet supported");
1604 return false;
1605 }
1606
1607 if (targetOp.getDevice()) {
1608 opInst.emitError("Device clause not yet supported");
1609 return false;
1610 }
1611
1612 if (targetOp.getThreadLimit()) {
1613 opInst.emitError("Thread limit clause not yet supported");
1614 return false;
1615 }
1616
1617 if (targetOp.getNowait()) {
1618 opInst.emitError("Nowait clause not yet supported");
1619 return false;
1620 }
1621
1622 return true;
1623}
1624
1625static LogicalResult
1626convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
1627 LLVM::ModuleTranslation &moduleTranslation) {
1628
1629 if (!targetOpSupported(opInst))
1630 return failure();
1631
1632 bool isDevice = false;
1633 if (auto offloadMod = dyn_cast<mlir::omp::OffloadModuleInterface>(
1634 opInst.getParentOfType<mlir::ModuleOp>().getOperation())) {
1635 isDevice = offloadMod.getIsDevice();
1636 }
1637
1638 if (isDevice) // TODO: Implement device codegen.
1639 return success();
1640
1641 auto targetOp = cast<omp::TargetOp>(opInst);
1642 auto &targetRegion = targetOp.getRegion();
1643
1644 llvm::SetVector<Value> operandSet;
1645 getUsedValuesDefinedAbove(targetRegion, operandSet);
1646
1647 // Collect the input arguments.
1648 llvm::SmallVector<llvm::Value *> inputs;
1649 for (Value operand : operandSet)
1650 inputs.push_back(moduleTranslation.lookupValue(operand));
1651
1652 LogicalResult bodyGenStatus = success();
1653
1654 using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
1655 auto bodyCB = [&](InsertPointTy allocaIP,
1656 InsertPointTy codeGenIP) -> InsertPointTy {
1657 builder.restoreIP(codeGenIP);
1658 llvm::BasicBlock *exitBlock = convertOmpOpRegions(
1
Passing null pointer value via 6th parameter 'continuationBlockPHIs'
2
Calling 'convertOmpOpRegions'
1659 targetRegion, "omp.target", builder, moduleTranslation, bodyGenStatus);
1660 builder.SetInsertPoint(exitBlock);
1661 return builder.saveIP();
1662 };
1663
1664 llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder);
1665 StringRef parentName = opInst.getParentOfType<LLVM::LLVMFuncOp>().getName();
1666 llvm::TargetRegionEntryInfo entryInfo;
1667
1668 if (!getTargetEntryUniqueInfo(entryInfo, targetOp, parentName))
1669 return failure();
1670
1671 int32_t defaultValTeams = -1;
1672 int32_t defaultValThreads = -1;
1673
1674 builder.restoreIP(moduleTranslation.getOpenMPBuilder()->createTarget(
1675 ompLoc, builder.saveIP(), entryInfo, defaultValTeams, defaultValThreads,
1676 inputs, bodyCB));
1677
1678 return bodyGenStatus;
1679}
1680
1681namespace {
1682
1683/// Implementation of the dialect interface that converts operations belonging
1684/// to the OpenMP dialect to LLVM IR.
1685class OpenMPDialectLLVMIRTranslationInterface
1686 : public LLVMTranslationDialectInterface {
1687public:
1688 using LLVMTranslationDialectInterface::LLVMTranslationDialectInterface;
1689
1690 /// Translates the given operation to LLVM IR using the provided IR builder
1691 /// and saving the state in `moduleTranslation`.
1692 LogicalResult
1693 convertOperation(Operation *op, llvm::IRBuilderBase &builder,
1694 LLVM::ModuleTranslation &moduleTranslation) const final;
1695
1696 LogicalResult
1697 amendOperation(Operation *op, NamedAttribute attribute,
1698 LLVM::ModuleTranslation &moduleTranslation) const final;
1699};
1700
1701} // namespace
1702
1703/// Given an OpenMP MLIR attribute, create the corresponding LLVM-IR, runtime
1704/// calls, or operation amendments
1705LogicalResult OpenMPDialectLLVMIRTranslationInterface::amendOperation(
1706 Operation *op, NamedAttribute attribute,
1707 LLVM::ModuleTranslation &moduleTranslation) const {
1708
1709 return llvm::TypeSwitch<Attribute, LogicalResult>(attribute.getValue())
1710 .Case([&](mlir::omp::FlagsAttr rtlAttr) {
1711 return convertFlagsAttr(op, rtlAttr, moduleTranslation);
1712 })
1713 .Default([&](Attribute attr) {
1714 // fall through for omp attributes that do not require lowering and/or
1715 // have no concrete definition and thus no type to define a case on
1716 return success();
1717 });
1718
1719 return failure();
1720}
1721
1722/// Given an OpenMP MLIR operation, create the corresponding LLVM IR
1723/// (including OpenMP runtime calls).
1724LogicalResult OpenMPDialectLLVMIRTranslationInterface::convertOperation(
1725 Operation *op, llvm::IRBuilderBase &builder,
1726 LLVM::ModuleTranslation &moduleTranslation) const {
1727
1728 llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder();
1729
1730 return llvm::TypeSwitch<Operation *, LogicalResult>(op)
1731 .Case([&](omp::BarrierOp) {
1732 ompBuilder->createBarrier(builder.saveIP(), llvm::omp::OMPD_barrier);
1733 return success();
1734 })
1735 .Case([&](omp::TaskwaitOp) {
1736 ompBuilder->createTaskwait(builder.saveIP());
1737 return success();
1738 })
1739 .Case([&](omp::TaskyieldOp) {
1740 ompBuilder->createTaskyield(builder.saveIP());
1741 return success();
1742 })
1743 .Case([&](omp::FlushOp) {
1744 // No support in Openmp runtime function (__kmpc_flush) to accept
1745 // the argument list.
1746 // OpenMP standard states the following:
1747 // "An implementation may implement a flush with a list by ignoring
1748 // the list, and treating it the same as a flush without a list."
1749 //
1750 // The argument list is discarded so that, flush with a list is treated
1751 // same as a flush without a list.
1752 ompBuilder->createFlush(builder.saveIP());
1753 return success();
1754 })
1755 .Case([&](omp::ParallelOp op) {
1756 return convertOmpParallel(op, builder, moduleTranslation);
1757 })
1758 .Case([&](omp::ReductionOp reductionOp) {
1759 return convertOmpReductionOp(reductionOp, builder, moduleTranslation);
1760 })
1761 .Case([&](omp::MasterOp) {
1762 return convertOmpMaster(*op, builder, moduleTranslation);
1763 })
1764 .Case([&](omp::CriticalOp) {
1765 return convertOmpCritical(*op, builder, moduleTranslation);
1766 })
1767 .Case([&](omp::OrderedRegionOp) {
1768 return convertOmpOrderedRegion(*op, builder, moduleTranslation);
1769 })
1770 .Case([&](omp::OrderedOp) {
1771 return convertOmpOrdered(*op, builder, moduleTranslation);
1772 })
1773 .Case([&](omp::WsLoopOp) {
1774 return convertOmpWsLoop(*op, builder, moduleTranslation);
1775 })
1776 .Case([&](omp::SimdLoopOp) {
1777 return convertOmpSimdLoop(*op, builder, moduleTranslation);
1778 })
1779 .Case([&](omp::AtomicReadOp) {
1780 return convertOmpAtomicRead(*op, builder, moduleTranslation);
1781 })
1782 .Case([&](omp::AtomicWriteOp) {
1783 return convertOmpAtomicWrite(*op, builder, moduleTranslation);
1784 })
1785 .Case([&](omp::AtomicUpdateOp op) {
1786 return convertOmpAtomicUpdate(op, builder, moduleTranslation);
1787 })
1788 .Case([&](omp::AtomicCaptureOp op) {
1789 return convertOmpAtomicCapture(op, builder, moduleTranslation);
1790 })
1791 .Case([&](omp::SectionsOp) {
1792 return convertOmpSections(*op, builder, moduleTranslation);
1793 })
1794 .Case([&](omp::SingleOp op) {
1795 return convertOmpSingle(op, builder, moduleTranslation);
1796 })
1797 .Case([&](omp::TaskOp op) {
1798 return convertOmpTaskOp(op, builder, moduleTranslation);
1799 })
1800 .Case([&](omp::TaskGroupOp op) {
1801 return convertOmpTaskgroupOp(op, builder, moduleTranslation);
1802 })
1803 .Case<omp::YieldOp, omp::TerminatorOp, omp::ReductionDeclareOp,
1804 omp::CriticalDeclareOp>([](auto op) {
1805 // `yield` and `terminator` can be just omitted. The block structure
1806 // was created in the region that handles their parent operation.
1807 // `reduction.declare` will be used by reductions and is not
1808 // converted directly, skip it.
1809 // `critical.declare` is only used to declare names of critical
1810 // sections which will be used by `critical` ops and hence can be
1811 // ignored for lowering. The OpenMP IRBuilder will create unique
1812 // name for critical section names.
1813 return success();
1814 })
1815 .Case([&](omp::ThreadprivateOp) {
1816 return convertOmpThreadprivate(*op, builder, moduleTranslation);
1817 })
1818 .Case<omp::DataOp, omp::EnterDataOp, omp::ExitDataOp>([&](auto op) {
1819 return convertOmpTargetData(op, builder, moduleTranslation);
1820 })
1821 .Case([&](omp::TargetOp) {
1822 return convertOmpTarget(*op, builder, moduleTranslation);
1823 })
1824 .Default([&](Operation *inst) {
1825 return inst->emitError("unsupported OpenMP operation: ")
1826 << inst->getName();
1827 });
1828}
1829
1830void mlir::registerOpenMPDialectTranslation(DialectRegistry &registry) {
1831 registry.insert<omp::OpenMPDialect>();
1832 registry.addExtension(+[](MLIRContext *ctx, omp::OpenMPDialect *dialect) {
1833 dialect->addInterfaces<OpenMPDialectLLVMIRTranslationInterface>();
1834 });
1835}
1836
1837void mlir::registerOpenMPDialectTranslation(MLIRContext &context) {
1838 DialectRegistry registry;
1839 registerOpenMPDialectTranslation(registry);
1840 context.appendDialectRegistry(registry);
1841}