diff --git a/flang/test/Lower/OpenMP/parallel-sections.f90 b/flang/test/Lower/OpenMP/parallel-sections.f90 --- a/flang/test/Lower/OpenMP/parallel-sections.f90 +++ b/flang/test/Lower/OpenMP/parallel-sections.f90 @@ -26,7 +26,6 @@ y = y - 5 !OMPDialect: omp.terminator !OMPDialect: omp.terminator - !OMPDialect: omp.terminator !$omp end parallel sections end subroutine omp_parallel_sections @@ -52,6 +51,5 @@ y = y + 5 !OMPDialect: omp.terminator !OMPDialect: omp.terminator - !OMPDialect: omp.terminator !$omp end parallel sections end subroutine omp_parallel_sections_allocate diff --git a/flang/test/Lower/OpenMP/sections.f90 b/flang/test/Lower/OpenMP/sections.f90 --- a/flang/test/Lower/OpenMP/sections.f90 +++ b/flang/test/Lower/OpenMP/sections.f90 @@ -47,10 +47,6 @@ !FIRDialect: fir.store {{.*}} to %[[DOUBLE_COUNT]] : !fir.ref !FIRDialect: omp.terminator !FIRDialect: } -!FIRDialect: omp.terminator -!FIRDialect: } -!FIRDialect: omp.sections nowait { -!FIRDialect: omp.terminator !FIRDialect: } !FIRDialect: return !FIRDialect: } @@ -99,13 +95,6 @@ !LLVMDialect: llvm.store {{.*}}, %[[DOUBLE_COUNT]] : !llvm.ptr !LLVMDialect: omp.terminator !LLVMDialect: } -!LLVMDialect: omp.terminator -!LLVMDialect: } -!LLVMDialect: omp.sections nowait { -!LLVMDialect: omp.section { -!LLVMDialect: omp.terminator -!LLVMDialect: } -!LLVMDialect: omp.terminator !LLVMDialect: } !LLVMDialect: llvm.return !LLVMDialect: } @@ -132,30 +121,17 @@ !FIRDialect: func @_QPfirstprivate(%[[ARG:.*]]: !fir.ref {fir.bindc_name = "alpha"}) { !FIRDialect: omp.sections { !FIRDialect: omp.section { -!FIRDialect: omp.terminator -!FIRDialect: } -!FIRDialect: omp.terminator -!FIRDialect: } -!FIRDialect: omp.sections { -!FIRDialect: omp.section { !FIRDialect: %[[PRIVATE_VAR:.*]] = fir.load %[[ARG]] : !fir.ref !FIRDialect: %[[CONSTANT:.*]] = arith.constant 5.000000e+00 : f32 !FIRDialect: %[[PRIVATE_VAR_2:.*]] = arith.mulf %[[PRIVATE_VAR]], %[[CONSTANT]] : f32 !FIRDialect: fir.store %[[PRIVATE_VAR_2]] to %[[ARG]] : !fir.ref !FIRDialect: omp.terminator !FIRDialect: } -!FIRDialect: omp.terminator !FIRDialect: } !FIRDialect: return !FIRDialect: } !LLVMDialect: llvm.func @_QPfirstprivate(%[[ARG:.*]]: !llvm.ptr {fir.bindc_name = "alpha"}) { -!LLVMDialect: omp.sections { -!LLVMDialect: omp.section { -!LLVMDialect: omp.terminator -!LLVMDialect: } -!LLVMDialect: omp.terminator -!LLVMDialect: } !LLVMDialect: omp.sections { !LLVMDialect: omp.section { !LLVMDialect: {{.*}} = llvm.load %[[ARG]] : !llvm.ptr @@ -164,7 +140,6 @@ !LLVMDialect: llvm.store {{.*}}, %[[ARG]] : !llvm.ptr !LLVMDialect: omp.terminator !LLVMDialect: } -!LLVMDialect: omp.terminator !LLVMDialect: } !LLVMDialect: llvm.return !LLVMDialect: } diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td --- a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td +++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td @@ -136,7 +136,7 @@ }]; } -def TerminatorOp : OpenMP_Op<"terminator", [Terminator]> { +def TerminatorOp : OpenMP_Op<"terminator", [Terminator, NoSideEffect]> { let summary = "terminator for OpenMP regions"; let description = [{ A terminator operation for regions that appear in the body of OpenMP @@ -169,7 +169,8 @@ // 2.8.1 Sections Construct //===----------------------------------------------------------------------===// -def SectionOp : OpenMP_Op<"section", [HasParent<"SectionsOp">]> { +def SectionOp : OpenMP_Op<"section", [HasParent<"SectionsOp">, + RecursiveSideEffects]> { let summary = "section directive"; let description = [{ A section operation encloses a region which represents one section in a @@ -181,7 +182,8 @@ } def SectionsOp : OpenMP_Op<"sections", [AttrSizedOperandSegments, - ReductionClauseInterface]> { + ReductionClauseInterface, RecursiveSideEffects, + SingleBlockImplicitTerminator<"TerminatorOp">]> { let summary = "sections construct"; let description = [{ The sections construct is a non-iterative worksharing construct that @@ -245,7 +247,8 @@ // 2.8.2 Single Construct //===----------------------------------------------------------------------===// -def SingleOp : OpenMP_Op<"single", [AttrSizedOperandSegments]> { +def SingleOp : OpenMP_Op<"single", [AttrSizedOperandSegments, + RecursiveSideEffects]> { let summary = "single directive"; let description = [{ The single construct specifies that the associated structured block is @@ -405,7 +408,8 @@ //===----------------------------------------------------------------------===// def SimdLoopOp : OpenMP_Op<"simdloop", [AttrSizedOperandSegments, - AllTypesMatch<["lowerBound", "upperBound", "step"]>]> { + AllTypesMatch<["lowerBound", "upperBound", "step"]>, + RecursiveSideEffects]> { let summary = "simd loop construct"; let description = [{ The simd construct can be applied to a loop to indicate that the loop can be @@ -469,7 +473,7 @@ def TaskOp : OpenMP_Op<"task", [AttrSizedOperandSegments, OutlineableOpenMPOpInterface, AutomaticAllocationScope, - ReductionClauseInterface]> { + ReductionClauseInterface, RecursiveSideEffects]> { let summary = "task construct"; let description = [{ The task construct defines an explicit task. @@ -582,7 +586,8 @@ // 2.14.5 target construct //===----------------------------------------------------------------------===// -def TargetOp : OpenMP_Op<"target",[AttrSizedOperandSegments]> { +def TargetOp : OpenMP_Op<"target",[AttrSizedOperandSegments, + RecursiveSideEffects]> { let summary = "target construct"; let description = [{ The target construct includes a region of code which is to be executed @@ -624,7 +629,7 @@ //===----------------------------------------------------------------------===// // 2.16 master Construct //===----------------------------------------------------------------------===// -def MasterOp : OpenMP_Op<"master"> { +def MasterOp : OpenMP_Op<"master", [RecursiveSideEffects]> { let summary = "master construct"; let description = [{ The master construct specifies a structured block that is executed by @@ -660,7 +665,7 @@ def CriticalOp : OpenMP_Op<"critical", - [DeclareOpInterfaceMethods]> { + [DeclareOpInterfaceMethods, RecursiveSideEffects]> { let summary = "critical construct"; let description = [{ The critical construct imposes a restriction on the associated structured @@ -739,7 +744,7 @@ let hasVerifier = 1; } -def OrderedRegionOp : OpenMP_Op<"ordered_region"> { +def OrderedRegionOp : OpenMP_Op<"ordered_region", [RecursiveSideEffects]> { let summary = "ordered construct with region"; let description = [{ The ordered construct with region specifies a structured block in a diff --git a/mlir/test/Dialect/OpenMP/canonicalize.mlir b/mlir/test/Dialect/OpenMP/canonicalize.mlir new file mode 100644 --- /dev/null +++ b/mlir/test/Dialect/OpenMP/canonicalize.mlir @@ -0,0 +1,248 @@ +// RUN: mlir-opt %s -canonicalize -split-input-file | FileCheck %s + +// CHECK-LABEL: func.func @all_empty_sections() +func.func @all_empty_sections() { + omp.sections { + omp.section {} + omp.section {} + omp.terminator + } + return +} + +// CHECK-NOT: omp.sections +// CHECK-NOT: omp.section + +// ----- + +// CHECK-LABEL: func.func @all_sections_only_terminator +func.func @all_sections_only_terminator() { + omp.sections { + omp.section { omp.terminator } + omp.section { omp.terminator } + omp.terminator + } + return +} + +// CHECK-NOT: omp.sections +// CHECK-NOT: omp.section + +// ----- + +// CHECK-LABEL: func.func @no_sections +func.func @no_sections() { + omp.sections {} + return +} + +// CHECK-NOT: omp.sections +// CHECK-NOT: omp.section + +// ----- + +// CHECK-LABEL: func.func @no_sections_only_terminator +func.func @no_sections_only_terminator() { + omp.sections { + omp.terminator + } + return +} + +// CHECK-NOT: omp.sections +// CHECK-NOT: omp.section + +// ----- + +func.func @one_empty_section() { + omp.sections { + omp.section {} // this operation should be eliminated + omp.section { + "test.foo"() : () -> () + omp.terminator + } + omp.terminator + } + return +} + +// CHECK-LABEL: func.func @one_empty_section() { +// CHECK-NEXT: omp.sections { +// CHECK-NEXT: omp.section { +// CHECK-NEXT: "test.foo"() : () -> () +// CHECK-NEXT: omp.terminator +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: return +// CHECK-NEXT: } + +// ----- + +func.func @one_section_only_terminator() { + omp.sections { + omp.section { + omp.terminator + } // this operation should be eliminated + omp.section { + "test.foo"() : () -> () + omp.terminator + } + omp.terminator + } + return +} + +// CHECK-LABEL: func.func @one_section_only_terminator() { +// CHECK-NEXT: omp.sections { +// CHECK-NEXT: omp.section { +// CHECK-NEXT: "test.foo"() : () -> () +// CHECK-NEXT: omp.terminator +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: return +// CHECK-NEXT: } + +// ----- + +// CHECK-LABEL: func.func @empty_parallel +func.func @empty_parallel() { + omp.parallel {} + return +} + +// CHECK-NOT: omp.parallel + +// ----- + +// CHECK-LABEL: func.func @parallel_only_terminator +func.func @parallel_only_terminator() { + omp.parallel { + omp.terminator + } + return +} + +// CHECK-NOT: omp.parallel + +// ----- + +// CHECK-LABEL: func.func @single_only_terminator +func.func @single_only_terminator() { + omp.single { + omp.terminator + } + return +} + +// CHECK-NOT: omp.single + +// ----- + +// CHECK-LABEL: func.func @wsloop_only_terminator +func.func @wsloop_only_terminator(%lb: i32, %ub: i32, %step: i32) { + omp.wsloop for (%i) : i32 = (%lb) to (%ub) step (%step) { + omp.terminator + } + return +} + +// CHECK-NOT: omp.wsloop + +// ----- + +// CHECK-LABEL: func.func @wsloop_only_yield +func.func @wsloop_only_yield(%lb: i32, %ub: i32, %step: i32) { + omp.wsloop for (%i) : i32 = (%lb) to (%ub) step (%step) { + omp.yield + } + return +} + +// CHECK-NOT: omp.wsloop + +// ----- + +// CHECK-LABEL: func.func @master_only_terminator +func.func @master_only_terminator() { + omp.master { + omp.terminator + } + return +} + +// CHECK-NOT: omp.master + +// ----- + +// CHECK-LABEL: func.func @critical_only_terminator +func.func @critical_only_terminator() { + omp.critical { + omp.terminator + } + return +} + +// CHECK-NOT: omp.critical + +// ----- + +// CHECK-LABEL: func.func @ordered_region_only_terminator +func.func @ordered_region_only_terminator(%lb: i32, %ub: i32, %step: i32) { + omp.wsloop ordered(0) for (%i) : i32 = (%lb) to (%ub) step (%step) { + omp.ordered_region { + omp.terminator + } + "test.foo"() : () -> () + } + return +} + +// CHECK-NOT: omp.ordered_region + +// ----- + +// CHECK-LABEL: func.func @simdloop_only_terminator +func.func @simdloop_only_terminator(%lb: i32, %ub: i32, %step: i32) { + omp.simdloop (%i) : i32 = (%lb) to (%ub) step (%step) { + omp.terminator + } + return +} + +// CHECK-NOT: omp.simdloop + +// ----- + +// CHECK-LABEL: func.func @simdloop_only_yield +func.func @simdloop_only_yield(%lb: i32, %ub: i32, %step: i32) { + omp.simdloop (%i) : i32 = (%lb) to (%ub) step (%step) { + omp.yield + } + return +} + +// CHECK-NOT: omp.simdloop + +// ----- + +// CHECK-LABEL: func.func @task_only_terminator +func.func @task_only_terminator() { + omp.task { + omp.terminator + } + return +} + +// CHECK-NOT: omp.task + +// ----- + +// CHECK-LABEL: func.func @target_only_terminator +func.func @target_only_terminator() { + omp.target { + omp.terminator + } + return +} + +// CHECK-NOT: omp.target diff --git a/mlir/test/Dialect/OpenMP/invalid.mlir b/mlir/test/Dialect/OpenMP/invalid.mlir --- a/mlir/test/Dialect/OpenMP/invalid.mlir +++ b/mlir/test/Dialect/OpenMP/invalid.mlir @@ -1063,7 +1063,7 @@ // ----- func.func @omp_sections() { - // expected-error @below {{failed to verify constraint: region with 1 blocks}} + // expected-error @below {{op expects region #0 to have 0 or 1 blocks}} omp.sections { omp.section { omp.terminator diff --git a/mlir/test/Dialect/OpenMP/ops.mlir b/mlir/test/Dialect/OpenMP/ops.mlir --- a/mlir/test/Dialect/OpenMP/ops.mlir +++ b/mlir/test/Dialect/OpenMP/ops.mlir @@ -1046,31 +1046,26 @@ %data_var3 : memref, %redn_var : !llvm.ptr) { // CHECK: omp.sections allocate(%{{.*}} : memref -> %{{.*}} : memref) "omp.sections" (%data_var1, %data_var1) ({ - // CHECK: omp.terminator omp.terminator }) {operand_segment_sizes = dense<[0,1,1]> : vector<3xi32>} : (memref, memref) -> () // CHECK: omp.sections reduction(@add_f32 -> %{{.*}} : !llvm.ptr) "omp.sections" (%redn_var) ({ - // CHECK: omp.terminator omp.terminator }) {operand_segment_sizes = dense<[1,0,0]> : vector<3xi32>, reductions=[@add_f32]} : (!llvm.ptr) -> () // CHECK: omp.sections nowait { omp.sections nowait { - // CHECK: omp.terminator omp.terminator } // CHECK: omp.sections reduction(@add_f32 -> %{{.*}} : !llvm.ptr) { omp.sections reduction(@add_f32 -> %redn_var : !llvm.ptr) { - // CHECK: omp.terminator omp.terminator } // CHECK: omp.sections allocate(%{{.*}} : memref -> %{{.*}} : memref) omp.sections allocate(%data_var1 : memref -> %data_var1 : memref) { - // CHECK: omp.terminator omp.terminator } @@ -1095,8 +1090,6 @@ // CHECK: "test.payload"(%{{.*}}) : (!llvm.ptr) -> () "test.payload"(%redn_var) : (!llvm.ptr) -> () } - // CHECK: omp.terminator - omp.terminator } return }