1414#include " flang/Semantics/type.h"
1515#include " flang/Support/Fortran.h"
1616#include " llvm/Support/AtomicOrdering.h"
17- #include " llvm/Support/raw_ostream.h"
18- #include < optional>
1917
20- // TODO: Move the parts that I am reusing from openmp-utils.h to
21- // evaluate/tools.h
22- #include " openmp-utils.h"
18+ #include < optional>
2319
2420#define CHECK_SIMPLE_CLAUSE (X, Y ) \
2521 void AccStructureChecker::Enter (const parser::AccClause::X &) { \
@@ -354,7 +350,7 @@ void AccStructureChecker::Leave(const parser::OpenACCAtomicConstruct &x) {
354350}
355351
356352void AccStructureChecker::CheckAtomicStmt (
357- const parser::AssignmentStmt &assign, std::string &construct) {
353+ const parser::AssignmentStmt &assign, const std::string &construct) {
358354 const auto &var{std::get<parser::Variable>(assign.t )};
359355 const auto &expr{std::get<parser::Expr>(assign.t )};
360356 const auto *rhs{GetExpr (context_, expr)};
@@ -376,38 +372,30 @@ void AccStructureChecker::CheckAtomicStmt(
376372 }
377373}
378374
375+ static constexpr evaluate::operation::OperatorSet validAccAtomicUpdateOperators{
376+ evaluate::operation::Operator::Add, evaluate::operation::Operator::Mul,
377+ evaluate::operation::Operator::Sub, evaluate::operation::Operator::Div,
378+ evaluate::operation::Operator::And, evaluate::operation::Operator::Or,
379+ evaluate::operation::Operator::Eqv, evaluate::operation::Operator::Neqv,
380+ evaluate::operation::Operator::Max, evaluate::operation::Operator::Min};
381+
379382static bool IsValidAtomicUpdateOperation (
380383 const evaluate::operation::Operator &op) {
381- switch (op) {
382- case evaluate::operation::Operator::Add:
383- case evaluate::operation::Operator::Mul:
384- case evaluate::operation::Operator::Sub:
385- case evaluate::operation::Operator::Div:
386- case evaluate::operation::Operator::And:
387- case evaluate::operation::Operator::Or:
388- case evaluate::operation::Operator::Eqv:
389- case evaluate::operation::Operator::Neqv:
390- // 2909 intrinsic-procedure name is one of max, min, iand, ior, or ieor.
391- case evaluate::operation::Operator::Max:
392- case evaluate::operation::Operator::Min:
393- // Currently all get mapped to And, Or, and Neqv
394- // case evaluate::operation::Operator::Iand:
395- // case evaluate::operation::Operator::Ior:
396- // case evaluate::operation::Operator::Ieor:
397- return true ;
398- case evaluate::operation::Operator::Convert:
399- case evaluate::operation::Operator::Identity:
400- default :
401- return false ;
402- }
384+ return validAccAtomicUpdateOperators.test (op);
403385}
404386
387+ // Couldn't reproduce this behavior with evaluate::UnwrapConvertedExpr which
388+ // is similar but only works within a single type category.
405389static SomeExpr GetExprModuloConversion (const SomeExpr &expr) {
406390 const auto [op, args]{evaluate::GetTopLevelOperation (expr)};
407391 // Check: if it is a conversion then it must have at least one argument.
408- CHECK ((op != evaluate::operation::Operator::Convert || args.size () >= 1 ) &&
392+ CHECK (((op != evaluate::operation::Operator::Convert &&
393+ op != evaluate::operation::Operator::Resize) ||
394+ args.size () >= 1 ) &&
409395 " Invalid conversion operation" );
410- if (op == evaluate::operation::Operator::Convert && args.size () == 1 ) {
396+ if ((op == evaluate::operation::Operator::Convert ||
397+ op == evaluate::operation::Operator::Resize) &&
398+ args.size () >= 1 ) {
411399 return args[0 ];
412400 }
413401 return expr;
@@ -416,17 +404,15 @@ static SomeExpr GetExprModuloConversion(const SomeExpr &expr) {
416404void AccStructureChecker::CheckAtomicUpdateStmt (
417405 const parser::AssignmentStmt &assign, const SomeExpr &updateVar,
418406 const SomeExpr *captureVar) {
419- static std::string construct{" update" };
420- CheckAtomicStmt (assign, construct);
407+ CheckAtomicStmt (assign, " update" );
421408 const auto &expr{std::get<parser::Expr>(assign.t )};
422409 const auto *rhs{GetExpr (context_, expr)};
423410 if (rhs) {
424411 const auto [op, args]{
425412 evaluate::GetTopLevelOperation (GetExprModuloConversion (*rhs))};
426413 if (!IsValidAtomicUpdateOperation (op)) {
427414 context_.Say (expr.source ,
428- " Invalid atomic update operation, can only use: *, +, -, *, /, and, or, eqv, neqv, max, min, iand, ior, ieor" _err_en_US,
429- construct);
415+ " Invalid atomic update operation, can only use: *, +, -, *, /, and, or, eqv, neqv, max, min, iand, ior, ieor" _err_en_US);
430416 } else {
431417 bool foundUpdateVar{false };
432418 for (const auto &arg : args) {
@@ -458,8 +444,7 @@ void AccStructureChecker::CheckAtomicUpdateStmt(
458444void AccStructureChecker::CheckAtomicWriteStmt (
459445 const parser::AssignmentStmt &assign, const SomeExpr &updateVar,
460446 const SomeExpr *captureVar) {
461- static std::string construct{" write" };
462- CheckAtomicStmt (assign, construct);
447+ CheckAtomicStmt (assign, " write" );
463448 const auto &expr{std::get<parser::Expr>(assign.t )};
464449 const auto *rhs{GetExpr (context_, expr)};
465450 if (rhs) {
@@ -474,15 +459,16 @@ void AccStructureChecker::CheckAtomicWriteStmt(
474459void AccStructureChecker::CheckAtomicCaptureStmt (
475460 const parser::AssignmentStmt &assign, const SomeExpr *updateVar,
476461 const SomeExpr &captureVar) {
477- static std::string construct{" capture" };
478- CheckAtomicStmt (assign, construct);
462+ CheckAtomicStmt (assign, " capture" );
479463}
480464
481465void AccStructureChecker::Enter (const parser::AccAtomicCapture &capture) {
482- const Fortran::parser::AssignmentStmt &stmt1 =
483- std::get<Fortran::parser::AccAtomicCapture::Stmt1>(capture.t ).v .statement ;
484- const Fortran::parser::AssignmentStmt &stmt2 =
485- std::get<Fortran::parser::AccAtomicCapture::Stmt2>(capture.t ).v .statement ;
466+ const Fortran::parser::AssignmentStmt &stmt1{
467+ std::get<Fortran::parser::AccAtomicCapture::Stmt1>(capture.t )
468+ .v .statement };
469+ const Fortran::parser::AssignmentStmt &stmt2{
470+ std::get<Fortran::parser::AccAtomicCapture::Stmt2>(capture.t )
471+ .v .statement };
486472 const auto &var1{std::get<parser::Variable>(stmt1.t )};
487473 const auto &var2{std::get<parser::Variable>(stmt2.t )};
488474 const auto *lhs1{GetExpr (context_, var1)};
@@ -507,7 +493,7 @@ void AccStructureChecker::Enter(const parser::AccAtomicCapture &capture) {
507493 bool stmt2CapturesLhs1{*lhs1 == GetExprModuloConversion (*rhs2)};
508494 if (stmt1CapturesLhs2 && !stmt2CapturesLhs1) {
509495 if (*lhs2 == GetExprModuloConversion (*rhs2)) {
510- // a = b; b = b; Doesn't fit the spec;
496+ // a = b; b = b: Doesn't fit the spec.
511497 context_.Say (std::get<parser::Verbatim>(capture.t ).source ,
512498 " The assignments in this atomic capture construct do not update a variable and capture either its initial or final value" _err_en_US);
513499 // TODO: Add attatchment that a = b seems to be a capture,
@@ -533,14 +519,14 @@ void AccStructureChecker::Enter(const parser::AccAtomicCapture &capture) {
533519 // Add attatchment that a = a is not considered an update,
534520 // but b = a seems to be a capture.
535521 } else {
536- // Take x = <expr>; v = x; as update; capture
522+ // Take x = <expr>; v = x: as update; capture
537523 const auto &updateVar{*lhs1};
538524 const auto &captureVar{*lhs2};
539525 CheckAtomicUpdateStmt (stmt1, updateVar, &captureVar);
540526 CheckAtomicCaptureStmt (stmt2, &updateVar, captureVar);
541527 }
542528 } else if (stmt1CapturesLhs2 && stmt2CapturesLhs1) {
543- // x1 = x2; x2 = x1; Doesn't fit the spec;
529+ // x1 = x2; x2 = x1; Doesn't fit the spec.
544530 context_.Say (std::get<parser::Verbatim>(capture.t ).source ,
545531 " The assignments in this atomic capture construct do not update a variable and capture either its initial or final value" _err_en_US);
546532 // TODO: Add attatchment that both assignments seem to be captures.
@@ -550,40 +536,33 @@ void AccStructureChecker::Enter(const parser::AccAtomicCapture &capture) {
550536 " The assignments in this atomic capture construct do not update a variable and capture either its initial or final value" _err_en_US);
551537 // TODO: Add attatchment that neither assignment seems to be a capture.
552538 }
553- return ;
554539}
555540
556541void AccStructureChecker::Enter (const parser::AccAtomicUpdate &x) {
557542 const auto &assign{
558543 std::get<parser::Statement<parser::AssignmentStmt>>(x.t ).statement };
559544 const auto &var{std::get<parser::Variable>(assign.t )};
560- const auto *updateVar{GetExpr (context_, var)};
561- if (!updateVar) {
562- return ;
545+ if (const auto *updateVar{GetExpr (context_, var)}) {
546+ CheckAtomicUpdateStmt (assign, *updateVar, /* captureVar=*/ nullptr );
563547 }
564- CheckAtomicUpdateStmt (assign, *updateVar, nullptr );
565548}
566549
567550void AccStructureChecker::Enter (const parser::AccAtomicWrite &x) {
568551 const auto &assign{
569552 std::get<parser::Statement<parser::AssignmentStmt>>(x.t ).statement };
570553 const auto &var{std::get<parser::Variable>(assign.t )};
571- const auto *updateVar{GetExpr (context_, var)};
572- if (!updateVar) {
573- return ;
554+ if (const auto *updateVar{GetExpr (context_, var)}) {
555+ CheckAtomicWriteStmt (assign, *updateVar, /* captureVar=*/ nullptr );
574556 }
575- CheckAtomicWriteStmt (assign, *updateVar, nullptr );
576557}
577558
578559void AccStructureChecker::Enter (const parser::AccAtomicRead &x) {
579560 const auto &assign{
580561 std::get<parser::Statement<parser::AssignmentStmt>>(x.t ).statement };
581562 const auto &var{std::get<parser::Variable>(assign.t )};
582- const auto *captureVar{GetExpr (context_, var)};
583- if (!captureVar) {
584- return ;
563+ if (const auto *captureVar{GetExpr (context_, var)}) {
564+ CheckAtomicCaptureStmt (assign, /* updateVar=*/ nullptr , *captureVar);
585565 }
586- CheckAtomicCaptureStmt (assign, nullptr , *captureVar);
587566}
588567
589568void AccStructureChecker::Enter (const parser::OpenACCCacheConstruct &x) {
0 commit comments