87 lines · cpp
1//===-- SPIRVStripConvergentIntrinsics.cpp ----------------------*- C++ -*-===//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-exception6//7//===----------------------------------------------------------------------===//8//9// This pass trims convergence intrinsics as those were only useful when10// modifying the CFG during IR passes.11//12//===----------------------------------------------------------------------===//13 14#include "SPIRV.h"15#include "SPIRVSubtarget.h"16#include "SPIRVUtils.h"17#include "llvm/IR/IntrinsicInst.h"18#include "llvm/IR/Intrinsics.h"19#include "llvm/Transforms/Utils/Cloning.h"20#include "llvm/Transforms/Utils/LowerMemIntrinsics.h"21 22using namespace llvm;23 24namespace {25class SPIRVStripConvergentIntrinsics : public FunctionPass {26public:27 static char ID;28 29 SPIRVStripConvergentIntrinsics() : FunctionPass(ID) {}30 31 bool runOnFunction(Function &F) override {32 DenseSet<Instruction *> ToRemove;33 34 // Is the instruction is a convergent intrinsic, add it to kill-list and35 // returns true. Returns false otherwise.36 auto CleanupIntrinsic = [&](IntrinsicInst *II) {37 if (II->getIntrinsicID() != Intrinsic::experimental_convergence_entry &&38 II->getIntrinsicID() != Intrinsic::experimental_convergence_loop &&39 II->getIntrinsicID() != Intrinsic::experimental_convergence_anchor)40 return false;41 42 II->replaceAllUsesWith(UndefValue::get(II->getType()));43 ToRemove.insert(II);44 return true;45 };46 47 // Replace the given CallInst by a similar CallInst with no convergencectrl48 // attribute.49 auto CleanupCall = [&](CallInst *CI) {50 auto OB = CI->getOperandBundle(LLVMContext::OB_convergencectrl);51 if (!OB.has_value())52 return;53 54 auto *NewCall = CallBase::removeOperandBundle(55 CI, LLVMContext::OB_convergencectrl, CI->getIterator());56 NewCall->copyMetadata(*CI);57 CI->replaceAllUsesWith(NewCall);58 ToRemove.insert(CI);59 };60 61 for (BasicBlock &BB : F) {62 for (Instruction &I : BB) {63 if (auto *II = dyn_cast<IntrinsicInst>(&I))64 if (CleanupIntrinsic(II))65 continue;66 if (auto *CI = dyn_cast<CallInst>(&I))67 CleanupCall(CI);68 }69 }70 71 // All usages must be removed before their definition is removed.72 for (Instruction *I : ToRemove)73 I->eraseFromParent();74 75 return ToRemove.size() != 0;76 }77};78} // namespace79 80char SPIRVStripConvergentIntrinsics::ID = 0;81INITIALIZE_PASS(SPIRVStripConvergentIntrinsics, "strip-convergent-intrinsics",82 "SPIRV strip convergent intrinsics", false, false)83 84FunctionPass *llvm::createSPIRVStripConvergenceIntrinsicsPass() {85 return new SPIRVStripConvergentIntrinsics();86}87