diff --git a/flang/test/Lower/OpenMP/critical.f90 b/flang/test/Lower/OpenMP/critical.f90 --- a/flang/test/Lower/OpenMP/critical.f90 +++ b/flang/test/Lower/OpenMP/critical.f90 @@ -1,41 +1,36 @@ -!RUN: %flang_fc1 -emit-fir -fopenmp %s -o - | FileCheck %s --check-prefix="FIRDialect" -!RUN: %flang_fc1 -emit-fir -fopenmp %s -o - | fir-opt --fir-to-llvm-ir | FileCheck %s --check-prefix="LLVMDialect" +!RUN: %flang_fc1 -emit-fir -fopenmp %s -o - | FileCheck %s --check-prefix="OMPDialect" +!RUN: %flang_fc1 -emit-fir -fopenmp %s -o - | fir-opt --fir-to-llvm-ir | FileCheck %s --check-prefix="OMPDialect" !RUN: %flang_fc1 -emit-fir -fopenmp %s -o - | fir-opt --fir-to-llvm-ir | tco | FileCheck %s --check-prefix="LLVMIR" +!OMPDialect: omp.critical.declare @help2 hint() +!OMPDialect: omp.critical.declare @help1 hint(contended) + subroutine omp_critical() use omp_lib integer :: x, y -!FIRDialect: omp.critical.declare @help hint(contended) -!LLVMDialect: omp.critical.declare @help hint(contended) -!FIRDialect: omp.critical(@help) -!LLVMDialect: omp.critical(@help) -!LLVMIR: call void @__kmpc_critical_with_hint({{.*}}, {{.*}}, {{.*}} @{{.*}}help.var, i32 2) -!$OMP CRITICAL(help) HINT(omp_lock_hint_contended) +!OMPDialect: omp.critical(@help1) +!LLVMIR: call void @__kmpc_critical_with_hint({{.*}}, {{.*}}, {{.*}} @{{.*}}help1.var, i32 2) +!$OMP CRITICAL(help1) HINT(omp_lock_hint_contended) x = x + y -!FIRDialect: omp.terminator -!LLVMDialect: omp.terminator -!LLVMIR: call void @__kmpc_end_critical({{.*}}, {{.*}}, {{.*}} @{{.*}}help.var) -!$OMP END CRITICAL(help) +!OMPDialect: omp.terminator +!LLVMIR: call void @__kmpc_end_critical({{.*}}, {{.*}}, {{.*}} @{{.*}}help1.var) +!$OMP END CRITICAL(help1) ! Test that the same name can be used again ! Also test with the zero hint expression -!FIRDialect: omp.critical(@help) -!LLVMDialect: omp.critical(@help) -!LLVMIR: call void @__kmpc_critical_with_hint({{.*}}, {{.*}}, {{.*}} @{{.*}}help.var, i32 2) -!$OMP CRITICAL(help) HINT(omp_lock_hint_none) +!OMPDialect: omp.critical(@help2) +!LLVMIR: call void @__kmpc_critical_with_hint({{.*}}, {{.*}}, {{.*}} @{{.*}}help2.var, i32 0) +!$OMP CRITICAL(help2) HINT(omp_lock_hint_none) x = x - y -!FIRDialect: omp.terminator -!LLVMDialect: omp.terminator -!LLVMIR: call void @__kmpc_end_critical({{.*}}, {{.*}}, {{.*}} @{{.*}}help.var) -!$OMP END CRITICAL(help) +!OMPDialect: omp.terminator +!LLVMIR: call void @__kmpc_end_critical({{.*}}, {{.*}}, {{.*}} @{{.*}}help2.var) +!$OMP END CRITICAL(help2) -!FIRDialect: omp.critical -!LLVMDialect: omp.critical +!OMPDialect: omp.critical !LLVMIR: call void @__kmpc_critical({{.*}}, {{.*}}, {{.*}} @{{.*}}_.var) !$OMP CRITICAL y = x + y -!FIRDialect: omp.terminator -!LLVMDialect: omp.terminator +!OMPDialect: omp.terminator !LLVMIR: call void @__kmpc_end_critical({{.*}}, {{.*}}, {{.*}} @{{.*}}_.var) !$OMP END CRITICAL end subroutine omp_critical 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 @@ -861,6 +861,7 @@ $region attr-dict }]; let hasRegionVerifier = 1; + let hasVerifier = 1; let extraClassDeclaration = [{ /// Returns the first operation in atomic capture region Operation* getFirstOp(); diff --git a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp --- a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp +++ b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp @@ -382,8 +382,13 @@ IntegerAttr &hintAttr) { StringRef hintKeyword; int64_t hint = 0; + bool firstHint = true; + if (failed(parser.parseOptionalKeyword(&hintKeyword))) { + hintAttr = IntegerAttr::get(parser.getBuilder().getI64Type(), 0); + return success(); + } do { - if (failed(parser.parseKeyword(&hintKeyword))) + if (!firstHint && failed(parser.parseKeyword(&hintKeyword))) return failure(); if (hintKeyword == "uncontended") hint |= 1; @@ -396,6 +401,7 @@ else return parser.emitError(parser.getCurrentLocation()) << hintKeyword << " is not a valid hint"; + firstHint = false; } while (succeeded(parser.parseOptionalComma())); hintAttr = IntegerAttr::get(parser.getBuilder().getI64Type(), hint); return success(); @@ -858,7 +864,7 @@ "element type is the same as that of the region argument"); } - return success(); + return verifySynchronizationHint(*this, hint_val()); } LogicalResult AtomicUpdateOp::verifyRegions() { @@ -909,6 +915,10 @@ return dyn_cast(getSecondOp()); } +LogicalResult AtomicCaptureOp::verify() { + return verifySynchronizationHint(*this, hint_val()); +} + LogicalResult AtomicCaptureOp::verifyRegions() { Block::OpListType &ops = region().front().getOperations(); if (ops.size() != 3) @@ -943,6 +953,10 @@ return firstReadStmt.emitError() << "captured variable in omp.atomic.read must be updated in " "second operation"; + + if (getFirstOp()->getAttr("hint_val") || getSecondOp()->getAttr("hint_val")) + return emitOpError( + "operations inside capture region must not have hint clause"); return success(); } 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 @@ -708,6 +708,42 @@ // ----- +func @omp_atomic_update(%x: memref, %expr: i32) { + // expected-error @below {{the hints omp_sync_hint_uncontended and omp_sync_hint_contended cannot be combined}} + omp.atomic.update hint(uncontended, contended) %x : memref { + ^bb0(%xval: i32): + %newval = llvm.add %xval, %expr : i32 + omp.yield (%newval : i32) + } + return +} + +// ----- + +func @omp_atomic_update(%x: memref, %expr: i32) { + // expected-error @below {{the hints omp_sync_hint_nonspeculative and omp_sync_hint_speculative cannot be combined}} + omp.atomic.update hint(nonspeculative, speculative) %x : memref { + ^bb0(%xval: i32): + %newval = llvm.add %xval, %expr : i32 + omp.yield (%newval : i32) + } + return +} + +// ----- + +func @omp_atomic_update(%x: memref, %expr: i32) { + // expected-error @below {{invalid_hint is not a valid hint}} + omp.atomic.update hint(invalid_hint) %x : memref { + ^bb0(%xval: i32): + %newval = llvm.add %xval, %expr : i32 + omp.yield (%newval : i32) + } + return +} + +// ----- + func @omp_atomic_capture(%x: memref, %v: memref, %expr: i32) { // expected-error @below {{expected three operations in omp.atomic.capture region}} omp.atomic.capture { @@ -848,6 +884,66 @@ // ----- +func @omp_atomic_capture(%x: memref, %v: memref, %expr: i32) { + // expected-error @below {{the hints omp_sync_hint_uncontended and omp_sync_hint_contended cannot be combined}} + omp.atomic.capture hint(contended, uncontended) { + omp.atomic.update %x : memref { + ^bb0(%xval: i32): + %newval = llvm.add %xval, %expr : i32 + omp.yield(%newval : i32) + } + omp.atomic.read %v = %x : memref + } + return +} + +// ----- + +func @omp_atomic_capture(%x: memref, %v: memref, %expr: i32) { + // expected-error @below {{the hints omp_sync_hint_nonspeculative and omp_sync_hint_speculative cannot be combined}} + omp.atomic.capture hint(nonspeculative, speculative) { + omp.atomic.update %x : memref { + ^bb0(%xval: i32): + %newval = llvm.add %xval, %expr : i32 + omp.yield(%newval : i32) + } + omp.atomic.read %v = %x : memref + } + return +} + +// ----- + +func @omp_atomic_capture(%x: memref, %v: memref, %expr: i32) { + // expected-error @below {{invalid_hint is not a valid hint}} + omp.atomic.capture hint(invalid_hint) { + omp.atomic.update %x : memref { + ^bb0(%xval: i32): + %newval = llvm.add %xval, %expr : i32 + omp.yield(%newval : i32) + } + omp.atomic.read %v = %x : memref + } + return +} + +// ----- + +func @omp_atomic_capture(%x: memref, %v: memref, %expr: i32) { + // expected-error @below {{operations inside capture region must not have hint clause}} + omp.atomic.capture { + omp.atomic.update hint(uncontended) %x : memref { + ^bb0(%xval: i32): + %newval = llvm.add %xval, %expr : i32 + omp.yield(%newval : i32) + } + omp.atomic.read %v = %x : memref + } + return +} + +// ----- + func @omp_sections(%data_var : memref) -> () { // expected-error @below {{expected equal sizes for allocate and allocator variables}} "omp.sections" (%data_var) ({ 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 @@ -583,6 +583,10 @@ omp.critical.declare @mutex7 hint(uncontended, speculative) // CHECK: omp.critical.declare @mutex8 hint(contended, speculative) omp.critical.declare @mutex8 hint(contended, speculative) +// CHECK: omp.critical.declare @mutex9 hint() +omp.critical.declare @mutex9 hint() +// CHECK: omp.critical.declare @mutex10 +omp.critical.declare @mutex10 // CHECK-LABEL: omp_critical @@ -657,6 +661,8 @@ omp.atomic.read %v = %x hint(nonspeculative, contended) : memref // CHECK: omp.atomic.read %[[v]] = %[[x]] memory_order(seq_cst) hint(contended, speculative) : memref omp.atomic.read %v = %x hint(speculative, contended) memory_order(seq_cst) : memref + // CHECK: omp.atomic.read %[[v]] = %[[x]] memory_order(seq_cst) hint() : memref + omp.atomic.read %v = %x hint() memory_order(seq_cst) : memref return } @@ -673,6 +679,8 @@ omp.atomic.write %addr = %val memory_order(relaxed) : memref, i32 // CHECK: omp.atomic.write %[[ADDR]] = %[[VAL]] hint(uncontended, speculative) : memref, i32 omp.atomic.write %addr = %val hint(speculative, uncontended) : memref, i32 + // CHECK: omp.atomic.write %[[ADDR]] = %[[VAL]] hint() : memref, i32 + omp.atomic.write %addr = %val hint() : memref, i32 return } @@ -728,6 +736,97 @@ %newval = llvm.icmp "eq" %xval, %exprBool : i1 omp.yield(%newval : i1) } + + // CHECK: omp.atomic.update hint() %[[X]] : memref + // CHECK-NEXT: (%[[XVAL:.*]]: i32): + // CHECK-NEXT: %[[NEWVAL:.*]] = llvm.add %[[XVAL]], %[[EXPR]] : i32 + // CHECK-NEXT: omp.yield(%[[NEWVAL]] : i32) + omp.atomic.update hint() %x : memref { + ^bb0(%xval: i32): + %newval = llvm.add %xval, %expr : i32 + omp.yield(%newval : i32) + } + + // CHECK: omp.atomic.update hint(uncontended) %[[X]] : memref + // CHECK-NEXT: (%[[XVAL:.*]]: i32): + // CHECK-NEXT: %[[NEWVAL:.*]] = llvm.add %[[XVAL]], %[[EXPR]] : i32 + // CHECK-NEXT: omp.yield(%[[NEWVAL]] : i32) + omp.atomic.update hint(uncontended) %x : memref { + ^bb0(%xval: i32): + %newval = llvm.add %xval, %expr : i32 + omp.yield(%newval : i32) + } + + // CHECK: omp.atomic.update hint(contended) %[[X]] : memref + // CHECK-NEXT: (%[[XVAL:.*]]: i32): + // CHECK-NEXT: %[[NEWVAL:.*]] = llvm.add %[[XVAL]], %[[EXPR]] : i32 + // CHECK-NEXT: omp.yield(%[[NEWVAL]] : i32) + omp.atomic.update hint(contended) %x : memref { + ^bb0(%xval: i32): + %newval = llvm.add %xval, %expr : i32 + omp.yield(%newval : i32) + } + + // CHECK: omp.atomic.update hint(nonspeculative) %[[X]] : memref + // CHECK-NEXT: (%[[XVAL:.*]]: i32): + // CHECK-NEXT: %[[NEWVAL:.*]] = llvm.add %[[XVAL]], %[[EXPR]] : i32 + // CHECK-NEXT: omp.yield(%[[NEWVAL]] : i32) + omp.atomic.update hint(nonspeculative) %x : memref { + ^bb0(%xval: i32): + %newval = llvm.add %xval, %expr : i32 + omp.yield(%newval : i32) + } + + // CHECK: omp.atomic.update hint(speculative) %[[X]] : memref + // CHECK-NEXT: (%[[XVAL:.*]]: i32): + // CHECK-NEXT: %[[NEWVAL:.*]] = llvm.add %[[XVAL]], %[[EXPR]] : i32 + // CHECK-NEXT: omp.yield(%[[NEWVAL]] : i32) + omp.atomic.update hint(speculative) %x : memref { + ^bb0(%xval: i32): + %newval = llvm.add %xval, %expr : i32 + omp.yield(%newval : i32) + } + + // CHECK: omp.atomic.update hint(uncontended, nonspeculative) %[[X]] : memref + // CHECK-NEXT: (%[[XVAL:.*]]: i32): + // CHECK-NEXT: %[[NEWVAL:.*]] = llvm.add %[[XVAL]], %[[EXPR]] : i32 + // CHECK-NEXT: omp.yield(%[[NEWVAL]] : i32) + omp.atomic.update hint(uncontended, nonspeculative) %x : memref { + ^bb0(%xval: i32): + %newval = llvm.add %xval, %expr : i32 + omp.yield(%newval : i32) + } + + // CHECK: omp.atomic.update hint(contended, nonspeculative) %[[X]] : memref + // CHECK-NEXT: (%[[XVAL:.*]]: i32): + // CHECK-NEXT: %[[NEWVAL:.*]] = llvm.add %[[XVAL]], %[[EXPR]] : i32 + // CHECK-NEXT: omp.yield(%[[NEWVAL]] : i32) + omp.atomic.update hint(contended, nonspeculative) %x : memref { + ^bb0(%xval: i32): + %newval = llvm.add %xval, %expr : i32 + omp.yield(%newval : i32) + } + + // CHECK: omp.atomic.update hint(uncontended, speculative) %[[X]] : memref + // CHECK-NEXT: (%[[XVAL:.*]]: i32): + // CHECK-NEXT: %[[NEWVAL:.*]] = llvm.add %[[XVAL]], %[[EXPR]] : i32 + // CHECK-NEXT: omp.yield(%[[NEWVAL]] : i32) + omp.atomic.update hint(uncontended, speculative) %x : memref { + ^bb0(%xval: i32): + %newval = llvm.add %xval, %expr : i32 + omp.yield(%newval : i32) + } + + // CHECK: omp.atomic.update hint(contended, speculative) %[[X]] : memref + // CHECK-NEXT: (%[[XVAL:.*]]: i32): + // CHECK-NEXT: %[[NEWVAL:.*]] = llvm.add %[[XVAL]], %[[EXPR]] : i32 + // CHECK-NEXT: omp.yield(%[[NEWVAL]] : i32) + omp.atomic.update hint(contended, speculative) %x : memref { + ^bb0(%xval: i32): + %newval = llvm.add %xval, %expr : i32 + omp.yield(%newval : i32) + } + return } @@ -774,6 +873,159 @@ omp.atomic.read %v = %x : memref omp.atomic.write %x = %expr : memref, i32 } + + // CHECK: omp.atomic.capture hint() { + // CHECK-NEXT: omp.atomic.update %[[x]] : memref + // CHECK-NEXT: (%[[xval:.*]]: i32): + // CHECK-NEXT: %[[newval:.*]] = llvm.add %[[xval]], %[[expr]] : i32 + // CHECK-NEXT: omp.yield(%[[newval]] : i32) + // CHECK-NEXT: } + // CHECK-NEXT: omp.atomic.read %[[v]] = %[[x]] : memref + // CHECK-NEXT: } + omp.atomic.capture hint() { + omp.atomic.update %x : memref { + ^bb0(%xval: i32): + %newval = llvm.add %xval, %expr : i32 + omp.yield(%newval : i32) + } + omp.atomic.read %v = %x : memref + } + + // CHECK: omp.atomic.capture hint(uncontended) { + // CHECK-NEXT: omp.atomic.update %[[x]] : memref + // CHECK-NEXT: (%[[xval:.*]]: i32): + // CHECK-NEXT: %[[newval:.*]] = llvm.add %[[xval]], %[[expr]] : i32 + // CHECK-NEXT: omp.yield(%[[newval]] : i32) + // CHECK-NEXT: } + // CHECK-NEXT: omp.atomic.read %[[v]] = %[[x]] : memref + // CHECK-NEXT: } + omp.atomic.capture hint(uncontended) { + omp.atomic.update %x : memref { + ^bb0(%xval: i32): + %newval = llvm.add %xval, %expr : i32 + omp.yield(%newval : i32) + } + omp.atomic.read %v = %x : memref + } + + // CHECK: omp.atomic.capture hint(contended) { + // CHECK-NEXT: omp.atomic.update %[[x]] : memref + // CHECK-NEXT: (%[[xval:.*]]: i32): + // CHECK-NEXT: %[[newval:.*]] = llvm.add %[[xval]], %[[expr]] : i32 + // CHECK-NEXT: omp.yield(%[[newval]] : i32) + // CHECK-NEXT: } + // CHECK-NEXT: omp.atomic.read %[[v]] = %[[x]] : memref + // CHECK-NEXT: } + omp.atomic.capture hint(contended) { + omp.atomic.update %x : memref { + ^bb0(%xval: i32): + %newval = llvm.add %xval, %expr : i32 + omp.yield(%newval : i32) + } + omp.atomic.read %v = %x : memref + } + + // CHECK: omp.atomic.capture hint(nonspeculative) { + // CHECK-NEXT: omp.atomic.update %[[x]] : memref + // CHECK-NEXT: (%[[xval:.*]]: i32): + // CHECK-NEXT: %[[newval:.*]] = llvm.add %[[xval]], %[[expr]] : i32 + // CHECK-NEXT: omp.yield(%[[newval]] : i32) + // CHECK-NEXT: } + // CHECK-NEXT: omp.atomic.read %[[v]] = %[[x]] : memref + // CHECK-NEXT: } + omp.atomic.capture hint(nonspeculative) { + omp.atomic.update %x : memref { + ^bb0(%xval: i32): + %newval = llvm.add %xval, %expr : i32 + omp.yield(%newval : i32) + } + omp.atomic.read %v = %x : memref + } + + // CHECK: omp.atomic.capture hint(speculative) { + // CHECK-NEXT: omp.atomic.update %[[x]] : memref + // CHECK-NEXT: (%[[xval:.*]]: i32): + // CHECK-NEXT: %[[newval:.*]] = llvm.add %[[xval]], %[[expr]] : i32 + // CHECK-NEXT: omp.yield(%[[newval]] : i32) + // CHECK-NEXT: } + // CHECK-NEXT: omp.atomic.read %[[v]] = %[[x]] : memref + // CHECK-NEXT: } + omp.atomic.capture hint(speculative) { + omp.atomic.update %x : memref { + ^bb0(%xval: i32): + %newval = llvm.add %xval, %expr : i32 + omp.yield(%newval : i32) + } + omp.atomic.read %v = %x : memref + } + + // CHECK: omp.atomic.capture hint(uncontended, nonspeculative) { + // CHECK-NEXT: omp.atomic.update %[[x]] : memref + // CHECK-NEXT: (%[[xval:.*]]: i32): + // CHECK-NEXT: %[[newval:.*]] = llvm.add %[[xval]], %[[expr]] : i32 + // CHECK-NEXT: omp.yield(%[[newval]] : i32) + // CHECK-NEXT: } + // CHECK-NEXT: omp.atomic.read %[[v]] = %[[x]] : memref + // CHECK-NEXT: } + omp.atomic.capture hint(uncontended, nonspeculative) { + omp.atomic.update %x : memref { + ^bb0(%xval: i32): + %newval = llvm.add %xval, %expr : i32 + omp.yield(%newval : i32) + } + omp.atomic.read %v = %x : memref + } + + // CHECK: omp.atomic.capture hint(contended, nonspeculative) { + // CHECK-NEXT: omp.atomic.update %[[x]] : memref + // CHECK-NEXT: (%[[xval:.*]]: i32): + // CHECK-NEXT: %[[newval:.*]] = llvm.add %[[xval]], %[[expr]] : i32 + // CHECK-NEXT: omp.yield(%[[newval]] : i32) + // CHECK-NEXT: } + // CHECK-NEXT: omp.atomic.read %[[v]] = %[[x]] : memref + // CHECK-NEXT: } + omp.atomic.capture hint(contended, nonspeculative) { + omp.atomic.update %x : memref { + ^bb0(%xval: i32): + %newval = llvm.add %xval, %expr : i32 + omp.yield(%newval : i32) + } + omp.atomic.read %v = %x : memref + } + + // CHECK: omp.atomic.capture hint(uncontended, speculative) { + // CHECK-NEXT: omp.atomic.update %[[x]] : memref + // CHECK-NEXT: (%[[xval:.*]]: i32): + // CHECK-NEXT: %[[newval:.*]] = llvm.add %[[xval]], %[[expr]] : i32 + // CHECK-NEXT: omp.yield(%[[newval]] : i32) + // CHECK-NEXT: } + // CHECK-NEXT: omp.atomic.read %[[v]] = %[[x]] : memref + // CHECK-NEXT: } + omp.atomic.capture hint(uncontended, speculative) { + omp.atomic.update %x : memref { + ^bb0(%xval: i32): + %newval = llvm.add %xval, %expr : i32 + omp.yield(%newval : i32) + } + omp.atomic.read %v = %x : memref + } + + // CHECK: omp.atomic.capture hint(contended, speculative) { + // CHECK-NEXT: omp.atomic.update %[[x]] : memref + // CHECK-NEXT: (%[[xval:.*]]: i32): + // CHECK-NEXT: %[[newval:.*]] = llvm.add %[[xval]], %[[expr]] : i32 + // CHECK-NEXT: omp.yield(%[[newval]] : i32) + // CHECK-NEXT: } + // CHECK-NEXT: omp.atomic.read %[[v]] = %[[x]] : memref + // CHECK-NEXT: } + omp.atomic.capture hint(contended, speculative) { + omp.atomic.update %x : memref { + ^bb0(%xval: i32): + %newval = llvm.add %xval, %expr : i32 + omp.yield(%newval : i32) + } + omp.atomic.read %v = %x : memref + } return }