[Mlir-commits] [mlir] 80dc5aa - [flang][mlir][OpenMP] Add linear modifier (val, ref, uval) (#187142)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Wed Mar 25 08:17:37 PDT 2026
Author: Chi-Chun, Chen
Date: 2026-03-25T10:17:30-05:00
New Revision: 80dc5aa537264f409d83097ce16b7e3abe6b84c1
URL: https://github.com/llvm/llvm-project/commit/80dc5aa537264f409d83097ce16b7e3abe6b84c1
DIFF: https://github.com/llvm/llvm-project/commit/80dc5aa537264f409d83097ce16b7e3abe6b84c1.diff
LOG: [flang][mlir][OpenMP] Add linear modifier (val, ref, uval) (#187142)
Add support for OpenMP linear modifiers `val`, `ref`, and `uval` as
defined in OpenMP 5.2 (5.4.6).
Added:
flang/test/Lower/OpenMP/linear_modifier.f90
Modified:
flang/lib/Lower/OpenMP/ClauseProcessor.cpp
flang/lib/Lower/OpenMP/ClauseProcessor.h
flang/lib/Lower/OpenMP/OpenMP.cpp
flang/test/Lower/OpenMP/composite_simd_linear.f90
flang/test/Lower/OpenMP/declare-simd.f90
flang/test/Lower/OpenMP/distribute-parallel-do-simd.f90
flang/test/Lower/OpenMP/simd-linear.f90
flang/test/Lower/OpenMP/wsloop-linear.f90
mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td
mlir/include/mlir/Dialect/OpenMP/OpenMPEnums.td
mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
mlir/test/Dialect/OpenMP/invalid.mlir
mlir/test/Dialect/OpenMP/ops.mlir
Removed:
################################################################################
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
index 8e50c38ce68cb..75df4163c8a55 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -1488,16 +1488,32 @@ bool ClauseProcessor::processIsDevicePtr(
return clauseFound;
}
-bool ClauseProcessor::processLinear(mlir::omp::LinearClauseOps &result) const {
+bool ClauseProcessor::processLinear(mlir::omp::LinearClauseOps &result,
+ bool isDeclareSimd) const {
lower::StatementContext stmtCtx;
+ std::vector<mlir::Attribute> typeAttrs;
+ std::vector<mlir::Attribute> linearModAttrs;
return findRepeatableClause<
omp::clause::Linear>([&](const omp::clause::Linear &clause,
const parser::CharBlock &) {
auto &objects = std::get<omp::ObjectList>(clause.t);
- static std::vector<mlir::Attribute> typeAttrs;
- if (!result.linearVars.size())
- typeAttrs.clear();
+ std::optional<mlir::omp::LinearModifier> explicitLinearMod;
+ if (auto &linearModifier =
+ std::get<std::optional<omp::clause::Linear::LinearModifier>>(
+ clause.t)) {
+ switch (*linearModifier) {
+ case omp::clause::Linear::LinearModifier::Val:
+ explicitLinearMod = mlir::omp::LinearModifier::val;
+ break;
+ case omp::clause::Linear::LinearModifier::Ref:
+ explicitLinearMod = mlir::omp::LinearModifier::ref;
+ break;
+ case omp::clause::Linear::LinearModifier::Uval:
+ explicitLinearMod = mlir::omp::LinearModifier::uval;
+ break;
+ }
+ }
for (const omp::Object &object : objects) {
semantics::Symbol *sym = object.sym();
@@ -1512,10 +1528,6 @@ bool ClauseProcessor::processLinear(mlir::omp::LinearClauseOps &result) const {
mlir::Value operand =
fir::getBase(converter.genExprValue(toEvExpr(*mod), stmtCtx));
result.linearStepVars.append(objects.size(), operand);
- } else if (std::get<std::optional<omp::clause::Linear::LinearModifier>>(
- clause.t)) {
- mlir::Location currentLocation = converter.getCurrentLocation();
- TODO(currentLocation, "Linear modifiers not yet implemented");
} else {
// If nothing is present, add the default step of 1.
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
@@ -1525,9 +1537,44 @@ bool ClauseProcessor::processLinear(mlir::omp::LinearClauseOps &result) const {
firOpBuilder.createIntegerConstant(currentLocation, integerTy, 1);
result.linearStepVars.append(objects.size(), operand);
}
+
+ // Determine the linear modifier:
+ // 1. Use explicit modifier if provided.
+ // 2. For OpenMP >= 5.2 (Section 5.4.6: "the default linear-modifier
+ // is val"):
+ // - declare simd: "ref" for POINTER or non-VALUE dummy args,
+ // "val" otherwise.
+ // - do/simd: always "val".
+ // 3. Otherwise, leave unset (UnitAttr placeholder).
+ auto getDeclareSimdDefaultMod = [](const semantics::Symbol &sym) {
+ const auto &ultimate = sym.GetUltimate();
+ if (semantics::IsPointer(ultimate))
+ return mlir::omp::LinearModifier::ref;
+ if (const auto *obj =
+ ultimate.detailsIf<semantics::ObjectEntityDetails>())
+ if (obj->isDummy() && !semantics::IsValue(ultimate))
+ return mlir::omp::LinearModifier::ref;
+ return mlir::omp::LinearModifier::val;
+ };
+
+ std::optional<mlir::omp::LinearModifier> linearMod;
+ if (explicitLinearMod)
+ linearMod = *explicitLinearMod;
+ else if (semaCtx.langOptions().OpenMPVersion >= 52)
+ linearMod = isDeclareSimd ? getDeclareSimdDefaultMod(*sym)
+ : mlir::omp::LinearModifier::val;
+
+ if (linearMod)
+ linearModAttrs.push_back(mlir::omp::LinearModifierAttr::get(
+ &converter.getMLIRContext(), *linearMod));
+ else
+ linearModAttrs.push_back(
+ mlir::UnitAttr::get(&converter.getMLIRContext()));
}
result.linearVarTypes =
mlir::ArrayAttr::get(&converter.getMLIRContext(), typeAttrs);
+ result.linearModifiers =
+ mlir::ArrayAttr::get(&converter.getMLIRContext(), linearModAttrs);
});
}
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.h b/flang/lib/Lower/OpenMP/ClauseProcessor.h
index 52e69c1796876..6c6056aac77e3 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.h
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.h
@@ -143,7 +143,8 @@ class ClauseProcessor {
bool processIsDevicePtr(
lower::StatementContext &stmtCtx, mlir::omp::IsDevicePtrClauseOps &result,
llvm::SmallVectorImpl<const semantics::Symbol *> &isDeviceSyms) const;
- bool processLinear(mlir::omp::LinearClauseOps &result) const;
+ bool processLinear(mlir::omp::LinearClauseOps &result,
+ bool isDeclareSimd = false) const;
bool
processLink(llvm::SmallVectorImpl<DeclareTargetCaptureInfo> &result) const;
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 77aced25f9f52..4d135019ea70c 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -1653,6 +1653,7 @@ static void genSimdClauses(
// linear semantics on IV. Process the same here.
static void
genSimdImplicitLinear(lower::AbstractConverter &converter,
+ semantics::SemanticsContext &semaCtx,
mlir::omp::SimdOperands &clauseOps,
mlir::omp::LoopNestOperands loopNestClauseOps,
llvm::SmallVector<const semantics::Symbol *> iv) {
@@ -1671,11 +1672,15 @@ genSimdImplicitLinear(lower::AbstractConverter &converter,
}
std::vector<mlir::Attribute> typeAttrs;
+ std::vector<mlir::Attribute> linearModAttrs;
// If attributes from explicit `linear(...)` clause are present,
// carry them forward.
if (clauseOps.linearVarTypes && !clauseOps.linearVarTypes.empty())
typeAttrs.assign(clauseOps.linearVarTypes.begin(),
clauseOps.linearVarTypes.end());
+ if (clauseOps.linearModifiers && !clauseOps.linearModifiers.empty())
+ linearModAttrs.assign(clauseOps.linearModifiers.begin(),
+ clauseOps.linearModifiers.end());
for (auto [loopVar, loopStep] : llvm::zip(iv, loopNestClauseOps.loopSteps)) {
const mlir::Value variable = converter.getSymbolAddress(*loopVar);
@@ -1696,13 +1701,22 @@ genSimdImplicitLinear(lower::AbstractConverter &converter,
Fortran::semantics::IsAllocatableOrPointer(loopVar->GetUltimate()))) {
mlir::Type ty = converter.genType(*loopVar);
typeAttrs.push_back(mlir::TypeAttr::get(ty));
+ if (semaCtx.langOptions().OpenMPVersion >= 52)
+ linearModAttrs.push_back(mlir::omp::LinearModifierAttr::get(
+ &converter.getMLIRContext(), mlir::omp::LinearModifier::val));
+ else
+ linearModAttrs.push_back(
+ mlir::UnitAttr::get(&converter.getMLIRContext()));
clauseOps.linearVars.push_back(variable);
clauseOps.linearStepVars.push_back(loopStep);
}
}
- if (!typeAttrs.empty())
+ if (!typeAttrs.empty()) {
clauseOps.linearVarTypes =
mlir::ArrayAttr::get(&converter.getMLIRContext(), typeAttrs);
+ clauseOps.linearModifiers =
+ mlir::ArrayAttr::get(&converter.getMLIRContext(), linearModAttrs);
+ }
}
static void genSingleClauses(lower::AbstractConverter &converter,
@@ -3233,7 +3247,8 @@ genStandaloneSimd(lower::AbstractConverter &converter, lower::SymMap &symTable,
llvm::SmallVector<const semantics::Symbol *> iv;
genLoopNestClauses(converter, semaCtx, eval, item->clauses, loc,
loopNestClauseOps, iv);
- genSimdImplicitLinear(converter, simdClauseOps, loopNestClauseOps, iv);
+ genSimdImplicitLinear(converter, semaCtx, simdClauseOps, loopNestClauseOps,
+ iv);
EntryBlockArgs simdArgs;
simdArgs.priv.syms = dsp.getDelayedPrivSymbols();
@@ -3412,7 +3427,8 @@ static mlir::omp::DistributeOp genCompositeDistributeParallelDoSimd(
llvm::SmallVector<const semantics::Symbol *> iv;
genLoopNestClauses(converter, semaCtx, eval, simdItem->clauses, loc,
loopNestClauseOps, iv);
- genSimdImplicitLinear(converter, simdClauseOps, loopNestClauseOps, iv);
+ genSimdImplicitLinear(converter, semaCtx, simdClauseOps, loopNestClauseOps,
+ iv);
// Operation creation.
EntryBlockArgs distributeArgs;
@@ -3484,7 +3500,8 @@ static mlir::omp::DistributeOp genCompositeDistributeSimd(
llvm::SmallVector<const semantics::Symbol *> iv;
genLoopNestClauses(converter, semaCtx, eval, simdItem->clauses, loc,
loopNestClauseOps, iv);
- genSimdImplicitLinear(converter, simdClauseOps, loopNestClauseOps, iv);
+ genSimdImplicitLinear(converter, semaCtx, simdClauseOps, loopNestClauseOps,
+ iv);
// Operation creation.
EntryBlockArgs distributeArgs;
@@ -3547,7 +3564,8 @@ static mlir::omp::WsloopOp genCompositeDoSimd(
llvm::SmallVector<const semantics::Symbol *> iv;
genLoopNestClauses(converter, semaCtx, eval, simdItem->clauses, loc,
loopNestClauseOps, iv);
- genSimdImplicitLinear(converter, simdClauseOps, loopNestClauseOps, iv);
+ genSimdImplicitLinear(converter, semaCtx, simdClauseOps, loopNestClauseOps,
+ iv);
// Operation creation.
EntryBlockArgs wsloopArgs;
@@ -4032,7 +4050,7 @@ genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
ClauseProcessor cp(converter, semaCtx, clauses);
cp.processAligned(clauseOps);
cp.processInbranch(clauseOps);
- cp.processLinear(clauseOps);
+ cp.processLinear(clauseOps, /*isDeclareSimd=*/true);
cp.processNotinbranch(clauseOps);
cp.processSimdlen(clauseOps);
cp.processUniform(clauseOps);
diff --git a/flang/test/Lower/OpenMP/composite_simd_linear.f90 b/flang/test/Lower/OpenMP/composite_simd_linear.f90
index 469b341c46657..ff290fc3dc4af 100644
--- a/flang/test/Lower/OpenMP/composite_simd_linear.f90
+++ b/flang/test/Lower/OpenMP/composite_simd_linear.f90
@@ -1,4 +1,5 @@
-! RUN: %flang_fc1 -fopenmp -emit-hlfir %s -o - 2>&1 | FileCheck %s
+! RUN: %flang_fc1 -fopenmp -emit-hlfir %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK,DEFAULT
+! RUN: %flang_fc1 -fopenmp -fopenmp-version=52 -emit-hlfir %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK,OPENMP52
subroutine do_simd
@@ -8,7 +9,8 @@ subroutine do_simd
!CHECK: %{{.*}} = arith.constant 1 : i32
!CHECK: %[[IV_STEP:.*]] = arith.constant 1 : i32
!CHECK: omp.wsloop {
-!CHECK: omp.simd linear(%[[X]]#0 : !fir.ref<i32> = %[[CONST]] : i32, %[[I]]#0 : !fir.ref<i32> = %[[IV_STEP]] : i32) {
+!DEFAULT: omp.simd linear(%[[X]]#0 : !fir.ref<i32> = %[[CONST]] : i32, %[[I]]#0 : !fir.ref<i32> = %[[IV_STEP]] : i32) {
+!OPENMP52: omp.simd linear(val(%[[X]]#0 : !fir.ref<i32> = %[[CONST]] : i32), val(%[[I]]#0 : !fir.ref<i32> = %[[IV_STEP]] : i32)) {
!CHECK: }
!CHECK: } {linear_var_types = [i32, i32], omp.composite}
!CHECK: } {omp.composite}
@@ -24,7 +26,8 @@ subroutine distribute_simd
!CHECK: %[[I:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFdistribute_simdEi"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: omp.teams {
!CHECK: omp.distribute {
-!CHECK: omp.simd linear(%[[I]]#0 : !fir.ref<i32> = %c1_i32 : i32) {
+!DEFAULT: omp.simd linear({{.*}}) {
+!OPENMP52: omp.simd linear(val({{.*}})) {
!CHECK: } {linear_var_types = [i32], omp.composite}
!CHECK: } {omp.composite}
integer :: i
@@ -45,7 +48,8 @@ subroutine distribute_parallel_do
!CHECK: %[[CONST]] = arith.constant 1 : i32
!CHECK: omp.distribute {
!CHECK: omp.wsloop {
-!CHECK: omp.simd linear(%[[I]]#0 : !fir.ref<i32> = %[[CONST]] : i32) {
+!DEFAULT: omp.simd linear(%[[I]]#0 : !fir.ref<i32> = %[[CONST]] : i32) {
+!OPENMP52: omp.simd linear(val(%[[I]]#0 : !fir.ref<i32> = %[[CONST]] : i32)) {
!$omp teams
!$omp distribute parallel do simd linear(i:1)
do i = 1, N
@@ -63,7 +67,8 @@ subroutine parallel_do
!CHECK: %{{.*}} = arith.constant 1 : i32
!CHECK: %[[IV_STEP:.*]] = arith.constant 1 : i32
!CHECK: omp.wsloop {
-!CHECK: omp.simd linear(%[[X]]#0 : !fir.ref<i32> = %[[LINEAR_STEP]] : i32, %[[I]]#0 : !fir.ref<i32> = %[[IV_STEP]] : i32) {
+!DEFAULT: omp.simd linear(%[[X]]#0 : !fir.ref<i32> = %[[LINEAR_STEP]] : i32, %[[I]]#0 : !fir.ref<i32> = %[[IV_STEP]] : i32) {
+!OPENMP52: omp.simd linear(val(%[[X]]#0 : !fir.ref<i32> = %[[LINEAR_STEP]] : i32), val(%[[I]]#0 : !fir.ref<i32> = %[[IV_STEP]] : i32)) {
integer :: x
!$omp parallel do simd linear(x:2)
do i = 1, N
@@ -80,7 +85,8 @@ subroutine teams_distribute
!CHECK: {{.*}} = arith.constant 1 : i32
!CHECK: %[[IV_STEP:.*]] = arith.constant 1 : i32
!CHECK: omp.distribute {
-!CHECK: omp.simd linear(%[[X]]#0 : !fir.ref<i32> = %[[LINEAR_STEP]] : i32, %[[I]]#0 : !fir.ref<i32> = %[[IV_STEP]] : i32) {
+!DEFAULT: omp.simd linear(%[[X]]#0 : !fir.ref<i32> = %[[LINEAR_STEP]] : i32, %[[I]]#0 : !fir.ref<i32> = %[[IV_STEP]] : i32) {
+!OPENMP52: omp.simd linear(val(%[[X]]#0 : !fir.ref<i32> = %[[LINEAR_STEP]] : i32), val(%[[I]]#0 : !fir.ref<i32> = %[[IV_STEP]] : i32)) {
integer :: x
!$omp teams distribute simd linear(x)
do i = 1, N
@@ -99,7 +105,8 @@ subroutine teams_distribute_parallel_do
!CHECK: %[[IV_STEP:.*]] = arith.constant 1 : i32
!CHECK: omp.distribute {
!CHECK: omp.wsloop {
-!CHECK: omp.simd linear(%[[X]]#0 : !fir.ref<i32> = %c1_i32 : i32, %[[I]]#0 : !fir.ref<i32> = %c1_i32_1 : i32) {
+!DEFAULT: omp.simd linear(%[[X]]#0 : !fir.ref<i32> = %c1_i32 : i32, %[[I]]#0 : !fir.ref<i32> = %c1_i32_1 : i32) {
+!OPENMP52: omp.simd linear(val(%[[X]]#0 : !fir.ref<i32> = %c1_i32 : i32), val(%[[I]]#0 : !fir.ref<i32> = %c1_i32_1 : i32)) {
integer :: x
!$omp teams distribute parallel do simd linear(x)
do i = 1, N
diff --git a/flang/test/Lower/OpenMP/declare-simd.f90 b/flang/test/Lower/OpenMP/declare-simd.f90
index 5b578b436817a..b2c4592ad4e8a 100644
--- a/flang/test/Lower/OpenMP/declare-simd.f90
+++ b/flang/test/Lower/OpenMP/declare-simd.f90
@@ -57,7 +57,7 @@ end subroutine declare_simd_linear
! CHECK: %[[SCOPE:.*]] = fir.dummy_scope : !fir.dscope
! CHECK: %[[I:.*]]:2 = hlfir.declare %{{.*}} dummy_scope %[[SCOPE]] arg 4 {{.*}} : (!fir.ref<i32>, !fir.dscope) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: %[[C1:.*]] = arith.constant 1 : i32
-! CHECK: omp.declare_simd linear(%[[I]]#0 : !fir.ref<i32> = %[[C1]] : i32) {linear_var_types = [i32]}{{$}}
+! CHECK: omp.declare_simd linear(ref(%[[I]]#0 : !fir.ref<i32> = %[[C1]] : i32)) {linear_var_types = [i32]}{{$}}
! CHECK: return
subroutine declare_simd_simdlen(x, y, n, i)
@@ -157,9 +157,62 @@ end subroutine declare_simd_combined
! CHECK-SAME: aligned(%[[X_DECL]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf64>>>> -> 64 : i64,
! CHECK-SAME: %[[Y_DECL]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf64>>>> -> 64 : i64)
! CHECK-SAME: inbranch
-! CHECK-SAME: linear(%[[I_DECL]]#0 : !fir.ref<i32> = %[[C1]] : i32)
+! CHECK-SAME: linear(ref(%[[I_DECL]]#0 : !fir.ref<i32> = %[[C1]] : i32))
! CHECK-SAME: simdlen(8)
! CHECK-SAME: uniform(%[[X_DECL]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf64>>>>,
! CHECK-SAME: %[[Y_DECL]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf64>>>>)
! CHECK-SAME: {linear_var_types = [i32]}{{$}}
! CHECK: return
+
+subroutine declare_simd_linear_val(a, b)
+#ifdef OMP_60
+!$omp declare_simd linear(a : val, step(2)) linear(b : val)
+#else
+!$omp declare simd linear(a : val, step(2)) linear(b : val)
+#endif
+ integer, intent(in) :: a, b
+end subroutine declare_simd_linear_val
+
+! CHECK-LABEL: func.func @_QPdeclare_simd_linear_val(
+! CHECK: %[[SCOPE:.*]] = fir.dummy_scope : !fir.dscope
+! CHECK: %[[A:.*]]:2 = hlfir.declare %{{.*}} dummy_scope %[[SCOPE]] arg 1 {{.*}} : (!fir.ref<i32>, !fir.dscope) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: %[[B:.*]]:2 = hlfir.declare %{{.*}} dummy_scope %[[SCOPE]] arg 2 {{.*}} : (!fir.ref<i32>, !fir.dscope) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: %[[C2:.*]] = arith.constant 2 : i32
+! CHECK: %[[C1:.*]] = arith.constant 1 : i32
+! CHECK: omp.declare_simd linear(val(%[[A]]#0 : !fir.ref<i32> = %[[C2]] : i32), val(%[[B]]#0 : !fir.ref<i32> = %[[C1]] : i32))
+! CHECK-SAME: {linear_var_types = [i32, i32]}{{$}}
+! CHECK: return
+
+subroutine declare_simd_linear_ref(x)
+#ifdef OMP_60
+!$omp declare_simd linear(x : ref, step(4))
+#else
+!$omp declare simd linear(x : ref, step(4))
+#endif
+ integer, allocatable, intent(inout) :: x
+end subroutine declare_simd_linear_ref
+
+! CHECK-LABEL: func.func @_QPdeclare_simd_linear_ref(
+! CHECK: %[[SCOPE:.*]] = fir.dummy_scope : !fir.dscope
+! CHECK: %[[X:.*]]:2 = hlfir.declare %{{.*}} dummy_scope %[[SCOPE]] arg 1 {{.*}} : (!fir.ref<!fir.box<!fir.heap<i32>>>, !fir.dscope) -> (!fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<!fir.box<!fir.heap<i32>>>)
+! CHECK: %[[C4:.*]] = arith.constant 4 : i32
+! CHECK: omp.declare_simd linear(ref(%[[X]]#0 : !fir.ref<!fir.box<!fir.heap<i32>>> = %[[C4]] : i32))
+! CHECK-SAME: {linear_var_types = [!fir.box<!fir.heap<i32>>]}{{$}}
+! CHECK: return
+
+subroutine declare_simd_linear_uval(y)
+#ifdef OMP_60
+!$omp declare_simd linear(y : uval)
+#else
+!$omp declare simd linear(y : uval)
+#endif
+ integer, intent(in) :: y
+end subroutine declare_simd_linear_uval
+
+! CHECK-LABEL: func.func @_QPdeclare_simd_linear_uval(
+! CHECK: %[[SCOPE:.*]] = fir.dummy_scope : !fir.dscope
+! CHECK: %[[Y:.*]]:2 = hlfir.declare %{{.*}} dummy_scope %[[SCOPE]] arg 1 {{.*}} : (!fir.ref<i32>, !fir.dscope) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: %[[C1:.*]] = arith.constant 1 : i32
+! CHECK: omp.declare_simd linear(uval(%[[Y]]#0 : !fir.ref<i32> = %[[C1]] : i32))
+! CHECK-SAME: {linear_var_types = [i32]}{{$}}
+! CHECK: return
diff --git a/flang/test/Lower/OpenMP/distribute-parallel-do-simd.f90 b/flang/test/Lower/OpenMP/distribute-parallel-do-simd.f90
index 7f91177cc3311..2543e9470452a 100644
--- a/flang/test/Lower/OpenMP/distribute-parallel-do-simd.f90
+++ b/flang/test/Lower/OpenMP/distribute-parallel-do-simd.f90
@@ -1,8 +1,10 @@
! This test checks lowering of OpenMP DISTRIBUTE PARALLEL DO SIMD composite
! constructs.
-! RUN: bbc -fopenmp -emit-hlfir %s -o - | FileCheck %s
-! RUN: %flang_fc1 -fopenmp -emit-hlfir %s -o - | FileCheck %s
+! RUN: bbc -fopenmp -emit-hlfir %s -o - | FileCheck %s --check-prefixes=CHECK,DEFAULT
+! RUN: %flang_fc1 -fopenmp -emit-hlfir %s -o - | FileCheck %s --check-prefixes=CHECK,DEFAULT
+! RUN: bbc -fopenmp -fopenmp-version=52 -emit-hlfir %s -o - | FileCheck %s --check-prefixes=CHECK,OPENMP52
+! RUN: %flang_fc1 -fopenmp -fopenmp-version=52 -emit-hlfir %s -o - | FileCheck %s --check-prefixes=CHECK,OPENMP52
! CHECK-LABEL: func.func @_QPdistribute_parallel_do_simd_num_threads(
subroutine distribute_parallel_do_simd_num_threads()
@@ -11,7 +13,8 @@ subroutine distribute_parallel_do_simd_num_threads()
! CHECK: omp.parallel num_threads({{.*}}) {
! CHECK: omp.distribute {
! CHECK-NEXT: omp.wsloop {
- ! CHECK-NEXT: omp.simd linear({{.*}}) {
+ ! DEFAULT-NEXT: omp.simd linear({{.*}}) {
+ ! OPENMP52-NEXT: omp.simd linear(val({{.*}})) {
! CHECK-NEXT: omp.loop_nest
!$omp distribute parallel do simd num_threads(10)
do index_ = 1, 10
@@ -28,7 +31,8 @@ subroutine distribute_parallel_do_simd_dist_schedule()
! CHECK: omp.parallel {
! CHECK: omp.distribute dist_schedule_static dist_schedule_chunk_size({{.*}}) {
! CHECK-NEXT: omp.wsloop {
- ! CHECK-NEXT: omp.simd linear({{.*}}) {
+ ! DEFAULT-NEXT: omp.simd linear({{.*}}) {
+ ! OPENMP52-NEXT: omp.simd linear(val({{.*}})) {
! CHECK-NEXT: omp.loop_nest
!$omp distribute parallel do simd dist_schedule(static, 4)
do index_ = 1, 10
@@ -45,7 +49,8 @@ subroutine distribute_parallel_do_simd_schedule()
! CHECK: omp.parallel {
! CHECK: omp.distribute {
! CHECK-NEXT: omp.wsloop schedule(static = {{.*}}) {
- ! CHECK-NEXT: omp.simd linear({{.*}}) {
+ ! DEFAULT-NEXT: omp.simd linear({{.*}}) {
+ ! OPENMP52-NEXT: omp.simd linear(val({{.*}})) {
! CHECK-NEXT: omp.loop_nest
!$omp distribute parallel do simd schedule(static, 4)
do index_ = 1, 10
@@ -62,7 +67,8 @@ subroutine distribute_parallel_do_simd_simdlen()
! CHECK: omp.parallel {
! CHECK: omp.distribute {
! CHECK-NEXT: omp.wsloop {
- ! CHECK-NEXT: omp.simd linear({{.*}}) simdlen(4) {
+ ! DEFAULT-NEXT: omp.simd linear({{.*}}) simdlen(4) {
+ ! OPENMP52-NEXT: omp.simd linear(val({{.*}})) simdlen(4) {
! CHECK-NEXT: omp.loop_nest
!$omp distribute parallel do simd simdlen(4)
do index_ = 1, 10
@@ -86,8 +92,10 @@ subroutine distribute_parallel_do_simd_private()
! CHECK: omp.parallel {
! CHECK: omp.distribute {
! CHECK-NEXT: omp.wsloop {
- ! CHECK-NEXT: omp.simd linear(%{{.*}}) private(@{{.*}} %[[X]]#0 -> %[[X_ARG:[^:]+]]
- ! CHECK-SAME: : !fir.ref<i64>) {
+ ! DEFAULT-NEXT: omp.simd linear(%{{.*}}) private(@{{.*}} %[[X]]#0 -> %[[X_ARG:[^:]+]]
+ ! DEFAULT-SAME: : !fir.ref<i64>) {
+ ! OPENMP52-NEXT: omp.simd linear(val(%{{.*}})) private(@{{.*}} %[[X]]#0 -> %[[X_ARG:[^:]+]]
+ ! OPENMP52-SAME: : !fir.ref<i64>) {
! CHECK-NEXT: omp.loop_nest
! CHECK: %[[X_PRIV:.*]]:2 = hlfir.declare %[[X_ARG]]
!$omp distribute parallel do simd private(x)
diff --git a/flang/test/Lower/OpenMP/linear_modifier.f90 b/flang/test/Lower/OpenMP/linear_modifier.f90
new file mode 100644
index 0000000000000..624fa170cc1bc
--- /dev/null
+++ b/flang/test/Lower/OpenMP/linear_modifier.f90
@@ -0,0 +1,54 @@
+! This test checks lowering of OpenMP linear clause with implicit modifiers.
+
+! RUN: %flang_fc1 -fopenmp -fopenmp-version=52 -emit-hlfir %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK,OPENMP52
+! RUN: %flang_fc1 -fopenmp -fopenmp-version=45 -emit-hlfir %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK,OPENMP45
+
+!CHECK: %[[X_alloca:.*]] = fir.alloca i32 {bindc_name = "x", uniq_name = "_QFsimple_linearEx"}
+!CHECK: %[[X:.*]]:2 = hlfir.declare %[[X_alloca]] {uniq_name = "_QFsimple_linearEx"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK: %[[const:.*]] = arith.constant 1 : i32
+subroutine simple_linear
+ implicit none
+ integer :: x, y, i
+ !OPENMP52: omp.wsloop linear(val(%[[X]]#0 : !fir.ref<i32> = %[[const]] : i32)) {{.*}}
+ !OPENMP45: omp.wsloop linear(%[[X]]#0 : !fir.ref<i32> = %[[const]] : i32) {{.*}}
+ !$omp do linear(x)
+ do i = 1, 10
+ y = x + 2
+ end do
+ !$omp end do
+ !CHECK: } {linear_var_types = [i32]}
+end subroutine
+
+subroutine linear_step
+!CHECK: %[[X_alloca:.*]] = fir.alloca i32 {bindc_name = "x", uniq_name = "_QFlinear_stepEx"}
+!CHECK: %[[X:.*]]:2 = hlfir.declare %[[X_alloca]] {uniq_name = "_QFlinear_stepEx"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+ implicit none
+ integer :: x, y, i
+ !CHECK: %[[const:.*]] = arith.constant 4 : i32
+ !OPENMP52: omp.wsloop linear(val(%[[X]]#0 : !fir.ref<i32> = %[[const]] : i32)) {{.*}}
+ !OPENMP45: omp.wsloop linear(%[[X]]#0 : !fir.ref<i32> = %[[const]] : i32) {{.*}}
+ !$omp do linear(x:4)
+ do i = 1, 10
+ y = x + 2
+ end do
+ !$omp end do
+ !CHECK: } {linear_var_types = [i32]}
+end subroutine
+
+subroutine do_simd_linear
+!CHECK: %[[I:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFdo_simd_linearEi"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK: %[[X:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFdo_simd_linearEx"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK: %[[CONST:.*]] = arith.constant 1 : i32
+!CHECK: %{{.*}} = arith.constant 1 : i32
+!CHECK: %[[IV_STEP:.*]] = arith.constant 1 : i32
+!CHECK: omp.wsloop {
+!OPENMP52: omp.simd linear(val(%[[X]]#0 : !fir.ref<i32> = %[[CONST]] : i32), val(%[[I]]#0 : !fir.ref<i32> = %[[IV_STEP]] : i32)) {
+!OPENMP45: omp.simd linear(%[[X]]#0 : !fir.ref<i32> = %[[CONST]] : i32, %[[I]]#0 : !fir.ref<i32> = %[[IV_STEP]] : i32) {
+ integer :: x
+ !$omp do simd linear(x:1)
+ do i = 1, 10
+ end do
+ !$omp end do simd
+!CHECK: } {linear_var_types = [i32, i32], omp.composite}
+!CHECK: } {omp.composite}
+end subroutine do_simd_linear
diff --git a/flang/test/Lower/OpenMP/simd-linear.f90 b/flang/test/Lower/OpenMP/simd-linear.f90
index b478cafb4fa1d..db5425e153a66 100644
--- a/flang/test/Lower/OpenMP/simd-linear.f90
+++ b/flang/test/Lower/OpenMP/simd-linear.f90
@@ -16,7 +16,7 @@
subroutine simple_linear
implicit none
integer :: x, y, i
- !CHECK: omp.simd linear(%[[X]]#0 : !fir.ref<i32> = %[[const]] : i32) {{.*}}
+ !CHECK: omp.simd linear(val(%[[X]]#0 : !fir.ref<i32> = %[[const]] : i32)) {{.*}}
!IMPLICIT: omp.simd linear(%[[X]]#0 : !fir.ref<i32> = %[[const]] : i32, %[[I]]#0 : !fir.ref<i32> = %{{.*}} : i32) {{.*}}
!$omp simd linear(x)
@@ -39,7 +39,7 @@ subroutine linear_step
implicit none
integer :: x, y, i
!CHECK: %[[const:.*]] = arith.constant 4 : i32
- !CHECK: omp.simd linear(%[[X]]#0 : !fir.ref<i32> = %[[const]] : i32) {{.*}}
+ !CHECK: omp.simd linear(val(%[[X]]#0 : !fir.ref<i32> = %[[const]] : i32)) {{.*}}
!IMPLICIT: omp.simd linear(%[[X]]#0 : !fir.ref<i32> = %[[const]] : i32, %[[I]]#0 : !fir.ref<i32> = %{{.*}} : i32) {{.*}}
!$omp simd linear(x:4)
@@ -71,7 +71,7 @@ subroutine linear_expr
!IMPLICIT: %[[const:.*]] = arith.constant 4 : i32
!IMPLICIT: %[[LINEAR_EXPR:.*]] = arith.addi %[[LOAD_A]], %[[const]] : i32
- !CHECK: omp.simd linear(%[[X]]#0 : !fir.ref<i32> = %[[LINEAR_EXPR]] : i32) {{.*}}
+ !CHECK: omp.simd linear(val(%[[X]]#0 : !fir.ref<i32> = %[[LINEAR_EXPR]] : i32)) {{.*}}
!IMPLICIT: omp.simd linear(%[[X]]#0 : !fir.ref<i32> = %[[LINEAR_EXPR]] : i32, %[[I]]#0 : !fir.ref<i32> = {{.*}} : i32) {{.*}}
!$omp simd linear(x:a+4)
@@ -96,11 +96,11 @@ subroutine non_i32_type
!IMPLICIT: %[[STEP_VAR_CONST:.*]] = arith.constant 1 : i32
integer(kind=8)::j=0
- !CHECK: omp.simd linear(%[[J_DECLARE]]#0 : !fir.ref<i64> = %[[CONST]] : i64) {{.*}}
+ !CHECK: omp.simd linear(val(%[[J_DECLARE]]#0 : !fir.ref<i64> = %[[CONST]] : i64)) {{.*}}
!IMPLICIT: omp.simd linear(%[[J_DECLARE]]#0 : !fir.ref<i64> = %[[CONST]] : i64, %[[I_DECLARE]]#0 : !fir.ref<i32> = %[[STEP_VAR_CONST]] : i32)
!$omp simd linear(j:1_8)
do i = 1,10
- end do
+ end do
!$omp end simd
!CHECK: } {linear_var_types = [i64]}
!IMPLICIT: } {linear_var_types = [i64, i32]}
diff --git a/flang/test/Lower/OpenMP/wsloop-linear.f90 b/flang/test/Lower/OpenMP/wsloop-linear.f90
index 67588e24c4c5a..78aede0cbfa11 100644
--- a/flang/test/Lower/OpenMP/wsloop-linear.f90
+++ b/flang/test/Lower/OpenMP/wsloop-linear.f90
@@ -1,7 +1,8 @@
! This test checks lowering of OpenMP DO Directive (Worksharing)
! with linear clause
-! RUN: %flang_fc1 -fopenmp -emit-hlfir %s -o - 2>&1 | FileCheck %s
+! RUN: %flang_fc1 -fopenmp -emit-hlfir %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK,DEFAULT
+! RUN: %flang_fc1 -fopenmp -fopenmp-version=52 -emit-hlfir %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK,OPENMP52
!CHECK: %[[X_alloca:.*]] = fir.alloca i32 {bindc_name = "x", uniq_name = "_QFsimple_linearEx"}
!CHECK: %[[X:.*]]:2 = hlfir.declare %[[X_alloca]] {uniq_name = "_QFsimple_linearEx"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
@@ -9,7 +10,8 @@
subroutine simple_linear
implicit none
integer :: x, y, i
- !CHECK: omp.wsloop linear(%[[X]]#0 : !fir.ref<i32> = %[[const]] : i32) {{.*}}
+ !DEFAULT: omp.wsloop linear(%[[X]]#0 : !fir.ref<i32> = %[[const]] : i32) {{.*}}
+ !OPENMP52: omp.wsloop linear(val(%[[X]]#0 : !fir.ref<i32> = %[[const]] : i32)) {{.*}}
!$omp do linear(x)
!CHECK: %[[LOAD:.*]] = fir.load %[[X]]#0 : !fir.ref<i32>
!CHECK: %[[const:.*]] = arith.constant 2 : i32
@@ -28,7 +30,8 @@ subroutine linear_step
implicit none
integer :: x, y, i
!CHECK: %[[const:.*]] = arith.constant 4 : i32
- !CHECK: omp.wsloop linear(%[[X]]#0 : !fir.ref<i32> = %[[const]] : i32) {{.*}}
+ !DEFAULT: omp.wsloop linear(%[[X]]#0 : !fir.ref<i32> = %[[const]] : i32) {{.*}}
+ !OPENMP52: omp.wsloop linear(val(%[[X]]#0 : !fir.ref<i32> = %[[const]] : i32)) {{.*}}
!$omp do linear(x:4)
!CHECK: %[[LOAD:.*]] = fir.load %[[X]]#0 : !fir.ref<i32>
!CHECK: %[[const:.*]] = arith.constant 2 : i32
@@ -50,7 +53,8 @@ subroutine linear_expr
!CHECK: %[[LOAD_A:.*]] = fir.load %[[A]]#0 : !fir.ref<i32>
!CHECK: %[[const:.*]] = arith.constant 4 : i32
!CHECK: %[[LINEAR_EXPR:.*]] = arith.addi %[[LOAD_A]], %[[const]] : i32
- !CHECK: omp.wsloop linear(%[[X]]#0 : !fir.ref<i32> = %[[LINEAR_EXPR]] : i32) {{.*}}
+ !DEFAULT: omp.wsloop linear(%[[X]]#0 : !fir.ref<i32> = %[[LINEAR_EXPR]] : i32) {{.*}}
+ !OPENMP52: omp.wsloop linear(val(%[[X]]#0 : !fir.ref<i32> = %[[LINEAR_EXPR]] : i32)) {{.*}}
!$omp do linear(x:a+4)
do i = 1, 10
y = x + 2
diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td
index 23c2fbdfd7368..b5a047dc613ff 100644
--- a/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td
+++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPClauses.td
@@ -773,12 +773,14 @@ class OpenMP_LinearClauseSkip<
extraClassDeclaration> {
let arguments = (ins Variadic<AnyType>:$linear_vars,
Variadic<AnyInteger>:$linear_step_vars,
- OptionalAttr<ArrayAttr>:$linear_var_types);
+ OptionalAttr<ArrayAttr>:$linear_var_types,
+ OptionalAttr<ArrayAttr>:$linear_modifiers);
let optAssemblyFormat = [{
`linear` `(`
custom<LinearClause>($linear_vars, type($linear_vars),
- $linear_step_vars, type($linear_step_vars)) `)`
+ $linear_step_vars, type($linear_step_vars),
+ $linear_modifiers) `)`
}];
let description = [{
@@ -786,6 +788,10 @@ class OpenMP_LinearClauseSkip<
associated linear operand. Note that the `linear_vars` and
`linear_step_vars` variadic lists should contain the same number of
elements.
+
+ The `linear_modifiers` attribute optionally specifies a per-variable
+ linear-modifier: `val`, `ref`, or `uval`. When omitted, the default
+ modifier is determined by the language semantics.
}];
}
diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPEnums.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPEnums.td
index 707850cbb47b7..06c5e0b89ff05 100644
--- a/mlir/include/mlir/Dialect/OpenMP/OpenMPEnums.td
+++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPEnums.td
@@ -237,6 +237,22 @@ def OrderModifier
def OrderModifierAttr : EnumAttr<OpenMP_Dialect, OrderModifier,
"order_mod">;
+//===----------------------------------------------------------------------===//
+// linear_modifier enum.
+//===----------------------------------------------------------------------===//
+
+def LinearModifierVal : I32EnumAttrCase<"val", 0>;
+def LinearModifierRef : I32EnumAttrCase<"ref", 1>;
+def LinearModifierUval : I32EnumAttrCase<"uval", 2>;
+
+def LinearModifier : OpenMP_I32EnumAttr<"LinearModifier", "linear modifier",
+ [LinearModifierVal, LinearModifierRef,
+ LinearModifierUval]>;
+
+def LinearModifierAttr : OpenMP_EnumAttr<LinearModifier, "linear_modifier"> {
+ let assemblyFormat = "`(` $value `)`";
+}
+
//===----------------------------------------------------------------------===//
// reduction_modifier enum.
//===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
index 7cab929d583ca..04418ee39be54 100644
--- a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
+++ b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
@@ -420,41 +420,112 @@ static void printClauseAttr(OpAsmPrinter &p, Operation *op, ClauseAttr attr) {
/// linear ::= `linear` `(` linear-list `)`
/// linear-list := linear-val | linear-val linear-list
/// linear-val := ssa-id-and-type `=` ssa-id-and-type
+/// | `val` `(` ssa-id-and-type `=` ssa-id-and-type `)`
+/// | `ref` `(` ssa-id-and-type `=` ssa-id-and-type `)`
+/// | `uval` `(` ssa-id-and-type `=` ssa-id-and-type `)`
static ParseResult parseLinearClause(
OpAsmParser &parser,
SmallVectorImpl<OpAsmParser::UnresolvedOperand> &linearVars,
SmallVectorImpl<Type> &linearTypes,
SmallVectorImpl<OpAsmParser::UnresolvedOperand> &linearStepVars,
- SmallVectorImpl<Type> &linearStepTypes) {
- return parser.parseCommaSeparatedList([&]() {
+ SmallVectorImpl<Type> &linearStepTypes, ArrayAttr &linearModifiers) {
+ SmallVector<Attribute> modifiers;
+ auto result = parser.parseCommaSeparatedList([&]() {
OpAsmParser::UnresolvedOperand var;
Type type, stepType;
OpAsmParser::UnresolvedOperand stepVar;
+
+ std::optional<omp::LinearModifier> linearModifier;
+ if (succeeded(parser.parseOptionalKeyword("val"))) {
+ linearModifier = omp::LinearModifier::val;
+ } else if (succeeded(parser.parseOptionalKeyword("ref"))) {
+ linearModifier = omp::LinearModifier::ref;
+ } else if (succeeded(parser.parseOptionalKeyword("uval"))) {
+ linearModifier = omp::LinearModifier::uval;
+ }
+
+ bool hasLinearModifierParens = linearModifier.has_value();
+ if (hasLinearModifierParens && parser.parseLParen())
+ return failure();
+
if (parser.parseOperand(var) || parser.parseColonType(type) ||
parser.parseEqual() || parser.parseOperand(stepVar) ||
parser.parseColonType(stepType))
return failure();
+ if (hasLinearModifierParens && parser.parseRParen())
+ return failure();
+
linearVars.push_back(var);
linearTypes.push_back(type);
linearStepVars.push_back(stepVar);
linearStepTypes.push_back(stepType);
+ if (linearModifier) {
+ modifiers.push_back(
+ omp::LinearModifierAttr::get(parser.getContext(), *linearModifier));
+ } else {
+ modifiers.push_back(UnitAttr::get(parser.getContext()));
+ }
return success();
});
+ if (failed(result))
+ return failure();
+ linearModifiers = ArrayAttr::get(parser.getContext(), modifiers);
+ return success();
}
/// Print Linear Clause
static void printLinearClause(OpAsmPrinter &p, Operation *op,
ValueRange linearVars, TypeRange linearTypes,
- ValueRange linearStepVars,
- TypeRange stepVarTypes) {
+ ValueRange linearStepVars, TypeRange stepVarTypes,
+ ArrayAttr linearModifiers) {
size_t linearVarsSize = linearVars.size();
for (unsigned i = 0; i < linearVarsSize; ++i) {
- std::string separator = i == linearVarsSize - 1 ? "" : ", ";
+ if (i != 0)
+ p << ", ";
+ // Print modifier keyword wrapper if present.
+ Attribute modAttr = linearModifiers ? linearModifiers[i] : nullptr;
+ auto mod = modAttr ? dyn_cast<omp::LinearModifierAttr>(modAttr) : nullptr;
+ if (mod) {
+ p << omp::stringifyLinearModifier(mod.getValue()) << "(";
+ }
p << linearVars[i] << " : " << linearTypes[i];
p << " = " << linearStepVars[i] << " : " << stepVarTypes[i];
- p << separator;
+ if (mod)
+ p << ")";
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Verifier for Linear modifier
+//===----------------------------------------------------------------------===//
+
+/// OpenMP 5.2, Section 5.4.6: "A linear-modifier may be specified as ref or
+/// uval only on a declare simd directive."
+/// Also verifies that modifier count matches variable count.
+static LogicalResult
+verifyLinearModifiers(Operation *op, std::optional<ArrayAttr> linearModifiers,
+ OperandRange linearVars, bool isDeclareSimd = false) {
+ if (!linearModifiers)
+ return success();
+ if (linearModifiers->size() != linearVars.size())
+ return op->emitOpError()
+ << "expected as many linear modifiers as linear variables";
+ if (!isDeclareSimd) {
+ for (Attribute attr : *linearModifiers) {
+ if (!attr)
+ continue;
+ auto modAttr = dyn_cast<omp::LinearModifierAttr>(attr);
+ if (!modAttr)
+ continue;
+ omp::LinearModifier mod = modAttr.getValue();
+ if (mod == omp::LinearModifier::ref || mod == omp::LinearModifier::uval)
+ return op->emitOpError()
+ << "linear modifier '" << omp::stringifyLinearModifier(mod)
+ << "' may only be specified on a declare simd directive";
+ }
}
+ return success();
}
//===----------------------------------------------------------------------===//
@@ -2897,7 +2968,7 @@ void WsloopOp::build(OpBuilder &builder, OperationState &state,
ArrayRef<NamedAttribute> attributes) {
build(builder, state, /*allocate_vars=*/{}, /*allocator_vars=*/{},
/*linear_vars=*/ValueRange(), /*linear_step_vars=*/ValueRange(),
- /*linear_var_types*/ nullptr,
+ /*linear_var_types*/ nullptr, /*linear_modifiers=*/nullptr,
/*nowait=*/false, /*order=*/nullptr, /*order_mod=*/nullptr,
/*ordered=*/nullptr, /*private_vars=*/{}, /*private_syms=*/nullptr,
/*private_needs_barrier=*/false,
@@ -2916,16 +2987,19 @@ void WsloopOp::build(OpBuilder &builder, OperationState &state,
WsloopOp::build(
builder, state,
/*allocate_vars=*/{}, /*allocator_vars=*/{}, clauses.linearVars,
- clauses.linearStepVars, clauses.linearVarTypes, clauses.nowait,
- clauses.order, clauses.orderMod, clauses.ordered, clauses.privateVars,
- makeArrayAttr(ctx, clauses.privateSyms), clauses.privateNeedsBarrier,
- clauses.reductionMod, clauses.reductionVars,
+ clauses.linearStepVars, clauses.linearVarTypes, clauses.linearModifiers,
+ clauses.nowait, clauses.order, clauses.orderMod, clauses.ordered,
+ clauses.privateVars, makeArrayAttr(ctx, clauses.privateSyms),
+ clauses.privateNeedsBarrier, clauses.reductionMod, clauses.reductionVars,
makeDenseBoolArrayAttr(ctx, clauses.reductionByref),
makeArrayAttr(ctx, clauses.reductionSyms), clauses.scheduleKind,
clauses.scheduleChunk, clauses.scheduleMod, clauses.scheduleSimd);
}
LogicalResult WsloopOp::verify() {
+ if (failed(
+ verifyLinearModifiers(*this, getLinearModifiers(), getLinearVars())))
+ return failure();
if (getLinearVars().size() &&
getLinearVarTypes().value().size() != getLinearVars().size())
return emitError() << "Ill-formed type attributes for linear variables";
@@ -2965,16 +3039,17 @@ LogicalResult WsloopOp::verifyRegions() {
void SimdOp::build(OpBuilder &builder, OperationState &state,
const SimdOperands &clauses) {
MLIRContext *ctx = builder.getContext();
- SimdOp::build(
- builder, state, clauses.alignedVars,
- makeArrayAttr(ctx, clauses.alignments), clauses.ifExpr,
- clauses.linearVars, clauses.linearStepVars, clauses.linearVarTypes,
- clauses.nontemporalVars, clauses.order, clauses.orderMod,
- clauses.privateVars, makeArrayAttr(ctx, clauses.privateSyms),
- clauses.privateNeedsBarrier, clauses.reductionMod, clauses.reductionVars,
- makeDenseBoolArrayAttr(ctx, clauses.reductionByref),
- makeArrayAttr(ctx, clauses.reductionSyms), clauses.safelen,
- clauses.simdlen);
+ SimdOp::build(builder, state, clauses.alignedVars,
+ makeArrayAttr(ctx, clauses.alignments), clauses.ifExpr,
+ clauses.linearVars, clauses.linearStepVars,
+ clauses.linearVarTypes, clauses.linearModifiers,
+ clauses.nontemporalVars, clauses.order, clauses.orderMod,
+ clauses.privateVars, makeArrayAttr(ctx, clauses.privateSyms),
+ clauses.privateNeedsBarrier, clauses.reductionMod,
+ clauses.reductionVars,
+ makeDenseBoolArrayAttr(ctx, clauses.reductionByref),
+ makeArrayAttr(ctx, clauses.reductionSyms), clauses.safelen,
+ clauses.simdlen);
}
LogicalResult SimdOp::verify() {
@@ -2990,6 +3065,10 @@ LogicalResult SimdOp::verify() {
if (verifyNontemporalClause(*this, getNontemporalVars()).failed())
return failure();
+ if (failed(
+ verifyLinearModifiers(*this, getLinearModifiers(), getLinearVars())))
+ return failure();
+
bool isCompositeChildLeaf =
llvm::dyn_cast_if_present<LoopWrapperInterface>((*this)->getParentOp());
@@ -4628,6 +4707,10 @@ LogicalResult DeclareSimdOp::verify() {
if (getInbranch() && getNotinbranch())
return emitOpError("cannot have both 'inbranch' and 'notinbranch'");
+ if (failed(verifyLinearModifiers(*this, getLinearModifiers(), getLinearVars(),
+ /*isDeclareSimd=*/true)))
+ return failure();
+
return verifyAlignedClause(*this, getAlignments(), getAlignedVars());
}
@@ -4637,8 +4720,9 @@ void DeclareSimdOp::build(OpBuilder &odsBuilder, OperationState &odsState,
DeclareSimdOp::build(odsBuilder, odsState, clauses.alignedVars,
makeArrayAttr(ctx, clauses.alignments), clauses.inbranch,
clauses.linearVars, clauses.linearStepVars,
- clauses.linearVarTypes, clauses.notinbranch,
- clauses.simdlen, clauses.uniformVars);
+ clauses.linearVarTypes, clauses.linearModifiers,
+ clauses.notinbranch, clauses.simdlen,
+ clauses.uniformVars);
}
//===----------------------------------------------------------------------===//
diff --git a/mlir/test/Dialect/OpenMP/invalid.mlir b/mlir/test/Dialect/OpenMP/invalid.mlir
index cbe18b9b882da..4879ea754bf75 100644
--- a/mlir/test/Dialect/OpenMP/invalid.mlir
+++ b/mlir/test/Dialect/OpenMP/invalid.mlir
@@ -3170,6 +3170,81 @@ func.func @omp_declare_simd_branch() -> () {
// -----
+func.func @omp_wsloop_linear_ref(%lb : index, %ub : index, %step : index,
+ %data_var : memref<i32>, %linear_var : i32) {
+ // expected-error @+1 {{'omp.wsloop' op linear modifier 'ref' may only be specified on a declare simd directive}}
+ omp.wsloop linear(ref(%data_var : memref<i32> = %linear_var : i32)) {
+ omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
+ omp.yield
+ }
+ } {linear_var_types = [i32]}
+ return
+}
+
+// -----
+
+func.func @omp_wsloop_linear_uval(%lb : index, %ub : index, %step : index,
+ %data_var : memref<i32>, %linear_var : i32) {
+ // expected-error @+1 {{'omp.wsloop' op linear modifier 'uval' may only be specified on a declare simd directive}}
+ omp.wsloop linear(uval(%data_var : memref<i32> = %linear_var : i32)) {
+ omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
+ omp.yield
+ }
+ } {linear_var_types = [i32]}
+ return
+}
+
+// -----
+
+func.func @omp_simd_linear_ref(%lb : index, %ub : index, %step : index,
+ %data_var : memref<i32>, %linear_var : i32) {
+ // expected-error @+1 {{'omp.simd' op linear modifier 'ref' may only be specified on a declare simd directive}}
+ omp.simd linear(ref(%data_var : memref<i32> = %linear_var : i32)) {
+ omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
+ omp.yield
+ }
+ } {linear_var_types = [i32]}
+ return
+}
+
+// -----
+
+func.func @omp_wsloop_linear_modifiers_mismatch(%lb : index, %ub : index, %step : index,
+ %data_var : memref<i32>, %linear_var : i32) {
+ // expected-error @below {{'omp.wsloop' op expected as many linear modifiers as linear variables}}
+ "omp.wsloop"(%data_var, %linear_var) ({
+ omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
+ omp.yield
+ }
+ }) {linear_modifiers = [#omp<linear_modifier(val)>, #omp<linear_modifier(val)>],
+ operandSegmentSizes = array<i32: 0, 0, 1, 1, 0, 0, 0>} : (memref<i32>, i32) -> ()
+ return
+}
+
+// -----
+
+func.func @omp_simd_linear_modifiers_mismatch(%lb : index, %ub : index, %step : index,
+ %data_var : memref<i32>, %linear_var : i32) {
+ // expected-error @below {{'omp.simd' op expected as many linear modifiers as linear variables}}
+ "omp.simd"(%data_var, %linear_var) ({
+ omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
+ omp.yield
+ }
+ }) {linear_modifiers = [#omp<linear_modifier(val)>, #omp<linear_modifier(val)>],
+ operandSegmentSizes = array<i32: 0, 0, 1, 1, 0, 0, 0>} : (memref<i32>, i32) -> ()
+ return
+}
+
+// -----
+
+func.func @omp_declare_simd_linear_modifiers_mismatch(%iv : i32, %step : i32) {
+ // expected-error @below {{'omp.declare_simd' op expected as many linear modifiers as linear variables}}
+ "omp.declare_simd"(%iv, %step) <{linear_modifiers = [#omp<linear_modifier(val)>, #omp<linear_modifier(ref)>], operandSegmentSizes = array<i32: 0, 1, 1, 0>}> : (i32, i32) -> ()
+ return
+}
+
+// -----
+
func.func @iterator_bad_result_type(%lb : index, %ub : index, %st : index) {
// expected-error at +1 {{result #0 must be OpenMP iterator-produced list handle, but got 'index'}}
%0 = omp.iterator(%i: index) = (%lb to %ub step %st) {
diff --git a/mlir/test/Dialect/OpenMP/ops.mlir b/mlir/test/Dialect/OpenMP/ops.mlir
index ba329cc67bb14..d924d479eba90 100644
--- a/mlir/test/Dialect/OpenMP/ops.mlir
+++ b/mlir/test/Dialect/OpenMP/ops.mlir
@@ -524,6 +524,15 @@ func.func @omp_wsloop_pretty(%lb : index, %ub : index, %step : index, %data_var
}
} { linear_var_types = [i32] }
+ // CHECK: omp.wsloop linear(val(%{{.*}} : memref<i32> = %{{.*}} : i32), val(%{{.*}} : memref<i32> = %{{.*}} : i32)) schedule(static) {
+ // CHECK-NEXT: omp.loop_nest
+ omp.wsloop schedule(static) linear(val(%data_var : memref<i32> = %linear_var : i32),
+ val(%data_var : memref<i32> = %linear_var : i32)) {
+ omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
+ omp.yield
+ }
+ } { linear_var_types = [i32, i32] }
+
// CHECK: omp.wsloop linear(%{{.*}} : memref<i32> = %{{.*}} : i32) ordered(2) schedule(static = %{{.*}} : i32) {
// CHECK-NEXT: omp.loop_nest
omp.wsloop ordered(2) linear(%data_var : memref<i32> = %linear_var : i32) schedule(static = %chunk_var : i32) {
@@ -744,6 +753,32 @@ func.func @omp_simd_pretty_order(%lb : index, %ub : index, %step : index) -> ()
return
}
+// CHECK-LABEL: omp_simd_linear_val
+func.func @omp_simd_linear_val(%lb : index, %ub : index, %step : index,
+ %data_var : memref<i32>, %linear_var : i32) -> () {
+ // CHECK: omp.simd linear(val(%{{.*}} : memref<i32> = %{{.*}} : i32))
+ omp.simd linear(val(%data_var : memref<i32> = %linear_var : i32)) {
+ omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
+ omp.yield
+ }
+ } {linear_var_types = [i32]}
+ return
+}
+
+// CHECK-LABEL: omp_simd_linear_val_multiple
+func.func @omp_simd_linear_val_multiple(%lb : index, %ub : index, %step : index,
+ %d1 : memref<i32>, %d2 : memref<i32>,
+ %s1 : i32, %s2 : i32) -> () {
+ // CHECK: omp.simd linear(val(%{{.*}} : memref<i32> = %{{.*}} : i32), val(%{{.*}} : memref<i32> = %{{.*}} : i32))
+ omp.simd linear(val(%d1 : memref<i32> = %s1 : i32),
+ val(%d2 : memref<i32> = %s2 : i32)) {
+ omp.loop_nest (%iv) : index = (%lb) to (%ub) step (%step) {
+ omp.yield
+ }
+ } {linear_var_types = [i32, i32]}
+ return
+}
+
// CHECK-LABEL: omp_simd_pretty_simdlen
func.func @omp_simd_pretty_simdlen(%lb : index, %ub : index, %step : index) -> () {
// CHECK: omp.simd simdlen(2)
@@ -3452,6 +3487,53 @@ func.func @omp_declare_simd_linear(%a: f64, %b: f64, %iv: i32, %step: i32) -> ()
return
}
+// CHECK-LABEL: func.func @omp_declare_simd_linear_val
+func.func @omp_declare_simd_linear_val(%iv: i32, %step: i32) -> () {
+ // CHECK: omp.declare_simd
+ // CHECK-SAME: linear(val(%{{.*}} : i32 = %{{.*}} : i32))
+ omp.declare_simd linear(val(%iv : i32 = %step : i32))
+ return
+}
+
+// CHECK-LABEL: func.func @omp_declare_simd_linear_ref
+func.func @omp_declare_simd_linear_ref(%p: memref<i32>, %step: i32) -> () {
+ // CHECK: omp.declare_simd
+ // CHECK-SAME: linear(ref(%{{.*}} : memref<i32> = %{{.*}} : i32))
+ omp.declare_simd linear(ref(%p : memref<i32> = %step : i32))
+ return
+}
+
+// CHECK-LABEL: func.func @omp_declare_simd_linear_uval
+func.func @omp_declare_simd_linear_uval(%p: memref<i32>, %step: i32) -> () {
+ // CHECK: omp.declare_simd
+ // CHECK-SAME: linear(uval(%{{.*}} : memref<i32> = %{{.*}} : i32))
+ omp.declare_simd linear(uval(%p : memref<i32> = %step : i32))
+ return
+}
+
+// CHECK-LABEL: func.func @omp_declare_simd_linear_mixed_modifiers
+func.func @omp_declare_simd_linear_mixed_modifiers(%a: i32, %b: memref<i32>,
+ %c: memref<i32>,
+ %s1: i32, %s2: i32, %s3: i32) -> () {
+ // CHECK: omp.declare_simd
+ // CHECK-SAME: linear(val(%{{.*}} : i32 = %{{.*}} : i32), ref(%{{.*}} : memref<i32> = %{{.*}} : i32), uval(%{{.*}} : memref<i32> = %{{.*}} : i32))
+ omp.declare_simd linear(val(%a : i32 = %s1 : i32),
+ ref(%b : memref<i32> = %s2 : i32),
+ uval(%c : memref<i32> = %s3 : i32))
+ return
+}
+
+// CHECK-LABEL: func.func @omp_declare_simd_linear_mixed_with_non_modifiers
+func.func @omp_declare_simd_linear_mixed_with_non_modifiers(
+ %a: i32, %b: memref<i32>, %c: i32, %s1: i32, %s2: i32, %s3: i32) -> () {
+ // CHECK: omp.declare_simd
+ // CHECK-SAME: linear(val(%{{.*}} : i32 = %{{.*}} : i32), %{{.*}} : memref<i32> = %{{.*}} : i32, ref(%{{.*}} : i32 = %{{.*}} : i32))
+ omp.declare_simd linear(val(%a : i32 = %s1 : i32),
+ %b : memref<i32> = %s2 : i32,
+ ref(%c : i32 = %s3 : i32))
+ return
+}
+
// CHECK-LABEL: func.func @omp_declare_simd_uniform
func.func @omp_declare_simd_uniform(%a: f64, %b: f64,
%p0: memref<i32>, %p1: memref<i32>) -> () {
More information about the Mlir-commits
mailing list