LLVM 23.0.0git
LoadStoreVec.cpp
Go to the documentation of this file.
1//===- LoadStoreVec.cpp - Vectorizer pass short load-store chains ---------===//
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
15
16namespace llvm {
17
18namespace sandboxir {
19
20std::optional<Type *> LoadStoreVec::canVectorize(ArrayRef<Instruction *> Bndl,
21 Scheduler &Sched) {
22 // TODO: Most of these checks are already implemented in LegalityAnalysis, we
23 // should reuse them.
24
25 // Check if in the same BB.
26 auto *BB = cast<Instruction>(Bndl[0])->getParent();
27 if (any_of(drop_begin(Bndl),
28 [BB](auto *V) { return cast<Instruction>(V)->getParent() != BB; }))
29 return std::nullopt;
30
31 // Check if instructions repeat.
32 SmallPtrSet<Value *, 8> Unique(Bndl.begin(), Bndl.end());
33 if (Unique.size() != Bndl.size())
34 return std::nullopt;
35
36 // TODO: This is target-dependent.
37 // Don't mix integer with floating point.
38 bool IsFloat = false;
39 bool IsInteger = false;
40 for ([[maybe_unused]] auto *I : Bndl) {
41 if (Utils::getExpectedType(I)->getScalarType()->isFloatingPointTy())
42 IsFloat = true;
43 else
44 IsInteger = true;
45 }
46 if (IsFloat && IsInteger)
47 return std::nullopt;
48
49 // Check scheduling.
50 if (!Sched.trySchedule(Bndl))
51 return std::nullopt;
52
53 return VecUtils::getCombinedVectorTypeFor(Bndl, *DL);
54}
55
56void LoadStoreVec::tryEraseDeadInstrs(ArrayRef<Instruction *> Stores,
58 SmallPtrSet<Instruction *, 8> DeadCandidates;
59 for (auto *SI : Stores) {
60 if (auto *PtrI =
62 DeadCandidates.insert(PtrI);
63 SI->eraseFromParent();
64 }
65 for (auto *LI : Loads) {
66 if (auto *PtrI =
68 DeadCandidates.insert(PtrI);
69 cast<LoadInst>(LI)->eraseFromParent();
70 }
71 for (auto *PtrI : DeadCandidates)
72 if (!PtrI->hasNUsesOrMore(1))
73 PtrI->eraseFromParent();
74}
75
77 SmallVector<Instruction *, 8> Bndl(Rgn.getAux().begin(), Rgn.getAux().end());
78 if (Bndl.size() < 2)
79 return false;
80 Function &F = *Bndl[0]->getParent()->getParent();
81 DL = &F.getParent()->getDataLayout();
82 auto &Ctx = F.getContext();
83 Scheduler Sched(A.getAA(), Ctx);
85 Bndl, A.getScalarEvolution(), *DL))
86 return false;
87 if (!canVectorize(Bndl, Sched))
88 return false;
89
91 Operands.reserve(Bndl.size());
92 for (auto *I : Bndl) {
93 auto *Op = cast<StoreInst>(I)->getValueOperand();
94 Operands.push_back(Op);
95 }
96 BasicBlock *BB = Bndl[0]->getParent();
97 // TODO: For now we only support load operands.
98 // TODO: For now we don't cross BBs.
99 // TODO: For now don't vectorize if the loads have external uses.
100 if (!all_of(Operands, [BB](Value *V) {
101 auto *LI = dyn_cast<LoadInst>(V);
102 if (LI == nullptr)
103 return false;
104 if (LI->getParent() != BB)
105 return false;
106 if (LI->hasNUsesOrMore(2))
107 return false;
108 return true;
109 }))
110 return false;
111 // TODO: Try to avoid the extra copy to an instruction vector.
113 Loads.reserve(Operands.size());
114 for (Value *Op : Operands)
116
118 Loads, A.getScalarEvolution(), *DL);
119 if (!Consecutive)
120 return false;
121 if (!canVectorize(Loads, Sched))
122 return false;
123
124 // Generate vector store and vector load
126 Value *LdPtr = cast<LoadInst>(Loads[0])->getPointerOperand();
127 // TODO: Compute alignment.
128 Align LdAlign(1);
129 auto LdWhereIt = std::next(VecUtils::getLowest(Loads)->getIterator());
130 auto *VecLd =
131 LoadInst::create(Ty, LdPtr, LdAlign, LdWhereIt, Ctx, "VecIinitL");
132
133 Value *StPtr = cast<StoreInst>(Bndl[0])->getPointerOperand();
134 // TODO: Compute alignment.
135 Align StAlign(1);
136 auto StWhereIt = std::next(VecUtils::getLowest(Bndl)->getIterator());
137 StoreInst::create(VecLd, StPtr, StAlign, StWhereIt, Ctx);
138
139 tryEraseDeadInstrs(Bndl, Loads);
140 return true;
141}
142
143} // namespace sandboxir
144
145} // namespace llvm
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
void reserve(size_type N)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
static LLVM_ABI LoadInst * create(Type *Ty, Value *Ptr, MaybeAlign Align, InsertPosition Pos, bool IsVolatile, Context &Ctx, const Twine &Name="")
bool runOnRegion(Region &Rgn, const Analyses &A) final
\Returns true if it modifies R.
The main job of the Region is to point to new instructions generated by vectorization passes.
Definition Region.h:96
const SmallVector< Instruction * > & getAux() const
\Returns the auxiliary vector.
Definition Region.h:156
The list scheduler.
Definition Scheduler.h:163
static LLVM_ABI StoreInst * create(Value *V, Value *Ptr, MaybeAlign Align, InsertPosition Pos, bool IsVolatile, Context &Ctx)
Just like llvm::Type these are immutable, unique, never get freed and can only be created via static ...
Definition Type.h:47
static Type * getExpectedType(const Value *V)
\Returns the expected type of Value V.
Definition Utils.h:32
A SandboxIR Value has users. This is the base class.
Definition Value.h:68
static Instruction * getLowest(ArrayRef< Instruction * > Instrs)
\Returns the instruction in Instrs that is lowest in the BB.
Definition VecUtils.h:147
static Type * getCombinedVectorTypeFor(ArrayRef< Instruction * > Bndl, const DataLayout &DL)
\Returns the combined vector type for Bndl, even when the element types differ.
Definition VecUtils.h:126
static bool areConsecutive(LoadOrStoreT *I1, LoadOrStoreT *I2, ScalarEvolution &SE, const DataLayout &DL)
\Returns true if I1 and I2 are load/stores accessing consecutive memory addresses.
Definition VecUtils.h:59
BasicBlock(llvm::BasicBlock *BB, Context &SBCtx)
Definition BasicBlock.h:75
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition STLExtras.h:316
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1739
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
const Value * getPointerOperand(const Value *V)
A helper function that returns the pointer operand of a load, store or GEP instruction.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1746
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39