[flang-commits] [flang] [llvm] [mlir] [Flang][OpenMP][OpenACC] Handle atomic read/capture when lhs and rhs … (PR #93776)

via flang-commits flang-commits at lists.llvm.org
Mon Jun 24 00:50:24 PDT 2024


https://github.com/harishch4 updated https://github.com/llvm/llvm-project/pull/93776

>From ba975743902a6bbcc6e44415d3cdf90b930fcbb1 Mon Sep 17 00:00:00 2001
From: Harish Chambeti <harishcse44 at gmail.com>
Date: Thu, 30 May 2024 12:29:28 +0530
Subject: [PATCH 1/2] [Flang][OpenMP][OpenACC] Handle atomic read/capture when
 lhs and rhs types are different

---
 flang/lib/Lower/DirectivesCommon.h           | 72 +++++++++++++++-----
 flang/test/Lower/OpenACC/acc-atomic-read.f90 |  8 ++-
 flang/test/Lower/OpenMP/atomic-capture.f90   | 30 ++++++++
 flang/test/Lower/OpenMP/atomic-read.f90      | 37 ++++++++++
 4 files changed, 129 insertions(+), 18 deletions(-)

diff --git a/flang/lib/Lower/DirectivesCommon.h b/flang/lib/Lower/DirectivesCommon.h
index 48b090f6d2dbe..d97ae2c5f51f4 100644
--- a/flang/lib/Lower/DirectivesCommon.h
+++ b/flang/lib/Lower/DirectivesCommon.h
@@ -30,6 +30,7 @@
 #include "flang/Lower/StatementContext.h"
 #include "flang/Lower/Support/Utils.h"
 #include "flang/Optimizer/Builder/BoxValue.h"
+#include "flang/Optimizer/Builder/Complex.h"
 #include "flang/Optimizer/Builder/FIRBuilder.h"
 #include "flang/Optimizer/Builder/HLFIRTools.h"
 #include "flang/Optimizer/Builder/Todo.h"
@@ -143,9 +144,24 @@ static inline void genOmpAccAtomicCaptureStatement(
     mlir::Value toAddress,
     [[maybe_unused]] const AtomicListT *leftHandClauseList,
     [[maybe_unused]] const AtomicListT *rightHandClauseList,
-    mlir::Type elementType, mlir::Location loc) {
+    mlir::Type elementType, mlir::Location loc,
+    mlir::Operation *atomicCaptureOp = nullptr) {
   // Generate `atomic.read` operation for atomic assigment statements
   fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
+  mlir::Value oldToAddress = toAddress;
+  if (fromAddress.getType() != oldToAddress.getType()) {
+    auto insertionPoint = firOpBuilder.saveInsertionPoint();
+    if (atomicCaptureOp)
+      firOpBuilder.setInsertionPoint(atomicCaptureOp);
+    auto alloca = firOpBuilder.create<fir::AllocaOp>(loc, elementType);
+    auto declareOp = firOpBuilder.create<hlfir::DeclareOp>(
+        loc, alloca, ".atomic.read.temp", /*shape=*/nullptr,
+        llvm::ArrayRef<mlir::Value>{},
+        /*dummy_scope=*/nullptr, fir::FortranVariableFlagsAttr{});
+    toAddress = declareOp.getBase();
+    if (atomicCaptureOp)
+      firOpBuilder.restoreInsertionPoint(insertionPoint);
+  }
 
   if constexpr (std::is_same<AtomicListT,
                              Fortran::parser::OmpAtomicClauseList>()) {
@@ -167,6 +183,24 @@ static inline void genOmpAccAtomicCaptureStatement(
     firOpBuilder.create<mlir::acc::AtomicReadOp>(
         loc, fromAddress, toAddress, mlir::TypeAttr::get(elementType));
   }
+
+  if (fromAddress.getType() != oldToAddress.getType()) {
+    auto insertionPoint = firOpBuilder.saveInsertionPoint();
+    if (atomicCaptureOp)
+      firOpBuilder.setInsertionPointAfter(atomicCaptureOp);
+    mlir::Value load = firOpBuilder.create<fir::LoadOp>(loc, toAddress);
+    if (auto cmplxTy = mlir::dyn_cast_or_null<fir::ComplexType>(elementType)) {
+      mlir::Value extractValue =
+          fir::factory::Complex{firOpBuilder, loc}.extractComplexPart(load,
+                                                                      false);
+      load = extractValue;
+    }
+    mlir::Value convert = firOpBuilder.create<fir::ConvertOp>(
+        loc, fir::unwrapRefType(oldToAddress.getType()), load);
+    firOpBuilder.create<fir::StoreOp>(loc, convert, oldToAddress);
+    if (atomicCaptureOp)
+      firOpBuilder.restoreInsertionPoint(insertionPoint);
+  }
 }
 
 /// Used to generate atomic.write operation which is created in existing
@@ -408,10 +442,6 @@ void genOmpAccAtomicRead(Fortran::lower::AbstractConverter &converter,
       fir::getBase(converter.genExprAddr(fromExpr, stmtCtx));
   mlir::Value toAddress = fir::getBase(converter.genExprAddr(
       *Fortran::semantics::GetExpr(assignmentStmtVariable), stmtCtx));
-  fir::FirOpBuilder &builder = converter.getFirOpBuilder();
-  if (fromAddress.getType() != toAddress.getType())
-    fromAddress =
-        builder.create<fir::ConvertOp>(loc, toAddress.getType(), fromAddress);
   genOmpAccAtomicCaptureStatement(converter, fromAddress, toAddress,
                                   leftHandClauseList, rightHandClauseList,
                                   elementType, loc);
@@ -481,12 +511,10 @@ void genOmpAccAtomicCapture(Fortran::lower::AbstractConverter &converter,
 
   const Fortran::parser::AssignmentStmt &stmt1 =
       std::get<typename AtomicT::Stmt1>(atomicCapture.t).v.statement;
-  const Fortran::evaluate::Assignment &assign1 = *stmt1.typedAssignment->v;
   const auto &stmt1Var{std::get<Fortran::parser::Variable>(stmt1.t)};
   const auto &stmt1Expr{std::get<Fortran::parser::Expr>(stmt1.t)};
   const Fortran::parser::AssignmentStmt &stmt2 =
       std::get<typename AtomicT::Stmt2>(atomicCapture.t).v.statement;
-  const Fortran::evaluate::Assignment &assign2 = *stmt2.typedAssignment->v;
   const auto &stmt2Var{std::get<Fortran::parser::Variable>(stmt2.t)};
   const auto &stmt2Expr{std::get<Fortran::parser::Expr>(stmt2.t)};
 
@@ -498,25 +526,37 @@ void genOmpAccAtomicCapture(Fortran::lower::AbstractConverter &converter,
   mlir::Value stmt1LHSArg, stmt1RHSArg, stmt2LHSArg, stmt2RHSArg;
   mlir::Type elementType;
   // LHS evaluations are common to all combinations of `atomic.capture`
-  stmt1LHSArg = fir::getBase(converter.genExprAddr(assign1.lhs, stmtCtx));
-  stmt2LHSArg = fir::getBase(converter.genExprAddr(assign2.lhs, stmtCtx));
+  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(assign1.rhs, stmtCtx));
+    stmt1RHSArg = fir::getBase(converter.genExprAddr(
+        *Fortran::semantics::GetExpr(stmt1Expr), stmtCtx));
+    // To handle type convert for atomic write/update.
+    const Fortran::evaluate::Assignment &assign2 = *stmt2.typedAssignment->v;
     stmt2RHSArg = fir::getBase(converter.genExprValue(assign2.rhs, stmtCtx));
   } else {
     // Atomic capture construct is of the form [update-stmt, capture-stmt]
+    // To handle type convert for atomic update.
+    const Fortran::evaluate::Assignment &assign1 = *stmt1.typedAssignment->v;
     stmt1RHSArg = fir::getBase(converter.genExprValue(assign1.rhs, stmtCtx));
-    stmt2RHSArg = fir::getBase(converter.genExprAddr(assign2.lhs, stmtCtx));
+    stmt2RHSArg = fir::getBase(converter.genExprAddr(
+        *Fortran::semantics::GetExpr(stmt2Expr), stmtCtx));
   }
   // Type information used in generation of `atomic.update` operation
   mlir::Type stmt1VarType =
-      fir::getBase(converter.genExprValue(assign1.lhs, stmtCtx)).getType();
+      fir::getBase(converter.genExprValue(
+                       *Fortran::semantics::GetExpr(stmt1Var), stmtCtx))
+          .getType();
   mlir::Type stmt2VarType =
-      fir::getBase(converter.genExprValue(assign2.lhs, stmtCtx)).getType();
+      fir::getBase(converter.genExprValue(
+                       *Fortran::semantics::GetExpr(stmt2Var), stmtCtx))
+          .getType();
 
   mlir::Operation *atomicCaptureOp = nullptr;
   if constexpr (std::is_same<AtomicListT,
@@ -547,7 +587,7 @@ void genOmpAccAtomicCapture(Fortran::lower::AbstractConverter &converter,
       genOmpAccAtomicCaptureStatement<AtomicListT>(
           converter, stmt1RHSArg, stmt1LHSArg,
           /*leftHandClauseList=*/nullptr,
-          /*rightHandClauseList=*/nullptr, elementType, loc);
+          /*rightHandClauseList=*/nullptr, elementType, loc, atomicCaptureOp);
       genOmpAccAtomicUpdateStatement<AtomicListT>(
           converter, stmt1RHSArg, stmt2VarType, stmt2Var, stmt2Expr,
           /*leftHandClauseList=*/nullptr,
@@ -560,7 +600,7 @@ void genOmpAccAtomicCapture(Fortran::lower::AbstractConverter &converter,
       genOmpAccAtomicCaptureStatement<AtomicListT>(
           converter, stmt1RHSArg, stmt1LHSArg,
           /*leftHandClauseList=*/nullptr,
-          /*rightHandClauseList=*/nullptr, elementType, loc);
+          /*rightHandClauseList=*/nullptr, elementType, loc, atomicCaptureOp);
       genOmpAccAtomicWriteStatement<AtomicListT>(
           converter, stmt1RHSArg, stmt2RHSArg,
           /*leftHandClauseList=*/nullptr,
@@ -575,7 +615,7 @@ void genOmpAccAtomicCapture(Fortran::lower::AbstractConverter &converter,
     genOmpAccAtomicCaptureStatement<AtomicListT>(
         converter, stmt1LHSArg, stmt2LHSArg,
         /*leftHandClauseList=*/nullptr,
-        /*rightHandClauseList=*/nullptr, elementType, loc);
+        /*rightHandClauseList=*/nullptr, elementType, loc, atomicCaptureOp);
     firOpBuilder.setInsertionPointToStart(&block);
     genOmpAccAtomicUpdateStatement<AtomicListT>(
         converter, stmt1LHSArg, stmt1VarType, stmt1Var, stmt1Expr,
diff --git a/flang/test/Lower/OpenACC/acc-atomic-read.f90 b/flang/test/Lower/OpenACC/acc-atomic-read.f90
index c1a97a9e5f74f..5c59c86236d4a 100644
--- a/flang/test/Lower/OpenACC/acc-atomic-read.f90
+++ b/flang/test/Lower/OpenACC/acc-atomic-read.f90
@@ -55,5 +55,9 @@ subroutine atomic_read_with_convert()
 ! CHECK: %[[X_DECL:.*]]:2 = hlfir.declare %[[X]] {uniq_name = "_QFatomic_read_with_convertEx"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
 ! CHECK: %[[Y:.*]] = fir.alloca i64 {bindc_name = "y", uniq_name = "_QFatomic_read_with_convertEy"}
 ! CHECK: %[[Y_DECL:.*]]:2 = hlfir.declare %[[Y]] {uniq_name = "_QFatomic_read_with_convertEy"} : (!fir.ref<i64>) -> (!fir.ref<i64>, !fir.ref<i64>)
-! CHECK: %[[CONV:.*]] = fir.convert %[[X_DECL]]#1 : (!fir.ref<i32>) -> !fir.ref<i64>
-! CHECK: acc.atomic.read %[[Y_DECL]]#1 = %[[CONV]] : !fir.ref<i64>, i32
+! CHECK: %[[TEMP:.*]] = fir.alloca i32
+! CHECK: %[[TEMP_DECL:.*]]:2 = hlfir.declare %[[TEMP]] {uniq_name = ".atomic.read.temp"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: acc.atomic.read %[[TEMP_DECL]]#0 = %1#1 : !fir.ref<i32>, i32
+! CHECK: %[[TEMP_LD:.*]] = fir.load %[[TEMP_DECL]]#0 : !fir.ref<i32>
+! CHECK: %[[TEMP_CVT:.*]] = fir.convert %[[TEMP_LD]] : (i32) -> i64
+! CHECK: fir.store %[[TEMP_CVT]] to %[[Y_DECL]]#1 : !fir.ref<i64>
diff --git a/flang/test/Lower/OpenMP/atomic-capture.f90 b/flang/test/Lower/OpenMP/atomic-capture.f90
index 32d8cd7bbf328..6489a560b77b0 100644
--- a/flang/test/Lower/OpenMP/atomic-capture.f90
+++ b/flang/test/Lower/OpenMP/atomic-capture.f90
@@ -97,3 +97,33 @@ subroutine pointers_in_atomic_capture()
         b = a
     !$omp end atomic
 end subroutine
+
+! CHECK-LABEL:   func.func @_QPcapture_with_convert() {
+! CHECK:           %[[VAL_0:.*]] = fir.alloca f32 {bindc_name = "c", uniq_name = "_QFcapture_with_convertEc"}
+! CHECK:           %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFcapture_with_convertEc"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+! CHECK:           %[[VAL_2:.*]] = fir.alloca f64 {bindc_name = "c2", uniq_name = "_QFcapture_with_convertEc2"}
+! CHECK:           %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] {uniq_name = "_QFcapture_with_convertEc2"} : (!fir.ref<f64>) -> (!fir.ref<f64>, !fir.ref<f64>)
+! CHECK:           %[[VAL_4:.*]] = fir.alloca f32
+! CHECK:           %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] {uniq_name = ".atomic.read.temp"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+! CHECK:           %[[VAL_6:.*]] = arith.constant 2.000000e+00 : f32
+! CHECK:           omp.atomic.capture {
+! CHECK:             omp.atomic.read %[[VAL_5]]#0 = %[[VAL_1]]#1 : !fir.ref<f32>, f32
+! CHECK:             omp.atomic.update %[[VAL_1]]#1 : !fir.ref<f32> {
+! CHECK:             ^bb0(%[[VAL_7:.*]]: f32):
+! CHECK:               %[[VAL_8:.*]] = arith.mulf %[[VAL_6]], %[[VAL_7]] fastmath<contract> : f32
+! CHECK:               omp.yield(%[[VAL_8]] : f32)
+! CHECK:             }
+! CHECK:           }
+! CHECK:           %[[VAL_9:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref<f32>
+! CHECK:           %[[VAL_10:.*]] = fir.convert %[[VAL_9]] : (f32) -> f64
+! CHECK:           fir.store %[[VAL_10]] to %[[VAL_3]]#1 : !fir.ref<f64>
+! CHECK:           return
+! CHECK:         }
+subroutine capture_with_convert()
+    real :: c
+    double precision :: c2
+!$omp atomic capture
+    c2 = c
+    c = 2.0 * c
+!$omp end atomic
+end
diff --git a/flang/test/Lower/OpenMP/atomic-read.f90 b/flang/test/Lower/OpenMP/atomic-read.f90
index 8c3f37c94975e..940c0d61d91ca 100644
--- a/flang/test/Lower/OpenMP/atomic-read.f90
+++ b/flang/test/Lower/OpenMP/atomic-read.f90
@@ -89,3 +89,40 @@ subroutine atomic_read_pointer()
   x = y
 end
 
+! CHECK-LABEL:   func.func @_QPread_with_convert() {
+! CHECK:           %[[VAL_0:.*]] = fir.alloca f32 {bindc_name = "a", uniq_name = "_QFread_with_convertEa"}
+! CHECK:           %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFread_with_convertEa"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+! CHECK:           %[[VAL_2:.*]] = fir.alloca i32 {bindc_name = "b", uniq_name = "_QFread_with_convertEb"}
+! CHECK:           %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] {uniq_name = "_QFread_with_convertEb"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK:           %[[VAL_4:.*]] = fir.alloca i32
+! CHECK:           %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] {uniq_name = ".atomic.read.temp"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK:           omp.atomic.read %[[VAL_5]]#0 = %[[VAL_3]]#1 : !fir.ref<i32>, i32
+! CHECK:           %[[VAL_6:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref<i32>
+! CHECK:           %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : (i32) -> f32
+! CHECK:           fir.store %[[VAL_7]] to %[[VAL_1]]#1 : !fir.ref<f32>
+subroutine read_with_convert()
+   real :: a
+   integer :: b
+   !$omp atomic read
+   a = b
+end
+
+! CHECK-LABEL:   func.func @_QPread_complex_with_convert() {
+! CHECK:           %[[VAL_0:.*]] = fir.alloca f32 {bindc_name = "s_v_r2", uniq_name = "_QFread_complex_with_convertEs_v_r2"}
+! CHECK:           %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFread_complex_with_convertEs_v_r2"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+! CHECK:           %[[VAL_2:.*]] = fir.alloca !fir.complex<4> {bindc_name = "s_x_c2", uniq_name = "_QFread_complex_with_convertEs_x_c2"}
+! CHECK:           %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] {uniq_name = "_QFread_complex_with_convertEs_x_c2"} : (!fir.ref<!fir.complex<4>>) -> (!fir.ref<!fir.complex<4>>, !fir.ref<!fir.complex<4>>)
+! CHECK:           %[[VAL_4:.*]] = fir.alloca !fir.complex<4>
+! CHECK:           %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] {uniq_name = ".atomic.read.temp"} : (!fir.ref<!fir.complex<4>>) -> (!fir.ref<!fir.complex<4>>, !fir.ref<!fir.complex<4>>)
+! CHECK:           omp.atomic.read %[[VAL_5]]#0 = %[[VAL_3]]#1 : !fir.ref<!fir.complex<4>>, !fir.complex<4>
+! CHECK:           %[[VAL_6:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref<!fir.complex<4>>
+! CHECK:           %[[VAL_7:.*]] = fir.extract_value %[[VAL_6]], [0 : index] : (!fir.complex<4>) -> f32
+! CHECK:           %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (f32) -> f32
+! CHECK:           fir.store %[[VAL_8]] to %[[VAL_1]]#1 : !fir.ref<f32>
+subroutine read_complex_with_convert()
+   real(kind=4)    :: s_v_r2
+   complex(kind=4) :: s_x_c2
+ !$omp atomic read
+    s_v_r2 = s_x_c2
+ !$omp end atomic
+end

>From 6cb96b45c48fa2534fb7cc0128c8014380c2c778 Mon Sep 17 00:00:00 2001
From: Harish Chambeti <harishcse44 at gmail.com>
Date: Mon, 24 Jun 2024 13:20:07 +0530
Subject: [PATCH 2/2] Handle atomic read/write type convert in OMPIRbBuilder

---
 flang/lib/Lower/DirectivesCommon.h            | 30 ++----------
 flang/test/Lower/OpenACC/acc-atomic-read.f90  | 20 ++++----
 flang/test/Lower/OpenMP/atomic-capture.f90    | 46 +++++++++----------
 flang/test/Lower/OpenMP/atomic-read.f90       | 43 +++++++----------
 llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp     | 17 +++++++
 .../OpenMP/OpenMPToLLVMIRTranslation.cpp      | 22 +++++++--
 mlir/test/Target/LLVMIR/openmp-llvm.mlir      | 43 +++++++++++++++++
 7 files changed, 128 insertions(+), 93 deletions(-)

diff --git a/flang/lib/Lower/DirectivesCommon.h b/flang/lib/Lower/DirectivesCommon.h
index d97ae2c5f51f4..70d4acb3e2da2 100644
--- a/flang/lib/Lower/DirectivesCommon.h
+++ b/flang/lib/Lower/DirectivesCommon.h
@@ -148,17 +148,13 @@ static inline void genOmpAccAtomicCaptureStatement(
     mlir::Operation *atomicCaptureOp = nullptr) {
   // Generate `atomic.read` operation for atomic assigment statements
   fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
-  mlir::Value oldToAddress = toAddress;
-  if (fromAddress.getType() != oldToAddress.getType()) {
+  mlir::Type fromTy = fromAddress.getType();
+  mlir::Type toTy = toAddress.getType();
+  if (fromTy != toTy) {
     auto insertionPoint = firOpBuilder.saveInsertionPoint();
     if (atomicCaptureOp)
       firOpBuilder.setInsertionPoint(atomicCaptureOp);
-    auto alloca = firOpBuilder.create<fir::AllocaOp>(loc, elementType);
-    auto declareOp = firOpBuilder.create<hlfir::DeclareOp>(
-        loc, alloca, ".atomic.read.temp", /*shape=*/nullptr,
-        llvm::ArrayRef<mlir::Value>{},
-        /*dummy_scope=*/nullptr, fir::FortranVariableFlagsAttr{});
-    toAddress = declareOp.getBase();
+    toAddress = firOpBuilder.create<fir::ConvertOp>(loc, fromTy, toAddress);
     if (atomicCaptureOp)
       firOpBuilder.restoreInsertionPoint(insertionPoint);
   }
@@ -183,24 +179,6 @@ static inline void genOmpAccAtomicCaptureStatement(
     firOpBuilder.create<mlir::acc::AtomicReadOp>(
         loc, fromAddress, toAddress, mlir::TypeAttr::get(elementType));
   }
-
-  if (fromAddress.getType() != oldToAddress.getType()) {
-    auto insertionPoint = firOpBuilder.saveInsertionPoint();
-    if (atomicCaptureOp)
-      firOpBuilder.setInsertionPointAfter(atomicCaptureOp);
-    mlir::Value load = firOpBuilder.create<fir::LoadOp>(loc, toAddress);
-    if (auto cmplxTy = mlir::dyn_cast_or_null<fir::ComplexType>(elementType)) {
-      mlir::Value extractValue =
-          fir::factory::Complex{firOpBuilder, loc}.extractComplexPart(load,
-                                                                      false);
-      load = extractValue;
-    }
-    mlir::Value convert = firOpBuilder.create<fir::ConvertOp>(
-        loc, fir::unwrapRefType(oldToAddress.getType()), load);
-    firOpBuilder.create<fir::StoreOp>(loc, convert, oldToAddress);
-    if (atomicCaptureOp)
-      firOpBuilder.restoreInsertionPoint(insertionPoint);
-  }
 }
 
 /// Used to generate atomic.write operation which is created in existing
diff --git a/flang/test/Lower/OpenACC/acc-atomic-read.f90 b/flang/test/Lower/OpenACC/acc-atomic-read.f90
index 5c59c86236d4a..5b9f9a9e84e3b 100644
--- a/flang/test/Lower/OpenACC/acc-atomic-read.f90
+++ b/flang/test/Lower/OpenACC/acc-atomic-read.f90
@@ -50,14 +50,12 @@ subroutine atomic_read_with_convert()
   y = x
 end
 
-! CHECK-LABEL: func.func @_QPatomic_read_with_convert() {
-! CHECK: %[[X:.*]] = fir.alloca i32 {bindc_name = "x", uniq_name = "_QFatomic_read_with_convertEx"}
-! CHECK: %[[X_DECL:.*]]:2 = hlfir.declare %[[X]] {uniq_name = "_QFatomic_read_with_convertEx"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
-! CHECK: %[[Y:.*]] = fir.alloca i64 {bindc_name = "y", uniq_name = "_QFatomic_read_with_convertEy"}
-! CHECK: %[[Y_DECL:.*]]:2 = hlfir.declare %[[Y]] {uniq_name = "_QFatomic_read_with_convertEy"} : (!fir.ref<i64>) -> (!fir.ref<i64>, !fir.ref<i64>)
-! CHECK: %[[TEMP:.*]] = fir.alloca i32
-! CHECK: %[[TEMP_DECL:.*]]:2 = hlfir.declare %[[TEMP]] {uniq_name = ".atomic.read.temp"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
-! CHECK: acc.atomic.read %[[TEMP_DECL]]#0 = %1#1 : !fir.ref<i32>, i32
-! CHECK: %[[TEMP_LD:.*]] = fir.load %[[TEMP_DECL]]#0 : !fir.ref<i32>
-! CHECK: %[[TEMP_CVT:.*]] = fir.convert %[[TEMP_LD]] : (i32) -> i64
-! CHECK: fir.store %[[TEMP_CVT]] to %[[Y_DECL]]#1 : !fir.ref<i64>
+!CHECK-LABEL: func.func @_QPatomic_read_with_convert() {
+!CHECK:   %[[X:.*]] = fir.alloca i32 {bindc_name = "x", uniq_name = "_QFatomic_read_with_convertEx"}
+!CHECK:   %[[X_DECL:.*]]:2 = hlfir.declare %[[X]] {uniq_name = "_QFatomic_read_with_convertEx"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK:   %[[Y:.*]] = fir.alloca i64 {bindc_name = "y", uniq_name = "_QFatomic_read_with_convertEy"}
+!CHECK:   %[[Y_DECL:.*]]:2 = hlfir.declare %[[Y]] {uniq_name = "_QFatomic_read_with_convertEy"} : (!fir.ref<i64>) -> (!fir.ref<i64>, !fir.ref<i64>)
+!CHECK:   %[[CVT:.*]] = fir.convert %[[Y_DECL]]#1 : (!fir.ref<i64>) -> !fir.ref<i32>
+!CHECK:   acc.atomic.read %[[CVT:.*]] = %[[X_DECL]]#1 : !fir.ref<i32>, i32
+!CHECK:   return
+!CHECK: }
diff --git a/flang/test/Lower/OpenMP/atomic-capture.f90 b/flang/test/Lower/OpenMP/atomic-capture.f90
index 6489a560b77b0..29488f0c4c044 100644
--- a/flang/test/Lower/OpenMP/atomic-capture.f90
+++ b/flang/test/Lower/OpenMP/atomic-capture.f90
@@ -98,32 +98,28 @@ subroutine pointers_in_atomic_capture()
     !$omp end atomic
 end subroutine
 
-! CHECK-LABEL:   func.func @_QPcapture_with_convert() {
-! CHECK:           %[[VAL_0:.*]] = fir.alloca f32 {bindc_name = "c", uniq_name = "_QFcapture_with_convertEc"}
-! CHECK:           %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFcapture_with_convertEc"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
-! CHECK:           %[[VAL_2:.*]] = fir.alloca f64 {bindc_name = "c2", uniq_name = "_QFcapture_with_convertEc2"}
-! CHECK:           %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] {uniq_name = "_QFcapture_with_convertEc2"} : (!fir.ref<f64>) -> (!fir.ref<f64>, !fir.ref<f64>)
-! CHECK:           %[[VAL_4:.*]] = fir.alloca f32
-! CHECK:           %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] {uniq_name = ".atomic.read.temp"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
-! CHECK:           %[[VAL_6:.*]] = arith.constant 2.000000e+00 : f32
-! CHECK:           omp.atomic.capture {
-! CHECK:             omp.atomic.read %[[VAL_5]]#0 = %[[VAL_1]]#1 : !fir.ref<f32>, f32
-! CHECK:             omp.atomic.update %[[VAL_1]]#1 : !fir.ref<f32> {
-! CHECK:             ^bb0(%[[VAL_7:.*]]: f32):
-! CHECK:               %[[VAL_8:.*]] = arith.mulf %[[VAL_6]], %[[VAL_7]] fastmath<contract> : f32
-! CHECK:               omp.yield(%[[VAL_8]] : f32)
-! CHECK:             }
-! CHECK:           }
-! CHECK:           %[[VAL_9:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref<f32>
-! CHECK:           %[[VAL_10:.*]] = fir.convert %[[VAL_9]] : (f32) -> f64
-! CHECK:           fir.store %[[VAL_10]] to %[[VAL_3]]#1 : !fir.ref<f64>
-! CHECK:           return
-! CHECK:         }
+!CHECK-LABEL: func.func @_QPcapture_with_convert() {
+!CHECK:   %[[A:.*]] = fir.alloca f32 {bindc_name = "a", uniq_name = "_QFcapture_with_convertEa"}
+!CHECK:   %[[A_DECL:.*]]:2 = hlfir.declare %[[A]] {uniq_name = "_QFcapture_with_convertEa"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+!CHECK:   %[[B:.*]] = fir.alloca f64 {bindc_name = "b", uniq_name = "_QFcapture_with_convertEb"}
+!CHECK:   %[[B_DECL:.*]]:2 = hlfir.declare %[[B]] {uniq_name = "_QFcapture_with_convertEb"} : (!fir.ref<f64>) -> (!fir.ref<f64>, !fir.ref<f64>)
+!CHECK:   %[[CVT:.*]] = fir.convert %[[B_DECL]]#1 : (!fir.ref<f64>) -> !fir.ref<f32>
+!CHECK:   %[[CST:.*]] = arith.constant 2.000000e+00 : f32
+!CHECK:   omp.atomic.capture {
+!CHECK:     omp.atomic.read %[[CVT:.*]] = %[[A_DECL]]#1 : !fir.ref<f32>, f32
+!CHECK:     omp.atomic.update %[[A_DECL]]#1 : !fir.ref<f32> {
+!CHECK:     ^bb0(%arg0: f32):
+!CHECK:       %[[RES:.*]] = arith.mulf %[[CST]], %arg0 fastmath<contract> : f32
+!CHECK:       omp.yield(%[[RES]] : f32)
+!CHECK:     }
+!CHECK:   }
+!CHECK:   return
+!CHECK: }
 subroutine capture_with_convert()
-    real :: c
-    double precision :: c2
+    real :: A
+    double precision :: B
 !$omp atomic capture
-    c2 = c
-    c = 2.0 * c
+    B = A
+    A = 2.0 * A
 !$omp end atomic
 end
diff --git a/flang/test/Lower/OpenMP/atomic-read.f90 b/flang/test/Lower/OpenMP/atomic-read.f90
index 940c0d61d91ca..bc29683f46abd 100644
--- a/flang/test/Lower/OpenMP/atomic-read.f90
+++ b/flang/test/Lower/OpenMP/atomic-read.f90
@@ -89,17 +89,13 @@ subroutine atomic_read_pointer()
   x = y
 end
 
-! CHECK-LABEL:   func.func @_QPread_with_convert() {
-! CHECK:           %[[VAL_0:.*]] = fir.alloca f32 {bindc_name = "a", uniq_name = "_QFread_with_convertEa"}
-! CHECK:           %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFread_with_convertEa"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
-! CHECK:           %[[VAL_2:.*]] = fir.alloca i32 {bindc_name = "b", uniq_name = "_QFread_with_convertEb"}
-! CHECK:           %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] {uniq_name = "_QFread_with_convertEb"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
-! CHECK:           %[[VAL_4:.*]] = fir.alloca i32
-! CHECK:           %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] {uniq_name = ".atomic.read.temp"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
-! CHECK:           omp.atomic.read %[[VAL_5]]#0 = %[[VAL_3]]#1 : !fir.ref<i32>, i32
-! CHECK:           %[[VAL_6:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref<i32>
-! CHECK:           %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : (i32) -> f32
-! CHECK:           fir.store %[[VAL_7]] to %[[VAL_1]]#1 : !fir.ref<f32>
+!CHECK-LABEL: func.func @_QPread_with_convert() {
+!CHECK:   %[[A:.*]] = fir.alloca f32 {bindc_name = "a", uniq_name = "_QFread_with_convertEa"}
+!CHECK:   %[[A_DECL]]:2 = hlfir.declare %[[A]] {uniq_name = "_QFread_with_convertEa"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+!CHECK:   %[[B:.*]] = fir.alloca i32 {bindc_name = "b", uniq_name = "_QFread_with_convertEb"}
+!CHECK:   %[[B_DECL]]:2 = hlfir.declare %[[B]] {uniq_name = "_QFread_with_convertEb"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK:   %[[CVT:.*]] = fir.convert %[[A_DECL]]#1 : (!fir.ref<f32>) -> !fir.ref<i32>
+!CHECK:   omp.atomic.read %[[CVT:.*]] = %[[B_DECL]]#1 : !fir.ref<i32>, i32
 subroutine read_with_convert()
    real :: a
    integer :: b
@@ -107,22 +103,17 @@ subroutine read_with_convert()
    a = b
 end
 
-! CHECK-LABEL:   func.func @_QPread_complex_with_convert() {
-! CHECK:           %[[VAL_0:.*]] = fir.alloca f32 {bindc_name = "s_v_r2", uniq_name = "_QFread_complex_with_convertEs_v_r2"}
-! CHECK:           %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFread_complex_with_convertEs_v_r2"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
-! CHECK:           %[[VAL_2:.*]] = fir.alloca !fir.complex<4> {bindc_name = "s_x_c2", uniq_name = "_QFread_complex_with_convertEs_x_c2"}
-! CHECK:           %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] {uniq_name = "_QFread_complex_with_convertEs_x_c2"} : (!fir.ref<!fir.complex<4>>) -> (!fir.ref<!fir.complex<4>>, !fir.ref<!fir.complex<4>>)
-! CHECK:           %[[VAL_4:.*]] = fir.alloca !fir.complex<4>
-! CHECK:           %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] {uniq_name = ".atomic.read.temp"} : (!fir.ref<!fir.complex<4>>) -> (!fir.ref<!fir.complex<4>>, !fir.ref<!fir.complex<4>>)
-! CHECK:           omp.atomic.read %[[VAL_5]]#0 = %[[VAL_3]]#1 : !fir.ref<!fir.complex<4>>, !fir.complex<4>
-! CHECK:           %[[VAL_6:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref<!fir.complex<4>>
-! CHECK:           %[[VAL_7:.*]] = fir.extract_value %[[VAL_6]], [0 : index] : (!fir.complex<4>) -> f32
-! CHECK:           %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (f32) -> f32
-! CHECK:           fir.store %[[VAL_8]] to %[[VAL_1]]#1 : !fir.ref<f32>
+!CHECK-LABEL: func.func @_QPread_complex_with_convert() {
+!CHECK:   %[[A:.*]] = fir.alloca f32 {bindc_name = "a", uniq_name = "_QFread_complex_with_convertEa"}
+!CHECK:   %[[A_DECL]]:2 = hlfir.declare %[[A]] {uniq_name = "_QFread_complex_with_convertEa"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+!CHECK:   %[[B:.*]] = fir.alloca !fir.complex<4> {bindc_name = "b", uniq_name = "_QFread_complex_with_convertEb"}
+!CHECK:   %[[B_DECL]]:2 = hlfir.declare %[[B]] {uniq_name = "_QFread_complex_with_convertEb"} : (!fir.ref<!fir.complex<4>>) -> (!fir.ref<!fir.complex<4>>, !fir.ref<!fir.complex<4>>)
+!CHECK:   %[[CVT:.*]] = fir.convert %[[A_DECL]]#1 : (!fir.ref<f32>) -> !fir.ref<!fir.complex<4>>
+!CHECK:   omp.atomic.read %[[CVT:.*]] = %[[B_DECL]]#1 : !fir.ref<!fir.complex<4>>, !fir.complex<4>
 subroutine read_complex_with_convert()
-   real(kind=4)    :: s_v_r2
-   complex(kind=4) :: s_x_c2
+   real(kind=4)    :: A
+   complex(kind=4) :: B
  !$omp atomic read
-    s_v_r2 = s_x_c2
+    A = B
  !$omp end atomic
 end
diff --git a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
index cb4de9c8876dc..04ab6baffcaa0 100644
--- a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
+++ b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
@@ -5879,6 +5879,20 @@ bool OpenMPIRBuilder::checkAndEmitFlushAfterAtomic(
   return Flush;
 }
 
+static void convertLLVMType(Value *&Val, Type *dstTy, IRBuilderBase &Builder) {
+  Type *srcTy = Val->getType();
+  if (srcTy != dstTy) {
+    if (dstTy->isIntegerTy() && srcTy->isFloatingPointTy())
+      Val = Builder.CreateFPToSI(Val, dstTy);
+    else if (dstTy->isFloatingPointTy() && srcTy->isIntegerTy())
+      Val = Builder.CreateSIToFP(Val, dstTy);
+    else if (dstTy->isFloatingPointTy() && srcTy->isFloatingPointTy())
+      Val = Builder.CreateFPCast(Val, dstTy);
+    else if (dstTy->isIntegerTy() && srcTy->isIntegerTy())
+      Val = Builder.CreateIntCast(Val, dstTy, true);
+  }
+}
+
 OpenMPIRBuilder::InsertPointTy
 OpenMPIRBuilder::createAtomicRead(const LocationDescription &Loc,
                                   AtomicOpValue &X, AtomicOpValue &V,
@@ -5889,6 +5903,7 @@ OpenMPIRBuilder::createAtomicRead(const LocationDescription &Loc,
   assert(X.Var->getType()->isPointerTy() &&
          "OMP Atomic expects a pointer to target memory");
   Type *XElemTy = X.ElemTy;
+  Type *VElemTy = V.ElemTy;
   assert((XElemTy->isFloatingPointTy() || XElemTy->isIntegerTy() ||
           XElemTy->isPointerTy()) &&
          "OMP atomic read expected a scalar type");
@@ -5913,6 +5928,7 @@ OpenMPIRBuilder::createAtomicRead(const LocationDescription &Loc,
       XRead = Builder.CreateIntToPtr(XLoad, XElemTy, "atomic.ptr.cast");
     }
   }
+  convertLLVMType(XRead, VElemTy, Builder);
   checkAndEmitFlushAfterAtomic(Loc, AO, AtomicKind::Read);
   Builder.CreateStore(XRead, V.Var, V.IsVolatile);
   return Builder.saveIP();
@@ -6137,6 +6153,7 @@ OpenMPIRBuilder::InsertPointTy OpenMPIRBuilder::createAtomicCapture(
                        X.IsVolatile, IsXBinopExpr);
 
   Value *CapturedVal = (IsPostfixUpdate ? Result.first : Result.second);
+  convertLLVMType(CapturedVal, V.ElemTy, Builder);
   Builder.CreateStore(CapturedVal, V.Var, V.IsVolatile);
 
   checkAndEmitFlushAfterAtomic(Loc, AO, AtomicKind::Capture);
diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
index 6ec4c120c11ea..e974370f6e03d 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -1529,11 +1529,17 @@ convertOmpAtomicRead(Operation &opInst, llvm::IRBuilderBase &builder,
   llvm::Value *x = moduleTranslation.lookupValue(readOp.getX());
   llvm::Value *v = moduleTranslation.lookupValue(readOp.getV());
 
-  llvm::Type *elementType =
-      moduleTranslation.convertType(readOp.getElementType());
+  llvm::Type *xTy = nullptr;
+  llvm::Type *vTy = nullptr;
+  xTy = moduleTranslation.convertType(readOp.getElementType());
 
-  llvm::OpenMPIRBuilder::AtomicOpValue V = {v, elementType, false, false};
-  llvm::OpenMPIRBuilder::AtomicOpValue X = {x, elementType, false, false};
+  if (llvm::AllocaInst *vAlloca = dyn_cast<llvm::AllocaInst>(v)) {
+    vTy = vAlloca->getAllocatedType();
+  } else {
+    vTy = v->getType();
+  }
+  llvm::OpenMPIRBuilder::AtomicOpValue V = {v, vTy, false, false};
+  llvm::OpenMPIRBuilder::AtomicOpValue X = {x, xTy, false, false};
   builder.restoreIP(ompBuilder->createAtomicRead(ompLoc, X, V, AO));
   return success();
 }
@@ -1698,10 +1704,16 @@ convertOmpAtomicCapture(omp::AtomicCaptureOp atomicCaptureOp,
       moduleTranslation.lookupValue(atomicCaptureOp.getAtomicReadOp().getV());
   llvm::Type *llvmXElementType = moduleTranslation.convertType(
       atomicCaptureOp.getAtomicReadOp().getElementType());
+  llvm::Type *llvmVElementType = nullptr;
+  if (llvm::AllocaInst *vAlloca = dyn_cast<llvm::AllocaInst>(llvmV)) {
+    llvmVElementType = vAlloca->getAllocatedType();
+  } else {
+    llvmVElementType = llvmV->getType();
+  }
   llvm::OpenMPIRBuilder::AtomicOpValue llvmAtomicX = {llvmX, llvmXElementType,
                                                       /*isSigned=*/false,
                                                       /*isVolatile=*/false};
-  llvm::OpenMPIRBuilder::AtomicOpValue llvmAtomicV = {llvmV, llvmXElementType,
+  llvm::OpenMPIRBuilder::AtomicOpValue llvmAtomicV = {llvmV, llvmVElementType,
                                                       /*isSigned=*/false,
                                                       /*isVolatile=*/false};
 
diff --git a/mlir/test/Target/LLVMIR/openmp-llvm.mlir b/mlir/test/Target/LLVMIR/openmp-llvm.mlir
index 8654899efefd2..47b7c7b50cfa7 100644
--- a/mlir/test/Target/LLVMIR/openmp-llvm.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-llvm.mlir
@@ -1359,6 +1359,23 @@ llvm.func @omp_atomic_read(%arg0 : !llvm.ptr, %arg1 : !llvm.ptr) -> () {
   llvm.return
 }
 
+// -----
+// CHECK-LABEL: @atomic_read_type_convert
+llvm.func @atomic_read_type_convert() {
+  // CHECK: %[[X:.*]] = alloca float, i64 1, align 4
+  %0 = llvm.mlir.constant(1 : i64) : i64
+  %1 = llvm.alloca %0 x f32 {bindc_name = "r"} : (i64) -> !llvm.ptr
+  // CHECK: %[[V:.*]] = alloca i32, i64 1, align 4
+  %2 = llvm.mlir.constant(1 : i64) : i64
+  %3 = llvm.alloca %2 x i32 {bindc_name = "i"} : (i64) -> !llvm.ptr
+  // CHECK: %[[X_LD:.*]] = load atomic i32, ptr %[[X]] monotonic, align 4
+  // CHECK: %[[X_VAL:.*]] = bitcast i32 %[[X_LD]] to float
+  // CHECK: %[[X_CVT:.*]] = fptosi float %[[X_VAL]] to i32
+  // CHECK: store i32 %[[X_CVT]], ptr %[[V]], align 4
+  omp.atomic.read %3 = %1 : !llvm.ptr, f32
+  llvm.return
+}
+
 // -----
 
 // CHECK-LABEL: @omp_atomic_write
@@ -2066,6 +2083,32 @@ llvm.func @omp_atomic_capture_misc(
   llvm.return
 }
 
+// -----
+// CHECK-LABEL: @atomic_capture_type_convert
+llvm.func @atomic_capture_type_convert() {
+    // CHECK: %[[V:.*]] = alloca double, i64 1, align 8
+    %0 = llvm.mlir.constant(1 : i64) : i64
+    %1 = llvm.alloca %0 x f64 {bindc_name = "c2"} : (i64) -> !llvm.ptr
+    %2 = llvm.mlir.constant(1 : i64) : i64
+    // CHECK: %[[X:.*]] = alloca float, i64 1, align 4
+    %3 = llvm.alloca %2 x f32 {bindc_name = "c"} : (i64) -> !llvm.ptr
+    %4 = llvm.mlir.constant(2.000000e+00 : f32) : f32
+    omp.atomic.capture {
+        // CHECK: %[[AT_LOAD_VAL:.*]] = load atomic i32, ptr %[[X]] monotonic, align 4
+        // CHECK: %[[LOAD_VAL_PHI:.*]] = phi i32 [ %[[AT_LOAD_VAL]], %entry ], [ %{{.*}}, %.atomic.cont ]
+        // CHECK: %[[X_VAL:.*]] = bitcast i32 %[[LOAD_VAL_PHI]] to float
+        // CHECK: %[[CVT:.*]] = fpext float %[[X_VAL]] to double
+        // CHECK: store double %[[CVT]], ptr %[[V]], align 8
+        omp.atomic.read %1 = %3 : !llvm.ptr, f32
+        omp.atomic.update %3 : !llvm.ptr {
+        ^bb0(%arg0: f32):
+        %5 = llvm.fmul %arg0, %4  {fastmathFlags = #llvm.fastmath<contract>} : f32
+        omp.yield(%5 : f32)
+        }
+    }
+    llvm.return
+}
+
 // -----
 
 // CHECK-LABEL: @omp_sections_empty



More information about the flang-commits mailing list