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; + linearStepVars, reductionVars, alignedVars; mlir::Value scheduleChunkClauseOperand, ifClauseOperand; mlir::Attribute scheduleClauseOperand, noWaitClauseOperand, orderedClauseOperand, orderClauseOperand; @@ -1213,8 +1213,8 @@ if (llvm::omp::OMPD_simd == ompDirective) { TypeRange resultType; auto SimdLoopOp = firOpBuilder.create( - currentLocation, resultType, lowerBound, upperBound, step, - ifClauseOperand, simdlenClauseOperand, safelenClauseOperand, + currentLocation, resultType, lowerBound, upperBound, step, alignedVars, + nullptr, ifClauseOperand, simdlenClauseOperand, safelenClauseOperand, /*inclusive=*/firOpBuilder.getUnitAttr()); createBodyOfOp(SimdLoopOp, converter, currentLocation, eval, &loopOpClauseList, iv); 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 @@ -385,6 +385,10 @@ Collapsed loops are represented by the simd-loop having a list of indices, bounds and steps where the size of the list is equal to the collapse value. + The `alignment_values` attribute additionally specifies alignment of each + corresponding aligned operand. Note that `$aligned_vars` and + `alignment_values` should contain the same number of elements. + When an if clause is present and evaluates to false, the preferred number of iterations to be executed concurrently is one, regardless of whether a simdlen clause is speciļ¬ed. @@ -408,6 +412,8 @@ let arguments = (ins Variadic:$lowerBound, Variadic:$upperBound, Variadic:$step, + Variadic:$aligned_vars, + OptionalAttr:$alignment_values, Optional:$if_expr, ConfinedAttr, [IntPositive]>:$simdlen, ConfinedAttr, [IntPositive]>:$safelen, @@ -416,7 +422,10 @@ let regions = (region AnyRegion:$region); let assemblyFormat = [{ - oilist(`if` `(` $if_expr `)` + oilist(`aligned` `(` + custom($aligned_vars, type($aligned_vars), + $alignment_values) `)` + |`if` `(` $if_expr `)` |`simdlen` `(` $simdlen `)` |`safelen` `(` $safelen `)` ) `for` custom($region, $lowerBound, $upperBound, $step, 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,81 @@ } } +//===----------------------------------------------------------------------===// +// Parser, verifier and printer for Aligned Clause +//===----------------------------------------------------------------------===// +static LogicalResult verifyAlignedClause(Operation *op, + Optional alignmentValues, + OperandRange alignedVariables) { + // Check if number of alignment values equals to number of aligned variables + if (!alignedVariables.empty()) { + if (!alignmentValues || alignmentValues->size() != alignedVariables.size()) + return op->emitOpError() + << "expected as many alignment values as aligned variables"; + } else { + if (alignmentValues) + return op->emitOpError() << "unexpected alignment values attribute"; + return success(); + } + + // Check if each var is aligned only once - OpenMP 4.5 -> 2.8.1 section + DenseSet alignedItems; + for (auto it : alignedVariables) + if (!alignedItems.insert(it).second) + return op->emitOpError() << "aligned variable used more than once"; + + if (!alignmentValues) + return success(); + + // Check if all alignment values are positive - OpenMP 4.5 -> 2.8.1 section + for (unsigned i = 0; i < (*alignmentValues).size(); ++i) { + if (auto intAttr = (*alignmentValues)[i].dyn_cast()) { + if (intAttr.getValue().sle(0)) + return op->emitOpError() << "alignment should be greater than 0"; + } else { + return op->emitOpError() << "expected integer alignment"; + } + } + + return success(); +} + +/// aligned ::= `aligned` `(` aligned-list `)` +/// aligned-list := aligned-val | aligned-val aligned-list +/// aligned-val := ssa-id-and-type `->` alignment +static ParseResult parseAlignedClause( + OpAsmParser &parser, + SmallVectorImpl &alignedItems, + SmallVectorImpl &types, ArrayAttr &alignmentValues) { + SmallVector alignmentVec; + if (failed(parser.parseCommaSeparatedList([&]() { + if (parser.parseOperand(alignedItems.emplace_back()) || + parser.parseColonType(types.emplace_back()) || + parser.parseArrow() || + parser.parseAttribute(alignmentVec.emplace_back())) { + return failure(); + } + return success(); + }))) + return failure(); + SmallVector alignments(alignmentVec.begin(), alignmentVec.end()); + alignmentValues = ArrayAttr::get(parser.getContext(), alignments); + return success(); +} + +/// Print Aligned Clause +static void printAlignedClause(OpAsmPrinter &p, Operation *op, + ValueRange alignedVars, + TypeRange alignedVarTypes, + Optional alignmentValues) { + for (unsigned i = 0; i < alignedVars.size(); ++i) { + if (i != 0) + p << ", "; + p << alignedVars[i] << " : " << alignedVars[i].getType(); + p << " -> " << (*alignmentValues)[i]; + } +} + //===----------------------------------------------------------------------===// // Parser, printer and verifier for Schedule Clause //===----------------------------------------------------------------------===// @@ -583,8 +658,8 @@ << "simdlen clause and safelen clause are both present, but the " "simdlen value is not less than or equal to safelen value"; } - - return success(); + return verifyAlignedClause(*this, this->getAlignmentValues(), + this->getAlignedVars()); } //===----------------------------------------------------------------------===// 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 @@ -205,6 +205,84 @@ // ----- +func.func @omp_simdloop_pretty_aligned(%lb : index, %ub : index, %step : index, + %data_var : memref) -> () { + // expected-error @below {{expected '->'}} + omp.simdloop aligned(%data_var : memref) + for (%iv) : index = (%lb) to (%ub) step (%step) { + omp.yield + } + return +} + +// ----- + +func.func @omp_simdloop_aligned_mismatch(%arg0 : index, %arg1 : index, + %arg2 : index, %arg3 : memref, + %arg4 : memref) -> () { + // expected-error @below {{op expected as many alignment values as aligned variables}} + "omp.simdloop"(%arg0, %arg1, %arg2, %arg3, %arg4) ({ + ^bb0(%arg5: index): + "omp.yield"() : () -> () + }) {alignment_values = [128], + operand_segment_sizes = array} : (index, index, index, memref, memref) -> () + return +} + +// ----- + +func.func @omp_simdloop_aligned_negative(%arg0 : index, %arg1 : index, + %arg2 : index, %arg3 : memref, + %arg4 : memref) -> () { + // expected-error @below {{op alignment should be greater than 0}} + "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) -> () + return +} + +// ----- + +func.func @omp_simdloop_unexpected_alignment(%arg0 : index, %arg1 : index, + %arg2 : index, %arg3 : memref, + %arg4 : memref) -> () { + // expected-error @below {{unexpected alignment values attribute}} + "omp.simdloop"(%arg0, %arg1, %arg2) ({ + ^bb0(%arg5: index): + "omp.yield"() : () -> () + }) {alignment_values = [1, 128], operand_segment_sizes = array} : (index, index, index) -> () + return +} + +// ----- + +func.func @omp_simdloop_aligned_float(%arg0 : index, %arg1 : index, + %arg2 : index, %arg3 : memref, + %arg4 : memref) -> () { + // expected-error @below {{failed to satisfy constraint: 64-bit integer array attribute}} + "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) -> () + return +} + +// ----- + +func.func @omp_simdloop_aligned_the_same_var(%arg0 : index, %arg1 : index, + %arg2 : index, %arg3 : memref, + %arg4 : memref) -> () { + // expected-error @below {{aligned variable used more than once}} + "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) -> () + return +} + +// ----- + func.func @omp_simdloop_pretty_simdlen(%lb : index, %ub : index, %step : index) -> () { // expected-error @below {{op attribute 'simdlen' failed to satisfy constraint: 64-bit signless integer attribute whose value is positive}} omp.simdloop simdlen(0) for (%iv): index = (%lb) to (%ub) step (%step) { 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,12 +333,39 @@ "omp.simdloop" (%lb, %ub, %step) ({ ^bb0(%iv: index): omp.yield - }) {operand_segment_sizes = array} : + }) {operand_segment_sizes = array} : (index, index, index) -> () return } +// CHECK-LABEL: omp_simdloop_aligned_list +func.func @omp_simdloop_aligned_list(%arg0 : index, %arg1 : index, %arg2 : index, + %arg3 : memref, %arg4 : memref) -> () { + // CHECK: omp.simdloop aligned(%{{.*}} : memref -> 32 : i64, + // CHECK-SAME: %{{.*}} : memref -> 128 : i64) + // CHECK-SAME: for (%{{.*}}) : index = (%{{.*}}) to (%{{.*}}) step (%{{.*}}) { + "omp.simdloop"(%arg0, %arg1, %arg2, %arg3, %arg4) ({ + ^bb0(%arg5: index): + "omp.yield"() : () -> () + }) {alignment_values = [32, 128], + operand_segment_sizes = array} : (index, index, index, memref, memref) -> () + return +} + +// CHECK-LABEL: omp_simdloop_aligned_single +func.func @omp_simdloop_aligned_single(%arg0 : index, %arg1 : index, %arg2 : index, + %arg3 : memref, %arg4 : memref) -> () { + // CHECK: omp.simdloop aligned(%{{.*}} : memref -> 32 : i64) + // CHECK-SAME: for (%{{.*}}) : index = (%{{.*}}) to (%{{.*}}) step (%{{.*}}) { + "omp.simdloop"(%arg0, %arg1, %arg2, %arg3) ({ + ^bb0(%arg5: index): + "omp.yield"() : () -> () + }) {alignment_values = [32], + operand_segment_sizes = array} : (index, index, index, memref) -> () + return +} + // CHECK-LABEL: omp_simdloop_pretty func.func @omp_simdloop_pretty(%lb : index, %ub : index, %step : index) -> () { // CHECK: omp.simdloop for (%{{.*}}) : index = (%{{.*}}) to (%{{.*}}) step (%{{.*}}) @@ -348,6 +375,20 @@ return } +// CHECK-LABEL: func.func @omp_simdloop_pretty_aligned( +func.func @omp_simdloop_pretty_aligned(%lb : index, %ub : index, %step : index, + %data_var : memref, + %data_var1 : memref) -> () { + // CHECK: omp.simdloop aligned(%{{.*}} : memref -> 32 : i64, + // CHECK-SAME: %{{.*}} : memref -> 128 : i64) + // CHECK-SAME: for (%{{.*}}) : index = (%{{.*}}) to (%{{.*}}) step (%{{.*}}) { + omp.simdloop aligned(%data_var : memref -> 32, %data_var1 : memref -> 128) + for (%iv) : index = (%lb) to (%ub) step (%step) { + omp.yield + } + return +} + // CHECK-LABEL: omp_simdloop_pretty_if func.func @omp_simdloop_pretty_if(%lb : index, %ub : index, %step : index, %if_cond : i1) -> () { // CHECK: omp.simdloop if(%{{.*}}) for (%{{.*}}) : index = (%{{.*}}) to (%{{.*}}) step (%{{.*}}) 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 @@ -694,7 +694,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