LLVM: lib/Target/DirectX/DXILIntrinsicExpansion.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
23#include "llvm/IR/IntrinsicsDirectX.h"
30
31#define DEBUG_TYPE "dxil-intrinsic-expansion"
32
33using namespace llvm;
34
36
37public:
40
42};
43
45 switch (F.getIntrinsicID()) {
46 case Intrinsic::abs:
47 case Intrinsic::atan2:
48 case Intrinsic::exp:
49 case Intrinsic:🪵
50 case Intrinsic::log10:
51 case Intrinsic::pow:
52 case Intrinsic::dx_all:
53 case Intrinsic::dx_any:
54 case Intrinsic::dx_cross:
55 case Intrinsic::dx_uclamp:
56 case Intrinsic::dx_sclamp:
57 case Intrinsic::dx_nclamp:
58 case Intrinsic::dx_degrees:
59 case Intrinsic::dx_lerp:
60 case Intrinsic::dx_normalize:
61 case Intrinsic::dx_fdot:
62 case Intrinsic::dx_sdot:
63 case Intrinsic::dx_udot:
64 case Intrinsic::dx_sign:
65 case Intrinsic::dx_step:
66 case Intrinsic::dx_radians:
67 case Intrinsic::vector_reduce_add:
68 case Intrinsic::vector_reduce_fadd:
69 return true;
70 }
71 return false;
72}
74 assert(IntrinsicId == Intrinsic::vector_reduce_add ||
75 IntrinsicId == Intrinsic::vector_reduce_fadd);
76
78 bool IsFAdd = (IntrinsicId == Intrinsic::vector_reduce_fadd);
79
82 auto *XVec = dyn_cast(Ty);
83 unsigned XVecSize = XVec->getNumElements();
85
86
87 if (IsFAdd) {
89 if (StartValue && !StartValue->isZeroValue())
90 Sum = Builder.CreateFAdd(Sum, StartValue);
91 }
92
93
94 for (unsigned I = 1; I < XVecSize; I++) {
96 if (IsFAdd)
98 else
99 Sum = Builder.CreateAdd(Sum, Elt);
100 }
101
102 return Sum;
103}
104
114 ConstantInt::get(EltTy, 0))
115 : ConstantInt::get(EltTy, 0);
116 auto *V = Builder.CreateSub(Zero, X);
117 return Builder.CreateIntrinsic(Ty, Intrinsic::smax, {X, V}, nullptr,
118 "dx.max");
119}
120
122
124 if (cast(VT)->getNumElements() != 3)
126 false);
127
131
135
139
144 };
145
146 Value *yz_zy = MulSub(op0_y, op0_z, op1_y, op1_z);
147 Value *zx_xz = MulSub(op0_z, op0_x, op1_z, op1_x);
148 Value *xy_yx = MulSub(op0_x, op0_y, op1_x, op1_y);
149
154 return cross;
155}
156
157
158
159
162 [[maybe_unused]] Type *BTy = B->getType();
164
166
167 auto *AVec = dyn_cast(ATy);
168
170
172 switch (AVec->getNumElements()) {
173 case 2:
174 DotIntrinsic = Intrinsic::dx_dot2;
175 break;
176 case 3:
177 DotIntrinsic = Intrinsic::dx_dot3;
178 break;
179 case 4:
180 DotIntrinsic = Intrinsic::dx_dot4;
181 break;
182 default:
184 Twine("Invalid dot product input vector: length is outside 2-4"),
185 false);
186 return nullptr;
187 }
190}
191
192
193
194
198}
199
200
203 assert(DotIntrinsic == Intrinsic::dx_sdot ||
204 DotIntrinsic == Intrinsic::dx_udot);
208 [[maybe_unused]] Type *BTy = B->getType();
210
212
213 auto *AVec = dyn_cast(ATy);
214
216
218 Intrinsic::ID MadIntrinsic = DotIntrinsic == Intrinsic::dx_sdot
219 ? Intrinsic::dx_imad
220 : Intrinsic::dx_umad;
223 Result = Builder.CreateMul(Elt0, Elt1);
224 for (unsigned I = 1; I < AVec->getNumElements(); I++) {
227 Result = Builder.CreateIntrinsic(Result->getType(), MadIntrinsic,
229 nullptr, "dx.mad");
230 }
231 return Result;
232}
233
246 auto *Exp2Call =
247 Builder.CreateIntrinsic(Ty, Intrinsic::exp2, {NewX}, nullptr, "dx.exp2");
250 return Exp2Call;
251}
252
259
262 if (IntrinsicId == Intrinsic::dx_any)
263 return Builder.CreateOr(Result, Elt);
264 assert(IntrinsicId == Intrinsic::dx_all);
265 return Builder.CreateAnd(Result, Elt);
266 };
267
268 Value *Result = nullptr;
271 ? Builder.CreateFCmpUNE(X, ConstantFP::get(EltTy, 0))
272 : Builder.CreateICmpNE(X, ConstantInt::get(EltTy, 0));
273 } else {
274 auto *XVec = dyn_cast(Ty);
280 ConstantFP::get(EltTy, 0)))
284 ConstantInt::get(EltTy, 0)));
286 for (unsigned I = 1; I < XVec->getNumElements(); I++) {
288 Result = ApplyOp(intrinsicId, Result, Elt);
289 }
290 }
291 return Result;
292}
293
301 return Builder.CreateFAdd(X, V, "dx.lerp");
302}
303
314 ConstantFP::get(EltTy, LogConstVal))
315 : ConstantFP::get(EltTy, LogConstVal);
316 auto *Log2Call =
317 Builder.CreateIntrinsic(Ty, Intrinsic::log2, {X}, nullptr, "elt.log2");
320 return Builder.CreateFMul(Ln2Const, Log2Call);
321}
324}
325
326
327
333
334 auto *XVec = dyn_cast(Ty);
335 if (!XVec) {
336 if (auto *constantFP = dyn_cast(X)) {
337 const APFloat &fpVal = constantFP->getValueAPF();
340 false);
341 }
343 }
344
346
347
348
349 if (auto *constantFP = dyn_cast(DotProduct)) {
350 const APFloat &fpVal = constantFP->getValueAPF();
353 false);
354 }
355
358 nullptr, "dx.rsqrt");
359
360 Value *MultiplicandVec =
362 return Builder.CreateFMul(X, MultiplicandVec);
363}
364
371
373
375 Builder.CreateIntrinsic(Ty, Intrinsic::atan, {Tan}, nullptr, "Elt.Atan");
378
379
383 Constant *Zero = ConstantFP::get(Ty, 0);
386
387
388 Value *Result = Atan;
393
394
396 Result = Builder.CreateSelect(XLt0AndYGe0, AtanAddPi, Result);
397
398
400 Result = Builder.CreateSelect(XLt0AndYLt0, AtanSubPi, Result);
401
402
404 Result = Builder.CreateSelect(XEq0AndYLt0, NegHalfPi, Result);
405
406
408 Result = Builder.CreateSelect(XEq0AndYGe0, HalfPi, Result);
409
410 return Result;
411}
412
414
419
420 auto *Log2Call =
421 Builder.CreateIntrinsic(Ty, Intrinsic::log2, {X}, nullptr, "elt.log2");
423 auto *Exp2Call =
424 Builder.CreateIntrinsic(Ty, Intrinsic::exp2, {Mul}, nullptr, "elt.exp2");
427 return Exp2Call;
428}
429
431
436
440
442 auto *XVec = dyn_cast(Ty);
447 }
448
450}
451
458}
459
461 if (ClampIntrinsic == Intrinsic::dx_uclamp)
462 return Intrinsic::umax;
463 if (ClampIntrinsic == Intrinsic::dx_sclamp)
464 return Intrinsic::smax;
465 assert(ClampIntrinsic == Intrinsic::dx_nclamp);
466 return Intrinsic::maxnum;
467}
468
470 if (ClampIntrinsic == Intrinsic::dx_uclamp)
471 return Intrinsic::umin;
472 if (ClampIntrinsic == Intrinsic::dx_sclamp)
473 return Intrinsic::smin;
474 assert(ClampIntrinsic == Intrinsic::dx_nclamp);
475 return Intrinsic::minnum;
476}
477
486 {X, Min}, nullptr, "dx.max");
488 {MaxCall, Max}, nullptr, "dx.min");
489}
490
496 return Builder.CreateFMul(X, DegreesRatio);
497}
498
505
507
513 } else {
517 }
518
521
522 return Builder.CreateSub(ZextGT, ZextLT);
523}
524
526 Value *Result = nullptr;
528 switch (IntrinsicId) {
529 case Intrinsic::abs:
531 break;
532 case Intrinsic::atan2:
534 break;
535 case Intrinsic::exp:
537 break;
538 case Intrinsic:🪵
540 break;
541 case Intrinsic::log10:
543 break;
544 case Intrinsic::pow:
546 break;
547 case Intrinsic::dx_all:
548 case Intrinsic::dx_any:
550 break;
551 case Intrinsic::dx_cross:
553 break;
554 case Intrinsic::dx_uclamp:
555 case Intrinsic::dx_sclamp:
556 case Intrinsic::dx_nclamp:
558 break;
559 case Intrinsic::dx_degrees:
561 break;
562 case Intrinsic::dx_lerp:
564 break;
565 case Intrinsic::dx_normalize:
567 break;
568 case Intrinsic::dx_fdot:
570 break;
571 case Intrinsic::dx_sdot:
572 case Intrinsic::dx_udot:
574 break;
575 case Intrinsic::dx_sign:
577 break;
578 case Intrinsic::dx_step:
580 break;
581 case Intrinsic::dx_radians:
583 break;
584 case Intrinsic::vector_reduce_add:
585 case Intrinsic::vector_reduce_fadd:
587 break;
588 }
589 if (Result) {
592 return true;
593 }
594 return false;
595}
596
600 continue;
601 bool IntrinsicExpanded = false;
603 auto *IntrinsicCall = dyn_cast(U);
604 if (!IntrinsicCall)
605 continue;
607 }
608 if (F.user_empty() && IntrinsicExpanded)
609 F.eraseFromParent();
610 }
611 return true;
612}
613
619}
620
623}
624
626
628 "DXIL Intrinsic Expansion", false, false)
631
634}
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static Value * expandNormalizeIntrinsic(CallInst *Orig)
static bool expandIntrinsic(Function &F, CallInst *Orig)
static Value * expandClampIntrinsic(CallInst *Orig, Intrinsic::ID ClampIntrinsic)
static bool expansionIntrinsics(Module &M)
static Value * expandLerpIntrinsic(CallInst *Orig)
static Value * expandCrossIntrinsic(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 * expandStepIntrinsic(CallInst *Orig)
static Value * expandIntegerDotIntrinsic(CallInst *Orig, Intrinsic::ID DotIntrinsic)
static Value * expandPowIntrinsic(CallInst *Orig)
static Value * expandLogIntrinsic(CallInst *Orig, float LogConstVal=numbers::ln2f)
static Value * expandDegreesIntrinsic(CallInst *Orig)
static Value * expandExpIntrinsic(CallInst *Orig)
static Value * expandSignIntrinsic(CallInst *Orig)
static Intrinsic::ID getMaxForClamp(Intrinsic::ID ClampIntrinsic)
static Value * expandAnyOrAllIntrinsic(CallInst *Orig, Intrinsic::ID intrinsicId)
static Value * expandAbs(CallInst *Orig)
static Value * expandFloatDotIntrinsic(CallInst *Orig, Value *A, Value *B)
static Value * expandRadiansIntrinsic(CallInst *Orig)
static bool isIntrinsicExpansion(Function &F)
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang", "erlang-compatible garbage collector")
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
static GCMetadataPrinterRegistry::Add< OcamlGCMetadataPrinter > Y("ocaml", "ocaml 3.10-compatible collector")
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
const SmallVectorImpl< MachineOperand > & Cond
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static unsigned getNumElements(Type *Ty)
This file defines the SmallVector class.
bool runOnModule(Module &M) override
runOnModule - Virtual method overriden by subclasses to process the module being operated on.
DXILIntrinsicExpansionLegacy()
A container for analyses that lazily runs them and caches their results.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
void setAttributes(AttributeList A)
Set the attributes for this call.
AttributeList getAttributes() const
Return the attributes for this call.
This class represents a function call, abstracting a target machine's calling convention.
void setTailCall(bool IsTc=true)
static Constant * getSplat(ElementCount EC, Constant *Elt)
Return a ConstantVector with the specified constant in each element.
This is an important base class in LLVM.
static Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
bool isZeroValue() const
Return true if the value is negative zero or null value.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &)
static constexpr ElementCount getFixed(ScalarTy MinVal)
Value * CreateFSub(Value *L, Value *R, const Twine &Name="", MDNode *FPMD=nullptr)
Value * CreateInsertElement(Type *VecTy, Value *NewElt, Value *Idx, const Twine &Name="")
Value * CreateFDiv(Value *L, Value *R, const Twine &Name="", MDNode *FPMD=nullptr)
Value * CreateExtractElement(Value *Vec, Value *Idx, const Twine &Name="")
Value * CreateFAdd(Value *L, Value *R, const Twine &Name="", MDNode *FPMD=nullptr)
Value * CreateVectorSplat(unsigned NumElts, Value *V, const Twine &Name="")
Return a vector value that contains.
Value * CreateSelect(Value *C, Value *True, Value *False, const Twine &Name="", Instruction *MDFrom=nullptr)
Value * CreateFCmpUNE(Value *LHS, Value *RHS, const Twine &Name="", MDNode *FPMathTag=nullptr)
void setFastMathFlags(FastMathFlags NewFMF)
Set the fast-math flags to be used with generated fp-math operators.
Value * CreateFCmpOLT(Value *LHS, Value *RHS, const Twine &Name="", MDNode *FPMathTag=nullptr)
Value * CreateICmpNE(Value *LHS, Value *RHS, const Twine &Name="")
CallInst * CreateIntrinsic(Intrinsic::ID ID, ArrayRef< Type * > Types, ArrayRef< Value * > Args, FMFSource FMFSource={}, const Twine &Name="")
Create a call to intrinsic ID with Args, mangled using Types.
Value * CreateSub(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Value * CreateZExt(Value *V, Type *DestTy, const Twine &Name="", bool IsNonNeg=false)
Value * CreateFCmpOEQ(Value *LHS, Value *RHS, const Twine &Name="", MDNode *FPMathTag=nullptr)
Value * CreateAnd(Value *LHS, Value *RHS, const Twine &Name="")
Value * CreateAdd(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Value * CreateOr(Value *LHS, Value *RHS, const Twine &Name="")
Value * CreateICmpSLT(Value *LHS, Value *RHS, const Twine &Name="")
Value * CreateFMul(Value *L, Value *R, const Twine &Name="", MDNode *FPMD=nullptr)
Value * CreateMul(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Value * CreateFCmpOGE(Value *LHS, Value *RHS, const Twine &Name="", MDNode *FPMathTag=nullptr)
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
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...
A Module instance is used to store all the information related to an LLVM module.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
The instances of the Type class are immutable: once they are created, they are never changed.
bool isVectorTy() const
True if this is an instance of VectorType.
bool isFloatingPointTy() const
Return true if this is one of the floating-point types.
bool isIntegerTy() const
True if this is an instance of IntegerType.
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
static UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
Value * getOperand(unsigned i) const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
StringRef getName() const
Return a constant reference to the value's name.
This is an optimization pass for GlobalISel generic memory operations.
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...
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
ModulePass * createDXILIntrinsicExpansionLegacyPass()
Pass to expand intrinsic operations that lack DXIL opCodes.