xref: /freebsd/contrib/llvm-project/llvm/include/llvm/CodeGen/GlobalISel/LoadStoreOpt.h (revision 5678d1d98a348f315453555377ccb28821a2ffcd)
1 //== llvm/CodeGen/GlobalISel/LoadStoreOpt.h - LoadStoreOpt -------*- 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 is an optimization pass for GlobalISel generic memory operations.
10 /// Specifically, it focuses on merging stores and loads to consecutive
11 /// addresses.
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_CODEGEN_GLOBALISEL_LOADSTOREOPT_H
15 #define LLVM_CODEGEN_GLOBALISEL_LOADSTOREOPT_H
16 
17 #include "llvm/ADT/BitVector.h"
18 #include "llvm/ADT/SmallPtrSet.h"
19 #include "llvm/ADT/SmallSet.h"
20 #include "llvm/ADT/SmallVector.h"
21 #include "llvm/Analysis/AliasAnalysis.h"
22 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
23 #include "llvm/CodeGen/MachineFunction.h"
24 #include "llvm/CodeGen/MachineFunctionPass.h"
25 
26 namespace llvm {
27 // Forward declarations.
28 class AnalysisUsage;
29 class GStore;
30 class LegalizerInfo;
31 class MachineBasicBlock;
32 class MachineInstr;
33 class TargetLowering;
34 struct LegalityQuery;
35 class MachineRegisterInfo;
36 namespace GISelAddressing {
37 /// Helper struct to store a base, index and offset that forms an address
38 class BaseIndexOffset {
39 private:
40   Register BaseReg;
41   Register IndexReg;
42   std::optional<int64_t> Offset;
43 
44 public:
45   BaseIndexOffset() = default;
46   Register getBase() { return BaseReg; }
47   Register getBase() const { return BaseReg; }
48   Register getIndex() { return IndexReg; }
49   Register getIndex() const { return IndexReg; }
50   void setBase(Register NewBase) { BaseReg = NewBase; }
51   void setIndex(Register NewIndex) { IndexReg = NewIndex; }
52   void setOffset(std::optional<int64_t> NewOff) { Offset = NewOff; }
53   bool hasValidOffset() const { return Offset.has_value(); }
54   int64_t getOffset() const { return *Offset; }
55 };
56 
57 /// Returns a BaseIndexOffset which describes the pointer in \p Ptr.
58 BaseIndexOffset getPointerInfo(Register Ptr, MachineRegisterInfo &MRI);
59 
60 /// Compute whether or not a memory access at \p MI1 aliases with an access at
61 /// \p MI2 \returns true if either alias/no-alias is known. Sets \p IsAlias
62 /// accordingly.
63 bool aliasIsKnownForLoadStore(const MachineInstr &MI1, const MachineInstr &MI2,
64                               bool &IsAlias, MachineRegisterInfo &MRI);
65 
66 /// Returns true if the instruction \p MI may alias \p Other.
67 /// This function uses multiple strategies to detect aliasing, whereas
68 /// aliasIsKnownForLoadStore just looks at the addresses of load/stores and is
69 /// tries to reason about base/index/offsets.
70 bool instMayAlias(const MachineInstr &MI, const MachineInstr &Other,
71                   MachineRegisterInfo &MRI, AliasAnalysis *AA);
72 } // namespace GISelAddressing
73 
74 using namespace GISelAddressing;
75 
76 class LoadStoreOpt : public MachineFunctionPass {
77 public:
78   static char ID;
79 
80 private:
81   /// An input function to decide if the pass should run or not
82   /// on the given MachineFunction.
83   std::function<bool(const MachineFunction &)> DoNotRunPass;
84 
85   MachineRegisterInfo *MRI = nullptr;
86   const TargetLowering *TLI = nullptr;
87   MachineFunction *MF = nullptr;
88   AliasAnalysis *AA = nullptr;
89   const LegalizerInfo *LI = nullptr;
90 
91   MachineIRBuilder Builder;
92 
93   /// Initialize the field members using \p MF.
94   void init(MachineFunction &MF);
95 
96   class StoreMergeCandidate {
97   public:
98     // The base pointer used as the base for all stores in this candidate.
99     Register BasePtr;
100     // Our algorithm is very simple at the moment. We assume that in instruction
101     // order stores are writing to incremeneting consecutive addresses. So when
102     // we walk the block in reverse order, the next eligible store must write to
103     // an offset one store width lower than CurrentLowestOffset.
104     int64_t CurrentLowestOffset;
105     SmallVector<GStore *> Stores;
106     // A vector of MachineInstr/unsigned pairs to denote potential aliases that
107     // need to be checked before the candidate is considered safe to merge. The
108     // unsigned value is an index into the Stores vector. The indexed store is
109     // the highest-indexed store that has already been checked to not have an
110     // alias with the instruction. We record this so we don't have to repeat
111     // alias checks that have been already done, only those with stores added
112     // after the potential alias is recorded.
113     SmallVector<std::pair<MachineInstr *, unsigned>> PotentialAliases;
114 
115     void addPotentialAlias(MachineInstr &MI);
116 
117     /// Reset this candidate back to an empty one.
118     void reset() {
119       Stores.clear();
120       PotentialAliases.clear();
121       CurrentLowestOffset = 0;
122       BasePtr = Register();
123     }
124   };
125 
126   bool isLegalOrBeforeLegalizer(const LegalityQuery &Query,
127                                 MachineFunction &MF) const;
128   /// If the given store is valid to be a member of the candidate, add it and
129   /// return true. Otherwise, returns false.
130   bool addStoreToCandidate(GStore &MI, StoreMergeCandidate &C);
131   /// Returns true if the instruction \p MI would potentially alias with any
132   /// stores in the candidate \p C.
133   bool operationAliasesWithCandidate(MachineInstr &MI, StoreMergeCandidate &C);
134   /// Merges the stores in the given vector into a wide store.
135   /// \p returns true if at least some of the stores were merged.
136   /// This may decide not to merge stores if heuristics predict it will not be
137   /// worth it.
138   bool mergeStores(SmallVectorImpl<GStore *> &StoresToMerge);
139   /// Perform a merge of all the stores in \p Stores into a single store.
140   /// Erases the old stores from the block when finished.
141   /// \returns true if merging was done. It may fail to perform a merge if
142   /// there are issues with materializing legal wide values.
143   bool doSingleStoreMerge(SmallVectorImpl<GStore *> &Stores);
144   bool processMergeCandidate(StoreMergeCandidate &C);
145   bool mergeBlockStores(MachineBasicBlock &MBB);
146   bool mergeFunctionStores(MachineFunction &MF);
147 
148   bool mergeTruncStore(GStore &StoreMI,
149                        SmallPtrSetImpl<GStore *> &DeletedStores);
150   bool mergeTruncStoresBlock(MachineBasicBlock &MBB);
151 
152   /// Initialize some target-specific data structures for the store merging
153   /// optimization. \p AddrSpace indicates which address space to use when
154   /// probing the legalizer info for legal stores.
155   void initializeStoreMergeTargetInfo(unsigned AddrSpace = 0);
156   /// A map between address space numbers and a bitvector of supported stores
157   /// sizes. Each bit in the bitvector represents whether a store size of
158   /// that bit's value is legal. E.g. if bit 64 is set, then 64 bit scalar
159   /// stores are legal.
160   DenseMap<unsigned, BitVector> LegalStoreSizes;
161   bool IsPreLegalizer = false;
162   /// Contains instructions to be erased at the end of a block scan.
163   SmallSet<MachineInstr *, 16> InstsToErase;
164 
165 public:
166   LoadStoreOpt();
167   LoadStoreOpt(std::function<bool(const MachineFunction &)>);
168 
169   StringRef getPassName() const override { return "LoadStoreOpt"; }
170 
171   MachineFunctionProperties getRequiredProperties() const override {
172     return MachineFunctionProperties()
173         .set(MachineFunctionProperties::Property::IsSSA);
174   }
175 
176   void getAnalysisUsage(AnalysisUsage &AU) const override;
177 
178   bool runOnMachineFunction(MachineFunction &MF) override;
179 };
180 
181 } // End namespace llvm.
182 
183 #endif
184