//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This pass strips convergence intrinsics and convergencectrl operand bundles, // as those are only useful when modifying the CFG during IR passes. // //===----------------------------------------------------------------------===// #include "llvm/Transforms/Utils/StripConvergenceIntrinsics.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" #include "llvm/Transforms/Utils.h" using namespace llvm; static bool stripConvergenceIntrinsics(Function &F) { SmallVector ConvergenceIntrinsics; bool Changed = false; for (BasicBlock &BB : F) { for (Instruction &I : make_early_inc_range(BB)) { auto *CI = dyn_cast(&I); if (!CI) continue; // Strip a convergencectrl operand bundle if present. Note that // convergence intrinsics (e.g. convergence.loop) may use a // convergencectrl bundle. if (CI->getOperandBundle(LLVMContext::OB_convergencectrl)) { auto *NewCall = CallBase::removeOperandBundle( CI, LLVMContext::OB_convergencectrl, CI->getIterator()); NewCall->copyMetadata(*CI); CI->replaceAllUsesWith(NewCall); CI->eraseFromParent(); CI = cast(NewCall); Changed = true; } // Collect convergence intrinsics for deferred removal. if (auto *II = dyn_cast(CI)) if (II->getIntrinsicID() == Intrinsic::experimental_convergence_entry || II->getIntrinsicID() == Intrinsic::experimental_convergence_loop || II->getIntrinsicID() == Intrinsic::experimental_convergence_anchor) ConvergenceIntrinsics.push_back(II); } } // Erase all convergence intrinsics now that convergence tokens are no // longer in use. for (IntrinsicInst *II : ConvergenceIntrinsics) II->eraseFromParent(); Changed |= !ConvergenceIntrinsics.empty(); return Changed; } PreservedAnalyses StripConvergenceIntrinsicsPass::run(Function &F, FunctionAnalysisManager &) { if (!stripConvergenceIntrinsics(F)) return PreservedAnalyses::all(); PreservedAnalyses PA; PA.preserveSet(); return PA; } namespace { class StripConvergenceIntrinsicsLegacyPass : public FunctionPass { public: static char ID; StripConvergenceIntrinsicsLegacyPass() : FunctionPass(ID) { initializeStripConvergenceIntrinsicsLegacyPassPass( *PassRegistry::getPassRegistry()); } bool runOnFunction(Function &F) override { return stripConvergenceIntrinsics(F); } }; } // namespace char StripConvergenceIntrinsicsLegacyPass::ID = 0; INITIALIZE_PASS(StripConvergenceIntrinsicsLegacyPass, "strip-convergence-intrinsics", "Strip convergence intrinsics and operand bundles", false, false) FunctionPass *llvm::createStripConvergenceIntrinsicsPass() { return new StripConvergenceIntrinsicsLegacyPass(); }