xref: /freebsd/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVStripConvergentIntrinsics.cpp (revision 7a6dacaca14b62ca4b74406814becb87a3fefac0)
1*7a6dacacSDimitry Andric //===-- SPIRVStripConvergentIntrinsics.cpp ----------------------*- C++ -*-===//
2*7a6dacacSDimitry Andric //
3*7a6dacacSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*7a6dacacSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*7a6dacacSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*7a6dacacSDimitry Andric //
7*7a6dacacSDimitry Andric //===----------------------------------------------------------------------===//
8*7a6dacacSDimitry Andric //
9*7a6dacacSDimitry Andric // This pass trims convergence intrinsics as those were only useful when
10*7a6dacacSDimitry Andric // modifying the CFG during IR passes.
11*7a6dacacSDimitry Andric //
12*7a6dacacSDimitry Andric //===----------------------------------------------------------------------===//
13*7a6dacacSDimitry Andric 
14*7a6dacacSDimitry Andric #include "SPIRV.h"
15*7a6dacacSDimitry Andric #include "SPIRVSubtarget.h"
16*7a6dacacSDimitry Andric #include "SPIRVTargetMachine.h"
17*7a6dacacSDimitry Andric #include "SPIRVUtils.h"
18*7a6dacacSDimitry Andric #include "llvm/CodeGen/IntrinsicLowering.h"
19*7a6dacacSDimitry Andric #include "llvm/IR/IRBuilder.h"
20*7a6dacacSDimitry Andric #include "llvm/IR/IntrinsicInst.h"
21*7a6dacacSDimitry Andric #include "llvm/IR/Intrinsics.h"
22*7a6dacacSDimitry Andric #include "llvm/IR/IntrinsicsSPIRV.h"
23*7a6dacacSDimitry Andric #include "llvm/Transforms/Utils/Cloning.h"
24*7a6dacacSDimitry Andric #include "llvm/Transforms/Utils/LowerMemIntrinsics.h"
25*7a6dacacSDimitry Andric 
26*7a6dacacSDimitry Andric using namespace llvm;
27*7a6dacacSDimitry Andric 
28*7a6dacacSDimitry Andric namespace llvm {
29*7a6dacacSDimitry Andric void initializeSPIRVStripConvergentIntrinsicsPass(PassRegistry &);
30*7a6dacacSDimitry Andric }
31*7a6dacacSDimitry Andric 
32*7a6dacacSDimitry Andric class SPIRVStripConvergentIntrinsics : public FunctionPass {
33*7a6dacacSDimitry Andric public:
34*7a6dacacSDimitry Andric   static char ID;
35*7a6dacacSDimitry Andric 
36*7a6dacacSDimitry Andric   SPIRVStripConvergentIntrinsics() : FunctionPass(ID) {
37*7a6dacacSDimitry Andric     initializeSPIRVStripConvergentIntrinsicsPass(
38*7a6dacacSDimitry Andric         *PassRegistry::getPassRegistry());
39*7a6dacacSDimitry Andric   };
40*7a6dacacSDimitry Andric 
41*7a6dacacSDimitry Andric   virtual bool runOnFunction(Function &F) override {
42*7a6dacacSDimitry Andric     DenseSet<Instruction *> ToRemove;
43*7a6dacacSDimitry Andric 
44*7a6dacacSDimitry Andric     for (BasicBlock &BB : F) {
45*7a6dacacSDimitry Andric       for (Instruction &I : BB) {
46*7a6dacacSDimitry Andric         if (auto *II = dyn_cast<IntrinsicInst>(&I)) {
47*7a6dacacSDimitry Andric           if (II->getIntrinsicID() !=
48*7a6dacacSDimitry Andric                   Intrinsic::experimental_convergence_entry &&
49*7a6dacacSDimitry Andric               II->getIntrinsicID() !=
50*7a6dacacSDimitry Andric                   Intrinsic::experimental_convergence_loop &&
51*7a6dacacSDimitry Andric               II->getIntrinsicID() !=
52*7a6dacacSDimitry Andric                   Intrinsic::experimental_convergence_anchor) {
53*7a6dacacSDimitry Andric             continue;
54*7a6dacacSDimitry Andric           }
55*7a6dacacSDimitry Andric 
56*7a6dacacSDimitry Andric           II->replaceAllUsesWith(UndefValue::get(II->getType()));
57*7a6dacacSDimitry Andric           ToRemove.insert(II);
58*7a6dacacSDimitry Andric         } else if (auto *CI = dyn_cast<CallInst>(&I)) {
59*7a6dacacSDimitry Andric           auto OB = CI->getOperandBundle(LLVMContext::OB_convergencectrl);
60*7a6dacacSDimitry Andric           if (!OB.has_value())
61*7a6dacacSDimitry Andric             continue;
62*7a6dacacSDimitry Andric 
63*7a6dacacSDimitry Andric           auto *NewCall = CallBase::removeOperandBundle(
64*7a6dacacSDimitry Andric               CI, LLVMContext::OB_convergencectrl, CI);
65*7a6dacacSDimitry Andric           NewCall->copyMetadata(*CI);
66*7a6dacacSDimitry Andric           CI->replaceAllUsesWith(NewCall);
67*7a6dacacSDimitry Andric           ToRemove.insert(CI);
68*7a6dacacSDimitry Andric         }
69*7a6dacacSDimitry Andric       }
70*7a6dacacSDimitry Andric     }
71*7a6dacacSDimitry Andric 
72*7a6dacacSDimitry Andric     // All usages must be removed before their definition is removed.
73*7a6dacacSDimitry Andric     for (Instruction *I : ToRemove)
74*7a6dacacSDimitry Andric       I->eraseFromParent();
75*7a6dacacSDimitry Andric 
76*7a6dacacSDimitry Andric     return ToRemove.size() != 0;
77*7a6dacacSDimitry Andric   }
78*7a6dacacSDimitry Andric };
79*7a6dacacSDimitry Andric 
80*7a6dacacSDimitry Andric char SPIRVStripConvergentIntrinsics::ID = 0;
81*7a6dacacSDimitry Andric INITIALIZE_PASS(SPIRVStripConvergentIntrinsics, "strip-convergent-intrinsics",
82*7a6dacacSDimitry Andric                 "SPIRV strip convergent intrinsics", false, false)
83*7a6dacacSDimitry Andric 
84*7a6dacacSDimitry Andric FunctionPass *llvm::createSPIRVStripConvergenceIntrinsicsPass() {
85*7a6dacacSDimitry Andric   return new SPIRVStripConvergentIntrinsics();
86*7a6dacacSDimitry Andric }
87