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"
13#include "clang/AST/Attr.h"
14#include "clang/AST/Attrs.inc"
15#include "clang/AST/Decl.h"
16#include "clang/AST/DeclBase.h"
17#include "clang/AST/DeclCXX.h"
19#include "clang/AST/Expr.h"
20#include "clang/AST/Type.h"
21#include "clang/AST/TypeLoc.h"
24#include "clang/Basic/LLVM.h"
29#include "clang/Sema/Sema.h"
30#include "clang/Sema/Template.h"
31#include "llvm/ADT/STLExtras.h"
32#include "llvm/ADT/SmallVector.h"
33#include "llvm/ADT/StringExtras.h"
34#include "llvm/ADT/StringRef.h"
35#include "llvm/Support/Casting.h"
36#include "llvm/Support/DXILABI.h"
37#include "llvm/Support/ErrorHandling.h"
38#include "llvm/TargetParser/Triple.h"
39#include <iterator>
40#include <utility>
41
42using namespace clang;
43using RegisterType = HLSLResourceBindingAttr::RegisterType;
44
45static RegisterType getRegisterType(ResourceClass RC) {
46 switch (RC) {
47 case ResourceClass::SRV:
48 return RegisterType::SRV;
49 case ResourceClass::UAV:
50 return RegisterType::UAV;
51 case ResourceClass::CBuffer:
52 return RegisterType::CBuffer;
53 case ResourceClass::Sampler:
54 return RegisterType::Sampler;
55 }
56 llvm_unreachable("unexpected ResourceClass value");
57}
58
59// Converts the first letter of string Slot to RegisterType.
60// Returns false if the letter does not correspond to a valid register type.
61static bool convertToRegisterType(StringRef Slot, RegisterType *RT) {
62 assert(RT != nullptr);
63 switch (Slot[0]) {
64 case 't':
65 case 'T':
66 *RT = RegisterType::SRV;
67 return true;
68 case 'u':
69 case 'U':
70 *RT = RegisterType::UAV;
71 return true;
72 case 'b':
73 case 'B':
74 *RT = RegisterType::CBuffer;
75 return true;
76 case 's':
77 case 'S':
78 *RT = RegisterType::Sampler;
79 return true;
80 case 'c':
81 case 'C':
82 *RT = RegisterType::C;
83 return true;
84 case 'i':
85 case 'I':
86 *RT = RegisterType::I;
87 return true;
88 default:
89 return false;
90 }
91}
92
93static ResourceClass getResourceClass(RegisterType RT) {
94 switch (RT) {
95 case RegisterType::SRV:
96 return ResourceClass::SRV;
97 case RegisterType::UAV:
98 return ResourceClass::UAV;
99 case RegisterType::CBuffer:
100 return ResourceClass::CBuffer;
101 case RegisterType::Sampler:
102 return ResourceClass::Sampler;
103 case RegisterType::C:
104 case RegisterType::I:
105 // Deliberately falling through to the unreachable below.
106 break;
107 }
108 llvm_unreachable("unexpected RegisterType value");
109}
110
112 ResourceClass ResClass) {
113 assert(getDeclBindingInfo(VD, ResClass) == nullptr &&
114 "DeclBindingInfo already added");
115 assert(!hasBindingInfoForDecl(VD) || BindingsList.back().Decl == VD);
116 // VarDecl may have multiple entries for different resource classes.
117 // DeclToBindingListIndex stores the index of the first binding we saw
118 // for this decl. If there are any additional ones then that index
119 // shouldn't be updated.
120 DeclToBindingListIndex.try_emplace(VD, BindingsList.size());
121 return &BindingsList.emplace_back(VD, ResClass);
122}
123
125 ResourceClass ResClass) {
126 auto Entry = DeclToBindingListIndex.find(VD);
127 if (Entry != DeclToBindingListIndex.end()) {
128 for (unsigned Index = Entry->getSecond();
129 Index < BindingsList.size() && BindingsList[Index].Decl == VD;
130 ++Index) {
131 if (BindingsList[Index].ResClass == ResClass)
132 return &BindingsList[Index];
133 }
134 }
135 return nullptr;
136}
137
139 return DeclToBindingListIndex.contains(VD);
140}
141
143
144Decl *SemaHLSL::ActOnStartBuffer(Scope *BufferScope, bool CBuffer,
145 SourceLocation KwLoc, IdentifierInfo *Ident,
146 SourceLocation IdentLoc,
147 SourceLocation LBrace) {
148 // For anonymous namespace, take the location of the left brace.
149 DeclContext *LexicalParent = SemaRef.getCurLexicalContext();
151 getASTContext(), LexicalParent, CBuffer, KwLoc, Ident, IdentLoc, LBrace);
152
153 // if CBuffer is false, then it's a TBuffer
154 auto RC = CBuffer ? llvm::hlsl::ResourceClass::CBuffer
155 : llvm::hlsl::ResourceClass::SRV;
156 auto RK = CBuffer ? llvm::hlsl::ResourceKind::CBuffer
157 : llvm::hlsl::ResourceKind::TBuffer;
158 Result->addAttr(HLSLResourceClassAttr::CreateImplicit(getASTContext(), RC));
159 Result->addAttr(HLSLResourceAttr::CreateImplicit(getASTContext(), RK));
160
161 SemaRef.PushOnScopeChains(Result, BufferScope);
162 SemaRef.PushDeclContext(BufferScope, Result);
163
164 return Result;
165}
166
167// Calculate the size of a legacy cbuffer type in bytes based on
168// https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-packing-rules
169static unsigned calculateLegacyCbufferSize(const ASTContext &Context,
170 QualType T) {
171 unsigned Size = 0;
172 constexpr unsigned CBufferAlign = 16;
173 if (const RecordType *RT = T->getAs<RecordType>()) {
174 const RecordDecl *RD = RT->getDecl();
175 for (const FieldDecl *Field : RD->fields()) {
176 QualType Ty = Field->getType();
177 unsigned FieldSize = calculateLegacyCbufferSize(Context, Ty);
178 // FIXME: This is not the correct alignment, it does not work for 16-bit
179 // types. See llvm/llvm-project#119641.
180 unsigned FieldAlign = 4;
181 if (Ty->isAggregateType())
182 FieldAlign = CBufferAlign;
183 Size = llvm::alignTo(Size, FieldAlign);
184 Size += FieldSize;
185 }
186 } else if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) {
187 if (unsigned ElementCount = AT->getSize().getZExtValue()) {
188 unsigned ElementSize =
189 calculateLegacyCbufferSize(Context, AT->getElementType());
190 unsigned AlignedElementSize = llvm::alignTo(ElementSize, CBufferAlign);
191 Size = AlignedElementSize * (ElementCount - 1) + ElementSize;
192 }
193 } else if (const VectorType *VT = T->getAs<VectorType>()) {
194 unsigned ElementCount = VT->getNumElements();
195 unsigned ElementSize =
196 calculateLegacyCbufferSize(Context, VT->getElementType());
197 Size = ElementSize * ElementCount;
198 } else {
199 Size = Context.getTypeSize(T) / 8;
200 }
201 return Size;
202}
203
204// Validate packoffset:
205// - if packoffset it used it must be set on all declarations inside the buffer
206// - packoffset ranges must not overlap
207static void validatePackoffset(Sema &S, HLSLBufferDecl *BufDecl) {
209
210 // Make sure the packoffset annotations are either on all declarations
211 // or on none.
212 bool HasPackOffset = false;
213 bool HasNonPackOffset = false;
214 for (auto *Field : BufDecl->decls()) {
215 VarDecl *Var = dyn_cast<VarDecl>(Field);
216 if (!Var)
217 continue;
218 if (Field->hasAttr<HLSLPackOffsetAttr>()) {
219 PackOffsetVec.emplace_back(Var, Field->getAttr<HLSLPackOffsetAttr>());
220 HasPackOffset = true;
221 } else {
222 HasNonPackOffset = true;
223 }
224 }
225
226 if (!HasPackOffset)
227 return;
228
229 if (HasNonPackOffset)
230 S.Diag(BufDecl->getLocation(), diag::warn_hlsl_packoffset_mix);
231
232 // Make sure there is no overlap in packoffset - sort PackOffsetVec by offset
233 // and compare adjacent values.
234 ASTContext &Context = S.getASTContext();
235 std::sort(PackOffsetVec.begin(), PackOffsetVec.end(),
236 [](const std::pair<VarDecl *, HLSLPackOffsetAttr *> &LHS,
237 const std::pair<VarDecl *, HLSLPackOffsetAttr *> &RHS) {
238 return LHS.second->getOffsetInBytes() <
239 RHS.second->getOffsetInBytes();
240 });
241 for (unsigned i = 0; i < PackOffsetVec.size() - 1; i++) {
242 VarDecl *Var = PackOffsetVec[i].first;
243 HLSLPackOffsetAttr *Attr = PackOffsetVec[i].second;
244 unsigned Size = calculateLegacyCbufferSize(Context, Var->getType());
245 unsigned Begin = Attr->getOffsetInBytes();
246 unsigned End = Begin + Size;
247 unsigned NextBegin = PackOffsetVec[i + 1].second->getOffsetInBytes();
248 if (End > NextBegin) {
249 VarDecl *NextVar = PackOffsetVec[i + 1].first;
250 S.Diag(NextVar->getLocation(), diag::err_hlsl_packoffset_overlap)
251 << NextVar << Var;
252 }
253 }
254}
255
257 auto *BufDecl = cast<HLSLBufferDecl>(Dcl);
258 BufDecl->setRBraceLoc(RBrace);
259
260 validatePackoffset(SemaRef, BufDecl);
261
263}
264
266 const AttributeCommonInfo &AL,
267 int X, int Y, int Z) {
268 if (HLSLNumThreadsAttr *NT = D->getAttr<HLSLNumThreadsAttr>()) {
269 if (NT->getX() != X || NT->getY() != Y || NT->getZ() != Z) {
270 Diag(NT->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL;
271 Diag(AL.getLoc(), diag::note_conflicting_attribute);
272 }
273 return nullptr;
274 }
275 return ::new (getASTContext())
276 HLSLNumThreadsAttr(getASTContext(), AL, X, Y, Z);
277}
278
280 const AttributeCommonInfo &AL,
281 int Min, int Max, int Preferred,
282 int SpelledArgsCount) {
283 if (HLSLWaveSizeAttr *WS = D->getAttr<HLSLWaveSizeAttr>()) {
284 if (WS->getMin() != Min || WS->getMax() != Max ||
285 WS->getPreferred() != Preferred ||
286 WS->getSpelledArgsCount() != SpelledArgsCount) {
287 Diag(WS->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL;
288 Diag(AL.getLoc(), diag::note_conflicting_attribute);
289 }
290 return nullptr;
291 }
292 HLSLWaveSizeAttr *Result = ::new (getASTContext())
293 HLSLWaveSizeAttr(getASTContext(), AL, Min, Max, Preferred);
294 Result->setSpelledArgsCount(SpelledArgsCount);
295 return Result;
296}
297
298HLSLShaderAttr *
300 llvm::Triple::EnvironmentType ShaderType) {
301 if (HLSLShaderAttr *NT = D->getAttr<HLSLShaderAttr>()) {
302 if (NT->getType() != ShaderType) {
303 Diag(NT->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL;
304 Diag(AL.getLoc(), diag::note_conflicting_attribute);
305 }
306 return nullptr;
307 }
308 return HLSLShaderAttr::Create(getASTContext(), ShaderType, AL);
309}
310
311HLSLParamModifierAttr *
313 HLSLParamModifierAttr::Spelling Spelling) {
314 // We can only merge an `in` attribute with an `out` attribute. All other
315 // combinations of duplicated attributes are ill-formed.
316 if (HLSLParamModifierAttr *PA = D->getAttr<HLSLParamModifierAttr>()) {
317 if ((PA->isIn() && Spelling == HLSLParamModifierAttr::Keyword_out) ||
318 (PA->isOut() && Spelling == HLSLParamModifierAttr::Keyword_in)) {
319 D->dropAttr<HLSLParamModifierAttr>();
320 SourceRange AdjustedRange = {PA->getLocation(), AL.getRange().getEnd()};
321 return HLSLParamModifierAttr::Create(
322 getASTContext(), /*MergedSpelling=*/true, AdjustedRange,
323 HLSLParamModifierAttr::Keyword_inout);
324 }
325 Diag(AL.getLoc(), diag::err_hlsl_duplicate_parameter_modifier) << AL;
326 Diag(PA->getLocation(), diag::note_conflicting_attribute);
327 return nullptr;
328 }
329 return HLSLParamModifierAttr::Create(getASTContext(), AL);
330}
331
334
336 return;
337
338 llvm::Triple::EnvironmentType Env = TargetInfo.getTriple().getEnvironment();
339 if (HLSLShaderAttr::isValidShaderType(Env) && Env != llvm::Triple::Library) {
340 if (const auto *Shader = FD->getAttr<HLSLShaderAttr>()) {
341 // The entry point is already annotated - check that it matches the
342 // triple.
343 if (Shader->getType() != Env) {
344 Diag(Shader->getLocation(), diag::err_hlsl_entry_shader_attr_mismatch)
345 << Shader;
346 FD->setInvalidDecl();
347 }
348 } else {
349 // Implicitly add the shader attribute if the entry function isn't
350 // explicitly annotated.
351 FD->addAttr(HLSLShaderAttr::CreateImplicit(getASTContext(), Env,
352 FD->getBeginLoc()));
353 }
354 } else {
355 switch (Env) {
356 case llvm::Triple::UnknownEnvironment:
357 case llvm::Triple::Library:
358 break;
359 default:
360 llvm_unreachable("Unhandled environment in triple");
361 }
362 }
363}
364
366 const auto *ShaderAttr = FD->getAttr<HLSLShaderAttr>();
367 assert(ShaderAttr && "Entry point has no shader attribute");
368 llvm::Triple::EnvironmentType ST = ShaderAttr->getType();
370 VersionTuple Ver = TargetInfo.getTriple().getOSVersion();
371 switch (ST) {
372 case llvm::Triple::Pixel:
373 case llvm::Triple::Vertex:
374 case llvm::Triple::Geometry:
375 case llvm::Triple::Hull:
376 case llvm::Triple::Domain:
377 case llvm::Triple::RayGeneration:
378 case llvm::Triple::Intersection:
379 case llvm::Triple::AnyHit:
380 case llvm::Triple::ClosestHit:
381 case llvm::Triple::Miss:
382 case llvm::Triple::Callable:
383 if (const auto *NT = FD->getAttr<HLSLNumThreadsAttr>()) {
385 {llvm::Triple::Compute,
386 llvm::Triple::Amplification,
387 llvm::Triple::Mesh});
388 FD->setInvalidDecl();
389 }
390 if (const auto *WS = FD->getAttr<HLSLWaveSizeAttr>()) {
392 {llvm::Triple::Compute,
393 llvm::Triple::Amplification,
394 llvm::Triple::Mesh});
395 FD->setInvalidDecl();
396 }
397 break;
398
399 case llvm::Triple::Compute:
400 case llvm::Triple::Amplification:
401 case llvm::Triple::Mesh:
402 if (!FD->hasAttr<HLSLNumThreadsAttr>()) {
403 Diag(FD->getLocation(), diag::err_hlsl_missing_numthreads)
404 << llvm::Triple::getEnvironmentTypeName(ST);
405 FD->setInvalidDecl();
406 }
407 if (const auto *WS = FD->getAttr<HLSLWaveSizeAttr>()) {
408 if (Ver < VersionTuple(6, 6)) {
409 Diag(WS->getLocation(), diag::err_hlsl_attribute_in_wrong_shader_model)
410 << WS << "6.6";
411 FD->setInvalidDecl();
412 } else if (WS->getSpelledArgsCount() > 1 && Ver < VersionTuple(6, 8)) {
413 Diag(
414 WS->getLocation(),
415 diag::err_hlsl_attribute_number_arguments_insufficient_shader_model)
416 << WS << WS->getSpelledArgsCount() << "6.8";
417 FD->setInvalidDecl();
418 }
419 }
420 break;
421 default:
422 llvm_unreachable("Unhandled environment in triple");
423 }
424
425 for (ParmVarDecl *Param : FD->parameters()) {
426 if (const auto *AnnotationAttr = Param->getAttr<HLSLAnnotationAttr>()) {
427 CheckSemanticAnnotation(FD, Param, AnnotationAttr);
428 } else {
429 // FIXME: Handle struct parameters where annotations are on struct fields.
430 // See: https://github.com/llvm/llvm-project/issues/57875
431 Diag(FD->getLocation(), diag::err_hlsl_missing_semantic_annotation);
432 Diag(Param->getLocation(), diag::note_previous_decl) << Param;
433 FD->setInvalidDecl();
434 }
435 }
436 // FIXME: Verify return type semantic annotation.
437}
438
440 FunctionDecl *EntryPoint, const Decl *Param,
441 const HLSLAnnotationAttr *AnnotationAttr) {
442 auto *ShaderAttr = EntryPoint->getAttr<HLSLShaderAttr>();
443 assert(ShaderAttr && "Entry point has no shader attribute");
444 llvm::Triple::EnvironmentType ST = ShaderAttr->getType();
445
446 switch (AnnotationAttr->getKind()) {
447 case attr::HLSLSV_DispatchThreadID:
448 case attr::HLSLSV_GroupIndex:
449 case attr::HLSLSV_GroupThreadID:
450 case attr::HLSLSV_GroupID:
451 if (ST == llvm::Triple::Compute)
452 return;
453 DiagnoseAttrStageMismatch(AnnotationAttr, ST, {llvm::Triple::Compute});
454 break;
455 default:
456 llvm_unreachable("Unknown HLSLAnnotationAttr");
457 }
458}
459
461 const Attr *A, llvm::Triple::EnvironmentType Stage,
462 std::initializer_list<llvm::Triple::EnvironmentType> AllowedStages) {
463 SmallVector<StringRef, 8> StageStrings;
464 llvm::transform(AllowedStages, std::back_inserter(StageStrings),
465 [](llvm::Triple::EnvironmentType ST) {
466 return StringRef(
467 HLSLShaderAttr::ConvertEnvironmentTypeToStr(ST));
468 });
469 Diag(A->getLoc(), diag::err_hlsl_attr_unsupported_in_stage)
470 << A << llvm::Triple::getEnvironmentTypeName(Stage)
471 << (AllowedStages.size() != 1) << join(StageStrings, ", ");
472}
473
474template <CastKind Kind>
475static void castVector(Sema &S, ExprResult &E, QualType &Ty, unsigned Sz) {
476 if (const auto *VTy = Ty->getAs<VectorType>())
477 Ty = VTy->getElementType();
478 Ty = S.getASTContext().getExtVectorType(Ty, Sz);
479 E = S.ImpCastExprToType(E.get(), Ty, Kind);
480}
481
482template <CastKind Kind>
484 E = S.ImpCastExprToType(E.get(), Ty, Kind);
485 return Ty;
486}
487
489 Sema &SemaRef, ExprResult &LHS, ExprResult &RHS, QualType LHSType,
490 QualType RHSType, QualType LElTy, QualType RElTy, bool IsCompAssign) {
491 bool LHSFloat = LElTy->isRealFloatingType();
492 bool RHSFloat = RElTy->isRealFloatingType();
493
494 if (LHSFloat && RHSFloat) {
495 if (IsCompAssign ||
496 SemaRef.getASTContext().getFloatingTypeOrder(LElTy, RElTy) > 0)
497 return castElement<CK_FloatingCast>(SemaRef, RHS, LHSType);
498
499 return castElement<CK_FloatingCast>(SemaRef, LHS, RHSType);
500 }
501
502 if (LHSFloat)
503 return castElement<CK_IntegralToFloating>(SemaRef, RHS, LHSType);
504
505 assert(RHSFloat);
506 if (IsCompAssign)
507 return castElement<clang::CK_FloatingToIntegral>(SemaRef, RHS, LHSType);
508
509 return castElement<CK_IntegralToFloating>(SemaRef, LHS, RHSType);
510}
511
513 Sema &SemaRef, ExprResult &LHS, ExprResult &RHS, QualType LHSType,
514 QualType RHSType, QualType LElTy, QualType RElTy, bool IsCompAssign) {
515
516 int IntOrder = SemaRef.Context.getIntegerTypeOrder(LElTy, RElTy);
517 bool LHSSigned = LElTy->hasSignedIntegerRepresentation();
518 bool RHSSigned = RElTy->hasSignedIntegerRepresentation();
519 auto &Ctx = SemaRef.getASTContext();
520
521 // If both types have the same signedness, use the higher ranked type.
522 if (LHSSigned == RHSSigned) {
523 if (IsCompAssign || IntOrder >= 0)
524 return castElement<CK_IntegralCast>(SemaRef, RHS, LHSType);
525
526 return castElement<CK_IntegralCast>(SemaRef, LHS, RHSType);
527 }
528
529 // If the unsigned type has greater than or equal rank of the signed type, use
530 // the unsigned type.
531 if (IntOrder != (LHSSigned ? 1 : -1)) {
532 if (IsCompAssign || RHSSigned)
533 return castElement<CK_IntegralCast>(SemaRef, RHS, LHSType);
534 return castElement<CK_IntegralCast>(SemaRef, LHS, RHSType);
535 }
536
537 // At this point the signed type has higher rank than the unsigned type, which
538 // means it will be the same size or bigger. If the signed type is bigger, it
539 // can represent all the values of the unsigned type, so select it.
540 if (Ctx.getIntWidth(LElTy) != Ctx.getIntWidth(RElTy)) {
541 if (IsCompAssign || LHSSigned)
542 return castElement<CK_IntegralCast>(SemaRef, RHS, LHSType);
543 return castElement<CK_IntegralCast>(SemaRef, LHS, RHSType);
544 }
545
546 // This is a bit of an odd duck case in HLSL. It shouldn't happen, but can due
547 // to C/C++ leaking through. The place this happens today is long vs long
548 // long. When arguments are vector<unsigned long, N> and vector<long long, N>,
549 // the long long has higher rank than long even though they are the same size.
550
551 // If this is a compound assignment cast the right hand side to the left hand
552 // side's type.
553 if (IsCompAssign)
554 return castElement<CK_IntegralCast>(SemaRef, RHS, LHSType);
555
556 // If this isn't a compound assignment we convert to unsigned long long.
557 QualType ElTy = Ctx.getCorrespondingUnsignedType(LHSSigned ? LElTy : RElTy);
558 QualType NewTy = Ctx.getExtVectorType(
559 ElTy, RHSType->castAs<VectorType>()->getNumElements());
560 (void)castElement<CK_IntegralCast>(SemaRef, RHS, NewTy);
561
562 return castElement<CK_IntegralCast>(SemaRef, LHS, NewTy);
563}
564
566 QualType SrcTy) {
567 if (DestTy->isRealFloatingType() && SrcTy->isRealFloatingType())
568 return CK_FloatingCast;
569 if (DestTy->isIntegralType(Ctx) && SrcTy->isIntegralType(Ctx))
570 return CK_IntegralCast;
571 if (DestTy->isRealFloatingType())
572 return CK_IntegralToFloating;
573 assert(SrcTy->isRealFloatingType() && DestTy->isIntegralType(Ctx));
574 return CK_FloatingToIntegral;
575}
576
578 QualType LHSType,
579 QualType RHSType,
580 bool IsCompAssign) {
581 const auto *LVecTy = LHSType->getAs<VectorType>();
582 const auto *RVecTy = RHSType->getAs<VectorType>();
583 auto &Ctx = getASTContext();
584
585 // If the LHS is not a vector and this is a compound assignment, we truncate
586 // the argument to a scalar then convert it to the LHS's type.
587 if (!LVecTy && IsCompAssign) {
588 QualType RElTy = RHSType->castAs<VectorType>()->getElementType();
589 RHS = SemaRef.ImpCastExprToType(RHS.get(), RElTy, CK_HLSLVectorTruncation);
590 RHSType = RHS.get()->getType();
591 if (Ctx.hasSameUnqualifiedType(LHSType, RHSType))
592 return LHSType;
593 RHS = SemaRef.ImpCastExprToType(RHS.get(), LHSType,
594 getScalarCastKind(Ctx, LHSType, RHSType));
595 return LHSType;
596 }
597
598 unsigned EndSz = std::numeric_limits<unsigned>::max();
599 unsigned LSz = 0;
600 if (LVecTy)
601 LSz = EndSz = LVecTy->getNumElements();
602 if (RVecTy)
603 EndSz = std::min(RVecTy->getNumElements(), EndSz);
604 assert(EndSz != std::numeric_limits<unsigned>::max() &&
605 "one of the above should have had a value");
606
607 // In a compound assignment, the left operand does not change type, the right
608 // operand is converted to the type of the left operand.
609 if (IsCompAssign && LSz != EndSz) {
610 Diag(LHS.get()->getBeginLoc(),
611 diag::err_hlsl_vector_compound_assignment_truncation)
612 << LHSType << RHSType;
613 return QualType();
614 }
615
616 if (RVecTy && RVecTy->getNumElements() > EndSz)
617 castVector<CK_HLSLVectorTruncation>(SemaRef, RHS, RHSType, EndSz);
618 if (!IsCompAssign && LVecTy && LVecTy->getNumElements() > EndSz)
619 castVector<CK_HLSLVectorTruncation>(SemaRef, LHS, LHSType, EndSz);
620
621 if (!RVecTy)
622 castVector<CK_VectorSplat>(SemaRef, RHS, RHSType, EndSz);
623 if (!IsCompAssign && !LVecTy)
624 castVector<CK_VectorSplat>(SemaRef, LHS, LHSType, EndSz);
625
626 // If we're at the same type after resizing we can stop here.
627 if (Ctx.hasSameUnqualifiedType(LHSType, RHSType))
628 return Ctx.getCommonSugaredType(LHSType, RHSType);
629
630 QualType LElTy = LHSType->castAs<VectorType>()->getElementType();
631 QualType RElTy = RHSType->castAs<VectorType>()->getElementType();
632
633 // Handle conversion for floating point vectors.
634 if (LElTy->isRealFloatingType() || RElTy->isRealFloatingType())
635 return handleFloatVectorBinOpConversion(SemaRef, LHS, RHS, LHSType, RHSType,
636 LElTy, RElTy, IsCompAssign);
637
638 assert(LElTy->isIntegralType(Ctx) && RElTy->isIntegralType(Ctx) &&
639 "HLSL Vectors can only contain integer or floating point types");
640 return handleIntegerVectorBinOpConversion(SemaRef, LHS, RHS, LHSType, RHSType,
641 LElTy, RElTy, IsCompAssign);
642}
643
645 BinaryOperatorKind Opc) {
646 assert((Opc == BO_LOr || Opc == BO_LAnd) &&
647 "Called with non-logical operator");
649 llvm::raw_svector_ostream OS(Buff);
651 StringRef NewFnName = Opc == BO_LOr ? "or" : "and";
652 OS << NewFnName << "(";
653 LHS->printPretty(OS, nullptr, PP);
654 OS << ", ";
655 RHS->printPretty(OS, nullptr, PP);
656 OS << ")";
657 SourceRange FullRange = SourceRange(LHS->getBeginLoc(), RHS->getEndLoc());
658 SemaRef.Diag(LHS->getBeginLoc(), diag::note_function_suggestion)
659 << NewFnName << FixItHint::CreateReplacement(FullRange, OS.str());
660}
661
663 llvm::VersionTuple SMVersion =
664 getASTContext().getTargetInfo().getTriple().getOSVersion();
665 uint32_t ZMax = 1024;
666 uint32_t ThreadMax = 1024;
667 if (SMVersion.getMajor() <= 4) {
668 ZMax = 1;
669 ThreadMax = 768;
670 } else if (SMVersion.getMajor() == 5) {
671 ZMax = 64;
672 ThreadMax = 1024;
673 }
674
675 uint32_t X;
676 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), X))
677 return;
678 if (X > 1024) {
680 diag::err_hlsl_numthreads_argument_oor)
681 << 0 << 1024;
682 return;
683 }
684 uint32_t Y;
685 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Y))
686 return;
687 if (Y > 1024) {
689 diag::err_hlsl_numthreads_argument_oor)
690 << 1 << 1024;
691 return;
692 }
693 uint32_t Z;
694 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(2), Z))
695 return;
696 if (Z > ZMax) {
698 diag::err_hlsl_numthreads_argument_oor)
699 << 2 << ZMax;
700 return;
701 }
702
703 if (X * Y * Z > ThreadMax) {
704 Diag(AL.getLoc(), diag::err_hlsl_numthreads_invalid) << ThreadMax;
705 return;
706 }
707
708 HLSLNumThreadsAttr *NewAttr = mergeNumThreadsAttr(D, AL, X, Y, Z);
709 if (NewAttr)
710 D->addAttr(NewAttr);
711}
712
713static bool isValidWaveSizeValue(unsigned Value) {
714 return llvm::isPowerOf2_32(Value) && Value >= 4 && Value <= 128;
715}
716
718 // validate that the wavesize argument is a power of 2 between 4 and 128
719 // inclusive
720 unsigned SpelledArgsCount = AL.getNumArgs();
721 if (SpelledArgsCount == 0 || SpelledArgsCount > 3)
722 return;
723
724 uint32_t Min;
726 return;
727
728 uint32_t Max = 0;
729 if (SpelledArgsCount > 1 &&
731 return;
732
733 uint32_t Preferred = 0;
734 if (SpelledArgsCount > 2 &&
735 !SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(2), Preferred))
736 return;
737
738 if (SpelledArgsCount > 2) {
739 if (!isValidWaveSizeValue(Preferred)) {
741 diag::err_attribute_power_of_two_in_range)
742 << AL << llvm::dxil::MinWaveSize << llvm::dxil::MaxWaveSize
743 << Preferred;
744 return;
745 }
746 // Preferred not in range.
747 if (Preferred < Min || Preferred > Max) {
749 diag::err_attribute_power_of_two_in_range)
750 << AL << Min << Max << Preferred;
751 return;
752 }
753 } else if (SpelledArgsCount > 1) {
756 diag::err_attribute_power_of_two_in_range)
757 << AL << llvm::dxil::MinWaveSize << llvm::dxil::MaxWaveSize << Max;
758 return;
759 }
760 if (Max < Min) {
761 Diag(AL.getLoc(), diag::err_attribute_argument_invalid) << AL << 1;
762 return;
763 } else if (Max == Min) {
764 Diag(AL.getLoc(), diag::warn_attr_min_eq_max) << AL;
765 }
766 } else {
769 diag::err_attribute_power_of_two_in_range)
770 << AL << llvm::dxil::MinWaveSize << llvm::dxil::MaxWaveSize << Min;
771 return;
772 }
773 }
774
775 HLSLWaveSizeAttr *NewAttr =
776 mergeWaveSizeAttr(D, AL, Min, Max, Preferred, SpelledArgsCount);
777 if (NewAttr)
778 D->addAttr(NewAttr);
779}
780
782 const auto *VT = T->getAs<VectorType>();
783
785 (VT && VT->getNumElements() > 3)) {
786 Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type)
787 << AL << "uint/uint2/uint3";
788 return false;
789 }
790
791 return true;
792}
793
795 auto *VD = cast<ValueDecl>(D);
796 if (!diagnoseInputIDType(VD->getType(), AL))
797 return;
798
799 D->addAttr(::new (getASTContext())
800 HLSLSV_DispatchThreadIDAttr(getASTContext(), AL));
801}
802
804 auto *VD = cast<ValueDecl>(D);
805 if (!diagnoseInputIDType(VD->getType(), AL))
806 return;
807
808 D->addAttr(::new (getASTContext())
809 HLSLSV_GroupThreadIDAttr(getASTContext(), AL));
810}
811
813 auto *VD = cast<ValueDecl>(D);
814 if (!diagnoseInputIDType(VD->getType(), AL))
815 return;
816
817 D->addAttr(::new (getASTContext()) HLSLSV_GroupIDAttr(getASTContext(), AL));
818}
819
821 if (!isa<VarDecl>(D) || !isa<HLSLBufferDecl>(D->getDeclContext())) {
822 Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_ast_node)
823 << AL << "shader constant in a constant buffer";
824 return;
825 }
826
827 uint32_t SubComponent;
828 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(0), SubComponent))
829 return;
830 uint32_t Component;
831 if (!SemaRef.checkUInt32Argument(AL, AL.getArgAsExpr(1), Component))
832 return;
833
834 QualType T = cast<VarDecl>(D)->getType().getCanonicalType();
835 // Check if T is an array or struct type.
836 // TODO: mark matrix type as aggregate type.
837 bool IsAggregateTy = (T->isArrayType() || T->isStructureType());
838
839 // Check Component is valid for T.
840 if (Component) {
841 unsigned Size = getASTContext().getTypeSize(T);
842 if (IsAggregateTy || Size > 128) {
843 Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary);
844 return;
845 } else {
846 // Make sure Component + sizeof(T) <= 4.
847 if ((Component * 32 + Size) > 128) {
848 Diag(AL.getLoc(), diag::err_hlsl_packoffset_cross_reg_boundary);
849 return;
850 }
851 QualType EltTy = T;
852 if (const auto *VT = T->getAs<VectorType>())
853 EltTy = VT->getElementType();
854 unsigned Align = getASTContext().getTypeAlign(EltTy);
855 if (Align > 32 && Component == 1) {
856 // NOTE: Component 3 will hit err_hlsl_packoffset_cross_reg_boundary.
857 // So we only need to check Component 1 here.
858 Diag(AL.getLoc(), diag::err_hlsl_packoffset_alignment_mismatch)
859 << Align << EltTy;
860 return;
861 }
862 }
863 }
864
865 D->addAttr(::new (getASTContext()) HLSLPackOffsetAttr(
866 getASTContext(), AL, SubComponent, Component));
867}
868
870 StringRef Str;
871 SourceLocation ArgLoc;
872 if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
873 return;
874
875 llvm::Triple::EnvironmentType ShaderType;
876 if (!HLSLShaderAttr::ConvertStrToEnvironmentType(Str, ShaderType)) {
877 Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
878 << AL << Str << ArgLoc;
879 return;
880 }
881
882 // FIXME: check function match the shader stage.
883
884 HLSLShaderAttr *NewAttr = mergeShaderAttr(D, AL, ShaderType);
885 if (NewAttr)
886 D->addAttr(NewAttr);
887}
888
890 Sema &S, QualType Wrapped, ArrayRef<const Attr *> AttrList,
891 QualType &ResType, HLSLAttributedResourceLocInfo *LocInfo) {
892 assert(AttrList.size() && "expected list of resource attributes");
893
894 QualType ContainedTy = QualType();
895 TypeSourceInfo *ContainedTyInfo = nullptr;
896 SourceLocation LocBegin = AttrList[0]->getRange().getBegin();
897 SourceLocation LocEnd = AttrList[0]->getRange().getEnd();
898
900
901 bool HasResourceClass = false;
902 for (const Attr *A : AttrList) {
903 if (!A)
904 continue;
905 LocEnd = A->getRange().getEnd();
906 switch (A->getKind()) {
907 case attr::HLSLResourceClass: {
908 ResourceClass RC = cast<HLSLResourceClassAttr>(A)->getResourceClass();
909 if (HasResourceClass) {
910 S.Diag(A->getLocation(), ResAttrs.ResourceClass == RC
911 ? diag::warn_duplicate_attribute_exact
912 : diag::warn_duplicate_attribute)
913 << A;
914 return false;
915 }
916 ResAttrs.ResourceClass = RC;
917 HasResourceClass = true;
918 break;
919 }
920 case attr::HLSLROV:
921 if (ResAttrs.IsROV) {
922 S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A;
923 return false;
924 }
925 ResAttrs.IsROV = true;
926 break;
927 case attr::HLSLRawBuffer:
928 if (ResAttrs.RawBuffer) {
929 S.Diag(A->getLocation(), diag::warn_duplicate_attribute_exact) << A;
930 return false;
931 }
932 ResAttrs.RawBuffer = true;
933 break;
934 case attr::HLSLContainedType: {
935 const HLSLContainedTypeAttr *CTAttr = cast<HLSLContainedTypeAttr>(A);
936 QualType Ty = CTAttr->getType();
937 if (!ContainedTy.isNull()) {
938 S.Diag(A->getLocation(), ContainedTy == Ty
939 ? diag::warn_duplicate_attribute_exact
940 : diag::warn_duplicate_attribute)
941 << A;
942 return false;
943 }
944 ContainedTy = Ty;
945 ContainedTyInfo = CTAttr->getTypeLoc();
946 break;
947 }
948 default:
949 llvm_unreachable("unhandled resource attribute type");
950 }
951 }
952
953 if (!HasResourceClass) {
954 S.Diag(AttrList.back()->getRange().getEnd(),
955 diag::err_hlsl_missing_resource_class);
956 return false;
957 }
958
960 Wrapped, ContainedTy, ResAttrs);
961
962 if (LocInfo && ContainedTyInfo) {
963 LocInfo->Range = SourceRange(LocBegin, LocEnd);
964 LocInfo->ContainedTyInfo = ContainedTyInfo;
965 }
966 return true;
967}
968
969// Validates and creates an HLSL attribute that is applied as type attribute on
970// HLSL resource. The attributes are collected in HLSLResourcesTypeAttrs and at
971// the end of the declaration they are applied to the declaration type by
972// wrapping it in HLSLAttributedResourceType.
974 // only allow resource type attributes on intangible types
975 if (!T->isHLSLResourceType()) {
976 Diag(AL.getLoc(), diag::err_hlsl_attribute_needs_intangible_type)
977 << AL << getASTContext().HLSLResourceTy;
978 return false;
979 }
980
981 // validate number of arguments
983 return false;
984
985 Attr *A = nullptr;
986 switch (AL.getKind()) {
987 case ParsedAttr::AT_HLSLResourceClass: {
988 if (!AL.isArgIdent(0)) {
989 Diag(AL.getLoc(), diag::err_attribute_argument_type)
991 return false;
992 }
993
995 StringRef Identifier = Loc->Ident->getName();
996 SourceLocation ArgLoc = Loc->Loc;
997
998 // Validate resource class value
999 ResourceClass RC;
1000 if (!HLSLResourceClassAttr::ConvertStrToResourceClass(Identifier, RC)) {
1001 Diag(ArgLoc, diag::warn_attribute_type_not_supported)
1002 << "ResourceClass" << Identifier;
1003 return false;
1004 }
1005 A = HLSLResourceClassAttr::Create(getASTContext(), RC, AL.getLoc());
1006 break;
1007 }
1008
1009 case ParsedAttr::AT_HLSLROV:
1010 A = HLSLROVAttr::Create(getASTContext(), AL.getLoc());
1011 break;
1012
1013 case ParsedAttr::AT_HLSLRawBuffer:
1014 A = HLSLRawBufferAttr::Create(getASTContext(), AL.getLoc());
1015 break;
1016
1017 case ParsedAttr::AT_HLSLContainedType: {
1018 if (AL.getNumArgs() != 1 && !AL.hasParsedType()) {
1019 Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
1020 return false;
1021 }
1022
1023 TypeSourceInfo *TSI = nullptr;
1025 assert(TSI && "no type source info for attribute argument");
1027 diag::err_incomplete_type))
1028 return false;
1029 A = HLSLContainedTypeAttr::Create(getASTContext(), TSI, AL.getLoc());
1030 break;
1031 }
1032
1033 default:
1034 llvm_unreachable("unhandled HLSL attribute");
1035 }
1036
1037 HLSLResourcesTypeAttrs.emplace_back(A);
1038 return true;
1039}
1040
1041// Combines all resource type attributes and creates HLSLAttributedResourceType.
1043 if (!HLSLResourcesTypeAttrs.size())
1044 return CurrentType;
1045
1046 QualType QT = CurrentType;
1049 HLSLResourcesTypeAttrs, QT, &LocInfo)) {
1050 const HLSLAttributedResourceType *RT =
1051 cast<HLSLAttributedResourceType>(QT.getTypePtr());
1052
1053 // Temporarily store TypeLoc information for the new type.
1054 // It will be transferred to HLSLAttributesResourceTypeLoc
1055 // shortly after the type is created by TypeSpecLocFiller which
1056 // will call the TakeLocForHLSLAttribute method below.
1057 LocsForHLSLAttributedResources.insert(std::pair(RT, LocInfo));
1058 }
1059 HLSLResourcesTypeAttrs.clear();
1060 return QT;
1061}
1062
1063// Returns source location for the HLSLAttributedResourceType
1066 HLSLAttributedResourceLocInfo LocInfo = {};
1067 auto I = LocsForHLSLAttributedResources.find(RT);
1068 if (I != LocsForHLSLAttributedResources.end()) {
1069 LocInfo = I->second;
1070 LocsForHLSLAttributedResources.erase(I);
1071 return LocInfo;
1072 }
1073 LocInfo.Range = SourceRange();
1074 return LocInfo;
1075}
1076
1077// Walks though the global variable declaration, collects all resource binding
1078// requirements and adds them to Bindings
1079void SemaHLSL::collectResourcesOnUserRecordDecl(const VarDecl *VD,
1080 const RecordType *RT) {
1081 const RecordDecl *RD = RT->getDecl();
1082 for (FieldDecl *FD : RD->fields()) {
1083 const Type *Ty = FD->getType()->getUnqualifiedDesugaredType();
1084
1085 // Unwrap arrays
1086 // FIXME: Calculate array size while unwrapping
1087 assert(!Ty->isIncompleteArrayType() &&
1088 "incomplete arrays inside user defined types are not supported");
1089 while (Ty->isConstantArrayType()) {
1090 const ConstantArrayType *CAT = cast<ConstantArrayType>(Ty);
1092 }
1093
1094 if (!Ty->isRecordType())
1095 continue;
1096
1097 if (const HLSLAttributedResourceType *AttrResType =
1099 // Add a new DeclBindingInfo to Bindings if it does not already exist
1100 ResourceClass RC = AttrResType->getAttrs().ResourceClass;
1101 DeclBindingInfo *DBI = Bindings.getDeclBindingInfo(VD, RC);
1102 if (!DBI)
1103 Bindings.addDeclBindingInfo(VD, RC);
1104 } else if (const RecordType *RT = dyn_cast<RecordType>(Ty)) {
1105 // Recursively scan embedded struct or class; it would be nice to do this
1106 // without recursion, but tricky to correctly calculate the size of the
1107 // binding, which is something we are probably going to need to do later
1108 // on. Hopefully nesting of structs in structs too many levels is
1109 // unlikely.
1110 collectResourcesOnUserRecordDecl(VD, RT);
1111 }
1112 }
1113}
1114
1115// Diagnore localized register binding errors for a single binding; does not
1116// diagnose resource binding on user record types, that will be done later
1117// in processResourceBindingOnDecl based on the information collected in
1118// collectResourcesOnVarDecl.
1119// Returns false if the register binding is not valid.
1121 Decl *D, RegisterType RegType,
1122 bool SpecifiedSpace) {
1123 int RegTypeNum = static_cast<int>(RegType);
1124
1125 // check if the decl type is groupshared
1126 if (D->hasAttr<HLSLGroupSharedAddressSpaceAttr>()) {
1127 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
1128 return false;
1129 }
1130
1131 // Cbuffers and Tbuffers are HLSLBufferDecl types
1132 if (HLSLBufferDecl *CBufferOrTBuffer = dyn_cast<HLSLBufferDecl>(D)) {
1133 ResourceClass RC = CBufferOrTBuffer->isCBuffer() ? ResourceClass::CBuffer
1134 : ResourceClass::SRV;
1135 if (RegType == getRegisterType(RC))
1136 return true;
1137
1138 S.Diag(D->getLocation(), diag::err_hlsl_binding_type_mismatch)
1139 << RegTypeNum;
1140 return false;
1141 }
1142
1143 // Samplers, UAVs, and SRVs are VarDecl types
1144 assert(isa<VarDecl>(D) && "D is expected to be VarDecl or HLSLBufferDecl");
1145 VarDecl *VD = cast<VarDecl>(D);
1146
1147 // Resource
1148 if (const HLSLAttributedResourceType *AttrResType =
1150 VD->getType().getTypePtr())) {
1151 if (RegType == getRegisterType(AttrResType->getAttrs().ResourceClass))
1152 return true;
1153
1154 S.Diag(D->getLocation(), diag::err_hlsl_binding_type_mismatch)
1155 << RegTypeNum;
1156 return false;
1157 }
1158
1159 const clang::Type *Ty = VD->getType().getTypePtr();
1160 while (Ty->isArrayType())
1162
1163 // Basic types
1164 if (Ty->isArithmeticType()) {
1165 bool DeclaredInCOrTBuffer = isa<HLSLBufferDecl>(D->getDeclContext());
1166 if (SpecifiedSpace && !DeclaredInCOrTBuffer)
1167 S.Diag(ArgLoc, diag::err_hlsl_space_on_global_constant);
1168
1169 if (!DeclaredInCOrTBuffer &&
1170 (Ty->isIntegralType(S.getASTContext()) || Ty->isFloatingType())) {
1171 // Default Globals
1172 if (RegType == RegisterType::CBuffer)
1173 S.Diag(ArgLoc, diag::warn_hlsl_deprecated_register_type_b);
1174 else if (RegType != RegisterType::C)
1175 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
1176 } else {
1177 if (RegType == RegisterType::C)
1178 S.Diag(ArgLoc, diag::warn_hlsl_register_type_c_packoffset);
1179 else
1180 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
1181 }
1182 return false;
1183 }
1184 if (Ty->isRecordType())
1185 // RecordTypes will be diagnosed in processResourceBindingOnDecl
1186 // that is called from ActOnVariableDeclarator
1187 return true;
1188
1189 // Anything else is an error
1190 S.Diag(ArgLoc, diag::err_hlsl_binding_type_mismatch) << RegTypeNum;
1191 return false;
1192}
1193
1195 RegisterType regType) {
1196 // make sure that there are no two register annotations
1197 // applied to the decl with the same register type
1198 bool RegisterTypesDetected[5] = {false};
1199 RegisterTypesDetected[static_cast<int>(regType)] = true;
1200
1201 for (auto it = TheDecl->attr_begin(); it != TheDecl->attr_end(); ++it) {
1202 if (HLSLResourceBindingAttr *attr =
1203 dyn_cast<HLSLResourceBindingAttr>(*it)) {
1204
1205 RegisterType otherRegType = attr->getRegisterType();
1206 if (RegisterTypesDetected[static_cast<int>(otherRegType)]) {
1207 int otherRegTypeNum = static_cast<int>(otherRegType);
1208 S.Diag(TheDecl->getLocation(),
1209 diag::err_hlsl_duplicate_register_annotation)
1210 << otherRegTypeNum;
1211 return false;
1212 }
1213 RegisterTypesDetected[static_cast<int>(otherRegType)] = true;
1214 }
1215 }
1216 return true;
1217}
1218
1220 Decl *D, RegisterType RegType,
1221 bool SpecifiedSpace) {
1222
1223 // exactly one of these two types should be set
1224 assert(((isa<VarDecl>(D) && !isa<HLSLBufferDecl>(D)) ||
1225 (!isa<VarDecl>(D) && isa<HLSLBufferDecl>(D))) &&
1226 "expecting VarDecl or HLSLBufferDecl");
1227
1228 // check if the declaration contains resource matching the register type
1229 if (!DiagnoseLocalRegisterBinding(S, ArgLoc, D, RegType, SpecifiedSpace))
1230 return false;
1231
1232 // next, if multiple register annotations exist, check that none conflict.
1233 return ValidateMultipleRegisterAnnotations(S, D, RegType);
1234}
1235
1237 if (isa<VarDecl>(TheDecl)) {
1239 cast<ValueDecl>(TheDecl)->getType(),
1240 diag::err_incomplete_type))
1241 return;
1242 }
1243 StringRef Space = "space0";
1244 StringRef Slot = "";
1245
1246 if (!AL.isArgIdent(0)) {
1247 Diag(AL.getLoc(), diag::err_attribute_argument_type)
1248 << AL << AANT_ArgumentIdentifier;
1249 return;
1250 }
1251
1253 StringRef Str = Loc->Ident->getName();
1254 SourceLocation ArgLoc = Loc->Loc;
1255
1256 SourceLocation SpaceArgLoc;
1257 bool SpecifiedSpace = false;
1258 if (AL.getNumArgs() == 2) {
1259 SpecifiedSpace = true;
1260 Slot = Str;
1261 if (!AL.isArgIdent(1)) {
1262 Diag(AL.getLoc(), diag::err_attribute_argument_type)
1263 << AL << AANT_ArgumentIdentifier;
1264 return;
1265 }
1266
1268 Space = Loc->Ident->getName();
1269 SpaceArgLoc = Loc->Loc;
1270 } else {
1271 Slot = Str;
1272 }
1273
1274 RegisterType RegType;
1275 unsigned SlotNum = 0;
1276 unsigned SpaceNum = 0;
1277
1278 // Validate.
1279 if (!Slot.empty()) {
1280 if (!convertToRegisterType(Slot, &RegType)) {
1281 Diag(ArgLoc, diag::err_hlsl_binding_type_invalid) << Slot.substr(0, 1);
1282 return;
1283 }
1284 if (RegType == RegisterType::I) {
1285 Diag(ArgLoc, diag::warn_hlsl_deprecated_register_type_i);
1286 return;
1287 }
1288
1289 StringRef SlotNumStr = Slot.substr(1);
1290 if (SlotNumStr.getAsInteger(10, SlotNum)) {
1291 Diag(ArgLoc, diag::err_hlsl_unsupported_register_number);
1292 return;
1293 }
1294 }
1295
1296 if (!Space.starts_with("space")) {
1297 Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space;
1298 return;
1299 }
1300 StringRef SpaceNumStr = Space.substr(5);
1301 if (SpaceNumStr.getAsInteger(10, SpaceNum)) {
1302 Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space;
1303 return;
1304 }
1305
1306 if (!DiagnoseHLSLRegisterAttribute(SemaRef, ArgLoc, TheDecl, RegType,
1307 SpecifiedSpace))
1308 return;
1309
1310 HLSLResourceBindingAttr *NewAttr =
1311 HLSLResourceBindingAttr::Create(getASTContext(), Slot, Space, AL);
1312 if (NewAttr) {
1313 NewAttr->setBinding(RegType, SlotNum, SpaceNum);
1314 TheDecl->addAttr(NewAttr);
1315 }
1316}
1317
1319 HLSLParamModifierAttr *NewAttr = mergeParamModifierAttr(
1320 D, AL,
1321 static_cast<HLSLParamModifierAttr::Spelling>(AL.getSemanticSpelling()));
1322 if (NewAttr)
1323 D->addAttr(NewAttr);
1324}
1325
1326namespace {
1327
1328/// This class implements HLSL availability diagnostics for default
1329/// and relaxed mode
1330///
1331/// The goal of this diagnostic is to emit an error or warning when an
1332/// unavailable API is found in code that is reachable from the shader
1333/// entry function or from an exported function (when compiling a shader
1334/// library).
1335///
1336/// This is done by traversing the AST of all shader entry point functions
1337/// and of all exported functions, and any functions that are referenced
1338/// from this AST. In other words, any functions that are reachable from
1339/// the entry points.
1340class DiagnoseHLSLAvailability : public DynamicRecursiveASTVisitor {
1341 Sema &SemaRef;
1342
1343 // Stack of functions to be scaned
1345
1346 // Tracks which environments functions have been scanned in.
1347 //
1348 // Maps FunctionDecl to an unsigned number that represents the set of shader
1349 // environments the function has been scanned for.
1350 // The llvm::Triple::EnvironmentType enum values for shader stages guaranteed
1351 // to be numbered from llvm::Triple::Pixel to llvm::Triple::Amplification
1352 // (verified by static_asserts in Triple.cpp), we can use it to index
1353 // individual bits in the set, as long as we shift the values to start with 0
1354 // by subtracting the value of llvm::Triple::Pixel first.
1355 //
1356 // The N'th bit in the set will be set if the function has been scanned
1357 // in shader environment whose llvm::Triple::EnvironmentType integer value
1358 // equals (llvm::Triple::Pixel + N).
1359 //
1360 // For example, if a function has been scanned in compute and pixel stage
1361 // environment, the value will be 0x21 (100001 binary) because:
1362 //
1363 // (int)(llvm::Triple::Pixel - llvm::Triple::Pixel) == 0
1364 // (int)(llvm::Triple::Compute - llvm::Triple::Pixel) == 5
1365 //
1366 // A FunctionDecl is mapped to 0 (or not included in the map) if it has not
1367 // been scanned in any environment.
1368 llvm::DenseMap<const FunctionDecl *, unsigned> ScannedDecls;
1369
1370 // Do not access these directly, use the get/set methods below to make
1371 // sure the values are in sync
1372 llvm::Triple::EnvironmentType CurrentShaderEnvironment;
1373 unsigned CurrentShaderStageBit;
1374
1375 // True if scanning a function that was already scanned in a different
1376 // shader stage context, and therefore we should not report issues that
1377 // depend only on shader model version because they would be duplicate.
1378 bool ReportOnlyShaderStageIssues;
1379
1380 // Helper methods for dealing with current stage context / environment
1381 void SetShaderStageContext(llvm::Triple::EnvironmentType ShaderType) {
1382 static_assert(sizeof(unsigned) >= 4);
1383 assert(HLSLShaderAttr::isValidShaderType(ShaderType));
1384 assert((unsigned)(ShaderType - llvm::Triple::Pixel) < 31 &&
1385 "ShaderType is too big for this bitmap"); // 31 is reserved for
1386 // "unknown"
1387
1388 unsigned bitmapIndex = ShaderType - llvm::Triple::Pixel;
1389 CurrentShaderEnvironment = ShaderType;
1390 CurrentShaderStageBit = (1 << bitmapIndex);
1391 }
1392
1393 void SetUnknownShaderStageContext() {
1394 CurrentShaderEnvironment = llvm::Triple::UnknownEnvironment;
1395 CurrentShaderStageBit = (1 << 31);
1396 }
1397
1398 llvm::Triple::EnvironmentType GetCurrentShaderEnvironment() const {
1399 return CurrentShaderEnvironment;
1400 }
1401
1402 bool InUnknownShaderStageContext() const {
1403 return CurrentShaderEnvironment == llvm::Triple::UnknownEnvironment;
1404 }
1405
1406 // Helper methods for dealing with shader stage bitmap
1407 void AddToScannedFunctions(const FunctionDecl *FD) {
1408 unsigned &ScannedStages = ScannedDecls[FD];
1409 ScannedStages |= CurrentShaderStageBit;
1410 }
1411
1412 unsigned GetScannedStages(const FunctionDecl *FD) { return ScannedDecls[FD]; }
1413
1414 bool WasAlreadyScannedInCurrentStage(const FunctionDecl *FD) {
1415 return WasAlreadyScannedInCurrentStage(GetScannedStages(FD));
1416 }
1417
1418 bool WasAlreadyScannedInCurrentStage(unsigned ScannerStages) {
1419 return ScannerStages & CurrentShaderStageBit;
1420 }
1421
1422 static bool NeverBeenScanned(unsigned ScannedStages) {
1423 return ScannedStages == 0;
1424 }
1425
1426 // Scanning methods
1427 void HandleFunctionOrMethodRef(FunctionDecl *FD, Expr *RefExpr);
1428 void CheckDeclAvailability(NamedDecl *D, const AvailabilityAttr *AA,
1430 const AvailabilityAttr *FindAvailabilityAttr(const Decl *D);
1431 bool HasMatchingEnvironmentOrNone(const AvailabilityAttr *AA);
1432
1433public:
1434 DiagnoseHLSLAvailability(Sema &SemaRef)
1435 : SemaRef(SemaRef),
1436 CurrentShaderEnvironment(llvm::Triple::UnknownEnvironment),
1437 CurrentShaderStageBit(0), ReportOnlyShaderStageIssues(false) {}
1438
1439 // AST traversal methods
1440 void RunOnTranslationUnit(const TranslationUnitDecl *TU);
1441 void RunOnFunction(const FunctionDecl *FD);
1442
1443 bool VisitDeclRefExpr(DeclRefExpr *DRE) override {
1444 FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(DRE->getDecl());
1445 if (FD)
1446 HandleFunctionOrMethodRef(FD, DRE);
1447 return true;
1448 }
1449
1450 bool VisitMemberExpr(MemberExpr *ME) override {
1451 FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(ME->getMemberDecl());
1452 if (FD)
1453 HandleFunctionOrMethodRef(FD, ME);
1454 return true;
1455 }
1456};
1457
1458void DiagnoseHLSLAvailability::HandleFunctionOrMethodRef(FunctionDecl *FD,
1459 Expr *RefExpr) {
1460 assert((isa<DeclRefExpr>(RefExpr) || isa<MemberExpr>(RefExpr)) &&
1461 "expected DeclRefExpr or MemberExpr");
1462
1463 // has a definition -> add to stack to be scanned
1464 const FunctionDecl *FDWithBody = nullptr;
1465 if (FD->hasBody(FDWithBody)) {
1466 if (!WasAlreadyScannedInCurrentStage(FDWithBody))
1467 DeclsToScan.push_back(FDWithBody);
1468 return;
1469 }
1470
1471 // no body -> diagnose availability
1472 const AvailabilityAttr *AA = FindAvailabilityAttr(FD);
1473 if (AA)
1474 CheckDeclAvailability(
1475 FD, AA, SourceRange(RefExpr->getBeginLoc(), RefExpr->getEndLoc()));
1476}
1477
1478void DiagnoseHLSLAvailability::RunOnTranslationUnit(
1479 const TranslationUnitDecl *TU) {
1480
1481 // Iterate over all shader entry functions and library exports, and for those
1482 // that have a body (definiton), run diag scan on each, setting appropriate
1483 // shader environment context based on whether it is a shader entry function
1484 // or an exported function. Exported functions can be in namespaces and in
1485 // export declarations so we need to scan those declaration contexts as well.
1487 DeclContextsToScan.push_back(TU);
1488
1489 while (!DeclContextsToScan.empty()) {
1490 const DeclContext *DC = DeclContextsToScan.pop_back_val();
1491 for (auto &D : DC->decls()) {
1492 // do not scan implicit declaration generated by the implementation
1493 if (D->isImplicit())
1494 continue;
1495
1496 // for namespace or export declaration add the context to the list to be
1497 // scanned later
1498 if (llvm::dyn_cast<NamespaceDecl>(D) || llvm::dyn_cast<ExportDecl>(D)) {
1499 DeclContextsToScan.push_back(llvm::dyn_cast<DeclContext>(D));
1500 continue;
1501 }
1502
1503 // skip over other decls or function decls without body
1504 const FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(D);
1505 if (!FD || !FD->isThisDeclarationADefinition())
1506 continue;
1507
1508 // shader entry point
1509 if (HLSLShaderAttr *ShaderAttr = FD->getAttr<HLSLShaderAttr>()) {
1510 SetShaderStageContext(ShaderAttr->getType());
1511 RunOnFunction(FD);
1512 continue;
1513 }
1514 // exported library function
1515 // FIXME: replace this loop with external linkage check once issue #92071
1516 // is resolved
1517 bool isExport = FD->isInExportDeclContext();
1518 if (!isExport) {
1519 for (const auto *Redecl : FD->redecls()) {
1520 if (Redecl->isInExportDeclContext()) {
1521 isExport = true;
1522 break;
1523 }
1524 }
1525 }
1526 if (isExport) {
1527 SetUnknownShaderStageContext();
1528 RunOnFunction(FD);
1529 continue;
1530 }
1531 }
1532 }
1533}
1534
1535void DiagnoseHLSLAvailability::RunOnFunction(const FunctionDecl *FD) {
1536 assert(DeclsToScan.empty() && "DeclsToScan should be empty");
1537 DeclsToScan.push_back(FD);
1538
1539 while (!DeclsToScan.empty()) {
1540 // Take one decl from the stack and check it by traversing its AST.
1541 // For any CallExpr found during the traversal add it's callee to the top of
1542 // the stack to be processed next. Functions already processed are stored in
1543 // ScannedDecls.
1544 const FunctionDecl *FD = DeclsToScan.pop_back_val();
1545
1546 // Decl was already scanned
1547 const unsigned ScannedStages = GetScannedStages(FD);
1548 if (WasAlreadyScannedInCurrentStage(ScannedStages))
1549 continue;
1550
1551 ReportOnlyShaderStageIssues = !NeverBeenScanned(ScannedStages);
1552
1553 AddToScannedFunctions(FD);
1554 TraverseStmt(FD->getBody());
1555 }
1556}
1557
1558bool DiagnoseHLSLAvailability::HasMatchingEnvironmentOrNone(
1559 const AvailabilityAttr *AA) {
1560 IdentifierInfo *IIEnvironment = AA->getEnvironment();
1561 if (!IIEnvironment)
1562 return true;
1563
1564 llvm::Triple::EnvironmentType CurrentEnv = GetCurrentShaderEnvironment();
1565 if (CurrentEnv == llvm::Triple::UnknownEnvironment)
1566 return false;
1567
1568 llvm::Triple::EnvironmentType AttrEnv =
1569 AvailabilityAttr::getEnvironmentType(IIEnvironment->getName());
1570
1571 return CurrentEnv == AttrEnv;
1572}
1573
1574const AvailabilityAttr *
1575DiagnoseHLSLAvailability::FindAvailabilityAttr(const Decl *D) {
1576 AvailabilityAttr const *PartialMatch = nullptr;
1577 // Check each AvailabilityAttr to find the one for this platform.
1578 // For multiple attributes with the same platform try to find one for this
1579 // environment.
1580 for (const auto *A : D->attrs()) {
1581 if (const auto *Avail = dyn_cast<AvailabilityAttr>(A)) {
1582 StringRef AttrPlatform = Avail->getPlatform()->getName();
1583 StringRef TargetPlatform =
1585
1586 // Match the platform name.
1587 if (AttrPlatform == TargetPlatform) {
1588 // Find the best matching attribute for this environment
1589 if (HasMatchingEnvironmentOrNone(Avail))
1590 return Avail;
1591 PartialMatch = Avail;
1592 }
1593 }
1594 }
1595 return PartialMatch;
1596}
1597
1598// Check availability against target shader model version and current shader
1599// stage and emit diagnostic
1600void DiagnoseHLSLAvailability::CheckDeclAvailability(NamedDecl *D,
1601 const AvailabilityAttr *AA,
1603
1604 IdentifierInfo *IIEnv = AA->getEnvironment();
1605
1606 if (!IIEnv) {
1607 // The availability attribute does not have environment -> it depends only
1608 // on shader model version and not on specific the shader stage.
1609
1610 // Skip emitting the diagnostics if the diagnostic mode is set to
1611 // strict (-fhlsl-strict-availability) because all relevant diagnostics
1612 // were already emitted in the DiagnoseUnguardedAvailability scan
1613 // (SemaAvailability.cpp).
1614 if (SemaRef.getLangOpts().HLSLStrictAvailability)
1615 return;
1616
1617 // Do not report shader-stage-independent issues if scanning a function
1618 // that was already scanned in a different shader stage context (they would
1619 // be duplicate)
1620 if (ReportOnlyShaderStageIssues)
1621 return;
1622
1623 } else {
1624 // The availability attribute has environment -> we need to know
1625 // the current stage context to property diagnose it.
1626 if (InUnknownShaderStageContext())
1627 return;
1628 }
1629
1630 // Check introduced version and if environment matches
1631 bool EnvironmentMatches = HasMatchingEnvironmentOrNone(AA);
1632 VersionTuple Introduced = AA->getIntroduced();
1633 VersionTuple TargetVersion =
1635
1636 if (TargetVersion >= Introduced && EnvironmentMatches)
1637 return;
1638
1639 // Emit diagnostic message
1640 const TargetInfo &TI = SemaRef.getASTContext().getTargetInfo();
1641 llvm::StringRef PlatformName(
1642 AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName()));
1643
1644 llvm::StringRef CurrentEnvStr =
1645 llvm::Triple::getEnvironmentTypeName(GetCurrentShaderEnvironment());
1646
1647 llvm::StringRef AttrEnvStr =
1648 AA->getEnvironment() ? AA->getEnvironment()->getName() : "";
1649 bool UseEnvironment = !AttrEnvStr.empty();
1650
1651 if (EnvironmentMatches) {
1652 SemaRef.Diag(Range.getBegin(), diag::warn_hlsl_availability)
1653 << Range << D << PlatformName << Introduced.getAsString()
1654 << UseEnvironment << CurrentEnvStr;
1655 } else {
1656 SemaRef.Diag(Range.getBegin(), diag::warn_hlsl_availability_unavailable)
1657 << Range << D;
1658 }
1659
1660 SemaRef.Diag(D->getLocation(), diag::note_partial_availability_specified_here)
1661 << D << PlatformName << Introduced.getAsString()
1662 << SemaRef.Context.getTargetInfo().getPlatformMinVersion().getAsString()
1663 << UseEnvironment << AttrEnvStr << CurrentEnvStr;
1664}
1665
1666} // namespace
1667
1669 // Skip running the diagnostics scan if the diagnostic mode is
1670 // strict (-fhlsl-strict-availability) and the target shader stage is known
1671 // because all relevant diagnostics were already emitted in the
1672 // DiagnoseUnguardedAvailability scan (SemaAvailability.cpp).
1674 if (SemaRef.getLangOpts().HLSLStrictAvailability &&
1675 TI.getTriple().getEnvironment() != llvm::Triple::EnvironmentType::Library)
1676 return;
1677
1678 DiagnoseHLSLAvailability(SemaRef).RunOnTranslationUnit(TU);
1679}
1680
1681// Helper function for CheckHLSLBuiltinFunctionCall
1682static bool CheckVectorElementCallArgs(Sema *S, CallExpr *TheCall) {
1683 assert(TheCall->getNumArgs() > 1);
1684 ExprResult A = TheCall->getArg(0);
1685
1686 QualType ArgTyA = A.get()->getType();
1687
1688 auto *VecTyA = ArgTyA->getAs<VectorType>();
1689 SourceLocation BuiltinLoc = TheCall->getBeginLoc();
1690
1691 for (unsigned i = 1; i < TheCall->getNumArgs(); ++i) {
1692 ExprResult B = TheCall->getArg(i);
1693 QualType ArgTyB = B.get()->getType();
1694 auto *VecTyB = ArgTyB->getAs<VectorType>();
1695 if (VecTyA == nullptr && VecTyB == nullptr)
1696 return false;
1697
1698 if (VecTyA && VecTyB) {
1699 bool retValue = false;
1700 if (VecTyA->getElementType() != VecTyB->getElementType()) {
1701 // Note: type promotion is intended to be handeled via the intrinsics
1702 // and not the builtin itself.
1703 S->Diag(TheCall->getBeginLoc(),
1704 diag::err_vec_builtin_incompatible_vector)
1705 << TheCall->getDirectCallee() << /*useAllTerminology*/ true
1706 << SourceRange(A.get()->getBeginLoc(), B.get()->getEndLoc());
1707 retValue = true;
1708 }
1709 if (VecTyA->getNumElements() != VecTyB->getNumElements()) {
1710 // You should only be hitting this case if you are calling the builtin
1711 // directly. HLSL intrinsics should avoid this case via a
1712 // HLSLVectorTruncation.
1713 S->Diag(BuiltinLoc, diag::err_vec_builtin_incompatible_vector)
1714 << TheCall->getDirectCallee() << /*useAllTerminology*/ true
1715 << SourceRange(TheCall->getArg(0)->getBeginLoc(),
1716 TheCall->getArg(1)->getEndLoc());
1717 retValue = true;
1718 }
1719 return retValue;
1720 }
1721 }
1722
1723 // Note: if we get here one of the args is a scalar which
1724 // requires a VectorSplat on Arg0 or Arg1
1725 S->Diag(BuiltinLoc, diag::err_vec_builtin_non_vector)
1726 << TheCall->getDirectCallee() << /*useAllTerminology*/ true
1727 << SourceRange(TheCall->getArg(0)->getBeginLoc(),
1728 TheCall->getArg(1)->getEndLoc());
1729 return true;
1730}
1731
1733 QualType ArgType = Arg->getType();
1735 S->Diag(Arg->getBeginLoc(), diag::err_typecheck_convert_incompatible)
1736 << ArgType << ExpectedType << 1 << 0 << 0;
1737 return true;
1738 }
1739 return false;
1740}
1741
1743 Sema *S, Expr *Arg, QualType ExpectedType,
1744 llvm::function_ref<bool(clang::QualType PassedType)> Check) {
1745 QualType PassedType = Arg->getType();
1746 if (Check(PassedType)) {
1747 if (auto *VecTyA = PassedType->getAs<VectorType>())
1749 ExpectedType, VecTyA->getNumElements(), VecTyA->getVectorKind());
1750 S->Diag(Arg->getBeginLoc(), diag::err_typecheck_convert_incompatible)
1751 << PassedType << ExpectedType << 1 << 0 << 0;
1752 return true;
1753 }
1754 return false;
1755}
1756
1758 Sema *S, CallExpr *TheCall, QualType ExpectedType,
1759 llvm::function_ref<bool(clang::QualType PassedType)> Check) {
1760 for (unsigned i = 0; i < TheCall->getNumArgs(); ++i) {
1761 Expr *Arg = TheCall->getArg(i);
1762 if (CheckArgTypeIsCorrect(S, Arg, ExpectedType, Check)) {
1763 return true;
1764 }
1765 }
1766 return false;
1767}
1768
1770 auto checkAllFloatTypes = [](clang::QualType PassedType) -> bool {
1771 return !PassedType->hasFloatingRepresentation();
1772 };
1773 return CheckAllArgTypesAreCorrect(S, TheCall, S->Context.FloatTy,
1774 checkAllFloatTypes);
1775}
1776
1778 auto checkFloatorHalf = [](clang::QualType PassedType) -> bool {
1779 clang::QualType BaseType =
1780 PassedType->isVectorType()
1781 ? PassedType->getAs<clang::VectorType>()->getElementType()
1782 : PassedType;
1783 return !BaseType->isHalfType() && !BaseType->isFloat32Type();
1784 };
1785 return CheckAllArgTypesAreCorrect(S, TheCall, S->Context.FloatTy,
1786 checkFloatorHalf);
1787}
1788
1789static bool CheckModifiableLValue(Sema *S, CallExpr *TheCall,
1790 unsigned ArgIndex) {
1791 auto *Arg = TheCall->getArg(ArgIndex);
1792 SourceLocation OrigLoc = Arg->getExprLoc();
1793 if (Arg->IgnoreCasts()->isModifiableLvalue(S->Context, &OrigLoc) ==
1795 return false;
1796 S->Diag(OrigLoc, diag::error_hlsl_inout_lvalue) << Arg << 0;
1797 return true;
1798}
1799
1800static bool CheckNoDoubleVectors(Sema *S, CallExpr *TheCall) {
1801 auto checkDoubleVector = [](clang::QualType PassedType) -> bool {
1802 if (const auto *VecTy = PassedType->getAs<VectorType>())
1803 return VecTy->getElementType()->isDoubleType();
1804 return false;
1805 };
1806 return CheckAllArgTypesAreCorrect(S, TheCall, S->Context.FloatTy,
1807 checkDoubleVector);
1808}
1810 auto checkAllSignedTypes = [](clang::QualType PassedType) -> bool {
1811 return !PassedType->hasIntegerRepresentation() &&
1812 !PassedType->hasFloatingRepresentation();
1813 };
1814 return CheckAllArgTypesAreCorrect(S, TheCall, S->Context.IntTy,
1815 checkAllSignedTypes);
1816}
1817
1819 auto checkAllUnsignedTypes = [](clang::QualType PassedType) -> bool {
1820 return !PassedType->hasUnsignedIntegerRepresentation();
1821 };
1822 return CheckAllArgTypesAreCorrect(S, TheCall, S->Context.UnsignedIntTy,
1823 checkAllUnsignedTypes);
1824}
1825
1827 QualType ReturnType) {
1828 auto *VecTyA = TheCall->getArg(0)->getType()->getAs<VectorType>();
1829 if (VecTyA)
1830 ReturnType = S->Context.getVectorType(ReturnType, VecTyA->getNumElements(),
1832 TheCall->setType(ReturnType);
1833}
1834
1835static bool CheckScalarOrVector(Sema *S, CallExpr *TheCall, QualType Scalar,
1836 unsigned ArgIndex) {
1837 assert(TheCall->getNumArgs() >= ArgIndex);
1838 QualType ArgType = TheCall->getArg(ArgIndex)->getType();
1839 auto *VTy = ArgType->getAs<VectorType>();
1840 // not the scalar or vector<scalar>
1841 if (!(S->Context.hasSameUnqualifiedType(ArgType, Scalar) ||
1842 (VTy &&
1843 S->Context.hasSameUnqualifiedType(VTy->getElementType(), Scalar)))) {
1844 S->Diag(TheCall->getArg(0)->getBeginLoc(),
1845 diag::err_typecheck_expect_scalar_or_vector)
1846 << ArgType << Scalar;
1847 return true;
1848 }
1849 return false;
1850}
1851
1852static bool CheckAnyScalarOrVector(Sema *S, CallExpr *TheCall,
1853 unsigned ArgIndex) {
1854 assert(TheCall->getNumArgs() >= ArgIndex);
1855 QualType ArgType = TheCall->getArg(ArgIndex)->getType();
1856 auto *VTy = ArgType->getAs<VectorType>();
1857 // not the scalar or vector<scalar>
1858 if (!(ArgType->isScalarType() ||
1859 (VTy && VTy->getElementType()->isScalarType()))) {
1860 S->Diag(TheCall->getArg(0)->getBeginLoc(),
1861 diag::err_typecheck_expect_any_scalar_or_vector)
1862 << ArgType;
1863 return true;
1864 }
1865 return false;
1866}
1867
1868static bool CheckBoolSelect(Sema *S, CallExpr *TheCall) {
1869 assert(TheCall->getNumArgs() == 3);
1870 Expr *Arg1 = TheCall->getArg(1);
1871 Expr *Arg2 = TheCall->getArg(2);
1872 if (!S->Context.hasSameUnqualifiedType(Arg1->getType(), Arg2->getType())) {
1873 S->Diag(TheCall->getBeginLoc(),
1874 diag::err_typecheck_call_different_arg_types)
1875 << Arg1->getType() << Arg2->getType() << Arg1->getSourceRange()
1876 << Arg2->getSourceRange();
1877 return true;
1878 }
1879
1880 TheCall->setType(Arg1->getType());
1881 return false;
1882}
1883
1884static bool CheckVectorSelect(Sema *S, CallExpr *TheCall) {
1885 assert(TheCall->getNumArgs() == 3);
1886 Expr *Arg1 = TheCall->getArg(1);
1887 Expr *Arg2 = TheCall->getArg(2);
1888 if (!Arg1->getType()->isVectorType()) {
1889 S->Diag(Arg1->getBeginLoc(), diag::err_builtin_non_vector_type)
1890 << "Second" << TheCall->getDirectCallee() << Arg1->getType()
1891 << Arg1->getSourceRange();
1892 return true;
1893 }
1894
1895 if (!Arg2->getType()->isVectorType()) {
1896 S->Diag(Arg2->getBeginLoc(), diag::err_builtin_non_vector_type)
1897 << "Third" << TheCall->getDirectCallee() << Arg2->getType()
1898 << Arg2->getSourceRange();
1899 return true;
1900 }
1901
1902 if (!S->Context.hasSameUnqualifiedType(Arg1->getType(), Arg2->getType())) {
1903 S->Diag(TheCall->getBeginLoc(),
1904 diag::err_typecheck_call_different_arg_types)
1905 << Arg1->getType() << Arg2->getType() << Arg1->getSourceRange()
1906 << Arg2->getSourceRange();
1907 return true;
1908 }
1909
1910 // caller has checked that Arg0 is a vector.
1911 // check all three args have the same length.
1912 if (TheCall->getArg(0)->getType()->getAs<VectorType>()->getNumElements() !=
1913 Arg1->getType()->getAs<VectorType>()->getNumElements()) {
1914 S->Diag(TheCall->getBeginLoc(),
1915 diag::err_typecheck_vector_lengths_not_equal)
1916 << TheCall->getArg(0)->getType() << Arg1->getType()
1917 << TheCall->getArg(0)->getSourceRange() << Arg1->getSourceRange();
1918 return true;
1919 }
1920 TheCall->setType(Arg1->getType());
1921 return false;
1922}
1923
1925 Sema *S, CallExpr *TheCall, unsigned ArgIndex,
1926 llvm::function_ref<bool(const HLSLAttributedResourceType *ResType)> Check =
1927 nullptr) {
1928 assert(TheCall->getNumArgs() >= ArgIndex);
1929 QualType ArgType = TheCall->getArg(ArgIndex)->getType();
1930 const HLSLAttributedResourceType *ResTy =
1932 if (!ResTy) {
1933 S->Diag(TheCall->getArg(ArgIndex)->getBeginLoc(),
1934 diag::err_typecheck_expect_hlsl_resource)
1935 << ArgType;
1936 return true;
1937 }
1938 if (Check && Check(ResTy)) {
1939 S->Diag(TheCall->getArg(ArgIndex)->getExprLoc(),
1940 diag::err_invalid_hlsl_resource_type)
1941 << ArgType;
1942 return true;
1943 }
1944 return false;
1945}
1946
1947// Note: returning true in this case results in CheckBuiltinFunctionCall
1948// returning an ExprError
1949bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
1950 switch (BuiltinID) {
1951 case Builtin::BI__builtin_hlsl_resource_getpointer: {
1952 if (SemaRef.checkArgCount(TheCall, 2) ||
1953 CheckResourceHandle(&SemaRef, TheCall, 0) ||
1954 CheckArgTypeMatches(&SemaRef, TheCall->getArg(1),
1956 return true;
1957
1958 auto *ResourceTy =
1960 QualType ContainedTy = ResourceTy->getContainedType();
1961 // TODO: Map to an hlsl_device address space.
1962 TheCall->setType(getASTContext().getPointerType(ContainedTy));
1963 TheCall->setValueKind(VK_LValue);
1964
1965 break;
1966 }
1967 case Builtin::BI__builtin_hlsl_all:
1968 case Builtin::BI__builtin_hlsl_any: {
1969 if (SemaRef.checkArgCount(TheCall, 1))
1970 return true;
1971 break;
1972 }
1973 case Builtin::BI__builtin_hlsl_asdouble: {
1974 if (SemaRef.checkArgCount(TheCall, 2))
1975 return true;
1977 return true;
1978
1979 SetElementTypeAsReturnType(&SemaRef, TheCall, getASTContext().DoubleTy);
1980 break;
1981 }
1982 case Builtin::BI__builtin_hlsl_elementwise_clamp: {
1983 if (SemaRef.checkArgCount(TheCall, 3))
1984 return true;
1985 if (CheckVectorElementCallArgs(&SemaRef, TheCall))
1986 return true;
1988 TheCall, /*CheckForFloatArgs*/
1989 TheCall->getArg(0)->getType()->hasFloatingRepresentation()))
1990 return true;
1991 break;
1992 }
1993 case Builtin::BI__builtin_hlsl_cross: {
1994 if (SemaRef.checkArgCount(TheCall, 2))
1995 return true;
1996 if (CheckVectorElementCallArgs(&SemaRef, TheCall))
1997 return true;
1999 return true;
2000 // ensure both args have 3 elements
2001 int NumElementsArg1 =
2002 TheCall->getArg(0)->getType()->castAs<VectorType>()->getNumElements();
2003 int NumElementsArg2 =
2004 TheCall->getArg(1)->getType()->castAs<VectorType>()->getNumElements();
2005
2006 if (NumElementsArg1 != 3) {
2007 int LessOrMore = NumElementsArg1 > 3 ? 1 : 0;
2008 SemaRef.Diag(TheCall->getBeginLoc(),
2009 diag::err_vector_incorrect_num_elements)
2010 << LessOrMore << 3 << NumElementsArg1 << /*operand*/ 1;
2011 return true;
2012 }
2013 if (NumElementsArg2 != 3) {
2014 int LessOrMore = NumElementsArg2 > 3 ? 1 : 0;
2015
2016 SemaRef.Diag(TheCall->getBeginLoc(),
2017 diag::err_vector_incorrect_num_elements)
2018 << LessOrMore << 3 << NumElementsArg2 << /*operand*/ 1;
2019 return true;
2020 }
2021
2022 ExprResult A = TheCall->getArg(0);
2023 QualType ArgTyA = A.get()->getType();
2024 // return type is the same as the input type
2025 TheCall->setType(ArgTyA);
2026 break;
2027 }
2028 case Builtin::BI__builtin_hlsl_dot: {
2029 if (SemaRef.checkArgCount(TheCall, 2))
2030 return true;
2031 if (CheckVectorElementCallArgs(&SemaRef, TheCall))
2032 return true;
2034 return true;
2035 if (CheckNoDoubleVectors(&SemaRef, TheCall))
2036 return true;
2037 break;
2038 }
2039 case Builtin::BI__builtin_hlsl_elementwise_firstbithigh: {
2041 return true;
2042
2043 const Expr *Arg = TheCall->getArg(0);
2044 QualType ArgTy = Arg->getType();
2045 QualType EltTy = ArgTy;
2046
2048
2049 if (auto *VecTy = EltTy->getAs<VectorType>()) {
2050 EltTy = VecTy->getElementType();
2051 ResTy = SemaRef.Context.getVectorType(ResTy, VecTy->getNumElements(),
2052 VecTy->getVectorKind());
2053 }
2054
2055 if (!EltTy->isIntegerType()) {
2056 Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
2057 << 1 << /* integer ty */ 6 << ArgTy;
2058 return true;
2059 }
2060
2061 TheCall->setType(ResTy);
2062 break;
2063 }
2064 case Builtin::BI__builtin_hlsl_select: {
2065 if (SemaRef.checkArgCount(TheCall, 3))
2066 return true;
2067 if (CheckScalarOrVector(&SemaRef, TheCall, getASTContext().BoolTy, 0))
2068 return true;
2069 QualType ArgTy = TheCall->getArg(0)->getType();
2070 if (ArgTy->isBooleanType() && CheckBoolSelect(&SemaRef, TheCall))
2071 return true;
2072 auto *VTy = ArgTy->getAs<VectorType>();
2073 if (VTy && VTy->getElementType()->isBooleanType() &&
2074 CheckVectorSelect(&SemaRef, TheCall))
2075 return true;
2076 break;
2077 }
2078 case Builtin::BI__builtin_hlsl_elementwise_saturate:
2079 case Builtin::BI__builtin_hlsl_elementwise_rcp: {
2081 return true;
2083 return true;
2084 break;
2085 }
2086 case Builtin::BI__builtin_hlsl_elementwise_degrees:
2087 case Builtin::BI__builtin_hlsl_elementwise_radians:
2088 case Builtin::BI__builtin_hlsl_elementwise_rsqrt:
2089 case Builtin::BI__builtin_hlsl_elementwise_frac: {
2091 return true;
2093 return true;
2094 break;
2095 }
2096 case Builtin::BI__builtin_hlsl_elementwise_isinf: {
2098 return true;
2100 return true;
2102 break;
2103 }
2104 case Builtin::BI__builtin_hlsl_lerp: {
2105 if (SemaRef.checkArgCount(TheCall, 3))
2106 return true;
2107 if (CheckVectorElementCallArgs(&SemaRef, TheCall))
2108 return true;
2110 return true;
2112 return true;
2113 break;
2114 }
2115 case Builtin::BI__builtin_hlsl_length: {
2117 return true;
2118 if (SemaRef.checkArgCount(TheCall, 1))
2119 return true;
2120
2121 ExprResult A = TheCall->getArg(0);
2122 QualType ArgTyA = A.get()->getType();
2123 QualType RetTy;
2124
2125 if (auto *VTy = ArgTyA->getAs<VectorType>())
2126 RetTy = VTy->getElementType();
2127 else
2128 RetTy = TheCall->getArg(0)->getType();
2129
2130 TheCall->setType(RetTy);
2131 break;
2132 }
2133 case Builtin::BI__builtin_hlsl_mad: {
2134 if (SemaRef.checkArgCount(TheCall, 3))
2135 return true;
2136 if (CheckVectorElementCallArgs(&SemaRef, TheCall))
2137 return true;
2139 TheCall, /*CheckForFloatArgs*/
2140 TheCall->getArg(0)->getType()->hasFloatingRepresentation()))
2141 return true;
2142 break;
2143 }
2144 case Builtin::BI__builtin_hlsl_normalize: {
2146 return true;
2147 if (SemaRef.checkArgCount(TheCall, 1))
2148 return true;
2149
2150 ExprResult A = TheCall->getArg(0);
2151 QualType ArgTyA = A.get()->getType();
2152 // return type is the same as the input type
2153 TheCall->setType(ArgTyA);
2154 break;
2155 }
2156 case Builtin::BI__builtin_hlsl_elementwise_sign: {
2158 return true;
2160 return true;
2162 break;
2163 }
2164 case Builtin::BI__builtin_hlsl_step: {
2165 if (SemaRef.checkArgCount(TheCall, 2))
2166 return true;
2168 return true;
2169
2170 ExprResult A = TheCall->getArg(0);
2171 QualType ArgTyA = A.get()->getType();
2172 // return type is the same as the input type
2173 TheCall->setType(ArgTyA);
2174 break;
2175 }
2176 // Note these are llvm builtins that we want to catch invalid intrinsic
2177 // generation. Normal handling of these builitns will occur elsewhere.
2178 case Builtin::BI__builtin_elementwise_bitreverse: {
2180 return true;
2181 break;
2182 }
2183 case Builtin::BI__builtin_hlsl_wave_read_lane_at: {
2184 if (SemaRef.checkArgCount(TheCall, 2))
2185 return true;
2186
2187 // Ensure index parameter type can be interpreted as a uint
2188 ExprResult Index = TheCall->getArg(1);
2189 QualType ArgTyIndex = Index.get()->getType();
2190 if (!ArgTyIndex->isIntegerType()) {
2191 SemaRef.Diag(TheCall->getArg(1)->getBeginLoc(),
2192 diag::err_typecheck_convert_incompatible)
2193 << ArgTyIndex << SemaRef.Context.UnsignedIntTy << 1 << 0 << 0;
2194 return true;
2195 }
2196
2197 // Ensure input expr type is a scalar/vector and the same as the return type
2198 if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0))
2199 return true;
2200
2201 ExprResult Expr = TheCall->getArg(0);
2202 QualType ArgTyExpr = Expr.get()->getType();
2203 TheCall->setType(ArgTyExpr);
2204 break;
2205 }
2206 case Builtin::BI__builtin_hlsl_wave_get_lane_index: {
2207 if (SemaRef.checkArgCount(TheCall, 0))
2208 return true;
2209 break;
2210 }
2211 case Builtin::BI__builtin_hlsl_elementwise_splitdouble: {
2212 if (SemaRef.checkArgCount(TheCall, 3))
2213 return true;
2214
2215 if (CheckScalarOrVector(&SemaRef, TheCall, SemaRef.Context.DoubleTy, 0) ||
2217 1) ||
2219 2))
2220 return true;
2221
2222 if (CheckModifiableLValue(&SemaRef, TheCall, 1) ||
2223 CheckModifiableLValue(&SemaRef, TheCall, 2))
2224 return true;
2225 break;
2226 }
2227 case Builtin::BI__builtin_hlsl_elementwise_clip: {
2228 if (SemaRef.checkArgCount(TheCall, 1))
2229 return true;
2230
2232 return true;
2233 break;
2234 }
2235 case Builtin::BI__builtin_elementwise_acos:
2236 case Builtin::BI__builtin_elementwise_asin:
2237 case Builtin::BI__builtin_elementwise_atan:
2238 case Builtin::BI__builtin_elementwise_atan2:
2239 case Builtin::BI__builtin_elementwise_ceil:
2240 case Builtin::BI__builtin_elementwise_cos:
2241 case Builtin::BI__builtin_elementwise_cosh:
2242 case Builtin::BI__builtin_elementwise_exp:
2243 case Builtin::BI__builtin_elementwise_exp2:
2244 case Builtin::BI__builtin_elementwise_floor:
2245 case Builtin::BI__builtin_elementwise_fmod:
2246 case Builtin::BI__builtin_elementwise_log:
2247 case Builtin::BI__builtin_elementwise_log2:
2248 case Builtin::BI__builtin_elementwise_log10:
2249 case Builtin::BI__builtin_elementwise_pow:
2250 case Builtin::BI__builtin_elementwise_roundeven:
2251 case Builtin::BI__builtin_elementwise_sin:
2252 case Builtin::BI__builtin_elementwise_sinh:
2253 case Builtin::BI__builtin_elementwise_sqrt:
2254 case Builtin::BI__builtin_elementwise_tan:
2255 case Builtin::BI__builtin_elementwise_tanh:
2256 case Builtin::BI__builtin_elementwise_trunc: {
2258 return true;
2259 break;
2260 }
2261 case Builtin::BI__builtin_hlsl_buffer_update_counter: {
2262 auto checkResTy = [](const HLSLAttributedResourceType *ResTy) -> bool {
2263 return !(ResTy->getAttrs().ResourceClass == ResourceClass::UAV &&
2264 ResTy->getAttrs().RawBuffer && ResTy->hasContainedType());
2265 };
2266 if (SemaRef.checkArgCount(TheCall, 2) ||
2267 CheckResourceHandle(&SemaRef, TheCall, 0, checkResTy) ||
2268 CheckArgTypeMatches(&SemaRef, TheCall->getArg(1),
2270 return true;
2271 Expr *OffsetExpr = TheCall->getArg(1);
2272 std::optional<llvm::APSInt> Offset =
2274 if (!Offset.has_value() || std::abs(Offset->getExtValue()) != 1) {
2275 SemaRef.Diag(TheCall->getArg(1)->getBeginLoc(),
2276 diag::err_hlsl_expect_arg_const_int_one_or_neg_one)
2277 << 1;
2278 return true;
2279 }
2280 break;
2281 }
2282 }
2283 return false;
2284}
2285
2289 WorkList.push_back(BaseTy);
2290 while (!WorkList.empty()) {
2291 QualType T = WorkList.pop_back_val();
2292 T = T.getCanonicalType().getUnqualifiedType();
2293 assert(!isa<MatrixType>(T) && "Matrix types not yet supported in HLSL");
2294 if (const auto *AT = dyn_cast<ConstantArrayType>(T)) {
2295 llvm::SmallVector<QualType, 16> ElementFields;
2296 // Generally I've avoided recursion in this algorithm, but arrays of
2297 // structs could be time-consuming to flatten and churn through on the
2298 // work list. Hopefully nesting arrays of structs containing arrays
2299 // of structs too many levels deep is unlikely.
2300 BuildFlattenedTypeList(AT->getElementType(), ElementFields);
2301 // Repeat the element's field list n times.
2302 for (uint64_t Ct = 0; Ct < AT->getZExtSize(); ++Ct)
2303 List.insert(List.end(), ElementFields.begin(), ElementFields.end());
2304 continue;
2305 }
2306 // Vectors can only have element types that are builtin types, so this can
2307 // add directly to the list instead of to the WorkList.
2308 if (const auto *VT = dyn_cast<VectorType>(T)) {
2309 List.insert(List.end(), VT->getNumElements(), VT->getElementType());
2310 continue;
2311 }
2312 if (const auto *RT = dyn_cast<RecordType>(T)) {
2313 const RecordDecl *RD = RT->getDecl();
2314 if (RD->isUnion()) {
2315 List.push_back(T);
2316 continue;
2317 }
2318 const CXXRecordDecl *CXXD = dyn_cast<CXXRecordDecl>(RD);
2319
2321 if (CXXD && CXXD->isStandardLayout())
2323
2324 for (const auto *FD : RD->fields())
2325 FieldTypes.push_back(FD->getType());
2326 // Reverse the newly added sub-range.
2327 std::reverse(FieldTypes.begin(), FieldTypes.end());
2328 WorkList.insert(WorkList.end(), FieldTypes.begin(), FieldTypes.end());
2329
2330 // If this wasn't a standard layout type we may also have some base
2331 // classes to deal with.
2332 if (CXXD && !CXXD->isStandardLayout()) {
2333 FieldTypes.clear();
2334 for (const auto &Base : CXXD->bases())
2335 FieldTypes.push_back(Base.getType());
2336 std::reverse(FieldTypes.begin(), FieldTypes.end());
2337 WorkList.insert(WorkList.end(), FieldTypes.begin(), FieldTypes.end());
2338 }
2339 continue;
2340 }
2341 List.push_back(T);
2342 }
2343}
2344
2346 // null and array types are not allowed.
2347 if (QT.isNull() || QT->isArrayType())
2348 return false;
2349
2350 // UDT types are not allowed
2351 if (QT->isRecordType())
2352 return false;
2353
2354 if (QT->isBooleanType() || QT->isEnumeralType())
2355 return false;
2356
2357 // the only other valid builtin types are scalars or vectors
2358 if (QT->isArithmeticType()) {
2359 if (SemaRef.Context.getTypeSize(QT) / 8 > 16)
2360 return false;
2361 return true;
2362 }
2363
2364 if (const VectorType *VT = QT->getAs<VectorType>()) {
2365 int ArraySize = VT->getNumElements();
2366
2367 if (ArraySize > 4)
2368 return false;
2369
2370 QualType ElTy = VT->getElementType();
2371 if (ElTy->isBooleanType())
2372 return false;
2373
2374 if (SemaRef.Context.getTypeSize(QT) / 8 > 16)
2375 return false;
2376 return true;
2377 }
2378
2379 return false;
2380}
2381
2383 if (T1.isNull() || T2.isNull())
2384 return false;
2385
2388
2389 // If both types are the same canonical type, they're obviously compatible.
2390 if (SemaRef.getASTContext().hasSameType(T1, T2))
2391 return true;
2392
2394 BuildFlattenedTypeList(T1, T1Types);
2396 BuildFlattenedTypeList(T2, T2Types);
2397
2398 // Check the flattened type list
2399 return llvm::equal(T1Types, T2Types,
2400 [this](QualType LHS, QualType RHS) -> bool {
2401 return SemaRef.IsLayoutCompatible(LHS, RHS);
2402 });
2403}
2404
2406 FunctionDecl *Old) {
2407 if (New->getNumParams() != Old->getNumParams())
2408 return true;
2409
2410 bool HadError = false;
2411
2412 for (unsigned i = 0, e = New->getNumParams(); i != e; ++i) {
2413 ParmVarDecl *NewParam = New->getParamDecl(i);
2414 ParmVarDecl *OldParam = Old->getParamDecl(i);
2415
2416 // HLSL parameter declarations for inout and out must match between
2417 // declarations. In HLSL inout and out are ambiguous at the call site,
2418 // but have different calling behavior, so you cannot overload a
2419 // method based on a difference between inout and out annotations.
2420 const auto *NDAttr = NewParam->getAttr<HLSLParamModifierAttr>();
2421 unsigned NSpellingIdx = (NDAttr ? NDAttr->getSpellingListIndex() : 0);
2422 const auto *ODAttr = OldParam->getAttr<HLSLParamModifierAttr>();
2423 unsigned OSpellingIdx = (ODAttr ? ODAttr->getSpellingListIndex() : 0);
2424
2425 if (NSpellingIdx != OSpellingIdx) {
2426 SemaRef.Diag(NewParam->getLocation(),
2427 diag::err_hlsl_param_qualifier_mismatch)
2428 << NDAttr << NewParam;
2429 SemaRef.Diag(OldParam->getLocation(), diag::note_previous_declaration_as)
2430 << ODAttr;
2431 HadError = true;
2432 }
2433 }
2434 return HadError;
2435}
2436
2438 assert(Param->hasAttr<HLSLParamModifierAttr>() &&
2439 "We should not get here without a parameter modifier expression");
2440 const auto *Attr = Param->getAttr<HLSLParamModifierAttr>();
2441 if (Attr->getABI() == ParameterABI::Ordinary)
2442 return ExprResult(Arg);
2443
2444 bool IsInOut = Attr->getABI() == ParameterABI::HLSLInOut;
2445 if (!Arg->isLValue()) {
2446 SemaRef.Diag(Arg->getBeginLoc(), diag::error_hlsl_inout_lvalue)
2447 << Arg << (IsInOut ? 1 : 0);
2448 return ExprError();
2449 }
2450
2452
2453 QualType Ty = Param->getType().getNonLValueExprType(Ctx);
2454
2455 // HLSL allows implicit conversions from scalars to vectors, but not the
2456 // inverse, so we need to disallow `inout` with scalar->vector or
2457 // scalar->matrix conversions.
2458 if (Arg->getType()->isScalarType() != Ty->isScalarType()) {
2459 SemaRef.Diag(Arg->getBeginLoc(), diag::error_hlsl_inout_scalar_extension)
2460 << Arg << (IsInOut ? 1 : 0);
2461 return ExprError();
2462 }
2463
2464 auto *ArgOpV = new (Ctx) OpaqueValueExpr(Param->getBeginLoc(), Arg->getType(),
2465 VK_LValue, OK_Ordinary, Arg);
2466
2467 // Parameters are initialized via copy initialization. This allows for
2468 // overload resolution of argument constructors.
2469 InitializedEntity Entity =
2471 ExprResult Res =
2472 SemaRef.PerformCopyInitialization(Entity, Param->getBeginLoc(), ArgOpV);
2473 if (Res.isInvalid())
2474 return ExprError();
2475 Expr *Base = Res.get();
2476 // After the cast, drop the reference type when creating the exprs.
2477 Ty = Ty.getNonLValueExprType(Ctx);
2478 auto *OpV = new (Ctx)
2480
2481 // Writebacks are performed with `=` binary operator, which allows for
2482 // overload resolution on writeback result expressions.
2484 tok::equal, ArgOpV, OpV);
2485
2486 if (Res.isInvalid())
2487 return ExprError();
2488 Expr *Writeback = Res.get();
2489 auto *OutExpr =
2490 HLSLOutArgExpr::Create(Ctx, Ty, ArgOpV, OpV, Writeback, IsInOut);
2491
2492 return ExprResult(OutExpr);
2493}
2494
2496 // If HLSL gains support for references, all the cites that use this will need
2497 // to be updated with semantic checking to produce errors for
2498 // pointers/references.
2499 assert(!Ty->isReferenceType() &&
2500 "Pointer and reference types cannot be inout or out parameters");
2502 Ty.addRestrict();
2503 return Ty;
2504}
2505
2507 if (VD->hasGlobalStorage()) {
2508 // make sure the declaration has a complete type
2510 VD->getLocation(),
2512 diag::err_typecheck_decl_incomplete_type)) {
2513 VD->setInvalidDecl();
2514 return;
2515 }
2516
2517 // find all resources on decl
2518 if (VD->getType()->isHLSLIntangibleType())
2519 collectResourcesOnVarDecl(VD);
2520
2521 // process explicit bindings
2522 processExplicitBindingsOnDecl(VD);
2523 }
2524}
2525
2526// Walks though the global variable declaration, collects all resource binding
2527// requirements and adds them to Bindings
2528void SemaHLSL::collectResourcesOnVarDecl(VarDecl *VD) {
2529 assert(VD->hasGlobalStorage() && VD->getType()->isHLSLIntangibleType() &&
2530 "expected global variable that contains HLSL resource");
2531
2532 // Cbuffers and Tbuffers are HLSLBufferDecl types
2533 if (const HLSLBufferDecl *CBufferOrTBuffer = dyn_cast<HLSLBufferDecl>(VD)) {
2534 Bindings.addDeclBindingInfo(VD, CBufferOrTBuffer->isCBuffer()
2535 ? ResourceClass::CBuffer
2536 : ResourceClass::SRV);
2537 return;
2538 }
2539
2540 // Unwrap arrays
2541 // FIXME: Calculate array size while unwrapping
2542 const Type *Ty = VD->getType()->getUnqualifiedDesugaredType();
2543 while (Ty->isConstantArrayType()) {
2544 const ConstantArrayType *CAT = cast<ConstantArrayType>(Ty);
2546 }
2547
2548 // Resource (or array of resources)
2549 if (const HLSLAttributedResourceType *AttrResType =
2551 Bindings.addDeclBindingInfo(VD, AttrResType->getAttrs().ResourceClass);
2552 return;
2553 }
2554
2555 // User defined record type
2556 if (const RecordType *RT = dyn_cast<RecordType>(Ty))
2557 collectResourcesOnUserRecordDecl(VD, RT);
2558}
2559
2560// Walks though the explicit resource binding attributes on the declaration,
2561// and makes sure there is a resource that matched the binding and updates
2562// DeclBindingInfoLists
2563void SemaHLSL::processExplicitBindingsOnDecl(VarDecl *VD) {
2564 assert(VD->hasGlobalStorage() && "expected global variable");
2565
2566 for (Attr *A : VD->attrs()) {
2567 HLSLResourceBindingAttr *RBA = dyn_cast<HLSLResourceBindingAttr>(A);
2568 if (!RBA)
2569 continue;
2570
2571 RegisterType RT = RBA->getRegisterType();
2572 assert(RT != RegisterType::I && "invalid or obsolete register type should "
2573 "never have an attribute created");
2574
2575 if (RT == RegisterType::C) {
2576 if (Bindings.hasBindingInfoForDecl(VD))
2577 SemaRef.Diag(VD->getLocation(),
2578 diag::warn_hlsl_user_defined_type_missing_member)
2579 << static_cast<int>(RT);
2580 continue;
2581 }
2582
2583 // Find DeclBindingInfo for this binding and update it, or report error
2584 // if it does not exist (user type does to contain resources with the
2585 // expected resource class).
2586 ResourceClass RC = getResourceClass(RT);
2587 if (DeclBindingInfo *BI = Bindings.getDeclBindingInfo(VD, RC)) {
2588 // update binding info
2589 BI->setBindingAttribute(RBA, BindingType::Explicit);
2590 } else {
2591 SemaRef.Diag(VD->getLocation(),
2592 diag::warn_hlsl_user_defined_type_missing_member)
2593 << static_cast<int>(RT);
2594 }
2595 }
2596}
Defines the clang::ASTContext interface.
Defines enum values for all the target-independent builtin functions.
const Decl * D
Expr * E
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
StringRef Identifier
Definition: Format.cpp:3059
const Environment & Env
Definition: HTMLLogger.cpp:147
#define X(type, name)
Definition: Value.h:144
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
static bool CheckArgTypeMatches(Sema *S, Expr *Arg, QualType ExpectedType)
Definition: SemaHLSL.cpp:1732
static void BuildFlattenedTypeList(QualType BaseTy, llvm::SmallVectorImpl< QualType > &List)
Definition: SemaHLSL.cpp:2286
static QualType handleIntegerVectorBinOpConversion(Sema &SemaRef, ExprResult &LHS, ExprResult &RHS, QualType LHSType, QualType RHSType, QualType LElTy, QualType RElTy, bool IsCompAssign)
Definition: SemaHLSL.cpp:512
static bool convertToRegisterType(StringRef Slot, RegisterType *RT)
Definition: SemaHLSL.cpp:61
static void castVector(Sema &S, ExprResult &E, QualType &Ty, unsigned Sz)
Definition: SemaHLSL.cpp:475
static bool CheckBoolSelect(Sema *S, CallExpr *TheCall)
Definition: SemaHLSL.cpp:1868
static bool CheckVectorElementCallArgs(Sema *S, CallExpr *TheCall)
Definition: SemaHLSL.cpp:1682
static bool DiagnoseHLSLRegisterAttribute(Sema &S, SourceLocation &ArgLoc, Decl *D, RegisterType RegType, bool SpecifiedSpace)
Definition: SemaHLSL.cpp:1219
static bool CheckUnsignedIntRepresentation(Sema *S, CallExpr *TheCall)
Definition: SemaHLSL.cpp:1818
static bool CheckFloatingOrIntRepresentation(Sema *S, CallExpr *TheCall)
Definition: SemaHLSL.cpp:1809
static bool CheckNoDoubleVectors(Sema *S, CallExpr *TheCall)
Definition: SemaHLSL.cpp:1800
static bool CheckAnyScalarOrVector(Sema *S, CallExpr *TheCall, unsigned ArgIndex)
Definition: SemaHLSL.cpp:1852
static void SetElementTypeAsReturnType(Sema *S, CallExpr *TheCall, QualType ReturnType)
Definition: SemaHLSL.cpp:1826
static unsigned calculateLegacyCbufferSize(const ASTContext &Context, QualType T)
Definition: SemaHLSL.cpp:169
static RegisterType getRegisterType(ResourceClass RC)
Definition: SemaHLSL.cpp:45
static bool CheckModifiableLValue(Sema *S, CallExpr *TheCall, unsigned ArgIndex)
Definition: SemaHLSL.cpp:1789
static QualType castElement(Sema &S, ExprResult &E, QualType Ty)
Definition: SemaHLSL.cpp:483
static bool CheckArgTypeIsCorrect(Sema *S, Expr *Arg, QualType ExpectedType, llvm::function_ref< bool(clang::QualType PassedType)> Check)
Definition: SemaHLSL.cpp:1742
static bool CheckVectorSelect(Sema *S, CallExpr *TheCall)
Definition: SemaHLSL.cpp:1884
static QualType handleFloatVectorBinOpConversion(Sema &SemaRef, ExprResult &LHS, ExprResult &RHS, QualType LHSType, QualType RHSType, QualType LElTy, QualType RElTy, bool IsCompAssign)
Definition: SemaHLSL.cpp:488
static ResourceClass getResourceClass(RegisterType RT)
Definition: SemaHLSL.cpp:93
static bool CheckFloatOrHalfRepresentations(Sema *S, CallExpr *TheCall)
Definition: SemaHLSL.cpp:1777
static bool CheckScalarOrVector(Sema *S, CallExpr *TheCall, QualType Scalar, unsigned ArgIndex)
Definition: SemaHLSL.cpp:1835
static bool CheckAllArgsHaveFloatRepresentation(Sema *S, CallExpr *TheCall)
Definition: SemaHLSL.cpp:1769
static bool CheckResourceHandle(Sema *S, CallExpr *TheCall, unsigned ArgIndex, llvm::function_ref< bool(const HLSLAttributedResourceType *ResType)> Check=nullptr)
Definition: SemaHLSL.cpp:1924
static void validatePackoffset(Sema &S, HLSLBufferDecl *BufDecl)
Definition: SemaHLSL.cpp:207
HLSLResourceBindingAttr::RegisterType RegisterType
Definition: SemaHLSL.cpp:43
static CastKind getScalarCastKind(ASTContext &Ctx, QualType DestTy, QualType SrcTy)
Definition: SemaHLSL.cpp:565
static bool isValidWaveSizeValue(unsigned Value)
Definition: SemaHLSL.cpp:713
static bool CheckAllArgTypesAreCorrect(Sema *S, CallExpr *TheCall, QualType ExpectedType, llvm::function_ref< bool(clang::QualType PassedType)> Check)
Definition: SemaHLSL.cpp:1757
static bool ValidateMultipleRegisterAnnotations(Sema &S, Decl *TheDecl, RegisterType regType)
Definition: SemaHLSL.cpp:1194
static bool DiagnoseLocalRegisterBinding(Sema &S, SourceLocation &ArgLoc, Decl *D, RegisterType RegType, bool SpecifiedSpace)
Definition: SemaHLSL.cpp:1120
This file declares semantic analysis for HLSL constructs.
SourceRange Range
Definition: SemaObjC.cpp:758
SourceLocation Loc
Definition: SemaObjC.cpp:759
Defines the clang::SourceLocation class and associated facilities.
Defines the clang::TypeLoc interface and its subclasses.
C Language Family Type Representation.
SourceLocation Begin
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:188
const ConstantArrayType * getAsConstantArrayType(QualType T) const
Definition: ASTContext.h:2915
int getIntegerTypeOrder(QualType LHS, QualType RHS) const
Return the highest ranked integer type, see C99 6.3.1.8p1.
CanQualType FloatTy
Definition: ASTContext.h:1172
bool hasSameType(QualType T1, QualType T2) const
Determine whether the given types T1 and T2 are equivalent.
Definition: ASTContext.h:2732
CanQualType DoubleTy
Definition: ASTContext.h:1172
QualType getVectorType(QualType VectorType, unsigned NumElts, VectorKind VecKind) const
Return the unique reference to a vector type of the specified element type and size.
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
QualType getLValueReferenceType(QualType T, bool SpelledAsLValue=true) const
Return the uniqued reference to the type for an lvalue reference to the specified type.
QualType getBaseElementType(const ArrayType *VAT) const
Return the innermost element type of an array type.
int getFloatingTypeOrder(QualType LHS, QualType RHS) const
Compare the rank of the two specified floating point types, ignoring the domain of the type (i....
CanQualType IntTy
Definition: ASTContext.h:1169
bool hasSameUnqualifiedType(QualType T1, QualType T2) const
Determine whether the given types are equivalent after cvr-qualifiers have been removed.
Definition: ASTContext.h:2763
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
Definition: ASTContext.h:2482
CanQualType UnsignedIntTy
Definition: ASTContext.h:1170
QualType getExtVectorType(QualType VectorType, unsigned NumElts) const
Return the unique reference to an extended vector type of the specified element type and size.
const TargetInfo & getTargetInfo() const
Definition: ASTContext.h:799
QualType getHLSLAttributedResourceType(QualType Wrapped, QualType Contained, const HLSLAttributedResourceType::Attributes &Attrs)
unsigned getTypeAlign(QualType T) const
Return the ABI-specified alignment of a (complete) type T, in bits.
Definition: ASTContext.h:2513
PtrTy get() const
Definition: Ownership.h:170
bool isInvalid() const
Definition: Ownership.h:166
QualType getElementType() const
Definition: Type.h:3589
Attr - This represents one attribute.
Definition: Attr.h:43
attr::Kind getKind() const
Definition: Attr.h:89
SourceLocation getLoc() const
Represents a C++ struct/union/class.
Definition: DeclCXX.h:258
bool isStandardLayout() const
Determine whether this class is standard-layout per C++ [class]p7.
Definition: DeclCXX.h:1237
base_class_range bases()
Definition: DeclCXX.h:620
const CXXRecordDecl * getStandardLayoutBaseWithFields() const
If this is a standard-layout class or union, any and all data members will be declared in the same ty...
Definition: DeclCXX.cpp:566
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2874
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: Expr.h:3068
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:3047
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition: Expr.h:3055
Represents the canonical version of C arrays with a specified constant size.
Definition: Type.h:3615
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition: DeclBase.h:1435
decl_range decls() const
decls_begin/decls_end - Iterate over the declarations stored in this context.
Definition: DeclBase.h:2349
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:576
void addAttr(Attr *A)
Definition: DeclBase.cpp:1010
attr_iterator attr_end() const
Definition: DeclBase.h:545
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
Definition: DeclBase.h:596
void setInvalidDecl(bool Invalid=true)
setInvalidDecl - Indicates the Decl had a semantic error.
Definition: DeclBase.cpp:151
bool isInExportDeclContext() const
Whether this declaration was exported in a lexical context.
Definition: DeclBase.cpp:1109
attr_iterator attr_begin() const
Definition: DeclBase.h:542
SourceLocation getLocation() const
Definition: DeclBase.h:442
DeclContext * getDeclContext()
Definition: DeclBase.h:451
attr_range attrs() const
Definition: DeclBase.h:538
SourceLocation getBeginLoc() const LLVM_READONLY
Definition: DeclBase.h:434
void dropAttr()
Definition: DeclBase.h:559
bool hasAttr() const
Definition: DeclBase.h:580
SourceLocation getBeginLoc() const LLVM_READONLY
Definition: Decl.h:786
Recursive AST visitor that supports extension via dynamic dispatch.
This represents one expression.
Definition: Expr.h:110
isModifiableLvalueResult isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc=nullptr) const
isModifiableLvalue - C99 6.3.2.1: an lvalue that does not have array type, does not have an incomplet...
void setType(QualType t)
Definition: Expr.h:143
bool isLValue() const
isLValue - True if this expression is an "l-value" according to the rules of the current language.
Definition: Expr.h:277
Expr * IgnoreCasts() LLVM_READONLY
Skip past any casts which might surround this expression until reaching a fixed point.
Definition: Expr.cpp:3074
void setValueKind(ExprValueKind Cat)
setValueKind - Set the value kind produced by this expression.
Definition: Expr.h:454
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
std::optional< llvm::APSInt > getIntegerConstantExpr(const ASTContext &Ctx, SourceLocation *Loc=nullptr) const
isIntegerConstantExpr - Return the value if this expression is a valid integer constant expression.
@ MLV_Valid
Definition: Expr.h:298
QualType getType() const
Definition: Expr.h:142
Represents a member of a struct/union/class.
Definition: Decl.h:3033
static FixItHint CreateReplacement(CharSourceRange RemoveRange, StringRef Code)
Create a code modification hint that replaces the given source range with the given code string.
Definition: Diagnostic.h:138
Represents a function declaration or definition.
Definition: Decl.h:1935
const ParmVarDecl * getParamDecl(unsigned i) const
Definition: Decl.h:2672
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
Definition: Decl.cpp:3243
bool isThisDeclarationADefinition() const
Returns whether this specific declaration of the function is also a definition that does not contain ...
Definition: Decl.h:2249
ArrayRef< ParmVarDecl * > parameters() const
Definition: Decl.h:2649
unsigned getNumParams() const
Return the number of parameters this function must have based on its FunctionType.
Definition: Decl.cpp:3702
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
Definition: Decl.cpp:3163
static const HLSLAttributedResourceType * findHandleTypeOnResource(const Type *RT)
Definition: Type.cpp:5433
HLSLBufferDecl - Represent a cbuffer or tbuffer declaration.
Definition: Decl.h:4939
static HLSLBufferDecl * Create(ASTContext &C, DeclContext *LexicalParent, bool CBuffer, SourceLocation KwLoc, IdentifierInfo *ID, SourceLocation IDLoc, SourceLocation LBrace)
Definition: Decl.cpp:5662
static HLSLOutArgExpr * Create(const ASTContext &C, QualType Ty, OpaqueValueExpr *Base, OpaqueValueExpr *OpV, Expr *WB, bool IsInOut)
Definition: Expr.cpp:5413
One of these records is kept for each identifier that is lexed.
StringRef getName() const
Return the actual identifier string.
Describes an entity that is being initialized.
static InitializedEntity InitializeParameter(ASTContext &Context, ParmVarDecl *Parm)
Create the initialization entity for a parameter.
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition: Expr.h:3236
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
Definition: Expr.h:3319
This represents a decl that may have a name.
Definition: Decl.h:253
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Definition: Decl.h:280
OpaqueValueExpr - An expression referring to an opaque object of a fixed type and value class.
Definition: Expr.h:1173
Represents a parameter to a function.
Definition: Decl.h:1725
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:260
unsigned getMinArgs() const
Definition: ParsedAttr.cpp:146
bool checkExactlyNumArgs(class Sema &S, unsigned Num) const
Check if the attribute has exactly as many args as Num.
Definition: ParsedAttr.cpp:296
IdentifierLoc * getArgAsIdent(unsigned Arg) const
Definition: ParsedAttr.h:404
bool hasParsedType() const
Definition: ParsedAttr.h:352
const ParsedType & getTypeArg() const
Definition: ParsedAttr.h:474
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:400
Expr * getArgAsExpr(unsigned Arg) const
Definition: ParsedAttr.h:398
AttributeCommonInfo::Kind getKind() const
Definition: ParsedAttr.h:625
A (possibly-)qualified type.
Definition: Type.h:929
void addRestrict()
Add the restrict qualifier to this QualType.
Definition: Type.h:1167
QualType getNonLValueExprType(const ASTContext &Context) const
Determine the type of a (typically non-lvalue) expression with the specified result type.
Definition: Type.cpp:3521
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition: Type.h:996
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition: Type.h:7931
QualType getCanonicalType() const
Definition: Type.h:7983
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
Definition: Type.h:8025
Represents a struct/union/class.
Definition: Decl.h:4160
field_range fields() const
Definition: Decl.h:4366
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
Definition: Type.h:6072
RecordDecl * getDecl() const
Definition: Type.h:6082
redecl_range redecls() const
Returns an iterator range for all the redeclarations of the same decl.
Definition: Redeclarable.h:295
bool hasBindingInfoForDecl(const VarDecl *VD) const
Definition: SemaHLSL.cpp:138
DeclBindingInfo * getDeclBindingInfo(const VarDecl *VD, ResourceClass ResClass)
Definition: SemaHLSL.cpp:124
DeclBindingInfo * addDeclBindingInfo(const VarDecl *VD, ResourceClass ResClass)
Definition: SemaHLSL.cpp:111
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
ExprResult ActOnOutParamExpr(ParmVarDecl *Param, Expr *Arg)
Definition: SemaHLSL.cpp:2437
void DiagnoseAttrStageMismatch(const Attr *A, llvm::Triple::EnvironmentType Stage, std::initializer_list< llvm::Triple::EnvironmentType > AllowedStages)
Definition: SemaHLSL.cpp:460
void handleWaveSizeAttr(Decl *D, const ParsedAttr &AL)
Definition: SemaHLSL.cpp:717
HLSLAttributedResourceLocInfo TakeLocForHLSLAttribute(const HLSLAttributedResourceType *RT)
Definition: SemaHLSL.cpp:1065
QualType ProcessResourceTypeAttributes(QualType Wrapped)
Definition: SemaHLSL.cpp:1042
void handleSV_GroupThreadIDAttr(Decl *D, const ParsedAttr &AL)
Definition: SemaHLSL.cpp:803
void handleShaderAttr(Decl *D, const ParsedAttr &AL)
Definition: SemaHLSL.cpp:869
void handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL)
Definition: SemaHLSL.cpp:794
void CheckEntryPoint(FunctionDecl *FD)
Definition: SemaHLSL.cpp:365
void emitLogicalOperatorFixIt(Expr *LHS, Expr *RHS, BinaryOperatorKind Opc)
Definition: SemaHLSL.cpp:644
HLSLNumThreadsAttr * mergeNumThreadsAttr(Decl *D, const AttributeCommonInfo &AL, int X, int Y, int Z)
Definition: SemaHLSL.cpp:265
void handlePackOffsetAttr(Decl *D, const ParsedAttr &AL)
Definition: SemaHLSL.cpp:820
void CheckSemanticAnnotation(FunctionDecl *EntryPoint, const Decl *Param, const HLSLAnnotationAttr *AnnotationAttr)
Definition: SemaHLSL.cpp:439
bool diagnoseInputIDType(QualType T, const ParsedAttr &AL)
Definition: SemaHLSL.cpp:781
void handleParamModifierAttr(Decl *D, const ParsedAttr &AL)
Definition: SemaHLSL.cpp:1318
bool IsScalarizedLayoutCompatible(QualType T1, QualType T2) const
Definition: SemaHLSL.cpp:2382
bool CheckCompatibleParameterABI(FunctionDecl *New, FunctionDecl *Old)
Definition: SemaHLSL.cpp:2405
QualType handleVectorBinOpConversion(ExprResult &LHS, ExprResult &RHS, QualType LHSType, QualType RHSType, bool IsCompAssign)
Definition: SemaHLSL.cpp:577
void handleResourceBindingAttr(Decl *D, const ParsedAttr &AL)
Definition: SemaHLSL.cpp:1236
bool IsTypedResourceElementCompatible(QualType T1)
Definition: SemaHLSL.cpp:2345
void handleNumThreadsAttr(Decl *D, const ParsedAttr &AL)
Definition: SemaHLSL.cpp:662
void DiagnoseAvailabilityViolations(TranslationUnitDecl *TU)
Definition: SemaHLSL.cpp:1668
void ActOnTopLevelFunction(FunctionDecl *FD)
Definition: SemaHLSL.cpp:332
bool handleResourceTypeAttr(QualType T, const ParsedAttr &AL)
Definition: SemaHLSL.cpp:973
HLSLShaderAttr * mergeShaderAttr(Decl *D, const AttributeCommonInfo &AL, llvm::Triple::EnvironmentType ShaderType)
Definition: SemaHLSL.cpp:299
void ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace)
Definition: SemaHLSL.cpp:256
HLSLParamModifierAttr * mergeParamModifierAttr(Decl *D, const AttributeCommonInfo &AL, HLSLParamModifierAttr::Spelling Spelling)
Definition: SemaHLSL.cpp:312
QualType getInoutParameterType(QualType Ty)
Definition: SemaHLSL.cpp:2495
SemaHLSL(Sema &S)
Definition: SemaHLSL.cpp:142
Decl * ActOnStartBuffer(Scope *BufferScope, bool CBuffer, SourceLocation KwLoc, IdentifierInfo *Ident, SourceLocation IdentLoc, SourceLocation LBrace)
Definition: SemaHLSL.cpp:144
HLSLWaveSizeAttr * mergeWaveSizeAttr(Decl *D, const AttributeCommonInfo &AL, int Min, int Max, int Preferred, int SpelledArgsCount)
Definition: SemaHLSL.cpp:279
void handleSV_GroupIDAttr(Decl *D, const ParsedAttr &AL)
Definition: SemaHLSL.cpp:812
void ActOnVariableDeclarator(VarDecl *VD)
Definition: SemaHLSL.cpp:2506
bool CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall)
Definition: SemaHLSL.cpp:1949
Sema - This implements semantic analysis and AST building for C.
Definition: Sema.h:464
Scope * getCurScope() const
Retrieve the parser's current scope.
Definition: Sema.h:732
ASTContext & Context
Definition: Sema.h:909
void PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext=true)
Add this decl to the scope shadowed decl chains.
Definition: SemaDecl.cpp:1497
ASTContext & getASTContext() const
Definition: Sema.h:532
ExprResult ImpCastExprToType(Expr *E, QualType Type, CastKind CK, ExprValueKind VK=VK_PRValue, const CXXCastPath *BasePath=nullptr, CheckedConversionKind CCK=CheckedConversionKind::Implicit)
ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast.
Definition: Sema.cpp:692
bool BuiltinVectorToScalarMath(CallExpr *TheCall)
bool IsLayoutCompatible(QualType T1, QualType T2) const
const LangOptions & getLangOpts() const
Definition: Sema.h:525
bool PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall)
DeclContext * getCurLexicalContext() const
Definition: Sema.h:736
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:4423
bool BuiltinElementwiseTernaryMath(CallExpr *TheCall, bool CheckForFloatArgs=true)
ExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc, tok::TokenKind Kind, Expr *LHSExpr, Expr *RHSExpr)
Binary Operators. 'Tok' is the token for the operator.
Definition: SemaExpr.cpp:15271
bool checkArgCount(CallExpr *Call, unsigned DesiredArgCount)
Checks that a call expression's argument count is the desired number.
bool RequireCompleteType(SourceLocation Loc, QualType T, CompleteTypeKind Kind, TypeDiagnoser &Diagnoser)
Ensure that the type T is a complete type.
Definition: SemaType.cpp:9068
void PushDeclContext(Scope *S, DeclContext *DC)
Set the current declaration context until it gets popped.
Definition: SemaDecl.cpp:1308
ExprResult PerformCopyInitialization(const InitializedEntity &Entity, SourceLocation EqualLoc, ExprResult Init, bool TopLevelOfInitList=false, bool AllowExplicit=false)
Definition: SemaInit.cpp:9713
void PopDeclContext()
Definition: SemaDecl.cpp:1315
static QualType GetTypeFromParser(ParsedType Ty, TypeSourceInfo **TInfo=nullptr)
Definition: SemaType.cpp:2750
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:357
void printPretty(raw_ostream &OS, PrinterHelper *Helper, const PrintingPolicy &Policy, unsigned Indentation=0, StringRef NewlineSymbol="\n", const ASTContext *Context=nullptr) const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:333
SourceLocation getBeginLoc() const LLVM_READONLY
Definition: Stmt.cpp:345
bool isUnion() const
Definition: Decl.h:3782
Exposes information about the current target.
Definition: TargetInfo.h:220
TargetOptions & getTargetOpts() const
Retrieve the target options.
Definition: TargetInfo.h:311
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
Definition: TargetInfo.h:1262
StringRef getPlatformName() const
Retrieve the name of the platform as it is used in the availability attribute.
Definition: TargetInfo.h:1666
VersionTuple getPlatformMinVersion() const
Retrieve the minimum desired version of the platform, to which the program should be compiled.
Definition: TargetInfo.h:1670
std::string HLSLEntry
The entry point name for HLSL shader being compiled as specified by -E.
The top declaration context.
Definition: Decl.h:84
SourceLocation getBeginLoc() const
Get the begin source location.
Definition: TypeLoc.cpp:192
A container of type source information.
Definition: Type.h:7902
TypeLoc getTypeLoc() const
Return the TypeLoc wrapper for the type source info.
Definition: TypeLoc.h:256
The base class of the type hierarchy.
Definition: Type.h:1828
bool isStructureType() const
Definition: Type.cpp:662
bool isBooleanType() const
Definition: Type.h:8638
bool isIncompleteArrayType() const
Definition: Type.h:8266
bool isConstantArrayType() const
Definition: Type.h:8262
bool isArrayType() const
Definition: Type.h:8258
bool isArithmeticType() const
Definition: Type.cpp:2315
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
Definition: Type.h:8550
const T * castAs() const
Member-template castAs<specific type>.
Definition: Type.h:8800
bool isReferenceType() const
Definition: Type.h:8204
bool isHLSLIntangibleType() const
Definition: Type.cpp:5103
bool isEnumeralType() const
Definition: Type.h:8290
bool isScalarType() const
Definition: Type.h:8609
bool isIntegralType(const ASTContext &Ctx) const
Determine whether this type is an integral type.
Definition: Type.cpp:2092
const Type * getArrayElementTypeNoTypeQual() const
If this is an array type, return the element type of the array, potentially with type qualifiers miss...
Definition: Type.cpp:460
bool hasUnsignedIntegerRepresentation() const
Determine whether this type has an unsigned integer representation of some sort, e....
Definition: Type.cpp:2270
bool isAggregateType() const
Determines whether the type is a C++ aggregate type or C aggregate or union type.
Definition: Type.cpp:2372
bool isFloat32Type() const
Definition: Type.h:8523
bool isHalfType() const
Definition: Type.h:8514
bool hasSignedIntegerRepresentation() const
Determine whether this type has an signed integer representation of some sort, e.g....
Definition: Type.cpp:2220
bool hasFloatingRepresentation() const
Determine whether this type has a floating-point representation of some sort, e.g....
Definition: Type.cpp:2292
bool isVectorType() const
Definition: Type.h:8298
bool isRealFloatingType() const
Floating point categories.
Definition: Type.cpp:2300
bool isFloatingType() const
Definition: Type.cpp:2283
const T * getAs() const
Member-template getAs<specific type>'.
Definition: Type.h:8731
const Type * getUnqualifiedDesugaredType() const
Return the specified type with any "sugar" removed from the type, removing any typedefs,...
Definition: Type.cpp:638
bool isRecordType() const
Definition: Type.h:8286
QualType getType() const
Definition: Decl.h:682
Represents a variable declaration or definition.
Definition: Decl.h:882
bool hasGlobalStorage() const
Returns true for all variables that do not have local storage.
Definition: Decl.h:1177
Represents a GCC generic vector type.
Definition: Type.h:4034
unsigned getNumElements() const
Definition: Type.h:4049
Defines the clang::TargetInfo interface.
const internal::VariadicAllOfMatcher< Attr > attr
Matches attributes.
The JSON file list parser is used to communicate input to InstallAPI.
@ OK_Ordinary
An ordinary object is located at an address in memory.
Definition: Specifiers.h:151
BinaryOperatorKind
@ AANT_ArgumentIdentifier
Definition: ParsedAttr.h:1081
@ Result
The result type of a method or function.
@ Ordinary
This parameter uses ordinary ABI rules for its type.
ActionResult< Expr * > ExprResult
Definition: Ownership.h:248
ExprResult ExprError()
Definition: Ownership.h:264
bool CreateHLSLAttributedResourceType(Sema &S, QualType Wrapped, ArrayRef< const Attr * > AttrList, QualType &ResType, HLSLAttributedResourceLocInfo *LocInfo=nullptr)
Definition: SemaHLSL.cpp:889
CastKind
CastKind - The kind of operation required for a conversion.
@ VK_LValue
An l-value expression is a reference to an object with independent storage.
Definition: Specifiers.h:139
const FunctionProtoType * T
@ Generic
not a target-specific vector type
Diagnostic wrappers for TextAPI types for error reporting.
Definition: Dominators.h:30
__DEVICE__ _Tp abs(const std::complex< _Tp > &__c)
Definition: complex_cmath.h:34
#define false
Definition: stdbool.h:26
TypeSourceInfo * ContainedTyInfo
Definition: TypeLoc.h:945
llvm::dxil::ResourceClass ResourceClass
Definition: Type.h:6255
Wraps an identifier and optional source location for the identifier.
Definition: ParsedAttr.h:103
Describes how types, statements, expressions, and declarations should be printed.
Definition: PrettyPrinter.h:57