Index: flang/include/flang/Parser/dump-parse-tree.h =================================================================== --- flang/include/flang/Parser/dump-parse-tree.h +++ flang/include/flang/Parser/dump-parse-tree.h @@ -500,6 +500,7 @@ NODE(parser, OmpLoopDirective) NODE(parser, OmpMapClause) NODE(parser, OmpMapType) + NODE(parser, OmpNontemporalClause) NODE(OmpMapType, Always) NODE_ENUM(OmpMapType, Type) static std::string GetNodeName(const llvm::omp::Clause &x) { Index: flang/include/flang/Parser/parse-tree.h =================================================================== --- flang/include/flang/Parser/parse-tree.h +++ flang/include/flang/Parser/parse-tree.h @@ -3376,6 +3376,13 @@ std::tuple, std::optional> t; }; +// nontemporal-clause -> NONTEMPORAL (variable-name-list) +struct OmpNontemporalClause { + TUPLE_CLASS_BOILERPLATE(OmpNontemporalClause); + CharBlock source; + std::tuple> t; +}; + // 2.15.3.7 linear-modifier -> REF | VAL | UVAL struct OmpLinearModifier { ENUM_CLASS(Type, Ref, Val, Uval) Index: flang/include/flang/Semantics/symbol.h =================================================================== --- flang/include/flang/Semantics/symbol.h +++ flang/include/flang/Semantics/symbol.h @@ -507,7 +507,7 @@ // OpenMP data-copying attribute OmpCopyIn, OmpCopyPrivate, // OpenMP miscellaneous flags - OmpCommonBlock, OmpReduction, OmpAligned, OmpAllocate, + OmpCommonBlock, OmpReduction, OmpAligned, OmpNontemporal, OmpAllocate, OmpDeclarativeAllocateDirective, OmpExecutableAllocateDirective, OmpDeclareSimd, OmpDeclareTarget, OmpThreadprivate, OmpDeclareReduction, OmpFlushed, OmpCriticalLock, OmpIfSpecified, OmpNone, OmpPreDetermined); Index: flang/lib/Parser/openmp-parsers.cpp =================================================================== --- flang/lib/Parser/openmp-parsers.cpp +++ flang/lib/Parser/openmp-parsers.cpp @@ -149,6 +149,9 @@ TYPE_PARSER(construct( nonemptyList(name), maybe(":" >> scalarIntConstantExpr))) +// NONTEMPORAL (list) +TYPE_PARSER(construct(nonemptyList(name))) + TYPE_PARSER( construct(designator) || construct("/" >> name / "/")) @@ -203,6 +206,8 @@ parenthesized(Parser{}))) || "MERGEABLE" >> construct(construct()) || "NOGROUP" >> construct(construct()) || + "NONTEMPORAL" >> construct(construct( + parenthesized(Parser{}))) || "NOTINBRANCH" >> construct(construct()) || "NOWAIT" >> construct(construct()) || Index: flang/lib/Parser/unparse.cpp =================================================================== --- flang/lib/Parser/unparse.cpp +++ flang/lib/Parser/unparse.cpp @@ -1990,6 +1990,9 @@ Walk(std::get>(x.t), ","); Walk(std::get>(x.t)); } + void Unparse(const OmpNontemporalClause &x) { + Walk(std::get>(x.t), ","); + } void Unparse(const OmpIfClause &x) { Walk(std::get>(x.t), ":"); Walk(std::get(x.t)); Index: flang/lib/Semantics/check-omp-structure.cpp =================================================================== --- flang/lib/Semantics/check-omp-structure.cpp +++ flang/lib/Semantics/check-omp-structure.cpp @@ -1060,7 +1060,6 @@ CHECK_SIMPLE_CLAUSE(InReduction, OMPC_in_reduction) CHECK_SIMPLE_CLAUSE(Inclusive, OMPC_inclusive) CHECK_SIMPLE_CLAUSE(Match, OMPC_match) -CHECK_SIMPLE_CLAUSE(Nontemporal, OMPC_nontemporal) CHECK_SIMPLE_CLAUSE(Order, OMPC_order) CHECK_SIMPLE_CLAUSE(Read, OMPC_read) CHECK_SIMPLE_CLAUSE(ReverseOffload, OMPC_reverse_offload) @@ -1426,6 +1425,9 @@ } // 2.8.1 TODO: list-item attribute check } +void OmpStructureChecker::Enter(const parser::OmpClause::Nontemporal &x) { + CheckAllowed(llvm::omp::Clause::OMPC_nontemporal); +} void OmpStructureChecker::Enter(const parser::OmpClause::Defaultmap &x) { CheckAllowed(llvm::omp::Clause::OMPC_defaultmap); using VariableCategory = parser::OmpDefaultmapClause::VariableCategory; Index: flang/lib/Semantics/resolve-directives.cpp =================================================================== --- flang/lib/Semantics/resolve-directives.cpp +++ flang/lib/Semantics/resolve-directives.cpp @@ -407,6 +407,13 @@ ResolveOmpNameList(alignedNameList, Symbol::Flag::OmpAligned); return false; } + + bool Pre(const parser::OmpNontemporalClause &x) { + const auto &nontemporalNameList{std::get>(x.t)}; + ResolveOmpNameList(nontemporalNameList, Symbol::Flag::OmpNontemporal); + return false; + } + void Post(const parser::Name &); // Keep track of labels in the statements that causes jumps to target labels Index: flang/test/Parser/omp-nontemporal-unparse.f90 =================================================================== --- /dev/null +++ flang/test/Parser/omp-nontemporal-unparse.f90 @@ -0,0 +1,19 @@ +! RUN: %flang_fc1 -fdebug-unparse-no-sema -fopenmp %s | FileCheck %s + +program omp_simd + integer i + integer, allocatable :: a(:) + + allocate(a(10)) + + !NONTEMPORAL + !$omp simd nontemporal(a) + do i = 1, 10 + a(i) = i + end do + !$omp end simd +end program omp_simd +!CHECK-LABEL: PROGRAM omp_simd + +!NONTEMPORAL +!CHECK: !$OMP SIMD NONTEMPORAL(a) Index: flang/test/Semantics/omp-nontemporal.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/omp-nontemporal.f90 @@ -0,0 +1,95 @@ +! RUN: %S/test_errors.sh %s %t %flang -fopenmp +! REQUIRES: shell +! Check OpenMP clause validity for NONTEMPORAL clause + +program omp_simd + integer i + integer, allocatable :: a(:) + + allocate(a(10)) + + !$omp simd nontemporal(a) + do i = 1, 10 + a(i) = i + end do + !$omp end simd + + !$omp parallel do simd nontemporal(a) + do i = 1, 10 + a(i) = i + end do + !$omp end parallel do simd + + !$omp parallel do simd nontemporal(a) + do i = 1, 10 + a(i) = i + end do + !$omp end parallel do simd + + !ERROR: NONTEMPORAL clause is not allowed on the DO SIMD directive + !$omp do simd nontemporal(a) + do i = 1, 10 + a(i) = i + end do + !$omp end do simd + + !$omp taskloop simd nontemporal(a) + do i = 1, 10 + a(i) = i + end do + !$omp end taskloop simd + + !$omp teams + !$omp distribute parallel do simd nontemporal(a) + do i = 1, 10 + a(i) = i + end do + !$omp end distribute parallel do simd + !$omp end teams + + !$omp teams + !$omp distribute simd nontemporal(a) + do i = 1, 10 + a(i) = i + end do + !$omp end distribute simd + !$omp end teams + + !$omp target parallel do simd nontemporal(a) + do i = 1, 10 + a(i) = i + end do + !$omp end target parallel do simd + + !$omp target simd nontemporal(a) + do i = 1, 10 + a(i) = i + end do + !$omp end target simd + + !$omp teams distribute simd nontemporal(a) + do i = 1, 10 + a(i) = i + end do + !$omp end teams distribute simd + + !$omp teams distribute parallel do simd nontemporal(a) + do i = 1, 10 + a(i) = i + end do + !$omp end teams distribute parallel do simd + + !$omp target teams distribute parallel do simd nontemporal(a) + do i = 1, 10 + a(i) = i + end do + !$omp end target teams distribute parallel do simd + + !$omp target teams distribute simd nontemporal(a) + do i = 1, 10 + a(i) = i + end do + !$omp end target teams distribute simd + + +end program omp_simd Index: llvm/include/llvm/Frontend/OpenMP/OMP.td =================================================================== --- llvm/include/llvm/Frontend/OpenMP/OMP.td +++ llvm/include/llvm/Frontend/OpenMP/OMP.td @@ -261,6 +261,7 @@ } def OMPC_NonTemporal : Clause<"nontemporal"> { let clangClass = "OMPNontemporalClause"; + let flangClass = "OmpNontemporalClause"; } def OMP_ORDER_concurrent : ClauseVal<"default",2,0> { let isDefault = 1; }