Files
llvm-project/llvm/lib/Transforms/Utils/StripConvergenceIntrinsics.cpp
Finn Plummer ffde06f4c1 [NFC][SPIRV] Move SPIRVStripConvergenceIntrinsics to Utils (#188537)
The `SPIRVStripConvergenceIntrinsic` pass was written as a spirv pass as
it is the currently the only target that emits convergence tokens during
codegen. There is nothing target specific to the pass, and, we plan to
emit convergence tokens when targeting DirectX (and all targets in
general), so move the pass to a common place.

The previous pass used temporary `Undef`s, as part of moving the pass we
can simply reverse the traverse order to remove the use of `Undef` as it
is deprecated.

Enables the pass for targeting DirectX and is a pre-req for:
https://github.com/llvm/llvm-project/pull/188792.

Assisted by: Github Copilot
2026-04-16 09:24:33 -07:00

100 lines
3.3 KiB
C++

//===----------------------------------------------------------------------===//
//
// 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();
}