| 1 | //===-- lib/Parser/openacc-parsers.cpp ------------------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | // Top-level grammar specification for OpenACC 3.3. |
| 10 | |
| 11 | #include "basic-parsers.h" |
| 12 | #include "expr-parsers.h" |
| 13 | #include "misc-parsers.h" |
| 14 | #include "stmt-parser.h" |
| 15 | #include "token-parsers.h" |
| 16 | #include "type-parser-implementation.h" |
| 17 | #include "flang/Parser/parse-tree.h" |
| 18 | |
| 19 | // OpenACC Directives and Clauses |
| 20 | namespace Fortran::parser { |
| 21 | |
| 22 | // Only need to handle ! line comments because prescanning normalizes the |
| 23 | // other types of line comments from fixed form. |
| 24 | constexpr auto startAccLine{skipStuffBeforeStatement >> |
| 25 | withMessage( |
| 26 | "expected OpenACC directive sentinel: !$ACC, C$ACC, or *$ACC"_err_en_US , |
| 27 | "!$ACC "_sptok )}; |
| 28 | constexpr auto endAccLine{space >> |
| 29 | recovery( |
| 30 | withMessage("expected end of OpenACC directive"_err_en_US , endOfLine), |
| 31 | SkipTo<'\n'>{} || ok)}; |
| 32 | |
| 33 | // Autogenerated clauses parser. Information is taken from ACC.td and the |
| 34 | // parser is generated by tablegen. |
| 35 | // Scalar value parsers are provided by Flang directly. Specific value parsers |
| 36 | // are provided below. |
| 37 | #define GEN_FLANG_CLAUSES_PARSER |
| 38 | #include "llvm/Frontend/OpenACC/ACC.inc" |
| 39 | |
| 40 | TYPE_PARSER( |
| 41 | construct<AccObject>(designator) || construct<AccObject>("/" >> name / "/" )) |
| 42 | |
| 43 | TYPE_PARSER(construct<AccObjectList>(nonemptyList(Parser<AccObject>{}))) |
| 44 | |
| 45 | TYPE_PARSER(construct<AccObjectListWithModifier>( |
| 46 | maybe(Parser<AccDataModifier>{}), Parser<AccObjectList>{})) |
| 47 | |
| 48 | TYPE_PARSER(construct<AccObjectListWithReduction>( |
| 49 | Parser<ReductionOperator>{} / ":" , Parser<AccObjectList>{})) |
| 50 | |
| 51 | // 2.16 (3249) wait-argument is: |
| 52 | // [devnum : int-expr :] [queues :] int-expr-list |
| 53 | TYPE_PARSER(construct<AccWaitArgument>(maybe("DEVNUM:" >> scalarIntExpr / ":" ), |
| 54 | "QUEUES:" >> nonemptyList(scalarIntExpr) || nonemptyList(scalarIntExpr))) |
| 55 | |
| 56 | // 2.9 (1984-1986) size-expr is one of: |
| 57 | // * (represented as an empty std::optional<ScalarIntExpr>) |
| 58 | // int-expr |
| 59 | TYPE_PARSER(construct<AccSizeExpr>(scalarIntExpr) || |
| 60 | construct<AccSizeExpr>("*" >> construct<std::optional<ScalarIntExpr>>())) |
| 61 | TYPE_PARSER(construct<AccSizeExprList>(nonemptyList(Parser<AccSizeExpr>{}))) |
| 62 | |
| 63 | TYPE_PARSER(sourced(construct<AccDeviceTypeExpr>( |
| 64 | first("*" >> pure(Fortran::common::OpenACCDeviceType::Star), |
| 65 | "DEFAULT" >> pure(Fortran::common::OpenACCDeviceType::Default), |
| 66 | "NVIDIA" >> pure(Fortran::common::OpenACCDeviceType::Nvidia), |
| 67 | "ACC_DEVICE_NVIDIA" >> pure(Fortran::common::OpenACCDeviceType::Nvidia), |
| 68 | "RADEON" >> pure(Fortran::common::OpenACCDeviceType::Radeon), |
| 69 | "HOST" >> pure(Fortran::common::OpenACCDeviceType::Host), |
| 70 | "MULTICORE" >> pure(Fortran::common::OpenACCDeviceType::Multicore))))) |
| 71 | |
| 72 | TYPE_PARSER( |
| 73 | construct<AccDeviceTypeExprList>(nonemptyList(Parser<AccDeviceTypeExpr>{}))) |
| 74 | |
| 75 | // tile size is one of: |
| 76 | // * (represented as an empty std::optional<ScalarIntExpr>) |
| 77 | // constant-int-expr |
| 78 | TYPE_PARSER(construct<AccTileExpr>(scalarIntConstantExpr) || |
| 79 | construct<AccTileExpr>( |
| 80 | "*" >> construct<std::optional<ScalarIntConstantExpr>>())) |
| 81 | TYPE_PARSER(construct<AccTileExprList>(nonemptyList(Parser<AccTileExpr>{}))) |
| 82 | |
| 83 | // 2.9 (1979-1982) gang-arg is one of : |
| 84 | // [num:]int-expr |
| 85 | // dim:int-expr |
| 86 | // static:size-expr |
| 87 | TYPE_PARSER(construct<AccGangArg>(construct<AccGangArg::Static>( |
| 88 | "STATIC: " >> Parser<AccSizeExpr>{})) || |
| 89 | construct<AccGangArg>( |
| 90 | construct<AccGangArg::Dim>("DIM: " >> scalarIntExpr)) || |
| 91 | construct<AccGangArg>( |
| 92 | construct<AccGangArg::Num>(maybe("NUM: "_tok ) >> scalarIntExpr))) |
| 93 | |
| 94 | // 2.9 gang-arg-list |
| 95 | TYPE_PARSER( |
| 96 | construct<AccGangArgList>(many(maybe(","_tok ) >> Parser<AccGangArg>{}))) |
| 97 | |
| 98 | // 2.9.1 collapse |
| 99 | TYPE_PARSER(construct<AccCollapseArg>( |
| 100 | "FORCE:"_tok >> pure(true) || pure(false), scalarIntConstantExpr)) |
| 101 | |
| 102 | // 2.5.15 Reduction, F'2023 R1131, and CUF reduction-op |
| 103 | // Operator for reduction |
| 104 | TYPE_PARSER(sourced(construct<ReductionOperator>( |
| 105 | first("+" >> pure(ReductionOperator::Operator::Plus), |
| 106 | "*" >> pure(ReductionOperator::Operator::Multiply), |
| 107 | "MAX" >> pure(ReductionOperator::Operator::Max), |
| 108 | "MIN" >> pure(ReductionOperator::Operator::Min), |
| 109 | "IAND" >> pure(ReductionOperator::Operator::Iand), |
| 110 | "IOR" >> pure(ReductionOperator::Operator::Ior), |
| 111 | "IEOR" >> pure(ReductionOperator::Operator::Ieor), |
| 112 | ".AND." >> pure(ReductionOperator::Operator::And), |
| 113 | ".OR." >> pure(ReductionOperator::Operator::Or), |
| 114 | ".EQV." >> pure(ReductionOperator::Operator::Eqv), |
| 115 | ".NEQV." >> pure(ReductionOperator::Operator::Neqv))))) |
| 116 | |
| 117 | // 2.15.1 Bind clause |
| 118 | TYPE_PARSER(sourced(construct<AccBindClause>(name)) || |
| 119 | sourced(construct<AccBindClause>(scalarDefaultCharExpr))) |
| 120 | |
| 121 | // 2.5.16 Default clause |
| 122 | TYPE_PARSER(construct<AccDefaultClause>( |
| 123 | first("NONE" >> pure(llvm::acc::DefaultValue::ACC_Default_none), |
| 124 | "PRESENT" >> pure(llvm::acc::DefaultValue::ACC_Default_present)))) |
| 125 | |
| 126 | // SELF clause is either a simple optional condition for compute construct |
| 127 | // or a synonym of the HOST clause for the update directive 2.14.4 holding |
| 128 | // an object list. |
| 129 | TYPE_PARSER( |
| 130 | construct<AccSelfClause>(Parser<AccObjectList>{}) / lookAhead(")"_tok ) || |
| 131 | construct<AccSelfClause>(scalarLogicalExpr / lookAhead(")"_tok )) || |
| 132 | construct<AccSelfClause>( |
| 133 | recovery(fail<std::optional<ScalarLogicalExpr>>( |
| 134 | "logical expression or object list expected"_err_en_US ), |
| 135 | SkipTo<')'>{} >> pure<std::optional<ScalarLogicalExpr>>()))) |
| 136 | |
| 137 | // Modifier for copyin, copyout, cache and create |
| 138 | TYPE_PARSER(construct<AccDataModifier>( |
| 139 | first("ZERO:" >> pure(AccDataModifier::Modifier::Zero), |
| 140 | "READONLY:" >> pure(AccDataModifier::Modifier::ReadOnly)))) |
| 141 | |
| 142 | // Combined directives |
| 143 | TYPE_PARSER(sourced(construct<AccCombinedDirective>( |
| 144 | first("KERNELS LOOP" >> pure(llvm::acc::Directive::ACCD_kernels_loop), |
| 145 | "PARALLEL LOOP" >> pure(llvm::acc::Directive::ACCD_parallel_loop), |
| 146 | "SERIAL LOOP" >> pure(llvm::acc::Directive::ACCD_serial_loop))))) |
| 147 | |
| 148 | // Block directives |
| 149 | TYPE_PARSER(sourced(construct<AccBlockDirective>( |
| 150 | first("DATA" >> pure(llvm::acc::Directive::ACCD_data), |
| 151 | "HOST_DATA" >> pure(llvm::acc::Directive::ACCD_host_data), |
| 152 | "KERNELS" >> pure(llvm::acc::Directive::ACCD_kernels), |
| 153 | "PARALLEL" >> pure(llvm::acc::Directive::ACCD_parallel), |
| 154 | "SERIAL" >> pure(llvm::acc::Directive::ACCD_serial))))) |
| 155 | |
| 156 | // Standalone directives |
| 157 | TYPE_PARSER(sourced(construct<AccStandaloneDirective>( |
| 158 | first("ENTER DATA" >> pure(llvm::acc::Directive::ACCD_enter_data), |
| 159 | "EXIT DATA" >> pure(llvm::acc::Directive::ACCD_exit_data), |
| 160 | "INIT" >> pure(llvm::acc::Directive::ACCD_init), |
| 161 | "SHUTDOWN" >> pure(llvm::acc::Directive::ACCD_shutdown), |
| 162 | "SET" >> pure(llvm::acc::Directive::ACCD_set), |
| 163 | "UPDATE" >> pure(llvm::acc::Directive::ACCD_update))))) |
| 164 | |
| 165 | // Loop directives |
| 166 | TYPE_PARSER(sourced(construct<AccLoopDirective>( |
| 167 | first("LOOP" >> pure(llvm::acc::Directive::ACCD_loop))))) |
| 168 | |
| 169 | TYPE_PARSER(construct<AccBeginLoopDirective>( |
| 170 | sourced(Parser<AccLoopDirective>{}), Parser<AccClauseList>{})) |
| 171 | |
| 172 | TYPE_PARSER(construct<AccEndLoop>("END LOOP"_tok )) |
| 173 | |
| 174 | TYPE_PARSER(construct<OpenACCLoopConstruct>( |
| 175 | sourced(Parser<AccBeginLoopDirective>{} / endAccLine), |
| 176 | maybe(Parser<DoConstruct>{}), |
| 177 | maybe(startAccLine >> Parser<AccEndLoop>{} / endAccLine))) |
| 178 | |
| 179 | // 2.15.1 Routine directive |
| 180 | TYPE_PARSER(sourced(construct<OpenACCRoutineConstruct>(verbatim("ROUTINE"_tok ), |
| 181 | maybe(parenthesized(name)), Parser<AccClauseList>{}))) |
| 182 | |
| 183 | // 2.10 Cache directive |
| 184 | TYPE_PARSER(sourced( |
| 185 | construct<OpenACCCacheConstruct>(sourced(construct<Verbatim>("CACHE"_tok )), |
| 186 | parenthesized(Parser<AccObjectListWithModifier>{})))) |
| 187 | |
| 188 | // 2.11 Combined constructs |
| 189 | TYPE_PARSER(construct<AccBeginCombinedDirective>( |
| 190 | sourced(Parser<AccCombinedDirective>{}), Parser<AccClauseList>{})) |
| 191 | |
| 192 | // 2.12 Atomic constructs |
| 193 | TYPE_PARSER(construct<AccEndAtomic>(startAccLine >> "END ATOMIC"_tok )) |
| 194 | |
| 195 | TYPE_PARSER("ATOMIC" >> construct<AccAtomicRead>(verbatim("READ"_tok ), |
| 196 | Parser<AccClauseList>{} / endAccLine, |
| 197 | statement(assignmentStmt), |
| 198 | maybe(Parser<AccEndAtomic>{} / endAccLine))) |
| 199 | |
| 200 | TYPE_PARSER("ATOMIC" >> construct<AccAtomicWrite>(verbatim("WRITE"_tok ), |
| 201 | Parser<AccClauseList>{} / endAccLine, |
| 202 | statement(assignmentStmt), |
| 203 | maybe(Parser<AccEndAtomic>{} / endAccLine))) |
| 204 | |
| 205 | TYPE_PARSER("ATOMIC" >> |
| 206 | construct<AccAtomicUpdate>(maybe(verbatim("UPDATE"_tok )), |
| 207 | Parser<AccClauseList>{} / endAccLine, statement(assignmentStmt), |
| 208 | maybe(Parser<AccEndAtomic>{} / endAccLine))) |
| 209 | |
| 210 | TYPE_PARSER("ATOMIC" >> |
| 211 | construct<AccAtomicCapture>(verbatim("CAPTURE"_tok ), |
| 212 | Parser<AccClauseList>{} / endAccLine, statement(assignmentStmt), |
| 213 | statement(assignmentStmt), Parser<AccEndAtomic>{} / endAccLine)) |
| 214 | |
| 215 | TYPE_PARSER( |
| 216 | sourced(construct<OpenACCAtomicConstruct>(Parser<AccAtomicRead>{})) || |
| 217 | sourced(construct<OpenACCAtomicConstruct>(Parser<AccAtomicCapture>{})) || |
| 218 | sourced(construct<OpenACCAtomicConstruct>(Parser<AccAtomicWrite>{})) || |
| 219 | sourced(construct<OpenACCAtomicConstruct>(Parser<AccAtomicUpdate>{}))) |
| 220 | |
| 221 | // 2.13 Declare constructs |
| 222 | TYPE_PARSER(sourced(construct<AccDeclarativeDirective>( |
| 223 | first("DECLARE" >> pure(llvm::acc::Directive::ACCD_declare))))) |
| 224 | |
| 225 | // [Clause, [Clause], ...] |
| 226 | TYPE_PARSER(sourced(construct<AccClauseList>( |
| 227 | many(maybe(","_tok ) >> sourced(Parser<AccClause>{}))))) |
| 228 | |
| 229 | // 2.16.3 Wait directive |
| 230 | TYPE_PARSER(sourced(construct<OpenACCWaitConstruct>( |
| 231 | sourced(construct<Verbatim>("WAIT"_tok )), |
| 232 | maybe(parenthesized(Parser<AccWaitArgument>{})), Parser<AccClauseList>{}))) |
| 233 | |
| 234 | // Block Constructs |
| 235 | TYPE_PARSER(sourced(construct<AccBeginBlockDirective>( |
| 236 | sourced(Parser<AccBlockDirective>{}), Parser<AccClauseList>{}))) |
| 237 | |
| 238 | TYPE_PARSER(startAccLine >> sourced(construct<AccEndBlockDirective>("END"_tok >> |
| 239 | recovery(sourced(Parser<AccBlockDirective>{}), |
| 240 | construct<AccBlockDirective>(pure( |
| 241 | llvm::acc::Directive::ACCD_data)))))) |
| 242 | |
| 243 | TYPE_PARSER(construct<OpenACCBlockConstruct>( |
| 244 | Parser<AccBeginBlockDirective>{} / endAccLine, block, |
| 245 | // NB, This allows mismatched directives, but semantics checks that they |
| 246 | // match. |
| 247 | recovery(withMessage("expected OpenACC end block directive"_err_en_US , |
| 248 | attempt(Parser<AccEndBlockDirective>{} / endAccLine)), |
| 249 | construct<AccEndBlockDirective>(construct<AccBlockDirective>( |
| 250 | pure(llvm::acc::Directive::ACCD_data)))))) |
| 251 | |
| 252 | // Standalone constructs |
| 253 | TYPE_PARSER(construct<OpenACCStandaloneConstruct>( |
| 254 | sourced(Parser<AccStandaloneDirective>{}), Parser<AccClauseList>{})) |
| 255 | |
| 256 | // Standalone declarative constructs |
| 257 | TYPE_PARSER(construct<OpenACCStandaloneDeclarativeConstruct>( |
| 258 | sourced(Parser<AccDeclarativeDirective>{}), Parser<AccClauseList>{})) |
| 259 | |
| 260 | TYPE_PARSER(startAccLine >> |
| 261 | withMessage("expected OpenACC directive"_err_en_US , |
| 262 | first(sourced(construct<OpenACCDeclarativeConstruct>( |
| 263 | Parser<OpenACCStandaloneDeclarativeConstruct>{})), |
| 264 | sourced(construct<OpenACCDeclarativeConstruct>( |
| 265 | Parser<OpenACCRoutineConstruct>{}))))) |
| 266 | |
| 267 | TYPE_PARSER(sourced(construct<OpenACCEndConstruct>( |
| 268 | "END"_tok >> "LOOP"_tok >> pure(llvm::acc::Directive::ACCD_loop)))) |
| 269 | |
| 270 | // OpenACC constructs |
| 271 | TYPE_CONTEXT_PARSER("OpenACC construct"_en_US , |
| 272 | startAccLine >> |
| 273 | withMessage("expected OpenACC directive"_err_en_US , |
| 274 | // Combined constructs before block constructs so we try to match |
| 275 | // the longest possible match first. |
| 276 | first( |
| 277 | construct<OpenACCConstruct>(Parser<OpenACCCombinedConstruct>{}), |
| 278 | construct<OpenACCConstruct>(Parser<OpenACCBlockConstruct>{}), |
| 279 | construct<OpenACCConstruct>(Parser<OpenACCLoopConstruct>{}), |
| 280 | construct<OpenACCConstruct>( |
| 281 | Parser<OpenACCStandaloneConstruct>{}), |
| 282 | construct<OpenACCConstruct>(Parser<OpenACCCacheConstruct>{}), |
| 283 | construct<OpenACCConstruct>(Parser<OpenACCWaitConstruct>{}), |
| 284 | construct<OpenACCConstruct>(Parser<OpenACCAtomicConstruct>{}), |
| 285 | construct<OpenACCConstruct>(Parser<OpenACCEndConstruct>{})))) |
| 286 | |
| 287 | TYPE_PARSER(startAccLine >> |
| 288 | sourced(construct<AccEndCombinedDirective>(sourced("END"_tok >> |
| 289 | construct<AccCombinedDirective>("KERNELS"_tok >> maybe("LOOP"_tok ) >> |
| 290 | pure(llvm::acc::Directive::ACCD_kernels_loop) || |
| 291 | "PARALLEL"_tok >> maybe("LOOP"_tok ) >> |
| 292 | pure(llvm::acc::Directive::ACCD_parallel_loop) || |
| 293 | "SERIAL"_tok >> maybe("LOOP"_tok ) >> |
| 294 | pure(llvm::acc::Directive::ACCD_serial_loop)))))) |
| 295 | |
| 296 | TYPE_PARSER(construct<OpenACCCombinedConstruct>( |
| 297 | sourced(Parser<AccBeginCombinedDirective>{} / endAccLine), |
| 298 | maybe(Parser<DoConstruct>{}), |
| 299 | maybe(Parser<AccEndCombinedDirective>{} / endAccLine))) |
| 300 | |
| 301 | } // namespace Fortran::parser |
| 302 | |