| //===----------------------------------------------------------------------===// |
| // |
| // 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<IntrinsicInst *> ConvergenceIntrinsics; |
| bool Changed = false; |
| |
| for (BasicBlock &BB : F) { |
| for (Instruction &I : make_early_inc_range(BB)) { |
| auto *CI = dyn_cast<CallInst>(&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<CallInst>(NewCall); |
| Changed = true; |
| } |
| |
| // Collect convergence intrinsics for deferred removal. |
| if (auto *II = dyn_cast<IntrinsicInst>(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<CFGAnalyses>(); |
| 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(); |
| } |