LLVM 24.0.0git
DXILIntrinsicExpansion.cpp
Go to the documentation of this file.
1//===- DXILIntrinsicExpansion.cpp - Prepare LLVM Module for DXIL encoding--===//
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/// \file This file contains DXIL intrinsic expansions for those that don't have
10// opcodes in DirectX Intermediate Language (DXIL).
11//===----------------------------------------------------------------------===//
12
14#include "DirectX.h"
15#include "llvm/ADT/APInt.h"
16#include "llvm/ADT/STLExtras.h"
18#include "llvm/CodeGen/Passes.h"
19#include "llvm/IR/Constants.h"
20#include "llvm/IR/IRBuilder.h"
21#include "llvm/IR/InstrTypes.h"
22#include "llvm/IR/Instruction.h"
24#include "llvm/IR/Intrinsics.h"
25#include "llvm/IR/IntrinsicsDirectX.h"
27#include "llvm/IR/Module.h"
28#include "llvm/IR/PassManager.h"
29#include "llvm/IR/Type.h"
30#include "llvm/Pass.h"
34
35#define DEBUG_TYPE "dxil-intrinsic-expansion"
36
37using namespace llvm;
38
40
41public:
42 bool runOnModule(Module &M) override;
44
45 static char ID; // Pass identification.
46};
47
48static bool resourceAccessNeeds64BitExpansion(Module *M, Type *OverloadTy,
49 bool IsRaw) {
50 if (IsRaw && M->getTargetTriple().getDXILVersion() > VersionTuple(1, 2))
51 return false;
52
53 Type *ScalarTy = OverloadTy->getScalarType();
54 return ScalarTy->isDoubleTy() || ScalarTy->isIntegerTy(64);
55}
56
58 Module *M = Orig->getModule();
59 if (M->getTargetTriple().getDXILVersion() >= VersionTuple(1, 9))
60 return nullptr;
61
62 Value *Val = Orig->getOperand(0);
63 Type *ValTy = Val->getType();
64 if (!ValTy->getScalarType()->isHalfTy())
65 return nullptr;
66
67 IRBuilder<> Builder(Orig);
68 Type *IType = Type::getInt16Ty(M->getContext());
69 Constant *PosInf =
70 ValTy->isVectorTy()
73 cast<FixedVectorType>(ValTy)->getNumElements()),
74 ConstantInt::get(IType, 0x7c00))
75 : ConstantInt::get(IType, 0x7c00);
76
77 Constant *NegInf =
78 ValTy->isVectorTy()
81 cast<FixedVectorType>(ValTy)->getNumElements()),
82 ConstantInt::get(IType, 0xfc00))
83 : ConstantInt::get(IType, 0xfc00);
84
85 Value *IVal = Builder.CreateBitCast(Val, PosInf->getType());
86 Value *B1 = Builder.CreateICmpEQ(IVal, PosInf);
87 Value *B2 = Builder.CreateICmpEQ(IVal, NegInf);
88 Value *B3 = Builder.CreateOr(B1, B2);
89 return B3;
90}
91
93 Module *M = Orig->getModule();
94 if (M->getTargetTriple().getDXILVersion() >= VersionTuple(1, 9))
95 return nullptr;
96
97 Value *Val = Orig->getOperand(0);
98 Type *ValTy = Val->getType();
99 if (!ValTy->getScalarType()->isHalfTy())
100 return nullptr;
101
102 IRBuilder<> Builder(Orig);
103 Type *IType = Type::getInt16Ty(M->getContext());
104
105 Constant *ExpBitMask =
106 ValTy->isVectorTy()
109 cast<FixedVectorType>(ValTy)->getNumElements()),
110 ConstantInt::get(IType, 0x7c00))
111 : ConstantInt::get(IType, 0x7c00);
112 Constant *SigBitMask =
113 ValTy->isVectorTy()
116 cast<FixedVectorType>(ValTy)->getNumElements()),
117 ConstantInt::get(IType, 0x3ff))
118 : ConstantInt::get(IType, 0x3ff);
119
120 Constant *Zero =
121 ValTy->isVectorTy()
124 cast<FixedVectorType>(ValTy)->getNumElements()),
125 ConstantInt::get(IType, 0))
126 : ConstantInt::get(IType, 0);
127
128 Value *IVal = Builder.CreateBitCast(Val, ExpBitMask->getType());
129 Value *Exp = Builder.CreateAnd(IVal, ExpBitMask);
130 Value *B1 = Builder.CreateICmpEQ(Exp, ExpBitMask);
131
132 Value *Sig = Builder.CreateAnd(IVal, SigBitMask);
133 Value *B2 = Builder.CreateICmpNE(Sig, Zero);
134 Value *B3 = Builder.CreateAnd(B1, B2);
135 return B3;
136}
137
139 Module *M = Orig->getModule();
140 if (M->getTargetTriple().getDXILVersion() >= VersionTuple(1, 9))
141 return nullptr;
142
143 Value *Val = Orig->getOperand(0);
144 Type *ValTy = Val->getType();
145 if (!ValTy->getScalarType()->isHalfTy())
146 return nullptr;
147
148 IRBuilder<> Builder(Orig);
149 Type *IType = Type::getInt16Ty(M->getContext());
150
151 Constant *ExpBitMask =
152 ValTy->isVectorTy()
155 cast<FixedVectorType>(ValTy)->getNumElements()),
156 ConstantInt::get(IType, 0x7c00))
157 : ConstantInt::get(IType, 0x7c00);
158
159 Value *IVal = Builder.CreateBitCast(Val, ExpBitMask->getType());
160 Value *Exp = Builder.CreateAnd(IVal, ExpBitMask);
161 Value *B1 = Builder.CreateICmpNE(Exp, ExpBitMask);
162 return B1;
163}
164
166 Module *M = Orig->getModule();
167 if (M->getTargetTriple().getDXILVersion() >= VersionTuple(1, 9))
168 return nullptr;
169
170 Value *Val = Orig->getOperand(0);
171 Type *ValTy = Val->getType();
172 if (!ValTy->getScalarType()->isHalfTy())
173 return nullptr;
174
175 IRBuilder<> Builder(Orig);
176 Type *IType = Type::getInt16Ty(M->getContext());
177
178 Constant *ExpBitMask =
179 ValTy->isVectorTy()
182 cast<FixedVectorType>(ValTy)->getNumElements()),
183 ConstantInt::get(IType, 0x7c00))
184 : ConstantInt::get(IType, 0x7c00);
185 Constant *Zero =
186 ValTy->isVectorTy()
189 cast<FixedVectorType>(ValTy)->getNumElements()),
190 ConstantInt::get(IType, 0))
191 : ConstantInt::get(IType, 0);
192
193 Value *IVal = Builder.CreateBitCast(Val, ExpBitMask->getType());
194 Value *Exp = Builder.CreateAnd(IVal, ExpBitMask);
195 Value *NotAllZeroes = Builder.CreateICmpNE(Exp, Zero);
196 Value *NotAllOnes = Builder.CreateICmpNE(Exp, ExpBitMask);
197 Value *B1 = Builder.CreateAnd(NotAllZeroes, NotAllOnes);
198 return B1;
199}
200
202 assert(F.getIntrinsicID() == Intrinsic::dx_fdot &&
203 "Function is not a dx.fdot intrinsic");
204 auto *ParamTy = cast<FixedVectorType>(F.getFunctionType()->getParamType(0));
205 return ParamTy->getNumElements() <= 4 ||
206 F.getParent()->getTargetTriple().getOSVersion() < VersionTuple(6, 9);
207}
208
210 switch (F.getIntrinsicID()) {
211 case Intrinsic::assume:
212 case Intrinsic::abs:
213 case Intrinsic::atan2:
214 case Intrinsic::copysign:
215 case Intrinsic::fshl:
216 case Intrinsic::fshr:
217 case Intrinsic::exp:
218 case Intrinsic::is_fpclass:
219 case Intrinsic::log:
220 case Intrinsic::log10:
221 case Intrinsic::pow:
222 case Intrinsic::powi:
223 case Intrinsic::dx_all:
224 case Intrinsic::dx_any:
225 case Intrinsic::dx_uclamp:
226 case Intrinsic::dx_sclamp:
227 case Intrinsic::dx_nclamp:
228 case Intrinsic::dx_isinf:
229 case Intrinsic::dx_isnan:
230 case Intrinsic::dx_normalize:
231 case Intrinsic::dx_sdot:
232 case Intrinsic::dx_udot:
233 case Intrinsic::dx_sign:
234 case Intrinsic::usub_sat:
235 case Intrinsic::vector_reduce_add:
236 case Intrinsic::vector_reduce_fadd:
237 case Intrinsic::matrix_multiply:
238 case Intrinsic::matrix_transpose:
239 case Intrinsic::umul_with_overflow:
240 case Intrinsic::smul_with_overflow:
241 case Intrinsic::dx_load_input:
242 case Intrinsic::dx_store_output:
243 return true;
244 case Intrinsic::dx_fdot:
246 case Intrinsic::dx_resource_load_rawbuffer:
248 F.getParent(), F.getReturnType()->getStructElementType(0),
249 /*IsRaw*/ true);
250 case Intrinsic::dx_resource_load_typedbuffer:
252 F.getParent(), F.getReturnType()->getStructElementType(0),
253 /*IsRaw*/ false);
254 case Intrinsic::dx_resource_store_rawbuffer:
256 F.getParent(), F.getFunctionType()->getParamType(3), /*IsRaw*/ true);
257 case Intrinsic::dx_resource_store_typedbuffer:
259 F.getParent(), F.getFunctionType()->getParamType(2), /*IsRaw*/ false);
260 }
261 return false;
262}
263
265 Value *A = Orig->getArgOperand(0);
266 Value *B = Orig->getArgOperand(1);
267 Type *Ty = A->getType();
268
269 IRBuilder<> Builder(Orig);
270
271 Value *Cmp = Builder.CreateICmpULT(A, B, "usub.cmp");
272 Value *Sub = Builder.CreateSub(A, B, "usub.sub");
273 Value *Zero = ConstantInt::get(Ty, 0);
274 return Builder.CreateSelect(Cmp, Zero, Sub, "usub.sat");
275}
276
277// Compute the high N bits of the 2N-bit unsigned product of two N-bit values
278// using only N-bit arithmetic, so we don't introduce a wider integer type that
279// may be unsupported in DXIL.
281 Type *Ty, unsigned BW) {
282 assert(BW % 2 == 0 && "high-half split needs symmetric halves");
283 unsigned Half = BW / 2;
284 Value *HalfShift = ConstantInt::get(Ty, Half);
285 Value *LoMask = ConstantInt::get(Ty, APInt::getLowBitsSet(BW, Half));
286
287 Value *U0 = Builder.CreateAnd(A, LoMask);
288 Value *U1 = Builder.CreateLShr(A, HalfShift);
289 Value *V0 = Builder.CreateAnd(B, LoMask);
290 Value *V1 = Builder.CreateLShr(B, HalfShift);
291
292 Value *W0 = Builder.CreateMul(U0, V0);
293 Value *T = Builder.CreateAdd(Builder.CreateMul(U1, V0),
294 Builder.CreateLShr(W0, HalfShift));
295 Value *W1 = Builder.CreateAnd(T, LoMask);
296 Value *W2 = Builder.CreateLShr(T, HalfShift);
297 W1 = Builder.CreateAdd(Builder.CreateMul(U0, V1), W1);
298 return Builder.CreateAdd(Builder.CreateAdd(Builder.CreateMul(U1, V1), W2),
299 Builder.CreateLShr(W1, HalfShift));
300}
301
302// Expand a {u,s}mul.with.overflow intrinsic. The low half of the result is a
303// plain multiply; overflow is derived from the high half of the double-width
304// product.
306 IRBuilder<> Builder(Orig);
307 Value *A = Orig->getArgOperand(0);
308 Value *B = Orig->getArgOperand(1);
309 Type *Ty = A->getType();
310 unsigned BW = Ty->getScalarSizeInBits();
311
312 Value *Lo;
313 Value *Ov;
314
315 // A plain double-width multiply is simplest, but we avoid it once it would
316 // introduce a 64-bit (or wider) integer, which DXIL does not always support.
317 // For i32 we use the native DXIL IMul/UMul ops, which return the full product
318 // as two i32s; wider types fall back to a same-width high-half computation.
319 if (2 * BW <= 32) {
320 Lo = Builder.CreateMul(A, B);
321 Type *WideTy = Ty->getWithNewBitWidth(2 * BW);
322 Value *WideA =
323 Signed ? Builder.CreateSExt(A, WideTy) : Builder.CreateZExt(A, WideTy);
324 Value *WideB =
325 Signed ? Builder.CreateSExt(B, WideTy) : Builder.CreateZExt(B, WideTy);
326 Value *Wide = Builder.CreateMul(WideA, WideB);
327 if (Signed) {
328 // Overflow when the full product doesn't fit back into BW signed bits.
329 Ov = Builder.CreateICmpNE(Wide, Builder.CreateSExt(Lo, WideTy));
330 } else {
331 Value *Hi = Builder.CreateLShr(Wide, ConstantInt::get(WideTy, BW));
332 Ov = Builder.CreateICmpNE(Hi, ConstantInt::get(WideTy, 0));
333 }
334 } else if (BW == 32) {
335 // IMul/UMul return {high, low}; index 0 is the high 32 bits.
336 Type *ResTy = StructType::get(Ty, Ty);
337 Intrinsic::ID IntrinsicID =
338 Signed ? Intrinsic::dx_imul : Intrinsic::dx_umul;
339 Value *Mul = Builder.CreateIntrinsic(ResTy, IntrinsicID, {A, B});
340 Value *Hi = Builder.CreateExtractValue(Mul, 0);
341 Lo = Builder.CreateExtractValue(Mul, 1);
342 if (Signed)
343 Ov = Builder.CreateICmpNE(
344 Hi, Builder.CreateAShr(Lo, ConstantInt::get(Ty, BW - 1)));
345 else
346 Ov = Builder.CreateICmpNE(Hi, ConstantInt::get(Ty, 0));
347 } else {
348 Lo = Builder.CreateMul(A, B);
349 Value *Hi = createMulHighUnsigned(Builder, A, B, Ty, BW);
350 if (Signed) {
351 // Turn the unsigned high half into the signed one, then overflow means it
352 // isn't the sign extension of the low half.
353 Value *SignShift = ConstantInt::get(Ty, BW - 1);
354 Value *ASign = Builder.CreateAShr(A, SignShift);
355 Value *BSign = Builder.CreateAShr(B, SignShift);
356 Hi = Builder.CreateSub(Hi, Builder.CreateAnd(ASign, B));
357 Hi = Builder.CreateSub(Hi, Builder.CreateAnd(BSign, A));
358 Ov = Builder.CreateICmpNE(Hi, Builder.CreateAShr(Lo, SignShift));
359 } else {
360 Ov = Builder.CreateICmpNE(Hi, ConstantInt::get(Ty, 0));
361 }
362 }
363
364 Value *Agg = PoisonValue::get(Orig->getType());
365 Agg = Builder.CreateInsertValue(Agg, Lo, 0);
366 return Builder.CreateInsertValue(Agg, Ov, 1);
367}
368
369static Value *expandVecReduceAdd(CallInst *Orig, Intrinsic::ID IntrinsicId) {
370 assert(IntrinsicId == Intrinsic::vector_reduce_add ||
371 IntrinsicId == Intrinsic::vector_reduce_fadd);
372
373 IRBuilder<> Builder(Orig);
374 bool IsFAdd = (IntrinsicId == Intrinsic::vector_reduce_fadd);
375
376 Value *X = Orig->getOperand(IsFAdd ? 1 : 0);
377 Type *Ty = X->getType();
378 auto *XVec = dyn_cast<FixedVectorType>(Ty);
379 unsigned XVecSize = XVec->getNumElements();
380 Value *Sum = Builder.CreateExtractElement(X, static_cast<uint64_t>(0));
381
382 // Handle the initial start value for floating-point addition.
383 if (IsFAdd) {
384 Constant *StartValue = dyn_cast<Constant>(Orig->getOperand(0));
385 if (StartValue && !StartValue->isNullValue())
386 Sum = Builder.CreateFAdd(Sum, StartValue);
387 }
388
389 // Accumulate the remaining vector elements.
390 for (unsigned I = 1; I < XVecSize; I++) {
391 Value *Elt = Builder.CreateExtractElement(X, I);
392 if (IsFAdd)
393 Sum = Builder.CreateFAdd(Sum, Elt);
394 else
395 Sum = Builder.CreateAdd(Sum, Elt);
396 }
397
398 return Sum;
399}
400
401static Value *expandAbs(CallInst *Orig) {
402 Value *X = Orig->getOperand(0);
403 IRBuilder<> Builder(Orig);
404 Type *Ty = X->getType();
405 Type *EltTy = Ty->getScalarType();
406 Constant *Zero = Ty->isVectorTy()
409 cast<FixedVectorType>(Ty)->getNumElements()),
410 ConstantInt::get(EltTy, 0))
411 : ConstantInt::get(EltTy, 0);
412 auto *V = Builder.CreateSub(Zero, X);
413 return Builder.CreateIntrinsic(Ty, Intrinsic::smax, {X, V}, nullptr,
414 "dx.max");
415}
416
417// Create a DXIL dot2, dot3, or dot4 for the given operands.
419 Type *ATy = A->getType();
420 [[maybe_unused]] Type *BTy = B->getType();
421 assert(ATy->isVectorTy() && BTy->isVectorTy());
422
423 IRBuilder<> Builder(Orig);
424
425 auto *AVec = dyn_cast<FixedVectorType>(ATy);
426
428
429 unsigned NumElts = AVec->getNumElements();
430 Intrinsic::ID DotIntrinsic;
431 switch (NumElts) {
432 case 2:
433 DotIntrinsic = Intrinsic::dx_dot2;
434 break;
435 case 3:
436 DotIntrinsic = Intrinsic::dx_dot3;
437 break;
438 case 4:
439 DotIntrinsic = Intrinsic::dx_dot4;
440 break;
441 default:
443 "Invalid dot product input vector: length is outside 2-4");
444 }
445
447 for (unsigned I = 0; I < NumElts; ++I)
448 Args.push_back(Builder.CreateExtractElement(A, Builder.getInt32(I)));
449 for (unsigned I = 0; I < NumElts; ++I)
450 Args.push_back(Builder.CreateExtractElement(B, Builder.getInt32(I)));
451 return Builder.CreateIntrinsic(ATy->getScalarType(), DotIntrinsic, Args,
452 nullptr, "dot");
453}
454
455// Expand an arbitrary-width float dot into the minimum number of legal DXIL
456// dot2, dot3, and dot4 operations.
458 Value *A = Orig->getOperand(0);
459 Value *B = Orig->getOperand(1);
460 unsigned NumElts = cast<FixedVectorType>(A->getType())->getNumElements();
461
462 // We return early here to avoid constructing unnecessary identity shuffles.
463 if (NumElts <= 4)
464 return expandFloatDotChunk(Orig, A, B);
465
467 VersionTuple(6, 9) &&
468 "long fdot must not be expanded for shader model 6.9 or later");
469
470 IRBuilder<> Builder(Orig);
471 Value *Result = nullptr;
472 for (unsigned Offset = 0; Offset < NumElts;) {
473 unsigned Remaining = NumElts - Offset;
474 // Taking four is optimal unless it would leave an illegal one-element
475 // tail. In that case, take three and finish with dot2.
476 unsigned ChunkSize = Remaining == 5 ? 3 : std::min(Remaining, 4u);
478 for (unsigned I = 0; I < ChunkSize; ++I)
479 Mask.push_back(Offset + I);
480 Value *AChunk = Builder.CreateShuffleVector(A, Mask);
481 Value *BChunk = Builder.CreateShuffleVector(B, Mask);
482 Value *Chunk = expandFloatDotChunk(Orig, AChunk, BChunk);
483 Result = Result ? Builder.CreateFAdd(Result, Chunk, "dot.add") : Chunk;
484 Offset += ChunkSize;
485 }
486 return Result;
487}
488
489// Expand integer dot product to multiply and add ops
491 Intrinsic::ID DotIntrinsic) {
492 assert(DotIntrinsic == Intrinsic::dx_sdot ||
493 DotIntrinsic == Intrinsic::dx_udot);
494 Value *A = Orig->getOperand(0);
495 Value *B = Orig->getOperand(1);
496 Type *ATy = A->getType();
497 [[maybe_unused]] Type *BTy = B->getType();
498 assert(ATy->isVectorTy() && BTy->isVectorTy());
499
500 IRBuilder<> Builder(Orig);
501
502 auto *AVec = dyn_cast<FixedVectorType>(ATy);
503
505
506 Value *Result;
507 Intrinsic::ID MadIntrinsic = DotIntrinsic == Intrinsic::dx_sdot
508 ? Intrinsic::dx_imad
509 : Intrinsic::dx_umad;
510 Value *Elt0 = Builder.CreateExtractElement(A, (uint64_t)0);
511 Value *Elt1 = Builder.CreateExtractElement(B, (uint64_t)0);
512 Result = Builder.CreateMul(Elt0, Elt1);
513 for (unsigned I = 1; I < AVec->getNumElements(); I++) {
514 Elt0 = Builder.CreateExtractElement(A, I);
515 Elt1 = Builder.CreateExtractElement(B, I);
516 Result = Builder.CreateIntrinsic(Result->getType(), MadIntrinsic,
517 ArrayRef<Value *>{Elt0, Elt1, Result},
518 nullptr, "dx.mad");
519 }
520 return Result;
521}
522
524 Value *X = Orig->getOperand(0);
525 IRBuilder<> Builder(Orig);
526 Type *Ty = X->getType();
527 Type *EltTy = Ty->getScalarType();
528 Constant *Log2eConst =
529 Ty->isVectorTy() ? ConstantVector::getSplat(
531 cast<FixedVectorType>(Ty)->getNumElements()),
532 ConstantFP::get(EltTy, numbers::log2ef))
533 : ConstantFP::get(EltTy, numbers::log2ef);
534 Value *NewX = Builder.CreateFMul(Log2eConst, X);
535 CallInst *Exp2Call = Builder.CreateIntrinsicWithoutFolding(
536 Ty, Intrinsic::exp2, {NewX}, nullptr, "dx.exp2");
537 Exp2Call->setTailCall(Orig->isTailCall());
538 Exp2Call->setAttributes(Orig->getAttributes());
539 return Exp2Call;
540}
541
543 Value *T = Orig->getArgOperand(1);
544 auto *TCI = dyn_cast<ConstantInt>(T);
545
546 // These FPClassTest cases have DXIL opcodes, so they will be handled in
547 // DXIL Op Lowering instead for all non f16 cases.
548 switch (TCI->getZExtValue()) {
550 return expand16BitIsInf(Orig);
552 return expand16BitIsNaN(Orig);
554 return expand16BitIsNormal(Orig);
556 return expand16BitIsFinite(Orig);
557 }
558
559 IRBuilder<> Builder(Orig);
560
561 Value *F = Orig->getArgOperand(0);
562 Type *FTy = F->getType();
563 unsigned FNumElem = 0; // 0 => F is not a vector
564
565 unsigned BitWidth; // Bit width of F or the ElemTy of F
566 Type *BitCastTy; // An IntNTy of the same bitwidth as F or ElemTy of F
567
568 if (auto *FVecTy = dyn_cast<FixedVectorType>(FTy)) {
569 Type *ElemTy = FVecTy->getElementType();
570 FNumElem = FVecTy->getNumElements();
571 BitWidth = ElemTy->getPrimitiveSizeInBits();
572 BitCastTy = FixedVectorType::get(Builder.getIntNTy(BitWidth), FNumElem);
573 } else {
575 BitCastTy = Builder.getIntNTy(BitWidth);
576 }
577
578 Value *FBitCast = Builder.CreateBitCast(F, BitCastTy);
579 switch (TCI->getZExtValue()) {
581 Value *NegZero =
582 ConstantInt::get(Builder.getIntNTy(BitWidth), 1 << (BitWidth - 1),
583 /*IsSigned=*/true);
584 Value *RetVal;
585 if (FNumElem) {
586 Value *NegZeroSplat = Builder.CreateVectorSplat(FNumElem, NegZero);
587 RetVal =
588 Builder.CreateICmpEQ(FBitCast, NegZeroSplat, "is.fpclass.negzero");
589 } else
590 RetVal = Builder.CreateICmpEQ(FBitCast, NegZero, "is.fpclass.negzero");
591 return RetVal;
592 }
593 default:
594 reportFatalUsageError("Unsupported FPClassTest");
595 }
596}
597
599 Intrinsic::ID IntrinsicId) {
600 Value *X = Orig->getOperand(0);
601 IRBuilder<> Builder(Orig);
602 Type *Ty = X->getType();
603 Type *EltTy = Ty->getScalarType();
604
605 auto ApplyOp = [&Builder](Intrinsic::ID IntrinsicId, Value *Result,
606 Value *Elt) {
607 if (IntrinsicId == Intrinsic::dx_any)
608 return Builder.CreateOr(Result, Elt);
609 assert(IntrinsicId == Intrinsic::dx_all);
610 return Builder.CreateAnd(Result, Elt);
611 };
612
613 Value *Result = nullptr;
614 if (!Ty->isVectorTy()) {
615 Result = EltTy->isFloatingPointTy()
616 ? Builder.CreateFCmpUNE(X, ConstantFP::get(EltTy, 0))
617 : Builder.CreateICmpNE(X, ConstantInt::get(EltTy, 0));
618 } else {
619 auto *XVec = dyn_cast<FixedVectorType>(Ty);
620 Value *Cond =
621 EltTy->isFloatingPointTy()
622 ? Builder.CreateFCmpUNE(
624 ElementCount::getFixed(XVec->getNumElements()),
625 ConstantFP::get(EltTy, 0)))
626 : Builder.CreateICmpNE(
628 ElementCount::getFixed(XVec->getNumElements()),
629 ConstantInt::get(EltTy, 0)));
630 Result = Builder.CreateExtractElement(Cond, (uint64_t)0);
631 for (unsigned I = 1; I < XVec->getNumElements(); I++) {
632 Value *Elt = Builder.CreateExtractElement(Cond, I);
633 Result = ApplyOp(IntrinsicId, Result, Elt);
634 }
635 }
636 return Result;
637}
638
640 float LogConstVal = numbers::ln2f) {
641 Value *X = Orig->getOperand(0);
642 IRBuilder<> Builder(Orig);
643 Type *Ty = X->getType();
644 Type *EltTy = Ty->getScalarType();
645 Constant *Ln2Const =
646 Ty->isVectorTy() ? ConstantVector::getSplat(
648 cast<FixedVectorType>(Ty)->getNumElements()),
649 ConstantFP::get(EltTy, LogConstVal))
650 : ConstantFP::get(EltTy, LogConstVal);
651 CallInst *Log2Call = Builder.CreateIntrinsicWithoutFolding(
652 Ty, Intrinsic::log2, {X}, nullptr, "elt.log2");
653 Log2Call->setTailCall(Orig->isTailCall());
654 Log2Call->setAttributes(Orig->getAttributes());
655 return Builder.CreateFMul(Ln2Const, Log2Call);
656}
660
661// Use dot product of vector operand with itself to calculate the length.
662// Divide the vector by that length to normalize it.
664 Value *X = Orig->getOperand(0);
665 Type *Ty = Orig->getType();
666 Type *EltTy = Ty->getScalarType();
667 IRBuilder<> Builder(Orig);
668
669 auto *XVec = dyn_cast<FixedVectorType>(Ty);
670 if (!XVec) {
671 if (auto *constantFP = dyn_cast<ConstantFP>(X)) {
672 const APFloat &fpVal = constantFP->getValueAPF();
673 if (fpVal.isZero())
674 reportFatalUsageError("Invalid input scalar: length is zero");
675 }
676 return Builder.CreateFDiv(X, X);
677 }
678
679 Value *DotProduct = expandFloatDotChunk(Orig, X, X);
680
681 // verify that the length is non-zero
682 // (if the dot product is non-zero, then the length is non-zero)
683 if (auto *constantFP = dyn_cast<ConstantFP>(DotProduct)) {
684 const APFloat &fpVal = constantFP->getValueAPF();
685 if (fpVal.isZero())
686 reportFatalUsageError("Invalid input vector: length is zero");
687 }
688
689 Value *Multiplicand = Builder.CreateIntrinsic(EltTy, Intrinsic::dx_rsqrt,
690 ArrayRef<Value *>{DotProduct},
691 nullptr, "dx.rsqrt");
692
693 Value *MultiplicandVec =
694 Builder.CreateVectorSplat(XVec->getNumElements(), Multiplicand);
695 return Builder.CreateFMul(X, MultiplicandVec);
696}
697
699 Value *Y = Orig->getOperand(0);
700 Value *X = Orig->getOperand(1);
701 Type *Ty = X->getType();
702 IRBuilder<> Builder(Orig);
703 Builder.setFastMathFlags(Orig->getFastMathFlags());
704
705 Value *Tan = Builder.CreateFDiv(Y, X);
706
707 CallInst *Atan = Builder.CreateIntrinsicWithoutFolding(
708 Ty, Intrinsic::atan, {Tan}, nullptr, "Elt.Atan");
709 Atan->setTailCall(Orig->isTailCall());
710 Atan->setAttributes(Orig->getAttributes());
711
712 // Modify atan result based on https://en.wikipedia.org/wiki/Atan2.
713 Constant *Pi = ConstantFP::get(Ty, llvm::numbers::pi);
714 Constant *HalfPi = ConstantFP::get(Ty, llvm::numbers::pi / 2);
715 Constant *NegHalfPi = ConstantFP::get(Ty, -llvm::numbers::pi / 2);
716 Constant *Zero = ConstantFP::get(Ty, 0);
717 Value *AtanAddPi = Builder.CreateFAdd(Atan, Pi);
718 Value *AtanSubPi = Builder.CreateFSub(Atan, Pi);
719
720 // x > 0 -> atan.
721 Value *Result = Atan;
722 Value *XLt0 = Builder.CreateFCmpOLT(X, Zero);
723 Value *XEq0 = Builder.CreateFCmpOEQ(X, Zero);
724 Value *YGe0 = Builder.CreateFCmpOGE(Y, Zero);
725 Value *YLt0 = Builder.CreateFCmpOLT(Y, Zero);
726
727 // x < 0, y >= 0 -> atan + pi.
728 Value *XLt0AndYGe0 = Builder.CreateAnd(XLt0, YGe0);
729 Result = Builder.CreateSelect(XLt0AndYGe0, AtanAddPi, Result);
730
731 // x < 0, y < 0 -> atan - pi.
732 Value *XLt0AndYLt0 = Builder.CreateAnd(XLt0, YLt0);
733 Result = Builder.CreateSelect(XLt0AndYLt0, AtanSubPi, Result);
734
735 // x == 0, y < 0 -> -pi/2
736 Value *XEq0AndYLt0 = Builder.CreateAnd(XEq0, YLt0);
737 Result = Builder.CreateSelect(XEq0AndYLt0, NegHalfPi, Result);
738
739 // x == 0, y > 0 -> pi/2
740 Value *XEq0AndYGe0 = Builder.CreateAnd(XEq0, YGe0);
741 Result = Builder.CreateSelect(XEq0AndYGe0, HalfPi, Result);
742
743 return Result;
744}
745
746template <bool LeftFunnel>
748 Type *Ty = Orig->getType();
749 Value *A = Orig->getOperand(0);
750 Value *B = Orig->getOperand(1);
751 Value *Shift = Orig->getOperand(2);
752
753 IRBuilder<> Builder(Orig);
754
755 unsigned BitWidth = Ty->getScalarSizeInBits();
757 "Can't use Mask to compute modulo and inverse");
758
759 // Note: if (Shift % BitWidth) == 0 then (BitWidth - Shift) == BitWidth,
760 // shifting by the bitwidth for shl/lshr returns a poisoned result. As such,
761 // we implement the same formula as LegalizerHelper::lowerFunnelShiftAsShifts.
762 //
763 // The funnel shift is expanded like so:
764 // fshl
765 // -> msb_extract((concat(A, B) << (Shift % BitWidth)), BitWidth)
766 // -> A << (Shift % BitWidth) | B >> 1 >> (BitWidth - 1 - (Shift % BitWidth))
767 // fshr
768 // -> lsb_extract((concat(A, B) >> (Shift % BitWidth), BitWidth))
769 // -> A << 1 << (BitWidth - 1 - (Shift % BitWidth)) | B >> (Shift % BitWidth)
770
771 // (BitWidth - 1) -> Mask
772 Constant *Mask = ConstantInt::get(Ty, Ty->getScalarSizeInBits() - 1);
773
774 // Shift % BitWidth
775 // -> Shift & (BitWidth - 1)
776 // -> Shift & Mask
777 Value *MaskedShift = Builder.CreateAnd(Shift, Mask);
778
779 // (BitWidth - 1) - (Shift % BitWidth)
780 // -> ~Shift & (BitWidth - 1)
781 // -> ~Shift & Mask
782 Value *NotShift = Builder.CreateNot(Shift);
783 Value *InverseShift = Builder.CreateAnd(NotShift, Mask);
784
785 Constant *One = ConstantInt::get(Ty, 1);
786 Value *ShiftedA;
787 Value *ShiftedB;
788
789 if (LeftFunnel) {
790 ShiftedA = Builder.CreateShl(A, MaskedShift);
791 Value *ShiftB1 = Builder.CreateLShr(B, One);
792 ShiftedB = Builder.CreateLShr(ShiftB1, InverseShift);
793 } else {
794 Value *ShiftA1 = Builder.CreateShl(A, One);
795 ShiftedA = Builder.CreateShl(ShiftA1, InverseShift);
796 ShiftedB = Builder.CreateLShr(B, MaskedShift);
797 }
798
799 Value *Result = Builder.CreateOr(ShiftedA, ShiftedB);
800 return Result;
801}
802
803static Value *expandPowIntrinsic(CallInst *Orig, Intrinsic::ID IntrinsicId) {
804
805 Value *X = Orig->getOperand(0);
806 Value *Y = Orig->getOperand(1);
807 Type *Ty = X->getType();
808 IRBuilder<> Builder(Orig);
809
810 if (IntrinsicId == Intrinsic::powi)
811 Y = Builder.CreateSIToFP(Y, Ty);
812
813 Value *Log2Call =
814 Builder.CreateIntrinsic(Ty, Intrinsic::log2, {X}, nullptr, "elt.log2");
815 auto *Mul = Builder.CreateFMul(Log2Call, Y);
816 CallInst *Exp2Call = Builder.CreateIntrinsicWithoutFolding(
817 Ty, Intrinsic::exp2, {Mul}, nullptr, "elt.exp2");
818 Exp2Call->setTailCall(Orig->isTailCall());
819 Exp2Call->setAttributes(Orig->getAttributes());
820 return Exp2Call;
821}
822
823static bool expandBufferLoadIntrinsic(CallInst *Orig, bool IsRaw) {
824 IRBuilder<> Builder(Orig);
825
826 Type *BufferTy = Orig->getType()->getStructElementType(0);
827 Type *ScalarTy = BufferTy->getScalarType();
828 bool IsDouble = ScalarTy->isDoubleTy();
829 assert(IsDouble || ScalarTy->isIntegerTy(64) &&
830 "Only expand double or int64 scalars or vectors");
831 bool IsVector = false;
832 unsigned ExtractNum = 2;
833 if (auto *VT = dyn_cast<FixedVectorType>(BufferTy)) {
834 ExtractNum = 2 * VT->getNumElements();
835 IsVector = true;
836 assert(IsRaw || ExtractNum == 4 && "TypedBufferLoad vector must be size 2");
837 }
838
840 Value *Result = PoisonValue::get(BufferTy);
841 unsigned Base = 0;
842 // If we need to extract more than 4 i32; we need to break it up into
843 // more than one load. LoadNum tells us how many i32s we are loading in
844 // each load
845 while (ExtractNum > 0) {
846 unsigned LoadNum = std::min(ExtractNum, 4u);
847 Type *Ty = VectorType::get(Builder.getInt32Ty(), LoadNum, false);
848
849 Type *LoadType = StructType::get(Ty, Builder.getInt1Ty());
850 Intrinsic::ID LoadIntrinsic = Intrinsic::dx_resource_load_typedbuffer;
851 SmallVector<Value *, 3> Args = {Orig->getOperand(0), Orig->getOperand(1)};
852 if (IsRaw) {
853 LoadIntrinsic = Intrinsic::dx_resource_load_rawbuffer;
854 Value *Tmp = Builder.getInt32(4 * Base * 2);
855 Args.push_back(Builder.CreateAdd(Orig->getOperand(2), Tmp));
856 }
857
858 Value *Load = Builder.CreateIntrinsic(LoadType, LoadIntrinsic, Args);
859 Loads.push_back(Load);
860
861 // extract the buffer load's result
862 Value *Extract = Builder.CreateExtractValue(Load, {0});
863
864 SmallVector<Value *> ExtractElements;
865 for (unsigned I = 0; I < LoadNum; ++I)
866 ExtractElements.push_back(
867 Builder.CreateExtractElement(Extract, Builder.getInt32(I)));
868
869 // combine into double(s) or int64(s)
870 for (unsigned I = 0; I < LoadNum; I += 2) {
871 Value *Combined = nullptr;
872 if (IsDouble)
873 // For doubles, use dx_asdouble intrinsic
874 Combined = Builder.CreateIntrinsic(
875 Builder.getDoubleTy(), Intrinsic::dx_asdouble,
876 {ExtractElements[I], ExtractElements[I + 1]});
877 else {
878 // For int64, manually combine two int32s
879 // First, zero-extend both values to i64
880 Value *Lo =
881 Builder.CreateZExt(ExtractElements[I], Builder.getInt64Ty());
882 Value *Hi =
883 Builder.CreateZExt(ExtractElements[I + 1], Builder.getInt64Ty());
884 // Shift the high bits left by 32 bits
885 Value *ShiftedHi = Builder.CreateShl(Hi, Builder.getInt64(32));
886 // OR the high and low bits together
887 Combined = Builder.CreateOr(Lo, ShiftedHi);
888 }
889
890 if (IsVector)
891 Result = Builder.CreateInsertElement(Result, Combined,
892 Builder.getInt32((I / 2) + Base));
893 else
894 Result = Combined;
895 }
896
897 ExtractNum -= LoadNum;
898 Base += LoadNum / 2;
899 }
900
901 Value *CheckBit = nullptr;
902 for (User *U : make_early_inc_range(Orig->users())) {
903 // If it's not a ExtractValueInst, we don't know how to
904 // handle it
905 auto *EVI = dyn_cast<ExtractValueInst>(U);
906 if (!EVI)
907 llvm_unreachable("Unexpected user of typedbufferload");
908
909 ArrayRef<unsigned> Indices = EVI->getIndices();
910 assert(Indices.size() == 1);
911
912 if (Indices[0] == 0) {
913 // Use of the value(s)
914 EVI->replaceAllUsesWith(Result);
915 } else {
916 // Use of the check bit
917 assert(Indices[0] == 1 && "Unexpected type for typedbufferload");
918 // Note: This does not always match the historical behaviour of DXC.
919 // See https://github.com/microsoft/DirectXShaderCompiler/issues/7622
920 if (!CheckBit) {
921 SmallVector<Value *, 2> CheckBits;
922 for (Value *L : Loads)
923 CheckBits.push_back(Builder.CreateExtractValue(L, {1}));
924 CheckBit = Builder.CreateAnd(CheckBits);
925 }
926 EVI->replaceAllUsesWith(CheckBit);
927 }
928 EVI->eraseFromParent();
929 }
930 Orig->eraseFromParent();
931 return true;
932}
933
934static bool expandBufferStoreIntrinsic(CallInst *Orig, bool IsRaw) {
935 IRBuilder<> Builder(Orig);
936
937 unsigned ValIndex = IsRaw ? 3 : 2;
938 Type *BufferTy = Orig->getFunctionType()->getParamType(ValIndex);
939 Type *ScalarTy = BufferTy->getScalarType();
940 bool IsDouble = ScalarTy->isDoubleTy();
941 assert((IsDouble || ScalarTy->isIntegerTy(64)) &&
942 "Only expand double or int64 scalars or vectors");
943
944 // Determine if we're dealing with a vector or scalar
945 bool IsVector = false;
946 unsigned ExtractNum = 2;
947 unsigned VecLen = 0;
948 if (auto *VT = dyn_cast<FixedVectorType>(BufferTy)) {
949 VecLen = VT->getNumElements();
950 assert(IsRaw || VecLen == 2 && "TypedBufferStore vector must be size 2");
951 ExtractNum = VecLen * 2;
952 IsVector = true;
953 }
954
955 // Create the appropriate vector type for the result
956 Type *Int32Ty = Builder.getInt32Ty();
957 Type *ResultTy = VectorType::get(Int32Ty, ExtractNum, false);
958 Value *Val = PoisonValue::get(ResultTy);
959
960 Type *SplitElementTy = Int32Ty;
961 if (IsVector)
962 SplitElementTy = VectorType::get(SplitElementTy, VecLen, false);
963
964 Value *LowBits = nullptr;
965 Value *HighBits = nullptr;
966 // Split the 64-bit values into 32-bit components
967 if (IsDouble) {
968 auto *SplitTy = llvm::StructType::get(SplitElementTy, SplitElementTy);
969 Value *Split = Builder.CreateIntrinsic(SplitTy, Intrinsic::dx_splitdouble,
970 {Orig->getOperand(ValIndex)});
971 LowBits = Builder.CreateExtractValue(Split, 0);
972 HighBits = Builder.CreateExtractValue(Split, 1);
973 } else {
974 // Handle int64 type(s)
975 Value *InputVal = Orig->getOperand(ValIndex);
976 Constant *ShiftAmt = Builder.getInt64(32);
977 if (IsVector)
978 ShiftAmt =
980
981 // Split into low and high 32-bit parts
982 LowBits = Builder.CreateTrunc(InputVal, SplitElementTy);
983 Value *ShiftedVal = Builder.CreateLShr(InputVal, ShiftAmt);
984 HighBits = Builder.CreateTrunc(ShiftedVal, SplitElementTy);
985 }
986
987 if (IsVector) {
989 for (unsigned I = 0; I < VecLen; ++I) {
990 Mask.push_back(I);
991 Mask.push_back(I + VecLen);
992 }
993 Val = Builder.CreateShuffleVector(LowBits, HighBits, Mask);
994 } else {
995 Val = Builder.CreateInsertElement(Val, LowBits, Builder.getInt32(0));
996 Val = Builder.CreateInsertElement(Val, HighBits, Builder.getInt32(1));
997 }
998
999 // If we need to extract more than 4 i32; we need to break it up into
1000 // more than one store. StoreNum tells us how many i32s we are storing in
1001 // each store
1002 unsigned Base = 0;
1003 while (ExtractNum > 0) {
1004 unsigned StoreNum = std::min(ExtractNum, 4u);
1005
1006 Intrinsic::ID StoreIntrinsic = Intrinsic::dx_resource_store_typedbuffer;
1007 SmallVector<Value *, 4> Args = {Orig->getOperand(0), Orig->getOperand(1)};
1008 if (IsRaw) {
1009 StoreIntrinsic = Intrinsic::dx_resource_store_rawbuffer;
1010 Value *Tmp = Builder.getInt32(4 * Base);
1011 Args.push_back(Builder.CreateAdd(Orig->getOperand(2), Tmp));
1012 }
1013
1015 for (unsigned I = 0; I < StoreNum; ++I) {
1016 Mask.push_back(Base + I);
1017 }
1018
1019 Value *SubVal = Val;
1020 if (VecLen > 2)
1021 SubVal = Builder.CreateShuffleVector(Val, Mask);
1022
1023 Args.push_back(SubVal);
1024 // Create the final intrinsic call
1025 Builder.CreateIntrinsic(Builder.getVoidTy(), StoreIntrinsic, Args);
1026
1027 ExtractNum -= StoreNum;
1028 Base += StoreNum;
1029 }
1030 Orig->eraseFromParent();
1031 return true;
1032}
1033
1035 if (ClampIntrinsic == Intrinsic::dx_uclamp)
1036 return Intrinsic::umax;
1037 if (ClampIntrinsic == Intrinsic::dx_sclamp)
1038 return Intrinsic::smax;
1039 assert(ClampIntrinsic == Intrinsic::dx_nclamp);
1040 return Intrinsic::maxnum;
1041}
1042
1044 if (ClampIntrinsic == Intrinsic::dx_uclamp)
1045 return Intrinsic::umin;
1046 if (ClampIntrinsic == Intrinsic::dx_sclamp)
1047 return Intrinsic::smin;
1048 assert(ClampIntrinsic == Intrinsic::dx_nclamp);
1049 return Intrinsic::minnum;
1050}
1051
1053 Intrinsic::ID ClampIntrinsic) {
1054 Value *X = Orig->getOperand(0);
1055 Value *Min = Orig->getOperand(1);
1056 Value *Max = Orig->getOperand(2);
1057 Type *Ty = X->getType();
1058 IRBuilder<> Builder(Orig);
1059 auto *MaxCall = Builder.CreateIntrinsic(Ty, getMaxForClamp(ClampIntrinsic),
1060 {X, Min}, nullptr, "dx.max");
1061 return Builder.CreateIntrinsic(Ty, getMinForClamp(ClampIntrinsic),
1062 {MaxCall, Max}, nullptr, "dx.min");
1063}
1064
1066 Value *X = Orig->getOperand(0);
1067 Type *Ty = X->getType();
1068 Type *ScalarTy = Ty->getScalarType();
1069 Type *RetTy = Orig->getType();
1070 Constant *Zero = Constant::getNullValue(Ty);
1071
1072 IRBuilder<> Builder(Orig);
1073
1074 Value *GT;
1075 Value *LT;
1076 if (ScalarTy->isFloatingPointTy()) {
1077 GT = Builder.CreateFCmpOLT(Zero, X);
1078 LT = Builder.CreateFCmpOLT(X, Zero);
1079 } else {
1080 assert(ScalarTy->isIntegerTy());
1081 GT = Builder.CreateICmpSLT(Zero, X);
1082 LT = Builder.CreateICmpSLT(X, Zero);
1083 }
1084
1085 Value *ZextGT = Builder.CreateZExt(GT, RetTy);
1086 Value *ZextLT = Builder.CreateZExt(LT, RetTy);
1087
1088 return Builder.CreateSub(ZextGT, ZextLT);
1089}
1090
1091// Expand llvm.copysign by combining the sign bit with the magnitude bits using
1092// bitwise operations.
1094 Value *Magnitude = Orig->getOperand(0);
1095 Value *Sign = Orig->getOperand(1);
1096 Type *Ty = Orig->getType();
1097
1098 IRBuilder<> Builder(Orig);
1099
1100 bool IsDouble = Ty->getScalarType()->isDoubleTy();
1101 unsigned BitWidth = IsDouble ? 32 : Ty->getScalarSizeInBits();
1102 Type *IntTy = Ty->getWithNewType(Builder.getIntNTy(BitWidth));
1103
1104 auto CopySignBit = [&](Value *MagnitudeInt, Value *SignInt) {
1105 APInt SignMaskVal = APInt::getSignMask(BitWidth);
1106 // `ConstantInt::get` broadcasts to a splat when `IntTy` is a vector.
1107 Constant *SignMask = ConstantInt::get(IntTy, SignMaskVal);
1108 Constant *NotSignMask = ConstantInt::get(IntTy, ~SignMaskVal);
1109
1110 Value *MagnitudeBits = Builder.CreateAnd(MagnitudeInt, NotSignMask);
1111 Value *SignBits = Builder.CreateAnd(SignInt, SignMask);
1112 return Builder.CreateOr(MagnitudeBits, SignBits);
1113 };
1114
1115 // Avoid i64 bitwise ops, which require the Int64Ops shader feature.
1116 if (IsDouble) {
1117 auto *SplitTy = StructType::get(IntTy, IntTy);
1118 Value *MagnitudeHalves = Builder.CreateIntrinsic(
1119 SplitTy, Intrinsic::dx_splitdouble, {Magnitude});
1120 Value *SignHalves =
1121 Builder.CreateIntrinsic(SplitTy, Intrinsic::dx_splitdouble, {Sign});
1122 Value *MagnitudeLow = Builder.CreateExtractValue(MagnitudeHalves, 0);
1123 Value *MagnitudeHigh = Builder.CreateExtractValue(MagnitudeHalves, 1);
1124 Value *SignHigh = Builder.CreateExtractValue(SignHalves, 1);
1125
1126 Value *CombinedHigh = CopySignBit(MagnitudeHigh, SignHigh);
1127 return Builder.CreateIntrinsic(Ty, Intrinsic::dx_asdouble,
1128 {MagnitudeLow, CombinedHigh});
1129 }
1130
1131 Value *MagnitudeInt = Builder.CreateBitCast(Magnitude, IntTy);
1132 Value *SignInt = Builder.CreateBitCast(Sign, IntTy);
1133 Value *CombinedInt = CopySignBit(MagnitudeInt, SignInt);
1134 return Builder.CreateBitCast(CombinedInt, Ty);
1135}
1136
1137// Expand llvm.matrix.multiply by extracting row/column vectors and computing
1138// dot products.
1139// Result[r,c] = dot(row_r(LHS), col_c(RHS))
1140// Element (r,c) is at index c*NumRows + r (column-major).
1142 Value *LHS = Orig->getArgOperand(0);
1143 Value *RHS = Orig->getArgOperand(1);
1144 unsigned LHSRows = cast<ConstantInt>(Orig->getArgOperand(2))->getZExtValue();
1145 unsigned LHSCols = cast<ConstantInt>(Orig->getArgOperand(3))->getZExtValue();
1146 unsigned RHSCols = cast<ConstantInt>(Orig->getArgOperand(4))->getZExtValue();
1147
1148 auto *RetTy = cast<FixedVectorType>(Orig->getType());
1149 Type *EltTy = RetTy->getElementType();
1150 bool IsFP = EltTy->isFloatingPointTy();
1151
1152 IRBuilder<> Builder(Orig);
1153
1154 // Column-major indexing:
1155 // LHS row R, element K: index = K * LHSRows + R
1156 // RHS col C, element K: index = C * LHSCols + K
1157 Value *Result = PoisonValue::get(RetTy);
1158
1159 // Extract all scalar elements from LHS and RHS once, then reuse them.
1160 unsigned LHSSize = LHSRows * LHSCols;
1161 unsigned RHSSize = LHSCols * RHSCols;
1162 SmallVector<Value *, 16> LHSElts(LHSSize);
1163 SmallVector<Value *, 16> RHSElts(RHSSize);
1164 for (unsigned I = 0; I < LHSSize; ++I)
1165 LHSElts[I] = Builder.CreateExtractElement(LHS, I);
1166 for (unsigned I = 0; I < RHSSize; ++I)
1167 RHSElts[I] = Builder.CreateExtractElement(RHS, I);
1168
1169 // Choose the appropriate scalar-arg dot intrinsic for floats.
1170 // K=1 and double types use scalar expansion instead.
1172 bool UseScalarFP = IsFP && (EltTy->isDoubleTy() || LHSCols == 1);
1173 if (IsFP && !UseScalarFP) {
1174 switch (LHSCols) {
1175 case 2:
1176 FloatDotID = Intrinsic::dx_dot2;
1177 break;
1178 case 3:
1179 FloatDotID = Intrinsic::dx_dot3;
1180 break;
1181 case 4:
1182 FloatDotID = Intrinsic::dx_dot4;
1183 break;
1184 default:
1186 "Invalid matrix inner dimension for dot product: must be 2-4");
1187 return nullptr;
1188 }
1189 }
1190
1191 for (unsigned C = 0; C < RHSCols; ++C) {
1192 for (unsigned R = 0; R < LHSRows; ++R) {
1193 // Gather row R from LHS and column C from RHS.
1194 SmallVector<Value *, 4> RowElts, ColElts;
1195 for (unsigned K = 0; K < LHSCols; ++K) {
1196 RowElts.push_back(LHSElts[K * LHSRows + R]);
1197 ColElts.push_back(RHSElts[C * LHSCols + K]);
1198 }
1199
1200 Value *Dot;
1201 if (UseScalarFP) {
1202 // Scalar fmul+fmuladd expansion for double types and K=1.
1203 Dot = Builder.CreateFMul(RowElts[0], ColElts[0]);
1204 for (unsigned K = 1; K < LHSCols; ++K)
1205 Dot = Builder.CreateIntrinsic(EltTy, Intrinsic::fmuladd,
1206 {RowElts[K], ColElts[K], Dot});
1207 } else if (IsFP) {
1208 // Emit scalar-arg DXIL dot directly (dx.dot2/dx.dot3/dx.dot4).
1210 Args.append(RowElts.begin(), RowElts.end());
1211 Args.append(ColElts.begin(), ColElts.end());
1212 Dot = Builder.CreateIntrinsic(EltTy, FloatDotID, Args);
1213 } else {
1214 // Integer: emit multiply + imad chain.
1215 Dot = Builder.CreateMul(RowElts[0], ColElts[0]);
1216 for (unsigned K = 1; K < LHSCols; ++K)
1217 Dot = Builder.CreateIntrinsic(EltTy, Intrinsic::dx_imad,
1218 {RowElts[K], ColElts[K], Dot});
1219 }
1220 unsigned ResIdx = C * LHSRows + R;
1221 Result = Builder.CreateInsertElement(Result, Dot, ResIdx);
1222 }
1223 }
1224 return Result;
1225}
1226
1227// Expand llvm.matrix.transpose as a shufflevector that permutes elements
1228// from column-major source to column-major transposed layout.
1229// Element (r,c) at index c*Rows + r moves to index r*Cols + c.
1231 Value *Mat = Orig->getArgOperand(0);
1232 unsigned Rows = cast<ConstantInt>(Orig->getArgOperand(1))->getZExtValue();
1233 unsigned Cols = cast<ConstantInt>(Orig->getArgOperand(2))->getZExtValue();
1234
1235 unsigned NumElts = Rows * Cols;
1236 SmallVector<int, 16> Mask(NumElts);
1237 for (unsigned I = 0; I < NumElts; ++I)
1238 Mask[I] = (I % Cols) * Rows + (I / Cols);
1239
1240 IRBuilder<> Builder(Orig);
1241 return Builder.CreateShuffleVector(Mat, Mask);
1242}
1243
1244// Scalarize a vector int_dx_store_output call into per-component scalar calls.
1245// The DXIL StoreOutput op is per-component; vector intrinsics are split here
1246// so that DXILOpLowering sees only scalar variants.
1247static bool expandStoreOutput(CallInst *Orig) {
1248 auto *VT = dyn_cast<FixedVectorType>(Orig->getArgOperand(3)->getType());
1249 if (!VT)
1250 return false; // already scalar, nothing to expand
1251
1252 IRBuilder<> Builder(Orig);
1253 Module *M = Orig->getModule();
1254 Type *Int8Ty = Builder.getInt8Ty();
1255 Type *Int32Ty = Builder.getInt32Ty();
1256 Type *ScalarTy = VT->getElementType();
1257 unsigned NumElems = VT->getNumElements();
1258
1259 Value *SigElementId = Orig->getArgOperand(0);
1260 Value *RowIndex = Orig->getArgOperand(1);
1261 Value *StartCol = Orig->getArgOperand(2); // i8
1262 Value *Data = Orig->getArgOperand(3);
1263 Value *StartColI32 = Builder.CreateZExt(StartCol, Int32Ty);
1264
1266 M, Intrinsic::dx_store_output, {ScalarTy});
1267
1268 for (unsigned I = 0; I < NumElems; ++I) {
1269 Value *Scalar =
1270 Builder.CreateExtractElement(Data, ConstantInt::get(Int32Ty, I));
1271 Value *ColIdx =
1272 Builder.CreateAdd(StartColI32, ConstantInt::get(Int32Ty, I));
1273 Value *ColI8 = Builder.CreateTrunc(ColIdx, Int8Ty);
1274 Builder.CreateCall(ScalarFn, {SigElementId, RowIndex, ColI8, Scalar});
1275 }
1276
1277 Orig->eraseFromParent();
1278 return true;
1279}
1280
1281// Scalarize a vector int_dx_load_input call into per-component scalar calls
1282// and reassemble the vector. The DXIL LoadInput op is per-component.
1284 auto *VT = dyn_cast<FixedVectorType>(Orig->getType());
1285 if (!VT)
1286 return nullptr; // already scalar, nothing to expand
1287
1288 IRBuilder<> Builder(Orig);
1289 Module *M = Orig->getModule();
1290 Type *Int8Ty = Builder.getInt8Ty();
1291 Type *Int32Ty = Builder.getInt32Ty();
1292 Type *ScalarTy = VT->getElementType();
1293 unsigned NumElems = VT->getNumElements();
1294
1295 Value *SigElementId = Orig->getArgOperand(0);
1296 Value *RowIndex = Orig->getArgOperand(1);
1297 Value *StartCol = Orig->getArgOperand(2); // i8
1298 Value *GsVertexOrPrimIndex = Orig->getArgOperand(3);
1299 Value *StartColI32 = Builder.CreateZExt(StartCol, Int32Ty);
1300
1302 M, Intrinsic::dx_load_input, {ScalarTy});
1303
1304 Value *Vec = PoisonValue::get(VT);
1305 for (unsigned I = 0; I < NumElems; ++I) {
1306 Value *ColIdx =
1307 Builder.CreateAdd(StartColI32, ConstantInt::get(Int32Ty, I));
1308 Value *ColI8 = Builder.CreateTrunc(ColIdx, Int8Ty);
1309 Value *Scalar = Builder.CreateCall(
1310 ScalarFn, {SigElementId, RowIndex, ColI8, GsVertexOrPrimIndex});
1311 Vec =
1312 Builder.CreateInsertElement(Vec, Scalar, ConstantInt::get(Int32Ty, I));
1313 }
1314
1315 return Vec;
1316}
1317
1318static bool expandIntrinsic(Function &F, CallInst *Orig) {
1319 Value *Result = nullptr;
1320 Intrinsic::ID IntrinsicId = F.getIntrinsicID();
1321 switch (IntrinsicId) {
1322 case Intrinsic::abs:
1323 Result = expandAbs(Orig);
1324 break;
1325 case Intrinsic::assume:
1326 Orig->eraseFromParent();
1327 return true;
1328 case Intrinsic::atan2:
1329 Result = expandAtan2Intrinsic(Orig);
1330 break;
1331 case Intrinsic::copysign:
1332 Result = expandCopySignIntrinsic(Orig);
1333 break;
1334 case Intrinsic::fshl:
1335 Result = expandFunnelShiftIntrinsic<true>(Orig);
1336 break;
1337 case Intrinsic::fshr:
1338 Result = expandFunnelShiftIntrinsic<false>(Orig);
1339 break;
1340 case Intrinsic::exp:
1341 Result = expandExpIntrinsic(Orig);
1342 break;
1343 case Intrinsic::is_fpclass:
1344 Result = expandIsFPClass(Orig);
1345 break;
1346 case Intrinsic::log:
1347 Result = expandLogIntrinsic(Orig);
1348 break;
1349 case Intrinsic::log10:
1350 Result = expandLog10Intrinsic(Orig);
1351 break;
1352 case Intrinsic::pow:
1353 case Intrinsic::powi:
1354 Result = expandPowIntrinsic(Orig, IntrinsicId);
1355 break;
1356 case Intrinsic::dx_all:
1357 case Intrinsic::dx_any:
1358 Result = expandAnyOrAllIntrinsic(Orig, IntrinsicId);
1359 break;
1360 case Intrinsic::dx_uclamp:
1361 case Intrinsic::dx_sclamp:
1362 case Intrinsic::dx_nclamp:
1363 Result = expandClampIntrinsic(Orig, IntrinsicId);
1364 break;
1365 case Intrinsic::dx_isinf:
1366 Result = expand16BitIsInf(Orig);
1367 break;
1368 case Intrinsic::dx_isnan:
1369 Result = expand16BitIsNaN(Orig);
1370 break;
1371 case Intrinsic::dx_normalize:
1372 Result = expandNormalizeIntrinsic(Orig);
1373 break;
1374 case Intrinsic::dx_fdot:
1375 Result = expandFloatDotIntrinsic(Orig);
1376 break;
1377 case Intrinsic::dx_sdot:
1378 case Intrinsic::dx_udot:
1379 Result = expandIntegerDotIntrinsic(Orig, IntrinsicId);
1380 break;
1381 case Intrinsic::dx_sign:
1382 Result = expandSignIntrinsic(Orig);
1383 break;
1384 case Intrinsic::dx_load_input:
1385 Result = expandLoadInput(Orig);
1386 break;
1387 case Intrinsic::dx_store_output:
1388 if (expandStoreOutput(Orig))
1389 return true;
1390 break;
1391 case Intrinsic::dx_resource_load_rawbuffer:
1392 if (expandBufferLoadIntrinsic(Orig, /*IsRaw*/ true))
1393 return true;
1394 break;
1395 case Intrinsic::dx_resource_store_rawbuffer:
1396 if (expandBufferStoreIntrinsic(Orig, /*IsRaw*/ true))
1397 return true;
1398 break;
1399 case Intrinsic::dx_resource_load_typedbuffer:
1400 if (expandBufferLoadIntrinsic(Orig, /*IsRaw*/ false))
1401 return true;
1402 break;
1403 case Intrinsic::dx_resource_store_typedbuffer:
1404 if (expandBufferStoreIntrinsic(Orig, /*IsRaw*/ false))
1405 return true;
1406 break;
1407 case Intrinsic::usub_sat:
1408 Result = expandUsubSat(Orig);
1409 break;
1410 case Intrinsic::umul_with_overflow:
1411 case Intrinsic::smul_with_overflow:
1412 Result = expandMulWithOverflow(Orig, /*Signed=*/IntrinsicId ==
1413 Intrinsic::smul_with_overflow);
1414 break;
1415 case Intrinsic::vector_reduce_add:
1416 case Intrinsic::vector_reduce_fadd:
1417 Result = expandVecReduceAdd(Orig, IntrinsicId);
1418 break;
1419 case Intrinsic::matrix_multiply:
1420 Result = expandMatrixMultiply(Orig);
1421 break;
1422 case Intrinsic::matrix_transpose:
1423 Result = expandMatrixTranspose(Orig);
1424 break;
1425 }
1426 if (Result) {
1427 Orig->replaceAllUsesWith(Result);
1428 Orig->eraseFromParent();
1429 return true;
1430 }
1431 return false;
1432}
1433
1435 for (auto &F : make_early_inc_range(M.functions())) {
1436 if (!isIntrinsicExpansion(F))
1437 continue;
1438 bool IntrinsicExpanded = false;
1439 for (User *U : make_early_inc_range(F.users())) {
1440 auto *IntrinsicCall = dyn_cast<CallInst>(U);
1441 if (!IntrinsicCall)
1442 continue;
1443 IntrinsicExpanded = expandIntrinsic(F, IntrinsicCall);
1444 }
1445 if (F.user_empty() && IntrinsicExpanded)
1446 F.eraseFromParent();
1447 }
1448 return true;
1449}
1450
1457
1461
1463
1465 "DXIL Intrinsic Expansion", false, false)
1467 "DXIL Intrinsic Expansion", false, false)
1468
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned uint64_t
This file implements a class to represent arbitrary precision integral constant values and operations...
#define X(NUM, ENUM, NAME)
Definition ELF.h:857
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
static Value * expand16BitIsNormal(CallInst *Orig)
static Value * expandNormalizeIntrinsic(CallInst *Orig)
static Value * createMulHighUnsigned(IRBuilder<> &Builder, Value *A, Value *B, Type *Ty, unsigned BW)
static bool expandIntrinsic(Function &F, CallInst *Orig)
static Value * expandClampIntrinsic(CallInst *Orig, Intrinsic::ID ClampIntrinsic)
static Value * expand16BitIsInf(CallInst *Orig)
static bool expansionIntrinsics(Module &M)
static Value * expandCopySignIntrinsic(CallInst *Orig)
static Value * expand16BitIsFinite(CallInst *Orig)
static Value * expandLoadInput(CallInst *Orig)
static Value * expandUsubSat(CallInst *Orig)
static Value * expandAnyOrAllIntrinsic(CallInst *Orig, Intrinsic::ID IntrinsicId)
static Value * expandFloatDotIntrinsic(CallInst *Orig)
static bool expandStoreOutput(CallInst *Orig)
static Value * expandMatrixTranspose(CallInst *Orig)
static Value * expandVecReduceAdd(CallInst *Orig, Intrinsic::ID IntrinsicId)
static Value * expandAtan2Intrinsic(CallInst *Orig)
static Value * expandLog10Intrinsic(CallInst *Orig)
static Intrinsic::ID getMinForClamp(Intrinsic::ID ClampIntrinsic)
static Value * expandIntegerDotIntrinsic(CallInst *Orig, Intrinsic::ID DotIntrinsic)
static bool expandBufferStoreIntrinsic(CallInst *Orig, bool IsRaw)
static Value * expandLogIntrinsic(CallInst *Orig, float LogConstVal=numbers::ln2f)
static Value * expandMulWithOverflow(CallInst *Orig, bool Signed)
static Value * expandPowIntrinsic(CallInst *Orig, Intrinsic::ID IntrinsicId)
static bool resourceAccessNeeds64BitExpansion(Module *M, Type *OverloadTy, bool IsRaw)
static Value * expandExpIntrinsic(CallInst *Orig)
static Value * expand16BitIsNaN(CallInst *Orig)
static Value * expandSignIntrinsic(CallInst *Orig)
static Intrinsic::ID getMaxForClamp(Intrinsic::ID ClampIntrinsic)
static bool shouldExpandFloatDotIntrinsic(Function &F)
static Value * expandFloatDotChunk(CallInst *Orig, Value *A, Value *B)
static Value * expandAbs(CallInst *Orig)
static bool isIntrinsicExpansion(Function &F)
static bool expandBufferLoadIntrinsic(CallInst *Orig, bool IsRaw)
static Value * expandMatrixMultiply(CallInst *Orig)
static Value * expandIsFPClass(CallInst *Orig)
static Value * expandFunnelShiftIntrinsic(CallInst *Orig)
#define DEBUG_TYPE
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
#define T
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition PassSupport.h:44
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition PassSupport.h:39
const SmallVectorImpl< MachineOperand > & Cond
This file contains some templates that are useful if you are working with the STL at all.
This file defines the SmallVector class.
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
Value * RHS
Value * LHS
BinaryOperator * Mul
bool runOnModule(Module &M) override
runOnModule - Virtual method overriden by subclasses to process the module being operated on.
bool isZero() const
Definition APFloat.h:1571
Class for arbitrary precision integers.
Definition APInt.h:78
static APInt getSignMask(unsigned BitWidth)
Get the SignMask for a specific bit width.
Definition APInt.h:226
static APInt getLowBitsSet(unsigned numBits, unsigned loBitsSet)
Constructs an APInt value that has the bottom loBitsSet bits set.
Definition APInt.h:303
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
size_t size() const
Get the array size.
Definition ArrayRef.h:141
void setAttributes(AttributeList A)
Set the attributes for this call.
Value * getArgOperand(unsigned i) const
FunctionType * getFunctionType() const
AttributeList getAttributes() const
Return the attributes for this call.
This class represents a function call, abstracting a target machine's calling convention.
bool isTailCall() const
void setTailCall(bool IsTc=true)
static LLVM_ABI Constant * getSplat(ElementCount EC, Constant *Elt)
Return a ConstantVector with the specified constant in each element.
This is an important base class in LLVM.
Definition Constant.h:43
bool isNullValue() const
Return true if this is the value that would be returned by getNullValue.
Definition Constant.h:64
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &)
static constexpr ElementCount getFixed(ScalarTy MinVal)
Definition TypeSize.h:309
static LLVM_ABI FixedVectorType * get(Type *ElementType, unsigned NumElts)
Definition Type.cpp:867
Type * getParamType(unsigned i) const
Parameter type accessors.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2903
LLVM_ABI const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI FastMathFlags getFastMathFlags() const LLVM_READONLY
Convenience function for getting all the fast-math flags, which must be an operator which supports th...
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition Pass.h:255
ModulePass(char &pid)
Definition Pass.h:257
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
const Triple & getTargetTriple() const
Get the target triple which is a string describing the target host.
Definition Module.h:323
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition Analysis.h:115
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
static LLVM_ABI StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
Definition Type.cpp:477
LLVM_ABI VersionTuple getOSVersion() const
Parse the version number from the OS name component of the triple, if present.
Definition Triple.cpp:1476
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
LLVM_ABI Type * getStructElementType(unsigned N) const
bool isVectorTy() const
True if this is an instance of VectorType.
Definition Type.h:288
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
Definition Type.cpp:309
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
Definition Type.cpp:307
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
Definition Type.h:368
LLVM_ABI TypeSize getPrimitiveSizeInBits() const LLVM_READONLY
Return the basic size of this type if it is a primitive type.
Definition Type.cpp:197
LLVM_ABI Type * getWithNewBitWidth(unsigned NewBitWidth) const
Given an integer or vector type, change the lane bitwidth to NewBitwidth, whilst keeping the old numb...
static LLVM_ABI IntegerType * getInt16Ty(LLVMContext &C)
Definition Type.cpp:308
bool isHalfTy() const
Return true if this is 'half', a 16-bit IEEE fp type.
Definition Type.h:144
LLVM_ABI Type * getWithNewType(Type *EltTy) const
Given vector type, change the element type, whilst keeping the old number of elements.
bool isDoubleTy() const
Return true if this is 'double', a 64-bit IEEE fp type.
Definition Type.h:158
bool isFloatingPointTy() const
Return true if this is one of the floating-point types.
Definition Type.h:186
bool isIntegerTy() const
True if this is an instance of IntegerType.
Definition Type.h:257
static LLVM_ABI IntegerType * getIntNTy(LLVMContext &C, unsigned N)
Definition Type.cpp:313
Value * getOperand(unsigned i) const
Definition User.h:207
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:255
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:553
iterator_range< user_iterator > users()
Definition Value.h:426
static LLVM_ABI VectorType * get(Type *ElementType, ElementCount EC)
This static method is the primary way to construct an VectorType.
Represents a version number in the form major[.minor[.subminor[.build]]].
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > OverloadTys={})
Look up the Function declaration of the intrinsic id in the Module M.
constexpr float ln10f
Definition MathExtras.h:51
constexpr float log2ef
Definition MathExtras.h:52
constexpr double pi
constexpr float ln2f
Definition MathExtras.h:50
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:578
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
@ Load
The value being inserted comes from a load (InsertElement only).
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition STLExtras.h:633
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition MathExtras.h:280
ModulePass * createDXILIntrinsicExpansionLegacyPass()
Pass to expand intrinsic operations that lack DXIL opCodes.
@ Sub
Subtraction of integers.
constexpr unsigned BitWidth
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.
Definition Error.cpp:177