64 omp Dialect
64.1 Beginner Summary
The omp dialect represents OpenMP directives in MLIR.
It models:
- Parallel regions.
- Teams and target offload.
- Worksharing loops.
- SIMD and loop wrappers.
- Sections and single/master/masked regions.
- Tasks and task loops.
- Reductions and private variables.
- Atomics and synchronization.
- Data mapping for target regions.
- OpenMP loop transformation handles.
For beginners, omp is the dialect that keeps OpenMP semantics visible inside MLIR before lowering to LLVM-compatible IR and, eventually, OpenMP runtime calls or LLVM IR constructs.
64.2 Why This Dialect Exists
OpenMP is not just “spawn some threads.” It has a large directive language:
parallel
for / do
simd
teams
target
map
private / firstprivate
reduction
task
atomic
barrier
critical
ordered
Those directives carry semantic information that should not be lost too early. The omp dialect preserves that information in MLIR form.
This gives MLIR a place to:
- Import OpenMP from Clang or Flang-style frontends.
- Convert
scf.parallelinto OpenMP worksharing constructs. - Analyze and transform OpenMP target offload regions.
- Represent privatization and reductions explicitly.
- Keep OpenMP directives separate from the eventual LLVM IR lowering.
64.3 When It Matters
The omp dialect matters in compiler pipelines that target OpenMP execution.
You see it when:
- A frontend lowers OpenMP source constructs into MLIR.
scf.parallelis converted to OpenMP.- A CPU pipeline wants OpenMP parallel worksharing.
- A GPU or accelerator offload pipeline uses OpenMP
targetregions. - Privatization, mapping, reduction, or task semantics must remain visible.
- OpenMP ops are being converted to LLVM-compatible operand and region types.
The dialect usually remains present until late lowering. convert-openmp-to-llvm does not erase OpenMP semantics; it converts operand types and nested IR so the OpenMP dialect can later be translated to LLVM IR using OpenMP lowering support.
64.4 When To Use It
Use omp when the IR should preserve OpenMP directive semantics.
Good uses include:
- Representing OpenMP source directives in MLIR.
- Lowering
scf.parallelto OpenMP. - Modeling OpenMP target offload.
- Expressing OpenMP data mapping with
omp.map.infoandomp.map.bounds. - Representing reductions with
omp.declare_reduction. - Representing private and firstprivate behavior with
omp.private. - Keeping tasking and synchronization semantics explicit.
Avoid using omp as a generic threading dialect. If the program only needs structured loops, use scf. If it needs GPU execution without OpenMP source semantics, use gpu or target-specific dialects. Use omp when OpenMP itself is the semantic contract.
64.5 Core Concepts
64.5.1 OpenMP Directives As Operations
Most OpenMP directives become operations with regions and clauses.
For example:
omp.parallel {
omp.barrier
omp.terminator
}
The operation is not just a generic region. It means OpenMP parallel execution, with OpenMP rules for teams of threads, data sharing, reductions, and barriers.
64.5.2 Clauses Become Operands And Attributes
OpenMP clauses such as if, num_threads, private, reduction, schedule, map, and nowait are represented through operation operands and attributes.
This makes clauses visible to MLIR verification and transformation passes.
64.5.3 Loop Wrappers And Loop Nests
The dialect separates wrapper directives from the rectangular loop nest:
omp.wsloopmodels a worksharing loop directive.omp.simdmodels SIMD execution.omp.distributemodels distribution across teams.omp.loop_nestholds the rectangular loop bounds, steps, and induction variables.
This separation lets one loop nest be wrapped by several OpenMP semantics.
64.5.4 OpenMP Target Offload
OpenMP target offload uses operations such as:
omp.targetomp.target_dataomp.target_enter_dataomp.target_exit_dataomp.target_updateomp.map.infoomp.map.bounds
These describe how host values are mapped to device execution.
64.5.5 OpenMP Conversion To LLVM Is Not Erasure
convert-openmp-to-llvm converts the IR around OpenMP to LLVM-compatible types and operations, but OpenMP operations can remain as OpenMP operations. This is different from a dialect that lowers completely to llvm.* ops in one step.
64.6 Operations
The current OpenMP dialect in this LLVM checkout defines 65 generated operations.
64.6.1 Parallel, Teams, And Region Structure
Core region operations:
omp.parallelomp.teamsomp.scopeomp.terminatoromp.yield
Single-thread or selected-thread regions:
omp.singleomp.masteromp.masked
Sections:
omp.sectionsomp.section
Workshare wrappers:
omp.workshareomp.workshare.loop_wrapperomp.workdistribute
64.6.2 Loops, Worksharing, SIMD, And Loop Transform Handles
Loop representation and wrappers:
omp.loop_nestomp.loopomp.wsloopomp.simdomp.distribute
Canonical-loop and transformation support:
omp.new_cliomp.canonical_loopomp.tileomp.fuseomp.unroll_heuristic
These model OpenMP-compatible canonical loop information and transformations.
64.6.3 Tasks
Tasking operations include:
omp.taskomp.taskgroupomp.taskwaitomp.taskyieldomp.taskloop.contextomp.taskloop.wrapper
Use these for OpenMP task semantics, including task loop lowering support.
64.6.4 Synchronization And Atomics
Synchronization operations:
omp.barrieromp.flushomp.criticalomp.critical.declareomp.orderedomp.ordered.regionomp.cancelomp.cancellation_pointomp.scan
Atomic operations:
omp.atomic.readomp.atomic.writeomp.atomic.updateomp.atomic.captureomp.atomic.compare
These carry OpenMP memory and synchronization semantics.
64.6.5 Data Sharing, Reductions, And Declarations
Data sharing and reductions:
omp.privateomp.declare_reductionomp.declare_simd
Mapping and mapper declarations:
omp.declare_mapperomp.declare_mapper.info
Allocation directives:
omp.allocate_diromp.allocate_free
Iterator and affinity helper operations:
omp.iteratoromp.affinity_entry
64.6.6 Target Offload And Memory
Target and data movement operations:
omp.targetomp.target_dataomp.target_enter_dataomp.target_exit_dataomp.target_updateomp.map.infoomp.map.bounds
Target/shared allocation operations:
omp.target_allocmemomp.target_freememomp.alloc_shared_memomp.free_shared_mem
Thread and group storage:
omp.threadprivateomp.groupprivate
64.7 Transformations
The OpenMP dialect has a small set of native transformation passes focused on offload metadata and device memory preparation.
64.7.1 Native OpenMP Passes
omp-mark-declare-target-
Marks functions called by an OpenMP declare-target function or
omp.targetregion as declare target. omp-offload-privatization-prepare-
Prepares OpenMP maps for privatized variables used by deferred target tasks, especially
nowaittarget regions where stack lifetime is not enough. omp-stack-to-shared-
Replaces selected
llvm.allocaoperations on target devices withomp.alloc_shared_memandomp.free_shared_memso values intended to be shared across threads use target shared memory.
64.7.2 Built-In Rewrite And Verification Surface
OpenMP operations have extensive verifier logic because clause combinations, region bodies, wrapper nesting, reductions, and mapping operands must satisfy OpenMP rules.
Important transformation-related concepts include:
- Privatizer recipes through
omp.private. - Reduction recipes through
omp.declare_reduction. - Mapper recipes through
omp.declare_mapper. - Loop wrapper composition around
omp.loop_nest. - Canonical loop information through
omp.new_cliandomp.canonical_loop. - Target mapping through
omp.map.infoandomp.map.bounds.
64.8 Conversions And Lowering Paths
64.8.1 From SCF
convert-scf-to-openmp converts scf.parallel to OpenMP parallel and worksharing constructs.
The conversion builds:
omp.parallelomp.wsloopomp.loop_nestomp.yieldomp.terminator- reduction declarations when needed
The pass has a num-threads option.
Use this when a structured parallel loop should become an OpenMP worksharing loop.
64.8.2 To LLVM-Compatible OpenMP
convert-openmp-to-llvm converts OpenMP operations so their operands, nested operations, and related memory/function/control-flow pieces are compatible with the LLVM dialect.
It populates conversion patterns for:
- OpenMP operations.
arithoperations used inside OpenMP regions.cfoperations and assertions.- MemRef operations.
- Func operations.
Some OpenMP operations such as omp.barrier, omp.flush, omp.taskwait, omp.taskyield, and omp.terminator remain legal OpenMP operations after this conversion. The generic convert-to-llvm driver can also use the OpenMP conversion interface.
The final translation to LLVM IR is where OpenMP runtime and LLVM OpenMP lowering support become relevant.
64.9 Example IR
64.9.1 Parallel Region
func.func @parallel_region() {
omp.parallel {
omp.barrier
omp.terminator
}
func.return
}
This creates an OpenMP parallel region with an explicit barrier inside it.
64.9.2 Worksharing Loop
func.func @workshare_loop() {
%c0 = arith.constant 0 : index
%c1 = arith.constant 1 : index
%c10 = arith.constant 10 : index
omp.parallel {
omp.wsloop {
omp.loop_nest (%i) : index = (%c0) to (%c10) step (%c1) {
omp.yield
}
}
omp.terminator
}
func.return
}
omp.wsloop gives the loop OpenMP worksharing semantics. omp.loop_nest contains the rectangular loop bounds and induction variable.
64.9.3 SCF To OpenMP Input
func.func @scf_parallel() {
%c0 = arith.constant 0 : index
%c1 = arith.constant 1 : index
%c10 = arith.constant 10 : index
scf.parallel (%i) = (%c0) to (%c10) step (%c1) {
scf.reduce
}
func.return
}
Running convert-scf-to-openmp turns this into OpenMP parallel and worksharing loop constructs.
64.10 Mental Model
Think of the omp dialect as “OpenMP directives in MLIR form.”
It is higher level than LLVM OpenMP runtime calls. It is also more specific than generic parallel loops because it preserves the OpenMP standard’s semantics.
The main question is:
Is the compiler still reasoning about OpenMP directives,
or is it ready to lower to LLVM-compatible runtime/codegen form?
If the answer is OpenMP directives, keep omp. If the answer is target codegen, run the OpenMP-to-LLVM conversion path and later LLVM IR translation.
64.11 Gotchas
OpenMP regions have OpenMP-specific terminators.
Many OpenMP regions end with omp.terminator or omp.yield, not func.return or scf.yield.
Loop wrappers are not the loop body itself.
omp.wsloop, omp.simd, and omp.distribute wrap loop semantics. The actual rectangular loop information is commonly in omp.loop_nest.
OpenMP-to-LLVM does not mean every omp op disappears.
The conversion prepares OpenMP operations for LLVM-compatible lowering. Some OpenMP operations remain as OpenMP dialect operations until final translation.
Clauses are semantic.
Changing or dropping map, private, reduction, nowait, or schedule information changes program meaning.
Target offload needs lifetime care.
The omp-offload-privatization-prepare pass exists because deferred target tasks can outlive stack allocations from the generating task.
64.12 Source Map
Primary source files:
mlir/include/mlir/Dialect/OpenMP/OpenMPDialect.tdmlir/include/mlir/Dialect/OpenMP/OpenMPOpBase.tdmlir/include/mlir/Dialect/OpenMP/OpenMPOps.tdmlir/include/mlir/Dialect/OpenMP/OpenMPClauses.tdmlir/include/mlir/Dialect/OpenMP/OpenMPEnums.tdmlir/include/mlir/Dialect/OpenMP/OpenMPOpsInterfaces.tdmlir/include/mlir/Dialect/OpenMP/Transforms/Passes.tdmlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cppmlir/lib/Dialect/OpenMP/Transforms/mlir/include/mlir/Conversion/Passes.tdmlir/lib/Conversion/OpenMPToLLVM/OpenMPToLLVM.cppmlir/lib/Conversion/SCFToOpenMP/SCFToOpenMP.cpp
Generated op documentation source:
mlir-tblgen --gen-op-doc -dialect=omp \
-I llvm-project-build/tools/mlir/include \
-I llvm-project/mlir/include \
llvm-project/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td