clang 20.0.0git
SemaHLSL.cpp
Go to the documentation of this file.
1//===- SemaHLSL.cpp - Semantic Analysis for HLSL constructs ---------------===//
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// This implements Semantic Analysis for HLSL constructs.
9//===----------------------------------------------------------------------===//
10
11#include "clang/Sema/SemaHLSL.h"
12#include "clang/AST/Decl.h"
13#include "clang/AST/Expr.h"
16#include "clang/Basic/LLVM.h"
19#include "clang/Sema/Sema.h"
20#include "llvm/ADT/STLExtras.h"
21#include "llvm/ADT/StringExtras.h"
22#include "llvm/ADT/StringRef.h"
23#include "llvm/Support/Casting.h"
24#include "llvm/Support/ErrorHandling.h"
25#include "llvm/TargetParser/Triple.h"
26#include <iterator>
27
28using namespace clang;
29
31
32Decl *SemaHLSL::ActOnStartBuffer(Scope *BufferScope, bool CBuffer,
33 SourceLocation KwLoc, IdentifierInfo *Ident,
34 SourceLocation IdentLoc,
35 SourceLocation LBrace) {
36 // For anonymous namespace, take the location of the left brace.
37 DeclContext *LexicalParent = SemaRef.getCurLexicalContext();
39 getASTContext(), LexicalParent, CBuffer, KwLoc, Ident, IdentLoc, LBrace);
40
41 SemaRef.PushOnScopeChains(Result, BufferScope);
42 SemaRef.PushDeclContext(BufferScope, Result);
43
44 return Result;
45}
46
47// Calculate the size of a legacy cbuffer type based on
48// https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-packing-rules
49static unsigned calculateLegacyCbufferSize(const ASTContext &Context,
50 QualType T) {
51 unsigned Size = 0;
52 constexpr unsigned CBufferAlign = 128;
53 if (const RecordType *RT = T->getAs<RecordType>()) {
54 const RecordDecl *RD = RT->getDecl();
55 for (const FieldDecl *Field : RD->fields()) {
56 QualType Ty = Field->getType();
57 unsigned FieldSize = calculateLegacyCbufferSize(Context, Ty);
58 unsigned FieldAlign = 32;
59 if (Ty->isAggregateType())
60 FieldAlign = CBufferAlign;
61 Size = llvm::alignTo(Size, FieldAlign);
62 Size += FieldSize;
63 }
64 } else if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) {
65 if (unsigned ElementCount = AT->getSize().getZExtValue()) {
66 unsigned ElementSize =
67 calculateLegacyCbufferSize(Context, AT->getElementType());
68 unsigned AlignedElementSize = llvm::alignTo(ElementSize, CBufferAlign);
69 Size = AlignedElementSize * (ElementCount - 1) + ElementSize;
70 }
71 } else if (const VectorType *VT = T->getAs<VectorType>()) {
72 unsigned ElementCount = VT->getNumElements();
73 unsigned ElementSize =
74 calculateLegacyCbufferSize(Context, VT->getElementType());
75 Size = ElementSize * ElementCount;
76 } else {
77 Size = Context.getTypeSize(T);
78 }
79 return Size;
80}
81
83 auto *BufDecl = cast<HLSLBufferDecl>(Dcl);
84 BufDecl->setRBraceLoc(RBrace);
85
86 // Validate packoffset.
88 bool HasPackOffset = false;
89 bool HasNonPackOffset = false;
90 for (auto *Field : BufDecl->decls()) {
91 VarDecl *Var = dyn_cast<VarDecl>(Field);
92 if (!Var)
93 continue;
94 if (Field->hasAttr<HLSLPackOffsetAttr>()) {
95 PackOffsetVec.emplace_back(Var, Field->getAttr<HLSLPackOffsetAttr>());
96 HasPackOffset = true;
97 } else {
98 HasNonPackOffset = true;
99 }
100 }
101
102 if (HasPackOffset && HasNonPackOffset)
103 Diag(BufDecl->getLocation(), diag::warn_hlsl_packoffset_mix);
104
105 if (HasPackOffset) {
106 ASTContext &Context = getASTContext();
107 // Make sure no overlap in packoffset.
108 // Sort PackOffsetVec by offset.
109 std::sort(PackOffsetVec.begin(), PackOffsetVec.end(),
110 [](const std::pair<VarDecl *, HLSLPackOffsetAttr *> &LHS,
111 const std::pair<VarDecl *, HLSLPackOffsetAttr *> &RHS) {
112 return LHS.second->getOffset() < RHS.second->getOffset();
113 });
114
115 for (unsigned i = 0; i < PackOffsetVec.size() - 1; i++) {
116 VarDecl *Var = PackOffsetVec[i].first;
117 HLSLPackOffsetAttr *Attr = PackOffsetVec[i].second;
118 unsigned Size = calculateLegacyCbufferSize(Context, Var->getType());
119 unsigned Begin = Attr->getOffset() * 32;
120 unsigned End = Begin + Size;
121 unsigned NextBegin = PackOffsetVec[i + 1].second->getOffset() * 32;
122 if (End > NextBegin) {
123 VarDecl *NextVar = PackOffsetVec[i + 1].first;
124 Diag(NextVar->getLocation(), diag::err_hlsl_packoffset_overlap)
125 << NextVar << Var;
126 }
127 }
128 }
129
131}
132
134 const AttributeCommonInfo &AL,
135 int X, int Y, int Z) {
136 if (HLSLNumThreadsAttr *NT = D->getAttr<HLSLNumThreadsAttr>()) {
137 if (NT->getX() != X || NT->getY() != Y || NT->getZ() != Z) {
138 Diag(NT->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL;
139 Diag(AL.getLoc(), diag::note_conflicting_attribute);
140 }
141 return nullptr;
142 }
143 return ::new (getASTContext())
144 HLSLNumThreadsAttr(getASTContext(), AL, X, Y, Z);
145}
146
147HLSLShaderAttr *
149 llvm::Triple::EnvironmentType ShaderType) {
150 if (HLSLShaderAttr *NT = D->getAttr<HLSLShaderAttr>()) {
151 if (NT->getType() != ShaderType) {
152 Diag(NT->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL;
153 Diag(AL.getLoc(), diag::note_conflicting_attribute);
154 }
155 return nullptr;
156 }
157 return HLSLShaderAttr::Create(getASTContext(), ShaderType, AL);
158}
159
160HLSLParamModifierAttr *
162 HLSLParamModifierAttr::Spelling Spelling) {
163 // We can only merge an `in` attribute with an `out` attribute. All other
164 // combinations of duplicated attributes are ill-formed.
165 if (HLSLParamModifierAttr *PA = D->getAttr<HLSLParamModifierAttr>()) {
166 if ((PA->isIn() && Spelling == HLSLParamModifierAttr::Keyword_out) ||
167 (PA->isOut() && Spelling == HLSLParamModifierAttr::Keyword_in)) {
168 D->dropAttr<HLSLParamModifierAttr>();
169 SourceRange AdjustedRange = {PA->getLocation(), AL.getRange().getEnd()};
170 return HLSLParamModifierAttr::Create(
171 getASTContext(), /*MergedSpelling=*/true, AdjustedRange,
172 HLSLParamModifierAttr::Keyword_inout);
173 }
174 Diag(AL.getLoc(), diag::err_hlsl_duplicate_parameter_modifier) << AL;
175 Diag(PA->getLocation(), diag::note_conflicting_attribute);
176 return nullptr;
177 }
178 return HLSLParamModifierAttr::Create(getASTContext(), AL);
179}
180
183
185 return;
186
187 llvm::Triple::EnvironmentType Env = TargetInfo.getTriple().getEnvironment();
188 if (HLSLShaderAttr::isValidShaderType(Env) && Env != llvm::Triple::Library) {
189 if (const auto *Shader = FD->getAttr<HLSLShaderAttr>()) {
190 // The entry point is already annotated - check that it matches the
191 // triple.
192 if (Shader->getType() != Env) {
193 Diag(Shader->getLocation(), diag::err_hlsl_entry_shader_attr_mismatch)
194 << Shader;
195 FD->setInvalidDecl();
196 }
197 } else {
198 // Implicitly add the shader attribute if the entry function isn't
199 // explicitly annotated.
200 FD->addAttr(HLSLShaderAttr::CreateImplicit(getASTContext(), Env,
201 FD->getBeginLoc()));
202 }
203 } else {
204 switch (Env) {
205 case llvm::Triple::UnknownEnvironment:
206 case llvm::Triple::Library:
207 break;
208 default:
209 llvm_unreachable("Unhandled environment in triple");
210 }
211 }
212}
213
215 const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>();
216 assert(ShaderAttr && "Entry point has no shader attribute");
217 llvm::Triple::EnvironmentType ST = ShaderAttr->getType();
218
219 switch (ST) {
220 case llvm::Triple::Pixel:
221 case llvm::Triple::Vertex:
222 case llvm::Triple::Geometry:
223 case llvm::Triple::Hull:
224 case llvm::Triple::Domain:
225 case llvm::Triple::RayGeneration:
226 case llvm::Triple::Intersection:
227 case llvm::Triple::AnyHit:
228 case llvm::Triple::ClosestHit:
229 case llvm::Triple::Miss:
230 case llvm::Triple::Callable:
231 if (const auto *NT = FD->getAttr<HLSLNumThreadsAttr>()) {
233 {llvm::Triple::Compute,
234 llvm::Triple::Amplification,
235 llvm::Triple::Mesh});
236 FD->setInvalidDecl();
237 }
238 break;
239
240 case llvm::Triple::Compute:
241 case llvm::Triple::Amplification:
242 case llvm::Triple::Mesh:
243 if (!FD->hasAttr<HLSLNumThreadsAttr>()) {
244 Diag(FD->getLocation(), diag::err_hlsl_missing_numthreads)
245 << llvm::Triple::getEnvironmentTypeName(ST);
246 FD->setInvalidDecl();
247 }
248 break;
249 default:
250 llvm_unreachable("Unhandled environment in triple");
251 }
252
253 for (ParmVarDecl *Param : FD->parameters()) {
254 if (const auto *AnnotationAttr = Param->getAttr<HLSLAnnotationAttr>()) {
255 CheckSemanticAnnotation(FD, Param, AnnotationAttr);
256 } else {
257 // FIXME: Handle struct parameters where annotations are on struct fields.
258 // See: https://github.com/llvm/llvm-project/issues/57875
259 Diag(FD->getLocation(), diag::err_hlsl_missing_semantic_annotation);
260 Diag(Param->getLocation(), diag::note_previous_decl) << Param;
261 FD->setInvalidDecl();
262 }
263 }
264 // FIXME: Verify return type semantic annotation.
265}
266
268 FunctionDecl *EntryPoint, const Decl *Param,
269 const HLSLAnnotationAttr *AnnotationAttr) {
270 auto *ShaderAttr = EntryPoint->getAttr<HLSLShaderAttr>();
271 assert(ShaderAttr && "Entry point has no shader attribute");
272 llvm::Triple::EnvironmentType ST = ShaderAttr->getType();
273
274 switch (AnnotationAttr->getKind()) {
275 case attr::HLSLSV_DispatchThreadID:
276 case attr::HLSLSV_GroupIndex:
277 if (ST == llvm::Triple::Compute)
278 return;
279 DiagnoseAttrStageMismatch(AnnotationAttr, ST, {llvm::Triple::Compute});
280 break;
281 default:
282 llvm_unreachable("Unknown HLSLAnnotationAttr");
283 }
284}
285
287 const Attr *A, llvm::Triple::EnvironmentType Stage,
288 std::initializer_list<llvm::Triple::EnvironmentType> AllowedStages) {
289 SmallVector<StringRef, 8> StageStrings;
290 llvm::transform(AllowedStages, std::back_inserter(StageStrings),
291 [](llvm::Triple::EnvironmentType ST) {
292 return StringRef(
293 HLSLShaderAttr::ConvertEnvironmentTypeToStr(ST));
294 });
295 Diag(A->getLoc(), diag::err_hlsl_attr_unsupported_in_stage)
296 << A << llvm::Triple::getEnvironmentTypeName(Stage)
297 << (AllowedStages.size() != 1) << join(StageStrings, ", ");
298}
299
301 llvm::VersionTuple SMVersion =
302 getASTContext().getTargetInfo().getTriple().getOSVersion();
303 uint32_t ZMax = 1024;
304 uint32_t ThreadMax = 1024;
305 if (SMVersion.getMajor() <= 4) {
306 ZMax = 1;
307 ThreadMax = 768;
308 } else if (SMVersion.getMajor() == 5) {
309 ZMax = 64;
310 ThreadMax = 1024;
311 }
312
313 uint32_t X;
314 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), X))
315 return;
316 if (X > 1024) {
318 diag::err_hlsl_numthreads_argument_oor)
319 << 0 << 1024;
320 return;
321 }
322 uint32_t Y;
323 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Y))
324 return;
325 if (Y > 1024) {
327 diag::err_hlsl_numthreads_argument_oor)
328 << 1 << 1024;
329 return;
330 }
331 uint32_t Z;
332 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(2), Z))
333 return;
334 if (Z > ZMax) {
336 diag::err_hlsl_numthreads_argument_oor)
337 << 2 << ZMax;
338 return;
339 }
340
341 if (X * Y * Z > ThreadMax) {
342 Diag(AL.getLoc(), diag::err_hlsl_numthreads_invalid) << ThreadMax;
343 return;
344 }
345
346 HLSLNumThreadsAttr *NewAttr = mergeNumThreadsAttr(D, AL, X, Y, Z);
347 if (NewAttr)
348 D->addAttr(NewAttr);
349}
350
353 return false;
354 if (const auto *VT = T->getAs<VectorType>())
355 return VT->getNumElements() <= 3;
356 return true;
357}
358
360 auto *VD = cast<ValueDecl>(D);
361 if (!isLegalTypeForHLSLSV_DispatchThreadID(VD->getType())) {
362 Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
363 << AL << "uint/uint2/uint3";
364 return;
365 }
366
367 D->addAttr(::new (getASTContext())
368 HLSLSV_DispatchThreadIDAttr(getASTContext(), AL));
369}
370
372 if (!isa<VarDecl>(D) || !isa<HLSLBufferDecl>(D->getDeclContext())) {
373 Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_ast_node)
374 << AL << "shader constant in a constant buffer";
375 return;
376 }
377
378 uint32_t SubComponent;
379 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), SubComponent))
380 return;
381 uint32_t Component;
382 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Component))
383 return;
384
385 QualType T = cast<VarDecl>(D)->getType().getCanonicalType();
386 // Check if T is an array or struct type.
387 // TODO: mark matrix type as aggregate type.
388 bool IsAggregateTy = (T->isArrayType() || T->isStructureType());
389
390 // Check Component is valid for T.
391 if (Component) {
392 unsigned Size = getASTContext().getTypeSize(T);
393 if (IsAggregateTy || Size > 128) {
394 Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary);
395 return;
396 } else {
397 // Make sure Component + sizeof(T) <= 4.
398 if ((Component * 32 + Size) > 128) {
399 Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary);
400 return;
401 }
402 QualType EltTy = T;
403 if (const auto *VT = T->getAs<VectorType>())
404 EltTy = VT->getElementType();
405 unsigned Align = getASTContext().getTypeAlign(EltTy);
406 if (Align > 32 && Component == 1) {
407 // NOTE: Component 3 will hit err_hlsl_packoffset_cross_reg_boundary.
408 // So we only need to check Component 1 here.
409 Diag(AL.getLoc(), diag::err_hlsl_packoffset_alignment_mismatch)
410 << Align << EltTy;
411 return;
412 }
413 }
414 }
415
416 D->addAttr(::new (getASTContext()) HLSLPackOffsetAttr(
417 getASTContext(), AL, SubComponent, Component));
418}
419
421 StringRef Str;
422 SourceLocation ArgLoc;
423 if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
424 return;
425
426 llvm::Triple::EnvironmentType ShaderType;
427 if (!HLSLShaderAttr::ConvertStrToEnvironmentType(Str, ShaderType)) {
428 Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
429 << AL << Str << ArgLoc;
430 return;
431 }
432
433 // FIXME: check function match the shader stage.
434
435 HLSLShaderAttr *NewAttr = mergeShaderAttr(D, AL, ShaderType);
436 if (NewAttr)
437 D->addAttr(NewAttr);
438}
439
441 if (!AL.isArgIdent(0)) {
442 Diag(AL.getLoc(), diag::err_attribute_argument_type)
444 return;
445 }
446
448 StringRef Identifier = Loc->Ident->getName();
449 SourceLocation ArgLoc = Loc->Loc;
450
451 // Validate.
452 llvm::dxil::ResourceClass RC;
453 if (!HLSLResourceClassAttr::ConvertStrToResourceClass(Identifier, RC)) {
454 Diag(ArgLoc, diag::warn_attribute_type_not_supported)
455 << "ResourceClass" << Identifier;
456 return;
457 }
458
459 D->addAttr(HLSLResourceClassAttr::Create(getASTContext(), RC, ArgLoc));
460}
461
463 StringRef Space = "space0";
464 StringRef Slot = "";
465
466 if (!AL.isArgIdent(0)) {
467 Diag(AL.getLoc(), diag::err_attribute_argument_type)
469 return;
470 }
471
473 StringRef Str = Loc->Ident->getName();
474 SourceLocation ArgLoc = Loc->Loc;
475
476 SourceLocation SpaceArgLoc;
477 if (AL.getNumArgs() == 2) {
478 Slot = Str;
479 if (!AL.isArgIdent(1)) {
480 Diag(AL.getLoc(), diag::err_attribute_argument_type)
482 return;
483 }
484
486 Space = Loc->Ident->getName();
487 SpaceArgLoc = Loc->Loc;
488 } else {
489 Slot = Str;
490 }
491
492 // Validate.
493 if (!Slot.empty()) {
494 switch (Slot[0]) {
495 case 'u':
496 case 'b':
497 case 's':
498 case 't':
499 break;
500 default:
501 Diag(ArgLoc, diag::err_hlsl_unsupported_register_type)
502 << Slot.substr(0, 1);
503 return;
504 }
505
506 StringRef SlotNum = Slot.substr(1);
507 unsigned Num = 0;
508 if (SlotNum.getAsInteger(10, Num)) {
509 Diag(ArgLoc, diag::err_hlsl_unsupported_register_number);
510 return;
511 }
512 }
513
514 if (!Space.starts_with("space")) {
515 Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space;
516 return;
517 }
518 StringRef SpaceNum = Space.substr(5);
519 unsigned Num = 0;
520 if (SpaceNum.getAsInteger(10, Num)) {
521 Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space;
522 return;
523 }
524
525 // FIXME: check reg type match decl. Issue
526 // https://github.com/llvm/llvm-project/issues/57886.
527 HLSLResourceBindingAttr *NewAttr =
528 HLSLResourceBindingAttr::Create(getASTContext(), Slot, Space, AL);
529 if (NewAttr)
530 D->addAttr(NewAttr);
531}
532
534 HLSLParamModifierAttr *NewAttr = mergeParamModifierAttr(
535 D, AL,
536 static_cast<HLSLParamModifierAttr::Spelling>(AL.getSemanticSpelling()));
537 if (NewAttr)
538 D->addAttr(NewAttr);
539}
540
541namespace {
542
543/// This class implements HLSL availability diagnostics for default
544/// and relaxed mode
545///
546/// The goal of this diagnostic is to emit an error or warning when an
547/// unavailable API is found in code that is reachable from the shader
548/// entry function or from an exported function (when compiling a shader
549/// library).
550///
551/// This is done by traversing the AST of all shader entry point functions
552/// and of all exported functions, and any functions that are referenced
553/// from this AST. In other words, any functions that are reachable from
554/// the entry points.
555class DiagnoseHLSLAvailability
556 : public RecursiveASTVisitor<DiagnoseHLSLAvailability> {
557
558 Sema &SemaRef;
559
560 // Stack of functions to be scaned
562
563 // Tracks which environments functions have been scanned in.
564 //
565 // Maps FunctionDecl to an unsigned number that represents the set of shader
566 // environments the function has been scanned for.
567 // The llvm::Triple::EnvironmentType enum values for shader stages guaranteed
568 // to be numbered from llvm::Triple::Pixel to llvm::Triple::Amplification
569 // (verified by static_asserts in Triple.cpp), we can use it to index
570 // individual bits in the set, as long as we shift the values to start with 0
571 // by subtracting the value of llvm::Triple::Pixel first.
572 //
573 // The N'th bit in the set will be set if the function has been scanned
574 // in shader environment whose llvm::Triple::EnvironmentType integer value
575 // equals (llvm::Triple::Pixel + N).
576 //
577 // For example, if a function has been scanned in compute and pixel stage
578 // environment, the value will be 0x21 (100001 binary) because:
579 //
580 // (int)(llvm::Triple::Pixel - llvm::Triple::Pixel) == 0
581 // (int)(llvm::Triple::Compute - llvm::Triple::Pixel) == 5
582 //
583 // A FunctionDecl is mapped to 0 (or not included in the map) if it has not
584 // been scanned in any environment.
585 llvm::DenseMap<const FunctionDecl *, unsigned> ScannedDecls;
586
587 // Do not access these directly, use the get/set methods below to make
588 // sure the values are in sync
589 llvm::Triple::EnvironmentType CurrentShaderEnvironment;
590 unsigned CurrentShaderStageBit;
591
592 // True if scanning a function that was already scanned in a different
593 // shader stage context, and therefore we should not report issues that
594 // depend only on shader model version because they would be duplicate.
595 bool ReportOnlyShaderStageIssues;
596
597 // Helper methods for dealing with current stage context / environment
598 void SetShaderStageContext(llvm::Triple::EnvironmentType ShaderType) {
599 static_assert(sizeof(unsigned) >= 4);
600 assert(HLSLShaderAttr::isValidShaderType(ShaderType));
601 assert((unsigned)(ShaderType - llvm::Triple::Pixel) < 31 &&
602 "ShaderType is too big for this bitmap"); // 31 is reserved for
603 // "unknown"
604
605 unsigned bitmapIndex = ShaderType - llvm::Triple::Pixel;
606 CurrentShaderEnvironment = ShaderType;
607 CurrentShaderStageBit = (1 << bitmapIndex);
608 }
609
610 void SetUnknownShaderStageContext() {
611 CurrentShaderEnvironment = llvm::Triple::UnknownEnvironment;
612 CurrentShaderStageBit = (1 << 31);
613 }
614
615 llvm::Triple::EnvironmentType GetCurrentShaderEnvironment() const {
616 return CurrentShaderEnvironment;
617 }
618
619 bool InUnknownShaderStageContext() const {
620 return CurrentShaderEnvironment == llvm::Triple::UnknownEnvironment;
621 }
622
623 // Helper methods for dealing with shader stage bitmap
624 void AddToScannedFunctions(const FunctionDecl *FD) {
625 unsigned &ScannedStages = ScannedDecls.getOrInsertDefault(FD);
626 ScannedStages |= CurrentShaderStageBit;
627 }
628
629 unsigned GetScannedStages(const FunctionDecl *FD) {
630 return ScannedDecls.getOrInsertDefault(FD);
631 }
632
633 bool WasAlreadyScannedInCurrentStage(const FunctionDecl *FD) {
634 return WasAlreadyScannedInCurrentStage(GetScannedStages(FD));
635 }
636
637 bool WasAlreadyScannedInCurrentStage(unsigned ScannerStages) {
638 return ScannerStages & CurrentShaderStageBit;
639 }
640
641 static bool NeverBeenScanned(unsigned ScannedStages) {
642 return ScannedStages == 0;
643 }
644
645 // Scanning methods
646 void HandleFunctionOrMethodRef(FunctionDecl *FD, Expr *RefExpr);
647 void CheckDeclAvailability(NamedDecl *D, const AvailabilityAttr *AA,
649 const AvailabilityAttr *FindAvailabilityAttr(const Decl *D);
650 bool HasMatchingEnvironmentOrNone(const AvailabilityAttr *AA);
651
652public:
653 DiagnoseHLSLAvailability(Sema &SemaRef)
654 : SemaRef(SemaRef),
655 CurrentShaderEnvironment(llvm::Triple::UnknownEnvironment),
656 CurrentShaderStageBit(0), ReportOnlyShaderStageIssues(false) {}
657
658 // AST traversal methods
659 void RunOnTranslationUnit(const TranslationUnitDecl *TU);
660 void RunOnFunction(const FunctionDecl *FD);
661
662 bool VisitDeclRefExpr(DeclRefExpr *DRE) {
663 FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(DRE->getDecl());
664 if (FD)
665 HandleFunctionOrMethodRef(FD, DRE);
666 return true;
667 }
668
669 bool VisitMemberExpr(MemberExpr *ME) {
670 FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(ME->getMemberDecl());
671 if (FD)
672 HandleFunctionOrMethodRef(FD, ME);
673 return true;
674 }
675};
676
677void DiagnoseHLSLAvailability::HandleFunctionOrMethodRef(FunctionDecl *FD,
678 Expr *RefExpr) {
679 assert((isa<DeclRefExpr>(RefExpr) || isa<MemberExpr>(RefExpr)) &&
680 "expected DeclRefExpr or MemberExpr");
681
682 // has a definition -> add to stack to be scanned
683 const FunctionDecl *FDWithBody = nullptr;
684 if (FD->hasBody(FDWithBody)) {
685 if (!WasAlreadyScannedInCurrentStage(FDWithBody))
686 DeclsToScan.push_back(FDWithBody);
687 return;
688 }
689
690 // no body -> diagnose availability
691 const AvailabilityAttr *AA = FindAvailabilityAttr(FD);
692 if (AA)
693 CheckDeclAvailability(
694 FD, AA, SourceRange(RefExpr->getBeginLoc(), RefExpr->getEndLoc()));
695}
696
697void DiagnoseHLSLAvailability::RunOnTranslationUnit(
698 const TranslationUnitDecl *TU) {
699
700 // Iterate over all shader entry functions and library exports, and for those
701 // that have a body (definiton), run diag scan on each, setting appropriate
702 // shader environment context based on whether it is a shader entry function
703 // or an exported function. Exported functions can be in namespaces and in
704 // export declarations so we need to scan those declaration contexts as well.
706 DeclContextsToScan.push_back(TU);
707
708 while (!DeclContextsToScan.empty()) {
709 const DeclContext *DC = DeclContextsToScan.pop_back_val();
710 for (auto &D : DC->decls()) {
711 // do not scan implicit declaration generated by the implementation
712 if (D->isImplicit())
713 continue;
714
715 // for namespace or export declaration add the context to the list to be
716 // scanned later
717 if (llvm::dyn_cast<NamespaceDecl>(D) || llvm::dyn_cast<ExportDecl>(D)) {
718 DeclContextsToScan.push_back(llvm::dyn_cast<DeclContext>(D));
719 continue;
720 }
721
722 // skip over other decls or function decls without body
723 const FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(D);
724 if (!FD || !FD->isThisDeclarationADefinition())
725 continue;
726
727 // shader entry point
728 if (HLSLShaderAttr *ShaderAttr = FD->getAttr<HLSLShaderAttr>()) {
729 SetShaderStageContext(ShaderAttr->getType());
730 RunOnFunction(FD);
731 continue;
732 }
733 // exported library function
734 // FIXME: replace this loop with external linkage check once issue #92071
735 // is resolved
736 bool isExport = FD->isInExportDeclContext();
737 if (!isExport) {
738 for (const auto *Redecl : FD->redecls()) {
739 if (Redecl->isInExportDeclContext()) {
740 isExport = true;
741 break;
742 }
743 }
744 }
745 if (isExport) {
746 SetUnknownShaderStageContext();
747 RunOnFunction(FD);
748 continue;
749 }
750 }
751 }
752}
753
754void DiagnoseHLSLAvailability::RunOnFunction(const FunctionDecl *FD) {
755 assert(DeclsToScan.empty() && "DeclsToScan should be empty");
756 DeclsToScan.push_back(FD);
757
758 while (!DeclsToScan.empty()) {
759 // Take one decl from the stack and check it by traversing its AST.
760 // For any CallExpr found during the traversal add it's callee to the top of
761 // the stack to be processed next. Functions already processed are stored in
762 // ScannedDecls.
763 const FunctionDecl *FD = DeclsToScan.pop_back_val();
764
765 // Decl was already scanned
766 const unsigned ScannedStages = GetScannedStages(FD);
767 if (WasAlreadyScannedInCurrentStage(ScannedStages))
768 continue;
769
770 ReportOnlyShaderStageIssues = !NeverBeenScanned(ScannedStages);
771
772 AddToScannedFunctions(FD);
773 TraverseStmt(FD->getBody());
774 }
775}
776
777bool DiagnoseHLSLAvailability::HasMatchingEnvironmentOrNone(
778 const AvailabilityAttr *AA) {
779 IdentifierInfo *IIEnvironment = AA->getEnvironment();
780 if (!IIEnvironment)
781 return true;
782
783 llvm::Triple::EnvironmentType CurrentEnv = GetCurrentShaderEnvironment();
784 if (CurrentEnv == llvm::Triple::UnknownEnvironment)
785 return false;
786
787 llvm::Triple::EnvironmentType AttrEnv =
788 AvailabilityAttr::getEnvironmentType(IIEnvironment->getName());
789
790 return CurrentEnv == AttrEnv;
791}
792
793const AvailabilityAttr *
794DiagnoseHLSLAvailability::FindAvailabilityAttr(const Decl *D) {
795 AvailabilityAttr const *PartialMatch = nullptr;
796 // Check each AvailabilityAttr to find the one for this platform.
797 // For multiple attributes with the same platform try to find one for this
798 // environment.
799 for (const auto *A : D->attrs()) {
800 if (const auto *Avail = dyn_cast<AvailabilityAttr>(A)) {
801 StringRef AttrPlatform = Avail->getPlatform()->getName();
802 StringRef TargetPlatform =
804
805 // Match the platform name.
806 if (AttrPlatform == TargetPlatform) {
807 // Find the best matching attribute for this environment
808 if (HasMatchingEnvironmentOrNone(Avail))
809 return Avail;
810 PartialMatch = Avail;
811 }
812 }
813 }
814 return PartialMatch;
815}
816
817// Check availability against target shader model version and current shader
818// stage and emit diagnostic
819void DiagnoseHLSLAvailability::CheckDeclAvailability(NamedDecl *D,
820 const AvailabilityAttr *AA,
822
823 IdentifierInfo *IIEnv = AA->getEnvironment();
824
825 if (!IIEnv) {
826 // The availability attribute does not have environment -> it depends only
827 // on shader model version and not on specific the shader stage.
828
829 // Skip emitting the diagnostics if the diagnostic mode is set to
830 // strict (-fhlsl-strict-availability) because all relevant diagnostics
831 // were already emitted in the DiagnoseUnguardedAvailability scan
832 // (SemaAvailability.cpp).
833 if (SemaRef.getLangOpts().HLSLStrictAvailability)
834 return;
835
836 // Do not report shader-stage-independent issues if scanning a function
837 // that was already scanned in a different shader stage context (they would
838 // be duplicate)
839 if (ReportOnlyShaderStageIssues)
840 return;
841
842 } else {
843 // The availability attribute has environment -> we need to know
844 // the current stage context to property diagnose it.
845 if (InUnknownShaderStageContext())
846 return;
847 }
848
849 // Check introduced version and if environment matches
850 bool EnvironmentMatches = HasMatchingEnvironmentOrNone(AA);
851 VersionTuple Introduced = AA->getIntroduced();
852 VersionTuple TargetVersion =
854
855 if (TargetVersion >= Introduced && EnvironmentMatches)
856 return;
857
858 // Emit diagnostic message
859 const TargetInfo &TI = SemaRef.getASTContext().getTargetInfo();
860 llvm::StringRef PlatformName(
861 AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName()));
862
863 llvm::StringRef CurrentEnvStr =
864 llvm::Triple::getEnvironmentTypeName(GetCurrentShaderEnvironment());
865
866 llvm::StringRef AttrEnvStr =
867 AA->getEnvironment() ? AA->getEnvironment()->getName() : "";
868 bool UseEnvironment = !AttrEnvStr.empty();
869
870 if (EnvironmentMatches) {
871 SemaRef.Diag(Range.getBegin(), diag::warn_hlsl_availability)
872 << Range << D << PlatformName << Introduced.getAsString()
873 << UseEnvironment << CurrentEnvStr;
874 } else {
875 SemaRef.Diag(Range.getBegin(), diag::warn_hlsl_availability_unavailable)
876 << Range << D;
877 }
878
879 SemaRef.Diag(D->getLocation(), diag::note_partial_availability_specified_here)
880 << D << PlatformName << Introduced.getAsString()
881 << SemaRef.Context.getTargetInfo().getPlatformMinVersion().getAsString()
882 << UseEnvironment << AttrEnvStr << CurrentEnvStr;
883}
884
885} // namespace
886
888 // Skip running the diagnostics scan if the diagnostic mode is
889 // strict (-fhlsl-strict-availability) and the target shader stage is known
890 // because all relevant diagnostics were already emitted in the
891 // DiagnoseUnguardedAvailability scan (SemaAvailability.cpp).
893 if (SemaRef.getLangOpts().HLSLStrictAvailability &&
894 TI.getTriple().getEnvironment() != llvm::Triple::EnvironmentType::Library)
895 return;
896
897 DiagnoseHLSLAvailability(SemaRef).RunOnTranslationUnit(TU);
898}
899
900// Helper function for CheckHLSLBuiltinFunctionCall
902 assert(TheCall->getNumArgs() > 1);
903 ExprResult A = TheCall->getArg(0);
904
905 QualType ArgTyA = A.get()->getType();
906
907 auto *VecTyA = ArgTyA->getAs<VectorType>();
908 SourceLocation BuiltinLoc = TheCall->getBeginLoc();
909
910 for (unsigned i = 1; i < TheCall->getNumArgs(); ++i) {
911 ExprResult B = TheCall->getArg(i);
912 QualType ArgTyB = B.get()->getType();
913 auto *VecTyB = ArgTyB->getAs<VectorType>();
914 if (VecTyA == nullptr && VecTyB == nullptr)
915 return false;
916
917 if (VecTyA && VecTyB) {
918 bool retValue = false;
919 if (VecTyA->getElementType() != VecTyB->getElementType()) {
920 // Note: type promotion is intended to be handeled via the intrinsics
921 // and not the builtin itself.
922 S->Diag(TheCall->getBeginLoc(),
923 diag::err_vec_builtin_incompatible_vector)
924 << TheCall->getDirectCallee() << /*useAllTerminology*/ true
925 << SourceRange(A.get()->getBeginLoc(), B.get()->getEndLoc());
926 retValue = true;
927 }
928 if (VecTyA->getNumElements() != VecTyB->getNumElements()) {
929 // You should only be hitting this case if you are calling the builtin
930 // directly. HLSL intrinsics should avoid this case via a
931 // HLSLVectorTruncation.
932 S->Diag(BuiltinLoc, diag::err_vec_builtin_incompatible_vector)
933 << TheCall->getDirectCallee() << /*useAllTerminology*/ true
934 << SourceRange(TheCall->getArg(0)->getBeginLoc(),
935 TheCall->getArg(1)->getEndLoc());
936 retValue = true;
937 }
938 return retValue;
939 }
940 }
941
942 // Note: if we get here one of the args is a scalar which
943 // requires a VectorSplat on Arg0 or Arg1
944 S->Diag(BuiltinLoc, diag::err_vec_builtin_non_vector)
945 << TheCall->getDirectCallee() << /*useAllTerminology*/ true
946 << SourceRange(TheCall->getArg(0)->getBeginLoc(),
947 TheCall->getArg(1)->getEndLoc());
948 return true;
949}
950
952 Sema *S, CallExpr *TheCall, QualType ExpectedType,
953 llvm::function_ref<bool(clang::QualType PassedType)> Check) {
954 for (unsigned i = 0; i < TheCall->getNumArgs(); ++i) {
955 QualType PassedType = TheCall->getArg(i)->getType();
956 if (Check(PassedType)) {
957 if (auto *VecTyA = PassedType->getAs<VectorType>())
959 ExpectedType, VecTyA->getNumElements(), VecTyA->getVectorKind());
960 S->Diag(TheCall->getArg(0)->getBeginLoc(),
961 diag::err_typecheck_convert_incompatible)
962 << PassedType << ExpectedType << 1 << 0 << 0;
963 return true;
964 }
965 }
966 return false;
967}
968
970 auto checkAllFloatTypes = [](clang::QualType PassedType) -> bool {
971 return !PassedType->hasFloatingRepresentation();
972 };
973 return CheckArgsTypesAreCorrect(S, TheCall, S->Context.FloatTy,
974 checkAllFloatTypes);
975}
976
978 auto checkFloatorHalf = [](clang::QualType PassedType) -> bool {
979 clang::QualType BaseType =
980 PassedType->isVectorType()
981 ? PassedType->getAs<clang::VectorType>()->getElementType()
982 : PassedType;
983 return !BaseType->isHalfType() && !BaseType->isFloat32Type();
984 };
985 return CheckArgsTypesAreCorrect(S, TheCall, S->Context.FloatTy,
986 checkFloatorHalf);
987}
988
990 auto checkDoubleVector = [](clang::QualType PassedType) -> bool {
991 if (const auto *VecTy = PassedType->getAs<VectorType>())
992 return VecTy->getElementType()->isDoubleType();
993 return false;
994 };
995 return CheckArgsTypesAreCorrect(S, TheCall, S->Context.FloatTy,
996 checkDoubleVector);
997}
998
1000 auto checkAllUnsignedTypes = [](clang::QualType PassedType) -> bool {
1001 return !PassedType->hasUnsignedIntegerRepresentation();
1002 };
1003 return CheckArgsTypesAreCorrect(S, TheCall, S->Context.UnsignedIntTy,
1004 checkAllUnsignedTypes);
1005}
1006
1008 QualType ReturnType) {
1009 auto *VecTyA = TheCall->getArg(0)->getType()->getAs<VectorType>();
1010 if (VecTyA)
1011 ReturnType = S->Context.getVectorType(ReturnType, VecTyA->getNumElements(),
1013 TheCall->setType(ReturnType);
1014}
1015
1016// Note: returning true in this case results in CheckBuiltinFunctionCall
1017// returning an ExprError
1018bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
1019 switch (BuiltinID) {
1020 case Builtin::BI__builtin_hlsl_all:
1021 case Builtin::BI__builtin_hlsl_any: {
1022 if (SemaRef.checkArgCount(TheCall, 1))
1023 return true;
1024 break;
1025 }
1026 case Builtin::BI__builtin_hlsl_elementwise_clamp: {
1027 if (SemaRef.checkArgCount(TheCall, 3))
1028 return true;
1029 if (CheckVectorElementCallArgs(&SemaRef, TheCall))
1030 return true;
1032 TheCall, /*CheckForFloatArgs*/
1033 TheCall->getArg(0)->getType()->hasFloatingRepresentation()))
1034 return true;
1035 break;
1036 }
1037 case Builtin::BI__builtin_hlsl_dot: {
1038 if (SemaRef.checkArgCount(TheCall, 2))
1039 return true;
1040 if (CheckVectorElementCallArgs(&SemaRef, TheCall))
1041 return true;
1043 return true;
1044 if (CheckNoDoubleVectors(&SemaRef, TheCall))
1045 return true;
1046 break;
1047 }
1048 case Builtin::BI__builtin_hlsl_elementwise_saturate:
1049 case Builtin::BI__builtin_hlsl_elementwise_rcp: {
1051 return true;
1053 return true;
1054 break;
1055 }
1056 case Builtin::BI__builtin_hlsl_elementwise_rsqrt:
1057 case Builtin::BI__builtin_hlsl_elementwise_frac: {
1059 return true;
1061 return true;
1062 break;
1063 }
1064 case Builtin::BI__builtin_hlsl_elementwise_isinf: {
1066 return true;
1068 return true;
1070 break;
1071 }
1072 case Builtin::BI__builtin_hlsl_lerp: {
1073 if (SemaRef.checkArgCount(TheCall, 3))
1074 return true;
1075 if (CheckVectorElementCallArgs(&SemaRef, TheCall))
1076 return true;
1078 return true;
1080 return true;
1081 break;
1082 }
1083 case Builtin::BI__builtin_hlsl_length: {
1085 return true;
1086 if (SemaRef.checkArgCount(TheCall, 1))
1087 return true;
1088
1089 ExprResult A = TheCall->getArg(0);
1090 QualType ArgTyA = A.get()->getType();
1091 QualType RetTy;
1092
1093 if (auto *VTy = ArgTyA->getAs<VectorType>())
1094 RetTy = VTy->getElementType();
1095 else
1096 RetTy = TheCall->getArg(0)->getType();
1097
1098 TheCall->setType(RetTy);
1099 break;
1100 }
1101 case Builtin::BI__builtin_hlsl_mad: {
1102 if (SemaRef.checkArgCount(TheCall, 3))
1103 return true;
1104 if (CheckVectorElementCallArgs(&SemaRef, TheCall))
1105 return true;
1107 TheCall, /*CheckForFloatArgs*/
1108 TheCall->getArg(0)->getType()->hasFloatingRepresentation()))
1109 return true;
1110 break;
1111 }
1112 case Builtin::BI__builtin_hlsl_normalize: {
1114 return true;
1115 if (SemaRef.checkArgCount(TheCall, 1))
1116 return true;
1117
1118 ExprResult A = TheCall->getArg(0);
1119 QualType ArgTyA = A.get()->getType();
1120 // return type is the same as the input type
1121 TheCall->setType(ArgTyA);
1122 break;
1123 }
1124 // Note these are llvm builtins that we want to catch invalid intrinsic
1125 // generation. Normal handling of these builitns will occur elsewhere.
1126 case Builtin::BI__builtin_elementwise_bitreverse: {
1128 return true;
1129 break;
1130 }
1131 case Builtin::BI__builtin_elementwise_acos:
1132 case Builtin::BI__builtin_elementwise_asin:
1133 case Builtin::BI__builtin_elementwise_atan:
1134 case Builtin::BI__builtin_elementwise_ceil:
1135 case Builtin::BI__builtin_elementwise_cos:
1136 case Builtin::BI__builtin_elementwise_cosh:
1137 case Builtin::BI__builtin_elementwise_exp:
1138 case Builtin::BI__builtin_elementwise_exp2:
1139 case Builtin::BI__builtin_elementwise_floor:
1140 case Builtin::BI__builtin_elementwise_log:
1141 case Builtin::BI__builtin_elementwise_log2:
1142 case Builtin::BI__builtin_elementwise_log10:
1143 case Builtin::BI__builtin_elementwise_pow:
1144 case Builtin::BI__builtin_elementwise_roundeven:
1145 case Builtin::BI__builtin_elementwise_sin:
1146 case Builtin::BI__builtin_elementwise_sinh:
1147 case Builtin::BI__builtin_elementwise_sqrt:
1148 case Builtin::BI__builtin_elementwise_tan:
1149 case Builtin::BI__builtin_elementwise_tanh:
1150 case Builtin::BI__builtin_elementwise_trunc: {
1152 return true;
1153 break;
1154 }
1155 }
1156 return false;
1157}
const Decl * D
StringRef Identifier
Definition: Format.cpp:3009
const Environment & Env
Definition: HTMLLogger.cpp:148
#define X(type, name)
Definition: Value.h:143
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
bool CheckNoDoubleVectors(Sema *S, CallExpr *TheCall)
Definition: SemaHLSL.cpp:989
bool CheckUnsignedIntRepresentation(Sema *S, CallExpr *TheCall)
Definition: SemaHLSL.cpp:999
bool CheckVectorElementCallArgs(Sema *S, CallExpr *TheCall)
Definition: SemaHLSL.cpp:901
static bool isLegalTypeForHLSLSV_DispatchThreadID(QualType T)
Definition: SemaHLSL.cpp:351
bool CheckFloatOrHalfRepresentations(Sema *S, CallExpr *TheCall)
Definition: SemaHLSL.cpp:977
bool CheckAllArgsHaveFloatRepresentation(Sema *S, CallExpr *TheCall)
Definition: SemaHLSL.cpp:969
static unsigned calculateLegacyCbufferSize(const ASTContext &Context, QualType T)
Definition: SemaHLSL.cpp:49
void SetElementTypeAsReturnType(Sema *S, CallExpr *TheCall, QualType ReturnType)
Definition: SemaHLSL.cpp:1007
bool CheckArgsTypesAreCorrect(Sema *S, CallExpr *TheCall, QualType ExpectedType, llvm::function_ref< bool(clang::QualType PassedType)> Check)
Definition: SemaHLSL.cpp:951
This file declares semantic analysis for HLSL constructs.
SourceRange Range
Definition: SemaObjC.cpp:758
SourceLocation Loc
Definition: SemaObjC.cpp:759
SourceLocation Begin
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:187
const ConstantArrayType * getAsConstantArrayType(QualType T) const
Definition: ASTContext.h:2825
CanQualType FloatTy
Definition: ASTContext.h:1131
QualType getVectorType(QualType VectorType, unsigned NumElts, VectorKind VecKind) const
Return the unique reference to a vector type of the specified element type and size.
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
Definition: ASTContext.h:2394
CanQualType UnsignedIntTy
Definition: ASTContext.h:1129
const TargetInfo & getTargetInfo() const
Definition: ASTContext.h:779
unsigned getTypeAlign(QualType T) const
Return the ABI-specified alignment of a (complete) type T, in bits.
Definition: ASTContext.h:2425
PtrTy get() const
Definition: Ownership.h:170
Attr - This represents one attribute.
Definition: Attr.h:42
attr::Kind getKind() const
Definition: Attr.h:88
SourceLocation getLoc() const
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2830
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: Expr.h:3021
SourceLocation getBeginLoc() const LLVM_READONLY
Definition: Expr.cpp:1638
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Definition: Expr.h:3000
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition: Expr.h:3008
Represents the canonical version of C arrays with a specified constant size.
Definition: Type.h:3604
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition: DeclBase.h:1436
decl_range decls() const
decls_begin/decls_end - Iterate over the declarations stored in this context.
Definition: DeclBase.h:2350
A reference to a declared variable, function, enum, etc.
Definition: Expr.h:1265
ValueDecl * getDecl()
Definition: Expr.h:1333
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
T * getAttr() const
Definition: DeclBase.h:580
void addAttr(Attr *A)
Definition: DeclBase.cpp:1013
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
Definition: DeclBase.h:600
void setInvalidDecl(bool Invalid=true)
setInvalidDecl - Indicates the Decl had a semantic error.
Definition: DeclBase.cpp:154
bool isInExportDeclContext() const
Whether this declaration was exported in a lexical context.
Definition: DeclBase.cpp:1112
SourceLocation getLocation() const
Definition: DeclBase.h:446
DeclContext * getDeclContext()
Definition: DeclBase.h:455
attr_range attrs() const
Definition: DeclBase.h:542
void dropAttr()
Definition: DeclBase.h:563
bool hasAttr() const
Definition: DeclBase.h:584
SourceLocation getBeginLoc() const LLVM_READONLY
Definition: Decl.h:783
This represents one expression.
Definition: Expr.h:110
void setType(QualType t)
Definition: Expr.h:143
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition: Expr.cpp:277
QualType getType() const
Definition: Expr.h:142
Represents a member of a struct/union/class.
Definition: Decl.h:3030
Represents a function declaration or definition.
Definition: Decl.h:1932
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
Definition: Decl.cpp:3224
bool isThisDeclarationADefinition() const
Returns whether this specific declaration of the function is also a definition that does not contain ...
Definition: Decl.h:2246
ArrayRef< ParmVarDecl * > parameters() const
Definition: Decl.h:2646
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
Definition: Decl.cpp:3144
HLSLBufferDecl - Represent a cbuffer or tbuffer declaration.
Definition: Decl.h:4924
static HLSLBufferDecl * Create(ASTContext &C, DeclContext *LexicalParent, bool CBuffer, SourceLocation KwLoc, IdentifierInfo *ID, SourceLocation IDLoc, SourceLocation LBrace)
Definition: Decl.cpp:5643
One of these records is kept for each identifier that is lexed.
StringRef getName() const
Return the actual identifier string.
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition: Expr.h:3187
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
Definition: Expr.h:3270
This represents a decl that may have a name.
Definition: Decl.h:249
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition: Decl.h:276
Represents a parameter to a function.
Definition: Decl.h:1722
ParsedAttr - Represents a syntactic attribute.
Definition: ParsedAttr.h:129
unsigned getSemanticSpelling() const
If the parsed attribute has a semantic equivalent, and it would have a semantic Spelling enumeration ...
Definition: ParsedAttr.cpp:262
IdentifierLoc * getArgAsIdent(unsigned Arg) const
Definition: ParsedAttr.h:406
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this attribute.
Definition: ParsedAttr.h:386
bool isArgIdent(unsigned Arg) const
Definition: ParsedAttr.h:402
Expr * getArgAsExpr(unsigned Arg) const
Definition: ParsedAttr.h:398
A (possibly-)qualified type.
Definition: Type.h:941
Represents a struct/union/class.
Definition: Decl.h:4145
field_range fields() const
Definition: Decl.h:4351
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
Definition: Type.h:5965
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
redecl_range redecls() const
Returns an iterator range for all the redeclarations of the same decl.
Definition: Redeclarable.h:297
Scope - A scope is a transient data structure that is used while parsing the program.
Definition: Scope.h:41
SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID, bool DeferHint=false)
Emit a diagnostic.
Definition: SemaBase.cpp:60
ASTContext & getASTContext() const
Definition: SemaBase.cpp:9
Sema & SemaRef
Definition: SemaBase.h:40
void handleResourceClassAttr(Decl *D, const ParsedAttr &AL)
Definition: SemaHLSL.cpp:440
void DiagnoseAttrStageMismatch(const Attr *A, llvm::Triple::EnvironmentType Stage, std::initializer_list< llvm::Triple::EnvironmentType > AllowedStages)
Definition: SemaHLSL.cpp:286
void handleShaderAttr(Decl *D, const ParsedAttr &AL)
Definition: SemaHLSL.cpp:420
void handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL)
Definition: SemaHLSL.cpp:359
void CheckEntryPoint(FunctionDecl *FD)
Definition: SemaHLSL.cpp:214
HLSLNumThreadsAttr * mergeNumThreadsAttr(Decl *D, const AttributeCommonInfo &AL, int X, int Y, int Z)
Definition: SemaHLSL.cpp:133
void handlePackOffsetAttr(Decl *D, const ParsedAttr &AL)
Definition: SemaHLSL.cpp:371
void CheckSemanticAnnotation(FunctionDecl *EntryPoint, const Decl *Param, const HLSLAnnotationAttr *AnnotationAttr)
Definition: SemaHLSL.cpp:267
void handleParamModifierAttr(Decl *D, const ParsedAttr &AL)
Definition: SemaHLSL.cpp:533
void handleResourceBindingAttr(Decl *D, const ParsedAttr &AL)
Definition: SemaHLSL.cpp:462
void handleNumThreadsAttr(Decl *D, const ParsedAttr &AL)
Definition: SemaHLSL.cpp:300
void DiagnoseAvailabilityViolations(TranslationUnitDecl *TU)
Definition: SemaHLSL.cpp:887
void ActOnTopLevelFunction(FunctionDecl *FD)
Definition: SemaHLSL.cpp:181
HLSLShaderAttr * mergeShaderAttr(Decl *D, const AttributeCommonInfo &AL, llvm::Triple::EnvironmentType ShaderType)
Definition: SemaHLSL.cpp:148
void ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace)
Definition: SemaHLSL.cpp:82
HLSLParamModifierAttr * mergeParamModifierAttr(Decl *D, const AttributeCommonInfo &AL, HLSLParamModifierAttr::Spelling Spelling)
Definition: SemaHLSL.cpp:161
SemaHLSL(Sema &S)
Definition: SemaHLSL.cpp:30
Decl * ActOnStartBuffer(Scope *BufferScope, bool CBuffer, SourceLocation KwLoc, IdentifierInfo *Ident, SourceLocation IdentLoc, SourceLocation LBrace)
Definition: SemaHLSL.cpp:32
bool CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall)
Definition: SemaHLSL.cpp:1018
Sema - This implements semantic analysis and AST building for C.
Definition: Sema.h:493
ASTContext & Context
Definition: Sema.h:962
void PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext=true)
Add this decl to the scope shadowed decl chains.
Definition: SemaDecl.cpp:1496
ASTContext & getASTContext() const
Definition: Sema.h:560
bool BuiltinVectorToScalarMath(CallExpr *TheCall)
const LangOptions & getLangOpts() const
Definition: Sema.h:553
bool PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall)
DeclContext * getCurLexicalContext() const
Definition: Sema.h:767
bool checkUInt32Argument(const AttrInfo &AI, const Expr *Expr, uint32_t &Val, unsigned Idx=UINT_MAX, bool StrictlyUnsigned=false)
If Expr is a valid integer constant, get the value of the integer expression and return success or fa...
Definition: Sema.h:4434
bool BuiltinElementwiseTernaryMath(CallExpr *TheCall, bool CheckForFloatArgs=true)
bool checkArgCount(CallExpr *Call, unsigned DesiredArgCount)
Checks that a call expression's argument count is the desired number.
void PushDeclContext(Scope *S, DeclContext *DC)
Set the current declaration context until it gets popped.
Definition: SemaDecl.cpp:1307
void PopDeclContext()
Definition: SemaDecl.cpp:1314
bool checkStringLiteralArgumentAttr(const AttributeCommonInfo &CI, const Expr *E, StringRef &Str, SourceLocation *ArgLocation=nullptr)
Check if the argument E is a ASCII string literal.
Encodes a location in the source.
A trivial tuple used to represent a source range.
SourceLocation getEnd() const
SourceLocation getBegin() const
SourceLocation getEndLoc() const LLVM_READONLY
Definition: Stmt.cpp:350
SourceLocation getBeginLoc() const LLVM_READONLY
Definition: Stmt.cpp:338
Exposes information about the current target.
Definition: TargetInfo.h:218
TargetOptions & getTargetOpts() const
Retrieve the target options.
Definition: TargetInfo.h:312
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
Definition: TargetInfo.h:1256
StringRef getPlatformName() const
Retrieve the name of the platform as it is used in the availability attribute.
Definition: TargetInfo.h:1659
VersionTuple getPlatformMinVersion() const
Retrieve the minimum desired version of the platform, to which the program should be compiled.
Definition: TargetInfo.h:1663
std::string HLSLEntry
The entry point name for HLSL shader being compiled as specified by -E.
The top declaration context.
Definition: Decl.h:84
bool isStructureType() const
Definition: Type.cpp:629
bool isArrayType() const
Definition: Type.h:8075
bool hasUnsignedIntegerRepresentation() const
Determine whether this type has an unsigned integer representation of some sort, e....
Definition: Type.cpp:2236
bool isAggregateType() const
Determines whether the type is a C++ aggregate type or C aggregate or union type.
Definition: Type.cpp:2338
bool isFloat32Type() const
Definition: Type.h:8332
bool isHalfType() const
Definition: Type.h:8323
bool hasFloatingRepresentation() const
Determine whether this type has a floating-point representation of some sort, e.g....
Definition: Type.cpp:2258
bool isVectorType() const
Definition: Type.h:8115
const T * getAs() const
Member-template getAs<specific type>'.
Definition: Type.h:8540
QualType getType() const
Definition: Decl.h:678
Represents a variable declaration or definition.
Definition: Decl.h:879
Represents a GCC generic vector type.
Definition: Type.h:4021
Defines the clang::TargetInfo interface.
The JSON file list parser is used to communicate input to InstallAPI.
@ AANT_ArgumentIdentifier
Definition: ParsedAttr.h:1083
@ Result
The result type of a method or function.
const FunctionProtoType * T
@ Generic
not a target-specific vector type
Diagnostic wrappers for TextAPI types for error reporting.
Definition: Dominators.h:30
#define false
Definition: stdbool.h:26
Wraps an identifier and optional source location for the identifier.
Definition: ParsedAttr.h:103