11fdf952dSChris Bieneman //===--- ParseHLSL.cpp - HLSL-specific parsing support --------------------===// 21fdf952dSChris Bieneman // 31fdf952dSChris Bieneman // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 41fdf952dSChris Bieneman // See https://llvm.org/LICENSE.txt for license information. 51fdf952dSChris Bieneman // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 61fdf952dSChris Bieneman // 71fdf952dSChris Bieneman //===----------------------------------------------------------------------===// 81fdf952dSChris Bieneman // 91fdf952dSChris Bieneman // This file implements the parsing logic for HLSL language features. 101fdf952dSChris Bieneman // 111fdf952dSChris Bieneman //===----------------------------------------------------------------------===// 121fdf952dSChris Bieneman 13e3fd0b20SXiang Li #include "clang/AST/Attr.h" 141fdf952dSChris Bieneman #include "clang/Basic/AttributeCommonInfo.h" 15834dfd23SKazu Hirata #include "clang/Basic/DiagnosticParse.h" 161fdf952dSChris Bieneman #include "clang/Parse/Parser.h" 17782ac218SXiang Li #include "clang/Parse/RAIIObjectsForParser.h" 18d345f6a2SVlad Serebrennikov #include "clang/Sema/SemaHLSL.h" 191fdf952dSChris Bieneman 201fdf952dSChris Bieneman using namespace clang; 211fdf952dSChris Bieneman 22782ac218SXiang Li static bool validateDeclsInsideHLSLBuffer(Parser::DeclGroupPtrTy DG, 23782ac218SXiang Li SourceLocation BufferLoc, 24782ac218SXiang Li bool IsCBuffer, Parser &P) { 25782ac218SXiang Li // The parse is failed, just return false. 26782ac218SXiang Li if (!DG) 27782ac218SXiang Li return false; 28782ac218SXiang Li DeclGroupRef Decls = DG.get(); 29782ac218SXiang Li bool IsValid = true; 30782ac218SXiang Li // Only allow function, variable, record decls inside HLSLBuffer. 31782ac218SXiang Li for (DeclGroupRef::iterator I = Decls.begin(), E = Decls.end(); I != E; ++I) { 32782ac218SXiang Li Decl *D = *I; 33782ac218SXiang Li if (isa<CXXRecordDecl, RecordDecl, FunctionDecl, VarDecl>(D)) 34782ac218SXiang Li continue; 35782ac218SXiang Li 36782ac218SXiang Li // FIXME: support nested HLSLBuffer and namespace inside HLSLBuffer. 37782ac218SXiang Li if (isa<HLSLBufferDecl, NamespaceDecl>(D)) { 38782ac218SXiang Li P.Diag(D->getLocation(), diag::err_invalid_declaration_in_hlsl_buffer) 39782ac218SXiang Li << IsCBuffer; 40782ac218SXiang Li IsValid = false; 41782ac218SXiang Li continue; 42782ac218SXiang Li } 43782ac218SXiang Li 44782ac218SXiang Li IsValid = false; 45782ac218SXiang Li P.Diag(D->getLocation(), diag::err_invalid_declaration_in_hlsl_buffer) 46782ac218SXiang Li << IsCBuffer; 47782ac218SXiang Li } 48782ac218SXiang Li return IsValid; 49782ac218SXiang Li } 50782ac218SXiang Li 51782ac218SXiang Li Decl *Parser::ParseHLSLBuffer(SourceLocation &DeclEnd) { 52782ac218SXiang Li assert((Tok.is(tok::kw_cbuffer) || Tok.is(tok::kw_tbuffer)) && 53782ac218SXiang Li "Not a cbuffer or tbuffer!"); 54782ac218SXiang Li bool IsCBuffer = Tok.is(tok::kw_cbuffer); 55782ac218SXiang Li SourceLocation BufferLoc = ConsumeToken(); // Eat the 'cbuffer' or 'tbuffer'. 56782ac218SXiang Li 57782ac218SXiang Li if (!Tok.is(tok::identifier)) { 58782ac218SXiang Li Diag(Tok, diag::err_expected) << tok::identifier; 59782ac218SXiang Li return nullptr; 60782ac218SXiang Li } 61782ac218SXiang Li 62782ac218SXiang Li IdentifierInfo *Identifier = Tok.getIdentifierInfo(); 63782ac218SXiang Li SourceLocation IdentifierLoc = ConsumeToken(); 64782ac218SXiang Li 65e3fd0b20SXiang Li ParsedAttributes Attrs(AttrFactory); 66eaab97a0SJoshua Batista MaybeParseHLSLAnnotations(Attrs, nullptr); 67e3fd0b20SXiang Li 68782ac218SXiang Li ParseScope BufferScope(this, Scope::DeclScope); 69782ac218SXiang Li BalancedDelimiterTracker T(*this, tok::l_brace); 70782ac218SXiang Li if (T.consumeOpen()) { 71782ac218SXiang Li Diag(Tok, diag::err_expected) << tok::l_brace; 72782ac218SXiang Li return nullptr; 73782ac218SXiang Li } 74782ac218SXiang Li 75b45c9c31SVlad Serebrennikov Decl *D = Actions.HLSL().ActOnStartBuffer(getCurScope(), IsCBuffer, BufferLoc, 76b45c9c31SVlad Serebrennikov Identifier, IdentifierLoc, 77782ac218SXiang Li T.getOpenLocation()); 78782ac218SXiang Li 79782ac218SXiang Li while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { 80782ac218SXiang Li // FIXME: support attribute on constants inside cbuffer/tbuffer. 81b78d5380SSaleem Abdulrasool ParsedAttributes DeclAttrs(AttrFactory); 82b78d5380SSaleem Abdulrasool ParsedAttributes EmptyDeclSpecAttrs(AttrFactory); 83782ac218SXiang Li 84b78d5380SSaleem Abdulrasool DeclGroupPtrTy Result = 85b78d5380SSaleem Abdulrasool ParseExternalDeclaration(DeclAttrs, EmptyDeclSpecAttrs); 86782ac218SXiang Li if (!validateDeclsInsideHLSLBuffer(Result, IdentifierLoc, IsCBuffer, 87782ac218SXiang Li *this)) { 88782ac218SXiang Li T.skipToEnd(); 89782ac218SXiang Li DeclEnd = T.getCloseLocation(); 90782ac218SXiang Li BufferScope.Exit(); 91b45c9c31SVlad Serebrennikov Actions.HLSL().ActOnFinishBuffer(D, DeclEnd); 92782ac218SXiang Li return nullptr; 93782ac218SXiang Li } 94782ac218SXiang Li } 95782ac218SXiang Li 96782ac218SXiang Li T.consumeClose(); 97782ac218SXiang Li DeclEnd = T.getCloseLocation(); 98782ac218SXiang Li BufferScope.Exit(); 99b45c9c31SVlad Serebrennikov Actions.HLSL().ActOnFinishBuffer(D, DeclEnd); 100782ac218SXiang Li 101e3fd0b20SXiang Li Actions.ProcessDeclAttributeList(Actions.CurScope, D, Attrs); 102782ac218SXiang Li return D; 103782ac218SXiang Li } 104782ac218SXiang Li 105e3fd0b20SXiang Li static void fixSeparateAttrArgAndNumber(StringRef ArgStr, SourceLocation ArgLoc, 106e3fd0b20SXiang Li Token Tok, ArgsVector &ArgExprs, 107e3fd0b20SXiang Li Parser &P, ASTContext &Ctx, 108e3fd0b20SXiang Li Preprocessor &PP) { 109e3fd0b20SXiang Li StringRef Num = StringRef(Tok.getLiteralData(), Tok.getLength()); 110e3fd0b20SXiang Li SourceLocation EndNumLoc = Tok.getEndLoc(); 111e3fd0b20SXiang Li 112e3fd0b20SXiang Li P.ConsumeToken(); // consume constant. 113e3fd0b20SXiang Li std::string FixedArg = ArgStr.str() + Num.str(); 114e3fd0b20SXiang Li P.Diag(ArgLoc, diag::err_hlsl_separate_attr_arg_and_number) 115e3fd0b20SXiang Li << FixedArg 116e3fd0b20SXiang Li << FixItHint::CreateReplacement(SourceRange(ArgLoc, EndNumLoc), FixedArg); 117e3fd0b20SXiang Li ArgsUnion &Slot = ArgExprs.back(); 118e3fd0b20SXiang Li Slot = IdentifierLoc::create(Ctx, ArgLoc, PP.getIdentifierInfo(FixedArg)); 119e3fd0b20SXiang Li } 120e3fd0b20SXiang Li 121eaab97a0SJoshua Batista void Parser::ParseHLSLAnnotations(ParsedAttributes &Attrs, 122c50ef30cSJoshua Batista SourceLocation *EndLoc, 123c50ef30cSJoshua Batista bool CouldBeBitField) { 124eaab97a0SJoshua Batista 125eaab97a0SJoshua Batista assert(Tok.is(tok::colon) && "Not a HLSL Annotation"); 126c50ef30cSJoshua Batista Token OldToken = Tok; 1271fdf952dSChris Bieneman ConsumeToken(); 1281fdf952dSChris Bieneman 129e3fd0b20SXiang Li IdentifierInfo *II = nullptr; 130e3fd0b20SXiang Li if (Tok.is(tok::kw_register)) 131e3fd0b20SXiang Li II = PP.getIdentifierInfo("register"); 132e3fd0b20SXiang Li else if (Tok.is(tok::identifier)) 133e3fd0b20SXiang Li II = Tok.getIdentifierInfo(); 134e3fd0b20SXiang Li 135e3fd0b20SXiang Li if (!II) { 136c50ef30cSJoshua Batista if (CouldBeBitField) { 137c50ef30cSJoshua Batista UnconsumeToken(OldToken); 138c50ef30cSJoshua Batista return; 139c50ef30cSJoshua Batista } 1401fdf952dSChris Bieneman Diag(Tok.getLocation(), diag::err_expected_semantic_identifier); 1411fdf952dSChris Bieneman return; 1421fdf952dSChris Bieneman } 1431fdf952dSChris Bieneman 1441fdf952dSChris Bieneman SourceLocation Loc = ConsumeToken(); 1451fdf952dSChris Bieneman if (EndLoc) 1461fdf952dSChris Bieneman *EndLoc = Tok.getLocation(); 1471fdf952dSChris Bieneman ParsedAttr::Kind AttrKind = 148eaab97a0SJoshua Batista ParsedAttr::getParsedKind(II, nullptr, ParsedAttr::AS_HLSLAnnotation); 1491fdf952dSChris Bieneman 150e3fd0b20SXiang Li ArgsVector ArgExprs; 151e3fd0b20SXiang Li switch (AttrKind) { 152e3fd0b20SXiang Li case ParsedAttr::AT_HLSLResourceBinding: { 153e3fd0b20SXiang Li if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after)) { 154e3fd0b20SXiang Li SkipUntil(tok::r_paren, StopAtSemi); // skip through ) 1551fdf952dSChris Bieneman return; 1561fdf952dSChris Bieneman } 157e3fd0b20SXiang Li if (!Tok.is(tok::identifier)) { 158e3fd0b20SXiang Li Diag(Tok.getLocation(), diag::err_expected) << tok::identifier; 159e3fd0b20SXiang Li SkipUntil(tok::r_paren, StopAtSemi); // skip through ) 160e3fd0b20SXiang Li return; 161e3fd0b20SXiang Li } 162e3fd0b20SXiang Li StringRef SlotStr = Tok.getIdentifierInfo()->getName(); 163e3fd0b20SXiang Li SourceLocation SlotLoc = Tok.getLocation(); 164e3fd0b20SXiang Li ArgExprs.push_back(ParseIdentifierLoc()); 165e3fd0b20SXiang Li 166e3fd0b20SXiang Li // Add numeric_constant for fix-it. 167e3fd0b20SXiang Li if (SlotStr.size() == 1 && Tok.is(tok::numeric_constant)) 168e3fd0b20SXiang Li fixSeparateAttrArgAndNumber(SlotStr, SlotLoc, Tok, ArgExprs, *this, 169e3fd0b20SXiang Li Actions.Context, PP); 170e3fd0b20SXiang Li 171e3fd0b20SXiang Li if (Tok.is(tok::comma)) { 172e3fd0b20SXiang Li ConsumeToken(); // consume comma 173e3fd0b20SXiang Li if (!Tok.is(tok::identifier)) { 174e3fd0b20SXiang Li Diag(Tok.getLocation(), diag::err_expected) << tok::identifier; 175e3fd0b20SXiang Li SkipUntil(tok::r_paren, StopAtSemi); // skip through ) 176e3fd0b20SXiang Li return; 177e3fd0b20SXiang Li } 178e3fd0b20SXiang Li StringRef SpaceStr = Tok.getIdentifierInfo()->getName(); 179e3fd0b20SXiang Li SourceLocation SpaceLoc = Tok.getLocation(); 180e3fd0b20SXiang Li ArgExprs.push_back(ParseIdentifierLoc()); 181e3fd0b20SXiang Li 182e3fd0b20SXiang Li // Add numeric_constant for fix-it. 183deffae5dSKazu Hirata if (SpaceStr == "space" && Tok.is(tok::numeric_constant)) 184e3fd0b20SXiang Li fixSeparateAttrArgAndNumber(SpaceStr, SpaceLoc, Tok, ArgExprs, *this, 185e3fd0b20SXiang Li Actions.Context, PP); 186e3fd0b20SXiang Li } 187e3fd0b20SXiang Li if (ExpectAndConsume(tok::r_paren, diag::err_expected)) { 188e3fd0b20SXiang Li SkipUntil(tok::r_paren, StopAtSemi); // skip through ) 189e3fd0b20SXiang Li return; 190e3fd0b20SXiang Li } 191e3fd0b20SXiang Li } break; 19241f0574cSXiang Li case ParsedAttr::AT_HLSLPackOffset: { 19341f0574cSXiang Li // Parse 'packoffset( c[Subcomponent][.component] )'. 19441f0574cSXiang Li // Check '('. 19541f0574cSXiang Li if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after)) { 19641f0574cSXiang Li SkipUntil(tok::r_paren, StopAtSemi); // skip through ) 19741f0574cSXiang Li return; 19841f0574cSXiang Li } 19941f0574cSXiang Li // Check c[Subcomponent] as an identifier. 20041f0574cSXiang Li if (!Tok.is(tok::identifier)) { 20141f0574cSXiang Li Diag(Tok.getLocation(), diag::err_expected) << tok::identifier; 20241f0574cSXiang Li SkipUntil(tok::r_paren, StopAtSemi); // skip through ) 20341f0574cSXiang Li return; 20441f0574cSXiang Li } 20541f0574cSXiang Li StringRef OffsetStr = Tok.getIdentifierInfo()->getName(); 20641f0574cSXiang Li SourceLocation SubComponentLoc = Tok.getLocation(); 20741f0574cSXiang Li if (OffsetStr[0] != 'c') { 20841f0574cSXiang Li Diag(Tok.getLocation(), diag::err_hlsl_packoffset_invalid_reg) 20941f0574cSXiang Li << OffsetStr; 21041f0574cSXiang Li SkipUntil(tok::r_paren, StopAtSemi); // skip through ) 21141f0574cSXiang Li return; 21241f0574cSXiang Li } 21341f0574cSXiang Li OffsetStr = OffsetStr.substr(1); 21441f0574cSXiang Li unsigned SubComponent = 0; 21541f0574cSXiang Li if (!OffsetStr.empty()) { 21641f0574cSXiang Li // Make sure SubComponent is a number. 21741f0574cSXiang Li if (OffsetStr.getAsInteger(10, SubComponent)) { 21841f0574cSXiang Li Diag(SubComponentLoc.getLocWithOffset(1), 21941f0574cSXiang Li diag::err_hlsl_unsupported_register_number); 22041f0574cSXiang Li SkipUntil(tok::r_paren, StopAtSemi); // skip through ) 22141f0574cSXiang Li return; 22241f0574cSXiang Li } 22341f0574cSXiang Li } 22441f0574cSXiang Li unsigned Component = 0; 22541f0574cSXiang Li ConsumeToken(); // consume identifier. 22641f0574cSXiang Li SourceLocation ComponentLoc; 22741f0574cSXiang Li if (Tok.is(tok::period)) { 22841f0574cSXiang Li ConsumeToken(); // consume period. 22941f0574cSXiang Li if (!Tok.is(tok::identifier)) { 23041f0574cSXiang Li Diag(Tok.getLocation(), diag::err_expected) << tok::identifier; 23141f0574cSXiang Li SkipUntil(tok::r_paren, StopAtSemi); // skip through ) 23241f0574cSXiang Li return; 23341f0574cSXiang Li } 23441f0574cSXiang Li StringRef ComponentStr = Tok.getIdentifierInfo()->getName(); 23541f0574cSXiang Li ComponentLoc = Tok.getLocation(); 23641f0574cSXiang Li ConsumeToken(); // consume identifier. 23741f0574cSXiang Li // Make sure Component is a single character. 23841f0574cSXiang Li if (ComponentStr.size() != 1) { 23941f0574cSXiang Li Diag(ComponentLoc, diag::err_hlsl_unsupported_component) 24041f0574cSXiang Li << ComponentStr; 24141f0574cSXiang Li SkipUntil(tok::r_paren, StopAtSemi); // skip through ) 24241f0574cSXiang Li return; 24341f0574cSXiang Li } 24441f0574cSXiang Li switch (ComponentStr[0]) { 24541f0574cSXiang Li case 'x': 24641f0574cSXiang Li case 'r': 24741f0574cSXiang Li Component = 0; 24841f0574cSXiang Li break; 24941f0574cSXiang Li case 'y': 25041f0574cSXiang Li case 'g': 25141f0574cSXiang Li Component = 1; 25241f0574cSXiang Li break; 25341f0574cSXiang Li case 'z': 25441f0574cSXiang Li case 'b': 25541f0574cSXiang Li Component = 2; 25641f0574cSXiang Li break; 25741f0574cSXiang Li case 'w': 25841f0574cSXiang Li case 'a': 25941f0574cSXiang Li Component = 3; 26041f0574cSXiang Li break; 26141f0574cSXiang Li default: 26241f0574cSXiang Li Diag(ComponentLoc, diag::err_hlsl_unsupported_component) 26341f0574cSXiang Li << ComponentStr; 26441f0574cSXiang Li SkipUntil(tok::r_paren, StopAtSemi); // skip through ) 26541f0574cSXiang Li return; 26641f0574cSXiang Li } 26741f0574cSXiang Li } 26841f0574cSXiang Li ASTContext &Ctx = Actions.getASTContext(); 26941f0574cSXiang Li QualType SizeTy = Ctx.getSizeType(); 27041f0574cSXiang Li uint64_t SizeTySize = Ctx.getTypeSize(SizeTy); 27141f0574cSXiang Li ArgExprs.push_back(IntegerLiteral::Create( 27241f0574cSXiang Li Ctx, llvm::APInt(SizeTySize, SubComponent), SizeTy, SubComponentLoc)); 27341f0574cSXiang Li ArgExprs.push_back(IntegerLiteral::Create( 27441f0574cSXiang Li Ctx, llvm::APInt(SizeTySize, Component), SizeTy, ComponentLoc)); 27541f0574cSXiang Li if (ExpectAndConsume(tok::r_paren, diag::err_expected)) { 27641f0574cSXiang Li SkipUntil(tok::r_paren, StopAtSemi); // skip through ) 27741f0574cSXiang Li return; 27841f0574cSXiang Li } 27941f0574cSXiang Li } break; 280e3fd0b20SXiang Li case ParsedAttr::UnknownAttribute: 281e3fd0b20SXiang Li Diag(Loc, diag::err_unknown_hlsl_semantic) << II; 282e3fd0b20SXiang Li return; 283*951a284fSZhengxing li case ParsedAttr::AT_HLSLSV_GroupThreadID: 2845fd4f32fSZhengxing li case ParsedAttr::AT_HLSLSV_GroupID: 285e3fd0b20SXiang Li case ParsedAttr::AT_HLSLSV_GroupIndex: 28614ae5d2bSXiang Li case ParsedAttr::AT_HLSLSV_DispatchThreadID: 287e3fd0b20SXiang Li break; 288e3fd0b20SXiang Li default: 289eaab97a0SJoshua Batista llvm_unreachable("invalid HLSL Annotation"); 290e3fd0b20SXiang Li break; 291e3fd0b20SXiang Li } 292e3fd0b20SXiang Li 293e3fd0b20SXiang Li Attrs.addNew(II, Loc, nullptr, SourceLocation(), ArgExprs.data(), 294eaab97a0SJoshua Batista ArgExprs.size(), ParsedAttr::Form::HLSLAnnotation()); 2951fdf952dSChris Bieneman } 296