1*7a6dacacSDimitry Andric //===-- SPIRVStripConvergentIntrinsics.cpp ----------------------*- C++ -*-===// 2*7a6dacacSDimitry Andric // 3*7a6dacacSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*7a6dacacSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*7a6dacacSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*7a6dacacSDimitry Andric // 7*7a6dacacSDimitry Andric //===----------------------------------------------------------------------===// 8*7a6dacacSDimitry Andric // 9*7a6dacacSDimitry Andric // This pass trims convergence intrinsics as those were only useful when 10*7a6dacacSDimitry Andric // modifying the CFG during IR passes. 11*7a6dacacSDimitry Andric // 12*7a6dacacSDimitry Andric //===----------------------------------------------------------------------===// 13*7a6dacacSDimitry Andric 14*7a6dacacSDimitry Andric #include "SPIRV.h" 15*7a6dacacSDimitry Andric #include "SPIRVSubtarget.h" 16*7a6dacacSDimitry Andric #include "SPIRVTargetMachine.h" 17*7a6dacacSDimitry Andric #include "SPIRVUtils.h" 18*7a6dacacSDimitry Andric #include "llvm/CodeGen/IntrinsicLowering.h" 19*7a6dacacSDimitry Andric #include "llvm/IR/IRBuilder.h" 20*7a6dacacSDimitry Andric #include "llvm/IR/IntrinsicInst.h" 21*7a6dacacSDimitry Andric #include "llvm/IR/Intrinsics.h" 22*7a6dacacSDimitry Andric #include "llvm/IR/IntrinsicsSPIRV.h" 23*7a6dacacSDimitry Andric #include "llvm/Transforms/Utils/Cloning.h" 24*7a6dacacSDimitry Andric #include "llvm/Transforms/Utils/LowerMemIntrinsics.h" 25*7a6dacacSDimitry Andric 26*7a6dacacSDimitry Andric using namespace llvm; 27*7a6dacacSDimitry Andric 28*7a6dacacSDimitry Andric namespace llvm { 29*7a6dacacSDimitry Andric void initializeSPIRVStripConvergentIntrinsicsPass(PassRegistry &); 30*7a6dacacSDimitry Andric } 31*7a6dacacSDimitry Andric 32*7a6dacacSDimitry Andric class SPIRVStripConvergentIntrinsics : public FunctionPass { 33*7a6dacacSDimitry Andric public: 34*7a6dacacSDimitry Andric static char ID; 35*7a6dacacSDimitry Andric 36*7a6dacacSDimitry Andric SPIRVStripConvergentIntrinsics() : FunctionPass(ID) { 37*7a6dacacSDimitry Andric initializeSPIRVStripConvergentIntrinsicsPass( 38*7a6dacacSDimitry Andric *PassRegistry::getPassRegistry()); 39*7a6dacacSDimitry Andric }; 40*7a6dacacSDimitry Andric 41*7a6dacacSDimitry Andric virtual bool runOnFunction(Function &F) override { 42*7a6dacacSDimitry Andric DenseSet<Instruction *> ToRemove; 43*7a6dacacSDimitry Andric 44*7a6dacacSDimitry Andric for (BasicBlock &BB : F) { 45*7a6dacacSDimitry Andric for (Instruction &I : BB) { 46*7a6dacacSDimitry Andric if (auto *II = dyn_cast<IntrinsicInst>(&I)) { 47*7a6dacacSDimitry Andric if (II->getIntrinsicID() != 48*7a6dacacSDimitry Andric Intrinsic::experimental_convergence_entry && 49*7a6dacacSDimitry Andric II->getIntrinsicID() != 50*7a6dacacSDimitry Andric Intrinsic::experimental_convergence_loop && 51*7a6dacacSDimitry Andric II->getIntrinsicID() != 52*7a6dacacSDimitry Andric Intrinsic::experimental_convergence_anchor) { 53*7a6dacacSDimitry Andric continue; 54*7a6dacacSDimitry Andric } 55*7a6dacacSDimitry Andric 56*7a6dacacSDimitry Andric II->replaceAllUsesWith(UndefValue::get(II->getType())); 57*7a6dacacSDimitry Andric ToRemove.insert(II); 58*7a6dacacSDimitry Andric } else if (auto *CI = dyn_cast<CallInst>(&I)) { 59*7a6dacacSDimitry Andric auto OB = CI->getOperandBundle(LLVMContext::OB_convergencectrl); 60*7a6dacacSDimitry Andric if (!OB.has_value()) 61*7a6dacacSDimitry Andric continue; 62*7a6dacacSDimitry Andric 63*7a6dacacSDimitry Andric auto *NewCall = CallBase::removeOperandBundle( 64*7a6dacacSDimitry Andric CI, LLVMContext::OB_convergencectrl, CI); 65*7a6dacacSDimitry Andric NewCall->copyMetadata(*CI); 66*7a6dacacSDimitry Andric CI->replaceAllUsesWith(NewCall); 67*7a6dacacSDimitry Andric ToRemove.insert(CI); 68*7a6dacacSDimitry Andric } 69*7a6dacacSDimitry Andric } 70*7a6dacacSDimitry Andric } 71*7a6dacacSDimitry Andric 72*7a6dacacSDimitry Andric // All usages must be removed before their definition is removed. 73*7a6dacacSDimitry Andric for (Instruction *I : ToRemove) 74*7a6dacacSDimitry Andric I->eraseFromParent(); 75*7a6dacacSDimitry Andric 76*7a6dacacSDimitry Andric return ToRemove.size() != 0; 77*7a6dacacSDimitry Andric } 78*7a6dacacSDimitry Andric }; 79*7a6dacacSDimitry Andric 80*7a6dacacSDimitry Andric char SPIRVStripConvergentIntrinsics::ID = 0; 81*7a6dacacSDimitry Andric INITIALIZE_PASS(SPIRVStripConvergentIntrinsics, "strip-convergent-intrinsics", 82*7a6dacacSDimitry Andric "SPIRV strip convergent intrinsics", false, false) 83*7a6dacacSDimitry Andric 84*7a6dacacSDimitry Andric FunctionPass *llvm::createSPIRVStripConvergenceIntrinsicsPass() { 85*7a6dacacSDimitry Andric return new SPIRVStripConvergentIntrinsics(); 86*7a6dacacSDimitry Andric } 87