[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