1*5f757f3fSDimitry Andric //===--- ParseOpenACC.cpp - OpenACC-specific parsing support --------------===// 2*5f757f3fSDimitry Andric // 3*5f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*5f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*5f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*5f757f3fSDimitry Andric // 7*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 8*5f757f3fSDimitry Andric // 9*5f757f3fSDimitry Andric // This file implements the parsing logic for OpenACC language features. 10*5f757f3fSDimitry Andric // 11*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 12*5f757f3fSDimitry Andric 13*5f757f3fSDimitry Andric #include "clang/Basic/OpenACCKinds.h" 14*5f757f3fSDimitry Andric #include "clang/Parse/ParseDiagnostic.h" 15*5f757f3fSDimitry Andric #include "clang/Parse/Parser.h" 16*5f757f3fSDimitry Andric #include "clang/Parse/RAIIObjectsForParser.h" 17*5f757f3fSDimitry Andric #include "llvm/ADT/StringRef.h" 18*5f757f3fSDimitry Andric #include "llvm/ADT/StringSwitch.h" 19*5f757f3fSDimitry Andric 20*5f757f3fSDimitry Andric using namespace clang; 21*5f757f3fSDimitry Andric using namespace llvm; 22*5f757f3fSDimitry Andric 23*5f757f3fSDimitry Andric namespace { 24*5f757f3fSDimitry Andric // An enum that contains the extended 'partial' parsed variants. This type 25*5f757f3fSDimitry Andric // should never escape the initial parse functionality, but is useful for 26*5f757f3fSDimitry Andric // simplifying the implementation. 27*5f757f3fSDimitry Andric enum class OpenACCDirectiveKindEx { 28*5f757f3fSDimitry Andric Invalid = static_cast<int>(OpenACCDirectiveKind::Invalid), 29*5f757f3fSDimitry Andric // 'enter data' and 'exit data' 30*5f757f3fSDimitry Andric Enter, 31*5f757f3fSDimitry Andric Exit, 32*5f757f3fSDimitry Andric }; 33*5f757f3fSDimitry Andric 34*5f757f3fSDimitry Andric // Translate single-token string representations to the OpenACC Directive Kind. 35*5f757f3fSDimitry Andric // This doesn't completely comprehend 'Compound Constructs' (as it just 36*5f757f3fSDimitry Andric // identifies the first token), and doesn't fully handle 'enter data', 'exit 37*5f757f3fSDimitry Andric // data', nor any of the 'atomic' variants, just the first token of each. So 38*5f757f3fSDimitry Andric // this should only be used by `ParseOpenACCDirectiveKind`. 39*5f757f3fSDimitry Andric OpenACCDirectiveKindEx getOpenACCDirectiveKind(Token Tok) { 40*5f757f3fSDimitry Andric if (!Tok.is(tok::identifier)) 41*5f757f3fSDimitry Andric return OpenACCDirectiveKindEx::Invalid; 42*5f757f3fSDimitry Andric OpenACCDirectiveKind DirKind = 43*5f757f3fSDimitry Andric llvm::StringSwitch<OpenACCDirectiveKind>( 44*5f757f3fSDimitry Andric Tok.getIdentifierInfo()->getName()) 45*5f757f3fSDimitry Andric .Case("parallel", OpenACCDirectiveKind::Parallel) 46*5f757f3fSDimitry Andric .Case("serial", OpenACCDirectiveKind::Serial) 47*5f757f3fSDimitry Andric .Case("kernels", OpenACCDirectiveKind::Kernels) 48*5f757f3fSDimitry Andric .Case("data", OpenACCDirectiveKind::Data) 49*5f757f3fSDimitry Andric .Case("host_data", OpenACCDirectiveKind::HostData) 50*5f757f3fSDimitry Andric .Case("loop", OpenACCDirectiveKind::Loop) 51*5f757f3fSDimitry Andric .Case("cache", OpenACCDirectiveKind::Cache) 52*5f757f3fSDimitry Andric .Case("atomic", OpenACCDirectiveKind::Atomic) 53*5f757f3fSDimitry Andric .Case("routine", OpenACCDirectiveKind::Routine) 54*5f757f3fSDimitry Andric .Case("declare", OpenACCDirectiveKind::Declare) 55*5f757f3fSDimitry Andric .Case("init", OpenACCDirectiveKind::Init) 56*5f757f3fSDimitry Andric .Case("shutdown", OpenACCDirectiveKind::Shutdown) 57*5f757f3fSDimitry Andric .Case("set", OpenACCDirectiveKind::Shutdown) 58*5f757f3fSDimitry Andric .Case("update", OpenACCDirectiveKind::Update) 59*5f757f3fSDimitry Andric .Case("wait", OpenACCDirectiveKind::Wait) 60*5f757f3fSDimitry Andric .Default(OpenACCDirectiveKind::Invalid); 61*5f757f3fSDimitry Andric 62*5f757f3fSDimitry Andric if (DirKind != OpenACCDirectiveKind::Invalid) 63*5f757f3fSDimitry Andric return static_cast<OpenACCDirectiveKindEx>(DirKind); 64*5f757f3fSDimitry Andric 65*5f757f3fSDimitry Andric return llvm::StringSwitch<OpenACCDirectiveKindEx>( 66*5f757f3fSDimitry Andric Tok.getIdentifierInfo()->getName()) 67*5f757f3fSDimitry Andric .Case("enter", OpenACCDirectiveKindEx::Enter) 68*5f757f3fSDimitry Andric .Case("exit", OpenACCDirectiveKindEx::Exit) 69*5f757f3fSDimitry Andric .Default(OpenACCDirectiveKindEx::Invalid); 70*5f757f3fSDimitry Andric } 71*5f757f3fSDimitry Andric 72*5f757f3fSDimitry Andric // Since 'atomic' is effectively a compound directive, this will decode the 73*5f757f3fSDimitry Andric // second part of the directive. 74*5f757f3fSDimitry Andric OpenACCAtomicKind getOpenACCAtomicKind(Token Tok) { 75*5f757f3fSDimitry Andric if (!Tok.is(tok::identifier)) 76*5f757f3fSDimitry Andric return OpenACCAtomicKind::Invalid; 77*5f757f3fSDimitry Andric return llvm::StringSwitch<OpenACCAtomicKind>( 78*5f757f3fSDimitry Andric Tok.getIdentifierInfo()->getName()) 79*5f757f3fSDimitry Andric .Case("read", OpenACCAtomicKind::Read) 80*5f757f3fSDimitry Andric .Case("write", OpenACCAtomicKind::Write) 81*5f757f3fSDimitry Andric .Case("update", OpenACCAtomicKind::Update) 82*5f757f3fSDimitry Andric .Case("capture", OpenACCAtomicKind::Capture) 83*5f757f3fSDimitry Andric .Default(OpenACCAtomicKind::Invalid); 84*5f757f3fSDimitry Andric } 85*5f757f3fSDimitry Andric 86*5f757f3fSDimitry Andric enum class OpenACCSpecialTokenKind { 87*5f757f3fSDimitry Andric ReadOnly, 88*5f757f3fSDimitry Andric DevNum, 89*5f757f3fSDimitry Andric Queues, 90*5f757f3fSDimitry Andric }; 91*5f757f3fSDimitry Andric 92*5f757f3fSDimitry Andric bool isOpenACCSpecialToken(OpenACCSpecialTokenKind Kind, Token Tok) { 93*5f757f3fSDimitry Andric if (!Tok.is(tok::identifier)) 94*5f757f3fSDimitry Andric return false; 95*5f757f3fSDimitry Andric 96*5f757f3fSDimitry Andric switch (Kind) { 97*5f757f3fSDimitry Andric case OpenACCSpecialTokenKind::ReadOnly: 98*5f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("readonly"); 99*5f757f3fSDimitry Andric case OpenACCSpecialTokenKind::DevNum: 100*5f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("devnum"); 101*5f757f3fSDimitry Andric case OpenACCSpecialTokenKind::Queues: 102*5f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("queues"); 103*5f757f3fSDimitry Andric } 104*5f757f3fSDimitry Andric llvm_unreachable("Unknown 'Kind' Passed"); 105*5f757f3fSDimitry Andric } 106*5f757f3fSDimitry Andric 107*5f757f3fSDimitry Andric bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, Token Tok) { 108*5f757f3fSDimitry Andric if (!Tok.is(tok::identifier)) 109*5f757f3fSDimitry Andric return false; 110*5f757f3fSDimitry Andric 111*5f757f3fSDimitry Andric switch (Kind) { 112*5f757f3fSDimitry Andric case OpenACCDirectiveKind::Parallel: 113*5f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("parallel"); 114*5f757f3fSDimitry Andric case OpenACCDirectiveKind::Serial: 115*5f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("serial"); 116*5f757f3fSDimitry Andric case OpenACCDirectiveKind::Kernels: 117*5f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("kernels"); 118*5f757f3fSDimitry Andric case OpenACCDirectiveKind::Data: 119*5f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("data"); 120*5f757f3fSDimitry Andric case OpenACCDirectiveKind::HostData: 121*5f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("host_data"); 122*5f757f3fSDimitry Andric case OpenACCDirectiveKind::Loop: 123*5f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("loop"); 124*5f757f3fSDimitry Andric case OpenACCDirectiveKind::Cache: 125*5f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("cache"); 126*5f757f3fSDimitry Andric 127*5f757f3fSDimitry Andric case OpenACCDirectiveKind::ParallelLoop: 128*5f757f3fSDimitry Andric case OpenACCDirectiveKind::SerialLoop: 129*5f757f3fSDimitry Andric case OpenACCDirectiveKind::KernelsLoop: 130*5f757f3fSDimitry Andric case OpenACCDirectiveKind::EnterData: 131*5f757f3fSDimitry Andric case OpenACCDirectiveKind::ExitData: 132*5f757f3fSDimitry Andric return false; 133*5f757f3fSDimitry Andric 134*5f757f3fSDimitry Andric case OpenACCDirectiveKind::Atomic: 135*5f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("atomic"); 136*5f757f3fSDimitry Andric case OpenACCDirectiveKind::Routine: 137*5f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("routine"); 138*5f757f3fSDimitry Andric case OpenACCDirectiveKind::Declare: 139*5f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("declare"); 140*5f757f3fSDimitry Andric case OpenACCDirectiveKind::Init: 141*5f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("init"); 142*5f757f3fSDimitry Andric case OpenACCDirectiveKind::Shutdown: 143*5f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("shutdown"); 144*5f757f3fSDimitry Andric case OpenACCDirectiveKind::Set: 145*5f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("set"); 146*5f757f3fSDimitry Andric case OpenACCDirectiveKind::Update: 147*5f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("update"); 148*5f757f3fSDimitry Andric case OpenACCDirectiveKind::Wait: 149*5f757f3fSDimitry Andric return Tok.getIdentifierInfo()->isStr("wait"); 150*5f757f3fSDimitry Andric case OpenACCDirectiveKind::Invalid: 151*5f757f3fSDimitry Andric return false; 152*5f757f3fSDimitry Andric } 153*5f757f3fSDimitry Andric llvm_unreachable("Unknown 'Kind' Passed"); 154*5f757f3fSDimitry Andric } 155*5f757f3fSDimitry Andric 156*5f757f3fSDimitry Andric OpenACCDirectiveKind 157*5f757f3fSDimitry Andric ParseOpenACCEnterExitDataDirective(Parser &P, Token FirstTok, 158*5f757f3fSDimitry Andric OpenACCDirectiveKindEx ExtDirKind) { 159*5f757f3fSDimitry Andric Token SecondTok = P.getCurToken(); 160*5f757f3fSDimitry Andric 161*5f757f3fSDimitry Andric if (SecondTok.isAnnotation()) { 162*5f757f3fSDimitry Andric P.Diag(FirstTok, diag::err_acc_invalid_directive) 163*5f757f3fSDimitry Andric << 0 << FirstTok.getIdentifierInfo(); 164*5f757f3fSDimitry Andric return OpenACCDirectiveKind::Invalid; 165*5f757f3fSDimitry Andric } 166*5f757f3fSDimitry Andric 167*5f757f3fSDimitry Andric if (!isOpenACCDirectiveKind(OpenACCDirectiveKind::Data, SecondTok)) { 168*5f757f3fSDimitry Andric if (!SecondTok.is(tok::identifier)) 169*5f757f3fSDimitry Andric P.Diag(SecondTok, diag::err_expected) << tok::identifier; 170*5f757f3fSDimitry Andric else 171*5f757f3fSDimitry Andric P.Diag(FirstTok, diag::err_acc_invalid_directive) 172*5f757f3fSDimitry Andric << 1 << FirstTok.getIdentifierInfo()->getName() 173*5f757f3fSDimitry Andric << SecondTok.getIdentifierInfo()->getName(); 174*5f757f3fSDimitry Andric return OpenACCDirectiveKind::Invalid; 175*5f757f3fSDimitry Andric } 176*5f757f3fSDimitry Andric 177*5f757f3fSDimitry Andric P.ConsumeToken(); 178*5f757f3fSDimitry Andric 179*5f757f3fSDimitry Andric return ExtDirKind == OpenACCDirectiveKindEx::Enter 180*5f757f3fSDimitry Andric ? OpenACCDirectiveKind::EnterData 181*5f757f3fSDimitry Andric : OpenACCDirectiveKind::ExitData; 182*5f757f3fSDimitry Andric } 183*5f757f3fSDimitry Andric 184*5f757f3fSDimitry Andric OpenACCAtomicKind ParseOpenACCAtomicKind(Parser &P) { 185*5f757f3fSDimitry Andric Token AtomicClauseToken = P.getCurToken(); 186*5f757f3fSDimitry Andric 187*5f757f3fSDimitry Andric // #pragma acc atomic is equivilent to update: 188*5f757f3fSDimitry Andric if (AtomicClauseToken.isAnnotation()) 189*5f757f3fSDimitry Andric return OpenACCAtomicKind::Update; 190*5f757f3fSDimitry Andric 191*5f757f3fSDimitry Andric OpenACCAtomicKind AtomicKind = getOpenACCAtomicKind(AtomicClauseToken); 192*5f757f3fSDimitry Andric 193*5f757f3fSDimitry Andric // If we don't know what this is, treat it as 'nothing', and treat the rest of 194*5f757f3fSDimitry Andric // this as a clause list, which, despite being invalid, is likely what the 195*5f757f3fSDimitry Andric // user was trying to do. 196*5f757f3fSDimitry Andric if (AtomicKind == OpenACCAtomicKind::Invalid) 197*5f757f3fSDimitry Andric return OpenACCAtomicKind::Update; 198*5f757f3fSDimitry Andric 199*5f757f3fSDimitry Andric P.ConsumeToken(); 200*5f757f3fSDimitry Andric return AtomicKind; 201*5f757f3fSDimitry Andric } 202*5f757f3fSDimitry Andric 203*5f757f3fSDimitry Andric // Parse and consume the tokens for OpenACC Directive/Construct kinds. 204*5f757f3fSDimitry Andric OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) { 205*5f757f3fSDimitry Andric Token FirstTok = P.getCurToken(); 206*5f757f3fSDimitry Andric 207*5f757f3fSDimitry Andric // Just #pragma acc can get us immediately to the end, make sure we don't 208*5f757f3fSDimitry Andric // introspect on the spelling before then. 209*5f757f3fSDimitry Andric if (FirstTok.isNot(tok::identifier)) { 210*5f757f3fSDimitry Andric P.Diag(FirstTok, diag::err_acc_missing_directive); 211*5f757f3fSDimitry Andric return OpenACCDirectiveKind::Invalid; 212*5f757f3fSDimitry Andric } 213*5f757f3fSDimitry Andric 214*5f757f3fSDimitry Andric P.ConsumeToken(); 215*5f757f3fSDimitry Andric 216*5f757f3fSDimitry Andric OpenACCDirectiveKindEx ExDirKind = getOpenACCDirectiveKind(FirstTok); 217*5f757f3fSDimitry Andric 218*5f757f3fSDimitry Andric // OpenACCDirectiveKindEx is meant to be an extended list 219*5f757f3fSDimitry Andric // over OpenACCDirectiveKind, so any value below Invalid is one of the 220*5f757f3fSDimitry Andric // OpenACCDirectiveKind values. This switch takes care of all of the extra 221*5f757f3fSDimitry Andric // parsing required for the Extended values. At the end of this block, 222*5f757f3fSDimitry Andric // ExDirKind can be assumed to be a valid OpenACCDirectiveKind, so we can 223*5f757f3fSDimitry Andric // immediately cast it and use it as that. 224*5f757f3fSDimitry Andric if (ExDirKind >= OpenACCDirectiveKindEx::Invalid) { 225*5f757f3fSDimitry Andric switch (ExDirKind) { 226*5f757f3fSDimitry Andric case OpenACCDirectiveKindEx::Invalid: { 227*5f757f3fSDimitry Andric P.Diag(FirstTok, diag::err_acc_invalid_directive) 228*5f757f3fSDimitry Andric << 0 << FirstTok.getIdentifierInfo(); 229*5f757f3fSDimitry Andric return OpenACCDirectiveKind::Invalid; 230*5f757f3fSDimitry Andric } 231*5f757f3fSDimitry Andric case OpenACCDirectiveKindEx::Enter: 232*5f757f3fSDimitry Andric case OpenACCDirectiveKindEx::Exit: 233*5f757f3fSDimitry Andric return ParseOpenACCEnterExitDataDirective(P, FirstTok, ExDirKind); 234*5f757f3fSDimitry Andric } 235*5f757f3fSDimitry Andric } 236*5f757f3fSDimitry Andric 237*5f757f3fSDimitry Andric OpenACCDirectiveKind DirKind = static_cast<OpenACCDirectiveKind>(ExDirKind); 238*5f757f3fSDimitry Andric 239*5f757f3fSDimitry Andric // Combined Constructs allows parallel loop, serial loop, or kernels loop. Any 240*5f757f3fSDimitry Andric // other attempt at a combined construct will be diagnosed as an invalid 241*5f757f3fSDimitry Andric // clause. 242*5f757f3fSDimitry Andric Token SecondTok = P.getCurToken(); 243*5f757f3fSDimitry Andric if (!SecondTok.isAnnotation() && 244*5f757f3fSDimitry Andric isOpenACCDirectiveKind(OpenACCDirectiveKind::Loop, SecondTok)) { 245*5f757f3fSDimitry Andric switch (DirKind) { 246*5f757f3fSDimitry Andric default: 247*5f757f3fSDimitry Andric // Nothing to do except in the below cases, as they should be diagnosed as 248*5f757f3fSDimitry Andric // a clause. 249*5f757f3fSDimitry Andric break; 250*5f757f3fSDimitry Andric case OpenACCDirectiveKind::Parallel: 251*5f757f3fSDimitry Andric P.ConsumeToken(); 252*5f757f3fSDimitry Andric return OpenACCDirectiveKind::ParallelLoop; 253*5f757f3fSDimitry Andric case OpenACCDirectiveKind::Serial: 254*5f757f3fSDimitry Andric P.ConsumeToken(); 255*5f757f3fSDimitry Andric return OpenACCDirectiveKind::SerialLoop; 256*5f757f3fSDimitry Andric case OpenACCDirectiveKind::Kernels: 257*5f757f3fSDimitry Andric P.ConsumeToken(); 258*5f757f3fSDimitry Andric return OpenACCDirectiveKind::KernelsLoop; 259*5f757f3fSDimitry Andric } 260*5f757f3fSDimitry Andric } 261*5f757f3fSDimitry Andric 262*5f757f3fSDimitry Andric return DirKind; 263*5f757f3fSDimitry Andric } 264*5f757f3fSDimitry Andric 265*5f757f3fSDimitry Andric void ParseOpenACCClauseList(Parser &P) { 266*5f757f3fSDimitry Andric // FIXME: In the future, we'll start parsing the clauses here, but for now we 267*5f757f3fSDimitry Andric // haven't implemented that, so just emit the unimplemented diagnostic and 268*5f757f3fSDimitry Andric // fail reasonably. 269*5f757f3fSDimitry Andric if (P.getCurToken().isNot(tok::annot_pragma_openacc_end)) 270*5f757f3fSDimitry Andric P.Diag(P.getCurToken(), diag::warn_pragma_acc_unimplemented_clause_parsing); 271*5f757f3fSDimitry Andric } 272*5f757f3fSDimitry Andric 273*5f757f3fSDimitry Andric } // namespace 274*5f757f3fSDimitry Andric 275*5f757f3fSDimitry Andric /// OpenACC 3.3, section 2.16: 276*5f757f3fSDimitry Andric /// In this section and throughout the specification, the term wait-argument 277*5f757f3fSDimitry Andric /// means: 278*5f757f3fSDimitry Andric /// [ devnum : int-expr : ] [ queues : ] async-argument-list 279*5f757f3fSDimitry Andric bool Parser::ParseOpenACCWaitArgument() { 280*5f757f3fSDimitry Andric // [devnum : int-expr : ] 281*5f757f3fSDimitry Andric if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::DevNum, Tok) && 282*5f757f3fSDimitry Andric NextToken().is(tok::colon)) { 283*5f757f3fSDimitry Andric // Consume devnum. 284*5f757f3fSDimitry Andric ConsumeToken(); 285*5f757f3fSDimitry Andric // Consume colon. 286*5f757f3fSDimitry Andric ConsumeToken(); 287*5f757f3fSDimitry Andric 288*5f757f3fSDimitry Andric ExprResult IntExpr = 289*5f757f3fSDimitry Andric getActions().CorrectDelayedTyposInExpr(ParseAssignmentExpression()); 290*5f757f3fSDimitry Andric if (IntExpr.isInvalid()) 291*5f757f3fSDimitry Andric return true; 292*5f757f3fSDimitry Andric 293*5f757f3fSDimitry Andric if (ExpectAndConsume(tok::colon)) 294*5f757f3fSDimitry Andric return true; 295*5f757f3fSDimitry Andric } 296*5f757f3fSDimitry Andric 297*5f757f3fSDimitry Andric // [ queues : ] 298*5f757f3fSDimitry Andric if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Queues, Tok) && 299*5f757f3fSDimitry Andric NextToken().is(tok::colon)) { 300*5f757f3fSDimitry Andric // Consume queues. 301*5f757f3fSDimitry Andric ConsumeToken(); 302*5f757f3fSDimitry Andric // Consume colon. 303*5f757f3fSDimitry Andric ConsumeToken(); 304*5f757f3fSDimitry Andric } 305*5f757f3fSDimitry Andric 306*5f757f3fSDimitry Andric // OpenACC 3.3, section 2.16: 307*5f757f3fSDimitry Andric // the term 'async-argument' means a nonnegative scalar integer expression, or 308*5f757f3fSDimitry Andric // one of the special values 'acc_async_noval' or 'acc_async_sync', as defined 309*5f757f3fSDimitry Andric // in the C header file and the Fortran opacc module. 310*5f757f3fSDimitry Andric // 311*5f757f3fSDimitry Andric // We are parsing this simply as list of assignment expressions (to avoid 312*5f757f3fSDimitry Andric // comma being troublesome), and will ensure it is an integral type. The 313*5f757f3fSDimitry Andric // 'special' types are defined as macros, so we can't really check those 314*5f757f3fSDimitry Andric // (other than perhaps as values at one point?), but the standard does say it 315*5f757f3fSDimitry Andric // is implementation-defined to use any other negative value. 316*5f757f3fSDimitry Andric // 317*5f757f3fSDimitry Andric // 318*5f757f3fSDimitry Andric bool FirstArg = true; 319*5f757f3fSDimitry Andric while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) { 320*5f757f3fSDimitry Andric if (!FirstArg) { 321*5f757f3fSDimitry Andric if (ExpectAndConsume(tok::comma)) 322*5f757f3fSDimitry Andric return true; 323*5f757f3fSDimitry Andric } 324*5f757f3fSDimitry Andric FirstArg = false; 325*5f757f3fSDimitry Andric 326*5f757f3fSDimitry Andric ExprResult CurArg = 327*5f757f3fSDimitry Andric getActions().CorrectDelayedTyposInExpr(ParseAssignmentExpression()); 328*5f757f3fSDimitry Andric 329*5f757f3fSDimitry Andric if (CurArg.isInvalid()) 330*5f757f3fSDimitry Andric return true; 331*5f757f3fSDimitry Andric } 332*5f757f3fSDimitry Andric 333*5f757f3fSDimitry Andric return false; 334*5f757f3fSDimitry Andric } 335*5f757f3fSDimitry Andric 336*5f757f3fSDimitry Andric ExprResult Parser::ParseOpenACCIDExpression() { 337*5f757f3fSDimitry Andric ExprResult Res; 338*5f757f3fSDimitry Andric if (getLangOpts().CPlusPlus) { 339*5f757f3fSDimitry Andric Res = ParseCXXIdExpression(/*isAddressOfOperand=*/false); 340*5f757f3fSDimitry Andric } else { 341*5f757f3fSDimitry Andric // There isn't anything quite the same as ParseCXXIdExpression for C, so we 342*5f757f3fSDimitry Andric // need to get the identifier, then call into Sema ourselves. 343*5f757f3fSDimitry Andric 344*5f757f3fSDimitry Andric if (Tok.isNot(tok::identifier)) { 345*5f757f3fSDimitry Andric Diag(Tok, diag::err_expected) << tok::identifier; 346*5f757f3fSDimitry Andric return ExprError(); 347*5f757f3fSDimitry Andric } 348*5f757f3fSDimitry Andric 349*5f757f3fSDimitry Andric Token FuncName = getCurToken(); 350*5f757f3fSDimitry Andric UnqualifiedId Name; 351*5f757f3fSDimitry Andric CXXScopeSpec ScopeSpec; 352*5f757f3fSDimitry Andric SourceLocation TemplateKWLoc; 353*5f757f3fSDimitry Andric Name.setIdentifier(FuncName.getIdentifierInfo(), ConsumeToken()); 354*5f757f3fSDimitry Andric 355*5f757f3fSDimitry Andric // Ensure this is a valid identifier. We don't accept causing implicit 356*5f757f3fSDimitry Andric // function declarations per the spec, so always claim to not have trailing 357*5f757f3fSDimitry Andric // L Paren. 358*5f757f3fSDimitry Andric Res = Actions.ActOnIdExpression(getCurScope(), ScopeSpec, TemplateKWLoc, 359*5f757f3fSDimitry Andric Name, /*HasTrailingLParen=*/false, 360*5f757f3fSDimitry Andric /*isAddressOfOperand=*/false); 361*5f757f3fSDimitry Andric } 362*5f757f3fSDimitry Andric 363*5f757f3fSDimitry Andric return getActions().CorrectDelayedTyposInExpr(Res); 364*5f757f3fSDimitry Andric } 365*5f757f3fSDimitry Andric 366*5f757f3fSDimitry Andric /// OpenACC 3.3, section 2.10: 367*5f757f3fSDimitry Andric /// A 'var' in a cache directive must be a single array element or a simple 368*5f757f3fSDimitry Andric /// subarray. In C and C++, a simple subarray is an array name followed by an 369*5f757f3fSDimitry Andric /// extended array range specification in brackets, with a start and length such 370*5f757f3fSDimitry Andric /// as: 371*5f757f3fSDimitry Andric /// 372*5f757f3fSDimitry Andric /// arr[lower:length] 373*5f757f3fSDimitry Andric /// 374*5f757f3fSDimitry Andric bool Parser::ParseOpenACCCacheVar() { 375*5f757f3fSDimitry Andric ExprResult ArrayName = ParseOpenACCIDExpression(); 376*5f757f3fSDimitry Andric if (ArrayName.isInvalid()) 377*5f757f3fSDimitry Andric return true; 378*5f757f3fSDimitry Andric 379*5f757f3fSDimitry Andric // If the expression is invalid, just continue parsing the brackets, there 380*5f757f3fSDimitry Andric // is likely other useful diagnostics we can emit inside of those. 381*5f757f3fSDimitry Andric 382*5f757f3fSDimitry Andric BalancedDelimiterTracker SquareBrackets(*this, tok::l_square, 383*5f757f3fSDimitry Andric tok::annot_pragma_openacc_end); 384*5f757f3fSDimitry Andric 385*5f757f3fSDimitry Andric // Square brackets are required, so error here, and try to recover by moving 386*5f757f3fSDimitry Andric // until the next comma, or the close paren/end of pragma. 387*5f757f3fSDimitry Andric if (SquareBrackets.expectAndConsume()) { 388*5f757f3fSDimitry Andric SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openacc_end, 389*5f757f3fSDimitry Andric Parser::StopBeforeMatch); 390*5f757f3fSDimitry Andric return true; 391*5f757f3fSDimitry Andric } 392*5f757f3fSDimitry Andric 393*5f757f3fSDimitry Andric ExprResult Lower = getActions().CorrectDelayedTyposInExpr(ParseExpression()); 394*5f757f3fSDimitry Andric if (Lower.isInvalid()) 395*5f757f3fSDimitry Andric return true; 396*5f757f3fSDimitry Andric 397*5f757f3fSDimitry Andric // The 'length' expression is optional, as this could be a single array 398*5f757f3fSDimitry Andric // element. If there is no colon, we can treat it as that. 399*5f757f3fSDimitry Andric if (getCurToken().is(tok::colon)) { 400*5f757f3fSDimitry Andric ConsumeToken(); 401*5f757f3fSDimitry Andric ExprResult Length = 402*5f757f3fSDimitry Andric getActions().CorrectDelayedTyposInExpr(ParseExpression()); 403*5f757f3fSDimitry Andric if (Length.isInvalid()) 404*5f757f3fSDimitry Andric return true; 405*5f757f3fSDimitry Andric } 406*5f757f3fSDimitry Andric 407*5f757f3fSDimitry Andric // Diagnose the square bracket being in the wrong place and continue. 408*5f757f3fSDimitry Andric return SquareBrackets.consumeClose(); 409*5f757f3fSDimitry Andric } 410*5f757f3fSDimitry Andric 411*5f757f3fSDimitry Andric /// OpenACC 3.3, section 2.10: 412*5f757f3fSDimitry Andric /// In C and C++, the syntax of the cache directive is: 413*5f757f3fSDimitry Andric /// 414*5f757f3fSDimitry Andric /// #pragma acc cache ([readonly:]var-list) new-line 415*5f757f3fSDimitry Andric void Parser::ParseOpenACCCacheVarList() { 416*5f757f3fSDimitry Andric // If this is the end of the line, just return 'false' and count on the close 417*5f757f3fSDimitry Andric // paren diagnostic to catch the issue. 418*5f757f3fSDimitry Andric if (getCurToken().isAnnotation()) 419*5f757f3fSDimitry Andric return; 420*5f757f3fSDimitry Andric 421*5f757f3fSDimitry Andric // The VarList is an optional `readonly:` followed by a list of a variable 422*5f757f3fSDimitry Andric // specifications. First, see if we have `readonly:`, else we back-out and 423*5f757f3fSDimitry Andric // treat it like the beginning of a reference to a potentially-existing 424*5f757f3fSDimitry Andric // `readonly` variable. 425*5f757f3fSDimitry Andric if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::ReadOnly, Tok) && 426*5f757f3fSDimitry Andric NextToken().is(tok::colon)) { 427*5f757f3fSDimitry Andric // Consume both tokens. 428*5f757f3fSDimitry Andric ConsumeToken(); 429*5f757f3fSDimitry Andric ConsumeToken(); 430*5f757f3fSDimitry Andric // FIXME: Record that this is a 'readonly' so that we can use that during 431*5f757f3fSDimitry Andric // Sema/AST generation. 432*5f757f3fSDimitry Andric } 433*5f757f3fSDimitry Andric 434*5f757f3fSDimitry Andric bool FirstArray = true; 435*5f757f3fSDimitry Andric while (!getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) { 436*5f757f3fSDimitry Andric if (!FirstArray) 437*5f757f3fSDimitry Andric ExpectAndConsume(tok::comma); 438*5f757f3fSDimitry Andric FirstArray = false; 439*5f757f3fSDimitry Andric if (ParseOpenACCCacheVar()) 440*5f757f3fSDimitry Andric SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end, tok::comma, 441*5f757f3fSDimitry Andric StopBeforeMatch); 442*5f757f3fSDimitry Andric } 443*5f757f3fSDimitry Andric } 444*5f757f3fSDimitry Andric 445*5f757f3fSDimitry Andric void Parser::ParseOpenACCDirective() { 446*5f757f3fSDimitry Andric OpenACCDirectiveKind DirKind = ParseOpenACCDirectiveKind(*this); 447*5f757f3fSDimitry Andric 448*5f757f3fSDimitry Andric // Once we've parsed the construct/directive name, some have additional 449*5f757f3fSDimitry Andric // specifiers that need to be taken care of. Atomic has an 'atomic-clause' 450*5f757f3fSDimitry Andric // that needs to be parsed. 451*5f757f3fSDimitry Andric if (DirKind == OpenACCDirectiveKind::Atomic) 452*5f757f3fSDimitry Andric ParseOpenACCAtomicKind(*this); 453*5f757f3fSDimitry Andric 454*5f757f3fSDimitry Andric // We've successfully parsed the construct/directive name, however a few of 455*5f757f3fSDimitry Andric // the constructs have optional parens that contain further details. 456*5f757f3fSDimitry Andric BalancedDelimiterTracker T(*this, tok::l_paren, 457*5f757f3fSDimitry Andric tok::annot_pragma_openacc_end); 458*5f757f3fSDimitry Andric 459*5f757f3fSDimitry Andric if (!T.consumeOpen()) { 460*5f757f3fSDimitry Andric switch (DirKind) { 461*5f757f3fSDimitry Andric default: 462*5f757f3fSDimitry Andric Diag(T.getOpenLocation(), diag::err_acc_invalid_open_paren); 463*5f757f3fSDimitry Andric T.skipToEnd(); 464*5f757f3fSDimitry Andric break; 465*5f757f3fSDimitry Andric case OpenACCDirectiveKind::Routine: { 466*5f757f3fSDimitry Andric // Routine has an optional paren-wrapped name of a function in the local 467*5f757f3fSDimitry Andric // scope. We parse the name, emitting any diagnostics 468*5f757f3fSDimitry Andric ExprResult RoutineName = ParseOpenACCIDExpression(); 469*5f757f3fSDimitry Andric // If the routine name is invalid, just skip until the closing paren to 470*5f757f3fSDimitry Andric // recover more gracefully. 471*5f757f3fSDimitry Andric if (RoutineName.isInvalid()) 472*5f757f3fSDimitry Andric T.skipToEnd(); 473*5f757f3fSDimitry Andric else 474*5f757f3fSDimitry Andric T.consumeClose(); 475*5f757f3fSDimitry Andric break; 476*5f757f3fSDimitry Andric } 477*5f757f3fSDimitry Andric case OpenACCDirectiveKind::Cache: 478*5f757f3fSDimitry Andric ParseOpenACCCacheVarList(); 479*5f757f3fSDimitry Andric // The ParseOpenACCCacheVarList function manages to recover from failures, 480*5f757f3fSDimitry Andric // so we can always consume the close. 481*5f757f3fSDimitry Andric T.consumeClose(); 482*5f757f3fSDimitry Andric break; 483*5f757f3fSDimitry Andric case OpenACCDirectiveKind::Wait: 484*5f757f3fSDimitry Andric // OpenACC has an optional paren-wrapped 'wait-argument'. 485*5f757f3fSDimitry Andric if (ParseOpenACCWaitArgument()) 486*5f757f3fSDimitry Andric T.skipToEnd(); 487*5f757f3fSDimitry Andric else 488*5f757f3fSDimitry Andric T.consumeClose(); 489*5f757f3fSDimitry Andric break; 490*5f757f3fSDimitry Andric } 491*5f757f3fSDimitry Andric } else if (DirKind == OpenACCDirectiveKind::Cache) { 492*5f757f3fSDimitry Andric // Cache's paren var-list is required, so error here if it isn't provided. 493*5f757f3fSDimitry Andric // We know that the consumeOpen above left the first non-paren here, so 494*5f757f3fSDimitry Andric // diagnose, then continue as if it was completely omitted. 495*5f757f3fSDimitry Andric Diag(Tok, diag::err_expected) << tok::l_paren; 496*5f757f3fSDimitry Andric } 497*5f757f3fSDimitry Andric 498*5f757f3fSDimitry Andric // Parses the list of clauses, if present. 499*5f757f3fSDimitry Andric ParseOpenACCClauseList(*this); 500*5f757f3fSDimitry Andric 501*5f757f3fSDimitry Andric Diag(getCurToken(), diag::warn_pragma_acc_unimplemented); 502*5f757f3fSDimitry Andric SkipUntil(tok::annot_pragma_openacc_end); 503*5f757f3fSDimitry Andric } 504*5f757f3fSDimitry Andric 505*5f757f3fSDimitry Andric // Parse OpenACC directive on a declaration. 506*5f757f3fSDimitry Andric Parser::DeclGroupPtrTy Parser::ParseOpenACCDirectiveDecl() { 507*5f757f3fSDimitry Andric assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token"); 508*5f757f3fSDimitry Andric 509*5f757f3fSDimitry Andric ParsingOpenACCDirectiveRAII DirScope(*this); 510*5f757f3fSDimitry Andric ConsumeAnnotationToken(); 511*5f757f3fSDimitry Andric 512*5f757f3fSDimitry Andric ParseOpenACCDirective(); 513*5f757f3fSDimitry Andric 514*5f757f3fSDimitry Andric return nullptr; 515*5f757f3fSDimitry Andric } 516*5f757f3fSDimitry Andric 517*5f757f3fSDimitry Andric // Parse OpenACC Directive on a Statement. 518*5f757f3fSDimitry Andric StmtResult Parser::ParseOpenACCDirectiveStmt() { 519*5f757f3fSDimitry Andric assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token"); 520*5f757f3fSDimitry Andric 521*5f757f3fSDimitry Andric ParsingOpenACCDirectiveRAII DirScope(*this); 522*5f757f3fSDimitry Andric ConsumeAnnotationToken(); 523*5f757f3fSDimitry Andric 524*5f757f3fSDimitry Andric ParseOpenACCDirective(); 525*5f757f3fSDimitry Andric 526*5f757f3fSDimitry Andric return StmtEmpty(); 527*5f757f3fSDimitry Andric } 528