Skip to content

Commit ed97932

Browse files
authored
[flang][OpenMP] Fix LASTPRIVATE for iteration variables (#69773)
Iteration variables behave slightly different with LASTPRIVATE, as they must be assigned the value that the copy would have after sequential execution of the loop. This case is now handled. This patch also fixes LASTPRIVATE for loops where the step is different from 1. Fixes #64055
1 parent 5af3742 commit ed97932

File tree

5 files changed

+176
-34
lines changed

5 files changed

+176
-34
lines changed

flang/lib/Lower/OpenMP.cpp

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ class DataSharingProcessor {
109109
bool hasLastPrivateOp;
110110
mlir::OpBuilder::InsertPoint lastPrivIP;
111111
mlir::OpBuilder::InsertPoint insPt;
112+
mlir::Value loopIV;
112113
// Symbols in private, firstprivate, and/or lastprivate clauses.
113114
llvm::SetVector<const Fortran::semantics::Symbol *> privatizedSymbols;
114115
llvm::SetVector<const Fortran::semantics::Symbol *> defaultSymbols;
@@ -157,6 +158,11 @@ class DataSharingProcessor {
157158
// dealocation code as well.
158159
void processStep1();
159160
void processStep2(mlir::Operation *op, bool isLoop);
161+
162+
void setLoopIV(mlir::Value iv) {
163+
assert(!loopIV && "Loop iteration variable already set");
164+
loopIV = iv;
165+
}
160166
};
161167

162168
void DataSharingProcessor::processStep1() {
@@ -270,7 +276,6 @@ void DataSharingProcessor ::insertBarrier() {
270276
}
271277

272278
void DataSharingProcessor::insertLastPrivateCompare(mlir::Operation *op) {
273-
mlir::arith::CmpIOp cmpOp;
274279
bool cmpCreated = false;
275280
mlir::OpBuilder::InsertPoint localInsPt = firOpBuilder.saveInsertionPoint();
276281
for (const Fortran::parser::OmpClause &clause : opClauseList.v) {
@@ -349,34 +354,55 @@ void DataSharingProcessor::insertLastPrivateCompare(mlir::Operation *op) {
349354
}
350355
}
351356
} else if (mlir::isa<mlir::omp::WsLoopOp>(op)) {
352-
mlir::Operation *lastOper = op->getRegion(0).back().getTerminator();
353-
firOpBuilder.setInsertionPoint(lastOper);
354-
355357
// Update the original variable just before exiting the worksharing
356358
// loop. Conversion as follows:
357359
//
358360
// omp.wsloop {
359361
// omp.wsloop { ...
360362
// ... store
361-
// store ===> %cmp = llvm.icmp "eq" %iv %ub
362-
// omp.yield fir.if %cmp {
363-
// } ^%lpv_update_blk:
363+
// store ===> %v = arith.addi %iv, %step
364+
// omp.yield %cmp = %step < 0 ? %v < %ub : %v > %ub
365+
// } fir.if %cmp {
366+
// fir.store %v to %loopIV
367+
// ^%lpv_update_blk:
364368
// }
365369
// omp.yield
366370
// }
367371
//
368372

369373
// Only generate the compare once in presence of multiple LastPrivate
370374
// clauses.
371-
if (!cmpCreated) {
372-
cmpOp = firOpBuilder.create<mlir::arith::CmpIOp>(
373-
op->getLoc(), mlir::arith::CmpIPredicate::eq,
374-
op->getRegion(0).front().getArguments()[0],
375-
mlir::dyn_cast<mlir::omp::WsLoopOp>(op).getUpperBound()[0]);
376-
}
377-
auto ifOp =
378-
firOpBuilder.create<fir::IfOp>(op->getLoc(), cmpOp, /*else*/ false);
375+
if (cmpCreated)
376+
continue;
377+
cmpCreated = true;
378+
379+
mlir::Location loc = op->getLoc();
380+
mlir::Operation *lastOper = op->getRegion(0).back().getTerminator();
381+
firOpBuilder.setInsertionPoint(lastOper);
382+
383+
mlir::Value iv = op->getRegion(0).front().getArguments()[0];
384+
mlir::Value ub =
385+
mlir::dyn_cast<mlir::omp::WsLoopOp>(op).getUpperBound()[0];
386+
mlir::Value step = mlir::dyn_cast<mlir::omp::WsLoopOp>(op).getStep()[0];
387+
388+
// v = iv + step
389+
// cmp = step < 0 ? v < ub : v > ub
390+
mlir::Value v = firOpBuilder.create<mlir::arith::AddIOp>(loc, iv, step);
391+
mlir::Value zero =
392+
firOpBuilder.createIntegerConstant(loc, step.getType(), 0);
393+
mlir::Value negativeStep = firOpBuilder.create<mlir::arith::CmpIOp>(
394+
loc, mlir::arith::CmpIPredicate::slt, step, zero);
395+
mlir::Value vLT = firOpBuilder.create<mlir::arith::CmpIOp>(
396+
loc, mlir::arith::CmpIPredicate::slt, v, ub);
397+
mlir::Value vGT = firOpBuilder.create<mlir::arith::CmpIOp>(
398+
loc, mlir::arith::CmpIPredicate::sgt, v, ub);
399+
mlir::Value cmpOp = firOpBuilder.create<mlir::arith::SelectOp>(
400+
loc, negativeStep, vLT, vGT);
401+
402+
auto ifOp = firOpBuilder.create<fir::IfOp>(loc, cmpOp, /*else*/ false);
379403
firOpBuilder.setInsertionPointToStart(&ifOp.getThenRegion().front());
404+
assert(loopIV && "loopIV was not set");
405+
firOpBuilder.create<fir::StoreOp>(op->getLoc(), v, loopIV);
380406
lastPrivIP = firOpBuilder.saveInsertionPoint();
381407
} else {
382408
TODO(converter.getCurrentLocation(),
@@ -2130,6 +2156,8 @@ static void createBodyOfOp(
21302156
proc.processStep1();
21312157
proc.processStep2(op, is_loop);
21322158
} else {
2159+
if (is_loop && args.size() > 0)
2160+
dsp->setLoopIV(converter.getSymbolAddress(*args[0]));
21332161
dsp->processStep2(op, is_loop);
21342162
}
21352163

flang/test/Lower/OpenMP/FIR/lastprivate-commonblock.f90

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,18 @@
1919
!CHECK: %[[val_c1_i32_0:.*]] = arith.constant 1 : i32
2020
!CHECK: omp.wsloop for (%[[arg:.*]]) : i32 = (%[[val_c1_i32]]) to (%[[val_c100_i32]]) inclusive step (%[[val_c1_i32_0]]) {
2121
!CHECK: fir.store %[[arg]] to %[[val_0]] : !fir.ref<i32>
22-
!CHECK: %[[val_11:.*]] = arith.cmpi eq, %[[arg]], %[[val_c100_i32]] : i32
23-
!CHECK: fir.if %[[val_11]] {
24-
!CHECK: %[[val_12:.*]] = fir.load %[[val_9]] : !fir.ref<f32>
25-
!CHECK: fir.store %[[val_12]] to %[[val_5]] : !fir.ref<f32>
26-
!CHECK: %[[val_13:.*]] = fir.load %[[val_10]] : !fir.ref<f32>
27-
!CHECK: fir.store %[[val_13]] to %[[val_8]] : !fir.ref<f32>
22+
!CHECK: %[[val_11:.*]] = arith.addi %[[arg]], %[[val_c1_i32_0]] : i32
23+
!CHECK: %[[val_c0_i32:.*]] = arith.constant 0 : i32
24+
!CHECK: %[[val_12:.*]] = arith.cmpi slt, %[[val_c1_i32_0]], %[[val_c0_i32]] : i32
25+
!CHECK: %[[val_13:.*]] = arith.cmpi slt, %[[val_11]], %[[val_c100_i32]] : i32
26+
!CHECK: %[[val_14:.*]] = arith.cmpi sgt, %[[val_11]], %[[val_c100_i32]] : i32
27+
!CHECK: %[[val_15:.*]] = arith.select %[[val_12]], %[[val_13]], %[[val_14]] : i1
28+
!CHECK: fir.if %[[val_15]] {
29+
!CHECK: fir.store %[[val_11]] to %[[val_0]] : !fir.ref<i32>
30+
!CHECK: %[[val_16:.*]] = fir.load %[[val_9]] : !fir.ref<f32>
31+
!CHECK: fir.store %[[val_16]] to %[[val_5]] : !fir.ref<f32>
32+
!CHECK: %[[val_17:.*]] = fir.load %[[val_10]] : !fir.ref<f32>
33+
!CHECK: fir.store %[[val_17]] to %[[val_8]] : !fir.ref<f32>
2834
!CHECK: }
2935
!CHECK: omp.yield
3036
!CHECK: }

flang/test/Lower/OpenMP/FIR/parallel-lastprivate-clause-scalar.f90

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
! This test checks lowering of `FIRSTPRIVATE` clause for scalar types.
1+
! This test checks lowering of `LASTPRIVATE` clause for scalar types.
22

33
! RUN: bbc -fopenmp -emit-fir %s -o - | FileCheck %s
44
! RUN: flang-new -fc1 -fopenmp -emit-fir %s -o - | FileCheck %s
@@ -24,8 +24,14 @@
2424
!CHECK-NEXT: %[[CALL_END_IO:.*]] = fir.call @_FortranAioEndIoStatement(%[[CALL_BEGIN_IO]])
2525

2626
! Testing last iteration check
27-
!CHECK-NEXT: %[[IV_CMP:.*]] = arith.cmpi eq, %[[INDX_WS]]
27+
!CHECK: %[[V:.*]] = arith.addi %[[INDX_WS]], %{{.*}} : i32
28+
!CHECK: %[[C0:.*]] = arith.constant 0 : i32
29+
!CHECK: %[[T1:.*]] = arith.cmpi slt, %{{.*}}, %[[C0]] : i32
30+
!CHECK: %[[T2:.*]] = arith.cmpi slt, %[[V]], %{{.*}} : i32
31+
!CHECK: %[[T3:.*]] = arith.cmpi sgt, %[[V]], %{{.*}} : i32
32+
!CHECK: %[[IV_CMP:.*]] = arith.select %[[T1]], %[[T2]], %[[T3]] : i1
2833
!CHECK: fir.if %[[IV_CMP]] {
34+
!CHECK: fir.store %[[V]] to %{{.*}} : !fir.ref<i32>
2935

3036
! Testing lastprivate val update
3137
!CHECK-DAG: %[[CVT:.*]] = fir.convert %[[ARG1_REF]] : (!fir.ref<!fir.char<1,5>>) -> !fir.ref<i8>
@@ -52,8 +58,14 @@ subroutine lastprivate_character(arg1)
5258
!CHECK: omp.wsloop for (%[[INDX_WS:.*]]) : {{.*}} {
5359

5460
! Testing last iteration check
55-
!CHECK-DAG: %[[IV_CMP:.*]] = arith.cmpi eq, %[[INDX_WS]]
56-
!CHECK-DAG: fir.if %[[IV_CMP]] {
61+
!CHECK: %[[V:.*]] = arith.addi %[[INDX_WS]], %{{.*}} : i32
62+
!CHECK: %[[C0:.*]] = arith.constant 0 : i32
63+
!CHECK: %[[T1:.*]] = arith.cmpi slt, %{{.*}}, %[[C0]] : i32
64+
!CHECK: %[[T2:.*]] = arith.cmpi slt, %[[V]], %{{.*}} : i32
65+
!CHECK: %[[T3:.*]] = arith.cmpi sgt, %[[V]], %{{.*}} : i32
66+
!CHECK: %[[IV_CMP:.*]] = arith.select %[[T1]], %[[T2]], %[[T3]] : i1
67+
!CHECK: fir.if %[[IV_CMP]] {
68+
!CHECK: fir.store %[[V]] to %{{.*}} : !fir.ref<i32>
5769

5870
! Testing lastprivate val update
5971
!CHECK-NEXT: %[[CLONE_LD:.*]] = fir.load %[[CLONE]] : !fir.ref<i32>
@@ -81,8 +93,14 @@ subroutine lastprivate_int(arg1)
8193
!CHECK: omp.wsloop for (%[[INDX_WS:.*]]) : {{.*}} {
8294

8395
! Testing last iteration check
84-
!CHECK: %[[IV_CMP1:.*]] = arith.cmpi eq, %[[INDX_WS]]
85-
!CHECK-NEXT: fir.if %[[IV_CMP1]] {
96+
!CHECK: %[[V:.*]] = arith.addi %[[INDX_WS]], %{{.*}} : i32
97+
!CHECK: %[[C0:.*]] = arith.constant 0 : i32
98+
!CHECK: %[[T1:.*]] = arith.cmpi slt, %{{.*}}, %[[C0]] : i32
99+
!CHECK: %[[T2:.*]] = arith.cmpi slt, %[[V]], %{{.*}} : i32
100+
!CHECK: %[[T3:.*]] = arith.cmpi sgt, %[[V]], %{{.*}} : i32
101+
!CHECK: %[[IV_CMP:.*]] = arith.select %[[T1]], %[[T2]], %[[T3]] : i1
102+
!CHECK: fir.if %[[IV_CMP]] {
103+
!CHECK: fir.store %[[V]] to %{{.*}} : !fir.ref<i32>
86104
! Testing lastprivate val update
87105
!CHECK-DAG: %[[CLONE_LD1:.*]] = fir.load %[[CLONE1]] : !fir.ref<i32>
88106
!CHECK-DAG: fir.store %[[CLONE_LD1]] to %[[ARG1]] : !fir.ref<i32>
@@ -112,8 +130,14 @@ subroutine mult_lastprivate_int(arg1, arg2)
112130
!CHECK: omp.wsloop for (%[[INDX_WS:.*]]) : {{.*}} {
113131

114132
!Testing last iteration check
115-
!CHECK: %[[IV_CMP1:.*]] = arith.cmpi eq, %[[INDX_WS]]
116-
!CHECK-NEXT: fir.if %[[IV_CMP1]] {
133+
!CHECK: %[[V:.*]] = arith.addi %[[INDX_WS]], %{{.*}} : i32
134+
!CHECK: %[[C0:.*]] = arith.constant 0 : i32
135+
!CHECK: %[[T1:.*]] = arith.cmpi slt, %{{.*}}, %[[C0]] : i32
136+
!CHECK: %[[T2:.*]] = arith.cmpi slt, %[[V]], %{{.*}} : i32
137+
!CHECK: %[[T3:.*]] = arith.cmpi sgt, %[[V]], %{{.*}} : i32
138+
!CHECK: %[[IV_CMP:.*]] = arith.select %[[T1]], %[[T2]], %[[T3]] : i1
139+
!CHECK: fir.if %[[IV_CMP]] {
140+
!CHECK: fir.store %[[V]] to %{{.*}} : !fir.ref<i32>
117141
!Testing lastprivate val update
118142
!CHECK-DAG: %[[CLONE_LD2:.*]] = fir.load %[[CLONE2]] : !fir.ref<i32>
119143
!CHECK-DAG: fir.store %[[CLONE_LD2]] to %[[ARG2]] : !fir.ref<i32>
@@ -148,8 +172,14 @@ subroutine mult_lastprivate_int2(arg1, arg2)
148172
!CHECK: omp.wsloop for (%[[INDX_WS:.*]]) : {{.*}} {
149173

150174
! Testing last iteration check
151-
!CHECK: %[[IV_CMP1:.*]] = arith.cmpi eq, %[[INDX_WS]]
152-
!CHECK-NEXT: fir.if %[[IV_CMP1]] {
175+
!CHECK: %[[V:.*]] = arith.addi %[[INDX_WS]], %{{.*}} : i32
176+
!CHECK: %[[C0:.*]] = arith.constant 0 : i32
177+
!CHECK: %[[T1:.*]] = arith.cmpi slt, %{{.*}}, %[[C0]] : i32
178+
!CHECK: %[[T2:.*]] = arith.cmpi slt, %[[V]], %{{.*}} : i32
179+
!CHECK: %[[T3:.*]] = arith.cmpi sgt, %[[V]], %{{.*}} : i32
180+
!CHECK: %[[IV_CMP:.*]] = arith.select %[[T1]], %[[T2]], %[[T3]] : i1
181+
!CHECK: fir.if %[[IV_CMP]] {
182+
!CHECK: fir.store %[[V]] to %{{.*}} : !fir.ref<i32>
153183
! Testing lastprivate val update
154184
!CHECK-NEXT: %[[CLONE_LD:.*]] = fir.load %[[CLONE2]] : !fir.ref<i32>
155185
!CHECK-NEXT: fir.store %[[CLONE_LD]] to %[[ARG2]] : !fir.ref<i32>
@@ -179,8 +209,14 @@ subroutine firstpriv_lastpriv_int(arg1, arg2)
179209
!CHECK-NEXT: omp.barrier
180210
!CHECK: omp.wsloop for (%[[INDX_WS:.*]]) : {{.*}} {
181211
! Testing last iteration check
182-
!CHECK: %[[IV_CMP1:.*]] = arith.cmpi eq, %[[INDX_WS]]
183-
!CHECK-NEXT: fir.if %[[IV_CMP1]] {
212+
!CHECK: %[[V:.*]] = arith.addi %[[INDX_WS]], %{{.*}} : i32
213+
!CHECK: %[[C0:.*]] = arith.constant 0 : i32
214+
!CHECK: %[[T1:.*]] = arith.cmpi slt, %{{.*}}, %[[C0]] : i32
215+
!CHECK: %[[T2:.*]] = arith.cmpi slt, %[[V]], %{{.*}} : i32
216+
!CHECK: %[[T3:.*]] = arith.cmpi sgt, %[[V]], %{{.*}} : i32
217+
!CHECK: %[[IV_CMP:.*]] = arith.select %[[T1]], %[[T2]], %[[T3]] : i1
218+
!CHECK: fir.if %[[IV_CMP]] {
219+
!CHECK: fir.store %[[V]] to %{{.*}} : !fir.ref<i32>
184220
! Testing lastprivate val update
185221
!CHECK-NEXT: %[[CLONE_LD:.*]] = fir.load %[[CLONE1]] : !fir.ref<i32>
186222
!CHECK-NEXT: fir.store %[[CLONE_LD]] to %[[ARG1]] : !fir.ref<i32>

flang/test/Lower/OpenMP/lastprivate-commonblock.f90

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,14 @@
1616
!CHECK: %[[PRIVATE_Y_REF:.*]] = fir.alloca f32 {bindc_name = "y", pinned, uniq_name = "_QFlastprivate_commonEy"}
1717
!CHECK: %[[PRIVATE_Y_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_Y_REF]] {uniq_name = "_QFlastprivate_commonEy"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
1818
!CHECK: omp.wsloop for (%[[I:.*]]) : i32 = (%{{.*}}) to (%{{.*}}) inclusive step (%{{.*}}) {
19-
!CHECK: %[[LAST_ITER:.*]] = arith.cmpi eq, %[[I]], %{{.*}} : i32
19+
!CHECK: %[[V:.*]] = arith.addi %[[I]], %{{.*}} : i32
20+
!CHECK: %[[C0:.*]] = arith.constant 0 : i32
21+
!CHECK: %[[NEG_STEP:.*]] = arith.cmpi slt, %{{.*}}, %[[C0]] : i32
22+
!CHECK: %[[V_LT:.*]] = arith.cmpi slt, %[[V]], %{{.*}} : i32
23+
!CHECK: %[[V_GT:.*]] = arith.cmpi sgt, %[[V]], %{{.*}} : i32
24+
!CHECK: %[[LAST_ITER:.*]] = arith.select %[[NEG_STEP]], %[[V_LT]], %[[V_GT]] : i1
2025
!CHECK: fir.if %[[LAST_ITER]] {
26+
!CHECK: fir.store %[[V]] to %{{.*}} : !fir.ref<i32>
2127
!CHECK: %[[PRIVATE_X_VAL:.*]] = fir.load %[[PRIVATE_X_DECL]]#0 : !fir.ref<f32>
2228
!CHECK: hlfir.assign %[[PRIVATE_X_VAL]] to %[[X_DECL]]#0 temporary_lhs : f32, !fir.ref<f32>
2329
!CHECK: %[[PRIVATE_Y_VAL:.*]] = fir.load %[[PRIVATE_Y_DECL]]#0 : !fir.ref<f32>
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
! Test LASTPRIVATE with iteration variable.
2+
! RUN: %flang_fc1 -emit-hlfir -fopenmp -o - %s 2>&1 | FileCheck %s
3+
4+
!CHECK-LABEL: func @_QPlastprivate_iv_inc
5+
!CHECK: %[[I_MEM:.*]] = fir.alloca i32 {adapt.valuebyref, pinned}
6+
!CHECK: %[[I:.*]]:2 = hlfir.declare %[[I_MEM]] {uniq_name = "_QFlastprivate_iv_incEi"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
7+
!CHECK: %[[I2_MEM:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFlastprivate_iv_incEi"}
8+
!CHECK: %[[I2:.*]]:2 = hlfir.declare %[[I2_MEM]] {uniq_name = "_QFlastprivate_iv_incEi"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
9+
!CHECK: %[[LB:.*]] = arith.constant 4 : i32
10+
!CHECK: %[[UB:.*]] = arith.constant 10 : i32
11+
!CHECK: %[[STEP:.*]] = arith.constant 3 : i32
12+
!CHECK: omp.wsloop for (%[[IV:.*]]) : i32 = (%[[LB]]) to (%[[UB]]) inclusive step (%[[STEP]]) {
13+
!CHECK: fir.store %[[IV]] to %[[I]]#1 : !fir.ref<i32>
14+
!CHECK: %[[V:.*]] = arith.addi %[[IV]], %[[STEP]] : i32
15+
!CHECK: %[[C0:.*]] = arith.constant 0 : i32
16+
!CHECK: %[[STEP_NEG:.*]] = arith.cmpi slt, %[[STEP]], %[[C0]] : i32
17+
!CHECK: %[[V_LT:.*]] = arith.cmpi slt, %[[V]], %[[UB]] : i32
18+
!CHECK: %[[V_GT:.*]] = arith.cmpi sgt, %[[V]], %[[UB]] : i32
19+
!CHECK: %[[CMP:.*]] = arith.select %[[STEP_NEG]], %[[V_LT]], %[[V_GT]] : i1
20+
!CHECK: fir.if %[[CMP]] {
21+
!CHECK: fir.store %[[V]] to %[[I]]#1 : !fir.ref<i32>
22+
!CHECK: %[[I_VAL:.*]] = fir.load %[[I]]#0 : !fir.ref<i32>
23+
!CHECK: hlfir.assign %[[I_VAL]] to %[[I2]]#0 temporary_lhs : i32, !fir.ref<i32>
24+
!CHECK: }
25+
!CHECK: omp.yield
26+
!CHECK: }
27+
subroutine lastprivate_iv_inc()
28+
integer :: i
29+
30+
!$omp do lastprivate(i)
31+
do i = 4, 10, 3
32+
end do
33+
!$omp end do
34+
end subroutine
35+
36+
!CHECK-LABEL: func @_QPlastprivate_iv_dec
37+
!CHECK: %[[I_MEM:.*]] = fir.alloca i32 {adapt.valuebyref, pinned}
38+
!CHECK: %[[I:.*]]:2 = hlfir.declare %[[I_MEM]] {uniq_name = "_QFlastprivate_iv_decEi"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
39+
!CHECK: %[[I2_MEM:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFlastprivate_iv_decEi"}
40+
!CHECK: %[[I2:.*]]:2 = hlfir.declare %[[I2_MEM]] {uniq_name = "_QFlastprivate_iv_decEi"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
41+
!CHECK: %[[LB:.*]] = arith.constant 10 : i32
42+
!CHECK: %[[UB:.*]] = arith.constant 1 : i32
43+
!CHECK: %[[STEP:.*]] = arith.constant -3 : i32
44+
!CHECK: omp.wsloop for (%[[IV:.*]]) : i32 = (%[[LB]]) to (%[[UB]]) inclusive step (%[[STEP]]) {
45+
!CHECK: fir.store %[[IV]] to %[[I]]#1 : !fir.ref<i32>
46+
!CHECK: %[[V:.*]] = arith.addi %[[IV]], %[[STEP]] : i32
47+
!CHECK: %[[C0:.*]] = arith.constant 0 : i32
48+
!CHECK: %[[STEP_NEG:.*]] = arith.cmpi slt, %[[STEP]], %[[C0]] : i32
49+
!CHECK: %[[V_LT:.*]] = arith.cmpi slt, %[[V]], %[[UB]] : i32
50+
!CHECK: %[[V_GT:.*]] = arith.cmpi sgt, %[[V]], %[[UB]] : i32
51+
!CHECK: %[[CMP:.*]] = arith.select %[[STEP_NEG]], %[[V_LT]], %[[V_GT]] : i1
52+
!CHECK: fir.if %[[CMP]] {
53+
!CHECK: fir.store %[[V]] to %[[I]]#1 : !fir.ref<i32>
54+
!CHECK: %[[I_VAL:.*]] = fir.load %[[I]]#0 : !fir.ref<i32>
55+
!CHECK: hlfir.assign %[[I_VAL]] to %[[I2]]#0 temporary_lhs : i32, !fir.ref<i32>
56+
!CHECK: }
57+
!CHECK: omp.yield
58+
!CHECK: }
59+
subroutine lastprivate_iv_dec()
60+
integer :: i
61+
62+
!$omp do lastprivate(i)
63+
do i = 10, 1, -3
64+
end do
65+
!$omp end do
66+
end subroutine

0 commit comments

Comments
 (0)