@@ -107,6 +107,18 @@ static Op createRegionOp(Fortran::lower::FirOpBuilder &builder,
107
107
return op;
108
108
}
109
109
110
+ template <typename Op>
111
+ static Op createSimpleOp (Fortran::lower::FirOpBuilder &builder,
112
+ mlir::Location loc,
113
+ const SmallVectorImpl<Value> &operands,
114
+ const SmallVectorImpl<int32_t > &operandSegments) {
115
+ llvm::ArrayRef<mlir::Type> argTy;
116
+ Op op = builder.create <Op>(loc, argTy, operands);
117
+ op.setAttr (Op::getOperandSegmentSizeAttr (),
118
+ builder.getI32VectorAttr (operandSegments));
119
+ return op;
120
+ }
121
+
110
122
static void genACC (Fortran::lower::AbstractConverter &converter,
111
123
Fortran::lower::pft::Evaluation &eval,
112
124
const Fortran::parser::OpenACCLoopConstruct &loopConstruct) {
@@ -516,6 +528,128 @@ genACC(Fortran::lower::AbstractConverter &converter,
516
528
}
517
529
}
518
530
531
+ static void
532
+ genACCExitDataOp (Fortran::lower::AbstractConverter &converter,
533
+ const Fortran::parser::AccClauseList &accClauseList) {
534
+ mlir::Value ifCond, async, waitDevnum;
535
+ SmallVector<Value, 2 > copyoutOperands, deleteOperands, detachOperands,
536
+ waitOperands;
537
+
538
+ // Async and wait clause have optional values but can be present with
539
+ // no value as well. When there is no value, the op has an attribute to
540
+ // represent the clause.
541
+ bool addAsyncAttr = false ;
542
+ bool addWaitAttr = false ;
543
+ bool addFinalizeAttr = false ;
544
+
545
+ auto &firOpBuilder = converter.getFirOpBuilder ();
546
+ auto currentLocation = converter.getCurrentLocation ();
547
+
548
+ // Lower clauses values mapped to operands.
549
+ // Keep track of each group of operands separatly as clauses can appear
550
+ // more than once.
551
+ for (const auto &clause : accClauseList.v ) {
552
+ if (const auto *ifClause =
553
+ std::get_if<Fortran::parser::AccClause::If>(&clause.u )) {
554
+ Value cond = fir::getBase (
555
+ converter.genExprValue (*Fortran::semantics::GetExpr (ifClause->v )));
556
+ ifCond = firOpBuilder.createConvert (currentLocation,
557
+ firOpBuilder.getI1Type (), cond);
558
+ } else if (const auto *asyncClause =
559
+ std::get_if<Fortran::parser::AccClause::Async>(&clause.u )) {
560
+ const auto &asyncClauseValue = asyncClause->v ;
561
+ if (asyncClauseValue) { // async has a value.
562
+ async = fir::getBase (converter.genExprValue (
563
+ *Fortran::semantics::GetExpr (*asyncClauseValue)));
564
+ } else {
565
+ addAsyncAttr = true ;
566
+ }
567
+ } else if (const auto *waitClause =
568
+ std::get_if<Fortran::parser::AccClause::Wait>(&clause.u )) {
569
+ const auto &waitClauseValue = waitClause->v ;
570
+ if (waitClauseValue) { // wait has a value.
571
+ const Fortran::parser::AccWaitArgument &waitArg = *waitClauseValue;
572
+ const std::list<Fortran::parser::ScalarIntExpr> &waitList =
573
+ std::get<std::list<Fortran::parser::ScalarIntExpr>>(waitArg.t );
574
+ for (const Fortran::parser::ScalarIntExpr &value : waitList) {
575
+ Value v = fir::getBase (
576
+ converter.genExprValue (*Fortran::semantics::GetExpr (value)));
577
+ waitOperands.push_back (v);
578
+ }
579
+
580
+ const std::optional<Fortran::parser::ScalarIntExpr> &waitDevnumValue =
581
+ std::get<std::optional<Fortran::parser::ScalarIntExpr>>(waitArg.t );
582
+ if (waitDevnumValue)
583
+ waitDevnum = fir::getBase (converter.genExprValue (
584
+ *Fortran::semantics::GetExpr (*waitDevnumValue)));
585
+ } else {
586
+ addWaitAttr = true ;
587
+ }
588
+ } else if (const auto *copyoutClause =
589
+ std::get_if<Fortran::parser::AccClause::Copyout>(
590
+ &clause.u )) {
591
+ const Fortran::parser::AccObjectListWithModifier &listWithModifier =
592
+ copyoutClause->v ;
593
+ const Fortran::parser::AccObjectList &accObjectList =
594
+ std::get<Fortran::parser::AccObjectList>(listWithModifier.t );
595
+ genObjectList (accObjectList, converter, copyoutOperands);
596
+ } else if (const auto *deleteClause =
597
+ std::get_if<Fortran::parser::AccClause::Delete>(&clause.u )) {
598
+ genObjectList (deleteClause->v , converter, deleteOperands);
599
+ } else if (const auto *detachClause =
600
+ std::get_if<Fortran::parser::AccClause::Detach>(&clause.u )) {
601
+ genObjectList (detachClause->v , converter, detachOperands);
602
+ } else if (std::get_if<Fortran::parser::AccClause::Finalize>(&clause.u )) {
603
+ addFinalizeAttr = true ;
604
+ }
605
+ }
606
+
607
+ // Prepare the operand segement size attribute and the operands value range.
608
+ SmallVector<Value, 8 > operands;
609
+ SmallVector<int32_t , 8 > operandSegments;
610
+ addOperand (operands, operandSegments, ifCond);
611
+ addOperand (operands, operandSegments, async);
612
+ addOperand (operands, operandSegments, waitDevnum);
613
+ addOperands (operands, operandSegments, waitOperands);
614
+ addOperands (operands, operandSegments, copyoutOperands);
615
+ addOperands (operands, operandSegments, deleteOperands);
616
+ addOperands (operands, operandSegments, detachOperands);
617
+
618
+ auto exitDataOp = createSimpleOp<mlir::acc::ExitDataOp>(
619
+ firOpBuilder, currentLocation, operands, operandSegments);
620
+
621
+ if (addAsyncAttr)
622
+ exitDataOp.asyncAttr (firOpBuilder.getUnitAttr ());
623
+ if (addWaitAttr)
624
+ exitDataOp.waitAttr (firOpBuilder.getUnitAttr ());
625
+ if (addFinalizeAttr)
626
+ exitDataOp.finalizeAttr (firOpBuilder.getUnitAttr ());
627
+ }
628
+
629
+ static void
630
+ genACC (Fortran::lower::AbstractConverter &converter,
631
+ Fortran::lower::pft::Evaluation &eval,
632
+ const Fortran::parser::OpenACCStandaloneConstruct &standaloneConstruct) {
633
+ const auto &standaloneDirective =
634
+ std::get<Fortran::parser::AccStandaloneDirective>(standaloneConstruct.t );
635
+ const auto &accClauseList =
636
+ std::get<Fortran::parser::AccClauseList>(standaloneConstruct.t );
637
+
638
+ if (standaloneDirective.v == llvm::acc::Directive::ACCD_enter_data) {
639
+ TODO (" OpenACC enter data directive not lowered yet!" );
640
+ } else if (standaloneDirective.v == llvm::acc::Directive::ACCD_exit_data) {
641
+ genACCExitDataOp (converter, accClauseList);
642
+ } else if (standaloneDirective.v == llvm::acc::Directive::ACCD_init) {
643
+ TODO (" OpenACC init directive not lowered yet!" );
644
+ } else if (standaloneDirective.v == llvm::acc::Directive::ACCD_shutdown) {
645
+ TODO (" OpenACC shutdown directive not lowered yet!" );
646
+ } else if (standaloneDirective.v == llvm::acc::Directive::ACCD_set) {
647
+ TODO (" OpenACC set directive not lowered yet!" );
648
+ } else if (standaloneDirective.v == llvm::acc::Directive::ACCD_update) {
649
+ TODO (" OpenACC update directive not lowered yet!" );
650
+ }
651
+ }
652
+
519
653
void Fortran::lower::genOpenACCConstruct (
520
654
Fortran::lower::AbstractConverter &converter,
521
655
Fortran::lower::pft::Evaluation &eval,
@@ -535,7 +669,7 @@ void Fortran::lower::genOpenACCConstruct(
535
669
},
536
670
[&](const Fortran::parser::OpenACCStandaloneConstruct
537
671
&standaloneConstruct) {
538
- TODO ( " OpenACC Standalone construct not lowered yet! " );
672
+ genACC (converter, eval, standaloneConstruct );
539
673
},
540
674
[&](const Fortran::parser::OpenACCRoutineConstruct
541
675
&routineConstruct) {
0 commit comments