Static Resolution
When all context selectors are compile-time evaluable (e.g., implementation={vendor(llvm)}, device={kind(host)}, device={isa("neon")}, construct={parallel}), the best-matching variant is selected at lowering time and only its directive is emitted.
Fortran input:
subroutine static_vendor()
!$omp metadirective &
!$omp & when(implementation={vendor(llvm)}: barrier) &
!$omp & otherwise(nothing)
end subroutine
MLIR output — the metadirective is gone, only the winning variant remains:
func.func @_QPstatic_vendor() {
%0 = fir.dummy_scope : !fir.dscope
omp.barrier
return
}
Since vendor(llvm) is always true inside Flang, barrier is selected at compile time. The metadirective leaves no trace in the IR.
Dynamic Resolution
When a when clause whose expression is not a compile-time constant, the metadirective is lowered to an fir.if/else chain that evaluates the condition at runtime.
Fortran input:
subroutine dynamic_user(n)
integer, intent(in) :: n
!$omp metadirective &
!$omp & when(user={condition(n > 1000)}: barrier) &
!$omp & otherwise(nothing)
end subroutine
MLIR output — an fir.if selects the variant at runtime:
func.func @_QPdynamic_user(%arg0: !fir.ref<i32> {fir.bindc_name = "n"}) {
%0 = fir.dummy_scope : !fir.dscope
%1:2 = hlfir.declare %arg0 ...
%2 = fir.load %1#0 : !fir.ref<i32>
%c1000_i32 = arith.constant 1000 : i32
%3 = arith.cmpi sgt, %2, %c1000_i32 : i32
fir.if %3 {
omp.barrier
} else {
// otherwise(nothing) — empty
}
return
}
With multiple dynamic when clauses, the fir.if chains nest: each dynamic condition is tested in priority order, with the static fallback (or otherwise) in the innermost else.
Mixed Static + Dynamic
When a when clause with a dynamic user={condition}], the static traits are evaluated first. Only statically-applicable variants enter the dynamic selection:
subroutine mixed_case(n)
integer, intent(in) :: n
!$omp metadirective &
!$omp & when(implementation={vendor(llvm)}, user={condition(n > 100)}: barrier) &
!$omp & when(implementation={vendor(llvm)}: flush) &
!$omp & otherwise(nothing)
end subroutine
Both when clauses pass the static vendor(llvm) check. The first has a dynamic condition, so it becomes a runtime branch; the second is fully static and becomes the fallback:
func.func @_QPmixed_case(%arg0: !fir.ref<i32> {fir.bindc_name = "n"}) {
%0 = fir.dummy_scope : !fir.dscope
%1:2 = hlfir.declare %arg0 ...
%2 = fir.load %1#0 : !fir.ref<i32>
%c100_i32 = arith.constant 100 : i32
%3 = arith.cmpi sgt, %2, %c100_i32 : i32
fir.if %3 {
omp.barrier
} else {
omp.flush
}
return
}