LLVM 24.0.0git
SPIRVRegularizer.cpp
Go to the documentation of this file.
1//===-- SPIRVRegularizer.cpp - regularize IR for SPIR-V ---------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This pass implements regularization of LLVM IR for SPIR-V. The prototype of
10// the pass was taken from SPIRV-LLVM translator.
11//
12//===----------------------------------------------------------------------===//
13
14#include "SPIRV.h"
15#include "llvm/ADT/STLExtras.h"
16#include "llvm/IR/Constants.h"
17#include "llvm/IR/IRBuilder.h"
20#include "llvm/IR/PassManager.h"
21
22#include <list>
23
24#define DEBUG_TYPE "spirv-regularizer"
25
26using namespace llvm;
27
28static bool runImpl(Function &F);
29
30namespace {
31struct SPIRVRegularizerLegacy : public FunctionPass {
32public:
33 static char ID;
34 SPIRVRegularizerLegacy() : FunctionPass(ID) {}
35 bool runOnFunction(Function &F) override { return runImpl(F); }
36 StringRef getPassName() const override { return "SPIR-V Regularizer"; }
37
38 void getAnalysisUsage(AnalysisUsage &AU) const override {
39 FunctionPass::getAnalysisUsage(AU);
40 }
41};
42} // namespace
43
44char SPIRVRegularizerLegacy::ID = 0;
45
46INITIALIZE_PASS(SPIRVRegularizerLegacy, DEBUG_TYPE, "SPIR-V Regularizer", false,
47 false)
48
49// Since SPIR-V cannot represent constant expression, constant expressions
50// in LLVM IR need to be lowered to instructions. For each function,
51// the constant expressions used by instructions of the function are replaced
52// by instructions placed in the entry block since it dominates all other BBs.
53// Each constant expression only needs to be lowered once in each function
54// and all uses of it by instructions in that function are replaced by
55// one instruction.
56// TODO: remove redundant instructions for common subexpression.
57static void runLowerConstExpr(Function &F) {
58 LLVMContext &Ctx = F.getContext();
59 std::list<Instruction *> WorkList;
60 for (auto &II : instructions(F))
61 WorkList.push_back(&II);
62
63 auto FBegin = F.begin();
64 while (!WorkList.empty()) {
65 Instruction *II = WorkList.front();
66
67 auto LowerOp = [&II, &FBegin, &F](Value *V) -> Value * {
68 if (isa<Function>(V))
69 return V;
70 auto *CE = cast<ConstantExpr>(V);
71 LLVM_DEBUG(dbgs() << "[lowerConstantExpressions] " << *CE);
72 auto ReplInst = CE->getAsInstruction();
73 auto InsPoint = II->getParent() == &*FBegin ? II : &FBegin->back();
74 ReplInst->insertBefore(InsPoint->getIterator());
75 LLVM_DEBUG(dbgs() << " -> " << *ReplInst << '\n');
76 std::vector<Instruction *> Users;
77 // Do not replace use during iteration of use. Do it in another loop.
78 for (auto U : CE->users()) {
79 LLVM_DEBUG(dbgs() << "[lowerConstantExpressions] Use: " << *U << '\n');
80 auto InstUser = dyn_cast<Instruction>(U);
81 // Only replace users in scope of current function.
82 if (InstUser && InstUser->getParent()->getParent() == &F)
83 Users.push_back(InstUser);
84 }
85 for (auto &User : Users) {
86 if (ReplInst->getParent() == User->getParent() &&
87 User->comesBefore(ReplInst))
88 ReplInst->moveBefore(User->getIterator());
89 User->replaceUsesOfWith(CE, ReplInst);
90 }
91 return ReplInst;
92 };
93
94 WorkList.pop_front();
95 for (unsigned OI = 0, OE = II->getNumOperands(); OI != OE; ++OI) {
96 auto *Op = II->getOperand(OI);
97 if (auto CE = dyn_cast<ConstantExpr>(Op)) {
98 WorkList.push_front(cast<Instruction>(LowerOp(CE)));
99 } else if (auto MDAsVal = dyn_cast<MetadataAsValue>(Op)) {
100 auto ConstMD = dyn_cast<ConstantAsMetadata>(MDAsVal->getMetadata());
101 if (!ConstMD)
102 continue;
103 Constant *C = ConstMD->getValue();
104 auto *CE = dyn_cast<ConstantExpr>(C);
105 if (!CE)
106 continue;
107 Value *ReplInst = LowerOp(CE);
108 Metadata *RepMD = ValueAsMetadata::get(ReplInst);
109 Value *RepMDVal = MetadataAsValue::get(Ctx, RepMD);
110 II->setOperand(OI, RepMDVal);
111 WorkList.push_front(cast<Instruction>(ReplInst));
112 }
113 }
114 }
115}
116
117// Lower i1 comparisons with certain predicates to logical operations.
118// The backend treats i1 as boolean values, and SPIR-V only allows logical
119// operations for boolean values. This function lowers i1 comparisons with
120// certain predicates to logical operations to generate valid SPIR-V.
122 for (auto &I : make_early_inc_range(instructions(F))) {
123 auto *Cmp = dyn_cast<ICmpInst>(&I);
124 if (!Cmp)
125 continue;
126
127 bool IsI1 = Cmp->getOperand(0)->getType()->getScalarType()->isIntegerTy(1);
128 if (!IsI1)
129 continue;
130
131 auto Pred = Cmp->getPredicate();
132 bool IsTargetPred =
133 Pred >= ICmpInst::ICMP_UGT && Pred <= ICmpInst::ICMP_SLE;
134 if (!IsTargetPred)
135 continue;
136
137 Value *P = Cmp->getOperand(0);
138 Value *Q = Cmp->getOperand(1);
139
140 IRBuilder<> Builder(Cmp);
141 Value *Result = nullptr;
142 switch (Pred) {
145 // Result = p & !q
146 Result = Builder.CreateAnd(P, Builder.CreateNot(Q));
147 break;
150 // Result = q & !p
151 Result = Builder.CreateAnd(Q, Builder.CreateNot(P));
152 break;
155 // Result = q | !p
156 Result = Builder.CreateOr(Q, Builder.CreateNot(P));
157 break;
160 // Result = p | !q
161 Result = Builder.CreateOr(P, Builder.CreateNot(Q));
162 break;
163 default:
164 llvm_unreachable("Unexpected predicate");
165 }
166
167 Result->takeName(Cmp);
168 Cmp->replaceAllUsesWith(Result);
169 Cmp->eraseFromParent();
170 }
171}
172
173static bool runImpl(Function &F) {
175 runLowerConstExpr(F);
176 return true;
177}
178
183
185 return new SPIRVRegularizerLegacy();
186}
for(const MachineOperand &MO :llvm::drop_begin(OldMI.operands(), Desc.getNumOperands()))
Expand Atomic instructions
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static bool runImpl(MachineFunction &MF)
Definition CFIFixup.cpp:304
This file contains the declarations for the subclasses of Constant, which represent the different fla...
static bool runOnFunction(Function &F, bool PostInlining)
#define DEBUG_TYPE
This header defines various interfaces for pass management in LLVM.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
uint64_t IntrinsicInst * II
#define P(N)
if(PassOpts->AAPipeline)
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
static void runLowerI1Comparisons(Function &F)
static bool runImpl(Function &F)
This file contains some templates that are useful if you are working with the STL at all.
@ ICMP_SLT
signed less than
Definition InstrTypes.h:769
@ ICMP_SLE
signed less or equal
Definition InstrTypes.h:770
@ ICMP_UGE
unsigned greater or equal
Definition InstrTypes.h:764
@ ICMP_UGT
unsigned greater than
Definition InstrTypes.h:763
@ ICMP_SGT
signed greater than
Definition InstrTypes.h:767
@ ICMP_ULT
unsigned less than
Definition InstrTypes.h:765
@ ICMP_SGE
signed greater or equal
Definition InstrTypes.h:768
@ ICMP_ULE
unsigned less or equal
Definition InstrTypes.h:766
This is an important base class in LLVM.
Definition Constant.h:43
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2908
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:68
static LLVM_ABI MetadataAsValue * get(LLVMContext &Context, Metadata *MD)
Definition Metadata.cpp:107
Root of the metadata hierarchy.
Definition Metadata.h:64
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition Analysis.h:115
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
static LLVM_ABI ValueAsMetadata * get(Value *V)
Definition Metadata.cpp:514
LLVM Value Representation.
Definition Value.h:75
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition STLExtras.h:649
FunctionPass * createSPIRVRegularizerPass()
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.