clang 24.0.0git
CGHLSLBuiltins.cpp
Go to the documentation of this file.
1//===------- CGHLSLBuiltins.cpp - Emit LLVM Code for HLSL builtins --------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This contains code to emit HLSL Builtin calls as LLVM code.
10//
11//===----------------------------------------------------------------------===//
12
13#include "CGBuiltin.h"
14#include "CGHLSLRuntime.h"
15#include "CodeGenFunction.h"
18#include "llvm/IR/MatrixBuilder.h"
19
20using namespace clang;
21using namespace CodeGen;
22using namespace llvm;
23
27 "asdouble operands types mismatch");
28 Value *OpLowBits = CGF.EmitScalarExpr(E->getArg(0));
29 Value *OpHighBits = CGF.EmitScalarExpr(E->getArg(1));
30
31 llvm::Type *ResultType = CGF.DoubleTy;
32 int N = 1;
33 if (auto *VTy = E->getArg(0)->getType()->getAs<clang::VectorType>()) {
34 N = VTy->getNumElements();
35 ResultType = llvm::FixedVectorType::get(CGF.DoubleTy, N);
36 }
37
38 if (CGF.CGM.getTarget().getTriple().isDXIL())
39 return CGF.Builder.CreateIntrinsic(
40 /*ReturnType=*/ResultType, Intrinsic::dx_asdouble,
41 {OpLowBits, OpHighBits}, nullptr, "hlsl.asdouble");
42
43 if (!E->getArg(0)->getType()->isVectorType()) {
44 OpLowBits = CGF.Builder.CreateVectorSplat(1, OpLowBits);
45 OpHighBits = CGF.Builder.CreateVectorSplat(1, OpHighBits);
46 }
47
49 for (int i = 0; i < N; i++) {
50 Mask.push_back(i);
51 Mask.push_back(i + N);
52 }
53
54 Value *BitVec = CGF.Builder.CreateShuffleVector(OpLowBits, OpHighBits, Mask);
55
56 return CGF.Builder.CreateBitCast(BitVec, ResultType);
57}
58
60 Value *Op0 = CGF->EmitScalarExpr(E->getArg(0));
61
62 Constant *FZeroConst = ConstantFP::getZero(CGF->FloatTy);
63 Value *CMP;
64 Value *LastInstr;
65
66 if (const auto *VecTy = E->getArg(0)->getType()->getAs<clang::VectorType>()) {
67 FZeroConst = ConstantVector::getSplat(
68 ElementCount::getFixed(VecTy->getNumElements()), FZeroConst);
69 auto *FCompInst = CGF->Builder.CreateFCmpOLT(Op0, FZeroConst);
70 CMP = CGF->Builder.CreateIntrinsic(
71 CGF->Builder.getInt1Ty(), CGF->CGM.getHLSLRuntime().getAnyIntrinsic(),
72 {FCompInst});
73 } else {
74 CMP = CGF->Builder.CreateFCmpOLT(Op0, FZeroConst);
75 }
76
77 if (CGF->CGM.getTarget().getTriple().isDXIL()) {
78 LastInstr = CGF->Builder.CreateIntrinsic(Intrinsic::dx_discard, {CMP});
79 } else if (CGF->CGM.getTarget().getTriple().isSPIRV()) {
80 BasicBlock *LT0 = CGF->createBasicBlock("lt0", CGF->CurFn);
81 BasicBlock *End = CGF->createBasicBlock("end", CGF->CurFn);
82
83 CGF->Builder.CreateCondBr(CMP, LT0, End);
84
85 CGF->Builder.SetInsertPoint(LT0);
86
87 CGF->Builder.CreateIntrinsic(Intrinsic::spv_discard, {});
88
89 LastInstr = CGF->Builder.CreateBr(End);
90 CGF->Builder.SetInsertPoint(End);
91 } else {
92 llvm_unreachable("Backend Codegen not supported.");
93 }
94
95 return LastInstr;
96}
97
99 Value *Op0 = CGF->EmitScalarExpr(E->getArg(0));
100 const auto *OutArg1 = dyn_cast<HLSLOutArgExpr>(E->getArg(1));
101 const auto *OutArg2 = dyn_cast<HLSLOutArgExpr>(E->getArg(2));
102
103 CallArgList Args;
104 LValue Op1TmpLValue =
105 CGF->EmitHLSLOutArgExpr(OutArg1, Args, OutArg1->getType());
106 LValue Op2TmpLValue =
107 CGF->EmitHLSLOutArgExpr(OutArg2, Args, OutArg2->getType());
108
110 Args.reverseWritebacks();
111
112 Value *LowBits = nullptr;
113 Value *HighBits = nullptr;
114
115 if (CGF->CGM.getTarget().getTriple().isDXIL()) {
116 llvm::Type *RetElementTy = CGF->Int32Ty;
117 if (auto *Op0VecTy = E->getArg(0)->getType()->getAs<clang::VectorType>())
118 RetElementTy = llvm::VectorType::get(
119 CGF->Int32Ty, ElementCount::getFixed(Op0VecTy->getNumElements()));
120 else if (auto *Op0MatTy =
122 RetElementTy = llvm::VectorType::get(
123 CGF->Int32Ty, ElementCount::getFixed(Op0MatTy->getNumRows() *
124 Op0MatTy->getNumColumns()));
125
126 auto *RetTy = llvm::StructType::get(RetElementTy, RetElementTy);
127
128 Value *CI = CGF->Builder.CreateIntrinsic(
129 RetTy, Intrinsic::dx_splitdouble, {Op0}, nullptr, "hlsl.splitdouble");
130
131 LowBits = CGF->Builder.CreateExtractValue(CI, 0);
132 HighBits = CGF->Builder.CreateExtractValue(CI, 1);
133 } else {
134 // For Non DXIL targets we generate the instructions.
135
136 if (!Op0->getType()->isVectorTy()) {
137 FixedVectorType *DestTy = FixedVectorType::get(CGF->Int32Ty, 2);
138 Value *Bitcast = CGF->Builder.CreateBitCast(Op0, DestTy);
139
140 LowBits = CGF->Builder.CreateExtractElement(Bitcast, (uint64_t)0);
141 HighBits = CGF->Builder.CreateExtractElement(Bitcast, 1);
142 } else {
143 int NumElements = 1;
144 if (const auto *VecTy =
146 NumElements = VecTy->getNumElements();
147 else if (const auto *MatTy =
149 NumElements = MatTy->getNumRows() * MatTy->getNumColumns();
150
151 FixedVectorType *Uint32VecTy =
152 FixedVectorType::get(CGF->Int32Ty, NumElements * 2);
153 Value *Uint32Vec = CGF->Builder.CreateBitCast(Op0, Uint32VecTy);
154 if (NumElements == 1) {
155 LowBits = CGF->Builder.CreateExtractElement(Uint32Vec, (uint64_t)0);
156 HighBits = CGF->Builder.CreateExtractElement(Uint32Vec, 1);
157 } else {
158 SmallVector<int> EvenMask, OddMask;
159 for (int I = 0, E = NumElements; I != E; ++I) {
160 EvenMask.push_back(I * 2);
161 OddMask.push_back(I * 2 + 1);
162 }
163 LowBits = CGF->Builder.CreateShuffleVector(Uint32Vec, EvenMask);
164 HighBits = CGF->Builder.CreateShuffleVector(Uint32Vec, OddMask);
165 }
166 }
167 }
168 CGF->Builder.CreateStore(LowBits, Op1TmpLValue.getAddress());
169 auto *LastInst =
170 CGF->Builder.CreateStore(HighBits, Op2TmpLValue.getAddress());
171 CGF->EmitWritebacks(Args);
172 return LastInst;
173}
174
176 const CallExpr *E) {
177 Value *Cond = CGF.EmitScalarExpr(E->getArg(0));
178 llvm::Type *I32 = CGF.Int32Ty;
179
180 llvm::Type *Vec4I32 = llvm::FixedVectorType::get(I32, 4);
181 [[maybe_unused]] llvm::StructType *Struct4I32 =
182 llvm::StructType::get(CGF.getLLVMContext(), {I32, I32, I32, I32});
183
184 if (CGF.CGM.getTarget().getTriple().isDXIL()) {
185 // Call DXIL intrinsic: returns { i32, i32, i32, i32 }
186 Value *StructVal =
187 CGF.EmitIntrinsicCall(Intrinsic::dx_wave_ballot, {I32}, {Cond});
188 assert(StructVal->getType() == Struct4I32 &&
189 "dx.wave.ballot must return {i32,i32,i32,i32}");
190
191 // Reassemble struct to <4 x i32>
192 llvm::Value *VecVal = llvm::PoisonValue::get(Vec4I32);
193 for (unsigned I = 0; I < 4; ++I) {
194 Value *Elt = CGF.Builder.CreateExtractValue(StructVal, I);
195 VecVal =
196 CGF.Builder.CreateInsertElement(VecVal, Elt, CGF.Builder.getInt32(I));
197 }
198
199 return VecVal;
200 }
201
202 if (CGF.CGM.getTarget().getTriple().isSPIRV())
203 return CGF.EmitIntrinsicCall(Intrinsic::spv_subgroup_ballot, {Cond});
204
205 llvm_unreachable(
206 "WaveActiveBallot is only supported for DXIL and SPIRV targets");
207}
208
210 const CallExpr *E) {
211 Value *Op0 = CGF.EmitScalarExpr(E->getArg(0));
212 QualType Op0Ty = E->getArg(0)->getType();
213 llvm::Type *ResType = CGF.FloatTy;
214 uint64_t NumElements = 0;
215 if (Op0->getType()->isVectorTy()) {
216 NumElements =
217 E->getArg(0)->getType()->castAs<clang::VectorType>()->getNumElements();
218 ResType =
219 llvm::VectorType::get(ResType, ElementCount::getFixed(NumElements));
220 }
222 llvm_unreachable(
223 "f16tof32 operand must have an unsigned int representation");
224
225 if (CGF.CGM.getTriple().isDXIL())
226 return CGF.Builder.CreateIntrinsic(ResType, Intrinsic::dx_legacyf16tof32,
227 ArrayRef<Value *>{Op0}, nullptr,
228 "hlsl.f16tof32");
229
230 if (CGF.CGM.getTriple().isSPIRV()) {
231 // We use the SPIRV UnpackHalf2x16 operation to avoid the need for the
232 // Int16 and Float16 capabilities
233 auto *UnpackType =
234 llvm::VectorType::get(CGF.FloatTy, ElementCount::getFixed(2));
235
236 if (NumElements == 0) {
237 // a scalar input - simply extract the first element of the unpacked
238 // vector
239 Value *Unpack = CGF.Builder.CreateIntrinsic(
240 UnpackType, Intrinsic::spv_unpackhalf2x16, ArrayRef<Value *>{Op0});
241 return CGF.Builder.CreateExtractElement(Unpack, (uint64_t)0);
242 }
243
244 // a vector input - build a congruent output vector by iterating through
245 // the input vector calling unpackhalf2x16 for each element
246 Value *Result = PoisonValue::get(ResType);
247 for (uint64_t I = 0; I < NumElements; I++) {
248 Value *InVal = CGF.Builder.CreateExtractElement(Op0, I);
249 Value *Unpack = CGF.Builder.CreateIntrinsic(
250 UnpackType, Intrinsic::spv_unpackhalf2x16, ArrayRef<Value *>{InVal});
251 Value *Res = CGF.Builder.CreateExtractElement(Unpack, (uint64_t)0);
252 Result = CGF.Builder.CreateInsertElement(Result, Res, I);
253 }
254 return Result;
255 }
256
257 llvm_unreachable("Intrinsic F16ToF32 not supported by target architecture");
258}
259
261 const CallExpr *E) {
262 Value *Op0 = CGF.EmitScalarExpr(E->getArg(0));
263 QualType Op0Ty = E->getArg(0)->getType();
264 llvm::Type *ResType = CGF.IntTy;
265 uint64_t NumElements = 0;
266 if (Op0->getType()->isVectorTy()) {
267 NumElements =
268 E->getArg(0)->getType()->castAs<clang::VectorType>()->getNumElements();
269 ResType =
270 llvm::VectorType::get(ResType, ElementCount::getFixed(NumElements));
271 }
272 if (!Op0Ty->hasFloatingRepresentation())
273 llvm_unreachable("f32tof16 operand must have a float representation");
274
275 if (CGF.CGM.getTriple().isDXIL())
276 return CGF.Builder.CreateIntrinsic(ResType, Intrinsic::dx_legacyf32tof16,
277 ArrayRef<Value *>{Op0}, nullptr,
278 "hlsl.f32tof16");
279
280 if (CGF.CGM.getTriple().isSPIRV()) {
281 // We use the SPIRV PackHalf2x16 operation to avoid the need for the
282 // Int16 and Float16 capabilities
283 auto *PackType =
284 llvm::VectorType::get(CGF.FloatTy, ElementCount::getFixed(2));
285
286 if (NumElements == 0) {
287 // a scalar input - simply insert the scalar in the first element
288 // of the 2 element float vector
289 Value *Float2 = Constant::getNullValue(PackType);
290 Float2 = CGF.Builder.CreateInsertElement(Float2, Op0, (uint64_t)0);
291 Value *Result = CGF.Builder.CreateIntrinsic(
292 ResType, Intrinsic::spv_packhalf2x16, ArrayRef<Value *>{Float2});
293 return Result;
294 }
295
296 // a vector input - build a congruent output vector by iterating through
297 // the input vector calling packhalf2x16 for each element
298 Value *Result = PoisonValue::get(ResType);
299 for (uint64_t I = 0; I < NumElements; I++) {
300 Value *Float2 = Constant::getNullValue(PackType);
301 Value *InVal = CGF.Builder.CreateExtractElement(Op0, I);
302 Float2 = CGF.Builder.CreateInsertElement(Float2, InVal, (uint64_t)0);
303 Value *Res = CGF.Builder.CreateIntrinsic(
304 CGF.IntTy, Intrinsic::spv_packhalf2x16, ArrayRef<Value *>{Float2});
305 Result = CGF.Builder.CreateInsertElement(Result, Res, I);
306 }
307 return Result;
308 }
309
310 llvm_unreachable("Intrinsic F32ToF16 not supported by target architecture");
311}
312
314 llvm::AtomicRMWInst::BinOp Op) {
315 // Emit `atomicrmw <op>` directly — no intermediate intrinsic needed on
316 // either DXIL or SPIR-V.
317 LValue DestLV = CGF.EmitLValue(E->getArg(0));
318 Address DestAddr = DestLV.getAddress();
319 Value *Val = CGF.EmitScalarExpr(E->getArg(1));
320 assert(E->getArg(1)->getType()->isIntegerType() &&
321 "Intrinsic InterlockedOp value operand must be an integer");
322
323 llvm::AtomicRMWInst *Call = CGF.Builder.CreateAtomicRMW(
324 Op, DestAddr, Val, llvm::AtomicOrdering::Monotonic);
325
326 // The 3-arg overload writes the old value (the RMW's return value) into
327 // the `original_value` reference parameter.
328 if (E->getNumArgs() == 3) {
329 LValue OrigLV = CGF.EmitLValue(E->getArg(2));
331 }
332 return Call;
333}
334
335static Value *emitBufferStride(CodeGenFunction *CGF, const Expr *HandleExpr,
336 LValue &Stride) {
337 // Figure out the stride of the buffer elements from the handle type.
338 auto *HandleTy =
340 QualType ElementTy = HandleTy->getContainedType();
341 Value *StrideValue = CGF->getTypeSize(ElementTy);
342 return CGF->Builder.CreateStore(StrideValue, Stride.getAddress());
343}
344
345// Return dot product intrinsic that corresponds to the QT scalar type
346static Intrinsic::ID getDotProductIntrinsic(CGHLSLRuntime &RT, QualType QT) {
347 if (QT->isFloatingType())
348 return RT.getFDotIntrinsic();
349 if (QT->isSignedIntegerType())
350 return RT.getSDotIntrinsic();
351 assert(QT->isUnsignedIntegerType());
352 return RT.getUDotIntrinsic();
353}
354
355static Intrinsic::ID getFirstBitHighIntrinsic(CGHLSLRuntime &RT, QualType QT) {
357 return RT.getFirstBitSHighIntrinsic();
358 }
359
361 return RT.getFirstBitUHighIntrinsic();
362}
363
364// Return wave active sum that corresponds to the QT scalar type
365static Intrinsic::ID getWaveActiveSumIntrinsic(llvm::Triple::ArchType Arch,
366 QualType QT) {
367 switch (Arch) {
368 case llvm::Triple::spirv:
369 return Intrinsic::spv_wave_reduce_sum;
370 case llvm::Triple::dxil: {
371 if (QT->isUnsignedIntegerType())
372 return Intrinsic::dx_wave_reduce_usum;
373 return Intrinsic::dx_wave_reduce_sum;
374 }
375 default:
376 llvm_unreachable("Intrinsic WaveActiveSum"
377 " not supported by target architecture");
378 }
379}
380
381// Return wave active product that corresponds to the QT scalar type
382static Intrinsic::ID getWaveActiveProductIntrinsic(llvm::Triple::ArchType Arch,
383 QualType QT) {
384 switch (Arch) {
385 case llvm::Triple::spirv:
386 return Intrinsic::spv_wave_product;
387 case llvm::Triple::dxil: {
388 if (QT->isUnsignedIntegerType())
389 return Intrinsic::dx_wave_uproduct;
390 return Intrinsic::dx_wave_product;
391 }
392 default:
393 llvm_unreachable("Intrinsic WaveActiveProduct"
394 " not supported by target architecture");
395 }
396}
397
398static Intrinsic::ID getPrefixCountBitsIntrinsic(llvm::Triple::ArchType Arch) {
399 switch (Arch) {
400 case llvm::Triple::spirv:
401 return Intrinsic::spv_subgroup_prefix_bit_count;
402 case llvm::Triple::dxil: {
403 return Intrinsic::dx_wave_prefix_bit_count;
404 }
405 default:
406 llvm_unreachable(
407 "WavePrefixOp instruction not supported by target architecture");
408 }
409}
410
411// Return wave prefix sum that corresponds to the QT scalar type
412static Intrinsic::ID getWavePrefixSumIntrinsic(llvm::Triple::ArchType Arch,
413 QualType QT) {
414 switch (Arch) {
415 case llvm::Triple::spirv:
416 return Intrinsic::spv_wave_prefix_sum;
417 case llvm::Triple::dxil: {
418 if (QT->isUnsignedIntegerType())
419 return Intrinsic::dx_wave_prefix_usum;
420 return Intrinsic::dx_wave_prefix_sum;
421 }
422 default:
423 llvm_unreachable("Intrinsic WavePrefixSum"
424 " not supported by target architecture");
425 }
426}
427
428// Return wave prefix product that corresponds to the QT scalar type
429static Intrinsic::ID getWavePrefixProductIntrinsic(llvm::Triple::ArchType Arch,
430 QualType QT) {
431 switch (Arch) {
432 case llvm::Triple::spirv:
433 return Intrinsic::spv_wave_prefix_product;
434 case llvm::Triple::dxil: {
435 if (QT->isUnsignedIntegerType())
436 return Intrinsic::dx_wave_prefix_uproduct;
437 return Intrinsic::dx_wave_prefix_product;
438 }
439 default:
440 llvm_unreachable("Intrinsic WavePrefixProduct"
441 " not supported by target architecture");
442 }
443}
444
445// Returns the mangled name for a builtin function that the SPIR-V backend
446// will expand into a spec Constant.
447static std::string getSpecConstantFunctionName(clang::QualType SpecConstantType,
448 ASTContext &Context) {
449 // The parameter types for our conceptual intrinsic function.
450 QualType ClangParamTypes[] = {Context.IntTy, SpecConstantType};
451
452 // Create a temporary FunctionDecl for the builtin fuction. It won't be
453 // added to the AST.
455 QualType FnType =
456 Context.getFunctionType(SpecConstantType, ClangParamTypes, EPI);
457 DeclarationName FuncName = &Context.Idents.get("__spirv_SpecConstant");
458 FunctionDecl *FnDeclForMangling = FunctionDecl::Create(
459 Context, Context.getTranslationUnitDecl(), SourceLocation(),
460 SourceLocation(), FuncName, FnType, /*TSI=*/nullptr, SC_Extern);
461
462 // Attach the created parameter declarations to the function declaration.
464 for (QualType ParamType : ClangParamTypes) {
466 Context, FnDeclForMangling, SourceLocation(), SourceLocation(),
467 /*IdentifierInfo*/ nullptr, ParamType, /*TSI*/ nullptr, SC_None,
468 /*DefaultArg*/ nullptr);
469 ParamDecls.push_back(PD);
470 }
471 FnDeclForMangling->setParams(ParamDecls);
472
473 // Get the mangled name.
474 std::string Name;
475 llvm::raw_string_ostream MangledNameStream(Name);
476 std::unique_ptr<MangleContext> Mangler(Context.createMangleContext());
477 Mangler->mangleName(FnDeclForMangling, MangledNameStream);
478 MangledNameStream.flush();
479
480 return Name;
481}
482
483static const HLSLAttributedResourceType *
485 if (const auto *RT = HandleQT->getAs<HLSLAttributedResourceType>())
486 return RT;
487 // If the expr is a texture/sampler record (or similar), peel to __handle.
488 if (const HLSLAttributedResourceType *RT =
489 HLSLAttributedResourceType::findHandleTypeOnResource(
490 HandleQT.getTypePtr()))
491 return RT;
492 llvm_unreachable("attributed handle type not found");
493}
494
495static const HLSLAttributedResourceType *
496getRequiredHandleType(const CallExpr *E, unsigned ArgNo) {
497 return getHandleAttributedType(E->getArg(ArgNo)->getType());
498}
499
500static llvm::Type *getOffsetType(CodeGenModule &CGM,
501 const HLSLAttributedResourceType *RT) {
502 const auto &Attrs = RT->getAttrs();
503 unsigned OffsetSize =
504 clang::hlsl::getResourceDimensions(Attrs.ResourceDimension);
505 llvm::Type *Int32Ty = CGM.Int32Ty;
506 if (OffsetSize == 1)
507 return Int32Ty;
508 return llvm::FixedVectorType::get(Int32Ty, OffsetSize);
509}
510
512 unsigned OffsetArgIndex, llvm::Type *OffsetTy) {
513 if (E->getNumArgs() > OffsetArgIndex)
514 return CGF.EmitScalarExpr(E->getArg(OffsetArgIndex));
515
516 return llvm::Constant::getNullValue(OffsetTy);
517}
518
520 unsigned ClampArgIndex) {
521 Value *Clamp = CGF.EmitScalarExpr(E->getArg(ClampArgIndex));
522 // The builtin is defined with variadic arguments, so the clamp parameter
523 // might have been promoted to double. The intrinsic requires a 32-bit
524 // float.
525 if (Clamp->getType() != CGF.Builder.getFloatTy())
526 Clamp = CGF.Builder.CreateFPCast(Clamp, CGF.Builder.getFloatTy());
527 return Clamp;
528}
529
531 unsigned IntrinsicID, unsigned NumRetComps,
532 bool HasLod) {
533 Value *Handle = CGF.EmitScalarExpr(E->getArg(0));
534
535 SmallVector<Value *> Args{Handle};
536 if (HasLod)
537 Args.push_back(CGF.EmitScalarExpr(E->getArg(1)));
538
539 Value *DimValue =
540 CGF.Builder.CreateIntrinsic(IntrinsicID, {Handle->getType()}, Args);
541
542 Value *LastStore = nullptr;
543 unsigned ArgIndex = HasLod ? 2 : 1;
544 for (unsigned i = 0; i < NumRetComps; ++i) {
545 const Expr *Arg = E->getArg(ArgIndex++);
546 LValue DimOut = CGF.EmitLValue(Arg);
547 Value *Elem = DimValue;
548 if (NumRetComps > 1)
549 Elem = CGF.Builder.CreateExtractElement(DimValue, i);
550
551 // Handle float casting if needed
552 if (Arg->getType()->isFloatingType())
553 Elem = CGF.Builder.CreateUIToFP(
554 Elem, llvm::Type::getFloatTy(CGF.getLLVMContext()));
555
556 LastStore = CGF.Builder.CreateStore(Elem, DimOut.getAddress());
557 }
558 return LastStore;
559}
560
562 const CallExpr *E,
564 if (!getLangOpts().HLSL)
565 return nullptr;
566
567 switch (BuiltinID) {
568 case Builtin::BI__builtin_hlsl_adduint64: {
569 Value *OpA = EmitScalarExpr(E->getArg(0));
570 Value *OpB = EmitScalarExpr(E->getArg(1));
571 QualType Arg0Ty = E->getArg(0)->getType();
572 uint64_t NumElements = Arg0Ty->castAs<VectorType>()->getNumElements();
573 assert(Arg0Ty == E->getArg(1)->getType() &&
574 "AddUint64 operand types must match");
575 assert(Arg0Ty->hasIntegerRepresentation() &&
576 "AddUint64 operands must have an integer representation");
577 assert((NumElements == 2 || NumElements == 4) &&
578 "AddUint64 operands must have 2 or 4 elements");
579
580 llvm::Value *LowA;
581 llvm::Value *HighA;
582 llvm::Value *LowB;
583 llvm::Value *HighB;
584
585 // Obtain low and high words of inputs A and B
586 if (NumElements == 2) {
587 LowA = Builder.CreateExtractElement(OpA, (uint64_t)0, "LowA");
588 HighA = Builder.CreateExtractElement(OpA, (uint64_t)1, "HighA");
589 LowB = Builder.CreateExtractElement(OpB, (uint64_t)0, "LowB");
590 HighB = Builder.CreateExtractElement(OpB, (uint64_t)1, "HighB");
591 } else {
592 LowA = Builder.CreateShuffleVector(OpA, {0, 2}, "LowA");
593 HighA = Builder.CreateShuffleVector(OpA, {1, 3}, "HighA");
594 LowB = Builder.CreateShuffleVector(OpB, {0, 2}, "LowB");
595 HighB = Builder.CreateShuffleVector(OpB, {1, 3}, "HighB");
596 }
597
598 // Use an uadd_with_overflow to compute the sum of low words and obtain a
599 // carry value
600 llvm::Value *Carry;
601 llvm::Value *LowSum = EmitOverflowIntrinsic(
602 *this, Intrinsic::uadd_with_overflow, LowA, LowB, Carry);
603 llvm::Value *ZExtCarry =
604 Builder.CreateZExt(Carry, HighA->getType(), "CarryZExt");
605
606 // Sum the high words and the carry
607 llvm::Value *HighSum = Builder.CreateAdd(HighA, HighB, "HighSum");
608 llvm::Value *HighSumPlusCarry =
609 Builder.CreateAdd(HighSum, ZExtCarry, "HighSumPlusCarry");
610
611 if (NumElements == 4) {
612 return Builder.CreateShuffleVector(LowSum, HighSumPlusCarry, {0, 2, 1, 3},
613 "hlsl.AddUint64");
614 }
615
616 llvm::Value *Result = PoisonValue::get(OpA->getType());
617 Result = Builder.CreateInsertElement(Result, LowSum, (uint64_t)0,
618 "hlsl.AddUint64.upto0");
619 Result = Builder.CreateInsertElement(Result, HighSumPlusCarry, (uint64_t)1,
620 "hlsl.AddUint64");
621 return Result;
622 }
623 case Builtin::BI__builtin_hlsl_resource_getpointer:
624 case Builtin::BI__builtin_hlsl_resource_getpointer_typed: {
625 Value *HandleOp = EmitScalarExpr(E->getArg(0));
626 bool IsIndexed =
627 BuiltinID == Builtin::BI__builtin_hlsl_resource_getpointer_typed ||
628 E->getNumArgs() > 1;
629
630 llvm::Type *RetTy = ConvertType(E->getType());
631 llvm::Function *IntrFn = nullptr;
632 llvm::CallInst *CI = nullptr;
633 if (IsIndexed) {
634 Value *IndexOp = EmitScalarExpr(E->getArg(1));
635 IntrFn = llvm::Intrinsic::getOrInsertDeclaration(
636 &CGM.getModule(),
637 CGM.getHLSLRuntime().getCreateResourceGetPointerIntrinsic(),
638 {RetTy, HandleOp->getType(), IndexOp->getType()});
639 CI = EmitRuntimeCall(IntrFn, {HandleOp, IndexOp});
640 } else {
641 IntrFn = llvm::Intrinsic::getOrInsertDeclaration(
642 &CGM.getModule(),
643 CGM.getHLSLRuntime().getCreateResourceGetBasePointerIntrinsic(),
644 {RetTy, HandleOp->getType()});
645 CI = EmitRuntimeCall(IntrFn, {HandleOp});
646 }
647 CI->setCallingConv(IntrFn->getCallingConv());
648 return CI;
649 }
650 case Builtin::BI__builtin_hlsl_resource_sample: {
651 Value *HandleOp = EmitScalarExpr(E->getArg(0));
652 Value *SamplerOp = EmitScalarExpr(E->getArg(1));
653 Value *CoordOp = EmitScalarExpr(E->getArg(2));
654 const HLSLAttributedResourceType *RT = getRequiredHandleType(E, 0);
655
657 Args.push_back(HandleOp);
658 Args.push_back(SamplerOp);
659 Args.push_back(CoordOp);
660 Args.push_back(emitHlslOffset(*this, E, 3, getOffsetType(CGM, RT)));
661
662 llvm::Type *RetTy = ConvertType(E->getType());
663 if (E->getNumArgs() <= 4) {
664 return Builder.CreateIntrinsic(
665 RetTy, CGM.getHLSLRuntime().getSampleIntrinsic(), Args);
666 }
667
668 Args.push_back(emitHlslClamp(*this, E, 4));
669 return Builder.CreateIntrinsic(
670 RetTy, CGM.getHLSLRuntime().getSampleClampIntrinsic(), Args);
671 }
672 case Builtin::BI__builtin_hlsl_resource_sample_bias: {
673 Value *HandleOp = EmitScalarExpr(E->getArg(0));
674 Value *SamplerOp = EmitScalarExpr(E->getArg(1));
675 Value *CoordOp = EmitScalarExpr(E->getArg(2));
676 Value *BiasOp = EmitScalarExpr(E->getArg(3));
677 if (BiasOp->getType() != Builder.getFloatTy())
678 BiasOp = Builder.CreateFPCast(BiasOp, Builder.getFloatTy());
679 const HLSLAttributedResourceType *RT = getRequiredHandleType(E, 0);
680
681 SmallVector<Value *, 6> Args; // Max 6 arguments for SampleBias
682 Args.push_back(HandleOp);
683 Args.push_back(SamplerOp);
684 Args.push_back(CoordOp);
685 Args.push_back(BiasOp);
686 Args.push_back(emitHlslOffset(*this, E, 4, getOffsetType(CGM, RT)));
687
688 llvm::Type *RetTy = ConvertType(E->getType());
689 if (E->getNumArgs() <= 5)
690 return Builder.CreateIntrinsic(
691 RetTy, CGM.getHLSLRuntime().getSampleBiasIntrinsic(), Args);
692
693 Args.push_back(emitHlslClamp(*this, E, 5));
694 return Builder.CreateIntrinsic(
695 RetTy, CGM.getHLSLRuntime().getSampleBiasClampIntrinsic(), Args);
696 }
697 case Builtin::BI__builtin_hlsl_resource_sample_grad: {
698 Value *HandleOp = EmitScalarExpr(E->getArg(0));
699 Value *SamplerOp = EmitScalarExpr(E->getArg(1));
700 Value *CoordOp = EmitScalarExpr(E->getArg(2));
701 Value *DDXOp = EmitScalarExpr(E->getArg(3));
702 Value *DDYOp = EmitScalarExpr(E->getArg(4));
703 const HLSLAttributedResourceType *RT = getRequiredHandleType(E, 0);
704
706 Args.push_back(HandleOp);
707 Args.push_back(SamplerOp);
708 Args.push_back(CoordOp);
709 Args.push_back(DDXOp);
710 Args.push_back(DDYOp);
711 Args.push_back(emitHlslOffset(*this, E, 5, getOffsetType(CGM, RT)));
712
713 llvm::Type *RetTy = ConvertType(E->getType());
714
715 if (E->getNumArgs() <= 6) {
716 return Builder.CreateIntrinsic(
717 RetTy, CGM.getHLSLRuntime().getSampleGradIntrinsic(), Args);
718 }
719
720 Args.push_back(emitHlslClamp(*this, E, 6));
721 return Builder.CreateIntrinsic(
722 RetTy, CGM.getHLSLRuntime().getSampleGradClampIntrinsic(), Args);
723 }
724 case Builtin::BI__builtin_hlsl_resource_sample_level: {
725 Value *HandleOp = EmitScalarExpr(E->getArg(0));
726 Value *SamplerOp = EmitScalarExpr(E->getArg(1));
727 Value *CoordOp = EmitScalarExpr(E->getArg(2));
728 Value *LODOp = EmitScalarExpr(E->getArg(3));
729 if (LODOp->getType() != Builder.getFloatTy())
730 LODOp = Builder.CreateFPCast(LODOp, Builder.getFloatTy());
731 const HLSLAttributedResourceType *RT = getRequiredHandleType(E, 0);
732
733 SmallVector<Value *, 5> Args; // Max 5 arguments for SampleLevel
734 Args.push_back(HandleOp);
735 Args.push_back(SamplerOp);
736 Args.push_back(CoordOp);
737 Args.push_back(LODOp);
738 Args.push_back(emitHlslOffset(*this, E, 4, getOffsetType(CGM, RT)));
739
740 llvm::Type *RetTy = ConvertType(E->getType());
741 return Builder.CreateIntrinsic(
742 RetTy, CGM.getHLSLRuntime().getSampleLevelIntrinsic(), Args);
743 }
744 case Builtin::BI__builtin_hlsl_resource_load_level: {
745 Value *HandleOp = EmitScalarExpr(E->getArg(0));
746 Value *CoordLODOp = EmitScalarExpr(E->getArg(1));
747
748 auto *CoordLODVecTy = cast<llvm::FixedVectorType>(CoordLODOp->getType());
749 unsigned NumElts = CoordLODVecTy->getNumElements();
750 assert(NumElts >= 2 && "CoordLOD must have at least 2 elements");
751
752 // Split CoordLOD into Coord and LOD
754 for (unsigned I = 0; I < NumElts - 1; ++I)
755 Mask.push_back(I);
756
757 Value *CoordOp =
758 Builder.CreateShuffleVector(CoordLODOp, Mask, "hlsl.load.coord");
759 Value *LODOp =
760 Builder.CreateExtractElement(CoordLODOp, NumElts - 1, "hlsl.load.lod");
761 const HLSLAttributedResourceType *RT = getRequiredHandleType(E, 0);
762
764 Args.push_back(HandleOp);
765 Args.push_back(CoordOp);
766 Args.push_back(LODOp);
767 Args.push_back(emitHlslOffset(*this, E, 2, getOffsetType(CGM, RT)));
768
769 llvm::Type *RetTy = ConvertType(E->getType());
770 return Builder.CreateIntrinsic(
771 RetTy, CGM.getHLSLRuntime().getLoadLevelIntrinsic(), Args);
772 }
773 case Builtin::BI__builtin_hlsl_resource_sample_cmp: {
774 Value *HandleOp = EmitScalarExpr(E->getArg(0));
775 Value *SamplerOp = EmitScalarExpr(E->getArg(1));
776 Value *CoordOp = EmitScalarExpr(E->getArg(2));
777 Value *CmpOp = EmitScalarExpr(E->getArg(3));
778 if (CmpOp->getType() != Builder.getFloatTy())
779 CmpOp = Builder.CreateFPCast(CmpOp, Builder.getFloatTy());
780 const HLSLAttributedResourceType *RT = getRequiredHandleType(E, 0);
781
782 SmallVector<Value *, 6> Args; // Max 6 arguments for SampleCmp
783 Args.push_back(HandleOp);
784 Args.push_back(SamplerOp);
785 Args.push_back(CoordOp);
786 Args.push_back(CmpOp);
787 Args.push_back(emitHlslOffset(*this, E, 4, getOffsetType(CGM, RT)));
788
789 llvm::Type *RetTy = ConvertType(E->getType());
790 if (E->getNumArgs() <= 5) {
791 return Builder.CreateIntrinsic(
792 RetTy, CGM.getHLSLRuntime().getSampleCmpIntrinsic(), Args);
793 }
794
795 Args.push_back(emitHlslClamp(*this, E, 5));
796 return Builder.CreateIntrinsic(
797 RetTy, CGM.getHLSLRuntime().getSampleCmpClampIntrinsic(), Args);
798 }
799 case Builtin::BI__builtin_hlsl_resource_sample_cmp_level_zero: {
800 Value *HandleOp = EmitScalarExpr(E->getArg(0));
801 Value *SamplerOp = EmitScalarExpr(E->getArg(1));
802 Value *CoordOp = EmitScalarExpr(E->getArg(2));
803 Value *CmpOp = EmitScalarExpr(E->getArg(3));
804 if (CmpOp->getType() != Builder.getFloatTy())
805 CmpOp = Builder.CreateFPCast(CmpOp, Builder.getFloatTy());
806 const HLSLAttributedResourceType *RT = getRequiredHandleType(E, 0);
807
809 Args.push_back(HandleOp);
810 Args.push_back(SamplerOp);
811 Args.push_back(CoordOp);
812 Args.push_back(CmpOp);
813 Args.push_back(emitHlslOffset(*this, E, 4, getOffsetType(CGM, RT)));
814
815 llvm::Type *RetTy = ConvertType(E->getType());
816 return Builder.CreateIntrinsic(
817 RetTy, CGM.getHLSLRuntime().getSampleCmpLevelZeroIntrinsic(), Args);
818 }
819 case Builtin::BI__builtin_hlsl_resource_calculate_lod: {
820 Value *HandleOp = EmitScalarExpr(E->getArg(0));
821 Value *SamplerOp = EmitScalarExpr(E->getArg(1));
822 Value *CoordOp = EmitScalarExpr(E->getArg(2));
823
824 return Builder.CreateIntrinsic(
825 ConvertType(E->getType()),
826 CGM.getHLSLRuntime().getCalculateLodIntrinsic(),
827 {HandleOp, SamplerOp, CoordOp});
828 }
829 case Builtin::BI__builtin_hlsl_resource_calculate_lod_unclamped: {
830 Value *HandleOp = EmitScalarExpr(E->getArg(0));
831 Value *SamplerOp = EmitScalarExpr(E->getArg(1));
832 Value *CoordOp = EmitScalarExpr(E->getArg(2));
833
834 return Builder.CreateIntrinsic(
835 ConvertType(E->getType()),
836 CGM.getHLSLRuntime().getCalculateLodUnclampedIntrinsic(),
837 {HandleOp, SamplerOp, CoordOp});
838 }
839 case Builtin::BI__builtin_hlsl_resource_gather: {
840 Value *HandleOp = EmitScalarExpr(E->getArg(0));
841 Value *SamplerOp = EmitScalarExpr(E->getArg(1));
842 Value *CoordOp = EmitScalarExpr(E->getArg(2));
843 Value *ComponentOp = EmitScalarExpr(E->getArg(3));
844 if (ComponentOp->getType() != Builder.getInt32Ty())
845 ComponentOp = Builder.CreateIntCast(ComponentOp, Builder.getInt32Ty(),
846 /*isSigned=*/false);
847 const HLSLAttributedResourceType *RT = getRequiredHandleType(E, 0);
848
850 Args.push_back(HandleOp);
851 Args.push_back(SamplerOp);
852 Args.push_back(CoordOp);
853 Args.push_back(ComponentOp);
854 Args.push_back(emitHlslOffset(*this, E, 4, getOffsetType(CGM, RT)));
855
856 llvm::Type *RetTy = ConvertType(E->getType());
857 return Builder.CreateIntrinsic(
858 RetTy, CGM.getHLSLRuntime().getGatherIntrinsic(), Args);
859 }
860 case Builtin::BI__builtin_hlsl_resource_gather_cmp: {
861 Value *HandleOp = EmitScalarExpr(E->getArg(0));
862 Value *SamplerOp = EmitScalarExpr(E->getArg(1));
863 Value *CoordOp = EmitScalarExpr(E->getArg(2));
864 Value *CompareOp = EmitScalarExpr(E->getArg(3));
865 if (CompareOp->getType() != Builder.getFloatTy())
866 CompareOp = Builder.CreateFPCast(CompareOp, Builder.getFloatTy());
867
869 Args.push_back(HandleOp);
870 Args.push_back(SamplerOp);
871 Args.push_back(CoordOp);
872 Args.push_back(CompareOp);
873
874 if (CGM.getTarget().getTriple().isDXIL()) {
875 Value *ComponentOp = EmitScalarExpr(E->getArg(4));
876 if (ComponentOp->getType() != Builder.getInt32Ty())
877 ComponentOp = Builder.CreateIntCast(ComponentOp, Builder.getInt32Ty(),
878 /*isSigned=*/false);
879 Args.push_back(ComponentOp);
880 }
881
882 const HLSLAttributedResourceType *RT = getRequiredHandleType(E, 0);
883 Args.push_back(emitHlslOffset(*this, E, 5, getOffsetType(CGM, RT)));
884
885 llvm::Type *RetTy = ConvertType(E->getType());
886 return Builder.CreateIntrinsic(
887 RetTy, CGM.getHLSLRuntime().getGatherCmpIntrinsic(), Args);
888 }
889 case Builtin::BI__builtin_hlsl_resource_load_with_status:
890 case Builtin::BI__builtin_hlsl_resource_load_with_status_typed: {
891 Value *HandleOp = EmitScalarExpr(E->getArg(0));
892 Value *IndexOp = EmitScalarExpr(E->getArg(1));
893
894 // Get the *address* of the status argument to write to it by reference
895 LValue StatusLVal = EmitLValue(E->getArg(2));
896 Address StatusAddr = StatusLVal.getAddress();
897
898 QualType HandleTy = E->getArg(0)->getType();
899 const HLSLAttributedResourceType *RT =
900 HandleTy->getAs<HLSLAttributedResourceType>();
901 assert(CGM.getTarget().getTriple().getArch() == llvm::Triple::dxil &&
902 "Only DXIL currently implements load with status");
903
904 Intrinsic::ID IntrID = RT->getAttrs().RawBuffer
905 ? llvm::Intrinsic::dx_resource_load_rawbuffer
906 : llvm::Intrinsic::dx_resource_load_typedbuffer;
907
908 llvm::Type *DataTy = ConvertType(E->getType());
909 llvm::Type *RetTy = llvm::StructType::get(Builder.getContext(),
910 {DataTy, Builder.getInt1Ty()});
911
913 Args.push_back(HandleOp);
914 Args.push_back(IndexOp);
915
916 if (RT->isRaw()) {
917 Value *Offset = Builder.getInt32(0);
918 // The offset parameter needs to be poison for ByteAddressBuffer
919 if (!RT->isStructured())
920 Offset = llvm::PoisonValue::get(Builder.getInt32Ty());
921 Args.push_back(Offset);
922 }
923
924 // The load intrinsics give us a (T value, i1 status) pair -
925 // shepherd these into the return value and out reference respectively.
926 Value *ResRet =
927 Builder.CreateIntrinsic(RetTy, IntrID, Args, {}, "ld.struct");
928 Value *LoadedValue = Builder.CreateExtractValue(ResRet, {0}, "ld.value");
929 Value *StatusBit = Builder.CreateExtractValue(ResRet, {1}, "ld.status");
930 Value *ExtendedStatus =
931 Builder.CreateZExt(StatusBit, Builder.getInt32Ty(), "ld.status.ext");
932 Builder.CreateStore(ExtendedStatus, StatusAddr);
933
934 return LoadedValue;
935 }
936 case Builtin::BI__builtin_hlsl_resource_uninitializedhandle: {
937 llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType());
938 return llvm::PoisonValue::get(HandleTy);
939 }
940 case Builtin::BI__builtin_hlsl_resource_handlefrombinding: {
941 llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType());
942 Value *RegisterOp = EmitScalarExpr(E->getArg(1));
943 Value *SpaceOp = EmitScalarExpr(E->getArg(2));
944 Value *RangeOp = EmitScalarExpr(E->getArg(3));
945 Value *IndexOp = EmitScalarExpr(E->getArg(4));
946 Value *Name = EmitScalarExpr(E->getArg(5));
947 llvm::Intrinsic::ID IntrinsicID =
948 CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic();
949 SmallVector<Value *> Args{SpaceOp, RegisterOp, RangeOp, IndexOp, Name};
950 return Builder.CreateIntrinsic(HandleTy, IntrinsicID, Args);
951 }
952 case Builtin::BI__builtin_hlsl_resource_handlefromimplicitbinding: {
953 llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType());
954 Value *OrderID = EmitScalarExpr(E->getArg(1));
955 Value *SpaceOp = EmitScalarExpr(E->getArg(2));
956 Value *RangeOp = EmitScalarExpr(E->getArg(3));
957 Value *IndexOp = EmitScalarExpr(E->getArg(4));
958 Value *Name = EmitScalarExpr(E->getArg(5));
959 llvm::Intrinsic::ID IntrinsicID =
960 CGM.getHLSLRuntime().getCreateHandleFromImplicitBindingIntrinsic();
961 SmallVector<Value *> Args{OrderID, SpaceOp, RangeOp, IndexOp, Name};
962 return Builder.CreateIntrinsic(HandleTy, IntrinsicID, Args);
963 }
964 case Builtin::BI__builtin_hlsl_resource_counterhandlefromimplicitbinding: {
965 Value *MainHandle = EmitScalarExpr(E->getArg(0));
966 if (!CGM.getTriple().isSPIRV())
967 return MainHandle;
968
969 llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType());
970 Value *OrderID = EmitScalarExpr(E->getArg(1));
971 Value *SpaceOp = EmitScalarExpr(E->getArg(2));
972 llvm::Intrinsic::ID IntrinsicID =
973 llvm::Intrinsic::spv_resource_counterhandlefromimplicitbinding;
974 SmallVector<Value *> Args{MainHandle, OrderID, SpaceOp};
975 return EmitIntrinsicCall(IntrinsicID, {HandleTy, MainHandle->getType()},
976 Args);
977 }
978 case Builtin::BI__builtin_hlsl_resource_nonuniformindex: {
979 Value *IndexOp = EmitScalarExpr(E->getArg(0));
980 llvm::Type *RetTy = ConvertType(E->getType());
981 return Builder.CreateIntrinsic(
982 RetTy, CGM.getHLSLRuntime().getNonUniformResourceIndexIntrinsic(),
983 ArrayRef<Value *>{IndexOp});
984 }
985 case Builtin::BI__builtin_hlsl_resource_getdimensions_x:
986 case Builtin::BI__builtin_hlsl_resource_getdimensions_x_float:
987 return emitGetDimensions(*this, E,
988 CGM.getHLSLRuntime().getGetDimensionsXIntrinsic(),
989 1, /*HasLod=*/false);
990 case Builtin::BI__builtin_hlsl_resource_getdimensions_xy:
991 case Builtin::BI__builtin_hlsl_resource_getdimensions_xy_float:
992 return emitGetDimensions(*this, E,
993 CGM.getHLSLRuntime().getGetDimensionsXYIntrinsic(),
994 2, /*HasLod=*/false);
995 case Builtin::BI__builtin_hlsl_resource_getdimensions_levels_xy:
996 case Builtin::BI__builtin_hlsl_resource_getdimensions_levels_xy_float:
997 return emitGetDimensions(
998 *this, E, CGM.getHLSLRuntime().getGetDimensionsLevelsXYIntrinsic(), 3,
999 /*HasLod=*/true);
1000 case Builtin::BI__builtin_hlsl_resource_getstride: {
1001 LValue Stride = EmitLValue(E->getArg(1));
1002 return emitBufferStride(this, E->getArg(0), Stride);
1003 }
1004 case Builtin::BI__builtin_hlsl_all: {
1005 Value *Op0 = EmitScalarExpr(E->getArg(0));
1006 return Builder.CreateIntrinsic(
1007 /*ReturnType=*/llvm::Type::getInt1Ty(getLLVMContext()),
1008 CGM.getHLSLRuntime().getAllIntrinsic(), ArrayRef<Value *>{Op0}, nullptr,
1009 "hlsl.all");
1010 }
1011 case Builtin::BI__builtin_hlsl_and: {
1012 Value *Op0 = EmitScalarExpr(E->getArg(0));
1013 Value *Op1 = EmitScalarExpr(E->getArg(1));
1014 return Builder.CreateAnd(Op0, Op1, "hlsl.and");
1015 }
1016 case Builtin::BI__builtin_hlsl_or: {
1017 Value *Op0 = EmitScalarExpr(E->getArg(0));
1018 Value *Op1 = EmitScalarExpr(E->getArg(1));
1019 return Builder.CreateOr(Op0, Op1, "hlsl.or");
1020 }
1021 case Builtin::BI__builtin_hlsl_any: {
1022 Value *Op0 = EmitScalarExpr(E->getArg(0));
1023 return Builder.CreateIntrinsic(
1024 /*ReturnType=*/llvm::Type::getInt1Ty(getLLVMContext()),
1025 CGM.getHLSLRuntime().getAnyIntrinsic(), ArrayRef<Value *>{Op0}, nullptr,
1026 "hlsl.any");
1027 }
1028 case Builtin::BI__builtin_hlsl_asdouble:
1029 return handleAsDoubleBuiltin(*this, E);
1030 case Builtin::BI__builtin_hlsl_elementwise_clamp: {
1031 Value *OpX = EmitScalarExpr(E->getArg(0));
1032 Value *OpMin = EmitScalarExpr(E->getArg(1));
1033 Value *OpMax = EmitScalarExpr(E->getArg(2));
1034
1035 QualType Ty = E->getArg(0)->getType();
1036 if (auto *VecTy = Ty->getAs<VectorType>())
1037 Ty = VecTy->getElementType();
1038
1039 Intrinsic::ID Intr;
1040 if (Ty->isFloatingType()) {
1041 Intr = CGM.getHLSLRuntime().getNClampIntrinsic();
1042 } else if (Ty->isUnsignedIntegerType()) {
1043 Intr = CGM.getHLSLRuntime().getUClampIntrinsic();
1044 } else {
1045 assert(Ty->isSignedIntegerType());
1046 Intr = CGM.getHLSLRuntime().getSClampIntrinsic();
1047 }
1048 return Builder.CreateIntrinsic(
1049 /*ReturnType=*/OpX->getType(), Intr,
1050 ArrayRef<Value *>{OpX, OpMin, OpMax}, nullptr, "hlsl.clamp");
1051 }
1052 case Builtin::BI__builtin_hlsl_crossf16:
1053 case Builtin::BI__builtin_hlsl_crossf32: {
1054 Value *Op0 = EmitScalarExpr(E->getArg(0));
1055 Value *Op1 = EmitScalarExpr(E->getArg(1));
1056 assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
1058 "cross operands must have a float representation");
1059 // make sure each vector has exactly 3 elements
1060 assert(
1061 E->getArg(0)->getType()->castAs<VectorType>()->getNumElements() == 3 &&
1062 E->getArg(1)->getType()->castAs<VectorType>()->getNumElements() == 3 &&
1063 "input vectors must have 3 elements each");
1064 return Builder.CreateIntrinsic(
1065 /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getCrossIntrinsic(),
1066 ArrayRef<Value *>{Op0, Op1}, nullptr, "hlsl.cross");
1067 }
1068 case Builtin::BI__builtin_hlsl_dot: {
1069 Value *Op0 = EmitScalarExpr(E->getArg(0));
1070 Value *Op1 = EmitScalarExpr(E->getArg(1));
1071 llvm::Type *T0 = Op0->getType();
1072 llvm::Type *T1 = Op1->getType();
1073
1074 // If the arguments are scalars, just emit a multiply
1075 if (!T0->isVectorTy() && !T1->isVectorTy()) {
1076 if (T0->isFloatingPointTy())
1077 return Builder.CreateFMul(Op0, Op1, "hlsl.dot");
1078
1079 if (T0->isIntegerTy())
1080 return Builder.CreateMul(Op0, Op1, "hlsl.dot");
1081
1082 llvm_unreachable(
1083 "Scalar dot product is only supported on ints and floats.");
1084 }
1085 // For vectors, validate types and emit the appropriate intrinsic
1086 assert(CGM.getContext().hasSameUnqualifiedType(E->getArg(0)->getType(),
1087 E->getArg(1)->getType()) &&
1088 "Dot product operands must have the same type.");
1089
1090 auto *VecTy0 = E->getArg(0)->getType()->castAs<VectorType>();
1091 assert(VecTy0 && "Dot product argument must be a vector.");
1092
1093 return Builder.CreateIntrinsic(
1094 /*ReturnType=*/T0->getScalarType(),
1095 getDotProductIntrinsic(CGM.getHLSLRuntime(), VecTy0->getElementType()),
1096 ArrayRef<Value *>{Op0, Op1}, nullptr, "hlsl.dot");
1097 }
1098 case Builtin::BI__builtin_hlsl_dot4add_i8packed: {
1099 Value *X = EmitScalarExpr(E->getArg(0));
1100 Value *Y = EmitScalarExpr(E->getArg(1));
1101 Value *Acc = EmitScalarExpr(E->getArg(2));
1102
1103 Intrinsic::ID ID = CGM.getHLSLRuntime().getDot4AddI8PackedIntrinsic();
1104 // Note that the argument order disagrees between the builtin and the
1105 // intrinsic here.
1106 return Builder.CreateIntrinsic(
1107 /*ReturnType=*/Acc->getType(), ID, ArrayRef<Value *>{Acc, X, Y},
1108 nullptr, "hlsl.dot4add.i8packed");
1109 }
1110 case Builtin::BI__builtin_hlsl_dot4add_u8packed: {
1111 Value *X = EmitScalarExpr(E->getArg(0));
1112 Value *Y = EmitScalarExpr(E->getArg(1));
1113 Value *Acc = EmitScalarExpr(E->getArg(2));
1114
1115 Intrinsic::ID ID = CGM.getHLSLRuntime().getDot4AddU8PackedIntrinsic();
1116 // Note that the argument order disagrees between the builtin and the
1117 // intrinsic here.
1118 return Builder.CreateIntrinsic(
1119 /*ReturnType=*/Acc->getType(), ID, ArrayRef<Value *>{Acc, X, Y},
1120 nullptr, "hlsl.dot4add.u8packed");
1121 }
1122 case Builtin::BI__builtin_hlsl_elementwise_firstbithigh: {
1123 Value *X = EmitScalarExpr(E->getArg(0));
1124
1125 return Builder.CreateIntrinsic(
1126 /*ReturnType=*/ConvertType(E->getType()),
1127 getFirstBitHighIntrinsic(CGM.getHLSLRuntime(), E->getArg(0)->getType()),
1128 ArrayRef<Value *>{X}, nullptr, "hlsl.firstbithigh");
1129 }
1130 case Builtin::BI__builtin_hlsl_elementwise_firstbitlow: {
1131 Value *X = EmitScalarExpr(E->getArg(0));
1132
1133 return Builder.CreateIntrinsic(
1134 /*ReturnType=*/ConvertType(E->getType()),
1135 CGM.getHLSLRuntime().getFirstBitLowIntrinsic(), ArrayRef<Value *>{X},
1136 nullptr, "hlsl.firstbitlow");
1137 }
1138 case Builtin::BI__builtin_hlsl_lerp: {
1139 Value *X = EmitScalarExpr(E->getArg(0));
1140 Value *Y = EmitScalarExpr(E->getArg(1));
1141 Value *S = EmitScalarExpr(E->getArg(2));
1142 if (!E->getArg(0)->getType()->hasFloatingRepresentation())
1143 llvm_unreachable("lerp operand must have a float representation");
1144 return Builder.CreateIntrinsic(
1145 /*ReturnType=*/X->getType(), CGM.getHLSLRuntime().getLerpIntrinsic(),
1146 ArrayRef<Value *>{X, Y, S}, nullptr, "hlsl.lerp");
1147 }
1148 case Builtin::BI__builtin_hlsl_normalize: {
1149 Value *X = EmitScalarExpr(E->getArg(0));
1150
1151 assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
1152 "normalize operand must have a float representation");
1153
1154 return Builder.CreateIntrinsic(
1155 /*ReturnType=*/X->getType(),
1156 CGM.getHLSLRuntime().getNormalizeIntrinsic(), ArrayRef<Value *>{X},
1157 nullptr, "hlsl.normalize");
1158 }
1159 case Builtin::BI__builtin_hlsl_elementwise_degrees: {
1160 Value *X = EmitScalarExpr(E->getArg(0));
1161
1162 assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
1163 "degree operand must have a float representation");
1164
1165 return Builder.CreateIntrinsic(
1166 /*ReturnType=*/X->getType(), CGM.getHLSLRuntime().getDegreesIntrinsic(),
1167 ArrayRef<Value *>{X}, nullptr, "hlsl.degrees");
1168 }
1169 case Builtin::BI__builtin_hlsl_elementwise_f16tof32: {
1170 return handleElementwiseF16ToF32(*this, E);
1171 }
1172 case Builtin::BI__builtin_hlsl_elementwise_f32tof16: {
1173 return handleElementwiseF32ToF16(*this, E);
1174 }
1175 case Builtin::BI__builtin_hlsl_elementwise_frac: {
1176 Value *Op0 = EmitScalarExpr(E->getArg(0));
1177 if (!E->getArg(0)->getType()->hasFloatingRepresentation())
1178 llvm_unreachable("frac operand must have a float representation");
1179 return Builder.CreateIntrinsic(
1180 /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getFracIntrinsic(),
1181 ArrayRef<Value *>{Op0}, nullptr, "hlsl.frac");
1182 }
1183 case Builtin::BI__builtin_hlsl_elementwise_isinf: {
1184 Value *Op0 = EmitScalarExpr(E->getArg(0));
1185 llvm::Type *Xty = Op0->getType();
1186 llvm::Type *retType = llvm::Type::getInt1Ty(this->getLLVMContext());
1187 if (Xty->isVectorTy()) {
1188 auto *XVecTy = E->getArg(0)->getType()->castAs<VectorType>();
1189 retType = llvm::VectorType::get(
1190 retType, ElementCount::getFixed(XVecTy->getNumElements()));
1191 }
1192 if (!E->getArg(0)->getType()->hasFloatingRepresentation())
1193 llvm_unreachable("isinf operand must have a float representation");
1194 return Builder.CreateIntrinsic(
1195 retType, CGM.getHLSLRuntime().getIsInfIntrinsic(),
1196 ArrayRef<Value *>{Op0}, nullptr, "hlsl.isinf");
1197 }
1198 case Builtin::BI__builtin_hlsl_elementwise_isnan: {
1199 Value *Op0 = EmitScalarExpr(E->getArg(0));
1200 llvm::Type *Xty = Op0->getType();
1201 llvm::Type *retType = llvm::Type::getInt1Ty(this->getLLVMContext());
1202 if (Xty->isVectorTy()) {
1203 auto *XVecTy = E->getArg(0)->getType()->castAs<VectorType>();
1204 retType = llvm::VectorType::get(
1205 retType, ElementCount::getFixed(XVecTy->getNumElements()));
1206 }
1207 if (!E->getArg(0)->getType()->hasFloatingRepresentation())
1208 llvm_unreachable("isnan operand must have a float representation");
1209 return Builder.CreateIntrinsic(
1210 retType, CGM.getHLSLRuntime().getIsNaNIntrinsic(),
1211 ArrayRef<Value *>{Op0}, nullptr, "hlsl.isnan");
1212 }
1213 case Builtin::BI__builtin_hlsl_mad: {
1214 Value *M = EmitScalarExpr(E->getArg(0));
1215 Value *A = EmitScalarExpr(E->getArg(1));
1216 Value *B = EmitScalarExpr(E->getArg(2));
1218 return Builder.CreateIntrinsic(
1219 /*ReturnType*/ M->getType(), Intrinsic::fmuladd,
1220 ArrayRef<Value *>{M, A, B}, nullptr, "hlsl.fmad");
1221
1223 if (CGM.getTarget().getTriple().getArch() == llvm::Triple::dxil)
1224 return Builder.CreateIntrinsic(
1225 /*ReturnType*/ M->getType(), Intrinsic::dx_imad,
1226 ArrayRef<Value *>{M, A, B}, nullptr, "dx.imad");
1227
1228 Value *Mul = Builder.CreateNSWMul(M, A);
1229 return Builder.CreateNSWAdd(Mul, B);
1230 }
1232 if (CGM.getTarget().getTriple().getArch() == llvm::Triple::dxil)
1233 return Builder.CreateIntrinsic(
1234 /*ReturnType=*/M->getType(), Intrinsic::dx_umad,
1235 ArrayRef<Value *>{M, A, B}, nullptr, "dx.umad");
1236
1237 Value *Mul = Builder.CreateNUWMul(M, A);
1238 return Builder.CreateNUWAdd(Mul, B);
1239 }
1240 case Builtin::BI__builtin_hlsl_mul: {
1241 Value *Op0 = EmitScalarExpr(E->getArg(0));
1242 Value *Op1 = EmitScalarExpr(E->getArg(1));
1243 QualType QTy0 = E->getArg(0)->getType();
1244 QualType QTy1 = E->getArg(1)->getType();
1245
1246 bool IsVec0 = QTy0->isVectorType();
1247 bool IsVec1 = QTy1->isVectorType();
1248 bool IsMat0 = QTy0->isConstantMatrixType();
1249 bool IsMat1 = QTy1->isConstantMatrixType();
1250
1251 // The matrix multiply intrinsic only operates on column-major order
1252 // matrices. Therefore matrix memory layout transforms must be inserted
1253 // before and after matrix multiply intrinsics.
1254 // Use whichever operand is a matrix to discover its declared layout.
1255 bool IsRowMajorMat0 = IsMat0 && isMatrixRowMajor(getLangOpts(), QTy0);
1256 bool IsRowMajorMat1 = IsMat1 && isMatrixRowMajor(getLangOpts(), QTy1);
1257
1258 llvm::MatrixBuilder MB(Builder);
1259 if (IsVec0 && IsMat1) {
1260 unsigned N = QTy0->castAs<VectorType>()->getNumElements();
1261 auto *MatTy = QTy1->castAs<ConstantMatrixType>();
1262 unsigned Rows = MatTy->getNumRows();
1263 unsigned Cols = MatTy->getNumColumns();
1264 assert(N == Rows && "vector length must match matrix row count");
1265 if (IsRowMajorMat1)
1266 Op1 = MB.CreateRowMajorToColumnMajorTransform(Op1, Rows, Cols);
1267 return MB.CreateMatrixMultiply(Op0, Op1, 1, N, Cols, "hlsl.mul");
1268 }
1269 if (IsMat0 && IsVec1) {
1270 auto *MatTy = QTy0->castAs<ConstantMatrixType>();
1271 unsigned Rows = MatTy->getNumRows();
1272 unsigned Cols = MatTy->getNumColumns();
1273 assert(QTy1->castAs<VectorType>()->getNumElements() == Cols &&
1274 "vector length must match matrix column count");
1275 if (IsRowMajorMat0)
1276 Op0 = MB.CreateRowMajorToColumnMajorTransform(Op0, Rows, Cols);
1277 return MB.CreateMatrixMultiply(Op0, Op1, Rows, Cols, 1, "hlsl.mul");
1278 }
1279 assert(IsMat0 && IsMat1);
1280 auto *MatTy0 = QTy0->castAs<ConstantMatrixType>();
1281 auto *MatTy1 = QTy1->castAs<ConstantMatrixType>();
1282 unsigned Rows0 = MatTy0->getNumRows();
1283 unsigned Rows1 = MatTy1->getNumRows();
1284 unsigned Cols0 = MatTy0->getNumColumns();
1285 unsigned Cols1 = MatTy1->getNumColumns();
1286 assert(Cols0 == Rows1 &&
1287 "inner matrix dimensions must match for multiplication");
1288 if (IsRowMajorMat0)
1289 Op0 = MB.CreateRowMajorToColumnMajorTransform(Op0, Rows0, Cols0);
1290 if (IsRowMajorMat1)
1291 Op1 = MB.CreateRowMajorToColumnMajorTransform(Op1, Rows1, Cols1);
1292
1293 Value *Result =
1294 MB.CreateMatrixMultiply(Op0, Op1, Rows0, Cols0, Cols1, "hlsl.mul");
1295
1296 bool IsResultRowMajor = isMatrixRowMajor(getLangOpts(), E->getType());
1297 if (IsResultRowMajor)
1298 Result = MB.CreateColumnMajorToRowMajorTransform(Result, Rows0, Cols1);
1299 return Result;
1300 }
1301 case Builtin::BI__builtin_hlsl_transpose: {
1302 Value *Op0 = EmitScalarExpr(E->getArg(0));
1303 auto *MatTy = E->getArg(0)->getType()->castAs<ConstantMatrixType>();
1304 unsigned Rows = MatTy->getNumRows();
1305 unsigned Cols = MatTy->getNumColumns();
1306 llvm::MatrixBuilder MB(Builder);
1307 // The correct lowering of a transpose depends on both the source layout
1308 // and the result layout.
1309 bool SrcRowMajor = isMatrixRowMajor(getLangOpts(), E->getArg(0)->getType());
1310 bool DstRowMajor = isMatrixRowMajor(getLangOpts(), E->getType());
1311 // When the source & result layouts differ, the operand already holds the
1312 // transposed result, ie transpose is a no-op on the underlying vector.
1313 if (SrcRowMajor != DstRowMajor)
1314 return Op0;
1315 // When the source and result share a layout, emit a transpose.
1316 if (SrcRowMajor)
1317 // For row-major operands the dimensions are swapped
1318 return MB.CreateMatrixTranspose(Op0, Cols, Rows);
1319 return MB.CreateMatrixTranspose(Op0, Rows, Cols);
1320 }
1321 case Builtin::BI__builtin_hlsl_elementwise_rcp: {
1322 Value *Op0 = EmitScalarExpr(E->getArg(0));
1323 if (!E->getArg(0)->getType()->hasFloatingRepresentation())
1324 llvm_unreachable("rcp operand must have a float representation");
1325 llvm::Type *Ty = Op0->getType();
1326 llvm::Type *EltTy = Ty->getScalarType();
1327 Constant *One = Ty->isVectorTy()
1328 ? ConstantVector::getSplat(
1329 ElementCount::getFixed(
1330 cast<FixedVectorType>(Ty)->getNumElements()),
1331 ConstantFP::get(EltTy, 1.0))
1332 : ConstantFP::get(EltTy, 1.0);
1333 return Builder.CreateFDiv(One, Op0, "hlsl.rcp");
1334 }
1335 case Builtin::BI__builtin_hlsl_elementwise_rsqrt: {
1336 Value *Op0 = EmitScalarExpr(E->getArg(0));
1337 if (!E->getArg(0)->getType()->hasFloatingRepresentation())
1338 llvm_unreachable("rsqrt operand must have a float representation");
1339 return Builder.CreateIntrinsic(
1340 /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getRsqrtIntrinsic(),
1341 ArrayRef<Value *>{Op0}, nullptr, "hlsl.rsqrt");
1342 }
1343 case Builtin::BI__builtin_hlsl_elementwise_saturate: {
1344 Value *Op0 = EmitScalarExpr(E->getArg(0));
1345 assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
1346 "saturate operand must have a float representation");
1347 return Builder.CreateIntrinsic(
1348 /*ReturnType=*/Op0->getType(),
1349 CGM.getHLSLRuntime().getSaturateIntrinsic(), ArrayRef<Value *>{Op0},
1350 nullptr, "hlsl.saturate");
1351 }
1352 case Builtin::BI__builtin_hlsl_wave_prefix_count_bits: {
1353 Value *Op = EmitScalarExpr(E->getArg(0));
1354 assert(Op->getType()->isIntegerTy(1) &&
1355 "WavePrefixBitCount operand must be a boolean type");
1356
1357 Intrinsic::ID IID =
1359
1360 return EmitIntrinsicCall(IID, ArrayRef{Op}, "hlsl.wave.prefix.bit.count");
1361 }
1362 case Builtin::BI__builtin_hlsl_select: {
1363 Value *OpCond = EmitScalarExpr(E->getArg(0));
1364 RValue RValTrue = EmitAnyExpr(E->getArg(1));
1365 Value *OpTrue =
1366 RValTrue.isScalar()
1367 ? RValTrue.getScalarVal()
1368 : Builder.CreateLoad(RValTrue.getAggregateAddress(), "true_val");
1369 RValue RValFalse = EmitAnyExpr(E->getArg(2));
1370 Value *OpFalse =
1371 RValFalse.isScalar()
1372 ? RValFalse.getScalarVal()
1373 : Builder.CreateLoad(RValFalse.getAggregateAddress(), "false_val");
1374 if (auto *VTy = E->getType()->getAs<VectorType>()) {
1375 if (!OpTrue->getType()->isVectorTy())
1376 OpTrue =
1377 Builder.CreateVectorSplat(VTy->getNumElements(), OpTrue, "splat");
1378 if (!OpFalse->getType()->isVectorTy())
1379 OpFalse =
1380 Builder.CreateVectorSplat(VTy->getNumElements(), OpFalse, "splat");
1381 }
1382
1383 Value *SelectVal =
1384 Builder.CreateSelect(OpCond, OpTrue, OpFalse, "hlsl.select");
1385 if (!RValTrue.isScalar())
1386 Builder.CreateStore(SelectVal, ReturnValue.getAddress(),
1387 ReturnValue.isVolatile());
1388
1389 return SelectVal;
1390 }
1391 case Builtin::BI__builtin_hlsl_step: {
1392 Value *Op0 = EmitScalarExpr(E->getArg(0));
1393 Value *Op1 = EmitScalarExpr(E->getArg(1));
1394 assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
1396 "step operands must have a float representation");
1397 return Builder.CreateIntrinsic(
1398 /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getStepIntrinsic(),
1399 ArrayRef<Value *>{Op0, Op1}, nullptr, "hlsl.step");
1400 }
1401 case Builtin::BI__builtin_hlsl_wave_active_all_equal: {
1402 Value *Op = EmitScalarExpr(E->getArg(0));
1403
1404 Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveActiveAllEqualIntrinsic();
1405 return EmitIntrinsicCall(ID, {Op->getType()}, {Op});
1406 }
1407 case Builtin::BI__builtin_hlsl_wave_active_all_true: {
1408 Value *Op = EmitScalarExpr(E->getArg(0));
1409 assert(Op->getType()->isIntegerTy(1) &&
1410 "Intrinsic WaveActiveAllTrue operand must be a bool");
1411
1412 Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveActiveAllTrueIntrinsic();
1413 return EmitIntrinsicCall(ID, {Op});
1414 }
1415 case Builtin::BI__builtin_hlsl_wave_active_any_true: {
1416 Value *Op = EmitScalarExpr(E->getArg(0));
1417 assert(Op->getType()->isIntegerTy(1) &&
1418 "Intrinsic WaveActiveAnyTrue operand must be a bool");
1419
1420 Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveActiveAnyTrueIntrinsic();
1421 return EmitIntrinsicCall(ID, {Op});
1422 }
1423 case Builtin::BI__builtin_hlsl_wave_active_bit_or: {
1424 Value *Op = EmitScalarExpr(E->getArg(0));
1425 assert(E->getArg(0)->getType()->hasUnsignedIntegerRepresentation() &&
1426 "Intrinsic WaveActiveBitOr operand must have an unsigned integer "
1427 "representation");
1428
1429 Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveActiveBitOrIntrinsic();
1430 return EmitIntrinsicCall(ID, {Op->getType()}, ArrayRef{Op},
1431 "hlsl.wave.active.bit.or");
1432 }
1433 case Builtin::BI__builtin_hlsl_wave_active_bit_xor: {
1434 Value *Op = EmitScalarExpr(E->getArg(0));
1435 assert(E->getArg(0)->getType()->hasUnsignedIntegerRepresentation() &&
1436 "Intrinsic WaveActiveBitXor operand must have an unsigned integer "
1437 "representation");
1438
1439 Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveActiveBitXorIntrinsic();
1440 return EmitIntrinsicCall(ID, {Op->getType()}, ArrayRef{Op},
1441 "hlsl.wave.active.bit.xor");
1442 }
1443 case Builtin::BI__builtin_hlsl_wave_active_bit_and: {
1444 Value *Op = EmitScalarExpr(E->getArg(0));
1445 assert(E->getArg(0)->getType()->hasUnsignedIntegerRepresentation() &&
1446 "Intrinsic WaveActiveBitAnd operand must have an unsigned integer "
1447 "representation");
1448
1449 Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveActiveBitAndIntrinsic();
1450 return EmitIntrinsicCall(ID, {Op->getType()}, ArrayRef{Op},
1451 "hlsl.wave.active.bit.and");
1452 }
1453 case Builtin::BI__builtin_hlsl_interlocked_add: {
1454 // Emit `atomicrmw` directly for both DXIL and SPIR-V — the backends pick
1455 // up the raw instruction (DXIL routes it via `dx.resource.atomic.binop`
1456 // in DXILResourceAccess for resource pointers, SPIR-V lowers via
1457 // selectAtomicRMW). No intermediate intrinsic.
1458 return handleInterlockedOp(*this, E, llvm::AtomicRMWInst::Add);
1459 }
1460 case Builtin::BI__builtin_hlsl_interlocked_or: {
1461 return handleInterlockedOp(*this, E, llvm::AtomicRMWInst::Or);
1462 }
1463 case Builtin::BI__builtin_hlsl_wave_active_ballot: {
1464 [[maybe_unused]] Value *Op = EmitScalarExpr(E->getArg(0));
1465 assert(Op->getType()->isIntegerTy(1) &&
1466 "Intrinsic WaveActiveBallot operand must be a bool");
1467
1468 return handleHlslWaveActiveBallot(*this, E);
1469 }
1470 case Builtin::BI__builtin_hlsl_wave_active_count_bits: {
1471 Value *OpExpr = EmitScalarExpr(E->getArg(0));
1472 Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveActiveCountBitsIntrinsic();
1473 return EmitIntrinsicCall(ID, ArrayRef{OpExpr});
1474 }
1475 case Builtin::BI__builtin_hlsl_wave_active_sum: {
1476 // Due to the use of variadic arguments, explicitly retrieve argument
1477 Value *OpExpr = EmitScalarExpr(E->getArg(0));
1478 Intrinsic::ID IID = getWaveActiveSumIntrinsic(
1479 getTarget().getTriple().getArch(), E->getArg(0)->getType());
1480
1481 return EmitIntrinsicCall(IID, {OpExpr->getType()}, ArrayRef{OpExpr},
1482 "hlsl.wave.active.sum");
1483 }
1484 case Builtin::BI__builtin_hlsl_wave_active_product: {
1485 // Due to the use of variadic arguments, explicitly retrieve argument
1486 Value *OpExpr = EmitScalarExpr(E->getArg(0));
1487 Intrinsic::ID IID = getWaveActiveProductIntrinsic(
1488 getTarget().getTriple().getArch(), E->getArg(0)->getType());
1489
1490 return EmitIntrinsicCall(IID, {OpExpr->getType()}, ArrayRef{OpExpr},
1491 "hlsl.wave.active.product");
1492 }
1493 case Builtin::BI__builtin_hlsl_wave_active_max: {
1494 // Due to the use of variadic arguments, explicitly retrieve argument
1495 Value *OpExpr = EmitScalarExpr(E->getArg(0));
1496 QualType QT = E->getArg(0)->getType();
1497 Intrinsic::ID IID;
1498 if (QT->isUnsignedIntegerType())
1499 IID = CGM.getHLSLRuntime().getWaveActiveUMaxIntrinsic();
1500 else
1501 IID = CGM.getHLSLRuntime().getWaveActiveMaxIntrinsic();
1502
1503 return EmitIntrinsicCall(IID, {OpExpr->getType()}, ArrayRef{OpExpr},
1504 "hlsl.wave.active.max");
1505 }
1506 case Builtin::BI__builtin_hlsl_wave_active_min: {
1507 // Due to the use of variadic arguments, explicitly retrieve argument
1508 Value *OpExpr = EmitScalarExpr(E->getArg(0));
1509 QualType QT = E->getArg(0)->getType();
1510 Intrinsic::ID IID;
1511 if (QT->isUnsignedIntegerType())
1512 IID = CGM.getHLSLRuntime().getWaveActiveUMinIntrinsic();
1513 else
1514 IID = CGM.getHLSLRuntime().getWaveActiveMinIntrinsic();
1515
1516 return EmitIntrinsicCall(IID, {OpExpr->getType()}, ArrayRef{OpExpr},
1517 "hlsl.wave.active.min");
1518 }
1519 case Builtin::BI__builtin_hlsl_wave_get_lane_index: {
1520 // We don't define a SPIR-V intrinsic, instead it is a SPIR-V built-in
1521 // defined in SPIRVBuiltins.td. So instead we manually get the matching name
1522 // for the DirectX intrinsic and the demangled builtin name
1523 switch (CGM.getTarget().getTriple().getArch()) {
1524 case llvm::Triple::dxil:
1525 return EmitIntrinsicCall(Intrinsic::dx_wave_getlaneindex);
1526 case llvm::Triple::spirv:
1527 return EmitRuntimeCall(CGM.CreateRuntimeFunction(
1528 llvm::FunctionType::get(IntTy, {}, false),
1529 "__hlsl_wave_get_lane_index", {}, false, true));
1530 default:
1531 llvm_unreachable(
1532 "Intrinsic WaveGetLaneIndex not supported by target architecture");
1533 }
1534 }
1535 case Builtin::BI__builtin_hlsl_wave_is_first_lane: {
1536 Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveIsFirstLaneIntrinsic();
1537 return EmitIntrinsicCall(ID);
1538 }
1539 case Builtin::BI__builtin_hlsl_wave_get_lane_count: {
1540 Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveGetLaneCountIntrinsic();
1541 return EmitIntrinsicCall(ID);
1542 }
1543 case Builtin::BI__builtin_hlsl_wave_read_lane_at: {
1544 // Due to the use of variadic arguments we must explicitly retrieve them and
1545 // create our function type.
1546 Value *OpExpr = EmitScalarExpr(E->getArg(0));
1547 Value *OpIndex = EmitScalarExpr(E->getArg(1));
1548 return EmitIntrinsicCall(CGM.getHLSLRuntime().getWaveReadLaneAtIntrinsic(),
1549 {OpExpr->getType()}, ArrayRef{OpExpr, OpIndex},
1550 "hlsl.wave.readlane");
1551 }
1552 case Builtin::BI__builtin_hlsl_wave_prefix_sum: {
1553 Value *OpExpr = EmitScalarExpr(E->getArg(0));
1554 Intrinsic::ID IID = getWavePrefixSumIntrinsic(
1555 getTarget().getTriple().getArch(), E->getArg(0)->getType());
1556 return EmitIntrinsicCall(IID, {OpExpr->getType()}, ArrayRef{OpExpr},
1557 "hlsl.wave.prefix.sum");
1558 }
1559 case Builtin::BI__builtin_hlsl_wave_prefix_product: {
1560 Value *OpExpr = EmitScalarExpr(E->getArg(0));
1561 Intrinsic::ID IID = getWavePrefixProductIntrinsic(
1562 getTarget().getTriple().getArch(), E->getArg(0)->getType());
1563 return EmitIntrinsicCall(IID, {OpExpr->getType()}, ArrayRef{OpExpr},
1564 "hlsl.wave.prefix.product");
1565 }
1566 case Builtin::BI__builtin_hlsl_quad_read_across_x: {
1567 Value *OpExpr = EmitScalarExpr(E->getArg(0));
1568 Intrinsic::ID ID = CGM.getHLSLRuntime().getQuadReadAcrossXIntrinsic();
1569 return EmitIntrinsicCall(ID, {OpExpr->getType()}, ArrayRef{OpExpr},
1570 "hlsl.quad.read.across.x");
1571 }
1572 case Builtin::BI__builtin_hlsl_quad_read_across_y: {
1573 Value *OpExpr = EmitScalarExpr(E->getArg(0));
1574 Intrinsic::ID ID = CGM.getHLSLRuntime().getQuadReadAcrossYIntrinsic();
1575 return EmitIntrinsicCall(ID, {OpExpr->getType()}, ArrayRef{OpExpr},
1576 "hlsl.quad.read.across.y");
1577 }
1578 case Builtin::BI__builtin_hlsl_quad_read_across_diagonal: {
1579 Value *OpExpr = EmitScalarExpr(E->getArg(0));
1580 Intrinsic::ID ID =
1581 CGM.getHLSLRuntime().getQuadReadAcrossDiagonalIntrinsic();
1582 return EmitRuntimeCall(Intrinsic::getOrInsertDeclaration(
1583 &CGM.getModule(), ID, {OpExpr->getType()}),
1584 ArrayRef{OpExpr}, "hlsl.quad.read.across.diagonal");
1585 }
1586 case Builtin::BI__builtin_hlsl_elementwise_sign: {
1587 auto *Arg0 = E->getArg(0);
1588 Value *Op0 = EmitScalarExpr(Arg0);
1589 llvm::Type *Xty = Op0->getType();
1590 llvm::Type *retType = llvm::Type::getInt32Ty(this->getLLVMContext());
1591 if (Xty->isVectorTy()) {
1592 auto *XVecTy = Arg0->getType()->castAs<VectorType>();
1593 retType = llvm::VectorType::get(
1594 retType, ElementCount::getFixed(XVecTy->getNumElements()));
1595 }
1596 assert((Arg0->getType()->hasFloatingRepresentation() ||
1597 Arg0->getType()->hasIntegerRepresentation()) &&
1598 "sign operand must have a float or int representation");
1599
1600 if (Arg0->getType()->hasUnsignedIntegerRepresentation()) {
1601 Value *Cmp = Builder.CreateICmpEQ(Op0, ConstantInt::get(Xty, 0));
1602 return Builder.CreateSelect(Cmp, ConstantInt::get(retType, 0),
1603 ConstantInt::get(retType, 1), "hlsl.sign");
1604 }
1605
1606 return Builder.CreateIntrinsic(
1607 retType, CGM.getHLSLRuntime().getSignIntrinsic(),
1608 ArrayRef<Value *>{Op0}, nullptr, "hlsl.sign");
1609 }
1610 case Builtin::BI__builtin_hlsl_elementwise_radians: {
1611 Value *Op0 = EmitScalarExpr(E->getArg(0));
1612 assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
1613 "radians operand must have a float representation");
1614 return Builder.CreateIntrinsic(
1615 /*ReturnType=*/Op0->getType(),
1616 CGM.getHLSLRuntime().getRadiansIntrinsic(), ArrayRef<Value *>{Op0},
1617 nullptr, "hlsl.radians");
1618 }
1619 case Builtin::BI__builtin_hlsl_buffer_update_counter: {
1620 Value *ResHandle = EmitScalarExpr(E->getArg(0));
1621 Value *Offset = EmitScalarExpr(E->getArg(1));
1622 Value *OffsetI8 = Builder.CreateIntCast(Offset, Int8Ty, true);
1623 return Builder.CreateIntrinsic(
1624 /*ReturnType=*/Offset->getType(),
1625 CGM.getHLSLRuntime().getBufferUpdateCounterIntrinsic(),
1626 ArrayRef<Value *>{ResHandle, OffsetI8}, nullptr);
1627 }
1628 case Builtin::BI__builtin_hlsl_elementwise_splitdouble: {
1629
1630 assert((E->getArg(0)->getType()->hasFloatingRepresentation() &&
1633 "asuint operands types mismatch");
1634 return handleHlslSplitdouble(E, this);
1635 }
1636 case Builtin::BI__builtin_hlsl_elementwise_clip:
1637 assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
1638 "clip operands types mismatch");
1639 return handleHlslClip(E, this);
1640 case Builtin::BI__builtin_hlsl_all_memory_barrier: {
1641 Intrinsic::ID ID = CGM.getHLSLRuntime().getAllMemoryBarrierIntrinsic();
1642 return EmitIntrinsicCall(ID);
1643 }
1644 case Builtin::BI__builtin_hlsl_all_memory_barrier_with_group_sync: {
1645 Intrinsic::ID ID =
1646 CGM.getHLSLRuntime().getAllMemoryBarrierWithGroupSyncIntrinsic();
1647 return EmitIntrinsicCall(ID);
1648 }
1649 case Builtin::BI__builtin_hlsl_device_memory_barrier: {
1650 Intrinsic::ID ID = CGM.getHLSLRuntime().getDeviceMemoryBarrierIntrinsic();
1651 return EmitIntrinsicCall(ID);
1652 }
1653 case Builtin::BI__builtin_hlsl_device_memory_barrier_with_group_sync: {
1654 Intrinsic::ID ID =
1655 CGM.getHLSLRuntime().getDeviceMemoryBarrierWithGroupSyncIntrinsic();
1656 return EmitIntrinsicCall(ID);
1657 }
1658 case Builtin::BI__builtin_hlsl_group_memory_barrier: {
1659 Intrinsic::ID ID = CGM.getHLSLRuntime().getGroupMemoryBarrierIntrinsic();
1660 return EmitIntrinsicCall(ID);
1661 }
1662 case Builtin::BI__builtin_hlsl_group_memory_barrier_with_group_sync: {
1663 Intrinsic::ID ID =
1664 CGM.getHLSLRuntime().getGroupMemoryBarrierWithGroupSyncIntrinsic();
1665 return EmitIntrinsicCall(ID);
1666 }
1667 case Builtin::BI__builtin_hlsl_elementwise_ddx_coarse: {
1668 Value *Op0 = EmitScalarExpr(E->getArg(0));
1669 if (!E->getArg(0)->getType()->hasFloatingRepresentation())
1670 llvm_unreachable("ddx_coarse operand must have a float representation");
1671 Intrinsic::ID ID = CGM.getHLSLRuntime().getDdxCoarseIntrinsic();
1672 return Builder.CreateIntrinsic(/*ReturnType=*/Op0->getType(), ID,
1673 ArrayRef<Value *>{Op0}, nullptr,
1674 "hlsl.ddx.coarse");
1675 }
1676 case Builtin::BI__builtin_hlsl_elementwise_ddy_coarse: {
1677 Value *Op0 = EmitScalarExpr(E->getArg(0));
1678 if (!E->getArg(0)->getType()->hasFloatingRepresentation())
1679 llvm_unreachable("ddy_coarse operand must have a float representation");
1680 Intrinsic::ID ID = CGM.getHLSLRuntime().getDdyCoarseIntrinsic();
1681 return Builder.CreateIntrinsic(/*ReturnType=*/Op0->getType(), ID,
1682 ArrayRef<Value *>{Op0}, nullptr,
1683 "hlsl.ddy.coarse");
1684 }
1685 case Builtin::BI__builtin_hlsl_elementwise_ddx_fine: {
1686 Value *Op0 = EmitScalarExpr(E->getArg(0));
1687 if (!E->getArg(0)->getType()->hasFloatingRepresentation())
1688 llvm_unreachable("ddx_fine operand must have a float representation");
1689 Intrinsic::ID ID = CGM.getHLSLRuntime().getDdxFineIntrinsic();
1690 return Builder.CreateIntrinsic(/*ReturnType=*/Op0->getType(), ID,
1691 ArrayRef<Value *>{Op0}, nullptr,
1692 "hlsl.ddx.fine");
1693 }
1694 case Builtin::BI__builtin_hlsl_elementwise_ddy_fine: {
1695 Value *Op0 = EmitScalarExpr(E->getArg(0));
1696 if (!E->getArg(0)->getType()->hasFloatingRepresentation())
1697 llvm_unreachable("ddy_fine operand must have a float representation");
1698 Intrinsic::ID ID = CGM.getHLSLRuntime().getDdyFineIntrinsic();
1699 return Builder.CreateIntrinsic(/*ReturnType=*/Op0->getType(), ID,
1700 ArrayRef<Value *>{Op0}, nullptr,
1701 "hlsl.ddy.fine");
1702 }
1703 case Builtin::BI__builtin_get_spirv_spec_constant_bool:
1704 case Builtin::BI__builtin_get_spirv_spec_constant_short:
1705 case Builtin::BI__builtin_get_spirv_spec_constant_ushort:
1706 case Builtin::BI__builtin_get_spirv_spec_constant_int:
1707 case Builtin::BI__builtin_get_spirv_spec_constant_uint:
1708 case Builtin::BI__builtin_get_spirv_spec_constant_longlong:
1709 case Builtin::BI__builtin_get_spirv_spec_constant_ulonglong:
1710 case Builtin::BI__builtin_get_spirv_spec_constant_half:
1711 case Builtin::BI__builtin_get_spirv_spec_constant_float:
1712 case Builtin::BI__builtin_get_spirv_spec_constant_double: {
1713 llvm::Function *SpecConstantFn = getSpecConstantFunction(E->getType());
1714 llvm::Value *SpecId = EmitScalarExpr(E->getArg(0));
1715 llvm::Value *DefaultVal = EmitScalarExpr(E->getArg(1));
1716 llvm::Value *Args[] = {SpecId, DefaultVal};
1717 return Builder.CreateCall(SpecConstantFn, Args);
1718 }
1719 }
1720 return nullptr;
1721}
1722
1724 const clang::QualType &SpecConstantType) {
1725
1726 // Find or create the declaration for the function.
1727 llvm::Module *M = &CGM.getModule();
1728 std::string MangledName =
1729 getSpecConstantFunctionName(SpecConstantType, getContext());
1730 llvm::Function *SpecConstantFn = M->getFunction(MangledName);
1731
1732 if (!SpecConstantFn) {
1733 llvm::Type *IntType = ConvertType(getContext().IntTy);
1734 llvm::Type *RetTy = ConvertType(SpecConstantType);
1735 llvm::Type *ArgTypes[] = {IntType, RetTy};
1736 llvm::FunctionType *FnTy = llvm::FunctionType::get(RetTy, ArgTypes, false);
1737 SpecConstantFn = llvm::Function::Create(
1738 FnTy, llvm::GlobalValue::ExternalLinkage, MangledName, M);
1739 }
1740 return SpecConstantFn;
1741}
llvm::Value * EmitOverflowIntrinsic(CodeGenFunction &CGF, const Intrinsic::ID IntrinsicID, llvm::Value *X, llvm::Value *Y, llvm::Value *&Carry)
Emit a call to llvm.
static Intrinsic::ID getWavePrefixSumIntrinsic(llvm::Triple::ArchType Arch, QualType QT)
static const HLSLAttributedResourceType * getRequiredHandleType(const CallExpr *E, unsigned ArgNo)
static Intrinsic::ID getDotProductIntrinsic(CGHLSLRuntime &RT, QualType QT)
static Intrinsic::ID getPrefixCountBitsIntrinsic(llvm::Triple::ArchType Arch)
static Intrinsic::ID getWaveActiveSumIntrinsic(llvm::Triple::ArchType Arch, QualType QT)
static std::string getSpecConstantFunctionName(clang::QualType SpecConstantType, ASTContext &Context)
static const HLSLAttributedResourceType * getHandleAttributedType(QualType HandleQT)
static Value * handleHlslSplitdouble(const CallExpr *E, CodeGenFunction *CGF)
static Value * handleInterlockedOp(CodeGenFunction &CGF, const CallExpr *E, llvm::AtomicRMWInst::BinOp Op)
static Value * emitBufferStride(CodeGenFunction *CGF, const Expr *HandleExpr, LValue &Stride)
static Intrinsic::ID getWavePrefixProductIntrinsic(llvm::Triple::ArchType Arch, QualType QT)
static Value * emitHlslClamp(CodeGenFunction &CGF, const CallExpr *E, unsigned ClampArgIndex)
static Intrinsic::ID getFirstBitHighIntrinsic(CGHLSLRuntime &RT, QualType QT)
static llvm::Type * getOffsetType(CodeGenModule &CGM, const HLSLAttributedResourceType *RT)
static Value * emitGetDimensions(CodeGenFunction &CGF, const CallExpr *E, unsigned IntrinsicID, unsigned NumRetComps, bool HasLod)
static Value * handleElementwiseF16ToF32(CodeGenFunction &CGF, const CallExpr *E)
static Value * handleAsDoubleBuiltin(CodeGenFunction &CGF, const CallExpr *E)
static Value * handleHlslWaveActiveBallot(CodeGenFunction &CGF, const CallExpr *E)
static Value * emitHlslOffset(CodeGenFunction &CGF, const CallExpr *E, unsigned OffsetArgIndex, llvm::Type *OffsetTy)
static Value * handleElementwiseF32ToF16(CodeGenFunction &CGF, const CallExpr *E)
static Intrinsic::ID getWaveActiveProductIntrinsic(llvm::Triple::ArchType Arch, QualType QT)
static Value * handleHlslClip(const CallExpr *E, CodeGenFunction *CGF)
Result
Implement __builtin_bit_cast and related operations.
#define X(type, name)
Definition Value.h:97
Defines AST-level helper utilities for matrix types.
static StringRef getTriple(const Command &Job)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:223
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:2949
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition Expr.h:3153
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition Expr.h:3140
Like RawAddress, an abstract representation of an aligned address, but the pointer contained in this ...
Definition Address.h:128
llvm::StoreInst * CreateStore(llvm::Value *Val, Address Addr, bool IsVolatile=false)
Definition CGBuilder.h:146
llvm::AtomicRMWInst * CreateAtomicRMW(llvm::AtomicRMWInst::BinOp Op, Address Addr, llvm::Value *Val, llvm::AtomicOrdering Ordering, llvm::SyncScope::ID SSID=llvm::SyncScope::System)
Definition CGBuilder.h:190
CallArgList - Type for representing both the value and type of arguments in a call.
Definition CGCall.h:276
CodeGenFunction - This class organizes the per-function state that is used while generating LLVM code...
llvm::Type * ConvertType(QualType T)
llvm::BasicBlock * createBasicBlock(const Twine &name="", llvm::Function *parent=nullptr, llvm::BasicBlock *before=nullptr)
createBasicBlock - Create an LLVM basic block.
const LangOptions & getLangOpts() const
const TargetInfo & getTarget() const
llvm::Function * getSpecConstantFunction(const clang::QualType &SpecConstantType)
LValue EmitHLSLOutArgExpr(const HLSLOutArgExpr *E, CallArgList &Args, QualType Ty)
Definition CGExpr.cpp:6406
void EmitWritebacks(const CallArgList &Args)
EmitWriteback - Emit callbacks for function.
Definition CGCall.cpp:5230
llvm::CallInst * EmitIntrinsicCall(llvm::Intrinsic::ID ID, const Twine &Name="")
llvm::Value * getTypeSize(QualType Ty)
Returns calculated size of the specified type.
void EmitStoreThroughLValue(RValue Src, LValue Dst, bool isInit=false)
EmitStoreThroughLValue - Store the specified rvalue into the specified lvalue, where both are guarant...
Definition CGExpr.cpp:2793
RValue EmitAnyExpr(const Expr *E, AggValueSlot aggSlot=AggValueSlot::ignored(), bool ignoreResult=false)
EmitAnyExpr - Emit code to compute the specified expression which can have any type.
Definition CGExpr.cpp:281
llvm::CallInst * EmitRuntimeCall(llvm::FunctionCallee callee, const Twine &name="")
llvm::Value * EmitScalarExpr(const Expr *E, bool IgnoreResultAssign=false)
EmitScalarExpr - Emit the computation of the specified expression of LLVM scalar type,...
Address ReturnValue
ReturnValue - The temporary alloca to hold the return value.
LValue EmitLValue(const Expr *E, KnownNonNull_t IsKnownNonNull=NotKnownNonNull)
EmitLValue - Emit code to compute a designator that specifies the location of the expression.
Definition CGExpr.cpp:1737
llvm::LLVMContext & getLLVMContext()
llvm::Value * EmitHLSLBuiltinExpr(unsigned BuiltinID, const CallExpr *E, ReturnValueSlot ReturnValue)
This class organizes the cross-function state that is used while generating LLVM code.
CGHLSLRuntime & getHLSLRuntime()
Return a reference to the configured HLSL runtime.
const TargetInfo & getTarget() const
const llvm::Triple & getTriple() const
LValue - This represents an lvalue references.
Definition CGValue.h:183
Address getAddress() const
Definition CGValue.h:373
RValue - This trivial value class is used to represent the result of an expression that is evaluated.
Definition CGValue.h:42
bool isScalar() const
Definition CGValue.h:64
static RValue get(llvm::Value *V)
Definition CGValue.h:99
Address getAggregateAddress() const
getAggregateAddr() - Return the Value* of the address of the aggregate.
Definition CGValue.h:84
llvm::Value * getScalarVal() const
getScalarVal() - Return the Value* of this scalar value.
Definition CGValue.h:72
ReturnValueSlot - Contains the address where the return value of a function can be stored,...
Definition CGCall.h:383
Represents a concrete matrix type with constant number of rows and columns.
Definition TypeBase.h:4486
unsigned getNumColumns() const
Returns the number of columns in the matrix.
Definition TypeBase.h:4505
unsigned getNumRows() const
Returns the number of rows in the matrix.
Definition TypeBase.h:4502
The name of a declaration.
This represents one expression.
Definition Expr.h:112
QualType getType() const
Definition Expr.h:144
Represents a function declaration or definition.
Definition Decl.h:2029
static FunctionDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation NLoc, DeclarationName N, QualType T, TypeSourceInfo *TInfo, StorageClass SC, bool UsesFPIntrin=false, bool isInlineSpecified=false, bool hasWrittenPrototype=true, ConstexprSpecKind ConstexprKind=ConstexprSpecKind::Unspecified, const AssociatedConstraint &TrailingRequiresClause={})
Definition Decl.h:2225
Represents a parameter to a function.
Definition Decl.h:1819
static ParmVarDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, const IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, StorageClass S, Expr *DefArg)
Definition Decl.cpp:2936
A (possibly-)qualified type.
Definition TypeBase.h:938
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition TypeBase.h:8489
Encodes a location in the source.
bool areArgsDestroyedLeftToRightInCallee() const
Are arguments to a call destroyed left to right in the callee?
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
TargetCXXABI getCXXABI() const
Get the C++ ABI currently in use.
bool isSignedIntegerType() const
Return true if this is an integer type that is signed, according to C99 6.2.5p4 [char,...
Definition Type.cpp:2270
bool hasIntegerRepresentation() const
Determine whether this type has an integer representation of some sort, e.g., it is an integer type o...
Definition Type.cpp:2123
bool isConstantMatrixType() const
Definition TypeBase.h:8893
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
Definition TypeBase.h:9136
const T * castAs() const
Member-template castAs<specific type>.
Definition TypeBase.h:9386
bool hasUnsignedIntegerRepresentation() const
Determine whether this type has an unsigned integer representation of some sort, e....
Definition Type.cpp:2380
bool hasSignedIntegerRepresentation() const
Determine whether this type has an signed integer representation of some sort, e.g....
Definition Type.cpp:2314
bool hasFloatingRepresentation() const
Determine whether this type has a floating-point representation of some sort, e.g....
Definition Type.cpp:2401
bool isVectorType() const
Definition TypeBase.h:8865
bool isFloatingType() const
Definition Type.cpp:2393
bool isUnsignedIntegerType() const
Return true if this is an integer type that is unsigned, according to C99 6.2.5p6 [which returns true...
Definition Type.cpp:2336
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9319
QualType getType() const
Definition Value.cpp:238
Represents a GCC generic vector type.
Definition TypeBase.h:4274
unsigned getNumElements() const
Definition TypeBase.h:4289
uint32_t getResourceDimensions(llvm::dxil::ResourceDimension Dim)
The JSON file list parser is used to communicate input to InstallAPI.
bool isMatrixRowMajor(const LangOptions &LangOpts, QualType T)
Returns true if matrices of T should be laid out in row-major order.
Definition MatrixUtils.h:29
@ SC_Extern
Definition Specifiers.h:252
@ SC_None
Definition Specifiers.h:251
Expr * Cond
};
@ Result
The result type of a method or function.
Definition TypeBase.h:906
U cast(CodeGen::Address addr)
Definition Address.h:327
Diagnostic wrappers for TextAPI types for error reporting.
Definition Dominators.h:30
llvm::IntegerType * Int8Ty
i8, i16, i32, and i64
Extra information about a function prototype.
Definition TypeBase.h:5491