Index: flang/lib/Semantics/check-omp-structure.h =================================================================== --- flang/lib/Semantics/check-omp-structure.h +++ flang/lib/Semantics/check-omp-structure.h @@ -229,6 +229,10 @@ void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x); void CheckDoWhile(const parser::OpenMPLoopConstruct &x); void CheckCycleConstraints(const parser::OpenMPLoopConstruct &x); + template + bool CheckOperatorValidity(const T &, const D &); + template void CheckAtomicConstructStructure(T &); + void CheckAtomicConstructStructure(const parser::OpenMPAtomicConstruct &); void CheckDistLinear(const parser::OpenMPLoopConstruct &x); void CheckSIMDNest(const parser::OpenMPConstruct &x); void CheckTargetNest(const parser::OpenMPConstruct &x); Index: flang/lib/Semantics/check-omp-structure.cpp =================================================================== --- flang/lib/Semantics/check-omp-structure.cpp +++ flang/lib/Semantics/check-omp-structure.cpp @@ -1287,11 +1287,108 @@ } } +template +bool OmpStructureChecker::CheckOperatorValidity( + const T &node, const D &variable) { + using AllowedBinaryOperators = + std::variant; + using BinaryOperators = std::variant; + + if constexpr (common::HasMember) { + const auto &variableName{variable.GetSource().ToString()}; + const auto &exprLeft{std::get<0>(node.t)}; + const auto &exprRight{std::get<1>(node.t)}; + if ((exprLeft.value().source.ToString() != variableName) && + (exprRight.value().source.ToString() != variableName)) { + context_.Say(variable.GetSource(), + "Atomic update variable '%s' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct"_err_en_US, + variableName); + } + + if constexpr (common::HasMember) { + return true; + } else { + return false; + } + } + return true; +} +template +void OmpStructureChecker::CheckAtomicConstructStructure(T &construct) { + const auto &dir{std::get(construct.t)}; + PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_atomic); + const auto &assignment{ + std::get>(construct.t) + .statement}; + const auto &expr{std::get(assignment.t)}; + const auto &var{std::get(assignment.t)}; + std::visit( + common::visitors{ + [&](const common::Indirection &x) { + const auto &procedureDesignator{ + std::get(x.value().v.t)}; + const auto &argSpecs{ + std::get>(x.value().v.t)}; + const parser::Name *name{ + std::get_if(&procedureDesignator.u)}; + if (name && + !(name->source == "max" || name->source == "min" || + name->source == "iand" || name->source == "ior" || + name->source == "ieor")) { + context_.Say(expr.source, + "Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement"_err_en_US); + } else if (name) { + bool foundMatch{false}; + for (const auto &argSpec : argSpecs) { + const auto &arg{std::get(argSpec.t)}; + if (const auto *parsedExpr{ + std::get_if>( + &arg.u)}) { + auto it{parsedExpr->value().source.begin()}; + while (it != parsedExpr->value().source.end()) { + std::string iter_val{*it}; + if (var.GetSource().ToString() == iter_val) { + foundMatch = true; + } + ++it; + } + } + } + if (!foundMatch) { + context_.Say(expr.source, + "Atomic update variable '%s' not found in the argument list of intrinsic procedure"_err_en_US, + var.GetSource().ToString()); + } + } + }, + [&](const auto &x) { + if (!CheckOperatorValidity(x, var)) { + context_.Say(expr.source, + "Invalid operator in OpenMP ATOMIC construct UPDATE statement"_err_en_US); + } + }, + }, + expr.u); +} + void OmpStructureChecker::Enter(const parser::OpenMPAtomicConstruct &x) { std::visit( common::visitors{ - [&](const auto &someAtomicConstruct) { - const auto &dir{std::get(someAtomicConstruct.t)}; + [&](const parser::OmpAtomic &atomicConstruct) { + CheckAtomicConstructStructure(atomicConstruct); + }, + [&](const parser::OmpAtomicUpdate &atomicConstruct) { + CheckAtomicConstructStructure(atomicConstruct); + }, + [&](const auto &atomicConstruct) { + const auto &dir{std::get(atomicConstruct.t)}; PushContextAndClauseSets( dir.source, llvm::omp::Directive::OMPD_atomic); }, Index: flang/test/Semantics/omp-atomic02.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/omp-atomic02.f90 @@ -0,0 +1,109 @@ +! RUN: python %S/test_errors.py %s %flang -fopenmp + +! OpenMP Atomic construct +! section 2.17.7 +! operator is one of +, *, -, /, .AND., .OR., .EQV., or .NEQV + +program OmpAtomic + use omp_lib + CHARACTER c*3, d*3 + LOGICAL l, m, n + + a = 1 + b = 2 + c = 'foo' + d = 'bar' + m = .TRUE. + n = .FALSE. + !$omp parallel num_threads(4) + + !$omp atomic + a = a + (4*2) + !$omp atomic + a = a*(b + 1) + !$omp atomic + a = a - 3 + !$omp atomic + a = a/(b + 1) + !$omp atomic + !ERROR: Invalid operator in OpenMP ATOMIC construct UPDATE statement + a = a**4 + !$omp atomic + !ERROR: Invalid operator in OpenMP ATOMIC construct UPDATE statement + c = c//d + !$omp atomic + !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + !ERROR: Invalid operator in OpenMP ATOMIC construct UPDATE statement + l = a .LT. b + !$omp atomic + !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + !ERROR: Invalid operator in OpenMP ATOMIC construct UPDATE statement + l = a .LE. b + !$omp atomic + !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + !ERROR: Invalid operator in OpenMP ATOMIC construct UPDATE statement + l = a .EQ. b + !$omp atomic + !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + !ERROR: Invalid operator in OpenMP ATOMIC construct UPDATE statement + l = a .NE. b + !$omp atomic + !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + !ERROR: Invalid operator in OpenMP ATOMIC construct UPDATE statement + l = a .GE. b + !$omp atomic + !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + !ERROR: Invalid operator in OpenMP ATOMIC construct UPDATE statement + l = a .GT. b + !$omp atomic + m = m .AND. n + !$omp atomic + m = m .OR. n + !$omp atomic + m = m .EQV. n + !$omp atomic + m = m .NEQV. n + !$omp atomic update + a = a + (4*2) + !$omp atomic update + a = a*(b + 1) + !$omp atomic update + a = a - 3 + !$omp atomic update + a = a/(b + 1) + !$omp atomic update + !ERROR: Invalid operator in OpenMP ATOMIC construct UPDATE statement + a = a**4 + !$omp atomic update + !ERROR: Invalid operator in OpenMP ATOMIC construct UPDATE statement + c = c//d + !$omp atomic update + !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + !ERROR: Invalid operator in OpenMP ATOMIC construct UPDATE statement + l = a .LT. b + !$omp atomic update + !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + !ERROR: Invalid operator in OpenMP ATOMIC construct UPDATE statement + l = a .LE. b + !$omp atomic update + !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + !ERROR: Invalid operator in OpenMP ATOMIC construct UPDATE statement + l = a .EQ. b + !$omp atomic update + !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + !ERROR: Invalid operator in OpenMP ATOMIC construct UPDATE statement + l = a .GE. b + !$omp atomic update + !ERROR: Atomic update variable 'l' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + !ERROR: Invalid operator in OpenMP ATOMIC construct UPDATE statement + l = a .GT. b + !$omp atomic update + m = m .AND. n + !$omp atomic update + m = m .OR. n + !$omp atomic update + m = m .EQV. n + !$omp atomic update + m = m .NEQV. n + !$omp end parallel +end program OmpAtomic Index: flang/test/Semantics/omp-atomic03.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/omp-atomic03.f90 @@ -0,0 +1,164 @@ +! RUN: python %S/test_errors.py %s %flang -fopenmp + +! OpenMP Atomic construct +! section 2.17.7 +! Intrinsic procedure name is one of MAX, MIN, IAND, IOR, or IEOR. + +program OmpAtomic + use omp_lib + real x + integer :: y, z + x = 5.73 + y = 3 + z = 1 +!$omp atomic + y = IAND(y, 4) +!$omp atomic + y = IOR(y, 5) +!$omp atomic + y = IEOR(y, 6) +!$omp atomic + y = MAX(y, 7) +!$omp atomic + y = MIN(y, 8) + +!$omp atomic + !ERROR: Atomic update variable 'z' not found in the argument list of intrinsic procedure + z = IAND(y, 4) +!$omp atomic + !ERROR: Atomic update variable 'z' not found in the argument list of intrinsic procedure + z = IOR(y, 5) +!$omp atomic + !ERROR: Atomic update variable 'z' not found in the argument list of intrinsic procedure + z = IEOR(y, 6) +!$omp atomic + !ERROR: Atomic update variable 'z' not found in the argument list of intrinsic procedure + z = MAX(y, 7) +!$omp atomic + !ERROR: Atomic update variable 'z' not found in the argument list of intrinsic procedure + z = MIN(y, 8) + +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + y = MOD(y, 9) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = ABS(x) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = SQRT(x) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = SIN(x) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = COS(x) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = TAN(x) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = ASIN(x) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = ACOS(x) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = ATAN(x) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = EXP(x) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = LOG(x) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + y = INT(x) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + y = NINT(x) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + y = FLOOR(x) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + y = FRACTION(x) +!$omp atomic + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + y = REAL(x) +!$omp atomic update + y = IAND(y, 4) +!$omp atomic update + y = IOR(y, 5) +!$omp atomic update + y = IEOR(y, 6) +!$omp atomic update + y = MAX(y, 7) +!$omp atomic update + y = MIN(y, 8) + +!$omp atomic update + !ERROR: Atomic update variable 'z' not found in the argument list of intrinsic procedure + z = IAND(y, 4) +!$omp atomic update + !ERROR: Atomic update variable 'z' not found in the argument list of intrinsic procedure + z = IOR(y, 5) +!$omp atomic update + !ERROR: Atomic update variable 'z' not found in the argument list of intrinsic procedure + z = IEOR(y, 6) +!$omp atomic update + !ERROR: Atomic update variable 'z' not found in the argument list of intrinsic procedure + z = MAX(y, 7) +!$omp atomic update + !ERROR: Atomic update variable 'z' not found in the argument list of intrinsic procedure + z = MIN(y, 8) + +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + y = MOD(y, 9) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = ABS(x) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = SQRT(x) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = SIN(x) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = COS(x) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = TAN(x) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = ASIN(x) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = ACOS(x) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = ATAN(x) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = EXP(x) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + x = LOG(x) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + y = INT(x) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + y = NINT(x) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + y = FLOOR(x) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + y = FRACTION(x) +!$omp atomic update + !ERROR: Invalid intrinsic procedure name in OpenMP ATOMIC construct UPDATE statement + y = REAL(x) +end program OmpAtomic Index: flang/test/Semantics/omp-atomic04.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/omp-atomic04.f90 @@ -0,0 +1,168 @@ +! RUN: python %S/test_errors.py %s %flang -fopenmp + +! OpenMP Atomic construct +! section 2.17.7 +! Update assignment must be 'var = var op expr' or 'var = expr op var' + +program OmpAtomic + use omp_lib + real x + integer y + logical m, n, l + x = 5.73 + y = 3 + m = .TRUE. + n = .FALSE. +!$omp atomic + x = x + 1 +!$omp atomic + x = 1 + x +!$omp atomic + !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + x = y + 1 +!$omp atomic + !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + x = 1 + y + +!$omp atomic + x = x - 1 +!$omp atomic + x = 1 - x +!$omp atomic + !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + x = y - 1 +!$omp atomic + !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + x = 1 - y + +!$omp atomic + x = x*1 +!$omp atomic + x = 1*x +!$omp atomic + !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + x = y*1 +!$omp atomic + !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + x = 1*y + +!$omp atomic + x = x/1 +!$omp atomic + x = 1/x +!$omp atomic + !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + x = y/1 +!$omp atomic + !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + x = 1/y + +!$omp atomic + m = m .AND. n +!$omp atomic + m = n .AND. m +!$omp atomic + !ERROR: Atomic update variable 'm' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + m = n .AND. l + +!$omp atomic + m = m .OR. n +!$omp atomic + m = n .OR. m +!$omp atomic + !ERROR: Atomic update variable 'm' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + m = n .OR. l + +!$omp atomic + m = m .EQV. n +!$omp atomic + m = n .EQV. m +!$omp atomic + !ERROR: Atomic update variable 'm' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + m = n .EQV. l + +!$omp atomic + m = m .NEQV. n +!$omp atomic + m = n .NEQV. m +!$omp atomic + !ERROR: Atomic update variable 'm' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + m = n .NEQV. l + +!$omp atomic update + x = x + 1 +!$omp atomic update + x = 1 + x +!$omp atomic update + !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + x = y + 1 +!$omp atomic + !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + x = 1 + y + +!$omp atomic update + x = x - 1 +!$omp atomic update + x = 1 - x +!$omp atomic update + !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + x = y - 1 +!$omp atomic update + !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + x = 1 - y + +!$omp atomic update + x = x*1 +!$omp atomic update + x = 1*x +!$omp atomic update + !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + x = y*1 +!$omp atomic update + !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + x = 1*y + +!$omp atomic update + x = x/1 +!$omp atomic update + x = 1/x +!$omp atomic update + !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + x = y/1 +!$omp atomic update + !ERROR: Atomic update variable 'x' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + x = 1/y + +!$omp atomic update + m = m .AND. n +!$omp atomic update + m = n .AND. m +!$omp atomic update + !ERROR: Atomic update variable 'm' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + m = n .AND. l + +!$omp atomic update + m = m .OR. n +!$omp atomic update + m = n .OR. m +!$omp atomic update + !ERROR: Atomic update variable 'm' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + m = n .OR. l + +!$omp atomic update + m = m .EQV. n +!$omp atomic update + m = n .EQV. m +!$omp atomic update + !ERROR: Atomic update variable 'm' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + m = n .EQV. l + +!$omp atomic update + m = m .NEQV. n +!$omp atomic update + m = n .NEQV. m +!$omp atomic update + !ERROR: Atomic update variable 'm' not found in the RHS of the assignment statement in an ATOMIC UPDATE construct + m = n .NEQV. l + +end program OmpAtomic