1*0fca6ea1SDimitry Andric //===- DXILIntrinsicExpansion.cpp - Prepare LLVM Module for DXIL encoding--===//
2*0fca6ea1SDimitry Andric //
3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0fca6ea1SDimitry Andric //
7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
8*0fca6ea1SDimitry Andric ///
9*0fca6ea1SDimitry Andric /// \file This file contains DXIL intrinsic expansions for those that don't have
10*0fca6ea1SDimitry Andric // opcodes in DirectX Intermediate Language (DXIL).
11*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
12*0fca6ea1SDimitry Andric
13*0fca6ea1SDimitry Andric #include "DXILIntrinsicExpansion.h"
14*0fca6ea1SDimitry Andric #include "DirectX.h"
15*0fca6ea1SDimitry Andric #include "llvm/ADT/STLExtras.h"
16*0fca6ea1SDimitry Andric #include "llvm/ADT/SmallVector.h"
17*0fca6ea1SDimitry Andric #include "llvm/CodeGen/Passes.h"
18*0fca6ea1SDimitry Andric #include "llvm/IR/IRBuilder.h"
19*0fca6ea1SDimitry Andric #include "llvm/IR/Instruction.h"
20*0fca6ea1SDimitry Andric #include "llvm/IR/Instructions.h"
21*0fca6ea1SDimitry Andric #include "llvm/IR/Intrinsics.h"
22*0fca6ea1SDimitry Andric #include "llvm/IR/IntrinsicsDirectX.h"
23*0fca6ea1SDimitry Andric #include "llvm/IR/Module.h"
24*0fca6ea1SDimitry Andric #include "llvm/IR/PassManager.h"
25*0fca6ea1SDimitry Andric #include "llvm/IR/Type.h"
26*0fca6ea1SDimitry Andric #include "llvm/Pass.h"
27*0fca6ea1SDimitry Andric #include "llvm/Support/ErrorHandling.h"
28*0fca6ea1SDimitry Andric #include "llvm/Support/MathExtras.h"
29*0fca6ea1SDimitry Andric
30*0fca6ea1SDimitry Andric #define DEBUG_TYPE "dxil-intrinsic-expansion"
31*0fca6ea1SDimitry Andric
32*0fca6ea1SDimitry Andric using namespace llvm;
33*0fca6ea1SDimitry Andric
isIntrinsicExpansion(Function & F)34*0fca6ea1SDimitry Andric static bool isIntrinsicExpansion(Function &F) {
35*0fca6ea1SDimitry Andric switch (F.getIntrinsicID()) {
36*0fca6ea1SDimitry Andric case Intrinsic::abs:
37*0fca6ea1SDimitry Andric case Intrinsic::exp:
38*0fca6ea1SDimitry Andric case Intrinsic::log:
39*0fca6ea1SDimitry Andric case Intrinsic::log10:
40*0fca6ea1SDimitry Andric case Intrinsic::pow:
41*0fca6ea1SDimitry Andric case Intrinsic::dx_any:
42*0fca6ea1SDimitry Andric case Intrinsic::dx_clamp:
43*0fca6ea1SDimitry Andric case Intrinsic::dx_uclamp:
44*0fca6ea1SDimitry Andric case Intrinsic::dx_lerp:
45*0fca6ea1SDimitry Andric case Intrinsic::dx_sdot:
46*0fca6ea1SDimitry Andric case Intrinsic::dx_udot:
47*0fca6ea1SDimitry Andric return true;
48*0fca6ea1SDimitry Andric }
49*0fca6ea1SDimitry Andric return false;
50*0fca6ea1SDimitry Andric }
51*0fca6ea1SDimitry Andric
expandAbs(CallInst * Orig)52*0fca6ea1SDimitry Andric static bool expandAbs(CallInst *Orig) {
53*0fca6ea1SDimitry Andric Value *X = Orig->getOperand(0);
54*0fca6ea1SDimitry Andric IRBuilder<> Builder(Orig->getParent());
55*0fca6ea1SDimitry Andric Builder.SetInsertPoint(Orig);
56*0fca6ea1SDimitry Andric Type *Ty = X->getType();
57*0fca6ea1SDimitry Andric Type *EltTy = Ty->getScalarType();
58*0fca6ea1SDimitry Andric Constant *Zero = Ty->isVectorTy()
59*0fca6ea1SDimitry Andric ? ConstantVector::getSplat(
60*0fca6ea1SDimitry Andric ElementCount::getFixed(
61*0fca6ea1SDimitry Andric cast<FixedVectorType>(Ty)->getNumElements()),
62*0fca6ea1SDimitry Andric ConstantInt::get(EltTy, 0))
63*0fca6ea1SDimitry Andric : ConstantInt::get(EltTy, 0);
64*0fca6ea1SDimitry Andric auto *V = Builder.CreateSub(Zero, X);
65*0fca6ea1SDimitry Andric auto *MaxCall =
66*0fca6ea1SDimitry Andric Builder.CreateIntrinsic(Ty, Intrinsic::smax, {X, V}, nullptr, "dx.max");
67*0fca6ea1SDimitry Andric Orig->replaceAllUsesWith(MaxCall);
68*0fca6ea1SDimitry Andric Orig->eraseFromParent();
69*0fca6ea1SDimitry Andric return true;
70*0fca6ea1SDimitry Andric }
71*0fca6ea1SDimitry Andric
expandIntegerDot(CallInst * Orig,Intrinsic::ID DotIntrinsic)72*0fca6ea1SDimitry Andric static bool expandIntegerDot(CallInst *Orig, Intrinsic::ID DotIntrinsic) {
73*0fca6ea1SDimitry Andric assert(DotIntrinsic == Intrinsic::dx_sdot ||
74*0fca6ea1SDimitry Andric DotIntrinsic == Intrinsic::dx_udot);
75*0fca6ea1SDimitry Andric Intrinsic::ID MadIntrinsic = DotIntrinsic == Intrinsic::dx_sdot
76*0fca6ea1SDimitry Andric ? Intrinsic::dx_imad
77*0fca6ea1SDimitry Andric : Intrinsic::dx_umad;
78*0fca6ea1SDimitry Andric Value *A = Orig->getOperand(0);
79*0fca6ea1SDimitry Andric Value *B = Orig->getOperand(1);
80*0fca6ea1SDimitry Andric [[maybe_unused]] Type *ATy = A->getType();
81*0fca6ea1SDimitry Andric [[maybe_unused]] Type *BTy = B->getType();
82*0fca6ea1SDimitry Andric assert(ATy->isVectorTy() && BTy->isVectorTy());
83*0fca6ea1SDimitry Andric
84*0fca6ea1SDimitry Andric IRBuilder<> Builder(Orig->getParent());
85*0fca6ea1SDimitry Andric Builder.SetInsertPoint(Orig);
86*0fca6ea1SDimitry Andric
87*0fca6ea1SDimitry Andric auto *AVec = dyn_cast<FixedVectorType>(A->getType());
88*0fca6ea1SDimitry Andric Value *Elt0 = Builder.CreateExtractElement(A, (uint64_t)0);
89*0fca6ea1SDimitry Andric Value *Elt1 = Builder.CreateExtractElement(B, (uint64_t)0);
90*0fca6ea1SDimitry Andric Value *Result = Builder.CreateMul(Elt0, Elt1);
91*0fca6ea1SDimitry Andric for (unsigned I = 1; I < AVec->getNumElements(); I++) {
92*0fca6ea1SDimitry Andric Elt0 = Builder.CreateExtractElement(A, I);
93*0fca6ea1SDimitry Andric Elt1 = Builder.CreateExtractElement(B, I);
94*0fca6ea1SDimitry Andric Result = Builder.CreateIntrinsic(Result->getType(), MadIntrinsic,
95*0fca6ea1SDimitry Andric ArrayRef<Value *>{Elt0, Elt1, Result},
96*0fca6ea1SDimitry Andric nullptr, "dx.mad");
97*0fca6ea1SDimitry Andric }
98*0fca6ea1SDimitry Andric Orig->replaceAllUsesWith(Result);
99*0fca6ea1SDimitry Andric Orig->eraseFromParent();
100*0fca6ea1SDimitry Andric return true;
101*0fca6ea1SDimitry Andric }
102*0fca6ea1SDimitry Andric
expandExpIntrinsic(CallInst * Orig)103*0fca6ea1SDimitry Andric static bool expandExpIntrinsic(CallInst *Orig) {
104*0fca6ea1SDimitry Andric Value *X = Orig->getOperand(0);
105*0fca6ea1SDimitry Andric IRBuilder<> Builder(Orig->getParent());
106*0fca6ea1SDimitry Andric Builder.SetInsertPoint(Orig);
107*0fca6ea1SDimitry Andric Type *Ty = X->getType();
108*0fca6ea1SDimitry Andric Type *EltTy = Ty->getScalarType();
109*0fca6ea1SDimitry Andric Constant *Log2eConst =
110*0fca6ea1SDimitry Andric Ty->isVectorTy() ? ConstantVector::getSplat(
111*0fca6ea1SDimitry Andric ElementCount::getFixed(
112*0fca6ea1SDimitry Andric cast<FixedVectorType>(Ty)->getNumElements()),
113*0fca6ea1SDimitry Andric ConstantFP::get(EltTy, numbers::log2ef))
114*0fca6ea1SDimitry Andric : ConstantFP::get(EltTy, numbers::log2ef);
115*0fca6ea1SDimitry Andric Value *NewX = Builder.CreateFMul(Log2eConst, X);
116*0fca6ea1SDimitry Andric auto *Exp2Call =
117*0fca6ea1SDimitry Andric Builder.CreateIntrinsic(Ty, Intrinsic::exp2, {NewX}, nullptr, "dx.exp2");
118*0fca6ea1SDimitry Andric Exp2Call->setTailCall(Orig->isTailCall());
119*0fca6ea1SDimitry Andric Exp2Call->setAttributes(Orig->getAttributes());
120*0fca6ea1SDimitry Andric Orig->replaceAllUsesWith(Exp2Call);
121*0fca6ea1SDimitry Andric Orig->eraseFromParent();
122*0fca6ea1SDimitry Andric return true;
123*0fca6ea1SDimitry Andric }
124*0fca6ea1SDimitry Andric
expandAnyIntrinsic(CallInst * Orig)125*0fca6ea1SDimitry Andric static bool expandAnyIntrinsic(CallInst *Orig) {
126*0fca6ea1SDimitry Andric Value *X = Orig->getOperand(0);
127*0fca6ea1SDimitry Andric IRBuilder<> Builder(Orig->getParent());
128*0fca6ea1SDimitry Andric Builder.SetInsertPoint(Orig);
129*0fca6ea1SDimitry Andric Type *Ty = X->getType();
130*0fca6ea1SDimitry Andric Type *EltTy = Ty->getScalarType();
131*0fca6ea1SDimitry Andric
132*0fca6ea1SDimitry Andric if (!Ty->isVectorTy()) {
133*0fca6ea1SDimitry Andric Value *Cond = EltTy->isFloatingPointTy()
134*0fca6ea1SDimitry Andric ? Builder.CreateFCmpUNE(X, ConstantFP::get(EltTy, 0))
135*0fca6ea1SDimitry Andric : Builder.CreateICmpNE(X, ConstantInt::get(EltTy, 0));
136*0fca6ea1SDimitry Andric Orig->replaceAllUsesWith(Cond);
137*0fca6ea1SDimitry Andric } else {
138*0fca6ea1SDimitry Andric auto *XVec = dyn_cast<FixedVectorType>(Ty);
139*0fca6ea1SDimitry Andric Value *Cond =
140*0fca6ea1SDimitry Andric EltTy->isFloatingPointTy()
141*0fca6ea1SDimitry Andric ? Builder.CreateFCmpUNE(
142*0fca6ea1SDimitry Andric X, ConstantVector::getSplat(
143*0fca6ea1SDimitry Andric ElementCount::getFixed(XVec->getNumElements()),
144*0fca6ea1SDimitry Andric ConstantFP::get(EltTy, 0)))
145*0fca6ea1SDimitry Andric : Builder.CreateICmpNE(
146*0fca6ea1SDimitry Andric X, ConstantVector::getSplat(
147*0fca6ea1SDimitry Andric ElementCount::getFixed(XVec->getNumElements()),
148*0fca6ea1SDimitry Andric ConstantInt::get(EltTy, 0)));
149*0fca6ea1SDimitry Andric Value *Result = Builder.CreateExtractElement(Cond, (uint64_t)0);
150*0fca6ea1SDimitry Andric for (unsigned I = 1; I < XVec->getNumElements(); I++) {
151*0fca6ea1SDimitry Andric Value *Elt = Builder.CreateExtractElement(Cond, I);
152*0fca6ea1SDimitry Andric Result = Builder.CreateOr(Result, Elt);
153*0fca6ea1SDimitry Andric }
154*0fca6ea1SDimitry Andric Orig->replaceAllUsesWith(Result);
155*0fca6ea1SDimitry Andric }
156*0fca6ea1SDimitry Andric Orig->eraseFromParent();
157*0fca6ea1SDimitry Andric return true;
158*0fca6ea1SDimitry Andric }
159*0fca6ea1SDimitry Andric
expandLerpIntrinsic(CallInst * Orig)160*0fca6ea1SDimitry Andric static bool expandLerpIntrinsic(CallInst *Orig) {
161*0fca6ea1SDimitry Andric Value *X = Orig->getOperand(0);
162*0fca6ea1SDimitry Andric Value *Y = Orig->getOperand(1);
163*0fca6ea1SDimitry Andric Value *S = Orig->getOperand(2);
164*0fca6ea1SDimitry Andric IRBuilder<> Builder(Orig->getParent());
165*0fca6ea1SDimitry Andric Builder.SetInsertPoint(Orig);
166*0fca6ea1SDimitry Andric auto *V = Builder.CreateFSub(Y, X);
167*0fca6ea1SDimitry Andric V = Builder.CreateFMul(S, V);
168*0fca6ea1SDimitry Andric auto *Result = Builder.CreateFAdd(X, V, "dx.lerp");
169*0fca6ea1SDimitry Andric Orig->replaceAllUsesWith(Result);
170*0fca6ea1SDimitry Andric Orig->eraseFromParent();
171*0fca6ea1SDimitry Andric return true;
172*0fca6ea1SDimitry Andric }
173*0fca6ea1SDimitry Andric
expandLogIntrinsic(CallInst * Orig,float LogConstVal=numbers::ln2f)174*0fca6ea1SDimitry Andric static bool expandLogIntrinsic(CallInst *Orig,
175*0fca6ea1SDimitry Andric float LogConstVal = numbers::ln2f) {
176*0fca6ea1SDimitry Andric Value *X = Orig->getOperand(0);
177*0fca6ea1SDimitry Andric IRBuilder<> Builder(Orig->getParent());
178*0fca6ea1SDimitry Andric Builder.SetInsertPoint(Orig);
179*0fca6ea1SDimitry Andric Type *Ty = X->getType();
180*0fca6ea1SDimitry Andric Type *EltTy = Ty->getScalarType();
181*0fca6ea1SDimitry Andric Constant *Ln2Const =
182*0fca6ea1SDimitry Andric Ty->isVectorTy() ? ConstantVector::getSplat(
183*0fca6ea1SDimitry Andric ElementCount::getFixed(
184*0fca6ea1SDimitry Andric cast<FixedVectorType>(Ty)->getNumElements()),
185*0fca6ea1SDimitry Andric ConstantFP::get(EltTy, LogConstVal))
186*0fca6ea1SDimitry Andric : ConstantFP::get(EltTy, LogConstVal);
187*0fca6ea1SDimitry Andric auto *Log2Call =
188*0fca6ea1SDimitry Andric Builder.CreateIntrinsic(Ty, Intrinsic::log2, {X}, nullptr, "elt.log2");
189*0fca6ea1SDimitry Andric Log2Call->setTailCall(Orig->isTailCall());
190*0fca6ea1SDimitry Andric Log2Call->setAttributes(Orig->getAttributes());
191*0fca6ea1SDimitry Andric auto *Result = Builder.CreateFMul(Ln2Const, Log2Call);
192*0fca6ea1SDimitry Andric Orig->replaceAllUsesWith(Result);
193*0fca6ea1SDimitry Andric Orig->eraseFromParent();
194*0fca6ea1SDimitry Andric return true;
195*0fca6ea1SDimitry Andric }
expandLog10Intrinsic(CallInst * Orig)196*0fca6ea1SDimitry Andric static bool expandLog10Intrinsic(CallInst *Orig) {
197*0fca6ea1SDimitry Andric return expandLogIntrinsic(Orig, numbers::ln2f / numbers::ln10f);
198*0fca6ea1SDimitry Andric }
199*0fca6ea1SDimitry Andric
expandPowIntrinsic(CallInst * Orig)200*0fca6ea1SDimitry Andric static bool expandPowIntrinsic(CallInst *Orig) {
201*0fca6ea1SDimitry Andric
202*0fca6ea1SDimitry Andric Value *X = Orig->getOperand(0);
203*0fca6ea1SDimitry Andric Value *Y = Orig->getOperand(1);
204*0fca6ea1SDimitry Andric Type *Ty = X->getType();
205*0fca6ea1SDimitry Andric IRBuilder<> Builder(Orig->getParent());
206*0fca6ea1SDimitry Andric Builder.SetInsertPoint(Orig);
207*0fca6ea1SDimitry Andric
208*0fca6ea1SDimitry Andric auto *Log2Call =
209*0fca6ea1SDimitry Andric Builder.CreateIntrinsic(Ty, Intrinsic::log2, {X}, nullptr, "elt.log2");
210*0fca6ea1SDimitry Andric auto *Mul = Builder.CreateFMul(Log2Call, Y);
211*0fca6ea1SDimitry Andric auto *Exp2Call =
212*0fca6ea1SDimitry Andric Builder.CreateIntrinsic(Ty, Intrinsic::exp2, {Mul}, nullptr, "elt.exp2");
213*0fca6ea1SDimitry Andric Exp2Call->setTailCall(Orig->isTailCall());
214*0fca6ea1SDimitry Andric Exp2Call->setAttributes(Orig->getAttributes());
215*0fca6ea1SDimitry Andric Orig->replaceAllUsesWith(Exp2Call);
216*0fca6ea1SDimitry Andric Orig->eraseFromParent();
217*0fca6ea1SDimitry Andric return true;
218*0fca6ea1SDimitry Andric }
219*0fca6ea1SDimitry Andric
getMaxForClamp(Type * ElemTy,Intrinsic::ID ClampIntrinsic)220*0fca6ea1SDimitry Andric static Intrinsic::ID getMaxForClamp(Type *ElemTy,
221*0fca6ea1SDimitry Andric Intrinsic::ID ClampIntrinsic) {
222*0fca6ea1SDimitry Andric if (ClampIntrinsic == Intrinsic::dx_uclamp)
223*0fca6ea1SDimitry Andric return Intrinsic::umax;
224*0fca6ea1SDimitry Andric assert(ClampIntrinsic == Intrinsic::dx_clamp);
225*0fca6ea1SDimitry Andric if (ElemTy->isVectorTy())
226*0fca6ea1SDimitry Andric ElemTy = ElemTy->getScalarType();
227*0fca6ea1SDimitry Andric if (ElemTy->isIntegerTy())
228*0fca6ea1SDimitry Andric return Intrinsic::smax;
229*0fca6ea1SDimitry Andric assert(ElemTy->isFloatingPointTy());
230*0fca6ea1SDimitry Andric return Intrinsic::maxnum;
231*0fca6ea1SDimitry Andric }
232*0fca6ea1SDimitry Andric
getMinForClamp(Type * ElemTy,Intrinsic::ID ClampIntrinsic)233*0fca6ea1SDimitry Andric static Intrinsic::ID getMinForClamp(Type *ElemTy,
234*0fca6ea1SDimitry Andric Intrinsic::ID ClampIntrinsic) {
235*0fca6ea1SDimitry Andric if (ClampIntrinsic == Intrinsic::dx_uclamp)
236*0fca6ea1SDimitry Andric return Intrinsic::umin;
237*0fca6ea1SDimitry Andric assert(ClampIntrinsic == Intrinsic::dx_clamp);
238*0fca6ea1SDimitry Andric if (ElemTy->isVectorTy())
239*0fca6ea1SDimitry Andric ElemTy = ElemTy->getScalarType();
240*0fca6ea1SDimitry Andric if (ElemTy->isIntegerTy())
241*0fca6ea1SDimitry Andric return Intrinsic::smin;
242*0fca6ea1SDimitry Andric assert(ElemTy->isFloatingPointTy());
243*0fca6ea1SDimitry Andric return Intrinsic::minnum;
244*0fca6ea1SDimitry Andric }
245*0fca6ea1SDimitry Andric
expandClampIntrinsic(CallInst * Orig,Intrinsic::ID ClampIntrinsic)246*0fca6ea1SDimitry Andric static bool expandClampIntrinsic(CallInst *Orig, Intrinsic::ID ClampIntrinsic) {
247*0fca6ea1SDimitry Andric Value *X = Orig->getOperand(0);
248*0fca6ea1SDimitry Andric Value *Min = Orig->getOperand(1);
249*0fca6ea1SDimitry Andric Value *Max = Orig->getOperand(2);
250*0fca6ea1SDimitry Andric Type *Ty = X->getType();
251*0fca6ea1SDimitry Andric IRBuilder<> Builder(Orig->getParent());
252*0fca6ea1SDimitry Andric Builder.SetInsertPoint(Orig);
253*0fca6ea1SDimitry Andric auto *MaxCall = Builder.CreateIntrinsic(
254*0fca6ea1SDimitry Andric Ty, getMaxForClamp(Ty, ClampIntrinsic), {X, Min}, nullptr, "dx.max");
255*0fca6ea1SDimitry Andric auto *MinCall =
256*0fca6ea1SDimitry Andric Builder.CreateIntrinsic(Ty, getMinForClamp(Ty, ClampIntrinsic),
257*0fca6ea1SDimitry Andric {MaxCall, Max}, nullptr, "dx.min");
258*0fca6ea1SDimitry Andric
259*0fca6ea1SDimitry Andric Orig->replaceAllUsesWith(MinCall);
260*0fca6ea1SDimitry Andric Orig->eraseFromParent();
261*0fca6ea1SDimitry Andric return true;
262*0fca6ea1SDimitry Andric }
263*0fca6ea1SDimitry Andric
expandIntrinsic(Function & F,CallInst * Orig)264*0fca6ea1SDimitry Andric static bool expandIntrinsic(Function &F, CallInst *Orig) {
265*0fca6ea1SDimitry Andric switch (F.getIntrinsicID()) {
266*0fca6ea1SDimitry Andric case Intrinsic::abs:
267*0fca6ea1SDimitry Andric return expandAbs(Orig);
268*0fca6ea1SDimitry Andric case Intrinsic::exp:
269*0fca6ea1SDimitry Andric return expandExpIntrinsic(Orig);
270*0fca6ea1SDimitry Andric case Intrinsic::log:
271*0fca6ea1SDimitry Andric return expandLogIntrinsic(Orig);
272*0fca6ea1SDimitry Andric case Intrinsic::log10:
273*0fca6ea1SDimitry Andric return expandLog10Intrinsic(Orig);
274*0fca6ea1SDimitry Andric case Intrinsic::pow:
275*0fca6ea1SDimitry Andric return expandPowIntrinsic(Orig);
276*0fca6ea1SDimitry Andric case Intrinsic::dx_any:
277*0fca6ea1SDimitry Andric return expandAnyIntrinsic(Orig);
278*0fca6ea1SDimitry Andric case Intrinsic::dx_uclamp:
279*0fca6ea1SDimitry Andric case Intrinsic::dx_clamp:
280*0fca6ea1SDimitry Andric return expandClampIntrinsic(Orig, F.getIntrinsicID());
281*0fca6ea1SDimitry Andric case Intrinsic::dx_lerp:
282*0fca6ea1SDimitry Andric return expandLerpIntrinsic(Orig);
283*0fca6ea1SDimitry Andric case Intrinsic::dx_sdot:
284*0fca6ea1SDimitry Andric case Intrinsic::dx_udot:
285*0fca6ea1SDimitry Andric return expandIntegerDot(Orig, F.getIntrinsicID());
286*0fca6ea1SDimitry Andric }
287*0fca6ea1SDimitry Andric return false;
288*0fca6ea1SDimitry Andric }
289*0fca6ea1SDimitry Andric
expansionIntrinsics(Module & M)290*0fca6ea1SDimitry Andric static bool expansionIntrinsics(Module &M) {
291*0fca6ea1SDimitry Andric for (auto &F : make_early_inc_range(M.functions())) {
292*0fca6ea1SDimitry Andric if (!isIntrinsicExpansion(F))
293*0fca6ea1SDimitry Andric continue;
294*0fca6ea1SDimitry Andric bool IntrinsicExpanded = false;
295*0fca6ea1SDimitry Andric for (User *U : make_early_inc_range(F.users())) {
296*0fca6ea1SDimitry Andric auto *IntrinsicCall = dyn_cast<CallInst>(U);
297*0fca6ea1SDimitry Andric if (!IntrinsicCall)
298*0fca6ea1SDimitry Andric continue;
299*0fca6ea1SDimitry Andric IntrinsicExpanded = expandIntrinsic(F, IntrinsicCall);
300*0fca6ea1SDimitry Andric }
301*0fca6ea1SDimitry Andric if (F.user_empty() && IntrinsicExpanded)
302*0fca6ea1SDimitry Andric F.eraseFromParent();
303*0fca6ea1SDimitry Andric }
304*0fca6ea1SDimitry Andric return true;
305*0fca6ea1SDimitry Andric }
306*0fca6ea1SDimitry Andric
run(Module & M,ModuleAnalysisManager &)307*0fca6ea1SDimitry Andric PreservedAnalyses DXILIntrinsicExpansion::run(Module &M,
308*0fca6ea1SDimitry Andric ModuleAnalysisManager &) {
309*0fca6ea1SDimitry Andric if (expansionIntrinsics(M))
310*0fca6ea1SDimitry Andric return PreservedAnalyses::none();
311*0fca6ea1SDimitry Andric return PreservedAnalyses::all();
312*0fca6ea1SDimitry Andric }
313*0fca6ea1SDimitry Andric
runOnModule(Module & M)314*0fca6ea1SDimitry Andric bool DXILIntrinsicExpansionLegacy::runOnModule(Module &M) {
315*0fca6ea1SDimitry Andric return expansionIntrinsics(M);
316*0fca6ea1SDimitry Andric }
317*0fca6ea1SDimitry Andric
318*0fca6ea1SDimitry Andric char DXILIntrinsicExpansionLegacy::ID = 0;
319*0fca6ea1SDimitry Andric
320*0fca6ea1SDimitry Andric INITIALIZE_PASS_BEGIN(DXILIntrinsicExpansionLegacy, DEBUG_TYPE,
321*0fca6ea1SDimitry Andric "DXIL Intrinsic Expansion", false, false)
322*0fca6ea1SDimitry Andric INITIALIZE_PASS_END(DXILIntrinsicExpansionLegacy, DEBUG_TYPE,
323*0fca6ea1SDimitry Andric "DXIL Intrinsic Expansion", false, false)
324*0fca6ea1SDimitry Andric
createDXILIntrinsicExpansionLegacyPass()325*0fca6ea1SDimitry Andric ModulePass *llvm::createDXILIntrinsicExpansionLegacyPass() {
326*0fca6ea1SDimitry Andric return new DXILIntrinsicExpansionLegacy();
327*0fca6ea1SDimitry Andric }
328