15f757f3fSDimitry Andric //===--- ParseOpenACC.cpp - OpenACC-specific parsing support --------------===// 25f757f3fSDimitry Andric // 35f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65f757f3fSDimitry Andric // 75f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 85f757f3fSDimitry Andric // 95f757f3fSDimitry Andric // This file implements the parsing logic for OpenACC language features. 105f757f3fSDimitry Andric // 115f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 125f757f3fSDimitry Andric 135f757f3fSDimitry Andric #include "clang/Basic/OpenACCKinds.h" 145f757f3fSDimitry Andric #include "clang/Parse/ParseDiagnostic.h" 155f757f3fSDimitry Andric #include "clang/Parse/Parser.h" 165f757f3fSDimitry Andric #include "clang/Parse/RAIIObjectsForParser.h" 175f757f3fSDimitry Andric #include "llvm/ADT/StringRef.h" 185f757f3fSDimitry Andric #include "llvm/ADT/StringSwitch.h" 195f757f3fSDimitry Andric 205f757f3fSDimitry Andric using namespace clang; 215f757f3fSDimitry Andric using namespace llvm; 225f757f3fSDimitry Andric 235f757f3fSDimitry Andric namespace { 245f757f3fSDimitry Andric // An enum that contains the extended 'partial' parsed variants. This type 255f757f3fSDimitry Andric // should never escape the initial parse functionality, but is useful for 265f757f3fSDimitry Andric // simplifying the implementation. 275f757f3fSDimitry Andric enum class OpenACCDirectiveKindEx { 285f757f3fSDimitry Andric Invalid = static_cast<int>(OpenACCDirectiveKind::Invalid), 295f757f3fSDimitry Andric // 'enter data' and 'exit data' 305f757f3fSDimitry Andric Enter, 315f757f3fSDimitry Andric Exit, 325f757f3fSDimitry Andric }; 335f757f3fSDimitry Andric 345f757f3fSDimitry Andric // Translate single-token string representations to the OpenACC Directive Kind. 355f757f3fSDimitry Andric // This doesn't completely comprehend 'Compound Constructs' (as it just 365f757f3fSDimitry Andric // identifies the first token), and doesn't fully handle 'enter data', 'exit 375f757f3fSDimitry Andric // data', nor any of the 'atomic' variants, just the first token of each. So 385f757f3fSDimitry Andric // this should only be used by `ParseOpenACCDirectiveKind`. 395f757f3fSDimitry Andric OpenACCDirectiveKindEx getOpenACCDirectiveKind(Token Tok) { 405f757f3fSDimitry Andric if (!Tok.is(tok::identifier)) 415f757f3fSDimitry Andric return OpenACCDirectiveKindEx::Invalid; 425f757f3fSDimitry Andric OpenACCDirectiveKind DirKind = 435f757f3fSDimitry Andric llvm::StringSwitch<OpenACCDirectiveKind>( 445f757f3fSDimitry Andric Tok.getIdentifierInfo()->getName()) 455f757f3fSDimitry Andric .Case("parallel", OpenACCDirectiveKind::Parallel) 465f757f3fSDimitry Andric .Case("serial", OpenACCDirectiveKind::Serial) 475f757f3fSDimitry Andric .Case("kernels", OpenACCDirectiveKind::Kernels) 485f757f3fSDimitry Andric .Case("data", OpenACCDirectiveKind::Data) 495f757f3fSDimitry Andric .Case("host_data", OpenACCDirectiveKind::HostData) 505f757f3fSDimitry Andric .Case("loop", OpenACCDirectiveKind::Loop) 515f757f3fSDimitry Andric .Case("cache", OpenACCDirectiveKind::Cache) 525f757f3fSDimitry Andric .Case("atomic", OpenACCDirectiveKind::Atomic) 535f757f3fSDimitry Andric .Case("routine", OpenACCDirectiveKind::Routine) 545f757f3fSDimitry Andric .Case("declare", OpenACCDirectiveKind::Declare) 555f757f3fSDimitry Andric .Case("init", OpenACCDirectiveKind::Init) 565f757f3fSDimitry Andric .Case("shutdown", OpenACCDirectiveKind::Shutdown) 575f757f3fSDimitry Andric .Case("set", OpenACCDirectiveKind::Shutdown) 585f757f3fSDimitry Andric .Case("update", OpenACCDirectiveKind::Update) 595f757f3fSDimitry Andric .Case("wait", OpenACCDirectiveKind::Wait) 605f757f3fSDimitry Andric .Default(OpenACCDirectiveKind::Invalid); 615f757f3fSDimitry Andric 625f757f3fSDimitry Andric if (DirKind != OpenACCDirectiveKind::Invalid) 635f757f3fSDimitry Andric return static_cast<OpenACCDirectiveKindEx>(DirKind); 645f757f3fSDimitry Andric 655f757f3fSDimitry Andric return llvm::StringSwitch<OpenACCDirectiveKindEx>( 665f757f3fSDimitry Andric Tok.getIdentifierInfo()->getName()) 675f757f3fSDimitry Andric .Case("enter", OpenACCDirectiveKindEx::Enter) 685f757f3fSDimitry Andric .Case("exit", OpenACCDirectiveKindEx::Exit) 695f757f3fSDimitry Andric .Default(OpenACCDirectiveKindEx::Invalid); 705f757f3fSDimitry Andric } 715f757f3fSDimitry Andric 72*cb14a3feSDimitry Andric // Translate single-token string representations to the OpenCC Clause Kind. 73*cb14a3feSDimitry Andric OpenACCClauseKind getOpenACCClauseKind(Token Tok) { 74*cb14a3feSDimitry Andric // auto is a keyword in some language modes, so make sure we parse it 75*cb14a3feSDimitry Andric // correctly. 76*cb14a3feSDimitry Andric if (Tok.is(tok::kw_auto)) 77*cb14a3feSDimitry Andric return OpenACCClauseKind::Auto; 78*cb14a3feSDimitry Andric 79*cb14a3feSDimitry Andric if (!Tok.is(tok::identifier)) 80*cb14a3feSDimitry Andric return OpenACCClauseKind::Invalid; 81*cb14a3feSDimitry Andric 82*cb14a3feSDimitry Andric return llvm::StringSwitch<OpenACCClauseKind>( 83*cb14a3feSDimitry Andric Tok.getIdentifierInfo()->getName()) 84*cb14a3feSDimitry Andric .Case("auto", OpenACCClauseKind::Auto) 85*cb14a3feSDimitry Andric .Case("finalize", OpenACCClauseKind::Finalize) 86*cb14a3feSDimitry Andric .Case("if_present", OpenACCClauseKind::IfPresent) 87*cb14a3feSDimitry Andric .Case("independent", OpenACCClauseKind::Independent) 88*cb14a3feSDimitry Andric .Case("nohost", OpenACCClauseKind::NoHost) 89*cb14a3feSDimitry Andric .Case("seq", OpenACCClauseKind::Seq) 90*cb14a3feSDimitry Andric .Case("vector", OpenACCClauseKind::Vector) 91*cb14a3feSDimitry Andric .Case("worker", OpenACCClauseKind::Worker) 92*cb14a3feSDimitry Andric .Default(OpenACCClauseKind::Invalid); 93*cb14a3feSDimitry Andric } 94*cb14a3feSDimitry Andric 955f757f3fSDimitry Andric // Since 'atomic' is effectively a compound directive, this will decode the 965f757f3fSDimitry Andric // second part of the directive. 975f757f3fSDimitry Andric OpenACCAtomicKind getOpenACCAtomicKind(Token Tok) { 985f757f3fSDimitry Andric if (!Tok.is(tok::identifier)) 995f757f3fSDimitry Andric return OpenACCAtomicKind::Invalid; 1005f757f3fSDimitry Andric return llvm::StringSwitch<OpenACCAtomicKind>( 1015f757f3fSDimitry Andric Tok.getIdentifierInfo()->getName()) 1025f757f3fSDimitry Andric .Case("read", OpenACCAtomicKind::Read) 1035f757f3fSDimitry Andric .Case("write", OpenACCAtomicKind::Write) 1045f757f3fSDimitry Andric .Case("update", OpenACCAtomicKind::Update) 1055f757f3fSDimitry Andric .Case("capture", OpenACCAtomicKind::Capture) 1065f757f3fSDimitry Andric .Default(OpenACCAtomicKind::Invalid); 1075f757f3fSDimitry Andric } 1085f757f3fSDimitry Andric 1095f757f3fSDimitry Andric enum class OpenACCSpecialTokenKind { 1105f757f3fSDimitry Andric ReadOnly, 1115f757f3fSDimitry Andric DevNum, 1125f757f3fSDimitry Andric Queues, 1135f757f3fSDimitry Andric }; 1145f757f3fSDimitry Andric 1155f757f3fSDimitry Andric bool isOpenACCSpecialToken(OpenACCSpecialTokenKind Kind, Token Tok) { 1165f757f3fSDimitry Andric if (!Tok.is(tok::identifier)) 1175f757f3fSDimitry Andric return false; 1185f757f3fSDimitry Andric 1195f757f3fSDimitry Andric switch (Kind) { 1205f757f3fSDimitry Andric case OpenACCSpecialTokenKind::ReadOnly: 1215f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("readonly"); 1225f757f3fSDimitry Andric case OpenACCSpecialTokenKind::DevNum: 1235f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("devnum"); 1245f757f3fSDimitry Andric case OpenACCSpecialTokenKind::Queues: 1255f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("queues"); 1265f757f3fSDimitry Andric } 1275f757f3fSDimitry Andric llvm_unreachable("Unknown 'Kind' Passed"); 1285f757f3fSDimitry Andric } 1295f757f3fSDimitry Andric 1305f757f3fSDimitry Andric bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, Token Tok) { 1315f757f3fSDimitry Andric if (!Tok.is(tok::identifier)) 1325f757f3fSDimitry Andric return false; 1335f757f3fSDimitry Andric 1345f757f3fSDimitry Andric switch (Kind) { 1355f757f3fSDimitry Andric case OpenACCDirectiveKind::Parallel: 1365f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("parallel"); 1375f757f3fSDimitry Andric case OpenACCDirectiveKind::Serial: 1385f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("serial"); 1395f757f3fSDimitry Andric case OpenACCDirectiveKind::Kernels: 1405f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("kernels"); 1415f757f3fSDimitry Andric case OpenACCDirectiveKind::Data: 1425f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("data"); 1435f757f3fSDimitry Andric case OpenACCDirectiveKind::HostData: 1445f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("host_data"); 1455f757f3fSDimitry Andric case OpenACCDirectiveKind::Loop: 1465f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("loop"); 1475f757f3fSDimitry Andric case OpenACCDirectiveKind::Cache: 1485f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("cache"); 1495f757f3fSDimitry Andric 1505f757f3fSDimitry Andric case OpenACCDirectiveKind::ParallelLoop: 1515f757f3fSDimitry Andric case OpenACCDirectiveKind::SerialLoop: 1525f757f3fSDimitry Andric case OpenACCDirectiveKind::KernelsLoop: 1535f757f3fSDimitry Andric case OpenACCDirectiveKind::EnterData: 1545f757f3fSDimitry Andric case OpenACCDirectiveKind::ExitData: 1555f757f3fSDimitry Andric return false; 1565f757f3fSDimitry Andric 1575f757f3fSDimitry Andric case OpenACCDirectiveKind::Atomic: 1585f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("atomic"); 1595f757f3fSDimitry Andric case OpenACCDirectiveKind::Routine: 1605f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("routine"); 1615f757f3fSDimitry Andric case OpenACCDirectiveKind::Declare: 1625f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("declare"); 1635f757f3fSDimitry Andric case OpenACCDirectiveKind::Init: 1645f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("init"); 1655f757f3fSDimitry Andric case OpenACCDirectiveKind::Shutdown: 1665f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("shutdown"); 1675f757f3fSDimitry Andric case OpenACCDirectiveKind::Set: 1685f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("set"); 1695f757f3fSDimitry Andric case OpenACCDirectiveKind::Update: 1705f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("update"); 1715f757f3fSDimitry Andric case OpenACCDirectiveKind::Wait: 1725f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("wait"); 1735f757f3fSDimitry Andric case OpenACCDirectiveKind::Invalid: 1745f757f3fSDimitry Andric return false; 1755f757f3fSDimitry Andric } 1765f757f3fSDimitry Andric llvm_unreachable("Unknown 'Kind' Passed"); 1775f757f3fSDimitry Andric } 1785f757f3fSDimitry Andric 1795f757f3fSDimitry Andric OpenACCDirectiveKind 1805f757f3fSDimitry Andric ParseOpenACCEnterExitDataDirective(Parser &P, Token FirstTok, 1815f757f3fSDimitry Andric OpenACCDirectiveKindEx ExtDirKind) { 1825f757f3fSDimitry Andric Token SecondTok = P.getCurToken(); 1835f757f3fSDimitry Andric 1845f757f3fSDimitry Andric if (SecondTok.isAnnotation()) { 1855f757f3fSDimitry Andric P.Diag(FirstTok, diag::err_acc_invalid_directive) 1865f757f3fSDimitry Andric << 0 << FirstTok.getIdentifierInfo(); 1875f757f3fSDimitry Andric return OpenACCDirectiveKind::Invalid; 1885f757f3fSDimitry Andric } 1895f757f3fSDimitry Andric 190*cb14a3feSDimitry Andric // Consume the second name anyway, this way we can continue on without making 191*cb14a3feSDimitry Andric // this oddly look like a clause. 192*cb14a3feSDimitry Andric P.ConsumeAnyToken(); 193*cb14a3feSDimitry Andric 1945f757f3fSDimitry Andric if (!isOpenACCDirectiveKind(OpenACCDirectiveKind::Data, SecondTok)) { 1955f757f3fSDimitry Andric if (!SecondTok.is(tok::identifier)) 1965f757f3fSDimitry Andric P.Diag(SecondTok, diag::err_expected) << tok::identifier; 1975f757f3fSDimitry Andric else 1985f757f3fSDimitry Andric P.Diag(FirstTok, diag::err_acc_invalid_directive) 1995f757f3fSDimitry Andric << 1 << FirstTok.getIdentifierInfo()->getName() 2005f757f3fSDimitry Andric << SecondTok.getIdentifierInfo()->getName(); 2015f757f3fSDimitry Andric return OpenACCDirectiveKind::Invalid; 2025f757f3fSDimitry Andric } 2035f757f3fSDimitry Andric 2045f757f3fSDimitry Andric return ExtDirKind == OpenACCDirectiveKindEx::Enter 2055f757f3fSDimitry Andric ? OpenACCDirectiveKind::EnterData 2065f757f3fSDimitry Andric : OpenACCDirectiveKind::ExitData; 2075f757f3fSDimitry Andric } 2085f757f3fSDimitry Andric 2095f757f3fSDimitry Andric OpenACCAtomicKind ParseOpenACCAtomicKind(Parser &P) { 2105f757f3fSDimitry Andric Token AtomicClauseToken = P.getCurToken(); 2115f757f3fSDimitry Andric 2125f757f3fSDimitry Andric // #pragma acc atomic is equivilent to update: 2135f757f3fSDimitry Andric if (AtomicClauseToken.isAnnotation()) 2145f757f3fSDimitry Andric return OpenACCAtomicKind::Update; 2155f757f3fSDimitry Andric 2165f757f3fSDimitry Andric OpenACCAtomicKind AtomicKind = getOpenACCAtomicKind(AtomicClauseToken); 2175f757f3fSDimitry Andric 2185f757f3fSDimitry Andric // If we don't know what this is, treat it as 'nothing', and treat the rest of 2195f757f3fSDimitry Andric // this as a clause list, which, despite being invalid, is likely what the 2205f757f3fSDimitry Andric // user was trying to do. 2215f757f3fSDimitry Andric if (AtomicKind == OpenACCAtomicKind::Invalid) 2225f757f3fSDimitry Andric return OpenACCAtomicKind::Update; 2235f757f3fSDimitry Andric 2245f757f3fSDimitry Andric P.ConsumeToken(); 2255f757f3fSDimitry Andric return AtomicKind; 2265f757f3fSDimitry Andric } 2275f757f3fSDimitry Andric 2285f757f3fSDimitry Andric // Parse and consume the tokens for OpenACC Directive/Construct kinds. 2295f757f3fSDimitry Andric OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) { 2305f757f3fSDimitry Andric Token FirstTok = P.getCurToken(); 2315f757f3fSDimitry Andric 2325f757f3fSDimitry Andric // Just #pragma acc can get us immediately to the end, make sure we don't 2335f757f3fSDimitry Andric // introspect on the spelling before then. 2345f757f3fSDimitry Andric if (FirstTok.isNot(tok::identifier)) { 2355f757f3fSDimitry Andric P.Diag(FirstTok, diag::err_acc_missing_directive); 236*cb14a3feSDimitry Andric 237*cb14a3feSDimitry Andric if (P.getCurToken().isNot(tok::annot_pragma_openacc_end)) 238*cb14a3feSDimitry Andric P.ConsumeAnyToken(); 239*cb14a3feSDimitry Andric 2405f757f3fSDimitry Andric return OpenACCDirectiveKind::Invalid; 2415f757f3fSDimitry Andric } 2425f757f3fSDimitry Andric 2435f757f3fSDimitry Andric P.ConsumeToken(); 2445f757f3fSDimitry Andric 2455f757f3fSDimitry Andric OpenACCDirectiveKindEx ExDirKind = getOpenACCDirectiveKind(FirstTok); 2465f757f3fSDimitry Andric 2475f757f3fSDimitry Andric // OpenACCDirectiveKindEx is meant to be an extended list 2485f757f3fSDimitry Andric // over OpenACCDirectiveKind, so any value below Invalid is one of the 2495f757f3fSDimitry Andric // OpenACCDirectiveKind values. This switch takes care of all of the extra 2505f757f3fSDimitry Andric // parsing required for the Extended values. At the end of this block, 2515f757f3fSDimitry Andric // ExDirKind can be assumed to be a valid OpenACCDirectiveKind, so we can 2525f757f3fSDimitry Andric // immediately cast it and use it as that. 2535f757f3fSDimitry Andric if (ExDirKind >= OpenACCDirectiveKindEx::Invalid) { 2545f757f3fSDimitry Andric switch (ExDirKind) { 2555f757f3fSDimitry Andric case OpenACCDirectiveKindEx::Invalid: { 2565f757f3fSDimitry Andric P.Diag(FirstTok, diag::err_acc_invalid_directive) 2575f757f3fSDimitry Andric << 0 << FirstTok.getIdentifierInfo(); 2585f757f3fSDimitry Andric return OpenACCDirectiveKind::Invalid; 2595f757f3fSDimitry Andric } 2605f757f3fSDimitry Andric case OpenACCDirectiveKindEx::Enter: 2615f757f3fSDimitry Andric case OpenACCDirectiveKindEx::Exit: 2625f757f3fSDimitry Andric return ParseOpenACCEnterExitDataDirective(P, FirstTok, ExDirKind); 2635f757f3fSDimitry Andric } 2645f757f3fSDimitry Andric } 2655f757f3fSDimitry Andric 2665f757f3fSDimitry Andric OpenACCDirectiveKind DirKind = static_cast<OpenACCDirectiveKind>(ExDirKind); 2675f757f3fSDimitry Andric 2685f757f3fSDimitry Andric // Combined Constructs allows parallel loop, serial loop, or kernels loop. Any 2695f757f3fSDimitry Andric // other attempt at a combined construct will be diagnosed as an invalid 2705f757f3fSDimitry Andric // clause. 2715f757f3fSDimitry Andric Token SecondTok = P.getCurToken(); 2725f757f3fSDimitry Andric if (!SecondTok.isAnnotation() && 2735f757f3fSDimitry Andric isOpenACCDirectiveKind(OpenACCDirectiveKind::Loop, SecondTok)) { 2745f757f3fSDimitry Andric switch (DirKind) { 2755f757f3fSDimitry Andric default: 2765f757f3fSDimitry Andric // Nothing to do except in the below cases, as they should be diagnosed as 2775f757f3fSDimitry Andric // a clause. 2785f757f3fSDimitry Andric break; 2795f757f3fSDimitry Andric case OpenACCDirectiveKind::Parallel: 2805f757f3fSDimitry Andric P.ConsumeToken(); 2815f757f3fSDimitry Andric return OpenACCDirectiveKind::ParallelLoop; 2825f757f3fSDimitry Andric case OpenACCDirectiveKind::Serial: 2835f757f3fSDimitry Andric P.ConsumeToken(); 2845f757f3fSDimitry Andric return OpenACCDirectiveKind::SerialLoop; 2855f757f3fSDimitry Andric case OpenACCDirectiveKind::Kernels: 2865f757f3fSDimitry Andric P.ConsumeToken(); 2875f757f3fSDimitry Andric return OpenACCDirectiveKind::KernelsLoop; 2885f757f3fSDimitry Andric } 2895f757f3fSDimitry Andric } 2905f757f3fSDimitry Andric 2915f757f3fSDimitry Andric return DirKind; 2925f757f3fSDimitry Andric } 2935f757f3fSDimitry Andric 294*cb14a3feSDimitry Andric // The OpenACC Clause List is a comma or space-delimited list of clauses (see 295*cb14a3feSDimitry Andric // the comment on ParseOpenACCClauseList). The concept of a 'clause' doesn't 296*cb14a3feSDimitry Andric // really have its owner grammar and each individual one has its own definition. 297*cb14a3feSDimitry Andric // However, they all are named with a single-identifier (or auto!) token, 298*cb14a3feSDimitry Andric // followed in some cases by either braces or parens. 299*cb14a3feSDimitry Andric bool ParseOpenACCClause(Parser &P) { 300*cb14a3feSDimitry Andric if (!P.getCurToken().isOneOf(tok::identifier, tok::kw_auto)) 301*cb14a3feSDimitry Andric return P.Diag(P.getCurToken(), diag::err_expected) << tok::identifier; 302*cb14a3feSDimitry Andric 303*cb14a3feSDimitry Andric OpenACCClauseKind Kind = getOpenACCClauseKind(P.getCurToken()); 304*cb14a3feSDimitry Andric 305*cb14a3feSDimitry Andric if (Kind == OpenACCClauseKind::Invalid) 306*cb14a3feSDimitry Andric return P.Diag(P.getCurToken(), diag::err_acc_invalid_clause) 307*cb14a3feSDimitry Andric << P.getCurToken().getIdentifierInfo(); 308*cb14a3feSDimitry Andric 309*cb14a3feSDimitry Andric // Consume the clause name. 310*cb14a3feSDimitry Andric P.ConsumeToken(); 311*cb14a3feSDimitry Andric 312*cb14a3feSDimitry Andric // FIXME: For future clauses, we need to handle parens/etc below. 313*cb14a3feSDimitry Andric return false; 314*cb14a3feSDimitry Andric } 315*cb14a3feSDimitry Andric 316*cb14a3feSDimitry Andric // Skip until we see the end of pragma token, but don't consume it. This is us 317*cb14a3feSDimitry Andric // just giving up on the rest of the pragma so we can continue executing. We 318*cb14a3feSDimitry Andric // have to do this because 'SkipUntil' considers paren balancing, which isn't 319*cb14a3feSDimitry Andric // what we want. 320*cb14a3feSDimitry Andric void SkipUntilEndOfDirective(Parser &P) { 321*cb14a3feSDimitry Andric while (P.getCurToken().isNot(tok::annot_pragma_openacc_end)) 322*cb14a3feSDimitry Andric P.ConsumeAnyToken(); 323*cb14a3feSDimitry Andric } 324*cb14a3feSDimitry Andric 325*cb14a3feSDimitry Andric // OpenACC 3.3, section 1.7: 326*cb14a3feSDimitry Andric // To simplify the specification and convey appropriate constraint information, 327*cb14a3feSDimitry Andric // a pqr-list is a comma-separated list of pdr items. The one exception is a 328*cb14a3feSDimitry Andric // clause-list, which is a list of one or more clauses optionally separated by 329*cb14a3feSDimitry Andric // commas. 3305f757f3fSDimitry Andric void ParseOpenACCClauseList(Parser &P) { 331*cb14a3feSDimitry Andric bool FirstClause = true; 332*cb14a3feSDimitry Andric while (P.getCurToken().isNot(tok::annot_pragma_openacc_end)) { 333*cb14a3feSDimitry Andric // Comma is optional in a clause-list. 334*cb14a3feSDimitry Andric if (!FirstClause && P.getCurToken().is(tok::comma)) 335*cb14a3feSDimitry Andric P.ConsumeToken(); 336*cb14a3feSDimitry Andric FirstClause = false; 337*cb14a3feSDimitry Andric 338*cb14a3feSDimitry Andric // Recovering from a bad clause is really difficult, so we just give up on 339*cb14a3feSDimitry Andric // error. 340*cb14a3feSDimitry Andric if (ParseOpenACCClause(P)) { 341*cb14a3feSDimitry Andric SkipUntilEndOfDirective(P); 342*cb14a3feSDimitry Andric return; 343*cb14a3feSDimitry Andric } 344*cb14a3feSDimitry Andric } 3455f757f3fSDimitry Andric } 3465f757f3fSDimitry Andric 3475f757f3fSDimitry Andric } // namespace 3485f757f3fSDimitry Andric 3495f757f3fSDimitry Andric /// OpenACC 3.3, section 2.16: 3505f757f3fSDimitry Andric /// In this section and throughout the specification, the term wait-argument 3515f757f3fSDimitry Andric /// means: 3525f757f3fSDimitry Andric /// [ devnum : int-expr : ] [ queues : ] async-argument-list 3535f757f3fSDimitry Andric bool Parser::ParseOpenACCWaitArgument() { 3545f757f3fSDimitry Andric // [devnum : int-expr : ] 3555f757f3fSDimitry Andric if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::DevNum, Tok) && 3565f757f3fSDimitry Andric NextToken().is(tok::colon)) { 3575f757f3fSDimitry Andric // Consume devnum. 3585f757f3fSDimitry Andric ConsumeToken(); 3595f757f3fSDimitry Andric // Consume colon. 3605f757f3fSDimitry Andric ConsumeToken(); 3615f757f3fSDimitry Andric 3625f757f3fSDimitry Andric ExprResult IntExpr = 3635f757f3fSDimitry Andric getActions().CorrectDelayedTyposInExpr(ParseAssignmentExpression()); 3645f757f3fSDimitry Andric if (IntExpr.isInvalid()) 3655f757f3fSDimitry Andric return true; 3665f757f3fSDimitry Andric 3675f757f3fSDimitry Andric if (ExpectAndConsume(tok::colon)) 3685f757f3fSDimitry Andric return true; 3695f757f3fSDimitry Andric } 3705f757f3fSDimitry Andric 3715f757f3fSDimitry Andric // [ queues : ] 3725f757f3fSDimitry Andric if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Queues, Tok) && 3735f757f3fSDimitry Andric NextToken().is(tok::colon)) { 3745f757f3fSDimitry Andric // Consume queues. 3755f757f3fSDimitry Andric ConsumeToken(); 3765f757f3fSDimitry Andric // Consume colon. 3775f757f3fSDimitry Andric ConsumeToken(); 3785f757f3fSDimitry Andric } 3795f757f3fSDimitry Andric 3805f757f3fSDimitry Andric // OpenACC 3.3, section 2.16: 3815f757f3fSDimitry Andric // the term 'async-argument' means a nonnegative scalar integer expression, or 3825f757f3fSDimitry Andric // one of the special values 'acc_async_noval' or 'acc_async_sync', as defined 3835f757f3fSDimitry Andric // in the C header file and the Fortran opacc module. 3845f757f3fSDimitry Andric // 3855f757f3fSDimitry Andric // We are parsing this simply as list of assignment expressions (to avoid 3865f757f3fSDimitry Andric // comma being troublesome), and will ensure it is an integral type. The 3875f757f3fSDimitry Andric // 'special' types are defined as macros, so we can't really check those 3885f757f3fSDimitry Andric // (other than perhaps as values at one point?), but the standard does say it 3895f757f3fSDimitry Andric // is implementation-defined to use any other negative value. 3905f757f3fSDimitry Andric // 3915f757f3fSDimitry Andric // 3925f757f3fSDimitry Andric bool FirstArg = true; 3935f757f3fSDimitry Andric while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) { 3945f757f3fSDimitry Andric if (!FirstArg) { 3955f757f3fSDimitry Andric if (ExpectAndConsume(tok::comma)) 3965f757f3fSDimitry Andric return true; 3975f757f3fSDimitry Andric } 3985f757f3fSDimitry Andric FirstArg = false; 3995f757f3fSDimitry Andric 4005f757f3fSDimitry Andric ExprResult CurArg = 4015f757f3fSDimitry Andric getActions().CorrectDelayedTyposInExpr(ParseAssignmentExpression()); 4025f757f3fSDimitry Andric 4035f757f3fSDimitry Andric if (CurArg.isInvalid()) 4045f757f3fSDimitry Andric return true; 4055f757f3fSDimitry Andric } 4065f757f3fSDimitry Andric 4075f757f3fSDimitry Andric return false; 4085f757f3fSDimitry Andric } 4095f757f3fSDimitry Andric 4105f757f3fSDimitry Andric ExprResult Parser::ParseOpenACCIDExpression() { 4115f757f3fSDimitry Andric ExprResult Res; 4125f757f3fSDimitry Andric if (getLangOpts().CPlusPlus) { 4135f757f3fSDimitry Andric Res = ParseCXXIdExpression(/*isAddressOfOperand=*/false); 4145f757f3fSDimitry Andric } else { 4155f757f3fSDimitry Andric // There isn't anything quite the same as ParseCXXIdExpression for C, so we 4165f757f3fSDimitry Andric // need to get the identifier, then call into Sema ourselves. 4175f757f3fSDimitry Andric 4185f757f3fSDimitry Andric if (Tok.isNot(tok::identifier)) { 4195f757f3fSDimitry Andric Diag(Tok, diag::err_expected) << tok::identifier; 4205f757f3fSDimitry Andric return ExprError(); 4215f757f3fSDimitry Andric } 4225f757f3fSDimitry Andric 4235f757f3fSDimitry Andric Token FuncName = getCurToken(); 4245f757f3fSDimitry Andric UnqualifiedId Name; 4255f757f3fSDimitry Andric CXXScopeSpec ScopeSpec; 4265f757f3fSDimitry Andric SourceLocation TemplateKWLoc; 4275f757f3fSDimitry Andric Name.setIdentifier(FuncName.getIdentifierInfo(), ConsumeToken()); 4285f757f3fSDimitry Andric 4295f757f3fSDimitry Andric // Ensure this is a valid identifier. We don't accept causing implicit 4305f757f3fSDimitry Andric // function declarations per the spec, so always claim to not have trailing 4315f757f3fSDimitry Andric // L Paren. 4325f757f3fSDimitry Andric Res = Actions.ActOnIdExpression(getCurScope(), ScopeSpec, TemplateKWLoc, 4335f757f3fSDimitry Andric Name, /*HasTrailingLParen=*/false, 4345f757f3fSDimitry Andric /*isAddressOfOperand=*/false); 4355f757f3fSDimitry Andric } 4365f757f3fSDimitry Andric 4375f757f3fSDimitry Andric return getActions().CorrectDelayedTyposInExpr(Res); 4385f757f3fSDimitry Andric } 4395f757f3fSDimitry Andric 4405f757f3fSDimitry Andric /// OpenACC 3.3, section 2.10: 4415f757f3fSDimitry Andric /// A 'var' in a cache directive must be a single array element or a simple 4425f757f3fSDimitry Andric /// subarray. In C and C++, a simple subarray is an array name followed by an 4435f757f3fSDimitry Andric /// extended array range specification in brackets, with a start and length such 4445f757f3fSDimitry Andric /// as: 4455f757f3fSDimitry Andric /// 4465f757f3fSDimitry Andric /// arr[lower:length] 4475f757f3fSDimitry Andric /// 4485f757f3fSDimitry Andric bool Parser::ParseOpenACCCacheVar() { 4495f757f3fSDimitry Andric ExprResult ArrayName = ParseOpenACCIDExpression(); 4505f757f3fSDimitry Andric if (ArrayName.isInvalid()) 4515f757f3fSDimitry Andric return true; 4525f757f3fSDimitry Andric 4535f757f3fSDimitry Andric // If the expression is invalid, just continue parsing the brackets, there 4545f757f3fSDimitry Andric // is likely other useful diagnostics we can emit inside of those. 4555f757f3fSDimitry Andric 4565f757f3fSDimitry Andric BalancedDelimiterTracker SquareBrackets(*this, tok::l_square, 4575f757f3fSDimitry Andric tok::annot_pragma_openacc_end); 4585f757f3fSDimitry Andric 4595f757f3fSDimitry Andric // Square brackets are required, so error here, and try to recover by moving 4605f757f3fSDimitry Andric // until the next comma, or the close paren/end of pragma. 4615f757f3fSDimitry Andric if (SquareBrackets.expectAndConsume()) { 4625f757f3fSDimitry Andric SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openacc_end, 4635f757f3fSDimitry Andric Parser::StopBeforeMatch); 4645f757f3fSDimitry Andric return true; 4655f757f3fSDimitry Andric } 4665f757f3fSDimitry Andric 4675f757f3fSDimitry Andric ExprResult Lower = getActions().CorrectDelayedTyposInExpr(ParseExpression()); 4685f757f3fSDimitry Andric if (Lower.isInvalid()) 4695f757f3fSDimitry Andric return true; 4705f757f3fSDimitry Andric 4715f757f3fSDimitry Andric // The 'length' expression is optional, as this could be a single array 4725f757f3fSDimitry Andric // element. If there is no colon, we can treat it as that. 4735f757f3fSDimitry Andric if (getCurToken().is(tok::colon)) { 4745f757f3fSDimitry Andric ConsumeToken(); 4755f757f3fSDimitry Andric ExprResult Length = 4765f757f3fSDimitry Andric getActions().CorrectDelayedTyposInExpr(ParseExpression()); 4775f757f3fSDimitry Andric if (Length.isInvalid()) 4785f757f3fSDimitry Andric return true; 4795f757f3fSDimitry Andric } 4805f757f3fSDimitry Andric 4815f757f3fSDimitry Andric // Diagnose the square bracket being in the wrong place and continue. 4825f757f3fSDimitry Andric return SquareBrackets.consumeClose(); 4835f757f3fSDimitry Andric } 4845f757f3fSDimitry Andric 4855f757f3fSDimitry Andric /// OpenACC 3.3, section 2.10: 4865f757f3fSDimitry Andric /// In C and C++, the syntax of the cache directive is: 4875f757f3fSDimitry Andric /// 4885f757f3fSDimitry Andric /// #pragma acc cache ([readonly:]var-list) new-line 4895f757f3fSDimitry Andric void Parser::ParseOpenACCCacheVarList() { 4905f757f3fSDimitry Andric // If this is the end of the line, just return 'false' and count on the close 4915f757f3fSDimitry Andric // paren diagnostic to catch the issue. 4925f757f3fSDimitry Andric if (getCurToken().isAnnotation()) 4935f757f3fSDimitry Andric return; 4945f757f3fSDimitry Andric 4955f757f3fSDimitry Andric // The VarList is an optional `readonly:` followed by a list of a variable 4965f757f3fSDimitry Andric // specifications. First, see if we have `readonly:`, else we back-out and 4975f757f3fSDimitry Andric // treat it like the beginning of a reference to a potentially-existing 4985f757f3fSDimitry Andric // `readonly` variable. 4995f757f3fSDimitry Andric if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::ReadOnly, Tok) && 5005f757f3fSDimitry Andric NextToken().is(tok::colon)) { 5015f757f3fSDimitry Andric // Consume both tokens. 5025f757f3fSDimitry Andric ConsumeToken(); 5035f757f3fSDimitry Andric ConsumeToken(); 5045f757f3fSDimitry Andric // FIXME: Record that this is a 'readonly' so that we can use that during 5055f757f3fSDimitry Andric // Sema/AST generation. 5065f757f3fSDimitry Andric } 5075f757f3fSDimitry Andric 5085f757f3fSDimitry Andric bool FirstArray = true; 5095f757f3fSDimitry Andric while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) { 5105f757f3fSDimitry Andric if (!FirstArray) 5115f757f3fSDimitry Andric ExpectAndConsume(tok::comma); 5125f757f3fSDimitry Andric FirstArray = false; 5135f757f3fSDimitry Andric if (ParseOpenACCCacheVar()) 5145f757f3fSDimitry Andric SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end, tok::comma, 5155f757f3fSDimitry Andric StopBeforeMatch); 5165f757f3fSDimitry Andric } 5175f757f3fSDimitry Andric } 5185f757f3fSDimitry Andric 5195f757f3fSDimitry Andric void Parser::ParseOpenACCDirective() { 5205f757f3fSDimitry Andric OpenACCDirectiveKind DirKind = ParseOpenACCDirectiveKind(*this); 5215f757f3fSDimitry Andric 5225f757f3fSDimitry Andric // Once we've parsed the construct/directive name, some have additional 5235f757f3fSDimitry Andric // specifiers that need to be taken care of. Atomic has an 'atomic-clause' 5245f757f3fSDimitry Andric // that needs to be parsed. 5255f757f3fSDimitry Andric if (DirKind == OpenACCDirectiveKind::Atomic) 5265f757f3fSDimitry Andric ParseOpenACCAtomicKind(*this); 5275f757f3fSDimitry Andric 5285f757f3fSDimitry Andric // We've successfully parsed the construct/directive name, however a few of 5295f757f3fSDimitry Andric // the constructs have optional parens that contain further details. 5305f757f3fSDimitry Andric BalancedDelimiterTracker T(*this, tok::l_paren, 5315f757f3fSDimitry Andric tok::annot_pragma_openacc_end); 5325f757f3fSDimitry Andric 5335f757f3fSDimitry Andric if (!T.consumeOpen()) { 5345f757f3fSDimitry Andric switch (DirKind) { 5355f757f3fSDimitry Andric default: 5365f757f3fSDimitry Andric Diag(T.getOpenLocation(), diag::err_acc_invalid_open_paren); 5375f757f3fSDimitry Andric T.skipToEnd(); 5385f757f3fSDimitry Andric break; 5395f757f3fSDimitry Andric case OpenACCDirectiveKind::Routine: { 5405f757f3fSDimitry Andric // Routine has an optional paren-wrapped name of a function in the local 5415f757f3fSDimitry Andric // scope. We parse the name, emitting any diagnostics 5425f757f3fSDimitry Andric ExprResult RoutineName = ParseOpenACCIDExpression(); 5435f757f3fSDimitry Andric // If the routine name is invalid, just skip until the closing paren to 5445f757f3fSDimitry Andric // recover more gracefully. 5455f757f3fSDimitry Andric if (RoutineName.isInvalid()) 5465f757f3fSDimitry Andric T.skipToEnd(); 5475f757f3fSDimitry Andric else 5485f757f3fSDimitry Andric T.consumeClose(); 5495f757f3fSDimitry Andric break; 5505f757f3fSDimitry Andric } 5515f757f3fSDimitry Andric case OpenACCDirectiveKind::Cache: 5525f757f3fSDimitry Andric ParseOpenACCCacheVarList(); 5535f757f3fSDimitry Andric // The ParseOpenACCCacheVarList function manages to recover from failures, 5545f757f3fSDimitry Andric // so we can always consume the close. 5555f757f3fSDimitry Andric T.consumeClose(); 5565f757f3fSDimitry Andric break; 5575f757f3fSDimitry Andric case OpenACCDirectiveKind::Wait: 5585f757f3fSDimitry Andric // OpenACC has an optional paren-wrapped 'wait-argument'. 5595f757f3fSDimitry Andric if (ParseOpenACCWaitArgument()) 5605f757f3fSDimitry Andric T.skipToEnd(); 5615f757f3fSDimitry Andric else 5625f757f3fSDimitry Andric T.consumeClose(); 5635f757f3fSDimitry Andric break; 5645f757f3fSDimitry Andric } 5655f757f3fSDimitry Andric } else if (DirKind == OpenACCDirectiveKind::Cache) { 5665f757f3fSDimitry Andric // Cache's paren var-list is required, so error here if it isn't provided. 5675f757f3fSDimitry Andric // We know that the consumeOpen above left the first non-paren here, so 5685f757f3fSDimitry Andric // diagnose, then continue as if it was completely omitted. 5695f757f3fSDimitry Andric Diag(Tok, diag::err_expected) << tok::l_paren; 5705f757f3fSDimitry Andric } 5715f757f3fSDimitry Andric 5725f757f3fSDimitry Andric // Parses the list of clauses, if present. 5735f757f3fSDimitry Andric ParseOpenACCClauseList(*this); 5745f757f3fSDimitry Andric 5755f757f3fSDimitry Andric Diag(getCurToken(), diag::warn_pragma_acc_unimplemented); 576*cb14a3feSDimitry Andric assert(Tok.is(tok::annot_pragma_openacc_end) && 577*cb14a3feSDimitry Andric "Didn't parse all OpenACC Clauses"); 578*cb14a3feSDimitry Andric ConsumeAnnotationToken(); 5795f757f3fSDimitry Andric } 5805f757f3fSDimitry Andric 5815f757f3fSDimitry Andric // Parse OpenACC directive on a declaration. 5825f757f3fSDimitry Andric Parser::DeclGroupPtrTy Parser::ParseOpenACCDirectiveDecl() { 5835f757f3fSDimitry Andric assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token"); 5845f757f3fSDimitry Andric 5855f757f3fSDimitry Andric ParsingOpenACCDirectiveRAII DirScope(*this); 5865f757f3fSDimitry Andric ConsumeAnnotationToken(); 5875f757f3fSDimitry Andric 5885f757f3fSDimitry Andric ParseOpenACCDirective(); 5895f757f3fSDimitry Andric 5905f757f3fSDimitry Andric return nullptr; 5915f757f3fSDimitry Andric } 5925f757f3fSDimitry Andric 5935f757f3fSDimitry Andric // Parse OpenACC Directive on a Statement. 5945f757f3fSDimitry Andric StmtResult Parser::ParseOpenACCDirectiveStmt() { 5955f757f3fSDimitry Andric assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token"); 5965f757f3fSDimitry Andric 5975f757f3fSDimitry Andric ParsingOpenACCDirectiveRAII DirScope(*this); 5985f757f3fSDimitry Andric ConsumeAnnotationToken(); 5995f757f3fSDimitry Andric 6005f757f3fSDimitry Andric ParseOpenACCDirective(); 6015f757f3fSDimitry Andric 6025f757f3fSDimitry Andric return StmtEmpty(); 6035f757f3fSDimitry Andric } 604