LLVM: lib/Target/RISCV/RISCVFoldMemOffset.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
21#include
22
23using namespace llvm;
24
25#define DEBUG_TYPE "riscv-fold-mem-offset"
26#define RISCV_FOLD_MEM_OFFSET_NAME "RISC-V Fold Memory Offset"
27
28namespace {
29
31public:
32 static char ID;
33
35
37
38 bool foldOffset(Register OrigReg, int64_t InitialOffset,
41
42 void getAnalysisUsage(AnalysisUsage &AU) const override {
45 }
46
48};
49
50
51class FoldableOffset {
52 std::optional<int64_t> Offset;
53
54public:
55 bool hasValue() const { return Offset.has_value(); }
56 int64_t getValue() const { return *Offset; }
57
58 FoldableOffset &operator=(int64_t RHS) {
60 return *this;
61 }
62
67 return *this;
68 }
69
71};
72
73}
74
75char RISCVFoldMemOffset::ID = 0;
77 false, false)
78
80 return new RISCVFoldMemOffset();
81}
82
83
84
85
86
87
88
89
90bool RISCVFoldMemOffset::foldOffset(
93
94 DenseMap<Register, int64_t> RegToOffsetMap;
95
96
97 RegToOffsetMap[OrigReg] = InitialOffset;
98
99 std::queue Worklist;
100 Worklist.push(OrigReg);
101
102 while (!Worklist.empty()) {
104 Worklist.pop();
105
107 return false;
108
109 for (auto &User : MRI.use_nodbg_instructions(Reg)) {
110 FoldableOffset Offset;
111
112 switch (User.getOpcode()) {
113 default:
114 return false;
115 case RISCV::ADD:
116 if (auto I = RegToOffsetMap.find(User.getOperand(1).getReg());
117 I != RegToOffsetMap.end())
119 if (auto I = RegToOffsetMap.find(User.getOperand(2).getReg());
120 I != RegToOffsetMap.end())
122 break;
123 case RISCV::SH1ADD:
124 if (auto I = RegToOffsetMap.find(User.getOperand(1).getReg());
125 I != RegToOffsetMap.end())
126 Offset = (uint64_t)I->second << 1;
127 if (auto I = RegToOffsetMap.find(User.getOperand(2).getReg());
128 I != RegToOffsetMap.end())
130 break;
131 case RISCV::SH2ADD:
132 if (auto I = RegToOffsetMap.find(User.getOperand(1).getReg());
133 I != RegToOffsetMap.end())
134 Offset = (uint64_t)I->second << 2;
135 if (auto I = RegToOffsetMap.find(User.getOperand(2).getReg());
136 I != RegToOffsetMap.end())
138 break;
139 case RISCV::SH3ADD:
140 if (auto I = RegToOffsetMap.find(User.getOperand(1).getReg());
141 I != RegToOffsetMap.end())
142 Offset = (uint64_t)I->second << 3;
143 if (auto I = RegToOffsetMap.find(User.getOperand(2).getReg());
144 I != RegToOffsetMap.end())
146 break;
147 case RISCV::ADD_UW:
148 case RISCV::SH1ADD_UW:
149 case RISCV::SH2ADD_UW:
150 case RISCV::SH3ADD_UW:
151
152 if (User.getOperand(1).getReg() == Reg)
153 return false;
154 if (auto I = RegToOffsetMap.find(User.getOperand(2).getReg());
155 I != RegToOffsetMap.end())
157 break;
158 case RISCV::SLLI: {
159 unsigned ShAmt = User.getOperand(2).getImm();
160 if (auto I = RegToOffsetMap.find(User.getOperand(1).getReg());
161 I != RegToOffsetMap.end())
162 Offset = (uint64_t)I->second << ShAmt;
163 break;
164 }
165 case RISCV::LB:
166 case RISCV::LBU:
167 case RISCV::SB:
168 case RISCV::LH:
169 case RISCV::LH_INX:
170 case RISCV::LHU:
171 case RISCV::FLH:
172 case RISCV::SH:
173 case RISCV::SH_INX:
174 case RISCV::FSH:
175 case RISCV::LW:
176 case RISCV::LW_INX:
177 case RISCV::LWU:
178 case RISCV::FLW:
179 case RISCV::SW:
180 case RISCV::SW_INX:
181 case RISCV::FSW:
182 case RISCV::LD:
183 case RISCV::FLD:
184 case RISCV::SD:
185 case RISCV::FSD: {
186
187 if (User.getOperand(0).getReg() == Reg)
188 return false;
189
190
191 if (.getOperand(2).isImm())
192 return false;
193
194
195
196 if (User.getOperand(1).getReg() == OrigReg)
197 return false;
198
199 auto I = RegToOffsetMap.find(User.getOperand(1).getReg());
200 if (I == RegToOffsetMap.end())
201 return false;
202
203 int64_t LocalOffset = User.getOperand(2).getImm();
205 int64_t CombinedOffset = (uint64_t)LocalOffset + (uint64_t)I->second;
207 return false;
208
209 FoldableInstrs[&User] = CombinedOffset;
210 continue;
211 }
212 }
213
214
215 assert(Offset.hasValue() && "Expected an offset");
216
217
218
219 int64_t OffsetVal = Offset.getValue();
220 auto P =
221 RegToOffsetMap.try_emplace(User.getOperand(0).getReg(), OffsetVal);
222 if (P.second) {
223 Worklist.push(User.getOperand(0).getReg());
224 } else if (P.first->second != OffsetVal) {
225 P.first->second = OffsetVal;
226 Worklist.push(User.getOperand(0).getReg());
227 }
228 }
229 }
230
231 return true;
232}
233
234bool RISCVFoldMemOffset::runOnMachineFunction(MachineFunction &MF) {
236 return false;
237
238
240 return false;
241
243
244 bool MadeChange = false;
245 for (MachineBasicBlock &MBB : MF) {
247
248
249 if (MI.getOpcode() != RISCV::ADDI)
250 continue;
251
252
253 if (.getOperand(1).isReg() ||
.getOperand(2).isImm())
254 continue;
255
256
257 if (MI.getOperand(1).getReg() == RISCV::X0)
258 continue;
259
260 int64_t Offset = MI.getOperand(2).getImm();
262
263 DenseMap<MachineInstr *, int64_t> FoldableInstrs;
264
265 if (!foldOffset(MI.getOperand(0).getReg(), Offset, MRI, FoldableInstrs))
266 continue;
267
268 if (FoldableInstrs.empty())
269 continue;
270
271
272
273 for (auto [MemMI, NewOffset] : FoldableInstrs)
274 MemMI->getOperand(2).setImm(NewOffset);
275
276 MRI.replaceRegWith(MI.getOperand(0).getReg(), MI.getOperand(1).getReg());
277 MRI.clearKillFlags(MI.getOperand(1).getReg());
278 MI.eraseFromParent();
279 }
280 }
281
282 return MadeChange;
283}
unsigned const MachineRegisterInfo * MRI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
Promote Memory to Register
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
#define RISCV_FOLD_MEM_OFFSET_NAME
Definition RISCVFoldMemOffset.cpp:26
Represent the analysis usage information of a pass.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
FunctionPass class - This class is used to implement most global optimizations.
bool hasOptSize() const
Optimize this function for size (-Os) or minimum size (-Oz).
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
Wrapper class representing virtual and physical registers.
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
StringRef - Represent a constant reference to a string, i.e.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ User
could "use" a pointer
This is an optimization pass for GlobalISel generic memory operations.
FunctionPass * createRISCVFoldMemOffsetPass()
constexpr bool isInt(int64_t x)
Checks if an integer fits into the given bit width.
APInt operator*(APInt a, uint64_t RHS)
LLVM_ATTRIBUTE_ALWAYS_INLINE DynamicAPInt & operator+=(DynamicAPInt &A, int64_t B)
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...