! RUN: %flang_fc1 -fopenmp -emit-llvm %s -o - | FileCheck %s ! Combinational testing of control flow graph and builder insertion points ! in mlir-to-llvm conversion: ! - mixing multiple delayed privatizations and multiple reductions ! - multiple blocks in the private alloc region ! - private alloc region has to read from the mold variable ! - firstprivate ! - multiple blocks in the private copy region ! - multiple blocks in the reduction init region ! - reduction init region has to read from the mold variable ! - re-used omp.private ops ! - re-used omp.reduction.declare ops ! - unstructured code inside of the parallel region ! - needs private dealloc region, and this has multiple blocks ! - needs reduction cleanup region, and this has multiple blocks ! This maybe belongs in the mlir tests, but what we are doing here is complex ! enough that I find the kind of minimised mlir code preferred by mlir reviewers ! hard to read without some fortran here for reference. Nothing like this would ! be generated by other upstream users of the MLIR OpenMP dialect. subroutine worst_case(a, b, c, d) real, allocatable :: a(:), b(:), c(:), d(:) integer i !$omp parallel firstprivate(a,b) reduction(+:c,d) if (sum(a) == 1) stop 1 !$omp end parallel end subroutine ! CHECK-LABEL: define internal void @worst_case_..omp_par ! CHECK-NEXT: omp.par.entry: ! [reduction alloc regions inlined here] ! CHECK: br label %omp.region.after_alloca ! CHECK: omp.region.after_alloca: ! CHECK-NEXT: br label %omp.par.region ! CHECK: omp.par.region: ! CHECK-NEXT: br label %omp.private.init ! CHECK: omp.private.init: ! CHECK-NEXT: br label %omp.private.init2 ! CHECK: omp.private.init2: ! [begin private alloc for first var] ! [read the length from the mold argument] ! [if it is non-zero...] ! CHECK: br i1 %{{.*}}, label %omp.private.init3, label %omp.private.init4 ! CHECK: omp.private.init4: ; preds = %omp.private.init2 ! [finish private alloc for first var with zero extent] ! CHECK: br label %omp.private.init5 ! CHECK: omp.private.init5: ; preds = %omp.private.init3, %omp.private.init4 ! CHECK-NEXT: br label %omp.region.cont ! CHECK: omp.region.cont: ; preds = %omp.private.init5 ! CHECK-NEXT: %{{.*}} = phi ptr ! CHECK-NEXT: br label %omp.private.init7 ! CHECK: omp.private.init7: ! [begin private alloc for second var] ! [read the length from the mold argument] ! [if it is non-zero...] ! CHECK: br i1 {{.*}}, label %omp.private.init8, label %omp.private.init9 ! CHECK: omp.private.init9: ; preds = %omp.private.init7 ! [finish private alloc for second var with zero extent] ! CHECK: br label %omp.private.init10 ! CHECK: omp.private.init10: ; preds = %omp.private.init8, %omp.private.init9 ! CHECK-NEXT: br label %omp.region.cont6 ! CHECK: omp.region.cont6: ; preds = %omp.private.init10 ! CHECK-NEXT: %{{.*}} = phi ptr ! CHECK-NEXT: br label %omp.private.copy ! CHECK: omp.private.copy: ! CHECK-NEXT: br label %omp.private.copy12 ! CHECK: omp.private.copy12: ; preds = %omp.private.copy ! [begin firstprivate copy for first var] ! [read the length, is it non-zero?] ! CHECK: br i1 %{{.*}}, label %omp.private.copy13, label %omp.private.copy14 ! CHECK: omp.private.copy14: ; preds = %omp.private.copy13, %omp.private.copy12 ! CHECK-NEXT: br label %omp.region.cont11 ! CHECK: omp.region.cont11: ; preds = %omp.private.copy14 ! CHECK-NEXT: %{{.*}} = phi ptr ! CHECK-NEXT: br label %omp.private.copy16 ! CHECK: omp.private.copy16: ; preds = %omp.region.cont11 ! [begin firstprivate copy for second var] ! [read the length, is it non-zero?] ! CHECK: br i1 %{{.*}}, label %omp.private.copy17, label %omp.private.copy18 ! CHECK: omp.private.copy18: ; preds = %omp.private.copy17, %omp.private.copy16 ! CHECK-NEXT: br label %omp.region.cont15 ! CHECK: omp.region.cont15: ; preds = %omp.private.copy18 ! CHECK-NEXT: %{{.*}} = phi ptr ! CHECK-NEXT: br label %omp.reduction.init ! CHECK: omp.reduction.init: ; preds = %omp.region.cont15 ! [deferred stores for results of reduction alloc regions] ! CHECK: br label %[[VAL_96:.*]] ! CHECK: omp.reduction.neutral: ; preds = %omp.reduction.init ! [start of reduction initialization region for first var] ! [null check:] ! CHECK: br i1 %{{.*}}, label %omp.reduction.neutral20, label %omp.reduction.neutral21 ! CHECK: omp.reduction.neutral21: ; preds = %omp.reduction.neutral ! [malloc the reduction variable] ! CHECK: br label %omp.reduction.neutral22 ! CHECK: omp.reduction.neutral22: ; preds = %omp.reduction.neutral23, %omp.reduction.neutral21 ! [inlined scalar-to-array init loop header] ! CHECK: br i1 %{{.*}}, label %omp.reduction.neutral23, label %omp.reduction.neutral24 ! CHECK: omp.reduction.neutral24: ; preds = %omp.reduction.neutral22 ! CHECK: br label %omp.reduction.neutral25 ! CHECK: omp.reduction.neutral25: ; preds = %omp.reduction.neutral20, %omp.reduction.neutral24 ! CHECK-NEXT: br label %omp.region.cont19 ! CHECK: omp.region.cont19: ; preds = %omp.reduction.neutral25 ! CHECK-NEXT: %{{.*}} = phi ptr ! CHECK-NEXT: br label %omp.reduction.neutral27 ! CHECK: omp.reduction.neutral27: ; preds = %omp.region.cont19 ! [start of reduction initialization region for second var] ! [null check:] ! CHECK: br i1 %{{.*}}, label %omp.reduction.neutral28, label %omp.reduction.neutral29 ! CHECK: omp.reduction.neutral29: ; preds = %omp.reduction.neutral27 ! [malloc the reduction variable] ! CHECK: br label %omp.reduction.neutral30 ! CHECK: omp.reduction.neutral30: ; preds = %omp.reduction.neutral31, %omp.reduction.neutral29 ! [inlined scalar-to-array init loop header] ! CHECK: br i1 %{{.*}}, label %omp.reduction.neutral31, label %omp.reduction.neutral32 ! CHECK: omp.reduction.neutral32: ; preds = %omp.reduction.neutral30 ! CHECK: br label %omp.reduction.neutral33 ! CHECK: omp.reduction.neutral33: ; preds = %omp.reduction.neutral28, %omp.reduction.neutral32 ! CHECK-NEXT: br label %omp.region.cont26 ! CHECK: omp.region.cont26: ; preds = %omp.reduction.neutral33 ! CHECK-NEXT: %{{.*}} = phi ptr ! CHECK-NEXT: br label %omp.par.region35 ! CHECK: omp.par.region35: ; preds = %omp.region.cont26 ! [call SUM runtime function] ! [if (sum(a) == 1)] ! CHECK: br i1 %{{.*}}, label %omp.par.region36, label %omp.par.region37 ! CHECK: omp.par.region37: ; preds = %omp.par.region35 ! CHECK-NEXT: br label %omp.region.cont34 ! CHECK: omp.region.cont34: ; preds = %omp.par.region36, %omp.par.region37 ! [omp parallel region done, call into the runtime to complete reduction] ! CHECK: %[[VAL_233:.*]] = call i32 @__kmpc_reduce( ! CHECK: switch i32 %[[VAL_233]], label %reduce.finalize [ ! CHECK-NEXT: i32 1, label %reduce.switch.nonatomic ! CHECK-NEXT: i32 2, label %reduce.switch.atomic ! CHECK-NEXT: ] ! CHECK: reduce.switch.atomic: ; preds = %omp.region.cont34 ! CHECK-NEXT: unreachable ! CHECK: reduce.switch.nonatomic: ; preds = %omp.region.cont34 ! CHECK-NEXT: %[[red_private_value_0:.*]] = load ptr, ptr %{{.*}}, align 8 ! CHECK-NEXT: br label %omp.reduction.nonatomic.body ! [various blocks implementing the reduction] ! CHECK: omp.region.cont42: ; preds = ! CHECK-NEXT: %{{.*}} = phi ptr ! CHECK-NEXT: call void @__kmpc_end_reduce( ! CHECK-NEXT: br label %reduce.finalize ! CHECK: reduce.finalize: ; preds = ! CHECK-NEXT: br label %omp.par.pre_finalize ! CHECK: omp.par.pre_finalize: ; preds = %reduce.finalize ! CHECK-NEXT: br label %.fini ! CHECK: .fini: ! CHECK-NEXT: %{{.*}} = load ptr, ptr ! CHECK-NEXT: br label %omp.reduction.cleanup ! CHECK: omp.reduction.cleanup: ; preds = %.fini ! [null check] ! CHECK: br i1 %{{.*}}, label %omp.reduction.cleanup48, label %omp.reduction.cleanup49 ! CHECK: omp.reduction.cleanup49: ; preds = %omp.reduction.cleanup48, %omp.reduction.cleanup ! CHECK-NEXT: br label %omp.region.cont47 ! CHECK: omp.region.cont47: ; preds = %omp.reduction.cleanup49 ! CHECK: br label %omp.reduction.cleanup51 ! CHECK: omp.reduction.cleanup51: ; preds = %omp.region.cont47 ! [null check] ! CHECK: br i1 %{{.*}}, label %omp.reduction.cleanup52, label %omp.reduction.cleanup53 ! CHECK: omp.reduction.cleanup53: ; preds = %omp.reduction.cleanup52, %omp.reduction.cleanup51 ! CHECK-NEXT: br label %omp.region.cont50 ! CHECK: omp.region.cont50: ; preds = %omp.reduction.cleanup53 ! CHECK-NEXT: br label %omp.private.dealloc ! CHECK: omp.private.dealloc: ; preds = %omp.region.cont50 ! [null check for first private var dealloc] ! CHECK: br i1 %{{.*}}, label %omp.private.dealloc55, label %omp.private.dealloc56 ! CHECK: omp.private.dealloc56: ; preds = %omp.private.dealloc55, %omp.private.dealloc ! CHECK-NEXT: br label %omp.region.cont54 ! CHECK: omp.region.cont54: ; preds = %omp.private.dealloc56 ! CHECK-NEXT: br label %omp.private.dealloc58 ! CHECK: omp.private.dealloc58: ; preds = %omp.region.cont54 ! [null check for second private var dealloc] ! CHECK: br i1 %{{.*}}, label %omp.private.dealloc59, label %omp.private.dealloc60 ! CHECK: omp.private.dealloc60: ; preds = %omp.private.dealloc59, %omp.private.dealloc58 ! CHECK-NEXT: br label %omp.region.cont57 ! CHECK: omp.par.region36: ; preds = %omp.par.region35 ! CHECK-NEXT: call void @_FortranAStopStatement ! CHECK: omp.reduction.neutral31: ; preds = %omp.reduction.neutral30 ! [inlined init loop body for second var] ! CHECK: br label %omp.reduction.neutral30 ! CHECK: omp.reduction.neutral28: ; preds = %omp.reduction.neutral27 ! [source length was zero: finish initializing second var] ! CHECK: br label %omp.reduction.neutral33 ! CHECK: omp.reduction.neutral23: ; preds = %omp.reduction.neutral22 ! [inlined init loop body for first var] ! CHECK: br label %omp.reduction.neutral22 ! CHECK: omp.reduction.neutral20: ; preds = %omp.reduction.neutral ! [source length was zero: finish initializing first var] ! CHECK: br label %omp.reduction.neutral25 ! CHECK: omp.private.copy17: ; preds = %omp.private.copy16 ! [source length was non-zero: call assign runtime] ! CHECK: br label %omp.private.copy18 ! CHECK: omp.private.copy13: ; preds = %omp.private.copy12 ! [source length was non-zero: call assign runtime] ! CHECK: br label %omp.private.copy14 ! CHECK: omp.private.init8: ; preds = %omp.private.init7 ! [var extent was non-zero: malloc a private array] ! CHECK: br label %omp.private.init10 ! CHECK: omp.private.init3: ; preds = %omp.private.init2 ! [var extent was non-zero: malloc a private array] ! CHECK: br label %omp.private.init5 ! CHECK: omp.par.exit.exitStub: ; preds = %omp.region.cont57 ! CHECK-NEXT: ret void