Skip to content

Commit 1bfbe4c

Browse files
[flang] Allow lowering of sub-expressions to be overridden
OpenACC/OpenMP atomic lowering needs a finer control over expression lowering. This patch allows mapping evaluate::Expr<T> to mlir::Value so that any subsequent expression lowering will use these values when an operand is a mapped Expr<T>. This is an alternative to #69866 From which I took the test. The same test as in #69866 are failing because the "non atomic part" is now out of the atomic.update op, which in some case causing verification failure because this is generated in the middle of an omp.atomic.capture. I did not try fixing these failures. My patch is about the lowering infrastructure and how to use it rather than the OpenMP semantics. Co-authored-by: Nimish Mishra <[email protected]>
1 parent ba468d4 commit 1bfbe4c

File tree

8 files changed

+171
-99
lines changed

8 files changed

+171
-99
lines changed

flang/include/flang/Lower/AbstractConverter.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ using SomeExpr = Fortran::evaluate::Expr<Fortran::evaluate::SomeType>;
6060
using SymbolRef = Fortran::common::Reference<const Fortran::semantics::Symbol>;
6161
class StatementContext;
6262

63+
using ExprToValueMap = llvm::DenseMap<const SomeExpr *, mlir::Value>;
64+
6365
//===----------------------------------------------------------------------===//
6466
// AbstractConverter interface
6567
//===----------------------------------------------------------------------===//
@@ -90,6 +92,14 @@ class AbstractConverter {
9092
/// added or replaced at the inner-most level of the local symbol map.
9193
virtual void bindSymbol(SymbolRef sym, const fir::ExtendedValue &exval) = 0;
9294

95+
/// Override lowering of expression with pre-lowered values.
96+
/// Associate mlir::Value to evaluate::Expr. All subsequent call to
97+
/// genExprXXX() will replace any occurrence of an overridden
98+
/// expression in the expression tree by the pre-lowered values.
99+
virtual void overrideExprValues(const ExprToValueMap *) = 0;
100+
void resetExprOverrides() { overrideExprValues(nullptr); }
101+
virtual const ExprToValueMap *getExprOverrides() = 0;
102+
93103
/// Get the label set associated with a symbol.
94104
virtual bool lookupLabelSet(SymbolRef sym, pft::LabelSet &labelSet) = 0;
95105

flang/lib/Lower/Bridge.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,15 @@ class FirConverter : public Fortran::lower::AbstractConverter {
504504
addSymbol(sym, exval, /*forced=*/true);
505505
}
506506

507+
void
508+
overrideExprValues(const Fortran::lower::ExprToValueMap *map) override final {
509+
exprValueOverrides = map;
510+
}
511+
512+
const Fortran::lower::ExprToValueMap *getExprOverrides() override final {
513+
return exprValueOverrides;
514+
}
515+
507516
bool lookupLabelSet(Fortran::lower::SymbolRef sym,
508517
Fortran::lower::pft::LabelSet &labelSet) override final {
509518
Fortran::lower::pft::FunctionLikeUnit &owningProc =
@@ -4890,6 +4899,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
48904899
/// Whether an OpenMP target region or declare target function/subroutine
48914900
/// intended for device offloading has been detected
48924901
bool ompDeviceCodeFound = false;
4902+
4903+
const Fortran::lower::ExprToValueMap *exprValueOverrides{nullptr};
48934904
};
48944905

48954906
} // namespace

flang/lib/Lower/ConvertExpr.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2963,8 +2963,21 @@ class ScalarExprLowering {
29632963
return asArray(x);
29642964
}
29652965

2966+
template <typename A>
2967+
mlir::Value getIfOverridenExpr(const Fortran::evaluate::Expr<A> &x) {
2968+
if (const Fortran::lower::ExprToValueMap *map =
2969+
converter.getExprOverrides()) {
2970+
Fortran::lower::SomeExpr someExpr = toEvExpr(x);
2971+
if (auto match = map->find(&someExpr); match != map->end())
2972+
return match->second;
2973+
}
2974+
return mlir::Value{};
2975+
}
2976+
29662977
template <typename A>
29672978
ExtValue gen(const Fortran::evaluate::Expr<A> &x) {
2979+
if (mlir::Value val = getIfOverridenExpr(x))
2980+
return val;
29682981
// Whole array symbols or components, and results of transformational
29692982
// functions already have a storage and the scalar expression lowering path
29702983
// is used to not create a new temporary storage.
@@ -2978,6 +2991,8 @@ class ScalarExprLowering {
29782991
}
29792992
template <typename A>
29802993
ExtValue genval(const Fortran::evaluate::Expr<A> &x) {
2994+
if (mlir::Value val = getIfOverridenExpr(x))
2995+
return val;
29812996
if (isScalar(x) || Fortran::evaluate::UnwrapWholeSymbolDataRef(x) ||
29822997
inInitializer)
29832998
return std::visit([&](const auto &e) { return genval(e); }, x.u);
@@ -2987,6 +3002,8 @@ class ScalarExprLowering {
29873002
template <int KIND>
29883003
ExtValue genval(const Fortran::evaluate::Expr<Fortran::evaluate::Type<
29893004
Fortran::common::TypeCategory::Logical, KIND>> &exp) {
3005+
if (mlir::Value val = getIfOverridenExpr(exp))
3006+
return val;
29903007
return std::visit([&](const auto &e) { return genval(e); }, exp.u);
29913008
}
29923009

flang/lib/Lower/ConvertExprToHLFIR.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1423,6 +1423,17 @@ class HlfirBuilder {
14231423

14241424
template <typename T>
14251425
hlfir::EntityWithAttributes gen(const Fortran::evaluate::Expr<T> &expr) {
1426+
if (const Fortran::lower::ExprToValueMap *map =
1427+
getConverter().getExprOverrides()) {
1428+
if constexpr (std::is_same_v<T, Fortran::evaluate::SomeType>) {
1429+
if (auto match = map->find(&expr); match != map->end())
1430+
return hlfir::EntityWithAttributes{match->second};
1431+
} else {
1432+
Fortran::lower::SomeExpr someExpr = toEvExpr(expr);
1433+
if (auto match = map->find(&someExpr); match != map->end())
1434+
return hlfir::EntityWithAttributes{match->second};
1435+
}
1436+
}
14261437
return std::visit([&](const auto &x) { return gen(x); }, expr.u);
14271438
}
14281439

flang/lib/Lower/DirectivesCommon.h

Lines changed: 45 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -205,57 +205,7 @@ static inline void genOmpAccAtomicUpdateStatement(
205205
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
206206
mlir::Location currentLocation = converter.getCurrentLocation();
207207

208-
const auto *varDesignator =
209-
std::get_if<Fortran::common::Indirection<Fortran::parser::Designator>>(
210-
&assignmentStmtVariable.u);
211-
assert(varDesignator && "Variable designator for atomic update assignment "
212-
"statement does not exist");
213-
const Fortran::parser::Name *name =
214-
Fortran::semantics::getDesignatorNameIfDataRef(varDesignator->value());
215-
if (!name)
216-
TODO(converter.getCurrentLocation(),
217-
"Array references as atomic update variable");
218-
assert(name && name->symbol &&
219-
"No symbol attached to atomic update variable");
220-
if (Fortran::semantics::IsAllocatableOrPointer(name->symbol->GetUltimate()))
221-
converter.bindSymbol(*name->symbol, lhsAddr);
222-
223-
// Lowering is in two steps :
224-
// subroutine sb
225-
// integer :: a, b
226-
// !$omp atomic update
227-
// a = a + b
228-
// end subroutine
229-
//
230-
// 1. Lower to scf.execute_region_op
231-
//
232-
// func.func @_QPsb() {
233-
// %0 = fir.alloca i32 {bindc_name = "a", uniq_name = "_QFsbEa"}
234-
// %1 = fir.alloca i32 {bindc_name = "b", uniq_name = "_QFsbEb"}
235-
// %2 = scf.execute_region -> i32 {
236-
// %3 = fir.load %0 : !fir.ref<i32>
237-
// %4 = fir.load %1 : !fir.ref<i32>
238-
// %5 = arith.addi %3, %4 : i32
239-
// scf.yield %5 : i32
240-
// }
241-
// return
242-
// }
243-
auto tempOp =
244-
firOpBuilder.create<mlir::scf::ExecuteRegionOp>(currentLocation, varType);
245-
firOpBuilder.createBlock(&tempOp.getRegion());
246-
mlir::Block &block = tempOp.getRegion().back();
247-
firOpBuilder.setInsertionPointToEnd(&block);
248-
Fortran::lower::StatementContext stmtCtx;
249-
mlir::Value rhsExpr = fir::getBase(converter.genExprValue(
250-
*Fortran::semantics::GetExpr(assignmentStmtExpr), stmtCtx));
251-
mlir::Value convertResult =
252-
firOpBuilder.createConvert(currentLocation, varType, rhsExpr);
253-
// Insert the terminator: YieldOp.
254-
firOpBuilder.create<mlir::scf::YieldOp>(currentLocation, convertResult);
255-
firOpBuilder.setInsertionPointToStart(&block);
256-
257-
// 2. Create the omp.atomic.update Operation using the Operations in the
258-
// temporary scf.execute_region Operation.
208+
// Create the omp.atomic.update Operation
259209
//
260210
// func.func @_QPsb() {
261211
// %0 = fir.alloca i32 {bindc_name = "a", uniq_name = "_QFsbEa"}
@@ -269,11 +219,31 @@ static inline void genOmpAccAtomicUpdateStatement(
269219
// }
270220
// return
271221
// }
272-
mlir::Value updateVar = converter.getSymbolAddress(*name->symbol);
273-
if (auto decl = updateVar.getDefiningOp<hlfir::DeclareOp>())
274-
updateVar = decl.getBase();
275222

276-
firOpBuilder.setInsertionPointAfter(tempOp);
223+
Fortran::lower::ExprToValueMap exprValueOverrides;
224+
// Lower any non atomic sub-expression before the atomic operation, and
225+
// map its lowered value to the semantic representation.
226+
const Fortran::lower::SomeExpr *nonAtomicSubExpr{nullptr};
227+
std::visit(
228+
[&](const auto &op) -> void {
229+
using T = std::decay_t<decltype(op)>;
230+
if constexpr (std::is_base_of<Fortran::parser::Expr::IntrinsicBinary,
231+
T>::value) {
232+
const auto &exprLeft{std::get<0>(op.t)};
233+
const auto &exprRight{std::get<1>(op.t)};
234+
if (exprLeft.value().source == assignmentStmtVariable.GetSource())
235+
nonAtomicSubExpr = Fortran::semantics::GetExpr(exprRight);
236+
else
237+
nonAtomicSubExpr = Fortran::semantics::GetExpr(exprLeft);
238+
}
239+
},
240+
assignmentStmtExpr.u);
241+
StatementContext nonAtomicStmtCtx;
242+
if (nonAtomicSubExpr) {
243+
mlir::Value nonAtomicVal = fir::getBase(converter.genExprValue(
244+
currentLocation, *nonAtomicSubExpr, nonAtomicStmtCtx));
245+
exprValueOverrides.try_emplace(nonAtomicSubExpr, nonAtomicVal);
246+
}
277247

278248
mlir::Operation *atomicUpdateOp = nullptr;
279249
if constexpr (std::is_same<AtomicListT,
@@ -289,10 +259,10 @@ static inline void genOmpAccAtomicUpdateStatement(
289259
genOmpAtomicHintAndMemoryOrderClauses(converter, *rightHandClauseList,
290260
hint, memoryOrder);
291261
atomicUpdateOp = firOpBuilder.create<mlir::omp::AtomicUpdateOp>(
292-
currentLocation, updateVar, hint, memoryOrder);
262+
currentLocation, lhsAddr, hint, memoryOrder);
293263
} else {
294264
atomicUpdateOp = firOpBuilder.create<mlir::acc::AtomicUpdateOp>(
295-
currentLocation, updateVar);
265+
currentLocation, lhsAddr);
296266
}
297267

298268
llvm::SmallVector<mlir::Type> varTys = {varType};
@@ -301,38 +271,25 @@ static inline void genOmpAccAtomicUpdateStatement(
301271
mlir::Value val =
302272
fir::getBase(atomicUpdateOp->getRegion(0).front().getArgument(0));
303273

304-
llvm::SmallVector<mlir::Operation *> ops;
305-
for (mlir::Operation &op : tempOp.getRegion().getOps())
306-
ops.push_back(&op);
307-
308-
// SCF Yield is converted to OMP Yield. All other operations are copied
309-
for (mlir::Operation *op : ops) {
310-
if (auto y = mlir::dyn_cast<mlir::scf::YieldOp>(op)) {
311-
firOpBuilder.setInsertionPointToEnd(
312-
&atomicUpdateOp->getRegion(0).front());
313-
if constexpr (std::is_same<AtomicListT,
314-
Fortran::parser::OmpAtomicClauseList>()) {
315-
firOpBuilder.create<mlir::omp::YieldOp>(currentLocation,
316-
y.getResults());
317-
} else {
318-
firOpBuilder.create<mlir::acc::YieldOp>(currentLocation,
319-
y.getResults());
320-
}
321-
op->erase();
274+
exprValueOverrides.try_emplace(
275+
Fortran::semantics::GetExpr(assignmentStmtVariable), val);
276+
{
277+
// statement context inside the atomic block.
278+
converter.overrideExprValues(&exprValueOverrides);
279+
Fortran::lower::StatementContext atomicStmtCtx;
280+
mlir::Value rhsExpr = fir::getBase(converter.genExprValue(
281+
*Fortran::semantics::GetExpr(assignmentStmtExpr), atomicStmtCtx));
282+
mlir::Value convertResult =
283+
firOpBuilder.createConvert(currentLocation, varType, rhsExpr);
284+
if constexpr (std::is_same<AtomicListT,
285+
Fortran::parser::OmpAtomicClauseList>()) {
286+
firOpBuilder.create<mlir::omp::YieldOp>(currentLocation, convertResult);
322287
} else {
323-
op->remove();
324-
atomicUpdateOp->getRegion(0).front().push_back(op);
288+
firOpBuilder.create<mlir::acc::YieldOp>(currentLocation, convertResult);
325289
}
290+
converter.resetExprOverrides();
326291
}
327-
328-
// Remove the load and replace all uses of load with the block argument
329-
for (mlir::Operation &op : atomicUpdateOp->getRegion(0).getOps()) {
330-
fir::LoadOp y = mlir::dyn_cast<fir::LoadOp>(&op);
331-
if (y && y.getMemref() == updateVar)
332-
y.getRes().replaceAllUsesWith(val);
333-
}
334-
335-
tempOp.erase();
292+
firOpBuilder.setInsertionPointAfter(atomicUpdateOp);
336293
}
337294

338295
/// Processes an atomic construct with write clause.
@@ -423,11 +380,7 @@ void genOmpAccAtomicUpdate(Fortran::lower::AbstractConverter &converter,
423380
Fortran::lower::StatementContext stmtCtx;
424381
mlir::Value lhsAddr = fir::getBase(converter.genExprAddr(
425382
*Fortran::semantics::GetExpr(assignmentStmtVariable), stmtCtx));
426-
mlir::Type varType =
427-
fir::getBase(
428-
converter.genExprValue(
429-
*Fortran::semantics::GetExpr(assignmentStmtVariable), stmtCtx))
430-
.getType();
383+
mlir::Type varType = fir::unwrapRefType(lhsAddr.getType());
431384
genOmpAccAtomicUpdateStatement<AtomicListT>(
432385
converter, lhsAddr, varType, assignmentStmtVariable, assignmentStmtExpr,
433386
leftHandClauseList, rightHandClauseList);
@@ -450,11 +403,7 @@ void genOmpAtomic(Fortran::lower::AbstractConverter &converter,
450403
Fortran::lower::StatementContext stmtCtx;
451404
mlir::Value lhsAddr = fir::getBase(converter.genExprAddr(
452405
*Fortran::semantics::GetExpr(assignmentStmtVariable), stmtCtx));
453-
mlir::Type varType =
454-
fir::getBase(
455-
converter.genExprValue(
456-
*Fortran::semantics::GetExpr(assignmentStmtVariable), stmtCtx))
457-
.getType();
406+
mlir::Type varType = fir::unwrapRefType(lhsAddr.getType());
458407
// If atomic-clause is not present on the construct, the behaviour is as if
459408
// the update clause is specified (for both OpenMP and OpenACC).
460409
genOmpAccAtomicUpdateStatement<AtomicListT>(

flang/test/Lower/OpenACC/acc-atomic-update-hlfir.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ subroutine sb
1414
!CHECK: %[[X_DECL:.*]]:2 = hlfir.declare %[[X_REF]] {uniq_name = "_QFsbEx"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
1515
!CHECK: %[[Y_REF:.*]] = fir.alloca i32 {bindc_name = "y", uniq_name = "_QFsbEy"}
1616
!CHECK: %[[Y_DECL:.*]]:2 = hlfir.declare %[[Y_REF]] {uniq_name = "_QFsbEy"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
17-
!CHECK: acc.atomic.update %[[X_DECL]]#0 : !fir.ref<i32> {
17+
!CHECK: acc.atomic.update %[[X_DECL]]#1 : !fir.ref<i32> {
1818
!CHECK: ^bb0(%[[ARG_X:.*]]: i32):
1919
!CHECK: %[[Y_VAL:.*]] = fir.load %[[Y_DECL]]#0 : !fir.ref<i32>
2020
!CHECK: %[[X_UPDATE_VAL:.*]] = arith.addi %[[ARG_X]], %[[Y_VAL]] : i32

flang/test/Lower/OpenMP/atomic-update-hlfir.f90

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ subroutine sb
1414
!CHECK: %[[X_DECL:.*]]:2 = hlfir.declare %[[X_REF]] {uniq_name = "_QFsbEx"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
1515
!CHECK: %[[Y_REF:.*]] = fir.alloca i32 {bindc_name = "y", uniq_name = "_QFsbEy"}
1616
!CHECK: %[[Y_DECL:.*]]:2 = hlfir.declare %[[Y_REF]] {uniq_name = "_QFsbEy"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
17-
!CHECK: omp.atomic.update %[[X_DECL]]#0 : !fir.ref<i32> {
17+
!CHECK: %[[Y_VAL:.*]] = fir.load %[[Y_DECL]]#0 : !fir.ref<i32>
18+
!CHECK: omp.atomic.update %[[X_DECL]]#1 : !fir.ref<i32> {
1819
!CHECK: ^bb0(%[[ARG_X:.*]]: i32):
19-
!CHECK: %[[Y_VAL:.*]] = fir.load %[[Y_DECL]]#0 : !fir.ref<i32>
2020
!CHECK: %[[X_UPDATE_VAL:.*]] = arith.addi %[[ARG_X]], %[[Y_VAL]] : i32
2121
!CHECK: omp.yield(%[[X_UPDATE_VAL]] : i32)
2222
!CHECK: }
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
!RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s
2+
3+
!CHECK: func.func @_QQmain() attributes {fir.bindc_name = "sample"} {
4+
!CHECK: %[[val_0:.*]] = fir.alloca i32 {bindc_name = "a", uniq_name = "_QFEa"}
5+
!CHECK: %[[val_1:.*]]:2 = hlfir.declare %[[val_0]] {uniq_name = "_QFEa"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
6+
!CHECK: %[[val_2:.*]] = fir.alloca i32 {bindc_name = "b", uniq_name = "_QFEb"}
7+
!CHECK: %[[val_3:.*]]:2 = hlfir.declare %[[val_2]] {uniq_name = "_QFEb"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
8+
!CHECK: %[[val_4:.*]] = fir.alloca i32 {bindc_name = "x", uniq_name = "_QFEx"}
9+
!CHECK: %[[val_5:.*]]:2 = hlfir.declare %[[val_4]] {uniq_name = "_QFEx"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
10+
!CHECK: %[[val_c5:.*]] = arith.constant 5 : index
11+
!CHECK: %[[val_6:.*]] = fir.alloca !fir.array<5xi32> {bindc_name = "y", uniq_name = "_QFEy"}
12+
!CHECK: %[[val_7:.*]] = fir.shape %[[val_c5]] : (index) -> !fir.shape<1>
13+
!CHECK: %[[val_8:.*]]:2 = hlfir.declare %[[val_6]](%[[val_7]]) {uniq_name = "_QFEy"} : (!fir.ref<!fir.array<5xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<5xi32>>, !fir.ref<!fir.array<5xi32>>)
14+
!CHECK: %[[val_c2:.*]] = arith.constant 2 : index
15+
!CHECK: %[[val_9:.*]] = hlfir.designate %[[val_8]]#0 (%[[val_c2]]) : (!fir.ref<!fir.array<5xi32>>, index) -> !fir.ref<i32>
16+
!CHECK: %[[val_c8:.*]] = arith.constant 8 : i32
17+
!CHECK: %[[val_10:.*]] = fir.load %[[val_5]]#0 : !fir.ref<i32>
18+
!CHECK: %[[val_11:.*]] = arith.addi %[[val_c8]], %[[val_10]] : i32
19+
!CHECK: %[[val_12:.*]] = hlfir.no_reassoc %[[val_11]] : i32
20+
!CHECK: omp.atomic.update %[[val_9]] : !fir.ref<i32> {
21+
!CHECK: ^bb0(%[[ARG:.*]]: i32):
22+
!CHECK: %[[val_18:.*]] = arith.muli %[[val_12]], %[[ARG]] : i32
23+
!CHECK: omp.yield(%[[val_18]] : i32)
24+
!CHECK: }
25+
!CHECK: %[[val_c2_0:.*]] = arith.constant 2 : index
26+
!CHECK: %[[val_13:.*]] = hlfir.designate %[[val_8]]#0 (%[[val_c2_0]]) : (!fir.ref<!fir.array<5xi32>>, index) -> !fir.ref<i32>
27+
!CHECK: %[[val_c8_1:.*]] = arith.constant 8 : i32
28+
!CHECK: omp.atomic.update %[[val_13:.*]] : !fir.ref<i32> {
29+
!CHECK: ^bb0(%[[ARG:.*]]: i32):
30+
!CHECK: %[[val_18:.*]] = arith.divsi %[[ARG]], %[[val_c8_1]] : i32
31+
!CHECK: omp.yield(%[[val_18]] : i32)
32+
!CHECK: }
33+
!CHECK: %[[val_c8_2:.*]] = arith.constant 8 : i32
34+
!CHECK: %[[val_c4:.*]] = arith.constant 4 : index
35+
!CHECK: %[[val_14:.*]] = hlfir.designate %[[val_8]]#0 (%[[val_c4]]) : (!fir.ref<!fir.array<5xi32>>, index) -> !fir.ref<i32>
36+
!CHECK: %[[val_15:.*]] = fir.load %[[val_14]] : !fir.ref<i32>
37+
!CHECK: %[[val_16:.*]] = arith.addi %[[val_c8_2]], %[[val_15]] : i32
38+
!CHECK: %[[val_17:.*]] = hlfir.no_reassoc %[[val_16]] : i32
39+
!CHECK: omp.atomic.update %[[val_5]]#1 : !fir.ref<i32> {
40+
!CHECK: ^bb0(%[[ARG:.*]]: i32):
41+
!CHECK: %[[val_18:.*]] = arith.addi %[[val_17]], %[[ARG]] : i32
42+
!CHECK: omp.yield(%[[val_18]] : i32)
43+
!CHECK: }
44+
!CHECK: %[[val_c8_3:.*]] = arith.constant 8 : i32
45+
!CHECK: omp.atomic.update %[[val_5]]#1 : !fir.ref<i32> {
46+
!CHECK: ^bb0(%[[ARG]]: i32):
47+
!CHECK: %[[val_18:.*]] = arith.subi %[[val_c8_3]], %[[ARG]] : i32
48+
!CHECK: omp.yield(%[[val_18]] : i32)
49+
!CHECK: }
50+
!CHECK: return
51+
!CHECK: }
52+
program sample
53+
54+
integer :: x
55+
integer, dimension(5) :: y
56+
integer :: a, b
57+
58+
!$omp atomic update
59+
y(2) = (8 + x) * y(2)
60+
!$omp end atomic
61+
62+
!$omp atomic update
63+
y(2) = y(2) / 8
64+
!$omp end atomic
65+
66+
!$omp atomic update
67+
x = (8 + y(4)) + x
68+
!$omp end atomic
69+
70+
!$omp atomic update
71+
x = 8 - x
72+
!$omp end atomic
73+
74+
end program sample

0 commit comments

Comments
 (0)