forked from OSchip/llvm-project
[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:
parent
45a5cd41e5
commit
3f4a63e5f8
|
@ -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
|
||||
|
|
|
@ -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: }
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue