//===-- lib/Parser/openacc-parsers.cpp ------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // Top-level grammar specification for OpenACC 3.3. #include "basic-parsers.h" #include "expr-parsers.h" #include "misc-parsers.h" #include "stmt-parser.h" #include "token-parsers.h" #include "type-parser-implementation.h" #include "flang/Parser/parse-tree.h" // OpenACC Directives and Clauses namespace Fortran::parser { // Only need to handle ! line comments because prescanning normalizes the // other types of line comments from fixed form. constexpr auto startAccLine{skipStuffBeforeStatement >> withMessage( "expected OpenACC directive sentinel: !$ACC, C$ACC, or *$ACC"_err_en_US, "!$ACC "_sptok)}; constexpr auto endAccLine{space >> recovery( withMessage("expected end of OpenACC directive"_err_en_US, endOfLine), SkipTo<'\n'>{} || ok)}; // Autogenerated clauses parser. Information is taken from ACC.td and the // parser is generated by tablegen. // Scalar value parsers are provided by Flang directly. Specific value parsers // are provided below. #define GEN_FLANG_CLAUSES_PARSER #include "llvm/Frontend/OpenACC/ACC.inc" TYPE_PARSER( construct(designator) || construct("/" >> name / "/")) TYPE_PARSER(construct(nonemptyList(Parser{}))) TYPE_PARSER(construct( maybe(Parser{}), Parser{})) TYPE_PARSER(construct( Parser{} / ":", Parser{})) // 2.16 (3249) wait-argument is: // [devnum : int-expr :] [queues :] int-expr-list TYPE_PARSER(construct(maybe("DEVNUM:" >> scalarIntExpr / ":"), "QUEUES:" >> nonemptyList(scalarIntExpr) || nonemptyList(scalarIntExpr))) // 2.9 (1984-1986) size-expr is one of: // * (represented as an empty std::optional) // int-expr TYPE_PARSER(construct(scalarIntExpr) || construct("*" >> construct>())) TYPE_PARSER(construct(nonemptyList(Parser{}))) TYPE_PARSER(sourced(construct( first("*" >> pure(Fortran::common::OpenACCDeviceType::Star), "DEFAULT" >> pure(Fortran::common::OpenACCDeviceType::Default), "NVIDIA" >> pure(Fortran::common::OpenACCDeviceType::Nvidia), "ACC_DEVICE_NVIDIA" >> pure(Fortran::common::OpenACCDeviceType::Nvidia), "RADEON" >> pure(Fortran::common::OpenACCDeviceType::Radeon), "HOST" >> pure(Fortran::common::OpenACCDeviceType::Host), "MULTICORE" >> pure(Fortran::common::OpenACCDeviceType::Multicore))))) TYPE_PARSER( construct(nonemptyList(Parser{}))) // tile size is one of: // * (represented as an empty std::optional) // constant-int-expr TYPE_PARSER(construct(scalarIntConstantExpr) || construct( "*" >> construct>())) TYPE_PARSER(construct(nonemptyList(Parser{}))) // 2.9 (1979-1982) gang-arg is one of : // [num:]int-expr // dim:int-expr // static:size-expr TYPE_PARSER(construct(construct( "STATIC: " >> Parser{})) || construct( construct("DIM: " >> scalarIntExpr)) || construct( construct(maybe("NUM: "_tok) >> scalarIntExpr))) // 2.9 gang-arg-list TYPE_PARSER( construct(many(maybe(","_tok) >> Parser{}))) // 2.9.1 collapse TYPE_PARSER(construct( "FORCE:"_tok >> pure(true) || pure(false), scalarIntConstantExpr)) // 2.5.15 Reduction, F'2023 R1131, and CUF reduction-op // Operator for reduction TYPE_PARSER(sourced(construct( first("+" >> pure(ReductionOperator::Operator::Plus), "*" >> pure(ReductionOperator::Operator::Multiply), "MAX" >> pure(ReductionOperator::Operator::Max), "MIN" >> pure(ReductionOperator::Operator::Min), "IAND" >> pure(ReductionOperator::Operator::Iand), "IOR" >> pure(ReductionOperator::Operator::Ior), "IEOR" >> pure(ReductionOperator::Operator::Ieor), ".AND." >> pure(ReductionOperator::Operator::And), ".OR." >> pure(ReductionOperator::Operator::Or), ".EQV." >> pure(ReductionOperator::Operator::Eqv), ".NEQV." >> pure(ReductionOperator::Operator::Neqv))))) // 2.15.1 Bind clause TYPE_PARSER(sourced(construct(name)) || sourced(construct(scalarDefaultCharExpr))) // 2.5.16 Default clause TYPE_PARSER(construct( first("NONE" >> pure(llvm::acc::DefaultValue::ACC_Default_none), "PRESENT" >> pure(llvm::acc::DefaultValue::ACC_Default_present)))) // SELF clause is either a simple optional condition for compute construct // or a synonym of the HOST clause for the update directive 2.14.4 holding // an object list. TYPE_PARSER( construct(Parser{}) / lookAhead(")"_tok) || construct(scalarLogicalExpr / lookAhead(")"_tok)) || construct( recovery(fail>( "logical expression or object list expected"_err_en_US), SkipTo<')'>{} >> pure>()))) // Modifier for copyin, copyout, cache and create TYPE_PARSER(construct( first("ZERO:" >> pure(AccDataModifier::Modifier::Zero), "READONLY:" >> pure(AccDataModifier::Modifier::ReadOnly)))) // Combined directives TYPE_PARSER(sourced(construct( first("KERNELS LOOP" >> pure(llvm::acc::Directive::ACCD_kernels_loop), "PARALLEL LOOP" >> pure(llvm::acc::Directive::ACCD_parallel_loop), "SERIAL LOOP" >> pure(llvm::acc::Directive::ACCD_serial_loop))))) // Block directives TYPE_PARSER(sourced(construct( first("DATA" >> pure(llvm::acc::Directive::ACCD_data), "HOST_DATA" >> pure(llvm::acc::Directive::ACCD_host_data), "KERNELS" >> pure(llvm::acc::Directive::ACCD_kernels), "PARALLEL" >> pure(llvm::acc::Directive::ACCD_parallel), "SERIAL" >> pure(llvm::acc::Directive::ACCD_serial))))) // Standalone directives TYPE_PARSER(sourced(construct( first("ENTER DATA" >> pure(llvm::acc::Directive::ACCD_enter_data), "EXIT DATA" >> pure(llvm::acc::Directive::ACCD_exit_data), "INIT" >> pure(llvm::acc::Directive::ACCD_init), "SHUTDOWN" >> pure(llvm::acc::Directive::ACCD_shutdown), "SET" >> pure(llvm::acc::Directive::ACCD_set), "UPDATE" >> pure(llvm::acc::Directive::ACCD_update))))) // Loop directives TYPE_PARSER(sourced(construct( first("LOOP" >> pure(llvm::acc::Directive::ACCD_loop))))) TYPE_PARSER(construct( sourced(Parser{}), Parser{})) TYPE_PARSER(construct("END LOOP"_tok)) TYPE_PARSER(construct( sourced(Parser{} / endAccLine), maybe(Parser{}), maybe(startAccLine >> Parser{} / endAccLine))) // 2.15.1 Routine directive TYPE_PARSER(sourced(construct(verbatim("ROUTINE"_tok), maybe(parenthesized(name)), Parser{}))) // 2.10 Cache directive TYPE_PARSER(sourced( construct(sourced(construct("CACHE"_tok)), parenthesized(Parser{})))) // 2.11 Combined constructs TYPE_PARSER(construct( sourced(Parser{}), Parser{})) // 2.12 Atomic constructs TYPE_PARSER(construct(startAccLine >> "END ATOMIC"_tok)) TYPE_PARSER("ATOMIC" >> construct(verbatim("READ"_tok), Parser{} / endAccLine, statement(assignmentStmt), maybe(Parser{} / endAccLine))) TYPE_PARSER("ATOMIC" >> construct(verbatim("WRITE"_tok), Parser{} / endAccLine, statement(assignmentStmt), maybe(Parser{} / endAccLine))) TYPE_PARSER("ATOMIC" >> construct(maybe(verbatim("UPDATE"_tok)), Parser{} / endAccLine, statement(assignmentStmt), maybe(Parser{} / endAccLine))) TYPE_PARSER("ATOMIC" >> construct(verbatim("CAPTURE"_tok), Parser{} / endAccLine, statement(assignmentStmt), statement(assignmentStmt), Parser{} / endAccLine)) TYPE_PARSER( sourced(construct(Parser{})) || sourced(construct(Parser{})) || sourced(construct(Parser{})) || sourced(construct(Parser{}))) // 2.13 Declare constructs TYPE_PARSER(sourced(construct( first("DECLARE" >> pure(llvm::acc::Directive::ACCD_declare))))) // [Clause, [Clause], ...] TYPE_PARSER(sourced(construct( many(maybe(","_tok) >> sourced(Parser{}))))) // 2.16.3 Wait directive TYPE_PARSER(sourced(construct( sourced(construct("WAIT"_tok)), maybe(parenthesized(Parser{})), Parser{}))) // Block Constructs TYPE_PARSER(sourced(construct( sourced(Parser{}), Parser{}))) TYPE_PARSER(startAccLine >> sourced(construct("END"_tok >> recovery(sourced(Parser{}), construct(pure( llvm::acc::Directive::ACCD_data)))))) TYPE_PARSER(construct( Parser{} / endAccLine, block, // NB, This allows mismatched directives, but semantics checks that they // match. recovery(withMessage("expected OpenACC end block directive"_err_en_US, attempt(Parser{} / endAccLine)), construct(construct( pure(llvm::acc::Directive::ACCD_data)))))) // Standalone constructs TYPE_PARSER(construct( sourced(Parser{}), Parser{})) // Standalone declarative constructs TYPE_PARSER(construct( sourced(Parser{}), Parser{})) TYPE_PARSER(startAccLine >> withMessage("expected OpenACC directive"_err_en_US, first(sourced(construct( Parser{})), sourced(construct( Parser{}))))) TYPE_PARSER(sourced(construct( "END"_tok >> "LOOP"_tok >> pure(llvm::acc::Directive::ACCD_loop)))) // OpenACC constructs TYPE_CONTEXT_PARSER("OpenACC construct"_en_US, startAccLine >> withMessage("expected OpenACC directive"_err_en_US, // Combined constructs before block constructs so we try to match // the longest possible match first. first( construct(Parser{}), construct(Parser{}), construct(Parser{}), construct( Parser{}), construct(Parser{}), construct(Parser{}), construct(Parser{}), construct(Parser{})))) TYPE_PARSER(startAccLine >> sourced(construct(sourced("END"_tok >> construct("KERNELS"_tok >> maybe("LOOP"_tok) >> pure(llvm::acc::Directive::ACCD_kernels_loop) || "PARALLEL"_tok >> maybe("LOOP"_tok) >> pure(llvm::acc::Directive::ACCD_parallel_loop) || "SERIAL"_tok >> maybe("LOOP"_tok) >> pure(llvm::acc::Directive::ACCD_serial_loop)))))) TYPE_PARSER(construct( sourced(Parser{} / endAccLine), maybe(Parser{}), maybe(Parser{} / endAccLine))) } // namespace Fortran::parser