xref: /llvm-project/clang/lib/Parse/ParseHLSL.cpp (revision 951a284fdff43f9b3aa2d2dbb2d01bbce3ab0673)
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