Index: flang/include/flang/Lower/OpenMP.h =================================================================== --- flang/include/flang/Lower/OpenMP.h +++ flang/include/flang/Lower/OpenMP.h @@ -34,6 +34,10 @@ struct OmpClauseList; } // namespace parser +namespace semantics { +class SemanticsContext; +} + namespace lower { class AbstractConverter; @@ -48,7 +52,8 @@ mlir::Location); void genOpenMPConstruct(AbstractConverter &, pft::Evaluation &, - const parser::OpenMPConstruct &); + const parser::OpenMPConstruct &, + Fortran::semantics::SemanticsContext &); void genOpenMPDeclarativeConstruct(AbstractConverter &, pft::Evaluation &, const parser::OpenMPDeclarativeConstruct &); int64_t getCollapseValue(const Fortran::parser::OmpClauseList &clauseList); Index: flang/lib/Lower/Bridge.cpp =================================================================== --- flang/lib/Lower/Bridge.cpp +++ flang/lib/Lower/Bridge.cpp @@ -2239,7 +2239,7 @@ void genFIR(const Fortran::parser::OpenMPConstruct &omp) { mlir::OpBuilder::InsertPoint insertPt = builder->saveInsertionPoint(); localSymbols.pushScope(); - genOpenMPConstruct(*this, getEval(), omp); + genOpenMPConstruct(*this, getEval(), omp, bridge.getSemanticsContext()); const Fortran::parser::OpenMPLoopConstruct *ompLoop = std::get_if(&omp.u); Index: flang/lib/Lower/OpenMP.cpp =================================================================== --- flang/lib/Lower/OpenMP.cpp +++ flang/lib/Lower/OpenMP.cpp @@ -24,6 +24,7 @@ #include "flang/Semantics/tools.h" #include "mlir/Dialect/OpenMP/OpenMPDialect.h" #include "llvm/Frontend/OpenMP/OMPConstants.h" +#include "llvm/Frontend/OpenMP/OMPIRBuilder.h" using DeclareTargetCapturePair = std::pair &alignVars, + llvm::SmallVector &alignmentValues); bool processCollapse(mlir::Location currentLocation, Fortran::lower::pft::Evaluation &eval, @@ -1183,10 +1188,107 @@ } } +/// Convert MLIR OpenMP target features attribute into +/// map +static llvm::StringMap getTargetFeatures(mlir::ModuleOp module) { + llvm::StringMap featuresMap; + llvm::SmallVector targetFeaturesVec; + llvm::StringRef targetFeaturesStr; + auto targetInterface = + llvm::dyn_cast(module.getOperation()); + if (!targetInterface) { + return featuresMap; + } + auto targetAttr = targetInterface.getTarget(); + if (!targetAttr) + return featuresMap; + targetFeaturesStr = targetAttr.getTargetFeatures(); + targetFeaturesStr.split(targetFeaturesVec, ","); + for (auto &feature : targetFeaturesVec) { + if (feature.empty()) + continue; + llvm::StringRef featureKeyString = feature.substr(1); + featuresMap[featureKeyString] = (feature[0] == '+'); + } + + return featuresMap; +} + //===----------------------------------------------------------------------===// // ClauseProcessor unique clauses //===----------------------------------------------------------------------===// +bool ClauseProcessor::processAligned( + mlir::Location currentLocation, + Fortran::semantics::SemanticsContext &semanticsContext, + llvm::SmallVector &alignVars, + llvm::SmallVector &alignmentValues) { + auto *alignedClause = findUniqueClause(); + if (!alignedClause) + return false; + const Fortran::parser::OmpAlignedClause &ompAlignClause = alignedClause->v; + mlir::IntegerAttr alignmentValueAttr; + fir::FirOpBuilder &builder = converter.getFirOpBuilder(); + Fortran::lower::StatementContext stmtCtx; + const Fortran::parser::OmpObjectList &ompObjectList = + std::get(ompAlignClause.t); + + const auto &alignmentValueParserExpr = + std::get>( + ompAlignClause.t); + if (alignmentValueParserExpr) { + // Use alignment value specified in the input Fortran code + const auto &alignmentValueExpr = + Fortran::semantics::GetExpr(alignmentValueParserExpr); + const std::optional alignment = + Fortran::evaluate::ToInt64(*alignmentValueExpr); + + alignmentValueAttr = builder.getI64IntegerAttr(*alignment); + } else { + // Get target features string stored in MLIR module and generate map where + // the key corresponds to given feature and bool value describes if given + // feature is enabled + llvm::StringMap featuresMap = getTargetFeatures(builder.getModule()); + + const llvm::Triple &triple = fir::getTargetTriple(builder.getModule()); + // Calculate the default alignment for given target + int64_t defaultOpenMPSimdAlignment = + llvm::OpenMPIRBuilder::getOpenMPDefaultSimdAlign(triple, featuresMap); + alignmentValueAttr = builder.getI64IntegerAttr(defaultOpenMPSimdAlignment); + } + + for (const Fortran::parser::OmpObject &ompItem : ompObjectList.v) { + const Fortran::parser::Designator *sym = nullptr; + std::visit(Fortran::common::visitors{ + [&](const Fortran::parser::Designator &designator) { + sym = &designator; + }, + [&](const Fortran::parser::Name &name) { + // Common block is represented in OmpObject as Name. + // According to OpenMP 5.2 spec (5.11) common block + // is not allowed as an aligned item. Flang parser checks + // if given aligned item is common block. That's why we + // skip common blocks in MLIR lowering + }}, + ompItem.u); + + if (!sym) + continue; + + // The default alignment for some targets is equal to 0. + // Do not generate alignment assumption if alignment is equal to 0. + if (alignmentValueAttr.getInt() <= 0) + continue; + + mlir::Value alignedItem = fir::getBase(converter.genExprAddr( + *(Fortran::semantics::AnalyzeExpr(semanticsContext, *sym)), stmtCtx, + ¤tLocation)); + alignVars.push_back(alignedItem); + alignmentValues.push_back(alignmentValueAttr); + } + return true; +} + bool ClauseProcessor::processCollapse( mlir::Location currentLocation, Fortran::lower::pft::Evaluation &eval, llvm::SmallVectorImpl &lowerBound, @@ -2314,7 +2416,8 @@ static void genOMP(Fortran::lower::AbstractConverter &converter, Fortran::lower::pft::Evaluation &eval, - const Fortran::parser::OpenMPLoopConstruct &loopConstruct) { + const Fortran::parser::OpenMPLoopConstruct &loopConstruct, + Fortran::semantics::SemanticsContext &semanticsContext) { fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); llvm::SmallVector lowerBound, upperBound, step, linearVars, linearStepVars, reductionVars, alignedVars, nontemporalVars; @@ -2325,7 +2428,7 @@ mlir::omp::ScheduleModifierAttr scheduleModClauseOperand; mlir::UnitAttr nowaitClauseOperand, scheduleSimdClauseOperand; mlir::IntegerAttr simdlenClauseOperand, safelenClauseOperand; - llvm::SmallVector reductionDeclSymbols; + llvm::SmallVector reductionDeclSymbols, alignmentValues; Fortran::lower::StatementContext stmtCtx; std::size_t loopVarTypeSize; llvm::SmallVector iv; @@ -2354,6 +2457,8 @@ ClauseProcessor cp(converter, loopOpClauseList); cp.processCollapse(currentLocation, eval, lowerBound, upperBound, step, iv, loopVarTypeSize); + cp.processAligned(currentLocation, semanticsContext, alignedVars, + alignmentValues); cp.processScheduleChunk(stmtCtx, scheduleChunkClauseOperand); cp.processIf(stmtCtx, Fortran::parser::OmpIfClause::DirectiveNameModifier::Simd, @@ -2380,8 +2485,11 @@ mlir::TypeRange resultType; auto simdLoopOp = firOpBuilder.create( currentLocation, resultType, lowerBound, upperBound, step, alignedVars, - /*alignment_values=*/nullptr, ifClauseOperand, nontemporalVars, - orderClauseOperand, simdlenClauseOperand, safelenClauseOperand, + alignmentValues.empty() + ? nullptr + : mlir::ArrayAttr::get(firOpBuilder.getContext(), alignmentValues), + ifClauseOperand, nontemporalVars, orderClauseOperand, + simdlenClauseOperand, safelenClauseOperand, /*inclusive=*/firOpBuilder.getUnitAttr()); createBodyOfOp( simdLoopOp, converter, currentLocation, eval, &loopOpClauseList, iv, @@ -3237,7 +3345,8 @@ void Fortran::lower::genOpenMPConstruct( Fortran::lower::AbstractConverter &converter, Fortran::lower::pft::Evaluation &eval, - const Fortran::parser::OpenMPConstruct &ompConstruct) { + const Fortran::parser::OpenMPConstruct &ompConstruct, + Fortran::semantics::SemanticsContext &semanticsContext) { std::visit( common::visitors{ [&](const Fortran::parser::OpenMPStandaloneConstruct @@ -3252,7 +3361,7 @@ genOMP(converter, eval, sectionConstruct); }, [&](const Fortran::parser::OpenMPLoopConstruct &loopConstruct) { - genOMP(converter, eval, loopConstruct); + genOMP(converter, eval, loopConstruct, semanticsContext); }, [&](const Fortran::parser::OpenMPDeclarativeAllocate &execAllocConstruct) { Index: flang/test/Lower/OpenMP/simd.f90 =================================================================== --- flang/test/Lower/OpenMP/simd.f90 +++ flang/test/Lower/OpenMP/simd.f90 @@ -164,3 +164,37 @@ end do !$OMP END SIMD end subroutine + +!CHECK: func.func @_QPsimdloop_aligned_cptr(%[[ARG_A:.*]]: !fir.ref +!CHECK-SAME: > {fir.bindc_name = "a"}) { +subroutine simdloop_aligned_cptr( A) + use iso_c_binding + integer :: i + type (c_ptr) :: A +!CHECK: omp.simdloop aligned(%[[ARG_A]] : !fir.ref +!CHECK-SAME: > +!CHECK-SAME: -> 256 : i64) + !$OMP SIMD ALIGNED(A:256) + do i = 1, 10 + call c_test_call(A) + end do + !$OMP END SIMD +end subroutine + +!CHECK-LABEL: func @_QPsimdloop_aligned_allocatable +subroutine simdloop_aligned_allocatable() + integer :: i + integer, allocatable :: A(:) + allocate(A(10)) +!CHECK: %[[A_PTR:.*]] = fir.alloca !fir.box>> {bindc_name = "a", +!CHECK-SAME: uniq_name = "_QFsimdloop_aligned_allocatableEa"} +!CHECK: %[[A_PTR_LOAD:.*]] = fir.load %[[A_PTR]] : !fir.ref>>> +!CHECK: %[[A_ALIGNED:.*]] = fir.box_addr %[[A_PTR_LOAD]] : (!fir.box>>) +!CHECK-SAME: -> !fir.heap> +!CHECK: omp.simdloop aligned(%[[A_ALIGNED]] : !fir.heap> -> 256 : i64) + !$OMP SIMD ALIGNED(A:256) + do i = 1, 10 + A(i) = i + end do +end subroutine Index: flang/test/Lower/OpenMP/simd_aarch64.f90 =================================================================== --- /dev/null +++ flang/test/Lower/OpenMP/simd_aarch64.f90 @@ -0,0 +1,20 @@ +! Tests for 2.9.3.1 Simd and target dependent defult alignment for AArch64 +! The default alignment for AARch is 0 so we do not emit aligned clause + +! REQUIRES: aarch64-registered-target +! RUN: %flang_fc1 -triple aarch64-unknown-linux-gnu -emit-fir -fopenmp %s -o - | FileCheck %s + +subroutine simdloop_aligned_cptr(A) + use iso_c_binding + integer :: i + type (c_ptr) :: A +!CHECK: omp.simdloop +!CHECK-NOT: aligned( +!CHECK-SAME: for (%[[IT:.*]]) : i32 = (%[[LB:.*]]) to (%[[UB:.*]]) inclusive step (%[[INC:.*]]) { + !$OMP SIMD ALIGNED(A) + do i = 1, 10 + call c_test_call(A) + end do + !$OMP END SIMD +end subroutine + Index: flang/test/Lower/OpenMP/simd_x86_64.f90 =================================================================== --- /dev/null +++ flang/test/Lower/OpenMP/simd_x86_64.f90 @@ -0,0 +1,36 @@ +! Tests for 2.9.3.1 Simd and target dependent defult alignment for x86 + +! REQUIRES: x86-registered-target +! RUN: %flang_fc1 -triple x86_64-unknown-linux-gnu -emit-fir -fopenmp -target-cpu x86-64 %s -o - | FileCheck --check-prefixes=DEFAULT %s +! RUN: %flang_fc1 -triple x86_64-unknown-linux-gnu -emit-fir -fopenmp -target-cpu x86-64 -target-feature +avx %s -o - | FileCheck --check-prefixes=AVX %s +! RUN: %flang_fc1 -triple x86_64-unknown-linux-gnu -emit-fir -fopenmp -target-cpu x86-64 -target-feature +avx512f %s -o - | FileCheck --check-prefixes=AVX512F %s + +!DEFAULT: func.func @_QPsimdloop_aligned_cptr(%[[ARG_A:.*]]: !fir.ref +!DEFAULT-SAME: > {fir.bindc_name = "a"}) { +!AVX: func.func @_QPsimdloop_aligned_cptr(%[[ARG_A:.*]]: !fir.ref +!AVX-SAME: > {fir.bindc_name = "a"}) { +!AVX512F: func.func @_QPsimdloop_aligned_cptr(%[[ARG_A:.*]]: !fir.ref +!AVX512F-SAME: > {fir.bindc_name = "a"}) { +subroutine simdloop_aligned_cptr(A) + use iso_c_binding + integer :: i + type (c_ptr) :: A +!DEFAULT: omp.simdloop aligned(%[[ARG_A]] : !fir.ref +!DEFAULT-SAME: > +!DEFAULT-SAME: -> 128 : i64) +!AVX: omp.simdloop aligned(%[[ARG_A]] : !fir.ref +!AVX-SAME: > +!AVX-SAME: -> 256 : i64) +!AVX512F: omp.simdloop aligned(%[[ARG_A]] : !fir.ref +!AVX512F-SAME: > +!AVX512F-SAME: -> 512 : i64) + !$OMP SIMD ALIGNED(A) + do i = 1, 10 + call c_test_call(A) + end do + !$OMP END SIMD +end subroutine +