diff --git a/flang/lib/Lower/OpenMP.cpp b/flang/lib/Lower/OpenMP.cpp --- a/flang/lib/Lower/OpenMP.cpp +++ b/flang/lib/Lower/OpenMP.cpp @@ -1054,7 +1054,7 @@ fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); mlir::Location currentLocation = converter.getCurrentLocation(); llvm::SmallVector lowerBound, upperBound, step, linearVars, - linearStepVars, reductionVars, alignedVars; + linearStepVars, reductionVars, alignedVars, nontemporalVars; mlir::Value scheduleChunkClauseOperand, ifClauseOperand; mlir::Attribute scheduleClauseOperand, noWaitClauseOperand, orderedClauseOperand, orderClauseOperand; @@ -1214,7 +1214,7 @@ TypeRange resultType; auto SimdLoopOp = firOpBuilder.create( currentLocation, resultType, lowerBound, upperBound, step, alignedVars, - nullptr, ifClauseOperand, + nullptr, ifClauseOperand, nontemporalVars, orderClauseOperand.dyn_cast_or_null(), simdlenClauseOperand, safelenClauseOperand, /*inclusive=*/firOpBuilder.getUnitAttr()); 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 @@ -394,6 +394,9 @@ iterations to be executed concurrently is one, regardless of whether a simdlen clause is speciļ¬ed. + The optional `nontemporal` attribute specifies variables which have low + temporal locality across the iterations where they are accessed. + The optional `order` attribute specifies which order the iterations of the associate loops are executed in. Currently the only option for this attribute is "concurrent". @@ -420,6 +423,7 @@ Variadic:$aligned_vars, OptionalAttr:$alignment_values, Optional:$if_expr, + Variadic:$nontemporal_vars, OptionalAttr:$order_val, ConfinedAttr, [IntPositive]>:$simdlen, ConfinedAttr, [IntPositive]>:$safelen, @@ -432,6 +436,7 @@ custom($aligned_vars, type($aligned_vars), $alignment_values) `)` |`if` `(` $if_expr `)` + |`nontemporal` `(` $nontemporal_vars `:` type($nontemporal_vars) `)` |`order` `(` custom($order_val) `)` |`simdlen` `(` $simdlen `)` |`safelen` `(` $safelen `)` 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 @@ -170,6 +170,22 @@ } } +//===----------------------------------------------------------------------===// +// Verifier for Nontemporal Clause +//===----------------------------------------------------------------------===// + +static LogicalResult +verifyNontemporalClause(Operation *op, OperandRange nontemporalVariables) { + + // Check if each var is unique - OpenMP 5.0 -> 2.9.3.1 section + DenseSet nontemporalItems; + for (const auto &it : nontemporalVariables) + if (!nontemporalItems.insert(it).second) + return op->emitOpError() << "nontemporal variable used more than once"; + + return success(); +} + //===----------------------------------------------------------------------===// // Parser, verifier and printer for Aligned Clause //===----------------------------------------------------------------------===// @@ -658,8 +674,13 @@ << "simdlen clause and safelen clause are both present, but the " "simdlen value is not less than or equal to safelen value"; } - return verifyAlignedClause(*this, this->getAlignmentValues(), - this->getAlignedVars()); + if (verifyAlignedClause(*this, this->getAlignmentValues(), + this->getAlignedVars()) + .failed()) + return failure(); + if (verifyNontemporalClause(*this, this->getNontemporalVars()).failed()) + return failure(); + 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 @@ -197,7 +197,7 @@ "omp.simdloop" (%lb, %ub, %step) ({ ^bb0(%iv: index): omp.yield - }) {operand_segment_sizes = array} : + }) {operand_segment_sizes = array} : (index, index, i32) -> () return @@ -225,7 +225,7 @@ ^bb0(%arg5: index): "omp.yield"() : () -> () }) {alignment_values = [128], - operand_segment_sizes = array} : (index, index, index, memref, memref) -> () + operand_segment_sizes = array} : (index, index, index, memref, memref) -> () return } @@ -238,7 +238,7 @@ "omp.simdloop"(%arg0, %arg1, %arg2, %arg3, %arg4) ({ ^bb0(%arg5: index): "omp.yield"() : () -> () - }) {alignment_values = [-1, 128], operand_segment_sizes = array} : (index, index, index, memref, memref) -> () + }) {alignment_values = [-1, 128], operand_segment_sizes = array} : (index, index, index, memref, memref) -> () return } @@ -251,7 +251,7 @@ "omp.simdloop"(%arg0, %arg1, %arg2) ({ ^bb0(%arg5: index): "omp.yield"() : () -> () - }) {alignment_values = [1, 128], operand_segment_sizes = array} : (index, index, index) -> () + }) {alignment_values = [1, 128], operand_segment_sizes = array} : (index, index, index) -> () return } @@ -264,7 +264,7 @@ "omp.simdloop"(%arg0, %arg1, %arg2, %arg3, %arg4) ({ ^bb0(%arg5: index): "omp.yield"() : () -> () - }) {alignment_values = [1.5, 128], operand_segment_sizes = array} : (index, index, index, memref, memref) -> () + }) {alignment_values = [1.5, 128], operand_segment_sizes = array} : (index, index, index, memref, memref) -> () return } @@ -277,7 +277,21 @@ "omp.simdloop"(%arg0, %arg1, %arg2, %arg3, %arg3) ({ ^bb0(%arg5: index): "omp.yield"() : () -> () - }) {alignment_values = [1, 128], operand_segment_sizes = array} : (index, index, index, memref, memref) -> () + }) {alignment_values = [1, 128], operand_segment_sizes = array} : (index, index, index, memref, memref) -> () + return +} + +// ----- + +func.func @omp_simdloop_nontemporal_the_same_var(%arg0 : index, + %arg1 : index, + %arg2 : index, + %arg3 : memref) -> () { + // expected-error @below {{nontemporal variable used more than once}} + "omp.simdloop"(%arg0, %arg1, %arg2, %arg3, %arg3) ({ + ^bb0(%arg5: index): + "omp.yield"() : () -> () + }) {operand_segment_sizes = array} : (index, index, index, memref, memref) -> () return } 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 @@ -333,7 +333,7 @@ "omp.simdloop" (%lb, %ub, %step) ({ ^bb0(%iv: index): omp.yield - }) {operand_segment_sizes = array} : + }) {operand_segment_sizes = array} : (index, index, index) -> () return @@ -349,7 +349,7 @@ ^bb0(%arg5: index): "omp.yield"() : () -> () }) {alignment_values = [32, 128], - operand_segment_sizes = array} : (index, index, index, memref, memref) -> () + operand_segment_sizes = array} : (index, index, index, memref, memref) -> () return } @@ -362,7 +362,37 @@ ^bb0(%arg5: index): "omp.yield"() : () -> () }) {alignment_values = [32], - operand_segment_sizes = array} : (index, index, index, memref) -> () + operand_segment_sizes = array} : (index, index, index, memref) -> () + return +} + +// CHECK-LABEL: omp_simdloop_nontemporal_list +func.func @omp_simdloop_nontemporal_list(%arg0 : index, + %arg1 : index, + %arg2 : index, + %arg3 : memref, + %arg4 : memref) -> () { + // CHECK: omp.simdloop nontemporal(%{{.*}}, %{{.*}} : memref, memref) + // CHECK-SAME: for (%{{.*}}) : index = (%{{.*}}) to (%{{.*}}) step (%{{.*}}) { + "omp.simdloop"(%arg0, %arg1, %arg2, %arg3, %arg4) ({ + ^bb0(%arg5: index): + "omp.yield"() : () -> () + }) {operand_segment_sizes = array} : (index, index, index, memref, memref) -> () + return +} + +// CHECK-LABEL: omp_simdloop_nontemporal_single +func.func @omp_simdloop_nontemporal_single(%arg0 : index, + %arg1 : index, + %arg2 : index, + %arg3 : memref, + %arg4 : memref) -> () { + // CHECK: omp.simdloop nontemporal(%{{.*}} : memref) + // CHECK-SAME: for (%{{.*}}) : index = (%{{.*}}) to (%{{.*}}) step (%{{.*}}) { + "omp.simdloop"(%arg0, %arg1, %arg2, %arg3) ({ + ^bb0(%arg5: index): + "omp.yield"() : () -> () + }) {operand_segment_sizes = array} : (index, index, index, memref) -> () return } @@ -398,6 +428,20 @@ return } +// CHECK-LABEL: func.func @omp_simdloop_pretty_nontemporal +func.func @omp_simdloop_pretty_nontemporal(%lb : index, + %ub : index, + %step : index, + %data_var : memref, + %data_var1 : memref) -> () { + // CHECK: omp.simdloop nontemporal(%{{.*}}, %{{.*}} : memref, memref) + // CHECK-SAME: for (%{{.*}}) : index = (%{{.*}}) to (%{{.*}}) step (%{{.*}}) { + omp.simdloop nontemporal(%data_var, %data_var1 : memref, memref) + for (%iv) : index = (%lb) to (%ub) step (%step) { + omp.yield + } + return +} // CHECK-LABEL: omp_simdloop_pretty_order func.func @omp_simdloop_pretty_order(%lb : index, %ub : index, %step : index) -> () { // CHECK: omp.simdloop order(concurrent) diff --git a/mlir/test/Target/LLVMIR/openmp-llvm.mlir b/mlir/test/Target/LLVMIR/openmp-llvm.mlir --- a/mlir/test/Target/LLVMIR/openmp-llvm.mlir +++ b/mlir/test/Target/LLVMIR/openmp-llvm.mlir @@ -628,7 +628,7 @@ %4 = llvm.getelementptr %arg0[%iv] : (!llvm.ptr, i64) -> !llvm.ptr llvm.store %3, %4 : !llvm.ptr omp.yield - }) {operand_segment_sizes = array} : + }) {operand_segment_sizes = array} : (i64, i64, i64) -> () llvm.return