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 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 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 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 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 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 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 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 } 196*0fca6ea1SDimitry Andric static bool expandLog10Intrinsic(CallInst *Orig) { 197*0fca6ea1SDimitry Andric return expandLogIntrinsic(Orig, numbers::ln2f / numbers::ln10f); 198*0fca6ea1SDimitry Andric } 199*0fca6ea1SDimitry Andric 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 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 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 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 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 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 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 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 325*0fca6ea1SDimitry Andric ModulePass *llvm::createDXILIntrinsicExpansionLegacyPass() { 326*0fca6ea1SDimitry Andric return new DXILIntrinsicExpansionLegacy(); 327*0fca6ea1SDimitry Andric } 328