Skip to content

Commit 00c511b

Browse files
Added lowering support for atomic read and write constructs
This patch adds lowering support for atomic read and write constructs. Also added is pointer modelling code to allow FIR pointer like types to be inferred and converted while lowering. Reviewed By: kiranchandramohan Differential Revision: https://reviews.llvm.org/D122725 Co-authored-by: Kiran Chandramohan <kiran.chandramohan@arm.com>
1 parent b02d88d commit 00c511b

File tree

8 files changed

+361
-9
lines changed

8 files changed

+361
-9
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//===-- Tools/PointerModels.h --------------------- *-C++-*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef FORTRAN_TOOLS_POINTER_MODELS_H
10+
#define FORTRAN_TOOLS_POINTER_MODELS_H
11+
12+
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
13+
14+
/// models for FIR pointer like types that already provide a `getElementType` or
15+
/// a `getEleTy` method
16+
17+
template <typename T>
18+
struct PointerLikeModel
19+
: public mlir::omp::PointerLikeType::ExternalModel<PointerLikeModel<T>, T> {
20+
mlir::Type getElementType(mlir::Type pointer) const {
21+
return pointer.cast<T>().getElementType();
22+
}
23+
};
24+
25+
template <typename T>
26+
struct AlternativePointerLikeModel
27+
: public mlir::omp::PointerLikeType::ExternalModel<
28+
AlternativePointerLikeModel<T>, T> {
29+
mlir::Type getElementType(mlir::Type pointer) const {
30+
return pointer.cast<T>().getEleTy();
31+
}
32+
};
33+
34+
#endif // FORTRAN_TOOLS_POINTER_MODELS_H

flang/lib/Lower/OpenMP.cpp

Lines changed: 140 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,145 @@ genOMP(Fortran::lower::AbstractConverter &converter,
452452
}
453453
}
454454

455+
static void genOmpAtomicHintAndMemoryOrderClauses(
456+
Fortran::lower::AbstractConverter &converter,
457+
const Fortran::parser::OmpAtomicClauseList &clauseList,
458+
mlir::IntegerAttr &hint,
459+
mlir::omp::ClauseMemoryOrderKindAttr &memory_order) {
460+
auto &firOpBuilder = converter.getFirOpBuilder();
461+
for (const auto &clause : clauseList.v) {
462+
if (auto ompClause = std::get_if<Fortran::parser::OmpClause>(&clause.u)) {
463+
if (auto hintClause =
464+
std::get_if<Fortran::parser::OmpClause::Hint>(&ompClause->u)) {
465+
const auto *expr = Fortran::semantics::GetExpr(hintClause->v);
466+
uint64_t hintExprValue = *Fortran::evaluate::ToInt64(*expr);
467+
hint = firOpBuilder.getI64IntegerAttr(hintExprValue);
468+
}
469+
} else if (auto ompMemoryOrderClause =
470+
std::get_if<Fortran::parser::OmpMemoryOrderClause>(
471+
&clause.u)) {
472+
if (std::get_if<Fortran::parser::OmpClause::Acquire>(
473+
&ompMemoryOrderClause->v.u)) {
474+
memory_order = mlir::omp::ClauseMemoryOrderKindAttr::get(
475+
firOpBuilder.getContext(), omp::ClauseMemoryOrderKind::Acquire);
476+
} else if (std::get_if<Fortran::parser::OmpClause::Relaxed>(
477+
&ompMemoryOrderClause->v.u)) {
478+
memory_order = mlir::omp::ClauseMemoryOrderKindAttr::get(
479+
firOpBuilder.getContext(), omp::ClauseMemoryOrderKind::Relaxed);
480+
} else if (std::get_if<Fortran::parser::OmpClause::SeqCst>(
481+
&ompMemoryOrderClause->v.u)) {
482+
memory_order = mlir::omp::ClauseMemoryOrderKindAttr::get(
483+
firOpBuilder.getContext(), omp::ClauseMemoryOrderKind::Seq_cst);
484+
} else if (std::get_if<Fortran::parser::OmpClause::Release>(
485+
&ompMemoryOrderClause->v.u)) {
486+
memory_order = mlir::omp::ClauseMemoryOrderKindAttr::get(
487+
firOpBuilder.getContext(), omp::ClauseMemoryOrderKind::Release);
488+
}
489+
}
490+
}
491+
}
492+
493+
static void
494+
genOmpAtomicWrite(Fortran::lower::AbstractConverter &converter,
495+
Fortran::lower::pft::Evaluation &eval,
496+
const Fortran::parser::OmpAtomicWrite &atomicWrite) {
497+
auto &firOpBuilder = converter.getFirOpBuilder();
498+
auto currentLocation = converter.getCurrentLocation();
499+
mlir::Value address;
500+
// If no hint clause is specified, the effect is as if
501+
// hint(omp_sync_hint_none) had been specified.
502+
mlir::IntegerAttr hint = nullptr;
503+
mlir::omp::ClauseMemoryOrderKindAttr memory_order = nullptr;
504+
const Fortran::parser::OmpAtomicClauseList &rightHandClauseList =
505+
std::get<2>(atomicWrite.t);
506+
const Fortran::parser::OmpAtomicClauseList &leftHandClauseList =
507+
std::get<0>(atomicWrite.t);
508+
const auto &assignmentStmtExpr =
509+
std::get<Fortran::parser::Expr>(std::get<3>(atomicWrite.t).statement.t);
510+
const auto &assignmentStmtVariable = std::get<Fortran::parser::Variable>(
511+
std::get<3>(atomicWrite.t).statement.t);
512+
Fortran::lower::StatementContext stmtCtx;
513+
auto value = fir::getBase(converter.genExprValue(
514+
*Fortran::semantics::GetExpr(assignmentStmtExpr), stmtCtx));
515+
if (auto varDesignator = std::get_if<
516+
Fortran::common::Indirection<Fortran::parser::Designator>>(
517+
&assignmentStmtVariable.u)) {
518+
if (const auto *name = getDesignatorNameIfDataRef(varDesignator->value())) {
519+
address = converter.getSymbolAddress(*name->symbol);
520+
}
521+
}
522+
523+
genOmpAtomicHintAndMemoryOrderClauses(converter, leftHandClauseList, hint,
524+
memory_order);
525+
genOmpAtomicHintAndMemoryOrderClauses(converter, rightHandClauseList, hint,
526+
memory_order);
527+
firOpBuilder.create<mlir::omp::AtomicWriteOp>(currentLocation, address, value,
528+
hint, memory_order);
529+
}
530+
531+
static void genOmpAtomicRead(Fortran::lower::AbstractConverter &converter,
532+
Fortran::lower::pft::Evaluation &eval,
533+
const Fortran::parser::OmpAtomicRead &atomicRead) {
534+
auto &firOpBuilder = converter.getFirOpBuilder();
535+
auto currentLocation = converter.getCurrentLocation();
536+
mlir::Value to_address;
537+
mlir::Value from_address;
538+
// If no hint clause is specified, the effect is as if
539+
// hint(omp_sync_hint_none) had been specified.
540+
mlir::IntegerAttr hint = nullptr;
541+
mlir::omp::ClauseMemoryOrderKindAttr memory_order = nullptr;
542+
const Fortran::parser::OmpAtomicClauseList &rightHandClauseList =
543+
std::get<2>(atomicRead.t);
544+
const Fortran::parser::OmpAtomicClauseList &leftHandClauseList =
545+
std::get<0>(atomicRead.t);
546+
const auto &assignmentStmtExpr =
547+
std::get<Fortran::parser::Expr>(std::get<3>(atomicRead.t).statement.t);
548+
const auto &assignmentStmtVariable = std::get<Fortran::parser::Variable>(
549+
std::get<3>(atomicRead.t).statement.t);
550+
if (auto exprDesignator = std::get_if<
551+
Fortran::common::Indirection<Fortran::parser::Designator>>(
552+
&assignmentStmtExpr.u)) {
553+
if (const auto *name =
554+
getDesignatorNameIfDataRef(exprDesignator->value())) {
555+
from_address = converter.getSymbolAddress(*name->symbol);
556+
}
557+
}
558+
559+
if (auto varDesignator = std::get_if<
560+
Fortran::common::Indirection<Fortran::parser::Designator>>(
561+
&assignmentStmtVariable.u)) {
562+
if (const auto *name = getDesignatorNameIfDataRef(varDesignator->value())) {
563+
to_address = converter.getSymbolAddress(*name->symbol);
564+
}
565+
}
566+
567+
genOmpAtomicHintAndMemoryOrderClauses(converter, leftHandClauseList, hint,
568+
memory_order);
569+
genOmpAtomicHintAndMemoryOrderClauses(converter, rightHandClauseList, hint,
570+
memory_order);
571+
firOpBuilder.create<mlir::omp::AtomicReadOp>(currentLocation, from_address,
572+
to_address, hint, memory_order);
573+
}
574+
575+
static void
576+
genOMP(Fortran::lower::AbstractConverter &converter,
577+
Fortran::lower::pft::Evaluation &eval,
578+
const Fortran::parser::OpenMPAtomicConstruct &atomicConstruct) {
579+
std::visit(Fortran::common::visitors{
580+
[&](const Fortran::parser::OmpAtomicRead &atomicRead) {
581+
genOmpAtomicRead(converter, eval, atomicRead);
582+
},
583+
[&](const Fortran::parser::OmpAtomicWrite &atomicWrite) {
584+
genOmpAtomicWrite(converter, eval, atomicWrite);
585+
},
586+
[&](const auto &) {
587+
TODO(converter.getCurrentLocation(),
588+
"Atomic update & capture");
589+
},
590+
},
591+
atomicConstruct.u);
592+
}
593+
455594
void Fortran::lower::genOpenMPConstruct(
456595
Fortran::lower::AbstractConverter &converter,
457596
Fortran::lower::pft::Evaluation &eval,
@@ -485,7 +624,7 @@ void Fortran::lower::genOpenMPConstruct(
485624
genOMP(converter, eval, blockConstruct);
486625
},
487626
[&](const Fortran::parser::OpenMPAtomicConstruct &atomicConstruct) {
488-
TODO(converter.getCurrentLocation(), "OpenMPAtomicConstruct");
627+
genOMP(converter, eval, atomicConstruct);
489628
},
490629
[&](const Fortran::parser::OpenMPCriticalConstruct
491630
&criticalConstruct) {

flang/lib/Optimizer/CodeGen/CodeGen.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3371,11 +3371,9 @@ class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> {
33713371
target.addLegalDialect<mlir::LLVM::LLVMDialect>();
33723372
// The OpenMP dialect is legal for Operations without regions, for those
33733373
// which contains regions it is legal if the region contains only the
3374-
// LLVM dialect.
3375-
target.addDynamicallyLegalOp<mlir::omp::ParallelOp, mlir::omp::WsLoopOp,
3376-
mlir::omp::MasterOp>([&](Operation *op) {
3377-
return typeConverter.isLegal(&op->getRegion(0));
3378-
});
3374+
// LLVM dialect. Add OpenMP dialect as a legal dialect for conversion and
3375+
// legalize conversion of OpenMP operations without regions.
3376+
mlir::configureOpenMPToLLVMConversionLegality(target, typeConverter);
33793377
target.addLegalDialect<mlir::omp::OpenMPDialect>();
33803378

33813379
// required NOPs for applying a full conversion

flang/lib/Optimizer/Dialect/FIRType.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include "flang/Optimizer/Dialect/FIRType.h"
1414
#include "flang/Optimizer/Dialect/FIRDialect.h"
15+
#include "flang/Tools/PointerModels.h"
1516
#include "mlir/IR/Builders.h"
1617
#include "mlir/IR/BuiltinDialect.h"
1718
#include "mlir/IR/Diagnostics.h"
@@ -904,4 +905,15 @@ void FIROpsDialect::registerTypes() {
904905
LLVMPointerType, PointerType, RealType, RecordType, ReferenceType,
905906
SequenceType, ShapeType, ShapeShiftType, ShiftType, SliceType,
906907
TypeDescType, fir::VectorType>();
908+
fir::ReferenceType::attachInterface<PointerLikeModel<fir::ReferenceType>>(
909+
*getContext());
910+
911+
fir::PointerType::attachInterface<PointerLikeModel<fir::PointerType>>(
912+
*getContext());
913+
914+
fir::HeapType::attachInterface<AlternativePointerLikeModel<fir::HeapType>>(
915+
*getContext());
916+
917+
fir::LLVMPointerType::attachInterface<
918+
AlternativePointerLikeModel<fir::LLVMPointerType>>(*getContext());
907919
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
! RUN: bbc -fopenmp -emit-fir %s -o - | \
2+
! RUN: FileCheck %s --check-prefix=FIRDialect
3+
! RUN: bbc -fopenmp %s -o - | fir-opt --fir-to-llvm-ir | \
4+
! RUN: FileCheck %s --check-prefix=LLVMDialect
5+
6+
! This test checks the lowering of atomic read
7+
8+
!FIRDialect: func @_QQmain() {
9+
!FIRDialect: %[[VAR_A:.*]] = fir.address_of(@_QFEa) : !fir.ref<!fir.char<1>>
10+
!FIRDialect: %[[VAR_B:.*]] = fir.address_of(@_QFEb) : !fir.ref<!fir.char<1>>
11+
!FIRDialect: %[[VAR_C:.*]] = fir.alloca !fir.logical<4> {bindc_name = "c", uniq_name = "_QFEc"}
12+
!FIRDialect: %[[VAR_D:.*]] = fir.alloca !fir.logical<4> {bindc_name = "d", uniq_name = "_QFEd"}
13+
!FIRDialect: %[[VAR_E:.*]] = fir.address_of(@_QFEe) : !fir.ref<!fir.char<1,8>>
14+
!FIRDialect: %[[VAR_F:.*]] = fir.address_of(@_QFEf) : !fir.ref<!fir.char<1,8>>
15+
!FIRDialect: %[[VAR_G:.*]] = fir.alloca f32 {bindc_name = "g", uniq_name = "_QFEg"}
16+
!FIRDialect: %[[VAR_H:.*]] = fir.alloca f32 {bindc_name = "h", uniq_name = "_QFEh"}
17+
!FIRDialect: %[[VAR_X:.*]] = fir.alloca i32 {bindc_name = "x", uniq_name = "_QFEx"}
18+
!FIRDialect: %[[VAR_Y:.*]] = fir.alloca i32 {bindc_name = "y", uniq_name = "_QFEy"}
19+
!FIRDialect: omp.atomic.read %[[VAR_X]] = %[[VAR_Y]] memory_order(acquire) hint(uncontended) : !fir.ref<i32>
20+
!FIRDialect: omp.atomic.read %[[VAR_A]] = %[[VAR_B]] memory_order(relaxed) hint(none) : !fir.ref<!fir.char<1>>
21+
!FIRDialect: omp.atomic.read %[[VAR_C]] = %[[VAR_D]] memory_order(seq_cst) hint(contended) : !fir.ref<!fir.logical<4>>
22+
!FIRDialect: omp.atomic.read %[[VAR_E]] = %[[VAR_F]] hint(speculative) : !fir.ref<!fir.char<1,8>>
23+
!FIRDialect: omp.atomic.read %[[VAR_G]] = %[[VAR_H]] hint(nonspeculative) : !fir.ref<f32>
24+
!FIRDialect: omp.atomic.read %[[VAR_G]] = %[[VAR_H]] : !fir.ref<f32>
25+
!FIRDialect: return
26+
!FIRDialect: }
27+
28+
!LLVMDialect: llvm.func @_QQmain() {
29+
!LLVMDialect: %[[LLVM_VAR_A:.*]] = llvm.mlir.addressof @_QFEa : !llvm.ptr<array<1 x i8>>
30+
!LLVMDialect: %[[LLVM_VAR_B:.*]] = llvm.mlir.addressof @_QFEb : !llvm.ptr<array<1 x i8>>
31+
!LLVMDialect: {{.*}} = llvm.mlir.constant(1 : i64) : i64
32+
!LLVMDialect: %[[LLVM_VAR_C:.*]] = llvm.alloca {{.*}} x i32 {bindc_name = "c", in_type = !fir.logical<4>, operand_segment_sizes = dense<0> : vector<2xi32>, uniq_name = "_QFEc"} : (i64) -> !llvm.ptr<i32>
33+
!LLVMDialect: {{.*}} = llvm.mlir.constant(1 : i64) : i64
34+
!LLVMDialect: %[[LLVM_VAR_D:.*]] = llvm.alloca {{.*}} x i32 {bindc_name = "d", in_type = !fir.logical<4>, operand_segment_sizes = dense<0> : vector<2xi32>, uniq_name = "_QFEd"} : (i64) -> !llvm.ptr<i32>
35+
!LLVMDialect: %[[LLVM_VAR_E:.*]] = llvm.mlir.addressof @_QFEe : !llvm.ptr<array<8 x i8>>
36+
!LLVMDialect: %[[LLVM_VAR_F:.*]] = llvm.mlir.addressof @_QFEf : !llvm.ptr<array<8 x i8>>
37+
!LLVMDialect: {{.*}} = llvm.mlir.constant(1 : i64) : i64
38+
!LLVMDialect: %[[LLVM_VAR_G:.*]] = llvm.alloca {{.*}} x f32 {bindc_name = "g", in_type = f32, operand_segment_sizes = dense<0> : vector<2xi32>, uniq_name = "_QFEg"} : (i64) -> !llvm.ptr<f32>
39+
!LLVMDialect: {{.*}} = llvm.mlir.constant(1 : i64) : i64
40+
!LLVMDialect: %[[LLVM_VAR_H:.*]] = llvm.alloca {{.*}} x f32 {bindc_name = "h", in_type = f32, operand_segment_sizes = dense<0> : vector<2xi32>, uniq_name = "_QFEh"} : (i64) -> !llvm.ptr<f32>
41+
!LLVMDialect: {{.*}} = llvm.mlir.constant(1 : i64) : i64
42+
!LLVMDialect: %[[LLVM_VAR_X:.*]] = llvm.alloca {{.*}} x i32 {bindc_name = "x", in_type = i32, operand_segment_sizes = dense<0> : vector<2xi32>, uniq_name = "_QFEx"} : (i64) -> !llvm.ptr<i32>
43+
!LLVMDialect: {{.*}} = llvm.mlir.constant(1 : i64) : i64
44+
!LLVMDialect: %[[LLVM_VAR_Y:.*]] = llvm.alloca {{.*}} x i32 {bindc_name = "y", in_type = i32, operand_segment_sizes = dense<0> : vector<2xi32>, uniq_name = "_QFEy"} : (i64) -> !llvm.ptr<i32>
45+
!LLVMDialect: omp.atomic.read %[[LLVM_VAR_X]] = %[[LLVM_VAR_Y]] memory_order(acquire) hint(uncontended) : !llvm.ptr<i32>
46+
!LLVMDialect: omp.atomic.read %[[LLVM_VAR_A]] = %[[LLVM_VAR_B]] memory_order(relaxed) hint(none) : !llvm.ptr<array<1 x i8>>
47+
!LLVMDialect: omp.atomic.read %[[LLVM_VAR_C]] = %[[LLVM_VAR_D]] memory_order(seq_cst) hint(contended) : !llvm.ptr<i32>
48+
!LLVMDialect: omp.atomic.read %[[LLVM_VAR_E]] = %[[LLVM_VAR_F]] hint(speculative) : !llvm.ptr<array<8 x i8>>
49+
!LLVMDialect: omp.atomic.read %[[LLVM_VAR_G]] = %[[LLVM_VAR_H]] hint(nonspeculative) : !llvm.ptr<f32>
50+
!LLVMDialect: omp.atomic.read %[[LLVM_VAR_G]] = %[[LLVM_VAR_H]] : !llvm.ptr<f32>
51+
!LLVMDialect: llvm.return
52+
!LLVMDialect: }
53+
54+
program OmpAtomic
55+
56+
use omp_lib
57+
integer :: x, y
58+
character :: a, b
59+
logical :: c, d
60+
character(8) :: e, f
61+
real g, h
62+
!$omp atomic acquire read hint(omp_sync_hint_uncontended)
63+
x = y
64+
!$omp atomic relaxed read hint(omp_sync_hint_none)
65+
a = b
66+
!$omp atomic read seq_cst hint(omp_sync_hint_contended)
67+
c = d
68+
!$omp atomic read hint(omp_sync_hint_speculative)
69+
e = f
70+
!$omp atomic read hint(omp_sync_hint_nonspeculative)
71+
g = h
72+
!$omp atomic read
73+
g = h
74+
end program OmpAtomic
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
! RUN: bbc -fopenmp -emit-fir %s -o - | \
2+
! RUN: FileCheck %s --check-prefix=FIRDialect
3+
! RUN: bbc -fopenmp %s -o - | fir-opt --fir-to-llvm-ir | \
4+
! RUN: FileCheck %s --check-prefix=LLVMDialect
5+
6+
! This test checks the lowering of atomic write
7+
8+
!FIRDialect: func @_QQmain() {
9+
!FIRDialect: %[[VAR_X:.*]] = fir.alloca i32 {bindc_name = "x", uniq_name = "_QFEx"}
10+
!FIRDialect: %[[VAR_Y:.*]] = fir.alloca i32 {bindc_name = "y", uniq_name = "_QFEy"}
11+
!FIRDialect: %[[VAR_Z:.*]] = fir.alloca i32 {bindc_name = "z", uniq_name = "_QFEz"}
12+
!FIRDialect: %[[CONST_44:.*]] = arith.constant 44 : i32
13+
!FIRDialect: omp.atomic.write %[[VAR_X]] = %[[CONST_44]] hint(uncontended) memory_order(seq_cst) : !fir.ref<i32>, i32
14+
!FIRDialect: %[[CONST_7:.*]] = arith.constant 7 : i32
15+
!FIRDialect: {{.*}} = fir.load %[[VAR_Y]] : !fir.ref<i32>
16+
!FIRDialect: %[[VAR_7y:.*]] = arith.muli %[[CONST_7]], {{.*}} : i32
17+
!FIRDialect: omp.atomic.write %[[VAR_X]] = %[[VAR_7y]] memory_order(relaxed) : !fir.ref<i32>, i32
18+
!FIRDialect: %[[CONST_10:.*]] = arith.constant 10 : i32
19+
!FIRDialect: {{.*}} = fir.load %[[VAR_X]] : !fir.ref<i32>
20+
!FIRDialect: {{.*}} = arith.muli %[[CONST_10]], {{.*}} : i32
21+
!FIRDialect: {{.*}} = fir.load %[[VAR_Z]] : !fir.ref<i32>
22+
!FIRDialect: %[[CONST_2:.*]] = arith.constant 2 : i32
23+
!FIRDialect: {{.*}} = arith.divsi {{.*}}, %[[CONST_2]] : i32
24+
!FIRDialect: {{.*}} = arith.addi {{.*}}, {{.*}} : i32
25+
!FIRDialect: omp.atomic.write %[[VAR_Y]] = {{.*}} hint(speculative) memory_order(release) : !fir.ref<i32>, i32
26+
!FIRDialect: return
27+
!FIRDialect: }
28+
29+
!LLVMDialect: llvm.func @_QQmain() {
30+
!LLVMDialect: %[[LLVM_VAR_2:.*]] = llvm.mlir.constant(2 : i32) : i32
31+
!LLVMDialect: %[[LLVM_VAR_10:.*]] = llvm.mlir.constant(10 : i32) : i32
32+
!LLVMDialect: %[[LLVM_VAR_7:.*]] = llvm.mlir.constant(7 : i32) : i32
33+
!LLVMDialect: %[[LLVM_VAR_44:.*]] = llvm.mlir.constant(44 : i32) : i32
34+
!LLVMDialect: %[[LLVM_VAR_1:.*]] = llvm.mlir.constant(1 : i64) : i64
35+
!LLVMDialect: %[[LLVM_VAR_X:.*]] = llvm.alloca {{.*}} x i32 {bindc_name = "x", in_type = i32, operand_segment_sizes = dense<0> : vector<2xi32>, uniq_name = "_QFEx"} : (i64) -> !llvm.ptr<i32>
36+
!LLVMDialect: %[[LLVM_VAR_1_SECOND:.*]] = llvm.mlir.constant(1 : i64) : i64
37+
!LLVMDialect: %[[LLVM_VAR_Y:.*]] = llvm.alloca {{.*}} x i32 {bindc_name = "y", in_type = i32, operand_segment_sizes = dense<0> : vector<2xi32>, uniq_name = "_QFEy"} : (i64) -> !llvm.ptr<i32>
38+
!LLVMDialect: %[[LLVM_VAR_1_THIRD:.*]] = llvm.mlir.constant(1 : i64) : i64
39+
!LLVMDialect: %[[LLVM_VAR_Z:.*]] = llvm.alloca {{.*}} x i32 {bindc_name = "z", in_type = i32, operand_segment_sizes = dense<0> : vector<2xi32>, uniq_name = "_QFEz"} : (i64) -> !llvm.ptr<i32>
40+
!LLVMDialect: omp.atomic.write %[[LLVM_VAR_X]] = %[[LLVM_VAR_44]] hint(uncontended) memory_order(seq_cst) : !llvm.ptr<i32>, i32
41+
!LLVMDialect: {{.*}} = llvm.load %[[LLVM_VAR_Y]] : !llvm.ptr<i32>
42+
!LLVMDialect: %[[LLVM_VAR_MUL_RESULT:.*]] = llvm.mul {{.*}}, %[[LLVM_VAR_7]] : i32
43+
!LLVMDialect: omp.atomic.write %[[LLVM_VAR_X]] = %[[LLVM_VAR_MUL_RESULT]] memory_order(relaxed) : !llvm.ptr<i32>, i32
44+
!LLVMDialect: {{.*}} = llvm.load %[[LLVM_VAR_X]] : !llvm.ptr<i32>
45+
!LLVMDialect: {{.*}} = llvm.mul {{.*}}, %[[LLVM_VAR_10]] : i32
46+
!LLVMDialect: {{.*}} = llvm.load %[[LLVM_VAR_Z]] : !llvm.ptr<i32>
47+
!LLVMDialect: {{.*}} = llvm.sdiv {{.*}}, %[[LLVM_VAR_2]] : i32
48+
!LLVMDialect: {{.*}} = llvm.add {{.*}} : i32
49+
!LLVMDialect: omp.atomic.write %[[LLVM_VAR_Y]] = {{.*}} hint(speculative) memory_order(release) : !llvm.ptr<i32>, i32
50+
!LLVMDialect: llvm.return
51+
!LLVMDialect: }
52+
53+
program OmpAtomicWrite
54+
use omp_lib
55+
integer :: x, y, z
56+
!$omp atomic seq_cst write hint(omp_sync_hint_uncontended)
57+
x = 8*4 + 12
58+
59+
!$omp atomic write relaxed
60+
x = 7 * y
61+
62+
!$omp atomic write release hint(omp_sync_hint_speculative)
63+
y = 10*x + z/2
64+
end program OmpAtomicWrite

mlir/include/mlir/Conversion/OpenMPToLLVM/ConvertOpenMPToLLVM.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,18 @@
1212

1313
namespace mlir {
1414
class LLVMTypeConverter;
15+
class ConversionTarget;
1516
class MLIRContext;
1617
class ModuleOp;
1718
template <typename T>
1819
class OperationPass;
1920
class RewritePatternSet;
2021

22+
/// Configure dynamic conversion legality of regionless operations from OpenMP
23+
/// to LLVM.
24+
void configureOpenMPToLLVMConversionLegality(ConversionTarget &target,
25+
LLVMTypeConverter &typeConverter);
26+
2127
/// Populate the given list with patterns that convert from OpenMP to LLVM.
2228
void populateOpenMPToLLVMConversionPatterns(LLVMTypeConverter &converter,
2329
RewritePatternSet &patterns);

0 commit comments

Comments
 (0)