[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).
This commit is contained in:
Chi-Chun, Chen 2026-03-25 10:17:30 -05:00 committed by GitHub
parent 33da12aae7
commit 80dc5aa537
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 521 additions and 66 deletions

View File

@ -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);
});
}

View File

@ -143,7 +143,8 @@ public:
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;

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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]}

View File

@ -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

View File

@ -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.
}];
}

View File

@ -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.
//===----------------------------------------------------------------------===//

View File

@ -420,43 +420,114 @@ 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();
}
//===----------------------------------------------------------------------===//
// Verifier for Nontemporal Clause
//===----------------------------------------------------------------------===//
@ -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);
}
//===----------------------------------------------------------------------===//

View File

@ -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@+1 {{result #0 must be OpenMP iterator-produced list handle, but got 'index'}}
%0 = omp.iterator(%i: index) = (%lb to %ub step %st) {

View File

@ -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>) -> () {