[NFC][SPIRV] Move SPIRVStripConvergenceIntrinsics to Utils#188537
Conversation
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
|
✅ With the latest revision this PR passed the undef deprecator. |
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 we can move the pass to a common place. Enables the pass for targeting DirectX and is a pre-req for: TODO.
by going in reverse order we remove the need to create a temporary undef value
b30f58c to
ad43112
Compare
|
@llvm/pr-subscribers-llvm-transforms @llvm/pr-subscribers-backend-directx Author: Finn Plummer (inbelic) ChangesThe The previous pass used temporary Enables the pass for targeting DirectX and is a pre-req for: #188792. Assisted by: Github Copilot Patch is 20.42 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/188537.diff 16 Files Affected:
diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h
index 48e4ecd8ee2af..4a566eed16e32 100644
--- a/llvm/include/llvm/InitializePasses.h
+++ b/llvm/include/llvm/InitializePasses.h
@@ -324,6 +324,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 a23d64b491a79..379aea8e07c8b 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 c92d93d7ae396..82f73faefb624 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -543,6 +543,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..23bd820883b92 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 {
@@ -125,6 +127,7 @@ class DirectXPassConfig : public TargetPassConfig {
addPass(createDeadStoreEliminationPass());
addPass(createDXILLegalizeLegacyPass());
addPass(createDXILResourceImplicitBindingLegacyPass());
+ addPass(createStripConvergenceIntrinsicsPass());
addPass(createDXILTranslateMetadataLegacyPass());
addPass(createDXILPostOptimizationValidationLegacyPass());
addPass(createDXILOpLoweringLegacyPass());
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 061bfc21bc447..cb3e46a0b5ce0 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);
}
@@ -225,7 +224,7 @@ void SPIRVPassConfig::addISelPrepare() {
addPass(createPromoteMemoryToRegisterPass());
}
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..84ef3e6f48a5d
--- /dev/null
+++ b/llvm/lib/Transforms/Utils/StripConvergenceIntrinsics.cpp
@@ -0,0 +1,89 @@
+//===----------------------------------------------------------------------===//
+//
+// 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/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) {
+ bool Changed = false;
+
+ // Iterate in reverse order so that uses of convergence tokens are removed
+ // before the convergence intrinsics that define them.
+ for (BasicBlock &BB : reverse(F)) {
+ for (Instruction &I : make_early_inc_range(reverse(BB))) {
+ if (auto *II = dyn_cast<IntrinsicInst>(&I)) {
+ if (II->getIntrinsicID() == Intrinsic::experimental_convergence_entry ||
+ II->getIntrinsicID() == Intrinsic::experimental_convergence_loop ||
+ II->getIntrinsicID() ==
+ Intrinsic::experimental_convergence_anchor) {
+ II->eraseFromParent();
+ Changed = true;
+ continue;
+ }
+ }
+ if (auto *CI = dyn_cast<CallInst>(&I)) {
+ auto OB = CI->getOperandBundle(LLVMContext::OB_convergencectrl);
+ if (!OB.has_value())
+ continue;
+ auto *NewCall = CallBase::removeOperandBundle(
+ CI, LLVMContext::OB_convergencectrl, CI->getIterator());
+ NewCall->copyMetadata(*CI);
+ CI->replaceAllUsesWith(NewCall);
+ CI->eraseFromParent();
+ Changed = true;
+ }
+ }
+ }
+
+ return Changed;
+}
+
+PreservedAnalyses
+StripConvergenceIntrinsicsPass::run(Function &F, FunctionAnalysisManager &) {
+ if (!stripConvergenceIntrinsics(F))
+ return PreservedAnalyses::all();
+ return PreservedAnalyses::none();
+}
+
+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..04e0194690e73 100644
--- a/llvm/test/CodeGen/DirectX/llc-pipeline.ll
+++ b/llvm/test/CodeGen/DirectX/llc-pipeline.ll
@@ -39,11 +39,14 @@
; CHECK-NEXT: DXIL Legalizer
; CHECK-NEXT: DXIL Resource Binding Analysis
; CHECK-NEXT: DXIL Resource Implicit Binding
+; CHECK-NEXT: FunctionPass Manager
+; CHECK-NEXT: Strip convergence intrinsics and operand bundles
; CHECK-NEXT: DXIL Resources Analysis
; CHECK-NEXT: DXIL Module Metadata analysis
; CHECK-NEXT: DXIL Shader Flag Analysis
; CHECK-NEXT: DXIL Root Signature Analysis
; CHECK-NEXT: DXIL Translate Metadata
+; CHECK-NEXT: DXIL Resource Binding Analysis
; CHECK-NEXT: DXIL Post Optimization Validation
; CHECK-NEXT: DXIL Op Lowering
; CHECK-NEXT: DXIL Prepare Module
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 3b256f1a3a2dc..81b12caeddec1 100644
--- a/llvm/test/CodeGen/SPIRV/llc-pipeline.ll
+++ b/llvm/test/CodeGen/SPIRV/llc-pipeline.ll
@@ -40,7 +40,7 @@
; SPIRV-O0-NEXT: FunctionPass Manager
; SPIRV-O0-NEXT: Lower invoke and unwind, for unwindless code generators
; SPIRV-O0-NEXT: Remove unreachable blocks from the CFG
-; 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
@@ -154,7 +154,7 @@
; SPIRV-Opt-NEXT: CodeGen Prepare
; SPIRV-Opt-NEXT: Lower invoke and unwind, for unwindless code generators
; SPIRV-Opt-NEXT: Remove unreachable blocks from the CFG
-; 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..e233075fce2ed
--- /dev/null
+++ b/llvm/test/Transforms/StripConvergenceIntrinsics/basic.ll
@@ -0,0 +1,58 @@
+; 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.convergenc...
[truncated]
|
There was a problem hiding this comment.
LGTM! Left a question about the position of the convergence strip pass in the pipeline.
One thing I've been thinking about, though I don't think it needs to be addressed in this PR: do we have a sense of the impact this change has on compilation times and binary sizes for targets other than DirectX and SPIRV?
The goal of sharing this pass between the two targets makes total sense — but I wonder if Transforms/Utils is the right home for it, given that convergence intrinsics are a GPU/shader-specific concept. Would something like a dedicated Transforms/GPU/ (or similar) be worth exploring as a place to share passes that are meaningful to GPU targets like SPIRV and DirectX, without pulling them into every LLVM build?
Happy to discuss further in a follow-up issue if others think it's worth exploring. Not a blocker at all!
| II->getIntrinsicID() == Intrinsic::experimental_convergence_loop || | ||
| II->getIntrinsicID() == | ||
| Intrinsic::experimental_convergence_anchor) { | ||
| II->eraseFromParent(); |
There was a problem hiding this comment.
One thing that is logically different in this path compared to the spirv logic is that there is no:
II->replaceAllUsesWith(UndefValue::get(II->getType())); statement in the IntrinsicInst case.
Is this intentional?
There was a problem hiding this comment.
Correct, when copying over the use of undef I hit the following: #188537 (comment) (click the see edit panel). So I thought, if it is easy to do, we should remove the use of undef now that it is deprecated.
The convergence control tokens are not necessarily bound to gpu use-cases, it could be used for modelling threads (or otherwise) so I think utils is fine |
|
|
| return PreservedAnalyses::all(); | ||
| return PreservedAnalyses::none(); |
There was a problem hiding this comment.
I think this pass preserves almost all analysis:
- loop analysis is ok
- CFG, domtree, etc
| ; Verify that convergence intrinsics and convergencectrl operand bundles are | ||
| ; stripped by the pass. | ||
|
|
||
| define void @entry_and_call() convergent { |
There was a problem hiding this comment.
You should add the test Deric mentioned: a block following a block it dominates in the CFG with intrinsincs to cleanup.
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/123/builds/38709 Here is the relevant piece of the build log for the reference |
…8537) 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: llvm#188792. Assisted by: Github Copilot
#188792) This pr allows codegen to generate convergence control tokens. This allows for a more accurate description of convergence behaviour to prevent (or allow) invalid control flow graph transforms. As noted, the use of convergence control tokens is the ideal norm and this follows that by enabling it for `DirectX`. This was done now under the precedent of preventing a convergent exit condition of a loop from being illegally moved across control flow. Test cases for this are explicitly added. Please see the individual commits for logically similar chunks. Unfortunately, it is tricky to stage this in smaller individual commits. Resolves #180621. #188537 is a pre-requisite of this passing HLSL offload suite tests. Assisted by: Github Copilot
…ting DirectX (#188792) This pr allows codegen to generate convergence control tokens. This allows for a more accurate description of convergence behaviour to prevent (or allow) invalid control flow graph transforms. As noted, the use of convergence control tokens is the ideal norm and this follows that by enabling it for `DirectX`. This was done now under the precedent of preventing a convergent exit condition of a loop from being illegally moved across control flow. Test cases for this are explicitly added. Please see the individual commits for logically similar chunks. Unfortunately, it is tricky to stage this in smaller individual commits. Resolves llvm/llvm-project#180621. llvm/llvm-project#188537 is a pre-requisite of this passing HLSL offload suite tests. Assisted by: Github Copilot
…ting DirectX (#188792) This pr allows codegen to generate convergence control tokens. This allows for a more accurate description of convergence behaviour to prevent (or allow) invalid control flow graph transforms. As noted, the use of convergence control tokens is the ideal norm and this follows that by enabling it for `DirectX`. This was done now under the precedent of preventing a convergent exit condition of a loop from being illegally moved across control flow. Test cases for this are explicitly added. Please see the individual commits for logically similar chunks. Unfortunately, it is tricky to stage this in smaller individual commits. Resolves llvm/llvm-project#180621. llvm/llvm-project#188537 is a pre-requisite of this passing HLSL offload suite tests. Assisted by: Github Copilot
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/114/builds/453 Here is the relevant piece of the build log for the reference |
llvm#188792) This pr allows codegen to generate convergence control tokens. This allows for a more accurate description of convergence behaviour to prevent (or allow) invalid control flow graph transforms. As noted, the use of convergence control tokens is the ideal norm and this follows that by enabling it for `DirectX`. This was done now under the precedent of preventing a convergent exit condition of a loop from being illegally moved across control flow. Test cases for this are explicitly added. Please see the individual commits for logically similar chunks. Unfortunately, it is tricky to stage this in smaller individual commits. Resolves llvm#180621. llvm#188537 is a pre-requisite of this passing HLSL offload suite tests. Assisted by: Github Copilot
…ting DirectX (#188792) This pr allows codegen to generate convergence control tokens. This allows for a more accurate description of convergence behaviour to prevent (or allow) invalid control flow graph transforms. As noted, the use of convergence control tokens is the ideal norm and this follows that by enabling it for `DirectX`. This was done now under the precedent of preventing a convergent exit condition of a loop from being illegally moved across control flow. Test cases for this are explicitly added. Please see the individual commits for logically similar chunks. Unfortunately, it is tricky to stage this in smaller individual commits. Resolves llvm/llvm-project#180621. llvm/llvm-project#188537 is a pre-requisite of this passing HLSL offload suite tests. Assisted by: Github Copilot
llvm#188792) This pr allows codegen to generate convergence control tokens. This allows for a more accurate description of convergence behaviour to prevent (or allow) invalid control flow graph transforms. As noted, the use of convergence control tokens is the ideal norm and this follows that by enabling it for `DirectX`. This was done now under the precedent of preventing a convergent exit condition of a loop from being illegally moved across control flow. Test cases for this are explicitly added. Please see the individual commits for logically similar chunks. Unfortunately, it is tricky to stage this in smaller individual commits. Resolves llvm#180621. llvm#188537 is a pre-requisite of this passing HLSL offload suite tests. Assisted by: Github Copilot
The
SPIRVStripConvergenceIntrinsicpass 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
Undefs, as part of moving the pass we can simply reverse the traverse order to remove the use ofUndefas it is deprecated.Enables the pass for targeting DirectX and is a pre-req for: #188792.
Assisted by: Github Copilot