[llvm] ffde06f - [NFC][SPIRV] Move `SPIRVStripConvergenceIntrinsics` to Utils (#188537)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Apr 16 09:24:38 PDT 2026
Author: Finn Plummer
Date: 2026-04-16T09:24:33-07:00
New Revision: ffde06f4c11927c60936802fb439a5195ac0742e
URL: https://github.com/llvm/llvm-project/commit/ffde06f4c11927c60936802fb439a5195ac0742e
DIFF: https://github.com/llvm/llvm-project/commit/ffde06f4c11927c60936802fb439a5195ac0742e.diff
LOG: [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
Added:
llvm/include/llvm/Transforms/Utils/StripConvergenceIntrinsics.h
llvm/lib/Transforms/Utils/StripConvergenceIntrinsics.cpp
llvm/test/CodeGen/DirectX/strip-convergence-intrinsics.ll
llvm/test/Transforms/StripConvergenceIntrinsics/basic.ll
Modified:
llvm/include/llvm/InitializePasses.h
llvm/include/llvm/Transforms/Utils.h
llvm/lib/Passes/PassBuilder.cpp
llvm/lib/Passes/PassRegistry.def
llvm/lib/Target/DirectX/DirectXTargetMachine.cpp
llvm/lib/Target/SPIRV/CMakeLists.txt
llvm/lib/Target/SPIRV/SPIRV.h
llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp
llvm/lib/Transforms/Utils/CMakeLists.txt
llvm/test/CodeGen/DirectX/llc-pipeline.ll
llvm/test/CodeGen/SPIRV/llc-pipeline.ll
Removed:
llvm/lib/Target/SPIRV/SPIRVStripConvergentIntrinsics.cpp
################################################################################
diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h
index 604118cee9e2e..012f1fb0ebd90 100644
--- a/llvm/include/llvm/InitializePasses.h
+++ b/llvm/include/llvm/InitializePasses.h
@@ -322,6 +322,8 @@ LLVM_ABI void initializeStackSafetyInfoWrapperPassPass(PassRegistry &);
LLVM_ABI void initializeStackSlotColoringLegacyPass(PassRegistry &);
LLVM_ABI void
initializeStraightLineStrengthReduceLegacyPassPass(PassRegistry &);
+LLVM_ABI void
+initializeStripConvergenceIntrinsicsLegacyPassPass(PassRegistry &);
LLVM_ABI void initializeStripDebugMachineModulePass(PassRegistry &);
LLVM_ABI void initializeStructurizeCFGLegacyPassPass(PassRegistry &);
LLVM_ABI void initializeTailCallElimPass(PassRegistry &);
diff --git a/llvm/include/llvm/Transforms/Utils.h b/llvm/include/llvm/Transforms/Utils.h
index 840e085379a1d..c4e4dffc80c66 100644
--- a/llvm/include/llvm/Transforms/Utils.h
+++ b/llvm/include/llvm/Transforms/Utils.h
@@ -129,6 +129,13 @@ LLVM_ABI Pass *createCanonicalizeFreezeInLoopsPass();
// functions that are registered in @llvm.global_ctors and which contain a call
// to `__cxa_atexit` to register their destructor functions.
LLVM_ABI ModulePass *createLowerGlobalDtorsLegacyPass();
+
+//===----------------------------------------------------------------------===//
+//
+// createStripConvergenceIntrinsicsPass - Strip convergence intrinsics and
+// convergencectrl operand bundles.
+//
+LLVM_ABI FunctionPass *createStripConvergenceIntrinsicsPass();
} // namespace llvm
#endif
diff --git a/llvm/include/llvm/Transforms/Utils/StripConvergenceIntrinsics.h b/llvm/include/llvm/Transforms/Utils/StripConvergenceIntrinsics.h
new file mode 100644
index 0000000000000..96a24641e34d2
--- /dev/null
+++ b/llvm/include/llvm/Transforms/Utils/StripConvergenceIntrinsics.h
@@ -0,0 +1,29 @@
+//===- StripConvergenceIntrinsics.h -----------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This pass strips convergence intrinsics and operand bundles as those are
+/// only useful when modifying the CFG during IR passes.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_UTILS_STRIPCONVERGENCEINTRINSICS_H
+#define LLVM_TRANSFORMS_UTILS_STRIPCONVERGENCEINTRINSICS_H
+
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+
+class StripConvergenceIntrinsicsPass
+ : public PassInfoMixin<StripConvergenceIntrinsicsPass> {
+public:
+ PreservedAnalyses run(Function &F, FunctionAnalysisManager &);
+};
+
+} // namespace llvm
+
+#endif // LLVM_TRANSFORMS_UTILS_STRIPCONVERGENCEINTRINSICS_H
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index 2751961e684d2..8c9f5a0c395cd 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -374,6 +374,7 @@
#include "llvm/Transforms/Utils/PredicateInfo.h"
#include "llvm/Transforms/Utils/ProfileVerify.h"
#include "llvm/Transforms/Utils/RelLookupTableConverter.h"
+#include "llvm/Transforms/Utils/StripConvergenceIntrinsics.h"
#include "llvm/Transforms/Utils/StripGCRelocates.h"
#include "llvm/Transforms/Utils/StripNonLineTableDebugInfo.h"
#include "llvm/Transforms/Utils/SymbolRewriter.h"
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index 9f7b3cf4df77b..2e9d9f3849d17 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -542,6 +542,7 @@ FUNCTION_PASS("sjlj-eh-prepare", SjLjEHPreparePass(TM))
FUNCTION_PASS("slp-vectorizer", SLPVectorizerPass())
FUNCTION_PASS("slsr", StraightLineStrengthReducePass())
FUNCTION_PASS("stack-protector", StackProtectorPass(*TM))
+FUNCTION_PASS("strip-convergence-intrinsics", StripConvergenceIntrinsicsPass())
FUNCTION_PASS("strip-gc-relocates", StripGCRelocates())
FUNCTION_PASS("tailcallelim", TailCallElimPass())
FUNCTION_PASS("transform-warning", WarnMissedTransformationsPass())
diff --git a/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp b/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp
index c0a92f92e1fba..234385828bd3d 100644
--- a/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp
+++ b/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp
@@ -50,6 +50,7 @@
#include "llvm/Transforms/IPO/GlobalDCE.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Scalar/Scalarizer.h"
+#include "llvm/Transforms/Utils.h"
#include <optional>
using namespace llvm;
@@ -81,6 +82,7 @@ LLVMInitializeDirectXTarget() {
initializeDXILForwardHandleAccessesLegacyPass(*PR);
initializeDSELegacyPassPass(*PR);
initializeDXILCBufferAccessLegacyPass(*PR);
+ initializeStripConvergenceIntrinsicsLegacyPassPass(*PR);
}
class DXILTargetObjectFile : public TargetLoweringObjectFile {
@@ -110,6 +112,7 @@ class DirectXPassConfig : public TargetPassConfig {
FunctionPass *createTargetRegisterAllocator(bool) override { return nullptr; }
void addCodeGenPrepare() override {
+ addPass(createStripConvergenceIntrinsicsPass());
addPass(createDXILFinalizeLinkageLegacyPass());
addPass(createGlobalDCEPass());
addPass(createDXILMemIntrinsicsLegacyPass());
diff --git a/llvm/lib/Target/SPIRV/CMakeLists.txt b/llvm/lib/Target/SPIRV/CMakeLists.txt
index 0ce96c23603ff..6c79856c713e9 100644
--- a/llvm/lib/Target/SPIRV/CMakeLists.txt
+++ b/llvm/lib/Target/SPIRV/CMakeLists.txt
@@ -29,7 +29,6 @@ add_llvm_target(SPIRVCodeGen
SPIRVInstructionSelector.cpp
SPIRVLegalizeImplicitBinding.cpp
SPIRVLegalizeZeroSizeArrays.cpp
- SPIRVStripConvergentIntrinsics.cpp
SPIRVLegalizePointerCast.cpp
SPIRVMergeRegionExitTargets.cpp
SPIRVISelLowering.cpp
diff --git a/llvm/lib/Target/SPIRV/SPIRV.h b/llvm/lib/Target/SPIRV/SPIRV.h
index 448a1f0ddaf96..231bbdcd5d304 100644
--- a/llvm/lib/Target/SPIRV/SPIRV.h
+++ b/llvm/lib/Target/SPIRV/SPIRV.h
@@ -24,7 +24,6 @@ FunctionPass *createSPIRVStructurizerPass();
ModulePass *createSPIRVCBufferAccessLegacyPass();
ModulePass *createSPIRVPushConstantAccessLegacyPass(SPIRVTargetMachine *TM);
FunctionPass *createSPIRVMergeRegionExitTargetsPass();
-FunctionPass *createSPIRVStripConvergenceIntrinsicsPass();
ModulePass *createSPIRVLegalizeImplicitBindingPass();
ModulePass *createSPIRVLegalizeZeroSizeArraysPass(const SPIRVTargetMachine &TM);
FunctionPass *createSPIRVLegalizePointerCastPass(SPIRVTargetMachine *TM);
@@ -57,7 +56,6 @@ void initializeSPIRVRegularizerPass(PassRegistry &);
void initializeSPIRVMergeRegionExitTargetsPass(PassRegistry &);
void initializeSPIRVPrepareFunctionsPass(PassRegistry &);
void initializeSPIRVPrepareGlobalsPass(PassRegistry &);
-void initializeSPIRVStripConvergentIntrinsicsPass(PassRegistry &);
void initializeSPIRVLegalizeImplicitBindingPass(PassRegistry &);
void initializeSPIRVLegalizeZeroSizeArraysLegacyPass(PassRegistry &);
void initializeSPIRVCtorDtorLoweringLegacyPass(PassRegistry &);
diff --git a/llvm/lib/Target/SPIRV/SPIRVStripConvergentIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVStripConvergentIntrinsics.cpp
deleted file mode 100644
index b1a8d1ab8a297..0000000000000
--- a/llvm/lib/Target/SPIRV/SPIRVStripConvergentIntrinsics.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-//===-- SPIRVStripConvergentIntrinsics.cpp ----------------------*- 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 trims convergence intrinsics as those were only useful when
-// modifying the CFG during IR passes.
-//
-//===----------------------------------------------------------------------===//
-
-#include "SPIRV.h"
-#include "SPIRVSubtarget.h"
-#include "SPIRVUtils.h"
-#include "llvm/IR/IntrinsicInst.h"
-#include "llvm/IR/Intrinsics.h"
-#include "llvm/Transforms/Utils/Cloning.h"
-#include "llvm/Transforms/Utils/LowerMemIntrinsics.h"
-
-using namespace llvm;
-
-namespace {
-class SPIRVStripConvergentIntrinsics : public FunctionPass {
-public:
- static char ID;
-
- SPIRVStripConvergentIntrinsics() : FunctionPass(ID) {}
-
- bool runOnFunction(Function &F) override {
- DenseSet<Instruction *> ToRemove;
-
- // Is the instruction is a convergent intrinsic, add it to kill-list and
- // returns true. Returns false otherwise.
- auto CleanupIntrinsic = [&](IntrinsicInst *II) {
- if (II->getIntrinsicID() != Intrinsic::experimental_convergence_entry &&
- II->getIntrinsicID() != Intrinsic::experimental_convergence_loop &&
- II->getIntrinsicID() != Intrinsic::experimental_convergence_anchor)
- return false;
-
- II->replaceAllUsesWith(UndefValue::get(II->getType()));
- ToRemove.insert(II);
- return true;
- };
-
- // Replace the given CallInst by a similar CallInst with no convergencectrl
- // attribute.
- auto CleanupCall = [&](CallInst *CI) {
- auto OB = CI->getOperandBundle(LLVMContext::OB_convergencectrl);
- if (!OB.has_value())
- return;
-
- auto *NewCall = CallBase::removeOperandBundle(
- CI, LLVMContext::OB_convergencectrl, CI->getIterator());
- NewCall->copyMetadata(*CI);
- CI->replaceAllUsesWith(NewCall);
- ToRemove.insert(CI);
- };
-
- for (BasicBlock &BB : F) {
- for (Instruction &I : BB) {
- if (auto *II = dyn_cast<IntrinsicInst>(&I))
- if (CleanupIntrinsic(II))
- continue;
- if (auto *CI = dyn_cast<CallInst>(&I))
- CleanupCall(CI);
- }
- }
-
- // All usages must be removed before their definition is removed.
- for (Instruction *I : ToRemove)
- I->eraseFromParent();
-
- return ToRemove.size() != 0;
- }
-};
-} // namespace
-
-char SPIRVStripConvergentIntrinsics::ID = 0;
-INITIALIZE_PASS(SPIRVStripConvergentIntrinsics, "strip-convergent-intrinsics",
- "SPIRV strip convergent intrinsics", false, false)
-
-FunctionPass *llvm::createSPIRVStripConvergenceIntrinsicsPass() {
- return new SPIRVStripConvergentIntrinsics();
-}
diff --git a/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp b/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp
index 6797722579137..24759b1e77d5f 100644
--- a/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp
@@ -66,7 +66,6 @@ extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSPIRVTarget() {
initializeSPIRVEmitNonSemanticDIPass(PR);
initializeSPIRVPrepareFunctionsPass(PR);
initializeSPIRVPrepareGlobalsPass(PR);
- initializeSPIRVStripConvergentIntrinsicsPass(PR);
initializeSPIRVCtorDtorLoweringLegacyPass(PR);
}
@@ -229,7 +228,7 @@ void SPIRVPassConfig::addISelPrepare() {
addPass(createLoopSimplifyPass());
}
SPIRVTargetMachine &TM = getTM<SPIRVTargetMachine>();
- addPass(createSPIRVStripConvergenceIntrinsicsPass());
+ addPass(createStripConvergenceIntrinsicsPass());
addPass(createSPIRVLegalizeImplicitBindingPass());
addPass(createSPIRVLegalizeZeroSizeArraysPass(TM));
addPass(createSPIRVCBufferAccessLegacyPass());
diff --git a/llvm/lib/Transforms/Utils/CMakeLists.txt b/llvm/lib/Transforms/Utils/CMakeLists.txt
index 2b5f5cf344e60..82e9edf674866 100644
--- a/llvm/lib/Transforms/Utils/CMakeLists.txt
+++ b/llvm/lib/Transforms/Utils/CMakeLists.txt
@@ -74,6 +74,7 @@ add_llvm_component_library(LLVMTransformUtils
RelLookupTableConverter.cpp
ScalarEvolutionExpander.cpp
SCCPSolver.cpp
+ StripConvergenceIntrinsics.cpp
StripGCRelocates.cpp
SSAUpdater.cpp
SSAUpdaterBulk.cpp
diff --git a/llvm/lib/Transforms/Utils/StripConvergenceIntrinsics.cpp b/llvm/lib/Transforms/Utils/StripConvergenceIntrinsics.cpp
new file mode 100644
index 0000000000000..667e23df667ee
--- /dev/null
+++ b/llvm/lib/Transforms/Utils/StripConvergenceIntrinsics.cpp
@@ -0,0 +1,99 @@
+//===----------------------------------------------------------------------===//
+//
+// 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();
+}
diff --git a/llvm/test/CodeGen/DirectX/llc-pipeline.ll b/llvm/test/CodeGen/DirectX/llc-pipeline.ll
index 586567ceb18ec..2474e08ac1549 100644
--- a/llvm/test/CodeGen/DirectX/llc-pipeline.ll
+++ b/llvm/test/CodeGen/DirectX/llc-pipeline.ll
@@ -14,6 +14,8 @@
; CHECK-OBJ-NEXT: Create Garbage Collector Module Metadata
; CHECK-NEXT: ModulePass Manager
+; CHECK-NEXT: FunctionPass Manager
+; CHECK-NEXT: Strip convergence intrinsics and operand bundles
; CHECK-NEXT: DXIL Finalize Linkage
; CHECK-NEXT: Dead Global Elimination
; CHECK-NEXT: DXIL Memory Intrinsic Elimination
diff --git a/llvm/test/CodeGen/DirectX/strip-convergence-intrinsics.ll b/llvm/test/CodeGen/DirectX/strip-convergence-intrinsics.ll
new file mode 100644
index 0000000000000..afd858ad4eec3
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/strip-convergence-intrinsics.ll
@@ -0,0 +1,38 @@
+; RUN: llc %s -mtriple=dxil-pc-shadermodel6.3-library -o - | FileCheck %s
+
+; Verify that convergence intrinsics and operand bundles are stripped
+; during DXIL lowering pipeline.
+
+; CHECK-LABEL: define float @test(
+; CHECK-NOT: convergence
+; CHECK: ret float
+
+; CHECK-LABEL: define void @test_loop(
+; CHECK-NOT: convergence
+; CHECK: ret void
+
+define float @test(float %a) convergent {
+entry:
+ %0 = call token @llvm.experimental.convergence.entry()
+ %1 = call float @llvm.dx.dot(float %a) [ "convergencectrl"(token %0) ]
+ ret float %1
+}
+
+define void @test_loop(float %a) convergent {
+entry:
+ %0 = call token @llvm.experimental.convergence.entry()
+ br label %loop
+
+loop:
+ %1 = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %0) ]
+ call void @convergent_callee() [ "convergencectrl"(token %1) ]
+ br i1 true, label %exit, label %loop
+
+exit:
+ ret void
+}
+
+declare void @convergent_callee() convergent
+declare float @llvm.dx.dot(float)
+declare token @llvm.experimental.convergence.entry()
+declare token @llvm.experimental.convergence.loop()
diff --git a/llvm/test/CodeGen/SPIRV/llc-pipeline.ll b/llvm/test/CodeGen/SPIRV/llc-pipeline.ll
index 2e83b3fe07d8b..6111bc22e8ed6 100644
--- a/llvm/test/CodeGen/SPIRV/llc-pipeline.ll
+++ b/llvm/test/CodeGen/SPIRV/llc-pipeline.ll
@@ -41,7 +41,7 @@
; SPIRV-O0-NEXT: Dominator Tree Construction
; SPIRV-O0-NEXT: Natural Loop Information
; SPIRV-O0-NEXT: Canonicalize natural loops
-; SPIRV-O0-NEXT: SPIRV strip convergent intrinsics
+; SPIRV-O0-NEXT: Strip convergence intrinsics and operand bundles
; SPIRV-O0-NEXT: SPIRV Legalize Implicit Binding
; SPIRV-O0-NEXT: SPIRV Legalize Zero-Size Arrays
; SPIRV-O0-NEXT: SPIRV CBuffer Access
@@ -156,7 +156,7 @@
; SPIRV-Opt-NEXT: Dominator Tree Construction
; SPIRV-Opt-NEXT: Natural Loop Information
; SPIRV-Opt-NEXT: Canonicalize natural loops
-; SPIRV-Opt-NEXT: SPIRV strip convergent intrinsics
+; SPIRV-Opt-NEXT: Strip convergence intrinsics and operand bundles
; SPIRV-Opt-NEXT: SPIRV Legalize Implicit Binding
; SPIRV-Opt-NEXT: SPIRV Legalize Zero-Size Arrays
; SPIRV-Opt-NEXT: SPIRV CBuffer Access
diff --git a/llvm/test/Transforms/StripConvergenceIntrinsics/basic.ll b/llvm/test/Transforms/StripConvergenceIntrinsics/basic.ll
new file mode 100644
index 0000000000000..62cd4739257ae
--- /dev/null
+++ b/llvm/test/Transforms/StripConvergenceIntrinsics/basic.ll
@@ -0,0 +1,79 @@
+; RUN: opt -passes=strip-convergence-intrinsics -S < %s | FileCheck %s
+
+; Verify that convergence intrinsics and convergencectrl operand bundles are
+; stripped by the pass.
+
+define void @entry_and_call() convergent {
+; CHECK-LABEL: define void @entry_and_call()
+; CHECK-NEXT: entry:
+; CHECK-NEXT: call void @convergent_callee()
+; CHECK-NOT: convergence
+; CHECK-NEXT: ret void
+entry:
+ %0 = call token @llvm.experimental.convergence.entry()
+ call void @convergent_callee() [ "convergencectrl"(token %0) ]
+ ret void
+}
+
+define void @loop_with_token() convergent {
+; CHECK-LABEL: define void @loop_with_token()
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br label %loop
+; CHECK: loop:
+; CHECK-NEXT: call void @convergent_callee()
+; CHECK-NOT: convergence
+; CHECK-NEXT: br i1
+entry:
+ %0 = call token @llvm.experimental.convergence.entry()
+ br label %loop
+
+loop:
+ %1 = call token @llvm.experimental.convergence.loop() [ "convergencectrl"(token %0) ]
+ call void @convergent_callee() [ "convergencectrl"(token %1) ]
+ br i1 true, label %exit, label %loop
+
+exit:
+ ret void
+}
+
+define void @anchor_token() convergent {
+; CHECK-LABEL: define void @anchor_token()
+; CHECK-NEXT: entry:
+; CHECK-NEXT: call void @convergent_callee()
+; CHECK-NOT: convergence
+; CHECK-NEXT: ret void
+entry:
+ %0 = call token @llvm.experimental.convergence.anchor()
+ call void @convergent_callee() [ "convergencectrl"(token %0) ]
+ ret void
+}
+
+; This ensures that when the use of a token is defined before the call that
+; creates the token, we are still able to strip them as expected.
+define void @reversed_block_order() convergent {
+; CHECK-LABEL: define void @reversed_block_order()
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br label %[[B:.*]]
+; CHECK: [[A:.*]]:
+; CHECK-NEXT: call void @convergent_callee()
+; CHECK-NEXT: ret void
+; CHECK: [[B]]:
+; CHECK-NEXT: br label %[[A]]
+entry:
+ br label %B
+A:
+ call void @convergent_callee() [ "convergencectrl"(token %tok) ]
+ ret void
+B:
+ %tok = call token @llvm.experimental.convergence.anchor()
+ br label %A
+}
+
+; Declarations may remain but should have no uses in function bodies.
+; CHECK-LABEL: declare void @convergent_callee
+
+declare void @convergent_callee() convergent
+
+declare token @llvm.experimental.convergence.entry()
+declare token @llvm.experimental.convergence.loop()
+declare token @llvm.experimental.convergence.anchor()
More information about the llvm-commits
mailing list