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