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
100 lines
3.3 KiB
C++
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();
|
|
}
|