diff --git a/flang/lib/Lower/OpenMP.cpp b/flang/lib/Lower/OpenMP.cpp --- a/flang/lib/Lower/OpenMP.cpp +++ b/flang/lib/Lower/OpenMP.cpp @@ -1701,6 +1701,36 @@ } } +static bool checkForSingleVariableOnRHS( + const Fortran::parser::AssignmentStmt &assignmentStmt) { + // Check if the assignment statement has a single variable on the RHS + const Fortran::parser::Expr &expr{ + std::get(assignmentStmt.t)}; + const Fortran::common::Indirection *designator = + std::get_if>( + &expr.u); + const Fortran::parser::Name *name = + designator ? getDesignatorNameIfDataRef(designator->value()) : nullptr; + return name != nullptr; +} + +static bool +checkForSymbolMatch(const Fortran::parser::AssignmentStmt &assignmentStmt) { + // Check if the symbol on the LHS of the assignment statement is present in + // the RHS expression + const auto &var{std::get(assignmentStmt.t)}; + const auto &expr{std::get(assignmentStmt.t)}; + const auto *e{Fortran::semantics::GetExpr(expr)}; + const auto *v{Fortran::semantics::GetExpr(var)}; + const Fortran::semantics::Symbol &varSymbol = + Fortran::evaluate::GetSymbolVector(*v).front(); + for (const Fortran::semantics::Symbol &symbol : + Fortran::evaluate::GetSymbolVector(*e)) + if (varSymbol == symbol) + return true; + return false; +} + static void genOmpAtomicHintAndMemoryOrderClauses( Fortran::lower::AbstractConverter &converter, const Fortran::parser::OmpAtomicClauseList &clauseList, @@ -1739,20 +1769,68 @@ } } +static void genOmpAtomicCaptureStatement( + Fortran::lower::AbstractConverter &converter, + Fortran::lower::pft::Evaluation &eval, mlir::Value from_address, + mlir::Value to_address, + const Fortran::parser::OmpAtomicClauseList *leftHandClauseList, + const Fortran::parser::OmpAtomicClauseList *rightHandClauseList, + mlir::Type elementType) { + // Generate `omp.atomic.read` operation for atomic assigment statements + auto &firOpBuilder = converter.getFirOpBuilder(); + auto currentLocation = converter.getCurrentLocation(); + + // If no hint clause is specified, the effect is as if + // hint(omp_sync_hint_none) had been specified. + mlir::IntegerAttr hint = nullptr; + + mlir::omp::ClauseMemoryOrderKindAttr memory_order = nullptr; + if (leftHandClauseList) + genOmpAtomicHintAndMemoryOrderClauses(converter, *leftHandClauseList, hint, + memory_order); + if (rightHandClauseList) + genOmpAtomicHintAndMemoryOrderClauses(converter, *rightHandClauseList, hint, + memory_order); + firOpBuilder.create( + currentLocation, from_address, to_address, + mlir::TypeAttr::get(elementType), hint, memory_order); +} + +static void genOmpAtomicWriteStatement( + Fortran::lower::AbstractConverter &converter, + Fortran::lower::pft::Evaluation &eval, mlir::Value lhs_addr, + mlir::Value rhs_expr, + const Fortran::parser::OmpAtomicClauseList *leftHandClauseList, + const Fortran::parser::OmpAtomicClauseList *rightHandClauseList, + mlir::Value *evaluatedExprValue = nullptr) { + // Generate `omp.atomic.write` operation for atomic assignment statements + auto &firOpBuilder = converter.getFirOpBuilder(); + auto currentLocation = converter.getCurrentLocation(); + // If no hint clause is specified, the effect is as if + // hint(omp_sync_hint_none) had been specified. + mlir::IntegerAttr hint = nullptr; + mlir::omp::ClauseMemoryOrderKindAttr memory_order = nullptr; + if (leftHandClauseList) + genOmpAtomicHintAndMemoryOrderClauses(converter, *leftHandClauseList, hint, + memory_order); + if (rightHandClauseList) + genOmpAtomicHintAndMemoryOrderClauses(converter, *rightHandClauseList, hint, + memory_order); + firOpBuilder.create(currentLocation, lhs_addr, + rhs_expr, hint, memory_order); +} + static void genOmpAtomicUpdateStatement( Fortran::lower::AbstractConverter &converter, - Fortran::lower::pft::Evaluation &eval, - const Fortran::parser::Variable &assignmentStmtVariable, + Fortran::lower::pft::Evaluation &eval, mlir::Value lhs_addr, + mlir::Type varType, const Fortran::parser::Variable &assignmentStmtVariable, const Fortran::parser::Expr &assignmentStmtExpr, const Fortran::parser::OmpAtomicClauseList *leftHandClauseList, const Fortran::parser::OmpAtomicClauseList *rightHandClauseList) { // Generate `omp.atomic.update` operation for atomic assignment statements auto &firOpBuilder = converter.getFirOpBuilder(); auto currentLocation = converter.getCurrentLocation(); - Fortran::lower::StatementContext stmtCtx; - mlir::Value address = fir::getBase(converter.genExprAddr( - *Fortran::semantics::GetExpr(assignmentStmtVariable), stmtCtx)); // If no hint clause is specified, the effect is as if // hint(omp_sync_hint_none) had been specified. mlir::IntegerAttr hint = nullptr; @@ -1764,16 +1842,11 @@ genOmpAtomicHintAndMemoryOrderClauses(converter, *rightHandClauseList, hint, memoryOrder); auto atomicUpdateOp = firOpBuilder.create( - currentLocation, address, hint, memoryOrder); + currentLocation, lhs_addr, hint, memoryOrder); //// Generate body of Atomic Update operation // If an argument for the region is provided then create the block with that // argument. Also update the symbol's address with the argument mlir value. - mlir::Type varType = - fir::getBase( - converter.genExprValue( - *Fortran::semantics::GetExpr(assignmentStmtVariable), stmtCtx)) - .getType(); SmallVector varTys = {varType}; SmallVector locs = {currentLocation}; firOpBuilder.createBlock(&atomicUpdateOp.getRegion(), {}, varTys, locs); @@ -1785,18 +1858,18 @@ assert(varDesignator && "Variable designator for atomic update assignment " "statement does not exist"); const auto *name = getDesignatorNameIfDataRef(varDesignator->value()); - assert(name && name->symbol && - "No symbol attached to atomic update variable"); - converter.bindSymbol(*name->symbol, val); + if (name) + converter.bindSymbol(*name->symbol, val); // Set the insert for the terminator operation to go at the end of the // block. mlir::Block &block = atomicUpdateOp.getRegion().back(); firOpBuilder.setInsertionPointToEnd(&block); - mlir::Value result = fir::getBase(converter.genExprValue( + Fortran::lower::StatementContext stmtCtx; + mlir::Value rhs_expr = fir::getBase(converter.genExprValue( *Fortran::semantics::GetExpr(assignmentStmtExpr), stmtCtx)); mlir::Value convertResult = - firOpBuilder.createConvert(currentLocation, varType, result); + firOpBuilder.createConvert(currentLocation, varType, rhs_expr); // Insert the terminator: YieldOp. firOpBuilder.create(currentLocation, convertResult); // Reset the insert point to before the terminator. @@ -1807,8 +1880,6 @@ genOmpAtomicWrite(Fortran::lower::AbstractConverter &converter, Fortran::lower::pft::Evaluation &eval, const Fortran::parser::OmpAtomicWrite &atomicWrite) { - auto &firOpBuilder = converter.getFirOpBuilder(); - auto currentLocation = converter.getCurrentLocation(); // Get the value and address of atomic write operands. const Fortran::parser::OmpAtomicClauseList &rightHandClauseList = std::get<2>(atomicWrite.t); @@ -1819,27 +1890,18 @@ const auto &assignmentStmtVariable = std::get( std::get<3>(atomicWrite.t).statement.t); Fortran::lower::StatementContext stmtCtx; - mlir::Value value = fir::getBase(converter.genExprValue( + // Get the value and address of atomic write operands. + mlir::Value rhs_expr = fir::getBase(converter.genExprValue( *Fortran::semantics::GetExpr(assignmentStmtExpr), stmtCtx)); - mlir::Value address = fir::getBase(converter.genExprAddr( + mlir::Value lhs_addr = fir::getBase(converter.genExprAddr( *Fortran::semantics::GetExpr(assignmentStmtVariable), stmtCtx)); - // If no hint clause is specified, the effect is as if - // hint(omp_sync_hint_none) had been specified. - mlir::IntegerAttr hint = nullptr; - mlir::omp::ClauseMemoryOrderKindAttr memoryOrder = nullptr; - genOmpAtomicHintAndMemoryOrderClauses(converter, leftHandClauseList, hint, - memoryOrder); - genOmpAtomicHintAndMemoryOrderClauses(converter, rightHandClauseList, hint, - memoryOrder); - firOpBuilder.create(currentLocation, address, value, - hint, memoryOrder); + genOmpAtomicWriteStatement(converter, eval, lhs_addr, rhs_expr, + &leftHandClauseList, &rightHandClauseList); } static void genOmpAtomicRead(Fortran::lower::AbstractConverter &converter, Fortran::lower::pft::Evaluation &eval, const Fortran::parser::OmpAtomicRead &atomicRead) { - auto &firOpBuilder = converter.getFirOpBuilder(); - auto currentLocation = converter.getCurrentLocation(); // Get the address of atomic read operands. const Fortran::parser::OmpAtomicClauseList &rightHandClauseList = std::get<2>(atomicRead.t); @@ -1858,17 +1920,9 @@ fir::getBase(converter.genExprAddr(fromExpr, stmtCtx)); mlir::Value toAddress = fir::getBase(converter.genExprAddr( *Fortran::semantics::GetExpr(assignmentStmtVariable), stmtCtx)); - // If no hint clause is specified, the effect is as if - // hint(omp_sync_hint_none) had been specified. - mlir::IntegerAttr hint = nullptr; - mlir::omp::ClauseMemoryOrderKindAttr memoryOrder = nullptr; - genOmpAtomicHintAndMemoryOrderClauses(converter, leftHandClauseList, hint, - memoryOrder); - genOmpAtomicHintAndMemoryOrderClauses(converter, rightHandClauseList, hint, - memoryOrder); - firOpBuilder.create( - currentLocation, fromAddress, toAddress, mlir::TypeAttr::get(elementType), - hint, memoryOrder); + genOmpAtomicCaptureStatement(converter, eval, fromAddress, toAddress, + &leftHandClauseList, &rightHandClauseList, + elementType); } static void @@ -1884,9 +1938,17 @@ const auto &assignmentStmtVariable = std::get( std::get<3>(atomicUpdate.t).statement.t); - genOmpAtomicUpdateStatement(converter, eval, assignmentStmtVariable, - assignmentStmtExpr, &leftHandClauseList, - &rightHandClauseList); + Fortran::lower::StatementContext stmtCtx; + mlir::Value lhs_addr = fir::getBase(converter.genExprAddr( + *Fortran::semantics::GetExpr(assignmentStmtVariable), stmtCtx)); + mlir::Type varType = + fir::getBase( + converter.genExprValue( + *Fortran::semantics::GetExpr(assignmentStmtVariable), stmtCtx)) + .getType(); + genOmpAtomicUpdateStatement(converter, eval, lhs_addr, varType, + assignmentStmtVariable, assignmentStmtExpr, + &leftHandClauseList, &rightHandClauseList); } static void genOmpAtomic(Fortran::lower::AbstractConverter &converter, @@ -1902,10 +1964,137 @@ std::get>( atomicConstruct.t) .statement.t); + Fortran::lower::StatementContext stmtCtx; + mlir::Value lhs_addr = fir::getBase(converter.genExprAddr( + *Fortran::semantics::GetExpr(assignmentStmtVariable), stmtCtx)); + mlir::Type varType = + fir::getBase( + converter.genExprValue( + *Fortran::semantics::GetExpr(assignmentStmtVariable), stmtCtx)) + .getType(); // If atomic-clause is not present on the construct, the behaviour is as if // the update clause is specified - genOmpAtomicUpdateStatement(converter, eval, assignmentStmtVariable, - assignmentStmtExpr, &atomicClauseList, nullptr); + genOmpAtomicUpdateStatement(converter, eval, lhs_addr, varType, + assignmentStmtVariable, assignmentStmtExpr, + &atomicClauseList, nullptr); +} + +static void +genOmpAtomicCapture(Fortran::lower::AbstractConverter &converter, + Fortran::lower::pft::Evaluation &eval, + const Fortran::parser::OmpAtomicCapture &atomicCapture) { + fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); + mlir::Location currentLocation = converter.getCurrentLocation(); + + mlir::IntegerAttr hint = nullptr; + mlir::omp::ClauseMemoryOrderKindAttr memory_order = nullptr; + const Fortran::parser::OmpAtomicClauseList &rightHandClauseList = + std::get<2>(atomicCapture.t); + const Fortran::parser::OmpAtomicClauseList &leftHandClauseList = + std::get<0>(atomicCapture.t); + genOmpAtomicHintAndMemoryOrderClauses(converter, leftHandClauseList, hint, + memory_order); + genOmpAtomicHintAndMemoryOrderClauses(converter, rightHandClauseList, hint, + memory_order); + + const Fortran::parser::AssignmentStmt &stmt1 = + std::get<3>(atomicCapture.t).v.statement; + const auto &stmt1Var{std::get(stmt1.t)}; + const auto &stmt1Expr{std::get(stmt1.t)}; + const Fortran::parser::AssignmentStmt &stmt2 = + std::get<4>(atomicCapture.t).v.statement; + const auto &stmt2Var{std::get(stmt2.t)}; + const auto &stmt2Expr{std::get(stmt2.t)}; + + // Pre-evaluate expressions to be used in the various operations inside + // `omp.atomic.capture` since it is not desirable to have anything other than + // a `omp.atomic.read`, `omp.atomic.write`, or `omp.atomic.update` operation + // inside `omp.atomic.capture` + Fortran::lower::StatementContext stmtCtx; + mlir::Value stmt1LHSArg, stmt1RHSArg, stmt2LHSArg, stmt2RHSArg; + mlir::Type elementType; + // LHS evaluations are common to all combinations of `omp.atomic.capture` + stmt1LHSArg = fir::getBase( + converter.genExprAddr(*Fortran::semantics::GetExpr(stmt1Var), stmtCtx)); + stmt2LHSArg = fir::getBase( + converter.genExprAddr(*Fortran::semantics::GetExpr(stmt2Var), stmtCtx)); + + // Operation specific RHS evaluations + if (checkForSingleVariableOnRHS(stmt1)) { + // Atomic capture construct is of the form [capture-stmt, update-stmt] or + // of the form [capture-stmt, write-stmt] + stmt1RHSArg = fir::getBase(converter.genExprAddr( + *Fortran::semantics::GetExpr(stmt1Expr), stmtCtx)); + stmt2RHSArg = fir::getBase(converter.genExprValue( + *Fortran::semantics::GetExpr(stmt2Expr), stmtCtx)); + + } else { + // Atomic capture construct is of the form [update-stmt, capture-stmt] + stmt1RHSArg = fir::getBase(converter.genExprValue( + *Fortran::semantics::GetExpr(stmt1Expr), stmtCtx)); + stmt2RHSArg = fir::getBase(converter.genExprAddr( + *Fortran::semantics::GetExpr(stmt2Expr), stmtCtx)); + } + // Type information used in generation of `omp.atomic.update` operation + mlir::Type stmt1VarType = + fir::getBase(converter.genExprValue( + *Fortran::semantics::GetExpr(stmt1Var), stmtCtx)) + .getType(); + mlir::Type stmt2VarType = + fir::getBase(converter.genExprValue( + *Fortran::semantics::GetExpr(stmt2Var), stmtCtx)) + .getType(); + + auto atomicCaptureOp = firOpBuilder.create( + currentLocation, hint, memory_order); + firOpBuilder.createBlock(&atomicCaptureOp.getRegion()); + mlir::Block &block = atomicCaptureOp.getRegion().back(); + firOpBuilder.setInsertionPointToStart(&block); + if (checkForSingleVariableOnRHS(stmt1)) { + if (checkForSymbolMatch(stmt2)) { + // Atomic capture construct is of the form [capture-stmt, update-stmt] + const Fortran::semantics::SomeExpr &fromExpr = + *Fortran::semantics::GetExpr(stmt1Expr); + elementType = converter.genType(fromExpr); + genOmpAtomicCaptureStatement(converter, eval, stmt1RHSArg, stmt1LHSArg, + /*leftHandClauseList=*/nullptr, + /*rightHandClauseList=*/nullptr, + elementType); + genOmpAtomicUpdateStatement(converter, eval, stmt1RHSArg, stmt2VarType, + stmt2Var, stmt2Expr, + /*leftHandClauseList=*/nullptr, + /*rightHandClauseList=*/nullptr); + } else { + // Atomic capture construct is of the form [capture-stmt, write-stmt] + const Fortran::semantics::SomeExpr &fromExpr = + *Fortran::semantics::GetExpr(stmt1Expr); + elementType = converter.genType(fromExpr); + genOmpAtomicCaptureStatement(converter, eval, stmt1RHSArg, stmt1LHSArg, + /*leftHandClauseList=*/nullptr, + /*rightHandClauseList=*/nullptr, + elementType); + genOmpAtomicWriteStatement(converter, eval, stmt1RHSArg, stmt2RHSArg, + /*leftHandClauseList=*/nullptr, + /*rightHandClauseList=*/nullptr); + } + } else { + // Atomic capture construct is of the form [update-stmt, capture-stmt] + firOpBuilder.setInsertionPointToEnd(&block); + const Fortran::semantics::SomeExpr &fromExpr = + *Fortran::semantics::GetExpr(stmt2Expr); + elementType = converter.genType(fromExpr); + genOmpAtomicCaptureStatement(converter, eval, stmt1LHSArg, stmt2LHSArg, + /*leftHandClauseList=*/nullptr, + /*rightHandClauseList=*/nullptr, elementType); + firOpBuilder.setInsertionPointToStart(&block); + genOmpAtomicUpdateStatement(converter, eval, stmt1LHSArg, stmt1VarType, + stmt1Var, stmt1Expr, + /*leftHandClauseList=*/nullptr, + /*rightHandClauseList=*/nullptr); + } + firOpBuilder.setInsertionPointToEnd(&block); + firOpBuilder.create(currentLocation); + firOpBuilder.setInsertionPointToStart(&block); } static void @@ -1925,8 +2114,8 @@ [&](const Fortran::parser::OmpAtomicUpdate &atomicUpdate) { genOmpAtomicUpdate(converter, eval, atomicUpdate); }, - [&](const auto &) { - TODO(converter.getCurrentLocation(), "Atomic capture"); + [&](const Fortran::parser::OmpAtomicCapture &atomicCapture) { + genOmpAtomicCapture(converter, eval, atomicCapture); }, }, atomicConstruct.u); diff --git a/flang/test/Lower/OpenMP/atomic-capture.f90 b/flang/test/Lower/OpenMP/atomic-capture.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Lower/OpenMP/atomic-capture.f90 @@ -0,0 +1,162 @@ +! RUN: %flang_fc1 -emit-fir -fopenmp %s -o - | FileCheck %s + +! This test checks the lowering of atomic capture + +program OmpAtomicCapture + use omp_lib + integer :: x, y + +!CHECK: %[[X:.*]] = fir.alloca i32 {bindc_name = "x", uniq_name = "_QFEx"} +!CHECK: %[[Y:.*]] = fir.alloca i32 {bindc_name = "y", uniq_name = "_QFEy"} +!CHECK: omp.atomic.capture memory_order(release) { +!CHECK: omp.atomic.read %[[X]] = %[[Y]] : !fir.ref +!CHECK: omp.atomic.update %[[Y]] : !fir.ref { +!CHECK: ^bb0(%[[ARG:.*]]: i32): +!CHECK: %[[temp:.*]] = fir.load %[[X]] : !fir.ref +!CHECK: %[[result:.*]] = arith.addi %[[temp]], %[[ARG]] : i32 +!CHECK: omp.yield(%[[result]] : i32) +!CHECK: } +!CHECK: } + + !$omp atomic capture release + x = y + y = x + y + !$omp end atomic + + +!CHECK: omp.atomic.capture hint(uncontended) { +!CHECK: omp.atomic.update %[[Y]] : !fir.ref { +!CHECK: ^bb0(%[[ARG:.*]]: i32): +!CHECK: %[[temp:.*]] = fir.load %[[X]] : !fir.ref +!CHECK: %[[result:.*]] = arith.muli %[[temp]], %[[ARG]] : i32 +!CHECK: omp.yield(%[[result]] : i32) +!CHECK: } +!CHECK: omp.atomic.read %[[X]] = %[[Y]] : !fir.ref +!CHECK: } + + !$omp atomic hint(omp_sync_hint_uncontended) capture + y = x * y + x = y + !$omp end atomic + +!CHECK: %[[constant_20:.*]] = arith.constant 20 : i32 +!CHECK: %[[constant_8:.*]] = arith.constant 8 : i32 +!CHECK: %[[temp:.*]] = fir.load %[[X]] : !fir.ref +!CHECK: %[[result:.*]] = arith.subi %[[constant_8]], %[[temp]] : i32 +!CHECK: %[[result_noreassoc:.*]] = fir.no_reassoc %[[result]] : i32 +!CHECK: %[[result:.*]] = arith.addi %[[constant_20]], %[[result_noreassoc]] : i32 +!CHECK: omp.atomic.capture memory_order(acquire) hint(nonspeculative) { +!CHECK: omp.atomic.read %[[X]] = %[[Y]] : !fir.ref +!CHECK: omp.atomic.write %[[Y]] = %[[result]] : !fir.ref, i32 +!CHECK: } + + !$omp atomic hint(omp_lock_hint_nonspeculative) capture acquire + x = y + y = 2 * 10 + (8 - x) + !$omp end atomic + + +!CHECK: %[[constant_20:.*]] = arith.constant 20 : i32 +!CHECK: %[[constant_8:.*]] = arith.constant 8 : i32 +!CHECK: %[[temp:.*]] = fir.load %[[X]] : !fir.ref +!CHECK: %[[result:.*]] = arith.subi %[[constant_8]], %[[temp]] : i32 +!CHECK: %[[result_noreassoc:.*]] = fir.no_reassoc %[[result]] : i32 +!CHECK: %[[result:.*]] = arith.addi %[[constant_20]], %[[result_noreassoc]] : i32 +!CHECK: omp.atomic.capture { +!CHECK: omp.atomic.read %[[X]] = %[[Y]] : !fir.ref +!CHECK: omp.atomic.write %[[Y]] = %[[result]] : !fir.ref, i32 +!CHECK: } + + !$omp atomic capture + x = y + y = 2 * 10 + (8 - x) + !$omp end atomic +end program + + + +subroutine pointers_in_atomic_capture() + +!CHECK: %{{.*}} = fir.alloca !fir.box> {bindc_name = "a", uniq_name = "_QFpointers_in_atomic_captureEa"} +!CHECK: %[[A:.*]] = fir.alloca !fir.ptr {uniq_name = "_QFpointers_in_atomic_captureEa.addr"} +!CHECK: %[[temp:.*]] = fir.zero_bits !fir.ptr +!CHECK: fir.store %[[temp]] to %[[A]] : !fir.ref> +!CHECK: %{{.*}} = fir.alloca !fir.box> {bindc_name = "b", uniq_name = "_QFpointers_in_atomic_captureEb"} +!CHECK: %[[B:.*]] = fir.alloca !fir.ptr {uniq_name = "_QFpointers_in_atomic_captureEb.addr"} +!CHECK: %[[temp:.*]] = fir.zero_bits !fir.ptr +!CHECK: fir.store %[[temp]] to %[[B]] : !fir.ref> +!CHECK: %[[C:.*]] = fir.alloca i32 {bindc_name = "c", fir.target, uniq_name = "_QFpointers_in_atomic_captureEc"} +!CHECK: %[[D:.*]] = fir.alloca i32 {bindc_name = "d", fir.target, uniq_name = "_QFpointers_in_atomic_captureEd"} +!CHECK: %[[temp:.*]] = fir.convert %[[C]] : (!fir.ref) -> !fir.ptr +!CHECK: fir.store %[[temp]] to %[[A]] : !fir.ref> +!CHECK: %[[temp:.*]] = fir.convert %[[D]] : (!fir.ref) -> !fir.ptr +!CHECK: fir.store %[[temp]] to %[[B]] : !fir.ref> + integer, pointer :: a, b + integer, target :: c, d + a=>c + b=>d + +!CHECK: %[[loaded_A:.*]] = fir.load %[[A]] : !fir.ref> +!CHECK: %[[loaded_B:.*]] = fir.load %[[B]] : !fir.ref> +!CHECK: omp.atomic.capture { +!CHECK: omp.atomic.update %[[loaded_A]] : !fir.ptr { +!CHECK: ^bb0(%[[ARG:.*]]: i32): +!CHECK: %[[temp:.*]] = fir.load %[[B]] : !fir.ref> +!CHECK: %[[loaded_B_update_op:.*]] = fir.load %[[temp]] : !fir.ptr +!CHECK: %[[result:.*]] = arith.addi %[[ARG]], %[[loaded_B_update_op]] : i32 +!CHECK: omp.yield(%[[result]] : i32) +!CHECK: } +!CHECK: omp.atomic.read %[[loaded_B]] = %[[loaded_A]] : !fir.ptr +!CHECK: } + !$omp atomic capture + a = a + b + b = a + !$omp end atomic + +!CHECK: %[[loaded_B:.*]] = fir.load %[[B]] : !fir.ref> +!CHECK: %[[loaded_A:.*]] = fir.load %[[A]] : !fir.ref> +!CHECK: %[[const:.*]] = arith.constant 10 : i32 +!CHECK: %[[loaded_B_write_op:.*]] = fir.load %[[B]] : !fir.ref> +!CHECK: %[[temp:.*]] = fir.load %[[loaded_B_write_op]] : !fir.ptr +!CHECK: %[[evaluated_expr:.*]] = arith.addi %[[const]], %[[temp]] : i32 +!CHECK: omp.atomic.capture { +!CHECK: omp.atomic.read %[[loaded_B]] = %[[loaded_A]] : !fir.ptr +!CHECK: omp.atomic.write %[[loaded_A]] = %[[evaluated_expr]] : !fir.ptr, i32 +!CHECK: } +!CHECK: return +!CHECK: } + !$omp atomic capture + b = a + a = 10 + b + !$omp end atomic +end subroutine + +!CHECK: func.func @_QParray_refs() { +!CHECK: %[[ARRAY:.*]] = fir.alloca !fir.array<5xf32> {bindc_name = "numbers", uniq_name = "_QFarray_refsEnumbers"} +!CHECK: %[[X:.*]] = fir.alloca f32 {bindc_name = "x", uniq_name = "_QFarray_refsEx"} +!CHECK: %[[const_1:.*]] = arith.constant 1 : i64 +!CHECK: %[[const_2:.*]] = arith.constant 1 : i64 +!CHECK: %[[const_sum:.*]] = arith.subi %[[const_1]], %[[const_2]] : i64 +!CHECK: %[[array_element:.*]] = fir.coordinate_of %[[ARRAY]], %[[const_sum]] : (!fir.ref>, i64) -> !fir.ref +!CHECK: omp.atomic.capture { +!CHECK: omp.atomic.update %[[array_element]] : !fir.ref { +!CHECK: ^bb0(%[[ARG:.*]]: f32): +!CHECK: %[[const_1:.*]] = arith.constant 1 : i64 +!CHECK: %[[const_2:.*]] = arith.constant 1 : i64 +!CHECK: %[[const_sum:.*]] = arith.subi %[[const_1]], %[[const_2]] : i64 +!CHECK: %[[array_element_ref:.*]] = fir.coordinate_of %[[ARRAY]], %[[const_sum]] : (!fir.ref>, i64) -> !fir.ref +!CHECK: %[[array_element_inner:.*]] = fir.load %[[array_element_ref]] +!CHECK: %[[cst:.*]] = arith.constant 1.000000e+01 : f32 +!CHECK: %[[result:.*]] = arith.addf %[[array_element_inner]], %[[cst]] fastmath : f32 +!CHECK: omp.yield(%[[result]] : f32) +!CHECK: } +!CHECK: omp.atomic.read %[[X]] = %[[array_element]] : !fir.ref +!CHECK: } +subroutine array_refs() + real, dimension(5) :: numbers + real :: x + !$omp atomic capture + numbers(1) = numbers(1) + 10 + x = numbers(1) + !$omp end atomic +end subroutine