Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/Sema/SemaHLSL.cpp
35233 views
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
1125