clang: lib/Parse/ParseOpenACC.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

20#include "llvm/ADT/StringRef.h"

21#include "llvm/ADT/StringSwitch.h"

22

23using namespace clang;

24using namespace llvm;

25

26namespace {

27

28

29

30enum class OpenACCDirectiveKindEx {

32

33 Enter,

34 Exit,

35};

36

37

38

39

40

41

42OpenACCDirectiveKindEx getOpenACCDirectiveKind(Token Tok) {

43 if (Tok.is(tok::identifier))

44 return OpenACCDirectiveKindEx::Invalid;

46 llvm::StringSwitch(

47 Tok.getIdentifierInfo()->getName())

64

66 return static_cast<OpenACCDirectiveKindEx>(DirKind);

67

68 return llvm::StringSwitch(

69 Tok.getIdentifierInfo()->getName())

70 .Case("enter", OpenACCDirectiveKindEx::Enter)

71 .Case("exit", OpenACCDirectiveKindEx::Exit)

72 .Default(OpenACCDirectiveKindEx::Invalid);

73}

74

75

77

78

79 if (Tok.is(tok::kw_auto))

81

82

83 if (Tok.is(tok::kw_default))

85

86

87 if (Tok.is(tok::kw_if))

89

90

91 if (Tok.is(tok::kw_private))

93

94

95 if (Tok.is(tok::kw_delete))

97

98 if (Tok.is(tok::identifier))

100

101 return llvm::StringSwitch(

102 Tok.getIdentifierInfo()->getName())

154}

155

156

157

159 if (Tok.is(tok::identifier))

161 return llvm::StringSwitch(

162 Tok.getIdentifierInfo()->getName())

168}

169

171 if (Tok.is(tok::identifier))

173

174 return llvm::StringSwitch(

175 Tok.getIdentifierInfo()->getName())

179}

180

181enum class OpenACCSpecialTokenKind {

182 ReadOnly,

183 DevNum,

184 Queues,

186 Force,

188 Length,

191};

192

193bool isOpenACCSpecialToken(OpenACCSpecialTokenKind Kind, Token Tok) {

194 if (Tok.is(tok::kw_static) && Kind == OpenACCSpecialTokenKind::Static)

195 return true;

196

197 if (Tok.is(tok::identifier))

198 return false;

199

200 switch (Kind) {

201 case OpenACCSpecialTokenKind::ReadOnly:

202 return Tok.getIdentifierInfo()->isStr("readonly");

203 case OpenACCSpecialTokenKind::DevNum:

204 return Tok.getIdentifierInfo()->isStr("devnum");

205 case OpenACCSpecialTokenKind::Queues:

206 return Tok.getIdentifierInfo()->isStr("queues");

207 case OpenACCSpecialTokenKind::Zero:

208 return Tok.getIdentifierInfo()->isStr("zero");

209 case OpenACCSpecialTokenKind::Force:

210 return Tok.getIdentifierInfo()->isStr("force");

211 case OpenACCSpecialTokenKind::Num:

212 return Tok.getIdentifierInfo()->isStr("num");

213 case OpenACCSpecialTokenKind::Length:

214 return Tok.getIdentifierInfo()->isStr("length");

215 case OpenACCSpecialTokenKind::Dim:

216 return Tok.getIdentifierInfo()->isStr("dim");

217 case OpenACCSpecialTokenKind::Static:

218 return Tok.getIdentifierInfo()->isStr("static");

219 }

220 llvm_unreachable("Unknown 'Kind' Passed");

221}

222

223

224

225

226bool isTokenIdentifierOrKeyword(Parser &P, Token Tok) {

227 if (Tok.is(tok::identifier))

228 return true;

229

230 if (Tok.isAnnotation() && Tok.getIdentifierInfo() &&

232 return true;

233

234 return false;

235}

236

237

238

239

240

241

242template

243bool tryParseAndConsumeSpecialTokenKind(Parser &P, OpenACCSpecialTokenKind Kind,

244 DirOrClauseTy DirOrClause) {

246

247

248 if (isTokenIdentifierOrKeyword(P, IdentTok) && P.NextToken().is(tok::colon)) {

251

252 if (!isOpenACCSpecialToken(Kind, IdentTok)) {

253 P.Diag(IdentTok, diag::err_acc_invalid_tag_kind)

255 << std::is_same_v<DirOrClauseTy, OpenACCClauseKind>;

256 return false;

257 }

258

259 return true;

260 }

261

262 return false;

263}

264

266 if (Tok.is(tok::identifier))

267 return false;

268

269 switch (Kind) {

271 return Tok.getIdentifierInfo()->isStr("parallel");

273 return Tok.getIdentifierInfo()->isStr("serial");

275 return Tok.getIdentifierInfo()->isStr("kernels");

277 return Tok.getIdentifierInfo()->isStr("data");

279 return Tok.getIdentifierInfo()->isStr("host_data");

281 return Tok.getIdentifierInfo()->isStr("loop");

283 return Tok.getIdentifierInfo()->isStr("cache");

284

290 return false;

291

293 return Tok.getIdentifierInfo()->isStr("atomic");

295 return Tok.getIdentifierInfo()->isStr("routine");

297 return Tok.getIdentifierInfo()->isStr("declare");

299 return Tok.getIdentifierInfo()->isStr("init");

301 return Tok.getIdentifierInfo()->isStr("shutdown");

303 return Tok.getIdentifierInfo()->isStr("set");

305 return Tok.getIdentifierInfo()->isStr("update");

307 return Tok.getIdentifierInfo()->isStr("wait");

309 return false;

310 }

311 llvm_unreachable("Unknown 'Kind' Passed");

312}

313

315

316

317

319 P.Diag(P.getCurToken(), diag::err_acc_expected_reduction_operator);

321 }

323

326

327 switch (ReductionKindTok.getKind()) {

328 case tok:➕

330 case tok:⭐

332 case tok::amp:

334 case tok::pipe:

336 case tok::caret:

338 case tok::ampamp:

340 case tok::pipepipe:

342 case tok::identifier:

347 [[fallthrough]];

348 default:

349 P.Diag(ReductionKindTok, diag::err_acc_invalid_reduction_operator);

351 }

352 llvm_unreachable("Reduction op token kind not caught by 'default'?");

353}

354

355

356

357bool expectIdentifierOrKeyword(Parser &P) {

359

360 if (isTokenIdentifierOrKeyword(P, Tok))

361 return false;

362

363 P.Diag(P.getCurToken(), diag::err_expected) << tok::identifier;

364 return true;

365}

366

368ParseOpenACCEnterExitDataDirective(Parser &P, Token FirstTok,

369 OpenACCDirectiveKindEx ExtDirKind) {

371

373 P.Diag(FirstTok, diag::err_acc_invalid_directive)

376 }

377

378

379

381

383 if (!SecondTok.is(tok::identifier))

384 P.Diag(SecondTok, diag::err_expected) << tok::identifier;

385 else

386 P.Diag(FirstTok, diag::err_acc_invalid_directive)

390 }

391

392 return ExtDirKind == OpenACCDirectiveKindEx::Enter

395}

396

399

400

403

404 OpenACCAtomicKind AtomicKind = getOpenACCAtomicKind(AtomicClauseToken);

405

406

407

408

411

412 return AtomicKind;

413}

414

415

418

419

420

421 if (FirstTok.isNot(tok::identifier)) {

422 P.Diag(FirstTok, diag::err_acc_missing_directive);

423

426

428 }

429

431

432 OpenACCDirectiveKindEx ExDirKind = getOpenACCDirectiveKind(FirstTok);

433

434

435

436

437

438

439

440 if (ExDirKind >= OpenACCDirectiveKindEx::Invalid) {

441 switch (ExDirKind) {

442 case OpenACCDirectiveKindEx::Invalid: {

443 P.Diag(FirstTok, diag::err_acc_invalid_directive)

446 }

447 case OpenACCDirectiveKindEx::Enter:

448 case OpenACCDirectiveKindEx::Exit:

449 return ParseOpenACCEnterExitDataDirective(P, FirstTok, ExDirKind);

450 }

451 }

452

454

455

456

457

461 switch (DirKind) {

462 default:

463

464

465 break;

475 }

476 }

477

478 return DirKind;

479}

480

481enum ClauseParensKind {

485};

486

489 switch (Kind) {

492 : ClauseParensKind::Optional;

498 return ClauseParensKind::Optional;

499

538 return ClauseParensKind::Required;

539

541 llvm_unreachable("Shortloop shouldn't be generated in clang");

549 return ClauseParensKind::None;

550 }

551 llvm_unreachable("Unhandled clause kind");

552}

553

556 return getClauseParensKind(DirKind, Kind) == ClauseParensKind::Optional;

557}

558

561 return getClauseParensKind(DirKind, Kind) == ClauseParensKind::Required;

562}

563

564

565

566

567

568void SkipUntilEndOfDirective(Parser &P) {

571}

572

574 switch (DirKind) {

576

577

588 return false;

599 return true;

600 }

601 llvm_unreachable("Unhandled directive->assoc stmt");

602}

603

605 switch (DirKind) {

609

610

616

617

636 return 0;

638 llvm_unreachable("Shouldn't be creating a scope for an invalid construct");

639 }

640 llvm_unreachable("Shouldn't be creating a scope for an invalid construct");

641}

642

643}

644

645Parser::OpenACCClauseParseResult Parser::OpenACCCanContinue() {

646 return {nullptr, OpenACCParseCanContinue::Can};

647}

648

649Parser::OpenACCClauseParseResult Parser::OpenACCCannotContinue() {

650 return {nullptr, OpenACCParseCanContinue::Cannot};

651}

652

653Parser::OpenACCClauseParseResult Parser::OpenACCSuccess(OpenACCClause *Clause) {

654 return {Clause, OpenACCParseCanContinue::Can};

655}

656

657ExprResult Parser::ParseOpenACCConditionExpr() {

658

659

660

661

663

665 return ER;

666

667 Sema::ConditionResult R =

670

672}

673

675

676

677 {

678 RevertingTentativeParsingAction TPA{*this};

679

680 while (isTokenIdentifierOrKeyword(*this, getCurToken()) &&

684 }

685

686 if (!isTokenIdentifierOrKeyword(*this, getCurToken()) ||

688

690 }

691 }

692

693 auto GetModKind = [](Token T) {

694 return StringSwitch(T.getIdentifierInfo()->getName())

702 };

703

705 auto ConsumeModKind = [&]() {

708

711 << diag::ACCModifier::Unknown << IdentToken.getIdentifierInfo() << CK;

714 << diag::ACCModifier::Duplicate << IdentToken.getIdentifierInfo()

715 << CK;

716 else

717 CurModList |= NewKind;

718

719

721

723 };

724

725

726

728 ConsumeModKind();

729

730

731

732 ConsumeModKind();

733

734 return CurModList;

735}

736

739 SmallVector<OpenACCClause *> Clauses;

740 bool FirstClause = true;

742

743 if (!FirstClause && getCurToken().is(tok::comma))

745 FirstClause = false;

746

747 OpenACCClauseParseResult Result = ParseOpenACCClause(Clauses, DirKind);

748 if (OpenACCClause *Clause = Result.getPointer()) {

749 Clauses.push_back(Clause);

750 } else if (Result.getInt() == OpenACCParseCanContinue::Cannot) {

751

752

753 SkipUntilEndOfDirective(*this);

754 return Clauses;

755 }

756 }

757 return Clauses;

758}

759

760Parser::OpenACCIntExprParseResult

764

765

766

768 return {ER, OpenACCParseCanContinue::Cannot};

769

771 OpenACCParseCanContinue::Can};

772}

773

777 OpenACCIntExprParseResult CurResult = ParseOpenACCIntExpr(DK, CK, Loc);

778

779 if (!CurResult.first.isUsable() &&

780 CurResult.second == OpenACCParseCanContinue::Cannot) {

781 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,

783 return true;

784 }

785

786 IntExprs.push_back(CurResult.first.get());

787

788 while (getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {

789 ExpectAndConsume(tok::comma);

790

791 CurResult = ParseOpenACCIntExpr(DK, CK, Loc);

792

793 if (!CurResult.first.isUsable() &&

794 CurResult.second == OpenACCParseCanContinue::Cannot) {

795 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,

797 return true;

798 }

799 IntExprs.push_back(CurResult.first.get());

800 }

801 return false;

802}

803

804bool Parser::ParseOpenACCDeviceTypeList(

806

807 if (expectIdentifierOrKeyword(*this)) {

808 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,

810 return true;

811 }

814

815 while (getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {

816 ExpectAndConsume(tok::comma);

817

818 if (expectIdentifierOrKeyword(*this)) {

819 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,

821 return true;

822 }

825 }

826 return false;

827}

828

830

831

834 tok::annot_pragma_openacc_end)) {

837 }

838

840

842 return SizeExpr;

843

846 SizeExpr.get());

847

848 return SizeExpr;

849}

850

851bool Parser::ParseOpenACCSizeExprList(

853 ExprResult SizeExpr = ParseOpenACCSizeExpr(CK);

855 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,

857 return true;

858 }

859

860 SizeExprs.push_back(SizeExpr.get());

861

862 while (getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {

863 ExpectAndConsume(tok::comma);

864

865 SizeExpr = ParseOpenACCSizeExpr(CK);

867 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,

869 return true;

870 }

871 SizeExprs.push_back(SizeExpr.get());

872 }

873 return false;

874}

875

876Parser::OpenACCGangArgRes Parser::ParseOpenACCGangArg(SourceLocation GangLoc) {

877

878 if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Static, getCurToken()) &&

880

885 }

886

887 if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Dim, getCurToken()) &&

891

892

895 }

896

897 if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Num, getCurToken()) &&

901

902 }

903

904

907 .first;

909}

910

911bool Parser::ParseOpenACCGangArgList(

914

915 Parser::OpenACCGangArgRes Res = ParseOpenACCGangArg(GangLoc);

916 if (!Res.second.isUsable()) {

917 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,

919 return true;

920 }

921

922 GKs.push_back(Res.first);

923 IntExprs.push_back(Res.second.get());

924

925 while (getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {

926 ExpectAndConsume(tok::comma);

927

928 Res = ParseOpenACCGangArg(GangLoc);

929 if (!Res.second.isUsable()) {

930 SkipUntil(tok::r_paren, tok::annot_pragma_openacc_end,

932 return true;

933 }

934

935 GKs.push_back(Res.first);

936 IntExprs.push_back(Res.second.get());

937 }

938 return false;

939}

940

941namespace {

942bool isUnsupportedExtensionClause(Token Tok) {

943 if (Tok.is(tok::identifier))

944 return false;

945

947}

948}

949

950Parser::OpenACCClauseParseResult

953

954

955 if (expectIdentifierOrKeyword(*this))

956 return OpenACCCannotContinue();

957

959

960 if (isUnsupportedExtensionClause(getCurToken())) {

961 Diag(getCurToken(), diag::warn_acc_unsupported_extension_clause)

963

964

965

968 tok::annot_pragma_openacc_end);

969

970 if (Parens.consumeOpen())

972

973 return OpenACCCanContinue();

977 return OpenACCCannotContinue();

978 }

979

980

982

983 return ParseOpenACCClauseParams(ExistingClauses, DirKind, Kind, ClauseLoc);

984}

985

986Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(

991 tok::annot_pragma_openacc_end);

992 SemaOpenACC::OpenACCParsedClause ParsedClause(DirKind, ClauseKind, ClauseLoc);

993

994 if (ClauseHasRequiredParens(DirKind, ClauseKind)) {

995 if (Parens.expectAndConsume()) {

996

997

998

999 SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openacc_end,

1001 return OpenACCCanContinue();

1002 }

1003 ParsedClause.setLParenLoc(Parens.getOpenLocation());

1004

1005 switch (ClauseKind) {

1008

1009 if (expectIdentifierOrKeyword(*this)) {

1011 return OpenACCCanContinue();

1012 }

1013

1015

1017 getOpenACCDefaultClauseKind(DefKindTok);

1018

1020 Diag(DefKindTok, diag::err_acc_invalid_default_clause_kind);

1022 return OpenACCCanContinue();

1023 }

1024

1025 ParsedClause.setDefaultDetails(DefKind);

1026 break;

1027 }

1029 ExprResult CondExpr = ParseOpenACCConditionExpr();

1030 ParsedClause.setConditionDetails(CondExpr.isUsable() ? CondExpr.get()

1031 : nullptr);

1032

1035 return OpenACCCanContinue();

1036 }

1037

1038 break;

1039 }

1053 ParsedClause.setVarListDetails(ParseOpenACCVarList(DirKind, ClauseKind),

1054 ModList);

1055 break;

1056 }

1058

1059

1061 ParsedClause.setReductionDetails(

1062 Op, ParseOpenACCVarList(DirKind, ClauseKind));

1063 break;

1064 }

1066

1067

1068

1070 [[fallthrough]];

1084 ParsedClause.setVarListDetails(ParseOpenACCVarList(DirKind, ClauseKind),

1086 break;

1088 bool HasForce = tryParseAndConsumeSpecialTokenKind(

1089 *this, OpenACCSpecialTokenKind::Force, ClauseKind);

1093 return OpenACCCanContinue();

1094 }

1095

1099

1102 return OpenACCCanContinue();

1103 }

1104

1105 ParsedClause.setCollapseDetails(HasForce, LoopCount.get());

1106 break;

1107 }

1109 ParsedClause.setBindDetails(ParseOpenACCBindClauseArgument());

1110

1111

1112 if (std::holds_alternativestd::monostate(

1113 ParsedClause.getBindDetails())) {

1115 return OpenACCCanContinue();

1116 }

1117 break;

1118 }

1120 llvm::SmallVector<Expr *> IntExprs;

1121

1124 IntExprs)) {

1126 return OpenACCCanContinue();

1127 }

1128 ParsedClause.setIntExprDetails(std::move(IntExprs));

1129 break;

1130 }

1136 ClauseKind, ClauseLoc)

1137 .first;

1140 return OpenACCCanContinue();

1141 }

1142

1143 ParsedClause.setIntExprDetails(IntExpr.get());

1144 break;

1145 }

1148 llvm::SmallVector Archs;

1150

1151

1152 ParsedClause.setDeviceTypeDetails(

1154 } else if (!ParseOpenACCDeviceTypeList(Archs)) {

1155 ParsedClause.setDeviceTypeDetails(std::move(Archs));

1156 } else {

1158 return OpenACCCanContinue();

1159 }

1160 break;

1161 }

1163 llvm::SmallVector<Expr *> SizeExprs;

1166 return OpenACCCanContinue();

1167 }

1168

1169 ParsedClause.setIntExprDetails(std::move(SizeExprs));

1170 break;

1171 }

1172 default:

1173 llvm_unreachable("Not a required parens type?");

1174 }

1175

1176 ParsedClause.setEndLoc(getCurToken().getLocation());

1177

1178 if (Parens.consumeClose())

1179 return OpenACCCannotContinue();

1180

1181 } else if (ClauseHasOptionalParens(DirKind, ClauseKind)) {

1182 if (Parens.consumeOpen()) {

1183 ParsedClause.setLParenLoc(Parens.getOpenLocation());

1184 switch (ClauseKind) {

1187 ExprResult CondExpr = ParseOpenACCConditionExpr();

1188 ParsedClause.setConditionDetails(CondExpr.isUsable() ? CondExpr.get()

1189 : nullptr);

1190

1193 return OpenACCCanContinue();

1194 }

1195 break;

1196 }

1199 tryParseAndConsumeSpecialTokenKind(*this,

1200 ClauseKind ==

1202 ? OpenACCSpecialTokenKind::Length

1203 : OpenACCSpecialTokenKind::Num,

1204 ClauseKind);

1206 ClauseKind, ClauseLoc)

1207 .first;

1210 return OpenACCCanContinue();

1211 }

1212 ParsedClause.setIntExprDetails(IntExpr.get());

1213 break;

1214 }

1219 .first;

1220 ParsedClause.setIntExprDetails(AsyncArg.isUsable() ? AsyncArg.get()

1221 : nullptr);

1224 return OpenACCCanContinue();

1225 }

1226 break;

1227 }

1229 llvm::SmallVector GKs;

1230 llvm::SmallVector<Expr *> IntExprs;

1231 if (ParseOpenACCGangArgList(ClauseLoc, GKs, IntExprs)) {

1233 return OpenACCCanContinue();

1234 }

1235 ParsedClause.setGangDetails(std::move(GKs), std::move(IntExprs));

1236 break;

1237 }

1239 OpenACCWaitParseInfo Info =

1240 ParseOpenACCWaitArgument(ClauseLoc,

1241 false);

1242 if (Info.Failed) {

1244 return OpenACCCanContinue();

1245 }

1246

1247 ParsedClause.setWaitDetails(Info.DevNumExpr, Info.QueuesLoc,

1248 std::move(Info.QueueIdExprs));

1249 break;

1250 }

1251 default:

1252 llvm_unreachable("Not an optional parens type?");

1253 }

1254 ParsedClause.setEndLoc(getCurToken().getLocation());

1255 if (Parens.consumeClose())

1256 return OpenACCCannotContinue();

1257 } else {

1258

1259

1260 ParsedClause.setEndLoc(ClauseLoc);

1261 }

1262 } else {

1263 ParsedClause.setEndLoc(ClauseLoc);

1264 }

1265 return OpenACCSuccess(

1266 Actions.OpenACC().ActOnClause(ExistingClauses, ParsedClause));

1267}

1268

1269Parser::OpenACCIntExprParseResult

1272 return ParseOpenACCIntExpr(DK, CK, Loc);

1273}

1274

1275Parser::OpenACCWaitParseInfo

1276Parser::ParseOpenACCWaitArgument(SourceLocation Loc, bool IsDirective) {

1277 OpenACCWaitParseInfo Result;

1278

1279 if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::DevNum, Tok) &&

1281

1283

1285

1286 OpenACCIntExprParseResult Res = ParseOpenACCIntExpr(

1290 Loc);

1291 if (Res.first.isInvalid() &&

1292 Res.second == OpenACCParseCanContinue::Cannot) {

1293 Result.Failed = true;

1295 }

1296

1297 if (ExpectAndConsume(tok::colon)) {

1298 Result.Failed = true;

1300 }

1301

1302 Result.DevNumExpr = Res.first.get();

1303 }

1304

1305

1306 if (isOpenACCSpecialToken(OpenACCSpecialTokenKind::Queues, Tok) &&

1308

1310

1312 }

1313

1314

1315

1316

1317

1318

1319

1320 OpenACCIntExprParseResult Res = ParseOpenACCAsyncArgument(

1324 Loc);

1325

1326 if (Res.first.isInvalid() &&

1327 Res.second == OpenACCParseCanContinue::Cannot) {

1328 Result.Failed = true;

1330 }

1331

1332 if (Res.first.isUsable())

1333 Result.QueueIdExprs.push_back(Res.first.get());

1334

1335 while (getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {

1336 if (ExpectAndConsume(tok::comma)) {

1337 Result.Failed = true;

1339 }

1340

1341 OpenACCIntExprParseResult Res = ParseOpenACCAsyncArgument(

1345 Loc);

1346

1347 if (Res.first.isInvalid() &&

1348 Res.second == OpenACCParseCanContinue::Cannot) {

1349 Result.Failed = true;

1351 }

1352

1353 if (Res.first.isUsable())

1354 Result.QueueIdExprs.push_back(Res.first.get());

1355 }

1356

1358}

1359

1360ExprResult Parser::ParseOpenACCIDExpression() {

1363 Res = ParseCXXIdExpression(true);

1364 } else {

1365

1366

1367

1368 if (Tok.isNot(tok::identifier)) {

1369 Diag(Tok, diag::err_expected) << tok::identifier;

1371 }

1372

1375 CXXScopeSpec ScopeSpec;

1376 SourceLocation TemplateKWLoc;

1378

1379

1380

1381

1382 Res = Actions.ActOnIdExpression(getCurScope(), ScopeSpec, TemplateKWLoc,

1383 Name, false,

1384 false);

1385 }

1386

1387 return Res;

1388}

1389

1390std::variant<std::monostate, clang::StringLiteral *, IdentifierInfo *>

1391Parser::ParseOpenACCBindClauseArgument() {

1392

1393

1394

1395

1396

1397

1400 return std::monostate{};

1401 }

1402

1406 return II;

1407 }

1408

1411 return std::monostate{};

1412 }

1413

1415 false, true);

1417 return std::monostate{};

1419}

1420

1421Parser::OpenACCVarParseResult Parser::ParseOpenACCVar(OpenACCDirectiveKind DK,

1423 OpenACCArraySectionRAII ArraySections(*this);

1424

1427

1430 return {Res, OpenACCParseCanContinue::Cannot};

1431 }

1432

1434 return {Res, OpenACCParseCanContinue::Can};

1435}

1436

1439 llvm::SmallVector<Expr *> Vars;

1440

1441 auto [Res, CanContinue] = ParseOpenACCVar(DK, CK);

1443 Vars.push_back(Res.get());

1444 } else if (CanContinue == OpenACCParseCanContinue::Cannot) {

1446 return Vars;

1447 }

1448

1449 while (getCurToken().isOneOf(tok::r_paren, tok::annot_pragma_openacc_end)) {

1450 ExpectAndConsume(tok::comma);

1451

1452 auto [Res, CanContinue] = ParseOpenACCVar(DK, CK);

1453

1455 Vars.push_back(Res.get());

1456 } else if (CanContinue == OpenACCParseCanContinue::Cannot) {

1458 return Vars;

1459 }

1460 }

1461 return Vars;

1462}

1463

1464Parser::OpenACCCacheParseInfo Parser::ParseOpenACCCacheVarList() {

1465

1466

1468 return {};

1469

1470 OpenACCCacheParseInfo CacheInfo;

1471

1473

1474

1475

1476 if (tryParseAndConsumeSpecialTokenKind(*this,

1477 OpenACCSpecialTokenKind::ReadOnly,

1479 CacheInfo.ReadOnlyLoc = ReadOnlyLoc;

1480

1481

1482

1485

1486 return CacheInfo;

1487}

1488

1489Parser::OpenACCDirectiveParseInfo

1490Parser::ParseOpenACCDirective() {

1491 SourceLocation StartLoc = ConsumeAnnotationToken();

1494 Parser::OpenACCWaitParseInfo WaitInfo;

1495 Parser::OpenACCCacheParseInfo CacheInfo;

1498

1500

1501

1502

1503

1505 AtomicKind = ParseOpenACCAtomicKind(*this);

1506

1507

1508

1510 tok::annot_pragma_openacc_end);

1511

1512 if (T.consumeOpen()) {

1513 switch (DirKind) {

1514 default:

1515 Diag(T.getOpenLocation(), diag::err_acc_invalid_open_paren);

1516 T.skipToEnd();

1517 break;

1519

1520

1521 RoutineName = ParseOpenACCIDExpression();

1522

1523

1524 if (!RoutineName.isUsable()) {

1525 T.skipToEnd();

1526 } else {

1527 T.consumeClose();

1528 RoutineName =

1530 }

1531 break;

1532 }

1534 CacheInfo = ParseOpenACCCacheVarList();

1535

1536

1537 T.consumeClose();

1538 break;

1540

1541 WaitInfo = ParseOpenACCWaitArgument(DirLoc, true);

1542 if (WaitInfo.Failed)

1543 T.skipToEnd();

1544 else

1545 T.consumeClose();

1546 break;

1547 }

1549

1550

1551

1552 Diag(Tok, diag::err_expected) << tok::l_paren;

1553 }

1554

1555

1556 OpenACCDirectiveParseInfo ParseInfo{DirKind,

1557 StartLoc,

1558 DirLoc,

1559 T.getOpenLocation(),

1560 T.getCloseLocation(),

1561 SourceLocation{},

1563 ? WaitInfo.QueuesLoc

1564 : CacheInfo.ReadOnlyLoc),

1565 AtomicKind,

1566 {},

1567 {}};

1568

1570 ParseInfo.Exprs = WaitInfo.getAllExprs();

1572 ParseInfo.Exprs = std::move(CacheInfo.Vars);

1574 ParseInfo.Exprs = llvm::SmallVector<Expr *>(1, RoutineName.get());

1575

1576 ParseInfo.Clauses = ParseOpenACCClauseList(DirKind);

1577

1578 assert(Tok.is(tok::annot_pragma_openacc_end) &&

1579 "Didn't parse all OpenACC Clauses");

1580 ParseInfo.EndLoc = ConsumeAnnotationToken();

1581 assert(ParseInfo.EndLoc.isValid() &&

1582 "Terminating annotation token not present");

1583

1584 return ParseInfo;

1585}

1586

1589 Decl *TagDecl, OpenACCDirectiveParseInfo &DirInfo) {

1591

1593 if (DirInfo.LParenLoc.isInvalid()) {

1594 if (Tok.isNot(tok::r_brace) && !isEofOrEom()) {

1596

1597

1598

1600 ParsedAttributes EmptyDeclSpecAttrs(AttrFactory);

1601 MaybeParseCXX11Attributes(Attrs);

1602 ParsingDeclSpec PDS(*this);

1603 Ptr = ParseExternalDeclaration(Attrs, EmptyDeclSpecAttrs, &PDS);

1604 }

1605

1606

1607

1608

1609 } else {

1610 Ptr = ParseCXXClassMemberDeclarationWithPragmas(AS, Attrs, TagType,

1611 TagDecl);

1612 }

1613 }

1614 }

1615

1617 getActions().OpenACC().ActOnEndRoutineDeclDirective(

1618 DirInfo.StartLoc, DirInfo.DirLoc, DirInfo.LParenLoc,

1619 DirInfo.Exprs.empty() ? nullptr : DirInfo.Exprs.front(),

1620 DirInfo.RParenLoc, DirInfo.Clauses, DirInfo.EndLoc, Ptr));

1621}

1622

1624Parser::ParseOpenACCAfterRoutineStmt(OpenACCDirectiveParseInfo &DirInfo) {

1626

1627

1628

1630

1631

1632

1633

1634 if (DirInfo.LParenLoc.isInvalid()) {

1636 NextStmt = ParseStatement();

1637 }

1638

1640 DirInfo.StartLoc, DirInfo.DirLoc, DirInfo.LParenLoc,

1641 DirInfo.Exprs.empty() ? nullptr : DirInfo.Exprs.front(),

1642 DirInfo.RParenLoc, DirInfo.Clauses, DirInfo.EndLoc, NextStmt.get());

1643}

1644

1648 assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token");

1649

1651

1652 OpenACCDirectiveParseInfo DirInfo = ParseOpenACCDirective();

1653

1654 if (getActions().OpenACC().ActOnStartDeclDirective(

1655 DirInfo.DirKind, DirInfo.StartLoc, DirInfo.Clauses))

1656 return nullptr;

1657

1659 return ParseOpenACCAfterRoutineDecl(AS, Attrs, TagType, TagDecl, DirInfo);

1660

1662 DirInfo.DirKind, DirInfo.StartLoc, DirInfo.DirLoc, DirInfo.LParenLoc,

1663 DirInfo.RParenLoc, DirInfo.EndLoc, DirInfo.Clauses));

1664}

1665

1667 assert(Tok.is(tok::annot_pragma_openacc) && "expected OpenACC Start Token");

1668

1670

1671 OpenACCDirectiveParseInfo DirInfo = ParseOpenACCDirective();

1672 if (getActions().OpenACC().ActOnStartStmtDirective(

1673 DirInfo.DirKind, DirInfo.StartLoc, DirInfo.Clauses))

1675

1677 return ParseOpenACCAfterRoutineStmt(DirInfo);

1678

1680 if (doesDirectiveHaveAssociatedStmt(DirInfo.DirKind)) {

1682 getActions().OpenACC(), DirInfo.DirKind, DirInfo.DirLoc, {},

1683 DirInfo.Clauses);

1685 ParseScope ACCScope(this, getOpenACCScopeFlags(DirInfo.DirKind));

1686

1688 DirInfo.StartLoc, DirInfo.DirKind, DirInfo.AtomicKind, DirInfo.Clauses,

1689 ParseStatement());

1690 }

1691

1693 DirInfo.DirKind, DirInfo.StartLoc, DirInfo.DirLoc, DirInfo.LParenLoc,

1694 DirInfo.MiscLoc, DirInfo.Exprs, DirInfo.AtomicKind, DirInfo.RParenLoc,

1695 DirInfo.EndLoc, DirInfo.Clauses, AssocStmt);

1696}

static Decl::Kind getKind(const Decl *D)

bool Optional

Is optional and can be removed.

bool is(tok::TokenKind Kind) const

Defines some OpenACC-specific enums and functions.

static constexpr bool isOneOf()

This file declares semantic analysis for OpenACC constructs and clauses.

static const TST TST_unspecified

Decl - This represents one declaration (or definition), e.g.

SourceLocation getExprLoc() const LLVM_READONLY

getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...

bool isStr(const char(&Str)[StrLen]) const

Return true if this is the identifier for the specified string.

StringRef getName() const

Return the actual identifier string.

static OpaquePtr make(DeclGroupRef P)

This is the base type for all OpenACC Clauses.

ParsedAttributes - A collection of parsed attributes.

ParseScope - Introduces a new scope for parsing.

Parser - This implements a parser for the C family of languages.

DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID)

ExprResult ParseStringLiteralExpression(bool AllowUserDefinedLiteral=false)

ParseStringLiteralExpression - This handles the various token types that form string literals,...

SourceLocation ConsumeToken()

ConsumeToken - Consume the current 'peek token' and lex the next one.

Sema & getActions() const

DeclGroupPtrTy ParseOpenACCDirectiveDecl(AccessSpecifier &AS, ParsedAttributes &Attrs, DeclSpec::TST TagType, Decl *TagDecl)

Parse OpenACC directive on a declaration.

Definition ParseOpenACC.cpp:1646

SourceLocation ConsumeAnyToken(bool ConsumeCodeCompletionTok=false)

ConsumeAnyToken - Dispatch to the right Consume* method based on the current token type.

ExprResult ParseConstantExpression()

StmtResult ParseOpenACCDirectiveStmt()

Definition ParseOpenACC.cpp:1666

OpaquePtr< DeclGroupRef > DeclGroupPtrTy

Scope * getCurScope() const

friend class ParsingOpenACCDirectiveRAII

bool SkipUntil(tok::TokenKind T, SkipUntilFlags Flags=static_cast< SkipUntilFlags >(0))

SkipUntil - Read tokens until we get to the specified token, then consume it (unless StopBeforeMatch ...

const Token & getCurToken() const

const LangOptions & getLangOpts() const

ExprResult ParseExpression(TypoCorrectionTypeBehavior CorrectionBehavior=TypoCorrectionTypeBehavior::AllowNonTypes)

Simple precedence-based parser for binary/ternary operators.

@ StopBeforeMatch

Stop skipping at specified token, but don't skip the token itself.

const Token & NextToken()

NextToken - This peeks ahead one token and returns it without consuming it.

ExprResult ParseAssignmentExpression(TypoCorrectionTypeBehavior CorrectionBehavior=TypoCorrectionTypeBehavior::AllowNonTypes)

Parse an expr that doesn't include (top-level) commas.

friend class BalancedDelimiterTracker

@ OpenACCLoopConstructScope

This is the scope of an OpenACC Loop/Combined construct, which is used to determine whether a 'cache'...

@ ContinueScope

This is a while, do, for, which can have continue statements embedded into it.

@ OpenACCComputeConstructScope

This is the scope of an OpenACC Compute Construct, which restricts jumping into/out of it.

@ BreakScope

This is a while, do, switch, for, etc that can have break statements embedded into it.

Helper type for the registration/assignment of constructs that need to 'know' about their parent cons...

ExprResult ActOnRoutineName(Expr *RoutineName)

ExprResult ActOnIntExpr(OpenACCDirectiveKind DK, OpenACCClauseKind CK, SourceLocation Loc, Expr *IntExpr)

Called when encountering an 'int-expr' for OpenACC, and manages conversions and diagnostics to 'int'.

void ActOnInvalidParseVar()

Called only if the parse of a 'var' was invalid, else 'ActOnVar' should be called.

StmtResult ActOnEndRoutineStmtDirective(SourceLocation StartLoc, SourceLocation DirLoc, SourceLocation LParenLoc, Expr *ReferencedFunc, SourceLocation RParenLoc, ArrayRef< const OpenACCClause * > Clauses, SourceLocation EndLoc, Stmt *NextStmt)

StmtResult ActOnAssociatedStmt(SourceLocation DirectiveLoc, OpenACCDirectiveKind K, OpenACCAtomicKind AtKind, ArrayRef< const OpenACCClause * > Clauses, StmtResult AssocStmt)

Called when we encounter an associated statement for our construct, this should check legality of the...

ExprResult ActOnVar(OpenACCDirectiveKind DK, OpenACCClauseKind CK, Expr *VarExpr)

Called when encountering a 'var' for OpenACC, ensures it is actually a declaration reference to a var...

void ActOnConstruct(OpenACCDirectiveKind K, SourceLocation DirLoc)

Called after the construct has been parsed, but clauses haven't been parsed.

ExprResult ActOnOpenACCAsteriskSizeExpr(SourceLocation AsteriskLoc)

void ActOnStartParseVar(OpenACCDirectiveKind DK, OpenACCClauseKind CK)

Called right before a 'var' is parsed, so we can set the state for parsing a 'cache' var.

StmtResult ActOnEndStmtDirective(OpenACCDirectiveKind K, SourceLocation StartLoc, SourceLocation DirLoc, SourceLocation LParenLoc, SourceLocation MiscLoc, ArrayRef< Expr * > Exprs, OpenACCAtomicKind AK, SourceLocation RParenLoc, SourceLocation EndLoc, ArrayRef< OpenACCClause * > Clauses, StmtResult AssocStmt)

Called after the directive has been completely parsed, including the declaration group or associated ...

@ Boolean

A boolean condition, from 'if', 'while', 'for', or 'do'.

ConditionResult ActOnCondition(Scope *S, SourceLocation Loc, Expr *SubExpr, ConditionKind CK, bool MissingOK=false)

Encodes a location in the source.

SourceLocation getBeginLoc() const LLVM_READONLY

Represents the declaration of a struct/union/class/enum.

Token - This structure provides full information about a lexed token.

IdentifierInfo * getIdentifierInfo() const

SourceLocation getLocation() const

Return a source location identifier for the specified offset in the current file.

bool is(tok::TokenKind K) const

is/isNot - Predicates to check if this token is a specific kind, as in "if (Tok.is(tok::l_brace)) {....

tok::TokenKind getKind() const

bool isNot(tok::TokenKind K) const

bool isAnnotation() const

Return true if this is any of tok::annot_* kind tokens.

void setIdentifier(const IdentifierInfo *Id, SourceLocation IdLoc)

Specify that this unqualified-id was parsed as an identifier.

bool isStringLiteral(TokenKind K)

Return true if this is a C or C++ string-literal (or C++11 user-defined-string-literal) token.

bool isAnnotation(TokenKind K)

Return true if this is any of tok::annot_* kinds.

The JSON file list parser is used to communicate input to InstallAPI.

@ Invalid

Invalid Reduction Clause Kind.

OpenACCClauseKind

Represents the kind of an OpenACC clause.

@ Auto

'auto' clause, allowed on 'loop' directives.

@ Bind

'bind' clause, allowed on routine constructs.

@ Gang

'gang' clause, allowed on 'loop' and Combined constructs.

@ Wait

'wait' clause, allowed on Compute, Data, 'update', and Combined constructs.

@ DevicePtr

'deviceptr' clause, allowed on Compute and Combined Constructs, plus 'data' and 'declare'.

@ PCopyOut

'copyout' clause alias 'pcopyout'. Preserved for diagnostic purposes.

@ VectorLength

'vector_length' clause, allowed on 'parallel', 'kernels', 'parallel loop', and 'kernels loop' constru...

@ Async

'async' clause, allowed on Compute, Data, 'update', 'wait', and Combined constructs.

@ PresentOrCreate

'create' clause alias 'present_or_create'.

@ Collapse

'collapse' clause, allowed on 'loop' and Combined constructs.

@ NoHost

'nohost' clause, allowed on 'routine' directives.

@ PresentOrCopy

'copy' clause alias 'present_or_copy'. Preserved for diagnostic purposes.

@ DeviceNum

'device_num' clause, allowed on 'init', 'shutdown', and 'set' constructs.

@ Private

'private' clause, allowed on 'parallel', 'serial', 'loop', 'parallel loop', and 'serial loop' constru...

@ Invalid

Represents an invalid clause, for the purposes of parsing.

@ Vector

'vector' clause, allowed on 'loop', Combined, and 'routine' directives.

@ Copy

'copy' clause, allowed on Compute and Combined Constructs, plus 'data' and 'declare'.

@ Worker

'worker' clause, allowed on 'loop', Combined, and 'routine' directives.

@ Create

'create' clause, allowed on Compute and Combined constructs, plus 'data', 'enter data',...

@ DeviceType

'device_type' clause, allowed on Compute, 'data', 'init', 'shutdown', 'set', update',...

@ DefaultAsync

'default_async' clause, allowed on 'set' construct.

@ Attach

'attach' clause, allowed on Compute and Combined constructs, plus 'data' and 'enter data'.

@ Shortloop

'shortloop' is represented in the ACC.td file, but isn't present in the standard.

@ NumGangs

'num_gangs' clause, allowed on 'parallel', 'kernels', parallel loop', and 'kernels loop' constructs.

@ If

'if' clause, allowed on all the Compute Constructs, Data Constructs, Executable Constructs,...

@ Default

'default' clause, allowed on parallel, serial, kernel (and compound) constructs.

@ UseDevice

'use_device' clause, allowed on 'host_data' construct.

@ NoCreate

'no_create' clause, allowed on allowed on Compute and Combined constructs, plus 'data'.

@ PresentOrCopyOut

'copyout' clause alias 'present_or_copyout'.

@ Link

'link' clause, allowed on 'declare' construct.

@ Reduction

'reduction' clause, allowed on Parallel, Serial, Loop, and the combined constructs.

@ Self

'self' clause, allowed on Compute and Combined Constructs, plus 'update'.

@ CopyOut

'copyout' clause, allowed on Compute and Combined constructs, plus 'data', 'exit data',...

@ Seq

'seq' clause, allowed on 'loop' and 'routine' directives.

@ FirstPrivate

'firstprivate' clause, allowed on 'parallel', 'serial', 'parallel loop', and 'serial loop' constructs...

@ Host

'host' clause, allowed on 'update' construct.

@ PCopy

'copy' clause alias 'pcopy'. Preserved for diagnostic purposes.

@ Tile

'tile' clause, allowed on 'loop' and Combined constructs.

@ PCopyIn

'copyin' clause alias 'pcopyin'. Preserved for diagnostic purposes.

@ DeviceResident

'device_resident' clause, allowed on the 'declare' construct.

@ PCreate

'create' clause alias 'pcreate'. Preserved for diagnostic purposes.

@ Present

'present' clause, allowed on Compute and Combined constructs, plus 'data' and 'declare'.

@ DType

'dtype' clause, an alias for 'device_type', stored separately for diagnostic purposes.

@ CopyIn

'copyin' clause, allowed on Compute and Combined constructs, plus 'data', 'enter data',...

@ Device

'device' clause, allowed on the 'update' construct.

@ Independent

'independent' clause, allowed on 'loop' directives.

@ NumWorkers

'num_workers' clause, allowed on 'parallel', 'kernels', parallel loop', and 'kernels loop' constructs...

@ IfPresent

'if_present' clause, allowed on 'host_data' and 'update' directives.

@ Detach

'detach' clause, allowed on the 'exit data' construct.

@ Delete

'delete' clause, allowed on the 'exit data' construct.

@ PresentOrCopyIn

'copyin' clause alias 'present_or_copyin'.

@ Finalize

'finalize' clause, allowed on 'exit data' directive.

AccessSpecifier

A C++ access specifier (public, private, protected), plus the special value "none" which means differ...

@ Invalid

Not a valid option.

@ Present

'present' option.

@ Result

The result type of a method or function.

const FunctionProtoType * T

U cast(CodeGen::Address addr)

@ None

The alignment was not explicit in code.

ActionResult< Expr * > ExprResult

@ Parens

New-expression has a C++98 paren-delimited initializer.

ActionResult< Stmt * > StmtResult

Diagnostic wrappers for TextAPI types for error reporting.