181ad6265SDimitry Andric //===--- ParseHLSL.cpp - HLSL-specific parsing support --------------------===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric // 981ad6265SDimitry Andric // This file implements the parsing logic for HLSL language features. 1081ad6265SDimitry Andric // 1181ad6265SDimitry Andric //===----------------------------------------------------------------------===// 1281ad6265SDimitry Andric 13bdd1243dSDimitry Andric #include "clang/AST/Attr.h" 1481ad6265SDimitry Andric #include "clang/Basic/AttributeCommonInfo.h" 1581ad6265SDimitry Andric #include "clang/Parse/ParseDiagnostic.h" 1681ad6265SDimitry Andric #include "clang/Parse/Parser.h" 17bdd1243dSDimitry Andric #include "clang/Parse/RAIIObjectsForParser.h" 18*0fca6ea1SDimitry Andric #include "clang/Sema/SemaHLSL.h" 1981ad6265SDimitry Andric 2081ad6265SDimitry Andric using namespace clang; 2181ad6265SDimitry Andric 22bdd1243dSDimitry Andric static bool validateDeclsInsideHLSLBuffer(Parser::DeclGroupPtrTy DG, 23bdd1243dSDimitry Andric SourceLocation BufferLoc, 24bdd1243dSDimitry Andric bool IsCBuffer, Parser &P) { 25bdd1243dSDimitry Andric // The parse is failed, just return false. 26bdd1243dSDimitry Andric if (!DG) 27bdd1243dSDimitry Andric return false; 28bdd1243dSDimitry Andric DeclGroupRef Decls = DG.get(); 29bdd1243dSDimitry Andric bool IsValid = true; 30bdd1243dSDimitry Andric // Only allow function, variable, record decls inside HLSLBuffer. 31bdd1243dSDimitry Andric for (DeclGroupRef::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) { 32bdd1243dSDimitry Andric Decl *D = *I; 33bdd1243dSDimitry Andric if (isa<CXXRecordDecl, RecordDecl, FunctionDecl, VarDecl>(D)) 34bdd1243dSDimitry Andric continue; 35bdd1243dSDimitry Andric 36bdd1243dSDimitry Andric // FIXME: support nested HLSLBuffer and namespace inside HLSLBuffer. 37bdd1243dSDimitry Andric if (isa<HLSLBufferDecl, NamespaceDecl>(D)) { 38bdd1243dSDimitry Andric P.Diag(D->getLocation(), diag::err_invalid_declaration_in_hlsl_buffer) 39bdd1243dSDimitry Andric << IsCBuffer; 40bdd1243dSDimitry Andric IsValid = false; 41bdd1243dSDimitry Andric continue; 42bdd1243dSDimitry Andric } 43bdd1243dSDimitry Andric 44bdd1243dSDimitry Andric IsValid = false; 45bdd1243dSDimitry Andric P.Diag(D->getLocation(), diag::err_invalid_declaration_in_hlsl_buffer) 46bdd1243dSDimitry Andric << IsCBuffer; 47bdd1243dSDimitry Andric } 48bdd1243dSDimitry Andric return IsValid; 49bdd1243dSDimitry Andric } 50bdd1243dSDimitry Andric 51bdd1243dSDimitry Andric Decl *Parser::ParseHLSLBuffer(SourceLocation &DeclEnd) { 52bdd1243dSDimitry Andric assert((Tok.is(tok::kw_cbuffer) || Tok.is(tok::kw_tbuffer)) && 53bdd1243dSDimitry Andric "Not a cbuffer or tbuffer!"); 54bdd1243dSDimitry Andric bool IsCBuffer = Tok.is(tok::kw_cbuffer); 55bdd1243dSDimitry Andric SourceLocation BufferLoc = ConsumeToken(); // Eat the 'cbuffer' or 'tbuffer'. 56bdd1243dSDimitry Andric 57bdd1243dSDimitry Andric if (!Tok.is(tok::identifier)) { 58bdd1243dSDimitry Andric Diag(Tok, diag::err_expected) << tok::identifier; 59bdd1243dSDimitry Andric return nullptr; 60bdd1243dSDimitry Andric } 61bdd1243dSDimitry Andric 62bdd1243dSDimitry Andric IdentifierInfo *Identifier = Tok.getIdentifierInfo(); 63bdd1243dSDimitry Andric SourceLocation IdentifierLoc = ConsumeToken(); 64bdd1243dSDimitry Andric 65bdd1243dSDimitry Andric ParsedAttributes Attrs(AttrFactory); 66*0fca6ea1SDimitry Andric MaybeParseHLSLAnnotations(Attrs, nullptr); 67bdd1243dSDimitry Andric 68bdd1243dSDimitry Andric ParseScope BufferScope(this, Scope::DeclScope); 69bdd1243dSDimitry Andric BalancedDelimiterTracker T(*this, tok::l_brace); 70bdd1243dSDimitry Andric if (T.consumeOpen()) { 71bdd1243dSDimitry Andric Diag(Tok, diag::err_expected) << tok::l_brace; 72bdd1243dSDimitry Andric return nullptr; 73bdd1243dSDimitry Andric } 74bdd1243dSDimitry Andric 75*0fca6ea1SDimitry Andric Decl *D = Actions.HLSL().ActOnStartBuffer(getCurScope(), IsCBuffer, BufferLoc, 76bdd1243dSDimitry Andric Identifier, IdentifierLoc, 77bdd1243dSDimitry Andric T.getOpenLocation()); 78bdd1243dSDimitry Andric 79bdd1243dSDimitry Andric while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { 80bdd1243dSDimitry Andric // FIXME: support attribute on constants inside cbuffer/tbuffer. 81bdd1243dSDimitry Andric ParsedAttributes DeclAttrs(AttrFactory); 82bdd1243dSDimitry Andric ParsedAttributes EmptyDeclSpecAttrs(AttrFactory); 83bdd1243dSDimitry Andric 84bdd1243dSDimitry Andric DeclGroupPtrTy Result = 85bdd1243dSDimitry Andric ParseExternalDeclaration(DeclAttrs, EmptyDeclSpecAttrs); 86bdd1243dSDimitry Andric if (!validateDeclsInsideHLSLBuffer(Result, IdentifierLoc, IsCBuffer, 87bdd1243dSDimitry Andric *this)) { 88bdd1243dSDimitry Andric T.skipToEnd(); 89bdd1243dSDimitry Andric DeclEnd = T.getCloseLocation(); 90bdd1243dSDimitry Andric BufferScope.Exit(); 91*0fca6ea1SDimitry Andric Actions.HLSL().ActOnFinishBuffer(D, DeclEnd); 92bdd1243dSDimitry Andric return nullptr; 93bdd1243dSDimitry Andric } 94bdd1243dSDimitry Andric } 95bdd1243dSDimitry Andric 96bdd1243dSDimitry Andric T.consumeClose(); 97bdd1243dSDimitry Andric DeclEnd = T.getCloseLocation(); 98bdd1243dSDimitry Andric BufferScope.Exit(); 99*0fca6ea1SDimitry Andric Actions.HLSL().ActOnFinishBuffer(D, DeclEnd); 100bdd1243dSDimitry Andric 101bdd1243dSDimitry Andric Actions.ProcessDeclAttributeList(Actions.CurScope, D, Attrs); 102bdd1243dSDimitry Andric return D; 103bdd1243dSDimitry Andric } 104bdd1243dSDimitry Andric 105bdd1243dSDimitry Andric static void fixSeparateAttrArgAndNumber(StringRef ArgStr, SourceLocation ArgLoc, 106bdd1243dSDimitry Andric Token Tok, ArgsVector &ArgExprs, 107bdd1243dSDimitry Andric Parser &P, ASTContext &Ctx, 108bdd1243dSDimitry Andric Preprocessor &PP) { 109bdd1243dSDimitry Andric StringRef Num = StringRef(Tok.getLiteralData(), Tok.getLength()); 110bdd1243dSDimitry Andric SourceLocation EndNumLoc = Tok.getEndLoc(); 111bdd1243dSDimitry Andric 112bdd1243dSDimitry Andric P.ConsumeToken(); // consume constant. 113bdd1243dSDimitry Andric std::string FixedArg = ArgStr.str() + Num.str(); 114bdd1243dSDimitry Andric P.Diag(ArgLoc, diag::err_hlsl_separate_attr_arg_and_number) 115bdd1243dSDimitry Andric << FixedArg 116bdd1243dSDimitry Andric << FixItHint::CreateReplacement(SourceRange(ArgLoc, EndNumLoc), FixedArg); 117bdd1243dSDimitry Andric ArgsUnion &Slot = ArgExprs.back(); 118bdd1243dSDimitry Andric Slot = IdentifierLoc::create(Ctx, ArgLoc, PP.getIdentifierInfo(FixedArg)); 119bdd1243dSDimitry Andric } 120bdd1243dSDimitry Andric 121*0fca6ea1SDimitry Andric void Parser::ParseHLSLAnnotations(ParsedAttributes &Attrs, 122*0fca6ea1SDimitry Andric SourceLocation *EndLoc, 123*0fca6ea1SDimitry Andric bool CouldBeBitField) { 124*0fca6ea1SDimitry Andric 125*0fca6ea1SDimitry Andric assert(Tok.is(tok::colon) && "Not a HLSL Annotation"); 126*0fca6ea1SDimitry Andric Token OldToken = Tok; 12781ad6265SDimitry Andric ConsumeToken(); 12881ad6265SDimitry Andric 129bdd1243dSDimitry Andric IdentifierInfo *II = nullptr; 130bdd1243dSDimitry Andric if (Tok.is(tok::kw_register)) 131bdd1243dSDimitry Andric II = PP.getIdentifierInfo("register"); 132bdd1243dSDimitry Andric else if (Tok.is(tok::identifier)) 133bdd1243dSDimitry Andric II = Tok.getIdentifierInfo(); 134bdd1243dSDimitry Andric 135bdd1243dSDimitry Andric if (!II) { 136*0fca6ea1SDimitry Andric if (CouldBeBitField) { 137*0fca6ea1SDimitry Andric UnconsumeToken(OldToken); 138*0fca6ea1SDimitry Andric return; 139*0fca6ea1SDimitry Andric } 14081ad6265SDimitry Andric Diag(Tok.getLocation(), diag::err_expected_semantic_identifier); 14181ad6265SDimitry Andric return; 14281ad6265SDimitry Andric } 14381ad6265SDimitry Andric 14481ad6265SDimitry Andric SourceLocation Loc = ConsumeToken(); 14581ad6265SDimitry Andric if (EndLoc) 14681ad6265SDimitry Andric *EndLoc = Tok.getLocation(); 14781ad6265SDimitry Andric ParsedAttr::Kind AttrKind = 148*0fca6ea1SDimitry Andric ParsedAttr::getParsedKind(II, nullptr, ParsedAttr::AS_HLSLAnnotation); 14981ad6265SDimitry Andric 150bdd1243dSDimitry Andric ArgsVector ArgExprs; 151bdd1243dSDimitry Andric switch (AttrKind) { 152bdd1243dSDimitry Andric case ParsedAttr::AT_HLSLResourceBinding: { 153bdd1243dSDimitry Andric if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after)) { 154bdd1243dSDimitry Andric SkipUntil(tok::r_paren, StopAtSemi); // skip through ) 15581ad6265SDimitry Andric return; 15681ad6265SDimitry Andric } 157bdd1243dSDimitry Andric if (!Tok.is(tok::identifier)) { 158bdd1243dSDimitry Andric Diag(Tok.getLocation(), diag::err_expected) << tok::identifier; 159bdd1243dSDimitry Andric SkipUntil(tok::r_paren, StopAtSemi); // skip through ) 160bdd1243dSDimitry Andric return; 161bdd1243dSDimitry Andric } 162bdd1243dSDimitry Andric StringRef SlotStr = Tok.getIdentifierInfo()->getName(); 163bdd1243dSDimitry Andric SourceLocation SlotLoc = Tok.getLocation(); 164bdd1243dSDimitry Andric ArgExprs.push_back(ParseIdentifierLoc()); 165bdd1243dSDimitry Andric 166bdd1243dSDimitry Andric // Add numeric_constant for fix-it. 167bdd1243dSDimitry Andric if (SlotStr.size() == 1 && Tok.is(tok::numeric_constant)) 168bdd1243dSDimitry Andric fixSeparateAttrArgAndNumber(SlotStr, SlotLoc, Tok, ArgExprs, *this, 169bdd1243dSDimitry Andric Actions.Context, PP); 170bdd1243dSDimitry Andric 171bdd1243dSDimitry Andric if (Tok.is(tok::comma)) { 172bdd1243dSDimitry Andric ConsumeToken(); // consume comma 173bdd1243dSDimitry Andric if (!Tok.is(tok::identifier)) { 174bdd1243dSDimitry Andric Diag(Tok.getLocation(), diag::err_expected) << tok::identifier; 175bdd1243dSDimitry Andric SkipUntil(tok::r_paren, StopAtSemi); // skip through ) 176bdd1243dSDimitry Andric return; 177bdd1243dSDimitry Andric } 178bdd1243dSDimitry Andric StringRef SpaceStr = Tok.getIdentifierInfo()->getName(); 179bdd1243dSDimitry Andric SourceLocation SpaceLoc = Tok.getLocation(); 180bdd1243dSDimitry Andric ArgExprs.push_back(ParseIdentifierLoc()); 181bdd1243dSDimitry Andric 182bdd1243dSDimitry Andric // Add numeric_constant for fix-it. 183*0fca6ea1SDimitry Andric if (SpaceStr == "space" && Tok.is(tok::numeric_constant)) 184bdd1243dSDimitry Andric fixSeparateAttrArgAndNumber(SpaceStr, SpaceLoc, Tok, ArgExprs, *this, 185bdd1243dSDimitry Andric Actions.Context, PP); 186bdd1243dSDimitry Andric } 187bdd1243dSDimitry Andric if (ExpectAndConsume(tok::r_paren, diag::err_expected)) { 188bdd1243dSDimitry Andric SkipUntil(tok::r_paren, StopAtSemi); // skip through ) 189bdd1243dSDimitry Andric return; 190bdd1243dSDimitry Andric } 191bdd1243dSDimitry Andric } break; 192*0fca6ea1SDimitry Andric case ParsedAttr::AT_HLSLPackOffset: { 193*0fca6ea1SDimitry Andric // Parse 'packoffset( c[Subcomponent][.component] )'. 194*0fca6ea1SDimitry Andric // Check '('. 195*0fca6ea1SDimitry Andric if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after)) { 196*0fca6ea1SDimitry Andric SkipUntil(tok::r_paren, StopAtSemi); // skip through ) 197*0fca6ea1SDimitry Andric return; 198*0fca6ea1SDimitry Andric } 199*0fca6ea1SDimitry Andric // Check c[Subcomponent] as an identifier. 200*0fca6ea1SDimitry Andric if (!Tok.is(tok::identifier)) { 201*0fca6ea1SDimitry Andric Diag(Tok.getLocation(), diag::err_expected) << tok::identifier; 202*0fca6ea1SDimitry Andric SkipUntil(tok::r_paren, StopAtSemi); // skip through ) 203*0fca6ea1SDimitry Andric return; 204*0fca6ea1SDimitry Andric } 205*0fca6ea1SDimitry Andric StringRef OffsetStr = Tok.getIdentifierInfo()->getName(); 206*0fca6ea1SDimitry Andric SourceLocation SubComponentLoc = Tok.getLocation(); 207*0fca6ea1SDimitry Andric if (OffsetStr[0] != 'c') { 208*0fca6ea1SDimitry Andric Diag(Tok.getLocation(), diag::err_hlsl_packoffset_invalid_reg) 209*0fca6ea1SDimitry Andric << OffsetStr; 210*0fca6ea1SDimitry Andric SkipUntil(tok::r_paren, StopAtSemi); // skip through ) 211*0fca6ea1SDimitry Andric return; 212*0fca6ea1SDimitry Andric } 213*0fca6ea1SDimitry Andric OffsetStr = OffsetStr.substr(1); 214*0fca6ea1SDimitry Andric unsigned SubComponent = 0; 215*0fca6ea1SDimitry Andric if (!OffsetStr.empty()) { 216*0fca6ea1SDimitry Andric // Make sure SubComponent is a number. 217*0fca6ea1SDimitry Andric if (OffsetStr.getAsInteger(10, SubComponent)) { 218*0fca6ea1SDimitry Andric Diag(SubComponentLoc.getLocWithOffset(1), 219*0fca6ea1SDimitry Andric diag::err_hlsl_unsupported_register_number); 220*0fca6ea1SDimitry Andric SkipUntil(tok::r_paren, StopAtSemi); // skip through ) 221*0fca6ea1SDimitry Andric return; 222*0fca6ea1SDimitry Andric } 223*0fca6ea1SDimitry Andric } 224*0fca6ea1SDimitry Andric unsigned Component = 0; 225*0fca6ea1SDimitry Andric ConsumeToken(); // consume identifier. 226*0fca6ea1SDimitry Andric SourceLocation ComponentLoc; 227*0fca6ea1SDimitry Andric if (Tok.is(tok::period)) { 228*0fca6ea1SDimitry Andric ConsumeToken(); // consume period. 229*0fca6ea1SDimitry Andric if (!Tok.is(tok::identifier)) { 230*0fca6ea1SDimitry Andric Diag(Tok.getLocation(), diag::err_expected) << tok::identifier; 231*0fca6ea1SDimitry Andric SkipUntil(tok::r_paren, StopAtSemi); // skip through ) 232*0fca6ea1SDimitry Andric return; 233*0fca6ea1SDimitry Andric } 234*0fca6ea1SDimitry Andric StringRef ComponentStr = Tok.getIdentifierInfo()->getName(); 235*0fca6ea1SDimitry Andric ComponentLoc = Tok.getLocation(); 236*0fca6ea1SDimitry Andric ConsumeToken(); // consume identifier. 237*0fca6ea1SDimitry Andric // Make sure Component is a single character. 238*0fca6ea1SDimitry Andric if (ComponentStr.size() != 1) { 239*0fca6ea1SDimitry Andric Diag(ComponentLoc, diag::err_hlsl_unsupported_component) 240*0fca6ea1SDimitry Andric << ComponentStr; 241*0fca6ea1SDimitry Andric SkipUntil(tok::r_paren, StopAtSemi); // skip through ) 242*0fca6ea1SDimitry Andric return; 243*0fca6ea1SDimitry Andric } 244*0fca6ea1SDimitry Andric switch (ComponentStr[0]) { 245*0fca6ea1SDimitry Andric case 'x': 246*0fca6ea1SDimitry Andric case 'r': 247*0fca6ea1SDimitry Andric Component = 0; 248*0fca6ea1SDimitry Andric break; 249*0fca6ea1SDimitry Andric case 'y': 250*0fca6ea1SDimitry Andric case 'g': 251*0fca6ea1SDimitry Andric Component = 1; 252*0fca6ea1SDimitry Andric break; 253*0fca6ea1SDimitry Andric case 'z': 254*0fca6ea1SDimitry Andric case 'b': 255*0fca6ea1SDimitry Andric Component = 2; 256*0fca6ea1SDimitry Andric break; 257*0fca6ea1SDimitry Andric case 'w': 258*0fca6ea1SDimitry Andric case 'a': 259*0fca6ea1SDimitry Andric Component = 3; 260*0fca6ea1SDimitry Andric break; 261*0fca6ea1SDimitry Andric default: 262*0fca6ea1SDimitry Andric Diag(ComponentLoc, diag::err_hlsl_unsupported_component) 263*0fca6ea1SDimitry Andric << ComponentStr; 264*0fca6ea1SDimitry Andric SkipUntil(tok::r_paren, StopAtSemi); // skip through ) 265*0fca6ea1SDimitry Andric return; 266*0fca6ea1SDimitry Andric } 267*0fca6ea1SDimitry Andric } 268*0fca6ea1SDimitry Andric ASTContext &Ctx = Actions.getASTContext(); 269*0fca6ea1SDimitry Andric QualType SizeTy = Ctx.getSizeType(); 270*0fca6ea1SDimitry Andric uint64_t SizeTySize = Ctx.getTypeSize(SizeTy); 271*0fca6ea1SDimitry Andric ArgExprs.push_back(IntegerLiteral::Create( 272*0fca6ea1SDimitry Andric Ctx, llvm::APInt(SizeTySize, SubComponent), SizeTy, SubComponentLoc)); 273*0fca6ea1SDimitry Andric ArgExprs.push_back(IntegerLiteral::Create( 274*0fca6ea1SDimitry Andric Ctx, llvm::APInt(SizeTySize, Component), SizeTy, ComponentLoc)); 275*0fca6ea1SDimitry Andric if (ExpectAndConsume(tok::r_paren, diag::err_expected)) { 276*0fca6ea1SDimitry Andric SkipUntil(tok::r_paren, StopAtSemi); // skip through ) 277*0fca6ea1SDimitry Andric return; 278*0fca6ea1SDimitry Andric } 279*0fca6ea1SDimitry Andric } break; 280bdd1243dSDimitry Andric case ParsedAttr::UnknownAttribute: 281bdd1243dSDimitry Andric Diag(Loc, diag::err_unknown_hlsl_semantic) << II; 282bdd1243dSDimitry Andric return; 283bdd1243dSDimitry Andric case ParsedAttr::AT_HLSLSV_GroupIndex: 284bdd1243dSDimitry Andric case ParsedAttr::AT_HLSLSV_DispatchThreadID: 285bdd1243dSDimitry Andric break; 286bdd1243dSDimitry Andric default: 287*0fca6ea1SDimitry Andric llvm_unreachable("invalid HLSL Annotation"); 288bdd1243dSDimitry Andric break; 289bdd1243dSDimitry Andric } 290bdd1243dSDimitry Andric 291bdd1243dSDimitry Andric Attrs.addNew(II, Loc, nullptr, SourceLocation(), ArgExprs.data(), 292*0fca6ea1SDimitry Andric ArgExprs.size(), ParsedAttr::Form::HLSLAnnotation()); 29381ad6265SDimitry Andric } 294