[Flang][OpenMP] Implementation of lowering of SIMD construct.

This patch adds code so that using bbc we are able to see an end-to-end lowering of simd construct in action.

Reviewed By: kiranchandramohan, peixin, shraiysh

Differential Revision: https://reviews.llvm.org/D125282
This commit is contained in:
Arnamoy Bhattacharyya 2022-06-13 09:07:23 -04:00
parent 45a5cd41e5
commit 3f4a63e5f8
3 changed files with 86 additions and 7 deletions

View File

@ -319,7 +319,8 @@ createBodyOfOp(Op &op, Fortran::lower::AbstractConverter &converter,
createEmptyRegionBlocks(firOpBuilder, eval.getNestedEvaluations());
// Insert the terminator.
if constexpr (std::is_same_v<Op, omp::WsLoopOp>) {
if constexpr (std::is_same_v<Op, omp::WsLoopOp> ||
std::is_same_v<Op, omp::SimdLoopOp>) {
mlir::ValueRange results;
firOpBuilder.create<mlir::omp::YieldOp>(loc, results);
} else {
@ -703,7 +704,7 @@ static void genOMP(Fortran::lower::AbstractConverter &converter,
mlir::Value scheduleChunkClauseOperand;
mlir::Attribute scheduleClauseOperand, collapseClauseOperand,
noWaitClauseOperand, orderedClauseOperand, orderClauseOperand;
const auto &wsLoopOpClauseList = std::get<Fortran::parser::OmpClauseList>(
const auto &loopOpClauseList = std::get<Fortran::parser::OmpClauseList>(
std::get<Fortran::parser::OmpBeginLoopDirective>(loopConstruct.t).t);
const auto ompDirective =
@ -714,7 +715,8 @@ static void genOMP(Fortran::lower::AbstractConverter &converter,
createCombinedParallelOp<Fortran::parser::OmpBeginLoopDirective>(
converter, eval,
std::get<Fortran::parser::OmpBeginLoopDirective>(loopConstruct.t));
} else if (llvm::omp::OMPD_do != ompDirective) {
} else if (llvm::omp::OMPD_do != ompDirective &&
llvm::omp::OMPD_simd != ompDirective) {
TODO(converter.getCurrentLocation(), "Construct enclosing do loop");
}
@ -722,7 +724,7 @@ static void genOMP(Fortran::lower::AbstractConverter &converter,
auto *doConstructEval = &eval.getFirstNestedEvaluation();
std::int64_t collapseValue =
Fortran::lower::getCollapseValue(wsLoopOpClauseList);
Fortran::lower::getCollapseValue(loopOpClauseList);
std::size_t loopVarTypeSize = 0;
SmallVector<const Fortran::semantics::Symbol *> iv;
do {
@ -755,7 +757,7 @@ static void genOMP(Fortran::lower::AbstractConverter &converter,
&*std::next(doConstructEval->getNestedEvaluations().begin());
} while (collapseValue > 0);
for (const auto &clause : wsLoopOpClauseList.v) {
for (const auto &clause : loopOpClauseList.v) {
if (const auto &scheduleClause =
std::get_if<Fortran::parser::OmpClause::Schedule>(&clause.u)) {
if (const auto &chunkExpr =
@ -782,6 +784,17 @@ static void genOMP(Fortran::lower::AbstractConverter &converter,
firOpBuilder.createConvert(currentLocation, loopVarType, step[it]);
}
// 2.9.3.1 SIMD construct
// TODO: Support all the clauses
if (llvm::omp::OMPD_simd == ompDirective) {
TypeRange resultType;
auto SimdLoopOp = firOpBuilder.create<mlir::omp::SimdLoopOp>(
currentLocation, resultType, lowerBound, upperBound, step);
createBodyOfOp<omp::SimdLoopOp>(SimdLoopOp, converter, currentLocation,
eval, &loopOpClauseList, iv);
return;
}
// FIXME: Add support for following clauses:
// 1. linear
// 2. order
@ -798,7 +811,7 @@ static void genOMP(Fortran::lower::AbstractConverter &converter,
/*inclusive=*/firOpBuilder.getUnitAttr());
// Handle attribute based clauses.
for (const Fortran::parser::OmpClause &clause : wsLoopOpClauseList.v) {
for (const Fortran::parser::OmpClause &clause : loopOpClauseList.v) {
if (const auto &orderedClause =
std::get_if<Fortran::parser::OmpClause::Ordered>(&clause.u)) {
if (orderedClause->v.has_value()) {
@ -873,7 +886,7 @@ static void genOMP(Fortran::lower::AbstractConverter &converter,
}
createBodyOfOp<omp::WsLoopOp>(wsLoopOp, converter, currentLocation, eval,
&wsLoopOpClauseList, iv);
&loopOpClauseList, iv);
}
static void

View File

@ -171,3 +171,49 @@ func.func @sections_data_without_clauses(%arg0: !fir.ref<i32> {fir.bindc_name =
// CHECK: }
// CHECK: omp.terminator
// CHECK: }
// -----
func.func @_QPsimd1(%arg0: !fir.ref<i32> {fir.bindc_name = "n"}, %arg1: !fir.ref<!fir.array<?xi32>> {fir.bindc_name = "arr"}) {
%c1_i64 = arith.constant 1 : i64
%c1_i32 = arith.constant 1 : i32
%0 = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFsbEi"}
omp.parallel {
%1 = fir.alloca i32 {adapt.valuebyref, pinned}
%2 = fir.load %arg0 : !fir.ref<i32>
omp.simdloop (%arg2) : i32 = (%c1_i32) to (%2) step (%c1_i32) {
fir.store %arg2 to %1 : !fir.ref<i32>
%3 = fir.load %1 : !fir.ref<i32>
%4 = fir.convert %3 : (i32) -> i64
%5 = arith.subi %4, %c1_i64 : i64
%6 = fir.coordinate_of %arg1, %5 : (!fir.ref<!fir.array<?xi32>>, i64) -> !fir.ref<i32>
fir.store %3 to %6 : !fir.ref<i32>
omp.yield
}
omp.terminator
}
return
}
// CHECK-LABEL: _QPsimd1
// CHECK-SAME: %[[N_REF:.*]]: !llvm.ptr<i32> {fir.bindc_name = "n"}, %[[ARR_REF:.*]]: !llvm.ptr<i32> {fir.bindc_name = "arr"}) {
// CHECK: %[[ONE_1:.*]] = llvm.mlir.constant(1 : i64) : i64
// CHECK: %[[ONE_2:.*]] = llvm.mlir.constant(1 : i32) : i32
// CHECK: omp.parallel {
// CHECK: %[[ONE_3:.*]] = llvm.mlir.constant(1 : i64) : i64
// CHECK: %[[I_VAR:.*]] = llvm.alloca %[[ONE_3]] x i32 {adapt.valuebyref, in_type = i32, operand_segment_sizes = dense<0> : vector<2xi32>, pinned} : (i64) -> !llvm.ptr<i32>
// CHECK: %[[N:.*]] = llvm.load %[[N_REF]] : !llvm.ptr<i32>
// CHECK: omp.simdloop
// CHECK-SAME: (%[[I:.*]]) : i32 = (%[[ONE_2]]) to (%[[N]]) step (%[[ONE_2]]) {
// CHECK: llvm.store %[[I]], %[[I_VAR]] : !llvm.ptr<i32>
// CHECK: %[[I1:.*]] = llvm.load %[[I_VAR]] : !llvm.ptr<i32>
// CHECK: %[[I1_EXT:.*]] = llvm.sext %[[I1]] : i32 to i64
// CHECK: %[[I_CSTYLE:.*]] = llvm.sub %[[I1_EXT]], %[[ONE_1]] : i64
// CHECK: %[[ARR_I_REF:.*]] = llvm.getelementptr %[[ARR_REF]][%[[I_CSTYLE]]] : (!llvm.ptr<i32>, i64) -> !llvm.ptr<i32>
// CHECK: llvm.store %[[I1]], %[[ARR_I_REF]] : !llvm.ptr<i32>
// CHECK: omp.yield
// CHECK: }
// CHECK: omp.terminator
// CHECK: }
// CHECK: llvm.return
// CHECK: }

View File

@ -0,0 +1,20 @@
! Tests for 2.9.3.1 Simd
! RUN: bbc -fopenmp -emit-fir %s -o - | FileCheck %s
!CHECK-LABEL: func @_QPsimdloop()
subroutine simdloop
integer :: i
!$OMP SIMD
! CHECK: %[[LB:.*]] = arith.constant 1 : i32
! CHECK-NEXT: %[[UB:.*]] = arith.constant 9 : i32
! CHECK-NEXT: %[[STEP:.*]] = arith.constant 1 : i32
! CHECK-NEXT: omp.simdloop (%[[I:.*]]) : i32 = (%[[LB]]) to (%[[UB]]) step (%[[STEP]]) {
do i=1, 9
! CHECK: fir.store %[[I]] to %[[LOCAL:.*]] : !fir.ref<i32>
! CHECK: %[[LD:.*]] = fir.load %[[LOCAL]] : !fir.ref<i32>
! CHECK: fir.call @_FortranAioOutputInteger32({{.*}}, %[[LD]]) : (!fir.ref<i8>, i32) -> i1
print*, i
end do
!$OMP END SIMD
end subroutine