Index: flang/lib/Lower/OpenMP.cpp =================================================================== --- flang/lib/Lower/OpenMP.cpp +++ flang/lib/Lower/OpenMP.cpp @@ -20,11 +20,13 @@ #include "flang/Optimizer/Builder/BoxValue.h" #include "flang/Optimizer/Builder/FIRBuilder.h" #include "flang/Optimizer/Builder/Todo.h" +#include "flang/Optimizer/Support/FIRContext.h" #include "flang/Parser/parse-tree.h" #include "flang/Semantics/tools.h" #include "mlir/Dialect/OpenMP/OpenMPDialect.h" #include "mlir/Dialect/SCF/IR/SCF.h" #include "llvm/Frontend/OpenMP/OMPConstants.h" +#include "llvm/Frontend/OpenMP/OMPIRBuilder.h" using namespace mlir; @@ -1125,6 +1127,43 @@ return mlir::omp::ScheduleModifier::none; } +static void +genAlignClause(Fortran::lower::AbstractConverter &converter, + const Fortran::parser::OmpAlignedClause &ompAlignClause, + SmallVector &alignVars, + SmallVector &alignmentValues) { + + mlir::Attribute alignmentValueAttr; + fir::FirOpBuilder &builder = converter.getFirOpBuilder(); + const std::list &ompNameList = + std::get>(ompAlignClause.t); + + const auto &alignmentValueParserExpr = + std::get>( + ompAlignClause.t); + if (alignmentValueParserExpr) { + const auto &alignmentValueExpr = + Fortran::semantics::GetExpr(alignmentValueParserExpr); + const std::optional alignment = + Fortran::evaluate::ToInt64(*alignmentValueExpr); + + alignmentValueAttr = builder.getI64IntegerAttr(*alignment); + } else { + // TODO: Pass target specific features when Flang driver supports it. + llvm::StringMap featuresMap; + const llvm::Triple &triple = fir::getTargetTriple(builder.getModule()); + int64_t defaultOpenMPSimdAlignment = + llvm::OpenMPIRBuilder::getOpenMPDefaultSimdAlign(triple, featuresMap); + alignmentValueAttr = builder.getI64IntegerAttr(defaultOpenMPSimdAlignment); + } + + for (const Fortran::parser::Name &ompItem : ompNameList) { + Fortran::semantics::Symbol *sym = ompItem.symbol; + alignVars.push_back(converter.getSymbolAddress(*sym)); + alignmentValues.push_back(alignmentValueAttr); + } +} + static mlir::omp::ScheduleModifier getSIMDModifier(const Fortran::parser::OmpScheduleClause &x) { const auto &modifier = @@ -1185,7 +1224,7 @@ mlir::Attribute scheduleClauseOperand, noWaitClauseOperand, orderedClauseOperand, orderClauseOperand; mlir::IntegerAttr simdlenClauseOperand, safelenClauseOperand; - SmallVector reductionDeclSymbols; + SmallVector reductionDeclSymbols, alignmentValues; Fortran::lower::StatementContext stmtCtx; const auto &loopOpClauseList = std::get( std::get(loopConstruct.t).t); @@ -1254,6 +1293,10 @@ } else if (const auto &ifClause = std::get_if(&clause.u)) { ifClauseOperand = getIfClauseOperand(converter, stmtCtx, ifClause); + } else if (const auto &alignedClause = + std::get_if( + &clause.u)) { + genAlignClause(converter, alignedClause->v, alignedVars, alignmentValues); } else if (const auto &reductionClause = std::get_if( &clause.u)) { @@ -1340,7 +1383,10 @@ TypeRange resultType; auto SimdLoopOp = firOpBuilder.create( currentLocation, resultType, lowerBound, upperBound, step, alignedVars, - nullptr, ifClauseOperand, nontemporalVars, + alignmentValues.empty() + ? nullptr + : mlir::ArrayAttr::get(firOpBuilder.getContext(), alignmentValues), + ifClauseOperand, nontemporalVars, orderClauseOperand.dyn_cast_or_null(), simdlenClauseOperand, safelenClauseOperand, /*inclusive=*/firOpBuilder.getUnitAttr()); Index: flang/test/Lower/OpenMP/simd.f90 =================================================================== --- flang/test/Lower/OpenMP/simd.f90 +++ flang/test/Lower/OpenMP/simd.f90 @@ -164,3 +164,20 @@ end do !$OMP END SIMD end subroutine + +!CHECK-LABEL: func @_QPsimdloop_aligned +subroutine simdloop_aligned(n) +integer :: i, n +integer :: A(n) +! CHECK: %[[LOWER_I:.*]] = arith.constant 1 : i32 +! CHECK: %[[UPPER_I:.*]] = fir.load %[[PARAM_ARG:.*]] : !fir.ref +! CHECK: %[[STEP_I:.*]] = arith.constant 1 : i32 +! CHECK: omp.simdloop aligned(%[[ARG_0:.*]] : !fir.ref> -> 256 : i64) +! CHECK-SAME: for (%[[ARG_1:.*]]) : i32 = (%[[LOWER_I]]) to ( +! CHECK-SAME: %[[UPPER_I]]) inclusive step (%[[STEP_I]]) { + !$OMP SIMD ALIGNED(A:256) + do i = 1, n + A(i) = i + end do + !$OMP END SIMD +end subroutine Index: mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td =================================================================== --- mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td +++ mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td @@ -448,6 +448,9 @@ /// Returns the number of loops in the simd loop nest. unsigned getNumLoops() { return getLowerBound().size(); } + /// Returns the number of aligned variables in the simd loop. + unsigned getNumAlignedVars() { return getAlignedVars().size(); } + }]; let hasCustomAssemblyFormat = 1; Index: mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp =================================================================== --- mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp +++ mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp @@ -998,6 +998,15 @@ safelen = builder.getInt64(safelenVar.value()); llvm::MapVector alignedVars; + for (unsigned i = 0; i < loop.getNumAlignedVars(); ++i) { + llvm::Value *alignedVar = + moduleTranslation.lookupValue(loop.getAlignedVars()[i]); + IntegerAttr alignmentAttr = + (loop.getAlignmentValues().value()[i].cast()); + alignedVars[alignedVar] = + builder.getInt64(alignmentAttr.getValue().getZExtValue()); + } + ompBuilder->applySimd( loopInfo, alignedVars, loop.getIfExpr() ? moduleTranslation.lookupValue(loop.getIfExpr()) Index: mlir/test/Target/LLVMIR/openmp-llvm.mlir =================================================================== --- mlir/test/Target/LLVMIR/openmp-llvm.mlir +++ mlir/test/Target/LLVMIR/openmp-llvm.mlir @@ -758,6 +758,30 @@ // ----- +// CHECK-LABEL: @simdloop_aligned +llvm.func @simdloop_aligned() { + %0 = llvm.mlir.constant(1 : i64) : i64 + %1 = llvm.alloca %0 x i32 {adapt.valuebyref, in_type = i32, operand_segment_sizes = array} : (i64) -> !llvm.ptr + %2 = llvm.mlir.addressof @_QFEa : !llvm.ptr> + %3 = llvm.mlir.constant(1 : i64) : i64 + %4 = llvm.alloca %3 x i32 {bindc_name = "i", in_type = i32, operand_segment_sizes = array, uniq_name = "_QFEi"} : (i64) -> !llvm.ptr + %5 = llvm.mlir.constant(1 : i32) : i32 + %6 = llvm.mlir.constant(256 : i32) : i32 + %7 = llvm.mlir.constant(1 : i32) : i32 + omp.simdloop aligned(%2 : !llvm.ptr> -> 64 : i64) for (%arg0) : i32 = (%5) to (%6) inclusive step (%7) { + // CHECK: call void @llvm.assume(i1 true) [ "align"(ptr @_QFEa, i64 64) ] + llvm.store %arg0, %1 : !llvm.ptr + omp.yield + } + llvm.return +} +llvm.mlir.global internal @_QFEa() {addr_space = 0 : i32} : !llvm.array<256 x i32> { + %0 = llvm.mlir.undef : !llvm.array<256 x i32> + llvm.return %0 : !llvm.array<256 x i32> +} + +// ----- + llvm.func @body(i64) llvm.func @test_omp_wsloop_ordered(%lb : i64, %ub : i64, %step : i64) -> () {