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 [[maybe_unused]] QualType ValTy = E->getArg(1)->getType();
321 if (Op == llvm::AtomicRMWInst::Xchg)
322 assert((ValTy->isIntegerType() || ValTy->isFloatingType()) &&
323 "InterlockedExchange value operand must be an integer or a float");
324 else
325 assert(ValTy->isIntegerType() &&
326 "Intrinsic InterlockedOp value operand must be an integer");
327
328 // Scopeless atomics will default to CrossDevice, which is illegal in Vulkan.
329 // Set the memory scope: Workgroup for groupshared, otherwise Device.
330 StringRef ScopeName = DestLV.getAddressSpace() == LangAS::hlsl_groupshared
331 ? "workgroup"
332 : "device";
333 llvm::SyncScope::ID SSID =
334 CGF.getLLVMContext().getOrInsertSyncScopeID(ScopeName);
335
336 llvm::AtomicRMWInst *Call = CGF.Builder.CreateAtomicRMW(
337 Op, DestAddr, Val, llvm::AtomicOrdering::Monotonic, SSID);
338
339 // The 3-arg overload writes the old value (the RMW's return value) into
340 // the `original_value` reference parameter.
341 if (E->getNumArgs() == 3) {
342 LValue OrigLV = CGF.EmitLValue(E->getArg(2));
344 }
345 return Call;
346}
347
348static Value *emitBufferStride(CodeGenFunction *CGF, const Expr *HandleExpr,
349 LValue &Stride) {
350 // Figure out the stride of the buffer elements from the handle type.
351 auto *HandleTy =
353 QualType ElementTy = HandleTy->getContainedType();
354 Value *StrideValue = CGF->getTypeSize(ElementTy);
355 return CGF->Builder.CreateStore(StrideValue, Stride.getAddress());
356}
357
358// Return dot product intrinsic that corresponds to the QT scalar type
359static Intrinsic::ID getDotProductIntrinsic(CGHLSLRuntime &RT, QualType QT) {
360 if (QT->isFloatingType())
361 return RT.getFDotIntrinsic();
362 if (QT->isSignedIntegerType())
363 return RT.getSDotIntrinsic();
364 assert(QT->isUnsignedIntegerType());
365 return RT.getUDotIntrinsic();
366}
367
368static Intrinsic::ID getFirstBitHighIntrinsic(CGHLSLRuntime &RT, QualType QT) {
370 return RT.getFirstBitSHighIntrinsic();
371 }
372
374 return RT.getFirstBitUHighIntrinsic();
375}
376
377// Return wave active sum that corresponds to the QT scalar type
378static Intrinsic::ID getWaveActiveSumIntrinsic(llvm::Triple::ArchType Arch,
379 QualType QT) {
380 switch (Arch) {
381 case llvm::Triple::spirv:
382 return Intrinsic::spv_wave_reduce_sum;
383 case llvm::Triple::dxil: {
384 if (QT->isUnsignedIntegerType())
385 return Intrinsic::dx_wave_reduce_usum;
386 return Intrinsic::dx_wave_reduce_sum;
387 }
388 default:
389 llvm_unreachable("Intrinsic WaveActiveSum"
390 " not supported by target architecture");
391 }
392}
393
394// Return wave active product that corresponds to the QT scalar type
395static Intrinsic::ID getWaveActiveProductIntrinsic(llvm::Triple::ArchType Arch,
396 QualType QT) {
397 switch (Arch) {
398 case llvm::Triple::spirv:
399 return Intrinsic::spv_wave_product;
400 case llvm::Triple::dxil: {
401 if (QT->isUnsignedIntegerType())
402 return Intrinsic::dx_wave_uproduct;
403 return Intrinsic::dx_wave_product;
404 }
405 default:
406 llvm_unreachable("Intrinsic WaveActiveProduct"
407 " not supported by target architecture");
408 }
409}
410
411static Intrinsic::ID getPrefixCountBitsIntrinsic(llvm::Triple::ArchType Arch) {
412 switch (Arch) {
413 case llvm::Triple::spirv:
414 return Intrinsic::spv_subgroup_prefix_bit_count;
415 case llvm::Triple::dxil: {
416 return Intrinsic::dx_wave_prefix_bit_count;
417 }
418 default:
419 llvm_unreachable(
420 "WavePrefixOp instruction not supported by target architecture");
421 }
422}
423
424// Return wave prefix sum that corresponds to the QT scalar type
425static Intrinsic::ID getWavePrefixSumIntrinsic(llvm::Triple::ArchType Arch,
426 QualType QT) {
427 switch (Arch) {
428 case llvm::Triple::spirv:
429 return Intrinsic::spv_wave_prefix_sum;
430 case llvm::Triple::dxil: {
431 if (QT->isUnsignedIntegerType())
432 return Intrinsic::dx_wave_prefix_usum;
433 return Intrinsic::dx_wave_prefix_sum;
434 }
435 default:
436 llvm_unreachable("Intrinsic WavePrefixSum"
437 " not supported by target architecture");
438 }
439}
440
441// Return wave prefix product that corresponds to the QT scalar type
442static Intrinsic::ID getWavePrefixProductIntrinsic(llvm::Triple::ArchType Arch,
443 QualType QT) {
444 switch (Arch) {
445 case llvm::Triple::spirv:
446 return Intrinsic::spv_wave_prefix_product;
447 case llvm::Triple::dxil: {
448 if (QT->isUnsignedIntegerType())
449 return Intrinsic::dx_wave_prefix_uproduct;
450 return Intrinsic::dx_wave_prefix_product;
451 }
452 default:
453 llvm_unreachable("Intrinsic WavePrefixProduct"
454 " not supported by target architecture");
455 }
456}
457
458// Returns the mangled name for a builtin function that the SPIR-V backend
459// will expand into a spec Constant.
460static std::string getSpecConstantFunctionName(clang::QualType SpecConstantType,
461 ASTContext &Context) {
462 // The parameter types for our conceptual intrinsic function.
463 QualType ClangParamTypes[] = {Context.IntTy, SpecConstantType};
464
465 // Create a temporary FunctionDecl for the builtin fuction. It won't be
466 // added to the AST.
468 QualType FnType =
469 Context.getFunctionType(SpecConstantType, ClangParamTypes, EPI);
470 DeclarationName FuncName = &Context.Idents.get("__spirv_SpecConstant");
471 FunctionDecl *FnDeclForMangling = FunctionDecl::Create(
472 Context, Context.getTranslationUnitDecl(), SourceLocation(),
473 SourceLocation(), FuncName, FnType, /*TSI=*/nullptr, SC_Extern);
474
475 // Attach the created parameter declarations to the function declaration.
477 for (QualType ParamType : ClangParamTypes) {
479 Context, FnDeclForMangling, SourceLocation(), SourceLocation(),
480 /*IdentifierInfo*/ nullptr, ParamType, /*TSI*/ nullptr, SC_None,
481 /*DefaultArg*/ nullptr);
482 ParamDecls.push_back(PD);
483 }
484 FnDeclForMangling->setParams(ParamDecls);
485
486 // Get the mangled name.
487 std::string Name;
488 llvm::raw_string_ostream MangledNameStream(Name);
489 std::unique_ptr<MangleContext> Mangler(Context.createMangleContext());
490 Mangler->mangleName(FnDeclForMangling, MangledNameStream);
491 MangledNameStream.flush();
492
493 return Name;
494}
495
496static const HLSLAttributedResourceType *
498 if (const auto *RT = HandleQT->getAs<HLSLAttributedResourceType>())
499 return RT;
500 // If the expr is a texture/sampler record (or similar), peel to __handle.
501 if (const HLSLAttributedResourceType *RT =
502 HLSLAttributedResourceType::findHandleTypeOnResource(
503 HandleQT.getTypePtr()))
504 return RT;
505 llvm_unreachable("attributed handle type not found");
506}
507
508static const HLSLAttributedResourceType *
509getRequiredHandleType(const CallExpr *E, unsigned ArgNo) {
510 return getHandleAttributedType(E->getArg(ArgNo)->getType());
511}
512
513static llvm::Type *getOffsetType(CodeGenModule &CGM,
514 const HLSLAttributedResourceType *RT) {
515 const auto &Attrs = RT->getAttrs();
516 unsigned OffsetSize =
517 clang::hlsl::getResourceDimensions(Attrs.ResourceDimension);
518 llvm::Type *Int32Ty = CGM.Int32Ty;
519 if (OffsetSize == 1)
520 return Int32Ty;
521 return llvm::FixedVectorType::get(Int32Ty, OffsetSize);
522}
523
525 unsigned OffsetArgIndex, llvm::Type *OffsetTy) {
526 if (E->getNumArgs() > OffsetArgIndex)
527 return CGF.EmitScalarExpr(E->getArg(OffsetArgIndex));
528
529 return llvm::Constant::getNullValue(OffsetTy);
530}
531
533 const HLSLAttributedResourceType *RT,
534 unsigned OffsetArgIndex) {
535 llvm::Type *OffsetTy = getOffsetType(CGF.CGM, RT);
536 if (!clang::hlsl::hasResourceOffset(RT->getAttrs().ResourceDimension))
537 return llvm::Constant::getNullValue(OffsetTy);
538 return emitHlslOffset(CGF, E, OffsetArgIndex, OffsetTy);
539}
540
541static unsigned getHlslClampArgIndex(const HLSLAttributedResourceType *RT,
542 unsigned OffsetArgIndex) {
543 return clang::hlsl::hasResourceOffset(RT->getAttrs().ResourceDimension)
544 ? OffsetArgIndex + 1
545 : OffsetArgIndex;
546}
547
549 unsigned IntrinsicID, unsigned NumRetComps,
550 bool HasLod) {
551 Value *Handle = CGF.EmitScalarExpr(E->getArg(0));
552
553 SmallVector<Value *> Args{Handle};
554 if (HasLod)
555 Args.push_back(CGF.EmitScalarExpr(E->getArg(1)));
556
557 Value *DimValue =
558 CGF.Builder.CreateIntrinsic(IntrinsicID, {Handle->getType()}, Args);
559
560 Value *LastStore = nullptr;
561 unsigned ArgIndex = HasLod ? 2 : 1;
562 for (unsigned i = 0; i < NumRetComps; ++i) {
563 const Expr *Arg = E->getArg(ArgIndex++);
564 LValue DimOut = CGF.EmitLValue(Arg);
565 Value *Elem = DimValue;
566 if (NumRetComps > 1)
567 Elem = CGF.Builder.CreateExtractElement(DimValue, i);
568
569 // Handle float casting if needed
570 if (Arg->getType()->isFloatingType())
571 Elem = CGF.Builder.CreateUIToFP(
572 Elem, llvm::Type::getFloatTy(CGF.getLLVMContext()));
573
574 LastStore = CGF.Builder.CreateStore(Elem, DimOut.getAddress());
575 }
576 return LastStore;
577}
578
579static llvm::Type *getAggregateType(llvm::Type *ScalarTy, QualType ArgTy) {
580 if (auto *MatTy = ArgTy->getAs<ConstantMatrixType>())
581 return llvm::VectorType::get(
582 ScalarTy, ElementCount::getFixed(MatTy->getNumElementsFlattened()));
583 if (auto *VecTy = ArgTy->getAs<clang::VectorType>())
584 return llvm::VectorType::get(
585 ScalarTy, ElementCount::getFixed(VecTy->getNumElements()));
586 return ScalarTy;
587}
588
590 const CallExpr *E,
592 if (!getLangOpts().HLSL)
593 return nullptr;
594
595 switch (BuiltinID) {
596 case Builtin::BI__builtin_hlsl_adduint64: {
597 Value *OpA = EmitScalarExpr(E->getArg(0));
598 Value *OpB = EmitScalarExpr(E->getArg(1));
599 QualType Arg0Ty = E->getArg(0)->getType();
600 uint64_t NumElements = Arg0Ty->castAs<VectorType>()->getNumElements();
601 assert(Arg0Ty == E->getArg(1)->getType() &&
602 "AddUint64 operand types must match");
603 assert(Arg0Ty->hasIntegerRepresentation() &&
604 "AddUint64 operands must have an integer representation");
605 assert((NumElements == 2 || NumElements == 4) &&
606 "AddUint64 operands must have 2 or 4 elements");
607
608 llvm::Value *LowA;
609 llvm::Value *HighA;
610 llvm::Value *LowB;
611 llvm::Value *HighB;
612
613 // Obtain low and high words of inputs A and B
614 if (NumElements == 2) {
615 LowA = Builder.CreateExtractElement(OpA, (uint64_t)0, "LowA");
616 HighA = Builder.CreateExtractElement(OpA, (uint64_t)1, "HighA");
617 LowB = Builder.CreateExtractElement(OpB, (uint64_t)0, "LowB");
618 HighB = Builder.CreateExtractElement(OpB, (uint64_t)1, "HighB");
619 } else {
620 LowA = Builder.CreateShuffleVector(OpA, {0, 2}, "LowA");
621 HighA = Builder.CreateShuffleVector(OpA, {1, 3}, "HighA");
622 LowB = Builder.CreateShuffleVector(OpB, {0, 2}, "LowB");
623 HighB = Builder.CreateShuffleVector(OpB, {1, 3}, "HighB");
624 }
625
626 // Use an uadd_with_overflow to compute the sum of low words and obtain a
627 // carry value
628 llvm::Value *Carry;
629 llvm::Value *LowSum = EmitOverflowIntrinsic(
630 *this, Intrinsic::uadd_with_overflow, LowA, LowB, Carry);
631 llvm::Value *ZExtCarry =
632 Builder.CreateZExt(Carry, HighA->getType(), "CarryZExt");
633
634 // Sum the high words and the carry
635 llvm::Value *HighSum = Builder.CreateAdd(HighA, HighB, "HighSum");
636 llvm::Value *HighSumPlusCarry =
637 Builder.CreateAdd(HighSum, ZExtCarry, "HighSumPlusCarry");
638
639 if (NumElements == 4) {
640 return Builder.CreateShuffleVector(LowSum, HighSumPlusCarry, {0, 2, 1, 3},
641 "hlsl.AddUint64");
642 }
643
644 llvm::Value *Result = PoisonValue::get(OpA->getType());
645 Result = Builder.CreateInsertElement(Result, LowSum, (uint64_t)0,
646 "hlsl.AddUint64.upto0");
647 Result = Builder.CreateInsertElement(Result, HighSumPlusCarry, (uint64_t)1,
648 "hlsl.AddUint64");
649 return Result;
650 }
651 case Builtin::BI__builtin_hlsl_resource_getpointer:
652 case Builtin::BI__builtin_hlsl_resource_getpointer_typed: {
653 Value *HandleOp = EmitScalarExpr(E->getArg(0));
654 bool IsIndexed =
655 BuiltinID == Builtin::BI__builtin_hlsl_resource_getpointer_typed ||
656 E->getNumArgs() > 1;
657
658 llvm::Type *RetTy = ConvertType(E->getType());
659 llvm::Function *IntrFn = nullptr;
660 llvm::CallInst *CI = nullptr;
661 if (IsIndexed) {
662 Value *IndexOp = EmitScalarExpr(E->getArg(1));
663 IntrFn = llvm::Intrinsic::getOrInsertDeclaration(
664 &CGM.getModule(),
665 CGM.getHLSLRuntime().getCreateResourceGetPointerIntrinsic(),
666 {RetTy, HandleOp->getType(), IndexOp->getType()});
667 CI = EmitRuntimeCall(IntrFn, {HandleOp, IndexOp});
668 } else {
669 IntrFn = llvm::Intrinsic::getOrInsertDeclaration(
670 &CGM.getModule(),
671 CGM.getHLSLRuntime().getCreateResourceGetBasePointerIntrinsic(),
672 {RetTy, HandleOp->getType()});
673 CI = EmitRuntimeCall(IntrFn, {HandleOp});
674 }
675 CI->setCallingConv(IntrFn->getCallingConv());
676 return CI;
677 }
678 case Builtin::BI__builtin_hlsl_transpose_if_memory_is_row_major: {
679 const Expr *ValueExpr = E->getArg(0);
680 if (hasAggregateEvaluationKind(ValueExpr->getType())) {
681 EmitAnyExprToMem(ValueExpr, ReturnValue.getAddress(),
682 ValueExpr->getType().getQualifiers(), /*IsInit=*/true);
683 return ReturnValue.getAddress().getBasePointer();
684 }
685
686 Value *ValueOp = EmitScalarExpr(ValueExpr);
687 const auto *MatTy = ValueExpr->getType()->getAs<ConstantMatrixType>();
688 if (!MatTy || !getLangOpts().HLSLSpvUseLegacyBufferMatrixOrder)
689 return ValueOp;
690
691 bool IsLoad =
692 E->getArg(1)->EvaluateKnownConstInt(getContext()).getBoolValue();
693 unsigned Rows = MatTy->getNumRows();
694 unsigned Columns = MatTy->getNumColumns();
695 llvm::MatrixBuilder MB(Builder);
696 return IsLoad ? MB.CreateMatrixTranspose(ValueOp, Columns, Rows)
697 : MB.CreateMatrixTranspose(ValueOp, Rows, Columns);
698 }
699 case Builtin::BI__builtin_hlsl_resource_sample: {
700 Value *HandleOp = EmitScalarExpr(E->getArg(0));
701 Value *SamplerOp = EmitScalarExpr(E->getArg(1));
702 Value *CoordOp = EmitScalarExpr(E->getArg(2));
703 const HLSLAttributedResourceType *RT = getRequiredHandleType(E, 0);
704
706 Args.push_back(HandleOp);
707 Args.push_back(SamplerOp);
708 Args.push_back(CoordOp);
709 constexpr unsigned OffsetIdx = 3;
710 Args.push_back(emitHlslSampleOffset(*this, E, RT, OffsetIdx));
711
712 llvm::Type *RetTy = ConvertType(E->getType());
713 const unsigned ClampIdx = getHlslClampArgIndex(RT, OffsetIdx);
714 if (E->getNumArgs() <= ClampIdx)
715 return EmitIntrinsicCall(CGM.getHLSLRuntime().getSampleIntrinsic(), Args,
716 RetTy);
717
718 Args.push_back(EmitScalarExpr(E->getArg(ClampIdx)));
719 return EmitIntrinsicCall(CGM.getHLSLRuntime().getSampleClampIntrinsic(),
720 Args, RetTy);
721 }
722 case Builtin::BI__builtin_hlsl_resource_sample_bias: {
723 Value *HandleOp = EmitScalarExpr(E->getArg(0));
724 Value *SamplerOp = EmitScalarExpr(E->getArg(1));
725 Value *CoordOp = EmitScalarExpr(E->getArg(2));
726 Value *BiasOp = EmitScalarExpr(E->getArg(3));
727 const HLSLAttributedResourceType *RT = getRequiredHandleType(E, 0);
728
729 SmallVector<Value *, 6> Args; // Max 6 arguments for SampleBias
730 Args.push_back(HandleOp);
731 Args.push_back(SamplerOp);
732 Args.push_back(CoordOp);
733 Args.push_back(BiasOp);
734 constexpr unsigned OffsetIdx = 4;
735 Args.push_back(emitHlslSampleOffset(*this, E, RT, OffsetIdx));
736
737 llvm::Type *RetTy = ConvertType(E->getType());
738 const unsigned ClampIdx = getHlslClampArgIndex(RT, OffsetIdx);
739 if (E->getNumArgs() <= ClampIdx)
740 return EmitIntrinsicCall(CGM.getHLSLRuntime().getSampleBiasIntrinsic(),
741 Args, RetTy);
742
743 Args.push_back(EmitScalarExpr(E->getArg(ClampIdx)));
744 return EmitIntrinsicCall(CGM.getHLSLRuntime().getSampleBiasClampIntrinsic(),
745 Args, RetTy);
746 }
747 case Builtin::BI__builtin_hlsl_resource_sample_grad: {
748 Value *HandleOp = EmitScalarExpr(E->getArg(0));
749 Value *SamplerOp = EmitScalarExpr(E->getArg(1));
750 Value *CoordOp = EmitScalarExpr(E->getArg(2));
751 Value *DDXOp = EmitScalarExpr(E->getArg(3));
752 Value *DDYOp = EmitScalarExpr(E->getArg(4));
753 const HLSLAttributedResourceType *RT = getRequiredHandleType(E, 0);
754
756 Args.push_back(HandleOp);
757 Args.push_back(SamplerOp);
758 Args.push_back(CoordOp);
759 Args.push_back(DDXOp);
760 Args.push_back(DDYOp);
761 constexpr unsigned OffsetIdx = 5;
762 Args.push_back(emitHlslSampleOffset(*this, E, RT, OffsetIdx));
763
764 llvm::Type *RetTy = ConvertType(E->getType());
765
766 const unsigned ClampIdx = getHlslClampArgIndex(RT, OffsetIdx);
767 if (E->getNumArgs() <= ClampIdx)
768 return Builder.CreateIntrinsic(
769 RetTy, CGM.getHLSLRuntime().getSampleGradIntrinsic(), Args);
770
771 Args.push_back(EmitScalarExpr(E->getArg(ClampIdx)));
772 return Builder.CreateIntrinsic(
773 RetTy, CGM.getHLSLRuntime().getSampleGradClampIntrinsic(), Args);
774 }
775 case Builtin::BI__builtin_hlsl_resource_sample_level: {
776 Value *HandleOp = EmitScalarExpr(E->getArg(0));
777 Value *SamplerOp = EmitScalarExpr(E->getArg(1));
778 Value *CoordOp = EmitScalarExpr(E->getArg(2));
779 Value *LODOp = EmitScalarExpr(E->getArg(3));
780 const HLSLAttributedResourceType *RT = getRequiredHandleType(E, 0);
781
782 SmallVector<Value *, 5> Args; // Max 5 arguments for SampleLevel
783 Args.push_back(HandleOp);
784 Args.push_back(SamplerOp);
785 Args.push_back(CoordOp);
786 Args.push_back(LODOp);
787 constexpr unsigned OffsetIdx = 4;
788 Args.push_back(emitHlslSampleOffset(*this, E, RT, OffsetIdx));
789
790 llvm::Type *RetTy = ConvertType(E->getType());
791 return Builder.CreateIntrinsic(
792 RetTy, CGM.getHLSLRuntime().getSampleLevelIntrinsic(), Args);
793 }
794 case Builtin::BI__builtin_hlsl_resource_load_level: {
795 Value *HandleOp = EmitScalarExpr(E->getArg(0));
796 Value *CoordLODOp = EmitScalarExpr(E->getArg(1));
797 const HLSLAttributedResourceType *RT = getRequiredHandleType(E, 0);
798
799 const auto &Attrs = RT->getAttrs();
800
801 Value *CoordOp = nullptr;
802 Value *LODOp = nullptr;
803 if (Attrs.ResourceClass == llvm::dxil::ResourceClass::UAV) {
804 // A UAV descriptor binds a single mip slice, so a RWTexture location is
805 // all coordinate and there is no mip level to select.
806 CoordOp = CoordLODOp;
807 LODOp = llvm::PoisonValue::get(Int32Ty);
808 } else {
809 // Split CoordLOD into Coord and LOD. 1D resources use a scalar
810 // coordinate rather than a 1-element vector.
811 unsigned CoordSize =
812 clang::hlsl::getResourceDimensions(Attrs.ResourceDimension) +
813 (Attrs.IsArray ? 1 : 0);
814 assert(cast<llvm::FixedVectorType>(CoordLODOp->getType())
815 ->getNumElements() == CoordSize + 1 &&
816 "CoordLOD must have one element per coordinate, plus the level");
817
818 if (CoordSize == 1) {
819 CoordOp = Builder.CreateExtractElement(CoordLODOp, uint64_t(0),
820 "hlsl.load.coord");
821 } else {
823 for (unsigned I = 0; I < CoordSize; ++I)
824 Mask.push_back(I);
825 CoordOp =
826 Builder.CreateShuffleVector(CoordLODOp, Mask, "hlsl.load.coord");
827 }
828 LODOp =
829 Builder.CreateExtractElement(CoordLODOp, CoordSize, "hlsl.load.lod");
830 }
831
833 Args.push_back(HandleOp);
834 Args.push_back(CoordOp);
835 Args.push_back(LODOp);
836 Args.push_back(emitHlslOffset(*this, E, 2, getOffsetType(CGM, RT)));
837
838 llvm::Type *RetTy = ConvertType(E->getType());
839 return Builder.CreateIntrinsic(
840 RetTy, CGM.getHLSLRuntime().getLoadLevelIntrinsic(), Args);
841 }
842 case Builtin::BI__builtin_hlsl_resource_load_ms: {
843 Value *HandleOp = EmitScalarExpr(E->getArg(0));
844 Value *CoordOp = EmitScalarExpr(E->getArg(1));
845 Value *SampleOp = EmitScalarExpr(E->getArg(2));
846 const HLSLAttributedResourceType *RT = getRequiredHandleType(E, 0);
847
849 Args.push_back(HandleOp);
850 Args.push_back(CoordOp);
851 Args.push_back(SampleOp);
852 Args.push_back(emitHlslOffset(*this, E, 3, getOffsetType(CGM, RT)));
853
854 llvm::Type *RetTy = ConvertType(E->getType());
855 return Builder.CreateIntrinsic(
856 RetTy, CGM.getHLSLRuntime().getLoadMSIntrinsic(), Args);
857 }
858 case Builtin::BI__builtin_hlsl_resource_sample_cmp: {
859 Value *HandleOp = EmitScalarExpr(E->getArg(0));
860 Value *SamplerOp = EmitScalarExpr(E->getArg(1));
861 Value *CoordOp = EmitScalarExpr(E->getArg(2));
862 Value *CmpOp = EmitScalarExpr(E->getArg(3));
863 const HLSLAttributedResourceType *RT = getRequiredHandleType(E, 0);
864
865 SmallVector<Value *, 6> Args; // Max 6 arguments for SampleCmp
866 Args.push_back(HandleOp);
867 Args.push_back(SamplerOp);
868 Args.push_back(CoordOp);
869 Args.push_back(CmpOp);
870 constexpr unsigned OffsetIdx = 4;
871 Args.push_back(emitHlslSampleOffset(*this, E, RT, OffsetIdx));
872
873 llvm::Type *RetTy = ConvertType(E->getType());
874 const unsigned ClampIdx = getHlslClampArgIndex(RT, OffsetIdx);
875 if (E->getNumArgs() <= ClampIdx)
876 return Builder.CreateIntrinsic(
877 RetTy, CGM.getHLSLRuntime().getSampleCmpIntrinsic(), Args);
878
879 Args.push_back(EmitScalarExpr(E->getArg(ClampIdx)));
880 return Builder.CreateIntrinsic(
881 RetTy, CGM.getHLSLRuntime().getSampleCmpClampIntrinsic(), Args);
882 }
883 case Builtin::BI__builtin_hlsl_resource_sample_cmp_level_zero: {
884 Value *HandleOp = EmitScalarExpr(E->getArg(0));
885 Value *SamplerOp = EmitScalarExpr(E->getArg(1));
886 Value *CoordOp = EmitScalarExpr(E->getArg(2));
887 Value *CmpOp = EmitScalarExpr(E->getArg(3));
888 const HLSLAttributedResourceType *RT = getRequiredHandleType(E, 0);
889
891 Args.push_back(HandleOp);
892 Args.push_back(SamplerOp);
893 Args.push_back(CoordOp);
894 Args.push_back(CmpOp);
895 constexpr unsigned OffsetIdx = 4;
896 Args.push_back(emitHlslSampleOffset(*this, E, RT, OffsetIdx));
897
898 llvm::Type *RetTy = ConvertType(E->getType());
899 return Builder.CreateIntrinsic(
900 RetTy, CGM.getHLSLRuntime().getSampleCmpLevelZeroIntrinsic(), Args);
901 }
902 case Builtin::BI__builtin_hlsl_resource_calculate_lod: {
903 Value *HandleOp = EmitScalarExpr(E->getArg(0));
904 Value *SamplerOp = EmitScalarExpr(E->getArg(1));
905 Value *CoordOp = EmitScalarExpr(E->getArg(2));
906
907 return EmitIntrinsicCall(CGM.getHLSLRuntime().getCalculateLodIntrinsic(),
908 {HandleOp, SamplerOp, CoordOp},
909 ConvertType(E->getType()));
910 }
911 case Builtin::BI__builtin_hlsl_resource_calculate_lod_unclamped: {
912 Value *HandleOp = EmitScalarExpr(E->getArg(0));
913 Value *SamplerOp = EmitScalarExpr(E->getArg(1));
914 Value *CoordOp = EmitScalarExpr(E->getArg(2));
915
916 return EmitIntrinsicCall(
917 CGM.getHLSLRuntime().getCalculateLodUnclampedIntrinsic(),
918 {HandleOp, SamplerOp, CoordOp}, ConvertType(E->getType()));
919 }
920 case Builtin::BI__builtin_hlsl_resource_gather: {
921 Value *HandleOp = EmitScalarExpr(E->getArg(0));
922 Value *SamplerOp = EmitScalarExpr(E->getArg(1));
923 Value *CoordOp = EmitScalarExpr(E->getArg(2));
924 Value *ComponentOp = EmitScalarExpr(E->getArg(3));
925 const HLSLAttributedResourceType *RT = getRequiredHandleType(E, 0);
926
928 Args.push_back(HandleOp);
929 Args.push_back(SamplerOp);
930 Args.push_back(CoordOp);
931 Args.push_back(ComponentOp);
932 Args.push_back(emitHlslOffset(*this, E, 4, getOffsetType(CGM, RT)));
933
934 llvm::Type *RetTy = ConvertType(E->getType());
935 return Builder.CreateIntrinsic(
936 RetTy, CGM.getHLSLRuntime().getGatherIntrinsic(), Args);
937 }
938 case Builtin::BI__builtin_hlsl_resource_gather_cmp: {
939 Value *HandleOp = EmitScalarExpr(E->getArg(0));
940 Value *SamplerOp = EmitScalarExpr(E->getArg(1));
941 Value *CoordOp = EmitScalarExpr(E->getArg(2));
942 Value *CompareOp = EmitScalarExpr(E->getArg(3));
943
945 Args.push_back(HandleOp);
946 Args.push_back(SamplerOp);
947 Args.push_back(CoordOp);
948 Args.push_back(CompareOp);
949
950 if (CGM.getTarget().getTriple().isDXIL()) {
951 Value *ComponentOp = EmitScalarExpr(E->getArg(4));
952 Args.push_back(ComponentOp);
953 }
954
955 const HLSLAttributedResourceType *RT = getRequiredHandleType(E, 0);
956 Args.push_back(emitHlslOffset(*this, E, 5, getOffsetType(CGM, RT)));
957
958 llvm::Type *RetTy = ConvertType(E->getType());
959 return Builder.CreateIntrinsic(
960 RetTy, CGM.getHLSLRuntime().getGatherCmpIntrinsic(), Args);
961 }
962 case Builtin::BI__builtin_hlsl_resource_load_with_status:
963 case Builtin::BI__builtin_hlsl_resource_load_with_status_typed: {
964 Value *HandleOp = EmitScalarExpr(E->getArg(0));
965 Value *IndexOp = EmitScalarExpr(E->getArg(1));
966
967 // Get the *address* of the status argument to write to it by reference
968 LValue StatusLVal = EmitLValue(E->getArg(2));
969 Address StatusAddr = StatusLVal.getAddress();
970
971 QualType HandleTy = E->getArg(0)->getType();
972 const HLSLAttributedResourceType *RT =
973 HandleTy->getAs<HLSLAttributedResourceType>();
974 assert(CGM.getTarget().getTriple().getArch() == llvm::Triple::dxil &&
975 "Only DXIL currently implements load with status");
976
977 Intrinsic::ID IntrID = RT->getAttrs().RawBuffer
978 ? llvm::Intrinsic::dx_resource_load_rawbuffer
979 : llvm::Intrinsic::dx_resource_load_typedbuffer;
980
981 llvm::Type *DataTy = ConvertType(E->getType());
982 llvm::Type *RetTy = llvm::StructType::get(Builder.getContext(),
983 {DataTy, Builder.getInt1Ty()});
984
986 Args.push_back(HandleOp);
987 Args.push_back(IndexOp);
988
989 if (RT->isRaw()) {
990 Value *Offset = Builder.getInt32(0);
991 // The offset parameter needs to be poison for ByteAddressBuffer
992 if (!RT->isStructured())
993 Offset = llvm::PoisonValue::get(Builder.getInt32Ty());
994 Args.push_back(Offset);
995 }
996
997 // The load intrinsics give us a (T value, i1 status) pair -
998 // shepherd these into the return value and out reference respectively.
999 Value *ResRet =
1000 Builder.CreateIntrinsic(RetTy, IntrID, Args, {}, "ld.struct");
1001 Value *LoadedValue = Builder.CreateExtractValue(ResRet, {0}, "ld.value");
1002 Value *StatusBit = Builder.CreateExtractValue(ResRet, {1}, "ld.status");
1003 Value *ExtendedStatus =
1004 Builder.CreateZExt(StatusBit, Builder.getInt32Ty(), "ld.status.ext");
1005 Builder.CreateStore(ExtendedStatus, StatusAddr);
1006
1007 return LoadedValue;
1008 }
1009 case Builtin::BI__builtin_hlsl_resource_uninitializedhandle: {
1010 llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType());
1011 return llvm::PoisonValue::get(HandleTy);
1012 }
1013 case Builtin::BI__builtin_hlsl_resource_handlefrombinding: {
1014 llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType());
1015 Value *RegisterOp = EmitScalarExpr(E->getArg(1));
1016 Value *SpaceOp = EmitScalarExpr(E->getArg(2));
1017 Value *RangeOp = EmitScalarExpr(E->getArg(3));
1018 Value *IndexOp = EmitScalarExpr(E->getArg(4));
1019 Value *Name = EmitScalarExpr(E->getArg(5));
1020 llvm::Intrinsic::ID IntrinsicID =
1021 CGM.getHLSLRuntime().getCreateHandleFromBindingIntrinsic();
1022 SmallVector<Value *> Args{SpaceOp, RegisterOp, RangeOp, IndexOp, Name};
1023 return Builder.CreateIntrinsic(HandleTy, IntrinsicID, Args);
1024 }
1025 case Builtin::BI__builtin_hlsl_resource_handlefromimplicitbinding: {
1026 llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType());
1027 Value *OrderID = EmitScalarExpr(E->getArg(1));
1028 Value *SpaceOp = EmitScalarExpr(E->getArg(2));
1029 Value *RangeOp = EmitScalarExpr(E->getArg(3));
1030 Value *IndexOp = EmitScalarExpr(E->getArg(4));
1031 Value *Name = EmitScalarExpr(E->getArg(5));
1032 llvm::Intrinsic::ID IntrinsicID =
1033 CGM.getHLSLRuntime().getCreateHandleFromImplicitBindingIntrinsic();
1034 SmallVector<Value *> Args{OrderID, SpaceOp, RangeOp, IndexOp, Name};
1035 return Builder.CreateIntrinsic(HandleTy, IntrinsicID, Args);
1036 }
1037 case Builtin::BI__builtin_hlsl_resource_counterhandlefromimplicitbinding: {
1038 Value *MainHandle = EmitScalarExpr(E->getArg(0));
1039 if (!CGM.getTriple().isSPIRV())
1040 return MainHandle;
1041
1042 llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType());
1043 Value *OrderID = EmitScalarExpr(E->getArg(1));
1044 Value *SpaceOp = EmitScalarExpr(E->getArg(2));
1045 llvm::Intrinsic::ID IntrinsicID =
1046 llvm::Intrinsic::spv_resource_counterhandlefromimplicitbinding;
1047 SmallVector<Value *> Args{MainHandle, OrderID, SpaceOp};
1048 return EmitIntrinsicCall(IntrinsicID, {HandleTy, MainHandle->getType()},
1049 Args);
1050 }
1051 case Builtin::BI__builtin_hlsl_resource_handlefromheap: {
1052 llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType());
1053 Value *IndexOp = EmitScalarExpr(E->getArg(1));
1054 llvm::Intrinsic::ID IntrinsicID =
1055 CGM.getHLSLRuntime().getCreateHandleFromHeapIntrinsic();
1056 return Builder.CreateIntrinsic(HandleTy, IntrinsicID, {IndexOp});
1057 }
1058 case Builtin::BI__builtin_hlsl_resource_counterhandlefromheap: {
1059 Value *MainHandle = EmitScalarExpr(E->getArg(0));
1060 if (!CGM.getTriple().isSPIRV())
1061 return MainHandle;
1062
1063 llvm::Type *HandleTy = CGM.getTypes().ConvertType(E->getType());
1064 llvm::Intrinsic::ID IntrinsicID =
1065 llvm::Intrinsic::spv_resource_counterhandlefromheap;
1066 return EmitIntrinsicCall(IntrinsicID, {HandleTy, MainHandle->getType()},
1067 {MainHandle});
1068 }
1069
1070 case Builtin::BI__builtin_hlsl_resource_nonuniformindex: {
1071 Value *IndexOp = EmitScalarExpr(E->getArg(0));
1072 llvm::Type *RetTy = ConvertType(E->getType());
1073 return Builder.CreateIntrinsic(
1074 RetTy, CGM.getHLSLRuntime().getNonUniformResourceIndexIntrinsic(),
1075 ArrayRef<Value *>{IndexOp});
1076 }
1077 case Builtin::BI__builtin_hlsl_resource_getdimensions_x:
1078 case Builtin::BI__builtin_hlsl_resource_getdimensions_x_float:
1079 return emitGetDimensions(*this, E,
1080 CGM.getHLSLRuntime().getGetDimensionsXIntrinsic(),
1081 1, /*HasLod=*/false);
1082 case Builtin::BI__builtin_hlsl_resource_getdimensions_xy:
1083 case Builtin::BI__builtin_hlsl_resource_getdimensions_xy_float:
1084 return emitGetDimensions(*this, E,
1085 CGM.getHLSLRuntime().getGetDimensionsXYIntrinsic(),
1086 2, /*HasLod=*/false);
1087 case Builtin::BI__builtin_hlsl_resource_getdimensions_levels_xy:
1088 case Builtin::BI__builtin_hlsl_resource_getdimensions_levels_xy_float:
1089 return emitGetDimensions(
1090 *this, E, CGM.getHLSLRuntime().getGetDimensionsLevelsXYIntrinsic(), 3,
1091 /*HasLod=*/true);
1092 case Builtin::BI__builtin_hlsl_resource_getstride: {
1093 LValue Stride = EmitLValue(E->getArg(1));
1094 return emitBufferStride(this, E->getArg(0), Stride);
1095 }
1096 case Builtin::BI__builtin_hlsl_all: {
1097 Value *Op0 = EmitScalarExpr(E->getArg(0));
1098 return Builder.CreateIntrinsic(
1099 /*ReturnType=*/llvm::Type::getInt1Ty(getLLVMContext()),
1100 CGM.getHLSLRuntime().getAllIntrinsic(), ArrayRef<Value *>{Op0}, nullptr,
1101 "hlsl.all");
1102 }
1103 case Builtin::BI__builtin_hlsl_and: {
1104 Value *Op0 = EmitScalarExpr(E->getArg(0));
1105 Value *Op1 = EmitScalarExpr(E->getArg(1));
1106 return Builder.CreateAnd(Op0, Op1, "hlsl.and");
1107 }
1108 case Builtin::BI__builtin_hlsl_or: {
1109 Value *Op0 = EmitScalarExpr(E->getArg(0));
1110 Value *Op1 = EmitScalarExpr(E->getArg(1));
1111 return Builder.CreateOr(Op0, Op1, "hlsl.or");
1112 }
1113 case Builtin::BI__builtin_hlsl_any: {
1114 Value *Op0 = EmitScalarExpr(E->getArg(0));
1115 return Builder.CreateIntrinsic(
1116 /*ReturnType=*/llvm::Type::getInt1Ty(getLLVMContext()),
1117 CGM.getHLSLRuntime().getAnyIntrinsic(), ArrayRef<Value *>{Op0}, nullptr,
1118 "hlsl.any");
1119 }
1120 case Builtin::BI__builtin_hlsl_asdouble:
1121 return handleAsDoubleBuiltin(*this, E);
1122 case Builtin::BI__builtin_hlsl_elementwise_clamp: {
1123 Value *OpX = EmitScalarExpr(E->getArg(0));
1124 Value *OpMin = EmitScalarExpr(E->getArg(1));
1125 Value *OpMax = EmitScalarExpr(E->getArg(2));
1126
1127 QualType Ty = E->getArg(0)->getType();
1128 if (auto *VecTy = Ty->getAs<VectorType>())
1129 Ty = VecTy->getElementType();
1130
1131 Intrinsic::ID Intr;
1132 if (Ty->isFloatingType()) {
1133 Intr = CGM.getHLSLRuntime().getNClampIntrinsic();
1134 } else if (Ty->isUnsignedIntegerType()) {
1135 Intr = CGM.getHLSLRuntime().getUClampIntrinsic();
1136 } else {
1137 assert(Ty->isSignedIntegerType());
1138 Intr = CGM.getHLSLRuntime().getSClampIntrinsic();
1139 }
1140 return Builder.CreateIntrinsic(
1141 /*ReturnType=*/OpX->getType(), Intr,
1142 ArrayRef<Value *>{OpX, OpMin, OpMax}, nullptr, "hlsl.clamp");
1143 }
1144 case Builtin::BI__builtin_hlsl_dot: {
1145 Value *Op0 = EmitScalarExpr(E->getArg(0));
1146 Value *Op1 = EmitScalarExpr(E->getArg(1));
1147 llvm::Type *T0 = Op0->getType();
1148 llvm::Type *T1 = Op1->getType();
1149
1150 // If the arguments are scalars, just emit a multiply
1151 if (!T0->isVectorTy() && !T1->isVectorTy()) {
1152 if (T0->isFloatingPointTy())
1153 return Builder.CreateFMul(Op0, Op1, "hlsl.dot");
1154
1155 if (T0->isIntegerTy())
1156 return Builder.CreateMul(Op0, Op1, "hlsl.dot");
1157
1158 llvm_unreachable(
1159 "Scalar dot product is only supported on ints and floats.");
1160 }
1161 // For vectors, validate types and emit the appropriate intrinsic
1162 assert(CGM.getContext().hasSameUnqualifiedType(E->getArg(0)->getType(),
1163 E->getArg(1)->getType()) &&
1164 "Dot product operands must have the same type.");
1165
1166 auto *VecTy0 = E->getArg(0)->getType()->castAs<VectorType>();
1167 assert(VecTy0 && "Dot product argument must be a vector.");
1168
1169 return Builder.CreateIntrinsic(
1170 /*ReturnType=*/T0->getScalarType(),
1171 getDotProductIntrinsic(CGM.getHLSLRuntime(), VecTy0->getElementType()),
1172 ArrayRef<Value *>{Op0, Op1}, nullptr, "hlsl.dot");
1173 }
1174 case Builtin::BI__builtin_hlsl_dot4add_i8packed: {
1175 Value *X = EmitScalarExpr(E->getArg(0));
1176 Value *Y = EmitScalarExpr(E->getArg(1));
1177 Value *Acc = EmitScalarExpr(E->getArg(2));
1178
1179 Intrinsic::ID ID = CGM.getHLSLRuntime().getDot4AddI8PackedIntrinsic();
1180 // Note that the argument order disagrees between the builtin and the
1181 // intrinsic here.
1182 return Builder.CreateIntrinsic(
1183 /*ReturnType=*/Acc->getType(), ID, ArrayRef<Value *>{Acc, X, Y},
1184 nullptr, "hlsl.dot4add.i8packed");
1185 }
1186 case Builtin::BI__builtin_hlsl_dot4add_u8packed: {
1187 Value *X = EmitScalarExpr(E->getArg(0));
1188 Value *Y = EmitScalarExpr(E->getArg(1));
1189 Value *Acc = EmitScalarExpr(E->getArg(2));
1190
1191 Intrinsic::ID ID = CGM.getHLSLRuntime().getDot4AddU8PackedIntrinsic();
1192 // Note that the argument order disagrees between the builtin and the
1193 // intrinsic here.
1194 return Builder.CreateIntrinsic(
1195 /*ReturnType=*/Acc->getType(), ID, ArrayRef<Value *>{Acc, X, Y},
1196 nullptr, "hlsl.dot4add.u8packed");
1197 }
1198 case Builtin::BI__builtin_hlsl_elementwise_firstbithigh: {
1199 Value *X = EmitScalarExpr(E->getArg(0));
1200
1201 return Builder.CreateIntrinsic(
1202 /*ReturnType=*/ConvertType(E->getType()),
1203 getFirstBitHighIntrinsic(CGM.getHLSLRuntime(), E->getArg(0)->getType()),
1204 ArrayRef<Value *>{X}, nullptr, "hlsl.firstbithigh");
1205 }
1206 case Builtin::BI__builtin_hlsl_elementwise_firstbitlow: {
1207 Value *X = EmitScalarExpr(E->getArg(0));
1208
1209 return Builder.CreateIntrinsic(
1210 /*ReturnType=*/ConvertType(E->getType()),
1211 CGM.getHLSLRuntime().getFirstBitLowIntrinsic(), ArrayRef<Value *>{X},
1212 nullptr, "hlsl.firstbitlow");
1213 }
1214 case Builtin::BI__builtin_hlsl_elementwise_f16tof32: {
1215 return handleElementwiseF16ToF32(*this, E);
1216 }
1217 case Builtin::BI__builtin_hlsl_elementwise_f32tof16: {
1218 return handleElementwiseF32ToF16(*this, E);
1219 }
1220 case Builtin::BI__builtin_hlsl_elementwise_frac: {
1221 Value *Op0 = EmitScalarExpr(E->getArg(0));
1222 if (!E->getArg(0)->getType()->hasFloatingRepresentation())
1223 llvm_unreachable("frac operand must have a float representation");
1224 return Builder.CreateIntrinsic(
1225 /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getFracIntrinsic(),
1226 ArrayRef<Value *>{Op0}, nullptr, "hlsl.frac");
1227 }
1228 case Builtin::BI__builtin_hlsl_elementwise_isinf: {
1229 Value *Op0 = EmitScalarExpr(E->getArg(0));
1230 if (!E->getArg(0)->getType()->hasFloatingRepresentation())
1231 llvm_unreachable("isinf operand must have a float representation");
1232 llvm::Type *retType = getAggregateType(
1233 llvm::Type::getInt1Ty(getLLVMContext()), E->getArg(0)->getType());
1234 return Builder.CreateIntrinsic(
1235 retType, CGM.getHLSLRuntime().getIsInfIntrinsic(),
1236 ArrayRef<Value *>{Op0}, nullptr, "hlsl.isinf");
1237 }
1238 case Builtin::BI__builtin_hlsl_elementwise_isnan: {
1239 Value *Op0 = EmitScalarExpr(E->getArg(0));
1240 if (!E->getArg(0)->getType()->hasFloatingRepresentation())
1241 llvm_unreachable("isnan operand must have a float representation");
1242 llvm::Type *retType = getAggregateType(
1243 llvm::Type::getInt1Ty(getLLVMContext()), E->getArg(0)->getType());
1244 return Builder.CreateIntrinsic(
1245 retType, CGM.getHLSLRuntime().getIsNaNIntrinsic(),
1246 ArrayRef<Value *>{Op0}, nullptr, "hlsl.isnan");
1247 }
1248 case Builtin::BI__builtin_hlsl_mad: {
1249 Value *M = EmitScalarExpr(E->getArg(0));
1250 Value *A = EmitScalarExpr(E->getArg(1));
1251 Value *B = EmitScalarExpr(E->getArg(2));
1253 return Builder.CreateIntrinsic(
1254 /*ReturnType*/ M->getType(), Intrinsic::fmuladd,
1255 ArrayRef<Value *>{M, A, B}, nullptr, "hlsl.fmad");
1256
1258 if (CGM.getTarget().getTriple().getArch() == llvm::Triple::dxil)
1259 return Builder.CreateIntrinsic(
1260 /*ReturnType*/ M->getType(), Intrinsic::dx_imad,
1261 ArrayRef<Value *>{M, A, B}, nullptr, "dx.imad");
1262
1263 Value *Mul = Builder.CreateNSWMul(M, A);
1264 return Builder.CreateNSWAdd(Mul, B);
1265 }
1267 if (CGM.getTarget().getTriple().getArch() == llvm::Triple::dxil)
1268 return Builder.CreateIntrinsic(
1269 /*ReturnType=*/M->getType(), Intrinsic::dx_umad,
1270 ArrayRef<Value *>{M, A, B}, nullptr, "dx.umad");
1271
1272 Value *Mul = Builder.CreateNUWMul(M, A);
1273 return Builder.CreateNUWAdd(Mul, B);
1274 }
1275 case Builtin::BI__builtin_hlsl_mul: {
1276 Value *Op0 = EmitScalarExpr(E->getArg(0));
1277 Value *Op1 = EmitScalarExpr(E->getArg(1));
1278 QualType QTy0 = E->getArg(0)->getType();
1279 QualType QTy1 = E->getArg(1)->getType();
1280
1281 bool IsVec0 = QTy0->isVectorType();
1282 bool IsVec1 = QTy1->isVectorType();
1283 bool IsMat0 = QTy0->isConstantMatrixType();
1284 bool IsMat1 = QTy1->isConstantMatrixType();
1285
1286 // The matrix multiply intrinsic only operates on column-major order
1287 // matrices. Therefore matrix memory layout transforms must be inserted
1288 // before and after matrix multiply intrinsics.
1289 // Use whichever operand is a matrix to discover its declared layout.
1290 bool IsRowMajorMat0 = IsMat0 && isMatrixRowMajor(getLangOpts(), QTy0);
1291 bool IsRowMajorMat1 = IsMat1 && isMatrixRowMajor(getLangOpts(), QTy1);
1292
1293 llvm::MatrixBuilder MB(Builder);
1294 if (IsVec0 && IsMat1) {
1295 unsigned N = QTy0->castAs<VectorType>()->getNumElements();
1296 auto *MatTy = QTy1->castAs<ConstantMatrixType>();
1297 unsigned Rows = MatTy->getNumRows();
1298 unsigned Cols = MatTy->getNumColumns();
1299 assert(N == Rows && "vector length must match matrix row count");
1300 if (IsRowMajorMat1)
1301 Op1 = MB.CreateRowMajorToColumnMajorTransform(Op1, Rows, Cols);
1302 return MB.CreateMatrixMultiply(Op0, Op1, 1, N, Cols, "hlsl.mul");
1303 }
1304 if (IsMat0 && IsVec1) {
1305 auto *MatTy = QTy0->castAs<ConstantMatrixType>();
1306 unsigned Rows = MatTy->getNumRows();
1307 unsigned Cols = MatTy->getNumColumns();
1308 assert(QTy1->castAs<VectorType>()->getNumElements() == Cols &&
1309 "vector length must match matrix column count");
1310 if (IsRowMajorMat0)
1311 Op0 = MB.CreateRowMajorToColumnMajorTransform(Op0, Rows, Cols);
1312 return MB.CreateMatrixMultiply(Op0, Op1, Rows, Cols, 1, "hlsl.mul");
1313 }
1314 assert(IsMat0 && IsMat1);
1315 auto *MatTy0 = QTy0->castAs<ConstantMatrixType>();
1316 auto *MatTy1 = QTy1->castAs<ConstantMatrixType>();
1317 unsigned Rows0 = MatTy0->getNumRows();
1318 unsigned Rows1 = MatTy1->getNumRows();
1319 unsigned Cols0 = MatTy0->getNumColumns();
1320 unsigned Cols1 = MatTy1->getNumColumns();
1321 assert(Cols0 == Rows1 &&
1322 "inner matrix dimensions must match for multiplication");
1323 if (IsRowMajorMat0)
1324 Op0 = MB.CreateRowMajorToColumnMajorTransform(Op0, Rows0, Cols0);
1325 if (IsRowMajorMat1)
1326 Op1 = MB.CreateRowMajorToColumnMajorTransform(Op1, Rows1, Cols1);
1327
1328 Value *Result =
1329 MB.CreateMatrixMultiply(Op0, Op1, Rows0, Cols0, Cols1, "hlsl.mul");
1330
1331 bool IsResultRowMajor = isMatrixRowMajor(getLangOpts(), E->getType());
1332 if (IsResultRowMajor)
1333 Result = MB.CreateColumnMajorToRowMajorTransform(Result, Rows0, Cols1);
1334 return Result;
1335 }
1336 case Builtin::BI__builtin_hlsl_transpose: {
1337 Value *Op0 = EmitScalarExpr(E->getArg(0));
1338 auto *MatTy = E->getArg(0)->getType()->castAs<ConstantMatrixType>();
1339 unsigned Rows = MatTy->getNumRows();
1340 unsigned Cols = MatTy->getNumColumns();
1341 llvm::MatrixBuilder MB(Builder);
1342 // The correct lowering of a transpose depends on both the source layout
1343 // and the result layout.
1344 bool SrcRowMajor = isMatrixRowMajor(getLangOpts(), E->getArg(0)->getType());
1345 bool DstRowMajor = isMatrixRowMajor(getLangOpts(), E->getType());
1346 // When the source & result layouts differ, the operand already holds the
1347 // transposed result, ie transpose is a no-op on the underlying vector.
1348 if (SrcRowMajor != DstRowMajor)
1349 return Op0;
1350 // When the source and result share a layout, emit a transpose.
1351 if (SrcRowMajor)
1352 // For row-major operands the dimensions are swapped
1353 return MB.CreateMatrixTranspose(Op0, Cols, Rows);
1354 return MB.CreateMatrixTranspose(Op0, Rows, Cols);
1355 }
1356 case Builtin::BI__builtin_hlsl_elementwise_rcp: {
1357 Value *Op0 = EmitScalarExpr(E->getArg(0));
1358 if (!E->getArg(0)->getType()->hasFloatingRepresentation())
1359 llvm_unreachable("rcp operand must have a float representation");
1360 llvm::Type *Ty = Op0->getType();
1361 llvm::Type *EltTy = Ty->getScalarType();
1362 Constant *One = Ty->isVectorTy()
1363 ? ConstantVector::getSplat(
1364 ElementCount::getFixed(
1365 cast<FixedVectorType>(Ty)->getNumElements()),
1366 ConstantFP::get(EltTy, 1.0))
1367 : ConstantFP::get(EltTy, 1.0);
1368 return Builder.CreateFDiv(One, Op0, "hlsl.rcp");
1369 }
1370 case Builtin::BI__builtin_hlsl_elementwise_rsqrt: {
1371 Value *Op0 = EmitScalarExpr(E->getArg(0));
1372 if (!E->getArg(0)->getType()->hasFloatingRepresentation())
1373 llvm_unreachable("rsqrt operand must have a float representation");
1374 return Builder.CreateIntrinsic(
1375 /*ReturnType=*/Op0->getType(), CGM.getHLSLRuntime().getRsqrtIntrinsic(),
1376 ArrayRef<Value *>{Op0}, nullptr, "hlsl.rsqrt");
1377 }
1378 case Builtin::BI__builtin_hlsl_elementwise_saturate: {
1379 Value *Op0 = EmitScalarExpr(E->getArg(0));
1380 assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
1381 "saturate operand must have a float representation");
1382 return Builder.CreateIntrinsic(
1383 /*ReturnType=*/Op0->getType(),
1384 CGM.getHLSLRuntime().getSaturateIntrinsic(), ArrayRef<Value *>{Op0},
1385 nullptr, "hlsl.saturate");
1386 }
1387 case Builtin::BI__builtin_hlsl_wave_prefix_count_bits: {
1388 Value *Op = EmitScalarExpr(E->getArg(0));
1389 assert(Op->getType()->isIntegerTy(1) &&
1390 "WavePrefixBitCount operand must be a boolean type");
1391
1392 Intrinsic::ID IID =
1394
1395 return EmitIntrinsicCall(IID, ArrayRef{Op}, "hlsl.wave.prefix.bit.count");
1396 }
1397 case Builtin::BI__builtin_hlsl_select: {
1398 Value *OpCond = EmitScalarExpr(E->getArg(0));
1399 RValue RValTrue = EmitAnyExpr(E->getArg(1));
1400 Value *OpTrue =
1401 RValTrue.isScalar()
1402 ? RValTrue.getScalarVal()
1403 : Builder.CreateLoad(RValTrue.getAggregateAddress(), "true_val");
1404 RValue RValFalse = EmitAnyExpr(E->getArg(2));
1405 Value *OpFalse =
1406 RValFalse.isScalar()
1407 ? RValFalse.getScalarVal()
1408 : Builder.CreateLoad(RValFalse.getAggregateAddress(), "false_val");
1409 if (auto *VTy = E->getType()->getAs<VectorType>()) {
1410 if (!OpTrue->getType()->isVectorTy())
1411 OpTrue =
1412 Builder.CreateVectorSplat(VTy->getNumElements(), OpTrue, "splat");
1413 if (!OpFalse->getType()->isVectorTy())
1414 OpFalse =
1415 Builder.CreateVectorSplat(VTy->getNumElements(), OpFalse, "splat");
1416 }
1417
1418 Value *SelectVal =
1419 Builder.CreateSelect(OpCond, OpTrue, OpFalse, "hlsl.select");
1420 if (!RValTrue.isScalar())
1421 Builder.CreateStore(SelectVal, ReturnValue.getAddress(),
1422 ReturnValue.isVolatile());
1423
1424 return SelectVal;
1425 }
1426 case Builtin::BI__builtin_hlsl_wave_active_all_equal: {
1427 Value *Op = EmitScalarExpr(E->getArg(0));
1428
1429 Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveActiveAllEqualIntrinsic();
1430 return EmitIntrinsicCall(ID, {Op->getType()}, {Op});
1431 }
1432 case Builtin::BI__builtin_hlsl_wave_active_all_true: {
1433 Value *Op = EmitScalarExpr(E->getArg(0));
1434 assert(Op->getType()->isIntegerTy(1) &&
1435 "Intrinsic WaveActiveAllTrue operand must be a bool");
1436
1437 Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveActiveAllTrueIntrinsic();
1438 return EmitIntrinsicCall(ID, {Op});
1439 }
1440 case Builtin::BI__builtin_hlsl_wave_active_any_true: {
1441 Value *Op = EmitScalarExpr(E->getArg(0));
1442 assert(Op->getType()->isIntegerTy(1) &&
1443 "Intrinsic WaveActiveAnyTrue operand must be a bool");
1444
1445 Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveActiveAnyTrueIntrinsic();
1446 return EmitIntrinsicCall(ID, {Op});
1447 }
1448 case Builtin::BI__builtin_hlsl_wave_active_bit_or: {
1449 Value *Op = EmitScalarExpr(E->getArg(0));
1450 assert(E->getArg(0)->getType()->hasUnsignedIntegerRepresentation() &&
1451 "Intrinsic WaveActiveBitOr operand must have an unsigned integer "
1452 "representation");
1453
1454 Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveActiveBitOrIntrinsic();
1455 return EmitIntrinsicCall(ID, {Op->getType()}, ArrayRef{Op},
1456 "hlsl.wave.active.bit.or");
1457 }
1458 case Builtin::BI__builtin_hlsl_wave_active_bit_xor: {
1459 Value *Op = EmitScalarExpr(E->getArg(0));
1460 assert(E->getArg(0)->getType()->hasUnsignedIntegerRepresentation() &&
1461 "Intrinsic WaveActiveBitXor operand must have an unsigned integer "
1462 "representation");
1463
1464 Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveActiveBitXorIntrinsic();
1465 return EmitIntrinsicCall(ID, {Op->getType()}, ArrayRef{Op},
1466 "hlsl.wave.active.bit.xor");
1467 }
1468 case Builtin::BI__builtin_hlsl_wave_active_bit_and: {
1469 Value *Op = EmitScalarExpr(E->getArg(0));
1470 assert(E->getArg(0)->getType()->hasUnsignedIntegerRepresentation() &&
1471 "Intrinsic WaveActiveBitAnd operand must have an unsigned integer "
1472 "representation");
1473
1474 Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveActiveBitAndIntrinsic();
1475 return EmitIntrinsicCall(ID, {Op->getType()}, ArrayRef{Op},
1476 "hlsl.wave.active.bit.and");
1477 }
1478 case Builtin::BI__builtin_hlsl_interlocked_add: {
1479 // Emit `atomicrmw` directly for both DXIL and SPIR-V — the backends pick
1480 // up the raw instruction (DXIL routes it via `dx.resource.atomic.binop`
1481 // in DXILResourceAccess for resource pointers, SPIR-V lowers via
1482 // selectAtomicRMW). No intermediate intrinsic.
1483 return handleInterlockedOp(*this, E, llvm::AtomicRMWInst::Add);
1484 }
1485 case Builtin::BI__builtin_hlsl_interlocked_and: {
1486 return handleInterlockedOp(*this, E, llvm::AtomicRMWInst::And);
1487 }
1488 case Builtin::BI__builtin_hlsl_interlocked_exchange: {
1489 return handleInterlockedOp(*this, E, llvm::AtomicRMWInst::Xchg);
1490 }
1491 case Builtin::BI__builtin_hlsl_interlocked_max: {
1492 llvm::AtomicRMWInst::BinOp Op =
1494 ? llvm::AtomicRMWInst::Max
1495 : llvm::AtomicRMWInst::UMax;
1496 return handleInterlockedOp(*this, E, Op);
1497 }
1498 case Builtin::BI__builtin_hlsl_interlocked_min: {
1499 llvm::AtomicRMWInst::BinOp Op =
1501 ? llvm::AtomicRMWInst::Min
1502 : llvm::AtomicRMWInst::UMin;
1503 return handleInterlockedOp(*this, E, Op);
1504 }
1505 case Builtin::BI__builtin_hlsl_interlocked_or: {
1506 return handleInterlockedOp(*this, E, llvm::AtomicRMWInst::Or);
1507 }
1508 case Builtin::BI__builtin_hlsl_interlocked_xor: {
1509 return handleInterlockedOp(*this, E, llvm::AtomicRMWInst::Xor);
1510 }
1511 case Builtin::BI__builtin_hlsl_wave_active_ballot: {
1512 [[maybe_unused]] Value *Op = EmitScalarExpr(E->getArg(0));
1513 assert(Op->getType()->isIntegerTy(1) &&
1514 "Intrinsic WaveActiveBallot operand must be a bool");
1515
1516 return handleHlslWaveActiveBallot(*this, E);
1517 }
1518 case Builtin::BI__builtin_hlsl_wave_active_count_bits: {
1519 Value *OpExpr = EmitScalarExpr(E->getArg(0));
1520 Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveActiveCountBitsIntrinsic();
1521 return EmitIntrinsicCall(ID, ArrayRef{OpExpr});
1522 }
1523 case Builtin::BI__builtin_hlsl_wave_active_sum: {
1524 // Due to the use of variadic arguments, explicitly retrieve argument
1525 Value *OpExpr = EmitScalarExpr(E->getArg(0));
1526 Intrinsic::ID IID = getWaveActiveSumIntrinsic(
1527 getTarget().getTriple().getArch(), E->getArg(0)->getType());
1528
1529 return EmitIntrinsicCall(IID, {OpExpr->getType()}, ArrayRef{OpExpr},
1530 "hlsl.wave.active.sum");
1531 }
1532 case Builtin::BI__builtin_hlsl_wave_active_product: {
1533 // Due to the use of variadic arguments, explicitly retrieve argument
1534 Value *OpExpr = EmitScalarExpr(E->getArg(0));
1535 Intrinsic::ID IID = getWaveActiveProductIntrinsic(
1536 getTarget().getTriple().getArch(), E->getArg(0)->getType());
1537
1538 return EmitIntrinsicCall(IID, {OpExpr->getType()}, ArrayRef{OpExpr},
1539 "hlsl.wave.active.product");
1540 }
1541 case Builtin::BI__builtin_hlsl_wave_active_max: {
1542 // Due to the use of variadic arguments, explicitly retrieve argument
1543 Value *OpExpr = EmitScalarExpr(E->getArg(0));
1544 QualType QT = E->getArg(0)->getType();
1545 Intrinsic::ID IID;
1546 if (QT->isUnsignedIntegerType())
1547 IID = CGM.getHLSLRuntime().getWaveActiveUMaxIntrinsic();
1548 else
1549 IID = CGM.getHLSLRuntime().getWaveActiveMaxIntrinsic();
1550
1551 return EmitIntrinsicCall(IID, {OpExpr->getType()}, ArrayRef{OpExpr},
1552 "hlsl.wave.active.max");
1553 }
1554 case Builtin::BI__builtin_hlsl_wave_active_min: {
1555 // Due to the use of variadic arguments, explicitly retrieve argument
1556 Value *OpExpr = EmitScalarExpr(E->getArg(0));
1557 QualType QT = E->getArg(0)->getType();
1558 Intrinsic::ID IID;
1559 if (QT->isUnsignedIntegerType())
1560 IID = CGM.getHLSLRuntime().getWaveActiveUMinIntrinsic();
1561 else
1562 IID = CGM.getHLSLRuntime().getWaveActiveMinIntrinsic();
1563
1564 return EmitIntrinsicCall(IID, {OpExpr->getType()}, ArrayRef{OpExpr},
1565 "hlsl.wave.active.min");
1566 }
1567 case Builtin::BI__builtin_hlsl_wave_get_lane_index: {
1568 // We don't define a SPIR-V intrinsic, instead it is a SPIR-V built-in
1569 // defined in SPIRVBuiltins.td. So instead we manually get the matching name
1570 // for the DirectX intrinsic and the demangled builtin name
1571 switch (CGM.getTarget().getTriple().getArch()) {
1572 case llvm::Triple::dxil:
1573 return EmitIntrinsicCall(Intrinsic::dx_wave_getlaneindex);
1574 case llvm::Triple::spirv:
1575 return EmitRuntimeCall(CGM.CreateRuntimeFunction(
1576 llvm::FunctionType::get(IntTy, {}, false),
1577 "__hlsl_wave_get_lane_index", {}, false, true));
1578 default:
1579 llvm_unreachable(
1580 "Intrinsic WaveGetLaneIndex not supported by target architecture");
1581 }
1582 }
1583 case Builtin::BI__builtin_hlsl_wave_is_first_lane: {
1584 Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveIsFirstLaneIntrinsic();
1585 return EmitIntrinsicCall(ID);
1586 }
1587 case Builtin::BI__builtin_hlsl_wave_get_lane_count: {
1588 Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveGetLaneCountIntrinsic();
1589 return EmitIntrinsicCall(ID);
1590 }
1591 case Builtin::BI__builtin_hlsl_wave_read_lane_at: {
1592 // Due to the use of variadic arguments we must explicitly retrieve them and
1593 // create our function type.
1594 Value *OpExpr = EmitScalarExpr(E->getArg(0));
1595 Value *OpIndex = EmitScalarExpr(E->getArg(1));
1596 return EmitIntrinsicCall(CGM.getHLSLRuntime().getWaveReadLaneAtIntrinsic(),
1597 {OpExpr->getType()}, ArrayRef{OpExpr, OpIndex},
1598 "hlsl.wave.readlane");
1599 }
1600 case Builtin::BI__builtin_hlsl_wave_read_lane_first: {
1601 Value *OpExpr = EmitScalarExpr(E->getArg(0));
1602 return EmitIntrinsicCall(
1603 CGM.getHLSLRuntime().getWaveReadLaneFirstIntrinsic(),
1604 {OpExpr->getType()}, ArrayRef{OpExpr}, "hlsl.wave.readlane.first");
1605 }
1606 case Builtin::BI__builtin_hlsl_wave_prefix_sum: {
1607 Value *OpExpr = EmitScalarExpr(E->getArg(0));
1608 Intrinsic::ID IID = getWavePrefixSumIntrinsic(
1609 getTarget().getTriple().getArch(), E->getArg(0)->getType());
1610 return EmitIntrinsicCall(IID, {OpExpr->getType()}, ArrayRef{OpExpr},
1611 "hlsl.wave.prefix.sum");
1612 }
1613 case Builtin::BI__builtin_hlsl_wave_prefix_product: {
1614 Value *OpExpr = EmitScalarExpr(E->getArg(0));
1615 Intrinsic::ID IID = getWavePrefixProductIntrinsic(
1616 getTarget().getTriple().getArch(), E->getArg(0)->getType());
1617 return EmitIntrinsicCall(IID, {OpExpr->getType()}, ArrayRef{OpExpr},
1618 "hlsl.wave.prefix.product");
1619 }
1620 case Builtin::BI__builtin_hlsl_quad_read_across_x: {
1621 Value *OpExpr = EmitScalarExpr(E->getArg(0));
1622 Intrinsic::ID ID = CGM.getHLSLRuntime().getQuadReadAcrossXIntrinsic();
1623 return EmitIntrinsicCall(ID, {OpExpr->getType()}, ArrayRef{OpExpr},
1624 "hlsl.quad.read.across.x");
1625 }
1626 case Builtin::BI__builtin_hlsl_quad_read_across_y: {
1627 Value *OpExpr = EmitScalarExpr(E->getArg(0));
1628 Intrinsic::ID ID = CGM.getHLSLRuntime().getQuadReadAcrossYIntrinsic();
1629 return EmitIntrinsicCall(ID, {OpExpr->getType()}, ArrayRef{OpExpr},
1630 "hlsl.quad.read.across.y");
1631 }
1632 case Builtin::BI__builtin_hlsl_quad_read_across_diagonal: {
1633 Value *OpExpr = EmitScalarExpr(E->getArg(0));
1634 Intrinsic::ID ID =
1635 CGM.getHLSLRuntime().getQuadReadAcrossDiagonalIntrinsic();
1636 return EmitRuntimeCall(Intrinsic::getOrInsertDeclaration(
1637 &CGM.getModule(), ID, {OpExpr->getType()}),
1638 ArrayRef{OpExpr}, "hlsl.quad.read.across.diagonal");
1639 }
1640 case Builtin::BI__builtin_hlsl_elementwise_sign: {
1641 auto *Arg0 = E->getArg(0);
1642 Value *Op0 = EmitScalarExpr(Arg0);
1643 llvm::Type *Xty = Op0->getType();
1644 llvm::Type *retType = llvm::Type::getInt32Ty(this->getLLVMContext());
1645 if (Xty->isVectorTy()) {
1646 auto *XVecTy = Arg0->getType()->castAs<VectorType>();
1647 retType = llvm::VectorType::get(
1648 retType, ElementCount::getFixed(XVecTy->getNumElements()));
1649 }
1650 assert((Arg0->getType()->hasFloatingRepresentation() ||
1651 Arg0->getType()->hasIntegerRepresentation()) &&
1652 "sign operand must have a float or int representation");
1653
1654 if (Arg0->getType()->hasUnsignedIntegerRepresentation()) {
1655 Value *Cmp = Builder.CreateICmpEQ(Op0, ConstantInt::get(Xty, 0));
1656 return Builder.CreateSelect(Cmp, ConstantInt::get(retType, 0),
1657 ConstantInt::get(retType, 1), "hlsl.sign");
1658 }
1659
1660 return Builder.CreateIntrinsic(
1661 retType, CGM.getHLSLRuntime().getSignIntrinsic(),
1662 ArrayRef<Value *>{Op0}, nullptr, "hlsl.sign");
1663 }
1664 case Builtin::BI__builtin_hlsl_buffer_update_counter: {
1665 Value *ResHandle = EmitScalarExpr(E->getArg(0));
1666 Value *Offset = EmitScalarExpr(E->getArg(1));
1667 Value *OffsetI8 = Builder.CreateIntCast(Offset, Int8Ty, true);
1668 return Builder.CreateIntrinsic(
1669 /*ReturnType=*/Offset->getType(),
1670 CGM.getHLSLRuntime().getBufferUpdateCounterIntrinsic(),
1671 ArrayRef<Value *>{ResHandle, OffsetI8}, nullptr);
1672 }
1673 case Builtin::BI__builtin_hlsl_elementwise_splitdouble: {
1674
1675 assert((E->getArg(0)->getType()->hasFloatingRepresentation() &&
1678 "asuint operands types mismatch");
1679 return handleHlslSplitdouble(E, this);
1680 }
1681 case Builtin::BI__builtin_hlsl_elementwise_clip:
1682 assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
1683 "clip operands types mismatch");
1684 return handleHlslClip(E, this);
1685 case Builtin::BI__builtin_hlsl_all_memory_barrier: {
1686 Intrinsic::ID ID = CGM.getHLSLRuntime().getAllMemoryBarrierIntrinsic();
1687 return EmitIntrinsicCall(ID);
1688 }
1689 case Builtin::BI__builtin_hlsl_all_memory_barrier_with_group_sync: {
1690 Intrinsic::ID ID =
1691 CGM.getHLSLRuntime().getAllMemoryBarrierWithGroupSyncIntrinsic();
1692 return EmitIntrinsicCall(ID);
1693 }
1694 case Builtin::BI__builtin_hlsl_device_memory_barrier: {
1695 Intrinsic::ID ID = CGM.getHLSLRuntime().getDeviceMemoryBarrierIntrinsic();
1696 return EmitIntrinsicCall(ID);
1697 }
1698 case Builtin::BI__builtin_hlsl_device_memory_barrier_with_group_sync: {
1699 Intrinsic::ID ID =
1700 CGM.getHLSLRuntime().getDeviceMemoryBarrierWithGroupSyncIntrinsic();
1701 return EmitIntrinsicCall(ID);
1702 }
1703 case Builtin::BI__builtin_hlsl_group_memory_barrier: {
1704 Intrinsic::ID ID = CGM.getHLSLRuntime().getGroupMemoryBarrierIntrinsic();
1705 return EmitIntrinsicCall(ID);
1706 }
1707 case Builtin::BI__builtin_hlsl_group_memory_barrier_with_group_sync: {
1708 Intrinsic::ID ID =
1709 CGM.getHLSLRuntime().getGroupMemoryBarrierWithGroupSyncIntrinsic();
1710 return EmitIntrinsicCall(ID);
1711 }
1712 case Builtin::BI__builtin_hlsl_elementwise_ddx_coarse: {
1713 Value *Op0 = EmitScalarExpr(E->getArg(0));
1714 if (!E->getArg(0)->getType()->hasFloatingRepresentation())
1715 llvm_unreachable("ddx_coarse operand must have a float representation");
1716 Intrinsic::ID ID = CGM.getHLSLRuntime().getDdxCoarseIntrinsic();
1717 return Builder.CreateIntrinsic(/*ReturnType=*/Op0->getType(), ID,
1718 ArrayRef<Value *>{Op0}, nullptr,
1719 "hlsl.ddx.coarse");
1720 }
1721 case Builtin::BI__builtin_hlsl_elementwise_ddy_coarse: {
1722 Value *Op0 = EmitScalarExpr(E->getArg(0));
1723 if (!E->getArg(0)->getType()->hasFloatingRepresentation())
1724 llvm_unreachable("ddy_coarse operand must have a float representation");
1725 Intrinsic::ID ID = CGM.getHLSLRuntime().getDdyCoarseIntrinsic();
1726 return Builder.CreateIntrinsic(/*ReturnType=*/Op0->getType(), ID,
1727 ArrayRef<Value *>{Op0}, nullptr,
1728 "hlsl.ddy.coarse");
1729 }
1730 case Builtin::BI__builtin_hlsl_elementwise_ddx_fine: {
1731 Value *Op0 = EmitScalarExpr(E->getArg(0));
1732 if (!E->getArg(0)->getType()->hasFloatingRepresentation())
1733 llvm_unreachable("ddx_fine operand must have a float representation");
1734 Intrinsic::ID ID = CGM.getHLSLRuntime().getDdxFineIntrinsic();
1735 return Builder.CreateIntrinsic(/*ReturnType=*/Op0->getType(), ID,
1736 ArrayRef<Value *>{Op0}, nullptr,
1737 "hlsl.ddx.fine");
1738 }
1739 case Builtin::BI__builtin_hlsl_elementwise_ddy_fine: {
1740 Value *Op0 = EmitScalarExpr(E->getArg(0));
1741 if (!E->getArg(0)->getType()->hasFloatingRepresentation())
1742 llvm_unreachable("ddy_fine operand must have a float representation");
1743 Intrinsic::ID ID = CGM.getHLSLRuntime().getDdyFineIntrinsic();
1744 return Builder.CreateIntrinsic(/*ReturnType=*/Op0->getType(), ID,
1745 ArrayRef<Value *>{Op0}, nullptr,
1746 "hlsl.ddy.fine");
1747 }
1748 case Builtin::BI__builtin_get_spirv_spec_constant_bool:
1749 case Builtin::BI__builtin_get_spirv_spec_constant_short:
1750 case Builtin::BI__builtin_get_spirv_spec_constant_ushort:
1751 case Builtin::BI__builtin_get_spirv_spec_constant_int:
1752 case Builtin::BI__builtin_get_spirv_spec_constant_uint:
1753 case Builtin::BI__builtin_get_spirv_spec_constant_longlong:
1754 case Builtin::BI__builtin_get_spirv_spec_constant_ulonglong:
1755 case Builtin::BI__builtin_get_spirv_spec_constant_half:
1756 case Builtin::BI__builtin_get_spirv_spec_constant_float:
1757 case Builtin::BI__builtin_get_spirv_spec_constant_double: {
1758 llvm::Function *SpecConstantFn = getSpecConstantFunction(E->getType());
1759 llvm::Value *SpecId = EmitScalarExpr(E->getArg(0));
1760 llvm::Value *DefaultVal = EmitScalarExpr(E->getArg(1));
1761 llvm::Value *Args[] = {SpecId, DefaultVal};
1762 return Builder.CreateCall(SpecConstantFn, Args);
1763 }
1764 }
1765 return nullptr;
1766}
1767
1769 const clang::QualType &SpecConstantType) {
1770
1771 // Find or create the declaration for the function.
1772 llvm::Module *M = &CGM.getModule();
1773 std::string MangledName =
1774 getSpecConstantFunctionName(SpecConstantType, getContext());
1775 llvm::Function *SpecConstantFn = M->getFunction(MangledName);
1776
1777 if (!SpecConstantFn) {
1778 llvm::Type *IntType = ConvertType(getContext().IntTy);
1779 llvm::Type *RetTy = ConvertType(SpecConstantType);
1780 llvm::Type *ArgTypes[] = {IntType, RetTy};
1781 llvm::FunctionType *FnTy = llvm::FunctionType::get(RetTy, ArgTypes, false);
1782 SpecConstantFn = llvm::Function::Create(
1783 FnTy, llvm::GlobalValue::ExternalLinkage, MangledName, M);
1784 }
1785 return SpecConstantFn;
1786}
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 unsigned getHlslClampArgIndex(const HLSLAttributedResourceType *RT, unsigned OffsetArgIndex)
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 * emitHlslSampleOffset(CodeGenFunction &CGF, const CallExpr *E, const HLSLAttributedResourceType *RT, unsigned OffsetArgIndex)
static Intrinsic::ID getFirstBitHighIntrinsic(CGHLSLRuntime &RT, QualType QT)
static llvm::Type * getOffsetType(CodeGenModule &CGM, const HLSLAttributedResourceType *RT)
static llvm::Type * getAggregateType(llvm::Type *ScalarTy, QualType ArgTy)
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:239
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:2987
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition Expr.h:3191
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition Expr.h:3178
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:277
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:6567
void EmitWritebacks(const CallArgList &Args)
EmitWriteback - Emit callbacks for function.
Definition CGCall.cpp:5255
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:2791
void EmitAnyExprToMem(const Expr *E, Address Location, Qualifiers Quals, bool IsInitializer)
EmitAnyExprToMem - Emits the code necessary to evaluate an arbitrary expression into the given memory...
Definition CGExpr.cpp:312
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:283
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,...
static bool hasAggregateEvaluationKind(QualType T)
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:1734
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:384
Represents a concrete matrix type with constant number of rows and columns.
Definition TypeBase.h:4478
unsigned getNumColumns() const
Returns the number of columns in the matrix.
Definition TypeBase.h:4497
unsigned getNumRows() const
Returns the number of rows in the matrix.
Definition TypeBase.h:4494
The name of a declaration.
This represents one expression.
Definition Expr.h:113
llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx) const
EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded integer.
QualType getType() const
Definition Expr.h:145
Represents a function declaration or definition.
Definition Decl.h:2059
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:2303
Represents a parameter to a function.
Definition Decl.h:1820
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:2943
A (possibly-)qualified type.
Definition TypeBase.h:938
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition TypeBase.h:8428
Qualifiers getQualifiers() const
Retrieve the set of qualifiers applied to this type.
Definition TypeBase.h:8468
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:2388
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:2241
bool isConstantMatrixType() const
Definition TypeBase.h:8832
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
Definition TypeBase.h:9081
const T * castAs() const
Member-template castAs<specific type>.
Definition TypeBase.h:9331
bool hasUnsignedIntegerRepresentation() const
Determine whether this type has an unsigned integer representation of some sort, e....
Definition Type.cpp:2500
bool hasSignedIntegerRepresentation() const
Determine whether this type has an signed integer representation of some sort, e.g....
Definition Type.cpp:2432
bool hasFloatingRepresentation() const
Determine whether this type has a floating-point representation of some sort, e.g....
Definition Type.cpp:2521
bool isVectorType() const
Definition TypeBase.h:8804
bool isFloatingType() const
Definition Type.cpp:2513
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:2456
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9264
QualType getType() const
Definition Value.cpp:238
Represents a GCC generic vector type.
Definition TypeBase.h:4266
unsigned getNumElements() const
Definition TypeBase.h:4281
uint32_t getResourceDimensions(llvm::dxil::ResourceDimension Dim)
bool hasResourceOffset(llvm::dxil::ResourceDimension Dim)
Top level wrappers for InstallAPI frontend operations.
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
@ 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:5483