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